diff --git a/.builds/freebsd.yml b/.builds/freebsd.yml new file mode 100644 index 000000000..7810e39af --- /dev/null +++ b/.builds/freebsd.yml @@ -0,0 +1,31 @@ +image: freebsd/latest +packages: +- databases/sqlite3 +- devel/boehm-gc-threaded +- devel/pcre +- devel/sdl20 +- devel/sfml +- www/node +- devel/gmake +- devel/git +sources: +- https://github.com/nim-lang/Nim +environment: + CC: /usr/bin/clang +tasks: +- setup: | + cd Nim + git clone --depth 1 -q https://github.com/nim-lang/csources.git + gmake -C csources -j $(sysctl -n hw.ncpu) + bin/nim c --skipUserCfg --skipParentCfg koch + echo 'export PATH=$HOME/Nim/bin:$PATH' >> $HOME/.buildenv +- test: | + cd Nim + if ! ./koch runCI; then + nim c -r tools/ci_testresults.nim + exit 1 + fi +triggers: +- action: email + condition: failure + to: Andreas Rumpf diff --git a/.gitattributes b/.gitattributes deleted file mode 100644 index 2c9ff103c..000000000 --- a/.gitattributes +++ /dev/null @@ -1,9 +0,0 @@ -# Avoids changelog conflicts by assuming additions-only, which is by far the common case. -# In the rare case where branch b1 rebases against branch b2 and both branches -# modified the same changelog entry, you'll end up with that changelog entry -# duplicated, which is easily identifiable and fixable. -/changelog.md merge=union - -# bug https://github.com/dom96/choosenim/issues/256 for WSL CRLF -*.sh text eol=lf -/config/build_config.txt text eol=lf diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 000000000..895b4ba61 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,40 @@ +--- +name: Bug report +about: Have you found an unexpected behavior? Use this template. +title: Think about the title, twice +labels: '' +assignees: '' + +--- + +Function `echo` outputs the wrong string. + +### Example +```nim +echo "Hello World!" +``` + +### Current Output +``` +Hola mundo! +``` + +### Expected Output +``` +Hello World! +``` + +### Possible Solution + +* In file xyz there is a call that might be the cause of it. + +### Additional Information + +* It was working in version a.b.c +* Issue #abc is related, but different because of ... +* This issue is blocking my project xyz + +``` +$ nim -v +Nim Compiler Version 0.1.2 +``` diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml deleted file mode 100644 index 8406f607f..000000000 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ /dev/null @@ -1,75 +0,0 @@ -name: "Bug Report" -description: "Create a new bug report. Have you found an unexpected behavior? Use this form." -title: "Think about the title, twice." -labels: ["unconfirmed"] -body: - -- type: markdown - attributes: - value: | - - **Please provide a minimal code example that reproduces the Bug!** :bug: - Reports with a reproducible example and descriptive detailed information will likely receive fixes faster. - -- type: textarea - id: description - attributes: - label: Description - description: | - Use DETAILED DESCRIPTIVE information about the problem. - Here, you go into more details about your Bug report. This section can be a few paragraphs long. - placeholder: Bug reports with reproducible code and detailed information will be fixed faster. - validations: - required: true - -- type: textarea - id: nim-version - attributes: - label: Nim Version - description: Copy and paste the output of `nim -v` on the command line. For development versions, make sure to include the commit hash. - validations: - required: true - -- type: textarea - id: current-logs - attributes: - label: Current Output - description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks. - placeholder: Bug reports with reproducible code and detailed information will be fixed faster. - render: text - -- type: textarea - id: expected-logs - attributes: - label: Expected Output - description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks. - placeholder: Bug reports with reproducible code and detailed information will be fixed faster. - render: text - -- type: textarea - id: possible-solution - attributes: - label: Possible Solution - description: Propose a possible solution. - validations: - required: false - -- type: textarea - id: extra-info - attributes: - label: Additional Information - description: Any additional relevant information. - validations: - required: false - -- type: markdown - attributes: - value: | - - Thanks for your contributions!, your Bug report will receive feedback from the community soon... - - Please check whether the problem still exists in the devel branch, see [rebuilding the compiler](https://nim-lang.github.io/Nim/intern.html#rebuilding-the-compiler). - - Consider writing a PR targetting devel branch after filing this, see [contributing](https://nim-lang.github.io/Nim/contributing.html). - - If it's a pre-existing compiler bug, see [Debugging the compiler](https://nim-lang.github.io/Nim/intern.html#debugging-the-compiler) - which should give more context on a compiler crash. - - If it's a regression, you can help us by identifying which version introduced the bug, - see [Bisecting for regressions](https://nim-lang.github.io/Nim/intern.html#bisecting-for-regressions), - or at least try known past releases (eg `choosenim 1.2.0`). - - [Please, consider a Donation for the Nim project.](https://nim-lang.org/donate.html) diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml deleted file mode 100644 index 0187064b5..000000000 --- a/.github/ISSUE_TEMPLATE/config.yml +++ /dev/null @@ -1,10 +0,0 @@ -contact_links: - - name: Forum - url: https://forum.nim-lang.org - about: Please ask and answer questions here. - - name: Discord - url: https://discord.gg/nim - about: Please ask and answer questions here. - - name: Stack Overflow - url: https://stackoverflow.com/questions/tagged/nim-lang - about: Please ask and answer questions here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 000000000..b9f7caad5 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,35 @@ +--- +name: Feature request +about: Do you want to suggest a new feature? Use this template. +title: '' +labels: '' +assignees: '' + +--- + + + + +### Summary + + + +### Description + + + +### Alternatives + + + +### Additional Information + diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml deleted file mode 100644 index 5cb458626..000000000 --- a/.github/ISSUE_TEMPLATE/feature_request.yml +++ /dev/null @@ -1,72 +0,0 @@ -name: "Feature request" -description: "Create a new Feature Request. Do you want to suggest a new feature? Use this form." -title: "Think about the title, twice." -labels: ["unconfirmed"] -body: - -- type: markdown - attributes: - value: | - - Please provide a minimal code example that illustrates the basic idea behind your feature request. - Reports with full repro code and descriptive detailed information will likely receive feedback faster. - - There is a separate repository for the detailed RFCs and proposals: https://github.com/nim-lang/RFCs. - If you have a simple feature request, you can post it here using this form, - but bear in mind that adding new features to the language is currently a low priority. - -- type: textarea - id: summary - attributes: - label: Summary - description: | - Use DETAILED DESCRIPTIVE information about the feature request. - Here, you go into more details about your ideas. This section can be a few paragraphs long. - placeholder: Short summary of your proposed feature. - validations: - required: true - -- type: textarea - id: description - attributes: - label: Description - description: Describe your solution, what problem does it fix? - validations: - required: true - -- type: textarea - id: alternatives - attributes: - label: Alternatives - description: Are there any alternatives you've considered? - validations: - required: false - -- type: textarea - id: Examples - attributes: - label: Examples - description: Provide examples for your feature request here. - placeholder: Example code here. - -- type: textarea - id: incompatibility - attributes: - label: Backwards Compatibility - description: If your Feature Request introduces backward-incompatible changes, describe them and propose how to deal with them. - validations: - required: false - -- type: textarea - id: links - attributes: - label: Links - description: Please copy and paste any relevant links to projects, issues, discussions, technical documentations, code samples, etc. - validations: - required: false - -- type: markdown - attributes: - value: | - - Thanks for your contributions!, your ideas will receive feedback from the community soon... - - **Remember to :star: Star the Nim project on GitHub!.** - - Consider writing a PR targetting devel branch after filing this, see [contributing](https://nim-lang.github.io/Nim/contributing.html). - - [Please, consider a Donation for the Nim project.](https://nim-lang.org/donate.html) diff --git a/.github/stale.yml b/.github/stale.yml deleted file mode 100644 index c175f64a0..000000000 --- a/.github/stale.yml +++ /dev/null @@ -1,69 +0,0 @@ -# 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 diff --git a/.github/workflows/ci_docs.yml b/.github/workflows/ci_docs.yml deleted file mode 100644 index cde30e5fa..000000000 --- a/.github/workflows/ci_docs.yml +++ /dev/null @@ -1,118 +0,0 @@ -name: Nim Docs CI -on: - push: - paths: - - 'compiler/docgen.nim' - - 'compiler/renderverbatim.nim' - - 'config/nimdoc.cfg' - - 'doc/**.rst' - - 'doc/**.md' - - 'doc/nimdoc.css' - - 'lib/**.nim' - - 'nimdoc/testproject/expected/testproject.html' - - 'tools/dochack/dochack.nim' - - 'tools/kochdocs.nim' - - '.github/workflows/ci_docs.yml' - - 'koch.nim' - - pull_request: - # Run only on changes on these files. - paths: - - 'compiler/docgen.nim' - - 'compiler/renderverbatim.nim' - - 'config/nimdoc.cfg' - - 'doc/**.rst' - - 'doc/**.md' - - 'doc/nimdoc.css' - - 'lib/**.nim' - - 'nimdoc/testproject/expected/testproject.html' - - 'tools/dochack/dochack.nim' - - 'tools/kochdocs.nim' - - '.github/workflows/ci_docs.yml' - - 'koch.nim' - -concurrency: - group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} - cancel-in-progress: true - -jobs: - build: - strategy: - fail-fast: false - matrix: - target: [linux, windows, osx] - include: - - target: linux - os: ubuntu-20.04 - - target: windows - os: windows-2019 - - target: osx - os: macos-11 - - name: ${{ matrix.target }} - runs-on: ${{ matrix.os }} - timeout-minutes: 60 # refs bug #18178 - - steps: - - name: 'Checkout' - uses: actions/checkout@v3 - with: - fetch-depth: 2 - - - name: 'Install build dependencies (macOS)' - if: runner.os == 'macOS' - run: brew install make - - - name: 'Install build dependencies (Windows)' - if: runner.os == 'Windows' - shell: bash - run: | - set -e - . ci/funs.sh - nimInternalInstallDepsWindows - echo "${{ github.workspace }}/dist/mingw64/bin" >> "${GITHUB_PATH}" - - - name: 'Add build binaries to PATH' - shell: bash - run: echo "${{ github.workspace }}/bin" >> "${GITHUB_PATH}" - - - name: 'System information' - shell: bash - run: . ci/funs.sh && nimCiSystemInfo - - - name: 'Build csourcesAny (posix)' - # this would work on windows and other CI use this on windows, - # but we ensure here that `ci/build_autogen.bat` keeps working on windows. - if: runner.os != 'Windows' - shell: bash - run: . ci/funs.sh && nimBuildCsourcesIfNeeded CC=gcc - # was previously using caching via `actions/cache@v1` but this wasn't - # used in other CI pipelines and it's unclear the added complexity - # was worth the saving; can be revisited if needed. - - - name: 'Build csourcesAny (windows)' - if: runner.os == 'Windows' - shell: cmd - run: ci/build_autogen.bat - - - name: 'Build koch' - shell: bash - run: nim c koch - - - name: 'Build the real compiler' - shell: bash - run: ./koch boot -d:release - - - name: 'Build documentation' - shell: bash - run: ./koch doc --git.commit:devel - - - name: 'Publish documentation to Github Pages' - if: | - github.event_name == 'push' && github.ref == 'refs/heads/devel' && - matrix.target == 'linux' - uses: crazy-max/ghaction-github-pages@v3 - with: - build_dir: doc/html - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/ci_packages.yml b/.github/workflows/ci_packages.yml deleted file mode 100644 index 0bec4cc21..000000000 --- a/.github/workflows/ci_packages.yml +++ /dev/null @@ -1,74 +0,0 @@ -name: Packages CI -on: - pull_request: - push: - branches: - - 'devel' - - 'version-2-0' - - 'version-1-6' - - 'version-1-2' - -concurrency: - group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} - cancel-in-progress: true - -jobs: - build: - strategy: - fail-fast: false - matrix: - os: [ubuntu-20.04, macos-11] - cpu: [amd64] - batch: ["allowed_failures", "0_3", "1_3", "2_3"] # list of `index_num` - name: '${{ matrix.os }} (batch: ${{ matrix.batch }})' - runs-on: ${{ matrix.os }} - timeout-minutes: 60 # refs bug #18178 - env: - NIM_TEST_PACKAGES: "1" - NIM_TESTAMENT_BATCH: ${{ matrix.batch }} - steps: - - name: 'Checkout' - uses: actions/checkout@v3 - with: - fetch-depth: 2 - - - name: 'Install node.js 16.x' - uses: actions/setup-node@v3 - with: - node-version: '16.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: '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: '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 diff --git a/.github/workflows/ci_publish.yml b/.github/workflows/ci_publish.yml deleted file mode 100644 index d6b628d8c..000000000 --- a/.github/workflows/ci_publish.yml +++ /dev/null @@ -1,90 +0,0 @@ -name: Tracking orc-booting compiler memory usage - -on: - pull_request_target: - types: [closed] - - -jobs: - build: - if: github.event.pull_request.merged == true - strategy: - fail-fast: false - matrix: - os: [ubuntu-20.04] - cpu: [amd64] - name: '${{ matrix.os }}' - runs-on: ${{ matrix.os }} - steps: - - name: 'Checkout' - uses: actions/checkout@v3 - with: - fetch-depth: 2 - - - name: 'Install node.js 16.x' - uses: actions/setup-node@v3 - with: - node-version: '16.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: '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: '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: 'Build koch' - shell: bash - run: nim c koch - - - name: 'Build Nim' - shell: bash - run: ./koch boot -d:release -d:nimStrictMode --lib:lib - - - name: 'Action' - shell: bash - run: nim c -r -d:release ci/action.nim - - - name: 'Comment' - uses: actions/github-script@v6 - with: - script: | - const fs = require('fs'); - - try { - const data = fs.readFileSync('ci/nimcache/results.txt', 'utf8'); - github.rest.issues.createComment({ - issue_number: context.issue.number, - owner: context.repo.owner, - repo: context.repo.repo, - body: data - }) - } catch (err) { - console.error(err); - } - diff --git a/.gitignore b/.gitignore index d0c4558df..de8732ee2 100644 --- a/.gitignore +++ b/.gitignore @@ -3,9 +3,9 @@ !*.* # Cache -nimcache*/ -rnimcache*/ -dnimcache*/ +nimcache/ +rnimcache/ +dnimcache/ *.o !/icons/*.o @@ -30,7 +30,7 @@ deinstall.sh doc/html/ doc/*.html -doc/pdf +doc/*.pdf doc/*.idx /web/upload /build/* @@ -64,49 +64,33 @@ lib/**/*.html testament.db /tests/**/*.json /tests/**/*.js - /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 +dist/ # Private directories and files (IDEs) .*/ ~* -# testament cruft; TODO: generate these in a gitignore'd dir (./build) in the first place. +# testament cruft; TODO: generate these in a gitignore'd dir in the first place. testresults/ test.txt /test.ini tweeter.db tweeter_test.db - -/tests/megatest.nim -/tests/ic/*_temp.nim -/tests/navigator/*_temp.nim - +megatest.nim /outputExpected.txt /outputGotten.txt -/t15148.txt -/tests/vm/tfile_rw.txt /lib/pure/*.js !/.builds/ -!/.github - # ignore debug dirs generated by dsymutil on OSX *.dSYM +nimdoc.out.css + # for `nim c -r nimdoc/tester` etc; this can be in multiple places htmldocs - -## these are not needed anymore unless checkout old older versions -nimdoc.out.css -# except here: -!/nimdoc/testproject/expected/* diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 31908d223..9f536e6c9 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,6 +1,4 @@ -# xxx unused, out of date - -image: ubuntu:18.04 +image: ubuntu:16.04 stages: - pre-build @@ -56,7 +54,7 @@ test-windows: script: - call ci\deps.bat - nim c testament\tester - - testament\tester.exe all + - testament\tester.exe --pedantic all tags: - windows - fast diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 000000000..d62fe20d2 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,94 @@ +sudo: false +language: c + +dist: xenial + +matrix: + fast_finish: true + + include: + - os: linux + env: + - NIM_COMPILE_TO_CPP=false + - CPU=amd64 + + - os: linux + env: + - NIM_COMPILE_TO_CPP=false + - CPU=i386 + addons: + apt: + packages: + - gcc-multilib + - g++-multilib + - libcurl4-openssl-dev:i386 + - libgc-dev:i386 + - libglib2.0-dev:i386 + - libpulse-dev:i386 + - libsdl1.2-dev:i386 + - libsfml-dev:i386 + + - os: osx + env: + - NIM_COMPILE_TO_CPP=false + - CPU=amd64 + + - os: osx + env: + - NIM_COMPILE_TO_CPP=true + - CPU=amd64 + +# To allow failures for a failing configuration, use something like: +# allow_failures: +# - env: NIM_COMPILE_TO_CPP=true +# - os: osx + +addons: + apt: + # update the list above if more deps are introduced + packages: + - libcurl4-openssl-dev + - libsdl1.2-dev + - libgc-dev + - libsfml-dev + - libc6-dbg + - valgrind + homebrew: + packages: + - boehmgc + - make + - sfml + update: true + +install: + - if [[ $CPU = i386 ]]; then echo -e "#!/bin/bash\n$(which gcc) -m32 \"\$@\"" > bin/gcc; fi + - if [[ $CPU = i386 ]]; then chmod 755 bin/gcc; fi + - if [[ $CPU = i386 ]]; then echo -e "#!/bin/bash\n$(which g++) -m32 \"\$@\"" > bin/g++; fi + - if [[ $CPU = i386 ]]; then chmod 755 bin/g++; fi + +before_script: + - git clone --depth 1 https://github.com/nim-lang/csources.git + - export PATH="$PWD/bin${PATH:+:$PATH}" + - make -C csources -j 2 LD=$CC ucpu=$CPU + +script: + - echo "travis_fold:start:nim_c_koch" + - nim c koch + - echo "travis_fold:end:nim_c_koch" + - ./koch runCI + +before_deploy: + # Make https://nim-lang.github.io/Nim work the same as https://nim-lang.github.io/Nim/overview.html + - cp -f ./doc/html/overview.html ./doc/html/index.html +deploy: # https://nim-lang.github.io/Nim + provider: pages + # local-dir *has* to be a relative path from the repo root. + local-dir: "doc/html" + skip-cleanup: true + github-token: "$GITHUB_OAUTH_TOKEN" + keep-history: false + on: + branch: devel + +# Extract failed tests +after_failure: nim c -r tools/ci_testresults.nim diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 000000000..e9407d124 --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,35 @@ +version: '{build}' + +environment: + DLLS_URL: https://nim-lang.org/download/dlls.zip + DLLS_ARCHIVE: dlls.zip + MINGW_DIR: mingw64 + MINGW_URL: https://nim-lang.org/download/mingw64.7z + MINGW_ARCHIVE: mingw64.7z + + matrix: + - NIM_TEST_PACKAGES: false + - NIM_TEST_PACKAGES: true + +cache: + - '%MINGW_ARCHIVE%' + - '%DLLS_ARCHIVE%' + + +install: + - ps: Install-Product node 8 # node 8 or later is required to test js async stuff + - IF not exist "%DLLS_ARCHIVE%" appveyor DownloadFile "%DLLS_URL%" -FileName "%DLLS_ARCHIVE%" + - 7z x -y "%DLLS_ARCHIVE%" -o"%CD%\BIN"> nul + - IF not exist "%MINGW_ARCHIVE%" appveyor DownloadFile "%MINGW_URL%" -FileName "%MINGW_ARCHIVE%" + - 7z x -y "%MINGW_ARCHIVE%" -o"%CD%\DIST"> nul + - SET PATH=%CD%\DIST\%MINGW_DIR%\BIN;%CD%\BIN;%PATH% + - git clone --depth 1 https://github.com/nim-lang/csources + - cd csources + - build64.bat + - cd .. + +build_script: + - bin\nim c koch + - koch runCI + +deploy: off diff --git a/azure-pipelines.yml b/azure-pipelines.yml index d034e3b9b..dccd0d05e 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -1,17 +1,3 @@ -trigger: - branches: - include: - - 'devel' - - 'version-*' -pr: - branches: - include: - - '*' - -variables: -- name: skipci - value: false - jobs: - job: packages @@ -20,34 +6,25 @@ jobs: strategy: matrix: Linux_amd64: - vmImage: 'ubuntu-20.04' + vmImage: 'ubuntu-16.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' + vmImage: 'ubuntu-16.04' CPU: i386 OSX_amd64: - vmImage: 'macOS-11' + vmImage: 'macOS-10.14' CPU: amd64 OSX_amd64_cpp: - vmImage: 'macOS-11' + vmImage: 'macOS-10.14' CPU: amd64 NIM_COMPILE_TO_CPP: true - Windows_amd64_batch0_3: + Windows_amd64: vmImage: 'windows-2019' CPU: amd64 - # see also: `NIM_TEST_PACKAGES` - NIM_TESTAMENT_BATCH: "0_3" - Windows_amd64_batch1_3: + Windows_amd64_pkg: vmImage: 'windows-2019' CPU: amd64 - NIM_TESTAMENT_BATCH: "1_3" - Windows_amd64_batch2_3: - vmImage: 'windows-2019' - CPU: amd64 - NIM_TESTAMENT_BATCH: "2_3" + NIM_TEST_PACKAGES: true pool: vmImage: $(vmImage) @@ -58,54 +35,49 @@ jobs: steps: - bash: git config --global core.autocrlf false displayName: 'Disable auto conversion to CRLF by git (Windows-only)' - condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT')) + condition: eq(variables['Agent.OS'], 'Windows_NT') - checkout: self - fetchDepth: 2 # see D20210329T004830 - - bash: | - set -e - . ci/funs.sh - if nimIsCiSkip; then - echo '##vso[task.setvariable variable=skipci]true' - fi - displayName: 'Check whether to skip CI' + - bash: git clone --depth 1 https://github.com/nim-lang/csources.git + displayName: 'Checkout csources' - task: NodeTool@0 inputs: - versionSpec: '16.x' - displayName: 'Install node.js 16.x' - condition: and(succeeded(), eq(variables['skipci'], 'false')) + versionSpec: '8.x' + displayName: 'Install node.js 8.x' - bash: | - set -e - . ci/funs.sh - echo_run sudo apt-fast update -qq + sudo apt-fast update -qq DEBIAN_FRONTEND='noninteractive' \ - echo_run sudo apt-fast 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 displayName: 'Install dependencies (amd64 Linux)' - condition: and(succeeded(), eq(variables['skipci'], 'false'), eq(variables['Agent.OS'], 'Linux'), eq(variables['CPU'], 'amd64')) + condition: and(eq(variables['Agent.OS'], 'Linux'), eq(variables['CPU'], 'amd64')) - bash: | - set -e - . ci/funs.sh - echo_run sudo dpkg --add-architecture i386 - # Downgrade llvm: - # - llvm has to be downgraded to have 32bit version installed for sfml. + sudo dpkg --add-architecture i386 + # Downgrade llvm, libgcc and libstdc++: + # - llvm has to be downgraded to have 32bit version installed for sfml. + # - libgcc and libstdc++ have to be downgraded as an optimization to + # prevent the use of the toolchain ppa, which has a terrible download + # speed. cat << EOF | sudo tee /etc/apt/preferences.d/pin-to-rel - Package: libllvm6.0 + Package: libllvm6.0 libgcc1 libstdc++6 Pin: origin "azure.archive.ubuntu.com" Pin-Priority: 1001 + + Package: * + Pin: release o=LP-PPA-ubuntu-toolchain-r-test + Pin-Priority: 100 EOF - # echo_run sudo apt-fast update -qq - echo_run sudo apt-fast update -qq || echo "failed, see bug #17343" + sudo apt-fast update -qq # `: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-fast install --no-install-recommends --allow-downgrades -yq \ + 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 @@ -114,55 +86,70 @@ jobs: exec $(which gcc) -m32 "\$@" EOF - cat << EOF > bin/g++ #!/bin/bash exec $(which g++) -m32 "\$@" EOF - echo_run chmod 755 bin/gcc - echo_run chmod 755 bin/g++ + chmod 755 bin/gcc + chmod 755 bin/g++ displayName: 'Install dependencies (i386 Linux)' - condition: and(succeeded(), eq(variables['skipci'], 'false'), eq(variables['Agent.OS'], 'Linux'), eq(variables['CPU'], 'i386')) + condition: and(eq(variables['Agent.OS'], 'Linux'), eq(variables['CPU'], 'i386')) - bash: brew install boehmgc make sfml displayName: 'Install dependencies (OSX)' - condition: and(succeeded(), eq(variables['skipci'], 'false'), eq(variables['Agent.OS'], 'Darwin')) + condition: eq(variables['Agent.OS'], 'Darwin') - bash: | - set -e - . ci/funs.sh - nimInternalInstallDepsWindows - echo_run echo '##vso[task.prependpath]$(System.DefaultWorkingDirectory)/dist/mingw64/bin' + mkdir dist + curl -L https://nim-lang.org/download/mingw64.7z -o dist/mingw64.7z + curl -L https://nim-lang.org/download/dlls.zip -o dist/dlls.zip + 7z x dist/mingw64.7z -odist + 7z x dist/dlls.zip -obin + echo '##vso[task.prependpath]$(System.DefaultWorkingDirectory)/dist/mingw64/bin' displayName: 'Install dependencies (Windows)' - condition: and(succeeded(), eq(variables['skipci'], 'false'), eq(variables['Agent.OS'], 'Windows_NT')) + condition: eq(variables['Agent.OS'], 'Windows_NT') - bash: echo '##vso[task.prependpath]$(System.DefaultWorkingDirectory)/bin' - condition: and(succeeded(), eq(variables['skipci'], 'false')) displayName: 'Add build binaries to PATH' - - bash: . ci/funs.sh && nimCiSystemInfo - condition: and(succeeded(), eq(variables['skipci'], 'false')) + - bash: | + echo 'PATH:' "$PATH" + echo '##[section]gcc version' + gcc -v + echo '##[section]nodejs version' + node -v + echo '##[section]make version' + make -v displayName: 'System information' - - bash: . ci/funs.sh && nimBuildCsourcesIfNeeded CC=gcc ucpu=$(CPU) - condition: and(succeeded(), eq(variables['skipci'], 'false')) - displayName: 'Build csourcesAny' + - bash: | + ncpu= + case '$(Agent.OS)' in + 'Linux') + ncpu=$(nproc) + ;; + 'Darwin') + ncpu=$(sysctl -n hw.ncpu) + ;; + 'Windows_NT') + ncpu=$NUMBER_OF_PROCESSORS + ;; + esac + [[ -z "$ncpu" || $ncpu -le 0 ]] && ncpu=1 - # this could be revived if performance justifies it (needs a few updates) - # - task: Cache@2 - # inputs: - # key: 'csourcesAny | "$(Agent.OS)" | $(CPU) | $(csources_version)' - # path: $(nim_csources) - # condition: and(succeeded(), eq(variables['skipci'], 'false')) - # displayName: 'Restore built csourcesAny' + make -C csources -j $ncpu CC=gcc ucpu=$(CPU) + displayName: 'Build csources' - - bash: . ci/funs.sh && nimInternalBuildKochAndRunCI - # would could also show on failure: echo '##vso[task.complete result=Failed]' - condition: and(succeeded(), eq(variables['skipci'], 'false')) - displayName: 'koch, Run CI' + - bash: nim c koch + displayName: 'Build koch' + + # set result to omit the "bash exited with error code '1'" message + - bash: | + ./koch runCI || echo '##vso[task.complete result=Failed]' + displayName: 'Run CI' env: SYSTEM_ACCESSTOKEN: $(System.AccessToken) diff --git a/bin/nim-gdb b/bin/nim-gdb index d4d60e432..9d6f462bb 100755 --- a/bin/nim-gdb +++ b/bin/nim-gdb @@ -5,16 +5,10 @@ set -e which nim > /dev/null || (echo "nim not in PATH"; exit 1) which gdb > /dev/null || (echo "gdb not in PATH"; exit 1) -which readlink > /dev/null || (echo "readlink not in PATH."; exit 1) - -if [[ $(uname -s) == Darwin || $(uname -s) == *BSD ]]; then - NIM_SYSROOT=$(dirname $(dirname $(readlink -f $(which nim)))) -else - NIM_SYSROOT=$(dirname $(dirname $(readlink -e $(which nim)))) -fi # Find out where the pretty printer Python module is -GDB_PYTHON_MODULE_PATH="$NIM_SYSROOT/tools/debug/nim-gdb.py" +NIM_SYSROOT=$(dirname $(dirname $(readlink -e $(which nim)))) +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 @@ -22,4 +16,6 @@ GDB_PYTHON_MODULE_PATH="$NIM_SYSROOT/tools/debug/nim-gdb.py" NIM_GDB="${NIM_GDB:-gdb}" # exec replaces the new process of bash with gdb. It is always good to # have fewer processes. -exec "${NIM_GDB}" -eval-command="source $GDB_PYTHON_MODULE_PATH" "$@" +exec ${NIM_GDB} \ + -eval-command "source $GDB_PYTHON_MODULE_PATH" \ + "$@" diff --git a/bin/nim-gdb.bat b/bin/nim-gdb.bat deleted file mode 100644 index b5537dd9d..000000000 --- a/bin/nim-gdb.bat +++ /dev/null @@ -1,14 +0,0 @@ -@echo off -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 @NIM_GDB=gdb.exe - -@echo source %@GDB_PYTHON_MODULE_PATH%> wingdbcommand.txt -%@NIM_GDB% --command="wingdbcommand.txt" %* -del wingdbcommand.txt /f /q - -EXIT /B %ERRORLEVEL% -@echo on diff --git a/build_all.bat b/build_all.bat index ef4a5f6a4..59df15594 100644 --- a/build_all.bat +++ b/build_all.bat @@ -1,29 +1,16 @@ @echo off -rem DO NO EDIT DIRECTLY! auto-generated by `nim r tools/ci_generate.nim` -rem Build development version of the compiler; can be rerun safely -rem bare bones version of ci/funs.sh adapted for windows. - -rem Read in some common shared variables (shared with other tools), -rem see https://stackoverflow.com/questions/3068929/how-to-read-file-contents-into-a-variable-in-a-batch-file -for /f "delims== tokens=1,2" %%G in (config/build_config.txt) do set %%G=%%H -SET nim_csources=bin\nim_csources_%nim_csourcesHash%.exe -echo "building from csources: %nim_csources%" - -if not exist %nim_csourcesDir% ( - git clone -q --depth 1 -b %nim_csourcesBranch% %nim_csourcesUrl% %nim_csourcesDir% +rem build development version of the compiler; can be rerun safely +if not exist csources ( + git clone --depth 1 https://github.com/nim-lang/csources.git ) - -if not exist %nim_csources% ( - cd %nim_csourcesDir% - git checkout %nim_csourcesHash% - echo "%PROCESSOR_ARCHITECTURE%" - if "%PROCESSOR_ARCHITECTURE%"=="AMD64" ( +if not exist bin\nim.exe ( + cd csources + if PROCESSOR_ARCHITECTURE == AMD64 ( SET ARCH=64 ) CALL build.bat 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 --skipUserCfg --skipParentCfg koch +koch.exe boot -d:release +koch.exe tools \ No newline at end of file diff --git a/build_all.sh b/build_all.sh old mode 100755 new mode 100644 index 83848f41a..84230c018 --- a/build_all.sh +++ b/build_all.sh @@ -1,17 +1,51 @@ -#!/bin/sh -# DO NO EDIT DIRECTLY! auto-generated by `nim r tools/ci_generate.nim` +#! /bin/sh # build development version of the compiler; can be rerun safely. -# arguments can be passed, e.g.: -# CC=gcc ucpu=amd64 uos=darwin +# arguments can be passed, eg `--os freebsd` set -u # error on undefined variables set -e # exit on first error -. ci/funs.sh -nimBuildCsourcesIfNeeded "$@" +echo_run(){ + echo "$*" + "$@" +} -echo_run bin/nim c --noNimblePath --skipUserCfg --skipParentCfg --hints:off koch -echo_run ./koch boot -d:release --skipUserCfg --skipParentCfg --hints:off -echo_run ./koch tools --skipUserCfg --skipParentCfg --hints:off +[ -d csources ] || echo_run git clone -q --depth 1 https://github.com/nim-lang/csources.git +nim_csources=bin/nim_csources + +build_nim_csources_via_script(){ + echo_run cd csources + echo_run sh build.sh "$@" +} + +build_nim_csources(){ + # avoid changing dir in case of failure + ( + if [ $# -ne 0 ]; then + # some args were passed (eg: `--cpu i386`), need to call build.sh + build_nim_csources_via_script "$@" + else + # no args, use multhreaded (5X faster on 16 cores: 10s instead of 50s) + makeX=make + unamestr=$(uname) + if [ "$unamestr" = 'FreeBSD' ]; then + makeX=gmake + fi + nCPU=$(nproc 2>/dev/null || sysctl -n hw.logicalcpu 2>/dev/null || getconf _NPROCESSORS_ONLN 2>/dev/null || 1) + which $makeX && echo_run $makeX -C csources -j $((nCPU + 2)) -l $nCPU || build_nim_csources_via_script + fi + ) + # keep $nim_csources in case needed to investigate bootstrap issues + # without having to rebuild from csources + echo_run cp bin/nim $nim_csources +} + +[ -f $nim_csources ] || echo_run build_nim_csources $@ + +# Note: if fails, may need to `cd csources && git pull` +echo_run bin/nim c --skipUserCfg --skipParentCfg koch + +echo_run ./koch boot -d:release -d:nimHasLibFFI +echo_run ./koch tools # Compile Nimble and other tools. diff --git a/changelog.md b/changelog.md index 2db577d0b..9bec0c47a 100644 --- a/changelog.md +++ b/changelog.md @@ -1,31 +1,123 @@ -# v2.2.0 - yyyy-mm-dd +# 1.2 - xxxx-xx-xx -## Changes affecting backward compatibility +## Changes affecting backwards compatibility -## Standard library additions and changes -[//]: # "Changes:" +### Breaking changes in the standard library + +- `base64.encode` no longer supports `lineLen` and `newLine`. + Use `base64.encodeMIME` instead. +- `os.splitPath()` behavior synchronized with `os.splitFile()` to return "/" + as the dir component of "/root_sub_dir" instead of the empty string. +- `sequtils.zip` now returns a sequence of anonymous tuples i.e. those tuples + now do not have fields named "a" and "b". +- `strutils.formatFloat` with `precision = 0` has the same behavior in all + backends, and it is compatible with Python's behavior, + e.g. `formatFloat(3.14159, precision = 0)` is now `3`, not `3.`. +- Global variable `lc` has been removed from sugar.nim. +- `distinctBase` has been moved from sugar.nim to typetraits and now implemented as + compiler type trait instead of macro. `distinctBase` in sugar module is now deprecated. +- `CountTable.mget` has been removed from `tables.nim`. It didn't work, and it + was an oversight to be included in v1.0. +- `tables.merge(CountTable, CountTable): CountTable` has been removed. + It didn't work well together with the existing inplace version of the same proc + (`tables.merge(var CountTable, CountTable)`). + It was an oversight to be included in v1.0. -[//]: # "Additions:" -- Added `parseutils.parseSize` - inverse to `strutils.formatSize` - to parse human readable sizes. +### Breaking changes in the compiler -[//]: # "Deprecations:" +- Implicit conversions for `const` behave correctly now, meaning that code like + `const SOMECONST = 0.int; procThatTakesInt32(SOMECONST)` will be illegal now. + Simply write `const SOMECONST = 0` instead. -[//]: # "Removals:" + +## Library additions + +- `macros.newLit` now works for ref object types. +- `system.writeFile` has been overloaded to also support `openarray[byte]`. +- Added overloaded `strformat.fmt` macro that use specified characters as + delimiter instead of '{' and '}'. +- introduced new procs in `tables.nim`: `OrderedTable.pop`, `CountTable.del`, + `CountTable.pop`, `Table.pop` +- To `strtabs.nim`, added `StringTable.clear` overload that reuses the existing mode. +- Added `sugar.outplace` for turning in-place algorithms like `sort` and `shuffle` into + operations that work on a copy of the data and return the mutated copy. As the existing + `sorted` does. +- Added `sugar.collect` that does comprehension for seq/set/table collections. +- Added `sugar.capture` for capturing some local loop variables when creating a closure. + This is an enhanced version of `closureScope`. +- Added `typetraits.lenTuple` to get number of elements of a tuple/type tuple, + and `typetraits.get` to get the ith element of a type tuple. +- Added `typetraits.genericParams` to return a tuple of generic params from a generic instantiation +- Added `os.normalizePathEnd` for additional path sanitization. +- Added `times.fromUnixFloat,toUnixFloat`, subsecond resolution versions of `fromUnix`,`toUnixFloat`. +- Added `wrapnils` module for chains of field-access and indexing where the LHS can be nil. + This simplifies code by reducing need for if-else branches around intermediate maybe nil values. + E.g. `echo ?.n.typ.kind` +- Added `minIndex` and `maxIndex` to the `sequtils` module +- Added `os.isRelativeTo` to tell whether a path is relative to another +- Added `resetOutputFormatters` to `unittest` + + +## Library changes + +- `asynchttpserver` now the request body is a FutureStream. +- `asyncdispatch.drain` now properly takes into account `selector.hasPendingOperations` + and only returns once all pending async operations are guaranteed to have completed. +- `asyncdispatch.drain` now consistently uses the passed timeout value for all + iterations of the event loop, and not just the first iteration. + This is more consistent with the other asyncdispatch apis, and allows + `asyncdispatch.drain` to be more efficient. +- `base64.encode` and `base64.decode` was made faster by about 50%. +- `htmlgen` adds [MathML](https://wikipedia.org/wiki/MathML) support + (ISO 40314). +- `macros.eqIdent` is now invariant to export markers and backtick quotes. +- `htmlgen.html` allows `lang` on the `` tag and common valid attributes. +- `macros.basename` and `basename=` got support for `PragmaExpr`, + so that an expression like `MyEnum {.pure.}` is handled correctly. +- `httpclient.maxredirects` changed from `int` to `Natural`, because negative values + serve no purpose whatsoever. +- `httpclient.newHttpClient` and `httpclient.newAsyncHttpClient` added `headers` + argument to set initial HTTP Headers, instead of a hardcoded empty `newHttpHeader()`. + + +## Language additions + +- An `align` pragma can now be used for variables and object fields, similar + to the `alignas` declaration modifier in C/C++. + +- `=sink` type bound operator is now optional. Compiler can now use combination + of `=destroy` and `copyMem` to move objects efficiently. ## Language changes +- Unsigned integer operators have been fixed to allow promotion of the first operand. +- Conversions to unsigned integers are unchecked at runtime, imitating earlier Nim + versions. The documentation was improved to acknowledge this special case. + See https://github.com/nim-lang/RFCs/issues/175 for more details. -## Compiler changes +### Tool changes +### Compiler changes -## Tool changes +- JS target indent is all spaces, instead of mixed spaces and tabs, for + generated JavaScript. +- The Nim compiler now supports the ``--asm`` command option for easier + inspection of the produced assembler code. +- The Nim compiler now supports a new pragma called ``.localPassc`` to + pass specific compiler options to the C(++) backend for the C(++) file + that was produced from the current Nim module. + +## Bugfixes + +- The `FD` variant of `selector.unregister` for `ioselector_epoll` and + `ioselector_select` now properly handle the `Event.User` select event type. diff --git a/changelogs/changelog_0_19_0.md b/changelogs/changelog_0_19_0.md index 45cefe933..18d3ca2b3 100644 --- a/changelogs/changelog_0_19_0.md +++ b/changelogs/changelog_0_19_0.md @@ -15,7 +15,7 @@ at runtime. Use ``ref object`` with inheritance rather than ``object`` with inheritance to prevent this issue. - The ``not nil`` type annotation now has to be enabled explicitly - via ``{.experimental: "notnil".}`` as we are still not pleased with how this + via ``{.experimental: "notnil"}`` as we are still not pleased with how this feature works with Nim's containers. - The parser now warns about inconsistent spacing around binary operators as these can easily be confused with unary operators. This warning will likely diff --git a/changelogs/changelog_1_2_0.md b/changelogs/changelog_1_2_0.md deleted file mode 100644 index 1f76df0b4..000000000 --- a/changelogs/changelog_1_2_0.md +++ /dev/null @@ -1,535 +0,0 @@ -# v1.2.0 - 2020-04-02 - - -## Standard library additions and changes -- Added overloaded `strformat.fmt` macro that use specified characters as - delimiter instead of '{' and '}'. -- Added new procs in `tables.nim`: `OrderedTable.pop`, `CountTable.del`, - `CountTable.pop`, `Table.pop`. -- Added `strtabs.clear` overload that reuses the existing mode. -- Added `browsers.osOpen` const alias for the operating system specific *"open"* command. -- Added `sugar.dup` for turning in-place algorithms like `sort` and `shuffle` - into operations that work on a copy of the data and return the mutated copy, - like the existing `sorted` does. -- Added `sugar.collect` that does comprehension for seq/set/table collections. -- Added `sugar.capture` for capturing some local loop variables when creating a - closure. This is an enhanced version of `closureScope`. -- Added `typetraits.tupleLen` to get number of elements of a tuple/type tuple, - and `typetraits.get` to get the ith element of a type tuple. -- Added `typetraits.genericParams` to return a tuple of generic params from a - generic instantiation. -- `options` now treats `proc` like other pointer types, meaning `nil` proc variables - are converted to `None`. -- Added `os.normalizePathEnd` for additional path sanitization. -- Added `times.fromUnixFloat,toUnixFloat`, sub-second resolution versions of - `fromUnix`,`toUnixFloat`. -- Added `wrapnils` module for chains of field-access and indexing where the LHS - can be nil. This simplifies code by reducing need for if-else branches around - intermediate maybe nil values. E.g. `echo ?.n.typ.kind`. -- Added `minIndex`, `maxIndex` and `unzip` to the `sequtils` module. -- Added `os.isRelativeTo` to tell whether a path is relative to another. -- Added `resetOutputFormatters` to `unittest`. -- Added `expectIdent` to the `macros` module. -- Added `os.isValidFilename` that returns `true` if `filename` argument is valid - for cross-platform use. -- Added `times.isLeapDay`. -- `base64` adds URL-Safe Base64, implements RFC-4648 Section-7. -- Added a new module, `std / compilesettings` for querying the compiler about - diverse configuration settings. -- Added `net.getPeerCertificates` and `asyncnet.getPeerCertificates` for - retrieving the verified certificate chain of the peer we are connected to - through an SSL-wrapped `Socket`/`AsyncSocket`. -- Added `browsers.openDefaultBrowser` without URL, implements IETF RFC-6694 Section-3. -- Added `jsconsole.trace`, `jsconsole.table`, `jsconsole.exception` for JavaScript target. -- Added `distinctBase` overload for values: `assert 12.MyInt.distinctBase == 12` -- Added new module `std/stackframes`, in particular `setFrameMsg`, which enables - custom runtime annotation of stackframes, see #13351 for examples. - Turn on/off via `--stackTraceMsgs:on/off`. -- Added `sequtils.countIt`, allowing for counting items using a predicate. -- Added a `with` macro for easy function chaining that's available everywhere, - there is no need to concern your APIs with returning the first argument - to enable "chaining", instead use the dedicated macro `with` that - was designed for it. For example: - -```nim -import std/with - -type - Foo = object - col, pos: string - -proc setColor(f: var Foo; r, g, b: int) = f.col = $(r, g, b) -proc setPosition(f: var Foo; x, y: float) = f.pos = $(x, y) - -var f: Foo -with(f, setColor(2, 3, 4), setPosition(0.0, 1.0)) -echo f -``` - -- `macros.newLit` now works for ref object types. -- `macro pragmas` can now be used in type sections. -- 5 new pragmas were added to Nim in order to make the upcoming tooling more - convenient to use. Nim compiler checks these pragmas for syntax but otherwise - ignores them. The pragmas are `requires`, `ensures`, `assume`, `assert`, `invariant`. -- `system.writeFile` has been overloaded to also support `openarray[byte]`. -- `asyncdispatch.drain` now properly takes into account `selector.hasPendingOperations` - and only returns once all pending async operations are guaranteed to have completed. -- `sequtils.zip` now returns a sequence of anonymous tuples i.e. those tuples - now do not have fields named "a" and "b". -- `distinctBase` has been moved from `sugar` to `typetraits` and now it is - implemented as compiler type trait instead of macro. `distinctBase` in sugar - module is now deprecated. -- `CountTable.mget` has been removed from `tables.nim`. It didn't work, and it - was an oversight to be included in v1.0. -- `tables.merge(CountTable, CountTable): CountTable` has been removed. - It didn't work well together with the existing inplace version of the same proc - (`tables.merge(var CountTable, CountTable)`). - It was an oversight to be included in v1.0. -- `asyncdispatch.drain` now consistently uses the passed timeout value for all - iterations of the event loop, and not just the first iteration. - This is more consistent with the other asyncdispatch APIs, and allows - `asyncdispatch.drain` to be more efficient. -- `base64.encode` and `base64.decode` were made faster by about 50%. -- `htmlgen` adds [MathML](https://wikipedia.org/wiki/MathML) support - (ISO 40314). -- `macros.eqIdent` is now invariant to export markers and backtick quotes. -- `htmlgen.html` allows `lang` in the `` tag and common valid attributes. -- `macros.basename` and `basename=` got support for `PragmaExpr`, - so that an expression like `MyEnum {.pure.}` is handled correctly. -- `httpclient.maxredirects` changed from `int` to `Natural`, because negative values - serve no purpose whatsoever. -- `httpclient.newHttpClient` and `httpclient.newAsyncHttpClient` added `headers` - argument to set initial HTTP Headers, instead of a hardcoded empty `newHttpHeader()`. -- `parseutils.parseUntil` has now a different behaviour if the `until` parameter is - empty. This was required for intuitive behaviour of the strscans module - (see bug #13605). -- `strutils.formatFloat` with `precision = 0` has the same behavior in all - backends, and it is compatible with Python's behavior, - e.g. `formatFloat(3.14159, precision = 0)` is now `3`, not `3.`. -- `times.parse` now only uses input to compute its result, and not `now`: - `parse("2020", "YYYY", utc())` is now `2020-01-01T00:00:00Z` instead of - `2020-03-02T00:00:00Z` if run on 03-02; it also doesn't crash anymore when - used on 29th, 30th, 31st of each month. -- `httpcore.==(string, HttpCode)` is now deprecated due to lack of practical - usage. The `$` operator can be used to obtain the string form of `HttpCode` - for comparison if desired. -- `std/oswalkdir` was buggy, it's now deprecated and reuses `std/os` procs. -- `os.walkDir` and `os.walkDirRec` now have new flag, `checkDir` (default: false). - If it is set to true, it will throw if input dir is invalid instead of a noop - (which is the default behaviour, as it was before this change), - `os.walkDirRec` only throws if top-level dir is invalid, but ignores errors for - subdirs, otherwise it would be impossible to resume iteration. -- The `FD` variant of `selector.unregister` for `ioselector_epoll` and - `ioselector_select` now properly handle the `Event.User` select event type. -- `joinPath` path normalization when `/` is the first argument works correctly: - `assert "/" / "/a" == "/a"`. Fixed the edge case: `assert "" / "" == ""`. -- `xmltree` now adds indentation consistently to child nodes for any number - of children nodes. -- `os.splitPath()` behavior synchronized with `os.splitFile()` to return "/" - as the dir component of `/root_sub_dir` instead of the empty string. -- The deprecated `lc` macro has been removed from `sugar`. It is now replaced - with the more powerful `collect` macro. -- `os.relativePath("foo", "foo")` is now `"."`, not `""`, as `""` means invalid - path and shouldn't be conflated with `"."`; use `-d:nimOldRelativePathBehavior` - to restore the old behavior. -- `os.joinPath(a, b)` now honors trailing slashes in `b` (or `a` if `b` = ""). -- `base64.encode` no longer supports `lineLen` and `newLine`. - Use `base64.encodeMime` instead. - - -### Breaking changes - -- `net.newContext` now performs SSL Certificate checking on Linux and OSX. - Define `nimDisableCertificateValidation` to disable it globally. - - - -## Language changes - -- An `align` pragma can now be used for variables and object fields, similar - to the `alignas` declaration modifier in C/C++. -- The `=sink` type bound operator is now optional. The compiler can now use a - combination of `=destroy` and `copyMem` to move objects efficiently. -- Unsigned integer operators have been fixed to allow promotion of the first operand. -- Conversions to unsigned integers are unchecked at runtime, imitating earlier Nim - versions. The documentation was improved to acknowledge this special case. - See https://github.com/nim-lang/RFCs/issues/175 for more details. -- There is a new syntax for lvalue references: `var b {.byaddr.} = expr` enabled by - `import std/decls`. -- `var a {.foo.}: MyType = expr` now lowers to `foo(a, MyType, expr)` for - non-builtin pragmas, enabling things like lvalue references (see `decls.byaddr`). - - - -## Compiler changes - -- The generated JS code uses spaces, instead of mixing spaces and tabs. -- The Nim compiler now supports the ``--asm`` command option for easier - inspection of the produced assembler code. -- The Nim compiler now supports a new pragma called ``.localPassc`` to - pass specific compiler options to the C(++) backend for the C(++) file - that was produced from the current Nim module. -- The compiler now inferes "sink parameters". To disable this for a specific routine, - annotate it with `.nosinks`. To disable it for a section of code, use - `{.push sinkInference: off.}`...`{.pop.}`. -- The compiler now supports a new switch `--panics:on` that turns runtime - errors like `IndexError` or `OverflowError` into fatal errors that **cannot** - be caught via Nim's `try` statement. `--panics:on` can improve the - runtime efficiency and code size of your program significantly. -- The compiler now warns about inheriting directly from `system.Exception` as - this is **very bad** style. You should inherit from `ValueError`, `IOError`, - `OSError` or from a different specific exception type that inherits from - `CatchableError` and cannot be confused with a `Defect`. -- The error reporting for Nim's effect system has been improved. -- Implicit conversions for `const` behave correctly now, meaning that code like - `const SOMECONST = 0.int; procThatTakesInt32(SOMECONST)` will be illegal now. - Simply write `const SOMECONST = 0` instead. -- The `{.dynlib.}` pragma is now required for exporting symbols when making - shared objects on POSIX and macOS, which make it consistent with the behavior - on Windows. -- The compiler is now more strict about type conversions concerning proc - types: Type conversions cannot be used to hide `.raise` effects or side - effects, instead a `cast` must be used. With the flag `--useVersion:1.0` the - old behaviour is emulated. -- The Nim compiler now implements a faster way to detect overflows based - on GCC's `__builtin_sadd_overflow` family of functions. (Clang also - supports these). Some versions of GCC lack this feature and unfortunately - we cannot detect this case reliably. So if you get compilation errors like - "undefined reference to `__builtin_saddll_overflow`" compile your programs - with `-d:nimEmulateOverflowChecks`. - - - - -## Bugfixes - -- Fixed "`nimgrep --nocolor` is ignored on posix; should be instead: `--nimgrep --color=[auto]|true|false`" - ([#7591](https://github.com/nim-lang/Nim/issues/7591)) -- Fixed "Runtime index on const array (of converted obj) causes C-compiler error" - ([#10514](https://github.com/nim-lang/Nim/issues/10514)) -- Fixed "windows x86 with vcc compile error with "asmNoStackFrame"" - ([#12298](https://github.com/nim-lang/Nim/issues/12298)) -- Fixed "[TODO] regression: Error: Locks requires --threads:on option" - ([#12330](https://github.com/nim-lang/Nim/issues/12330)) -- Fixed "Add --cc option to --help or --fullhelp output" - ([#12010](https://github.com/nim-lang/Nim/issues/12010)) -- Fixed "questionable `csize` definition in `system.nim`" - ([#12187](https://github.com/nim-lang/Nim/issues/12187)) -- Fixed "os.getAppFilename() returns incorrect results on OpenBSD" - ([#12389](https://github.com/nim-lang/Nim/issues/12389)) -- Fixed "HashSet[uint64] slow insertion depending on values" - ([#11764](https://github.com/nim-lang/Nim/issues/11764)) -- Fixed "Differences between compiling 'classic call syntax' vs 'method call syntax' ." - ([#12453](https://github.com/nim-lang/Nim/issues/12453)) -- Fixed "c -d:nodejs --> SIGSEGV: Illegal storage access" - ([#12502](https://github.com/nim-lang/Nim/issues/12502)) -- Fixed "Closure iterator crashes on --newruntime due to "dangling references"" - ([#12443](https://github.com/nim-lang/Nim/issues/12443)) -- Fixed "No `=destroy` for elements of closure environments other than for latest devel --gc:destructors" - ([#12577](https://github.com/nim-lang/Nim/issues/12577)) -- Fixed "strutils:formatBiggestFloat() gives different results in JS mode" - ([#8242](https://github.com/nim-lang/Nim/issues/8242)) -- Fixed "Regression (devel): the new `csize_t` definition isn't consistently used, nor tested thoroughly..." - ([#12597](https://github.com/nim-lang/Nim/issues/12597)) -- Fixed "tables.take() is defined only for `Table` and missed for other table containers" - ([#12519](https://github.com/nim-lang/Nim/issues/12519)) -- Fixed "`pthread_key_t` errors on OpenBSD" - ([#12135](https://github.com/nim-lang/Nim/issues/12135)) -- Fixed "newruntime: simple seq pop at ct results in compile error" - ([#12644](https://github.com/nim-lang/Nim/issues/12644)) -- Fixed "[Windows] finish.exe C:\Users\\.nimble\bin is not in your PATH environment variable." - ([#12319](https://github.com/nim-lang/Nim/issues/12319)) -- Fixed "Error with strformat + asyncdispatch + const" - ([#12612](https://github.com/nim-lang/Nim/issues/12612)) -- Fixed "MultipartData needs $" - ([#11863](https://github.com/nim-lang/Nim/issues/11863)) -- Fixed "Nim stdlib style issues with --styleCheck:error" - ([#12687](https://github.com/nim-lang/Nim/issues/12687)) -- Fixed "new $nimbleDir path substitution yields unexpected search paths" - ([#12767](https://github.com/nim-lang/Nim/issues/12767)) -- Fixed "Regression: inlined procs now get multiple rounds of destructor injection" - ([#12766](https://github.com/nim-lang/Nim/issues/12766)) -- Fixed "newruntime: compiler generates defective code" - ([#12669](https://github.com/nim-lang/Nim/issues/12669)) -- Fixed "broken windows modules path handling because of 'os.relativePath' breaking changes" - ([#12734](https://github.com/nim-lang/Nim/issues/12734)) -- Fixed "for loop tuple syntax not rendered correctly" - ([#12740](https://github.com/nim-lang/Nim/issues/12740)) -- Fixed "Crash when trying to use `type.name[0]`" - ([#12804](https://github.com/nim-lang/Nim/issues/12804)) -- Fixed "Enums should be considered Trivial types in Atomics" - ([#12812](https://github.com/nim-lang/Nim/issues/12812)) -- Fixed "Produce static/const initializations for variables when possible" - ([#12216](https://github.com/nim-lang/Nim/issues/12216)) -- Fixed "Assigning descriminator field leads to internal assert with --gc:destructors" - ([#12821](https://github.com/nim-lang/Nim/issues/12821)) -- Fixed "nimsuggest `use` command does not return all instances of symbol" - ([#12832](https://github.com/nim-lang/Nim/issues/12832)) -- Fixed "@[] is a problem for --gc:destructors" - ([#12820](https://github.com/nim-lang/Nim/issues/12820)) -- Fixed "Codegen ICE in allPathsAsgnResult" - ([#12827](https://github.com/nim-lang/Nim/issues/12827)) -- Fixed "seq[Object with ref and destructor type] doesn't work in old runtime" - ([#12882](https://github.com/nim-lang/Nim/issues/12882)) -- Fixed "Destructor not invoked because it is instantiated too late, old runtime" - ([#12883](https://github.com/nim-lang/Nim/issues/12883)) -- Fixed "The collect macro does not handle if/case correctly" - ([#12874](https://github.com/nim-lang/Nim/issues/12874)) -- Fixed "allow typed/untyped params in magic procs (even if not in stdlib)" - ([#12911](https://github.com/nim-lang/Nim/issues/12911)) -- Fixed "ARC/newruntime memory corruption" - ([#12899](https://github.com/nim-lang/Nim/issues/12899)) -- Fixed "tasyncclosestall.nim still flaky test: Address already in use" - ([#12919](https://github.com/nim-lang/Nim/issues/12919)) -- Fixed "newruntime and computed goto: variables inside the loop are in generated code uninitialised" - ([#12785](https://github.com/nim-lang/Nim/issues/12785)) -- Fixed "osx: dsymutil needs to be called for debug builds to keep debug info" - ([#12735](https://github.com/nim-lang/Nim/issues/12735)) -- Fixed "codegen ICE with ref objects, gc:destructors" - ([#12826](https://github.com/nim-lang/Nim/issues/12826)) -- Fixed "mutable iterator cannot yield named tuples" - ([#12945](https://github.com/nim-lang/Nim/issues/12945)) -- Fixed "parsecfg stores "\r\n" line breaks just as "\n"" - ([#12970](https://github.com/nim-lang/Nim/issues/12970)) -- Fixed "db_postgres.getValue issues warning when no rows found" - ([#12973](https://github.com/nim-lang/Nim/issues/12973)) -- Fixed "ARC: Unpacking tuple with seq causes segfault" - ([#12989](https://github.com/nim-lang/Nim/issues/12989)) -- Fixed "ARC/newruntime: strutils.join on seq with only empty strings causes segfault" - ([#12965](https://github.com/nim-lang/Nim/issues/12965)) -- Fixed "regression (1.0.4): `{.push exportc.}` wrongly affects generic instantiations, causing codegen errors" - ([#12985](https://github.com/nim-lang/Nim/issues/12985)) -- Fixed "cdt, crash with --gc:arc, works fine with default gc" - ([#12978](https://github.com/nim-lang/Nim/issues/12978)) -- Fixed "ARC: No indexError thrown on out-of-bound seq access, SIGSEGV instead" - ([#12961](https://github.com/nim-lang/Nim/issues/12961)) -- Fixed "ARC/async: Returning in a try-block results in wrong codegen" - ([#12956](https://github.com/nim-lang/Nim/issues/12956)) -- Fixed "asm keyword is generating wrong output C code when --cc:tcc" - ([#12988](https://github.com/nim-lang/Nim/issues/12988)) -- Fixed "Destructor not invoked" - ([#13026](https://github.com/nim-lang/Nim/issues/13026)) -- Fixed "ARC/newruntime: Adding inherited var ref object to seq with base type causes segfault" - ([#12964](https://github.com/nim-lang/Nim/issues/12964)) -- Fixed "Style check error with JS compiler target" - ([#13032](https://github.com/nim-lang/Nim/issues/13032)) -- Fixed "regression(1.0.4): undeclared identifier: 'readLines'; plus another regression and bug" - ([#13013](https://github.com/nim-lang/Nim/issues/13013)) -- Fixed "regression(1.04) `invalid pragma: since` with nim js" - ([#12996](https://github.com/nim-lang/Nim/issues/12996)) -- Fixed "Sink to MemMove optimization in injectdestructors" - ([#13002](https://github.com/nim-lang/Nim/issues/13002)) -- Fixed "--gc:arc: `catch` doesn't work with exception subclassing" - ([#13072](https://github.com/nim-lang/Nim/issues/13072)) -- Fixed "nim c --gc:arc --exceptions:{setjmp,goto} incorrectly handles raise; `nim cpp --gc:arc` is ok" - ([#13070](https://github.com/nim-lang/Nim/issues/13070)) -- Fixed "typetraits feature request - get subtype of a generic type" - ([#6454](https://github.com/nim-lang/Nim/issues/6454)) -- Fixed "CountTable inconsistencies between keys() and len() after setting value to 0" - ([#12813](https://github.com/nim-lang/Nim/issues/12813)) -- Fixed "{.align.} pragma is not applied if there is a generic field" - ([#13122](https://github.com/nim-lang/Nim/issues/13122)) -- Fixed "ARC, finalizer, allow rebinding the same function multiple times" - ([#13112](https://github.com/nim-lang/Nim/issues/13112)) -- Fixed "`nim doc` treats `export localSymbol` incorrectly" - ([#13100](https://github.com/nim-lang/Nim/issues/13100)) -- Fixed "--gc:arc SIGSEGV (double free?)" - ([#13119](https://github.com/nim-lang/Nim/issues/13119)) -- Fixed "codegen bug with arc" - ([#13105](https://github.com/nim-lang/Nim/issues/13105)) -- Fixed "symbols not defined in the grammar" - ([#10665](https://github.com/nim-lang/Nim/issues/10665)) -- Fixed "[JS] Move is not defined" - ([#9674](https://github.com/nim-lang/Nim/issues/9674)) -- Fixed "[TODO] pathutils.`/` can return invalid AbsoluteFile" - ([#13121](https://github.com/nim-lang/Nim/issues/13121)) -- Fixed "regression(1.04) `nim doc main.nim` generates broken html (no css)" - ([#12998](https://github.com/nim-lang/Nim/issues/12998)) -- Fixed "Wrong supportsCopyMem on string in type section" - ([#13095](https://github.com/nim-lang/Nim/issues/13095)) -- Fixed "Arc, finalizer, out of memory" - ([#13157](https://github.com/nim-lang/Nim/issues/13157)) -- Fixed "`--genscript` messes up nimcache and future nim invocations" - ([#13144](https://github.com/nim-lang/Nim/issues/13144)) -- Fixed "--gc:arc with --exceptions:goto for "nim c" generate invalid c code" - ([#13186](https://github.com/nim-lang/Nim/issues/13186)) -- Fixed "[regression] duplicate member `_i1` codegen bug" - ([#13195](https://github.com/nim-lang/Nim/issues/13195)) -- Fixed "RTree investigations with valgrind for --gc:arc" - ([#13110](https://github.com/nim-lang/Nim/issues/13110)) -- Fixed "relativePath("foo", ".") returns wrong path" - ([#13211](https://github.com/nim-lang/Nim/issues/13211)) -- Fixed "asyncftpclient - problem with welcome.msg" - ([#4684](https://github.com/nim-lang/Nim/issues/4684)) -- Fixed "Unclear error message, lowest priority" - ([#13256](https://github.com/nim-lang/Nim/issues/13256)) -- Fixed "Channel messages are corrupted" - ([#13219](https://github.com/nim-lang/Nim/issues/13219)) -- Fixed "Codegen bug with exportc and case objects" - ([#13281](https://github.com/nim-lang/Nim/issues/13281)) -- Fixed "[bugfix] fix #11590: c compiler warnings silently ignored, giving undefined behavior" - ([#11591](https://github.com/nim-lang/Nim/issues/11591)) -- Fixed "[CI] tnetdial flaky test" - ([#13132](https://github.com/nim-lang/Nim/issues/13132)) -- Fixed "Cross-Compiling with -d:mingw fails to locate compiler under OSX" - ([#10717](https://github.com/nim-lang/Nim/issues/10717)) -- Fixed "`nim doc --project` broken with imports below main project file or duplicate names" - ([#13150](https://github.com/nim-lang/Nim/issues/13150)) -- Fixed "regression: isNamedTuple(MyGenericTuple[int]) is false, should be true" - ([#13349](https://github.com/nim-lang/Nim/issues/13349)) -- Fixed "--gc:arc codegen bug copying objects bound to C structs with missing C struct fields" - ([#13269](https://github.com/nim-lang/Nim/issues/13269)) -- Fixed "write requires conversion to string" - ([#13182](https://github.com/nim-lang/Nim/issues/13182)) -- Fixed "Some remarks to stdlib documentation" - ([#13352](https://github.com/nim-lang/Nim/issues/13352)) -- Fixed "a `check` in unittest generated by template doesn't show actual value" - ([#6736](https://github.com/nim-lang/Nim/issues/6736)) -- Fixed "Implicit return with case expression fails with 'var' return." - ([#3339](https://github.com/nim-lang/Nim/issues/3339)) -- Fixed "Segfault with closure on arc" - ([#13314](https://github.com/nim-lang/Nim/issues/13314)) -- Fixed "[Macro] Crash on malformed case statement with multiple else" - ([#13255](https://github.com/nim-lang/Nim/issues/13255)) -- Fixed "regression: `echo 'discard' | nim c -r -` generates a file '-' ; `-` should be treated specially" - ([#13374](https://github.com/nim-lang/Nim/issues/13374)) -- Fixed "on OSX, debugging (w gdb or lldb) a nim program crashes at the 1st call to `execCmdEx`" - ([#9634](https://github.com/nim-lang/Nim/issues/9634)) -- Fixed "Internal error in getTypeDescAux" - ([#13378](https://github.com/nim-lang/Nim/issues/13378)) -- Fixed "gc:arc mode breaks tuple let" - ([#13368](https://github.com/nim-lang/Nim/issues/13368)) -- Fixed "Nim compiler hangs for certain C/C++ compiler errors" - ([#8648](https://github.com/nim-lang/Nim/issues/8648)) -- Fixed "htmlgen does not support `data-*` attributes" - ([#13444](https://github.com/nim-lang/Nim/issues/13444)) -- Fixed "[gc:arc] setLen will cause string not to be null-terminated." - ([#13457](https://github.com/nim-lang/Nim/issues/13457)) -- Fixed "joinPath("", "") is "/" ; should be """ - ([#13455](https://github.com/nim-lang/Nim/issues/13455)) -- Fixed "[CI] flaky test on windows: tests/osproc/texitcode.nim" - ([#13449](https://github.com/nim-lang/Nim/issues/13449)) -- Fixed "Casting to float32 on NimVM is broken" - ([#13479](https://github.com/nim-lang/Nim/issues/13479)) -- Fixed "`--hints:off` doesn't work (doesn't override ~/.config/nim.cfg)" - ([#8312](https://github.com/nim-lang/Nim/issues/8312)) -- Fixed "joinPath("", "") is "/" ; should be """ - ([#13455](https://github.com/nim-lang/Nim/issues/13455)) -- Fixed "tables.values is broken" - ([#13496](https://github.com/nim-lang/Nim/issues/13496)) -- Fixed "global user config can override project specific config" - ([#9405](https://github.com/nim-lang/Nim/issues/9405)) -- Fixed "Non deterministic macros and id consistency problem" - ([#12627](https://github.com/nim-lang/Nim/issues/12627)) -- Fixed "try expression doesn't work with return on expect branch" - ([#13490](https://github.com/nim-lang/Nim/issues/13490)) -- Fixed "CI will break every 4 years on feb 28: times doesn't handle leap years properly" - ([#13543](https://github.com/nim-lang/Nim/issues/13543)) -- Fixed "[minor] `nimgrep --word` doesn't work with operators (eg misses `1 +% 2`)" - ([#13528](https://github.com/nim-lang/Nim/issues/13528)) -- Fixed "`as` is usable as infix operator but its existence and precedence are not documented" - ([#13409](https://github.com/nim-lang/Nim/issues/13409)) -- Fixed "JSON unmarshalling drops seq's items" - ([#13531](https://github.com/nim-lang/Nim/issues/13531)) -- Fixed "os.joinPath returns wrong path when head ends '\' or '/' and tail starts '..'." - ([#13579](https://github.com/nim-lang/Nim/issues/13579)) -- Fixed "Block-local types with the same name lead to bad codegen (sighashes regression)" - ([#5170](https://github.com/nim-lang/Nim/issues/5170)) -- Fixed "tuple codegen error" - ([#12704](https://github.com/nim-lang/Nim/issues/12704)) -- Fixed "newHttpHeaders does not accept repeated headers" - ([#13573](https://github.com/nim-lang/Nim/issues/13573)) -- Fixed "regression: --incremental:on fails on simplest example" - ([#13319](https://github.com/nim-lang/Nim/issues/13319)) -- Fixed "strscan can't get value of last element in format" - ([#13605](https://github.com/nim-lang/Nim/issues/13605)) -- Fixed "hashes_examples crashes with "Bus Error" (unaligned access) on sparc64" - ([#12508](https://github.com/nim-lang/Nim/issues/12508)) -- Fixed "gc:arc bug with re-used `seq[T]`" - ([#13596](https://github.com/nim-lang/Nim/issues/13596)) -- Fixed "`raise CatchableError` is broken with --gc:arc when throwing inside a proc" - ([#13599](https://github.com/nim-lang/Nim/issues/13599)) -- Fixed "cpp --gc:arc --exceptions:goto fails to raise with discard" - ([#13436](https://github.com/nim-lang/Nim/issues/13436)) -- Fixed "terminal doesn't compile with -d:useWinAnsi" - ([#13607](https://github.com/nim-lang/Nim/issues/13607)) -- Fixed "Parsing "sink ptr T" - region needs to be an object type" - ([#12757](https://github.com/nim-lang/Nim/issues/12757)) -- Fixed "gc:arc + threads:on + closures compilation error" - ([#13519](https://github.com/nim-lang/Nim/issues/13519)) -- Fixed "[ARC] segmentation fault" - ([#13240](https://github.com/nim-lang/Nim/issues/13240)) -- Fixed "times.toDateTime buggy on 29th, 30th and 31th of each month" - ([#13558](https://github.com/nim-lang/Nim/issues/13558)) -- Fixed "Deque misbehaves on VM" - ([#13310](https://github.com/nim-lang/Nim/issues/13310)) -- Fixed "Nimscript listFiles should throw exception when path is not found" - ([#12676](https://github.com/nim-lang/Nim/issues/12676)) -- Fixed "koch boot fails if even an empty config.nims is present in ~/.config/nims/ [devel regression]" - ([#13633](https://github.com/nim-lang/Nim/issues/13633)) -- Fixed "nim doc generates lots of false positive LockLevel warnings" - ([#13218](https://github.com/nim-lang/Nim/issues/13218)) -- Fixed "Arrays are passed by copy to iterators, causing crashes, unnecessary allocations and slowdowns" - ([#12747](https://github.com/nim-lang/Nim/issues/12747)) -- Fixed "Range types always uses signed integer as a base type" - ([#13646](https://github.com/nim-lang/Nim/issues/13646)) -- Fixed "Generate c code cannot compile with recent devel version" - ([#13645](https://github.com/nim-lang/Nim/issues/13645)) -- Fixed "[regression] VM: Error: cannot convert -1 to uint64" - ([#13661](https://github.com/nim-lang/Nim/issues/13661)) -- Fixed "Spurious raiseException(Exception) detected" - ([#13654](https://github.com/nim-lang/Nim/issues/13654)) -- Fixed "gc:arc memory leak" - ([#13659](https://github.com/nim-lang/Nim/issues/13659)) -- Fixed "Error: cannot convert -1 to uint (inside tuples)" - ([#13671](https://github.com/nim-lang/Nim/issues/13671)) -- Fixed "strformat issue with --gc:arc" - ([#13622](https://github.com/nim-lang/Nim/issues/13622)) -- Fixed "astToStr doesn't work inside generics" - ([#13524](https://github.com/nim-lang/Nim/issues/13524)) -- Fixed "oswalkdir.walkDirRec wont return folders" - ([#11458](https://github.com/nim-lang/Nim/issues/11458)) -- Fixed "`echo 'echo 1' | nim c -r -` silently gives wrong results (nimBetterRun not updated for stdin)" - ([#13412](https://github.com/nim-lang/Nim/issues/13412)) -- Fixed "gc:arc destroys the global variable accidentally." - ([#13691](https://github.com/nim-lang/Nim/issues/13691)) -- Fixed "[minor] sigmatch errors should be sorted, for reproducible errors" - ([#13538](https://github.com/nim-lang/Nim/issues/13538)) -- Fixed "Exception when converting csize to clong" - ([#13698](https://github.com/nim-lang/Nim/issues/13698)) -- Fixed "ARC: variables are no copied on the thread spawn causing crashes" - ([#13708](https://github.com/nim-lang/Nim/issues/13708)) -- Fixed "Illegal distinct seq causes compiler crash" - ([#13720](https://github.com/nim-lang/Nim/issues/13720)) -- Fixed "cyclic seq definition crashes the compiler" - ([#13715](https://github.com/nim-lang/Nim/issues/13715)) -- Fixed "Iterator with openArray parameter make the argument evaluated many times" - ([#13417](https://github.com/nim-lang/Nim/issues/13417)) -- Fixed "net/asyncnet: Unable to access peer's certificate chain" - ([#13299](https://github.com/nim-lang/Nim/issues/13299)) -- Fixed "Accidentally "SIGSEGV: Illegal storage access" error after arc optimizations (#13325)" - ([#13709](https://github.com/nim-lang/Nim/issues/13709)) -- Fixed "Base64 Regression" - ([#13722](https://github.com/nim-lang/Nim/issues/13722)) -- Fixed "A regression (?) with --gc:arc and repr" - ([#13731](https://github.com/nim-lang/Nim/issues/13731)) -- Fixed "Internal compiler error when using the new variable pragmas" - ([#13737](https://github.com/nim-lang/Nim/issues/13737)) -- Fixed "bool conversion produces vcc 2019 warning at cpp compilation stage" - ([#13744](https://github.com/nim-lang/Nim/issues/13744)) -- Fixed "Compiler "does not detect" a type recursion error in the wrong code, remaining frozen" - ([#13763](https://github.com/nim-lang/Nim/issues/13763)) -- Fixed "[minor] regression: `Foo[0.0] is Foo[-0.0]` is now false" - ([#13730](https://github.com/nim-lang/Nim/issues/13730)) -- Fixed "`nim doc` - only whitespace on first line causes segfault" - ([#13631](https://github.com/nim-lang/Nim/issues/13631)) -- Fixed "hashset regression" - ([#13794](https://github.com/nim-lang/Nim/issues/13794)) -- Fixed "`os.getApplFreebsd` could return incorrect paths in the case of a long path" - ([#13806](https://github.com/nim-lang/Nim/issues/13806)) -- Fixed "Destructors are not inherited" - ([#13810](https://github.com/nim-lang/Nim/issues/13810)) -- Fixed "io.readLines AssertionError on devel" - ([#13829](https://github.com/nim-lang/Nim/issues/13829)) -- Fixed "exceptions:goto accidentally reset the variable during exception handling" - ([#13782](https://github.com/nim-lang/Nim/issues/13782)) diff --git a/changelogs/changelog_1_4_0.md b/changelogs/changelog_1_4_0.md deleted file mode 100644 index 77f66ffde..000000000 --- a/changelogs/changelog_1_4_0.md +++ /dev/null @@ -1,874 +0,0 @@ -# v1.4.0 - 2020-10-16 - - - -## Standard library additions and changes - -- Added some enhancements to `std/jsonutils` module. - * Added a possibility to deserialize JSON arrays directly to `HashSet` and - `OrderedSet` types and respectively to serialize those types to JSON arrays - via `jsonutils.fromJson` and `jsonutils.toJson` procedures. - * Added a possibility to deserialize JSON `null` objects to Nim option objects - and respectively to serialize Nim option object to JSON object if `isSome` - or to JSON null object if `isNone` via `jsonutils.fromJson` and - `jsonutils.toJson` procedures. - * Added a `Joptions` parameter to `jsonutils.fromJson` currently - containing two boolean options `allowExtraKeys` and `allowMissingKeys`. - - If `allowExtraKeys` is `true` Nim's object to which the JSON is parsed is - not required to have a field for every JSON key. - - If `allowMissingKeys` is `true` Nim's object to which JSON is parsed is - allowed to have fields without corresponding JSON keys. -- Added `bindParams`, `bindParam` to `db_sqlite` for binding parameters into a `SqlPrepared` statement. -- Added `tryInsert`,`insert` procs to `db_*` libs which accept primary key column name. -- Added `xmltree.newVerbatimText` support create `style`'s,`script`'s text. -- `uri` module now implements RFC-2397. -- Added [DOM Parser](https://developer.mozilla.org/en-US/docs/Web/API/DOMParser) - to the `dom` module for the JavaScript target. -- The default hash for `Ordinal` has changed to something more bit-scrambling. - `import hashes; proc hash(x: myInt): Hash = hashIdentity(x)` recovers the old - one in an instantiation context while `-d:nimIntHash1` recovers it globally. -- `deques.peekFirst` and `deques.peekLast` now have `var Deque[T] -> var T` overloads. -- File handles created from high-level abstractions in the stdlib will no longer - be inherited by child processes. In particular, these modules are affected: - `asyncdispatch`, `asyncnet`, `system`, `nativesockets`, `net` and `selectors`. - - For `asyncdispatch`, `asyncnet`, `net` and `nativesockets`, an `inheritable` - flag has been added to all `proc`s that create sockets, allowing the user to - control whether the resulting socket is inheritable. This flag is provided to - ease the writing of multi-process servers, where sockets inheritance is - desired. - - For a transition period, define `nimInheritHandles` to enable file handle - inheritance by default. This flag does **not** affect the `selectors` module - due to the differing semantics between operating systems. - - `asyncdispatch.setInheritable`, `system.setInheritable` and - `nativesockets.setInheritable` are also introduced for setting file handle or - socket inheritance. Not all platforms have these `proc`s defined. - -- The file descriptors created for internal bookkeeping by `ioselector_kqueue` - and `ioselector_epoll` will no longer be leaked to child processes. - -- `strutils.formatFloat` with `precision = 0` has been restored to the version - 1 behaviour that produces a trailing dot, e.g. `formatFloat(3.14159, precision = 0)` - is now `3.`, not `3`. -- Added `commonPrefixLen` to `critbits`. - -- `relativePath(rel, abs)` and `relativePath(abs, rel)` used to silently give wrong results - (see #13222); instead they now use `getCurrentDir` to resolve those cases, - and this can now throw in edge cases where `getCurrentDir` throws. - `relativePath` also now works for js with `-d:nodejs`. - -- JavaScript and NimScript standard library changes: `streams.StringStream` is - now supported in JavaScript, with the limitation that any buffer `pointer`s - used must be castable to `ptr string`, any incompatible pointer type will not - work. The `lexbase` and `streams` modules used to fail to compile on - NimScript due to a bug, but this has been fixed. - - The following modules now compile on both JS and NimScript: `parsecsv`, - `parsecfg`, `parsesql`, `xmlparser`, `htmlparser` and `ropes`. Additionally - supported for JS is `cstrutils.startsWith` and `cstrutils.endsWith`, for - NimScript: `json`, `parsejson`, `strtabs` and `unidecode`. - -- Added `streams.readStr` and `streams.peekStr` overloads to - accept an existing string to modify, which avoids memory - allocations, similar to `streams.readLine` (#13857). - -- Added high-level `asyncnet.sendTo` and `asyncnet.recvFrom` UDP functionality. - -- `dollars.$` now works for unsigned ints with `nim js`. - -- Improvements to the `bitops` module, including bitslices, non-mutating versions - of the original masking functions, `mask`/`masked`, and varargs support for - `bitand`, `bitor`, and `bitxor`. - -- `sugar.=>` and `sugar.->` changes: Previously `(x, y: int)` was transformed - into `(x: auto, y: int)`, it now becomes `(x: int, y: int)` for consistency - with regular proc definitions (although you cannot use semicolons). - - Pragmas and using a name are now allowed on the lefthand side of `=>`. Here - is an example of these changes: - ```nim - import sugar - - foo(x, y: int) {.noSideEffect.} => x + y - - # is transformed into - - proc foo(x: int, y: int): auto {.noSideEffect.} = x + y - ``` - -- The fields of `times.DateTime` are now private, and are accessed with getters and deprecated setters. - -- The `times` module now handles the default value for `DateTime` more consistently. - Most procs raise an assertion error when given - an uninitialized `DateTime`, the exceptions are `==` and `$` (which returns `"Uninitialized DateTime"`). - The proc `times.isInitialized` has been added which can be used to check if - a `DateTime` has been initialized. - -- Fix a bug where calling `close` on io streams in `osproc.startProcess` was a noop and led to - hangs if a process had both reads from stdin and writes (e.g. to stdout). - -- The callback that is passed to `system.onThreadDestruction` must now be `.raises: []`. -- The callback that is assigned to `system.onUnhandledException` must now be `.gcsafe`. - -- `osproc.execCmdEx` now takes an optional `input` for stdin, `workingDir` and `env` - parameters. - -- Added a `ssl_config` module containing lists of secure ciphers as recommended by - [Mozilla OpSec](https://wiki.mozilla.org/Security/Server_Side_TLS) - -- `net.newContext` now defaults to the list of ciphers targeting - ["Intermediate compatibility"](https://wiki.mozilla.org/Security/Server_Side_TLS#Intermediate_compatibility_.28recommended.29) - per Mozilla's recommendation instead of `ALL`. This change should protect - users from the use of weak and insecure ciphers while still provides - adequate compatibility with the majority of the Internet. - -- A new module `std/jsonutils` with hookable `jsonTo,toJson,fromJson` operations for json - serialization/deserialization of custom types was added. - -- A new proc `heapqueue.find[T](heap: HeapQueue[T], x: T): int` to get index of element ``x`` - was added. -- Added `rstgen.rstToLatex` a convenience proc for `renderRstToOut` and `initRstGenerator`. -- Added `os.normalizeExe`. -- `macros.newLit` now preserves named vs unnamed tuples. -- Added `random.gauss`, that uses the ratio of uniforms method of sampling from a Gaussian distribution. -- Added `typetraits.elementType` to get the element type of an iterable. -- `typetraits.$` changes: `$(int,)` is now `"(int,)"` instead of `"(int)"`; - `$tuple[]` is now `"tuple[]"` instead of `"tuple"`; - `$((int, float), int)` is now `"((int, float), int)"` instead of `"(tuple of (int, float), int)"` -- Added `macros.extractDocCommentsAndRunnables` helper. - -- `strformat.fmt` and `strformat.&` support `specifier =`. `fmt"{expr=}"` now - expands to `fmt"expr={expr}"`. -- Deprecations: instead of `os.existsDir` use `dirExists`, instead of `os.existsFile` use `fileExists`. - -- Added the `jsre` module, [Regular Expressions for the JavaScript target.](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions). -- Made `maxLines` argument `Positive` in `logging.newRollingFileLogger`, - because negative values will result in a new file being created for each logged - line which doesn't make sense. -- Changed `log` in `logging` to use proper log level for JavaScript, - e.g. `debug` uses `console.debug`, `info` uses `console.info`, `warn` uses `console.warn`, etc. -- Tables, HashSets, SharedTables and deques don't require anymore that the passed - initial size must be a power of two - this is done internally. - Proc `rightSize` for Tables and HashSets is deprecated, as it is not needed anymore. - `CountTable.inc` takes `val: int` again not `val: Positive`; i.e. it can "count down" again. -- Removed deprecated symbols from `macros` module, some of which were deprecated already in `0.15`. -- Removed `sugar.distinctBase`, deprecated since `0.19`. Use `typetraits.distinctBase`. -- `asyncdispatch.PDispatcher.handles` is exported so that an external low-level libraries can access it. - -- `std/with`, `sugar.dup` now support object field assignment expressions: - ```nim - import std/with - - type Foo = object - x, y: int - - var foo = Foo() - with foo: - x = 10 - y = 20 - - echo foo - ``` - -- Proc `math.round` is no longer deprecated. The advice to use `strformat` instead - cannot be applied to every use case. The limitations and the (lack of) reliability - of `round` are well documented. - -- Added `getprotobyname` to `winlean`. Added `getProtoByname` to `nativesockets` which returns a protocol code - from the database that matches the protocol `name`. - -- Added missing attributes and methods to `dom.Navigator` like `deviceMemory`, `onLine`, `vibrate()`, etc. - -- Added `strutils.indentation` and `strutils.dedent` which enable indented string literals: - ```nim - import strutils - echo dedent """ - This - is - cool! - """ - ``` - -- Added `initUri(isIpv6: bool)` to `uri` module, now `uri` supports parsing ipv6 hostname. - -- Added `readLines(p: Process)` to `osproc`. - -- Added the below `toX` procs for collections. The usage is similar to procs such as - `sets.toHashSet` and `tables.toTable`. Previously, it was necessary to create the - respective empty collection and add items manually. - * `critbits.toCritBitTree`, which creates a `CritBitTree` from an `openArray` of - items or an `openArray` of pairs. - * `deques.toDeque`, which creates a `Deque` from an `openArray`. - * `heapqueue.toHeapQueue`, which creates a `HeapQueue` from an `openArray`. - * `intsets.toIntSet`, which creates an `IntSet` from an `openArray`. - -- Added `progressInterval` argument to `asyncftpclient.newAsyncFtpClient` to control the interval - at which progress callbacks are called. - -- Added `os.copyFileToDir`. - -## Language changes - -- The `=destroy` hook no longer has to reset its target, as the compiler now automatically inserts - `wasMoved` calls where needed. -- The `=` hook is now called `=copy` for clarity. The old name `=` is still available so there - is no need to update your code. This change was backported to 1.2 too so you can use the - more readable `=copy` without loss of compatibility. - -- In the newruntime it is now allowed to assign to the discriminator field - without restrictions as long as the case object doesn't have a custom destructor. - The discriminator value doesn't have to be a constant either. If you have a - custom destructor for a case object and you do want to freely assign discriminator - fields, it is recommended to refactor the object into 2 objects like this: - - ```nim - type - MyObj = object - case kind: bool - of true: y: ptr UncheckedArray[float] - of false: z: seq[int] - - proc `=destroy`(x: MyObj) = - if x.kind and x.y != nil: - deallocShared(x.y) - ``` - Refactor into: - ```nim - type - MySubObj = object - val: ptr UncheckedArray[float] - MyObj = object - case kind: bool - of true: y: MySubObj - of false: z: seq[int] - - proc `=destroy`(x: MySubObj) = - if x.val != nil: - deallocShared(x.val) - ``` -- `getImpl` on enum type symbols now returns field syms instead of idents. This helps - with writing typed macros. The old behavior for backwards compatibility can be restored - with `--useVersion:1.0`. -- The typed AST for proc headers will now have the arguments be syms instead of idents. - This helps with writing typed macros. The old behaviour for backwards compatibility can - be restored with `--useVersion:1.0`. -- ``let`` statements can now be used without a value if declared with - ``importc``/``importcpp``/``importjs``/``importobjc``. -- The keyword `from` is now usable as an operator. -- Exceptions inheriting from `system.Defect` are no longer tracked with - the `.raises: []` exception tracking mechanism. This is more consistent with the - built-in operations. The following always used to compile (and still does): - ```nim - proc mydiv(a, b): int {.raises: [].} = - a div b # can raise an DivByZeroDefect - ``` - - Now also this compiles: - ```nim - proc mydiv(a, b): int {.raises: [].} = - if b == 0: raise newException(DivByZeroDefect, "division by zero") - else: result = a div b - ``` - - The reason for this is that `DivByZeroDefect` inherits from `Defect` and - with `--panics:on` `Defects` become unrecoverable errors. - -- Added the `thiscall` calling convention as specified by Microsoft, mostly for hooking purposes. -- Deprecated the `{.unroll.}` pragma, because it was always ignored by the compiler anyway. -- Removed the deprecated `strutils.isNilOrWhitespace`. -- Removed the deprecated `sharedtables.initSharedTable`. -- Removed the deprecated `asyncdispatch.newAsyncNativeSocket`. -- Removed the deprecated `dom.releaseEvents` and `dom.captureEvents`. - -- Removed `sharedlist.initSharedList`, was deprecated and produces undefined behaviour. - -- There is a new experimental feature called "strictFuncs" which makes the definition of - `.noSideEffect` stricter. [See here](manual_experimental.html#stricts-funcs) - for more information. - -- "for-loop macros" (see [the manual](manual.html#macros-for-loop-macros)) are no longer - an experimental feature. In other words, you don't have to write pragma - `{.experimental: "forLoopMacros".}` if you want to use them. - -- Added the ``.noalias`` pragma. It is mapped to C's ``restrict`` keyword for the increased - performance this keyword can enable. - -- `items` no longer compiles with enums with holes as its behavior was error prone, see #14004. -- `system.deepcopy` has to be enabled explicitly for `--gc:arc` and `--gc:orc` via - `--deepcopy:on`. - -- Added the `std/effecttraits` module for introspection of the inferred effects. - We hope this enables `async` macros that are precise about the possible exceptions that - can be raised. -- The pragma blocks `{.gcsafe.}: ...` and `{.noSideEffect.}: ...` can now also be - written as `{.cast(gcsafe).}: ...` and `{.cast(noSideEffect).}: ...`. This is the new - preferred way of writing these, emphasizing their unsafe nature. - - -## Compiler changes - -- Specific warnings can now be turned into errors via `--warningAsError[X]:on|off`. -- The `define` and `undef` pragmas have been de-deprecated. -- New command: `nim r main.nim [args...]` which compiles and runs main.nim, and implies `--usenimcache` - so that the output is saved to $nimcache/main$exeExt, using the same logic as `nim c -r` to - avoid recompilations when sources don't change. - Example: - ```bash - nim r compiler/nim.nim --help # only compiled the first time - echo 'import os; echo getCurrentCompilerExe()' | nim r - # this works too - nim r compiler/nim.nim --fullhelp # no recompilation - nim r --nimcache:/tmp main # binary saved to /tmp/main - ``` -- `--hint:processing` is now supported and means `--hint:processing:on` - (likewise with other hints and warnings), which is consistent with all other bool flags. - (since 1.3.3). -- `nim doc -r main` and `nim rst2html -r main` now call `openDefaultBrowser`. -- Added the new hint `--hint:msgOrigin` will show where a compiler msg (hint|warning|error) - was generated; this helps in particular when it's non obvious where it came from - either because multiple locations generate the same message, or because the - message involves runtime formatting. -- Added the new flag `--backend:js|c|cpp|objc` (or -b:js etc), to change the backend; can be - used with any command (e.g. nim r, doc, check etc); safe to re-assign. -- Added the new flag `--doccmd:cmd` to pass additional flags for runnableExamples, - e.g.: `--doccmd:-d:foo --threads` - use `--doccmd:skip` to skip runnableExamples and rst test snippets. -- Added the new flag `--usenimcache` to output binary files to nimcache. -- `runnableExamples "-b:cpp -r:off": code` is now supported, allowing to override - how an example is compiled and run, for example to change the backend. -- `nim doc` now outputs under `$projectPath/htmldocs` when `--outdir` is unspecified - (with or without `--project`); passing `--project` now automatically generates - an index and enables search. - See [docgen](docgen.html#introduction-quick-start) for details. -- Removed the `--oldNewlines` switch. -- Removed the `--laxStrings` switch for mutating the internal zero terminator on strings. -- Removed the `--oldast` switch. -- Removed the `--oldgensym` switch. -- `$getType(untyped)` is now "untyped" instead of "expr", `$getType(typed)` is - now "typed" instead of "stmt". -- Sink inference is now disabled per default and has to enabled explicitly via - `--sinkInference:on`. *Note*: For the standard library sink inference remains - enabled. This change is most relevant for the `--gc:arc`, `--gc:orc` memory - management modes. - - -## Tool changes - -- `nimsuggest` now returns both the forward declaration and the - implementation location upon a `def` query. Previously the behavior was - to return the forward declaration only. - - -## Bugfixes - -- Fixed "repr() not available for uint{,8,16,32,64} under --gc:arc" - ([#13872](https://github.com/nim-lang/Nim/issues/13872)) -- Fixed "Critical: 1 completed Future, multiple await: Only 1 await will be awakened (the last one)" - ([#13889](https://github.com/nim-lang/Nim/issues/13889)) -- Fixed "crash on openarray interator with argument in stmtListExpr" - ([#13739](https://github.com/nim-lang/Nim/issues/13739)) -- Fixed "Some compilers on Windows don't work" - ([#13910](https://github.com/nim-lang/Nim/issues/13910)) -- Fixed "httpclient hangs if it recieves an HTTP 204 (No Content)" - ([#13894](https://github.com/nim-lang/Nim/issues/13894)) -- Fixed ""distinct uint64" type corruption on 32-bit, when using {.borrow.} operators" - ([#13902](https://github.com/nim-lang/Nim/issues/13902)) -- Fixed "Regression: impossible to use typed pragmas with proc types" - ([#13909](https://github.com/nim-lang/Nim/issues/13909)) -- Fixed "openssl wrapper corrupts stack on OpenSSL 1.1.1f + Android" - ([#13903](https://github.com/nim-lang/Nim/issues/13903)) -- Fixed "C compile error with --gc:arc on version 1.2.0 "unknown type name 'TGenericSeq'" - ([#13863](https://github.com/nim-lang/Nim/issues/13863)) -- Fixed "var return type for proc doesn't work at c++ backend" - ([#13848](https://github.com/nim-lang/Nim/issues/13848)) -- Fixed "TimeFormat() should raise an error but craches at compilation time" - ([#12864](https://github.com/nim-lang/Nim/issues/12864)) -- Fixed "gc:arc cannot fully support threadpool with FlowVar" - ([#13781](https://github.com/nim-lang/Nim/issues/13781)) -- Fixed "simple 'var openarray[char]' assignment crash when the openarray source is a local string and using gc:arc" - ([#14003](https://github.com/nim-lang/Nim/issues/14003)) -- Fixed "Cant use expressions with `when` in `type` sections." - ([#14007](https://github.com/nim-lang/Nim/issues/14007)) -- Fixed "`for a in MyEnum` gives incorrect results with enum with holes" - ([#14001](https://github.com/nim-lang/Nim/issues/14001)) -- Fixed "Trivial crash" - ([#12741](https://github.com/nim-lang/Nim/issues/12741)) -- Fixed "Enum with holes cannot be used as Table index" - ([#12834](https://github.com/nim-lang/Nim/issues/12834)) -- Fixed "spawn proc that uses typedesc crashes the compiler" - ([#14014](https://github.com/nim-lang/Nim/issues/14014)) -- Fixed "Docs Search `Results` box styling is not Dark Mode Friendly" - ([#13972](https://github.com/nim-lang/Nim/issues/13972)) -- Fixed "--gc:arc -d:useSysAssert undeclared identifier `cstderr` with newSeq" - ([#14038](https://github.com/nim-lang/Nim/issues/14038)) -- Fixed "issues in the manual" - ([#12486](https://github.com/nim-lang/Nim/issues/12486)) -- Fixed "Annoying warning: inherit from a more precise exception type like ValueError, IOError or OSError [InheritFromException]" - ([#14052](https://github.com/nim-lang/Nim/issues/14052)) -- Fixed "relativePath("foo", "/") and relativePath("/", "foo") is wrong" - ([#13222](https://github.com/nim-lang/Nim/issues/13222)) -- Fixed "[regression] `parseEnum` does not work anymore for enums with holes" - ([#14030](https://github.com/nim-lang/Nim/issues/14030)) -- Fixed "Exception types in the stdlib should inherit from `CatchableError` or `Defect`, not `Exception`" - ([#10288](https://github.com/nim-lang/Nim/issues/10288)) -- Fixed "Make debugSend and debugRecv procs public in smtp.nim" - ([#12189](https://github.com/nim-lang/Nim/issues/12189)) -- Fixed "xmltree need add raw text, when add style element" - ([#14064](https://github.com/nim-lang/Nim/issues/14064)) -- Fixed "raises requirement does not propagate to derived methods" - ([#8481](https://github.com/nim-lang/Nim/issues/8481)) -- Fixed "tests/stdlib/tgetaddrinfo.nim fails on NetBSD" - ([#14091](https://github.com/nim-lang/Nim/issues/14091)) -- Fixed "tests/niminaction/Chapter8/sdl/sdl_test.nim fails on NetBSD" - ([#14088](https://github.com/nim-lang/Nim/issues/14088)) -- Fixed "Incorrect escape sequence for example in jsffi library documentation" - ([#14110](https://github.com/nim-lang/Nim/issues/14110)) -- Fixed "HCR: Can not link exported const, in external library" - ([#13915](https://github.com/nim-lang/Nim/issues/13915)) -- Fixed "Cannot import std/unidecode" - ([#14112](https://github.com/nim-lang/Nim/issues/14112)) -- Fixed "macOS: dsymutil should not be called on static libraries" - ([#14132](https://github.com/nim-lang/Nim/issues/14132)) -- Fixed "nim jsondoc -o:doc.json filename.nim fails when sequences without a type are used" - ([#14066](https://github.com/nim-lang/Nim/issues/14066)) -- Fixed "algorithm.sortedByIt template corrupts tuple input under --gc:arc" - ([#14079](https://github.com/nim-lang/Nim/issues/14079)) -- Fixed "Invalid C code with lvalue conversion" - ([#14160](https://github.com/nim-lang/Nim/issues/14160)) -- Fixed "strformat: doc example fails" - ([#14054](https://github.com/nim-lang/Nim/issues/14054)) -- Fixed "Nim doc fail to run for nim 1.2.0 (nim 1.0.4 is ok)" - ([#13986](https://github.com/nim-lang/Nim/issues/13986)) -- Fixed "Exception when converting csize to clong" - ([#13698](https://github.com/nim-lang/Nim/issues/13698)) -- Fixed "[Documentation] overloading using named arguments works but is not documented" - ([#11932](https://github.com/nim-lang/Nim/issues/11932)) -- Fixed "import os + use of existsDir/dirExists/existsFile/fileExists/findExe in config.nims causes "ambiguous call' error" - ([#14142](https://github.com/nim-lang/Nim/issues/14142)) -- Fixed "import os + use of existsDir/dirExists/existsFile/fileExists/findExe in config.nims causes "ambiguous call' error" - ([#14142](https://github.com/nim-lang/Nim/issues/14142)) -- Fixed "runnableExamples doc gen crashes compiler with `except Exception as e` syntax" - ([#14177](https://github.com/nim-lang/Nim/issues/14177)) -- Fixed "[ARC] Segfault with cyclic references (?)" - ([#14159](https://github.com/nim-lang/Nim/issues/14159)) -- Fixed "Semcheck regression when accessing a static parameter in proc" - ([#14136](https://github.com/nim-lang/Nim/issues/14136)) -- Fixed "iterator walkDir doesn't work with -d:useWinAnsi" - ([#14201](https://github.com/nim-lang/Nim/issues/14201)) -- Fixed "cas is wrong for tcc" - ([#14151](https://github.com/nim-lang/Nim/issues/14151)) -- Fixed "proc execCmdEx doesn't work with -d:useWinAnsi" - ([#14203](https://github.com/nim-lang/Nim/issues/14203)) -- Fixed "Use -d:nimEmulateOverflowChecks by default?" - ([#14209](https://github.com/nim-lang/Nim/issues/14209)) -- Fixed "Old sequences with destructor objects bug" - ([#14217](https://github.com/nim-lang/Nim/issues/14217)) -- Fixed "[ARC] ICE when changing the discriminant of a return value" - ([#14244](https://github.com/nim-lang/Nim/issues/14244)) -- Fixed "[ARC] ICE with static objects" - ([#14236](https://github.com/nim-lang/Nim/issues/14236)) -- Fixed "[ARC] "internal error: environment misses: a" in a finalizer" - ([#14243](https://github.com/nim-lang/Nim/issues/14243)) -- Fixed "[ARC] compile failure using repr with object containing `ref seq[string]`" - ([#14270](https://github.com/nim-lang/Nim/issues/14270)) -- Fixed "[ARC] implicit move on last use happening on non-last use" - ([#14269](https://github.com/nim-lang/Nim/issues/14269)) -- Fixed "[ARC] Compiler crash with a recursive non-ref object variant" - ([#14294](https://github.com/nim-lang/Nim/issues/14294)) -- Fixed "htmlparser.parseHtml behaves differently using --gc:arc or --gc:orc" - ([#13946](https://github.com/nim-lang/Nim/issues/13946)) -- Fixed "Invalid return value of openProcess is NULL rather than INVALID_HANDLE_VALUE(-1) in windows" - ([#14289](https://github.com/nim-lang/Nim/issues/14289)) -- Fixed "ARC codegen bug with inline iterators" - ([#14219](https://github.com/nim-lang/Nim/issues/14219)) -- Fixed "Building koch on OpenBSD fails unless the Nim directory is in `$PATH`" - ([#13758](https://github.com/nim-lang/Nim/issues/13758)) -- Fixed "[gc:arc] case object assignment SIGSEGV: destroy not called for primitive type " - ([#14312](https://github.com/nim-lang/Nim/issues/14312)) -- Fixed "Crash when using thread and --gc:arc " - ([#13881](https://github.com/nim-lang/Nim/issues/13881)) -- Fixed "Getting "Warning: Cannot prove that 'result' is initialized" for an importcpp'd proc with `var T` return type" - ([#14314](https://github.com/nim-lang/Nim/issues/14314)) -- Fixed "`nim cpp -r --gc:arc` segfaults on caught AssertionError" - ([#13071](https://github.com/nim-lang/Nim/issues/13071)) -- Fixed "tests/async/tasyncawait.nim is recently very flaky" - ([#14320](https://github.com/nim-lang/Nim/issues/14320)) -- Fixed "Documentation nonexistent quitprocs module" - ([#14331](https://github.com/nim-lang/Nim/issues/14331)) -- Fixed "SIGSEV encountered when creating threads in a loop w/ --gc:arc" - ([#13935](https://github.com/nim-lang/Nim/issues/13935)) -- Fixed "nim-gdb is missing from all released packages" - ([#13104](https://github.com/nim-lang/Nim/issues/13104)) -- Fixed "sysAssert error with gc:arc on 3 line program" - ([#13862](https://github.com/nim-lang/Nim/issues/13862)) -- Fixed "compiler error with inline async proc and pragma" - ([#13998](https://github.com/nim-lang/Nim/issues/13998)) -- Fixed "[ARC] Compiler crash when adding to a seq[ref Object]" - ([#14333](https://github.com/nim-lang/Nim/issues/14333)) -- Fixed "nimvm: sysFatal: unhandled exception: 'sons' is not accessible using discriminant 'kind' of type 'TNode' [FieldError]" - ([#14340](https://github.com/nim-lang/Nim/issues/14340)) -- Fixed "[Regression] karax events are not firing " - ([#14350](https://github.com/nim-lang/Nim/issues/14350)) -- Fixed "odbcsql module has some wrong integer types" - ([#9771](https://github.com/nim-lang/Nim/issues/9771)) -- Fixed "db_sqlite needs sqlPrepared" - ([#13559](https://github.com/nim-lang/Nim/issues/13559)) -- Fixed "[Regression] `createThread` is not GC-safe" - ([#14370](https://github.com/nim-lang/Nim/issues/14370)) -- Fixed "Broken example on hot code reloading" - ([#14380](https://github.com/nim-lang/Nim/issues/14380)) -- Fixed "runnableExamples block with `except` on specified error fails with `nim doc`" - ([#12746](https://github.com/nim-lang/Nim/issues/12746)) -- Fixed "compiler as a library: findNimStdLibCompileTime fails to find system.nim" - ([#12293](https://github.com/nim-lang/Nim/issues/12293)) -- Fixed "5 bugs with importcpp exceptions" - ([#14369](https://github.com/nim-lang/Nim/issues/14369)) -- Fixed "Docs shouldn't collapse pragmas inside runnableExamples/code blocks" - ([#14174](https://github.com/nim-lang/Nim/issues/14174)) -- Fixed "Bad codegen/emit for hashes.hiXorLo in some contexts." - ([#14394](https://github.com/nim-lang/Nim/issues/14394)) -- Fixed "Boehm GC does not scan thread-local storage" - ([#14364](https://github.com/nim-lang/Nim/issues/14364)) -- Fixed "RVO not exception safe" - ([#14126](https://github.com/nim-lang/Nim/issues/14126)) -- Fixed "runnableExamples that are only compiled" - ([#10731](https://github.com/nim-lang/Nim/issues/10731)) -- Fixed "`foldr` raises IndexError when called on sequence" - ([#14404](https://github.com/nim-lang/Nim/issues/14404)) -- Fixed "moveFile does not overwrite destination file" - ([#14057](https://github.com/nim-lang/Nim/issues/14057)) -- Fixed "doc2 outputs in current work dir" - ([#6583](https://github.com/nim-lang/Nim/issues/6583)) -- Fixed "[docgen] proc doc comments silently omitted after 1st runnableExamples" - ([#9227](https://github.com/nim-lang/Nim/issues/9227)) -- Fixed "`nim doc --project` shows '@@/' instead of '../' for relative paths to submodules" - ([#14448](https://github.com/nim-lang/Nim/issues/14448)) -- Fixed "re, nre have wrong `start` semantics" - ([#14284](https://github.com/nim-lang/Nim/issues/14284)) -- Fixed "runnableExamples should preserve source code doc comments, strings, and (maybe) formatting" - ([#8871](https://github.com/nim-lang/Nim/issues/8871)) -- Fixed "`nim doc ..` fails when runnableExamples uses `$` [devel] [regression]" - ([#14485](https://github.com/nim-lang/Nim/issues/14485)) -- Fixed "`items` is 20%~30% slower than iteration via an index" - ([#14421](https://github.com/nim-lang/Nim/issues/14421)) -- Fixed "ARC: unreliable setLen " - ([#14495](https://github.com/nim-lang/Nim/issues/14495)) -- Fixed "lent is unsafe: after #14447 you can modify variables with "items" loop for sequences" - ([#14498](https://github.com/nim-lang/Nim/issues/14498)) -- Fixed "`var op = fn()` wrongly gives warning `ObservableStores` with `object of RootObj` type" - ([#14514](https://github.com/nim-lang/Nim/issues/14514)) -- Fixed "Compiler assertion" - ([#14562](https://github.com/nim-lang/Nim/issues/14562)) -- Fixed "Can't get `ord` of a value of a Range type in the JS backend " - ([#14570](https://github.com/nim-lang/Nim/issues/14570)) -- Fixed "js: can't take addr of param (including implicitly via `lent`)" - ([#14576](https://github.com/nim-lang/Nim/issues/14576)) -- Fixed "{.noinit.} ignored in for loop -> bad codegen for non-movable types" - ([#14118](https://github.com/nim-lang/Nim/issues/14118)) -- Fixed "generic destructor gives: `Error: unresolved generic parameter`" - ([#14315](https://github.com/nim-lang/Nim/issues/14315)) -- Fixed "Memory leak with arc gc" - ([#14568](https://github.com/nim-lang/Nim/issues/14568)) -- Fixed "escape analysis broken with `lent`" - ([#14557](https://github.com/nim-lang/Nim/issues/14557)) -- Fixed "`wrapWords` seems to ignore linebreaks when wrapping, leaving breaks in the wrong place" - ([#14579](https://github.com/nim-lang/Nim/issues/14579)) -- Fixed "`lent` gives wrong results with -d:release" - ([#14578](https://github.com/nim-lang/Nim/issues/14578)) -- Fixed "Nested await expressions regression: `await a(await expandValue())` doesnt compile" - ([#14279](https://github.com/nim-lang/Nim/issues/14279)) -- Fixed "windows CI docs fails with strange errors" - ([#14545](https://github.com/nim-lang/Nim/issues/14545)) -- Fixed "[CI] tests/async/tioselectors.nim flaky test for freebsd + OSX CI" - ([#13166](https://github.com/nim-lang/Nim/issues/13166)) -- Fixed "seq.setLen sometimes doesn't zero memory" - ([#14655](https://github.com/nim-lang/Nim/issues/14655)) -- Fixed "`nim dump` is roughly 100x slower in 1.3 versus 1.2" - ([#14179](https://github.com/nim-lang/Nim/issues/14179)) -- Fixed "Regression: devel docgen cannot generate document for method" - ([#14691](https://github.com/nim-lang/Nim/issues/14691)) -- Fixed "recently flaky tests/async/t7758.nim" - ([#14685](https://github.com/nim-lang/Nim/issues/14685)) -- Fixed "Bind no longer working in generic procs." - ([#11811](https://github.com/nim-lang/Nim/issues/11811)) -- Fixed "The pegs module doesn't work with generics!" - ([#14718](https://github.com/nim-lang/Nim/issues/14718)) -- Fixed "Defer is not properly working for asynchronous procedures." - ([#13899](https://github.com/nim-lang/Nim/issues/13899)) -- Fixed "Add an ARC test with threads in a loop" - ([#14690](https://github.com/nim-lang/Nim/issues/14690)) -- Fixed "[goto exceptions] {.noReturn.} pragma is not detected in a case expression" - ([#14458](https://github.com/nim-lang/Nim/issues/14458)) -- Fixed "[exceptions:goto] C compiler error with dynlib pragma calling a proc" - ([#14240](https://github.com/nim-lang/Nim/issues/14240)) -- Fixed "Cannot borrow var float64 in infix assignment" - ([#14440](https://github.com/nim-lang/Nim/issues/14440)) -- Fixed "lib/pure/memfiles.nim: compilation error with --taintMode:on" - ([#14760](https://github.com/nim-lang/Nim/issues/14760)) -- Fixed "newWideCString allocates a multiple of the memory needed" - ([#14750](https://github.com/nim-lang/Nim/issues/14750)) -- Fixed "Nim source archive install: 'install.sh' fails with error: cp: cannot stat 'bin/nim-gdb': No such file or directory" - ([#14748](https://github.com/nim-lang/Nim/issues/14748)) -- Fixed "`nim cpp -r tests/exception/t9657` hangs" - ([#10343](https://github.com/nim-lang/Nim/issues/10343)) -- Fixed "Detect tool fails on FreeBSD" - ([#14715](https://github.com/nim-lang/Nim/issues/14715)) -- Fixed "compiler crash: `findUnresolvedStatic` " - ([#14802](https://github.com/nim-lang/Nim/issues/14802)) -- Fixed "seq namespace (?) regression" - ([#4796](https://github.com/nim-lang/Nim/issues/4796)) -- Fixed "Possible out of bounds string access in std/colors parseColor and isColor" - ([#14839](https://github.com/nim-lang/Nim/issues/14839)) -- Fixed "compile error on latest devel with orc and ssl" - ([#14647](https://github.com/nim-lang/Nim/issues/14647)) -- Fixed "[minor] `$` wrong for type tuple" - ([#13432](https://github.com/nim-lang/Nim/issues/13432)) -- Fixed "Documentation missing on devel asyncftpclient" - ([#14846](https://github.com/nim-lang/Nim/issues/14846)) -- Fixed "nimpretty is confused with a trailing comma in enum definition" - ([#14401](https://github.com/nim-lang/Nim/issues/14401)) -- Fixed "Output arguments get ignored when compiling with --app:staticlib" - ([#12745](https://github.com/nim-lang/Nim/issues/12745)) -- Fixed "[ARC] destructive move destroys the object too early" - ([#14396](https://github.com/nim-lang/Nim/issues/14396)) -- Fixed "highlite.getNextToken() crashes if the buffer string is "echo "\""" - ([#14830](https://github.com/nim-lang/Nim/issues/14830)) -- Fixed "Memory corruption with --gc:arc with a seq of objects with an empty body." - ([#14472](https://github.com/nim-lang/Nim/issues/14472)) -- Fixed "Stropped identifiers don't work as field names in tuple literals" - ([#14911](https://github.com/nim-lang/Nim/issues/14911)) -- Fixed "Please revert my commit" - ([#14930](https://github.com/nim-lang/Nim/issues/14930)) -- Fixed "[ARC] C compiler error with inline iterators and imports" - ([#14864](https://github.com/nim-lang/Nim/issues/14864)) -- Fixed "AsyncHttpClient segfaults with gc:orc, possibly memory corruption" - ([#14402](https://github.com/nim-lang/Nim/issues/14402)) -- Fixed "[ARC] Template with a block evaluating to a GC'd value results in a compiler crash" - ([#14899](https://github.com/nim-lang/Nim/issues/14899)) -- Fixed "[ARC] Weird issue with if expressions and templates" - ([#14900](https://github.com/nim-lang/Nim/issues/14900)) -- Fixed "xmlparser does not compile on devel" - ([#14805](https://github.com/nim-lang/Nim/issues/14805)) -- Fixed "returning lent T from a var T param gives codegen errors or SIGSEGV" - ([#14878](https://github.com/nim-lang/Nim/issues/14878)) -- Fixed "[ARC] Weird issue with if expressions and templates" - ([#14900](https://github.com/nim-lang/Nim/issues/14900)) -- Fixed "threads:on + gc:orc + unittest = C compiler errors" - ([#14865](https://github.com/nim-lang/Nim/issues/14865)) -- Fixed "mitems, mpairs doesn't work at compile time anymore" - ([#12129](https://github.com/nim-lang/Nim/issues/12129)) -- Fixed "strange result from executing code in const expression" - ([#10465](https://github.com/nim-lang/Nim/issues/10465)) -- Fixed "Same warning printed 3 times" - ([#11009](https://github.com/nim-lang/Nim/issues/11009)) -- Fixed "type alias for generic typeclass doesn't work" - ([#4668](https://github.com/nim-lang/Nim/issues/4668)) -- Fixed "exceptions:goto Bug devel codegen lvalue NIM_FALSE=NIM_FALSE" - ([#14925](https://github.com/nim-lang/Nim/issues/14925)) -- Fixed "the --useVersion:1.0 no longer works in devel" - ([#14912](https://github.com/nim-lang/Nim/issues/14912)) -- Fixed "template declaration of iterator doesn't compile" - ([#4722](https://github.com/nim-lang/Nim/issues/4722)) -- Fixed "Compiler crash on type inheritance with static generic parameter and equality check" - ([#12571](https://github.com/nim-lang/Nim/issues/12571)) -- Fixed "Nim crashes while handling a cast in async circumstances." - ([#13815](https://github.com/nim-lang/Nim/issues/13815)) -- Fixed "[ARC] Internal compiler error when calling an iterator from an inline proc " - ([#14383](https://github.com/nim-lang/Nim/issues/14383)) -- Fixed ""Cannot instantiate" error when template uses generic type" - ([#5926](https://github.com/nim-lang/Nim/issues/5926)) -- Fixed "Different raises behaviour for newTerminal between Linux and Windows" - ([#12759](https://github.com/nim-lang/Nim/issues/12759)) -- Fixed "Expand on a type (that defines a proc type) in error message " - ([#6608](https://github.com/nim-lang/Nim/issues/6608)) -- Fixed "unittest require quits program with an exit code of 0" - ([#14475](https://github.com/nim-lang/Nim/issues/14475)) -- Fixed "Range type: Generics vs concrete type, semcheck difference." - ([#8426](https://github.com/nim-lang/Nim/issues/8426)) -- Fixed "[Macro] Type mismatch when parameter name is the same as a field" - ([#13253](https://github.com/nim-lang/Nim/issues/13253)) -- Fixed "Generic instantiation failure when converting a sequence of circular generic types to strings" - ([#10396](https://github.com/nim-lang/Nim/issues/10396)) -- Fixed "initOptParser ignores argument after value option with empty value." - ([#13086](https://github.com/nim-lang/Nim/issues/13086)) -- Fixed "[ARC] proc with both explicit and implicit return results in a C compiler error" - ([#14985](https://github.com/nim-lang/Nim/issues/14985)) -- Fixed "Alias type forgets implicit generic params depending on order" - ([#14990](https://github.com/nim-lang/Nim/issues/14990)) -- Fixed "[ARC] sequtils.insert has different behaviour between ARC/refc" - ([#14994](https://github.com/nim-lang/Nim/issues/14994)) -- Fixed "The documentation for "hot code reloading" references a non-existent npm package" - ([#13621](https://github.com/nim-lang/Nim/issues/13621)) -- Fixed "existsDir deprecated but breaking `dir` undeclared" - ([#15006](https://github.com/nim-lang/Nim/issues/15006)) -- Fixed "uri.decodeUrl crashes on incorrectly formatted input" - ([#14082](https://github.com/nim-lang/Nim/issues/14082)) -- Fixed "testament incorrectly reports time for tests, leading to wrong conclusions" - ([#14822](https://github.com/nim-lang/Nim/issues/14822)) -- Fixed "Calling peekChar with Stream returned from osproc.outputStream generate runtime error" - ([#14906](https://github.com/nim-lang/Nim/issues/14906)) -- Fixed "localPassC pragma should come *after* other flags" - ([#14194](https://github.com/nim-lang/Nim/issues/14194)) -- Fixed ""Could not load" dynamic library at runtime because of hidden dependency" - ([#2408](https://github.com/nim-lang/Nim/issues/2408)) -- Fixed "--gc:arc generate invalid code for {.global.} (`«nimErr_» in NIM_UNLIKELY`)" - ([#14480](https://github.com/nim-lang/Nim/issues/14480)) -- Fixed "Using `^` from stdlib/math along with converters gives a match for types that aren't SomeNumber" - ([#15033](https://github.com/nim-lang/Nim/issues/15033)) -- Fixed "[ARC] Weird exception behaviour from doAssertRaises" - ([#15026](https://github.com/nim-lang/Nim/issues/15026)) -- Fixed "[ARC] Compiler crash declaring a finalizer proc directly in 'new'" - ([#15044](https://github.com/nim-lang/Nim/issues/15044)) -- Fixed "[ARC] C compiler error when creating a var of a const seq" - ([#15036](https://github.com/nim-lang/Nim/issues/15036)) -- Fixed "code with named arguments in proc of winim/com can not been compiled" - ([#15056](https://github.com/nim-lang/Nim/issues/15056)) -- Fixed "javascript backend produces javascript code with syntax error in object syntax" - ([#14534](https://github.com/nim-lang/Nim/issues/14534)) -- Fixed "--gc:arc should be ignored in JS mode." - ([#14684](https://github.com/nim-lang/Nim/issues/14684)) -- Fixed "arc: C compilation error with imported global code using a closure iterator" - ([#12990](https://github.com/nim-lang/Nim/issues/12990)) -- Fixed "[ARC] Crash when modifying a string with mitems iterator" - ([#15052](https://github.com/nim-lang/Nim/issues/15052)) -- Fixed "[ARC] SIGSEGV when calling a closure as a tuple field in a seq" - ([#15038](https://github.com/nim-lang/Nim/issues/15038)) -- Fixed "pass varargs[seq[T]] to iterator give empty seq " - ([#12576](https://github.com/nim-lang/Nim/issues/12576)) -- Fixed "Compiler crashes when using string as object variant selector with else branch" - ([#14189](https://github.com/nim-lang/Nim/issues/14189)) -- Fixed "JS compiler error related to implicit return and return var type" - ([#11354](https://github.com/nim-lang/Nim/issues/11354)) -- Fixed "`nkRecWhen` causes internalAssert in semConstructFields" - ([#14698](https://github.com/nim-lang/Nim/issues/14698)) -- Fixed "Memory leaks with async (closure iterators?) under ORC" - ([#15076](https://github.com/nim-lang/Nim/issues/15076)) -- Fixed "strutil.insertSep() fails on negative numbers" - ([#11352](https://github.com/nim-lang/Nim/issues/11352)) -- Fixed "Constructing a uint64 range on a 32-bit machine leads to incorrect codegen" - ([#14616](https://github.com/nim-lang/Nim/issues/14616)) -- Fixed "heapqueue pushpop() proc doesn't compile" - ([#14139](https://github.com/nim-lang/Nim/issues/14139)) -- Fixed "[ARC] SIGSEGV when trying to swap in a literal/const string" - ([#15112](https://github.com/nim-lang/Nim/issues/15112)) -- Fixed "Defer and --gc:arc" - ([#15071](https://github.com/nim-lang/Nim/issues/15071)) -- Fixed "internal error: compiler/semobjconstr.nim(324, 20) example" - ([#15111](https://github.com/nim-lang/Nim/issues/15111)) -- Fixed "[ARC] Sequence "disappears" with a table inside of a table with an object variant" - ([#15122](https://github.com/nim-lang/Nim/issues/15122)) -- Fixed "[ARC] SIGSEGV with tuple assignment caused by cursor inference" - ([#15130](https://github.com/nim-lang/Nim/issues/15130)) -- Fixed "Issue with --gc:arc at compile time" - ([#15129](https://github.com/nim-lang/Nim/issues/15129)) -- Fixed "Writing an empty string to an AsyncFile raises an IndexDefect" - ([#15148](https://github.com/nim-lang/Nim/issues/15148)) -- Fixed "Compiler is confused about call convention of function with nested closure" - ([#5688](https://github.com/nim-lang/Nim/issues/5688)) -- Fixed "Nil check on each field fails in generic function" - ([#15101](https://github.com/nim-lang/Nim/issues/15101)) -- Fixed "{.nimcall.} convention won't avoid the creation of closures" - ([#8473](https://github.com/nim-lang/Nim/issues/8473)) -- Fixed "smtp.nim(161, 40) Error: type mismatch: got but expected 'SslContext = void'" - ([#15177](https://github.com/nim-lang/Nim/issues/15177)) -- Fixed "[strscans] scanf doesn't match a single character with $+ if it's the end of the string" - ([#15064](https://github.com/nim-lang/Nim/issues/15064)) -- Fixed "Crash and incorrect return values when using readPasswordFromStdin on Windows." - ([#15207](https://github.com/nim-lang/Nim/issues/15207)) -- Fixed "Possible capture error with fieldPairs and genericParams" - ([#15221](https://github.com/nim-lang/Nim/issues/15221)) -- Fixed "The StmtList processing of template parameters can lead to unexpected errors" - ([#5691](https://github.com/nim-lang/Nim/issues/5691)) -- Fixed "[ARC] C compiler error when passing a var openArray to a sink openArray" - ([#15035](https://github.com/nim-lang/Nim/issues/15035)) -- Fixed "Inconsistent unsigned -> signed RangeDefect usage across integer sizes" - ([#15210](https://github.com/nim-lang/Nim/issues/15210)) -- Fixed "toHex results in RangeDefect exception when used with large uint64" - ([#15257](https://github.com/nim-lang/Nim/issues/15257)) -- Fixed "Arc sink arg crash" - ([#15238](https://github.com/nim-lang/Nim/issues/15238)) -- Fixed "SQL escape in db_mysql is not enough" - ([#15219](https://github.com/nim-lang/Nim/issues/15219)) -- Fixed "Mixing 'return' with expressions is allowed in 1.2" - ([#15280](https://github.com/nim-lang/Nim/issues/15280)) -- Fixed "os.getFileInfo() causes ICE with --gc:arc on Windows" - ([#15286](https://github.com/nim-lang/Nim/issues/15286)) -- Fixed "[ARC] Sequence "disappears" with a table inside of a table with an object variant" - ([#15122](https://github.com/nim-lang/Nim/issues/15122)) -- Fixed "Documentation regression jsre module missing" - ([#15183](https://github.com/nim-lang/Nim/issues/15183)) -- Fixed "CountTable.smallest/largest() on empty table either asserts or gives bogus answer" - ([#15021](https://github.com/nim-lang/Nim/issues/15021)) -- Fixed "[Regression] Parser regression" - ([#15305](https://github.com/nim-lang/Nim/issues/15305)) -- Fixed "[ARC] SIGSEGV with tuple unpacking caused by cursor inference" - ([#15147](https://github.com/nim-lang/Nim/issues/15147)) -- Fixed "LwIP/FreeRTOS compile error - missing SIGPIPE and more " - ([#15302](https://github.com/nim-lang/Nim/issues/15302)) -- Fixed "Memory leaks with async (closure iterators?) under ORC" - ([#15076](https://github.com/nim-lang/Nim/issues/15076)) -- Fixed "Bug compiling with --gc:arg or --gc:orc" - ([#15325](https://github.com/nim-lang/Nim/issues/15325)) -- Fixed "memory corruption in tmarshall.nim" - ([#9754](https://github.com/nim-lang/Nim/issues/9754)) -- Fixed "typed macros break generic proc definitions" - ([#15326](https://github.com/nim-lang/Nim/issues/15326)) -- Fixed "nim doc2 ignores --docSeeSrcUrl parameter" - ([#6071](https://github.com/nim-lang/Nim/issues/6071)) -- Fixed "The decodeData Iterator from cgi module crash" - ([#15369](https://github.com/nim-lang/Nim/issues/15369)) -- Fixed "|| iterator generates invalid code when compiling with --debugger:native" - ([#9710](https://github.com/nim-lang/Nim/issues/9710)) -- Fixed "Wrong number of variables" - ([#15360](https://github.com/nim-lang/Nim/issues/15360)) -- Fixed "Coercions with distinct types should traverse pointer modifiers transparently." - ([#7165](https://github.com/nim-lang/Nim/issues/7165)) -- Fixed "Error with distinct generic TableRef" - ([#6060](https://github.com/nim-lang/Nim/issues/6060)) -- Fixed "Support images in nim docgen" - ([#6430](https://github.com/nim-lang/Nim/issues/6430)) -- Fixed "Regression. Double sem check for procs." - ([#15389](https://github.com/nim-lang/Nim/issues/15389)) -- Fixed "uri.nim url with literal ipv6 address is printed wrong, and cannot parsed again" - ([#15333](https://github.com/nim-lang/Nim/issues/15333)) -- Fixed "[ARC] Object variant gets corrupted with cursor inference" - ([#15361](https://github.com/nim-lang/Nim/issues/15361)) -- Fixed "`nim doc ..` compiler crash (regression 0.19.6 => 1.0)" - ([#14474](https://github.com/nim-lang/Nim/issues/14474)) -- Fixed "cannot borrow result; what it borrows from is potentially mutated" - ([#15403](https://github.com/nim-lang/Nim/issues/15403)) -- Fixed "memory corruption for seq.add(seq) with gc:arc and d:useMalloc " - ([#14983](https://github.com/nim-lang/Nim/issues/14983)) -- Fixed "DocGen HTML output appears improperly when encountering text immediately after/before inline monospace; in some cases won't compile" - ([#11537](https://github.com/nim-lang/Nim/issues/11537)) -- Fixed "Deepcopy in arc crashes" - ([#15405](https://github.com/nim-lang/Nim/issues/15405)) -- Fixed "pop pragma takes invalid input" - ([#15430](https://github.com/nim-lang/Nim/issues/15430)) -- Fixed "tests/stdlib/tgetprotobyname fails on NetBSD" - ([#15452](https://github.com/nim-lang/Nim/issues/15452)) -- Fixed "defer doesnt work with block, break and await" - ([#15243](https://github.com/nim-lang/Nim/issues/15243)) -- Fixed "tests/stdlib/tssl failing on NetBSD" - ([#15493](https://github.com/nim-lang/Nim/issues/15493)) -- Fixed "strictFuncs doesn't seem to catch simple ref mutation" - ([#15508](https://github.com/nim-lang/Nim/issues/15508)) -- Fixed "Sizeof of case object is incorrect. Showstopper" - ([#15516](https://github.com/nim-lang/Nim/issues/15516)) -- Fixed "[ARC] Internal error when trying to use a parallel for loop" - ([#15512](https://github.com/nim-lang/Nim/issues/15512)) -- Fixed "[ARC] Type-bound assign op is not being generated" - ([#15510](https://github.com/nim-lang/Nim/issues/15510)) -- Fixed "[ARC] Crash when adding openArray proc argument to a local seq" - ([#15511](https://github.com/nim-lang/Nim/issues/15511)) -- Fixed "VM: const case object gets some fields zeroed out at runtime" - ([#13081](https://github.com/nim-lang/Nim/issues/13081)) -- Fixed "regression(1.2.6 => devel): VM: const case object field access gives: 'sons' is not accessible" - ([#15532](https://github.com/nim-lang/Nim/issues/15532)) -- Fixed "Csources: huge size increase (x2.3) in 0.20" - ([#12027](https://github.com/nim-lang/Nim/issues/12027)) -- Fixed "Out of date error message for GC options" - ([#15547](https://github.com/nim-lang/Nim/issues/15547)) -- Fixed "dbQuote additional escape regression" - ([#15560](https://github.com/nim-lang/Nim/issues/15560)) diff --git a/changelogs/changelog_1_6_0.md b/changelogs/changelog_1_6_0.md deleted file mode 100644 index 4a1047d20..000000000 --- a/changelogs/changelog_1_6_0.md +++ /dev/null @@ -1,957 +0,0 @@ -# v1.6.0 - 2021-10-14 - - - -# Major new features - -With so many new features, pinpointing the most salient ones is a subjective exercise, -but here are a select few: - - -## `iterable[T]` - -The `iterable[T]` type class was added to match called iterators, -which solves a number of long-standing issues related to iterators. -Example: - -```nim -iterator iota(n: int): int = - for i in 0.. response.json()) - .then((json: JsObject) => console.log(json)) - .catch((err: Error) => console.log("Request Failed", err)) -discard fn() -``` - - -## New `std/tasks` module - -Provides basic primitives for creating parallel programs. -Example: -```nim -import std/tasks -var num = 0 -proc hello(a: int) = num+=a - -let b = toTask hello(13) # arguments must be isolated, see `std/isolation` -b.invoke() -assert num == 13 -b.invoke() # can be called again -assert num == 26 -``` - - -## New module: `std/genasts` - -Provides an API `genAst` that avoids the problems inherent with `quote do` and can -be used as a replacement. -Example showing how this could be used for writing a simplified version of `unittest.check`: -```nim -import std/[genasts, macros, strutils] -macro check2(cond: bool): untyped = - assert cond.kind == nnkInfix, "$# not implemented" % $cond.kind - result = genAst(cond, s = repr(cond), lhs = cond[1], rhs = cond[2]): - # each local symbol we access must be explicitly captured - if not cond: - doAssert false, "'$#'' failed: lhs: '$#', rhs: '$#'" % [s, $lhs, $rhs] -let a = 3 -check2 a*2 == a+3 -if false: check2 a*2 < a+1 # would error with: 'a * 2 < a + 1'' failed: lhs: '6', rhs: '4' -``` - -See PR [#17426](https://github.com/nim-lang/Nim/pull/17426) for details. - - -## New module: `std/setutils` - -- Added `setutils.toSet` that can take any iterable and convert it to a built-in `set`, - if the iterable yields a built-in settable type. -- Added `setutils.fullSet` which returns a full built-in `set` for a valid type. -- Added `setutils.complement` which returns the complement of a built-in `set`. -- Added `setutils.[]=`. - - -## New module: `std/enumutils` - -- Added `genEnumCaseStmt` macro that generates - case statement to parse string to enum. -- Added `items` for enums with holes. -- Added `symbolName` to return the `enum` symbol name ignoring the human-readable name. -- Added `symbolRank` to return the index in which an `enum` member is listed in an enum. - - -## `system` - -- Added `system.prepareMutation` for better support of low - level `moveMem`, `copyMem` operations for `gc:orc`'s copy-on-write string - implementation. -- `system.addEscapedChar` now renders `\r` as `\r` instead of `\c`, to be compatible - with most other languages. -- Added `cmpMem` to `system`. -- `doAssertRaises` now correctly handles foreign exceptions. -- `addInt` now supports unsigned integers. - -Compatibility notes: -- `system.delete` had surprising behavior when the index passed to it was out of - bounds (it would delete the last entry then). Compile with `-d:nimStrictDelete` so - that an index error is produced instead. Be aware however that your code might depend on - this quirky behavior so a review process is required on your part before you can - use `-d:nimStrictDelete`. To make this review easier, use the `-d:nimAuditDelete` - switch, which pretends that `system.delete` is deprecated so that it is easier - to see where it was used in your code. - `-d:nimStrictDelete` will become the default in upcoming versions. -- `cuchar` is now deprecated as it aliased `char` where arguably it should have aliased `uint8`. - Please use `char` or `uint8` instead. -- `repr` now doesn't insert trailing newlines; the previous behavior was very inconsistent, - see [#16034](https://github.com/nim-lang/Nim/pull/16034). - Use `-d:nimLegacyReprWithNewline` for the previous behavior. - `repr` now also renders ASTs correctly for user defined literals, setters, `do`, etc. -- Deprecated `any`. See RFC [#281](https://github.com/nim-lang/RFCs/issues/281). -- The unary slice `..b` was deprecated, use `0..b` instead. - - -## `std/math` - -- Added `almostEqual` for comparing two float values using a machine epsilon. -- Added `clamp` which allows using a `Slice` to clamp to a value. -- Added `ceilDiv` for integer division that rounds up. -- Added `isNaN`. -- Added `copySign`. -- Added `euclDiv` and `euclMod`. -- Added `signbit`. -- Added `frexp` overload procs. Deprecated `c_frexp`, use `frexp` instead. - -Compatibility notes: -- `math.round` now rounds "away from zero" in the JS backend, which is consistent - with other backends. See [#9125](https://github.com/nim-lang/Nim/pull/9125). - Use `-d:nimLegacyJsRound` for the previous behavior. - - -## Random number generators: `std/random`, `std/sysrand`, `std/oids` - -- Added `std/sysrand` module (see details above). -- Added `randState` template that exposes the default random number generator. - Useful for library authors. -- Added `initRand()` overload with no argument which uses the current time as a seed. -- `initRand(seed)` now allows `seed == 0`. -- Fixed overflow bugs. -- Fix `initRand` to avoid random number sequences overlapping, refs - [#18744](https://github.com/nim-lang/Nim/pull/18744). -- `std/oids` now uses `std/random`. - -Compatibility notes: -- Deprecated `std/mersenne`. -- `random.initRand(seed)` now produces non-skewed values for the first call to - `rand()` after initialization with a small (< 30000) seed. - Use `-d:nimLegacyRandomInitRand` to restore previous behavior for a transition - time, see PR [#17467](https://github.com/nim-lang/Nim/pull/17467). - - -## `std/json`, `std/jsonutils` - -- With `-d:nimPreviewJsonutilsHoleyEnum`, `jsonutils` now can serialize/deserialize - holey enums as regular enums (via `ord`) instead of as strings. - It is expected that this behavior becomes the new default in upcoming versions. - `toJson` now serializes `JsonNode` as is via reference (without a deep copy) - instead of treating `JsonNode` as a regular ref object, - this can be customized via `jsonNodeMode`. -- `std/json` and `std/jsonutils` now serialize `NaN`, `Inf`, `-Inf` as strings, - so that `%[NaN, -Inf]` is the string `["nan","-inf"]` instead of `[nan,-inf]` - which was invalid JSON. -- `std/json` can now handle integer literals and floating point literals of - arbitrary length and precision. - Numbers that do not fit the underlying `BiggestInt` or `BiggestFloat` fields are - kept as string literals and one can use external BigNum libraries to handle these. - The `parseFloat` family of functions also has now optional `rawIntegers` and - `rawFloats` parameters that can be used to enforce that all integer or float - literals remain in the "raw" string form so that client code can easily treat - small and large numbers uniformly. -- Added `BackwardsIndex` overload for `JsonNode`. -- `json.%`,`json.to`, `jsonutils.fromJson`,`jsonutils.toJson` now work with `uint|uint64` - instead of raising (as in 1.4) or giving wrong results (as in 1.2). -- `std/jsonutils` now handles `cstring` (including as Table key), and `set`. -- Added `jsonutils.jsonTo` overload with `opt = Joptions()` param. -- `jsonutils.toJson` now supports customization via `ToJsonOptions`. -- `std/json`, `std/jsonutils` now support round-trip serialization when - `-d:nimPreviewFloatRoundtrip` is used. - - -## `std/typetraits`, `std/compilesettings` - -- `distinctBase` now is identity instead of error for non distinct types. -- `distinctBase` now allows controlling whether to be recursive or not. -- Added `enumLen` to return the number of elements in an enum. -- Added `HoleyEnum` for enums with holes, `OrdinalEnum` for enums without holes. -- Added `hasClosure`. -- Added `pointerBase` to return `T` for `ref T | ptr T`. -- Added `compilesettings.SingleValueSetting.libPath`. - - -## networking: `std/net`, `std/asyncnet`, `std/htmlgen`, `std/httpclient`, `std/asyncdispatch`, `std/asynchttpserver`, `std/httpcore` - -- Fixed buffer overflow bugs in `std/net`. -- Exported `sslHandle` from `std/net` and `std/asyncnet`. -- Added `hasDataBuffered` to `std/asyncnet`. -- Various functions in `std/httpclient` now accept `url` of type `Uri`. - Moreover, the `request` function's `httpMethod` argument of type `string` was - deprecated in favor of `HttpMethod` `enum` type; see - [#15919](https://github.com/nim-lang/Nim/pull/15919). -- Added `asyncdispatch.activeDescriptors` that returns the number of currently - active async event handles/file descriptors. -- Added `getPort` to `std/asynchttpserver` to resolve OS-assigned `Port(0)`; - this is usually recommended instead of hardcoding ports which can lead to - "Address already in use" errors. -- Fixed premature garbage collection in `std/asyncdispatch`, when a stacktrace - override is in place. -- Added `httpcore.is1xx` and missing HTTP codes. -- Added `htmlgen.portal` for [making "SPA style" pages using HTML only](https://web.dev/hands-on-portals). - -Compatibility notes: -- On Windows, the SSL library now checks for valid certificates. - For this purpose it uses the `cacert.pem` file, which was extracted - from `https://curl.se/ca/cacert.pem`. Besides - the OpenSSL DLLs (e.g. `libssl-1_1-x64.dll`, `libcrypto-1_1-x64.dll`) you - now also need to ship `cacert.pem` with your `.exe` file. - - -## `std/hashes` - -- `hashes.hash` can now support `object` and `ref` (can be overloaded in user code), - if `-d:nimPreviewHashRef` is used. It is expected that this behavior - becomes the new default in upcoming versions. -- `hashes.hash(proc|ptr|ref|pointer)` now calls `hash(int)` and honors `-d:nimIntHash1`. - `hashes.hash(closure)` has also been improved. - - -## OS: `std/os`, `std/io`, `std/socketstream`, `std/linenoise`, `std/tempfiles` - -- `os.FileInfo` (returned by `getFileInfo`) now contains `blockSize`, - determining preferred I/O block size for this file object. -- Added `os.getCacheDir()` to return platform specific cache directory. -- Improved `os.getTempDir()`, see PR [#16914](https://github.com/nim-lang/Nim/pull/16914). -- Added `os.isAdmin` to tell whether the caller's process is a member of the - Administrators local group (on Windows) or a root (on POSIX). -- Added optional `options` argument to `copyFile`, `copyFileToDir`, and - `copyFileWithPermissions`. By default, on non-Windows OSes, symlinks are - followed (copy files symlinks point to); on Windows, `options` argument is - ignored and symlinks are skipped. -- On non-Windows OSes, `copyDir` and `copyDirWithPermissions` copy symlinks as - symlinks (instead of skipping them as it was before); on Windows symlinks are - skipped. -- On non-Windows OSes, `moveFile` and `moveDir` move symlinks as symlinks - (instead of skipping them sometimes as it was before). -- Added optional `followSymlinks` argument to `setFilePermissions`. -- Added a simpler to use `io.readChars` overload. -- Added `socketstream` module that wraps sockets in the stream interface. -- Added experimental `linenoise.readLineStatus` to get line and status (e.g. ctrl-D or ctrl-C). - - -## Environment variable handling - -- Empty environment variable values are now supported across OS's and backends. -- Environment variable APIs now work in multithreaded scenarios, by delegating to - direct OS calls instead of trying to keep track of the environment. -- `putEnv`, `delEnv` now work at compile time. -- NodeJS backend now supports osenv: `getEnv`, `putEnv`, `envPairs`, `delEnv`, `existsEnv`. - -Compatibility notes: -- `std/os`: `putEnv` now raises if the first argument contains a `=`. - - -## POSIX - -- On POSIX systems, the default signal handlers used for Nim programs (it's - used for printing the stacktrace on fatal signals) will now re-raise the - signal for the OS default handlers to handle. - This lets the OS perform its default actions, which might include core - dumping (on select signals) and notifying the parent process about the cause - of termination. -- On POSIX systems, we now ignore `SIGPIPE` signals, use `-d:nimLegacySigpipeHandler` - for previous behavior. -- Added `posix_utils.osReleaseFile` to get system identification from `os-release` - file on Linux and the BSDs. - ([link](https://www.freedesktop.org/software/systemd/man/os-release.html)) -- Removed undefined behavior for `posix.open`. - - -## `std/prelude` - -- `std/strformat` is now part of `include std/prelude`. -- Added `std/sequtils` import to `std/prelude`. -- `std/prelude` now works with the JS target. -- `std/prelude` can now be used via `include std/prelude`, but `include prelude` still works. - - -## String manipulation: `std/strformat`, `std/strbasics` - -- Added support for parenthesized expressions. -- Added support for const strings instead of just string literals. -- Added `std/strbasics` for high-performance string operations. -- Added `strip`, `setSlice`, `add(a: var string, b: openArray[char])`. - - -## `std/wrapnils` - -- `std/wrapnils` doesn't use `experimental:dotOperators` anymore, avoiding - issues like bug [#13063](https://github.com/nim-lang/Nim/issues/13063) - (which affected error messages) for modules importing `std/wrapnils`. -- Added `??.` macro which returns an `Option`. -- `std/wrapnils` can now be used to protect against `FieldDefect` errors in - case objects, generates optimal code (no overhead compared to manual - if-else branches), and preserves lvalue semantics which allows modifying - an expression. - - -## Containers: `std/algorithm`, `std/lists`, `std/sequtils`, `std/options`, `std/packedsets` - -- Removed the optional `longestMatch` parameter of the `critbits._WithPrefix` - iterators (it never worked reliably). -- Added `algorithm.merge`. -- In `std/lists`: renamed `append` to `add` and retained `append` as an alias; - added `prepend` and `prependMoved` analogously to `add` and `addMoved`; - added `remove` for `SinglyLinkedList`s. -- Added new operations for singly- and doubly linked lists: `lists.toSinglyLinkedList` - and `lists.toDoublyLinkedList` convert from `openArray`s; `lists.copy` implements - shallow copying; `lists.add` concatenates two lists - an O(1) variation that consumes - its argument, `addMoved`, is also supplied. - See PRs [#16362](https://github.com/nim-lang/Nim/pull/16362), - [#16536](https://github.com/nim-lang/Nim/pull/16536). -- New module: `std/packedsets`. - Generalizes `std/intsets`, see PR [#15564](https://github.com/nim-lang/Nim/pull/15564). - -Compatibility notes: -- Deprecated `sequtils.delete` and added an overload taking a `Slice` that raises - a defect if the slice is out of bounds, likewise with `strutils.delete`. -- Deprecated `proc reversed*[T](a: openArray[T], first: Natural, last: int): seq[T]` - in `std/algorithm`. -- `std/options` changed `$some(3)` to `"some(3)"` instead of `"Some(3)"` - and `$none(int)` to `"none(int)"` instead of `"None[int]"`. - - -## `std/times` - -- Added `ZZZ` and `ZZZZ` patterns to `times.nim` `DateTime` parsing, to match time - zone offsets without colons, e.g. `UTC+7 -> +0700`. -- Added `dateTime` and deprecated `initDateTime`. - - -## `std/macros` and AST - -- New module `std/genasts`, see description above. -- The required name of case statement macros for the experimental - `caseStmtMacros` feature has changed from `match` to `` `case` ``. -- Tuple expressions are now parsed consistently as - `nnkTupleConstr` node. Will affect macros expecting nodes to be of `nnkPar`. -- In `std/macros`, `treeRepr,lispRepr,astGenRepr` now represent SymChoice nodes - in a collapsed way. - Use `-d:nimLegacyMacrosCollapseSymChoice` to get the previous behavior. -- Made custom op in `macros.quote` work for all statements. - - -## `std/sugar` - -- Added `sugar.dumpToString` which improves on `sugar.dump`. -- Added an overload for the `collect` macro that infers the container type based - on the syntax of the last expression. Works with std seqs, tables and sets. - -Compatibility notes: -- Removed support for named procs in `sugar.=>`. - - -## Parsing: `std/parsecfg`, `std/strscans`, `std/uri` - -- Added `sections` iterator in `parsecfg`. -- `strscans.scanf` now supports parsing single characters. -- Added `strscans.scanTuple` which uses `strscans.scanf` internally, - returning a tuple which can be unpacked for easier usage of `scanf`. -- Added `decodeQuery` to `std/uri`. -- `parseopt.initOptParser` has been made available and `parseopt` has been - added back to `std/prelude` for all backends. Previously `initOptParser` was - unavailable if the `std/os` module did not have `paramCount` or `paramStr`, - but the use of these in `initOptParser` were conditionally to the runtime - arguments passed to it, so `initOptParser` has been changed to raise - `ValueError` when the real command line is not available. `parseopt` was - previously excluded from `std/prelude` for JS, as it could not be imported. - -Compatibility notes: -- Changed the behavior of `uri.decodeQuery` when there are unencoded `=` - characters in the decoded values. Prior versions would raise an error. This is - no longer the case to comply with the HTML spec and other languages' - implementations. Old behavior can be obtained with - `-d:nimLegacyParseQueryStrict`. `cgi.decodeData` which uses the same - underlying code is also updated the same way. - - -## JS stdlib changes - -- Added `std/jsbigints` module, which provides arbitrary precision integers for the JS target. -- Added `setCurrentException` for the JS backend. -- `writeStackTrace` is available in the JS backend now. -- Added `then`, `catch` to `std/asyncjs` for promise pipelining, for now hidden - behind `-d:nimExperimentalAsyncjsThen`. -- Added `std/jsfetch` module [Fetch](https://developer.mozilla.org/docs/Web/API/Fetch_API) - wrapper for the JS target. -- Added `std/jsheaders` module [Headers](https://developer.mozilla.org/en-US/docs/Web/API/Headers) - wrapper for the JS target. -- Added `std/jsformdata` module [FormData](https://developer.mozilla.org/en-US/docs/Web/API/FormData) - wrapper for the JS target. -- Added `jscore.debugger` to [call any available debugging functionality, such as breakpoints](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/debugger). -- Added `jsconsole.dir`, `jsconsole.dirxml`, `jsconsole.timeStamp`. -- Added dollar `$` and `len` for `jsre.RegExp`. -- Added `jsconsole.jsAssert` for the JS target. -- Added `**` to `std/jsffi`. -- Added `copyWithin` [for `seq` and `array` for JS targets](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/copyWithin). -- In `std/dom`, `Interval` is now a `ref object`, same as `Timeout`. - Definitions of `setTimeout`, `clearTimeout`, `setInterval`, `clearInterval` were updated. -- Added `dom.scrollIntoView` proc with options. -- Added `dom.setInterval`, `dom.clearInterval` overloads. -- Merged `std/dom_extensions` into the `std/dom` module, - as it was a module with a single line, see RFC [#413](https://github.com/nim-lang/RFCs/issues/413). -- `$` now gives more correct results on the JS backend. - - -## JS compiler changes - -- `cstring` doesn't support the `[]=` operator anymore in the JS backend. -- Array literals now use JS typed arrays when the corresponding JS typed array exists, - for example `[byte(1), 2, 3]` generates `new Uint8Array([1, 2, 3])`. - - -## VM and nimscript backend - -- VM now supports `addr(mystring[ind])` (index + index assignment). -- `nimscript` now handles `except Exception as e`. -- `nil` dereference is not allowed at compile time. `cast[ptr int](nil)[]` is rejected at compile time. -- `static[T]` now works better, refs [#17590](https://github.com/nim-lang/Nim/pull/17590), - [#15853](https://github.com/nim-lang/Nim/pull/15853). -- `distinct T` conversions now work in VM. -- `items(cstring)` now works in VM. -- Fix `addr`, `len`, `high` in VM ([#16002](https://github.com/nim-lang/Nim/pull/16002), - [#16610](https://github.com/nim-lang/Nim/pull/16610)). -- `std/cstrutils` now works in VM. - - -## OS/platform-specific notes - -- Support for Apple silicon/M1. -- Support for 32-bit RISC-V, refs [#16231](https://github.com/nim-lang/Nim/pull/16231). -- Support for armv8l, refs [#18901](https://github.com/nim-lang/Nim/pull/18901). -- Support for CROSSOS, refs [#18889](https://github.com/nim-lang/Nim/pull/18889). -- The allocator for Nintendo Switch, which was nonfunctional because - of breaking changes in libnx, was removed, in favor of the new `-d:nimAllocPagesViaMalloc` option. -- Allow reading parameters when compiling for Nintendo Switch. -- `--nimcache` now correctly works in a cross-compilation setting. -- Cross compilation targeting Windows was improved. -- This now works from macOS/Linux: `nim r -d:mingw main` - - - -## Performance / memory optimizations - -- The comment field in PNode AST was moved to a side channel, reducing overall - memory usage during compilation by a factor 1.25x -- `std/jsonutils` deserialization is now up to 20x faster. -- `os.copyFile` is now 2.5x faster on macOS, by using `copyfile` from `copyfile.h`; - use `-d:nimLegacyCopyFile` for macOS < 10.5. -- Float to string conversion is now 10x faster thanks to the Dragonbox algorithm, - with `-d:nimPreviewFloatRoundtrip`. -- `newSeqWith` is 3x faster. -- CI now supports batching (making Windows CI 2.3X faster). -- Sets now uses the optimized `countSetBits` proc, see PR - [#17334](https://github.com/nim-lang/Nim/pull/17334). - - -## Debugging - -- You can now enable/disable VM tracing in user code via `vmutils.vmTrace`. -- `koch tools` now builds `bin/nim_dbg` which allows easy access to a debug version - of Nim without recompiling. -- Added new module `compiler/debugutils` to help with debugging Nim compiler. -- Renamed `-d:nimCompilerStackraceHints` to `-d:nimCompilerStacktraceHints` and - used it in more contexts; this flag which works in tandem with `--stackTraceMsgs` - to show user code context in compiler stacktraces. - - -## Type system - -- `typeof(voidStmt)` now works and returns `void`. -- `enum` values can now be overloaded. This needs to be enabled - via `{.experimental: "overloadableEnums".}`. We hope that this feature allows - for the development of more fluent (less ugly) APIs. - See RFC [#373](https://github.com/nim-lang/RFCs/issues/373) for more details. -- A type conversion from one `enum` type to another now produces an `[EnumConv]` warning. - You should use `ord` (or `cast`, but the compiler won't help, if you misuse it) instead. - ```nim - type A = enum a1, a2 - type B = enum b1, b2 - echo a1.B # produces a warning - echo a1.ord.B # produces no warning - ``` -- A dangerous implicit conversion to `cstring` now triggers a `[CStringConv]` warning. - This warning will become an error in future versions! Use an explicit conversion - like `cstring(x)` in order to silence the warning. -- There is a new warning for *any* type conversion to `enum` that can be enabled via - `.warning[AnyEnumConv]:on` or `--warning:AnyEnumConv:on`. -- Reusing a type name in a different scope now works, refs [#17710](https://github.com/nim-lang/Nim/pull/17710). -- Fixed implicit and explicit generics in procedures, refs [#18808](https://github.com/nim-lang/Nim/pull/18808). - - -## New-style concepts - -Example: -```nim -type - Comparable = concept # no T, an atom - proc cmp(a, b: Self): int -``` -The new design does not rely on `system.compiles` and may compile faster. -See PR [#15251](https://github.com/nim-lang/Nim/pull/15251) -and RFC [#168](https://github.com/nim-lang/RFCs/issues/168) for details. - - -## Lexical / syntactic - -- Nim now supports a small subset of Unicode operators as operator symbols. - The supported symbols are: "∙ ∘ × ★ ⊗ ⊘ ⊙ ⊛ ⊠ ⊡ ∩ ∧ ⊓ ± ⊕ ⊖ ⊞ ⊟ ∪ ∨ ⊔". - To enable this feature, use `--experimental:unicodeOperators`. Note that due - to parser limitations you **cannot** enable this feature via a - pragma `{.experimental: "unicodeOperators".}` reliably, you need to enable - it via the command line or in a configuration file. -- `var a {.foo.} = expr` now works inside templates (except when `foo` is overloaded). - - -## Compiler messages, error messages, hints, warnings - -- Significant improvement to error messages involving effect mismatches, - see PRs [#18384](https://github.com/nim-lang/Nim/pull/18384), - [#18418](https://github.com/nim-lang/Nim/pull/18418). -- Added `--declaredLocs` to show symbol declaration location in error messages. -- Added `--spellSuggest` to show spelling suggestions on typos. -- Added `--processing:dots|filenames|off` which customizes `hintProcessing`; - `--processing:filenames` shows which include/import modules are being compiled as an import stack. -- `FieldDefect` messages now shows discriminant value + lineinfo, in all backends (C, JS, VM) -- Added `--hintAsError` with similar semantics as `--warningAsError`. -- Added `--unitsep:on|off` to control whether to add ASCII unit separator `\31` - before a newline for every generated message (potentially multiline), - so tooling can tell when messages start and end. -- Added `--filenames:abs|canonical|legacyRelProj` which replaces `--listFullPaths:on|off` -- `--hint:all:on|off` is now supported to select or deselect all hints; it - differs from `--hints:on|off` which acts as a (reversible) gate. - Likewise with `--warning:all:on|off`. -- The style checking of the compiler now supports a `--styleCheck:usages` switch. - This switch enforces that every symbol is written as it was declared, not enforcing - the official Nim style guide. To be enabled, this has to be combined either - with `--styleCheck:error` or `--styleCheck:hint`. -- Type mismatch errors now show more context, use `-d:nimLegacyTypeMismatch` for - previous behavior. -- `typedesc[Foo]` now renders as such instead of `type Foo` in compiler messages. -- `runnableExamples` now show originating location in stacktraces on failure. -- `SuccessX` message now shows more useful information. -- New `DuplicateModuleImport` warning; improved `UnusedImport` and - `XDeclaredButNotUsed` accuracy. - -Compatibility notes: -- `--hint:CC` now prints to stderr (like all other hints) instead of stdout. - - -## Building and running Nim programs, configuration system - -- JSON build instructions are now generated in `$nimcache/outFileBasename.json` - instead of `$nimcache/projectName.json`. This allows avoiding recompiling a - given project compiled with different options if the output file differs. -- `--usenimcache` (implied by `nim r main`) now generates an output file that includes - a hash of some of the compilation options, which allows caching generated binaries: - ```bash - nim r main # recompiles - nim r -d:foo main # recompiles - nim r main # uses cached binary - nim r main arg1 arg2 # likewise (runtime arguments are irrelevant) - ``` -- `nim r` now supports cross compilation from unix to windows when specifying - `-d:mingw` by using Wine, e.g.: - `nim r --eval:'import os; echo "a" / "b"'` prints `a\b`. -- `nim` can compile version 1.4.0 as follows: - `nim c --lib:lib --stylecheck:off -d:nimVersion140 compiler/nim`. - `-d:nimVersion140` is not needed for bootstrapping, only for building 1.4.0 from devel. -- `nim e` now accepts arbitrary file extensions for the nimscript file, - although `.nims` is still the preferred extension in general. -- The configuration subsystem now allows for `-d:release` and `-d:danger` to work as expected. - The downside is that these defines now have custom logic that doesn't apply for - other defines. - - -## Multithreading - -- TLS: macOS now uses native TLS (`--tlsEmulation:off`). TLS now works with - `importcpp` non-POD types; such types must use `.cppNonPod` and - `--tlsEmulation:off`should be used. -- Added `unsafeIsolate` and `extract` to `std/isolation`. -- Added `std/tasks`, see description above. - - -## Memory management - -- `--gc:arc` now bootstraps (PR [#17342](https://github.com/nim-lang/Nim/pull/17342)). -- Lots of improvements to `gc:arc`, `gc:orc`, see PR - [#15697](https://github.com/nim-lang/Nim/pull/15697), - [#16849](https://github.com/nim-lang/Nim/pull/16849), - [#17993](https://github.com/nim-lang/Nim/pull/17993). -- `--gc:orc` is now 10% faster than previously for common workloads. - If you have trouble with its changed behavior, compile with `-d:nimOldOrc`. -- The `--gc:orc` algorithm was refined so that custom container types can participate in the - cycle collection process. See the documentation of `=trace` for more details. -- On embedded devices `malloc` can now be used instead of `mmap` via `-d:nimAllocPagesViaMalloc`. - This is only supported for `--gc:orc` or `--gc:arc`. - -Compatibility notes: -- `--newruntime` and `--refchecks` are deprecated, - use `--gc:arc`, `--gc:orc`, or `--gc:none` as appropriate instead. - - -## Docgen - -- docgen: RST files can now use single backticks instead of double backticks and - correctly render in both `nim rst2html` (as before) as well as common tools rendering - RST directly (e.g. GitHub). - This is done by adding the `default-role:: code` directive inside the RST file - (which is now handled by `nim rst2html`). -- Source+Edit links now appear on top of every docgen'd page when - `nim doc --git.url:url ...` is given. -- Latex doc generation is revised: output `.tex` files should be compiled - by `xelatex` (not by `pdflatex` as before). Now default Latex settings - provide support for Unicode and better avoid margin overflows. - The minimum required version is TeXLive 2018 (or an equivalent MikTeX version). -- The RST parser now supports footnotes, citations, admonitions, and short style - references with symbols. -- The RST parser now supports Markdown table syntax. - Known limitations: - - cell alignment is not supported, i.e. alignment annotations in a delimiter - row (`:---`, `:--:`, `---:`) are ignored - - every table row must start with `|`, e.g. `| cell 1 | cell 2 |`. -- Implemented `doc2tex` compiler command which converts documentation in - `.nim` files to Latex. -- docgen now supports syntax highlighting for inline code. -- docgen now supports same-line doc comments: - ```nim - func fn*(a: int): int = 42 ## Doc comment - ``` -- docgen now renders `deprecated` and other pragmas. -- `runnableExamples` now works with templates and nested templates. -- `runnableExamples: "-r:off"` now works for examples that should compile but not run. -- `runnableExamples` now renders code verbatim, and produces correct code in all cases. -- docgen now shows correct, canonical import paths in docs. -- docgen now shows all routines in sidebar, and the proc signature is now shown in sidebar. - - -## Effects and checks - -- Significant improvement to error messages involving effect mismatches -- There is a new `cast` section `{.cast(uncheckedAssign).}: body` that disables some - compiler checks regarding `case objects`. This allows serialization libraries - to avoid ugly, non-portable solutions. See RFC - [#407](https://github.com/nim-lang/RFCs/issues/407) for more details. - -Compatibility notes: -- Fixed effect tracking for borrowed procs (see [#18882](https://github.com/nim-lang/Nim/pull/18882)). - One consequence is that, under some circumstances, Nim could previously permit a procedure with side effects to be written with `func` - you may need to change some occurrences of `func` to `proc`. - To illustrate, Nim versions before 1.6.0 compile the below without error - ```nim - proc print(s: string) = - echo s - - type - MyString = distinct string - - proc print(s: MyString) {.borrow.} - - func foo(s: MyString) = - print(s) - ``` - but Nim 1.6.0 produces the error - ``` - Error: 'foo' can have side effects - ``` - similar to how we expect that - ```nim - func print(s: string) = - echo s - ``` - produces - ``` - Error: 'print' can have side effects - ``` - - -## Tools - -- Major improvements to `nimgrep`, see PR [#15612 -](https://github.com/nim-lang/Nim/pull/15612). -- `fusion` is now un-bundled from Nim, `./koch fusion` will - install it via Nimble at a fixed hash. -- `testament`: added `nimoutFull: bool` spec to compare full output of compiler - instead of a subset; many bugfixes to testament. - - -## Misc/cleanups - -- Deprecated `TaintedString` and `--taintmode`. -- Deprecated `--nilseqs` which is now a noop. -- Added `-d:nimStrictMode` in CI in several places to ensure code doesn't have - certain hints/warnings. -- Removed `.travis.yml`, `appveyor.yml.disabled`, `.github/workflows/ci.yml.disabled`. -- `[skip ci]` now works in azure and CI pipelines, see detail in PR - [#17561](https://github.com/nim-lang/Nim/pull/17561). diff --git a/changelogs/changelog_2_0_0.md b/changelogs/changelog_2_0_0.md deleted file mode 100644 index cbe755478..000000000 --- a/changelogs/changelog_2_0_0.md +++ /dev/null @@ -1,367 +0,0 @@ -# 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 follows Apache HttpClient(Java), http(go) and .Net HttpWebResponse(C#) behavior. Previously it raised `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 `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. - -- 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 experimental `nimPreviewDotLikeOps` switch is going to be removed or deprecated because it didn't fullfill its promises. - -- The `{.this.}` pragma, deprecated since 0.19, has been removed. -- `nil` literals can no longer be directly assigned to variables or fields of `distinct` pointer types. They must be converted instead. - ```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`. - -- Redefining templates with the same signature was previously - allowed to support certain macro code. To do this explicitly, the - `{.redefine.}` pragma has been added. Note that this is only for templates. - Implicit redefinition of templates is now deprecated and will give an error in the future. - -- Using an unnamed break in a block is deprecated. This warning will become an error in future versions! Use a named block with a named break instead. - -- Several Standard libraries are moved to nimble packages, use `nimble` to install them: - - `std/punycode` => `punycode` - - `std/asyncftpclient` => `asyncftpclient` - - `std/smtp` => `smtp` - - `std/db_common` => `db_connector/db_common` - - `std/db_sqlite` => `db_connector/db_sqlite` - - `std/db_mysql` => `db_connector/db_mysql` - - `std/db_postgres` => `db_connector/db_postgres` - - `std/db_odbc` => `db_connector/db_odbc` - -- Previously, calls like `foo(a, b): ...` or `foo(a, b) do: ...` where the final argument of - `foo` had type `proc ()` were assumed by the compiler to mean `foo(a, b, proc () = ...)`. - This behavior is now deprecated. Use `foo(a, b) do (): ...` or `foo(a, b, proc () = ...)` instead. - -- If no exception or any exception deriving from Exception but not Defect or CatchableError given in except, a `warnBareExcept` warning will be triggered. - -- The experimental strictFuncs feature now disallows a store to the heap via a `ref` or `ptr` indirection. - -- Underscores (`_`) as routine parameters are now ignored and cannot be used in the routine body. - The following code now does not compile: - - ```nim - proc foo(_: int): int = _ + 1 - echo foo(1) - ``` - - Instead, the following code now compiles: - - ```nim - proc foo(_, _: int): int = 123 - echo foo(1, 2) - ``` -- Underscores (`_`) as generic parameters are not supported and cannot be used. - Generics that use `_` as parameters will no longer compile requires you to replace `_` with something else: - - ```nim - proc foo[_](t: typedesc[_]): string = "BAR" # Can not compile - proc foo[T](t: typedesc[T]): string = "BAR" # Can compile - ``` - -- - Added the `--legacy:verboseTypeMismatch` switch to get legacy type mismatch error messages. - -## 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. - -- `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). - -[//]: # "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 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. - - ```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-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 - 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 be overridden by users. - -## 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 - -- Nim now ships Nimble version 0.14 which added support for lock-files. Libraries are stored in `$nimbleDir/pkgs2` (it was `$nimbleDir/pkgs`). diff --git a/changelogs/changelog_X_XX_X.md b/changelogs/changelog_X_XX_X.md index 524599b11..45a8cbc44 100644 --- a/changelogs/changelog_X_XX_X.md +++ b/changelogs/changelog_X_XX_X.md @@ -1,23 +1,34 @@ -# v1.xx.x - yyyy-mm-dd +# vx.xx.x - yyyy-mm-dd This is an example file. The changes should go to changelog.md! -## Changes affecting backward compatibility -- `foo` now behaves differently, use `-d:nimLegacyFoo` for previous behavior. +## Changes affecting backwards compatibility -## Standard library additions and changes +- Example item: `Foo` changed to `Bar`. -- Added `example.exampleProc`. -- Changed `example.foo` to take additional `bar` parameter. +### Breaking changes in the standard library + + +### Breaking changes in the compiler + + +## Library additions + +## Library changes + +## Language additions + ## Language changes -## Compiler changes +### Tool changes -## Tool changes +### Compiler changes + +## Bugfixes diff --git a/ci/action.nim b/ci/action.nim deleted file mode 100644 index 5d3a50fda..000000000 --- a/ci/action.nim +++ /dev/null @@ -1,26 +0,0 @@ -import std/[strutils, os, osproc, parseutils, strformat] - - -proc main() = - var msg = "" - const cmd = "./koch boot --gc:orc -d:release" - - let (output, exitCode) = execCmdEx(cmd) - - doAssert exitCode == 0, output - - let start = rfind(output, "Hint: mm") - doAssert parseUntil(output, msg, "; proj", start) > 0, output - - let (commitHash, _) = execCmdEx("""git log --format="%H" -n 1""") - - let welcomeMessage = fmt"""Thanks for your hard work on this PR! -The lines below are statistics of the Nim compiler built from {commitHash} - -{msg} -""" - createDir "ci/nimcache" - writeFile "ci/nimcache/results.txt", welcomeMessage - -when isMainModule: - main() diff --git a/ci/build.bat b/ci/build.bat new file mode 100644 index 000000000..cdce8d3d2 --- /dev/null +++ b/ci/build.bat @@ -0,0 +1,14 @@ +REM Some debug info +echo "Running on %CI_RUNNER_ID% (%CI_RUNNER_DESCRIPTION%) with tags %CI_RUNNER_TAGS%." +gcc -v + +git clone --depth 1 https://github.com/nim-lang/csources.git +cd csources +call build64.bat +cd .. +set PATH=%CD%\bin;%PATH% +nim -v +nim c koch +koch.exe boot +copy bin/nim bin/nimd +koch.exe boot -d:release diff --git a/ci/build.sh b/ci/build.sh new file mode 100644 index 000000000..6321fffba --- /dev/null +++ b/ci/build.sh @@ -0,0 +1,15 @@ +sh ci/deps.sh + +# Build from C sources. +git clone --depth 1 https://github.com/nim-lang/csources.git +cd csources +sh build.sh +cd .. +# Add Nim to the PATH +export PATH=$(pwd)/bin${PATH:+:$PATH} +# Bootstrap. +nim -v +nim c koch +./koch boot +cp bin/nim bin/nimd +./koch boot -d:release diff --git a/ci/build_autogen.bat b/ci/build_autogen.bat deleted file mode 100644 index 0b6ca566e..000000000 --- a/ci/build_autogen.bat +++ /dev/null @@ -1,26 +0,0 @@ -@echo off -rem DO NO EDIT DIRECTLY! auto-generated by `nim r tools/ci_generate.nim` -rem Build development version of the compiler; can be rerun safely -rem bare bones version of ci/funs.sh adapted for windows. - -rem Read in some common shared variables (shared with other tools), -rem see https://stackoverflow.com/questions/3068929/how-to-read-file-contents-into-a-variable-in-a-batch-file -for /f "delims== tokens=1,2" %%G in (config/build_config.txt) do set %%G=%%H -SET nim_csources=bin\nim_csources_%nim_csourcesHash%.exe -echo "building from csources: %nim_csources%" - -if not exist %nim_csourcesDir% ( - git clone -q --depth 1 -b %nim_csourcesBranch% %nim_csourcesUrl% %nim_csourcesDir% -) - -if not exist %nim_csources% ( - cd %nim_csourcesDir% - git checkout %nim_csourcesHash% - echo "%PROCESSOR_ARCHITECTURE%" - if "%PROCESSOR_ARCHITECTURE%"=="AMD64" ( - SET ARCH=64 - ) - CALL build.bat - cd .. - copy /y bin\nim.exe %nim_csources% -) diff --git a/ci/deps.bat b/ci/deps.bat new file mode 100644 index 000000000..bda1fe14f --- /dev/null +++ b/ci/deps.bat @@ -0,0 +1,4 @@ +nim e install_nimble.nims +nim e tests/test_nimscript.nims +nimble update +nimble install -y zip opengl sdl1 jester@#head niminst diff --git a/ci/deps.sh b/ci/deps.sh new file mode 100644 index 000000000..f0f831a2a --- /dev/null +++ b/ci/deps.sh @@ -0,0 +1,16 @@ +# Some debug info +echo "Running on $CI_RUNNER_ID ($CI_RUNNER_DESCRIPTION) with tags $CI_RUNNER_TAGS." + +# Packages +apt-get update -qq +apt-get install -y -qq build-essential git libcurl4-openssl-dev libsdl1.2-dev libgc-dev nodejs + +gcc -v + +export PATH=$(pwd)/bin${PATH:+:$PATH} + +# Nimble deps +nim e install_nimble.nims +nim e tests/test_nimscript.nims +nimble update +nimble install zip opengl sdl1 jester@#head niminst diff --git a/ci/funs.sh b/ci/funs.sh deleted file mode 100644 index 8e7f8faf7..000000000 --- a/ci/funs.sh +++ /dev/null @@ -1,143 +0,0 @@ -# Utilities used in CI pipelines and tooling to avoid duplication. -# Avoid top-level statements. -# Prefer nim scripts whenever possible. -# functions starting with `_` are considered internal, less stable. - -echo_run () { - # echo's a command before running it, which helps understanding logs - echo "" - echo "cmd: $@" # in azure we could also use this: echo '##[section]"$@"' - "$@" -} - -nimGetLastCommit() { - git log --no-merges -1 --pretty=format:"%s" -} - -nimIsCiSkip(){ - # D20210329T004830:here refs https://github.com/microsoft/azure-pipelines-agent/issues/2944 - # `--no-merges` is needed to avoid merge commits which occur for PR's. - # $(Build.SourceVersionMessage) is not helpful - # nor is `github.event.head_commit.message` for github actions. - # Note: `[skip ci]` is now handled automatically for github actions, see https://github.blog/changelog/2021-02-08-github-actions-skip-pull-request-and-push-workflows-with-skip-ci/ - commitMsg=$(nimGetLastCommit) - echo commitMsg: "$commitMsg" - if [[ $commitMsg == *"[skip ci]"* ]]; then - echo "skipci: true" - return 0 - else - echo "skipci: false" - return 1 - fi -} - -nimInternalInstallDepsWindows(){ - echo_run mkdir dist - echo_run curl -L https://nim-lang.org/download/mingw64.7z -o dist/mingw64.7z - echo_run curl -L https://nim-lang.org/download/dlls.zip -o dist/dlls.zip - echo_run 7z x dist/mingw64.7z -odist - echo_run 7z x dist/dlls.zip -obin -} - -nimInternalBuildKochAndRunCI(){ - echo_run nim c koch - if ! echo_run ./koch runCI; then - echo_run echo "runCI failed" - echo_run nim r tools/ci_testresults.nim - return 1 - fi -} - -nimDefineVars(){ - . config/build_config.txt - nim_csources=bin/nim_csources_$nim_csourcesHash -} - -_nimNumCpu(){ - # linux: $(nproc) - # FreeBSD | macOS: $(sysctl -n hw.ncpu) - # OpenBSD: $(sysctl -n hw.ncpuonline) - # windows: $NUMBER_OF_PROCESSORS ? - echo $(nproc 2>/dev/null || sysctl -n hw.logicalcpu 2>/dev/null || getconf _NPROCESSORS_ONLN 2>/dev/null || 1) -} - -_nimBuildCsourcesIfNeeded(){ - # if some systems cannot use make or gmake, we could add support for calling `build.sh` - # but this is slower (not parallel jobs) and would require making build.sh - # understand the arguments passed to the makefile (e.g. `CC=gcc ucpu=amd64 uos=darwin`), - # instead of `--cpu amd64 --os darwin`. - unamestr=$(uname) - # uname values: https://en.wikipedia.org/wiki/Uname - if [ "$unamestr" = 'FreeBSD' ]; then - makeX=gmake - elif [ "$unamestr" = 'OpenBSD' ]; then - makeX=gmake - elif [ "$unamestr" = 'NetBSD' ]; then - makeX=gmake - elif [ "$unamestr" = 'CROSSOS' ]; then - makeX=gmake - elif [ "$unamestr" = 'SunOS' ]; then - makeX=gmake - else - makeX=make - fi - nCPU=$(_nimNumCpu) - echo_run which $makeX - # parallel jobs (5X faster on 16 cores: 10s instead of 50s) - echo_run $makeX -C $nim_csourcesDir -j $((nCPU + 2)) -l $nCPU "$@" - # keep $nim_csources in case needed to investigate bootstrap issues - # without having to rebuild - echo_run cp bin/nim $nim_csources -} - -nimCiSystemInfo(){ - nimDefineVars - echo_run eval echo '$'nim_csources - echo_run pwd - echo_run date - echo_run uname -a - echo_run git log --no-merges -1 --pretty=oneline - echo_run eval echo '$'PATH - echo_run gcc -v - echo_run node -v - echo_run make -v -} - -nimCsourcesHash(){ - nimDefineVars - echo $nim_csourcesHash -} - -nimBuildCsourcesIfNeeded(){ - # goal: allow cachine each tagged version independently - # to avoid rebuilding, so that tools like `git bisect` - # can grab a cached past version without rebuilding. - nimDefineVars - ( - set -e - # avoid polluting caller scope with internal variable definitions. - if test -f "$nim_csources"; then - echo "$nim_csources exists." - else - if test -d "$nim_csourcesDir"; then - echo "$nim_csourcesDir exists." - else - # Note: using git tags would allow fetching just what's needed, unlike git hashes, e.g. - # via `git clone -q --depth 1 --branch $tag $nim_csourcesUrl`. - echo_run git clone -q --depth 1 -b $nim_csourcesBranch \ - $nim_csourcesUrl "$nim_csourcesDir" - # old `git` versions don't support -C option, using `cd` explicitly: - echo_run cd "$nim_csourcesDir" - echo_run git checkout $nim_csourcesHash - echo_run cd "$OLDPWD" - # if needed we could also add: `git reset --hard $nim_csourcesHash` - fi - _nimBuildCsourcesIfNeeded "$@" - fi - - echo_run rm -f bin/nim - # fixes bug #17913, but it's unclear why it's needed, maybe specific to MacOS Big Sur 11.3 on M1 arch? - echo_run cp $nim_csources bin/nim - echo_run $nim_csources -v - ) -} diff --git a/ci/nsis_build.bat b/ci/nsis_build.bat new file mode 100644 index 000000000..4806810d7 --- /dev/null +++ b/ci/nsis_build.bat @@ -0,0 +1,59 @@ +REM - Run the full testsuite; testament\tester all + +REM - Uncomment the list of changes in news.txt +REM - write a news ticker entry +REM - Update the version + +REM - Generate the full docs; koch web0 +REM - Generate the installers; +REM - Update the version in system.nim +REM - Test the installers +REM - Tag the release +REM - Merge devel into master +REM - Update csources + +set NIMVER=%1 + +Rem Build -docs file: +koch web0 +cd web\upload +7z a -tzip docs-%NIMVER%.zip *.html +move /y docs-%NIMVER%.zip download +cd ..\.. + +Rem Build csources +koch csources -d:release || exit /b + +rem Grab C sources and nimsuggest +git clone --depth 1 https://github.com/nim-lang/csources.git + +set PATH=%CD%\bin;%PATH% + +ReM Build Win32 version: + +set PATH=C:\Users\araq\projects\mingw32\bin;%PATH% +cd csources +call build.bat +cd .. +ReM Rebuilding koch is necessary because it uses its pointer size to determine +ReM which mingw link to put in the NSIS installer. +nim c --out:koch_temp koch || exit /b +koch_temp boot -d:release || exit /b +koch_temp nsis -d:release || exit /b +koch_temp zip -d:release || exit /b +dir build +move /y build\nim_%NIMVER%.exe build\nim-%NIMVER%_x32.exe || exit /b +move /y build\nim-%NIMVER%.zip build\nim-%NIMVER%_x32.zip || exit /b + + +ReM Build Win64 version: +set PATH=C:\Users\araq\projects\mingw64\bin;%PATH% +cd csources +call build64.bat +cd .. +nim c --out:koch_temp koch || exit /b +koch_temp boot -d:release || exit /b +koch_temp nsis -d:release || exit /b +koch_temp zip -d:release || exit /b +move /y build\nim_%NIMVER%.exe build\nim-%NIMVER%_x64.exe || exit /b +move /y build\nim-%NIMVER%.zip build\nim-%NIMVER%_x64.zip || exit /b diff --git a/compiler.nimble b/compiler.nimble new file mode 100644 index 000000000..f4da45519 --- /dev/null +++ b/compiler.nimble @@ -0,0 +1,9 @@ + +version = system.NimVersion +author = "Andreas Rumpf" +description = "Compiler package providing the compiler sources as a library." +license = "MIT" + +installDirs = @["compiler", "nimsuggest"] + +requires "nim >= 0.14.0" diff --git a/compiler/aliasanalysis.nim b/compiler/aliasanalysis.nim deleted file mode 100644 index f14b81524..000000000 --- a/compiler/aliasanalysis.nim +++ /dev/null @@ -1,128 +0,0 @@ - -import ast - -import std / assertions - -const - PathKinds0* = {nkDotExpr, nkCheckedFieldExpr, - nkBracketExpr, nkDerefExpr, nkHiddenDeref, - nkAddr, nkHiddenAddr, - nkObjDownConv, nkObjUpConv} - PathKinds1* = {nkHiddenStdConv, nkHiddenSubConv} - -proc skipConvDfa*(n: PNode): PNode = - result = n - while true: - case result.kind - of nkObjDownConv, nkObjUpConv: - result = result[0] - of PathKinds1: - result = result[1] - else: break - -proc isAnalysableFieldAccess*(orig: PNode; owner: PSym): bool = - var n = orig - while true: - case n.kind - of PathKinds0 - {nkHiddenDeref, nkDerefExpr}: - n = n[0] - of PathKinds1: - n = n[1] - of nkHiddenDeref, nkDerefExpr: - # We "own" sinkparam[].loc but not ourVar[].location as it is a nasty - # pointer indirection. - # bug #14159, we cannot reason about sinkParam[].location as it can - # still be shared for tyRef. - n = n[0] - return n.kind == nkSym and n.sym.owner == owner and - (n.sym.typ.skipTypes(abstractInst-{tyOwned}).kind in {tyOwned}) - else: break - # XXX Allow closure deref operations here if we know - # the owner controlled the closure allocation? - result = n.kind == nkSym and n.sym.owner == owner and - {sfGlobal, sfThread, sfCursor} * n.sym.flags == {} and - (n.sym.kind != skParam or isSinkParam(n.sym)) # or n.sym.typ.kind == tyVar) - # Note: There is a different move analyzer possible that checks for - # consume(param.key); param.key = newValue for all paths. Then code like - # - # let splited = split(move self.root, x) - # self.root = merge(splited.lower, splited.greater) - # - # could be written without the ``move self.root``. However, this would be - # wrong! Then the write barrier for the ``self.root`` assignment would - # free the old data and all is lost! Lesson: Don't be too smart, trust the - # lower level C++ optimizer to specialize this code. - -type AliasKind* = enum - yes, no, maybe - -proc aliases*(obj, field: PNode): AliasKind = - # obj -> field: - # x -> x: true - # x -> x.f: true - # x.f -> x: false - # x.f -> x.f: true - # x.f -> x.v: false - # x -> x[]: true - # x[] -> x: false - # x -> x[0]: true - # x[0] -> x: false - # x[0] -> x[0]: true - # x[0] -> x[1]: false - # x -> x[i]: true - # x[i] -> x: false - # x[i] -> x[i]: maybe; Further analysis could make this return true when i is a runtime-constant - # x[i] -> x[j]: maybe; also returns maybe if only one of i or j is a compiletime-constant - template collectImportantNodes(result, n) = - var result: seq[PNode] - var n = n - while true: - case n.kind - of PathKinds0 - {nkDotExpr, nkBracketExpr, nkDerefExpr, nkHiddenDeref}: - n = n[0] - of PathKinds1: - n = n[1] - of nkDotExpr, nkBracketExpr, nkDerefExpr, nkHiddenDeref: - result.add n - n = n[0] - of nkSym: - result.add n - break - else: return no - - collectImportantNodes(objImportantNodes, obj) - collectImportantNodes(fieldImportantNodes, field) - - # If field is less nested than obj, then it cannot be part of/aliased by obj - if fieldImportantNodes.len < objImportantNodes.len: return no - - result = yes - for i in 1..objImportantNodes.len: - # We compare the nodes leading to the location of obj and field - # with each other. - # We continue until they diverge, in which case we return no, or - # until we reach the location of obj, in which case we do not need - # to look further, since field must be part of/aliased by obj now. - # If we encounter an element access using an index which is a runtime value, - # we simply return maybe instead of yes; should further nodes not diverge. - let currFieldPath = fieldImportantNodes[^i] - let currObjPath = objImportantNodes[^i] - - if currFieldPath.kind != currObjPath.kind: - return no - - case currFieldPath.kind - of nkSym: - if currFieldPath.sym != currObjPath.sym: return no - of nkDotExpr: - if currFieldPath[1].sym != currObjPath[1].sym: return no - of nkDerefExpr, nkHiddenDeref: - discard - of nkBracketExpr: - if currFieldPath[1].kind in nkLiterals and currObjPath[1].kind in nkLiterals: - if currFieldPath[1].intVal != currObjPath[1].intVal: - return no - else: - result = maybe - else: assert false # unreachable - diff --git a/compiler/aliases.nim b/compiler/aliases.nim index 4b50fdb28..0006c9fe6 100644 --- a/compiler/aliases.nim +++ b/compiler/aliases.nim @@ -12,9 +12,6 @@ import ast, astalgo, types, trees, intsets -when defined(nimPreviewSlimSystem): - import std/assertions - type TAnalysisResult* = enum arNo, arMaybe, arYes @@ -77,29 +74,24 @@ proc isPartOf*(a, b: PNode): TAnalysisResult = ## cases: ## ## YES-cases: - ## ``` ## x <| x # for general trees ## x[] <| x ## x[i] <| x ## x.f <| x - ## ``` ## ## NO-cases: - ## ``` ## x !<| y # depending on type and symbol kind ## x[constA] !<| x[constB] ## x.f !<| x.g ## x.f !<| y.f iff x !<= y - ## ``` ## ## MAYBE-cases: ## - ## ``` ## x[] ?<| y[] iff compatible type ## ## ## x[] ?<| y depending on type - ## ``` + ## if a.kind == b.kind: case a.kind of nkSym: diff --git a/lib/std/private/asciitables.nim b/compiler/asciitables.nim similarity index 89% rename from lib/std/private/asciitables.nim rename to compiler/asciitables.nim index cbc595651..39bb26a5c 100644 --- a/lib/std/private/asciitables.nim +++ b/compiler/asciitables.nim @@ -1,6 +1,6 @@ #[ -move to std/asciitables.nim once stable, or to a fusion package -once compiler can depend on fusion +move to std/asciitables.nim once stable, or to a nimble paackage +once compiler can depend on nimble ]# type Cell* = object @@ -8,7 +8,7 @@ type Cell* = object width*, row*, col*, ncols*, nrows*: int iterator parseTableCells*(s: string, delim = '\t'): Cell = - ## Iterates over all cells in a `delim`-delimited `s`, after a 1st + ## iterates over all cells in a `delim`-delimited `s`, after a 1st ## pass that computes number of rows, columns, and width of each column. var widths: seq[int] var cell: Cell @@ -69,7 +69,7 @@ iterator parseTableCells*(s: string, delim = '\t'): Cell = finishRow() proc alignTable*(s: string, delim = '\t', fill = ' ', sep = " "): string = - ## Formats a `delim`-delimited `s` representing a table; each cell is aligned + ## formats a `delim`-delimited `s` representing a table; each cell is aligned ## to a width that's computed for each column; consecutive columns are ## delimited by `sep`, and alignment space is filled using `fill`. ## More customized formatting can be done by calling `parseTableCells` directly. diff --git a/compiler/ast.nim b/compiler/ast.nim index f93c8d910..5938d4e53 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -10,27 +10,28 @@ # abstract syntax tree + symbol table import - lineinfos, hashes, options, ropes, idents, int128, tables + lineinfos, hashes, options, ropes, idents, idgen, int128 from strutils import toLowerAscii -when defined(nimPreviewSlimSystem): - import std/assertions - export int128 type TCallingConvention* = enum - ccNimCall = "nimcall" # nimcall, also the default - ccStdCall = "stdcall" # procedure is stdcall - ccCDecl = "cdecl" # cdecl - ccSafeCall = "safecall" # safecall - ccSysCall = "syscall" # system call - ccInline = "inline" # proc should be inlined - ccNoInline = "noinline" # proc should not be inlined - ccFastCall = "fastcall" # fastcall (pass parameters in registers) - ccThisCall = "thiscall" # thiscall (parameters are pushed right-to-left) - ccClosure = "closure" # proc has a closure - ccNoConvention = "noconv" # needed for generating proper C procs sometimes + ccDefault, # proc has no explicit calling convention + ccStdCall, # procedure is stdcall + ccCDecl, # cdecl + ccSafeCall, # safecall + ccSysCall, # system call + ccInline, # proc should be inlined + ccNoInline, # proc should not be inlined + ccFastCall, # fastcall (pass parameters in registers) + ccClosure, # proc has a closure + ccNoConvention # needed for generating proper C procs sometimes + +const + CallingConvToStr*: array[TCallingConvention, string] = ["", "stdcall", + "cdecl", "safecall", "syscall", "inline", "noinline", "fastcall", + "closure", "noconv"] type TNodeKind* = enum # order is extremely important, because ranges are used @@ -207,31 +208,28 @@ type nkPtrTy, # ``ptr T`` nkVarTy, # ``var T`` nkConstTy, # ``const T`` - nkOutTy, # ``out T`` + nkMutableTy, # ``mutable T`` nkDistinctTy, # distinct type nkProcTy, # proc type nkIteratorTy, # iterator type - nkSinkAsgn, # '=sink(x, y)' + nkSharedTy, # 'shared T' + # we use 'nkPostFix' for the 'not nil' addition nkEnumTy, # enum body nkEnumFieldDef, # `ident = expr` in an enumeration nkArgList, # argument list nkPattern, # a special pattern; used for matching - nkHiddenTryStmt, # a hidden try statement + nkHiddenTryStmt, # token used for interpretation nkClosure, # (prc, env)-pair (internally used for code gen) nkGotoState, # used for the state machine (for iterators) nkState, # give a label to a code section (for iterators) nkBreakState, # special break statement for easier code generation nkFuncDef, # a func nkTupleConstr # a tuple constructor - nkError # erroneous AST node - 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 TNodeKinds* = set[TNodeKind] type - TSymFlag* = enum # 49 flags! + TSymFlag* = enum # 40 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 @@ -240,8 +238,6 @@ type sfGlobal, # symbol is at global scope sfForward, # symbol is forward declared - sfWasForwarded, # symbol had a forward declaration - # (implies it's too dangerous to patch its type signature) sfImportc, # symbol is external; imported sfExportc, # symbol is exported (under a specified name) sfMangleCpp, # mangle as cpp (combines with `sfExportc`) @@ -259,20 +255,14 @@ type # *OR*: a proc is indirectly called (used as first class) sfCompilerProc, # proc is a compiler proc, that is a C proc that is # needed for the code generator - sfEscapes # param escapes - # currently unimplemented + sfProcvar, # proc can be passed to a proc var sfDiscriminant, # field is a discriminant in a record/object - sfRequiresInit, # field must be initialized during construction sfDeprecated, # symbol is deprecated sfExplain, # provide more diagnostics when this symbol is used sfError, # usage of symbol should trigger a compile-time error sfShadowed, # a symbol that was shadowed in some inner scope sfThread, # proc will run as a thread # variable is a thread variable - sfCppNonPod, # tells compiler to treat such types as non-pod's, so that - # `thread_local` is used instead of `__thread` for - # {.threadvar.} + `--threads`. Only makes sense for importcpp types. - # This has a performance impact so isn't set by default. sfCompileTime, # proc can be evaluated at compile time sfConstructor, # proc is a C++ constructor sfDispatcher, # copied method symbol is the dispatcher @@ -297,19 +287,6 @@ type sfTemplateParam # symbol is a template parameter sfCursor # variable/field is a cursor, see RFC 177 for details sfInjectDestructors # whether the proc needs the 'injectdestructors' transformation - sfNeverRaises # proc can never raise an exception, not even OverflowDefect - # or out-of-memory - sfSystemRaisesDefect # proc in the system can raise defects - 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' - 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 - # object fields has one. - # - # This is disallowed but can cause the typechecking to go into - # an infinite loop, this flag is used as a sentinel to stop it. TSymFlags* = set[TSymFlag] @@ -328,6 +305,10 @@ const # the compiler will avoid printing such names # in user messages. + sfHoisted* = sfForward + # an expression was hoised to an anonymous variable. + # the flag is applied to the var/let symbol + sfNoForward* = sfRegister # forward declarations are not required (per module) sfReorder* = sfForward @@ -338,10 +319,10 @@ const sfExperimental* = sfOverriden # module uses the .experimental switch sfGoto* = sfOverriden # var is used for 'goto' code generation sfWrittenTo* = sfBorrow # param is assigned to - # currently unimplemented + sfEscapes* = sfProcvar # param escapes sfBase* = sfDiscriminant + sfIsSelf* = sfOverriden # param is 'self' sfCustomPragma* = sfRegister # symbol is custom pragma template - sfTemplateRedefinition* = sfExportc # symbol is a redefinition of an earlier template const # getting ready for the future expr/stmt merge @@ -350,14 +331,11 @@ const nkEffectList* = nkArgList # hacks ahead: an nkEffectList is a node with 4 children: exceptionEffects* = 0 # exceptions at position 0 - requiresEffects* = 1 # 'requires' annotation - ensuresEffects* = 2 # 'ensures' annotation + usesEffects* = 1 # read effects at position 1 + writeEffects* = 2 # write effects at position 2 tagEffects* = 3 # user defined tag ('gc', 'time' etc.) pragmasEffects* = 4 # not an effect, but a slot for pragmas in proc type - forbiddenEffects* = 5 # list of illegal effects - effectListLen* = 6 # list of effects list - nkLastBlockStmts* = {nkRaiseStmt, nkReturnStmt, nkBreakStmt, nkContinueStmt} - # these must be last statements in a block + effectListLen* = 5 # list of effects list type TTypeKind* = enum # order is important! @@ -391,7 +369,7 @@ type tySequence, tyProc, tyPointer, tyOpenArray, - tyString, tyCstring, tyForward, + tyString, tyCString, tyForward, tyInt, tyInt8, tyInt16, tyInt32, tyInt64, # signed integers tyFloat, tyFloat32, tyFloat64, tyFloat128, tyUInt, tyUInt8, tyUInt16, tyUInt32, tyUInt64, @@ -447,17 +425,15 @@ type # instantiation and prior to this it has the potential to # be any type. - tyConcept - # new style concept. + tyOpt + # Builtin optional type tyVoid # now different from tyEmpty, hurray! - tyIterable static: # remind us when TTypeKind stops to fit in a single 64-bit word - # assert TTypeKind.high.ord <= 63 - discard + assert TTypeKind.high.ord <= 63 const tyPureObject* = tyTuple @@ -473,11 +449,6 @@ const tyMetaTypes* = {tyGenericParam, tyTypeDesc, tyUntyped} + tyTypeClasses tyUserTypeClasses* = {tyUserTypeClass, tyUserTypeClassInst} - # consider renaming as `tyAbstractVarRange` - abstractVarRange* = {tyGenericInst, tyRange, tyVar, tyDistinct, tyOrdinal, - tyTypeDesc, tyAlias, tyInferred, tySink, tyOwned} - abstractInst* = {tyGenericInst, tyDistinct, tyOrdinal, tyTypeDesc, tyAlias, - tyInferred, tySink, tyOwned} # xxx what about tyStatic? type TTypeKinds* = set[TTypeKind] @@ -507,13 +478,9 @@ type nfDefaultRefsParam # a default param value references another parameter # the flag is applied to proc default values and to calls nfExecuteOnReload # A top-level statement that will be executed during reloads - nfLastRead # this node is a last read - nfFirstWrite # this node is a first write - nfHasComment # node has a comment - nfUseDefaultField # node has a default value (object constructor) TNodeFlags* = set[TNodeFlag] - TTypeFlag* = enum # keep below 32 for efficiency reasons (now: 46) + TTypeFlag* = enum # keep below 32 for efficiency reasons (now: ~40) tfVarargs, # procedure has C styled varargs # tyArray type represeting a varargs list tfNoSideEffect, # procedure type does not allow side effects @@ -543,11 +510,9 @@ type tfIterator, # type is really an iterator, not a tyProc tfPartial, # type is declared as 'partial' tfNotNil, # type cannot be 'nil' - tfRequiresInit, # type constains a "not nil" constraint somewhere or - # a `requiresInit` field, so the default zero init - # is not appropriate - tfNeedsFullInit, # object type marked with {.requiresInit.} - # all fields must be initialized + + tfNeedsInit, # type constains a "not nil" constraint somewhere or some + # other type so that it requires initialization tfVarIsPtr, # 'var' type is translated like 'ptr' even in C++ mode tfHasMeta, # type contains "wildcard" sub-types such as generic params # or other type classes @@ -576,13 +541,6 @@ type # If it has one, t.destructor is not nil. tfAcyclic # object type was annotated as .acyclic tfIncompleteStruct # treat this type as if it had sizeof(pointer) - tfCompleteStruct - # (for importc types); type is fully specified, allowing to compute - # sizeof, alignof, offsetof at CT - tfExplicitCallConv - tfIsConstructor - tfEffectSystemWorkaround - tfIsOutParam TTypeFlags* = set[TTypeFlag] @@ -624,31 +582,27 @@ type const routineKinds* = {skProc, skFunc, skMethod, skIterator, skConverter, skMacro, skTemplate} - ExportableSymKinds* = {skVar, skLet, skConst, skType, skEnumField, skStub, skAlias} + routineKinds - tfUnion* = tfNoSideEffect tfGcSafe* = tfThread tfObjHasKids* = tfEnumHasHoles tfReturnsNew* = tfInheritable skError* = skUnknown -var - eqTypeFlags* = {tfIterator, tfNotNil, tfVarIsPtr, tfGcSafe, tfNoSideEffect, tfIsOutParam} - ## type flags that are essential for type equality. - ## This is now a variable because for emulation of version:1.0 we - ## might exclude {tfGcSafe, tfNoSideEffect}. + # type flags that are essential for type equality: + eqTypeFlags* = {tfIterator, tfNotNil, tfVarIsPtr} type TMagic* = enum # symbols that require compiler magic: mNone, - mDefined, mDeclared, mDeclaredInScope, mCompiles, mArrGet, mArrPut, mAsgn, + mDefined, mDefinedInScope, mCompiles, mArrGet, mArrPut, mAsgn, mLow, mHigh, mSizeOf, mAlignOf, mOffsetOf, mTypeTrait, mIs, mOf, mAddr, mType, mTypeOf, - mPlugin, mEcho, mShallowCopy, mSlurp, mStaticExec, mStatic, + mRoof, mPlugin, mEcho, mShallowCopy, mSlurp, mStaticExec, mStatic, mParseExprToAst, mParseStmtToAst, mExpandToAst, mQuoteAst, - mInc, mDec, mOrd, + mUnaryLt, mInc, mDec, mOrd, mNew, mNewFinalize, mNewSeq, mNewSeqOfCap, mLengthOpenArray, mLengthStr, mLengthArray, mLengthSeq, + mXLenStr, mXLenSeq, mIncl, mExcl, mCard, mChr, mGCref, mGCunref, mAddI, mSubI, mMulI, mDivI, mModI, @@ -660,42 +614,40 @@ type mEqI, mLeI, mLtI, mEqF64, mLeF64, mLtF64, mLeU, mLtU, + mLeU64, mLtU64, mEqEnum, mLeEnum, mLtEnum, mEqCh, mLeCh, mLtCh, mEqB, mLeB, mLtB, - mEqRef, mLePtr, mLtPtr, + mEqRef, mEqUntracedRef, mLePtr, mLtPtr, mXor, mEqCString, mEqProc, mUnaryMinusI, mUnaryMinusI64, mAbsI, mNot, mUnaryPlusI, mBitnotI, mUnaryPlusF64, mUnaryMinusF64, - mCharToStr, mBoolToStr, - mIntToStr, mInt64ToStr, mFloatToStr, # for compiling nimStdlibVersion < 1.5.1 (not bootstrapping) - mCStrToStr, + mCharToStr, mBoolToStr, mIntToStr, mInt64ToStr, mFloatToStr, mCStrToStr, mStrToStr, mEnumToStr, mAnd, mOr, - mImplies, mIff, mExists, mForall, mOld, mEqStr, mLeStr, mLtStr, - mEqSet, mLeSet, mLtSet, mMulSet, mPlusSet, mMinusSet, + mEqSet, mLeSet, mLtSet, mMulSet, mPlusSet, mMinusSet, mSymDiffSet, mConStrStr, mSlice, mDotDot, # this one is only necessary to give nice compile time warnings mFields, mFieldPairs, mOmpParFor, mAppendStrCh, mAppendStrStr, mAppendSeqElem, - mInSet, mRepr, mExit, + mInRange, mInSet, mRepr, mExit, mSetLengthStr, mSetLengthSeq, mIsPartOf, mAstToStr, mParallel, - mSwap, mIsNil, mArrToSeq, mOpenArrayToSeq, + mSwap, mIsNil, mArrToSeq, mCopyStr, mCopyStrLast, mNewString, mNewStringOfCap, mParseBiggestFloat, - mMove, mWasMoved, mDestroy, mTrace, - mDefault, mUnown, mFinished, mIsolate, mAccessEnv, mAccessTypeField, mReset, - mArray, mOpenArray, mRange, mSet, mSeq, mVarargs, + mMove, mWasMoved, mDestroy, + mDefault, mUnown, mAccessEnv, mAccessTypeInfo, mReset, + mArray, mOpenArray, mRange, mSet, mSeq, mOpt, mVarargs, mRef, mPtr, mVar, mDistinct, mVoid, mTuple, - mOrdinal, mIterableType, + mOrdinal, mInt, mInt8, mInt16, mInt32, mInt64, mUInt, mUInt8, mUInt16, mUInt32, mUInt64, mFloat, mFloat32, mFloat64, mFloat128, mBool, mChar, mString, mCstring, - mPointer, mNil, mExpr, mStmt, mTypeDesc, - mVoidType, mPNimrodNode, mSpawn, mDeepCopy, + mPointer, mEmptySet, mIntSetBaseType, mNil, mExpr, mStmt, mTypeDesc, + mVoidType, mPNimrodNode, mShared, mGuarded, mLock, mSpawn, mDeepCopy, mIsMainModule, mCompileDate, mCompileTime, mProcCall, mCpuEndian, mHostOS, mHostCPU, mBuildOS, mBuildCPU, mAppType, mCompileOption, mCompileOptionArg, @@ -706,22 +658,22 @@ 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, + mNBindSym, mLocals, mNCallSite, mEqIdent, mEqNimrodNode, mSameNodeType, mGetImpl, mNGenSym, mNHint, mNWarning, mNError, - mInstantiationInfo, mGetTypeInfo, mGetTypeInfoV2, - mNimvm, mIntDefine, mStrDefine, mBoolDefine, mGenericDefine, mRunnableExamples, + mInstantiationInfo, mGetTypeInfo, + mNimvm, mIntDefine, mStrDefine, mBoolDefine, mRunnableExamples, mException, mBuiltinType, mSymOwner, mUncheckedArray, mGetImplTransf, - mSymIsInstantiationOf, mNodeId, mPrivateAccess, mZeroDefault + mSymIsInstantiationOf, mNodeId +# things that we can evaluate safely at compile time, even if not asked for it: const - # things that we can evaluate safely at compile time, even if not asked for it: - ctfeWhitelist* = {mNone, mSucc, + ctfeWhitelist* = {mNone, mUnaryLt, mSucc, mPred, mInc, mDec, mOrd, mLengthOpenArray, - mLengthStr, mLengthArray, mLengthSeq, + mLengthStr, mLengthArray, mLengthSeq, mXLenStr, mXLenSeq, mArrGet, mArrPut, mAsgn, mDestroy, mIncl, mExcl, mCard, mChr, mAddI, mSubI, mMulI, mDivI, mModI, @@ -732,47 +684,23 @@ const mEqI, mLeI, mLtI, mEqF64, mLeF64, mLtF64, mLeU, mLtU, + mLeU64, mLtU64, mEqEnum, mLeEnum, mLtEnum, mEqCh, mLeCh, mLtCh, mEqB, mLeB, mLtB, - mEqRef, mEqProc, mLePtr, mLtPtr, mEqCString, mXor, + mEqRef, mEqProc, mEqUntracedRef, mLePtr, mLtPtr, mEqCString, mXor, mUnaryMinusI, mUnaryMinusI64, mAbsI, mNot, mUnaryPlusI, mBitnotI, mUnaryPlusF64, mUnaryMinusF64, - mCharToStr, mBoolToStr, - mIntToStr, mInt64ToStr, mFloatToStr, - mCStrToStr, + mCharToStr, mBoolToStr, mIntToStr, mInt64ToStr, mFloatToStr, mCStrToStr, mStrToStr, mEnumToStr, mAnd, mOr, mEqStr, mLeStr, mLtStr, - mEqSet, mLeSet, mLtSet, mMulSet, mPlusSet, mMinusSet, + mEqSet, mLeSet, mLtSet, mMulSet, mPlusSet, mMinusSet, mSymDiffSet, mConStrStr, mAppendStrCh, mAppendStrStr, mAppendSeqElem, - mInSet, mRepr, mOpenArrayToSeq} - - generatedMagics* = {mNone, mIsolate, mFinished, mOpenArrayToSeq} - ## magics that are generated as normal procs in the backend + mInRange, mInSet, mRepr, + mCopyStr, mCopyStrLast} type - ItemId* = object - module*: int32 - item*: int32 - -proc `$`*(x: ItemId): string = - "(module: " & $x.module & ", item: " & $x.item & ")" - -proc `==`*(a, b: ItemId): bool {.inline.} = - a.item == b.item and a.module == b.module - -proc hash*(x: ItemId): Hash = - var h: Hash = hash(x.module) - h = h !& hash(x.item) - result = !$h - - -type - TIdObj* {.acyclic.} = object of RootObj - itemId*: ItemId - PIdObj* = ref TIdObj - PNode* = ref TNode TNodeSeq* = seq[PNode] PType* = ref TType @@ -796,8 +724,7 @@ type ident*: PIdent else: sons*: TNodeSeq - when defined(nimsuggest): - endInfo*: TLineInfo + comment*: string TStrTable* = object # a table[PIdent] of PSym counter*: int @@ -818,7 +745,7 @@ type locOther # location is something other TLocFlag* = enum lfIndirect, # backend introduced a pointer - lfFullExternalName, # only used when 'conf.cmd == cmdNimfix': Indicates + lfFullExternalName, # only used when 'conf.cmd == cmdPretty': Indicates # that the symbol has been imported via 'importc: "fullname"' and # no format string. lfNoDeepCopy, # no need for a deep copy @@ -852,7 +779,6 @@ type libHeader, libDynamic TLib* = object # also misused for headers! - # keep in sync with PackedLib kind*: TLibKind generated*: bool # needed for the backends: isOverriden*: bool @@ -869,22 +795,35 @@ type PInstantiation* = ref TInstantiation - TScope* {.acyclic.} = object + TScope* = object depthLevel*: int symbols*: TStrTable parent*: PScope - allowPrivateAccess*: seq[PSym] # # enable access to private fields PScope* = ref TScope PLib* = ref TLib - TSym* {.acyclic.} = object of TIdObj # Keep in sync with PackedSym + TSym* {.acyclic.} = object of TIdObj # proc and type instantiations are cached in the generic symbol case kind*: TSymKind + of skType, skGenericParam: + typeInstCache*: seq[PType] of routineKinds: - #procInstCache*: seq[PInstantiation] - gcUnsafetyReason*: PSym # for better error messages regarding gcsafe + procInstCache*: seq[PInstantiation] + gcUnsafetyReason*: PSym # for better error messages wrt gcsafe transformedBody*: PNode # cached body after transf pass + of skModule, skPackage: + # modules keep track of the generic symbols they use from other modules. + # this is because in incremental compilation, when a module is about to + # be replaced with a newer version, we must decrement the usage count + # of all previously used generics. + # For 'import as' we copy the module symbol but shallowCopy the 'tab' + # and set the 'usedGenerics' to ... XXX gah! Better set module.name + # instead? But this doesn't work either. --> We need an skModuleAlias? + # No need, just leave it as skModule but set the owner accordingly and + # check for the owner when touching 'usedGenerics'. + usedGenerics*: seq[PInstantiation] + tab*: TStrTable # interface table for modules of skLet, skVar, skField, skForVar: guard*: PSym bitsize*: int @@ -894,8 +833,6 @@ type typ*: PType name*: PIdent info*: TLineInfo - when defined(nimsuggest): - endInfo*: TLineInfo owner*: PSym flags*: TSymFlags ast*: PNode # syntax tree of proc, iterator, etc.: @@ -910,7 +847,7 @@ type position*: int # used for many different things: # for enum fields its position; # for fields its offset - # for parameters its position (starting with 0) + # for parameters its position # for a conditional: # 1 iff the symbol is defined, else 0 # (or not in symbol table) @@ -922,7 +859,7 @@ type annex*: PLib # additional fields (seldom used, so we use a # reference to another object to save space) when hasFFI: - cname*: string # resolved C declaration name in importc decl, e.g.: + cname*: string # resolved C declaration name in importc decl, eg: # proc fun() {.importc: "$1aux".} => cname = funaux constraint*: PNode # additional constraints like 'lit|result'; also # misused for the codegenDecl pragma in the hope @@ -933,20 +870,20 @@ type allUsages*: seq[TLineInfo] TTypeSeq* = seq[PType] + TLockLevel* = distinct int16 TTypeAttachedOp* = enum ## as usual, order is important here - attachedWasMoved, attachedDestructor, attachedAsgn, attachedSink, attachedTrace, + attachedDispose, attachedDeepCopy TType* {.acyclic.} = object of TIdObj # \ # types are identical iff they have the # same id; there may be multiple copies of a type # in memory! - # Keep in sync with PackedType kind*: TTypeKind # kind of type callConv*: TCallingConvention # for procs flags*: TTypeFlags # flags of the type @@ -963,15 +900,18 @@ type owner*: PSym # the 'owner' of the type sym*: PSym # types have the sym associated with them # it is used for converting types to strings + attachedOps*: array[TTypeAttachedOp, PSym] # destructors, etc. + methods*: seq[(int,PSym)] # attached methods size*: BiggestInt # the size of the type in bytes # -1 means that the size is unkwown align*: int16 # the type's alignment requirements paddingAtEnd*: int16 # + lockLevel*: TLockLevel # lock level as required for deadlock checking loc*: TLoc typeInst*: PType # for generic instantiations the tyGenericInst that led to this # type. - uniqueId*: ItemId # due to a design mistake, we need to keep the real ID here as it - # is required by the --incremental:on mode. + uniqueId*: int # due to a design mistake, we need to keep the real ID here as it + # required by the --incremental:on mode. TPair* = object key*, val*: RootRef @@ -1015,45 +955,13 @@ type TImplication* = enum impUnknown, impNo, impYes -template nodeId(n: PNode): int = cast[int](n) - -type Gconfig = object - # we put comments in a side channel to avoid increasing `sizeof(TNode)`, which - # reduces memory usage given that `PNode` is the most allocated type by far. - comments: Table[int, string] # nodeId => comment - useIc*: bool - -var gconfig {.threadvar.}: Gconfig - -proc setUseIc*(useIc: bool) = gconfig.useIc = useIc - -proc comment*(n: PNode): string = - if nfHasComment in n.flags and not gconfig.useIc: - # IC doesn't track comments, see `packed_ast`, so this could fail - result = gconfig.comments[n.nodeId] - -proc `comment=`*(n: PNode, a: string) = - let id = n.nodeId - if a.len > 0: - # if needed, we could periodically cleanup gconfig.comments when its size increases, - # to ensure only live nodes (and with nfHasComment) have an entry in gconfig.comments; - # for compiling compiler, the waste is very small: - # num calls to newNodeImpl: 14984160 (num of PNode allocations) - # size of gconfig.comments: 33585 - # num of nodes with comments that were deleted and hence wasted: 3081 - n.flags.incl nfHasComment - gconfig.comments[id] = a - elif nfHasComment in n.flags: - n.flags.excl nfHasComment - gconfig.comments.del(id) - # BUGFIX: a module is overloadable so that a proc can have the # same name as an imported module. This is necessary because of # the poor naming choices in the standard library. const OverloadableSyms* = {skProc, skFunc, skMethod, skIterator, - skConverter, skModule, skTemplate, skMacro, skEnumField} + skConverter, skModule, skTemplate, skMacro} GenericTypes*: TTypeKinds = {tyGenericInvocation, tyGenericBody, tyGenericParam} @@ -1067,21 +975,23 @@ const tyBool, tyChar, tyEnum, tyArray, tyObject, tySet, tyTuple, tyRange, tyPtr, tyRef, tyVar, tyLent, tySequence, tyProc, tyPointer, - tyOpenArray, tyString, tyCstring, tyInt..tyInt64, tyFloat..tyFloat128, + tyOpenArray, tyString, tyCString, tyInt..tyInt64, tyFloat..tyFloat128, tyUInt..tyUInt64} IntegralTypes* = {tyBool, tyChar, tyEnum, tyInt..tyInt64, tyFloat..tyFloat128, tyUInt..tyUInt64} # weird name because it contains tyFloat ConstantDataTypes*: TTypeKinds = {tyArray, tySet, tyTuple, tySequence} - NilableTypes*: TTypeKinds = {tyPointer, tyCstring, tyRef, tyPtr, - tyProc, tyError} # TODO + NilableTypes*: TTypeKinds = {tyPointer, tyCString, tyRef, tyPtr, + tyProc, tyError} PtrLikeKinds*: TTypeKinds = {tyPointer, tyPtr} # for VM + ExportableSymKinds* = {skVar, skConst, skProc, skFunc, skMethod, skType, + skIterator, + skMacro, skTemplate, skConverter, skEnumField, skLet, skStub, skAlias} PersistentNodeFlags*: TNodeFlags = {nfBase2, nfBase8, nfBase16, nfDotSetter, nfDotField, nfIsRef, nfIsPtr, nfPreventCg, nfLL, nfFromTemplate, nfDefaultRefsParam, - nfExecuteOnReload, nfLastRead, - nfFirstWrite, nfUseDefaultField} + nfExecuteOnReload} namePos* = 0 patternPos* = 1 # empty except for term rewriting macros genericParamsPos* = 2 @@ -1104,9 +1014,7 @@ const nkFloatLiterals* = {nkFloatLit..nkFloat128Lit} nkLambdaKinds* = {nkLambda, nkDo} declarativeDefs* = {nkProcDef, nkFuncDef, nkMethodDef, nkIteratorDef, nkConverterDef} - routineDefs* = declarativeDefs + {nkMacroDef, nkTemplateDef} procDefs* = nkLambdaKinds + declarativeDefs - callableDefs* = nkLambdaKinds + routineDefs nkSymChoices* = {nkClosedSymChoice, nkOpenSymChoice} nkStrKinds* = {nkStrLit..nkTripleStrLit} @@ -1117,62 +1025,31 @@ const defaultSize = -1 defaultAlignment = -1 - defaultOffset* = -1 + defaultOffset = -1 -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 - else: nil -const - moduleShift = when defined(cpu32): 20 else: 24 +proc getnimblePkg*(a: PSym): PSym = + result = a + while result != nil: + case result.kind + of skModule: + result = result.owner + assert result.kind == skPackage + of skPackage: + if result.owner == nil: + break + else: + result = result.owner + else: + assert false, $result.kind -template id*(a: PIdObj): int = - let x = a - (x.itemId.module.int shl moduleShift) + x.itemId.item.int - -type - IdGenerator* = ref object # unfortunately, we really need the 'shared mutable' aspect here. - module*: int32 - symId*: int32 - typeId*: int32 - sealed*: bool - -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) - -proc nextSymId*(x: IdGenerator): ItemId {.inline.} = - assert(not x.sealed) - inc x.symId - result = ItemId(module: x.module, item: x.symId) - -proc nextTypeId*(x: IdGenerator): ItemId {.inline.} = - assert(not x.sealed) - inc x.typeId - result = ItemId(module: x.module, item: x.typeId) - -when false: - proc nextId*(x: IdGenerator): ItemId {.inline.} = - inc x.item - result = x[] - -when false: - proc storeBack*(dest: var IdGenerator; src: IdGenerator) {.inline.} = - assert dest.ItemId.module == src.ItemId.module - if dest.ItemId.item > src.ItemId.item: - echo dest.ItemId.item, " ", src.ItemId.item, " ", src.ItemId.module - assert dest.ItemId.item <= src.ItemId.item - dest = src +proc getnimblePkgId*(a: PSym): int = + let b = a.getnimblePkg + result = if b == nil: -1 else: b.id var ggDebug* {.deprecated.}: bool ## convenience switch for trying out things +#var +# gMainPackageId*: int proc isCallExpr*(n: PNode): bool = result = n.kind in nkCallKinds @@ -1182,7 +1059,11 @@ proc discardSons*(father: PNode) type Indexable = PNode | PType proc len*(n: Indexable): int {.inline.} = - result = n.sons.len + when defined(nimNoNilSeqs): + result = n.sons.len + else: + if isNil(n.sons): result = 0 + else: result = n.sons.len proc safeLen*(n: PNode): int {.inline.} = ## works even for leaves. @@ -1191,15 +1072,14 @@ proc safeLen*(n: PNode): int {.inline.} = proc safeArrLen*(n: PNode): int {.inline.} = ## works for array-like objects (strings passed as openArray in VM). - if n.kind in {nkStrLit..nkTripleStrLit}: result = n.strVal.len + if n.kind in {nkStrLit..nkTripleStrLit}:result = n.strVal.len elif n.kind in {nkNone..nkFloat128Lit}: result = 0 else: result = n.len proc add*(father, son: Indexable) = assert son != nil - father.sons.add(son) - -proc addAllowNil*(father, son: Indexable) {.inline.} = + when not defined(nimNoNilSeqs): + if isNil(father.sons): father.sons = @[] father.sons.add(son) template `[]`*(n: Indexable, i: int): Indexable = n.sons[i] @@ -1208,77 +1088,12 @@ template `[]=`*(n: Indexable, i: int; x: Indexable) = n.sons[i] = x template `[]`*(n: Indexable, i: BackwardsIndex): Indexable = n[n.len - i.int] template `[]=`*(n: Indexable, i: BackwardsIndex; x: Indexable) = n[n.len - i.int] = x -proc getDeclPragma*(n: PNode): PNode = - ## return the `nkPragma` node for declaration `n`, or `nil` if no pragma was found. - ## Currently only supports routineDefs + {nkTypeDef}. - case n.kind - of routineDefs: - if n[pragmasPos].kind != nkEmpty: result = n[pragmasPos] - of nkTypeDef: - #[ - type F3*{.deprecated: "x3".} = int - - TypeSection - TypeDef - PragmaExpr - Postfix - Ident "*" - Ident "F3" - Pragma - ExprColonExpr - Ident "deprecated" - StrLit "x3" - Empty - Ident "int" - ]# - if n[0].kind == nkPragmaExpr: - result = n[0][1] - else: - # support as needed for `nkIdentDefs` etc. - result = nil - if result != nil: - assert result.kind == nkPragma, $(result.kind, n.kind) - -proc extractPragma*(s: PSym): PNode = - ## gets the pragma node of routine/type/var/let/const symbol `s` - if s.kind in routineKinds: - result = s.ast[pragmasPos] - elif s.kind in {skType, skVar, skLet, skConst}: - if s.ast != nil and s.ast.len > 0: - if s.ast[0].kind == nkPragmaExpr and s.ast[0].len > 1: - # s.ast = nkTypedef / nkPragmaExpr / [nkSym, nkPragma] - result = s.ast[0][1] - assert result == nil or result.kind == nkPragma - -proc skipPragmaExpr*(n: PNode): PNode = - ## if pragma expr, give the node the pragmas are applied to, - ## otherwise give node itself - if n.kind == nkPragmaExpr: - result = n[0] - else: - result = n - -proc setInfoRecursive*(n: PNode, info: TLineInfo) = - ## set line info recursively - if n != nil: - for i in 0.. 0: - newSeq(result.sons, children) - setIdMaybe() - -proc newNodeIT*(kind: TNodeKind, info: TLineInfo, typ: PType): PNode = - ## new node with line info, type, and no children - result = newNode(kind) - result.info = info - result.typ = typ - proc newTree*(kind: TNodeKind; children: varargs[PNode]): PNode = result = newNode(kind) if children.len > 0: result.info = children[0].info result.sons = @children -proc newTreeI*(kind: TNodeKind; info: TLineInfo; children: varargs[PNode]): PNode = - result = newNodeI(kind, info) - if children.len > 0: - result.info = children[0].info - result.sons = @children - -proc newTreeIT*(kind: TNodeKind; info: TLineInfo; typ: PType; children: varargs[PNode]): PNode = - result = newNodeIT(kind, info, typ) - if children.len > 0: - result.info = children[0].info - result.sons = @children - template previouslyInferred*(t: PType): PType = if t.sons.len > 1: t.lastSon else: nil -when false: - import tables, strutils - var x: CountTable[string] - - addQuitProc proc () {.noconv.} = - for k, v in pairs(x): - echo k - echo v - -proc newSym*(symKind: TSymKind, name: PIdent, id: ItemId, owner: PSym, +proc newSym*(symKind: TSymKind, name: PIdent, owner: PSym, info: TLineInfo; options: TOptions = {}): PSym = # generates a symbol and initializes the hash field too - result = PSym(name: name, kind: symKind, flags: {}, info: info, itemId: id, + result = PSym(name: name, kind: symKind, flags: {}, info: info, id: getID(), options: options, owner: owner, offset: defaultOffset) - when false: - if id.module == 48 and id.item == 39: - writeStackTrace() - echo "kind ", symKind, " ", name.s - if owner != nil: echo owner.name.s + when debugIds: + registerId(result) proc astdef*(s: PSym): PNode = # get only the definition (initializer) portion of the ast - if s.ast != nil and s.ast.kind in {nkIdentDefs, nkConstDef}: + if s.ast != nil and s.ast.kind == nkIdentDefs: s.ast[2] else: s.ast @@ -1413,7 +1181,10 @@ proc copyObjectSet*(dest: var TObjectSet, src: TObjectSet) = for i in 0..high(src.data): dest.data[i] = src.data[i] proc discardSons*(father: PNode) = - father.sons = @[] + when defined(nimNoNilSeqs): + father.sons = @[] + else: + father.sons = nil proc withInfo*(n: PNode, info: TLineInfo): PNode = n.info = info @@ -1436,6 +1207,43 @@ proc newSymNode*(sym: PSym, info: TLineInfo): PNode = result.typ = sym.typ result.info = info +proc newNodeI*(kind: TNodeKind, info: TLineInfo): PNode = + result = PNode(kind: kind, info: info) + when defined(useNodeIds): + result.id = gNodeId + if result.id == nodeIdToDebug: + echo "KIND ", result.kind + writeStackTrace() + inc gNodeId + +proc newNodeI*(kind: TNodeKind, info: TLineInfo, children: int): PNode = + result = PNode(kind: kind, info: info) + if children > 0: + newSeq(result.sons, children) + when defined(useNodeIds): + result.id = gNodeId + if result.id == nodeIdToDebug: + echo "KIND ", result.kind + writeStackTrace() + inc gNodeId + +proc newNode*(kind: TNodeKind, info: TLineInfo, sons: TNodeSeq = @[], + typ: PType = nil): PNode = + # XXX use shallowCopy here for ownership transfer: + result = PNode(kind: kind, info: info, typ: typ) + result.sons = sons + when defined(useNodeIds): + result.id = gNodeId + if result.id == nodeIdToDebug: + echo "KIND ", result.kind + writeStackTrace() + inc gNodeId + +proc newNodeIT*(kind: TNodeKind, info: TLineInfo, typ: PType): PNode = + result = newNode(kind) + result.info = info + result.typ = typ + proc newIntNode*(kind: TNodeKind, intVal: BiggestInt): PNode = result = newNode(kind) result.intVal = intVal @@ -1455,8 +1263,12 @@ proc skipTypes*(t: PType, kinds: TTypeKinds): PType = while result.kind in kinds: result = lastSon(result) proc newIntTypeNode*(intVal: BiggestInt, typ: PType): PNode = - let kind = skipTypes(typ, abstractVarRange).kind - case kind + + # this is dirty. abstractVarRange isn't defined yet and therefore it + # is duplicated here. + const abstractVarRange = {tyGenericInst, tyRange, tyVar, tyDistinct, tyOrdinal, + tyTypeDesc, tyAlias, tyInferred, tySink, tyOwned} + case skipTypes(typ, abstractVarRange).kind of tyInt: result = newNode(nkIntLit) of tyInt8: result = newNode(nkInt8Lit) of tyInt16: result = newNode(nkInt16Lit) @@ -1468,12 +1280,9 @@ proc newIntTypeNode*(intVal: BiggestInt, typ: PType): PNode = of tyUInt16: result = newNode(nkUInt16Lit) of tyUInt32: result = newNode(nkUInt32Lit) of tyUInt64: result = newNode(nkUInt64Lit) - of tyBool, tyEnum: + else: # tyBool, tyEnum # XXX: does this really need to be the kind nkIntLit? result = newNode(nkIntLit) - of tyStatic: # that's a pre-existing bug, will fix in another PR - result = newNode(nkIntLit) - else: doAssert false, $kind result.intVal = intVal result.typ = typ @@ -1502,8 +1311,16 @@ proc newProcNode*(kind: TNodeKind, info: TLineInfo, body: PNode, pragmas, exceptions, body] const + UnspecifiedLockLevel* = TLockLevel(-1'i16) + MaxLockLevel* = 1000'i16 + UnknownLockLevel* = TLockLevel(1001'i16) AttachedOpToStr*: array[TTypeAttachedOp, string] = [ - "=wasMoved", "=destroy", "=copy", "=sink", "=trace", "=deepcopy"] + "=destroy", "=", "=sink", "=trace", "=dispose", "=deepcopy"] + +proc `$`*(x: TLockLevel): string = + if x.ord == UnspecifiedLockLevel.ord: result = "" + elif x.ord == UnknownLockLevel.ord: result = "" + else: result = $int16(x) proc `$`*(s: PSym): string = if s != nil: @@ -1511,25 +1328,33 @@ proc `$`*(s: PSym): string = else: result = "" -proc newType*(kind: TTypeKind, id: ItemId; owner: PSym): PType = +proc newType*(kind: TTypeKind, owner: PSym): PType = + let id = getID() result = PType(kind: kind, owner: owner, size: defaultSize, - align: defaultAlignment, itemId: id, - uniqueId: id) + align: defaultAlignment, id: id, uniqueId: id, + lockLevel: UnspecifiedLockLevel) + when debugIds: + registerId(result) when false: - if result.itemId.module == 55 and result.itemId.item == 2: + if result.id == 76426: echo "KNID ", kind writeStackTrace() - proc mergeLoc(a: var TLoc, b: TLoc) = - if a.k == low(typeof(a.k)): a.k = b.k - if a.storage == low(typeof(a.storage)): a.storage = b.storage - a.flags.incl b.flags + if a.k == low(a.k): a.k = b.k + if a.storage == low(a.storage): a.storage = b.storage + a.flags = a.flags + b.flags if a.lode == nil: a.lode = b.lode - if a.r == "": a.r = b.r + if a.r == nil: a.r = b.r proc newSons*(father: Indexable, length: int) = - setLen(father.sons, length) + when defined(nimNoNilSeqs): + setLen(father.sons, length) + else: + if isNil(father.sons): + newSeq(father.sons, length) + else: + setLen(father.sons, length) proc assignType*(dest, src: PType) = dest.kind = src.kind @@ -1538,10 +1363,12 @@ proc assignType*(dest, src: PType) = dest.n = src.n dest.size = src.size dest.align = src.align + dest.attachedOps = src.attachedOps + dest.lockLevel = src.lockLevel # this fixes 'type TLock = TSysLock': if src.sym != nil: if dest.sym != nil: - dest.sym.flags.incl src.sym.flags-{sfUsed, sfExported} + dest.sym.flags = dest.sym.flags + (src.sym.flags-{sfExported}) if dest.sym.annex == nil: dest.sym.annex = src.sym.annex mergeLoc(dest.sym.loc, src.sym.loc) else: @@ -1549,41 +1376,49 @@ proc assignType*(dest, src: PType) = newSons(dest, src.len) for i in 0..= nkNone and n.kind <= nkNilLit proc isEmptyType*(t: PType): bool {.inline.} = - ## 'void' and 'typed' types are often equivalent to 'nil' these days: + ## 'void' and 'stmt' types are often equivalent to 'nil' these days: result = t == nil or t.kind in {tyVoid, tyTyped} proc makeStmtList*(n: PNode): PNode = @@ -1960,20 +1793,19 @@ proc skipStmtList*(n: PNode): PNode = else: result = n -proc toVar*(typ: PType; kind: TTypeKind; idgen: IdGenerator): PType = +proc toVar*(typ: PType): PType = ## If ``typ`` is not a tyVar then it is converted into a `var ` and ## returned. Otherwise ``typ`` is simply returned as-is. result = typ - if typ.kind != kind: - result = newType(kind, nextTypeId(idgen), typ.owner) + if typ.kind != tyVar: + result = newType(tyVar, typ.owner) rawAddSon(result, typ) -proc toRef*(typ: PType; idgen: IdGenerator): PType = +proc toRef*(typ: PType): PType = ## If ``typ`` is a tyObject then it is converted into a `ref ` and ## returned. Otherwise ``typ`` is simply returned as-is. - result = typ if typ.skipTypes({tyAlias, tyGenericInst}).kind == tyObject: - result = newType(tyRef, nextTypeId(idgen), typ.owner) + result = newType(tyRef, typ.owner) rawAddSon(result, typ) proc toObject*(typ: PType): PType = @@ -1984,26 +1816,6 @@ proc toObject*(typ: PType): PType = if t.kind == tyRef: t.lastSon else: typ -proc toObjectFromRefPtrGeneric*(typ: PType): PType = - #[ - See also `toObject`. - Finds the underlying `object`, even in cases like these: - type - B[T] = object f0: int - A1[T] = ref B[T] - A2[T] = ref object f1: int - A3 = ref object f2: int - A4 = object f3: int - ]# - result = typ - while true: - case result.kind - of tyGenericBody: result = result.lastSon - of tyRef, tyPtr, tyGenericInst, tyGenericInvocation, tyAlias: result = result[0] - # automatic dereferencing is deep, refs #18298. - else: break - assert result.sym != nil - proc isImportedException*(t: PType; conf: ConfigRef): bool = assert t != nil @@ -2018,14 +1830,8 @@ proc isImportedException*(t: PType; conf: ConfigRef): bool = proc isInfixAs*(n: PNode): bool = return n.kind == nkInfix and n[0].kind == nkIdent and n[0].ident.s == "as" -proc skipColon*(n: PNode): PNode = - result = n - if n.kind == nkExprColonExpr: - 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: + if n.kind == nkSym and n.typ.kind == tyStatic and n.typ.n == nil: return n for son in n: @@ -2041,38 +1847,32 @@ when false: for i in 0.. 0)) + result = fn.typ != nil and fn.typ.n != nil and ((fn.typ.n[0].len < effectListLen) or + (fn.typ.n[0][exceptionEffects] != nil and + fn.typ.n[0][exceptionEffects].safeLen > 0)) proc toHumanStrImpl[T](kind: T, num: static int): string = result = $kind @@ -2122,20 +1922,3 @@ proc toHumanStr*(kind: TSymKind): string = proc toHumanStr*(kind: TTypeKind): string = ## strips leading `tk` result = toHumanStrImpl(kind, 2) - -proc skipAddr*(n: PNode): PNode {.inline.} = - (if n.kind == nkHiddenAddr: n[0] else: n) - -proc isNewStyleConcept*(n: PNode): bool {.inline.} = - assert n.kind == nkTypeClassTy - result = n[0].kind == nkEmpty - -proc isOutParam*(t: PType): bool {.inline.} = tfIsOutParam in t.flags - -const - nodesToIgnoreSet* = {nkNone..pred(nkSym), succ(nkSym)..nkNilLit, - nkTypeSection, nkProcDef, nkConverterDef, - nkMethodDef, nkIteratorDef, nkMacroDef, nkTemplateDef, nkLambda, nkDo, - nkFuncDef, nkConstSection, nkConstDef, nkIncludeStmt, nkImportStmt, - nkExportStmt, nkPragma, nkCommentStmt, nkBreakState, - nkTypeOfExpr, nkMixinStmt, nkBindStmt} diff --git a/compiler/astalgo.nim b/compiler/astalgo.nim index 4e09fab02..fd95b3780 100644 --- a/compiler/astalgo.nim +++ b/compiler/astalgo.nim @@ -12,14 +12,9 @@ # the data structures here are used in various places of the compiler. import - ast, hashes, intsets, options, lineinfos, ropes, idents, rodutils, + ast, hashes, intsets, strutils, options, lineinfos, ropes, idents, rodutils, msgs -import strutils except addf - -when defined(nimPreviewSlimSystem): - import std/assertions - 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 @@ -29,55 +24,55 @@ proc typeToYaml*(conf: ConfigRef; n: PType, indent: int = 0, maxRecDepth: int = proc symToYaml*(conf: ConfigRef; n: PSym, indent: int = 0, maxRecDepth: int = - 1): Rope proc lineInfoToStr*(conf: ConfigRef; info: TLineInfo): Rope +when declared(echo): + # these are for debugging only: They are not really deprecated, but I want + # the warning so that release versions do not contain debugging statements: + proc debug*(n: PSym; conf: ConfigRef = nil) {.exportc: "debugSym", deprecated.} + proc debug*(n: PType; conf: ConfigRef = nil) {.exportc: "debugType", deprecated.} + proc debug*(n: PNode; conf: ConfigRef = nil) {.exportc: "debugNode", deprecated.} -# these are for debugging only: They are not really deprecated, but I want -# the warning so that release versions do not contain debugging statements: -proc debug*(n: PSym; conf: ConfigRef = nil) {.exportc: "debugSym", deprecated.} -proc debug*(n: PType; conf: ConfigRef = nil) {.exportc: "debugType", deprecated.} -proc debug*(n: PNode; conf: ConfigRef = nil) {.exportc: "debugNode", deprecated.} + proc typekinds*(t: PType) {.deprecated.} = + var t = t + var s = "" + while t != nil and t.len > 0: + s.add $t.kind + s.add " " + t = t.lastSon + echo s -proc typekinds*(t: PType) {.deprecated.} = - var t = t - var s = "" - while t != nil and t.len > 0: - s.add $t.kind - s.add " " - t = t.lastSon - echo s - -template debug*(x: PSym|PType|PNode) {.deprecated.} = - when compiles(c.config): - debug(c.config, x) - elif compiles(c.graph.config): - debug(c.graph.config, x) - else: - error() - -template debug*(x: auto) {.deprecated.} = - echo x - -template mdbg*: bool {.deprecated.} = - when compiles(c.graph): - c.module.fileIdx == c.graph.config.projectMainIdx - elif compiles(c.module): - c.module.fileIdx == c.config.projectMainIdx - elif compiles(c.c.module): - c.c.module.fileIdx == c.c.config.projectMainIdx - elif compiles(m.c.module): - m.c.module.fileIdx == m.c.config.projectMainIdx - elif compiles(cl.c.module): - cl.c.module.fileIdx == cl.c.config.projectMainIdx - elif compiles(p): - when compiles(p.lex): - p.lex.fileIdx == p.lex.config.projectMainIdx + template debug*(x: PSym|PType|PNode) {.deprecated.} = + when compiles(c.config): + debug(c.config, x) + elif compiles(c.graph.config): + debug(c.graph.config, x) else: - p.module.module.fileIdx == p.config.projectMainIdx - elif compiles(m.module.fileIdx): - m.module.fileIdx == m.config.projectMainIdx - elif compiles(L.fileIdx): - L.fileIdx == L.config.projectMainIdx - else: - error() + error() + + template debug*(x: auto) {.deprecated.} = + echo x + + template mdbg*: bool {.deprecated.} = + when compiles(c.graph): + c.module.fileIdx == c.graph.config.projectMainIdx + elif compiles(c.module): + c.module.fileIdx == c.config.projectMainIdx + elif compiles(c.c.module): + c.c.module.fileIdx == c.c.config.projectMainIdx + elif compiles(m.c.module): + m.c.module.fileIdx == m.c.config.projectMainIdx + elif compiles(cl.c.module): + cl.c.module.fileIdx == cl.c.config.projectMainIdx + elif compiles(p): + when compiles(p.lex): + p.lex.fileIdx == p.lex.config.projectMainIdx + else: + p.module.module.fileIdx == p.config.projectMainIdx + elif compiles(m.module.fileIdx): + m.module.fileIdx == m.config.projectMainIdx + elif compiles(L.fileIdx): + L.fileIdx == L.config.projectMainIdx + else: + error() # --------------------------- ident tables ---------------------------------- proc idTableGet*(t: TIdTable, key: PIdObj): RootRef @@ -115,14 +110,14 @@ proc iiTablePut*(t: var TIITable, key, val: int) # implementation -proc skipConvCastAndClosure*(n: PNode): PNode = +proc skipConvAndClosure*(n: PNode): PNode = result = n while true: case result.kind of nkObjUpConv, nkObjDownConv, nkChckRange, nkChckRangeF, nkChckRange64, nkClosure: result = result[0] - of nkHiddenStdConv, nkHiddenSubConv, nkConv, nkCast: + of nkHiddenStdConv, nkHiddenSubConv, nkConv: result = result[1] else: break @@ -187,7 +182,6 @@ proc getModule*(s: PSym): PSym = assert((result.kind == skModule) or (result.owner != result)) while result != nil and result.kind != skModule: result = result.owner -proc fromSystem*(op: PSym): bool {.inline.} = sfSystemModule in getModule(op).flags proc getSymFromList*(list: PNode, ident: PIdent, start: int = 0): PSym = for i in start..' suffix that we need to ## ignore, see compiler / evaltempl.nim, snippet: - ## ``` - ## result.add newIdentNode(getIdent(c.ic, x.name.s & "\`gensym" & $x.id), + ## + ##..code-block:: nim + ## + ## result.add newIdentNode(getIdent(c.ic, x.name.s & "\`gensym" & $x.id), ## if c.instLines: actual.info else: templ.info) - ## ``` for i in 1.. 0: sonsRope = rope("[") @@ -349,7 +344,7 @@ proc typeToYamlAux(conf: ConfigRef; n: PType, marker: var IntSet, indent: int, result.addf("$N$1\"n\": $2", [istr, treeToYamlAux(conf, n.n, marker, indent + 2, maxRecDepth - 1)]) if card(n.flags) > 0: result.addf("$N$1\"flags\": $2", [istr, flagsToStr(n.flags)]) - result.addf("$N$1\"callconv\": $2", [istr, makeYamlString($n.callConv)]) + result.addf("$N$1\"callconv\": $2", [istr, makeYamlString(CallingConvToStr[n.callConv])]) result.addf("$N$1\"size\": $2", [istr, rope(n.size)]) result.addf("$N$1\"align\": $2", [istr, rope(n.align)]) result.addf("$N$1\"sons\": $2", [istr, sonsRope]) @@ -589,26 +584,16 @@ proc value(this: var DebugPrinter; value: PNode) = this.openCurly this.key "kind" this.value value.kind - if value.comment.len > 0: - this.key "comment" - this.value value.comment when defined(useNodeIds): this.key "id" this.value value.id if this.conf != nil: this.key "info" this.value $lineInfoToStr(this.conf, value.info) - if value.flags != {}: + if card(value.flags) > 0: this.key "flags" this.value value.flags - if value.typ != nil: - this.key "typ" - this.value value.typ.kind - else: - this.key "typ" - this.value "nil" - case value.kind of nkCharLit..nkUInt64Lit: this.key "intVal" @@ -642,30 +627,30 @@ proc value(this: var DebugPrinter; value: PNode) = this.closeCurly +when declared(echo): + proc debug(n: PSym; conf: ConfigRef) = + var this: DebugPrinter + this.visited = initTable[pointer, int]() + this.renderSymType = true + this.useColor = not defined(windows) + this.value(n) + echo($this.res) -proc debug(n: PSym; conf: ConfigRef) = - var this: DebugPrinter - this.visited = initTable[pointer, int]() - this.renderSymType = true - this.useColor = not defined(windows) - this.value(n) - echo($this.res) + proc debug(n: PType; conf: ConfigRef) = + var this: DebugPrinter + this.visited = initTable[pointer, int]() + this.renderSymType = true + this.useColor = not defined(windows) + this.value(n) + echo($this.res) -proc debug(n: PType; conf: ConfigRef) = - var this: DebugPrinter - this.visited = initTable[pointer, int]() - this.renderSymType = true - this.useColor = not defined(windows) - this.value(n) - echo($this.res) - -proc debug(n: PNode; conf: ConfigRef) = - var this: DebugPrinter - this.visited = initTable[pointer, int]() - #this.renderSymType = true - this.useColor = not defined(windows) - this.value(n) - echo($this.res) + proc debug(n: PNode; conf: ConfigRef) = + var this: DebugPrinter + this.visited = initTable[pointer, int]() + #this.renderSymType = true + this.useColor = not defined(windows) + this.value(n) + echo($this.res) proc nextTry(h, maxHash: Hash): Hash = result = ((5 * h) + 1) and maxHash @@ -766,9 +751,9 @@ proc strTableAdd*(t: var TStrTable, n: PSym) = proc strTableInclReportConflict*(t: var TStrTable, n: PSym; onConflictKeepOld = false): PSym = - # if `t` has a conflicting symbol (same identifier as `n`), return it - # otherwise return `nil`. Incl `n` to `t` unless `onConflictKeepOld = true` - # and a conflict was found. + # returns true if n is already in the string table: + # It is essential that `n` is written nevertheless! + # This way the newest redefinition is picked by the semantic analyses! assert n.name != nil var h: Hash = n.name.h and high(t.data) var replaceSlot = -1 @@ -784,10 +769,9 @@ proc strTableInclReportConflict*(t: var TStrTable, n: PSym; replaceSlot = h h = nextTry(h, high(t.data)) if replaceSlot >= 0: - result = t.data[replaceSlot] # found it if not onConflictKeepOld: t.data[replaceSlot] = n # overwrite it with newer definition! - return result # but return the old one + return t.data[replaceSlot] # found it elif mustRehash(t.data.len, t.counter): strTableEnlarge(t) strTableRawInsert(t.data, n) @@ -816,21 +800,16 @@ type name*: PIdent proc nextIdentIter*(ti: var TIdentIter, tab: TStrTable): PSym = - # hot spots var h = ti.h and high(tab.data) var start = h - var p {.cursor.} = tab.data[h] - while p != nil: - if p.name.id == ti.name.id: break + result = tab.data[h] + while result != nil: + if result.name.id == ti.name.id: break h = nextTry(h, high(tab.data)) if h == start: - p = nil + result = nil break - p = tab.data[h] - if p != nil: - result = p # increase the count - else: - result = nil + result = tab.data[h] ti.h = nextTry(h, high(tab.data)) proc initIdentIter*(ti: var TIdentIter, tab: TStrTable, s: PIdent): PSym = @@ -1061,14 +1040,3 @@ proc isAddrNode*(n: PNode): bool = 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: - result.add ", " - result.add sym.name.s - -proc isDiscriminantField*(n: PNode): bool = - if n.kind == nkCheckedFieldExpr: sfDiscriminant in n[0][1].sym.flags - elif n.kind == nkDotExpr: sfDiscriminant in n[1].sym.flags - else: false diff --git a/compiler/astmsgs.nim b/compiler/astmsgs.nim deleted file mode 100644 index a9027126a..000000000 --- a/compiler/astmsgs.nim +++ /dev/null @@ -1,39 +0,0 @@ -# this module avoids ast depending on msgs or vice versa -import std/strutils -import options, ast, msgs - -proc typSym*(t: PType): PSym = - result = t.sym - if result == nil and t.kind == tyGenericInst: # this might need to be refined - result = t[0].sym - -proc addDeclaredLoc*(result: var string, conf: ConfigRef; sym: PSym) = - result.add " [$1 declared in $2]" % [sym.kind.toHumanStr, toFileLineCol(conf, sym.info)] - -proc addDeclaredLocMaybe*(result: var string, conf: ConfigRef; sym: PSym) = - if optDeclaredLocs in conf.globalOptions and sym != nil: - addDeclaredLoc(result, conf, sym) - -proc addDeclaredLoc*(result: var string, conf: ConfigRef; typ: PType) = - # xxx figure out how to resolve `tyGenericParam`, e.g. for - # proc fn[T](a: T, b: T) = discard - # fn(1.1, "a") - let typ = typ.skipTypes(abstractInst + {tyStatic, tySequence, tyArray, tySet, tyUserTypeClassInst, tyVar, tyRef, tyPtr} - {tyRange}) - 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) - -template quoteExpr*(a: string): untyped = - ## can be used for quoting expressions in error msgs. - "'" & a & "'" - -proc genFieldDefect*(conf: ConfigRef, field: string, disc: PSym): string = - let obj = disc.owner.name.s # `types.typeToString` might be better, eg for generics - result = "field '$#' is not accessible for type '$#'" % [field, obj] - if optDeclaredLocs in conf.globalOptions: - result.add " [discriminant declared in $#]" % toFileLineCol(conf, disc.info) - result.add " using '$# = " % disc.name.s diff --git a/compiler/backendpragmas.nim b/compiler/backendpragmas.nim deleted file mode 100644 index b18644810..000000000 --- a/compiler/backendpragmas.nim +++ /dev/null @@ -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..= 0) x[int(elem.divElemSize)] = x[int(elem.divElemSize)] or (One shl elem.modElemSize) -proc bitSetExcl*(x: var TBitSet, elem: BiggestInt) = +proc bitSetExcl(x: var TBitSet, elem: BiggestInt) = x[int(elem.divElemSize)] = x[int(elem.divElemSize)] and not(One shl elem.modElemSize) -proc bitSetInit*(b: var TBitSet, length: int) = +proc bitSetInit(b: var TBitSet, length: int) = newSeq(b, length) -proc bitSetUnion*(x: var TBitSet, y: TBitSet) = +proc bitSetUnion(x: var TBitSet, y: TBitSet) = for i in 0..high(x): x[i] = x[i] or y[i] -proc bitSetDiff*(x: var TBitSet, y: TBitSet) = +proc bitSetDiff(x: var TBitSet, y: TBitSet) = for i in 0..high(x): x[i] = x[i] and not y[i] -proc bitSetSymDiff*(x: var TBitSet, y: TBitSet) = +proc bitSetSymDiff(x: var TBitSet, y: TBitSet) = for i in 0..high(x): x[i] = x[i] xor y[i] -proc bitSetIntersect*(x: var TBitSet, y: TBitSet) = +proc bitSetIntersect(x: var TBitSet, y: TBitSet) = for i in 0..high(x): x[i] = x[i] and y[i] -proc bitSetEquals*(x, y: TBitSet): bool = +proc bitSetEquals(x, y: TBitSet): bool = for i in 0..high(x): if x[i] != y[i]: return false result = true -proc bitSetContains*(x, y: TBitSet): bool = +proc bitSetContains(x, y: TBitSet): bool = for i in 0..high(x): if (x[i] and not y[i]) != Zero: return false @@ -86,6 +96,6 @@ const populationCount: array[uint8, uint8] = block: arr -proc bitSetCard*(x: TBitSet): BiggestInt = +proc bitSetCard(x: TBitSet): BiggestInt = for it in x: result.inc int(populationCount[it]) diff --git a/compiler/btrees.nim b/compiler/btrees.nim index c79442249..65edc54f3 100644 --- a/compiler/btrees.nim +++ b/compiler/btrees.nim @@ -10,16 +10,13 @@ ## BTree implementation with few features, but good enough for the ## Nim compiler's needs. -when defined(nimPreviewSlimSystem): - import std/assertions - const M = 512 # max children per B-tree node = M-1 # (must be even and greater than 2) Mhalf = M div 2 type - Node[Key, Val] {.acyclic.} = ref object + Node[Key, Val] = ref object entries: int keys: array[M, Key] case isInternal: bool @@ -68,10 +65,7 @@ proc copyHalf[Key, Val](h, result: Node[Key, Val]) = result.links[j] = h.links[Mhalf + j] else: for j in 0..') + +proc encodeType(w: PRodWriter, t: PType, result: var string) = + if t == nil: + # nil nodes have to be stored too: + result.add("[]") + return + # we need no surrounding [] here because the type is in a line of its own + if t.kind == tyForward: internalError("encodeType: tyForward") + # for the new rodfile viewer we use a preceding [ so that the data section + # can easily be disambiguated: + result.add('[') + encodeVInt(ord(t.kind), result) + result.add('+') + encodeVInt(t.id, result) + if t.n != nil: + encodeNode(w, unknownLineInfo, t.n, result) + if t.flags != {}: + result.add('$') + encodeVInt(cast[int32](t.flags), result) + if t.callConv != low(t.callConv): + result.add('?') + encodeVInt(ord(t.callConv), result) + if t.owner != nil: + result.add('*') + encodeVInt(t.owner.id, result) + pushSym(w, t.owner) + if t.sym != nil: + result.add('&') + encodeVInt(t.sym.id, result) + pushSym(w, t.sym) + if t.size != - 1: + result.add('/') + encodeVBiggestInt(t.size, result) + if t.align != - 1: + result.add('=') + encodeVInt(t.align, result) + encodeLoc(w, t.loc, result) + for i in 0.. 0): - message(p.config, le.info, warnObservableStores, $le) - # bug #19613 prevent dangerous aliasing too: - if dest != nil and dest != le: - for i in 1.. 0: @@ -221,84 +92,76 @@ proc openArrayLoc(p: BProc, formalType: PType, n: PNode; result: var Rope) = for i in 0..Field0, $1->Field1" % [rdLoc(a)] - else: - result.add "$1.Field0, $1.Field1" % [rdLoc(a)] + var b, c: TLoc + initLocExpr(p, q[1], a) + initLocExpr(p, q[2], b) + initLocExpr(p, q[3], c) + # but first produce the required index checks: + if optBoundsCheck in p.options: + genBoundsCheck(p, a, b, c) + let ty = skipTypes(a.t, abstractVar+{tyPtr}) + let dest = getTypeDesc(p.module, n.typ[0]) + case ty.kind + of tyArray: + let first = toInt64(firstOrd(p.config, ty)) + if first == 0: + result = "($4*)(($1)+($2)), ($3)-($2)+1" % [rdLoc(a), rdLoc(b), rdLoc(c), dest] else: - result.add "$1, $1Len_0" % [rdLoc(a)] + result = "($5*)($1)+(($2)-($4)), ($3)-($2)+1" % + [rdLoc(a), rdLoc(b), rdLoc(c), intLiteral(first), dest] + of tyOpenArray, tyVarargs, tyUncheckedArray, tyCString: + result = "($4*)($1)+($2), ($3)-($2)+1" % [rdLoc(a), rdLoc(b), rdLoc(c), dest] of tyString, tySequence: - let ntyp = skipTypes(n.typ, abstractInst) - if formalType.skipTypes(abstractInst).kind in {tyVar} and ntyp.kind == tyString and - optSeqDestructors in p.config.globalOptions: - linefmt(p, cpsStmts, "#nimPrepareStrMutationV2($1);$n", [byRefLoc(p, a)]) - if ntyp.kind in {tyVar} and not compileToCpp(p.module): + if skipTypes(n.typ, abstractInst).kind == tyVar and + not compileToCpp(p.module): + result = "($5*)(*$1)$4+($2), ($3)-($2)+1" % [rdLoc(a), rdLoc(b), rdLoc(c), dataField(p), dest] + else: + result = "($5*)$1$4+($2), ($3)-($2)+1" % [rdLoc(a), rdLoc(b), rdLoc(c), dataField(p), dest] + else: + internalError(p.config, "openArrayLoc: " & typeToString(a.t)) + else: + initLocExpr(p, n, a) + case skipTypes(a.t, abstractVar).kind + of tyOpenArray, tyVarargs: + result = "$1, $1Len_0" % [rdLoc(a)] + of tyString, tySequence: + if skipTypes(n.typ, abstractInst).kind == tyVar and + not compileToCpp(p.module): var t: TLoc t.r = "(*$1)" % [a.rdLoc] - result.add "($4) ? ((*$1)$3) : NIM_NIL, $2" % - [a.rdLoc, lenExpr(p, t), dataField(p), - dataFieldAccessor(p, "*" & a.rdLoc)] + result = "(*$1)$3, $2" % [a.rdLoc, lenExpr(p, t), dataField(p)] else: - result.add "($4) ? ($1$3) : NIM_NIL, $2" % - [a.rdLoc, lenExpr(p, a), dataField(p), dataFieldAccessor(p, a.rdLoc)] + result = "$1$3, $2" % [a.rdLoc, lenExpr(p, a), dataField(p)] of tyArray: - result.add "$1, $2" % [rdLoc(a), rope(lengthOrd(p.config, a.t))] + result = "$1, $2" % [rdLoc(a), rope(lengthOrd(p.config, a.t))] of tyPtr, tyRef: case lastSon(a.t).kind of tyString, tySequence: var t: TLoc t.r = "(*$1)" % [a.rdLoc] - result.add "($4) ? ((*$1)$3) : NIM_NIL, $2" % - [a.rdLoc, lenExpr(p, t), dataField(p), - dataFieldAccessor(p, "*" & a.rdLoc)] + result = "(*$1)$3, $2" % [a.rdLoc, lenExpr(p, t), dataField(p)] of tyArray: - result.add "$1, $2" % [rdLoc(a), rope(lengthOrd(p.config, lastSon(a.t)))] + result = "$1, $2" % [rdLoc(a), rope(lengthOrd(p.config, lastSon(a.t)))] else: internalError(p.config, "openArrayLoc: " & typeToString(a.t)) else: internalError(p.config, "openArrayLoc: " & typeToString(a.t)) -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, gcOrc} and - getSize(p.config, a.lode.typ) < 1024: - getTemp(p, a.lode.typ, result, needsInit=false) - genAssignment(p, result, a, {}) - else: - result = a - -proc literalsNeedsTmp(p: BProc, a: TLoc): TLoc = - getTemp(p, a.lode.typ, result, needsInit=false) - genAssignment(p, result, a, {}) - -proc genArgStringToCString(p: BProc, n: PNode; result: var Rope; needsTmp: bool) {.inline.} = +proc genArgStringToCString(p: BProc, n: PNode): Rope {.inline.} = var a: TLoc initLocExpr(p, n[0], a) - appcg(p.module, result, "#nimToCStringConv($1)", [withTmpIfNeeded(p, a, needsTmp).rdLoc]) + result = ropecg(p.module, "#nimToCStringConv($1)", [a.rdLoc]) -proc genArg(p: BProc, n: PNode, param: PSym; call: PNode; result: var Rope; needsTmp = false) = +proc genArg(p: BProc, n: PNode, param: PSym; call: PNode): Rope = var a: TLoc if n.kind == nkStringToCString: - genArgStringToCString(p, n, result, needsTmp) + result = genArgStringToCString(p, n) 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) + result = openArrayLoc(p, n) 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) - else: - addAddrLoc(p.config, withTmpIfNeeded(p, a, needsTmp), result) - elif p.module.compileToCpp and param.typ.kind in {tyVar} and + result = addrLoc(p.config, a) + elif p.module.compileToCpp and param.typ.kind == tyVar and n.kind == nkHiddenAddr: initLocExprSingleUse(p, n[0], a) # if the proc is 'importc'ed but not 'importcpp'ed then 'var T' still @@ -307,111 +170,31 @@ proc genArg(p: BProc, n: PNode, param: PSym; call: PNode; result: var Rope; need if callee.kind == nkSym and {sfImportc, sfInfixCall, sfCompilerProc} * callee.sym.flags == {sfImportc} and {lfHeader, lfNoDecl} * callee.sym.loc.flags != {}: - addAddrLoc(p.config, a, result) + result = addrLoc(p.config, a) else: - addRdLoc(a, result) + result = rdLoc(a) else: initLocExprSingleUse(p, n, a) - addRdLoc(withTmpIfNeeded(p, a, needsTmp), result) - #assert result != nil + result = rdLoc(a) -proc genArgNoParam(p: BProc, n: PNode; result: var Rope; needsTmp = false) = +proc genArgNoParam(p: BProc, n: PNode): Rope = var a: TLoc if n.kind == nkStringToCString: - genArgStringToCString(p, n, result, needsTmp) + result = genArgStringToCString(p, n) else: initLocExprSingleUse(p, n, a) - addRdLoc(withTmpIfNeeded(p, a, needsTmp), result) + result = rdLoc(a) -import aliasanalysis - -proc potentialAlias(n: PNode, potentialWrites: seq[PNode]): bool = - for p in potentialWrites: - if p.aliases(n) != no or n.aliases(p) != no: - return true - -proc skipTrivialIndirections(n: PNode): PNode = - result = n - while true: - case result.kind - of nkDerefExpr, nkHiddenDeref, nkAddr, nkHiddenAddr, nkObjDownConv, nkObjUpConv: - result = result[0] - of nkHiddenStdConv, nkHiddenSubConv: - result = result[1] - else: break - -proc getPotentialWrites(n: PNode; mutate: bool; result: var seq[PNode]) = - case n.kind: - of nkLiterals, nkIdent, nkFormalParams: discard - of nkSym: - if mutate: result.add n - of nkAsgn, nkFastAsgn, nkSinkAsgn: - getPotentialWrites(n[0], true, result) - getPotentialWrites(n[1], mutate, result) - of nkAddr, nkHiddenAddr: - getPotentialWrites(n[0], true, result) - of nkBracketExpr, nkDotExpr, nkCheckedFieldExpr: - getPotentialWrites(n[0], mutate, result) - of nkCallKinds: - case n.getMagic: - of mIncl, mExcl, mInc, mDec, mAppendStrCh, mAppendStrStr, mAppendSeqElem, - mAddr, mNew, mNewFinalize, mWasMoved, mDestroy, mReset: - getPotentialWrites(n[1], true, result) - for i in 2.. 1: pl.add(", ") + if isInvalidReturnType(p.config, typ[0]): + if ri.len > 1: pl.add(~", ") # beware of 'result = p(result)'. We may need to allocate a temporary: - if d.k in {locTemp, locNone} or not preventNrvo(p, d.lode, le, ri): + if d.k in {locTemp, locNone} or not leftAppearsOnRightSide(le, ri): # Great, we can use 'd': if d.k == locNone: getTemp(p, typ[0], d, needsInit=true) @@ -480,9 +262,8 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) = getTemp(p, typ[0], tmp, needsInit=true) pl.add(addrLoc(p.config, tmp)) genCallPattern() - if canRaise: raiseExit(p) genAssignment(p, d, tmp, {}) # no need for deep copying - elif isHarmlessStore(p, canRaise, d): + else: if d.k == locNone: getTemp(p, typ[0], d) assert(d.t != nil) # generate an assignment to d: var list: TLoc @@ -491,49 +272,29 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) = list.r = PatIter % [rdLoc(op), pl, pl.addComma, rawProc] else: list.r = PatProc % [rdLoc(op), pl, pl.addComma, rawProc] + genAssignment(p, d, list, {}) # no need for deep copying - if canRaise: raiseExit(p) - else: - var tmp: TLoc - getTemp(p, typ[0], tmp) - assert(d.t != nil) # generate an assignment to d: - var list: TLoc - initLoc(list, locCall, d.lode, OnUnknown) - if tfIterator in typ.flags: - list.r = PatIter % [rdLoc(op), pl, pl.addComma, rawProc] - else: - list.r = PatProc % [rdLoc(op), pl, pl.addComma, rawProc] - genAssignment(p, tmp, list, {}) - if canRaise: raiseExit(p) - genAssignment(p, d, tmp, {}) else: genCallPattern() - if canRaise: raiseExit(p) -proc genOtherArg(p: BProc; ri: PNode; i: int; typ: PType; result: var Rope; - argsCounter: var int) = +proc genOtherArg(p: BProc; ri: PNode; i: int; typ: PType): Rope = if i < typ.len: # 'var T' is 'T&' in C++. This means we ignore the request of # any nkHiddenAddr when it's a 'var T'. let paramType = typ.n[i] assert(paramType.kind == nkSym) if paramType.typ.isCompileTimeOnly: - discard - elif typ[i].kind in {tyVar} and ri[i].kind == nkHiddenAddr: - if argsCounter > 0: result.add ", " - genArgNoParam(p, ri[i][0], result) - inc argsCounter + result = nil + elif typ[i].kind == tyVar and ri[i].kind == nkHiddenAddr: + result = genArgNoParam(p, ri[i][0]) else: - if argsCounter > 0: result.add ", " - genArgNoParam(p, ri[i], result) #, typ.n[i].sym) - inc argsCounter + result = genArgNoParam(p, ri[i]) #, typ.n[i].sym) else: if tfVarargs notin typ.flags: localError(p.config, ri.info, "wrong argument count") + result = nil else: - if argsCounter > 0: result.add ", " - genArgNoParam(p, ri[i], result) - inc argsCounter + result = genArgNoParam(p, ri[i]) discard """ Dot call syntax in C++ @@ -590,7 +351,7 @@ proc skipAddrDeref(node: PNode): PNode = else: result = node -proc genThisArg(p: BProc; ri: PNode; i: int; typ: PType; result: var Rope) = +proc genThisArg(p: BProc; ri: PNode; i: int; typ: PType): Rope = # for better or worse c2nim translates the 'this' argument to a 'var T'. # However manual wrappers may also use 'ptr T'. In any case we support both # for convenience. @@ -601,75 +362,78 @@ proc genThisArg(p: BProc; ri: PNode; i: int; typ: PType; result: var Rope) = var ri = ri[i] while ri.kind == nkObjDownConv: ri = ri[0] let t = typ[i].skipTypes({tyGenericInst, tyAlias, tySink}) - if t.kind in {tyVar}: + if t.kind == tyVar: let x = if ri.kind == nkHiddenAddr: ri[0] else: ri if x.typ.kind == tyPtr: - genArgNoParam(p, x, result) + result = genArgNoParam(p, x) result.add("->") elif x.kind in {nkHiddenDeref, nkDerefExpr} and x[0].typ.kind == tyPtr: - genArgNoParam(p, x[0], result) + result = genArgNoParam(p, x[0]) result.add("->") else: - genArgNoParam(p, x, result) + result = genArgNoParam(p, x) result.add(".") elif t.kind == tyPtr: if ri.kind in {nkAddr, nkHiddenAddr}: - genArgNoParam(p, ri[0], result) + result = genArgNoParam(p, ri[0]) result.add(".") else: - genArgNoParam(p, ri, result) + result = genArgNoParam(p, ri) result.add("->") else: ri = skipAddrDeref(ri) if ri.kind in {nkAddr, nkHiddenAddr}: ri = ri[0] - genArgNoParam(p, ri, result) #, typ.n[i].sym) + result = genArgNoParam(p, ri) #, typ.n[i].sym) result.add(".") -proc genPatternCall(p: BProc; ri: PNode; pat: string; typ: PType; result: var Rope) = +proc genPatternCall(p: BProc; ri: PNode; pat: string; typ: PType): Rope = var i = 0 var j = 1 while i < pat.len: case pat[i] of '@': - var argsCounter = 0 + var first = true for k in j.. 0: + if not first: + result.add(~", ") + first = false + result.add arg inc i of '#': if i+1 < pat.len and pat[i+1] in {'+', '@'}: let ri = ri[j] if ri.kind in nkCallKinds: let typ = skipTypes(ri[0].typ, abstractInst) - if pat[i+1] == '+': genArgNoParam(p, ri[0], result) - result.add("(") + if pat[i+1] == '+': result.add genArgNoParam(p, ri[0]) + result.add(~"(") if 1 < ri.len: - var argsCounterB = 0 - genOtherArg(p, ri, 1, typ, result, argsCounterB) + result.add genOtherArg(p, ri, 1, typ) for k in j+1.. 0 if pat.contains({'#', '(', '@', '\''}): - var pl = newRopeAppender() - genPatternCall(p, ri, pat, typ, pl) + var pl = genPatternCall(p, ri, pat, typ) # simpler version of 'fixupCall' that works with the pl+params combination: var typ = skipTypes(ri[0].typ, abstractInst) if typ[0] != nil: @@ -710,79 +473,80 @@ proc genInfixCall(p: BProc, le, ri: PNode, d: var TLoc) = list.r = pl genAssignment(p, d, list, {}) # no need for deep copying else: - pl.add(";\n") + pl.add(~";$n") line(p, cpsStmts, pl) else: - var pl = newRopeAppender() - var argsCounter = 0 + var pl: Rope = nil + #var param = typ.n[1].sym if 1 < ri.len: - genThisArg(p, ri, 1, typ, pl) + pl.add(genThisArg(p, ri, 1, typ)) pl.add(op.r) - var params = newRopeAppender() + var params: Rope for i in 2.. 0 var start = 3 if ' ' in pat: start = 1 pl.add(op.r) if ri.len > 1: - pl.add(": ") - genArg(p, ri[1], typ.n[1].sym, ri, pl) + pl.add(~": ") + pl.add(genArg(p, ri[1], typ.n[1].sym, ri)) start = 2 else: if ri.len > 1: - genArg(p, ri[1], typ.n[1].sym, ri, pl) - pl.add(" ") + pl.add(genArg(p, ri[1], typ.n[1].sym, ri)) + pl.add(~" ") pl.add(op.r) if ri.len > 2: - pl.add(": ") - genArg(p, ri[2], typ.n[2].sym, ri, pl) + pl.add(~": ") + pl.add(genArg(p, ri[2], typ.n[2].sym, ri)) for i in start..= typ.len: internalError(p.config, ri.info, "varargs for objective C method?") assert(typ.n[i].kind == nkSym) var param = typ.n[i].sym - pl.add(" ") + pl.add(~" ") pl.add(param.name.s) - pl.add(": ") - genArg(p, ri[i], param, ri, pl) + pl.add(~": ") + pl.add(genArg(p, ri[i], param, ri)) if typ[0] != nil: - if isInvalidReturnType(p.config, typ): - if ri.len > 1: pl.add(" ") + if isInvalidReturnType(p.config, typ[0]): + if ri.len > 1: pl.add(~" ") # beware of 'result = p(result)'. We always allocate a temporary: if d.k in {locTemp, locNone}: # We already got a temp. Great, special case it: if d.k == locNone: getTemp(p, typ[0], d, needsInit=true) - pl.add("Result: ") + pl.add(~"Result: ") pl.add(addrLoc(p.config, d)) - pl.add("];\n") + pl.add(~"];$n") line(p, cpsStmts, pl) else: var tmp: TLoc getTemp(p, typ[0], tmp, needsInit=true) pl.add(addrLoc(p.config, tmp)) - pl.add("];\n") + pl.add(~"];$n") line(p, cpsStmts, pl) genAssignment(p, d, tmp, {}) # no need for deep copying else: - pl.add("]") + pl.add(~"]") if d.k == locNone: getTemp(p, typ[0], d) assert(d.t != nil) # generate an assignment to d: var list: TLoc @@ -790,36 +554,23 @@ proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) = list.r = pl genAssignment(p, d, list, {}) # no need for deep copying else: - pl.add("];\n") + pl.add(~"];$n") line(p, cpsStmts, pl) -proc notYetAlive(n: PNode): bool {.inline.} = - let r = getRoot(n) - result = r != nil and r.loc.lode == nil - -proc isInactiveDestructorCall(p: BProc, e: PNode): bool = - #[ Consider this example. - - var :tmpD_3281815 - try: - if true: - return - let args_3280013 = - wasMoved_3281816(:tmpD_3281815) - `=_3280036`(:tmpD_3281815, [1]) - :tmpD_3281815 - finally: - `=destroy_3280027`(args_3280013) - - We want to return early but the 'finally' section is traversed before - the 'let args = ...' statement. We exploit this to generate better - code for 'return'. ]# - result = e.len == 2 and e[0].kind == nkSym and - e[0].sym.name.s == "=destroy" and notYetAlive(e[1].skipAddr) +proc genCall(p: BProc, e: PNode, d: var TLoc) = + if e[0].typ.skipTypes({tyGenericInst, tyAlias, tySink, tyOwned}).callConv == ccClosure: + genClosureCall(p, nil, e, d) + elif e[0].kind == nkSym and sfInfixCall in e[0].sym.flags: + genInfixCall(p, nil, e, d) + elif e[0].kind == nkSym and sfNamedParamCall in e[0].sym.flags: + genNamedParamCall(p, e, d) + else: + genPrefixCall(p, nil, e, d) + postStmtActions(p) + if p.config.exc == excGoto and canRaise(e[0]): + raiseExit(p) proc genAsgnCall(p: BProc, le, ri: PNode, d: var TLoc) = - if p.withinBlockLeaveActions > 0 and isInactiveDestructorCall(p, ri): - return if ri[0].typ.skipTypes({tyGenericInst, tyAlias, tySink, tyOwned}).callConv == ccClosure: genClosureCall(p, le, ri, d) elif ri[0].kind == nkSym and sfInfixCall in ri[0].sym.flags: @@ -828,5 +579,6 @@ proc genAsgnCall(p: BProc, le, ri: PNode, d: var TLoc) = genNamedParamCall(p, ri, d) else: genPrefixCall(p, le, ri, d) - -proc genCall(p: BProc, e: PNode, d: var TLoc) = genAsgnCall(p, nil, e, d) + postStmtActions(p) + if p.config.exc == excGoto and canRaise(ri[0]): + raiseExit(p) diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index a64a42219..632e4bb31 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -9,40 +9,35 @@ # included from cgen.nim -when defined(nimCompilerStacktraceHints): - import std/stackframes - proc getNullValueAuxT(p: BProc; orig, t: PType; obj, constOrNil: PNode, result: var Rope; count: var int; isConst: bool, info: TLineInfo) # -------------------------- constant expressions ------------------------ -proc rdSetElemLoc(conf: ConfigRef; a: TLoc, typ: PType; result: var Rope) - -proc int64Literal(i: BiggestInt; result: var Rope) = +proc int64Literal(i: BiggestInt): Rope = if i > low(int64): - result.add "IL64($1)" % [rope(i)] + result = "IL64($1)" % [rope(i)] else: - result.add "(IL64(-9223372036854775807) - IL64(1))" + result = ~"(IL64(-9223372036854775807) - IL64(1))" -proc uint64Literal(i: uint64; result: var Rope) = result.add rope($i & "ULL") +proc uint64Literal(i: uint64): Rope = rope($i & "ULL") -proc intLiteral(i: BiggestInt; result: var Rope) = +proc intLiteral(i: BiggestInt): Rope = if i > low(int32) and i <= high(int32): - result.add rope(i) + result = rope(i) elif i == low(int32): # Nim has the same bug for the same reasons :-) - result.add "(-2147483647 -1)" + result = ~"(-2147483647 -1)" elif i > low(int64): - result.add "IL64($1)" % [rope(i)] + result = "IL64($1)" % [rope(i)] else: - result.add "(IL64(-9223372036854775807) - IL64(1))" + result = ~"(IL64(-9223372036854775807) - IL64(1))" -proc intLiteral(i: Int128; result: var Rope) = - intLiteral(toInt64(i), result) +proc intLiteral(i: Int128): Rope = + intLiteral(toInt64(i)) -proc genLiteral(p: BProc, n: PNode, ty: PType; result: var Rope) = +proc genLiteral(p: BProc, n: PNode, ty: PType): Rope = case n.kind of nkCharLit..nkUInt64Lit: var k: TTypeKind @@ -56,68 +51,61 @@ proc genLiteral(p: BProc, n: PNode, ty: PType; result: var Rope) = else: k = tyNil # don't go into the case variant that uses 'ty' case k of tyChar, tyNil: - intLiteral(n.intVal, result) + result = intLiteral(n.intVal) of tyBool: - if n.intVal != 0: result.add "NIM_TRUE" - else: result.add "NIM_FALSE" - of tyInt64: int64Literal(n.intVal, result) - of tyUInt64: uint64Literal(uint64(n.intVal), result) + if n.intVal != 0: result = ~"NIM_TRUE" + else: result = ~"NIM_FALSE" + of tyInt64: result = int64Literal(n.intVal) + of tyUInt64: result = uint64Literal(uint64(n.intVal)) else: - result.add "((" - result.add getTypeDesc(p.module, ty) - result.add ")" - intLiteral(n.intVal, result) - result.add ")" + result = "(($1) $2)" % [getTypeDesc(p.module, + ty), intLiteral(n.intVal)] of nkNilLit: let k = if ty == nil: tyPointer else: skipTypes(ty, abstractVarRange).kind if k == tyProc and skipTypes(ty, abstractVarRange).callConv == ccClosure: let id = nodeTableTestOrSet(p.module.dataCache, n, p.module.labels) - let tmpName = p.module.tmpBase & rope(id) + result = p.module.tmpBase & rope(id) if id == p.module.labels: # not found in cache: inc(p.module.labels) - p.module.s[cfsStrData].addf( + p.module.s[cfsData].addf( "static NIM_CONST $1 $2 = {NIM_NIL,NIM_NIL};$n", - [getTypeDesc(p.module, ty), tmpName]) - result.add tmpName - elif k in {tyPointer, tyNil, tyProc}: - result.add rope("NIM_NIL") + [getTypeDesc(p.module, ty), result]) else: - result.add "(($1) NIM_NIL)" % [getTypeDesc(p.module, ty)] + result = rope("NIM_NIL") of nkStrLit..nkTripleStrLit: let k = if ty == nil: tyString else: skipTypes(ty, abstractVarRange + {tyStatic, tyUserTypeClass, tyUserTypeClassInst}).kind case k of tyNil: - genNilStringLiteral(p.module, n.info, result) + result = genNilStringLiteral(p.module, n.info) of tyString: - # with the new semantics for not 'nil' strings, we can map "" to nil and + # with the new semantics for 'nil' strings, we can map "" to nil and # save tons of allocations: - if n.strVal.len == 0 and optSeqDestructors notin p.config.globalOptions: - genNilStringLiteral(p.module, n.info, result) + if n.strVal.len == 0 and optNilSeqs notin p.options and + optSeqDestructors notin p.config.globalOptions: + result = genNilStringLiteral(p.module, n.info) else: - genStringLiteral(p.module, n, result) + result = genStringLiteral(p.module, n) else: - result.add makeCString(n.strVal) + result = makeCString(n.strVal) of nkFloatLit, nkFloat64Lit: - if ty.kind == tyFloat32: - result.add rope(n.floatVal.float32.toStrMaxPrecision) - else: - result.add rope(n.floatVal.toStrMaxPrecision) + result = rope(n.floatVal.toStrMaxPrecision) of nkFloat32Lit: - result.add rope(n.floatVal.float32.toStrMaxPrecision) + result = rope(n.floatVal.toStrMaxPrecision("f")) else: internalError(p.config, n.info, "genLiteral(" & $n.kind & ')') + result = nil -proc genLiteral(p: BProc, n: PNode; result: var Rope) = - genLiteral(p, n, n.typ, result) +proc genLiteral(p: BProc, n: PNode): Rope = + result = genLiteral(p, n, n.typ) proc bitSetToWord(s: TBitSet, size: int): BiggestUInt = result = 0 for j in 0.. 8: var res = "{\n" for i in 0.. 8: let id = nodeTableTestOrSet(p.module.dataCache, n, p.module.labels) - let tmpName = p.module.tmpBase & rope(id) + result = p.module.tmpBase & rope(id) if id == p.module.labels: # not found in cache: inc(p.module.labels) - p.module.s[cfsStrData].addf("static NIM_CONST $1 $2 = ", - [getTypeDesc(p.module, n.typ), tmpName]) - genRawSetData(cs, size, p.module.s[cfsStrData]) - p.module.s[cfsStrData].addf(";$n", []) - result.add tmpName + p.module.s[cfsData].addf("static NIM_CONST $1 $2 = $3;$n", + [getTypeDesc(p.module, n.typ), result, genRawSetData(cs, size)]) else: - genRawSetData(cs, size, result) + result = genRawSetData(cs, size) proc getStorageLoc(n: PNode): TStorageLoc = - ## deadcode case n.kind of nkSym: case n.sym.kind @@ -186,7 +171,8 @@ proc canMove(p: BProc, n: PNode; dest: TLoc): bool = if not isDeepConstExpr(n) or n.len == 0: if skipTypes(n.typ, abstractVarRange).kind == tySequence: return true - elif n.kind in nkStrKinds and n.strVal.len == 0: + elif optNilSeqs notin p.options and + n.kind in nkStrKinds and n.strVal.len == 0: # Empty strings are codegen'd as NIM_NIL so it's just a pointer copy return true result = n.kind in nkCallKinds @@ -220,7 +206,7 @@ proc asgnComplexity(n: PNode): int = else: discard proc optAsgnLoc(a: TLoc, t: PType, field: Rope): TLoc = - assert field != "" + assert field != nil result.k = locField result.storage = a.storage result.lode = lodeTyp t @@ -254,7 +240,7 @@ proc genOptAsgnObject(p: BProc, dest, src: TLoc, flags: TAssignmentFlags, case t.kind of nkSym: let field = t.sym - if field.loc.r == "": fillObjectFields(p.module, typ) + if field.loc.r == nil: fillObjectFields(p.module, typ) genAssignment(p, optAsgnLoc(dest, field.typ, field.loc.r), optAsgnLoc(src, field.typ, field.loc.r), newflags) of nkRecList: @@ -280,38 +266,10 @@ proc genGenericAsgn(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = [addrLoc(p.config, dest), addrLoc(p.config, src), rdLoc(dest)]) else: linefmt(p, cpsStmts, "#genericShallowAssign((void*)$1, (void*)$2, $3);$n", - [addrLoc(p.config, dest), addrLoc(p.config, src), genTypeInfoV1(p.module, dest.t, dest.lode.info)]) + [addrLoc(p.config, dest), addrLoc(p.config, src), genTypeInfo(p.module, dest.t, dest.lode.info)]) else: 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) = - assert d.k != locNone - # getTemp(p, d.t, d) - - case a.t.skipTypes(abstractVar).kind - of tyOpenArray, tyVarargs: - if reifiedOpenArray(a.lode): - 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]) - of tySequence: - linefmt(p, cpsStmts, "$1.Field0 = ($5) ? ($2$3) : NIM_NIL; $1.Field1 = $4;$n", - [rdLoc(d), a.rdLoc, dataField(p), lenExpr(p, a), dataFieldAccessor(p, a.rdLoc)]) - of tyArray: - linefmt(p, cpsStmts, "$1.Field0 = $2; $1.Field1 = $3;$n", - [rdLoc(d), rdLoc(a), rope(lengthOrd(p.config, a.t))]) - of tyString: - let etyp = skipTypes(a.t, abstractInst) - if etyp.kind in {tyVar} and optSeqDestructors in p.config.globalOptions: - linefmt(p, cpsStmts, "#nimPrepareStrMutationV2($1);$n", [byRefLoc(p, a)]) - - linefmt(p, cpsStmts, "$1.Field0 = ($5) ? ($2$3) : NIM_NIL; $1.Field1 = $4;$n", - [rdLoc(d), a.rdLoc, dataField(p), lenExpr(p, a), dataFieldAccessor(p, a.rdLoc)]) - else: - internalError(p.config, a.lode.info, "cannot handle " & $a.t.kind) + [addrLoc(p.config, dest), addrLoc(p.config, src), genTypeInfo(p.module, dest.t, dest.lode.info)]) proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = # This function replaces all other methods for generating @@ -332,7 +290,7 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = else: linefmt(p, cpsStmts, "#genericSeqAssign($1, $2, $3);$n", [addrLoc(p.config, dest), rdLoc(src), - genTypeInfoV1(p.module, dest.t, dest.lode.info)]) + genTypeInfo(p.module, dest.t, dest.lode.info)]) of tyString: if optSeqDestructors in p.config.globalOptions: genGenericAsgn(p, dest, src, flags) @@ -391,13 +349,11 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = of tyOpenArray, tyVarargs: # 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) - elif containsGarbageCollectedRef(dest.t): + if containsGarbageCollectedRef(dest.t): linefmt(p, cpsStmts, # XXX: is this correct for arrays? "#genericAssignOpenArray((void*)$1, (void*)$2, $1Len_0, $3);$n", [addrLoc(p.config, dest), addrLoc(p.config, src), - genTypeInfoV1(p.module, dest.t, dest.lode.info)]) + genTypeInfo(p.module, dest.t, dest.lode.info)]) else: linefmt(p, cpsStmts, # bug #4799, keep the nimCopyMem for a while @@ -405,12 +361,12 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = "$1 = $2;$n", [rdLoc(dest), rdLoc(src)]) of tySet: - if mapSetType(p.config, ty) == ctArray: + if mapType(p.config, ty) == ctArray: linefmt(p, cpsStmts, "#nimCopyMem((void*)$1, (NIM_CONST void*)$2, $3);$n", [rdLoc(dest), rdLoc(src), getSize(p.config, dest.t)]) else: linefmt(p, cpsStmts, "$1 = $2;$n", [rdLoc(dest), rdLoc(src)]) - of tyPtr, tyPointer, tyChar, tyBool, tyEnum, tyCstring, + of tyPtr, tyPointer, tyChar, tyBool, tyEnum, tyCString, tyInt..tyUInt64, tyRange, tyVar, tyLent, tyNil: linefmt(p, cpsStmts, "$1 = $2;$n", [rdLoc(dest), rdLoc(src)]) else: internalError(p.config, "genAssignment: " & $ty.kind) @@ -439,28 +395,23 @@ proc genDeepCopy(p: BProc; dest, src: TLoc) = # XXX optimize this linefmt(p, cpsStmts, "#genericDeepCopy((void*)$1, (void*)$2, $3);$n", [addrLoc(p.config, dest), addrLocOrTemp(src), - genTypeInfoV1(p.module, dest.t, dest.lode.info)]) + genTypeInfo(p.module, dest.t, dest.lode.info)]) of tySequence, tyString: - if optTinyRtti in p.config.globalOptions: - linefmt(p, cpsStmts, "#genericDeepCopy((void*)$1, (void*)$2, $3);$n", - [addrLoc(p.config, dest), addrLocOrTemp(src), - genTypeInfoV1(p.module, dest.t, dest.lode.info)]) - else: - linefmt(p, cpsStmts, "#genericSeqDeepCopy($1, $2, $3);$n", - [addrLoc(p.config, dest), rdLoc(src), - genTypeInfoV1(p.module, dest.t, dest.lode.info)]) + linefmt(p, cpsStmts, "#genericSeqDeepCopy($1, $2, $3);$n", + [addrLoc(p.config, dest), rdLoc(src), + genTypeInfo(p.module, dest.t, dest.lode.info)]) of tyOpenArray, tyVarargs: linefmt(p, cpsStmts, "#genericDeepCopyOpenArray((void*)$1, (void*)$2, $1Len_0, $3);$n", [addrLoc(p.config, dest), addrLocOrTemp(src), - genTypeInfoV1(p.module, dest.t, dest.lode.info)]) + genTypeInfo(p.module, dest.t, dest.lode.info)]) of tySet: - if mapSetType(p.config, ty) == ctArray: + if mapType(p.config, ty) == ctArray: linefmt(p, cpsStmts, "#nimCopyMem((void*)$1, (NIM_CONST void*)$2, $3);$n", [rdLoc(dest), rdLoc(src), getSize(p.config, dest.t)]) else: linefmt(p, cpsStmts, "$1 = $2;$n", [rdLoc(dest), rdLoc(src)]) - of tyPointer, tyChar, tyBool, tyEnum, tyCstring, + of tyPointer, tyChar, tyBool, tyEnum, tyCString, tyInt..tyUInt64, tyRange, tyVar, tyLent: linefmt(p, cpsStmts, "$1 = $2;$n", [rdLoc(dest), rdLoc(src)]) else: internalError(p.config, "genDeepCopy: " & $ty.kind) @@ -555,34 +506,23 @@ template binaryArithOverflowRaw(p: BProc, t: PType, a, b: TLoc; else: getTypeDesc(p.module, t) var result = getTempName(p.module) linefmt(p, cpsLocals, "$1 $2;$n", [storage, result]) - lineCg(p, cpsStmts, "if (#$2($3, $4, &$1)) { #raiseOverflow(); ", - [result, cpname, rdCharLoc(a), rdCharLoc(b)]) - raiseInstr(p, p.s(cpsStmts)) - linefmt p, cpsStmts, "};$n", [] - + lineCg(p, cpsStmts, "$1 = #$2($3, $4);$n", [result, cpname, rdCharLoc(a), rdCharLoc(b)]) if size < p.config.target.intSize or t.kind in {tyRange, tyEnum}: - var first = newRopeAppender() - intLiteral(firstOrd(p.config, t), first) - var last = newRopeAppender() - intLiteral(lastOrd(p.config, t), last) - linefmt(p, cpsStmts, "if ($1 < $2 || $1 > $3){ #raiseOverflow(); ", - [result, first, last]) - raiseInstr(p, p.s(cpsStmts)) - linefmt p, cpsStmts, "}$n", [] - + linefmt(p, cpsStmts, "if ($1 < $2 || $1 > $3) #raiseOverflow();$n", + [result, intLiteral(firstOrd(p.config, t)), intLiteral(lastOrd(p.config, t))]) result proc binaryArithOverflow(p: BProc, e: PNode, d: var TLoc, m: TMagic) = const prc: array[mAddI..mPred, string] = [ - "nimAddInt", "nimSubInt", - "nimMulInt", "nimDivInt", "nimModInt", - "nimAddInt", "nimSubInt" + "addInt", "subInt", + "mulInt", "divInt", "modInt", + "addInt", "subInt" ] prc64: array[mAddI..mPred, string] = [ - "nimAddInt64", "nimSubInt64", - "nimMulInt64", "nimDivInt64", "nimModInt64", - "nimAddInt64", "nimSubInt64" + "addInt64", "subInt64", + "mulInt64", "divInt64", "modInt64", + "addInt64", "subInt64" ] opr: array[mAddI..mPred, string] = ["+", "-", "*", "/", "%", "+", "-"] var a, b: TLoc @@ -597,26 +537,9 @@ proc binaryArithOverflow(p: BProc, e: PNode, d: var TLoc, m: TMagic) = let res = "($1)($2 $3 $4)" % [getTypeDesc(p.module, e.typ), rdLoc(a), rope(opr[m]), rdLoc(b)] putIntoDest(p, d, e, res) else: - # we handle div by zero here so that we know that the compilerproc's - # result is only for overflows. - var needsOverflowCheck = true - if m in {mDivI, mModI}: - var canBeZero = true - if e[2].kind in {nkIntLit..nkUInt64Lit}: - canBeZero = e[2].intVal == 0 - if e[2].kind in {nkIntLit..nkInt64Lit}: - needsOverflowCheck = e[2].intVal == -1 - if canBeZero: - linefmt(p, cpsStmts, "if ($1 == 0){ #raiseDivByZero(); ", [rdLoc(b)]) - raiseInstr(p, p.s(cpsStmts)) - linefmt(p, cpsStmts, "}$n", []) - if needsOverflowCheck: - let res = binaryArithOverflowRaw(p, t, a, b, - if t.kind == tyInt64: prc64[m] else: prc[m]) - putIntoDest(p, d, e, "($#)($#)" % [getTypeDesc(p.module, e.typ), res]) - else: - let res = "($1)($2 $3 $4)" % [getTypeDesc(p.module, e.typ), rdLoc(a), rope(opr[m]), rdLoc(b)] - putIntoDest(p, d, e, res) + let res = binaryArithOverflowRaw(p, t, a, b, + if t.kind == tyInt64: prc64[m] else: prc[m]) + putIntoDest(p, d, e, "($#)($#)" % [getTypeDesc(p.module, e.typ), res]) proc unaryArithOverflow(p: BProc, e: PNode, d: var TLoc, m: TMagic) = var @@ -626,13 +549,8 @@ proc unaryArithOverflow(p: BProc, e: PNode, d: var TLoc, m: TMagic) = initLocExpr(p, e[1], a) t = skipTypes(e.typ, abstractRange) if optOverflowCheck in p.options: - var first = newRopeAppender() - intLiteral(firstOrd(p.config, t), first) - linefmt(p, cpsStmts, "if ($1 == $2){ #raiseOverflow(); ", - [rdLoc(a), first]) - raiseInstr(p, p.s(cpsStmts)) - linefmt p, cpsStmts, "}$n", [] - + linefmt(p, cpsStmts, "if ($1 == $2) #raiseOverflow();$n", + [rdLoc(a), intLiteral(firstOrd(p.config, t))]) case m of mUnaryMinusI: putIntoDest(p, d, e, "((NI$2)-($1))" % [rdLoc(a), rope(getSize(p.config, t) * 8)]) @@ -687,6 +605,8 @@ proc binaryArith(p: BProc, e: PNode, d: var TLoc, op: TMagic) = of mLtF64: applyFormat("($1 < $2)") of mLeU: applyFormat("((NU$3)($1) <= (NU$3)($2))") of mLtU: applyFormat("((NU$3)($1) < (NU$3)($2))") + of mLeU64: applyFormat("((NU64)($1) <= (NU64)($2))") + of mLtU64: applyFormat("((NU64)($1) < (NU64)($2))") of mEqEnum: applyFormat("($1 == $2)") of mLeEnum: applyFormat("($1 <= $2)") of mLtEnum: applyFormat("($1 < $2)") @@ -697,6 +617,7 @@ proc binaryArith(p: BProc, e: PNode, d: var TLoc, op: TMagic) = of mLeB: applyFormat("($1 <= $2)") of mLtB: applyFormat("($1 < $2)") of mEqRef: applyFormat("($1 == $2)") + of mEqUntracedRef: applyFormat("($1 == $2)") of mLePtr: applyFormat("($1 <= $2)") of mLtPtr: applyFormat("($1 < $2)") of mXor: applyFormat("($1 != $2)") @@ -749,26 +670,11 @@ proc unaryArith(p: BProc, e: PNode, d: var TLoc, op: TMagic) = proc isCppRef(p: BProc; typ: PType): bool {.inline.} = result = p.module.compileToCpp and - skipTypes(typ, abstractInstOwned).kind in {tyVar} and + skipTypes(typ, abstractInstOwned).kind == tyVar and tfVarIsPtr notin skipTypes(typ, abstractInstOwned).flags -proc derefBlock(p: BProc, e: PNode, d: var TLoc) = - # We transform (block: x)[] to (block: x[]) - let e0 = e[0] - var n = shallowCopy(e0) - n.typ = e.typ - for i in 0 ..< e0.len - 1: - n[i] = e0[i] - n[e0.len-1] = newTreeIT(nkHiddenDeref, e.info, e.typ, e0[e0.len-1]) - expr p, n, d - proc genDeref(p: BProc, e: PNode, d: var TLoc) = - if e.kind == nkHiddenDeref and e[0].kind in {nkBlockExpr, nkBlockStmt}: - # bug #20107. Watch out to not deref the pointer too late. - derefBlock(p, e, d) - return - - let mt = mapType(p.config, e[0].typ, mapTypeChooser(e[0])) + let mt = mapType(p.config, e[0].typ) 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? @@ -781,7 +687,7 @@ proc genDeref(p: BProc, e: PNode, d: var TLoc) = if typ.kind in {tyUserTypeClass, tyUserTypeClassInst} and typ.isResolvedUserTypeClass: typ = typ.lastSon typ = typ.skipTypes(abstractInstOwned) - if typ.kind in {tyVar} and tfVarIsPtr notin typ.flags and p.module.compileToCpp and e[0].kind == nkHiddenAddr: + if typ.kind == tyVar and tfVarIsPtr notin typ.flags and p.module.compileToCpp and e[0].kind == nkHiddenAddr: initLocExprSingleUse(p, e[0][0], d) return else: @@ -804,7 +710,7 @@ proc genDeref(p: BProc, e: PNode, d: var TLoc) = else: internalError(p.config, e.info, "genDeref " & $typ.kind) elif p.module.compileToCpp: - if typ.kind in {tyVar} and tfVarIsPtr notin typ.flags and + if typ.kind == tyVar and tfVarIsPtr notin typ.flags and e.kind == nkHiddenDeref: putIntoDest(p, d, e, rdLoc(a), a.storage) return @@ -814,21 +720,10 @@ proc genDeref(p: BProc, e: PNode, d: var TLoc) = # See tmissingderef. So we get rid of the deref instead. The codegen # ends up using 'memcpy' for the array assignment, # so the '&' and '*' cancel out: - putIntoDest(p, d, e, rdLoc(a), a.storage) + putIntoDest(p, d, lodeTyp(a.t[0]), rdLoc(a), a.storage) else: putIntoDest(p, d, e, "(*$1)" % [rdLoc(a)], a.storage) -proc cowBracket(p: BProc; n: PNode) = - if n.kind == nkBracketExpr and optSeqDestructors in p.config.globalOptions: - let strCandidate = n[0] - if strCandidate.typ.skipTypes(abstractInst).kind == tyString: - var a: TLoc - initLocExpr(p, strCandidate, a) - linefmt(p, cpsStmts, "#nimPrepareStrMutationV2($1);$n", [byRefLoc(p, a)]) - -proc cow(p: BProc; n: PNode) {.inline.} = - if n.kind == nkHiddenAddr: cowBracket(p, n[0]) - proc genAddr(p: BProc, e: PNode, d: var TLoc) = # careful 'addr(myptrToArray)' needs to get the ampersand: if e[0].typ.skipTypes(abstractInstOwned).kind in {tyRef, tyPtr}: @@ -836,7 +731,7 @@ 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])) == ctArray or isCppRef(p, e.typ): + elif mapType(p.config, e[0].typ) == ctArray or isCppRef(p, e.typ): expr(p, e[0], d) else: var a: TLoc @@ -871,7 +766,7 @@ proc genTupleElem(p: BProc, e: PNode, d: var TLoc) = proc lookupFieldAgain(p: BProc, ty: PType; field: PSym; r: var Rope; resTyp: ptr PType = nil): PSym = var ty = ty - assert r != "" + assert r != nil while ty != nil: ty = ty.skipTypes(skipPtrs) assert(ty.kind in {tyTuple, tyObject}) @@ -892,18 +787,15 @@ proc genRecordField(p: BProc, e: PNode, d: var TLoc) = if ty.kind == tyTuple: # we found a unique tuple type which lacks field information # so we use Field$i - r.add ".Field" - r.add rope(f.position) + r.addf(".Field$1", [rope(f.position)]) putIntoDest(p, d, e, r, a.storage) else: var rtyp: PType let field = lookupFieldAgain(p, ty, f, r, addr rtyp) - if field.loc.r == "" and rtyp != nil: fillObjectFields(p.module, rtyp) - if field.loc.r == "": internalError(p.config, e.info, "genRecordField 3 " & typeToString(ty)) - r.add "." - r.add field.loc.r + if field.loc.r == nil and rtyp != nil: fillObjectFields(p.module, rtyp) + if field.loc.r == nil: internalError(p.config, e.info, "genRecordField 3 " & typeToString(ty)) + r.addf(".$1", [field.loc.r]) putIntoDest(p, d, e, r, a.storage) - r.freeze proc genInExprAux(p: BProc, e: PNode, a, b, d: var TLoc) @@ -920,57 +812,22 @@ proc genFieldCheck(p: BProc, e: PNode, obj: Rope, field: PSym) = initLoc(test, locNone, it, OnStack) initLocExpr(p, it[1], u) initLoc(v, locExpr, disc, OnUnknown) - v.r = newRopeAppender() - v.r.add obj + v.r = obj v.r.add(".") v.r.add(disc.sym.loc.r) genInExprAux(p, it, u, v, test) - var msg = "" - if optDeclaredLocs in p.config.globalOptions: - # xxx this should be controlled by a separate flag, and - # used for other similar defects so that location information is shown - # even without the expensive `--stacktrace`; binary size could be optimized - # by encoding the file names separately from `file(line:col)`, essentially - # passing around `TLineInfo` + the set of files in the project. - msg.add toFileLineCol(p.config, e.info) & " " - msg.add genFieldDefect(p.config, field.name.s, disc.sym) - var strLit = newRopeAppender() - genStringLiteral(p.module, newStrNode(nkStrLit, msg), strLit) - - ## discriminant check - template fun(code) = linefmt(p, cpsStmts, code, [rdLoc(test)]) - if op.magic == mNot: fun("if ($1) ") else: fun("if (!($1)) ") - - ## call raiseFieldError2 on failure - var discIndex = newRopeAppender() - rdSetElemLoc(p.config, v, u.t, discIndex) - if optTinyRtti in p.config.globalOptions: - # 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]) - + let msg = genFieldError(field, disc.sym) + let strLit = genStringLiteral(p.module, newStrNode(nkStrLit, msg)) + if op.magic == mNot: + linefmt(p, cpsStmts, + "if ($1) #raiseFieldError($2);$n", + [rdLoc(test), strLit]) else: - # complication needed for signed types - let first = p.config.firstOrd(disc.sym.typ) - var firstLit = newRopeAppender() - int64Literal(cast[int](first), firstLit) - let discName = genTypeInfo(p.config, p.module, disc.sym.typ, e.info) - 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", [] + linefmt(p, cpsStmts, + "if (!($1)) #raiseFieldError($2);$n", + [rdLoc(test), strLit]) proc genCheckedRecordField(p: BProc, e: PNode, d: var TLoc) = - assert e[0].kind == nkDotExpr if optFieldCheck in p.options: var a: TLoc genRecordFieldAux(p, e[0], d, a) @@ -978,14 +835,12 @@ proc genCheckedRecordField(p: BProc, e: PNode, d: var TLoc) = var r = rdLoc(a) let f = e[0][1].sym let field = lookupFieldAgain(p, ty, f, r) - if field.loc.r == "": fillObjectFields(p.module, ty) - if field.loc.r == "": + if field.loc.r == nil: fillObjectFields(p.module, ty) + if field.loc.r == nil: internalError(p.config, e.info, "genCheckedRecordField") # generate the checks: genFieldCheck(p, e, r, field) - r.add(".") - r.add field.loc.r + r.add(ropecg(p.module, ".$1", [field.loc.r])) putIntoDest(p, d, e[0], r, a.storage) - r.freeze else: genRecordField(p, e[0], d) @@ -1002,28 +857,18 @@ proc genArrayElem(p: BProc, n, x, y: PNode, d: var TLoc) = initLocExpr(p, x, a) initLocExpr(p, y, b) var ty = skipTypes(a.t, abstractVarRange + abstractPtrs + tyUserTypeClasses) - var first = newRopeAppender() - intLiteral(firstOrd(p.config, ty), first) + var first = intLiteral(firstOrd(p.config, ty)) # emit range check: if optBoundsCheck in p.options and ty.kind != tyUncheckedArray: if not isConstExpr(y): # semantic pass has already checked for const index expressions - if firstOrd(p.config, ty) == 0 and lastOrd(p.config, ty) >= 0: + if firstOrd(p.config, ty) == 0: if (firstOrd(p.config, b.t) < firstOrd(p.config, ty)) or (lastOrd(p.config, b.t) > lastOrd(p.config, ty)): - var last = newRopeAppender() - intLiteral(lastOrd(p.config, ty), last) - linefmt(p, cpsStmts, "if ((NU)($1) > (NU)($2)){ #raiseIndexError2($1, $2); ", - [rdCharLoc(b), last]) - raiseInstr(p, p.s(cpsStmts)) - linefmt p, cpsStmts, "}$n", [] + linefmt(p, cpsStmts, "if ((NU)($1) > (NU)($2)) #raiseIndexError2($1, $2);$n", + [rdCharLoc(b), intLiteral(lastOrd(p.config, ty))]) else: - var last = newRopeAppender() - intLiteral(lastOrd(p.config, ty), last) - linefmt(p, cpsStmts, "if ($1 < $2 || $1 > $3){ #raiseIndexError3($1, $2, $3); ", - [rdCharLoc(b), first, last]) - raiseInstr(p, p.s(cpsStmts)) - linefmt p, cpsStmts, "}$n", [] - + linefmt(p, cpsStmts, "if ($1 < $2 || $1 > $3) #raiseIndexError3($1, $2, $3);$n", + [rdCharLoc(b), first, intLiteral(lastOrd(p.config, ty))]) else: let idx = getOrdValue(y) if idx < firstOrd(p.config, ty) or idx > lastOrd(p.config, ty): @@ -1044,67 +889,33 @@ proc genBoundsCheck(p: BProc; arr, a, b: TLoc) = let ty = skipTypes(arr.t, abstractVarRange) case ty.kind of tyOpenArray, tyVarargs: - if reifiedOpenArray(arr.lode): - linefmt(p, cpsStmts, - "if ($2-$1 != -1 && " & - "($1 < 0 || $1 >= $3.Field1 || $2 < 0 || $2 >= $3.Field1)){ #raiseIndexError4($1, $2, $3.Field1); ", - [rdLoc(a), rdLoc(b), rdLoc(arr)]) - else: - linefmt(p, cpsStmts, - "if ($2-$1 != -1 && ($1 < 0 || $1 >= $3Len_0 || $2 < 0 || $2 >= $3Len_0))" & - "{ #raiseIndexError4($1, $2, $3Len_0); ", - [rdLoc(a), rdLoc(b), rdLoc(arr)]) - raiseInstr(p, p.s(cpsStmts)) - linefmt p, cpsStmts, "}$n", [] - - of tyArray: - var first = newRopeAppender() - intLiteral(firstOrd(p.config, ty), first) - var last = newRopeAppender() - intLiteral(lastOrd(p.config, ty), last) linefmt(p, cpsStmts, "if ($2-$1 != -1 && " & - "($2-$1 < -1 || $1 < $3 || $1 > $4 || $2 < $3 || $2 > $4)){ #raiseIndexError(); ", - [rdCharLoc(a), rdCharLoc(b), first, last]) - - raiseInstr(p, p.s(cpsStmts)) - linefmt p, cpsStmts, "}$n", [] - + "((NU)($1) >= (NU)($3Len_0) || (NU)($2) >= (NU)($3Len_0))) #raiseIndexError();$n", + [rdLoc(a), rdLoc(b), rdLoc(arr)]) + of tyArray: + let first = intLiteral(firstOrd(p.config, ty)) + linefmt(p, cpsStmts, + "if ($2-$1 != -1 && " & + "($2-$1 < -1 || $1 < $3 || $1 > $4 || $2 < $3 || $2 > $4)) #raiseIndexError();$n", + [rdCharLoc(a), rdCharLoc(b), first, intLiteral(lastOrd(p.config, ty))]) of tySequence, tyString: linefmt(p, cpsStmts, "if ($2-$1 != -1 && " & - "($1 < 0 || $1 >= $3 || $2 < 0 || $2 >= $3)){ #raiseIndexError4($1, $2, $3); ", + "((NU)($1) >= (NU)$3 || (NU)($2) >= (NU)$3)) #raiseIndexError();$n", [rdLoc(a), rdLoc(b), lenExpr(p, arr)]) - raiseInstr(p, p.s(cpsStmts)) - linefmt p, cpsStmts, "}$n", [] - else: discard proc genOpenArrayElem(p: BProc, n, x, y: PNode, d: var TLoc) = var a, b: TLoc initLocExpr(p, x, a) - initLocExpr(p, y, b) - if not reifiedOpenArray(x): - # emit range check: - if optBoundsCheck in p.options: - linefmt(p, cpsStmts, "if ($1 < 0 || $1 >= $2Len_0){ #raiseIndexError2($1,$2Len_0-1); ", - [rdCharLoc(b), rdLoc(a)]) # BUGFIX: ``>=`` and not ``>``! - raiseInstr(p, p.s(cpsStmts)) - linefmt p, cpsStmts, "}$n", [] - - inheritLocation(d, a) - putIntoDest(p, d, n, - ropecg(p.module, "$1[$2]", [rdLoc(a), rdCharLoc(b)]), a.storage) - else: - if optBoundsCheck in p.options: - linefmt(p, cpsStmts, "if ($1 < 0 || $1 >= $2.Field1){ #raiseIndexError2($1,$2.Field1-1); ", - [rdCharLoc(b), rdLoc(a)]) # BUGFIX: ``>=`` and not ``>``! - raiseInstr(p, p.s(cpsStmts)) - linefmt p, cpsStmts, "}$n", [] - - inheritLocation(d, a) - putIntoDest(p, d, n, - ropecg(p.module, "$1.Field0[$2]", [rdLoc(a), rdCharLoc(b)]), a.storage) + initLocExpr(p, y, b) # emit range check: + if optBoundsCheck in p.options: + linefmt(p, cpsStmts, "if ((NU)($1) >= (NU)($2Len_0)) #raiseIndexError2($1,$2Len_0-1);$n", + [rdLoc(b), rdLoc(a)]) # BUGFIX: ``>=`` and not ``>``! + inheritLocation(d, a) + putIntoDest(p, d, n, + ropecg(p.module, "$1[$2]", [rdLoc(a), rdCharLoc(b)]), a.storage) proc genSeqElem(p: BProc, n, x, y: PNode, d: var TLoc) = var a, b: TLoc @@ -1114,12 +925,14 @@ proc genSeqElem(p: BProc, n, x, y: PNode, d: var TLoc) = if ty.kind in {tyRef, tyPtr}: ty = skipTypes(ty.lastSon, abstractVarRange) # emit range check: if optBoundsCheck in p.options: - linefmt(p, cpsStmts, - "if ($1 < 0 || $1 >= $2){ #raiseIndexError2($1,$2-1); ", - [rdCharLoc(b), lenExpr(p, a)]) - raiseInstr(p, p.s(cpsStmts)) - linefmt p, cpsStmts, "}$n", [] - + if ty.kind == tyString and (not defined(nimNoZeroTerminator) or optLaxStrings in p.options): + linefmt(p, cpsStmts, + "if ((NU)($1) > (NU)$2) #raiseIndexError2($1,$2);$n", + [rdLoc(b), lenExpr(p, a)]) + else: + linefmt(p, cpsStmts, + "if ((NU)($1) >= (NU)$2) #raiseIndexError2($1,$2-1);$n", + [rdLoc(b), lenExpr(p, a)]) if d.k == locNone: d.storage = OnHeap if skipTypes(a.t, abstractVar).kind in {tyRef, tyPtr}: a.r = ropecg(p.module, "(*$1)", [a.r]) @@ -1138,7 +951,7 @@ proc genBracketExpr(p: BProc; n: PNode; d: var TLoc) = of tyArray: genArrayElem(p, n, n[0], n[1], d) of tyOpenArray, tyVarargs: genOpenArrayElem(p, n, n[0], n[1], d) of tySequence, tyString: genSeqElem(p, n, n[0], n[1], d) - of tyCstring: genCStringElem(p, n, n[0], n[1], d) + of tyCString: genCStringElem(p, n, n[0], n[1], d) of tyTuple: genTupleElem(p, n, d) else: internalError(p.config, n.info, "expr(nkBracketExpr, " & $ty.kind & ')') discard getTypeDesc(p.module, n.typ) @@ -1223,23 +1036,17 @@ proc genEcho(p: BProc, n: PNode) = internalAssert p.config, n.kind == nkBracket if p.config.target.targetOS == osGenode: # echo directly to the Genode LOG session - var args: Rope = "" + var args: Rope = nil var a: TLoc - for i, it in n.sons: + for it in n.sons: if it.skipConv.kind == nkNilLit: args.add(", \"\"") - elif n.len != 0: + else: initLocExpr(p, it, a) - if i > 0: - args.add(", ") - case detectStrVersion(p.module) - of 2: - args.add(ropecg(p.module, "Genode::Cstring($1.p->data, $1.len)", [a.rdLoc])) - else: - args.add(ropecg(p.module, "Genode::Cstring($1->data, $1->len)", [a.rdLoc])) + args.add(ropecg(p.module, ", Genode::Cstring($1->data, $1->len)", [rdLoc(a)])) p.module.includeHeader("") p.module.includeHeader("") - linefmt(p, cpsStmts, """Genode::log($1);$n""", [args]) + linefmt(p, cpsStmts, """Genode::log(""$1);$n""", [args]) else: if n.len == 0: linefmt(p, cpsStmts, "#echoBinSafe(NIM_NIL, $1);$n", [n.len]) @@ -1264,7 +1071,7 @@ proc strLoc(p: BProc; d: TLoc): Rope = proc genStrConcat(p: BProc, e: PNode, d: var TLoc) = # - # s = "Hello " & name & ", how do you feel?" & 'z' + # s = 'Hello ' & name & ', how do you feel?' & 'z' # # # { @@ -1282,8 +1089,8 @@ proc genStrConcat(p: BProc, e: PNode, d: var TLoc) = var a, tmp: TLoc getTemp(p, e.typ, tmp) var L = 0 - var appends: Rope = "" - var lens: Rope = "" + var appends: Rope = nil + var lens: Rope = nil for i in 0.. - # s &= "Hello " & name & ", how do you feel?" & 'z' + # s &= 'Hello ' & name & ', how do you feel?' & 'z' # // BUG: what if s is on the left side too? # # { @@ -1361,12 +1168,12 @@ proc genSeqElemAppend(p: BProc, e: PNode, d: var TLoc) = const seqAppendPattern = "($2) #incrSeqV3((TGenericSeq*)($1), $3)" call.r = ropecg(p.module, seqAppendPattern, [rdLoc(a), getTypeDesc(p.module, e[1].typ), - genTypeInfoV1(p.module, seqType, e.info)]) + genTypeInfo(p.module, seqType, e.info)]) else: const seqAppendPattern = "($2) #incrSeqV3($1, $3)" call.r = ropecg(p.module, seqAppendPattern, [rdLoc(a), getTypeDesc(p.module, e[1].typ), - genTypeInfoV1(p.module, seqType, e.info)]) + genTypeInfo(p.module, seqType, e.info)]) # emit the write barrier if required, but we can always move here, so # use 'genRefAssign' for the seq. genRefAssign(p, a, call) @@ -1382,11 +1189,9 @@ proc genSeqElemAppend(p: BProc, e: PNode, d: var TLoc) = proc genReset(p: BProc, n: PNode) = var a: TLoc initLocExpr(p, n[1], a) - specializeReset(p, a) - when false: - linefmt(p, cpsStmts, "#genericReset((void*)$1, $2);$n", - [addrLoc(p.config, a), - genTypeInfoV1(p.module, skipTypes(a.t, {tyVar}), n.info)]) + linefmt(p, cpsStmts, "#genericReset((void*)$1, $2);$n", + [addrLoc(p.config, a), + genTypeInfo(p.module, skipTypes(a.t, {tyVar}), n.info)]) proc genDefault(p: BProc; n: PNode; d: var TLoc) = if d.k == locNone: getTemp(p, n.typ, d, needsInit=true) @@ -1400,30 +1205,29 @@ proc rawGenNew(p: BProc, a: var TLoc, sizeExpr: Rope; needsInit: bool) = let refType = typ.skipTypes(abstractInstOwned) assert refType.kind == tyRef let bt = refType.lastSon - if sizeExpr == "": + if sizeExpr.isNil: sizeExpr = "sizeof($1)" % [getTypeDesc(p.module, bt)] if optTinyRtti in p.config.globalOptions: if needsInit: - b.r = ropecg(p.module, "($1) #nimNewObj($2, NIM_ALIGNOF($3))", - [getTypeDesc(p.module, typ), sizeExpr, getTypeDesc(p.module, bt)]) + b.r = ropecg(p.module, "($1) #nimNewObj($2)", + [getTypeDesc(p.module, typ), sizeExpr]) else: - b.r = ropecg(p.module, "($1) #nimNewObjUninit($2, NIM_ALIGNOF($3))", - [getTypeDesc(p.module, typ), sizeExpr, getTypeDesc(p.module, bt)]) + b.r = ropecg(p.module, "($1) #nimNewObjUninit($2)", + [getTypeDesc(p.module, typ), sizeExpr]) genAssignment(p, a, b, {}) else: - let ti = genTypeInfoV1(p.module, typ, a.lode.info) - let op = getAttachedOp(p.module.g.graph, bt, attachedDestructor) - if op != nil and not isTrivialProc(p.module.g.graph, op): + let ti = genTypeInfo(p.module, typ, a.lode.info) + if bt.destructor != nil and not isTrivialProc(bt.destructor): # the prototype of a destructor is ``=destroy(x: var T)`` and that of a # finalizer is: ``proc (x: ref T) {.nimcall.}``. We need to check the calling # convention at least: - if op.typ == nil or op.typ.callConv != ccNimCall: + if bt.destructor.typ == nil or bt.destructor.typ.callConv != ccDefault: localError(p.module.config, a.lode.info, "the destructor that is turned into a finalizer needs " & "to have the 'nimcall' calling convention") var f: TLoc - initLocExpr(p, newSymNode(op), f) + initLocExpr(p, newSymNode(bt.destructor), f) p.module.s[cfsTypeInit3].addf("$1->finalizer = (void*)$2;$n", [ti, rdLoc(f)]) if a.storage == OnHeap and usesWriteBarrier(p.config): @@ -1456,7 +1260,7 @@ proc genNew(p: BProc, e: PNode) = initLocExpr(p, e[2], se) rawGenNew(p, a, se.rdLoc, needsInit = true) else: - rawGenNew(p, a, "", needsInit = true) + rawGenNew(p, a, nil, needsInit = true) gcUsage(p.config, e) proc genNewSeqAux(p: BProc, dest: TLoc, length: Rope; lenIsZero: bool) = @@ -1472,18 +1276,18 @@ proc genNewSeqAux(p: BProc, dest: TLoc, length: Rope; lenIsZero: bool) = if p.config.selectedGC == gcGo: # we need the write barrier call.r = ropecg(p.module, "($1) #newSeq($2, $3)", [getTypeDesc(p.module, seqtype), - genTypeInfoV1(p.module, seqtype, dest.lode.info), length]) + genTypeInfo(p.module, seqtype, dest.lode.info), length]) linefmt(p, cpsStmts, "#unsureAsgnRef((void**) $1, $2);$n", [addrLoc(p.config, dest), call.rdLoc]) else: call.r = ropecg(p.module, "($1) #newSeqRC1($2, $3)", [getTypeDesc(p.module, seqtype), - genTypeInfoV1(p.module, seqtype, dest.lode.info), length]) + genTypeInfo(p.module, seqtype, dest.lode.info), length]) linefmt(p, cpsStmts, "$1 = $2;$n", [dest.rdLoc, call.rdLoc]) else: if lenIsZero: call.r = rope"NIM_NIL" else: call.r = ropecg(p.module, "($1) #newSeq($2, $3)", [getTypeDesc(p.module, seqtype), - genTypeInfoV1(p.module, seqtype, dest.lode.info), length]) + genTypeInfo(p.module, seqtype, dest.lode.info), length]) genAssignment(p, dest, call, {}) proc genNewSeq(p: BProc, e: PNode) = @@ -1492,12 +1296,12 @@ proc genNewSeq(p: BProc, e: PNode) = initLocExpr(p, e[2], b) if optSeqDestructors in p.config.globalOptions: let seqtype = skipTypes(e[1].typ, abstractVarRange) - linefmt(p, cpsStmts, "$1.len = $2; $1.p = ($4*) #newSeqPayload($2, sizeof($3), NIM_ALIGNOF($3));$n", - [a.rdLoc, b.rdLoc, - getTypeDesc(p.module, seqtype.lastSon), - getSeqPayloadType(p.module, seqtype)]) + linefmt(p, cpsStmts, "$1.len = $2; $1.p = ($4*) #newSeqPayload($2, sizeof($3));$n", + [a.rdLoc, b.rdLoc, getTypeDesc(p.module, seqtype.lastSon), + getSeqPayloadType(p.module, seqtype)]) else: - let lenIsZero = e[2].kind == nkIntLit and e[2].intVal == 0 + let lenIsZero = optNilSeqs notin p.options and + e[2].kind == nkIntLit and e[2].intVal == 0 genNewSeqAux(p, a, b.rdLoc, lenIsZero) gcUsage(p.config, e) @@ -1507,15 +1311,14 @@ 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*) #newSeqPayload($2, sizeof($3), NIM_ALIGNOF($3));$n", + linefmt(p, cpsStmts, "$1.len = 0; $1.p = ($4*) #newSeqPayload($2, sizeof($3));$n", [d.rdLoc, a.rdLoc, getTypeDesc(p.module, seqtype.lastSon), - getSeqPayloadType(p.module, seqtype), - ]) + getSeqPayloadType(p.module, seqtype)]) else: putIntoDest(p, d, e, ropecg(p.module, "($1)#nimNewSeqOfCap($2, $3)", [ getTypeDesc(p.module, seqtype), - genTypeInfoV1(p.module, seqtype, e.info), a.rdLoc])) + genTypeInfo(p.module, seqtype, e.info), a.rdLoc])) gcUsage(p.config, e) proc rawConstExpr(p: BProc, n: PNode; d: var TLoc) = @@ -1526,9 +1329,8 @@ proc rawConstExpr(p: BProc, n: PNode; d: var TLoc) = if id == p.module.labels: # expression not found in the cache: inc(p.module.labels) - p.module.s[cfsData].addf("static NIM_CONST $1 $2 = ", [getTypeDesc(p.module, t), d.r]) - genBracedInit(p, n, isConst = true, t, p.module.s[cfsData]) - p.module.s[cfsData].addf(";$n", []) + p.module.s[cfsData].addf("static NIM_CONST $1 $2 = $3;$n", + [getTypeDesc(p.module, t), d.r, genBracedInit(p, n, isConst = true)]) proc handleConstExpr(p: BProc, n: PNode, d: var TLoc): bool = if d.k == locNone and n.len > ord(n.kind == nkObjConstr) and n.isDeepConstExpr: @@ -1538,17 +1340,10 @@ proc handleConstExpr(p: BProc, n: PNode, d: var TLoc): bool = result = false proc genObjConstr(p: BProc, e: PNode, d: var TLoc) = - #echo renderTree e, " ", e.isDeepConstExpr + #echo rendertree e, " ", e.isDeepConstExpr # inheritance in C++ does not allow struct initialization so # we skip this step here: - if not p.module.compileToCpp and optSeqDestructors notin p.config.globalOptions: - # disabled optimization: it is wrong for C++ and now also - # causes trouble for --gc:arc, see bug #13240 - #[ - var box: seq[Thing] - for i in 0..3: - box.add Thing(s1: "121") # pass by sink can mutate Thing. - ]# + if not p.module.compileToCpp: if handleConstExpr(p, e, d): return var t = e.typ.skipTypes(abstractInstOwned) let isRef = t.kind == tyRef @@ -1565,7 +1360,7 @@ proc genObjConstr(p: BProc, e: PNode, d: var TLoc) = getTemp(p, t, tmp) r = rdLoc(tmp) if isRef: - rawGenNew(p, tmp, "", needsInit = nfAllFieldsSet notin e.flags) + rawGenNew(p, tmp, nil, needsInit = nfAllFieldsSet notin e.flags) t = t.lastSon.skipTypes(abstractInstOwned) r = "(*$1)" % [r] gcUsage(p.config, e) @@ -1581,8 +1376,8 @@ proc genObjConstr(p: BProc, e: PNode, d: var TLoc) = var tmp2: TLoc tmp2.r = r let field = lookupFieldAgain(p, ty, it[0].sym, tmp2.r) - if field.loc.r == "": fillObjectFields(p.module, ty) - if field.loc.r == "": internalError(p.config, e.info, "genObjConstr") + if field.loc.r == nil: fillObjectFields(p.module, ty) + if field.loc.r == nil: internalError(p.config, e.info, "genObjConstr") if it.len == 3 and optFieldCheck in p.options: genFieldCheck(p, it[2], r, field) tmp2.r.add(".") @@ -1615,21 +1410,19 @@ proc genSeqConstr(p: BProc, n: PNode, d: var TLoc) = elif d.k == locNone: getTemp(p, n.typ, d) - var lit = newRopeAppender() - intLiteral(n.len, lit) + let l = intLiteral(n.len) if optSeqDestructors in p.config.globalOptions: let seqtype = n.typ - linefmt(p, cpsStmts, "$1.len = $2; $1.p = ($4*) #newSeqPayload($2, sizeof($3), NIM_ALIGNOF($3));$n", - [rdLoc dest[], lit, getTypeDesc(p.module, seqtype.lastSon), + linefmt(p, cpsStmts, "$1.len = $2; $1.p = ($4*) #newSeqPayload($2, sizeof($3));$n", + [rdLoc dest[], l, getTypeDesc(p.module, seqtype.lastSon), getSeqPayloadType(p.module, seqtype)]) else: # generate call to newSeq before adding the elements per hand: - genNewSeqAux(p, dest[], lit, n.len == 0) + genNewSeqAux(p, dest[], l, + optNilSeqs notin p.options and n.len == 0) for i in 0..finalizer = (void*)$2;$n", [ti, rdLoc(f)]) b.r = ropecg(p.module, "($1) #newObj($2, sizeof($3))", [ getTypeDesc(p.module, refType), @@ -1702,30 +1491,34 @@ proc genNewFinalize(p: BProc, e: PNode) = genObjectInit(p, cpsStmts, bt, a, constructRefObj) gcUsage(p.config, e) -proc genOfHelper(p: BProc; dest: PType; a: Rope; info: TLineInfo; result: var Rope) = +proc genOfHelper(p: BProc; dest: PType; a: Rope; info: TLineInfo): Rope = if optTinyRtti in p.config.globalOptions: - let token = $genDisplayElem(MD5Digest(hashType(dest, p.config))) - appcg(p.module, result, "#isObjDisplayCheck($#.m_type, $#, $#)", [a, getObjDepth(dest), token]) + result = ropecg(p.module, "#isObj($1.m_type, $2)", + [a, genTypeInfo2Name(p.module, dest)]) else: - # unfortunately 'genTypeInfoV1' sets tfObjHasKids as a side effect, so we + # unfortunately 'genTypeInfo' sets tfObjHasKids as a side effect, so we # have to call it here first: - let ti = genTypeInfoV1(p.module, dest, info) + let ti = genTypeInfo(p.module, dest, info) if tfFinal in dest.flags or (objHasKidsValid in p.module.flags and tfObjHasKids notin dest.flags): - result.add "$1.m_type == $2" % [a, ti] + result = "$1.m_type == $2" % [a, ti] else: - cgsym(p.module, "TNimType") + discard cgsym(p.module, "TNimType") inc p.module.labels let cache = "Nim_OfCheck_CACHE" & p.module.labels.rope p.module.s[cfsVars].addf("static TNimType* $#[2];$n", [cache]) - appcg(p.module, result, "#isObjWithCache($#.m_type, $#, $#)", [a, ti, cache]) + result = ropecg(p.module, "#isObjWithCache($#.m_type, $#, $#)", [a, ti, cache]) + when false: + # former version: + result = ropecg(p.module, "#isObj($1.m_type, $2)", + [a, genTypeInfo(p.module, dest, info)]) proc genOf(p: BProc, x: PNode, typ: PType, d: var TLoc) = var a: TLoc initLocExpr(p, x, a) var dest = skipTypes(typ, typedescPtrs) var r = rdLoc(a) - var nilCheck: Rope = "" + var nilCheck: Rope = nil var t = skipTypes(a.t, abstractInstOwned) while t.kind in {tyVar, tyLent, tyPtr, tyRef}: if t.kind notin {tyVar, tyLent}: nilCheck = r @@ -1735,27 +1528,16 @@ proc genOf(p: BProc, x: PNode, typ: PType, d: var TLoc) = discard getTypeDesc(p.module, t) if not p.module.compileToCpp: while t.kind == tyObject and t[0] != nil: - r.add(".Sup") + r.add(~".Sup") t = skipTypes(t[0], skipPtrs) if isObjLackingTypeField(t): globalError(p.config, x.info, "no 'of' operator available for pure objects") - - var ro = newRopeAppender() - genOfHelper(p, dest, r, x.info, ro) - var ofExpr = newRopeAppender() - ofExpr.add "(" - if nilCheck != "": - ofExpr.add "(" - ofExpr.add nilCheck - ofExpr.add ") && (" - ofExpr.add ro - ofExpr.add "))" + if nilCheck != nil: + r = ropecg(p.module, "(($1) && ($2))", [nilCheck, genOfHelper(p, dest, r, x.info)]) else: - ofExpr.add ro - ofExpr.add ")" - - putIntoDest(p, d, x, ofExpr, a.storage) + r = ropecg(p.module, "($1)", [genOfHelper(p, dest, r, x.info)]) + putIntoDest(p, d, x, r, a.storage) proc genOf(p: BProc, n: PNode, d: var TLoc) = genOf(p, n[1], n[2].typ, d) @@ -1779,12 +1561,12 @@ proc genRepr(p: BProc, e: PNode, d: var TLoc) = of tyEnum, tyOrdinal: putIntoDest(p, d, e, ropecg(p.module, "#reprEnum((NI)$1, $2)", [ - rdLoc(a), genTypeInfoV1(p.module, t, e.info)]), a.storage) + rdLoc(a), genTypeInfo(p.module, t, e.info)]), a.storage) of tyString: putIntoDest(p, d, e, ropecg(p.module, "#reprStr($1)", [rdLoc(a)]), a.storage) of tySet: putIntoDest(p, d, e, ropecg(p.module, "#reprSet($1, $2)", [ - addrLoc(p.config, a), genTypeInfoV1(p.module, t, e.info)]), a.storage) + addrLoc(p.config, a), genTypeInfo(p.module, t, e.info)]), a.storage) of tyOpenArray, tyVarargs: var b: TLoc case skipTypes(a.t, abstractVarRange).kind @@ -1792,80 +1574,36 @@ proc genRepr(p: BProc, e: PNode, d: var TLoc) = putIntoDest(p, b, e, "$1, $1Len_0" % [rdLoc(a)], a.storage) of tyString, tySequence: putIntoDest(p, b, e, - "($4) ? ($1$3) : NIM_NIL, $2" % - [rdLoc(a), lenExpr(p, a), dataField(p), dataFieldAccessor(p, a.rdLoc)], - a.storage) + "$1$3, $2" % [rdLoc(a), lenExpr(p, a), dataField(p)], a.storage) of tyArray: putIntoDest(p, b, e, "$1, $2" % [rdLoc(a), rope(lengthOrd(p.config, a.t))], a.storage) else: internalError(p.config, e[0].info, "genRepr()") putIntoDest(p, d, e, ropecg(p.module, "#reprOpenArray($1, $2)", [rdLoc(b), - genTypeInfoV1(p.module, elemType(t), e.info)]), a.storage) - of tyCstring, tyArray, tyRef, tyPtr, tyPointer, tyNil, tySequence: + genTypeInfo(p.module, elemType(t), e.info)]), a.storage) + of tyCString, tyArray, tyRef, tyPtr, tyPointer, tyNil, tySequence: putIntoDest(p, d, e, ropecg(p.module, "#reprAny($1, $2)", [ - rdLoc(a), genTypeInfoV1(p.module, t, e.info)]), a.storage) + rdLoc(a), genTypeInfo(p.module, t, e.info)]), a.storage) of tyEmpty, tyVoid: localError(p.config, e.info, "'repr' doesn't support 'void' type") else: putIntoDest(p, d, e, ropecg(p.module, "#reprAny($1, $2)", - [addrLoc(p.config, a), genTypeInfoV1(p.module, t, e.info)]), + [addrLoc(p.config, a), genTypeInfo(p.module, t, e.info)]), a.storage) gcUsage(p.config, e) -proc rdMType(p: BProc; a: TLoc; nilCheck: var Rope; result: var Rope; enforceV1 = false) = - var derefs = rdLoc(a) - var t = skipTypes(a.t, abstractInst) - while t.kind in {tyVar, tyLent, tyPtr, tyRef}: - if t.kind notin {tyVar, tyLent}: nilCheck = derefs - if t.kind notin {tyVar, tyLent} or not p.module.compileToCpp: - derefs = "(*$1)" % [derefs] - t = skipTypes(t.lastSon, abstractInst) - result.add derefs - discard getTypeDesc(p.module, t) - if not p.module.compileToCpp: - while t.kind == tyObject and t[0] != nil: - result.add(".Sup") - t = skipTypes(t[0], skipPtrs) - result.add ".m_type" - if optTinyRtti in p.config.globalOptions and enforceV1: - result.add "->typeInfoV1" - proc genGetTypeInfo(p: BProc, e: PNode, d: var TLoc) = - cgsym(p.module, "TNimType") + discard cgsym(p.module, "TNimType") let t = e[1].typ - # ordinary static type information - putIntoDest(p, d, e, genTypeInfoV1(p.module, t, e.info)) - -proc genGetTypeInfoV2(p: BProc, e: PNode, d: var TLoc) = - let t = e[1].typ - if isFinal(t) or e[0].sym.name.s != "getDynamicTypeInfo": - # ordinary static type information - putIntoDest(p, d, e, genTypeInfoV2(p.module, t, e.info)) - else: - var a: TLoc - initLocExpr(p, e[1], a) - var nilCheck = "" - # use the dynamic type stored at offset 0: - var rt = newRopeAppender() - rdMType(p, a, nilCheck, rt) - putIntoDest(p, d, e, rt) - -proc genAccessTypeField(p: BProc; e: PNode; d: var TLoc) = - var a: TLoc - initLocExpr(p, e[1], a) - var nilCheck = "" - # use the dynamic type stored at offset 0: - var rt = newRopeAppender() - rdMType(p, a, nilCheck, rt) - putIntoDest(p, d, e, rt) + putIntoDest(p, d, e, genTypeInfo(p.module, t, e.info)) template genDollar(p: BProc, n: PNode, d: var TLoc, frmt: string) = var a: TLoc initLocExpr(p, n[1], a) a.r = ropecg(p.module, frmt, [rdLoc(a)]) - a.flags.excl lfIndirect # this flag should not be propagated here (not just for HCR) + a.flags = a.flags - {lfIndirect} # this flag should not be propagated here (not just for HCR) if d.k == locNone: getTemp(p, n.typ, d) genAssignment(p, d, a, {}) gcUsage(p.config, n) @@ -1879,25 +1617,17 @@ proc genArrayLen(p: BProc, e: PNode, d: var TLoc, op: TMagic) = # Bug #9279, len(toOpenArray()) has to work: if a.kind in nkCallKinds and a[0].kind == nkSym and a[0].sym.magic == mSlice: # magic: pass slice to openArray: - var m: TLoc var b, c: TLoc - initLocExpr(p, a[1], m) initLocExpr(p, a[2], b) initLocExpr(p, a[3], c) - if optBoundsCheck in p.options: - genBoundsCheck(p, m, b, c) if op == mHigh: putIntoDest(p, d, e, ropecg(p.module, "($2)-($1)", [rdLoc(b), rdLoc(c)])) else: 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: - 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, "($1Len_0-1)") + else: unaryExpr(p, e, d, "$1Len_0") + of tyCString: if op == mHigh: unaryExpr(p, e, d, "($1 ? (#nimCStrLen($1)-1) : -1)") else: unaryExpr(p, e, d, "($1 ? #nimCStrLen($1) : 0)") of tyString: @@ -1921,20 +1651,20 @@ 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 makePtrType(baseType: PType): PType = + result = newType(tyPtr, baseType.owner) + addSonSkipIntLit(result, baseType) -proc makeAddr(n: PNode; idgen: IdGenerator): PNode = +proc makeAddr(n: PNode): PNode = if n.kind == nkHiddenAddr: result = n else: result = newTree(nkHiddenAddr, n) - result.typ = makePtrType(n.typ, idgen) + result.typ = makePtrType(n.typ) proc genSetLengthSeq(p: BProc, e: PNode, d: var TLoc) = if optSeqDestructors in p.config.globalOptions: - e[1] = makeAddr(e[1], p.module.idgen) + e[1] = makeAddr(e[1]) genCall(p, e, d) return var a, b, call: TLoc @@ -1950,13 +1680,13 @@ proc genSetLengthSeq(p: BProc, e: PNode, d: var TLoc) = 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)]) + genTypeInfo(p.module, t.skipTypes(abstractInst), e.info)]) else: const setLenPattern = "($3) #setLengthSeqV2($1, $4, $2)" call.r = ropecg(p.module, setLenPattern, [ rdLoc(a), rdLoc(b), getTypeDesc(p.module, t), - genTypeInfoV1(p.module, t.skipTypes(abstractInst), e.info)]) + genTypeInfo(p.module, t.skipTypes(abstractInst), e.info)]) genAssignment(p, a, call, {}) gcUsage(p.config, e) @@ -1981,8 +1711,6 @@ proc genSwap(p: BProc, e: PNode, d: var TLoc) = # temp = a # a = b # b = temp - cowBracket(p, e[1]) - cowBracket(p, e[2]) var a, b, tmp: TLoc getTemp(p, skipTypes(e[1].typ, abstractVar), tmp) initLocExpr(p, e[1], a) # eval a @@ -1991,17 +1719,14 @@ proc genSwap(p: BProc, e: PNode, d: var TLoc) = genAssignment(p, a, b, {}) genAssignment(p, b, tmp, {}) -proc rdSetElemLoc(conf: ConfigRef; a: TLoc, typ: PType; result: var Rope) = +proc rdSetElemLoc(conf: ConfigRef; a: TLoc, typ: PType): Rope = # read a location of an set element; it may need a subtraction operation # before the set operation - result.add "(" - result.add rdCharLoc(a) + result = rdCharLoc(a) let setType = typ.skipTypes(abstractPtrs) assert(setType.kind == tySet) if firstOrd(conf, setType) != 0: - result.add " - " - result.add rope(firstOrd(conf, setType)) - result.add ")" + result = "($1- $2)" % [result, rope(firstOrd(conf, setType))] proc fewCmps(conf: ConfigRef; s: PNode): bool = # this function estimates whether it is better to emit code @@ -2015,15 +1740,13 @@ proc fewCmps(conf: ConfigRef; s: PNode): bool = result = s.len <= 8 # 8 seems to be a good value template binaryExprIn(p: BProc, e: PNode, a, b, d: var TLoc, frmt: string) = - var elem = newRopeAppender() - rdSetElemLoc(p.config, b, a.t, elem) - putIntoDest(p, d, e, frmt % [rdLoc(a), elem]) + putIntoDest(p, d, e, frmt % [rdLoc(a), rdSetElemLoc(p.config, b, a.t)]) proc genInExprAux(p: BProc, e: PNode, a, b, d: var TLoc) = case int(getSize(p.config, skipTypes(e[1].typ, abstractVar))) - of 1: binaryExprIn(p, e, a, b, d, "(($1 &((NU8)1<<((NU)($2)&7U)))!=0)") - of 2: binaryExprIn(p, e, a, b, d, "(($1 &((NU16)1<<((NU)($2)&15U)))!=0)") - of 4: binaryExprIn(p, e, a, b, d, "(($1 &((NU32)1<<((NU)($2)&31U)))!=0)") + of 1: binaryExprIn(p, e, a, b, d, "(($1 &(1U<<((NU)($2)&7U)))!=0)") + of 2: binaryExprIn(p, e, a, b, d, "(($1 &(1U<<((NU)($2)&15U)))!=0)") + of 4: binaryExprIn(p, e, a, b, d, "(($1 &(1U<<((NU)($2)&31U)))!=0)") of 8: binaryExprIn(p, e, a, b, d, "(($1 &((NU64)1<<((NU)($2)&63U)))!=0)") else: binaryExprIn(p, e, a, b, d, "(($1[(NU)($2)>>3] &(1U<<((NU)($2)&7U)))!=0)") @@ -2032,9 +1755,7 @@ template binaryStmtInExcl(p: BProc, e: PNode, d: var TLoc, frmt: string) = assert(d.k == locNone) initLocExpr(p, e[1], a) initLocExpr(p, e[2], b) - var elem = newRopeAppender() - rdSetElemLoc(p.config, b, a.t, elem) - lineF(p, cpsStmts, frmt, [rdLoc(a), elem]) + lineF(p, cpsStmts, frmt, [rdLoc(a), rdSetElemLoc(p.config, b, a.t)]) proc genInOp(p: BProc, e: PNode, d: var TLoc) = var a, b, x, y: TLoc @@ -2076,7 +1797,7 @@ proc genInOp(p: BProc, e: PNode, d: var TLoc) = proc genSetOp(p: BProc, e: PNode, d: var TLoc, op: TMagic) = const - lookupOpr: array[mLeSet..mMinusSet, string] = [ + lookupOpr: array[mLeSet..mSymDiffSet, string] = [ "for ($1 = 0; $1 < $2; $1++) { $n" & " $3 = (($4[$1] & ~ $5[$1]) == 0);$n" & " if (!$3) break;}$n", @@ -2086,7 +1807,8 @@ proc genSetOp(p: BProc, e: PNode, d: var TLoc, op: TMagic) = "if ($3) $3 = (#nimCmpMem($4, $5, $2) != 0);$n", "&", "|", - "& ~"] + "& ~", + "^"] var a, b, i: TLoc var setType = skipTypes(e[1].typ, abstractVar) var size = int(getSize(p.config, setType)) @@ -2116,6 +1838,7 @@ proc genSetOp(p: BProc, e: PNode, d: var TLoc, op: TMagic) = of mMulSet: binaryExpr(p, e, d, "($1 & $2)") of mPlusSet: binaryExpr(p, e, d, "($1 | $2)") of mMinusSet: binaryExpr(p, e, d, "($1 & ~ $2)") + of mSymDiffSet: binaryExpr(p, e, d, "($1 ^ $2)") of mInSet: genInOp(p, e, d) else: internalError(p.config, e.info, "genSetOp()") @@ -2126,7 +1849,7 @@ proc genSetOp(p: BProc, e: PNode, d: var TLoc, op: TMagic) = of mCard: var a: TLoc initLocExpr(p, e[1], a) - putIntoDest(p, d, e, ropecg(p.module, "#cardSet($1, $2)", [addrLoc(p.config, a), size])) + putIntoDest(p, d, e, ropecg(p.module, "#cardSet($1, $2)", [rdCharLoc(a), size])) of mLtSet, mLeSet: getTemp(p, getSysType(p.module.g.graph, unknownLineInfo, tyInt), i) # our counter initLocExpr(p, e[1], a) @@ -2145,7 +1868,7 @@ proc genSetOp(p: BProc, e: PNode, d: var TLoc, op: TMagic) = initLocExpr(p, e[1], a) initLocExpr(p, e[2], b) putIntoDest(p, d, e, ropecg(p.module, "(#nimCmpMem($1, $2, $3)==0)", [a.rdCharLoc, b.rdCharLoc, size])) - of mMulSet, mPlusSet, mMinusSet: + of mMulSet, mPlusSet, mMinusSet, mSymDiffSet: # we inline the simple for loop for better code generation: getTemp(p, getSysType(p.module.g.graph, unknownLineInfo, tyInt), i) # our counter initLocExpr(p, e[1], a) @@ -2185,14 +1908,7 @@ proc genSomeCast(p: BProc, e: PNode, d: var TLoc) = elif optSeqDestructors in p.config.globalOptions and etyp.kind in {tySequence, tyString}: putIntoDest(p, d, e, "(*($1*) (&$2))" % [getTypeDesc(p.module, e.typ), rdCharLoc(a)], a.storage) - elif etyp.kind == tyBool and srcTyp.kind in IntegralTypes: - putIntoDest(p, d, e, "(($1) != 0)" % [rdCharLoc(a)], a.storage) else: - if etyp.kind == tyPtr: - # generates the definition of structs for casts like cast[ptr object](addr x)[] - let internalType = etyp.skipTypes({tyPtr}) - if internalType.kind == tyObject: - discard getTypeDesc(p.module, internalType) putIntoDest(p, d, e, "(($1) ($2))" % [getTypeDesc(p.module, e.typ), rdCharLoc(a)], a.storage) @@ -2220,53 +1936,21 @@ proc genCast(p: BProc, e: PNode, d: var TLoc) = # C code; plus it's the right thing to do for closures: genSomeCast(p, e, d) -proc genRangeChck(p: BProc, n: PNode, d: var TLoc) = +proc genRangeChck(p: BProc, n: PNode, d: var TLoc, magic: string) = var a: TLoc var dest = skipTypes(n.typ, abstractVar) - initLocExpr(p, n[0], a) if optRangeCheck notin p.options or (dest.kind in {tyUInt..tyUInt64} and checkUnsignedConversions notin p.config.legacyFeatures): - discard "no need to generate a check because it was disabled" + initLocExpr(p, n[0], a) + putIntoDest(p, d, n, "(($1) ($2))" % + [getTypeDesc(p.module, dest), rdCharLoc(a)], a.storage) else: - let n0t = n[0].typ - - # emit range check: - if n0t.kind in {tyUInt, tyUInt64}: - var first = newRopeAppender() - genLiteral(p, n[1], dest, first) - var last = newRopeAppender() - genLiteral(p, n[2], dest, last) - linefmt(p, cpsStmts, "if ($1 > ($5)($3)){ #raiseRangeErrorNoArgs(); ", - [rdCharLoc(a), first, last, - raiser, getTypeDesc(p.module, n0t)]) - raiseInstr(p, p.s(cpsStmts)) - linefmt p, cpsStmts, "}$n", [] - - else: - let raiser = - case skipTypes(n.typ, abstractVarRange).kind - of tyUInt..tyUInt64, tyChar: "raiseRangeErrorU" - of tyFloat..tyFloat128: "raiseRangeErrorF" - else: "raiseRangeErrorI" - cgsym(p.module, raiser) - - let boundaryCast = - if n0t.skipTypes(abstractVarRange).kind in {tyUInt, tyUInt32, tyUInt64}: - "(NI64)" - else: - "" - var first = newRopeAppender() - genLiteral(p, n[1], dest, first) - var last = newRopeAppender() - genLiteral(p, n[2], dest, last) - linefmt(p, cpsStmts, "if ($5($1) < $2 || $5($1) > $3){ $4($1, $2, $3); ", - [rdCharLoc(a), first, last, - raiser, boundaryCast]) - raiseInstr(p, p.s(cpsStmts)) - linefmt p, cpsStmts, "}$n", [] - - putIntoDest(p, d, n, "(($1) ($2))" % - [getTypeDesc(p.module, dest), rdCharLoc(a)], a.storage) + let mm = if dest.kind in {tyUInt32, tyUInt64, tyUInt}: "chckRangeU" else: magic + initLocExpr(p, n[0], a) + putIntoDest(p, d, lodeTyp dest, ropecg(p.module, "(($1)#$5($2, $3, $4))", [ + getTypeDesc(p.module, dest), rdCharLoc(a), + genLiteral(p, n[1], dest), genLiteral(p, n[2], dest), + mm]), a.storage) proc genConv(p: BProc, e: PNode, d: var TLoc) = let destType = e.typ.skipTypes({tyVar, tyLent, tyGenericInst, tyAlias, tySink}) @@ -2318,15 +2002,9 @@ proc binaryFloatArith(p: BProc, e: PNode, d: var TLoc, m: TMagic) = [opr[m], rdLoc(a), rdLoc(b), getSimpleTypeDesc(p.module, e[1].typ)])) if optNaNCheck in p.options: - linefmt(p, cpsStmts, "if ($1 != $1){ #raiseFloatInvalidOp(); ", [rdLoc(d)]) - raiseInstr(p, p.s(cpsStmts)) - linefmt p, cpsStmts, "}$n", [] - + linefmt(p, cpsStmts, "#nanCheck($1);$n", [rdLoc(d)]) if optInfCheck in p.options: - linefmt(p, cpsStmts, "if ($1 != 0.0 && $1*0.5 == $1) { #raiseFloatOverflow($1); ", [rdLoc(d)]) - raiseInstr(p, p.s(cpsStmts)) - linefmt p, cpsStmts, "}$n", [] - + linefmt(p, cpsStmts, "#infCheck($1);$n", [rdLoc(d)]) else: binaryArith(p, e, d, m) @@ -2335,14 +2013,10 @@ proc skipAddr(n: PNode): PNode = proc genWasMoved(p: BProc; n: PNode) = var a: TLoc - let n1 = n[1].skipAddr - if p.withinBlockLeaveActions > 0 and notYetAlive(n1): - discard - else: - 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)]) + initLocExpr(p, n[1].skipAddr, 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 @@ -2351,7 +2025,7 @@ proc genMove(p: BProc; n: PNode; d: var TLoc) = # generated by liftdestructors: var src: TLoc initLocExpr(p, n[2], src) - linefmt(p, cpsStmts, "if ($1.p != $2.p) {", [rdLoc(a), rdLoc(src)]) + linefmt(p, cpsStmts, "if ($1.len && $1.p != $2.p) {", [rdLoc(a), rdLoc(src)]) genStmts(p, n[3]) linefmt(p, cpsStmts, "}$n$1.len = $2.len; $1.p = $2.p;$n", [rdLoc(a), rdLoc(src)]) else: @@ -2367,26 +2041,21 @@ proc genDestroy(p: BProc; n: PNode) = of tyString: var a: TLoc initLocExpr(p, arg, a) - if optThreads in p.config.globalOptions: - linefmt(p, cpsStmts, "if ($1.p && !($1.p->cap & NIM_STRLIT_FLAG)) {$n" & - " #deallocShared($1.p);$n" & - "}$n", [rdLoc(a)]) - else: - linefmt(p, cpsStmts, "if ($1.p && !($1.p->cap & NIM_STRLIT_FLAG)) {$n" & - " #dealloc($1.p);$n" & - "}$n", [rdLoc(a)]) + linefmt(p, cpsStmts, "if ($1.p && !($1.p->cap & NIM_STRLIT_FLAG)) {$n" & + " #deallocShared($1.p);$n" & + " $1.p = NIM_NIL; }$n", + [rdLoc(a)]) of tySequence: var a: TLoc initLocExpr(p, arg, a) linefmt(p, cpsStmts, "if ($1.p && !($1.p->cap & NIM_STRLIT_FLAG)) {$n" & - " #alignedDealloc($1.p, NIM_ALIGNOF($2));$n" & - "}$n", + " #deallocShared($1.p);$n" & + " $1.p = NIM_NIL; }$n", [rdLoc(a), getTypeDesc(p.module, t.lastSon)]) else: discard "nothing to do" else: let t = n[1].typ.skipTypes(abstractVar) - let op = getAttachedOp(p.module.g.graph, t, attachedDestructor) - if op != nil and getBody(p.module.g.graph, op).len != 0: + if t.destructor != nil and t.destructor.ast[bodyPos].len != 0: internalError(p.config, n.info, "destructor turned out to be not trivial") discard "ignore calls to the default destructor" @@ -2401,31 +2070,42 @@ proc genDispose(p: BProc; n: PNode) = if elemType.destructor != nil: var destroyCall = newNodeI(nkCall, n.info) genStmts(p, destroyCall) - lineFmt(p, cpsStmts, "#nimRawDispose($1, NIM_ALIGNOF($2))", [rdLoc(a), getTypeDesc(p.module, elemType)]) + lineCg(p, cpsStmts, ["#nimRawDispose($#)", rdLoc(a)]) else: # ``nimRawDisposeVirtual`` calls the ``finalizer`` which is the same as the # destructor, but it uses the runtime type. Afterwards the memory is freed: 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, gcOrc}) - if d.k == locNone: getTemp(p, e.typ, d) - linefmt(p, cpsStmts, "$1.Field0 = $2; $1.Field1 = $3;$n", [rdLoc(d), x, y]) - when false: - localError(p.config, e.info, "invalid context for 'toOpenArray'; " & - "'toOpenArray' is only valid within a call expression") - proc genEnumToStr(p: BProc, e: PNode, d: var TLoc) = + const ToStringProcSlot = -4 let t = e[1].typ.skipTypes(abstractInst+{tyRange}) - let toStrProc = getToStringProc(p.module.g.graph, t) - # XXX need to modify this logic for IC. + var toStrProc: PSym = nil + for idx, p in items(t.methods): + if idx == ToStringProcSlot: + toStrProc = p + break + if toStrProc == nil: + toStrProc = genEnumToStrProc(t, e.info, p.module.g.graph) + t.methods.add((ToStringProcSlot, toStrProc)) var n = copyTree(e) n[0] = newSymNode(toStrProc) expr(p, n, d) +proc rdMType(p: BProc; a: TLoc; nilCheck: var Rope): Rope = + result = rdLoc(a) + var t = skipTypes(a.t, abstractInst) + while t.kind in {tyVar, tyLent, tyPtr, tyRef}: + if t.kind notin {tyVar, tyLent}: nilCheck = result + if t.kind notin {tyVar, tyLent} or not p.module.compileToCpp: + result = "(*$1)" % [result] + t = skipTypes(t.lastSon, abstractInst) + discard getTypeDesc(p.module, t) + if not p.module.compileToCpp: + while t.kind == tyObject and t[0] != nil: + result.add(".Sup") + t = skipTypes(t[0], skipPtrs) + result.add ".m_type" + proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) = case op of mOr, mAnd: genAndOr(p, e, d, op) @@ -2437,13 +2117,17 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) = of mAddI..mPred: binaryArithOverflow(p, e, d, op) of mRepr: genRepr(p, e, d) of mGetTypeInfo: genGetTypeInfo(p, e, d) - of mGetTypeInfoV2: genGetTypeInfoV2(p, e, d) of mSwap: genSwap(p, e, d) + of mUnaryLt: + if optOverflowCheck notin p.options: unaryExpr(p, e, d, "($1 - 1)") + else: unaryExpr(p, e, d, "#subInt($1, 1)") of mInc, mDec: const opr: array[mInc..mDec, string] = ["+=", "-="] - const fun64: array[mInc..mDec, string] = ["nimAddInt64", "nimSubInt64"] - const fun: array[mInc..mDec, string] = ["nimAddInt","nimSubInt"] - let underlying = skipTypes(e[1].typ, {tyGenericInst, tyAlias, tySink, tyVar, tyLent, tyRange, tyDistinct}) + const fun64: array[mInc..mDec, string] = ["addInt64", + "subInt64"] + const fun: array[mInc..mDec, string] = ["addInt", + "subInt"] + let underlying = skipTypes(e[1].typ, {tyGenericInst, tyAlias, tySink, tyVar, tyLent, tyRange}) if optOverflowCheck notin p.options or underlying.kind in {tyUInt..tyUInt64}: binaryStmt(p, e, d, opr[op]) else: @@ -2453,7 +2137,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) = initLocExpr(p, e[1], a) initLocExpr(p, e[2], b) - let ranged = skipTypes(e[1].typ, {tyGenericInst, tyAlias, tySink, tyVar, tyLent, tyDistinct}) + let ranged = skipTypes(e[1].typ, {tyGenericInst, tyAlias, tySink, tyVar, tyLent}) let res = binaryArithOverflowRaw(p, ranged, a, b, if underlying.kind == tyInt64: fun64[op] else: fun[op]) @@ -2474,7 +2158,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) = of mAppendStrStr: genStrAppend(p, e, d) of mAppendSeqElem: if optSeqDestructors in p.config.globalOptions: - e[1] = makeAddr(e[1], p.module.idgen) + e[1] = makeAddr(e[1]) genCall(p, e, d) else: genSeqElemAppend(p, e, d) @@ -2486,14 +2170,9 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) = of mInt64ToStr: genDollar(p, e, d, "#nimInt64ToStr($1)") of mBoolToStr: genDollar(p, e, d, "#nimBoolToStr($1)") of mCharToStr: genDollar(p, e, d, "#nimCharToStr($1)") - of mFloatToStr: - if e[1].typ.skipTypes(abstractInst).kind == tyFloat32: - genDollar(p, e, d, "#nimFloat32ToStr($1)") - else: - genDollar(p, e, d, "#nimFloatToStr($1)") + of mFloatToStr: genDollar(p, e, d, "#nimFloatToStr($1)") of mCStrToStr: genDollar(p, e, d, "#cstrToNimstr($1)") of mStrToStr, mUnown: expr(p, e[1], d) - of generatedMagics: genCall(p, e, d) of mEnumToStr: if optTinyRtti in p.config.globalOptions: genEnumToStr(p, e, d) @@ -2505,33 +2184,31 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) = if optTinyRtti in p.config.globalOptions: var a: TLoc initLocExpr(p, e[1], a) - rawGenNew(p, a, "", needsInit = true) + rawGenNew(p, a, nil, needsInit = true) gcUsage(p.config, e) else: genNewFinalize(p, e) - of mNewSeq: - if optSeqDestructors in p.config.globalOptions: - e[1] = makeAddr(e[1], p.module.idgen) - genCall(p, e, d) - else: - genNewSeq(p, e) + of mNewSeq: genNewSeq(p, e) 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, skVar)]) + putIntoDest(p, d, e, "((NI)sizeof($1))" % [getTypeDesc(p.module, t)]) of mAlignOf: let t = e[1].typ.skipTypes({tyTypeDesc}) - putIntoDest(p, d, e, "((NI)NIM_ALIGNOF($1))" % [getTypeDesc(p.module, t, skVar)]) + if not p.module.compileToCpp: + p.module.includeHeader("") + putIntoDest(p, d, e, "((NI)alignof($1))" % [getTypeDesc(p.module, t)]) of mOffsetOf: var dotExpr: PNode - if e[1].kind == nkDotExpr: - dotExpr = e[1] - elif e[1].kind == nkCheckedFieldExpr: - dotExpr = e[1][0] - else: - internalError(p.config, e.info, "unknown ast") + block findDotExpr: + if e[1].kind == nkDotExpr: + dotExpr = e[1] + elif e[1].kind == nkCheckedFieldExpr: + dotExpr = e[1][0] + else: + internalError(p.config, e.info, "unknown ast") let t = dotExpr[0].typ.skipTypes({tyTypeDesc}) - let tname = getTypeDesc(p.module, t, skVar) + let tname = getTypeDesc(p.module, t) let member = if t.kind == tyTuple: "Field" & rope(dotExpr[1].sym.position) @@ -2541,6 +2218,21 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) = of mOrd: genOrd(p, e, d) of mLengthArray, mHigh, mLengthStr, mLengthSeq, mLengthOpenArray: genArrayLen(p, e, d, op) + of mXLenStr: + if not p.module.compileToCpp: + unaryExpr(p, e, d, "($1->Sup.len)") + else: + unaryExpr(p, e, d, "$1->len") + of mXLenSeq: + # see 'taddhigh.nim' for why we need to use a temporary here: + var a, tmp: TLoc + initLocExpr(p, e[1], a) + getIntTemp(p, tmp) + if not p.module.compileToCpp: + lineCg(p, cpsStmts, "$1 = $2->Sup.len;$n", [tmp.r, rdLoc(a)]) + else: + lineCg(p, cpsStmts, "$1 = $2->len;$n", [tmp.r, rdLoc(a)]) + putIntoDest(p, d, e, tmp.r) of mGCref: unaryStmt(p, e, d, "if ($1) { #nimGCref($1); }$n") of mGCunref: unaryStmt(p, e, d, "if ($1) { #nimGCunref($1); }$n") of mSetLengthStr: genSetLengthStr(p, e, d) @@ -2548,6 +2240,8 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) = of mIncl, mExcl, mCard, mLtSet, mLeSet, mEqSet, mMulSet, mPlusSet, mMinusSet, mInSet: genSetOp(p, e, d, op) + of mCopyStr, mCopyStrLast: + genCall(p, e, d) of mNewString, mNewStringOfCap, mExit, mParseBiggestFloat: var opr = e[0].sym # Why would anyone want to set nodecl to one of these hardcoded magics? @@ -2555,7 +2249,6 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) = # somehow forward-declared from some other usage, but it is *possible* if lfNoDecl notin opr.loc.flags: let prc = magicsys.getCompilerProc(p.module.g.graph, $opr.loc.r) - assert prc != nil, $opr.loc.r # HACK: # Explicitly add this proc as declared here so the cgsym call doesn't # add a forward declaration - without this we could end up with the same @@ -2568,13 +2261,13 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) = let wasDeclared = containsOrIncl(p.module.declaredProtos, prc.id) # Make the function behind the magic get actually generated - this will # not lead to a forward declaration! The genCall will lead to one. - cgsym(p.module, $opr.loc.r) + discard cgsym(p.module, $opr.loc.r) # make sure we have pointer-initialising code for hot code reloading if not wasDeclared and p.hcrOn: p.module.s[cfsDynLibInit].addf("\t$1 = ($2) hcrGetProc($3, \"$1\");$n", [mangleDynLibProc(prc), getTypeDesc(p.module, prc.loc.t), getModuleDllPath(p.module, prc)]) genCall(p, e, d) - of mDefault, mZeroDefault: genDefault(p, e, d) + of mDefault: genDefault(p, e, d) of mReset: genReset(p, e) of mEcho: genEcho(p, e[1].skipConv) of mArrToSeq: genArrToSeq(p, e, d) @@ -2582,21 +2275,17 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) = localError(p.config, e.info, strutils.`%`(errXMustBeCompileTime, e[0].sym.name.s)) of mSpawn: when defined(leanCompiler): - p.config.quitOrRaise "compiler built without support for the 'spawn' statement" + quit "compiler built without support for the 'spawn' statement" else: - let n = spawn.wrapProcForSpawn(p.module.g.graph, p.module.idgen, p.module.module, e, e.typ, nil, nil) + let n = spawn.wrapProcForSpawn(p.module.g.graph, p.module.module, e, e.typ, nil, nil) expr(p, n, d) of mParallel: when defined(leanCompiler): - p.config.quitOrRaise "compiler built without support for the 'parallel' statement" + quit "compiler built without support for the 'parallel' statement" else: - let n = semparallel.liftParallel(p.module.g.graph, p.module.idgen, p.module.module, e) + let n = semparallel.liftParallel(p.module.g.graph, p.module.module, e) expr(p, n, d) of mDeepCopy: - if p.config.selectedGC in {gcArc, gcOrc} and optEnableDeepCopy notin p.config.globalOptions: - localError(p.config, e.info, - "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] initLocExpr(p, x, a) @@ -2607,9 +2296,14 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) = of mMove: genMove(p, e, d) of mDestroy: genDestroy(p, e) of mAccessEnv: unaryExpr(p, e, d, "$1.ClE_0") - of mAccessTypeField: genAccessTypeField(p, e, d) - of mSlice: genSlice(p, e, d) - of mTrace: discard "no code to generate" + of mAccessTypeInfo: + var a: TLoc + var dummy: Rope + initLocExpr(p, e[1], a) + putIntoDest(p, d, e, rdMType(p, a, dummy)) + of mSlice: + localError(p.config, e.info, "invalid context for 'toOpenArray'; " & + "'toOpenArray' is only valid within a call expression") else: when defined(debugMagics): echo p.prc.name.s, " ", p.prc.id, " ", p.prc.flags, " ", p.prc.ast[genericParamsPos].kind @@ -2623,9 +2317,7 @@ proc genSetConstr(p: BProc, e: PNode, d: var TLoc) = var a, b, idx: TLoc if nfAllConst in e.flags: - var elem = newRopeAppender() - genSetNode(p, e, elem) - putIntoDest(p, d, e, elem) + putIntoDest(p, d, e, genSetNode(p, e)) else: if d.k == locNone: getTemp(p, e.typ, d) if getSize(p.config, e.typ) > 8: @@ -2637,19 +2329,13 @@ proc genSetConstr(p: BProc, e: PNode, d: var TLoc) = getTemp(p, getSysType(p.module.g.graph, unknownLineInfo, tyInt), idx) # our counter initLocExpr(p, it[0], a) initLocExpr(p, it[1], b) - var aa = newRopeAppender() - rdSetElemLoc(p.config, a, e.typ, aa) - var bb = newRopeAppender() - rdSetElemLoc(p.config, b, e.typ, bb) lineF(p, cpsStmts, "for ($1 = $3; $1 <= $4; $1++) $n" & "$2[(NU)($1)>>3] |=(1U<<((NU)($1)&7U));$n", [rdLoc(idx), rdLoc(d), - aa, bb]) + rdSetElemLoc(p.config, a, e.typ), rdSetElemLoc(p.config, b, e.typ)]) else: initLocExpr(p, it, a) - var aa = newRopeAppender() - rdSetElemLoc(p.config, a, e.typ, aa) lineF(p, cpsStmts, "$1[(NU)($2)>>3] |=(1U<<((NU)($2)&7U));$n", - [rdLoc(d), aa]) + [rdLoc(d), rdSetElemLoc(p.config, a, e.typ)]) else: # small set var ts = "NU" & $(getSize(p.config, e.typ) * 8) @@ -2659,21 +2345,15 @@ proc genSetConstr(p: BProc, e: PNode, d: var TLoc) = getTemp(p, getSysType(p.module.g.graph, unknownLineInfo, tyInt), idx) # our counter initLocExpr(p, it[0], a) initLocExpr(p, it[1], b) - var aa = newRopeAppender() - rdSetElemLoc(p.config, a, e.typ, aa) - var bb = newRopeAppender() - rdSetElemLoc(p.config, b, e.typ, bb) - lineF(p, cpsStmts, "for ($1 = $3; $1 <= $4; $1++) $n" & "$2 |=(($5)(1)<<(($1)%(sizeof($5)*8)));$n", [ - rdLoc(idx), rdLoc(d), aa, bb, rope(ts)]) + rdLoc(idx), rdLoc(d), rdSetElemLoc(p.config, a, e.typ), + rdSetElemLoc(p.config, b, e.typ), rope(ts)]) else: initLocExpr(p, it, a) - var aa = newRopeAppender() - rdSetElemLoc(p.config, a, e.typ, aa) lineF(p, cpsStmts, "$1 |=(($3)(1)<<(($2)%(sizeof($3)*8)));$n", - [rdLoc(d), aa, rope(ts)]) + [rdLoc(d), rdSetElemLoc(p.config, a, e.typ), rope(ts)]) proc genTupleConstr(p: BProc, n: PNode, d: var TLoc) = var rec: TLoc @@ -2699,10 +2379,8 @@ proc genClosure(p: BProc, n: PNode, d: var TLoc) = if isConstClosure(n): inc(p.module.labels) var tmp = "CNSTCLOSURE" & rope(p.module.labels) - var data = "static NIM_CONST $1 $2 = " % [getTypeDesc(p.module, n.typ), tmp] - genBracedInit(p, n, isConst = true, n.typ, data) - data.addf(";$n", []) - p.module.s[cfsData].add data + p.module.s[cfsData].addf("static NIM_CONST $1 $2 = $3;$n", + [getTypeDesc(p.module, n.typ), tmp, genBracedInit(p, n, isConst = true)]) putIntoDest(p, d, n, tmp, OnStatic) else: var tmp, a, b: TLoc @@ -2727,14 +2405,12 @@ proc genArrayConstr(p: BProc, n: PNode, d: var TLoc) = if d.k == locNone: getTemp(p, n.typ, d) for i in 0.. 0: exprOrStmt - if frameName != "": + if frameName != nil: p.s(cpsStmts).add deinitFrameNoDebug(p, frameName) proc genStmtListExpr(p: BProc, n: PNode, d: var TLoc) = @@ -2767,74 +2443,65 @@ proc genStmtList(p: BProc, n: PNode) = genStmtListExprImpl: genStmts(p, n[^1]) -from parampatterns import isLValue - proc upConv(p: BProc, n: PNode, d: var TLoc) = var a: TLoc initLocExpr(p, n[0], a) let dest = skipTypes(n.typ, abstractPtrs) if optObjCheck in p.options and not isObjLackingTypeField(dest): - var nilCheck = "" - var r = newRopeAppender() - rdMType(p, a, nilCheck, r) - if optTinyRtti in p.config.globalOptions: - let checkFor = $getObjDepth(dest) - let token = $genDisplayElem(MD5Digest(hashType(dest, p.config))) - if nilCheck != "": - linefmt(p, cpsStmts, "if ($1 && !#isObjDisplayCheck($2, $3, $4)){ #raiseObjectConversionError(); ", - [nilCheck, r, checkFor, token]) - else: - linefmt(p, cpsStmts, "if (!#isObjDisplayCheck($1, $2, $3)){ #raiseObjectConversionError(); ", - [r, checkFor, token]) + var nilCheck = Rope(nil) + let r = rdMType(p, a, nilCheck) + let checkFor = if optTinyRtti in p.config.globalOptions: + genTypeInfo2Name(p.module, dest) + else: + genTypeInfo(p.module, dest, n.info) + if nilCheck != nil: + linefmt(p, cpsStmts, "if ($1) #chckObj($2, $3);$n", + [nilCheck, r, checkFor]) else: - let checkFor = genTypeInfoV1(p.module, dest, n.info) - if nilCheck != "": - linefmt(p, cpsStmts, "if ($1 && !#isObj($2, $3)){ #raiseObjectConversionError(); ", - [nilCheck, r, checkFor]) - else: - linefmt(p, cpsStmts, "if (!#isObj($1, $2)){ #raiseObjectConversionError(); ", - [r, checkFor]) - raiseInstr(p, p.s(cpsStmts)) - linefmt p, cpsStmts, "}$n", [] - + linefmt(p, cpsStmts, "#chckObj($1, $2);$n", + [r, checkFor]) if n[0].typ.kind != tyObject: - if n.isLValue: - putIntoDest(p, d, n, - "(*(($1*) (&($2))))" % [getTypeDesc(p.module, n.typ), rdLoc(a)], a.storage) - else: - putIntoDest(p, d, n, + putIntoDest(p, d, n, "(($1) ($2))" % [getTypeDesc(p.module, n.typ), rdLoc(a)], a.storage) else: putIntoDest(p, d, n, "(*($1*) ($2))" % [getTypeDesc(p.module, dest), addrLoc(p.config, a)], a.storage) proc downConv(p: BProc, n: PNode, d: var TLoc) = - var arg = n[0] - while arg.kind == nkObjDownConv: arg = arg[0] - - let dest = skipTypes(n.typ, abstractPtrs) - let src = skipTypes(arg.typ, abstractPtrs) - discard getTypeDesc(p.module, src) - let isRef = skipTypes(arg.typ, abstractInstOwned).kind in {tyRef, tyPtr, tyVar, tyLent} - if isRef and d.k == locNone and n.typ.skipTypes(abstractInstOwned).kind in {tyRef, tyPtr} and n.isLValue: - # it can happen that we end up generating '&&x->Sup' here, so we pack - # the '&x->Sup' into a temporary and then those address is taken - # (see bug #837). However sometimes using a temporary is not correct: - # init(TFigure(my)) # where it is passed to a 'var TFigure'. We test - # this by ensuring the destination is also a pointer: - var a: TLoc - initLocExpr(p, arg, a) - putIntoDest(p, d, n, - "(*(($1*) (&($2))))" % [getTypeDesc(p.module, n.typ), rdLoc(a)], a.storage) - elif p.module.compileToCpp: - # C++ implicitly downcasts for us - expr(p, arg, d) + if p.module.compileToCpp: + discard getTypeDesc(p.module, skipTypes(n[0].typ, abstractPtrs)) + expr(p, n[0], d) # downcast does C++ for us else: + var dest = skipTypes(n.typ, abstractPtrs) + + var arg = n[0] + while arg.kind == nkObjDownConv: arg = arg[0] + + var src = skipTypes(arg.typ, abstractPtrs) + discard getTypeDesc(p.module, src) var a: TLoc initLocExpr(p, arg, a) - var r = rdLoc(a) & (if isRef: "->Sup" else: ".Sup") + var r = rdLoc(a) + let isRef = skipTypes(arg.typ, abstractInstOwned).kind in {tyRef, tyPtr, tyVar, tyLent} + if isRef: + r.add("->Sup") + else: + r.add(".Sup") for i in 2..abs(inheritanceDiff(dest, src)): r.add(".Sup") - putIntoDest(p, d, n, if isRef: "&" & r else: r, a.storage) + if isRef: + # it can happen that we end up generating '&&x->Sup' here, so we pack + # the '&x->Sup' into a temporary and then those address is taken + # (see bug #837). However sometimes using a temporary is not correct: + # init(TFigure(my)) # where it is passed to a 'var TFigure'. We test + # this by ensuring the destination is also a pointer: + if d.k == locNone and skipTypes(n.typ, abstractInstOwned).kind in {tyRef, tyPtr, tyVar, tyLent}: + getTemp(p, n.typ, d) + linefmt(p, cpsStmts, "$1 = &$2;$n", [rdLoc(d), r]) + else: + r = "&" & r + putIntoDest(p, d, n, r, a.storage) + else: + putIntoDest(p, d, n, r, a.storage) proc exprComplexConst(p: BProc, n: PNode, d: var TLoc) = let t = n.typ @@ -2845,10 +2512,8 @@ proc exprComplexConst(p: BProc, n: PNode, d: var TLoc) = if id == p.module.labels: # expression not found in the cache: inc(p.module.labels) - p.module.s[cfsData].addf("static NIM_CONST $1 $2 = ", - [getTypeDesc(p.module, t, skConst), tmp]) - genBracedInit(p, n, isConst = true, t, p.module.s[cfsData]) - p.module.s[cfsData].addf(";$n", []) + p.module.s[cfsData].addf("static NIM_CONST $1 $2 = $3;$n", + [getTypeDesc(p.module, t), tmp, genBracedInit(p, n, isConst = true)]) if d.k == locNone: fillLoc(d, locData, n, tmp, OnStatic) @@ -2859,66 +2524,7 @@ proc exprComplexConst(p: BProc, n: PNode, d: var TLoc) = if t.kind notin {tySequence, tyString}: d.storage = OnStatic -proc genConstSetup(p: BProc; sym: PSym): bool = - let m = p.module - useHeader(m, sym) - if sym.loc.k == locNone: - fillBackendName(p.module, sym) - fillLoc(sym.loc, locData, sym.astdef, OnStatic) - if m.hcrOn: incl(sym.loc.flags, lfIndirect) - result = lfNoDecl notin sym.loc.flags - -proc genConstHeader(m, q: BModule; p: BProc, sym: PSym) = - if sym.loc.r == "": - 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, skVar), sym.loc.r]); - m.initProc.procSec(cpsLocals).addf( - "\t$1 = ($2*)hcrGetGlobal($3, \"$1\");$n", [sym.loc.r, - getTypeDesc(m, sym.loc.t, skVar), getModuleDllPath(q, sym)]) - else: - let headerDecl = "extern NIM_CONST $1 $2;$n" % - [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) - -proc genConstDefinition(q: BModule; p: BProc; sym: PSym) = - # add a suffix for hcr - will later init the global pointer with this data - let actualConstName = if q.hcrOn: sym.loc.r & "_const" else: sym.loc.r - var data = newRopeAppender() - data.addf("N_LIB_PRIVATE NIM_CONST $1 $2 = ", - [getTypeDesc(q, sym.typ), actualConstName]) - genBracedInit(q.initProc, sym.astdef, isConst = true, sym.typ, data) - data.addf(";$n", []) - 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, 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", - [getModuleDllPath(q, sym), sym.loc.r, rdLoc(sym.loc)]) - # always copy over the contents of the actual constant with the _const - # suffix ==> this means that the constant is reloadable & updatable! - q.initProc.procSec(cpsLocals).add(ropecg(q, - "\t#nimCopyMem((void*)$1, (NIM_CONST void*)&$2, sizeof($3));$n", - [sym.loc.r, actualConstName, rdLoc(sym.loc)])) - -proc genConstStmt(p: BProc, n: PNode) = - # This code is only used in the new DCE implementation. - assert useAliveDataFromDce in p.module.flags - let m = p.module - for it in n: - if it[0].kind == nkSym: - let sym = it[0].sym - if not isSimpleConst(sym.typ) and sym.itemId.item in m.alive and genConstSetup(p, sym): - genConstDefinition(m, p, sym) - proc expr(p: BProc, n: PNode, d: var TLoc) = - when defined(nimCompilerStacktraceHints): - setFrameMsg p.config$n.info & " " & $n.kind p.currLineInfo = n.info case n.kind @@ -2926,7 +2532,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) = var sym = n.sym case sym.kind of skMethod: - if useAliveDataFromDce in p.module.flags or {sfDispatcher, sfForward} * sym.flags != {}: + if {sfDispatcher, sfForward} * sym.flags != {}: # we cannot produce code for the dispatcher yet: fillProcLoc(p.module, n) genProcPrototype(p.module, sym) @@ -2939,23 +2545,13 @@ proc expr(p: BProc, n: PNode, d: var TLoc) = if sfCompileTime in sym.flags: localError(p.config, n.info, "request to generate code for .compileTime proc: " & sym.name.s) - if useAliveDataFromDce in p.module.flags and sym.typ.callConv != ccInline: - fillProcLoc(p.module, n) - genProcPrototype(p.module, sym) - else: - genProc(p.module, sym) - if sym.loc.r == "" or sym.loc.lode == nil: + genProc(p.module, sym) + if sym.loc.r == nil or sym.loc.lode == nil: internalError(p.config, n.info, "expr: proc not init " & sym.name.s) putLocIntoDest(p, d, sym.loc) of skConst: if isSimpleConst(sym.typ): - var lit = newRopeAppender() - genLiteral(p, sym.astdef, sym.typ, lit) - putIntoDest(p, d, n, lit, OnStatic) - elif useAliveDataFromDce in p.module.flags: - genConstHeader(p.module, p.module, p, sym) - assert((sym.loc.r != "") and (sym.loc.t != nil)) - putLocIntoDest(p, d, sym.loc) + putIntoDest(p, d, n, genLiteral(p, sym.ast, sym.typ), OnStatic) else: genComplexConst(p, sym, d) of skEnumField: @@ -2969,7 +2565,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) = if sfCompileTime in sym.flags: genSingleVar(p, sym, n, astdef(sym)) - if sym.loc.r == "" or sym.loc.t == nil: + if sym.loc.r == nil or sym.loc.t == nil: #echo "FAILED FOR PRCO ", p.prc.name.s #echo renderTree(p.prc.ast, {renderIds}) internalError p.config, n.info, "expr: var not init " & sym.name.s & "_" & $sym.id @@ -2982,19 +2578,13 @@ proc expr(p: BProc, n: PNode, d: var TLoc) = else: putLocIntoDest(p, d, sym.loc) of skTemp: - when false: - # this is more harmful than helpful. - if sym.loc.r == "": - # we now support undeclared 'skTemp' variables for easier - # transformations in other parts of the compiler: - assignLocalVar(p, n) - if sym.loc.r == "" or sym.loc.t == nil: + if sym.loc.r == nil or sym.loc.t == nil: #echo "FAILED FOR PRCO ", p.prc.name.s #echo renderTree(p.prc.ast, {renderIds}) internalError(p.config, n.info, "expr: temp not init " & sym.name.s & "_" & $sym.id) putLocIntoDest(p, d, sym.loc) of skParam: - if sym.loc.r == "" or sym.loc.t == nil: + if sym.loc.r == nil or sym.loc.t == nil: # echo "FAILED FOR PRCO ", p.prc.name.s # debug p.prc.typ.n # echo renderTree(p.prc.ast, {renderIds}) @@ -3003,17 +2593,12 @@ proc expr(p: BProc, n: PNode, d: var TLoc) = else: internalError(p.config, n.info, "expr(" & $sym.kind & "); unknown symbol") of nkNilLit: if not isEmptyType(n.typ): - var lit = newRopeAppender() - genLiteral(p, n, lit) - putIntoDest(p, d, n, lit) + putIntoDest(p, d, n, genLiteral(p, n)) of nkStrLit..nkTripleStrLit: - var lit = newRopeAppender() - genLiteral(p, n, lit) - putDataIntoDest(p, d, n, lit) - of nkIntLit..nkUInt64Lit, nkFloatLit..nkFloat128Lit, nkCharLit: - var lit = newRopeAppender() - genLiteral(p, n, lit) - putIntoDest(p, d, n, lit) + putDataIntoDest(p, d, n, genLiteral(p, n)) + of nkIntLit..nkUInt64Lit, + nkFloatLit..nkFloat128Lit, nkCharLit: + putIntoDest(p, d, n, genLiteral(p, n)) of nkCall, nkHiddenCallConv, nkInfix, nkPrefix, nkPostfix, nkCommand, nkCallStrLit: genLineDir(p, n) # may be redundant, it is generated in fixupCall as well @@ -3033,9 +2618,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) = genCall(p, n, d) of nkCurly: if isDeepConstExpr(n) and n.len != 0: - var lit = newRopeAppender() - genSetNode(p, n, lit) - putIntoDest(p, d, n, lit) + putIntoDest(p, d, n, genSetNode(p, n)) else: genSetConstr(p, n, d) of nkBracket: @@ -3055,16 +2638,7 @@ 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 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 nkHiddenAddr, nkAddr: genAddr(p, n, d) of nkBracketExpr: genBracketExpr(p, n, d) of nkDerefExpr, nkHiddenDeref: genDeref(p, n, d) of nkDotExpr: genRecordField(p, n, d) @@ -3078,13 +2652,15 @@ proc expr(p: BProc, n: PNode, d: var TLoc) = expr(p, n[1][0], d) of nkObjDownConv: downConv(p, n, d) of nkObjUpConv: upConv(p, n, d) - of nkChckRangeF, nkChckRange64, nkChckRange: genRangeChck(p, n, d) + of nkChckRangeF: genRangeChck(p, n, d, "chckRangeF") + of nkChckRange64: genRangeChck(p, n, d, "chckRange64") + of nkChckRange: genRangeChck(p, n, d, "chckRange") of nkStringToCString: convStrToCStr(p, n, d) of nkCStringToString: convCStrToStr(p, n, d) of nkLambdaKinds: var sym = n[namePos].sym genProc(p.module, sym) - if sym.loc.r == "" or sym.loc.lode == nil: + if sym.loc.r == nil or sym.loc.lode == nil: internalError(p.config, n.info, "expr: proc not init " & sym.name.s) putLocIntoDest(p, d, sym.loc) of nkClosure: genClosure(p, n, d) @@ -3092,20 +2668,15 @@ proc expr(p: BProc, n: PNode, d: var TLoc) = of nkEmpty: discard of nkWhileStmt: genWhileStmt(p, n) of nkVarSection, nkLetSection: genVarStmt(p, n) - of nkConstSection: - if useAliveDataFromDce in p.module.flags: - genConstStmt(p, n) - # else: consts generated lazily on use + of nkConstSection: discard # consts generated lazily on use of nkForStmt: internalError(p.config, n.info, "for statement not eliminated") of nkCaseStmt: genCase(p, n, d) of nkReturnStmt: genReturnStmt(p, n) of nkBreakStmt: genBreakStmt(p, n) of nkAsgn: - cow(p, n[1]) if nfPreventCg notin n.flags: genAsgn(p, n, fastAsgn=false) - of nkFastAsgn, nkSinkAsgn: - cow(p, n[1]) + of nkFastAsgn: if nfPreventCg notin n.flags: # transf is overly aggressive with 'nkFastAsgn', so we work around here. # See tests/run/tcnstseq3 for an example that would fail otherwise. @@ -3136,35 +2707,17 @@ proc expr(p: BProc, n: PNode, d: var TLoc) = nkFromStmt, nkTemplateDef, nkMacroDef, nkStaticStmt: discard of nkPragma: genPragma(p, n) - 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 - - inc p.inUncheckedAssignSection, inUncheckedAssignSection - expr(p, n.lastSon, d) - dec p.inUncheckedAssignSection, inUncheckedAssignSection - + of nkPragmaBlock: expr(p, n.lastSon, d) of nkProcDef, nkFuncDef, nkMethodDef, nkConverterDef: if n[genericParamsPos].kind == nkEmpty: var prc = n[namePos].sym - if useAliveDataFromDce in p.module.flags: - if p.module.alive.contains(prc.itemId.item) and - prc.magic in generatedMagics: - genProc(p.module, prc) - elif prc.skipGenericOwner.kind == skModule and sfCompileTime notin prc.flags: + # due to a bug/limitation in the lambda lifting, unused inner procs + # are not transformed correctly. We work around this issue (#411) here + # by ensuring it's no inner proc (owner is a module): + if prc.skipGenericOwner.kind == skModule and sfCompileTime notin prc.flags: if ({sfExportc, sfCompilerProc} * prc.flags == {sfExportc}) or (sfExportc in prc.flags and lfExportLib in prc.loc.flags) or (prc.kind == skMethod): - # due to a bug/limitation in the lambda lifting, unused inner procs - # are not transformed correctly. We work around this issue (#411) here - # by ensuring it's no inner proc (owner is a module). # Generate proc even if empty body, bugfix #11651. genProc(p.module, prc) of nkParForStmt: genParForStmt(p, n) @@ -3174,76 +2727,55 @@ proc expr(p: BProc, n: PNode, d: var TLoc) = inc p.splitDecls genGotoState(p, n) of nkBreakState: genBreakState(p, n, d) - of nkMixinStmt, nkBindStmt: discard else: internalError(p.config, n.info, "expr(" & $n.kind & "); unknown node kind") -proc getDefaultValue(p: BProc; typ: PType; info: TLineInfo; result: var Rope) = +proc genNamedConstExpr(p: BProc, n: PNode; isConst: bool): Rope = + if n.kind == nkExprColonExpr: result = genBracedInit(p, n[1], isConst) + else: result = genBracedInit(p, n, isConst) + +proc getDefaultValue(p: BProc; typ: PType; info: TLineInfo): Rope = var t = skipTypes(typ, abstractRange+{tyOwned}-{tyTypeDesc}) case t.kind - of tyBool: result.add rope"NIM_FALSE" - of tyEnum, tyChar, tyInt..tyInt64, tyUInt..tyUInt64: result.add rope"0" - of tyFloat..tyFloat128: result.add rope"0.0" - of tyCstring, tyVar, tyLent, tyPointer, tyPtr, tyUntyped, + of tyBool: result = rope"NIM_FALSE" + of tyEnum, tyChar, tyInt..tyInt64, tyUInt..tyUInt64: result = rope"0" + of tyFloat..tyFloat128: result = rope"0.0" + of tyCString, tyVar, tyLent, tyPointer, tyPtr, tyUntyped, tyTyped, tyTypeDesc, tyStatic, tyRef, tyNil: - result.add rope"NIM_NIL" + result = rope"NIM_NIL" of tyString, tySequence: if optSeqDestructors in p.config.globalOptions: - result.add "{0, NIM_NIL}" + result = rope"{0, NIM_NIL}" else: - result.add "NIM_NIL" + result = rope"NIM_NIL" of tyProc: if t.callConv != ccClosure: - result.add "NIM_NIL" + result = rope"NIM_NIL" else: - result.add "{NIM_NIL, NIM_NIL}" + result = rope"{NIM_NIL, NIM_NIL}" of tyObject: var count = 0 result.add "{" getNullValueAuxT(p, t, t, t.n, nil, result, count, true, info) result.add "}" of tyTuple: - result.add "{" - if p.vccAndC and t.len == 0: - result.add "0" + result = rope"{" for i in 0.. 0: result.add ", " - getDefaultValue(p, t[i], info, result) + result.add getDefaultValue(p, t[i], info) result.add "}" of tyArray: - result.add "{" + result = rope"{" for i in 0.. 0: result.add ", " - getDefaultValue(p, t.sons[1], info, result) + result.add getDefaultValue(p, t.sons[1], info) result.add "}" #result = rope"{}" - of tyOpenArray, tyVarargs: - result.add "{NIM_NIL, 0}" of tySet: - if mapSetType(p.config, t) == ctArray: result.add "{}" - else: result.add "0" + if mapType(p.config, t) == ctArray: result = rope"{}" + else: result = rope"0" else: globalError(p.config, info, "cannot create null element for: " & $t.kind) -proc caseObjDefaultBranch(obj: PNode; branch: Int128): int = - for i in 1 ..< obj.len: - for j in 0 .. obj[i].len - 2: - if obj[i][j].kind == nkRange: - let x = getOrdValue(obj[i][j][0]) - let y = getOrdValue(obj[i][j][1]) - if branch >= x and branch <= y: - return i - elif getOrdValue(obj[i][j]) == branch: - return i - if obj[i].len == 1: - # else branch - return i - assert(false, "unreachable") - -proc isEmptyCaseObjectBranch(n: PNode): bool = - for it in n: - if it.kind == nkSym and not isEmptyType(it.sym.typ): return false - return true - proc getNullValueAux(p: BProc; t: PType; obj, constOrNil: PNode, result: var Rope; count: var int; isConst: bool, info: TLineInfo) = @@ -3266,14 +2798,31 @@ proc getNullValueAux(p: BProc; t: PType; obj, constOrNil: PNode, branch = getOrdValue(constOrNil[i]) break - let selectedBranch = caseObjDefaultBranch(obj, branch) + var selectedBranch = -1 + block branchSelection: + for i in 1 ..< obj.len: + for j in 0 .. obj[i].len - 2: + if obj[i][j].kind == nkRange: + let x = getOrdValue(obj[i][j][0]) + let y = getOrdValue(obj[i][j][1]) + if branch >= x and branch <= y: + selectedBranch = i + break branchSelection + elif getOrdValue(obj[i][j]) == branch: + selectedBranch = i + break branchSelection + if obj[i].len == 1: + # else branch + selectedBranch = i + assert(selectedBranch >= 1) + 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): - result.add "._" & mangleRecFieldName(p.module, obj[0].sym) & "_" & $selectedBranch & " = {" + if b.kind == nkRecList and b.len > 0: + result.add "._" & mangleRecFieldName(p.module, obj[0].sym) & "_" & $selectedBranch & " = {" getNullValueAux(p, t, b, constOrNil, result, countB, isConst, info) result.add "}" elif b.kind == nkSym: @@ -3288,15 +2837,14 @@ proc getNullValueAux(p: BProc; t: PType; obj, constOrNil: PNode, if constOrNil != nil: for i in 1.. 0: result.add ",\n" - if it.kind == nkExprColonExpr: genBracedInit(p, it[1], isConst, it[0].typ, result) - else: genBracedInit(p, it, isConst, it.typ, result) - result.add("}\n") +proc genConstSimpleList(p: BProc, n: PNode; isConst: bool): Rope = + result = rope("{") + for i in 0.. 0: + result.add(genNamedConstExpr(p, n[^1], isConst)) + result.addf("}$n", []) -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.. 0: result.add ",\n" - if it.kind == nkExprColonExpr: genBracedInit(p, it[1], isConst, tup[i], result) - else: genBracedInit(p, it, isConst, tup[i], result) - result.add("}\n") - -proc genConstSeq(p: BProc, n: PNode, t: PType; isConst: bool; result: var Rope) = +proc genConstSeq(p: BProc, n: PNode, t: PType; isConst: bool): Rope = var data = "{{$1, $1 | NIM_STRLIT_FLAG}" % [n.len.rope] - let base = t.skipTypes(abstractInst)[0] if n.len > 0: # array part needs extra curlies: data.add(", {") for i in 0.. 0: data.addf(",$n", []) - genBracedInit(p, n[i], isConst, base, data) + data.add genBracedInit(p, n[i], isConst) data.add("}") data.add("}") - let tmpName = getTempName(p.module) + result = getTempName(p.module) + let base = t.skipTypes(abstractInst)[0] - appcg(p.module, cfsStrData, + appcg(p.module, cfsData, "static $5 struct {$n" & " #TGenericSeq Sup;$n" & " $1 data[$2];$n" & "} $3 = $4;$n", [ - getTypeDesc(p.module, base), n.len, tmpName, data, + getTypeDesc(p.module, base), n.len, result, data, if isConst: "NIM_CONST" else: ""]) - result.add "(($1)&$2)" % [getTypeDesc(p.module, t), tmpName] + result = "(($1)&$2)" % [getTypeDesc(p.module, t), result] -proc genConstSeqV2(p: BProc, n: PNode, t: PType; isConst: bool; result: var Rope) = - let base = t.skipTypes(abstractInst)[0] +proc genConstSeqV2(p: BProc, n: PNode, t: PType; isConst: bool): Rope = var data = rope"{" for i in 0.. 0: data.addf(",$n", []) - genBracedInit(p, n[i], isConst, base, data) + data.add genBracedInit(p, n[i], isConst) data.add("}") let payload = getTempName(p.module) + let base = t.skipTypes(abstractInst)[0] - appcg(p.module, cfsStrData, + appcg(p.module, cfsData, "static $5 struct {$n" & " NI cap; $1 data[$2];$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] + result = "{$1, ($2*)&$3}" % [rope(n.len), getSeqPayloadType(p.module, t), payload] -proc genBracedInit(p: BProc, n: PNode; isConst: bool; optionalType: PType; result: var Rope) = +proc genBracedInit(p: BProc, n: PNode; isConst: bool): Rope = case n.kind of nkHiddenStdConv, nkHiddenSubConv: - genBracedInit(p, n[1], isConst, n.typ, result) + result = genBracedInit(p, n[1], isConst) else: var ty = tyNone - var typ: PType = nil - if optionalType == nil: + if n.typ == nil: if n.kind in nkStrKinds: ty = tyString else: internalError(p.config, n.info, "node has no type") else: - typ = skipTypes(optionalType, abstractInstOwned + {tyStatic}) - ty = typ.kind + ty = skipTypes(n.typ, abstractInstOwned).kind case ty of tySet: - let cs = toBitSet(p.config, n) - genRawSetData(cs, int(getSize(p.config, n.typ)), result) + var cs: TBitSet + toBitSet(p.config, n, cs) + result = genRawSetData(cs, int(getSize(p.config, n.typ))) of tySequence: if optSeqDestructors in p.config.globalOptions: - genConstSeqV2(p, n, typ, isConst, result) + result = genConstSeqV2(p, n, n.typ, isConst) else: - genConstSeq(p, n, typ, isConst, result) + result = genConstSeq(p, n, n.typ, isConst) of tyProc: - if typ.callConv == ccClosure and n.safeLen > 1 and n[1].kind == nkNilLit: - # n.kind could be: nkClosure, nkTupleConstr and maybe others; `n.safeLen` - # guards against the case of `nkSym`, refs bug #14340. + if n.typ.callConv == ccClosure and n.len > 1 and n[1].kind == nkNilLit: # Conversion: nimcall -> closure. # this hack fixes issue that nkNilLit is expanded to {NIM_NIL,NIM_NIL} # this behaviour is needed since closure_var = nil must be @@ -3432,45 +2960,27 @@ proc genBracedInit(p: BProc, n: PNode; isConst: bool; optionalType: PType; resul # leading to duplicate code like this: # "{NIM_NIL,NIM_NIL}, {NIM_NIL,NIM_NIL}" if n[0].kind == nkNilLit: - result.add "{NIM_NIL,NIM_NIL}" + result = ~"{NIM_NIL,NIM_NIL}" else: var d: TLoc initLocExpr(p, n[0], d) - result.add "{(($1) $2),NIM_NIL}" % [getClosureType(p.module, typ, clHalfWithEnv), rdLoc(d)] + result = "{(($1) $2),NIM_NIL}" % [getClosureType(p.module, n.typ, clHalfWithEnv), rdLoc(d)] else: var d: TLoc initLocExpr(p, n, d) - result.add rdLoc(d) - of tyArray, tyVarargs: - genConstSimpleList(p, n, isConst, result) - of tyTuple: - genConstTuple(p, n, isConst, typ, result) - of tyOpenArray: - if n.kind != nkBracket: - internalError(p.config, n.info, "const openArray expression is not an array construction") - - var data = newRopeAppender() - genConstSimpleList(p, n, isConst, data) - - let payload = getTempName(p.module) - let ctype = getTypeDesc(p.module, typ[0]) - let arrLen = n.len - appcg(p.module, cfsStrData, - "static $5 $1 $3[$2] = $4;$n", [ - ctype, arrLen, payload, data, - if isConst: "const" else: ""]) - result.add "{($1*)&$2, $3}" % [ctype, payload, rope arrLen] - + result = rdLoc(d) + of tyArray, tyTuple, tyOpenArray, tyVarargs: + result = genConstSimpleList(p, n, isConst) of tyObject: - genConstObjConstr(p, n, isConst, result) - of tyString, tyCstring: + result = genConstObjConstr(p, n, isConst) + of tyString, tyCString: if optSeqDestructors in p.config.globalOptions and n.kind != nkNilLit and ty == tyString: - genStringLiteralV2Const(p.module, n, isConst, result) + result = genStringLiteralV2Const(p.module, n, isConst) else: var d: TLoc initLocExpr(p, n, d) - result.add rdLoc(d) + result = rdLoc(d) else: var d: TLoc initLocExpr(p, n, d) - result.add rdLoc(d) + result = rdLoc(d) diff --git a/compiler/ccgliterals.nim b/compiler/ccgliterals.nim index cbef6771f..ee56da586 100644 --- a/compiler/ccgliterals.nim +++ b/compiler/ccgliterals.nim @@ -21,7 +21,7 @@ template detectVersion(field, corename) = if core == nil or core.kind != skConst: m.g.field = 1 else: - m.g.field = toInt(ast.getInt(core.astdef)) + m.g.field = toInt(ast.getInt(core.ast)) result = m.g.field proc detectStrVersion(m: BModule): int = @@ -32,87 +32,82 @@ proc detectSeqVersion(m: BModule): int = # ----- Version 1: GC'ed strings and seqs -------------------------------- -proc genStringLiteralDataOnlyV1(m: BModule, s: string; result: var Rope) = - cgsym(m, "TGenericSeq") - let tmp = getTempName(m) - result.add tmp - m.s[cfsStrData].addf("STRING_LITERAL($1, $2, $3);$n", - [tmp, makeCString(s), rope(s.len)]) +proc genStringLiteralDataOnlyV1(m: BModule, s: string): Rope = + discard cgsym(m, "TGenericSeq") + result = getTempName(m) + m.s[cfsData].addf("STRING_LITERAL($1, $2, $3);$n", + [result, makeCString(s), rope(s.len)]) -proc genStringLiteralV1(m: BModule; n: PNode; result: var Rope) = +proc genStringLiteralV1(m: BModule; n: PNode): Rope = if s.isNil: - appcg(m, result, "((#NimStringDesc*) NIM_NIL)", []) + result = ropecg(m, "((#NimStringDesc*) NIM_NIL)", []) else: let id = nodeTableTestOrSet(m.dataCache, n, m.labels) if id == m.labels: # string literal not found in the cache: - appcg(m, result, "((#NimStringDesc*) &", []) - genStringLiteralDataOnlyV1(m, n.strVal, result) - result.add ")" + result = ropecg(m, "((#NimStringDesc*) &$1)", + [genStringLiteralDataOnlyV1(m, n.strVal)]) else: - appcg(m, result, "((#NimStringDesc*) &$1$2)", + result = ropecg(m, "((#NimStringDesc*) &$1$2)", [m.tmpBase, id]) # ------ Version 2: destructor based strings and seqs ----------------------- proc genStringLiteralDataOnlyV2(m: BModule, s: string; result: Rope; isConst: bool) = - m.s[cfsStrData].addf("static $4 struct {$n" & + m.s[cfsData].addf("static $4 struct {$n" & " NI cap; NIM_CHAR data[$2+1];$n" & "} $1 = { $2 | NIM_STRLIT_FLAG, $3 };$n", [result, rope(s.len), makeCString(s), rope(if isConst: "const" else: "")]) -proc genStringLiteralV2(m: BModule; n: PNode; isConst: bool; result: var Rope) = +proc genStringLiteralV2(m: BModule; n: PNode; isConst: bool): Rope = let id = nodeTableTestOrSet(m.dataCache, n, m.labels) if id == m.labels: let pureLit = getTempName(m) genStringLiteralDataOnlyV2(m, n.strVal, pureLit, isConst) - let tmp = getTempName(m) - result.add tmp - cgsym(m, "NimStrPayload") - cgsym(m, "NimStringV2") + result = getTempName(m) + discard cgsym(m, "NimStrPayload") + discard cgsym(m, "NimStringV2") # string literal not found in the cache: - m.s[cfsStrData].addf("static $4 NimStringV2 $1 = {$2, (NimStrPayload*)&$3};$n", - [tmp, rope(n.strVal.len), pureLit, rope(if isConst: "const" else: "")]) + m.s[cfsData].addf("static $4 NimStringV2 $1 = {$2, (NimStrPayload*)&$3};$n", + [result, rope(n.strVal.len), pureLit, rope(if isConst: "const" else: "")]) else: - let tmp = getTempName(m) - result.add tmp - m.s[cfsStrData].addf("static $4 NimStringV2 $1 = {$2, (NimStrPayload*)&$3};$n", - [tmp, rope(n.strVal.len), m.tmpBase & rope(id), + result = getTempName(m) + m.s[cfsData].addf("static $4 NimStringV2 $1 = {$2, (NimStrPayload*)&$3};$n", + [result, rope(n.strVal.len), m.tmpBase & rope(id), rope(if isConst: "const" else: "")]) -proc genStringLiteralV2Const(m: BModule; n: PNode; isConst: bool; result: var Rope) = +proc genStringLiteralV2Const(m: BModule; n: PNode; isConst: bool): Rope = let id = nodeTableTestOrSet(m.dataCache, n, m.labels) var pureLit: Rope if id == m.labels: pureLit = getTempName(m) - cgsym(m, "NimStrPayload") - cgsym(m, "NimStringV2") + discard cgsym(m, "NimStrPayload") + discard cgsym(m, "NimStringV2") # string literal not found in the cache: genStringLiteralDataOnlyV2(m, n.strVal, pureLit, isConst) else: pureLit = m.tmpBase & rope(id) - result.addf "{$1, (NimStrPayload*)&$2}", [rope(n.strVal.len), pureLit] + result = "{$1, (NimStrPayload*)&$2}" % [rope(n.strVal.len), pureLit] # ------ Version selector --------------------------------------------------- proc genStringLiteralDataOnly(m: BModule; s: string; info: TLineInfo; - isConst: bool; result: var Rope) = + isConst: bool): Rope = case detectStrVersion(m) - of 0, 1: genStringLiteralDataOnlyV1(m, s, result) + of 0, 1: result = genStringLiteralDataOnlyV1(m, s) of 2: - let tmp = getTempName(m) - genStringLiteralDataOnlyV2(m, s, tmp, isConst) - result.add tmp + result = getTempName(m) + genStringLiteralDataOnlyV2(m, s, result, isConst) else: localError(m.config, info, "cannot determine how to produce code for string literal") -proc genNilStringLiteral(m: BModule; info: TLineInfo; result: var Rope) = - appcg(m, result, "((#NimStringDesc*) NIM_NIL)", []) +proc genNilStringLiteral(m: BModule; info: TLineInfo): Rope = + result = ropecg(m, "((#NimStringDesc*) NIM_NIL)", []) -proc genStringLiteral(m: BModule; n: PNode; result: var Rope) = +proc genStringLiteral(m: BModule; n: PNode): Rope = case detectStrVersion(m) - of 0, 1: genStringLiteralV1(m, n, result) - of 2: genStringLiteralV2(m, n, isConst = true, result) + of 0, 1: result = genStringLiteralV1(m, n) + of 2: result = genStringLiteralV2(m, n, isConst = true) else: localError(m.config, n.info, "cannot determine how to produce code for string literal") diff --git a/compiler/ccgmerge_unused.nim b/compiler/ccgmerge.nim similarity index 92% rename from compiler/ccgmerge_unused.nim rename to compiler/ccgmerge.nim index a1413034f..2be34aace 100644 --- a/compiler/ccgmerge_unused.nim +++ b/compiler/ccgmerge.nim @@ -19,11 +19,13 @@ import const CFileSectionNames: array[TCFileSection, string] = [ + cfsMergeInfo: "", cfsHeaders: "NIM_merge_HEADERS", cfsFrameDefines: "NIM_merge_FRAME_DEFINES", cfsForwardTypes: "NIM_merge_FORWARD_TYPES", cfsTypes: "NIM_merge_TYPES", cfsSeqTypes: "NIM_merge_SEQ_TYPES", + cfsFieldInfo: "NIM_merge_FIELD_INFO", cfsTypeInfo: "NIM_merge_TYPE_INFO", cfsProcHeaders: "NIM_merge_PROC_HEADERS", cfsData: "NIM_merge_DATA", @@ -32,8 +34,11 @@ const cfsInitProc: "NIM_merge_INIT_PROC", cfsDatInitProc: "NIM_merge_DATINIT_PROC", cfsTypeInit1: "NIM_merge_TYPE_INIT1", + cfsTypeInit2: "NIM_merge_TYPE_INIT2", cfsTypeInit3: "NIM_merge_TYPE_INIT3", - cfsDynLibInit: "NIM_merge_DYNLIB_INIT" + cfsDebugInit: "NIM_merge_DEBUG_INIT", + cfsDynLibInit: "NIM_merge_DYNLIB_INIT", + cfsDynLibDeinit: "NIM_merge_DYNLIB_DEINIT", ] CProcSectionNames: array[TCProcSection, string] = [ cpsLocals: "NIM_merge_PROC_LOCALS", @@ -43,10 +48,6 @@ const NimMergeEndMark = "/*\tNIM_merge_END:*/" proc genSectionStart*(fs: TCFileSection; conf: ConfigRef): Rope = - # useful for debugging and only adds at most a few lines in each file - result.add("\n/* section: ") - result.add(CFileSectionNames[fs]) - result.add(" */\n") if compilationCachePresent(conf): result = nil result.add("\n/*\t") @@ -175,6 +176,10 @@ proc readKey(L: var TBaseLexer, result: var string) = if L.buf[pos] != ':': doAssert(false, "ccgmerge: ':' expected") L.bufpos = pos + 1 # skip ':' +proc newFakeType(id: int): PType = + new(result) + result.id = id + proc readTypeCache(L: var TBaseLexer, result: var TypeCache) = if ^L.bufpos != '{': doAssert(false, "ccgmerge: '{' expected") inc L.bufpos @@ -183,7 +188,10 @@ proc readTypeCache(L: var TBaseLexer, result: var TypeCache) = var key = decodeStr(L.buf, L.bufpos) if ^L.bufpos != ':': doAssert(false, "ccgmerge: ':' expected") inc L.bufpos - discard decodeStr(L.buf, L.bufpos) + var value = decodeStr(L.buf, L.bufpos) + # XXX implement me + when false: + idTablePut(result, newFakeType(key), value.rope) inc L.bufpos proc readIntSet(L: var TBaseLexer, result: var IntSet) = @@ -213,6 +221,9 @@ proc processMergeInfo(L: var TBaseLexer, m: BModule) = m.flags = cast[set[CodegenFlag]](decodeVInt(L.buf, L.bufpos) != 0) else: doAssert(false, "ccgmerge: unknown key: " & k) +when not defined(nimhygiene): + {.pragma: inject.} + template withCFile(cfilename: AbsoluteFile, body: untyped) = var s = llStreamOpen(cfilename, fmRead) if s == nil: return @@ -267,7 +278,7 @@ proc mergeRequired*(m: BModule): bool = if m.s[i] != nil: #echo "not empty: ", i, " ", m.s[i] return true - for i in TCProcSection: + for i in low(TCProcSection)..high(TCProcSection): if m.initProc.s(i) != nil: #echo "not empty: ", i, " ", m.initProc.s[i] return true @@ -277,7 +288,7 @@ proc mergeFiles*(cfilename: AbsoluteFile, m: BModule) = var old: TMergeSections readMergeSections(cfilename, old) # do the merge; old section before new section: - for i in TCFileSection: + for i in low(TCFileSection)..high(TCFileSection): m.s[i] = old.f[i] & m.s[i] - for i in TCProcSection: + for i in low(TCProcSection)..high(TCProcSection): m.initProc.s(i) = old.p[i] & m.initProc.s(i) diff --git a/compiler/ccgreset.nim b/compiler/ccgreset.nim deleted file mode 100644 index 5e6456704..000000000 --- a/compiler/ccgreset.nim +++ /dev/null @@ -1,107 +0,0 @@ -# -# -# The Nim Compiler -# (c) Copyright 2020 Andreas Rumpf -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# - -# included from cgen.nim - -## Code specialization instead of the old, incredibly slow 'genericReset' -## implementation. - -proc specializeResetT(p: BProc, accessor: Rope, typ: PType) - -proc specializeResetN(p: BProc, accessor: Rope, n: PNode; - typ: PType) = - if n == nil: return - case n.kind - of nkRecList: - for i in 0.. 2 @@ -99,10 +90,13 @@ proc genVarTuple(p: BProc, n: PNode) = let vn = n[i] let v = vn.sym if sfCompileTime in v.flags: continue + var traverseProc: Rope if sfGlobal in v.flags: - assignGlobalVar(p, vn, "") + assignGlobalVar(p, vn, nil) genObjectInit(p, cpsInit, v.typ, v.loc, constructObj) - registerTraverseProc(p, v) + traverseProc = getTraverseProc(p, v) + if traverseProc != nil and not p.hcrOn: + registerTraverseProc(p, v, traverseProc) else: assignLocalVar(p, vn) initLocalVar(p, v, immediateAsgn=isAssignedImmediately(p.config, n[^1])) @@ -114,7 +108,7 @@ proc genVarTuple(p: BProc, n: PNode) = field.r = "$1.$2" % [rdLoc(tup), mangleRecFieldName(p.module, t.n[i].sym)] putLocIntoDest(p, v.loc, field) if forHcr or isGlobalInBlock: - hcrGlobals.add((loc: v.loc, tp: "NULL")) + hcrGlobals.add((loc: v.loc, tp: if traverseProc == nil: ~"NULL" else: traverseProc)) if forHcr: # end the block where the tuple gets initialized @@ -144,12 +138,12 @@ proc loadInto(p: BProc, le, ri: PNode, a: var TLoc) {.inline.} = a.flags.incl(lfEnforceDeref) expr(p, ri, a) -proc assignLabel(b: var TBlock; result: var Rope) {.inline.} = +proc assignLabel(b: var TBlock): Rope {.inline.} = b.label = "LA" & b.id.rope - result.add b.label + result = b.label -proc blockBody(b: var TBlock; result: var Rope) = - result.add b.sections[cpsLocals] +proc blockBody(b: var TBlock): Rope = + result = b.sections[cpsLocals] if b.frameLen > 0: result.addf("FR_.len+=$1;$n", [b.frameLen.rope]) result.add(b.sections[cpsInit]) @@ -158,7 +152,7 @@ proc blockBody(b: var TBlock; result: var Rope) = proc endBlock(p: BProc, blockEnd: Rope) = let topBlock = p.blocks.len-1 # the block is merged into the parent block - p.blocks[topBlock].blockBody(p.blocks[topBlock-1].sections[cpsStmts]) + p.blocks[topBlock-1].sections[cpsStmts].add(p.blocks[topBlock].blockBody) setLen(p.blocks, topBlock) # this is done after the block is popped so $n is # properly indented when pretty printing is enabled @@ -170,7 +164,7 @@ proc endBlock(p: BProc) = var blockEnd: Rope if frameLen > 0: blockEnd.addf("FR_.len-=$1;$n", [frameLen.rope]) - if p.blocks[topBlock].label.len != 0: + if p.blocks[topBlock].label != nil: blockEnd.addf("} $1: ;$n", [p.blocks[topBlock].label]) else: blockEnd.addf("}$n", []) @@ -206,7 +200,6 @@ proc blockLeaveActions(p: BProc, howManyTrys, howManyExcepts: int) = var stack = newSeq[tuple[fin: PNode, inExcept: bool, label: Natural]](0) - inc p.withinBlockLeaveActions for i in 1..howManyTrys: let tryStmt = p.nestedTryStmts.pop if p.config.exc == excSetjmp: @@ -224,17 +217,16 @@ proc blockLeaveActions(p: BProc, howManyTrys, howManyExcepts: int) = if finallyStmt != nil: genStmts(p, finallyStmt[0]) - dec p.withinBlockLeaveActions - # push old elements again: for i in countdown(howManyTrys-1, 0): p.nestedTryStmts.add(stack[i]) - # Pop exceptions that was handled by the - # except-blocks we are in - if noSafePoints notin p.flags: - for i in countdown(howManyExcepts-1, 0): - linefmt(p, cpsStmts, "#popCurrentException();$n", []) + if p.config.exc != excCpp: + # Pop exceptions that was handled by the + # except-blocks we are in + if noSafePoints notin p.flags: + for i in countdown(howManyExcepts-1, 0): + linefmt(p, cpsStmts, "#popCurrentException();$n", []) proc genGotoState(p: BProc, n: PNode) = # we resist the temptation to translate it into duff's device as it later @@ -278,15 +270,17 @@ proc genGotoVar(p: BProc; value: PNode) = else: lineF(p, cpsStmts, "goto NIMSTATE_$#;$n", [value.intVal.rope]) -proc genBracedInit(p: BProc, n: PNode; isConst: bool; optionalType: PType; result: var Rope) +proc genBracedInit(p: BProc, n: PNode; isConst: bool): Rope -proc potentialValueInit(p: BProc; v: PSym; value: PNode; result: var Rope) = +proc potentialValueInit(p: BProc; v: PSym; value: PNode): Rope = if lfDynamicLib in v.loc.flags or sfThread in v.flags or p.hcrOn: - discard "nothing to do" + result = nil elif sfGlobal in v.flags and value != nil and isDeepConstExpr(value, p.module.compileToCpp) and p.withinLoop == 0 and not containsGarbageCollectedRef(v.typ): #echo "New code produced for ", v.name.s, " ", p.config $ value.info - genBracedInit(p, value, isConst = false, v.typ, result) + result = genBracedInit(p, value, isConst = false) + else: + result = nil proc genSingleVar(p: BProc, v: PSym; vn, value: PNode) = if sfGoto in v.flags: @@ -294,8 +288,8 @@ proc genSingleVar(p: BProc, v: PSym; vn, value: PNode) = genGotoVar(p, value) return var targetProc = p - var valueAsRope = "" - potentialValueInit(p, v, value, valueAsRope) + var traverseProc: Rope + let valueAsRope = potentialValueInit(p, v, value) if sfGlobal in v.flags: if v.flags * {sfImportc, sfExportc} == {sfImportc} and value.kind == nkEmpty and @@ -311,7 +305,7 @@ proc genSingleVar(p: BProc, v: PSym; vn, value: PNode) = # That's why we are doing the construction inside the preInitProc. # genObjectInit relies on the C runtime's guarantees that # global variables will be initialized to zero. - if valueAsRope.len == 0: + if valueAsRope == nil: var loc = v.loc # When the native TLS is unavailable, a global thread-local variable needs @@ -325,7 +319,9 @@ proc genSingleVar(p: BProc, v: PSym; vn, value: PNode) = # if sfImportc notin v.flags: constructLoc(p.module.preInitProc, v.loc) if sfExportc in v.flags and p.module.g.generatedHeader != nil: genVarPrototype(p.module.g.generatedHeader, vn) - registerTraverseProc(p, v) + traverseProc = getTraverseProc(p, v) + if traverseProc != nil and not p.hcrOn: + registerTraverseProc(p, v, traverseProc) else: let imm = isAssignedImmediately(p.config, value) if imm and p.module.compileToCpp and p.splitDecls == 0 and @@ -338,14 +334,14 @@ proc genSingleVar(p: BProc, v: PSym; vn, value: PNode) = var tmp: TLoc if value.kind in nkCallKinds and value[0].kind == nkSym and sfConstructor in value[0].sym.flags: - var params = newRopeAppender() - var argsCounter = 0 + var params: Rope let typ = skipTypes(value[0].typ, abstractInst) assert(typ.kind == tyProc) for i in 1..= 0 and not p.blocks[idx].isLoop: dec idx if idx < 0 or not p.blocks[idx].isLoop: internalError(p.config, t.info, "no loop to break") - p.blocks[idx].label = "LA" & p.blocks[idx].id.rope + let label = assignLabel(p.blocks[idx]) blockLeaveActions(p, p.nestedTryStmts.len - p.blocks[idx].nestedTryStmts, p.inExceptBlockLen - p.blocks[idx].nestedExceptStmts) genLineDir(p, t) - lineF(p, cpsStmts, "goto $1;$n", [p.blocks[idx].label]) + lineF(p, cpsStmts, "goto $1;$n", [label]) proc raiseExit(p: BProc) = assert p.config.exc == excGoto - if nimErrorFlagDisabled notin p.flags: - p.flags.incl nimErrorFlagAccessed - if p.nestedTryStmts.len == 0: - p.flags.incl beforeRetNeeded - # easy case, simply goto 'ret': - lineCg(p, cpsStmts, "if (NIM_UNLIKELY(*nimErr_)) goto BeforeRet_;$n", []) - else: - lineCg(p, cpsStmts, "if (NIM_UNLIKELY(*nimErr_)) goto LA$1_;$n", - [p.nestedTryStmts[^1].label]) + p.flags.incl nimErrorFlagAccessed + if p.nestedTryStmts.len == 0: + p.flags.incl beforeRetNeeded + # easy case, simply goto 'ret': + lineCg(p, cpsStmts, "if (NIM_UNLIKELY(*nimErr_)) goto BeforeRet_;$n", []) + else: + lineCg(p, cpsStmts, "if (NIM_UNLIKELY(*nimErr_)) goto LA$1_;$n", + [p.nestedTryStmts[^1].label]) proc finallyActions(p: BProc) = if p.config.exc != excGoto and p.nestedTryStmts.len > 0 and p.nestedTryStmts[^1].inExcept: @@ -727,32 +706,15 @@ proc finallyActions(p: BProc) = if finallyBlock != nil: genSimpleBlock(p, finallyBlock[0]) -proc raiseInstr(p: BProc; result: var Rope) = - if p.config.exc == excGoto: - let L = p.nestedTryStmts.len - if L == 0: - p.flags.incl beforeRetNeeded - # easy case, simply goto 'ret': - result.add ropecg(p.module, "goto BeforeRet_;$n", []) - else: - # raise inside an 'except' must go to the finally block, - # raise outside an 'except' block must go to the 'except' list. - result.add ropecg(p.module, "goto LA$1_;$n", - [p.nestedTryStmts[L-1].label]) - # + ord(p.nestedTryStmts[L-1].inExcept)]) - proc genRaiseStmt(p: BProc, t: PNode) = + if p.config.exc == excCpp: + discard cgsym(p.module, "popCurrentExceptionEx") if t[0].kind != nkEmpty: var a: TLoc initLocExprSingleUse(p, t[0], a) finallyActions(p) var e = rdLoc(a) - discard getTypeDesc(p.module, t[0].typ) var typ = skipTypes(t[0].typ, abstractPtrs) - # XXX For reasons that currently escape me, this is only required by the new - # C++ based exception handling: - if p.config.exc == excCpp: - blockLeaveActions(p, howManyTrys = 0, howManyExcepts = p.inExceptBlockLen) genLineDir(p, t) if isImportedException(typ, p.config): lineF(p, cpsStmts, "throw $1;$n", [e]) @@ -768,10 +730,21 @@ proc genRaiseStmt(p: BProc, t: PNode) = genLineDir(p, t) # reraise the last exception: if p.config.exc == excCpp: - line(p, cpsStmts, "throw;\n") + line(p, cpsStmts, ~"throw;$n") else: linefmt(p, cpsStmts, "#reraiseException();$n", []) - raiseInstr(p, p.s(cpsStmts)) + if p.config.exc == excGoto: + let L = p.nestedTryStmts.len + if L == 0: + p.flags.incl beforeRetNeeded + # easy case, simply goto 'ret': + lineCg(p, cpsStmts, "goto BeforeRet_;$n", []) + else: + # raise inside an 'except' must go to the finally block, + # raise outside an 'except' block must go to the 'except' list. + lineCg(p, cpsStmts, "goto LA$1_;$n", + [p.nestedTryStmts[L-1].label]) + # + ord(p.nestedTryStmts[L-1].inExcept)]) template genCaseGenericBranch(p: BProc, b: PNode, e: TLoc, rangeFormat, eqFormat: FormatStr, labl: TLabel) = @@ -831,27 +804,17 @@ template genCaseGeneric(p: BProc, t: PNode, d: var TLoc, fixLabel(p, lend) proc genCaseStringBranch(p: BProc, b: PNode, e: TLoc, labl: TLabel, - stringKind: TTypeKind, branches: var openArray[Rope]) = var x: TLoc for i in 0.. RangeExpandLimit: + if (b[i].kind == nkRange) and + b[i][1].intVal - b[i][0].intVal > RangeExpandLimit: return true proc ifSwitchSplitPoint(p: BProc, n: PNode): int = @@ -917,22 +871,16 @@ proc genCaseRange(p: BProc, branch: PNode) = for j in 0.. 0: genIfForCaseUntil(p, n, d, rangeFormat = "if ($1 >= $2 && $1 <= $3) goto $4;$n", eqFormat = "if ($1 == $2) goto $3;$n", - splitPoint, a) else: "" + splitPoint, a) else: nil # generate switch part (might be empty): if splitPoint+1 < n.len: @@ -965,7 +913,7 @@ proc genOrdinalCase(p: BProc, n: PNode, d: var TLoc) = 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) + if lend != nil: fixLabel(p, lend) proc genCase(p: BProc, t: PNode, d: var TLoc) = genLineDir(p, t) @@ -973,9 +921,7 @@ proc genCase(p: BProc, t: PNode, d: var TLoc) = getTemp(p, t.typ, d) case skipTypes(t[0].typ, abstractVarRange).kind of tyString: - genStringCase(p, t, tyString, d) - of tyCstring: - genStringCase(p, t, tyCstring, d) + genStringCase(p, t, d) of tyFloat..tyFloat128: genCaseGeneric(p, t, d, "if ($1 >= $2 && $1 <= $3) goto $4;$n", "if ($1 == $2) goto $3;$n") @@ -994,178 +940,6 @@ proc genRestoreFrameAfterException(p: BProc) = linefmt(p, cpsStmts, "#setFrame(_nimCurFrame);$n", []) proc genTryCpp(p: BProc, t: PNode, d: var TLoc) = - #[ code to generate: - - std::exception_ptr error = nullptr; - try { - body; - } catch (Exception e) { - error = std::current_exception(); - if (ofExpr(e, TypeHere)) { - - error = nullptr; // handled - } else if (...) { - - } else { - throw; - } - } catch(...) { - // C++ exception occured, not under Nim's control. - } - { - /* finally: */ - printf('fin!\n'); - if (error) std::rethrow_exception(error); // re-raise the exception - } - ]# - p.module.includeHeader("") - - if not isEmptyType(t.typ) and d.k == locNone: - getTemp(p, t.typ, d) - genLineDir(p, t) - - inc(p.labels, 2) - let etmp = p.labels - - 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)) - - if t.kind == nkHiddenTryStmt: - lineCg(p, cpsStmts, "try {$n", []) - expr(p, t[0], d) - lineCg(p, cpsStmts, "}$n", []) - else: - startBlock(p, "try {$n") - expr(p, t[0], d) - endBlock(p) - - # First pass: handle Nim based exceptions: - lineCg(p, cpsStmts, "catch (#Exception* T$1_) {$n", [etmp+1]) - genRestoreFrameAfterException(p) - # an unhandled exception happened! - lineCg(p, cpsStmts, "T$1_ = std::current_exception();$n", [etmp]) - p.nestedTryStmts[^1].inExcept = true - var hasImportedCppExceptions = false - var i = 1 - var hasIf = false - var hasElse = false - while (i < t.len) and (t[i].kind == nkExceptBranch): - # bug #4230: avoid false sharing between branches: - if d.k == locTemp and isEmptyType(t.typ): d.k = locNone - if t[i].len == 1: - hasImportedCppExceptions = true - # general except section: - hasElse = true - 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) - else: - var orExpr = newRopeAppender() - var exvar = PNode(nil) - for j in 0..$1, $2, $3)", [memberName, checkFor, $genDisplayElem(MD5Digest(hashType(typeNode.typ, p.config)))]) - else: - let checkFor = genTypeInfoV1(p.module, typeNode.typ, typeNode.info) - appcg(p.module, orExpr, "#isObj(#nimBorrowCurrentException()->$1, $2)", [memberName, checkFor]) - - if orExpr.len != 0: - if hasIf: - startBlock(p, "else if ($1) {$n", [orExpr]) - else: - startBlock(p, "if ($1) {$n", [orExpr]) - hasIf = true - if exvar != nil: - fillLocalName(p, exvar.sym) - fillLoc(exvar.sym.loc, locTemp, exvar, OnStack) - linefmt(p, cpsStmts, "$1 $2 = T$3_;$n", [getTypeDesc(p.module, exvar.sym.typ), - rdLoc(exvar.sym.loc), rope(etmp+1)]) - # we handled the error: - linefmt(p, cpsStmts, "T$1_ = nullptr;$n", [etmp]) - expr(p, t[i][^1], d) - linefmt(p, cpsStmts, "#popCurrentException();$n", []) - endBlock(p) - inc(i) - if hasIf and not hasElse: - linefmt(p, cpsStmts, "else throw;$n", [etmp]) - linefmt(p, cpsStmts, "}$n", []) - - # Second pass: handle C++ based exceptions: - template genExceptBranchBody(body: PNode) {.dirty.} = - genRestoreFrameAfterException(p) - #linefmt(p, cpsStmts, "T$1_ = std::current_exception();$n", [etmp]) - expr(p, body, d) - - var catchAllPresent = false - incl p.flags, noSafePoints # mark as not needing 'popCurrentException' - if hasImportedCppExceptions: - for i in 1.. 0 and t[^1].kind == nkFinally: - if not catchAllPresent: - startBlock(p, "catch (...) {", []) - genRestoreFrameAfterException(p) - linefmt(p, cpsStmts, "T$1_ = std::current_exception();$n", [etmp]) - endBlock(p) - - startBlock(p) - genStmts(p, t[^1][0]) - linefmt(p, cpsStmts, "if (T$1_) std::rethrow_exception(T$1_);$n", [etmp]) - endBlock(p) - -proc genTryCppOld(p: BProc, t: PNode, d: var TLoc) = - # There are two versions we generate, depending on whether we - # catch C++ exceptions, imported via .importcpp or not. The - # code can be easier if there are no imported C++ exceptions - # to deal with. - # code to generate: # # try @@ -1189,7 +963,7 @@ proc genTryCppOld(p: BProc, t: PNode, d: var TLoc) = if not isEmptyType(t.typ) and d.k == locNone: getTemp(p, t.typ, d) genLineDir(p, t) - cgsym(p.module, "popCurrentExceptionEx") + discard cgsym(p.module, "popCurrentExceptionEx") let fin = if t[^1].kind == nkFinally: t[^1] else: nil p.nestedTryStmts.add((fin, false, 0.Natural)) startBlock(p, "try {$n") @@ -1215,8 +989,7 @@ proc genTryCppOld(p: BProc, t: PNode, d: var TLoc) = for j in 0.. 1 and t[^1].kind == nkFinally: + genStmts(p, t[^1][0]) + return + let fin = if t[^1].kind == nkFinally: t[^1] else: nil - inc p.labels - let lab = p.labels - let hasExcept = t[1].kind == nkExceptBranch - if hasExcept: inc p.withinTryWithExcept + inc p.labels, 2 + let lab = p.labels-1 p.nestedTryStmts.add((fin, false, Natural lab)) p.flags.incl nimErrorFlagAccessed - - if not isEmptyType(t.typ) and d.k == locNone: - getTemp(p, t.typ, d) + p.procSec(cpsLocals).add(ropecg(p.module, "NI oldNimErr$1_;$n", [lab])) + linefmt(p, cpsStmts, "oldNimErr$1_ = *nimErr_; *nimErr_ = 0;;$n", [lab]) expr(p, t[0], d) @@ -1273,7 +1050,8 @@ proc genTryGoto(p: BProc; t: PNode; d: var TLoc) = startBlock(p, "if (NIM_UNLIKELY(*nimErr_)) {$n") else: startBlock(p) - linefmt(p, cpsStmts, "LA$1_:;$n", [lab]) + # pretend we did handle the error for the safe execution of the sections: + linefmt(p, cpsStmts, "LA$1_: oldNimErr$1_ = *nimErr_; *nimErr_ = 0;$n", [lab]) p.nestedTryStmts[^1].inExcept = true var i = 1 @@ -1290,25 +1068,24 @@ proc genTryGoto(p: BProc; t: PNode; d: var TLoc) = if i > 1: lineF(p, cpsStmts, "else", []) startBlock(p) # we handled the exception, remember this: - linefmt(p, cpsStmts, "*nimErr_ = NIM_FALSE;$n", []) + linefmt(p, cpsStmts, "--oldNimErr$1_;$n", [lab]) expr(p, t[i][0], d) else: - var orExpr = newRopeAppender() + var orExpr: Rope = nil for j in 0..$1, $2, $3)", [memberName, checkFor, $genDisplayElem(MD5Digest(hashType(t[i][j].typ, p.config)))]) + if orExpr != nil: orExpr.add("||") + let checkFor = if optTinyRtti in p.config.globalOptions: + genTypeInfo2Name(p.module, 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]) + genTypeInfo(p.module, t[i][j].typ, t[i][j].info) + let memberName = if p.module.compileToCpp: "m_type" else: "Sup.m_type" + appcg(p.module, orExpr, "#isObj(#nimBorrowCurrentException()->$1, $2)", [memberName, checkFor]) if i > 1: line(p, cpsStmts, "else ") startBlock(p, "if ($1) {$n", [orExpr]) # we handled the exception, remember this: - linefmt(p, cpsStmts, "*nimErr_ = NIM_FALSE;$n", []) + linefmt(p, cpsStmts, "--oldNimErr$1_;$n", [lab]) expr(p, t[i][^1], d) linefmt(p, cpsStmts, "#popCurrentException();$n", []) @@ -1319,16 +1096,17 @@ proc genTryGoto(p: BProc; t: PNode; d: var TLoc) = discard pop(p.nestedTryStmts) endBlock(p) + #linefmt(p, cpsStmts, "LA$1_:;$n", [lab+1]) if i < t.len and t[i].kind == nkFinally: startBlock(p) - if not bodyCanRaise(p, t[i][0]): + if not bodyCanRaise(t[i][0]): # this is an important optimization; most destroy blocks are detected not to raise an # exception and so we help the C optimizer by not mutating nimErr_ pointlessly: genStmts(p, t[i][0]) else: # pretend we did handle the error for the safe execution of the 'finally' section: - p.procSec(cpsLocals).add(ropecg(p.module, "NIM_BOOL oldNimErrFin$1_;$n", [lab])) - linefmt(p, cpsStmts, "oldNimErrFin$1_ = *nimErr_; *nimErr_ = NIM_FALSE;$n", [lab]) + p.procSec(cpsLocals).add(ropecg(p.module, "NI oldNimErrFin$1_;$n", [lab])) + linefmt(p, cpsStmts, "oldNimErrFin$1_ = *nimErr_; *nimErr_ = 0;$n", [lab]) genStmts(p, t[i][0]) # this is correct for all these cases: # 1. finally is run during ordinary control flow @@ -1336,10 +1114,11 @@ proc genTryGoto(p: BProc; t: PNode; d: var TLoc) = # error back to nil. # 3. finally is run for exception handling code without any 'except' # handler present or only handlers that did not match. - linefmt(p, cpsStmts, "*nimErr_ = oldNimErrFin$1_;$n", [lab]) + linefmt(p, cpsStmts, "*nimErr_ += oldNimErr$1_ + (*nimErr_ - oldNimErrFin$1_); oldNimErr$1_ = 0;$n", [lab]) + raiseExit(p) endBlock(p) - raiseExit(p) - if hasExcept: inc p.withinTryWithExcept + # restore the real error value: + linefmt(p, cpsStmts, "*nimErr_ += oldNimErr$1_;$n", [lab]) proc genTrySetjmp(p: BProc, t: PNode, d: var TLoc) = # code to generate: @@ -1379,7 +1158,7 @@ proc genTrySetjmp(p: BProc, t: PNode, d: var TLoc) = else: p.flags.incl noSafePoints genLineDir(p, t) - cgsym(p.module, "Exception") + discard cgsym(p.module, "Exception") var safePoint: Rope if not quirkyExceptions: safePoint = getTempName(p.module) @@ -1389,33 +1168,17 @@ proc genTrySetjmp(p: BProc, t: PNode, d: var TLoc) = linefmt(p, cpsStmts, "$1.status = setjmp($1.context);$n", [safePoint]) elif isDefined(p.config, "nimSigSetjmp"): linefmt(p, cpsStmts, "$1.status = sigsetjmp($1.context, 0);$n", [safePoint]) - elif isDefined(p.config, "nimBuiltinSetjmp"): - linefmt(p, cpsStmts, "$1.status = __builtin_setjmp($1.context);$n", [safePoint]) elif isDefined(p.config, "nimRawSetjmp"): - if isDefined(p.config, "mswindows"): - if isDefined(p.config, "vcc") or isDefined(p.config, "clangcl"): - # For the vcc compiler, use `setjmp()` with one argument. - # See https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/setjmp?view=msvc-170 - linefmt(p, cpsStmts, "$1.status = setjmp($1.context);$n", [safePoint]) - else: - # The Windows `_setjmp()` takes two arguments, with the second being an - # undocumented buffer used by the SEH mechanism for stack unwinding. - # Mingw-w64 has been trying to get it right for years, but it's still - # prone to stack corruption during unwinding, so we disable that by setting - # it to NULL. - # More details: https://github.com/status-im/nimbus-eth2/issues/3121 - linefmt(p, cpsStmts, "$1.status = _setjmp($1.context, 0);$n", [safePoint]) - else: - linefmt(p, cpsStmts, "$1.status = _setjmp($1.context);$n", [safePoint]) + linefmt(p, cpsStmts, "$1.status = _setjmp($1.context);$n", [safePoint]) else: linefmt(p, cpsStmts, "$1.status = setjmp($1.context);$n", [safePoint]) - lineCg(p, cpsStmts, "if ($1.status == 0) {$n", [safePoint]) + startBlock(p, "if ($1.status == 0) {$n", [safePoint]) let fin = if t[^1].kind == nkFinally: t[^1] else: nil p.nestedTryStmts.add((fin, quirkyExceptions, 0.Natural)) expr(p, t[0], d) if not quirkyExceptions: linefmt(p, cpsStmts, "#popSafePoint();$n", []) - lineCg(p, cpsStmts, "}$n", []) + endBlock(p) startBlock(p, "else {$n") linefmt(p, cpsStmts, "#popSafePoint();$n", []) genRestoreFrameAfterException(p) @@ -1438,17 +1201,16 @@ proc genTrySetjmp(p: BProc, t: PNode, d: var TLoc) = linefmt(p, cpsStmts, "#popCurrentException();$n", []) endBlock(p) else: - var orExpr = newRopeAppender() + var orExpr: Rope = nil for j in 0..$1, $2, $3)", [memberName, checkFor, $genDisplayElem(MD5Digest(hashType(t[i][j].typ, p.config)))]) + if orExpr != nil: orExpr.add("||") + let checkFor = if optTinyRtti in p.config.globalOptions: + genTypeInfo2Name(p.module, 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]) + genTypeInfo(p.module, t[i][j].typ, t[i][j].info) + let memberName = if p.module.compileToCpp: "m_type" else: "Sup.m_type" + appcg(p.module, orExpr, "#isObj(#nimBorrowCurrentException()->$1, $2)", [memberName, checkFor]) if i > 1: line(p, cpsStmts, "else ") startBlock(p, "if ($1) {$n", [orExpr]) @@ -1474,7 +1236,7 @@ proc genTrySetjmp(p: BProc, t: PNode, d: var TLoc) = if not quirkyExceptions: linefmt(p, cpsStmts, "if ($1.status != 0) #reraiseException();$n", [safePoint]) -proc genAsmOrEmitStmt(p: BProc, t: PNode, isAsmStmt=false; result: var Rope) = +proc genAsmOrEmitStmt(p: BProc, t: PNode, isAsmStmt=false): Rope = var res = "" for it in t.sons: case it.kind @@ -1490,8 +1252,13 @@ proc genAsmOrEmitStmt(p: BProc, t: PNode, isAsmStmt=false; result: var Rope) = res.add($getTypeDesc(p.module, sym.typ)) else: discard getTypeDesc(p.module, skipTypes(sym.typ, abstractPtrs)) - fillBackendName(p.module, sym) - res.add($sym.loc.r) + var r = sym.loc.r + if r == nil: + # if no name has already been given, + # it doesn't matter much: + r = mangleName(p.module, sym) + sym.loc.r = r # but be consequent! + res.add($r) of nkTypeOfExpr: res.add($getTypeDesc(p.module, it.typ)) else: @@ -1512,17 +1279,16 @@ proc genAsmOrEmitStmt(p: BProc, t: PNode, isAsmStmt=false; result: var Rope) = else: # ignore empty lines result.add("\"") - result.add(x.replace("\"", "\\\"")) + result.add(x) result.add("\\n\"\n") else: res.add("\L") - result.add res.rope + result = res.rope proc genAsmStmt(p: BProc, t: PNode) = assert(t.kind == nkAsmStmt) genLineDir(p, t) - var s = newRopeAppender() - genAsmOrEmitStmt(p, t, isAsmStmt=true, s) + var s = genAsmOrEmitStmt(p, t, isAsmStmt=true) # see bug #2362, "top level asm statements" seem to be a mis-feature # but even if we don't do this, the example in #2362 cannot possibly # work: @@ -1530,20 +1296,18 @@ proc genAsmStmt(p: BProc, t: PNode) = # top level asm statement? p.module.s[cfsProcHeaders].add runtimeFormat(CC[p.config.cCompiler].asmStmtFrmt, [s]) else: - addIndent p, p.s(cpsStmts) - p.s(cpsStmts).add runtimeFormat(CC[p.config.cCompiler].asmStmtFrmt, [s]) + p.s(cpsStmts).add indentLine(p, runtimeFormat(CC[p.config.cCompiler].asmStmtFrmt, [s])) 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 proc genEmit(p: BProc, t: PNode) = - var s = newRopeAppender() - genAsmOrEmitStmt(p, t[1], false, s) + var s = genAsmOrEmitStmt(p, t[1]) if p.prc == nil: # top level emit pragma? let section = determineSection(t[1]) @@ -1554,47 +1318,53 @@ proc genEmit(p: BProc, t: PNode) = line(p, cpsStmts, s) proc genPragma(p: BProc, n: PNode) = - for i in 0.. error. - s.loc.r = res.rope + if m.hcrOn or isKeyword(s.name) or m.g.config.cppDefines.contains(res): + res.add "_0" + result = res.rope + s.loc.r = result writeMangledName(m.ndi, s, m.config) -proc fillLocalName(p: BProc; s: PSym) = +proc mangleLocalName(p: BProc; s: PSym): Rope = assert s.kind in skLocalVars+{skTemp} #assert sfGlobal notin s.flags - if s.loc.r == "": + result = s.loc.r + if result == nil: var key = s.name.s.mangle + shallow(key) let counter = p.sigConflicts.getOrDefault(key) - var result = key.rope + result = key.rope if s.kind == skTemp: # speed up conflict search for temps (these are quite common): if counter != 0: result.add "_" & rope(counter+1) @@ -92,6 +105,7 @@ proc scopeMangledParam(p: BProc; param: PSym) = ## generate unique identifiers reliably (consider that ``var a = a`` is ## even an idiom in Nim). var key = param.name.s.mangle + shallow(key) p.sigConflicts.inc(key) const @@ -99,12 +113,13 @@ const tyDistinct, tyRange, tyStatic, tyAlias, tySink, tyInferred, tyOwned} -proc typeName(typ: PType; result: var Rope) = +proc typeName(typ: PType): Rope = let typ = typ.skipTypes(irrelevantForBackend) - result.add $typ.kind - if typ.sym != nil and typ.kind in {tyObject, tyEnum}: - result.add "_" - result.add typ.sym.name.s.mangle + result = + if typ.sym != nil and typ.kind in {tyObject, tyEnum}: + rope($typ.kind & '_' & typ.sym.name.s.mangle) + else: + rope($typ.kind) proc getTypeName(m: BModule; typ: PType; sig: SigHash): Rope = var t = typ @@ -117,17 +132,14 @@ proc getTypeName(m: BModule; typ: PType; sig: SigHash): Rope = else: break let typ = if typ.kind in {tyAlias, tySink, tyOwned}: typ.lastSon else: typ - if typ.loc.r == "": - typ.typeName(typ.loc.r) - typ.loc.r.add $sig + if typ.loc.r == nil: + typ.loc.r = typ.typeName & $sig else: when defined(debugSigHashes): # check consistency: - var tn = newRopeAppender() - typ.typeName(tn) - assert($typ.loc.r == $(tn & $sig)) + assert($typ.loc.r == $(typ.typeName & $sig)) result = typ.loc.r - if result == "": internalError(m.config, "getTypeName: " & $typ.kind) + if result == nil: internalError(m.config, "getTypeName: " & $typ.kind) proc mapSetType(conf: ConfigRef; typ: PType): TCTypeKind = case int(getSize(conf, typ)) @@ -137,7 +149,7 @@ proc mapSetType(conf: ConfigRef; typ: PType): TCTypeKind = of 8: result = ctInt64 else: result = ctArray -proc mapType(conf: ConfigRef; typ: PType; kind: TSymKind): TCTypeKind = +proc mapType(conf: ConfigRef; typ: PType): TCTypeKind = ## Maps a Nim type to a C type case typ.kind of tyNone, tyTyped: result = ctVoid @@ -145,17 +157,14 @@ proc mapType(conf: ConfigRef; typ: PType; kind: TSymKind): TCTypeKind = of tyChar: result = ctChar of tyNil: result = ctPtr of tySet: result = mapSetType(conf, typ) - of tyOpenArray, tyVarargs: - if kind == skParam: result = ctArray - else: result = ctStruct - of tyArray, tyUncheckedArray: result = ctArray + of tyOpenArray, tyArray, tyVarargs, tyUncheckedArray: result = ctArray of tyObject, tyTuple: result = ctStruct of tyUserTypeClasses: doAssert typ.isResolvedUserTypeClass - return mapType(conf, typ.lastSon, kind) + return mapType(conf, typ.lastSon) of tyGenericBody, tyGenericInst, tyGenericParam, tyDistinct, tyOrdinal, tyTypeDesc, tyAlias, tySink, tyInferred, tyOwned: - result = mapType(conf, lastSon(typ), kind) + result = mapType(conf, lastSon(typ)) of tyEnum: if firstOrd(conf, typ) < 0: result = ctInt32 @@ -166,7 +175,7 @@ proc mapType(conf: ConfigRef; typ: PType; kind: TSymKind): TCTypeKind = of 4: result = ctInt32 of 8: result = ctInt64 else: result = ctInt32 - of tyRange: result = mapType(conf, typ[0], kind) + of tyRange: result = mapType(conf, typ[0]) of tyPtr, tyVar, tyLent, tyRef: var base = skipTypes(typ.lastSon, typedescInst) case base.kind @@ -179,18 +188,18 @@ proc mapType(conf: ConfigRef; typ: PType; kind: TSymKind): TCTypeKind = of tySequence: result = ctNimSeq of tyProc: result = if typ.callConv != ccClosure: ctProc else: ctStruct of tyString: result = ctNimStr - of tyCstring: result = ctCString + of tyCString: result = ctCString of tyInt..tyUInt64: result = TCTypeKind(ord(typ.kind) - ord(tyInt) + ord(ctInt)) of tyStatic: - if typ.n != nil: result = mapType(conf, lastSon typ, kind) - else: doAssert(false, "mapType: " & $typ.kind) - else: doAssert(false, "mapType: " & $typ.kind) + if typ.n != nil: result = mapType(conf, lastSon typ) + else: doAssert(false, "mapType") + else: doAssert(false, "mapType") proc mapReturnType(conf: ConfigRef; typ: PType): TCTypeKind = #if skipTypes(typ, typedescInst).kind == tyArray: result = ctPtr #else: - result = mapType(conf, typ, skResult) + result = mapType(conf, typ) proc isImportedType(t: PType): bool = result = t.sym != nil and sfImportc in t.sym.flags @@ -200,27 +209,20 @@ proc isImportedCppType(t: PType): bool = result = (t.sym != nil and sfInfixCall in t.sym.flags) or (x.sym != nil and sfInfixCall in x.sym.flags) -proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet; kind: TSymKind): Rope +proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope proc isObjLackingTypeField(typ: PType): bool {.inline.} = result = (typ.kind == tyObject) and ((tfFinal in typ.flags) and (typ[0] == nil) or isPureObject(typ)) -proc isInvalidReturnType(conf: ConfigRef; typ: PType, isProc = true): bool = +proc isInvalidReturnType(conf: ConfigRef; rettype: PType): bool = # Arrays and sets cannot be returned by a C procedure, because C is # such a poor programming language. # We exclude records with refs too. This enhances efficiency and # is necessary for proper code generation of assignments. - var rettype = typ - var isAllowedCall = true - if isProc: - rettype = rettype[0] - isAllowedCall = typ.callConv in {ccClosure, ccInline, ccNimCall} - if rettype == nil or (isAllowedCall and - getSize(conf, rettype) > conf.target.floatSize*3): - result = true + if rettype == nil: result = true else: - case mapType(conf, rettype, skResult) + case mapType(conf, rettype) of ctArray: result = not (skipTypes(rettype, typedescInst).kind in {tyVar, tyLent, tyRef, tyPtr}) @@ -236,7 +238,7 @@ const "N_STDCALL", "N_CDECL", "N_SAFECALL", "N_SYSCALL", # this is probably not correct for all platforms, # but one can #define it to what one wants - "N_INLINE", "N_NOINLINE", "N_FASTCALL", "N_THISCALL", "N_CLOSURE", "N_NOCONV"] + "N_INLINE", "N_NOINLINE", "N_FASTCALL", "N_CLOSURE", "N_NOCONV"] proc cacheGetType(tab: TypeCache; sig: SigHash): Rope = # returns nil if we need to declare this type @@ -245,20 +247,41 @@ proc cacheGetType(tab: TypeCache; sig: SigHash): Rope = result = tab.getOrDefault(sig) proc addAbiCheck(m: BModule, t: PType, name: Rope) = - if isDefined(m.config, "checkAbi") and (let size = getSize(m.config, t); size != szUnknownSize): - var msg = "backend & Nim disagree on size for: " - msg.addTypeHeader(m.config, t) - var msg2 = "" - msg2.addQuoted msg # not a hostspot so extra allocation doesn't matter - m.s[cfsTypeInfo].addf("NIM_STATIC_ASSERT(sizeof($1) == $2, $3);$n", [name, rope(size), msg2.rope]) - # see `testCodegenABICheck` for example error message it generates + if isDefined(m.config, "checkabi") and (let size = getSize(m.config, t); size != szUnknownSize): + m.s[cfsTypeInfo].addf("NIM_CHECK_SIZE($1, $2);$n", [name, rope(size)]) +proc ccgIntroducedPtr(conf: ConfigRef; s: PSym, retType: PType): bool = + var pt = skipTypes(s.typ, typedescInst) + assert skResult != s.kind -proc fillResult(conf: ConfigRef; param: PNode, proctype: PType) = - fillLoc(param.sym.loc, locParam, param, "Result", + 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 (optByRef in s.options) or (getSize(conf, pt) > conf.target.floatSize * 3): + result = true # requested anyway + elif retType != nil and retType.kind == tyLent: + result = true + elif (tfFinal in pt.flags) and (pt[0] == nil): + result = false # no need, because no subtyping possible + else: + result = true # ordinary objects are always passed by reference, + # otherwise casting doesn't work + of tyTuple: + if retType != nil and retType.kind == tyLent: + result = true + else: + result = (getSize(conf, pt) > conf.target.floatSize*3) or (optByRef in s.options) + else: result = false + +proc fillResult(conf: ConfigRef; param: PNode) = + fillLoc(param.sym.loc, locParam, param, ~"Result", OnStack) let t = param.sym.typ - if mapReturnType(conf, t) != ctArray and isInvalidReturnType(conf, proctype): + if mapReturnType(conf, t) != ctArray and isInvalidReturnType(conf, t): incl(param.sym.loc.flags, lfIndirect) param.sym.loc.storage = OnUnknown @@ -281,13 +304,13 @@ proc getSimpleTypeDesc(m: BModule, typ: PType): Rope = of tyString: case detectStrVersion(m) of 2: - cgsym(m, "NimStrPayload") - cgsym(m, "NimStringV2") + discard cgsym(m, "NimStrPayload") + discard cgsym(m, "NimStringV2") result = typeNameOrLiteral(m, typ, "NimStringV2") else: - cgsym(m, "NimStringDesc") + discard cgsym(m, "NimStringDesc") result = typeNameOrLiteral(m, typ, "NimStringDesc*") - of tyCstring: result = typeNameOrLiteral(m, typ, "NCSTRING") + of tyCString: result = typeNameOrLiteral(m, typ, "NCSTRING") of tyBool: result = typeNameOrLiteral(m, typ, "NIM_BOOL") of tyChar: result = typeNameOrLiteral(m, typ, "NIM_CHAR") of tyNil: result = typeNameOrLiteral(m, typ, "void*") @@ -299,12 +322,13 @@ proc getSimpleTypeDesc(m: BModule, typ: PType): Rope = else: internalError(m.config, "tyStatic for getSimpleTypeDesc") of tyGenericInst, tyAlias, tySink, tyOwned: result = getSimpleTypeDesc(m, lastSon typ) - else: result = "" + else: result = nil - if result != "" and typ.isImportedType(): - let sig = hashType(typ, m.config) - if cacheGetType(m.typeCache, sig) == "": + if result != nil and typ.isImportedType(): + let sig = hashType typ + if cacheGetType(m.typeCache, sig) == nil: m.typeCache[sig] = result + addAbiCheck(m, typ, result) proc pushType(m: BModule, typ: PType) = for i in 0..high(m.typeStack): @@ -316,11 +340,11 @@ proc getTypePre(m: BModule, typ: PType; sig: SigHash): Rope = if typ == nil: result = rope("void") else: result = getSimpleTypeDesc(m, typ) - if result == "": result = cacheGetType(m.typeCache, sig) + if result == nil: result = cacheGetType(m.typeCache, sig) proc structOrUnion(t: PType): Rope = - let cachedUnion = rope("union") - let cachedStruct = rope("struct") + let cachedUnion {.global.} = rope("union") + let cachedStruct {.global.} = rope("struct") let t = t.skipTypes({tyAlias, tySink}) if tfUnion in t.flags: cachedUnion else: cachedStruct @@ -337,10 +361,10 @@ proc seqStar(m: BModule): string = proc getTypeForward(m: BModule, typ: PType; sig: SigHash): Rope = result = cacheGetType(m.forwTypeCache, sig) - if result != "": return + if result != nil: return result = getTypePre(m, typ, sig) - if result != "": return - let concrete = typ.skipTypes(abstractInst) + if result != nil: return + let concrete = typ.skipTypes(abstractInst + {tyOpt}) case concrete.kind of tySequence, tyTuple, tyObject: result = getTypeName(m, typ, sig) @@ -352,7 +376,7 @@ proc getTypeForward(m: BModule, typ: PType; sig: SigHash): Rope = doAssert m.forwTypeCache[sig] == result else: internalError(m.config, "getTypeForward(" & $typ.kind & ')') -proc getTypeDescWeak(m: BModule; t: PType; check: var IntSet; kind: TSymKind): Rope = +proc getTypeDescWeak(m: BModule; t: PType; check: var IntSet): Rope = ## like getTypeDescAux but creates only a *weak* dependency. In other words ## we know we only need a pointer to it so we only generate a struct forward ## declaration: @@ -360,18 +384,18 @@ proc getTypeDescWeak(m: BModule; t: PType; check: var IntSet; kind: TSymKind): R case etB.kind of tyObject, tyTuple: if isImportedCppType(etB) and t.kind == tyGenericInst: - result = getTypeDescAux(m, t, check, kind) + result = getTypeDescAux(m, t, check) else: - result = getTypeForward(m, t, hashType(t, m.config)) + result = getTypeForward(m, t, hashType(t)) pushType(m, t) of tySequence: - let sig = hashType(t, m.config) + let sig = hashType(t) if optSeqDestructors in m.config.globalOptions: if skipTypes(etB[0], typedescInst).kind == tyEmpty: internalError(m.config, "cannot map the empty seq type to a C type") result = cacheGetType(m.forwTypeCache, sig) - if result == "": + if result == nil: result = getTypeName(m, t, sig) if not isImportedType(t): m.forwTypeCache[sig] = result @@ -379,7 +403,7 @@ proc getTypeDescWeak(m: BModule; t: PType; check: var IntSet; kind: TSymKind): R let payload = result & "_Content" addForwardStructFormat(m, rope"struct", payload) - if cacheGetType(m.typeCache, sig) == "": + if cacheGetType(m.typeCache, sig) == nil: m.typeCache[sig] = result #echo "adding ", sig, " ", typeToString(t), " ", m.module.name.s appcg(m, m.s[cfsTypes], @@ -390,18 +414,18 @@ proc getTypeDescWeak(m: BModule; t: PType; check: var IntSet; kind: TSymKind): R result = getTypeForward(m, t, sig) & seqStar(m) pushType(m, t) else: - result = getTypeDescAux(m, t, check, kind) + result = getTypeDescAux(m, t, check) proc getSeqPayloadType(m: BModule; t: PType): Rope = var check = initIntSet() - result = getTypeDescWeak(m, t, check, skParam) & "_Content" + result = getTypeDescWeak(m, t, check) & "_Content" #result = getTypeForward(m, t, hashType(t)) & "_Content" proc seqV2ContentType(m: BModule; t: PType; check: var IntSet) = - let sig = hashType(t, m.config) + let sig = hashType(t) let result = cacheGetType(m.typeCache, sig) - if result == "": - discard getTypeDescAux(m, t, check, skVar) + if result == nil: + discard getTypeDescAux(m, t, check) else: # little hack for now to prevent multiple definitions of the same # Seq_Content: @@ -410,7 +434,7 @@ $3ifndef $2_Content_PP $3define $2_Content_PP struct $2_Content { NI cap; $1 data[SEQ_DECL_SIZE];}; $3endif$N - """, [getTypeDescAux(m, t.skipTypes(abstractInst)[0], check, skVar), result, rope"#"]) + """, [getTypeDescAux(m, t.skipTypes(abstractInst)[0], check), result, rope"#"]) proc paramStorageLoc(param: PSym): TStorageLoc = if param.typ.skipTypes({tyVar, tyLent, tyTypeDesc}).kind notin { @@ -422,34 +446,31 @@ proc paramStorageLoc(param: PSym): TStorageLoc = proc genProcParams(m: BModule, t: PType, rettype, params: var Rope, check: var IntSet, declareEnvironment=true; weakDep=false) = - params = "(" - if t[0] == nil or isInvalidReturnType(m.config, t): - rettype = "void" + params = nil + if t[0] == nil or isInvalidReturnType(m.config, t[0]): + rettype = ~"void" else: - rettype = getTypeDescAux(m, t[0], check, skResult) + rettype = getTypeDescAux(m, t[0], check) for i in 1..raiseId) #popCurrentExceptionEx(this->raiseId);}$n", [name]) + appcg(m, result, "virtual void raise() { throw *this; }$n", []) # required for polymorphic exceptions + if typ.sym.magic == mException: + # Add cleanup destructor to Exception base class + appcg(m, result, "~$1();$n", [name]) + # define it out of the class body and into the procs section so we don't have to + # artificially forward-declare popCurrentExceptionEx (very VERY troublesome for HCR) + appcg(m, cfsProcs, "inline $1::~$1() {if(this->raiseId) #popCurrentExceptionEx(this->raiseId);}$n", [name]) hasField = true else: appcg(m, result, " {$n $1 Sup;$n", - [getTypeDescAux(m, typ[0].skipTypes(skipPtrs), check, skField)]) + [getTypeDescAux(m, typ[0].skipTypes(skipPtrs), check)]) hasField = true else: result.addf(" {$n", [name]) let desc = getRecordFields(m, typ, check) - if desc == "" and not hasField: + if desc == nil and not hasField: result.addf("char dummy;$n", []) else: result.add(desc) @@ -626,11 +636,11 @@ proc getRecordDesc(m: BModule, typ: PType, name: Rope, proc getTupleDesc(m: BModule, typ: PType, name: Rope, check: var IntSet): Rope = result = "$1 $2 {$n" % [structOrUnion(typ), name] - var desc: Rope = "" + var desc: Rope = nil for i in 0.. 1: result.add(" COMMA ") - addResultType(tt[i]) + addResultType(origTyp[i]) result.add("> ") # always call for sideeffects: assert t.kind != tyTuple @@ -869,13 +860,13 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet; kind: TSymKin # The resulting type will include commas and these won't play well # with the C macros for defining procs such as N_NIMCALL. We must # create a typedef for the type and use it in the proc signature: - let typedefName = "TY" & $sig + let typedefName = ~"TY" & $sig m.s[cfsTypes].addf("typedef $1 $2;$n", [result, typedefName]) m.typeCache[sig] = typedefName result = typedefName else: result = cacheGetType(m.forwTypeCache, sig) - if result == "": + if result == nil: result = getTypeName(m, origTyp, sig) m.forwTypeCache[sig] = result if not isImportedType(t): @@ -887,13 +878,9 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet; kind: TSymKin else: getTupleDesc(m, t, result, check) if not isImportedType(t): m.s[cfsTypes].add(recdesc) - elif tfIncompleteStruct notin t.flags: - discard # addAbiCheck(m, t, result) # already handled elsewhere + elif tfIncompleteStruct notin t.flags: addAbiCheck(m, t, result) of tySet: - # Don't use the imported name as it may be scoped: 'Foo::SomeKind' - result = rope("tySet_") - t.lastSon.typeName(result) - result.add $t.lastSon.hashType(m.config) + result = $t.kind & '_' & getTypeName(m, t.lastSon, hashType t.lastSon) m.typeCache[sig] = result if not isImportedType(t): let s = int(getSize(m.config, t)) @@ -903,16 +890,16 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet; kind: TSymKin [result, rope(getSize(m.config, t))]) of tyGenericInst, tyDistinct, tyOrdinal, tyTypeDesc, tyAlias, tySink, tyOwned, tyUserTypeClass, tyUserTypeClassInst, tyInferred: - result = getTypeDescAux(m, lastSon(t), check, kind) + result = getTypeDescAux(m, lastSon(t), check) else: internalError(m.config, "getTypeDescAux(" & $t.kind & ')') - result = "" + result = nil # fixes bug #145: excl(check, t.id) -proc getTypeDesc(m: BModule, typ: PType; kind = skParam): Rope = +proc getTypeDesc(m: BModule, typ: PType): Rope = var check = initIntSet() - result = getTypeDescAux(m, typ, check, kind) + result = getTypeDescAux(m, typ, check) type TClosureTypeKind = enum ## In C closures are mapped to 3 different things. @@ -944,9 +931,8 @@ proc finishTypeDescriptions(m: BModule) = if optSeqDestructors in m.config.globalOptions and t.skipTypes(abstractInst).kind == tySequence: seqV2ContentType(m, t, check) else: - discard getTypeDescAux(m, t, check, skParam) + discard getTypeDescAux(m, t, check) inc(i) - m.typeStack.setLen 0 template cgDeclFrmt*(s: PSym): string = s.constraint.strVal @@ -957,12 +943,21 @@ proc isReloadable(m: BModule, prc: PSym): bool = proc isNonReloadable(m: BModule, prc: PSym): bool = return m.hcrOn and sfNonReloadable in prc.flags -proc genProcHeader(m: BModule, prc: PSym; result: var Rope; asPtr: bool = false) = +proc genProcHeader(m: BModule, prc: PSym, asPtr: bool = false): Rope = + var + rettype, params: Rope # using static is needed for inline procs + if lfExportLib in prc.loc.flags: + if isHeaderFile in m.flags: + result.add "N_LIB_IMPORT " + else: + result.add "N_LIB_EXPORT " + elif prc.typ.callConv == ccInline or asPtr or isNonReloadable(m, prc): + result.add "static " + elif sfImportc notin prc.flags: + result.add "N_LIB_PRIVATE " var check = initIntSet() - fillBackendName(m, prc) - fillLoc(prc.loc, locProc, prc.ast[namePos], OnUnknown) - var rettype, params: Rope + fillLoc(prc.loc, locProc, prc.ast[namePos], mangleName(m, prc), OnUnknown) genProcParams(m, prc.typ, rettype, params, check) # handle the 2 options for hotcodereloading codegen - function pointer # (instead of forward declaration) or header for function body with "_actual" postfix @@ -973,25 +968,16 @@ proc genProcHeader(m: BModule, prc: PSym; result: var Rope; asPtr: bool = false) # careful here! don't access ``prc.ast`` as that could reload large parts of # the object graph! if prc.constraint.isNil: - if lfExportLib in prc.loc.flags: - if isHeaderFile in m.flags: - result.add "N_LIB_IMPORT " - else: - result.add "N_LIB_EXPORT " - elif prc.typ.callConv == ccInline or asPtr or isNonReloadable(m, prc): - result.add "static " - elif sfImportc notin prc.flags: - result.add "N_LIB_PRIVATE " result.addf("$1$2($3, $4)$5", [rope(CallingConvToStr[prc.typ.callConv]), asPtrStr, rettype, name, params]) else: let asPtrStr = if asPtr: (rope("(*") & name & ")") else: name - result.add runtimeFormat(prc.cgDeclFrmt, [rettype, asPtrStr, params]) + result = runtimeFormat(prc.cgDeclFrmt, [rettype, asPtrStr, params]) # ------------------ type info generation ------------------------------------- -proc genTypeInfoV1(m: BModule, t: PType; info: TLineInfo): Rope +proc genTypeInfo(m: BModule, t: PType; info: TLineInfo): Rope proc getNimNode(m: BModule): Rope = result = "$1[$2]" % [m.typeNodesName, rope(m.typeNodes)] inc(m.typeNodes) @@ -1011,22 +997,19 @@ proc genTypeInfoAuxBase(m: BModule; typ, origType: PType; let nameHcr = tiNameForHcr(m, name) var size: Rope - if tfIncompleteStruct in typ.flags: - size = rope"void*" - else: - size = getTypeDesc(m, origType, skVar) + if tfIncompleteStruct in typ.flags: size = rope"void*" + else: size = getTypeDesc(m, origType) m.s[cfsTypeInit3].addf( - "$1.size = sizeof($2);$n$1.align = NIM_ALIGNOF($2);$n$1.kind = $3;$n$1.base = $4;$n", - [nameHcr, size, rope(nimtypeKind), base] - ) + "$1.size = sizeof($2);$n" & "$1.kind = $3;$n" & "$1.base = $4;$n", + [nameHcr, size, rope(nimtypeKind), base]) # compute type flags for GC optimization var flags = 0 if not containsGarbageCollectedRef(typ): flags = flags or 1 if not canFormAcycle(typ): flags = flags or 2 - #else echo("can contain a cycle: " & typeToString(typ)) + #else MessageOut("can contain a cycle: " & typeToString(typ)) if flags != 0: m.s[cfsTypeInit3].addf("$1.flags = $2;$n", [nameHcr, rope(flags)]) - cgsym(m, "TNimType") + discard cgsym(m, "TNimType") if isDefined(m.config, "nimTypeNames"): var typename = typeToString(if origType.typeInst != nil: origType.typeInst else: origType, preferName) @@ -1034,16 +1017,16 @@ proc genTypeInfoAuxBase(m: BModule; typ, origType: PType; typename = "anon ref object from " & m.config$origType.skipTypes(skipPtrs).sym.info m.s[cfsTypeInit3].addf("$1.name = $2;$n", [nameHcr, makeCString typename]) - cgsym(m, "nimTypeRoot") + discard cgsym(m, "nimTypeRoot") m.s[cfsTypeInit3].addf("$1.nextType = nimTypeRoot; nimTypeRoot=&$1;$n", [nameHcr]) if m.hcrOn: - m.s[cfsStrData].addf("static TNimType* $1;$n", [name]) + m.s[cfsData].addf("static TNimType* $1;$n", [name]) m.hcrCreateTypeInfosProc.addf("\thcrRegisterGlobal($2, \"$1\", sizeof(TNimType), NULL, (void**)&$1);$n", [name, getModuleDllPath(m, m.module)]) else: - m.s[cfsStrData].addf("N_LIB_PRIVATE TNimType $1;$n", [name]) + m.s[cfsData].addf("N_LIB_PRIVATE TNimType $1;$n", [name]) proc genTypeInfoAux(m: BModule, typ, origType: PType, name: Rope; info: TLineInfo) = @@ -1054,7 +1037,7 @@ proc genTypeInfoAux(m: BModule, typ, origType: PType, name: Rope; if typ.kind == tyPtr and x.kind == tyObject and incompleteType(x): base = rope("0") else: - base = genTypeInfoV1(m, x, info) + base = genTypeInfo(m, x, info) else: base = rope("0") genTypeInfoAuxBase(m, typ, origType, name, base, info) @@ -1066,12 +1049,12 @@ proc discriminatorTableName(m: BModule, objtype: PType, d: PSym): Rope = objtype = objtype[0].skipTypes(abstractPtrs) if objtype.sym == nil: internalError(m.config, d.info, "anonymous obj with discriminator") - result = "NimDT_$1_$2" % [rope($hashType(objtype, m.config)), rope(d.name.s.mangle)] + result = "NimDT_$1_$2" % [rope($hashType(objtype)), rope(d.name.s.mangle)] proc rope(arg: Int128): Rope = rope($arg) proc discriminatorTableDecl(m: BModule, objtype: PType, d: PSym): Rope = - cgsym(m, "TNimNode") + discard cgsym(m, "TNimNode") var tmp = discriminatorTableName(m, objtype, d) result = "TNimNode* $1[$2];$n" % [tmp, rope(lengthOrd(m.config, d.typ)+1)] @@ -1106,14 +1089,14 @@ proc genObjectFields(m: BModule, typ, origType: PType, n: PNode, expr: Rope; var tmp = discriminatorTableName(m, typ, field) var L = lengthOrd(m.config, field.typ) assert L > 0 - if field.loc.r == "": fillObjectFields(m, typ) + if field.loc.r == nil: fillObjectFields(m, typ) if field.loc.t == nil: internalError(m.config, n.info, "genObjectFields") m.s[cfsTypeInit3].addf("$1.kind = 3;$n" & "$1.offset = offsetof($2, $3);$n" & "$1.typ = $4;$n" & "$1.name = $5;$n" & "$1.sons = &$6[0];$n" & - "$1.len = $7;$n", [expr, getTypeDesc(m, origType, skVar), field.loc.r, - genTypeInfoV1(m, field.typ, info), + "$1.len = $7;$n", [expr, getTypeDesc(m, origType), field.loc.r, + genTypeInfo(m, field.typ, info), makeCString(field.name.s), tmp, rope(L)]) m.s[cfsData].addf("TNimNode* $1[$2];$n", [tmp, rope(L+1)]) @@ -1144,13 +1127,13 @@ proc genObjectFields(m: BModule, typ, origType: PType, n: PNode, expr: Rope; # Do not produce code for void types if isEmptyType(field.typ): return if field.bitsize == 0: - if field.loc.r == "": fillObjectFields(m, typ) + if field.loc.r == nil: fillObjectFields(m, typ) if field.loc.t == nil: internalError(m.config, n.info, "genObjectFields") m.s[cfsTypeInit3].addf("$1.kind = 1;$n" & "$1.offset = offsetof($2, $3);$n" & "$1.typ = $4;$n" & - "$1.name = $5;$n", [expr, getTypeDesc(m, origType, skVar), - field.loc.r, genTypeInfoV1(m, field.typ, info), makeCString(field.name.s)]) + "$1.name = $5;$n", [expr, getTypeDesc(m, origType), + field.loc.r, genTypeInfo(m, field.typ, info), makeCString(field.name.s)]) else: internalError(m.config, n.info, "genObjectFields") proc genObjectInfo(m: BModule, typ, origType: PType, name: Rope; info: TLineInfo) = @@ -1185,7 +1168,7 @@ proc genTupleInfo(m: BModule, typ, origType: PType, name: Rope; info: TLineInfo) "$1.offset = offsetof($2, Field$3);$n" & "$1.typ = $4;$n" & "$1.name = \"Field$3\";$n", - [tmp2, getTypeDesc(m, origType, skVar), rope(i), genTypeInfoV1(m, a, info)]) + [tmp2, getTypeDesc(m, origType), rope(i), genTypeInfo(m, a, info)]) m.s[cfsTypeInit3].addf("$1.len = $2; $1.kind = 2; $1.sons = &$3[0];$n", [expr, rope(typ.len), tmp]) else: @@ -1238,18 +1221,18 @@ proc genSetInfo(m: BModule, typ: PType, name: Rope; info: TLineInfo) = assert(typ[0] != nil) genTypeInfoAux(m, typ, typ, name, info) var tmp = getNimNode(m) - m.s[cfsTypeInit3].addf("$1.len = $2; $1.kind = 0;$n$3.node = &$1;$n", + m.s[cfsTypeInit3].addf("$1.len = $2; $1.kind = 0;$n" & "$3.node = &$1;$n", [tmp, rope(firstOrd(m.config, typ)), tiNameForHcr(m, name)]) proc genArrayInfo(m: BModule, typ: PType, name: Rope; info: TLineInfo) = - genTypeInfoAuxBase(m, typ, typ, name, genTypeInfoV1(m, typ[1], info), info) + genTypeInfoAuxBase(m, typ, typ, name, genTypeInfo(m, typ[1], info), info) proc fakeClosureType(m: BModule; owner: PSym): PType = # we generate the same RTTI as for a tuple[pointer, ref tuple[]] - result = newType(tyTuple, nextTypeId m.idgen, owner) - result.rawAddSon(newType(tyPointer, nextTypeId m.idgen, owner)) - var r = newType(tyRef, nextTypeId m.idgen, owner) - let obj = createObj(m.g.graph, m.idgen, owner, owner.info, final=false) + result = newType(tyTuple, owner) + result.rawAddSon(newType(tyPointer, owner)) + var r = newType(tyRef, owner) + let obj = createObj(m.g.graph, owner, owner.info, final=false) r.rawAddSon(obj) result.rawAddSon(r) @@ -1260,355 +1243,161 @@ proc genDeepCopyProc(m: BModule; s: PSym; result: Rope) = m.s[cfsTypeInit3].addf("$1.deepcopy =(void* (N_RAW_NIMCALL*)(void*))$2;$n", [result, s.loc.r]) -proc declareNimType(m: BModule, name: string; str: Rope, module: int) = - let nr = rope(name) +proc declareNimType(m: BModule, str: Rope, ownerModule: PSym) = if m.hcrOn: - m.s[cfsStrData].addf("static $2* $1;$n", [str, nr]) - m.s[cfsTypeInit1].addf("\t$1 = ($3*)hcrGetGlobal($2, \"$1\");$n", - [str, getModuleDllPath(m, module), nr]) + m.s[cfsData].addf("static TNimType* $1;$n", [str]) + m.s[cfsTypeInit1].addf("\t$1 = (TNimType*)hcrGetGlobal($2, \"$1\");$n", + [str, getModuleDllPath(m, ownerModule)]) else: - m.s[cfsStrData].addf("extern $2 $1;$n", [str, nr]) + m.s[cfsData].addf("extern TNimType $1;$n", [str]) proc genTypeInfo2Name(m: BModule; t: PType): Rope = + var res = "|" var it = t - it = it.skipTypes(skipPtrs) - if it.sym != nil and tfFromGeneric notin it.flags: - var m = it.sym.owner - while m != nil and m.kind != skModule: m = m.owner - if m == nil or sfSystemModule in m.flags: - # produce short names for system types: - result = it.sym.name.s + while it != nil: + it = it.skipTypes(skipPtrs) + if it.sym != nil: + var m = it.sym.owner + while m != nil and m.kind != skModule: m = m.owner + if m == nil or sfSystemModule in m.flags: + # produce short names for system types: + res.add it.sym.name.s + else: + var p = m.owner + if p != nil and p.kind == skPackage: + res.add p.name.s & "." + res.add m.name.s & "." + res.add it.sym.name.s else: - var p = m.owner - if p != nil and p.kind == skPackage: - result.add p.name.s & "." - result.add m.name.s & "." - result.add it.sym.name.s - else: - result = $hashType(it, m.config) - result = makeCString(result) + res.add $hashType(it) + res.add "|" + it = it[0] + result = makeCString(res) -proc isTrivialProc(g: ModuleGraph; s: PSym): bool {.inline.} = getBody(g, s).len == 0 +proc isTrivialProc(s: PSym): bool {.inline.} = s.ast[bodyPos].len == 0 -proc genHook(m: BModule; t: PType; info: TLineInfo; op: TTypeAttachedOp; result: var Rope) = - let theProc = getAttachedOp(m.g.graph, t, op) - if theProc != nil and not isTrivialProc(m.g.graph, theProc): +proc genHook(m: BModule; t: PType; info: TLineInfo; op: TTypeAttachedOp): Rope = + let theProc = t.attachedOps[op] + if theProc != nil and not isTrivialProc(theProc): # the prototype of a destructor is ``=destroy(x: var T)`` and that of a # finalizer is: ``proc (x: ref T) {.nimcall.}``. We need to check the calling # convention at least: - if theProc.typ == nil or theProc.typ.callConv != ccNimCall: + if theProc.typ == nil or theProc.typ.callConv != ccDefault: localError(m.config, info, theProc.name.s & " needs to have the 'nimcall' calling convention") genProc(m, theProc) - result.add theProc.loc.r - - when false: - if not canFormAcycle(t) and op == attachedTrace: - echo "ayclic but has this =trace ", t, " ", theProc.ast + result = theProc.loc.r else: - when false: - if op == attachedTrace and m.config.selectedGC == gcOrc and - containsGarbageCollectedRef(t): - # unfortunately this check is wrong for an object type that only contains - # .cursor fields like 'Node' inside 'cycleleak'. - internalError(m.config, info, "no attached trace proc found") - result.add rope("NIM_NIL") + result = rope("NIM_NIL") -proc getObjDepth(t: PType): int16 = - var x = t - result = -1 - while x != nil: - x = skipTypes(x, skipPtrs) - x = x[0] - inc(result) - -proc genDisplayElem(d: MD5Digest): uint32 = - result = 0 - for i in 0..3: - result += uint32(d[i]) - result = result shl 8 - -proc genDisplay(m: BModule, t: PType, depth: int): Rope = - result = Rope"{" - var x = t - var seqs = newSeq[string](depth+1) - var i = 0 - while x != nil: - x = skipTypes(x, skipPtrs) - seqs[i] = $genDisplayElem(MD5Digest(hashType(x, m.config))) - x = x[0] - inc i - - for i in countdown(depth, 1): - result.add seqs[i] & ", " - result.add seqs[0] - result.add "}" - -proc genTypeInfoV2OldImpl(m: BModule; t, origType: PType, name: Rope; info: TLineInfo) = - cgsym(m, "TNimTypeV2") - m.s[cfsStrData].addf("N_LIB_PRIVATE TNimTypeV2 $1;$n", [name]) - - var flags = 0 - if not canFormAcycle(t): flags = flags or 1 - - var typeEntry = newRopeAppender() - addf(typeEntry, "$1.destructor = (void*)", [name]) - genHook(m, t, info, attachedDestructor, typeEntry) - - addf(typeEntry, "; $1.traceImpl = (void*)", [name]) - genHook(m, t, info, attachedTrace, typeEntry) - - let objDepth = if t.kind == tyObject: getObjDepth(t) else: -1 - - if t.kind in {tyObject, tyDistinct} and incompleteType(t): - localError(m.config, info, "request for RTTI generation for incomplete object: " & - typeToString(t)) - - if isDefined(m.config, "nimTypeNames"): - var typeName: Rope - if t.kind in {tyObject, tyDistinct}: - typeName = genTypeInfo2Name(m, t) - else: - typeName = rope("NIM_NIL") - addf(typeEntry, "; $1.name = $2", [name, typeName]) - addf(typeEntry, "; $1.size = sizeof($2); $1.align = (NI16) NIM_ALIGNOF($2); $1.depth = $3; $1.flags = $4;", - [name, getTypeDesc(m, t), rope(objDepth), rope(flags)]) - - if objDepth >= 0: - let objDisplay = genDisplay(m, t, objDepth) - let objDisplayStore = getTempName(m) - m.s[cfsVars].addf("static $1 $2[$3] = $4;$n", [getTypeDesc(m, getSysType(m.g.graph, unknownLineInfo, tyUInt32), skVar), objDisplayStore, rope(objDepth+1), objDisplay]) - addf(typeEntry, "$1.display = $2;$n", [name, rope(objDisplayStore)]) - - m.s[cfsTypeInit3].add typeEntry - - if t.kind == tyObject and t.len > 0 and t[0] != nil and optEnableDeepCopy in m.config.globalOptions: - discard genTypeInfoV1(m, t, info) - -proc genTypeInfoV2Impl(m: BModule; t, origType: PType, name: Rope; info: TLineInfo) = - cgsym(m, "TNimTypeV2") - m.s[cfsStrData].addf("N_LIB_PRIVATE TNimTypeV2 $1;$n", [name]) - - var flags = 0 - if not canFormAcycle(t): flags = flags or 1 - - var typeEntry = newRopeAppender() - addf(typeEntry, "N_LIB_PRIVATE TNimTypeV2 $1 = {", [name]) - add(typeEntry, ".destructor = (void*)") - genHook(m, t, info, attachedDestructor, typeEntry) - - let objDepth = if t.kind == tyObject: getObjDepth(t) else: -1 - - if t.kind in {tyObject, tyDistinct} and incompleteType(t): - localError(m.config, info, "request for RTTI generation for incomplete object: " & - typeToString(t)) - - addf(typeEntry, ", .size = sizeof($1), .align = (NI16) NIM_ALIGNOF($1), .depth = $2", - [getTypeDesc(m, t), rope(objDepth)]) - - if objDepth >= 0: - let objDisplay = genDisplay(m, t, objDepth) - let objDisplayStore = getTempName(m) - m.s[cfsVars].addf("static NIM_CONST $1 $2[$3] = $4;$n", [getTypeDesc(m, getSysType(m.g.graph, unknownLineInfo, tyUInt32), skVar), objDisplayStore, rope(objDepth+1), objDisplay]) - addf(typeEntry, ", .display = $1", [rope(objDisplayStore)]) - if isDefined(m.config, "nimTypeNames"): - var typeName: Rope - if t.kind in {tyObject, tyDistinct}: - typeName = genTypeInfo2Name(m, t) - else: - typeName = rope("NIM_NIL") - addf(typeEntry, ", .name = $1", [typeName]) - add(typeEntry, ", .traceImpl = (void*)") - genHook(m, t, info, attachedTrace, typeEntry) - - addf(typeEntry, ", .flags = $1};$n", [rope(flags)]) - m.s[cfsVars].add typeEntry - - if t.kind == tyObject and t.len > 0 and t[0] != nil and optEnableDeepCopy in m.config.globalOptions: - discard genTypeInfoV1(m, t, info) - -proc genTypeInfoV2(m: BModule, t: PType; info: TLineInfo): Rope = - let origType = t - # distinct types can have their own destructors - var t = skipTypes(origType, irrelevantForBackend + tyUserTypeClasses - {tyDistinct}) - - let prefixTI = if m.hcrOn: "(" else: "(&" - - let sig = hashType(origType, m.config) - result = m.typeInfoMarkerV2.getOrDefault(sig) - if result != "": - return prefixTI.rope & result & ")".rope - - let marker = m.g.typeInfoMarkerV2.getOrDefault(sig) - if marker.str != "": - cgsym(m, "TNimTypeV2") - declareNimType(m, "TNimTypeV2", marker.str, marker.owner) - # also store in local type section: - m.typeInfoMarkerV2[sig] = marker.str - return prefixTI.rope & marker.str & ")".rope - - result = "NTIv2$1_" % [rope($sig)] - m.typeInfoMarkerV2[sig] = result - - let owner = t.skipTypes(typedescPtrs).itemId.module - if owner != m.module.position and moduleOpenForCodegen(m.g.graph, FileIndex owner): - # make sure the type info is created in the owner module - discard genTypeInfoV2(m.g.modules[owner], origType, info) - # reference the type info as extern here - cgsym(m, "TNimTypeV2") - declareNimType(m, "TNimTypeV2", result, owner) - return prefixTI.rope & result & ")".rope - - m.g.typeInfoMarkerV2[sig] = (str: result, owner: owner) - if m.compileToCpp: - genTypeInfoV2OldImpl(m, t, origType, result, info) +proc genTypeInfoV2(m: BModule, t, origType: PType, name: Rope; info: TLineInfo) = + var typeName: Rope + if t.kind == tyObject: + if incompleteType(t): + localError(m.config, info, "request for RTTI generation for incomplete object: " & + typeToString(t)) + typeName = genTypeInfo2Name(m, t) else: - genTypeInfoV2Impl(m, t, origType, result, info) - result = prefixTI.rope & result & ")".rope + typeName = rope("NIM_NIL") -proc openArrayToTuple(m: BModule; t: PType): PType = - result = newType(tyTuple, nextTypeId m.idgen, t.owner) - let p = newType(tyPtr, nextTypeId m.idgen, t.owner) - let a = newType(tyUncheckedArray, nextTypeId m.idgen, t.owner) - a.add t.lastSon - p.add a - result.add p - result.add getSysType(m.g.graph, t.owner.info, tyInt) + m.s[cfsData].addf("N_LIB_PRIVATE TNimType $1;$n", [name]) + let destroyImpl = genHook(m, t, info, attachedDestructor) + let traceImpl = genHook(m, t, info, attachedTrace) + let disposeImpl = genHook(m, t, info, attachedDispose) -proc typeToC(t: PType): string = - ## Just for more readable names, the result doesn't have - ## to be unique. - let s = typeToString(t) - result = newStringOfCap(s.len) - for i in 0..typeInfoV1 = (void*)&$2; $2.typeInfoV2 = (void*)$1;$n", [ - v2info, result]) + of tyStatic: + if t.n != nil: result = genTypeInfo(m, lastSon t, info) + else: internalError(m.config, "genTypeInfo(" & $t.kind & ')') + of tyUserTypeClasses: + internalAssert m.config, t.isResolvedUserTypeClass + return genTypeInfo(m, t.lastSon, info) + of tyProc: + if t.callConv != ccClosure: + genTypeInfoAuxBase(m, t, t, result, rope"0", info) + else: + let x = fakeClosureType(m, t.owner) + genTupleInfo(m, x, x, result, info) + of tySequence: + genTypeInfoAux(m, t, t, result, info) + if optSeqDestructors notin m.config.globalOptions: + if m.config.selectedGC >= gcMarkAndSweep: + let markerProc = genTraverseProc(m, origType, sig) + m.s[cfsTypeInit3].addf("$1.marker = $2;$n", [tiNameForHcr(m, result), markerProc]) + of tyRef: + genTypeInfoAux(m, t, t, result, info) + if m.config.selectedGC >= gcMarkAndSweep: + let markerProc = genTraverseProc(m, origType, sig) + m.s[cfsTypeInit3].addf("$1.marker = $2;$n", [tiNameForHcr(m, result), markerProc]) + of tyPtr, tyRange, tyUncheckedArray: genTypeInfoAux(m, t, t, result, info) + of tyArray: genArrayInfo(m, t, result, info) + of tySet: genSetInfo(m, t, result, info) + of tyEnum: genEnumInfo(m, t, result, info) + of tyObject: + genObjectInfo(m, t, origType, result, info) + of tyTuple: + # if t.n != nil: genObjectInfo(m, t, result) + # else: + # BUGFIX: use consistently RTTI without proper field names; otherwise + # results are not deterministic! + genTupleInfo(m, t, origType, result, info) + else: internalError(m.config, "genTypeInfo(" & $t.kind & ')') + if t.attachedOps[attachedDeepCopy] != nil: + genDeepCopyProc(m, t.attachedOps[attachedDeepCopy], result) + elif origType.attachedOps[attachedDeepCopy] != nil: + genDeepCopyProc(m, origType.attachedOps[attachedDeepCopy], result) result = prefixTI.rope & result & ")".rope proc genTypeSection(m: BModule, n: PNode) = discard - -proc genTypeInfo*(config: ConfigRef, m: BModule, t: PType; info: TLineInfo): Rope = - if optTinyRtti in config.globalOptions: - result = genTypeInfoV2(m, t, info) - else: - result = genTypeInfoV1(m, t, info) diff --git a/compiler/ccgutils.nim b/compiler/ccgutils.nim index d86ebe461..f2a8c1e36 100644 --- a/compiler/ccgutils.nim +++ b/compiler/ccgutils.nim @@ -10,11 +10,8 @@ # This module declares some helpers for the C code generator. import - ast, types, hashes, strutils, msgs, wordrecg, - platform, trees, options, cgendata - -when defined(nimPreviewSlimSystem): - import std/assertions + ast, hashes, strutils, msgs, wordrecg, + platform, trees, options proc getPragmaStmt*(n: PNode, w: TSpecialWord): PNode = case n.kind @@ -53,7 +50,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 @@ -109,39 +106,3 @@ proc mangle*(name: string): string = requiresUnderscore = true if requiresUnderscore: result.add "_" - -proc mapSetType(conf: ConfigRef; typ: PType): TCTypeKind = - case int(getSize(conf, typ)) - of 1: result = ctInt8 - of 2: result = ctInt16 - of 4: result = ctInt32 - of 8: result = ctInt64 - else: result = ctArray - -proc ccgIntroducedPtr*(conf: ConfigRef; s: PSym, retType: PType): bool = - var pt = skipTypes(s.typ, typedescInst) - assert skResult != s.kind - - 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 (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): - result = false # no need, because no subtyping possible - else: - result = true # ordinary objects are always passed by reference, - # otherwise casting doesn't work - of tyTuple: - result = (getSize(conf, pt) > conf.target.floatSize*3) or (optByRef in s.options) - else: - result = false - # first parameter and return type is 'lent T'? --> use pass by pointer - if s.position == 0 and retType != nil and retType.kind == tyLent: - result = not (pt.kind in {tyVar, tyArray, tyOpenArray, tyVarargs, tyRef, tyPtr, tyPointer} or - pt.kind == tySet and mapSetType(conf, pt) == ctArray) - diff --git a/compiler/cgen.nim b/compiler/cgen.nim index d2095016c..fd14817e0 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -12,22 +12,19 @@ import ast, astalgo, hashes, trees, platform, magicsys, extccomp, options, intsets, nversion, nimsets, msgs, bitsets, idents, types, - ccgutils, os, ropes, math, wordrecg, treetab, cgmeth, - rodutils, renderer, cgendata, aliases, - lowerings, tables, sets, ndi, lineinfos, pathutils, transf, - injectdestructors, astmsgs, modulepaths, backendpragmas - -import pipelineutils - -when defined(nimPreviewSlimSystem): - import std/assertions + ccgutils, os, ropes, math, passes, wordrecg, treetab, cgmeth, + rodutils, renderer, cgendata, ccgmerge, aliases, + lowerings, tables, sets, ndi, lineinfos, pathutils, transf, enumtostr, + injectdestructors when not defined(leanCompiler): import spawn, semparallel -import strutils except `%`, addf # collides with ropes.`%` +import strutils except `%` # collides with ropes.`%` -from ic / ic import ModuleBackendFlag +from modulegraphs import ModuleGraph, PPassContext +from lineinfos import + warnGcMem, errXMustBeCompileTime, hintDependency, errGenerated, errCannotOpenFile import dynlib when not declared(dynlib.libCandidates): @@ -53,35 +50,23 @@ proc addForwardedProc(m: BModule, prc: PSym) = m.g.forwardedProcs.add(prc) proc findPendingModule(m: BModule, s: PSym): BModule = - # TODO fixme - if m.config.symbolFiles == v2Sf: - let ms = s.itemId.module #getModule(s) - result = m.g.modules[ms] - else: - var ms = getModule(s) - result = m.g.modules[ms.position] + var ms = getModule(s) + result = m.g.modules[ms.position] proc initLoc(result: var TLoc, k: TLocKind, lode: PNode, s: TStorageLoc) = result.k = k result.storage = s result.lode = lode - result.r = "" + result.r = nil 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 - if a.k == locNone: - a.k = k - a.lode = lode - a.storage = s - if a.r == "": a.r = r - -proc fillLoc(a: var TLoc, k: TLocKind, lode: PNode, s: TStorageLoc) {.inline.} = +proc fillLoc(a: var TLoc, k: TLocKind, lode: PNode, r: Rope, s: TStorageLoc) = # fills the loc if it is not already initialized if a.k == locNone: a.k = k a.lode = lode a.storage = s + if a.r == nil: a.r = r proc t(a: TLoc): PType {.inline.} = if a.lode.kind == nkSym: @@ -105,24 +90,24 @@ proc useHeader(m: BModule, sym: PSym) = let str = getStr(sym.annex.path) m.includeHeader(str) -proc cgsym(m: BModule, name: string) -proc cgsymValue(m: BModule, name: string): Rope +proc cgsym(m: BModule, name: string): Rope proc getCFile(m: BModule): AbsoluteFile proc getModuleDllPath(m: BModule): Rope = let (dir, name, ext) = splitFile(getCFile(m)) let filename = strutils.`%`(platform.OS[m.g.config.target.targetOS].dllFrmt, [name & ext]) - result = makeCString(dir.string & "/" & filename) - -proc getModuleDllPath(m: BModule, module: int): Rope = - result = getModuleDllPath(m.g.modules[module]) + return makeCString(dir.string & "/" & filename) proc getModuleDllPath(m: BModule, s: PSym): Rope = - result = getModuleDllPath(m.g.modules[s.itemId.module]) + return getModuleDllPath(findPendingModule(m, s)) import macros +proc cgFormatValue(result: var string; value: Rope) = + for str in leaves(value): + result.add str + proc cgFormatValue(result: var string; value: string) = result.add value @@ -168,11 +153,6 @@ macro ropecg(m: BModule, frmt: static[FormatStr], args: untyped): Rope = inc(i) result.add newCall(formatValue, resVar, args[num]) inc(num) - of '^': - flushStrLit() - inc(i) - result.add newCall(formatValue, resVar, args[^1]) - inc(num) of '0'..'9': var j = 0 while true: @@ -203,7 +183,7 @@ macro ropecg(m: BModule, frmt: static[FormatStr], args: untyped): Rope = var ident = newLit(substr(frmt, i, j-1)) i = j flushStrLit() - result.add newCall(formatValue, resVar, newCall(ident"cgsymValue", m, ident)) + result.add newCall(formatValue, resVar, newCall(ident"cgsym", m, ident)) elif frmt[i] == '#' and frmt[i+1] == '$': inc(i, 2) var j = 0 @@ -212,11 +192,7 @@ macro ropecg(m: BModule, frmt: static[FormatStr], args: untyped): Rope = inc(i) let ident = args[j-1] flushStrLit() - result.add newCall(formatValue, resVar, newCall(ident"cgsymValue", m, ident)) - elif frmt[i] == '#' and frmt[i+1] == '#': - inc(i, 2) - strLit.add("#") - + result.add newCall(formatValue, resVar, newCall(ident"cgsym", m, ident)) var start = i while i < frmt.len: if frmt[i] != '$' and frmt[i] != '#': inc(i) @@ -227,9 +203,10 @@ macro ropecg(m: BModule, frmt: static[FormatStr], args: untyped): Rope = flushStrLit() result.add newCall(ident"rope", resVar) -proc addIndent(p: BProc; result: var Rope) = +proc indentLine(p: BProc, r: Rope): Rope = + result = r for i in 0..= 0 - if optLineDir in conf.options and line > 0: + if optLineDir in conf.options: 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, toFullPath(conf, info), 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 @@ -287,21 +262,23 @@ 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") - genCLineDir(p.s(cpsStmts), t.info, p.config) + p.s(cpsStmts).add(~"//" & sourceLine(p.config, t.info) & "\L") + 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 freshLineInfo(p, t.info): linefmt(p, cpsStmts, "nimln_($1, $2);$n", [line, quotedFilename(p.config, t.info)]) +proc postStmtActions(p: BProc) {.inline.} = + p.s(cpsStmts).add(p.module.injectStmt) + proc accessThreadLocalVar(p: BProc, s: PSym) proc emulatedThreadVars(conf: ConfigRef): bool {.inline.} proc genProc(m: BModule, prc: PSym) -proc raiseInstr(p: BProc; result: var Rope) template compileToCpp(m: BModule): untyped = - m.config.backend == backendCpp or sfCompileToCpp in m.module.flags + m.config.cmd == cmdCompileToCpp or sfCompileToCpp in m.module.flags proc getTempName(m: BModule): Rope = result = m.tmpBase & rope(m.labels) @@ -309,18 +286,10 @@ proc getTempName(m: BModule): Rope = proc rdLoc(a: TLoc): Rope = # 'read' location (deref if indirect) - if lfIndirect in a.flags: - result = "(*" & a.r & ")" - else: - result = a.r + result = a.r + if lfIndirect in a.flags: result = "(*$1)" % [result] -proc addRdLoc(a: TLoc; result: var Rope) = - if lfIndirect in a.flags: - result.add "(*" & a.r & ")" - else: - result.add a.r - -proc lenField(p: BProc): Rope {.inline.} = +proc lenField(p: BProc): Rope = result = rope(if p.module.compileToCpp: "len" else: "Sup.len") proc lenExpr(p: BProc; a: TLoc): Rope = @@ -329,12 +298,6 @@ proc lenExpr(p: BProc; a: TLoc): Rope = else: result = "($1 ? $1->$2 : 0)" % [rdLoc(a), lenField(p)] -proc dataFieldAccessor(p: BProc, sym: Rope): Rope = - if optSeqDestructors in p.config.globalOptions: - result = "(" & sym & ").p" - else: - result = sym - proc dataField(p: BProc): Rope = if optSeqDestructors in p.config.globalOptions: result = rope".p->data" @@ -346,29 +309,16 @@ include ccgtypes # ------------------------------ Manager of temporaries ------------------ -template mapTypeChooser(n: PNode): TSymKind = - (if n.kind == nkSym: n.sym.kind else: skVar) - -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)) != 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)) != ctArray: - result = "(&" & a.r & ")" - else: - result = a.r + result = a.r + if lfIndirect notin a.flags and mapType(conf, a.t) != ctArray: + result = "(&" & result & ")" proc byRefLoc(p: BProc; a: TLoc): Rope = - if lfIndirect notin a.flags and mapType(p.config, a.t, mapTypeChooser(a)) != ctArray and not + result = a.r + if lfIndirect notin a.flags and mapType(p.config, a.t) != ctArray and not p.module.compileToCpp: - result = "(&" & a.r & ")" - else: - result = a.r + result = "(&" & result & ")" proc rdCharLoc(a: TLoc): Rope = # read a location that may need a char-cast: @@ -392,6 +342,11 @@ type proc genObjectInit(p: BProc, section: TCProcSection, t: PType, a: var TLoc, mode: ObjConstrMode) = + if p.module.compileToCpp and t.isException and p.config.exc == excCpp: + # init vtable in Exception object for polymorphic exceptions + includeHeader(p.module, "") + linefmt(p, section, "new ($1) $2;$n", [rdLoc(a), getTypeDesc(p.module, t)]) + #if optNimV2 in p.config.globalOptions: return case analyseObjectWithTypeField(t) of frNone: @@ -404,10 +359,7 @@ proc genObjectInit(p: BProc, section: TCProcSection, t: PType, a: var TLoc, while s.kind == tyObject and s[0] != nil: r.add(".Sup") s = skipTypes(s[0], skipPtrs) - if optTinyRtti in p.config.globalOptions: - linefmt(p, section, "$1.m_type = $2;$n", [r, genTypeInfoV2(p.module, t, a.lode.info)]) - else: - linefmt(p, section, "$1.m_type = $2;$n", [r, genTypeInfoV1(p.module, t, a.lode.info)]) + linefmt(p, section, "$1.m_type = $2;$n", [r, genTypeInfo(p.module, t, a.lode.info)]) of frEmbedded: if optTinyRtti in p.config.globalOptions: var tmp: TLoc @@ -416,14 +368,14 @@ 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, mapTypeChooser(a))]) + [rdLoc(a), rdLoc(tmp), getTypeDesc(p.module, objType)]) else: rawConstExpr(p, newNodeIT(nkType, a.lode.info, t), tmp) genAssignment(p, a, tmp, {}) else: # worst case for performance: var r = if mode == constructObj: addrLoc(p.config, a) else: rdLoc(a) - linefmt(p, section, "#objectInit($1, $2);$n", [r, genTypeInfoV1(p.module, t, a.lode.info)]) + linefmt(p, section, "#objectInit($1, $2);$n", [r, genTypeInfo(p.module, t, a.lode.info)]) if isException(t): var r = rdLoc(a) @@ -439,23 +391,16 @@ proc genRefAssign(p: BProc, dest, src: TLoc) proc isComplexValueType(t: PType): bool {.inline.} = let t = t.skipTypes(abstractInst + tyUserTypeClasses) - result = t.kind in {tyArray, tySet, tyTuple, tyObject, tyOpenArray} or + result = t.kind in {tyArray, tySet, tyTuple, tyObject} or (t.kind == tyProc and t.callConv == ccClosure) -include ccgreset - proc resetLoc(p: BProc, loc: var TLoc) = let containsGcRef = optSeqDestructors notin p.config.globalOptions and containsGarbageCollectedRef(loc.t) let typ = skipTypes(loc.t, abstractVarRange) if isImportedCppType(typ): return if optSeqDestructors in p.config.globalOptions and typ.kind in {tyString, tySequence}: - assert loc.r != "" - - let atyp = skipTypes(loc.t, abstractInst) - if atyp.kind in {tyVar, tyLent}: - linefmt(p, cpsStmts, "$1->len = 0; $1->p = NIM_NIL;$n", [rdLoc(loc)]) - else: - linefmt(p, cpsStmts, "$1.len = 0; $1.p = NIM_NIL;$n", [rdLoc(loc)]) + assert rdLoc(loc) != nil + linefmt(p, cpsStmts, "$1.len = 0; $1.p = NIM_NIL;$n", [rdLoc(loc)]) elif not isComplexValueType(typ): if containsGcRef: var nilLoc: TLoc @@ -465,11 +410,11 @@ proc resetLoc(p: BProc, loc: var TLoc) = else: linefmt(p, cpsStmts, "$1 = 0;$n", [rdLoc(loc)]) else: + if optNilCheck in p.options: + linefmt(p, cpsStmts, "#chckNil((void*)$1);$n", [addrLoc(p.config, loc)]) if loc.storage != OnStack and containsGcRef: - specializeReset(p, loc) - when false: - linefmt(p, cpsStmts, "#genericReset((void*)$1, $2);$n", - [addrLoc(p.config, loc), genTypeInfoV1(p.module, loc.t, loc.lode.info)]) + linefmt(p, cpsStmts, "#genericReset((void*)$1, $2);$n", + [addrLoc(p.config, loc), genTypeInfo(p.module, loc.t, loc.lode.info)]) # XXX: generated reset procs should not touch the m_type # field, so disabling this should be safe: genObjectInit(p, cpsStmts, loc.t, loc, constructObj) @@ -477,35 +422,25 @@ proc resetLoc(p: BProc, loc: var TLoc) = # array passed as argument decayed into pointer, bug #7332 # 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, mapTypeChooser(loc))]) + [addrLoc(p.config, loc), getTypeDesc(p.module, loc.t)]) # 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) -proc isOrHasImportedCppType(typ: PType): bool = - searchTypeFor(typ.skipTypes({tyRef}), isImportedCppType) - proc constructLoc(p: BProc, loc: var TLoc, isTemp = false) = let typ = loc.t - if optSeqDestructors in p.config.globalOptions and skipTypes(typ, abstractInst + {tyStatic}).kind in {tyString, tySequence}: + if optSeqDestructors in p.config.globalOptions and skipTypes(typ, abstractInst).kind in {tyString, tySequence}: linefmt(p, cpsStmts, "$1.len = 0; $1.p = NIM_NIL;$n", [rdLoc(loc)]) elif not isComplexValueType(typ): - if containsGarbageCollectedRef(loc.t): - var nilLoc: TLoc - initLoc(nilLoc, locTemp, loc.lode, OnStack) - nilLoc.r = rope("NIM_NIL") - genRefAssign(p, loc, nilLoc) - else: - linefmt(p, cpsStmts, "$1 = ($2)0;$n", [rdLoc(loc), - getTypeDesc(p.module, typ, mapTypeChooser(loc))]) + linefmt(p, cpsStmts, "$1 = ($2)0;$n", [rdLoc(loc), + getTypeDesc(p.module, typ)]) 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, mapTypeChooser(loc))]) + [addrLoc(p.config, loc), getTypeDesc(p.module, typ)]) genObjectInit(p, cpsStmts, loc.t, loc, constructObj) proc initLocalVar(p: BProc, v: PSym, immediateAsgn: bool) = @@ -523,28 +458,17 @@ 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, skVar), result.r]) - else: - linefmt(p, cpsLocals, "$1 $2;$n", [getTypeDesc(p.module, t, skVar), result.r]) + linefmt(p, cpsLocals, "$1 $2;$n", [getTypeDesc(p.module, t), result.r]) result.k = locTemp result.lode = lodeTyp t result.storage = OnStack result.flags = {} constructLoc(p, result, not needsInit) - when false: - # XXX Introduce a compiler switch in order to detect these easily. - if getSize(p.config, t) > 1024 * 1024: - if p.prc != nil: - echo "ENORMOUS TEMPORARY! ", p.config $ p.prc.info - else: - echo "ENORMOUS TEMPORARY! ", p.config $ p.lastLineInfo - writeStackTrace() 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, skVar), result.r, value]) + linefmt(p, cpsStmts, "$1 $2 = $3;$n", [getTypeDesc(p.module, t), result.r, value]) result.k = locTemp result.lode = lodeTyp t result.storage = OnStack @@ -562,21 +486,16 @@ proc getIntTemp(p: BProc, result: var TLoc) = proc localVarDecl(p: BProc; n: PNode): Rope = let s = n.sym if s.loc.k == locNone: - fillLocalName(p, s) - fillLoc(s.loc, locLocalVar, n, OnStack) + fillLoc(s.loc, locLocalVar, n, mangleLocalName(p, s), OnStack) 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, n.info, p.config) - - result.add getTypeDesc(p.module, s.typ, skVar) + result.add getTypeDesc(p.module, s.typ) if s.constraint.isNil: if sfRegister in s.flags: result.add(" register") #elif skipTypes(s.typ, abstractInst).kind in GcTypeKinds: # decl.add(" GC_GUARD") if sfVolatile in s.flags: result.add(" volatile") - if sfNoalias in s.flags: result.add(" NIM_NOALIAS") result.add(" ") result.add(s.loc.r) else: @@ -587,7 +506,7 @@ proc assignLocalVar(p: BProc, n: PNode) = # 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: "\L" - let decl = localVarDecl(p, n) & (if p.module.compileToCpp and isOrHasImportedCppType(n.typ): "{};" else: ";") & nl + let decl = localVarDecl(p, n) & ";" & nl line(p, cpsLocals, decl) include ccgthreadvars @@ -603,8 +522,7 @@ proc treatGlobalDifferentlyForHCR(m: BModule, s: PSym): bool = proc assignGlobalVar(p: BProc, n: PNode; value: Rope) = let s = n.sym if s.loc.k == locNone: - fillBackendName(p.module, s) - fillLoc(s.loc, locGlobalVar, n, OnHeap) + fillLoc(s.loc, locGlobalVar, n, mangleName(p.module, s), OnHeap) if treatGlobalDifferentlyForHCR(p.module, s): incl(s.loc.flags, lfIndirect) if lfDynamicLib in s.loc.flags: @@ -613,7 +531,7 @@ proc assignGlobalVar(p: BProc, n: PNode; value: Rope) = varInDynamicLib(q, s) else: s.loc.r = mangleDynLibProc(s) - if value != "": + if value != nil: internalError(p.config, n.info, ".dynlib variables cannot have a value") return useHeader(p.module, s) @@ -621,11 +539,11 @@ proc assignGlobalVar(p: BProc, n: PNode; value: Rope) = if not containsOrIncl(p.module.declaredThings, s.id): if sfThread in s.flags: declareThreadVar(p.module, s, sfImportc in s.flags) - if value != "": + if value != nil: internalError(p.config, n.info, ".threadvar variables cannot have a value") else: - var decl: Rope = "" - var td = getTypeDesc(p.module, s.loc.t, skVar) + var decl: Rope = nil + var td = getTypeDesc(p.module, s.loc.t) if s.constraint.isNil: if s.kind in {skLet, skVar, skField, skForVar} and s.alignment > 0: decl.addf "NIM_ALIGN($1) ", [rope(s.alignment)] @@ -633,35 +551,33 @@ proc assignGlobalVar(p: BProc, n: PNode; value: Rope) = 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 ") + if s.kind == skLet and value != nil: 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 value != nil: decl.addf(" $1 = $2;$n", [s.loc.r, value]) else: decl.addf(" $1;$n", [s.loc.r]) else: - if value != "": + if value != nil: 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 == "": + if p.withinLoop > 0 and value == nil: # fixes tests/run/tzeroarray: resetLoc(p, s.loc) proc assignParam(p: BProc, s: PSym, retType: PType) = - assert(s.loc.r != "") + assert(s.loc.r != nil) scopeMangledParam(p, s) proc fillProcLoc(m: BModule; n: PNode) = let sym = n.sym if sym.loc.k == locNone: - fillBackendName(m, sym) - fillLoc(sym.loc, locProc, n, OnStack) + fillLoc(sym.loc, locProc, n, mangleName(m, sym), OnStack) proc getLabel(p: BProc): TLabel = inc(p.labels) @@ -676,9 +592,9 @@ proc genStmts(p: BProc, t: PNode) proc expr(p: BProc, n: PNode, d: var TLoc) proc genProcPrototype(m: BModule, sym: PSym) proc putLocIntoDest(p: BProc, d: var TLoc, s: TLoc) -proc intLiteral(i: BiggestInt; result: var Rope) -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 intLiteral(i: BiggestInt): Rope +proc genLiteral(p: BProc, n: PNode): Rope +proc genOtherArg(p: BProc; ri: PNode; i: int; typ: PType): Rope proc raiseExit(p: BProc) proc initLocExpr(p: BProc, e: PNode, result: var TLoc) = @@ -702,25 +618,25 @@ include ccgcalls, "ccgstmts.nim" proc initFrame(p: BProc, procname, filename: Rope): Rope = const frameDefines = """ -$1define nimfr_(proc, file) \ - TFrame FR_; \ - FR_.procname = proc; FR_.filename = file; FR_.line = 0; FR_.len = 0; #nimFrame(&FR_); + $1 define nimfr_(proc, file) \ + TFrame FR_; \ + FR_.procname = proc; FR_.filename = file; FR_.line = 0; FR_.len = 0; #nimFrame(&FR_); - $1define nimfrs_(proc, file, slots, length) \ - 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_); + $1 define nimfrs_(proc, file, slots, length) \ + 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, file) \ - FR_.line = n; FR_.filename = file; -""" + $1 define nimln_(n, file) \ + FR_.line = n; FR_.filename = file; + """ if p.module.s[cfsFrameDefines].len == 0: appcg(p.module, p.module.s[cfsFrameDefines], frameDefines, ["#"]) - cgsym(p.module, "nimFrame") + discard cgsym(p.module, "nimFrame") result = ropecg(p.module, "\tnimfr_($1, $2);$n", [procname, filename]) proc initFrameNoDebug(p: BProc; frame, procname, filename: Rope; line: int): Rope = - cgsym(p.module, "nimFrame") + discard cgsym(p.module, "nimFrame") p.blocks[0].sections[cpsLocals].addf("TFrame $1;$n", [frame]) result = ropecg(p.module, "\t$1.procname = $2; $1.filename = $3; " & " $1.line = $4; $1.len = -1; nimFrame(&$1);$n", @@ -747,37 +663,32 @@ proc loadDynamicLib(m: BModule, lib: PLib) = if not lib.generated: lib.generated = true var tmp = getTempName(m) - assert(lib.name == "") + assert(lib.name == nil) lib.name = tmp # BUGFIX: cgsym has awful side-effects m.s[cfsVars].addf("static void* $1;$n", [tmp]) if lib.path.kind in {nkStrLit..nkTripleStrLit}: var s: TStringSeq = @[] libCandidates(lib.path.strVal, s) rawMessage(m.config, hintDependency, lib.path.strVal) - var loadlib: Rope = "" + var loadlib: Rope = nil for i in 0..high(s): inc(m.labels) if i > 0: loadlib.add("||") let n = newStrNode(nkStrLit, s[i]) n.info = lib.path.info - appcg(m, loadlib, "($1 = #nimLoadLibrary(", [tmp]) - genStringLiteral(m, n, loadlib) - loadlib.addf "))$n", [] + appcg(m, loadlib, "($1 = #nimLoadLibrary($2))$n", + [tmp, genStringLiteral(m, n)]) appcg(m, m.s[cfsDynLibInit], - "if (!($1)) #nimLoadLibraryError(", - [loadlib]) - genStringLiteral(m, lib.path, m.s[cfsDynLibInit]) - m.s[cfsDynLibInit].addf ");$n", [] - + "if (!($1)) #nimLoadLibraryError($2);$n", + [loadlib, genStringLiteral(m, lib.path)]) else: var p = newProc(nil, m) - p.options.excl optStackTrace - p.flags.incl nimErrorFlagDisabled + p.options = p.options - {optStackTrace} var dest: TLoc initLoc(dest, locTemp, lib.path, OnStack) dest.r = getTempName(m) appcg(m, m.s[cfsDynLibInit],"$1 $2;$n", - [getTypeDesc(m, lib.path.typ, skVar), rdLoc(dest)]) + [getTypeDesc(m, lib.path.typ), rdLoc(dest)]) expr(p, lib.path, dest) m.s[cfsVars].add(p.s(cpsLocals)) @@ -787,7 +698,7 @@ proc loadDynamicLib(m: BModule, lib: PLib) = "if (!($1 = #nimLoadLibrary($2))) #nimLoadLibraryError($2);$n", [tmp, rdLoc(dest)]) - if lib.name == "": internalError(m.config, "loadDynamicLib") + if lib.name == nil: internalError(m.config, "loadDynamicLib") proc mangleDynLibProc(sym: PSym): Rope = # we have to build this as a single rope in order not to trip the @@ -817,7 +728,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, skVar), params, makeCString($extname)] + [tmp, getTypeDesc(m, sym.typ), params, makeCString($extname)] var last = lastSon(n) if last.kind == nkHiddenStdConv: last = last[1] internalAssert(m.config, last.kind == nkStrLit) @@ -831,8 +742,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, skVar), lib.name, makeCString($extname)]) - m.s[cfsVars].addf("$2 $1;$n", [sym.loc.r, getTypeDesc(m, sym.loc.t, skVar)]) + [tmp, getTypeDesc(m, sym.typ), lib.name, makeCString($extname)]) + m.s[cfsVars].addf("$2 $1;$n", [sym.loc.r, getTypeDesc(m, sym.loc.t)]) proc varInDynamicLib(m: BModule, sym: PSym) = var lib = sym.annex @@ -844,33 +755,26 @@ 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, skVar), lib.name, makeCString($extname)]) + [tmp, getTypeDesc(m, sym.typ), lib.name, makeCString($extname)]) m.s[cfsVars].addf("$2* $1;$n", - [sym.loc.r, getTypeDesc(m, sym.loc.t, skVar)]) + [sym.loc.r, getTypeDesc(m, sym.loc.t)]) proc symInDynamicLibPartial(m: BModule, sym: PSym) = sym.loc.r = mangleDynLibProc(sym) sym.typ.sym = nil # generate a new name -proc cgsymImpl(m: BModule; sym: PSym) {.inline.} = - case sym.kind - of skProc, skFunc, skMethod, skConverter, skIterator: genProc(m, sym) - of skVar, skResult, skLet: genVarPrototype(m, newSymNode sym) - of skType: discard getTypeDesc(m, sym.typ) - else: internalError(m.config, "cgsym: " & $sym.kind) - -proc cgsym(m: BModule, name: string) = +proc cgsym(m: BModule, name: string): Rope = let sym = magicsys.getCompilerProc(m.g.graph, name) if sym != nil: - cgsymImpl m, sym - else: - rawMessage(m.config, errGenerated, "system module needs: " & name) - -proc cgsymValue(m: BModule, name: string): Rope = - let sym = magicsys.getCompilerProc(m.g.graph, name) - if sym != nil: - cgsymImpl m, sym + case sym.kind + of skProc, skFunc, skMethod, skConverter, skIterator: genProc(m, sym) + of skVar, skResult, skLet: genVarPrototype(m, newSymNode sym) + of skType: discard getTypeDesc(m, sym.typ) + else: internalError(m.config, "cgsym: " & name & ": " & $sym.kind) else: + # we used to exclude the system module from this check, but for DLL + # generation support this sloppyness leads to hard to detect bugs, so + # we're picky here for the system module too: rawMessage(m.config, errGenerated, "system module needs: " & name) result = sym.loc.r if m.hcrOn and sym != nil and sym.kind in {skProc..skIterator}: @@ -901,12 +805,12 @@ proc generateHeaders(m: BModule) = #undef unix """) -proc openNamespaceNim(namespace: string; result: var Rope) = +proc openNamespaceNim(namespace: string): Rope = result.add("namespace ") result.add(namespace) result.add(" {\L") -proc closeNamespaceNim(result: var Rope) = +proc closeNamespaceNim(): Rope = result.add("}\L") proc closureSetup(p: BProc, prc: PSym) = @@ -927,19 +831,13 @@ proc closureSetup(p: BProc, prc: PSym) = [rdLoc(env.loc), getTypeDesc(p.module, env.typ)]) proc containsResult(n: PNode): bool = - result = false - case n.kind - of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit, nkFormalParams: - discard - of nkSym: - if n.sym.kind == skResult: - result = true + if n.kind == nkSym and n.sym.kind == skResult: + result = true else: - for i in 0..= 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): + if not isInvalidReturnType(m.config, prc.typ[0]): 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) @@ -1108,11 +1002,11 @@ proc genProcAux(m: BModule, prc: PSym) = else: # declare the result symbol: assignLocalVar(p, resNode) - assert(res.loc.r != "") + assert(res.loc.r != nil) initLocalVar(p, res, immediateAsgn=false) returnStmt = ropecg(p.module, "\treturn $1;$n", [rdLoc(res.loc)]) else: - fillResult(p.config, resNode, prc.typ) + fillResult(p.config, resNode) assignParam(p, res, prc.typ[0]) # We simplify 'unsureAsgn(result, nil); unsureAsgn(result, x)' # to 'unsureAsgn(result, x)' @@ -1137,7 +1031,7 @@ proc genProcAux(m: BModule, prc: PSym) = var generatedProc: Rope generatedProc.genCLineDir prc.info, m.config - if isNoReturn(p.module, prc): + if sfNoReturn in prc.flags: if hasDeclspec in extccomp.CC[p.config.cCompiler].props: header = "__declspec(noreturn) " & header if sfPure in prc.flags: @@ -1166,10 +1060,10 @@ proc genProcAux(m: BModule, prc: PSym) = if beforeRetNeeded in p.flags: generatedProc.add("{") generatedProc.add(p.s(cpsInit)) generatedProc.add(p.s(cpsStmts)) - if beforeRetNeeded in p.flags: generatedProc.add("\t}BeforeRet_: ;\n") + if beforeRetNeeded in p.flags: generatedProc.add(~"\t}BeforeRet_: ;$n") if optStackTrace in prc.options: generatedProc.add(deinitFrame(p)) generatedProc.add(returnStmt) - generatedProc.add("}\n") + generatedProc.add(~"}$N") m.s[cfsProcs].add(generatedProc) if isReloadable(m, prc): m.s[cfsDynLibInit].addf("\t$1 = ($3) hcrRegisterProc($4, \"$1\", (void*)$2);$n", @@ -1178,17 +1072,17 @@ proc genProcAux(m: BModule, prc: PSym) = proc requiresExternC(m: BModule; sym: PSym): bool {.inline.} = result = (sfCompileToCpp in m.module.flags and sfCompileToCpp notin sym.getModule().flags and - m.config.backend != backendCpp) or ( + m.config.cmd != cmdCompileToCpp) or ( sym.flags * {sfInfixCall, sfCompilerProc, sfMangleCpp} == {} and sym.flags * {sfImportc, sfExportc} != {} and sym.magic == mNone and - m.config.backend == backendCpp) + m.config.cmd == cmdCompileToCpp) proc genProcPrototype(m: BModule, sym: PSym) = useHeader(m, sym) if lfNoDecl in sym.loc.flags: return if lfDynamicLib in sym.loc.flags: - if sym.itemId.module != m.module.position and + if getModule(sym).id != m.module.id and not containsOrIncl(m.declaredThings, sym.id): m.s[cfsVars].add(ropecg(m, "$1 $2 $3;$n", [(if isReloadable(m, sym): "static" else: "extern"), @@ -1198,16 +1092,15 @@ proc genProcPrototype(m: BModule, sym: PSym) = [mangleDynLibProc(sym), getTypeDesc(m, sym.loc.t), getModuleDllPath(m, sym)]) elif not containsOrIncl(m.declaredProtos, sym.id): let asPtr = isReloadable(m, sym) - var header = newRopeAppender() - genProcHeader(m, sym, header, asPtr) + var header = genProcHeader(m, sym, asPtr) if not asPtr: - if isNoReturn(m, sym) and hasDeclspec in extccomp.CC[m.config.cCompiler].props: + if sfNoReturn in sym.flags and hasDeclspec in extccomp.CC[m.config.cCompiler].props: header = "__declspec(noreturn) " & header if sym.typ.callConv != ccInline and requiresExternC(m, sym): header = "extern \"C\" " & header if sfPure in sym.flags and hasAttribute in CC[m.config.cCompiler].props: header.add(" __attribute__((naked))") - if isNoReturn(m, sym) and hasAttribute in CC[m.config.cCompiler].props: + if sfNoReturn in sym.flags and hasAttribute in CC[m.config.cCompiler].props: header.add(" __attribute__((noreturn))") m.s[cfsProcHeaders].add(ropecg(m, "$1;$N", [header])) @@ -1217,7 +1110,7 @@ proc genProcNoForward(m: BModule, prc: PSym) = fillProcLoc(m, prc.ast[namePos]) useHeader(m, prc) # dependency to a compilerproc: - cgsym(m, prc.name.s) + discard cgsym(m, prc.name.s) return if lfNoDecl in prc.loc.flags: fillProcLoc(m, prc.ast[namePos]) @@ -1230,9 +1123,7 @@ proc genProcNoForward(m: BModule, prc: PSym) = #if prc.loc.k == locNone: # mangle the inline proc based on the module where it is defined - # not on the first module that uses it - let m2 = if m.config.symbolFiles != disabledSf: m - else: findPendingModule(m, prc) - fillProcLoc(m2, prc.ast[namePos]) + fillProcLoc(findPendingModule(m, prc), prc.ast[namePos]) #elif {sfExportc, sfImportc} * prc.flags == {}: # # reset name to restore consistency in case of hashing collisions: # echo "resetting ", prc.id, " by ", m.module.name.s @@ -1277,16 +1168,25 @@ proc genProcNoForward(m: BModule, prc: PSym) = if sfInfixCall notin prc.flags: genProcPrototype(m, prc) proc requestConstImpl(p: BProc, sym: PSym) = - if genConstSetup(p, sym): - let m = p.module - # declare implementation: - var q = findPendingModule(m, sym) - if q != nil and not containsOrIncl(q.declaredThings, sym.id): - assert q.initProc.module == q - genConstDefinition(q, p, sym) - # declare header: - if q != m and not containsOrIncl(m.declaredThings, sym.id): - genConstHeader(m, q, p, sym) + var m = p.module + useHeader(m, sym) + if sym.loc.k == locNone: + fillLoc(sym.loc, locData, sym.ast, mangleName(p.module, sym), OnStatic) + if lfNoDecl in sym.loc.flags: return + # declare implementation: + var q = findPendingModule(m, sym) + if q != nil and not containsOrIncl(q.declaredThings, sym.id): + assert q.initProc.module == q + q.s[cfsData].addf("N_LIB_PRIVATE NIM_CONST $1 $2 = $3;$n", + [getTypeDesc(q, sym.typ), sym.loc.r, genBracedInit(q.initProc, sym.ast, isConst = true)]) + # declare header: + if q != m and not containsOrIncl(m.declaredThings, sym.id): + assert(sym.loc.r != nil) + let headerDecl = "extern NIM_CONST $1 $2;$n" % + [getTypeDesc(m, sym.loc.t), 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) proc isActivated(prc: PSym): bool = prc.typ != nil @@ -1308,15 +1208,14 @@ proc genVarPrototype(m: BModule, n: PNode) = #assert(sfGlobal in sym.flags) let sym = n.sym useHeader(m, sym) - fillBackendName(m, sym) - fillLoc(sym.loc, locGlobalVar, n, OnHeap) + fillLoc(sym.loc, locGlobalVar, n, mangleName(m, sym), OnHeap) if treatGlobalDifferentlyForHCR(m, sym): incl(sym.loc.flags, lfIndirect) if (lfNoDecl in sym.loc.flags) or contains(m.declaredThings, sym.id): return if sym.owner.id != m.module.id: # else we already have the symbol generated! - assert(sym.loc.r != "") + assert(sym.loc.r != nil) if sfThread in sym.flags: declareThreadVar(m, sym, true) else: @@ -1324,36 +1223,38 @@ proc genVarPrototype(m: BModule, n: PNode) = 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, skVar)) + m.s[cfsVars].add(getTypeDesc(m, sym.loc.t)) 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") if sfVolatile in sym.flags: m.s[cfsVars].add(" volatile") - if sfNoalias in sym.flags: m.s[cfsVars].add(" NIM_NOALIAS") 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, skVar), getModuleDllPath(m, sym)]) + getTypeDesc(m, sym.loc.t), getModuleDllPath(m, sym)]) -proc addNimDefines(result: var Rope; conf: ConfigRef) {.inline.} = +proc addIntTypes(result: var Rope; conf: ConfigRef) {.inline.} = result.addf("#define NIM_INTBITS $1\L", [ platform.CPU[conf.target.targetCPU].intSize.rope]) if conf.cppCustomNamespace.len > 0: result.add("#define USE_NIM_NAMESPACE ") result.add(conf.cppCustomNamespace) result.add("\L") - if conf.isDefined("nimEmulateOverflowChecks"): - result.add("#define NIM_EmulateOverflowChecks\L") - -proc headerTop(): Rope = - result = "/* Generated by Nim Compiler v$1 */$N" % [rope(VersionAsString)] proc getCopyright(conf: ConfigRef; cfile: Cfile): Rope = - result = headerTop() - if optCompileOnly notin conf.globalOptions: - result.add ("/* Compiled for: $1, $2, $3 */$N" & - "/* Command for C compiler:$n $4 */$N") % - [rope(platform.OS[conf.target.targetOS].name), + if optCompileOnly in conf.globalOptions: + result = ("/* Generated by Nim Compiler v$1 */$N" & + "/* (c) " & copyrightYear & " Andreas Rumpf */$N" & + "/* The generated code is subject to the original license. */$N") % + [rope(VersionAsString)] + else: + result = ("/* Generated by Nim Compiler v$1 */$N" & + "/* (c) " & copyrightYear & " Andreas Rumpf */$N" & + "/* The generated code is subject to the original license. */$N" & + "/* Compiled for: $2, $3, $4 */$N" & + "/* Command for C compiler:$n $5 */$N") % + [rope(VersionAsString), + rope(platform.OS[conf.target.targetOS].name), rope(platform.CPU[conf.target.targetCPU].name), rope(extccomp.CC[conf.cCompiler].name), rope(getCompileCFileCmd(conf, cfile))] @@ -1361,27 +1262,25 @@ proc getCopyright(conf: ConfigRef; cfile: Cfile): Rope = proc getFileHeader(conf: ConfigRef; cfile: Cfile): Rope = result = getCopyright(conf, cfile) if conf.hcrOn: result.add("#define NIM_HOT_CODE_RELOADING\L") - addNimDefines(result, conf) + addIntTypes(result, conf) -proc getSomeNameForModule(conf: ConfigRef, filename: AbsoluteFile): Rope = - ## Returns a mangled module name. - result.add mangleModuleName(conf, filename).mangle - -proc getSomeNameForModule(m: BModule): Rope = - ## Returns a mangled module name. - assert m.module.kind == skModule - assert m.module.owner.kind == skPackage - result.add mangleModuleName(m.g.config, m.filename).mangle +proc getSomeNameForModule(m: PSym): Rope = + assert m.kind == skModule + assert m.owner.kind == skPackage + if {sfSystemModule, sfMainModule} * m.flags == {}: + result = m.owner.name.s.mangle.rope + result.add "_" + result.add m.name.s.mangle proc getSomeInitName(m: BModule, suffix: string): Rope = if not m.hcrOn: - result = getSomeNameForModule(m) + result = getSomeNameForModule(m.module) result.add suffix proc getInitName(m: BModule): Rope = if sfMainModule in m.module.flags: # generate constant name for main module, for "easy" debugging. - result = rope(m.config.nimMainPrefix) & rope"NimMainModule" + result = rope"NimMainModule" else: result = getSomeInitName(m, "Init000") @@ -1402,11 +1301,9 @@ proc genMainProc(m: BModule) = assert prc != nil let n = newStrNode(nkStrLit, prc.annex.path.strVal) n.info = prc.annex.path.info - var strLit = newRopeAppender() - genStringLiteral(m, n, strLit) appcg(m, result, "\tif (!($1 = #nimLoadLibrary($2)))$N" & "\t\t#nimLoadLibraryError($2);$N", - [handle, strLit]) + [handle, genStringLiteral(m, n)]) preMainCode.add(loadLib("hcr_handle", "hcrGetProc")) preMainCode.add("\tvoid* rtl_handle;\L") @@ -1416,59 +1313,47 @@ proc genMainProc(m: BModule) = 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 "\tN_LIB_PRIVATE int cmdCount;\L" - posixCmdLine.add "\tN_LIB_PRIVATE char** cmdLine;\L" - posixCmdLine.add "\tN_LIB_PRIVATE char** gEnv;\L" + preMainCode.add("\tPreMain();\L") const + # not a big deal if we always compile these 3 global vars... makes the HCR code easier + PosixCmdLine = + "N_LIB_PRIVATE int cmdCount;$N" & + "N_LIB_PRIVATE char** cmdLine;$N" & + "N_LIB_PRIVATE char** gEnv;$N" + # The use of a volatile function pointer to call Pre/NimMainInner # prevents inlining of the NimMainInner function and dependent # functions, which might otherwise merge their stack frames. - PreMainBody = "$N" & - "N_LIB_PRIVATE void $3PreMainInner(void) {$N" & + "N_LIB_PRIVATE void PreMainInner(void) {$N" & "$2" & "}$N$N" & - "$4" & - "N_LIB_PRIVATE void $3PreMain(void) {$N" & - "\t##if $5$N" & # 1 for volatile call, 0 for non-volatile + PosixCmdLine & + "N_LIB_PRIVATE void PreMain(void) {$N" & "\tvoid (*volatile inner)(void);$N" & - "\tinner = $3PreMainInner;$N" & + "\tinner = PreMainInner;$N" & "$1" & "\t(*inner)();$N" & - "\t##else$N" & - "$1" & - "\t$3PreMainInner();$N" & - "\t##endif$N" & "}$N$N" MainProcs = - "\t$^NimMain();$N" + "\tNimMain();$N" MainProcsWithResult = MainProcs & ("\treturn $1nim_program_result;$N") - NimMainInner = "N_LIB_PRIVATE N_CDECL(void, $5NimMainInner)(void) {$N" & + NimMainInner = "N_LIB_PRIVATE N_CDECL(void, NimMainInner)(void) {$N" & "$1" & "}$N$N" NimMainProc = - "N_CDECL(void, $5NimMain)(void) {$N" & - "\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" & - "\t##else$N" & - "$4" & - "$2" & - "\t$5NimMainInner();$N" & - "\t##endif$N" & + "N_CDECL(void, NimMain)(void) {$N" & + "\tvoid (*volatile inner)(void);$N" & + "$4" & + "\tinner = NimMainInner;$N" & + "$2" & + "\t(*inner)();$N" & "}$N$N" NimMainBody = NimMainInner & NimMainProc @@ -1511,7 +1396,7 @@ proc genMainProc(m: BModule) = GenodeNimMain = "extern Genode::Env *nim_runtime_env;$N" & - "extern \"C\" void nim_component_construct(Genode::Env*);$N$N" & + "extern void nim_component_construct(Genode::Env*);$N$N" & NimMainBody ComponentConstruct = @@ -1533,91 +1418,67 @@ proc genMainProc(m: BModule) = m.includeHeader("") let initStackBottomCall = - if m.config.target.targetOS == osStandalone or m.config.selectedGC in {gcNone, gcArc, gcOrc}: "".rope + if m.config.target.targetOS == osStandalone or m.config.selectedGC == gcNone: "".rope else: ropecg(m, "\t#initStackBottomWith((void *)&inner);$N", []) inc(m.labels) - - 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]) + appcg(m, m.s[cfsProcs], PreMainBody, [m.g.mainDatInit, m.g.otherModsInit]) if m.config.target.targetOS == osWindows and m.config.globalOptions * {optGenGuiApp, optGenDynLib} != {}: if optGenGuiApp in m.config.globalOptions: const nimMain = WinNimMain appcg(m, m.s[cfsProcs], nimMain, - [m.g.mainModInit, initStackBottomCall, m.labels, preMainCode, m.config.nimMainPrefix, isVolatile]) + [m.g.mainModInit, initStackBottomCall, m.labels, preMainCode]) else: const nimMain = WinNimDllMain appcg(m, m.s[cfsProcs], nimMain, - [m.g.mainModInit, initStackBottomCall, m.labels, preMainCode, m.config.nimMainPrefix, isVolatile]) + [m.g.mainModInit, initStackBottomCall, m.labels, preMainCode]) elif m.config.target.targetOS == osGenode: const nimMain = GenodeNimMain appcg(m, m.s[cfsProcs], nimMain, - [m.g.mainModInit, initStackBottomCall, m.labels, preMainCode, m.config.nimMainPrefix, isVolatile]) + [m.g.mainModInit, initStackBottomCall, m.labels, preMainCode]) elif optGenDynLib in m.config.globalOptions: const nimMain = PosixNimDllMain appcg(m, m.s[cfsProcs], nimMain, - [m.g.mainModInit, initStackBottomCall, m.labels, preMainCode, m.config.nimMainPrefix, isVolatile]) + [m.g.mainModInit, initStackBottomCall, m.labels, preMainCode]) + elif m.config.target.targetOS == osStandalone: + const nimMain = NimMainBody + appcg(m, m.s[cfsProcs], nimMain, + [m.g.mainModInit, initStackBottomCall, m.labels, preMainCode]) else: const nimMain = NimMainBody appcg(m, m.s[cfsProcs], nimMain, - [m.g.mainModInit, initStackBottomCall, m.labels, preMainCode, m.config.nimMainPrefix, isVolatile]) + [m.g.mainModInit, initStackBottomCall, m.labels, preMainCode]) + if optNoMain notin m.config.globalOptions: if m.config.cppCustomNamespace.len > 0: - closeNamespaceNim(m.s[cfsProcs]) - m.s[cfsProcs].add "using namespace " & m.config.cppCustomNamespace & ";\L" + m.s[cfsProcs].add closeNamespaceNim() & "using namespace " & m.config.cppCustomNamespace & ";\L" if m.config.target.targetOS == osWindows and m.config.globalOptions * {optGenGuiApp, optGenDynLib} != {}: if optGenGuiApp in m.config.globalOptions: const otherMain = WinCMain - appcg(m, m.s[cfsProcs], otherMain, [if m.hcrOn: "*" else: "", m.config.nimMainPrefix]) + appcg(m, m.s[cfsProcs], otherMain, [if m.hcrOn: "*" else: ""]) else: const otherMain = WinCDllMain - appcg(m, m.s[cfsProcs], otherMain, [m.config.nimMainPrefix]) + appcg(m, m.s[cfsProcs], otherMain, []) elif m.config.target.targetOS == osGenode: const otherMain = ComponentConstruct - appcg(m, m.s[cfsProcs], otherMain, [m.config.nimMainPrefix]) + appcg(m, m.s[cfsProcs], otherMain, []) elif optGenDynLib in m.config.globalOptions: const otherMain = PosixCDllMain - appcg(m, m.s[cfsProcs], otherMain, [m.config.nimMainPrefix]) + appcg(m, m.s[cfsProcs], otherMain, []) elif m.config.target.targetOS == osStandalone: const otherMain = StandaloneCMain - appcg(m, m.s[cfsProcs], otherMain, [m.config.nimMainPrefix]) + appcg(m, m.s[cfsProcs], otherMain, []) else: const otherMain = PosixCMain - appcg(m, m.s[cfsProcs], otherMain, [if m.hcrOn: "*" else: "", m.config.nimMainPrefix]) + appcg(m, m.s[cfsProcs], otherMain, [if m.hcrOn: "*" else: ""]) + if m.config.cppCustomNamespace.len > 0: - openNamespaceNim(m.config.cppCustomNamespace, m.s[cfsProcs]) - -proc registerInitProcs*(g: BModuleList; m: PSym; flags: set[ModuleBackendFlag]) = - ## Called from the IC backend. - if HasDatInitProc in flags: - let datInit = getSomeNameForModule(g.config, g.config.toFullPath(m.info.fileIndex).AbsoluteFile) & "DatInit000" - g.mainModProcs.addf("N_LIB_PRIVATE N_NIMCALL(void, $1)(void);$N", [datInit]) - g.mainDatInit.addf("\t$1();$N", [datInit]) - if HasModuleInitProc in flags: - let init = getSomeNameForModule(g.config, g.config.toFullPath(m.info.fileIndex).AbsoluteFile) & "Init000" - g.mainModProcs.addf("N_LIB_PRIVATE N_NIMCALL(void, $1)(void);$N", [init]) - let initCall = "\t$1();$N" % [init] - if sfMainModule in m.flags: - g.mainModInit.add(initCall) - elif sfSystemModule in m.flags: - g.mainDatInit.add(initCall) # systemInit must called right after systemDatInit if any - else: - g.otherModsInit.add(initCall) - -proc whichInitProcs*(m: BModule): set[ModuleBackendFlag] = - # called from IC. - result = {} - if m.hcrOn or m.preInitProc.s(cpsInit).len > 0 or m.preInitProc.s(cpsStmts).len > 0: - result.incl HasModuleInitProc - for i in cfsTypeInit1..cfsDynLibInit: - if m.s[i].len != 0: - result.incl HasDatInitProc - break + m.s[cfsProcs].add openNamespaceNim(m.config.cppCustomNamespace) proc registerModuleToMain(g: BModuleList; m: BModule) = let @@ -1636,7 +1497,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", []) @@ -1653,9 +1514,6 @@ proc registerModuleToMain(g: BModuleList; m: BModule) = # nasty nasty hack to get the command line functionality working with HCR # register the 2 variables on behalf of the os module which might not even # be loaded (in which case it will get collected but that is not a problem) - # EDIT: indeed, this hack, in combination with another un-necessary one - # (`makeCString` was doing line wrap of string litterals) was root cause for - # bug #16265. let osModulePath = ($systemModulePath).replace("stdlib_system", "stdlib_os").rope g.mainDatInit.addf("\thcrAddModule($1);\n", [osModulePath]) g.mainDatInit.add("\tint* cmd_count;\n") @@ -1677,7 +1535,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, gcOrc}: + if m.config.target.targetOS != osStandalone and m.config.selectedGC != gcNone: g.mainDatInit.add(ropecg(m, "\t#initStackBottomWith((void *)&inner);$N", [])) if m.s[cfsInitProc].len > 0: @@ -1707,13 +1565,14 @@ proc genDatInitCode(m: BModule) = for i in cfsTypeInit1..cfsDynLibInit: if m.s[i].len != 0: moduleDatInitRequired = true + prc.add(genSectionStart(i, m.config)) prc.add(m.s[i]) + prc.add(genSectionEnd(i, m.config)) prc.addf("}$N$N", []) if moduleDatInitRequired: m.s[cfsDatInitProc].add(prc) - #rememberFlag(m.g.graph, m.module, HasDatInitProc) # Very similar to the contents of symInDynamicLib - basically only the # things needed for the hot code reloading runtime procs to be loaded @@ -1728,10 +1587,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, skVar)]) + m.s[cfsVars].addf("static $2 $1;$n", [prc.loc.r, getTypeDesc(m, prc.loc.t)]) result = "\t$1 = ($2) $3($4, $5);$n" % - [tmp, getTypeDesc(m, prc.typ, skVar), getProcFunc.rope, handle.rope, makeCString(prefix & sym)] + [tmp, getTypeDesc(m, prc.typ), getProcFunc.rope, handle.rope, makeCString(prefix & sym)] proc genInitCode(m: BModule) = ## this function is called in cgenWriteModules after all modules are closed, @@ -1766,23 +1625,21 @@ proc genInitCode(m: BModule) = if m.thing.s(section).len > 0: moduleInitRequired = true if addHcrGuards: prc.add("\tif (nim_hcr_do_init_) {\n\n") + prc.add(genSectionStart(section, m.config)) prc.add(m.thing.s(section)) + prc.add(genSectionEnd(section, m.config)) if addHcrGuards: prc.add("\n\t} // nim_hcr_do_init_\n") if m.preInitProc.s(cpsInit).len > 0 or m.preInitProc.s(cpsStmts).len > 0: # Give this small function its own scope prc.addf("{$N", []) # Keep a bogus frame in case the code needs one - prc.add("\tTFrame FR_; FR_.len = 0;\n") + prc.add(~"\tTFrame FR_; FR_.len = 0;$N") writeSection(preInitProc, cpsLocals) writeSection(preInitProc, cpsInit, m.hcrOn) writeSection(preInitProc, cpsStmts) - prc.addf("}/* preInitProc end */$N", []) - when false: - m.initProc.blocks[0].sections[cpsLocals].add m.preInitProc.s(cpsLocals) - m.initProc.blocks[0].sections[cpsInit].prepend m.preInitProc.s(cpsInit) - m.initProc.blocks[0].sections[cpsStmts].prepend m.preInitProc.s(cpsStmts) + prc.addf("}$N", []) # add new scope for following code, because old vcc compiler need variable # be defined at the top of the block @@ -1799,23 +1656,15 @@ proc genInitCode(m: BModule) = var procname = makeCString(m.module.name.s) prc.add(initFrame(m.initProc, procname, quotedFilename(m.config, m.module.info))) else: - prc.add("\tTFrame FR_; FR_.len = 0;\n") + prc.add(~"\tTFrame FR_; FR_.len = 0;$N") writeSection(initProc, cpsInit, m.hcrOn) writeSection(initProc, cpsStmts) if beforeRetNeeded in m.initProc.flags: - prc.add("\tBeforeRet_: ;\n") - - if sfMainModule in m.module.flags and m.config.exc == excGoto: - if getCompilerProc(m.g.graph, "nimTestErrorFlag") != nil: - m.appcg(prc, "\t#nimTestErrorFlag();$n", []) - + prc.add(~"\tBeforeRet_: ;$n") if optStackTrace in m.initProc.options and preventStackTrace notin m.flags: prc.add(deinitFrame(m.initProc)) - elif sfMainModule in m.module.flags and m.config.exc == excGoto: - if getCompilerProc(m.g.graph, "nimTestErrorFlag") != nil: - m.appcg(prc, "\t#nimTestErrorFlag();$n", []) prc.addf("}$N", []) @@ -1839,7 +1688,7 @@ proc genInitCode(m: BModule) = m.s[cfsInitProc].addf("}$N$N", []) for i, el in pairs(m.extensionLoaders): - if el != "": + if el != nil: let ex = "NIM_EXTERNC N_NIMCALL(void, nimLoadProcs$1)(void) {$2}$N$N" % [(i.ord - '0'.ord).rope, el] moduleInitRequired = true @@ -1847,7 +1696,6 @@ proc genInitCode(m: BModule) = if moduleInitRequired or sfMainModule in m.module.flags: m.s[cfsInitProc].add(prc) - #rememberFlag(m.g.graph, m.module, HasModuleInitProc) genDatInitCode(m) @@ -1862,21 +1710,28 @@ proc genModule(m: BModule, cfile: Cfile): Rope = var moduleIsEmpty = true result = getFileHeader(m.config, cfile) + result.add(genMergeInfo(m)) generateThreadLocalStorage(m) generateHeaders(m) + result.add(genSectionStart(cfsHeaders, m.config)) result.add(m.s[cfsHeaders]) if m.config.cppCustomNamespace.len > 0: - openNamespaceNim(m.config.cppCustomNamespace, result) + result.add openNamespaceNim(m.config.cppCustomNamespace) + result.add(genSectionEnd(cfsHeaders, m.config)) + result.add(genSectionStart(cfsFrameDefines, m.config)) if m.s[cfsFrameDefines].len > 0: result.add(m.s[cfsFrameDefines]) else: result.add("#define nimfr_(x, y)\n#define nimln_(x, y)\n") + result.add(genSectionEnd(cfsFrameDefines, m.config)) for i in cfsForwardTypes..cfsProcs: if m.s[i].len > 0: moduleIsEmpty = false + result.add(genSectionStart(i, m.config)) result.add(m.s[i]) + result.add(genSectionEnd(i, m.config)) if m.s[cfsInitProc].len > 0: moduleIsEmpty = false @@ -1886,10 +1741,15 @@ proc genModule(m: BModule, cfile: Cfile): Rope = result.add(m.s[cfsDatInitProc]) if m.config.cppCustomNamespace.len > 0: - closeNamespaceNim(result) + result.add closeNamespaceNim() if moduleIsEmpty: - result = "" + result = nil + +proc newPreInitProc(m: BModule): BProc = + result = newProc(nil, m) + # little hack so that unique temporaries are generated: + result.labels = 100_000 proc initProcOptions(m: BModule): TOptions = let opts = m.config.options @@ -1910,11 +1770,8 @@ proc rawNewModule(g: BModuleList; module: PSym, filename: AbsoluteFile): BModule result.typeInfoMarker = initTable[SigHash, Rope]() result.sigConflicts = initCountTable[SigHash]() result.initProc = newProc(nil, result) - for i in low(result.s)..high(result.s): result.s[i] = newRopeAppender() result.initProc.options = initProcOptions(result) - result.preInitProc = newProc(nil, result) - result.preInitProc.flags.incl nimErrorFlagDisabled - result.preInitProc.labels = 100_000 # little hack so that unique temporaries are generated + result.preInitProc = newPreInitProc(result) initNodeTable(result.dataCache) result.typeStack = @[] result.typeNodesName = getTempName(result) @@ -1931,7 +1788,7 @@ proc rawNewModule(g: BModuleList; module: PSym, filename: AbsoluteFile): BModule proc rawNewModule(g: BModuleList; module: PSym; conf: ConfigRef): BModule = result = rawNewModule(g, module, AbsoluteFile toFullPath(conf, module.position.FileIndex)) -proc newModule*(g: BModuleList; module: PSym; conf: ConfigRef): BModule = +proc newModule(g: BModuleList; module: PSym; conf: ConfigRef): BModule = # we should create only one cgen module for each module sym result = rawNewModule(g, module, conf) if module.position >= g.modules.len: @@ -1944,10 +1801,9 @@ template injectG() {.dirty.} = graph.backend = newModuleList(graph) let g = BModuleList(graph.backend) -proc setupCgen*(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PPassContext = +proc myOpen(graph: ModuleGraph; module: PSym): PPassContext = injectG() result = newModule(g, module, graph.config) - result.idgen = idgen if optGenIndex in graph.config.globalOptions and g.generatedHeader == nil: let f = if graph.config.headerFile.len > 0: AbsoluteFile graph.config.headerFile else: graph.config.projectFull @@ -1956,23 +1812,28 @@ proc setupCgen*(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PPassCont incl g.generatedHeader.flags, isHeaderFile proc writeHeader(m: BModule) = - var result = headerTop() + var result = ("/* Generated by Nim Compiler v$1 */$N" & + "/* (c) 2017 Andreas Rumpf */$N" & + "/* The generated code is subject to the original license. */$N") % + [rope(VersionAsString)] + var guard = "__$1__" % [m.filename.splitFile.name.rope] result.addf("#ifndef $1$n#define $1$n", [guard]) - addNimDefines(result, m.config) + addIntTypes(result, m.config) generateHeaders(m) generateThreadLocalStorage(m) for i in cfsHeaders..cfsProcs: + result.add(genSectionStart(i, m.config)) result.add(m.s[i]) - if m.config.cppCustomNamespace.len > 0 and i == cfsHeaders: - openNamespaceNim(m.config.cppCustomNamespace, result) + result.add(genSectionEnd(i, m.config)) + if m.config.cppCustomNamespace.len > 0 and i == cfsHeaders: result.add openNamespaceNim(m.config.cppCustomNamespace) result.add(m.s[cfsInitProc]) if optGenDynLib in m.config.globalOptions: result.add("N_LIB_IMPORT ") - result.addf("N_CDECL(void, $1NimMain)(void);$n", [rope m.config.nimMainPrefix]) - if m.config.cppCustomNamespace.len > 0: closeNamespaceNim(result) + result.addf("N_CDECL(void, NimMain)(void);$n", []) + if m.config.cppCustomNamespace.len > 0: result.add closeNamespaceNim() result.addf("#endif /* $1 */$n", [guard]) if not writeRope(result, m.filename): rawMessage(m.config, errCannotOpenFile, m.filename.string) @@ -1980,9 +1841,9 @@ proc writeHeader(m: BModule) = proc getCFile(m: BModule): AbsoluteFile = let ext = if m.compileToCpp: ".nim.cpp" - elif m.config.backend == backendObjc or sfCompileToObjc in m.module.flags: ".nim.m" + elif m.config.cmd == cmdCompileToOC or sfCompileToObjc in m.module.flags: ".nim.m" else: ".nim.c" - result = changeFileExt(completeCfilePath(m.config, mangleModuleName(m.config, m.cfilename).AbsoluteFile), ext) + result = changeFileExt(completeCfilePath(m.config, withPackageName(m.config, m.cfilename)), ext) when false: proc myOpenCached(graph: ModuleGraph; module: PSym, rd: PRodReader): PPassContext = @@ -2010,15 +1871,19 @@ proc addHcrInitGuards(p: BProc, n: PNode, inInitGuard: var bool) = genStmts(p, n) -proc genTopLevelStmt*(m: BModule; n: PNode) = - ## Also called from `ic/cbackend.nim`. - if pipelineutils.skipCodegen(m.config, n): return +proc myProcess(b: PPassContext, n: PNode): PNode = + result = n + if b == nil: return + var m = BModule(b) + if passes.skipCodegen(m.config, n) or + not moduleHasChanged(m.g.graph, m.module): + return m.initProc.options = initProcOptions(m) #softRnl = if optLineDir in m.config.options: noRnl else: rnl # XXX replicate this logic! - var transformedN = transformStmt(m.g.graph, m.idgen, m.module, n) + var transformedN = transformStmt(m.g.graph, m.module, n) if sfInjectDestructors in m.module.flags: - transformedN = injectDestructorCalls(m.g.graph, m.idgen, m.module, transformedN) + transformedN = injectDestructorCalls(m.g.graph, m.module, transformedN) if m.hcrOn: addHcrInitGuards(m.initProc, transformedN, m.inHcrInitGuard) @@ -2056,52 +1921,82 @@ proc shouldRecompile(m: BModule; code: Rope, cfile: Cfile): bool = # it would generate multiple 'main' procs, for instance. proc writeModule(m: BModule, pending: bool) = - template onExit() = close(m.ndi, m.config) let cfile = getCFile(m) - if moduleHasChanged(m.g.graph, m.module): + + if true or optForceFullMake in m.config.globalOptions: + if moduleHasChanged(m.g.graph, m.module): + genInitCode(m) + finishTypeDescriptions(m) + if sfMainModule in m.module.flags: + # generate main file: + genMainProc(m) + m.s[cfsProcHeaders].add(m.g.mainModProcs) + generateThreadVarsSize(m) + + var cf = Cfile(nimname: m.module.name.s, cname: cfile, + obj: completeCfilePath(m.config, toObjFile(m.config, cfile)), flags: {}) + var code = genModule(m, cf) + if code != nil or m.config.symbolFiles != disabledSf: + when hasTinyCBackend: + if conf.cmd == cmdRun: + tccgen.compileCCode($code) + return + + if not shouldRecompile(m, code, cf): cf.flags = {CfileFlag.Cached} + addFileToCompile(m.config, cf) + elif pending and mergeRequired(m) and sfMainModule notin m.module.flags: + let cf = Cfile(nimname: m.module.name.s, cname: cfile, + obj: completeCfilePath(m.config, toObjFile(m.config, cfile)), flags: {}) + mergeFiles(cfile, m) genInitCode(m) finishTypeDescriptions(m) - if sfMainModule in m.module.flags: - # generate main file: - genMainProc(m) - m.s[cfsProcHeaders].add(m.g.mainModProcs) - generateThreadVarsSize(m) - - var cf = Cfile(nimname: m.module.name.s, cname: cfile, - obj: completeCfilePath(m.config, toObjFile(m.config, cfile)), flags: {}) - var code = genModule(m, cf) - if code != "" or m.config.symbolFiles != disabledSf: - when hasTinyCBackend: - if m.config.cmd == cmdTcc: - tccgen.compileCCode($code, m.config) - onExit() - return - - if not shouldRecompile(m, code, cf): cf.flags = {CfileFlag.Cached} + var code = genModule(m, cf) + if code != nil: + if not writeRope(code, cfile): + rawMessage(m.config, errCannotOpenFile, cfile.string) + addFileToCompile(m.config, cf) + else: + # Consider: first compilation compiles ``system.nim`` and produces + # ``system.c`` but then compilation fails due to an error. This means + # that ``system.o`` is missing, so we need to call the C compiler for it: + var cf = Cfile(nimname: m.module.name.s, cname: cfile, + obj: completeCfilePath(m.config, toObjFile(m.config, cfile)), flags: {}) + if not fileExists(cf.obj): cf.flags = {CfileFlag.Cached} addFileToCompile(m.config, cf) - onExit() + close(m.ndi) proc updateCachedModule(m: BModule) = let cfile = getCFile(m) var cf = Cfile(nimname: m.module.name.s, cname: cfile, obj: completeCfilePath(m.config, toObjFile(m.config, cfile)), flags: {}) - if sfMainModule notin m.module.flags: - genMainProc(m) - cf.flags = {CfileFlag.Cached} - addFileToCompile(m.config, cf) -proc finalCodegenActions*(graph: ModuleGraph; m: BModule; n: PNode) = - ## Also called from IC. + if mergeRequired(m) and sfMainModule notin m.module.flags: + mergeFiles(cfile, m) + genInitCode(m) + finishTypeDescriptions(m) + var code = genModule(m, cf) + if code != nil: + if not writeRope(code, cfile): + rawMessage(m.config, errCannotOpenFile, cfile.string) + addFileToCompile(m.config, cf) + else: + if sfMainModule notin m.module.flags: + genMainProc(m) + cf.flags = {CfileFlag.Cached} + addFileToCompile(m.config, cf) + +proc myClose(graph: ModuleGraph; b: PPassContext, n: PNode): PNode = + result = n + if b == nil: return + var m = BModule(b) if sfMainModule in m.module.flags: - # phase ordering problem here: We need to announce this - # dependency to 'nimTestErrorFlag' before system.c has been written to disk. - if m.config.exc == excGoto and getCompilerProc(graph, "nimTestErrorFlag") != nil: - cgsym(m, "nimTestErrorFlag") + let testForError = getCompilerProc(graph, "nimTestErrorFlag") + if testForError != nil and graph.config.exc == excGoto: + n.add newTree(nkCall, testForError.newSymNode) - 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 + for i in countdown(high(graph.globalDestructors), 0): + n.add graph.globalDestructors[i] + 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? @@ -2112,7 +2007,7 @@ proc finalCodegenActions*(graph: ModuleGraph; m: BModule; n: PNode) = if m.hcrOn: # make sure this is pulled in (meaning hcrGetGlobal() is called for it during init) - cgsym(m, "programResult") + discard cgsym(m, "programResult") if m.inHcrInitGuard: endBlock(m.initProc) @@ -2122,25 +2017,24 @@ proc finalCodegenActions*(graph: ModuleGraph; m: BModule; n: PNode) = # so it can load the HCR runtime and later pass the library handle to the HCR runtime which # will in turn pass it to the other modules it initializes so they can initialize the # register/get procs so they don't have to have the definitions of these functions as well - cgsym(m, "nimLoadLibrary") - cgsym(m, "nimLoadLibraryError") - cgsym(m, "nimGetProcAddr") - cgsym(m, "procAddrError") - cgsym(m, "rawWrite") + discard cgsym(m, "nimLoadLibrary") + discard cgsym(m, "nimLoadLibraryError") + discard cgsym(m, "nimGetProcAddr") + discard cgsym(m, "procAddrError") + discard cgsym(m, "rawWrite") # raise dependencies on behalf of genMainProc - if m.config.target.targetOS != osStandalone and m.config.selectedGC notin {gcNone, gcArc, gcOrc}: - cgsym(m, "initStackBottomWith") + if m.config.target.targetOS != osStandalone and m.config.selectedGC != gcNone: + discard cgsym(m, "initStackBottomWith") if emulatedThreadVars(m.config) and m.config.target.targetOS != osStandalone: - cgsym(m, "initThreadVarsEmulation") + discard cgsym(m, "initThreadVarsEmulation") if m.g.forwardedProcs.len == 0: incl m.flags, objHasKidsValid let disp = generateMethodDispatchers(graph) for x in disp: genProcAux(m, x.sym) - let mm = m - m.g.modulesClosed.add mm + m.g.modulesClosed.add m proc genForwardedProcs(g: BModuleList) = # Forward declared proc:s lack bodies when first encountered, so they're given @@ -2149,7 +2043,8 @@ proc genForwardedProcs(g: BModuleList) = while g.forwardedProcs.len > 0: let prc = g.forwardedProcs.pop() - m = g.modules[prc.itemId.module] + ms = getModule(prc) + m = g.modules[ms.position] if sfForward in prc.flags: internalError(m.config, prc.info, "still forwarded: " & prc.name.s) @@ -2168,3 +2063,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) diff --git a/compiler/cgendata.nim b/compiler/cgendata.nim index e1309e0fd..326bdeb45 100644 --- a/compiler/cgendata.nim +++ b/compiler/cgendata.nim @@ -11,11 +11,12 @@ import ast, ropes, options, intsets, - tables, ndi, lineinfos, pathutils, modulegraphs, sets + tables, ndi, lineinfos, pathutils, modulegraphs type TLabel* = Rope # for the C generator a label is just a rope TCFileSection* = enum # the sections a generated C file consists of + cfsMergeInfo, # section containing merge information cfsHeaders, # section for C include file headers cfsFrameDefines # section for nim frame macros cfsForwardTypes, # section for C forward typedefs @@ -23,17 +24,21 @@ type cfsSeqTypes, # section for sequence types only # this is needed for strange type generation # reasons - cfsTypeInfo, # section for type information (ag ABI checks) + cfsFieldInfo, # section for field information + cfsTypeInfo, # section for type information cfsProcHeaders, # section for C procs prototypes - cfsStrData, # section for constant string literals cfsData, # section for C constant data cfsVars, # section for C variable declarations cfsProcs, # section for C procs that are not inline cfsInitProc, # section for the C init proc cfsDatInitProc, # section for the C datInit proc cfsTypeInit1, # section 1 for declarations of type information + cfsTypeInit2, # section 2 for init of type information cfsTypeInit3, # section 3 for init of type information + cfsDebugInit, # section for init of debug information cfsDynLibInit, # section for init of dynamic library binding + cfsDynLibDeinit # section for deinitialization of dynamic + # libraries TCTypeKind* = enum # describes the type kind of a C type ctVoid, ctChar, ctBool, ctInt, ctInt8, ctInt16, ctInt32, ctInt64, @@ -65,8 +70,7 @@ type hasCurFramePointer, noSafePoints, nimErrorFlagAccessed, - nimErrorFlagDeclared, - nimErrorFlagDisabled + nimErrorFlagDeclared TCProc = object # represents C proc that is currently generated prc*: PSym # the Nim proc that this C proc belongs to @@ -86,20 +90,16 @@ 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 # requires 'T x = T()' to become 'T x; x = T()' # (yes, C++ is weird like that) - withinTryWithExcept*: int # required for goto based exception handling - withinBlockLeaveActions*: int # complex to explain sigConflicts*: CountTable[string] - inUncheckedAssignSection*: int TTypeSeq* = seq[PType] TypeCache* = Table[SigHash, Rope] - TypeCacheWithOwner* = Table[SigHash, tuple[str: Rope, owner: int32]] + TypeCacheWithOwner* = Table[SigHash, tuple[str: Rope, owner: PSym]] CodegenFlag* = enum preventStackTrace, # true if stack traces need to be prevented @@ -109,8 +109,7 @@ type isHeaderFile, # C source file is the header file includesStringh, # C source file already includes ```` objHasKidsValid # whether we can rely on tfObjHasKids - useAliveDataFromDce # use the `alive: IntSet` field instead of - # computing alive data on our own. + BModuleList* = ref object of RootObj mainModProcs*, mainModInit*, otherModsInit*, mainDatInit*: Rope @@ -120,7 +119,6 @@ type forwardedProcs*: seq[PSym] # proc:s that did not yet have a body generatedHeader*: BModule typeInfoMarker*: TypeCacheWithOwner - typeInfoMarkerV2*: TypeCacheWithOwner config*: ConfigRef graph*: ModuleGraph strVersion*, seqVersion*: int # version of the string/seq implementation to use @@ -145,17 +143,11 @@ type # without extension) tmpBase*: Rope # base for temp identifier generation typeCache*: TypeCache # cache the generated types - 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 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 - alive*: IntSet # symbol IDs of alive data as computed by `dce.nim` headerFiles*: seq[string] # needed headers to include typeInfoMarker*: TypeCache # needed for generating type information - typeInfoMarkerV2*: TypeCache initProc*: BProc # code for init procedure preInitProc*: BProc # code executed before the init proc hcrCreateTypeInfosProc*: Rope # type info globals are in here when HCR=on @@ -167,13 +159,13 @@ type labels*: Natural # for generating unique module-scope names extensionLoaders*: array['0'..'9', Rope] # special procs for the # OpenGL wrapper + injectStmt*: Rope sigConflicts*: CountTable[SigHash] g*: BModuleList ndi*: NdiFile 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: @@ -187,24 +179,19 @@ proc procSec*(p: BProc, s: TCProcSection): var Rope {.inline.} = # top level proc sections result = p.blocks[0].sections[s] -proc initBlock*(): TBlock = - result = TBlock() - for i in low(result.sections)..high(result.sections): - result.sections[i] = newRopeAppender() - proc newProc*(prc: PSym, module: BModule): BProc = new(result) result.prc = prc result.module = module - result.options = if prc != nil: prc.options - else: module.config.options - result.blocks = @[initBlock()] + if prc != nil: result.options = prc.options + else: result.options = module.config.options + newSeq(result.blocks, 1) result.nestedTryStmts = @[] result.finallySafePoints = @[] result.sigConflicts = initCountTable[string]() proc newModuleList*(g: ModuleGraph): BModuleList = - BModuleList(typeInfoMarker: initTable[SigHash, tuple[str: Rope, owner: int32]](), + BModuleList(typeInfoMarker: initTable[SigHash, tuple[str: Rope, owner: PSym]](), config: g.config, graph: g, nimtvDeclared: initIntSet()) iterator cgenModules*(g: BModuleList): BModule = diff --git a/compiler/cgmeth.nim b/compiler/cgmeth.nim index 4940a9093..a71ac6ea7 100644 --- a/compiler/cgmeth.nim +++ b/compiler/cgmeth.nim @@ -7,15 +7,11 @@ # distribution, for details about the copyright. # -## This module implements code generation for methods. +## This module implements code generation for multi methods. import intsets, options, ast, msgs, idents, renderer, types, magicsys, - sempass2, modulegraphs, lineinfos - -when defined(nimPreviewSlimSystem): - import std/assertions - + sempass2, strutils, modulegraphs, lineinfos proc genConv(n: PNode, d: PType, downcast: bool; conf: ConfigRef): PNode = var dest = skipTypes(d, abstractPtrs) @@ -50,7 +46,6 @@ proc methodCall*(n: PNode; conf: ConfigRef): PNode = # replace ordinary method by dispatcher method: let disp = getDispatcher(result[0].sym) if disp != nil: - result[0].typ = disp.typ result[0].sym = disp # change the arguments to up/downcasts to fit the dispatcher's parameters: for i in 1.. resultPos: - disp.ast[resultPos].sym = copySym(s.ast[resultPos].sym, nextSymId(idgen)) + disp.ast[resultPos].sym = copySym(s.ast[resultPos].sym) else: # We've encountered a method prototype without a filled-in # resultPos slot. We put a placeholder in there that will @@ -148,7 +140,24 @@ proc fixupDispatcher(meth, disp: PSym; conf: ConfigRef) = disp.ast[resultPos].kind == nkEmpty: disp.ast[resultPos] = copyTree(meth.ast[resultPos]) -proc methodDef*(g: ModuleGraph; idgen: IdGenerator; s: PSym) = + # The following code works only with lock levels, so we disable + # it when they're not available. + when declared(TLockLevel): + proc `<`(a, b: TLockLevel): bool {.borrow.} + proc `==`(a, b: TLockLevel): bool {.borrow.} + if disp.typ.lockLevel == UnspecifiedLockLevel: + disp.typ.lockLevel = meth.typ.lockLevel + elif meth.typ.lockLevel != UnspecifiedLockLevel and + meth.typ.lockLevel != disp.typ.lockLevel: + message(conf, meth.info, warnLockLevel, + "method has lock level $1, but another method has $2" % + [$meth.typ.lockLevel, $disp.typ.lockLevel]) + # XXX The following code silences a duplicate warning in + # checkMethodeffects() in sempass2.nim for now. + if disp.typ.lockLevel < meth.typ.lockLevel: + disp.typ.lockLevel = meth.typ.lockLevel + +proc methodDef*(g: ModuleGraph; s: PSym, fromCache: bool) = var witness: PSym for i in 0..= 0: - result = newNodeI(nkStmtList, n.info) - for i in countdown(c.finallys.high, fin): - var vars = FreshVarsContext(tab: initTable[int, PSym](), config: c.config, info: n.info, idgen: c.idgen) - result.add freshVars(copyTree(c.finallys[i]), vars) - c.idgen = vars.idgen - result.add n - of nkSkip: discard - else: - for i in 0 ..< n.len: - result[i] = preprocess(c, n[i]) - -proc transformClosureIterator*(g: ModuleGraph; idgen: IdGenerator; fn: PSym, n: PNode): PNode = +proc transformClosureIterator*(g: ModuleGraph; fn: PSym, n: PNode): PNode = var ctx: Ctx ctx.g = g ctx.fn = fn - ctx.idgen = idgen if getEnvParam(fn).isNil: # Lambda lifting was not done yet. Use temporary :state sym, which will # be handled specially by lambda lifting. Local temp vars (if needed) # should follow the same logic. - 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"), nextSymId(idgen), fn, fn.info) - var pc = PreprocessContext(finallys: @[], config: g.config, idgen: idgen) - var n = preprocess(pc, n.toStmtList) - #echo "transformed into ", n - #var n = n.toStmtList + ctx.stateVarSym = newSym(skVar, getIdent(ctx.g.cache, ":state"), fn, fn.info) + ctx.stateVarSym.typ = g.createClosureIterStateType(fn) + ctx.stateLoopLabel = newSym(skLabel, getIdent(ctx.g.cache, ":stateLoop"), fn, fn.info) + var n = n.toStmtList discard ctx.newState(n, nil) let gotoOut = newTree(nkGotoState, g.newIntLit(n.info, -1)) diff --git a/compiler/cmdlinehelper.nim b/compiler/cmdlinehelper.nim index 02162755c..b3c0c46c2 100644 --- a/compiler/cmdlinehelper.nim +++ b/compiler/cmdlinehelper.nim @@ -7,31 +7,20 @@ # distribution, for details about the copyright. # -## Helpers for binaries that use compiler passes, e.g.: nim, nimsuggest, nimfix +## Helpers for binaries that use compiler passes, eg: nim, nimsuggest, nimfix import - options, idents, nimconf, extccomp, commands, msgs, - lineinfos, modulegraphs, condsyms, os, pathutils, parseopt + options, idents, nimconf, scriptconfig, extccomp, commands, msgs, + lineinfos, modulegraphs, condsyms, os, pathutils -proc prependCurDir*(f: AbsoluteFile): AbsoluteFile = - when defined(unix): - if os.isAbsolute(f.string): result = f - else: result = AbsoluteFile("./" & f.string) - else: - result = f - -proc addCmdPrefix*(result: var string, kind: CmdLineKind) = - # consider moving this to std/parseopt - case kind - of cmdLongOption: result.add "--" - of cmdShortOption: result.add "-" - of cmdArgument, cmdEnd: discard +from strutils import normalize type NimProg* = ref object suggestMode*: bool supportsStdinFile*: bool processCmdLine*: proc(pass: TCmdLinePass, cmd: string; config: ConfigRef) + mainCommand*: proc(graph: ModuleGraph) proc initDefinesProg*(self: NimProg, conf: ConfigRef, name: string) = condsyms.initDefines(conf.symbols) @@ -39,40 +28,76 @@ proc initDefinesProg*(self: NimProg, conf: ConfigRef, name: string) = proc processCmdLineAndProjectPath*(self: NimProg, conf: ConfigRef) = self.processCmdLine(passCmd1, "", conf) - if conf.projectIsCmd and conf.projectName in ["-", ""]: - handleCmdInput(conf) - elif self.supportsStdinFile and conf.projectName == "-": + if self.supportsStdinFile and conf.projectName == "-": handleStdinInput(conf) elif conf.projectName != "": - setFromProjectName(conf, conf.projectName) + try: + conf.projectFull = canonicalizePath(conf, AbsoluteFile conf.projectName) + except OSError: + conf.projectFull = AbsoluteFile conf.projectName + let p = splitFile(conf.projectFull) + let dir = if p.dir.isEmpty: AbsoluteDir getCurrentDir() else: p.dir + conf.projectPath = AbsoluteDir canonicalizePath(conf, AbsoluteFile dir) + conf.projectName = p.name else: conf.projectPath = AbsoluteDir canonicalizePath(conf, AbsoluteFile getCurrentDir()) -proc loadConfigsAndProcessCmdLine*(self: NimProg, cache: IdentCache; conf: ConfigRef; - graph: ModuleGraph): bool = +proc loadConfigsAndRunMainCommand*(self: NimProg, cache: IdentCache; conf: ConfigRef): bool = + loadConfigs(DefaultConfig, cache, conf) # load all config files if self.suggestMode: - conf.setCmd cmdIdeTools - if conf.cmd == cmdNimscript: - incl(conf.globalOptions, optWasNimscript) - loadConfigs(DefaultConfig, cache, conf, graph.idgen) # load all config files + conf.command = "nimsuggest" - if not self.suggestMode: + template runNimScriptIfExists(path: AbsoluteFile) = + let p = path # eval once + if fileExists(p): + runNimScript(cache, p, freshDefines = false, conf) + + # Caution: make sure this stays in sync with `loadConfigs` + if optSkipSystemConfigFile notin conf.globalOptions: + runNimScriptIfExists(getSystemConfigPath(conf, DefaultConfigNims)) + + if optSkipUserConfigFile notin conf.globalOptions: + runNimScriptIfExists(getUserConfigPath(DefaultConfigNims)) + + if optSkipParentConfigFiles notin conf.globalOptions: + for dir in parentDirs(conf.projectPath.string, fromRoot = true, inclusive = false): + runNimScriptIfExists(AbsoluteDir(dir) / DefaultConfigNims) + + if optSkipProjConfigFile notin conf.globalOptions: + runNimScriptIfExists(conf.projectPath / DefaultConfigNims) + block: let scriptFile = conf.projectFull.changeFileExt("nims") - # 'nim foo.nims' means to just run the NimScript file and do nothing more: - if fileExists(scriptFile) and scriptFile == conf.projectFull: - if conf.cmd == cmdNone: conf.setCmd cmdNimscript - if conf.cmd == cmdNimscript: return false + if not self.suggestMode: + runNimScriptIfExists(scriptFile) + # 'nim foo.nims' means to just run the NimScript file and do nothing more: + if fileExists(scriptFile) and scriptFile == conf.projectFull: + if conf.command == "": + conf.command = "e" + return false + elif conf.command.normalize == "e": + return false + else: + if scriptFile != conf.projectFull: + runNimScriptIfExists(scriptFile) + else: + # 'nimsuggest foo.nims' means to just auto-complete the NimScript file + discard + # now process command line arguments again, because some options in the # command line can overwrite the config file's settings - if conf.backend != backendJs: # bug #19059 - extccomp.initVars(conf) + extccomp.initVars(conf) + # XXX This is hacky. We need to find a better way. + case conf.command + of "cpp", "compiletocpp": + conf.cmd = cmdCompileToCpp + else: + discard + self.processCmdLine(passCmd2, "", conf) - if conf.cmd == cmdNone: + if conf.command == "": rawMessage(conf, errGenerated, "command missing") + let graph = newModuleGraph(cache, conf) graph.suggestMode = self.suggestMode + self.mainCommand(graph) return true - -proc loadConfigsAndRunMainCommand*(self: NimProg, cache: IdentCache; conf: ConfigRef; graph: ModuleGraph): bool = - ## Alias for loadConfigsAndProcessCmdLine, here for backwards compatibility - loadConfigsAndProcessCmdLine(self, cache, conf, graph) diff --git a/compiler/commands.nim b/compiler/commands.nim index 7c0f7ab0a..ca6ef5d94 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -9,33 +9,34 @@ # This module handles the parsing of command line arguments. + # We do this here before the 'import' statement so 'defined' does not get -# confused with 'TGCMode.gcMarkAndSweep' etc. +# confused with 'TGCMode.gcGenerational' etc. template bootSwitch(name, expr, userString) = # Helper to build boot constants, for debugging you can 'echo' the else part. const name = if expr: " " & userString else: "" bootSwitch(usedRelease, defined(release), "-d:release") bootSwitch(usedDanger, defined(danger), "-d:danger") -# `useLinenoise` deprecated in favor of `nimUseLinenoise`, kept for backward compatibility -bootSwitch(useLinenoise, defined(nimUseLinenoise) or defined(useLinenoise), "-d:nimUseLinenoise") +bootSwitch(usedGnuReadline, defined(useLinenoise), "-d:useLinenoise") bootSwitch(usedBoehm, defined(boehmgc), "--gc:boehm") bootSwitch(usedMarkAndSweep, defined(gcmarkandsweep), "--gc:markAndSweep") +bootSwitch(usedGenerational, defined(gcgenerational), "--gc:generational") bootSwitch(usedGoGC, defined(gogc), "--gc:go") bootSwitch(usedNoGC, defined(nogc), "--gc:none") -import std/[setutils, os, strutils, parseutils, parseopt, sequtils, strtabs] import - msgs, options, nversion, condsyms, extccomp, platform, - wordrecg, nimblecmd, lineinfos, pathutils, pathnorm + os, msgs, options, nversion, condsyms, strutils, extccomp, platform, + wordrecg, parseutils, nimblecmd, parseopt, sequtils, lineinfos, + pathutils, strtabs -from ast import setUseIc, eqTypeFlags, tfGcSafe, tfNoSideEffect - -when defined(nimPreviewSlimSystem): - import std/assertions +from incremental import nimIncremental # but some have deps to imported modules. Yay. bootSwitch(usedTinyC, hasTinyCBackend, "-d:tinyc") +bootSwitch(usedNativeStacktrace, + defined(nativeStackTrace) and nativeStackTraceSupported, + "-d:nativeStackTrace") bootSwitch(usedFFI, hasFFI, "-d:nimHasLibFFI") type @@ -50,14 +51,15 @@ const "Copyright (c) 2006-" & copyrightYear & " by Andreas Rumpf\n" proc genFeatureDesc[T: enum](t: typedesc[T]): string {.compileTime.} = - result = "" - for f in T: - if result.len > 0: result.add "|" - result.add $f + var x = "" + for f in low(T)..high(T): + if x.len > 0: x.add "|" + x.add $f + x const - Usage = slurp"../doc/basicopt.txt".replace(" //", " ") - AdvancedUsage = slurp"../doc/advopt.txt".replace(" //", " ") % [genFeatureDesc(Feature), genFeatureDesc(LegacyFeature)] + Usage = slurp"../doc/basicopt.txt".replace(" //", " ") + AdvancedUsage = slurp"../doc/advopt.txt".replace(" //", " ") % [genFeatureDesc(Feature), genFeatureDesc(LegacyFeature)] proc getCommandLineDesc(conf: ConfigRef): string = result = (HelpMessage % [VersionAsString, platform.OS[conf.target.hostOS].name, @@ -94,14 +96,13 @@ proc writeVersionInfo(conf: ConfigRef; pass: TCmdLinePass) = CPU[conf.target.hostCPU].name, CompileDate]), {msgStdout}) - const gitHash {.strdefine.} = gorge("git log -n 1 --format=%H").strip - # xxx move this logic to std/private/gitutils + const gitHash = gorge("git log -n 1 --format=%H").strip when gitHash.len == 40: msgWriteln(conf, "git hash: " & gitHash, {msgStdout}) msgWriteln(conf, "active boot switches:" & usedRelease & usedDanger & - usedTinyC & useLinenoise & - usedFFI & usedBoehm & usedMarkAndSweep & usedGoGC & usedNoGC, + usedTinyC & usedGnuReadline & usedNativeStacktrace & + usedFFI & usedBoehm & usedMarkAndSweep & usedGenerational & usedGoGC & usedNoGC, {msgStdout}) msgQuit(0) @@ -116,7 +117,7 @@ const errInvalidCmdLineOption = "invalid command line option: '$1'" errOnOrOffExpectedButXFound = "'on' or 'off' expected, but '$1' found" errOnOffOrListExpectedButXFound = "'on', 'off' or 'list' expected, but '$1' found" - errOffHintsError = "'off', 'hint', 'error' or 'usages' expected, but '$1' found" + errOffHintsError = "'off', 'hint' or 'error' expected, but '$1' found" proc invalidCmdLineOption(conf: ConfigRef; pass: TCmdLinePass, switch: string, info: TLineInfo) = if switch == " ": localError(conf, info, errInvalidCmdLineOption % "-") @@ -140,36 +141,27 @@ proc splitSwitch(conf: ConfigRef; switch: string, cmd, arg: var string, pass: TC elif switch[i] == '[': arg = substr(switch, i) else: invalidCmdLineOption(conf, pass, switch, info) -template switchOn(arg: string): bool = - # xxx use `switchOn` wherever appropriate - case arg.normalize - of "", "on": true - of "off": false - else: - localError(conf, info, errOnOrOffExpectedButXFound % arg) - false - proc processOnOffSwitch(conf: ConfigRef; op: TOptions, arg: string, pass: TCmdLinePass, info: TLineInfo) = case arg.normalize - of "", "on": conf.options.incl op - of "off": conf.options.excl op + of "","on": conf.options = conf.options + op + of "off": conf.options = conf.options - op else: localError(conf, info, errOnOrOffExpectedButXFound % arg) proc processOnOffSwitchOrList(conf: ConfigRef; op: TOptions, arg: string, pass: TCmdLinePass, info: TLineInfo): bool = result = false case arg.normalize - of "on": conf.options.incl op - of "off": conf.options.excl op + of "on": conf.options = conf.options + op + of "off": conf.options = conf.options - op of "list": result = true else: localError(conf, info, errOnOffOrListExpectedButXFound % arg) proc processOnOffSwitchG(conf: ConfigRef; op: TGlobalOptions, arg: string, pass: TCmdLinePass, info: TLineInfo) = case arg.normalize - of "", "on": conf.globalOptions.incl op - of "off": conf.globalOptions.excl op + of "", "on": conf.globalOptions = conf.globalOptions + op + of "off": conf.globalOptions = conf.globalOptions - op else: localError(conf, info, errOnOrOffExpectedButXFound % arg) proc expectArg(conf: ConfigRef; switch, arg: string, pass: TCmdLinePass, info: TLineInfo) = @@ -182,9 +174,9 @@ proc expectNoArg(conf: ConfigRef; switch, arg: string, pass: TCmdLinePass, info: proc processSpecificNote*(arg: string, state: TSpecialWord, pass: TCmdLinePass, info: TLineInfo; orig: string; conf: ConfigRef) = - var id = "" # arg = key or [key] or key:val or [key]:val; with val=on|off + var id = "" # arg = key:val or [key]:val; with val=on|off var i = 0 - var notes: set[TMsgKind] + var n = hintMin var isBracket = false if i < arg.len and arg[i] == '[': isBracket = true @@ -196,41 +188,27 @@ proc processSpecificNote*(arg: string, state: TSpecialWord, pass: TCmdLinePass, if i < arg.len and arg[i] == ']': inc(i) else: invalidCmdLineOption(conf, pass, orig, info) - if i == arg.len: discard - elif i < arg.len and (arg[i] in {':', '='}): inc(i) + if i < arg.len and (arg[i] in {':', '='}): inc(i) else: invalidCmdLineOption(conf, pass, orig, info) - - let isSomeHint = state in {wHint, wHintAsError} - template findNote(noteMin, noteMax, name) = - # 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: 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} - elif isSomeHint: findNote(hintMin, hintMax, "hint") - else: findNote(warnMin, warnMax, "warning") - var val = substr(arg, i).normalize - if val == "": val = "on" - if val notin ["on", "off"]: - # xxx in future work we should also allow users to have control over `foreignPackageNotes` - # so that they can enable `hints|warnings|warningAsErrors` for all the code they depend on. - localError(conf, info, errOnOrOffExpectedButXFound % arg) + if state == wHint: + let x = findStr(lineinfos.HintsToStr, id) + if x >= 0: n = TNoteKind(x + ord(hintMin)) + else: localError(conf, info, "unknown hint: " & id) else: - let isOn = val == "on" - if isOn and id.normalize == "all": - localError(conf, info, "only 'all:off' is supported") - for n in notes: - if n notin conf.cmdlineNotes or pass == passCmd1: - if pass == passCmd1: incl(conf.cmdlineNotes, n) - incl(conf.modifiedyNotes, n) - if state in {wWarningAsError, wHintAsError}: - conf.warningAsErrors[n] = isOn # xxx rename warningAsErrors to noteAsErrors - else: - conf.notes[n] = isOn - conf.mainPackageNotes[n] = isOn - if not isOn: excl(conf.foreignPackageNotes, n) + let x = findStr(lineinfos.WarningsToStr, id) + if x >= 0: n = TNoteKind(x + ord(warnMin)) + else: localError(conf, info, "unknown warning: " & id) + case substr(arg, i).normalize + of "on": + incl(conf.notes, n) + incl(conf.mainPackageNotes, n) + incl(conf.enableNotes, n) + of "off": + excl(conf.notes, n) + excl(conf.mainPackageNotes, n) + incl(conf.disableNotes, n) + excl(conf.foreignPackageNotes, n) + else: localError(conf, info, errOnOrOffExpectedButXFound % arg) proc processCompile(conf: ConfigRef; filename: string) = var found = findFile(conf, filename) @@ -238,24 +216,20 @@ proc processCompile(conf: ConfigRef; filename: string) = extccomp.addExternalFileToCompile(conf, found) const - errNoneBoehmRefcExpectedButXFound = "'arc', 'orc', 'markAndSweep', 'boehm', 'go', 'none', 'regions', or 'refc' expected, but '$1' found" + errNoneBoehmRefcExpectedButXFound = "'none', 'boehm' or 'refc' expected, but '$1' found" errNoneSpeedOrSizeExpectedButXFound = "'none', 'speed' or 'size' expected, but '$1' found" errGuiConsoleOrLibExpectedButXFound = "'gui', 'console' or 'lib' expected, but '$1' found" - errInvalidExceptionSystem = "'goto', 'setjmp', 'cpp' or 'quirky' expected, but '$1' found" - -template warningOptionNoop(switch: string) = - warningDeprecated(conf, info, "'$#' is deprecated, now a noop" % switch) - -template deprecatedAlias(oldName, newName: string) = - warningDeprecated(conf, info, "'$#' is a deprecated alias for '$#'" % [oldName, newName]) + errInvalidExceptionSystem = "'goto', 'setjump', 'cpp' or 'quirky' expected, but '$1' found" proc testCompileOptionArg*(conf: ConfigRef; switch, arg: string, info: TLineInfo): bool = case switch.normalize - of "gc", "mm": + of "gc": case arg.normalize of "boehm": result = conf.selectedGC == gcBoehm of "refc": result = conf.selectedGC == gcRefc + of "v2": result = false of "markandsweep": result = conf.selectedGC == gcMarkAndSweep + of "generational": result = false of "destructors", "arc": result = conf.selectedGC == gcArc of "orc": result = conf.selectedGC == gcOrc of "hooks": result = conf.selectedGC == gcHooks @@ -301,7 +275,6 @@ proc testCompileOption*(conf: ConfigRef; switch: string, info: TLineInfo): bool of "hints": result = contains(conf.options, optHints) of "threadanalysis": result = contains(conf.globalOptions, optThreadAnalysis) of "stacktrace": result = contains(conf.options, optStackTrace) - of "stacktracemsgs": result = contains(conf.options, optStackTraceMsgs) of "linetrace": result = contains(conf.options, optLineTrace) of "debugger": result = contains(conf.globalOptions, optCDebug) of "profiler": result = contains(conf.options, optProfiler) @@ -311,31 +284,27 @@ proc testCompileOption*(conf: ConfigRef; switch: string, info: TLineInfo): bool result = conf.options * {optNaNCheck, optInfCheck} == {optNaNCheck, optInfCheck} of "infchecks": result = contains(conf.options, optInfCheck) of "nanchecks": result = contains(conf.options, optNaNCheck) + of "nilchecks": result = contains(conf.options, optNilCheck) of "objchecks": result = contains(conf.options, optObjCheck) of "fieldchecks": result = contains(conf.options, optFieldCheck) of "rangechecks": result = contains(conf.options, optRangeCheck) of "boundchecks": result = contains(conf.options, optBoundsCheck) - of "refchecks": - warningDeprecated(conf, info, "refchecks is deprecated!") - result = contains(conf.options, optRefCheck) + of "refchecks": result = contains(conf.options, optRefCheck) of "overflowchecks": result = contains(conf.options, optOverflowCheck) - of "staticboundchecks": result = contains(conf.options, optStaticBoundsCheck) of "stylechecks": result = contains(conf.options, optStyleCheck) of "linedir": result = contains(conf.options, optLineDir) of "assertions", "a": result = contains(conf.options, optAssert) of "run", "r": result = contains(conf.globalOptions, optRun) of "symbolfiles": result = conf.symbolFiles != disabledSf of "genscript": result = contains(conf.globalOptions, optGenScript) - of "gencdeps": result = contains(conf.globalOptions, optGenCDeps) of "threads": result = contains(conf.globalOptions, optThreads) + of "taintmode": result = contains(conf.globalOptions, optTaintMode) of "tlsemulation": result = contains(conf.globalOptions, optTlsEmulation) of "implicitstatic": result = contains(conf.options, optImplicitStatic) - of "patterns", "trmacros": - if switch.normalize == "patterns": deprecatedAlias(switch, "trmacros") - result = contains(conf.options, optTrMacros) + of "patterns", "trmacros": result = contains(conf.options, optTrMacros) of "excessivestacktrace": result = contains(conf.globalOptions, optExcessiveStackTrace) - of "nilseqs", "nilchecks", "taintmode": warningOptionNoop(switch) - of "panics": result = contains(conf.globalOptions, optPanics) + of "nilseqs": result = contains(conf.options, optNilSeqs) + of "oldast": result = contains(conf.options, optOldAst) else: invalidCmdLineOption(conf, passCmd1, switch, info) proc processPath(conf: ConfigRef; path: string, info: TLineInfo, @@ -369,242 +338,57 @@ proc processCfgPath(conf: ConfigRef; path: string, info: TLineInfo): AbsoluteDir const errInvalidNumber = "$1 is not a valid number" -proc makeAbsolute(s: string): AbsoluteFile = - if isAbsolute(s): - AbsoluteFile pathnorm.normalizePath(s) - else: - AbsoluteFile pathnorm.normalizePath(os.getCurrentDir() / s) - -proc setTrackingInfo(conf: ConfigRef; dirty, file, line, column: string, - info: TLineInfo) = - ## set tracking info, common code for track, trackDirty, & ideTrack - var ln, col: int - if parseUtils.parseInt(line, ln) <= 0: - localError(conf, info, errInvalidNumber % line) - if parseUtils.parseInt(column, col) <= 0: - localError(conf, info, errInvalidNumber % column) - - let a = makeAbsolute(file) - if dirty == "": - conf.m.trackPos = newLineInfo(conf, a, ln, col) - else: - let dirtyOriginalIdx = fileInfoIdx(conf, a) - if dirtyOriginalIdx.int32 >= 0: - msgs.setDirtyFile(conf, dirtyOriginalIdx, makeAbsolute(dirty)) - conf.m.trackPos = newLineInfo(dirtyOriginalIdx, ln, col) - proc trackDirty(conf: ConfigRef; arg: string, info: TLineInfo) = var a = arg.split(',') if a.len != 4: localError(conf, info, "DIRTY_BUFFER,ORIGINAL_FILE,LINE,COLUMN expected") - setTrackingInfo(conf, a[0], a[1], a[2], a[3], info) + var line, column: int + if parseUtils.parseInt(a[2], line) <= 0: + localError(conf, info, errInvalidNumber % a[1]) + if parseUtils.parseInt(a[3], column) <= 0: + localError(conf, info, errInvalidNumber % a[2]) + + let dirtyOriginalIdx = fileInfoIdx(conf, AbsoluteFile a[1]) + if dirtyOriginalIdx.int32 >= 0: + msgs.setDirtyFile(conf, dirtyOriginalIdx, AbsoluteFile a[0]) + + conf.m.trackPos = newLineInfo(dirtyOriginalIdx, line, column) proc track(conf: ConfigRef; arg: string, info: TLineInfo) = var a = arg.split(',') if a.len != 3: localError(conf, info, "FILE,LINE,COLUMN expected") - setTrackingInfo(conf, "", a[0], a[1], a[2], info) - -proc trackIde(conf: ConfigRef; cmd: IdeCmd, arg: string, info: TLineInfo) = - ## set the tracking info related to an ide cmd, supports optional dirty file - var a = arg.split(',') - case a.len - of 4: - setTrackingInfo(conf, a[0], a[1], a[2], a[3], info) - of 3: - setTrackingInfo(conf, "", a[0], a[1], a[2], info) - else: - localError(conf, info, "[DIRTY_BUFFER,]ORIGINAL_FILE,LINE,COLUMN expected") - conf.ideCmd = cmd + var line, column: int + if parseUtils.parseInt(a[1], line) <= 0: + localError(conf, info, errInvalidNumber % a[1]) + if parseUtils.parseInt(a[2], column) <= 0: + localError(conf, info, errInvalidNumber % a[2]) + conf.m.trackPos = newLineInfo(conf, AbsoluteFile a[0], line, column) proc dynlibOverride(conf: ConfigRef; switch, arg: string, pass: TCmdLinePass, info: TLineInfo) = if pass in {passCmd2, passPP}: expectArg(conf, switch, arg, pass, info) options.inclDynlibOverride(conf, arg) -template handleStdinOrCmdInput = - conf.projectFull = conf.projectName.AbsoluteFile - conf.projectPath = AbsoluteDir getCurrentDir() - if conf.outDir.isEmpty: - conf.outDir = getNimcacheDir(conf) - proc handleStdinInput*(conf: ConfigRef) = conf.projectName = "stdinfile" + conf.projectFull = conf.projectName.AbsoluteFile + conf.projectPath = AbsoluteDir getCurrentDir() conf.projectIsStdin = true - handleStdinOrCmdInput() - -proc handleCmdInput*(conf: ConfigRef) = - conf.projectName = "cmdfile" - handleStdinOrCmdInput() - -proc parseCommand*(command: string): Command = - case command.normalize - of "c", "cc", "compile", "compiletoc": cmdCompileToC - of "cpp", "compiletocpp": cmdCompileToCpp - of "objc", "compiletooc": cmdCompileToOC - of "js", "compiletojs": cmdCompileToJS - of "r": cmdCrun - of "run": cmdTcc - of "check": cmdCheck - of "e": cmdNimscript - of "doc0": cmdDoc0 - of "doc2", "doc": cmdDoc - of "doc2tex": cmdDoc2tex - of "rst2html": cmdRst2html - of "md2tex": cmdMd2tex - of "md2html": cmdMd2html - of "rst2tex": cmdRst2tex - of "jsondoc0": cmdJsondoc0 - of "jsondoc2", "jsondoc": cmdJsondoc - of "ctags": cmdCtags - of "buildindex": cmdBuildindex - of "gendepend": cmdGendepend - of "dump": cmdDump - of "parse": cmdParse - of "rod": cmdRod - of "secret": cmdInteractive - of "nop", "help": cmdNop - of "jsonscript": cmdJsonscript - else: cmdUnknown - -proc setCmd*(conf: ConfigRef, cmd: Command) = - ## sets cmd, backend so subsequent flags can query it (e.g. so --gc:arc can be ignored for backendJs) - # Note that `--backend` can override the backend, so the logic here must remain reversible. - conf.cmd = cmd - case cmd - of cmdCompileToC, cmdCrun, cmdTcc: conf.backend = backendC - of cmdCompileToCpp: conf.backend = backendCpp - of cmdCompileToOC: conf.backend = backendObjc - of cmdCompileToJS: conf.backend = backendJs - else: discard - -proc setCommandEarly*(conf: ConfigRef, command: string) = - conf.command = command - setCmd(conf, command.parseCommand) - # command early customizations - # must be handled here to honor subsequent `--hint:x:on|off` - case conf.cmd - of cmdRst2html, cmdRst2tex, cmdMd2html, cmdMd2tex: - # xxx see whether to add others: cmdGendepend, etc. - conf.foreignPackageNotes = {hintSuccessX} - else: - conf.foreignPackageNotes = foreignPackageNotesDefault - -proc specialDefine(conf: ConfigRef, key: string; pass: TCmdLinePass) = - # Keep this syncronized with the default config/nim.cfg! - if cmpIgnoreStyle(key, "nimQuirky") == 0: - conf.exc = excQuirky - elif cmpIgnoreStyle(key, "release") == 0 or cmpIgnoreStyle(key, "danger") == 0: - if pass in {passCmd1, passPP}: - conf.options.excl {optStackTrace, optLineTrace, optLineDir, optOptimizeSize} - conf.globalOptions.excl {optExcessiveStackTrace, optCDebug} - conf.options.incl optOptimizeSpeed - if cmpIgnoreStyle(key, "danger") == 0 or cmpIgnoreStyle(key, "quick") == 0: - if pass in {passCmd1, passPP}: - conf.options.excl {optObjCheck, optFieldCheck, optRangeCheck, optBoundsCheck, - optOverflowCheck, optAssert, optStackTrace, optLineTrace, optLineDir} - conf.globalOptions.excl {optCDebug} - -proc initOrcDefines*(conf: ConfigRef) = - conf.selectedGC = gcOrc - defineSymbol(conf.symbols, "gcorc") - defineSymbol(conf.symbols, "gcdestructors") - incl conf.globalOptions, optSeqDestructors - incl conf.globalOptions, optTinyRtti - defineSymbol(conf.symbols, "nimSeqsV2") - defineSymbol(conf.symbols, "nimV2") - if conf.exc == excNone and conf.backend != backendCpp: - conf.exc = excGoto - -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 - if pass in {passCmd2, passPP}: - defineSymbol(conf.symbols, "nimSeqsV2") - defineSymbol(conf.symbols, "nimV2") - if conf.exc == excNone and conf.backend != backendCpp: - conf.exc = excGoto - -proc unregisterArcOrc(conf: ConfigRef) = - undefSymbol(conf.symbols, "gcdestructors") - undefSymbol(conf.symbols, "gcarc") - undefSymbol(conf.symbols, "gcorc") - undefSymbol(conf.symbols, "nimSeqsV2") - undefSymbol(conf.symbols, "nimV2") - excl conf.globalOptions, optSeqDestructors - excl conf.globalOptions, optTinyRtti - -proc processMemoryManagementOption(switch, arg: string, pass: TCmdLinePass, - info: TLineInfo; conf: ConfigRef) = - if conf.backend == backendJs: return # for: bug #16033 - expectArg(conf, switch, arg, pass, info) - if pass in {passCmd2, passPP}: - case arg.normalize - of "boehm": - unregisterArcOrc(conf) - conf.selectedGC = gcBoehm - defineSymbol(conf.symbols, "boehmgc") - incl conf.globalOptions, optTlsEmulation # Boehm GC doesn't scan the real TLS - of "refc": - unregisterArcOrc(conf) - defineSymbol(conf.symbols, "gcrefc") - conf.selectedGC = gcRefc - of "markandsweep": - unregisterArcOrc(conf) - conf.selectedGC = gcMarkAndSweep - defineSymbol(conf.symbols, "gcmarkandsweep") - of "destructors", "arc": - registerArcOrc(pass, conf, false) - of "orc": - registerArcOrc(pass, conf, true) - of "hooks": - conf.selectedGC = gcHooks - defineSymbol(conf.symbols, "gchooks") - incl conf.globalOptions, optSeqDestructors - processOnOffSwitchG(conf, {optSeqDestructors}, arg, pass, info) - if pass in {passCmd2, passPP}: - defineSymbol(conf.symbols, "nimSeqsV2") - of "go": - unregisterArcOrc(conf) - conf.selectedGC = gcGo - defineSymbol(conf.symbols, "gogc") - of "none": - unregisterArcOrc(conf) - conf.selectedGC = gcNone - defineSymbol(conf.symbols, "nogc") - of "stack", "regions": - unregisterArcOrc(conf) - conf.selectedGC = gcRegions - defineSymbol(conf.symbols, "gcregions") - else: localError(conf, info, errNoneBoehmRefcExpectedButXFound % arg) + if conf.outDir.isEmpty: + conf.outDir = getNimcacheDir(conf) proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; conf: ConfigRef) = var key, val: string case switch.normalize - of "eval": - expectArg(conf, switch, arg, pass, info) - conf.projectIsCmd = true - conf.cmdInput = arg # can be empty (a nim file with empty content is valid too) - if conf.cmd == cmdNone: - conf.command = "e" - conf.setCmd cmdNimscript # better than `cmdCrun` as a default - conf.implicitCmd = true of "path", "p": expectArg(conf, switch, arg, pass, info) for path in nimbleSubs(conf, arg): addPath(conf, if pass == passPP: processCfgPath(conf, path, info) else: processPath(conf, path, info), info) of "nimblepath", "babelpath": - if switch.normalize == "babelpath": deprecatedAlias(switch, "nimblepath") + # keep the old name for compat if pass in {passCmd2, passPP} and optNoNimblePath notin conf.globalOptions: expectArg(conf, switch, arg, pass, info) var path = processPath(conf, arg, info, notRelativeToProj=true) @@ -613,7 +397,6 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; path = nimbleDir / RelativeDir"pkgs" nimblePath(conf, path, info) of "nonimblepath", "nobabelpath": - if switch.normalize == "nobabelpath": deprecatedAlias(switch, "nonimblepath") expectNoArg(conf, switch, arg, pass, info) disableNimblePath(conf) of "clearnimblepath": @@ -626,10 +409,6 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; conf.lazyPaths.keepItIf(it != path) of "nimcache": expectArg(conf, switch, arg, pass, info) - var arg = arg - # refs bug #18674, otherwise `--os:windows` messes up with `--nimcache` set - # in config nims files, e.g. via: `import os; switch("nimcache", "/tmp/somedir")` - if conf.target.targetOS == osWindows and DirSep == '/': arg = arg.replace('\\', '/') conf.nimcacheDir = processPath(conf, arg, info, notRelativeToProj=true) of "out", "o": expectArg(conf, switch, arg, pass, info) @@ -639,32 +418,30 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; of "outdir": expectArg(conf, switch, arg, pass, info) conf.outDir = processPath(conf, arg, info, notRelativeToProj=true) - of "usenimcache": - processOnOffSwitchG(conf, {optUseNimcache}, arg, pass, info) of "docseesrcurl": expectArg(conf, switch, arg, pass, info) conf.docSeeSrcUrl = arg of "docroot": - conf.docRoot = if arg.len == 0: docRootDefault else: arg - 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} - conf.backend = backend - of "doccmd": conf.docCmd = arg + conf.docRoot = if arg.len == 0: "@default" else: arg + of "mainmodule", "m": + discard "allow for backwards compatibility, but don't do anything" of "define", "d": expectArg(conf, switch, arg, pass, info) if {':', '='} in arg: splitSwitch(conf, arg, key, val, pass, info) - specialDefine(conf, key, pass) + if cmpIgnoreStyle(key, "nimQuirky") == 0: + conf.exc = excQuirky defineSymbol(conf.symbols, key, val) else: - specialDefine(conf, arg, pass) + if cmpIgnoreStyle(arg, "nimQuirky") == 0: + conf.exc = excQuirky defineSymbol(conf.symbols, arg) of "undef", "u": expectArg(conf, switch, arg, pass, info) undefSymbol(conf.symbols, arg) + of "symbol": + expectArg(conf, switch, arg, pass, info) + # deprecated, do nothing of "compile": expectArg(conf, switch, arg, pass, info) if pass in {passCmd2, passPP}: processCompile(conf, arg) @@ -685,25 +462,68 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; of "forcebuild", "f": processOnOffSwitchG(conf, {optForceFullMake}, arg, pass, info) of "project": - processOnOffSwitchG(conf, {optWholeProject, optGenIndex}, arg, pass, info) + processOnOffSwitchG(conf, {optWholeProject}, arg, pass, info) of "gc": - warningDeprecated(conf, info, "`gc:option` is deprecated; use `mm:option` instead") - processMemoryManagementOption(switch, arg, pass, info, conf) - of "mm": - processMemoryManagementOption(switch, arg, pass, info, conf) + expectArg(conf, switch, arg, pass, info) + if pass in {passCmd2, passPP}: + case arg.normalize + of "boehm": + conf.selectedGC = gcBoehm + defineSymbol(conf.symbols, "boehmgc") + of "refc": + conf.selectedGC = gcRefc + of "v2": + message(conf, info, warnDeprecated, "--gc:v2 is deprecated; using default gc") + of "markandsweep": + conf.selectedGC = gcMarkAndSweep + defineSymbol(conf.symbols, "gcmarkandsweep") + of "destructors", "arc": + conf.selectedGC = gcArc + if conf.cmd != cmdCompileToCpp: + conf.exc = excGoto + defineSymbol(conf.symbols, "gcdestructors") + defineSymbol(conf.symbols, "gcarc") + incl conf.globalOptions, optSeqDestructors + incl conf.globalOptions, optTinyRtti + if pass in {passCmd2, passPP}: + defineSymbol(conf.symbols, "nimSeqsV2") + defineSymbol(conf.symbols, "nimV2") + of "orc": + conf.selectedGC = gcOrc + if conf.cmd != cmdCompileToCpp: + conf.exc = excGoto + defineSymbol(conf.symbols, "gcdestructors") + defineSymbol(conf.symbols, "gcorc") + incl conf.globalOptions, optSeqDestructors + incl conf.globalOptions, optTinyRtti + if pass in {passCmd2, passPP}: + defineSymbol(conf.symbols, "nimSeqsV2") + defineSymbol(conf.symbols, "nimV2") + of "hooks": + conf.selectedGC = gcHooks + defineSymbol(conf.symbols, "gchooks") + incl conf.globalOptions, optSeqDestructors + processOnOffSwitchG(conf, {optSeqDestructors}, arg, pass, info) + if pass in {passCmd2, passPP}: + defineSymbol(conf.symbols, "nimSeqsV2") + of "go": + conf.selectedGC = gcGo + defineSymbol(conf.symbols, "gogc") + of "none": + conf.selectedGC = gcNone + defineSymbol(conf.symbols, "nogc") + of "stack", "regions": + conf.selectedGC = gcRegions + defineSymbol(conf.symbols, "gcregions") + else: localError(conf, info, errNoneBoehmRefcExpectedButXFound % arg) of "warnings", "w": if processOnOffSwitchOrList(conf, {optWarns}, arg, pass, info): listWarnings(conf) of "warning": processSpecificNote(arg, wWarning, pass, info, switch, conf) of "hint": processSpecificNote(arg, wHint, pass, info, switch, conf) - of "warningaserror": processSpecificNote(arg, wWarningAsError, pass, info, switch, conf) - of "hintaserror": processSpecificNote(arg, wHintAsError, pass, info, switch, conf) of "hints": if processOnOffSwitchOrList(conf, {optHints}, arg, pass, info): listHints(conf) - of "threadanalysis": - if conf.backend == backendJs: discard - else: processOnOffSwitchG(conf, {optThreadAnalysis}, arg, pass, info) + of "threadanalysis": processOnOffSwitchG(conf, {optThreadAnalysis}, arg, pass, info) of "stacktrace": processOnOffSwitch(conf, {optStackTrace}, arg, pass, info) - of "stacktracemsgs": processOnOffSwitch(conf, {optStackTraceMsgs}, arg, pass, info) of "excessivestacktrace": processOnOffSwitchG(conf, {optExcessiveStackTrace}, arg, pass, info) of "linetrace": processOnOffSwitch(conf, {optLineTrace}, arg, pass, info) of "debugger": @@ -740,32 +560,43 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; else: undefSymbol(conf.symbols, "hotcodereloading") undefSymbol(conf.symbols, "useNimRtl") + of "oldnewlines": + case arg.normalize + of "", "on": + conf.oldNewlines = true + defineSymbol(conf.symbols, "nimOldNewlines") + of "off": + conf.oldNewlines = false + undefSymbol(conf.symbols, "nimOldNewlines") + else: + localError(conf, info, errOnOrOffExpectedButXFound % arg) + of "laxstrings": processOnOffSwitch(conf, {optLaxStrings}, arg, pass, info) + of "nilseqs": processOnOffSwitch(conf, {optNilSeqs}, arg, pass, info) + of "oldast": processOnOffSwitch(conf, {optOldAst}, arg, pass, info) of "checks", "x": processOnOffSwitch(conf, ChecksOptions, arg, pass, info) of "floatchecks": processOnOffSwitch(conf, {optNaNCheck, optInfCheck}, arg, pass, info) of "infchecks": processOnOffSwitch(conf, {optInfCheck}, arg, pass, info) of "nanchecks": processOnOffSwitch(conf, {optNaNCheck}, arg, pass, info) + of "nilchecks": processOnOffSwitch(conf, {optNilCheck}, arg, pass, info) of "objchecks": processOnOffSwitch(conf, {optObjCheck}, arg, pass, info) of "fieldchecks": processOnOffSwitch(conf, {optFieldCheck}, arg, pass, info) of "rangechecks": processOnOffSwitch(conf, {optRangeCheck}, arg, pass, info) of "boundchecks": processOnOffSwitch(conf, {optBoundsCheck}, arg, pass, info) - of "refchecks": - warningDeprecated(conf, info, "refchecks is deprecated!") - processOnOffSwitch(conf, {optRefCheck}, arg, pass, info) + of "refchecks": processOnOffSwitch(conf, {optRefCheck}, arg, pass, info) of "overflowchecks": processOnOffSwitch(conf, {optOverflowCheck}, arg, pass, info) - of "staticboundchecks": processOnOffSwitch(conf, {optStaticBoundsCheck}, arg, pass, info) of "stylechecks": processOnOffSwitch(conf, {optStyleCheck}, arg, pass, info) of "linedir": processOnOffSwitch(conf, {optLineDir}, arg, pass, info) of "assertions", "a": processOnOffSwitch(conf, {optAssert}, arg, pass, info) + of "deadcodeelim": discard # deprecated, dead code elim always on of "threads": - if conf.backend == backendJs or conf.cmd == cmdNimscript: discard - else: processOnOffSwitchG(conf, {optThreads}, arg, pass, info) - #if optThreads in conf.globalOptions: conf.setNote(warnGcUnsafe) + processOnOffSwitchG(conf, {optThreads}, arg, pass, info) + #if optThreads in conf.globalOptions: incl(conf.notes, warnGcUnsafe) of "tlsemulation": processOnOffSwitchG(conf, {optTlsEmulation}, arg, pass, info) + of "taintmode": processOnOffSwitchG(conf, {optTaintMode}, arg, pass, info) of "implicitstatic": processOnOffSwitch(conf, {optImplicitStatic}, arg, pass, info) of "patterns", "trmacros": - if switch.normalize == "patterns": deprecatedAlias(switch, "trmacros") processOnOffSwitch(conf, {optTrMacros}, arg, pass, info) of "opt": expectArg(conf, switch, arg, pass, info) @@ -817,18 +648,12 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; of "clib": expectArg(conf, switch, arg, pass, info) if pass in {passCmd2, passPP}: - conf.cLinkedLibs.add arg + conf.cLinkedLibs.add processPath(conf, arg, info).string of "header": if conf != nil: conf.headerFile = arg incl(conf.globalOptions, optGenIndex) 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}: @@ -878,10 +703,9 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; if verbosity notin {0..3}: localError(conf, info, "invalid verbosity level: '$1'" % arg) conf.verbosity = verbosity - var verb = NotesVerbosity[conf.verbosity] - ## We override the default `verb` by explicitly modified (set/unset) notes. - conf.notes = (conf.modifiedyNotes * conf.notes + verb) - - (conf.modifiedyNotes * verb - conf.notes) + conf.notes = NotesVerbosity[conf.verbosity] + incl(conf.notes, conf.enableNotes) + excl(conf.notes, conf.disableNotes) conf.mainPackageNotes = conf.notes of "parallelbuild": expectArg(conf, switch, arg, pass, info) @@ -898,19 +722,19 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; of "help", "h": expectNoArg(conf, switch, arg, pass, info) helpOnError(conf, pass) - of "symbolfiles", "incremental", "ic": - if switch.normalize == "symbolfiles": deprecatedAlias(switch, "incremental") - # xxx maybe also ic, since not in help? - if pass in {passCmd2, passPP}: - case arg.normalize - of "on": conf.symbolFiles = v2Sf - of "off": conf.symbolFiles = disabledSf - of "writeonly": conf.symbolFiles = writeOnlySf - of "readonly": conf.symbolFiles = readOnlySf - of "v2": conf.symbolFiles = v2Sf - of "stress": conf.symbolFiles = stressTest - else: localError(conf, info, "invalid option for --incremental: " & arg) - setUseIc(conf.symbolFiles != disabledSf) + of "symbolfiles": discard "ignore for backwards compat" + of "incremental": + when not nimIncremental: + localError(conf, info, "the compiler was not built with " & + "incremental compilation features; bootstrap with " & + "-d:nimIncremental to enable") + case arg.normalize + of "on": conf.symbolFiles = v2Sf + of "off": conf.symbolFiles = disabledSf + of "writeonly": conf.symbolFiles = writeOnlySf + of "readonly": conf.symbolFiles = readOnlySf + of "v2": conf.symbolFiles = v2Sf + else: localError(conf, info, "invalid option for --incremental: " & arg) of "skipcfg": processOnOffSwitchG(conf, {optSkipSystemConfigFile}, arg, pass, info) of "skipprojcfg": @@ -920,11 +744,8 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; of "skipparentcfg": processOnOffSwitchG(conf, {optSkipParentConfigFiles}, arg, pass, info) of "genscript", "gendeps": - if switch.normalize == "gendeps": deprecatedAlias(switch, "genscript") processOnOffSwitchG(conf, {optGenScript}, arg, pass, info) processOnOffSwitchG(conf, {optCompileOnly}, arg, pass, info) - of "gencdeps": - processOnOffSwitchG(conf, {optGenCDeps}, arg, pass, info) of "colors": processOnOffSwitchG(conf, {optUseColors}, arg, pass, info) of "lib": expectArg(conf, switch, arg, pass, info) @@ -934,9 +755,8 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; splitSwitch(conf, arg, key, val, pass, info) os.putEnv(key, val) of "cc": - if conf.backend != backendJs: # bug #19330 - expectArg(conf, switch, arg, pass, info) - setCC(conf, arg, info) + expectArg(conf, switch, arg, pass, info) + setCC(conf, arg, info) of "track": expectArg(conf, switch, arg, pass, info) track(conf, arg, info) @@ -947,50 +767,28 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; expectNoArg(conf, switch, arg, pass, info) conf.ideCmd = ideSug of "def": + expectNoArg(conf, switch, arg, pass, info) + conf.ideCmd = ideDef + of "eval": expectArg(conf, switch, arg, pass, info) - trackIde(conf, ideDef, arg, info) + conf.evalExpr = arg of "context": expectNoArg(conf, switch, arg, pass, info) conf.ideCmd = ideCon of "usages": - expectArg(conf, switch, arg, pass, info) - trackIde(conf, ideUse, arg, info) - of "defusages": - expectArg(conf, switch, arg, pass, info) - trackIde(conf, ideDus, arg, info) + expectNoArg(conf, switch, arg, pass, info) + conf.ideCmd = ideUse of "stdout": processOnOffSwitchG(conf, {optStdout}, arg, pass, info) - of "filenames": - case arg.normalize - of "abs": conf.filenameOption = foAbs - of "canonical": conf.filenameOption = foCanonical - of "legacyrelproj": conf.filenameOption = foLegacyRelProj - else: localError(conf, info, "expected: abs|canonical|legacyRelProj, got: $1" % arg) - of "processing": - incl(conf.notes, hintProcessing) - incl(conf.mainPackageNotes, hintProcessing) - case arg.normalize - of "dots": conf.hintProcessingDots = true - of "filenames": conf.hintProcessingDots = false - of "off": - excl(conf.notes, hintProcessing) - excl(conf.mainPackageNotes, hintProcessing) - else: localError(conf, info, "expected: dots|filenames|off, got: $1" % arg) - of "unitsep": - conf.unitSep = if switchOn(arg): "\31" else: "" of "listfullpaths": - # xxx in future work, use `warningDeprecated` - conf.filenameOption = if switchOn(arg): foAbs else: foCanonical - of "spellsuggest": - if arg.len == 0: conf.spellSuggestMax = spellSuggestSecretSauce - elif arg == "auto": conf.spellSuggestMax = spellSuggestSecretSauce - else: conf.spellSuggestMax = parseInt(arg) - of "declaredlocs": - processOnOffSwitchG(conf, {optDeclaredLocs}, arg, pass, info) + processOnOffSwitchG(conf, {optListFullPaths}, arg, pass, info) of "dynliboverride": dynlibOverride(conf, switch, arg, pass, info) of "dynliboverrideall": processOnOffSwitchG(conf, {optDynlibOverrideAll}, arg, pass, info) + of "cs": + # only supported for compatibility. Does nothing. + expectArg(conf, switch, arg, pass, info) of "experimental": if arg.len == 0: conf.features.incl oldExperimentalFeatures @@ -1008,9 +806,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 @@ -1023,7 +818,6 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; if conf != nil: conf.cppDefine(arg) of "newruntime": - warningDeprecated(conf, info, "newruntime is deprecated, use arc/orc instead!") expectNoArg(conf, switch, arg, pass, info) if pass in {passCmd2, passPP}: doAssert(conf != nil) @@ -1045,7 +839,6 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; of "off": conf.globalOptions = conf.globalOptions - {optStyleHint, optStyleError} of "hint": conf.globalOptions = conf.globalOptions + {optStyleHint} - {optStyleError} of "error": conf.globalOptions = conf.globalOptions + {optStyleError} - of "usages": conf.globalOptions.incl optStyleUsages else: localError(conf, info, errOffHintsError % arg) of "showallmismatches": processOnOffSwitchG(conf, {optShowAllMismatches}, arg, pass, info) @@ -1062,63 +855,34 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; of "expandmacro": expectArg(conf, switch, arg, pass, info) conf.macrosToExpand[arg] = "T" - of "expandarc": - expectArg(conf, switch, arg, pass, info) - conf.arcToExpand[arg] = "T" + of "oldgensym": + processOnOffSwitchG(conf, {optNimV019}, arg, pass, info) 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 + # always be compatible with 1.0.2 for now: + defineSymbol(conf.symbols, "NimPatch", "2") 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") + localError(conf, info, "unknown Nim version; currently supported values are: {1.0}") of "benchmarkvm": processOnOffSwitchG(conf, {optBenchmarkVM}, arg, pass, info) - of "profilevm": - processOnOffSwitchG(conf, {optProfileVM}, arg, pass, info) - of "sinkinference": - processOnOffSwitch(conf, {optSinkInference}, arg, pass, info) - of "cursorinference": - # undocumented, for debugging purposes only: - processOnOffSwitch(conf, {optCursorInference}, arg, pass, info) - of "panics": - processOnOffSwitchG(conf, {optPanics}, arg, pass, info) - if optPanics in conf.globalOptions: - defineSymbol(conf.symbols, "nimPanics") - of "sourcemap": # xxx document in --fullhelp - conf.globalOptions.incl optSourcemap - conf.options.incl optLineDir - of "deepcopy": - processOnOffSwitchG(conf, {optEnableDeepCopy}, arg, pass, info) of "": # comes from "-" in for example: `nim c -r -` (gets stripped from -) handleStdinInput(conf) - of "nilseqs", "nilchecks", "symbol", "taintmode", "cs", "deadcodeelim": warningOptionNoop(switch) - of "nimmainprefix": conf.nimMainPrefix = arg else: if strutils.find(switch, '.') >= 0: options.setConfigVar(conf, switch, arg) else: invalidCmdLineOption(conf, pass, switch, info) +template gCmdLineInfo*(): untyped = newLineInfo(commandLineIdx, 1, 1) + proc processCommand*(switch: string, pass: TCmdLinePass; config: ConfigRef) = var cmd, arg: string splitSwitch(config, switch, cmd, arg, pass, gCmdLineInfo) processSwitch(cmd, arg, pass, gCmdLineInfo, config) + proc processSwitch*(pass: TCmdLinePass; p: OptParser; config: ConfigRef) = # hint[X]:off is parsed as (p.key = "hint[X]", p.val = "off") # we transform it to (key = hint, val = [X]:off) @@ -1132,22 +896,19 @@ proc processSwitch*(pass: TCmdLinePass; p: OptParser; config: ConfigRef) = proc processArgument*(pass: TCmdLinePass; p: OptParser; argsCount: var int; config: ConfigRef): bool = - if argsCount == 0 and config.implicitCmd: - argsCount.inc if argsCount == 0: # nim filename.nims is the same as "nim e filename.nims": if p.key.endsWith(".nims"): - config.setCmd cmdNimscript + config.command = "e" incl(config.globalOptions, optWasNimscript) config.projectName = unixToNativePath(p.key) config.arguments = cmdLineRest(p) result = true - elif pass != passCmd2: setCommandEarly(config, p.key) + elif pass != passCmd2: + config.command = p.key else: if pass == passCmd1: config.commandArgs.add p.key if argsCount == 1: - if p.key.endsWith(".nims"): - incl(config.globalOptions, optWasNimscript) # support UNIX style filenames everywhere for portable build scripts: if config.projectName.len == 0: config.projectName = unixToNativePath(p.key) diff --git a/compiler/concepts.nim b/compiler/concepts.nim deleted file mode 100644 index bcf2d4d0e..000000000 --- a/compiler/concepts.nim +++ /dev/null @@ -1,344 +0,0 @@ -# -# -# The Nim Compiler -# (c) Copyright 2020 Andreas Rumpf -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# - -## New styled concepts for Nim. See https://github.com/nim-lang/RFCs/issues/168 -## for details. Note this is a first implementation and only the "Concept matching" -## section has been implemented. - -import ast, astalgo, semdata, lookups, lineinfos, idents, msgs, renderer, types, intsets - -from magicsys import addSonSkipIntLit - -when defined(nimPreviewSlimSystem): - import std/assertions - -const - logBindings = false - -## Code dealing with Concept declarations -## -------------------------------------- - -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"), 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) - addDecl(c, s, info) - -proc isSelf*(t: PType): bool {.inline.} = - ## Is this the magical 'Self' type? - t.kind == tyTypeDesc and tfPacked in t.flags - -proc makeTypeDesc*(c: PContext, typ: PType): PType = - if typ.kind == tyTypeDesc and not isSelf(typ): - result = typ - else: - result = newTypeS(tyTypeDesc, c) - incl result.flags, tfCheckedForDestructor - result.addSonSkipIntLit(typ, c.idgen) - -proc semConceptDecl(c: PContext; n: PNode): PNode = - ## Recursive helper for semantic checking for the concept declaration. - ## Currently we only support (possibly empty) lists of statements - ## containing 'proc' declarations and the like. - case n.kind - of nkStmtList, nkStmtListExpr: - result = shallowCopy(n) - for i in 0.. 0 and f[0].kind != tyNone: - # also check the generic's constraints: - let oldLen = m.inferred.len - result = matchType(c, f[0], a, m) - m.inferred.setLen oldLen - if result: - when logBindings: echo "A adding ", f, " ", ak - m.inferred.add((f, ak)) - elif m.magic == mArrGet and ak.kind in {tyArray, tyOpenArray, tySequence, tyVarargs, tyCstring, tyString}: - when logBindings: echo "B adding ", f, " ", lastSon ak - m.inferred.add((f, lastSon ak)) - result = true - else: - when logBindings: echo "C adding ", f, " ", ak - m.inferred.add((f, ak)) - #echo "binding ", typeToString(ak), " to ", typeToString(f) - result = true - elif not m.marker.containsOrIncl(old.id): - result = matchType(c, old, ak, m) - if m.magic == mArrPut and ak.kind == tyGenericParam: - result = true - #echo "B for ", result, " to ", typeToString(a), " to ", typeToString(m.potentialImplementation) - - of tyVar, tySink, tyLent, tyOwned: - # modifiers in the concept must be there in the actual implementation - # too but not vice versa. - if a.kind == f.kind: - result = matchType(c, f.sons[0], a.sons[0], m) - elif m.magic == mArrPut: - result = matchType(c, f.sons[0], a, m) - else: - result = false - of tyEnum, tyObject, tyDistinct: - result = sameType(f, a) - of tyEmpty, tyString, tyCstring, tyPointer, tyNil, tyUntyped, tyTyped, tyVoid: - result = a.skipTypes(ignorableForArgType).kind == f.kind - of tyBool, tyChar, tyInt..tyUInt64: - let ak = a.skipTypes(ignorableForArgType) - result = ak.kind == f.kind or ak.kind == tyOrdinal or - (ak.kind == tyGenericParam and ak.len > 0 and ak[0].kind == tyOrdinal) - of tyConcept: - let oldLen = m.inferred.len - let oldPotentialImplementation = m.potentialImplementation - m.potentialImplementation = a - result = conceptMatchNode(c, f.n.lastSon, m) - m.potentialImplementation = oldPotentialImplementation - if not result: - m.inferred.setLen oldLen - of tyArray, tyTuple, tyVarargs, tyOpenArray, tyRange, tySequence, tyRef, tyPtr, - tyGenericInst: - let ak = a.skipTypes(ignorableForArgType - {f.kind}) - if ak.kind == f.kind and f.len == ak.len: - for i in 0..= a.len - if not result: - m.inferred.setLen oldLen - else: - for i in 0.. \"$2\";$n", [rope(importing), rope(imported)]) + b.dotGraph.addf("$1 -> \"$2\";$n", [rope(importing), rope(imported)]) # s1 -> s2_4[label="[0-9]"]; -proc toNimblePath(s: string, isStdlib: bool): string = - const stdPrefix = "std/" - const pkgPrefix = "pkg/" - if isStdlib: - let sub = "lib/" - var start = s.find(sub) - if start < 0: - doAssert false - else: - start += sub.len - let base = s[start..^1] - - if base.startsWith("system") or base.startsWith("std"): - result = base - else: - for dir in stdlibDirs: - if base.startsWith(dir): - return stdPrefix & base.splitFile.name - - result = stdPrefix & base - else: - var sub = getEnv("NIMBLE_DIR") - if sub.len == 0: - sub = ".nimble/pkgs/" - else: - sub.add "/pkgs/" - var start = s.find(sub) - if start < 0: - result = s - else: - start += sub.len - start += skipUntil(s, '/', start) - start += 1 - result = pkgPrefix & s[start..^1] - -proc addDependency(c: PPassContext, g: PGen, b: Backend, n: PNode) = - doAssert n.kind == nkSym, $n.kind - - let path = splitFile(toProjPath(g.config, n.sym.position.FileIndex)) - let modulePath = splitFile(toProjPath(g.config, g.module.position.FileIndex)) - let parent = nativeToUnixPath(modulePath.dir / modulePath.name).toNimblePath(belongsToStdlib(g.graph, g.module)) - let child = nativeToUnixPath(path.dir / path.name).toNimblePath(belongsToStdlib(g.graph, n.sym)) - addDependencyAux(b, parent, child) - -proc addDotDependency*(c: PPassContext, n: PNode): PNode = +proc addDotDependency(c: PPassContext, n: PNode): PNode = result = n let g = PGen(c) let b = Backend(g.graph.backend) case n.kind of nkImportStmt: for i in 0.. we need to 'join' every pushed 'fork' here + + +This works and then our abstract interpretation needs to deal with 'fork' +differently. It really causes a split in execution. Two threads are +"spawned" and both need to reach the 'join L' instruction. Afterwards +the abstract interpretations are joined and execution resumes single +threaded. + + +Abstract Interpretation +----------------------- + +proc interpret(pc, state, comesFrom): state = + result = state + # we need an explicit 'create' instruction (an explicit heap), in order + # to deal with 'var x = create(); var y = x; var z = y; destroy(z)' + while true: + case pc + of fork: + let a = interpret(pc+1, result, pc) + let b = interpret(forkTarget, result, pc) + result = a ++ b # ++ is a union operation + inc pc + of join: + if joinTarget == comesFrom: return result + else: inc pc + of use X: + if not result.contains(x): + error "variable not initialized " & x + inc pc + of def X: + if not result.contains(x): + result.incl X + else: + error "overwrite of variable causes memory leak " & x + inc pc + of destroy X: + result.excl X + +This is correct but still can lead to false positives: + +proc p(cond: bool) = + if cond: + new(x) + otherThings() + if cond: + destroy x + +Is not a leak. We should find a way to model *data* flow, not just +control flow. One solution is to rewrite the 'if' without a fork +instruction. The unstructured aspect can now be easily dealt with +the 'goto' and 'join' instructions. + +proc p(cond: bool) = + L0: fork Lend + new(x) + # do not 'join' here! + + Lend: + otherThings() + join L0 # SKIP THIS FOR new(x) SOMEHOW + destroy x + join L0 # but here. + + + +But if we follow 'goto Louter' we will never come to the join point. +We restore the bindings after popping pc from the stack then there +"no" problem?! + + +while cond: + prelude() + if not condB: break + postlude() + +---> +var setFlag = true +while cond and not setFlag: + prelude() + if not condB: + setFlag = true # BUT: Dependency + if not setFlag: # HERE + postlude() + +---> +var setFlag = true +while cond and not setFlag: + prelude() + if not condB: + postlude() + setFlag = true + + +------------------------------------------------- + +while cond: + prelude() + if more: + if not condB: break + stuffHere() + postlude() + +--> +var setFlag = true +while cond and not setFlag: + prelude() + if more: + if not condB: + setFlag = false + else: + stuffHere() + postlude() + else: + postlude() + +This is getting complicated. Instead we keep the whole 'join' idea but +duplicate the 'join' instructions on breaks and return exits! + +]# + +proc joinI(c: var Con; fromFork: TPosition; n: PNode) = + let dist = fromFork.int - c.code.len + c.code.add Instr(n: n, kind: join, dest: dist) + +proc genLabel(c: Con): TPosition = + result = TPosition(c.code.len) + +proc jmpBack(c: var Con, n: PNode, p = TPosition(0)) = + let dist = p.int - c.code.len + doAssert(low(int) div 2 + 1 < dist and dist < high(int) div 2) + c.code.add Instr(n: n, kind: goto, dest: dist) proc patch(c: var Con, p: TPosition) = # patch with current index - c.code[p.int].dest = checkedDistance(c.code.len - p.int) - -proc gen(c: var Con; n: PNode) + let p = p.int + let diff = c.code.len - p + doAssert(low(int) div 2 + 1 < diff and diff < high(int) div 2) + c.code[p].dest = diff proc popBlock(c: var Con; oldLen: int) = - var exits: seq[TPosition] - exits.add c.gotoI() - for f in c.blocks[oldLen].breakFixups: - c.patch(f[0]) - for finale in f[1]: - c.gen(finale) - exits.add c.gotoI() - for e in exits: - c.patch e + for f in c.blocks[oldLen].fixups: + c.patch(f) c.blocks.setLen(oldLen) -template withBlock(labl: PSym; body: untyped) = - let oldLen = c.blocks.len - c.blocks.add TBlock(isTryBlock: false, label: labl) +template withBlock(labl: PSym; body: untyped) {.dirty.} = + var oldLen {.gensym.} = c.blocks.len + c.blocks.add TBlock(label: labl, fixups: @[]) body popBlock(c, oldLen) @@ -132,28 +287,117 @@ proc isTrue(n: PNode): bool = n.kind == nkSym and n.sym.kind == skEnumField and n.sym.position != 0 or n.kind == nkIntLit and n.intVal != 0 -template forkT(body) = - let lab1 = c.forkI() +proc gen(c: var Con; n: PNode) # {.noSideEffect.} + +when true: + proc genWhile(c: var Con; n: PNode) = + # We unroll every loop 3 times. We emulate 0, 1, 2 iterations + # through the loop. We need to prove this is correct for our + # purposes. But Herb Sutter claims it is. (Proof by authority.) + #[ + while cond: + body + + Becomes: + + if cond: + body + if cond: + body + if cond: + body + + We still need to ensure 'break' resolves properly, so an AST to AST + translation is impossible. + + So the code to generate is: + + cond + fork L4 # F1 + body + cond + fork L5 # F2 + body + cond + fork L6 # F3 + body + L6: + join F3 + L5: + join F2 + L4: + join F1 + ]# + if isTrue(n[0]): + # 'while true' is an idiom in Nim and so we produce + # better code for it: + for i in 0..2: + withBlock(nil): + c.gen(n[1]) + else: + let oldForksLen = c.forks.len + var endings: array[3, TPosition] + for i in 0..2: + withBlock(nil): + c.gen(n[0]) + endings[i] = c.forkI(n) + c.gen(n[1]) + for i in countdown(endings.high, 0): + let endPos = endings[i] + c.patch(endPos) + c.joinI(c.forks.pop(), n) + doAssert(c.forks.len == oldForksLen) + +else: + + proc genWhile(c: var Con; n: PNode) = + # lab1: + # cond, tmp + # fork tmp, lab2 + # body + # jmp lab1 + # lab2: + let oldForksLen = c.forks.len + let lab1 = c.genLabel + withBlock(nil): + if isTrue(n[0]): + c.gen(n[1]) + c.jmpBack(n, lab1) + else: + c.gen(n[0]) + let lab2 = c.forkI(n) + c.gen(n[1]) + c.jmpBack(n, lab1) + c.patch(lab2) + setLen(c.forks, oldForksLen) + +proc genBlock(c: var Con; n: PNode) = + withBlock(n[0].sym): + c.gen(n[1]) + +proc genJoins(c: var Con; n: PNode) = + for i in countdown(c.forks.high, 0): joinI(c, c.forks[i], n) + +proc genBreak(c: var Con; n: PNode) = + genJoins(c, n) + let lab1 = c.gotoI(n) + if n[0].kind == nkSym: + #echo cast[int](n[0].sym) + for i in countdown(c.blocks.len-1, 0): + if c.blocks[i].label == n[0].sym: + c.blocks[i].fixups.add lab1 + return + #globalError(n.info, "VM problem: cannot find 'break' target") + else: + c.blocks[c.blocks.high].fixups.add lab1 + +template forkT(n, body) = + let oldLen = c.forks.len + let lab1 = c.forkI(n) body c.patch(lab1) - -proc genWhile(c: var Con; n: PNode) = - # lab1: - # cond, tmp - # fork tmp, lab2 - # body - # jmp lab1 - # lab2: - let lab1 = c.genLabel - withBlock(nil): - if isTrue(n[0]): - c.gen(n[1]) - c.jmpBack(lab1) - else: - c.gen(n[0]) - forkT: - c.gen(n[1]) - c.jmpBack(lab1) + c.joinI(lab1, n) + setLen(c.forks, oldLen) proc genIf(c: var Con, n: PNode) = #[ @@ -192,23 +436,21 @@ proc genIf(c: var Con, n: PNode) = join F1 ]# + let oldLen = c.forks.len var endings: seq[TPosition] = @[] - let oldInteresting = c.interestingInstructions - let oldLen = c.code.len - for i in 0.. 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 - - c.blocks[i].breakFixups.add (lab1, trailingFinales) - -proc genBreak(c: var Con; n: PNode) = - inc c.interestingInstructions - if n[0].kind == nkSym: - for i in countdown(c.blocks.high, 0): - if not c.blocks[i].isTryBlock and c.blocks[i].label == n[0].sym: - genBreakOrRaiseAux(c, i, n) - return - #globalError(n.info, "VM problem: cannot find 'break' target") - else: - for i in countdown(c.blocks.high, 0): - if not c.blocks[i].isTryBlock: - genBreakOrRaiseAux(c, i, n) - return + let elsePos = c.forkI(it.lastSon) + c.gen(it.lastSon) + endings.add(c.gotoI(it.lastSon)) + c.patch(elsePos) + for i in countdown(endings.high, 0): + let endPos = endings[i] + c.patch(endPos) + c.joinI(c.forks.pop(), n) + doAssert(c.forks.len == oldLen) proc genTry(c: var Con; n: PNode) = + let oldLen = c.forks.len var endings: seq[TPosition] = @[] - - let oldLen = c.blocks.len - c.blocks.add TBlock(isTryBlock: true, finale: if n[^1].kind == nkFinally: n[^1] else: newNode(nkEmpty)) - inc c.inTryStmt + let oldFixups = c.tryStmtFixups.len + + #let elsePos = c.forkI(n) c.gen(n[0]) dec c.inTryStmt - - for f in c.blocks[oldLen].raiseFixups: + for i in oldFixups..c.tryStmtFixups.high: + let f = c.tryStmtFixups[i] c.patch(f) + # we also need to produce join instructions + # for the 'fork' that might precede the goto instruction + if f.int-1 >= 0 and c.code[f.int-1].kind == fork: + c.joinI(TPosition(f.int-1), n) - c.blocks.setLen oldLen + setLen(c.tryStmtFixups, oldFixups) + #c.patch(elsePos) for i in 1.. 0: - for i in countdown(c.blocks.high, 0): - if c.blocks[i].isTryBlock: - genBreakOrRaiseAux(c, i, n) - return - assert false #Unreachable + c.tryStmtFixups.add c.gotoI(n) else: - genNoReturn(c) + genNoReturn(c, n) proc genImplicitReturn(c: var Con) = if c.owner.kind in {skProc, skFunc, skMethod, skIterator, skConverter} and resultPos < c.owner.ast.len: gen(c, c.owner.ast[resultPos]) proc genReturn(c: var Con; n: PNode) = - inc c.interestingInstructions + genJoins(c, n) if n[0].kind != nkEmpty: gen(c, n[0]) else: genImplicitReturn(c) - genBreakOrRaiseAux(c, 0, n) + genNoReturn(c, n) const InterestingSyms = {skVar, skResult, skLet, skParam, skForVar, skTemp} + PathKinds0 = {nkDotExpr, nkCheckedFieldExpr, + nkBracketExpr, nkDerefExpr, nkHiddenDeref, + nkAddr, nkHiddenAddr, + nkObjDownConv, nkObjUpConv} + PathKinds1 = {nkHiddenStdConv, nkHiddenSubConv} -proc skipTrivials(c: var Con, n: PNode): PNode = +proc skipConvDfa*(n: PNode): PNode = result = n while true: case result.kind - of PathKinds0 - {nkBracketExpr}: - result = result[0] - of nkBracketExpr: - gen(c, result[1]) + of nkObjDownConv, nkObjUpConv: result = result[0] of PathKinds1: result = result[1] else: break proc genUse(c: var Con; orig: PNode) = - let n = c.skipTrivials(orig) + var n = orig + while true: + case n.kind + of PathKinds0 - {nkBracketExpr}: + n = n[0] + of nkBracketExpr: + gen(c, n[1]) + n = n[0] + of PathKinds1: + n = n[1] + else: break + if n.kind == nkSym and n.sym.kind in InterestingSyms: + c.code.add Instr(n: orig, kind: use) - if n.kind == nkSym: - if n.sym.kind in InterestingSyms and n.sym == c.root: - c.code.add Instr(kind: use, n: orig) - inc c.interestingInstructions - else: - gen(c, n) +proc aliases*(obj, field: PNode): bool = + var n = field + var obj = obj + while obj.kind in {nkHiddenSubConv, nkHiddenStdConv, nkObjDownConv, nkObjUpConv}: + obj = obj[0] + while true: + if sameTrees(obj, n): return true + case n.kind + of PathKinds0, PathKinds1: + n = n[0] + else: + break -proc genDef(c: var Con; orig: PNode) = - let n = c.skipTrivials(orig) +proc useInstrTargets*(ins: Instr; loc: PNode): bool = + assert ins.kind == use + result = sameTrees(ins.n, loc) or + ins.n.aliases(loc) or loc.aliases(ins.n) + # We can come here if loc is 'x.f' and ins.n is 'x' or the other way round. + # use x.f; question: does it affect the full 'x'? No. + # use x; question does it affect 'x.f'? Yes. + +proc defInstrTargets*(ins: Instr; loc: PNode): bool = + assert ins.kind == def + result = sameTrees(ins.n, loc) or ins.n.aliases(loc) + # We can come here if loc is 'x.f' and ins.n is 'x' or the other way round. + # def x.f; question: does it affect the full 'x'? No. + # def x; question: does it affect the 'x.f'? Yes. + +proc isAnalysableFieldAccess*(orig: PNode; owner: PSym): bool = + var n = orig + while true: + case n.kind + of nkDotExpr, nkCheckedFieldExpr, nkHiddenSubConv, nkHiddenStdConv, + nkObjDownConv, nkObjUpConv, nkHiddenAddr, nkAddr: + n = n[0] + of nkBracketExpr: + # in a[i] the 'i' must be known + if n.len > 1 and n[1].kind in {nkCharLit..nkUInt64Lit}: + n = n[0] + else: + return false + of nkHiddenDeref, nkDerefExpr: + # We "own" sinkparam[].loc but not ourVar[].location as it is a nasty + # pointer indirection. + n = n[0] + return n.kind == nkSym and n.sym.owner == owner and (isSinkParam(n.sym) or + n.sym.typ.skipTypes(abstractInst-{tyOwned}).kind in {tyOwned}) + else: + break + # XXX Allow closure deref operations here if we know + # the owner controlled the closure allocation? + result = n.kind == nkSym and n.sym.owner == owner and + owner.kind != skModule and + (n.sym.kind != skParam or isSinkParam(n.sym)) # or n.sym.typ.kind == tyVar) + # Note: There is a different move analyzer possible that checks for + # consume(param.key); param.key = newValue for all paths. Then code like + # + # let splited = split(move self.root, x) + # self.root = merge(splited.lower, splited.greater) + # + # could be written without the ``move self.root``. However, this would be + # wrong! Then the write barrier for the ``self.root`` assignment would + # free the old data and all is lost! Lesson: Don't be too smart, trust the + # lower level C++ optimizer to specialize this code. + +proc genDef(c: var Con; n: PNode) = + var m = n + # XXX do something about this duplicated logic here. + while true: + case m.kind + of nkDotExpr, nkCheckedFieldExpr, nkHiddenSubConv, nkHiddenStdConv, + nkObjDownConv, nkObjUpConv, nkHiddenAddr, nkAddr: + m = m[0] + of nkBracketExpr: + gen(c, m[1]) + m = m[0] + of nkHiddenDeref, nkDerefExpr: + m = m[0] + else: + break if n.kind == nkSym and n.sym.kind in InterestingSyms: - if n.sym == c.root: - c.code.add Instr(kind: def, n: orig) - inc c.interestingInstructions + c.code.add Instr(n: n, kind: def) + elif isAnalysableFieldAccess(n, c.owner): + c.code.add Instr(n: n, kind: def) + else: + # bug #13314: An assignment to t5.w = -5 is a usage of 't5' + # we still need to gather the use information: + gen(c, n) proc genCall(c: var Con; n: PNode) = gen(c, n[0]) var t = n[0].typ if t != nil: t = t.skipTypes(abstractInst) + inc c.inCall for i in 1.. 0 and canRaiseConservative(n[0]): + if c.inTryStmt > 0 and canRaiseConservative(n[0]): # we generate the instruction sequence: # fork lab1 # goto exceptionHandler (except or finally) # lab1: # join F1 - forkT: - for i in countdown(c.blocks.high, 0): - if c.blocks[i].isTryBlock: - genBreakOrRaiseAux(c, i, n) - break + let endGoto = c.forkI(n) + c.tryStmtFixups.add c.gotoI(n) + c.patch(endGoto) + c.joinI(c.forks.pop(), n) + dec c.inCall proc genMagic(c: var Con; n: PNode; m: TMagic) = case m @@ -429,23 +742,17 @@ proc gen(c: var Con; n: PNode) = else: genCall(c, n) if sfNoReturn in n[0].sym.flags: - genNoReturn(c) + genNoReturn(c, n) else: genCall(c, n) of nkCharLit..nkNilLit: discard - of nkAsgn, nkFastAsgn, nkSinkAsgn: + of nkAsgn, nkFastAsgn: gen(c, n[1]) - - if n[0].kind in PathKinds0: - let a = c.skipTrivials(n[0]) - if a.kind in nkCallKinds: - gen(c, a) - # watch out: 'obj[i].f2 = value' sets 'f2' but # "uses" 'i'. But we are only talking about builtin array indexing so # it doesn't matter and 'x = 34' is NOT a usage of 'x'. genDef(c, n[0]) - of PathKinds0 - {nkObjDownConv, nkObjUpConv}: + of PathKinds0 - {nkHiddenStdConv, nkHiddenSubConv, nkObjDownConv, nkObjUpConv}: genUse(c, n) of nkIfStmt, nkIfExpr: genIf(c, n) of nkWhenStmt: @@ -462,40 +769,18 @@ proc gen(c: var Con; n: PNode) = nkBracket, nkCurly, nkPar, nkTupleConstr, nkClosure, nkObjConstr, nkYieldStmt: for x in n: gen(c, x) of nkPragmaBlock: gen(c, n.lastSon) - of nkDiscardStmt, nkObjDownConv, nkObjUpConv, nkStringToCString, nkCStringToString: - gen(c, n[0]) - of nkConv, nkExprColonExpr, nkExprEqExpr, nkCast, PathKinds1: + of nkDiscardStmt, nkObjDownConv, nkObjUpConv: gen(c, n[0]) + of nkConv, nkExprColonExpr, nkExprEqExpr, nkCast, nkHiddenSubConv, nkHiddenStdConv: gen(c, n[1]) + of nkStringToCString, nkCStringToString: gen(c, n[0]) of nkVarSection, nkLetSection: genVarSection(c, n) - of nkDefer: doAssert false, "dfa construction pass requires the elimination of 'defer'" + of nkDefer: + doAssert false, "dfa construction pass requires the elimination of 'defer'" else: discard -when false: - proc optimizeJumps(c: var ControlFlowGraph) = - for i in 0.. pc: - pc = newPc - else: - break - c[i].dest = pc - i - of loop, def, use: discard - -proc constructCfg*(s: PSym; body: PNode; root: PSym): ControlFlowGraph = +proc constructCfg*(s: PSym; body: PNode): ControlFlowGraph = ## constructs a control flow graph for ``body``. - var c = Con(code: @[], blocks: @[], owner: s, root: root) - withBlock(s): - gen(c, body) - if root.kind == skResult: - genImplicitReturn(c) - when defined(gcArc) or defined(gcOrc): - result = c.code # will move - else: - shallowCopy(result, c.code) - when false: - optimizeJumps result + var c = Con(code: @[], blocks: @[], owner: s) + gen(c, body) + genImplicitReturn(c) + shallowCopy(result, c.code) diff --git a/compiler/docgen.nim b/compiler/docgen.nim index 8105cc807..15ff2e167 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -7,170 +7,54 @@ # 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. It is currently pretty simple: No +# semantic checking is done for the code. 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], - json, xmltree, trees, types, + ast, strutils, strtabs, options, msgs, os, ropes, idents, + wordrecg, syntaxes, renderer, lexer, packages/docutils/rstast, + packages/docutils/rst, packages/docutils/rstgen, + json, xmltree, cgi, trees, types, typesrenderer, astalgo, lineinfos, intsets, - pathutils, tables, nimpaths, renderverbatim, osproc, packages -import packages/docutils/rstast except FileIndex, TLineInfo - -from uri import encodeUrl -from nodejs import findNodeJs - -when defined(nimPreviewSlimSystem): - import std/[assertions, syncio] - + pathutils, trees const exportSection = skField - docCmdSkip = "skip" - DocColOffset = "## ".len # assuming that a space was added after ## + htmldocsDir = RelativeDir"htmldocs" type - ItemFragment = object ## A fragment from each item will be eventually - ## constructed by converting `rst` fields to strings. - case isRst: bool - of true: - rst: PRstNode - of false: ## contains ready markup e.g. from runnableExamples - str: string - ItemPre = seq[ItemFragment] ## A pre-processed item. - Item = object ## Any item in documentation, e.g. symbol - ## entry. Configuration variable ``doc.item`` - ## is used for its HTML rendering. - descRst: ItemPre ## Description of the item (may contain - ## runnableExamples). - substitutions: seq[string] ## Variable names in `doc.item`... - sortName: string ## The string used for sorting in output - info: rstast.TLineInfo ## place where symbol was defined (for messages) - anchor: string ## e.g. HTML anchor - name: string ## short name of the symbol, not unique - ## (includes backticks ` if present) - detailedName: string ## longer name like `proc search(x: int): int` - ModSection = object ## Section like Procs, Types, etc. - secItems: Table[string, seq[Item]] - ## Map basic name -> pre-processed items. - finalMarkup: string ## The items, after RST pass 2 and rendering. - ModSections = array[TSymKind, ModSection] - TocItem = object ## HTML TOC item - content: string - sortName: string - TocSectionsFinal = array[TSymKind, string] - ExampleGroup = ref object - ## a group of runnableExamples with same rdoccmd - rdoccmd: string ## from 1st arg in `runnableExamples(rdoccmd): body` - docCmd: string ## from user config, e.g. --doccmd:-d:foo - code: string ## contains imports; each import contains `body` - index: int ## group index - JsonItem = object # pre-processed item: `rst` should be finalized - json: JsonNode - rst: PRstNode - rstField: string + TSections = array[TSymKind, Rope] TDocumentor = object of rstgen.RstGenerator - modDescPre: ItemPre # module description, not finalized - modDescFinal: string # module description, after RST pass 2 and rendering + modDesc: Rope # module description module: PSym - modDeprecationMsg: string - section: ModSections # entries of ``.nim`` file (for `proc`s, etc) - tocSimple: array[TSymKind, seq[TocItem]] - # TOC entries for non-overloadable symbols (e.g. types, constants)... - tocTable: array[TSymKind, Table[string, seq[TocItem]]] - # ...otherwise (e.g. procs) - toc2: TocSectionsFinal # TOC `content`, which is probably wrapped - # in `doc.section.toc2` - toc: TocSectionsFinal # final TOC (wrapped in `doc.section.toc`) + modDeprecationMsg: Rope + toc, section: TSections indexValFilename: string analytics: string # Google Analytics javascript, "" if doesn't exist seenSymbols: StringTableRef # avoids duplicate symbol generation for HTML. - jEntriesPre: seq[JsonItem] # pre-processed RST + JSON content - jEntriesFinal: JsonNode # final JSON after RST pass 2 and rendering + jArray: JsonNode types: TStrTable - sharedState: PRstSharedState - standaloneDoc: bool # is markup (.rst/.md) document? + isPureRst: bool conf*: ConfigRef cache*: IdentCache exampleCounter: int emitted: IntSet # we need to track which symbols have been emitted # already. See bug #3655 + destFile*: AbsoluteFile thisDir*: AbsoluteDir - exampleGroups: OrderedTable[string, ExampleGroup] - wroteSupportFiles*: bool - nimToRstFid: Table[lineinfos.FileIndex, rstast.FileIndex] - ## map Nim FileIndex -> RST one, it's needed because we keep them separate + examples: string + wroteCss*: bool PDoc* = ref TDocumentor ## Alias to type less. -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 nativeToUnix(path: string): string = + doAssert not path.isAbsolute # absolute files need more care for the drive + when DirSep == '\\': + result = replace(path, '\\', '/') + else: result = path -proc addRstFileIndex(d: PDoc, info: lineinfos.TLineInfo): rstast.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'. - ## Also handles leading zeros well (however note that leading zeros are - ## significant when lengths of numbers mismatch, e.g. 'bar08' > 'bar8' !). - runnableExamples: - doAssert cmpDecimalsIgnoreCase("uint8", "uint16") < 0 - doAssert cmpDecimalsIgnoreCase("val00032", "val16suffix") > 0 - doAssert cmpDecimalsIgnoreCase("val16suffix", "val16") > 0 - doAssert cmpDecimalsIgnoreCase("val_08_32", "val_08_8") > 0 - doAssert cmpDecimalsIgnoreCase("val_07_32", "val_08_8") < 0 - doAssert cmpDecimalsIgnoreCase("ab8", "ab08") < 0 - doAssert cmpDecimalsIgnoreCase("ab8de", "ab08c") < 0 # sanity check - let aLen = a.len - let bLen = b.len - var - iA = 0 - iB = 0 - while iA < aLen and iB < bLen: - if isDigit(a[iA]) and isDigit(b[iB]): - var - limitA = iA # index after the last (least significant) digit - limitB = iB - while limitA < aLen and isDigit(a[limitA]): inc limitA - while limitB < bLen and isDigit(b[limitB]): inc limitB - var pos = max(limitA-iA, limitB-iA) - while pos > 0: - if limitA-pos < iA: # digit in `a` is 0 effectively - result = ord('0') - ord(b[limitB-pos]) - elif limitB-pos < iB: # digit in `b` is 0 effectively - result = ord(a[limitA-pos]) - ord('0') - else: - result = ord(a[limitA-pos]) - ord(b[limitB-pos]) - if result != 0: return - dec pos - result = (limitA - iA) - (limitB - iB) # consider 'bar08' > 'bar8' - if result != 0: return - iA = limitA - iB = limitB - else: - result = ord(toLowerAscii(a[iA])) - ord(toLowerAscii(b[iB])) - if result != 0: return - inc iA - inc iB - result = (aLen - iA) - (bLen - iB) - -proc prettyString(a: object): string = - # xxx pending std/prettyprint refs https://github.com/nim-lang/RFCs/issues/203#issuecomment-602534906 - for k, v in fieldPairs(a): - result.add k & ": " & $v & "\n" - -proc presentationPath*(conf: ConfigRef, file: AbsoluteFile): RelativeFile = +proc presentationPath*(conf: ConfigRef, file: AbsoluteFile, isTitle = false): RelativeFile = ## returns a relative file that will be appended to outDir let file2 = $file template bail() = @@ -178,7 +62,7 @@ proc presentationPath*(conf: ConfigRef, file: AbsoluteFile): RelativeFile = proc nimbleDir(): AbsoluteDir = getNimbleFile(conf, file2).parentDir.AbsoluteDir case conf.docRoot: - of docRootDefault: + of "@default": # using `@` instead of `$` to avoid shell quoting complications result = getRelativePathFromConfigPath(conf, file) let dir = nimbleDir() if not dir.isEmpty: @@ -194,19 +78,16 @@ proc presentationPath*(conf: ConfigRef, file: AbsoluteFile): RelativeFile = result = getRelativePathFromConfigPath(conf, file) if result.isEmpty: bail() elif conf.docRoot.len > 0: - # we're (currently) requiring `isAbsolute` to avoid confusion when passing - # a relative path (would it be relative with regard to $PWD or to projectfile) - conf.globalAssert conf.docRoot.isAbsolute, arg=conf.docRoot - conf.globalAssert conf.docRoot.dirExists, arg=conf.docRoot - # needed because `canonicalizePath` called on `file` - result = file.relativeTo conf.docRoot.expandFilename.AbsoluteDir + doAssert conf.docRoot.isAbsolute, conf.docRoot # or globalError + doAssert conf.docRoot.existsDir, conf.docRoot + result = relativeTo(file, conf.docRoot.AbsoluteDir) else: bail() - if isAbsolute(result.string): - result = file.string.splitPath()[1].RelativeFile - result = result.string.replace("..", dotdotMangle).RelativeFile + if isTitle: + result = result.string.nativeToUnix.RelativeFile + else: + result = result.string.replace("..", "@@").RelativeFile ## refs #13223 doAssert not result.isEmpty - doAssert not isAbsolute(result.string) proc whichType(d: PDoc; n: PNode): PSym = if n.kind == nkSym: @@ -229,7 +110,7 @@ proc attachToType(d: PDoc; p: PSym): PSym = if params.len > 0: check(0) for i in 2.. @@ -345,27 +182,21 @@ proc newDocumentor*(filename: AbsoluteFile; cache: IdentCache; conf: ConfigRef, """ % [conf.configVars.getOrDefault"doc.googleAnalytics"] - elif conf.configVars.hasKey("doc.plausibleAnalytics"): - result.analytics = """ - - """ % [conf.configVars.getOrDefault"doc.plausibleAnalytics"] else: result.analytics = "" result.seenSymbols = newStringTable(modeCaseInsensitive) result.id = 100 - result.jEntriesFinal = newJArray() + result.jArray = newJArray() initStrTable result.types result.onTestSnippet = - proc (gen: var RstGenerator; filename, cmd: string; status: int; content: string) {.gcsafe.} = - if conf.docCmd == docCmdSkip: return - inc(gen.id) - var d = (ptr TDocumentor)(addr gen) + proc (gen: var RstGenerator; filename, cmd: string; status: int; content: string) = + var d = TDocumentor(gen) var outp: AbsoluteFile if filename.len == 0: + inc(d.id) let nameOnly = splitFile(d.filename).name - # "snippets" needed, refs bug #17183 - outp = getNimcacheDir(conf) / "snippets".RelativeDir / RelativeDir(nameOnly) / + outp = getNimcacheDir(conf) / RelativeDir(nameOnly) / RelativeFile(nameOnly & "_snippet_" & $d.id & ".nim") elif isAbsolute(filename): outp = AbsoluteFile(filename) @@ -376,34 +207,21 @@ proc newDocumentor*(filename: AbsoluteFile; cache: IdentCache; conf: ConfigRef, # Make sure the destination directory exists createDir(outp.splitFile.dir) # Include the current file if we're parsing a nim file - let importStmt = if d.standaloneDoc: "" else: "import \"$1\"\n" % [d.filename.replace("\\", "/")] + let importStmt = if d.isPureRst: "" else: "import \"$1\"\n" % [d.filename.replace("\\", "/")] writeFile(outp, importStmt & content) - - proc interpSnippetCmd(cmd: string): string = - # backward compatibility hacks; interpolation commands should explicitly use `$` - if cmd.startsWith "nim ": result = "$nim " & cmd[4..^1] - else: result = cmd - # factor with D20210224T221756 - result = result.replace("$1", "$options") % [ - "nim", os.getAppFilename().quoteShell, - "libpath", quoteShell(d.conf.libpath), - "docCmd", d.conf.docCmd, - "backend", $d.conf.backend, - "options", outp.quoteShell, - # xxx `quoteShell` seems buggy if user passes options = "-d:foo somefile.nim" - ] - let cmd = cmd.interpSnippetCmd - rawMessage(conf, hintExecuting, cmd) - let (output, gotten) = execCmdEx(cmd) - if gotten != status: - rawMessage(conf, errGenerated, "snippet failed: cmd: '$1' status: $2 expected: $3 output: $4" % [cmd, $gotten, $status, output]) + let c = if cmd.startsWith("nim "): os.getAppFilename() & cmd.substr(3) + else: cmd + let c2 = c % quoteShell(outp) + rawMessage(conf, hintExecuting, c2) + if execShellCmd(c2) != status: + rawMessage(conf, errGenerated, "executing of external program failed: " & c2) result.emitted = initIntSet() - result.destFile = destFile - result.thisDir = result.destFile.AbsoluteFile.splitFile.dir + result.destFile = getOutFile2(conf, presentationPath(conf, filename), + outExt, htmldocsDir, false) + result.thisDir = result.destFile.splitFile.dir -template dispA(conf: ConfigRef; dest: var string, xml, tex: string, - args: openArray[string]) = - if not conf.isLatexCmd: dest.addf(xml, args) +template dispA(conf: ConfigRef; dest: var Rope, xml, tex: string, args: openArray[Rope]) = + if conf.cmd != cmdRst2tex: dest.addf(xml, args) else: dest.addf(tex, args) proc getVarIdx(varnames: openArray[string], id: string): int = @@ -412,30 +230,89 @@ proc getVarIdx(varnames: openArray[string], id: string): int = return i result = -1 -proc genComment(d: PDoc, n: PNode): PRstNode = - if n.comment.len > 0: - d.sharedState.currFileIdx = addRstFileIndex(d, n.info) - result = parseRst(n.comment, - toLinenumber(n.info), - toColumn(n.info) + DocColOffset, - d.conf, d.sharedState) +proc ropeFormatNamedVars(conf: ConfigRef; frmt: FormatStr, + varnames: openArray[string], + varvalues: openArray[Rope]): Rope = + var i = 0 + result = nil + var num = 0 + while i < frmt.len: + if frmt[i] == '$': + inc(i) # skip '$' + case frmt[i] + of '#': + result.add(varvalues[num]) + inc(num) + inc(i) + of '$': + result.add("$") + inc(i) + of '0'..'9': + var j = 0 + while true: + j = (j * 10) + ord(frmt[i]) - ord('0') + inc(i) + if (i > frmt.len + 0 - 1) or not (frmt[i] in {'0'..'9'}): break + if j > high(varvalues) + 1: + rawMessage(conf, errGenerated, "Invalid format string; too many $s: " & frmt) + num = j + result.add(varvalues[j - 1]) + of 'A'..'Z', 'a'..'z', '\x80'..'\xFF': + var id = "" + while true: + id.add(frmt[i]) + inc(i) + if not (frmt[i] in {'A'..'Z', '_', 'a'..'z', '\x80'..'\xFF'}): break + var idx = getVarIdx(varnames, id) + if idx >= 0: result.add(varvalues[idx]) + else: rawMessage(conf, errGenerated, "unknown substition variable: " & id) + of '{': + var id = "" + inc(i) + while i < frmt.len and frmt[i] != '}': + id.add(frmt[i]) + inc(i) + if i >= frmt.len: + rawMessage(conf, errGenerated, "expected closing '}'") + else: + inc(i) # skip } + # search for the variable: + let idx = getVarIdx(varnames, id) + if idx >= 0: result.add(varvalues[idx]) + else: rawMessage(conf, errGenerated, "unknown substition variable: " & id) + else: + result.add("$") + var start = i + while i < frmt.len: + if frmt[i] != '$': inc(i) + else: break + if i - 1 >= start: result.add(substr(frmt, start, i - 1)) -proc genRecCommentAux(d: PDoc, n: PNode): PRstNode = +proc genComment(d: PDoc, n: PNode): string = + result = "" + var dummyHasToc: bool + if n.comment.len > 0: + renderRstToOut(d[], parseRst(n.comment, toFullPath(d.conf, n.info), + toLinenumber(n.info), toColumn(n.info), + dummyHasToc, d.options, d.conf), result) + +proc genRecCommentAux(d: PDoc, n: PNode): Rope = if n == nil: return nil - result = genComment(d, n) + result = genComment(d, n).rope if result == nil: if n.kind in {nkStmtList, nkStmtListExpr, nkTypeDef, nkConstDef, - nkObjectTy, nkRefTy, nkPtrTy, nkAsgn, nkFastAsgn, nkSinkAsgn, nkHiddenStdConv}: + nkObjectTy, nkRefTy, nkPtrTy, nkAsgn, nkFastAsgn, nkHiddenStdConv}: # notin {nkEmpty..nkNilLit, nkEnumTy, nkTupleTy}: for i in 0.. 0: return +proc belongsToPackage(conf: ConfigRef; module: PSym): bool = + result = module.kind == skModule and module.getnimblePkgId == conf.mainPackageId + proc externalDep(d: PDoc; module: PSym): string = if optWholeProject in d.conf.globalOptions or d.conf.docRoot.len > 0: let full = AbsoluteFile toFullPath(d.conf, FileIndex module.position) - let tmp = getOutFile2(d.conf, presentationPath(d.conf, full), HtmlExt, sfMainModule notin module.flags) + let tmp = getOutFile2(d.conf, presentationPath(d.conf, full), HtmlExt, + htmldocsDir, sfMainModule notin module.flags) result = relativeTo(tmp, d.thisDir, '/').string else: result = extractFilename toFullPath(d.conf, FileIndex module.position) -proc nodeToHighlightedHtml(d: PDoc; n: PNode; result: var string; - renderFlags: TRenderFlags = {}; - procLink: string) = +proc nodeToHighlightedHtml(d: PDoc; n: PNode; result: var Rope; renderFlags: TRenderFlags = {}; + procLink: Rope) = var r: TSrcGen var literal = "" initTokRender(r, n, renderFlags) var kind = tkEof var tokenPos = 0 var procTokenPos = 0 - template escLit(): untyped = esc(d.target, literal) while true: getNextTok(r, kind, literal) inc tokenPos @@ -483,61 +363,61 @@ proc nodeToHighlightedHtml(d: PDoc; n: PNode; result: var string; break of tkComment: dispA(d.conf, result, "$1", "\\spanComment{$1}", - [escLit]) + [rope(esc(d.target, literal))]) of tokKeywordLow..tokKeywordHigh: if kind in {tkProc, tkMethod, tkIterator, tkMacro, tkTemplate, tkFunc, tkConverter}: procTokenPos = tokenPos dispA(d.conf, result, "$1", "\\spanKeyword{$1}", - [literal]) + [rope(literal)]) of tkOpr: dispA(d.conf, result, "$1", "\\spanOperator{$1}", - [escLit]) - of tkStrLit..tkTripleStrLit, tkCustomLit: + [rope(esc(d.target, literal))]) + of tkStrLit..tkTripleStrLit: dispA(d.conf, result, "$1", - "\\spanStringLit{$1}", [escLit]) + "\\spanStringLit{$1}", [rope(esc(d.target, literal))]) of tkCharLit: dispA(d.conf, result, "$1", "\\spanCharLit{$1}", - [escLit]) + [rope(esc(d.target, literal))]) of tkIntLit..tkUInt64Lit: dispA(d.conf, result, "$1", - "\\spanDecNumber{$1}", [escLit]) + "\\spanDecNumber{$1}", [rope(esc(d.target, literal))]) of tkFloatLit..tkFloat128Lit: dispA(d.conf, result, "$1", - "\\spanFloatNumber{$1}", [escLit]) + "\\spanFloatNumber{$1}", [rope(esc(d.target, literal))]) of tkSymbol: let s = getTokSym(r) # -2 because of the whitespace in between: - if procTokenPos == tokenPos-2 and procLink != "": + if procTokenPos == tokenPos-2 and procLink != nil: dispA(d.conf, result, "$1", - "\\spanIdentifier{$1}", [escLit, procLink]) + "\\spanIdentifier{$1}", [rope(esc(d.target, literal)), procLink]) elif s != nil and s.kind in {skType, skVar, skLet, skConst} and sfExported in s.flags and s.owner != nil and - belongsToProjectPackage(d.conf, s.owner) and d.target == outHtml: + belongsToPackage(d.conf, s.owner) and d.target == outHtml: let external = externalDep(d, s.owner) result.addf "$3", - [changeFileExt(external, "html"), literal, - escLit] + [rope changeFileExt(external, "html"), rope literal, + rope(esc(d.target, literal))] else: dispA(d.conf, result, "$1", - "\\spanIdentifier{$1}", [escLit]) + "\\spanIdentifier{$1}", [rope(esc(d.target, literal))]) of tkSpaces, tkInvalid: result.add(literal) - of tkHideableStart: - template fun(s) = dispA(d.conf, result, s, "\\spanOther{$1}", [escLit]) - if renderRunnableExamples in renderFlags: fun "$1" - else: - # 1st span is required for the JS to work properly - fun """ - -... + of tkCurlyDotLe: + dispA(d.conf, result, "" & # This span is required for the JS to work properly + """{...} -""".replace("\n", "") # Must remove newlines because wrapped in a
-    of tkHideableEnd:
-      template fun(s) = dispA(d.conf, result, s, "\\spanOther{$1}", [escLit])
-      if renderRunnableExamples in renderFlags: fun "$1"
-      else: fun ""
-    of tkCurlyDotLe: dispA(d.conf, result, "$1", "\\spanOther{$1}", [escLit])
-    of tkCurlyDotRi: dispA(d.conf, result, "$1", "\\spanOther{$1}", [escLit])
+
+$1
+""".replace("\n", ""),  # Must remove newlines because wrapped in a 
+                    "\\spanOther{$1}",
+                  [rope(esc(d.target, literal))])
+    of tkCurlyDotRi:
+      dispA(d.conf, result, """
+
+$1
+""".replace("\n", ""),
+                    "\\spanOther{$1}",
+                  [rope(esc(d.target, literal))])
     of tkParLe, tkParRi, tkBracketLe, tkBracketRi, tkCurlyLe, tkCurlyRi,
        tkBracketDotLe, tkBracketDotRi, tkParDotLe,
        tkParDotRi, tkComma, tkSemiColon, tkColon, tkEquals, tkDot, tkDotDot,
@@ -545,116 +425,51 @@ proc nodeToHighlightedHtml(d: PDoc; n: PNode; result: var string;
        tkGStrLit, tkGTripleStrLit, tkInfixOpr, tkPrefixOpr, tkPostfixOpr,
        tkBracketLeColon:
       dispA(d.conf, result, "$1", "\\spanOther{$1}",
-            [escLit])
+            [rope(esc(d.target, literal))])
 
-proc exampleOutputDir(d: PDoc): AbsoluteDir = d.conf.getNimcacheDir / RelativeDir"runnableExamples"
-
-proc runAllExamples(d: PDoc) =
-  # This used to be: `let backend = if isDefined(d.conf, "js"): "js"` (etc), however
-  # using `-d:js` (etc) cannot work properly, e.g. would fail with `importjs`
-  # since semantics are affected by `config.backend`, not by isDefined(d.conf, "js")
-  let outputDir = d.exampleOutputDir
-  for _, group in d.exampleGroups:
-    if group.docCmd == docCmdSkip: continue
-    let outp = outputDir / RelativeFile("$1_group$2_examples.nim" % [d.filename.splitFile.name, $group.index])
-    group.code = "# autogenerated by docgen\n# source: $1\n# rdoccmd: $2\n$3" % [d.filename, group.rdoccmd, group.code]
-    writeFile(outp, group.code)
-    # most useful semantics is that `docCmd` comes after `rdoccmd`, so that we can (temporarily) override
-    # via command line
-    # D20210224T221756:here
-    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,
-      "path", quoteShell(d.conf.projectPath),
-      "libpath", quoteShell(d.conf.libpath),
-      "nimcache", quoteShell(outputDir),
-      "file", quoteShell(outp),
-      "rdoccmd", group.rdoccmd,
-      "docCmd", group.docCmd,
-    ]
-    if d.conf.backend == backendJs and findNodeJs() == "":
-      discard "ignore JS runnableExample"
-    elif os.execShellCmd(cmd) != 0:
-      d.conf.quitOrRaise "[runnableExamples] failed: generated file: '$1' group: '$2' cmd: $3" % [outp.string, group[].prettyString, cmd]
-    else:
-      # keep generated source file `outp` to allow inspection.
-      rawMessage(d.conf, hintSuccess, ["runnableExamples: " & outp.string])
-      # removeFile(outp.changeFileExt(ExeExt)) # it's in nimcache, no need to remove
-
-proc quoted(a: string): string = result.addQuoted(a)
-
-proc toInstantiationInfo(conf: ConfigRef, info: TLineInfo): (string, int, int) =
-  # xxx expose in compiler/lineinfos.nim
-  (conf.toMsgFilename(info), info.line.int, info.col.int + ColOffset)
-
-proc prepareExample(d: PDoc; n: PNode, topLevel: bool): tuple[rdoccmd: string, code: string] =
-  ## returns `rdoccmd` and source code for this runnableExamples
-  var rdoccmd = ""
-  if n.len < 2 or n.len > 3: globalError(d.conf, n.info, "runnableExamples invalid")
-  if n.len == 3:
-    let n1 = n[1]
-    # xxx this should be evaluated during sempass
-    if n1.kind notin nkStrKinds: globalError(d.conf, n1.info, "string litteral expected")
-    rdoccmd = n1.strVal
-
-  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)
-
-  let comment = "autogenerated by docgen\nloc: $1\nrdoccmd: $2" % [loc, rdoccmd]
-  let outputDir = d.exampleOutputDir
+proc testExample(d: PDoc; ex: PNode) =
+  if d.conf.errorCounter > 0: return
+  let outputDir = d.conf.getNimcacheDir / RelativeDir"runnableExamples"
   createDir(outputDir)
   inc d.exampleCounter
-  let outp = outputDir / RelativeFile("$#_examples_$#.nim" % [d.filename.extractFilename.changeFileExt"", $d.exampleCounter])
-
-  if useRenderModule:
-    var docComment = newTree(nkCommentStmt)
-    docComment.comment = comment
-    var runnableExamples = newTree(nkStmtList,
-        docComment,
-        newTree(nkImportStmt, newStrNode(nkStrLit, d.filename)))
-    runnableExamples.info = n.info
-    for a in n.lastSon: runnableExamples.add a
-
-    # buggy, refs bug #17292
-    # still worth fixing as it can affect other code relying on `renderModule`,
-    # so we keep this code path here for now, which could still be useful in some
-    # other situations.
-    renderModule(runnableExamples, outp.string, conf = d.conf)
+  let outp = outputDir / RelativeFile(extractFilename(d.filename.changeFileExt"" &
+      "_examples" & $d.exampleCounter & ".nim"))
+  #let nimcache = outp.changeFileExt"" & "_nimcache"
+  renderModule(ex, d.filename, outp.string, conf = d.conf)
+  d.examples.add "import r\"" & outp.string & "\"\n"
 
+proc runAllExamples(d: PDoc) =
+  if d.examples.len == 0: return
+  let outputDir = d.conf.getNimcacheDir / RelativeDir"runnableExamples"
+  let outp = outputDir / RelativeFile(extractFilename(d.filename.changeFileExt"" &
+      "_examples.nim"))
+  writeFile(outp, d.examples)
+  let backend = if isDefined(d.conf, "js"): "js"
+                elif isDefined(d.conf, "cpp"): "cpp"
+                elif isDefined(d.conf, "objc"): "objc"
+                else: "c"
+  if os.execShellCmd(os.getAppFilename() & " " & backend &
+                    " --warning[UnusedImport]:off" &
+                    " --path:" & quoteShell(d.conf.projectPath) &
+                    " --nimcache:" & quoteShell(outputDir) &
+                    " -r " & quoteShell(outp)) != 0:
+    quit "[Examples] failed: see " & outp.string
   else:
-    var code2 = code
-    if code.len > 0 and "codeReordering" notin code:
-      # hacky but simplest solution, until we devise a way to make `{.line.}`
-      # work without introducing a scope
-      code2 = """
-{.line: $#.}:
-$#
-""" % [$toInstantiationInfo(d.conf, n.info), codeIndent]
-    code2 = """
-#[
-$#
-]#
-import $#
-$#
-""" % [comment, d.filename.quoted, code2]
-    writeFile(outp.string, code2)
+    # keep generated source file `outp` to allow inspection.
+    rawMessage(d.conf, hintSuccess, ["runnableExamples: " & outp.string])
+    removeFile(outp.changeFileExt(ExeExt))
 
-  if rdoccmd notin d.exampleGroups:
-    d.exampleGroups[rdoccmd] = ExampleGroup(rdoccmd: rdoccmd, docCmd: d.conf.docCmd, index: d.exampleGroups.len)
-  d.exampleGroups[rdoccmd].code.add "import $1\n" % outp.string.quoted
 
-  var codeShown: string
-  if topLevel: # refs https://github.com/nim-lang/RFCs/issues/352
-    let title = canonicalImport(d.conf, AbsoluteFile d.filename)
-    codeShown = "import $#\n$#" % [title, code]
-  else:
-    codeShown = code
-  result = (rdoccmd, codeShown)
+proc prepareExamples(d: PDoc; n: PNode) =
+  var docComment = newTree(nkCommentStmt)
+  let loc = d.conf.toFileLineCol(n.info)
+  docComment.comment = "autogenerated by docgen from " & loc
+  var runnableExamples = newTree(nkStmtList,
+      docComment,
+      newTree(nkImportStmt, newStrNode(nkStrLit, d.filename)))
+  runnableExamples.info = n.info
+  for a in n.lastSon: runnableExamples.add a
+  testExample(d, runnableExamples)
   when false:
     proc extractImports(n: PNode; result: PNode) =
       if n.kind in {nkImportStmt, nkImportExceptStmt, nkFromStmt}:
@@ -668,108 +483,36 @@ $#
     for imp in imports: runnableExamples.add imp
     runnableExamples.add newTree(nkBlockStmt, newNode(nkEmpty), copyTree savedLastSon)
 
-type RunnableState = enum
-  rsStart
-  rsComment
-  rsRunnable
-  rsDone
-
-proc getAllRunnableExamplesImpl(d: PDoc; n: PNode, dest: var ItemPre,
-                                state: RunnableState, topLevel: bool):
-                               RunnableState =
-  ##[
-  Simple state machine to tell whether we render runnableExamples and doc comments.
-  This is to ensure that we can interleave runnableExamples and doc comments freely;
-  the logic is easy to change but currently a doc comment following another doc comment
-  will not render, to avoid rendering in following case:
-
-  proc fn* =
-    runnableExamples: discard
-    ## d1
-    runnableExamples: discard
-    ## d2
-
-    ## internal explanation  # <- this one should be out; it's part of rest of function body and would likey not make sense in doc comment
-    discard # some code
-  ]##
-
+proc getAllRunnableExamplesRec(d: PDoc; n, orig: PNode; dest: var Rope) =
+  if n.info.fileIndex != orig.info.fileIndex: return
   case n.kind
-  of nkCommentStmt:
-    if state in {rsStart, rsRunnable}:
-      dest.add genRecComment(d, n)
-      return rsComment
   of nkCallKinds:
     if isRunnableExamples(n[0]) and
         n.len >= 2 and n.lastSon.kind == nkStmtList:
-      if state in {rsStart, rsComment, rsRunnable}:
-        let (rdoccmd, code) = prepareExample(d, n, topLevel)
-        var msg = "Example:"
-        if rdoccmd.len > 0: msg.add " cmd: " & rdoccmd
-        var s: string
-        dispA(d.conf, s, "\n

$1

\n", - "\n\n\\textbf{$1}\n", [msg]) - dest.add s - inc d.listingCounter - let id = $d.listingCounter - dest.add(d.config.getOrDefault"doc.listing_start" % [id, "langNim", ""]) - var dest2 = "" - renderNimCode(dest2, code, d.target) - dest.add dest2 - dest.add(d.config.getOrDefault"doc.listing_end" % id) - return rsRunnable - else: - localError(d.conf, n.info, errUser, "runnableExamples must appear before the first non-comment statement") + prepareExamples(d, n) + dispA(d.conf, dest, "\n

$1

\n", + "\n\\textbf{$1}\n", [rope"Examples:"]) + inc d.listingCounter + let id = $d.listingCounter + dest.add(d.config.getOrDefault"doc.listing_start" % [id, "langNim"]) + # this is a rather hacky way to get rid of the initial indentation + # that the renderer currently produces: + var i = 0 + var body = n.lastSon + if body.len == 1 and body.kind == nkStmtList and + body.lastSon.kind == nkStmtList: + body = body.lastSon + for b in body: + if i > 0: dest.add "\n" + inc i + nodeToHighlightedHtml(d, b, dest, {}, nil) + dest.add(d.config.getOrDefault"doc.listing_end" % id) else: discard - return rsDone - # change this to `rsStart` if you want to keep generating doc comments - # and runnableExamples that occur after some code in routine + for i in 0.. - result = - ## foo - 3; - - proc someType*(): int = - ## foo - 3 -=> - ## foo - result = 3; - - so we normalize the results to get to the statement list containing the - (0 or more) doc comments and runnableExamples. - ]## - result = n[bodyPos] - - # This won't be transformed: result.id = 10. Namely result[0].kind != nkSym. - if result.kind == nkAsgn and result[0].kind == nkSym and - n.len > bodyPos+1 and n[bodyPos+1].kind == nkSym: - doAssert result.len == 2 - result = result[1] - -proc getAllRunnableExamples(d: PDoc, n: PNode, dest: var ItemPre) = - var n = n - var state = rsStart - template fn(n2, topLevel) = - state = getAllRunnableExamplesImpl(d, n2, dest, state, topLevel) - dest.add genComment(d, n) - case n.kind - of routineDefs: - n = n.getRoutineBody - case n.kind - of nkCommentStmt, nkCallKinds: fn(n, topLevel = false) - else: - for i in 0.. paramsPos and n[paramsPos].kind == nkFormalParams: + if n.len > paramsPos and n[paramsPos].kind == nkFormalParams: let params = renderParamTypes(n[paramsPos]) if params.len > 0: result.add(defaultParamSeparator) result.add(params) +proc isCallable(n: PNode): bool = + ## Returns true if `n` contains a callable node. + case n.kind + of nkProcDef, nkMethodDef, nkIteratorDef, nkMacroDef, nkTemplateDef, + nkConverterDef, nkFuncDef: result = true + else: + result = false + proc docstringSummary(rstText: string): string = ## Returns just the first line or a brief chunk of text from a rst string. ## @@ -898,7 +646,7 @@ proc docstringSummary(rstText: string): string = result = rstText.substr(2).strip var pos = result.find('\L') if pos > 0: - result.setLen(pos - 1) + result.delete(pos, result.len - 1) result.add("…") if pos < maxDocstringChars: return @@ -906,21 +654,23 @@ proc docstringSummary(rstText: string): string = pos = result.find({'.', ',', ':'}) let last = result.len - 1 if pos > 0 and pos < last: - result.setLen(pos - 1) + result.delete(pos, last) result.add("…") -proc genDeprecationMsg(d: PDoc, n: PNode): string = +proc genDeprecationMsg(d: PDoc, n: PNode): Rope = ## Given a nkPragma wDeprecated node output a well-formatted section if n == nil: return case n.safeLen: of 0: # Deprecated w/o any message - result = getConfigVar(d.conf, "doc.deprecationmsg") % [ - "label" , "Deprecated", "message", ""] + result = ropeFormatNamedVars(d.conf, + getConfigVar(d.conf, "doc.deprecationmsg"), ["label", "message"], + [~"Deprecated", nil]) of 2: # Deprecated w/ a message if n[1].kind in {nkStrLit..nkTripleStrLit}: - result = getConfigVar(d.conf, "doc.deprecationmsg") % [ - "label", "Deprecated:", "message", xmltree.escape(n[1].strVal)] + result = ropeFormatNamedVars(d.conf, + getConfigVar(d.conf, "doc.deprecationmsg"), ["label", "message"], + [~"Deprecated:", rope(xmltree.escape(n[1].strVal))]) else: doAssert false @@ -928,13 +678,54 @@ type DocFlags = enum kDefault kForceExport -proc genSeeSrc(d: PDoc, path: string, line: int): string = +proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind, docFlags: DocFlags) = + if (docFlags != kForceExport) and not isVisible(d, nameNode): return + let + name = getName(d, nameNode) + nameRope = name.rope + var plainDocstring = getPlainDocstring(n) # call here before genRecComment! + var result: Rope = nil + var literal, plainName = "" + var kind = tkEof + var comm = genRecComment(d, n) # call this here for the side-effect! + getAllRunnableExamples(d, n, comm) + var r: TSrcGen + # Obtain the plain rendered string for hyperlink titles. + initTokRender(r, n, {renderNoBody, renderNoComments, renderDocComments, + renderNoPragmas, renderNoProcDefs}) + while true: + getNextTok(r, kind, literal) + if kind == tkEof: + break + plainName.add(literal) + + var pragmaNode: PNode = nil + if n.isCallable and n[pragmasPos].kind != nkEmpty: + pragmaNode = findPragma(n[pragmasPos], wDeprecated) + + inc(d.id) + let + plainNameRope = rope(xmltree.escape(plainName.strip)) + cleanPlainSymbol = renderPlainSymbolName(nameNode) + complexSymbol = complexName(k, n, cleanPlainSymbol) + plainSymbolRope = rope(cleanPlainSymbol) + plainSymbolEncRope = rope(encodeUrl(cleanPlainSymbol)) + itemIDRope = rope(d.id) + symbolOrId = d.newUniquePlainSymbol(complexSymbol) + symbolOrIdRope = symbolOrId.rope + symbolOrIdEncRope = encodeUrl(symbolOrId).rope + deprecationMsgRope = genDeprecationMsg(d, pragmaNode) + + nodeToHighlightedHtml(d, n, result, {renderNoBody, renderNoComments, + renderDocComments, renderSyms}, symbolOrIdEncRope) + + var seeSrcRope: Rope = nil let docItemSeeSrc = getConfigVar(d.conf, "doc.item.seesrc") if docItemSeeSrc.len > 0: - let path = relativeTo(AbsoluteFile path, AbsoluteDir getCurrentDir(), '/') + let path = relativeTo(AbsoluteFile toFullPath(d.conf, n.info), AbsoluteDir getCurrentDir(), '/') when false: let cwd = canonicalizePath(d.conf, getCurrentDir()) - var path = path + var path = toFullPath(d.conf, n.info) if path.startsWith(cwd): path = path[cwd.len+1..^1].replace('\\', '/') let gitUrl = getConfigVar(d.conf, "git.url") @@ -944,268 +735,65 @@ proc genSeeSrc(d: PDoc, path: string, line: int): string = else: "version-$1-$2" % [$NimMajor, $NimMinor] let commit = getConfigVar(d.conf, "git.commit", defaultBranch) let develBranch = getConfigVar(d.conf, "git.devel", "devel") - dispA(d.conf, result, "$1", "", [docItemSeeSrc % [ - "path", path.string, "line", $line, "url", gitUrl, - "commit", commit, "devel", develBranch]]) + dispA(d.conf, seeSrcRope, "$1", "", [ropeFormatNamedVars(d.conf, docItemSeeSrc, + ["path", "line", "url", "commit", "devel"], [rope path.string, + rope($n.info.line), rope gitUrl, rope commit, rope develBranch])]) -proc symbolPriority(k: TSymKind): int = - result = case k - of skMacro: -3 - of skTemplate: -2 - of skIterator: -1 - else: 0 # including skProc which have higher priority - # documentation itself has even higher priority 1 + d.section[k].add(ropeFormatNamedVars(d.conf, getConfigVar(d.conf, "doc.item"), + ["name", "header", "desc", "itemID", "header_plain", "itemSym", + "itemSymOrID", "itemSymEnc", "itemSymOrIDEnc", "seeSrc", "deprecationMsg"], + [nameRope, result, comm, itemIDRope, plainNameRope, plainSymbolRope, + symbolOrIdRope, plainSymbolEncRope, symbolOrIdEncRope, seeSrcRope, + deprecationMsgRope])) -proc getTypeKind(n: PNode): string = - case n[2].kind - of nkEnumTy: "enum" - of nkObjectTy: "object" - of nkTupleTy: "tuple" - else: "" + let external = d.destFile.relativeTo(d.conf.outDir, '/').changeFileExt(HtmlExt).string -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``. - result.name = baseName.nimIdentNormalize - result.symKind = k.toHumanStr - if k in routineKinds: - var - paramTypes: seq[string] - renderParamTypes(paramTypes, n[paramsPos], toNormalize=true) - let paramNames = renderParamNames(n[paramsPos], toNormalize=true) - # In some rare cases (system.typeof) parameter type is not set for default: - doAssert paramTypes.len <= paramNames.len - for i in 0 ..< paramNames.len: - if i < paramTypes.len: - result.parameters.add (paramNames[i], paramTypes[i]) - else: - result.parameters.add (paramNames[i], "") - result.parametersProvided = true - - result.outType = renderOutType(n[paramsPos], toNormalize=true) - - if k in {skProc, skFunc, skType, skIterator}: - # Obtain `result.generics` - # Use `n[miscPos]` since n[genericParamsPos] does not contain constraints - var genNode: PNode = nil - if k == skType: - genNode = n[1] # FIXME: what is index 1? - else: - if n[miscPos].kind != nkEmpty: - genNode = n[miscPos][1] # FIXME: what is index 1? - if genNode != nil: - var literal = "" - var r: TSrcGen - initTokRender(r, genNode, {renderNoBody, renderNoComments, - renderNoPragmas, renderNoProcDefs, renderExpandUsing}) - var kind = tkEof - while true: - getNextTok(r, kind, literal) - if kind == tkEof: - break - if kind != tkSpaces: - result.generics.add(literal.nimIdentNormalize) - - if k == skType: result.symTypeKind = getTypeKind(n) - -proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind, docFlags: DocFlags, nonExports: bool = false) = - if (docFlags != kForceExport) and not isVisible(d, nameNode): return - let - name = getName(nameNode) - nameEsc = esc(d.target, name) - var plainDocstring = getPlainDocstring(n) # call here before genRecComment! - var result = "" - var literal, plainName = "" - var kind = tkEof - var comm: ItemPre - if n.kind in routineDefs: - getAllRunnableExamples(d, n, comm) - else: - comm.add genRecComment(d, n) - - var r: TSrcGen - # Obtain the plain rendered string for hyperlink titles. - initTokRender(r, n, {renderNoBody, renderNoComments, renderDocComments, - renderNoPragmas, renderNoProcDefs, renderExpandUsing}) - while true: - getNextTok(r, kind, literal) - if kind == tkEof: - break - plainName.add(literal) - - var pragmaNode = getDeclPragma(n) - if pragmaNode != nil: pragmaNode = findPragma(pragmaNode, wDeprecated) - - inc(d.id) - let - plainNameEsc = esc(d.target, plainName.strip) - typeDescr = - if k == skType and getTypeKind(n) != "": getTypeKind(n) - else: k.toHumanStr - detailedName = typeDescr & " " & ( - if k in routineKinds: plainName else: name) - uniqueName = if k in routineKinds: plainNameEsc else: nameEsc - sortName = if k in routineKinds: plainName.strip else: name - cleanPlainSymbol = renderPlainSymbolName(nameNode) - complexSymbol = complexName(k, n, cleanPlainSymbol) - plainSymbolEnc = encodeUrl(cleanPlainSymbol, usePlus = false) - symbolOrId = d.newUniquePlainSymbol(complexSymbol) - symbolOrIdEnc = encodeUrl(symbolOrId, usePlus = false) - deprecationMsg = genDeprecationMsg(d, pragmaNode) - rstLangSymbol = toLangSymbol(k, n, cleanPlainSymbol) - - # we generate anchors automatically for subsequent use in doc comments - 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) - - let renderFlags = - if nonExports: {renderNoBody, renderNoComments, renderDocComments, renderSyms, - renderExpandUsing, renderNonExportedFields} - else: {renderNoBody, renderNoComments, renderDocComments, renderSyms, renderExpandUsing} - nodeToHighlightedHtml(d, n, result, renderFlags, symbolOrIdEnc) - - let seeSrc = genSeeSrc(d, toFullPath(d.conf, n.info), n.info.line.int) - - d.section[k].secItems.mgetOrPut(cleanPlainSymbol, newSeq[Item]()).add Item( - descRst: comm, - sortName: sortName, - info: lineinfo, - anchor: symbolOrId, - detailedName: detailedName, - name: name, - substitutions: @[ - "uniqueName", uniqueName, - "header", result, "itemID", $d.id, - "header_plain", plainNameEsc, "itemSym", cleanPlainSymbol, - "itemSymEnc", plainSymbolEnc, - "itemSymOrIDEnc", symbolOrIdEnc, "seeSrc", seeSrc, - "deprecationMsg", deprecationMsg]) - - let external = d.destFile.AbsoluteFile.relativeTo(d.conf.outDir, '/').changeFileExt(HtmlExt).string - - var attype = "" + var attype: Rope if k in routineKinds and nameNode.kind == nkSym: let att = attachToType(d, nameNode.sym) if att != nil: - attype = esc(d.target, att.name.s) + attype = rope esc(d.target, att.name.s) elif k == skType and nameNode.kind == nkSym and nameNode.sym.typ.kind in {tyEnum, tyBool}: let etyp = nameNode.sym.typ for e in etyp.n: 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, - content: getConfigVar(d.conf, "doc.item.toc") % [ - "name", name, "header_plain", plainNameEsc, - "itemSymOrIDEnc", symbolOrIdEnc]) + d.toc[k].add(ropeFormatNamedVars(d.conf, getConfigVar(d.conf, "doc.item.toc"), + ["name", "header", "desc", "itemID", "header_plain", "itemSym", + "itemSymOrID", "itemSymEnc", "itemSymOrIDEnc", "attype"], + [rope(getName(d, nameNode, d.splitAfter)), result, comm, + itemIDRope, plainNameRope, plainSymbolRope, symbolOrIdRope, + plainSymbolEncRope, symbolOrIdEncRope, attype])) - d.tocTable[k].mgetOrPut(cleanPlainSymbol, newSeq[TocItem]()).add TocItem( - sortName: sortName, - content: getConfigVar(d.conf, "doc.item.tocTable") % [ - "name", name, "header_plain", plainNameEsc, - "itemSymOrID", symbolOrId.replace(",", ","), - "itemSymOrIDEnc", symbolOrIdEnc]) + # 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.isCallable: linkTitle.add(xmltree.escape(plainName.strip)) + else: linkTitle.add(xmltree.escape(complexSymbol.strip)) - setIndexTerm(d[], ieNim, htmlFile = external, id = symbolOrId, term = name, - linkTitle = detailedName, - linkDesc = xmltree.escape(plainDocstring.docstringSummary), - line = n.info.line.int) + 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): JsonItem = +proc genJsonItem(d: PDoc, n, nameNode: PNode, k: TSymKind): JsonNode = if not isVisible(d, nameNode): return var - name = getNameEsc(d, nameNode) - comm = genRecComment(d, n) + name = getName(d, nameNode) + comm = $genRecComment(d, n) r: TSrcGen - 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: - result.rst = comm - result.rstField = "description" + initTokRender(r, n, {renderNoBody, renderNoComments, renderDocComments}) + result = %{ "name": %name, "type": %($k), "line": %n.info.line.int, + "col": %n.info.col} + if comm.len > 0: + result["description"] = %comm if r.buf.len > 0: - result.json["code"] = %r.buf - if k in routineKinds: - result.json["signature"] = newJObject() - if n[paramsPos][0].kind != nkEmpty: - result.json["signature"]["return"] = %($n[paramsPos][0]) - if n[paramsPos].len > 1: - result.json["signature"]["arguments"] = newJArray() - for paramIdx in 1 ..< n[paramsPos].len: - for identIdx in 0 ..< n[paramsPos][paramIdx].len - 2: - let - paramName = $n[paramsPos][paramIdx][identIdx] - paramType = $n[paramsPos][paramIdx][^2] - if n[paramsPos][paramIdx][^1].kind != nkEmpty: - let paramDefault = $n[paramsPos][paramIdx][^1] - result.json["signature"]["arguments"].add %{"name": %paramName, "type": %paramType, "default": %paramDefault} - else: - result.json["signature"]["arguments"].add %{"name": %paramName, "type": %paramType} - if n[pragmasPos].kind != nkEmpty: - result.json["signature"]["pragmas"] = newJArray() - for pragma in n[pragmasPos]: - result.json["signature"]["pragmas"].add %($pragma) - if n[genericParamsPos].kind != nkEmpty: - result.json["signature"]["genericParams"] = newJArray() - for genericParam in n[genericParamsPos]: - var param = %{"name": %($genericParam)} - if genericParam.sym.typ.sons.len > 0: - param["types"] = newJArray() - for kind in genericParam.sym.typ.sons: - param["types"].add %($kind) - result.json["signature"]["genericParams"].add param - if optGenIndex in d.conf.globalOptions: - genItem(d, n, nameNode, k, kForceExport) - -proc setDoctype(d: PDoc, n: PNode) = - ## Processes `{.doctype.}` pragma changing Markdown/RST parsing options. - if n == nil: - return - if n.len != 2: - localError(d.conf, n.info, errUser, - "doctype pragma takes exactly 1 argument" - ) - return - var dt = "" - case n[1].kind - of nkStrLit: - dt = toLowerAscii(n[1].strVal) - of nkIdent: - dt = toLowerAscii(n[1].ident.s) - else: - localError(d.conf, n.info, errUser, - "unknown argument type $1 provided to doctype" % [$n[1].kind] - ) - return - case dt - of "markdown": - d.sharedState.options.incl roSupportMarkdown - d.sharedState.options.incl roPreferMarkdown - of "rstmarkdown": - d.sharedState.options.incl roSupportMarkdown - d.sharedState.options.excl roPreferMarkdown - of "rst": - d.sharedState.options.excl roSupportMarkdown - d.sharedState.options.excl roPreferMarkdown - else: - localError(d.conf, n.info, errUser, - ( - "unknown doctype value \"$1\", should be from " & - "\"RST\", \"Markdown\", \"RstMarkdown\"" - ) % [dt] - ) + result["code"] = %r.buf proc checkForFalse(n: PNode): bool = result = n.kind == nkIdent and cmpIgnoreStyle(n.ident.s, "false") == 0 @@ -1222,37 +810,33 @@ proc traceDeps(d: PDoc, it: PNode) = for x in it[2]: a[2] = x traceDeps(d, a) - elif it.kind == nkSym and belongsToProjectPackage(d.conf, it.sym): + elif it.kind == nkSym and belongsToPackage(d.conf, it.sym): let external = externalDep(d, it.sym) - if d.section[k].finalMarkup != "": d.section[k].finalMarkup.add(", ") - dispA(d.conf, d.section[k].finalMarkup, + if d.section[k] != nil: d.section[k].add(", ") + dispA(d.conf, d.section[k], "$1", - "$1", [esc(d.target, external.prettyLink), - changeFileExt(external, "html")]) + "$1", [rope esc(d.target, changeFileExt(external, "")), + rope changeFileExt(external, "html")]) proc exportSym(d: PDoc; s: PSym) = const k = exportSection - if s.kind == skModule and belongsToProjectPackage(d.conf, s): + if s.kind == skModule and belongsToPackage(d.conf, s): let external = externalDep(d, s) - if d.section[k].finalMarkup != "": d.section[k].finalMarkup.add(", ") - dispA(d.conf, d.section[k].finalMarkup, + if d.section[k] != nil: d.section[k].add(", ") + dispA(d.conf, d.section[k], "$1", - "$1", [esc(d.target, external.prettyLink), - changeFileExt(external, "html")]) + "$1", [rope esc(d.target, changeFileExt(external, "")), + rope changeFileExt(external, "html")]) elif s.kind != skModule and s.owner != nil: let module = originatingModule(s) - if belongsToProjectPackage(d.conf, module): - let - complexSymbol = complexName(s.kind, s.ast, s.name.s) - symbolOrId = d.newUniquePlainSymbol(complexSymbol) - external = externalDep(d, module) - if d.section[k].finalMarkup != "": d.section[k].finalMarkup.add(", ") + if belongsToPackage(d.conf, module): + let external = externalDep(d, module) + if d.section[k] != nil: d.section[k].add(", ") # XXX proper anchor generation here - dispA(d.conf, d.section[k].finalMarkup, - "$1", - "$1", [esc(d.target, s.name.s), - changeFileExt(external, "html"), - symbolOrId]) + dispA(d.conf, d.section[k], + "$1", + "$1", [rope esc(d.target, s.name.s), + rope changeFileExt(external, "html")]) proc documentNewEffect(cache: IdentCache; n: PNode): PNode = let s = n[namePos].sym @@ -1267,19 +851,18 @@ proc documentEffect(cache: IdentCache; n, x: PNode, effectType: TSpecialWord, id let actual = s.typ.n[0] if actual.len != effectListLen: return let real = actual[idx] - if real == nil: return - let realLen = real.len + # warning: hack ahead: - var effects = newNodeI(nkBracket, n.info, realLen) - for i in 0.. 0: - result = newTreeI(nkExprColonExpr, n.info, - newIdentNode(getIdent(cache, pragmaName), n.info), effects) + result = newNode(nkExprColonExpr, n.info, @[ + newIdentNode(getIdent(cache, pragmaName), n.info), effects]) proc documentRaises*(cache: IdentCache; n: PNode) = if n[namePos].kind != nkSym: return @@ -1302,9 +885,8 @@ proc documentRaises*(cache: IdentCache; n: PNode) = let p3 = documentWriteEffect(cache, n, sfWrittenTo, "writes") let p4 = documentNewEffect(cache, n) let p5 = documentWriteEffect(cache, n, sfEscapes, "escapes") - let p6 = documentEffect(cache, n, pragmas, wForbids, forbiddenEffects) - if p1 != nil or p2 != nil or p3 != nil or p4 != nil or p5 != nil or p6 != nil: + if p1 != nil or p2 != nil or p3 != nil or p4 != nil or p5 != nil: if pragmas.kind == nkEmpty: n[pragmasPos] = newNodeI(nkPragma, n.info) if p1 != nil: n[pragmasPos].add p1 @@ -1312,25 +894,21 @@ proc documentRaises*(cache: IdentCache; n: PNode) = if p3 != nil: n[pragmasPos].add p3 if p4 != nil: n[pragmasPos].add p4 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) = - ## Goes through nim nodes recursively and collects doc comments. - ## Main function for `doc`:option: command, - ## which is implemented in ``docgen2.nim``. +proc generateDoc*(d: PDoc, n, orig: PNode, docFlags: DocFlags = kDefault) = 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) d.modDeprecationMsg.add(genDeprecationMsg(d, pragmaNode)) - let doctypeNode = findPragma(n, wDoctype) - setDoctype(d, doctypeNode) - of nkCommentStmt: d.modDescPre.add(genComment(d, n)) - of nkProcDef, nkFuncDef: + of nkCommentStmt: d.modDesc.add(genComment(d, n)) + of nkProcDef: when useEffectSystem: documentRaises(d.cache, n) genItemAux(skProc) + of nkFuncDef: + when useEffectSystem: documentRaises(d.cache, n) + genItemAux(skFunc) of nkMethodDef: when useEffectSystem: documentRaises(d.cache, n) genItemAux(skMethod) @@ -1347,186 +925,46 @@ 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.. 1: - 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, - LangSymbol(symKind: k.toHumanStr, - name: name, - isGroup: true), - priority = symbolPriority(k), - # select index `0` just to have any meaningful warning: - info = overloadChoices[0].info) - - if optGenIndexOnly in d.conf.globalOptions: - return - - # Finalize fragments of ``.nim`` or ``.rst`` file - proc renderItemPre(d: PDoc, fragments: ItemPre, result: var string) = - for f in fragments: - case f.isRst: - of true: - var resolved = resolveSubs(d.sharedState, f.rst) - renderRstToOut(d[], resolved, result) - of false: result &= f.str - proc cmp(x, y: Item): int = cmpDecimalsIgnoreCase(x.sortName, y.sortName) - for k in TSymKind: - # add symbols to section for each `k`, while optionally wrapping - # overloadable items with the same basic name by ``doc.item2`` - let overloadableNames = toSeq(keys(d.section[k].secItems)) - for plainName in overloadableNames.sorted(cmpDecimalsIgnoreCase): - var overloadChoices = d.section[k].secItems[plainName] - overloadChoices.sort(cmp) - var nameContent = "" - for item in overloadChoices: - var itemDesc: string - renderItemPre(d, item.descRst, itemDesc) - nameContent.add( - getConfigVar(d.conf, "doc.item") % ( - item.substitutions & @[ - "desc", itemDesc, - "name", item.name, - "itemSymOrID", item.anchor])) - if k in routineKinds: - let plainNameEsc1 = esc(d.target, plainName.strip) - let plainNameEsc2 = esc(d.target, plainName.strip, escMode=emUrl) - d.section[k].finalMarkup.add( - getConfigVar(d.conf, "doc.item2") % ( - @["header_plain", plainNameEsc1, - "overloadGroupName", overloadGroupName(plainNameEsc2, k), - "content", nameContent])) - else: - d.section[k].finalMarkup.add(nameContent) - d.section[k].secItems.clear - renderItemPre(d, d.modDescPre, d.modDescFinal) - d.modDescPre.setLen 0 - - # Finalize fragments of ``.json`` file - for i, entry in d.jEntriesPre: - if entry.rst != nil: - let resolved = resolveSubs(d.sharedState, entry.rst) - var str: string - renderRstToOut(d[], resolved, str) - entry.json[entry.rstField] = %str - d.jEntriesPre[i].rst = nil - - 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 add(d: PDoc; j: JsonNode) = + if j != nil: d.jArray.add j proc generateJson*(d: PDoc, n: PNode, includeComments: bool = true) = case n.kind - of nkPragma: - let doctypeNode = findPragma(n, wDoctype) - setDoctype(d, doctypeNode) of nkCommentStmt: if includeComments: - d.add JsonItem(rst: genComment(d, n), rstField: "comment", - json: %Table[string, string]()) + d.add %*{"comment": genComment(d, n)} else: - d.modDescPre.add(genComment(d, n)) - of nkProcDef, nkFuncDef: + d.modDesc.add(genComment(d, n)) + of nkProcDef: when useEffectSystem: documentRaises(d.cache, n) d.add genJsonItem(d, n, n[namePos], skProc) + of nkFuncDef: + when useEffectSystem: documentRaises(d.cache, n) + d.add genJsonItem(d, n, n[namePos], skFunc) of nkMethodDef: when useEffectSystem: documentRaises(d.cache, n) d.add genJsonItem(d, n, n[namePos], skMethod) @@ -1556,9 +994,9 @@ proc generateJson*(d: PDoc, n: PNode, includeComments: bool = true) = 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) = +proc generateTags*(d: PDoc, n: PNode, r: var Rope) = case n.kind of nkCommentStmt: if startsWith(n.comment, "##"): @@ -1598,304 +1036,212 @@ proc generateTags*(d: PDoc, n: PNode, r: var string) = generateTags(d, lastSon(n[0]), r) else: discard -proc genSection(d: PDoc, kind: TSymKind, groupedToc = false) = +proc genSection(d: PDoc, kind: TSymKind) = const sectionNames: array[skModule..skField, string] = [ "Imports", "Types", "Vars", "Lets", "Consts", "Vars", "Procs", "Funcs", "Methods", "Iterators", "Converters", "Macros", "Templates", "Exports" ] - if d.section[kind].finalMarkup == "": return - var title = sectionNames[kind] - d.section[kind].finalMarkup = getConfigVar(d.conf, "doc.section") % [ - "sectionid", $ord(kind), "sectionTitle", title, - "sectionTitleID", $(ord(kind) + 50), "content", d.section[kind].finalMarkup] + if d.section[kind] == nil: return + var title = sectionNames[kind].rope + d.section[kind] = ropeFormatNamedVars(d.conf, getConfigVar(d.conf, "doc.section"), [ + "sectionid", "sectionTitle", "sectionTitleID", "content"], [ + ord(kind).rope, title, rope(ord(kind) + 50), d.section[kind]]) + d.toc[kind] = ropeFormatNamedVars(d.conf, getConfigVar(d.conf, "doc.section.toc"), [ + "sectionid", "sectionTitle", "sectionTitleID", "content"], [ + ord(kind).rope, title, rope(ord(kind) + 50), d.toc[kind]]) - proc cmp(x, y: TocItem): int = cmpDecimalsIgnoreCase(x.sortName, y.sortName) - if groupedToc: - let overloadableNames = toSeq(keys(d.tocTable[kind])) - for plainName in overloadableNames.sorted(cmpDecimalsIgnoreCase): - var overloadChoices = d.tocTable[kind][plainName] - overloadChoices.sort(cmp) - var content: string - for item in overloadChoices: - content.add item.content - d.toc2[kind].add getConfigVar(d.conf, "doc.section.toc2") % [ - "sectionid", $ord(kind), "sectionTitle", title, - "sectionTitleID", $(ord(kind) + 50), - "content", content, "plainName", plainName] - else: - for item in d.tocSimple[kind].sorted(cmp): - d.toc2[kind].add item.content +proc cssHref(outDir: AbsoluteDir, destFile: AbsoluteFile): Rope = + rope($relativeTo(outDir / RelativeFile"nimdoc.out.css", destFile.splitFile().dir, '/')) - let sectionValues = @[ - "sectionID", $ord(kind), "sectionTitleID", $(ord(kind) + 50), - "sectionTitle", title - ] - - # Check if the toc has any children - if d.toc2[kind] != "": - # Use the dropdown version instead and store the children in the dropdown - d.toc[kind] = getConfigVar(d.conf, "doc.section.toc") % (sectionValues & @[ - "content", d.toc2[kind] - ]) - else: - # Just have the link - d.toc[kind] = getConfigVar(d.conf, "doc.section.toc_item") % sectionValues - -proc relLink(outDir: AbsoluteDir, destFile: AbsoluteFile, linkto: RelativeFile): string = - $relativeTo(outDir / linkto, destFile.splitFile().dir, '/') - -proc genOutFile(d: PDoc, groupedToc = false): string = +proc genOutFile(d: PDoc): Rope = var - code, content: string + code, content: Rope title = "" var j = 0 - var toc = "" - renderTocEntries(d[], j, 1, toc) - for i in TSymKind: - var shouldSort = i in routineKinds and groupedToc - genSection(d, i, shouldSort) + var tmp = "" + renderTocEntries(d[], j, 1, tmp) + var toc = tmp.rope + for i in low(TSymKind)..high(TSymKind): + genSection(d, i) toc.add(d.toc[i]) - if toc != "" or d.target == outLatex: - # for Latex $doc.toc will automatically generate TOC if `d.hasToc` is set - toc = getConfigVar(d.conf, "doc.toc") % ["content", toc] - for i in TSymKind: code.add(d.section[i].finalMarkup) + if toc != nil: + toc = ropeFormatNamedVars(d.conf, getConfigVar(d.conf, "doc.toc"), ["content"], [toc]) + for i in low(TSymKind)..high(TSymKind): code.add(d.section[i]) # 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 = presentationPath(d.conf, AbsoluteFile d.filename).changeFileExt(HtmlExt).string.nativeToUnix + setIndexTerm(d[], external, "", title) else: - title = canonicalImport(d.conf, AbsoluteFile d.filename) - title = esc(d.target, title) - var subtitle = "" - if d.meta[metaSubtitle] != "": - dispA(d.conf, subtitle, "

$1

", - "\\\\\\vspace{0.5em}\\large $1", [esc(d.target, d.meta[metaSubtitle])]) + # Modules get an automatic title for the HTML, but no entry in the index. + # better than `extractFilename(changeFileExt(d.filename, ""))` as it disambiguates dups + title = $presentationPath(d.conf, AbsoluteFile d.filename, isTitle = true).changeFileExt("") - var groupsection = getConfigVar(d.conf, "doc.body_toc_groupsection") - let bodyname = if d.hasToc and not d.standaloneDoc and not d.conf.isLatexCmd: - groupsection.setLen 0 - "doc.body_toc_group" + let bodyname = if d.hasToc and not d.isPureRst: "doc.body_toc_group" elif d.hasToc: "doc.body_toc" else: "doc.body_no_toc" - let seeSrc = genSeeSrc(d, d.filename, 1) - content = getConfigVar(d.conf, bodyname) % [ - "title", title, "subtitle", subtitle, - "tableofcontents", toc, "moduledesc", d.modDescFinal, "date", getDateStr(), - "time", getClockStr(), "content", code, - "deprecationMsg", d.modDeprecationMsg, - "theindexhref", relLink(d.conf.outDir, d.destFile.AbsoluteFile, - theindexFname.RelativeFile), - "body_toc_groupsection", groupsection, "seeSrc", seeSrc] + content = ropeFormatNamedVars(d.conf, getConfigVar(d.conf, bodyname), ["title", + "tableofcontents", "moduledesc", "date", "time", "content", "deprecationMsg"], + [title.rope, toc, d.modDesc, rope(getDateStr()), + rope(getClockStr()), code, d.modDeprecationMsg]) if optCompileOnly notin d.conf.globalOptions: # XXX what is this hack doing here? 'optCompileOnly' means raw output!? - code = getConfigVar(d.conf, "doc.file") % [ - "nimdoccss", relLink(d.conf.outDir, d.destFile.AbsoluteFile, - nimdocOutCss.RelativeFile), - "dochackjs", relLink(d.conf.outDir, d.destFile.AbsoluteFile, - docHackJsFname.RelativeFile), - "title", title, "subtitle", subtitle, "tableofcontents", toc, - "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] + code = ropeFormatNamedVars(d.conf, getConfigVar(d.conf, "doc.file"), [ + "nimdoccss", "title", "tableofcontents", "moduledesc", "date", "time", + "content", "author", "version", "analytics", "deprecationMsg"], + [cssHref(d.conf.outDir, d.destFile), title.rope, toc, d.modDesc, rope(getDateStr()), rope(getClockStr()), + content, d.meta[metaAuthor].rope, d.meta[metaVersion].rope, d.analytics.rope, 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 = if not d.conf.outDir.isEmpty: d.conf.outDir + else: d.conf.projectPath / htmldocsDir + createDir(dir) + let dest = dir / changeFileExt(presentationPath(d.conf, AbsoluteFile d.filename), IndexExt) writeIndexFile(d[], dest.string) proc updateOutfile(d: PDoc, outfile: AbsoluteFile) = - if d.module == nil or sfMainModule in d.module.flags: # nil for e.g. for commandRst2Html - if d.conf.outFile.isEmpty: + if d.module == nil or sfMainModule in d.module.flags: # nil for eg for commandRst2Html + if d.conf.outFile.isEmpty and not d.conf.outDir.isEmpty: d.conf.outFile = outfile.relativeTo(d.conf.outDir) - if isAbsolute(d.conf.outFile.string): - 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 +proc writeOutput*(d: PDoc, useWarning = false) = runAllExamples(d) - var content = genOutFile(d, groupedToc) + var content = genOutFile(d) if optStdout in d.conf.globalOptions: - write(stdout, content) + writeRope(stdout, content) else: - template outfile: untyped = d.destFile.AbsoluteFile - #let outfile = getOutFile2(d.conf, shortenDir(d.conf, filename), outExt) - let dir = outfile.splitFile.dir - createDir(dir) + template outfile: untyped = d.destFile + #let outfile = getOutFile2(d.conf, shortenDir(d.conf, filename), outExt, htmldocsDir) + createDir(outfile.splitFile.dir) updateOutfile(d, outfile) - try: - writeFile(outfile, content) - except IOError: + if not writeRope(content, outfile): rawMessage(d.conf, if useWarning: warnCannotOpenFile else: errCannotOpenFile, outfile.string) - if not d.wroteSupportFiles: # nimdoc.css + dochack.js - let nimr = $d.conf.getPrefixDir() - case d.target - of outHtml: - copyFile(docCss.interp(nimr = nimr), $d.conf.outDir / nimdocOutCss) - of outLatex: - copyFile(docCls.interp(nimr = nimr), $d.conf.outDir / nimdocOutCls) - if optGenIndex in d.conf.globalOptions: - let docHackJs2 = getDocHacksJs(nimr, nim = getAppFilename()) - copyFile(docHackJs2, $d.conf.outDir / docHackJs2.lastPathPart) - d.wroteSupportFiles = true + elif not d.wroteCss: + let cssSource = $d.conf.getPrefixDir() / "doc" / "nimdoc.css" + let cssDest = $d.conf.outDir / "nimdoc.out.css" + # renamed to make it easier to use with gitignore in user's repos + copyFile(cssSource, cssDest) + d.wroteCss = true proc writeOutputJson*(d: PDoc, useWarning = false) = runAllExamples(d) var modDesc: string - for desc in d.modDescFinal: + for desc in d.modDesc: modDesc &= desc let content = %*{"orig": d.filename, "nimble": getPackageName(d.conf, d.filename), "moduleDescription": modDesc, - "entries": d.jEntriesFinal} + "entries": d.jArray} if optStdout in d.conf.globalOptions: write(stdout, $content) else: - let dir = d.destFile.splitFile.dir - createDir(dir) var f: File - if open(f, d.destFile, fmWrite): + if open(f, d.destFile.string, fmWrite): write(f, $content) close(f) - updateOutfile(d, d.destFile.AbsoluteFile) + updateOutfile(d, d.destFile) else: localError(d.conf, newLineInfo(d.conf, AbsoluteFile d.filename, -1, -1), - warnUser, "unable to open file \"" & d.destFile & + warnUser, "unable to open file \"" & d.destFile.string & "\" for writing") proc handleDocOutputOptions*(conf: ConfigRef) = if optWholeProject in conf.globalOptions: # Backward compatibility with previous versions - # xxx this is buggy when user provides `nim doc --project -o:sub/bar.html main`, - # it'd write to `sub/bar.html/main.html` conf.outDir = AbsoluteDir(conf.outDir / conf.outFile) proc commandDoc*(cache: IdentCache, conf: ConfigRef) = - ## implementation of deprecated ``doc0`` command (without semantic checking) handleDocOutputOptions conf 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) - finishGenerateDoc(d) + var d = newDocumentor(conf.projectFull, cache, conf) + d.hasToc = true + generateDoc(d, ast, ast) writeOutput(d) generateIndex(d) proc commandRstAux(cache: IdentCache, conf: ConfigRef; - filename: AbsoluteFile, outExt: string, - preferMarkdown: bool) = + filename: AbsoluteFile, outExt: string) = var filen = addFileExt(filename, "txt") - var d = newDocumentor(filen, cache, conf, outExt, standaloneDoc = true, - preferMarkdown = preferMarkdown, hasToc = false) - let rst = parseRst(readFile(filen.string), - line=LineRstInit, column=ColRstInit, - conf, d.sharedState) - d.modDescPre = @[ItemFragment(isRst: true, rst: rst)] - finishGenerateDoc(d) + var d = newDocumentor(filen, cache, conf, outExt) + + d.isPureRst = true + var rst = parseRst(readFile(filen.string), filen.string, 0, 1, d.hasToc, + {roSupportRawDirective, roSupportMarkdown}, conf) + var modDesc = newStringOfCap(30_000) + renderRstToOut(d[], rst, modDesc) + d.modDesc = rope(modDesc) writeOutput(d) generateIndex(d) -proc commandRst2Html*(cache: IdentCache, conf: ConfigRef, - preferMarkdown=false) = - commandRstAux(cache, conf, conf.projectFull, HtmlExt, preferMarkdown) +proc commandRst2Html*(cache: IdentCache, conf: ConfigRef) = + commandRstAux(cache, conf, conf.projectFull, HtmlExt) -proc commandRst2TeX*(cache: IdentCache, conf: ConfigRef, - preferMarkdown=false) = - commandRstAux(cache, conf, conf.projectFull, TexExt, preferMarkdown) +proc commandRst2TeX*(cache: IdentCache, conf: ConfigRef) = + commandRstAux(cache, conf, conf.projectFull, TexExt) proc commandJson*(cache: IdentCache, conf: ConfigRef) = - ## implementation of a deprecated jsondoc0 command var ast = parseFile(conf.projectMainIdx, cache, conf) if ast == nil: return - var d = newDocumentor(conf.projectFull, cache, conf, hasToc = true) + var d = newDocumentor(conf.projectFull, cache, conf) d.onTestSnippet = proc (d: var RstGenerator; filename, cmd: string; - status: int; content: string) {.gcsafe.} = + status: int; content: string) = localError(conf, newLineInfo(conf, AbsoluteFile d.filename, -1, -1), warnUser, "the ':test:' attribute is not supported by this backend") + d.hasToc = true generateJson(d, ast) - finishGenerateDoc(d) - let json = d.jEntriesFinal - let content = pretty(json) + let json = d.jArray + let content = rope(pretty(json)) if optStdout in d.conf.globalOptions: - write(stdout, content) + writeRope(stdout, content) else: #echo getOutFile(gProjectFull, JsonExt) let filename = getOutFile(conf, RelativeFile conf.projectName, JsonExt) - try: - writeFile(filename, content) - except IOError: + if not writeRope(content, filename): rawMessage(conf, errCannotOpenFile, filename.string) proc commandTags*(cache: IdentCache, conf: ConfigRef) = var ast = parseFile(conf.projectMainIdx, cache, conf) if ast == nil: return - var d = newDocumentor(conf.projectFull, cache, conf, hasToc = true) + var d = newDocumentor(conf.projectFull, cache, conf) d.onTestSnippet = proc (d: var RstGenerator; filename, cmd: string; - status: int; content: string) {.gcsafe.} = + status: int; content: string) = localError(conf, newLineInfo(conf, AbsoluteFile d.filename, -1, -1), warnUser, "the ':test:' attribute is not supported by this backend") + d.hasToc = true var - content = "" + content: Rope generateTags(d, ast, content) if optStdout in d.conf.globalOptions: - write(stdout, content) + writeRope(stdout, content) else: #echo getOutFile(gProjectFull, TagsExt) let filename = getOutFile(conf, RelativeFile conf.projectName, TagsExt) - try: - writeFile(filename, content) - except IOError: + if not writeRope(content, filename): rawMessage(conf, errCannotOpenFile, filename.string) -proc commandBuildIndex*(conf: ConfigRef, dir: string, outFile = RelativeFile"") = - if optGenIndexOnly in conf.globalOptions: - return - var content = mergeIndexes(dir) +proc commandBuildIndex*(cache: IdentCache, conf: ConfigRef) = + var content = mergeIndexes(conf.projectFull.string).rope - var outFile = outFile - if outFile.isEmpty: outFile = theindexFname.RelativeFile.changeFileExt("") + var outFile = RelativeFile"theindex" + if conf.outFile != RelativeFile"": + outFile = conf.outFile let filename = getOutFile(conf, outFile, HtmlExt) - let code = getConfigVar(conf, "doc.file") % [ - "nimdoccss", relLink(conf.outDir, filename, nimdocOutCss.RelativeFile), - "dochackjs", relLink(conf.outDir, filename, docHackJsFname.RelativeFile), - "title", "Index", - "subtitle", "", "tableofcontents", "", "moduledesc", "", - "date", getDateStr(), "time", getClockStr(), - "content", content, "author", "", "version", "", "analytics", ""] + let code = ropeFormatNamedVars(conf, getConfigVar(conf, "doc.file"), [ + "nimdoccss", "title", "tableofcontents", "moduledesc", "date", "time", + "content", "author", "version", "analytics"], + [cssHref(conf.outDir, filename), rope"Index", nil, nil, rope(getDateStr()), + rope(getClockStr()), content, nil, nil, nil]) # no analytics because context is not available - try: - writeFile(filename, code) - except IOError: - rawMessage(conf, errCannotOpenFile, filename.string) - -proc commandBuildIndexJson*(conf: ConfigRef, dir: string, outFile = RelativeFile"") = - var (modules, symbols, docs) = readIndexDir(dir) - let documents = toSeq(keys(Table[IndexEntry, seq[IndexEntry]](docs))) - let body = %*({"documents": documents, "modules": modules, "symbols": symbols}) - - var outFile = outFile - if outFile.isEmpty: outFile = theindexFname.RelativeFile.changeFileExt("") - let filename = getOutFile(conf, outFile, JsonExt) - - try: - writeFile(filename, $body) - except IOError: + if not writeRope(code, filename): rawMessage(conf, errCannotOpenFile, filename.string) diff --git a/compiler/docgen2.nim b/compiler/docgen2.nim index 0941be78a..438417ca0 100644 --- a/compiler/docgen2.nim +++ b/compiler/docgen2.nim @@ -11,7 +11,7 @@ # semantic checking. import - options, ast, msgs, docgen, lineinfos, pathutils, packages + options, ast, msgs, passes, docgen, lineinfos, pathutils from modulegraphs import ModuleGraph, PPassContext @@ -23,36 +23,34 @@ type PGen = ref TGen proc shouldProcess(g: PGen): bool = - (optWholeProject in g.doc.conf.globalOptions and g.doc.conf.belongsToProjectPackage(g.module)) or + (optWholeProject in g.doc.conf.globalOptions and g.module.getnimblePkgId == g.doc.conf.mainPackageId) or sfMainModule in g.module.flags or g.config.projectMainIdx == g.module.info.fileIndex template closeImpl(body: untyped) {.dirty.} = var g = PGen(p) let useWarning = sfMainModule notin g.module.flags - let groupedToc = true if shouldProcess(g): - finishGenerateDoc(g.doc) body try: generateIndex(g.doc) 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) + writeOutput(g.doc, useWarning) -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): @@ -64,15 +62,20 @@ template myOpenImpl(ext: untyped) {.dirty.} = g.module = module g.config = graph.config var d = newDocumentor(AbsoluteFile toFullPath(graph.config, FileIndex module.position), - graph.cache, graph.config, ext, module, hasToc = true) + graph.cache, graph.config, ext, module) + d.hasToc = true g.doc = d result = g -proc openHtml*(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PPassContext = +proc myOpen(graph: ModuleGraph; module: PSym): PPassContext = myOpenImpl(HtmlExt) -proc openTex*(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PPassContext = - myOpenImpl(TexExt) - -proc openJson*(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PPassContext = +proc myOpenJson(graph: ModuleGraph; module: PSym): PPassContext = myOpenImpl(JsonExt) + +const docgen2Pass* = makePass(open = myOpen, process = processNode, close = close) +const docgen2JsonPass* = makePass(open = myOpenJson, process = processNodeJson, + close = closeJson) + +proc finishDoc2Pass*(project: string) = + discard diff --git a/compiler/enumtostr.nim b/compiler/enumtostr.nim index f8b3744d5..42d844609 100644 --- a/compiler/enumtostr.nim +++ b/compiler/enumtostr.nim @@ -1,20 +1,16 @@ import ast, idents, lineinfos, modulegraphs, magicsys -when defined(nimPreviewSlimSystem): - import std/assertions +proc genEnumToStrProc*(t: PType; info: TLineInfo; g: ModuleGraph): PSym = + result = newSym(skProc, getIdent(g.cache, "$"), t.owner, info) - -proc genEnumToStrProc*(t: PType; info: TLineInfo; g: ModuleGraph; idgen: IdGenerator): PSym = - result = newSym(skProc, getIdent(g.cache, "$"), nextSymId idgen, t.owner, info) - - let dest = newSym(skParam, getIdent(g.cache, "e"), nextSymId idgen, result, info) + let dest = newSym(skParam, getIdent(g.cache, "e"), result, info) dest.typ = t - let res = newSym(skResult, getIdent(g.cache, "result"), nextSymId idgen, result, info) + let res = newSym(skResult, getIdent(g.cache, "result"), result, info) res.typ = getSysType(g, info, tyString) - result.typ = newType(tyProc, nextTypeId idgen, t.owner) + result.typ = newType(tyProc, t.owner) result.typ.n = newNodeI(nkFormalParams, info) rawAddSon(result.typ, res.typ) result.typ.n.add newNodeI(nkEffectList, info) @@ -30,7 +26,7 @@ proc genEnumToStrProc*(t: PType; info: TLineInfo; g: ModuleGraph; idgen: IdGener assert(t.n[i].kind == nkSym) var field = t.n[i].sym let val = if field.ast == nil: field.name.s else: field.ast.strVal - caseStmt.add newTree(nkOfBranch, newIntTypeNode(field.position, t), + caseStmt.add newTree(nkOfBranch, newSymNode(field), newTree(nkStmtList, newTree(nkFastAsgn, newSymNode(res), newStrNode(val, info)))) #newIntTypeNode(nkIntLit, field.position, t) @@ -44,7 +40,6 @@ proc genEnumToStrProc*(t: PType; info: TLineInfo; g: ModuleGraph; idgen: IdGener n[resultPos] = newSymNode(res) result.ast = n incl result.flags, sfFromGeneric - incl result.flags, sfNeverRaises proc searchObjCaseImpl(obj: PNode; field: PSym): PNode = case obj.kind @@ -66,16 +61,16 @@ proc searchObjCase(t: PType; field: PSym): PNode = result = searchObjCase(t[0].skipTypes({tyAlias, tyGenericInst, tyRef, tyPtr}), field) doAssert result != nil -proc genCaseObjDiscMapping*(t: PType; field: PSym; info: TLineInfo; g: ModuleGraph; idgen: IdGenerator): PSym = - result = newSym(skProc, getIdent(g.cache, "objDiscMapping"), nextSymId idgen, t.owner, info) +proc genCaseObjDiscMapping*(t: PType; field: PSym; info: TLineInfo; g: ModuleGraph): PSym = + result = newSym(skProc, getIdent(g.cache, "objDiscMapping"), t.owner, info) - let dest = newSym(skParam, getIdent(g.cache, "e"), nextSymId idgen, result, info) + let dest = newSym(skParam, getIdent(g.cache, "e"), result, info) dest.typ = field.typ - let res = newSym(skResult, getIdent(g.cache, "result"), nextSymId idgen, result, info) + let res = newSym(skResult, getIdent(g.cache, "result"), result, info) res.typ = getSysType(g, info, tyUInt8) - result.typ = newType(tyProc, nextTypeId idgen, t.owner) + result.typ = newType(tyProc, t.owner) result.typ.n = newNodeI(nkFormalParams, info) rawAddSon(result.typ, res.typ) result.typ.n.add newNodeI(nkEffectList, info) @@ -106,4 +101,3 @@ proc genCaseObjDiscMapping*(t: PType; field: PSym; info: TLineInfo; g: ModuleGra n[resultPos] = newSymNode(res) result.ast = n incl result.flags, sfFromGeneric - incl result.flags, sfNeverRaises diff --git a/compiler/errorhandling.nim b/compiler/errorhandling.nim deleted file mode 100644 index a8361105e..000000000 --- a/compiler/errorhandling.nim +++ /dev/null @@ -1,82 +0,0 @@ -# -# -# The Nim Compiler -# (c) Copyright 2021 Andreas Rumpf -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# - -## This module contains support code for new-styled error -## handling via an `nkError` node kind. - -import ast, renderer, options, strutils, types - -when defined(nimPreviewSlimSystem): - import std/assertions - -type - ErrorKind* = enum ## expand as you need. - RawTypeMismatchError - ExpressionCannotBeCalled - CustomError - WrongNumberOfArguments - AmbiguousCall - -proc errorSubNode*(n: PNode): PNode = - case n.kind - of nkEmpty..nkNilLit: - result = nil - of nkError: - result = n - else: - result = nil - for i in 0.. 1 - let wrongNode = n[0] - case ErrorKind(n[1].intVal) - of RawTypeMismatchError: - result = "type mismatch" - of ExpressionCannotBeCalled: - result = "expression '$1' cannot be called" % wrongNode[0].renderTree - of CustomError: - result = n[2].strVal - of WrongNumberOfArguments: - result = "wrong number of arguments" - of AmbiguousCall: - let a = n[2].sym - let b = n[3].sym - var args = "(" - for i in 1.. 1: args.add(", ") - args.add(typeToString(wrongNode[i].typ)) - args.add(")") - result = "ambiguous call; both $1 and $2 match for: $3" % [ - getProcHeader(config, a), - getProcHeader(config, b), - args] diff --git a/compiler/evalffi.nim b/compiler/evalffi.nim index 0577619b8..856410eda 100644 --- a/compiler/evalffi.nim +++ b/compiler/evalffi.nim @@ -17,8 +17,6 @@ when defined(windows): const libcDll = "msvcrt.dll" elif defined(linux): const libcDll = "libc.so(.6|.5|)" -elif defined(openbsd): - const libcDll = "/usr/lib/libc.so(.95.1|)" elif defined(bsd): const libcDll = "/lib/libc.so.7" elif defined(osx): @@ -65,19 +63,19 @@ proc importcSymbol*(conf: ConfigRef, sym: PSym): PNode = if (lib.isNil or lib.kind == libHeader) and not gExeHandle.isNil: libPathMsg = "current exe: " & getAppFilename() & " nor libc: " & libcDll # first try this exe itself: - theAddr = gExeHandle.symAddr(name.cstring) + theAddr = gExeHandle.symAddr(name) # then try libc: if theAddr.isNil: let dllhandle = getDll(conf, gDllCache, libcDll, sym.info) - theAddr = dllhandle.symAddr(name.cstring) + theAddr = dllhandle.symAddr(name) elif not lib.isNil: let dll = if lib.kind == libHeader: libcDll else: lib.path.strVal libPathMsg = dll let dllhandle = getDll(conf, gDllCache, dll, sym.info) - theAddr = dllhandle.symAddr(name.cstring) + theAddr = dllhandle.symAddr(name) 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 @@ -92,11 +90,26 @@ proc mapType(conf: ConfigRef, t: ast.PType): ptr libffi.Type = else: result = nil of tyFloat, tyFloat64: result = addr libffi.type_double of tyFloat32: result = addr libffi.type_float - of tyVar, tyLent, tyPointer, tyPtr, tyRef, tyCstring, tySequence, tyString, tyUntyped, + of tyVar, tyLent, tyPointer, tyPtr, tyRef, tyCString, tySequence, tyString, tyUntyped, tyTyped, tyTypeDesc, tyProc, tyArray, tyStatic, tyNil: result = addr libffi.type_pointer of tyDistinct, tyAlias, tySink: result = mapType(conf, t[0]) + of tyObject: + var els = newSeq[ptr libffi.Type](t.n.sons.len + 1) + var ty: ptr libffi.Type = cast[ptr libffi.Type](alloc(sizeof(libffi.Type))) + + ty.size = 0 + ty.alignment = 0 + ty.typ = tkSTRUCT + ty.elements = addr els[0] + + els[els.len-1] = nil + for i in 0.. evalTemplateLimit: @@ -188,10 +181,8 @@ proc evalTemplate*(n: PNode, tmpl, genSymOwner: PSym; ctx.config = conf ctx.ic = ic initIdTable(ctx.mapping) - ctx.instID = instID[] - ctx.idgen = idgen - let body = tmpl.ast[bodyPos] + let body = tmpl.getBody #echo "instantion of ", renderTree(body, {renderIds}) if isAtom(body): result = newNodeI(nkPar, body.info) @@ -204,7 +195,7 @@ proc evalTemplate*(n: PNode, tmpl, genSymOwner: PSym; result = copyNode(body) ctx.instLines = sfCallsite in tmpl.flags if ctx.instLines: - setInfoRecursive(result, n.info) + result.info = n.info for i in 0.. 0: - flushDot(conf) - stderr.writeLine(cmd) +proc libNameTmpl(conf: ConfigRef): string {.inline.} = + result = if conf.target.targetOS == osWindows: "$1.lib" else: "lib$1.a" proc nameToCC*(name: string): TSystemCC = ## Returns the kind of compiler referred to by `name`, or ccNone @@ -299,10 +389,8 @@ proc nameToCC*(name: string): TSystemCC = return i result = ccNone -proc listCCnames(): string = - result = "" +proc listCCnames(): seq[string] = for i in succ(ccNone)..high(TSystemCC): - if i > succ(ccNone): result.add ", " result.add CC[i].name proc isVSCompatible*(conf: ConfigRef): bool = @@ -313,24 +401,22 @@ proc isVSCompatible*(conf: ConfigRef): bool = proc getConfigVar(conf: ConfigRef; c: TSystemCC, suffix: string): string = # use ``cpu.os.cc`` for cross compilation, unless ``--compileOnly`` is given # for niminst support - var fullSuffix = suffix - case conf.backend - of backendCpp, backendJs, backendObjc: fullSuffix = "." & $conf.backend & suffix - of backendC: discard - of backendInvalid: - # during parsing of cfg files; we don't know the backend yet, no point in - # guessing wrong thing - return "" + let fullSuffix = + if conf.cmd == cmdCompileToCpp: + ".cpp" & suffix + elif conf.cmd == cmdCompileToOC: + ".objc" & suffix + elif conf.cmd == cmdCompileToJS: + ".js" & suffix + else: + suffix - if (conf.target.hostOS != conf.target.targetOS or conf.target.hostCPU != conf.target.targetCPU) and - optCompileOnly notin conf.globalOptions: + if optCompileOnly notin conf.globalOptions: let fullCCname = platform.CPU[conf.target.targetCPU].name & '.' & 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: @@ -339,11 +425,12 @@ proc getConfigVar(conf: ConfigRef; c: TSystemCC, suffix: string): string = proc setCC*(conf: ConfigRef; ccname: string; info: TLineInfo) = conf.cCompiler = nameToCC(ccname) if conf.cCompiler == ccNone: - localError(conf, info, "unknown C compiler: '$1'. Available options are: $2" % [ccname, listCCnames()]) + let ccList = listCCnames().join(", ") + localError(conf, info, "unknown C compiler: '$1'. Available options are: $2" % [ccname, ccList]) conf.compileOptions = getConfigVar(conf, conf.cCompiler, ".options.always") conf.linkOptions = "" conf.cCompilerPath = getConfigVar(conf, conf.cCompiler, ".path") - for c in CC: undefSymbol(conf.symbols, c.name) + for i in low(CC)..high(CC): undefSymbol(conf.symbols, CC[i].name) defineSymbol(conf.symbols, CC[conf.cCompiler].name) proc addOpt(dest: var string, src: string) = @@ -365,7 +452,7 @@ proc addCompileOptionCmd*(conf: ConfigRef; option: string) = proc initVars*(conf: ConfigRef) = # we need to define the symbol here, because ``CC`` may have never been set! - for c in CC: undefSymbol(conf.symbols, c.name) + for i in low(CC)..high(CC): undefSymbol(conf.symbols, CC[i].name) defineSymbol(conf.symbols, CC[conf.cCompiler].name) addCompileOption(conf, getConfigVar(conf, conf.cCompiler, ".options.always")) #addLinkOption(getConfigVar(cCompiler, ".options.linker")) @@ -374,7 +461,6 @@ proc initVars*(conf: ConfigRef) = proc completeCfilePath*(conf: ConfigRef; cfile: AbsoluteFile, createSubDir: bool = true): AbsoluteFile = - ## Generate the absolute file path to the generated modules. result = completeGeneratedFilePath(conf, cfile, createSubDir) proc toObjFile*(conf: ConfigRef; filename: AbsoluteFile): AbsoluteFile = @@ -385,7 +471,7 @@ proc addFileToCompile*(conf: ConfigRef; cf: Cfile) = conf.toCompile.add(cf) proc addLocalCompileOption*(conf: ConfigRef; option: string; nimfile: AbsoluteFile) = - let key = completeCfilePath(conf, mangleModuleName(conf, nimfile).AbsoluteFile).string + let key = completeCfilePath(conf, withPackageName(conf, nimfile)).string var value = conf.cfileSpecificOptions.getOrDefault(key) if strutils.find(value, option, 0) < 0: addOpt(value, option) @@ -403,7 +489,7 @@ proc addExternalFileToLink*(conf: ConfigRef; filename: AbsoluteFile) = conf.externalToLink.insert(filename.string, 0) proc execWithEcho(conf: ConfigRef; cmd: string, msg = hintExecuting): int = - rawMessage(conf, msg, if msg == hintLinking and not(optListCmd in conf.globalOptions or conf.verbosity > 1): "" else: cmd) + rawMessage(conf, msg, cmd) result = execCmd(cmd) proc execExternalProgram*(conf: ConfigRef; cmd: string, msg = hintExecuting) = @@ -438,16 +524,11 @@ proc noAbsolutePaths(conf: ConfigRef): bool {.inline.} = # really: Cross compilation from Linux to Linux for example is entirely # reasonable. # `optGenMapping` is included here for niminst. - # We use absolute paths for vcc / cl, see issue #19883. - let options = - if conf.cCompiler == ccVcc: - {optGenMapping} - else: - {optGenScript, optGenMapping} - result = conf.globalOptions * options != {} + result = conf.globalOptions * {optGenScript, optGenMapping} != {} proc cFileSpecificOptions(conf: ConfigRef; nimname, fullNimFile: string): string = result = conf.compileOptions + addOpt(result, conf.cfileSpecificOptions.getOrDefault(fullNimFile)) for option in conf.compileOptionsCmd: if strutils.find(result, option, 0) < 0: @@ -468,15 +549,13 @@ proc cFileSpecificOptions(conf: ConfigRef; nimname, fullNimFile: string): string let key = nimname & ".always" if existsConfigVar(conf, key): addOpt(result, getConfigVar(conf, key)) - addOpt(result, conf.cfileSpecificOptions.getOrDefault(fullNimFile)) - proc getCompileOptions(conf: ConfigRef): string = result = cFileSpecificOptions(conf, "__dummy__", "__dummy__") proc vccplatform(conf: ConfigRef): string = # VCC specific but preferable over the config hacks people # had to do before, see #11306 - if conf.cCompiler == ccVcc: + if conf.cCompiler == ccVcc: let exe = getConfigVar(conf, conf.cCompiler, ".exe") if "vccexe.exe" == extractFilename(exe): result = case conf.target.targetCPU @@ -496,79 +575,35 @@ proc needsExeExt(conf: ConfigRef): bool {.inline.} = result = (optGenScript in conf.globalOptions and conf.target.targetOS == osWindows) or (conf.target.hostOS == osWindows) -proc useCpp(conf: ConfigRef; cfile: AbsoluteFile): bool = - # List of possible file extensions taken from gcc - for ext in [".C", ".cc", ".cpp", ".CPP", ".c++", ".cp", ".cxx"]: - if cfile.string.endsWith(ext): return true - false - -proc envFlags(conf: ConfigRef): string = - result = if conf.backend == backendCpp: - getEnv("CXXFLAGS") - else: - getEnv("CFLAGS") - -proc getCompilerExe(conf: ConfigRef; compiler: TSystemCC; isCpp: bool): string = - if compiler == ccEnv: - result = if isCpp: - getEnv("CXX") - else: - getEnv("CC") - else: - result = if isCpp: - CC[compiler].cppCompiler - else: - CC[compiler].compilerExe +proc getCompilerExe(conf: ConfigRef; compiler: TSystemCC; cfile: AbsoluteFile): string = + result = if conf.cmd == cmdCompileToCpp and not cfile.string.endsWith(".c"): + CC[compiler].cppCompiler + else: + CC[compiler].compilerExe if result.len == 0: rawMessage(conf, errGenerated, "Compiler '$1' doesn't support the requested target" % CC[compiler].name) -proc ccHasSaneOverflow*(conf: ConfigRef): bool = - if conf.cCompiler == ccGcc: - result = false # assume an old or crappy GCC - 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) - if exitCode == 0: - var major: int - discard parseInt(s, major) - result = major >= 5 - else: - result = conf.cCompiler == ccCLang - proc getLinkerExe(conf: ConfigRef; compiler: TSystemCC): string = result = if CC[compiler].linkerExe.len > 0: CC[compiler].linkerExe - else: getCompilerExe(conf, compiler, optMixedMode in conf.globalOptions or conf.backend == backendCpp) + elif optMixedMode in conf.globalOptions and conf.cmd != cmdCompileToCpp: CC[compiler].cppCompiler + else: getCompilerExe(conf, compiler, AbsoluteFile"") proc getCompileCFileCmd*(conf: ConfigRef; cfile: Cfile, isMainFile = false; produceOutput = false): string = - let - c = conf.cCompiler - isCpp = useCpp(conf, cfile.cname) + let c = conf.cCompiler # We produce files like module.nim.cpp, so the absolute Nim filename is not # cfile.name but `cfile.cname.changeFileExt("")`: var options = cFileSpecificOptions(conf, cfile.nimname, cfile.cname.changeFileExt("").string) - if isCpp: - # needs to be prepended so that --passc:-std=c++17 can override default. - # we could avoid allocation by making cFileSpecificOptions inplace - options = CC[c].cppXsupport & ' ' & options - # If any C++ file was compiled, we need to use C++ driver for linking as well - incl conf.globalOptions, optMixedMode - var exe = getConfigVar(conf, c, ".exe") - if exe.len == 0: exe = getCompilerExe(conf, c, isCpp) + if exe.len == 0: exe = getCompilerExe(conf, c, cfile.cname) if needsExeExt(conf): exe = addFileExt(exe, "exe") if (optGenDynLib in conf.globalOptions or (conf.hcrOn and not isMainFile)) and ospNeedsPIC in platform.OS[conf.target.targetOS].props: options.add(' ' & CC[c].pic) - if cfile.customArgs != "": - options.add ' ' - options.add cfile.customArgs - var compilePattern: string # compute include paths: var includeCmd = CC[c].includeCmd & quoteShell(conf.libpath) @@ -578,16 +613,16 @@ proc getCompileCFileCmd*(conf: ConfigRef; cfile: Cfile, compilePattern = joinPath(conf.cCompilerPath, exe) else: - compilePattern = getCompilerExe(conf, c, isCpp) + compilePattern = getCompilerExe(conf, c, cfile.cname) includeCmd.add(join([CC[c].includeCmd, quoteShell(conf.projectPath.string)])) - let cf = if noAbsolutePaths(conf): AbsoluteFile extractFilename(cfile.cname.string) + var cf = if noAbsolutePaths(conf): AbsoluteFile extractFilename(cfile.cname.string) else: cfile.cname - let objfile = + var objfile = if cfile.obj.isEmpty: - if CfileFlag.External notin cfile.flags or noAbsolutePaths(conf): + if not cfile.flags.contains(CfileFlag.External) or noAbsolutePaths(conf): toObjFile(conf, cf).string else: completeCfilePath(conf, toObjFile(conf, cf)).string @@ -605,8 +640,7 @@ proc getCompileCFileCmd*(conf: ConfigRef; cfile: Cfile, "dfile", dfile, "file", cfsh, "objfile", quoteShell(objfile), "options", options, "include", includeCmd, "nim", getPrefixDir(conf).string, - "lib", conf.libpath.string, - "ccenvflags", envFlags(conf)]) + "lib", conf.libpath.string]) if optProduceAsm in conf.globalOptions: if CC[conf.cCompiler].produceAsm.len > 0: @@ -620,14 +654,13 @@ proc getCompileCFileCmd*(conf: ConfigRef; cfile: Cfile, "for the selected C compiler: " & CC[conf.cCompiler].name) result.add(' ') - strutils.addf(result, CC[c].compileTmpl, [ + result.addf(CC[c].compileTmpl, [ "dfile", dfile, "file", cfsh, "objfile", quoteShell(objfile), "options", options, "include", includeCmd, "nim", quoteShell(getPrefixDir(conf)), "lib", quoteShell(conf.libpath), - "vccplatform", vccplatform(conf), - "ccenvflags", envFlags(conf)]) + "vccplatform", vccplatform(conf)]) proc footprint(conf: ConfigRef; cfile: Cfile): SecureHash = result = secureHash( @@ -638,10 +671,11 @@ proc footprint(conf: ConfigRef; cfile: Cfile): SecureHash = getCompileCFileCmd(conf, cfile)) proc externalFileChanged(conf: ConfigRef; cfile: Cfile): bool = - if conf.backend == backendJs: return false # pre-existing behavior, but not sure it's good + if conf.cmd notin {cmdCompileToC, cmdCompileToCpp, cmdCompileToOC, cmdCompileToLLVM, cmdNone}: + return false - let hashFile = toGeneratedFile(conf, conf.mangleModuleName(cfile.cname).AbsoluteFile, "sha1") - let currentHash = footprint(conf, cfile) + var hashFile = toGeneratedFile(conf, conf.withPackageName(cfile.cname), "sha1") + var currentHash = footprint(conf, cfile) var f: File if open(f, hashFile.string, fmRead): let oldHash = parseSecureHash(f.readLine()) @@ -655,10 +689,8 @@ proc externalFileChanged(conf: ConfigRef; cfile: Cfile): bool = close(f) proc addExternalFileToCompile*(conf: ConfigRef; c: var Cfile) = - # we want to generate the hash file unconditionally - let extFileChanged = externalFileChanged(conf, c) if optForceFullMake notin conf.globalOptions and fileExists(c.obj) and - not extFileChanged: + not externalFileChanged(conf, c): c.flags.incl CfileFlag.Cached else: # make sure Nim keeps recompiling the external file on reruns @@ -672,14 +704,34 @@ proc addExternalFileToCompile*(conf: ConfigRef; filename: AbsoluteFile) = flags: {CfileFlag.External}) addExternalFileToCompile(conf, c) +proc compileCFiles(conf: ConfigRef; list: CfileList, script: var Rope, cmds: var TStringSeq, + prettyCmds: var TStringSeq) = + var currIdx = 0 + for it in list: + # call the C compiler for the .c file: + if it.flags.contains(CfileFlag.Cached): continue + var compileCmd = getCompileCFileCmd(conf, it, currIdx == list.len - 1, produceOutput=true) + inc currIdx + if optCompileOnly notin conf.globalOptions: + cmds.add(compileCmd) + let (_, name, _) = splitFile(it.cname) + prettyCmds.add(if hintCC in conf.notes: "CC: " & demanglePackageName(name) else: "") + if optGenScript in conf.globalOptions: + script.add(compileCmd) + script.add("\n") + proc getLinkCmd(conf: ConfigRef; output: AbsoluteFile, - objfiles: string, isDllBuild: bool, removeStaticFile: bool): string = + objfiles: string, isDllBuild: bool): string = if optGenStaticLib in conf.globalOptions: - if removeStaticFile: - removeFile output # fixes: bug #16947 - result = CC[conf.cCompiler].buildLib % ["libfile", quoteShell(output), - "objfiles", objfiles, - "vccplatform", vccplatform(conf)] + var libname: string + if not conf.outFile.isEmpty: + libname = conf.outFile.string.expandTilde + if not libname.isAbsolute(): + libname = getCurrentDir() / libname + else: + libname = (libNameTmpl(conf) % splitFile(conf.projectName).name) + result = CC[conf.cCompiler].buildLib % ["libfile", quoteShell(libname), + "objfiles", objfiles] else: var linkerExe = getConfigVar(conf, conf.cCompiler, ".linkerexe") if linkerExe.len == 0: linkerExe = getLinkerExe(conf, conf.cCompiler) @@ -712,7 +764,7 @@ proc getLinkCmd(conf: ConfigRef; output: AbsoluteFile, "buildgui", buildgui, "options", linkOptions, "objfiles", objfiles, "exefile", exefile, "nim", getPrefixDir(conf).string, "lib", conf.libpath.string]) result.add ' ' - strutils.addf(result, linkTmpl, ["builddll", builddll, + result.addf(linkTmpl, ["builddll", builddll, "mapfile", mapfile, "buildgui", buildgui, "options", linkOptions, "objfiles", objfiles, "exefile", exefile, @@ -760,9 +812,8 @@ proc getLinkCmd(conf: ConfigRef; output: AbsoluteFile, if optCDebug in conf.globalOptions and conf.cCompiler == ccVcc: result.add " /Zi /FS /Od" -template getLinkCmd(conf: ConfigRef; output: AbsoluteFile, objfiles: string, - removeStaticFile = false): string = - getLinkCmd(conf, output, objfiles, optGenDynLib in conf.globalOptions, removeStaticFile) +template getLinkCmd(conf: ConfigRef; output: AbsoluteFile, objfiles: string): string = + getLinkCmd(conf, output, objfiles, optGenDynLib in conf.globalOptions) template tryExceptOSErrorMessage(conf: ConfigRef; errorPrefix: string = "", body: untyped) = try: @@ -776,22 +827,26 @@ template tryExceptOSErrorMessage(conf: ConfigRef; errorPrefix: string = "", body (ose.msg & " " & $ose.errorCode)) raise -proc getExtraCmds(conf: ConfigRef; output: AbsoluteFile): seq[string] = - when defined(macosx): - if optCDebug in conf.globalOptions and optGenStaticLib notin conf.globalOptions: - # if needed, add an option to skip or override location - result.add "dsymutil " & $(output).quoteShell - proc execLinkCmd(conf: ConfigRef; linkCmd: string) = tryExceptOSErrorMessage(conf, "invocation of external linker program failed."): execExternalProgram(conf, linkCmd, hintLinking) +proc maybeRunDsymutil(conf: ConfigRef; exe: AbsoluteFile) = + when defined(osx): + if optCDebug notin conf.globalOptions: return + # if needed, add an option to skip or override location + let cmd = "dsymutil " & $(exe).quoteShell + conf.extraCmds.add cmd + tryExceptOSErrorMessage(conf, "invocation of dsymutil failed."): + execExternalProgram(conf, cmd, hintExecuting) + proc execCmdsInParallel(conf: ConfigRef; cmds: seq[string]; prettyCb: proc (idx: int)) = let runCb = proc (idx: int, p: Process) = let exitCode = p.peekExitCode if exitCode != 0: rawMessage(conf, errGenerated, "execution of an external compiler program '" & - cmds[idx] & "' failed with exit code: " & $exitCode & "\n\n") + cmds[idx] & "' failed with exit code: " & $exitCode & "\n\n" & + p.outputStream.readAll.strip) if conf.numberOfProcessors == 0: conf.numberOfProcessors = countProcessors() var res = 0 if conf.numberOfProcessors <= 1: @@ -803,8 +858,15 @@ proc execCmdsInParallel(conf: ConfigRef; cmds: seq[string]; prettyCb: proc (idx: cmds[i]) else: tryExceptOSErrorMessage(conf, "invocation of external compiler program failed."): - res = execProcesses(cmds, {poStdErrToStdOut, poUsePath, poParentStreams}, + if optListCmd in conf.globalOptions or conf.verbosity > 1: + res = execProcesses(cmds, {poEchoCmd, poStdErrToStdOut, poUsePath}, + conf.numberOfProcessors, afterRunEvent=runCb) + elif conf.verbosity == 1: + res = execProcesses(cmds, {poStdErrToStdOut, poUsePath}, conf.numberOfProcessors, prettyCb, afterRunEvent=runCb) + else: + res = execProcesses(cmds, {poStdErrToStdOut, poUsePath}, + conf.numberOfProcessors, afterRunEvent=runCb) if res != 0: if conf.numberOfProcessors <= 1: rawMessage(conf, errGenerated, "execution of an external program failed: '$1'" % @@ -836,15 +898,6 @@ proc linkViaResponseFile(conf: ConfigRef; cmd: string) = 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 @@ -855,51 +908,21 @@ proc hcrLinkTargetName(conf: ConfigRef, objFile: string, isMain = false): Absolu else: platform.OS[conf.target.targetOS].dllFrmt % basename result = conf.getNimcacheDir / RelativeFile(targetName) -proc displayProgressCC(conf: ConfigRef, path, compileCmd: string): string = - if conf.hasHint(hintCC): - if optListCmd in conf.globalOptions or conf.verbosity > 1: - result = MsgKindToStr[hintCC] % (demangleModuleName(path.splitFile.name) & ": " & compileCmd) - 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 - extraCmds: seq[string] if conf.globalOptions * {optCompileOnly, optGenScript} == {optCompileOnly}: return # speed up that call if only compiling and no script shall be # generated #var c = cCompiler - var script: Rope = "" - var cmds: TStringSeq - var prettyCmds: TStringSeq - let prettyCb = proc (idx: int) = writePrettyCmdsStderr(prettyCmds[idx]) - - for idx, it in conf.toCompile: - # call the C compiler for the .c file: - if CfileFlag.Cached in it.flags: continue - let compileCmd = getCompileCFileCmd(conf, it, idx == conf.toCompile.len - 1, produceOutput=true) - if optCompileOnly notin conf.globalOptions: - cmds.add(compileCmd) - prettyCmds.add displayProgressCC(conf, $it.cname, compileCmd) - if optGenScript in conf.globalOptions: - script.add(compileCmd) - script.add("\n") - + var script: Rope = nil + var cmds: TStringSeq = @[] + var prettyCmds: TStringSeq = @[] + let prettyCb = proc (idx: int) = + when declared(echo): + let cmd = prettyCmds[idx] + if cmd != "": echo cmd + compileCFiles(conf, conf.toCompile, script, cmds, prettyCmds) if optCompileOnly notin conf.globalOptions: execCmdsInParallel(conf, cmds, prettyCb) if optNoLinking notin conf.globalOptions: @@ -918,14 +941,14 @@ proc callCCompiler*(conf: ConfigRef) = # don't relink each of the many binaries (one for each source file) if the nim code is # cached because that would take too much time for small changes - the only downside to # this is that if an external-to-link file changes the final target wouldn't be relinked - if CfileFlag.Cached in x.flags: continue + if x.flags.contains(CfileFlag.Cached): continue # we pass each object file as if it is the project file - a .dll will be created for each such # object file in the nimcache directory, and only in the case of the main project file will # there be probably an executable (if the project is such) which will be copied out of the nimcache let objFile = conf.getObjFilePath(x) let buildDll = idx != mainFileIdx let linkTarget = conf.hcrLinkTargetName(objFile, not buildDll) - cmds.add(getLinkCmd(conf, linkTarget, objfiles & " " & quoteShell(objFile), buildDll, removeStaticFile = true)) + cmds.add(getLinkCmd(conf, linkTarget, objfiles & " " & quoteShell(objFile), buildDll)) # try to remove all .pdb files for the current binary so they don't accumulate endlessly in the nimcache # for more info check the comment inside of getLinkCmd() where the /PDB: MSVC flag is used if isVSCompatible(conf): @@ -936,10 +959,10 @@ proc callCCompiler*(conf: ConfigRef) = prettyCmds = map(prettyCmds, proc (curr: string): string = return curr.replace("CC", "Link")) execCmdsInParallel(conf, cmds, prettyCb) # only if not cached - copy the resulting main file from the nimcache folder to its originally intended destination - if CfileFlag.Cached notin conf.toCompile[mainFileIdx].flags: + if not conf.toCompile[mainFileIdx].flags.contains(CfileFlag.Cached): let mainObjFile = getObjFilePath(conf, conf.toCompile[mainFileIdx]) - let src = conf.hcrLinkTargetName(mainObjFile, true) - let dst = conf.prepareToWriteOutput + var src = conf.hcrLinkTargetName(mainObjFile, true) + var dst = conf.prepareToWriteOutput copyFileWithPermissions(src.string, dst.string) else: for x in conf.toCompile: @@ -947,14 +970,18 @@ proc callCCompiler*(conf: ConfigRef) = objfiles.add(' ') objfiles.add(quoteShell(objFile)) let mainOutput = if optGenScript notin conf.globalOptions: conf.prepareToWriteOutput - else: AbsoluteFile(conf.outFile) - - linkCmd = getLinkCmd(conf, mainOutput, objfiles, removeStaticFile = true) - extraCmds = getExtraCmds(conf, mainOutput) + else: AbsoluteFile(conf.projectName) + linkCmd = getLinkCmd(conf, mainOutput, objfiles) if optCompileOnly notin conf.globalOptions: - preventLinkCmdMaxCmdLen(conf, linkCmd) - for cmd in extraCmds: - execExternalProgram(conf, cmd, hintExecuting) + 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) + maybeRunDsymutil(conf, mainOutput) else: linkCmd = "" if optGenScript in conf.globalOptions: @@ -962,99 +989,166 @@ proc callCCompiler*(conf: ConfigRef) = script.add("\n") generateScript(conf, script) +#from json import escapeJson +import json, std / sha1 + template hashNimExe(): string = $secureHashFile(os.getAppFilename()) -proc jsonBuildInstructionsFile*(conf: ConfigRef): AbsoluteFile = - # `outFile` is better than `projectName`, as it allows having different json - # files for a given source file compiled with different options; it also - # works out of the box with `hashMainCompilationParams`. - result = getNimcacheDir(conf) / conf.outFile.changeFileExt("json") - -const cacheVersion = "D20210525T193831" # update when `BuildCache` spec changes -type BuildCache = object - cacheVersion: string - outputFile: string - compile: seq[(string, string)] - link: seq[string] - linkcmd: string - extraCmds: seq[string] - configFiles: seq[string] # the hash shouldn't be needed - stdinInput: bool - projectIsCmd: bool - cmdInput: string - currentDir: string - cmdline: string - depfiles: seq[(string, string)] - nimexe: string - proc writeJsonBuildInstructions*(conf: ConfigRef) = - var linkFiles = collect(for it in conf.externalToLink: - var it = it - if conf.noAbsolutePaths: it = it.extractFilename - it.addFileExt(CC[conf.cCompiler].objExt)) - for it in conf.toCompile: linkFiles.add it.obj.string - var bcache = BuildCache( - cacheVersion: cacheVersion, - outputFile: conf.absOutFile.string, - compile: collect(for i, it in conf.toCompile: - if CfileFlag.Cached notin it.flags: (it.cname.string, getCompileCFileCmd(conf, it))), - link: linkFiles, - linkcmd: getLinkCmd(conf, conf.absOutFile, linkFiles.quoteShellCommand), - extraCmds: getExtraCmds(conf, conf.absOutFile), - stdinInput: conf.projectIsStdin, - projectIsCmd: conf.projectIsCmd, - cmdInput: conf.cmdInput, - configFiles: conf.configFiles.mapIt(it.string), - currentDir: getCurrentDir()) - if optRun in conf.globalOptions or isDefined(conf, "nimBetterRun"): - bcache.cmdline = conf.commandLine - bcache.depfiles = collect(for it in conf.m.fileInfos: + template lit(x: untyped) = f.write x + template str(x: untyped) = + when compiles(escapeJson(x, buf)): + buf.setLen 0 + escapeJson(x, buf) + f.write buf + else: + f.write escapeJson(x) + + proc cfiles(conf: ConfigRef; f: File; buf: var string; clist: CfileList, isExternal: bool) = + var i = 0 + for it in clist: + if CfileFlag.Cached in it.flags: continue + let compileCmd = getCompileCFileCmd(conf, it) + if i > 0: lit ",\L" + lit "[" + str it.cname.string + lit ", " + str compileCmd + lit "]" + inc i + + proc linkfiles(conf: ConfigRef; f: File; buf, objfiles: var string; clist: CfileList; + llist: seq[string]) = + var pastStart = false + for it in llist: + let objfile = if noAbsolutePaths(conf): it.extractFilename + else: it + let objstr = addFileExt(objfile, CC[conf.cCompiler].objExt) + objfiles.add(' ') + objfiles.add(objstr) + if pastStart: lit ",\L" + str objstr + pastStart = true + + for it in clist: + let objstr = quoteShell(it.obj) + objfiles.add(' ') + objfiles.add(objstr) + if pastStart: lit ",\L" + str objstr + pastStart = true + lit "\L" + + proc depfiles(conf: ConfigRef; f: File) = + var i = 0 + for it in conf.m.fileInfos: let path = it.fullPath.string if isAbsolute(path): # TODO: else? - (path, $secureHashFile(path))) - bcache.nimexe = hashNimExe() - conf.jsonBuildFile = conf.jsonBuildInstructionsFile - conf.jsonBuildFile.string.writeFile(bcache.toJson.pretty) + if i > 0: lit "],\L" + lit "[" + str path + lit ", " + str $secureHashFile(path) + inc i + lit "]\L" -proc changeDetectedViaJsonBuildInstructions*(conf: ConfigRef; jsonFile: AbsoluteFile): bool = - if not fileExists(jsonFile) or not fileExists(conf.absOutFile): return true - var bcache: BuildCache - try: bcache.fromJson(jsonFile.string.parseFile) + + var buf = newStringOfCap(50) + + let jsonFile = conf.getNimcacheDir / RelativeFile(conf.projectName & ".json") + + var f: File + if open(f, jsonFile.string, fmWrite): + lit "{\"compile\":[\L" + cfiles(conf, f, buf, conf.toCompile, false) + lit "],\L\"link\":[\L" + var objfiles = "" + # XXX add every file here that is to link + linkfiles(conf, f, buf, objfiles, conf.toCompile, conf.externalToLink) + + lit "],\L\"linkcmd\": " + str getLinkCmd(conf, conf.absOutFile, objfiles) + + lit ",\L\"extraCmds\": " + lit $(%* conf.extraCmds) + + if optRun in conf.globalOptions or isDefined(conf, "nimBetterRun"): + lit ",\L\"cmdline\": " + str conf.commandLine + lit ",\L\"depfiles\":[\L" + depfiles(conf, f) + lit "],\L\"nimexe\": \L" + str hashNimExe() + lit "\L" + + lit "\L}\L" + close(f) + +proc changeDetectedViaJsonBuildInstructions*(conf: ConfigRef; projectfile: AbsoluteFile): bool = + let jsonFile = toGeneratedFile(conf, projectfile, "json") + if not fileExists(jsonFile): return true + if not fileExists(conf.absOutFile): return true + result = false + try: + let data = json.parseFile(jsonFile.string) + if not data.hasKey("depfiles") or not data.hasKey("cmdline"): + return true + let oldCmdLine = data["cmdline"].getStr + if conf.commandLine != oldCmdLine: + return true + if hashNimExe() != data["nimexe"].getStr: + return true + let depfilesPairs = data["depfiles"] + doAssert depfilesPairs.kind == JArray + for p in depfilesPairs: + doAssert p.kind == JArray + # >= 2 for forwards compatibility with potential later .json files: + doAssert p.len >= 2 + let depFilename = p[0].getStr + let oldHashValue = p[1].getStr + let newHashValue = $secureHashFile(depFilename) + if oldHashValue != newHashValue: + return true except IOError, OSError, ValueError: - stderr.write "Warning: JSON processing failed for: $#\n" % jsonFile.string - return true - if bcache.currentDir != getCurrentDir() or # fixes bug #16271 - bcache.configFiles != conf.configFiles.mapIt(it.string) or - bcache.cacheVersion != cacheVersion or bcache.outputFile != conf.absOutFile.string or - bcache.cmdline != conf.commandLine or bcache.nimexe != hashNimExe() or - bcache.projectIsCmd != conf.projectIsCmd or conf.cmdInput != bcache.cmdInput: return true - if bcache.stdinInput or conf.projectIsStdin: return true - # xxx optimize by returning false if stdin input was the same - for (file, hash) in bcache.depfiles: - if $secureHashFile(file) != hash: return true + echo "Warning: JSON processing failed: ", getCurrentExceptionMsg() + result = true -proc runJsonBuildInstructions*(conf: ConfigRef; jsonFile: AbsoluteFile) = - var bcache: BuildCache - try: bcache.fromJson(jsonFile.string.parseFile) - except ValueError, KeyError, JsonKindError: - let e = getCurrentException() - conf.quitOrRaise "\ncaught exception:\n$#\nstacktrace:\n$#error evaluating JSON file: $#" % - [e.msg, e.getStackTrace(), jsonFile.string] - let output = bcache.outputFile - createDir output.parentDir - let outputCurrent = $conf.absOutFile - if output != outputCurrent or bcache.cacheVersion != cacheVersion: - globalError(conf, gCmdLineInfo, - "jsonscript command outputFile '$1' must match '$2' which was specified during --compileOnly, see \"outputFile\" entry in '$3' " % - [outputCurrent, output, jsonFile.string]) - var cmds, prettyCmds: TStringSeq - let prettyCb = proc (idx: int) = writePrettyCmdsStderr(prettyCmds[idx]) - for (name, cmd) in bcache.compile: - cmds.add cmd - prettyCmds.add displayProgressCC(conf, name, cmd) - execCmdsInParallel(conf, cmds, prettyCb) - preventLinkCmdMaxCmdLen(conf, bcache.linkcmd) - for cmd in bcache.extraCmds: execExternalProgram(conf, cmd, hintExecuting) +proc runJsonBuildInstructions*(conf: ConfigRef; projectfile: AbsoluteFile) = + let jsonFile = toGeneratedFile(conf, projectfile, "json") + try: + let data = json.parseFile(jsonFile.string) + let toCompile = data["compile"] + doAssert toCompile.kind == JArray + var cmds: TStringSeq = @[] + var prettyCmds: TStringSeq = @[] + for c in toCompile: + doAssert c.kind == JArray + doAssert c.len >= 2 + + cmds.add(c[1].getStr) + let (_, name, _) = splitFile(c[0].getStr) + prettyCmds.add("CC: " & demanglePackageName(name)) + + let prettyCb = proc (idx: int) = + when declared(echo): + echo prettyCmds[idx] + execCmdsInParallel(conf, cmds, prettyCb) + + let linkCmd = data["linkcmd"] + doAssert linkCmd.kind == JString + execLinkCmd(conf, linkCmd.getStr) + if data.hasKey("extraCmds"): + let extraCmds = data["extraCmds"] + doAssert extraCmds.kind == JArray + for cmd in extraCmds: + doAssert cmd.kind == JString, $cmd.kind + let cmd2 = cmd.getStr + execExternalProgram(conf, cmd2, hintExecuting) + + except: + when declared(echo): + echo getCurrentException().getStackTrace() + quit "error evaluating JSON file: " & jsonFile.string proc genMappingFiles(conf: ConfigRef; list: CfileList): Rope = for it in list: diff --git a/compiler/filter_tmpl.nim b/compiler/filter_tmpl.nim index 84ed99164..1d95369a8 100644 --- a/compiler/filter_tmpl.nim +++ b/compiler/filter_tmpl.nim @@ -22,7 +22,7 @@ type info: TLineInfo indent, emitPar: int x: string # the current input line - outp: PLLStream # the output will be parsed by parser + outp: PLLStream # the output will be parsed by pnimsyn subsChar, nimDirective: char emit, conc, toStr: string curly, bracket, par: int @@ -199,8 +199,8 @@ proc parseLine(p: var TTmplParser) = inc(j) llStreamWrite(p.outp, "\\n\"") -proc filterTmpl*(conf: ConfigRef, stdin: PLLStream, filename: AbsoluteFile, - call: PNode): PLLStream = +proc filterTmpl*(stdin: PLLStream, filename: AbsoluteFile, + call: PNode; conf: ConfigRef): PLLStream = var p: TTmplParser p.config = conf p.info = newLineInfo(conf, filename, 0, 0) @@ -214,9 +214,9 @@ proc filterTmpl*(conf: ConfigRef, stdin: PLLStream, filename: AbsoluteFile, p.x = newStringOfCap(120) # do not process the first line which contains the directive: if llStreamReadLine(p.inp, p.x): - inc p.info.line + p.info.line = p.info.line + 1'u16 while llStreamReadLine(p.inp, p.x): - inc p.info.line + p.info.line = p.info.line + 1'u16 parseLine(p) newLine(p) result = p.outp diff --git a/compiler/forloops.nim b/compiler/forloops.nim new file mode 100644 index 000000000..d857b3c51 --- /dev/null +++ b/compiler/forloops.nim @@ -0,0 +1,89 @@ +# +# +# The Nim Compiler +# (c) Copyright 2015 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +## This module implements for loop detection for better C code generation. + +import ast, astalgo + +const + someCmp = {mEqI, mEqF64, mEqEnum, mEqCh, mEqB, mEqRef, mEqProc, + mEqUntracedRef, mLeI, mLeF64, mLeU, mLeU64, mLeEnum, + mLeCh, mLeB, mLePtr, mLtI, mLtF64, mLtU, mLtU64, mLtEnum, + mLtCh, mLtB, mLtPtr} + +proc isCounter(s: PSym): bool {.inline.} = + s.kind in {skResult, skVar, skLet, skTemp} and + {sfGlobal, sfAddrTaken} * s.flags == {} + +proc isCall(n: PNode): bool {.inline.} = + n.kind in nkCallKinds and n[0].kind == nkSym + +proc fromSystem(op: PSym): bool = sfSystemModule in getModule(op).flags + +proc getCounter(lastStmt: PNode): PSym = + if lastStmt.isCall: + let op = lastStmt.sym + if op.magic in {mDec, mInc} or + ((op.name.s == "+=" or op.name.s == "-=") and op.fromSystem): + if op[1].kind == nkSym and isCounter(op[1].sym): + result = op[1].sym + +proc counterInTree(n, loop: PNode; counter: PSym): bool = + # prune the search tree: within the loop the counter may be used: + if n == loop: return + case n.kind + of nkSym: + if n.sym == counter: return true + of nkVarSection, nkLetSection: + # definitions are fine! + for it in n: + if counterInTree(it.lastSon): return true + else: + for i in 0..= 1: result = shallowCopy(n) for i in 0.. x + (-4) result = negate(result[1], result[2], result, o) of someLen: result[0] = o.opLen.newSymNode - of someLt - {mLtF64}: + of someLt: # x < y same as x <= y-1: let y = n[2].canon(o) let p = pred(y) @@ -303,12 +318,12 @@ proc canon*(n: PNode; o: Operators): PNode = if plus != nil and not isLetLocation(x, true): result = buildCall(result[0].sym, plus, y[1]) else: discard - elif x.isValue and y.getMagic in someAdd and y[2].kind == x.kind: + elif x.isValue and y.getMagic in someAdd and y[2].isValue: # 0 <= a.len + 3 # -3 <= a.len result[1] = x |-| y[2] result[2] = y[1] - elif x.isValue and y.getMagic in someSub and y[2].kind == x.kind: + elif x.isValue and y.getMagic in someSub and y[2].isValue: # 0 <= a.len - 3 # 3 <= a.len result[1] = x |+| y[2] @@ -328,8 +343,6 @@ proc usefulFact(n: PNode; o: Operators): PNode = if isLetLocation(n[1], true) or isLetLocation(n[2], true): # XXX algebraic simplifications! 'i-1 < a.len' --> 'i < a.len+1' result = n - elif n[1].getMagic in someLen or n[2].getMagic in someLen: - result = n of someLe+someLt: if isLetLocation(n[1], true) or isLetLocation(n[2], true): # XXX algebraic simplifications! 'i-1 < a.len' --> 'i < a.len+1' @@ -390,24 +403,14 @@ proc usefulFact(n: PNode; o: Operators): PNode = type TModel* = object s*: seq[PNode] # the "knowledge base" - g*: ModuleGraph - beSmart*: bool + o*: Operators proc addFact*(m: var TModel, nn: PNode) = - let n = usefulFact(nn, m.g.operators) - if n != nil: - if not m.beSmart: - m.s.add n - else: - let c = canon(n, m.g.operators) - if c.getMagic == mAnd: - addFact(m, c[1]) - addFact(m, c[2]) - else: - m.s.add c + let n = usefulFact(nn, m.o) + if n != nil: m.s.add n proc addFactNeg*(m: var TModel, n: PNode) = - let n = n.neg(m.g.operators) + let n = n.neg(m.o) if n != nil: addFact(m, n) proc sameOpr(a, b: PSym): bool = @@ -447,16 +450,10 @@ proc sameTree*(a, b: PNode): bool = proc hasSubTree(n, x: PNode): bool = if n.sameTree(x): result = true else: - case n.kind - of nkEmpty..nkNilLit: - result = n.sameTree(x) - of nkFormalParams: - discard - else: - for i in 0..= x - if b.getMagic in someAdd: - if zero() <=? b[2] and a <=? b[1]: return impYes - # x <= y-c if x+c <= y - if b[2] <=? zero() and (canon(m.g.operators.opSub.buildCall(a, b[2]), m.g.operators) <=? b[1]): - return impYes + if b.getMagic in someAdd and zero() <=? b[2] and a <=? b[1]: return impYes # x+c <= y if c <= 0 and x <= y if a.getMagic in someAdd and a[2] <=? zero() and a[1] <=? b: return impYes @@ -834,20 +826,20 @@ proc ple(m: TModel; a, b: PNode): TImplication = if a.getMagic in someMul and a[2].isValue and a[1].getMagic in someDiv and a[1][2].isValue: # simplify (x div 4) * 2 <= y to x div (c div d) <= y - if ple(m, buildCall(m.g.operators.opDiv, a[1][1], `|div|`(a[1][2], a[2])), b) == impYes: + if ple(m, buildCall(m.o.opDiv, a[1][1], `|div|`(a[1][2], a[2])), b) == impYes: return impYes # x*3 + x == x*4. It follows that: # x*3 + y <= x*4 if y <= x and 3 <= 4 if a =~ x*dc + y and b =~ x2*ec: if sameTree(x, x2): - let ec1 = m.g.operators.opAdd.buildCall(ec, minusOne()) + let ec1 = m.o.opAdd.buildCall(ec, minusOne()) if x >=? 1 and ec >=? 1 and dc >=? 1 and dc <=? ec1 and y <=? x: return impYes elif a =~ x*dc and b =~ x2*ec + y: #echo "BUG cam ehrer e ", a, " <=? ", b if sameTree(x, x2): - let ec1 = m.g.operators.opAdd.buildCall(ec, minusOne()) + let ec1 = m.o.opAdd.buildCall(ec, minusOne()) if x >=? 1 and ec >=? 1 and dc >=? 1 and dc <=? ec1 and y <=? zero(): return impYes @@ -910,13 +902,10 @@ proc pleViaModelRec(m: var TModel; a, b: PNode): TImplication = # --> true if (len-100) <= (len-1) let x = fact[1] let y = fact[2] - # x <= y. - # Question: x <= b? True iff y <= b. - if sameTree(x, a): - if ple(m, y, b) == impYes: return impYes - if y.getMagic in someAdd and b.getMagic in someAdd and sameTree(y[1], b[1]): - if ple(m, b[2], y[2]) == impYes: - return impYes + if sameTree(x, a) and y.getMagic in someAdd and b.getMagic in someAdd and + sameTree(y[1], b[1]): + if ple(m, b[2], y[2]) == impYes: + return impYes # x <= y implies a <= b if a <= x and y <= b if ple(m, a, x) == impYes: @@ -950,12 +939,12 @@ proc pleViaModel(model: TModel; aa, bb: PNode): TImplication = var b = bb if replacements.len > 0: m.s = @[] - m.g = model.g + m.o = model.o # make the other facts consistent: for fact in model.s: if fact != nil and fact.getMagic notin someEq: # XXX 'canon' should not be necessary here, but it is - m.s.add applyReplacements(fact, replacements).canon(m.g.operators) + m.s.add applyReplacements(fact, replacements).canon(m.o) a = applyReplacements(aa, replacements) b = applyReplacements(bb, replacements) else: @@ -964,25 +953,20 @@ proc pleViaModel(model: TModel; aa, bb: PNode): TImplication = result = pleViaModelRec(m, a, b) proc proveLe*(m: TModel; a, b: PNode): TImplication = - let x = canon(m.g.operators.opLe.buildCall(a, b), m.g.operators) + let x = canon(m.o.opLe.buildCall(a, b), m.o) #echo "ROOT ", renderTree(x[1]), " <=? ", renderTree(x[2]) result = ple(m, x[1], x[2]) if result == impUnknown: # try an alternative: a <= b iff not (b < a) iff not (b+1 <= a): - let y = canon(m.g.operators.opLe.buildCall(m.g.operators.opAdd.buildCall(b, one()), a), m.g.operators) + let y = canon(m.o.opLe.buildCall(m.o.opAdd.buildCall(b, one()), a), m.o) result = ~ple(m, y[1], y[2]) proc addFactLe*(m: var TModel; a, b: PNode) = - m.s.add canon(m.g.operators.opLe.buildCall(a, b), m.g.operators) - -proc addFactLt*(m: var TModel; a, b: PNode) = - let bb = m.g.operators.opAdd.buildCall(b, minusOne()) - addFactLe(m, a, bb) + m.s.add canon(m.o.opLe.buildCall(a, b), m.o) proc settype(n: PNode): PType = - result = newType(tySet, ItemId(module: -1, item: -1), n.typ.owner) - var idgen: IdGenerator - addSonSkipIntLit(result, n.typ, idgen) + result = newType(tySet, n.typ.owner) + addSonSkipIntLit(result, n.typ) proc buildOf(it, loc: PNode; o: Operators): PNode = var s = newNodeI(nkCurly, it.info, it.len-1) @@ -1008,14 +992,14 @@ proc buildElse(n: PNode; o: Operators): PNode = proc addDiscriminantFact*(m: var TModel, n: PNode) = var fact = newNodeI(nkCall, n.info, 3) - fact[0] = newSymNode(m.g.operators.opEq) + fact[0] = newSymNode(m.o.opEq) fact[1] = n[0] fact[2] = n[1] m.s.add fact proc addAsgnFact*(m: var TModel, key, value: PNode) = var fact = newNodeI(nkCall, key.info, 3) - fact[0] = newSymNode(m.g.operators.opEq) + fact[0] = newSymNode(m.o.opEq) fact[1] = key fact[2] = value m.s.add fact @@ -1031,7 +1015,7 @@ proc sameSubexprs*(m: TModel; a, b: PNode): bool = # However, nil checking requires exactly the same mechanism! But for now # we simply use sameTree and live with the unsoundness of the analysis. var check = newNodeI(nkCall, a.info, 3) - check[0] = newSymNode(m.g.operators.opEq) + check[0] = newSymNode(m.o.opEq) check[1] = a check[2] = b result = m.doesImply(check) == impYes @@ -1039,9 +1023,9 @@ proc sameSubexprs*(m: TModel; a, b: PNode): bool = proc addCaseBranchFacts*(m: var TModel, n: PNode, i: int) = let branch = n[i] if branch.kind == nkOfBranch: - m.s.add buildOf(branch, n[0], m.g.operators) + m.s.add buildOf(branch, n[0], m.o) else: - m.s.add n.buildElse(m.g.operators).neg(m.g.operators) + m.s.add n.buildElse(m.o).neg(m.o) proc buildProperFieldCheck(access, check: PNode; o: Operators): PNode = if check[1].kind == nkCurly: @@ -1057,12 +1041,8 @@ proc buildProperFieldCheck(access, check: PNode; o: Operators): PNode = assert check.getMagic == mNot result = buildProperFieldCheck(access, check[1], o).neg(o) -proc checkFieldAccess*(m: TModel, n: PNode; conf: ConfigRef; produceError: bool) = +proc checkFieldAccess*(m: TModel, n: PNode; conf: ConfigRef) = for i in 1.. '" & renderTree(result, {renderNoComments}) & "'") @@ -71,7 +67,7 @@ proc hlo(c: PContext, n: PNode): PNode = # already processed (special cases in semstmts.nim) result = n else: - if n.kind in {nkFastAsgn, nkAsgn, nkSinkAsgn, nkIdentDefs, nkVarTuple} and + if n.kind in {nkFastAsgn, nkAsgn, nkIdentDefs, nkVarTuple} and n[0].kind == nkSym and {sfGlobal, sfPure} * n[0].sym.flags == {sfGlobal, sfPure}: # do not optimize 'var g {.global} = re(...)' again! @@ -90,9 +86,9 @@ proc hlo(c: PContext, n: PNode): PNode = else: result = fitNode(c, n.typ, result, n.info) # optimization has been applied so check again: - result = commonOptimizations(c.graph, c.idgen, c.module, result) + result = commonOptimizations(c.graph, c.module, result) result = hlo(c, result) - result = commonOptimizations(c.graph, c.idgen, c.module, result) + result = commonOptimizations(c.graph, c.module, result) proc hloBody(c: PContext, n: PNode): PNode = # fast exit: diff --git a/compiler/ic/bitabs.nim b/compiler/ic/bitabs.nim deleted file mode 100644 index a55131051..000000000 --- a/compiler/ic/bitabs.nim +++ /dev/null @@ -1,171 +0,0 @@ -## A BiTable is a table that can be seen as an optimized pair -## of `(Table[LitId, Val], Table[Val, LitId])`. - -import hashes, rodfiles - -when defined(nimPreviewSlimSystem): - import std/assertions - -type - LitId* = distinct uint32 - - BiTable*[T] = object - vals: seq[T] # indexed by LitId - keys: seq[LitId] # indexed by hash(val) - -proc nextTry(h, maxHash: Hash): Hash {.inline.} = - result = (h + 1) and maxHash - -template maxHash(t): untyped = high(t.keys) -template isFilled(x: LitId): bool = x.uint32 > 0'u32 - -proc `$`*(x: LitId): string {.borrow.} -proc `<`*(x, y: LitId): bool {.borrow.} -proc `<=`*(x, y: LitId): bool {.borrow.} -proc `==`*(x, y: LitId): bool {.borrow.} -proc hash*(x: LitId): Hash {.borrow.} - - -proc len*[T](t: BiTable[T]): int = t.vals.len - -proc mustRehash(length, counter: int): bool {.inline.} = - assert(length > counter) - result = (length * 2 < counter * 3) or (length - counter < 4) - -const - idStart = 256 ## - ## Ids do not start with 0 but with this value. The IR needs it. - ## TODO: explain why - -template idToIdx(x: LitId): int = x.int - idStart - -proc hasLitId*[T](t: BiTable[T]; x: LitId): bool = - let idx = idToIdx(x) - result = idx >= 0 and idx < t.vals.len - -proc enlarge[T](t: var BiTable[T]) = - var n: seq[LitId] - newSeq(n, len(t.keys) * 2) - swap(t.keys, n) - for i in 0..high(n): - let eh = n[i] - if isFilled(eh): - var j = hash(t.vals[idToIdx eh]) and maxHash(t) - while isFilled(t.keys[j]): - j = nextTry(j, maxHash(t)) - t.keys[j] = move n[i] - -proc getKeyId*[T](t: BiTable[T]; v: T): LitId = - let origH = hash(v) - var h = origH and maxHash(t) - if t.keys.len != 0: - while true: - let litId = t.keys[h] - if not isFilled(litId): break - if t.vals[idToIdx t.keys[h]] == v: return litId - h = nextTry(h, maxHash(t)) - return LitId(0) - -proc getOrIncl*[T](t: var BiTable[T]; v: T): LitId = - let origH = hash(v) - var h = origH and maxHash(t) - if t.keys.len != 0: - while true: - let litId = t.keys[h] - if not isFilled(litId): break - if t.vals[idToIdx t.keys[h]] == v: return litId - h = nextTry(h, maxHash(t)) - # not found, we need to insert it: - if mustRehash(t.keys.len, t.vals.len): - enlarge(t) - # recompute where to insert: - h = origH and maxHash(t) - while true: - let litId = t.keys[h] - if not isFilled(litId): break - h = nextTry(h, maxHash(t)) - else: - setLen(t.keys, 16) - h = origH and maxHash(t) - - result = LitId(t.vals.len + idStart) - t.keys[h] = result - t.vals.add v - - -proc `[]`*[T](t: var BiTable[T]; litId: LitId): var T {.inline.} = - let idx = idToIdx litId - assert idx < t.vals.len - result = t.vals[idx] - -proc `[]`*[T](t: BiTable[T]; litId: LitId): lent T {.inline.} = - let idx = idToIdx litId - assert idx < t.vals.len - result = t.vals[idx] - -proc hash*[T](t: BiTable[T]): Hash = - ## as the keys are hashes of the values, we simply use them instead - var h: Hash = 0 - for i, n in pairs t.keys: - h = h !& hash((i, n)) - result = !$h - -proc store*[T](f: var RodFile; t: BiTable[T]) = - storeSeq(f, t.vals) - storeSeq(f, t.keys) - -proc load*[T](f: var RodFile; t: var BiTable[T]) = - loadSeq(f, t.vals) - loadSeq(f, t.keys) - -when isMainModule: - - var t: BiTable[string] - - echo getOrIncl(t, "hello") - - echo getOrIncl(t, "hello") - echo getOrIncl(t, "hello3") - echo getOrIncl(t, "hello4") - echo getOrIncl(t, "helloasfasdfdsa") - echo getOrIncl(t, "hello") - echo getKeyId(t, "hello") - echo getKeyId(t, "none") - - for i in 0 ..< 100_000: - discard t.getOrIncl($i & "___" & $i) - - for i in 0 ..< 100_000: - assert t.getOrIncl($i & "___" & $i).idToIdx == i + 4 - echo "begin" - echo t.vals.len - - echo t.vals[0] - echo t.vals[1004] - - echo "middle" - - var tf: BiTable[float] - - discard tf.getOrIncl(0.4) - discard tf.getOrIncl(16.4) - discard tf.getOrIncl(32.4) - echo getKeyId(tf, 32.4) - - var f2 = open("testblah.bin", fmWrite) - echo store(f2, tf) - f2.close - - var f1 = open("testblah.bin", fmRead) - - var t2: BiTable[float] - - echo f1.load(t2) - echo t2.vals.len - - echo getKeyId(t2, 32.4) - - echo "end" - - - f1.close diff --git a/compiler/ic/cbackend.nim b/compiler/ic/cbackend.nim deleted file mode 100644 index 815078a36..000000000 --- a/compiler/ic/cbackend.nim +++ /dev/null @@ -1,178 +0,0 @@ -# -# -# The Nim Compiler -# (c) Copyright 2021 Andreas Rumpf -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# - -## New entry point into our C/C++ code generator. Ideally -## somebody would rewrite the old backend (which is 8000 lines of crufty Nim code) -## to work on packed trees directly and produce the C code as an AST which can -## then be rendered to text in a very simple manner. Unfortunately nobody wrote -## this code. So instead we wrap the existing cgen.nim and its friends so that -## we call directly into the existing code generation logic but avoiding the -## naive, outdated `passes` design. Thus you will see some -## `useAliveDataFromDce in flags` checks in the old code -- the old code is -## also doing cross-module dependency tracking and DCE that we don't need -## anymore. DCE is now done as prepass over the entire packed module graph. - -import std/packedsets, algorithm, tables - -when defined(nimPreviewSlimSystem): - import std/assertions - -import ".."/[ast, options, lineinfos, modulegraphs, cgendata, cgen, - pathutils, extccomp, msgs, modulepaths] - -import packed_ast, ic, dce, rodfiles - -proc unpackTree(g: ModuleGraph; thisModule: int; - tree: PackedTree; n: NodePos): PNode = - var decoder = initPackedDecoder(g.config, g.cache) - result = loadNodes(decoder, g.packed, thisModule, tree, n) - -proc setupBackendModule(g: ModuleGraph; m: var LoadedModule) = - if g.backend == nil: - g.backend = cgendata.newModuleList(g) - assert g.backend != nil - var bmod = cgen.newModule(BModuleList(g.backend), m.module, g.config) - bmod.idgen = idgenFromLoadedModule(m) - -proc generateCodeForModule(g: ModuleGraph; m: var LoadedModule; alive: var AliveSyms) = - var bmod = BModuleList(g.backend).modules[m.module.position] - assert bmod != nil - bmod.flags.incl useAliveDataFromDce - bmod.alive = move alive[m.module.position] - - for p in allNodes(m.fromDisk.topLevel): - let n = unpackTree(g, m.module.position, m.fromDisk.topLevel, p) - cgen.genTopLevelStmt(bmod, n) - - finalCodegenActions(g, bmod, newNodeI(nkStmtList, m.module.info)) - m.fromDisk.backendFlags = cgen.whichInitProcs(bmod) - -proc replayTypeInfo(g: ModuleGraph; m: var LoadedModule; origin: FileIndex) = - for x in mitems(m.fromDisk.emittedTypeInfo): - #echo "found type ", x, " for file ", int(origin) - g.emittedTypeInfo[x] = origin - -proc addFileToLink(config: ConfigRef; m: PSym) = - let filename = AbsoluteFile toFullPath(config, m.position.FileIndex) - let ext = - if config.backend == backendCpp: ".nim.cpp" - elif config.backend == backendObjc: ".nim.m" - else: ".nim.c" - let cfile = changeFileExt(completeCfilePath(config, - mangleModuleName(config, filename).AbsoluteFile), ext) - let objFile = completeCfilePath(config, toObjFile(config, cfile)) - if fileExists(objFile): - var cf = Cfile(nimname: m.name.s, cname: cfile, - obj: objFile, - flags: {CfileFlag.Cached}) - addFileToCompile(config, cf) - -when defined(debugDce): - import os, std/packedsets - -proc storeAliveSymsImpl(asymFile: AbsoluteFile; s: seq[int32]) = - var f = rodfiles.create(asymFile.string) - f.storeHeader() - f.storeSection aliveSymsSection - f.storeSeq(s) - close f - -template prepare {.dirty.} = - let asymFile = toRodFile(config, AbsoluteFile toFullPath(config, position.FileIndex), ".alivesyms") - var s = newSeqOfCap[int32](alive[position].len) - for a in items(alive[position]): s.add int32(a) - sort(s) - -proc storeAliveSyms(config: ConfigRef; position: int; alive: AliveSyms) = - prepare() - storeAliveSymsImpl(asymFile, s) - -proc aliveSymsChanged(config: ConfigRef; position: int; alive: AliveSyms): bool = - prepare() - var f2 = rodfiles.open(asymFile.string) - f2.loadHeader() - f2.loadSection aliveSymsSection - var oldData: seq[int32] - f2.loadSeq(oldData) - f2.close - if f2.err == ok and oldData == s: - result = false - else: - when defined(debugDce): - let oldAsSet = toPackedSet[int32](oldData) - let newAsSet = toPackedSet[int32](s) - echo "set of live symbols changed ", asymFile.changeFileExt("rod"), " ", position, " ", f2.err - echo "in old but not in new ", oldAsSet.difference(newAsSet), " number of entries in old ", oldAsSet.len - echo "in new but not in old ", newAsSet.difference(oldAsSet), " number of entries in new ", newAsSet.len - #if execShellCmd(getAppFilename() & " rod " & quoteShell(asymFile.changeFileExt("rod"))) != 0: - # echo "command failed" - result = true - storeAliveSymsImpl(asymFile, s) - -proc genPackedModule(g: ModuleGraph, i: int; alive: var AliveSyms) = - # case statement here to enforce exhaustive checks. - case g.packed[i].status - of undefined: - discard "nothing to do" - of loading, stored: - assert false - of storing, outdated: - storeAliveSyms(g.config, g.packed[i].module.position, alive) - generateCodeForModule(g, g.packed[i], alive) - closeRodFile(g, g.packed[i].module) - of loaded: - if g.packed[i].loadedButAliveSetChanged: - generateCodeForModule(g, g.packed[i], alive) - else: - addFileToLink(g.config, g.packed[i].module) - replayTypeInfo(g, g.packed[i], FileIndex(i)) - - if g.backend == nil: - g.backend = cgendata.newModuleList(g) - registerInitProcs(BModuleList(g.backend), g.packed[i].module, g.packed[i].fromDisk.backendFlags) - -proc generateCode*(g: ModuleGraph) = - ## The single entry point, generate C(++) code for the entire - ## Nim program aka `ModuleGraph`. - resetForBackend(g) - var alive = computeAliveSyms(g.packed, g.config) - - when false: - for i in 0..high(g.packed): - echo i, " is of status ", g.packed[i].status, " ", toFullPath(g.config, FileIndex(i)) - - # First pass: Setup all the backend modules for all the modules that have - # changed: - for i in 0..high(g.packed): - # case statement here to enforce exhaustive checks. - case g.packed[i].status - of undefined: - discard "nothing to do" - of loading, stored: - assert false - of storing, outdated: - setupBackendModule(g, g.packed[i]) - of loaded: - # Even though this module didn't change, DCE might trigger a change. - # Consider this case: Module A uses symbol S from B and B does not use - # S itself. A is then edited not to use S either. Thus we have to - # recompile B in order to remove S from the final result. - if aliveSymsChanged(g.config, g.packed[i].module.position, alive): - g.packed[i].loadedButAliveSetChanged = true - setupBackendModule(g, g.packed[i]) - - # Second pass: Code generation. - let mainModuleIdx = g.config.projectMainIdx2.int - # We need to generate the main module last, because only then - # all init procs have been registered: - for i in 0..high(g.packed): - if i != mainModuleIdx: - genPackedModule(g, i, alive) - if mainModuleIdx >= 0: - genPackedModule(g, mainModuleIdx, alive) diff --git a/compiler/ic/dce.nim b/compiler/ic/dce.nim deleted file mode 100644 index bc61a38de..000000000 --- a/compiler/ic/dce.nim +++ /dev/null @@ -1,165 +0,0 @@ -# -# -# The Nim Compiler -# (c) Copyright 2021 Andreas Rumpf -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# - -## Dead code elimination (=DCE) for IC. - -import std/[intsets, tables] - -when defined(nimPreviewSlimSystem): - import std/assertions - -import ".." / [ast, options, lineinfos, types] - -import packed_ast, ic, bitabs - -type - AliveSyms* = seq[IntSet] - AliveContext* = object ## Purpose is to fill the 'alive' field. - stack: seq[(int, TOptions, NodePos)] ## A stack for marking symbols as alive. - decoder: PackedDecoder ## We need a PackedDecoder for module ID address translations. - thisModule: int ## The module we're currently analysing for DCE. - alive: AliveSyms ## The final result of our computation. - options: TOptions - compilerProcs: Table[string, (int, int32)] - -proc isExportedToC(c: var AliveContext; g: PackedModuleGraph; symId: int32): bool = - ## "Exported to C" procs are special (these are marked with '.exportc') because these - ## must not be optimized away! - let symPtr = unsafeAddr g[c.thisModule].fromDisk.syms[symId] - let flags = symPtr.flags - # due to a bug/limitation in the lambda lifting, unused inner procs - # are not transformed correctly; issue (#411). However, the whole purpose here - # is to eliminate unused procs. So there is no special logic required for this case. - if sfCompileTime notin flags: - if ({sfExportc, sfCompilerProc} * flags != {}) or - (symPtr.kind == skMethod): - result = true - # XXX: This used to be a condition to: - # (sfExportc in prc.flags and lfExportLib in prc.loc.flags) or - if sfCompilerProc in flags: - c.compilerProcs[g[c.thisModule].fromDisk.strings[symPtr.name]] = (c.thisModule, symId) - -template isNotGeneric(n: NodePos): bool = ithSon(tree, n, genericParamsPos).kind == nkEmpty - -proc followLater(c: var AliveContext; g: PackedModuleGraph; module: int; item: int32) = - ## Marks a symbol 'item' as used and later in 'followNow' the symbol's body will - ## be analysed. - if not c.alive[module].containsOrIncl(item): - var body = g[module].fromDisk.syms[item].ast - if body != emptyNodeId: - let opt = g[module].fromDisk.syms[item].options - if g[module].fromDisk.syms[item].kind in routineKinds: - body = NodeId ithSon(g[module].fromDisk.bodies, NodePos body, bodyPos) - c.stack.add((module, opt, NodePos(body))) - - when false: - let nid = g[module].fromDisk.syms[item].name - if nid != LitId(0): - let name = g[module].fromDisk.strings[nid] - if name in ["nimFrame", "callDepthLimitReached"]: - echo "I was called! ", name, " body exists: ", body != emptyNodeId, " ", module, " ", item - -proc requestCompilerProc(c: var AliveContext; g: PackedModuleGraph; name: string) = - let (module, item) = c.compilerProcs[name] - followLater(c, g, module, item) - -proc loadTypeKind(t: PackedItemId; c: AliveContext; g: PackedModuleGraph; toSkip: set[TTypeKind]): TTypeKind = - template kind(t: ItemId): TTypeKind = g[t.module].fromDisk.types[t.item].kind - - var t2 = translateId(t, g, c.thisModule, c.decoder.config) - result = t2.kind - while result in toSkip: - t2 = translateId(g[t2.module].fromDisk.types[t2.item].types[^1], g, t2.module, c.decoder.config) - result = t2.kind - -proc rangeCheckAnalysis(c: var AliveContext; g: PackedModuleGraph; tree: PackedTree; n: NodePos) = - ## Replicates the logic of `ccgexprs.genRangeChck`. - ## XXX Refactor so that the duplicated logic is avoided. However, for now it's not clear - ## the approach has enough merit. - var dest = loadTypeKind(n.typ, c, g, abstractVar) - if optRangeCheck notin c.options or dest in {tyUInt..tyUInt64}: - discard "no need to generate a check because it was disabled" - else: - let n0t = loadTypeKind(n.firstSon.typ, c, g, {}) - if n0t in {tyUInt, tyUInt64}: - c.requestCompilerProc(g, "raiseRangeErrorNoArgs") - else: - let raiser = - case loadTypeKind(n.typ, c, g, abstractVarRange) - of tyUInt..tyUInt64, tyChar: "raiseRangeErrorU" - of tyFloat..tyFloat128: "raiseRangeErrorF" - else: "raiseRangeErrorI" - c.requestCompilerProc(g, raiser) - -proc aliveCode(c: var AliveContext; g: PackedModuleGraph; tree: PackedTree; n: NodePos) = - ## Marks the symbols we encounter when we traverse the AST at `tree[n]` as alive, unless - ## it is purely in a declarative context (type section etc.). - case n.kind - of nkNone..pred(nkSym), succ(nkSym)..nkNilLit: - discard "ignore non-sym atoms" - of nkSym: - # This symbol is alive and everything its body references. - followLater(c, g, c.thisModule, n.operand) - of nkModuleRef: - let (n1, n2) = sons2(tree, n) - assert n1.kind == nkInt32Lit - assert n2.kind == nkInt32Lit - let m = n1.litId - let item = n2.operand - let otherModule = toFileIndexCached(c.decoder, g, c.thisModule, m).int - followLater(c, g, otherModule, item) - of nkMacroDef, nkTemplateDef, nkTypeSection, nkTypeOfExpr, - nkCommentStmt, nkIncludeStmt, - nkImportStmt, nkImportExceptStmt, nkExportStmt, nkExportExceptStmt, - nkFromStmt, nkStaticStmt: - discard - of nkVarSection, nkLetSection, nkConstSection: - # XXX ignore the defining local variable name? - for son in sonsReadonly(tree, n): - aliveCode(c, g, tree, son) - of nkChckRangeF, nkChckRange64, nkChckRange: - rangeCheckAnalysis(c, g, tree, n) - of nkProcDef, nkConverterDef, nkMethodDef, nkFuncDef, nkIteratorDef: - if n.firstSon.kind == nkSym and isNotGeneric(n): - let item = n.firstSon.operand - if isExportedToC(c, g, item): - # This symbol is alive and everything its body references. - followLater(c, g, c.thisModule, item) - else: - for son in sonsReadonly(tree, n): - aliveCode(c, g, tree, son) - -proc followNow(c: var AliveContext; g: PackedModuleGraph) = - ## Mark all entries in the stack. Marking can add more entries - ## to the stack but eventually we have looked at every alive symbol. - while c.stack.len > 0: - let (modId, opt, ast) = c.stack.pop() - c.thisModule = modId - c.options = opt - aliveCode(c, g, g[modId].fromDisk.bodies, ast) - -proc computeAliveSyms*(g: PackedModuleGraph; conf: ConfigRef): AliveSyms = - ## Entry point for our DCE algorithm. - var c = AliveContext(stack: @[], decoder: PackedDecoder(config: conf), - thisModule: -1, alive: newSeq[IntSet](g.len), - options: conf.options) - for i in countdown(high(g), 0): - if g[i].status != undefined: - c.thisModule = i - for p in allNodes(g[i].fromDisk.topLevel): - aliveCode(c, g, g[i].fromDisk.topLevel, p) - - followNow(c, g) - result = move(c.alive) - -proc isAlive*(a: AliveSyms; module: int, item: int32): bool = - ## Backends use this to query if a symbol is `alive` which means - ## we need to produce (C/C++/etc) code for it. - result = a[module].contains(item) - diff --git a/compiler/ic/design.rst b/compiler/ic/design.rst deleted file mode 100644 index b096e3103..000000000 --- a/compiler/ic/design.rst +++ /dev/null @@ -1,56 +0,0 @@ -==================================== - Incremental Recompilations -==================================== - -We split the Nim compiler into a frontend and a backend. -The frontend produces a set of `.rod` files. Every `.nim` module -produces its own `.rod` file. - -- The IR must be a faithful representation of the AST in memory. -- The backend can do its own caching but doesn't have to. In the - current implementation the backend also caches its results. - -Advantage of the "set of files" vs the previous global database: -- By construction, we either read from the `.rod` file or from the - `.nim` file, there can be no inconsistency. There can also be no - partial updates. -- No dependency to external packages (SQLite). SQLite simply is too - slow and the old way of serialization was too slow too. We use a - format designed for Nim and expect to base further tools on this - file format. - -References to external modules must be (moduleId, symId) pairs. -The symbol IDs are module specific. This way no global ID increment -mechanism needs to be implemented that we could get wrong. ModuleIds -are rod-file specific too. - - - -Global state ------------- - -There is no global state. - -Rod File Format ---------------- - -It's a simple binary file format. `rodfiles.nim` contains some details. - - -Backend -------- - -Nim programmers have to come to enjoy whole-program dead code elimination, -by default. Since this is a "whole program" optimization, it does break -modularity. However, thanks to the packed AST representation we can perform -this global analysis without having to unpack anything. This is basically -a mark&sweep GC algorithm: - -- Start with the top level statements. Every symbol that is referenced - from a top level statement is not "dead" and needs to be compiled by - the backend. -- Every symbol referenced from a referenced symbol also has to be - compiled. - -Caching logic: Only if the set of alive symbols is different from the -last run, the module has to be regenerated. diff --git a/compiler/ic/ic.nim b/compiler/ic/ic.nim deleted file mode 100644 index 36a57f11e..000000000 --- a/compiler/ic/ic.nim +++ /dev/null @@ -1,1231 +0,0 @@ -# -# -# The Nim Compiler -# (c) Copyright 2020 Andreas Rumpf -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# - -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 - -when defined(nimPreviewSlimSystem): - import std/[syncio, assertions, formatfloat] - -type - PackedConfig* = object - backend: TBackend - selectedGC: TGCMode - cCompiler: TSystemCC - options: TOptions - globalOptions: TGlobalOptions - - ModuleBackendFlag* = enum - HasDatInitProc - HasModuleInitProc - - PackedModule* = object ## the parts of a PackedEncoder that are part of the .rod file - definedSymbols: string - moduleFlags: TSymFlags - includes*: seq[(LitId, string)] # first entry is the module filename itself - imports: seq[LitId] # the modules this module depends on - toReplay*: PackedTree # pragmas and VM specific state to replay. - topLevel*: PackedTree # top level statements - bodies*: PackedTree # other trees. Referenced from typ.n and sym.ast by their position. - #producedGenerics*: Table[GenericKey, SymId] - exports*: seq[(LitId, int32)] - hidden*: seq[(LitId, int32)] - reexports*: seq[(LitId, PackedItemId)] - compilerProcs*: seq[(LitId, int32)] - converters*, methods*, trmacros*, pureEnums*: seq[int32] - - typeInstCache*: seq[(PackedItemId, PackedItemId)] - procInstCache*: seq[PackedInstantiation] - attachedOps*: seq[(PackedItemId, TTypeAttachedOp, PackedItemId)] - methodsPerType*: seq[(PackedItemId, int, PackedItemId)] - enumToStringProcs*: seq[(PackedItemId, PackedItemId)] - - emittedTypeInfo*: seq[string] - backendFlags*: set[ModuleBackendFlag] - - syms*: seq[PackedSym] - types*: seq[PackedType] - strings*: BiTable[string] # we could share these between modules. - numbers*: BiTable[BiggestInt] # we also store floats in here so - # that we can assure that every bit is kept - - cfg: PackedConfig - - PackedEncoder* = object - #m*: PackedModule - thisModule*: int32 - lastFile*: FileIndex # remember the last lookup entry. - lastLit*: LitId - filenames*: Table[FileIndex, LitId] - pendingTypes*: seq[PType] - pendingSyms*: seq[PSym] - typeMarker*: IntSet #Table[ItemId, TypeId] # ItemId.item -> TypeId - symMarker*: IntSet #Table[ItemId, SymId] # ItemId.item -> SymId - config*: ConfigRef - -proc toString*(tree: PackedTree; n: NodePos; m: PackedModule; nesting: int; - result: var string) = - let pos = n.int - if result.len > 0 and result[^1] notin {' ', '\n'}: - result.add ' ' - - result.add $tree[pos].kind - case tree.nodes[pos].kind - of nkNone, nkEmpty, nkNilLit, nkType: discard - of nkIdent, nkStrLit..nkTripleStrLit: - result.add " " - result.add m.strings[LitId tree.nodes[pos].operand] - of nkSym: - result.add " " - result.add m.strings[m.syms[tree.nodes[pos].operand].name] - of directIntLit: - result.add " " - result.addInt tree.nodes[pos].operand - of externSIntLit: - result.add " " - result.addInt m.numbers[LitId tree.nodes[pos].operand] - of externUIntLit: - result.add " " - result.addInt cast[uint64](m.numbers[LitId tree.nodes[pos].operand]) - of nkFloatLit..nkFloat128Lit: - result.add " " - result.addFloat cast[BiggestFloat](m.numbers[LitId tree.nodes[pos].operand]) - else: - result.add "(\n" - for i in 1..(nesting+1)*2: result.add ' ' - for child in sonsReadonly(tree, n): - toString(tree, child, m, nesting + 1, result) - result.add "\n" - for i in 1..nesting*2: result.add ' ' - result.add ")" - #for i in 1..nesting*2: result.add ' ' - -proc toString*(tree: PackedTree; n: NodePos; m: PackedModule): string = - result = "" - toString(tree, n, m, 0, result) - -proc debug*(tree: PackedTree; m: PackedModule) = - stdout.write toString(tree, NodePos 0, m) - -proc isActive*(e: PackedEncoder): bool = e.config != nil -proc disable(e: var PackedEncoder) = e.config = nil - -template primConfigFields(fn: untyped) {.dirty.} = - fn backend - fn selectedGC - fn cCompiler - fn options - fn globalOptions - -proc definedSymbolsAsString(config: ConfigRef): string = - result = newStringOfCap(200) - result.add "config" - for d in definedSymbolNames(config.symbols): - result.add ' ' - result.add d - -proc rememberConfig(c: var PackedEncoder; m: var PackedModule; config: ConfigRef; pc: PackedConfig) = - m.definedSymbols = definedSymbolsAsString(config) - #template rem(x) = - # c.m.cfg.x = config.x - #primConfigFields rem - m.cfg = pc - -const - debugConfigDiff = defined(debugConfigDiff) - -when debugConfigDiff: - import hashes, tables, intsets, sha1, strutils, sets - -proc configIdentical(m: PackedModule; config: ConfigRef): bool = - result = m.definedSymbols == definedSymbolsAsString(config) - when debugConfigDiff: - if not result: - var wordsA = m.definedSymbols.split(Whitespace).toHashSet() - var wordsB = definedSymbolsAsString(config).split(Whitespace).toHashSet() - for c in wordsA - wordsB: - echo "in A but not in B ", c - for c in wordsB - wordsA: - echo "in B but not in A ", c - template eq(x) = - result = result and m.cfg.x == config.x - when debugConfigDiff: - if m.cfg.x != config.x: - echo "B ", m.cfg.x, " ", config.x - primConfigFields eq - -proc rememberStartupConfig*(dest: var PackedConfig, config: ConfigRef) = - template rem(x) = - dest.x = config.x - primConfigFields rem - dest.globalOptions.excl optForceFullMake - -proc hashFileCached(conf: ConfigRef; fileIdx: FileIndex): string = - result = msgs.getHash(conf, fileIdx) - if result.len == 0: - let fullpath = msgs.toFullPath(conf, fileIdx) - result = $secureHashFile(fullpath) - msgs.setHash(conf, fileIdx, result) - -proc toLitId(x: FileIndex; c: var PackedEncoder; m: var PackedModule): LitId = - ## store a file index as a literal - if x == c.lastFile: - result = c.lastLit - else: - result = c.filenames.getOrDefault(x) - if result == LitId(0): - let p = msgs.toFullPath(c.config, x) - result = getOrIncl(m.strings, p) - c.filenames[x] = result - c.lastFile = x - c.lastLit = result - assert result != LitId(0) - -proc toFileIndex*(x: LitId; m: PackedModule; config: ConfigRef): FileIndex = - result = msgs.fileInfoIdx(config, AbsoluteFile m.strings[x]) - -proc includesIdentical(m: var PackedModule; config: ConfigRef): bool = - for it in mitems(m.includes): - if hashFileCached(config, toFileIndex(it[0], m, config)) != it[1]: - return false - result = true - -proc initEncoder*(c: var PackedEncoder; m: var PackedModule; moduleSym: PSym; config: ConfigRef; pc: PackedConfig) = - ## setup a context for serializing to packed ast - c.thisModule = moduleSym.itemId.module - c.config = config - m.moduleFlags = moduleSym.flags - m.bodies = newTreeFrom(m.topLevel) - m.toReplay = newTreeFrom(m.topLevel) - - c.lastFile = FileIndex(-10) - - let thisNimFile = FileIndex c.thisModule - var h = msgs.getHash(config, thisNimFile) - if h.len == 0: - let fullpath = msgs.toFullPath(config, thisNimFile) - if isAbsolute(fullpath): - # For NimScript compiler API support the main Nim file might be from a stream. - h = $secureHashFile(fullpath) - msgs.setHash(config, thisNimFile, h) - m.includes.add((toLitId(thisNimFile, c, m), h)) # the module itself - - rememberConfig(c, m, config, pc) - -proc addIncludeFileDep*(c: var PackedEncoder; m: var PackedModule; f: FileIndex) = - m.includes.add((toLitId(f, c, m), hashFileCached(c.config, f))) - -proc addImportFileDep*(c: var PackedEncoder; m: var PackedModule; f: FileIndex) = - m.imports.add toLitId(f, c, m) - -proc addHidden*(c: var PackedEncoder; m: var PackedModule; s: PSym) = - let nameId = getOrIncl(m.strings, s.name.s) - m.hidden.add((nameId, s.itemId.item)) - -proc addExported*(c: var PackedEncoder; m: var PackedModule; s: PSym) = - let nameId = getOrIncl(m.strings, s.name.s) - m.exports.add((nameId, s.itemId.item)) - -proc addConverter*(c: var PackedEncoder; m: var PackedModule; s: PSym) = - assert c.thisModule == s.itemId.module - m.converters.add(s.itemId.item) - -proc addTrmacro*(c: var PackedEncoder; m: var PackedModule; s: PSym) = - m.trmacros.add(s.itemId.item) - -proc addPureEnum*(c: var PackedEncoder; m: var PackedModule; s: PSym) = - assert s.kind == skType - m.pureEnums.add(s.itemId.item) - -proc addMethod*(c: var PackedEncoder; m: var PackedModule; s: PSym) = - m.methods.add s.itemId.item - -proc addReexport*(c: var PackedEncoder; m: var PackedModule; s: PSym) = - let nameId = getOrIncl(m.strings, s.name.s) - m.reexports.add((nameId, PackedItemId(module: toLitId(s.itemId.module.FileIndex, c, m), - item: s.itemId.item))) - -proc addCompilerProc*(c: var PackedEncoder; m: var PackedModule; s: PSym) = - let nameId = getOrIncl(m.strings, s.name.s) - m.compilerProcs.add((nameId, s.itemId.item)) - -proc toPackedNode*(n: PNode; ir: var PackedTree; c: var PackedEncoder; m: var PackedModule) -proc storeSym*(s: PSym; c: var PackedEncoder; m: var PackedModule): PackedItemId -proc storeType(t: PType; c: var PackedEncoder; m: var PackedModule): PackedItemId - -proc flush(c: var PackedEncoder; m: var PackedModule) = - ## serialize any pending types or symbols from the context - while true: - if c.pendingTypes.len > 0: - discard storeType(c.pendingTypes.pop, c, m) - elif c.pendingSyms.len > 0: - discard storeSym(c.pendingSyms.pop, c, m) - else: - break - -proc toLitId(x: string; m: var PackedModule): LitId = - ## store a string as a literal - result = getOrIncl(m.strings, x) - -proc toLitId(x: BiggestInt; m: var PackedModule): LitId = - ## store an integer as a literal - result = getOrIncl(m.numbers, x) - -proc toPackedInfo(x: TLineInfo; c: var PackedEncoder; m: var PackedModule): PackedLineInfo = - PackedLineInfo(line: x.line, col: x.col, file: toLitId(x.fileIndex, c, m)) - -proc safeItemId(s: PSym; c: var PackedEncoder; m: var PackedModule): PackedItemId {.inline.} = - ## given a symbol, produce an ItemId with the correct properties - ## for local or remote symbols, packing the symbol as necessary - if s == nil or s.kind == skPackage: - result = nilItemId - #elif s.itemId.module == c.thisModule: - # result = PackedItemId(module: LitId(0), item: s.itemId.item) - else: - assert int(s.itemId.module) >= 0 - result = PackedItemId(module: toLitId(s.itemId.module.FileIndex, c, m), - item: s.itemId.item) - -proc addMissing(c: var PackedEncoder; p: PSym) = - ## consider queuing a symbol for later addition to the packed tree - if p != nil and p.itemId.module == c.thisModule: - if p.itemId.item notin c.symMarker: - if not (sfForward in p.flags and p.kind in routineKinds): - c.pendingSyms.add p - -proc addMissing(c: var PackedEncoder; p: PType) = - ## consider queuing a type for later addition to the packed tree - if p != nil and p.uniqueId.module == c.thisModule: - if p.uniqueId.item notin c.typeMarker: - c.pendingTypes.add p - -template storeNode(dest, src, field) = - var nodeId: NodeId - if src.field != nil: - nodeId = getNodeId(m.bodies) - toPackedNode(src.field, m.bodies, c, m) - else: - nodeId = emptyNodeId - dest.field = nodeId - -proc storeTypeLater(t: PType; c: var PackedEncoder; m: var PackedModule): PackedItemId = - # We store multiple different trees in m.bodies. For this to work out, we - # cannot immediately store types/syms. We enqueue them instead to ensure - # we only write one tree into m.bodies after the other. - if t.isNil: return nilItemId - - assert t.uniqueId.module >= 0 - assert t.uniqueId.item > 0 - result = PackedItemId(module: toLitId(t.uniqueId.module.FileIndex, c, m), item: t.uniqueId.item) - if t.uniqueId.module == c.thisModule: - # the type belongs to this module, so serialize it here, eventually. - addMissing(c, t) - -proc storeSymLater(s: PSym; c: var PackedEncoder; m: var PackedModule): PackedItemId = - if s.isNil: return nilItemId - assert s.itemId.module >= 0 - assert s.itemId.module >= 0 - result = PackedItemId(module: toLitId(s.itemId.module.FileIndex, c, m), item: s.itemId.item) - if s.itemId.module == c.thisModule: - # the sym belongs to this module, so serialize it here, eventually. - addMissing(c, s) - -proc storeType(t: PType; c: var PackedEncoder; m: var PackedModule): PackedItemId = - ## serialize a ptype - if t.isNil: return nilItemId - - assert t.uniqueId.module >= 0 - assert t.uniqueId.item > 0 - result = PackedItemId(module: toLitId(t.uniqueId.module.FileIndex, c, m), item: t.uniqueId.item) - - if t.uniqueId.module == c.thisModule and not c.typeMarker.containsOrIncl(t.uniqueId.item): - if t.uniqueId.item >= m.types.len: - setLen m.types, t.uniqueId.item+1 - - var p = PackedType(kind: t.kind, flags: t.flags, callConv: t.callConv, - size: t.size, align: t.align, nonUniqueId: t.itemId.item, - paddingAtEnd: t.paddingAtEnd) - storeNode(p, t, n) - p.typeInst = t.typeInst.storeType(c, m) - for kid in items t.sons: - p.types.add kid.storeType(c, m) - c.addMissing t.sym - p.sym = t.sym.safeItemId(c, m) - c.addMissing t.owner - p.owner = t.owner.safeItemId(c, m) - - # fill the reserved slot, nothing else: - m.types[t.uniqueId.item] = p - -proc toPackedLib(l: PLib; c: var PackedEncoder; m: var PackedModule): PackedLib = - ## the plib hangs off the psym via the .annex field - if l.isNil: return - result.kind = l.kind - result.generated = l.generated - result.isOverriden = l.isOverriden - result.name = toLitId($l.name, m) - storeNode(result, l, path) - -proc storeSym*(s: PSym; c: var PackedEncoder; m: var PackedModule): PackedItemId = - ## serialize a psym - if s.isNil: return nilItemId - - assert s.itemId.module >= 0 - result = PackedItemId(module: toLitId(s.itemId.module.FileIndex, c, m), item: s.itemId.item) - - if s.itemId.module == c.thisModule and not c.symMarker.containsOrIncl(s.itemId.item): - if s.itemId.item >= m.syms.len: - setLen m.syms, s.itemId.item+1 - - 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, options: s.options, - name: s.name.s.toLitId(m)) - - storeNode(p, s, ast) - storeNode(p, s, constraint) - - if s.kind in {skLet, skVar, skField, skForVar}: - c.addMissing s.guard - p.guard = s.guard.safeItemId(c, m) - p.bitsize = s.bitsize - p.alignment = s.alignment - - p.externalName = toLitId(s.loc.r, m) - p.locFlags = s.loc.flags - c.addMissing s.typ - p.typ = s.typ.storeType(c, m) - c.addMissing s.owner - p.owner = s.owner.safeItemId(c, m) - p.annex = toPackedLib(s.annex, c, m) - when hasFFI: - p.cname = toLitId(s.cname, m) - - # fill the reserved slot, nothing else: - m.syms[s.itemId.item] = p - -proc addModuleRef(n: PNode; ir: var PackedTree; c: var PackedEncoder; m: var PackedModule) = - ## 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) - 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, - operand: n.sym.itemId.item) - -proc toPackedNode*(n: PNode; ir: var PackedTree; c: var PackedEncoder; m: var PackedModule) = - ## serialize a node into the tree - if n == nil: - ir.nodes.add PackedNode(kind: nkNilRodNode, flags: {}, operand: 1) - return - let info = toPackedInfo(n.info, c, m) - case n.kind - of nkNone, nkEmpty, nkNilLit, nkType: - ir.nodes.add PackedNode(kind: n.kind, flags: n.flags, operand: 0, - typeId: storeTypeLater(n.typ, c, m), info: info) - of nkIdent: - ir.nodes.add PackedNode(kind: n.kind, flags: n.flags, - operand: int32 getOrIncl(m.strings, n.ident.s), - typeId: storeTypeLater(n.typ, c, m), info: info) - of nkSym: - if n.sym.itemId.module == c.thisModule: - # it is a symbol that belongs to the module we're currently - # packing: - let id = n.sym.storeSymLater(c, m).item - ir.nodes.add PackedNode(kind: nkSym, flags: n.flags, operand: id, - typeId: storeTypeLater(n.typ, c, m), info: info) - else: - # store it as an external module reference: - addModuleRef(n, ir, c, m) - of directIntLit: - ir.nodes.add PackedNode(kind: n.kind, flags: n.flags, - operand: int32(n.intVal), - typeId: storeTypeLater(n.typ, c, m), info: info) - of externIntLit: - ir.nodes.add PackedNode(kind: n.kind, flags: n.flags, - operand: int32 getOrIncl(m.numbers, n.intVal), - typeId: storeTypeLater(n.typ, c, m), info: info) - of nkStrLit..nkTripleStrLit: - ir.nodes.add PackedNode(kind: n.kind, flags: n.flags, - operand: int32 getOrIncl(m.strings, n.strVal), - typeId: storeTypeLater(n.typ, c, m), info: info) - of nkFloatLit..nkFloat128Lit: - ir.nodes.add PackedNode(kind: n.kind, flags: n.flags, - operand: int32 getOrIncl(m.numbers, cast[BiggestInt](n.floatVal)), - typeId: storeTypeLater(n.typ, c, m), info: info) - else: - let patchPos = ir.prepare(n.kind, n.flags, - storeTypeLater(n.typ, c, m), info) - for i in 0.. 0 - - if not g[si].typesInit: - g[si].typesInit = true - setLen g[si].types, g[si].fromDisk.types.len - - if g[si].types[t.item] == nil: - result = typeHeaderFromPacked(c, g, g[si].fromDisk.types[t.item], si, t.item) - # store it here early on, so that recursions work properly: - g[si].types[t.item] = result - typeBodyFromPacked(c, g, g[si].fromDisk.types[t.item], si, t.item, result) - else: - result = g[si].types[t.item] - assert result.itemId.item > 0 - -proc setupLookupTables(g: var PackedModuleGraph; conf: ConfigRef; cache: IdentCache; - fileIdx: FileIndex; m: var LoadedModule) = - m.iface = initTable[PIdent, seq[PackedItemId]]() - m.ifaceHidden = initTable[PIdent, seq[PackedItemId]]() - template impl(iface, e) = - let nameLit = e[0] - let e2 = - when e[1] is PackedItemId: e[1] - else: PackedItemId(module: LitId(0), item: e[1]) - iface.mgetOrPut(cache.getIdent(m.fromDisk.strings[nameLit]), @[]).add(e2) - - for e in m.fromDisk.exports: - m.iface.impl(e) - m.ifaceHidden.impl(e) - for e in m.fromDisk.reexports: - m.iface.impl(e) - m.ifaceHidden.impl(e) - for e in m.fromDisk.hidden: - m.ifaceHidden.impl(e) - - let filename = AbsoluteFile toFullPath(conf, 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. - m.module = PSym(kind: skModule, itemId: ItemId(module: int32(fileIdx), item: 0'i32), - name: getIdent(cache, splitFile(filename).name), - info: newLineInfo(fileIdx, 1, 1), - position: int(fileIdx)) - m.module.owner = getPackage(conf, cache, fileIdx) - m.module.flags = m.fromDisk.moduleFlags - -proc loadToReplayNodes(g: var PackedModuleGraph; conf: ConfigRef; cache: IdentCache; - fileIdx: FileIndex; m: var LoadedModule) = - m.module.ast = newNode(nkStmtList) - if m.fromDisk.toReplay.len > 0: - var decoder = PackedDecoder( - lastModule: int32(-1), - lastLit: LitId(0), - lastFile: FileIndex(-1), - config: conf, - cache: cache) - for p in allNodes(m.fromDisk.toReplay): - m.module.ast.add loadNodes(decoder, g, int(fileIdx), m.fromDisk.toReplay, p) - -proc needsRecompile(g: var PackedModuleGraph; conf: ConfigRef; cache: IdentCache; - fileIdx: FileIndex; cachedModules: var seq[FileIndex]): bool = - # Does the file belong to the fileIdx need to be recompiled? - let m = int(fileIdx) - if m >= g.len: - g.setLen(m+1) - - case g[m].status - of undefined: - g[m].status = loading - let fullpath = msgs.toFullPath(conf, fileIdx) - let rod = toRodFile(conf, AbsoluteFile fullpath) - let err = loadRodFile(rod, g[m].fromDisk, conf) - if err == ok: - result = optForceFullMake in conf.globalOptions - # check its dependencies: - for dep in g[m].fromDisk.imports: - let fid = toFileIndex(dep, g[m].fromDisk, conf) - # Warning: we need to traverse the full graph, so - # do **not use break here**! - if needsRecompile(g, conf, cache, fid, cachedModules): - result = true - - if not result: - setupLookupTables(g, conf, cache, fileIdx, g[m]) - cachedModules.add fileIdx - g[m].status = loaded - else: - g[m] = LoadedModule(status: outdated, module: g[m].module) - else: - loadError(err, rod, conf) - g[m].status = outdated - result = true - when false: loadError(err, rod, conf) - of loading, loaded: - # For loading: Assume no recompile is required. - result = false - of outdated, storing, stored: - result = true - -proc moduleFromRodFile*(g: var PackedModuleGraph; conf: ConfigRef; cache: IdentCache; - fileIdx: FileIndex; cachedModules: var seq[FileIndex]): PSym = - ## Returns 'nil' if the module needs to be recompiled. - if needsRecompile(g, conf, cache, fileIdx, cachedModules): - result = nil - else: - result = g[int fileIdx].module - assert result != nil - assert result.position == int(fileIdx) - for m in cachedModules: - loadToReplayNodes(g, conf, cache, m, g[int m]) - -template setupDecoder() {.dirty.} = - var decoder = PackedDecoder( - lastModule: int32(-1), - lastLit: LitId(0), - lastFile: FileIndex(-1), - config: config, - cache: cache) - -proc loadProcBody*(config: ConfigRef, cache: IdentCache; - g: var PackedModuleGraph; s: PSym): PNode = - let mId = s.itemId.module - var decoder = PackedDecoder( - lastModule: int32(-1), - lastLit: LitId(0), - lastFile: FileIndex(-1), - config: config, - cache: cache) - let pos = g[mId].fromDisk.syms[s.itemId.item].ast - assert pos != emptyNodeId - result = loadProcBody(decoder, g, mId, g[mId].fromDisk.bodies, NodePos pos) - -proc loadTypeFromId*(config: ConfigRef, cache: IdentCache; - g: var PackedModuleGraph; module: int; id: PackedItemId): PType = - if id.item < g[module].types.len: - result = g[module].types[id.item] - else: - result = nil - if result == nil: - var decoder = PackedDecoder( - lastModule: int32(-1), - lastLit: LitId(0), - lastFile: FileIndex(-1), - config: config, - cache: cache) - result = loadType(decoder, g, module, id) - -proc loadSymFromId*(config: ConfigRef, cache: IdentCache; - g: var PackedModuleGraph; module: int; id: PackedItemId): PSym = - if id.item < g[module].syms.len: - result = g[module].syms[id.item] - else: - result = nil - if result == nil: - var decoder = PackedDecoder( - lastModule: int32(-1), - lastLit: LitId(0), - lastFile: FileIndex(-1), - config: config, - cache: cache) - result = loadSym(decoder, g, module, id) - -proc translateId*(id: PackedItemId; g: PackedModuleGraph; thisModule: int; config: ConfigRef): ItemId = - if id.module == LitId(0): - ItemId(module: thisModule.int32, item: id.item) - else: - ItemId(module: toFileIndex(id.module, g[thisModule].fromDisk, config).int32, item: id.item) - -proc checkForHoles(m: PackedModule; config: ConfigRef; moduleId: int) = - var bugs = 0 - for i in 1 .. high(m.syms): - if m.syms[i].kind == skUnknown: - echo "EMPTY ID ", i, " module ", moduleId, " ", toFullPath(config, FileIndex(moduleId)) - inc bugs - assert bugs == 0 - when false: - var nones = 0 - for i in 1 .. high(m.types): - inc nones, m.types[i].kind == tyNone - assert nones < 1 - -proc simulateLoadedModule*(g: var PackedModuleGraph; conf: ConfigRef; cache: IdentCache; - moduleSym: PSym; m: PackedModule) = - # For now only used for heavy debugging. In the future we could use this to reduce the - # compiler's memory consumption. - let idx = moduleSym.position - assert g[idx].status in {storing} - g[idx].status = loaded - assert g[idx].module == moduleSym - setupLookupTables(g, conf, cache, FileIndex(idx), g[idx]) - loadToReplayNodes(g, conf, cache, FileIndex(idx), g[idx]) - -# ---------------- symbol table handling ---------------- - -type - RodIter* = object - decoder: PackedDecoder - values: seq[PackedItemId] - i, module: int - -template interfSelect(a: LoadedModule, importHidden: bool): auto = - var ret = a.iface.addr - if importHidden: ret = a.ifaceHidden.addr - ret[] - -proc initRodIter*(it: var RodIter; config: ConfigRef, cache: IdentCache; - g: var PackedModuleGraph; module: FileIndex; - name: PIdent, importHidden: bool): PSym = - it.decoder = PackedDecoder( - lastModule: int32(-1), - lastLit: LitId(0), - lastFile: FileIndex(-1), - config: config, - cache: cache) - it.values = g[int module].interfSelect(importHidden).getOrDefault(name) - it.i = 0 - it.module = int(module) - if it.i < it.values.len: - result = loadSym(it.decoder, g, int(module), it.values[it.i]) - inc it.i - -proc initRodIterAllSyms*(it: var RodIter; config: ConfigRef, cache: IdentCache; - g: var PackedModuleGraph; module: FileIndex, importHidden: bool): PSym = - it.decoder = PackedDecoder( - lastModule: int32(-1), - lastLit: LitId(0), - lastFile: FileIndex(-1), - config: config, - cache: cache) - it.values = @[] - it.module = int(module) - for v in g[int module].interfSelect(importHidden).values: - it.values.add v - it.i = 0 - if it.i < it.values.len: - result = loadSym(it.decoder, g, int(module), it.values[it.i]) - inc it.i - -proc nextRodIter*(it: var RodIter; g: var PackedModuleGraph): PSym = - if it.i < it.values.len: - result = loadSym(it.decoder, g, it.module, it.values[it.i]) - inc it.i - -iterator interfaceSymbols*(config: ConfigRef, cache: IdentCache; - g: var PackedModuleGraph; module: FileIndex; - name: PIdent, importHidden: bool): PSym = - setupDecoder() - let values = g[int module].interfSelect(importHidden).getOrDefault(name) - for pid in values: - let s = loadSym(decoder, g, int(module), pid) - assert s != nil - yield s - -proc interfaceSymbol*(config: ConfigRef, cache: IdentCache; - g: var PackedModuleGraph; module: FileIndex; - name: PIdent, importHidden: bool): PSym = - setupDecoder() - let values = g[int module].interfSelect(importHidden).getOrDefault(name) - result = loadSym(decoder, g, int(module), values[0]) - -proc idgenFromLoadedModule*(m: LoadedModule): IdGenerator = - IdGenerator(module: m.module.itemId.module, symId: int32 m.fromDisk.syms.len, - typeId: int32 m.fromDisk.types.len) - -proc searchForCompilerproc*(m: LoadedModule; name: string): int32 = - # slow, linear search, but the results are cached: - for it in items(m.fromDisk.compilerProcs): - if m.fromDisk.strings[it[0]] == name: - return it[1] - return -1 - -# ------------------------- .rod file viewer --------------------------------- - -proc rodViewer*(rodfile: AbsoluteFile; config: ConfigRef, cache: IdentCache) = - var m: PackedModule - let err = loadRodFile(rodfile, m, config, ignoreConfig=true) - if err != ok: - config.quitOrRaise "Error: could not load: " & $rodfile.string & " reason: " & $err - - when true: - echo "exports:" - for ex in m.exports: - echo " ", m.strings[ex[0]], " local ID: ", ex[1] - assert ex[0] == m.syms[ex[1]].name - # ex[1] int32 - - echo "reexports:" - for ex in m.reexports: - echo " ", m.strings[ex[0]] - # reexports*: seq[(LitId, PackedItemId)] - - echo "hidden: " & $m.hidden.len - for ex in m.hidden: - echo " ", m.strings[ex[0]], " local ID: ", ex[1] - - echo "all symbols" - for i in 0..high(m.syms): - if m.syms[i].name != LitId(0): - echo " ", m.strings[m.syms[i].name], " local ID: ", i, " kind ", m.syms[i].kind - else: - echo " local ID: ", i, " kind ", m.syms[i].kind - - echo "symbols: ", m.syms.len, " types: ", m.types.len, - " top level nodes: ", m.topLevel.nodes.len, " other nodes: ", m.bodies.nodes.len, - " strings: ", m.strings.len, " numbers: ", m.numbers.len diff --git a/compiler/ic/integrity.nim b/compiler/ic/integrity.nim deleted file mode 100644 index d341fd653..000000000 --- a/compiler/ic/integrity.nim +++ /dev/null @@ -1,153 +0,0 @@ -# -# -# The Nim Compiler -# (c) Copyright 2021 Andreas Rumpf -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# - -## Integrity checking for a set of .rod files. -## The set must cover a complete Nim project. - -import sets - -when defined(nimPreviewSlimSystem): - import std/assertions - -import ".." / [ast, modulegraphs] -import packed_ast, bitabs, ic - -type - CheckedContext = object - g: ModuleGraph - thisModule: int32 - checkedSyms: HashSet[ItemId] - checkedTypes: HashSet[ItemId] - -proc checkType(c: var CheckedContext; typeId: PackedItemId) -proc checkForeignSym(c: var CheckedContext; symId: PackedItemId) -proc checkNode(c: var CheckedContext; tree: PackedTree; n: NodePos) - -proc checkTypeObj(c: var CheckedContext; typ: PackedType) = - for child in typ.types: - checkType(c, child) - if typ.n != emptyNodeId: - checkNode(c, c.g.packed[c.thisModule].fromDisk.bodies, NodePos typ.n) - if typ.sym != nilItemId: - checkForeignSym(c, typ.sym) - if typ.owner != nilItemId: - checkForeignSym(c, typ.owner) - checkType(c, typ.typeInst) - -proc checkType(c: var CheckedContext; typeId: PackedItemId) = - if typeId == nilItemId: return - let itemId = translateId(typeId, c.g.packed, c.thisModule, c.g.config) - if not c.checkedTypes.containsOrIncl(itemId): - let oldThisModule = c.thisModule - c.thisModule = itemId.module - checkTypeObj c, c.g.packed[itemId.module].fromDisk.types[itemId.item] - c.thisModule = oldThisModule - -proc checkSym(c: var CheckedContext; s: PackedSym) = - if s.name != LitId(0): - assert c.g.packed[c.thisModule].fromDisk.strings.hasLitId s.name - checkType c, s.typ - if s.ast != emptyNodeId: - checkNode(c, c.g.packed[c.thisModule].fromDisk.bodies, NodePos s.ast) - if s.owner != nilItemId: - checkForeignSym(c, s.owner) - -proc checkLocalSym(c: var CheckedContext; item: int32) = - let itemId = ItemId(module: c.thisModule, item: item) - if not c.checkedSyms.containsOrIncl(itemId): - checkSym c, c.g.packed[c.thisModule].fromDisk.syms[item] - -proc checkForeignSym(c: var CheckedContext; symId: PackedItemId) = - let itemId = translateId(symId, c.g.packed, c.thisModule, c.g.config) - if not c.checkedSyms.containsOrIncl(itemId): - let oldThisModule = c.thisModule - c.thisModule = itemId.module - checkSym c, c.g.packed[itemId.module].fromDisk.syms[itemId.item] - c.thisModule = oldThisModule - -proc checkNode(c: var CheckedContext; tree: PackedTree; n: NodePos) = - if tree[n.int].typeId != nilItemId: - checkType(c, tree[n.int].typeId) - case n.kind - of nkEmpty, nkNilLit, nkType, nkNilRodNode: - discard - of nkIdent: - assert c.g.packed[c.thisModule].fromDisk.strings.hasLitId n.litId - of nkSym: - checkLocalSym(c, tree.nodes[n.int].operand) - of directIntLit: - discard - of externIntLit, nkFloatLit..nkFloat128Lit: - assert c.g.packed[c.thisModule].fromDisk.numbers.hasLitId n.litId - of nkStrLit..nkTripleStrLit: - assert c.g.packed[c.thisModule].fromDisk.strings.hasLitId n.litId - of nkModuleRef: - let (n1, n2) = sons2(tree, n) - assert n1.kind == nkInt32Lit - assert n2.kind == nkInt32Lit - checkForeignSym(c, PackedItemId(module: n1.litId, item: tree.nodes[n2.int].operand)) - else: - for n0 in sonsReadonly(tree, n): - checkNode(c, tree, n0) - -proc checkTree(c: var CheckedContext; t: PackedTree) = - for p in allNodes(t): checkNode(c, t, p) - -proc checkLocalSymIds(c: var CheckedContext; m: PackedModule; symIds: seq[int32]) = - for symId in symIds: - assert symId >= 0 and symId < m.syms.len, $symId & " " & $m.syms.len - -proc checkModule(c: var CheckedContext; m: PackedModule) = - # We check that: - # - Every symbol references existing types and symbols. - # - Every tree node references existing types and symbols. - for i in 0..high(m.syms): - checkLocalSym c, int32(i) - - checkTree c, m.toReplay - checkTree c, m.topLevel - - for e in m.exports: - assert e[1] >= 0 and e[1] < m.syms.len - assert e[0] == m.syms[e[1]].name - - for e in m.compilerProcs: - assert e[1] >= 0 and e[1] < m.syms.len - assert e[0] == m.syms[e[1]].name - - checkLocalSymIds c, m, m.converters - checkLocalSymIds c, m, m.methods - checkLocalSymIds c, m, m.trmacros - checkLocalSymIds c, m, m.pureEnums - #[ - To do: Check all these fields: - - reexports*: seq[(LitId, PackedItemId)] - macroUsages*: seq[(PackedItemId, PackedLineInfo)] - - typeInstCache*: seq[(PackedItemId, PackedItemId)] - procInstCache*: seq[PackedInstantiation] - attachedOps*: seq[(TTypeAttachedOp, PackedItemId, PackedItemId)] - methodsPerType*: seq[(PackedItemId, int, PackedItemId)] - enumToStringProcs*: seq[(PackedItemId, PackedItemId)] - ]# - -proc checkIntegrity*(g: ModuleGraph) = - var c = CheckedContext(g: g) - for i in 0..high(g.packed): - # case statement here to enforce exhaustive checks. - case g.packed[i].status - of undefined: - discard "nothing to do" - of loading: - assert false, "cannot check integrity: Module still loading" - of stored, storing, outdated, loaded: - c.thisModule = int32 i - checkModule(c, g.packed[i].fromDisk) - diff --git a/compiler/ic/navigator.nim b/compiler/ic/navigator.nim deleted file mode 100644 index cbba591c5..000000000 --- a/compiler/ic/navigator.nim +++ /dev/null @@ -1,170 +0,0 @@ -# -# -# The Nim Compiler -# (c) Copyright 2021 Andreas Rumpf -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# - -## Supports the "nim check --ic:on --defusages:FILE,LINE,COL" -## IDE-like features. It uses the set of .rod files to accomplish -## its task. The set must cover a complete Nim project. - -import sets - -from os import nil -from std/private/miscdollars import toLocation - -when defined(nimPreviewSlimSystem): - import std/assertions - -import ".." / [ast, modulegraphs, msgs, options] -import packed_ast, bitabs, ic - -type - NavContext = object - g: ModuleGraph - thisModule: int32 - trackPos: PackedLineInfo - alreadyEmitted: HashSet[string] - outputSep: char # for easier testing, use short filenames and spaces instead of tabs. - -proc isTracked(current, trackPos: PackedLineInfo, tokenLen: int): bool = - if current.file == trackPos.file and current.line == trackPos.line: - let col = trackPos.col - if col >= current.col and col < current.col+tokenLen: - return true - -proc searchLocalSym(c: var NavContext; s: PackedSym; info: PackedLineInfo): bool = - result = s.name != LitId(0) and - isTracked(info, c.trackPos, c.g.packed[c.thisModule].fromDisk.strings[s.name].len) - -proc searchForeignSym(c: var NavContext; s: ItemId; info: PackedLineInfo): bool = - let name = c.g.packed[s.module].fromDisk.syms[s.item].name - result = name != LitId(0) and - isTracked(info, c.trackPos, c.g.packed[s.module].fromDisk.strings[name].len) - -const - EmptyItemId = ItemId(module: -1'i32, item: -1'i32) - -proc search(c: var NavContext; tree: PackedTree): ItemId = - # We use the linear representation here directly: - for i in 0..high(tree.nodes): - case tree.nodes[i].kind - of nkSym: - let item = tree.nodes[i].operand - if searchLocalSym(c, c.g.packed[c.thisModule].fromDisk.syms[item], tree.nodes[i].info): - return ItemId(module: c.thisModule, item: item) - of nkModuleRef: - if tree.nodes[i].info.line == c.trackPos.line and tree.nodes[i].info.file == c.trackPos.file: - let (n1, n2) = sons2(tree, NodePos i) - assert n1.kind == nkInt32Lit - assert n2.kind == nkInt32Lit - let pId = PackedItemId(module: n1.litId, item: tree.nodes[n2.int].operand) - let itemId = translateId(pId, c.g.packed, c.thisModule, c.g.config) - if searchForeignSym(c, itemId, tree.nodes[i].info): - return itemId - else: discard - return EmptyItemId - -proc isDecl(tree: PackedTree; n: NodePos): bool = - # XXX This is not correct yet. - const declarativeNodes = procDefs + {nkMacroDef, nkTemplateDef, - nkLetSection, nkVarSection, nkUsingStmt, nkConstSection, nkTypeSection, - nkIdentDefs, nkEnumTy, nkVarTuple} - result = n.int >= 0 and tree[n.int].kind in declarativeNodes - -proc usage(c: var NavContext; info: PackedLineInfo; isDecl: bool) = - var m = "" - var file = c.g.packed[c.thisModule].fromDisk.strings[info.file] - if c.outputSep == ' ': - file = os.extractFilename file - toLocation(m, file, info.line.int, info.col.int + ColOffset) - if not c.alreadyEmitted.containsOrIncl(m): - msgWriteln c.g.config, (if isDecl: "def" else: "usage") & c.outputSep & m - -proc list(c: var NavContext; tree: PackedTree; sym: ItemId) = - for i in 0..high(tree.nodes): - case tree.nodes[i].kind - of nkSym: - let item = tree.nodes[i].operand - if sym.item == item and sym.module == c.thisModule: - usage(c, tree.nodes[i].info, isDecl(tree, parent(NodePos i))) - of nkModuleRef: - let (n1, n2) = sons2(tree, NodePos i) - assert n1.kind == nkInt32Lit - assert n2.kind == nkInt32Lit - let pId = PackedItemId(module: n1.litId, item: tree.nodes[n2.int].operand) - let itemId = translateId(pId, c.g.packed, c.thisModule, c.g.config) - if itemId.item == sym.item and sym.module == itemId.module: - usage(c, tree.nodes[i].info, isDecl(tree, parent(NodePos i))) - else: discard - -proc searchForIncludeFile(g: ModuleGraph; fullPath: string): int = - for i in 0..high(g.packed): - for k in 1..high(g.packed[i].fromDisk.includes): - # we start from 1 because the first "include" file is - # the module's filename. - if os.cmpPaths(g.packed[i].fromDisk.strings[g.packed[i].fromDisk.includes[k][0]], fullPath) == 0: - return i - return -1 - -proc nav(g: ModuleGraph) = - # translate the track position to a packed position: - let unpacked = g.config.m.trackPos - var mid = unpacked.fileIndex.int - - let fullPath = toFullPath(g.config, unpacked.fileIndex) - - if g.packed[mid].status == undefined: - # check if 'mid' is an include file of some other module: - mid = searchForIncludeFile(g, fullPath) - - if mid < 0: - localError(g.config, unpacked, "unknown file name: " & fullPath) - return - - let fileId = g.packed[mid].fromDisk.strings.getKeyId(fullPath) - - if fileId == LitId(0): - internalError(g.config, unpacked, "cannot find a valid file ID") - return - - var c = NavContext( - g: g, - thisModule: int32 mid, - trackPos: PackedLineInfo(line: unpacked.line, col: unpacked.col, file: fileId), - outputSep: if isDefined(g.config, "nimIcNavigatorTests"): ' ' else: '\t' - ) - var symId = search(c, g.packed[mid].fromDisk.topLevel) - if symId == EmptyItemId: - symId = search(c, g.packed[mid].fromDisk.bodies) - - if symId == EmptyItemId: - localError(g.config, unpacked, "no symbol at this position") - return - - for i in 0..high(g.packed): - # case statement here to enforce exhaustive checks. - case g.packed[i].status - of undefined: - discard "nothing to do" - of loading: - assert false, "cannot check integrity: Module still loading" - of stored, storing, outdated, loaded: - c.thisModule = int32 i - list(c, g.packed[i].fromDisk.topLevel, symId) - list(c, g.packed[i].fromDisk.bodies, symId) - -proc navDefinition*(g: ModuleGraph) = nav(g) -proc navUsages*(g: ModuleGraph) = nav(g) -proc navDefusages*(g: ModuleGraph) = nav(g) - -proc writeRodFiles*(g: ModuleGraph) = - for i in 0..high(g.packed): - case g.packed[i].status - of undefined, loading, stored, loaded: - discard "nothing to do" - of storing, outdated: - closeRodFile(g, g.packed[i].module) diff --git a/compiler/ic/packed_ast.nim b/compiler/ic/packed_ast.nim deleted file mode 100644 index 87b1516fa..000000000 --- a/compiler/ic/packed_ast.nim +++ /dev/null @@ -1,419 +0,0 @@ -# -# -# The Nim Compiler -# (c) Copyright 2020 Andreas Rumpf -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# - -## Packed AST representation, mostly based on a seq of nodes. -## For IC support. Far future: Rewrite the compiler passes to -## use this representation directly in all the transformations, -## it is superior. - -import hashes, tables, strtabs -import bitabs -import ".." / [ast, options] - -when defined(nimPreviewSlimSystem): - import std/assertions - -type - SymId* = distinct int32 - ModuleId* = distinct int32 - NodePos* = distinct int - - NodeId* = distinct int32 - - PackedItemId* = object - module*: LitId # 0 if it's this module - item*: int32 # same as the in-memory representation - -const - nilItemId* = PackedItemId(module: LitId(0), item: -1.int32) - -const - emptyNodeId* = NodeId(-1) - -type - PackedLineInfo* = object - line*: uint16 - col*: int16 - file*: LitId - - PackedLib* = object - kind*: TLibKind - generated*: bool - isOverriden*: bool - name*: LitId - path*: NodeId - - PackedSym* = object - kind*: TSymKind - name*: LitId - typ*: PackedItemId - flags*: TSymFlags - magic*: TMagic - info*: PackedLineInfo - ast*: NodeId - owner*: PackedItemId - guard*: PackedItemId - bitsize*: int - alignment*: int # for alignment - options*: TOptions - position*: int - offset*: int - externalName*: LitId # instead of TLoc - locFlags*: TLocFlags - annex*: PackedLib - when hasFFI: - cname*: LitId - constraint*: NodeId - - PackedType* = object - kind*: TTypeKind - callConv*: TCallingConvention - #nodekind*: TNodeKind - flags*: TTypeFlags - types*: seq[PackedItemId] - n*: NodeId - #nodeflags*: TNodeFlags - sym*: PackedItemId - owner*: PackedItemId - size*: BiggestInt - align*: int16 - paddingAtEnd*: int16 - # not serialized: loc*: TLoc because it is backend-specific - typeInst*: PackedItemId - nonUniqueId*: int32 - - PackedNode* = object # 28 bytes - kind*: TNodeKind - flags*: TNodeFlags - operand*: int32 # for kind in {nkSym, nkSymDef}: SymId - # for kind in {nkStrLit, nkIdent, nkNumberLit}: LitId - # for kind in nkInt32Lit: direct value - # for non-atom kinds: the number of nodes (for easy skipping) - typeId*: PackedItemId - info*: PackedLineInfo - - PackedTree* = object ## usually represents a full Nim module - nodes*: seq[PackedNode] - - PackedInstantiation* = object - key*, sym*: PackedItemId - concreteTypes*: seq[PackedItemId] - -proc `==`*(a, b: SymId): bool {.borrow.} -proc hash*(a: SymId): Hash {.borrow.} - -proc `==`*(a, b: NodePos): bool {.borrow.} -#proc `==`*(a, b: PackedItemId): bool {.borrow.} -proc `==`*(a, b: NodeId): bool {.borrow.} - -proc newTreeFrom*(old: PackedTree): PackedTree = - result.nodes = @[] - when false: result.sh = old.sh - -when false: - proc declareSym*(tree: var PackedTree; kind: TSymKind; - name: LitId; info: PackedLineInfo): SymId = - result = SymId(tree.sh.syms.len) - tree.sh.syms.add PackedSym(kind: kind, name: name, flags: {}, magic: mNone, info: info) - - proc litIdFromName*(tree: PackedTree; name: string): LitId = - result = tree.sh.strings.getOrIncl(name) - - proc add*(tree: var PackedTree; kind: TNodeKind; token: string; info: PackedLineInfo) = - tree.nodes.add PackedNode(kind: kind, info: info, - operand: int32 getOrIncl(tree.sh.strings, token)) - - proc add*(tree: var PackedTree; kind: TNodeKind; info: PackedLineInfo) = - tree.nodes.add PackedNode(kind: kind, operand: 0, info: info) - -proc throwAwayLastNode*(tree: var PackedTree) = - tree.nodes.setLen(tree.nodes.len-1) - -proc addIdent*(tree: var PackedTree; s: LitId; info: PackedLineInfo) = - tree.nodes.add PackedNode(kind: nkIdent, operand: int32(s), info: info) - -proc addSym*(tree: var PackedTree; s: int32; info: PackedLineInfo) = - tree.nodes.add PackedNode(kind: nkSym, operand: s, info: info) - -proc addModuleId*(tree: var PackedTree; s: ModuleId; info: PackedLineInfo) = - tree.nodes.add PackedNode(kind: nkInt32Lit, operand: int32(s), info: info) - -proc addSymDef*(tree: var PackedTree; s: SymId; info: PackedLineInfo) = - tree.nodes.add PackedNode(kind: nkSym, operand: int32(s), info: info) - -proc isAtom*(tree: PackedTree; pos: int): bool {.inline.} = tree.nodes[pos].kind <= nkNilLit - -proc copyTree*(dest: var PackedTree; tree: PackedTree; n: NodePos) = - # and this is why the IR is superior. We can copy subtrees - # via a linear scan. - let pos = n.int - let L = if isAtom(tree, pos): 1 else: tree.nodes[pos].operand - let d = dest.nodes.len - dest.nodes.setLen(d + L) - for i in 0.. nkNilLit - let distance = int32(tree.nodes.len - pos) - tree.nodes[pos].operand = distance - -proc len*(tree: PackedTree): int {.inline.} = tree.nodes.len - -proc `[]`*(tree: PackedTree; i: int): lent PackedNode {.inline.} = - tree.nodes[i] - -proc nextChild(tree: PackedTree; pos: var int) {.inline.} = - if tree.nodes[pos].kind > nkNilLit: - assert tree.nodes[pos].operand > 0 - inc pos, tree.nodes[pos].operand - else: - inc pos - -iterator sonsReadonly*(tree: PackedTree; n: NodePos): NodePos = - var pos = n.int - assert tree.nodes[pos].kind > nkNilLit - let last = pos + tree.nodes[pos].operand - inc pos - while pos < last: - yield NodePos pos - nextChild tree, pos - -iterator sons*(dest: var PackedTree; tree: PackedTree; n: NodePos): NodePos = - let patchPos = prepare(dest, tree, n) - for x in sonsReadonly(tree, n): yield x - patch dest, patchPos - -iterator isons*(dest: var PackedTree; tree: PackedTree; - n: NodePos): (int, NodePos) = - var i = 0 - for ch0 in sons(dest, tree, n): - yield (i, ch0) - inc i - -iterator sonsFrom1*(tree: PackedTree; n: NodePos): NodePos = - var pos = n.int - assert tree.nodes[pos].kind > nkNilLit - let last = pos + tree.nodes[pos].operand - inc pos - if pos < last: - nextChild tree, pos - while pos < last: - yield NodePos pos - nextChild tree, pos - -iterator sonsWithoutLast2*(tree: PackedTree; n: NodePos): NodePos = - var count = 0 - for child in sonsReadonly(tree, n): - inc count - var pos = n.int - assert tree.nodes[pos].kind > nkNilLit - let last = pos + tree.nodes[pos].operand - inc pos - while pos < last and count > 2: - yield NodePos pos - dec count - nextChild tree, pos - -proc parentImpl(tree: PackedTree; n: NodePos): NodePos = - # finding the parent of a node is rather easy: - var pos = n.int - 1 - while pos >= 0 and (isAtom(tree, pos) or (pos + tree.nodes[pos].operand - 1 < n.int)): - dec pos - #assert pos >= 0, "node has no parent" - result = NodePos(pos) - -template parent*(n: NodePos): NodePos = parentImpl(tree, n) - -proc hasXsons*(tree: PackedTree; n: NodePos; x: int): bool = - var count = 0 - if tree.nodes[n.int].kind > nkNilLit: - for child in sonsReadonly(tree, n): inc count - result = count == x - -proc hasAtLeastXsons*(tree: PackedTree; n: NodePos; x: int): bool = - if tree.nodes[n.int].kind > nkNilLit: - var count = 0 - for child in sonsReadonly(tree, n): - inc count - if count >= x: return true - return false - -proc firstSon*(tree: PackedTree; n: NodePos): NodePos {.inline.} = - NodePos(n.int+1) -proc kind*(tree: PackedTree; n: NodePos): TNodeKind {.inline.} = - tree.nodes[n.int].kind -proc litId*(tree: PackedTree; n: NodePos): LitId {.inline.} = - LitId tree.nodes[n.int].operand -proc info*(tree: PackedTree; n: NodePos): PackedLineInfo {.inline.} = - tree.nodes[n.int].info - -template typ*(n: NodePos): PackedItemId = - tree.nodes[n.int].typeId -template flags*(n: NodePos): TNodeFlags = - tree.nodes[n.int].flags - -template operand*(n: NodePos): int32 = - tree.nodes[n.int].operand - -proc span*(tree: PackedTree; pos: int): int {.inline.} = - if isAtom(tree, pos): 1 else: tree.nodes[pos].operand - -proc sons2*(tree: PackedTree; n: NodePos): (NodePos, NodePos) = - assert(not isAtom(tree, n.int)) - let a = n.int+1 - let b = a + span(tree, a) - result = (NodePos a, NodePos b) - -proc sons3*(tree: PackedTree; n: NodePos): (NodePos, NodePos, NodePos) = - assert(not isAtom(tree, n.int)) - let a = n.int+1 - let b = a + span(tree, a) - let c = b + span(tree, b) - result = (NodePos a, NodePos b, NodePos c) - -proc ithSon*(tree: PackedTree; n: NodePos; i: int): NodePos = - if tree.nodes[n.int].kind > nkNilLit: - var count = 0 - for child in sonsReadonly(tree, n): - if count == i: return child - inc count - assert false, "node has no i-th child" - -when false: - proc `@`*(tree: PackedTree; lit: LitId): lent string {.inline.} = - tree.sh.strings[lit] - -template kind*(n: NodePos): TNodeKind = tree.nodes[n.int].kind -template info*(n: NodePos): PackedLineInfo = tree.nodes[n.int].info -template litId*(n: NodePos): LitId = LitId tree.nodes[n.int].operand - -template symId*(n: NodePos): SymId = SymId tree.nodes[n.int].operand - -proc firstSon*(n: NodePos): NodePos {.inline.} = NodePos(n.int+1) - -when false: - # xxx `nkStrLit` or `nkStrLit..nkTripleStrLit:` below? - proc strLit*(tree: PackedTree; n: NodePos): lent string = - assert n.kind == nkStrLit - result = tree.sh.strings[LitId tree.nodes[n.int].operand] - - proc strVal*(tree: PackedTree; n: NodePos): string = - assert n.kind == nkStrLit - result = tree.sh.strings[LitId tree.nodes[n.int].operand] - #result = cookedStrLit(raw) - - proc filenameVal*(tree: PackedTree; n: NodePos): string = - case n.kind - of nkStrLit: - result = strVal(tree, n) - of nkIdent: - result = tree.sh.strings[n.litId] - of nkSym: - result = tree.sh.strings[tree.sh.syms[int n.symId].name] - else: - result = "" - - proc identAsStr*(tree: PackedTree; n: NodePos): lent string = - assert n.kind == nkIdent - result = tree.sh.strings[LitId tree.nodes[n.int].operand] - -const - externIntLit* = {nkCharLit, - nkIntLit, - nkInt8Lit, - nkInt16Lit, - nkInt64Lit, - nkUIntLit, - nkUInt8Lit, - nkUInt16Lit, - nkUInt32Lit, - nkUInt64Lit} # nkInt32Lit is missing by design! - - externSIntLit* = {nkIntLit, nkInt8Lit, nkInt16Lit, nkInt64Lit} - externUIntLit* = {nkUIntLit, nkUInt8Lit, nkUInt16Lit, nkUInt32Lit, nkUInt64Lit} - directIntLit* = nkInt32Lit - -when false: - proc identIdImpl(tree: PackedTree; n: NodePos): LitId = - if n.kind == nkIdent: - result = n.litId - elif n.kind == nkSym: - result = tree.sh.syms[int n.symId].name - else: - result = LitId(0) - - template identId*(n: NodePos): LitId = identIdImpl(tree, n) - -template copyInto*(dest, n, body) = - let patchPos = prepare(dest, tree, n) - body - patch dest, patchPos - -template copyIntoKind*(dest, kind, info, body) = - let patchPos = prepare(dest, kind, info) - body - patch dest, patchPos - -when false: - proc hasPragma*(tree: PackedTree; n: NodePos; pragma: string): bool = - let litId = tree.sh.strings.getKeyId(pragma) - if litId == LitId(0): - return false - assert n.kind == nkPragma - for ch0 in sonsReadonly(tree, n): - if ch0.kind == nkExprColonExpr: - if ch0.firstSon.identId == litId: - return true - elif ch0.identId == litId: - return true - -proc getNodeId*(tree: PackedTree): NodeId {.inline.} = NodeId tree.nodes.len - -when false: - proc produceError*(dest: var PackedTree; tree: PackedTree; n: NodePos; msg: string) = - let patchPos = prepare(dest, nkError, n.info) - dest.add nkStrLit, msg, n.info - copyTree(dest, tree, n) - patch dest, patchPos - -iterator allNodes*(tree: PackedTree): NodePos = - var p = 0 - while p < tree.len: - yield NodePos(p) - let s = span(tree, p) - inc p, s - -proc toPackedItemId*(item: int32): PackedItemId {.inline.} = - PackedItemId(module: LitId(0), item: item) diff --git a/compiler/ic/replayer.nim b/compiler/ic/replayer.nim deleted file mode 100644 index 8eee0b3d8..000000000 --- a/compiler/ic/replayer.nim +++ /dev/null @@ -1,160 +0,0 @@ -# -# -# The Nim Compiler -# (c) Copyright 2020 Andreas Rumpf -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# - -## Module that contains code to replay global VM state changes and pragma -## state like ``{.compile: "foo.c".}``. For IC (= Incremental compilation) -## support. - -import ".." / [ast, modulegraphs, trees, extccomp, btrees, - msgs, lineinfos, pathutils, options, cgmeth] - -import tables - -when defined(nimPreviewSlimSystem): - import std/assertions - -import packed_ast, ic, bitabs - -proc replayStateChanges*(module: PSym; g: ModuleGraph) = - let list = module.ast - assert list != nil - assert list.kind == nkStmtList - for n in list: - assert n.kind == nkReplayAction - # Fortunately only a tiny subset of the available pragmas need to - # be replayed here. This is always a subset of ``pragmas.stmtPragmas``. - if n.len >= 2: - internalAssert g.config, n[0].kind == nkStrLit and n[1].kind == nkStrLit - case n[0].strVal - of "hint": message(g.config, n.info, hintUser, n[1].strVal) - of "warning": message(g.config, n.info, warnUser, n[1].strVal) - of "error": localError(g.config, n.info, errUser, n[1].strVal) - of "compile": - internalAssert g.config, n.len == 4 and n[2].kind == nkStrLit - let cname = AbsoluteFile n[1].strVal - var cf = Cfile(nimname: splitFile(cname).name, cname: cname, - obj: AbsoluteFile n[2].strVal, - flags: {CfileFlag.External}, - customArgs: n[3].strVal) - extccomp.addExternalFileToCompile(g.config, cf) - of "link": - extccomp.addExternalFileToLink(g.config, AbsoluteFile n[1].strVal) - of "passl": - extccomp.addLinkOption(g.config, n[1].strVal) - of "passc": - extccomp.addCompileOption(g.config, n[1].strVal) - of "localpassc": - extccomp.addLocalCompileOption(g.config, n[1].strVal, toFullPathConsiderDirty(g.config, module.info.fileIndex)) - of "cppdefine": - options.cppDefine(g.config, n[1].strVal) - of "inc": - let destKey = n[1].strVal - let by = n[2].intVal - let v = getOrDefault(g.cacheCounters, destKey) - g.cacheCounters[destKey] = v+by - of "put": - let destKey = n[1].strVal - let key = n[2].strVal - let val = n[3] - if not contains(g.cacheTables, destKey): - g.cacheTables[destKey] = initBTree[string, PNode]() - if not contains(g.cacheTables[destKey], key): - g.cacheTables[destKey].add(key, val) - else: - internalError(g.config, n.info, "key already exists: " & key) - of "incl": - let destKey = n[1].strVal - let val = n[2] - if not contains(g.cacheSeqs, destKey): - g.cacheSeqs[destKey] = newTree(nkStmtList, val) - else: - block search: - for existing in g.cacheSeqs[destKey]: - if exprStructuralEquivalent(existing, val, strictSymEquality=true): - break search - g.cacheSeqs[destKey].add val - of "add": - let destKey = n[1].strVal - let val = n[2] - if not contains(g.cacheSeqs, destKey): - g.cacheSeqs[destKey] = newTree(nkStmtList, val) - else: - g.cacheSeqs[destKey].add val - else: - internalAssert g.config, false - -proc replayBackendProcs*(g: ModuleGraph; module: int) = - for it in mitems(g.packed[module].fromDisk.attachedOps): - let key = translateId(it[0], g.packed, module, g.config) - let op = it[1] - let tmp = translateId(it[2], g.packed, module, g.config) - let symId = FullId(module: tmp.module, packed: it[2]) - g.attachedOps[op][key] = LazySym(id: symId, sym: nil) - - for it in mitems(g.packed[module].fromDisk.enumToStringProcs): - let key = translateId(it[0], g.packed, module, g.config) - let tmp = translateId(it[1], g.packed, module, g.config) - let symId = FullId(module: tmp.module, packed: it[1]) - g.enumToStringProcs[key] = LazySym(id: symId, sym: nil) - -proc replayGenericCacheInformation*(g: ModuleGraph; module: int) = - ## We remember the generic instantiations a module performed - ## in order to to avoid the code bloat that generic code tends - ## to imply. This is cheaper than deduplication of identical - ## generic instantiations. However, deduplication is more - ## powerful and general and I hope to implement it soon too - ## (famous last words). - assert g.packed[module].status == loaded - for it in g.packed[module].fromDisk.typeInstCache: - let key = translateId(it[0], g.packed, module, g.config) - g.typeInstCache.mgetOrPut(key, @[]).add LazyType(id: FullId(module: module, packed: it[1]), typ: nil) - - for it in mitems(g.packed[module].fromDisk.procInstCache): - let key = translateId(it.key, g.packed, module, g.config) - let sym = translateId(it.sym, g.packed, module, g.config) - var concreteTypes = newSeq[FullId](it.concreteTypes.len) - for i in 0..high(it.concreteTypes): - let tmp = translateId(it.concreteTypes[i], g.packed, module, g.config) - concreteTypes[i] = FullId(module: tmp.module, packed: it.concreteTypes[i]) - - g.procInstCache.mgetOrPut(key, @[]).add LazyInstantiation( - module: module, sym: FullId(module: sym.module, packed: it.sym), - concreteTypes: concreteTypes, inst: nil) - - for it in mitems(g.packed[module].fromDisk.methodsPerType): - let key = translateId(it[0], g.packed, module, g.config) - let col = it[1] - let tmp = translateId(it[2], g.packed, module, g.config) - let symId = FullId(module: tmp.module, packed: it[2]) - g.methodsPerType.mgetOrPut(key, @[]).add (col, LazySym(id: symId, sym: nil)) - - replayBackendProcs(g, module) - - for it in mitems(g.packed[module].fromDisk.methods): - let sym = loadSymFromId(g.config, g.cache, g.packed, module, - PackedItemId(module: LitId(0), item: it)) - methodDef(g, g.idgen, sym) - - when false: - # not used anymore: - for it in mitems(g.packed[module].fromDisk.compilerProcs): - let symId = FullId(module: module, packed: PackedItemId(module: LitId(0), item: it[1])) - g.lazyCompilerprocs[g.packed[module].fromDisk.sh.strings[it[0]]] = symId - - for it in mitems(g.packed[module].fromDisk.converters): - let symId = FullId(module: module, packed: PackedItemId(module: LitId(0), item: it)) - g.ifaces[module].converters.add LazySym(id: symId, sym: nil) - - for it in mitems(g.packed[module].fromDisk.trmacros): - let symId = FullId(module: module, packed: PackedItemId(module: LitId(0), item: it)) - g.ifaces[module].patterns.add LazySym(id: symId, sym: nil) - - for it in mitems(g.packed[module].fromDisk.pureEnums): - let symId = FullId(module: module, packed: PackedItemId(module: LitId(0), item: it)) - g.ifaces[module].pureEnums.add LazySym(id: symId, sym: nil) diff --git a/compiler/ic/rodfiles.nim b/compiler/ic/rodfiles.nim deleted file mode 100644 index e492624d0..000000000 --- a/compiler/ic/rodfiles.nim +++ /dev/null @@ -1,249 +0,0 @@ -# -# -# The Nim Compiler -# (c) Copyright 2020 Andreas Rumpf -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# - -## Low level binary format used by the compiler to store and load various AST -## and related data. -## -## NB: this is incredibly low level and if you're interested in how the -## compiler works and less a storage format, you're probably looking for -## the `ic` or `packed_ast` modules to understand the logical format. - -from typetraits import supportsCopyMem - -when defined(nimPreviewSlimSystem): - import std/[syncio, assertions] - -## Overview -## ======== -## `RodFile` represents a Rod File (versioned binary format), and the -## associated data for common interactions such as IO and error tracking -## (`RodFileError`). The file format broken up into sections (`RodSection`) -## and preceded by a header (see: `cookie`). The precise layout, section -## ordering and data following the section are determined by the user. See -## `ic.loadRodFile`. -## -## A basic but "wrong" example of the lifecycle: -## --------------------------------------------- -## 1. `create` or `open` - create a new one or open an existing -## 2. `storeHeader` - header info -## 3. `storePrim` or `storeSeq` - save your stuff -## 4. `close` - and we're done -## -## Now read the bits below to understand what's missing. -## -## ### Issues with the Example -## Missing Sections: -## This is a low level API, so headers and sections need to be stored and -## loaded by the user, see `storeHeader` & `loadHeader` and `storeSection` & -## `loadSection`, respectively. -## -## No Error Handling: -## The API is centered around IO and prone to error, each operation checks or -## sets the `RodFile.err` field. A user of this API needs to handle these -## appropriately. -## -## API Notes -## ========= -## -## Valid inputs for Rod files -## -------------------------- -## ASTs, hopes, dreams, and anything as long as it and any children it may have -## support `copyMem`. This means anything that is not a pointer and that does not contain a pointer. At a glance these are: -## * string -## * objects & tuples (fields are recursed) -## * sequences AKA `seq[T]` -## -## Note on error handling style -## ---------------------------- -## A flag based approach is used where operations no-op in case of a -## preexisting error and set the flag if they encounter one. -## -## Misc -## ---- -## * 'Prim' is short for 'primitive', as in a non-sequence type - -type - RodSection* = enum - versionSection - configSection - stringsSection - checkSumsSection - depsSection - numbersSection - exportsSection - hiddenSection - reexportsSection - compilerProcsSection - trmacrosSection - convertersSection - methodsSection - pureEnumsSection - toReplaySection - topLevelSection - bodiesSection - symsSection - typesSection - typeInstCacheSection - procInstCacheSection - attachedOpsSection - methodsPerTypeSection - enumToStringProcsSection - typeInfoSection # required by the backend - backendFlagsSection - aliveSymsSection # beware, this is stored in a `.alivesyms` file. - - RodFileError* = enum - ok, tooBig, cannotOpen, ioFailure, wrongHeader, wrongSection, configMismatch, - includeFileChanged - - RodFile* = object - f*: File - currentSection*: RodSection # for error checking - err*: RodFileError # little experiment to see if this works - # better than exceptions. - -const - RodVersion = 1 - cookie = [byte(0), byte('R'), byte('O'), byte('D'), - byte(sizeof(int)*8), byte(system.cpuEndian), byte(0), byte(RodVersion)] - -proc setError(f: var RodFile; err: RodFileError) {.inline.} = - f.err = err - #raise newException(IOError, "IO error") - -proc storePrim*(f: var RodFile; s: string) = - ## Stores a string. - ## The len is prefixed to allow for later retreival. - if f.err != ok: return - if s.len >= high(int32): - setError f, tooBig - return - var lenPrefix = int32(s.len) - if writeBuffer(f.f, addr lenPrefix, sizeof(lenPrefix)) != sizeof(lenPrefix): - setError f, ioFailure - else: - if s.len != 0: - if writeBuffer(f.f, unsafeAddr(s[0]), s.len) != s.len: - setError f, ioFailure - -proc storePrim*[T](f: var RodFile; x: T) = - ## Stores a non-sequence/string `T`. - ## If `T` doesn't support `copyMem` and is an object or tuple then the fields - ## are written -- the user from context will need to know which `T` to load. - if f.err != ok: return - when supportsCopyMem(T): - if writeBuffer(f.f, unsafeAddr(x), sizeof(x)) != sizeof(x): - setError f, ioFailure - elif T is tuple: - for y in fields(x): - storePrim(f, y) - elif T is object: - for y in fields(x): - when y is seq: - storeSeq(f, y) - else: - storePrim(f, y) - else: - {.error: "unsupported type for 'storePrim'".} - -proc storeSeq*[T](f: var RodFile; s: seq[T]) = - ## Stores a sequence of `T`s, with the len as a prefix for later retrieval. - if f.err != ok: return - if s.len >= high(int32): - setError f, tooBig - return - var lenPrefix = int32(s.len) - if writeBuffer(f.f, addr lenPrefix, sizeof(lenPrefix)) != sizeof(lenPrefix): - setError f, ioFailure - else: - for i in 0.. 0: - if readBuffer(f.f, unsafeAddr(s[0]), s.len) != s.len: - setError f, ioFailure - -proc loadPrim*[T](f: var RodFile; x: var T) = - ## Load a non-sequence/string `T`. - if f.err != ok: return - when supportsCopyMem(T): - if readBuffer(f.f, unsafeAddr(x), sizeof(x)) != sizeof(x): - setError f, ioFailure - elif T is tuple: - for y in fields(x): - loadPrim(f, y) - elif T is object: - for y in fields(x): - when y is seq: - loadSeq(f, y) - else: - loadPrim(f, y) - else: - {.error: "unsupported type for 'loadPrim'".} - -proc loadSeq*[T](f: var RodFile; s: var seq[T]) = - ## `T` must be compatible with `copyMem`, see `loadPrim` - if f.err != ok: return - var lenPrefix = int32(0) - if readBuffer(f.f, addr lenPrefix, sizeof(lenPrefix)) != sizeof(lenPrefix): - setError f, ioFailure - else: - s = newSeq[T](lenPrefix) - for i in 0.. 0: - (result[0][^1], result[1]) = splitPragmas(c, result[0][^1]) - -proc importSymbol(c: PContext, n: PNode, fromMod: PSym; importSet: var IntSet) = - let (n, kws) = splitPragmas(c, n) - if kws.len > 0: - globalError(c.config, n.info, "unexpected pragma") - +proc importSymbol(c: PContext, n: PNode, fromMod: PSym) = let ident = lookups.considerQuotedIdent(c, n) - let s = someSym(c.graph, fromMod, ident) + let s = strTableGet(fromMod.tab, ident) if s == nil: errorUndeclaredIdentifier(c, n.info, ident.s) else: @@ -141,77 +84,34 @@ 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 - var e = initModuleIter(it, c.graph, fromMod, s.name) + var it: TIdentIter + var e = initIdentIter(it, fromMod.tab, s.name) while e != nil: if e.name.id != s.name.id: internalError(c.config, n.info, "importSymbol: 3") if s.kind in ExportableSymKinds: - rawImportSymbol(c, e, fromMod, importSet) - e = nextModuleIter(it, c.graph) + rawImportSymbol(c, e, fromMod) + e = nextIdentIter(it, fromMod.tab) else: - rawImportSymbol(c, s, fromMod, importSet) - suggestSym(c.graph, n.info, s, c.graph.usageSym, false) - -proc addImport(c: PContext; im: sink ImportedModule) = - for i in 0..high(c.imports): - if c.imports[i].m == im.m: - # we have already imported the module: Check which import - # is more "powerful": - case c.imports[i].mode - of importAll: discard "already imported all symbols" - of importSet: - case im.mode - of importAll, importExcept: - # XXX: slightly wrong semantics for 'importExcept'... - # But we should probably change the spec and disallow this case. - c.imports[i] = im - of importSet: - # merge the import sets: - c.imports[i].imported.incl im.imported - of importExcept: - case im.mode - of importAll: - c.imports[i] = im - of importSet: - discard - of importExcept: - var cut = initIntSet() - # only exclude what is consistent between the two sets: - for j in im.exceptSet: - if j in c.imports[i].exceptSet: - cut.incl j - c.imports[i].exceptSet = cut - return - c.imports.add im - -template addUnnamedIt(c: PContext, fromMod: PSym; filter: untyped) {.dirty.} = - for it in mitems c.graph.ifaces[fromMod.position].converters: - if filter: - loadPackedSym(c.graph, it) - if sfExported in it.sym.flags: - addConverter(c, it) - for it in mitems c.graph.ifaces[fromMod.position].patterns: - if filter: - loadPackedSym(c.graph, it) - if sfExported in it.sym.flags: - addPattern(c, it) - for it in mitems c.graph.ifaces[fromMod.position].pureEnums: - if filter: - loadPackedSym(c.graph, it) - importPureEnumFields(c, it.sym, it.sym.typ) + rawImportSymbol(c, s, fromMod) + suggestSym(c.config, n.info, s, c.graph.usageSym, false) proc importAllSymbolsExcept(c: PContext, fromMod: PSym, exceptSet: IntSet) = - c.addImport ImportedModule(m: fromMod, mode: importExcept, exceptSet: exceptSet) - addUnnamedIt(c, fromMod, it.sym.name.id notin exceptSet) + var i: TTabIter + var s = initTabIter(i, fromMod.tab) + while s != nil: + if s.kind != skModule: + if s.kind != skEnumField: + if s.kind notin ExportableSymKinds: + internalError(c.config, s.info, "importAllSymbols: " & $s.kind & " " & s.name.s) + if exceptSet.isNil or s.name.id notin exceptSet: + rawImportSymbol(c, s, fromMod) + s = nextIter(i, fromMod.tab) proc importAllSymbols*(c: PContext, fromMod: PSym) = - c.addImport ImportedModule(m: fromMod, mode: importAll) - addUnnamedIt(c, fromMod, true) - when false: - var exceptSet: IntSet - importAllSymbolsExcept(c, fromMod, exceptSet) + var exceptSet: IntSet + importAllSymbolsExcept(c, fromMod, exceptSet) -proc importForwarded(c: PContext, n: PNode, exceptSet: IntSet; fromMod: PSym; importSet: var IntSet) = +proc importForwarded(c: PContext, n: PNode, exceptSet: IntSet; fromMod: PSym) = if n.isNil: return case n.kind of nkExportStmt: @@ -221,55 +121,27 @@ proc importForwarded(c: PContext, n: PNode, exceptSet: IntSet; fromMod: PSym; im if s.kind == skModule: importAllSymbolsExcept(c, s, exceptSet) elif exceptSet.isNil or s.name.id notin exceptSet: - rawImportSymbol(c, s, fromMod, importSet) + rawImportSymbol(c, s, fromMod) of nkExportExceptStmt: localError(c.config, n.info, "'export except' not implemented") else: for i in 0..n.safeLen-1: - importForwarded(c, n[i], exceptSet, fromMod, importSet) + importForwarded(c, n[i], exceptSet, fromMod) -proc importModuleAs(c: PContext; n: PNode, realModule: PSym, importHidden: bool): PSym = +proc importModuleAs(c: PContext; n: PNode, realModule: PSym): PSym = result = realModule - template createModuleAliasImpl(ident): untyped = - createModuleAlias(realModule, nextSymId c.idgen, ident, n.info, c.config.options) + c.unusedImports.add((realModule, n.info)) 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") elif n[1].ident.id != realModule.name.id: # some misguided guy will write 'import abc.foo as foo' ... - result = createModuleAliasImpl(n[1].ident) - if result == realModule: - # avoids modifying `realModule`, see D20201209T194412 for `import {.all.}` - result = createModuleAliasImpl(realModule.name) - if importHidden: - result.options.incl optImportHidden - c.unusedImports.add((result, n.info)) - c.importModuleMap[result.id] = realModule.id + result = createModuleAlias(realModule, n[1].ident, realModule.info, + c.config.options) -proc transformImportAs(c: PContext; n: PNode): tuple[node: PNode, importHidden: bool] = - var ret: typeof(result) - proc processPragma(n2: PNode): PNode = - let (result2, kws) = splitPragmas(c, n2) - result = result2 - for ai in kws: - case ai - of wImportHidden: ret.importHidden = true - else: globalError(c.config, n.info, "invalid pragma, expected: " & ${wImportHidden}) - - if n.kind == nkInfix and considerQuotedIdent(c, n[0]).s == "as": - ret.node = newNodeI(nkImportAs, n.info) - ret.node.add n[1].processPragma - ret.node.add n[2] - else: - ret.node = n.processPragma - return ret - -proc myImportModule(c: PContext, n: var PNode, importStmtResult: PNode): PSym = - let transf = transformImportAs(c, n) - n = transf.node +proc myImportModule(c: PContext, n: PNode; importStmtResult: PNode): PSym = let f = checkModuleName(c.config, n) if f != InvalidFileIdx: - addImportFileDep(c, f) let L = c.graph.importStack.len let recursion = c.graph.importStack.find(f) c.graph.importStack.add f @@ -282,42 +154,44 @@ proc myImportModule(c: PContext, n: var PNode, importStmtResult: PNode): PSym = toFullPath(c.config, c.graph.importStack[i+1]) c.recursiveDep = err - var realModule: PSym discard pushOptionEntry(c) - realModule = c.graph.importModuleCallback(c.graph, c.module, f) - result = importModuleAs(c, n, realModule, transf.importHidden) + result = importModuleAs(c, n, c.graph.importModuleCallback(c.graph, c.module, f)) popOptionEntry(c) #echo "set back to ", L c.graph.importStack.setLen(L) # we cannot perform this check reliably because of - # test: modules/import_in_config) # xxx is that still true? - if realModule == c.module: - localError(c.config, n.info, "module '$1' cannot import itself" % realModule.name.s) - if sfDeprecated in realModule.flags: - var prefix = "" - if realModule.constraint != nil: prefix = realModule.constraint.strVal & "; " - message(c.config, n.info, warnDeprecated, prefix & realModule.name.s & " is deprecated") - suggestSym(c.graph, n.info, result, c.graph.usageSym, false) + # test: modules/import_in_config) + when true: + if result.info.fileIndex == c.module.info.fileIndex and + result.info.fileIndex == n.info.fileIndex: + localError(c.config, n.info, "A module cannot import itself") + if sfDeprecated in result.flags: + if result.constraint != nil: + message(c.config, n.info, warnDeprecated, result.constraint.strVal & "; " & result.name.s & " is deprecated") + else: + message(c.config, n.info, warnDeprecated, result.name.s & " is deprecated") + suggestSym(c.config, n.info, result, c.graph.usageSym, false) importStmtResult.add newSymNode(result, n.info) #newStrNode(toFullPath(c.config, f), n.info) -proc afterImport(c: PContext, m: PSym) = - # fixes bug #17510, for re-exported symbols - let realModuleId = c.importModuleMap[m.id] - for s in allSyms(c.graph, m): - if s.owner.id != realModuleId: - c.exportIndirections.incl((m.id, s.id)) +proc transformImportAs(c: PContext; n: PNode): PNode = + if n.kind == nkInfix and considerQuotedIdent(c, n[0]).s == "as": + result = newNodeI(nkImportAs, n.info) + result.add n[1] + result.add n[2] + else: + result = n proc impMod(c: PContext; it: PNode; importStmtResult: PNode) = - var it = it + let it = transformImportAs(c, it) let m = myImportModule(c, it, importStmtResult) if m != nil: + var emptySet: IntSet # ``addDecl`` needs to be done before ``importAllSymbols``! addDecl(c, m, it.info) # add symbol to symbol table of module - importAllSymbols(c, m) + importAllSymbolsExcept(c, m, emptySet) #importForwarded(c, m.ast, emptySet, m) - afterImport(c, m) proc evalImport*(c: PContext, n: PNode): PNode = result = newNodeI(nkImportStmt, n.info) @@ -346,25 +220,22 @@ proc evalImport*(c: PContext, n: PNode): PNode = proc evalFrom*(c: PContext, n: PNode): PNode = result = newNodeI(nkImportStmt, n.info) checkMinSonsLen(n, 2, c.config) + n[0] = transformImportAs(c, n[0]) var m = myImportModule(c, n[0], result) if m != nil: n[0] = newSymNode(m) addDecl(c, m, n.info) # add symbol to symbol table of module - - var im = ImportedModule(m: m, mode: importSet, imported: initIntSet()) for i in 1.. 0, "cannot find file name for DB ID " & $dbId + result = fileInfoIdx(conf, AbsoluteFile fullpath) + + + proc addModuleDep*(incr: var IncrementalCtx; conf: ConfigRef; + module, fileIdx: FileIndex; + isIncludeFile: bool) = + if conf.symbolFiles != v2Sf: return + + let a = toDbFileId(incr, conf, module) + let b = toDbFileId(incr, conf, fileIdx) + + incr.db.exec(sql"insert into deps(module, dependency, isIncludeFile) values (?, ?, ?)", + a, b, ord(isIncludeFile)) + + # --------------- Database model --------------------------------------------- + + proc createDb*(db: DbConn) = + db.exec(sql""" + create table if not exists controlblock( + idgen integer not null + ); + """) + + db.exec(sql""" + create table if not exists config( + config varchar(8000) not null + ); + """) + + db.exec(sql""" + create table if not exists filenames( + id integer primary key, + nimid integer not null, + fullpath varchar(8000) not null, + fullHash varchar(256) not null + ); + """) + db.exec sql"create index if not exists FilenameIx on filenames(fullpath);" + + db.exec(sql""" + create table if not exists modules( + id integer primary key, + nimid integer not null, + fullpath varchar(8000) not null, + interfHash varchar(256) not null, + fullHash varchar(256) not null, + + created timestamp not null default (DATETIME('now')) + );""") + db.exec(sql"""create unique index if not exists SymNameIx on modules(fullpath);""") + + db.exec(sql""" + create table if not exists deps( + id integer primary key, + module integer not null, + dependency integer not null, + isIncludeFile integer not null, + foreign key (module) references filenames(id), + foreign key (dependency) references filenames(id) + );""") + db.exec(sql"""create index if not exists DepsIx on deps(module);""") + + db.exec(sql""" + create table if not exists types( + id integer primary key, + nimid integer not null, + module integer not null, + data blob not null, + foreign key (module) references module(id) + ); + """) + db.exec sql"create index TypeByModuleIdx on types(module);" + db.exec sql"create index TypeByNimIdIdx on types(nimid);" + + db.exec(sql""" + create table if not exists syms( + id integer primary key, + nimid integer not null, + module integer not null, + name varchar(256) not null, + data blob not null, + exported int not null, + foreign key (module) references module(id) + ); + """) + db.exec sql"create index if not exists SymNameIx on syms(name);" + db.exec sql"create index SymByNameAndModuleIdx on syms(name, module);" + db.exec sql"create index SymByModuleIdx on syms(module);" + db.exec sql"create index SymByNimIdIdx on syms(nimid);" + + + db.exec(sql""" + create table if not exists toplevelstmts( + id integer primary key, + position integer not null, + module integer not null, + data blob not null, + foreign key (module) references module(id) + ); + """) + db.exec sql"create index TopLevelStmtByModuleIdx on toplevelstmts(module);" + db.exec sql"create index TopLevelStmtByPositionIdx on toplevelstmts(position);" + + db.exec(sql""" + create table if not exists statics( + id integer primary key, + module integer not null, + data blob not null, + foreign key (module) references module(id) + ); + """) + db.exec sql"create index StaticsByModuleIdx on toplevelstmts(module);" + db.exec sql"insert into controlblock(idgen) values (0)" + + +else: + type + IncrementalCtx* = object + + template init*(incr: IncrementalCtx) = discard + + template addModuleDep*(incr: var IncrementalCtx; conf: ConfigRef; + module, fileIdx: FileIndex; + isIncludeFile: bool) = + discard diff --git a/compiler/index.nim b/compiler/index.nim deleted file mode 100644 index 2c2a34fb5..000000000 --- a/compiler/index.nim +++ /dev/null @@ -1,18 +0,0 @@ -##[ -This module only exists to generate docs for the compiler. - -## links -* [main docs](../lib.html) -* [compiler user guide](../nimc.html) -* [Internals of the Nim Compiler](../intern.html) -]## - -#[ -note: this is named `index` so that navigating to https://nim-lang.github.io/Nim/compiler/ -will work. - -xxx this should also import other modules, not transitively imported by `compiler/nim.nim`, -eg `evalffi`, otherwise these aren't shown. A glob could be used at CT. -]# - -import nim diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim index d58f28289..dc431ef38 100644 --- a/compiler/injectdestructors.nim +++ b/compiler/injectdestructors.nim @@ -13,172 +13,171 @@ ## See doc/destructors.rst for a spec of the implemented rewrite rules + import - intsets, strtabs, ast, astalgo, msgs, renderer, magicsys, types, idents, - strutils, options, lowerings, tables, modulegraphs, - lineinfos, parampatterns, sighashes, liftdestructors, optimizer, - varpartitions, aliasanalysis, dfa + intsets, ast, msgs, renderer, magicsys, types, idents, + strutils, options, dfa, lowerings, tables, modulegraphs, msgs, + lineinfos, parampatterns, sighashes -when defined(nimPreviewSlimSystem): - import std/assertions - -from trees import exprStructuralEquivalent, getRoot +from trees import exprStructuralEquivalent type Con = object owner: PSym - when true: - g: ControlFlowGraph + g: ControlFlowGraph + jumpTargets: IntSet + destroys, topLevelVars: PNode graph: ModuleGraph - inLoop, inSpawn, inLoopCond: int + emptyNode: PNode + otherRead: PNode + inLoop: int uninit: IntSet # set of uninit'ed vars - idgen: IdGenerator - body: PNode - otherUsage: TLineInfo - - Scope = object # we do scope-based memory management. - # a scope is comparable to an nkStmtListExpr like - # (try: statements; dest = y(); finally: destructors(); dest) - vars: seq[PSym] - wasMoved: seq[PNode] - final: seq[PNode] # finally section - locals: seq[PSym] - body: PNode - needsTry: bool - parent: ptr Scope - - ProcessMode = enum - normal - consumed - sinkArg + uninitComputed: bool const toDebug {.strdefine.} = "" -when toDebug.len > 0: - var shouldDebug = false template dbg(body) = when toDebug.len > 0: - if shouldDebug: + if c.owner.name.s == toDebug or toDebug == "always": body -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}: - assert(not containsGarbageCollectedRef(t)) +proc isLastRead(location: PNode; c: var Con; pc, comesFrom: int): int = + var pc = pc + while pc < c.g.len: + case c.g[pc].kind + of def: + if defInstrTargets(c.g[pc], location): + # the path leads to a redefinition of 's' --> abandon it. + return high(int) + inc pc + of use: + if useInstrTargets(c.g[pc], location): + c.otherRead = c.g[pc].n + return -1 + inc pc + of goto: + pc = pc + c.g[pc].dest + of fork: + # every branch must lead to the last read of the location: + let variantA = isLastRead(location, c, pc+1, pc) + if variantA < 0: return -1 + var variantB = isLastRead(location, c, pc + c.g[pc].dest, pc) + if variantB < 0: return -1 + elif variantB == high(int): + variantB = variantA + pc = variantB + of InstrKind.join: + let dest = pc + c.g[pc].dest + if dest == comesFrom: return pc + 1 + inc pc + return pc -proc getTemp(c: var Con; s: var Scope; typ: PType; info: TLineInfo): PNode = - 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) +proc isLastRead(n: PNode; c: var Con): bool = + # first we need to search for the instruction that belongs to 'n': + c.otherRead = nil + var instr = -1 + let m = dfa.skipConvDfa(n) -proc nestedScope(parent: var Scope; body: PNode): Scope = - Scope(vars: @[], locals: @[], wasMoved: @[], final: @[], body: body, needsTry: false, parent: addr(parent)) + for i in 0..= c.g.len: return true -proc moveOrCopy(dest, ri: PNode; c: var Con; s: var Scope; flags: set[MoveOrCopyFlag] = {}): PNode + result = isLastRead(n, c, instr+1, -1) >= 0 + dbg: echo "ugh ", c.otherRead.isNil, " ", result -when false: - var - perfCounters: array[InstrKind, int] - - proc showCounters*() = - for i in low(InstrKind)..high(InstrKind): - echo "INSTR ", i, " ", perfCounters[i] - -proc isLastReadImpl(n: PNode; c: var Con; scope: var Scope): bool = - let root = parampatterns.exprRoot(n, allowCalls=false) - if root == nil: return false - - var s = addr(scope) - while s != nil: - if s.locals.contains(root): break - s = s.parent - - c.g = constructCfg(c.owner, if s != nil: s.body else: c.body, root) - dbg: - echo "\n### ", c.owner.name.s, ":\nCFG:" - echoCfg(c.g) - #echo c.body - - var j = 0 - while j < c.g.len: - if c.g[j].kind == use and c.g[j].n == n: break - inc j - c.otherUsage = unknownLineInfo - if j < c.g.len: - var pcs = @[j+1] - var marked = initIntSet() - result = true - while pcs.len > 0: - var pc = pcs.pop() - if not marked.contains(pc): - let oldPc = pc - while pc < c.g.len: - dbg: - echo "EXEC ", c.g[pc].kind, " ", pc, " ", n - when false: - inc perfCounters[c.g[pc].kind] - case c.g[pc].kind - of loop: - let back = pc + c.g[pc].dest - if not marked.containsOrIncl(back): - pc = back - else: - break - of goto: - pc = pc + c.g[pc].dest - of fork: - if not marked.contains(pc+1): - pcs.add pc + 1 - pc = pc + c.g[pc].dest - of use: - if c.g[pc].n.aliases(n) != no or n.aliases(c.g[pc].n) != no: - c.otherUsage = c.g[pc].n.info - return false - inc pc - of def: - if c.g[pc].n.aliases(n) == yes: - # the path leads to a redefinition of 's' --> sink 's'. - break - elif n.aliases(c.g[pc].n) != no: - # only partially writes to 's' --> can't sink 's', so this def reads 's' - # or maybe writes to 's' --> can't sink 's' - c.otherUsage = c.g[pc].n.info - return false - inc pc - marked.incl oldPc - else: - result = false - -proc isLastRead(n: PNode; c: var Con; s: var Scope): bool = - if not hasDestructor(c, n.typ): return true - - let m = skipConvDfa(n) - result = (m.kind == nkSym and sfSingleUsedTemp in m.sym.flags) or - isLastReadImpl(n, c, s) +proc isFirstWrite(location: PNode; c: var Con; pc, comesFrom: int; instr: int): int = + var pc = pc + while pc < instr: + case c.g[pc].kind + of def: + if defInstrTargets(c.g[pc], location): + # a definition of 's' before ours makes ours not the first write + return -1 + inc pc + of use: + if useInstrTargets(c.g[pc], location): + return -1 + inc pc + of goto: + pc = pc + c.g[pc].dest + of fork: + # every branch must not contain a def/use of our location: + let variantA = isFirstWrite(location, c, pc+1, pc, instr) + if variantA < 0: return -1 + var variantB = isFirstWrite(location, c, pc + c.g[pc].dest, pc, instr + c.g[pc].dest) + if variantB < 0: return -1 + elif variantB == high(int): + variantB = variantA + pc = variantB + of InstrKind.join: + let dest = pc + c.g[pc].dest + if dest == comesFrom: return pc + 1 + inc pc + return pc proc isFirstWrite(n: PNode; c: var Con): bool = - let m = skipConvDfa(n) - result = nfFirstWrite in m.flags + # first we need to search for the instruction that belongs to 'n': + var instr = -1 + let m = dfa.skipConvDfa(n) -proc isCursor(n: PNode): bool = - case n.kind - of nkSym: - sfCursor in n.sym.flags - of nkDotExpr: - isCursor(n[1]) - of nkCheckedFieldExpr: - isCursor(n[0]) - else: - false + for i in countdown(c.g.len-1, 0): # We search backwards here to treat loops correctly + if c.g[i].kind == def and c.g[i].n == m: + if instr < 0: + instr = i + break + + if instr < 0: return false + # we go through all paths going to 'instr' and need to + # ensure that we don't find another 'def/use X' instruction. + if instr == 0: return true + + result = isFirstWrite(n, c, 0, -1, instr) >= 0 + +proc initialized(code: ControlFlowGraph; pc: int, + init, uninit: var IntSet; comesFrom: int): int = + ## Computes the set of definitely initialized variables across all code paths + ## as an IntSet of IDs. + var pc = pc + while pc < code.len: + case code[pc].kind + of goto: + pc = pc + code[pc].dest + of fork: + let target = pc + code[pc].dest + var initA = initIntSet() + var initB = initIntSet() + let pcA = initialized(code, pc+1, initA, uninit, pc) + discard initialized(code, target, initB, uninit, pc) + # we add vars if they are in both branches: + for v in initA: + if v in initB: + init.incl v + pc = pcA+1 + of InstrKind.join: + let target = pc + code[pc].dest + if comesFrom == target: return pc + inc pc + of use: + let v = code[pc].n.sym + if v.kind != skParam and v.id notin init: + # attempt to read an uninit'ed variable + uninit.incl v.id + inc pc + of def: + let v = code[pc].n.sym + init.incl v.id + inc pc + return pc template isUnpackedTuple(n: PNode): bool = ## we move out all elements of unpacked tuples, @@ -187,15 +186,13 @@ template isUnpackedTuple(n: PNode): bool = proc checkForErrorPragma(c: Con; t: PType; ri: PNode; opname: string) = var m = "'" & opname & "' is not available for type <" & typeToString(t) & ">" - if (opname == "=" or opname == "=copy") and ri != nil: + if opname == "=" and ri != nil: m.add "; requires a copy because it's not the last read of '" m.add renderTree(ri) m.add '\'' - if c.otherUsage != unknownLineInfo: - # ri.comment.startsWith('\n'): + if c.otherRead != nil: m.add "; another read is done here: " - m.add c.graph.config $ c.otherUsage - #m.add c.graph.config $ c.g[parseInt(ri.comment[1..^1])].n.info + m.add c.graph.config $ c.otherRead.info elif ri.kind == nkSym and ri.sym.kind == skParam and not isSinkType(ri.sym.typ): m.add "; try to make " m.add renderTree(ri) @@ -204,225 +201,157 @@ proc checkForErrorPragma(c: Con; t: PType; ri: PNode; opname: string) = m.add c.owner.name.s localError(c.graph.config, ri.info, errGenerated, m) -proc makePtrType(c: var Con, baseType: PType): PType = - result = newType(tyPtr, nextTypeId c.idgen, c.owner) - addSonSkipIntLit(result, baseType, c.idgen) +proc makePtrType(c: Con, baseType: PType): PType = + result = newType(tyPtr, c.owner) + addSonSkipIntLit(result, baseType) -proc genOp(c: var Con; op: PSym; dest: PNode): PNode = - let addrExp = newNodeIT(nkHiddenAddr, dest.info, makePtrType(c, dest.typ)) - addrExp.add(dest) - result = newTree(nkCall, newSymNode(op), addrExp) +proc genOp(c: Con; t: PType; kind: TTypeAttachedOp; dest, ri: PNode): PNode = + var op = t.attachedOps[kind] -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: + if op == nil or op.ast[genericParamsPos].kind != nkEmpty: # 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) + op = canon.attachedOps[kind] + if op == nil: #echo dest.typ.id globalError(c.graph.config, dest.info, "internal error: '" & AttachedOpToStr[kind] & "' operator not found for type " & typeToString(t)) - elif op.ast.isGenericRoutine: + elif op.ast[genericParamsPos].kind != nkEmpty: globalError(c.graph.config, dest.info, "internal error: '" & AttachedOpToStr[kind] & "' operator is generic") dbg: if kind == attachedDestructor: echo "destructor is ", op.id, " ", op.ast if sfError in op.flags: checkForErrorPragma(c, t, ri, AttachedOpToStr[kind]) - c.genOp(op, dest) + let addrExp = newNodeIT(nkHiddenAddr, dest.info, makePtrType(c, dest.typ)) + addrExp.add(dest) + result = newTree(nkCall, newSymNode(op), addrExp) -proc genDestroy(c: var Con; dest: PNode): PNode = +proc genDestroy(c: Con; dest: PNode): PNode = let t = dest.typ.skipTypes({tyGenericInst, tyAlias, tySink}) - result = c.genOp(t, attachedDestructor, dest, nil) + result = genOp(c, t, attachedDestructor, dest, nil) + +when false: + proc preventMoveRef(dest, ri: PNode): bool = + let lhs = dest.typ.skipTypes({tyGenericInst, tyAlias, tySink}) + var ri = ri + if ri.kind in nkCallKinds and ri[0].kind == nkSym and ri[0].sym.magic == mUnown: + ri = ri[1] + let rhs = ri.typ.skipTypes({tyGenericInst, tyAlias, tySink}) + result = lhs.kind == tyRef and rhs.kind == tyOwned proc canBeMoved(c: Con; t: PType): bool {.inline.} = let t = t.skipTypes({tyGenericInst, tyAlias, tySink}) if optOwnedRefs in c.graph.config.globalOptions: - result = t.kind != tyRef and getAttachedOp(c.graph, t, attachedSink) != nil + result = t.kind != tyRef and t.attachedOps[attachedSink] != nil else: - result = getAttachedOp(c.graph, t, attachedSink) != nil + result = t.attachedOps[attachedSink] != nil -proc isNoInit(dest: PNode): bool {.inline.} = - result = dest.kind == nkSym and sfNoInit in dest.sym.flags - -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): - # optimize sink call into a bitwise memcopy +proc genSink(c: var Con; dest, ri: PNode): PNode = + if isFirstWrite(dest, c): # optimize sink call into a bitwise memcopy result = newTree(nkFastAsgn, dest, ri) else: let t = dest.typ.skipTypes({tyGenericInst, tyAlias, tySink}) - if getAttachedOp(c.graph, t, attachedSink) != nil: - result = c.genOp(t, attachedSink, dest, ri) + if t.attachedOps[attachedSink] != nil: + result = genOp(c, t, attachedSink, dest, ri) result.add ri else: # the default is to use combination of `=destroy(dest)` and # and copyMem(dest, source). This is efficient. - result = newTree(nkStmtList, c.genDestroy(dest), newTree(nkFastAsgn, dest, ri)) + let snk = newTree(nkFastAsgn, dest, ri) + result = newTree(nkStmtList, genDestroy(c, dest), snk) -proc isCriticalLink(dest: PNode): bool {.inline.} = - #[ - Lins's idea that only "critical" links can introduce a cycle. This is - 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. - - These constructs cannot possibly create cycles:: - - local = ... - - new(x) - dest = ObjectConstructor(field: noalias(dest)) - - But since 'ObjectConstructor' is already moved into 'dest' all we really have - to look for is assignments to local variables. - ]# - result = dest.kind != nkSym - -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(t): - if t.kind == tyRef: - result.add callCodegenProc(c.graph, "nimMarkCyclic", dest.info, dest) - else: - let xenv = genBuiltin(c.graph, c.idgen, mAccessEnv, "accessEnv", dest) - xenv.typ = getSysType(c.graph, dest.info, tyPointer) - result.add callCodegenProc(c.graph, "nimMarkCyclic", dest.info, xenv) - -proc genCopyNoCheck(c: var Con; dest, ri: PNode; a: TTypeAttachedOp): PNode = +proc genCopyNoCheck(c: Con; dest, ri: PNode): PNode = let t = dest.typ.skipTypes({tyGenericInst, tyAlias, tySink}) - result = c.genOp(t, a, dest, ri) - assert ri.typ != nil + result = genOp(c, t, attachedAsgn, dest, ri) -proc genCopy(c: var Con; dest, ri: PNode; flags: set[MoveOrCopyFlag]): PNode = +proc genCopy(c: var Con; dest, ri: PNode): PNode = let t = dest.typ if tfHasOwned in t.flags and ri.kind != nkNilLit: # try to improve the error message here: - if IsExplicitSink in flags: - c.checkForErrorPragma(t, ri, "=sink") - else: - c.checkForErrorPragma(t, ri, "=copy") - let a = if IsExplicitSink in flags: attachedSink else: attachedAsgn - result = c.genCopyNoCheck(dest, ri, a) - assert ri.typ != nil + if c.otherRead == nil: discard isLastRead(ri, c) + checkForErrorPragma(c, t, ri, "=") + result = genCopyNoCheck(c, dest, ri) -proc genDiscriminantAsgn(c: var Con; s: var Scope; n: PNode): PNode = - # discriminator is ordinal value that doesn't need sink destroy - # but fields within active case branch might need destruction +proc addTopVar(c: var Con; v: PNode) = + c.topLevelVars.add newTree(nkIdentDefs, v, c.emptyNode, c.emptyNode) - # tmp to support self assignments - let tmp = c.getTemp(s, n[1].typ, n.info) +proc getTemp(c: var Con; typ: PType; info: TLineInfo): PNode = + let sym = newSym(skTemp, getIdent(c.graph.cache, ":tmpD"), c.owner, info) + sym.typ = typ + result = newSymNode(sym) + c.addTopVar(result) - result = newTree(nkStmtList) - result.add newTree(nkFastAsgn, tmp, p(n[1], c, s, consumed)) - result.add p(n[0], c, s, normal) - - let le = p(n[0], c, s, normal) - let leDotExpr = if le.kind == nkCheckedFieldExpr: le[0] else: le - let objType = leDotExpr[0].typ - - if hasDestructor(c, objType): - if getAttachedOp(c.graph, objType, attachedDestructor) != nil and - 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) - 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 & ")") +proc genWasMoved(n: PNode; c: var Con): PNode = + result = newNodeI(nkCall, n.info) + result.add(newSymNode(createMagic(c.graph, "wasMoved", mWasMoved))) + result.add copyTree(n) #mWasMoved does not take the address proc genDefaultCall(t: PType; c: Con; info: TLineInfo): PNode = result = newNodeI(nkCall, info) - result.add(newSymNode(createMagic(c.graph, c.idgen, "default", mDefault))) + result.add(newSymNode(createMagic(c.graph, "default", mDefault))) result.typ = t -proc destructiveMoveVar(n: PNode; c: var Con; s: var Scope): PNode = +proc destructiveMoveVar(n: PNode; c: var Con): PNode = # generate: (let tmp = v; reset(v); tmp) - if not hasDestructor(c, n.typ): - assert n.kind != nkSym or not hasDestructor(c, n.sym.typ) + if not hasDestructor(n.typ): result = copyTree(n) else: result = newNodeIT(nkStmtListExpr, n.info, n.typ) - var temp = newSym(skLet, getIdent(c.graph.cache, "blitTmp"), nextSymId c.idgen, c.owner, n.info) + var temp = newSym(skLet, getIdent(c.graph.cache, "blitTmp"), c.owner, n.info) temp.typ = n.typ var v = newNodeI(nkLetSection, n.info) let tempAsNode = newSymNode(temp) var vpart = newNodeI(nkIdentDefs, tempAsNode.info, 3) vpart[0] = tempAsNode - vpart[1] = newNodeI(nkEmpty, tempAsNode.info) + vpart[1] = c.emptyNode vpart[2] = n v.add(vpart) result.add v - let nn = skipConv(n) - c.genMarkCyclic(result, nn) - let wasMovedCall = c.genWasMoved(nn) - result.add wasMovedCall + result.add genWasMoved(skipConv(n), c) result.add tempAsNode -proc isCapturedVar(n: PNode): bool = - let root = getRoot(n) - if root != nil: result = root.name.s[0] == ':' +proc sinkParamIsLastReadCheck(c: var Con, s: PNode) = + assert s.kind == nkSym and s.sym.kind == skParam + if not isLastRead(s, c): + localError(c.graph.config, c.otherRead.info, "sink parameter `" & $s.sym.name.s & + "` is already consumed at " & toFileLineCol(c. graph.config, s.info)) -proc passCopyToSink(n: PNode; c: var Con; s: var Scope): PNode = +type + ProcessMode = enum + normal + consumed + sinkArg + +proc p(n: PNode; c: var Con; mode: ProcessMode): PNode +proc moveOrCopy(dest, ri: PNode; c: var Con): PNode + +proc isClosureEnv(n: PNode): bool = n.kind == nkSym and n.sym.name.s[0] == ':' + +proc passCopyToSink(n: PNode; c: var Con): PNode = result = newNodeIT(nkStmtListExpr, n.info, n.typ) - 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) + let tmp = getTemp(c, n.typ, n.info) + # XXX This is only required if we are in a loop. Since we move temporaries + # out of loops we need to mark it as 'wasMoved'. + result.add genWasMoved(tmp, c) + if hasDestructor(n.typ): + var m = genCopy(c, tmp, n) + m.add p(n, c, normal) result.add m - if isLValue(n) and not isCapturedVar(n) and n.typ.skipTypes(abstractInst).kind != tyRef and c.inSpawn == 0: + if isLValue(n) and not isClosureEnv(n): 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) + "use 'move($1)' to prevent it") % $n) else: 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 - # no need to destroy it. + assert(not containsGarbageCollectedRef(n.typ)) + result.add newTree(nkAsgn, tmp, p(n, c, normal)) result.add tmp proc isDangerousSeq(t: PType): bool {.inline.} = @@ -444,20 +373,87 @@ proc containsConstSeq(n: PNode): bool = if containsConstSeq(son): return true else: discard -proc ensureDestruction(arg, orig: PNode; c: var Con; s: var Scope): PNode = +template handleNested(n: untyped, processCall: untyped) = + case n.kind + of nkStmtList, nkStmtListExpr: + if n.len == 0: return n + result = copyNode(n) + for i in 0.. 0: - # unpacked tuple needs reset at every loop iteration - res.add newTree(nkFastAsgn, v, genDefaultCall(v.typ, c, v.info)) - elif sfThread notin v.sym.flags and sfCursor notin v.sym.flags: - # do not destroy thread vars for now at all for consistency. - if {sfGlobal, sfPure} <= v.sym.flags or sfGlobal in v.sym.flags and s.parent == nil: - c.graph.globalDestructors.add c.genDestroy(v) - else: - s.final.add c.genDestroy(v) - -proc processScope(c: var Con; s: var Scope; ret: PNode): PNode = - result = newNodeI(nkStmtList, ret.info) - if s.vars.len > 0: - let varSection = newNodeI(nkVarSection, ret.info) - for tmp in s.vars: - varSection.add newTree(nkIdentDefs, newSymNode(tmp), newNodeI(nkEmpty, ret.info), - newNodeI(nkEmpty, ret.info)) - result.add varSection - if s.wasMoved.len > 0 or s.final.len > 0: - let finSection = newNodeI(nkStmtList, ret.info) - for m in s.wasMoved: finSection.add m - for i in countdown(s.final.high, 0): finSection.add s.final[i] - if s.needsTry: - result.add newTryFinally(ret, finSection) - else: - result.add ret - result.add finSection - else: - result.add ret - - if s.parent != nil: s.parent[].needsTry = s.parent[].needsTry or s.needsTry - -template processScopeExpr(c: var Con; s: var Scope; ret: PNode, processCall: untyped, tmpFlags: TSymFlags): PNode = - assert not ret.typ.isEmptyType - var result = newNodeIT(nkStmtListExpr, ret.info, ret.typ) - # There is a possibility to do this check: s.wasMoved.len > 0 or s.final.len > 0 - # later and use it to eliminate the temporary when theres no need for it, but its - # tricky because you would have to intercept moveOrCopy at a certain point - let tmp = c.getTemp(s.parent[], ret.typ, ret.info) - tmp.sym.flags = tmpFlags - let cpy = if hasDestructor(c, ret.typ): - s.parent[].final.add c.genDestroy(tmp) - moveOrCopy(tmp, ret, c, s, {IsDecl}) - else: - newTree(nkFastAsgn, tmp, p(ret, c, s, normal)) - - if s.vars.len > 0: - let varSection = newNodeI(nkVarSection, ret.info) - for tmp in s.vars: - varSection.add newTree(nkIdentDefs, newSymNode(tmp), newNodeI(nkEmpty, ret.info), - newNodeI(nkEmpty, ret.info)) - result.add varSection - let finSection = newNodeI(nkStmtList, ret.info) - for m in s.wasMoved: finSection.add m - for i in countdown(s.final.high, 0): finSection.add s.final[i] - if s.needsTry: - result.add newTryFinally(newTree(nkStmtListExpr, cpy, processCall(tmp, s.parent[])), finSection) - else: - result.add cpy - result.add finSection - result.add processCall(tmp, s.parent[]) - - if s.parent != nil: s.parent[].needsTry = s.parent[].needsTry or s.needsTry - - result - -template handleNestedTempl(n, processCall: untyped, willProduceStmt = false, - tmpFlags = {sfSingleUsedTemp}) = - template maybeVoid(child, s): untyped = - if isEmptyType(child.typ): p(child, c, s, normal) - else: processCall(child, s) - - case n.kind - of nkStmtList, nkStmtListExpr: - # a statement list does not open a new scope - if n.len == 0: return n - result = copyNode(n) - for i in 0.. 0: - c.inSpawn.dec - let parameters = n[0].typ let L = if parameters != nil: parameters.len else: 0 - - when false: - var isDangerous = false - if n[0].kind == nkSym and n[0].sym.magic in {mOr, mAnd}: - inc c.inDangerousBranch - isDangerous = true - result = shallowCopy(n) for i in 1.. 0): - result[i] = p(n[i], c, s, sinkArg) + if i < L and isSinkTypeForParam(parameters[i]): + result[i] = p(n[i], c, sinkArg) else: - result[i] = p(n[i], c, s, normal) - - when false: - if isDangerous: - dec c.inDangerousBranch - + result[i] = p(n[i], c, normal) 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, gcOrc}: - let destroyOld = c.genDestroy(result[1]) + let destroyOld = genDestroy(c, result[1]) result = newTree(nkStmtList, destroyOld, result) else: - result[0] = p(n[0], c, s, normal) - if canRaise(n[0]): s.needsTry = true + result[0] = p(n[0], c, normal) + if mode == normal: - result = ensureDestruction(result, n, c, s) + result = ensureDestruction(result, c) of nkDiscardStmt: # Small optimization result = shallowCopy(n) if n[0].kind != nkEmpty: - result[0] = p(n[0], c, s, normal) + result[0] = p(n[0], c, normal) else: result[0] = copyNode(n[0]) of nkVarSection, nkLetSection: @@ -821,319 +579,233 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSing result = newNodeI(nkStmtList, n.info) for it in n: var ri = it[^1] - if it.kind == nkVarTuple and hasDestructor(c, ri.typ): - for i in 0.. 0: + ri = genDefaultCall(v.typ, c, v.info) if ri.kind != nkEmpty: - result.add moveOrCopy(v, ri, c, s, if v.kind == nkSym: {IsDecl} else: {}) - elif ri.kind == nkEmpty and c.inLoop > 0: - let skipInit = v.kind == nkDotExpr and # Closure var - sfNoInit in v[1].sym.flags - if not skipInit: - result.add moveOrCopy(v, genDefaultCall(v.typ, c, v.info), c, s, if v.kind == nkSym: {IsDecl} else: {}) + result.add moveOrCopy(v, ri, c) else: # keep the var but transform 'ri': var v = copyNode(n) var itCopy = copyNode(it) for j in 0.. 0 and isDangerousSeq(ri.typ): + result = genCopy(c, dest, ri) + result.add p(ri, c, consumed) + else: + result = genSink(c, dest, p(ri, c, consumed)) + of nkObjConstr, nkTupleConstr, nkClosure, nkCharLit..nkNilLit: + result = genSink(c, dest, p(ri, c, consumed)) + of nkSym: + if isSinkParam(ri.sym): + # Rule 3: `=sink`(x, z); wasMoved(z) + sinkParamIsLastReadCheck(c, ri) + let snk = genSink(c, dest, ri) + result = newTree(nkStmtList, snk, genWasMoved(ri, c)) + elif ri.sym.kind != skParam and ri.sym.owner == c.owner and + isLastRead(ri, c) and canBeMoved(c, dest.typ): + # Rule 3: `=sink`(x, z); wasMoved(z) + let snk = genSink(c, dest, ri) + result = newTree(nkStmtList, snk, genWasMoved(ri, c)) + else: + result = genCopy(c, dest, ri) + result.add p(ri, c, consumed) + of nkHiddenSubConv, nkHiddenStdConv, nkConv: + when false: + result = moveOrCopy(dest, ri[1], c) + if not sameType(ri.typ, ri[1].typ): + let copyRi = copyTree(ri) + copyRi[1] = result[^1] + result[^1] = copyRi + else: + result = genSink(c, dest, p(ri, c, sinkArg)) + of nkObjDownConv, nkObjUpConv: + when false: + result = moveOrCopy(dest, ri[0], c) + let copyRi = copyTree(ri) + copyRi[0] = result[^1] + result[^1] = copyRi + else: + result = genSink(c, dest, p(ri, c, sinkArg)) + of nkStmtListExpr, nkBlockExpr, nkIfExpr, nkCaseStmt: + handleNested(ri): moveOrCopy(dest, node, c) else: - case a.kind - of nkSym, nkDotExpr, nkCheckedFieldExpr, nkBracketExpr: - # Reached an endpoint, flip to recurse the other side. - sameLocation(b, a) - of nkAddr, nkHiddenAddr, nkDerefExpr, nkHiddenDeref: - # We don't need to check addr/deref levels or differentiate between the two, - # since pointers don't have hooks :) (e.g: var p: ptr pointer; p[] = addr p) - sameLocation(a[0], b) - of nkObjDownConv, nkObjUpConv: sameLocation(a[0], b) - of nkHiddenStdConv, nkHiddenSubConv: sameLocation(a[1], b) - else: false - -proc genFieldAccessSideEffects(c: var Con; dest, ri: PNode; flags: set[MoveOrCopyFlag] = {}): PNode = - # with side effects - var temp = newSym(skLet, getIdent(c.graph.cache, "bracketTmp"), nextSymId c.idgen, c.owner, ri[1].info) - temp.typ = ri[1].typ - var v = newNodeI(nkLetSection, ri[1].info) - let tempAsNode = newSymNode(temp) - - var vpart = newNodeI(nkIdentDefs, tempAsNode.info, 3) - vpart[0] = tempAsNode - vpart[1] = newNodeI(nkEmpty, tempAsNode.info) - vpart[2] = ri[1] - v.add(vpart) - - var newAccess = copyNode(ri) - newAccess.add ri[0] - newAccess.add tempAsNode - - var snk = c.genSink(dest, newAccess, flags) - result = newTree(nkStmtList, v, snk, c.genWasMoved(newAccess)) - -proc moveOrCopy(dest, ri: PNode; c: var Con; s: var Scope, flags: set[MoveOrCopyFlag] = {}): PNode = - if sameLocation(dest, ri): - # rule (self-assignment-removal): - result = newNodeI(nkEmpty, dest.info) - elif isCursor(dest): - case ri.kind: - 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 - handleNestedTempl(ri, process, willProduceStmt = true) + if isAnalysableFieldAccess(ri, c.owner) and isLastRead(ri, c) and + canBeMoved(c, dest.typ): + # Rule 3: `=sink`(x, z); wasMoved(z) + let snk = genSink(c, dest, ri) + result = newTree(nkStmtList, snk, genWasMoved(ri, c)) else: - result = newTree(nkFastAsgn, dest, p(ri, c, s, normal)) + result = genCopy(c, dest, ri) + result.add p(ri, c, consumed) + +proc computeUninit(c: var Con) = + if not c.uninitComputed: + c.uninitComputed = true + c.uninit = initIntSet() + var init = initIntSet() + discard initialized(c.g, pc = 0, init, c.uninit, comesFrom = -1) + +proc injectDefaultCalls(n: PNode, c: var Con) = + case n.kind + of nkVarSection, nkLetSection: + for it in n: + if it.kind == nkIdentDefs and it[^1].kind == nkEmpty: + computeUninit(c) + for j in 0.. 0 and isDangerousSeq(ri.typ): - result = c.genCopy(dest, ri, flags) - result.add p(ri, c, s, consumed) - c.finishCopy(result, dest, isFromSink = false) - else: - result = c.genSink(dest, p(ri, c, s, consumed), flags) - of nkObjConstr, nkTupleConstr, nkClosure, nkCharLit..nkNilLit: - 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(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(dest, ri, flags) - result = newTree(nkStmtList, snk, c.genWasMoved(ri)) - else: - result = c.genCopy(dest, ri, flags) - result.add p(ri, c, s, consumed) - c.finishCopy(result, dest, isFromSink = false) - of nkHiddenSubConv, nkHiddenStdConv, nkConv, nkObjDownConv, nkObjUpConv, nkCast: - 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 - handleNestedTempl(ri, process, willProduceStmt = true) - of nkRaiseStmt: - result = pRaiseStmt(ri, c, s) - else: - 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(dest, ri, flags) - result = newTree(nkStmtList, snk, c.genWasMoved(ri)) - else: - result = c.genCopy(dest, ri, flags) - result.add p(ri, c, s, consumed) - c.finishCopy(result, dest, isFromSink = false) + for i in 0.. 0: - shouldDebug = toDebug == owner.name.s or toDebug == "always" +proc injectDestructorCalls*(g: ModuleGraph; owner: PSym; n: PNode): PNode = if sfGeneratedOp in owner.flags or (owner.kind == skIterator and isInlineIterator(owner.typ)): return n - var c = Con(owner: owner, graph: g, idgen: idgen, body: n, otherUsage: unknownLineInfo) - - if optCursorInference in g.config.options: - computeCursors(owner, n, g) - - var scope = Scope(body: n) - let body = p(n, c, scope, normal) - + var c: Con + c.owner = owner + c.destroys = newNodeI(nkStmtList, n.info) + c.topLevelVars = newNodeI(nkVarSection, n.info) + c.graph = g + c.emptyNode = newNodeI(nkEmpty, n.info) + let cfg = constructCfg(owner, n) + shallowCopy(c.g, cfg) + c.jumpTargets = initIntSet() + for i in 0.. 0: + result.add c.topLevelVars + if c.destroys.len > 0: + c.destroys.sons = reverseDestroys(c.destroys.sons) + if owner.kind == skModule: + result.add newTryFinally(body, extractDestroysForTemporaries(c, c.destroys)) + g.globalDestructors.add c.destroys + else: + result.add newTryFinally(body, c.destroys) + else: + result.add body dbg: echo ">---------transformed-to--------->" echo renderTree(result, {renderIds}) - - if g.config.arcToExpand.hasKey(owner.name.s): - echo "--expandArc: ", owner.name.s - echo renderTree(result, {renderIr, renderNoComments}) - echo "-- end of expandArc ------------------------" diff --git a/compiler/installer.ini b/compiler/installer.ini index 226682715..f8676ab08 100644 --- a/compiler/installer.ini +++ b/compiler/installer.ini @@ -6,14 +6,13 @@ Name: "Nim" Version: "$version" Platforms: """ windows: i386;amd64 - linux: i386;hppa;ia64;alpha;amd64;powerpc64;arm;sparc;sparc64;m68k;mips;mipsel;mips64;mips64el;powerpc;powerpc64el;arm64;riscv32;riscv64 - macosx: i386;amd64;powerpc64;arm64 + linux: i386;hppa;ia64;alpha;amd64;powerpc64;arm;sparc;sparc64;m68k;mips;mipsel;mips64;mips64el;powerpc;powerpc64el;arm64;riscv64 + macosx: i386;amd64;powerpc64 solaris: i386;amd64;sparc;sparc64 - freebsd: i386;amd64;powerpc64;arm;arm64;riscv64;sparc64;mips;mipsel;mips64;mips64el;powerpc;powerpc64el + freebsd: i386;amd64;powerpc64 netbsd: i386;amd64 - openbsd: i386;amd64;arm;arm64 + openbsd: i386;amd64 dragonfly: i386;amd64 - crossos: amd64 haiku: i386;amd64 android: i386;arm;arm64 nintendoswitch: arm64 @@ -36,8 +35,9 @@ App: Console License: "copying.txt" [Config] -Files: "config/*.cfg" -Files: "config/config.nims" +Files: "config/nim.cfg" +Files: "config/nimdoc.cfg" +Files: "config/nimdoc.tex.cfg" [Documentation] ; Files: "doc/*.html" @@ -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" @@ -90,7 +89,6 @@ Files: "bin/vccexe.exe" Files: "bin/nimgrab.exe" Files: "bin/nimpretty.exe" Files: "bin/testament.exe" -Files: "bin/nim-gdb.bat" Files: "koch.exe" Files: "finish.exe" @@ -111,7 +109,6 @@ Download: r"Aporia Text Editor|dist|aporia.zip|97997|https://nim-lang.org/downlo Files: "bin/makelink.exe" Files: "bin/7zG.exe" Files: "bin/*.dll" -Files: "bin/cacert.pem" [UnixBin] Files: "bin/nim" @@ -120,8 +117,6 @@ Files: "bin/nim" [Unix] InstallScript: "yes" UninstallScript: "yes" -Files: "bin/nim-gdb" -Files: "build_all.sh" [InnoSetup] @@ -143,5 +138,5 @@ shortDesc: "The Nim Compiler" licenses: "bin/nim,MIT;lib/*,MIT;" [nimble] -pkgName: "nim" +pkgName: "compiler" pkgFiles: "compiler/*;doc/basicopt.txt;doc/advopt.txt;doc/nimdoc.css" diff --git a/compiler/int128.nim b/compiler/int128.nim index b0341eb37..573cc6082 100644 --- a/compiler/int128.nim +++ b/compiler/int128.nim @@ -1,16 +1,13 @@ ## This module is for compiler internal use only. For reliable error ## messages and range checks, the compiler needs a data type that can -## hold all from `low(BiggestInt)` to `high(BiggestUInt)`, This +## hold all from ``low(BiggestInt)`` to ``high(BiggestUInt)``, This ## type is for that purpose. from math import trunc -when defined(nimPreviewSlimSystem): - import std/assertions - type Int128* = object - udata: array[4, uint32] + udata: array[4,uint32] template sdata(arg: Int128, idx: int): int32 = # udata and sdata was supposed to be in a union, but unions are @@ -20,28 +17,27 @@ template sdata(arg: Int128, idx: int): int32 = # encoding least significant int first (like LittleEndian) const - Zero* = Int128(udata: [0'u32, 0, 0, 0]) - One* = Int128(udata: [1'u32, 0, 0, 0]) - Ten* = Int128(udata: [10'u32, 0, 0, 0]) - Min = Int128(udata: [0'u32, 0, 0, 0x80000000'u32]) - Max = Int128(udata: [high(uint32), high(uint32), high(uint32), uint32(high(int32))]) - NegOne* = Int128(udata: [0xffffffff'u32, 0xffffffff'u32, 0xffffffff'u32, 0xffffffff'u32]) + Zero* = Int128(udata: [0'u32,0,0,0]) + One* = Int128(udata: [1'u32,0,0,0]) + Ten* = Int128(udata: [10'u32,0,0,0]) + Min = Int128(udata: [0'u32,0,0,0x80000000'u32]) + Max = Int128(udata: [high(uint32),high(uint32),high(uint32),uint32(high(int32))]) + NegOne* = Int128(udata: [0xffffffff'u32,0xffffffff'u32,0xffffffff'u32,0xffffffff'u32]) template low*(t: typedesc[Int128]): Int128 = Min 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: +proc toInt128*[T: SomeInteger](arg: T): Int128 = + when 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) + else: + when sizeof(arg) <= 4: result.sdata(0) = int32(arg) if arg < 0: # sign extend result.sdata(1) = -1 @@ -58,9 +54,15 @@ proc toInt128*[T: SomeInteger | bool](arg: T): Int128 = template isNegative(arg: Int128): bool = arg.sdata(3) < 0 -proc bitconcat(a, b: uint32): uint64 = +template isNegative(arg: int32): bool = + arg < 0 + +proc bitconcat(a,b: uint32): uint64 = (uint64(a) shl 32) or uint64(b) +proc bitsplit(a: uint64): (uint32,uint32) = + (cast[uint32](a shr 32), cast[uint32](a)) + proc toInt64*(arg: Int128): int64 = if isNegative(arg): assert(arg.sdata(3) == -1, "out of range") @@ -174,6 +176,7 @@ proc toHex*(arg: Int128): string = result.addToHex(arg) proc inc*(a: var Int128, y: uint32 = 1) = + let input = a a.udata[0] += y if unlikely(a.udata[0] < y): a.udata[1].inc @@ -183,7 +186,7 @@ proc inc*(a: var Int128, y: uint32 = 1) = a.udata[3].inc doAssert(a.sdata(3) != low(int32), "overflow") -proc cmp*(a, b: Int128): int = +proc cmp*(a,b: Int128): int = let tmp1 = cmp(a.sdata(3), b.sdata(3)) if tmp1 != 0: return tmp1 let tmp2 = cmp(a.udata[2], b.udata[2]) @@ -193,38 +196,44 @@ proc cmp*(a, b: Int128): int = let tmp4 = cmp(a.udata[0], b.udata[0]) return tmp4 -proc `<`*(a, b: Int128): bool = - cmp(a, b) < 0 +proc `<`*(a,b: Int128): bool = + cmp(a,b) < 0 -proc `<=`*(a, b: Int128): bool = - cmp(a, b) <= 0 +proc `<=`*(a,b: Int128): bool = + cmp(a,b) <= 0 -proc `==`*(a, b: Int128): bool = +proc `==`*(a,b: Int128): bool = if a.udata[0] != b.udata[0]: return false if a.udata[1] != b.udata[1]: return false if a.udata[2] != b.udata[2]: return false if a.udata[3] != b.udata[3]: return false return true +proc inplaceBitnot(a: var Int128) = + a.udata[0] = not a.udata[0] + a.udata[1] = not a.udata[1] + a.udata[2] = not a.udata[2] + a.udata[3] = not a.udata[3] + proc bitnot*(a: Int128): Int128 = result.udata[0] = not a.udata[0] result.udata[1] = not a.udata[1] result.udata[2] = not a.udata[2] result.udata[3] = not a.udata[3] -proc bitand*(a, b: Int128): Int128 = +proc bitand*(a,b: Int128): Int128 = result.udata[0] = a.udata[0] and b.udata[0] result.udata[1] = a.udata[1] and b.udata[1] result.udata[2] = a.udata[2] and b.udata[2] result.udata[3] = a.udata[3] and b.udata[3] -proc bitor*(a, b: Int128): Int128 = +proc bitor*(a,b: Int128): Int128 = result.udata[0] = a.udata[0] or b.udata[0] result.udata[1] = a.udata[1] or b.udata[1] result.udata[2] = a.udata[2] or b.udata[2] result.udata[3] = a.udata[3] or b.udata[3] -proc bitxor*(a, b: Int128): Int128 = +proc bitxor*(a,b: Int128): Int128 = result.udata[0] = a.udata[0] xor b.udata[0] result.udata[1] = a.udata[1] xor b.udata[1] result.udata[2] = a.udata[2] xor b.udata[2] @@ -241,14 +250,14 @@ proc `shr`*(a: Int128, b: int): Int128 = if isNegative(a): result.sdata(3) = -1 result.sdata(2) = a.sdata(3) shr (b and 31) - result.udata[1] = cast[uint32](bitconcat(a.udata[3], a.udata[2]) shr (b and 31)) - result.udata[0] = cast[uint32](bitconcat(a.udata[2], a.udata[1]) shr (b and 31)) + result.udata[1] = cast[uint32](bitconcat(a.udata[2], a.udata[1]) shr (b and 31)) + result.udata[0] = cast[uint32](bitconcat(a.udata[1], a.udata[0]) shr (b and 31)) elif b < 96: if isNegative(a): result.sdata(3) = -1 result.sdata(2) = -1 result.sdata(1) = a.sdata(3) shr (b and 31) - result.udata[0] = cast[uint32](bitconcat(a.udata[3], a.udata[2]) shr (b and 31)) + result.udata[0] = cast[uint32](bitconcat(a.udata[1], a.udata[0]) shr (b and 31)) else: # b < 128 if isNegative(a): result.sdata(3) = -1 @@ -279,7 +288,7 @@ proc `shl`*(a: Int128, b: int): Int128 = result.udata[2] = 0 result.udata[3] = a.udata[0] shl (b and 31) -proc `+`*(a, b: Int128): Int128 = +proc `+`*(a,b: Int128): Int128 = let tmp0 = uint64(a.udata[0]) + uint64(b.udata[0]) result.udata[0] = cast[uint32](tmp0) let tmp1 = uint64(a.udata[1]) + uint64(b.udata[1]) + (tmp0 shr 32) @@ -296,7 +305,7 @@ proc `-`*(a: Int128): Int128 = result = bitnot(a) result.inc -proc `-`*(a, b: Int128): Int128 = +proc `-`*(a,b: Int128): Int128 = a + (-b) proc `-=`*(a: var Int128, b: Int128) = @@ -333,7 +342,7 @@ proc `*`*(a: Int128, b: int32): Int128 = proc `*=`*(a: var Int128, b: int32): Int128 = result = result * b -proc makeInt128(high, low: uint64): Int128 = +proc makeInt128(high,low: uint64): Int128 = result.udata[0] = cast[uint32](low) result.udata[1] = cast[uint32](low shr 32) result.udata[2] = cast[uint32](high) @@ -345,14 +354,27 @@ proc high64(a: Int128): uint64 = proc low64(a: Int128): uint64 = bitconcat(a.udata[1], a.udata[0]) -proc `*`*(lhs, rhs: Int128): Int128 = - let a32 = uint64(lhs.udata[1]) - let a00 = uint64(lhs.udata[0]) - let b32 = uint64(rhs.udata[1]) - let b00 = uint64(rhs.udata[0]) +proc `*`*(lhs,rhs: Int128): Int128 = + let + a = cast[uint64](lhs.udata[0]) + b = cast[uint64](lhs.udata[1]) + c = cast[uint64](lhs.udata[2]) + d = cast[uint64](lhs.udata[3]) + + e = cast[uint64](rhs.udata[0]) + f = cast[uint64](rhs.udata[1]) + g = cast[uint64](rhs.udata[2]) + h = cast[uint64](rhs.udata[3]) + + + let a32 = cast[uint64](lhs.udata[1]) + let a00 = cast[uint64](lhs.udata[0]) + let b32 = cast[uint64](rhs.udata[1]) + let b00 = cast[uint64](rhs.udata[0]) + result = makeInt128(high64(lhs) * low64(rhs) + low64(lhs) * high64(rhs) + a32 * b32, a00 * b00) - result += toInt128(a32 * b00) shl 32 - result += toInt128(a00 * b32) shl 32 + result = result + toInt128(a32 * b00) shl 32 + result = result + toInt128(a00 * b32) shl 32 proc `*=`*(a: var Int128, b: Int128) = a = a * b @@ -367,7 +389,7 @@ proc fastLog2*(a: Int128): int = if a.udata[1] != 0: return 32 + fastLog2(a.udata[1]) if a.udata[0] != 0: - return fastLog2(a.udata[0]) + return fastLog2(a.udata[0]) proc divMod*(dividend, divisor: Int128): tuple[quotient, remainder: Int128] = assert(divisor != Zero) @@ -405,7 +427,7 @@ proc divMod*(dividend, divisor: Int128): tuple[quotient, remainder: Int128] = for i in 0..shift: quotient = quotient shl 1 if dividend >= denominator: - dividend -= denominator + dividend = dividend - denominator quotient = bitor(quotient, One) denominator = denominator shr 1 @@ -419,18 +441,18 @@ proc divMod*(dividend, divisor: Int128): tuple[quotient, remainder: Int128] = else: result.remainder = dividend -proc `div`*(a, b: Int128): Int128 = - let (a, _) = divMod(a, b) +proc `div`*(a,b: Int128): Int128 = + let (a,b) = divMod(a,b) return a -proc `mod`*(a, b: Int128): Int128 = - let (_, b) = divMod(a, b) +proc `mod`*(a,b: Int128): Int128 = + let (a,b) = divMod(a,b) return b proc addInt128*(result: var string; value: Int128) = let initialSize = result.len if value == Zero: - result.add '0' + result.add "0" elif value == low(Int128): result.add "-170141183460469231731687303715884105728" else: @@ -451,13 +473,11 @@ proc addInt128*(result: var string; value: Int128) = j -= 1 proc `$`*(a: Int128): string = - # "-170141183460469231731687303715884105728".len == 41 - result = newStringOfCap(41) result.addInt128(a) proc parseDecimalInt128*(arg: string, pos: int = 0): Int128 = assert(pos < arg.len) - assert(arg[pos] in {'-', '0'..'9'}) + assert(arg[pos] in {'-','0'..'9'}) var isNegative = false var pos = pos @@ -477,13 +497,13 @@ proc parseDecimalInt128*(arg: string, pos: int = 0): Int128 = # fluff proc `<`*(a: Int128, b: BiggestInt): bool = - cmp(a, toInt128(b)) < 0 + cmp(a,toInt128(b)) < 0 proc `<`*(a: BiggestInt, b: Int128): bool = cmp(toInt128(a), b) < 0 proc `<=`*(a: Int128, b: BiggestInt): bool = - cmp(a, toInt128(b)) <= 0 + cmp(a,toInt128(b)) <= 0 proc `<=`*(a: BiggestInt, b: Int128): bool = cmp(toInt128(a), b) <= 0 @@ -519,7 +539,7 @@ proc toFloat64*(arg: Int128): float64 = proc ldexp(x: float64, exp: cint): float64 {.importc: "ldexp", header: "".} -template bitor(a, b, c: Int128): Int128 = bitor(bitor(a, b), c) +template bitor(a,b,c: Int128): Int128 = bitor(bitor(a,b), c) proc toInt128*(arg: float64): Int128 = let isNegative = arg < 0 @@ -572,3 +592,107 @@ proc maskBytes*(arg: Int128, numbytes: int): Int128 {.noinit.} = return maskUInt64(arg) else: assert(false, "masking only implemented for 1, 2, 4 and 8 bytes") + + + + +when isMainModule: + let (a,b) = divMod(Ten,Ten) + + doAssert $One == "1" + doAssert $Ten == "10" + doAssert $Zero == "0" + let c = parseDecimalInt128("12345678989876543210123456789") + doAssert $c == "12345678989876543210123456789" + + var d : array[39, Int128] + d[0] = parseDecimalInt128("1") + d[1] = parseDecimalInt128("10") + d[2] = parseDecimalInt128("100") + d[3] = parseDecimalInt128("1000") + d[4] = parseDecimalInt128("10000") + d[5] = parseDecimalInt128("100000") + d[6] = parseDecimalInt128("1000000") + d[7] = parseDecimalInt128("10000000") + d[8] = parseDecimalInt128("100000000") + d[9] = parseDecimalInt128("1000000000") + d[10] = parseDecimalInt128("10000000000") + d[11] = parseDecimalInt128("100000000000") + d[12] = parseDecimalInt128("1000000000000") + d[13] = parseDecimalInt128("10000000000000") + d[14] = parseDecimalInt128("100000000000000") + d[15] = parseDecimalInt128("1000000000000000") + d[16] = parseDecimalInt128("10000000000000000") + d[17] = parseDecimalInt128("100000000000000000") + d[18] = parseDecimalInt128("1000000000000000000") + d[19] = parseDecimalInt128("10000000000000000000") + d[20] = parseDecimalInt128("100000000000000000000") + d[21] = parseDecimalInt128("1000000000000000000000") + d[22] = parseDecimalInt128("10000000000000000000000") + d[23] = parseDecimalInt128("100000000000000000000000") + d[24] = parseDecimalInt128("1000000000000000000000000") + d[25] = parseDecimalInt128("10000000000000000000000000") + d[26] = parseDecimalInt128("100000000000000000000000000") + d[27] = parseDecimalInt128("1000000000000000000000000000") + d[28] = parseDecimalInt128("10000000000000000000000000000") + d[29] = parseDecimalInt128("100000000000000000000000000000") + d[30] = parseDecimalInt128("1000000000000000000000000000000") + d[31] = parseDecimalInt128("10000000000000000000000000000000") + d[32] = parseDecimalInt128("100000000000000000000000000000000") + d[33] = parseDecimalInt128("1000000000000000000000000000000000") + d[34] = parseDecimalInt128("10000000000000000000000000000000000") + d[35] = parseDecimalInt128("100000000000000000000000000000000000") + d[36] = parseDecimalInt128("1000000000000000000000000000000000000") + d[37] = parseDecimalInt128("10000000000000000000000000000000000000") + d[38] = parseDecimalInt128("100000000000000000000000000000000000000") + + for i in 0..= 0: + doAssert d[i] div d[j] == d[i-j] + + var sum: Int128 + + for it in d: + sum += it + + doAssert $sum == "111111111111111111111111111111111111111" + + for it in d.mitems: + it = -it + + for i in 0..= 0: + doAssert d[i] div d[j] == -d[i-j] + + doAssert $high(Int128) == "170141183460469231731687303715884105727" + doAssert $low(Int128) == "-170141183460469231731687303715884105728" + + var ma = 100'i64 + var mb = 13 + + doAssert toInt128(ma) * toInt128(0) == toInt128(0) + doAssert toInt128(-ma) * toInt128(0) == toInt128(0) + + # sign correctness + doAssert divMod(toInt128( ma),toInt128( mb)) == (toInt128( ma div mb), toInt128( ma mod mb)) + doAssert divMod(toInt128(-ma),toInt128( mb)) == (toInt128(-ma div mb), toInt128(-ma mod mb)) + doAssert divMod(toInt128( ma),toInt128(-mb)) == (toInt128( ma div -mb), toInt128( ma mod -mb)) + doAssert divMod(toInt128(-ma),toInt128(-mb)) == (toInt128(-ma div -mb), toInt128(-ma mod -mb)) + + doAssert divMod(toInt128( mb),toInt128( mb)) == (toInt128( mb div mb), toInt128( mb mod mb)) + doAssert divMod(toInt128(-mb),toInt128( mb)) == (toInt128(-mb div mb), toInt128(-mb mod mb)) + doAssert divMod(toInt128( mb),toInt128(-mb)) == (toInt128( mb div -mb), toInt128( mb mod -mb)) + doAssert divMod(toInt128(-mb),toInt128(-mb)) == (toInt128(-mb div -mb), toInt128(-mb mod -mb)) + + doAssert divMod(toInt128( mb),toInt128( ma)) == (toInt128( mb div ma), toInt128( mb mod ma)) + doAssert divMod(toInt128(-mb),toInt128( ma)) == (toInt128(-mb div ma), toInt128(-mb mod ma)) + doAssert divMod(toInt128( mb),toInt128(-ma)) == (toInt128( mb div -ma), toInt128( mb mod -ma)) + doAssert divMod(toInt128(-mb),toInt128(-ma)) == (toInt128(-mb div -ma), toInt128(-mb mod -ma)) diff --git a/compiler/isolation_check.nim b/compiler/isolation_check.nim deleted file mode 100644 index 2674605dc..000000000 --- a/compiler/isolation_check.nim +++ /dev/null @@ -1,151 +0,0 @@ -# -# -# The Nim Compiler -# (c) Copyright 2020 Andreas Rumpf -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# - -## Implementation of the check that `recover` needs, see -## https://github.com/nim-lang/RFCs/issues/244 for more details. - -import - ast, types, renderer, intsets - -when defined(nimPreviewSlimSystem): - import std/assertions - -proc canAlias(arg, ret: PType; marker: var IntSet): bool - -proc canAliasN(arg: PType; n: PNode; marker: var IntSet): bool = - case n.kind - of nkRecList: - for i in 0.. 0 and ret[0] != nil: - result = canAlias(arg, ret[0], marker) - else: - result = true - of tyTuple: - for i in 0.. 0: - result = checkIsolate(n[^1]) - else: - result = false - else: - # unanalysable expression: - result = false - else: - # no ref, no cry: - result = true diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index d0a143793..d63856b87 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -14,35 +14,29 @@ The JS code generator contains only 2 tricks: Trick 1 ------- -Some locations (for example 'var int') require "fat pointers" (`etyBaseIndex`) +Some locations (for example 'var int') require "fat pointers" (``etyBaseIndex``) which are pairs (array, index). The derefence operation is then 'array[index]'. -Check `mapType` for the details. +Check ``mapType`` for the details. Trick 2 ------- It is preferable to generate '||' and '&&' if possible since that is more idiomatic and hence should be friendlier for the JS JIT implementation. However -code like `foo and (let bar = baz())` cannot be translated this way. Instead -the expressions need to be transformed into statements. `isSimpleExpr` +code like ``foo and (let bar = baz())`` cannot be translated this way. Instead +the expressions need to be transformed into statements. ``isSimpleExpr`` implements the required case distinction. """ import - ast, trees, magicsys, options, - nversion, msgs, idents, types, - ropes, ccgutils, wordrecg, renderer, - cgmeth, lowerings, sighashes, modulegraphs, lineinfos, rodutils, - transf, injectdestructors, sourcemap, astmsgs, backendpragmas + ast, strutils, trees, magicsys, options, + nversion, msgs, idents, types, tables, + ropes, math, passes, ccgutils, wordrecg, renderer, + intsets, cgmeth, lowerings, sighashes, modulegraphs, lineinfos, rodutils, + transf, injectdestructors -import pipelineutils - -import json, sets, math, tables, intsets -import strutils except addf - -when defined(nimPreviewSlimSystem): - import std/[assertions, syncio] +from modulegraphs import ModuleGraph, PPassContext type TJSGen = object of PPassContext @@ -92,7 +86,6 @@ type generatedSyms: IntSet typeInfoGenerated: IntSet unique: int # for temp identifier generation - inSystem: bool PProc = ref TProc TProc = object @@ -100,7 +93,6 @@ type prc: PSym globals, locals, body: Rope options: TOptions - optionsStack: seq[TOptions] module: BModule g: PGlobals generatedParamCopies: IntSet @@ -114,18 +106,21 @@ type template config*(p: PProc): ConfigRef = p.module.config proc indentLine(p: PProc, r: Rope): Rope = + result = r var p = p - var ind = 0 while true: - inc ind, p.blocks.len + p.extraIndent + for i in 0.. 0 and s.name.s[i-1] in {'a'..'z'}: + x.add '_' + x.add(chr(c.ord - 'A'.ord + 'a'.ord)) + of 'a'..'z', '_', '0'..'9': x.add c else: x.add("HEX" & toHex(ord(c), 2)) @@ -264,7 +253,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)) @@ -293,21 +282,6 @@ proc makeJSString(s: string, escapeNonAscii = true): Rope = else: result = escapeJSString(s).rope -proc makeJsNimStrLit(s: string): Rope = - var x = newStringOfCap(4*s.len+1) - x.add "[" - var i = 0 - if i < s.len: - x.addInt int64(s[i]) - inc i - while i < s.len: - x.add "," - x.addInt int64(s[i]) - inc i - x.add "]" - result = rope(x) - - include jstypes proc gen(p: PProc, n: PNode, r: var TCompRes) @@ -331,25 +305,17 @@ proc useMagic(p: PProc, name: string) = proc isSimpleExpr(p: PProc; n: PNode): bool = # calls all the way down --> can stay expression based - case n.kind - of nkCallKinds, nkBracketExpr, nkDotExpr, nkPar, nkTupleConstr, - nkObjConstr, nkBracket, nkCurly, - nkDerefExpr, nkHiddenDeref, nkAddr, nkHiddenAddr, - nkConv, nkHiddenStdConv, nkHiddenSubConv: + if n.kind in nkCallKinds+{nkBracketExpr, nkDotExpr, nkPar, nkTupleConstr} or + (n.kind in {nkObjConstr, nkBracket, nkCurly}): for c in n: if not p.isSimpleExpr(c): return false result = true - of nkStmtListExpr: - for i in 0.. genFieldAccess, nkCheckedFieldExpr -> genCheckedFieldOp - # but the uses of maybeMakeTempAssignable don't need them - else: - result = (a: a, tmp: b) - else: - result = (a: a, tmp: b) - -template binaryExpr(p: PProc, n: PNode, r: var TCompRes, magic, frmt: string, - reassign = false) = +template binaryExpr(p: PProc, n: PNode, r: var TCompRes, magic, frmt: string) = # $1 and $2 in the `frmt` string bind to lhs and rhs of the expr, # if $3 or $4 are present they will be substituted with temps for # lhs and rhs respectively @@ -546,11 +474,8 @@ template binaryExpr(p: PProc, n: PNode, r: var TCompRes, magic, frmt: string, var a, tmp = x.rdLoc b, tmp2 = y.rdLoc - when reassign: - (a, tmp) = maybeMakeTempAssignable(p, n[1], x) - else: - when "$3" in frmt: (a, tmp) = maybeMakeTemp(p, n[1], x) - when "$4" in frmt: (b, tmp2) = maybeMakeTemp(p, n[2], y) + when "$3" in frmt: (a, tmp) = maybeMakeTemp(p, n[1], x) + when "$4" in frmt: (b, tmp2) = maybeMakeTemp(p, n[2], y) r.res = frmt % [a, b, tmp, tmp2] r.kind = resExpr @@ -567,13 +492,13 @@ template unsignedTrimmer(size: BiggestInt): Rope = size.unsignedTrimmerJS proc binaryUintExpr(p: PProc, n: PNode, r: var TCompRes, op: string, - reassign: static[bool] = false) = + reassign = false) = var x, y: TCompRes gen(p, n[1], x) gen(p, n[2], y) let trimmer = unsignedTrimmer(n[1].typ.skipTypes(abstractRange).size) - when reassign: - let (a, tmp) = maybeMakeTempAssignable(p, n[1], x) + if reassign: + let (a, tmp) = maybeMakeTemp(p, n[1], x) r.res = "$1 = (($5 $2 $3) $4)" % [a, rope op, y.rdLoc, trimmer, tmp] else: r.res = "(($1 $2 $3) $4)" % [x.rdLoc, rope op, y.rdLoc, trimmer] @@ -600,7 +525,7 @@ template unaryExpr(p: PProc, n: PNode, r: var TCompRes, magic, frmt: string) = proc arithAux(p: PProc, n: PNode, r: var TCompRes, op: TMagic) = var x, y: TCompRes - xLoc, yLoc: Rope + xLoc,yLoc: Rope let i = ord(optOverflowCheck notin p.options) useMagic(p, jsMagics[op][i]) if n.len > 2: @@ -612,12 +537,13 @@ proc arithAux(p: PProc, n: PNode, r: var TCompRes, op: TMagic) = gen(p, n[1], r) xLoc = r.rdLoc - template applyFormat(frmt) = - r.res = frmt % [xLoc, yLoc] - template applyFormat(frmtA, frmtB) = - if i == 0: applyFormat(frmtA) else: applyFormat(frmtB) + template applyFormat(frmtA, frmtB: string) = + if i == 0: + r.res = frmtA % [xLoc, yLoc] + else: + r.res = frmtB % [xLoc, yLoc] - case op + case op: of mAddI: applyFormat("addInt($1, $2)", "($1 + $2)") of mSubI: applyFormat("subInt($1, $2)", "($1 - $2)") of mMulI: applyFormat("mulInt($1, $2)", "($1 * $2)") @@ -630,16 +556,8 @@ proc arithAux(p: PProc, n: PNode, r: var TCompRes, op: TMagic) = of mMulF64: applyFormat("($1 * $2)", "($1 * $2)") of mDivF64: applyFormat("($1 / $2)", "($1 / $2)") of mShrI: applyFormat("", "") - of mShlI: - if n[1].typ.size <= 4: - applyFormat("($1 << $2)", "($1 << $2)") - else: - applyFormat("($1 * Math.pow(2, $2))", "($1 * Math.pow(2, $2))") - of mAshrI: - if n[1].typ.size <= 4: - applyFormat("($1 >> $2)", "($1 >> $2)") - else: - applyFormat("Math.floor($1 / Math.pow(2, $2))", "Math.floor($1 / Math.pow(2, $2))") + of mShlI: applyFormat("($1 << $2)", "($1 << $2)") + of mAshrI: applyFormat("($1 >> $2)", "($1 >> $2)") of mBitandI: applyFormat("($1 & $2)", "($1 & $2)") of mBitorI: applyFormat("($1 | $2)", "($1 | $2)") of mBitxorI: applyFormat("($1 ^ $2)", "($1 ^ $2)") @@ -658,6 +576,8 @@ proc arithAux(p: PProc, n: PNode, r: var TCompRes, op: TMagic) = of mLtF64: applyFormat("($1 < $2)", "($1 < $2)") of mLeU: applyFormat("($1 <= $2)", "($1 <= $2)") of mLtU: applyFormat("($1 < $2)", "($1 < $2)") + of mLeU64: applyFormat("($1 <= $2)", "($1 <= $2)") + of mLtU64: applyFormat("($1 < $2)", "($1 < $2)") of mEqEnum: applyFormat("($1 == $2)", "($1 == $2)") of mLeEnum: applyFormat("($1 <= $2)", "($1 <= $2)") of mLtEnum: applyFormat("($1 < $2)", "($1 < $2)") @@ -668,6 +588,7 @@ proc arithAux(p: PProc, n: PNode, r: var TCompRes, op: TMagic) = of mLeB: applyFormat("($1 <= $2)", "($1 <= $2)") of mLtB: applyFormat("($1 < $2)", "($1 < $2)") of mEqRef: applyFormat("($1 == $2)", "($1 == $2)") + of mEqUntracedRef: applyFormat("($1 == $2)", "($1 == $2)") of mLePtr: applyFormat("($1 <= $2)", "($1 <= $2)") of mLtPtr: applyFormat("($1 < $2)", "($1 < $2)") of mXor: applyFormat("($1 != $2)", "($1 != $2)") @@ -683,10 +604,11 @@ proc arithAux(p: PProc, n: PNode, r: var TCompRes, op: TMagic) = of mUnaryMinusF64: applyFormat("-($1)", "-($1)") of mCharToStr: applyFormat("nimCharToStr($1)", "nimCharToStr($1)") of mBoolToStr: applyFormat("nimBoolToStr($1)", "nimBoolToStr($1)") - of mIntToStr: applyFormat("cstrToNimstr(($1) + \"\")", "cstrToNimstr(($1) + \"\")") - of mInt64ToStr: applyFormat("cstrToNimstr(($1) + \"\")", "cstrToNimstr(($1) + \"\")") + of mIntToStr: applyFormat("cstrToNimstr(($1)+\"\")", "cstrToNimstr(($1)+\"\")") + of mInt64ToStr: applyFormat("cstrToNimstr(($1)+\"\")", "cstrToNimstr(($1)+\"\")") + of mFloatToStr: applyFormat("cstrToNimstr(($1)+\"\")", "cstrToNimstr(($1)+\"\")") of mCStrToStr: applyFormat("cstrToNimstr($1)", "cstrToNimstr($1)") - of mStrToStr, mUnown, mIsolate, mFinished: applyFormat("$1", "$1") + of mStrToStr, mUnown: applyFormat("$1", "$1") else: assert false, $op @@ -695,10 +617,7 @@ proc arith(p: PProc, n: PNode, r: var TCompRes, op: TMagic) = of mAddU: binaryUintExpr(p, n, r, "+") of mSubU: binaryUintExpr(p, n, r, "-") of mMulU: binaryUintExpr(p, n, r, "*") - of mDivU: - binaryUintExpr(p, n, r, "/") - if n[1].typ.skipTypes(abstractRange).size == 8: - r.res = "Math.trunc($1)" % [r.res] + of mDivU: binaryUintExpr(p, n, r, "/") of mDivI: arithAux(p, n, r, op) of mModI: @@ -707,10 +626,12 @@ proc arith(p: PProc, n: PNode, r: var TCompRes, op: TMagic) = 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: + let trimmer = unsignedTrimmer(n[1].typ.skipTypes(abstractRange).size) + r.res = "(($1 $2) >>> $3)" % [x.rdLoc, trimmer, y.rdLoc] + of mCharToStr, mBoolToStr, mIntToStr, mInt64ToStr, mFloatToStr, + mCStrToStr, mStrToStr, mEnumToStr: arithAux(p, n, r, op) - of mEqRef: + of mEqRef, mEqUntracedRef: if mapType(n[1].typ) != etyBaseIndex: arithAux(p, n, r, op) else: @@ -726,19 +647,11 @@ proc hasFrameInfo(p: PProc): bool = ({optLineTrace, optStackTrace} * p.options == {optLineTrace, optStackTrace}) and ((p.prc == nil) or not (sfPure in p.prc.flags)) -proc lineDir(config: ConfigRef, info: TLineInfo, line: int): Rope = - "/* line $2:$3 \"$1\" */$n" % [ - rope(toFullPath(config, info)), rope(line), rope(info.toColumn) - ] - 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 optLineDir in p.options: + lineF(p, "// line $2 \"$1\"$n", + [rope(toFilename(p.config, n.info)), rope(line)]) if hasFrameInfo(p): lineF(p, "F.line = $1;$n", [rope(line)]) @@ -751,9 +664,9 @@ proc genWhileStmt(p: PProc, n: PNode) = p.blocks[^1].id = -p.unique p.blocks[^1].isLoop = true let labl = p.unique.rope - lineF(p, "Label$1: while (true) {$n", [labl]) + lineF(p, "L$1: while (true) {$n", [labl]) p.nested: gen(p, n[0], cond) - lineF(p, "if (!$1) break Label$2;$n", + lineF(p, "if (!$1) break L$2;$n", [cond.res, labl]) p.nested: genStmt(p, n[1]) lineF(p, "}$n", [labl]) @@ -766,7 +679,7 @@ proc moveInto(p: PProc, src: var TCompRes, dest: TCompRes) = else: lineF(p, "$1;$n", [src.rdLoc]) src.kind = resNone - src.res = "" + src.res = nil proc genTry(p: PProc, n: PNode, r: var TCompRes) = # code to generate: @@ -776,8 +689,8 @@ proc genTry(p: PProc, n: PNode, r: var TCompRes) = # try { # stmts; # --excHandler; - # } catch (EXCEPTION) { - # var prevJSError = lastJSError; lastJSError = EXCEPTION; + # } catch (EXC) { + # var prevJSError = lastJSError; lastJSError = EXC; # framePtr = tmpFramePtr; # --excHandler; # if (e.typ && e.typ == NTI433 || e.typ == NTI2321) { @@ -802,16 +715,18 @@ proc genTry(p: PProc, n: PNode, r: var TCompRes) = if catchBranchesExist: p.body.add("++excHandler;\L") var tmpFramePtr = rope"F" + if optStackTrace notin p.options: + tmpFramePtr = p.getTemp(true) + line(p, tmpFramePtr & " = framePtr;\L") lineF(p, "try {$n", []) var a: TCompRes gen(p, n[0], a) moveInto(p, a, r) var generalCatchBranchExists = false if catchBranchesExist: - p.body.addf("--excHandler;$n} catch (EXCEPTION) {$n var prevJSError = lastJSError;$n" & - " lastJSError = EXCEPTION;$n --excHandler;$n", []) - if hasFrameInfo(p): - line(p, "framePtr = $1;$n" % [tmpFramePtr]) + p.body.addf("--excHandler;$n} catch (EXC) {$n var prevJSError = lastJSError;$n" & + " lastJSError = EXC;$n --excHandler;$n", []) + line(p, "framePtr = $1;$n" % [tmpFramePtr]) while i < n.len and n[i].kind == nkExceptBranch: if n[i].len == 1: # general except section: @@ -821,7 +736,7 @@ proc genTry(p: PProc, n: PNode, r: var TCompRes) = moveInto(p, a, r) if i > 1: lineF(p, "}$n", []) else: - var orExpr: Rope = "" + var orExpr: Rope = nil var excAlias: PNode = nil useMagic(p, "isObj") @@ -834,13 +749,13 @@ proc genTry(p: PProc, n: PNode, r: var TCompRes) = excAlias = it[2] # If this is a ``except exc as sym`` branch there must be no following # nodes - doAssert orExpr == "" + doAssert orExpr == nil elif it.kind == nkType: throwObj = it else: internalError(p.config, n.info, "genTryStmt") - if orExpr != "": orExpr.add("||") + if orExpr != nil: orExpr.add("||") # Generate the correct type checking code depending on whether this is a # NIM-native or a JS-native exception # if isJsObject(throwObj.typ): @@ -870,8 +785,7 @@ proc genTry(p: PProc, n: PNode, r: var TCompRes) = line(p, "}\L") lineF(p, "lastJSError = prevJSError;$n") line(p, "} finally {\L") - if hasFrameInfo(p): - line(p, "framePtr = $1;$n" % [tmpFramePtr]) + line(p, "framePtr = $1;$n" % [tmpFramePtr]) if i < n.len and n[i].kind == nkFinally: genStmt(p, n[i][0]) line(p, "}\L") @@ -892,18 +806,13 @@ proc genRaiseStmt(p: PProc, n: PNode) = proc genCaseJS(p: PProc, n: PNode, r: var TCompRes) = var - a, b, cond, stmt: TCompRes + cond, stmt: TCompRes genLineDir(p, n) gen(p, n[0], cond) - let typeKind = skipTypes(n[0].typ, abstractVar).kind - var transferRange = false - let anyString = typeKind in {tyString, tyCstring} - case typeKind - of tyString: + let stringSwitch = skipTypes(n[0].typ, abstractVar).kind == tyString + if stringSwitch: useMagic(p, "toJSStr") lineF(p, "switch (toJSStr($1)) {$n", [cond.rdLoc]) - of tyFloat..tyFloat128, tyInt..tyInt64, tyUInt..tyUInt64: - transferRange = true else: lineF(p, "switch ($1) {$n", [cond.rdLoc]) if not isEmptyType(n.typ): @@ -911,71 +820,37 @@ proc genCaseJS(p: PProc, n: PNode, r: var TCompRes) = r.res = getTemp(p) for i in 1..= $2 && $1 <= $3 || $n", [cond.rdLoc, a.rdLoc, b.rdLoc]) - else: - lineF(p, "$1 >= $2 && $1 <= $3", [cond.rdLoc, a.rdLoc, b.rdLoc]) - else: - var v = copyNode(e[0]) - while v.intVal <= e[1].intVal: - gen(p, v, cond) - lineF(p, "case $1:$n", [cond.rdLoc]) - inc(v.intVal) + var v = copyNode(e[0]) + while v.intVal <= e[1].intVal: + gen(p, v, cond) + lineF(p, "case $1:$n", [cond.rdLoc]) + inc(v.intVal) else: - if anyString: + if stringSwitch: case e.kind of nkStrLit..nkTripleStrLit: lineF(p, "case $1:$n", [makeJSString(e.strVal, false)]) - of nkNilLit: lineF(p, "case null:$n", []) else: internalError(p.config, e.info, "jsgen.genCaseStmt: 2") else: - if transferRange: - gen(p, e, a) - if j != itLen - 2: - lineF(p, "$1 == $2 || $n", [cond.rdLoc, a.rdLoc]) - else: - lineF(p, "$1 == $2", [cond.rdLoc, a.rdLoc]) - else: - gen(p, e, a) - lineF(p, "case $1:$n", [a.rdLoc]) - if transferRange: - lineF(p, "){", []) + gen(p, e, cond) + lineF(p, "case $1:$n", [cond.rdLoc]) p.nested: gen(p, lastSon(it), stmt) moveInto(p, stmt, r) - if transferRange: - lineF(p, "}$n", []) - else: - lineF(p, "break;$n", []) + lineF(p, "break;$n", []) of nkElse: - if transferRange: - lineF(p, "else{$n", []) - else: - lineF(p, "default: $n", []) + lineF(p, "default: $n", []) p.nested: gen(p, it[0], stmt) moveInto(p, stmt, r) - if transferRange: - lineF(p, "}$n", []) - else: - lineF(p, "break;$n", []) + lineF(p, "break;$n", []) else: internalError(p.config, it.info, "jsgen.genCaseStmt") - if not transferRange: - lineF(p, "}$n", []) + lineF(p, "}$n", []) proc genBlock(p: PProc, n: PNode, r: var TCompRes) = inc(p.unique) @@ -987,12 +862,12 @@ proc genBlock(p: PProc, n: PNode, r: var TCompRes) = sym.loc.k = locOther sym.position = idx+1 let labl = p.unique - lineF(p, "Label$1: {$n", [labl.rope]) + lineF(p, "L$1: do {$n", [labl.rope]) setLen(p.blocks, idx + 1) p.blocks[idx].id = - p.unique # negative because it isn't used yet gen(p, n[1], r) setLen(p.blocks, idx) - lineF(p, "};$n", [labl.rope]) + lineF(p, "} while(false);$n", [labl.rope]) proc genBreakStmt(p: PProc, n: PNode) = var idx: int @@ -1010,11 +885,11 @@ proc genBreakStmt(p: PProc, n: PNode) = if idx < 0 or not p.blocks[idx].isLoop: internalError(p.config, n.info, "no loop to break") p.blocks[idx].id = abs(p.blocks[idx].id) # label is used - lineF(p, "break Label$1;$n", [rope(p.blocks[idx].id)]) + lineF(p, "break L$1;$n", [rope(p.blocks[idx].id)]) proc genAsmOrEmitStmt(p: PProc, n: PNode) = genLineDir(p, n) - p.body.add p.indentLine("") + p.body.add p.indentLine(nil) for i in 0..= 2 and x[0].typ.skipTypes(abstractInst).kind == tyCstring: - localError(p.config, x.info, "cstring doesn't support `[]=` operator") - gen(p, x, a) genLineDir(p, y) gen(p, y, b) # we don't care if it's an etyBaseIndex (global) of a string, it's # still a string that needs to be copied properly: - if x.typ.skipTypes(abstractInst).kind in {tySequence, tyString}: + if x.typ.skipTypes(abstractInst).kind in {tySequence, tyOpt, tyString}: xtyp = etySeq case xtyp of etySeq: - if x.typ.kind in {tyVar, tyLent} or (needsNoCopy(p, y) and needsNoCopy(p, x)) or noCopyNeeded: + if (needsNoCopy(p, y) and needsNoCopy(p, x)) or noCopyNeeded: lineF(p, "$1 = $2;$n", [a.rdLoc, b.rdLoc]) else: useMagic(p, "nimCopy") lineF(p, "$1 = nimCopy(null, $2, $3);$n", [a.rdLoc, b.res, genTypeInfo(p, y.typ)]) of etyObject: - if x.typ.kind in {tyVar, tyLent} or (needsNoCopy(p, y) and needsNoCopy(p, x)) or noCopyNeeded: + if x.typ.kind == tyVar or (needsNoCopy(p, y) and needsNoCopy(p, x)) or noCopyNeeded: lineF(p, "$1 = $2;$n", [a.rdLoc, b.rdLoc]) else: useMagic(p, "nimCopy") - # supports proc getF(): var T - if x.kind in {nkHiddenDeref, nkDerefExpr} and x[0].kind in nkCallKinds: - lineF(p, "nimCopy($1, $2, $3);$n", - [a.res, b.res, genTypeInfo(p, x.typ)]) - else: - lineF(p, "$1 = nimCopy($1, $2, $3);$n", - [a.res, b.res, genTypeInfo(p, x.typ)]) + lineF(p, "nimCopy($1, $2, $3);$n", + [a.res, b.res, genTypeInfo(p, y.typ)]) of etyBaseIndex: if a.typ != etyBaseIndex or b.typ != etyBaseIndex: if y.kind == nkCall: @@ -1150,25 +1016,10 @@ proc genAsgnAux(p: PProc, x, y: PNode, noCopyNeeded: bool) = lineF(p, "var $1 = $4; $2 = $1[0]; $3 = $1[1];$n", [tmp, a.address, a.res, b.rdLoc]) elif b.typ == etyBaseIndex: lineF(p, "$# = [$#, $#];$n", [a.res, b.address, b.res]) - elif b.typ == etyNone: - internalAssert p.config, b.address == "" - lineF(p, "$# = [$#, 0];$n", [a.address, b.res]) - elif x.typ.kind == tyVar and y.typ.kind == tyPtr: - lineF(p, "$# = [$#, $#];$n", [a.res, b.address, b.res]) - lineF(p, "$1 = $2;$n", [a.address, b.res]) - lineF(p, "$1 = $2;$n", [a.rdLoc, b.rdLoc]) - elif a.typ == etyBaseIndex: - # array indexing may not map to var type - if b.address != "": - lineF(p, "$1 = $2; $3 = $4;$n", [a.address, b.address, a.res, b.res]) - else: - lineF(p, "$1 = $2;$n", [a.address, b.res]) else: - internalError(p.config, x.info, $("genAsgn", b.typ, a.typ)) - elif b.address != "": - lineF(p, "$1 = $2; $3 = $4;$n", [a.address, b.address, a.res, b.res]) + internalError(p.config, x.info, "genAsgn") else: - lineF(p, "$1 = $2;$n", [a.address, b.res]) + lineF(p, "$1 = $2; $3 = $4;$n", [a.address, b.address, a.res, b.res]) else: lineF(p, "$1 = $2;$n", [a.rdLoc, b.rdLoc]) @@ -1183,7 +1034,7 @@ proc genFastAsgn(p: PProc, n: PNode) = # See bug #5933. So we try to be more compatible with the C backend semantics # here for 'shallowCopy'. This is an educated guess and might require further # changes later: - let noCopy = n[0].typ.skipTypes(abstractInst).kind in {tySequence, tyString} + let noCopy = n[0].typ.skipTypes(abstractInst).kind in {tySequence, tyOpt, tyString} genAsgnAux(p, n[0], n[1], noCopyNeeded=noCopy) proc genSwap(p: PProc, n: PNode) = @@ -1217,7 +1068,7 @@ proc genFieldAddr(p: PProc, n: PNode, r: var TCompRes) = else: if b[1].kind != nkSym: internalError(p.config, b[1].info, "genFieldAddr") var f = b[1].sym - if f.loc.r == "": f.loc.r = mangleName(p.module, f) + if f.loc.r == nil: f.loc.r = mangleName(p.module, f) r.res = makeJSString($f.loc.r) internalAssert p.config, a.typ != etyBaseIndex r.address = a.res @@ -1245,7 +1096,7 @@ proc genFieldAccess(p: PProc, n: PNode, r: var TCompRes) = else: if n[1].kind != nkSym: internalError(p.config, n[1].info, "genFieldAccess") var f = n[1].sym - if f.loc.r == "": f.loc.r = mangleName(p.module, f) + if f.loc.r == nil: f.loc.r = mangleName(p.module, f) r.res = "$1.$2" % [r.res, f.loc.r] mkTemp(1) r.kind = resExpr @@ -1266,11 +1117,11 @@ proc genCheckedFieldOp(p: PProc, n: PNode, addrTyp: PType, r: var TCompRes) = # Field symbol var field = accessExpr[1].sym internalAssert p.config, field.kind == skField - if field.loc.r == "": field.loc.r = mangleName(p.module, field) + if field.loc.r == nil: field.loc.r = mangleName(p.module, field) # Discriminant symbol let disc = checkExpr[2].sym internalAssert p.config, disc.kind == skField - if disc.loc.r == "": disc.loc.r = mangleName(p.module, disc) + if disc.loc.r == nil: disc.loc.r = mangleName(p.module, disc) var setx: TCompRes gen(p, checkExpr[1], setx) @@ -1282,13 +1133,12 @@ proc genCheckedFieldOp(p: PProc, n: PNode, addrTyp: PType, r: var TCompRes) = let tmp = p.getTemp() lineF(p, "var $1 = $2;$n", tmp, obj.res) - useMagic(p, "raiseFieldError2") + useMagic(p, "raiseFieldError") useMagic(p, "makeNimstrLit") - useMagic(p, "reprDiscriminant") # no need to offset by firstOrd unlike for cgen - let msg = genFieldDefect(p.config, field.name.s, disc) - lineF(p, "if ($1[$2.$3]$4undefined) { raiseFieldError2(makeNimstrLit($5), reprDiscriminant($2.$3, $6)); }$n", - setx.res, tmp, disc.loc.r, if negCheck: "!==" else: "===", - makeJSString(msg), genTypeInfo(p, disc.typ)) + let msg = genFieldError(field, disc) + lineF(p, "if ($1[$2.$3]$4undefined) { raiseFieldError(makeNimstrLit($5)); }$n", + setx.res, tmp, disc.loc.r, if negCheck: ~"!==" else: ~"===", + makeJSString(msg)) if addrTyp != nil and mapType(p, addrTyp) == etyBaseIndex: r.typ = etyBaseIndex @@ -1315,13 +1165,9 @@ proc genArrayAddr(p: PProc, n: PNode, r: var TCompRes) = first = firstOrd(p.config, typ[0]) if optBoundsCheck in p.options: useMagic(p, "chckIndx") - if first == 0: # save a couple chars - r.res = "chckIndx($1, 0, ($2).length - 1)" % [b.res, tmp] - else: - r.res = "chckIndx($1, $2, ($3).length + ($2) - 1) - ($2)" % [ - b.res, rope(first), tmp] + r.res = "chckIndx($1, $2, ($3 != null ? $3.length : 0)+$2-1)-$2" % [b.res, rope(first), tmp] elif first != 0: - r.res = "($1) - ($2)" % [b.res, rope(first)] + r.res = "($1)-$2" % [b.res, rope(first)] else: r.res = b.res r.kind = resExpr @@ -1330,14 +1176,14 @@ proc genArrayAccess(p: PProc, n: PNode, r: var TCompRes) = var ty = skipTypes(n[0].typ, abstractVarRange) if ty.kind in {tyRef, tyPtr, tyLent, tyOwned}: ty = skipTypes(ty.lastSon, abstractVarRange) case ty.kind - of tyArray, tyOpenArray, tySequence, tyString, tyCstring, tyVarargs: + of tyArray, tyOpenArray, tySequence, tyString, tyCString, tyVarargs: genArrayAddr(p, n, r) of tyTuple: genFieldAddr(p, n, r) else: internalError(p.config, n.info, "expr(nkBracketExpr, " & $ty.kind & ')') r.typ = mapType(n.typ) - if r.res == "": internalError(p.config, n.info, "genArrayAccess") - if ty.kind == tyCstring: + if r.res == nil: internalError(p.config, n.info, "genArrayAccess") + if ty.kind == tyCString: r.res = "$1.charCodeAt($2)" % [r.address, r.res] elif r.typ == etyBaseIndex: if needsTemp(p, n[0]): @@ -1361,96 +1207,58 @@ template isIndirect(x: PSym): bool = v.kind notin {skProc, skFunc, skConverter, skMethod, skIterator, skConst, skTemp, skLet}) -proc genSymAddr(p: PProc, n: PNode, typ: PType, r: var TCompRes) = - let s = n.sym - if s.loc.r == "": internalError(p.config, n.info, "genAddr: 3") - case s.kind - of skParam: - r.res = s.loc.r - r.address = "" - r.typ = etyNone - of skVar, skLet, skResult: - r.kind = resExpr - let jsType = mapType(p): - if typ.isNil: - n.typ - else: - typ - if jsType == etyObject: - # make addr() a no-op: - r.typ = etyNone - if isIndirect(s): - r.res = s.loc.r & "[0]" - else: - r.res = s.loc.r - r.address = "" - elif {sfGlobal, sfAddrTaken} * s.flags != {} or jsType == etyBaseIndex: - # for ease of code generation, we do not distinguish between - # sfAddrTaken and sfGlobal. - r.typ = etyBaseIndex - r.address = s.loc.r - r.res = rope("0") - else: - # 'var openArray' for instance produces an 'addr' but this is harmless: - gen(p, n, r) - #internalError(p.config, n.info, "genAddr: 4 " & renderTree(n)) - else: internalError(p.config, n.info, $("genAddr: 2", s.kind)) - proc genAddr(p: PProc, n: PNode, r: var TCompRes) = - if n.kind == nkSym: - genSymAddr(p, n, nil, r) - else: - case n[0].kind - of nkSym: - genSymAddr(p, n[0], n.typ, r) - of nkCheckedFieldExpr: - genCheckedFieldOp(p, n[0], n.typ, r) - of nkDotExpr: - if mapType(p, n.typ) == etyBaseIndex: - genFieldAddr(p, n[0], r) + case n[0].kind + of nkSym: + let s = n[0].sym + if s.loc.r == nil: internalError(p.config, n.info, "genAddr: 3") + case s.kind + of skVar, skLet, skResult: + r.kind = resExpr + let jsType = mapType(p, n.typ) + if jsType == etyObject: + # make addr() a no-op: + r.typ = etyNone + if isIndirect(s): + r.res = s.loc.r & "[0]" + else: + r.res = s.loc.r + r.address = nil + elif {sfGlobal, sfAddrTaken} * s.flags != {} or jsType == etyBaseIndex: + # for ease of code generation, we do not distinguish between + # sfAddrTaken and sfGlobal. + r.typ = etyBaseIndex + r.address = s.loc.r + r.res = rope("0") else: - genFieldAccess(p, n[0], r) - of nkBracketExpr: - var ty = skipTypes(n[0].typ, abstractVarRange) - if ty.kind in MappedToObject: - gen(p, n[0], r) - else: - let kindOfIndexedExpr = skipTypes(n[0][0].typ, abstractVarRange).kind - case kindOfIndexedExpr - of tyArray, tyOpenArray, tySequence, tyString, tyCstring, tyVarargs: - genArrayAddr(p, n[0], r) - of tyTuple: - genFieldAddr(p, n[0], r) - of tyGenericBody: - genAddr(p, n[^1], r) - else: internalError(p.config, n[0].info, "expr(nkBracketExpr, " & $kindOfIndexedExpr & ')') - of nkObjDownConv: - gen(p, n[0], r) - 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: - genAddr(p, n[0], r) - of nkStmtListExpr: - if n.len == 1: gen(p, n[0], r) - else: internalError(p.config, n[0].info, "genAddr for complex nkStmtListExpr") - of nkCallKinds: - if n[0].typ.kind == tyOpenArray: # 'var openArray' for instance produces an 'addr' but this is harmless: - # namely toOpenArray(a, 1, 3) gen(p, n[0], r) - else: - internalError(p.config, n[0].info, "genAddr: " & $n[0].kind) + #internalError(p.config, n.info, "genAddr: 4 " & renderTree(n)) + else: internalError(p.config, n.info, "genAddr: 2") + of nkCheckedFieldExpr: + genCheckedFieldOp(p, n[0], n.typ, r) + of nkDotExpr: + if mapType(p, n.typ) == etyBaseIndex: + genFieldAddr(p, n[0], r) else: - internalError(p.config, n[0].info, "genAddr: " & $n[0].kind) + genFieldAccess(p, n[0], r) + of nkBracketExpr: + var ty = skipTypes(n[0].typ, abstractVarRange) + if ty.kind in MappedToObject: + gen(p, n[0], r) + else: + let kindOfIndexedExpr = skipTypes(n[0][0].typ, abstractVarRange).kind + case kindOfIndexedExpr + of tyArray, tyOpenArray, tySequence, tyString, tyCString, tyVarargs: + genArrayAddr(p, n[0], r) + of tyTuple: + genFieldAddr(p, n[0], r) + else: internalError(p.config, n[0].info, "expr(nkBracketExpr, " & $kindOfIndexedExpr & ')') + of nkObjDownConv: + gen(p, n[0], r) + of nkHiddenDeref: + gen(p, n[0][0], r) + else: internalError(p.config, n[0].info, "genAddr: " & $n[0].kind) proc attachProc(p: PProc; content: Rope; s: PSym) = p.g.code.add(content) @@ -1489,10 +1297,10 @@ proc genSym(p: PProc, n: PNode, r: var TCompRes) = var s = n.sym case s.kind of skVar, skLet, skParam, skTemp, skResult, skForVar: - if s.loc.r == "": + if s.loc.r == nil: internalError(p.config, n.info, "symbol has no generated name: " & s.name.s) if sfCompileTime in s.flags: - genVarInit(p, s, if s.astdef != nil: s.astdef else: newNodeI(nkEmpty, s.info)) + genVarInit(p, s, if s.ast != nil: s.ast else: newNodeI(nkEmpty, s.info)) if s.kind == skParam: genCopyForParamIfNeeded(p, n) let k = mapType(p, s.typ) @@ -1514,7 +1322,7 @@ proc genSym(p: PProc, n: PNode, r: var TCompRes) = r.res = s.loc.r of skConst: genConstant(p, s) - if s.loc.r == "": + if s.loc.r == nil: internalError(p.config, n.info, "symbol has no generated name: " & s.name.s) r.res = s.loc.r of skProc, skFunc, skConverter, skMethod: @@ -1523,10 +1331,10 @@ proc genSym(p: PProc, n: PNode, r: var TCompRes) = s.name.s) discard mangleName(p.module, s) r.res = s.loc.r - if lfNoDecl in s.loc.flags or s.magic notin generatedMagics or + if lfNoDecl in s.loc.flags or s.magic != mNone or {sfImportc, sfInfixCall} * s.flags != {}: discard - elif s.kind == skMethod and getBody(p.module.graph, s).kind == nkEmpty: + elif s.kind == skMethod and s.getBody.kind == nkEmpty: # we cannot produce code for the dispatcher yet: discard elif sfForward in s.flags: @@ -1534,19 +1342,15 @@ proc genSym(p: PProc, n: PNode, r: var TCompRes) = else: genProcForSymIfNeeded(p, s) else: - if s.loc.r == "": + if s.loc.r == nil: internalError(p.config, n.info, "symbol has no generated name: " & s.name.s) - if mapType(p, s.typ) == etyBaseIndex: - r.address = s.loc.r - r.res = s.loc.r & "_Idx" - else: - r.res = s.loc.r + r.res = s.loc.r r.kind = resVal proc genDeref(p: PProc, n: PNode, r: var TCompRes) = let it = n[0] let t = mapType(p, it.typ) - if t == etyObject or it.typ.kind == tyLent: + if t == etyObject: gen(p, it, r) else: var a: TCompRes @@ -1559,7 +1363,7 @@ proc genDeref(p: PProc, n: PNode, r: var TCompRes) = r.res = "$1[1]" % [tmp] r.tmpLoc = tmp elif a.typ == etyBaseIndex: - if a.tmpLoc != "": + if a.tmpLoc != nil: r.tmpLoc = a.tmpLoc r.res = a.rdLoc else: @@ -1682,9 +1486,9 @@ proc genPatternCall(p: PProc; n: PNode; pat: string; typ: PType; proc genInfixCall(p: PProc, n: PNode, r: var TCompRes) = # don't call '$' here for efficiency: let f = n[0].sym - if f.loc.r == "": f.loc.r = mangleName(p.module, f) + if f.loc.r == nil: f.loc.r = mangleName(p.module, f) if sfInfixCall in f.flags: - let pat = $n[0].sym.loc.r + let pat = n[0].sym.loc.r.data internalAssert p.config, pat.len > 0 if pat.contains({'#', '(', '@'}): var typ = skipTypes(n[0].typ, abstractInst) @@ -1694,10 +1498,10 @@ proc genInfixCall(p: PProc, n: PNode, r: var TCompRes) = if n.len != 1: gen(p, n[1], r) if r.typ == etyBaseIndex: - if r.address == "": + if r.address == nil: globalError(p.config, n.info, "cannot invoke with infix syntax") r.res = "$1[$2]" % [r.address, r.res] - r.address = "" + r.address = nil r.typ = etyNone r.res.add(".") var op: TCompRes @@ -1765,35 +1569,26 @@ proc createObjInitList(p: PProc, typ: PType, excludedFieldIDs: IntSet, output: v t = t[0] proc arrayTypeForElemType(typ: PType): string = - let typ = typ.skipTypes(abstractRange) + # XXX This should also support tyEnum and tyBool case typ.kind of tyInt, tyInt32: "Int32Array" of tyInt16: "Int16Array" of tyInt8: "Int8Array" of tyUInt, tyUInt32: "Uint32Array" of tyUInt16: "Uint16Array" - of tyUInt8, tyChar, tyBool: "Uint8Array" + of tyUInt8: "Uint8Array" of tyFloat32: "Float32Array" of tyFloat64, tyFloat: "Float64Array" - of tyEnum: - case typ.size - of 1: "Uint8Array" - of 2: "Uint16Array" - of 4: "Uint32Array" - else: "" else: "" proc createVar(p: PProc, typ: PType, indirect: bool): Rope = var t = skipTypes(typ, abstractInst) case t.kind of tyInt..tyInt64, tyUInt..tyUInt64, tyEnum, tyChar: - if $t.sym.loc.r == "bigint": - result = putToSeq("0n", indirect) - else: - result = putToSeq("0", indirect) + result = putToSeq("0", indirect) of tyFloat..tyFloat128: result = putToSeq("0.0", indirect) - of tyRange, tyGenericInst, tyAlias, tySink, tyOwned, tyLent: + of tyRange, tyGenericInst, tyAlias, tySink, tyOwned: result = createVar(p, lastSon(typ), indirect) of tySet: result = putToSeq("{}", indirect) @@ -1833,28 +1628,26 @@ proc createVar(p: PProc, typ: PType, indirect: bool): Rope = of tyObject: var initList: Rope createObjInitList(p, t, initIntSet(), initList) - result = ("({$1})") % [initList] + result = ("{$1}") % [initList] if indirect: result = "[$1]" % [result] - of tyVar, tyPtr, tyRef, tyPointer: + of tyVar, tyPtr, tyLent, tyRef, tyPointer: if mapType(p, t) == etyBaseIndex: result = putToSeq("[null, 0]", indirect) else: result = putToSeq("null", indirect) - of tySequence, tyString: - result = putToSeq("[]", indirect) - of tyCstring, tyProc: + of tySequence, tyOpt, tyString, tyCString, tyProc: result = putToSeq("null", indirect) of tyStatic: if t.n != nil: result = createVar(p, lastSon t, indirect) else: internalError(p.config, "createVar: " & $t.kind) - result = "" + result = nil else: internalError(p.config, "createVar: " & $t.kind) - result = "" + result = nil -template returnType: untyped = "" +template returnType: untyped = ~"" proc genVarInit(p: PProc, v: PSym, n: PNode) = var @@ -1863,7 +1656,6 @@ proc genVarInit(p: PProc, v: PSym, n: PNode) = varCode: string varName = mangleName(p.module, v) useReloadingGuard = sfGlobal in v.flags and p.config.hcrOn - useGlobalPragmas = sfGlobal in v.flags and ({sfPure, sfThread} * v.flags != {}) if v.constraint.isNil: if useReloadingGuard: @@ -1871,10 +1663,6 @@ proc genVarInit(p: PProc, v: PSym, n: PNode) = lineF(p, "if ($1 === undefined) {$n", varName) varCode = $varName inc p.extraIndent - elif useGlobalPragmas: - lineF(p, "if (globalThis.$1 === undefined) {$n", varName) - varCode = "globalThis." & $varName - inc p.extraIndent else: varCode = "var $2" else: @@ -1927,7 +1715,7 @@ proc genVarInit(p: PProc, v: PSym, n: PNode) = else: line(p, runtimeFormat(varCode & " = $3;$n", [returnType, v.loc.r, s])) - if useReloadingGuard or useGlobalPragmas: + if useReloadingGuard: dec p.extraIndent lineF(p, "}$n") @@ -1936,7 +1724,7 @@ proc genVarStmt(p: PProc, n: PNode) = var a = n[i] if a.kind != nkCommentStmt: if a.kind == nkVarTuple: - let unpacked = lowerTupleUnpacking(p.module.graph, a, p.module.idgen, p.prc) + let unpacked = lowerTupleUnpacking(p.module.graph, a, p.prc) genStmt(p, unpacked) else: assert(a.kind == nkIdentDefs) @@ -1952,9 +1740,10 @@ proc genVarStmt(p: PProc, n: PNode) = proc genConstant(p: PProc, c: PSym) = if lfNoDecl notin c.loc.flags and not p.g.generatedSyms.containsOrIncl(c.id): - let oldBody = move p.body - #genLineDir(p, c.astdef) - genVarInit(p, c, c.astdef) + let oldBody = p.body + p.body = nil + #genLineDir(p, c.ast) + genVarInit(p, c, c.ast) p.g.constants.add(p.body) p.body = oldBody @@ -1974,13 +1763,13 @@ proc genNewSeq(p: PProc, n: PNode) = gen(p, n[1], x) gen(p, n[2], y) let t = skipTypes(n[1].typ, abstractVar)[0] - lineF(p, "$1 = new Array($2); for (var i = 0 ; i < $2 ; ++i) { $1[i] = $3; }", [ + lineF(p, "$1 = new Array($2); for (var i=0;i<$2;++i) {$1[i]=$3;}", [ x.rdLoc, y.rdLoc, createVar(p, t, false)]) proc genOrd(p: PProc, n: PNode, r: var TCompRes) = - case skipTypes(n[1].typ, abstractVar + abstractRange).kind + case skipTypes(n[1].typ, abstractVar).kind of tyEnum, tyInt..tyUInt64, tyChar: gen(p, n[1], r) - of tyBool: unaryExpr(p, n, r, "", "($1 ? 1 : 0)") + of tyBool: unaryExpr(p, n, r, "", "($1 ? 1:0)") else: internalError(p.config, n.info, "genOrd") proc genConStrStr(p: PProc, n: PNode, r: var TCompRes) = @@ -2006,7 +1795,27 @@ proc genConStrStr(p: PProc, n: PNode, r: var TCompRes) = else: r.res.add("$1 || [])" % [a.res]) -proc genReprAux(p: PProc, n: PNode, r: var TCompRes, magic: string, typ: Rope = "") = +proc genToArray(p: PProc; n: PNode; r: var TCompRes) = + # we map mArray to PHP's array constructor, a mild hack: + var a, b: TCompRes + r.kind = resExpr + r.res = rope("array(") + let x = skipConv(n[1]) + if x.kind == nkBracket: + for i in 0.. 0: r.res.add(", ") + gen(p, it[0], a) + gen(p, it[1], b) + r.res.add("$# => $#" % [a.rdLoc, b.rdLoc]) + else: + localError(p.config, it.info, "'toArray' needs tuple constructors") + else: + localError(p.config, x.info, "'toArray' needs an array literal") + r.res.add(")") + +proc genReprAux(p: PProc, n: PNode, r: var TCompRes, magic: string, typ: Rope = nil) = useMagic(p, magic) r.res.add(magic & "(") var a: TCompRes @@ -2015,7 +1824,7 @@ proc genReprAux(p: PProc, n: PNode, r: var TCompRes, magic: string, typ: Rope = if magic == "reprAny": # the pointer argument in reprAny is expandend to # (pointedto, pointer), so we need to fill it - if a.address.len == 0: + if a.address.isNil: r.res.add(a.res) r.res.add(", null") else: @@ -2023,14 +1832,14 @@ proc genReprAux(p: PProc, n: PNode, r: var TCompRes, magic: string, typ: Rope = else: r.res.add(a.res) - if typ != "": + if not typ.isNil: r.res.add(", ") r.res.add(typ) r.res.add(")") proc genRepr(p: PProc, n: PNode, r: var TCompRes) = let t = skipTypes(n[1].typ, abstractVarRange) - case t.kind + case t.kind: of tyInt..tyInt64, tyUInt..tyUInt64: genReprAux(p, n, r, "reprInt") of tyChar: @@ -2053,7 +1862,6 @@ proc genRepr(p: PProc, n: PNode, r: var TCompRes) = genReprAux(p, n, r, "reprJSONStringify") else: genReprAux(p, n, r, "reprAny", genTypeInfo(p, t)) - r.kind = resExpr proc genOf(p: PProc, n: PNode, r: var TCompRes) = var x: TCompRes @@ -2078,7 +1886,7 @@ proc genReset(p: PProc, n: PNode) = if x.typ == etyBaseIndex: lineF(p, "$1 = null, $2 = 0;$n", [x.address, x.res]) else: - let (a, tmp) = maybeMakeTempAssignable(p, n[1], x) + let (a, tmp) = maybeMakeTemp(p, n[1], x) lineF(p, "$1 = genericReset($3, $2);$n", [a, genTypeInfo(p, n[1].typ), tmp]) @@ -2091,23 +1899,6 @@ proc genMove(p: PProc; n: PNode; r: var TCompRes) = genReset(p, n) #lineF(p, "$1 = $2;$n", [dest.rdLoc, src.rdLoc]) -proc genJSArrayConstr(p: PProc, n: PNode, r: var TCompRes) = - var a: TCompRes - r.res = rope("[") - r.kind = resExpr - for i in 0 ..< n.len: - if i > 0: r.res.add(", ") - gen(p, n[i], a) - if a.typ == etyBaseIndex: - r.res.addf("[$1, $2]", [a.address, a.res]) - else: - if not needsNoCopy(p, n[i]): - let typ = n[i].typ.skipTypes(abstractInst) - useMagic(p, "nimCopy") - a.res = "nimCopy(null, $1, $2)" % [a.rdLoc, genTypeInfo(p, typ)] - r.res.add(a.res) - r.res.add("]") - proc genMagic(p: PProc, n: PNode, r: var TCompRes) = var a: TCompRes @@ -2119,37 +1910,43 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) = of mAddI..mStrToStr: arith(p, n, r, op) of mRepr: genRepr(p, n, r) of mSwap: genSwap(p, n) + of mUnaryLt: + # XXX: range checking? + if not (optOverflowCheck in p.options): unaryExpr(p, n, r, "", "$1 - 1") + else: unaryExpr(p, n, r, "subInt", "subInt($1, 1)") of mAppendStrCh: binaryExpr(p, n, r, "addChar", - "addChar($1, $2);") + "if ($1 != null) { addChar($3, $2); } else { $3 = [$2]; }") of mAppendStrStr: var lhs, rhs: TCompRes gen(p, n[1], lhs) gen(p, n[2], rhs) - if skipTypes(n[1].typ, abstractVarRange).kind == tyCstring: - let (b, tmp) = maybeMakeTemp(p, n[2], rhs) - r.res = "if (null != $1) { if (null == $2) $2 = $3; else $2 += $3; }" % - [b, lhs.rdLoc, tmp] + let rhsIsLit = n[2].kind in nkStrKinds + let (a, tmp) = maybeMakeTemp(p, n[1], lhs) + if skipTypes(n[1].typ, abstractVarRange).kind == tyCString: + r.res = "if ($1 != null) { $4 += $2; } else { $4 = $2$3; }" % [ + a, rhs.rdLoc, if rhsIsLit: nil else: ~".slice()", tmp] else: - let (a, tmp) = maybeMakeTemp(p, n[1], lhs) - r.res = "$1.push.apply($3, $2);" % [a, rhs.rdLoc, tmp] + r.res = "if ($1 != null) { $4 = ($4).concat($2); } else { $4 = $2$3; }" % [ + lhs.rdLoc, rhs.rdLoc, if rhsIsLit: nil else: ~".slice()", tmp] r.kind = resExpr of mAppendSeqElem: var x, y: TCompRes gen(p, n[1], x) gen(p, n[2], y) + let (a, tmp) = maybeMakeTemp(p, n[1], x) if mapType(n[2].typ) == etyBaseIndex: let c = "[$1, $2]" % [y.address, y.res] - r.res = "$1.push($2);" % [x.rdLoc, c] + r.res = "if ($1 != null) { $3.push($2); } else { $3 = [$2]; }" % [a, c, tmp] elif needsNoCopy(p, n[2]): - r.res = "$1.push($2);" % [x.rdLoc, y.rdLoc] + r.res = "if ($1 != null) { $3.push($2); } else { $3 = [$2]; }" % [a, y.rdLoc, tmp] else: useMagic(p, "nimCopy") let c = getTemp(p, defineInLocals=false) lineF(p, "var $1 = nimCopy(null, $2, $3);$n", [c, y.rdLoc, genTypeInfo(p, n[2].typ)]) - r.res = "$1.push($2);" % [x.rdLoc, c] + r.res = "if ($1 != null) { $3.push($2); } else { $3 = [$2]; }" % [a, c, tmp] r.kind = resExpr of mConStrStr: genConStrStr(p, n, r) @@ -2171,52 +1968,35 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) = of mNew, mNewFinalize: genNew(p, n) of mChr: gen(p, n[1], r) of mArrToSeq: - # only array literals doesn't need copy - if n[1].kind == nkBracket: - genJSArrayConstr(p, n[1], r) + if needsNoCopy(p, n[1]): + gen(p, n[1], r) else: var x: TCompRes gen(p, n[1], x) useMagic(p, "nimCopy") r.res = "nimCopy(null, $1, $2)" % [x.rdLoc, genTypeInfo(p, n.typ)] - of mOpenArrayToSeq: - genCall(p, n, r) - of mDestroy, mTrace: discard "ignore calls to the default destructor" + of mDestroy: discard "ignore calls to the default destructor" of mOrd: genOrd(p, n, r) of mLengthStr, mLengthSeq, mLengthOpenArray, mLengthArray: - var x: TCompRes - gen(p, n[1], x) - if skipTypes(n[1].typ, abstractInst).kind == tyCstring: - let (a, tmp) = maybeMakeTemp(p, n[1], x) - r.res = "(($1) == null ? 0 : ($2).length)" % [a, tmp] - else: - r.res = "($1).length" % [x.rdLoc] - r.kind = resExpr + unaryExpr(p, n, r, "", "($1 != null ? $2.length : 0)") + of mXLenStr, mXLenSeq: + unaryExpr(p, n, r, "", "$1.length") of mHigh: - var x: TCompRes - gen(p, n[1], x) - if skipTypes(n[1].typ, abstractInst).kind == tyCstring: - let (a, tmp) = maybeMakeTemp(p, n[1], x) - r.res = "(($1) == null ? -1 : ($2).length - 1)" % [a, tmp] - else: - r.res = "($1).length - 1" % [x.rdLoc] - r.kind = resExpr + unaryExpr(p, n, r, "", "($1 != null ? ($2.length-1) : -1)") of mInc: if n[1].typ.skipTypes(abstractRange).kind in {tyUInt..tyUInt64}: binaryUintExpr(p, n, r, "+", true) else: if optOverflowCheck notin p.options: binaryExpr(p, n, r, "", "$1 += $2") - else: binaryExpr(p, n, r, "addInt", "$1 = addInt($3, $2)", true) + else: binaryExpr(p, n, r, "addInt", "$1 = addInt($3, $2)") of ast.mDec: if n[1].typ.skipTypes(abstractRange).kind in {tyUInt..tyUInt64}: binaryUintExpr(p, n, r, "-", true) else: if optOverflowCheck notin p.options: binaryExpr(p, n, r, "", "$1 -= $2") - else: binaryExpr(p, n, r, "subInt", "$1 = subInt($3, $2)", true) + else: binaryExpr(p, n, r, "subInt", "$1 = subInt($3, $2)") of mSetLengthStr: - binaryExpr(p, n, r, "mnewString", - """if ($1.length < $2) { for (var i = $3.length; i < $4; ++i) $3.push(0); } - else {$3.length = $4; }""") + binaryExpr(p, n, r, "mnewString", "($1 == null ? $3 = mnewString($2) : $3.length = $2)") of mSetLengthSeq: var x, y: TCompRes gen(p, n[1], x) @@ -2224,7 +2004,8 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) = let t = skipTypes(n[1].typ, abstractVar)[0] let (a, tmp) = maybeMakeTemp(p, n[1], x) let (b, tmp2) = maybeMakeTemp(p, n[2], y) - r.res = """if ($1.length < $2) { for (var i = $4.length ; i < $5 ; ++i) $4.push($3); } + r.res = """if ($1 === null) $4 = []; + if ($4.length < $2) { for (var i=$4.length;i<$5;++i) $4.push($3); } else { $4.length = $5; }""" % [a, b, createVar(p, t, false), tmp, tmp2] r.kind = resExpr of mCard: unaryExpr(p, n, r, "SetCard", "SetCard($1)") @@ -2241,11 +2022,13 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) = of mNewSeq: genNewSeq(p, n) of mNewSeqOfCap: unaryExpr(p, n, r, "", "[]") of mOf: genOf(p, n, r) - of mDefault, mZeroDefault: genDefault(p, n, r) + of mDefault: genDefault(p, n, r) of mReset, mWasMoved: genReset(p, n) of mEcho: genEcho(p, n, r) of mNLen..mNError, mSlurp, mStaticExec: localError(p.config, n.info, errXMustBeCompileTime % n[0].sym.name.s) + of mCopyStr: + binaryExpr(p, n, r, "", "($1.slice($2))") of mNewString: unaryExpr(p, n, r, "mnewString", "mnewString($1)") of mNewStringOfCap: unaryExpr(p, n, r, "mnewString", "mnewString(0)") @@ -2261,7 +2044,7 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) = gen(p, n[1], x) gen(p, n[2], y) gen(p, n[3], z) - r.res = "($1.slice($2, $3 + 1))" % [x.rdLoc, y.rdLoc, z.rdLoc] + r.res = "($1.slice($2, $3+1))" % [x.rdLoc, y.rdLoc, z.rdLoc] r.kind = resExpr of mMove: genMove(p, n, r) @@ -2281,11 +2064,7 @@ proc genSetConstr(p: PProc, n: PNode, r: var TCompRes) = if it.kind == nkRange: gen(p, it[0], a) gen(p, it[1], b) - - if it[0].typ.kind == tyBool: - r.res.addf("$1, $2", [a.res, b.res]) - else: - r.res.addf("[$1, $2]", [a.res, b.res]) + r.res.addf("[$1, $2]", [a.res, b.res]) else: gen(p, it, a) r.res.add(a.res) @@ -2298,26 +2077,21 @@ proc genSetConstr(p: PProc, n: PNode, r: var TCompRes) = r.res = tmp proc genArrayConstr(p: PProc, n: PNode, r: var TCompRes) = - ## Constructs array or sequence. - ## Nim array of uint8..uint32, int8..int32 maps to JS typed arrays. - ## Nim sequence maps to JS array. - var t = skipTypes(n.typ, abstractInst) - let e = elemType(t) - 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]` - # TODO use `set` or loop to initialize typed array which improves performances in some situations - var a: TCompRes - r.res = "new $1([" % [rope(jsTyp)] - r.kind = resExpr - for i in 0 ..< n.len: - if i > 0: r.res.add(", ") - gen(p, n[i], a) + var a: TCompRes + r.res = rope("[") + r.kind = resExpr + for i in 0.. 0: r.res.add(", ") + gen(p, n[i], a) + if a.typ == etyBaseIndex: + r.res.addf("[$1, $2]", [a.address, a.res]) + else: + if not needsNoCopy(p, n[i]): + let typ = n[i].typ.skipTypes(abstractInst) + useMagic(p, "nimCopy") + a.res = "nimCopy(null, $1, $2)" % [a.rdLoc, genTypeInfo(p, typ)] r.res.add(a.res) - r.res.add("])") - else: - genJSArrayConstr(p, n, r) + r.res.add("]") proc genTupleConstr(p: PProc, n: PNode, r: var TCompRes) = var a: TCompRes @@ -2343,7 +2117,6 @@ proc genObjConstr(p: PProc, n: PNode, r: var TCompRes) = r.kind = resExpr var initList : Rope var fieldIDs = initIntSet() - let nTyp = n.typ.skipTypes(abstractInst) for i in 1.. 1: initList.add(", ") var it = n[i] @@ -2351,8 +2124,8 @@ proc genObjConstr(p: PProc, n: PNode, r: var TCompRes) = let val = it[1] gen(p, val, a) var f = it[0].sym - if f.loc.r == "": f.loc.r = mangleName(p.module, f) - fieldIDs.incl(lookupFieldAgain(n.typ.skipTypes({tyDistinct}), f).id) + if f.loc.r == nil: f.loc.r = mangleName(p.module, f) + fieldIDs.incl(f.id) let typ = val.typ.skipTypes(abstractInst) if a.typ == etyBaseIndex: @@ -2373,18 +2146,12 @@ proc genConv(p: PProc, n: PNode, r: var TCompRes) = if dest.kind == src.kind: # no-op conversion return - let toInt = (dest.kind in tyInt..tyInt32) - let fromInt = (src.kind in tyInt..tyInt32) - let toUint = (dest.kind in tyUInt..tyUInt32) - let fromUint = (src.kind in tyUInt..tyUInt32) - if toUint and (fromInt or fromUint): - let trimmer = unsignedTrimmer(dest.size) - r.res = "($1 $2)" % [r.res, trimmer] - elif dest.kind == tyBool: + case dest.kind: + of tyBool: r.res = "(!!($1))" % [r.res] r.kind = resExpr - elif toInt: - r.res = "(($1) | 0)" % [r.res] + of tyInt: + r.res = "(($1)|0)" % [r.res] else: # TODO: What types must we handle here? discard @@ -2412,7 +2179,7 @@ proc convStrToCStr(p: PProc, n: PNode, r: var TCompRes) = gen(p, n[0][0], r) else: gen(p, n[0], r) - if r.res == "": internalError(p.config, n.info, "convStrToCStr") + if r.res == nil: internalError(p.config, n.info, "convStrToCStr") useMagic(p, "toJSStr") r.res = "toJSStr($1)" % [r.res] r.kind = resExpr @@ -2424,7 +2191,7 @@ proc convCStrToStr(p: PProc, n: PNode, r: var TCompRes) = gen(p, n[0][0], r) else: gen(p, n[0], r) - if r.res == "": internalError(p.config, n.info, "convCStrToStr") + if r.res == nil: internalError(p.config, n.info, "convCStrToStr") useMagic(p, "cstrToNimstr") r.res = "cstrToNimstr($1)" % [r.res] r.kind = resExpr @@ -2440,7 +2207,7 @@ proc genReturnStmt(p: PProc, n: PNode) = proc frameCreate(p: PProc; procname, filename: Rope): Rope = const frameFmt = - "var F = {procname: $1, prev: framePtr, filename: $2, line: 0};$n" + "var F={procname:$1,prev:framePtr,filename:$2,line:0};$n" result = p.indentLine(frameFmt % [procname, filename]) result.add p.indentLine(ropes.`%`("framePtr = F;$n", [])) @@ -2452,13 +2219,13 @@ proc genProcBody(p: PProc, prc: PSym): Rope = if hasFrameInfo(p): result = frameCreate(p, makeJSString(prc.owner.name.s & '.' & prc.name.s), - makeJSString(toFilenameOption(p.config, prc.info.fileIndex, foStacktrace))) + makeJSString(toFilename(p.config, prc.info))) else: - result = "" + result = nil if p.beforeRetNeeded: - result.add p.indentLine("BeforeRet: {\n") + result.add p.indentLine(~"BeforeRet: do {$n") result.add p.body - result.add p.indentLine("};\n") + result.add p.indentLine(~"} while (false);$n") else: result.add(p.body) if prc.typ.callConv == ccSysCall: @@ -2468,13 +2235,12 @@ proc genProcBody(p: PProc, prc: PSym): Rope = result.add(frameDestroy(p)) proc optionalLine(p: Rope): Rope = - if p == "": - return "" + if p == nil: + return nil else: return p & "\L" proc genProc(oldProc: PProc, prc: PSym): Rope = - ## Generate a JS procedure ('function'). var resultSym: PSym a: TCompRes @@ -2482,18 +2248,16 @@ proc genProc(oldProc: PProc, prc: PSym): Rope = # echo "BEGIN generating code for: " & prc.name.s var p = newProc(oldProc.g, oldProc.module, prc.ast, prc.options) p.up = oldProc - var returnStmt: Rope = "" - var resultAsgn: Rope = "" + var returnStmt: Rope = nil + var resultAsgn: Rope = nil var name = mangleName(p.module, prc) let header = generateHeader(p, prc.typ) 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 + if not isIndirect(resultSym) and resultSym.typ.kind in {tyVar, tyPtr, tyLent, tyRef, tyOwned} and - mapType(p, resultSym.typ) == etyBaseIndex - if useRawPointer: + mapType(p, resultSym.typ) == etyBaseIndex: resultAsgn = p.indentLine(("var $# = null;$n") % [mname]) resultAsgn.add p.indentLine("var $#_Idx = 0;$n" % [mname]) else: @@ -2505,16 +2269,12 @@ proc genProc(oldProc: PProc, prc: PSym): Rope = else: returnStmt = "return $#;$n" % [a.res] - var transformedBody = transformBody(p.module.graph, p.module.idgen, prc, dontUseCache) + var transformedBody = transformBody(oldProc.module.graph, prc, cache = false) if sfInjectDestructors in prc.flags: - transformedBody = injectDestructorCalls(p.module.graph, p.module.idgen, prc, transformedBody) + transformedBody = injectDestructorCalls(oldProc.module.graph, prc, transformedBody) p.nested: genStmt(p, transformedBody) - - if optLineDir in p.config.options: - result = lineDir(p.config, prc.info, toLinenumber(prc.info)) - var def: Rope if not prc.constraint.isNil: def = runtimeFormat(prc.constraint.strVal & " {$n$#$#$#$#$#", @@ -2527,8 +2287,7 @@ proc genProc(oldProc: PProc, prc: PSym): Rope = optionalLine(genProcBody(p, prc)), optionalLine(p.indentLine(returnStmt))]) else: - # if optLineDir in p.config.options: - # result.add("\L") + result = ~"\L" if p.config.hcrOn: # Here, we introduce thunks that create the equivalent of a jump table @@ -2537,10 +2296,10 @@ proc genProc(oldProc: PProc, prc: PSym): Rope = # references will end up calling the reloaded code. var thunkName = name name = name & "IMLP" - result.add("\Lfunction $#() { return $#.apply(this, arguments); }$n" % + result.add("function $#() { return $#.apply(this, arguments); }$n" % [thunkName, name]) - def = "\Lfunction $#($#) {$n$#$#$#$#$#" % + def = "function $#($#) {$n$#$#$#$#$#" % [ name, header, optionalLine(p.globals), @@ -2551,7 +2310,7 @@ proc genProc(oldProc: PProc, prc: PSym): Rope = dec p.extraIndent result.add p.indentLine(def) - result.add p.indentLine("}\n") + result.add p.indentLine(~"}$n") #if gVerbosity >= 3: # echo "END generated code for: " & prc.name.s @@ -2559,17 +2318,12 @@ proc genProc(oldProc: PProc, prc: PSym): Rope = proc genStmt(p: PProc, n: PNode) = var r: TCompRes gen(p, n, r) - if r.res != "": lineF(p, "$#;$n", [r.res]) + if r.res != nil: lineF(p, "$#;$n", [r.res]) proc genPragma(p: PProc, n: PNode) = - for i in 0.. 0: s.add(", \L") s.add(genObjectFields(p, typ, n[i])) @@ -44,13 +44,13 @@ proc genObjectFields(p: PProc, typ: PType, n: PNode): Rope = s = genTypeInfo(p, field.typ) for i in 1.. 0: s.add(", \L") s.addf("{kind: 1, offset: \"Field$1\", len: 0, " & @@ -102,7 +102,7 @@ proc genTupleInfo(p: PProc, typ: PType, name: Rope) = p.g.typeInfo.addf("$1.node = NNI$2;$n", [name, rope(typ.id)]) proc genEnumInfo(p: PProc, typ: PType, name: Rope) = - var s: Rope = "" + var s: Rope = nil for i in 0.. which cannot be captured as it would violate memory" & - " safety, declared here: $3; using '-d:nimNoLentIterators' helps in some cases." & - " Consider using a which can be captured.") % - [s.name.s, typeToString(s.typ), g.config$s.info]) - elif not (owner.typ.callConv == ccClosure or owner.typ.callConv == ccNimCall and tfExplicitCallConv notin owner.typ.flags): + " safety, declared here: $3") % [s.name.s, typeToString(s.typ), g.config$s.info]) + elif owner.typ.callConv notin {ccClosure, ccDefault}: localError(g.config, n.info, "illegal capture '$1' because '$2' has the calling convention: <$3>" % - [s.name.s, owner.name.s, $owner.typ.callConv]) + [s.name.s, owner.name.s, CallingConvToStr[owner.typ.callConv]]) incl(owner.typ.flags, tfCapturesEnv) owner.typ.callConv = ccClosure @@ -311,15 +304,13 @@ type ownerToType: Table[int, PType] somethingToDo: bool graph: ModuleGraph - idgen: IdGenerator -proc initDetectionPass(g: ModuleGraph; fn: PSym; idgen: IdGenerator): DetectionPass = +proc initDetectionPass(g: ModuleGraph; fn: PSym): DetectionPass = result.processed = initIntSet() result.capturedVars = initIntSet() result.ownerToType = initTable[int, PType]() result.processed.incl(fn.id) result.graph = g - result.idgen = idgen discard """ proc outer = @@ -335,15 +326,15 @@ proc getEnvTypeForOwner(c: var DetectionPass; owner: PSym; info: TLineInfo): PType = result = c.ownerToType.getOrDefault(owner.id) if result.isNil: - result = newType(tyRef, nextTypeId(c.idgen), owner) - let obj = createEnvObj(c.graph, c.idgen, owner, info) + result = newType(tyRef, owner) + let obj = createEnvObj(c.graph, owner, info) rawAddSon(result, obj) c.ownerToType[owner.id] = result -proc asOwnedRef(c: var DetectionPass; t: PType): PType = +proc asOwnedRef(c: DetectionPass; t: PType): PType = if optOwnedRefs in c.graph.config.globalOptions: assert t.kind == tyRef - result = newType(tyOwned, nextTypeId(c.idgen), t.owner) + result = newType(tyOwned, t.owner) result.flags.incl tfHasOwned result.rawAddSon t else: @@ -352,7 +343,7 @@ proc asOwnedRef(c: var DetectionPass; t: PType): PType = proc getEnvTypeForOwnerUp(c: var DetectionPass; owner: PSym; info: TLineInfo): PType = var r = c.getEnvTypeForOwner(owner, info) - result = newType(tyPtr, nextTypeId(c.idgen), owner) + result = newType(tyPtr, owner) rawAddSon(result, r.skipTypes({tyOwned, tyRef, tyPtr})) proc createUpField(c: var DetectionPass; dest, dep: PSym; info: TLineInfo) = @@ -380,7 +371,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, nextSymId(c.idgen), obj.owner, obj.owner.info) + let result = newSym(skField, upIdent, obj.owner, obj.owner.info) result.typ = fieldType when false: if c.graph.config.selectedGC == gcDestructors: @@ -418,7 +409,7 @@ proc addClosureParam(c: var DetectionPass; fn: PSym; info: TLineInfo) = 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), nextSymId(c.idgen), fn, fn.info) + cp = newSym(skParam, getIdent(c.graph.cache, paramName), fn, fn.info) incl(cp.flags, sfFromGeneric) cp.typ = t addHiddenParam(fn, cp) @@ -441,7 +432,7 @@ proc detectCapturedVars(n: PNode; owner: PSym; c: var DetectionPass) = if innerProc: if s.isIterator: c.somethingToDo = true if not c.processed.containsOrIncl(s.id): - let body = transformBody(c.graph, c.idgen, s, useCache) + let body = transformBody(c.graph, s, cache = true) detectCapturedVars(body, s, c) let ow = s.skipGenericOwner if ow == owner: @@ -454,11 +445,11 @@ proc detectCapturedVars(n: PNode; owner: PSym; c: var DetectionPass) = #let obj = c.getEnvTypeForOwner(s.owner).skipTypes({tyOwned, tyRef, tyPtr}) if s.name.id == getIdent(c.graph.cache, ":state").id: - obj.n[0].sym.itemId = ItemId(module: s.itemId.module, item: -s.itemId.item) + obj.n[0].sym.id = -s.id else: - discard addField(obj, s, c.graph.cache, c.idgen) + addField(obj, s, c.graph.cache) # direct or indirect dependency: - elif (innerProc and not s.isIterator and s.typ.callConv == ccClosure) or interestingVar(s): + elif (innerProc and s.typ.callConv == ccClosure) or interestingVar(s): discard """ proc outer() = var x: int @@ -478,7 +469,7 @@ proc detectCapturedVars(n: PNode; owner: PSym; c: var DetectionPass) = if interestingVar(s) and not c.capturedVars.containsOrIncl(s.id): let obj = c.getEnvTypeForOwner(ow, n.info).skipTypes({tyOwned, tyRef, tyPtr}) #getHiddenParam(owner).typ.skipTypes({tyOwned, tyRef, tyPtr}) - discard addField(obj, s, c.graph.cache, c.idgen) + addField(obj, s, c.graph.cache) # create required upFields: var w = owner.skipGenericOwner if isInnerProc(w) or owner.isIterator: @@ -502,8 +493,7 @@ proc detectCapturedVars(n: PNode; owner: PSym; c: var DetectionPass) = w = up of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit, nkTemplateDef, nkTypeSection, nkProcDef, nkMethodDef, - nkConverterDef, nkMacroDef, nkFuncDef, nkCommentStmt, - nkTypeOfExpr, nkMixinStmt, nkBindStmt: + nkConverterDef, nkMacroDef, nkFuncDef, nkCommentStmt, nkTypeOfExpr: discard of nkLambdaKinds, nkIteratorDef: if n.typ != nil: @@ -544,8 +534,8 @@ proc accessViaEnvParam(g: ModuleGraph; n: PNode; owner: PSym): PNode = localError(g.config, n.info, "internal error: environment misses: " & s.name.s) result = n -proc newEnvVar(cache: IdentCache; owner: PSym; typ: PType; info: TLineInfo; idgen: IdGenerator): PNode = - var v = newSym(skVar, getIdent(cache, envName), nextSymId(idgen), owner, info) +proc newEnvVar(cache: IdentCache; owner: PSym; typ: PType; info: TLineInfo): PNode = + var v = newSym(skVar, getIdent(cache, envName), owner, info) v.flags = {sfShadowed, sfGeneratedOp} v.typ = typ result = newSymNode(v) @@ -557,7 +547,7 @@ proc newEnvVar(cache: IdentCache; owner: PSym; typ: PType; info: TLineInfo; idge else: result = newSymNode(v) -proc setupEnvVar(owner: PSym; d: var DetectionPass; +proc setupEnvVar(owner: PSym; d: DetectionPass; c: var LiftingPass; info: TLineInfo): PNode = if owner.isIterator: return getHiddenParam(d.graph, owner).newSymNode @@ -566,10 +556,10 @@ proc setupEnvVar(owner: PSym; d: var DetectionPass; let envVarType = d.ownerToType.getOrDefault(owner.id) if envVarType.isNil: localError d.graph.config, owner.info, "internal error: could not determine closure type" - result = newEnvVar(d.graph.cache, owner, asOwnedRef(d, envVarType), info, d.idgen) + result = newEnvVar(d.graph.cache, owner, asOwnedRef(d, envVarType), info) c.envVars[owner.id] = result if optOwnedRefs in d.graph.config.globalOptions: - var v = newSym(skVar, getIdent(d.graph.cache, envName & "Alt"), nextSymId d.idgen, owner, info) + var v = newSym(skVar, getIdent(d.graph.cache, envName & "Alt"), owner, info) v.flags = {sfShadowed, sfGeneratedOp} v.typ = envVarType c.unownedEnvVars[owner.id] = newSymNode(v) @@ -585,7 +575,7 @@ proc getUpViaParam(g: ModuleGraph; owner: PSym): PNode = result = rawIndirectAccess(result, upField, p.info) proc rawClosureCreation(owner: PSym; - d: var DetectionPass; c: var LiftingPass; + d: DetectionPass; c: var LiftingPass; info: TLineInfo): PNode = result = newNodeI(nkStmtList, owner.info) @@ -604,14 +594,14 @@ proc rawClosureCreation(owner: PSym; addVar(v, unowned) # add 'new' statement: - result.add genCreateEnv(env) + result.add(newCall(getSysSym(d.graph, env.info, "internalNew"), env)) if optOwnedRefs in d.graph.config.globalOptions: let unowned = c.unownedEnvVars[owner.id] assert unowned != nil let env2 = copyTree(env) env2.typ = unowned.typ result.add newAsgnStmt(unowned, env2, env.info) - createTypeBoundOpsLL(d.graph, unowned.typ, env.info, d.idgen, owner) + createTypeBoundOpsLL(d.graph, unowned.typ, env.info, owner) # add assignment statements for captured parameters: for i in 1..= em.maxLineLen div 2 @@ -402,7 +402,7 @@ proc endsInAlpha(em: Emitter): bool = while i >= 0 and em.kinds[i] in {ltBeginSection, ltEndSection}: dec(i) result = if i >= 0: em.tokens[i].lastChar in SymChars+{'_'} else: false -proc emitComment(em: var Emitter; tok: Token; dontIndent: bool) = +proc emitComment(em: var Emitter; tok: TToken; dontIndent: bool) = var col = em.col let lit = strip fileSection(em.config, em.fid, tok.commentOffsetA, tok.commentOffsetB) em.lineSpan = countNewlines(lit) @@ -417,7 +417,7 @@ proc emitComment(em: var Emitter; tok: Token; dontIndent: bool) = inc col emitMultilineComment(em, lit, col, dontIndent) -proc emitTok*(em: var Emitter; L: Lexer; tok: Token) = +proc emitTok*(em: var Emitter; L: TLexer; tok: TToken) = template wasExportMarker(em): bool = em.kinds.len > 0 and em.kinds[^1] == ltExportMarker @@ -452,9 +452,6 @@ proc emitTok*(em: var Emitter; L: Lexer; tok: Token) = if tok.tokType in openPars and tok.indent > em.indentStack[^1]: while em.indentStack[^1] < tok.indent: em.indentStack.add(em.indentStack[^1] + em.indWidth) - while em.indentStack[^1] > tok.indent: - discard em.indentStack.pop() - # aka: we are in an expression context: let alignment = max(tok.indent - em.indentStack[^1], 0) em.indentLevel = alignment + em.indentStack.high * em.indWidth @@ -494,7 +491,7 @@ proc emitTok*(em: var Emitter; L: Lexer; tok: Token) = wrSpace em if not em.inquote: - wr(em, $tok.tokType, ltKeyword) + wr(em, TokTypeToStr[tok.tokType], ltKeyword) if tok.tokType in {tkAnd, tkOr, tkIn, tkNotin}: rememberSplit(splitIn) wrSpace em @@ -503,32 +500,31 @@ proc emitTok*(em: var Emitter; L: Lexer; tok: Token) = wr(em, tok.ident.s, ltIdent) of tkColon: - wr(em, $tok.tokType, ltOther) + wr(em, TokTypeToStr[tok.tokType], ltOther) wrSpace em of tkSemiColon, tkComma: - wr(em, $tok.tokType, ltOther) + wr(em, TokTypeToStr[tok.tokType], ltOther) rememberSplit(splitComma) wrSpace em of openPars: - if tok.strongSpaceA and not em.endsInWhite and + if tok.strongSpaceA > 0 and not em.endsInWhite and (not em.wasExportMarker or tok.tokType == tkCurlyDotLe): wrSpace em - wr(em, $tok.tokType, ltSomeParLe) - if tok.tokType != tkCurlyDotLe: - rememberSplit(splitParLe) + wr(em, TokTypeToStr[tok.tokType], ltSomeParLe) + rememberSplit(splitParLe) of closedPars: - wr(em, $tok.tokType, ltSomeParRi) + wr(em, TokTypeToStr[tok.tokType], ltSomeParRi) of tkColonColon: - wr(em, $tok.tokType, ltOther) + wr(em, TokTypeToStr[tok.tokType], ltOther) of tkDot: lastTokWasTerse = true - wr(em, $tok.tokType, ltOther) + wr(em, TokTypeToStr[tok.tokType], ltOther) of tkEquals: if not em.inquote and not em.endsInWhite: wrSpace(em) - wr(em, $tok.tokType, ltOther) + wr(em, TokTypeToStr[tok.tokType], ltOther) if not em.inquote: wrSpace(em) of tkOpr, tkDotDot: - if em.inquote or (((not tok.strongSpaceA) and tok.strongSpaceB == tsNone) and + if em.inquote or ((tok.strongSpaceA == 0 and tok.strongSpaceB == 0) and tok.ident.s notin ["<", ">", "<=", ">=", "==", "!="]): # bug #9504: remember to not spacify a keyword: lastTokWasTerse = true @@ -538,28 +534,24 @@ 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.strongSpaceB == tsNone and tok.strongSpaceA + tok.strongSpaceB == 0 and tok.strongSpaceA > 0 if not isUnary(tok): rememberSplit(splitBinary) wrSpace(em) of tkAccent: if not em.inquote and endsInAlpha(em): wrSpace(em) - wr(em, $tok.tokType, ltOther) + wr(em, TokTypeToStr[tok.tokType], ltOther) em.inquote = not em.inquote of tkComment: if not preventComment: emitComment(em, tok, dontIndent = false) of tkIntLit..tkStrLit, tkRStrLit, tkTripleStrLit, tkGStrLit, tkGTripleStrLit, tkCharLit: - if not em.inquote: - let lit = fileSection(em.config, em.fid, tok.offsetA, tok.offsetB) - if endsInAlpha(em) and tok.tokType notin {tkGStrLit, tkGTripleStrLit}: wrSpace(em) - em.lineSpan = countNewlines(lit) - if em.lineSpan > 0: calcCol(em, lit) - wr em, lit, ltLit - else: - if endsInAlpha(em): wrSpace(em) - wr em, tok.literal, ltLit + let lit = fileSection(em.config, em.fid, tok.offsetA, tok.offsetB) + if endsInAlpha(em) and tok.tokType notin {tkGStrLit, tkGTripleStrLit}: wrSpace(em) + em.lineSpan = countNewlines(lit) + if em.lineSpan > 0: calcCol(em, lit) + wr em, lit, ltLit of tkEof: discard else: let lit = if tok.ident != nil: tok.ident.s else: tok.literal diff --git a/compiler/lexer.nim b/compiler/lexer.nim index a62d40e54..9420d7a48 100644 --- a/compiler/lexer.nim +++ b/compiler/lexer.nim @@ -7,21 +7,18 @@ # distribution, for details about the copyright. # -# This lexer is handwritten for efficiency. I used an elegant buffering +# This scanner is handwritten for efficiency. I used an elegant buffering # scheme which I have not seen anywhere else: # We guarantee that a whole line is in the buffer. Thus only when scanning -# the \n or \r character we have to check whether we need to read in the next +# the \n or \r character we have to check wether we need to read in the next # chunk. (\n or \r already need special handling for incrementing the line -# counter; choosing both \n and \r allows the lexer to properly read Unix, +# counter; choosing both \n and \r allows the scanner to properly read Unix, # DOS or Macintosh text files, even when it is not the native format. import hashes, options, msgs, strutils, platform, idents, nimlexbase, llstream, wordrecg, lineinfos, pathutils, parseutils -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'} @@ -29,55 +26,45 @@ const SymStartChars*: set[char] = {'a'..'z', 'A'..'Z', '\x80'..'\xFF'} OpChars*: set[char] = {'+', '-', '*', '/', '\\', '<', '>', '!', '?', '^', '.', '|', '=', '%', '&', '$', '@', '~', ':'} - UnaryMinusWhitelist = {' ', '\t', '\n', '\r', ',', ';', '(', '[', '{'} # don't forget to update the 'highlite' module if these charsets should change type - TokType* = enum - tkInvalid = "tkInvalid", tkEof = "[EOF]", # order is important here! - tkSymbol = "tkSymbol", # keywords: - tkAddr = "addr", tkAnd = "and", tkAs = "as", tkAsm = "asm", - tkBind = "bind", tkBlock = "block", tkBreak = "break", tkCase = "case", tkCast = "cast", - tkConcept = "concept", tkConst = "const", tkContinue = "continue", tkConverter = "converter", - tkDefer = "defer", tkDiscard = "discard", tkDistinct = "distinct", tkDiv = "div", tkDo = "do", - tkElif = "elif", tkElse = "else", tkEnd = "end", tkEnum = "enum", tkExcept = "except", tkExport = "export", - tkFinally = "finally", tkFor = "for", tkFrom = "from", tkFunc = "func", - tkIf = "if", tkImport = "import", tkIn = "in", tkInclude = "include", tkInterface = "interface", - tkIs = "is", tkIsnot = "isnot", tkIterator = "iterator", - tkLet = "let", - tkMacro = "macro", tkMethod = "method", tkMixin = "mixin", tkMod = "mod", tkNil = "nil", tkNot = "not", tkNotin = "notin", - tkObject = "object", tkOf = "of", tkOr = "or", tkOut = "out", - tkProc = "proc", tkPtr = "ptr", tkRaise = "raise", tkRef = "ref", tkReturn = "return", - tkShl = "shl", tkShr = "shr", tkStatic = "static", - tkTemplate = "template", - tkTry = "try", tkTuple = "tuple", tkType = "type", tkUsing = "using", - tkVar = "var", tkWhen = "when", tkWhile = "while", tkXor = "xor", - tkYield = "yield", # end of keywords + TTokType* = enum + tkInvalid, tkEof, # order is important here! + tkSymbol, # keywords: + tkAddr, tkAnd, tkAs, tkAsm, + tkBind, tkBlock, tkBreak, tkCase, tkCast, + tkConcept, tkConst, tkContinue, tkConverter, + tkDefer, tkDiscard, tkDistinct, tkDiv, tkDo, + tkElif, tkElse, tkEnd, tkEnum, tkExcept, tkExport, + tkFinally, tkFor, tkFrom, tkFunc, + tkIf, tkImport, tkIn, tkInclude, tkInterface, + tkIs, tkIsnot, tkIterator, + tkLet, + tkMacro, tkMethod, tkMixin, tkMod, tkNil, tkNot, tkNotin, + tkObject, tkOf, tkOr, tkOut, + tkProc, tkPtr, tkRaise, tkRef, tkReturn, + tkShl, tkShr, tkStatic, + tkTemplate, + tkTry, tkTuple, tkType, tkUsing, + tkVar, tkWhen, tkWhile, tkXor, + tkYield, # end of keywords + tkIntLit, tkInt8Lit, tkInt16Lit, tkInt32Lit, tkInt64Lit, + tkUIntLit, tkUInt8Lit, tkUInt16Lit, tkUInt32Lit, tkUInt64Lit, + tkFloatLit, tkFloat32Lit, tkFloat64Lit, tkFloat128Lit, + tkStrLit, tkRStrLit, tkTripleStrLit, + tkGStrLit, tkGTripleStrLit, tkCharLit, tkParLe, tkParRi, tkBracketLe, + tkBracketRi, tkCurlyLe, tkCurlyRi, + tkBracketDotLe, tkBracketDotRi, # [. and .] + tkCurlyDotLe, tkCurlyDotRi, # {. and .} + tkParDotLe, tkParDotRi, # (. and .) + tkComma, tkSemiColon, + tkColon, tkColonColon, tkEquals, tkDot, tkDotDot, tkBracketLeColon, + tkOpr, tkComment, tkAccent, + tkSpaces, tkInfixOpr, tkPrefixOpr, tkPostfixOpr - tkIntLit = "tkIntLit", tkInt8Lit = "tkInt8Lit", tkInt16Lit = "tkInt16Lit", - tkInt32Lit = "tkInt32Lit", tkInt64Lit = "tkInt64Lit", - tkUIntLit = "tkUIntLit", tkUInt8Lit = "tkUInt8Lit", tkUInt16Lit = "tkUInt16Lit", - tkUInt32Lit = "tkUInt32Lit", tkUInt64Lit = "tkUInt64Lit", - tkFloatLit = "tkFloatLit", tkFloat32Lit = "tkFloat32Lit", - tkFloat64Lit = "tkFloat64Lit", tkFloat128Lit = "tkFloat128Lit", - tkStrLit = "tkStrLit", tkRStrLit = "tkRStrLit", tkTripleStrLit = "tkTripleStrLit", - tkGStrLit = "tkGStrLit", tkGTripleStrLit = "tkGTripleStrLit", tkCharLit = "tkCharLit", - tkCustomLit = "tkCustomLit", - - tkParLe = "(", tkParRi = ")", tkBracketLe = "[", - tkBracketRi = "]", tkCurlyLe = "{", tkCurlyRi = "}", - tkBracketDotLe = "[.", tkBracketDotRi = ".]", - tkCurlyDotLe = "{.", tkCurlyDotRi = ".}", - tkParDotLe = "(.", tkParDotRi = ".)", - tkComma = ",", tkSemiColon = ";", - tkColon = ":", tkColonColon = "::", tkEquals = "=", - tkDot = ".", tkDotDot = "..", tkBracketLeColon = "[:", - tkOpr, tkComment, tkAccent = "`", - # these are fake tokens used by renderer.nim - tkSpaces, tkInfixOpr, tkPrefixOpr, tkPostfixOpr, tkHideableStart, tkHideableEnd - - TokTypes* = set[TokType] + TTokTypes* = set[TTokType] const weakTokens = {tkComma, tkSemiColon, tkColon, @@ -86,52 +73,80 @@ const # tokens that should not be considered for previousToken tokKeywordLow* = succ(tkSymbol) tokKeywordHigh* = pred(tkIntLit) + TokTypeToStr*: array[TTokType, string] = ["tkInvalid", "[EOF]", + "tkSymbol", + "addr", "and", "as", "asm", + "bind", "block", "break", "case", "cast", + "concept", "const", "continue", "converter", + "defer", "discard", "distinct", "div", "do", + "elif", "else", "end", "enum", "except", "export", + "finally", "for", "from", "func", "if", + "import", "in", "include", "interface", "is", "isnot", "iterator", + "let", + "macro", "method", "mixin", "mod", + "nil", "not", "notin", "object", "of", "or", + "out", "proc", "ptr", "raise", "ref", "return", + "shl", "shr", "static", + "template", + "try", "tuple", "type", "using", + "var", "when", "while", "xor", + "yield", + "tkIntLit", "tkInt8Lit", "tkInt16Lit", "tkInt32Lit", "tkInt64Lit", + "tkUIntLit", "tkUInt8Lit", "tkUInt16Lit", "tkUInt32Lit", "tkUInt64Lit", + "tkFloatLit", "tkFloat32Lit", "tkFloat64Lit", "tkFloat128Lit", + "tkStrLit", "tkRStrLit", + "tkTripleStrLit", "tkGStrLit", "tkGTripleStrLit", "tkCharLit", "(", + ")", "[", "]", "{", "}", "[.", ".]", "{.", ".}", "(.", ".)", + ",", ";", + ":", "::", "=", ".", "..", "[:", + "tkOpr", "tkComment", "`", + "tkSpaces", "tkInfixOpr", + "tkPrefixOpr", "tkPostfixOpr"] type - NumericalBase* = enum + TNumericalBase* = enum base10, # base10 is listed as the first element, # so that it is the correct default value base2, base8, base16 - TokenSpacing* = enum - tsNone, tsTrailing, tsEof + CursorPosition* {.pure.} = enum ## XXX remove this again + None, InToken, BeforeToken, AfterToken - Token* = object # a Nim token - tokType*: TokType # the type of the 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 + TToken* = object # a Nim token + tokType*: TTokType # the type of the 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*: TNumericalBase # the numerical base; only valid for int + # or float literals + strongSpaceA*: int8 # leading spaces of an operator + strongSpaceB*: int8 # trailing spaces of an operator + literal*: string # the parsed (string) literal; and + # documentation comments are here too line*, col*: int when defined(nimpretty): - offsetA*, offsetB*: int # used for pretty printing so that literals - # like 0b01 or r"\L" are unaffected + offsetA*, offsetB*: int # used for pretty printing so that literals + # like 0b01 or r"\L" are unaffected commentOffsetA*, commentOffsetB*: int - ErrorHandler* = proc (conf: ConfigRef; info: TLineInfo; msg: TMsgKind; arg: string) - Lexer* = object of TBaseLexer + TErrorHandler* = proc (conf: ConfigRef; info: TLineInfo; msg: TMsgKind; arg: string) + TLexer* = object of TBaseLexer fileIdx*: FileIndex indentAhead*: int # if > 0 an indentation has already been read # this is needed because scanning comments # needs so much look-ahead currLineIndent*: int strongSpaces*, allowTabs*: bool - errorHandler*: ErrorHandler + cursor*: CursorPosition + errorHandler*: TErrorHandler cache*: IdentCache when defined(nimsuggest): previousToken: TLineInfo - tokenEnd*: TLineInfo - previousTokenEnd*: TLineInfo config*: ConfigRef -proc getLineInfo*(L: Lexer, tok: Token): TLineInfo {.inline.} = +proc getLineInfo*(L: TLexer, tok: TToken): TLineInfo {.inline.} = result = newLineInfo(L.fileIdx, tok.line, tok.col) when defined(nimpretty): result.offsetA = tok.offsetA @@ -139,8 +154,8 @@ proc getLineInfo*(L: Lexer, tok: Token): TLineInfo {.inline.} = result.commentOffsetA = tok.commentOffsetA result.commentOffsetB = tok.commentOffsetB -proc isKeyword*(kind: TokType): bool = - (kind >= tokKeywordLow) and (kind <= tokKeywordHigh) +proc isKeyword*(kind: TTokType): bool = + result = (kind >= tokKeywordLow) and (kind <= tokKeywordHigh) template ones(n): untyped = ((1 shl n)-1) # for utf-8 conversion @@ -154,31 +169,32 @@ proc isNimIdentifier*(s: string): bool = inc(i) result = true -proc `$`*(tok: Token): string = +proc `$`*(tok: TToken): string = case tok.tokType - of tkIntLit..tkInt64Lit: $tok.iNumber - of tkFloatLit..tkFloat64Lit: $tok.fNumber - of tkInvalid, tkStrLit..tkCharLit, tkComment: tok.literal - of tkParLe..tkColon, tkEof, tkAccent: $tok.tokType + of tkIntLit..tkInt64Lit: result = $tok.iNumber + of tkFloatLit..tkFloat64Lit: result = $tok.fNumber + of tkInvalid, tkStrLit..tkCharLit, tkComment: result = tok.literal + of tkParLe..tkColon, tkEof, tkAccent: + result = TokTypeToStr[tok.tokType] else: if tok.ident != nil: - tok.ident.s + result = tok.ident.s else: - "" + result = "" -proc prettyTok*(tok: Token): string = - if isKeyword(tok.tokType): "keyword " & tok.ident.s - else: $tok +proc prettyTok*(tok: TToken): string = + if isKeyword(tok.tokType): result = "keyword " & tok.ident.s + else: result = $tok -proc printTok*(conf: ConfigRef; tok: Token) = - # xxx factor with toLocation - msgWriteln(conf, $tok.line & ":" & $tok.col & "\t" & $tok.tokType & " " & $tok) +proc printTok*(conf: ConfigRef; tok: TToken) = + msgWriteln(conf, $tok.line & ":" & $tok.col & "\t" & + TokTypeToStr[tok.tokType] & " " & $tok) -proc initToken*(L: var Token) = +proc initToken*(L: var TToken) = L.tokType = tkInvalid L.iNumber = 0 L.indent = 0 - L.strongSpaceA = false + L.strongSpaceA = 0 L.literal = "" L.fNumber = 0.0 L.base = base10 @@ -187,11 +203,11 @@ proc initToken*(L: var Token) = L.commentOffsetA = 0 L.commentOffsetB = 0 -proc fillToken(L: var Token) = +proc fillToken(L: var TToken) = L.tokType = tkInvalid L.iNumber = 0 L.indent = 0 - L.strongSpaceA = false + L.strongSpaceA = 0 setLen(L.literal, 0) L.fNumber = 0.0 L.base = base10 @@ -200,7 +216,7 @@ proc fillToken(L: var Token) = L.commentOffsetA = 0 L.commentOffsetB = 0 -proc openLexer*(lex: var Lexer, fileIdx: FileIndex, inputstream: PLLStream; +proc openLexer*(lex: var TLexer, fileIdx: FileIndex, inputstream: PLLStream; cache: IdentCache; config: ConfigRef) = openBaseLexer(lex, inputstream) lex.fileIdx = fileIdx @@ -212,36 +228,36 @@ proc openLexer*(lex: var Lexer, fileIdx: FileIndex, inputstream: PLLStream; lex.previousToken.fileIndex = fileIdx lex.config = config -proc openLexer*(lex: var Lexer, filename: AbsoluteFile, inputstream: PLLStream; +proc openLexer*(lex: var TLexer, filename: AbsoluteFile, inputstream: PLLStream; cache: IdentCache; config: ConfigRef) = openLexer(lex, fileInfoIdx(config, filename), inputstream, cache, config) -proc closeLexer*(lex: var Lexer) = +proc closeLexer*(lex: var TLexer) = if lex.config != nil: inc(lex.config.linesCompiled, lex.lineNumber) closeBaseLexer(lex) -proc getLineInfo(L: Lexer): TLineInfo = +proc getLineInfo(L: TLexer): TLineInfo = result = newLineInfo(L.fileIdx, L.lineNumber, getColNumber(L, L.bufpos)) -proc dispMessage(L: Lexer; info: TLineInfo; msg: TMsgKind; arg: string) = +proc dispMessage(L: TLexer; info: TLineInfo; msg: TMsgKind; arg: string) = if L.errorHandler.isNil: msgs.message(L.config, info, msg, arg) else: L.errorHandler(L.config, info, msg, arg) -proc lexMessage*(L: Lexer, msg: TMsgKind, arg = "") = +proc lexMessage*(L: TLexer, msg: TMsgKind, arg = "") = L.dispMessage(getLineInfo(L), msg, arg) -proc lexMessageTok*(L: Lexer, msg: TMsgKind, tok: Token, arg = "") = +proc lexMessageTok*(L: TLexer, msg: TMsgKind, tok: TToken, arg = "") = var info = newLineInfo(L.fileIdx, tok.line, tok.col) L.dispMessage(info, msg, arg) -proc lexMessagePos(L: var Lexer, msg: TMsgKind, pos: int, arg = "") = +proc lexMessagePos(L: var TLexer, msg: TMsgKind, pos: int, arg = "") = var info = newLineInfo(L.fileIdx, L.lineNumber, pos - L.lineStart) L.dispMessage(info, msg, arg) -proc matchTwoChars(L: Lexer, first: char, second: set[char]): bool = +proc matchTwoChars(L: TLexer, first: char, second: set[char]): bool = result = (L.buf[L.bufpos] == first) and (L.buf[L.bufpos + 1] in second) template tokenBegin(tok, pos) {.dirty.} = @@ -255,6 +271,7 @@ template tokenEnd(tok, pos) {.dirty.} = let colB = getColNumber(L, pos)+1 if L.fileIdx == L.config.m.trackPos.fileIndex and L.config.m.trackPos.col in colA..colB and L.lineNumber == L.config.m.trackPos.line.int and L.config.ideCmd in {ideSug, ideCon}: + L.cursor = CursorPosition.InToken L.config.m.trackPos.col = colA.int16 colA = 0 when defined(nimpretty): @@ -279,22 +296,23 @@ template tokenEndPrevious(tok, pos) = let colB = getColNumber(L, pos) if L.fileIdx == L.config.m.trackPos.fileIndex and L.config.m.trackPos.col in colA..colB and L.lineNumber == L.config.m.trackPos.line.int and L.config.ideCmd in {ideSug, ideCon}: + L.cursor = CursorPosition.BeforeToken L.config.m.trackPos = L.previousToken L.config.m.trackPosAttached = true colA = 0 when defined(nimpretty): tok.offsetB = L.offsetBase + pos -template eatChar(L: var Lexer, t: var Token, replacementChar: char) = +template eatChar(L: var TLexer, t: var TToken, replacementChar: char) = t.literal.add(replacementChar) inc(L.bufpos) -template eatChar(L: var Lexer, t: var Token) = +template eatChar(L: var TLexer, t: var TToken) = t.literal.add(L.buf[L.bufpos]) inc(L.bufpos) -proc getNumber(L: var Lexer, result: var Token) = - proc matchUnderscoreChars(L: var Lexer, tok: var Token, chars: set[char]): Natural = +proc getNumber(L: var TLexer, result: var TToken) = + proc matchUnderscoreChars(L: var TLexer, tok: var TToken, chars: set[char]): Natural = var pos = L.bufpos # use registers for pos, buf result = 0 while true: @@ -314,18 +332,19 @@ proc getNumber(L: var Lexer, result: var Token) = inc(pos) L.bufpos = pos - proc matchChars(L: var Lexer, tok: var Token, chars: set[char]) = + proc matchChars(L: var TLexer, tok: var TToken, chars: set[char]) = var pos = L.bufpos # use registers for pos, buf while L.buf[pos] in chars: tok.literal.add(L.buf[pos]) inc(pos) L.bufpos = pos - proc lexMessageLitNum(L: var Lexer, msg: string, startpos: int, msgKind = errGenerated) = + proc lexMessageLitNum(L: var TLexer, msg: string, startpos: int, msgKind = errGenerated) = # Used to get slightly human friendlier err messages. - const literalishChars = {'A'..'Z', 'a'..'z', '0'..'9', '_', '.', '\''} + const literalishChars = {'A'..'F', 'a'..'f', '0'..'9', 'X', 'x', 'o', 'O', + 'c', 'C', 'b', 'B', '_', '.', '\'', 'd', 'i', 'u'} var msgPos = L.bufpos - var t: Token + var t: TToken t.literal = "" L.bufpos = startpos # Use L.bufpos as pos because of matchChars matchChars(L, t, literalishChars) @@ -335,14 +354,15 @@ proc getNumber(L: var Lexer, result: var Token) = t.literal.add(L.buf[L.bufpos]) inc(L.bufpos) matchChars(L, t, literalishChars) - if L.buf[L.bufpos] in literalishChars: - t.literal.add(L.buf[L.bufpos]) + if L.buf[L.bufpos] in {'\'', 'f', 'F', 'd', 'D', 'i', 'I', 'u', 'U'}: inc(L.bufpos) + t.literal.add(L.buf[L.bufpos]) matchChars(L, t, {'0'..'9'}) L.bufpos = msgPos lexMessage(L, msgKind, msg % t.literal) var + startpos, endpos: int xi: BiggestInt isBase10 = true numDigits = 0 @@ -354,17 +374,8 @@ proc getNumber(L: var Lexer, result: var Token) = result.tokType = tkIntLit # int literal until we know better result.literal = "" result.base = base10 - tokenBegin(result, L.bufpos) - - var isPositive = true - if L.buf[L.bufpos] == '-': - eatChar(L, result) - isPositive = false - - let startpos = L.bufpos - - template setNumber(field, value) = - field = (if isPositive: value else: -value) + startpos = L.bufpos + tokenBegin(result, startpos) # First stage: find out base, make verifications, build token literal string # {'c', 'C'} is added for deprecation reasons to provide a clear error message @@ -404,188 +415,204 @@ proc getNumber(L: var Lexer, result: var Token) = discard matchUnderscoreChars(L, result, {'0'..'9'}) if L.buf[L.bufpos] in {'e', 'E'}: result.tokType = tkFloatLit - eatChar(L, result) + eatChar(L, result, 'e') if L.buf[L.bufpos] in {'+', '-'}: eatChar(L, result) discard matchUnderscoreChars(L, result, {'0'..'9'}) - let endpos = L.bufpos + endpos = L.bufpos # Second stage, find out if there's a datatype suffix and handle it var postPos = endpos - if L.buf[postPos] in {'\'', 'f', 'F', 'd', 'D', 'i', 'I', 'u', 'U'}: - let errPos = postPos - var customLitPossible = false if L.buf[postPos] == '\'': inc(postPos) - customLitPossible = true - if L.buf[postPos] in SymChars: - var suffix = newStringOfCap(10) - while true: - suffix.add L.buf[postPos] - inc postPos - if L.buf[postPos] notin SymChars+{'_'}: break - let suffixAsLower = suffix.toLowerAscii - case suffixAsLower - of "f", "f32": result.tokType = tkFloat32Lit - of "d", "f64": result.tokType = tkFloat64Lit - of "f128": result.tokType = tkFloat128Lit - of "i8": result.tokType = tkInt8Lit - of "i16": result.tokType = tkInt16Lit - of "i32": result.tokType = tkInt32Lit - of "i64": result.tokType = tkInt64Lit - of "u": result.tokType = tkUIntLit - of "u8": result.tokType = tkUInt8Lit - of "u16": result.tokType = tkUInt16Lit - of "u32": result.tokType = tkUInt32Lit - of "u64": result.tokType = tkUInt64Lit - elif customLitPossible: - # remember the position of the `'` so that the parser doesn't - # have to reparse the custom literal: - result.iNumber = len(result.literal) - result.literal.add '\'' - result.literal.add suffix - result.tokType = tkCustomLit + case L.buf[postPos] + of 'f', 'F': + inc(postPos) + if (L.buf[postPos] == '3') and (L.buf[postPos + 1] == '2'): + result.tokType = tkFloat32Lit + inc(postPos, 2) + elif (L.buf[postPos] == '6') and (L.buf[postPos + 1] == '4'): + result.tokType = tkFloat64Lit + inc(postPos, 2) + elif (L.buf[postPos] == '1') and + (L.buf[postPos + 1] == '2') and + (L.buf[postPos + 2] == '8'): + result.tokType = tkFloat128Lit + inc(postPos, 3) + else: # "f" alone defaults to float32 + result.tokType = tkFloat32Lit + of 'd', 'D': # ad hoc convenience shortcut for f64 + inc(postPos) + result.tokType = tkFloat64Lit + of 'i', 'I': + inc(postPos) + if (L.buf[postPos] == '6') and (L.buf[postPos + 1] == '4'): + result.tokType = tkInt64Lit + inc(postPos, 2) + elif (L.buf[postPos] == '3') and (L.buf[postPos + 1] == '2'): + result.tokType = tkInt32Lit + inc(postPos, 2) + elif (L.buf[postPos] == '1') and (L.buf[postPos + 1] == '6'): + result.tokType = tkInt16Lit + inc(postPos, 2) + elif (L.buf[postPos] == '8'): + result.tokType = tkInt8Lit + inc(postPos) else: - lexMessageLitNum(L, "invalid number suffix: '$1'", errPos) + lexMessageLitNum(L, "invalid number: '$1'", startpos) + of 'u', 'U': + inc(postPos) + if (L.buf[postPos] == '6') and (L.buf[postPos + 1] == '4'): + result.tokType = tkUInt64Lit + inc(postPos, 2) + elif (L.buf[postPos] == '3') and (L.buf[postPos + 1] == '2'): + result.tokType = tkUInt32Lit + inc(postPos, 2) + elif (L.buf[postPos] == '1') and (L.buf[postPos + 1] == '6'): + result.tokType = tkUInt16Lit + inc(postPos, 2) + elif (L.buf[postPos] == '8'): + result.tokType = tkUInt8Lit + inc(postPos) + else: + result.tokType = tkUIntLit else: - lexMessageLitNum(L, "invalid number suffix: '$1'", errPos) + lexMessageLitNum(L, "invalid number: '$1'", startpos) # Is there still a literalish char awaiting? Then it's an error! if L.buf[postPos] in literalishChars or (L.buf[postPos] == '.' and L.buf[postPos + 1] in {'0'..'9'}): lexMessageLitNum(L, "invalid number: '$1'", startpos) - if result.tokType != tkCustomLit: - # Third stage, extract actual number - L.bufpos = startpos # restore position - var pos = startpos - try: - if (L.buf[pos] == '0') and (L.buf[pos + 1] in baseCodeChars): - inc(pos, 2) - xi = 0 # it is a base prefix + # Third stage, extract actual number + L.bufpos = startpos # restore position + var pos: int = startpos + try: + if (L.buf[pos] == '0') and (L.buf[pos + 1] in baseCodeChars): + inc(pos, 2) + xi = 0 # it is a base prefix - case L.buf[pos - 1] - of 'b', 'B': - result.base = base2 - while pos < endpos: - if L.buf[pos] != '_': - xi = `shl`(xi, 1) or (ord(L.buf[pos]) - ord('0')) + case L.buf[pos - 1] + of 'b', 'B': + result.base = base2 + while pos < endpos: + if L.buf[pos] != '_': + xi = `shl`(xi, 1) or (ord(L.buf[pos]) - ord('0')) + inc(pos) + # 'c', 'C' is deprecated + of 'o', 'c', 'C': + result.base = base8 + while pos < endpos: + if L.buf[pos] != '_': + xi = `shl`(xi, 3) or (ord(L.buf[pos]) - ord('0')) + inc(pos) + of 'x', 'X': + result.base = base16 + while pos < endpos: + case L.buf[pos] + of '_': inc(pos) - # 'c', 'C' is deprecated (a warning is issued elsewhere) - of 'o', 'c', 'C': - result.base = base8 - while pos < endpos: - if L.buf[pos] != '_': - xi = `shl`(xi, 3) or (ord(L.buf[pos]) - ord('0')) + of '0'..'9': + xi = `shl`(xi, 4) or (ord(L.buf[pos]) - ord('0')) inc(pos) - of 'x', 'X': - result.base = base16 - while pos < endpos: - case L.buf[pos] - of '_': - inc(pos) - of '0'..'9': - xi = `shl`(xi, 4) or (ord(L.buf[pos]) - ord('0')) - inc(pos) - of 'a'..'f': - xi = `shl`(xi, 4) or (ord(L.buf[pos]) - ord('a') + 10) - inc(pos) - of 'A'..'F': - xi = `shl`(xi, 4) or (ord(L.buf[pos]) - ord('A') + 10) - inc(pos) - else: - break - else: - internalError(L.config, getLineInfo(L), "getNumber") - - case result.tokType - of tkIntLit, tkInt64Lit: setNumber result.iNumber, xi - of tkInt8Lit: setNumber result.iNumber, ashr(xi shl 56, 56) - of tkInt16Lit: setNumber result.iNumber, ashr(xi shl 48, 48) - of tkInt32Lit: setNumber result.iNumber, ashr(xi shl 32, 32) - of tkUIntLit, tkUInt64Lit: setNumber result.iNumber, xi - of tkUInt8Lit: setNumber result.iNumber, xi and 0xff - of tkUInt16Lit: setNumber result.iNumber, xi and 0xffff - of tkUInt32Lit: setNumber result.iNumber, xi and 0xffffffff - of tkFloat32Lit: - setNumber result.fNumber, (cast[ptr float32](addr(xi)))[] - # note: this code is endian neutral! - # XXX: Test this on big endian machine! - of tkFloat64Lit, tkFloatLit: - setNumber result.fNumber, (cast[ptr float64](addr(xi)))[] - else: internalError(L.config, getLineInfo(L), "getNumber") - - # Bounds checks. Non decimal literals are allowed to overflow the range of - # the datatype as long as their pattern don't overflow _bitwise_, hence - # below checks of signed sizes against uint*.high is deliberate: - # (0x80'u8 = 128, 0x80'i8 = -128, etc == OK) - if result.tokType notin floatTypes: - let outOfRange = - case result.tokType - of tkUInt8Lit, tkUInt16Lit, tkUInt32Lit: result.iNumber != xi - of tkInt8Lit: (xi > BiggestInt(uint8.high)) - of tkInt16Lit: (xi > BiggestInt(uint16.high)) - of tkInt32Lit: (xi > BiggestInt(uint32.high)) - else: false - - if outOfRange: - #echo "out of range num: ", result.iNumber, " vs ", xi - lexMessageLitNum(L, "number out of range: '$1'", startpos) - + of 'a'..'f': + xi = `shl`(xi, 4) or (ord(L.buf[pos]) - ord('a') + 10) + inc(pos) + of 'A'..'F': + xi = `shl`(xi, 4) or (ord(L.buf[pos]) - ord('A') + 10) + inc(pos) + else: + break else: - case result.tokType - of floatTypes: - result.fNumber = parseFloat(result.literal) - of tkUInt64Lit, tkUIntLit: - var iNumber: uint64 - var len: int - try: - len = parseBiggestUInt(result.literal, iNumber) - except ValueError: - raise newException(OverflowDefect, "number out of range: " & result.literal) - if len != result.literal.len: - raise newException(ValueError, "invalid integer: " & result.literal) - result.iNumber = cast[int64](iNumber) - else: - var iNumber: int64 - var len: int - try: - len = parseBiggestInt(result.literal, iNumber) - except ValueError: - raise newException(OverflowDefect, "number out of range: " & result.literal) - if len != result.literal.len: - raise newException(ValueError, "invalid integer: " & result.literal) - result.iNumber = iNumber + internalError(L.config, getLineInfo(L), "getNumber") - # Explicit bounds checks. - let outOfRange = - case result.tokType - of tkInt8Lit: result.iNumber > int8.high or result.iNumber < int8.low - of tkUInt8Lit: result.iNumber > BiggestInt(uint8.high) or result.iNumber < 0 - of tkInt16Lit: result.iNumber > int16.high or result.iNumber < int16.low - of tkUInt16Lit: result.iNumber > BiggestInt(uint16.high) or result.iNumber < 0 - of tkInt32Lit: result.iNumber > int32.high or result.iNumber < int32.low - of tkUInt32Lit: result.iNumber > BiggestInt(uint32.high) or result.iNumber < 0 - else: false + case result.tokType + of tkIntLit, tkInt64Lit: result.iNumber = xi + of tkInt8Lit: result.iNumber = ashr(xi shl 56, 56) + of tkInt16Lit: result.iNumber = ashr(xi shl 48, 48) + of tkInt32Lit: result.iNumber = ashr(xi shl 32, 32) + of tkUIntLit, tkUInt64Lit: result.iNumber = xi + of tkUInt8Lit: result.iNumber = xi and 0xff + of tkUInt16Lit: result.iNumber = xi and 0xffff + of tkUInt32Lit: result.iNumber = xi and 0xffffffff + of tkFloat32Lit: + result.fNumber = (cast[PFloat32](addr(xi)))[] + # note: this code is endian neutral! + # XXX: Test this on big endian machine! + of tkFloat64Lit, tkFloatLit: + result.fNumber = (cast[PFloat64](addr(xi)))[] + else: internalError(L.config, getLineInfo(L), "getNumber") + + # Bounds checks. Non decimal literals are allowed to overflow the range of + # the datatype as long as their pattern don't overflow _bitwise_, hence + # below checks of signed sizes against uint*.high is deliberate: + # (0x80'u8 = 128, 0x80'i8 = -128, etc == OK) + if result.tokType notin floatTypes: + let outOfRange = case result.tokType: + of tkUInt8Lit, tkUInt16Lit, tkUInt32Lit: result.iNumber != xi + of tkInt8Lit: (xi > BiggestInt(uint8.high)) + of tkInt16Lit: (xi > BiggestInt(uint16.high)) + of tkInt32Lit: (xi > BiggestInt(uint32.high)) + else: false if outOfRange: + #echo "out of range num: ", result.iNumber, " vs ", xi lexMessageLitNum(L, "number out of range: '$1'", startpos) - # Promote int literal to int64? Not always necessary, but more consistent - if result.tokType == tkIntLit: - if result.iNumber > high(int32) or result.iNumber < low(int32): - result.tokType = tkInt64Lit + else: + case result.tokType + of floatTypes: + result.fNumber = parseFloat(result.literal) + of tkUInt64Lit, tkUIntLit: + var iNumber: uint64 + var len: int + try: + len = parseBiggestUInt(result.literal, iNumber) + except ValueError: + raise newException(OverflowError, "number out of range: " & $result.literal) + if len != result.literal.len: + raise newException(ValueError, "invalid integer: " & $result.literal) + result.iNumber = cast[int64](iNumber) + else: + var iNumber: int64 + var len: int + try: + len = parseBiggestInt(result.literal, iNumber) + except ValueError: + raise newException(OverflowError, "number out of range: " & $result.literal) + if len != result.literal.len: + raise newException(ValueError, "invalid integer: " & $result.literal) + result.iNumber = iNumber - except ValueError: - lexMessageLitNum(L, "invalid number: '$1'", startpos) - except OverflowDefect, RangeDefect: - lexMessageLitNum(L, "number out of range: '$1'", startpos) + # Explicit bounds checks. Only T.high needs to be considered + # since result.iNumber can't be negative. + let outOfRange = + case result.tokType + of tkInt8Lit: result.iNumber > int8.high + of tkUInt8Lit: result.iNumber > BiggestInt(uint8.high) + of tkInt16Lit: result.iNumber > int16.high + of tkUInt16Lit: result.iNumber > BiggestInt(uint16.high) + of tkInt32Lit: result.iNumber > int32.high + of tkUInt32Lit: result.iNumber > BiggestInt(uint32.high) + else: false + + if outOfRange: lexMessageLitNum(L, "number out of range: '$1'", startpos) + + # Promote int literal to int64? Not always necessary, but more consistent + if result.tokType == tkIntLit: + if result.iNumber > high(int32): + result.tokType = tkInt64Lit + + except ValueError: + lexMessageLitNum(L, "invalid number: '$1'", startpos) + except OverflowError, RangeError: + lexMessageLitNum(L, "number out of range: '$1'", startpos) tokenEnd(result, postPos-1) L.bufpos = postPos -proc handleHexChar(L: var Lexer, xi: var int; position: range[0..4]) = +proc handleHexChar(L: var TLexer, xi: var int; position: range[0..4]) = template invalid() = lexMessage(L, errGenerated, "expected a hex digit, but found: " & L.buf[L.bufpos] & @@ -610,7 +637,7 @@ proc handleHexChar(L: var Lexer, xi: var int; position: range[0..4]) = # Need to progress for `nim check` inc(L.bufpos) -proc handleDecChars(L: var Lexer, xi: var int) = +proc handleDecChars(L: var TLexer, xi: var int) = while L.buf[L.bufpos] in {'0'..'9'}: xi = (xi * 10) + (ord(L.buf[L.bufpos]) - ord('0')) inc(L.bufpos) @@ -653,11 +680,16 @@ proc addUnicodeCodePoint(s: var string, i: int) = s[pos+4] = chr(i shr 6 and ones(6) or 0b10_0000_00) s[pos+5] = chr(i and ones(6) or 0b10_0000_00) -proc getEscapedChar(L: var Lexer, tok: var Token) = +proc getEscapedChar(L: var TLexer, tok: var TToken) = inc(L.bufpos) # skip '\' case L.buf[L.bufpos] of 'n', 'N': - tok.literal.add('\L') + if L.config.oldNewlines: + if tok.tokType == tkCharLit: + lexMessage(L, errGenerated, "\\n not allowed in character literal") + tok.literal.add(L.config.target.tnl) + else: + tok.literal.add('\L') inc(L.bufpos) of 'p', 'P': if tok.tokType == tkCharLit: @@ -733,13 +765,18 @@ proc getEscapedChar(L: var Lexer, tok: var Token) = else: lexMessage(L, errGenerated, "invalid character constant") else: lexMessage(L, errGenerated, "invalid character constant") -proc handleCRLF(L: var Lexer, pos: int): int = +proc newString(s: cstring, len: int): string = + ## XXX, how come there is no support for this? + result = newString(len) + for i in 0.. MaxLineLength: - lexMessagePos(L, hintLineTooLong, pos) + if col > MaxLineLength: + lexMessagePos(L, hintLineTooLong, pos) case L.buf[pos] of CR: @@ -756,7 +793,7 @@ type raw, generalized -proc getString(L: var Lexer, tok: var Token, mode: StringMode) = +proc getString(L: var TLexer, tok: var TToken, mode: StringMode) = var pos = L.bufpos var line = L.lineNumber # save linenumber for better error message tokenBegin(tok, pos - ord(mode == raw)) @@ -822,9 +859,8 @@ proc getString(L: var Lexer, tok: var Token, mode: StringMode) = inc(pos) L.bufpos = pos -proc getCharacter(L: var Lexer; tok: var Token) = +proc getCharacter(L: var TLexer, tok: var TToken) = tokenBegin(tok, L.bufpos) - let startPos = L.bufpos inc(L.bufpos) # skip ' var c = L.buf[L.bufpos] case c @@ -835,61 +871,12 @@ proc getCharacter(L: var Lexer; tok: var Token) = else: tok.literal = $c inc(L.bufpos) - if L.buf[L.bufpos] == '\'': - tokenEndIgnore(tok, L.bufpos) - inc(L.bufpos) # skip ' - else: - if startPos > 0 and L.buf[startPos-1] == '`': - tok.literal = "'" - L.bufpos = startPos+1 - else: - lexMessage(L, errGenerated, "missing closing ' for character literal") - tokenEndIgnore(tok, L.bufpos) + if L.buf[L.bufpos] != '\'': + lexMessage(L, errGenerated, "missing closing ' for character literal") + tokenEndIgnore(tok, L.bufpos) + inc(L.bufpos) # skip ' -const - UnicodeOperatorStartChars = {'\226', '\194', '\195'} - # the allowed unicode characters ("∙ ∘ × ★ ⊗ ⊘ ⊙ ⊛ ⊠ ⊡ ∩ ∧ ⊓ ± ⊕ ⊖ ⊞ ⊟ ∪ ∨ ⊔") - # all start with one of these. - -type - UnicodeOprPred = enum - Mul, Add - -proc unicodeOprLen(buf: cstring; pos: int): (int8, UnicodeOprPred) = - template m(len): untyped = (int8(len), Mul) - template a(len): untyped = (int8(len), Add) - result = 0.m - case buf[pos] - of '\226': - if buf[pos+1] == '\136': - if buf[pos+2] == '\152': result = 3.m # ∘ - elif buf[pos+2] == '\153': result = 3.m # ∙ - elif buf[pos+2] == '\167': result = 3.m # ∧ - elif buf[pos+2] == '\168': result = 3.a # ∨ - elif buf[pos+2] == '\169': result = 3.m # ∩ - elif buf[pos+2] == '\170': result = 3.a # ∪ - elif buf[pos+1] == '\138': - if buf[pos+2] == '\147': result = 3.m # ⊓ - elif buf[pos+2] == '\148': result = 3.a # ⊔ - elif buf[pos+2] == '\149': result = 3.a # ⊕ - elif buf[pos+2] == '\150': result = 3.a # ⊖ - elif buf[pos+2] == '\151': result = 3.m # ⊗ - elif buf[pos+2] == '\152': result = 3.m # ⊘ - elif buf[pos+2] == '\153': result = 3.m # ⊙ - elif buf[pos+2] == '\155': result = 3.m # ⊛ - elif buf[pos+2] == '\158': result = 3.a # ⊞ - elif buf[pos+2] == '\159': result = 3.a # ⊟ - elif buf[pos+2] == '\160': result = 3.m # ⊠ - elif buf[pos+2] == '\161': result = 3.m # ⊡ - elif buf[pos+1] == '\152' and buf[pos+2] == '\133': result = 3.m # ★ - of '\194': - if buf[pos+1] == '\177': result = 2.a # ± - of '\195': - if buf[pos+1] == '\151': result = 2.m # × - else: - discard - -proc getSymbol(L: var Lexer, tok: var Token) = +proc getSymbol(L: var TLexer, tok: var TToken) = var h: Hash = 0 var pos = L.bufpos tokenBegin(tok, pos) @@ -897,7 +884,7 @@ proc getSymbol(L: var Lexer, tok: var Token) = while true: var c = L.buf[pos] case c - of 'a'..'z', '0'..'9': + of 'a'..'z', '0'..'9', '\x80'..'\xFF': h = h !& ord(c) inc(pos) of 'A'..'Z': @@ -911,106 +898,84 @@ proc getSymbol(L: var Lexer, tok: var Token) = break inc(pos) suspicious = true - of '\x80'..'\xFF': - if c in UnicodeOperatorStartChars and unicodeOprLen(L.buf, pos)[0] != 0: - break - else: - h = h !& ord(c) - inc(pos) else: break tokenEnd(tok, pos-1) h = !$h - tok.ident = L.cache.getIdent(cast[cstring](addr(L.buf[L.bufpos])), pos - L.bufpos, h) + tok.ident = L.cache.getIdent(addr(L.buf[L.bufpos]), pos - L.bufpos, h) if (tok.ident.id < ord(tokKeywordLow) - ord(tkSymbol)) or (tok.ident.id > ord(tokKeywordHigh) - ord(tkSymbol)): tok.tokType = tkSymbol else: - tok.tokType = TokType(tok.ident.id + ord(tkSymbol)) + tok.tokType = TTokType(tok.ident.id + ord(tkSymbol)) if suspicious and {optStyleHint, optStyleError} * L.config.globalOptions != {}: lintReport(L.config, getLineInfo(L), tok.ident.s.normalize, tok.ident.s) L.bufpos = pos -proc endOperator(L: var Lexer, tok: var Token, pos: int, +proc endOperator(L: var TLexer, tok: var TToken, pos: int, hash: Hash) {.inline.} = var h = !$hash - tok.ident = L.cache.getIdent(cast[cstring](addr(L.buf[L.bufpos])), pos - L.bufpos, h) + tok.ident = L.cache.getIdent(addr(L.buf[L.bufpos]), pos - L.bufpos, h) if (tok.ident.id < oprLow) or (tok.ident.id > oprHigh): tok.tokType = tkOpr - else: tok.tokType = TokType(tok.ident.id - oprLow + ord(tkColon)) + else: tok.tokType = TTokType(tok.ident.id - oprLow + ord(tkColon)) L.bufpos = pos -proc getOperator(L: var Lexer, tok: var Token) = +proc getOperator(L: var TLexer, tok: var TToken) = var pos = L.bufpos tokenBegin(tok, pos) var h: Hash = 0 while true: var c = L.buf[pos] - if c in OpChars: - h = h !& ord(c) - inc(pos) - elif c in UnicodeOperatorStartChars: - let oprLen = unicodeOprLen(L.buf, pos)[0] - if oprLen == 0: break - for i in 0.. 1 and tok.ident.s[^1] == '>' and - tok.ident.s[^2] in {'-', '~', '='}: return 0 + tok.ident.s[^2] in {'-', '~', '='}: return considerStrongSpaces(1) template considerAsgn(value: untyped) = result = if tok.ident.s[^1] == '=': 1 else: value case relevantChar of '$', '^': considerAsgn(10) - of '*', '%', '/', '\\': considerAsgn(MulPred) + of '*', '%', '/', '\\': considerAsgn(9) of '~': result = 8 - of '+', '-', '|': considerAsgn(PlusPred) + of '+', '-', '|': considerAsgn(8) of '&': considerAsgn(7) of '=', '<', '>', '!': result = 5 of '.': considerAsgn(6) of '?': result = 2 - of UnicodeOperatorStartChars: - if tok.ident.s[^1] == '=': - result = 1 - else: - let (len, pred) = unicodeOprLen(cstring(tok.ident.s), 0) - if len != 0: - result = if pred == Mul: MulPred else: PlusPred - else: - result = 2 else: considerAsgn(2) of tkDiv, tkMod, tkShl, tkShr: result = 9 + of tkIn, tkNotin, tkIs, tkIsnot, tkOf, tkAs: result = 5 of tkDotDot: result = 6 - of tkIn, tkNotin, tkIs, tkIsnot, tkOf, tkAs, tkFrom: result = 5 of tkAnd: result = 4 of tkOr, tkXor, tkPtr, tkRef: result = 3 else: return -10 + result = considerStrongSpaces(result) -proc newlineFollows*(L: Lexer): bool = + +proc newlineFollows*(L: TLexer): bool = var pos = L.bufpos while true: case L.buf[pos] @@ -1026,7 +991,7 @@ proc newlineFollows*(L: Lexer): bool = else: break -proc skipMultiLineComment(L: var Lexer; tok: var Token; start: int; +proc skipMultiLineComment(L: var TLexer; tok: var TToken; start: int; isDoc: bool) = var pos = start var toStrip = 0 @@ -1034,10 +999,8 @@ proc skipMultiLineComment(L: var Lexer; tok: var Token; start: int; # detect the amount of indentation: if isDoc: toStrip = getColNumber(L, pos) - while L.buf[pos] == ' ': - inc pos - inc toStrip - while L.buf[pos] in {CR, LF}: # skip blank lines + while L.buf[pos] == ' ': inc pos + if L.buf[pos] in {CR, LF}: pos = handleCRLF(L, pos) toStrip = 0 while L.buf[pos] == ' ': @@ -1093,14 +1056,14 @@ proc skipMultiLineComment(L: var Lexer; tok: var Token; start: int; when defined(nimpretty): tok.commentOffsetB = L.offsetBase + pos - 1 -proc scanComment(L: var Lexer, tok: var Token) = +proc scanComment(L: var TLexer, tok: var TToken) = 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 + tok.commentOffsetA = L.offsetBase + pos - 1 if L.buf[pos+2] == '[': skipMultiLineComment(L, tok, pos+3, true) @@ -1109,17 +1072,11 @@ proc scanComment(L: var Lexer, tok: var Token) = inc(pos, 2) var toStrip = 0 - var stripInit = false + while L.buf[pos] == ' ': + inc pos + inc toStrip while true: - if not stripInit: # find baseline indentation inside comment - while L.buf[pos] == ' ': - inc pos - inc toStrip - if L.buf[pos] in {CR, LF}: # don't set toStrip in blank comment lines - toStrip = 0 - else: # found first non-whitespace character - stripInit = true var lastBackslash = -1 while L.buf[pos] notin {CR, LF, nimlexbase.EndOfFile}: if L.buf[pos] == '\\': lastBackslash = pos+1 @@ -1135,12 +1092,11 @@ proc scanComment(L: var Lexer, tok: var Token) = if L.buf[pos] == '#' and L.buf[pos+1] == '#': tok.literal.add "\n" inc(pos, 2) - if stripInit: - var c = toStrip - while L.buf[pos] == ' ' and c > 0: - inc pos - dec c - inc tok.iNumber + var c = toStrip + while L.buf[pos] == ' ' and c > 0: + inc pos + dec c + inc tok.iNumber else: if L.buf[pos] > ' ': L.indentAhead = indent @@ -1150,10 +1106,10 @@ proc scanComment(L: var Lexer, tok: var Token) = when defined(nimpretty): tok.commentOffsetB = L.offsetBase + pos - 1 -proc skip(L: var Lexer, tok: var Token) = +proc skip(L: var TLexer, tok: var TToken) = var pos = L.bufpos tokenBegin(tok, pos) - tok.strongSpaceA = false + tok.strongSpaceA = 0 when defined(nimpretty): var hasComment = false var commentIndent = L.currLineIndent @@ -1164,8 +1120,7 @@ proc skip(L: var Lexer, tok: var Token) = case L.buf[pos] of ' ': inc(pos) - if not tok.strongSpaceA: - tok.strongSpaceA = true + inc(tok.strongSpaceA) of '\t': if not L.allowTabs: lexMessagePos(L, errGenerated, pos, "tabs are not allowed, use spaces instead") inc(pos) @@ -1187,7 +1142,7 @@ proc skip(L: var Lexer, tok: var Token) = pos = L.bufpos else: break - tok.strongSpaceA = false + tok.strongSpaceA = 0 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] == '#'): @@ -1223,18 +1178,16 @@ proc skip(L: var Lexer, tok: var Token) = tok.tokType = tkComment tok.indent = commentIndent -proc rawGetTok*(L: var Lexer, tok: var Token) = +proc rawGetTok*(L: var TLexer, tok: var TToken) = 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 L.previousToken.col = tok.col.int16 + when defined(nimsuggest): + L.cursor = CursorPosition.None fillToken(tok) if L.indentAhead >= 0: tok.indent = L.indentAhead @@ -1250,15 +1203,10 @@ proc rawGetTok*(L: var Lexer, tok: var Token) = var c = L.buf[L.bufpos] tok.line = L.lineNumber tok.col = getColNumber(L, L.bufpos) - if c in SymStartChars - {'r', 'R'} - UnicodeOperatorStartChars: + if c in SymStartChars - {'r', 'R'}: getSymbol(L, tok) else: case c - of UnicodeOperatorStartChars: - if unicodeOprLen(L.buf, L.bufpos)[0] != 0: - getOperator(L, tok) - else: - getSymbol(L, tok) of '#': scanComment(L, tok) of '*': @@ -1310,6 +1258,7 @@ proc rawGetTok*(L: var Lexer, tok: var Token) = if L.fileIdx == L.config.m.trackPos.fileIndex and tok.col+1 == L.config.m.trackPos.col and tok.line == L.config.m.trackPos.line.int and L.config.ideCmd == ideSug: tok.tokType = tkDot + L.cursor = CursorPosition.InToken L.config.m.trackPos.col = tok.col.int16 inc(L.bufpos) atTokenEnd() @@ -1366,28 +1315,7 @@ proc rawGetTok*(L: var Lexer, tok: var Token) = getNumber(L, tok) let c = L.buf[L.bufpos] if c in SymChars+{'_'}: - if c in UnicodeOperatorStartChars and - unicodeOprLen(L.buf, L.bufpos)[0] != 0: - discard - else: - lexMessage(L, errGenerated, "invalid token: no whitespace between number and identifier") - of '-': - if L.buf[L.bufpos+1] in {'0'..'9'} and - (L.bufpos-1 == 0 or L.buf[L.bufpos-1] in UnaryMinusWhitelist): - # x)-23 # binary minus - # ,-23 # unary minus - # \n-78 # unary minus? Yes. - # =-3 # parsed as `=-` anyway - getNumber(L, tok) - let c = L.buf[L.bufpos] - if c in SymChars+{'_'}: - if c in UnicodeOperatorStartChars and - unicodeOprLen(L.buf, L.bufpos)[0] != 0: - discard - else: - lexMessage(L, errGenerated, "invalid token: no whitespace between number and identifier") - else: - getOperator(L, tok) + lexMessage(L, errGenerated, "invalid token: no whitespace between number and identifier") else: if c in OpChars: getOperator(L, tok) @@ -1403,8 +1331,8 @@ proc rawGetTok*(L: var Lexer, tok: var Token) = proc getIndentWidth*(fileIdx: FileIndex, inputstream: PLLStream; cache: IdentCache; config: ConfigRef): int = - var lex: Lexer - var tok: Token + var lex: TLexer + var tok: TToken initToken(tok) openLexer(lex, fileIdx, inputstream, cache, config) var prevToken = tkEof @@ -1418,11 +1346,11 @@ proc getIndentWidth*(fileIdx: FileIndex, inputstream: PLLStream; proc getPrecedence*(ident: PIdent): int = ## assumes ident is binary operator already - var tok: Token + var tok: TToken initToken(tok) tok.ident = ident tok.tokType = if tok.ident.id in ord(tokKeywordLow) - ord(tkSymbol)..ord(tokKeywordHigh) - ord(tkSymbol): - TokType(tok.ident.id + ord(tkSymbol)) + TTokType(tok.ident.id + ord(tkSymbol)) else: tkOpr - getPrecedence(tok) + getPrecedence(tok, false) diff --git a/compiler/liftdestructors.nim b/compiler/liftdestructors.nim index 467f015d8..377ba149a 100644 --- a/compiler/liftdestructors.nim +++ b/compiler/liftdestructors.nim @@ -8,16 +8,16 @@ # ## This module implements lifting for type-bound operations -## (``=sink``, ``=copy``, ``=destroy``, ``=deepCopy``). +## (``=sink``, ``=``, ``=destroy``, ``=deepCopy``). + +# Todo: +# - use openArray instead of array to avoid over-specializations import modulegraphs, lineinfos, idents, ast, renderer, semdata, - sighashes, lowerings, options, types, msgs, magicsys, tables, ccgutils + sighashes, lowerings, options, types, msgs, magicsys, tables from trees import isCaseObj -when defined(nimPreviewSlimSystem): - import std/assertions - type TLiftCtx = object g: ModuleGraph @@ -26,22 +26,13 @@ type fn: PSym asgnForType: PType recurse: bool - addMemReset: bool # add wasMoved() call after destructor call - canRaise: bool - filterDiscriminator: PSym # we generating destructor for case branch c: PContext # c can be nil, then we are called from lambdalifting! - idgen: IdGenerator - -template destructor*(t: PType): PSym = getAttachedOp(c.g, t, attachedDestructor) -template assignment*(t: PType): PSym = getAttachedOp(c.g, t, attachedAsgn) -template asink*(t: PType): PSym = getAttachedOp(c.g, t, attachedSink) proc fillBody(c: var TLiftCtx; t: PType; body, x, y: PNode) proc produceSym(g: ModuleGraph; c: PContext; typ: PType; kind: TTypeAttachedOp; - info: TLineInfo; idgen: IdGenerator): PSym + info: TLineInfo): PSym -proc createTypeBoundOps*(g: ModuleGraph; c: PContext; orig: PType; info: TLineInfo; - idgen: IdGenerator) +proc createTypeBoundOps*(g: ModuleGraph; c: PContext; orig: PType; info: TLineInfo) proc at(a, i: PNode, elemType: PType): PNode = result = newNodeI(nkBracketExpr, a.info, 2) @@ -49,10 +40,6 @@ proc at(a, i: PNode, elemType: PType): PNode = result[1] = i result.typ = elemType -proc destructorOverriden(g: ModuleGraph; t: PType): bool = - let op = getAttachedOp(g, t, attachedDestructor) - op != nil and sfOverriden in op.flags - proc fillBodyTup(c: var TLiftCtx; t: PType; body, x, y: PNode) = for i in 0.. 0 and t[0] != nil: - fillBody(c, skipTypes(t[0], abstractPtrs), body, x, y) + fillBodyObjTImpl(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) = @@ -243,16 +153,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), 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, - # because the wasMoved(dest) call would zero out src, if dest aliases src. - var cond = newTree(nkCall, newSymNode(c.g.getSysMagic(c.info, "==", mEqRef)), - 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), nextSymId c.idgen, c.fn, c.info) + var temp = newSym(skTemp, getIdent(c.g.cache, lowerings.genPrefix), c.fn, c.info) temp.typ = x.typ incl(temp.flags, sfFromGeneric) var v = newNodeI(nkVarSection, c.info) @@ -262,7 +163,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, "wasMoved", mWasMoved))) wasMovedCall.add x # mWasMoved does not take the address body.add wasMovedCall @@ -278,57 +179,29 @@ proc fillBodyObjT(c: var TLiftCtx; t: PType, body, x, y: PNode) = else: fillBodyObjTImpl(c, t, body, x, y) -proc boolLit*(g: ModuleGraph; info: TLineInfo; value: bool): PNode = - result = newIntLit(g, info, ord value) - result.typ = getSysType(g, info, tyBool) - -proc getCycleParam(c: TLiftCtx): PNode = - assert c.kind == attachedAsgn - if c.fn.typ.len == 4: - result = c.fn.typ.n.lastSon - assert result.kind == nkSym - assert result.sym.name.s == "cyclic" - else: - result = boolLit(c.g, c.info, true) - -proc newHookCall(c: var TLiftCtx; op: PSym; x, y: PNode): PNode = +proc newHookCall(g: ModuleGraph; op: PSym; x, y: PNode): PNode = #if sfError in op.flags: # localError(c.config, x.info, "usage of '$1' is a user-defined error" % op.name.s) result = newNodeI(nkCall, x.info) result.add newSymNode(op) - if sfNeverRaises notin op.flags: - c.canRaise = true if op.typ.sons[1].kind == tyVar: - result.add genAddr(c, x) + result.add genAddr(g, x) else: result.add x if y != nil: result.add y - if op.typ.len == 4: - assert y != nil - if c.fn.typ.len == 4: - result.add getCycleParam(c) - else: - # assume the worst: A cycle is created: - result.add boolLit(c.g, y.info, true) -proc newOpCall(c: var TLiftCtx; op: PSym; x: PNode): PNode = +proc newOpCall(op: PSym; x: PNode): PNode = result = newNodeIT(nkCall, x.info, op.typ[0]) result.add(newSymNode(op)) result.add x - if sfNeverRaises notin op.flags: - c.canRaise = true -proc newDeepCopyCall(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) +proc newDeepCopyCall(op: PSym; x, y: PNode): PNode = + result = newAsgnStmt(x, newOpCall(op, y)) proc useNoGc(c: TLiftCtx; t: PType): bool {.inline.} = result = optSeqDestructors in c.g.config.globalOptions and - ({tfHasGCedMem, tfHasOwned} * t.flags != {} or usesBuiltinArc(t)) + ({tfHasGCedMem, tfHasOwned} * t.flags != {} or t.isGCedMem) proc requiresDestructor(c: TLiftCtx; t: PType): bool {.inline.} = result = optSeqDestructors in c.g.config.globalOptions and @@ -345,20 +218,14 @@ proc instantiateGeneric(c: var TLiftCtx; op: PSym; t, typeInst: PType): PSym = 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 destructorOverriden = destructorOverriden(c.g, t) - if op != nil and op != c.fn and - (sfOverriden in op.flags or destructorOverriden): + let op = field + if field != nil and sfOverriden in field.flags: if sfError in op.flags: incl c.fn.flags, sfError #else: # markUsed(c.g.config, c.info, op, c.g.usageSym) onUse(c.info, op) - body.add newHookCall(c, op, x, y) - result = true - 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) + body.add newHookCall(c.g, op, x, y) result = true elif tfHasAsgn in t.flags: var op: PSym @@ -372,14 +239,14 @@ proc considerAsgnOrSink(c: var TLiftCtx; t: PType; body, x, y: PNode; else: op = field if op == nil: - op = produceSym(c.g, c.c, t, c.kind, c.info, c.idgen) + op = produceSym(c.g, c.c, t, c.kind, c.info) if sfError in op.flags: incl c.fn.flags, sfError #else: # markUsed(c.g.config, c.info, op, c.g.usageSym) onUse(c.info, op) # We also now do generic instantiations in the destructor lifting pass: - if op.ast.isGenericRoutine: + if op.ast[genericParamsPos].kind != nkEmpty: op = instantiateGeneric(c, op, t, t.typeInst) field = op #echo "trying to use ", op.ast @@ -387,28 +254,28 @@ proc considerAsgnOrSink(c: var TLiftCtx; t: PType; body, x, y: PNode; #debug(t) #return false assert op.ast[genericParamsPos].kind == nkEmpty - body.add newHookCall(c, op, x, y) + body.add newHookCall(c.g, op, x, y) result = true proc addDestructorCall(c: var TLiftCtx; orig: PType; body, x: PNode) = - let t = orig.skipTypes(abstractInst - {tyDistinct}) + let t = orig.skipTypes(abstractInst) var op = t.destructor if op != nil and sfOverriden in op.flags: - if op.ast.isGenericRoutine: + if op.ast[genericParamsPos].kind != nkEmpty: # patch generic destructor: op = instantiateGeneric(c, op, t, t.typeInst) - setAttachedOp(c.g, c.idgen.module, t, attachedDestructor, op) + t.attachedOps[attachedDestructor] = op if op == nil and (useNoGc(c, t) or requiresDestructor(c, t)): - op = produceSym(c.g, c.c, t, attachedDestructor, c.info, c.idgen) + op = produceSym(c.g, c.c, t, attachedDestructor, c.info) doAssert op != nil doAssert op == t.destructor if op != nil: #markUsed(c.g.config, c.info, op, c.g.usageSym) onUse(c.info, op) - body.add destructorCall(c, op, x) + body.add destructorCall(c.g, op, x) elif useNoGc(c, t): internalError(c.g.config, c.info, "type-bound operator could not be resolved") @@ -419,52 +286,30 @@ proc considerUserDefinedOp(c: var TLiftCtx; t: PType; body, x, y: PNode): bool = var op = t.destructor if op != nil and sfOverriden in op.flags: - if op.ast.isGenericRoutine: + if op.ast[genericParamsPos].kind != nkEmpty: # patch generic destructor: op = instantiateGeneric(c, op, t, t.typeInst) - setAttachedOp(c.g, c.idgen.module, t, attachedDestructor, op) + t.attachedOps[attachedDestructor] = op #markUsed(c.g.config, c.info, op, c.g.usageSym) onUse(c.info, op) - body.add destructorCall(c, op, x) + body.add destructorCall(c.g, op, x) result = true #result = addDestructorCall(c, t, body, x) of attachedAsgn, attachedSink, attachedTrace: - var op = getAttachedOp(c.g, t, c.kind) - if op != nil and sfOverriden in op.flags: - if op.ast.isGenericRoutine: - # patch generic =trace: - op = instantiateGeneric(c, op, t, t.typeInst) - setAttachedOp(c.g, c.idgen.module, t, c.kind, op) - - result = considerAsgnOrSink(c, t, body, x, y, op) - if op != nil: - setAttachedOp(c.g, c.idgen.module, t, c.kind, op) - + result = considerAsgnOrSink(c, t, body, x, y, t.attachedOps[c.kind]) + of attachedDispose: + result = considerAsgnOrSink(c, t, body, x, nil, t.attachedOps[c.kind]) of attachedDeepCopy: - let op = getAttachedOp(c.g, t, attachedDeepCopy) + let op = t.attachedOps[attachedDeepCopy] if op != nil: #markUsed(c.g.config, c.info, op, c.g.usageSym) onUse(c.info, op) - body.add newDeepCopyCall(c, op, x, y) - result = true - - of attachedWasMoved: - var op = getAttachedOp(c.g, t, attachedWasMoved) - if op != nil and sfOverriden 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) + body.add newDeepCopyCall(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), nextSymId(c.idgen), c.fn, c.info) + var temp = newSym(skTemp, getIdent(c.g.cache, lowerings.genPrefix), c.fn, c.info) temp.typ = getSysType(c.g, body.info, tyInt) incl(temp.flags, sfFromGeneric) @@ -473,53 +318,55 @@ proc declareCounter(c: var TLiftCtx; body: PNode; first: BiggestInt): PNode = v.addVar(result, lowerings.newIntLit(c.g, body.info, first)) body.add v -proc declareTempOf(c: var TLiftCtx; body: PNode; value: PNode): PNode = - 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) +proc genBuiltin(g: ModuleGraph; magic: TMagic; name: string; i: PNode): PNode = + result = newNodeI(nkCall, i.info) + result.add createMagic(g, name, magic).newSymNode + result.add i - var v = newNodeI(nkVarSection, c.info) - result = newSymNode(temp) - v.addVar(result, value) - body.add v +proc genWhileLoop(c: var TLiftCtx; i, dest: PNode): PNode = + result = newNodeI(nkWhileStmt, c.info, 2) + let cmp = genBuiltin(c.g, mLtI, "<", i) + cmp.add genLen(c.g, dest) + cmp.typ = getSysType(c.g, c.info, tyBool) + result[0] = cmp + result[1] = newNodeI(nkStmtList, c.info) + +proc genIf(c: var TLiftCtx; cond, action: PNode): PNode = + result = newTree(nkIfStmt, newTree(nkElifBranch, cond, action)) proc addIncStmt(c: var TLiftCtx; body, i: PNode) = - let incCall = genBuiltin(c, mInc, "inc", i) + let incCall = genBuiltin(c.g, mInc, "inc", i) incCall.add lowerings.newIntLit(c.g, c.info, 1) body.add incCall -proc newSeqCall(c: var TLiftCtx; x, y: PNode): PNode = +proc newSeqCall(g: ModuleGraph; x, y: PNode): PNode = # don't call genAddr(c, x) here: - result = genBuiltin(c, mNewSeq, "newSeq", x) - let lenCall = genBuiltin(c, mLengthSeq, "len", y) - lenCall.typ = getSysType(c.g, x.info, tyInt) + result = genBuiltin(g, mNewSeq, "newSeq", x) + let lenCall = genBuiltin(g, mLengthSeq, "len", y) + lenCall.typ = getSysType(g, x.info, tyInt) result.add lenCall -proc setLenStrCall(c: var TLiftCtx; x, y: PNode): PNode = - let lenCall = genBuiltin(c, mLengthStr, "len", y) - lenCall.typ = getSysType(c.g, x.info, tyInt) - result = genBuiltin(c, mSetLengthStr, "setLen", x) # genAddr(g, x)) +proc setLenStrCall(g: ModuleGraph; x, y: PNode): PNode = + let lenCall = genBuiltin(g, mLengthStr, "len", y) + lenCall.typ = getSysType(g, x.info, tyInt) + result = genBuiltin(g, mSetLengthStr, "setLen", x) # genAddr(g, x)) result.add lenCall proc setLenSeqCall(c: var TLiftCtx; t: PType; x, y: PNode): PNode = - let lenCall = genBuiltin(c, mLengthSeq, "len", y) + let lenCall = genBuiltin(c.g, mLengthSeq, "len", y) lenCall.typ = getSysType(c.g, x.info, tyInt) var op = getSysMagic(c.g, x.info, "setLen", mSetLengthSeq) op = instantiateGeneric(c, op, t, t) result = newTree(nkCall, newSymNode(op, x.info), x, lenCall) proc forallElements(c: var TLiftCtx; t: PType; body, x, y: PNode) = - let counterIdx = body.len let i = declareCounter(c, body, toInt64(firstOrd(c.g.config, t))) let whileLoop = genWhileLoop(c, i, x) let elemType = t.lastSon let b = if c.kind == attachedTrace: y else: y.at(i, elemType) fillBody(c, elemType, whileLoop[1], x.at(i, elemType), b) - if whileLoop[1].len > 0: - addIncStmt(c, whileLoop[1], i) - body.add whileLoop - else: - body.sons.setLen counterIdx + addIncStmt(c, whileLoop[1], i) + body.add whileLoop proc fillSeqOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = case c.kind @@ -532,223 +379,166 @@ proc fillSeqOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = body.add setLenSeqCall(c, t, x, y) forallElements(c, t, body, x, y) of attachedSink: - let moveCall = genBuiltin(c, mMove, "move", x) + let moveCall = genBuiltin(c.g, mMove, "move", x) moveCall.add y doAssert t.destructor != nil - moveCall.add destructorCall(c, t.destructor, x) + moveCall.add destructorCall(c.g, t.destructor, x) body.add moveCall of attachedDestructor: # destroy all elements: forallElements(c, t, body, x, y) - body.add genBuiltin(c, mDestroy, "destroy", x) + body.add genBuiltin(c.g, mDestroy, "destroy", x) of attachedTrace: - if canFormAcycle(t.elemType): - # follow all elements: - forallElements(c, t, body, x, y) - of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "wasMoved", x) + # follow all elements: + forallElements(c, t, body, x, y) + of attachedDispose: + body.add genBuiltin(c.g, mDestroy, "destroy", x) proc useSeqOrStrOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = - createTypeBoundOps(c.g, c.c, t, body.info, c.idgen) + createTypeBoundOps(c.g, c.c, t, body.info) # recursions are tricky, so we might need to forward the generated # operation here: var t = t if t.assignment == nil or t.destructor == nil: - let h = sighashes.hashType(t,c.g.config, {CoType, CoConsiderOwned, CoDistinct}) + let h = sighashes.hashType(t, {CoType, CoConsiderOwned, CoDistinct}) let canon = c.g.canonTypes.getOrDefault(h) if canon != nil: t = canon case c.kind of attachedAsgn, attachedDeepCopy: - # XXX: replace these with assertions. - if t.assignment == nil: - return # protect from recursion - body.add newHookCall(c, t.assignment, x, y) + doAssert t.assignment != nil + body.add newHookCall(c.g, t.assignment, x, y) of attachedSink: # we always inline the move for better performance: - let moveCall = genBuiltin(c, mMove, "move", x) + let moveCall = genBuiltin(c.g, mMove, "move", x) moveCall.add y doAssert t.destructor != nil - moveCall.add destructorCall(c, t.destructor, x) + moveCall.add destructorCall(c.g, t.destructor, x) body.add moveCall # alternatively we could do this: when false: doAssert t.asink != nil - body.add newHookCall(c, t.asink, x, y) + body.add newHookCall(c.g, t.asink, x, y) of attachedDestructor: doAssert t.destructor != nil - body.add destructorCall(c, t.destructor, x) + body.add destructorCall(c.g, t.destructor, x) of attachedTrace: - 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) + body.add newHookCall(c.g, t.attachedOps[c.kind], x, y) + of attachedDispose: + body.add newHookCall(c.g, t.attachedOps[c.kind], x, nil) proc fillStrOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = case c.kind of attachedAsgn, attachedDeepCopy: - body.add callCodegenProc(c.g, "nimAsgnStrV2", c.info, genAddr(c, x), y) + body.add callCodegenProc(c.g, "nimAsgnStrV2", c.info, genAddr(c.g, x), y) of attachedSink: - let moveCall = genBuiltin(c, mMove, "move", x) + let moveCall = genBuiltin(c.g, mMove, "move", x) moveCall.add y doAssert t.destructor != nil - moveCall.add destructorCall(c, t.destructor, x) + moveCall.add destructorCall(c.g, t.destructor, x) body.add moveCall - of attachedDestructor: - body.add genBuiltin(c, mDestroy, "destroy", x) + of attachedDestructor, attachedDispose: + body.add genBuiltin(c.g, 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*(t: PType): bool = - case t.kind - of tyRef: result = types.canFormAcycle(t.lastSon) - of tyProc: result = t.callConv == ccClosure - else: result = false proc atomicRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = - #[ bug #15753 is really subtle. Usually the classical write barrier for reference - counting looks like this:: - - incRef source # increment first; this takes care of self-assignments1 - decRef dest - dest[] = source - - However, 'decRef dest' might trigger a cycle collection and then the collector - traverses the graph. It is crucial that when it follows the pointers the assignment - 'dest[] = source' already happened so that we don't do trial deletion on a wrong - graph -- this causes premature freeing of objects! The correct barrier looks like - this:: - - let tmp = dest - incRef source - dest[] = source - decRef tmp - - ]# var actions = newNodeI(nkStmtList, c.info) let elemType = t.lastSon - createTypeBoundOps(c.g, c.c, elemType, c.info, c.idgen) - let isCyclic = c.g.config.selectedGC == gcOrc and types.canFormAcycle(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 tmp = - if isCyclic and c.kind in {attachedAsgn, attachedSink}: - declareTempOf(c, body, x) - else: - x - if isFinal(elemType): - addDestructorCall(c, elemType, actions, genDeref(tmp, nkDerefExpr)) - var alignOf = genBuiltin(c, mAlignOf, "alignof", newNodeIT(nkType, c.info, elemType)) - alignOf.typ = getSysType(c.g, c.info, tyInt) - actions.add callCodegenProc(c.g, "nimRawDispose", c.info, tmp, alignOf) + addDestructorCall(c, elemType, actions, genDeref(x, nkDerefExpr)) + actions.add callCodegenProc(c.g, "nimRawDispose", c.info, x) else: - addDestructorCall(c, elemType, newNodeI(nkStmtList, c.info), genDeref(tmp, nkDerefExpr)) - actions.add callCodegenProc(c.g, "nimDestroyAndDispose", c.info, tmp) + addDestructorCall(c, elemType, newNodeI(nkStmtList, c.info), genDeref(x, nkDerefExpr)) + actions.add callCodegenProc(c.g, "nimDestroyAndDispose", c.info, x) + + let isCyclic = c.g.config.selectedGC == gcOrc and types.canFormAcycle(t) var cond: PNode if isCyclic: if isFinal(elemType): - let typInfo = genBuiltin(c, mGetTypeInfoV2, "getTypeInfoV2", newNodeIT(nkType, x.info, elemType)) + let typInfo = genBuiltin(c.g, mGetTypeInfo, "getTypeInfo", newNodeIT(nkType, x.info, elemType)) typInfo.typ = getSysType(c.g, c.info, tyPointer) - cond = callCodegenProc(c.g, "nimDecRefIsLastCyclicStatic", c.info, tmp, typInfo) + cond = callCodegenProc(c.g, "nimDecRefIsLastCyclicStatic", c.info, x, typInfo) else: - cond = callCodegenProc(c.g, "nimDecRefIsLastCyclicDyn", c.info, tmp) - elif isInheritableAcyclicRef: - cond = callCodegenProc(c.g, "nimDecRefIsLastDyn", c.info, x) + cond = callCodegenProc(c.g, "nimDecRefIsLastCyclicDyn", c.info, x) else: cond = callCodegenProc(c.g, "nimDecRefIsLast", c.info, x) cond.typ = getSysType(c.g, x.info, tyBool) case c.kind of attachedSink: - if isCyclic: - body.add newAsgnStmt(x, y) - body.add genIf(c, cond, actions) - else: - body.add genIf(c, cond, actions) - body.add newAsgnStmt(x, y) + body.add genIf(c, cond, actions) + body.add newAsgnStmt(x, y) of attachedAsgn: - if isCyclic: - body.add genIf(c, y, callCodegenProc(c.g, - "nimIncRefCyclic", c.info, y, getCycleParam(c))) - body.add newAsgnStmt(x, y) - body.add genIf(c, cond, actions) - else: - body.add genIf(c, y, callCodegenProc(c.g, "nimIncRef", c.info, y)) - body.add genIf(c, cond, actions) - body.add newAsgnStmt(x, y) + body.add genIf(c, y, callCodegenProc(c.g, + if isCyclic: "nimIncRefCyclic" else: "nimIncRef", c.info, y)) + body.add genIf(c, cond, actions) + body.add newAsgnStmt(x, y) of attachedDestructor: + actions.add newAsgnStmt(x, newNodeIT(nkNilLit, body.info, t)) body.add genIf(c, cond, actions) of attachedDeepCopy: assert(false, "cannot happen") of attachedTrace: - if isCyclic: - if isFinal(elemType): - let typInfo = genBuiltin(c, mGetTypeInfoV2, "getTypeInfoV2", newNodeIT(nkType, x.info, elemType)) - typInfo.typ = getSysType(c.g, c.info, tyPointer) - body.add callCodegenProc(c.g, "nimTraceRef", c.info, genAddrOf(x, c.idgen), typInfo, y) - else: - # 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) - + if isFinal(elemType): + let typInfo = genBuiltin(c.g, mGetTypeInfo, "getTypeInfo", newNodeIT(nkType, x.info, elemType)) + typInfo.typ = getSysType(c.g, c.info, tyPointer) + body.add callCodegenProc(c.g, "nimTraceRef", c.info, x, typInfo, y) + else: + # If the ref is polymorphic we have to account for this + body.add callCodegenProc(c.g, "nimTraceRefDyn", c.info, x, y) + of attachedDispose: + # this is crucial! dispose is like =destroy but we don't follow refs + # as that is dealt within the cycle collector. + when false: + let cond = copyTree(x) + cond.typ = getSysType(c.g, x.info, tyBool) + actions.add callCodegenProc(c.g, "nimRawDispose", c.info, x) + body.add genIf(c, cond, actions) proc atomicClosureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = ## Closures are really like refs except they always use a virtual destructor ## and we need to do the refcounting only on the ref field which we call 'xenv': - let xenv = genBuiltin(c, mAccessEnv, "accessEnv", x) + let xenv = genBuiltin(c.g, mAccessEnv, "accessEnv", x) xenv.typ = getSysType(c.g, c.info, tyPointer) - let isCyclic = c.g.config.selectedGC == gcOrc - let tmp = - if isCyclic and c.kind in {attachedAsgn, attachedSink}: - declareTempOf(c, body, xenv) - else: - xenv - var actions = newNodeI(nkStmtList, c.info) - actions.add callCodegenProc(c.g, "nimDestroyAndDispose", c.info, tmp) + actions.add callCodegenProc(c.g, "nimDestroyAndDispose", c.info, xenv) let decRefProc = - if isCyclic: "nimDecRefIsLastCyclicDyn" + if c.g.config.selectedGC == gcOrc: "nimDecRefIsLastCyclicDyn" else: "nimDecRefIsLast" - let cond = callCodegenProc(c.g, decRefProc, c.info, tmp) + let cond = callCodegenProc(c.g, decRefProc, c.info, xenv) cond.typ = getSysType(c.g, x.info, tyBool) case c.kind of attachedSink: - if isCyclic: - body.add newAsgnStmt(x, y) - body.add genIf(c, cond, actions) - else: - body.add genIf(c, cond, actions) - body.add newAsgnStmt(x, y) + body.add genIf(c, cond, actions) + body.add newAsgnStmt(x, y) of attachedAsgn: - let yenv = genBuiltin(c, mAccessEnv, "accessEnv", y) + let yenv = genBuiltin(c.g, mAccessEnv, "accessEnv", y) yenv.typ = getSysType(c.g, c.info, tyPointer) - if isCyclic: - body.add genIf(c, yenv, callCodegenProc(c.g, "nimIncRefCyclic", c.info, yenv, getCycleParam(c))) - body.add newAsgnStmt(x, y) - body.add genIf(c, cond, actions) - else: - body.add genIf(c, yenv, callCodegenProc(c.g, "nimIncRef", c.info, yenv)) - - body.add genIf(c, cond, actions) - body.add newAsgnStmt(x, y) + let incRefProc = + if c.g.config.selectedGC == gcOrc: "nimIncRefCyclic" + else: "nimIncRef" + body.add genIf(c, yenv, callCodegenProc(c.g, incRefProc, c.info, yenv)) + body.add genIf(c, cond, actions) + body.add newAsgnStmt(x, y) of attachedDestructor: + actions.add newAsgnStmt(xenv, newNodeIT(nkNilLit, body.info, xenv.typ)) 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) + body.add callCodegenProc(c.g, "nimTraceRefDyn", c.info, xenv, y) + of attachedDispose: + # this is crucial! dispose is like =destroy but we don't follow refs + # as that is dealt within the cycle collector. + when false: + let cond = copyTree(xenv) + cond.typ = getSysType(c.g, xenv.info, tyBool) + actions.add callCodegenProc(c.g, "nimRawDispose", c.info, xenv) + body.add genIf(c, cond, actions) proc weakrefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = case c.kind @@ -766,27 +556,25 @@ proc weakrefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = # prevent wrong "dangling refs exist" problems: var actions = newNodeI(nkStmtList, c.info) actions.add callCodegenProc(c.g, "nimDecWeakRef", c.info, x) + actions.add newAsgnStmt(x, newNodeIT(nkNilLit, body.info, t)) let des = genIf(c, x, actions) if body.len == 0: body.add des else: body.sons.insert(des, 0) of attachedDeepCopy: assert(false, "cannot happen") - of attachedTrace: discard - of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "wasMoved", x) + of attachedTrace, attachedDispose: discard proc ownedRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = var actions = newNodeI(nkStmtList, c.info) let elemType = t.lastSon #fillBody(c, elemType, actions, genDeref(x), genDeref(y)) - #var disposeCall = genBuiltin(c, mDispose, "dispose", x) + #var disposeCall = genBuiltin(c.g, mDispose, "dispose", x) if isFinal(elemType): addDestructorCall(c, elemType, actions, genDeref(x, nkDerefExpr)) - var alignOf = genBuiltin(c, mAlignOf, "alignof", newNodeIT(nkType, c.info, elemType)) - alignOf.typ = getSysType(c.g, c.info, tyInt) - actions.add callCodegenProc(c.g, "nimRawDispose", c.info, x, alignOf) + actions.add callCodegenProc(c.g, "nimRawDispose", c.info, x) else: addDestructorCall(c, elemType, newNodeI(nkStmtList, c.info), genDeref(x, nkDerefExpr)) actions.add callCodegenProc(c.g, "nimDestroyAndDispose", c.info, x) @@ -796,10 +584,10 @@ proc ownedRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = body.add genIf(c, x, actions) body.add newAsgnStmt(x, y) of attachedDestructor: + actions.add newAsgnStmt(x, newNodeIT(nkNilLit, body.info, t)) body.add genIf(c, x, actions) of attachedDeepCopy: assert(false, "cannot happen") - of attachedTrace: discard - of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "wasMoved", x) + of attachedTrace, attachedDispose: discard proc closureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = if c.kind == attachedDeepCopy: @@ -807,12 +595,12 @@ proc closureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = # have to go through some indirection; we delegate this to the codegen: let call = newNodeI(nkCall, c.info, 2) call.typ = t - call[0] = newSymNode(createMagic(c.g, c.idgen, "deepCopy", mDeepCopy)) + call[0] = newSymNode(createMagic(c.g, "deepCopy", mDeepCopy)) 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, gcOrc}: - let xx = genBuiltin(c, mAccessEnv, "accessEnv", x) + let xx = genBuiltin(c.g, mAccessEnv, "accessEnv", x) xx.typ = getSysType(c.g, c.info, tyPointer) case c.kind of attachedSink: @@ -821,23 +609,25 @@ proc closureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = body.add genIf(c, xx, callCodegenProc(c.g, "nimDecWeakRef", c.info, xx)) body.add newAsgnStmt(x, y) of attachedAsgn: - let yy = genBuiltin(c, mAccessEnv, "accessEnv", y) + let yy = genBuiltin(c.g, mAccessEnv, "accessEnv", y) yy.typ = getSysType(c.g, c.info, tyPointer) 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 attachedDestructor: - let des = genIf(c, xx, callCodegenProc(c.g, "nimDecWeakRef", c.info, xx)) + var actions = newNodeI(nkStmtList, c.info) + actions.add callCodegenProc(c.g, "nimDecWeakRef", c.info, xx) + actions.add newAsgnStmt(xx, newNodeIT(nkNilLit, body.info, xx.typ)) + let des = genIf(c, xx, actions) if body.len == 0: body.add des else: body.sons.insert(des, 0) of attachedDeepCopy: assert(false, "cannot happen") - of attachedTrace: discard - of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "wasMoved", x) + of attachedTrace, attachedDispose: discard proc ownedClosureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = - let xx = genBuiltin(c, mAccessEnv, "accessEnv", x) + let xx = genBuiltin(c.g, mAccessEnv, "accessEnv", x) xx.typ = getSysType(c.g, c.info, tyPointer) var actions = newNodeI(nkStmtList, c.info) #discard addDestructorCall(c, elemType, newNodeI(nkStmtList, c.info), genDeref(xx)) @@ -847,16 +637,16 @@ proc ownedClosureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = body.add genIf(c, xx, actions) body.add newAsgnStmt(x, y) of attachedDestructor: + actions.add newAsgnStmt(xx, newNodeIT(nkNilLit, body.info, xx.typ)) body.add genIf(c, xx, actions) of attachedDeepCopy: assert(false, "cannot happen") - of attachedTrace: discard - of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "wasMoved", x) + of attachedTrace, attachedDispose: discard proc fillBody(c: var TLiftCtx; t: PType; body, x, y: PNode) = case t.kind of tyNone, tyEmpty, tyVoid: discard - of tyPointer, tySet, tyBool, tyChar, tyEnum, tyInt..tyUInt64, tyCstring, - tyPtr, tyUncheckedArray, tyVar, tyLent: + of tyPointer, tySet, tyBool, tyChar, tyEnum, tyInt..tyUInt64, tyCString, + tyPtr, tyOpt, tyUncheckedArray, tyVar, tyLent: defaultOp(c, t, body, x, y) of tyRef: if c.g.config.selectedGC in {gcArc, gcOrc}: @@ -901,7 +691,7 @@ proc fillBody(c: var TLiftCtx; t: PType; body, x, y: PNode) = discard considerUserDefinedOp(c, t, body, x, y) elif tfHasAsgn in t.flags: if c.kind in {attachedAsgn, attachedSink, attachedDeepCopy}: - body.add newSeqCall(c, x, y) + body.add newSeqCall(c.g, x, y) forallElements(c, t, body, x, y) else: defaultOp(c, t, body, x, y) @@ -932,91 +722,69 @@ proc fillBody(c: var TLiftCtx; t: PType; body, x, y: PNode) = of tyFromExpr, tyProxy, tyBuiltInTypeClass, tyUserTypeClass, tyUserTypeClassInst, tyCompositeTypeClass, tyAnd, tyOr, tyNot, tyAnything, tyGenericParam, tyGenericBody, tyNil, tyUntyped, tyTyped, - tyTypeDesc, tyGenericInvocation, tyForward, tyStatic: + tyTypeDesc, tyGenericInvocation, tyForward: #internalError(c.g.config, c.info, "assignment requested for type: " & typeToString(t)) discard of tyOrdinal, tyRange, tyInferred, - tyGenericInst, tyAlias, tySink: + tyGenericInst, tyStatic, tyAlias, tySink: fillBody(c, lastSon(t), body, x, y) - of tyConcept, tyIterable: doAssert false proc produceSymDistinctType(g: ModuleGraph; c: PContext; typ: PType; - kind: TTypeAttachedOp; info: TLineInfo; - idgen: IdGenerator): PSym = + kind: TTypeAttachedOp; info: TLineInfo): PSym = assert typ.kind == tyDistinct let baseType = typ[0] - if getAttachedOp(g, baseType, kind) == nil: - discard produceSym(g, c, baseType, kind, info, idgen) - result = getAttachedOp(g, baseType, kind) - setAttachedOp(g, idgen.module, typ, kind, result) + if baseType.attachedOps[kind] == nil: + discard produceSym(g, c, baseType, kind, info) + typ.attachedOps[kind] = baseType.attachedOps[kind] + result = typ.attachedOps[kind] -proc symPrototype(g: ModuleGraph; typ: PType; owner: PSym; kind: TTypeAttachedOp; - info: TLineInfo; idgen: IdGenerator): PSym = +proc produceSym(g: ModuleGraph; c: PContext; typ: PType; kind: TTypeAttachedOp; + info: TLineInfo): PSym = + if typ.kind == tyDistinct: + return produceSymDistinctType(g, c, typ, kind, info) + var a: TLiftCtx + a.info = info + a.g = g + a.kind = kind + a.c = c + let body = newNodeI(nkStmtList, info) let procname = getIdent(g.cache, AttachedOpToStr[kind]) - 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"), - nextSymId(idgen), result, info) - dest.typ = makeVarType(typ.owner, typ, idgen) + + result = newSym(skProc, procname, typ.owner, info) + a.fn = result + a.asgnForType = typ + + let dest = newSym(skParam, getIdent(g.cache, "dest"), result, info) + let src = newSym(skParam, getIdent(g.cache, if kind == attachedTrace: "env" else: "src"), result, info) + var d: PNode + #if kind notin {attachedTrace, attachedDispose}: + dest.typ = makeVarType(typ.owner, typ) + d = newDeref(newSymNode(dest)) + #else: + # dest.typ = typ + # d = newSymNode(dest) + if kind == attachedTrace: src.typ = getSysType(g, info, tyPointer) else: src.typ = typ - result.typ = newProcType(info, nextTypeId(idgen), owner) + result.typ = newProcType(info, typ.owner) result.typ.addParam dest - if kind notin {attachedDestructor, attachedWasMoved}: + if kind notin {attachedDestructor, attachedDispose}: result.typ.addParam src - if kind == attachedAsgn and g.config.selectedGC == gcOrc and - cyclicType(typ.skipTypes(abstractInst)): - let cycleParam = newSym(skParam, getIdent(g.cache, "cyclic"), - nextSymId(idgen), result, info) - cycleParam.typ = getSysType(g, info, tyBool) - result.typ.addParam cycleParam - - var n = newNodeI(nkProcDef, info, bodyPos+1) - for i in 0..
\n", - "\n\n$2\\begin{rstpre}\n$1\n\\end{rstpre}\n\n", result) - of rnMarkdownBlockQuote: - d.curQuotationDepth = 1 - var tmp = "" - renderAux(d, n, "$1", "$1", tmp) - let itemEnding = - if d.target == outHtml: "" else: "\\end{rstquote}" - tmp.add itemEnding.repeat(d.curQuotationDepth - 1) - dispA(d.target, result, - "$1\n", - "\n\\begin{rstquote}\n$2\n$1\\end{rstquote}\n", [tmp, n.anchor.idS]) - of rnMarkdownBlockQuoteItem: - let addQuotationDepth = n.quotationDepth - d.curQuotationDepth - var itemPrefix: string # start or ending (quotation grey bar on the left) - if addQuotationDepth >= 0: - let s = - if d.target == outHtml: "
" - else: "\\begin{rstquote}" - itemPrefix = s.repeat(addQuotationDepth) - else: - let s = - if d.target == outHtml: "
" - else: "\\end{rstquote}" - itemPrefix = s.repeat(-addQuotationDepth) - renderAux(d, n, itemPrefix & "

$1

", itemPrefix & "\n$1", result) - d.curQuotationDepth = n.quotationDepth + renderAux(d, n, "
$1
\n", + "\\begin{rstpre}\n$1\n\\end{rstpre}\n", result) + of rnQuotedLiteralBlock: + doAssert false, "renderRstToOut" of rnLineBlock: - if n.sons.len == 1 and n.sons[0].lineIndent == "\n": - # whole line block is one empty line, no need to add extra spacing - renderAux(d, n, "$1

", "\n\n$2\n$1", result) - else: # add extra spacing around the line block for Latex - renderAux(d, n, "$1

", - "\n\\vspace{0.5em}$2\n$1\\vspace{0.5em}\n", result) + renderAux(d, n, "

$1

", "$1\n\n", result) of rnLineBlockItem: - if n.lineIndent.len == 0: # normal case - no additional indentation - renderAux(d, n, "$1
", "\\noindent $1\n\n", result) - elif n.lineIndent == "\n": # add one empty line - renderAux(d, n, "
", "\\vspace{1em}\n", result) - else: # additional indentation w.r.t. '| ' - let indent = $(0.5 * (n.lineIndent.len - 1).toFloat) & "em" - renderAux(d, n, - "$1
", - "\\noindent\\hspace{" & indent & "}$1\n\n", result) + renderAux(d, n, "$1
", "$1\\\\\n", result) of rnBlockQuote: - renderAux(d, n, "

$1

\n", - "\\begin{quote}\n$2\n$1\\end{quote}\n", result) - of rnAdmonition: renderAdmonition(d, n, result) - of rnTable, rnGridTable, rnMarkdownTable: + renderAux(d, n, "

$1

\n", + "\\begin{quote}$1\\end{quote}\n", result) + of rnTable, rnGridTable: renderAux(d, n, - "$1", - "\n$2\n\\begin{rsttab}{" & - "L".repeat(n.colCount) & "}\n\\toprule\n$1" & - "\\addlinespace[0.1em]\\bottomrule\n\\end{rsttab}", result) + "$1
", + "\\begin{table}\\begin{rsttab}{" & + texColumns(n) & "|}\n\\hline\n$1\\end{rsttab}\\end{table}", result) of rnTableRow: if len(n) >= 1: - case d.target - of outHtml: + if d.target == outLatex: + #var tmp = "" + renderRstToOut(d, n.sons[0], result) + for i in countup(1, len(n) - 1): + result.add(" & ") + renderRstToOut(d, n.sons[i], result) + result.add("\\\\\n\\hline\n") + else: result.add("") renderAux(d, n, result) result.add("\n") - of outLatex: - if n.sons[0].kind == rnTableHeaderCell: - result.add "\\rowcolor{gray!15} " - var spanLines: seq[(int, int)] - var nCell = 0 - for uCell in 0 .. n.len - 1: - renderRstToOut(d, n.sons[uCell], result) - if n.sons[uCell].span > 0: - spanLines.add (nCell + 1, nCell + n.sons[uCell].span) - nCell += n.sons[uCell].span - else: - nCell += 1 - if uCell != n.len - 1: - result.add(" & ") - result.add("\\\\") - if n.endsHeader: result.add("\\midrule\n") - for (start, stop) in spanLines: - result.add("\\cmidrule(lr){$1-$2}" % [$start, $stop]) - result.add("\n") - of rnTableHeaderCell, rnTableDataCell: - case d.target - of outHtml: - let tag = if n.kind == rnTableHeaderCell: "th" else: "td" - var spanSpec: string - if n.span <= 1: spanSpec = "" - else: - spanSpec = " colspan=\"" & $n.span & "\" style=\"text-align: center\"" - renderAux(d, n, "<$1$2>$$1" % [tag, spanSpec], "", result) - of outLatex: - let text = if n.kind == rnTableHeaderCell: "\\textbf{$1}" else: "$1" - var latexStr: string - if n.span <= 1: latexStr = text - else: latexStr = "\\multicolumn{" & $n.span & "}{c}{" & text & "}" - renderAux(d, n, "", latexStr, result) - of rnFootnoteGroup: - renderAux(d, n, - "
" & - "
\n$1
\n", - "\n\n\\noindent\\rule{0.25\\linewidth}{.4pt}\n" & - "\\begin{rstfootnote}\n$1\\end{rstfootnote}\n\n", - result) - of rnFootnote, rnCitation: - var mark = "" - renderAux(d, n.sons[0], mark) - var body = "" - renderRstToOut(d, n.sons[1], body) + of rnTableDataCell: + renderAux(d, n, "$1", "$1", result) + of rnTableHeaderCell: + renderAux(d, n, "$1", "\\textbf{$1}", result) + of rnLabel: + doAssert false, "renderRstToOut" # used for footnotes and other + of rnFootnote: + doAssert false, "renderRstToOut" # a footnote + of rnCitation: + doAssert false, "renderRstToOut" # similar to footnote + of rnRef: + var tmp = "" + renderAux(d, n, tmp) dispA(d.target, result, - "
" & - "[$3]" & - "
  $1\n\n", - "\\item[\\textsuperscript{[$3]}]$2 $1\n", - [body, n.anchor.idS, mark, n.anchor]) - of rnPandocRef: - renderHyperlink(d, text=n.sons[0], link=n.sons[1], result, external=false) - of rnRstRef: - renderHyperlink(d, text=n.sons[0], link=n.sons[0], result, external=false) + "$1", + "$1\\ref{$2}", [tmp, rstnodeToRefname(n)]) of rnStandaloneHyperlink: - renderHyperlink(d, text=n.sons[0], link=n.sons[0], result, external=true) - of rnInternalRef: - renderHyperlink(d, text=n.sons[0], link=n.sons[1], result, external=false) - of rnNimdocRef: - renderHyperlink(d, text=n.sons[0], link=n.sons[1], result, external=false, - nimdoc=true, tooltip=n.tooltip) + renderAux(d, n, + "$1", + "\\href{$1}{$1}", result) of rnHyperlink: - renderHyperlink(d, text=n.sons[0], link=n.sons[1], result, external=true) - of rnFootnoteRef: - var tmp = "[" - renderAux(d, n.sons[0], tmp) - tmp.add "]" + var tmp0 = "" + var tmp1 = "" + renderRstToOut(d, n.sons[0], tmp0) + renderRstToOut(d, n.sons[1], tmp1) dispA(d.target, result, - "" & - "$1", - "\\textsuperscript{\\hyperlink{$2}{\\textbf{$1}}}", - [tmp, n.sons[1].text]) + "$1", + "\\href{$2}{$1}", [tmp0, tmp1]) of rnDirArg, rnRaw: renderAux(d, n, result) of rnRawHtml: - if d.target != outLatex and not lastSon(n).isNil: + if d.target != outLatex: result.add addNodes(lastSon(n)) of rnRawLatex: - if d.target == outLatex and not lastSon(n).isNil: + if d.target == outLatex: result.add addNodes(lastSon(n)) of rnImage, rnFigure: renderImage(d, n, result) - of rnCodeBlock, rnInlineCode: renderCode(d, n, result) + of rnCodeBlock: renderCodeBlock(d, n, result) of rnContainer: renderContainer(d, n, result) of rnSubstitutionReferences, rnSubstitutionDef: renderAux(d, n, "|$1|", "|$1|", result) of rnDirective: renderAux(d, n, "", "", result) - of rnUnknownRole, rnCodeFragment: + of rnGeneralRole: var tmp0 = "" var tmp1 = "" renderRstToOut(d, n.sons[0], tmp0) renderRstToOut(d, n.sons[1], tmp1) - var class = tmp1 - # don't allow missing role break latex compilation: - if d.target == outLatex and n.kind == rnUnknownRole: class = "Other" - if n.kind == rnCodeFragment: - dispA(d.target, result, - "" & - "$1", - "\\rstcode{\\span$2{$1}}", [tmp0, class]) - else: # rnUnknownRole, not necessarily code/monospace font - dispA(d.target, result, "$1", "\\span$2{$1}", - [tmp0, class]) + dispA(d.target, result, "$1", "\\span$2{$1}", + [tmp0, tmp1]) of rnSub: renderAux(d, n, "$1", "\\rstsub{$1}", result) of rnSup: renderAux(d, n, "$1", "\\rstsup{$1}", result) of rnEmphasis: renderAux(d, n, "$1", "\\emph{$1}", result) @@ -1347,22 +1148,13 @@ proc renderRstToOut(d: PDoc, n: PRstNode, result: var string) = of rnInlineLiteral, rnInterpretedText: renderAux(d, n, "$1", - "\\rstcode{$1}", result) - of rnInlineTarget: - var tmp = "" - renderAux(d, n, tmp) - dispA(d.target, result, - "$1", - "\\label{$2}\\hypertarget{$2}{$1}", - [tmp, rstnodeToRefname(n)]) + "\\texttt{$1}", result) of rnSmiley: renderSmiley(d, n, result) - of rnLeaf: result.add(esc(d.target, n.text, escMode=d.escMode)) + of rnLeaf: result.add(esc(d.target, n.text)) of rnContents: d.hasToc = true - of rnDefaultRole: discard of rnTitle: d.meta[metaTitle] = "" renderRstToOut(d, n.sons[0], d.meta[metaTitle]) - d.meta[metaTitleRaw] = n.sons[0].addNodes # ----------------------------------------------------------------------------- @@ -1492,7 +1284,7 @@ $moduledesc $content """) - setConfigVar("doc.listing_start", "") + setConfigVar("doc.listing_start", "
")
   setConfigVar("doc.listing_end", "
") setConfigVar("doc.listing_button", "
") setConfigVar("doc.body_no_toc", "$moduledesc $content") @@ -1502,8 +1294,7 @@ $content # ---------- forum --------------------------------------------------------- proc rstToHtml*(s: string, options: RstParseOptions, - config: StringTableRef, - msgHandler: MsgHandler = rst.defaultMsgHandler): string {.gcsafe.} = + config: StringTableRef): string = ## Converts an input rst string into embeddable HTML. ## ## This convenience proc parses any input string using rst markup (it doesn't @@ -1513,13 +1304,12 @@ proc rstToHtml*(s: string, options: RstParseOptions, ## work. For an explanation of the ``config`` parameter see the ## ``initRstGenerator`` proc. Example: ## - ## ```nim + ## .. code-block:: nim ## import packages/docutils/rstgen, strtabs ## ## echo rstToHtml("*Hello* **world**!", {}, ## newStringTable(modeStyleInsensitive)) ## # --> Hello world! - ## ``` ## ## If you need to allow the rst ``include`` directive or tweak the generated ## output you have to create your own ``RstGenerator`` with @@ -1528,30 +1318,18 @@ proc rstToHtml*(s: string, options: RstParseOptions, proc myFindFile(filename: string): string = # we don't find any files in online mode: result = "" - proc myFindRefFile(filename: string): (string, string) = - result = ("", "") const filen = "input" - let (rst, filenames, t) = rstParse(s, filen, - line=LineRstInit, column=ColRstInit, - options, myFindFile, myFindRefFile, msgHandler) var d: RstGenerator - initRstGenerator(d, outHtml, config, filen, myFindFile, msgHandler, - filenames, hasToc = t) + initRstGenerator(d, outHtml, config, filen, options, myFindFile, + rst.defaultMsgHandler) + var dummyHasToc = false + var rst = rstParse(s, filen, 0, 1, dummyHasToc, options) result = "" renderRstToOut(d, rst, result) - strbasics.strip(result) -proc rstToLatex*(rstSource: string; options: RstParseOptions): string {.inline, since: (1, 3).} = - ## Convenience proc for `renderRstToOut` and `initRstGenerator`. - runnableExamples: doAssert rstToLatex("*Hello* **world**", {}) == """\emph{Hello} \textbf{world}""" - if rstSource.len == 0: return - let (rst, filenames, t) = rstParse(rstSource, "", - line=LineRstInit, column=ColRstInit, - options) - var rstGenera: RstGenerator - rstGenera.initRstGenerator(outLatex, defaultConfig(), "input", - filenames=filenames, hasToc = t) - rstGenera.renderRstToOut(rst, result) - strbasics.strip(result) +when isMainModule: + assert rstToHtml("*Hello* **world**!", {}, + newStringTable(modeStyleInsensitive)) == + "Hello world!" diff --git a/lib/packages/docutils/rstidx.nim b/lib/packages/docutils/rstidx.nim deleted file mode 100644 index c109636d7..000000000 --- a/lib/packages/docutils/rstidx.nim +++ /dev/null @@ -1,138 +0,0 @@ -# -# Nim's Runtime Library -# (c) Copyright 2022 Andreas Rumpf -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. - -## Nim `idx`:idx: file format related definitions. - -import strutils, std/syncio, hashes -from os import splitFile - -type - IndexEntryKind* = enum ## discriminator tag - ieMarkupTitle = "markupTitle" - ## RST/Markdown title, text in `keyword` + - ## HTML text in `linkTitle` - ieNimTitle = "nimTitle" - ## Nim title - ieHeading = "heading" ## RST/Markdown markup heading, escaped - ieIdxRole = "idx" ## RST :idx: definition, escaped - ieNim = "nim" ## Nim symbol, unescaped - ieNimGroup = "nimgrp" ## Nim overload group, unescaped - IndexEntry* = object - kind*: IndexEntryKind ## 0. - keyword*: string ## 1. - link*: string ## 2. - linkTitle*: string ## 3. contains a prettier text for the href - linkDesc*: string ## 4. the title attribute of the final href - line*: int ## 5. - module*: string ## origin file, NOT a field in ``.idx`` file - aux*: string ## auxuliary field, NOT a field in ``.idx`` file - -proc isDocumentationTitle*(hyperlink: string): bool = - ## Returns true if the hyperlink is actually a documentation title. - ## - ## Documentation titles lack the hash. See `mergeIndexes() - ## <#mergeIndexes,string>`_ for a more detailed explanation. - result = hyperlink.find('#') < 0 - -proc `$`*(e: IndexEntry): string = - """("$1", "$2", "$3", "$4", $5)""" % [ - e.keyword, e.link, e.linkTitle, e.linkDesc, $e.line] - -proc quoteIndexColumn(text: string): string = - ## Returns a safe version of `text` for serialization to the ``.idx`` file. - ## - ## The returned version can be put without worries in a line based tab - ## separated column text file. The following character sequence replacements - ## will be performed for that goal: - ## - ## * ``"\\"`` => ``"\\\\"`` - ## * ``"\n"`` => ``"\\n"`` - ## * ``"\t"`` => ``"\\t"`` - result = newStringOfCap(text.len + 3) - for c in text: - case c - of '\\': result.add "\\" - of '\L': result.add "\\n" - of '\C': discard - of '\t': result.add "\\t" - else: result.add c - -proc unquoteIndexColumn*(text: string): string = - ## Returns the unquoted version generated by ``quoteIndexColumn``. - result = text.multiReplace(("\\t", "\t"), ("\\n", "\n"), ("\\\\", "\\")) - -proc formatIndexEntry*(kind: IndexEntryKind; htmlFile, id, term, linkTitle, - linkDesc: string, line: int): - tuple[entry: string, isTitle: bool] = - result.entry = $kind - result.entry.add('\t') - result.entry.add term - result.entry.add('\t') - result.entry.add(htmlFile) - if id.len > 0: - result.entry.add('#') - result.entry.add(id) - result.isTitle = false - else: - result.isTitle = true - result.entry.add('\t' & linkTitle.quoteIndexColumn) - result.entry.add('\t' & linkDesc.quoteIndexColumn) - result.entry.add('\t' & $line) - result.entry.add("\n") - -proc parseIndexEntryKind(s: string): IndexEntryKind = - result = case s: - of "nim": ieNim - of "nimgrp": ieNimGroup - of "heading": ieHeading - of "idx": ieIdxRole - of "nimTitle": ieNimTitle - of "markupTitle": ieMarkupTitle - else: raise newException(ValueError, "unknown index entry value $1" % [s]) - -proc parseIdxFile*(path: string): - tuple[fileEntries: seq[IndexEntry], title: IndexEntry] = - var - f = 0 - newSeq(result.fileEntries, 500) - setLen(result.fileEntries, 0) - let (_, base, _) = path.splitFile - for line in lines(path): - let s = line.find('\t') - if s < 0: continue - setLen(result.fileEntries, f+1) - let cols = line.split('\t') - result.fileEntries[f].kind = parseIndexEntryKind(cols[0]) - result.fileEntries[f].keyword = cols[1] - result.fileEntries[f].link = cols[2] - if result.title.keyword.len == 0: - result.fileEntries[f].module = base - else: - result.fileEntries[f].module = result.title.keyword - - result.fileEntries[f].linkTitle = cols[3].unquoteIndexColumn - result.fileEntries[f].linkDesc = cols[4].unquoteIndexColumn - result.fileEntries[f].line = parseInt(cols[5]) - - if result.fileEntries[f].kind in {ieNimTitle, ieMarkupTitle}: - result.title = result.fileEntries[f] - inc f - -proc cmp*(a, b: IndexEntry): int = - ## Sorts two ``IndexEntry`` first by `keyword` field, then by `link`. - result = cmpIgnoreStyle(a.keyword, b.keyword) - if result == 0: - result = cmpIgnoreStyle(a.link, b.link) - -proc hash*(x: IndexEntry): Hash = - ## Returns the hash for the combined fields of the type. - ## - ## The hash is computed as the chained hash of the individual string hashes. - result = x.keyword.hash !& x.link.hash - result = result !& x.linkTitle.hash - result = result !& x.linkDesc.hash - result = !$result diff --git a/lib/posix/epoll.nim b/lib/posix/epoll.nim index 7ee062e4f..2d38137bb 100644 --- a/lib/posix/epoll.nim +++ b/lib/posix/epoll.nim @@ -7,6 +7,8 @@ # distribution, for details about the copyright. # +{.deadCodeElim: on.} # dce option deprecated + from posix import SocketHandle const @@ -21,7 +23,6 @@ const EPOLLWRBAND* = 0x00000200 EPOLLMSG* = 0x00000400 EPOLLRDHUP* = 0x00002000 - EPOLLEXCLUSIVE* = 1 shl 28 EPOLLWAKEUP* = 1 shl 29 EPOLLONESHOT* = 1 shl 30 EPOLLET* = 1 shl 31 @@ -33,67 +34,56 @@ const EPOLL_CTL_DEL* = 2 # Remove a file descriptor from the interface. EPOLL_CTL_MOD* = 3 # Change file descriptor epoll_event structure. -# https://github.com/torvalds/linux/blob/ff6992735ade75aae3e35d16b17da1008d753d28/include/uapi/linux/eventpoll.h#L77 -when defined(linux) and defined(amd64): - {.pragma: epollPacked, packed.} -else: - {.pragma: epollPacked.} - type - EpollData* {.importc: "epoll_data_t", - header: "", pure, final, union.} = object - `ptr`* {.importc: "ptr".}: pointer - fd* {.importc: "fd".}: cint - u32* {.importc: "u32".}: uint32 + EpollData* {.importc: "union epoll_data", + header: "", pure, final.} = object # TODO: This is actually a union. u64* {.importc: "u64".}: uint64 - EpollEvent* {.importc: "struct epoll_event", header: "", pure, final, epollPacked.} = object + EpollEvent* {.importc: "struct epoll_event", header: "", pure, final.} = object events*: uint32 # Epoll events data*: EpollData # User data variable proc epoll_create*(size: cint): cint {.importc: "epoll_create", header: "".} ## Creates an epoll instance. Returns an fd for the new instance. - ## - ## The "size" parameter is a hint specifying the number of file - ## descriptors to be associated with the new instance. The fd - ## returned by epoll_create() should be closed with close(). + ## The "size" parameter is a hint specifying the number of file + ## descriptors to be associated with the new instance. The fd + ## returned by epoll_create() should be closed with close(). proc epoll_create1*(flags: cint): cint {.importc: "epoll_create1", header: "".} ## Same as epoll_create but with an FLAGS parameter. The unused SIZE - ## parameter has been dropped. + ## parameter has been dropped. proc epoll_ctl*(epfd: cint; op: cint; fd: cint | SocketHandle; event: ptr EpollEvent): cint {. importc: "epoll_ctl", header: "".} - ## Manipulate an epoll instance "epfd". Returns `0` in case of success, - ## `-1` in case of error (the "errno" variable will contain the specific error code). - ## - ## The "op" parameter is one of the `EPOLL_CTL_*` - ## constants defined above. The "fd" parameter is the target of the - ## operation. The "event" parameter describes which events the caller - ## is interested in and any associated user data. + ## Manipulate an epoll instance "epfd". Returns 0 in case of success, + ## -1 in case of error ( the "errno" variable will contain the + ## specific error code ) The "op" parameter is one of the EPOLL_CTL_* + ## constants defined above. The "fd" parameter is the target of the + ## operation. The "event" parameter describes which events the caller + ## is interested in and any associated user data. proc epoll_wait*(epfd: cint; events: ptr EpollEvent; maxevents: cint; timeout: cint): cint {.importc: "epoll_wait", header: "".} ## Wait for events on an epoll instance "epfd". Returns the number of - ## triggered events returned in "events" buffer. Or -1 in case of - ## error with the "errno" variable set to the specific error code. The - ## "events" parameter is a buffer that will contain triggered - ## events. The "maxevents" is the maximum number of events to be - ## returned ( usually size of "events" ). The "timeout" parameter - ## specifies the maximum wait time in milliseconds (-1 == infinite). + ## triggered events returned in "events" buffer. Or -1 in case of + ## error with the "errno" variable set to the specific error code. The + ## "events" parameter is a buffer that will contain triggered + ## events. The "maxevents" is the maximum number of events to be + ## returned ( usually size of "events" ). The "timeout" parameter + ## specifies the maximum wait time in milliseconds (-1 == infinite). ## - ## This function is a cancellation point and therefore not marked with - ## __THROW. + ## This function is a cancellation point and therefore not marked with + ## __THROW. #proc epoll_pwait*(epfd: cint; events: ptr EpollEvent; maxevents: cint; # timeout: cint; ss: ptr sigset_t): cint {. # importc: "epoll_pwait", header: "".} # Same as epoll_wait, but the thread's signal mask is temporarily -# and atomically replaced with the one provided as parameter. +# and atomically replaced with the one provided as parameter. # -# This function is a cancellation point and therefore not marked with -# __THROW. +# This function is a cancellation point and therefore not marked with +# __THROW. diff --git a/lib/posix/inotify.nim b/lib/posix/inotify.nim index 109d3680e..f88e48a2d 100644 --- a/lib/posix/inotify.nim +++ b/lib/posix/inotify.nim @@ -7,94 +7,66 @@ # distribution, for details about the copyright. # -when defined(nimPreviewSlimSystem): - import std/syncio +{.deadCodeElim: on.} # dce option deprecated # Get the platform-dependent flags. # Structure describing an inotify event. type - InotifyEvent* {.pure, final, importc: "struct inotify_event", - header: "".} = object ## An Inotify event. - wd* {.importc: "wd".}: FileHandle ## Watch descriptor. - mask* {.importc: "mask".}: uint32 ## Watch mask. - cookie* {.importc: "cookie".}: uint32 ## Cookie to synchronize two events. - len* {.importc: "len".}: uint32 ## Length (including NULs) of name. - name* {.importc: "name".}: char ## Name. + InotifyEvent*{.pure, final, importc: "struct inotify_event", + header: "".} = object + wd*{.importc: "wd".}: cint # Watch descriptor. + mask*{.importc: "mask".}: uint32 # Watch mask. + cookie*{.importc: "cookie".}: uint32 # Cookie to synchronize two events. + len*{.importc: "len".}: uint32 # Length (including NULs) of name. + name*{.importc: "name".}: char # Name. # Supported events suitable for MASK parameter of INOTIFY_ADD_WATCH. const - IN_ACCESS* = 0x00000001 ## File was accessed. - IN_MODIFY* = 0x00000002 ## File was modified. - IN_ATTRIB* = 0x00000004 ## Metadata changed. - IN_CLOSE_WRITE* = 0x00000008 ## Writtable file was closed. - IN_CLOSE_NOWRITE* = 0x00000010 ## Unwrittable file closed. - IN_CLOSE* = (IN_CLOSE_WRITE or IN_CLOSE_NOWRITE) ## Close. - IN_OPEN* = 0x00000020 ## File was opened. - IN_MOVED_FROM* = 0x00000040 ## File was moved from X. - IN_MOVED_TO* = 0x00000080 ## File was moved to Y. - IN_MOVE* = (IN_MOVED_FROM or IN_MOVED_TO) ## Moves. - IN_CREATE* = 0x00000100 ## Subfile was created. - IN_DELETE* = 0x00000200 ## Subfile was deleted. - IN_DELETE_SELF* = 0x00000400 ## Self was deleted. - IN_MOVE_SELF* = 0x00000800 ## Self was moved. - + IN_ACCESS* = 0x00000001 # File was accessed. + IN_MODIFY* = 0x00000002 # File was modified. + IN_ATTRIB* = 0x00000004 # Metadata changed. + IN_CLOSE_WRITE* = 0x00000008 # Writtable file was closed. + IN_CLOSE_NOWRITE* = 0x00000010 # Unwrittable file closed. + IN_CLOSE* = (IN_CLOSE_WRITE or IN_CLOSE_NOWRITE) # Close. + IN_OPEN* = 0x00000020 # File was opened. + IN_MOVED_FROM* = 0x00000040 # File was moved from X. + IN_MOVED_TO* = 0x00000080 # File was moved to Y. + IN_MOVE* = (IN_MOVED_FROM or IN_MOVED_TO) # Moves. + IN_CREATE* = 0x00000100 # Subfile was created. + IN_DELETE* = 0x00000200 # Subfile was deleted. + IN_DELETE_SELF* = 0x00000400 # Self was deleted. + IN_MOVE_SELF* = 0x00000800 # Self was moved. # Events sent by the kernel. const - IN_UNMOUNT* = 0x00002000 ## Backing fs was unmounted. - IN_Q_OVERFLOW* = 0x00004000 ## Event queued overflowed. - IN_IGNORED* = 0x00008000 ## File was ignored. - + IN_UNMOUNT* = 0x00002000 # Backing fs was unmounted. + IN_Q_OVERFLOW* = 0x00004000 # Event queued overflowed. + IN_IGNORED* = 0x00008000 # File was ignored. # Special flags. const - IN_ONLYDIR* = 0x01000000 ## Only watch the path if it is a directory. - IN_DONT_FOLLOW* = 0x02000000 ## Do not follow a sym link. - IN_EXCL_UNLINK* = 0x04000000 ## Exclude events on unlinked objects. - IN_MASK_ADD* = 0x20000000 ## Add to the mask of an already existing watch. - IN_ISDIR* = 0x40000000 ## Event occurred against dir. - IN_ONESHOT* = 0x80000000 ## Only send event once. - + IN_ONLYDIR* = 0x01000000 # Only watch the path if it is a + # directory. + IN_DONT_FOLLOW* = 0x02000000 # Do not follow a sym link. + IN_EXCL_UNLINK* = 0x04000000 # Exclude events on unlinked + # objects. + IN_MASK_ADD* = 0x20000000 # Add to the mask of an already + # existing watch. + IN_ISDIR* = 0x40000000 # Event occurred against dir. + IN_ONESHOT* = 0x80000000 # Only send event once. # All events which a program can wait on. const IN_ALL_EVENTS* = (IN_ACCESS or IN_MODIFY or IN_ATTRIB or IN_CLOSE_WRITE or IN_CLOSE_NOWRITE or IN_OPEN or IN_MOVED_FROM or IN_MOVED_TO or IN_CREATE or IN_DELETE or IN_DELETE_SELF or IN_MOVE_SELF) - - -proc inotify_init*(): FileHandle {.cdecl, importc: "inotify_init", +# Create and initialize inotify instance. +proc inotify_init*(): cint{.cdecl, importc: "inotify_init", + header: "".} +# Create and initialize inotify instance. +proc inotify_init1*(flags: cint): cint{.cdecl, importc: "inotify_init1", header: "".} - ## Create and initialize inotify instance. - -proc inotify_init1*(flags: cint): FileHandle {.cdecl, importc: "inotify_init1", - header: "".} - ## Create and initialize inotify instance. - -proc inotify_add_watch*(fd: cint; name: cstring; mask: uint32): cint {.cdecl, - importc: "inotify_add_watch", header: "".} - ## Add watch of object NAME to inotify instance FD. Notify about events specified by MASK. - -proc inotify_rm_watch*(fd: cint; wd: cint): cint {.cdecl, +# Add watch of object NAME to inotify instance FD. Notify about +# events specified by MASK. +proc inotify_add_watch*(fd: cint; name: cstring; mask: uint32): cint{. + cdecl, importc: "inotify_add_watch", header: "".} +# Remove the watch specified by WD from the inotify instance FD. +proc inotify_rm_watch*(fd: cint; wd: cint): cint{.cdecl, importc: "inotify_rm_watch", header: "".} - ## Remove the watch specified by WD from the inotify instance FD. - -iterator inotify_events*(evs: pointer, n: int): ptr InotifyEvent = - ## Abstract the packed buffer interface to yield event object pointers. - ## ```Nim - ## var evs = newSeq[byte](8192) # Already did inotify_init+add_watch - ## while (let n = read(fd, evs[0].addr, 8192); n) > 0: # read forever - ## for e in inotify_events(evs[0].addr, n): echo e[].len # echo name lens - ## ``` - var ev: ptr InotifyEvent = cast[ptr InotifyEvent](evs) - var n = n - while n > 0: - yield ev - let sz = InotifyEvent.sizeof + int(ev[].len) - n -= sz - ev = cast[ptr InotifyEvent](cast[uint](ev) + uint(sz)) - -runnableExamples: - when defined(linux): - let inoty: FileHandle = inotify_init() ## Create 1 Inotify. - doAssert inoty >= 0 ## Check for errors (FileHandle is alias to cint). - let watchdoge: cint = inotify_add_watch(inoty, ".", IN_ALL_EVENTS) ## Add directory to watchdog. - doAssert watchdoge >= 0 ## Check for errors. - doAssert inotify_rm_watch(inoty, watchdoge) >= 0 ## Remove directory from the watchdog diff --git a/lib/posix/kqueue.nim b/lib/posix/kqueue.nim index c83ae33ea..18b47f5d5 100644 --- a/lib/posix/kqueue.nim +++ b/lib/posix/kqueue.nim @@ -153,7 +153,7 @@ proc kevent*(kqFD: cint, changelist: ptr KEvent, nchanges: cint, eventlist: ptr KEvent, nevents: cint, timeout: ptr Timespec): cint {.importc: "kevent", header: "".} - ## Manipulates queue for given `kqFD` descriptor. + ## Manipulates queue for given ``kqFD`` descriptor. proc EV_SET*(event: ptr KEvent, ident: uint, filter: cshort, flags: cushort, fflags: cuint, data: int, udata: pointer) diff --git a/lib/posix/linux.nim b/lib/posix/linux.nim index 9a5e9f062..25c7c7979 100644 --- a/lib/posix/linux.nim +++ b/lib/posix/linux.nim @@ -1,37 +1,28 @@ +{.deadCodeElim: on.} # dce option deprecated + import posix -## Flags of `clone` syscall. -## See `clone syscall manual -## `_ for more information. const - CSIGNAL* = 0x000000FF'i32 - CLONE_VM* = 0x00000100'i32 - CLONE_FS* = 0x00000200'i32 - CLONE_FILES* = 0x00000400'i32 - CLONE_SIGHAND* = 0x00000800'i32 - CLONE_PIDFD* = 0x00001000'i32 - CLONE_PTRACE* = 0x00002000'i32 - CLONE_VFORK* = 0x00004000'i32 - CLONE_PARENT* = 0x00008000'i32 - CLONE_THREAD* = 0x00010000'i32 - CLONE_NEWNS* = 0x00020000'i32 - CLONE_SYSVSEM* = 0x00040000'i32 - CLONE_SETTLS* = 0x00080000'i32 - CLONE_PARENT_SETTID* = 0x00100000'i32 - CLONE_CHILD_CLEARTID* = 0x00200000'i32 - CLONE_DETACHED* = 0x00400000'i32 - CLONE_UNTRACED* = 0x00800000'i32 - CLONE_CHILD_SETTID* = 0x01000000'i32 - CLONE_NEWCGROUP* = 0x02000000'i32 - CLONE_NEWUTS* = 0x04000000'i32 - CLONE_NEWIPC* = 0x08000000'i32 - CLONE_NEWUSER* = 0x10000000'i32 - CLONE_NEWPID* = 0x20000000'i32 - CLONE_NEWNET* = 0x40000000'i32 - CLONE_IO* = 0x80000000'i32 + CSIGNAL* = 0x000000FF + CLONE_VM* = 0x00000100 + CLONE_FS* = 0x00000200 + CLONE_FILES* = 0x00000400 + CLONE_SIGHAND* = 0x00000800 + CLONE_PTRACE* = 0x00002000 + CLONE_VFORK* = 0x00004000 + CLONE_PARENT* = 0x00008000 + CLONE_THREAD* = 0x00010000 + CLONE_NEWNS* = 0x00020000 + CLONE_SYSVSEM* = 0x00040000 + CLONE_SETTLS* = 0x00080000 + CLONE_PARENT_SETTID* = 0x00100000 + CLONE_CHILD_CLEARTID* = 0x00200000 + CLONE_DETACHED* = 0x00400000 + CLONE_UNTRACED* = 0x00800000 + CLONE_CHILD_SETTID* = 0x01000000 + CLONE_STOPPED* = 0x02000000 - -# fn should be of type proc (a2: pointer) {.cdecl.} +# fn should be of type proc (a2: pointer): void {.cdecl.} proc clone*(fn: pointer; child_stack: pointer; flags: cint; arg: pointer; ptid: ptr Pid; tls: pointer; ctid: ptr Pid): cint {.importc, header: "".} diff --git a/lib/posix/posix.nim b/lib/posix/posix.nim index 12fc8fd57..f69d42cdd 100644 --- a/lib/posix/posix.nim +++ b/lib/posix/posix.nim @@ -27,19 +27,17 @@ ## the \`identifier\` notation is used. ## ## This library relies on the header files of your C compiler. The -## resulting C code will just `#include ` and *not* define the +## resulting C code will just ``#include `` and *not* define the ## symbols declared here. # Dead code elimination ensures that we don't accidentally generate #includes # for files that might not exist on a specific platform! The user will get an # error only if they actually try to use the missing declaration +{.deadCodeElim: on.} # dce option deprecated when defined(nimHasStyleChecks): {.push styleChecks: off.} -when defined(nimPreviewSlimSystem): - import std/syncio - # TODO these constants don't seem to be fetched from a header file for unknown # platforms - where do they come from and why are they here? when false: @@ -91,10 +89,10 @@ const type Sighandler = proc (a: cint) {.noconv.} const StatHasNanoseconds* = defined(linux) or defined(freebsd) or - defined(osx) or defined(openbsd) or defined(dragonfly) or defined(haiku) ## \ + defined(osx) or defined(openbsd) or defined(dragonfly) ## \ ## Boolean flag that indicates if the system supports nanosecond time - ## resolution in the fields of `Stat`. Note that the nanosecond based fields - ## (`Stat.st_atim`, `Stat.st_mtim` and `Stat.st_ctim`) can be accessed + ## resolution in the fields of ``Stat``. Note that the nanosecond based fields + ## (``Stat.st_atim``, ``Stat.st_mtim`` and ``Stat.st_ctim``) can be accessed ## without checking this flag, because this module defines fallback procs ## when they are not available. @@ -108,8 +106,6 @@ elif (defined(macos) or defined(macosx) or defined(bsd)) and defined(cpu64): include posix_macos_amd64 elif defined(nintendoswitch): include posix_nintendoswitch -elif defined(haiku): - include posix_haiku else: include posix_other @@ -154,13 +150,11 @@ proc htons*(a1: uint16): uint16 {.importc, header: "".} proc ntohl*(a1: uint32): uint32 {.importc, header: "".} proc ntohs*(a1: uint16): uint16 {.importc, header: "".} -when not defined(zephyr): - proc inet_addr*(a1: cstring): InAddrT {.importc, header: "".} - proc inet_ntoa*(a1: InAddr): cstring {.importc, header: "".} - -proc inet_ntop*(a1: cint, a2: pointer | ptr InAddr | ptr In6Addr, a3: cstring, a4: int32): cstring {. +proc inet_addr*(a1: cstring): InAddrT {.importc, header: "".} +proc inet_ntoa*(a1: InAddr): cstring {.importc, header: "".} +proc inet_ntop*(a1: cint, a2: pointer, a3: cstring, a4: int32): cstring {. importc:"(char *)$1", header: "".} -proc inet_pton*(a1: cint, a2: cstring, a3: pointer | ptr InAddr | ptr In6Addr): cint {. +proc inet_pton*(a1: cint, a2: cstring, a3: pointer): cint {. importc, header: "".} var @@ -188,38 +182,13 @@ proc dlsym*(a1: pointer, a2: cstring): pointer {.importc, header: "", s proc creat*(a1: cstring, a2: Mode): cint {.importc, header: "", sideEffect.} proc fcntl*(a1: cint | SocketHandle, a2: cint): cint {.varargs, importc, header: "", sideEffect.} -proc openImpl(a1: cstring, a2: cint): cint {.varargs, importc: "open", header: "", sideEffect.} -proc open*(a1: cstring, a2: cint, mode: Mode | cint = 0.Mode): cint {.inline.} = - # prevents bug #17888 - openImpl(a1, a2, mode) - +proc open*(a1: cstring, a2: cint): cint {.varargs, importc, header: "", sideEffect.} proc posix_fadvise*(a1: cint, a2, a3: Off, a4: cint): cint {. importc, header: "".} +proc posix_fallocate*(a1: cint, a2, a3: Off): cint {. + importc, header: "".} -proc ftruncate*(a1: cint, a2: Off): cint {.importc, header: "".} -when defined(osx): # 2001 POSIX evidently does not concern Apple - type FStore {.importc: "fstore_t", header: "", bycopy.} = object - fst_flags: uint32 ## IN: flags word - fst_posmode: cint ## IN: indicates offset field - fst_offset, ## IN: start of the region - fst_length, ## IN: size of the region - fst_bytesalloc: Off ## OUT: number of bytes allocated - var F_PEOFPOSMODE {.importc, header: "".}: cint - var F_ALLOCATEALL {.importc, header: "".}: uint32 - var F_PREALLOCATE {.importc, header: "".}: cint - proc posix_fallocate*(a1: cint, a2, a3: Off): cint = - var fst = FStore(fst_flags: F_ALLOCATEALL, fst_posmode: F_PEOFPOSMODE, - fst_offset: a2, fst_length: a3) - # Must also call ftruncate to match what POSIX does. Unlike posix_fallocate, - # this can shrink files. Could guard w/getFileSize, but caller likely knows - # present size & has no good reason to call this unless it is growing. - if fcntl(a1, F_PREALLOCATE, fst.addr) != cint(-1): ftruncate(a1, a2 + a3) - else: cint(-1) -else: - proc posix_fallocate*(a1: cint, a2, a3: Off): cint {. - importc, header: "".} - -when not defined(haiku) and not defined(openbsd): +when not defined(haiku) and not defined(OpenBSD): proc fmtmsg*(a1: int, a2: cstring, a3: cint, a4, a5, a6: cstring): cint {.importc, header: "".} @@ -270,52 +239,26 @@ proc setlocale*(a1: cint, a2: cstring): cstring {. proc strfmon*(a1: cstring, a2: int, a3: cstring): int {.varargs, importc, header: "".} -when not (defined(nintendoswitch) or defined(macos) or defined(macosx)): - proc mq_notify*(mqdes: Mqd, event: ptr SigEvent): cint {. +when not defined(nintendoswitch): + proc mq_close*(a1: Mqd): cint {.importc, header: "".} + proc mq_getattr*(a1: Mqd, a2: ptr MqAttr): cint {. importc, header: "".} - - proc mq_open*(name: cstring, flags: cint): Mqd {. + proc mq_notify*(a1: Mqd, a2: ptr SigEvent): cint {. + importc, header: "".} + proc mq_open*(a1: cstring, a2: cint): Mqd {. varargs, importc, header: "".} - - proc mq_close*(mqdes: Mqd): cint {.importc, header: "".} - - proc mq_receive*( - mqdes: Mqd, - buffer: cstring, - length: csize_t, - priority: var cuint - ): int {.importc, header: "".} - - proc mq_timedreceive*( - mqdes: Mqd, - buffer: cstring, - length: csize_t, - priority: cuint, - timeout: ptr Timespec - ): int {.importc, header: "".} - - proc mq_send*( - mqdes: Mqd, - buffer: cstring, - length: csize_t, - priority: cuint - ): cint {.importc, header: "".} - - proc mq_timedsend*( - mqdes: Mqd, - buffer: cstring, - length: csize_t, - priority: cuint, - timeout: ptr Timespec - ): cint {.importc, header: "".} - - proc mq_getattr*(mqdes: Mqd, attribute: ptr MqAttr): cint {. + proc mq_receive*(a1: Mqd, a2: cstring, a3: int, a4: var int): int {. + importc, header: "".} + proc mq_send*(a1: Mqd, a2: cstring, a3: int, a4: int): cint {. + importc, header: "".} + proc mq_setattr*(a1: Mqd, a2, a3: ptr MqAttr): cint {. importc, header: "".} - proc mq_setattr*(mqdes: Mqd, newAttribute, oldAttribute: ptr MqAttr): cint {. - importc, header: "".} - - proc mq_unlink*(mqdes: cstring): cint {.importc, header: "".} + proc mq_timedreceive*(a1: Mqd, a2: cstring, a3: int, a4: int, + a5: ptr Timespec): int {.importc, header: "".} + proc mq_timedsend*(a1: Mqd, a2: cstring, a3: int, a4: int, + a5: ptr Timespec): cint {.importc, header: "".} + proc mq_unlink*(a1: cstring): cint {.importc, header: "".} proc getpwnam*(a1: cstring): ptr Passwd {.importc, header: "".} @@ -503,7 +446,7 @@ proc pthread_spin_unlock*(a1: ptr Pthread_spinlock): cint {. proc pthread_testcancel*() {.importc, header: "".} -proc exitnow*(code: int) {.importc: "_exit", header: "".} +proc exitnow*(code: int): void {.importc: "_exit", header: "".} proc access*(a1: cstring, a2: cint): cint {.importc, header: "".} proc alarm*(a1: cint): cint {.importc, header: "".} proc chdir*(a1: cstring): cint {.importc, header: "".} @@ -532,6 +475,7 @@ proc fpathconf*(a1, a2: cint): int {.importc, header: "".} proc fsync*(a1: cint): cint {.importc, header: "".} ## synchronize a file's buffer cache to the storage device +proc ftruncate*(a1: cint, a2: Off): cint {.importc, header: "".} proc getcwd*(a1: cstring, a2: int): cstring {.importc, header: "", sideEffect.} proc getuid*(): Uid {.importc, header: "", sideEffect.} ## returns the real user ID of the calling process @@ -584,8 +528,7 @@ proc pread*(a1: cint, a2: pointer, a3: int, a4: Off): int {. proc pwrite*(a1: cint, a2: pointer, a3: int, a4: Off): int {. importc, header: "".} proc read*(a1: cint, a2: pointer, a3: int): int {.importc, header: "".} -when not defined(nintendoswitch): - proc readlink*(a1, a2: cstring, a3: int): int {.importc, header: "".} +proc readlink*(a1, a2: cstring, a3: int): int {.importc, header: "".} proc ioctl*(f: FileHandle, device: uint): int {.importc: "ioctl", header: "", varargs, tags: [WriteIOEffect].} ## A system call for device-specific input/output operations and other @@ -604,10 +547,7 @@ proc setsid*(): Pid {.importc, header: "".} proc setuid*(a1: Uid): cint {.importc, header: "".} proc sleep*(a1: cint): cint {.importc, header: "".} proc swab*(a1, a2: pointer, a3: int) {.importc, header: "".} -when not defined(nintendoswitch): - proc symlink*(a1, a2: cstring): cint {.importc, header: "".} -else: - proc symlink*(a1, a2: cstring): cint = -1 +proc symlink*(a1, a2: cstring): cint {.importc, header: "".} proc sync*() {.importc, header: "".} proc sysconf*(a1: cint): int {.importc, header: "".} proc tcgetpgrp*(a1: cint): Pid {.importc, header: "".} @@ -645,8 +585,6 @@ proc fstatvfs*(a1: cint, a2: var Statvfs): cint {. importc, header: "".} proc chmod*(a1: cstring, a2: Mode): cint {.importc, header: "", sideEffect.} -when defined(osx) or defined(freebsd): - proc lchmod*(a1: cstring, a2: Mode): cint {.importc, header: "", sideEffect.} proc fchmod*(a1: cint, a2: Mode): cint {.importc, header: "", sideEffect.} proc fstat*(a1: cint, a2: var Stat): cint {.importc, header: "", sideEffect.} proc lstat*(a1: cstring, a2: var Stat): cint {.importc, header: "", sideEffect.} @@ -699,8 +637,7 @@ proc posix_madvise*(a1: pointer, a2: int, a3: cint): cint {. importc, header: "".} proc posix_mem_offset*(a1: pointer, a2: int, a3: var Off, a4: var int, a5: var cint): cint {.importc, header: "".} -when not (defined(linux) and defined(amd64)) and not defined(nintendoswitch) and - not defined(haiku): +when not (defined(linux) and defined(amd64)) and not defined(nintendoswitch): proc posix_typed_mem_get_info*(a1: cint, a2: var Posix_typed_mem_info): cint {.importc, header: "".} proc posix_typed_mem_open*(a1: cstring, a2, a3: cint): cint {. @@ -825,13 +762,6 @@ else: proc sigtimedwait*(a1: var Sigset, a2: var SigInfo, a3: var Timespec): cint {.importc, header: "".} -when defined(sunos) or defined(solaris): - # The following compile time flag is needed on Illumos/Solaris to use the POSIX - # `sigwait` implementation. See the documentation here: - # https://docs.oracle.com/cd/E19455-01/806-5257/6je9h033k/index.html - # https://www.illumos.org/man/2/sigwait - {.passc: "-D_POSIX_PTHREAD_SEMANTICS".} - proc sigwait*(a1: var Sigset, a2: var cint): cint {. importc, header: "".} proc sigwaitinfo*(a1: var Sigset, a2: var SigInfo): cint {. @@ -944,9 +874,15 @@ proc CMSG_NXTHDR*(mhdr: ptr Tmsghdr, cmsg: ptr Tcmsghdr): ptr Tcmsghdr {. proc CMSG_FIRSTHDR*(mhdr: ptr Tmsghdr): ptr Tcmsghdr {. importc, header: "".} +proc CMSG_SPACE*(len: csize): csize {. + importc, header: "", deprecated: "argument `len` should be of type `csize_t`".} + proc CMSG_SPACE*(len: csize_t): csize_t {. importc, header: "".} +proc CMSG_LEN*(len: csize): csize {. + importc, header: "", deprecated: "argument `len` should be of type `csize_t`".} + proc CMSG_LEN*(len: csize_t): csize_t {. importc, header: "".} @@ -958,13 +894,9 @@ proc `==`*(x, y: SocketHandle): bool {.borrow.} proc accept*(a1: SocketHandle, a2: ptr SockAddr, a3: ptr SockLen): SocketHandle {. importc, header: "", sideEffect.} -when defined(linux) or defined(bsd): - proc accept4*(a1: SocketHandle, a2: ptr SockAddr, a3: ptr SockLen, - flags: cint): SocketHandle {.importc, header: "".} - proc bindSocket*(a1: SocketHandle, a2: ptr SockAddr, a3: SockLen): cint {. importc: "bind", header: "".} - ## is Posix's `bind`, because `bind` is a reserved word + ## is Posix's ``bind``, because ``bind`` is a reserved word proc connect*(a1: SocketHandle, a2: ptr SockAddr, a3: SockLen): cint {. importc, header: "".} @@ -1024,15 +956,9 @@ proc IN6_IS_ADDR_LINKLOCAL* (a1: ptr In6Addr): cint {. proc IN6_IS_ADDR_SITELOCAL* (a1: ptr In6Addr): cint {. importc, header: "".} ## Unicast site-local address. -when defined(lwip): - proc IN6_IS_ADDR_V4MAPPED*(ipv6_address: ptr In6Addr): cint = - var bits32: ptr array[4, uint32] = cast[ptr array[4, uint32]](ipv6_address) - return (bits32[1] == 0'u32 and bits32[2] == htonl(0x0000FFFF)).cint -else: - proc IN6_IS_ADDR_V4MAPPED* (a1: ptr In6Addr): cint {. - importc, header: "".} - ## IPv4 mapped address. - +proc IN6_IS_ADDR_V4MAPPED* (a1: ptr In6Addr): cint {. + importc, header: "".} + ## IPv4 mapped address. proc IN6_IS_ADDR_V4COMPAT* (a1: ptr In6Addr): cint {. importc, header: "".} ## IPv4-compatible address. @@ -1056,7 +982,7 @@ proc endhostent*() {.importc, header: "".} proc endnetent*() {.importc, header: "".} proc endprotoent*() {.importc, header: "".} proc endservent*() {.importc, header: "".} -proc freeAddrInfo*(a1: ptr AddrInfo) {.importc: "freeaddrinfo", header: "".} +proc freeaddrinfo*(a1: ptr AddrInfo) {.importc, header: "".} proc gai_strerror*(a1: cint): cstring {.importc:"(char *)$1", header: "".} @@ -1094,9 +1020,8 @@ proc setnetent*(a1: cint) {.importc, header: "".} proc setprotoent*(a1: cint) {.importc, header: "".} proc setservent*(a1: cint) {.importc, header: "".} -when not defined(lwip): - proc poll*(a1: ptr TPollfd, a2: Tnfds, a3: int): cint {. - importc, header: "", sideEffect.} +proc poll*(a1: ptr TPollfd, a2: Tnfds, a3: int): cint {. + importc, header: "", sideEffect.} proc realpath*(name, resolved: cstring): cstring {. importc: "realpath", header: "".} @@ -1104,25 +1029,11 @@ proc realpath*(name, resolved: cstring): cstring {. proc mkstemp*(tmpl: cstring): cint {.importc, header: "", sideEffect.} ## Creates a unique temporary file. ## - ## .. warning:: The `tmpl` argument is written to by `mkstemp` and thus - ## can't be a string literal. If in doubt make a copy of the cstring before - ## passing it in. - -proc mkstemps*(tmpl: cstring, suffixlen: int): cint {.importc, header: "", sideEffect.} - ## Creates a unique temporary file. - ## - ## .. warning:: The `tmpl` argument is written to by `mkstemps` and thus - ## can't be a string literal. If in doubt make a copy of the cstring before - ## passing it in. + ## **Warning**: The `tmpl` argument is written to by `mkstemp` and thus + ## can't be a string literal. If in doubt copy the string before passing it. proc mkdtemp*(tmpl: cstring): pointer {.importc, header: "", sideEffect.} -when defined(linux) or defined(bsd) or defined(osx): - proc mkostemp*(tmpl: cstring, oflags: cint): cint {.importc, header: "", sideEffect.} - proc mkostemps*(tmpl: cstring, suffixlen: cint, oflags: cint): cint {.importc, header: "", sideEffect.} - - proc posix_memalign*(memptr: pointer, alignment: csize_t, size: csize_t): cint {.importc, header: "".} - proc utimes*(path: cstring, times: ptr array[2, Timeval]): int {. importc: "utimes", header: "", sideEffect.} ## Sets file access and modification times. @@ -1139,15 +1050,15 @@ proc handle_signal(sig: cint, handler: proc (a: cint) {.noconv.}) {.importc: "si template onSignal*(signals: varargs[cint], body: untyped) = ## Setup code to be executed when Unix signals are received. The - ## currently handled signal is injected as `sig` into the calling + ## currently handled signal is injected as ``sig`` into the calling ## scope. ## ## Example: - ## ```Nim - ## from std/posix import SIGINT, SIGTERM, onSignal + ## + ## .. code-block:: + ## from posix import SIGINT, SIGTERM, onSignal ## onSignal(SIGINT, SIGTERM): ## echo "bye from signal ", sig - ## ``` for s in signals: handle_signal(s, @@ -1164,12 +1075,12 @@ type ## The getrlimit() and setrlimit() system calls get and set resource limits respectively. ## Each resource has an associated soft and hard limit, as defined by the RLimit structure -proc setrlimit*(resource: cint, rlp: var RLimit): cint {. - importc: "setrlimit", header: "".} +proc setrlimit*(resource: cint, rlp: var RLimit): cint + {.importc: "setrlimit",header: "".} ## The setrlimit() system calls sets resource limits. -proc getrlimit*(resource: cint, rlp: var RLimit): cint {. - importc: "getrlimit", header: "".} +proc getrlimit*(resource: cint, rlp: var RLimit): cint + {.importc: "getrlimit",header: "".} ## The getrlimit() system call gets resource limits. when defined(nimHasStyleChecks): diff --git a/lib/posix/posix_freertos_consts.nim b/lib/posix/posix_freertos_consts.nim deleted file mode 100644 index 0f0fc0aae..000000000 --- a/lib/posix/posix_freertos_consts.nim +++ /dev/null @@ -1,506 +0,0 @@ -# Generated by detect.nim - - - -# -var E2BIG* {.importc: "E2BIG", header: "".}: cint -var EACCES* {.importc: "EACCES", header: "".}: cint -var EADDRINUSE* {.importc: "EADDRINUSE", header: "".}: cint -var EADDRNOTAVAIL* {.importc: "EADDRNOTAVAIL", header: "".}: cint -var EAFNOSUPPORT* {.importc: "EAFNOSUPPORT", header: "".}: cint -var EAGAIN* {.importc: "EAGAIN", header: "".}: cint -var EALREADY* {.importc: "EALREADY", header: "".}: cint -var EBADF* {.importc: "EBADF", header: "".}: cint -var EBADMSG* {.importc: "EBADMSG", header: "".}: cint -var EBUSY* {.importc: "EBUSY", header: "".}: cint -var ECANCELED* {.importc: "ECANCELED", header: "".}: cint -var ECHILD* {.importc: "ECHILD", header: "".}: cint -var ECONNABORTED* {.importc: "ECONNABORTED", header: "".}: cint -var ECONNREFUSED* {.importc: "ECONNREFUSED", header: "".}: cint -var ECONNRESET* {.importc: "ECONNRESET", header: "".}: cint -var EDEADLK* {.importc: "EDEADLK", header: "".}: cint -var EDESTADDRREQ* {.importc: "EDESTADDRREQ", header: "".}: cint -var EDOM* {.importc: "EDOM", header: "".}: cint -var EDQUOT* {.importc: "EDQUOT", header: "".}: cint -var EEXIST* {.importc: "EEXIST", header: "".}: cint -var EFAULT* {.importc: "EFAULT", header: "".}: cint -var EFBIG* {.importc: "EFBIG", header: "".}: cint -var EHOSTUNREACH* {.importc: "EHOSTUNREACH", header: "".}: cint -var EIDRM* {.importc: "EIDRM", header: "".}: cint -var EILSEQ* {.importc: "EILSEQ", header: "".}: cint -var EINPROGRESS* {.importc: "EINPROGRESS", header: "".}: cint -var EINTR* {.importc: "EINTR", header: "".}: cint -var EINVAL* {.importc: "EINVAL", header: "".}: cint -var EIO* {.importc: "EIO", header: "".}: cint -var EISCONN* {.importc: "EISCONN", header: "".}: cint -var EISDIR* {.importc: "EISDIR", header: "".}: cint -var ELOOP* {.importc: "ELOOP", header: "".}: cint -var EMFILE* {.importc: "EMFILE", header: "".}: cint -var EMLINK* {.importc: "EMLINK", header: "".}: cint -var EMSGSIZE* {.importc: "EMSGSIZE", header: "".}: cint -var EMULTIHOP* {.importc: "EMULTIHOP", header: "".}: cint -var ENAMETOOLONG* {.importc: "ENAMETOOLONG", header: "".}: cint -var ENETDOWN* {.importc: "ENETDOWN", header: "".}: cint -var ENETRESET* {.importc: "ENETRESET", header: "".}: cint -var ENETUNREACH* {.importc: "ENETUNREACH", header: "".}: cint -var ENFILE* {.importc: "ENFILE", header: "".}: cint -var ENOBUFS* {.importc: "ENOBUFS", header: "".}: cint -var ENODATA* {.importc: "ENODATA", header: "".}: cint -var ENODEV* {.importc: "ENODEV", header: "".}: cint -var ENOENT* {.importc: "ENOENT", header: "".}: cint -var ENOEXEC* {.importc: "ENOEXEC", header: "".}: cint -var ENOLCK* {.importc: "ENOLCK", header: "".}: cint -var ENOLINK* {.importc: "ENOLINK", header: "".}: cint -var ENOMEM* {.importc: "ENOMEM", header: "".}: cint -var ENOMSG* {.importc: "ENOMSG", header: "".}: cint -var ENOPROTOOPT* {.importc: "ENOPROTOOPT", header: "".}: cint -var ENOSPC* {.importc: "ENOSPC", header: "".}: cint -var ENOSR* {.importc: "ENOSR", header: "".}: cint -var ENOSTR* {.importc: "ENOSTR", header: "".}: cint -var ENOSYS* {.importc: "ENOSYS", header: "".}: cint -var ENOTCONN* {.importc: "ENOTCONN", header: "".}: cint -var ENOTDIR* {.importc: "ENOTDIR", header: "".}: cint -var ENOTEMPTY* {.importc: "ENOTEMPTY", header: "".}: cint -var ENOTSOCK* {.importc: "ENOTSOCK", header: "".}: cint -var ENOTSUP* {.importc: "ENOTSUP", header: "".}: cint -var ENOTTY* {.importc: "ENOTTY", header: "".}: cint -var ENXIO* {.importc: "ENXIO", header: "".}: cint -var EOPNOTSUPP* {.importc: "EOPNOTSUPP", header: "".}: cint -var EOVERFLOW* {.importc: "EOVERFLOW", header: "".}: cint -var EPERM* {.importc: "EPERM", header: "".}: cint -var EPIPE* {.importc: "EPIPE", header: "".}: cint -var EPROTO* {.importc: "EPROTO", header: "".}: cint -var EPROTONOSUPPORT* {.importc: "EPROTONOSUPPORT", header: "".}: cint -var EPROTOTYPE* {.importc: "EPROTOTYPE", header: "".}: cint -var ERANGE* {.importc: "ERANGE", header: "".}: cint -var EROFS* {.importc: "EROFS", header: "".}: cint -var ESPIPE* {.importc: "ESPIPE", header: "".}: cint -var ESRCH* {.importc: "ESRCH", header: "".}: cint -var ESTALE* {.importc: "ESTALE", header: "".}: cint -var ETIME* {.importc: "ETIME", header: "".}: cint -var ETIMEDOUT* {.importc: "ETIMEDOUT", header: "".}: cint -var ETXTBSY* {.importc: "ETXTBSY", header: "".}: cint -var EWOULDBLOCK* {.importc: "EWOULDBLOCK", header: "".}: cint -var EXDEV* {.importc: "EXDEV", header: "".}: cint - -# -var F_GETFD* {.importc: "F_GETFD", header: "".}: cint -# var F_SETFD* {.importc: "F_SETFD", header: "".}: cint -var F_GETFL* {.importc: "F_GETFL", header: "".}: cint -var F_SETFL* {.importc: "F_SETFL", header: "".}: cint -# var F_GETLK* {.importc: "F_GETLK", header: "".}: cint -# var F_SETLK* {.importc: "F_SETLK", header: "".}: cint -# var F_SETLKW* {.importc: "F_SETLKW", header: "".}: cint -# var F_GETOWN* {.importc: "F_GETOWN", header: "".}: cint -# var F_SETOWN* {.importc: "F_SETOWN", header: "".}: cint -# var FD_CLOEXEC* {.importc: "FD_CLOEXEC", header: "".}: cint -# var F_RDLCK* {.importc: "F_RDLCK", header: "".}: cint -# var F_UNLCK* {.importc: "F_UNLCK", header: "".}: cint -# var F_WRLCK* {.importc: "F_WRLCK", header: "".}: cint -var O_CREAT* {.importc: "O_CREAT", header: "".}: cint -var O_EXCL* {.importc: "O_EXCL", header: "".}: cint -# var O_NOCTTY* {.importc: "O_NOCTTY", header: "".}: cint -var O_TRUNC* {.importc: "O_TRUNC", header: "".}: cint -var O_APPEND* {.importc: "O_APPEND", header: "".}: cint -# var O_DSYNC* {.importc: "O_DSYNC", header: "".}: cint -var O_NONBLOCK* {.importc: "O_NONBLOCK", header: "".}: cint -# var O_RSYNC* {.importc: "O_RSYNC", header: "".}: cint -# var O_SYNC* {.importc: "O_SYNC", header: "".}: cint -# var O_ACCMODE* {.importc: "O_ACCMODE", header: "".}: cint -var O_RDONLY* {.importc: "O_RDONLY", header: "".}: cint -var O_RDWR* {.importc: "O_RDWR", header: "".}: cint -var O_WRONLY* {.importc: "O_WRONLY", header: "".}: cint -# var O_CLOEXEC* {.importc: "O_CLOEXEC", header: "".}: cint - -# # -# var LC_ALL* {.importc: "LC_ALL", header: "".}: cint -# var LC_COLLATE* {.importc: "LC_COLLATE", header: "".}: cint -# var LC_CTYPE* {.importc: "LC_CTYPE", header: "".}: cint -# var LC_MESSAGES* {.importc: "LC_MESSAGES", header: "".}: cint -# var LC_MONETARY* {.importc: "LC_MONETARY", header: "".}: cint -# var LC_NUMERIC* {.importc: "LC_NUMERIC", header: "".}: cint -# var LC_TIME* {.importc: "LC_TIME", header: "".}: cint - -# -var HOST_NOT_FOUND* {.importc: "HOST_NOT_FOUND", header: "".}: cint -var NO_DATA* {.importc: "NO_DATA", header: "".}: cint -var NO_RECOVERY* {.importc: "NO_RECOVERY", header: "".}: cint -var TRY_AGAIN* {.importc: "TRY_AGAIN", header: "".}: cint -var AI_PASSIVE* {.importc: "AI_PASSIVE", header: "".}: cint -var AI_CANONNAME* {.importc: "AI_CANONNAME", header: "".}: cint -var AI_NUMERICHOST* {.importc: "AI_NUMERICHOST", header: "".}: cint -var AI_NUMERICSERV* {.importc: "AI_NUMERICSERV", header: "".}: cint -var AI_V4MAPPED* {.importc: "AI_V4MAPPED", header: "".}: cint -var AI_ALL* {.importc: "AI_ALL", header: "".}: cint -var AI_ADDRCONFIG* {.importc: "AI_ADDRCONFIG", header: "".}: cint -var NI_NOFQDN* {.importc: "NI_NOFQDN", header: "".}: cint -var NI_NUMERICHOST* {.importc: "NI_NUMERICHOST", header: "".}: cint -var NI_NAMEREQD* {.importc: "NI_NAMEREQD", header: "".}: cint -var NI_NUMERICSERV* {.importc: "NI_NUMERICSERV", header: "".}: cint -var NI_DGRAM* {.importc: "NI_DGRAM", header: "".}: cint -var EAI_AGAIN* {.importc: "EAI_AGAIN", header: "".}: cint -var EAI_BADFLAGS* {.importc: "EAI_BADFLAGS", header: "".}: cint -var EAI_FAIL* {.importc: "EAI_FAIL", header: "".}: cint -var EAI_FAMILY* {.importc: "EAI_FAMILY", header: "".}: cint -var EAI_MEMORY* {.importc: "EAI_MEMORY", header: "".}: cint -var EAI_NONAME* {.importc: "EAI_NONAME", header: "".}: cint -var EAI_SERVICE* {.importc: "EAI_SERVICE", header: "".}: cint -var EAI_SOCKTYPE* {.importc: "EAI_SOCKTYPE", header: "".}: cint - -var LWIP_DNS_API_DECLARE_H_ERRNO* {.importc: "LWIP_DNS_API_DECLARE_H_ERRNO", header: "".}: cint -var LWIP_DNS_API_DEFINE_ERRORS* {.importc: "LWIP_DNS_API_DEFINE_ERRORS", header: "".}: cint -var LWIP_DNS_API_DEFINE_FLAGS* {.importc: "LWIP_DNS_API_DEFINE_FLAGS", header: "".}: cint -var LWIP_DNS_API_DECLARE_STRUCTS* {.importc: "LWIP_DNS_API_DECLARE_STRUCTS", header: "".}: cint -var NETDB_ELEM_SIZE* {.importc: "NETDB_ELEM_SIZE", header: "".}: cint - - -# -var ENABLE_LOOPBACK* {.importc: "ENABLE_LOOPBACK", header: "".}: cint -var NETIF_MAX_HWADDR_LEN* {.importc: "NETIF_MAX_HWADDR_LEN", header: "".}: cint -var NETIF_NAMESIZE* {.importc: "NETIF_NAMESIZE", header: "".}: cint -var NETIF_FLAG_UP* {.importc: "NETIF_FLAG_UP", header: "".}: cint -var NETIF_FLAG_BROADCAST* {.importc: "NETIF_FLAG_BROADCAST", header: "".}: cint -var NETIF_FLAG_LINK_UP* {.importc: "NETIF_FLAG_LINK_UP", header: "".}: cint -var NETIF_FLAG_ETHARP* {.importc: "NETIF_FLAG_ETHARP", header: "".}: cint -var NETIF_FLAG_ETHERNET* {.importc: "NETIF_FLAG_ETHERNET", header: "".}: cint -var NETIF_FLAG_IGMP* {.importc: "NETIF_FLAG_IGMP", header: "".}: cint -var NETIF_FLAG_MLD6* {.importc: "NETIF_FLAG_MLD6", header: "".}: cint -var NETIF_FLAG_GARP* {.importc: "NETIF_FLAG_GARP", header: "".}: cint -var NETIF_CHECKSUM_GEN_IP* {.importc: "NETIF_CHECKSUM_GEN_IP", header: "".}: cint -var NETIF_CHECKSUM_GEN_UDP* {.importc: "NETIF_CHECKSUM_GEN_UDP", header: "".}: cint -var NETIF_CHECKSUM_GEN_TCP* {.importc: "NETIF_CHECKSUM_GEN_TCP", header: "".}: cint -var NETIF_CHECKSUM_GEN_ICMP* {.importc: "NETIF_CHECKSUM_GEN_ICMP", header: "".}: cint -var NETIF_CHECKSUM_GEN_ICMP6* {.importc: "NETIF_CHECKSUM_GEN_ICMP6", header: "".}: cint -var NETIF_CHECKSUM_CHECK_IP* {.importc: "NETIF_CHECKSUM_CHECK_IP", header: "".}: cint -var NETIF_CHECKSUM_CHECK_UDP* {.importc: "NETIF_CHECKSUM_CHECK_UDP", header: "".}: cint -var NETIF_CHECKSUM_CHECK_TCP* {.importc: "NETIF_CHECKSUM_CHECK_TCP", header: "".}: cint -var NETIF_CHECKSUM_CHECK_ICMP* {.importc: "NETIF_CHECKSUM_CHECK_ICMP", header: "".}: cint -var NETIF_CHECKSUM_CHECK_ICMP6* {.importc: "NETIF_CHECKSUM_CHECK_ICMP6", header: "".}: cint -var NETIF_CHECKSUM_ENABLE_ALL* {.importc: "NETIF_CHECKSUM_ENABLE_ALL", header: "".}: cint -var NETIF_CHECKSUM_DISABLE_ALL* {.importc: "NETIF_CHECKSUM_DISABLE_ALL", header: "".}: cint -var NETIF_ADDR_IDX_MAX* {.importc: "NETIF_ADDR_IDX_MAX", header: "".}: cint -var LWIP_NETIF_USE_HINTS* {.importc: "LWIP_NETIF_USE_HINTS", header: "".}: cint -var NETIF_NO_INDEX* {.importc: "NETIF_NO_INDEX", header: "".}: cint -var LWIP_NSC_NONE* {.importc: "LWIP_NSC_NONE", header: "".}: cint -var LWIP_NSC_NETIF_ADDED* {.importc: "LWIP_NSC_NETIF_ADDED", header: "".}: cint -var LWIP_NSC_NETIF_REMOVED* {.importc: "LWIP_NSC_NETIF_REMOVED", header: "".}: cint -var LWIP_NSC_LINK_CHANGED* {.importc: "LWIP_NSC_LINK_CHANGED", header: "".}: cint -var LWIP_NSC_STATUS_CHANGED* {.importc: "LWIP_NSC_STATUS_CHANGED", header: "".}: cint -var LWIP_NSC_IPV4_ADDRESS_CHANGED* {.importc: "LWIP_NSC_IPV4_ADDRESS_CHANGED", header: "".}: cint -var LWIP_NSC_IPV4_GATEWAY_CHANGED* {.importc: "LWIP_NSC_IPV4_GATEWAY_CHANGED", header: "".}: cint -var LWIP_NSC_IPV4_NETMASK_CHANGED* {.importc: "LWIP_NSC_IPV4_NETMASK_CHANGED", header: "".}: cint -var LWIP_NSC_IPV4_SETTINGS_CHANGED* {.importc: "LWIP_NSC_IPV4_SETTINGS_CHANGED", header: "".}: cint -var LWIP_NSC_IPV6_SET* {.importc: "LWIP_NSC_IPV6_SET", header: "".}: cint -var LWIP_NSC_IPV6_ADDR_STATE_CHANGED* {.importc: "LWIP_NSC_IPV6_ADDR_STATE_CHANGED", header: "".}: cint -#define NETIF_DECLARE_EXT_CALLBACK(name) - - -# -var IF_NAMESIZE* {.importc: "IF_NAMESIZE", header: "".}: cint - -# -var IPPROTO_IP* {.importc: "IPPROTO_IP", header: "".}: cint -var IPPROTO_IPV6* {.importc: "IPPROTO_IPV6", header: "".}: cint -var IPPROTO_ICMP* {.importc: "IPPROTO_ICMP", header: "".}: cint -var IPPROTO_ICMPV6* {.importc: "IPPROTO_ICMPV6", header: "".}: cint -var IPPROTO_RAW* {.importc: "IPPROTO_RAW", header: "".}: cint -var IPPROTO_TCP* {.importc: "IPPROTO_TCP", header: "".}: cint -var IPPROTO_UDP* {.importc: "IPPROTO_UDP", header: "".}: cint -var INADDR_ANY* {.importc: "INADDR_ANY", header: "".}: InAddrScalar -var INADDR_LOOPBACK* {.importc: "INADDR_LOOPBACK", header: "".}: InAddrScalar -var INADDR_BROADCAST* {.importc: "INADDR_BROADCAST", header: "".}: InAddrScalar -var INET_ADDRSTRLEN* {.importc: "INET_ADDRSTRLEN", header: "".}: cint -var INET6_ADDRSTRLEN* {.importc: "INET6_ADDRSTRLEN", header: "".}: cint -var IPV6_JOIN_GROUP* {.importc: "IPV6_JOIN_GROUP", header: "".}: cint -var IPV6_LEAVE_GROUP* {.importc: "IPV6_LEAVE_GROUP", header: "".}: cint -var IPV6_MULTICAST_HOPS* {.importc: "IPV6_MULTICAST_HOPS", header: "".}: cint -var IPV6_MULTICAST_IF* {.importc: "IPV6_MULTICAST_IF", header: "".}: cint -var IPV6_MULTICAST_LOOP* {.importc: "IPV6_MULTICAST_LOOP", header: "".}: cint -var IPV6_UNICAST_HOPS* {.importc: "IPV6_UNICAST_HOPS", header: "".}: cint -var IPV6_V6ONLY* {.importc: "IPV6_V6ONLY", header: "".}: cint - -# -const TCP_NODELAY* = 0x01 # don't delay send to coalesce packets -const TCP_KEEPALIVE* = 0x02 # send KEEPALIVE probes when idle for pcb->keep_idle milliseconds -const TCP_KEEPIDLE* = 0x03 # set pcb->keep_idle - Same as TCP_KEEPALIVE, but use seconds for get/setsockopt -const TCP_KEEPINTVL* = 0x04 # set pcb->keep_intvl - Use seconds for get/setsockopt -const TCP_KEEPCNT* = 0x05 # set pcb->keep_cnt - Use number of probes sent for get/setsockopt - -# -# var NL_SETD* {.importc: "NL_SETD", header: "".}: cint -# var NL_CAT_LOCALE* {.importc: "NL_CAT_LOCALE", header: "".}: cint - -# -# var POLLIN* {.importc: "POLLIN", header: "".}: cshort -# var POLLRDNORM* {.importc: "POLLRDNORM", header: "".}: cshort -# var POLLRDBAND* {.importc: "POLLRDBAND", header: "".}: cshort -# var POLLPRI* {.importc: "POLLPRI", header: "".}: cshort -# var POLLOUT* {.importc: "POLLOUT", header: "".}: cshort -# var POLLWRNORM* {.importc: "POLLWRNORM", header: "".}: cshort -# var POLLWRBAND* {.importc: "POLLWRBAND", header: "".}: cshort -# var POLLERR* {.importc: "POLLERR", header: "".}: cshort -# var POLLHUP* {.importc: "POLLHUP", header: "".}: cshort -# var POLLNVAL* {.importc: "POLLNVAL", header: "".}: cshort - -# -var PTHREAD_STACK_MIN* {.importc: "PTHREAD_STACK_MIN", header: "".}: cint -# var PTHREAD_BARRIER_SERIAL_THREAD* {.importc: "PTHREAD_BARRIER_SERIAL_THREAD", header: "".}: cint -# var PTHREAD_CANCEL_ASYNCHRONOUS* {.importc: "PTHREAD_CANCEL_ASYNCHRONOUS", header: "".}: cint -# var PTHREAD_CANCEL_ENABLE* {.importc: "PTHREAD_CANCEL_ENABLE", header: "".}: cint -# var PTHREAD_CANCEL_DEFERRED* {.importc: "PTHREAD_CANCEL_DEFERRED", header: "".}: cint -# var PTHREAD_CANCEL_DISABLE* {.importc: "PTHREAD_CANCEL_DISABLE", header: "".}: cint -# var PTHREAD_CREATE_DETACHED* {.importc: "PTHREAD_CREATE_DETACHED", header: "".}: cint -# var PTHREAD_CREATE_JOINABLE* {.importc: "PTHREAD_CREATE_JOINABLE", header: "".}: cint -# var PTHREAD_EXPLICIT_SCHED* {.importc: "PTHREAD_EXPLICIT_SCHED", header: "".}: cint -# var PTHREAD_INHERIT_SCHED* {.importc: "PTHREAD_INHERIT_SCHED", header: "".}: cint -# var PTHREAD_MUTEX_DEFAULT* {.importc: "PTHREAD_MUTEX_DEFAULT", header: "".}: cint -# var PTHREAD_MUTEX_ERRORCHECK* {.importc: "PTHREAD_MUTEX_ERRORCHECK", header: "".}: cint -# var PTHREAD_MUTEX_NORMAL* {.importc: "PTHREAD_MUTEX_NORMAL", header: "".}: cint -# var PTHREAD_MUTEX_RECURSIVE* {.importc: "PTHREAD_MUTEX_RECURSIVE", header: "".}: cint -# var PTHREAD_PRIO_INHERIT* {.importc: "PTHREAD_PRIO_INHERIT", header: "".}: cint -# var PTHREAD_PRIO_NONE* {.importc: "PTHREAD_PRIO_NONE", header: "".}: cint -# var PTHREAD_PRIO_PROTECT* {.importc: "PTHREAD_PRIO_PROTECT", header: "".}: cint -# var PTHREAD_PROCESS_SHARED* {.importc: "PTHREAD_PROCESS_SHARED", header: "".}: cint -# var PTHREAD_PROCESS_PRIVATE* {.importc: "PTHREAD_PROCESS_PRIVATE", header: "".}: cint -# var PTHREAD_SCOPE_PROCESS* {.importc: "PTHREAD_SCOPE_PROCESS", header: "".}: cint -# var PTHREAD_SCOPE_SYSTEM* {.importc: "PTHREAD_SCOPE_SYSTEM", header: "".}: cint - -# # -# var SCHED_FIFO* {.importc: "SCHED_FIFO", header: "".}: cint -# var SCHED_RR* {.importc: "SCHED_RR", header: "".}: cint -# var SCHED_SPORADIC* {.importc: "SCHED_SPORADIC", header: "".}: cint -# var SCHED_OTHER* {.importc: "SCHED_OTHER", header: "".}: cint - -# -var SEM_FAILED* {.importc: "SEM_FAILED", header: "".}: pointer - -# # -# var SIGEV_NONE* {.importc: "SIGEV_NONE", header: "".}: cint -# var SIGEV_SIGNAL* {.importc: "SIGEV_SIGNAL", header: "".}: cint -# var SIGEV_THREAD* {.importc: "SIGEV_THREAD", header: "".}: cint -# var SIGABRT* {.importc: "SIGABRT", header: "".}: cint -# var SIGALRM* {.importc: "SIGALRM", header: "".}: cint -# var SIGBUS* {.importc: "SIGBUS", header: "".}: cint -# var SIGCHLD* {.importc: "SIGCHLD", header: "".}: cint -# var SIGCONT* {.importc: "SIGCONT", header: "".}: cint -# var SIGFPE* {.importc: "SIGFPE", header: "".}: cint -# var SIGHUP* {.importc: "SIGHUP", header: "".}: cint -# var SIGILL* {.importc: "SIGILL", header: "".}: cint -# var SIGINT* {.importc: "SIGINT", header: "".}: cint -# var SIGKILL* {.importc: "SIGKILL", header: "".}: cint -# var SIGPIPE* {.importc: "SIGPIPE", header: "".}: cint -# var SIGQUIT* {.importc: "SIGQUIT", header: "".}: cint -# var SIGSEGV* {.importc: "SIGSEGV", header: "".}: cint -# var SIGSTOP* {.importc: "SIGSTOP", header: "".}: cint -# var SIGTERM* {.importc: "SIGTERM", header: "".}: cint -# var SIGTSTP* {.importc: "SIGTSTP", header: "".}: cint -# var SIGTTIN* {.importc: "SIGTTIN", header: "".}: cint -# var SIGTTOU* {.importc: "SIGTTOU", header: "".}: cint -# var SIGUSR1* {.importc: "SIGUSR1", header: "".}: cint -# var SIGUSR2* {.importc: "SIGUSR2", header: "".}: cint -# var SIGPOLL* {.importc: "SIGPOLL", header: "".}: cint -# var SIGPROF* {.importc: "SIGPROF", header: "".}: cint -# var SIGSYS* {.importc: "SIGSYS", header: "".}: cint -# var SIGTRAP* {.importc: "SIGTRAP", header: "".}: cint -# var SIGURG* {.importc: "SIGURG", header: "".}: cint -# var SIGVTALRM* {.importc: "SIGVTALRM", header: "".}: cint -# var SIGXCPU* {.importc: "SIGXCPU", header: "".}: cint -# var SIGXFSZ* {.importc: "SIGXFSZ", header: "".}: cint -# var SA_NOCLDSTOP* {.importc: "SA_NOCLDSTOP", header: "".}: cint -# var SIG_BLOCK* {.importc: "SIG_BLOCK", header: "".}: cint -# var SIG_UNBLOCK* {.importc: "SIG_UNBLOCK", header: "".}: cint -# var SIG_SETMASK* {.importc: "SIG_SETMASK", header: "".}: cint -# var SA_ONSTACK* {.importc: "SA_ONSTACK", header: "".}: cint -# var SA_RESETHAND* {.importc: "SA_RESETHAND", header: "".}: cint -# var SA_RESTART* {.importc: "SA_RESTART", header: "".}: cint -# var SA_SIGINFO* {.importc: "SA_SIGINFO", header: "".}: cint -# var SA_NOCLDWAIT* {.importc: "SA_NOCLDWAIT", header: "".}: cint -# var SA_NODEFER* {.importc: "SA_NODEFER", header: "".}: cint -# var SS_ONSTACK* {.importc: "SS_ONSTACK", header: "".}: cint -# var SS_DISABLE* {.importc: "SS_DISABLE", header: "".}: cint -# var MINSIGSTKSZ* {.importc: "MINSIGSTKSZ", header: "".}: cint -# var SIGSTKSZ* {.importc: "SIGSTKSZ", header: "".}: cint -# var SIG_HOLD* {.importc: "SIG_HOLD", header: "".}: Sighandler -# var SIG_DFL* {.importc: "SIG_DFL", header: "".}: Sighandler -# var SIG_ERR* {.importc: "SIG_ERR", header: "".}: Sighandler -# var SIG_IGN* {.importc: "SIG_IGN", header: "".}: Sighandler - -# # -# var IPC_CREAT* {.importc: "IPC_CREAT", header: "".}: cint -# var IPC_EXCL* {.importc: "IPC_EXCL", header: "".}: cint -# var IPC_NOWAIT* {.importc: "IPC_NOWAIT", header: "".}: cint -# var IPC_PRIVATE* {.importc: "IPC_PRIVATE", header: "".}: cint -# var IPC_RMID* {.importc: "IPC_RMID", header: "".}: cint -# var IPC_SET* {.importc: "IPC_SET", header: "".}: cint -# var IPC_STAT* {.importc: "IPC_STAT", header: "".}: cint - -# # -# var PROT_READ* {.importc: "PROT_READ", header: "".}: cint -# var PROT_WRITE* {.importc: "PROT_WRITE", header: "".}: cint -# var PROT_EXEC* {.importc: "PROT_EXEC", header: "".}: cint -# var PROT_NONE* {.importc: "PROT_NONE", header: "".}: cint -# var MAP_ANONYMOUS* {.importc: "MAP_ANONYMOUS", header: "".}: cint -# var MAP_FIXED_NOREPLACE* {.importc: "MAP_FIXED_NOREPLACE", header: "".}: cint -# var MAP_NORESERVE* {.importc: "MAP_NORESERVE", header: "".}: cint -# var MAP_SHARED* {.importc: "MAP_SHARED", header: "".}: cint -# var MAP_PRIVATE* {.importc: "MAP_PRIVATE", header: "".}: cint -# var MAP_FIXED* {.importc: "MAP_FIXED", header: "".}: cint -# var MS_ASYNC* {.importc: "MS_ASYNC", header: "".}: cint -# var MS_SYNC* {.importc: "MS_SYNC", header: "".}: cint -# var MS_INVALIDATE* {.importc: "MS_INVALIDATE", header: "".}: cint -# var MCL_CURRENT* {.importc: "MCL_CURRENT", header: "".}: cint -# var MCL_FUTURE* {.importc: "MCL_FUTURE", header: "".}: cint -# var MAP_FAILED* {.importc: "MAP_FAILED", header: "".}: pointer -# var POSIX_MADV_NORMAL* {.importc: "POSIX_MADV_NORMAL", header: "".}: cint -# var POSIX_MADV_SEQUENTIAL* {.importc: "POSIX_MADV_SEQUENTIAL", header: "".}: cint -# var POSIX_MADV_RANDOM* {.importc: "POSIX_MADV_RANDOM", header: "".}: cint -# var POSIX_MADV_WILLNEED* {.importc: "POSIX_MADV_WILLNEED", header: "".}: cint -# var POSIX_MADV_DONTNEED* {.importc: "POSIX_MADV_DONTNEED", header: "".}: cint -# var POSIX_TYPED_MEM_ALLOCATE* {.importc: "POSIX_TYPED_MEM_ALLOCATE", header: "".}: cint -# var POSIX_TYPED_MEM_ALLOCATE_CONTIG* {.importc: "POSIX_TYPED_MEM_ALLOCATE_CONTIG", header: "".}: cint -# var POSIX_TYPED_MEM_MAP_ALLOCATABLE* {.importc: "POSIX_TYPED_MEM_MAP_ALLOCATABLE", header: "".}: cint - -# -# var RLIMIT_NOFILE* {.importc: "RLIMIT_NOFILE", header: "".}: cint - -var FD_MAX* {.importc: "CONFIG_LWIP_MAX_SOCKETS", header: "".}: cint - -# -var FD_SETSIZE* {.importc: "FD_SETSIZE", header: "".}: cint - -# -# struct msghdr->msg_flags bit field values -const MSG_TRUNC* = 0x04 -const MSG_CTRUNC* = 0x08 - -# Flags we can use with send and recv. -const MSG_PEEK* = 0x01 # Peeks at an incoming message -const MSG_WAITALL* = 0x02 # Unimplemented: Requests that the function block until the full amount of data requested can be returned -const MSG_OOB* = 0x04 # Unimplemented: Requests out-of-band data. The significance and semantics of out-of-band data are protocol-specific -const MSG_DONTWAIT* = 0x08 # Nonblocking i/o for this operation only -const MSG_MORE* = 0x10 # Sender will send more -# const MSG_NOSIGNAL* = 0x20 # Uninmplemented: Requests not to send the SIGPIPE signal if an attempt to send is made on a stream-oriented socket that is no longer connected. - -# Alternately, they can defined like this, but the above seems better when they're known/stable values: -# var MSG_TRUNC* {.importc: "MSG_TRUNC", header: "".}: cint -# var MSG_CTRUNC* {.importc: "MSG_CTRUNC", header: "".}: cint -# var MSG_DONTROUTE* {.importc: "MSG_DONTROUTE", header: "".}: cint # not defined in lwip -# var MSG_EOR* {.importc: "MSG_EOR", header: "".}: cint # not defined in lwip -# var MSG_OOB* {.importc: "MSG_OOB", header: "".}: cint - - -# var SCM_RIGHTS* {.importc: "SCM_RIGHTS", header: "".}: cint -var SO_ACCEPTCONN* {.importc: "SO_ACCEPTCONN", header: "".}: cint -var SO_BROADCAST* {.importc: "SO_BROADCAST", header: "".}: cint -var SO_DEBUG* {.importc: "SO_DEBUG", header: "".}: cint -var SO_DONTROUTE* {.importc: "SO_DONTROUTE", header: "".}: cint -var SO_ERROR* {.importc: "SO_ERROR", header: "".}: cint -var SO_KEEPALIVE* {.importc: "SO_KEEPALIVE", header: "".}: cint -var SO_LINGER* {.importc: "SO_LINGER", header: "".}: cint -var SO_OOBINLINE* {.importc: "SO_OOBINLINE", header: "".}: cint -var SO_RCVBUF* {.importc: "SO_RCVBUF", header: "".}: cint -var SO_RCVLOWAT* {.importc: "SO_RCVLOWAT", header: "".}: cint -var SO_RCVTIMEO* {.importc: "SO_RCVTIMEO", header: "".}: cint -var SO_REUSEADDR* {.importc: "SO_REUSEADDR", header: "".}: cint -var SO_SNDBUF* {.importc: "SO_SNDBUF", header: "".}: cint -var SO_SNDLOWAT* {.importc: "SO_SNDLOWAT", header: "".}: cint -var SO_SNDTIMEO* {.importc: "SO_SNDTIMEO", header: "".}: cint -var SO_TYPE* {.importc: "SO_TYPE", header: "".}: cint -var SOCK_DGRAM* {.importc: "SOCK_DGRAM", header: "".}: cint -var SOCK_RAW* {.importc: "SOCK_RAW", header: "".}: cint - -# var SOCK_SEQPACKET* {.importc: "SOCK_SEQPACKET", header: "".}: cint -const SOCK_SEQPACKET* = cint(5) - -var SOCK_STREAM* {.importc: "SOCK_STREAM", header: "".}: cint -var SOL_SOCKET* {.importc: "SOL_SOCKET", header: "".}: cint - -const SocketMaxConnections {.intdefine.}: int = 32 -var SOMAXCONN*: cint = SocketMaxConnections.cint - -var AF_INET* {.importc: "AF_INET", header: "".}: cint -var AF_INET6* {.importc: "AF_INET6", header: "".}: cint -# var AF_UNIX* {.importc: "AF_UNIX", header: "".}: cint -const AF_UNIX*: cint = 1 # for compat with Nim libraries, doesn't exist on freertos -var AF_UNSPEC* {.importc: "AF_UNSPEC", header: "".}: cint -var SHUT_RD* {.importc: "SHUT_RD", header: "".}: cint -var SHUT_RDWR* {.importc: "SHUT_RDWR", header: "".}: cint -var SHUT_WR* {.importc: "SHUT_WR", header: "".}: cint - -# # -# - -# var S_IFBLK* {.importc: "S_IFBLK", header: "".}: cint -# var S_IFCHR* {.importc: "S_IFCHR", header: "".}: cint -# var S_IFDIR* {.importc: "S_IFDIR", header: "".}: cint -# var S_IFIFO* {.importc: "S_IFIFO", header: "".}: cint -# var S_IFLNK* {.importc: "S_IFLNK", header: "".}: cint -# var S_IFMT* {.importc: "S_IFMT", header: "".}: cint -# var S_IFREG* {.importc: "S_IFREG", header: "".}: cint -# var S_IFSOCK* {.importc: "S_IFSOCK", header: "".}: cint -var S_IRGRP* {.importc: "S_IRGRP", header: "".}: cint -var S_IROTH* {.importc: "S_IROTH", header: "".}: cint -var S_IRUSR* {.importc: "S_IRUSR", header: "".}: cint -# var S_IRWXG* {.importc: "S_IRWXG", header: "".}: cint -# var S_IRWXO* {.importc: "S_IRWXO", header: "".}: cint -# var S_IRWXU* {.importc: "S_IRWXU", header: "".}: cint -# var S_ISGID* {.importc: "S_ISGID", header: "".}: cint -# var S_ISUID* {.importc: "S_ISUID", header: "".}: cint -# var S_ISVTX* {.importc: "S_ISVTX", header: "".}: cint -var S_IWGRP* {.importc: "S_IWGRP", header: "".}: cint -var S_IWOTH* {.importc: "S_IWOTH", header: "".}: cint -var S_IWUSR* {.importc: "S_IWUSR", header: "".}: cint -var S_IXGRP* {.importc: "S_IXGRP", header: "".}: cint -var S_IXOTH* {.importc: "S_IXOTH", header: "".}: cint -var S_IXUSR* {.importc: "S_IXUSR", header: "".}: cint - -# # -# var ST_RDONLY* {.importc: "ST_RDONLY", header: "".}: cint -# var ST_NOSUID* {.importc: "ST_NOSUID", header: "".}: cint - -# # -# var WNOHANG* {.importc: "WNOHANG", header: "".}: cint -# var WUNTRACED* {.importc: "WUNTRACED", header: "".}: cint -# var WEXITED* {.importc: "WEXITED", header: "".}: cint -# var WSTOPPED* {.importc: "WSTOPPED", header: "".}: cint -# var WCONTINUED* {.importc: "WCONTINUED", header: "".}: cint -# var WNOWAIT* {.importc: "WNOWAIT", header: "".}: cint -# var P_ALL* {.importc: "P_ALL", header: "".}: cint -# var P_PID* {.importc: "P_PID", header: "".}: cint -# var P_PGID* {.importc: "P_PGID", header: "".}: cint - -# # -# var POSIX_SPAWN_RESETIDS* {.importc: "POSIX_SPAWN_RESETIDS", header: "".}: cint -# var POSIX_SPAWN_SETPGROUP* {.importc: "POSIX_SPAWN_SETPGROUP", header: "".}: cint -# var POSIX_SPAWN_SETSCHEDPARAM* {.importc: "POSIX_SPAWN_SETSCHEDPARAM", header: "".}: cint -# var POSIX_SPAWN_SETSCHEDULER* {.importc: "POSIX_SPAWN_SETSCHEDULER", header: "".}: cint -# var POSIX_SPAWN_SETSIGDEF* {.importc: "POSIX_SPAWN_SETSIGDEF", header: "".}: cint -# var POSIX_SPAWN_SETSIGMASK* {.importc: "POSIX_SPAWN_SETSIGMASK", header: "".}: cint - -## -# var IOFBF* {.importc: "_IOFBF", header: "".}: cint -# var IONBF* {.importc: "_IONBF", header: "".}: cint - -# -var CLOCKS_PER_SEC* {.importc: "CLOCKS_PER_SEC", header: "".}: clong -var CLOCK_PROCESS_CPUTIME_ID* {.importc: "CLOCK_PROCESS_CPUTIME_ID", header: "".}: cint -var CLOCK_THREAD_CPUTIME_ID* {.importc: "CLOCK_THREAD_CPUTIME_ID", header: "".}: cint -var CLOCK_REALTIME* {.importc: "CLOCK_REALTIME", header: "".}: cint -var TIMER_ABSTIME* {.importc: "TIMER_ABSTIME", header: "".}: cint -var CLOCK_MONOTONIC* {.importc: "CLOCK_MONOTONIC", header: "".}: cint - -# - -const F_OK* = cint(0) -const R_OK* = cint(4) -const W_OK* = cint(2) -const X_OK* = cint(1) -const F_LOCK* = cint(1) -const F_TEST* = cint(3) -const F_TLOCK* = cint(2) -const F_ULOCK* = cint(0) - -# -const SEEK_SET* = cint(0) -const SEEK_CUR* = cint(1) -const SEEK_END* = cint(2) diff --git a/lib/posix/posix_haiku.nim b/lib/posix/posix_haiku.nim deleted file mode 100644 index 32a6d24e2..000000000 --- a/lib/posix/posix_haiku.nim +++ /dev/null @@ -1,603 +0,0 @@ -# -# -# Nim's Runtime Library -# (c) Copyright 2020 Andreas Rumpf -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# - -when defined(nimHasStyleChecks): - {.push styleChecks: off.} - -const - hasSpawnH = true # should exist for every Posix system nowadays - hasAioH = defined(linux) - -when defined(linux) and not defined(android): - # On Linux: - # timer_{create,delete,settime,gettime}, - # clock_{getcpuclockid, getres, gettime, nanosleep, settime} lives in librt - {.passl: "-lrt".} -when defined(solaris): - # On Solaris hstrerror lives in libresolv - {.passl: "-lresolv".} - -type - DIR* {.importc: "DIR", header: "", - incompleteStruct.} = object - ## A type representing a directory stream. - -type - SocketHandle* = distinct cint # The type used to represent socket descriptors - -type - Time* {.importc: "time_t", header: "".} = distinct ( - when defined(i386): - int32 - else: - int64 - ) - Timespec* {.importc: "struct timespec", - header: "", final, pure.} = object ## struct timespec - tv_sec*: Time ## Seconds. - tv_nsec*: int ## Nanoseconds. - - Dirent* {.importc: "struct dirent", - header: "", final, pure.} = object ## dirent_t struct - when defined(haiku): - d_dev*: Dev ## Device (not POSIX) - d_pdev*: Dev ## Parent device (only for queries) (not POSIX) - d_ino*: Ino ## File serial number. - when defined(dragonfly): - # DragonflyBSD doesn't have `d_reclen` field. - d_type*: uint8 - elif defined(linux) or defined(macosx) or defined(freebsd) or - defined(netbsd) or defined(openbsd) or defined(genode): - d_reclen*: cshort ## Length of this record. (not POSIX) - d_type*: int8 ## Type of file; not supported by all filesystem types. - ## (not POSIX) - when defined(linux) or defined(openbsd): - d_off*: Off ## Not an offset. Value that `telldir()` would return. - elif defined(haiku): - d_pino*: Ino ## Parent inode (only for queries) (not POSIX) - d_reclen*: cushort ## Length of this record. (not POSIX) - - when not defined(haiku): - d_name*: array[0..255, char] ## Name of entry. - else: - d_name*: UncheckedArray[char] ## Name of entry (NUL terminated). - - Tflock* {.importc: "struct flock", final, pure, - header: "".} = object ## flock type - l_type*: cshort ## Type of lock; F_RDLCK, F_WRLCK, F_UNLCK. - l_whence*: cshort ## Flag for starting offset. - l_start*: Off ## Relative offset in bytes. - l_len*: Off ## Size; if 0 then until EOF. - l_pid*: Pid ## Process ID of the process holding the lock; - ## returned with F_GETLK. - - FTW* {.importc: "struct FTW", header: "", final, pure.} = object - base*: cint - level*: cint - - Glob* {.importc: "glob_t", header: "", - final, pure.} = object ## glob_t - gl_pathc*: int ## Count of paths matched by pattern. - gl_pathv*: cstringArray ## Pointer to a list of matched pathnames. - gl_offs*: int ## Slots to reserve at the beginning of gl_pathv. - - Group* {.importc: "struct group", header: "", - final, pure.} = object ## struct group - gr_name*: cstring ## The name of the group. - gr_gid*: Gid ## Numerical group ID. - gr_mem*: cstringArray ## Pointer to a null-terminated array of character - ## pointers to member names. - - Iconv* {.importc: "iconv_t", header: "", final, pure.} = - object ## Identifies the conversion from one codeset to another. - - Lconv* {.importc: "struct lconv", header: "", final, - pure.} = object - currency_symbol*: cstring - decimal_point*: cstring - frac_digits*: char - grouping*: cstring - int_curr_symbol*: cstring - int_frac_digits*: char - int_n_cs_precedes*: char - int_n_sep_by_space*: char - int_n_sign_posn*: char - int_p_cs_precedes*: char - int_p_sep_by_space*: char - int_p_sign_posn*: char - mon_decimal_point*: cstring - mon_grouping*: cstring - mon_thousands_sep*: cstring - negative_sign*: cstring - n_cs_precedes*: char - n_sep_by_space*: char - n_sign_posn*: char - positive_sign*: cstring - p_cs_precedes*: char - p_sep_by_space*: char - p_sign_posn*: char - thousands_sep*: cstring - - Mqd* {.importc: "mqd_t", header: "", final, pure.} = object - MqAttr* {.importc: "struct mq_attr", - header: "", - final, pure.} = object ## message queue attribute - mq_flags*: int ## Message queue flags. - mq_maxmsg*: int ## Maximum number of messages. - mq_msgsize*: int ## Maximum message size. - mq_curmsgs*: int ## Number of messages currently queued. - - Passwd* {.importc: "struct passwd", header: "", - final, pure.} = object ## struct passwd - pw_name*: cstring ## User's login name. - pw_uid*: Uid ## Numerical user ID. - pw_gid*: Gid ## Numerical group ID. - pw_dir*: cstring ## Initial working directory. - pw_shell*: cstring ## Program to use as shell. - - Blkcnt* {.importc: "blkcnt_t", header: "".} = int64 - ## used for file block counts - Blksize* {.importc: "blksize_t", header: "".} = int32 - ## used for block sizes - Clock* {.importc: "clock_t", header: "".} = int32 - ClockId* {.importc: "clockid_t", header: "".} = int32 - Dev* {.importc: "dev_t", header: "".} = int32 - Fsblkcnt* {.importc: "fsblkcnt_t", header: "".} = int64 - Fsfilcnt* {.importc: "fsfilcnt_t", header: "".} = int64 - Gid* {.importc: "gid_t", header: "".} = uint32 - Id* {.importc: "id_t", header: "".} = int32 - Ino* {.importc: "ino_t", header: "".} = int64 - Key* {.importc: "key_t", header: "".} = int32 - Mode* {.importc: "mode_t", header: "".} = ( - when defined(android) or defined(macos) or defined(macosx) or - (defined(bsd) and not defined(openbsd) and not defined(netbsd)): - uint16 - else: - uint32 - ) - Nlink* {.importc: "nlink_t", header: "".} = int32 - Off* {.importc: "off_t", header: "".} = int64 - Pid* {.importc: "pid_t", header: "".} = int32 - Pthread_attr* {.importc: "pthread_attr_t", header: "".} = object - Pthread_barrier* {.importc: "pthread_barrier_t", - header: "".} = object - Pthread_barrierattr* {.importc: "pthread_barrierattr_t", - header: "".} = object - Pthread_cond* {.importc: "pthread_cond_t", header: "".} = object - Pthread_condattr* {.importc: "pthread_condattr_t", - header: "".} = object - Pthread_key* {.importc: "pthread_key_t", header: "".} = object - Pthread_mutex* {.importc: "pthread_mutex_t", header: "".} = object - Pthread_mutexattr* {.importc: "pthread_mutexattr_t", - header: "".} = object - Pthread_once* {.importc: "pthread_once_t", header: "".} = object - Pthread_rwlock* {.importc: "pthread_rwlock_t", - header: "".} = object - Pthread_rwlockattr* {.importc: "pthread_rwlockattr_t", - header: "".} = object - Pthread_spinlock* {.importc: "pthread_spinlock_t", - header: "".} = object - Pthread* {.importc: "pthread_t", header: "".} = object - Suseconds* {.importc: "suseconds_t", header: "".} = int32 - #Ttime* {.importc: "time_t", header: "".} = int - Timer* {.importc: "timer_t", header: "".} = object - Uid* {.importc: "uid_t", header: "".} = uint32 - Useconds* {.importc: "useconds_t", header: "".} = uint32 - - Utsname* {.importc: "struct utsname", - header: "", - final, pure.} = object ## struct utsname - sysname*, ## Name of this implementation of the operating system. - nodename*, ## Name of this node within the communications - ## network to which this node is attached, if any. - release*, ## Current release level of this implementation. - version*, ## Current version level of this release. - machine*: array[32, char] ## Name of the hardware type on which the - ## system is running. - - Sem* {.importc: "sem_t", header: "", final, pure.} = object - Ipc_perm* {.importc: "struct ipc_perm", - header: "", final, pure.} = object ## struct ipc_perm - uid*: Uid ## Owner's user ID. - gid*: Gid ## Owner's group ID. - cuid*: Uid ## Creator's user ID. - cgid*: Gid ## Creator's group ID. - mode*: Mode ## Read/write permission. - - Stat* {.importc: "struct stat", - header: "", final, pure.} = object ## struct stat - st_dev*: Dev ## Device ID of device containing file. - st_ino*: Ino ## File serial number. - st_mode*: Mode ## Mode of file (see below). - st_nlink*: Nlink ## Number of hard links to the file. - st_uid*: Uid ## User ID of file. - st_gid*: Gid ## Group ID of file. - st_rdev*: Dev ## Device ID (if file is character or block special). - st_size*: Off ## For regular files, the file size in bytes. - ## For symbolic links, the length in bytes of the - ## pathname contained in the symbolic link. - ## For a shared memory object, the length in bytes. - ## For a typed memory object, the length in bytes. - ## For other file types, the use of this field is - ## unspecified. - when StatHasNanoseconds: - st_atim*: Timespec ## Time of last access. - st_mtim*: Timespec ## Time of last data modification. - st_ctim*: Timespec ## Time of last status change. - else: - st_atime*: Time ## Time of last access. - st_mtime*: Time ## Time of last data modification. - st_ctime*: Time ## Time of last status change. - st_blksize*: Blksize ## A file system-specific preferred I/O block size - ## for this object. In some file system types, this - ## may vary from file to file. - st_blocks*: Blkcnt ## Number of blocks allocated for this object. - - - Statvfs* {.importc: "struct statvfs", header: "", - final, pure.} = object ## struct statvfs - f_bsize*: culong ## File system block size. - f_frsize*: culong ## Fundamental file system block size. - f_blocks*: Fsblkcnt ## Total number of blocks on file system - ## in units of f_frsize. - f_bfree*: Fsblkcnt ## Total number of free blocks. - f_bavail*: Fsblkcnt ## Number of free blocks available to - ## non-privileged process. - f_files*: Fsfilcnt ## Total number of file serial numbers. - f_ffree*: Fsfilcnt ## Total number of free file serial numbers. - f_favail*: Fsfilcnt ## Number of file serial numbers available to - ## non-privileged process. - f_fsid*: culong ## File system ID. - f_flag*: culong ## Bit mask of f_flag values. - f_namemax*: culong ## Maximum filename length. - - Tm* {.importc: "struct tm", header: "", - final, pure.} = object ## struct tm - tm_sec*: cint ## Seconds [0,60]. - tm_min*: cint ## Minutes [0,59]. - tm_hour*: cint ## Hour [0,23]. - tm_mday*: cint ## Day of month [1,31]. - tm_mon*: cint ## Month of year [0,11]. - tm_year*: cint ## Years since 1900. - tm_wday*: cint ## Day of week [0,6] (Sunday =0). - tm_yday*: cint ## Day of year [0,365]. - tm_isdst*: cint ## Daylight Savings flag. - Itimerspec* {.importc: "struct itimerspec", header: "", - final, pure.} = object ## struct itimerspec - it_interval*: Timespec ## Timer period. - it_value*: Timespec ## Timer expiration. - - Sig_atomic* {.importc: "sig_atomic_t", header: "".} = cint - ## Possibly volatile-qualified integer type of an object that can be - ## accessed as an atomic entity, even in the presence of asynchronous - ## interrupts. - Sigset* {.importc: "sigset_t", header: "".} = uint64 - - SigEvent* {.importc: "struct sigevent", - header: "", final, pure.} = object ## struct sigevent - sigev_notify*: cint ## Notification type. - sigev_signo*: cint ## Signal number. - sigev_value*: SigVal ## Signal value. - sigev_notify_function*: proc (x: SigVal) {.noconv.} ## Notification func. - sigev_notify_attributes*: ptr Pthread_attr ## Notification attributes. - - SigVal* {.importc: "union sigval", - header: "", final, pure.} = object ## struct sigval - sival_ptr*: pointer ## pointer signal value; - ## integer signal value not defined! - Sigaction* {.importc: "struct sigaction", - header: "", final, pure.} = object ## struct sigaction - sa_handler*: proc (x: cint) {.noconv.} ## Pointer to a signal-catching - ## function or one of the macros - ## SIG_IGN or SIG_DFL. - sa_mask*: Sigset ## Set of signals to be blocked during execution of - ## the signal handling function. - sa_flags*: cint ## Special flags. - sa_sigaction*: proc (x: cint, y: ptr SigInfo, z: pointer) {.noconv.} - - Stack* {.importc: "stack_t", - header: "", final, pure.} = object ## stack_t - ss_sp*: pointer ## Stack base or pointer. - ss_size*: csize_t ## Stack size. - ss_flags*: cint ## Flags. - - SigInfo* {.importc: "siginfo_t", - header: "", final, pure.} = object ## siginfo_t - si_signo*: cint ## Signal number. - si_code*: cint ## Signal code. - si_errno*: cint ## If non-zero, an errno value associated with - ## this signal, as defined in . - si_pid*: Pid ## Sending process ID. - si_uid*: Uid ## Real user ID of sending process. - si_addr*: pointer ## Address of faulting instruction. - si_status*: cint ## Exit value or signal. - si_band*: int ## Band event for SIGPOLL. - si_value*: SigVal ## Signal value. - - Nl_item* {.importc: "nl_item", header: "".} = cint - Nl_catd* {.importc: "nl_catd", header: "".} = cint - - Sched_param* {.importc: "struct sched_param", - header: "", - final, pure.} = object ## struct sched_param - sched_priority*: cint - - Timeval* {.importc: "struct timeval", header: "", - final, pure.} = object ## struct timeval - tv_sec*: Time ## Seconds. - tv_usec*: Suseconds ## Microseconds. - TFdSet* {.importc: "fd_set", header: "", - final, pure.} = object - Mcontext* {.importc: "mcontext_t", header: "", - final, pure.} = object - Ucontext* {.importc: "ucontext_t", header: "", - final, pure.} = object ## ucontext_t - uc_link*: ptr Ucontext ## Pointer to the context that is resumed - ## when this context returns. - uc_sigmask*: Sigset ## The set of signals that are blocked when this - ## context is active. - uc_stack*: Stack ## The stack used by this context. - uc_mcontext*: Mcontext ## A machine-specific representation of the saved - ## context. - -when hasAioH: - type - Taiocb* {.importc: "struct aiocb", header: "", - final, pure.} = object ## struct aiocb - aio_fildes*: cint ## File descriptor. - aio_offset*: Off ## File offset. - aio_buf*: pointer ## Location of buffer. - aio_nbytes*: int ## Length of transfer. - aio_reqprio*: cint ## Request priority offset. - aio_sigevent*: SigEvent ## Signal number and value. - aio_lio_opcode: cint ## Operation to be performed. - -when hasSpawnH: - type - Tposix_spawnattr* {.importc: "posix_spawnattr_t", - header: "", final, pure.} = object - Tposix_spawn_file_actions* {.importc: "posix_spawn_file_actions_t", - header: "", final, pure.} = object - -when defined(linux): - # from sys/un.h - const Sockaddr_un_path_length* = 108 -elif defined(haiku): - # from sys/un.h - const Sockaddr_un_path_length* = 126 -else: - # according to http://pubs.opengroup.org/onlinepubs/009604499/basedefs/sys/un.h.html - # this is >=92 - const Sockaddr_un_path_length* = 92 - -type - SockLen* {.importc: "socklen_t", header: "".} = uint32 - TSa_Family* {.importc: "sa_family_t", header: "".} = uint8 - - SockAddr* {.importc: "struct sockaddr", header: "", - pure, final.} = object ## struct sockaddr - sa_family*: TSa_Family ## Address family. - sa_data*: array[0..255, char] ## Socket address (variable-length data). - - Sockaddr_un* {.importc: "struct sockaddr_un", header: "", - pure, final.} = object ## struct sockaddr_un - sun_family*: TSa_Family ## Address family. - sun_path*: array[0..Sockaddr_un_path_length-1, char] ## Socket path - - Sockaddr_storage* {.importc: "struct sockaddr_storage", - header: "", - pure, final.} = object ## struct sockaddr_storage - ss_family*: TSa_Family ## Address family. - - Tif_nameindex* {.importc: "struct if_nameindex", final, - pure, header: "".} = object ## struct if_nameindex - if_index*: cuint ## Numeric index of the interface. - if_name*: cstring ## Null-terminated name of the interface. - - - IOVec* {.importc: "struct iovec", pure, final, - header: "".} = object ## struct iovec - iov_base*: pointer ## Base address of a memory region for input or output. - iov_len*: csize_t ## The size of the memory pointed to by iov_base. - - Tmsghdr* {.importc: "struct msghdr", pure, final, - header: "".} = object ## struct msghdr - msg_name*: pointer ## Optional address. - msg_namelen*: SockLen ## Size of address. - msg_iov*: ptr IOVec ## Scatter/gather array. - msg_iovlen*: cint ## Members in msg_iov. - msg_control*: pointer ## Ancillary data; see below. - msg_controllen*: SockLen ## Ancillary data buffer len. - msg_flags*: cint ## Flags on received message. - - - Tcmsghdr* {.importc: "struct cmsghdr", pure, final, - header: "".} = object ## struct cmsghdr - cmsg_len*: SockLen ## Data byte count, including the cmsghdr. - cmsg_level*: cint ## Originating protocol. - cmsg_type*: cint ## Protocol-specific type. - - TLinger* {.importc: "struct linger", pure, final, - header: "".} = object ## struct linger - l_onoff*: cint ## Indicates whether linger option is enabled. - l_linger*: cint ## Linger time, in seconds. - - InPort* = uint16 - InAddrScalar* = uint32 - - InAddrT* {.importc: "in_addr_t", pure, final, - header: "".} = uint32 - - InAddr* {.importc: "struct in_addr", pure, final, - header: "".} = object ## struct in_addr - s_addr*: InAddrScalar - - Sockaddr_in* {.importc: "struct sockaddr_in", pure, final, - header: "".} = object ## struct sockaddr_in - sin_family*: TSa_Family ## AF_INET. - sin_port*: InPort ## Port number. - sin_addr*: InAddr ## IP address. - - In6Addr* {.importc: "struct in6_addr", pure, final, - header: "".} = object ## struct in6_addr - s6_addr*: array[0..15, char] - - Sockaddr_in6* {.importc: "struct sockaddr_in6", pure, final, - header: "".} = object ## struct sockaddr_in6 - sin6_family*: TSa_Family ## AF_INET6. - sin6_port*: InPort ## Port number. - sin6_flowinfo*: int32 ## IPv6 traffic class and flow information. - sin6_addr*: In6Addr ## IPv6 address. - sin6_scope_id*: int32 ## Set of interfaces for a scope. - - Tipv6_mreq* {.importc: "struct ipv6_mreq", pure, final, - header: "".} = object ## struct ipv6_mreq - ipv6mr_multiaddr*: In6Addr ## IPv6 multicast address. - ipv6mr_interface*: cuint ## Interface index. - - Hostent* {.importc: "struct hostent", pure, final, - header: "".} = object ## struct hostent - h_name*: cstring ## Official name of the host. - h_aliases*: cstringArray ## A pointer to an array of pointers to - ## alternative host names, terminated by a - ## null pointer. - h_addrtype*: cint ## Address type. - h_length*: cint ## The length, in bytes, of the address. - h_addr_list*: cstringArray ## A pointer to an array of pointers to network - ## addresses (in network byte order) for the - ## host, terminated by a null pointer. - - Tnetent* {.importc: "struct netent", pure, final, - header: "".} = object ## struct netent - n_name*: cstring ## Official, fully-qualified (including the - ## domain) name of the host. - n_aliases*: cstringArray ## A pointer to an array of pointers to - ## alternative network names, terminated by a - ## null pointer. - n_addrtype*: cint ## The address type of the network. - n_net*: InAddrT ## The network number, in host byte order. - - Protoent* {.importc: "struct protoent", pure, final, - header: "".} = object ## struct protoent - p_name*: cstring ## Official name of the protocol. - p_aliases*: cstringArray ## A pointer to an array of pointers to - ## alternative protocol names, terminated by - ## a null pointer. - p_proto*: cint ## The protocol number. - - Servent* {.importc: "struct servent", pure, final, - header: "".} = object ## struct servent - s_name*: cstring ## Official name of the service. - s_aliases*: cstringArray ## A pointer to an array of pointers to - ## alternative service names, terminated by - ## a null pointer. - s_port*: cint ## The port number at which the service - ## resides, in network byte order. - s_proto*: cstring ## The name of the protocol to use when - ## contacting the service. - - AddrInfo* {.importc: "struct addrinfo", pure, final, - header: "".} = object ## struct addrinfo - ai_flags*: cint ## Input flags. - ai_family*: cint ## Address family of socket. - ai_socktype*: cint ## Socket type. - ai_protocol*: cint ## Protocol of socket. - ai_addrlen*: SockLen ## Length of socket address. - ai_addr*: ptr SockAddr ## Socket address of socket. - ai_canonname*: cstring ## Canonical name of service location. - ai_next*: ptr AddrInfo ## Pointer to next in list. - - TPollfd* {.importc: "struct pollfd", pure, final, - header: "".} = object ## struct pollfd - fd*: cint ## The following descriptor being polled. - events*: cshort ## The input event flags (see below). - revents*: cshort ## The output event flags (see below). - - Tnfds* {.importc: "nfds_t", header: "".} = culong - -var - errno* {.importc, header: "".}: cint ## error variable - h_errno* {.importc, header: "".}: cint - daylight* {.importc, header: "".}: cint - timezone* {.importc, header: "".}: int - -# Regenerate using detect.nim! -include posix_other_consts - -when defined(linux): - var - MAP_POPULATE* {.importc, header: "".}: cint - ## Populate (prefault) page tables for a mapping. -else: - var - MAP_POPULATE*: cint = 0 - -when defined(linux) or defined(nimdoc): - when defined(alpha) or defined(mips) or defined(mipsel) or - defined(mips64) or defined(mips64el) or defined(parisc) or - defined(sparc) or defined(sparc64) or defined(nimdoc): - const SO_REUSEPORT* = cint(0x0200) - ## Multiple binding: load balancing on incoming TCP connections - ## or UDP packets. (Requires Linux kernel > 3.9) - else: - const SO_REUSEPORT* = cint(15) -else: - var SO_REUSEPORT* {.importc, header: "".}: cint - -when defined(macosx): - # We can't use the NOSIGNAL flag in the `send` function, it has no effect - # Instead we should use SO_NOSIGPIPE in setsockopt - const - MSG_NOSIGNAL* = 0'i32 - var - SO_NOSIGPIPE* {.importc, header: "".}: cint -elif defined(solaris): - # Solaris doesn't have MSG_NOSIGNAL - const - MSG_NOSIGNAL* = 0'i32 -else: - var - MSG_NOSIGNAL* {.importc, header: "".}: cint - ## No SIGPIPE generated when an attempt to send is made on a stream-oriented socket that is no longer connected. - -when defined(haiku): - const - SIGKILLTHR* = 21 ## BeOS specific: Kill just the thread, not team - -when hasSpawnH: - when defined(linux): - # better be safe than sorry; Linux has this flag, macosx doesn't, don't - # know about the other OSes - - # Non-GNU systems like TCC and musl-libc don't define __USE_GNU, so we - # can't get the magic number from spawn.h - const POSIX_SPAWN_USEVFORK* = cint(0x40) - else: - # macosx lacks this, so we define the constant to be 0 to not affect - # OR'ing of flags: - const POSIX_SPAWN_USEVFORK* = cint(0) - -# -proc WEXITSTATUS*(s: cint): cint {.importc, header: "".} - ## Exit code, if WIFEXITED(s) -proc WTERMSIG*(s: cint): cint {.importc, header: "".} - ## Termination signal, if WIFSIGNALED(s) -proc WSTOPSIG*(s: cint): cint {.importc, header: "".} - ## Stop signal, if WIFSTOPPED(s) -proc WIFEXITED*(s: cint): bool {.importc, header: "".} - ## True if child exited normally. -proc WIFSIGNALED*(s: cint): bool {.importc, header: "".} - ## True if child exited due to uncaught signal. -proc WIFSTOPPED*(s: cint): bool {.importc, header: "".} - ## True if child is currently stopped. -proc WIFCONTINUED*(s: cint): bool {.importc, header: "".} - ## True if child has been continued. - -when defined(nimHasStyleChecks): - {.pop.} diff --git a/lib/posix/posix_linux_amd64.nim b/lib/posix/posix_linux_amd64.nim index 4eb357d62..bb82d9e5e 100644 --- a/lib/posix/posix_linux_amd64.nim +++ b/lib/posix/posix_linux_amd64.nim @@ -34,6 +34,9 @@ type type SocketHandle* = distinct cint # The type used to represent socket descriptors +# not detected by detect.nim, guarded by #ifdef __USE_UNIX98 in glibc +const SIG_HOLD* = cast[Sighandler](2) + type Time* {.importc: "time_t", header: "".} = distinct clong @@ -47,7 +50,7 @@ type d_ino*: Ino d_off*: Off d_reclen*: cushort - d_type*: int8 # uint8 really! + d_type*: int8 # cuchar really! d_name*: array[256, cchar] Tflock* {.importc: "struct flock", final, pure, @@ -168,7 +171,7 @@ type Pthread_key* {.importc: "pthread_key_t", header: "".} = cuint Pthread_mutex* {.importc: "pthread_mutex_t", header: "", pure, final.} = object - abi: array[40 div sizeof(clong), clong] + abi: array[48 div sizeof(clong), clong] Pthread_mutexattr* {.importc: "pthread_mutexattr_t", header: "", pure, final.} = object abi: array[4 div sizeof(cint), cint] @@ -225,7 +228,7 @@ type st_mode*: Mode ## Mode of file (see below). st_uid*: Uid ## User ID of file. st_gid*: Gid ## Group ID of file. - pad0 {.importc: "__pad0".}: cint + pad0: cint st_rdev*: Dev ## Device ID (if file is character or block special). st_size*: Off ## For regular files, the file size in bytes. ## For symbolic links, the length in bytes of the @@ -241,6 +244,8 @@ type st_atim*: Timespec ## Time of last access. st_mtim*: Timespec ## Time of last data modification. st_ctim*: Timespec ## Time of last status change. + reserved: array[3, clong] + Statvfs* {.importc: "struct statvfs", header: "", final, pure.} = object ## struct statvfs @@ -334,7 +339,7 @@ type si_status*: cint ## Exit value or signal. si_band*: int ## Band event for SIGPOLL. si_value*: SigVal ## Signal value. - pad {.importc: "_pad".}: array[128 - 56, uint8] + pad {.importc: "_pad"}: array[128 - 56, uint8] Nl_item* {.importc: "nl_item", header: "".} = cint Nl_catd* {.importc: "nl_catd", header: "".} = pointer @@ -428,8 +433,8 @@ type header: "", pure, final.} = object ## struct sockaddr_storage ss_family*: TSa_Family ## Address family. - ss_padding {.importc: "__ss_padding".}: array[128 - sizeof(cshort) - sizeof(culong), char] - ss_align {.importc: "__ss_align".}: clong + ss_padding: array[128 - sizeof(cshort) - sizeof(culong), char] + ss_align: clong Tif_nameindex* {.importc: "struct if_nameindex", final, pure, header: "".} = object ## struct if_nameindex @@ -568,6 +573,8 @@ var # Regenerate using detect.nim! include posix_linux_amd64_consts +const POSIX_SPAWN_USEVFORK* = cint(0x40) # needs _GNU_SOURCE! + # proc WEXITSTATUS*(s: cint): cint = (s and 0xff00) shr 8 proc WTERMSIG*(s:cint): cint = s and 0x7f diff --git a/lib/posix/posix_linux_amd64_consts.nim b/lib/posix/posix_linux_amd64_consts.nim index f3230f71d..7352e8e35 100644 --- a/lib/posix/posix_linux_amd64_consts.nim +++ b/lib/posix/posix_linux_amd64_consts.nim @@ -100,7 +100,6 @@ const EXDEV* = cint(18) # const F_DUPFD* = cint(0) -const F_DUPFD_CLOEXEC* = cint(1030) const F_GETFD* = cint(1) const F_SETFD* = cint(2) const F_GETFL* = cint(3) @@ -127,11 +126,6 @@ const O_ACCMODE* = cint(3) const O_RDONLY* = cint(0) const O_RDWR* = cint(2) const O_WRONLY* = cint(1) -const O_CLOEXEC* = cint(524288) -const O_DIRECT* = cint(16384) -const O_PATH* = cint(2097152) -const O_NOATIME* = cint(262144) -const O_TMPFILE* = cint(4259840) const POSIX_FADV_NORMAL* = cint(0) const POSIX_FADV_SEQUENTIAL* = cint(2) const POSIX_FADV_RANDOM* = cint(1) @@ -178,20 +172,13 @@ const FNM_NOMATCH* = cint(1) const FNM_PATHNAME* = cint(1) const FNM_PERIOD* = cint(4) const FNM_NOESCAPE* = cint(2) -const FNM_NOSYS* = cint(-1) # const FTW_F* = cint(0) const FTW_D* = cint(1) const FTW_DNR* = cint(2) -const FTW_DP* = cint(5) const FTW_NS* = cint(3) const FTW_SL* = cint(4) -const FTW_SLN* = cint(6) -const FTW_PHYS* = cint(1) -const FTW_MOUNT* = cint(2) -const FTW_DEPTH* = cint(8) -const FTW_CHDIR* = cint(4) # const GLOB_APPEND* = cint(32) @@ -413,7 +400,6 @@ const SS_ONSTACK* = cint(1) const SS_DISABLE* = cint(2) const MINSIGSTKSZ* = cint(2048) const SIGSTKSZ* = cint(8192) -const SIG_HOLD* = cast[Sighandler](2) const SIG_DFL* = cast[Sighandler](0) const SIG_ERR* = cast[Sighandler](-1) const SIG_IGN* = cast[Sighandler](1) @@ -483,9 +469,8 @@ const SOCK_DGRAM* = cint(2) const SOCK_RAW* = cint(3) const SOCK_SEQPACKET* = cint(5) const SOCK_STREAM* = cint(1) -const SOCK_CLOEXEC* = cint(524288) const SOL_SOCKET* = cint(1) -const SOMAXCONN* = cint(4096) +const SOMAXCONN* = cint(128) const SO_REUSEPORT* = cint(15) const MSG_NOSIGNAL* = cint(16384) const MSG_PEEK* = cint(2) @@ -543,7 +528,6 @@ const POSIX_SPAWN_SETSCHEDPARAM* = cint(16) const POSIX_SPAWN_SETSCHEDULER* = cint(32) const POSIX_SPAWN_SETSIGDEF* = cint(4) const POSIX_SPAWN_SETSIGMASK* = cint(8) -const POSIX_SPAWN_USEVFORK* = cint(64) # const IOFBF* = cint(0) diff --git a/lib/posix/posix_macos_amd64.nim b/lib/posix/posix_macos_amd64.nim index d6b5834cb..8a20d127f 100644 --- a/lib/posix/posix_macos_amd64.nim +++ b/lib/posix/posix_macos_amd64.nim @@ -7,6 +7,8 @@ # distribution, for details about the copyright. # +{.deadCodeElim: on.} # dce option deprecated + when defined(nimHasStyleChecks): {.push styleChecks: off.} @@ -45,7 +47,7 @@ type d_type*: int8 ## Type of file; not supported by all filesystem types. ## (not POSIX) when defined(linux) or defined(openbsd): - d_off*: Off ## Not an offset. Value that `telldir()` would return. + d_off*: Off ## Not an offset. Value that ``telldir()`` would return. elif defined(haiku): d_pino*: Ino ## Parent inode (only for queries) (not POSIX) d_reclen*: cushort ## Length of this record. (not POSIX) @@ -108,6 +110,15 @@ type p_sign_posn*: char thousands_sep*: cstring + Mqd* {.importc: "mqd_t", header: "", final, pure.} = object + MqAttr* {.importc: "struct mq_attr", + header: "", + final, pure.} = object ## message queue attribute + mq_flags*: int ## Message queue flags. + mq_maxmsg*: int ## Maximum number of messages. + mq_msgsize*: int ## Maximum message size. + mq_curmsgs*: int ## Number of messages currently queued. + Passwd* {.importc: "struct passwd", header: "", final, pure.} = object ## struct passwd pw_name*: cstring ## User's login name. @@ -366,18 +377,6 @@ when hasSpawnH: Tposix_spawn_file_actions* {.importc: "posix_spawn_file_actions_t", header: "", final, pure.} = object - -when not defined(macos) and not defined(macosx): # freebsd - type - Mqd* {.importc: "mqd_t", header: "", final, pure.} = object - MqAttr* {.importc: "struct mq_attr", - header: "", - final, pure.} = object ## message queue attribute - mq_flags*: int ## Message queue flags. - mq_maxmsg*: int ## Maximum number of messages. - mq_msgsize*: int ## Maximum message size. - mq_curmsgs*: int ## Number of messages currently queued. - when defined(linux): # from sys/un.h const Sockaddr_un_path_length* = 108 @@ -414,7 +413,7 @@ type IOVec* {.importc: "struct iovec", pure, final, header: "".} = object ## struct iovec iov_base*: pointer ## Base address of a memory region for input or output. - iov_len*: csize_t ## The size of the memory pointed to by iov_base. + iov_len*: int ## The size of the memory pointed to by iov_base. Tmsghdr* {.importc: "struct msghdr", pure, final, header: "".} = object ## struct msghdr @@ -560,11 +559,8 @@ when defined(linux) or defined(nimdoc): else: var SO_REUSEPORT* {.importc, header: "".}: cint -when defined(linux) or defined(bsd): - var SOCK_CLOEXEC* {.importc, header: "".}: cint - when defined(macosx): - # We can't use the NOSIGNAL flag in the `send` function, it has no effect + # We can't use the NOSIGNAL flag in the ``send`` function, it has no effect # Instead we should use SO_NOSIGPIPE in setsockopt const MSG_NOSIGNAL* = 0'i32 @@ -598,11 +594,11 @@ when hasSpawnH: # proc WEXITSTATUS*(s: cint): cint {.importc, header: "".} - ## Exit code, if WIFEXITED(s) + ## Exit code, iff WIFEXITED(s) proc WTERMSIG*(s: cint): cint {.importc, header: "".} - ## Termination signal, if WIFSIGNALED(s) + ## Termination signal, iff WIFSIGNALED(s) proc WSTOPSIG*(s: cint): cint {.importc, header: "".} - ## Stop signal, if WIFSTOPPED(s) + ## Stop signal, iff WIFSTOPPED(s) proc WIFEXITED*(s: cint): bool {.importc, header: "".} ## True if child exited normally. proc WIFSIGNALED*(s: cint): bool {.importc, header: "".} diff --git a/lib/posix/posix_nintendoswitch.nim b/lib/posix/posix_nintendoswitch.nim index b66563695..d1cc042ea 100644 --- a/lib/posix/posix_nintendoswitch.nim +++ b/lib/posix/posix_nintendoswitch.nim @@ -33,7 +33,7 @@ type Dirent* {.importc: "struct dirent", header: "", final, pure.} = object ## dirent_t struct d_ino*: Ino - d_type*: int8 # uint8 really! + d_type*: int8 # cuchar really! d_name*: array[256, cchar] Tflock* {.importc: "struct flock", final, pure, @@ -286,7 +286,7 @@ type header: "", final, pure.} = object ## stack_t ss_sp*: pointer ## Stack base or pointer. ss_flags*: cint ## Flags. - ss_size*: csize_t ## Stack size. + ss_size*: csize ## Stack size. SigInfo* {.importc: "siginfo_t", header: "", final, pure.} = object ## siginfo_t @@ -321,7 +321,7 @@ type aio_lio_opcode*: cint ## Operation to be performed. aio_reqprio*: cint ## Request priority offset. aio_buf*: pointer ## Location of buffer. - aio_nbytes*: csize_t ## Length of transfer. + aio_nbytes*: csize ## Length of transfer. aio_sigevent*: SigEvent ## Signal number and value. next_prio: pointer abs_prio: cint @@ -347,20 +347,20 @@ type SockAddr* {.importc: "struct sockaddr", header: "", pure, final.} = object ## struct sockaddr - sa_len: uint8 + sa_len: cuchar sa_family*: TSa_Family ## Address family. sa_data*: array[14, char] ## Socket address (variable-length data). Sockaddr_storage* {.importc: "struct sockaddr_storage", header: "", pure, final.} = object ## struct sockaddr_storage - ss_len: uint8 + ss_len: cuchar ss_family*: TSa_Family ## Address family. - ss_padding1: array[64 - sizeof(uint8) - sizeof(cshort), char] + ss_padding1: array[64 - sizeof(cuchar) - sizeof(cshort), char] ss_align: clonglong ss_padding2: array[ - 128 - sizeof(uint8) - sizeof(cshort) - - (64 - sizeof(uint8) - sizeof(cshort)) - 64, char] + 128 - sizeof(cuchar) - sizeof(cshort) - + (64 - sizeof(cuchar) - sizeof(cshort)) - 64, char] Tif_nameindex* {.importc: "struct if_nameindex", final, pure, header: "".} = object ## struct if_nameindex @@ -371,22 +371,22 @@ type IOVec* {.importc: "struct iovec", pure, final, header: "".} = object ## struct iovec iov_base*: pointer ## Base address of a memory region for input or output. - iov_len*: csize_t ## The size of the memory pointed to by iov_base. + iov_len*: csize ## The size of the memory pointed to by iov_base. Tmsghdr* {.importc: "struct msghdr", pure, final, header: "".} = object ## struct msghdr msg_name*: pointer ## Optional address. msg_namelen*: SockLen ## Size of address. msg_iov*: ptr IOVec ## Scatter/gather array. - msg_iovlen*: csize_t ## Members in msg_iov. + msg_iovlen*: csize ## Members in msg_iov. msg_control*: pointer ## Ancillary data; see below. - msg_controllen*: csize_t ## Ancillary data buffer len. + msg_controllen*: csize ## Ancillary data buffer len. msg_flags*: cint ## Flags on received message. Tcmsghdr* {.importc: "struct cmsghdr", pure, final, header: "".} = object ## struct cmsghdr - cmsg_len*: csize_t ## Data byte count, including the cmsghdr. + cmsg_len*: csize ## Data byte count, including the cmsghdr. cmsg_level*: cint ## Originating protocol. cmsg_type*: cint ## Protocol-specific type. diff --git a/lib/posix/posix_openbsd_amd64.nim b/lib/posix/posix_openbsd_amd64.nim index 1ef4a4182..d9ac84a1d 100644 --- a/lib/posix/posix_openbsd_amd64.nim +++ b/lib/posix/posix_openbsd_amd64.nim @@ -7,6 +7,8 @@ # distribution, for details about the copyright. # +{.deadCodeElim: on.} # dce option deprecated + when defined(nimHasStyleChecks): {.push styleChecks: off.} @@ -45,7 +47,7 @@ type d_type*: int8 ## Type of file; not supported by all filesystem types. ## (not POSIX) when defined(linux) or defined(openbsd): - d_off*: Off ## Not an offset. Value that `telldir()` would return. + d_off*: Off ## Not an offset. Value that ``telldir()`` would return. elif defined(haiku): d_pino*: Ino ## Parent inode (only for queries) (not POSIX) d_reclen*: cushort ## Length of this record. (not POSIX) @@ -398,7 +400,7 @@ type IOVec* {.importc: "struct iovec", pure, final, header: "".} = object ## struct iovec iov_base*: pointer ## Base address of a memory region for input or output. - iov_len*: csize_t ## The size of the memory pointed to by iov_base. + iov_len*: int ## The size of the memory pointed to by iov_base. Tmsghdr* {.importc: "struct msghdr", pure, final, header: "".} = object ## struct msghdr @@ -532,8 +534,6 @@ when defined(nimdoc): else: var SO_REUSEPORT* {.importc, header: "".}: cint -var SOCK_CLOEXEC* {.importc, header: "".}: cint - var MSG_NOSIGNAL* {.importc, header: "".}: cint when hasSpawnH: @@ -543,11 +543,11 @@ when hasSpawnH: # proc WEXITSTATUS*(s: cint): cint {.importc, header: "".} - ## Exit code, if WIFEXITED(s) + ## Exit code, iff WIFEXITED(s) proc WTERMSIG*(s: cint): cint {.importc, header: "".} - ## Termination signal, if WIFSIGNALED(s) + ## Termination signal, iff WIFSIGNALED(s) proc WSTOPSIG*(s: cint): cint {.importc, header: "".} - ## Stop signal, if WIFSTOPPED(s) + ## Stop signal, iff WIFSTOPPED(s) proc WIFEXITED*(s: cint): bool {.importc, header: "".} ## True if child exited normally. proc WIFSIGNALED*(s: cint): bool {.importc, header: "".} diff --git a/lib/posix/posix_other.nim b/lib/posix/posix_other.nim index 1b6734b51..e42092513 100644 --- a/lib/posix/posix_other.nim +++ b/lib/posix/posix_other.nim @@ -7,17 +7,14 @@ # distribution, for details about the copyright. # +{.deadCodeElim: on.} # dce option deprecated + when defined(nimHasStyleChecks): {.push styleChecks: off.} -when defined(freertos) or defined(zephyr) or defined(nuttx): - const - hasSpawnH = false # should exist for every Posix system nowadays - hasAioH = false -else: - const - hasSpawnH = true # should exist for every Posix system nowadays - hasAioH = defined(linux) +const + hasSpawnH = true # should exist for every Posix system nowadays + hasAioH = defined(linux) when defined(linux) and not defined(android): # On Linux: @@ -37,12 +34,7 @@ type SocketHandle* = distinct cint # The type used to represent socket descriptors type - Time* {.importc: "time_t", header: "".} = distinct ( - when defined(nimUse64BitCTime): - int64 - else: - clong - ) + Time* {.importc: "time_t", header: "".} = distinct clong Timespec* {.importc: "struct timespec", header: "", final, pure.} = object ## struct timespec @@ -64,7 +56,7 @@ type d_type*: int8 ## Type of file; not supported by all filesystem types. ## (not POSIX) when defined(linux) or defined(openbsd): - d_off*: Off ## Not an offset. Value that `telldir()` would return. + d_off*: Off ## Not an offset. Value that ``telldir()`` would return. elif defined(haiku): d_pino*: Ino ## Parent inode (only for queries) (not POSIX) d_reclen*: cushort ## Length of this record. (not POSIX) @@ -391,33 +383,9 @@ when hasSpawnH: header: "", final, pure.} = object when defined(linux): - const Sockaddr_max_length* = 255 # from sys/un.h const Sockaddr_un_path_length* = 108 -elif defined(zephyr): - when defined(net_ipv6): - const Sockaddr_max_length* = 24 - elif defined(net_raw): - const Sockaddr_max_length* = 20 - elif defined(net_ipv4): - const Sockaddr_max_length* = 8 - else: - const Sockaddr_max_length* = 255 # just for compilation purposes - - const Sockaddr_un_path_length* = Sockaddr_max_length - # Zephyr is heavily customizable so it's easy to get to a state - # where Nim & Zephyr IPv6 settings are out of sync, causing painful runtime failures. - when defined(net_ipv4) or defined(net_ipv6) or defined(net_raw): - {.emit: ["NIM_STATIC_ASSERT(NET_SOCKADDR_MAX_SIZE == ", - Sockaddr_max_length, - ",\"NET_SOCKADDR_MAX_SIZE and Sockaddr_max_length size mismatch!", - " Check that Nim and Zephyr IPv4/IPv6 settings match.", - " Try adding -d:net_ipv6 to enable IPv6 for Nim on Zephyr.\" );"].} -elif defined(freertos) or defined(lwip): - const Sockaddr_max_length* = 14 - const Sockaddr_un_path_length* = 108 else: - const Sockaddr_max_length* = 255 # according to http://pubs.opengroup.org/onlinepubs/009604499/basedefs/sys/un.h.html # this is >=92 const Sockaddr_un_path_length* = 92 @@ -426,57 +394,21 @@ type SockLen* {.importc: "socklen_t", header: "".} = cuint TSa_Family* {.importc: "sa_family_t", header: "".} = cushort -when defined(lwip): - type - SockAddr* {.importc: "struct sockaddr", header: "", - pure, final.} = object ## struct sockaddr - sa_len*: uint8 ## Address family. - sa_family*: TSa_Family ## Address family. - sa_data*: array[0..Sockaddr_max_length-sizeof(uint8)-sizeof(TSa_Family), char] ## Socket address (variable-length data). + SockAddr* {.importc: "struct sockaddr", header: "", + pure, final.} = object ## struct sockaddr + sa_family*: TSa_Family ## Address family. + sa_data*: array[0..255, char] ## Socket address (variable-length data). - Sockaddr_storage* {.importc: "struct sockaddr_storage", - header: "", - pure, final.} = object ## struct sockaddr_storage - s2_len*: uint8 ## Address family. - ss_family*: TSa_Family ## Address family. - s2_data1*: array[2, char] ## Address family. - s2_data2*: array[3, uint32] ## Address family. - when defined(lwip6) or defined(net_ipv6): - s2_data3*: array[3, uint32] ## Address family. -elif defined(zephyr): - type - SockAddr* {.importc: "struct sockaddr", header: "", - pure, final.} = object ## struct sockaddr - sa_family*: TSa_Family ## Address family. - data*: array[0..Sockaddr_max_length-sizeof(TSa_Family), char] ## Socket address (variable-length data). - - Sockaddr_storage* {.importc: "struct sockaddr_storage", - header: "", - pure, final.} = object ## struct sockaddr_storage - ss_family*: TSa_Family ## Address family. - data*: array[0..Sockaddr_max_length-sizeof(TSa_Family), char] ## Socket address (variable-length data). - {.emit: ["NIM_STATIC_ASSERT(sizeof(struct sockaddr) == ", sizeof(Sockaddr), ",\"struct size mismatch\" );"].} - {.emit: ["NIM_STATIC_ASSERT(sizeof(struct sockaddr_storage) == ", sizeof(Sockaddr_storage), ",\"struct size mismatch\" );"].} -else: - type - SockAddr* {.importc: "struct sockaddr", header: "", - pure, final.} = object ## struct sockaddr - sa_family*: TSa_Family ## Address family. - sa_data*: array[0..Sockaddr_max_length-sizeof(TSa_Family), char] ## Socket address (variable-length data). - - Sockaddr_storage* {.importc: "struct sockaddr_storage", - header: "", - pure, final.} = object ## struct sockaddr_storage - ss_family*: TSa_Family ## Address family. - -type Sockaddr_un* {.importc: "struct sockaddr_un", header: "", pure, final.} = object ## struct sockaddr_un sun_family*: TSa_Family ## Address family. - sun_path*: array[0..Sockaddr_un_path_length-sizeof(TSa_Family), char] ## Socket path + sun_path*: array[0..Sockaddr_un_path_length-1, char] ## Socket path + Sockaddr_storage* {.importc: "struct sockaddr_storage", + header: "", + pure, final.} = object ## struct sockaddr_storage + ss_family*: TSa_Family ## Address family. -type Tif_nameindex* {.importc: "struct if_nameindex", final, pure, header: "".} = object ## struct if_nameindex if_index*: cint ## Numeric index of the interface. @@ -486,7 +418,7 @@ type IOVec* {.importc: "struct iovec", pure, final, header: "".} = object ## struct iovec iov_base*: pointer ## Base address of a memory region for input or output. - iov_len*: csize_t ## The size of the memory pointed to by iov_base. + iov_len*: int ## The size of the memory pointed to by iov_base. Tmsghdr* {.importc: "struct msghdr", pure, final, header: "".} = object ## struct msghdr @@ -520,7 +452,6 @@ type header: "".} = object ## struct in_addr s_addr*: InAddrScalar - # TODO: Fixme for FreeRTOS/LwIP, these are incorrect Sockaddr_in* {.importc: "struct sockaddr_in", pure, final, header: "".} = object ## struct sockaddr_in sin_family*: TSa_Family ## AF_INET. @@ -596,20 +527,13 @@ type ai_canonname*: cstring ## Canonical name of service location. ai_next*: ptr AddrInfo ## Pointer to next in list. -when not defined(lwip): - type - TPollfd* {.importc: "struct pollfd", pure, final, - header: "".} = object ## struct pollfd - fd*: cint ## The following descriptor being polled. - events*: cshort ## The input event flags (see below). - revents*: cshort ## The output event flags (see below). + TPollfd* {.importc: "struct pollfd", pure, final, + header: "".} = object ## struct pollfd + fd*: cint ## The following descriptor being polled. + events*: cshort ## The input event flags (see below). + revents*: cshort ## The output event flags (see below). - when defined(zephyr): - type - Tnfds* = distinct cint - else: - type - Tnfds* {.importc: "nfds_t", header: "".} = cint + Tnfds* {.importc: "nfds_t", header: "".} = cint var errno* {.importc, header: "".}: cint ## error variable @@ -618,10 +542,7 @@ var timezone* {.importc, header: "".}: int # Regenerate using detect.nim! -when defined(lwip): - include posix_freertos_consts -else: - include posix_other_consts +include posix_other_consts when defined(linux): var @@ -640,17 +561,11 @@ when defined(linux) or defined(nimdoc): ## or UDP packets. (Requires Linux kernel > 3.9) else: const SO_REUSEPORT* = cint(15) -elif defined(nuttx): - # Not supported, use SO_REUSEADDR to avoid compilation errors. - var SO_REUSEPORT* {.importc: "SO_REUSEADDR", header: "".}: cint else: var SO_REUSEPORT* {.importc, header: "".}: cint -when defined(linux) or defined(bsd): - var SOCK_CLOEXEC* {.importc, header: "".}: cint - when defined(macosx): - # We can't use the NOSIGNAL flag in the `send` function, it has no effect + # We can't use the NOSIGNAL flag in the ``send`` function, it has no effect # Instead we should use SO_NOSIGPIPE in setsockopt const MSG_NOSIGNAL* = 0'i32 @@ -660,10 +575,6 @@ elif defined(solaris): # Solaris doesn't have MSG_NOSIGNAL const MSG_NOSIGNAL* = 0'i32 -elif defined(zephyr) or defined(freertos) or defined(lwip): - # LwIP/FreeRTOS doesn't have MSG_NOSIGNAL - const - MSG_NOSIGNAL* = 0x20'i32 else: var MSG_NOSIGNAL* {.importc, header: "".}: cint @@ -688,11 +599,11 @@ when hasSpawnH: # proc WEXITSTATUS*(s: cint): cint {.importc, header: "".} - ## Exit code, if WIFEXITED(s) + ## Exit code, iff WIFEXITED(s) proc WTERMSIG*(s: cint): cint {.importc, header: "".} - ## Termination signal, if WIFSIGNALED(s) + ## Termination signal, iff WIFSIGNALED(s) proc WSTOPSIG*(s: cint): cint {.importc, header: "".} - ## Stop signal, if WIFSTOPPED(s) + ## Stop signal, iff WIFSTOPPED(s) proc WIFEXITED*(s: cint): bool {.importc, header: "".} ## True if child exited normally. proc WIFSIGNALED*(s: cint): bool {.importc, header: "".} diff --git a/lib/posix/posix_other_consts.nim b/lib/posix/posix_other_consts.nim index 08069fe9a..9fcbe425d 100644 --- a/lib/posix/posix_other_consts.nim +++ b/lib/posix/posix_other_consts.nim @@ -99,10 +99,6 @@ var EXDEV* {.importc: "EXDEV", header: "".}: cint # var F_DUPFD* {.importc: "F_DUPFD", header: "".}: cint -when defined(nuttx): - var F_DUPFD_CLOEXEC* {.importc: "F_DUPFD_CLOEXEC", header: "".}: cint -else: - var F_DUPFD_CLOEXEC* {.importc: "F_DUPFD", header: "".}: cint var F_GETFD* {.importc: "F_GETFD", header: "".}: cint var F_SETFD* {.importc: "F_SETFD", header: "".}: cint var F_GETFL* {.importc: "F_GETFL", header: "".}: cint @@ -129,12 +125,6 @@ var O_ACCMODE* {.importc: "O_ACCMODE", header: "".}: cint var O_RDONLY* {.importc: "O_RDONLY", header: "".}: cint var O_RDWR* {.importc: "O_RDWR", header: "".}: cint var O_WRONLY* {.importc: "O_WRONLY", header: "".}: cint -var O_CLOEXEC* {.importc: "O_CLOEXEC", header: "".}: cint -when defined(nuttx): - var O_DIRECT* {.importc: "O_DIRECT", header: "".}: cint - var O_PATH* {.importc: "O_PATH", header: "".}: cint - var O_NOATIME* {.importc: "O_NOATIME", header: "".}: cint - var O_TMPFILE* {.importc: "O_TMPFILE", header: "".}: cint var POSIX_FADV_NORMAL* {.importc: "POSIX_FADV_NORMAL", header: "".}: cint var POSIX_FADV_SEQUENTIAL* {.importc: "POSIX_FADV_SEQUENTIAL", header: "".}: cint var POSIX_FADV_RANDOM* {.importc: "POSIX_FADV_RANDOM", header: "".}: cint @@ -470,9 +460,6 @@ var RLIMIT_NOFILE* {.importc: "RLIMIT_NOFILE", header: "".}: cin # var FD_SETSIZE* {.importc: "FD_SETSIZE", header: "".}: cint -when defined(zephyr): - # Zephyr specific hardcoded value - var FD_MAX* {.importc: "CONFIG_POSIX_MAX_FDS ", header: "".}: cint # var MSG_CTRUNC* {.importc: "MSG_CTRUNC", header: "".}: cint @@ -498,15 +485,10 @@ var SO_SNDTIMEO* {.importc: "SO_SNDTIMEO", header: "".}: cint var SO_TYPE* {.importc: "SO_TYPE", header: "".}: cint var SOCK_DGRAM* {.importc: "SOCK_DGRAM", header: "".}: cint var SOCK_RAW* {.importc: "SOCK_RAW", header: "".}: cint -when defined(zephyr): - const SOCK_SEQPACKET* = cint(5) - var SOMAXCONN* {.importc: "CONFIG_NET_SOCKETS_POLL_MAX", header: "".}: cint -else: - var SOCK_SEQPACKET* {.importc: "SOCK_SEQPACKET", header: "".}: cint - var SOMAXCONN* {.importc: "SOMAXCONN", header: "".}: cint - +var SOCK_SEQPACKET* {.importc: "SOCK_SEQPACKET", header: "".}: cint var SOCK_STREAM* {.importc: "SOCK_STREAM", header: "".}: cint var SOL_SOCKET* {.importc: "SOL_SOCKET", header: "".}: cint +var SOMAXCONN* {.importc: "SOMAXCONN", header: "".}: cint var MSG_PEEK* {.importc: "MSG_PEEK", header: "".}: cint var MSG_TRUNC* {.importc: "MSG_TRUNC", header: "".}: cint var MSG_WAITALL* {.importc: "MSG_WAITALL", header: "".}: cint @@ -750,6 +732,3 @@ var SEEK_SET* {.importc: "SEEK_SET", header: "".}: cint var SEEK_CUR* {.importc: "SEEK_CUR", header: "".}: cint var SEEK_END* {.importc: "SEEK_END", header: "".}: cint -# -when defined(nuttx): - var NEPOLL_MAX* {.importc: "CONFIG_FS_NEPOLL_DESCRIPTORS", header: "".}: cint diff --git a/lib/posix/posix_utils.nim b/lib/posix/posix_utils.nim index 7e4a2eeda..20a71971a 100644 --- a/lib/posix/posix_utils.nim +++ b/lib/posix/posix_utils.nim @@ -7,21 +7,19 @@ # ## A set of helpers for the POSIX module. -## Raw interfaces are in the other ``posix*.nim`` files. +## Raw interfaces are in the other posix*.nim files. # Where possible, contribute OS-independent procs in `os `_ instead. -import posix, parsecfg, os -import std/private/since +{.deadCodeElim: on.} # dce option deprecated -when defined(nimPreviewSlimSystem): - import std/syncio +import posix type Uname* = object sysname*, nodename*, release*, version*, machine*: string template charArrayToString(input: typed): string = - $cast[cstring](addr input) + $cstring(addr input) proc uname*(): Uname = ## Provides system information in a `Uname` struct with sysname, nodename, @@ -43,8 +41,8 @@ proc uname*(): Uname = result.machine = charArrayToString u.machine proc fsync*(fd: int) = - ## synchronize a file's buffer cache to the storage device - if fsync(fd.cint) != 0: + ## synchronize a file's buffer cache to the storage device + if fsync(fd.cint) != 0: raise newException(OSError, $strerror(errno)) proc stat*(path: string): Stat = @@ -60,10 +58,9 @@ proc memoryLock*(a1: pointer, a2: int) = proc memoryLockAll*(flags: int) = ## Locks all memory for the running process to prevent swapping. ## - ## example: - ## ```nim + ## example:: + ## ## memoryLockAll(MCL_CURRENT or MCL_FUTURE) - ## ``` if mlockall(flags.cint) != 0: raise newException(OSError, $strerror(errno)) @@ -83,23 +80,12 @@ proc sendSignal*(pid: Pid, signal: int) = if kill(pid, signal.cint) != 0: raise newException(OSError, $strerror(errno)) -proc mkstemp*(prefix: string, suffix=""): (string, File) = - ## Creates a unique temporary file from a prefix string. A six-character string - ## will be added. If suffix is provided it will be added to the string +proc mkstemp*(prefix: string): (string, File) = + ## Creates a unique temporary file from a prefix string. Adds a six chars suffix. ## The file is created with perms 0600. ## Returns the filename and a file opened in r/w mode. - var tmpl = cstring(prefix & "XXXXXX" & suffix) - let fd = - if len(suffix) == 0: - when declared(mkostemp): - mkostemp(tmpl, O_CLOEXEC) - else: - mkstemp(tmpl) - else: - when declared(mkostemps): - mkostemps(tmpl, cint(len(suffix)), O_CLOEXEC) - else: - mkstemps(tmpl, cint(len(suffix))) + var tmpl = cstring(prefix & "XXXXXX") + let fd = mkstemp(tmpl) var f: File if open(f, fd, fmReadWrite): return ($tmpl, f) @@ -113,21 +99,3 @@ proc mkdtemp*(prefix: string): string = raise newException(OSError, $strerror(errno)) return $tmpl -proc osReleaseFile*(): Config {.since: (1, 5).} = - ## Gets system identification from `os-release` file and returns it as a `parsecfg.Config`. - ## You also need to import the `parsecfg` module to gain access to this object. - ## The `os-release` file is an official Freedesktop.org open standard. - ## Available in Linux and BSD distributions, except Android and Android-based Linux. - ## `os-release` file is not available on Windows and OS X by design. - ## * https://www.freedesktop.org/software/systemd/man/os-release.html - runnableExamples: - import std/parsecfg - when defined(linux): - let data = osReleaseFile() - echo "OS name: ", data.getSectionValue("", "NAME") ## the data is up to each distro. - - # We do not use a {.strdefine.} because Standard says it *must* be that path. - for osReleaseFile in ["/etc/os-release", "/usr/lib/os-release"]: - if fileExists(osReleaseFile): - return loadConfig(osReleaseFile) - raise newException(IOError, "File not found: /etc/os-release, /usr/lib/os-release") diff --git a/lib/posix/termios.nim b/lib/posix/termios.nim index f755c720d..6a7ffb33e 100644 --- a/lib/posix/termios.nim +++ b/lib/posix/termios.nim @@ -7,6 +7,7 @@ # distribution, for details about the copyright. # +{.deadCodeElim: on.} # dce option deprecated import posix type @@ -237,11 +238,8 @@ proc tcFlow*(fd: cint; action: cint): cint {.importc: "tcflow", header: "".} # Get process group ID for session leader for controlling terminal FD. -# Window size ioctl. Solaris based systems have an uncommen place for this. -when defined(solaris) or defined(sunos): - var TIOCGWINSZ*{.importc, header: "".}: culong -else: - var TIOCGWINSZ*{.importc, header: "".}: culong +# Window size ioctl. Should work on on any Unix that xterm has been ported to. +var TIOCGWINSZ*{.importc, header: "".}: culong when defined(nimHasStyleChecks): {.push styleChecks: off.} diff --git a/lib/prelude.nim b/lib/prelude.nim new file mode 100644 index 000000000..940864207 --- /dev/null +++ b/lib/prelude.nim @@ -0,0 +1,23 @@ +# +# +# Nim's Runtime Library +# (c) Copyright 2012 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +## This is an include file that simply imports common modules for your +## convenience: +## +## .. code-block:: nim +## include prelude +## +## Same as: +## +## .. code-block:: nim +## import os, strutils, times, parseutils, parseopt, hashes, tables, sets + +import os, strutils, times, parseutils, parseopt, hashes, tables, sets + + diff --git a/lib/pure/algorithm.nim b/lib/pure/algorithm.nim index 65402e9fb..67df2a7c0 100644 --- a/lib/pure/algorithm.nim +++ b/lib/pure/algorithm.nim @@ -7,64 +7,62 @@ # distribution, for details about the copyright. # -## This module implements some common generic algorithms on `openArray`s. +## This module implements some common generic algorithms. ## ## Basic usage ## =========== ## - -runnableExamples: - type People = tuple - year: int - name: string - - var a: seq[People] - - a.add((2000, "John")) - a.add((2005, "Marie")) - a.add((2010, "Jane")) - - # Sorting with default system.cmp - a.sort() - assert a == @[(year: 2000, name: "John"), (year: 2005, name: "Marie"), - (year: 2010, name: "Jane")] - - proc myCmp(x, y: People): int = - cmp(x.name, y.name) - - # Sorting with custom proc - a.sort(myCmp) - assert a == @[(year: 2010, name: "Jane"), (year: 2000, name: "John"), - (year: 2005, name: "Marie")] - +## .. code-block:: +## import algorithm +## +## type People = tuple +## year: int +## name: string +## +## var a: seq[People] +## +## a.add((2000, "John")) +## a.add((2005, "Marie")) +## a.add((2010, "Jane")) +## +## # Sorting with default system.cmp +## a.sort() +## assert a == @[(year: 2000, name: "John"), (year: 2005, name: "Marie"), +## (year: 2010, name: "Jane")] +## +## proc myCmp(x, y: People): int = +## if x.name < y.name: -1 +## elif x.name == y.name: 0 +## else: 1 +## +## # Sorting with custom proc +## a.sort(myCmp) +## assert a == @[(year: 2010, name: "Jane"), (year: 2000, name: "John"), +## (year: 2005, name: "Marie")] +## +## ## See also ## ======== ## * `sequtils module`_ for working with the built-in seq type ## * `tables module`_ for sorting tables -import std/private/since - -when defined(nimPreviewSlimSystem): - import std/assertions - - type SortOrder* = enum Descending, Ascending proc `*`*(x: int, order: SortOrder): int {.inline.} = - ## Flips the sign of `x` if `order == Descending`. - ## If `order == Ascending` then `x` is returned. + ## Flips ``x`` if ``order == Descending``. + ## If ``order == Ascending`` then ``x`` is returned. ## - ## `x` is supposed to be the result of a comparator, i.e. - ## | `< 0` for *less than*, - ## | `== 0` for *equal*, - ## | `> 0` for *greater than*. + ## ``x`` is supposed to be the result of a comparator, i.e. + ## | ``< 0`` for *less than*, + ## | ``== 0`` for *equal*, + ## | ``> 0`` for *greater than*. runnableExamples: - assert -123 * Descending == 123 - assert 123 * Descending == -123 - assert -123 * Ascending == -123 - assert 123 * Ascending == 123 + assert `*`(-123, Descending) == 123 + assert `*`(123, Descending) == -123 + assert `*`(-123, Ascending) == -123 + assert `*`(123, Ascending) == 123 var y = order.ord - 1 result = (x xor y) - y @@ -75,20 +73,20 @@ template fillImpl[T](a: var openArray[T], first, last: int, value: T) = inc(x) proc fill*[T](a: var openArray[T], first, last: Natural, value: T) = - ## Assigns `value` to all elements of the slice `a[first..last]`. + ## Fills the slice ``a[first..last]`` with ``value``. ## - ## If an invalid range is passed, it raises `IndexDefect`. + ## If an invalid range is passed, it raises IndexError. runnableExamples: var a: array[6, int] a.fill(1, 3, 9) assert a == [0, 9, 9, 9, 0, 0] a.fill(3, 5, 7) assert a == [0, 9, 9, 7, 7, 7] - doAssertRaises(IndexDefect, a.fill(1, 7, 9)) + doAssertRaises(IndexError, a.fill(1, 7, 9)) fillImpl(a, first, last, value) proc fill*[T](a: var openArray[T], value: T) = - ## Assigns `value` to all elements of the container `a`. + ## Fills the container ``a`` with ``value``. runnableExamples: var a: array[6, int] a.fill(9) @@ -99,20 +97,20 @@ proc fill*[T](a: var openArray[T], value: T) = proc reverse*[T](a: var openArray[T], first, last: Natural) = - ## Reverses the slice `a[first..last]`. + ## Reverses the slice ``a[first..last]``. ## - ## If an invalid range is passed, it raises `IndexDefect`. + ## If an invalid range is passed, it raises IndexError. ## ## **See also:** - ## * `reversed proc<#reversed,openArray[T],Natural,int>`_ reverse a slice and returns a `seq[T]` - ## * `reversed proc<#reversed,openArray[T]>`_ reverse and returns a `seq[T]` + ## * `reversed proc<#reversed,openArray[T],Natural,int>`_ reverse a slice and returns a ``seq[T]`` + ## * `reversed proc<#reversed,openArray[T]>`_ reverse and returns a ``seq[T]`` runnableExamples: var a = [1, 2, 3, 4, 5, 6] a.reverse(1, 3) assert a == [1, 4, 3, 2, 5, 6] a.reverse(1, 3) assert a == [1, 2, 3, 4, 5, 6] - doAssertRaises(IndexDefect, a.reverse(1, 7)) + doAssertRaises(IndexError, a.reverse(1, 7)) var x = first var y = last while x < y: @@ -121,63 +119,74 @@ proc reverse*[T](a: var openArray[T], first, last: Natural) = inc(x) proc reverse*[T](a: var openArray[T]) = - ## Reverses the contents of the container `a`. + ## Reverses the contents of the container ``a``. ## ## **See also:** - ## * `reversed proc<#reversed,openArray[T],Natural,int>`_ reverse a slice and returns a `seq[T]` - ## * `reversed proc<#reversed,openArray[T]>`_ reverse and returns a `seq[T]` + ## * `reversed proc<#reversed,openArray[T],Natural,int>`_ reverse a slice and returns a ``seq[T]`` + ## * `reversed proc<#reversed,openArray[T]>`_ reverse and returns a ``seq[T]`` runnableExamples: var a = [1, 2, 3, 4, 5, 6] a.reverse() assert a == [6, 5, 4, 3, 2, 1] a.reverse() assert a == [1, 2, 3, 4, 5, 6] - # the max is needed, since a.high is -1 if a is empty reverse(a, 0, max(0, a.high)) -proc reversed*[T](a: openArray[T]): seq[T] {.inline.} = - ## Returns the elements of `a` in reverse order. +proc reversed*[T](a: openArray[T], first: Natural, last: int): seq[T] = + ## Returns the reverse of the slice ``a[first..last]``. + ## + ## If an invalid range is passed, it raises IndexError. ## ## **See also:** + ## * `reverse proc<#reverse,openArray[T],Natural,Natural>`_ reverse a slice ## * `reverse proc<#reverse,openArray[T]>`_ runnableExamples: - assert [10, 11, 12].reversed == @[12, 11, 10] - assert seq[string].default.reversed == @[] - let n = a.len - result.setLen(n) - for i in 0..= first-1 + var i = last - first + var x = first.int + result = newSeq[T](i + 1) + while i >= 0: + result[i] = a[x] + dec(i) + inc(x) -proc reversed*[T](a: openArray[T], first: Natural, last: int): seq[T] - {.inline, deprecated: "use: `reversed(toOpenArray(a, first, last))`".} = - reversed(toOpenArray(a, first, last)) - -when defined(nimHasEffectsOf): - {.experimental: "strictEffects".} -else: - {.pragma: effectsOf.} +proc reversed*[T](a: openArray[T]): seq[T] = + ## Returns the reverse of the container ``a``. + ## + ## **See also:** + ## * `reverse proc<#reverse,openArray[T],Natural,Natural>`_ reverse a slice + ## * `reverse proc<#reverse,openArray[T]>`_ + runnableExamples: + let + a = [1, 2, 3, 4, 5, 6] + b = reversed(a) + assert b == @[6, 5, 4, 3, 2, 1] + reversed(a, 0, a.high) proc binarySearch*[T, K](a: openArray[T], key: K, - cmp: proc (x: T, y: K): int {.closure.}): int {.effectsOf: cmp.} = - ## Binary search for `key` in `a`. Return the index of `key` or -1 if not found. - ## Assumes that `a` is sorted according to `cmp`. + cmp: proc (x: T, y: K): int {.closure.}): int = + ## Binary search for ``key`` in ``a``. Returns -1 if not found. ## - ## `cmp` is the comparator function to use, the expected return values are - ## the same as those of system.cmp. + ## ``cmp`` is the comparator function to use, the expected return values are + ## the same as that of system.cmp. runnableExamples: assert binarySearch(["a", "b", "c", "d"], "d", system.cmp[string]) == 3 - assert binarySearch(["a", "b", "c", "d"], "c", system.cmp[string]) == 2 - let len = a.len - - if len == 0: + assert binarySearch(["a", "b", "d", "c"], "d", system.cmp[string]) == 2 + if a.len == 0: return -1 + let len = a.len + if len == 1: if cmp(a[0], key) == 0: return 0 else: return -1 - result = 0 if (len and (len - 1)) == 0: # when `len` is a power of 2, a faster shr can be used. var step = len shr 1 @@ -188,7 +197,7 @@ proc binarySearch*[T, K](a: openArray[T], key: K, if cmpRes == 0: return i - if cmpRes < 0: + if cmpRes < 1: result = i step = step shr 1 if cmp(a[result], key) != 0: result = -1 @@ -208,32 +217,34 @@ proc binarySearch*[T, K](a: openArray[T], key: K, if result >= len or cmp(a[result], key) != 0: result = -1 proc binarySearch*[T](a: openArray[T], key: T): int = - ## Binary search for `key` in `a`. Return the index of `key` or -1 if not found. - ## Assumes that `a` is sorted. + ## Binary search for ``key`` in ``a``. Returns -1 if not found. runnableExamples: assert binarySearch([0, 1, 2, 3, 4], 4) == 4 - assert binarySearch([0, 1, 2, 3, 4], 2) == 2 + assert binarySearch([0, 1, 4, 2, 3], 4) == 2 + binarySearch(a, key, cmp[T]) + +proc smartBinarySearch*[T](a: openArray[T], key: T): int {.deprecated: + "Deprecated since v0.18.1; Use 'binarySearch'".} = binarySearch(a, key, cmp[T]) const onlySafeCode = true -proc lowerBound*[T, K](a: openArray[T], key: K, - cmp: proc(x: T, k: K): int {.closure.}): int {.effectsOf: cmp.} = - ## Returns the index of the first element in `a` that is not less than - ## (i.e. greater or equal to) `key`, or last if no such element is found. +proc lowerBound*[T, K](a: openArray[T], key: K, cmp: proc(x: T, k: K): int {. + closure.}): int = + ## Returns a position to the first element in the ``a`` that is greater than + ## ``key``, or last if no such element is found. ## In other words if you have a sorted sequence and you call - ## `insert(thing, elm, lowerBound(thing, elm))` + ## ``insert(thing, elm, lowerBound(thing, elm))`` ## the sequence will still be sorted. - ## Assumes that `a` is sorted according to `cmp`. ## - ## If an invalid range is passed, it raises `IndexDefect`. + ## If an invalid range is passed, it raises IndexError. ## - ## This version uses `cmp` to compare the elements. - ## The expected return values are the same as those of `system.cmp`. + ## The version uses ``cmp`` to compare the elements. + ## The expected return values are the same as that of ``system.cmp``. ## ## **See also:** - ## * `upperBound proc<#upperBound,openArray[T],K,proc(T,K)>`_ sorted by `cmp` in the specified order + ## * `upperBound proc<#upperBound,openArray[T],K,proc(T,K)>`_ sorted by ``cmp`` in the specified order ## * `upperBound proc<#upperBound,openArray[T],T>`_ runnableExamples: var arr = @[1, 2, 3, 5, 6, 7, 8, 9] @@ -255,35 +266,33 @@ proc lowerBound*[T, K](a: openArray[T], key: K, count = step proc lowerBound*[T](a: openArray[T], key: T): int = lowerBound(a, key, cmp[T]) - ## Returns the index of the first element in `a` that is not less than - ## (i.e. greater or equal to) `key`, or last if no such element is found. + ## Returns a position to the first element in the ``a`` that is greater than + ## ``key``, or last if no such element is found. ## In other words if you have a sorted sequence and you call - ## `insert(thing, elm, lowerBound(thing, elm))` + ## ``insert(thing, elm, lowerBound(thing, elm))`` ## the sequence will still be sorted. - ## Assumes that `a` is sorted. ## - ## This version uses the default comparison function `cmp`. + ## The version uses the default comparison function ``cmp``. ## ## **See also:** - ## * `upperBound proc<#upperBound,openArray[T],K,proc(T,K)>`_ sorted by `cmp` in the specified order + ## * `upperBound proc<#upperBound,openArray[T],K,proc(T,K)>`_ sorted by ``cmp`` in the specified order ## * `upperBound proc<#upperBound,openArray[T],T>`_ -proc upperBound*[T, K](a: openArray[T], key: K, - cmp: proc(x: T, k: K): int {.closure.}): int {.effectsOf: cmp.} = - ## Returns the index of the first element in `a` that is greater than - ## `key`, or last if no such element is found. +proc upperBound*[T, K](a: openArray[T], key: K, cmp: proc(x: T, k: K): int {. + closure.}): int = + ## Returns a position to the first element in the ``a`` that is not less + ## (i.e. greater or equal to) than ``key``, or last if no such element is found. ## In other words if you have a sorted sequence and you call - ## `insert(thing, elm, upperBound(thing, elm))` + ## ``insert(thing, elm, upperBound(thing, elm))`` ## the sequence will still be sorted. - ## Assumes that `a` is sorted according to `cmp`. ## - ## If an invalid range is passed, it raises `IndexDefect`. + ## If an invalid range is passed, it raises IndexError. ## - ## This version uses `cmp` to compare the elements. The expected - ## return values are the same as those of `system.cmp`. + ## The version uses ``cmp`` to compare the elements. The expected + ## return values are the same as that of ``system.cmp``. ## ## **See also:** - ## * `lowerBound proc<#lowerBound,openArray[T],K,proc(T,K)>`_ sorted by `cmp` in the specified order + ## * `lowerBound proc<#lowerBound,openArray[T],K,proc(T,K)>`_ sorted by ``cmp`` in the specified order ## * `lowerBound proc<#lowerBound,openArray[T],T>`_ runnableExamples: var arr = @[1, 2, 3, 5, 6, 7, 8, 9] @@ -305,20 +314,19 @@ proc upperBound*[T, K](a: openArray[T], key: K, count = step proc upperBound*[T](a: openArray[T], key: T): int = upperBound(a, key, cmp[T]) - ## Returns the index of the first element in `a` that is greater than - ## `key`, or last if no such element is found. + ## Returns a position to the first element in the ``a`` that is not less + ## (i.e. greater or equal to) than ``key``, or last if no such element is found. ## In other words if you have a sorted sequence and you call - ## `insert(thing, elm, upperBound(thing, elm))` + ## ``insert(thing, elm, upperBound(thing, elm))`` ## the sequence will still be sorted. - ## Assumes that `a` is sorted. ## - ## This version uses the default comparison function `cmp`. + ## The version uses the default comparison function ``cmp``. ## ## **See also:** - ## * `lowerBound proc<#lowerBound,openArray[T],K,proc(T,K)>`_ sorted by `cmp` in the specified order + ## * `lowerBound proc<#lowerBound,openArray[T],K,proc(T,K)>`_ sorted by ``cmp`` in the specified order ## * `lowerBound proc<#lowerBound,openArray[T],T>`_ -template `<-`(a, b) = +template `<-` (a, b) = when defined(gcDestructors): a = move b elif onlySafeCode: @@ -326,12 +334,12 @@ template `<-`(a, b) = else: copyMem(addr(a), addr(b), sizeof(T)) -proc mergeAlt[T](a, b: var openArray[T], lo, m, hi: int, - cmp: proc (x, y: T): int {.closure.}, order: SortOrder) {.effectsOf: cmp.} = - # Optimization: If max(left) <= min(right) there is nothing to do! - # 1 2 3 4 ## 5 6 7 8 +proc merge[T](a, b: var openArray[T], lo, m, hi: int, + cmp: proc (x, y: T): int {.closure.}, order: SortOrder) = + # optimization: If max(left) <= min(right) there is nothing to do! + # 1 2 3 4 ## 5 6 7 8 # -> O(n) for sorted arrays. - # On random data this saves up to 40% of mergeAlt calls. + # On random data this safes up to 40% of merge calls if cmp(a[m], a[m+1]) * order <= 0: return var j = lo # copy a[j..m] into b: @@ -367,38 +375,37 @@ proc mergeAlt[T](a, b: var openArray[T], lo, m, hi: int, func sort*[T](a: var openArray[T], cmp: proc (x, y: T): int {.closure.}, - order = SortOrder.Ascending) {.effectsOf: cmp.} = + order = SortOrder.Ascending) = ## Default Nim sort (an implementation of merge sort). The sorting - ## is guaranteed to be stable (that is, equal elements stay in the same order) - ## and the worst case is guaranteed to be O(n log n). - ## Sorts by `cmp` in the specified `order`. + ## is guaranteed to be stable and the worst case is guaranteed to + ## be O(n log n). ## ## The current implementation uses an iterative ## mergesort to achieve this. It uses a temporary sequence of - ## length `a.len div 2`. If you do not wish to provide your own - ## `cmp`, you may use `system.cmp` or instead call the overloaded - ## version of `sort`, which uses `system.cmp`. + ## length ``a.len div 2``. If you do not wish to provide your own + ## ``cmp``, you may use ``system.cmp`` or instead call the overloaded + ## version of ``sort``, which uses ``system.cmp``. ## - ## ```nim - ## sort(myIntArray, system.cmp[int]) - ## # do not use cmp[string] here as we want to use the specialized - ## # overload: - ## sort(myStrArray, system.cmp) - ## ``` + ## .. code-block:: nim + ## + ## sort(myIntArray, system.cmp[int]) + ## # do not use cmp[string] here as we want to use the specialized + ## # overload: + ## sort(myStrArray, system.cmp) ## ## You can inline adhoc comparison procs with the `do notation ## `_. Example: ## - ## ```nim + ## .. code-block:: nim + ## ## people.sort do (x, y: Person) -> int: ## result = cmp(x.surname, y.surname) ## if result == 0: ## result = cmp(x.name, y.name) - ## ``` ## ## **See also:** ## * `sort proc<#sort,openArray[T]>`_ - ## * `sorted proc<#sorted,openArray[T],proc(T,T)>`_ sorted by `cmp` in the specified order + ## * `sorted proc<#sorted,openArray[T],proc(T,T)>`_ sorted by ``cmp`` in the specified order ## * `sorted proc<#sorted,openArray[T]>`_ ## * `sortedByIt template<#sortedByIt.t,untyped,untyped>`_ runnableExamples: @@ -409,28 +416,29 @@ func sort*[T](a: var openArray[T], sort(d, myCmp) assert d == ["fo", "qux", "boo", "barr"] var n = a.len - var b = newSeq[T](n div 2) + var b: seq[T] + newSeq(b, n div 2) var s = 1 while s < n: var m = n-1-s while m >= 0: - mergeAlt(a, b, max(m-s+1, 0), m, m+s, cmp, order) + merge(a, b, max(m-s+1, 0), m, m+s, cmp, order) dec(m, s*2) s = s*2 proc sort*[T](a: var openArray[T], order = SortOrder.Ascending) = sort[T](a, system.cmp[T], order) - ## Shortcut version of `sort` that uses `system.cmp[T]` as the comparison function. + ## Shortcut version of ``sort`` that uses ``system.cmp[T]`` as the comparison function. ## ## **See also:** ## * `sort func<#sort,openArray[T],proc(T,T)>`_ - ## * `sorted proc<#sorted,openArray[T],proc(T,T)>`_ sorted by `cmp` in the specified order + ## * `sorted proc<#sorted,openArray[T],proc(T,T)>`_ sorted by ``cmp`` in the specified order ## * `sorted proc<#sorted,openArray[T]>`_ ## * `sortedByIt template<#sortedByIt.t,untyped,untyped>`_ proc sorted*[T](a: openArray[T], cmp: proc(x, y: T): int {.closure.}, - order = SortOrder.Ascending): seq[T] {.effectsOf: cmp.} = - ## Returns `a` sorted by `cmp` in the specified `order`. + order = SortOrder.Ascending): seq[T] = + ## Returns ``a`` sorted by ``cmp`` in the specified ``order``. ## ## **See also:** ## * `sort func<#sort,openArray[T],proc(T,T)>`_ @@ -451,7 +459,7 @@ proc sorted*[T](a: openArray[T], cmp: proc(x, y: T): int {.closure.}, sort(result, cmp, order) proc sorted*[T](a: openArray[T], order = SortOrder.Ascending): seq[T] = - ## Shortcut version of `sorted` that uses `system.cmp[T]` as the comparison function. + ## Shortcut version of ``sorted`` that uses ``system.cmp[T]`` as the comparison function. ## ## **See also:** ## * `sort func<#sort,openArray[T],proc(T,T)>`_ @@ -469,18 +477,18 @@ proc sorted*[T](a: openArray[T], order = SortOrder.Ascending): seq[T] = sorted[T](a, system.cmp[T], order) template sortedByIt*(seq1, op: untyped): untyped = - ## Convenience template around the `sorted` proc to reduce typing. + ## Convenience template around the ``sorted`` proc to reduce typing. ## - ## The template injects the `it` variable which you can use directly in an + ## The template injects the ``it`` variable which you can use directly in an ## expression. ## - ## Because the underlying `cmp()` is defined for tuples you can also do + ## Because the underlying ``cmp()`` is defined for tuples you can do ## a nested sort. ## ## **See also:** ## * `sort func<#sort,openArray[T],proc(T,T)>`_ ## * `sort proc<#sort,openArray[T]>`_ - ## * `sorted proc<#sorted,openArray[T],proc(T,T)>`_ sorted by `cmp` in the specified order + ## * `sorted proc<#sorted,openArray[T],proc(T,T)>`_ sorted by ``cmp`` in the specified order ## * `sorted proc<#sorted,openArray[T]>`_ runnableExamples: type Person = tuple[name: string, age: int] @@ -496,7 +504,7 @@ template sortedByIt*(seq1, op: untyped): untyped = # Nested sort assert people.sortedByIt((it.age, it.name)) == @[(name: "p2", age: 20), (name: "p3", age: 30), (name: "p4", age: 30), (name: "p1", age: 60)] - var result = sorted(seq1, proc(x, y: typeof(items(seq1), typeOfIter)): int = + var result = sorted(seq1, proc(x, y: type(seq1[0])): int = var it {.inject.} = x let a = op it = y @@ -506,10 +514,10 @@ template sortedByIt*(seq1, op: untyped): untyped = func isSorted*[T](a: openArray[T], cmp: proc(x, y: T): int {.closure.}, - order = SortOrder.Ascending): bool {.effectsOf: cmp.} = - ## Checks to see whether `a` is already sorted in `order` - ## using `cmp` for the comparison. The parameters are identical - ## to `sort`. Requires O(n) time. + order = SortOrder.Ascending): bool = + ## Checks to see whether ``a`` is already sorted in ``order`` + ## using ``cmp`` for the comparison. Parameters identical + ## to ``sort``. Requires O(n) time. ## ## **See also:** ## * `isSorted proc<#isSorted,openArray[T]>`_ @@ -532,7 +540,7 @@ func isSorted*[T](a: openArray[T], return false proc isSorted*[T](a: openArray[T], order = SortOrder.Ascending): bool = - ## Shortcut version of `isSorted` that uses `system.cmp[T]` as the comparison function. + ## Shortcut version of ``isSorted`` that uses ``system.cmp[T]`` as the comparison function. ## ## **See also:** ## * `isSorted func<#isSorted,openArray[T],proc(T,T)>`_ @@ -551,142 +559,47 @@ proc isSorted*[T](a: openArray[T], order = SortOrder.Ascending): bool = assert isSorted(e) == false isSorted(a, system.cmp[T], order) -proc merge*[T]( - result: var seq[T], - x, y: openArray[T], cmp: proc(x, y: T): int {.closure.} -) {.since: (1, 5, 1), effectsOf: cmp.} = - ## Merges two sorted `openArray`. `x` and `y` are assumed to be sorted. - ## If you do not wish to provide your own `cmp`, - ## you may use `system.cmp` or instead call the overloaded - ## version of `merge`, which uses `system.cmp`. - ## - ## .. note:: The original data of `result` is not cleared, - ## new data is appended to `result`. - ## - ## **See also:** - ## * `merge proc<#merge,seq[T],openArray[T],openArray[T]>`_ - runnableExamples: - let x = @[1, 3, 6] - let y = @[2, 3, 4] - - block: - var merged = @[7] # new data is appended to merged sequence - merged.merge(x, y, system.cmp[int]) - assert merged == @[7, 1, 2, 3, 3, 4, 6] - - block: - var merged = @[7] # if you only want new data, clear merged sequence first - merged.setLen(0) - merged.merge(x, y, system.cmp[int]) - assert merged.isSorted - assert merged == @[1, 2, 3, 3, 4, 6] - - import std/sugar - - var res: seq[(int, int)] - res.merge([(1, 1)], [(1, 2)], (a, b) => a[0] - b[0]) - assert res == @[(1, 1), (1, 2)] - - assert seq[int].default.dup(merge([1, 3], [2, 4])) == @[1, 2, 3, 4] - - let - sizeX = x.len - sizeY = y.len - oldLen = result.len - - result.setLen(oldLen + sizeX + sizeY) - - var - ix = 0 - iy = 0 - i = oldLen - - while true: - if ix == sizeX: - while iy < sizeY: - result[i] = y[iy] - inc i - inc iy - return - - if iy == sizeY: - while ix < sizeX: - result[i] = x[ix] - inc i - inc ix - return - - let itemX = x[ix] - let itemY = y[iy] - - if cmp(itemX, itemY) > 0: # to have a stable sort - result[i] = itemY - inc iy - else: - result[i] = itemX - inc ix - - inc i - -proc merge*[T](result: var seq[T], x, y: openArray[T]) {.inline, since: (1, 5, 1).} = - ## Shortcut version of `merge` that uses `system.cmp[T]` as the comparison function. - ## - ## **See also:** - ## * `merge proc<#merge,seq[T],openArray[T],openArray[T],proc(T,T)>`_ - runnableExamples: - let x = [5, 10, 15, 20, 25] - let y = [50, 40, 30, 20, 10].sorted - - var merged: seq[int] - merged.merge(x, y) - assert merged.isSorted - assert merged == @[5, 10, 10, 15, 20, 20, 25, 30, 40, 50] - merge(result, x, y, system.cmp) - proc product*[T](x: openArray[seq[T]]): seq[seq[T]] = - ## Produces the Cartesian product of the array. - ## Every element of the result is a combination of one element from each seq in `x`, - ## with the ith element coming from `x[i]`. - ## - ## .. warning:: complexity may explode. + ## Produces the Cartesian product of the array. Warning: complexity + ## may explode. runnableExamples: assert product(@[@[1], @[2]]) == @[@[1, 2]] assert product(@[@["A", "K"], @["Q"]]) == @[@["K", "Q"], @["A", "Q"]] - let xLen = x.len result = newSeq[seq[T]]() - if xLen == 0: + if x.len == 0: return - if xLen == 1: + if x.len == 1: result = @x return var - indices = newSeq[int](xLen) - initial = newSeq[int](xLen) + indexes = newSeq[int](x.len) + initial = newSeq[int](x.len) index = 0 - var next = newSeq[T](xLen) - for i in 0 ..< xLen: + var next = newSeq[T]() + next.setLen(x.len) + for i in 0..(x.len-1): if len(x[i]) == 0: return - initial[i] = len(x[i]) - 1 - indices = initial + initial[i] = len(x[i])-1 + indexes = initial while true: - while indices[index] == -1: - indices[index] = initial[index] + while indexes[index] == -1: + indexes[index] = initial[index] index += 1 - if index == xLen: return - indices[index] -= 1 - for ni, i in indices: + if index == x.len: return + indexes[index] -= 1 + for ni, i in indexes: next[ni] = x[ni][i] result.add(next) index = 0 - indices[index] -= 1 + indexes[index] -= 1 proc nextPermutation*[T](x: var openArray[T]): bool {.discardable.} = - ## Calculates the next lexicographic permutation, directly modifying `x`. + ## Calculates the next lexicographic permutation, directly modifying ``x``. ## The result is whether a permutation happened, otherwise we have reached ## the last-ordered permutation. ## ## If you start with an unsorted array/seq, the repeated permutations - ## will **not** give you all permutations but stop with the last. + ## will **not** give you all permutations but stop with last. ## ## **See also:** ## * `prevPermutation proc<#prevPermutation,openArray[T]>`_ @@ -722,7 +635,7 @@ proc nextPermutation*[T](x: var openArray[T]): bool {.discardable.} = proc prevPermutation*[T](x: var openArray[T]): bool {.discardable.} = ## Calculates the previous lexicographic permutation, directly modifying - ## `x`. The result is whether a permutation happened, otherwise we have + ## ``x``. The result is whether a permutation happened, otherwise we have ## reached the first-ordered permutation. ## ## **See also:** @@ -755,9 +668,38 @@ proc prevPermutation*[T](x: var openArray[T]): bool {.discardable.} = result = true +when isMainModule: + # Tests for lowerBound + var arr = @[1, 2, 3, 5, 6, 7, 8, 9] + assert arr.lowerBound(0) == 0 + assert arr.lowerBound(4) == 3 + assert arr.lowerBound(5) == 3 + assert arr.lowerBound(10) == 8 + arr = @[1, 5, 10] + assert arr.lowerBound(4) == 1 + assert arr.lowerBound(5) == 1 + assert arr.lowerBound(6) == 2 + # Tests for isSorted + var srt1 = [1, 2, 3, 4, 4, 4, 4, 5] + var srt2 = ["iello", "hello"] + var srt3 = [1.0, 1.0, 1.0] + var srt4: seq[int] + assert srt1.isSorted(cmp) == true + assert srt2.isSorted(cmp) == false + assert srt3.isSorted(cmp) == true + assert srt4.isSorted(cmp) == true + var srtseq = newSeq[int]() + assert srtseq.isSorted(cmp) == true + # Tests for reversed + var arr1 = @[0, 1, 2, 3, 4] + assert arr1.reversed() == @[4, 3, 2, 1, 0] + for i in 0 .. high(arr1): + assert arr1.reversed(0, i) == arr1.reversed()[high(arr1) - i .. high(arr1)] + assert arr1.reversed(i, high(arr1)) == arr1.reversed()[0 .. high(arr1) - i] + + proc rotateInternal[T](arg: var openArray[T]; first, middle, last: int): int = - ## A port of std::rotate from C++. - ## Ported from [this reference](http://www.cplusplus.com/reference/algorithm/rotate/). + ## A port of std::rotate from c++. Ported from `this reference `_. result = first + last - middle if first == middle or middle == last: @@ -796,8 +738,7 @@ proc rotateInternal[T](arg: var openArray[T]; first, middle, last: int): int = next = mMiddle proc rotatedInternal[T](arg: openArray[T]; first, middle, last: int): seq[T] = - let argLen = arg.len - result = newSeq[T](argLen) + result = newSeq[T](arg.len) for i in 0 ..< first: result[i] = arg[i] let n = last - middle @@ -806,34 +747,34 @@ proc rotatedInternal[T](arg: openArray[T]; first, middle, last: int): seq[T] = result[first+i] = arg[middle+i] for i in 0 ..< m: result[first+n+i] = arg[first+i] - for i in last ..< argLen: + for i in last ..< arg.len: result[i] = arg[i] proc rotateLeft*[T](arg: var openArray[T]; slice: HSlice[int, int]; - dist: int): int {.discardable.} = + dist: int): int {.discardable.} = ## Performs a left rotation on a range of elements. If you want to rotate - ## right, use a negative `dist`. Specifically, `rotateLeft` rotates - ## the elements at `slice` by `dist` positions. + ## right, use a negative ``dist``. Specifically, ``rotateLeft`` rotates + ## the elements at ``slice`` by ``dist`` positions. ## - ## | The element at index `slice.a + dist` will be at index `slice.a`. - ## | The element at index `slice.b` will be at `slice.a + dist - 1`. - ## | The element at index `slice.a` will be at `slice.b + 1 - dist`. - ## | The element at index `slice.a + dist - 1` will be at `slice.b`. + ## | The element at index ``slice.a + dist`` will be at index ``slice.a``. + ## | The element at index ``slice.b`` will be at ``slice.a + dist -1``. + ## | The element at index ``slice.a`` will be at ``slice.b + 1 - dist``. + ## | The element at index ``slice.a + dist - 1`` will be at ``slice.b``. ## - ## Elements outside of `slice` will be left unchanged. - ## The time complexity is linear to `slice.b - slice.a + 1`. - ## If an invalid range (`HSlice`) is passed, it raises `IndexDefect`. + ## Elements outside of ``slice`` will be left unchanged. + ## The time complexity is linear to ``slice.b - slice.a + 1``. + ## If an invalid range (``HSlice``) is passed, it raises IndexError. ## - ## `slice` - ## : The indices of the element range that should be rotated. + ## ``slice`` + ## The indices of the element range that should be rotated. ## - ## `dist` - ## : The distance in amount of elements that the data should be rotated. + ## ``dist`` + ## The distance in amount of elements that the data should be rotated. ## Can be negative, can be any number. ## ## **See also:** ## * `rotateLeft proc<#rotateLeft,openArray[T],int>`_ for a version which rotates the whole container - ## * `rotatedLeft proc<#rotatedLeft,openArray[T],HSlice[int,int],int>`_ for a version which returns a `seq[T]` + ## * `rotatedLeft proc<#rotatedLeft,openArray[T],HSlice[int,int],int>`_ for a version which returns a ``seq[T]`` runnableExamples: var a = [0, 1, 2, 3, 4, 5] a.rotateLeft(1 .. 4, 3) @@ -842,19 +783,18 @@ proc rotateLeft*[T](arg: var openArray[T]; slice: HSlice[int, int]; assert a == [0, 3, 4, 1, 2, 5] a.rotateLeft(1 .. 4, -3) assert a == [0, 4, 1, 2, 3, 5] - doAssertRaises(IndexDefect, a.rotateLeft(1 .. 7, 2)) + doAssertRaises(IndexError, a.rotateLeft(1 .. 7, 2)) let sliceLen = slice.b + 1 - slice.a let distLeft = ((dist mod sliceLen) + sliceLen) mod sliceLen - arg.rotateInternal(slice.a, slice.a + distLeft, slice.b + 1) + arg.rotateInternal(slice.a, slice.a+distLeft, slice.b + 1) proc rotateLeft*[T](arg: var openArray[T]; dist: int): int {.discardable.} = - ## Same as `rotateLeft`, but with default arguments for slice, - ## so that this procedure operates on the entire - ## `arg`, and not just on a part of it. + ## Default arguments for slice, so that this procedure operates on the entire + ## ``arg``, and not just on a part of it. ## ## **See also:** ## * `rotateLeft proc<#rotateLeft,openArray[T],HSlice[int,int],int>`_ for a version which rotates a range - ## * `rotatedLeft proc<#rotatedLeft,openArray[T],int>`_ for a version which returns a `seq[T]` + ## * `rotatedLeft proc<#rotatedLeft,openArray[T],int>`_ for a version which returns a ``seq[T]`` runnableExamples: var a = [1, 2, 3, 4, 5] a.rotateLeft(2) @@ -863,23 +803,23 @@ proc rotateLeft*[T](arg: var openArray[T]; dist: int): int {.discardable.} = assert a == [2, 3, 4, 5, 1] a.rotateLeft(-6) assert a == [1, 2, 3, 4, 5] - let argLen = arg.len - let distLeft = ((dist mod argLen) + argLen) mod argLen - arg.rotateInternal(0, distLeft, argLen) + let arglen = arg.len + let distLeft = ((dist mod arglen) + arglen) mod arglen + arg.rotateInternal(0, distLeft, arglen) proc rotatedLeft*[T](arg: openArray[T]; slice: HSlice[int, int], - dist: int): seq[T] = - ## Same as `rotateLeft`, just with the difference that it does - ## not modify the argument. It creates a new `seq` instead. + dist: int): seq[T] = + ## Same as ``rotateLeft``, just with the difference that it does + ## not modify the argument. It creates a new ``seq`` instead. ## - ## Elements outside of `slice` will be left unchanged. - ## If an invalid range (`HSlice`) is passed, it raises `IndexDefect`. + ## Elements outside of ``slice`` will be left unchanged. + ## If an invalid range (``HSlice``) is passed, it raises IndexError. ## - ## `slice` - ## : The indices of the element range that should be rotated. + ## ``slice`` + ## The indices of the element range that should be rotated. ## - ## `dist` - ## : The distance in amount of elements that the data should be rotated. + ## ``dist`` + ## The distance in amount of elements that the data should be rotated. ## Can be negative, can be any number. ## ## **See also:** @@ -895,11 +835,11 @@ proc rotatedLeft*[T](arg: openArray[T]; slice: HSlice[int, int], assert a == @[1, 5, 2, 3, 4] let sliceLen = slice.b + 1 - slice.a let distLeft = ((dist mod sliceLen) + sliceLen) mod sliceLen - arg.rotatedInternal(slice.a, slice.a + distLeft, slice.b + 1) + arg.rotatedInternal(slice.a, slice.a+distLeft, slice.b+1) proc rotatedLeft*[T](arg: openArray[T]; dist: int): seq[T] = - ## Same as `rotateLeft`, just with the difference that it does - ## not modify the argument. It creates a new `seq` instead. + ## Same as ``rotateLeft``, just with the difference that it does + ## not modify the argument. It creates a new ``seq`` instead. ## ## **See also:** ## * `rotateLeft proc<#rotateLeft,openArray[T],int>`_ for the in-place version of this proc @@ -912,6 +852,74 @@ proc rotatedLeft*[T](arg: openArray[T]; dist: int): seq[T] = assert a == @[2, 3, 4, 5, 1] a = rotatedLeft(a, -6) assert a == @[1, 2, 3, 4, 5] - let argLen = arg.len - let distLeft = ((dist mod argLen) + argLen) mod argLen - arg.rotatedInternal(0, distLeft, argLen) + let arglen = arg.len + let distLeft = ((dist mod arglen) + arglen) mod arglen + arg.rotatedInternal(0, distLeft, arg.len) + +when isMainModule: + var list = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + let list2 = list.rotatedLeft(1 ..< 9, 3) + let expected = [0, 4, 5, 6, 7, 8, 1, 2, 3, 9, 10] + + doAssert list.rotateLeft(1 ..< 9, 3) == 6 + doAssert list == expected + doAssert list2 == @expected + + var s0, s1, s2, s3, s4, s5 = "xxxabcdefgxxx" + + doAssert s0.rotateLeft(3 ..< 10, 3) == 7 + doAssert s0 == "xxxdefgabcxxx" + doAssert s1.rotateLeft(3 ..< 10, 2) == 8 + doAssert s1 == "xxxcdefgabxxx" + doAssert s2.rotateLeft(3 ..< 10, 4) == 6 + doAssert s2 == "xxxefgabcdxxx" + doAssert s3.rotateLeft(3 ..< 10, -3) == 6 + doAssert s3 == "xxxefgabcdxxx" + doAssert s4.rotateLeft(3 ..< 10, -10) == 6 + doAssert s4 == "xxxefgabcdxxx" + doAssert s5.rotateLeft(3 ..< 10, 11) == 6 + doAssert s5 == "xxxefgabcdxxx" + + block product: + doAssert product(newSeq[seq[int]]()) == newSeq[seq[int]](), "empty input" + doAssert product(@[newSeq[int](), @[], @[]]) == newSeq[seq[int]](), "bit more empty input" + doAssert product(@[@[1, 2]]) == @[@[1, 2]], "a simple case of one element" + doAssert product(@[@[1, 2], @[3, 4]]) == @[@[2, 4], @[1, 4], @[2, 3], @[1, + 3]], "two elements" + doAssert product(@[@[1, 2], @[3, 4], @[5, 6]]) == @[@[2, 4, 6], @[1, 4, 6], + @[2, 3, 6], @[1, 3, 6], @[2, 4, 5], @[1, 4, 5], @[2, 3, 5], @[1, 3, 5]], "three elements" + doAssert product(@[@[1, 2], @[]]) == newSeq[seq[int]](), "two elements, but one empty" + + block lowerBound: + doAssert lowerBound([1, 2, 4], 3, system.cmp[int]) == 2 + doAssert lowerBound([1, 2, 2, 3], 4, system.cmp[int]) == 4 + doAssert lowerBound([1, 2, 3, 10], 11) == 4 + + block upperBound: + doAssert upperBound([1, 2, 4], 3, system.cmp[int]) == 2 + doAssert upperBound([1, 2, 2, 3], 3, system.cmp[int]) == 4 + doAssert upperBound([1, 2, 3, 5], 3) == 3 + + block fillEmptySeq: + var s = newSeq[int]() + s.fill(0) + + block testBinarySearch: + var noData: seq[int] + doAssert binarySearch(noData, 7) == -1 + let oneData = @[1] + doAssert binarySearch(oneData, 1) == 0 + doAssert binarySearch(onedata, 7) == -1 + let someData = @[1, 3, 4, 7] + doAssert binarySearch(someData, 1) == 0 + doAssert binarySearch(somedata, 7) == 3 + doAssert binarySearch(someData, -1) == -1 + doAssert binarySearch(someData, 5) == -1 + doAssert binarySearch(someData, 13) == -1 + let moreData = @[1, 3, 5, 7, 4711] + doAssert binarySearch(moreData, -1) == -1 + doAssert binarySearch(moreData, 1) == 0 + doAssert binarySearch(moreData, 5) == 2 + doAssert binarySearch(moreData, 6) == -1 + doAssert binarySearch(moreData, 4711) == 4 + doAssert binarySearch(moreData, 4712) == -1 diff --git a/lib/pure/async.nim b/lib/pure/async.nim index 249c5f639..97b29f81d 100644 --- a/lib/pure/async.nim +++ b/lib/pure/async.nim @@ -1,9 +1,6 @@ -## Exports [asyncmacro](asyncmacro.html) and [asyncfutures](asyncfutures.html) for native backends, -## and [asyncjs](asyncjs.html) on the JS backend. - when defined(js): - import asyncjs - export asyncjs + import asyncjs + export asyncjs else: - import asyncmacro, asyncfutures - export asyncmacro, asyncfutures + import asyncmacro, asyncfutures + export asyncmacro, asyncfutures diff --git a/lib/pure/asyncdispatch.nim b/lib/pure/asyncdispatch.nim index 63062d8da..d724242d7 100644 --- a/lib/pure/asyncdispatch.nim +++ b/lib/pure/asyncdispatch.nim @@ -8,25 +8,25 @@ # ## This module implements asynchronous IO. This includes a dispatcher, -## a `Future` type implementation, and an `async` macro which allows -## asynchronous code to be written in a synchronous style with the `await` +## a ``Future`` type implementation, and an ``async`` macro which allows +## asynchronous code to be written in a synchronous style with the ``await`` ## keyword. ## -## The dispatcher acts as a kind of event loop. You must call `poll` on it -## (or a function which does so for you such as `waitFor` or `runForever`) +## The dispatcher acts as a kind of event loop. You must call ``poll`` on it +## (or a function which does so for you such as ``waitFor`` or ``runForever``) ## in order to poll for any outstanding events. The underlying implementation ## is based on epoll on Linux, IO Completion Ports on Windows and select on ## other operating systems. ## -## The `poll` function will not, on its own, return any events. Instead -## an appropriate `Future` object will be completed. A `Future` is a +## The ``poll`` function will not, on its own, return any events. Instead +## an appropriate ``Future`` object will be completed. A ``Future`` is a ## type which holds a value which is not yet available, but which *may* be ## available in the future. You can check whether a future is finished -## by using the `finished` function. When a future is finished it means that +## by using the ``finished`` function. When a future is finished it means that ## either the value that it holds is now available or it holds an error instead. ## The latter situation occurs when the operation to complete a future fails ## with an exception. You can distinguish between the two situations with the -## `failed` function. +## ``failed`` function. ## ## Future objects can also store a callback procedure which will be called ## automatically once the future completes. @@ -35,34 +35,34 @@ ## pattern. In this ## pattern you make a request for an action, and once that action is fulfilled ## a future is completed with the result of that action. Requests can be -## made by calling the appropriate functions. For example: calling the `recv` +## made by calling the appropriate functions. For example: calling the ``recv`` ## function will create a request for some data to be read from a socket. The -## future which the `recv` function returns will then complete once the +## future which the ``recv`` function returns will then complete once the ## requested amount of data is read **or** an exception occurs. ## ## Code to read some data from a socket may look something like this: -## ```Nim -## var future = socket.recv(100) -## future.addCallback( -## proc () = -## echo(future.read) -## ) -## ``` ## -## All asynchronous functions returning a `Future` will not block. They +## .. code-block::nim +## var future = socket.recv(100) +## future.addCallback( +## proc () = +## echo(future.read) +## ) +## +## All asynchronous functions returning a ``Future`` will not block. They ## will not however return immediately. An asynchronous function will have ## code which will be executed before an asynchronous request is made, in most ## cases this code sets up the request. ## -## In the above example, the `recv` function will return a brand new -## `Future` instance once the request for data to be read from the socket -## is made. This `Future` instance will complete once the requested amount +## In the above example, the ``recv`` function will return a brand new +## ``Future`` instance once the request for data to be read from the socket +## is made. This ``Future`` instance will complete once the requested amount ## of data is read, in this case it is 100 bytes. The second line sets a ## callback on this future which will be called once the future completes. -## All the callback does is write the data stored in the future to `stdout`. -## The `read` function is used for this and it checks whether the future -## completes with an error for you (if it did, it will simply raise the -## error), if there is no error, however, it returns the value of the future. +## All the callback does is write the data stored in the future to ``stdout``. +## The ``read`` function is used for this and it checks whether the future +## completes with an error for you (if it did it will simply raise the +## error), if there is no error however it returns the value of the future. ## ## Asynchronous procedures ## ======================= @@ -71,14 +71,14 @@ ## this by allowing you to write asynchronous code the same way as you would ## write synchronous code. ## -## An asynchronous procedure is marked using the `{.async.}` pragma. -## When marking a procedure with the `{.async.}` pragma it must have a -## `Future[T]` return type or no return type at all. If you do not specify -## a return type then `Future[void]` is assumed. +## An asynchronous procedure is marked using the ``{.async.}`` pragma. +## When marking a procedure with the ``{.async.}`` pragma it must have a +## ``Future[T]`` return type or no return type at all. If you do not specify +## a return type then ``Future[void]`` is assumed. ## -## Inside asynchronous procedures `await` can be used to call any +## Inside asynchronous procedures ``await`` can be used to call any ## procedures which return a -## `Future`; this includes asynchronous procedures. When a procedure is +## ``Future``; this includes asynchronous procedures. When a procedure is ## "awaited", the asynchronous procedure it is awaited in will ## suspend its execution ## until the awaited procedure's Future completes. At which point the @@ -86,83 +86,52 @@ ## when an asynchronous procedure is suspended other asynchronous procedures ## will be run by the dispatcher. ## -## The `await` call may be used in many contexts. It can be used on the right -## hand side of a variable declaration: `var data = await socket.recv(100)`, +## The ``await`` call may be used in many contexts. It can be used on the right +## hand side of a variable declaration: ``var data = await socket.recv(100)``, ## in which case the variable will be set to the value of the future -## automatically. It can be used to await a `Future` object, and it can -## be used to await a procedure returning a `Future[void]`: -## `await socket.send("foobar")`. +## automatically. It can be used to await a ``Future`` object, and it can +## be used to await a procedure returning a ``Future[void]``: +## ``await socket.send("foobar")``. ## -## If an awaited future completes with an error, then `await` will re-raise -## this error. To avoid this, you can use the `yield` keyword instead of -## `await`. The following section shows different ways that you can handle +## If an awaited future completes with an error, then ``await`` will re-raise +## this error. To avoid this, you can use the ``yield`` keyword instead of +## ``await``. The following section shows different ways that you can handle ## exceptions in async procs. ## -## .. caution:: -## Procedures marked {.async.} do not support mutable parameters such -## as `var int`. References such as `ref int` should be used instead. -## ## Handling Exceptions ## ------------------- ## -## You can handle exceptions in the same way as in ordinary Nim code; -## by using the try statement: +## The most reliable way to handle exceptions is to use ``yield`` on a future +## then check the future's ``failed`` property. For example: ## -## ```Nim -## try: -## let data = await sock.recv(100) -## echo("Received ", data) -## except: -## # Handle exception -## ``` +## .. code-block:: Nim +## var future = sock.recv(100) +## yield future +## if future.failed: +## # Handle exception ## -## An alternative approach to handling exceptions is to use `yield` on a future -## then check the future's `failed` property. For example: +## The ``async`` procedures also offer limited support for the try statement. ## -## ```Nim -## var future = sock.recv(100) -## yield future -## if future.failed: -## # Handle exception -## ``` +## .. code-block:: Nim +## try: +## let data = await sock.recv(100) +## echo("Received ", data) +## except: +## # Handle exception +## +## Unfortunately the semantics of the try statement may not always be correct, +## and occasionally the compilation may fail altogether. +## As such it is better to use the former style when possible. ## ## ## Discarding futures ## ================== ## -## Futures should **never** be discarded directly because they may contain -## errors. If you do not care for the result of a Future then you should use -## the `asyncCheck` procedure instead of the `discard` keyword. Note that this -## does not wait for completion, and you should use `waitFor` or `await` for that purpose. -## -## .. note:: `await` also checks if the future fails, so you can safely discard -## its result. -## -## Handling futures -## ================ -## -## There are many different operations that apply to a future. -## The three primary high-level operations are `asyncCheck`, -## `waitFor`, and `await`. -## -## * `asyncCheck`: Raises an exception if the future fails. It neither waits -## for the future to finish nor returns the result of the future. -## * `waitFor`: Polls the event loop and blocks the current thread until the -## future finishes. This is often used to call an async procedure from a -## synchronous context and should never be used in an `async` proc. -## * `await`: Pauses execution in the current async procedure until the future -## finishes. While the current procedure is paused, other async procedures will -## continue running. Should be used instead of `waitFor` in an async -## procedure. -## -## Here is a handy quick reference chart showing their high-level differences: -## ============== ===================== ======================= -## Procedure Context Blocking -## ============== ===================== ======================= -## `asyncCheck` non-async and async non-blocking -## `waitFor` non-async blocks current thread -## `await` async suspends current proc -## ============== ===================== ======================= +## Futures should **never** be discarded. This is because they may contain +## errors. If you do not care for the result of a Future then you should +## use the ``asyncCheck`` procedure instead of the ``discard`` keyword. Note +## however that this does not wait for completion, and you should use +## ``waitFor`` for that purpose. ## ## Examples ## ======== @@ -175,14 +144,14 @@ ## ============================= ## ## It's possible to get into a situation where an async proc, or more accurately -## a `Future[T]` gets stuck and +## a ``Future[T]`` gets stuck and ## never completes. This can happen for various reasons and can cause serious ## memory leaks. When this occurs it's hard to identify the procedure that is ## stuck. ## ## Thankfully there is a mechanism which tracks the count of each pending future. -## All you need to do to enable it is compile with `-d:futureLogging` and -## use the `getFuturesInProgress` procedure to get the list of pending futures +## All you need to do to enable it is compile with ``-d:futureLogging`` and +## use the ``getFuturesInProgress`` procedure to get the list of pending futures ## together with the stack traces to the moment of their creation. ## ## You may also find it useful to use this @@ -195,50 +164,22 @@ ## Limitations/Bugs ## ================ ## -## * The effect system (`raises: []`) does not work with async procedures. -## * Mutable parameters are not supported by async procedures. -## -## -## Multiple async backend support -## ============================== -## -## Thanks to its powerful macro support, Nim allows ``async``/``await`` to be -## implemented in libraries with only minimal support from the language - as -## such, multiple ``async`` libraries exist, including ``asyncdispatch`` and -## ``chronos``, and more may come to be developed in the future. -## -## Libraries built on top of async/await may wish to support multiple async -## backends - the best way to do so is to create separate modules for each backend -## that may be imported side-by-side. -## -## An alternative way is to select backend using a global compile flag - this -## method makes it difficult to compose applications that use both backends as may -## happen with transitive dependencies, but may be appropriate in some cases - -## libraries choosing this path should call the flag `asyncBackend`, allowing -## applications to choose the backend with `-d:asyncBackend=`. -## -## Known `async` backends include: -## -## * `-d:asyncBackend=none`: disable `async` support completely -## * `-d:asyncBackend=asyncdispatch`: https://nim-lang.org/docs/asyncdispatch.html -## * `-d:asyncBackend=chronos`: https://github.com/status-im/nim-chronos/ -## -## ``none`` can be used when a library supports both a synchronous and -## asynchronous API, to disable the latter. +## * The effect system (``raises: []``) does not work with async procedures. -import os, tables, strutils, times, heapqueue, options, asyncstreams +include "system/inclrtl" + +import os, tables, strutils, times, heapqueue, lists, options, asyncstreams import options, math, std/monotimes import asyncfutures except callSoon import nativesockets, net, deques -when defined(nimPreviewSlimSystem): - import std/[assertions, syncio] - export Port, SocketFlag export asyncfutures except callSoon export asyncstreams +#{.injectStmt: newGcInvariant().} + # TODO: Check if yielded future is nil and throw a more meaningful exception type @@ -281,8 +222,6 @@ proc adjustTimeout( result = max(nextTimer.get(), 0) result = min(pollTimeout, result) -proc runOnce(timeout: int): bool {.gcsafe.} - proc callSoon*(cbproc: proc () {.gcsafe.}) {.gcsafe.} ## Schedule `cbproc` to be called as soon as possible. ## The callback is called when control returns to the event loop. @@ -291,16 +230,6 @@ proc initCallSoonProc = if asyncfutures.getCallSoonProc().isNil: asyncfutures.setCallSoonProc(callSoon) -template implementSetInheritable() {.dirty.} = - when declared(setInheritable): - proc setInheritable*(fd: AsyncFD, inheritable: bool): bool = - ## Control whether a file handle can be inherited by child processes. - ## Returns `true` on success. - ## - ## This procedure is not guaranteed to be available for all platforms. - ## Test for availability with `declared() `_. - fd.FileHandle.setInheritable(inheritable) - when defined(windows) or defined(nimdoc): import winlean, sets, hashes type @@ -316,7 +245,7 @@ when defined(windows) or defined(nimdoc): PDispatcher* = ref object of PDispatcherBase ioPort: Handle - handles*: HashSet[AsyncFD] # Export handles so that an external library can register them. + handles: HashSet[AsyncFD] CustomObj = object of OVERLAPPED data*: CompletionData @@ -338,7 +267,7 @@ when defined(windows) or defined(nimdoc): pcd: PostCallbackDataPtr AsyncEvent* = ptr AsyncEventImpl - Callback* = proc (fd: AsyncFD): bool {.closure, gcsafe.} + Callback = proc (fd: AsyncFD): bool {.closure, gcsafe.} proc hash(x: AsyncFD): Hash {.borrow.} proc `==`*(x: AsyncFD, y: AsyncFD): bool {.borrow.} @@ -347,13 +276,13 @@ when defined(windows) or defined(nimdoc): ## Creates a new Dispatcher instance. new result result.ioPort = createIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0, 1) - result.handles = initHashSet[AsyncFD]() - result.timers.clear() - result.callbacks = initDeque[proc () {.closure, gcsafe.}](64) + result.handles = initSet[AsyncFD]() + result.timers.newHeapQueue() + result.callbacks = initDeque[proc ()](64) var gDisp{.threadvar.}: owned PDispatcher ## Global dispatcher - proc setGlobalDispatcher*(disp: sink PDispatcher) = + proc setGlobalDispatcher*(disp: owned PDispatcher) = if not gDisp.isNil: assert gDisp.callbacks.len == 0 gDisp = disp @@ -370,7 +299,7 @@ when defined(windows) or defined(nimdoc): return disp.ioPort proc register*(fd: AsyncFD) = - ## Registers `fd` with the dispatcher. + ## Registers ``fd`` with the dispatcher. let p = getGlobalDispatcher() if createIoCompletionPort(fd.Handle, p.ioPort, @@ -392,7 +321,7 @@ when defined(windows) or defined(nimdoc): let p = getGlobalDispatcher() p.handles.len != 0 or p.timers.len != 0 or p.callbacks.len != 0 - proc runOnce(timeout: int): bool = + proc runOnce(timeout = 500): bool = let p = getGlobalDispatcher() if p.handles.len == 0 and p.timers.len == 0 and p.callbacks.len == 0: raise newException(ValueError, @@ -469,7 +398,7 @@ when defined(windows) or defined(nimdoc): addr bytesRet, nil, nil) == 0 proc initAll() = - let dummySock = createNativeSocket() + let dummySock = newNativeSocket() if dummySock == INVALID_SOCKET: raiseOSError(osLastError()) var fun: pointer = nil @@ -493,16 +422,16 @@ when defined(windows) or defined(nimdoc): proc recv*(socket: AsyncFD, size: int, flags = {SocketFlag.SafeDisconn}): owned(Future[string]) = - ## Reads **up to** `size` bytes from `socket`. Returned future will + ## Reads **up to** ``size`` bytes from ``socket``. Returned future will ## complete once all the data requested is read, a part of the data has been ## read, or the socket has disconnected in which case the future will - ## complete with a value of `""`. + ## complete with a value of ``""``. ## - ## .. warning:: The `Peek` socket flag is not supported on Windows. + ## **Warning**: The ``Peek`` socket flag is not supported on Windows. # Things to note: - # * When WSARecv completes immediately then `bytesReceived` is very + # * When WSARecv completes immediately then ``bytesReceived`` is very # unreliable. # * Still need to implement message-oriented socket disconnection, # '\0' in the message currently signifies a socket disconnect. Who @@ -566,17 +495,17 @@ when defined(windows) or defined(nimdoc): proc recvInto*(socket: AsyncFD, buf: pointer, size: int, flags = {SocketFlag.SafeDisconn}): owned(Future[int]) = - ## Reads **up to** `size` bytes from `socket` into `buf`, which must + ## Reads **up to** ``size`` bytes from ``socket`` into ``buf``, which must ## at least be of that size. Returned future will complete once all the ## data requested is read, a part of the data has been read, or the socket ## has disconnected in which case the future will complete with a value of - ## `0`. + ## ``0``. ## - ## .. warning:: The `Peek` socket flag is not supported on Windows. + ## **Warning**: The ``Peek`` socket flag is not supported on Windows. # Things to note: - # * When WSARecv completes immediately then `bytesReceived` is very + # * When WSARecv completes immediately then ``bytesReceived`` is very # unreliable. # * Still need to implement message-oriented socket disconnection, # '\0' in the message currently signifies a socket disconnect. Who @@ -632,11 +561,11 @@ when defined(windows) or defined(nimdoc): proc send*(socket: AsyncFD, buf: pointer, size: int, flags = {SocketFlag.SafeDisconn}): owned(Future[void]) = - ## Sends `size` bytes from `buf` to `socket`. The returned future + ## Sends ``size`` bytes from ``buf`` to ``socket``. The returned future ## will complete once all data has been sent. ## - ## .. warning:: Use it with caution. If `buf` refers to GC'ed object, - ## you must use GC_ref/GC_unref calls to avoid early freeing of the buffer. + ## **WARNING**: Use it with caution. If ``buf`` refers to GC'ed object, + ## you must use GC_ref/GC_unref calls to avoid early freeing of the buffer. verifyPresence(socket) var retFuture = newFuture[void]("send") @@ -670,16 +599,16 @@ when defined(windows) or defined(nimdoc): retFuture.fail(newException(OSError, osErrorMsg(err))) else: retFuture.complete() - # We don't deallocate `ol` here because even though this completed + # We don't deallocate ``ol`` here because even though this completed # immediately poll will still be notified about its completion and it will - # free `ol`. + # free ``ol``. return retFuture proc sendTo*(socket: AsyncFD, data: pointer, size: int, saddr: ptr SockAddr, saddrLen: SockLen, flags = {SocketFlag.SafeDisconn}): owned(Future[void]) = - ## Sends `data` to specified destination `saddr`, using - ## socket `socket`. The returned future will complete once all data + ## Sends ``data`` to specified destination ``saddr``, using + ## socket ``socket``. The returned future will complete once all data ## has been sent. verifyPresence(socket) var retFuture = newFuture[void]("sendTo") @@ -715,17 +644,17 @@ when defined(windows) or defined(nimdoc): retFuture.fail(newException(OSError, osErrorMsg(err))) else: retFuture.complete() - # We don't deallocate `ol` here because even though this completed + # We don't deallocate ``ol`` here because even though this completed # immediately poll will still be notified about its completion and it will - # free `ol`. + # free ``ol``. return retFuture proc recvFromInto*(socket: AsyncFD, data: pointer, size: int, saddr: ptr SockAddr, saddrLen: ptr SockLen, flags = {SocketFlag.SafeDisconn}): owned(Future[int]) = - ## Receives a datagram data from `socket` into `buf`, which must - ## be at least of size `size`, address of datagram's sender will be - ## stored into `saddr` and `saddrLen`. Returned future will complete + ## Receives a datagram data from ``socket`` into ``buf``, which must + ## be at least of size ``size``, address of datagram's sender will be + ## stored into ``saddr`` and ``saddrLen``. Returned future will complete ## once one datagram has been received, and will return size of packet ## received. verifyPresence(socket) @@ -768,9 +697,8 @@ when defined(windows) or defined(nimdoc): retFuture.complete(bytesReceived) return retFuture - proc acceptAddr*(socket: AsyncFD, flags = {SocketFlag.SafeDisconn}, - inheritable = defined(nimInheritHandles)): - owned(Future[tuple[address: string, client: AsyncFD]]) {.gcsafe.} = + proc acceptAddr*(socket: AsyncFD, flags = {SocketFlag.SafeDisconn}): + owned(Future[tuple[address: string, client: AsyncFD]]) = ## Accepts a new connection. Returns a future containing the client socket ## corresponding to that connection and the remote address of the client. ## The future will complete when the connection is successfully accepted. @@ -778,17 +706,14 @@ when defined(windows) or defined(nimdoc): ## The resulting client socket is automatically registered to the ## dispatcher. ## - ## If `inheritable` is false (the default), the resulting client socket will - ## not be inheritable by child processes. - ## - ## The `accept` call may result in an error if the connecting socket - ## disconnects during the duration of the `accept`. If the `SafeDisconn` + ## The ``accept`` call may result in an error if the connecting socket + ## disconnects during the duration of the ``accept``. If the ``SafeDisconn`` ## flag is specified then this error will not be raised and instead ## accept will be called again. verifyPresence(socket) var retFuture = newFuture[tuple[address: string, client: AsyncFD]]("acceptAddr") - var clientSock = createNativeSocket(inheritable = inheritable) + var clientSock = newNativeSocket() if clientSock == osInvalidSocket: raiseOSError(osLastError()) const lpOutputLen = 1024 @@ -837,7 +762,7 @@ when defined(windows) or defined(nimdoc): var ol = newCustom() ol.data = CompletionData(fd: socket, cb: - proc (fd: AsyncFD, bytesCount: DWORD, errcode: OSErrorCode) {.gcsafe.} = + proc (fd: AsyncFD, bytesCount: DWORD, errcode: OSErrorCode) = if not retFuture.finished: if errcode == OSErrorCode(-1): completeAccept() @@ -859,21 +784,19 @@ when defined(windows) or defined(nimdoc): GC_unref(ol) else: completeAccept() - # We don't deallocate `ol` here because even though this completed + # We don't deallocate ``ol`` here because even though this completed # immediately poll will still be notified about its completion and it will - # free `ol`. + # free ``ol``. return retFuture - implementSetInheritable() - proc closeSocket*(socket: AsyncFD) = ## Closes a socket and ensures that it is unregistered. socket.SocketHandle.close() getGlobalDispatcher().handles.excl(socket) proc unregister*(fd: AsyncFD) = - ## Unregisters `fd`. + ## Unregisters ``fd``. getGlobalDispatcher().handles.excl(fd) proc contains*(disp: PDispatcher, fd: AsyncFD): bool = @@ -973,9 +896,9 @@ when defined(windows) or defined(nimdoc): proc addRead*(fd: AsyncFD, cb: Callback) = ## Start watching the file descriptor for read availability and then call - ## the callback `cb`. + ## the callback ``cb``. ## - ## This is not `pure` mechanism for Windows Completion Ports (IOCP), + ## This is not ``pure`` mechanism for Windows Completion Ports (IOCP), ## so if you can avoid it, please do it. Use `addRead` only if really ## need it (main usecase is adaptation of unix-like libraries to be ## asynchronous on Windows). @@ -984,16 +907,16 @@ when defined(windows) or defined(nimdoc): ## or asyncdispatch.accept(), because they are using IOCP, please use ## nativesockets.recv() and nativesockets.accept() instead. ## - ## Be sure your callback `cb` returns `true`, if you want to remove - ## watch of `read` notifications, and `false`, if you want to continue + ## Be sure your callback ``cb`` returns ``true``, if you want to remove + ## watch of `read` notifications, and ``false``, if you want to continue ## receiving notifications. registerWaitableEvent(fd, cb, FD_READ or FD_ACCEPT or FD_OOB or FD_CLOSE) proc addWrite*(fd: AsyncFD, cb: Callback) = ## Start watching the file descriptor for write availability and then call - ## the callback `cb`. + ## the callback ``cb``. ## - ## This is not `pure` mechanism for Windows Completion Ports (IOCP), + ## This is not ``pure`` mechanism for Windows Completion Ports (IOCP), ## so if you can avoid it, please do it. Use `addWrite` only if really ## need it (main usecase is adaptation of unix-like libraries to be ## asynchronous on Windows). @@ -1002,8 +925,8 @@ when defined(windows) or defined(nimdoc): ## or asyncdispatch.connect(), because they are using IOCP, please use ## nativesockets.send() and nativesockets.connect() instead. ## - ## Be sure your callback `cb` returns `true`, if you want to remove - ## watch of `write` notifications, and `false`, if you want to continue + ## Be sure your callback ``cb`` returns ``true``, if you want to remove + ## watch of `write` notifications, and ``false``, if you want to continue ## receiving notifications. registerWaitableEvent(fd, cb, FD_WRITE or FD_CONNECT or FD_CLOSE) @@ -1043,12 +966,12 @@ when defined(windows) or defined(nimdoc): raiseOSError(osLastError()) proc addTimer*(timeout: int, oneshot: bool, cb: Callback) = - ## Registers callback `cb` to be called when timer expired. + ## Registers callback ``cb`` to be called when timer expired. ## ## Parameters: ## - ## * `timeout` - timeout value in milliseconds. - ## * `oneshot` + ## * ``timeout`` - timeout value in milliseconds. + ## * ``oneshot`` ## * `true` - generate only one timeout event ## * `false` - generate timeout events periodically @@ -1077,17 +1000,16 @@ when defined(windows) or defined(nimdoc): registerWaitableHandle(p, hEvent, flags, pcd, timeout, timercb) proc addProcess*(pid: int, cb: Callback) = - ## Registers callback `cb` to be called when process with process ID - ## `pid` exited. - const NULL = Handle(0) + ## Registers callback ``cb`` to be called when process with process ID + ## ``pid`` exited. let p = getGlobalDispatcher() let procFlags = SYNCHRONIZE var hProcess = openProcess(procFlags, 0, pid.DWORD) - if hProcess == NULL: + if hProcess == INVALID_HANDLE_VALUE: raiseOSError(osLastError()) var pcd = cast[PostCallbackDataPtr](allocShared0(sizeof(PostCallbackData))) - var flags = WT_EXECUTEINWAITTHREAD.DWORD or WT_EXECUTEONLYONCE.DWORD + var flags = WT_EXECUTEINWAITTHREAD.DWORD proc proccb(fd: AsyncFD, bytesCount: DWORD, errcode: OSErrorCode) = closeWaitable(hProcess) @@ -1096,10 +1018,10 @@ when defined(windows) or defined(nimdoc): registerWaitableHandle(p, hProcess, flags, pcd, INFINITE, proccb) proc newAsyncEvent*(): AsyncEvent = - ## Creates a new thread-safe `AsyncEvent` object. + ## Creates a new thread-safe ``AsyncEvent`` object. ## - ## New `AsyncEvent` object is not automatically registered with - ## dispatcher like `AsyncSocket`. + ## New ``AsyncEvent`` object is not automatically registered with + ## dispatcher like ``AsyncSocket``. var sa = SECURITY_ATTRIBUTES( nLength: sizeof(SECURITY_ATTRIBUTES).cint, bInheritHandle: 1 @@ -1111,12 +1033,12 @@ when defined(windows) or defined(nimdoc): result.hEvent = event proc trigger*(ev: AsyncEvent) = - ## Set event `ev` to signaled state. + ## Set event ``ev`` to signaled state. if setEvent(ev.hEvent) == 0: raiseOSError(osLastError()) proc unregister*(ev: AsyncEvent) = - ## Unregisters event `ev`. + ## Unregisters event ``ev``. doAssert(ev.hWaiter != 0, "Event is not registered in the queue!") let p = getGlobalDispatcher() p.handles.excl(AsyncFD(ev.hEvent)) @@ -1127,14 +1049,14 @@ when defined(windows) or defined(nimdoc): ev.hWaiter = 0 proc close*(ev: AsyncEvent) = - ## Closes event `ev`. + ## Closes event ``ev``. let res = closeHandle(ev.hEvent) deallocShared(cast[pointer](ev)) if res == 0: raiseOSError(osLastError()) proc addEvent*(ev: AsyncEvent, cb: Callback) = - ## Registers callback `cb` to be called when `ev` will be signaled + ## Registers callback ``cb`` to be called when ``ev`` will be signaled doAssert(ev.hWaiter == 0, "Event is already registered in the queue!") let p = getGlobalDispatcher() @@ -1169,12 +1091,6 @@ else: import selectors from posix import EINTR, EAGAIN, EINPROGRESS, EWOULDBLOCK, MSG_PEEK, MSG_NOSIGNAL - when declared(posix.accept4): - from posix import accept4, SOCK_CLOEXEC - when defined(genode): - import genode/env # get the implicit Genode env - import genode/signals - const InitCallbackListSize = 4 # initial size of callbacks sequence, # associated with file/socket descriptor. @@ -1182,7 +1098,7 @@ else: # queue. type AsyncFD* = distinct cint - Callback* = proc (fd: AsyncFD): bool {.closure, gcsafe.} + Callback = proc (fd: AsyncFD): bool {.closure, gcsafe.} AsyncData = object readList: seq[Callback] @@ -1192,8 +1108,6 @@ else: PDispatcher* = ref object of PDispatcherBase selector: Selector[AsyncData] - when defined(genode): - signalHandler: SignalHandler proc `==`*(x, y: AsyncFD): bool {.borrow.} proc `==`*(x, y: AsyncEvent): bool {.borrow.} @@ -1207,24 +1121,11 @@ else: proc newDispatcher*(): owned(PDispatcher) = new result result.selector = newSelector[AsyncData]() - result.timers.clear() - result.callbacks = initDeque[proc () {.closure, gcsafe.}](InitDelayedCallbackListSize) - when defined(genode): - let entrypoint = ep(cast[GenodeEnv](runtimeEnv)) - result.signalHandler = newSignalHandler(entrypoint): - discard runOnce(0) + result.timers.newHeapQueue() + result.callbacks = initDeque[proc ()](InitDelayedCallbackListSize) var gDisp{.threadvar.}: owned PDispatcher ## Global dispatcher - when defined(nuttx): - import std/exitprocs - - proc cleanDispatcher() {.noconv.} = - gDisp = nil - - proc addFinalyzer() = - addExitProc(cleanDispatcher) - proc setGlobalDispatcher*(disp: owned PDispatcher) = if not gDisp.isNil: assert gDisp.callbacks.len == 0 @@ -1234,8 +1135,6 @@ else: proc getGlobalDispatcher*(): PDispatcher = if gDisp.isNil: setGlobalDispatcher(newDispatcher()) - when defined(nuttx): - addFinalyzer() result = gDisp proc getIoHandler*(disp: PDispatcher): Selector[AsyncData] = @@ -1281,12 +1180,6 @@ else: let p = getGlobalDispatcher() not p.selector.isEmpty() or p.timers.len != 0 or p.callbacks.len != 0 - proc prependSeq(dest: var seq[Callback]; src: sink seq[Callback]) = - var old = move dest - dest = src - for i in 0..high(old): - dest.add(move old[i]) - proc processBasicCallbacks( fd: AsyncFD, event: Event ): tuple[readCbListCount, writeCbListCount: int] = @@ -1306,12 +1199,10 @@ else: withData(selector, fd.int, fdData): case event of Event.Read: - #shallowCopy(curList, fdData.readList) - curList = move fdData.readList + shallowCopy(curList, fdData.readList) fdData.readList = newSeqOfCap[Callback](InitCallbackListSize) of Event.Write: - #shallowCopy(curList, fdData.writeList) - curList = move fdData.writeList + shallowCopy(curList, fdData.writeList) fdData.writeList = newSeqOfCap[Callback](InitCallbackListSize) else: assert false, "Cannot process callbacks for " & $event @@ -1319,24 +1210,22 @@ else: let newLength = max(len(curList), InitCallbackListSize) var newList = newSeqOfCap[Callback](newLength) - var eventsExtinguished = false for cb in curList: - if eventsExtinguished: - newList.add(cb) - elif not cb(fd): + if not cb(fd): # Callback wants to be called again. newList.add(cb) # This callback has returned with EAGAIN, so we don't need to # call any other callbacks as they are all waiting for the same event # on the same fd. - # We do need to ensure they are called again though. - eventsExtinguished = true + break withData(selector, fd.int, fdData) do: # Descriptor is still present in the queue. case event - of Event.Read: prependSeq(fdData.readList, newList) - of Event.Write: prependSeq(fdData.writeList, newList) + of Event.Read: + fdData.readList = newList & fdData.readList + of Event.Write: + fdData.writeList = newList & fdData.writeList else: assert false, "Cannot process callbacks for " & $event @@ -1347,25 +1236,25 @@ else: result.readCbListCount = -1 result.writeCbListCount = -1 - proc processCustomCallbacks(p: PDispatcher; fd: AsyncFD) = + template processCustomCallbacks(ident: untyped) = # Process pending custom event callbacks. Custom events are # {Event.Timer, Event.Signal, Event.Process, Event.Vnode}. # There can be only one callback registered with one descriptor, # so there is no need to iterate over list. var curList: seq[Callback] - withData(p.selector, fd.int, adata) do: - curList = move adata.readList + withData(p.selector, ident.int, adata) do: + shallowCopy(curList, adata.readList) adata.readList = newSeqOfCap[Callback](InitCallbackListSize) let newLength = len(curList) var newList = newSeqOfCap[Callback](newLength) var cb = curList[0] - if not cb(fd): + if not cb(fd.AsyncFD): newList.add(cb) - withData(p.selector, fd.int, adata) do: + withData(p.selector, ident.int, adata) do: # descriptor still present in queue. adata.readList = newList & adata.readList if len(adata.readList) == 0: @@ -1375,8 +1264,6 @@ else: # descriptor was unregistered in callback via `unregister()`. discard - implementSetInheritable() - proc closeSocket*(sock: AsyncFD) = let selector = getGlobalDispatcher().selector if sock.SocketHandle notin selector: @@ -1393,11 +1280,14 @@ else: ValueError, "Expecting async operations to stop when fd has closed." ) - proc runOnce(timeout: int): bool = + + proc runOnce(timeout = 500): bool = let p = getGlobalDispatcher() + when ioselSupportedPlatform: + let customSet = {Event.Timer, Event.Signal, Event.Process, + Event.Vnode} + if p.selector.isEmpty() and p.timers.len == 0 and p.callbacks.len == 0: - when defined(genode): - if timeout == 0: return raise newException(ValueError, "No handles or timers registered in dispatcher.") @@ -1431,11 +1321,9 @@ else: result = true when ioselSupportedPlatform: - const customSet = {Event.Timer, Event.Signal, Event.Process, - Event.Vnode} if (customSet * events) != {}: isCustomEvent = true - processCustomCallbacks(p, fd) + processCustomCallbacks(fd) result = true # because state `data` can be modified in callback we need to update @@ -1463,8 +1351,7 @@ else: flags.toOSFlags()) if res < 0: let lastError = osLastError() - if lastError.int32 != EINTR and lastError.int32 != EWOULDBLOCK and - lastError.int32 != EAGAIN: + if lastError.int32 notin {EINTR, EWOULDBLOCK, EAGAIN}: if flags.isDisconnectionError(lastError): retFuture.complete("") else: @@ -1492,8 +1379,7 @@ else: flags.toOSFlags()) if res < 0: let lastError = osLastError() - if lastError.int32 != EINTR and lastError.int32 != EWOULDBLOCK and - lastError.int32 != EAGAIN: + if lastError.int32 notin {EINTR, EWOULDBLOCK, EAGAIN}: if flags.isDisconnectionError(lastError): retFuture.complete(0) else: @@ -1521,9 +1407,7 @@ else: MSG_NOSIGNAL) if res < 0: let lastError = osLastError() - if lastError.int32 != EINTR and - lastError.int32 != EWOULDBLOCK and - lastError.int32 != EAGAIN: + if lastError.int32 notin {EINTR, EWOULDBLOCK, EAGAIN}: if flags.isDisconnectionError(lastError): retFuture.complete() else: @@ -1544,8 +1428,8 @@ else: proc sendTo*(socket: AsyncFD, data: pointer, size: int, saddr: ptr SockAddr, saddrLen: SockLen, flags = {SocketFlag.SafeDisconn}): owned(Future[void]) = - ## Sends `data` of size `size` in bytes to specified destination - ## (`saddr` of size `saddrLen` in bytes, using socket `socket`. + ## Sends ``data`` of size ``size`` in bytes to specified destination + ## (``saddr`` of size ``saddrLen`` in bytes, using socket ``socket``. ## The returned future will complete once all data has been sent. var retFuture = newFuture[void]("sendTo") @@ -1561,8 +1445,7 @@ else: cast[ptr SockAddr](addr(staddr[0])), stalen) if res < 0: let lastError = osLastError() - if lastError.int32 != EINTR and lastError.int32 != EWOULDBLOCK and - lastError.int32 != EAGAIN: + if lastError.int32 notin {EINTR, EWOULDBLOCK, EAGAIN}: retFuture.fail(newException(OSError, osErrorMsg(lastError))) else: result = false # We still want this callback to be called. @@ -1575,9 +1458,9 @@ else: proc recvFromInto*(socket: AsyncFD, data: pointer, size: int, saddr: ptr SockAddr, saddrLen: ptr SockLen, flags = {SocketFlag.SafeDisconn}): owned(Future[int]) = - ## Receives a datagram data from `socket` into `data`, which must - ## be at least of size `size` in bytes, address of datagram's sender - ## will be stored into `saddr` and `saddrLen`. Returned future will + ## Receives a datagram data from ``socket`` into ``data``, which must + ## be at least of size ``size`` in bytes, address of datagram's sender + ## will be stored into ``saddr`` and ``saddrLen``. Returned future will ## complete once one datagram has been received, and will return size ## of packet received. var retFuture = newFuture[int]("recvFromInto") @@ -1587,8 +1470,7 @@ else: saddr, saddrLen) if res < 0: let lastError = osLastError() - if lastError.int32 != EINTR and lastError.int32 != EWOULDBLOCK and - lastError.int32 != EAGAIN: + if lastError.int32 notin {EINTR, EWOULDBLOCK, EAGAIN}: retFuture.fail(newException(OSError, osErrorMsg(lastError))) else: result = false @@ -1597,33 +1479,19 @@ else: addRead(socket, cb) return retFuture - proc acceptAddr*(socket: AsyncFD, flags = {SocketFlag.SafeDisconn}, - inheritable = defined(nimInheritHandles)): + proc acceptAddr*(socket: AsyncFD, flags = {SocketFlag.SafeDisconn}): owned(Future[tuple[address: string, client: AsyncFD]]) = var retFuture = newFuture[tuple[address: string, client: AsyncFD]]("acceptAddr") - proc cb(sock: AsyncFD): bool {.gcsafe.} = + proc cb(sock: AsyncFD): bool = result = true var sockAddress: Sockaddr_storage var addrLen = sizeof(sockAddress).SockLen - var client = - when declared(accept4): - accept4(sock.SocketHandle, cast[ptr SockAddr](addr(sockAddress)), - addr(addrLen), if inheritable: 0 else: SOCK_CLOEXEC) - else: - accept(sock.SocketHandle, cast[ptr SockAddr](addr(sockAddress)), - addr(addrLen)) - when declared(setInheritable) and not declared(accept4): - if client != osInvalidSocket and not setInheritable(client, inheritable): - # Set failure first because close() itself can fail, - # altering osLastError(). - retFuture.fail(newOSError(osLastError())) - close client - return false - + var client = accept(sock.SocketHandle, + cast[ptr SockAddr](addr(sockAddress)), addr(addrLen)) if client == osInvalidSocket: let lastError = osLastError() - assert lastError.int32 != EWOULDBLOCK and lastError.int32 != EAGAIN + assert lastError.int32 notin {EWOULDBLOCK, EAGAIN} if lastError.int32 == EINTR: return false else: @@ -1647,45 +1515,45 @@ else: proc addTimer*(timeout: int, oneshot: bool, cb: Callback) = ## Start watching for timeout expiration, and then call the - ## callback `cb`. - ## `timeout` - time in milliseconds, - ## `oneshot` - if `true` only one event will be dispatched, - ## if `false` continuous events every `timeout` milliseconds. + ## callback ``cb``. + ## ``timeout`` - time in milliseconds, + ## ``oneshot`` - if ``true`` only one event will be dispatched, + ## if ``false`` continuous events every ``timeout`` milliseconds. let p = getGlobalDispatcher() var data = newAsyncData() data.readList.add(cb) p.selector.registerTimer(timeout, oneshot, data) proc addSignal*(signal: int, cb: Callback) = - ## Start watching signal `signal`, and when signal appears, call the - ## callback `cb`. + ## Start watching signal ``signal``, and when signal appears, call the + ## callback ``cb``. let p = getGlobalDispatcher() var data = newAsyncData() data.readList.add(cb) p.selector.registerSignal(signal, data) proc addProcess*(pid: int, cb: Callback) = - ## Start watching for process exit with pid `pid`, and then call - ## the callback `cb`. + ## Start watching for process exit with pid ``pid``, and then call + ## the callback ``cb``. let p = getGlobalDispatcher() var data = newAsyncData() data.readList.add(cb) p.selector.registerProcess(pid, data) proc newAsyncEvent*(): AsyncEvent = - ## Creates new `AsyncEvent`. + ## Creates new ``AsyncEvent``. result = AsyncEvent(newSelectEvent()) proc trigger*(ev: AsyncEvent) = - ## Sets new `AsyncEvent` to signaled state. + ## Sets new ``AsyncEvent`` to signaled state. trigger(SelectEvent(ev)) proc close*(ev: AsyncEvent) = - ## Closes `AsyncEvent` + ## Closes ``AsyncEvent`` close(SelectEvent(ev)) proc addEvent*(ev: AsyncEvent, cb: Callback) = - ## Start watching for event `ev`, and call callback `cb`, when + ## Start watching for event ``ev``, and call callback ``cb``, when ## ev will be set to signaled state. let p = getGlobalDispatcher() var data = newAsyncData() @@ -1693,26 +1561,20 @@ else: p.selector.registerEvent(SelectEvent(ev), data) proc drain*(timeout = 500) = - ## Waits for completion of **all** events and processes them. Raises `ValueError` - ## if there are no pending operations. In contrast to `poll` this - ## processes as many events as are available until the timeout has elapsed. - var curTimeout = timeout - let start = now() - while hasPendingOperations(): - discard runOnce(curTimeout) - curTimeout -= (now() - start).inMilliseconds.int - if curTimeout < 0: - break + ## Waits for completion events and processes them. Raises ``ValueError`` + ## if there are no pending operations. In contrast to ``poll`` this + ## processes as many events as are available. + if runOnce(timeout) or hasPendingOperations(): + while hasPendingOperations() and runOnce(timeout): discard proc poll*(timeout = 500) = - ## Waits for completion events and processes them. Raises `ValueError` + ## Waits for completion events and processes them. Raises ``ValueError`` ## if there are no pending operations. This runs the underlying OS ## `epoll`:idx: or `kqueue`:idx: primitive only once. discard runOnce(timeout) -template createAsyncNativeSocketImpl(domain, sockType, protocol: untyped, - inheritable = defined(nimInheritHandles)) = - let handle = createNativeSocket(domain, sockType, protocol, inheritable) +template createAsyncNativeSocketImpl(domain, sockType, protocol) = + let handle = newNativeSocket(domain, sockType, protocol) if handle == osInvalidSocket: return osInvalidSocket.AsyncFD handle.setBlocking(false) @@ -1722,15 +1584,23 @@ template createAsyncNativeSocketImpl(domain, sockType, protocol: untyped, register(result) proc createAsyncNativeSocket*(domain: cint, sockType: cint, - protocol: cint, - inheritable = defined(nimInheritHandles)): AsyncFD = - createAsyncNativeSocketImpl(domain, sockType, protocol, inheritable) + protocol: cint): AsyncFD = + createAsyncNativeSocketImpl(domain, sockType, protocol) proc createAsyncNativeSocket*(domain: Domain = Domain.AF_INET, - sockType: SockType = SOCK_STREAM, - protocol: Protocol = IPPROTO_TCP, - inheritable = defined(nimInheritHandles)): AsyncFD = - createAsyncNativeSocketImpl(domain, sockType, protocol, inheritable) + sockType: SockType = SOCK_STREAM, + protocol: Protocol = IPPROTO_TCP): AsyncFD = + createAsyncNativeSocketImpl(domain, sockType, protocol) + +proc newAsyncNativeSocket*(domain: cint, sockType: cint, + protocol: cint): AsyncFD {.deprecated: "use createAsyncNativeSocket instead".} = + createAsyncNativeSocketImpl(domain, sockType, protocol) + +proc newAsyncNativeSocket*(domain: Domain = Domain.AF_INET, + sockType: SockType = SOCK_STREAM, + protocol: Protocol = IPPROTO_TCP): AsyncFD + {.deprecated: "use createAsyncNativeSocket instead".} = + createAsyncNativeSocketImpl(domain, sockType, protocol) when defined(windows) or defined(nimdoc): proc bindToDomain(handle: SocketHandle, domain: Domain) = @@ -1759,8 +1629,6 @@ when defined(windows) or defined(nimdoc): proc (fd: AsyncFD, bytesCount: DWORD, errcode: OSErrorCode) = if not retFuture.finished: if errcode == OSErrorCode(-1): - const SO_UPDATE_CONNECT_CONTEXT = 0x7010 - socket.SocketHandle.setSockOptInt(SOL_SOCKET, SO_UPDATE_CONNECT_CONTEXT, 1) # 15022 retFuture.complete() else: retFuture.fail(newException(OSError, osErrorMsg(errcode))) @@ -1772,13 +1640,13 @@ when defined(windows) or defined(nimdoc): if ret: # Request to connect completed immediately. retFuture.complete() - # We don't deallocate `ol` here because even though this completed + # We don't deallocate ``ol`` here because even though this completed # immediately poll will still be notified about its completion and it - # will free `ol`. + # will free ``ol``. else: let lastError = osLastError() if lastError.int32 != ERROR_IO_PENDING: - # With ERROR_IO_PENDING `ol` will be deallocated in `poll`, + # With ERROR_IO_PENDING ``ol`` will be deallocated in ``poll``, # and the future will be completed/failed there, too. GC_unref(ol) retFuture.fail(newException(OSError, osErrorMsg(lastError))) @@ -1851,7 +1719,7 @@ template asyncAddrInfoLoop(addrInfo: ptr AddrInfo, fd: untyped, curAddrInfo = curAddrInfo.ai_next if curAddrInfo == nil: - freeAddrInfo(addrInfo) + freeaddrinfo(addrInfo) when shouldCreateFd: closeUnusedFds() if lastException != nil: @@ -1867,7 +1735,7 @@ template asyncAddrInfoLoop(addrInfo: ptr AddrInfo, fd: untyped, try: curFd = createAsyncNativeSocket(domain, sockType, protocol) except: - freeAddrInfo(addrInfo) + freeaddrinfo(addrInfo) closeUnusedFds() raise getCurrentException() when defined(windows): @@ -1877,7 +1745,7 @@ template asyncAddrInfoLoop(addrInfo: ptr AddrInfo, fd: untyped, doConnect(curFd, curAddrInfo).callback = tryNextAddrInfo curAddrInfo = curAddrInfo.ai_next else: - freeAddrInfo(addrInfo) + freeaddrinfo(addrInfo) when shouldCreateFd: closeUnusedFds(ord(domain)) retFuture.complete(curFd) @@ -1888,9 +1756,9 @@ template asyncAddrInfoLoop(addrInfo: ptr AddrInfo, fd: untyped, proc dial*(address: string, port: Port, protocol: Protocol = IPPROTO_TCP): owned(Future[AsyncFD]) = - ## Establishes connection to the specified `address`:`port` pair via the + ## Establishes connection to the specified ``address``:``port`` pair via the ## specified protocol. The procedure iterates through possible - ## resolutions of the `address` until it succeeds, meaning that it + ## resolutions of the ``address`` until it succeeds, meaning that it ## seamlessly works with both IPv4 and IPv6. ## Returns the async file descriptor, registered in the dispatcher of ## the current thread, ready to send or receive data. @@ -1918,7 +1786,7 @@ proc connect*(socket: AsyncFD, address: string, port: Port, proc sleepAsync*(ms: int | float): owned(Future[void]) = ## Suspends the execution of the current async procedure for the next - ## `ms` milliseconds. + ## ``ms`` milliseconds. var retFuture = newFuture[void]("sleepAsync") let p = getGlobalDispatcher() when ms is int: @@ -1929,11 +1797,11 @@ proc sleepAsync*(ms: int | float): owned(Future[void]) = return retFuture proc withTimeout*[T](fut: Future[T], timeout: int): owned(Future[bool]) = - ## Returns a future which will complete once `fut` completes or after - ## `timeout` milliseconds has elapsed. + ## Returns a future which will complete once ``fut`` completes or after + ## ``timeout`` milliseconds has elapsed. ## - ## If `fut` completes first the returned future will hold true, - ## otherwise, if `timeout` milliseconds has elapsed first, the returned + ## If ``fut`` completes first the returned future will hold true, + ## otherwise, if ``timeout`` milliseconds has elapsed first, the returned ## future will hold false. var retFuture = newFuture[bool]("asyncdispatch.`withTimeout`") @@ -1951,17 +1819,12 @@ proc withTimeout*[T](fut: Future[T], timeout: int): owned(Future[bool]) = return retFuture proc accept*(socket: AsyncFD, - flags = {SocketFlag.SafeDisconn}, - inheritable = defined(nimInheritHandles)): owned(Future[AsyncFD]) = + flags = {SocketFlag.SafeDisconn}): owned(Future[AsyncFD]) = ## Accepts a new connection. Returns a future containing the client socket ## corresponding to that connection. - ## - ## If `inheritable` is false (the default), the resulting client socket - ## will not be inheritable by child processes. - ## ## The future will complete when the connection is successfully accepted. var retFut = newFuture[AsyncFD]("accept") - var fut = acceptAddr(socket, flags, inheritable) + var fut = acceptAddr(socket, flags) fut.callback = proc (future: Future[tuple[address: string, client: AsyncFD]]) = assert future.finished @@ -1976,7 +1839,7 @@ proc keepAlive(x: string) = proc send*(socket: AsyncFD, data: string, flags = {SocketFlag.SafeDisconn}): owned(Future[void]) = - ## Sends `data` to `socket`. The returned future will complete once all + ## Sends ``data`` to ``socket``. The returned future will complete once all ## data has been sent. var retFuture = newFuture[void]("send") if data.len > 0: @@ -1994,8 +1857,7 @@ proc send*(socket: AsyncFD, data: string, return retFuture # -- Await Macro -import asyncmacro -export asyncmacro +include asyncmacro proc readAll*(future: FutureStream[string]): owned(Future[string]) {.async.} = ## Returns a future that will complete when all the string data from the @@ -2022,44 +1884,3 @@ proc waitFor*[T](fut: Future[T]): T = poll() fut.read - -proc activeDescriptors*(): int {.inline.} = - ## Returns the current number of active file descriptors for the current - ## event loop. This is a cheap operation that does not involve a system call. - when defined(windows): - result = getGlobalDispatcher().handles.len - elif not defined(nimdoc): - result = getGlobalDispatcher().selector.count - -when defined(posix): - import posix - -when defined(linux) or defined(windows) or defined(macosx) or defined(bsd) or - defined(solaris) or defined(zephyr) or defined(freertos) or defined(nuttx): - proc maxDescriptors*(): int {.raises: OSError.} = - ## Returns the maximum number of active file descriptors for the current - ## process. This involves a system call. For now `maxDescriptors` is - ## supported on the following OSes: Windows, Linux, OSX, BSD, Solaris. - when defined(windows): - result = 16_700_000 - elif defined(zephyr) or defined(freertos): - result = FD_MAX - else: - var fdLim: RLimit - if getrlimit(RLIMIT_NOFILE, fdLim) < 0: - raiseOSError(osLastError()) - result = int(fdLim.rlim_cur) - 1 - -when defined(genode): - proc scheduleCallbacks*(): bool {.discardable.} = - ## *Genode only.* - ## Schedule callback processing and return immediately. - ## Returns `false` if there is nothing to schedule. - ## RPC servers should call this to dispatch `callSoon` - ## bodies after retiring an RPC to its client. - ## This is effectively a non-blocking `poll(…)` and is - ## equivalent to scheduling a momentary no-op timeout - ## but faster and with less overhead. - let dis = getGlobalDispatcher() - result = dis.callbacks.len > 0 - if result: submit(dis.signalHandler.cap) diff --git a/lib/pure/asyncfile.nim b/lib/pure/asyncfile.nim index 96d5e6d2e..ad111ec50 100644 --- a/lib/pure/asyncfile.nim +++ b/lib/pure/asyncfile.nim @@ -9,27 +9,21 @@ ## This module implements asynchronous file reading and writing. ## -## ```Nim -## import std/[asyncfile, asyncdispatch, os] +## .. code-block:: Nim +## import asyncfile, asyncdispatch, os ## -## proc main() {.async.} = -## var file = openAsync(getTempDir() / "foobar.txt", fmReadWrite) -## await file.write("test") -## file.setFilePos(0) -## let data = await file.readAll() -## doAssert data == "test" -## file.close() +## proc main() {.async.} = +## var file = openAsync(getTempDir() / "foobar.txt", fmReadWrite) +## await file.write("test") +## file.setFilePos(0) +## let data = await file.readAll() +## doAssert data == "test" +## file.close() ## -## waitFor main() -## ``` +## waitFor main() import asyncdispatch, os -when defined(nimPreviewSlimSystem): - import std/[assertions, syncio] - when defined(windows) or defined(nimdoc): - import std/widestrs - # TODO: Fix duplication introduced by PR #4683. when defined(windows) or defined(nimdoc): @@ -96,15 +90,20 @@ proc newAsyncFile*(fd: AsyncFD): AsyncFile = register(fd) proc openAsync*(filename: string, mode = fmRead): AsyncFile = - ## Opens a file specified by the path in `filename` using - ## the specified FileMode `mode` asynchronously. + ## Opens a file specified by the path in ``filename`` using + ## the specified FileMode ``mode`` asynchronously. when defined(windows) or defined(nimdoc): let flags = FILE_FLAG_OVERLAPPED or FILE_ATTRIBUTE_NORMAL let desiredAccess = getDesiredAccess(mode) let creationDisposition = getCreationDisposition(mode, filename) - let fd = createFileW(newWideCString(filename), desiredAccess, - FILE_SHARE_READ, - nil, creationDisposition, flags, 0) + when useWinUnicode: + let fd = createFileW(newWideCString(filename), desiredAccess, + FILE_SHARE_READ, + nil, creationDisposition, flags, 0) + else: + let fd = createFileA(filename, desiredAccess, + FILE_SHARE_READ, + nil, creationDisposition, flags, 0) if fd == INVALID_HANDLE_VALUE: raiseOSError(osLastError()) @@ -125,11 +124,11 @@ proc openAsync*(filename: string, mode = fmRead): AsyncFile = result = newAsyncFile(fd.AsyncFD) proc readBuffer*(f: AsyncFile, buf: pointer, size: int): Future[int] = - ## Read `size` bytes from the specified file asynchronously starting at + ## Read ``size`` bytes from the specified file asynchronously starting at ## the current position of the file pointer. ## ## If the file pointer is past the end of the file then zero is returned - ## and no bytes are read into `buf` + ## and no bytes are read into ``buf`` var retFuture = newFuture[int]("asyncfile.readBuffer") when defined(windows) or defined(nimdoc): @@ -202,12 +201,11 @@ proc readBuffer*(f: AsyncFile, buf: pointer, size: int): Future[int] = return retFuture proc read*(f: AsyncFile, size: int): Future[string] = - ## Read `size` bytes from the specified file asynchronously starting at - ## the current position of the file pointer. `size` should be greater than zero. + ## Read ``size`` bytes from the specified file asynchronously starting at + ## the current position of the file pointer. ## ## If the file pointer is past the end of the file then an empty string is ## returned. - assert size > 0 var retFuture = newFuture[string]("asyncfile.read") when defined(windows) or defined(nimdoc): @@ -334,7 +332,7 @@ proc readAll*(f: AsyncFile): Future[string] {.async.} = result.add data proc writeBuffer*(f: AsyncFile, buf: pointer, size: int): Future[void] = - ## Writes `size` bytes from `buf` to the file specified asynchronously. + ## Writes ``size`` bytes from ``buf`` to the file specified asynchronously. ## ## The returned Future will complete once all data has been written to the ## specified file. @@ -381,7 +379,7 @@ proc writeBuffer*(f: AsyncFile, buf: pointer, size: int): Future[void] = proc cb(fd: AsyncFD): bool = result = true - let remainderSize = size - written + let remainderSize = size-written var cbuf = cast[cstring](buf) let res = write(fd.cint, addr cbuf[written], remainderSize.cint) if res < 0: @@ -403,7 +401,7 @@ proc writeBuffer*(f: AsyncFile, buf: pointer, size: int): Future[void] = return retFuture proc write*(f: AsyncFile, data: string): Future[void] = - ## Writes `data` to the file specified asynchronously. + ## Writes ``data`` to the file specified asynchronously. ## ## The returned Future will complete once all data has been written to the ## specified file. @@ -411,7 +409,7 @@ proc write*(f: AsyncFile, data: string): Future[void] = var copy = data when defined(windows) or defined(nimdoc): var buffer = alloc0(data.len) - copyMem(buffer, copy.cstring, data.len) + copyMem(buffer, addr copy[0], data.len) var ol = newCustom() ol.data = CompletionData(fd: f.fd, cb: @@ -456,15 +454,8 @@ proc write*(f: AsyncFile, data: string): Future[void] = proc cb(fd: AsyncFD): bool = result = true - - let remainderSize = data.len - written - - let res = - if data.len == 0: - write(fd.cint, copy.cstring, 0) - else: - write(fd.cint, addr copy[written], remainderSize.cint) - + let remainderSize = data.len-written + let res = write(fd.cint, addr copy[written], remainderSize.cint) if res < 0: let lastError = osLastError() if lastError.int32 != EAGAIN: diff --git a/lib/pure/asyncftpclient.nim b/lib/pure/asyncftpclient.nim new file mode 100644 index 000000000..7bbfc2a35 --- /dev/null +++ b/lib/pure/asyncftpclient.nim @@ -0,0 +1,439 @@ +# +# +# Nim's Runtime Library +# (c) Copyright 2015 Dominik Picheta +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +## This module implements an asynchronous FTP client. It allows you to connect +## to an FTP server and perform operations on it such as for example: +## +## * The upload of new files. +## * The removal of existing files. +## * Download of files. +## * Changing of files' permissions. +## * Navigation through the FTP server's directories. +## +## Connecting to an FTP server +## =========================== +## +## In order to begin any sort of transfer of files you must first +## connect to an FTP server. You can do so with the ``connect`` procedure. +## +## .. code-block::nim +## import asyncdispatch, asyncftpclient +## proc main() {.async.} = +## var ftp = newAsyncFtpClient("example.com", user = "test", pass = "test") +## await ftp.connect() +## echo("Connected") +## waitFor(main()) +## +## A new ``main`` async procedure must be declared to allow the use of the +## ``await`` keyword. The connection will complete asynchronously and the +## client will be connected after the ``await ftp.connect()`` call. +## +## Uploading a new file +## ==================== +## +## After a connection is made you can use the ``store`` procedure to upload +## a new file to the FTP server. Make sure to check you are in the correct +## working directory before you do so with the ``pwd`` procedure, you can also +## instead specify an absolute path. +## +## .. code-block::nim +## import asyncdispatch, asyncftpclient +## proc main() {.async.} = +## var ftp = newAsyncFtpClient("example.com", user = "test", pass = "test") +## await ftp.connect() +## let currentDir = await ftp.pwd() +## assert currentDir == "/home/user/" +## await ftp.store("file.txt", "file.txt") +## echo("File finished uploading") +## waitFor(main()) +## +## Checking the progress of a file transfer +## ======================================== +## +## The progress of either a file upload or a file download can be checked +## by specifying a ``onProgressChanged`` procedure to the ``store`` or +## ``retrFile`` procedures. +## +## .. code-block::nim +## import asyncdispatch, asyncftpclient +## +## proc onProgressChanged(total, progress: BiggestInt, +## speed: float): Future[void] = +## echo("Uploaded ", progress, " of ", total, " bytes") +## echo("Current speed: ", speed, " kb/s") +## +## proc main() {.async.} = +## var ftp = newAsyncFtpClient("example.com", user = "test", pass = "test") +## await ftp.connect() +## await ftp.store("file.txt", "/home/user/file.txt", onProgressChanged) +## echo("File finished uploading") +## waitFor(main()) + + +import asyncdispatch, asyncnet, nativesockets, strutils, parseutils, os, times +from net import BufferSize + +type + AsyncFtpClient* = ref object + csock*: AsyncSocket + dsock*: AsyncSocket + user*, pass*: string + address*: string + port*: Port + jobInProgress*: bool + job*: FtpJob + dsockConnected*: bool + + FtpJobType* = enum + JRetrText, JRetr, JStore + + FtpJob = ref object + prc: proc (ftp: AsyncFtpClient, async: bool): bool {.nimcall, gcsafe.} + case typ*: FtpJobType + of JRetrText: + lines: string + of JRetr, JStore: + file: File + filename: string + total: BiggestInt # In bytes. + progress: BiggestInt # In bytes. + oneSecond: BiggestInt # Bytes transferred in one second. + lastProgressReport: float # Time + toStore: string # Data left to upload (Only used with async) + + FtpEventType* = enum + EvTransferProgress, EvLines, EvRetr, EvStore + + FtpEvent* = object ## Event + filename*: string + case typ*: FtpEventType + of EvLines: + lines*: string ## Lines that have been transferred. + of EvRetr, EvStore: ## Retr/Store operation finished. + nil + of EvTransferProgress: + bytesTotal*: BiggestInt ## Bytes total. + bytesFinished*: BiggestInt ## Bytes transferred. + speed*: BiggestInt ## Speed in bytes/s + currentJob*: FtpJobType ## The current job being performed. + + ReplyError* = object of IOError + + ProgressChangedProc* = + proc (total, progress: BiggestInt, speed: float): + Future[void] {.closure, gcsafe.} + +const multiLineLimit = 10000 + +proc expectReply(ftp: AsyncFtpClient): Future[TaintedString] {.async.} = + var line = await ftp.csock.recvLine() + result = TaintedString(line) + var count = 0 + while line[3] == '-': + ## Multi-line reply. + line = await ftp.csock.recvLine() + string(result).add("\n" & line) + count.inc() + if count >= multiLineLimit: + raise newException(ReplyError, "Reached maximum multi-line reply count.") + +proc send*(ftp: AsyncFtpClient, m: string): Future[TaintedString] {.async.} = + ## Send a message to the server, and wait for a primary reply. + ## ``\c\L`` is added for you. + ## + ## **Note:** The server may return multiple lines of coded replies. + await ftp.csock.send(m & "\c\L") + return await ftp.expectReply() + +proc assertReply(received: TaintedString, expected: varargs[string]) = + for i in items(expected): + if received.string.startsWith(i): return + raise newException(ReplyError, + "Expected reply '$1' got: $2" % + [expected.join("' or '"), received.string]) + +proc pasv(ftp: AsyncFtpClient) {.async.} = + ## Negotiate a data connection. + ftp.dsock = newAsyncSocket() + + var pasvMsg = (await ftp.send("PASV")).string.strip.TaintedString + assertReply(pasvMsg, "227") + var betweenParens = captureBetween(pasvMsg.string, '(', ')') + var nums = betweenParens.split(',') + var ip = nums[0 .. ^3] + var port = nums[^2 .. ^1] + var properPort = port[0].parseInt()*256+port[1].parseInt() + await ftp.dsock.connect(ip.join("."), Port(properPort)) + ftp.dsockConnected = true + +proc normalizePathSep(path: string): string = + return replace(path, '\\', '/') + +proc connect*(ftp: AsyncFtpClient) {.async.} = + ## Connect to the FTP server specified by ``ftp``. + await ftp.csock.connect(ftp.address, ftp.port) + + var reply = await ftp.expectReply() + if string(reply).startsWith("120"): + # 120 Service ready in nnn minutes. + # We wait until we receive 220. + reply = await ftp.expectReply() + + # Handle 220 messages from the server + assertReply(reply, "220") + + if ftp.user != "": + assertReply(await(ftp.send("USER " & ftp.user)), "230", "331") + + if ftp.pass != "": + assertReply(await(ftp.send("PASS " & ftp.pass)), "230") + +proc pwd*(ftp: AsyncFtpClient): Future[TaintedString] {.async.} = + ## Returns the current working directory. + let wd = await ftp.send("PWD") + assertReply wd, "257" + return wd.string.captureBetween('"').TaintedString # " + +proc cd*(ftp: AsyncFtpClient, dir: string) {.async.} = + ## Changes the current directory on the remote FTP server to ``dir``. + assertReply(await(ftp.send("CWD " & dir.normalizePathSep)), "250") + +proc cdup*(ftp: AsyncFtpClient) {.async.} = + ## Changes the current directory to the parent of the current directory. + assertReply(await(ftp.send("CDUP")), "200") + +proc getLines(ftp: AsyncFtpClient): Future[string] {.async.} = + ## Downloads text data in ASCII mode + result = "" + assert ftp.dsockConnected + while ftp.dsockConnected: + let r = await ftp.dsock.recvLine() + if r.string == "": + ftp.dsockConnected = false + else: + result.add(r.string & "\n") + + assertReply(await(ftp.expectReply()), "226") + +proc listDirs*(ftp: AsyncFtpClient, dir = ""): Future[seq[string]] {.async.} = + ## Returns a list of filenames in the given directory. If ``dir`` is "", + ## the current directory is used. If ``async`` is true, this + ## function will return immediately and it will be your job to + ## use asyncdispatch's ``poll`` to progress this operation. + await ftp.pasv() + + assertReply(await(ftp.send("NLST " & dir.normalizePathSep)), ["125", "150"]) + + result = splitLines(await ftp.getLines()) + +proc existsFile*(ftp: AsyncFtpClient, file: string): Future[bool] {.async.} = + ## Determines whether ``file`` exists. + var files = await ftp.listDirs() + for f in items(files): + if f.normalizePathSep == file.normalizePathSep: return true + +proc createDir*(ftp: AsyncFtpClient, dir: string, recursive = false){.async.} = + ## Creates a directory ``dir``. If ``recursive`` is true, the topmost + ## subdirectory of ``dir`` will be created first, following the secondmost... + ## etc. this allows you to give a full path as the ``dir`` without worrying + ## about subdirectories not existing. + if not recursive: + assertReply(await(ftp.send("MKD " & dir.normalizePathSep)), "257") + else: + var reply = TaintedString"" + var previousDirs = "" + for p in split(dir, {os.DirSep, os.AltSep}): + if p != "": + previousDirs.add(p) + reply = await ftp.send("MKD " & previousDirs) + previousDirs.add('/') + assertReply reply, "257" + +proc chmod*(ftp: AsyncFtpClient, path: string, + permissions: set[FilePermission]) {.async.} = + ## Changes permission of ``path`` to ``permissions``. + var userOctal = 0 + var groupOctal = 0 + var otherOctal = 0 + for i in items(permissions): + case i + of fpUserExec: userOctal.inc(1) + of fpUserWrite: userOctal.inc(2) + of fpUserRead: userOctal.inc(4) + of fpGroupExec: groupOctal.inc(1) + of fpGroupWrite: groupOctal.inc(2) + of fpGroupRead: groupOctal.inc(4) + of fpOthersExec: otherOctal.inc(1) + of fpOthersWrite: otherOctal.inc(2) + of fpOthersRead: otherOctal.inc(4) + + var perm = $userOctal & $groupOctal & $otherOctal + assertReply(await(ftp.send("SITE CHMOD " & perm & + " " & path.normalizePathSep)), "200") + +proc list*(ftp: AsyncFtpClient, dir = ""): Future[string] {.async.} = + ## Lists all files in ``dir``. If ``dir`` is ``""``, uses the current + ## working directory. + await ftp.pasv() + + let reply = await ftp.send("LIST" & " " & dir.normalizePathSep) + assertReply(reply, ["125", "150"]) + + result = await ftp.getLines() + +proc retrText*(ftp: AsyncFtpClient, file: string): Future[string] {.async.} = + ## Retrieves ``file``. File must be ASCII text. + await ftp.pasv() + let reply = await ftp.send("RETR " & file.normalizePathSep) + assertReply(reply, ["125", "150"]) + + result = await ftp.getLines() + +proc getFile(ftp: AsyncFtpClient, file: File, total: BiggestInt, + onProgressChanged: ProgressChangedProc) {.async.} = + assert ftp.dsockConnected + var progress = 0 + var progressInSecond = 0 + var countdownFut = sleepAsync(1000) + var dataFut = ftp.dsock.recv(BufferSize) + while ftp.dsockConnected: + await dataFut or countdownFut + if countdownFut.finished: + asyncCheck onProgressChanged(total, progress, + progressInSecond.float) + progressInSecond = 0 + countdownFut = sleepAsync(1000) + + if dataFut.finished: + let data = dataFut.read + if data != "": + progress.inc(data.len) + progressInSecond.inc(data.len) + file.write(data) + dataFut = ftp.dsock.recv(BufferSize) + else: + ftp.dsockConnected = false + + assertReply(await(ftp.expectReply()), "226") + +proc defaultOnProgressChanged*(total, progress: BiggestInt, + speed: float): Future[void] {.nimcall, gcsafe, procvar.} = + ## Default FTP ``onProgressChanged`` handler. Does nothing. + result = newFuture[void]() + #echo(total, " ", progress, " ", speed) + result.complete() + +proc retrFile*(ftp: AsyncFtpClient, file, dest: string, + onProgressChanged: ProgressChangedProc = defaultOnProgressChanged) {.async.} = + ## Downloads ``file`` and saves it to ``dest``. + ## The ``EvRetr`` event is passed to the specified ``handleEvent`` function + ## when the download is finished. The event's ``filename`` field will be equal + ## to ``file``. + var destFile = open(dest, mode = fmWrite) + await ftp.pasv() + var reply = await ftp.send("RETR " & file.normalizePathSep) + assertReply reply, ["125", "150"] + if {'(', ')'} notin reply.string: + raise newException(ReplyError, "Reply has no file size.") + var fileSize: BiggestInt + if reply.string.captureBetween('(', ')').parseBiggestInt(fileSize) == 0: + raise newException(ReplyError, "Reply has no file size.") + + await getFile(ftp, destFile, fileSize, onProgressChanged) + destFile.close() + +proc doUpload(ftp: AsyncFtpClient, file: File, + onProgressChanged: ProgressChangedProc) {.async.} = + assert ftp.dsockConnected + + let total = file.getFileSize() + var data = newString(4000) + var progress = 0 + var progressInSecond = 0 + var countdownFut = sleepAsync(1000) + var sendFut: Future[void] = nil + while ftp.dsockConnected: + if sendFut == nil or sendFut.finished: + # TODO: Async file reading. + let len = file.readBuffer(addr(data[0]), 4000) + setLen(data, len) + if len == 0: + # File finished uploading. + ftp.dsock.close() + ftp.dsockConnected = false + + assertReply(await(ftp.expectReply()), "226") + else: + progress.inc(len) + progressInSecond.inc(len) + sendFut = ftp.dsock.send(data) + + if countdownFut.finished: + asyncCheck onProgressChanged(total, progress, progressInSecond.float) + progressInSecond = 0 + countdownFut = sleepAsync(1000) + + await countdownFut or sendFut + +proc store*(ftp: AsyncFtpClient, file, dest: string, + onProgressChanged: ProgressChangedProc = defaultOnProgressChanged) {.async.} = + ## Uploads ``file`` to ``dest`` on the remote FTP server. Usage of this + ## function asynchronously is recommended to view the progress of + ## the download. + ## The ``EvStore`` event is passed to the specified ``handleEvent`` function + ## when the upload is finished, and the ``filename`` field will be + ## equal to ``file``. + var destFile = open(file) + await ftp.pasv() + + let reply = await ftp.send("STOR " & dest.normalizePathSep) + assertReply reply, ["125", "150"] + + await doUpload(ftp, destFile, onProgressChanged) + +proc rename*(ftp: AsyncFtpClient, nameFrom: string, nameTo: string) {.async.} = + ## Rename a file or directory on the remote FTP Server from current name + ## ``name_from`` to new name ``name_to`` + assertReply(await ftp.send("RNFR " & nameFrom), "350") + assertReply(await ftp.send("RNTO " & nameTo), "250") + +proc removeFile*(ftp: AsyncFtpClient, filename: string) {.async.} = + ## Delete a file ``filename`` on the remote FTP server + assertReply(await ftp.send("DELE " & filename), "250") + +proc removeDir*(ftp: AsyncFtpClient, dir: string) {.async.} = + ## Delete a directory ``dir`` on the remote FTP server + assertReply(await ftp.send("RMD " & dir), "250") + +proc newAsyncFtpClient*(address: string, port = Port(21), + user, pass = ""): AsyncFtpClient = + ## Creates a new ``AsyncFtpClient`` object. + new result + result.user = user + result.pass = pass + result.address = address + result.port = port + result.dsockConnected = false + result.csock = newAsyncSocket() + +when not defined(testing) and isMainModule: + var ftp = newAsyncFtpClient("example.com", user = "test", pass = "test") + proc main(ftp: AsyncFtpClient) {.async.} = + await ftp.connect() + echo await ftp.pwd() + echo await ftp.listDirs() + await ftp.store("payload.jpg", "payload.jpg") + await ftp.retrFile("payload.jpg", "payload2.jpg") + await ftp.rename("payload.jpg", "payload_renamed.jpg") + await ftp.store("payload.jpg", "payload_remove.jpg") + await ftp.removeFile("payload_remove.jpg") + await ftp.createDir("deleteme") + await ftp.removeDir("deleteme") + echo("Finished") + + waitFor main(ftp) diff --git a/lib/pure/asyncfutures.nim b/lib/pure/asyncfutures.nim index 51aaaca36..7aac192d2 100644 --- a/lib/pure/asyncfutures.nim +++ b/lib/pure/asyncfutures.nim @@ -9,12 +9,6 @@ import os, tables, strutils, times, heapqueue, options, deques, cstrutils -import system/stacktraces - -when defined(nimPreviewSlimSystem): - import std/objectdollar # for StackTraceEntry - import std/assertions - # TODO: This shouldn't need to be included, but should ideally be exported. type CallbackFunc = proc () {.closure, gcsafe.} @@ -29,7 +23,7 @@ type finished: bool error*: ref Exception ## Stored exception errorStackTrace*: string - when not defined(release) or defined(futureLogging): + when not defined(release): stackTrace: seq[StackTraceEntry] ## For debugging purposes only. id: int fromProc: string @@ -39,7 +33,7 @@ type FutureVar*[T] = distinct Future[T] - FutureError* = object of Defect + FutureError* = object of Exception cause*: FutureBase when not defined(release): @@ -90,19 +84,19 @@ when isFutureLoggingEnabled: var callSoonProc {.threadvar.}: proc (cbproc: proc ()) {.gcsafe.} proc getCallSoonProc*(): (proc(cbproc: proc ()) {.gcsafe.}) = - ## Get current implementation of `callSoon`. + ## Get current implementation of ``callSoon``. return callSoonProc proc setCallSoonProc*(p: (proc(cbproc: proc ()) {.gcsafe.})) = - ## Change current implementation of `callSoon`. This is normally called when dispatcher from `asyncdispatcher` is initialized. + ## Change current implementation of ``callSoon``. This is normally called when dispatcher from ``asyncdispatcher`` is initialized. callSoonProc = p -proc callSoon*(cbproc: proc () {.gcsafe.}) = - ## Call `cbproc` "soon". +proc callSoon*(cbproc: proc ()) = + ## Call ``cbproc`` "soon". ## - ## If async dispatcher is running, `cbproc` will be executed during next dispatcher tick. + ## If async dispatcher is running, ``cbproc`` will be executed during next dispatcher tick. ## - ## If async dispatcher is not running, `cbproc` will be executed immediately. + ## If async dispatcher is not running, ``cbproc`` will be executed immediately. if callSoonProc.isNil: # Loop not initialized yet. Call the function directly to allow setup code to use futures. cbproc() @@ -121,29 +115,29 @@ template setupFutureBase(fromProc: string) = proc newFuture*[T](fromProc: string = "unspecified"): owned(Future[T]) = ## Creates a new future. ## - ## Specifying `fromProc`, which is a string specifying the name of the proc + ## Specifying ``fromProc``, which is a string specifying the name of the proc ## that this future belongs to, is a good habit as it helps with debugging. setupFutureBase(fromProc) when isFutureLoggingEnabled: logFutureStart(result) proc newFutureVar*[T](fromProc = "unspecified"): owned(FutureVar[T]) = - ## Create a new `FutureVar`. This Future type is ideally suited for + ## Create a new ``FutureVar``. This Future type is ideally suited for ## situations where you want to avoid unnecessary allocations of Futures. ## - ## Specifying `fromProc`, which is a string specifying the name of the proc + ## Specifying ``fromProc``, which is a string specifying the name of the proc ## that this future belongs to, is a good habit as it helps with debugging. let fo = newFuture[T](fromProc) result = typeof(result)(fo) when isFutureLoggingEnabled: logFutureStart(Future[T](result)) proc clean*[T](future: FutureVar[T]) = - ## Resets the `finished` status of `future`. + ## Resets the ``finished`` status of ``future``. Future[T](future).finished = false Future[T](future).error = nil proc checkFinished[T](future: Future[T]) = ## Checks whether `future` is finished. If it is then raises a - ## `FutureError`. + ## ``FutureError``. when not defined(release): if future.finished: var msg = "" @@ -163,15 +157,33 @@ proc checkFinished[T](future: Future[T]) = raise err proc call(callbacks: var CallbackList) = - var current = callbacks - while true: - if not current.function.isNil: - callSoon(current.function) + when not defined(nimV2): + # strictly speaking a little code duplication here, but we strive + # to minimize regressions and I'm not sure I got the 'nimV2' logic + # right: + var current = callbacks + while true: + if not current.function.isNil: + callSoon(current.function) + + if current.next.isNil: + break + else: + current = current.next[] + else: + var currentFunc = unown callbacks.function + var currentNext = unown callbacks.next + + while true: + if not currentFunc.isNil: + callSoon(currentFunc) + + if currentNext.isNil: + break + else: + currentFunc = currentNext.function + currentNext = unown currentNext.next - if current.next.isNil: - break - else: - current = current.next[] # callback will be called only once, let GC collect them now callbacks.next = nil callbacks.function = nil @@ -193,25 +205,27 @@ proc add(callbacks: var CallbackList, function: CallbackFunc) = last = last.next last.next = newCallback -proc completeImpl[T, U](future: Future[T], val: U, isVoid: static bool) = +proc complete*[T](future: Future[T], val: T) = + ## Completes ``future`` with value ``val``. #assert(not future.finished, "Future already finished, cannot finish twice.") checkFinished(future) assert(future.error == nil) - when not isVoid: - future.value = val + future.value = val future.finished = true future.callbacks.call() when isFutureLoggingEnabled: logFutureFinish(future) -proc complete*[T](future: Future[T], val: T) = - ## Completes `future` with value `val`. - completeImpl(future, val, false) - -proc complete*(future: Future[void], val = Future[void].default) = - completeImpl(future, (), true) +proc complete*(future: Future[void]) = + ## Completes a void ``future``. + #assert(not future.finished, "Future already finished, cannot finish twice.") + checkFinished(future) + assert(future.error == nil) + future.finished = true + future.callbacks.call() + when isFutureLoggingEnabled: logFutureFinish(future) proc complete*[T](future: FutureVar[T]) = - ## Completes a `FutureVar`. + ## Completes a ``FutureVar``. template fut: untyped = Future[T](future) checkFinished(fut) assert(fut.error == nil) @@ -220,7 +234,7 @@ proc complete*[T](future: FutureVar[T]) = when isFutureLoggingEnabled: logFutureFinish(Future[T](future)) proc complete*[T](future: FutureVar[T], val: T) = - ## Completes a `FutureVar` with value `val`. + ## Completes a ``FutureVar`` with value ``val``. ## ## Any previously stored value will be overwritten. template fut: untyped = Future[T](future) @@ -229,10 +243,10 @@ proc complete*[T](future: FutureVar[T], val: T) = fut.finished = true fut.value = val fut.callbacks.call() - when isFutureLoggingEnabled: logFutureFinish(fut) + when isFutureLoggingEnabled: logFutureFinish(future) proc fail*[T](future: Future[T], error: ref Exception) = - ## Completes `future` with `error`. + ## Completes ``future`` with ``error``. #assert(not future.finished, "Future already finished, cannot finish twice.") checkFinished(future) future.finished = true @@ -249,7 +263,7 @@ proc clearCallbacks*(future: FutureBase) = proc addCallback*(future: FutureBase, cb: proc() {.closure, gcsafe.}) = ## Adds the callbacks proc to be called when the future completes. ## - ## If future has already completed then `cb` will be called immediately. + ## If future has already completed then ``cb`` will be called immediately. assert cb != nil if future.finished: callSoon(cb) @@ -260,7 +274,7 @@ proc addCallback*[T](future: Future[T], cb: proc (future: Future[T]) {.closure, gcsafe.}) = ## Adds the callbacks proc to be called when the future completes. ## - ## If future has already completed then `cb` will be called immediately. + ## If future has already completed then ``cb`` will be called immediately. future.addCallback( proc() = cb(future) @@ -269,9 +283,9 @@ proc addCallback*[T](future: Future[T], proc `callback=`*(future: FutureBase, cb: proc () {.closure, gcsafe.}) = ## Clears the list of callbacks and sets the callback proc to be called when the future completes. ## - ## If future has already completed then `cb` will be called immediately. + ## If future has already completed then ``cb`` will be called immediately. ## - ## It's recommended to use `addCallback` or `then` instead. + ## It's recommended to use ``addCallback`` or ``then`` instead. future.clearCallbacks future.addCallback cb @@ -279,71 +293,56 @@ proc `callback=`*[T](future: Future[T], cb: proc (future: Future[T]) {.closure, gcsafe.}) = ## Sets the callback proc to be called when the future completes. ## - ## If future has already completed then `cb` will be called immediately. + ## If future has already completed then ``cb`` will be called immediately. future.callback = proc () = cb(future) -template getFilenameProcname(entry: StackTraceEntry): (string, string) = - when compiles(entry.filenameStr) and compiles(entry.procnameStr): - # We can't rely on "entry.filename" and "entry.procname" still being valid - # cstring pointers, because the "string.data" buffers they pointed to might - # be already garbage collected (this entry being a non-shallow copy, - # "entry.filename" no longer points to "entry.filenameStr.data", but to the - # buffer of the original object). - (entry.filenameStr, entry.procnameStr) - else: - ($entry.filename, $entry.procname) - proc getHint(entry: StackTraceEntry): string = ## We try to provide some hints about stack trace entries that the user ## may not be familiar with, in particular calls inside the stdlib. - - let (filename, procname) = getFilenameProcname(entry) - result = "" - if procname == "processPendingCallbacks": - if cmpIgnoreStyle(filename, "asyncdispatch.nim") == 0: + if entry.procname == cstring"processPendingCallbacks": + if cmpIgnoreStyle(entry.filename, "asyncdispatch.nim") == 0: return "Executes pending callbacks" - elif procname == "poll": - if cmpIgnoreStyle(filename, "asyncdispatch.nim") == 0: + elif entry.procname == cstring"poll": + if cmpIgnoreStyle(entry.filename, "asyncdispatch.nim") == 0: return "Processes asynchronous completion events" - if procname.endsWith(NimAsyncContinueSuffix): - if cmpIgnoreStyle(filename, "asyncmacro.nim") == 0: + if entry.procname.endsWith(NimAsyncContinueSuffix): + if cmpIgnoreStyle(entry.filename, "asyncmacro.nim") == 0: return "Resumes an async procedure" -proc `$`*(stackTraceEntries: seq[StackTraceEntry]): string = - when defined(nimStackTraceOverride): - let entries = addDebuggingInfo(stackTraceEntries) - else: - let entries = stackTraceEntries - +proc `$`*(entries: seq[StackTraceEntry]): string = result = "" # Find longest filename & line number combo for alignment purposes. var longestLeft = 0 for entry in entries: - let (filename, procname) = getFilenameProcname(entry) + if entry.procname.isNil: continue - if procname == "": continue - - let leftLen = filename.len + len($entry.line) - if leftLen > longestLeft: - longestLeft = leftLen + let left = $entry.filename & $entry.line + if left.len > longestLeft: + longestLeft = left.len + var indent = 2 # Format the entries. for entry in entries: - let (filename, procname) = getFilenameProcname(entry) + if entry.procname.isNil: + if entry.line == -10: + result.add(spaces(indent) & "#[\n") + indent.inc(2) + else: + indent.dec(2) + result.add(spaces(indent) & "]#\n") + continue - if procname == "" and entry.line == reraisedFromBegin: - break - - let left = "$#($#)" % [filename, $entry.line] - result.add((spaces(2) & "$# $#\n") % [ + let left = "$#($#)" % [$entry.filename, $entry.line] + result.add((spaces(indent) & "$#$# $#\n") % [ left, - procname + spaces(longestLeft - left.len + 2), + $entry.procname ]) let hint = getHint(entry) if hint.len > 0: - result.add(spaces(4) & "## " & hint & "\n") + result.add(spaces(indent+2) & "## " & hint & "\n") proc injectStacktrace[T](future: Future[T]) = when not defined(release): @@ -363,67 +362,66 @@ proc injectStacktrace[T](future: Future[T]) = newMsg.add($entries) newMsg.add("Exception message: " & exceptionMsg & "\n") + newMsg.add("Exception type:") # # For debugging purposes - # newMsg.add("Exception type:") # for entry in getStackTraceEntries(future.error): # newMsg.add "\n" & $entry future.error.msg = newMsg proc read*[T](future: Future[T] | FutureVar[T]): T = - ## Retrieves the value of `future`. Future must be finished otherwise - ## this function will fail with a `ValueError` exception. + ## Retrieves the value of ``future``. Future must be finished otherwise + ## this function will fail with a ``ValueError`` exception. ## ## If the result of the future is an error then that error will be raised. - when future is Future[T]: - let fut {.cursor.} = future - else: - let fut {.cursor.} = Future[T](future) + {.push hint[ConvFromXtoItselfNotNeeded]: off.} + let fut = Future[T](future) + {.pop.} if fut.finished: if fut.error != nil: injectStacktrace(fut) raise fut.error when T isnot void: - result = fut.value + return fut.value else: # TODO: Make a custom exception type for this? raise newException(ValueError, "Future still in progress.") proc readError*[T](future: Future[T]): ref Exception = - ## Retrieves the exception stored in `future`. + ## Retrieves the exception stored in ``future``. ## - ## An `ValueError` exception will be thrown if no exception exists + ## An ``ValueError`` exception will be thrown if no exception exists ## in the specified Future. if future.error != nil: return future.error else: raise newException(ValueError, "No error in future.") proc mget*[T](future: FutureVar[T]): var T = - ## Returns a mutable value stored in `future`. + ## Returns a mutable value stored in ``future``. ## - ## Unlike `read`, this function will not raise an exception if the + ## Unlike ``read``, this function will not raise an exception if the ## Future has not been finished. result = Future[T](future).value proc finished*(future: FutureBase | FutureVar): bool = - ## Determines whether `future` has completed. + ## Determines whether ``future`` has completed. ## - ## `True` may indicate an error or a value. Use `failed` to distinguish. + ## ``True`` may indicate an error or a value. Use ``failed`` to distinguish. when future is FutureVar: result = (FutureBase(future)).finished else: result = future.finished proc failed*(future: FutureBase): bool = - ## Determines whether `future` completed with an error. + ## Determines whether ``future`` completed with an error. return future.error != nil proc asyncCheck*[T](future: Future[T]) = - ## Sets a callback on `future` which raises an exception if the future + ## Sets a callback on ``future`` which raises an exception if the future ## finished with an error. ## - ## This should be used instead of `discard` to discard void futures, - ## or use `waitFor` if you need to wait for the future's completion. + ## This should be used instead of ``discard`` to discard void futures, + ## or use ``waitFor`` if you need to wait for the future's completion. assert(not future.isNil, "Future is nil") # TODO: We can likely look at the stack trace here and inject the location # where the `asyncCheck` was called to give a better error stack message. @@ -434,7 +432,7 @@ proc asyncCheck*[T](future: Future[T]) = future.callback = asyncCheckCallback proc `and`*[T, Y](fut1: Future[T], fut2: Future[Y]): Future[void] = - ## Returns a future which will complete once both `fut1` and `fut2` + ## Returns a future which will complete once both ``fut1`` and ``fut2`` ## complete. var retFuture = newFuture[void]("asyncdispatch.`and`") fut1.callback = @@ -450,7 +448,7 @@ proc `and`*[T, Y](fut1: Future[T], fut2: Future[Y]): Future[void] = return retFuture proc `or`*[T, Y](fut1: Future[T], fut2: Future[Y]): Future[void] = - ## Returns a future which will complete once either `fut1` or `fut2` + ## Returns a future which will complete once either ``fut1`` or ``fut2`` ## complete. var retFuture = newFuture[void]("asyncdispatch.`or`") proc cb[X](fut: Future[X]) = @@ -463,14 +461,14 @@ proc `or`*[T, Y](fut1: Future[T], fut2: Future[Y]): Future[void] = proc all*[T](futs: varargs[Future[T]]): auto = ## Returns a future which will complete once - ## all futures in `futs` complete. + ## all futures in ``futs`` complete. ## If the argument is empty, the returned future completes immediately. ## - ## If the awaited futures are not `Future[void]`, the returned future + ## If the awaited futures are not ``Future[void]``, the returned future ## will hold the values of all awaited futures in a sequence. ## - ## If the awaited futures *are* `Future[void]`, - ## this proc returns `Future[void]`. + ## If the awaited futures *are* ``Future[void]``, + ## this proc returns ``Future[void]``. when T is void: var diff --git a/lib/pure/asynchttpserver.nim b/lib/pure/asynchttpserver.nim index c09fe35ca..5292ac75a 100644 --- a/lib/pure/asynchttpserver.nim +++ b/lib/pure/asynchttpserver.nim @@ -11,86 +11,126 @@ ## ## This HTTP server has not been designed to be used in production, but ## for testing applications locally. Because of this, when deploying your -## application in production you should use a reverse proxy (for example nginx) -## instead of allowing users to connect directly to this server. +## application you should use a reverse proxy (for example nginx) instead of +## allowing users to connect directly to this server. +## +## Basic usage +## =========== +## +## This example will create an HTTP server on port 8080. The server will +## respond to all requests with a ``200 OK`` response code and "Hello World" +## as the response body. +## +## .. code-block::nim +## import asynchttpserver, asyncdispatch +## +## var server = newAsyncHttpServer() +## proc cb(req: Request) {.async.} = +## await req.respond(Http200, "Hello World") +## +## waitFor server.serve(Port(8080), cb) +## +## Basic Post request handle +## ========================= +## +## This example will create an HTTP server on port 8080. The server will +## respond with a page with the actual and expected body length after +## submitting a file. +## +## .. code-block::nim +## import asynchttpserver, asyncdispatch +## import strutils, strformat +## +## proc htmlpage(contentLength, bodyLength: int): string = +## return &""" +## +## +## +## +## +## +##
+## File:
+## +##

+## Expected Body Length: {contentLength} bytes
+## Actual Body Length: {bodyLength} bytes +## +## +## """ +## +## proc cb(req: Request) {.async.} = +## var +## contentLength = 0 +## bodyLength = 0 +## if req.reqMethod == HttpPost: +## contentLength = req.headers["Content-length"].parseInt +## if contentLength < 8*1024: # the default chunkSize +## # read the request body at once +## let body = await req.bodyStream.readAll(); +## bodyLength = body.len +## else: +## # read 8*1024 bytes at a time +## while (let data = await req.bodyStream.read(); data[0]): +## bodyLength += data[1].len +## await req.respond(Http200, htmlpage(contentLength, bodyLength)) +## +## let server = newAsyncHttpServer(maxBody = 10485760) # 10 MB +## waitFor server.serve(Port(8080), cb) -runnableExamples("-r:off"): - # This example will create an HTTP server on an automatically chosen port. - # It will respond to all requests with a `200 OK` response code and "Hello World" - # as the response body. - import std/asyncdispatch - proc main {.async.} = - var server = newAsyncHttpServer() - proc cb(req: Request) {.async.} = - echo (req.reqMethod, req.url, req.headers) - let headers = {"Content-type": "text/plain; charset=utf-8"} - await req.respond(Http200, "Hello World", headers.newHttpHeaders()) - - server.listen(Port(0)) # or Port(8080) to hardcode the standard HTTP port. - let port = server.getPort - echo "test this with: curl localhost:" & $port.uint16 & "/" - while true: - if server.shouldAcceptRequest(): - await server.acceptRequest(cb) - else: - # too many concurrent connections, `maxFDs` exceeded - # wait 500ms for FDs to be closed - await sleepAsync(500) - - waitFor main() - -import asyncnet, asyncdispatch, parseutils, uri, strutils +import tables, asyncnet, asyncdispatch, parseutils, uri, strutils import httpcore -from nativesockets import getLocalAddr, Domain, AF_INET, AF_INET6 -import std/private/since - -when defined(nimPreviewSlimSystem): - import std/assertions export httpcore except parseHeader -const - maxLine = 8*1024 - # TODO: If it turns out that the decisions that asynchttpserver makes # explicitly, about whether to close the client sockets or upgrade them are # wrong, then add a return value which determines what to do for the callback. # Also, maybe move `client` out of `Request` object and into the args for # the proc. -type - Request* = object - client*: AsyncSocket # TODO: Separate this into a Response object? - reqMethod*: HttpMethod - headers*: HttpHeaders - protocol*: tuple[orig: string, major, minor: int] - url*: Uri - hostname*: string ## The hostname of the client that made the request. - body*: string +const + maxLine = 8*1024 + +when (NimMajor, NimMinor) >= (1, 1): + const + chunkSize = 8*1024 ## This seems perfectly reasonable for default chunkSize. + + type + Request* = object + client*: AsyncSocket # TODO: Separate this into a Response object? + reqMethod*: HttpMethod + headers*: HttpHeaders + protocol*: tuple[orig: string, major, minor: int] + url*: Uri + hostname*: string ## The hostname of the client that made the request. + body*: string # For future removal + bodyStream*: FutureStream[string] +else: + type + Request* = object + client*: AsyncSocket # TODO: Separate this into a Response object? + reqMethod*: HttpMethod + headers*: HttpHeaders + protocol*: tuple[orig: string, major, minor: int] + url*: Uri + hostname*: string ## The hostname of the client that made the request. + body*: string + +type AsyncHttpServer* = ref object socket: AsyncSocket reuseAddr: bool reusePort: bool maxBody: int ## The maximum content-length that will be read for the body. - maxFDs: int - -proc getPort*(self: AsyncHttpServer): Port {.since: (1, 5, 1).} = - ## Returns the port `self` was bound to. - ## - ## Useful for identifying what port `self` is bound to, if it - ## was chosen automatically, for example via `listen(Port(0))`. - runnableExamples: - from std/nativesockets import Port - let server = newAsyncHttpServer() - server.listen(Port(0)) - assert server.getPort.uint16 > 0 - server.close() - result = getLocalAddr(self.socket)[1] proc newAsyncHttpServer*(reuseAddr = true, reusePort = false, maxBody = 8388608): AsyncHttpServer = - ## Creates a new `AsyncHttpServer` instance. - result = AsyncHttpServer(reuseAddr: reuseAddr, reusePort: reusePort, maxBody: maxBody) + ## Creates a new ``AsyncHttpServer`` instance. + new result + result.reuseAddr = reuseAddr + result.reusePort = reusePort + result.maxBody = maxBody proc addHeaders(msg: var string, headers: HttpHeaders) = for k, v in headers: @@ -104,15 +144,15 @@ proc sendHeaders*(req: Request, headers: HttpHeaders): Future[void] = proc respond*(req: Request, code: HttpCode, content: string, headers: HttpHeaders = nil): Future[void] = - ## Responds to the request with the specified `HttpCode`, headers and + ## Responds to the request with the specified ``HttpCode``, headers and ## content. ## ## This procedure will **not** close the client socket. ## ## Example: ## - ## .. code-block:: Nim - ## import std/json + ## .. code-block::nim + ## import json ## proc handler(req: Request) {.async.} = ## if req.url.path == "/hello-world": ## let msg = %* {"message": "Hello World"} @@ -124,20 +164,15 @@ proc respond*(req: Request, code: HttpCode, content: string, if headers != nil: msg.addHeaders(headers) - - # If the headers did not contain a Content-Length use our own - if headers.isNil() or not headers.hasKey("Content-Length"): - msg.add("Content-Length: ") - # this particular way saves allocations: - msg.addInt content.len - msg.add "\c\L" - - msg.add "\c\L" + msg.add("Content-Length: ") + # this particular way saves allocations: + msg.add content.len + msg.add "\c\L\c\L" msg.add(content) result = req.client.send(msg) proc respondError(req: Request, code: HttpCode): Future[void] = - ## Responds to the request with the specified `HttpCode`. + ## Responds to the request with the specified ``HttpCode``. let content = $code var msg = "HTTP/1.1 " & content & "\c\L" @@ -158,22 +193,11 @@ proc parseProtocol(protocol: string): tuple[orig: string, major, minor: int] = proc sendStatus(client: AsyncSocket, status: string): Future[void] = client.send("HTTP/1.1 " & status & "\c\L\c\L") -func hasChunkedEncoding(request: Request): bool = - ## Searches for a chunked transfer encoding - const transferEncoding = "Transfer-Encoding" - - if request.headers.hasKey(transferEncoding): - for encoding in seq[string](request.headers[transferEncoding]): - if "chunked" == encoding.strip: - # Returns true if it is both an HttpPost and has chunked encoding - return request.reqMethod == HttpPost - return false - proc processRequest( server: AsyncHttpServer, req: FutureVar[Request], client: AsyncSocket, - address: sink string, + address: string, lineFut: FutureVar[string], callback: proc (request: Request): Future[void] {.closure, gcsafe.}, ): Future[bool] {.async.} = @@ -186,13 +210,16 @@ proc processRequest( # Header: val # \n request.headers.clear() - request.body = "" - when defined(gcArc) or defined(gcOrc): - request.hostname = address - else: - request.hostname.shallowCopy(address) + request.hostname.shallowCopy(address) assert client != nil request.client = client + when (NimMajor, NimMinor) >= (1, 1): + request.bodyStream = newFutureStream[string]() + # To uncomment in the future after compatibility issues + # with third parties are solved + # else: + # request.body = "" + request.body = "" # Temporary fix for future removal # We should skip at least one empty line before the request # https://tools.ietf.org/html/rfc7230#section-3.5 @@ -287,47 +314,23 @@ proc processRequest( if contentLength > server.maxBody: await request.respondError(Http413) return false - request.body = await client.recv(contentLength) - if request.body.len != contentLength: - await request.respond(Http400, "Bad Request. Content-Length does not match actual.") - return true - elif hasChunkedEncoding(request): - # https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Transfer-Encoding - var sizeOrData = 0 - var bytesToRead = 0 - request.body = "" - while true: - lineFut.mget.setLen(0) - lineFut.clean() - - # The encoding format alternates between specifying a number of bytes to read - # and the data to be read, of the previously specified size - if sizeOrData mod 2 == 0: - # Expect a number of chars to read - await client.recvLineInto(lineFut, maxLength = maxLine) - try: - bytesToRead = lineFut.mget.parseHexInt - except ValueError: - # Malformed request - await request.respond(Http411, ("Invalid chunked transfer encoding - " & - "chunk data size must be hex encoded")) - return true + when (NimMajor, NimMinor) >= (1, 1): + var remainder = contentLength + while remainder > 0: + let readSize = min(remainder, chunkSize) + let data = await client.recv(read_size) + if data.len != read_size: + await request.respond(Http400, "Bad Request. Content-Length does not match actual.") + return true + await request.bodyStream.write(data) + remainder -= data.len + request.bodyStream.complete() else: - if bytesToRead == 0: - # Done reading chunked data - break - - # Read bytesToRead and add to body - let chunk = await client.recv(bytesToRead) - request.body.add(chunk) - # Skip \r\n (chunk terminating bytes per spec) - let separator = await client.recv(2) - if separator != "\r\n": - await request.respond(Http400, "Bad Request. Encoding separator must be \\r\\n") + request.body = await client.recv(contentLength) + if request.body.len != contentLength: + await request.respond(Http400, "Bad Request. Content-Length does not match actual.") return true - - inc sizeOrData elif request.reqMethod == HttpPost: await request.respond(Http411, "Content-Length required.") return true @@ -368,73 +371,43 @@ proc processClient(server: AsyncHttpServer, client: AsyncSocket, address: string let retry = await processRequest( server, request, client, address, lineFut, callback ) - if not retry: - client.close() - break - -const - nimMaxDescriptorsFallback* {.intdefine.} = 16_000 ## fallback value for \ - ## when `maxDescriptors` is not available. - ## This can be set on the command line during compilation - ## via `-d:nimMaxDescriptorsFallback=N` - -proc listen*(server: AsyncHttpServer; port: Port; address = ""; domain = AF_INET) = - ## Listen to the given port and address. - when declared(maxDescriptors): - server.maxFDs = try: maxDescriptors() except: nimMaxDescriptorsFallback - else: - server.maxFDs = nimMaxDescriptorsFallback - server.socket = newAsyncSocket(domain) - if server.reuseAddr: - server.socket.setSockOpt(OptReuseAddr, true) - when not defined(nuttx): - if server.reusePort: - server.socket.setSockOpt(OptReusePort, true) - server.socket.bindAddr(port, address) - server.socket.listen() - -proc shouldAcceptRequest*(server: AsyncHttpServer; - assumedDescriptorsPerRequest = 5): bool {.inline.} = - ## Returns true if the process's current number of opened file - ## descriptors is still within the maximum limit and so it's reasonable to - ## accept yet another request. - result = assumedDescriptorsPerRequest < 0 or - (activeDescriptors() + assumedDescriptorsPerRequest < server.maxFDs) - -proc acceptRequest*(server: AsyncHttpServer, - callback: proc (request: Request): Future[void] {.closure, gcsafe.}) {.async.} = - ## Accepts a single request. Write an explicit loop around this proc so that - ## errors can be handled properly. - var (address, client) = await server.socket.acceptAddr() - asyncCheck processClient(server, client, address, callback) + if not retry: break proc serve*(server: AsyncHttpServer, port: Port, callback: proc (request: Request): Future[void] {.closure, gcsafe.}, - address = ""; - assumedDescriptorsPerRequest = -1; - domain = AF_INET) {.async.} = + address = "") {.async.} = ## Starts the process of listening for incoming HTTP connections on the ## specified address and port. ## ## When a request is made by a client the specified callback will be called. - ## - ## If `assumedDescriptorsPerRequest` is 0 or greater the server cares about - ## the process's maximum file descriptor limit. It then ensures that the - ## process still has the resources for `assumedDescriptorsPerRequest` - ## file descriptors before accepting a connection. - ## - ## You should prefer to call `acceptRequest` instead with a custom server - ## loop so that you're in control over the error handling and logging. - listen server, port, address, domain + server.socket = newAsyncSocket() + if server.reuseAddr: + server.socket.setSockOpt(OptReuseAddr, true) + if server.reusePort: + server.socket.setSockOpt(OptReusePort, true) + server.socket.bindAddr(port, address) + server.socket.listen() + while true: - if shouldAcceptRequest(server, assumedDescriptorsPerRequest): - var (address, client) = await server.socket.acceptAddr() - asyncCheck processClient(server, client, address, callback) - else: - poll() + var (address, client) = await server.socket.acceptAddr() + asyncCheck processClient(server, client, address, callback) #echo(f.isNil) #echo(f.repr) proc close*(server: AsyncHttpServer) = ## Terminates the async http server instance. server.socket.close() + +when not defined(testing) and isMainModule: + proc main = + var server = newAsyncHttpServer() + proc cb(req: Request) {.async.} = + #echo(req.reqMethod, " ", req.url) + #echo(req.headers) + let headers = {"Date": "Tue, 29 Apr 2014 23:40:08 GMT", + "Content-type": "text/plain; charset=utf-8"} + await req.respond(Http200, "Hello World", headers.newHttpHeaders()) + + asyncCheck server.serve(Port(5555), cb) + runForever() + main() diff --git a/lib/pure/asyncmacro.nim b/lib/pure/asyncmacro.nim index d80a47101..11eba427b 100644 --- a/lib/pure/asyncmacro.nim +++ b/lib/pure/asyncmacro.nim @@ -7,63 +7,104 @@ # distribution, for details about the copyright. # -## Implements the `async` and `multisync` macros for `asyncdispatch`. +## `asyncdispatch` module depends on the `asyncmacro` module to work properly. import macros, strutils, asyncfutures -# TODO: Ref https://github.com/nim-lang/Nim/issues/5617 -# TODO: Add more line infos -proc newCallWithLineInfo(fromNode: NimNode; theProc: NimNode, args: varargs[NimNode]): NimNode = - result = newCall(theProc, args) - result.copyLineInfo(fromNode) +proc skipUntilStmtList(node: NimNode): NimNode {.compileTime.} = + # Skips a nest of StmtList's. + result = node + if node[0].kind == nnkStmtList: + result = skipUntilStmtList(node[0]) + +proc skipStmtList(node: NimNode): NimNode {.compileTime.} = + result = node + if node[0].kind == nnkStmtList: + result = node[0] template createCb(retFutureSym, iteratorNameSym, strName, identName, futureVarCompletions: untyped) = bind finished + let retFutUnown = unown retFutureSym + var nameIterVar = iteratorNameSym - proc identName {.closure, stackTrace: off.} = + proc identName {.closure.} = try: if not nameIterVar.finished: - var next = nameIterVar() + var next = unown nameIterVar() # Continue while the yielded future is already finished. while (not next.isNil) and next.finished: - next = nameIterVar() + next = unown nameIterVar() if nameIterVar.finished: break if next == nil: - if not retFutureSym.finished: - let msg = "Async procedure ($1) yielded `nil`, are you await'ing a `nil` Future?" - raise newException(AssertionDefect, msg % strName) + if not retFutUnown.finished: + let msg = "Async procedure ($1) yielded `nil`, are you await'ing a " & + "`nil` Future?" + raise newException(AssertionError, msg % strName) else: {.gcsafe.}: - next.addCallback cast[proc() {.closure, gcsafe.}](identName) + {.push hint[ConvFromXtoItselfNotNeeded]: off.} + next.callback = (proc() {.closure, gcsafe.})(identName) + {.pop.} except: futureVarCompletions - if retFutureSym.finished: + if retFutUnown.finished: # Take a look at tasyncexceptions for the bug which this fixes. # That test explains it better than I can here. raise else: - retFutureSym.fail(getCurrentException()) + retFutUnown.fail(getCurrentException()) identName() -proc createFutureVarCompletions(futureVarIdents: seq[NimNode], fromNode: NimNode): NimNode = +template useVar(result: var NimNode, futureVarNode: NimNode, valueReceiver, + rootReceiver: untyped, fromNode: NimNode) = + ## Params: + ## futureVarNode: The NimNode which is a symbol identifying the Future[T] + ## variable to yield. + ## fromNode: Used for better debug information (to give context). + ## valueReceiver: The node which defines an expression that retrieves the + ## future's value. + ## + ## rootReceiver: ??? TODO + # -> yield future + result.add newNimNode(nnkYieldStmt, fromNode).add(futureVarNode) + # -> future.read + valueReceiver = newDotExpr(futureVarNode, newIdentNode("read")) + result.add rootReceiver + +template createVar(result: var NimNode, futSymName: string, + asyncProc: NimNode, + valueReceiver, rootReceiver: untyped, + fromNode: NimNode) = + result = newNimNode(nnkStmtList, fromNode) + var futSym = genSym(nskVar, "future") + result.add newVarStmt(futSym, asyncProc) # -> var future = y + useVar(result, futSym, valueReceiver, rootReceiver, fromNode) + +proc createFutureVarCompletions(futureVarIdents: seq[NimNode], + fromNode: NimNode): NimNode {.compileTime.} = result = newNimNode(nnkStmtList, fromNode) # Add calls to complete each FutureVar parameter. for ident in futureVarIdents: # Only complete them if they have not been completed already by the user. + # TODO: Once https://github.com/nim-lang/Nim/issues/5617 is fixed. + # TODO: Add line info to the complete() call! # In the meantime, this was really useful for debugging :) #result.add(newCall(newIdentNode("echo"), newStrLitNode(fromNode.lineinfo))) result.add newIfStmt( ( newCall(newIdentNode("not"), newDotExpr(ident, newIdentNode("finished"))), - newCallWithLineInfo(fromNode, newIdentNode("complete"), ident) + newCall(newIdentNode("complete"), ident) ) ) -proc processBody(node, retFutureSym: NimNode, futureVarIdents: seq[NimNode]): NimNode = +proc processBody(node, retFutureSym: NimNode, + subTypeIsVoid: bool, + futureVarIdents: seq[NimNode]): NimNode {.compileTime.} = + #echo(node.treeRepr) result = node case node.kind of nnkReturnStmt: @@ -73,26 +114,75 @@ proc processBody(node, retFutureSym: NimNode, futureVarIdents: seq[NimNode]): Ni result.add createFutureVarCompletions(futureVarIdents, node) if node[0].kind == nnkEmpty: - result.add newCall(newIdentNode("complete"), retFutureSym, newIdentNode("result")) + if not subTypeIsVoid: + result.add newCall(newIdentNode("complete"), retFutureSym, + newIdentNode("result")) + else: + result.add newCall(newIdentNode("complete"), retFutureSym) else: - let x = node[0].processBody(retFutureSym, futureVarIdents) + let x = node[0].processBody(retFutureSym, subTypeIsVoid, + futureVarIdents) if x.kind == nnkYieldStmt: result.add x else: result.add newCall(newIdentNode("complete"), retFutureSym, x) result.add newNimNode(nnkReturnStmt, node).add(newNilLit()) return # Don't process the children of this return stmt + of nnkCommand, nnkCall: + if node[0].eqIdent("await"): + case node[1].kind + of nnkIdent, nnkInfix, nnkDotExpr, nnkCall, nnkCommand: + # await x + # await x or y + # await foo(p, x) + # await foo p, x + var futureValue: NimNode + result.createVar("future" & $node[1][0].toStrLit, node[1], futureValue, + futureValue, node) + else: + error("Invalid node kind in 'await', got: " & $node[1].kind) + elif node.len > 1 and node[1].kind == nnkCommand and + node[1][0].eqIdent("await"): + # foo await x + var newCommand = node + result.createVar("future" & $node[0].toStrLit, node[1][1], newCommand[1], + newCommand, node) + + of nnkVarSection, nnkLetSection: + case node[0][^1].kind + of nnkCommand: + if node[0][^1][0].eqIdent("await"): + # var x = await y + var newVarSection = node # TODO: Should this use copyNimNode? + result.createVar("future" & node[0][0].strVal, node[0][^1][1], + newVarSection[0][^1], newVarSection, node) + else: discard + of nnkAsgn: + case node[1].kind + of nnkCommand: + if node[1][0].eqIdent("await"): + # x = await y + var newAsgn = node + result.createVar("future" & $node[0].toStrLit, node[1][1], newAsgn[1], + newAsgn, node) + else: discard + of nnkDiscardStmt: + # discard await x + if node[0].kind == nnkCommand and + node[0][0].eqIdent("await"): + var newDiscard = node + result.createVar("futureDiscard_" & $toStrLit(node[0][1]), node[0][1], + newDiscard[0], newDiscard, node) of RoutineNodes-{nnkTemplateDef}: # skip all the nested procedure definitions return else: discard for i in 0 ..< result.len: - result[i] = processBody(result[i], retFutureSym, futureVarIdents) + result[i] = processBody(result[i], retFutureSym, subTypeIsVoid, + futureVarIdents) - # echo result.repr - -proc getName(node: NimNode): string = +proc getName(node: NimNode): string {.compileTime.} = case node.kind of nnkPostfix: return node[1].strVal @@ -101,68 +191,30 @@ proc getName(node: NimNode): string = of nnkEmpty: return "anonymous" else: - error("Unknown name.", node) + error("Unknown name.") -proc getFutureVarIdents(params: NimNode): seq[NimNode] = +proc getFutureVarIdents(params: NimNode): seq[NimNode] {.compileTime.} = result = @[] for i in 1 ..< len(params): expectKind(params[i], nnkIdentDefs) if params[i][1].kind == nnkBracketExpr and - params[i][1][0].eqIdent(FutureVar.astToStr): - ## eqIdent: first char is case sensitive!!! + params[i][1][0].eqIdent("futurevar"): result.add(params[i][0]) proc isInvalidReturnType(typeName: string): bool = return typeName notin ["Future"] #, "FutureStream"] -proc verifyReturnType(typeName: string, node: NimNode = nil) = +proc verifyReturnType(typeName: string) {.compileTime.} = if typeName.isInvalidReturnType: error("Expected return type of 'Future' got '$1'" % - typeName, node) + typeName) -template await*(f: typed): untyped {.used.} = - static: - error "await expects Future[T], got " & $typeof(f) - -template await*[T](f: Future[T]): auto {.used.} = - when not defined(nimHasTemplateRedefinitionPragma): - {.pragma: redefine.} - template yieldFuture {.redefine.} = yield FutureBase() - - when compiles(yieldFuture): - var internalTmpFuture: FutureBase = f - yield internalTmpFuture - (cast[typeof(f)](internalTmpFuture)).read() - else: - macro errorAsync(futureError: Future[T]) = - error( - "Can only 'await' inside a proc marked as 'async'. Use " & - "'waitFor' when calling an 'async' proc in a non-async scope instead", - futureError) - errorAsync(f) - -proc asyncSingleProc(prc: NimNode): NimNode = +proc asyncSingleProc(prc: NimNode): NimNode {.compileTime.} = ## This macro transforms a single procedure into a closure iterator. - ## The `async` macro supports a stmtList holding multiple async procedures. - if prc.kind == nnkProcTy: - result = prc - if prc[0][0].kind == nnkEmpty: - result[0][0] = quote do: Future[void] - return result - - if prc.kind in RoutineNodes and prc.name.kind != nnkEmpty: - # Only non anonymous functions need/can have stack trace disabled - prc.addPragma(nnkExprColonExpr.newTree(ident"stackTrace", ident"off")) - + ## The ``async`` macro supports a stmtList holding multiple async procedures. if prc.kind notin {nnkProcDef, nnkLambda, nnkMethodDef, nnkDo}: error("Cannot transform this node kind into an async proc." & - " proc/method definition or lambda node expected.", prc) - - if prc[4].kind != nnkEmpty: - for prag in prc[4]: - if prag.eqIdent("discardable"): - error("Cannot make async proc discardable. Futures have to be " & - "checked with `asyncCheck` instead of discarded", prag) + " proc/method definition or lambda node expected.") let prcName = prc.name.getName @@ -174,24 +226,29 @@ proc asyncSingleProc(prc: NimNode): NimNode = # Verify that the return type is a Future[T] if returnType.kind == nnkBracketExpr: let fut = repr(returnType[0]) - verifyReturnType(fut, returnType[0]) + verifyReturnType(fut) baseType = returnType[1] elif returnType.kind in nnkCallKinds and returnType[0].eqIdent("[]"): let fut = repr(returnType[1]) - verifyReturnType(fut, returnType[0]) + verifyReturnType(fut) baseType = returnType[2] elif returnType.kind == nnkEmpty: baseType = returnType else: - verifyReturnType(repr(returnType), returnType) + verifyReturnType(repr(returnType)) + + let subtypeIsVoid = returnType.kind == nnkEmpty or + (baseType.kind == nnkIdent and returnType[1].eqIdent("void")) let futureVarIdents = getFutureVarIdents(prc.params) + var outerProcBody = newNimNode(nnkStmtList, prc.body) # Extract the documentation comment from the original procedure declaration. # Note that we're not removing it from the body in order not to make this # transformation even more complex. - let body2 = extractDocCommentsAndRunnables(prc.body) + if prc.body.len > 1 and prc.body[0].kind == nnkCommentStmt: + outerProcBody.add(prc.body[0]) # -> var retFuture = newFuture[T]() var retFutureSym = genSym(nskVar, "retFuture") @@ -212,40 +269,40 @@ proc asyncSingleProc(prc: NimNode): NimNode = # -> {.pop.} # -> # -> complete(retFuture, result) - var iteratorNameSym = genSym(nskIterator, $prcName & " (Async)") - var procBody = prc.body.processBody(retFutureSym, futureVarIdents) + var iteratorNameSym = genSym(nskIterator, $prcName & "Iter") + var procBody = prc.body.processBody(retFutureSym, subtypeIsVoid, + futureVarIdents) # don't do anything with forward bodies (empty) if procBody.kind != nnkEmpty: - # fix #13899, defer should not escape its original scope - let blockStmt = newStmtList(newTree(nnkBlockStmt, newEmptyNode(), procBody)) - procBody = newStmtList() - let resultIdent = ident"result" - procBody.add quote do: - template nimAsyncDispatchSetResult(x: `subRetType`) {.used.} = - # If the proc has implicit return then this will get called - `resultIdent` = x - template nimAsyncDispatchSetResult(x: untyped) {.used.} = - # If the proc doesn't have implicit return then this will get called - x - procBody.add newCall(ident"nimAsyncDispatchSetResult", blockStmt) procBody.add(createFutureVarCompletions(futureVarIdents, nil)) - procBody.insert(0): quote do: - {.push warning[resultshadowed]: off.} - when `subRetType` isnot void: - var `resultIdent`: `subRetType` - else: - var `resultIdent`: Future[void] - {.pop.} - procBody.add quote do: - complete(`retFutureSym`, `resultIdent`) - var closureIterator = newProc(iteratorNameSym, [quote do: owned(FutureBase)], + if not subtypeIsVoid: + procBody.insert(0, newNimNode(nnkPragma).add(newIdentNode("push"), + newNimNode(nnkExprColonExpr).add(newNimNode(nnkBracketExpr).add( + newIdentNode("warning"), newIdentNode("resultshadowed")), + newIdentNode("off")))) # -> {.push warning[resultshadowed]: off.} + + procBody.insert(1, newNimNode(nnkVarSection, prc.body).add( + newIdentDefs(newIdentNode("result"), baseType))) # -> var result: T + + procBody.insert(2, newNimNode(nnkPragma).add( + newIdentNode("pop"))) # -> {.pop.}) + + procBody.add( + newCall(newIdentNode("complete"), + retFutureSym, newIdentNode("result"))) # -> complete(retFuture, result) + else: + # -> complete(retFuture) + procBody.add(newCall(newIdentNode("complete"), retFutureSym)) + + var closureIterator = newProc(iteratorNameSym, [parseExpr("owned(FutureBase)")], procBody, nnkIteratorDef) closureIterator.pragma = newNimNode(nnkPragma, lineInfoFrom = prc.body) closureIterator.addPragma(newIdentNode("closure")) # If proc has an explicit gcsafe pragma, we add it to iterator as well. - if prc.pragma.findChild(it.kind in {nnkSym, nnkIdent} and $it == "gcsafe") != nil: + if prc.pragma.findChild(it.kind in {nnkSym, nnkIdent} and $it == + "gcsafe") != nil: closureIterator.addPragma(newIdentNode("gcsafe")) outerProcBody.add(closureIterator) @@ -254,26 +311,26 @@ proc asyncSingleProc(prc: NimNode): NimNode = # friendlier stack traces: var cbName = genSym(nskProc, prcName & NimAsyncContinueSuffix) var procCb = getAst createCb(retFutureSym, iteratorNameSym, - newStrLitNode(prcName), - cbName, - createFutureVarCompletions(futureVarIdents, nil) - ) + newStrLitNode(prcName), + cbName, + createFutureVarCompletions(futureVarIdents, nil)) outerProcBody.add procCb # -> return retFuture outerProcBody.add newNimNode(nnkReturnStmt, prc.body[^1]).add(retFutureSym) result = prc - # Add discardable pragma. - if returnType.kind == nnkEmpty: - # xxx consider removing `owned`? it's inconsistent with non-void case - result.params[0] = quote do: owned(Future[void]) - # based on the yglukhov's patch to chronos: https://github.com/status-im/nim-chronos/pull/47 + if subtypeIsVoid: + # Add discardable pragma. + if returnType.kind == nnkEmpty: + # Add Future[void] + result.params[0] = parseExpr("owned(Future[void])") if procBody.kind != nnkEmpty: - body2.add quote do: - `outerProcBody` - result.body = body2 + result.body = outerProcBody + #echo(treeRepr(result)) + #if prcName == "recvLineInto": + # echo(toStrLit(result)) macro async*(prc: untyped): untyped = ## Macro which processes async procedures into the appropriate @@ -287,11 +344,55 @@ macro async*(prc: untyped): untyped = when defined(nimDumpAsync): echo repr result + +# Multisync +proc emptyNoop[T](x: T): T = + # The ``await``s are replaced by a call to this for simplicity. + when T isnot void: + return x + +proc stripAwait(node: NimNode): NimNode = + ## Strips out all ``await`` commands from a procedure body, replaces them + ## with ``emptyNoop`` for simplicity. + result = node + + let emptyNoopSym = bindSym("emptyNoop") + + case node.kind + of nnkCommand, nnkCall: + if node[0].eqIdent("await"): + node[0] = emptyNoopSym + elif node.len > 1 and node[1].kind == nnkCommand and node[1][0].eqIdent("await"): + # foo await x + node[1][0] = emptyNoopSym + of nnkVarSection, nnkLetSection: + case node[0][^1].kind + of nnkCommand: + if node[0][^1][0].eqIdent("await"): + # var x = await y + node[0][^1][0] = emptyNoopSym + else: discard + of nnkAsgn: + case node[1].kind + of nnkCommand: + if node[1][0].eqIdent("await"): + # x = await y + node[1][0] = emptyNoopSym + else: discard + of nnkDiscardStmt: + # discard await x + if node[0].kind == nnkCommand and node[0][0].eqIdent("await"): + node[0][0] = emptyNoopSym + else: discard + + for i in 0 ..< result.len: + result[i] = stripAwait(result[i]) + proc splitParamType(paramType: NimNode, async: bool): NimNode = result = paramType if paramType.kind == nnkInfix and paramType[0].strVal in ["|", "or"]: - let firstAsync = "async" in paramType[1].toStrLit().strVal.normalize - let secondAsync = "async" in paramType[2].toStrLit().strVal.normalize + let firstAsync = "async" in paramType[1].strVal.normalize + let secondAsync = "async" in paramType[2].strVal.normalize if firstAsync: result = paramType[if async: 1 else: 2] @@ -303,14 +404,14 @@ proc stripReturnType(returnType: NimNode): NimNode = result = returnType if returnType.kind == nnkBracketExpr: let fut = repr(returnType[0]) - verifyReturnType(fut, returnType) + verifyReturnType(fut) result = returnType[1] proc splitProc(prc: NimNode): (NimNode, NimNode) = ## Takes a procedure definition which takes a generic union of arguments, ## for example: proc (socket: Socket | AsyncSocket). - ## It transforms them so that `proc (socket: Socket)` and - ## `proc (socket: AsyncSocket)` are returned. + ## It transforms them so that ``proc (socket: Socket)`` and + ## ``proc (socket: AsyncSocket)`` are returned. result[0] = prc.copyNimTree() # Retrieve the `T` inside `Future[T]`. @@ -319,12 +420,8 @@ proc splitProc(prc: NimNode): (NimNode, NimNode) = for i in 1 ..< result[0][3].len: # Sync proc (0) -> FormalParams (3) -> IdentDefs, the parameter (i) -> # parameter type (1). - result[0][3][i][1] = splitParamType(result[0][3][i][1], async=false) - var multisyncAwait = quote: - template await(value: typed): untyped = - value - - result[0][^1] = nnkStmtList.newTree(multisyncAwait, result[0][^1]) + result[0][3][i][1] = splitParamType(result[0][3][i][1], async = false) + result[0][6] = stripAwait(result[0][6]) result[1] = prc.copyNimTree() if result[1][3][0].kind == nnkBracketExpr: @@ -338,9 +435,14 @@ macro multisync*(prc: untyped): untyped = ## Macro which processes async procedures into both asynchronous and ## synchronous procedures. ## - ## The generated async procedures use the `async` macro, whereas the - ## generated synchronous procedures simply strip off the `await` calls. + ## The generated async procedures use the ``async`` macro, whereas the + ## generated synchronous procedures simply strip off the ``await`` calls. let (sync, asyncPrc) = splitProc(prc) result = newStmtList() result.add(asyncSingleProc(asyncPrc)) result.add(sync) + +proc await*[T](x: T) = + ## The 'await' keyword is also defined here for technical + ## reasons. (Generic symbol lookup prepass.) + {.error: "Await only available within .async".} diff --git a/lib/pure/asyncnet.nim b/lib/pure/asyncnet.nim index d35dbdfaf..88852fb84 100644 --- a/lib/pure/asyncnet.nim +++ b/lib/pure/asyncnet.nim @@ -8,27 +8,27 @@ # ## This module implements a high-level asynchronous sockets API based on the -## asynchronous dispatcher defined in the `asyncdispatch` module. +## asynchronous dispatcher defined in the ``asyncdispatch`` module. ## ## Asynchronous IO in Nim ## ====================== ## ## Async IO in Nim consists of multiple layers (from highest to lowest): ## -## * `asyncnet` module +## * ``asyncnet`` module ## ## * Async await ## -## * `asyncdispatch` module (event loop) +## * ``asyncdispatch`` module (event loop) ## -## * `selectors` module +## * ``selectors`` module ## ## Each builds on top of the layers below it. The selectors module is an -## abstraction for the various system `select()` mechanisms such as epoll or +## abstraction for the various system ``select()`` mechanisms such as epoll or ## kqueue. If you wish you can use it directly, and some people have done so ## `successfully `_. ## But you must be aware that on Windows it only supports -## `select()`. +## ``select()``. ## ## The async dispatcher implements the proactor pattern and also has an ## implementation of IOCP. It implements the proactor pattern for other @@ -45,16 +45,16 @@ ## layers interchangeably (as long as you only care about non-Windows ## platforms). ## -## For most applications using `asyncnet` is the way to go as it builds +## For most applications using ``asyncnet`` is the way to go as it builds ## over all the layers, providing some extra features such as buffering. ## ## SSL ## === ## -## SSL can be enabled by compiling with the `-d:ssl` flag. +## SSL can be enabled by compiling with the ``-d:ssl`` flag. ## -## You must create a new SSL context with the `newContext` function defined -## in the `net` module. You may then call `wrapSocket` on your socket using +## You must create a new SSL context with the ``newContext`` function defined +## in the ``net`` module. You may then call ``wrapSocket`` on your socket using ## the newly created SSL context to get an SSL socket. ## ## Examples @@ -65,8 +65,9 @@ ## ## The following example demonstrates a simple chat server. ## -## ```Nim -## import std/[asyncnet, asyncdispatch] +## .. code-block::nim +## +## import asyncnet, asyncdispatch ## ## var clients {.threadvar.}: seq[AsyncSocket] ## @@ -92,22 +93,18 @@ ## ## asyncCheck serve() ## runForever() -## ``` +## -import std/private/since - -when defined(nimPreviewSlimSystem): - import std/[assertions, syncio] - -import asyncdispatch, nativesockets, net, os +import asyncdispatch +import nativesockets +import net +import os export SOBool # TODO: Remove duplication introduced by PR #4683. const defineSsl = defined(ssl) or defined(nimdoc) -const useNimNetLite = defined(nimNetLite) or defined(freertos) or defined(zephyr) or - defined(nuttx) when defineSsl: import openssl @@ -128,33 +125,25 @@ type sslContext: SslContext bioIn: BIO bioOut: BIO - sslNoShutdown: bool domain: Domain sockType: SockType protocol: Protocol AsyncSocket* = ref AsyncSocketDesc proc newAsyncSocket*(fd: AsyncFD, domain: Domain = AF_INET, - sockType: SockType = SOCK_STREAM, - protocol: Protocol = IPPROTO_TCP, - buffered = true, - inheritable = defined(nimInheritHandles)): owned(AsyncSocket) = - ## Creates a new `AsyncSocket` based on the supplied params. + sockType: SockType = SOCK_STREAM, + protocol: Protocol = IPPROTO_TCP, buffered = true): owned(AsyncSocket) = + ## Creates a new ``AsyncSocket`` based on the supplied params. ## - ## The supplied `fd`'s non-blocking state will be enabled implicitly. + ## The supplied ``fd``'s non-blocking state will be enabled implicitly. ## - ## If `inheritable` is false (the default), the supplied `fd` will not - ## be inheritable by child processes. - ## - ## **Note**: This procedure will **NOT** register `fd` with the global + ## **Note**: This procedure will **NOT** register ``fd`` with the global ## async dispatcher. You need to do this manually. If you have used - ## `newAsyncNativeSocket` to create `fd` then it's already registered. + ## ``newAsyncNativeSocket`` to create ``fd`` then it's already registered. assert fd != osInvalidSocket.AsyncFD new(result) result.fd = fd.SocketHandle fd.SocketHandle.setBlocking(false) - if not fd.SocketHandle.setInheritable(inheritable): - raiseOSError(osLastError()) result.isBuffered = buffered result.domain = domain result.sockType = sockType @@ -163,19 +152,15 @@ proc newAsyncSocket*(fd: AsyncFD, domain: Domain = AF_INET, result.currPos = 0 proc newAsyncSocket*(domain: Domain = AF_INET, sockType: SockType = SOCK_STREAM, - protocol: Protocol = IPPROTO_TCP, buffered = true, - inheritable = defined(nimInheritHandles)): owned(AsyncSocket) = + protocol: Protocol = IPPROTO_TCP, buffered = true): owned(AsyncSocket) = ## Creates a new asynchronous socket. ## ## This procedure will also create a brand new file descriptor for ## this socket. - ## - ## If `inheritable` is false (the default), the new file descriptor will not - ## be inheritable by child processes. - let fd = createAsyncNativeSocket(domain, sockType, protocol, inheritable) + let fd = createAsyncNativeSocket(domain, sockType, protocol) if fd.SocketHandle == osInvalidSocket: raiseOSError(osLastError()) - result = newAsyncSocket(fd, domain, sockType, protocol, buffered, inheritable) + result = newAsyncSocket(fd, domain, sockType, protocol, buffered) proc getLocalAddr*(socket: AsyncSocket): (string, Port) = ## Get the socket's local address and port number. @@ -183,34 +168,28 @@ proc getLocalAddr*(socket: AsyncSocket): (string, Port) = ## This is high-level interface for `getsockname`:idx:. getLocalAddr(socket.fd, socket.domain) -when not useNimNetLite: - proc getPeerAddr*(socket: AsyncSocket): (string, Port) = - ## Get the socket's peer address and port number. - ## - ## This is high-level interface for `getpeername`:idx:. - getPeerAddr(socket.fd, socket.domain) +proc getPeerAddr*(socket: AsyncSocket): (string, Port) = + ## Get the socket's peer address and port number. + ## + ## This is high-level interface for `getpeername`:idx:. + getPeerAddr(socket.fd, socket.domain) proc newAsyncSocket*(domain, sockType, protocol: cint, - buffered = true, - inheritable = defined(nimInheritHandles)): owned(AsyncSocket) = + buffered = true): owned(AsyncSocket) = ## Creates a new asynchronous socket. ## ## This procedure will also create a brand new file descriptor for ## this socket. - ## - ## If `inheritable` is false (the default), the new file descriptor will not - ## be inheritable by child processes. - let fd = createAsyncNativeSocket(domain, sockType, protocol, inheritable) + let fd = createAsyncNativeSocket(domain, sockType, protocol) if fd.SocketHandle == osInvalidSocket: raiseOSError(osLastError()) result = newAsyncSocket(fd, Domain(domain), SockType(sockType), - Protocol(protocol), buffered, inheritable) + Protocol(protocol), buffered) when defineSsl: - proc getSslError(socket: AsyncSocket, err: cint): cint = - assert socket.isSsl + proc getSslError(handle: SslPtr, err: cint): cint = assert err < 0 - var ret = SSL_get_error(socket.sslHandle, err.cint) + var ret = SSL_get_error(handle, err.cint) case ret of SSL_ERROR_ZERO_RETURN: raiseSSLError("TLS/SSL connection failed to initiate, socket closed prematurely.") @@ -221,7 +200,6 @@ when defineSsl: of SSL_ERROR_WANT_X509_LOOKUP: raiseSSLError("Function for x509 lookup has been called.") of SSL_ERROR_SYSCALL, SSL_ERROR_SSL: - socket.sslNoShutdown = true raiseSSLError() else: raiseSSLError("Unknown Error") @@ -230,7 +208,7 @@ when defineSsl: let len = bioCtrlPending(socket.bioOut) if len > 0: var data = newString(len) - let read = bioRead(socket.bioOut, cast[cstring](addr data[0]), len) + let read = bioRead(socket.bioOut, addr data[0], len) assert read != 0 if read < 0: raiseSSLError() @@ -239,7 +217,7 @@ when defineSsl: proc appeaseSsl(socket: AsyncSocket, flags: set[SocketFlag], sslError: cint): owned(Future[bool]) {.async.} = - ## Returns `true` if `socket` is still connected, otherwise `false`. + ## Returns ``true`` if ``socket`` is still connected, otherwise ``false``. result = true case sslError of SSL_ERROR_WANT_WRITE: @@ -248,7 +226,7 @@ when defineSsl: var data = await recv(socket.fd.AsyncFD, BufferSize, flags) let length = len(data) if length > 0: - let ret = bioWrite(socket.bioIn, cast[cstring](addr data[0]), length.cint) + let ret = bioWrite(socket.bioIn, addr data[0], length.cint) if ret < 0: raiseSSLError() elif length == 0: @@ -262,17 +240,18 @@ when defineSsl: op: untyped) = var opResult {.inject.} = -1.cint while opResult < 0: - ErrClearError() # Call the desired operation. opResult = op + # Bit hackish here. + # TODO: Introduce an async template transformation pragma? # Send any remaining pending SSL data. - await sendPendingSslData(socket, flags) + yield sendPendingSslData(socket, flags) # If the operation failed, try to see if SSL has some data to read # or write. if opResult < 0: - let err = getSslError(socket, opResult.cint) + let err = getSslError(socket.sslHandle, opResult.cint) let fut = appeaseSsl(socket, flags, err.cint) yield fut if not fut.read(): @@ -285,9 +264,9 @@ when defineSsl: proc dial*(address: string, port: Port, protocol = IPPROTO_TCP, buffered = true): owned(Future[AsyncSocket]) {.async.} = - ## Establishes connection to the specified `address`:`port` pair via the + ## Establishes connection to the specified ``address``:``port`` pair via the ## specified protocol. The procedure iterates through possible - ## resolutions of the `address` until it succeeds, meaning that it + ## resolutions of the ``address`` until it succeeds, meaning that it ## seamlessly works with both IPv4 and IPv6. ## Returns AsyncSocket ready to send or receive data. let asyncFd = await asyncdispatch.dial(address, port, protocol) @@ -296,9 +275,9 @@ proc dial*(address: string, port: Port, protocol = IPPROTO_TCP, result = newAsyncSocket(asyncFd, domain, sockType, protocol, buffered) proc connect*(socket: AsyncSocket, address: string, port: Port) {.async.} = - ## Connects `socket` to server at `address:port`. + ## Connects ``socket`` to server at ``address:port``. ## - ## Returns a `Future` which will complete when the connection succeeds + ## Returns a ``Future`` which will complete when the connection succeeds ## or an error occurs. await connect(socket.fd.AsyncFD, address, port, socket.domain) if socket.isSsl: @@ -314,7 +293,7 @@ proc connect*(socket: AsyncSocket, address: string, port: Port) {.async.} = template readInto(buf: pointer, size: int, socket: AsyncSocket, flags: set[SocketFlag]): int = - ## Reads **up to** `size` bytes from `socket` into `buf`. Note that + ## Reads **up to** ``size`` bytes from ``socket`` into ``buf``. Note that ## this is a template and not a proc. assert(not socket.closed, "Cannot `recv` on a closed socket") var res = 0 @@ -325,8 +304,10 @@ template readInto(buf: pointer, size: int, socket: AsyncSocket, sslRead(socket.sslHandle, cast[cstring](buf), size.cint)) res = opResult else: + var recvIntoFut = asyncdispatch.recvInto(socket.fd.AsyncFD, buf, size, flags) + yield recvIntoFut # Not in SSL mode. - res = await asyncdispatch.recvInto(socket.fd.AsyncFD, buf, size, flags) + res = recvIntoFut.read() res template readIntoBuf(socket: AsyncSocket, @@ -338,10 +319,10 @@ template readIntoBuf(socket: AsyncSocket, proc recvInto*(socket: AsyncSocket, buf: pointer, size: int, flags = {SocketFlag.SafeDisconn}): owned(Future[int]) {.async.} = - ## Reads **up to** `size` bytes from `socket` into `buf`. + ## Reads **up to** ``size`` bytes from ``socket`` into ``buf``. ## ## For buffered sockets this function will attempt to read all the requested - ## data. It will read this data in `BufferSize` chunks. + ## data. It will read this data in ``BufferSize`` chunks. ## ## For unbuffered sockets this function makes no effort to read ## all the data requested. It will return as much data as the operating system @@ -352,7 +333,7 @@ proc recvInto*(socket: AsyncSocket, buf: pointer, size: int, ## requested data. ## ## If socket is disconnected and no data is available - ## to be read then the future will complete with a value of `0`. + ## to be read then the future will complete with a value of ``0``. if socket.isBuffered: let originalBufPos = socket.currPos @@ -386,10 +367,10 @@ proc recvInto*(socket: AsyncSocket, buf: pointer, size: int, proc recv*(socket: AsyncSocket, size: int, flags = {SocketFlag.SafeDisconn}): owned(Future[string]) {.async.} = - ## Reads **up to** `size` bytes from `socket`. + ## Reads **up to** ``size`` bytes from ``socket``. ## ## For buffered sockets this function will attempt to read all the requested - ## data. It will read this data in `BufferSize` chunks. + ## data. It will read this data in ``BufferSize`` chunks. ## ## For unbuffered sockets this function makes no effort to read ## all the data requested. It will return as much data as the operating system @@ -400,11 +381,10 @@ proc recv*(socket: AsyncSocket, size: int, ## requested data. ## ## If socket is disconnected and no data is available - ## to be read then the future will complete with a value of `""`. + ## to be read then the future will complete with a value of ``""``. if socket.isBuffered: result = newString(size) - when not defined(nimSeqsV2): - shallow(result) + shallow(result) let originalBufPos = socket.currPos if socket.bufLen == 0: @@ -439,7 +419,7 @@ proc recv*(socket: AsyncSocket, size: int, proc send*(socket: AsyncSocket, buf: pointer, size: int, flags = {SocketFlag.SafeDisconn}) {.async.} = - ## Sends `size` bytes from `buf` to `socket`. The returned future will complete once all + ## Sends ``size`` bytes from ``buf`` to ``socket``. The returned future will complete once all ## data has been sent. assert socket != nil assert(not socket.closed, "Cannot `send` on a closed socket") @@ -453,30 +433,25 @@ proc send*(socket: AsyncSocket, buf: pointer, size: int, proc send*(socket: AsyncSocket, data: string, flags = {SocketFlag.SafeDisconn}) {.async.} = - ## Sends `data` to `socket`. The returned future will complete once all + ## Sends ``data`` to ``socket``. The returned future will complete once all ## data has been sent. assert socket != nil if socket.isSsl: when defineSsl: var copy = data sslLoop(socket, flags, - sslWrite(socket.sslHandle, cast[cstring](addr copy[0]), copy.len.cint)) + sslWrite(socket.sslHandle, addr copy[0], copy.len.cint)) await sendPendingSslData(socket, flags) else: await send(socket.fd.AsyncFD, data, flags) -proc acceptAddr*(socket: AsyncSocket, flags = {SocketFlag.SafeDisconn}, - inheritable = defined(nimInheritHandles)): +proc acceptAddr*(socket: AsyncSocket, flags = {SocketFlag.SafeDisconn}): owned(Future[tuple[address: string, client: AsyncSocket]]) = ## Accepts a new connection. Returns a future containing the client socket ## corresponding to that connection and the remote address of the client. - ## - ## If `inheritable` is false (the default), the resulting client socket will - ## not be inheritable by child processes. - ## ## The future will complete when the connection is successfully accepted. var retFuture = newFuture[tuple[address: string, client: AsyncSocket]]("asyncnet.acceptAddr") - var fut = acceptAddr(socket.fd.AsyncFD, flags, inheritable) + var fut = acceptAddr(socket.fd.AsyncFD, flags) fut.callback = proc (future: Future[tuple[address: string, client: AsyncFD]]) = assert future.finished @@ -485,7 +460,7 @@ proc acceptAddr*(socket: AsyncSocket, flags = {SocketFlag.SafeDisconn}, else: let resultTup = (future.read.address, newAsyncSocket(future.read.client, socket.domain, - socket.sockType, socket.protocol, socket.isBuffered, inheritable)) + socket.sockType, socket.protocol, socket.isBuffered)) retFuture.complete(resultTup) return retFuture @@ -493,8 +468,6 @@ proc accept*(socket: AsyncSocket, flags = {SocketFlag.SafeDisconn}): owned(Future[AsyncSocket]) = ## Accepts a new connection. Returns a future containing the client socket ## corresponding to that connection. - ## If `inheritable` is false (the default), the resulting client socket will - ## not be inheritable by child processes. ## The future will complete when the connection is successfully accepted. var retFut = newFuture[AsyncSocket]("asyncnet.accept") var fut = acceptAddr(socket, flags) @@ -509,24 +482,25 @@ proc accept*(socket: AsyncSocket, proc recvLineInto*(socket: AsyncSocket, resString: FutureVar[string], flags = {SocketFlag.SafeDisconn}, maxLength = MaxLineLength) {.async.} = - ## Reads a line of data from `socket` into `resString`. + ## Reads a line of data from ``socket`` into ``resString``. ## - ## If a full line is read `\r\L` is not - ## added to `line`, however if solely `\r\L` is read then `line` + ## If a full line is read ``\r\L`` is not + ## added to ``line``, however if solely ``\r\L`` is read then ``line`` ## will be set to it. ## - ## If the socket is disconnected, `line` will be set to `""`. + ## If the socket is disconnected, ``line`` will be set to ``""``. ## - ## If the socket is disconnected in the middle of a line (before `\r\L` - ## is read) then line will be set to `""`. + ## If the socket is disconnected in the middle of a line (before ``\r\L`` + ## is read) then line will be set to ``""``. ## The partial line **will be lost**. ## - ## The `maxLength` parameter determines the maximum amount of characters - ## that can be read. `resString` will be truncated after that. + ## The ``maxLength`` parameter determines the maximum amount of characters + ## that can be read. ``resString`` will be truncated after that. ## - ## .. warning:: The `Peek` flag is not yet implemented. + ## **Warning**: The ``Peek`` flag is not yet implemented. ## - ## .. warning:: `recvLineInto` on unbuffered sockets assumes that the protocol uses `\r\L` to delimit a new line. + ## **Warning**: ``recvLineInto`` on unbuffered sockets assumes that the + ## protocol uses ``\r\L`` to delimit a new line. assert SocketFlag.Peek notin flags ## TODO: result = newFuture[void]("asyncnet.recvLineInto") @@ -601,25 +575,26 @@ proc recvLineInto*(socket: AsyncSocket, resString: FutureVar[string], proc recvLine*(socket: AsyncSocket, flags = {SocketFlag.SafeDisconn}, maxLength = MaxLineLength): owned(Future[string]) {.async.} = - ## Reads a line of data from `socket`. Returned future will complete once + ## Reads a line of data from ``socket``. Returned future will complete once ## a full line is read or an error occurs. ## - ## If a full line is read `\r\L` is not - ## added to `line`, however if solely `\r\L` is read then `line` + ## If a full line is read ``\r\L`` is not + ## added to ``line``, however if solely ``\r\L`` is read then ``line`` ## will be set to it. ## - ## If the socket is disconnected, `line` will be set to `""`. + ## If the socket is disconnected, ``line`` will be set to ``""``. ## - ## If the socket is disconnected in the middle of a line (before `\r\L` - ## is read) then line will be set to `""`. + ## If the socket is disconnected in the middle of a line (before ``\r\L`` + ## is read) then line will be set to ``""``. ## The partial line **will be lost**. ## - ## The `maxLength` parameter determines the maximum amount of characters + ## The ``maxLength`` parameter determines the maximum amount of characters ## that can be read. The result is truncated after that. ## - ## .. warning:: The `Peek` flag is not yet implemented. + ## **Warning**: The ``Peek`` flag is not yet implemented. ## - ## .. warning:: `recvLine` on unbuffered sockets assumes that the protocol uses `\r\L` to delimit a new line. + ## **Warning**: ``recvLine`` on unbuffered sockets assumes that the protocol + ## uses ``\r\L`` to delimit a new line. assert SocketFlag.Peek notin flags ## TODO: # TODO: Optimise this @@ -630,8 +605,8 @@ proc recvLine*(socket: AsyncSocket, proc listen*(socket: AsyncSocket, backlog = SOMAXCONN) {.tags: [ ReadIOEffect].} = - ## Marks `socket` as accepting connections. - ## `Backlog` specifies the maximum length of the + ## Marks ``socket`` as accepting connections. + ## ``Backlog`` specifies the maximum length of the ## queue of pending connections. ## ## Raises an OSError error upon failure. @@ -639,9 +614,9 @@ proc listen*(socket: AsyncSocket, backlog = SOMAXCONN) {.tags: [ proc bindAddr*(socket: AsyncSocket, port = Port(0), address = "") {. tags: [ReadIOEffect].} = - ## Binds `address`:`port` to the socket. + ## Binds ``address``:``port`` to the socket. ## - ## If `address` is "" then ADDR_ANY will be bound. + ## If ``address`` is "" then ADDR_ANY will be bound. var realaddr = address if realaddr == "": case socket.domain @@ -653,16 +628,11 @@ proc bindAddr*(socket: AsyncSocket, port = Port(0), address = "") {. var aiList = getAddrInfo(realaddr, port, socket.domain) if bindAddr(socket.fd, aiList.ai_addr, aiList.ai_addrlen.SockLen) < 0'i32: - freeAddrInfo(aiList) + freeaddrinfo(aiList) raiseOSError(osLastError()) - freeAddrInfo(aiList) + freeaddrinfo(aiList) -proc hasDataBuffered*(s: AsyncSocket): bool {.since: (1, 5).} = - ## Determines whether an AsyncSocket has data buffered. - # xxx dedup with std/net - s.isBuffered and s.bufLen > 0 and s.currPos != s.bufLen - -when defined(posix) and not useNimNetLite: +when defined(posix): proc connectUnix*(socket: AsyncSocket, path: string): owned(Future[void]) = ## Binds Unix socket to `path`. @@ -719,38 +689,22 @@ elif defined(nimdoc): proc close*(socket: AsyncSocket) = ## Closes the socket. - if socket.closed: return - defer: socket.fd.AsyncFD.closeSocket() - socket.closed = true # TODO: Add extra debugging checks for this. - when defineSsl: if socket.isSsl: - let res = - # Don't call SSL_shutdown if the connection has not been fully - # established, see: - # https://github.com/openssl/openssl/issues/710#issuecomment-253897666 - if not socket.sslNoShutdown and SSL_in_init(socket.sslHandle) == 0: - ErrClearError() - SSL_shutdown(socket.sslHandle) - else: - 0 + let res = SSL_shutdown(socket.sslHandle) SSL_free(socket.sslHandle) if res == 0: discard elif res != 1: raiseSSLError() + socket.closed = true # TODO: Add extra debugging checks for this. when defineSsl: - proc sslHandle*(self: AsyncSocket): SslPtr = - ## Retrieve the ssl pointer of `socket`. - ## Useful for interfacing with `openssl`. - self.sslHandle - proc wrapSocket*(ctx: SslContext, socket: AsyncSocket) = ## Wraps a socket in an SSL context. This function effectively turns - ## `socket` into an SSL socket. + ## ``socket`` into an SSL socket. ## ## **Disclaimer**: This code is not well tested, may be very unsafe and ## prone to security vulnerabilities. @@ -764,14 +718,12 @@ when defineSsl: socket.bioOut = bioNew(bioSMem()) sslSetBio(socket.sslHandle, socket.bioIn, socket.bioOut) - socket.sslNoShutdown = true - proc wrapConnectedSocket*(ctx: SslContext, socket: AsyncSocket, handshake: SslHandshakeType, hostname: string = "") = ## Wraps a connected socket in an SSL context. This function effectively - ## turns `socket` into an SSL socket. - ## `hostname` should be specified so that the client knows which hostname + ## turns ``socket`` into an SSL socket. + ## ``hostname`` should be specified so that the client knows which hostname ## the server certificate should be validated against. ## ## This should be called on a connected socket, and will perform @@ -791,31 +743,20 @@ when defineSsl: of handshakeAsServer: sslSetAcceptState(socket.sslHandle) - proc getPeerCertificates*(socket: AsyncSocket): seq[Certificate] {.since: (1, 1).} = - ## Returns the certificate chain received by the peer we are connected to - ## through the given socket. - ## The handshake must have been completed and the certificate chain must - ## have been verified successfully or else an empty sequence is returned. - ## The chain is ordered from leaf certificate to root certificate. - if not socket.isSsl: - result = newSeq[Certificate]() - else: - result = getPeerCertificates(socket.sslHandle) - proc getSockOpt*(socket: AsyncSocket, opt: SOBool, level = SOL_SOCKET): bool {. tags: [ReadIOEffect].} = - ## Retrieves option `opt` as a boolean value. + ## Retrieves option ``opt`` as a boolean value. var res = getSockOptInt(socket.fd, cint(level), toCInt(opt)) result = res != 0 proc setSockOpt*(socket: AsyncSocket, opt: SOBool, value: bool, level = SOL_SOCKET) {.tags: [WriteIOEffect].} = - ## Sets option `opt` to a boolean value specified by `value`. + ## Sets option ``opt`` to a boolean value specified by ``value``. var valuei = cint(if value: 1 else: 0) setSockOptInt(socket.fd, cint(level), toCInt(opt), valuei) proc isSsl*(socket: AsyncSocket): bool = - ## Determines whether `socket` is a SSL socket. + ## Determines whether ``socket`` is a SSL socket. socket.isSsl proc getFd*(socket: AsyncSocket): SocketHandle = @@ -826,130 +767,6 @@ proc isClosed*(socket: AsyncSocket): bool = ## Determines whether the socket has been closed. return socket.closed -proc sendTo*(socket: AsyncSocket, address: string, port: Port, data: string, - flags = {SocketFlag.SafeDisconn}): owned(Future[void]) - {.async, since: (1, 3).} = - ## This proc sends `data` to the specified `address`, which may be an IP - ## address or a hostname. If a hostname is specified this function will try - ## each IP of that hostname. The returned future will complete once all data - ## has been sent. - ## - ## If an error occurs an OSError exception will be raised. - ## - ## This proc is normally used with connectionless sockets (UDP sockets). - assert(socket.protocol != IPPROTO_TCP, - "Cannot `sendTo` on a TCP socket. Use `send` instead") - assert(not socket.closed, "Cannot `sendTo` on a closed socket") - - let aiList = getAddrInfo(address, port, socket.domain, socket.sockType, - socket.protocol) - - var - it = aiList - success = false - lastException: ref Exception - - while it != nil: - let fut = sendTo(socket.fd.AsyncFD, cstring(data), len(data), it.ai_addr, - it.ai_addrlen.SockLen, flags) - - yield fut - - if not fut.failed: - success = true - - break - - lastException = fut.readError() - - it = it.ai_next - - freeAddrInfo(aiList) - - if not success: - if lastException != nil: - raise lastException - else: - raise newException(IOError, "Couldn't resolve address: " & address) - -proc recvFrom*(socket: AsyncSocket, data: FutureVar[string], size: int, - address: FutureVar[string], port: FutureVar[Port], - flags = {SocketFlag.SafeDisconn}): owned(Future[int]) - {.async, since: (1, 3).} = - ## Receives a datagram data from `socket` into `data`, which must be at - ## least of size `size`. The address and port of datagram's sender will be - ## stored into `address` and `port`, respectively. Returned future will - ## complete once one datagram has been received, and will return size of - ## packet received. - ## - ## If an error occurs an OSError exception will be raised. - ## - ## This proc is normally used with connectionless sockets (UDP sockets). - ## - ## **Notes** - ## * `data` must be initialized to the length of `size`. - ## * `address` must be initialized to 46 in length. - template adaptRecvFromToDomain(domain: Domain) = - var lAddr = sizeof(sAddr).SockLen - - result = await recvFromInto(AsyncFD(getFd(socket)), cstring(data.mget()), size, - cast[ptr SockAddr](addr sAddr), addr lAddr, - flags) - - data.mget().setLen(result) - data.complete() - - getAddrString(cast[ptr SockAddr](addr sAddr), address.mget()) - - address.complete() - - when domain == AF_INET6: - port.complete(ntohs(sAddr.sin6_port).Port) - else: - port.complete(ntohs(sAddr.sin_port).Port) - - assert(socket.protocol != IPPROTO_TCP, - "Cannot `recvFrom` on a TCP socket. Use `recv` or `recvInto` instead") - assert(not socket.closed, "Cannot `recvFrom` on a closed socket") - assert(size == len(data.mget()), - "`date` was not initialized correctly. `size` != `len(data.mget())`") - assert(46 == len(address.mget()), - "`address` was not initialized correctly. 46 != `len(address.mget())`") - - case socket.domain - of AF_INET6: - var sAddr: Sockaddr_in6 - adaptRecvFromToDomain(AF_INET6) - of AF_INET: - var sAddr: Sockaddr_in - adaptRecvFromToDomain(AF_INET) - else: - raise newException(ValueError, "Unknown socket address family") - -proc recvFrom*(socket: AsyncSocket, size: int, - flags = {SocketFlag.SafeDisconn}): - owned(Future[tuple[data: string, address: string, port: Port]]) - {.async, since: (1, 3).} = - ## Receives a datagram data from `socket`, which must be at least of size - ## `size`. Returned future will complete once one datagram has been received - ## and will return tuple with: data of packet received; and address and port - ## of datagram's sender. - ## - ## If an error occurs an OSError exception will be raised. - ## - ## This proc is normally used with connectionless sockets (UDP sockets). - var - data = newFutureVar[string]() - address = newFutureVar[string]() - port = newFutureVar[Port]() - - data.mget().setLen(size) - address.mget().setLen(46) - - let read = await recvFrom(socket, data, size, address, port, flags) - - result = (data.mget(), address.mget(), port.mget()) - when not defined(testing) and isMainModule: type TestCases = enum diff --git a/lib/pure/asyncstreams.nim b/lib/pure/asyncstreams.nim index 3f7774ed8..44e73003e 100644 --- a/lib/pure/asyncstreams.nim +++ b/lib/pure/asyncstreams.nim @@ -11,9 +11,6 @@ import asyncfutures -when defined(nimPreviewSlimSystem): - import std/assertions - import deques type @@ -24,17 +21,16 @@ type queue: Deque[T] finished: bool cb: proc () {.closure, gcsafe.} - error*: ref Exception proc newFutureStream*[T](fromProc = "unspecified"): FutureStream[T] = - ## Create a new `FutureStream`. This future's callback is activated when + ## Create a new ``FutureStream``. This future's callback is activated when ## two events occur: ## ## * New data is written into the future stream. ## * The future stream is completed (this means that no more data will be ## written). ## - ## Specifying `fromProc`, which is a string specifying the name of the proc + ## Specifying ``fromProc``, which is a string specifying the name of the proc ## that this future belongs to, is a good habit as it helps with debugging. ## ## **Note:** The API of FutureStream is still new and so has a higher @@ -43,49 +39,35 @@ proc newFutureStream*[T](fromProc = "unspecified"): FutureStream[T] = result.queue = initDeque[T]() proc complete*[T](future: FutureStream[T]) = - ## Completes a `FutureStream` signalling the end of data. - assert(future.error == nil, "Trying to complete failed stream") + ## Completes a ``FutureStream`` signalling the end of data. future.finished = true if not future.cb.isNil: future.cb() -proc fail*[T](future: FutureStream[T], error: ref Exception) = - ## Completes `future` with `error`. - assert(not future.finished) - future.finished = true - future.error = error - if not future.cb.isNil: - future.cb() - proc `callback=`*[T](future: FutureStream[T], cb: proc (future: FutureStream[T]) {.closure, gcsafe.}) = ## Sets the callback proc to be called when data was placed inside the ## future stream. ## ## The callback is also called when the future is completed. So you should - ## use `finished` to check whether data is available. + ## use ``finished`` to check whether data is available. ## - ## If the future stream already has data or is finished then `cb` will be + ## If the future stream already has data or is finished then ``cb`` will be ## called immediately. - proc named() = cb(future) - future.cb = named + future.cb = proc () = cb(future) if future.queue.len > 0 or future.finished: callSoon(future.cb) proc finished*[T](future: FutureStream[T]): bool = - ## Check if a `FutureStream` is finished. `true` value means that + ## Check if a ``FutureStream`` is finished. ``true`` value means that ## no more data will be placed inside the stream *and* that there is ## no data waiting to be retrieved. result = future.finished and future.queue.len == 0 -proc failed*[T](future: FutureStream[T]): bool = - ## Determines whether `future` completed with an error. - return future.error != nil - proc write*[T](future: FutureStream[T], value: T): Future[void] = ## Writes the specified value inside the specified future stream. ## - ## This will raise `ValueError` if `future` is finished. + ## This will raise ``ValueError`` if ``future`` is finished. result = newFuture[void]("FutureStream.put") if future.finished: let msg = "FutureStream is finished and so no longer accepts new data." @@ -98,43 +80,37 @@ proc write*[T](future: FutureStream[T], value: T): Future[void] = result.complete() proc read*[T](future: FutureStream[T]): owned(Future[(bool, T)]) = - ## Returns a future that will complete when the `FutureStream` has data + ## Returns a future that will complete when the ``FutureStream`` has data ## placed into it. The future will be completed with the oldest ## value stored inside the stream. The return value will also determine - ## whether data was retrieved, `false` means that the future stream was + ## whether data was retrieved, ``false`` means that the future stream was ## completed and no data was retrieved. ## ## This function will remove the data that was returned from the underlying - ## `FutureStream`. + ## ``FutureStream``. var resFut = newFuture[(bool, T)]("FutureStream.take") let savedCb = future.cb - proc newCb(fs: FutureStream[T]) = - # Exit early if `resFut` is already complete. (See #8994). - if resFut.finished: return + var newCb = + proc (fs: FutureStream[T]) = + # Exit early if `resFut` is already complete. (See #8994). + if resFut.finished: return - # We don't want this callback called again. - #future.cb = nil + # We don't want this callback called again. + future.cb = nil - # The return value depends on whether the FutureStream has finished. - var res: (bool, T) - if finished(fs): - # Remember, this callback is called when the FutureStream is completed. - res[0] = false - else: - res[0] = true - res[1] = fs.queue.popFirst() + # The return value depends on whether the FutureStream has finished. + var res: (bool, T) + if finished(fs): + # Remember, this callback is called when the FutureStream is completed. + res[0] = false + else: + res[0] = true + res[1] = fs.queue.popFirst() - if fs.failed: - resFut.fail(fs.error) - else: resFut.complete(res) - # If the saved callback isn't nil then let's call it. - if not savedCb.isNil: - if fs.queue.len > 0: - savedCb() - else: - future.cb = savedCb + # If the saved callback isn't nil then let's call it. + if not savedCb.isNil: savedCb() if future.queue.len > 0 or future.finished: newCb(future) diff --git a/lib/pure/base64.nim b/lib/pure/base64.nim index 795820433..067f21c5f 100644 --- a/lib/pure/base64.nim +++ b/lib/pure/base64.nim @@ -16,81 +16,59 @@ ## Each Base64 digit represents exactly 6 bits of data. Three 8-bit ## bytes (i.e., a total of 24 bits) can therefore be represented by ## four 6-bit Base64 digits. - -##[ -# Basic usage +## +## Basic usage +## =========== +## ## Encoding data -]## - -runnableExamples: - let encoded = encode("Hello World") - assert encoded == "SGVsbG8gV29ybGQ=" - +## ------------- +## +## .. code-block::nim +## import base64 +## let encoded = encode("Hello World") +## assert encoded == "SGVsbG8gV29ybGQ=" ## ## Apart from strings you can also encode lists of integers or characters: ## - -runnableExamples: - let encodedInts = encode([1'u8,2,3]) - assert encodedInts == "AQID" - let encodedChars = encode(['h','e','y']) - assert encodedChars == "aGV5" - -##[ +## .. code-block::nim +## import base64 +## let encodedInts = encode([1,2,3]) +## assert encodedInts == "AQID" +## let encodedChars = encode(['h','e','y']) +## assert encodedChars == "aGV5" +## +## ## Decoding data -]## - -runnableExamples: - let decoded = decode("SGVsbG8gV29ybGQ=") - assert decoded == "Hello World" - -##[ -## URL Safe Base64 -]## - -runnableExamples: - assert encode("c\xf7>", safe = true) == "Y_c-" - assert encode("c\xf7>", safe = false) == "Y/c+" - +## ------------- +## +## .. code-block::nim +## import base64 +## let decoded = decode("SGVsbG8gV29ybGQ=") +## assert decoded == "Hello World" +## +## ## See also ## ======== ## ## * `hashes module`_ for efficient computations of hash values for diverse Nim types -## * `md5 module`_ for the MD5 checksum algorithm -## * `sha1 module`_ for the SHA-1 checksum algorithm - -template cbBase(a, b): untyped = [ - 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', - 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', - 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', - 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', a, b] - -let - cb64 = cbBase('+', '/') - cb64safe = cbBase('-', '_') - -const - cb64VM = cbBase('+', '/') - cb64safeVM = cbBase('-', '_') +## * `md5 module`_ implements the MD5 checksum algorithm +## * `sha1 module`_ implements a sha1 encoder and decoder const + cb64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" invalidChar = 255 -template encodeSize(size: int): int = (size * 4 div 3) + 6 - -template encodeInternal(s, alphabet: typed): untyped = +template encodeInternal(s: typed): untyped = ## encodes `s` into base64 representation. + proc encodeSize(size: int): int = + return (size * 4 div 3) + 6 result.setLen(encodeSize(s.len)) - let - padding = s.len mod 3 - inputEnds = s.len - padding - var inputIndex = 0 outputIndex = 0 + inputEnds = s.len - s.len mod 3 n: uint32 b: uint32 @@ -99,8 +77,8 @@ template encodeInternal(s, alphabet: typed): untyped = n = exp inc inputIndex - template outputChar(x: typed) = - result[outputIndex] = alphabet[x and 63] + template outputChar(x: untyped) = + result[outputIndex] = cb64[x and 63] inc outputIndex template outputChar(c: char) = @@ -116,6 +94,7 @@ template encodeInternal(s, alphabet: typed): untyped = outputChar(n shr 6) outputChar(n shr 0) + var padding = s.len mod 3 if padding == 1: inputByte(b shl 16) outputChar(n shr 18) @@ -133,75 +112,48 @@ template encodeInternal(s, alphabet: typed): untyped = result.setLen(outputIndex) -template encodeImpl() {.dirty.} = - when nimvm: - block: - let lookupTableVM = if safe: cb64safeVM else: cb64VM - encodeInternal(s, lookupTableVM) - else: - block: - let lookupTable = if safe: unsafeAddr(cb64safe) else: unsafeAddr(cb64) - encodeInternal(s, lookupTable) - -proc encode*[T: byte|char](s: openArray[T], safe = false): string = +proc encode*[T: SomeInteger|char](s: openArray[T]): string = ## Encodes `s` into base64 representation. ## - ## If `safe` is `true` then it will encode using the - ## URL-Safe and Filesystem-safe standard alphabet characters, - ## which substitutes `-` instead of `+` and `_` instead of `/`. - ## * https://en.wikipedia.org/wiki/Base64#URL_applications - ## * https://tools.ietf.org/html/rfc4648#page-7 + ## This procedure encodes an openarray (array or sequence) of either integers + ## or characters. ## ## **See also:** + ## * `encode proc<#encode,string>`_ for encoding a string + ## * `decode proc<#decode,string>`_ for decoding a string + runnableExamples: + assert encode(['n', 'i', 'm']) == "bmlt" + assert encode(@['n', 'i', 'm']) == "bmlt" + assert encode([1, 2, 3, 4, 5]) == "AQIDBAU=" + encodeInternal(s) + +proc encode*(s: string): string = + ## Encodes ``s`` into base64 representation. + ## + ## This procedure encodes a string. + ## + ## **See also:** + ## * `encode proc<#encode,openArray[T]>`_ for encoding an openarray ## * `decode proc<#decode,string>`_ for decoding a string runnableExamples: assert encode("Hello World") == "SGVsbG8gV29ybGQ=" - assert encode(['n', 'i', 'm']) == "bmlt" - assert encode(@['n', 'i', 'm']) == "bmlt" - assert encode([1'u8, 2, 3, 4, 5]) == "AQIDBAU=" - encodeImpl() + encodeInternal(s) -proc encode*[T: SomeInteger and not byte](s: openArray[T], safe = false): string - {.deprecated: "use `byte` or `char` instead".} = - encodeImpl() - -proc encodeMime*(s: string, lineLen = 75.Positive, newLine = "\r\n", - safe = false): string = - ## Encodes `s` into base64 representation as lines. - ## Used in email MIME format, use `lineLen` and `newline`. +proc encodeMIME*(s: string, lineLen = 75, newLine = "\r\n"): string = + ## Encodes ``s`` into base64 representation as lines. + ## Used in email MIME forma, use ``lineLen`` and ``newline``. ## ## This procedure encodes a string according to MIME spec. ## - ## If `safe` is `true` then it will encode using the - ## URL-Safe and Filesystem-safe standard alphabet characters, - ## which substitutes `-` instead of `+` and `_` instead of `/`. - ## * https://en.wikipedia.org/wiki/Base64#URL_applications - ## * https://tools.ietf.org/html/rfc4648#page-7 - ## ## **See also:** - ## * `encode proc<#encode,openArray[T]>`_ for encoding an openArray + ## * `encode proc<#encode,string>`_ for encoding a string ## * `decode proc<#decode,string>`_ for decoding a string runnableExamples: - assert encodeMime("Hello World", 4, "\n") == "SGVs\nbG8g\nV29y\nbGQ=" - template cpy(l, src, idx) = - b = l - while i < b: - result[i] = src[idx] - inc i - inc idx - - if s.len == 0: return - let e = encode(s, safe) - if e.len <= lineLen or newLine.len == 0: - return e - result = newString(e.len + newLine.len * ((e.len div lineLen) - int(e.len mod lineLen == 0))) - var i, j, k, b: int - let nd = e.len - lineLen - while j < nd: - cpy(i + lineLen, e, j) - cpy(i + newLine.len, newLine, k) - k = 0 - cpy(result.len, e, j) + assert encodeMIME("Hello World", 4, "\n") == "SGVs\nbG8g\nV29y\nbGQ=" + for i, c in encode(s): + if i != 0 and (i mod lineLen == 0): + result.add(newLine) + result.add(c) proc initDecodeTable*(): array[256, char] = # computes a decode table at compile time @@ -219,11 +171,12 @@ const decodeTable = initDecodeTable() proc decode*(s: string): string = - ## Decodes string `s` in base64 representation back into its original form. + ## Decodes string ``s`` in base64 representation back into its original form. ## The initial whitespace is skipped. ## ## **See also:** ## * `encode proc<#encode,openArray[T]>`_ for encoding an openarray + ## * `encode proc<#encode,string>`_ for encoding a string runnableExamples: assert decode("SGVsbG8gV29ybGQ=") == "Hello World" assert decode(" SGVsbG8gV29ybGQ=") == "Hello World" @@ -234,11 +187,11 @@ proc decode*(s: string): string = template inputChar(x: untyped) = let x = int decodeTable[ord(s[inputIndex])] + inc inputIndex if x == invalidChar: raise newException(ValueError, "Invalid base64 format character `" & s[inputIndex] & "` (ord " & $s[inputIndex].ord & ") at location " & $inputIndex & ".") - inc inputIndex template outputChar(x: untyped) = result[outputIndex] = char(x and 255) @@ -279,3 +232,6 @@ proc decode*(s: string): string = outputChar(a shl 2 or b shr 4) outputChar(b shl 4 or c shr 2) result.setLen(outputIndex) + + + diff --git a/lib/pure/bitops.nim b/lib/pure/bitops.nim index a518c25d2..9ebdabb7b 100644 --- a/lib/pure/bitops.nim +++ b/lib/pure/bitops.nim @@ -8,374 +8,140 @@ # ## This module implements a series of low level methods for bit manipulation. + +## By default, this module use compiler intrinsics where possible to improve performance +## on supported compilers: ``GCC``, ``LLVM_GCC``, ``CLANG``, ``VCC``, ``ICC``. ## -## By default, compiler intrinsics are used where possible to improve performance -## on supported compilers: `GCC`, `LLVM_GCC`, `CLANG`, `VCC`, `ICC`. -## -## The module will fallback to pure nim procs in case the backend is not supported. +## The module will fallback to pure nim procs incase the backend is not supported. ## You can also use the flag `noIntrinsicsBitOpts` to disable compiler intrinsics. ## -## This module is also compatible with other backends: `JavaScript`, `NimScript` -## as well as the `compiletime VM`. +## This module is also compatible with other backends: ``Javascript``, ``Nimscript`` +## as well as the ``compiletime VM``. ## -## As a result of using optimized functions/intrinsics, some functions can return +## As a result of using optimized function/intrinsics some functions can return ## undefined results if the input is invalid. You can use the flag `noUndefinedBitOpts` ## to force predictable behaviour for all input, causing a small performance hit. ## -## At this time only `fastLog2`, `firstSetBit`, `countLeadingZeroBits` and `countTrailingZeroBits` -## may return undefined and/or platform dependent values if given invalid input. +## At this time only `fastLog2`, `firstSetBit, `countLeadingZeroBits`, `countTrailingZeroBits` +## may return undefined and/or platform dependent value if given invalid input. -import macros -import std/private/since -from std/private/bitops_utils import forwardImpl, castToUnsigned - -func bitnot*[T: SomeInteger](x: T): T {.magic: "BitnotI".} +proc bitnot*[T: SomeInteger](x: T): T {.magic: "BitnotI", noSideEffect.} ## Computes the `bitwise complement` of the integer `x`. -func internalBitand[T: SomeInteger](x, y: T): T {.magic: "BitandI".} +proc bitand*[T: SomeInteger](x, y: T): T {.magic: "BitandI", noSideEffect.} + ## Computes the `bitwise and` of numbers `x` and `y`. -func internalBitor[T: SomeInteger](x, y: T): T {.magic: "BitorI".} +proc bitor*[T: SomeInteger](x, y: T): T {.magic: "BitorI", noSideEffect.} + ## Computes the `bitwise or` of numbers `x` and `y`. -func internalBitxor[T: SomeInteger](x, y: T): T {.magic: "BitxorI".} +proc bitxor*[T: SomeInteger](x, y: T): T {.magic: "BitxorI", noSideEffect.} + ## Computes the `bitwise xor` of numbers `x` and `y`. -macro bitand*[T: SomeInteger](x, y: T; z: varargs[T]): T = - ## Computes the `bitwise and` of all arguments collectively. - let fn = bindSym("internalBitand") - result = newCall(fn, x, y) - for extra in z: - result = newCall(fn, result, extra) +const useBuiltins = not defined(noIntrinsicsBitOpts) +const noUndefined = defined(noUndefinedBitOpts) +const useGCC_builtins = (defined(gcc) or defined(llvm_gcc) or + defined(clang)) and useBuiltins +const useICC_builtins = defined(icc) and useBuiltins +const useVCC_builtins = defined(vcc) and useBuiltins +const arch64 = sizeof(int) == 8 -macro bitor*[T: SomeInteger](x, y: T; z: varargs[T]): T = - ## Computes the `bitwise or` of all arguments collectively. - let fn = bindSym("internalBitor") - result = newCall(fn, x, y) - for extra in z: - result = newCall(fn, result, extra) +template toUnsigned(x: int8): uint8 = cast[uint8](x) +template toUnsigned(x: int16): uint16 = cast[uint16](x) +template toUnsigned(x: int32): uint32 = cast[uint32](x) +template toUnsigned(x: int64): uint64 = cast[uint64](x) +template toUnsigned(x: int): uint = cast[uint](x) -macro bitxor*[T: SomeInteger](x, y: T; z: varargs[T]): T = - ## Computes the `bitwise xor` of all arguments collectively. - let fn = bindSym("internalBitxor") - result = newCall(fn, x, y) - for extra in z: - result = newCall(fn, result, extra) +template forwardImpl(impl, arg) {.dirty.} = + when sizeof(x) <= 4: + when x is SomeSignedInt: + impl(cast[uint32](x.int32)) + else: + impl(x.uint32) + else: + when x is SomeSignedInt: + impl(cast[uint64](x.int64)) + else: + impl(x.uint64) +when defined(nimHasalignOf): -type BitsRange*[T] = range[0..sizeof(T)*8-1] - ## A range with all bit positions for type `T`. + import macros -func bitsliced*[T: SomeInteger](v: T; slice: Slice[int]): T {.inline, since: (1, 3).} = - ## Returns an extracted (and shifted) slice of bits from `v`. - runnableExamples: - doAssert 0b10111.bitsliced(2 .. 4) == 0b101 - doAssert 0b11100.bitsliced(0 .. 2) == 0b100 - doAssert 0b11100.bitsliced(0 ..< 3) == 0b100 + type BitsRange*[T] = range[0..sizeof(T)*8-1] + ## Returns a range with all bit positions for type ``T`` - let - upmost = sizeof(T) * 8 - 1 - uv = v.castToUnsigned - (uv shl (upmost - slice.b) shr (upmost - slice.b + slice.a)).T + proc setMask*[T: SomeInteger](v: var T, mask: T) {.inline.} = + ## Returns ``v``, with all the ``1`` bits from ``mask`` set to 1 + v = v or mask -proc bitslice*[T: SomeInteger](v: var T; slice: Slice[int]) {.inline, since: (1, 3).} = - ## Mutates `v` into an extracted (and shifted) slice of bits from `v`. - runnableExamples: - var x = 0b101110 - x.bitslice(2 .. 4) - doAssert x == 0b011 + proc clearMask*[T: SomeInteger](v: var T, mask: T) {.inline.} = + ## Returns ``v``, with all the ``1`` bits from ``mask`` set to 0 + v = v and not mask - let - upmost = sizeof(T) * 8 - 1 - uv = v.castToUnsigned - v = (uv shl (upmost - slice.b) shr (upmost - slice.b + slice.a)).T + proc flipMask*[T: SomeInteger](v: var T, mask: T) {.inline.} = + ## Returns ``v``, with all the ``1`` bits from ``mask`` flipped + v = v xor mask -func toMask*[T: SomeInteger](slice: Slice[int]): T {.inline, since: (1, 3).} = - ## Creates a bitmask based on a slice of bits. - runnableExamples: - doAssert toMask[int32](1 .. 3) == 0b1110'i32 - doAssert toMask[int32](0 .. 3) == 0b1111'i32 + proc setBit*[T: SomeInteger](v: var T, bit: BitsRange[T]) {.inline.} = + ## Returns ``v``, with the bit at position ``bit`` set to 1 + v.setMask(1.T shl bit) - let - upmost = sizeof(T) * 8 - 1 - bitmask = bitnot(0.T).castToUnsigned - (bitmask shl (upmost - slice.b + slice.a) shr (upmost - slice.b)).T + proc clearBit*[T: SomeInteger](v: var T, bit: BitsRange[T]) {.inline.} = + ## Returns ``v``, with the bit at position ``bit`` set to 0 + v.clearMask(1.T shl bit) -proc masked*[T: SomeInteger](v, mask :T): T {.inline, since: (1, 3).} = - ## Returns `v`, with only the `1` bits from `mask` matching those of - ## `v` set to 1. - ## - ## Effectively maps to a `bitand <#bitand.m,T,T,varargs[T]>`_ operation. - runnableExamples: - let v = 0b0000_0011'u8 - doAssert v.masked(0b0000_1010'u8) == 0b0000_0010'u8 + proc flipBit*[T: SomeInteger](v: var T, bit: BitsRange[T]) {.inline.} = + ## Returns ``v``, with the bit at position ``bit`` flipped + v.flipMask(1.T shl bit) - bitand(v, mask) + macro setBits*(v: typed, bits: varargs[typed]): untyped = + ## Returns ``v``, with the bits at positions ``bits`` set to 1 + bits.expectKind(nnkBracket) + result = newStmtList() + for bit in bits: + result.add newCall("setBit", v, bit) -func masked*[T: SomeInteger](v: T; slice: Slice[int]): T {.inline, since: (1, 3).} = - ## Returns `v`, with only the `1` bits in the range of `slice` - ## matching those of `v` set to 1. - ## - ## Effectively maps to a `bitand <#bitand.m,T,T,varargs[T]>`_ operation. - runnableExamples: - let v = 0b0000_1011'u8 - doAssert v.masked(1 .. 3) == 0b0000_1010'u8 + macro clearBits*(v: typed, bits: varargs[typed]): untyped = + ## Returns ``v``, with the bits at positions ``bits`` set to 0 + bits.expectKind(nnkBracket) + result = newStmtList() + for bit in bits: + result.add newCall("clearBit", v, bit) - bitand(v, toMask[T](slice)) + macro flipBits*(v: typed, bits: varargs[typed]): untyped = + ## Returns ``v``, with the bits at positions ``bits`` set to 0 + bits.expectKind(nnkBracket) + result = newStmtList() + for bit in bits: + result.add newCall("flipBit", v, bit) -proc mask*[T: SomeInteger](v: var T; mask: T) {.inline, since: (1, 3).} = - ## Mutates `v`, with only the `1` bits from `mask` matching those of - ## `v` set to 1. - ## - ## Effectively maps to a `bitand <#bitand.m,T,T,varargs[T]>`_ operation. - runnableExamples: - var v = 0b0000_0011'u8 - v.mask(0b0000_1010'u8) - doAssert v == 0b0000_0010'u8 - - v = bitand(v, mask) - -proc mask*[T: SomeInteger](v: var T; slice: Slice[int]) {.inline, since: (1, 3).} = - ## Mutates `v`, with only the `1` bits in the range of `slice` - ## matching those of `v` set to 1. - ## - ## Effectively maps to a `bitand <#bitand.m,T,T,varargs[T]>`_ operation. - runnableExamples: - var v = 0b0000_1011'u8 - v.mask(1 .. 3) - doAssert v == 0b0000_1010'u8 - - v = bitand(v, toMask[T](slice)) - -func setMasked*[T: SomeInteger](v, mask :T): T {.inline, since: (1, 3).} = - ## Returns `v`, with all the `1` bits from `mask` set to 1. - ## - ## Effectively maps to a `bitor <#bitor.m,T,T,varargs[T]>`_ operation. - runnableExamples: - let v = 0b0000_0011'u8 - doAssert v.setMasked(0b0000_1010'u8) == 0b0000_1011'u8 - - bitor(v, mask) - -func setMasked*[T: SomeInteger](v: T; slice: Slice[int]): T {.inline, since: (1, 3).} = - ## Returns `v`, with all the `1` bits in the range of `slice` set to 1. - ## - ## Effectively maps to a `bitor <#bitor.m,T,T,varargs[T]>`_ operation. - runnableExamples: - let v = 0b0000_0011'u8 - doAssert v.setMasked(2 .. 3) == 0b0000_1111'u8 - - bitor(v, toMask[T](slice)) - -proc setMask*[T: SomeInteger](v: var T; mask: T) {.inline.} = - ## Mutates `v`, with all the `1` bits from `mask` set to 1. - ## - ## Effectively maps to a `bitor <#bitor.m,T,T,varargs[T]>`_ operation. - runnableExamples: - var v = 0b0000_0011'u8 - v.setMask(0b0000_1010'u8) - doAssert v == 0b0000_1011'u8 - - v = bitor(v, mask) - -proc setMask*[T: SomeInteger](v: var T; slice: Slice[int]) {.inline, since: (1, 3).} = - ## Mutates `v`, with all the `1` bits in the range of `slice` set to 1. - ## - ## Effectively maps to a `bitor <#bitor.m,T,T,varargs[T]>`_ operation. - runnableExamples: - var v = 0b0000_0011'u8 - v.setMask(2 .. 3) - doAssert v == 0b0000_1111'u8 - - v = bitor(v, toMask[T](slice)) - -func clearMasked*[T: SomeInteger](v, mask :T): T {.inline, since: (1, 3).} = - ## Returns `v`, with all the `1` bits from `mask` set to 0. - ## - ## Effectively maps to a `bitand <#bitand.m,T,T,varargs[T]>`_ operation - ## with an *inverted mask*. - runnableExamples: - let v = 0b0000_0011'u8 - doAssert v.clearMasked(0b0000_1010'u8) == 0b0000_0001'u8 - - bitand(v, bitnot(mask)) - -func clearMasked*[T: SomeInteger](v: T; slice: Slice[int]): T {.inline, since: (1, 3).} = - ## Returns `v`, with all the `1` bits in the range of `slice` set to 0. - ## - ## Effectively maps to a `bitand <#bitand.m,T,T,varargs[T]>`_ operation - ## with an *inverted mask*. - runnableExamples: - let v = 0b0000_0011'u8 - doAssert v.clearMasked(1 .. 3) == 0b0000_0001'u8 - - bitand(v, bitnot(toMask[T](slice))) - -proc clearMask*[T: SomeInteger](v: var T; mask: T) {.inline.} = - ## Mutates `v`, with all the `1` bits from `mask` set to 0. - ## - ## Effectively maps to a `bitand <#bitand.m,T,T,varargs[T]>`_ operation - ## with an *inverted mask*. - runnableExamples: - var v = 0b0000_0011'u8 - v.clearMask(0b0000_1010'u8) - doAssert v == 0b0000_0001'u8 - - v = bitand(v, bitnot(mask)) - -proc clearMask*[T: SomeInteger](v: var T; slice: Slice[int]) {.inline, since: (1, 3).} = - ## Mutates `v`, with all the `1` bits in the range of `slice` set to 0. - ## - ## Effectively maps to a `bitand <#bitand.m,T,T,varargs[T]>`_ operation - ## with an *inverted mask*. - runnableExamples: - var v = 0b0000_0011'u8 - v.clearMask(1 .. 3) - doAssert v == 0b0000_0001'u8 - - v = bitand(v, bitnot(toMask[T](slice))) - -func flipMasked*[T: SomeInteger](v, mask :T): T {.inline, since: (1, 3).} = - ## Returns `v`, with all the `1` bits from `mask` flipped. - ## - ## Effectively maps to a `bitxor <#bitxor.m,T,T,varargs[T]>`_ operation. - runnableExamples: - let v = 0b0000_0011'u8 - doAssert v.flipMasked(0b0000_1010'u8) == 0b0000_1001'u8 - - bitxor(v, mask) - -func flipMasked*[T: SomeInteger](v: T; slice: Slice[int]): T {.inline, since: (1, 3).} = - ## Returns `v`, with all the `1` bits in the range of `slice` flipped. - ## - ## Effectively maps to a `bitxor <#bitxor.m,T,T,varargs[T]>`_ operation. - runnableExamples: - let v = 0b0000_0011'u8 - doAssert v.flipMasked(1 .. 3) == 0b0000_1101'u8 - - bitxor(v, toMask[T](slice)) - -proc flipMask*[T: SomeInteger](v: var T; mask: T) {.inline.} = - ## Mutates `v`, with all the `1` bits from `mask` flipped. - ## - ## Effectively maps to a `bitxor <#bitxor.m,T,T,varargs[T]>`_ operation. - runnableExamples: - var v = 0b0000_0011'u8 - v.flipMask(0b0000_1010'u8) - doAssert v == 0b0000_1001'u8 - - v = bitxor(v, mask) - -proc flipMask*[T: SomeInteger](v: var T; slice: Slice[int]) {.inline, since: (1, 3).} = - ## Mutates `v`, with all the `1` bits in the range of `slice` flipped. - ## - ## Effectively maps to a `bitxor <#bitxor.m,T,T,varargs[T]>`_ operation. - runnableExamples: - var v = 0b0000_0011'u8 - v.flipMask(1 .. 3) - doAssert v == 0b0000_1101'u8 - - v = bitxor(v, toMask[T](slice)) - -proc setBit*[T: SomeInteger](v: var T; bit: BitsRange[T]) {.inline.} = - ## Mutates `v`, with the bit at position `bit` set to 1. - runnableExamples: - var v = 0b0000_0011'u8 - v.setBit(5'u8) - doAssert v == 0b0010_0011'u8 - - v.setMask(1.T shl bit) - -proc clearBit*[T: SomeInteger](v: var T; bit: BitsRange[T]) {.inline.} = - ## Mutates `v`, with the bit at position `bit` set to 0. - runnableExamples: - var v = 0b0000_0011'u8 - v.clearBit(1'u8) - doAssert v == 0b0000_0001'u8 - - v.clearMask(1.T shl bit) - -proc flipBit*[T: SomeInteger](v: var T; bit: BitsRange[T]) {.inline.} = - ## Mutates `v`, with the bit at position `bit` flipped. - runnableExamples: - var v = 0b0000_0011'u8 - v.flipBit(1'u8) - doAssert v == 0b0000_0001'u8 - - v = 0b0000_0011'u8 - v.flipBit(2'u8) - doAssert v == 0b0000_0111'u8 - - v.flipMask(1.T shl bit) - -macro setBits*(v: typed; bits: varargs[typed]): untyped = - ## Mutates `v`, with the bits at positions `bits` set to 1. - runnableExamples: - var v = 0b0000_0011'u8 - v.setBits(3, 5, 7) - doAssert v == 0b1010_1011'u8 - - bits.expectKind(nnkBracket) - result = newStmtList() - for bit in bits: - result.add newCall("setBit", v, bit) - -macro clearBits*(v: typed; bits: varargs[typed]): untyped = - ## Mutates `v`, with the bits at positions `bits` set to 0. - runnableExamples: - var v = 0b1111_1111'u8 - v.clearBits(1, 3, 5, 7) - doAssert v == 0b0101_0101'u8 - - bits.expectKind(nnkBracket) - result = newStmtList() - for bit in bits: - result.add newCall("clearBit", v, bit) - -macro flipBits*(v: typed; bits: varargs[typed]): untyped = - ## Mutates `v`, with the bits at positions `bits` set to 0. - runnableExamples: - var v = 0b0000_1111'u8 - v.flipBits(1, 3, 5, 7) - doAssert v == 0b1010_0101'u8 - - bits.expectKind(nnkBracket) - result = newStmtList() - for bit in bits: - result.add newCall("flipBit", v, bit) - - -proc testBit*[T: SomeInteger](v: T; bit: BitsRange[T]): bool {.inline.} = - ## Returns true if the bit in `v` at positions `bit` is set to 1. - runnableExamples: - let v = 0b0000_1111'u8 - doAssert v.testBit(0) - doAssert not v.testBit(7) - - let mask = 1.T shl bit - return (v and mask) == mask + proc testBit*[T: SomeInteger](v: T, bit: BitsRange[T]): bool {.inline.} = + ## Returns true if the bit in ``v`` at positions ``bit`` is set to 1 + let mask = 1.T shl bit + return (v and mask) == mask # #### Pure Nim version #### -func firstSetBitNim(x: uint32): int {.inline.} = +proc firstSetBitNim(x: uint32): int {.inline, noSideEffect.} = ## Returns the 1-based index of the least significant set bit of x, or if x is zero, returns zero. # https://graphics.stanford.edu/%7Eseander/bithacks.html#ZerosOnRightMultLookup const lookup: array[32, uint8] = [0'u8, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8, 31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9] - let v = x.uint32 - let k = not v + 1 # get two's complement # cast[uint32](-cast[int32](v)) + var v = x.uint32 + var k = not v + 1 # get two's complement # cast[uint32](-cast[int32](v)) result = 1 + lookup[uint32((v and k) * 0x077CB531'u32) shr 27].int -func firstSetBitNim(x: uint64): int {.inline.} = +proc firstSetBitNim(x: uint64): int {.inline, noSideEffect.} = ## Returns the 1-based index of the least significant set bit of x, or if x is zero, returns zero. # https://graphics.stanford.edu/%7Eseander/bithacks.html#ZerosOnRightMultLookup - let v = uint64(x) + var v = uint64(x) var k = uint32(v and 0xFFFFFFFF'u32) if k == 0: k = uint32(v shr 32'u32) and 0xFFFFFFFF'u32 result = 32 - else: - result = 0 result += firstSetBitNim(k) -func fastlog2Nim(x: uint32): int {.inline.} = +proc fastlog2Nim(x: uint32): int {.inline, noSideEffect.} = ## Quickly find the log base 2 of a 32-bit or less integer. # https://graphics.stanford.edu/%7Eseander/bithacks.html#IntegerLogDeBruijn # https://stackoverflow.com/questions/11376288/fast-computing-of-log2-for-64-bit-integers @@ -389,7 +155,7 @@ func fastlog2Nim(x: uint32): int {.inline.} = v = v or v shr 16 result = lookup[uint32(v * 0x07C4ACDD'u32) shr 27].int -func fastlog2Nim(x: uint64): int {.inline.} = +proc fastlog2Nim(x: uint64): int {.inline, noSideEffect.} = ## Quickly find the log base 2 of a 64-bit integer. # https://graphics.stanford.edu/%7Eseander/bithacks.html#IntegerLogDeBruijn # https://stackoverflow.com/questions/11376288/fast-computing-of-log2-for-64-bit-integers @@ -406,11 +172,13 @@ func fastlog2Nim(x: uint64): int {.inline.} = v = v or v shr 32 result = lookup[(v * 0x03F6EAF2CD271461'u64) shr 58].int -import system/countbits_impl +# sets.nim cannot import bitops, but bitops can use include +# system/sets to eliminate code duplication. sets.nim defines +# countBits32 and countBits64. +include system/sets -const useBuiltinsRotate = (defined(amd64) or defined(i386)) and - (defined(gcc) or defined(clang) or defined(vcc) or - (defined(icl) and not defined(cpp))) and useBuiltins +template countSetBitsNim(n: uint32): int = countBits32(n) +template countSetBitsNim(n: uint64): int = countBits64(n) template parityImpl[T](value: T): int = # formula id from: https://graphics.stanford.edu/%7Eseander/bithacks.html#ParityParallel @@ -427,6 +195,11 @@ template parityImpl[T](value: T): int = when useGCC_builtins: + # Returns the number of set 1-bits in value. + proc builtin_popcount(x: cuint): cint {.importc: "__builtin_popcount", cdecl.} + proc builtin_popcountll(x: culonglong): cint {. + importc: "__builtin_popcountll", cdecl.} + # Returns the bit parity in value proc builtin_parity(x: cuint): cint {.importc: "__builtin_parity", cdecl.} proc builtin_parityll(x: culonglong): cint {.importc: "__builtin_parityll", cdecl.} @@ -444,17 +217,25 @@ when useGCC_builtins: proc builtin_ctzll(x: culonglong): cint {.importc: "__builtin_ctzll", cdecl.} elif useVCC_builtins: + # Counts the number of one bits (population count) in a 16-, 32-, or 64-byte unsigned integer. + proc builtin_popcnt16(a2: uint16): uint16 {. + importc: "__popcnt16"header: "", noSideEffect.} + proc builtin_popcnt32(a2: uint32): uint32 {. + importc: "__popcnt"header: "", noSideEffect.} + proc builtin_popcnt64(a2: uint64): uint64 {. + importc: "__popcnt64"header: "", noSideEffect.} + # Search the mask data from most significant bit (MSB) to least significant bit (LSB) for a set bit (1). - func bitScanReverse(index: ptr culong, mask: culong): uint8 {. - importc: "_BitScanReverse", header: "".} - func bitScanReverse64(index: ptr culong, mask: uint64): uint8 {. - importc: "_BitScanReverse64", header: "".} + proc bitScanReverse(index: ptr culong, mask: culong): cuchar {. + importc: "_BitScanReverse", header: "", noSideEffect.} + proc bitScanReverse64(index: ptr culong, mask: uint64): cuchar {. + importc: "_BitScanReverse64", header: "", noSideEffect.} # Search the mask data from least significant bit (LSB) to the most significant bit (MSB) for a set bit (1). - func bitScanForward(index: ptr culong, mask: culong): uint8 {. - importc: "_BitScanForward", header: "".} - func bitScanForward64(index: ptr culong, mask: uint64): uint8 {. - importc: "_BitScanForward64", header: "".} + proc bitScanForward(index: ptr culong, mask: culong): cuchar {. + importc: "_BitScanForward", header: "", noSideEffect.} + proc bitScanForward64(index: ptr culong, mask: uint64): cuchar {. + importc: "_BitScanForward64", header: "", noSideEffect.} template vcc_scan_impl(fnc: untyped; v: untyped): int = var index: culong @@ -462,47 +243,71 @@ elif useVCC_builtins: index.int elif useICC_builtins: + + # Intel compiler intrinsics: http://fulla.fnal.gov/intel/compiler_c/main_cls/intref_cls/common/intref_allia_misc.htm + # see also: https://software.intel.com/en-us/node/523362 + # Count the number of bits set to 1 in an integer a, and return that count in dst. + proc builtin_popcnt32(a: cint): cint {. + importc: "_popcnt"header: "", noSideEffect.} + proc builtin_popcnt64(a: uint64): cint {. + importc: "_popcnt64"header: "", noSideEffect.} + # Returns the number of trailing 0-bits in x, starting at the least significant bit position. If x is 0, the result is undefined. - func bitScanForward(p: ptr uint32, b: uint32): uint8 {. - importc: "_BitScanForward", header: "".} - func bitScanForward64(p: ptr uint32, b: uint64): uint8 {. - importc: "_BitScanForward64", header: "".} + proc bitScanForward(p: ptr uint32, b: uint32): cuchar {. + importc: "_BitScanForward", header: "", noSideEffect.} + proc bitScanForward64(p: ptr uint32, b: uint64): cuchar {. + importc: "_BitScanForward64", header: "", noSideEffect.} # Returns the number of leading 0-bits in x, starting at the most significant bit position. If x is 0, the result is undefined. - func bitScanReverse(p: ptr uint32, b: uint32): uint8 {. - importc: "_BitScanReverse", header: "".} - func bitScanReverse64(p: ptr uint32, b: uint64): uint8 {. - importc: "_BitScanReverse64", header: "".} + proc bitScanReverse(p: ptr uint32, b: uint32): cuchar {. + importc: "_BitScanReverse", header: "", noSideEffect.} + proc bitScanReverse64(p: ptr uint32, b: uint64): cuchar {. + importc: "_BitScanReverse64", header: "", noSideEffect.} template icc_scan_impl(fnc: untyped; v: untyped): int = var index: uint32 discard fnc(index.addr, v) index.int -func countSetBits*(x: SomeInteger): int {.inline.} = - ## Counts the set bits in an integer (also called `Hamming weight`:idx:). - runnableExamples: - doAssert countSetBits(0b0000_0011'u8) == 2 - doAssert countSetBits(0b1010_1010'u8) == 4 - result = countSetBitsImpl(x) +proc countSetBits*(x: SomeInteger): int {.inline, noSideEffect.} = + ## Counts the set bits in integer. (also called `Hamming weight`:idx:.) + # TODO: figure out if ICC support _popcnt32/_popcnt64 on platform without POPCNT. + # like GCC and MSVC + when x is SomeSignedInt: + let x = x.toUnsigned + when nimvm: + result = forwardImpl(countSetBitsNim, x) + else: + when useGCC_builtins: + when sizeof(x) <= 4: result = builtin_popcount(x.cuint).int + else: result = builtin_popcountll(x.culonglong).int + elif useVCC_builtins: + when sizeof(x) <= 2: result = builtin_popcnt16(x.uint16).int + elif sizeof(x) <= 4: result = builtin_popcnt32(x.uint32).int + elif arch64: result = builtin_popcnt64(x.uint64).int + else: result = builtin_popcnt32((x.uint64 and 0xFFFFFFFF'u64).uint32).int + + builtin_popcnt32((x.uint64 shr 32'u64).uint32).int + elif useICC_builtins: + when sizeof(x) <= 4: result = builtin_popcnt32(x.cint).int + elif arch64: result = builtin_popcnt64(x.uint64).int + else: result = builtin_popcnt32((x.uint64 and 0xFFFFFFFF'u64).cint).int + + builtin_popcnt32((x.uint64 shr 32'u64).cint).int + else: + when sizeof(x) <= 4: result = countSetBitsNim(x.uint32) + else: result = countSetBitsNim(x.uint64) -func popcount*(x: SomeInteger): int {.inline.} = - ## Alias for `countSetBits <#countSetBits,SomeInteger>`_ (Hamming weight). +proc popcount*(x: SomeInteger): int {.inline, noSideEffect.} = + ## Alias for for countSetBits (Hamming weight.) result = countSetBits(x) -func parityBits*(x: SomeInteger): int {.inline.} = - ## Calculate the bit parity in an integer. If the number of 1-bits - ## is odd, the parity is 1, otherwise 0. - runnableExamples: - doAssert parityBits(0b0000_0000'u8) == 0 - doAssert parityBits(0b0101_0001'u8) == 1 - doAssert parityBits(0b0110_1001'u8) == 0 - doAssert parityBits(0b0111_1111'u8) == 1 - +proc parityBits*(x: SomeInteger): int {.inline, noSideEffect.} = + ## Calculate the bit parity in integer. If number of 1-bit + ## is odd parity is 1, otherwise 0. # Can be used a base if creating ASM version. # https://stackoverflow.com/questions/21617970/how-to-check-if-value-has-even-parity-of-bits-or-odd - let x = x.castToUnsigned + when x is SomeSignedInt: + let x = x.toUnsigned when nimvm: result = forwardImpl(parityImpl, x) else: @@ -513,19 +318,13 @@ func parityBits*(x: SomeInteger): int {.inline.} = when sizeof(x) <= 4: result = parityImpl(x.uint32) else: result = parityImpl(x.uint64) -func firstSetBit*(x: SomeInteger): int {.inline.} = - ## Returns the 1-based index of the least significant set bit of `x`. - ## If `x` is zero, when `noUndefinedBitOpts` is set, the result is 0, - ## otherwise the result is undefined. - runnableExamples: - doAssert firstSetBit(0b0000_0001'u8) == 1 - doAssert firstSetBit(0b0000_0010'u8) == 2 - doAssert firstSetBit(0b0000_0100'u8) == 3 - doAssert firstSetBit(0b0000_1000'u8) == 4 - doAssert firstSetBit(0b0000_1111'u8) == 1 - +proc firstSetBit*(x: SomeInteger): int {.inline, noSideEffect.} = + ## Returns the 1-based index of the least significant set bit of x. + ## If `x` is zero, when ``noUndefinedBitOpts`` is set, result is 0, + ## otherwise result is undefined. # GCC builtin 'builtin_ffs' already handle zero input. - let x = x.castToUnsigned + when x is SomeSignedInt: + let x = x.toUnsigned when nimvm: when noUndefined: if x == 0: @@ -556,18 +355,12 @@ func firstSetBit*(x: SomeInteger): int {.inline.} = when sizeof(x) <= 4: result = firstSetBitNim(x.uint32) else: result = firstSetBitNim(x.uint64) -func fastLog2*(x: SomeInteger): int {.inline.} = +proc fastLog2*(x: SomeInteger): int {.inline, noSideEffect.} = ## Quickly find the log base 2 of an integer. - ## If `x` is zero, when `noUndefinedBitOpts` is set, the result is -1, - ## otherwise the result is undefined. - runnableExamples: - doAssert fastLog2(0b0000_0001'u8) == 0 - doAssert fastLog2(0b0000_0010'u8) == 1 - doAssert fastLog2(0b0000_0100'u8) == 2 - doAssert fastLog2(0b0000_1000'u8) == 3 - doAssert fastLog2(0b0000_1111'u8) == 3 - - let x = x.castToUnsigned + ## If `x` is zero, when ``noUndefinedBitOpts`` is set, result is -1, + ## otherwise result is undefined. + when x is SomeSignedInt: + let x = x.toUnsigned when noUndefined: if x == 0: return -1 @@ -595,21 +388,12 @@ func fastLog2*(x: SomeInteger): int {.inline.} = when sizeof(x) <= 4: result = fastlog2Nim(x.uint32) else: result = fastlog2Nim(x.uint64) -func countLeadingZeroBits*(x: SomeInteger): int {.inline.} = - ## Returns the number of leading zero bits in an integer. - ## If `x` is zero, when `noUndefinedBitOpts` is set, the result is 0, - ## otherwise the result is undefined. - ## - ## **See also:** - ## * `countTrailingZeroBits proc <#countTrailingZeroBits,SomeInteger>`_ - runnableExamples: - doAssert countLeadingZeroBits(0b0000_0001'u8) == 7 - doAssert countLeadingZeroBits(0b0000_0010'u8) == 6 - doAssert countLeadingZeroBits(0b0000_0100'u8) == 5 - doAssert countLeadingZeroBits(0b0000_1000'u8) == 4 - doAssert countLeadingZeroBits(0b0000_1111'u8) == 4 - - let x = x.castToUnsigned +proc countLeadingZeroBits*(x: SomeInteger): int {.inline, noSideEffect.} = + ## Returns the number of leading zero bits in integer. + ## If `x` is zero, when ``noUndefinedBitOpts`` is set, result is 0, + ## otherwise result is undefined. + when x is SomeSignedInt: + let x = x.toUnsigned when noUndefined: if x == 0: return 0 @@ -623,21 +407,12 @@ func countLeadingZeroBits*(x: SomeInteger): int {.inline.} = when sizeof(x) <= 4: result = sizeof(x)*8 - 1 - fastlog2Nim(x.uint32) else: result = sizeof(x)*8 - 1 - fastlog2Nim(x.uint64) -func countTrailingZeroBits*(x: SomeInteger): int {.inline.} = - ## Returns the number of trailing zeros in an integer. - ## If `x` is zero, when `noUndefinedBitOpts` is set, the result is 0, - ## otherwise the result is undefined. - ## - ## **See also:** - ## * `countLeadingZeroBits proc <#countLeadingZeroBits,SomeInteger>`_ - runnableExamples: - doAssert countTrailingZeroBits(0b0000_0001'u8) == 0 - doAssert countTrailingZeroBits(0b0000_0010'u8) == 1 - doAssert countTrailingZeroBits(0b0000_0100'u8) == 2 - doAssert countTrailingZeroBits(0b0000_1000'u8) == 3 - doAssert countTrailingZeroBits(0b0000_1111'u8) == 0 - - let x = x.castToUnsigned +proc countTrailingZeroBits*(x: SomeInteger): int {.inline, noSideEffect.} = + ## Returns the number of trailing zeros in integer. + ## If `x` is zero, when ``noUndefinedBitOpts`` is set, result is 0, + ## otherwise result is undefined. + when x is SomeSignedInt: + let x = x.toUnsigned when noUndefined: if x == 0: return 0 @@ -650,196 +425,69 @@ func countTrailingZeroBits*(x: SomeInteger): int {.inline.} = else: result = firstSetBit(x) - 1 -when useBuiltinsRotate: - when defined(gcc): - # GCC was tested until version 4.8.1 and intrinsics were present. Not tested - # in previous versions. - func builtin_rotl8(value: uint8, shift: cint): uint8 - {.importc: "__rolb", header: "".} - func builtin_rotl16(value: cushort, shift: cint): cushort - {.importc: "__rolw", header: "".} - func builtin_rotl32(value: cuint, shift: cint): cuint - {.importc: "__rold", header: "".} - when defined(amd64): - func builtin_rotl64(value: culonglong, shift: cint): culonglong - {.importc: "__rolq", header: "".} - func builtin_rotr8(value: uint8, shift: cint): uint8 - {.importc: "__rorb", header: "".} - func builtin_rotr16(value: cushort, shift: cint): cushort - {.importc: "__rorw", header: "".} - func builtin_rotr32(value: cuint, shift: cint): cuint - {.importc: "__rord", header: "".} - when defined(amd64): - func builtin_rotr64(value: culonglong, shift: cint): culonglong - {.importc: "__rorq", header: "".} - elif defined(clang): - # In CLANG, builtins have been present since version 8.0.0 and intrinsics - # since version 9.0.0. This implementation chose the builtins, as they have - # been around for longer. - # https://releases.llvm.org/8.0.0/tools/clang/docs/ReleaseNotes.html#non-comprehensive-list-of-changes-in-this-release - # https://releases.llvm.org/8.0.0/tools/clang/docs/LanguageExtensions.html#builtin-rotateleft - # source for correct declarations: https://github.com/llvm/llvm-project/blob/main/clang/include/clang/Basic/Builtins.def - func builtin_rotl8(value: uint8, shift: uint8): uint8 - {.importc: "__builtin_rotateleft8", nodecl.} - func builtin_rotl16(value: cushort, shift: cushort): cushort - {.importc: "__builtin_rotateleft16", nodecl.} - func builtin_rotl32(value: cuint, shift: cuint): cuint - {.importc: "__builtin_rotateleft32", nodecl.} - when defined(amd64): - func builtin_rotl64(value: culonglong, shift: culonglong): culonglong - {.importc: "__builtin_rotateleft64", nodecl.} +proc rotateLeftBits*(value: uint8; + amount: range[0..8]): uint8 {.inline, noSideEffect.} = + ## Left-rotate bits in a 8-bits value. + # using this form instead of the one below should handle any value + # out of range as well as negative values. + # result = (value shl amount) or (value shr (8 - amount)) + # taken from: https://en.wikipedia.org/wiki/Circular_shift#Implementing_circular_shifts + let amount = amount and 7 + result = (value shl amount) or (value shr ( (-amount) and 7)) - func builtin_rotr8(value: uint8, shift: uint8): uint8 - {.importc: "__builtin_rotateright8", nodecl.} - func builtin_rotr16(value: cushort, shift: cushort): cushort - {.importc: "__builtin_rotateright16", nodecl.} - func builtin_rotr32(value: cuint, shift: cuint): cuint - {.importc: "__builtin_rotateright32", nodecl.} - when defined(amd64): - # shift is unsigned, refs https://github.com/llvm-mirror/clang/commit/892de415b7fde609dafc4e6c1643b7eaa0150a4d - func builtin_rotr64(value: culonglong, shift: culonglong): culonglong - {.importc: "__builtin_rotateright64", nodecl.} - elif defined(vcc): - # Tested on Microsoft (R) C/C++ Optimizing Compiler 19.28.29335 x64 and x86. - # Not tested in previous versions. - # https://docs.microsoft.com/en-us/cpp/intrinsics/rotl8-rotl16?view=msvc-160 - # https://docs.microsoft.com/en-us/cpp/intrinsics/rotr8-rotr16?view=msvc-160 - # https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/rotl-rotl64-rotr-rotr64?view=msvc-160 - func builtin_rotl8(value: uint8, shift: uint8): uint8 - {.importc: "_rotl8", header: "".} - func builtin_rotl16(value: cushort, shift: uint8): cushort - {.importc: "_rotl16", header: "".} - func builtin_rotl32(value: cuint, shift: cint): cuint - {.importc: "_rotl", header: "".} - when defined(amd64): - func builtin_rotl64(value: culonglong, shift: cint): culonglong - {.importc: "_rotl64", header: "".} +proc rotateLeftBits*(value: uint16; + amount: range[0..16]): uint16 {.inline, noSideEffect.} = + ## Left-rotate bits in a 16-bits value. + let amount = amount and 15 + result = (value shl amount) or (value shr ( (-amount) and 15)) - func builtin_rotr8(value: uint8, shift: uint8): uint8 - {.importc: "_rotr8", header: "".} - func builtin_rotr16(value: cushort, shift: uint8): cushort - {.importc: "_rotr16", header: "".} - func builtin_rotr32(value: cuint, shift: cint): cuint - {.importc: "_rotr", header: "".} - when defined(amd64): - func builtin_rotr64(value: culonglong, shift: cint): culonglong - {.importc: "_rotr64", header: "".} - elif defined(icl): - # Tested on Intel(R) C++ Intel(R) 64 Compiler Classic Version 2021.1.2 Build - # 20201208_000000 x64 and x86. Not tested in previous versions. - func builtin_rotl8(value: uint8, shift: cint): uint8 - {.importc: "__rolb", header: "".} - func builtin_rotl16(value: cushort, shift: cint): cushort - {.importc: "__rolw", header: "".} - func builtin_rotl32(value: cuint, shift: cint): cuint - {.importc: "__rold", header: "".} - when defined(amd64): - func builtin_rotl64(value: culonglong, shift: cint): culonglong - {.importc: "__rolq", header: "".} +proc rotateLeftBits*(value: uint32; + amount: range[0..32]): uint32 {.inline, noSideEffect.} = + ## Left-rotate bits in a 32-bits value. + let amount = amount and 31 + result = (value shl amount) or (value shr ( (-amount) and 31)) - func builtin_rotr8(value: uint8, shift: cint): uint8 - {.importc: "__rorb", header: "".} - func builtin_rotr16(value: cushort, shift: cint): cushort - {.importc: "__rorw", header: "".} - func builtin_rotr32(value: cuint, shift: cint): cuint - {.importc: "__rord", header: "".} - when defined(amd64): - func builtin_rotr64(value: culonglong, shift: cint): culonglong - {.importc: "__rorq", header: "".} +proc rotateLeftBits*(value: uint64; + amount: range[0..64]): uint64 {.inline, noSideEffect.} = + ## Left-rotate bits in a 64-bits value. + let amount = amount and 63 + result = (value shl amount) or (value shr ( (-amount) and 63)) -func rotl[T: SomeUnsignedInt](value: T, rot: int32): T {.inline.} = - ## Left-rotate bits in a `value`. - # https://stackoverflow.com/a/776523 - const mask = 8 * sizeof(value) - 1 - let rot = rot and mask - (value shl rot) or (value shr ((-rot) and mask)) -func rotr[T: SomeUnsignedInt](value: T, rot: int32): T {.inline.} = - ## Right-rotate bits in a `value`. - const mask = 8 * sizeof(value) - 1 - let rot = rot and mask - (value shr rot) or (value shl ((-rot) and mask)) +proc rotateRightBits*(value: uint8; + amount: range[0..8]): uint8 {.inline, noSideEffect.} = + ## Right-rotate bits in a 8-bits value. + let amount = amount and 7 + result = (value shr amount) or (value shl ( (-amount) and 7)) -func shiftTypeTo(size: static int, shift: int): auto {.inline.} = - ## Returns the `shift` for the rotation according to the compiler and the - ## `size`. - when (defined(vcc) and (size in [4, 8])) or defined(gcc) or defined(icl): - cint(shift) - elif (defined(vcc) and (size in [1, 2])) or (defined(clang) and size == 1): - uint8(shift) - elif defined(clang): - when size == 2: - cushort(shift) - elif size == 4: - cuint(shift) - elif size == 8: - culonglong(shift) +proc rotateRightBits*(value: uint16; + amount: range[0..16]): uint16 {.inline, noSideEffect.} = + ## Right-rotate bits in a 16-bits value. + let amount = amount and 15 + result = (value shr amount) or (value shl ( (-amount) and 15)) -func rotateLeftBits*[T: SomeUnsignedInt](value: T, shift: range[0..(sizeof(T) * 8)]): T {.inline.} = - ## Left-rotate bits in a `value`. - runnableExamples: - doAssert rotateLeftBits(0b0110_1001'u8, 4) == 0b1001_0110'u8 - doAssert rotateLeftBits(0b00111100_11000011'u16, 8) == - 0b11000011_00111100'u16 - doAssert rotateLeftBits(0b0000111111110000_1111000000001111'u32, 16) == - 0b1111000000001111_0000111111110000'u32 - doAssert rotateLeftBits(0b00000000111111111111111100000000_11111111000000000000000011111111'u64, 32) == - 0b11111111000000000000000011111111_00000000111111111111111100000000'u64 - when nimvm: - rotl(value, shift.int32) - else: - when useBuiltinsRotate: - const size = sizeof(T) - when size == 1: - builtin_rotl8(value.uint8, shiftTypeTo(size, shift)).T - elif size == 2: - builtin_rotl16(value.cushort, shiftTypeTo(size, shift)).T - elif size == 4: - builtin_rotl32(value.cuint, shiftTypeTo(size, shift)).T - elif size == 8 and arch64: - builtin_rotl64(value.culonglong, shiftTypeTo(size, shift)).T - else: - rotl(value, shift.int32) - else: - rotl(value, shift.int32) +proc rotateRightBits*(value: uint32; + amount: range[0..32]): uint32 {.inline, noSideEffect.} = + ## Right-rotate bits in a 32-bits value. + let amount = amount and 31 + result = (value shr amount) or (value shl ( (-amount) and 31)) -func rotateRightBits*[T: SomeUnsignedInt](value: T, shift: range[0..(sizeof(T) * 8)]): T {.inline.} = - ## Right-rotate bits in a `value`. - runnableExamples: - doAssert rotateRightBits(0b0110_1001'u8, 4) == 0b1001_0110'u8 - doAssert rotateRightBits(0b00111100_11000011'u16, 8) == - 0b11000011_00111100'u16 - doAssert rotateRightBits(0b0000111111110000_1111000000001111'u32, 16) == - 0b1111000000001111_0000111111110000'u32 - doAssert rotateRightBits(0b00000000111111111111111100000000_11111111000000000000000011111111'u64, 32) == - 0b11111111000000000000000011111111_00000000111111111111111100000000'u64 - when nimvm: - rotr(value, shift.int32) - else: - when useBuiltinsRotate: - const size = sizeof(T) - when size == 1: - builtin_rotr8(value.uint8, shiftTypeTo(size, shift)).T - elif size == 2: - builtin_rotr16(value.cushort, shiftTypeTo(size, shift)).T - elif size == 4: - builtin_rotr32(value.cuint, shiftTypeTo(size, shift)).T - elif size == 8 and arch64: - builtin_rotr64(value.culonglong, shiftTypeTo(size, shift)).T - else: - rotr(value, shift.int32) - else: - rotr(value, shift.int32) +proc rotateRightBits*(value: uint64; + amount: range[0..64]): uint64 {.inline, noSideEffect.} = + ## Right-rotate bits in a 64-bits value. + let amount = amount and 63 + result = (value shr amount) or (value shl ( (-amount) and 63)) -func repeatBits[T: SomeUnsignedInt](x: SomeUnsignedInt; retType: type[T]): T = +proc repeatBits[T: SomeUnsignedInt](x: SomeUnsignedInt; retType: type[T]): T {. + noSideEffect.} = result = x var i = 1 while i != (sizeof(T) div sizeof(x)): result = (result shl (sizeof(x)*8*i)) or result i *= 2 -func reverseBits*[T: SomeUnsignedInt](x: T): T = +proc reverseBits*[T: SomeUnsignedInt](x: T): T {.noSideEffect.} = ## Return the bit reversal of x. runnableExamples: doAssert reverseBits(0b10100100'u8) == 0b00100101'u8 diff --git a/lib/pure/browsers.nim b/lib/pure/browsers.nim index ab248db36..3f2045c3b 100644 --- a/lib/pure/browsers.nim +++ b/lib/pure/browsers.nim @@ -12,85 +12,35 @@ ## ## Unstable API. -import std/private/since - import strutils -when defined(nimPreviewSlimSystem): - import std/assertions - when defined(windows): import winlean - when defined(nimPreviewSlimSystem): - import std/widestrs - from os import absolutePath else: - import os - when not defined(osx): - import osproc + import os, osproc -const osOpenCmd* = - when defined(macos) or defined(macosx) or defined(windows): "open" else: "xdg-open" ## \ - ## Alias for the operating system specific *"open"* command, - ## `"open"` on OSX, MacOS and Windows, `"xdg-open"` on Linux, BSD, etc. - -proc prepare(s: string): string = - if s.contains("://"): - result = s - else: - result = "file://" & absolutePath(s) - -proc openDefaultBrowserImpl(url: string) = +proc openDefaultBrowser*(url: string) = + ## opens `url` with the user's default browser. This does not block. + ## + ## Under Windows, ``ShellExecute`` is used. Under Mac OS X the ``open`` + ## command is used. Under Unix, it is checked if ``xdg-open`` exists and + ## used if it does. Otherwise the environment variable ``BROWSER`` is + ## used to determine the default browser to use. + ## + ## This proc doesn't raise an exception on error, beware. when defined(windows): - var o = newWideCString(osOpenCmd) - var u = newWideCString(prepare url) + var o = newWideCString("open") + var u = newWideCString(url) discard shellExecuteW(0'i32, o, u, nil, nil, SW_SHOWNORMAL) elif defined(macosx): - discard execShellCmd(osOpenCmd & " " & quoteShell(prepare url)) + discard execShellCmd("open " & quoteShell(url)) else: - var u = quoteShell(prepare url) - if execShellCmd(osOpenCmd & " " & u) == 0: return - for b in getEnv("BROWSER").split(PathSep): + var u = quoteShell(url) + if execShellCmd("xdg-open " & u) == 0: return + for b in getEnv("BROWSER").string.split(PathSep): try: - # we use `startProcess` here because we don't want to block! + # we use ``startProcess`` here because we don't want to block! discard startProcess(command = b, args = [url], options = {poUsePath}) return except OSError: discard - -proc openDefaultBrowser*(url: string) = - ## Opens `url` with the user's default browser. This does not block. - ## The URL must not be empty string, to open on a blank page see `openDefaultBrowser()`. - ## - ## Under Windows, `ShellExecute` is used. Under Mac OS X the `open` - ## command is used. Under Unix, it is checked if `xdg-open` exists and - ## used if it does. Otherwise the environment variable `BROWSER` is - ## used to determine the default browser to use. - ## - ## This proc doesn't raise an exception on error, beware. - ## - ## ```nim - ## block: openDefaultBrowser("https://nim-lang.org") - ## ``` - doAssert url.len > 0, "URL must not be empty string" - openDefaultBrowserImpl(url) - -proc openDefaultBrowser*() {.since: (1, 1).} = - ## Opens the user's default browser without any `url` (blank page). This does not block. - ## Implements IETF RFC-6694 Section 3, "about:blank" must be reserved for a blank page. - ## - ## Under Windows, `ShellExecute` is used. Under Mac OS X the `open` - ## command is used. Under Unix, it is checked if `xdg-open` exists and - ## used if it does. Otherwise the environment variable `BROWSER` is - ## used to determine the default browser to use. - ## - ## This proc doesn't raise an exception on error, beware. - ## - ## ```nim - ## block: openDefaultBrowser() - ## ``` - ## - ## **See also:** - ## - ## * https://tools.ietf.org/html/rfc6694#section-3 - openDefaultBrowserImpl("http:about:blank") # See IETF RFC-6694 Section 3. diff --git a/lib/pure/cgi.nim b/lib/pure/cgi.nim index e761569a1..dd7c4d477 100644 --- a/lib/pure/cgi.nim +++ b/lib/pure/cgi.nim @@ -9,32 +9,35 @@ ## This module implements helper procs for CGI applications. Example: ## -## ```Nim -## import std/[strtabs, cgi] +## .. code-block:: Nim ## -## # Fill the values when debugging: -## when debug: -## setTestData("name", "Klaus", "password", "123456") -## # read the data into `myData` -## var myData = readData() -## # check that the data's variable names are "name" or "password" -## validateData(myData, "name", "password") -## # start generating content: -## writeContentType() -## # generate content: -## write(stdout, "\n") -## write(stdout, "Test\n") -## writeLine(stdout, "your name: " & myData["name"]) -## writeLine(stdout, "your password: " & myData["password"]) -## writeLine(stdout, "") -## ``` +## import strtabs, cgi +## +## # Fill the values when debugging: +## when debug: +## setTestData("name", "Klaus", "password", "123456") +## # read the data into `myData` +## var myData = readData() +## # check that the data's variable names are "name" or "password" +## validateData(myData, "name", "password") +## # start generating content: +## writeContentType() +## # generate content: +## write(stdout, "\n") +## write(stdout, "Test\n") +## writeLine(stdout, "your name: " & myData["name"]) +## writeLine(stdout, "your password: " & myData["password"]) +## writeLine(stdout, "") import strutils, os, strtabs, cookies, uri export uri.encodeUrl, uri.decodeUrl -when defined(nimPreviewSlimSystem): - import std/syncio - +proc handleHexChar(c: char, x: var int) {.inline.} = + case c + of '0'..'9': x = (x shl 4) or (ord(c) - ord('0')) + of 'a'..'f': x = (x shl 4) or (ord(c) - ord('a') + 10) + of 'A'..'F': x = (x shl 4) or (ord(c) - ord('A') + 10) + else: assert(false) proc addXmlChar(dest: var string, c: char) {.inline.} = case c @@ -46,31 +49,34 @@ proc addXmlChar(dest: var string, c: char) {.inline.} = proc xmlEncode*(s: string): string = ## Encodes a value to be XML safe: - ## * `"` is replaced by `"` - ## * `<` is replaced by `<` - ## * `>` is replaced by `>` - ## * `&` is replaced by `&` + ## * ``"`` is replaced by ``"`` + ## * ``<`` is replaced by ``<`` + ## * ``>`` is replaced by ``>`` + ## * ``&`` is replaced by ``&`` ## * every other character is carried over. result = newStringOfCap(s.len + s.len shr 2) for i in 0..len(s)-1: addXmlChar(result, s[i]) type - CgiError* = object of IOError ## Exception that is raised if a CGI error occurs. - RequestMethod* = enum ## The used request method. + CgiError* = object of IOError ## exception that is raised if a CGI error occurs + RequestMethod* = enum ## the used request method methodNone, ## no REQUEST_METHOD environment variable methodPost, ## query uses the POST method methodGet ## query uses the GET method proc cgiError*(msg: string) {.noreturn.} = - ## Raises a `CgiError` exception with message `msg`. - raise newException(CgiError, msg) + ## raises an ECgi exception with message `msg`. + var e: ref CgiError + new(e) + e.msg = msg + raise e proc getEncodedData(allowedMethods: set[RequestMethod]): string = - case getEnv("REQUEST_METHOD") + case getEnv("REQUEST_METHOD").string of "POST": if methodPost notin allowedMethods: cgiError("'REQUEST_METHOD' 'POST' is not supported") - var L = parseInt(getEnv("CONTENT_LENGTH")) + var L = parseInt(getEnv("CONTENT_LENGTH").string) if L == 0: return "" result = newString(L) @@ -79,182 +85,218 @@ proc getEncodedData(allowedMethods: set[RequestMethod]): string = of "GET": if methodGet notin allowedMethods: cgiError("'REQUEST_METHOD' 'GET' is not supported") - result = getEnv("QUERY_STRING") + result = getEnv("QUERY_STRING").string else: if methodNone notin allowedMethods: cgiError("'REQUEST_METHOD' must be 'POST' or 'GET'") -iterator decodeData*(data: string): tuple[key, value: string] = +iterator decodeData*(data: string): tuple[key, value: TaintedString] = ## Reads and decodes CGI data and yields the (name, value) pairs the ## data consists of. - for (key, value) in uri.decodeQuery(data): - yield (key, value) + var i = 0 + var name = "" + var value = "" + # decode everything in one pass: + while i < data.len: + setLen(name, 0) # reuse memory + while i < data.len: + case data[i] + of '%': + var x = 0 + handleHexChar(data[i+1], x) + handleHexChar(data[i+2], x) + inc(i, 2) + add(name, chr(x)) + of '+': add(name, ' ') + of '=', '&': break + else: add(name, data[i]) + inc(i) + if i >= data.len or data[i] != '=': cgiError("'=' expected") + inc(i) # skip '=' + setLen(value, 0) # reuse memory + while i < data.len: + case data[i] + of '%': + var x = 0 + if i+2 < data.len: + handleHexChar(data[i+1], x) + handleHexChar(data[i+2], x) + inc(i, 2) + add(value, chr(x)) + of '+': add(value, ' ') + of '&', '\0': break + else: add(value, data[i]) + inc(i) + yield (name.TaintedString, value.TaintedString) + if i < data.len: + if data[i] == '&': inc(i) + else: cgiError("'&' expected") iterator decodeData*(allowedMethods: set[RequestMethod] = - {methodNone, methodPost, methodGet}): tuple[key, value: string] = + {methodNone, methodPost, methodGet}): tuple[key, value: TaintedString] = ## Reads and decodes CGI data and yields the (name, value) pairs the ## data consists of. If the client does not use a method listed in the - ## `allowedMethods` set, a `CgiError` exception is raised. + ## `allowedMethods` set, an `ECgi` exception is raised. let data = getEncodedData(allowedMethods) - for (key, value) in uri.decodeQuery(data): + for key, value in decodeData(data): yield (key, value) proc readData*(allowedMethods: set[RequestMethod] = {methodNone, methodPost, methodGet}): StringTableRef = - ## Reads CGI data. If the client does not use a method listed in the - ## `allowedMethods` set, a `CgiError` exception is raised. + ## Read CGI data. If the client does not use a method listed in the + ## `allowedMethods` set, an `ECgi` exception is raised. result = newStringTable() for name, value in decodeData(allowedMethods): - result[name] = value + result[name.string] = value.string proc readData*(data: string): StringTableRef = - ## Reads CGI data from a string. + ## Read CGI data from a string. result = newStringTable() for name, value in decodeData(data): - result[name] = value + result[name.string] = value.string proc validateData*(data: StringTableRef, validKeys: varargs[string]) = - ## Validates data; raises `CgiError` if this fails. This checks that each variable + ## validates data; raises `ECgi` if this fails. This checks that each variable ## name of the CGI `data` occurs in the `validKeys` array. for key, val in pairs(data): if find(validKeys, key) < 0: cgiError("unknown variable name: " & key) proc getContentLength*(): string = - ## Returns contents of the `CONTENT_LENGTH` environment variable. - return getEnv("CONTENT_LENGTH") + ## returns contents of the ``CONTENT_LENGTH`` environment variable + return getEnv("CONTENT_LENGTH").string proc getContentType*(): string = - ## Returns contents of the `CONTENT_TYPE` environment variable. - return getEnv("CONTENT_Type") + ## returns contents of the ``CONTENT_TYPE`` environment variable + return getEnv("CONTENT_Type").string proc getDocumentRoot*(): string = - ## Returns contents of the `DOCUMENT_ROOT` environment variable. - return getEnv("DOCUMENT_ROOT") + ## returns contents of the ``DOCUMENT_ROOT`` environment variable + return getEnv("DOCUMENT_ROOT").string proc getGatewayInterface*(): string = - ## Returns contents of the `GATEWAY_INTERFACE` environment variable. - return getEnv("GATEWAY_INTERFACE") + ## returns contents of the ``GATEWAY_INTERFACE`` environment variable + return getEnv("GATEWAY_INTERFACE").string proc getHttpAccept*(): string = - ## Returns contents of the `HTTP_ACCEPT` environment variable. - return getEnv("HTTP_ACCEPT") + ## returns contents of the ``HTTP_ACCEPT`` environment variable + return getEnv("HTTP_ACCEPT").string proc getHttpAcceptCharset*(): string = - ## Returns contents of the `HTTP_ACCEPT_CHARSET` environment variable. - return getEnv("HTTP_ACCEPT_CHARSET") + ## returns contents of the ``HTTP_ACCEPT_CHARSET`` environment variable + return getEnv("HTTP_ACCEPT_CHARSET").string proc getHttpAcceptEncoding*(): string = - ## Returns contents of the `HTTP_ACCEPT_ENCODING` environment variable. - return getEnv("HTTP_ACCEPT_ENCODING") + ## returns contents of the ``HTTP_ACCEPT_ENCODING`` environment variable + return getEnv("HTTP_ACCEPT_ENCODING").string proc getHttpAcceptLanguage*(): string = - ## Returns contents of the `HTTP_ACCEPT_LANGUAGE` environment variable. - return getEnv("HTTP_ACCEPT_LANGUAGE") + ## returns contents of the ``HTTP_ACCEPT_LANGUAGE`` environment variable + return getEnv("HTTP_ACCEPT_LANGUAGE").string proc getHttpConnection*(): string = - ## Returns contents of the `HTTP_CONNECTION` environment variable. - return getEnv("HTTP_CONNECTION") + ## returns contents of the ``HTTP_CONNECTION`` environment variable + return getEnv("HTTP_CONNECTION").string proc getHttpCookie*(): string = - ## Returns contents of the `HTTP_COOKIE` environment variable. - return getEnv("HTTP_COOKIE") + ## returns contents of the ``HTTP_COOKIE`` environment variable + return getEnv("HTTP_COOKIE").string proc getHttpHost*(): string = - ## Returns contents of the `HTTP_HOST` environment variable. - return getEnv("HTTP_HOST") + ## returns contents of the ``HTTP_HOST`` environment variable + return getEnv("HTTP_HOST").string proc getHttpReferer*(): string = - ## Returns contents of the `HTTP_REFERER` environment variable. - return getEnv("HTTP_REFERER") + ## returns contents of the ``HTTP_REFERER`` environment variable + return getEnv("HTTP_REFERER").string proc getHttpUserAgent*(): string = - ## Returns contents of the `HTTP_USER_AGENT` environment variable. - return getEnv("HTTP_USER_AGENT") + ## returns contents of the ``HTTP_USER_AGENT`` environment variable + return getEnv("HTTP_USER_AGENT").string proc getPathInfo*(): string = - ## Returns contents of the `PATH_INFO` environment variable. - return getEnv("PATH_INFO") + ## returns contents of the ``PATH_INFO`` environment variable + return getEnv("PATH_INFO").string proc getPathTranslated*(): string = - ## Returns contents of the `PATH_TRANSLATED` environment variable. - return getEnv("PATH_TRANSLATED") + ## returns contents of the ``PATH_TRANSLATED`` environment variable + return getEnv("PATH_TRANSLATED").string proc getQueryString*(): string = - ## Returns contents of the `QUERY_STRING` environment variable. - return getEnv("QUERY_STRING") + ## returns contents of the ``QUERY_STRING`` environment variable + return getEnv("QUERY_STRING").string proc getRemoteAddr*(): string = - ## Returns contents of the `REMOTE_ADDR` environment variable. - return getEnv("REMOTE_ADDR") + ## returns contents of the ``REMOTE_ADDR`` environment variable + return getEnv("REMOTE_ADDR").string proc getRemoteHost*(): string = - ## Returns contents of the `REMOTE_HOST` environment variable. - return getEnv("REMOTE_HOST") + ## returns contents of the ``REMOTE_HOST`` environment variable + return getEnv("REMOTE_HOST").string proc getRemoteIdent*(): string = - ## Returns contents of the `REMOTE_IDENT` environment variable. - return getEnv("REMOTE_IDENT") + ## returns contents of the ``REMOTE_IDENT`` environment variable + return getEnv("REMOTE_IDENT").string proc getRemotePort*(): string = - ## Returns contents of the `REMOTE_PORT` environment variable. - return getEnv("REMOTE_PORT") + ## returns contents of the ``REMOTE_PORT`` environment variable + return getEnv("REMOTE_PORT").string proc getRemoteUser*(): string = - ## Returns contents of the `REMOTE_USER` environment variable. - return getEnv("REMOTE_USER") + ## returns contents of the ``REMOTE_USER`` environment variable + return getEnv("REMOTE_USER").string proc getRequestMethod*(): string = - ## Returns contents of the `REQUEST_METHOD` environment variable. - return getEnv("REQUEST_METHOD") + ## returns contents of the ``REQUEST_METHOD`` environment variable + return getEnv("REQUEST_METHOD").string proc getRequestURI*(): string = - ## Returns contents of the `REQUEST_URI` environment variable. - return getEnv("REQUEST_URI") + ## returns contents of the ``REQUEST_URI`` environment variable + return getEnv("REQUEST_URI").string proc getScriptFilename*(): string = - ## Returns contents of the `SCRIPT_FILENAME` environment variable. - return getEnv("SCRIPT_FILENAME") + ## returns contents of the ``SCRIPT_FILENAME`` environment variable + return getEnv("SCRIPT_FILENAME").string proc getScriptName*(): string = - ## Returns contents of the `SCRIPT_NAME` environment variable. - return getEnv("SCRIPT_NAME") + ## returns contents of the ``SCRIPT_NAME`` environment variable + return getEnv("SCRIPT_NAME").string proc getServerAddr*(): string = - ## Returns contents of the `SERVER_ADDR` environment variable. - return getEnv("SERVER_ADDR") + ## returns contents of the ``SERVER_ADDR`` environment variable + return getEnv("SERVER_ADDR").string proc getServerAdmin*(): string = - ## Returns contents of the `SERVER_ADMIN` environment variable. - return getEnv("SERVER_ADMIN") + ## returns contents of the ``SERVER_ADMIN`` environment variable + return getEnv("SERVER_ADMIN").string proc getServerName*(): string = - ## Returns contents of the `SERVER_NAME` environment variable. - return getEnv("SERVER_NAME") + ## returns contents of the ``SERVER_NAME`` environment variable + return getEnv("SERVER_NAME").string proc getServerPort*(): string = - ## Returns contents of the `SERVER_PORT` environment variable. - return getEnv("SERVER_PORT") + ## returns contents of the ``SERVER_PORT`` environment variable + return getEnv("SERVER_PORT").string proc getServerProtocol*(): string = - ## Returns contents of the `SERVER_PROTOCOL` environment variable. - return getEnv("SERVER_PROTOCOL") + ## returns contents of the ``SERVER_PROTOCOL`` environment variable + return getEnv("SERVER_PROTOCOL").string proc getServerSignature*(): string = - ## Returns contents of the `SERVER_SIGNATURE` environment variable. - return getEnv("SERVER_SIGNATURE") + ## returns contents of the ``SERVER_SIGNATURE`` environment variable + return getEnv("SERVER_SIGNATURE").string proc getServerSoftware*(): string = - ## Returns contents of the `SERVER_SOFTWARE` environment variable. - return getEnv("SERVER_SOFTWARE") + ## returns contents of the ``SERVER_SOFTWARE`` environment variable + return getEnv("SERVER_SOFTWARE").string proc setTestData*(keysvalues: varargs[string]) = - ## Fills the appropriate environment variables to test your CGI application. + ## fills the appropriate environment variables to test your CGI application. ## This can only simulate the 'GET' request method. `keysvalues` should ## provide embedded (name, value)-pairs. Example: - ## ```Nim - ## setTestData("name", "Hanz", "password", "12345") - ## ``` + ## + ## .. code-block:: Nim + ## setTestData("name", "Hanz", "password", "12345") putEnv("REQUEST_METHOD", "GET") var i = 0 var query = "" @@ -267,11 +309,11 @@ proc setTestData*(keysvalues: varargs[string]) = putEnv("QUERY_STRING", query) proc writeContentType*() = - ## Calls this before starting to send your HTML data to `stdout`. This + ## call this before starting to send your HTML data to `stdout`. This ## implements this part of the CGI protocol: - ## ```Nim - ## write(stdout, "Content-type: text/html\n\n") - ## ``` + ## + ## .. code-block:: Nim + ## write(stdout, "Content-type: text/html\n\n") write(stdout, "Content-type: text/html\n\n") proc resetForStacktrace() = @@ -304,10 +346,10 @@ proc setCookie*(name, value: string) = var gcookies {.threadvar.}: StringTableRef -proc getCookie*(name: string): string = +proc getCookie*(name: string): TaintedString = ## Gets a cookie. If no cookie of `name` exists, "" is returned. if gcookies == nil: gcookies = parseCookies(getHttpCookie()) - result = gcookies.getOrDefault(name) + result = TaintedString(gcookies.getOrDefault(name)) proc existsCookie*(name: string): bool = ## Checks if a cookie of `name` exists. diff --git a/lib/pure/collections/critbits.nim b/lib/pure/collections/critbits.nim index 24257dacb..a28bb447c 100644 --- a/lib/pure/collections/critbits.nim +++ b/lib/pure/collections/critbits.nim @@ -8,36 +8,11 @@ # ## This module implements a `crit bit tree`:idx: which is an efficient -## container for a sorted set of strings, or for a sorted mapping of strings. Based on the -## [excellent paper by Adam Langley](https://www.imperialviolet.org/binary/critbit.pdf). +## container for a sorted set of strings, or for a sorted mapping of strings. Based on the excellent paper +## by Adam Langley. ## (A crit bit tree is a form of `radix tree`:idx: or `patricia trie`:idx:.) -runnableExamples: - from std/sequtils import toSeq - - var critbitAsSet: CritBitTree[void] = ["kitten", "puppy"].toCritBitTree - doAssert critbitAsSet.len == 2 - critbitAsSet.incl("") - doAssert "" in critbitAsSet - critbitAsSet.excl("") - doAssert "" notin critbitAsSet - doAssert toSeq(critbitAsSet.items) == @["kitten", "puppy"] - let same = ["puppy", "kitten", "puppy"].toCritBitTree - doAssert toSeq(same.keys) == toSeq(critbitAsSet.keys) - - var critbitAsDict: CritBitTree[int] = {"key1": 42}.toCritBitTree - doAssert critbitAsDict.len == 1 - critbitAsDict["key2"] = 0 - doAssert "key2" in critbitAsDict - doAssert critbitAsDict["key2"] == 0 - critbitAsDict.excl("key1") - doAssert "key1" notin critbitAsDict - doAssert toSeq(critbitAsDict.pairs) == @[("key2", 0)] - -import std/private/since - -when defined(nimPreviewSlimSystem): - import std/assertions +include "system/inclrtl" type NodeObj[T] {.acyclic.} = object @@ -53,17 +28,13 @@ type Node[T] = ref NodeObj[T] CritBitTree*[T] = object ## The crit bit tree can either be used ## as a mapping from strings to - ## some type `T` or as a set of - ## strings if `T` is `void`. + ## some type ``T`` or as a set of + ## strings if ``T`` is void. root: Node[T] count: int -func len*[T](c: CritBitTree[T]): int {.inline.} = - ## Returns the number of elements in `c` in O(1). - runnableExamples: - let c = ["key1", "key2"].toCritBitTree - doAssert c.len == 2 - +proc len*[T](c: CritBitTree[T]): int = + ## returns the number of elements in `c` in O(1). result = c.count proc rawGet[T](c: CritBitTree[T], key: string): Node[T] = @@ -76,17 +47,12 @@ proc rawGet[T](c: CritBitTree[T], key: string): Node[T] = else: return if it.key == key: it else: nil -func contains*[T](c: CritBitTree[T], key: string): bool {.inline.} = - ## Returns true if `c` contains the given `key`. - runnableExamples: - var c: CritBitTree[void] - incl(c, "key") - doAssert c.contains("key") - +proc contains*[T](c: CritBitTree[T], key: string): bool {.inline.} = + ## returns true iff `c` contains the given `key`. result = rawGet(c, key) != nil -func hasKey*[T](c: CritBitTree[T], key: string): bool {.inline.} = - ## Alias for `contains <#contains,CritBitTree[T],string>`_. +proc hasKey*[T](c: CritBitTree[T], key: string): bool {.inline.} = + ## alias for `contains`. result = rawGet(c, key) != nil proc rawInsert[T](c: var CritBitTree[T], key: string): Node[T] = @@ -139,7 +105,7 @@ proc rawInsert[T](c: var CritBitTree[T], key: string): Node[T] = wherep[] = inner inc c.count -func exclImpl[T](c: var CritBitTree[T], key: string): int = +proc exclImpl[T](c: var CritBitTree[T], key: string): int = var p = c.root var wherep = addr(c.root) var whereq: ptr Node[T] = nil @@ -164,62 +130,20 @@ func exclImpl[T](c: var CritBitTree[T], key: string): int = return c.count proc excl*[T](c: var CritBitTree[T], key: string) = - ## Removes `key` (and its associated value) from the set `c`. + ## removes `key` (and its associated value) from the set `c`. ## If the `key` does not exist, nothing happens. - ## - ## **See also:** - ## * `incl proc <#incl,CritBitTree[void],string>`_ - ## * `incl proc <#incl,CritBitTree[T],string,T>`_ - runnableExamples: - var c: CritBitTree[void] - incl(c, "key") - excl(c, "key") - doAssert not c.contains("key") - discard exclImpl(c, key) proc missingOrExcl*[T](c: var CritBitTree[T], key: string): bool = - ## Returns true if `c` does not contain the given `key`. If the key - ## does exist, `c.excl(key)` is performed. - ## - ## **See also:** - ## * `excl proc <#excl,CritBitTree[T],string>`_ - ## * `containsOrIncl proc <#containsOrIncl,CritBitTree[T],string,T>`_ - ## * `containsOrIncl proc <#containsOrIncl,CritBitTree[void],string>`_ - runnableExamples: - block: - var c: CritBitTree[void] - doAssert c.missingOrExcl("key") - block: - var c: CritBitTree[void] - incl(c, "key") - doAssert not c.missingOrExcl("key") - doAssert not c.contains("key") - + ## Returns true iff `c` does not contain the given `key`. If the key + ## does exist, c.excl(key) is performed. let oldCount = c.count discard exclImpl(c, key) result = c.count == oldCount -proc containsOrIncl*[T](c: var CritBitTree[T], key: string, val: sink T): bool = - ## Returns true if `c` contains the given `key`. If the key does not exist, - ## `c[key] = val` is performed. - ## - ## **See also:** - ## * `incl proc <#incl,CritBitTree[void],string>`_ - ## * `incl proc <#incl,CritBitTree[T],string,T>`_ - ## * `containsOrIncl proc <#containsOrIncl,CritBitTree[void],string>`_ - ## * `missingOrExcl proc <#missingOrExcl,CritBitTree[T],string>`_ - runnableExamples: - block: - var c: CritBitTree[int] - doAssert not c.containsOrIncl("key", 42) - doAssert c.contains("key") - block: - var c: CritBitTree[int] - incl(c, "key", 21) - doAssert c.containsOrIncl("key", 42) - doAssert c["key"] == 21 - +proc containsOrIncl*[T](c: var CritBitTree[T], key: string, val: T): bool = + ## returns true iff `c` contains the given `key`. If the key does not exist + ## ``c[key] = val`` is performed. let oldCount = c.count var n = rawInsert(c, key) result = c.count == oldCount @@ -227,99 +151,50 @@ proc containsOrIncl*[T](c: var CritBitTree[T], key: string, val: sink T): bool = if not result: n.val = val proc containsOrIncl*(c: var CritBitTree[void], key: string): bool = - ## Returns true if `c` contains the given `key`. If the key does not exist, + ## returns true iff `c` contains the given `key`. If the key does not exist ## it is inserted into `c`. - ## - ## **See also:** - ## * `incl proc <#incl,CritBitTree[void],string>`_ - ## * `incl proc <#incl,CritBitTree[T],string,T>`_ - ## * `containsOrIncl proc <#containsOrIncl,CritBitTree[T],string,T>`_ - ## * `missingOrExcl proc <#missingOrExcl,CritBitTree[T],string>`_ - runnableExamples: - block: - var c: CritBitTree[void] - doAssert not c.containsOrIncl("key") - doAssert c.contains("key") - block: - var c: CritBitTree[void] - incl(c, "key") - doAssert c.containsOrIncl("key") - let oldCount = c.count discard rawInsert(c, key) result = c.count == oldCount proc inc*(c: var CritBitTree[int]; key: string, val: int = 1) = - ## Increments `c[key]` by `val`. - runnableExamples: - var c: CritBitTree[int] - c["key"] = 1 - inc(c, "key") - doAssert c["key"] == 2 - + ## increments `c[key]` by `val`. var n = rawInsert(c, key) inc n.val, val proc incl*(c: var CritBitTree[void], key: string) = - ## Includes `key` in `c`. - ## - ## **See also:** - ## * `excl proc <#excl,CritBitTree[T],string>`_ - ## * `incl proc <#incl,CritBitTree[T],string,T>`_ - runnableExamples: - var c: CritBitTree[void] - incl(c, "key") - doAssert c.hasKey("key") - + ## includes `key` in `c`. discard rawInsert(c, key) -proc incl*[T](c: var CritBitTree[T], key: string, val: sink T) = - ## Inserts `key` with value `val` into `c`. - ## - ## **See also:** - ## * `excl proc <#excl,CritBitTree[T],string>`_ - ## * `incl proc <#incl,CritBitTree[void],string>`_ - runnableExamples: - var c: CritBitTree[int] - incl(c, "key", 42) - doAssert c["key"] == 42 - +proc incl*[T](c: var CritBitTree[T], key: string, val: T) = + ## inserts `key` with value `val` into `c`. var n = rawInsert(c, key) n.val = val -proc `[]=`*[T](c: var CritBitTree[T], key: string, val: sink T) = - ## Alias for `incl <#incl,CritBitTree[T],string,T>`_. - ## - ## **See also:** - ## * `[] proc <#[],CritBitTree[T],string>`_ - ## * `[] proc <#[],CritBitTree[T],string_2>`_ +proc `[]=`*[T](c: var CritBitTree[T], key: string, val: T) = + ## puts a (key, value)-pair into `t`. var n = rawInsert(c, key) n.val = val template get[T](c: CritBitTree[T], key: string): T = let n = rawGet(c, key) if n == nil: - raise newException(KeyError, "key not found: " & key) + when compiles($key): + raise newException(KeyError, "key not found: " & $key) + else: + raise newException(KeyError, "key not found") n.val -func `[]`*[T](c: CritBitTree[T], key: string): lent T {.inline.} = - ## Retrieves the value at `c[key]`. If `key` is not in `t`, the - ## `KeyError` exception is raised. One can check with `hasKey` whether +proc `[]`*[T](c: CritBitTree[T], key: string): T {.inline.} = + ## retrieves the value at ``c[key]``. If `key` is not in `t`, the + ## ``KeyError`` exception is raised. One can check with ``hasKey`` whether ## the key exists. - ## - ## **See also:** - ## * `[] proc <#[],CritBitTree[T],string_2>`_ - ## * `[]= proc <#[]=,CritBitTree[T],string,T>`_ get(c, key) -func `[]`*[T](c: var CritBitTree[T], key: string): var T {.inline.} = - ## Retrieves the value at `c[key]`. The value can be modified. - ## If `key` is not in `t`, the `KeyError` exception is raised. - ## - ## **See also:** - ## * `[] proc <#[],CritBitTree[T],string>`_ - ## * `[]= proc <#[]=,CritBitTree[T],string,T>`_ +proc `[]`*[T](c: var CritBitTree[T], key: string): var T {.inline.} = + ## retrieves the value at ``c[key]``. The value can be modified. + ## If `key` is not in `t`, the ``KeyError`` exception is raised. get(c, key) iterator leaves[T](n: Node[T]): Node[T] = @@ -336,64 +211,33 @@ iterator leaves[T](n: Node[T]): Node[T] = yield it iterator keys*[T](c: CritBitTree[T]): string = - ## Yields all keys in lexicographical order. - runnableExamples: - from std/sequtils import toSeq - - let c = {"key1": 1, "key2": 2}.toCritBitTree - doAssert toSeq(c.keys) == @["key1", "key2"] - + ## yields all keys in lexicographical order. for x in leaves(c.root): yield x.key -iterator values*[T](c: CritBitTree[T]): lent T = - ## Yields all values of `c` in the lexicographical order of the +iterator values*[T](c: CritBitTree[T]): T = + ## yields all values of `c` in the lexicographical order of the ## corresponding keys. - ## - ## **See also:** - ## * `mvalues iterator <#mvalues.i,CritBitTree[T]>`_ - runnableExamples: - from std/sequtils import toSeq - - let c = {"key1": 1, "key2": 2}.toCritBitTree - doAssert toSeq(c.values) == @[1, 2] - for x in leaves(c.root): yield x.val iterator mvalues*[T](c: var CritBitTree[T]): var T = - ## Yields all values of `c` in the lexicographical order of the + ## yields all values of `c` in the lexicographical order of the ## corresponding keys. The values can be modified. - ## - ## **See also:** - ## * `values iterator <#values.i,CritBitTree[T]>`_ for x in leaves(c.root): yield x.val iterator items*[T](c: CritBitTree[T]): string = - ## Alias for `keys <#keys.i,CritBitTree[T]>`_. + ## yields all keys in lexicographical order. for x in leaves(c.root): yield x.key iterator pairs*[T](c: CritBitTree[T]): tuple[key: string, val: T] = - ## Yields all `(key, value)`-pairs of `c` in the lexicographical order of the - ## corresponding keys. - ## - ## **See also:** - ## * `mpairs iterator <#mpairs.i,CritBitTree[T]>`_ - runnableExamples: - from std/sequtils import toSeq - - let c = {"key1": 1, "key2": 2}.toCritBitTree - doAssert toSeq(c.pairs) == @[(key: "key1", val: 1), (key: "key2", val: 2)] - + ## yields all (key, value)-pairs of `c`. for x in leaves(c.root): yield (x.key, x.val) iterator mpairs*[T](c: var CritBitTree[T]): tuple[key: string, val: var T] = - ## Yields all `(key, value)`-pairs of `c` in the lexicographical order of the - ## corresponding keys. The yielded values can be modified. - ## - ## **See also:** - ## * `pairs iterator <#pairs.i,CritBitTree[T]>`_ + ## yields all (key, value)-pairs of `c`. The yielded values can be modified. for x in leaves(c.root): yield (x.key, x.val) -proc allprefixedAux[T](c: CritBitTree[T], key: string): Node[T] = +proc allprefixedAux[T](c: CritBitTree[T], key: string; + longestMatch: bool): Node[T] = var p = c.root var top = p if p != nil: @@ -403,83 +247,58 @@ proc allprefixedAux[T](c: CritBitTree[T], key: string): Node[T] = let dir = (1 + (ch.ord or p.otherBits.ord)) shr 8 p = p.child[dir] if q.byte < key.len: top = p - for i in 0 ..< key.len: - if i >= p.key.len or p.key[i] != key[i]: return + if not longestMatch: + for i in 0 ..< key.len: + if i >= p.key.len or p.key[i] != key[i]: return result = top -iterator keysWithPrefix*[T](c: CritBitTree[T], prefix: string): string = - ## Yields all keys starting with `prefix`. - runnableExamples: - from std/sequtils import toSeq - - let c = {"key1": 42, "key2": 43}.toCritBitTree - doAssert toSeq(c.keysWithPrefix("key")) == @["key1", "key2"] - - let top = allprefixedAux(c, prefix) +iterator itemsWithPrefix*[T](c: CritBitTree[T], prefix: string; + longestMatch = false): string = + ## yields all keys starting with `prefix`. If `longestMatch` is true, + ## the longest match is returned, it doesn't have to be a complete match then. + let top = allprefixedAux(c, prefix, longestMatch) for x in leaves(top): yield x.key -iterator valuesWithPrefix*[T](c: CritBitTree[T], prefix: string): lent T = - ## Yields all values of `c` starting with `prefix` of the +iterator keysWithPrefix*[T](c: CritBitTree[T], prefix: string; + longestMatch = false): string = + ## yields all keys starting with `prefix`. + let top = allprefixedAux(c, prefix, longestMatch) + for x in leaves(top): yield x.key + +iterator valuesWithPrefix*[T](c: CritBitTree[T], prefix: string; + longestMatch = false): T = + ## yields all values of `c` starting with `prefix` of the ## corresponding keys. - ## - ## **See also:** - ## * `mvaluesWithPrefix iterator <#mvaluesWithPrefix.i,CritBitTree[T],string>`_ - runnableExamples: - from std/sequtils import toSeq - - let c = {"key1": 42, "key2": 43}.toCritBitTree - doAssert toSeq(c.valuesWithPrefix("key")) == @[42, 43] - - let top = allprefixedAux(c, prefix) + let top = allprefixedAux(c, prefix, longestMatch) for x in leaves(top): yield x.val -iterator mvaluesWithPrefix*[T](c: var CritBitTree[T], prefix: string): var T = - ## Yields all values of `c` starting with `prefix` of the +iterator mvaluesWithPrefix*[T](c: var CritBitTree[T], prefix: string; + longestMatch = false): var T = + ## yields all values of `c` starting with `prefix` of the ## corresponding keys. The values can be modified. - ## - ## **See also:** - ## * `valuesWithPrefix iterator <#valuesWithPrefix.i,CritBitTree[T],string>`_ - let top = allprefixedAux(c, prefix) + let top = allprefixedAux(c, prefix, longestMatch) for x in leaves(top): yield x.val -iterator itemsWithPrefix*[T](c: CritBitTree[T], prefix: string): string = - ## Alias for `keysWithPrefix <#keysWithPrefix.i,CritBitTree[T],string>`_. - let top = allprefixedAux(c, prefix) - for x in leaves(top): yield x.key - iterator pairsWithPrefix*[T](c: CritBitTree[T], - prefix: string): tuple[key: string, val: T] = - ## Yields all (key, value)-pairs of `c` starting with `prefix`. - ## - ## **See also:** - ## * `mpairsWithPrefix iterator <#mpairsWithPrefix.i,CritBitTree[T],string>`_ - runnableExamples: - from std/sequtils import toSeq - - let c = {"key1": 42, "key2": 43}.toCritBitTree - doAssert toSeq(c.pairsWithPrefix("key")) == @[(key: "key1", val: 42), (key: "key2", val: 43)] - - let top = allprefixedAux(c, prefix) + prefix: string; + longestMatch = false): tuple[key: string, val: T] = + ## yields all (key, value)-pairs of `c` starting with `prefix`. + let top = allprefixedAux(c, prefix, longestMatch) for x in leaves(top): yield (x.key, x.val) iterator mpairsWithPrefix*[T](c: var CritBitTree[T], - prefix: string): tuple[key: string, val: var T] = - ## Yields all (key, value)-pairs of `c` starting with `prefix`. + prefix: string; + longestMatch = false): tuple[key: string, val: var T] = + ## yields all (key, value)-pairs of `c` starting with `prefix`. ## The yielded values can be modified. - ## - ## **See also:** - ## * `pairsWithPrefix iterator <#pairsWithPrefix.i,CritBitTree[T],string>`_ - let top = allprefixedAux(c, prefix) + let top = allprefixedAux(c, prefix, longestMatch) for x in leaves(top): yield (x.key, x.val) -func `$`*[T](c: CritBitTree[T]): string = - ## Turns `c` into a string representation. - runnableExamples: - doAssert $CritBitTree[int].default == "{:}" - doAssert $toCritBitTree({"key1": 1, "key2": 2}) == """{"key1": 1, "key2": 2}""" - doAssert $CritBitTree[void].default == "{}" - doAssert $toCritBitTree(["key1", "key2"]) == """{"key1", "key2"}""" - +proc `$`*[T](c: CritBitTree[T]): string = + ## turns `c` into a string representation. Example outputs: + ## ``{keyA: value, keyB: value}``, ``{:}`` + ## If `T` is void the outputs look like: + ## ``{keyA, keyB}``, ``{}``. if c.len == 0: when T is void: result = "{}" @@ -505,33 +324,64 @@ func `$`*[T](c: CritBitTree[T]): string = result.addQuoted(val) result.add("}") -func commonPrefixLen*[T](c: CritBitTree[T]): int {.inline, since((1, 3)).} = - ## Returns the length of the longest common prefix of all keys in `c`. - ## If `c` is empty, returns 0. - runnableExamples: - var c: CritBitTree[void] - doAssert c.commonPrefixLen == 0 - incl(c, "key1") - doAssert c.commonPrefixLen == 4 - incl(c, "key2") - doAssert c.commonPrefixLen == 3 +when isMainModule: + import sequtils - if c.root != nil: - if c.root.isLeaf: len(c.root.key) - else: c.root.byte - else: 0 + var r: CritBitTree[void] + r.incl "abc" + r.incl "xyz" + r.incl "def" + r.incl "definition" + r.incl "prefix" + r.incl "foo" -proc toCritBitTree*[T](pairs: sink openArray[(string, T)]): CritBitTree[T] {.since: (1, 3).} = - ## Creates a new `CritBitTree` that contains the given `pairs`. - runnableExamples: - doAssert {"a": "0", "b": "1", "c": "2"}.toCritBitTree is CritBitTree[string] - doAssert {"a": 0, "b": 1, "c": 2}.toCritBitTree is CritBitTree[int] + doAssert r.contains"def" - for item in pairs: result.incl item[0], item[1] + r.excl "def" + assert r.missingOrExcl("foo") == false + assert "foo" notin toSeq(r.items) -proc toCritBitTree*(items: sink openArray[string]): CritBitTree[void] {.since: (1, 3).} = - ## Creates a new `CritBitTree` that contains the given `items`. - runnableExamples: - doAssert ["a", "b", "c"].toCritBitTree is CritBitTree[void] + assert r.missingOrExcl("foo") == true - for item in items: result.incl item + assert toSeq(r.items) == @["abc", "definition", "prefix", "xyz"] + + assert toSeq(r.itemsWithPrefix("de")) == @["definition"] + var c = CritBitTree[int]() + + c.inc("a") + assert c["a"] == 1 + + c.inc("a", 4) + assert c["a"] == 5 + + c.inc("a", -5) + assert c["a"] == 0 + + c.inc("b", 2) + assert c["b"] == 2 + + c.inc("c", 3) + assert c["c"] == 3 + + c.inc("a", 1) + assert c["a"] == 1 + + var cf = CritBitTree[float]() + + cf.incl("a", 1.0) + assert cf["a"] == 1.0 + + cf.incl("b", 2.0) + assert cf["b"] == 2.0 + + cf.incl("c", 3.0) + assert cf["c"] == 3.0 + + assert cf.len == 3 + cf.excl("c") + assert cf.len == 2 + + var cb: CritBitTree[string] + cb.incl("help", "help") + for k in cb.keysWithPrefix("helpp"): + doAssert false, "there is no prefix helpp" diff --git a/lib/pure/collections/deques.nim b/lib/pure/collections/deques.nim index 60e0fd351..1aa525bd6 100644 --- a/lib/pure/collections/deques.nim +++ b/lib/pure/collections/deques.nim @@ -7,57 +7,58 @@ # distribution, for details about the copyright. # -## An implementation of a `deque`:idx: (double-ended queue). -## The underlying implementation uses a `seq`. +## Implementation of a `deque`:idx: (double-ended queue). +## The underlying implementation uses a ``seq``. ## -## .. note:: None of the procs that get an individual value from the deque should be used -## on an empty deque. -## -## If compiled with the `boundChecks` option, those procs will raise an `IndexDefect` -## on such access. This should not be relied upon, as `-d:danger` or `--checks:off` will -## disable those checks and then the procs may return garbage or crash the program. +## None of the procs that get an individual value from the deque can be used +## on an empty deque. +## If compiled with `boundChecks` option, those procs will raise an `IndexError` +## on such access. This should not be relied upon, as `-d:release` will +## disable those checks and may return garbage or crash the program. ## ## As such, a check to see if the deque is empty is needed before any ## access, unless your program logic guarantees it indirectly. - -runnableExamples: - var a = [10, 20, 30, 40].toDeque - - doAssertRaises(IndexDefect, echo a[4]) - - a.addLast(50) - assert $a == "[10, 20, 30, 40, 50]" - - assert a.peekFirst == 10 - assert a.peekLast == 50 - assert len(a) == 5 - - assert a.popFirst == 10 - assert a.popLast == 50 - assert len(a) == 3 - - a.addFirst(11) - a.addFirst(22) - a.addFirst(33) - assert $a == "[33, 22, 11, 20, 30, 40]" - - a.shrink(fromFirst = 1, fromLast = 2) - assert $a == "[22, 11, 20]" - -## See also -## ======== +## +## .. code-block:: Nim +## import deques +## +## var a = initDeque[int]() +## +## doAssertRaises(IndexError, echo a[0]) +## +## for i in 1 .. 5: +## a.addLast(10*i) +## assert $a == "[10, 20, 30, 40, 50]" +## +## assert a.peekFirst == 10 +## assert a.peekLast == 50 +## assert len(a) == 5 +## +## assert a.popFirst == 10 +## assert a.popLast == 50 +## assert len(a) == 3 +## +## a.addFirst(11) +## a.addFirst(22) +## a.addFirst(33) +## assert $a == "[33, 22, 11, 20, 30, 40]" +## +## a.shrink(fromFirst = 1, fromLast = 2) +## assert $a == "[22, 11, 20]" +## +## +## **See also:** ## * `lists module `_ for singly and doubly linked lists and rings +## * `channels module `_ for inter-thread communication -import std/private/since import math type Deque*[T] = object - ## A double-ended queue backed with a ringed `seq` buffer. + ## A double-ended queue backed with a ringed seq buffer. ## - ## To initialize an empty deque, - ## use the `initDeque proc <#initDeque,int>`_. + ## To initialize an empty deque use `initDeque proc <#initDeque,int>`_. data: seq[T] head, tail, count, mask: int @@ -65,73 +66,81 @@ const defaultInitialSize* = 4 template initImpl(result: typed, initialSize: int) = - let correctSize = nextPowerOfTwo(initialSize) - result.mask = correctSize - 1 - newSeq(result.data, correctSize) - + assert isPowerOfTwo(initialSize) + result.mask = initialSize-1 + newSeq(result.data, initialSize) + template checkIfInitialized(deq: typed) = when compiles(defaultInitialSize): if deq.mask == 0: initImpl(deq, defaultInitialSize) -proc initDeque*[T](initialSize: int = defaultInitialSize): Deque[T] = - ## Creates a new empty deque. +proc initDeque*[T](initialSize: int = 4): Deque[T] = + ## Create a new empty deque. ## ## Optionally, the initial capacity can be reserved via `initialSize` - ## as a performance optimization - ## (default: `defaultInitialSize <#defaultInitialSize>`_). + ## as a performance optimization. ## The length of a newly created deque will still be 0. ## - ## **See also:** - ## * `toDeque proc <#toDeque,openArray[T]>`_ + ## ``initialSize`` must be a power of two (default: 4). + ## If you need to accept runtime values for this you could use the + ## `nextPowerOfTwo proc`_ from the + ## `math module`_. result.initImpl(initialSize) proc len*[T](deq: Deque[T]): int {.inline.} = - ## Returns the number of elements of `deq`. + ## Return the number of elements of `deq`. result = deq.count template emptyCheck(deq) = # Bounds check for the regular deque access. when compileOption("boundChecks"): if unlikely(deq.count < 1): - raise newException(IndexDefect, "Empty deque.") + raise newException(IndexError, "Empty deque.") template xBoundsCheck(deq, i) = # Bounds check for the array like accesses. - when compileOption("boundChecks"): # `-d:danger` or `--checks:off` should disable this. + when compileOption("boundChecks"): # d:release should disable this. if unlikely(i >= deq.count): # x < deq.low is taken care by the Natural parameter - raise newException(IndexDefect, + raise newException(IndexError, "Out of bounds: " & $i & " > " & $(deq.count - 1)) if unlikely(i < 0): # when used with BackwardsIndex - raise newException(IndexDefect, + raise newException(IndexError, "Out of bounds: " & $i & " < 0") -proc `[]`*[T](deq: Deque[T], i: Natural): lent T {.inline.} = - ## Accesses the `i`-th element of `deq`. +proc `[]`*[T](deq: Deque[T], i: Natural): T {.inline.} = + ## Access the i-th element of `deq`. runnableExamples: - let a = [10, 20, 30, 40, 50].toDeque + var a = initDeque[int]() + for i in 1 .. 5: + a.addLast(10*i) assert a[0] == 10 assert a[3] == 40 - doAssertRaises(IndexDefect, echo a[8]) + doAssertRaises(IndexError, echo a[8]) xBoundsCheck(deq, i) return deq.data[(deq.head + i) and deq.mask] proc `[]`*[T](deq: var Deque[T], i: Natural): var T {.inline.} = - ## Accesses the `i`-th element of `deq` and returns a mutable + ## Access the i-th element of `deq` and return a mutable ## reference to it. runnableExamples: - var a = [10, 20, 30, 40, 50].toDeque - inc(a[0]) - assert a[0] == 11 + var a = initDeque[int]() + for i in 1 .. 5: + a.addLast(10*i) + assert a[0] == 10 + assert a[3] == 40 + doAssertRaises(IndexError, echo a[8]) xBoundsCheck(deq, i) return deq.data[(deq.head + i) and deq.mask] -proc `[]=`*[T](deq: var Deque[T], i: Natural, val: sink T) {.inline.} = - ## Sets the `i`-th element of `deq` to `val`. +proc `[]=`*[T](deq: var Deque[T], i: Natural, val: T) {.inline.} = + ## Change the i-th element of `deq`. runnableExamples: - var a = [10, 20, 30, 40, 50].toDeque + var a = initDeque[int]() + for i in 1 .. 5: + a.addLast(10*i) a[0] = 99 a[3] = 66 assert $a == "[99, 20, 30, 66, 50]" @@ -140,38 +149,44 @@ proc `[]=`*[T](deq: var Deque[T], i: Natural, val: sink T) {.inline.} = xBoundsCheck(deq, i) deq.data[(deq.head + i) and deq.mask] = val -proc `[]`*[T](deq: Deque[T], i: BackwardsIndex): lent T {.inline.} = - ## Accesses the backwards indexed `i`-th element. +proc `[]`*[T](deq: Deque[T], i: BackwardsIndex): T {.inline.} = + ## Access the backwards indexed i-th element. ## ## `deq[^1]` is the last element. runnableExamples: - let a = [10, 20, 30, 40, 50].toDeque + var a = initDeque[int]() + for i in 1 .. 5: + a.addLast(10*i) assert a[^1] == 50 assert a[^4] == 20 - doAssertRaises(IndexDefect, echo a[^9]) + doAssertRaises(IndexError, echo a[^9]) xBoundsCheck(deq, deq.len - int(i)) return deq[deq.len - int(i)] proc `[]`*[T](deq: var Deque[T], i: BackwardsIndex): var T {.inline.} = - ## Accesses the backwards indexed `i`-th element and returns a mutable - ## reference to it. + ## Access the backwards indexed i-th element. ## ## `deq[^1]` is the last element. runnableExamples: - var a = [10, 20, 30, 40, 50].toDeque - inc(a[^1]) - assert a[^1] == 51 + var a = initDeque[int]() + for i in 1 .. 5: + a.addLast(10*i) + assert a[^1] == 50 + assert a[^4] == 20 + doAssertRaises(IndexError, echo a[^9]) xBoundsCheck(deq, deq.len - int(i)) return deq[deq.len - int(i)] -proc `[]=`*[T](deq: var Deque[T], i: BackwardsIndex, x: sink T) {.inline.} = - ## Sets the backwards indexed `i`-th element of `deq` to `x`. +proc `[]=`*[T](deq: var Deque[T], i: BackwardsIndex, x: T) {.inline.} = + ## Change the backwards indexed i-th element. ## ## `deq[^1]` is the last element. runnableExamples: - var a = [10, 20, 30, 40, 50].toDeque + var a = initDeque[int]() + for i in 1 .. 5: + a.addLast(10*i) a[^1] = 99 a[^3] = 77 assert $a == "[10, 20, 77, 40, 99]" @@ -180,32 +195,37 @@ proc `[]=`*[T](deq: var Deque[T], i: BackwardsIndex, x: sink T) {.inline.} = xBoundsCheck(deq, deq.len - int(i)) deq[deq.len - int(i)] = x -iterator items*[T](deq: Deque[T]): lent T = - ## Yields every element of `deq`. +iterator items*[T](deq: Deque[T]): T = + ## Yield every element of `deq`. + ## + ## **Examples:** + ## + ## .. code-block:: + ## var a = initDeque[int]() + ## for i in 1 .. 3: + ## a.addLast(10*i) + ## + ## for x in a: # the same as: for x in items(a): + ## echo x + ## + ## # 10 + ## # 20 + ## # 30 ## - ## **See also:** - ## * `mitems iterator <#mitems.i,Deque[T]>`_ - runnableExamples: - from std/sequtils import toSeq - - let a = [10, 20, 30, 40, 50].toDeque - assert toSeq(a.items) == @[10, 20, 30, 40, 50] - var i = deq.head for c in 0 ..< deq.count: yield deq.data[i] i = (i + 1) and deq.mask iterator mitems*[T](deq: var Deque[T]): var T = - ## Yields every element of `deq`, which can be modified. - ## - ## **See also:** - ## * `items iterator <#items.i,Deque[T]>`_ + ## Yield every element of `deq`, which can be modified. runnableExamples: - var a = [10, 20, 30, 40, 50].toDeque + var a = initDeque[int]() + for i in 1 .. 5: + a.addLast(10*i) assert $a == "[10, 20, 30, 40, 50]" for x in mitems(a): - x = 5 * x - 1 + x = 5*x - 1 assert $a == "[49, 99, 149, 199, 249]" var i = deq.head @@ -214,29 +234,36 @@ iterator mitems*[T](deq: var Deque[T]): var T = i = (i + 1) and deq.mask iterator pairs*[T](deq: Deque[T]): tuple[key: int, val: T] = - ## Yields every `(position, value)`-pair of `deq`. - runnableExamples: - from std/sequtils import toSeq - - let a = [10, 20, 30].toDeque - assert toSeq(a.pairs) == @[(0, 10), (1, 20), (2, 30)] - + ## Yield every (position, value) of `deq`. + ## + ## **Examples:** + ## + ## .. code-block:: + ## var a = initDeque[int]() + ## for i in 1 .. 3: + ## a.addLast(10*i) + ## + ## for k, v in pairs(a): + ## echo "key: ", k, ", value: ", v + ## + ## # key: 0, value: 10 + ## # key: 1, value: 20 + ## # key: 2, value: 30 + ## var i = deq.head for c in 0 ..< deq.count: yield (c, deq.data[i]) i = (i + 1) and deq.mask proc contains*[T](deq: Deque[T], item: T): bool {.inline.} = - ## Returns true if `item` is in `deq` or false if not found. + ## Return true if `item` is in `deq` or false if not found. ## - ## Usually used via the `in` operator. - ## It is the equivalent of `deq.find(item) >= 0`. - runnableExamples: - let q = [7, 9].toDeque - assert 7 in q - assert q.contains(7) - assert 8 notin q - + ## Usually used via the ``in`` operator. + ## It is the equivalent of ``deq.find(item) >= 0``. + ## + ## .. code-block:: Nim + ## if x in q: + ## assert q.contains(x) for e in deq: if e == item: return true return false @@ -247,24 +274,27 @@ proc expandIfNeeded[T](deq: var Deque[T]) = if unlikely(deq.count >= cap): var n = newSeq[T](cap * 2) var i = 0 - for x in mitems(deq): - when nimvm: n[i] = x # workaround for VM bug - else: n[i] = move(x) + for x in mitems(deq): # don't use copyMem because of the GC and because it's slower. + n[i] = move(x) inc i deq.data = move(n) deq.mask = cap * 2 - 1 deq.tail = deq.count deq.head = 0 -proc addFirst*[T](deq: var Deque[T], item: sink T) = - ## Adds an `item` to the beginning of `deq`. +proc addFirst*[T](deq: var Deque[T], item: T) = + ## Add an `item` to the beginning of the `deq`. ## - ## **See also:** - ## * `addLast proc <#addLast,Deque[T],sinkT>`_ + ## See also: + ## * `addLast proc <#addLast,Deque[T],T>`_ + ## * `peekFirst proc <#peekFirst,Deque[T]>`_ + ## * `peekLast proc <#peekLast,Deque[T]>`_ + ## * `popFirst proc <#popFirst,Deque[T]>`_ + ## * `popLast proc <#popLast,Deque[T]>`_ runnableExamples: var a = initDeque[int]() for i in 1 .. 5: - a.addFirst(10 * i) + a.addFirst(10*i) assert $a == "[50, 40, 30, 20, 10]" expandIfNeeded(deq) @@ -272,15 +302,19 @@ proc addFirst*[T](deq: var Deque[T], item: sink T) = deq.head = (deq.head - 1) and deq.mask deq.data[deq.head] = item -proc addLast*[T](deq: var Deque[T], item: sink T) = - ## Adds an `item` to the end of `deq`. +proc addLast*[T](deq: var Deque[T], item: T) = + ## Add an `item` to the end of the `deq`. ## - ## **See also:** - ## * `addFirst proc <#addFirst,Deque[T],sinkT>`_ + ## See also: + ## * `addFirst proc <#addFirst,Deque[T],T>`_ + ## * `peekFirst proc <#peekFirst,Deque[T]>`_ + ## * `peekLast proc <#peekLast,Deque[T]>`_ + ## * `popFirst proc <#popFirst,Deque[T]>`_ + ## * `popLast proc <#popLast,Deque[T]>`_ runnableExamples: var a = initDeque[int]() for i in 1 .. 5: - a.addLast(10 * i) + a.addLast(10*i) assert $a == "[10, 20, 30, 40, 50]" expandIfNeeded(deq) @@ -288,28 +322,19 @@ proc addLast*[T](deq: var Deque[T], item: sink T) = deq.data[deq.tail] = item deq.tail = (deq.tail + 1) and deq.mask -proc toDeque*[T](x: openArray[T]): Deque[T] {.since: (1, 3).} = - ## Creates a new deque that contains the elements of `x` (in the same order). - ## - ## **See also:** - ## * `initDeque proc <#initDeque,int>`_ - runnableExamples: - let a = toDeque([7, 8, 9]) - assert len(a) == 3 - assert $a == "[7, 8, 9]" - - result.initImpl(x.len) - for item in items(x): - result.addLast(item) - -proc peekFirst*[T](deq: Deque[T]): lent T {.inline.} = +proc peekFirst*[T](deq: Deque[T]): T {.inline.} = ## Returns the first element of `deq`, but does not remove it from the deque. ## - ## **See also:** - ## * `peekFirst proc <#peekFirst,Deque[T]_2>`_ which returns a mutable reference + ## See also: + ## * `addFirst proc <#addFirst,Deque[T],T>`_ + ## * `addLast proc <#addLast,Deque[T],T>`_ ## * `peekLast proc <#peekLast,Deque[T]>`_ + ## * `popFirst proc <#popFirst,Deque[T]>`_ + ## * `popLast proc <#popLast,Deque[T]>`_ runnableExamples: - let a = [10, 20, 30, 40, 50].toDeque + var a = initDeque[int]() + for i in 1 .. 5: + a.addLast(10*i) assert $a == "[10, 20, 30, 40, 50]" assert a.peekFirst == 10 assert len(a) == 5 @@ -317,14 +342,19 @@ proc peekFirst*[T](deq: Deque[T]): lent T {.inline.} = emptyCheck(deq) result = deq.data[deq.head] -proc peekLast*[T](deq: Deque[T]): lent T {.inline.} = +proc peekLast*[T](deq: Deque[T]): T {.inline.} = ## Returns the last element of `deq`, but does not remove it from the deque. ## - ## **See also:** - ## * `peekLast proc <#peekLast,Deque[T]_2>`_ which returns a mutable reference + ## See also: + ## * `addFirst proc <#addFirst,Deque[T],T>`_ + ## * `addLast proc <#addLast,Deque[T],T>`_ ## * `peekFirst proc <#peekFirst,Deque[T]>`_ + ## * `popFirst proc <#popFirst,Deque[T]>`_ + ## * `popLast proc <#popLast,Deque[T]>`_ runnableExamples: - let a = [10, 20, 30, 40, 50].toDeque + var a = initDeque[int]() + for i in 1 .. 5: + a.addLast(10*i) assert $a == "[10, 20, 30, 40, 50]" assert a.peekLast == 50 assert len(a) == 5 @@ -332,64 +362,49 @@ proc peekLast*[T](deq: Deque[T]): lent T {.inline.} = emptyCheck(deq) result = deq.data[(deq.tail - 1) and deq.mask] -proc peekFirst*[T](deq: var Deque[T]): var T {.inline, since: (1, 3).} = - ## Returns a mutable reference to the first element of `deq`, - ## but does not remove it from the deque. - ## - ## **See also:** - ## * `peekFirst proc <#peekFirst,Deque[T]>`_ - ## * `peekLast proc <#peekLast,Deque[T]_2>`_ - runnableExamples: - var a = [10, 20, 30, 40, 50].toDeque - a.peekFirst() = 99 - assert $a == "[99, 20, 30, 40, 50]" - - emptyCheck(deq) - result = deq.data[deq.head] - -proc peekLast*[T](deq: var Deque[T]): var T {.inline, since: (1, 3).} = - ## Returns a mutable reference to the last element of `deq`, - ## but does not remove it from the deque. - ## - ## **See also:** - ## * `peekFirst proc <#peekFirst,Deque[T]_2>`_ - ## * `peekLast proc <#peekLast,Deque[T]>`_ - runnableExamples: - var a = [10, 20, 30, 40, 50].toDeque - a.peekLast() = 99 - assert $a == "[10, 20, 30, 40, 99]" - - emptyCheck(deq) - result = deq.data[(deq.tail - 1) and deq.mask] - template destroy(x: untyped) = reset(x) proc popFirst*[T](deq: var Deque[T]): T {.inline, discardable.} = - ## Removes and returns the first element of the `deq`. + ## Remove and returns the first element of the `deq`. ## ## See also: + ## * `addFirst proc <#addFirst,Deque[T],T>`_ + ## * `addLast proc <#addLast,Deque[T],T>`_ + ## * `peekFirst proc <#peekFirst,Deque[T]>`_ + ## * `peekLast proc <#peekLast,Deque[T]>`_ ## * `popLast proc <#popLast,Deque[T]>`_ + ## * `clear proc <#clear,Deque[T]>`_ ## * `shrink proc <#shrink,Deque[T],int,int>`_ runnableExamples: - var a = [10, 20, 30, 40, 50].toDeque + var a = initDeque[int]() + for i in 1 .. 5: + a.addLast(10*i) assert $a == "[10, 20, 30, 40, 50]" assert a.popFirst == 10 assert $a == "[20, 30, 40, 50]" emptyCheck(deq) dec deq.count - result = move deq.data[deq.head] + result = deq.data[deq.head] + destroy(deq.data[deq.head]) deq.head = (deq.head + 1) and deq.mask proc popLast*[T](deq: var Deque[T]): T {.inline, discardable.} = - ## Removes and returns the last element of the `deq`. + ## Remove and returns the last element of the `deq`. ## - ## **See also:** + ## See also: + ## * `addFirst proc <#addFirst,Deque[T],T>`_ + ## * `addLast proc <#addLast,Deque[T],T>`_ + ## * `peekFirst proc <#peekFirst,Deque[T]>`_ + ## * `peekLast proc <#peekLast,Deque[T]>`_ ## * `popFirst proc <#popFirst,Deque[T]>`_ + ## * `clear proc <#clear,Deque[T]>`_ ## * `shrink proc <#shrink,Deque[T],int,int>`_ runnableExamples: - var a = [10, 20, 30, 40, 50].toDeque + var a = initDeque[int]() + for i in 1 .. 5: + a.addLast(10*i) assert $a == "[10, 20, 30, 40, 50]" assert a.popLast == 50 assert $a == "[10, 20, 30, 40]" @@ -397,16 +412,20 @@ proc popLast*[T](deq: var Deque[T]): T {.inline, discardable.} = emptyCheck(deq) dec deq.count deq.tail = (deq.tail - 1) and deq.mask - result = move deq.data[deq.tail] + result = deq.data[deq.tail] + destroy(deq.data[deq.tail]) proc clear*[T](deq: var Deque[T]) {.inline.} = ## Resets the deque so that it is empty. ## - ## **See also:** + ## See also: + ## * `clear proc <#clear,Deque[T]>`_ ## * `shrink proc <#shrink,Deque[T],int,int>`_ runnableExamples: - var a = [10, 20, 30, 40, 50].toDeque - assert $a == "[10, 20, 30, 40, 50]" + var a = initDeque[int]() + for i in 1 .. 5: + a.addFirst(10*i) + assert $a == "[50, 40, 30, 20, 10]" clear(a) assert len(a) == 0 @@ -415,21 +434,21 @@ proc clear*[T](deq: var Deque[T]) {.inline.} = deq.tail = deq.head proc shrink*[T](deq: var Deque[T], fromFirst = 0, fromLast = 0) = - ## Removes `fromFirst` elements from the front of the deque and + ## Remove `fromFirst` elements from the front of the deque and ## `fromLast` elements from the back. ## ## If the supplied number of elements exceeds the total number of elements ## in the deque, the deque will remain empty. ## - ## **See also:** + ## See also: ## * `clear proc <#clear,Deque[T]>`_ - ## * `popFirst proc <#popFirst,Deque[T]>`_ - ## * `popLast proc <#popLast,Deque[T]>`_ runnableExamples: - var a = [10, 20, 30, 40, 50].toDeque - assert $a == "[10, 20, 30, 40, 50]" + var a = initDeque[int]() + for i in 1 .. 5: + a.addFirst(10*i) + assert $a == "[50, 40, 30, 20, 10]" a.shrink(fromFirst = 2, fromLast = 1) - assert $a == "[30, 40]" + assert $a == "[30, 20]" if fromFirst + fromLast > deq.count: clear(deq) @@ -440,19 +459,113 @@ proc shrink*[T](deq: var Deque[T], fromFirst = 0, fromLast = 0) = deq.head = (deq.head + 1) and deq.mask for i in 0 ..< fromLast: - destroy(deq.data[(deq.tail - 1) and deq.mask]) + destroy(deq.data[deq.tail]) deq.tail = (deq.tail - 1) and deq.mask dec deq.count, fromFirst + fromLast proc `$`*[T](deq: Deque[T]): string = - ## Turns a deque into its string representation. - runnableExamples: - let a = [10, 20, 30].toDeque - assert $a == "[10, 20, 30]" - + ## Turn a deque into its string representation. result = "[" for x in deq: if result.len > 1: result.add(", ") result.addQuoted(x) result.add("]") + + + +when isMainModule: + var deq = initDeque[int](1) + deq.addLast(4) + deq.addFirst(9) + deq.addFirst(123) + var first = deq.popFirst() + deq.addLast(56) + assert(deq.peekLast() == 56) + deq.addLast(6) + assert(deq.peekLast() == 6) + var second = deq.popFirst() + deq.addLast(789) + assert(deq.peekLast() == 789) + + assert first == 123 + assert second == 9 + assert($deq == "[4, 56, 6, 789]") + + assert deq[0] == deq.peekFirst and deq.peekFirst == 4 + #assert deq[^1] == deq.peekLast and deq.peekLast == 789 + deq[0] = 42 + deq[deq.len - 1] = 7 + + assert 6 in deq and 789 notin deq + assert deq.find(6) >= 0 + assert deq.find(789) < 0 + + block: + var d = initDeque[int](1) + d.addLast 7 + d.addLast 8 + d.addLast 10 + d.addFirst 5 + d.addFirst 2 + d.addFirst 1 + d.addLast 20 + d.shrink(fromLast = 2) + doAssert($d == "[1, 2, 5, 7, 8]") + d.shrink(2, 1) + doAssert($d == "[5, 7]") + d.shrink(2, 2) + doAssert d.len == 0 + + for i in -2 .. 10: + if i in deq: + assert deq.contains(i) and deq.find(i) >= 0 + else: + assert(not deq.contains(i) and deq.find(i) < 0) + + when compileOption("boundChecks"): + try: + echo deq[99] + assert false + except IndexError: + discard + + try: + assert deq.len == 4 + for i in 0 ..< 5: deq.popFirst() + assert false + except IndexError: + discard + + # grabs some types of resize error. + deq = initDeque[int]() + for i in 1 .. 4: deq.addLast i + deq.popFirst() + deq.popLast() + for i in 5 .. 8: deq.addFirst i + assert $deq == "[8, 7, 6, 5, 2, 3]" + + # Similar to proc from the documentation example + proc foo(a, b: Positive) = # assume random positive values for `a` and `b`. + var deq = initDeque[int]() + assert deq.len == 0 + for i in 1 .. a: deq.addLast i + + if b < deq.len: # checking before indexed access. + assert deq[b] == b + 1 + + # The following two lines don't need any checking on access due to the logic + # of the program, but that would not be the case if `a` could be 0. + assert deq.peekFirst == 1 + assert deq.peekLast == a + + while deq.len > 0: # checking if the deque is empty + assert deq.popFirst() > 0 + + #foo(0,0) + foo(8, 5) + foo(10, 9) + foo(1, 1) + foo(2, 1) + foo(1, 5) + foo(3, 2) diff --git a/lib/pure/collections/hashcommon.nim b/lib/pure/collections/hashcommon.nim index 8fd4c6e08..d9a914afc 100644 --- a/lib/pure/collections/hashcommon.nim +++ b/lib/pure/collections/hashcommon.nim @@ -7,17 +7,17 @@ # distribution, for details about the copyright. # -# An `include` file which contains common code for +# An ``include`` file which contains common code for # hash sets and tables. -when defined(nimPreviewSlimSystem): - import std/assertions - -import std / outparams - const growthFactor = 2 +when not defined(nimHasDefault): + template default[T](t: typedesc[T]): T = + var v: T + v + # hcode for real keys cannot be zero. hcode==0 signifies an empty slot. These # two procs retain clarity of that encoding without the space cost of an enum. proc isEmpty(hcode: Hash): bool {.inline.} = @@ -29,14 +29,9 @@ proc isFilled(hcode: Hash): bool {.inline.} = proc nextTry(h, maxHash: Hash): Hash {.inline.} = result = (h + 1) and maxHash -proc mustRehash[T](t: T): bool {.inline.} = - # If this is changed, make sure to synchronize it with `slotsNeeded` below - assert(t.dataLen > t.counter) - result = (t.dataLen * 2 < t.counter * 3) or (t.dataLen - t.counter < 4) - -proc slotsNeeded(count: Natural): int {.inline.} = - # Make sure to synchronize with `mustRehash` above - result = nextPowerOfTwo(count * 3 div 2 + 4) +proc mustRehash(length, counter: int): bool {.inline.} = + assert(length > counter) + result = (length * 2 < counter * 3) or (length - counter < 4) template rawGetKnownHCImpl() {.dirty.} = if t.dataLen == 0: @@ -69,5 +64,5 @@ template rawGetImpl() {.dirty.} = genHashImpl(key, hc) rawGetKnownHCImpl() -proc rawGet[X, A](t: X, key: A, hc: var Hash): int {.inline, outParamsAt: [3].} = +proc rawGet[X, A](t: X, key: A, hc: var Hash): int {.inline.} = rawGetImpl() diff --git a/lib/pure/collections/heapqueue.nim b/lib/pure/collections/heapqueue.nim index 89e532951..f958a5b0a 100644 --- a/lib/pure/collections/heapqueue.nim +++ b/lib/pure/collections/heapqueue.nim @@ -6,81 +6,76 @@ # See the file "copying.txt", included in this # distribution, for details about the copyright. +##[ + The `heapqueue` module implements a + `heap data structure`_ + that can be used as a + `priority queue`_. + Heaps are arrays for which `a[k] <= a[2*k+1]` and `a[k] <= a[2*k+2]` for + all `k`, counting elements from 0. The interesting property of a heap is that + `a[0]` is always its smallest element. -## The `heapqueue` module implements a -## `binary heap data structure`_ -## that can be used as a `priority queue`_. -## They are represented as arrays for which `a[k] <= a[2*k+1]` and `a[k] <= a[2*k+2]` -## for all indices `k` (counting elements from 0). The interesting property of a heap is that -## `a[0]` is always its smallest element. -## -## Basic usage -## ----------- -## -runnableExamples: - var heap = [8, 2].toHeapQueue - heap.push(5) - # the first element is the lowest element - assert heap[0] == 2 - # remove and return the lowest element - assert heap.pop() == 2 - # the lowest element remaining is 5 - assert heap[0] == 5 + Basic usage + ----------- + .. code-block:: Nim + import heapqueue -## Usage with custom objects -## ------------------------- -## To use a `HeapQueue` with a custom object, the `<` operator must be -## implemented. + var heap = initHeapQueue[int]() + heap.push(8) + heap.push(2) + heap.push(5) + # The first element is the lowest element + assert heap[0] == 2 + # Remove and return the lowest element + assert heap.pop() == 2 + # The lowest element remaining is 5 + assert heap[0] == 5 -runnableExamples: - type Job = object - priority: int + Usage with custom object + ------------------------ + To use a `HeapQueue` with a custom object, the `<` operator must be + implemented. - proc `<`(a, b: Job): bool = a.priority < b.priority + .. code-block:: Nim + import heapqueue - var jobs = initHeapQueue[Job]() - jobs.push(Job(priority: 1)) - jobs.push(Job(priority: 2)) + type Job = object + priority: int - assert jobs[0].priority == 1 + proc `<`(a, b: Job): bool = a.priority < b.priority + var jobs = initHeapQueue[Job]() + jobs.push(Job(priority: 1)) + jobs.push(Job(priority: 2)) -import std/private/since + assert jobs[0].priority == 1 +]## type HeapQueue*[T] = object ## A heap queue, commonly known as a priority queue. data: seq[T] proc initHeapQueue*[T](): HeapQueue[T] = - ## Creates a new empty heap. - ## - ## Heaps are initialized by default, so it is not necessary to call - ## this function explicitly. - ## - ## **See also:** - ## * `toHeapQueue proc <#toHeapQueue,openArray[T]>`_ + ## Create a new empty heap. discard proc len*[T](heap: HeapQueue[T]): int {.inline.} = - ## Returns the number of elements of `heap`. - runnableExamples: - let heap = [9, 5, 8].toHeapQueue - assert heap.len == 3 - + ## Return the number of elements of `heap`. heap.data.len -proc `[]`*[T](heap: HeapQueue[T], i: Natural): lent T {.inline.} = - ## Accesses the i-th element of `heap`. +proc `[]`*[T](heap: HeapQueue[T], i: Natural): T {.inline.} = + ## Access the i-th element of `heap`. heap.data[i] -proc heapCmp[T](x, y: T): bool {.inline.} = x < y +proc heapCmp[T](x, y: T): bool {.inline.} = + return (x < y) -proc siftup[T](heap: var HeapQueue[T], startpos, p: int) = - ## `heap` is a heap at all indices >= `startpos`, except possibly for `p`. `p` - ## is the index of a leaf with a possibly out-of-order value. Restores the +proc siftdown[T](heap: var HeapQueue[T], startpos, p: int) = + ## 'heap' is a heap at all indices >= startpos, except possibly for pos. pos + ## is the index of a leaf with a possibly out-of-order value. Restore the ## heap invariant. var pos = p - let newitem = heap[pos] + var newitem = heap[pos] # Follow the path to the root, moving parents down until finding a place # newitem fits. while pos > startpos: @@ -93,14 +88,13 @@ proc siftup[T](heap: var HeapQueue[T], startpos, p: int) = break heap.data[pos] = newitem -proc siftdownToBottom[T](heap: var HeapQueue[T], p: int) = - # This is faster when the element should be close to the bottom. +proc siftup[T](heap: var HeapQueue[T], p: int) = let endpos = len(heap) var pos = p let startpos = pos let newitem = heap[pos] # Bubble up the smaller child until hitting a leaf. - var childpos = 2 * pos + 1 # leftmost child position + var childpos = 2*pos + 1 # leftmost child position while childpos < endpos: # Set childpos to index of smaller child. let rightpos = childpos + 1 @@ -109,143 +103,132 @@ proc siftdownToBottom[T](heap: var HeapQueue[T], p: int) = # Move the smaller child up. heap.data[pos] = heap[childpos] pos = childpos - childpos = 2 * pos + 1 - # The leaf at pos is empty now. Put newitem there, and bubble it up + childpos = 2*pos + 1 + # The leaf at pos is empty now. Put newitem there, and bubble it up # to its final resting place (by sifting its parents down). heap.data[pos] = newitem - siftup(heap, startpos, pos) + siftdown(heap, startpos, pos) -proc siftdown[T](heap: var HeapQueue[T], p: int) = - let endpos = len(heap) - var pos = p - let newitem = heap[pos] - var childpos = 2 * pos + 1 - while childpos < endpos: - let rightpos = childpos + 1 - if rightpos < endpos and not heapCmp(heap[childpos], heap[rightpos]): - childpos = rightpos - if not heapCmp(heap[childpos], newitem): - break - heap.data[pos] = heap[childpos] - pos = childpos - childpos = 2 * pos + 1 - heap.data[pos] = newitem - -proc push*[T](heap: var HeapQueue[T], item: sink T) = - ## Pushes `item` onto `heap`, maintaining the heap invariant. +proc push*[T](heap: var HeapQueue[T], item: T) = + ## Push `item` onto heap, maintaining the heap invariant. heap.data.add(item) - siftup(heap, 0, len(heap) - 1) - -proc toHeapQueue*[T](x: openArray[T]): HeapQueue[T] {.since: (1, 3).} = - ## Creates a new HeapQueue that contains the elements of `x`. - ## - ## **See also:** - ## * `initHeapQueue proc <#initHeapQueue>`_ - runnableExamples: - var heap = [9, 5, 8].toHeapQueue - assert heap.pop() == 5 - assert heap[0] == 8 - - # see https://en.wikipedia.org/wiki/Binary_heap#Building_a_heap - result.data = @x - for i in countdown(x.len div 2 - 1, 0): - siftdown(result, i) + siftdown(heap, 0, len(heap)-1) proc pop*[T](heap: var HeapQueue[T]): T = - ## Pops and returns the smallest item from `heap`, + ## Pop and return the smallest item from `heap`, ## maintaining the heap invariant. - runnableExamples: - var heap = [9, 5, 8].toHeapQueue - assert heap.pop() == 5 - let lastelt = heap.data.pop() if heap.len > 0: result = heap[0] heap.data[0] = lastelt - siftdownToBottom(heap, 0) + siftup(heap, 0) else: result = lastelt -proc find*[T](heap: HeapQueue[T], x: T): int {.since: (1, 3).} = - ## Linear scan to find the index of the item `x` or -1 if not found. - runnableExamples: - let heap = [9, 5, 8].toHeapQueue - assert heap.find(5) == 0 - assert heap.find(9) == 1 - assert heap.find(777) == -1 - - result = -1 - for i in 0 ..< heap.len: - if heap[i] == x: return i - proc del*[T](heap: var HeapQueue[T], index: Natural) = ## Removes the element at `index` from `heap`, maintaining the heap invariant. - runnableExamples: - var heap = [9, 5, 8].toHeapQueue - heap.del(1) - assert heap[0] == 5 - assert heap[1] == 8 - swap(heap.data[^1], heap.data[index]) let newLen = heap.len - 1 heap.data.setLen(newLen) if index < newLen: - siftdownToBottom(heap, index) + heap.siftup(index) -proc replace*[T](heap: var HeapQueue[T], item: sink T): T = - ## Pops and returns the current smallest value, and add the new item. - ## This is more efficient than `pop()` followed by `push()`, and can be +proc replace*[T](heap: var HeapQueue[T], item: T): T = + ## Pop and return the current smallest value, and add the new item. + ## This is more efficient than pop() followed by push(), and can be ## more appropriate when using a fixed-size heap. Note that the value - ## returned may be larger than `item`! That constrains reasonable uses of - ## this routine unless written as part of a conditional replacement. + ## returned may be larger than item! That constrains reasonable uses of + ## this routine unless written as part of a conditional replacement: ## - ## **See also:** - ## * `pushpop proc <#pushpop,HeapQueue[T],sinkT>`_ - runnableExamples: - var heap = [5, 12].toHeapQueue - assert heap.replace(6) == 5 - assert heap.len == 2 - assert heap[0] == 6 - assert heap.replace(4) == 6 - + ## .. code-block:: nim + ## if item > heap[0]: + ## item = replace(heap, item) result = heap[0] heap.data[0] = item - siftdown(heap, 0) + siftup(heap, 0) -proc pushpop*[T](heap: var HeapQueue[T], item: sink T): T = - ## Fast version of a `push()` followed by a `pop()`. - ## - ## **See also:** - ## * `replace proc <#replace,HeapQueue[T],sinkT>`_ - runnableExamples: - var heap = [5, 12].toHeapQueue - assert heap.pushpop(6) == 5 - assert heap.len == 2 - assert heap[0] == 6 - assert heap.pushpop(4) == 4 - - result = item - if heap.len > 0 and heapCmp(heap.data[0], result): - swap(result, heap.data[0]) - siftdown(heap, 0) +proc pushpop*[T](heap: var HeapQueue[T], item: T): T = + ## Fast version of a push followed by a pop. + if heap.len > 0 and heapCmp(heap[0], item): + swap(item, heap[0]) + siftup(heap, 0) + return item proc clear*[T](heap: var HeapQueue[T]) = - ## Removes all elements from `heap`, making it empty. + ## Remove all elements from `heap`, making it empty. runnableExamples: - var heap = [9, 5, 8].toHeapQueue + var heap = initHeapQueue[int]() + heap.push(1) heap.clear() assert heap.len == 0 - heap.data.setLen(0) proc `$`*[T](heap: HeapQueue[T]): string = - ## Turns a heap into its string representation. + ## Turn a heap into its string representation. runnableExamples: - let heap = [1, 2].toHeapQueue + var heap = initHeapQueue[int]() + heap.push(1) + heap.push(2) assert $heap == "[1, 2]" - result = "[" for x in heap.data: if result.len > 1: result.add(", ") result.addQuoted(x) result.add("]") + +proc newHeapQueue*[T](): HeapQueue[T] {.deprecated: + "Deprecated since v0.20.0: use 'initHeapQueue' instead.".} = + initHeapQueue[T]() + +proc newHeapQueue*[T](heap: var HeapQueue[T]) {.deprecated: + "Deprecated since v0.20.0: use 'clear' instead.".} = + heap.clear() + +when isMainModule: + proc toSortedSeq[T](h: HeapQueue[T]): seq[T] = + var tmp = h + result = @[] + while tmp.len > 0: + result.add(pop(tmp)) + + block: # Simple sanity test + var heap = initHeapQueue[int]() + let data = [1, 3, 5, 7, 9, 2, 4, 6, 8, 0] + for item in data: + push(heap, item) + doAssert(heap[0] == 0) + doAssert(heap.toSortedSeq == @[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) + + block: # Test del + var heap = initHeapQueue[int]() + let data = [1, 3, 5, 7, 9, 2, 4, 6, 8, 0] + for item in data: push(heap, item) + + heap.del(0) + doAssert(heap[0] == 1) + + heap.del(heap.data.find(7)) + doAssert(heap.toSortedSeq == @[1, 2, 3, 4, 5, 6, 8, 9]) + + heap.del(heap.data.find(5)) + doAssert(heap.toSortedSeq == @[1, 2, 3, 4, 6, 8, 9]) + + heap.del(heap.data.find(6)) + doAssert(heap.toSortedSeq == @[1, 2, 3, 4, 8, 9]) + + heap.del(heap.data.find(2)) + doAssert(heap.toSortedSeq == @[1, 3, 4, 8, 9]) + + block: # Test del last + var heap = initHeapQueue[int]() + let data = [1, 2, 3] + for item in data: push(heap, item) + + heap.del(2) + doAssert(heap.toSortedSeq == @[1, 2]) + + heap.del(1) + doAssert(heap.toSortedSeq == @[1]) + + heap.del(0) + doAssert(heap.toSortedSeq == @[]) diff --git a/lib/pure/collections/intsets.nim b/lib/pure/collections/intsets.nim index 765a23e97..8338ceaca 100644 --- a/lib/pure/collections/intsets.nim +++ b/lib/pure/collections/intsets.nim @@ -7,17 +7,666 @@ # distribution, for details about the copyright. # -## Specialization of the generic `packedsets module `_ -## (see its documentation for more examples) for ordinal sparse sets. +## The ``intsets`` module implements an efficient `int` set implemented as a +## `sparse bit set`:idx:. +## +## **Note**: Currently the assignment operator ``=`` for ``IntSet`` +## performs some rather meaningless shallow copy. Since Nim currently does +## not allow the assignment operator to be overloaded, use `assign proc +## <#assign,IntSet,IntSet>`_ to get a deep copy. +## +## **See also:** +## * `sets module `_ for more general hash sets -import std/private/since -import std/packedsets -export packedsets + +import + hashes type - IntSet* = PackedSet[int] + BitScalar = uint -proc toIntSet*(x: openArray[int]): IntSet {.since: (1, 3), inline.} = toPackedSet[int](x) +const + InitIntSetSize = 8 # must be a power of two! + TrunkShift = 9 + BitsPerTrunk = 1 shl TrunkShift # needs to be a power of 2 and + # divisible by 64 + TrunkMask = BitsPerTrunk - 1 + IntsPerTrunk = BitsPerTrunk div (sizeof(BitScalar) * 8) + IntShift = 5 + ord(sizeof(BitScalar) == 8) # 5 or 6, depending on int width + IntMask = 1 shl IntShift - 1 -proc initIntSet*(): IntSet {.inline.} = initPackedSet[int]() +type + PTrunk = ref Trunk + Trunk = object + next: PTrunk # all nodes are connected with this pointer + key: int # start address at bit 0 + bits: array[0..IntsPerTrunk - 1, BitScalar] # a bit vector + TrunkSeq = seq[PTrunk] + IntSet* = object ## An efficient set of `int` implemented as a sparse bit set. + elems: int # only valid for small numbers + counter, max: int + head: PTrunk + data: TrunkSeq + a: array[0..33, int] # profiling shows that 34 elements are enough + +proc mustRehash(length, counter: int): bool {.inline.} = + assert(length > counter) + result = (length * 2 < counter * 3) or (length - counter < 4) + +proc nextTry(h, maxHash: Hash): Hash {.inline.} = + result = ((5 * h) + 1) and maxHash + +proc intSetGet(t: IntSet, key: int): PTrunk = + var h = key and t.max + while t.data[h] != nil: + if t.data[h].key == key: + return t.data[h] + h = nextTry(h, t.max) + result = nil + +proc intSetRawInsert(t: IntSet, data: var TrunkSeq, desc: PTrunk) = + var h = desc.key and t.max + while data[h] != nil: + assert(data[h] != desc) + h = nextTry(h, t.max) + assert(data[h] == nil) + data[h] = desc + +proc intSetEnlarge(t: var IntSet) = + var n: TrunkSeq + var oldMax = t.max + t.max = ((t.max + 1) * 2) - 1 + newSeq(n, t.max + 1) + for i in countup(0, oldMax): + if t.data[i] != nil: intSetRawInsert(t, n, t.data[i]) + swap(t.data, n) + +proc intSetPut(t: var IntSet, key: int): PTrunk = + var h = key and t.max + while t.data[h] != nil: + if t.data[h].key == key: + return t.data[h] + h = nextTry(h, t.max) + if mustRehash(t.max + 1, t.counter): intSetEnlarge(t) + inc(t.counter) + h = key and t.max + while t.data[h] != nil: h = nextTry(h, t.max) + assert(t.data[h] == nil) + new(result) + result.next = t.head + result.key = key + t.head = result + t.data[h] = result + +proc bitincl(s: var IntSet, key: int) {.inline.} = + var t = intSetPut(s, `shr`(key, TrunkShift)) + var u = key and TrunkMask + t.bits[u shr IntShift] = t.bits[u shr IntShift] or + (BitScalar(1) shl (u and IntMask)) + +proc exclImpl(s: var IntSet, key: int) = + if s.elems <= s.a.len: + for i in 0.. 1: result.add(", ") + result.add($key) + result.add("}") + + +iterator items*(s: IntSet): int {.inline.} = + ## Iterates over any included element of `s`. + if s.elems <= s.a.len: + for i in 0..`_ for excluding an element + ## * `incl proc <#incl,IntSet,IntSet>`_ for including other set + ## * `containsOrIncl proc <#containsOrIncl,IntSet,int>`_ + runnableExamples: + var a = initIntSet() + a.incl(3) + a.incl(3) + assert len(a) == 1 + + if s.elems <= s.a.len: + for i in 0..`_. + ## + ## See also: + ## * `excl proc <#excl,IntSet,IntSet>`_ for excluding other set + ## * `incl proc <#incl,IntSet,int>`_ for including an element + ## * `containsOrIncl proc <#containsOrIncl,IntSet,int>`_ + runnableExamples: + var + a = initIntSet() + b = initIntSet() + a.incl(1) + b.incl(5) + a.incl(b) + assert len(a) == 2 + assert 5 in a + + for item in other: incl(s, item) + +proc containsOrIncl*(s: var IntSet, key: int): bool = + ## Includes `key` in the set `s` and tells if `key` was already in `s`. + ## + ## The difference with regards to the `incl proc <#incl,IntSet,int>`_ is + ## that this proc returns `true` if `s` already contained `key`. The + ## proc will return `false` if `key` was added as a new value to `s` during + ## this call. + ## + ## See also: + ## * `incl proc <#incl,IntSet,int>`_ for including an element + ## * `missingOrExcl proc <#missingOrExcl,IntSet,int>`_ + runnableExamples: + var a = initIntSet() + assert a.containsOrIncl(3) == false + assert a.containsOrIncl(3) == true + assert a.containsOrIncl(4) == false + + if s.elems <= s.a.len: + for i in 0..`_ for including an element + ## * `excl proc <#excl,IntSet,IntSet>`_ for excluding other set + ## * `missingOrExcl proc <#missingOrExcl,IntSet,int>`_ + runnableExamples: + var a = initIntSet() + a.incl(3) + a.excl(3) + a.excl(3) + a.excl(99) + assert len(a) == 0 + exclImpl(s, key) + +proc excl*(s: var IntSet, other: IntSet) = + ## Excludes all elements from `other` from `s`. + ## + ## This is the in-place version of `s - other <#-,IntSet,IntSet>`_. + ## + ## See also: + ## * `incl proc <#incl,IntSet,IntSet>`_ for including other set + ## * `excl proc <#excl,IntSet,int>`_ for excluding an element + ## * `missingOrExcl proc <#missingOrExcl,IntSet,int>`_ + runnableExamples: + var + a = initIntSet() + b = initIntSet() + a.incl(1) + a.incl(5) + b.incl(5) + a.excl(b) + assert len(a) == 1 + assert 5 notin a + + for item in other: excl(s, item) + +proc missingOrExcl*(s: var IntSet, key: int): bool = + ## Excludes `key` in the set `s` and tells if `key` was already missing from `s`. + ## + ## The difference with regards to the `excl proc <#excl,IntSet,int>`_ is + ## that this proc returns `true` if `key` was missing from `s`. + ## The proc will return `false` if `key` was in `s` and it was removed + ## during this call. + ## + ## See also: + ## * `excl proc <#excl,IntSet,int>`_ for excluding an element + ## * `excl proc <#excl,IntSet,IntSet>`_ for excluding other set + ## * `containsOrIncl proc <#containsOrIncl,IntSet,int>`_ + runnableExamples: + var a = initIntSet() + a.incl(5) + assert a.missingOrExcl(5) == false + assert a.missingOrExcl(5) == true + + var count = s.elems + exclImpl(s, key) + result = count == s.elems + +proc clear*(result: var IntSet) = + ## Clears the IntSet back to an empty state. + runnableExamples: + var a = initIntSet() + a.incl(5) + a.incl(7) + clear(a) + assert len(a) == 0 + + # setLen(result.data, InitIntSetSize) + # for i in 0..InitIntSetSize-1: result.data[i] = nil + # result.max = InitIntSetSize-1 + when defined(nimNoNilSeqs): + result.data = @[] + else: + result.data = nil + result.max = 0 + result.counter = 0 + result.head = nil + result.elems = 0 + +proc isNil*(x: IntSet): bool {.inline.} = x.head.isNil and x.elems == 0 + +proc assign*(dest: var IntSet, src: IntSet) = + ## Copies `src` to `dest`. + ## `dest` does not need to be initialized by `initIntSet proc <#initIntSet>`_. + runnableExamples: + var + a = initIntSet() + b = initIntSet() + b.incl(5) + b.incl(7) + a.assign(b) + assert len(a) == 2 + + if src.elems <= src.a.len: + when defined(nimNoNilSeqs): + dest.data = @[] + else: + dest.data = nil + dest.max = 0 + dest.counter = src.counter + dest.head = nil + dest.elems = src.elems + dest.a = src.a + else: + dest.counter = src.counter + dest.max = src.max + dest.elems = src.elems + newSeq(dest.data, src.data.len) + + var it = src.head + while it != nil: + var h = it.key and dest.max + while dest.data[h] != nil: h = nextTry(h, dest.max) + assert(dest.data[h] == nil) + var n: PTrunk + new(n) + n.next = dest.head + n.key = it.key + n.bits = it.bits + dest.head = n + dest.data[h] = n + it = it.next + +proc union*(s1, s2: IntSet): IntSet = + ## Returns the union of the sets `s1` and `s2`. + ## + ## The same as `s1 + s2 <#+,IntSet,IntSet>`_. + runnableExamples: + var + a = initIntSet() + b = initIntSet() + a.incl(1); a.incl(2); a.incl(3) + b.incl(3); b.incl(4); b.incl(5) + assert union(a, b).len == 5 + ## {1, 2, 3, 4, 5} + + result.assign(s1) + incl(result, s2) + +proc intersection*(s1, s2: IntSet): IntSet = + ## Returns the intersection of the sets `s1` and `s2`. + ## + ## The same as `s1 * s2 <#*,IntSet,IntSet>`_. + runnableExamples: + var + a = initIntSet() + b = initIntSet() + a.incl(1); a.incl(2); a.incl(3) + b.incl(3); b.incl(4); b.incl(5) + assert intersection(a, b).len == 1 + ## {3} + + result = initIntSet() + for item in s1: + if contains(s2, item): + incl(result, item) + +proc difference*(s1, s2: IntSet): IntSet = + ## Returns the difference of the sets `s1` and `s2`. + ## + ## The same as `s1 - s2 <#-,IntSet,IntSet>`_. + runnableExamples: + var + a = initIntSet() + b = initIntSet() + a.incl(1); a.incl(2); a.incl(3) + b.incl(3); b.incl(4); b.incl(5) + assert difference(a, b).len == 2 + ## {1, 2} + + result = initIntSet() + for item in s1: + if not contains(s2, item): + incl(result, item) + +proc symmetricDifference*(s1, s2: IntSet): IntSet = + ## Returns the symmetric difference of the sets `s1` and `s2`. + runnableExamples: + var + a = initIntSet() + b = initIntSet() + a.incl(1); a.incl(2); a.incl(3) + b.incl(3); b.incl(4); b.incl(5) + assert symmetricDifference(a, b).len == 4 + ## {1, 2, 4, 5} + + result.assign(s1) + for item in s2: + if containsOrIncl(result, item): excl(result, item) + +proc `+`*(s1, s2: IntSet): IntSet {.inline.} = + ## Alias for `union(s1, s2) <#union,IntSet,IntSet>`_. + result = union(s1, s2) + +proc `*`*(s1, s2: IntSet): IntSet {.inline.} = + ## Alias for `intersection(s1, s2) <#intersection,IntSet,IntSet>`_. + result = intersection(s1, s2) + +proc `-`*(s1, s2: IntSet): IntSet {.inline.} = + ## Alias for `difference(s1, s2) <#difference,IntSet,IntSet>`_. + result = difference(s1, s2) + +proc disjoint*(s1, s2: IntSet): bool = + ## Returns true if the sets `s1` and `s2` have no items in common. + runnableExamples: + var + a = initIntSet() + b = initIntSet() + a.incl(1); a.incl(2) + b.incl(2); b.incl(3) + assert disjoint(a, b) == false + b.excl(2) + assert disjoint(a, b) == true + + for item in s1: + if contains(s2, item): + return false + return true + +proc len*(s: IntSet): int {.inline.} = + ## Returns the number of elements in `s`. + if s.elems < s.a.len: + result = s.elems + else: + result = 0 + for _ in s: + inc(result) + +proc card*(s: IntSet): int {.inline.} = + ## Alias for `len() <#len,IntSet>`_. + result = s.len() + +proc `<=`*(s1, s2: IntSet): bool = + ## Returns true if `s1` is subset of `s2`. + ## + ## A subset `s1` has all of its elements in `s2`, and `s2` doesn't necessarily + ## have more elements than `s1`. That is, `s1` can be equal to `s2`. + runnableExamples: + var + a = initIntSet() + b = initIntSet() + a.incl(1) + b.incl(1); b.incl(2) + assert a <= b + a.incl(2) + assert a <= b + a.incl(3) + assert(not (a <= b)) + + for item in s1: + if not s2.contains(item): + return false + return true + +proc `<`*(s1, s2: IntSet): bool = + ## Returns true if `s1` is proper subset of `s2`. + ## + ## A strict or proper subset `s1` has all of its elements in `s2`, but `s2` has + ## more elements than `s1`. + runnableExamples: + var + a = initIntSet() + b = initIntSet() + a.incl(1) + b.incl(1); b.incl(2) + assert a < b + a.incl(2) + assert(not (a < b)) + return s1 <= s2 and not (s2 <= s1) + +proc `==`*(s1, s2: IntSet): bool = + ## Returns true if both `s1` and `s2` have the same elements and set size. + return s1 <= s2 and s2 <= s1 + +proc `$`*(s: IntSet): string = + ## The `$` operator for int sets. + ## + ## Converts the set `s` to a string, mostly for logging and printing purposes. + dollarImpl() + + + +when isMainModule: + import sequtils, algorithm + + var x = initIntSet() + x.incl(1) + x.incl(2) + x.incl(7) + x.incl(1056) + + x.incl(1044) + x.excl(1044) + + assert x.containsOrIncl(888) == false + assert 888 in x + assert x.containsOrIncl(888) == true + + assert x.missingOrExcl(888) == false + assert 888 notin x + assert x.missingOrExcl(888) == true + + var xs = toSeq(items(x)) + xs.sort(cmp[int]) + assert xs == @[1, 2, 7, 1056] + + var y: IntSet + assign(y, x) + var ys = toSeq(items(y)) + ys.sort(cmp[int]) + assert ys == @[1, 2, 7, 1056] + + assert x == y + + var z: IntSet + for i in 0..1000: + incl z, i + assert z.len() == i+1 + for i in 0..1000: + assert z.contains(i) + + var w = initIntSet() + w.incl(1) + w.incl(4) + w.incl(50) + w.incl(1001) + w.incl(1056) + + var xuw = x.union(w) + var xuws = toSeq(items(xuw)) + xuws.sort(cmp[int]) + assert xuws == @[1, 2, 4, 7, 50, 1001, 1056] + + var xiw = x.intersection(w) + var xiws = toSeq(items(xiw)) + xiws.sort(cmp[int]) + assert xiws == @[1, 1056] + + var xdw = x.difference(w) + var xdws = toSeq(items(xdw)) + xdws.sort(cmp[int]) + assert xdws == @[2, 7] + + var xsw = x.symmetricDifference(w) + var xsws = toSeq(items(xsw)) + xsws.sort(cmp[int]) + assert xsws == @[2, 4, 7, 50, 1001] + + x.incl(w) + xs = toSeq(items(x)) + xs.sort(cmp[int]) + assert xs == @[1, 2, 4, 7, 50, 1001, 1056] + + assert w <= x + + assert w < x + + assert(not disjoint(w, x)) + + var u = initIntSet() + u.incl(3) + u.incl(5) + u.incl(500) + assert disjoint(u, x) + + var v = initIntSet() + v.incl(2) + v.incl(50) + + x.excl(v) + xs = toSeq(items(x)) + xs.sort(cmp[int]) + assert xs == @[1, 4, 7, 1001, 1056] + + proc bug12366 = + var + x = initIntSet() + y = initIntSet() + n = 3584 + + for i in 0..n: + x.incl(i) + y.incl(i) + + let z = symmetricDifference(x, y) + doAssert z.len == 0 + doAssert $z == "{}" + + bug12366() diff --git a/lib/pure/collections/lists.nim b/lib/pure/collections/lists.nim index a08c62964..bd22949bf 100644 --- a/lib/pure/collections/lists.nim +++ b/lib/pure/collections/lists.nim @@ -13,90 +13,119 @@ ## * `singly linked rings <#SinglyLinkedRing>`_ (circular lists) ## * `doubly linked rings <#DoublyLinkedRing>`_ (circular lists) ## -## # Basic Usage +## +## Basic Usage +## =========== +## ## Because it makes no sense to do otherwise, the `next` and `prev` pointers ## are not hidden from you and can be manipulated directly for efficiency. ## -## ## Lists -runnableExamples: - var list = initDoublyLinkedList[int]() - let - a = newDoublyLinkedNode[int](3) - b = newDoublyLinkedNode[int](7) - c = newDoublyLinkedNode[int](9) - - list.add(a) - list.add(b) - list.prepend(c) - - assert a.next == b - assert a.prev == c - assert c.next == a - assert c.next.next == b - assert c.prev == nil - assert b.next == nil - -## ## Rings -runnableExamples: - var ring = initSinglyLinkedRing[int]() - let - a = newSinglyLinkedNode[int](3) - b = newSinglyLinkedNode[int](7) - c = newSinglyLinkedNode[int](9) - - ring.add(a) - ring.add(b) - ring.prepend(c) - - assert c.next == a - assert a.next == b - assert c.next.next == b - assert b.next == c - assert c.next.next.next == c - -## # See also +## Lists +## ----- +## +## .. code-block:: +## import lists +## +## var +## l = initDoublyLinkedList[int]() +## a = newDoublyLinkedNode[int](3) +## b = newDoublyLinkedNode[int](7) +## c = newDoublyLinkedNode[int](9) +## +## l.append(a) +## l.append(b) +## l.prepend(c) +## +## assert a.next == b +## assert a.prev == c +## assert c.next == a +## assert c.next.next == b +## assert c.prev == nil +## assert b.next == nil +## +## +## Rings +## ----- +## +## .. code-block:: +## import lists +## +## var +## l = initSinglyLinkedRing[int]() +## a = newSinglyLinkedNode[int](3) +## b = newSinglyLinkedNode[int](7) +## c = newSinglyLinkedNode[int](9) +## +## l.append(a) +## l.append(b) +## l.prepend(c) +## +## assert c.next == a +## assert a.next == b +## assert c.next.next == b +## assert b.next == c +## assert c.next.next.next == c +## +## See also +## ======== +## ## * `deques module `_ for double-ended queues +## * `sharedlist module `_ for shared singly-linked lists -import std/private/since -when defined(nimPreviewSlimSystem): - import std/assertions +when not defined(nimhygiene): + {.pragma: dirty.} + +when not defined(nimHasCursor): + {.pragma: cursor.} type - DoublyLinkedNodeObj*[T] = object - ## A node of a doubly linked list. + DoublyLinkedNodeObj*[T] = object ## \ + ## A node a doubly linked list consists of. ## ## It consists of a `value` field, and pointers to `next` and `prev`. - next*: DoublyLinkedNode[T] - prev* {.cursor.}: DoublyLinkedNode[T] + next*: (ref DoublyLinkedNodeObj[T]) + prev* {.cursor.}: ref DoublyLinkedNodeObj[T] value*: T DoublyLinkedNode*[T] = ref DoublyLinkedNodeObj[T] - SinglyLinkedNodeObj*[T] = object - ## A node of a singly linked list. + SinglyLinkedNodeObj*[T] = object ## \ + ## A node a singly linked list consists of. ## ## It consists of a `value` field, and a pointer to `next`. - next*: SinglyLinkedNode[T] + next*: (ref SinglyLinkedNodeObj[T]) value*: T SinglyLinkedNode*[T] = ref SinglyLinkedNodeObj[T] - SinglyLinkedList*[T] = object + SinglyLinkedList*[T] = object ## \ ## A singly linked list. - head*: SinglyLinkedNode[T] + ## + ## Use `initSinglyLinkedList proc <#initSinglyLinkedList>`_ to create + ## a new empty list. + head*: (SinglyLinkedNode[T]) tail* {.cursor.}: SinglyLinkedNode[T] - DoublyLinkedList*[T] = object + DoublyLinkedList*[T] = object ## \ ## A doubly linked list. - head*: DoublyLinkedNode[T] + ## + ## Use `initDoublyLinkedList proc <#initDoublyLinkedList>`_ to create + ## a new empty list. + head*: (DoublyLinkedNode[T]) tail* {.cursor.}: DoublyLinkedNode[T] - SinglyLinkedRing*[T] = object + SinglyLinkedRing*[T] = object ## \ ## A singly linked ring. - head*: SinglyLinkedNode[T] + ## + ## Use `initSinglyLinkedRing proc <#initSinglyLinkedRing>`_ to create + ## a new empty ring. + head*: (SinglyLinkedNode[T]) tail* {.cursor.}: SinglyLinkedNode[T] - DoublyLinkedRing*[T] = object + DoublyLinkedRing*[T] = object ## \ ## A doubly linked ring. + ## + ## Use `initDoublyLinkedRing proc <#initDoublyLinkedRing>`_ to create + ## a new empty ring. head*: DoublyLinkedNode[T] SomeLinkedList*[T] = SinglyLinkedList[T] | DoublyLinkedList[T] @@ -109,84 +138,46 @@ type proc initSinglyLinkedList*[T](): SinglyLinkedList[T] = ## Creates a new singly linked list that is empty. - ## - ## Singly linked lists are initialized by default, so it is not necessary to - ## call this function explicitly. runnableExamples: - let a = initSinglyLinkedList[int]() - + var a = initSinglyLinkedList[int]() discard proc initDoublyLinkedList*[T](): DoublyLinkedList[T] = ## Creates a new doubly linked list that is empty. - ## - ## Doubly linked lists are initialized by default, so it is not necessary to - ## call this function explicitly. runnableExamples: - let a = initDoublyLinkedList[int]() - + var a = initDoublyLinkedList[int]() discard proc initSinglyLinkedRing*[T](): SinglyLinkedRing[T] = ## Creates a new singly linked ring that is empty. - ## - ## Singly linked rings are initialized by default, so it is not necessary to - ## call this function explicitly. runnableExamples: - let a = initSinglyLinkedRing[int]() - + var a = initSinglyLinkedRing[int]() discard proc initDoublyLinkedRing*[T](): DoublyLinkedRing[T] = ## Creates a new doubly linked ring that is empty. - ## - ## Doubly linked rings are initialized by default, so it is not necessary to - ## call this function explicitly. runnableExamples: - let a = initDoublyLinkedRing[int]() - + var a = initDoublyLinkedRing[int]() discard -proc newDoublyLinkedNode*[T](value: T): DoublyLinkedNode[T] = +proc newDoublyLinkedNode*[T](value: T): (DoublyLinkedNode[T]) = ## Creates a new doubly linked node with the given `value`. runnableExamples: - let n = newDoublyLinkedNode[int](5) + var n = newDoublyLinkedNode[int](5) assert n.value == 5 new(result) result.value = value -proc newSinglyLinkedNode*[T](value: T): SinglyLinkedNode[T] = +proc newSinglyLinkedNode*[T](value: T): (SinglyLinkedNode[T]) = ## Creates a new singly linked node with the given `value`. runnableExamples: - let n = newSinglyLinkedNode[int](5) + var n = newSinglyLinkedNode[int](5) assert n.value == 5 new(result) result.value = value -func toSinglyLinkedList*[T](elems: openArray[T]): SinglyLinkedList[T] {.since: (1, 5, 1).} = - ## Creates a new `SinglyLinkedList` from the members of `elems`. - runnableExamples: - from std/sequtils import toSeq - let a = [1, 2, 3, 4, 5].toSinglyLinkedList - assert a.toSeq == [1, 2, 3, 4, 5] - - result = initSinglyLinkedList[T]() - for elem in elems.items: - result.add(elem) - -func toDoublyLinkedList*[T](elems: openArray[T]): DoublyLinkedList[T] {.since: (1, 5, 1).} = - ## Creates a new `DoublyLinkedList` from the members of `elems`. - runnableExamples: - from std/sequtils import toSeq - let a = [1, 2, 3, 4, 5].toDoublyLinkedList - assert a.toSeq == [1, 2, 3, 4, 5] - - result = initDoublyLinkedList[T]() - for elem in elems.items: - result.add(elem) - template itemsListImpl() {.dirty.} = var it = L.head while it != nil: @@ -204,91 +195,101 @@ template itemsRingImpl() {.dirty.} = iterator items*[T](L: SomeLinkedList[T]): T = ## Yields every value of `L`. ## - ## **See also:** + ## See also: ## * `mitems iterator <#mitems.i,SomeLinkedList[T]>`_ ## * `nodes iterator <#nodes.i,SomeLinkedList[T]>`_ - runnableExamples: - from std/sugar import collect - from std/sequtils import toSeq - let a = collect(initSinglyLinkedList): - for i in 1..3: 10 * i - assert toSeq(items(a)) == toSeq(a) - assert toSeq(a) == @[10, 20, 30] - + ## + ## **Examples:** + ## + ## .. code-block:: + ## var a = initSinglyLinkedList[int]() + ## for i in 1 .. 3: + ## a.append(10*i) + ## + ## for x in a: # the same as: for x in items(a): + ## echo x + ## + ## # 10 + ## # 20 + ## # 30 itemsListImpl() iterator items*[T](L: SomeLinkedRing[T]): T = ## Yields every value of `L`. ## - ## **See also:** + ## See also: ## * `mitems iterator <#mitems.i,SomeLinkedRing[T]>`_ ## * `nodes iterator <#nodes.i,SomeLinkedRing[T]>`_ - runnableExamples: - from std/sugar import collect - from std/sequtils import toSeq - let a = collect(initSinglyLinkedRing): - for i in 1..3: 10 * i - assert toSeq(items(a)) == toSeq(a) - assert toSeq(a) == @[10, 20, 30] - + ## + ## **Examples:** + ## + ## .. code-block:: + ## var a = initSinglyLinkedRing[int]() + ## for i in 1 .. 3: + ## a.append(10*i) + ## + ## for x in a: # the same as: for x in items(a): + ## echo x + ## + ## # 10 + ## # 20 + ## # 30 itemsRingImpl() iterator mitems*[T](L: var SomeLinkedList[T]): var T = ## Yields every value of `L` so that you can modify it. ## - ## **See also:** + ## See also: ## * `items iterator <#items.i,SomeLinkedList[T]>`_ ## * `nodes iterator <#nodes.i,SomeLinkedList[T]>`_ runnableExamples: var a = initSinglyLinkedList[int]() - for i in 1..5: - a.add(10 * i) + for i in 1 .. 5: + a.append(10*i) assert $a == "[10, 20, 30, 40, 50]" for x in mitems(a): - x = 5 * x - 1 + x = 5*x - 1 assert $a == "[49, 99, 149, 199, 249]" - itemsListImpl() iterator mitems*[T](L: var SomeLinkedRing[T]): var T = ## Yields every value of `L` so that you can modify it. ## - ## **See also:** + ## See also: ## * `items iterator <#items.i,SomeLinkedRing[T]>`_ ## * `nodes iterator <#nodes.i,SomeLinkedRing[T]>`_ runnableExamples: var a = initSinglyLinkedRing[int]() - for i in 1..5: - a.add(10 * i) + for i in 1 .. 5: + a.append(10*i) assert $a == "[10, 20, 30, 40, 50]" for x in mitems(a): - x = 5 * x - 1 + x = 5*x - 1 assert $a == "[49, 99, 149, 199, 249]" - itemsRingImpl() iterator nodes*[T](L: SomeLinkedList[T]): SomeLinkedNode[T] = ## Iterates over every node of `x`. Removing the current node from the ## list during traversal is supported. ## - ## **See also:** + ## See also: ## * `items iterator <#items.i,SomeLinkedList[T]>`_ ## * `mitems iterator <#mitems.i,SomeLinkedList[T]>`_ runnableExamples: var a = initDoublyLinkedList[int]() - for i in 1..5: - a.add(10 * i) + for i in 1 .. 5: + a.append(10*i) assert $a == "[10, 20, 30, 40, 50]" for x in nodes(a): if x.value == 30: a.remove(x) else: - x.value = 5 * x.value - 1 + x.value = 5*x.value - 1 assert $a == "[49, 99, 199, 249]" var it = L.head while it != nil: - let nxt = it.next + var nxt = it.next yield it it = nxt @@ -296,35 +297,31 @@ iterator nodes*[T](L: SomeLinkedRing[T]): SomeLinkedNode[T] = ## Iterates over every node of `x`. Removing the current node from the ## list during traversal is supported. ## - ## **See also:** + ## See also: ## * `items iterator <#items.i,SomeLinkedRing[T]>`_ ## * `mitems iterator <#mitems.i,SomeLinkedRing[T]>`_ runnableExamples: var a = initDoublyLinkedRing[int]() - for i in 1..5: - a.add(10 * i) + for i in 1 .. 5: + a.append(10*i) assert $a == "[10, 20, 30, 40, 50]" for x in nodes(a): if x.value == 30: a.remove(x) else: - x.value = 5 * x.value - 1 + x.value = 5*x.value - 1 assert $a == "[49, 99, 199, 249]" var it = L.head if it != nil: while true: - let nxt = it.next + var nxt = it.next yield it it = nxt if it == L.head: break proc `$`*[T](L: SomeLinkedCollection[T]): string = ## Turns a list into its string representation for logging and printing. - runnableExamples: - let a = [1, 2, 3, 4].toSinglyLinkedList - assert $a == "[1, 2, 3, 4]" - result = "[" for x in nodes(L): if result.len > 1: result.add(", ") @@ -335,10 +332,12 @@ proc find*[T](L: SomeLinkedCollection[T], value: T): SomeLinkedNode[T] = ## Searches in the list for a value. Returns `nil` if the value does not ## exist. ## - ## **See also:** + ## See also: ## * `contains proc <#contains,SomeLinkedCollection[T],T>`_ runnableExamples: - let a = [9, 8].toSinglyLinkedList + var a = initSinglyLinkedList[int]() + a.append(9) + a.append(8) assert a.find(9).value == 9 assert a.find(1) == nil @@ -347,13 +346,14 @@ proc find*[T](L: SomeLinkedCollection[T], value: T): SomeLinkedNode[T] = proc contains*[T](L: SomeLinkedCollection[T], value: T): bool {.inline.} = ## Searches in the list for a value. Returns `false` if the value does not - ## exist, `true` otherwise. This allows the usage of the `in` and `notin` - ## operators. + ## exist, `true` otherwise. ## - ## **See also:** + ## See also: ## * `find proc <#find,SomeLinkedCollection[T],T>`_ runnableExamples: - let a = [9, 8].toSinglyLinkedList + var a = initSinglyLinkedList[int]() + a.append(9) + a.append(8) assert a.contains(9) assert 8 in a assert(not a.contains(1)) @@ -361,67 +361,20 @@ proc contains*[T](L: SomeLinkedCollection[T], value: T): bool {.inline.} = result = find(L, value) != nil -proc prepend*[T: SomeLinkedList](a: var T, b: T) {.since: (1, 5, 1).} = - ## Prepends a shallow copy of `b` to the beginning of `a`. - ## - ## **See also:** - ## * `prependMoved proc <#prependMoved,T,T>`_ - ## for moving the second list instead of copying - runnableExamples: - from std/sequtils import toSeq - var a = [4, 5].toSinglyLinkedList - let b = [1, 2, 3].toSinglyLinkedList - a.prepend(b) - assert a.toSeq == [1, 2, 3, 4, 5] - assert b.toSeq == [1, 2, 3] - a.prepend(a) - assert a.toSeq == [1, 2, 3, 4, 5, 1, 2, 3, 4, 5] - - var tmp = b.copy - tmp.addMoved(a) - a = tmp - -proc prependMoved*[T: SomeLinkedList](a, b: var T) {.since: (1, 5, 1).} = - ## Moves `b` before the head of `a`. Efficiency: O(1). - ## Note that `b` becomes empty after the operation unless it has the same address as `a`. - ## Self-prepending results in a cycle. - ## - ## **See also:** - ## * `prepend proc <#prepend,T,T>`_ - ## for prepending a copy of a list - runnableExamples: - import std/[sequtils, enumerate, sugar] - var - a = [4, 5].toSinglyLinkedList - b = [1, 2, 3].toSinglyLinkedList - c = [0, 1].toSinglyLinkedList - a.prependMoved(b) - assert a.toSeq == [1, 2, 3, 4, 5] - assert b.toSeq == [] - c.prependMoved(c) - let s = collect: - for i, ci in enumerate(c): - if i == 6: break - ci - assert s == [0, 1, 0, 1, 0, 1] - - b.addMoved(a) - when defined(js): # XXX: swap broken in js; bug #16771 - (b, a) = (a, b) - else: swap a, b - -proc add*[T](L: var SinglyLinkedList[T], n: SinglyLinkedNode[T]) {.inline.} = +proc append*[T](L: var SinglyLinkedList[T], + n: SinglyLinkedNode[T]) {.inline.} = ## Appends (adds to the end) a node `n` to `L`. Efficiency: O(1). ## - ## **See also:** - ## * `add proc <#add,SinglyLinkedList[T],T>`_ for appending a value + ## See also: + ## * `append proc <#append,SinglyLinkedList[T],T>`_ for appending a value ## * `prepend proc <#prepend,SinglyLinkedList[T],SinglyLinkedNode[T]>`_ ## for prepending a node ## * `prepend proc <#prepend,SinglyLinkedList[T],T>`_ for prepending a value runnableExamples: - var a = initSinglyLinkedList[int]() - let n = newSinglyLinkedNode[int](9) - a.add(n) + var + a = initSinglyLinkedList[int]() + n = newSinglyLinkedNode[int](9) + a.append(n) assert a.contains(9) n.next = nil @@ -431,34 +384,34 @@ proc add*[T](L: var SinglyLinkedList[T], n: SinglyLinkedNode[T]) {.inline.} = L.tail = n if L.head == nil: L.head = n -proc add*[T](L: var SinglyLinkedList[T], value: T) {.inline.} = +proc append*[T](L: var SinglyLinkedList[T], value: T) {.inline.} = ## Appends (adds to the end) a value to `L`. Efficiency: O(1). ## - ## **See also:** - ## * `add proc <#add,SinglyLinkedList[T],T>`_ for appending a value + ## See also: + ## * `append proc <#append,SinglyLinkedList[T],T>`_ for appending a value ## * `prepend proc <#prepend,SinglyLinkedList[T],SinglyLinkedNode[T]>`_ ## for prepending a node ## * `prepend proc <#prepend,SinglyLinkedList[T],T>`_ for prepending a value runnableExamples: var a = initSinglyLinkedList[int]() - a.add(9) - a.add(8) + a.append(9) + a.append(8) assert a.contains(9) - - add(L, newSinglyLinkedNode(value)) + append(L, newSinglyLinkedNode(value)) proc prepend*[T](L: var SinglyLinkedList[T], n: SinglyLinkedNode[T]) {.inline.} = ## Prepends (adds to the beginning) a node to `L`. Efficiency: O(1). ## - ## **See also:** - ## * `add proc <#add,SinglyLinkedList[T],SinglyLinkedNode[T]>`_ + ## See also: + ## * `append proc <#append,SinglyLinkedList[T],SinglyLinkedNode[T]>`_ ## for appending a node - ## * `add proc <#add,SinglyLinkedList[T],T>`_ for appending a value + ## * `append proc <#append,SinglyLinkedList[T],T>`_ for appending a value ## * `prepend proc <#prepend,SinglyLinkedList[T],T>`_ for prepending a value runnableExamples: - var a = initSinglyLinkedList[int]() - let n = newSinglyLinkedNode[int](9) + var + a = initSinglyLinkedList[int]() + n = newSinglyLinkedNode[int](9) a.prepend(n) assert a.contains(9) @@ -469,10 +422,10 @@ proc prepend*[T](L: var SinglyLinkedList[T], proc prepend*[T](L: var SinglyLinkedList[T], value: T) {.inline.} = ## Prepends (adds to the beginning) a node to `L`. Efficiency: O(1). ## - ## **See also:** - ## * `add proc <#add,SinglyLinkedList[T],SinglyLinkedNode[T]>`_ + ## See also: + ## * `append proc <#append,SinglyLinkedList[T],SinglyLinkedNode[T]>`_ ## for appending a node - ## * `add proc <#add,SinglyLinkedList[T],T>`_ for appending a value + ## * `append proc <#append,SinglyLinkedList[T],T>`_ for appending a value ## * `prepend proc <#prepend,SinglyLinkedList[T],SinglyLinkedNode[T]>`_ ## for prepending a node runnableExamples: @@ -480,80 +433,25 @@ proc prepend*[T](L: var SinglyLinkedList[T], value: T) {.inline.} = a.prepend(9) a.prepend(8) assert a.contains(9) - prepend(L, newSinglyLinkedNode(value)) -func copy*[T](a: SinglyLinkedList[T]): SinglyLinkedList[T] {.since: (1, 5, 1).} = - ## Creates a shallow copy of `a`. - runnableExamples: - from std/sequtils import toSeq - type Foo = ref object - x: int - var - f = Foo(x: 1) - a = [f].toSinglyLinkedList - let b = a.copy - a.add([f].toSinglyLinkedList) - assert a.toSeq == [f, f] - assert b.toSeq == [f] # b isn't modified... - f.x = 42 - assert a.head.value.x == 42 - assert b.head.value.x == 42 # ... but the elements are not deep copied - let c = [1, 2, 3].toSinglyLinkedList - assert $c == $c.copy - result = initSinglyLinkedList[T]() - for x in a.items: - result.add(x) - -proc addMoved*[T](a, b: var SinglyLinkedList[T]) {.since: (1, 5, 1).} = - ## Moves `b` to the end of `a`. Efficiency: O(1). - ## Note that `b` becomes empty after the operation unless it has the same address as `a`. - ## Self-adding results in a cycle. - ## - ## **See also:** - ## * `add proc <#add,T,T>`_ for adding a copy of a list - runnableExamples: - import std/[sequtils, enumerate, sugar] - var - a = [1, 2, 3].toSinglyLinkedList - b = [4, 5].toSinglyLinkedList - c = [0, 1].toSinglyLinkedList - a.addMoved(b) - assert a.toSeq == [1, 2, 3, 4, 5] - assert b.toSeq == [] - c.addMoved(c) - let s = collect: - for i, ci in enumerate(c): - if i == 6: break - ci - assert s == [0, 1, 0, 1, 0, 1] - - if b.head != nil: - if a.head == nil: - a.head = b.head - else: - a.tail.next = b.head - a.tail = b.tail - if a.addr != b.addr: - b.head = nil - b.tail = nil - -proc add*[T](L: var DoublyLinkedList[T], n: DoublyLinkedNode[T]) = +proc append*[T](L: var DoublyLinkedList[T], n: DoublyLinkedNode[T]) = ## Appends (adds to the end) a node `n` to `L`. Efficiency: O(1). ## - ## **See also:** - ## * `add proc <#add,DoublyLinkedList[T],T>`_ for appending a value + ## See also: + ## * `append proc <#append,DoublyLinkedList[T],T>`_ for appending a value ## * `prepend proc <#prepend,DoublyLinkedList[T],DoublyLinkedNode[T]>`_ ## for prepending a node ## * `prepend proc <#prepend,DoublyLinkedList[T],T>`_ for prepending a value ## * `remove proc <#remove,DoublyLinkedList[T],DoublyLinkedNode[T]>`_ ## for removing a node runnableExamples: - var a = initDoublyLinkedList[int]() - let n = newDoublyLinkedNode[int](9) - a.add(n) + var + a = initDoublyLinkedList[int]() + n = newDoublyLinkedNode[int](9) + a.append(n) assert a.contains(9) n.next = nil @@ -564,11 +462,11 @@ proc add*[T](L: var DoublyLinkedList[T], n: DoublyLinkedNode[T]) = L.tail = n if L.head == nil: L.head = n -proc add*[T](L: var DoublyLinkedList[T], value: T) = +proc append*[T](L: var DoublyLinkedList[T], value: T) = ## Appends (adds to the end) a value to `L`. Efficiency: O(1). ## - ## **See also:** - ## * `add proc <#add,DoublyLinkedList[T],DoublyLinkedNode[T]>`_ + ## See also: + ## * `append proc <#append,DoublyLinkedList[T],DoublyLinkedNode[T]>`_ ## for appending a node ## * `prepend proc <#prepend,DoublyLinkedList[T],DoublyLinkedNode[T]>`_ ## for prepending a node @@ -577,25 +475,25 @@ proc add*[T](L: var DoublyLinkedList[T], value: T) = ## for removing a node runnableExamples: var a = initDoublyLinkedList[int]() - a.add(9) - a.add(8) + a.append(9) + a.append(8) assert a.contains(9) - - add(L, newDoublyLinkedNode(value)) + append(L, newDoublyLinkedNode(value)) proc prepend*[T](L: var DoublyLinkedList[T], n: DoublyLinkedNode[T]) = ## Prepends (adds to the beginning) a node `n` to `L`. Efficiency: O(1). ## - ## **See also:** - ## * `add proc <#add,DoublyLinkedList[T],DoublyLinkedNode[T]>`_ + ## See also: + ## * `append proc <#append,DoublyLinkedList[T],DoublyLinkedNode[T]>`_ ## for appending a node - ## * `add proc <#add,DoublyLinkedList[T],T>`_ for appending a value + ## * `append proc <#append,DoublyLinkedList[T],T>`_ for appending a value ## * `prepend proc <#prepend,DoublyLinkedList[T],T>`_ for prepending a value ## * `remove proc <#remove,DoublyLinkedList[T],DoublyLinkedNode[T]>`_ ## for removing a node runnableExamples: - var a = initDoublyLinkedList[int]() - let n = newDoublyLinkedNode[int](9) + var + a = initDoublyLinkedList[int]() + n = newDoublyLinkedNode[int](9) a.prepend(n) assert a.contains(9) @@ -610,10 +508,10 @@ proc prepend*[T](L: var DoublyLinkedList[T], n: DoublyLinkedNode[T]) = proc prepend*[T](L: var DoublyLinkedList[T], value: T) = ## Prepends (adds to the beginning) a value to `L`. Efficiency: O(1). ## - ## **See also:** - ## * `add proc <#add,DoublyLinkedList[T],DoublyLinkedNode[T]>`_ + ## See also: + ## * `append proc <#append,DoublyLinkedList[T],DoublyLinkedNode[T]>`_ ## for appending a node - ## * `add proc <#add,DoublyLinkedList[T],T>`_ for appending a value + ## * `append proc <#append,DoublyLinkedList[T],T>`_ for appending a value ## * `prepend proc <#prepend,DoublyLinkedList[T],DoublyLinkedNode[T]>`_ ## for prepending a node ## * `remove proc <#remove,DoublyLinkedList[T],DoublyLinkedNode[T]>`_ @@ -623,147 +521,18 @@ proc prepend*[T](L: var DoublyLinkedList[T], value: T) = a.prepend(9) a.prepend(8) assert a.contains(9) - prepend(L, newDoublyLinkedNode(value)) -func copy*[T](a: DoublyLinkedList[T]): DoublyLinkedList[T] {.since: (1, 5, 1).} = - ## Creates a shallow copy of `a`. - runnableExamples: - from std/sequtils import toSeq - type Foo = ref object - x: int - var - f = Foo(x: 1) - a = [f].toDoublyLinkedList - let b = a.copy - a.add([f].toDoublyLinkedList) - assert a.toSeq == [f, f] - assert b.toSeq == [f] # b isn't modified... - f.x = 42 - assert a.head.value.x == 42 - assert b.head.value.x == 42 # ... but the elements are not deep copied - - let c = [1, 2, 3].toDoublyLinkedList - assert $c == $c.copy - - result = initDoublyLinkedList[T]() - for x in a.items: - result.add(x) - -proc addMoved*[T](a, b: var DoublyLinkedList[T]) {.since: (1, 5, 1).} = - ## Moves `b` to the end of `a`. Efficiency: O(1). - ## Note that `b` becomes empty after the operation unless it has the same address as `a`. - ## Self-adding results in a cycle. - ## - ## **See also:** - ## * `add proc <#add,T,T>`_ - ## for adding a copy of a list - runnableExamples: - import std/[sequtils, enumerate, sugar] - var - a = [1, 2, 3].toDoublyLinkedList - b = [4, 5].toDoublyLinkedList - c = [0, 1].toDoublyLinkedList - a.addMoved(b) - assert a.toSeq == [1, 2, 3, 4, 5] - assert b.toSeq == [] - c.addMoved(c) - let s = collect: - for i, ci in enumerate(c): - if i == 6: break - ci - assert s == [0, 1, 0, 1, 0, 1] - - if b.head != nil: - if a.head == nil: - a.head = b.head - else: - b.head.prev = a.tail - a.tail.next = b.head - a.tail = b.tail - if a.addr != b.addr: - b.head = nil - b.tail = nil - -proc add*[T: SomeLinkedList](a: var T, b: T) {.since: (1, 5, 1).} = - ## Appends a shallow copy of `b` to the end of `a`. - ## - ## **See also:** - ## * `addMoved proc <#addMoved,SinglyLinkedList[T],SinglyLinkedList[T]>`_ - ## * `addMoved proc <#addMoved,DoublyLinkedList[T],DoublyLinkedList[T]>`_ - ## for moving the second list instead of copying - runnableExamples: - from std/sequtils import toSeq - var a = [1, 2, 3].toSinglyLinkedList - let b = [4, 5].toSinglyLinkedList - a.add(b) - assert a.toSeq == [1, 2, 3, 4, 5] - assert b.toSeq == [4, 5] - a.add(a) - assert a.toSeq == [1, 2, 3, 4, 5, 1, 2, 3, 4, 5] - - var tmp = b.copy - a.addMoved(tmp) - -proc remove*[T](L: var SinglyLinkedList[T], n: SinglyLinkedNode[T]): bool {.discardable.} = - ## Removes a node `n` from `L`. - ## Returns `true` if `n` was found in `L`. - ## Efficiency: O(n); the list is traversed until `n` is found. - ## Attempting to remove an element not contained in the list is a no-op. - ## When the list is cyclic, the cycle is preserved after removal. - runnableExamples: - import std/[sequtils, enumerate, sugar] - var a = [0, 1, 2].toSinglyLinkedList - let n = a.head.next - assert n.value == 1 - assert a.remove(n) == true - assert a.toSeq == [0, 2] - assert a.remove(n) == false - assert a.toSeq == [0, 2] - a.addMoved(a) # cycle: [0, 2, 0, 2, ...] - a.remove(a.head) - let s = collect: - for i, ai in enumerate(a): - if i == 4: break - ai - assert s == [2, 2, 2, 2] - - if n == L.head: - L.head = n.next - if L.tail.next == n: - L.tail.next = L.head # restore cycle - else: - var prev = L.head - while prev.next != n and prev.next != nil: - prev = prev.next - if prev.next == nil: - return false - prev.next = n.next - if L.tail == n: - L.tail = prev # update tail if we removed the last node - true - proc remove*[T](L: var DoublyLinkedList[T], n: DoublyLinkedNode[T]) = ## Removes a node `n` from `L`. Efficiency: O(1). - ## This function assumes, for the sake of efficiency, that `n` is contained in `L`, - ## otherwise the effects are undefined. - ## When the list is cyclic, the cycle is preserved after removal. runnableExamples: - import std/[sequtils, enumerate, sugar] - var a = [0, 1, 2].toSinglyLinkedList - let n = a.head.next - assert n.value == 1 + var + a = initDoublyLinkedList[int]() + n = newDoublyLinkedNode[int](5) + a.append(n) + assert 5 in a a.remove(n) - assert a.toSeq == [0, 2] - a.remove(n) - assert a.toSeq == [0, 2] - a.addMoved(a) # cycle: [0, 2, 0, 2, ...] - a.remove(a.head) - let s = collect: - for i, ai in enumerate(a): - if i == 4: break - ai - assert s == [2, 2, 2, 2] + assert 5 notin a if n == L.tail: L.tail = n.prev if n == L.head: L.head = n.next @@ -772,57 +541,59 @@ proc remove*[T](L: var DoublyLinkedList[T], n: DoublyLinkedNode[T]) = -proc add*[T](L: var SinglyLinkedRing[T], n: SinglyLinkedNode[T]) = +proc append*[T](L: var SinglyLinkedRing[T], n: SinglyLinkedNode[T]) = ## Appends (adds to the end) a node `n` to `L`. Efficiency: O(1). ## - ## **See also:** - ## * `add proc <#add,SinglyLinkedRing[T],T>`_ for appending a value + ## See also: + ## * `append proc <#append,SinglyLinkedRing[T],T>`_ for appending a value ## * `prepend proc <#prepend,SinglyLinkedRing[T],SinglyLinkedNode[T]>`_ ## for prepending a node ## * `prepend proc <#prepend,SinglyLinkedRing[T],T>`_ for prepending a value runnableExamples: - var a = initSinglyLinkedRing[int]() - let n = newSinglyLinkedNode[int](9) - a.add(n) + var + a = initSinglyLinkedRing[int]() + n = newSinglyLinkedNode[int](9) + a.append(n) assert a.contains(9) if L.head != nil: n.next = L.head assert(L.tail != nil) L.tail.next = n + L.tail = n else: n.next = n L.head = n - L.tail = n + L.tail = n -proc add*[T](L: var SinglyLinkedRing[T], value: T) = +proc append*[T](L: var SinglyLinkedRing[T], value: T) = ## Appends (adds to the end) a value to `L`. Efficiency: O(1). ## - ## **See also:** - ## * `add proc <#add,SinglyLinkedRing[T],SinglyLinkedNode[T]>`_ + ## See also: + ## * `append proc <#append,SinglyLinkedRing[T],SinglyLinkedNode[T]>`_ ## for appending a node ## * `prepend proc <#prepend,SinglyLinkedRing[T],SinglyLinkedNode[T]>`_ ## for prepending a node ## * `prepend proc <#prepend,SinglyLinkedRing[T],T>`_ for prepending a value runnableExamples: var a = initSinglyLinkedRing[int]() - a.add(9) - a.add(8) + a.append(9) + a.append(8) assert a.contains(9) - - add(L, newSinglyLinkedNode(value)) + append(L, newSinglyLinkedNode(value)) proc prepend*[T](L: var SinglyLinkedRing[T], n: SinglyLinkedNode[T]) = ## Prepends (adds to the beginning) a node `n` to `L`. Efficiency: O(1). ## - ## **See also:** - ## * `add proc <#add,SinglyLinkedRing[T],SinglyLinkedNode[T]>`_ + ## See also: + ## * `append proc <#append,SinglyLinkedRing[T],SinglyLinkedNode[T]>`_ ## for appending a node - ## * `add proc <#add,SinglyLinkedRing[T],T>`_ for appending a value + ## * `append proc <#append,SinglyLinkedRing[T],T>`_ for appending a value ## * `prepend proc <#prepend,SinglyLinkedRing[T],T>`_ for prepending a value runnableExamples: - var a = initSinglyLinkedRing[int]() - let n = newSinglyLinkedNode[int](9) + var + a = initSinglyLinkedRing[int]() + n = newSinglyLinkedNode[int](9) a.prepend(n) assert a.contains(9) @@ -838,10 +609,10 @@ proc prepend*[T](L: var SinglyLinkedRing[T], n: SinglyLinkedNode[T]) = proc prepend*[T](L: var SinglyLinkedRing[T], value: T) = ## Prepends (adds to the beginning) a value to `L`. Efficiency: O(1). ## - ## **See also:** - ## * `add proc <#add,SinglyLinkedRing[T],SinglyLinkedNode[T]>`_ + ## See also: + ## * `append proc <#append,SinglyLinkedRing[T],SinglyLinkedNode[T]>`_ ## for appending a node - ## * `add proc <#add,SinglyLinkedRing[T],T>`_ for appending a value + ## * `append proc <#append,SinglyLinkedRing[T],T>`_ for appending a value ## * `prepend proc <#prepend,SinglyLinkedRing[T],SinglyLinkedNode[T]>`_ ## for prepending a node runnableExamples: @@ -849,25 +620,25 @@ proc prepend*[T](L: var SinglyLinkedRing[T], value: T) = a.prepend(9) a.prepend(8) assert a.contains(9) - prepend(L, newSinglyLinkedNode(value)) -proc add*[T](L: var DoublyLinkedRing[T], n: DoublyLinkedNode[T]) = +proc append*[T](L: var DoublyLinkedRing[T], n: DoublyLinkedNode[T]) = ## Appends (adds to the end) a node `n` to `L`. Efficiency: O(1). ## - ## **See also:** - ## * `add proc <#add,DoublyLinkedRing[T],T>`_ for appending a value + ## See also: + ## * `append proc <#append,DoublyLinkedRing[T],T>`_ for appending a value ## * `prepend proc <#prepend,DoublyLinkedRing[T],DoublyLinkedNode[T]>`_ ## for prepending a node ## * `prepend proc <#prepend,DoublyLinkedRing[T],T>`_ for prepending a value ## * `remove proc <#remove,DoublyLinkedRing[T],DoublyLinkedNode[T]>`_ ## for removing a node runnableExamples: - var a = initDoublyLinkedRing[int]() - let n = newDoublyLinkedNode[int](9) - a.add(n) + var + a = initDoublyLinkedRing[int]() + n = newDoublyLinkedNode[int](9) + a.append(n) assert a.contains(9) if L.head != nil: @@ -880,11 +651,11 @@ proc add*[T](L: var DoublyLinkedRing[T], n: DoublyLinkedNode[T]) = n.next = n L.head = n -proc add*[T](L: var DoublyLinkedRing[T], value: T) = +proc append*[T](L: var DoublyLinkedRing[T], value: T) = ## Appends (adds to the end) a value to `L`. Efficiency: O(1). ## - ## **See also:** - ## * `add proc <#add,DoublyLinkedRing[T],DoublyLinkedNode[T]>`_ + ## See also: + ## * `append proc <#append,DoublyLinkedRing[T],DoublyLinkedNode[T]>`_ ## for appending a node ## * `prepend proc <#prepend,DoublyLinkedRing[T],DoublyLinkedNode[T]>`_ ## for prepending a node @@ -893,25 +664,25 @@ proc add*[T](L: var DoublyLinkedRing[T], value: T) = ## for removing a node runnableExamples: var a = initDoublyLinkedRing[int]() - a.add(9) - a.add(8) + a.append(9) + a.append(8) assert a.contains(9) - - add(L, newDoublyLinkedNode(value)) + append(L, newDoublyLinkedNode(value)) proc prepend*[T](L: var DoublyLinkedRing[T], n: DoublyLinkedNode[T]) = ## Prepends (adds to the beginning) a node `n` to `L`. Efficiency: O(1). ## - ## **See also:** - ## * `add proc <#add,DoublyLinkedRing[T],DoublyLinkedNode[T]>`_ + ## See also: + ## * `append proc <#append,DoublyLinkedRing[T],DoublyLinkedNode[T]>`_ ## for appending a node - ## * `add proc <#add,DoublyLinkedRing[T],T>`_ for appending a value + ## * `append proc <#append,DoublyLinkedRing[T],T>`_ for appending a value ## * `prepend proc <#prepend,DoublyLinkedRing[T],T>`_ for prepending a value ## * `remove proc <#remove,DoublyLinkedRing[T],DoublyLinkedNode[T]>`_ ## for removing a node runnableExamples: - var a = initDoublyLinkedRing[int]() - let n = newDoublyLinkedNode[int](9) + var + a = initDoublyLinkedRing[int]() + n = newDoublyLinkedNode[int](9) a.prepend(n) assert a.contains(9) @@ -928,10 +699,10 @@ proc prepend*[T](L: var DoublyLinkedRing[T], n: DoublyLinkedNode[T]) = proc prepend*[T](L: var DoublyLinkedRing[T], value: T) = ## Prepends (adds to the beginning) a value to `L`. Efficiency: O(1). ## - ## **See also:** - ## * `add proc <#add,DoublyLinkedRing[T],DoublyLinkedNode[T]>`_ + ## See also: + ## * `append proc <#append,DoublyLinkedRing[T],DoublyLinkedNode[T]>`_ ## for appending a node - ## * `add proc <#add,DoublyLinkedRing[T],T>`_ for appending a value + ## * `append proc <#append,DoublyLinkedRing[T],T>`_ for appending a value ## * `prepend proc <#prepend,DoublyLinkedRing[T],DoublyLinkedNode[T]>`_ ## for prepending a node ## * `remove proc <#remove,DoublyLinkedRing[T],DoublyLinkedNode[T]>`_ @@ -941,17 +712,15 @@ proc prepend*[T](L: var DoublyLinkedRing[T], value: T) = a.prepend(9) a.prepend(8) assert a.contains(9) - prepend(L, newDoublyLinkedNode(value)) proc remove*[T](L: var DoublyLinkedRing[T], n: DoublyLinkedNode[T]) = ## Removes `n` from `L`. Efficiency: O(1). - ## This function assumes, for the sake of efficiency, that `n` is contained in `L`, - ## otherwise the effects are undefined. runnableExamples: - var a = initDoublyLinkedRing[int]() - let n = newDoublyLinkedNode[int](5) - a.add(n) + var + a = initDoublyLinkedRing[int]() + n = newDoublyLinkedNode[int](5) + a.append(n) assert 5 in a a.remove(n) assert 5 notin a @@ -959,37 +728,9 @@ proc remove*[T](L: var DoublyLinkedRing[T], n: DoublyLinkedNode[T]) = n.next.prev = n.prev n.prev.next = n.next if n == L.head: - let p = L.head.prev + var p = L.head.prev if p == L.head: # only one element left: L.head = nil else: - L.head = p - -proc append*[T](a: var (SinglyLinkedList[T] | SinglyLinkedRing[T]), - b: SinglyLinkedList[T] | SinglyLinkedNode[T] | T) = - ## Alias for `a.add(b)`. - ## - ## **See also:** - ## * `add proc <#add,SinglyLinkedList[T],SinglyLinkedNode[T]>`_ - ## * `add proc <#add,SinglyLinkedList[T],T>`_ - ## * `add proc <#add,T,T>`_ - a.add(b) - -proc append*[T](a: var (DoublyLinkedList[T] | DoublyLinkedRing[T]), - b: DoublyLinkedList[T] | DoublyLinkedNode[T] | T) = - ## Alias for `a.add(b)`. - ## - ## **See also:** - ## * `add proc <#add,DoublyLinkedList[T],DoublyLinkedNode[T]>`_ - ## * `add proc <#add,DoublyLinkedList[T],T>`_ - ## * `add proc <#add,T,T>`_ - a.add(b) - -proc appendMoved*[T: SomeLinkedList](a, b: var T) {.since: (1, 5, 1).} = - ## Alias for `a.addMoved(b)`. - ## - ## **See also:** - ## * `addMoved proc <#addMoved,SinglyLinkedList[T],SinglyLinkedList[T]>`_ - ## * `addMoved proc <#addMoved,DoublyLinkedList[T],DoublyLinkedList[T]>`_ - a.addMoved(b) + L.head = L.head.prev diff --git a/lib/pure/collections/sequtils.nim b/lib/pure/collections/sequtils.nim index 1773e827b..d56742ba9 100644 --- a/lib/pure/collections/sequtils.nim +++ b/lib/pure/collections/sequtils.nim @@ -7,19 +7,19 @@ # distribution, for details about the copyright. # -## Although this module has `seq` in its name, it implements operations -## not only for the `seq`:idx: type, but for three built-in container types -## under the `openArray` umbrella: +## Although this module has ``seq`` in its name, it implements operations +## not only for `seq`:idx: type, but for three built-in container types under +## the ``openArray`` umbrella: ## * sequences ## * strings ## * array ## -## The `system` module defines several common functions, such as: -## * `newSeq[T]` for creating new sequences of type `T` -## * `@` for converting arrays and strings to sequences -## * `add` for adding new elements to strings and sequences -## * `&` for string and seq concatenation -## * `in` (alias for `contains`) and `notin` for checking if an item is +## The system module defines several common functions, such as: +## * ``newSeq[T]`` for creating new sequences of type ``T`` +## * ``@`` for converting arrays and strings to sequences +## * ``add`` for adding new elements to strings and sequences +## * ``&`` for string and seq concatenation +## * ``in`` (alias for ``contains``) and ``notin`` for checking if an item is ## in a container ## ## This module builds upon that, providing additional functionality in form of @@ -27,52 +27,45 @@ ## languages. ## ## For functional style programming you have different options at your disposal: -## * the `sugar.collect macro`_ -## * pass an `anonymous proc`_ -## * import the `sugar module`_ and use -## the `=> macro.m,untyped,untyped>`_ +## * pass `anonymous proc`_ +## * import `sugar module`_ and use +## `=> macro.m,untyped,untyped>`_ ## * use `...It templates<#18>`_ ## (`mapIt<#mapIt.t,typed,untyped>`_, ## `filterIt<#filterIt.t,untyped,untyped>`_, etc.) ## -## Chaining of functions is possible thanks to the +## The chaining of functions is possible thanks to the ## `method call syntax`_. - -runnableExamples: - import std/sugar - - # Creating a sequence from 1 to 10, multiplying each member by 2, - # keeping only the members which are not divisible by 6. - let - foo = toSeq(1..10).map(x => x * 2).filter(x => x mod 6 != 0) - bar = toSeq(1..10).mapIt(it * 2).filterIt(it mod 6 != 0) - baz = collect: - for i in 1..10: - let j = 2 * i - if j mod 6 != 0: - j - - doAssert foo == bar - doAssert foo == baz - doAssert foo == @[2, 4, 8, 10, 14, 16, 20] - - doAssert foo.any(x => x > 17) - doAssert not bar.allIt(it < 20) - doAssert foo.foldl(a + b) == 74 # sum of all members - - -runnableExamples: - from std/strutils import join - - let - vowels = @"aeiou" - foo = "sequtils is an awesome module" - - doAssert (vowels is seq[char]) and (vowels == @['a', 'e', 'i', 'o', 'u']) - doAssert foo.filterIt(it notin vowels).join == "sqtls s n wsm mdl" - -## See also -## ======== +## +## .. code-block:: +## import sequtils, sugar +## +## # Creating a sequence from 1 to 10, multiplying each member by 2, +## # keeping only the members which are not divisible by 6. +## let +## foo = toSeq(1..10).map(x => x*2).filter(x => x mod 6 != 0) +## bar = toSeq(1..10).mapIt(it*2).filterIt(it mod 6 != 0) +## +## doAssert foo == bar +## echo foo # @[2, 4, 8, 10, 14, 16, 20] +## +## echo foo.any(x => x > 17) # true +## echo bar.allIt(it < 20) # false +## echo foo.foldl(a + b) # 74; sum of all members +## +## .. code-block:: +## import sequtils +## from strutils import join +## +## let +## vowels = @"aeiou" # creates a sequence @['a', 'e', 'i', 'o', 'u'] +## foo = "sequtils is an awesome module" +## +## echo foo.filterIt(it notin vowels).join # "sqtls s n wsm mdl" +## +## ---- +## +## **See also**: ## * `strutils module`_ for common string functions ## * `sugar module`_ for syntactic sugar macros ## * `algorithm module`_ for common generic algorithms @@ -80,27 +73,22 @@ runnableExamples: ## heterogeneous members -import std/private/since +include "system/inclrtl" import macros -when defined(nimPreviewSlimSystem): - import std/assertions +when not defined(nimhygiene): + {.pragma: dirty.} -when defined(nimHasEffectsOf): - {.experimental: "strictEffects".} -else: - {.pragma: effectsOf.} - macro evalOnceAs(expAlias, exp: untyped, letAssigneable: static[bool]): untyped = - ## Injects `expAlias` in caller scope, to avoid bugs involving multiple - ## substitution in macro arguments such as - ## https://github.com/nim-lang/Nim/issues/7187. - ## `evalOnceAs(myAlias, myExp)` will behave as `let myAlias = myExp` - ## except when `letAssigneable` is false (e.g. to handle openArray) where - ## it just forwards `exp` unchanged. + ## Injects ``expAlias`` in caller scope, to avoid bugs involving multiple + ## substitution in macro arguments such as + ## https://github.com/nim-lang/Nim/issues/7187 + ## ``evalOnceAs(myAlias, myExp)`` will behave as ``let myAlias = myExp`` + ## except when ``letAssigneable`` is false (e.g. to handle openArray) where + ## it just forwards ``exp`` unchanged expectKind(expAlias, nnkIdent) var val = exp @@ -115,12 +103,12 @@ macro evalOnceAs(expAlias, exp: untyped, newProc(name = genSym(nskTemplate, $expAlias), params = [getType(untyped)], body = val, procType = nnkTemplateDef)) -func concat*[T](seqs: varargs[seq[T]]): seq[T] = +proc concat*[T](seqs: varargs[seq[T]]): seq[T] = ## Takes several sequences' items and returns them inside a new sequence. ## All sequences must be of the same type. ## - ## **See also:** - ## * `distribute func<#distribute,seq[T],Positive>`_ for a reverse + ## See also: + ## * `distribute proc<#distribute,seq[T],Positive>`_ for a reverse ## operation ## runnableExamples: @@ -140,7 +128,7 @@ func concat*[T](seqs: varargs[seq[T]]): seq[T] = result[i] = itm inc(i) -func count*[T](s: openArray[T], x: T): int = +proc count*[T](s: openArray[T], x: T): int = ## Returns the number of occurrences of the item `x` in the container `s`. ## runnableExamples: @@ -155,7 +143,7 @@ func count*[T](s: openArray[T], x: T): int = if itm == x: inc result -func cycle*[T](s: openArray[T], n: Natural): seq[T] = +proc cycle*[T](s: openArray[T], n: Natural): seq[T] = ## Returns a new sequence with the items of the container `s` repeated ## `n` times. ## `n` must be a non-negative number (zero or more). @@ -186,10 +174,10 @@ proc repeat*[T](x: T, n: Natural): seq[T] = for i in 0 ..< n: result[i] = x -func deduplicate*[T](s: openArray[T], isSorted: bool = false): seq[T] = +proc deduplicate*[T](s: openArray[T], isSorted: bool = false): seq[T] = ## Returns a new sequence without duplicates. ## - ## Setting the optional argument `isSorted` to true (default: false) + ## Setting the optional argument ``isSorted`` to ``true`` (default: false) ## uses a faster algorithm for deduplication. ## runnableExamples: @@ -214,9 +202,9 @@ func deduplicate*[T](s: openArray[T], isSorted: bool = false): seq[T] = for itm in items(s): if not result.contains(itm): result.add(itm) -func minIndex*[T](s: openArray[T]): int {.since: (1, 1).} = +proc minIndex*[T](s: openArray[T]): int {.since: (1, 1).} = ## Returns the index of the minimum value of `s`. - ## `T` needs to have a `<` operator. + ## ``T`` needs to have a ``<`` operator. runnableExamples: let a = @[1, 2, 3, 4] @@ -231,9 +219,9 @@ func minIndex*[T](s: openArray[T]): int {.since: (1, 1).} = for i in 1..high(s): if s[i] < s[result]: result = i -func maxIndex*[T](s: openArray[T]): int {.since: (1, 1).} = +proc maxIndex*[T](s: openArray[T]): int {.since: (1, 1).} = ## Returns the index of the maximum value of `s`. - ## `T` needs to have a `<` operator. + ## ``T`` needs to have a ``<`` operator. runnableExamples: let a = @[1, 2, 3, 4] @@ -257,9 +245,9 @@ template zipImpl(s1, s2, retType: untyped): untyped = ## If one container is shorter, the remaining items in the longer container ## are discarded. ## - ## **Note**: For Nim 1.0.x and older version, `zip` returned a seq of - ## named tuples with fields `a` and `b`. For Nim versions 1.1.x and newer, - ## `zip` returns a seq of unnamed tuples. + ## **Note**: For Nim 1.0.x and older version, ``zip`` returned a seq of + ## named tuple with fields ``a`` and ``b``. For Nim versions 1.1.x and newer, + ## ``zip`` returns a seq of unnamed tuples. runnableExamples: let short = @[1, 2, 3] @@ -293,33 +281,19 @@ when (NimMajor, NimMinor) <= (1, 0): else: zipImpl(s1, s2, seq[(S, T)]) -proc unzip*[S, T](s: openArray[(S, T)]): (seq[S], seq[T]) {.since: (1, 1).} = - ## Returns a tuple of two sequences split out from a sequence of 2-field tuples. - runnableExamples: - let - zipped = @[(1, 'a'), (2, 'b'), (3, 'c')] - unzipped1 = @[1, 2, 3] - unzipped2 = @['a', 'b', 'c'] - assert zipped.unzip() == (unzipped1, unzipped2) - assert zip(unzipped1, unzipped2).unzip() == (unzipped1, unzipped2) - result = (newSeq[S](s.len), newSeq[T](s.len)) - for i in 0..`_ func. + ## inverse of the `concat <#concat,varargs[seq[T]]>`_ proc. ## The input sequence `s` can be empty, which will produce ## `num` empty sequences. ## ## If `spread` is false and the length of `s` is not a multiple of `num`, the - ## func will max out the first sub-sequence with `1 + len(s) div num` + ## proc will max out the first sub-sequence with ``1 + len(s) div num`` ## entries, leaving the remainder of elements to the last sequence. ## - ## On the other hand, if `spread` is true, the func will distribute evenly + ## On the other hand, if `spread` is true, the proc will distribute evenly ## the remainder of the division across all sequences, which makes the result ## more suited to multithreading where you are passing equal sized work units ## to a thread pool and want to maximize core usage. @@ -334,6 +308,7 @@ func distribute*[T](s: seq[T], num: Positive, spread = true): seq[seq[T]] = if num < 2: result = @[s] return + let num = int(num) # XXX probably only needed because of .. bug # Create the result and calculate the stride size and the remainder if any. result = newSeq[seq[T]](num) @@ -364,18 +339,14 @@ func distribute*[T](s: seq[T], num: Positive, spread = true): seq[seq[T]] = first = last proc map*[T, S](s: openArray[T], op: proc (x: T): S {.closure.}): - seq[S] {.inline, effectsOf: op.} = - ## Returns a new sequence with the results of the `op` proc applied to every + seq[S]{.inline.} = + ## Returns a new sequence with the results of `op` proc applied to every ## item in the container `s`. ## - ## Since the input is not modified, you can use it to + ## Since the input is not modified you can use it to ## transform the type of the elements in the input container. ## - ## Instead of using `map` and `filter`, consider using the `collect` macro - ## from the `sugar` module. - ## - ## **See also:** - ## * `sugar.collect macro`_ + ## See also: ## * `mapIt template<#mapIt.t,typed,untyped>`_ ## * `apply proc<#apply,openArray[T],proc(T)_2>`_ for the in-place version ## @@ -390,14 +361,15 @@ proc map*[T, S](s: openArray[T], op: proc (x: T): S {.closure.}): result[i] = op(s[i]) proc apply*[T](s: var openArray[T], op: proc (x: var T) {.closure.}) - {.inline, effectsOf: op.} = - ## Applies `op` to every item in `s`, modifying it directly. + {.inline.} = + ## Applies `op` to every item in `s` modifying it directly. ## - ## Note that the container `s` must be declared as a `var`, - ## since `s` is modified in-place. - ## The parameter function takes a `var T` type parameter. + ## Note that container `s` must be declared as a ``var`` + ## and it is required for your input and output types to + ## be the same, since `s` is modified in-place. + ## The parameter function takes a ``var T`` type parameter. ## - ## **See also:** + ## See also: ## * `applyIt template<#applyIt.t,untyped,untyped>`_ ## * `map proc<#map,openArray[T],proc(T)>`_ ## @@ -409,15 +381,15 @@ proc apply*[T](s: var openArray[T], op: proc (x: var T) {.closure.}) for i in 0 ..< s.len: op(s[i]) proc apply*[T](s: var openArray[T], op: proc (x: T): T {.closure.}) - {.inline, effectsOf: op.} = + {.inline.} = ## Applies `op` to every item in `s` modifying it directly. ## - ## Note that the container `s` must be declared as a `var` + ## Note that container `s` must be declared as a ``var`` ## and it is required for your input and output types to ## be the same, since `s` is modified in-place. - ## The parameter function takes and returns a `T` type variable. + ## The parameter function takes and returns a ``T`` type variable. ## - ## **See also:** + ## See also: ## * `applyIt template<#applyIt.t,untyped,untyped>`_ ## * `map proc<#map,openArray[T],proc(T)>`_ ## @@ -428,25 +400,12 @@ proc apply*[T](s: var openArray[T], op: proc (x: T): T {.closure.}) for i in 0 ..< s.len: s[i] = op(s[i]) -proc apply*[T](s: openArray[T], op: proc (x: T) {.closure.}) {.inline, since: (1, 3), effectsOf: op.} = - ## Same as `apply` but for a proc that does not return anything - ## and does not mutate `s` directly. - runnableExamples: - var message: string - apply([0, 1, 2, 3, 4], proc(item: int) = message.addInt item) - assert message == "01234" - for i in 0 ..< s.len: op(s[i]) - -iterator filter*[T](s: openArray[T], pred: proc(x: T): bool {.closure.}): T {.effectsOf: pred.} = +iterator filter*[T](s: openArray[T], pred: proc(x: T): bool {.closure.}): T = ## Iterates through a container `s` and yields every item that fulfills the - ## predicate `pred` (a function that returns a `bool`). + ## predicate `pred` (function that returns a `bool`). ## - ## Instead of using `map` and `filter`, consider using the `collect` macro - ## from the `sugar` module. - ## - ## **See also:** - ## * `sugar.collect macro`_ - ## * `filter proc<#filter,openArray[T],proc(T)>`_ + ## See also: + ## * `fliter proc<#filter,openArray[T],proc(T)>`_ ## * `filterIt template<#filterIt.t,untyped,untyped>`_ ## runnableExamples: @@ -461,15 +420,11 @@ iterator filter*[T](s: openArray[T], pred: proc(x: T): bool {.closure.}): T {.ef yield s[i] proc filter*[T](s: openArray[T], pred: proc(x: T): bool {.closure.}): seq[T] - {.inline, effectsOf: pred.} = - ## Returns a new sequence with all the items of `s` that fulfill the - ## predicate `pred` (a function that returns a `bool`). + {.inline.} = + ## Returns a new sequence with all the items of `s` that fulfilled the + ## predicate `pred` (function that returns a `bool`). ## - ## Instead of using `map` and `filter`, consider using the `collect` macro - ## from the `sugar` module. - ## - ## **See also:** - ## * `sugar.collect macro`_ + ## See also: ## * `filterIt template<#filterIt.t,untyped,untyped>`_ ## * `filter iterator<#filter.i,openArray[T],proc(T)>`_ ## * `keepIf proc<#keepIf,seq[T],proc(T)>`_ for the in-place version @@ -488,16 +443,16 @@ proc filter*[T](s: openArray[T], pred: proc(x: T): bool {.closure.}): seq[T] result.add(s[i]) proc keepIf*[T](s: var seq[T], pred: proc(x: T): bool {.closure.}) - {.inline, effectsOf: pred.} = - ## Keeps the items in the passed sequence `s` if they fulfill the - ## predicate `pred` (a function that returns a `bool`). + {.inline.} = + ## Keeps the items in the passed sequence `s` if they fulfilled the + ## predicate `pred` (function that returns a `bool`). ## - ## Note that `s` must be declared as a `var`. + ## Note that `s` must be declared as a ``var``. ## ## Similar to the `filter proc<#filter,openArray[T],proc(T)>`_, ## but modifies the sequence directly. ## - ## **See also:** + ## See also: ## * `keepItIf template<#keepItIf.t,seq,untyped>`_ ## * `filter proc<#filter,openArray[T],proc(T)>`_ ## @@ -517,51 +472,12 @@ proc keepIf*[T](s: var seq[T], pred: proc(x: T): bool {.closure.}) inc(pos) setLen(s, pos) -func delete*[T](s: var seq[T]; slice: Slice[int]) = - ## Deletes the items `s[slice]`, raising `IndexDefect` if the slice contains - ## elements out of range. - ## - ## This operation moves all elements after `s[slice]` in linear time. - runnableExamples: - var a = @[10, 11, 12, 13, 14] - doAssertRaises(IndexDefect): a.delete(4..5) - assert a == @[10, 11, 12, 13, 14] - a.delete(4..4) - assert a == @[10, 11, 12, 13] - a.delete(1..2) - assert a == @[10, 13] - a.delete(1..<1) # empty slice - assert a == @[10, 13] - when compileOption("boundChecks"): - if not (slice.a < s.len and slice.a >= 0 and slice.b < s.len): - raise newException(IndexDefect, $(slice: slice, len: s.len)) - if slice.b >= slice.a: - template defaultImpl = - var i = slice.a - var j = slice.b + 1 - var newLen = s.len - j + i - while i < newLen: - when defined(gcDestructors): - s[i] = move(s[j]) - else: - s[i].shallowCopy(s[j]) - inc(i) - inc(j) - setLen(s, newLen) - when nimvm: defaultImpl() - else: - when defined(js): - let n = slice.b - slice.a + 1 - let first = slice.a - {.emit: "`s`.splice(`first`, `n`);".} - else: - defaultImpl() - -func delete*[T](s: var seq[T]; first, last: Natural) {.deprecated: "use `delete(s, first..last)`".} = - ## Deletes the items of a sequence `s` at positions `first..last` - ## (including both ends of the range). +proc delete*[T](s: var seq[T]; first, last: Natural) = + ## Deletes in the items of a sequence `s` at positions ``first..last`` + ## (including both ends of a range). ## This modifies `s` itself, it does not return a copy. - runnableExamples("--warning:deprecated:off"): + ## + runnableExamples: let outcome = @[1, 1, 1, 1, 1, 1, 1, 1] var dest = @[1, 1, 1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1] dest.delete(3, 8) @@ -570,8 +486,8 @@ func delete*[T](s: var seq[T]; first, last: Natural) {.deprecated: "use `delete( if first >= s.len: return var i = first - var j = min(len(s), last + 1) - var newLen = len(s) - j + i + var j = min(len(s), last+1) + var newLen = len(s)-j+i while i < newLen: when defined(gcDestructors): s[i] = move(s[j]) @@ -581,11 +497,11 @@ func delete*[T](s: var seq[T]; first, last: Natural) {.deprecated: "use `delete( inc(j) setLen(s, newLen) -func insert*[T](dest: var seq[T], src: openArray[T], pos = 0) = +proc insert*[T](dest: var seq[T], src: openArray[T], pos = 0) = ## Inserts items from `src` into `dest` at position `pos`. This modifies ## `dest` itself, it does not return a copy. ## - ## Note that the elements of `src` and `dest` must be of the same type. + ## Notice that `src` and `dest` must be of the same type. ## runnableExamples: var dest = @[1, 1, 1, 1, 1, 1, 1, 1] @@ -596,8 +512,7 @@ func insert*[T](dest: var seq[T], src: openArray[T], pos = 0) = assert dest == outcome var j = len(dest) - 1 - var i = j + len(src) - if i == j: return + var i = len(dest) + len(src) - 1 dest.setLen(i + 1) # Move items after `pos` to the end of the sequence. @@ -616,20 +531,16 @@ func insert*[T](dest: var seq[T], src: openArray[T], pos = 0) = template filterIt*(s, pred: untyped): untyped = - ## Returns a new sequence with all the items of `s` that fulfill the + ## Returns a new sequence with all the items of `s` that fulfilled the ## predicate `pred`. ## ## Unlike the `filter proc<#filter,openArray[T],proc(T)>`_ and ## `filter iterator<#filter.i,openArray[T],proc(T)>`_, - ## the predicate needs to be an expression using the `it` variable - ## for testing, like: `filterIt("abcxyz", it == 'x')`. + ## the predicate needs to be an expression using the ``it`` variable + ## for testing, like: ``filterIt("abcxyz", it == 'x')``. ## - ## Instead of using `mapIt` and `filterIt`, consider using the `collect` macro - ## from the `sugar` module. - ## - ## **See also:** - ## * `sugar.collect macro`_ - ## * `filter proc<#filter,openArray[T],proc(T)>`_ + ## See also: + ## * `fliter proc<#filter,openArray[T],proc(T)>`_ ## * `filter iterator<#filter.i,openArray[T],proc(T)>`_ ## runnableExamples: @@ -640,20 +551,20 @@ template filterIt*(s, pred: untyped): untyped = assert acceptable == @[-2.0, 24.5, 44.31] assert notAcceptable == @[-272.15, 99.9, -113.44] - var result = newSeq[typeof(s[0])]() + var result = newSeq[type(s[0])]() for it {.inject.} in items(s): if pred: result.add(it) result template keepItIf*(varSeq: seq, pred: untyped) = - ## Keeps the items in the passed sequence (must be declared as a `var`) - ## if they fulfill the predicate. + ## Keeps the items in the passed sequence (must be declared as a ``var``) + ## if they fulfilled the predicate. ## ## Unlike the `keepIf proc<#keepIf,seq[T],proc(T)>`_, ## the predicate needs to be an expression using - ## the `it` variable for testing, like: `keepItIf("abcxyz", it == 'x')`. + ## the ``it`` variable for testing, like: ``keepItIf("abcxyz", it == 'x')``. ## - ## **See also:** + ## See also: ## * `keepIf proc<#keepIf,seq[T],proc(T)>`_ ## * `filterIt template<#filterIt.t,untyped,untyped>`_ ## @@ -674,42 +585,23 @@ template keepItIf*(varSeq: seq, pred: untyped) = inc(pos) setLen(varSeq, pos) -since (1, 1): - template countIt*(s, pred: untyped): int = - ## Returns a count of all the items that fulfill the predicate. - ## - ## The predicate needs to be an expression using - ## the `it` variable for testing, like: `countIt(@[1, 2, 3], it > 2)`. - ## - runnableExamples: - let numbers = @[-3, -2, -1, 0, 1, 2, 3, 4, 5, 6] - iterator iota(n: int): int = - for i in 0..`_ ## * `any proc<#any,openArray[T],proc(T)>`_ ## runnableExamples: let numbers = @[1, 4, 5, 8, 9, 7, 4] - assert all(numbers, proc (x: int): bool = x < 10) == true - assert all(numbers, proc (x: int): bool = x < 9) == false + assert all(numbers, proc (x: int): bool = return x < 10) == true + assert all(numbers, proc (x: int): bool = return x < 9) == false for i in s: if not pred(i): return false - true + return true template allIt*(s, pred: untyped): bool = ## Iterates through a container and checks if every item fulfills the @@ -717,9 +609,9 @@ template allIt*(s, pred: untyped): bool = ## ## Unlike the `all proc<#all,openArray[T],proc(T)>`_, ## the predicate needs to be an expression using - ## the `it` variable for testing, like: `allIt("abba", it == 'a')`. + ## the ``it`` variable for testing, like: ``allIt("abba", it == 'a')``. ## - ## **See also:** + ## See also: ## * `all proc<#all,openArray[T],proc(T)>`_ ## * `anyIt template<#anyIt.t,untyped,untyped>`_ ## @@ -735,33 +627,33 @@ template allIt*(s, pred: untyped): bool = break result -proc any*[T](s: openArray[T], pred: proc(x: T): bool {.closure.}): bool {.effectsOf: pred.} = - ## Iterates through a container and checks if at least one item - ## fulfills the predicate. +proc any*[T](s: openArray[T], pred: proc(x: T): bool {.closure.}): bool = + ## Iterates through a container and checks if some item fulfills the + ## predicate. ## - ## **See also:** + ## See also: ## * `anyIt template<#anyIt.t,untyped,untyped>`_ ## * `all proc<#all,openArray[T],proc(T)>`_ ## runnableExamples: let numbers = @[1, 4, 5, 8, 9, 7, 4] - assert any(numbers, proc (x: int): bool = x > 8) == true - assert any(numbers, proc (x: int): bool = x > 9) == false + assert any(numbers, proc (x: int): bool = return x > 8) == true + assert any(numbers, proc (x: int): bool = return x > 9) == false for i in s: if pred(i): return true - false + return false template anyIt*(s, pred: untyped): bool = - ## Iterates through a container and checks if at least one item - ## fulfills the predicate. + ## Iterates through a container and checks if some item fulfills the + ## predicate. ## ## Unlike the `any proc<#any,openArray[T],proc(T)>`_, ## the predicate needs to be an expression using - ## the `it` variable for testing, like: `anyIt("abba", it == 'a')`. + ## the ``it`` variable for testing, like: ``anyIt("abba", it == 'a')``. ## - ## **See also:** + ## See also: ## * `any proc<#any,openArray[T],proc(T)>`_ ## * `allIt template<#allIt.t,untyped,untyped>`_ ## @@ -779,7 +671,7 @@ template anyIt*(s, pred: untyped): bool = template toSeq1(s: not iterator): untyped = # overload for typed but not iterator - type OutType = typeof(items(s)) + type OutType = type(items(s)) when compiles(s.len): block: evalOnceAs(s2, s, compiles((let _ = s))) @@ -790,7 +682,7 @@ template toSeq1(s: not iterator): untyped = i += 1 result else: - var result: seq[OutType]# = @[] + var result: seq[OutType] = @[] for it in s: result.add(it) result @@ -800,14 +692,14 @@ template toSeq2(iter: iterator): untyped = evalOnceAs(iter2, iter(), false) when compiles(iter2.len): var i = 0 - var result = newSeq[typeof(iter2)](iter2.len) + var result = newSeq[type(iter2)](iter2.len) for x in iter2: result[i] = x inc i result else: - type OutType = typeof(iter2()) - var result: seq[OutType]# = @[] + type OutType = type(iter2()) + var result: seq[OutType] = @[] when compiles(iter2()): evalOnceAs(iter4, iter, false) let iter3 = iter4() @@ -826,8 +718,8 @@ template toSeq*(iter: untyped): untyped = let myRange = 1..5 mySet: set[int8] = {5'i8, 3, 1} - assert typeof(myRange) is HSlice[system.int, system.int] - assert typeof(mySet) is set[int8] + assert type(myRange) is HSlice[system.int, system.int] + assert type(mySet) is set[int8] let mySeq1 = toSeq(myRange) @@ -844,14 +736,14 @@ template toSeq*(iter: untyped): untyped = when compiles(iter.len): block: evalOnceAs(iter2, iter, true) - var result = newSeq[typeof(iter)](iter2.len) + var result = newSeq[type(iter)](iter2.len) var i = 0 for x in iter2: result[i] = x inc i result else: - var result: seq[typeof(iter)]# = @[] + var result: seq[type(iter)] = @[] for x in iter: result.add(x) result @@ -862,15 +754,15 @@ template foldl*(sequence, operation: untyped): untyped = ## The sequence is required to have at least a single element. Debug versions ## of your program will assert in this situation but release versions will ## happily go ahead. If the sequence has a single element it will be returned - ## without applying `operation`. + ## without applying ``operation``. ## - ## The `operation` parameter should be an expression which uses the - ## variables `a` and `b` for each step of the fold. Since this is a left + ## The ``operation`` parameter should be an expression which uses the + ## variables ``a`` and ``b`` for each step of the fold. Since this is a left ## fold, for non associative binary operations like subtraction think that ## the sequence of numbers 1, 2 and 3 will be parenthesized as (((1) - 2) - ## 3). ## - ## **See also:** + ## See also: ## * `foldl template<#foldl.t,,,>`_ with a starting parameter ## * `foldr template<#foldr.t,untyped,untyped>`_ ## @@ -882,21 +774,14 @@ template foldl*(sequence, operation: untyped): untyped = multiplication = foldl(numbers, a * b) words = @["nim", "is", "cool"] concatenation = foldl(words, a & b) - procs = @["proc", "Is", "Also", "Fine"] - - - func foo(acc, cur: string): string = - result = acc & cur - assert addition == 25, "Addition is (((5)+9)+11)" assert subtraction == -15, "Subtraction is (((5)-9)-11)" assert multiplication == 495, "Multiplication is (((5)*9)*11)" assert concatenation == "nimiscool" - assert foldl(procs, foo(a, b)) == "procIsAlsoFine" let s = sequence assert s.len > 0, "Can't fold empty sequences" - var result: typeof(s[0]) + var result: type(s[0]) result = s[0] for i in 1..`_ ## runnableExamples: @@ -924,7 +809,8 @@ template foldl*(sequence, operation, first): untyped = digits = foldl(numbers, a & (chr(b + ord('0'))), "") assert digits == "0815" - var result: typeof(first) = first + var result: type(first) + result = first for x in items(sequence): let a {.inject.} = result @@ -938,15 +824,15 @@ template foldr*(sequence, operation: untyped): untyped = ## The sequence is required to have at least a single element. Debug versions ## of your program will assert in this situation but release versions will ## happily go ahead. If the sequence has a single element it will be returned - ## without applying `operation`. + ## without applying ``operation``. ## - ## The `operation` parameter should be an expression which uses the - ## variables `a` and `b` for each step of the fold. Since this is a right + ## The ``operation`` parameter should be an expression which uses the + ## variables ``a`` and ``b`` for each step of the fold. Since this is a right ## fold, for non associative binary operations like subtraction think that ## the sequence of numbers 1, 2 and 3 will be parenthesized as (1 - (2 - ## (3))). ## - ## **See also:** + ## See also: ## * `foldl template<#foldl.t,untyped,untyped>`_ ## * `foldl template<#foldl.t,,,>`_ with a starting parameter ## @@ -963,11 +849,11 @@ template foldr*(sequence, operation: untyped): untyped = assert multiplication == 495, "Multiplication is (5*(9*(11)))" assert concatenation == "nimiscool" - let s = sequence # xxx inefficient, use {.evalonce.} pending #13750 - let n = s.len - assert n > 0, "Can't fold empty sequences" - var result = s[n - 1] - for i in countdown(n - 2, 0): + let s = sequence + assert s.len > 0, "Can't fold empty sequences" + var result: type(s[0]) + result = sequence[s.len - 1] + for i in countdown(s.len - 2, 0): let a {.inject.} = s[i] b {.inject.} = result @@ -975,20 +861,16 @@ template foldr*(sequence, operation: untyped): untyped = result template mapIt*(s: typed, op: untyped): untyped = - ## Returns a new sequence with the results of the `op` proc applied to every + ## Returns a new sequence with the results of `op` proc applied to every ## item in the container `s`. ## ## Since the input is not modified you can use it to ## transform the type of the elements in the input container. ## - ## The template injects the `it` variable which you can use directly in an + ## The template injects the ``it`` variable which you can use directly in an ## expression. ## - ## Instead of using `mapIt` and `filterIt`, consider using the `collect` macro - ## from the `sugar` module. - ## - ## **See also:** - ## * `sugar.collect macro`_ + ## See also: ## * `map proc<#map,openArray[T],proc(T)>`_ ## * `applyIt template<#applyIt.t,untyped,untyped>`_ for the in-place version ## @@ -998,55 +880,43 @@ template mapIt*(s: typed, op: untyped): untyped = strings = nums.mapIt($(4 * it)) assert strings == @["4", "8", "12", "16"] - type OutType = typeof(( - block: - var it{.inject.}: typeof(items(s), typeOfIter); - op), typeOfProc) - when OutType is not (proc): - # Here, we avoid to create closures in loops. - # This avoids https://github.com/nim-lang/Nim/issues/12625 - when compiles(s.len): - block: # using a block avoids https://github.com/nim-lang/Nim/issues/8580 + when defined(nimHasTypeof): + type OutType = typeof(( + block: + var it{.inject.}: typeof(items(s), typeOfIter); + op), typeOfProc) + else: + type OutType = type(( + block: + var it{.inject.}: type(items(s)); + op)) + when compiles(s.len): + block: # using a block avoids https://github.com/nim-lang/Nim/issues/8580 - # BUG: `evalOnceAs(s2, s, false)` would lead to C compile errors - # (`error: use of undeclared identifier`) instead of Nim compile errors - evalOnceAs(s2, s, compiles((let _ = s))) + # BUG: `evalOnceAs(s2, s, false)` would lead to C compile errors + # (`error: use of undeclared identifier`) instead of Nim compile errors + evalOnceAs(s2, s, compiles((let _ = s))) - var i = 0 - var result = newSeq[OutType](s2.len) - for it {.inject.} in s2: - result[i] = op - i += 1 - result - else: - var result: seq[OutType]# = @[] - # use `items` to avoid https://github.com/nim-lang/Nim/issues/12639 - for it {.inject.} in items(s): - result.add(op) + var i = 0 + var result = newSeq[OutType](s2.len) + for it {.inject.} in s2: + result[i] = op + i += 1 result else: - # `op` is going to create closures in loops, let's fallback to `map`. - # NOTE: Without this fallback, developers have to define a helper function and - # call `map`: - # [1, 2].map((it) => ((x: int) => it + x)) - # With this fallback, above code can be simplified to: - # [1, 2].mapIt((x: int) => it + x) - # In this case, `mapIt` is just syntax sugar for `map`. - type InType = typeof(items(s), typeOfIter) - # Use a help proc `f` to create closures for each element in `s` - let f = proc (x: InType): OutType = - let it {.inject.} = x - op - map(s, f) + var result: seq[OutType] = @[] + for it {.inject.} in s: + result.add(op) + result template applyIt*(varSeq, op: untyped) = - ## Convenience template around the mutable `apply` proc to reduce typing. + ## Convenience template around the mutable ``apply`` proc to reduce typing. ## - ## The template injects the `it` variable which you can use directly in an - ## expression. The expression has to return the same type as the elements - ## of the sequence you are mutating. + ## The template injects the ``it`` variable which you can use directly in an + ## expression. The expression has to return the same type as the sequence you + ## are mutating. ## - ## **See also:** + ## See also: ## * `apply proc<#apply,openArray[T],proc(T)_2>`_ ## * `mapIt template<#mapIt.t,typed,untyped>`_ ## @@ -1061,29 +931,29 @@ template applyIt*(varSeq, op: untyped) = template newSeqWith*(len: int, init: untyped): untyped = - ## Creates a new `seq` of length `len`, calling `init` to initialize - ## each value of the seq. + ## Creates a new sequence of length `len`, calling `init` to initialize + ## each value of the sequence. + ## + ## Useful for creating "2D" sequences - sequences containing other sequences + ## or to populate fields of the created sequence. ## - ## Useful for creating "2D" seqs - seqs containing other seqs - ## or to populate fields of the created seq. runnableExamples: - ## Creates a seq containing 5 bool seqs, each of length of 3. + ## Creates a sequence containing 5 bool sequences, each of length of 3. var seq2D = newSeqWith(5, newSeq[bool](3)) assert seq2D.len == 5 assert seq2D[0].len == 3 assert seq2D[4][2] == false - ## Creates a seq with random numbers - import std/random - var seqRand = newSeqWith(20, rand(1.0)) - assert seqRand[0] != seqRand[1] + ## Creates a sequence of 20 random numbers from 1 to 10 + import random + var seqRand = newSeqWith(20, rand(10)) - var result = newSeq[typeof(init)](len) + var result = newSeq[type(init)](len) for i in 0 ..< len: result[i] = init - move(result) # refs bug #7295 + result -func mapLitsImpl(constructor: NimNode; op: NimNode; nested: bool; +proc mapLitsImpl(constructor: NimNode; op: NimNode; nested: bool; filter = nnkLiterals): NimNode = if constructor.kind in filter: result = newNimNode(nnkCall, lineInfoFrom = constructor) @@ -1099,34 +969,504 @@ func mapLitsImpl(constructor: NimNode; op: NimNode; nested: bool; macro mapLiterals*(constructor, op: untyped; nested = true): untyped = - ## Applies `op` to each of the **atomic** literals like `3` - ## or `"abc"` in the specified `constructor` AST. This can + ## Applies ``op`` to each of the **atomic** literals like ``3`` + ## or ``"abc"`` in the specified ``constructor`` AST. This can ## be used to map every array element to some target type: - runnableExamples: - let x = mapLiterals([0.1, 1.2, 2.3, 3.4], int) - doAssert x is array[4, int] - doAssert x == [int(0.1), int(1.2), int(2.3), int(3.4)] - ## If `nested` is true (which is the default), the literals are replaced - ## everywhere in the `constructor` AST, otherwise only the first level + ## + ## Example: + ## + ## .. code-block:: + ## let x = mapLiterals([0.1, 1.2, 2.3, 3.4], int) + ## doAssert x is array[4, int] + ## + ## Short notation for: + ## + ## .. code-block:: + ## let x = [int(0.1), int(1.2), int(2.3), int(3.4)] + ## + ## If ``nested`` is true (which is the default), the literals are replaced + ## everywhere in the ``constructor`` AST, otherwise only the first level ## is considered: - runnableExamples: - let a = mapLiterals((1.2, (2.3, 3.4), 4.8), int) - let b = mapLiterals((1.2, (2.3, 3.4), 4.8), int, nested=false) - assert a == (1, (2, 3), 4) - assert b == (1, (2.3, 3.4), 4) - - let c = mapLiterals((1, (2, 3), 4, (5, 6)), `$`) - let d = mapLiterals((1, (2, 3), 4, (5, 6)), `$`, nested=false) - assert c == ("1", ("2", "3"), "4", ("5", "6")) - assert d == ("1", (2, 3), "4", (5, 6)) - ## There are no constraints for the `constructor` AST, it + ## + ## .. code-block:: + ## let a = mapLiterals((1.2, (2.3, 3.4), 4.8), int) + ## let b = mapLiterals((1.2, (2.3, 3.4), 4.8), int, nested=false) + ## assert a == (1, (2, 3), 4) + ## assert b == (1, (2.3, 3.4), 4) + ## + ## let c = mapLiterals((1, (2, 3), 4, (5, 6)), `$`) + ## let d = mapLiterals((1, (2, 3), 4, (5, 6)), `$`, nested=false) + ## assert c == ("1", ("2", "3"), "4", ("5", "6")) + ## assert d == ("1", (2, 3), "4", (5, 6)) + ## + ## There are no constraints for the ``constructor`` AST, it ## works for nested tuples of arrays of sets etc. result = mapLitsImpl(constructor, op, nested.boolVal) iterator items*[T](xs: iterator: T): T = - ## Iterates over each element yielded by a closure iterator. This may + ## iterates over each element yielded by a closure iterator. This may ## not seem particularly useful on its own, but this allows closure - ## iterators to be used by the mapIt, filterIt, allIt, anyIt, etc. + ## iterators to be used by the the mapIt, filterIt, allIt, anyIt, etc. ## templates. for x in xs(): yield x + +when isMainModule: + import strutils + from algorithm import sorted + + # helper for testing double substitution side effects which are handled + # by `evalOnceAs` + var counter = 0 + proc identity[T](a: T): auto = + counter.inc + a + + block: # concat test + let + s1 = @[1, 2, 3] + s2 = @[4, 5] + s3 = @[6, 7] + total = concat(s1, s2, s3) + assert total == @[1, 2, 3, 4, 5, 6, 7] + + block: # count test + let + s1 = @[1, 2, 3, 2] + s2 = @['a', 'b', 'x', 'a'] + a1 = [1, 2, 3, 2] + a2 = ['a', 'b', 'x', 'a'] + r0 = count(s1, 0) + r1 = count(s1, 1) + r2 = count(s1, 2) + r3 = count(s2, 'y') + r4 = count(s2, 'x') + r5 = count(s2, 'a') + ar0 = count(a1, 0) + ar1 = count(a1, 1) + ar2 = count(a1, 2) + ar3 = count(a2, 'y') + ar4 = count(a2, 'x') + ar5 = count(a2, 'a') + assert r0 == 0 + assert r1 == 1 + assert r2 == 2 + assert r3 == 0 + assert r4 == 1 + assert r5 == 2 + assert ar0 == 0 + assert ar1 == 1 + assert ar2 == 2 + assert ar3 == 0 + assert ar4 == 1 + assert ar5 == 2 + + block: # cycle tests + let + a = @[1, 2, 3] + b: seq[int] = @[] + c = [1, 2, 3] + + doAssert a.cycle(3) == @[1, 2, 3, 1, 2, 3, 1, 2, 3] + doAssert a.cycle(0) == @[] + #doAssert a.cycle(-1) == @[] # will not compile! + doAssert b.cycle(3) == @[] + doAssert c.cycle(3) == @[1, 2, 3, 1, 2, 3, 1, 2, 3] + doAssert c.cycle(0) == @[] + + block: # repeat tests + assert repeat(10, 5) == @[10, 10, 10, 10, 10] + assert repeat(@[1, 2, 3], 2) == @[@[1, 2, 3], @[1, 2, 3]] + assert repeat([1, 2, 3], 2) == @[[1, 2, 3], [1, 2, 3]] + + block: # deduplicates test + let + dup1 = @[1, 1, 3, 4, 2, 2, 8, 1, 4] + dup2 = @["a", "a", "c", "d", "d"] + dup3 = [1, 1, 3, 4, 2, 2, 8, 1, 4] + dup4 = ["a", "a", "c", "d", "d"] + unique1 = deduplicate(dup1) + unique2 = deduplicate(dup2) + unique3 = deduplicate(dup3) + unique4 = deduplicate(dup4) + unique5 = deduplicate(dup1.sorted, true) + unique6 = deduplicate(dup2, true) + unique7 = deduplicate(dup3.sorted, true) + unique8 = deduplicate(dup4, true) + assert unique1 == @[1, 3, 4, 2, 8] + assert unique2 == @["a", "c", "d"] + assert unique3 == @[1, 3, 4, 2, 8] + assert unique4 == @["a", "c", "d"] + assert unique5 == @[1, 2, 3, 4, 8] + assert unique6 == @["a", "c", "d"] + assert unique7 == @[1, 2, 3, 4, 8] + assert unique8 == @["a", "c", "d"] + + block: # zip test + let + short = @[1, 2, 3] + long = @[6, 5, 4, 3, 2, 1] + words = @["one", "two", "three"] + ashort = [1, 2, 3] + along = [6, 5, 4, 3, 2, 1] + awords = ["one", "two", "three"] + zip1 = zip(short, long) + zip2 = zip(short, words) + zip3 = zip(ashort, along) + assert zip1 == @[(1, 6), (2, 5), (3, 4)] + assert zip2 == @[(1, "one"), (2, "two"), (3, "three")] + assert zip3 == @[(1, 6), (2, 5), (3, 4)] + assert zip1[2][1] == 4 + assert zip2[2][1] == "three" + assert zip3[2][1] == 4 + when (NimMajor, NimMinor) <= (1, 0): + let + # In Nim 1.0.x and older, zip returned a seq of tuple strictly + # with fields named "a" and "b". + zipAb = zip(ashort, awords) + assert zipAb == @[(a: 1, b: "one"), (2, "two"), (3, "three")] + assert zipAb[2].b == "three" + else: + let + # As zip returns seq of anonymous tuples, they can be assigned + # to any variable that's a sequence of named tuples too. + zipXy: seq[tuple[x: int, y: string]] = zip(ashort, awords) + zipMn: seq[tuple[m: int, n: string]] = zip(ashort, words) + assert zipXy == @[(x: 1, y: "one"), (2, "two"), (3, "three")] + assert zipMn == @[(m: 1, n: "one"), (2, "two"), (3, "three")] + assert zipXy[2].y == "three" + assert zipMn[2].n == "three" + + block: # distribute tests + let numbers = @[1, 2, 3, 4, 5, 6, 7] + doAssert numbers.distribute(3) == @[@[1, 2, 3], @[4, 5], @[6, 7]] + doAssert numbers.distribute(6)[0] == @[1, 2] + doAssert numbers.distribute(6)[5] == @[7] + let a = @[1, 2, 3, 4, 5, 6, 7] + doAssert a.distribute(1, true) == @[@[1, 2, 3, 4, 5, 6, 7]] + doAssert a.distribute(1, false) == @[@[1, 2, 3, 4, 5, 6, 7]] + doAssert a.distribute(2, true) == @[@[1, 2, 3, 4], @[5, 6, 7]] + doAssert a.distribute(2, false) == @[@[1, 2, 3, 4], @[5, 6, 7]] + doAssert a.distribute(3, true) == @[@[1, 2, 3], @[4, 5], @[6, 7]] + doAssert a.distribute(3, false) == @[@[1, 2, 3], @[4, 5, 6], @[7]] + doAssert a.distribute(4, true) == @[@[1, 2], @[3, 4], @[5, 6], @[7]] + doAssert a.distribute(4, false) == @[@[1, 2], @[3, 4], @[5, 6], @[7]] + doAssert a.distribute(5, true) == @[@[1, 2], @[3, 4], @[5], @[6], @[7]] + doAssert a.distribute(5, false) == @[@[1, 2], @[3, 4], @[5, 6], @[7], @[]] + doAssert a.distribute(6, true) == @[@[1, 2], @[3], @[4], @[5], @[6], @[7]] + doAssert a.distribute(6, false) == @[ + @[1, 2], @[3, 4], @[5, 6], @[7], @[], @[]] + doAssert a.distribute(8, false) == a.distribute(8, true) + doAssert a.distribute(90, false) == a.distribute(90, true) + var b = @[0] + for f in 1 .. 25: b.add(f) + doAssert b.distribute(5, true)[4].len == 5 + doAssert b.distribute(5, false)[4].len == 2 + + block: # map test + let + numbers = @[1, 4, 5, 8, 9, 7, 4] + anumbers = [1, 4, 5, 8, 9, 7, 4] + m1 = map(numbers, proc(x: int): int = 2*x) + m2 = map(anumbers, proc(x: int): int = 2*x) + assert m1 == @[2, 8, 10, 16, 18, 14, 8] + assert m2 == @[2, 8, 10, 16, 18, 14, 8] + + block: # apply test + var a = @["1", "2", "3", "4"] + apply(a, proc(x: var string) = x &= "42") + assert a == @["142", "242", "342", "442"] + + block: # filter proc test + let + colors = @["red", "yellow", "black"] + acolors = ["red", "yellow", "black"] + f1 = filter(colors, proc(x: string): bool = x.len < 6) + f2 = filter(colors) do (x: string) -> bool: x.len > 5 + f3 = filter(acolors, proc(x: string): bool = x.len < 6) + f4 = filter(acolors) do (x: string) -> bool: x.len > 5 + assert f1 == @["red", "black"] + assert f2 == @["yellow"] + assert f3 == @["red", "black"] + assert f4 == @["yellow"] + + block: # filter iterator test + let numbers = @[1, 4, 5, 8, 9, 7, 4] + let anumbers = [1, 4, 5, 8, 9, 7, 4] + assert toSeq(filter(numbers, proc (x: int): bool = x mod 2 == 0)) == + @[4, 8, 4] + assert toSeq(filter(anumbers, proc (x: int): bool = x mod 2 == 0)) == + @[4, 8, 4] + + block: # keepIf test + var floats = @[13.0, 12.5, 5.8, 2.0, 6.1, 9.9, 10.1] + keepIf(floats, proc(x: float): bool = x > 10) + assert floats == @[13.0, 12.5, 10.1] + + block: # delete tests + let outcome = @[1, 1, 1, 1, 1, 1, 1, 1] + var dest = @[1, 1, 1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1] + dest.delete(3, 8) + assert outcome == dest, """\ + Deleting range 3-9 from [1,1,1,2,2,2,2,2,2,1,1,1,1,1] + is [1,1,1,1,1,1,1,1]""" + var x = @[1, 2, 3] + x.delete(100, 100) + assert x == @[1, 2, 3] + + block: # insert tests + var dest = @[1, 1, 1, 1, 1, 1, 1, 1] + let + src = @[2, 2, 2, 2, 2, 2] + outcome = @[1, 1, 1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1] + dest.insert(src, 3) + assert dest == outcome, """\ + Inserting [2,2,2,2,2,2] into [1,1,1,1,1,1,1,1] + at 3 is [1,1,1,2,2,2,2,2,2,1,1,1,1,1]""" + + block: # filterIt test + let + temperatures = @[-272.15, -2.0, 24.5, 44.31, 99.9, -113.44] + acceptable = filterIt(temperatures, it < 50 and it > -10) + notAcceptable = filterIt(temperatures, it > 50 or it < -10) + assert acceptable == @[-2.0, 24.5, 44.31] + assert notAcceptable == @[-272.15, 99.9, -113.44] + + block: # keepItIf test + var candidates = @["foo", "bar", "baz", "foobar"] + keepItIf(candidates, it.len == 3 and it[0] == 'b') + assert candidates == @["bar", "baz"] + + block: # all + let + numbers = @[1, 4, 5, 8, 9, 7, 4] + anumbers = [1, 4, 5, 8, 9, 7, 4] + len0seq: seq[int] = @[] + assert all(numbers, proc (x: int): bool = return x < 10) == true + assert all(numbers, proc (x: int): bool = return x < 9) == false + assert all(len0seq, proc (x: int): bool = return false) == true + assert all(anumbers, proc (x: int): bool = return x < 10) == true + assert all(anumbers, proc (x: int): bool = return x < 9) == false + + block: # allIt + let + numbers = @[1, 4, 5, 8, 9, 7, 4] + anumbers = [1, 4, 5, 8, 9, 7, 4] + len0seq: seq[int] = @[] + assert allIt(numbers, it < 10) == true + assert allIt(numbers, it < 9) == false + assert allIt(len0seq, false) == true + assert allIt(anumbers, it < 10) == true + assert allIt(anumbers, it < 9) == false + + block: # any + let + numbers = @[1, 4, 5, 8, 9, 7, 4] + anumbers = [1, 4, 5, 8, 9, 7, 4] + len0seq: seq[int] = @[] + assert any(numbers, proc (x: int): bool = return x > 8) == true + assert any(numbers, proc (x: int): bool = return x > 9) == false + assert any(len0seq, proc (x: int): bool = return true) == false + assert any(anumbers, proc (x: int): bool = return x > 8) == true + assert any(anumbers, proc (x: int): bool = return x > 9) == false + + block: # anyIt + let + numbers = @[1, 4, 5, 8, 9, 7, 4] + anumbers = [1, 4, 5, 8, 9, 7, 4] + len0seq: seq[int] = @[] + assert anyIt(numbers, it > 8) == true + assert anyIt(numbers, it > 9) == false + assert anyIt(len0seq, true) == false + assert anyIt(anumbers, it > 8) == true + assert anyIt(anumbers, it > 9) == false + + block: # toSeq test + block: + let + numeric = @[1, 2, 3, 4, 5, 6, 7, 8, 9] + oddNumbers = toSeq(filter(numeric) do (x: int) -> bool: + if x mod 2 == 1: + result = true) + assert oddNumbers == @[1, 3, 5, 7, 9] + + block: + doAssert [1, 2].toSeq == @[1, 2] + doAssert @[1, 2].toSeq == @[1, 2] + + doAssert @[1, 2].toSeq == @[1, 2] + doAssert toSeq(@[1, 2]) == @[1, 2] + + block: + iterator myIter(seed: int): auto = + for i in 0..= 0: result = true else: - if mustRehash(s): + if mustRehash(len(s.data), s.counter): enlarge(s) index = rawGetKnownHC(s, key, hc) rawInsert(s, s.data, key, hc, -1 - index) @@ -86,7 +86,7 @@ proc exclImpl[A](s: var HashSet[A], key: A): bool {.inline.} = var j = i # The correctness of this depends on (h+1) in nextTry, var r = j # though may be adaptable to other simple sequences. s.data[i].hcode = 0 # mark current EMPTY - s.data[i].key = default(typeof(s.data[i].key)) + s.data[i].key = default(type(s.data[i].key)) doWhile((i >= r and r > j) or (r > j and j > i) or (j > i and i >= r)): i = (i + 1) and msk # increment mod table size if isEmpty(s.data[i].hcode): # end of collision cluster; So all done diff --git a/lib/pure/collections/sets.nim b/lib/pure/collections/sets.nim index 11e324923..9dd72cb56 100644 --- a/lib/pure/collections/sets.nim +++ b/lib/pure/collections/sets.nim @@ -7,7 +7,7 @@ # distribution, for details about the copyright. # -## The `sets` module implements an efficient `hash set`:idx: and +## The ``sets`` module implements an efficient `hash set`:idx: and ## ordered hash set. ## ## Hash sets are different from the `built in set type @@ -16,7 +16,7 @@ ## ## Common usages of sets: ## * removing duplicates from a container by converting it with `toHashSet proc -## <#toHashSet,openArray[A]>`_ (see also `sequtils.deduplicate func +## <#toHashSet,openArray[A]>`_ (see also `sequtils.deduplicate proc ## `_) ## * membership testing ## * mathematical operations on two sets, such as @@ -40,7 +40,7 @@ ## ## ## Note: The data types declared here have *value semantics*: This means -## that `=` performs a copy of the set. +## that ``=`` performs a copy of the set. ## ## **See also:** ## * `intsets module `_ for efficient int sets @@ -50,10 +50,10 @@ import hashes, math -when not defined(nimHasEffectsOf): - {.pragma: effectsOf.} - {.pragma: myShallow.} +when not defined(nimhygiene): + {.pragma: dirty.} + # For "integer-like A" that are too big for intsets/bit-vectors to be practical, # it would be best to shrink hcode to the same size as the integer. Larger # codes should never be needed, and this can pack more entries per cache-line. @@ -64,7 +64,7 @@ type HashSet*[A] {.myShallow.} = object ## \ ## A generic hash set. ## - ## Use `init proc <#init,HashSet[A]>`_ or `initHashSet proc <#initHashSet>`_ + ## Use `init proc <#init,HashSet[A],int>`_ or `initHashSet proc <#initHashSet,int>`_ ## before calling other procs on it. data: KeyValuePairSeq[A] counter: int @@ -76,18 +76,19 @@ type OrderedSet*[A] {.myShallow.} = object ## \ ## A generic hash set that remembers insertion order. ## - ## Use `init proc <#init,OrderedSet[A]>`_ or `initOrderedSet proc - ## <#initOrderedSet>`_ before calling other procs on it. + ## Use `init proc <#init,OrderedSet[A],int>`_ or `initOrderedSet proc + ## <#initOrderedSet,int>`_ before calling other procs on it. data: OrderedKeyValuePairSeq[A] counter, first, last: int - SomeSet*[A] = HashSet[A] | OrderedSet[A] - ## Type union representing `HashSet` or `OrderedSet`. const defaultInitialSize* = 64 include setimpl +proc rightSize*(count: Natural): int {.inline.} + + # --------------------------------------------------------------------- # ------------------------------ HashSet ------------------------------ # --------------------------------------------------------------------- @@ -96,6 +97,11 @@ include setimpl proc init*[A](s: var HashSet[A], initialSize = defaultInitialSize) = ## Initializes a hash set. ## + ## The `initialSize` parameter needs to be a power of two (default: 64). + ## If you need to accept runtime values for this, you can use + ## `math.nextPowerOfTwo proc `_ or + ## `rightSize proc <#rightSize,Natural>`_ from this module. + ## ## Starting from Nim v0.20, sets are initialized by default and it is ## not necessary to call this function explicitly. ## @@ -104,19 +110,21 @@ proc init*[A](s: var HashSet[A], initialSize = defaultInitialSize) = ## existing values and calling `excl() <#excl,HashSet[A],A>`_ on them. ## ## See also: - ## * `initHashSet proc <#initHashSet>`_ + ## * `initHashSet proc <#initHashSet,int>`_ ## * `toHashSet proc <#toHashSet,openArray[A]>`_ runnableExamples: var a: HashSet[int] + assert(not a.isValid) init(a) + assert a.isValid initImpl(s, initialSize) proc initHashSet*[A](initialSize = defaultInitialSize): HashSet[A] = - ## Wrapper around `init proc <#init,HashSet[A]>`_ for initialization of + ## Wrapper around `init proc <#init,HashSet[A],int>`_ for initialization of ## hash sets. ## - ## Returns an empty hash set you can assign directly in `var` blocks in a + ## Returns an empty hash set you can assign directly in ``var`` blocks in a ## single line. ## ## Starting from Nim v0.20, sets are initialized by default and it is @@ -133,7 +141,7 @@ proc initHashSet*[A](initialSize = defaultInitialSize): HashSet[A] = proc `[]`*[A](s: var HashSet[A], key: A): var A = ## Returns the element that is actually stored in `s` which has the same - ## value as `key` or raises the `KeyError` exception. + ## value as `key` or raises the ``KeyError`` exception. ## ## This is useful when one overloaded `hash` and `==` but still needs ## reference semantics for sharing. @@ -167,27 +175,6 @@ proc contains*[A](s: HashSet[A], key: A): bool = var index = rawGet(s, key, hc) result = index >= 0 -proc len*[A](s: HashSet[A]): int = - ## Returns the number of elements in `s`. - ## - ## Due to an implementation detail you can call this proc on variables which - ## have not been initialized yet. The proc will return zero as the length - ## then. - runnableExamples: - var a: HashSet[string] - assert len(a) == 0 - let s = toHashSet([3, 5, 7]) - assert len(s) == 3 - - result = s.counter - -proc card*[A](s: HashSet[A]): int = - ## Alias for `len() <#len,HashSet[A]>`_. - ## - ## Card stands for the `cardinality - ## `_ of a set. - result = s.counter - proc incl*[A](s: var HashSet[A], key: A) = ## Includes an element `key` in `s`. ## @@ -230,7 +217,7 @@ proc toHashSet*[A](keys: openArray[A]): HashSet[A] = ## Duplicates are removed. ## ## See also: - ## * `initHashSet proc <#initHashSet>`_ + ## * `initHashSet proc <#initHashSet,int>`_ runnableExamples: let a = toHashSet([5, 3, 2]) @@ -240,7 +227,7 @@ proc toHashSet*[A](keys: openArray[A]): HashSet[A] = assert len(b) == 5 ## b == {'a', 'b', 'c', 'd', 'r'} - result = initHashSet[A](keys.len) + result = initHashSet[A](rightSize(keys.len)) for key in items(keys): result.incl(key) iterator items*[A](s: HashSet[A]): A = @@ -262,11 +249,8 @@ iterator items*[A](s: HashSet[A]): A = ## assert a.len == 2 ## echo b ## # --> {(a: 1, b: 3), (a: 0, b: 4)} - let length = s.len for h in 0 .. high(s.data): - if isFilled(s.data[h].hcode): - yield s.data[h].key - assert(len(s) == length, "the length of the HashSet changed while iterating over it") + if isFilled(s.data[h].hcode): yield s.data[h].key proc containsOrIncl*[A](s: var HashSet[A], key: A): bool = ## Includes `key` in the set `s` and tells if `key` was already in `s`. @@ -345,15 +329,16 @@ proc missingOrExcl*[A](s: var HashSet[A], key: A): bool = exclImpl(s, key) proc pop*[A](s: var HashSet[A]): A = - ## Removes and returns an arbitrary element from the set `s`. + ## Remove and return an arbitrary element from the set `s`. ## - ## Raises `KeyError` if the set `s` is empty. + ## Raises KeyError if the set `s` is empty. ## ## See also: ## * `clear proc <#clear,HashSet[A]>`_ runnableExamples: var s = toHashSet([2, 1]) - assert [s.pop, s.pop] in [[1, 2], [2,1]] # order unspecified + assert s.pop == 1 + assert s.pop == 2 doAssertRaises(KeyError, echo s.pop) for h in 0 .. high(s.data): @@ -379,7 +364,28 @@ proc clear*[A](s: var HashSet[A]) = s.counter = 0 for i in 0 ..< s.data.len: s.data[i].hcode = 0 - s.data[i].key = default(typeof(s.data[i].key)) + s.data[i].key = default(type(s.data[i].key)) + +proc len*[A](s: HashSet[A]): int = + ## Returns the number of elements in `s`. + ## + ## Due to an implementation detail you can call this proc on variables which + ## have not been initialized yet. The proc will return zero as the length + ## then. + runnableExamples: + var a: HashSet[string] + assert len(a) == 0 + let s = toHashSet([3, 5, 7]) + assert len(s) == 3 + + result = s.counter + +proc card*[A](s: HashSet[A]): int = + ## Alias for `len() <#len,HashSet[A]>`_. + ## + ## Card stands for the `cardinality + ## `_ of a set. + result = s.counter proc union*[A](s1, s2: HashSet[A]): HashSet[A] = @@ -425,15 +431,8 @@ proc intersection*[A](s1, s2: HashSet[A]): HashSet[A] = assert c == toHashSet(["b"]) result = initHashSet[A](max(min(s1.data.len, s2.data.len), 2)) - - # iterate over the elements of the smaller set - if s1.data.len < s2.data.len: - for item in s1: - if item in s2: incl(result, item) - else: - for item in s2: - if item in s1: incl(result, item) - + for item in s1: + if item in s2: incl(result, item) proc difference*[A](s1, s2: HashSet[A]): HashSet[A] = ## Returns the difference of the sets `s1` and `s2`. @@ -559,7 +558,7 @@ proc `==`*[A](s, t: HashSet[A]): bool = s.counter == t.counter and s <= t -proc map*[A, B](data: HashSet[A], op: proc (x: A): B {.closure.}): HashSet[B] {.effectsOf: op.} = +proc map*[A, B](data: HashSet[A], op: proc (x: A): B {.closure.}): HashSet[B] = ## Returns a new set after applying `op` proc on each of the elements of ##`data` set. ## @@ -594,6 +593,15 @@ proc `$`*[A](s: HashSet[A]): string = ## # --> {no, esc'aping, is " provided} dollarImpl() +proc rightSize*(count: Natural): int {.inline.} = + ## Return the value of `initialSize` to support `count` items. + ## + ## If more items are expected to be added, simply add that + ## expected extra amount to the parameter before calling this. + ## + ## Internally, we want `mustRehash(rightSize(x), x) == false`. + result = nextPowerOfTwo(count * 3 div 2 + 4) + proc initSet*[A](initialSize = defaultInitialSize): HashSet[A] {.deprecated: "Deprecated since v0.20, use 'initHashSet'".} = initHashSet[A](initialSize) @@ -604,12 +612,14 @@ proc toSet*[A](keys: openArray[A]): HashSet[A] {.deprecated: proc isValid*[A](s: HashSet[A]): bool {.deprecated: "Deprecated since v0.20; sets are initialized by default".} = ## Returns `true` if the set has been initialized (with `initHashSet proc - ## <#initHashSet>`_ or `init proc <#init,HashSet[A]>`_). + ## <#initHashSet,int>`_ or `init proc <#init,HashSet[A],int>`_). ## - runnableExamples: - proc savePreferences(options: HashSet[string]) = - assert options.isValid, "Pass an initialized set!" - # Do stuff here, may crash in release builds! + ## **Examples:** + ## + ## .. code-block :: + ## proc savePreferences(options: HashSet[string]) = + ## assert options.isValid, "Pass an initialized set!" + ## # Do stuff here, may crash in release builds! result = s.data.len > 0 @@ -633,6 +643,11 @@ template forAllOrderedPairs(yieldStmt: untyped) {.dirty.} = proc init*[A](s: var OrderedSet[A], initialSize = defaultInitialSize) = ## Initializes an ordered hash set. ## + ## The `initialSize` parameter needs to be a power of two (default: 64). + ## If you need to accept runtime values for this, you can use + ## `math.nextPowerOfTwo proc `_ or + ## `rightSize proc <#rightSize,Natural>`_ from this module. + ## ## Starting from Nim v0.20, sets are initialized by default and it is ## not necessary to call this function explicitly. ## @@ -641,19 +656,21 @@ proc init*[A](s: var OrderedSet[A], initialSize = defaultInitialSize) = ## existing values and calling `excl() <#excl,HashSet[A],A>`_ on them. ## ## See also: - ## * `initOrderedSet proc <#initOrderedSet>`_ + ## * `initOrderedSet proc <#initOrderedSet,int>`_ ## * `toOrderedSet proc <#toOrderedSet,openArray[A]>`_ runnableExamples: var a: OrderedSet[int] + assert(not a.isValid) init(a) + assert a.isValid initImpl(s, initialSize) proc initOrderedSet*[A](initialSize = defaultInitialSize): OrderedSet[A] = - ## Wrapper around `init proc <#init,OrderedSet[A]>`_ for initialization of + ## Wrapper around `init proc <#init,OrderedSet[A],int>`_ for initialization of ## ordered hash sets. ## - ## Returns an empty ordered hash set you can assign directly in `var` blocks + ## Returns an empty ordered hash set you can assign directly in ``var`` blocks ## in a single line. ## ## Starting from Nim v0.20, sets are initialized by default and it is @@ -675,7 +692,7 @@ proc toOrderedSet*[A](keys: openArray[A]): OrderedSet[A] = ## Duplicates are removed. ## ## See also: - ## * `initOrderedSet proc <#initOrderedSet>`_ + ## * `initOrderedSet proc <#initOrderedSet,int>`_ runnableExamples: let a = toOrderedSet([5, 3, 2]) @@ -685,7 +702,7 @@ proc toOrderedSet*[A](keys: openArray[A]): OrderedSet[A] = assert len(b) == 5 ## b == {'a', 'b', 'r', 'c', 'd'} # different than in HashSet - result = initOrderedSet[A](keys.len) + result = initOrderedSet[A](rightSize(keys.len)) for key in items(keys): result.incl(key) proc contains*[A](s: OrderedSet[A], key: A): bool = @@ -813,7 +830,7 @@ proc clear*[A](s: var OrderedSet[A]) = for i in 0 ..< s.data.len: s.data[i].hcode = 0 s.data[i].next = 0 - s.data[i].key = default(typeof(s.data[i].key)) + s.data[i].key = default(type(s.data[i].key)) proc len*[A](s: OrderedSet[A]): int {.inline.} = ## Returns the number of elements in `s`. @@ -902,10 +919,8 @@ iterator items*[A](s: OrderedSet[A]): A = ## # --> Got 5 ## # --> Got 8 ## # --> Got 4 - let length = s.len forAllOrderedPairs: yield s.data[h].key - assert(len(s) == length, "the length of the OrderedSet changed while iterating over it") iterator pairs*[A](s: OrderedSet[A]): tuple[a: int, b: A] = ## Iterates through (position, value) tuples of OrderedSet `s`. @@ -916,7 +931,311 @@ iterator pairs*[A](s: OrderedSet[A]): tuple[a: int, b: A] = p.add(x) assert p == @[(0, 'a'), (1, 'b'), (2, 'r'), (3, 'c'), (4, 'd')] - let length = s.len forAllOrderedPairs: yield (idx, s.data[h].key) - assert(len(s) == length, "the length of the OrderedSet changed while iterating over it") + + + +proc isValid*[A](s: OrderedSet[A]): bool {.deprecated: + "Deprecated since v0.20; sets are initialized by default".} = + ## + ## Returns `true` if the set has been initialized (with `initHashSet proc + ## <#initOrderedSet,int>`_ or `init proc <#init,OrderedSet[A],int>`_). + ## + ## **Examples:** + ## + ## .. code-block :: + ## proc savePreferences(options: OrderedSet[string]) = + ## assert options.isValid, "Pass an initialized set!" + ## # Do stuff here, may crash in release builds! + result = s.data.len > 0 + + +# ----------------------------------------------------------------------- + + + +when isMainModule and not defined(release): + proc testModule() = + ## Internal micro test to validate docstrings and such. + block isValidTest: # isValid is deprecated + var options: HashSet[string] + proc savePreferences(options: HashSet[string]) = + assert options.isValid, "Pass an initialized set!" + options = initHashSet[string]() + options.savePreferences + + block lenTest: + var values: HashSet[int] + assert(not values.isValid) + assert values.len == 0 + assert values.card == 0 + + block setIterator: + type pair = tuple[a, b: int] + var a, b = initHashSet[pair]() + a.incl((2, 3)) + a.incl((3, 2)) + a.incl((2, 3)) + for x, y in a.items: + b.incl((x - 2, y + 1)) + assert a.len == b.card + assert a.len == 2 + #echo b + + block setContains: + var values = initHashSet[int]() + assert(not values.contains(2)) + values.incl(2) + assert values.contains(2) + values.excl(2) + assert(not values.contains(2)) + + values.incl(4) + var others = toHashSet([6, 7]) + values.incl(others) + assert values.len == 3 + + values.init + assert values.containsOrIncl(2) == false + assert values.containsOrIncl(2) == true + var + a = toHashSet([1, 2]) + b = toHashSet([1]) + b.incl(2) + assert a == b + + block exclusions: + var s = toHashSet([2, 3, 6, 7]) + s.excl(2) + s.excl(2) + assert s.len == 3 + + var + numbers = toHashSet([1, 2, 3, 4, 5]) + even = toHashSet([2, 4, 6, 8]) + numbers.excl(even) + #echo numbers + # --> {1, 3, 5} + + block toSeqAndString: + var a = toHashSet([2, 7, 5]) + var b = initHashSet[int]() + for x in [2, 7, 5]: b.incl(x) + assert($a == $b) + #echo a + #echo toHashSet(["no", "esc'aping", "is \" provided"]) + + #block orderedToSeqAndString: + # echo toOrderedSet([2, 4, 5]) + # echo toOrderedSet(["no", "esc'aping", "is \" provided"]) + + block setOperations: + var + a = toHashSet(["a", "b"]) + b = toHashSet(["b", "c"]) + c = union(a, b) + assert c == toHashSet(["a", "b", "c"]) + var d = intersection(a, b) + assert d == toHashSet(["b"]) + var e = difference(a, b) + assert e == toHashSet(["a"]) + var f = symmetricDifference(a, b) + assert f == toHashSet(["a", "c"]) + assert d < a and d < b + assert((a < a) == false) + assert d <= a and d <= b + assert((a <= a)) + # Alias test. + assert a + b == toHashSet(["a", "b", "c"]) + assert a * b == toHashSet(["b"]) + assert a - b == toHashSet(["a"]) + assert a -+- b == toHashSet(["a", "c"]) + assert disjoint(a, b) == false + assert disjoint(a, b - a) == true + + block mapSet: + var a = toHashSet([1, 2, 3]) + var b = a.map(proc (x: int): string = $x) + assert b == toHashSet(["1", "2", "3"]) + + block isValidTest: # isValid is deprecated + var cards: OrderedSet[string] + proc saveTarotCards(cards: OrderedSet[string]) = + assert cards.isValid, "Pass an initialized set!" + cards = initOrderedSet[string]() + cards.saveTarotCards + + block lenTest: + var values: OrderedSet[int] + assert(not values.isValid) + assert values.len == 0 + assert values.card == 0 + + block setIterator: + type pair = tuple[a, b: int] + var a, b = initOrderedSet[pair]() + a.incl((2, 3)) + a.incl((3, 2)) + a.incl((2, 3)) + for x, y in a.items: + b.incl((x - 2, y + 1)) + assert a.len == b.card + assert a.len == 2 + + block setPairsIterator: + var s = toOrderedSet([1, 3, 5, 7]) + var items = newSeq[tuple[a: int, b: int]]() + for idx, item in s: items.add((idx, item)) + assert items == @[(0, 1), (1, 3), (2, 5), (3, 7)] + + block exclusions: + var s = toOrderedSet([1, 2, 3, 6, 7, 4]) + + s.excl(3) + s.excl(3) + s.excl(1) + s.excl(4) + + var items = newSeq[int]() + for item in s: items.add item + assert items == @[2, 6, 7] + + block: #9005 + var s = initOrderedSet[(int, int)]() + for i in 0 .. 30: incl(s, (i, 0)) + for i in 0 .. 30: excl(s, (i, 0)) + doAssert s.len == 0 + + #block orderedSetIterator: + # var a = initOrderedSet[int]() + # for value in [9, 2, 1, 5, 1, 8, 4, 2]: + # a.incl(value) + # for value in a.items: + # echo "Got ", value + + block setContains: + var values = initOrderedSet[int]() + assert(not values.contains(2)) + values.incl(2) + assert values.contains(2) + + block toSeqAndString: + var a = toOrderedSet([2, 4, 5]) + var b = initOrderedSet[int]() + for x in [2, 4, 5]: b.incl(x) + assert($a == $b) + assert(a == b) # https://github.com/Araq/Nim/issues/1413 + + block initBlocks: + var a: OrderedSet[int] + a.init(4) + a.incl(2) + a.init + assert a.len == 0 and a.isValid + a = initOrderedSet[int](4) + a.incl(2) + assert a.len == 1 + + var b: HashSet[int] + b.init(4) + b.incl(2) + b.init + assert b.len == 0 and b.isValid + b = initHashSet[int](4) + b.incl(2) + assert b.len == 1 + + for i in 0 .. 32: + var s = rightSize(i) + if s <= i or mustRehash(s, i): + echo "performance issue: rightSize() will not elide enlarge() at ", i + + block missingOrExcl: + var s = toOrderedSet([2, 3, 6, 7]) + assert s.missingOrExcl(4) == true + assert s.missingOrExcl(6) == false + + block orderedSetEquality: + type pair = tuple[a, b: int] + + var aa = initOrderedSet[pair]() + var bb = initOrderedSet[pair]() + + var x = (a: 1, b: 2) + var y = (a: 3, b: 4) + + aa.incl(x) + aa.incl(y) + + bb.incl(x) + bb.incl(y) + assert aa == bb + + block setsWithoutInit: + var + a: HashSet[int] + b: HashSet[int] + c: HashSet[int] + d: HashSet[int] + e: HashSet[int] + + doAssert a.containsOrIncl(3) == false + doAssert a.contains(3) + doAssert a.len == 1 + doAssert a.containsOrIncl(3) + a.incl(3) + doAssert a.len == 1 + a.incl(6) + doAssert a.len == 2 + + b.incl(5) + doAssert b.len == 1 + b.excl(5) + b.excl(c) + doAssert b.missingOrExcl(5) + doAssert b.disjoint(c) + + d = b + c + doAssert d.len == 0 + d = b * c + doAssert d.len == 0 + d = b - c + doAssert d.len == 0 + d = b -+- c + doAssert d.len == 0 + + doAssert (d < e) == false + doAssert d <= e + doAssert d == e + + block setsWithoutInit: + var + a: OrderedSet[int] + b: OrderedSet[int] + c: OrderedSet[int] + d: HashSet[int] + + + doAssert a.containsOrIncl(3) == false + doAssert a.contains(3) + doAssert a.len == 1 + doAssert a.containsOrIncl(3) + a.incl(3) + doAssert a.len == 1 + a.incl(6) + doAssert a.len == 2 + + b.incl(5) + doAssert b.len == 1 + doAssert b.missingOrExcl(5) == false + doAssert b.missingOrExcl(5) + + doAssert c.missingOrExcl(9) + d.incl(c) + doAssert d.len == 0 + + when not defined(testing): + echo "Micro tests run successfully." + + testModule() diff --git a/lib/pure/collections/sharedlist.nim b/lib/pure/collections/sharedlist.nim index e61883220..f9182acce 100644 --- a/lib/pure/collections/sharedlist.nim +++ b/lib/pure/collections/sharedlist.nim @@ -11,8 +11,6 @@ ## ## Unstable API. -{.deprecated.} - {.push stackTrace: off.} import @@ -37,10 +35,8 @@ template withLock(t, x: untyped) = release(t.lock) proc iterAndMutate*[A](x: var SharedList[A]; action: proc(x: A): bool) = - ## Iterates over the list. If `action` returns true, the + ## iterates over the list. If 'action' returns true, the ## current item is removed from the list. - ## - ## .. warning:: It may not preserve the element order after some modifications. withLock(x): var n = x.head while n != nil: @@ -51,9 +47,8 @@ proc iterAndMutate*[A](x: var SharedList[A]; action: proc(x: A): bool) = if action(n.d[i]): acquire(x.lock) let t = x.tail - dec t.dataLen # TODO considering t.dataLen == 0, - # probably the module should be refactored using doubly linked lists n.d[i] = t.d[t.dataLen] + dec t.dataLen else: acquire(x.lock) inc i @@ -70,14 +65,11 @@ iterator items*[A](x: var SharedList[A]): A = proc add*[A](x: var SharedList[A]; y: A) = withLock(x): var node: SharedListNode[A] - if x.tail == nil: - node = cast[typeof node](allocShared0(sizeof(node[]))) - x.tail = node - x.head = node - elif x.tail.dataLen == ElemsPerNode: - node = cast[typeof node](allocShared0(sizeof(node[]))) - x.tail.next = node + if x.tail == nil or x.tail.dataLen == ElemsPerNode: + node = cast[type node](allocShared0(sizeof(node[]))) + node.next = x.tail x.tail = node + if x.head == nil: x.head = node else: node = x.tail node.d[node.dataLen] = y @@ -102,4 +94,10 @@ proc deinitSharedList*[A](t: var SharedList[A]) = clear(t) deinitLock t.lock +proc initSharedList*[A](): SharedList[A] {.deprecated: "use 'init' instead".} = + ## This is not posix compliant, may introduce undefined behavior. + initLock result.lock + result.head = nil + result.tail = nil + {.pop.} diff --git a/lib/pure/collections/sharedtables.nim b/lib/pure/collections/sharedtables.nim index 816ab49ab..1a6148752 100644 --- a/lib/pure/collections/sharedtables.nim +++ b/lib/pure/collections/sharedtables.nim @@ -14,11 +14,11 @@ ## ## Unstable API. -{.deprecated.} - import hashes, math, locks +include "system/inclrtl" + type KeyValuePair[A, B] = tuple[hcode: Hash, key: A, val: B] KeyValuePairSeq[A, B] = ptr UncheckedArray[KeyValuePair[A, B]] @@ -32,7 +32,7 @@ template maxHash(t): untyped = t.dataLen-1 include tableimpl template st_maybeRehashPutImpl(enlarge) {.dirty.} = - if mustRehash(t): + if mustRehash(t.dataLen, t.counter): enlarge(t) index = rawGetKnownHC(t, key, hc) index = -1 - index # important to transform for mgetOrPutImpl @@ -62,27 +62,17 @@ template withLock(t, x: untyped) = template withValue*[A, B](t: var SharedTable[A, B], key: A, value, body: untyped) = - ## Retrieves the value at `t[key]`. - ## `value` can be modified in the scope of the `withValue` call. - runnableExamples: - var table: SharedTable[string, string] - init(table) - - table["a"] = "x" - table["b"] = "y" - table["c"] = "z" - - table.withValue("a", value): - assert value[] == "x" - - table.withValue("b", value): - value[] = "modified" - - table.withValue("b", value): - assert value[] == "modified" - - table.withValue("nonexistent", value): - assert false # not called + ## retrieves the value at ``t[key]``. + ## `value` can be modified in the scope of the ``withValue`` call. + ## + ## .. code-block:: nim + ## + ## sharedTable.withValue(key, value) do: + ## # block is executed only if ``key`` in ``t`` + ## # value is threadsafe in block + ## value.name = "username" + ## value.uid = 1000 + ## acquire(t.lock) try: var hc: Hash @@ -96,33 +86,20 @@ template withValue*[A, B](t: var SharedTable[A, B], key: A, template withValue*[A, B](t: var SharedTable[A, B], key: A, value, body1, body2: untyped) = - ## Retrieves the value at `t[key]`. - ## `value` can be modified in the scope of the `withValue` call. - runnableExamples: - var table: SharedTable[string, string] - init(table) - - table["a"] = "x" - table["b"] = "y" - table["c"] = "z" - - - table.withValue("a", value): - value[] = "m" - - var flag = false - table.withValue("d", value): - discard value - doAssert false - do: # if "d" notin table - flag = true - - if flag: - table["d"] = "n" - - assert table.mget("a") == "m" - assert table.mget("d") == "n" - + ## retrieves the value at ``t[key]``. + ## `value` can be modified in the scope of the ``withValue`` call. + ## + ## .. code-block:: nim + ## + ## sharedTable.withValue(key, value) do: + ## # block is executed only if ``key`` in ``t`` + ## # value is threadsafe in block + ## value.name = "username" + ## value.uid = 1000 + ## do: + ## # block is executed when ``key`` not in ``t`` + ## raise newException(KeyError, "Key not found") + ## acquire(t.lock) try: var hc: Hash @@ -137,8 +114,8 @@ template withValue*[A, B](t: var SharedTable[A, B], key: A, release(t.lock) proc mget*[A, B](t: var SharedTable[A, B], key: A): var B = - ## Retrieves the value at `t[key]`. The value can be modified. - ## If `key` is not in `t`, the `KeyError` exception is raised. + ## retrieves the value at ``t[key]``. The value can be modified. + ## If `key` is not in `t`, the ``KeyError`` exception is raised. withLock t: var hc: Hash var index = rawGet(t, key, hc) @@ -151,42 +128,38 @@ proc mget*[A, B](t: var SharedTable[A, B], key: A): var B = raise newException(KeyError, "key not found") proc mgetOrPut*[A, B](t: var SharedTable[A, B], key: A, val: B): var B = - ## Retrieves value at `t[key]` or puts `val` if not present, either way + ## retrieves value at ``t[key]`` or puts ``val`` if not present, either way ## returning a value which can be modified. **Note**: This is inherently ## unsafe in the context of multi-threading since it returns a pointer - ## to `B`. + ## to ``B``. withLock t: mgetOrPutImpl(enlarge) proc hasKeyOrPut*[A, B](t: var SharedTable[A, B], key: A, val: B): bool = - ## Returns true if `key` is in the table, otherwise inserts `value`. + ## returns true iff `key` is in the table, otherwise inserts `value`. withLock t: hasKeyOrPutImpl(enlarge) -template tabMakeEmpty(i) = t.data[i].hcode = 0 -template tabCellEmpty(i) = isEmpty(t.data[i].hcode) -template tabCellHash(i) = t.data[i].hcode - proc withKey*[A, B](t: var SharedTable[A, B], key: A, mapper: proc(key: A, val: var B, pairExists: var bool)) = - ## Computes a new mapping for the `key` with the specified `mapper` + ## Computes a new mapping for the ``key`` with the specified ``mapper`` ## procedure. ## - ## The `mapper` takes 3 arguments: + ## The ``mapper`` takes 3 arguments: ## - ## 1. `key` - the current key, if it exists, or the key passed to - ## `withKey` otherwise; - ## 2. `val` - the current value, if the key exists, or default value + ## 1. ``key`` - the current key, if it exists, or the key passed to + ## ``withKey`` otherwise; + ## 2. ``val`` - the current value, if the key exists, or default value ## of the type otherwise; - ## 3. `pairExists` - `true` if the key exists, `false` otherwise. + ## 3. ``pairExists`` - ``true`` if the key exists, ``false`` otherwise. ## - ## The `mapper` can can modify `val` and `pairExists` values to change + ## The ``mapper`` can can modify ``val`` and ``pairExists`` values to change ## the mapping of the key or delete it from the table. - ## When adding a value, make sure to set `pairExists` to `true` along - ## with modifying the `val`. + ## When adding a value, make sure to set ``pairExists`` to ``true`` along + ## with modifying the ``val``. ## ## The operation is performed atomically and other operations on the table - ## will be blocked while the `mapper` is invoked, so it should be short and + ## will be blocked while the ``mapper`` is invoked, so it should be short and ## simple. ## ## Example usage: @@ -208,7 +181,7 @@ proc withKey*[A, B](t: var SharedTable[A, B], key: A, if pairExists: mapper(t.data[index].key, t.data[index].val, pairExists) if not pairExists: - delImplIdx(t, index, tabMakeEmpty, tabCellEmpty, tabCellHash) + delImplIdx(t, index) else: var val: B mapper(key, val, pairExists) @@ -216,31 +189,30 @@ proc withKey*[A, B](t: var SharedTable[A, B], key: A, st_maybeRehashPutImpl(enlarge) proc `[]=`*[A, B](t: var SharedTable[A, B], key: A, val: B) = - ## Puts a (key, value)-pair into `t`. + ## puts a (key, value)-pair into `t`. withLock t: putImpl(enlarge) proc add*[A, B](t: var SharedTable[A, B], key: A, val: B) = - ## Puts a new (key, value)-pair into `t` even if `t[key]` already exists. + ## puts a new (key, value)-pair into `t` even if ``t[key]`` already exists. ## This can introduce duplicate keys into the table! withLock t: addImpl(enlarge) proc del*[A, B](t: var SharedTable[A, B], key: A) = - ## Deletes `key` from hash table `t`. + ## deletes `key` from hash table `t`. withLock t: - delImpl(tabMakeEmpty, tabCellEmpty, tabCellHash) + delImpl() -proc len*[A, B](t: var SharedTable[A, B]): int = - ## Number of elements in `t`. - withLock t: - result = t.counter - -proc init*[A, B](t: var SharedTable[A, B], initialSize = 32) = - ## Creates a new hash table that is empty. +proc init*[A, B](t: var SharedTable[A, B], initialSize = 64) = + ## creates a new hash table that is empty. ## ## This proc must be called before any other usage of `t`. - let initialSize = slotsNeeded(initialSize) + ## + ## `initialSize` needs to be a power of two. If you need to accept runtime + ## values for this you could use the ``nextPowerOfTwo`` proc from the + ## `math `_ module or the ``rightSize`` proc from this module. + assert isPowerOfTwo(initialSize) t.counter = 0 t.dataLen = initialSize t.data = cast[KeyValuePairSeq[A, B]](allocShared0( @@ -250,3 +222,13 @@ proc init*[A, B](t: var SharedTable[A, B], initialSize = 32) = proc deinitSharedTable*[A, B](t: var SharedTable[A, B]) = deallocShared(t.data) deinitLock t.lock + +proc initSharedTable*[A, B](initialSize = 64): SharedTable[A, B] {.deprecated: + "use 'init' instead".} = + ## This is not posix compliant, may introduce undefined behavior. + assert isPowerOfTwo(initialSize) + result.counter = 0 + result.dataLen = initialSize + result.data = cast[KeyValuePairSeq[A, B]](allocShared0( + sizeof(KeyValuePair[A, B]) * initialSize)) + initLock result.lock diff --git a/lib/pure/collections/tableimpl.nim b/lib/pure/collections/tableimpl.nim index 81079a3d1..85bffd60f 100644 --- a/lib/pure/collections/tableimpl.nim +++ b/lib/pure/collections/tableimpl.nim @@ -7,7 +7,7 @@ # distribution, for details about the copyright. # -# An `include` file for the different table implementations. +# An ``include`` file for the different table implementations. include hashcommon @@ -23,11 +23,11 @@ template rawInsertImpl() {.dirty.} = data[h].val = val data[h].hcode = hc -proc rawGetDeep[X, A](t: X, key: A, hc: var Hash): int {.inline, outParamsAt: [3].} = +proc rawGetDeep[X, A](t: X, key: A, hc: var Hash): int {.inline.} = rawGetDeepImpl() proc rawInsert[X, A, B](t: var X, data: var KeyValuePairSeq[A, B], - key: A, val: sink B, hc: Hash, h: Hash) = + key: A, val: B, hc: Hash, h: Hash) = rawInsertImpl() template checkIfInitialized() = @@ -37,7 +37,7 @@ template checkIfInitialized() = template addImpl(enlarge) {.dirty.} = checkIfInitialized() - if mustRehash(t): enlarge(t) + if mustRehash(t.dataLen, t.counter): enlarge(t) var hc: Hash var j = rawGetDeep(t, key, hc) rawInsert(t, t.data, key, val, hc, j) @@ -45,7 +45,7 @@ template addImpl(enlarge) {.dirty.} = template maybeRehashPutImpl(enlarge) {.dirty.} = checkIfInitialized() - if mustRehash(t): + if mustRehash(t.dataLen, t.counter): enlarge(t) index = rawGetKnownHC(t, key, hc) index = -1 - index # important to transform for mgetOrPutImpl @@ -78,52 +78,22 @@ template hasKeyOrPutImpl(enlarge) {.dirty.} = maybeRehashPutImpl(enlarge) else: result = true -# delImplIdx is KnuthV3 Algo6.4R adapted to i=i+1 (from i=i-1) which has come to -# be called "back shift delete". It shifts elements in the collision cluster of -# a victim backward to make things as-if the victim were never inserted in the -# first place. This is desirable to keep things "ageless" after many deletes. -# It is trickier than you might guess since initial probe (aka "home") locations -# of keys in a cluster may collide and since table addresses wrap around. -# -# A before-after diagram might look like ('.' means empty): -# slot: 0 1 2 3 4 5 6 7 -# before(1) -# hash1: 6 7 . 3 . 5 5 6 ; Really hash() and msk -# data1: E F . A . B C D ; About to delete C @index 6 -# after(2) -# hash2: 7 . . 3 . 5 6 6 ; Really hash() and msk -# data2: F . . A . B D E ; After deletion of C -# -# This lowers total search depth over the whole table from 1+1+2+2+2+2=10 to 7. -# Had the victim been B@5, C would need back shifting to slot 5. Total depth is -# always lowered by at least 1, e.g. victim A@3. This is all quite fast when -# empty slots are frequent (also needed to keep insert/miss searches fast) and -# hash() is either fast or avoided (via `.hcode`). It need not compare keys. -# -# delImplIdx realizes the above transformation, but only works for dense Linear -# Probing, nextTry(h)=h+1. This is not an important limitation since that's the -# fastest sequence on any CPU made since the 1980s. { Performance analysis often -# overweights "key cmp" neglecting cache behavior, giving bad ideas how big/slow -# tables behave (when perf matters most!). Comparing hcode first means usually -# only 1 key cmp is needed for *any* seq. Timing only predictable activity, -# small tables, and/or integer keys often perpetuates such bad ideas. } - -template delImplIdx(t, i, makeEmpty, cellEmpty, cellHash) = +template delImplIdx(t, i) = let msk = maxHash(t) if i >= 0: dec(t.counter) block outer: while true: # KnuthV3 Algo6.4R adapted for i=i+1 instead of i=i-1 - var j = i # The correctness of this depends on (h+1) in nextTry + var j = i # The correctness of this depends on (h+1) in nextTry, var r = j # though may be adaptable to other simple sequences. - makeEmpty(i) # mark current EMPTY - t.data[i].key = default(typeof(t.data[i].key)) - t.data[i].val = default(typeof(t.data[i].val)) + t.data[i].hcode = 0 # mark current EMPTY + t.data[i].key = default(type(t.data[i].key)) + t.data[i].val = default(type(t.data[i].val)) while true: i = (i + 1) and msk # increment mod table size - if cellEmpty(i): # end of collision cluster; So all done + if isEmpty(t.data[i].hcode): # end of collision cluster; So all done break outer - r = cellHash(i) and msk # initial probe index for key@slot i + r = t.data[i].hcode and msk # "home" location of key@i if not ((i >= r and r > j) or (r > j and j > i) or (j > i and i >= r)): break when defined(js): @@ -131,48 +101,30 @@ template delImplIdx(t, i, makeEmpty, cellEmpty, cellHash) = else: t.data[j] = move(t.data[i]) # data[j] will be marked EMPTY next loop -template delImpl(makeEmpty, cellEmpty, cellHash) {.dirty.} = +template delImpl() {.dirty.} = var hc: Hash var i = rawGet(t, key, hc) - delImplIdx(t, i, makeEmpty, cellEmpty, cellHash) - -template delImplNoHCode(makeEmpty, cellEmpty, cellHash) {.dirty.} = - if t.dataLen > 0: - var i: Hash = hash(key) and maxHash(t) - while not cellEmpty(i): - if t.data[i].key == key: - delImplIdx(t, i, makeEmpty, cellEmpty, cellHash) - break - i = nextTry(i, maxHash(t)) + delImplIdx(t, i) template clearImpl() {.dirty.} = for i in 0 ..< t.dataLen: when compiles(t.data[i].hcode): # CountTable records don't contain a hcode t.data[i].hcode = 0 - t.data[i].key = default(typeof(t.data[i].key)) - t.data[i].val = default(typeof(t.data[i].val)) + t.data[i].key = default(type(t.data[i].key)) + t.data[i].val = default(type(t.data[i].val)) t.counter = 0 -template ctAnd(a, b): bool = - when a: - when b: true - else: false - else: false - template initImpl(result: typed, size: int) = - let correctSize = slotsNeeded(size) - when ctAnd(declared(SharedTable), typeof(result) is SharedTable): - init(result, correctSize) - else: - result.counter = 0 - newSeq(result.data, correctSize) - when compiles(result.first): - result.first = -1 - result.last = -1 + assert isPowerOfTwo(size) + result.counter = 0 + newSeq(result.data, size) + when compiles(result.first): + result.first = -1 + result.last = -1 template insertImpl() = # for CountTable if t.dataLen == 0: initImpl(t, defaultInitialSize) - if mustRehash(t): enlarge(t) + if mustRehash(len(t.data), t.counter): enlarge(t) ctRawInsert(t, t.data, key, val) inc(t.counter) diff --git a/lib/pure/collections/tables.nim b/lib/pure/collections/tables.nim index 4737fa478..a0cc73ad6 100644 --- a/lib/pure/collections/tables.nim +++ b/lib/pure/collections/tables.nim @@ -7,137 +7,158 @@ # distribution, for details about the copyright. # -## The `tables` module implements variants of an efficient `hash table`:idx: +## The ``tables`` module implements variants of an efficient `hash table`:idx: ## (also often named `dictionary`:idx: in other programming languages) that is ## a mapping from keys to values. ## ## There are several different types of hash tables available: ## * `Table<#Table>`_ is the usual hash table, -## * `OrderedTable<#OrderedTable>`_ is like `Table` but remembers insertion order, +## * `OrderedTable<#OrderedTable>`_ is like ``Table`` but remembers insertion order, ## * `CountTable<#CountTable>`_ is a mapping from a key to its number of occurrences ## ## For consistency with every other data type in Nim these have **value** -## semantics, this means that `=` performs a copy of the hash table. +## semantics, this means that ``=`` performs a copy of the hash table. ## ## For `ref semantics`_ -## use their `Ref` variants: `TableRef<#TableRef>`_, +## use their ``Ref`` variants: `TableRef<#TableRef>`_, ## `OrderedTableRef<#OrderedTableRef>`_, and `CountTableRef<#CountTableRef>`_. ## -## To give an example, when `a` is a `Table`, then `var b = a` gives `b` -## as a new independent table. `b` is initialised with the contents of `a`. -## Changing `b` does not affect `a` and vice versa: - -runnableExamples: - var - a = {1: "one", 2: "two"}.toTable # creates a Table - b = a - - assert a == b - - b[3] = "three" - assert 3 notin a - assert 3 in b - assert a != b - -## On the other hand, when `a` is a `TableRef` instead, then changes to `b` -## also affect `a`. Both `a` and `b` **ref** the same data structure: - -runnableExamples: - var - a = {1: "one", 2: "two"}.newTable # creates a TableRef - b = a - - assert a == b - - b[3] = "three" - - assert 3 in a - assert 3 in b - assert a == b - +## To give an example, when ``a`` is a ``Table``, then ``var b = a`` gives ``b`` +## as a new independent table. ``b`` is initialised with the contents of ``a``. +## Changing ``b`` does not affect ``a`` and vice versa: +## +## .. code-block:: +## import tables +## +## var +## a = {1: "one", 2: "two"}.toTable # creates a Table +## b = a +## +## echo a, b # output: {1: one, 2: two}{1: one, 2: two} +## +## b[3] = "three" +## echo a, b # output: {1: one, 2: two}{1: one, 2: two, 3: three} +## echo a == b # output: false +## +## On the other hand, when ``a`` is a ``TableRef`` instead, then changes to ``b`` +## also affect ``a``. Both ``a`` and ``b`` **ref** the same data structure: +## +## .. code-block:: +## import tables +## +## var +## a = {1: "one", 2: "two"}.newTable # creates a TableRef +## b = a +## +## echo a, b # output: {1: one, 2: two}{1: one, 2: two} +## +## b[3] = "three" +## echo a, b # output: {1: one, 2: two, 3: three}{1: one, 2: two, 3: three} +## echo a == b # output: true ## ## ---- ## - -## # Basic usage - - -## ## Table -runnableExamples: - from std/sequtils import zip - - let - names = ["John", "Paul", "George", "Ringo"] - years = [1940, 1942, 1943, 1940] - - var beatles = initTable[string, int]() - - for pairs in zip(names, years): - let (name, birthYear) = pairs - beatles[name] = birthYear - - assert beatles == {"George": 1943, "Ringo": 1940, "Paul": 1942, "John": 1940}.toTable - - - var beatlesByYear = initTable[int, seq[string]]() - - for pairs in zip(years, names): - let (birthYear, name) = pairs - if not beatlesByYear.hasKey(birthYear): - # if a key doesn't exist, we create one with an empty sequence - # before we can add elements to it - beatlesByYear[birthYear] = @[] - beatlesByYear[birthYear].add(name) - - assert beatlesByYear == {1940: @["John", "Ringo"], 1942: @["Paul"], 1943: @["George"]}.toTable - -## ## OrderedTable +## Basic usage +## =========== +## +## Table +## ----- +## +## .. code-block:: +## import tables +## from sequtils import zip +## +## let +## names = ["John", "Paul", "George", "Ringo"] +## years = [1940, 1942, 1943, 1940] +## +## var beatles = initTable[string, int]() +## +## for pairs in zip(names, years): +## let (name, birthYear) = pairs +## beatles[name] = birthYear +## +## echo beatles +## # {"George": 1943, "Ringo": 1940, "Paul": 1942, "John": 1940} +## +## +## var beatlesByYear = initTable[int, seq[string]]() +## +## for pairs in zip(years, names): +## let (birthYear, name) = pairs +## if not beatlesByYear.hasKey(birthYear): +## # if a key doesn't exist, we create one with an empty sequence +## # before we can add elements to it +## beatlesByYear[birthYear] = @[] +## beatlesByYear[birthYear].add(name) +## +## echo beatlesByYear +## # {1940: @["John", "Ringo"], 1942: @["Paul"], 1943: @["George"]} +## +## +## +## OrderedTable +## ------------ +## ## `OrderedTable<#OrderedTable>`_ is used when it is important to preserve ## the insertion order of keys. - -runnableExamples: - let - a = [('z', 1), ('y', 2), ('x', 3)] - ot = a.toOrderedTable # ordered tables - - assert $ot == """{'z': 1, 'y': 2, 'x': 3}""" - -## ## CountTable +## +## .. code-block:: +## import tables +## +## let +## a = [('z', 1), ('y', 2), ('x', 3)] +## t = a.toTable # regular table +## ot = a.toOrderedTable # ordered tables +## +## echo t # {'x': 3, 'y': 2, 'z': 1} +## echo ot # {'z': 1, 'y': 2, 'x': 3} +## +## +## +## CountTable +## ---------- +## ## `CountTable<#CountTable>`_ is useful for counting number of items of some ## container (e.g. string, sequence or array), as it is a mapping where the ## items are the keys, and their number of occurrences are the values. ## For that purpose `toCountTable proc<#toCountTable,openArray[A]>`_ ## comes handy: - -runnableExamples: - let myString = "abracadabra" - let letterFrequencies = toCountTable(myString) - assert $letterFrequencies == "{'a': 5, 'd': 1, 'b': 2, 'r': 2, 'c': 1}" - +## +## .. code-block:: +## import tables +## +## let myString = "abracadabra" +## let letterFrequencies = toCountTable(myString) +## echo letterFrequencies +## # 'a': 5, 'b': 2, 'c': 1, 'd': 1, 'r': 2} +## ## The same could have been achieved by manually iterating over a container ## and increasing each key's value with `inc proc -## <#inc,CountTable[A],A,int>`_: - -runnableExamples: - let myString = "abracadabra" - var letterFrequencies = initCountTable[char]() - for c in myString: - letterFrequencies.inc(c) - assert $letterFrequencies == "{'d': 1, 'r': 2, 'c': 1, 'a': 5, 'b': 2}" - +## <#inc,CountTable[A],A,Positive>`_: +## +## .. code-block:: +## import tables +## +## let myString = "abracadabra" +## var letterFrequencies = initCountTable[char]() +## for c in myString: +## letterFrequencies.inc(c) +## echo letterFrequencies +## # output: {'a': 5, 'b': 2, 'c': 1, 'd': 1, 'r': 2} ## ## ---- ## - -## ## Hashing ## -## If you are using simple standard types like `int` or `string` for the +## +## Hashing +## ------- +## +## If you are using simple standard types like ``int`` or ``string`` for the ## keys of the table you won't have any problems, but as soon as you try to use ## a more complex object as a key you will be greeted by a strange compiler ## error: ## -## .. code:: -## ## Error: type mismatch: got (Person) ## but expected one of: ## hashes.hash(x: openArray[A]): Hash @@ -146,62 +167,59 @@ runnableExamples: ## … ## ## What is happening here is that the types used for table keys require to have -## a `hash()` proc which will convert them to a `Hash `_ +## a ``hash()`` proc which will convert them to a `Hash `_ ## value, and the compiler is listing all the hash functions it knows. -## Additionally there has to be a `==` operator that provides the same -## semantics as its corresponding `hash` proc. +## Additionally there has to be a ``==`` operator that provides the same +## semantics as its corresponding ``hash`` proc. ## -## After you add `hash` and `==` for your custom type everything will work. -## Currently, however, `hash` for objects is not defined, whereas -## `system.==` for objects does exist and performs a "deep" comparison (every +## After you add ``hash`` and ``==`` for your custom type everything will work. +## Currently, however, ``hash`` for objects is not defined, whereas +## ``system.==`` for objects does exist and performs a "deep" comparison (every ## field is compared) which is usually what you want. So in the following -## example implementing only `hash` suffices: - -runnableExamples: - import std/hashes - - type - Person = object - firstName, lastName: string - - proc hash(x: Person): Hash = - ## Piggyback on the already available string hash proc. - ## - ## Without this proc nothing works! - result = x.firstName.hash !& x.lastName.hash - result = !$result - - var - salaries = initTable[Person, int]() - p1, p2: Person - - p1.firstName = "Jon" - p1.lastName = "Ross" - salaries[p1] = 30_000 - - p2.firstName = "소진" - p2.lastName = "박" - salaries[p2] = 45_000 - +## example implementing only ``hash`` suffices: +## +## .. code-block:: +## import tables, hashes +## +## type +## Person = object +## firstName, lastName: string +## +## proc hash(x: Person): Hash = +## ## Piggyback on the already available string hash proc. +## ## +## ## Without this proc nothing works! +## result = x.firstName.hash !& x.lastName.hash +## result = !$result +## +## var +## salaries = initTable[Person, int]() +## p1, p2: Person +## +## p1.firstName = "Jon" +## p1.lastName = "Ross" +## salaries[p1] = 30_000 +## +## p2.firstName = "소진" +## p2.lastName = "박" +## salaries[p2] = 45_000 ## ## ---- ## - -## # See also +## See also +## ======== ## ## * `json module`_ for table-like structure which allows ## heterogeneous members +## * `sharedtables module`_ for shared hash table support ## * `strtabs module`_ for efficient hash tables ## mapping from strings to strings ## * `hashes module`_ for helper functions for hashing -import std/private/since import hashes, math, algorithm - -when not defined(nimHasEffectsOf): - {.pragma: effectsOf.} +include "system/inclrtl" type KeyValuePair[A, B] = tuple[hcode: Hash, key: A, val: B] @@ -212,16 +230,16 @@ type ## `data` and `counter` are internal implementation details which ## can't be accessed. ## - ## For creating an empty Table, use `initTable proc<#initTable>`_. + ## For creating an empty Table, use `initTable proc<#initTable,int>`_. data: KeyValuePairSeq[A, B] counter: int TableRef*[A, B] = ref Table[A, B] ## Ref version of `Table<#Table>`_. ## ## For creating a new empty TableRef, use `newTable proc - ## <#newTable>`_. + ## <#newTable,int>`_. const - defaultInitialSize* = 32 + defaultInitialSize* = 64 # ------------------------------ helpers --------------------------------- @@ -232,21 +250,20 @@ template dataLen(t): untyped = len(t.data) include tableimpl -proc raiseKeyError[T](key: T) {.noinline, noreturn.} = - when compiles($key): - raise newException(KeyError, "key not found: " & $key) - else: - raise newException(KeyError, "key not found") +proc rightSize*(count: Natural): int {.inline.} template get(t, key): untyped = - ## retrieves the value at `t[key]`. The value can be modified. - ## If `key` is not in `t`, the `KeyError` exception is raised. + ## retrieves the value at ``t[key]``. The value can be modified. + ## If ``key`` is not in ``t``, the ``KeyError`` exception is raised. mixin rawGet var hc: Hash var index = rawGet(t, key, hc) if index >= 0: result = t.data[index].val else: - raiseKeyError(key) + when compiles($key): + raise newException(KeyError, "key not found: " & $key) + else: + raise newException(KeyError, "key not found") proc enlarge[A, B](t: var Table[A, B]) = var n: KeyValuePairSeq[A, B] @@ -273,20 +290,26 @@ proc enlarge[A, B](t: var Table[A, B]) = proc initTable*[A, B](initialSize = defaultInitialSize): Table[A, B] = ## Creates a new hash table that is empty. ## + ## ``initialSize`` must be a power of two (default: 64). + ## If you need to accept runtime values for this you could use the + ## `nextPowerOfTwo proc`_ from the + ## `math module`_ or the `rightSize proc<#rightSize,Natural>`_ + ## from this module. + ## ## Starting from Nim v0.20, tables are initialized by default and it is ## not necessary to call this function explicitly. ## ## See also: ## * `toTable proc<#toTable,openArray[]>`_ - ## * `newTable proc<#newTable>`_ for creating a `TableRef` + ## * `newTable proc<#newTable,int>`_ for creating a `TableRef` runnableExamples: let a = initTable[int, string]() b = initTable[char, seq[int]]() initImpl(result, initialSize) -proc `[]=`*[A, B](t: var Table[A, B], key: A, val: sink B) = - ## Inserts a `(key, value)` pair into `t`. +proc `[]=`*[A, B](t: var Table[A, B], key: A, val: B) = + ## Inserts a ``(key, value)`` pair into ``t``. ## ## See also: ## * `[] proc<#[],Table[A,B],A>`_ for retrieving a value of a key @@ -302,25 +325,25 @@ proc `[]=`*[A, B](t: var Table[A, B], key: A, val: sink B) = putImpl(enlarge) proc toTable*[A, B](pairs: openArray[(A, B)]): Table[A, B] = - ## Creates a new hash table that contains the given `pairs`. + ## Creates a new hash table that contains the given ``pairs``. ## - ## `pairs` is a container consisting of `(key, value)` tuples. + ## ``pairs`` is a container consisting of ``(key, value)`` tuples. ## ## See also: - ## * `initTable proc<#initTable>`_ + ## * `initTable proc<#initTable,int>`_ ## * `newTable proc<#newTable,openArray[]>`_ for a `TableRef` version runnableExamples: let a = [('a', 5), ('b', 9)] let b = toTable(a) assert b == {'a': 5, 'b': 9}.toTable - result = initTable[A, B](pairs.len) + result = initTable[A, B](rightSize(pairs.len)) for key, val in items(pairs): result[key] = val proc `[]`*[A, B](t: Table[A, B], key: A): B = - ## Retrieves the value at `t[key]`. + ## Retrieves the value at ``t[key]``. ## - ## If `key` is not in `t`, the `KeyError` exception is raised. + ## If ``key`` is not in ``t``, the ``KeyError`` exception is raised. ## One can check with `hasKey proc<#hasKey,Table[A,B],A>`_ whether ## the key exists. ## @@ -329,7 +352,7 @@ proc `[]`*[A, B](t: Table[A, B], key: A): B = ## a default value (e.g. zero for int) if the key doesn't exist ## * `getOrDefault proc<#getOrDefault,Table[A,B],A,B>`_ to return ## a custom value if the key doesn't exist - ## * `[]= proc<#[]=,Table[A,B],A,sinkB>`_ for inserting a new + ## * `[]= proc<#[]=,Table[A,B],A,B>`_ for inserting a new ## (key, value) pair in the table ## * `hasKey proc<#hasKey,Table[A,B],A>`_ for checking if a key is in ## the table @@ -341,23 +364,23 @@ proc `[]`*[A, B](t: Table[A, B], key: A): B = get(t, key) proc `[]`*[A, B](t: var Table[A, B], key: A): var B = - ## Retrieves the value at `t[key]`. The value can be modified. + ## Retrieves the value at ``t[key]``. The value can be modified. ## - ## If `key` is not in `t`, the `KeyError` exception is raised. + ## If ``key`` is not in ``t``, the ``KeyError`` exception is raised. ## ## See also: ## * `getOrDefault proc<#getOrDefault,Table[A,B],A>`_ to return ## a default value (e.g. zero for int) if the key doesn't exist ## * `getOrDefault proc<#getOrDefault,Table[A,B],A,B>`_ to return ## a custom value if the key doesn't exist - ## * `[]= proc<#[]=,Table[A,B],A,sinkB>`_ for inserting a new + ## * `[]= proc<#[]=,Table[A,B],A,B>`_ for inserting a new ## (key, value) pair in the table ## * `hasKey proc<#hasKey,Table[A,B],A>`_ for checking if a key is in ## the table get(t, key) proc hasKey*[A, B](t: Table[A, B], key: A): bool = - ## Returns true if `key` is in the table `t`. + ## Returns true if ``key`` is in the table ``t``. ## ## See also: ## * `contains proc<#contains,Table[A,B],A>`_ for use with the `in` operator @@ -376,7 +399,7 @@ proc hasKey*[A, B](t: Table[A, B], key: A): bool = proc contains*[A, B](t: Table[A, B], key: A): bool = ## Alias of `hasKey proc<#hasKey,Table[A,B],A>`_ for use with - ## the `in` operator. + ## the ``in`` operator. runnableExamples: let a = {'a': 5, 'b': 9}.toTable doAssert 'b' in a == true @@ -385,7 +408,7 @@ proc contains*[A, B](t: Table[A, B], key: A): bool = return hasKey[A, B](t, key) proc hasKeyOrPut*[A, B](t: var Table[A, B], key: A, val: B): bool = - ## Returns true if `key` is in the table, otherwise inserts `value`. + ## Returns true if ``key`` is in the table, otherwise inserts ``value``. ## ## See also: ## * `hasKey proc<#hasKey,Table[A,B],A>`_ @@ -405,8 +428,8 @@ proc hasKeyOrPut*[A, B](t: var Table[A, B], key: A, val: B): bool = hasKeyOrPutImpl(enlarge) proc getOrDefault*[A, B](t: Table[A, B], key: A): B = - ## Retrieves the value at `t[key]` if `key` is in `t`. Otherwise, the - ## default initialization value for type `B` is returned (e.g. 0 for any + ## Retrieves the value at ``t[key]`` if ``key`` is in ``t``. Otherwise, the + ## default initialization value for type ``B`` is returned (e.g. 0 for any ## integer type). ## ## See also: @@ -424,8 +447,8 @@ proc getOrDefault*[A, B](t: Table[A, B], key: A): B = getOrDefaultImpl(t, key) proc getOrDefault*[A, B](t: Table[A, B], key: A, default: B): B = - ## Retrieves the value at `t[key]` if `key` is in `t`. - ## Otherwise, `default` is returned. + ## Retrieves the value at ``t[key]`` if ``key`` is in ``t``. + ## Otherwise, ``default`` is returned. ## ## See also: ## * `[] proc<#[],Table[A,B],A>`_ for retrieving a value of a key @@ -442,16 +465,9 @@ proc getOrDefault*[A, B](t: Table[A, B], key: A, default: B): B = getOrDefaultImpl(t, key, default) proc mgetOrPut*[A, B](t: var Table[A, B], key: A, val: B): var B = - ## Retrieves value at `t[key]` or puts `val` if not present, either way + ## Retrieves value at ``t[key]`` or puts ``val`` if not present, either way ## returning a value which can be modified. ## - ## - ## Note that while the value returned is of type `var B`, - ## it is easy to accidentally create a copy of the value at `t[key]`. - ## Remember that seqs and strings are value types, and therefore - ## cannot be copied into a separate variable for modification. - ## See the example below. - ## ## See also: ## * `[] proc<#[],Table[A,B],A>`_ for retrieving a value of a key ## * `hasKey proc<#hasKey,Table[A,B],A>`_ @@ -466,46 +482,27 @@ proc mgetOrPut*[A, B](t: var Table[A, B], key: A, val: B): var B = doAssert a.mgetOrPut('z', 99) == 99 doAssert a == {'a': 5, 'b': 9, 'z': 99}.toTable - # An example of accidentally creating a copy - var t = initTable[int, seq[int]]() - # In this example, we expect t[10] to be modified, - # but it is not. - var copiedSeq = t.mgetOrPut(10, @[10]) - copiedSeq.add(20) - doAssert t[10] == @[10] - # Correct - t.mgetOrPut(25, @[25]).add(35) - doAssert t[25] == @[25, 35] - mgetOrPutImpl(enlarge) proc len*[A, B](t: Table[A, B]): int = - ## Returns the number of keys in `t`. + ## Returns the number of keys in ``t``. runnableExamples: let a = {'a': 5, 'b': 9}.toTable doAssert len(a) == 2 result = t.counter -proc add*[A, B](t: var Table[A, B], key: A, val: sink B) {.deprecated: - "Deprecated since v1.4; it was more confusing than useful, use `[]=`".} = - ## Puts a new `(key, value)` pair into `t` even if `t[key]` already exists. +proc add*[A, B](t: var Table[A, B], key: A, val: B) = + ## Puts a new ``(key, value)`` pair into ``t`` even if ``t[key]`` already exists. ## ## **This can introduce duplicate keys into the table!** ## - ## Use `[]= proc<#[]=,Table[A,B],A,sinkB>`_ for inserting a new + ## Use `[]= proc<#[]=,Table[A,B],A,B>`_ for inserting a new ## (key, value) pair in the table without introducing duplicates. addImpl(enlarge) -template tabMakeEmpty(i) = t.data[i].hcode = 0 -template tabCellEmpty(i) = isEmpty(t.data[i].hcode) -template tabCellHash(i) = t.data[i].hcode - proc del*[A, B](t: var Table[A, B], key: A) = - ## Deletes `key` from hash table `t`. Does nothing if the key does not exist. - ## - ## .. warning:: If duplicate keys were added (via the now deprecated `add` proc), - ## this may need to be called multiple times. + ## Deletes ``key`` from hash table ``t``. Does nothing if the key does not exist. ## ## See also: ## * `pop proc<#pop,Table[A,B],A,B>`_ @@ -517,17 +514,14 @@ proc del*[A, B](t: var Table[A, B], key: A) = a.del('z') doAssert a == {'b': 9, 'c': 13}.toTable - delImpl(tabMakeEmpty, tabCellEmpty, tabCellHash) + delImpl() proc pop*[A, B](t: var Table[A, B], key: A, val: var B): bool = - ## Deletes the `key` from the table. - ## Returns `true`, if the `key` existed, and sets `val` to the - ## mapping of the key. Otherwise, returns `false`, and the `val` is + ## Deletes the ``key`` from the table. + ## Returns ``true``, if the ``key`` existed, and sets ``val`` to the + ## mapping of the key. Otherwise, returns ``false``, and the ``val`` is ## unchanged. ## - ## .. warning:: If duplicate keys were added (via the now deprecated `add` proc), - ## this may need to be called multiple times. - ## ## See also: ## * `del proc<#del,Table[A,B],A>`_ ## * `clear proc<#clear,Table[A,B]>`_ to empty the whole table @@ -548,7 +542,7 @@ proc pop*[A, B](t: var Table[A, B], key: A, val: var B): bool = result = index >= 0 if result: val = move(t.data[index].val) - delImplIdx(t, index, tabMakeEmpty, tabCellEmpty, tabCellHash) + delImplIdx(t, index) proc take*[A, B](t: var Table[A, B], key: A, val: var B): bool {.inline.} = ## Alias for: @@ -570,12 +564,12 @@ proc clear*[A, B](t: var Table[A, B]) = clearImpl() proc `$`*[A, B](t: Table[A, B]): string = - ## The `$` operator for hash tables. Used internally when calling `echo` + ## The ``$`` operator for hash tables. Used internally when calling `echo` ## on a table. dollarImpl() proc `==`*[A, B](s, t: Table[A, B]): bool = - ## The `==` operator for hash tables. Returns `true` if the content of both + ## The ``==`` operator for hash tables. Returns ``true`` if the content of both ## tables contains the same key-value pairs. Insert order does not matter. runnableExamples: let @@ -585,6 +579,15 @@ proc `==`*[A, B](s, t: Table[A, B]): bool = equalsImpl(s, t) +proc rightSize*(count: Natural): int {.inline.} = + ## Return the value of ``initialSize`` to support ``count`` items. + ## + ## If more items are expected to be added, simply add that + ## expected extra amount to the parameter before calling this. + ## + ## Internally, we want mustRehash(rightSize(x), x) == false. + result = nextPowerOfTwo(count * 3 div 2 + 4) + proc indexBy*[A, B, C](collection: A, index: proc(x: B): C): Table[C, B] = ## Index the collection with the proc provided. # TODO: As soon as supported, change collection: A to collection: A[B] @@ -595,31 +598,17 @@ proc indexBy*[A, B, C](collection: A, index: proc(x: B): C): Table[C, B] = template withValue*[A, B](t: var Table[A, B], key: A, value, body: untyped) = - ## Retrieves the value at `t[key]`. + ## Retrieves the value at ``t[key]``. + ## + ## ``value`` can be modified in the scope of the ``withValue`` call. + ## + ## .. code-block:: nim + ## + ## sharedTable.withValue(key, value) do: + ## # block is executed only if ``key`` in ``t`` + ## value.name = "username" + ## value.uid = 1000 ## - ## `value` can be modified in the scope of the `withValue` call. - runnableExamples: - type - User = object - name: string - uid: int - - var t = initTable[int, User]() - let u = User(name: "Hello", uid: 99) - t[1] = u - - t.withValue(1, value): - # block is executed only if `key` in `t` - value.name = "Nim" - value.uid = 1314 - - t.withValue(2, value): - value.name = "No" - value.uid = 521 - - assert t[1].name == "Nim" - assert t[1].uid == 1314 - mixin rawGet var hc: Hash var index = rawGet(t, key, hc) @@ -630,35 +619,20 @@ template withValue*[A, B](t: var Table[A, B], key: A, value, body: untyped) = template withValue*[A, B](t: var Table[A, B], key: A, value, body1, body2: untyped) = - ## Retrieves the value at `t[key]`. + ## Retrieves the value at ``t[key]``. + ## + ## ``value`` can be modified in the scope of the ``withValue`` call. + ## + ## .. code-block:: nim + ## + ## table.withValue(key, value) do: + ## # block is executed only if ``key`` in ``t`` + ## value.name = "username" + ## value.uid = 1000 + ## do: + ## # block is executed when ``key`` not in ``t`` + ## raise newException(KeyError, "Key not found") ## - ## `value` can be modified in the scope of the `withValue` call. - runnableExamples: - type - User = object - name: string - uid: int - - var t = initTable[int, User]() - let u = User(name: "Hello", uid: 99) - t[1] = u - - t.withValue(1, value): - # block is executed only if `key` in `t` - value.name = "Nim" - value.uid = 1314 - - t.withValue(521, value): - doAssert false - do: - # block is executed when `key` not in `t` - t[1314] = User(name: "exist", uid: 521) - - assert t[1].name == "Nim" - assert t[1].uid == 1314 - assert t[1314].name == "exist" - assert t[1314].uid == 521 - mixin rawGet var hc: Hash var index = rawGet(t, key, hc) @@ -671,7 +645,7 @@ template withValue*[A, B](t: var Table[A, B], key: A, iterator pairs*[A, B](t: Table[A, B]): (A, B) = - ## Iterates over any `(key, value)` pair in the table `t`. + ## Iterates over any ``(key, value)`` pair in the table ``t``. ## ## See also: ## * `mpairs iterator<#mpairs.i,Table[A,B]>`_ @@ -701,7 +675,7 @@ iterator pairs*[A, B](t: Table[A, B]): (A, B) = assert(len(t) == L, "the length of the table changed while iterating over it") iterator mpairs*[A, B](t: var Table[A, B]): (A, var B) = - ## Iterates over any `(key, value)` pair in the table `t` (must be + ## Iterates over any ``(key, value)`` pair in the table ``t`` (must be ## declared as `var`). The values can be modified. ## ## See also: @@ -722,8 +696,8 @@ iterator mpairs*[A, B](t: var Table[A, B]): (A, var B) = yield (t.data[h].key, t.data[h].val) assert(len(t) == L, "the length of the table changed while iterating over it") -iterator keys*[A, B](t: Table[A, B]): lent A = - ## Iterates over any key in the table `t`. +iterator keys*[A, B](t: Table[A, B]): A = + ## Iterates over any key in the table ``t``. ## ## See also: ## * `pairs iterator<#pairs.i,Table[A,B]>`_ @@ -743,8 +717,8 @@ iterator keys*[A, B](t: Table[A, B]): lent A = yield t.data[h].key assert(len(t) == L, "the length of the table changed while iterating over it") -iterator values*[A, B](t: Table[A, B]): lent B = - ## Iterates over any value in the table `t`. +iterator values*[A, B](t: Table[A, B]): B = + ## Iterates over any value in the table ``t``. ## ## See also: ## * `pairs iterator<#pairs.i,Table[A,B]>`_ @@ -765,7 +739,7 @@ iterator values*[A, B](t: Table[A, B]): lent B = assert(len(t) == L, "the length of the table changed while iterating over it") iterator mvalues*[A, B](t: var Table[A, B]): var B = - ## Iterates over any value in the table `t` (must be + ## Iterates over any value in the table ``t`` (must be ## declared as `var`). The values can be modified. ## ## See also: @@ -786,20 +760,25 @@ iterator mvalues*[A, B](t: var Table[A, B]): var B = yield t.data[h].val assert(len(t) == L, "the length of the table changed while iterating over it") -iterator allValues*[A, B](t: Table[A, B]; key: A): B {.deprecated: - "Deprecated since v1.4; tables with duplicated keys are deprecated".} = - ## Iterates over any value in the table `t` that belongs to the given `key`. +iterator allValues*[A, B](t: Table[A, B]; key: A): B = + ## Iterates over any value in the table ``t`` that belongs to the given ``key``. ## ## Used if you have a table with duplicate keys (as a result of using - ## `add proc<#add,Table[A,B],A,sinkB>`_). + ## `add proc<#add,Table[A,B],A,B>`_). ## - runnableExamples: - import std/[sequtils, algorithm] - - var a = {'a': 3, 'b': 5}.toTable - for i in 1..3: a.add('z', 10*i) - doAssert toSeq(a.pairs).sorted == @[('a', 3), ('b', 5), ('z', 10), ('z', 20), ('z', 30)] - doAssert sorted(toSeq(a.allValues('z'))) == @[10, 20, 30] + ## **Examples:** + ## + ## .. code-block:: + ## var a = {'a': 3, 'b': 5}.toTable + ## for i in 1..3: + ## a.add('z', 10*i) + ## echo a # {'a': 3, 'b': 5, 'z': 10, 'z': 20, 'z': 30} + ## + ## for v in a.allValues('z'): + ## echo v + ## # 10 + ## # 20 + ## # 30 var h: Hash = genHash(key) and high(t.data) let L = len(t) while isFilled(t.data[h].hcode): @@ -815,29 +794,34 @@ iterator allValues*[A, B](t: Table[A, B]; key: A): B {.deprecated: # ------------------------------------------------------------------- -proc newTable*[A, B](initialSize = defaultInitialSize): TableRef[A, B] = +proc newTable*[A, B](initialSize = defaultInitialSize): TableRef[A, B] = ## Creates a new ref hash table that is empty. ## + ## ``initialSize`` must be a power of two (default: 64). + ## If you need to accept runtime values for this you could use the + ## `nextPowerOfTwo proc`_ from the + ## `math module`_ or the `rightSize proc<#rightSize,Natural>`_ + ## from this module. + ## ## See also: ## * `newTable proc<#newTable,openArray[]>`_ for creating a `TableRef` ## from a collection of `(key, value)` pairs - ## * `initTable proc<#initTable>`_ for creating a `Table` + ## * `initTable proc<#initTable,int>`_ for creating a `Table` runnableExamples: let a = newTable[int, string]() b = newTable[char, seq[int]]() new(result) - {.noSideEffect.}: - result[] = initTable[A, B](initialSize) + result[] = initTable[A, B](initialSize) -proc newTable*[A, B](pairs: openArray[(A, B)]): TableRef[A, B] = - ## Creates a new ref hash table that contains the given `pairs`. +proc newTable*[A, B](pairs: openArray[(A, B)]): TableRef[A, B] = + ## Creates a new ref hash table that contains the given ``pairs``. ## - ## `pairs` is a container consisting of `(key, value)` tuples. + ## ``pairs`` is a container consisting of ``(key, value)`` tuples. ## ## See also: - ## * `newTable proc<#newTable>`_ + ## * `newTable proc<#newTable,int>`_ ## * `toTable proc<#toTable,openArray[]>`_ for a `Table` version runnableExamples: let a = [('a', 5), ('b', 9)] @@ -845,21 +829,19 @@ proc newTable*[A, B](pairs: openArray[(A, B)]): TableRef[A, B] = assert b == {'a': 5, 'b': 9}.newTable new(result) - {.noSideEffect.}: - result[] = toTable[A, B](pairs) + result[] = toTable[A, B](pairs) -proc newTableFrom*[A, B, C](collection: A, index: proc(x: B): C): TableRef[C, B] = +proc newTableFrom*[A, B, C](collection: A, index: proc(x: B): C): TableRef[C, B] = ## Index the collection with the proc provided. # TODO: As soon as supported, change collection: A to collection: A[B] result = newTable[C, B]() - {.noSideEffect.}: - for item in collection: - result[index(item)] = item + for item in collection: + result[index(item)] = item proc `[]`*[A, B](t: TableRef[A, B], key: A): var B = - ## Retrieves the value at `t[key]`. + ## Retrieves the value at ``t[key]``. ## - ## If `key` is not in `t`, the `KeyError` exception is raised. + ## If ``key`` is not in ``t``, the ``KeyError`` exception is raised. ## One can check with `hasKey proc<#hasKey,TableRef[A,B],A>`_ whether ## the key exists. ## @@ -868,7 +850,7 @@ proc `[]`*[A, B](t: TableRef[A, B], key: A): var B = ## a default value (e.g. zero for int) if the key doesn't exist ## * `getOrDefault proc<#getOrDefault,TableRef[A,B],A,B>`_ to return ## a custom value if the key doesn't exist - ## * `[]= proc<#[]=,TableRef[A,B],A,sinkB>`_ for inserting a new + ## * `[]= proc<#[]=,TableRef[A,B],A,B>`_ for inserting a new ## (key, value) pair in the table ## * `hasKey proc<#hasKey,TableRef[A,B],A>`_ for checking if a key is in ## the table @@ -880,8 +862,8 @@ proc `[]`*[A, B](t: TableRef[A, B], key: A): var B = result = t[][key] -proc `[]=`*[A, B](t: TableRef[A, B], key: A, val: sink B) = - ## Inserts a `(key, value)` pair into `t`. +proc `[]=`*[A, B](t: TableRef[A, B], key: A, val: B) = + ## Inserts a ``(key, value)`` pair into ``t``. ## ## See also: ## * `[] proc<#[],TableRef[A,B],A>`_ for retrieving a value of a key @@ -897,7 +879,7 @@ proc `[]=`*[A, B](t: TableRef[A, B], key: A, val: sink B) = t[][key] = val proc hasKey*[A, B](t: TableRef[A, B], key: A): bool = - ## Returns true if `key` is in the table `t`. + ## Returns true if ``key`` is in the table ``t``. ## ## See also: ## * `contains proc<#contains,TableRef[A,B],A>`_ for use with the `in` @@ -916,7 +898,7 @@ proc hasKey*[A, B](t: TableRef[A, B], key: A): bool = proc contains*[A, B](t: TableRef[A, B], key: A): bool = ## Alias of `hasKey proc<#hasKey,TableRef[A,B],A>`_ for use with - ## the `in` operator. + ## the ``in`` operator. runnableExamples: let a = {'a': 5, 'b': 9}.newTable doAssert 'b' in a == true @@ -924,8 +906,8 @@ proc contains*[A, B](t: TableRef[A, B], key: A): bool = return hasKey[A, B](t, key) -proc hasKeyOrPut*[A, B](t: TableRef[A, B], key: A, val: B): bool = - ## Returns true if `key` is in the table, otherwise inserts `value`. +proc hasKeyOrPut*[A, B](t: var TableRef[A, B], key: A, val: B): bool = + ## Returns true if ``key`` is in the table, otherwise inserts ``value``. ## ## See also: ## * `hasKey proc<#hasKey,TableRef[A,B],A>`_ @@ -945,8 +927,8 @@ proc hasKeyOrPut*[A, B](t: TableRef[A, B], key: A, val: B): bool = t[].hasKeyOrPut(key, val) proc getOrDefault*[A, B](t: TableRef[A, B], key: A): B = - ## Retrieves the value at `t[key]` if `key` is in `t`. Otherwise, the - ## default initialization value for type `B` is returned (e.g. 0 for any + ## Retrieves the value at ``t[key]`` if ``key`` is in ``t``. Otherwise, the + ## default initialization value for type ``B`` is returned (e.g. 0 for any ## integer type). ## ## See also: @@ -964,8 +946,8 @@ proc getOrDefault*[A, B](t: TableRef[A, B], key: A): B = getOrDefault(t[], key) proc getOrDefault*[A, B](t: TableRef[A, B], key: A, default: B): B = - ## Retrieves the value at `t[key]` if `key` is in `t`. - ## Otherwise, `default` is returned. + ## Retrieves the value at ``t[key]`` if ``key`` is in ``t``. + ## Otherwise, ``default`` is returned. ## ## See also: ## * `[] proc<#[],TableRef[A,B],A>`_ for retrieving a value of a key @@ -982,15 +964,9 @@ proc getOrDefault*[A, B](t: TableRef[A, B], key: A, default: B): B = getOrDefault(t[], key, default) proc mgetOrPut*[A, B](t: TableRef[A, B], key: A, val: B): var B = - ## Retrieves value at `t[key]` or puts `val` if not present, either way + ## Retrieves value at ``t[key]`` or puts ``val`` if not present, either way ## returning a value which can be modified. ## - ## Note that while the value returned is of type `var B`, - ## it is easy to accidentally create an copy of the value at `t[key]`. - ## Remember that seqs and strings are value types, and therefore - ## cannot be copied into a separate variable for modification. - ## See the example below. - ## ## See also: ## * `[] proc<#[],TableRef[A,B],A>`_ for retrieving a value of a key ## * `hasKey proc<#hasKey,TableRef[A,B],A>`_ @@ -1005,41 +981,29 @@ proc mgetOrPut*[A, B](t: TableRef[A, B], key: A, val: B): var B = doAssert a.mgetOrPut('z', 99) == 99 doAssert a == {'a': 5, 'b': 9, 'z': 99}.newTable - # An example of accidentally creating a copy - var t = newTable[int, seq[int]]() - # In this example, we expect t[10] to be modified, - # but it is not. - var copiedSeq = t.mgetOrPut(10, @[10]) - copiedSeq.add(20) - doAssert t[10] == @[10] - # Correct - t.mgetOrPut(25, @[25]).add(35) - doAssert t[25] == @[25, 35] t[].mgetOrPut(key, val) proc len*[A, B](t: TableRef[A, B]): int = - ## Returns the number of keys in `t`. + ## Returns the number of keys in ``t``. runnableExamples: let a = {'a': 5, 'b': 9}.newTable doAssert len(a) == 2 result = t.counter -proc add*[A, B](t: TableRef[A, B], key: A, val: sink B) {.deprecated: - "Deprecated since v1.4; it was more confusing than useful, use `[]=`".} = - ## Puts a new `(key, value)` pair into `t` even if `t[key]` already exists. +proc add*[A, B](t: TableRef[A, B], key: A, val: B) = + ## Puts a new ``(key, value)`` pair into ``t`` even if ``t[key]`` already exists. ## ## **This can introduce duplicate keys into the table!** ## - ## Use `[]= proc<#[]=,TableRef[A,B],A,sinkB>`_ for inserting a new + ## Use `[]= proc<#[]=,TableRef[A,B],A,B>`_ for inserting a new ## (key, value) pair in the table without introducing duplicates. t[].add(key, val) proc del*[A, B](t: TableRef[A, B], key: A) = - ## Deletes `key` from hash table `t`. Does nothing if the key does not exist. + ## Deletes ``key`` from hash table ``t``. Does nothing if the key does not exist. ## - ## .. warning:: If duplicate keys were added (via the now deprecated `add` proc), - ## this may need to be called multiple times. + ## **If duplicate keys were added, this may need to be called multiple times.** ## ## See also: ## * `pop proc<#pop,TableRef[A,B],A,B>`_ @@ -1054,13 +1018,12 @@ proc del*[A, B](t: TableRef[A, B], key: A) = t[].del(key) proc pop*[A, B](t: TableRef[A, B], key: A, val: var B): bool = - ## Deletes the `key` from the table. - ## Returns `true`, if the `key` existed, and sets `val` to the - ## mapping of the key. Otherwise, returns `false`, and the `val` is + ## Deletes the ``key`` from the table. + ## Returns ``true``, if the ``key`` existed, and sets ``val`` to the + ## mapping of the key. Otherwise, returns ``false``, and the ``val`` is ## unchanged. ## - ## .. warning:: If duplicate keys were added (via the now deprecated `add` proc), - ## this may need to be called multiple times. + ## **If duplicate keys were added, this may need to be called multiple times.** ## ## See also: ## * `del proc<#del,TableRef[A,B],A>`_ @@ -1099,13 +1062,13 @@ proc clear*[A, B](t: TableRef[A, B]) = clearImpl() proc `$`*[A, B](t: TableRef[A, B]): string = - ## The `$` operator for hash tables. Used internally when calling `echo` + ## The ``$`` operator for hash tables. Used internally when calling `echo` ## on a table. dollarImpl() proc `==`*[A, B](s, t: TableRef[A, B]): bool = - ## The `==` operator for hash tables. Returns `true` if either both tables - ## are `nil`, or neither is `nil` and the content of both tables contains the + ## The ``==`` operator for hash tables. Returns ``true`` if either both tables + ## are ``nil``, or neither is ``nil`` and the content of both tables contains the ## same key-value pairs. Insert order does not matter. runnableExamples: let @@ -1120,7 +1083,7 @@ proc `==`*[A, B](s, t: TableRef[A, B]): bool = iterator pairs*[A, B](t: TableRef[A, B]): (A, B) = - ## Iterates over any `(key, value)` pair in the table `t`. + ## Iterates over any ``(key, value)`` pair in the table ``t``. ## ## See also: ## * `mpairs iterator<#mpairs.i,TableRef[A,B]>`_ @@ -1150,7 +1113,7 @@ iterator pairs*[A, B](t: TableRef[A, B]): (A, B) = assert(len(t) == L, "the length of the table changed while iterating over it") iterator mpairs*[A, B](t: TableRef[A, B]): (A, var B) = - ## Iterates over any `(key, value)` pair in the table `t`. The values + ## Iterates over any ``(key, value)`` pair in the table ``t``. The values ## can be modified. ## ## See also: @@ -1171,8 +1134,8 @@ iterator mpairs*[A, B](t: TableRef[A, B]): (A, var B) = yield (t.data[h].key, t.data[h].val) assert(len(t) == L, "the length of the table changed while iterating over it") -iterator keys*[A, B](t: TableRef[A, B]): lent A = - ## Iterates over any key in the table `t`. +iterator keys*[A, B](t: TableRef[A, B]): A = + ## Iterates over any key in the table ``t``. ## ## See also: ## * `pairs iterator<#pairs.i,TableRef[A,B]>`_ @@ -1192,8 +1155,8 @@ iterator keys*[A, B](t: TableRef[A, B]): lent A = yield t.data[h].key assert(len(t) == L, "the length of the table changed while iterating over it") -iterator values*[A, B](t: TableRef[A, B]): lent B = - ## Iterates over any value in the table `t`. +iterator values*[A, B](t: TableRef[A, B]): B = + ## Iterates over any value in the table ``t``. ## ## See also: ## * `pairs iterator<#pairs.i,TableRef[A,B]>`_ @@ -1214,7 +1177,7 @@ iterator values*[A, B](t: TableRef[A, B]): lent B = assert(len(t) == L, "the length of the table changed while iterating over it") iterator mvalues*[A, B](t: TableRef[A, B]): var B = - ## Iterates over any value in the table `t`. The values can be modified. + ## Iterates over any value in the table ``t``. The values can be modified. ## ## See also: ## * `mpairs iterator<#mpairs.i,TableRef[A,B]>`_ @@ -1253,14 +1216,14 @@ type ## Hash table that remembers insertion order. ## ## For creating an empty OrderedTable, use `initOrderedTable proc - ## <#initOrderedTable>`_. + ## <#initOrderedTable,int>`_. data: OrderedKeyValuePairSeq[A, B] counter, first, last: int OrderedTableRef*[A, B] = ref OrderedTable[A, B] ## Ref version of ## `OrderedTable<#OrderedTable>`_. ## ## For creating a new empty OrderedTableRef, use `newOrderedTable proc - ## <#newOrderedTable>`_. + ## <#newOrderedTable,int>`_. # ------------------------------ helpers --------------------------------- @@ -1276,7 +1239,7 @@ proc rawGet[A, B](t: OrderedTable[A, B], key: A, hc: var Hash): int = proc rawInsert[A, B](t: var OrderedTable[A, B], data: var OrderedKeyValuePairSeq[A, B], - key: A, val: sink B, hc: Hash, h: Hash) = + key: A, val: B, hc: Hash, h: Hash) = rawInsertImpl() data[h].next = -1 if t.first < 0: t.first = h @@ -1297,7 +1260,7 @@ proc enlarge[A, B](t: var OrderedTable[A, B]) = var j: Hash = eh and maxHash(t) while isFilled(t.data[j].hcode): j = nextTry(j, maxHash(t)) - rawInsert(t, t.data, move n[h].key, move n[h].val, n[h].hcode, j) + rawInsert(t, t.data, n[h].key, n[h].val, n[h].hcode, j) h = nxt template forAllOrderedPairs(yieldStmt: untyped) {.dirty.} = @@ -1314,12 +1277,18 @@ template forAllOrderedPairs(yieldStmt: untyped) {.dirty.} = proc initOrderedTable*[A, B](initialSize = defaultInitialSize): OrderedTable[A, B] = ## Creates a new ordered hash table that is empty. ## + ## ``initialSize`` must be a power of two (default: 64). + ## If you need to accept runtime values for this you could use the + ## `nextPowerOfTwo proc`_ from the + ## `math module`_ or the `rightSize proc<#rightSize,Natural>`_ + ## from this module. + ## ## Starting from Nim v0.20, tables are initialized by default and it is ## not necessary to call this function explicitly. ## ## See also: ## * `toOrderedTable proc<#toOrderedTable,openArray[]>`_ - ## * `newOrderedTable proc<#newOrderedTable>`_ for creating an + ## * `newOrderedTable proc<#newOrderedTable,int>`_ for creating an ## `OrderedTableRef` runnableExamples: let @@ -1327,8 +1296,8 @@ proc initOrderedTable*[A, B](initialSize = defaultInitialSize): OrderedTable[A, b = initOrderedTable[char, seq[int]]() initImpl(result, initialSize) -proc `[]=`*[A, B](t: var OrderedTable[A, B], key: A, val: sink B) = - ## Inserts a `(key, value)` pair into `t`. +proc `[]=`*[A, B](t: var OrderedTable[A, B], key: A, val: B) = + ## Inserts a ``(key, value)`` pair into ``t``. ## ## See also: ## * `[] proc<#[],OrderedTable[A,B],A>`_ for retrieving a value of a key @@ -1344,12 +1313,12 @@ proc `[]=`*[A, B](t: var OrderedTable[A, B], key: A, val: sink B) = putImpl(enlarge) proc toOrderedTable*[A, B](pairs: openArray[(A, B)]): OrderedTable[A, B] = - ## Creates a new ordered hash table that contains the given `pairs`. + ## Creates a new ordered hash table that contains the given ``pairs``. ## - ## `pairs` is a container consisting of `(key, value)` tuples. + ## ``pairs`` is a container consisting of ``(key, value)`` tuples. ## ## See also: - ## * `initOrderedTable proc<#initOrderedTable>`_ + ## * `initOrderedTable proc<#initOrderedTable,int>`_ ## * `newOrderedTable proc<#newOrderedTable,openArray[]>`_ for an ## `OrderedTableRef` version runnableExamples: @@ -1357,13 +1326,13 @@ proc toOrderedTable*[A, B](pairs: openArray[(A, B)]): OrderedTable[A, B] = let b = toOrderedTable(a) assert b == {'a': 5, 'b': 9}.toOrderedTable - result = initOrderedTable[A, B](pairs.len) + result = initOrderedTable[A, B](rightSize(pairs.len)) for key, val in items(pairs): result[key] = val proc `[]`*[A, B](t: OrderedTable[A, B], key: A): B = - ## Retrieves the value at `t[key]`. + ## Retrieves the value at ``t[key]``. ## - ## If `key` is not in `t`, the `KeyError` exception is raised. + ## If ``key`` is not in ``t``, the ``KeyError`` exception is raised. ## One can check with `hasKey proc<#hasKey,OrderedTable[A,B],A>`_ whether ## the key exists. ## @@ -1372,7 +1341,7 @@ proc `[]`*[A, B](t: OrderedTable[A, B], key: A): B = ## a default value (e.g. zero for int) if the key doesn't exist ## * `getOrDefault proc<#getOrDefault,OrderedTable[A,B],A,B>`_ to return ## a custom value if the key doesn't exist - ## * `[]= proc<#[]=,OrderedTable[A,B],A,sinkB>`_ for inserting a new + ## * `[]= proc<#[]=,OrderedTable[A,B],A,B>`_ for inserting a new ## (key, value) pair in the table ## * `hasKey proc<#hasKey,OrderedTable[A,B],A>`_ for checking if a ## key is in the table @@ -1385,23 +1354,23 @@ proc `[]`*[A, B](t: OrderedTable[A, B], key: A): B = get(t, key) proc `[]`*[A, B](t: var OrderedTable[A, B], key: A): var B = - ## Retrieves the value at `t[key]`. The value can be modified. + ## Retrieves the value at ``t[key]``. The value can be modified. ## - ## If `key` is not in `t`, the `KeyError` exception is raised. + ## If ``key`` is not in ``t``, the ``KeyError`` exception is raised. ## ## See also: ## * `getOrDefault proc<#getOrDefault,OrderedTable[A,B],A>`_ to return ## a default value (e.g. zero for int) if the key doesn't exist ## * `getOrDefault proc<#getOrDefault,OrderedTable[A,B],A,B>`_ to return ## a custom value if the key doesn't exist - ## * `[]= proc<#[]=,OrderedTable[A,B],A,sinkB>`_ for inserting a new + ## * `[]= proc<#[]=,OrderedTable[A,B],A,B>`_ for inserting a new ## (key, value) pair in the table ## * `hasKey proc<#hasKey,OrderedTable[A,B],A>`_ for checking if a ## key is in the table get(t, key) proc hasKey*[A, B](t: OrderedTable[A, B], key: A): bool = - ## Returns true if `key` is in the table `t`. + ## Returns true if ``key`` is in the table ``t``. ## ## See also: ## * `contains proc<#contains,OrderedTable[A,B],A>`_ for use with the `in` @@ -1421,7 +1390,7 @@ proc hasKey*[A, B](t: OrderedTable[A, B], key: A): bool = proc contains*[A, B](t: OrderedTable[A, B], key: A): bool = ## Alias of `hasKey proc<#hasKey,OrderedTable[A,B],A>`_ for use with - ## the `in` operator. + ## the ``in`` operator. runnableExamples: let a = {'a': 5, 'b': 9}.toOrderedTable doAssert 'b' in a == true @@ -1430,7 +1399,7 @@ proc contains*[A, B](t: OrderedTable[A, B], key: A): bool = return hasKey[A, B](t, key) proc hasKeyOrPut*[A, B](t: var OrderedTable[A, B], key: A, val: B): bool = - ## Returns true if `key` is in the table, otherwise inserts `value`. + ## Returns true if ``key`` is in the table, otherwise inserts ``value``. ## ## See also: ## * `hasKey proc<#hasKey,OrderedTable[A,B],A>`_ @@ -1450,8 +1419,8 @@ proc hasKeyOrPut*[A, B](t: var OrderedTable[A, B], key: A, val: B): bool = hasKeyOrPutImpl(enlarge) proc getOrDefault*[A, B](t: OrderedTable[A, B], key: A): B = - ## Retrieves the value at `t[key]` if `key` is in `t`. Otherwise, the - ## default initialization value for type `B` is returned (e.g. 0 for any + ## Retrieves the value at ``t[key]`` if ``key`` is in ``t``. Otherwise, the + ## default initialization value for type ``B`` is returned (e.g. 0 for any ## integer type). ## ## See also: @@ -1469,8 +1438,8 @@ proc getOrDefault*[A, B](t: OrderedTable[A, B], key: A): B = getOrDefaultImpl(t, key) proc getOrDefault*[A, B](t: OrderedTable[A, B], key: A, default: B): B = - ## Retrieves the value at `t[key]` if `key` is in `t`. - ## Otherwise, `default` is returned. + ## Retrieves the value at ``t[key]`` if ``key`` is in ``t``. + ## Otherwise, ``default`` is returned. ## ## See also: ## * `[] proc<#[],OrderedTable[A,B],A>`_ for retrieving a value of a key @@ -1487,7 +1456,7 @@ proc getOrDefault*[A, B](t: OrderedTable[A, B], key: A, default: B): B = getOrDefaultImpl(t, key, default) proc mgetOrPut*[A, B](t: var OrderedTable[A, B], key: A, val: B): var B = - ## Retrieves value at `t[key]` or puts `val` if not present, either way + ## Retrieves value at ``t[key]`` or puts ``val`` if not present, either way ## returning a value which can be modified. ## ## See also: @@ -1507,25 +1476,24 @@ proc mgetOrPut*[A, B](t: var OrderedTable[A, B], key: A, val: B): var B = mgetOrPutImpl(enlarge) proc len*[A, B](t: OrderedTable[A, B]): int {.inline.} = - ## Returns the number of keys in `t`. + ## Returns the number of keys in ``t``. runnableExamples: let a = {'a': 5, 'b': 9}.toOrderedTable doAssert len(a) == 2 result = t.counter -proc add*[A, B](t: var OrderedTable[A, B], key: A, val: sink B) {.deprecated: - "Deprecated since v1.4; it was more confusing than useful, use `[]=`".} = - ## Puts a new `(key, value)` pair into `t` even if `t[key]` already exists. +proc add*[A, B](t: var OrderedTable[A, B], key: A, val: B) = + ## Puts a new ``(key, value)`` pair into ``t`` even if ``t[key]`` already exists. ## ## **This can introduce duplicate keys into the table!** ## - ## Use `[]= proc<#[]=,OrderedTable[A,B],A,sinkB>`_ for inserting a new + ## Use `[]= proc<#[]=,OrderedTable[A,B],A,B>`_ for inserting a new ## (key, value) pair in the table without introducing duplicates. addImpl(enlarge) proc del*[A, B](t: var OrderedTable[A, B], key: A) = - ## Deletes `key` from hash table `t`. Does nothing if the key does not exist. + ## Deletes ``key`` from hash table ``t``. Does nothing if the key does not exist. ## ## O(n) complexity. ## @@ -1554,13 +1522,13 @@ proc del*[A, B](t: var OrderedTable[A, B], key: A) = dec t.counter else: var j = -1 - rawGetKnownHC(t, n[h].key, n[h].hcode) - rawInsert(t, t.data, move n[h].key, move n[h].val, n[h].hcode, j) + rawInsert(t, t.data, n[h].key, n[h].val, n[h].hcode, j) h = nxt proc pop*[A, B](t: var OrderedTable[A, B], key: A, val: var B): bool {.since: (1, 1).} = - ## Deletes the `key` from the table. - ## Returns `true`, if the `key` existed, and sets `val` to the - ## mapping of the key. Otherwise, returns `false`, and the `val` is + ## Deletes the ``key`` from the table. + ## Returns ``true``, if the ``key`` existed, and sets ``val`` to the + ## mapping of the key. Otherwise, returns ``false``, and the ``val`` is ## unchanged. ## ## O(n) complexity. @@ -1604,15 +1572,15 @@ proc clear*[A, B](t: var OrderedTable[A, B]) = t.last = -1 proc sort*[A, B](t: var OrderedTable[A, B], cmp: proc (x, y: (A, B)): int, - order = SortOrder.Ascending) {.effectsOf: cmp.} = - ## Sorts `t` according to the function `cmp`. + order = SortOrder.Ascending) = + ## Sorts ``t`` according to the function ``cmp``. ## ## This modifies the internal list ## that kept the insertion order, so insertion order is lost after this - ## call but key lookup and insertions remain possible after `sort` (in + ## call but key lookup and insertions remain possible after ``sort`` (in ## contrast to the `sort proc<#sort,CountTable[A]>`_ for count tables). runnableExamples: - import std/[algorithm] + import algorithm var a = initOrderedTable[char, int]() for i, c in "cab": a[c] = 10*i @@ -1663,12 +1631,12 @@ proc sort*[A, B](t: var OrderedTable[A, B], cmp: proc (x, y: (A, B)): int, t.last = tail proc `$`*[A, B](t: OrderedTable[A, B]): string = - ## The `$` operator for ordered hash tables. Used internally when calling + ## The ``$`` operator for ordered hash tables. Used internally when calling ## `echo` on a table. dollarImpl() proc `==`*[A, B](s, t: OrderedTable[A, B]): bool = - ## The `==` operator for ordered hash tables. Returns `true` if both the + ## The ``==`` operator for ordered hash tables. Returns ``true`` if both the ## content and the order are equal. runnableExamples: let @@ -1678,8 +1646,6 @@ proc `==`*[A, B](s, t: OrderedTable[A, B]): bool = if s.counter != t.counter: return false - if s.counter == 0 and t.counter == 0: - return true var ht = t.first var hs = s.first while ht >= 0 and hs >= 0: @@ -1695,7 +1661,7 @@ proc `==`*[A, B](s, t: OrderedTable[A, B]): bool = iterator pairs*[A, B](t: OrderedTable[A, B]): (A, B) = - ## Iterates over any `(key, value)` pair in the table `t` in insertion + ## Iterates over any ``(key, value)`` pair in the table ``t`` in insertion ## order. ## ## See also: @@ -1726,7 +1692,7 @@ iterator pairs*[A, B](t: OrderedTable[A, B]): (A, B) = assert(len(t) == L, "the length of the table changed while iterating over it") iterator mpairs*[A, B](t: var OrderedTable[A, B]): (A, var B) = - ## Iterates over any `(key, value)` pair in the table `t` (must be + ## Iterates over any ``(key, value)`` pair in the table ``t`` (must be ## declared as `var`) in insertion order. The values can be modified. ## ## See also: @@ -1747,8 +1713,8 @@ iterator mpairs*[A, B](t: var OrderedTable[A, B]): (A, var B) = yield (t.data[h].key, t.data[h].val) assert(len(t) == L, "the length of the table changed while iterating over it") -iterator keys*[A, B](t: OrderedTable[A, B]): lent A = - ## Iterates over any key in the table `t` in insertion order. +iterator keys*[A, B](t: OrderedTable[A, B]): A = + ## Iterates over any key in the table ``t`` in insertion order. ## ## See also: ## * `pairs iterator<#pairs.i,OrderedTable[A,B]>`_ @@ -1768,8 +1734,8 @@ iterator keys*[A, B](t: OrderedTable[A, B]): lent A = yield t.data[h].key assert(len(t) == L, "the length of the table changed while iterating over it") -iterator values*[A, B](t: OrderedTable[A, B]): lent B = - ## Iterates over any value in the table `t` in insertion order. +iterator values*[A, B](t: OrderedTable[A, B]): B = + ## Iterates over any value in the table ``t`` in insertion order. ## ## See also: ## * `pairs iterator<#pairs.i,OrderedTable[A,B]>`_ @@ -1789,7 +1755,7 @@ iterator values*[A, B](t: OrderedTable[A, B]): lent B = assert(len(t) == L, "the length of the table changed while iterating over it") iterator mvalues*[A, B](t: var OrderedTable[A, B]): var B = - ## Iterates over any value in the table `t` (must be + ## Iterates over any value in the table ``t`` (must be ## declared as `var`) in insertion order. The values ## can be modified. ## @@ -1811,33 +1777,42 @@ iterator mvalues*[A, B](t: var OrderedTable[A, B]): var B = yield t.data[h].val assert(len(t) == L, "the length of the table changed while iterating over it") + + + + # --------------------------------------------------------------------------- # --------------------------- OrderedTableRef ------------------------------- # --------------------------------------------------------------------------- -proc newOrderedTable*[A, B](initialSize = defaultInitialSize): OrderedTableRef[A, B] = +proc newOrderedTable*[A, B](initialSize = defaultInitialSize): OrderedTableRef[A, B] = ## Creates a new ordered ref hash table that is empty. ## + ## ``initialSize`` must be a power of two (default: 64). + ## If you need to accept runtime values for this you could use the + ## `nextPowerOfTwo proc`_ from the + ## `math module`_ or the `rightSize proc<#rightSize,Natural>`_ + ## from this module. + ## ## See also: ## * `newOrderedTable proc<#newOrderedTable,openArray[]>`_ for creating ## an `OrderedTableRef` from a collection of `(key, value)` pairs - ## * `initOrderedTable proc<#initOrderedTable>`_ for creating an + ## * `initOrderedTable proc<#initOrderedTable,int>`_ for creating an ## `OrderedTable` runnableExamples: let a = newOrderedTable[int, string]() b = newOrderedTable[char, seq[int]]() new(result) - {.noSideEffect.}: - result[] = initOrderedTable[A, B](initialSize) + result[] = initOrderedTable[A, B](initialSize) -proc newOrderedTable*[A, B](pairs: openArray[(A, B)]): OrderedTableRef[A, B] = - ## Creates a new ordered ref hash table that contains the given `pairs`. +proc newOrderedTable*[A, B](pairs: openArray[(A, B)]): OrderedTableRef[A, B] = + ## Creates a new ordered ref hash table that contains the given ``pairs``. ## - ## `pairs` is a container consisting of `(key, value)` tuples. + ## ``pairs`` is a container consisting of ``(key, value)`` tuples. ## ## See also: - ## * `newOrderedTable proc<#newOrderedTable>`_ + ## * `newOrderedTable proc<#newOrderedTable,int>`_ ## * `toOrderedTable proc<#toOrderedTable,openArray[]>`_ for an ## `OrderedTable` version runnableExamples: @@ -1845,15 +1820,14 @@ proc newOrderedTable*[A, B](pairs: openArray[(A, B)]): OrderedTableRef[A, B] = let b = newOrderedTable(a) assert b == {'a': 5, 'b': 9}.newOrderedTable - result = newOrderedTable[A, B](pairs.len) - {.noSideEffect.}: - for key, val in items(pairs): result[key] = val + result = newOrderedTable[A, B](rightSize(pairs.len)) + for key, val in items(pairs): result.add(key, val) proc `[]`*[A, B](t: OrderedTableRef[A, B], key: A): var B = - ## Retrieves the value at `t[key]`. + ## Retrieves the value at ``t[key]``. ## - ## If `key` is not in `t`, the `KeyError` exception is raised. + ## If ``key`` is not in ``t``, the ``KeyError`` exception is raised. ## One can check with `hasKey proc<#hasKey,OrderedTableRef[A,B],A>`_ whether ## the key exists. ## @@ -1862,7 +1836,7 @@ proc `[]`*[A, B](t: OrderedTableRef[A, B], key: A): var B = ## a default value (e.g. zero for int) if the key doesn't exist ## * `getOrDefault proc<#getOrDefault,OrderedTableRef[A,B],A,B>`_ to return ## a custom value if the key doesn't exist - ## * `[]= proc<#[]=,OrderedTableRef[A,B],A,sinkB>`_ for inserting a new + ## * `[]= proc<#[]=,OrderedTableRef[A,B],A,B>`_ for inserting a new ## (key, value) pair in the table ## * `hasKey proc<#hasKey,OrderedTableRef[A,B],A>`_ for checking if ## a key is in the table @@ -1873,8 +1847,8 @@ proc `[]`*[A, B](t: OrderedTableRef[A, B], key: A): var B = echo a['z'] result = t[][key] -proc `[]=`*[A, B](t: OrderedTableRef[A, B], key: A, val: sink B) = - ## Inserts a `(key, value)` pair into `t`. +proc `[]=`*[A, B](t: OrderedTableRef[A, B], key: A, val: B) = + ## Inserts a ``(key, value)`` pair into ``t``. ## ## See also: ## * `[] proc<#[],OrderedTableRef[A,B],A>`_ for retrieving a value of a key @@ -1890,7 +1864,7 @@ proc `[]=`*[A, B](t: OrderedTableRef[A, B], key: A, val: sink B) = t[][key] = val proc hasKey*[A, B](t: OrderedTableRef[A, B], key: A): bool = - ## Returns true if `key` is in the table `t`. + ## Returns true if ``key`` is in the table ``t``. ## ## See also: ## * `contains proc<#contains,OrderedTableRef[A,B],A>`_ for use with the `in` @@ -1909,7 +1883,7 @@ proc hasKey*[A, B](t: OrderedTableRef[A, B], key: A): bool = proc contains*[A, B](t: OrderedTableRef[A, B], key: A): bool = ## Alias of `hasKey proc<#hasKey,OrderedTableRef[A,B],A>`_ for use with - ## the `in` operator. + ## the ``in`` operator. runnableExamples: let a = {'a': 5, 'b': 9}.newOrderedTable doAssert 'b' in a == true @@ -1917,8 +1891,8 @@ proc contains*[A, B](t: OrderedTableRef[A, B], key: A): bool = return hasKey[A, B](t, key) -proc hasKeyOrPut*[A, B](t: OrderedTableRef[A, B], key: A, val: B): bool = - ## Returns true if `key` is in the table, otherwise inserts `value`. +proc hasKeyOrPut*[A, B](t: var OrderedTableRef[A, B], key: A, val: B): bool = + ## Returns true if ``key`` is in the table, otherwise inserts ``value``. ## ## See also: ## * `hasKey proc<#hasKey,OrderedTableRef[A,B],A>`_ @@ -1938,8 +1912,8 @@ proc hasKeyOrPut*[A, B](t: OrderedTableRef[A, B], key: A, val: B): bool = result = t[].hasKeyOrPut(key, val) proc getOrDefault*[A, B](t: OrderedTableRef[A, B], key: A): B = - ## Retrieves the value at `t[key]` if `key` is in `t`. Otherwise, the - ## default initialization value for type `B` is returned (e.g. 0 for any + ## Retrieves the value at ``t[key]`` if ``key`` is in ``t``. Otherwise, the + ## default initialization value for type ``B`` is returned (e.g. 0 for any ## integer type). ## ## See also: @@ -1957,8 +1931,8 @@ proc getOrDefault*[A, B](t: OrderedTableRef[A, B], key: A): B = getOrDefault(t[], key) proc getOrDefault*[A, B](t: OrderedTableRef[A, B], key: A, default: B): B = - ## Retrieves the value at `t[key]` if `key` is in `t`. - ## Otherwise, `default` is returned. + ## Retrieves the value at ``t[key]`` if ``key`` is in ``t``. + ## Otherwise, ``default`` is returned. ## ## See also: ## * `[] proc<#[],OrderedTableRef[A,B],A>`_ for retrieving a value of a key @@ -1975,7 +1949,7 @@ proc getOrDefault*[A, B](t: OrderedTableRef[A, B], key: A, default: B): B = getOrDefault(t[], key, default) proc mgetOrPut*[A, B](t: OrderedTableRef[A, B], key: A, val: B): var B = - ## Retrieves value at `t[key]` or puts `val` if not present, either way + ## Retrieves value at ``t[key]`` or puts ``val`` if not present, either way ## returning a value which can be modified. ## ## See also: @@ -1995,25 +1969,24 @@ proc mgetOrPut*[A, B](t: OrderedTableRef[A, B], key: A, val: B): var B = result = t[].mgetOrPut(key, val) proc len*[A, B](t: OrderedTableRef[A, B]): int {.inline.} = - ## Returns the number of keys in `t`. + ## Returns the number of keys in ``t``. runnableExamples: let a = {'a': 5, 'b': 9}.newOrderedTable doAssert len(a) == 2 result = t.counter -proc add*[A, B](t: OrderedTableRef[A, B], key: A, val: sink B) {.deprecated: - "Deprecated since v1.4; it was more confusing than useful, use `[]=`".} = - ## Puts a new `(key, value)` pair into `t` even if `t[key]` already exists. +proc add*[A, B](t: OrderedTableRef[A, B], key: A, val: B) = + ## Puts a new ``(key, value)`` pair into ``t`` even if ``t[key]`` already exists. ## ## **This can introduce duplicate keys into the table!** ## - ## Use `[]= proc<#[]=,OrderedTableRef[A,B],A,sinkB>`_ for inserting a new + ## Use `[]= proc<#[]=,OrderedTableRef[A,B],A,B>`_ for inserting a new ## (key, value) pair in the table without introducing duplicates. t[].add(key, val) proc del*[A, B](t: OrderedTableRef[A, B], key: A) = - ## Deletes `key` from hash table `t`. Does nothing if the key does not exist. + ## Deletes ``key`` from hash table ``t``. Does nothing if the key does not exist. ## ## See also: ## * `clear proc<#clear,OrderedTableRef[A,B]>`_ to empty the whole table @@ -2027,9 +2000,9 @@ proc del*[A, B](t: OrderedTableRef[A, B], key: A) = t[].del(key) proc pop*[A, B](t: OrderedTableRef[A, B], key: A, val: var B): bool {.since: (1, 1).} = - ## Deletes the `key` from the table. - ## Returns `true`, if the `key` existed, and sets `val` to the - ## mapping of the key. Otherwise, returns `false`, and the `val` is + ## Deletes the ``key`` from the table. + ## Returns ``true``, if the ``key`` existed, and sets ``val`` to the + ## mapping of the key. Otherwise, returns ``false``, and the ``val`` is ## unchanged. ## ## See also: @@ -2063,15 +2036,15 @@ proc clear*[A, B](t: OrderedTableRef[A, B]) = clear(t[]) proc sort*[A, B](t: OrderedTableRef[A, B], cmp: proc (x, y: (A, B)): int, - order = SortOrder.Ascending) {.effectsOf: cmp.} = - ## Sorts `t` according to the function `cmp`. + order = SortOrder.Ascending) = + ## Sorts ``t`` according to the function ``cmp``. ## ## This modifies the internal list ## that kept the insertion order, so insertion order is lost after this - ## call but key lookup and insertions remain possible after `sort` (in + ## call but key lookup and insertions remain possible after ``sort`` (in ## contrast to the `sort proc<#sort,CountTableRef[A]>`_ for count tables). runnableExamples: - import std/[algorithm] + import algorithm var a = newOrderedTable[char, int]() for i, c in "cab": a[c] = 10*i @@ -2084,13 +2057,13 @@ proc sort*[A, B](t: OrderedTableRef[A, B], cmp: proc (x, y: (A, B)): int, t[].sort(cmp, order = order) proc `$`*[A, B](t: OrderedTableRef[A, B]): string = - ## The `$` operator for hash tables. Used internally when calling `echo` + ## The ``$`` operator for hash tables. Used internally when calling `echo` ## on a table. dollarImpl() proc `==`*[A, B](s, t: OrderedTableRef[A, B]): bool = - ## The `==` operator for ordered hash tables. Returns true if either both - ## tables are `nil`, or neither is `nil` and the content and the order of + ## The ``==`` operator for ordered hash tables. Returns true if either both + ## tables are ``nil``, or neither is ``nil`` and the content and the order of ## both are equal. runnableExamples: let @@ -2105,7 +2078,7 @@ proc `==`*[A, B](s, t: OrderedTableRef[A, B]): bool = iterator pairs*[A, B](t: OrderedTableRef[A, B]): (A, B) = - ## Iterates over any `(key, value)` pair in the table `t` in insertion + ## Iterates over any ``(key, value)`` pair in the table ``t`` in insertion ## order. ## ## See also: @@ -2136,7 +2109,7 @@ iterator pairs*[A, B](t: OrderedTableRef[A, B]): (A, B) = assert(len(t) == L, "the length of the table changed while iterating over it") iterator mpairs*[A, B](t: OrderedTableRef[A, B]): (A, var B) = - ## Iterates over any `(key, value)` pair in the table `t` in insertion + ## Iterates over any ``(key, value)`` pair in the table ``t`` in insertion ## order. The values can be modified. ## ## See also: @@ -2157,8 +2130,8 @@ iterator mpairs*[A, B](t: OrderedTableRef[A, B]): (A, var B) = yield (t.data[h].key, t.data[h].val) assert(len(t) == L, "the length of the table changed while iterating over it") -iterator keys*[A, B](t: OrderedTableRef[A, B]): lent A = - ## Iterates over any key in the table `t` in insertion order. +iterator keys*[A, B](t: OrderedTableRef[A, B]): A = + ## Iterates over any key in the table ``t`` in insertion order. ## ## See also: ## * `pairs iterator<#pairs.i,OrderedTableRef[A,B]>`_ @@ -2178,8 +2151,8 @@ iterator keys*[A, B](t: OrderedTableRef[A, B]): lent A = yield t.data[h].key assert(len(t) == L, "the length of the table changed while iterating over it") -iterator values*[A, B](t: OrderedTableRef[A, B]): lent B = - ## Iterates over any value in the table `t` in insertion order. +iterator values*[A, B](t: OrderedTableRef[A, B]): B = + ## Iterates over any value in the table ``t`` in insertion order. ## ## See also: ## * `pairs iterator<#pairs.i,OrderedTableRef[A,B]>`_ @@ -2199,7 +2172,7 @@ iterator values*[A, B](t: OrderedTableRef[A, B]): lent B = assert(len(t) == L, "the length of the table changed while iterating over it") iterator mvalues*[A, B](t: OrderedTableRef[A, B]): var B = - ## Iterates over any value in the table `t` in insertion order. The values + ## Iterates over any value in the table ``t`` in insertion order. The values ## can be modified. ## ## See also: @@ -2235,7 +2208,7 @@ type ## Hash table that counts the number of each key. ## ## For creating an empty CountTable, use `initCountTable proc - ## <#initCountTable>`_. + ## <#initCountTable,int>`_. data: seq[tuple[key: A, val: int]] counter: int isSorted: bool @@ -2243,7 +2216,7 @@ type ## `CountTable<#CountTable>`_. ## ## For creating a new empty CountTableRef, use `newCountTable proc - ## <#newCountTable>`_. + ## <#newCountTable,int>`_. # ------------------------------ helpers --------------------------------- @@ -2259,9 +2232,22 @@ proc enlarge[A](t: var CountTable[A]) = var n: seq[tuple[key: A, val: int]] newSeq(n, len(t.data) * growthFactor) for i in countup(0, high(t.data)): - if t.data[i].val != 0: ctRawInsert(t, n, move t.data[i].key, move t.data[i].val) + if t.data[i].val != 0: ctRawInsert(t, n, t.data[i].key, t.data[i].val) swap(t.data, n) +proc remove[A](t: var CountTable[A], key: A) = + var n: seq[tuple[key: A, val: int]] + newSeq(n, len(t.data)) + var removed: bool + for i in countup(0, high(t.data)): + if t.data[i].val != 0: + if t.data[i].key != key: + ctRawInsert(t, n, t.data[i].key, t.data[i].val) + else: + removed = true + swap(t.data, n) + if removed: dec(t.counter) + proc rawGet[A](t: CountTable[A], key: A): int = if t.data.len == 0: return -1 @@ -2275,35 +2261,42 @@ template ctget(t, key, default: untyped): untyped = var index = rawGet(t, key) result = if index >= 0: t.data[index].val else: default -proc inc*[A](t: var CountTable[A], key: A, val = 1) +proc inc*[A](t: var CountTable[A], key: A, val: Positive = 1) # ---------------------------------------------------------------------- proc initCountTable*[A](initialSize = defaultInitialSize): CountTable[A] = ## Creates a new count table that is empty. ## + ## ``initialSize`` must be a power of two (default: 64). + ## If you need to accept runtime values for this you could use the + ## `nextPowerOfTwo proc`_ from the + ## `math module`_ or the `rightSize proc<#rightSize,Natural>`_ + ## from this module. + ## ## Starting from Nim v0.20, tables are initialized by default and it is ## not necessary to call this function explicitly. ## ## See also: ## * `toCountTable proc<#toCountTable,openArray[A]>`_ - ## * `newCountTable proc<#newCountTable>`_ for creating a + ## * `newCountTable proc<#newCountTable,int>`_ for creating a ## `CountTableRef` initImpl(result, initialSize) proc toCountTable*[A](keys: openArray[A]): CountTable[A] = - ## Creates a new count table with every member of a container `keys` + ## Creates a new count table with every member of a container ``keys`` ## having a count of how many times it occurs in that container. - result = initCountTable[A](keys.len) + result = initCountTable[A](rightSize(keys.len)) for key in items(keys): result.inc(key) proc `[]`*[A](t: CountTable[A], key: A): int = - ## Retrieves the value at `t[key]` if `key` is in `t`. - ## Otherwise `0` is returned. + ## Retrieves the value at ``t[key]`` if ``key`` is in ``t``. + ## Otherwise ``0`` is returned. ## ## See also: ## * `getOrDefault<#getOrDefault,CountTable[A],A,int>`_ to return ## a custom value if the key doesn't exist + ## * `mget proc<#mget,CountTable[A],A>`_ ## * `[]= proc<#[]%3D,CountTable[A],A,int>`_ for inserting a new ## (key, value) pair in the table ## * `hasKey proc<#hasKey,CountTable[A],A>`_ for checking if a key @@ -2311,21 +2304,17 @@ proc `[]`*[A](t: CountTable[A], key: A): int = assert(not t.isSorted, "CountTable must not be used after sorting") ctget(t, key, 0) -template cntMakeEmpty(i) = t.data[i].val = 0 -template cntCellEmpty(i) = t.data[i].val == 0 -template cntCellHash(i) = hash(t.data[i].key) - proc `[]=`*[A](t: var CountTable[A], key: A, val: int) = - ## Inserts a `(key, value)` pair into `t`. + ## Inserts a ``(key, value)`` pair into ``t``. ## ## See also: ## * `[] proc<#[],CountTable[A],A>`_ for retrieving a value of a key - ## * `inc proc<#inc,CountTable[A],A,int>`_ for incrementing a + ## * `inc proc<#inc,CountTable[A],A,Positive>`_ for incrementing a ## value of a key assert(not t.isSorted, "CountTable must not be used after sorting") assert val >= 0 if val == 0: - delImplNoHCode(cntMakeEmpty, cntCellEmpty, cntCellHash) + t.remove(key) else: let h = rawGet(t, key) if h >= 0: @@ -2333,8 +2322,11 @@ proc `[]=`*[A](t: var CountTable[A], key: A, val: int) = else: insertImpl() -proc inc*[A](t: var CountTable[A], key: A, val = 1) = - ## Increments `t[key]` by `val` (default: 1). +proc inc*[A](t: var CountTable[A], key: A, val: Positive = 1) = + ## Increments ``t[key]`` by ``val`` (default: 1). + ## + ## ``val`` must be a positive number. If you need to decrement a value, + ## use a regular ``Table`` instead. runnableExamples: var a = toCountTable("aab") a.inc('a') @@ -2345,22 +2337,16 @@ proc inc*[A](t: var CountTable[A], key: A, val = 1) = var index = rawGet(t, key) if index >= 0: inc(t.data[index].val, val) - if t.data[index].val == 0: - delImplIdx(t, index, cntMakeEmpty, cntCellEmpty, cntCellHash) + if t.data[index].val == 0: dec(t.counter) else: - if val != 0: - insertImpl() - -proc len*[A](t: CountTable[A]): int = - ## Returns the number of keys in `t`. - result = t.counter + insertImpl() proc smallest*[A](t: CountTable[A]): tuple[key: A, val: int] = - ## Returns the `(key, value)` pair with the smallest `val`. Efficiency: O(n) + ## Returns the ``(key, value)`` pair with the smallest ``val``. Efficiency: O(n) ## ## See also: ## * `largest proc<#largest,CountTable[A]>`_ - assert t.len > 0, "counttable is empty" + assert t.len > 0 var minIdx = -1 for h in 0 .. high(t.data): if t.data[h].val > 0 and (minIdx == -1 or t.data[minIdx].val > t.data[h].val): @@ -2369,11 +2355,11 @@ proc smallest*[A](t: CountTable[A]): tuple[key: A, val: int] = result.val = t.data[minIdx].val proc largest*[A](t: CountTable[A]): tuple[key: A, val: int] = - ## Returns the `(key, value)` pair with the largest `val`. Efficiency: O(n) + ## Returns the ``(key, value)`` pair with the largest ``val``. Efficiency: O(n) ## ## See also: ## * `smallest proc<#smallest,CountTable[A]>`_ - assert t.len > 0, "counttable is empty" + assert t.len > 0 var maxIdx = 0 for h in 1 .. high(t.data): if t.data[maxIdx].val < t.data[h].val: maxIdx = h @@ -2381,7 +2367,7 @@ proc largest*[A](t: CountTable[A]): tuple[key: A, val: int] = result.val = t.data[maxIdx].val proc hasKey*[A](t: CountTable[A], key: A): bool = - ## Returns true if `key` is in the table `t`. + ## Returns true if ``key`` is in the table ``t``. ## ## See also: ## * `contains proc<#contains,CountTable[A],A>`_ for use with the `in` @@ -2394,12 +2380,12 @@ proc hasKey*[A](t: CountTable[A], key: A): bool = proc contains*[A](t: CountTable[A], key: A): bool = ## Alias of `hasKey proc<#hasKey,CountTable[A],A>`_ for use with - ## the `in` operator. + ## the ``in`` operator. return hasKey[A](t, key) proc getOrDefault*[A](t: CountTable[A], key: A; default: int = 0): int = - ## Retrieves the value at `t[key]` if `key` is in `t`. Otherwise, the - ## integer value of `default` is returned. + ## Retrieves the value at ``t[key]`` if``key`` is in ``t``. Otherwise, the + ## integer value of ``default`` is returned. ## ## See also: ## * `[] proc<#[],CountTable[A],A>`_ for retrieving a value of a key @@ -2407,8 +2393,14 @@ proc getOrDefault*[A](t: CountTable[A], key: A; default: int = 0): int = ## is in the table ctget(t, key, default) +proc len*[A](t: CountTable[A]): int = + ## Returns the number of keys in ``t``. + result = t.counter + proc del*[A](t: var CountTable[A], key: A) {.since: (1, 1).} = - ## Deletes `key` from table `t`. Does nothing if the key does not exist. + ## Deletes ``key`` from table ``t``. Does nothing if the key does not exist. + ## + ## O(n) complexity. ## ## See also: ## * `pop proc<#pop,CountTable[A],A,int>`_ @@ -2422,14 +2414,16 @@ proc del*[A](t: var CountTable[A], key: A) {.since: (1, 1).} = a.del('c') assert a == toCountTable("aa") - delImplNoHCode(cntMakeEmpty, cntCellEmpty, cntCellHash) + remove(t, key) proc pop*[A](t: var CountTable[A], key: A, val: var int): bool {.since: (1, 1).} = - ## Deletes the `key` from the table. - ## Returns `true`, if the `key` existed, and sets `val` to the - ## mapping of the key. Otherwise, returns `false`, and the `val` is + ## Deletes the ``key`` from the table. + ## Returns ``true``, if the ``key`` existed, and sets ``val`` to the + ## mapping of the key. Otherwise, returns ``false``, and the ``val`` is ## unchanged. ## + ## O(n) complexity. + ## ## See also: ## * `del proc<#del,CountTable[A],A>`_ ## * `clear proc<#clear,CountTable[A]>`_ to empty the whole table @@ -2446,7 +2440,7 @@ proc pop*[A](t: var CountTable[A], key: A, val: var int): bool {.since: (1, 1).} result = index >= 0 if result: val = move(t.data[index].val) - delImplIdx(t, index, cntMakeEmpty, cntCellEmpty, cntCellHash) + remove(t, key) proc clear*[A](t: var CountTable[A]) = ## Resets the table so that it is empty. @@ -2464,13 +2458,13 @@ proc sort*[A](t: var CountTable[A], order = SortOrder.Descending) = ## Sorts the count table so that, by default, the entry with the ## highest counter comes first. ## - ## .. warning:: This is destructive! Once sorted, you must not modify `t` afterwards! + ## **WARNING:** This is destructive! Once sorted, you must not modify ``t`` afterwards! ## ## You can use the iterators `pairs<#pairs.i,CountTable[A]>`_, ## `keys<#keys.i,CountTable[A]>`_, and `values<#values.i,CountTable[A]>`_ - ## to iterate over `t` in the sorted order. + ## to iterate over ``t`` in the sorted order. runnableExamples: - import std/[algorithm, sequtils] + import algorithm, sequtils var a = toCountTable("abracadabra") doAssert a == "aaaaabbrrcd".toCountTable a.sort() @@ -2508,18 +2502,18 @@ when (NimMajor, NimMinor) <= (1, 0): result.inc(key, value) proc `$`*[A](t: CountTable[A]): string = - ## The `$` operator for count tables. Used internally when calling `echo` + ## The ``$`` operator for count tables. Used internally when calling `echo` ## on a table. dollarImpl() proc `==`*[A](s, t: CountTable[A]): bool = - ## The `==` operator for count tables. Returns `true` if both tables + ## The ``==`` operator for count tables. Returns ``true`` if both tables ## contain the same keys with the same count. Insert order does not matter. equalsImpl(s, t) iterator pairs*[A](t: CountTable[A]): (A, int) = - ## Iterates over any `(key, value)` pair in the table `t`. + ## Iterates over any ``(key, value)`` pair in the table ``t``. ## ## See also: ## * `mpairs iterator<#mpairs.i,CountTable[A]>`_ @@ -2552,7 +2546,7 @@ iterator pairs*[A](t: CountTable[A]): (A, int) = assert(len(t) == L, "the length of the table changed while iterating over it") iterator mpairs*[A](t: var CountTable[A]): (A, var int) = - ## Iterates over any `(key, value)` pair in the table `t` (must be + ## Iterates over any ``(key, value)`` pair in the table ``t`` (must be ## declared as `var`). The values can be modified. ## ## See also: @@ -2570,8 +2564,8 @@ iterator mpairs*[A](t: var CountTable[A]): (A, var int) = yield (t.data[h].key, t.data[h].val) assert(len(t) == L, "the length of the table changed while iterating over it") -iterator keys*[A](t: CountTable[A]): lent A = - ## Iterates over any key in the table `t`. +iterator keys*[A](t: CountTable[A]): A = + ## Iterates over any key in the table ``t``. ## ## See also: ## * `pairs iterator<#pairs.i,CountTable[A]>`_ @@ -2589,7 +2583,7 @@ iterator keys*[A](t: CountTable[A]): lent A = assert(len(t) == L, "the length of the table changed while iterating over it") iterator values*[A](t: CountTable[A]): int = - ## Iterates over any value in the table `t`. + ## Iterates over any value in the table ``t``. ## ## See also: ## * `pairs iterator<#pairs.i,CountTable[A]>`_ @@ -2607,7 +2601,7 @@ iterator values*[A](t: CountTable[A]): int = assert(len(t) == L, "the length of the table changed while iterating over it") iterator mvalues*[A](t: var CountTable[A]): var int = - ## Iterates over any value in the table `t` (must be + ## Iterates over any value in the table ``t`` (must be ## declared as `var`). The values can be modified. ## ## See also: @@ -2637,33 +2631,37 @@ iterator mvalues*[A](t: var CountTable[A]): var int = proc inc*[A](t: CountTableRef[A], key: A, val = 1) -proc newCountTable*[A](initialSize = defaultInitialSize): CountTableRef[A] = +proc newCountTable*[A](initialSize = defaultInitialSize): CountTableRef[A] = ## Creates a new ref count table that is empty. ## + ## ``initialSize`` must be a power of two (default: 64). + ## If you need to accept runtime values for this you could use the + ## `nextPowerOfTwo proc`_ from the + ## `math module`_ or the `rightSize proc<#rightSize,Natural>`_ + ## from this module. + ## ## See also: ## * `newCountTable proc<#newCountTable,openArray[A]>`_ for creating ## a `CountTableRef` from a collection - ## * `initCountTable proc<#initCountTable>`_ for creating a + ## * `initCountTable proc<#initCountTable,int>`_ for creating a ## `CountTable` new(result) - {.noSideEffect.}: - result[] = initCountTable[A](initialSize) + result[] = initCountTable[A](initialSize) -proc newCountTable*[A](keys: openArray[A]): CountTableRef[A] = - ## Creates a new ref count table with every member of a container `keys` +proc newCountTable*[A](keys: openArray[A]): CountTableRef[A] = + ## Creates a new ref count table with every member of a container ``keys`` ## having a count of how many times it occurs in that container. - result = newCountTable[A](keys.len) - {.noSideEffect.}: - for key in items(keys): result.inc(key) + result = newCountTable[A](rightSize(keys.len)) + for key in items(keys): result.inc(key) proc `[]`*[A](t: CountTableRef[A], key: A): int = - ## Retrieves the value at `t[key]` if `key` is in `t`. - ## Otherwise `0` is returned. + ## Retrieves the value at ``t[key]`` if ``key`` is in ``t``. + ## Otherwise ``0`` is returned. ## ## See also: ## * `getOrDefault<#getOrDefault,CountTableRef[A],A,int>`_ to return ## a custom value if the key doesn't exist - ## * `inc proc<#inc,CountTableRef[A],A,int>`_ to inc even if missing + ## * `mget proc<#mget,CountTableRef[A],A>`_ ## * `[]= proc<#[]%3D,CountTableRef[A],A,int>`_ for inserting a new ## (key, value) pair in the table ## * `hasKey proc<#hasKey,CountTableRef[A],A>`_ for checking if a key @@ -2671,42 +2669,40 @@ proc `[]`*[A](t: CountTableRef[A], key: A): int = result = t[][key] proc `[]=`*[A](t: CountTableRef[A], key: A, val: int) = - ## Inserts a `(key, value)` pair into `t`. + ## Inserts a ``(key, value)`` pair into ``t``. ## ## See also: ## * `[] proc<#[],CountTableRef[A],A>`_ for retrieving a value of a key ## * `inc proc<#inc,CountTableRef[A],A,int>`_ for incrementing a ## value of a key assert val > 0 - {.noSideEffect.}: - t[][key] = val + t[][key] = val proc inc*[A](t: CountTableRef[A], key: A, val = 1) = - ## Increments `t[key]` by `val` (default: 1). + ## Increments ``t[key]`` by ``val`` (default: 1). runnableExamples: var a = newCountTable("aab") a.inc('a') a.inc('b', 10) doAssert a == newCountTable("aaabbbbbbbbbbb") - {.noSideEffect.}: - t[].inc(key, val) + t[].inc(key, val) -proc smallest*[A](t: CountTableRef[A]): tuple[key: A, val: int] = - ## Returns the `(key, value)` pair with the smallest `val`. Efficiency: O(n) +proc smallest*[A](t: CountTableRef[A]): (A, int) = + ## Returns the ``(key, value)`` pair with the smallest ``val``. Efficiency: O(n) ## ## See also: ## * `largest proc<#largest,CountTableRef[A]>`_ t[].smallest -proc largest*[A](t: CountTableRef[A]): tuple[key: A, val: int] = - ## Returns the `(key, value)` pair with the largest `val`. Efficiency: O(n) +proc largest*[A](t: CountTableRef[A]): (A, int) = + ## Returns the ``(key, value)`` pair with the largest ``val``. Efficiency: O(n) ## ## See also: ## * `smallest proc<#smallest,CountTable[A]>`_ t[].largest proc hasKey*[A](t: CountTableRef[A], key: A): bool = - ## Returns true if `key` is in the table `t`. + ## Returns true if ``key`` is in the table ``t``. ## ## See also: ## * `contains proc<#contains,CountTableRef[A],A>`_ for use with the `in` @@ -2718,12 +2714,12 @@ proc hasKey*[A](t: CountTableRef[A], key: A): bool = proc contains*[A](t: CountTableRef[A], key: A): bool = ## Alias of `hasKey proc<#hasKey,CountTableRef[A],A>`_ for use with - ## the `in` operator. + ## the ``in`` operator. return hasKey[A](t, key) proc getOrDefault*[A](t: CountTableRef[A], key: A, default: int): int = - ## Retrieves the value at `t[key]` if `key` is in `t`. Otherwise, the - ## integer value of `default` is returned. + ## Retrieves the value at ``t[key]`` if``key`` is in ``t``. Otherwise, the + ## integer value of ``default`` is returned. ## ## See also: ## * `[] proc<#[],CountTableRef[A],A>`_ for retrieving a value of a key @@ -2732,11 +2728,13 @@ proc getOrDefault*[A](t: CountTableRef[A], key: A, default: int): int = result = t[].getOrDefault(key, default) proc len*[A](t: CountTableRef[A]): int = - ## Returns the number of keys in `t`. + ## Returns the number of keys in ``t``. result = t.counter proc del*[A](t: CountTableRef[A], key: A) {.since: (1, 1).} = - ## Deletes `key` from table `t`. Does nothing if the key does not exist. + ## Deletes ``key`` from table ``t``. Does nothing if the key does not exist. + ## + ## O(n) complexity. ## ## See also: ## * `pop proc<#pop,CountTableRef[A],A,int>`_ @@ -2744,11 +2742,13 @@ proc del*[A](t: CountTableRef[A], key: A) {.since: (1, 1).} = del(t[], key) proc pop*[A](t: CountTableRef[A], key: A, val: var int): bool {.since: (1, 1).} = - ## Deletes the `key` from the table. - ## Returns `true`, if the `key` existed, and sets `val` to the - ## mapping of the key. Otherwise, returns `false`, and the `val` is + ## Deletes the ``key`` from the table. + ## Returns ``true``, if the ``key`` existed, and sets ``val`` to the + ## mapping of the key. Otherwise, returns ``false``, and the ``val`` is ## unchanged. ## + ## O(n) complexity. + ## ## See also: ## * `del proc<#del,CountTableRef[A],A>`_ ## * `clear proc<#clear,CountTableRef[A]>`_ to empty the whole table @@ -2770,7 +2770,7 @@ proc sort*[A](t: CountTableRef[A], order = SortOrder.Descending) = ## ## You can use the iterators `pairs<#pairs.i,CountTableRef[A]>`_, ## `keys<#keys.i,CountTableRef[A]>`_, and `values<#values.i,CountTableRef[A]>`_ - ## to iterate over `t` in the sorted order. + ## to iterate over ``t`` in the sorted order. t[].sort(order = order) proc merge*[A](s, t: CountTableRef[A]) = @@ -2785,13 +2785,13 @@ proc merge*[A](s, t: CountTableRef[A]) = s[].merge(t[]) proc `$`*[A](t: CountTableRef[A]): string = - ## The `$` operator for count tables. Used internally when calling `echo` + ## The ``$`` operator for count tables. Used internally when calling `echo` ## on a table. dollarImpl() proc `==`*[A](s, t: CountTableRef[A]): bool = - ## The `==` operator for count tables. Returns `true` if either both tables - ## are `nil`, or neither is `nil` and both contain the same keys with the same + ## The ``==`` operator for count tables. Returns ``true`` if either both tables + ## are ``nil``, or neither is ``nil`` and both contain the same keys with the same ## count. Insert order does not matter. if isNil(s): result = isNil(t) elif isNil(t): result = false @@ -2799,7 +2799,7 @@ proc `==`*[A](s, t: CountTableRef[A]): bool = iterator pairs*[A](t: CountTableRef[A]): (A, int) = - ## Iterates over any `(key, value)` pair in the table `t`. + ## Iterates over any ``(key, value)`` pair in the table ``t``. ## ## See also: ## * `mpairs iterator<#mpairs.i,CountTableRef[A]>`_ @@ -2832,7 +2832,7 @@ iterator pairs*[A](t: CountTableRef[A]): (A, int) = assert(len(t) == L, "the length of the table changed while iterating over it") iterator mpairs*[A](t: CountTableRef[A]): (A, var int) = - ## Iterates over any `(key, value)` pair in the table `t`. The values can + ## Iterates over any ``(key, value)`` pair in the table ``t``. The values can ## be modified. ## ## See also: @@ -2851,7 +2851,7 @@ iterator mpairs*[A](t: CountTableRef[A]): (A, var int) = assert(len(t) == L, "table modified while iterating over it") iterator keys*[A](t: CountTableRef[A]): A = - ## Iterates over any key in the table `t`. + ## Iterates over any key in the table ``t``. ## ## See also: ## * `pairs iterator<#pairs.i,CountTable[A]>`_ @@ -2869,7 +2869,7 @@ iterator keys*[A](t: CountTableRef[A]): A = assert(len(t) == L, "the length of the table changed while iterating over it") iterator values*[A](t: CountTableRef[A]): int = - ## Iterates over any value in the table `t`. + ## Iterates over any value in the table ``t``. ## ## See also: ## * `pairs iterator<#pairs.i,CountTableRef[A]>`_ @@ -2887,7 +2887,7 @@ iterator values*[A](t: CountTableRef[A]): int = assert(len(t) == L, "the length of the table changed while iterating over it") iterator mvalues*[A](t: CountTableRef[A]): var int = - ## Iterates over any value in the table `t`. The values can be modified. + ## Iterates over any value in the table ``t``. The values can be modified. ## ## See also: ## * `mpairs iterator<#mpairs.i,CountTableRef[A]>`_ @@ -2903,3 +2903,317 @@ iterator mvalues*[A](t: CountTableRef[A]): var int = if t.data[h].val != 0: yield t.data[h].val assert(len(t) == L, "the length of the table changed while iterating over it") + + + + +when isMainModule: + type + Person = object + firstName, lastName: string + + proc hash(x: Person): Hash = + ## Piggyback on the already available string hash proc. + ## + ## Without this proc nothing works! + result = x.firstName.hash !& x.lastName.hash + result = !$result + + var + salaries = initTable[Person, int]() + p1, p2: Person + p1.firstName = "Jon" + p1.lastName = "Ross" + salaries[p1] = 30_000 + p2.firstName = "소진" + p2.lastName = "박" + salaries[p2] = 45_000 + var + s2 = initOrderedTable[Person, int]() + s3 = initCountTable[Person]() + s2[p1] = 30_000 + s2[p2] = 45_000 + s3[p1] = 30_000 + s3[p2] = 45_000 + + block: # Ordered table should preserve order after deletion + var + s4 = initOrderedTable[int, int]() + s4[1] = 1 + s4[2] = 2 + s4[3] = 3 + + var prev = 0 + for i in s4.values: + doAssert(prev < i) + prev = i + + s4.del(2) + doAssert(2 notin s4) + doAssert(s4.len == 2) + prev = 0 + for i in s4.values: + doAssert(prev < i) + prev = i + + block: # Deletion from OrderedTable should account for collision groups. See issue #5057. + # The bug is reproducible only with exact keys + const key1 = "boy_jackpot.inGamma" + const key2 = "boy_jackpot.outBlack" + + var t = { + key1: 0, + key2: 0 + }.toOrderedTable() + + t.del(key1) + assert(t.len == 1) + assert(key2 in t) + + var + t1 = initCountTable[string]() + t2 = initCountTable[string]() + t1.inc("foo") + t1.inc("bar", 2) + t1.inc("baz", 3) + t2.inc("foo", 4) + t2.inc("bar") + t2.inc("baz", 11) + merge(t1, t2) + assert(t1["foo"] == 5) + assert(t1["bar"] == 3) + assert(t1["baz"] == 14) + + let + t1r = newCountTable[string]() + t2r = newCountTable[string]() + t1r.inc("foo") + t1r.inc("bar", 2) + t1r.inc("baz", 3) + t2r.inc("foo", 4) + t2r.inc("bar") + t2r.inc("baz", 11) + merge(t1r, t2r) + assert(t1r["foo"] == 5) + assert(t1r["bar"] == 3) + assert(t1r["baz"] == 14) + + var + t1l = initCountTable[string]() + t2l = initCountTable[string]() + t1l.inc("foo") + t1l.inc("bar", 2) + t1l.inc("baz", 3) + t2l.inc("foo", 4) + t2l.inc("bar") + t2l.inc("baz", 11) + + block: + const testKey = "TESTKEY" + let t: CountTableRef[string] = newCountTable[string]() + + # Before, does not compile with error message: + #test_counttable.nim(7, 43) template/generic instantiation from here + #lib/pure/collections/tables.nim(117, 21) template/generic instantiation from here + #lib/pure/collections/tableimpl.nim(32, 27) Error: undeclared field: 'hcode + doAssert 0 == t[testKey] + t.inc(testKey, 3) + doAssert 3 == t[testKey] + + block: + # Clear tests + var clearTable = newTable[int, string]() + clearTable[42] = "asd" + clearTable[123123] = "piuyqwb " + doAssert clearTable[42] == "asd" + clearTable.clear() + doAssert(not clearTable.hasKey(123123)) + doAssert clearTable.getOrDefault(42) == "" + + block: #5482 + var a = [("wrong?", "foo"), ("wrong?", "foo2")].newOrderedTable() + var b = newOrderedTable[string, string](initialSize = 2) + b.add("wrong?", "foo") + b.add("wrong?", "foo2") + assert a == b + + block: #5482 + var a = {"wrong?": "foo", "wrong?": "foo2"}.newOrderedTable() + var b = newOrderedTable[string, string](initialSize = 2) + b.add("wrong?", "foo") + b.add("wrong?", "foo2") + assert a == b + + block: #5487 + var a = {"wrong?": "foo", "wrong?": "foo2"}.newOrderedTable() + var b = newOrderedTable[string, string]() # notice, default size! + b.add("wrong?", "foo") + b.add("wrong?", "foo2") + assert a == b + + block: #5487 + var a = [("wrong?", "foo"), ("wrong?", "foo2")].newOrderedTable() + var b = newOrderedTable[string, string]() # notice, default size! + b.add("wrong?", "foo") + b.add("wrong?", "foo2") + assert a == b + + block: + var a = {"wrong?": "foo", "wrong?": "foo2"}.newOrderedTable() + var b = [("wrong?", "foo"), ("wrong?", "foo2")].newOrderedTable() + var c = newOrderedTable[string, string]() # notice, default size! + c.add("wrong?", "foo") + c.add("wrong?", "foo2") + assert a == b + assert a == c + + block: #6250 + let + a = {3: 1}.toOrderedTable + b = {3: 2}.toOrderedTable + assert((a == b) == false) + assert((b == a) == false) + + block: #6250 + let + a = {3: 2}.toOrderedTable + b = {3: 2}.toOrderedTable + assert((a == b) == true) + assert((b == a) == true) + + block: # CountTable.smallest + let t = toCountTable([0, 0, 5, 5, 5]) + doAssert t.smallest == (0, 2) + + block: #10065 + let t = toCountTable("abracadabra") + doAssert t['z'] == 0 + + var t_mut = toCountTable("abracadabra") + doAssert t_mut['z'] == 0 + # the previous read may not have modified the table. + doAssert t_mut.hasKey('z') == false + t_mut['z'] = 1 + doAssert t_mut['z'] == 1 + doAssert t_mut.hasKey('z') == true + + block: #12813 #13079 + var t = toCountTable("abracadabra") + doAssert len(t) == 5 + + t['a'] = 0 # remove a key + doAssert len(t) == 4 + + block: + var tp: Table[string, string] = initTable[string, string]() + doAssert "test1" == tp.getOrDefault("test1", "test1") + tp["test2"] = "test2" + doAssert "test2" == tp.getOrDefault("test2", "test1") + var tr: TableRef[string, string] = newTable[string, string]() + doAssert "test1" == tr.getOrDefault("test1", "test1") + tr["test2"] = "test2" + doAssert "test2" == tr.getOrDefault("test2", "test1") + var op: OrderedTable[string, string] = initOrderedTable[string, string]() + doAssert "test1" == op.getOrDefault("test1", "test1") + op["test2"] = "test2" + doAssert "test2" == op.getOrDefault("test2", "test1") + var orf: OrderedTableRef[string, string] = newOrderedTable[string, string]() + doAssert "test1" == orf.getOrDefault("test1", "test1") + orf["test2"] = "test2" + doAssert "test2" == orf.getOrDefault("test2", "test1") + + block tableWithoutInit: + var + a: Table[string, int] + b: Table[string, int] + c: Table[string, int] + d: Table[string, int] + e: Table[string, int] + + a["a"] = 7 + doAssert a.hasKey("a") + doAssert a.len == 1 + doAssert a["a"] == 7 + a["a"] = 9 + doAssert a.len == 1 + doAssert a["a"] == 9 + + doAssert b.hasKeyOrPut("b", 5) == false + doAssert b.hasKey("b") + doAssert b.hasKeyOrPut("b", 8) + doAssert b["b"] == 5 + + doAssert c.getOrDefault("a") == 0 + doAssert c.getOrDefault("a", 3) == 3 + c["a"] = 6 + doAssert c.getOrDefault("a", 3) == 6 + + doAssert d.mgetOrPut("a", 3) == 3 + doAssert d.mgetOrPut("a", 6) == 3 + + var x = 99 + doAssert e.pop("a", x) == false + doAssert x == 99 + e["a"] = 77 + doAssert e.pop("a", x) + doAssert x == 77 + + block orderedTableWithoutInit: + var + a: OrderedTable[string, int] + b: OrderedTable[string, int] + c: OrderedTable[string, int] + d: OrderedTable[string, int] + + a["a"] = 7 + doAssert a.hasKey("a") + doAssert a.len == 1 + doAssert a["a"] == 7 + a["a"] = 9 + doAssert a.len == 1 + doAssert a["a"] == 9 + + doAssert b.hasKeyOrPut("b", 5) == false + doAssert b.hasKey("b") + doAssert b.hasKeyOrPut("b", 8) + doAssert b["b"] == 5 + + doAssert c.getOrDefault("a") == 0 + doAssert c.getOrDefault("a", 3) == 3 + c["a"] = 6 + doAssert c.getOrDefault("a", 3) == 6 + + doAssert d.mgetOrPut("a", 3) == 3 + doAssert d.mgetOrPut("a", 6) == 3 + + block countTableWithoutInit: + var + a: CountTable[string] + b: CountTable[string] + c: CountTable[string] + d: CountTable[string] + e: CountTable[string] + + a["a"] = 7 + doAssert a.hasKey("a") + doAssert a.len == 1 + doAssert a["a"] == 7 + a["a"] = 9 + doAssert a.len == 1 + doAssert a["a"] == 9 + + doAssert b["b"] == 0 + b.inc("b") + doAssert b["b"] == 1 + + doAssert c.getOrDefault("a") == 0 + doAssert c.getOrDefault("a", 3) == 3 + c["a"] = 6 + doAssert c.getOrDefault("a", 3) == 6 + + e["f"] = 3 + merge(d, e) + doAssert d.hasKey("f") + d.inc("f") + merge(d, e) + doAssert d["f"] == 7 diff --git a/lib/pure/colors.nim b/lib/pure/colors.nim index b688fad54..d57e309e9 100644 --- a/lib/pure/colors.nim +++ b/lib/pure/colors.nim @@ -6,8 +6,7 @@ # distribution, for details about the copyright. # -## This module implements color handling for Nim, -## namely color mixing and parsing the CSS color names. +## This module implements color handling for Nim. import strutils from algorithm import binarySearch @@ -15,7 +14,7 @@ from algorithm import binarySearch type Color* = distinct int ## A color stored as RGB, e.g. `0xff00cc`. -proc `==`*(a, b: Color): bool {.borrow.} +proc `==` *(a, b: Color): bool {.borrow.} ## Compares two colors. ## ## .. code-block:: @@ -24,7 +23,7 @@ proc `==`*(a, b: Color): bool {.borrow.} ## b = colFuchsia ## c = Color(0x00_ff_cc) ## assert a == b - ## assert not (a == c) + ## assert not a == c template extract(a: Color, r, g, b: untyped) = var r = a.int shr 16 and 0xff @@ -171,7 +170,6 @@ const colDarkGoldenRod* = Color(0xB8860B) colDarkGray* = Color(0xA9A9A9) colDarkGreen* = Color(0x006400) - colDarkGrey* = Color(0xA9A9A9) colDarkKhaki* = Color(0xBDB76B) colDarkMagenta* = Color(0x8B008B) colDarkOliveGreen* = Color(0x556B2F) @@ -182,13 +180,11 @@ const colDarkSeaGreen* = Color(0x8FBC8F) colDarkSlateBlue* = Color(0x483D8B) colDarkSlateGray* = Color(0x2F4F4F) - colDarkSlateGrey* = Color(0x2F4F4F) colDarkTurquoise* = Color(0x00CED1) colDarkViolet* = Color(0x9400D3) colDeepPink* = Color(0xFF1493) colDeepSkyBlue* = Color(0x00BFFF) colDimGray* = Color(0x696969) - colDimGrey* = Color(0x696969) colDodgerBlue* = Color(0x1E90FF) colFireBrick* = Color(0xB22222) colFloralWhite* = Color(0xFFFAF0) @@ -200,7 +196,6 @@ const colGoldenRod* = Color(0xDAA520) colGray* = Color(0x808080) colGreen* = Color(0x008000) - colGrey* = Color(0x808080) colGreenYellow* = Color(0xADFF2F) colHoneyDew* = Color(0xF0FFF0) colHotPink* = Color(0xFF69B4) @@ -216,15 +211,13 @@ const colLightCoral* = Color(0xF08080) colLightCyan* = Color(0xE0FFFF) colLightGoldenRodYellow* = Color(0xFAFAD2) - colLightGray* = Color(0xD3D3D3) - colLightGreen* = Color(0x90EE90) colLightGrey* = Color(0xD3D3D3) + colLightGreen* = Color(0x90EE90) colLightPink* = Color(0xFFB6C1) colLightSalmon* = Color(0xFFA07A) colLightSeaGreen* = Color(0x20B2AA) colLightSkyBlue* = Color(0x87CEFA) colLightSlateGray* = Color(0x778899) - colLightSlateGrey* = Color(0x778899) colLightSteelBlue* = Color(0xB0C4DE) colLightYellow* = Color(0xFFFFE0) colLime* = Color(0x00FF00) @@ -235,7 +228,7 @@ const colMediumAquaMarine* = Color(0x66CDAA) colMediumBlue* = Color(0x0000CD) colMediumOrchid* = Color(0xBA55D3) - colMediumPurple* = Color(0x9370DB) + colMediumPurple* = Color(0x9370D8) colMediumSeaGreen* = Color(0x3CB371) colMediumSlateBlue* = Color(0x7B68EE) colMediumSpringGreen* = Color(0x00FA9A) @@ -256,7 +249,7 @@ const colPaleGoldenRod* = Color(0xEEE8AA) colPaleGreen* = Color(0x98FB98) colPaleTurquoise* = Color(0xAFEEEE) - colPaleVioletRed* = Color(0xDB7093) + colPaleVioletRed* = Color(0xD87093) colPapayaWhip* = Color(0xFFEFD5) colPeachPuff* = Color(0xFFDAB9) colPeru* = Color(0xCD853F) @@ -264,7 +257,6 @@ const colPlum* = Color(0xDDA0DD) colPowderBlue* = Color(0xB0E0E6) colPurple* = Color(0x800080) - colRebeccaPurple* = Color(0x663399) colRed* = Color(0xFF0000) colRosyBrown* = Color(0xBC8F8F) colRoyalBlue* = Color(0x4169E1) @@ -278,7 +270,6 @@ const colSkyBlue* = Color(0x87CEEB) colSlateBlue* = Color(0x6A5ACD) colSlateGray* = Color(0x708090) - colSlateGrey* = Color(0x708090) colSnow* = Color(0xFFFAFA) colSpringGreen* = Color(0x00FF7F) colSteelBlue* = Color(0x4682B4) @@ -294,155 +285,147 @@ const colYellow* = Color(0xFFFF00) colYellowGreen* = Color(0x9ACD32) - colorNames = { - "aliceblue": colAliceBlue, - "antiquewhite": colAntiqueWhite, - "aqua": colAqua, - "aquamarine": colAquamarine, - "azure": colAzure, - "beige": colBeige, - "bisque": colBisque, - "black": colBlack, - "blanchedalmond": colBlanchedAlmond, - "blue": colBlue, - "blueviolet": colBlueViolet, - "brown": colBrown, - "burlywood": colBurlyWood, - "cadetblue": colCadetBlue, - "chartreuse": colChartreuse, - "chocolate": colChocolate, - "coral": colCoral, - "cornflowerblue": colCornflowerBlue, - "cornsilk": colCornsilk, - "crimson": colCrimson, - "cyan": colCyan, - "darkblue": colDarkBlue, - "darkcyan": colDarkCyan, - "darkgoldenrod": colDarkGoldenRod, - "darkgray": colDarkGray, - "darkgreen": colDarkGreen, - "darkgrey": colDarkGrey, - "darkkhaki": colDarkKhaki, - "darkmagenta": colDarkMagenta, - "darkolivegreen": colDarkOliveGreen, - "darkorange": colDarkorange, - "darkorchid": colDarkOrchid, - "darkred": colDarkRed, - "darksalmon": colDarkSalmon, - "darkseagreen": colDarkSeaGreen, - "darkslateblue": colDarkSlateBlue, - "darkslategray": colDarkSlateGray, - "darkslategrey": colDarkSlateGrey, - "darkturquoise": colDarkTurquoise, - "darkviolet": colDarkViolet, - "deeppink": colDeepPink, - "deepskyblue": colDeepSkyBlue, - "dimgray": colDimGray, - "dimgrey": colDimGrey, - "dodgerblue": colDodgerBlue, - "firebrick": colFireBrick, - "floralwhite": colFloralWhite, - "forestgreen": colForestGreen, - "fuchsia": colFuchsia, - "gainsboro": colGainsboro, - "ghostwhite": colGhostWhite, - "gold": colGold, - "goldenrod": colGoldenRod, - "gray": colGray, - "green": colGreen, - "grey": colGrey, - "greenyellow": colGreenYellow, - "honeydew": colHoneyDew, - "hotpink": colHotPink, - "indianred": colIndianRed, - "indigo": colIndigo, - "ivory": colIvory, - "khaki": colKhaki, - "lavender": colLavender, - "lavenderblush": colLavenderBlush, - "lawngreen": colLawnGreen, - "lemonchiffon": colLemonChiffon, - "lightblue": colLightBlue, - "lightcoral": colLightCoral, - "lightcyan": colLightCyan, - "lightgoldenrodyellow": colLightGoldenRodYellow, - "lightgray": colLightGray, - "lightgreen": colLightGreen, - "lightgrey": colLightGrey, - "lightpink": colLightPink, - "lightsalmon": colLightSalmon, - "lightseagreen": colLightSeaGreen, - "lightskyblue": colLightSkyBlue, - "lightslategray": colLightSlateGray, - "lightslategrey": colLightSlateGrey, - "lightsteelblue": colLightSteelBlue, - "lightyellow": colLightYellow, - "lime": colLime, - "limegreen": colLimeGreen, - "linen": colLinen, - "magenta": colMagenta, - "maroon": colMaroon, - "mediumaquamarine": colMediumAquaMarine, - "mediumblue": colMediumBlue, - "mediumorchid": colMediumOrchid, - "mediumpurple": colMediumPurple, - "mediumseagreen": colMediumSeaGreen, - "mediumslateblue": colMediumSlateBlue, - "mediumspringgreen": colMediumSpringGreen, - "mediumturquoise": colMediumTurquoise, - "mediumvioletred": colMediumVioletRed, - "midnightblue": colMidnightBlue, - "mintcream": colMintCream, - "mistyrose": colMistyRose, - "moccasin": colMoccasin, - "navajowhite": colNavajoWhite, - "navy": colNavy, - "oldlace": colOldLace, - "olive": colOlive, - "olivedrab": colOliveDrab, - "orange": colOrange, - "orangered": colOrangeRed, - "orchid": colOrchid, - "palegoldenrod": colPaleGoldenRod, - "palegreen": colPaleGreen, - "paleturquoise": colPaleTurquoise, - "palevioletred": colPaleVioletRed, - "papayawhip": colPapayaWhip, - "peachpuff": colPeachPuff, - "peru": colPeru, - "pink": colPink, - "plum": colPlum, - "powderblue": colPowderBlue, - "purple": colPurple, - "rebeccapurple": colRebeccaPurple, - "red": colRed, - "rosybrown": colRosyBrown, - "royalblue": colRoyalBlue, - "saddlebrown": colSaddleBrown, - "salmon": colSalmon, - "sandybrown": colSandyBrown, - "seagreen": colSeaGreen, - "seashell": colSeaShell, - "sienna": colSienna, - "silver": colSilver, - "skyblue": colSkyBlue, - "slateblue": colSlateBlue, - "slategray": colSlateGray, - "slategrey": colSlateGrey, - "snow": colSnow, - "springgreen": colSpringGreen, - "steelblue": colSteelBlue, - "tan": colTan, - "teal": colTeal, - "thistle": colThistle, - "tomato": colTomato, - "turquoise": colTurquoise, - "violet": colViolet, - "wheat": colWheat, - "white": colWhite, - "whitesmoke": colWhiteSmoke, - "yellow": colYellow, - "yellowgreen": colYellowGreen} + colorNames = [ + ("aliceblue", colAliceBlue), + ("antiquewhite", colAntiqueWhite), + ("aqua", colAqua), + ("aquamarine", colAquamarine), + ("azure", colAzure), + ("beige", colBeige), + ("bisque", colBisque), + ("black", colBlack), + ("blanchedalmond", colBlanchedAlmond), + ("blue", colBlue), + ("blueviolet", colBlueViolet), + ("brown", colBrown), + ("burlywood", colBurlyWood), + ("cadetblue", colCadetBlue), + ("chartreuse", colChartreuse), + ("chocolate", colChocolate), + ("coral", colCoral), + ("cornflowerblue", colCornflowerBlue), + ("cornsilk", colCornsilk), + ("crimson", colCrimson), + ("cyan", colCyan), + ("darkblue", colDarkBlue), + ("darkcyan", colDarkCyan), + ("darkgoldenrod", colDarkGoldenRod), + ("darkgray", colDarkGray), + ("darkgreen", colDarkGreen), + ("darkkhaki", colDarkKhaki), + ("darkmagenta", colDarkMagenta), + ("darkolivegreen", colDarkOliveGreen), + ("darkorange", colDarkorange), + ("darkorchid", colDarkOrchid), + ("darkred", colDarkRed), + ("darksalmon", colDarkSalmon), + ("darkseagreen", colDarkSeaGreen), + ("darkslateblue", colDarkSlateBlue), + ("darkslategray", colDarkSlateGray), + ("darkturquoise", colDarkTurquoise), + ("darkviolet", colDarkViolet), + ("deeppink", colDeepPink), + ("deepskyblue", colDeepSkyBlue), + ("dimgray", colDimGray), + ("dodgerblue", colDodgerBlue), + ("firebrick", colFireBrick), + ("floralwhite", colFloralWhite), + ("forestgreen", colForestGreen), + ("fuchsia", colFuchsia), + ("gainsboro", colGainsboro), + ("ghostwhite", colGhostWhite), + ("gold", colGold), + ("goldenrod", colGoldenRod), + ("gray", colGray), + ("green", colGreen), + ("greenyellow", colGreenYellow), + ("honeydew", colHoneyDew), + ("hotpink", colHotPink), + ("indianred", colIndianRed), + ("indigo", colIndigo), + ("ivory", colIvory), + ("khaki", colKhaki), + ("lavender", colLavender), + ("lavenderblush", colLavenderBlush), + ("lawngreen", colLawnGreen), + ("lemonchiffon", colLemonChiffon), + ("lightblue", colLightBlue), + ("lightcoral", colLightCoral), + ("lightcyan", colLightCyan), + ("lightgoldenrodyellow", colLightGoldenRodYellow), + ("lightgrey", colLightGrey), + ("lightgreen", colLightGreen), + ("lightpink", colLightPink), + ("lightsalmon", colLightSalmon), + ("lightseagreen", colLightSeaGreen), + ("lightskyblue", colLightSkyBlue), + ("lightslategray", colLightSlateGray), + ("lightsteelblue", colLightSteelBlue), + ("lightyellow", colLightYellow), + ("lime", colLime), + ("limegreen", colLimeGreen), + ("linen", colLinen), + ("magenta", colMagenta), + ("maroon", colMaroon), + ("mediumaquamarine", colMediumAquaMarine), + ("mediumblue", colMediumBlue), + ("mediumorchid", colMediumOrchid), + ("mediumpurple", colMediumPurple), + ("mediumseagreen", colMediumSeaGreen), + ("mediumslateblue", colMediumSlateBlue), + ("mediumspringgreen", colMediumSpringGreen), + ("mediumturquoise", colMediumTurquoise), + ("mediumvioletred", colMediumVioletRed), + ("midnightblue", colMidnightBlue), + ("mintcream", colMintCream), + ("mistyrose", colMistyRose), + ("moccasin", colMoccasin), + ("navajowhite", colNavajoWhite), + ("navy", colNavy), + ("oldlace", colOldLace), + ("olive", colOlive), + ("olivedrab", colOliveDrab), + ("orange", colOrange), + ("orangered", colOrangeRed), + ("orchid", colOrchid), + ("palegoldenrod", colPaleGoldenRod), + ("palegreen", colPaleGreen), + ("paleturquoise", colPaleTurquoise), + ("palevioletred", colPaleVioletRed), + ("papayawhip", colPapayaWhip), + ("peachpuff", colPeachPuff), + ("peru", colPeru), + ("pink", colPink), + ("plum", colPlum), + ("powderblue", colPowderBlue), + ("purple", colPurple), + ("red", colRed), + ("rosybrown", colRosyBrown), + ("royalblue", colRoyalBlue), + ("saddlebrown", colSaddleBrown), + ("salmon", colSalmon), + ("sandybrown", colSandyBrown), + ("seagreen", colSeaGreen), + ("seashell", colSeaShell), + ("sienna", colSienna), + ("silver", colSilver), + ("skyblue", colSkyBlue), + ("slateblue", colSlateBlue), + ("slategray", colSlateGray), + ("snow", colSnow), + ("springgreen", colSpringGreen), + ("steelblue", colSteelBlue), + ("tan", colTan), + ("teal", colTeal), + ("thistle", colThistle), + ("tomato", colTomato), + ("turquoise", colTurquoise), + ("violet", colViolet), + ("wheat", colWheat), + ("white", colWhite), + ("whitesmoke", colWhiteSmoke), + ("yellow", colYellow), + ("yellowgreen", colYellowGreen)] proc `$`*(c: Color): string = ## Converts a color into its textual representation. @@ -457,7 +440,7 @@ proc colorNameCmp(x: tuple[name: string, col: Color], y: string): int = proc parseColor*(name: string): Color = ## Parses `name` to a color value. ## - ## If no valid color could be parsed `ValueError` is raised. + ## If no valid color could be parsed ``ValueError`` is raised. ## Case insensitive. ## runnableExamples: @@ -469,7 +452,7 @@ proc parseColor*(name: string): Color = assert parseColor(b) == Color(0x01_79_fc) doAssertRaises(ValueError): discard parseColor(c) - if name.len > 0 and name[0] == '#': + if name[0] == '#': result = Color(parseHexInt(name)) else: var idx = binarySearch(colorNames, name, colorNameCmp) @@ -478,7 +461,7 @@ proc parseColor*(name: string): Color = proc isColor*(name: string): bool = ## Returns true if `name` is a known color name or a hexadecimal color - ## prefixed with `#`. Case insensitive. + ## prefixed with ``#``. Case insensitive. ## runnableExamples: var @@ -489,10 +472,9 @@ proc isColor*(name: string): bool = assert b.isColor assert not c.isColor - if name.len == 0: return false if name[0] == '#': for i in 1 .. name.len-1: - if name[i] notin HexDigits: return false + if name[i] notin {'0'..'9', 'a'..'f', 'A'..'F'}: return false result = true else: result = binarySearch(colorNames, name, colorNameCmp) >= 0 diff --git a/lib/pure/complex.nim b/lib/pure/complex.nim index 1e8349ef6..d57adeb92 100644 --- a/lib/pure/complex.nim +++ b/lib/pure/complex.nim @@ -7,31 +7,8 @@ # distribution, for details about the copyright. # -## This module implements complex numbers -## and basic mathematical operations on them. -## -## Complex numbers are currently generic over 64-bit or 32-bit floats. - -runnableExamples: - from std/math import almostEqual, sqrt - - func almostEqual(a, b: Complex): bool = - almostEqual(a.re, b.re) and almostEqual(a.im, b.im) - - let - z1 = complex(1.0, 2.0) - z2 = complex(3.0, -4.0) - - assert almostEqual(z1 + z2, complex(4.0, -2.0)) - assert almostEqual(z1 - z2, complex(-2.0, 6.0)) - assert almostEqual(z1 * z2, complex(11.0, 2.0)) - assert almostEqual(z1 / z2, complex(-0.2, 0.4)) - - assert almostEqual(abs(z1), sqrt(5.0)) - assert almostEqual(conjugate(z1), complex(1.0, -2.0)) - - let (r, phi) = z1.polar - assert almostEqual(rect(r, phi), z1) +## This module implements complex numbers. +## Complex numbers are currently implemented as generic on a 64-bit or 32-bit float. {.push checks: off, line_dir: off, stack_trace: off, debugger: off.} # the user does not want to trace a part of the standard library! @@ -40,156 +17,147 @@ import math type Complex*[T: SomeFloat] = object - ## A complex number, consisting of a real and an imaginary part. re*, im*: T + ## A complex number, consisting of a real and an imaginary part. Complex64* = Complex[float64] - ## Alias for a complex number using 64-bit floats. + ## Alias for a pair of 64-bit floats. Complex32* = Complex[float32] - ## Alias for a complex number using 32-bit floats. + ## Alias for a pair of 32-bit floats. -func complex*[T: SomeFloat](re: T; im: T = 0.0): Complex[T] = - ## Returns a `Complex[T]` with real part `re` and imaginary part `im`. +proc complex*[T: SomeFloat](re: T; im: T = 0.0): Complex[T] = result.re = re result.im = im -func complex32*(re: float32; im: float32 = 0.0): Complex32 = - ## Returns a `Complex32` with real part `re` and imaginary part `im`. +proc complex32*(re: float32; im: float32 = 0.0): Complex[float32] = result.re = re result.im = im -func complex64*(re: float64; im: float64 = 0.0): Complex64 = - ## Returns a `Complex64` with real part `re` and imaginary part `im`. +proc complex64*(re: float64; im: float64 = 0.0): Complex[float64] = result.re = re result.im = im -template im*(arg: typedesc[float32]): Complex32 = complex32(0, 1) - ## Returns the imaginary unit (`complex32(0, 1)`). -template im*(arg: typedesc[float64]): Complex64 = complex64(0, 1) - ## Returns the imaginary unit (`complex64(0, 1)`). -template im*(arg: float32): Complex32 = complex32(0, arg) - ## Returns `arg` as an imaginary number (`complex32(0, arg)`). -template im*(arg: float64): Complex64 = complex64(0, arg) - ## Returns `arg` as an imaginary number (`complex64(0, arg)`). +template im*(arg: typedesc[float32]): Complex32 = complex[float32](0, 1) +template im*(arg: typedesc[float64]): Complex64 = complex[float64](0, 1) +template im*(arg: float32): Complex32 = complex[float32](0, arg) +template im*(arg: float64): Complex64 = complex[float64](0, arg) -func abs*[T](z: Complex[T]): T = - ## Returns the absolute value of `z`, - ## that is the distance from (0, 0) to `z`. +proc abs*[T](z: Complex[T]): T = + ## Return the distance from (0,0) to ``z``. result = hypot(z.re, z.im) -func abs2*[T](z: Complex[T]): T = - ## Returns the squared absolute value of `z`, - ## that is the squared distance from (0, 0) to `z`. - ## This is more efficient than `abs(z) ^ 2`. - result = z.re * z.re + z.im * z.im - -func sgn*[T](z: Complex[T]): Complex[T] = - ## Returns the phase of `z` as a unit complex number, - ## or 0 if `z` is 0. - let a = abs(z) - if a != 0: - result = z / a +proc abs2*[T](z: Complex[T]): T = + ## Return the squared distance from (0,0) to ``z``. + result = z.re*z.re + z.im*z.im -func conjugate*[T](z: Complex[T]): Complex[T] = - ## Returns the complex conjugate of `z` (`complex(z.re, -z.im)`). +proc conjugate*[T](z: Complex[T]): Complex[T] = + ## Conjugate of complex number ``z``. result.re = z.re result.im = -z.im -func inv*[T](z: Complex[T]): Complex[T] = - ## Returns the multiplicative inverse of `z` (`1/z`). +proc inv*[T](z: Complex[T]): Complex[T] = + ## Multiplicative inverse of complex number ``z``. conjugate(z) / abs2(z) -func `==`*[T](x, y: Complex[T]): bool = - ## Compares two complex numbers for equality. +proc `==` *[T](x, y: Complex[T]): bool = + ## Compare two complex numbers ``x`` and ``y`` for equality. result = x.re == y.re and x.im == y.im -func `+`*[T](x: T; y: Complex[T]): Complex[T] = - ## Adds a real number to a complex number. +proc `+` *[T](x: T; y: Complex[T]): Complex[T] = + ## Add a real number to a complex number. result.re = x + y.re result.im = y.im -func `+`*[T](x: Complex[T]; y: T): Complex[T] = - ## Adds a complex number to a real number. +proc `+` *[T](x: Complex[T]; y: T): Complex[T] = + ## Add a complex number to a real number. result.re = x.re + y result.im = x.im -func `+`*[T](x, y: Complex[T]): Complex[T] = - ## Adds two complex numbers. +proc `+` *[T](x, y: Complex[T]): Complex[T] = + ## Add two complex numbers. result.re = x.re + y.re result.im = x.im + y.im -func `-`*[T](z: Complex[T]): Complex[T] = +proc `-` *[T](z: Complex[T]): Complex[T] = ## Unary minus for complex numbers. result.re = -z.re result.im = -z.im -func `-`*[T](x: T; y: Complex[T]): Complex[T] = - ## Subtracts a complex number from a real number. - result.re = x - y.re - result.im = -y.im +proc `-` *[T](x: T; y: Complex[T]): Complex[T] = + ## Subtract a complex number from a real number. + x + (-y) -func `-`*[T](x: Complex[T]; y: T): Complex[T] = - ## Subtracts a real number from a complex number. +proc `-` *[T](x: Complex[T]; y: T): Complex[T] = + ## Subtract a real number from a complex number. result.re = x.re - y result.im = x.im -func `-`*[T](x, y: Complex[T]): Complex[T] = - ## Subtracts two complex numbers. +proc `-` *[T](x, y: Complex[T]): Complex[T] = + ## Subtract two complex numbers. result.re = x.re - y.re result.im = x.im - y.im -func `*`*[T](x: T; y: Complex[T]): Complex[T] = - ## Multiplies a real number with a complex number. - result.re = x * y.re - result.im = x * y.im - -func `*`*[T](x: Complex[T]; y: T): Complex[T] = - ## Multiplies a complex number with a real number. - result.re = x.re * y - result.im = x.im * y - -func `*`*[T](x, y: Complex[T]): Complex[T] = - ## Multiplies two complex numbers. - result.re = x.re * y.re - x.im * y.im - result.im = x.im * y.re + x.re * y.im - -func `/`*[T](x: Complex[T]; y: T): Complex[T] = - ## Divides a complex number by a real number. +proc `/` *[T](x: Complex[T]; y: T): Complex[T] = + ## Divide complex number ``x`` by real number ``y``. result.re = x.re / y result.im = x.im / y -func `/`*[T](x: T; y: Complex[T]): Complex[T] = - ## Divides a real number by a complex number. +proc `/` *[T](x: T; y: Complex[T]): Complex[T] = + ## Divide real number ``x`` by complex number ``y``. result = x * inv(y) -func `/`*[T](x, y: Complex[T]): Complex[T] = - ## Divides two complex numbers. - x * conjugate(y) / abs2(y) +proc `/` *[T](x, y: Complex[T]): Complex[T] = + ## Divide ``x`` by ``y``. + var r, den: T + if abs(y.re) < abs(y.im): + r = y.re / y.im + den = y.im + r * y.re + result.re = (x.re * r + x.im) / den + result.im = (x.im * r - x.re) / den + else: + r = y.im / y.re + den = y.re + r * y.im + result.re = (x.re + r * x.im) / den + result.im = (x.im - r * x.re) / den -func `+=`*[T](x: var Complex[T]; y: Complex[T]) = - ## Adds `y` to `x`. +proc `*` *[T](x: T; y: Complex[T]): Complex[T] = + ## Multiply a real number and a complex number. + result.re = x * y.re + result.im = x * y.im + +proc `*` *[T](x: Complex[T]; y: T): Complex[T] = + ## Multiply a complex number with a real number. + result.re = x.re * y + result.im = x.im * y + +proc `*` *[T](x, y: Complex[T]): Complex[T] = + ## Multiply ``x`` with ``y``. + result.re = x.re * y.re - x.im * y.im + result.im = x.im * y.re + x.re * y.im + + +proc `+=` *[T](x: var Complex[T]; y: Complex[T]) = + ## Add ``y`` to ``x``. x.re += y.re x.im += y.im -func `-=`*[T](x: var Complex[T]; y: Complex[T]) = - ## Subtracts `y` from `x`. +proc `-=` *[T](x: var Complex[T]; y: Complex[T]) = + ## Subtract ``y`` from ``x``. x.re -= y.re x.im -= y.im -func `*=`*[T](x: var Complex[T]; y: Complex[T]) = - ## Multiplies `x` by `y`. +proc `*=` *[T](x: var Complex[T]; y: Complex[T]) = + ## Multiply ``y`` to ``x``. let im = x.im * y.re + x.re * y.im x.re = x.re * y.re - x.im * y.im x.im = im -func `/=`*[T](x: var Complex[T]; y: Complex[T]) = - ## Divides `x` by `y` in place. +proc `/=` *[T](x: var Complex[T]; y: Complex[T]) = + ## Divide ``x`` by ``y`` in place. x = x / y -func sqrt*[T](z: Complex[T]): Complex[T] = - ## Computes the - ## ([principal](https://en.wikipedia.org/wiki/Square_root#Principal_square_root_of_a_complex_number)) - ## square root of a complex number `z`. +proc sqrt*[T](z: Complex[T]): Complex[T] = + ## Square root for a complex number ``z``. var x, y, w, r: T if z.re == 0.0 and z.im == 0.0: @@ -211,37 +179,29 @@ func sqrt*[T](z: Complex[T]): Complex[T] = result.im = if z.im >= 0.0: w else: -w result.re = z.im / (result.im + result.im) -func exp*[T](z: Complex[T]): Complex[T] = - ## Computes the exponential function (`e^z`). - let +proc exp*[T](z: Complex[T]): Complex[T] = + ## ``e`` raised to the power ``z``. + var rho = exp(z.re) theta = z.im result.re = rho * cos(theta) result.im = rho * sin(theta) -func ln*[T](z: Complex[T]): Complex[T] = - ## Returns the - ## ([principal value](https://en.wikipedia.org/wiki/Complex_logarithm#Principal_value) - ## of the) natural logarithm of `z`. +proc ln*[T](z: Complex[T]): Complex[T] = + ## Returns the natural log of ``z``. result.re = ln(abs(z)) result.im = arctan2(z.im, z.re) -func log10*[T](z: Complex[T]): Complex[T] = - ## Returns the logarithm base 10 of `z`. - ## - ## **See also:** - ## * `ln func<#ln,Complex[T]>`_ +proc log10*[T](z: Complex[T]): Complex[T] = + ## Returns the log base 10 of ``z``. result = ln(z) / ln(10.0) -func log2*[T](z: Complex[T]): Complex[T] = - ## Returns the logarithm base 2 of `z`. - ## - ## **See also:** - ## * `ln func<#ln,Complex[T]>`_ +proc log2*[T](z: Complex[T]): Complex[T] = + ## Returns the log base 2 of ``z``. result = ln(z) / ln(2.0) -func pow*[T](x, y: Complex[T]): Complex[T] = - ## `x` raised to the power of `y`. +proc pow*[T](x, y: Complex[T]): Complex[T] = + ## ``x`` raised to the power ``y``. if x.re == 0.0 and x.im == 0.0: if y.re == 0.0 and y.im == 0.0: result.re = 1.0 @@ -254,7 +214,7 @@ func pow*[T](x, y: Complex[T]): Complex[T] = elif y.re == -1.0 and y.im == 0.0: result = T(1.0) / x else: - let + var rho = abs(x) theta = arctan2(x.im, x.re) s = pow(rho, y.re) * exp(-y.im * theta) @@ -262,141 +222,235 @@ func pow*[T](x, y: Complex[T]): Complex[T] = result.re = s * cos(r) result.im = s * sin(r) -func pow*[T](x: Complex[T]; y: T): Complex[T] = - ## The complex number `x` raised to the power of the real number `y`. +proc pow*[T](x: Complex[T]; y: T): Complex[T] = + ## Complex number ``x`` raised to the power ``y``. pow(x, complex[T](y)) -func sin*[T](z: Complex[T]): Complex[T] = - ## Returns the sine of `z`. +proc sin*[T](z: Complex[T]): Complex[T] = + ## Returns the sine of ``z``. result.re = sin(z.re) * cosh(z.im) result.im = cos(z.re) * sinh(z.im) -func arcsin*[T](z: Complex[T]): Complex[T] = - ## Returns the inverse sine of `z`. +proc arcsin*[T](z: Complex[T]): Complex[T] = + ## Returns the inverse sine of ``z``. result = -im(T) * ln(im(T) * z + sqrt(T(1.0) - z*z)) -func cos*[T](z: Complex[T]): Complex[T] = - ## Returns the cosine of `z`. +proc cos*[T](z: Complex[T]): Complex[T] = + ## Returns the cosine of ``z``. result.re = cos(z.re) * cosh(z.im) result.im = -sin(z.re) * sinh(z.im) -func arccos*[T](z: Complex[T]): Complex[T] = - ## Returns the inverse cosine of `z`. +proc arccos*[T](z: Complex[T]): Complex[T] = + ## Returns the inverse cosine of ``z``. result = -im(T) * ln(z + sqrt(z*z - T(1.0))) -func tan*[T](z: Complex[T]): Complex[T] = - ## Returns the tangent of `z`. +proc tan*[T](z: Complex[T]): Complex[T] = + ## Returns the tangent of ``z``. result = sin(z) / cos(z) -func arctan*[T](z: Complex[T]): Complex[T] = - ## Returns the inverse tangent of `z`. +proc arctan*[T](z: Complex[T]): Complex[T] = + ## Returns the inverse tangent of ``z``. result = T(0.5)*im(T) * (ln(T(1.0) - im(T)*z) - ln(T(1.0) + im(T)*z)) -func cot*[T](z: Complex[T]): Complex[T] = - ## Returns the cotangent of `z`. +proc cot*[T](z: Complex[T]): Complex[T] = + ## Returns the cotangent of ``z``. result = cos(z)/sin(z) -func arccot*[T](z: Complex[T]): Complex[T] = - ## Returns the inverse cotangent of `z`. +proc arccot*[T](z: Complex[T]): Complex[T] = + ## Returns the inverse cotangent of ``z``. result = T(0.5)*im(T) * (ln(T(1.0) - im(T)/z) - ln(T(1.0) + im(T)/z)) -func sec*[T](z: Complex[T]): Complex[T] = - ## Returns the secant of `z`. +proc sec*[T](z: Complex[T]): Complex[T] = + ## Returns the secant of ``z``. result = T(1.0) / cos(z) -func arcsec*[T](z: Complex[T]): Complex[T] = - ## Returns the inverse secant of `z`. +proc arcsec*[T](z: Complex[T]): Complex[T] = + ## Returns the inverse secant of ``z``. result = -im(T) * ln(im(T) * sqrt(1.0 - 1.0/(z*z)) + T(1.0)/z) -func csc*[T](z: Complex[T]): Complex[T] = - ## Returns the cosecant of `z`. +proc csc*[T](z: Complex[T]): Complex[T] = + ## Returns the cosecant of ``z``. result = T(1.0) / sin(z) -func arccsc*[T](z: Complex[T]): Complex[T] = - ## Returns the inverse cosecant of `z`. +proc arccsc*[T](z: Complex[T]): Complex[T] = + ## Returns the inverse cosecant of ``z``. result = -im(T) * ln(sqrt(T(1.0) - T(1.0)/(z*z)) + im(T)/z) -func sinh*[T](z: Complex[T]): Complex[T] = - ## Returns the hyperbolic sine of `z`. +proc sinh*[T](z: Complex[T]): Complex[T] = + ## Returns the hyperbolic sine of ``z``. result = T(0.5) * (exp(z) - exp(-z)) -func arcsinh*[T](z: Complex[T]): Complex[T] = - ## Returns the inverse hyperbolic sine of `z`. +proc arcsinh*[T](z: Complex[T]): Complex[T] = + ## Returns the inverse hyperbolic sine of ``z``. result = ln(z + sqrt(z*z + 1.0)) -func cosh*[T](z: Complex[T]): Complex[T] = - ## Returns the hyperbolic cosine of `z`. +proc cosh*[T](z: Complex[T]): Complex[T] = + ## Returns the hyperbolic cosine of ``z``. result = T(0.5) * (exp(z) + exp(-z)) -func arccosh*[T](z: Complex[T]): Complex[T] = - ## Returns the inverse hyperbolic cosine of `z`. +proc arccosh*[T](z: Complex[T]): Complex[T] = + ## Returns the inverse hyperbolic cosine of ``z``. result = ln(z + sqrt(z*z - T(1.0))) -func tanh*[T](z: Complex[T]): Complex[T] = - ## Returns the hyperbolic tangent of `z`. +proc tanh*[T](z: Complex[T]): Complex[T] = + ## Returns the hyperbolic tangent of ``z``. result = sinh(z) / cosh(z) -func arctanh*[T](z: Complex[T]): Complex[T] = - ## Returns the inverse hyperbolic tangent of `z`. +proc arctanh*[T](z: Complex[T]): Complex[T] = + ## Returns the inverse hyperbolic tangent of ``z``. result = T(0.5) * (ln((T(1.0)+z) / (T(1.0)-z))) -func coth*[T](z: Complex[T]): Complex[T] = - ## Returns the hyperbolic cotangent of `z`. - result = cosh(z) / sinh(z) - -func arccoth*[T](z: Complex[T]): Complex[T] = - ## Returns the inverse hyperbolic cotangent of `z`. - result = T(0.5) * (ln(T(1.0) + T(1.0)/z) - ln(T(1.0) - T(1.0)/z)) - -func sech*[T](z: Complex[T]): Complex[T] = - ## Returns the hyperbolic secant of `z`. +proc sech*[T](z: Complex[T]): Complex[T] = + ## Returns the hyperbolic secant of ``z``. result = T(2.0) / (exp(z) + exp(-z)) -func arcsech*[T](z: Complex[T]): Complex[T] = - ## Returns the inverse hyperbolic secant of `z`. +proc arcsech*[T](z: Complex[T]): Complex[T] = + ## Returns the inverse hyperbolic secant of ``z``. result = ln(1.0/z + sqrt(T(1.0)/z+T(1.0)) * sqrt(T(1.0)/z-T(1.0))) -func csch*[T](z: Complex[T]): Complex[T] = - ## Returns the hyperbolic cosecant of `z`. +proc csch*[T](z: Complex[T]): Complex[T] = + ## Returns the hyperbolic cosecant of ``z``. result = T(2.0) / (exp(z) - exp(-z)) -func arccsch*[T](z: Complex[T]): Complex[T] = - ## Returns the inverse hyperbolic cosecant of `z`. +proc arccsch*[T](z: Complex[T]): Complex[T] = + ## Returns the inverse hyperbolic cosecant of ``z``. result = ln(T(1.0)/z + sqrt(T(1.0)/(z*z) + T(1.0))) -func phase*[T](z: Complex[T]): T = - ## Returns the phase (or argument) of `z`, that is the angle in polar representation. - ## - ## | `result = arctan2(z.im, z.re)` +proc coth*[T](z: Complex[T]): Complex[T] = + ## Returns the hyperbolic cotangent of ``z``. + result = cosh(z) / sinh(z) + +proc arccoth*[T](z: Complex[T]): Complex[T] = + ## Returns the inverse hyperbolic cotangent of ``z``. + result = T(0.5) * (ln(T(1.0) + T(1.0)/z) - ln(T(1.0) - T(1.0)/z)) + +proc phase*[T](z: Complex[T]): T = + ## Returns the phase of ``z``. arctan2(z.im, z.re) -func polar*[T](z: Complex[T]): tuple[r, phi: T] = - ## Returns `z` in polar coordinates. - ## - ## | `result.r = abs(z)` - ## | `result.phi = phase(z)` - ## - ## **See also:** - ## * `rect func<#rect,T,T>`_ for the inverse operation +proc polar*[T](z: Complex[T]): tuple[r, phi: T] = + ## Returns ``z`` in polar coordinates. (r: abs(z), phi: phase(z)) -func rect*[T](r, phi: T): Complex[T] = - ## Returns the complex number with polar coordinates `r` and `phi`. +proc rect*[T](r, phi: T): Complex[T] = + ## Returns the complex number with polar coordinates ``r`` and ``phi``. ## - ## | `result.re = r * cos(phi)` - ## | `result.im = r * sin(phi)` - ## - ## **See also:** - ## * `polar func<#polar,Complex[T]>`_ for the inverse operation + ## | ``result.re = r * cos(phi)`` + ## | ``result.im = r * sin(phi)`` complex(r * cos(phi), r * sin(phi)) -func `$`*(z: Complex): string = - ## Returns `z`'s string representation as `"(re, im)"`. - runnableExamples: - doAssert $complex(1.0, 2.0) == "(1.0, 2.0)" - +proc `$`*(z: Complex): string = + ## Returns ``z``'s string representation as ``"(re, im)"``. result = "(" & $z.re & ", " & $z.im & ")" {.pop.} + + +when isMainModule: + proc `=~`[T](x, y: Complex[T]): bool = + result = abs(x.re-y.re) < 1e-6 and abs(x.im-y.im) < 1e-6 + + proc `=~`[T](x: Complex[T]; y: T): bool = + result = abs(x.re-y) < 1e-6 and abs(x.im) < 1e-6 + + var + z: Complex64 = complex(0.0, 0.0) + oo: Complex64 = complex(1.0, 1.0) + a: Complex64 = complex(1.0, 2.0) + b: Complex64 = complex(-1.0, -2.0) + m1: Complex64 = complex(-1.0, 0.0) + i: Complex64 = complex(0.0, 1.0) + one: Complex64 = complex(1.0, 0.0) + tt: Complex64 = complex(10.0, 20.0) + ipi: Complex64 = complex(0.0, -PI) + + doAssert(a/2.0 =~ complex(0.5, 1.0)) + doAssert(a == a) + doAssert((a-a) == z) + doAssert((a+b) == z) + doAssert((a+b) =~ 0.0) + doAssert((a/b) == m1) + doAssert((1.0/a) =~ complex(0.2, -0.4)) + doAssert((a*b) == complex(3.0, -4.0)) + doAssert(10.0*a == tt) + doAssert(a*10.0 == tt) + doAssert(tt/10.0 == a) + doAssert(oo+(-1.0) == i) + doAssert( (-1.0)+oo == i) + doAssert(abs(oo) == sqrt(2.0)) + doAssert(conjugate(a) == complex(1.0, -2.0)) + doAssert(sqrt(m1) == i) + doAssert(exp(ipi) =~ m1) + + doAssert(pow(a, b) =~ complex(-3.72999124927876, -1.68815826725068)) + doAssert(pow(z, a) =~ complex(0.0, 0.0)) + doAssert(pow(z, z) =~ complex(1.0, 0.0)) + doAssert(pow(a, one) =~ a) + doAssert(pow(a, m1) =~ complex(0.2, -0.4)) + doAssert(pow(a, 2.0) =~ complex(-3.0, 4.0)) + doAssert(pow(a, 2) =~ complex(-3.0, 4.0)) + doAssert(not(pow(a, 2.0) =~ a)) + + doAssert(ln(a) =~ complex(0.804718956217050, 1.107148717794090)) + doAssert(log10(a) =~ complex(0.349485002168009, 0.480828578784234)) + doAssert(log2(a) =~ complex(1.16096404744368, 1.59727796468811)) + + doAssert(sin(a) =~ complex(3.16577851321617, 1.95960104142161)) + doAssert(cos(a) =~ complex(2.03272300701967, -3.05189779915180)) + doAssert(tan(a) =~ complex(0.0338128260798967, 1.0147936161466335)) + doAssert(cot(a) =~ 1.0 / tan(a)) + doAssert(sec(a) =~ 1.0 / cos(a)) + doAssert(csc(a) =~ 1.0 / sin(a)) + doAssert(arcsin(a) =~ complex(0.427078586392476, 1.528570919480998)) + doAssert(arccos(a) =~ complex(1.14371774040242, -1.52857091948100)) + doAssert(arctan(a) =~ complex(1.338972522294494, 0.402359478108525)) + doAssert(arccot(a) =~ complex(0.2318238045004031, -0.402359478108525)) + doAssert(arcsec(a) =~ complex(1.384478272687081, 0.3965682301123288)) + doAssert(arccsc(a) =~ complex(0.1863180541078155, -0.3965682301123291)) + + doAssert(cosh(a) =~ complex(-0.642148124715520, 1.068607421382778)) + doAssert(sinh(a) =~ complex(-0.489056259041294, 1.403119250622040)) + doAssert(tanh(a) =~ complex(1.1667362572409199, -0.243458201185725)) + doAssert(sech(a) =~ 1.0 / cosh(a)) + doAssert(csch(a) =~ 1.0 / sinh(a)) + doAssert(coth(a) =~ 1.0 / tanh(a)) + doAssert(arccosh(a) =~ complex(1.528570919480998, 1.14371774040242)) + doAssert(arcsinh(a) =~ complex(1.469351744368185, 1.06344002357775)) + doAssert(arctanh(a) =~ complex(0.173286795139986, 1.17809724509617)) + doAssert(arcsech(a) =~ arccosh(1.0/a)) + doAssert(arccsch(a) =~ arcsinh(1.0/a)) + doAssert(arccoth(a) =~ arctanh(1.0/a)) + + doAssert(phase(a) == 1.1071487177940904) + var t = polar(a) + doAssert(rect(t.r, t.phi) =~ a) + doAssert(rect(1.0, 2.0) =~ complex(-0.4161468365471424, 0.9092974268256817)) + + + var + i64: Complex32 = complex(0.0f, 1.0f) + a64: Complex32 = 2.0f*i64 + 1.0.float32 + b64: Complex32 = complex(-1.0'f32, -2.0'f32) + + doAssert(a64 == a64) + doAssert(a64 == -b64) + doAssert(a64 + b64 =~ 0.0'f32) + doAssert(not(pow(a64, b64) =~ a64)) + doAssert(pow(a64, 0.5f) =~ sqrt(a64)) + doAssert(pow(a64, 2) =~ complex(-3.0'f32, 4.0'f32)) + doAssert(sin(arcsin(b64)) =~ b64) + doAssert(cosh(arccosh(a64)) =~ a64) + + doAssert(phase(a64) - 1.107149f < 1e-6) + var t64 = polar(a64) + doAssert(rect(t64.r, t64.phi) =~ a64) + doAssert(rect(1.0f, 2.0f) =~ complex(-0.4161468f, 0.90929742f)) + doAssert(sizeof(a64) == 8) + doAssert(sizeof(a) == 16) + + doAssert 123.0.im + 456.0 == complex64(456, 123) + + var localA = complex(0.1'f32) + doAssert localA.im is float32 diff --git a/lib/pure/concurrency/atomics.nim b/lib/pure/concurrency/atomics.nim index c7b881bc5..29491f68c 100644 --- a/lib/pure/concurrency/atomics.nim +++ b/lib/pure/concurrency/atomics.nim @@ -11,45 +11,7 @@ ## ## Unstable API. -runnableExamples: - # Atomic - var loc: Atomic[int] - loc.store(4) - assert loc.load == 4 - loc.store(2) - assert loc.load(moRelaxed) == 2 - loc.store(9) - assert loc.load(moAcquire) == 9 - loc.store(0, moRelease) - assert loc.load == 0 - - assert loc.exchange(7) == 0 - assert loc.load == 7 - - var expected = 7 - assert loc.compareExchange(expected, 5, moRelaxed, moRelaxed) - assert expected == 7 - assert loc.load == 5 - - assert not loc.compareExchange(expected, 12, moRelaxed, moRelaxed) - assert expected == 5 - assert loc.load == 5 - - assert loc.fetchAdd(1) == 5 - assert loc.fetchAdd(2) == 6 - assert loc.fetchSub(3) == 8 - - loc.atomicInc(1) - assert loc.load == 6 - - # AtomicFlag - var flag: AtomicFlag - - assert not flag.testAndSet - assert flag.testAndSet - flag.clear(moRelaxed) - assert not flag.testAndSet - +import macros when defined(cpp) or defined(nimdoc): # For the C++ backend, types and operations map directly to C++11 atomics. @@ -89,11 +51,10 @@ when defined(cpp) or defined(nimdoc): ## with other moSequentiallyConsistent operations. type - Atomic*[T] {.importcpp: "std::atomic", completeStruct.} = object + Atomic* {.importcpp: "std::atomic".} [T] = object ## An atomic object with underlying type `T`. - raw: T - AtomicFlag* {.importcpp: "std::atomic_flag", size: 1.} = object + AtomicFlag* {.importcpp: "std::atomic_flag".} = object ## An atomic boolean state. # Access operations @@ -211,8 +172,8 @@ else: # MSVC intrinsics proc interlockedExchange(location: pointer; desired: int8): int8 {.importc: "_InterlockedExchange8".} - proc interlockedExchange(location: pointer; desired: int16): int16 {.importc: "_InterlockedExchange16".} - proc interlockedExchange(location: pointer; desired: int32): int32 {.importc: "_InterlockedExchange".} + proc interlockedExchange(location: pointer; desired: int16): int16 {.importc: "_InterlockedExchange".} + proc interlockedExchange(location: pointer; desired: int32): int32 {.importc: "_InterlockedExchange16".} proc interlockedExchange(location: pointer; desired: int64): int64 {.importc: "_InterlockedExchange64".} proc interlockedCompareExchange(location: pointer; desired, expected: int8): int8 {.importc: "_InterlockedCompareExchange8".} @@ -286,23 +247,26 @@ else: moSequentiallyConsistent type - # Atomic*[T] {.importcpp: "_Atomic('0)".} = object + # Atomic* {.importcpp: "_Atomic('0)".} [T] = object - AtomicInt8 {.importc: "_Atomic NI8".} = int8 - AtomicInt16 {.importc: "_Atomic NI16".} = int16 - AtomicInt32 {.importc: "_Atomic NI32".} = int32 - AtomicInt64 {.importc: "_Atomic NI64".} = int64 + AtomicInt8 {.importc: "_Atomic NI8".} = object + AtomicInt16 {.importc: "_Atomic NI16".} = object + AtomicInt32 {.importc: "_Atomic NI32".} = object + AtomicInt64 {.importc: "_Atomic NI64".} = object + + template atomicType*(T: typedesc[Trivial]): untyped = + # Maps the size of a trivial type to it's internal atomic type + when sizeof(T) == 1: AtomicInt8 + elif sizeof(T) == 2: AtomicInt16 + elif sizeof(T) == 4: AtomicInt32 + elif sizeof(T) == 8: AtomicInt64 type - AtomicFlag* {.importc: "atomic_flag", size: 1.} = object + AtomicFlag* {.importc: "atomic_flag".} = object Atomic*[T] = object when T is Trivial: - # Maps the size of a trivial type to it's internal atomic type - when sizeof(T) == 1: value: AtomicInt8 - elif sizeof(T) == 2: value: AtomicInt16 - elif sizeof(T) == 4: value: AtomicInt32 - elif sizeof(T) == 8: value: AtomicInt64 + value: T.atomicType else: nonAtomicValue: T guard: AtomicFlag @@ -333,7 +297,7 @@ else: {.pop.} proc load*[T: Trivial](location: var Atomic[T]; order: MemoryOrder = moSequentiallyConsistent): T {.inline.} = - cast[T](atomic_load_explicit[nonAtomicType(T), typeof(location.value)](addr(location.value), order)) + cast[T](atomic_load_explicit[nonAtomicType(T), type(location.value)](addr(location.value), order)) proc store*[T: Trivial](location: var Atomic[T]; desired: T; order: MemoryOrder = moSequentiallyConsistent) {.inline.} = atomic_store_explicit(addr(location.value), cast[nonAtomicType(T)](desired), order) proc exchange*[T: Trivial](location: var Atomic[T]; desired: T; order: MemoryOrder = moSequentiallyConsistent): T {.inline.} = @@ -361,11 +325,9 @@ else: cast[T](atomic_fetch_xor_explicit(addr(location.value), cast[nonAtomicType(T)](value), order)) template withLock[T: not Trivial](location: var Atomic[T]; order: MemoryOrder; body: untyped): untyped = - while testAndSet(location.guard, moAcquire): discard - try: - body - finally: - clear(location.guard, moRelease) + while location.guard.testAndSet(moAcquire): discard + body + location.guard.clear(moRelease) proc load*[T: not Trivial](location: var Atomic[T]; order: MemoryOrder = moSequentiallyConsistent): T {.inline.} = withLock(location, order): @@ -383,14 +345,16 @@ else: proc compareExchange*[T: not Trivial](location: var Atomic[T]; expected: var T; desired: T; success, failure: MemoryOrder): bool {.inline.} = withLock(location, success): if location.nonAtomicValue != expected: - expected = location.nonAtomicValue return false - expected = desired swap(location.nonAtomicValue, expected) return true proc compareExchangeWeak*[T: not Trivial](location: var Atomic[T]; expected: var T; desired: T; success, failure: MemoryOrder): bool {.inline.} = - compareExchange(location, expected, desired, success, failure) + withLock(location, success): + if location.nonAtomicValue != expected: + return false + swap(location.nonAtomicValue, expected) + return true proc compareExchange*[T: not Trivial](location: var Atomic[T]; expected: var T; desired: T; order: MemoryOrder = moSequentiallyConsistent): bool {.inline.} = compareExchange(location, expected, desired, order, order) diff --git a/lib/pure/concurrency/cpuinfo.nim b/lib/pure/concurrency/cpuinfo.nim index 1d2ff63e1..515d7e2da 100644 --- a/lib/pure/concurrency/cpuinfo.nim +++ b/lib/pure/concurrency/cpuinfo.nim @@ -7,30 +7,23 @@ # distribution, for details about the copyright. # -## This module implements a proc to determine the number of CPUs / cores. - -runnableExamples: - doAssert countProcessors() > 0 - +## This module implements procs to determine the number of CPUs / cores. include "system/inclrtl" -when defined(posix) and not (defined(macosx) or defined(bsd)): +when not defined(windows): import posix -when defined(windows): - import std/private/win_getsysteminfo - when defined(freebsd) or defined(macosx): - {.emit: "#include ".} + {.emit:"#include ".} when defined(openbsd) or defined(netbsd): - {.emit: "#include ".} + {.emit:"#include ".} when defined(macosx) or defined(bsd): # we HAVE to emit param.h before sysctl.h so we cannot use .header here # either. The amount of archaic bullshit in Poonix based OSes is just insane. - {.emit: "#include ".} + {.emit:"#include ".} const CTL_HW = 6 HW_AVAILCPU = 25 @@ -40,7 +33,7 @@ when defined(macosx) or defined(bsd): importc: "sysctl", nodecl.} when defined(genode): - import genode/env + include genode/env proc affinitySpaceTotal(env: GenodeEnvPtr): cuint {. importcpp: "@->cpu().affinity_space().total()".} @@ -54,13 +47,28 @@ when defined(haiku): header: "".} proc countProcessors*(): int {.rtl, extern: "ncpi$1".} = - ## Returns the number of the processors/cores the machine has. + ## returns the number of the processors/cores the machine has. ## Returns 0 if it cannot be detected. when defined(windows): + type + SYSTEM_INFO {.final, pure.} = object + u1: int32 + dwPageSize: int32 + lpMinimumApplicationAddress: pointer + lpMaximumApplicationAddress: pointer + dwActiveProcessorMask: ptr int32 + dwNumberOfProcessors: int32 + dwProcessorType: int32 + dwAllocationGranularity: int32 + wProcessorLevel: int16 + wProcessorRevision: int16 + + proc GetSystemInfo(lpSystemInfo: var SYSTEM_INFO) {.stdcall, dynlib: "kernel32", importc: "GetSystemInfo".} + var - si: SystemInfo - getSystemInfo(addr si) - result = int(si.dwNumberOfProcessors) + si: SYSTEM_INFO + GetSystemInfo(si) + result = si.dwNumberOfProcessors elif defined(macosx) or defined(bsd): var mib: array[0..3, cint] diff --git a/lib/pure/concurrency/cpuload.nim b/lib/pure/concurrency/cpuload.nim index 137dd67ad..3ee7336f0 100644 --- a/lib/pure/concurrency/cpuload.nim +++ b/lib/pure/concurrency/cpuload.nim @@ -19,9 +19,6 @@ when defined(windows): elif defined(linux): from cpuinfo import countProcessors -when defined(nimPreviewSlimSystem): - import std/syncio - type ThreadPoolAdvice* = enum doNothing, @@ -91,7 +88,7 @@ when not defined(testing) and isMainModule and not defined(nimdoc): proc busyLoop() = while true: - discard rand(80) + discard random(80) os.sleep(100) spawn busyLoop() diff --git a/lib/pure/concurrency/threadpool.nim b/lib/pure/concurrency/threadpool.nim index 0eb20dc9a..1f7df7c00 100644 --- a/lib/pure/concurrency/threadpool.nim +++ b/lib/pure/concurrency/threadpool.nim @@ -7,24 +7,21 @@ # distribution, for details about the copyright. # -## Implements Nim's `parallel & spawn statements `_. +## Implements Nim's `spawn `_. +## +## **See also:** +## * `threads module `_ +## * `channels module `_ +## * `locks module `_ +## * `asyncdispatch module `_ ## ## Unstable API. -## -## See also -## ======== -## * `threads module `_ for basic thread support -## * `locks module `_ for locks and condition variables -## * `asyncdispatch module `_ for asynchronous IO when not compileOption("threads"): {.error: "Threadpool requires --threads:on option.".} import cpuinfo, cpuload, locks, os -when defined(nimPreviewSlimSystem): - import std/[assertions, typedthreads, sysatomics] - {.push stackTrace:off.} type @@ -54,35 +51,38 @@ proc signal(cv: var Semaphore) = release(cv.L) signal(cv.c) -const CacheLineSize = 64 # true for most archs +const CacheLineSize = 32 # true for most archs type - Barrier {.compilerproc.} = object + Barrier {.compilerProc.} = object entered: int cv: Semaphore # Semaphore takes 3 words at least - left {.align(CacheLineSize).}: int - interest {.align(CacheLineSize).} : bool # whether the master is interested in the "all done" event + when sizeof(int) < 8: + cacheAlign: array[CacheLineSize-4*sizeof(int), byte] + left: int + cacheAlign2: array[CacheLineSize-sizeof(int), byte] + interest: bool # whether the master is interested in the "all done" event -proc barrierEnter(b: ptr Barrier) {.compilerproc, inline.} = +proc barrierEnter(b: ptr Barrier) {.compilerProc, inline.} = # due to the signaling between threads, it is ensured we are the only # one with access to 'entered' so we don't need 'atomicInc' here: inc b.entered # also we need no 'fence' instructions here as soon 'nimArgsPassingDone' # will be called which already will perform a fence for us. -proc barrierLeave(b: ptr Barrier) {.compilerproc, inline.} = +proc barrierLeave(b: ptr Barrier) {.compilerProc, inline.} = atomicInc b.left when not defined(x86): fence() # We may not have seen the final value of b.entered yet, # so we need to check for >= instead of ==. if b.interest and b.left >= b.entered: signal(b.cv) -proc openBarrier(b: ptr Barrier) {.compilerproc, inline.} = +proc openBarrier(b: ptr Barrier) {.compilerProc, inline.} = b.entered = 0 b.left = 0 b.interest = false -proc closeBarrier(b: ptr Barrier) {.compilerproc.} = +proc closeBarrier(b: ptr Barrier) {.compilerProc.} = fence() if b.left != b.entered: b.cv.initSemaphore() @@ -101,8 +101,8 @@ type cv: Semaphore idx: int - FlowVarBase* = ref FlowVarBaseObj ## Untyped base class for `FlowVar[T] <#FlowVar>`_. - FlowVarBaseObj {.acyclic.} = object of RootObj + FlowVarBase* = ref FlowVarBaseObj ## Untyped base class for ``FlowVar[T]``. + FlowVarBaseObj = object of RootObj ready, usesSemaphore, awaited: bool cv: Semaphore # for 'blockUntilAny' support ai: ptr AwaitInfo @@ -111,10 +111,10 @@ type # be RootRef here otherwise the wrong GC keeps track of it! owner: pointer # ptr Worker - FlowVarObj[T] {.acyclic.} = object of FlowVarBaseObj + FlowVarObj[T] = object of FlowVarBaseObj blob: T - FlowVar*[T] {.compilerproc.} = ref FlowVarObj[T] ## A data flow variable. + FlowVar*{.compilerProc.}[T] = ref FlowVarObj[T] ## A data flow variable. ToFreeQueue = object len: int @@ -137,8 +137,8 @@ type const threadpoolWaitMs {.intdefine.}: int = 100 -proc blockUntil*(fv: var FlowVarBaseObj) = - ## Waits until the value for `fv` arrives. +proc blockUntil*(fv: FlowVarBase) = + ## Waits until the value for the ``fv`` arrives. ## ## Usually it is not necessary to call this explicitly. if fv.usesSemaphore and not fv.awaited: @@ -185,7 +185,7 @@ proc attach(fv: FlowVarBase; i: int): bool = result = false release(fv.cv.L) -proc finished(fv: var FlowVarBaseObj) = +proc finished(fv: FlowVarBase) = doAssert fv.ai.isNil, "flowVar is still attached to an 'blockUntilAny'" # we have to protect against the rare cases where the owner of the flowVar # simply disregards the flowVar and yet the "flowVar" has not yet written @@ -208,18 +208,16 @@ proc finished(fv: var FlowVarBaseObj) = # the worker thread waits for "data" to be set to nil before shutting down owner.data = nil -proc `=destroy`[T](fv: var FlowVarObj[T]) = - finished(fv) - `=destroy`(fv.blob) +proc fvFinalizer[T](fv: FlowVar[T]) = finished(fv) -proc nimCreateFlowVar[T](): FlowVar[T] {.compilerproc.} = - new(result) +proc nimCreateFlowVar[T](): FlowVar[T] {.compilerProc.} = + new(result, fvFinalizer) -proc nimFlowVarCreateSemaphore(fv: FlowVarBase) {.compilerproc.} = +proc nimFlowVarCreateSemaphore(fv: FlowVarBase) {.compilerProc.} = fv.cv.initSemaphore() fv.usesSemaphore = true -proc nimFlowVarSignal(fv: FlowVarBase) {.compilerproc.} = +proc nimFlowVarSignal(fv: FlowVarBase) {.compilerProc.} = if fv.ai != nil: acquire(fv.ai.cv.L) fv.ai.idx = fv.idx @@ -230,51 +228,60 @@ proc nimFlowVarSignal(fv: FlowVarBase) {.compilerproc.} = signal(fv.cv) proc awaitAndThen*[T](fv: FlowVar[T]; action: proc (x: T) {.closure.}) = - ## Blocks until `fv` is available and then passes its value - ## to `action`. + ## Blocks until the ``fv`` is available and then passes its value + ## to ``action``. ## - ## Note that due to Nim's parameter passing semantics, this - ## means that `T` doesn't need to be copied, so `awaitAndThen` can - ## sometimes be more efficient than the `^ proc <#^,FlowVar[T]>`_. - blockUntil(fv[]) - when defined(nimV2): - action(fv.blob) - elif T is string or T is seq: + ## Note that due to Nim's parameter passing semantics this + ## means that ``T`` doesn't need to be copied so ``awaitAndThen`` can + ## sometimes be more efficient than `^ proc <#^,FlowVar[T]>`_. + blockUntil(fv) + when T is string or T is seq: action(cast[T](fv.data)) elif T is ref: {.error: "'awaitAndThen' not available for FlowVar[ref]".} else: action(fv.blob) - finished(fv[]) + finished(fv) proc unsafeRead*[T](fv: FlowVar[ref T]): ptr T = ## Blocks until the value is available and then returns this value. - blockUntil(fv[]) + blockUntil(fv) + result = cast[ptr T](fv.data) + finished(fv) + +proc `^`*[T](fv: FlowVar[ref T]): ref T = + ## Blocks until the value is available and then returns this value. + blockUntil(fv) + let src = cast[ref T](fv.data) when defined(nimV2): - result = cast[ptr T](fv.blob) + result = src else: - result = cast[ptr T](fv.data) - finished(fv[]) + deepCopy result, src + finished(fv) proc `^`*[T](fv: FlowVar[T]): T = ## Blocks until the value is available and then returns this value. - blockUntil(fv[]) - when not defined(nimV2) and (T is string or T is seq or T is ref): - deepCopy result, cast[T](fv.data) + blockUntil(fv) + when T is string or T is seq: + let src = cast[T](fv.data) + when defined(nimV2): + result = src + else: + deepCopy result, src else: result = fv.blob - finished(fv[]) + finished(fv) proc blockUntilAny*(flowVars: openArray[FlowVarBase]): int = - ## Awaits any of the given `flowVars`. Returns the index of one `flowVar` + ## Awaits any of the given ``flowVars``. Returns the index of one ``flowVar`` ## for which a value arrived. ## - ## A `flowVar` only supports one call to `blockUntilAny` at the same time. - ## That means if you `blockUntilAny([a,b])` and `blockUntilAny([b,c])` - ## the second call will only block until `c`. If there is no `flowVar` left + ## A ``flowVar`` only supports one call to ``blockUntilAny`` at the same time. + ## That means if you ``blockUntilAny([a,b])`` and ``blockUntilAny([b,c])`` + ## the second call will only block until ``c``. If there is no ``flowVar`` left ## to be able to wait on, -1 is returned. ## - ## **Note:** This results in non-deterministic behaviour and should be avoided. + ## **Note**: This results in non-deterministic behaviour and should be avoided. var ai: AwaitInfo ai.cv.initSemaphore() var conflicts = 0 @@ -295,9 +302,9 @@ proc blockUntilAny*(flowVars: openArray[FlowVarBase]): int = destroySemaphore(ai.cv) proc isReady*(fv: FlowVarBase): bool = - ## Determines whether the specified `FlowVarBase`'s value is available. + ## Determines whether the specified ``FlowVarBase``'s value is available. ## - ## If `true`, awaiting `fv` will not block. + ## If ``true``, awaiting ``fv`` will not block. if fv.usesSemaphore and not fv.awaited: acquire(fv.cv.L) result = fv.cv.counter > 0 @@ -305,31 +312,31 @@ proc isReady*(fv: FlowVarBase): bool = else: result = true -proc nimArgsPassingDone(p: pointer) {.compilerproc.} = +proc nimArgsPassingDone(p: pointer) {.compilerProc.} = let w = cast[ptr Worker](p) signal(w.taskStarted) const - MaxThreadPoolSize* {.intdefine.} = 256 ## Maximum size of the thread pool. 256 threads - ## should be good enough for anybody ;-) - MaxDistinguishedThread* {.intdefine.} = 32 ## Maximum number of "distinguished" threads. + MaxThreadPoolSize* = 256 ## Maximum size of the thread pool. 256 threads + ## should be good enough for anybody ;-) + MaxDistinguishedThread* = 32 ## Maximum number of "distinguished" threads. type - ThreadId* = range[0..MaxDistinguishedThread-1] ## A thread identifier. + ThreadId* = range[0..MaxDistinguishedThread-1] var currentPoolSize: int maxPoolSize = MaxThreadPoolSize minPoolSize = 4 - gSomeReady: Semaphore + gSomeReady : Semaphore readyWorker: ptr Worker # A workaround for recursion deadlock issue # https://github.com/nim-lang/Nim/issues/4597 var numSlavesLock: Lock - numSlavesRunning {.guard: numSlavesLock.}: int - numSlavesWaiting {.guard: numSlavesLock.}: int + numSlavesRunning {.guard: numSlavesLock}: int + numSlavesWaiting {.guard: numSlavesLock}: int isSlave {.threadvar.}: bool numSlavesLock.initLock @@ -402,7 +409,7 @@ proc setMinPoolSize*(size: range[1..MaxThreadPoolSize]) = proc setMaxPoolSize*(size: range[1..MaxThreadPoolSize]) = ## Sets the maximum thread pool size. The default value of this - ## is `MaxThreadPoolSize <#MaxThreadPoolSize>`_. + ## is ``MaxThreadPoolSize`` (256). maxPoolSize = size if currentPoolSize > maxPoolSize: for i in maxPoolSize..currentPoolSize-1: @@ -442,45 +449,43 @@ proc setup() = for i in 0..`_ instead. result = gSomeReady.counter > 0 -proc spawn*(call: sink typed) {.magic: "Spawn".} = - ## Always spawns a new task, so that the `call` is never executed on +proc spawn*(call: typed): void {.magic: "Spawn".} + ## Always spawns a new task, so that the ``call`` is never executed on ## the calling thread. ## - ## `call` has to be a proc call `p(...)` where `p` is gcsafe and has a - ## return type that is either `void` or compatible with `FlowVar[T]`. - discard "It uses `nimSpawn3` internally" + ## ``call`` has to be proc call ``p(...)`` where ``p`` is gcsafe and has a + ## return type that is either ``void`` or compatible with ``FlowVar[T]``. -proc pinnedSpawn*(id: ThreadId; call: sink typed) {.magic: "Spawn".} = - ## Always spawns a new task on the worker thread with `id`, so that - ## the `call` is **always** executed on the thread. +proc pinnedSpawn*(id: ThreadId; call: typed): void {.magic: "Spawn".} + ## Always spawns a new task on the worker thread with ``id``, so that + ## the ``call`` is **always** executed on the thread. ## - ## `call` has to be a proc call `p(...)` where `p` is gcsafe and has a - ## return type that is either `void` or compatible with `FlowVar[T]`. - discard "It uses `nimSpawn4` internally" + ## ``call`` has to be proc call ``p(...)`` where ``p`` is gcsafe and has a + ## return type that is either ``void`` or compatible with ``FlowVar[T]``. -template spawnX*(call) = +template spawnX*(call): void = ## Spawns a new task if a CPU core is ready, otherwise executes the ## call in the calling thread. ## - ## Usually, it is advised to use the `spawn proc <#spawn,sinktyped>`_ - ## in order to not block the producer for an unknown amount of time. + ## Usually it is advised to use `spawn proc <#spawn,typed>`_ in order to + ## not block the producer for an unknown amount of time. ## - ## `call` has to be a proc call `p(...)` where `p` is gcsafe and has a - ## return type that is either 'void' or compatible with `FlowVar[T]`. + ## ``call`` has to be proc call ``p(...)`` where ``p`` is gcsafe and has a + ## return type that is either 'void' or compatible with ``FlowVar[T]``. (if preferSpawn(): spawn call else: call) proc parallel*(body: untyped) {.magic: "Parallel".} ## A parallel section can be used to execute a block in parallel. ## - ## `body` has to be in a DSL that is a particular subset of the language. + ## ``body`` has to be in a DSL that is a particular subset of the language. ## ## Please refer to `the manual `_ ## for further information. @@ -491,7 +496,7 @@ var initLock stateLock -proc nimSpawn3(fn: WorkerProc; data: pointer) {.compilerproc.} = +proc nimSpawn3(fn: WorkerProc; data: pointer) {.compilerProc.} = # implementation of 'spawn' that is used by the code generator. while true: if selectWorker(readyWorker, fn, data): return @@ -576,7 +581,7 @@ var initLock distinguishedLock -proc nimSpawn4(fn: WorkerProc; data: pointer; id: ThreadId) {.compilerproc.} = +proc nimSpawn4(fn: WorkerProc; data: pointer; id: ThreadId) {.compilerProc.} = acquire(distinguishedLock) if not distinguishedData[id].initialized: activateDistinguishedThread(id) @@ -587,7 +592,7 @@ proc nimSpawn4(fn: WorkerProc; data: pointer; id: ThreadId) {.compilerproc.} = proc sync*() = - ## A simple barrier to wait for all `spawn`ed tasks. + ## A simple barrier to wait for all ``spawn``'ed tasks. ## ## If you need more elaborate waiting, you have to use an explicit barrier. while true: diff --git a/lib/pure/cookies.nim b/lib/pure/cookies.nim index 22704e434..eaff86ae6 100644 --- a/lib/pure/cookies.nim +++ b/lib/pure/cookies.nim @@ -9,28 +9,18 @@ ## This module implements helper procs for parsing Cookies. -import strtabs, times, options - -when defined(nimPreviewSlimSystem): - import std/assertions - - -type - SameSite* {.pure.} = enum ## The SameSite cookie attribute. - ## `Default` means that `setCookie` - ## proc will not set `SameSite` attribute. - Default, None, Lax, Strict +import strtabs, times proc parseCookies*(s: string): StringTableRef = - ## Parses cookies into a string table. + ## parses cookies into a string table. ## ## The proc is meant to parse the Cookie header set by a client, not the ## "Set-Cookie" header set by servers. - runnableExamples: - import std/strtabs - let cookieJar = parseCookies("a=1; foo=bar") - assert cookieJar["a"] == "1" - assert cookieJar["foo"] == "bar" + ## + ## Example: + ## + ## .. code-block::Nim + ## doAssert parseCookies("a=1; foo=bar") == {"a": 1, "foo": "bar"}.newStringTable result = newStringTable(modeCaseInsensitive) var i = 0 @@ -49,12 +39,9 @@ proc parseCookies*(s: string): StringTableRef = proc setCookie*(key, value: string, domain = "", path = "", expires = "", noName = false, - secure = false, httpOnly = false, - maxAge = none(int), sameSite = SameSite.Default): string = + secure = false, httpOnly = false): string = ## Creates a command in the format of - ## `Set-Cookie: key=value; Domain=...; ...` - ## - ## .. tip:: Cookies can be vulnerable. Consider setting `secure=true`, `httpOnly=true` and `sameSite=Strict`. + ## ``Set-Cookie: key=value; Domain=...; ...`` result = "" if not noName: result.add("Set-Cookie: ") result.add key & "=" & value @@ -63,19 +50,27 @@ proc setCookie*(key, value: string, domain = "", path = "", if expires != "": result.add("; Expires=" & expires) if secure: result.add("; Secure") if httpOnly: result.add("; HttpOnly") - if maxAge.isSome: result.add("; Max-Age=" & $maxAge.unsafeGet) - - if sameSite != SameSite.Default: - if sameSite == SameSite.None: - doAssert secure, "Cookies with SameSite=None must specify the Secure attribute!" - result.add("; SameSite=" & $sameSite) proc setCookie*(key, value: string, expires: DateTime|Time, domain = "", path = "", noName = false, - secure = false, httpOnly = false, - maxAge = none(int), sameSite = SameSite.Default): string = + secure = false, httpOnly = false): string = ## Creates a command in the format of - ## `Set-Cookie: key=value; Domain=...; ...` - result = setCookie(key, value, domain, path, + ## ``Set-Cookie: key=value; Domain=...; ...`` + return setCookie(key, value, domain, path, format(expires.utc, "ddd',' dd MMM yyyy HH:mm:ss 'GMT'"), - noName, secure, httpOnly, maxAge, sameSite) + noname, secure, httpOnly) + +when isMainModule: + let expire = fromUnix(0) + 1.seconds + + let cookies = [ + setCookie("test", "value", expire), + setCookie("test", "value", expire.local), + setCookie("test", "value", expire.utc) + ] + let expected = "Set-Cookie: test=value; Expires=Thu, 01 Jan 1970 00:00:01 GMT" + doAssert cookies == [expected, expected, expected] + + let table = parseCookies("uid=1; kp=2") + doAssert table["uid"] == "1" + doAssert table["kp"] == "2" diff --git a/lib/pure/coro.nim b/lib/pure/coro.nim index 3b9bba59b..350b9f187 100644 --- a/lib/pure/coro.nim +++ b/lib/pure/coro.nim @@ -8,11 +8,11 @@ # ## Nim coroutines implementation, supports several context switching methods: -## ======== ============ +## -------- ------------ ## ucontext available on unix and alike (default) ## setjmp available on unix and alike (x86/64 only) ## fibers available and required on windows. -## ======== ============ +## -------- ------------ ## ## -d:nimCoroutines Required to build this module. ## -d:nimCoroutinesUcontext Use ucontext backend. @@ -21,8 +21,6 @@ ## ## Unstable API. -import system/coro_detection - when not nimCoroutines and not defined(nimdoc): when defined(noNimCoroutines): {.error: "Coroutines can not be used with -d:noNimCoroutines".} @@ -33,19 +31,11 @@ import os import lists include system/timers -when defined(nimPreviewSlimSystem): - import std/assertions - const defaultStackSize = 512 * 1024 -const useOrcArc = defined(gcArc) or defined(gcOrc) - -when useOrcArc: - proc nimGC_setStackBottom*(theStackBottom: pointer) = discard proc GC_addStack(bottom: pointer) {.cdecl, importc.} proc GC_removeStack(bottom: pointer) {.cdecl, importc.} proc GC_setActiveStack(bottom: pointer) {.cdecl, importc.} -proc GC_getActiveStack() : pointer {.cdecl, importc.} const CORO_BACKEND_UCONTEXT = 0 @@ -58,7 +48,7 @@ when defined(windows): {.warning: "ucontext coroutine backend is not available on windows, defaulting to fibers.".} when defined(nimCoroutinesSetjmp): {.warning: "setjmp coroutine backend is not available on windows, defaulting to fibers.".} -elif defined(haiku) or defined(openbsd): +elif defined(haiku): const coroBackend = CORO_BACKEND_SETJMP when defined(nimCoroutinesUcontext): {.warning: "ucontext coroutine backend is not available on haiku, defaulting to setjmp".} @@ -68,7 +58,7 @@ else: const coroBackend = CORO_BACKEND_UCONTEXT when coroBackend == CORO_BACKEND_FIBERS: - import windows/winlean + import windows.winlean type Context = pointer @@ -168,7 +158,7 @@ type ## CoroutineRef holds a pointer to actual coroutine object. Public API always returns ## CoroutineRef instead of CoroutinePtr in order to allow holding a reference to coroutine ## object while it can be safely deallocated by coroutine scheduler loop. In this case - ## Coroutine.reference.coro is set to nil. Public API checks for it being nil and + ## Coroutine.reference.coro is set to nil. Public API checks for for it being nil and ## gracefully fails if it is nil. coro: CoroutinePtr @@ -176,7 +166,6 @@ type coroutines: DoublyLinkedList[CoroutinePtr] current: DoublyLinkedNode[CoroutinePtr] loop: Coroutine - ncbottom: pointer # non coroutine stack botttom var ctx {.threadvar.}: CoroutineLoopContext @@ -194,8 +183,6 @@ proc initialize() = ctx.coroutines = initDoublyLinkedList[CoroutinePtr]() ctx.loop = Coroutine() ctx.loop.state = CORO_EXECUTING - when not useOrcArc: - ctx.ncbottom = GC_getActiveStack() when coroBackend == CORO_BACKEND_FIBERS: ctx.loop.execContext = ConvertThreadToFiberEx(nil, FIBER_FLAG_FLOAT_SWITCH) @@ -205,9 +192,7 @@ proc switchTo(current, to: CoroutinePtr) = ## Switches execution from `current` into `to` context. to.lastRun = getTicks() # Update position of current stack so gc invoked from another stack knows how much to scan. - when not useOrcArc: - GC_setActiveStack(current.stack.bottom) - nimGC_setStackBottom(current.stack.bottom) + GC_setActiveStack(current.stack.bottom) var frame = getFrameState() block: # Execution will switch to another fiber now. We do not need to update current stack @@ -229,16 +214,13 @@ proc switchTo(current, to: CoroutinePtr) = {.error: "Invalid coroutine backend set.".} # Execution was just resumed. Restore frame information and set active stack. setFrameState(frame) - when not useOrcArc: - GC_setActiveStack(current.stack.bottom) - nimGC_setStackBottom(ctx.ncbottom) + GC_setActiveStack(current.stack.bottom) proc suspend*(sleepTime: float = 0) = - ## Stops coroutine execution and resumes no sooner than after `sleeptime` seconds. + ## Stops coroutine execution and resumes no sooner than after ``sleeptime`` seconds. ## Until then other coroutines are executed. var current = getCurrent() current.sleepTime = sleepTime - nimGC_setStackBottom(ctx.ncbottom) switchTo(current, addr(ctx.loop)) proc runCurrentTask() = @@ -248,15 +230,13 @@ proc runCurrentTask() = block: var current = getCurrent() current.stack.bottom = sp - nimGC_setStackBottom(current.stack.bottom) # Execution of new fiber just started. Since it was entered not through `switchTo` we # have to set active stack here as well. GC_removeStack() has to be called in main loop # because we still need stack available in final suspend(0) call from which we will not # return. - when not useOrcArc: - GC_addStack(sp) - # Activate current stack because we are executing in a new coroutine. - GC_setActiveStack(sp) + GC_addStack(sp) + # Activate current stack because we are executing in a new coroutine. + GC_setActiveStack(sp) current.state = CORO_EXECUTING try: current.fn() # Start coroutine execution @@ -264,7 +244,6 @@ proc runCurrentTask() = echo "Unhandled exception in coroutine." writeStackTrace() current.state = CORO_FINISHED - nimGC_setStackBottom(ctx.ncbottom) suspend(0) # Exit coroutine without returning from coroExecWithStack() doAssert false @@ -278,11 +257,13 @@ proc start*(c: proc(), stacksize: int = defaultStackSize): CoroutineRef {.discar coro = cast[CoroutinePtr](alloc0(sizeof(Coroutine))) coro.execContext = CreateFiberEx(stacksize, stacksize, FIBER_FLAG_FLOAT_SWITCH, - (proc(p: pointer) {.stdcall.} = runCurrentTask()), nil) + (proc(p: pointer): void {.stdcall.} = runCurrentTask()), + nil) + coro.stack.size = stacksize else: coro = cast[CoroutinePtr](alloc0(sizeof(Coroutine) + stacksize)) - coro.stack.top = cast[pointer](cast[int](coro) + sizeof(Coroutine)) - coro.stack.bottom = cast[pointer](cast[int](coro.stack.top) + stacksize) + coro.stack.top = cast[pointer](cast[ByteAddress](coro) + sizeof(Coroutine)) + coro.stack.bottom = cast[pointer](cast[ByteAddress](coro.stack.top) + stacksize) when coroBackend == CORO_BACKEND_UCONTEXT: discard getcontext(coro.execContext) coro.execContext.uc_stack.ss_sp = coro.stack.top @@ -297,9 +278,9 @@ proc start*(c: proc(), stacksize: int = defaultStackSize): CoroutineRef {.discar return coro.reference proc run*() = + initialize() ## Starts main coroutine scheduler loop which exits when all coroutines exit. ## Calling this proc starts execution of first coroutine. - initialize() ctx.current = ctx.coroutines.head var minDelay: float = 0 while ctx.current != nil: @@ -323,8 +304,7 @@ proc run*() = next = ctx.current.next current.reference.coro = nil ctx.coroutines.remove(ctx.current) - when not useOrcArc: - GC_removeStack(current.stack.bottom) + GC_removeStack(current.stack.bottom) when coroBackend == CORO_BACKEND_FIBERS: DeleteFiber(current.execContext) else: @@ -338,9 +318,9 @@ proc run*() = ctx.current = ctx.current.next proc alive*(c: CoroutineRef): bool = c.coro != nil and c.coro.state != CORO_FINISHED - ## Returns `true` if coroutine has not returned, `false` otherwise. + ## Returns ``true`` if coroutine has not returned, ``false`` otherwise. proc wait*(c: CoroutineRef, interval = 0.01) = - ## Returns only after coroutine `c` has returned. `interval` is time in seconds how often. + ## Returns only after coroutine ``c`` has returned. ``interval`` is time in seconds how often. while alive(c): suspend(interval) diff --git a/lib/pure/cstrutils.nim b/lib/pure/cstrutils.nim index c907e54d8..fe9ceb68b 100644 --- a/lib/pure/cstrutils.nim +++ b/lib/pure/cstrutils.nim @@ -7,116 +7,75 @@ # distribution, for details about the copyright. # -## This module supports helper routines for working with `cstring` -## without having to convert `cstring` to `string`, in order to +## This module supports helper routines for working with ``cstring`` +## without having to convert ``cstring`` to ``string`` in order to ## save allocations. -## -## See also -## ======== -## * `strutils module `_ for working with `string` -include system/inclrtl -import std/private/strimpl +include "system/inclrtl" +proc toLowerAscii(c: char): char {.inline.} = + if c in {'A'..'Z'}: + result = chr(ord(c) + (ord('a') - ord('A'))) + else: + result = c -when defined(js): - func jsStartsWith(s, prefix: cstring): bool {.importjs: "#.startsWith(#)".} - func jsEndsWith(s, suffix: cstring): bool {.importjs: "#.endsWith(#)".} - - -func startsWith*(s, prefix: cstring): bool {.rtl, extern: "csuStartsWith".} = - ## Returns true if `s` starts with `prefix`. +proc startsWith*(s, prefix: cstring): bool {.noSideEffect, + rtl, extern: "csuStartsWith".} = + ## Returns true iff ``s`` starts with ``prefix``. ## - ## The JS backend uses the native `String.prototype.startsWith` function. - runnableExamples: - assert startsWith(cstring"Hello, Nimion", cstring"Hello") - assert not startsWith(cstring"Hello, Nimion", cstring"Nimion") - assert startsWith(cstring"Hello", cstring"") + ## If ``prefix == ""`` true is returned. + var i = 0 + while true: + if prefix[i] == '\0': return true + if s[i] != prefix[i]: return false + inc(i) - when nimvm: - startsWithImpl(s, prefix) - else: - when defined(js): - result = jsStartsWith(s, prefix) - else: - var i = 0 - while true: - if prefix[i] == '\0': return true - if s[i] != prefix[i]: return false - inc(i) - -func endsWith*(s, suffix: cstring): bool {.rtl, extern: "csuEndsWith".} = - ## Returns true if `s` ends with `suffix`. +proc endsWith*(s, suffix: cstring): bool {.noSideEffect, + rtl, extern: "csuEndsWith".} = + ## Returns true iff ``s`` ends with ``suffix``. ## - ## The JS backend uses the native `String.prototype.endsWith` function. - runnableExamples: - assert endsWith(cstring"Hello, Nimion", cstring"Nimion") - assert not endsWith(cstring"Hello, Nimion", cstring"Hello") - assert endsWith(cstring"Hello", cstring"") + ## If ``suffix == ""`` true is returned. + let slen = s.len + var i = 0 + var j = slen - len(suffix) + while i+j <% slen: + if s[i+j] != suffix[i]: return false + inc(i) + if suffix[i] == '\0': return true - when nimvm: - endsWithImpl(s, suffix) - else: - when defined(js): - result = jsEndsWith(s, suffix) - else: - let slen = s.len - var i = 0 - var j = slen - len(suffix) - while i + j <% slen: - if s[i + j] != suffix[i]: return false - inc(i) - if suffix[i] == '\0': return true +proc cmpIgnoreStyle*(a, b: cstring): int {.noSideEffect, + rtl, extern: "csuCmpIgnoreStyle".} = + ## Semantically the same as ``cmp(normalize($a), normalize($b))``. It + ## is just optimized to not allocate temporary strings. This should + ## NOT be used to compare Nim identifier names. use `macros.eqIdent` + ## for that. Returns: + ## + ## | 0 iff a == b + ## | < 0 iff a < b + ## | > 0 iff a > b + var i = 0 + var j = 0 + while true: + while a[i] == '_': inc(i) + while b[j] == '_': inc(j) # BUGFIX: typo + var aa = toLowerAscii(a[i]) + var bb = toLowerAscii(b[j]) + result = ord(aa) - ord(bb) + if result != 0 or aa == '\0': break + inc(i) + inc(j) -func cmpIgnoreStyle*(a, b: cstring): int {.rtl, extern: "csuCmpIgnoreStyle".} = - ## Semantically the same as `cmp(normalize($a), normalize($b))`. It - ## is just optimized to not allocate temporary strings. This should - ## NOT be used to compare Nim identifier names, use `macros.eqIdent` - ## for that. Returns: - ## * 0 if `a == b` - ## * < 0 if `a < b` - ## * \> 0 if `a > b` - runnableExamples: - assert cmpIgnoreStyle(cstring"hello", cstring"H_e_L_Lo") == 0 - - when nimvm: - cmpIgnoreStyleImpl(a, b) - else: - when defined(js): - cmpIgnoreStyleImpl(a, b) - else: - var i = 0 - var j = 0 - while true: - while a[i] == '_': inc(i) - while b[j] == '_': inc(j) # BUGFIX: typo - var aa = toLowerAscii(a[i]) - var bb = toLowerAscii(b[j]) - result = ord(aa) - ord(bb) - if result != 0 or aa == '\0': break - inc(i) - inc(j) - -func cmpIgnoreCase*(a, b: cstring): int {.rtl, extern: "csuCmpIgnoreCase".} = +proc cmpIgnoreCase*(a, b: cstring): int {.noSideEffect, + rtl, extern: "csuCmpIgnoreCase".} = ## Compares two strings in a case insensitive manner. Returns: - ## * 0 if `a == b` - ## * < 0 if `a < b` - ## * \> 0 if `a > b` - runnableExamples: - assert cmpIgnoreCase(cstring"hello", cstring"HeLLo") == 0 - assert cmpIgnoreCase(cstring"echo", cstring"hello") < 0 - assert cmpIgnoreCase(cstring"yellow", cstring"hello") > 0 - - when nimvm: - cmpIgnoreCaseImpl(a, b) - else: - when defined(js): - cmpIgnoreCaseImpl(a, b) - else: - var i = 0 - while true: - var aa = toLowerAscii(a[i]) - var bb = toLowerAscii(b[i]) - result = ord(aa) - ord(bb) - if result != 0 or aa == '\0': break - inc(i) + ## + ## | 0 iff a == b + ## | < 0 iff a < b + ## | > 0 iff a > b + var i = 0 + while true: + var aa = toLowerAscii(a[i]) + var bb = toLowerAscii(b[i]) + result = ord(aa) - ord(bb) + if result != 0 or aa == '\0': break + inc(i) diff --git a/lib/pure/db_common.nim b/lib/pure/db_common.nim new file mode 100644 index 000000000..96c13c003 --- /dev/null +++ b/lib/pure/db_common.nim @@ -0,0 +1,100 @@ +# +# +# Nim's Runtime Library +# (c) Copyright 2015 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +## Common datatypes and definitions for all ``db_*.nim`` ( +## `db_mysql `_, `db_postgres `_, +## and `db_sqlite `_) modules. + +type + DbError* = object of IOError ## exception that is raised if a database error occurs + + SqlQuery* = distinct string ## an SQL query string + + + DbEffect* = object of IOEffect ## effect that denotes a database operation + ReadDbEffect* = object of DbEffect ## effect that denotes a read operation + WriteDbEffect* = object of DbEffect ## effect that denotes a write operation + + DbTypeKind* = enum ## a superset of datatypes that might be supported. + dbUnknown, ## unknown datatype + dbSerial, ## datatype used for primary auto-increment keys + dbNull, ## datatype used for the NULL value + dbBit, ## bit datatype + dbBool, ## boolean datatype + dbBlob, ## blob datatype + dbFixedChar, ## string of fixed length + dbVarchar, ## string datatype + dbJson, ## JSON datatype + dbXml, ## XML datatype + dbInt, ## some integer type + dbUInt, ## some unsigned integer type + dbDecimal, ## decimal numbers (fixed-point number) + dbFloat, ## some floating point type + dbDate, ## a year-month-day description + dbTime, ## HH:MM:SS information + dbDatetime, ## year-month-day and HH:MM:SS information, + ## plus optional time or timezone information + dbTimestamp, ## Timestamp values are stored as the number of seconds + ## since the epoch ('1970-01-01 00:00:00' UTC). + dbTimeInterval, ## an interval [a,b] of times + dbEnum, ## some enum + dbSet, ## set of enum values + dbArray, ## an array of values + dbComposite, ## composite type (record, struct, etc) + dbUrl, ## a URL + dbUuid, ## a UUID + dbInet, ## an IP address + dbMacAddress, ## a MAC address + dbGeometry, ## some geometric type + dbPoint, ## Point on a plane (x,y) + dbLine, ## Infinite line ((x1,y1),(x2,y2)) + dbLseg, ## Finite line segment ((x1,y1),(x2,y2)) + dbBox, ## Rectangular box ((x1,y1),(x2,y2)) + dbPath, ## Closed or open path (similar to polygon) ((x1,y1),...) + dbPolygon, ## Polygon (similar to closed path) ((x1,y1),...) + dbCircle, ## Circle <(x,y),r> (center point and radius) + dbUser1, ## user definable datatype 1 (for unknown extensions) + dbUser2, ## user definable datatype 2 (for unknown extensions) + dbUser3, ## user definable datatype 3 (for unknown extensions) + dbUser4, ## user definable datatype 4 (for unknown extensions) + dbUser5 ## user definable datatype 5 (for unknown extensions) + + DbType* = object ## describes a database type + kind*: DbTypeKind ## the kind of the described type + notNull*: bool ## does the type contain NULL? + name*: string ## the name of the type + size*: Natural ## the size of the datatype; 0 if of variable size + maxReprLen*: Natural ## maximal length required for the representation + precision*, scale*: Natural ## precision and scale of the number + min*, max*: BiggestInt ## the minimum and maximum of allowed values + validValues*: seq[string] ## valid values of an enum or a set + + DbColumn* = object ## information about a database column + name*: string ## name of the column + tableName*: string ## name of the table the column belongs to (optional) + typ*: DbType ## type of the column + primaryKey*: bool ## is this a primary key? + foreignKey*: bool ## is this a foreign key? + DbColumns* = seq[DbColumn] + +template sql*(query: string): SqlQuery = + ## constructs a SqlQuery from the string `query`. This is supposed to be + ## used as a raw-string-literal modifier: + ## ``sql"update user set counter = counter + 1"`` + ## + ## If assertions are turned off, it does nothing. If assertions are turned + ## on, later versions will check the string for valid syntax. + SqlQuery(query) + +proc dbError*(msg: string) {.noreturn, noinline.} = + ## raises an DbError exception with message `msg`. + var e: ref DbError + new(e) + e.msg = msg + raise e diff --git a/lib/pure/distros.nim b/lib/pure/distros.nim index 25c961197..63cfe6719 100644 --- a/lib/pure/distros.nim +++ b/lib/pure/distros.nim @@ -9,12 +9,12 @@ ## This module implements the basics for Linux distribution ("distro") ## detection and the OS's native package manager. Its primary purpose is to -## produce output for Nimble packages, like: +## produce output for Nimble packages like:: ## -## To complete the installation, run: +## To complete the installation, run: ## -## sudo apt-get install libblas-dev -## sudo apt-get install libvoodoo +## sudo apt-get libblas-dev +## sudo apt-get libvoodoo ## ## The above output could be the result of a code snippet like: ## @@ -27,16 +27,16 @@ ## ## See `packaging `_ for hints on distributing Nim using OS packages. -from std/strutils import contains, toLowerAscii +from strutils import contains, toLowerAscii when not defined(nimscript): - from std/osproc import execProcess - from std/envvars import existsEnv + from osproc import execProcess + from os import existsEnv type Distribution* {.pure.} = enum ## the list of known distributions Windows ## some version of Windows - Posix ## some POSIX system + Posix ## some Posix system MacOSX ## some version of OSX Linux ## some version of Linux Ubuntu @@ -52,7 +52,6 @@ type CentOS Deepin ArchLinux - Artix Antergos PCLinuxOS Mageia @@ -109,7 +108,7 @@ type Clonezilla SteamOS Absolute - NixOS ## NixOS or a Nix build environment + NixOS ## NixOS or a Nix build environment AUSTRUMI Arya Porteus @@ -124,7 +123,6 @@ type ExTiX Rockstor GoboLinux - Void BSD FreeBSD @@ -136,85 +134,66 @@ type const LacksDevPackages* = {Distribution.Gentoo, Distribution.Slackware, - Distribution.ArchLinux, Distribution.Artix, Distribution.Antergos, - Distribution.BlackArch, Distribution.ArchBang} + Distribution.ArchLinux} -# we cache the result of the 'cmdRelease' +# we cache the result of the 'uname -a' # execution for faster platform detections. -var unameRes, osReleaseIDRes, releaseRes, hostnamectlRes: string +var unameRes, releaseRes, hostnamectlRes: string -template cmdRelease(cmd, cache): untyped = +template unameRelease(cmd, cache): untyped = if cache.len == 0: cache = (when defined(nimscript): gorge(cmd) else: execProcess(cmd)) cache -template uname(): untyped = cmdRelease("uname -a", unameRes) -template osReleaseID(): untyped = cmdRelease("cat /etc/os-release | grep ^ID=", osReleaseIDRes) -template release(): untyped = cmdRelease("lsb_release -d", releaseRes) -template hostnamectl(): untyped = cmdRelease("hostnamectl", hostnamectlRes) - -proc detectOsWithAllCmd(d: Distribution): bool = - let dd = toLowerAscii($d) - result = dd in toLowerAscii(osReleaseID()) or dd in toLowerAscii(release()) or - dd in toLowerAscii(uname()) or ("operating system: " & dd) in - toLowerAscii(hostnamectl()) +template uname(): untyped = unameRelease("uname -a", unameRes) +template release(): untyped = unameRelease("lsb_release -d", releaseRes) +template hostnamectl(): untyped = unameRelease("hostnamectl", hostnamectlRes) proc detectOsImpl(d: Distribution): bool = case d - of Distribution.Windows: result = defined(windows) + of Distribution.Windows: ## some version of Windows + result = defined(windows) of Distribution.Posix: result = defined(posix) of Distribution.MacOSX: result = defined(macosx) of Distribution.Linux: result = defined(linux) + of Distribution.Ubuntu, Distribution.Gentoo, Distribution.FreeBSD, + Distribution.OpenBSD: + result = ("-" & $d & " ") in uname() + of Distribution.RedHat: + result = "Red Hat" in uname() of Distribution.BSD: result = defined(bsd) + of Distribution.ArchLinux: + result = "arch" in toLowerAscii(uname()) + of Distribution.NixOS: + result = existsEnv("NIX_BUILD_TOP") or existsEnv("__NIXOS_SET_ENVIRONMENT_DONE") + # Check if this is a Nix build or NixOS environment + of Distribution.OpenSUSE: + result = "suse" in toLowerAscii(uname()) or "suse" in toLowerAscii(release()) + of Distribution.GoboLinux: + result = "-Gobo " in uname() + of Distribution.OpenMandriva: + result = "mandriva" in toLowerAscii(uname()) + of Distribution.Solaris: + let uname = toLowerAscii(uname()) + result = ("sun" in uname) or ("solaris" in uname) + of Distribution.Haiku: + result = defined(haiku) else: - when defined(bsd): - case d - of Distribution.FreeBSD, Distribution.OpenBSD: - result = $d in uname() - else: - result = false - elif defined(linux): - case d - of Distribution.Gentoo: - result = ("-" & $d & " ") in uname() - of Distribution.Elementary, Distribution.Ubuntu, Distribution.Debian, - Distribution.Fedora, Distribution.OpenMandriva, Distribution.CentOS, - Distribution.Alpine, Distribution.Mageia, Distribution.Zorin, Distribution.Void: - result = toLowerAscii($d) in osReleaseID() - of Distribution.RedHat: - result = "rhel" in osReleaseID() - of Distribution.ArchLinux: - result = "arch" in osReleaseID() - of Distribution.Artix: - result = "artix" in osReleaseID() - of Distribution.NixOS: - # Check if this is a Nix build or NixOS environment - result = existsEnv("NIX_BUILD_TOP") or existsEnv("__NIXOS_SET_ENVIRONMENT_DONE") - of Distribution.OpenSUSE: - result = "suse" in toLowerAscii(uname()) or "suse" in toLowerAscii(release()) - of Distribution.GoboLinux: - result = "-Gobo " in uname() - of Distribution.Solaris: - let uname = toLowerAscii(uname()) - result = ("sun" in uname) or ("solaris" in uname) - of Distribution.Haiku: - result = defined(haiku) - else: - result = detectOsWithAllCmd(d) - else: - result = false + let dd = toLowerAscii($d) + result = dd in toLowerAscii(uname()) or dd in toLowerAscii(release()) or + ("operating system: " & dd) in toLowerAscii(hostnamectl()) template detectOs*(d: untyped): bool = - ## Distro/OS detection. For convenience, the - ## required `Distribution.` qualifier is added to the + ## Distro/OS detection. For convenience the + ## required ``Distribution.`` qualifier is added to the ## enum value. detectOsImpl(Distribution.d) when not defined(nimble): - var foreignDeps*: seq[string] = @[] ## Registered foreign deps. + var foreignDeps: seq[string] = @[] proc foreignCmd*(cmd: string; requiresSudo = false) = - ## Registers a foreign command to the internal list of commands + ## Registers a foreign command to the intern list of commands ## that can be queried later. let c = (if requiresSudo: "sudo " else: "") & cmd when defined(nimble): @@ -223,11 +202,11 @@ proc foreignCmd*(cmd: string; requiresSudo = false) = foreignDeps.add(c) proc foreignDepInstallCmd*(foreignPackageName: string): (string, bool) = - ## Returns the distro's native command to install `foreignPackageName` + ## Returns the distro's native command line to install 'foreignPackageName' ## and whether it requires root/admin rights. let p = foreignPackageName when defined(windows): - result = ("choco install " & p, false) + result = ("Chocolatey install " & p, false) elif defined(bsd): result = ("ports install " & p, true) elif defined(linux): @@ -250,16 +229,12 @@ proc foreignDepInstallCmd*(foreignPackageName: string): (string, bool) = result = ("netpkg install " & p, true) elif detectOs(NixOS): result = ("nix-env -i " & p, false) - elif detectOs(Solaris) or detectOs(FreeBSD): + elif detectOs(Solaris): result = ("pkg install " & p, true) - elif detectOs(OpenBSD): - result = ("pkg_add " & p, true) elif detectOs(PCLinuxOS): result = ("rpm -ivh " & p, true) - elif detectOs(ArchLinux) or detectOs(Manjaro) or detectOs(Artix): + elif detectOs(ArchLinux) or detectOs(Manjaro): result = ("pacman -S " & p, true) - elif detectOs(Void): - result = ("xbps-install " & p, true) else: result = (" install " & p, true) elif defined(haiku): @@ -268,12 +243,17 @@ proc foreignDepInstallCmd*(foreignPackageName: string): (string, bool) = result = ("brew install " & p, false) proc foreignDep*(foreignPackageName: string) = - ## Registers `foreignPackageName` to the internal list of foreign deps. - ## It is your job to ensure that the package name is correct. + ## Registers 'foreignPackageName' to the internal list of foreign deps. + ## It is your job to ensure the package name let (installCmd, sudo) = foreignDepInstallCmd(foreignPackageName) - foreignCmd(installCmd, sudo) + foreignCmd installCmd, sudo proc echoForeignDeps*() = ## Writes the list of registered foreign deps to stdout. for d in foreignDeps: echo d + +when false: + foreignDep("libblas-dev") + foreignDep "libfoo" + echoForeignDeps() diff --git a/lib/pure/dynlib.nim b/lib/pure/dynlib.nim index 48fd91b8f..f31ae94dd 100644 --- a/lib/pure/dynlib.nim +++ b/lib/pure/dynlib.nim @@ -8,8 +8,8 @@ # ## This module implements the ability to access symbols from shared -## libraries. On POSIX this uses the `dlsym` mechanism, on -## Windows `LoadLibrary`. +## libraries. On POSIX this uses the ``dlsym`` mechanism, on +## Windows ``LoadLibrary``. ## ## Examples ## ======== @@ -17,64 +17,75 @@ ## Loading a simple C function ## --------------------------- ## -## The following example demonstrates loading a function called `greet` +## The following example demonstrates loading a function called 'greet' ## from a library that is determined at runtime based upon a language choice. -## If the library fails to load or the function `greet` is not found, +## If the library fails to load or the function 'greet' is not found, ## it quits with a failure error code. ## -runnableExamples: - type - GreetFunction = proc (): cstring {.gcsafe, stdcall.} +## .. code-block::nim +## +## import dynlib +## +## type +## greetFunction = proc(): cstring {.gcsafe, stdcall.} +## +## let lang = stdin.readLine() +## +## let lib = case lang +## of "french": +## loadLib("french.dll") +## else: +## loadLib("english.dll") +## +## if lib == nil: +## echo "Error loading library" +## quit(QuitFailure) +## +## let greet = cast[greetFunction](lib.symAddr("greet")) +## +## if greet == nil: +## echo "Error loading 'greet' function from library" +## quit(QuitFailure) +## +## let greeting = greet() +## +## echo greeting +## +## unloadLib(lib) +## - proc loadGreet(lang: string) = - let lib = - case lang - of "french": - loadLib("french.dll") - else: - loadLib("english.dll") - assert lib != nil, "Error loading library" - - let greet = cast[GreetFunction](lib.symAddr("greet")) - assert greet != nil, "Error loading 'greet' function from library" - - echo greet() - - unloadLib(lib) - - -import std/strutils +import strutils type - LibHandle* = pointer ## A handle to a dynamically loaded library. + LibHandle* = pointer ## a handle to a dynamically loaded library proc loadLib*(path: string, globalSymbols = false): LibHandle {.gcsafe.} - ## Loads a library from `path`. Returns nil if the library could not + ## loads a library from `path`. Returns nil if the library could not ## be loaded. proc loadLib*(): LibHandle {.gcsafe.} - ## Gets the handle from the current executable. Returns nil if the + ## gets the handle from the current executable. Returns nil if the ## library could not be loaded. proc unloadLib*(lib: LibHandle) {.gcsafe.} - ## Unloads the library `lib`. + ## unloads the library `lib` proc raiseInvalidLibrary*(name: cstring) {.noinline, noreturn.} = - ## Raises a `LibraryError` exception. + ## raises an `EInvalidLibrary` exception. raise newException(LibraryError, "could not find symbol: " & $name) proc symAddr*(lib: LibHandle, name: cstring): pointer {.gcsafe.} - ## Retrieves the address of a procedure/variable from `lib`. Returns nil + ## retrieves the address of a procedure/variable from `lib`. Returns nil ## if the symbol could not be found. proc checkedSymAddr*(lib: LibHandle, name: cstring): pointer = - ## Retrieves the address of a procedure/variable from `lib`. Raises - ## `LibraryError` if the symbol could not be found. + ## retrieves the address of a procedure/variable from `lib`. Raises + ## `EInvalidLibrary` if the symbol could not be found. result = symAddr(lib, name) if result == nil: raiseInvalidLibrary(name) proc libCandidates*(s: string, dest: var seq[string]) = - ## Given a library name pattern `s`, write possible library names to `dest`. + ## given a library name pattern `s` write possible library names to `dest`. var le = strutils.find(s, '(') var ri = strutils.find(s, ')', le+1) if le >= 0 and ri > le: @@ -86,10 +97,9 @@ proc libCandidates*(s: string, dest: var seq[string]) = add(dest, s) proc loadLibPattern*(pattern: string, globalSymbols = false): LibHandle = - ## Loads a library with name matching `pattern`, similar to what the `dynlib` + ## loads a library with name matching `pattern`, similar to what `dlimport` ## pragma does. Returns nil if the library could not be loaded. - ## - ## .. warning:: this proc uses the GC and so cannot be used to load the GC. + ## Warning: this proc uses the GC and so cannot be used to load the GC. var candidates = newSeq[string]() libCandidates(pattern, candidates) for c in candidates: @@ -140,32 +150,6 @@ elif defined(nintendoswitch): proc symAddr(lib: LibHandle, name: cstring): pointer = raise newException(OSError, "symAddr not implemented on Nintendo Switch!") -elif defined(genode): - # - # ========================================================================= - # Not implemented for Genode without POSIX. Raise an error if called. - # ========================================================================= - # - - template raiseErr(prc: string) = - raise newException(OSError, prc & " not implemented, compile with POSIX suport") - - proc dlclose(lib: LibHandle) = - raiseErr(OSError, "dlclose") - proc dlopen(path: cstring, mode: int): LibHandle = - raiseErr(OSError, "dlopen") - proc dlsym(lib: LibHandle, name: cstring): pointer = - raiseErr(OSError, "dlsym") - proc loadLib(path: string, global_symbols = false): LibHandle = - raiseErr(OSError, "loadLib") - proc loadLib(): LibHandle = - raiseErr(OSError, "loadLib") - proc unloadLib(lib: LibHandle) = - raiseErr(OSError, "unloadLib") - proc symAddr(lib: LibHandle, name: cstring): pointer = - raiseErr(OSError, "symAddr") - - elif defined(windows) or defined(dos): # # ======================================================================= diff --git a/lib/pure/encodings.nim b/lib/pure/encodings.nim index 0d7e878e5..e3be1764b 100644 --- a/lib/pure/encodings.nim +++ b/lib/pure/encodings.nim @@ -7,46 +7,15 @@ # distribution, for details about the copyright. # -## Routines for converting between different character encodings. On UNIX, this uses +## Converts between different character encodings. On UNIX, this uses ## the `iconv`:idx: library, on Windows the Windows API. -## -## The following example shows how to change character encodings. -runnableExamples: - when defined(windows): - let - orig = "öäüß" - # convert `orig` from "UTF-8" to "CP1252" - cp1252 = convert(orig, "CP1252", "UTF-8") - # convert `cp1252` from "CP1252" to "ibm850" - ibm850 = convert(cp1252, "ibm850", "CP1252") - current = getCurrentEncoding() - assert orig == "\195\182\195\164\195\188\195\159" - assert ibm850 == "\148\132\129\225" - assert convert(ibm850, current, "ibm850") == orig -## The example below uses a reuseable `EncodingConverter` object which is -## created by `open` with `destEncoding` and `srcEncoding` specified. You can use -## `convert` on this object multiple times. -runnableExamples: - when defined(windows): - var fromGB2312 = open("utf-8", "gb2312") - let first = "\203\173\197\194\163\191\210\187" & - "\203\242\209\204\211\234\200\206\198\189\201\250" - assert fromGB2312.convert(first) == "谁怕?一蓑烟雨任平生" - - let second = "\211\208\176\215\205\183\200\231" & - "\208\194\163\172\199\227\184\199\200\231\185\202" - assert fromGB2312.convert(second) == "有白头如新,倾盖如故" - - -import os -when defined(nimPreviewSlimSystem): - import std/assertions +import os, parseutils, strutils when not defined(windows): type ConverterObj = object - EncodingConverter* = ptr ConverterObj ## Can convert between two character sets. + EncodingConverter* = ptr ConverterObj ## can convert between two character sets else: type @@ -55,11 +24,10 @@ else: dest, src: CodePage type - EncodingError* = object of ValueError ## Exception that is raised - ## for encoding errors. + EncodingError* = object of ValueError ## exception that is raised + ## for encoding errors when defined(windows): - import parseutils, strutils proc eqEncodingNames(a, b: string): bool = var i = 0 var j = 0 @@ -103,7 +71,6 @@ when defined(windows): (875, "cp875"), # IBM EBCDIC Greek Modern (932, "shift_jis"), # ANSI/OEM Japanese; Japanese (Shift-JIS) (936, "gb2312"), # ANSI/OEM Simplified Chinese (PRC, Singapore); Chinese Simplified (GB2312) - (936, "gbk"), # Alias for GB2312 encoding (949, "ks_c_5601-1987"), # ANSI/OEM Korean (Unified Hangul Code) (950, "big5"), # ANSI/OEM Traditional Chinese (Taiwan; Hong Kong SAR, PRC); Chinese Traditional (Big5) (1026, "IBM1026"), # IBM EBCDIC Turkish (Latin 5) @@ -313,10 +280,8 @@ else: var errno {.importc, header: "".}: cint - when defined(bsd): + when defined(freebsd) or defined(netbsd): {.pragma: importIconv, cdecl, header: "".} - when defined(openbsd): - {.passL: "-liconv".} else: {.pragma: importIconv, cdecl, dynlib: iconvDll.} @@ -324,12 +289,15 @@ else: importc: "iconv_open", importIconv.} proc iconvClose(c: EncodingConverter) {. importc: "iconv_close", importIconv.} - proc iconv(c: EncodingConverter, inbuf: ptr cstring, inbytesLeft: ptr csize_t, - outbuf: ptr cstring, outbytesLeft: ptr csize_t): csize_t {. + proc iconv(c: EncodingConverter, inbuf: var cstring, inbytesLeft: var int, + outbuf: var cstring, outbytesLeft: var int): int {. + importc: "iconv", importIconv.} + proc iconv(c: EncodingConverter, inbuf: pointer, inbytesLeft: pointer, + outbuf: var cstring, outbytesLeft: var int): int {. importc: "iconv", importIconv.} proc getCurrentEncoding*(uiApp = false): string = - ## Retrieves the current encoding. On Unix, "UTF-8" is always returned. + ## retrieves the current encoding. On Unix, always "UTF-8" is returned. ## The `uiApp` parameter is Windows specific. If true, the UI's code-page ## is returned, if false, the Console's code-page is returned. when defined(windows): @@ -338,8 +306,8 @@ proc getCurrentEncoding*(uiApp = false): string = result = "UTF-8" proc open*(destEncoding = "UTF-8", srcEncoding = "CP1252"): EncodingConverter = - ## Opens a converter that can convert from `srcEncoding` to `destEncoding`. - ## Raises `EncodingError` if it cannot fulfill the request. + ## opens a converter that can convert from `srcEncoding` to `destEncoding`. + ## Raises `IOError` if it cannot fulfill the request. when not defined(windows): result = iconvOpen(destEncoding, srcEncoding) if result == nil: @@ -357,7 +325,7 @@ proc open*(destEncoding = "UTF-8", srcEncoding = "CP1252"): EncodingConverter = "cannot find encoding " & srcEncoding) proc close*(c: EncodingConverter) = - ## Frees the resources the converter `c` holds. + ## frees the resources the converter `c` holds. when not defined(windows): iconvClose(c) @@ -452,22 +420,21 @@ when defined(windows): else: convertFromWideString(codePageTo, wideString) proc convert*(c: EncodingConverter, s: string): string = + ## converts `s` to `destEncoding` that was given to the converter `c`. It + ## assumed that `s` is in `srcEncoding`. + ## utf-16BE, utf-32 conversions not supported on windows result = convertWin(c.src, c.dest, s) else: proc convert*(c: EncodingConverter, s: string): string = - ## Converts `s` to `destEncoding` that was given to the converter `c`. It - ## assumes that `s` is in `srcEncoding`. - ## - ## .. warning:: UTF-16BE and UTF-32 conversions are not supported on Windows. result = newString(s.len) - var inLen = csize_t len(s) - var outLen = csize_t len(result) + var inLen = len(s) + var outLen = len(result) var src = cstring(s) var dst = cstring(result) - var iconvres: csize_t + var iconvres: int while inLen > 0: - iconvres = iconv(c, addr src, addr inLen, addr dst, addr outLen) - if iconvres == high(csize_t): + iconvres = iconv(c, src, inLen, dst, outLen) + if iconvres == -1: var lerr = errno if lerr == EILSEQ or lerr == EINVAL: # unknown char, skip @@ -478,34 +445,105 @@ else: dec(outLen) elif lerr == E2BIG: var offset = cast[int](dst) - cast[int](cstring(result)) - setLen(result, len(result) + inLen.int * 2 + 5) + setLen(result, len(result)+inLen*2+5) # 5 is minimally one utf-8 char dst = cast[cstring](cast[int](cstring(result)) + offset) - outLen = csize_t(len(result) - offset) + outLen = len(result) - offset else: raiseOSError(lerr.OSErrorCode) # iconv has a buffer that needs flushing, specially if the last char is # not '\0' - discard iconv(c, nil, nil, addr dst, addr outLen) - if iconvres == high(csize_t) and errno == E2BIG: + discard iconv(c, nil, nil, dst, outLen) + if iconvres == cint(-1) and errno == E2BIG: var offset = cast[int](dst) - cast[int](cstring(result)) - setLen(result, len(result) + inLen.int * 2 + 5) + setLen(result, len(result)+inLen*2+5) # 5 is minimally one utf-8 char dst = cast[cstring](cast[int](cstring(result)) + offset) - outLen = csize_t(len(result) - offset) - discard iconv(c, nil, nil, addr dst, addr outLen) + outLen = len(result) - offset + discard iconv(c, nil, nil, dst, outLen) # trim output buffer - setLen(result, len(result) - outLen.int) + setLen(result, len(result) - outLen) proc convert*(s: string, destEncoding = "UTF-8", srcEncoding = "CP1252"): string = - ## Converts `s` to `destEncoding`. It assumed that `s` is in `srcEncoding`. + ## converts `s` to `destEncoding`. It assumed that `s` is in `srcEncoding`. ## This opens a converter, uses it and closes it again and is thus more ## convenient but also likely less efficient than re-using a converter. - ## - ## .. warning:: UTF-16BE and UTF-32 conversions are not supported on Windows. + ## utf-16BE, utf-32 conversions not supported on windows var c = open(destEncoding, srcEncoding) try: result = convert(c, s) finally: close(c) + +when not defined(testing) and isMainModule: + let + orig = "öäüß" + cp1252 = convert(orig, "CP1252", "UTF-8") + ibm850 = convert(cp1252, "ibm850", "CP1252") + current = getCurrentEncoding() + echo "Original string from source code: ", orig + echo "Forced ibm850 encoding: ", ibm850 + echo "Current encoding: ", current + echo "From ibm850 to current: ", convert(ibm850, current, "ibm850") + +when not defined(testing) and isMainModule and defined(windows): + block should_throw_on_unsupported_conversions: + let original = "some string" + + doAssertRaises(EncodingError): + discard convert(original, "utf-8", "utf-32") + + doAssertRaises(EncodingError): + discard convert(original, "utf-8", "unicodeFFFE") + + doAssertRaises(EncodingError): + discard convert(original, "utf-8", "utf-32BE") + + doAssertRaises(EncodingError): + discard convert(original, "unicodeFFFE", "utf-8") + + doAssertRaises(EncodingError): + discard convert(original, "utf-32", "utf-8") + + doAssertRaises(EncodingError): + discard convert(original, "utf-32BE", "utf-8") + + block should_convert_from_utf16_to_utf8: + let original = "\x42\x04\x35\x04\x41\x04\x42\x04" # utf-16 little endian test string "тест" + let result = convert(original, "utf-8", "utf-16") + doAssert(result == "\xd1\x82\xd0\xb5\xd1\x81\xd1\x82") + + block should_convert_from_utf16_to_win1251: + let original = "\x42\x04\x35\x04\x41\x04\x42\x04" # utf-16 little endian test string "тест" + let result = convert(original, "windows-1251", "utf-16") + doAssert(result == "\xf2\xe5\xf1\xf2") + + block should_convert_from_win1251_to_koi8r: + let original = "\xf2\xe5\xf1\xf2" # win1251 test string "тест" + let result = convert(original, "koi8-r", "windows-1251") + doAssert(result == "\xd4\xc5\xd3\xd4") + + block should_convert_from_koi8r_to_win1251: + let original = "\xd4\xc5\xd3\xd4" # koi8r test string "тест" + let result = convert(original, "windows-1251", "koi8-r") + doAssert(result == "\xf2\xe5\xf1\xf2") + + block should_convert_from_utf8_to_win1251: + let original = "\xd1\x82\xd0\xb5\xd1\x81\xd1\x82" # utf-8 test string "тест" + let result = convert(original, "windows-1251", "utf-8") + doAssert(result == "\xf2\xe5\xf1\xf2") + + block should_convert_from_utf8_to_utf16: + let original = "\xd1\x82\xd0\xb5\xd1\x81\xd1\x82" # utf-8 test string "тест" + let result = convert(original, "utf-16", "utf-8") + doAssert(result == "\x42\x04\x35\x04\x41\x04\x42\x04") + + block should_handle_empty_string_for_any_conversion: + let original = "" + var result = convert(original, "utf-16", "utf-8") + doAssert(result == "") + result = convert(original, "utf-8", "utf-16") + doAssert(result == "") + result = convert(original, "windows-1251", "koi8-r") + doAssert(result == "") diff --git a/lib/pure/endians.nim b/lib/pure/endians.nim index a0dc97c1d..29fde1c80 100644 --- a/lib/pure/endians.nim +++ b/lib/pure/endians.nim @@ -10,11 +10,6 @@ ## This module contains helpers that deal with different byte orders ## (`endian`:idx:). ## -## Endianess is the order of bytes of a value in memory. Big-endian means that -## the most significant byte is stored at the smallest memory address, -## while little endian means that the least-significant byte is stored -## at the smallest address. See also https://en.wikipedia.org/wiki/Endianness. -## ## Unstable API. when defined(gcc) or defined(llvm_gcc) or defined(clang): @@ -52,7 +47,7 @@ else: when useBuiltinSwap: template swapOpImpl(T: typedesc, op: untyped) = - ## We have to use `copyMem` here instead of a simple dereference because they + ## We have to use `copyMem` here instead of a simple deference because they ## may point to a unaligned address. A sufficiently smart compiler _should_ ## be able to elide them when they're not necessary. var tmp: T @@ -61,40 +56,18 @@ when useBuiltinSwap: copyMem(outp, addr tmp, sizeof(T)) proc swapEndian64*(outp, inp: pointer) {.inline, noSideEffect.} = - ## Copies `inp` to `outp`, reversing the byte order. - ## Both buffers are supposed to contain at least 8 bytes. - runnableExamples: - var a = [1'u8, 2, 3, 4, 5, 6, 7, 8] - var b: array[8, uint8] - swapEndian64(addr b, addr a) - assert b == [8'u8, 7, 6, 5, 4, 3, 2, 1] - swapOpImpl(uint64, builtin_bswap64) proc swapEndian32*(outp, inp: pointer) {.inline, noSideEffect.} = - ## Copies `inp` to `outp`, reversing the byte order. - ## Both buffers are supposed to contain at least 4 bytes. - runnableExamples: - var a = [1'u8, 2, 3, 4] - var b: array[4, uint8] - swapEndian32(addr b, addr a) - assert b == [4'u8, 3, 2, 1] - swapOpImpl(uint32, builtin_bswap32) proc swapEndian16*(outp, inp: pointer) {.inline, noSideEffect.} = - ## Copies `inp` to `outp`, reversing the byte order. - ## Both buffers are supposed to contain at least 2 bytes. - runnableExamples: - var a = [1'u8, 2] - var b: array[2, uint8] - swapEndian16(addr b, addr a) - assert b == [2'u8, 1] - swapOpImpl(uint16, builtin_bswap16) else: proc swapEndian64*(outp, inp: pointer) = + ## copies `inp` to `outp` swapping bytes. Both buffers are supposed to + ## contain at least 8 bytes. var i = cast[cstring](inp) var o = cast[cstring](outp) o[0] = i[7] @@ -107,6 +80,8 @@ else: o[7] = i[0] proc swapEndian32*(outp, inp: pointer) = + ## copies `inp` to `outp` swapping bytes. Both buffers are supposed to + ## contain at least 4 bytes. var i = cast[cstring](inp) var o = cast[cstring](outp) o[0] = i[3] @@ -115,6 +90,8 @@ else: o[3] = i[0] proc swapEndian16*(outp, inp: pointer) = + ## copies `inp` to `outp` swapping bytes. Both buffers are supposed to + ## contain at least 2 bytes. var i = cast[cstring](inp) var o = cast[cstring](outp) o[0] = i[1] @@ -129,20 +106,8 @@ when system.cpuEndian == bigEndian: proc bigEndian16*(outp, inp: pointer) {.inline.} = copyMem(outp, inp, 2) else: proc littleEndian64*(outp, inp: pointer) {.inline.} = copyMem(outp, inp, 8) - ## Copies `inp` to `outp`, storing it in 64-bit little-endian order. - ## Both buffers are supposed to contain at least 8 bytes. proc littleEndian32*(outp, inp: pointer) {.inline.} = copyMem(outp, inp, 4) - ## Copies `inp` to `outp`, storing it in 32-bit little-endian order. - ## Both buffers are supposed to contain at least 4 bytes. proc littleEndian16*(outp, inp: pointer){.inline.} = copyMem(outp, inp, 2) - ## Copies `inp` to `outp`, storing it in 16-bit little-endian order. - ## Both buffers are supposed to contain at least 2 bytes. proc bigEndian64*(outp, inp: pointer) {.inline.} = swapEndian64(outp, inp) - ## Copies `inp` to `outp`, storing it in 64-bit big-endian order. - ## Both buffers are supposed to contain at least 8 bytes. proc bigEndian32*(outp, inp: pointer) {.inline.} = swapEndian32(outp, inp) - ## Copies `inp` to `outp`, storing it in 32-bit big-endian order. - ## Both buffers are supposed to contain at least 4 bytes. proc bigEndian16*(outp, inp: pointer) {.inline.} = swapEndian16(outp, inp) - ## Copies `inp` to `outp`, storing it in 16-bit big-endian order. - ## Both buffers are supposed to contain at least 2 bytes. diff --git a/lib/pure/fenv.nim b/lib/pure/fenv.nim index ddb6a1a0c..6da6aedad 100644 --- a/lib/pure/fenv.nim +++ b/lib/pure/fenv.nim @@ -9,10 +9,10 @@ ## Floating-point environment. Handling of floating-point rounding and ## exceptions (overflow, division by zero, etc.). -## The types, vars and procs are bindings for the C standard library -## [](https://en.cppreference.com/w/c/numeric/fenv) header. -when defined(posix) and not defined(genode): +{.deadCodeElim: on.} # dce option deprecated + +when defined(Posix) and not defined(genode): {.passl: "-lm".} var @@ -37,8 +37,8 @@ var FE_UPWARD* {.importc, header: "".}: cint ## round toward +Inf FE_DFL_ENV* {.importc, header: "".}: cint - ## macro of type pointer to `fenv_t` to be used as the argument - ## to functions taking an argument of type `fenv_t`; in this + ## macro of type pointer to fenv_t to be used as the argument + ## to functions taking an argument of type fenv_t; in this ## case the default environment will be used type @@ -130,7 +130,7 @@ template fpRadix*: int = FLT_RADIX ## point type on the architecture used to build the program. template mantissaDigits*(T: typedesc[float32]): int = FLT_MANT_DIG - ## Number of digits (in base `floatingPointRadix`) in the mantissa + ## Number of digits (in base ``floatingPointRadix``) in the mantissa ## of 32-bit floating-point numbers. template digits*(T: typedesc[float32]): int = FLT_DIG ## Number of decimal digits that can be represented in a @@ -156,7 +156,7 @@ template epsilon*(T: typedesc[float32]): float32 = FLT_EPSILON ## 1.0 that can be represented in a 32-bit floating-point type. template mantissaDigits*(T: typedesc[float64]): int = DBL_MANT_DIG - ## Number of digits (in base `floatingPointRadix`) in the mantissa + ## Number of digits (in base ``floatingPointRadix``) in the mantissa ## of 64-bit floating-point numbers. template digits*(T: typedesc[float64]): int = DBL_DIG ## Number of decimal digits that can be represented in a @@ -180,3 +180,11 @@ template maximumPositiveValue*(T: typedesc[float64]): float64 = DBL_MAX template epsilon*(T: typedesc[float64]): float64 = DBL_EPSILON ## The difference between 1.0 and the smallest number greater than ## 1.0 that can be represented in a 64-bit floating-point type. + + +when isMainModule: + func is_significant(x: float): bool = + if x > minimumPositiveValue(float) and x < maximumPositiveValue(float): true + else: false + + doAssert is_significant(10.0) diff --git a/lib/pure/future.nim b/lib/pure/future.nim new file mode 100644 index 000000000..40dba7846 --- /dev/null +++ b/lib/pure/future.nim @@ -0,0 +1,4 @@ + +{.deprecated: "Use the new 'sugar' module instead".} + +include sugar diff --git a/lib/pure/hashes.nim b/lib/pure/hashes.nim index 4ae4938c6..ac8498517 100644 --- a/lib/pure/hashes.nim +++ b/lib/pure/hashes.nim @@ -10,76 +10,49 @@ ## This module implements efficient computations of hash values for diverse ## Nim types. All the procs are based on these two building blocks: ## - `!& proc <#!&,Hash,int>`_ used to start or mix a hash value, and -## - `!$ proc <#!$,Hash>`_ used to finish the hash value. +## - `!$ proc <#!$,Hash>`_ used to *finish* the hash value. ## ## If you want to implement hash procs for your custom types, ## you will end up writing the following kind of skeleton of code: - -runnableExamples: - type - Something = object - foo: int - bar: string - - iterator items(x: Something): Hash = - yield hash(x.foo) - yield hash(x.bar) - - proc hash(x: Something): Hash = - ## Computes a Hash from `x`. - var h: Hash = 0 - # Iterate over parts of `x`. - for xAtom in x: - # Mix the atom with the partial hash. - h = h !& xAtom - # Finish the hash. - result = !$h - -## If your custom types contain fields for which there already is a `hash` proc, -## you can simply hash together the hash values of the individual fields: - -runnableExamples: - type - Something = object - foo: int - bar: string - - proc hash(x: Something): Hash = - ## Computes a Hash from `x`. - var h: Hash = 0 - h = h !& hash(x.foo) - h = h !& hash(x.bar) - result = !$h - -## .. important:: Use `-d:nimPreviewHashRef` to -## enable hashing `ref`s. It is expected that this behavior -## becomes the new default in upcoming versions. ## -## .. note:: If the type has a `==` operator, the following must hold: -## If two values compare equal, their hashes must also be equal. +## .. code-block:: Nim +## proc hash(x: Something): Hash = +## ## Computes a Hash from `x`. +## var h: Hash = 0 +## # Iterate over parts of `x`. +## for xAtom in x: +## # Mix the atom with the partial hash. +## h = h !& xAtom +## # Finish the hash. +## result = !$h ## -## See also -## ======== -## * `md5 module `_ for the MD5 checksum algorithm -## * `base64 module `_ for a Base64 encoder and decoder -## * `std/sha1 module `_ for the SHA-1 checksum algorithm +## If your custom types contain fields for which there already is a hash proc, +## like for example objects made up of ``strings``, you can simply hash +## together the hash value of the individual fields: +## +## .. code-block:: Nim +## proc hash(x: Something): Hash = +## ## Computes a Hash from `x`. +## var h: Hash = 0 +## h = h !& hash(x.foo) +## h = h !& hash(x.bar) +## result = !$h +## +## **See also:** +## * `md5 module `_ for MD5 checksum algorithm +## * `base64 module `_ for a base64 encoder and decoder +## * `std/sha1 module `_ for a sha1 encoder and decoder ## * `tables module `_ for hash tables -import std/private/since - -when defined(nimPreviewSlimSystem): - import std/assertions - - type Hash* = int ## A hash value. Hash tables using these values should - ## always have a size of a power of two so they can use the `and` - ## operator instead of `mod` for truncation of the hash value. + ## always have a size of a power of two and can use the ``and`` + ## operator instead of ``mod`` for truncation of the hash value. proc `!&`*(h: Hash, val: int): Hash {.inline.} = ## Mixes a hash value `h` with `val` to produce a new hash value. ## - ## This is only needed if you need to implement a `hash` proc for a new datatype. + ## This is only needed if you need to implement a hash proc for a new datatype. let h = cast[uint](h) let val = cast[uint](val) var res = h + val @@ -90,107 +63,19 @@ proc `!&`*(h: Hash, val: int): Hash {.inline.} = proc `!$`*(h: Hash): Hash {.inline.} = ## Finishes the computation of the hash value. ## - ## This is only needed if you need to implement a `hash` proc for a new datatype. + ## This is only needed if you need to implement a hash proc for a new datatype. let h = cast[uint](h) # Hash is practically unsigned. var res = h + h shl 3 res = res xor (res shr 11) res = res + res shl 15 result = cast[Hash](res) -proc hiXorLoFallback64(a, b: uint64): uint64 {.inline.} = - let # Fall back in 64-bit arithmetic - aH = a shr 32 - aL = a and 0xFFFFFFFF'u64 - bH = b shr 32 - bL = b and 0xFFFFFFFF'u64 - rHH = aH * bH - rHL = aH * bL - rLH = aL * bH - rLL = aL * bL - t = rLL + (rHL shl 32) - var c = if t < rLL: 1'u64 else: 0'u64 - let lo = t + (rLH shl 32) - c += (if lo < t: 1'u64 else: 0'u64) - let hi = rHH + (rHL shr 32) + (rLH shr 32) + c - return hi xor lo - -proc hiXorLo(a, b: uint64): uint64 {.inline.} = - # XOR of the high & low 8 bytes of the full 16 byte product. - when nimvm: - result = hiXorLoFallback64(a, b) # `result =` is necessary here. - else: - when Hash.sizeof < 8: - result = hiXorLoFallback64(a, b) - elif defined(gcc) or defined(llvm_gcc) or defined(clang): - {.emit: """__uint128_t r = `a`; r *= `b`; `result` = (r >> 64) ^ r;""".} - elif defined(windows) and not defined(tcc): - proc umul128(a, b: uint64, c: ptr uint64): uint64 {.importc: "_umul128", header: "intrin.h".} - var b = b - let c = umul128(a, b, addr b) - result = c xor b - else: - result = hiXorLoFallback64(a, b) - -when defined(js): - import std/jsbigints - import std/private/jsutils - - proc hiXorLoJs(a, b: JsBigInt): JsBigInt = - let - prod = a * b - mask = big"0xffffffffffffffff" # (big"1" shl big"64") - big"1" - result = (prod shr big"64") xor (prod and mask) - - template hashWangYiJS(x: JsBigInt): Hash = - let - P0 = big"0xa0761d6478bd642f" - P1 = big"0xe7037ed1a0b428db" - P58 = big"0xeb44accab455d16d" # big"0xeb44accab455d165" xor big"8" - res = hiXorLoJs(hiXorLoJs(P0, x xor P1), P58) - cast[Hash](toNumber(wrapToInt(res, 32))) - - template toBits(num: float): JsBigInt = - let - x = newArrayBuffer(8) - y = newFloat64Array(x) - if hasBigUint64Array(): - let z = newBigUint64Array(x) - y[0] = num - z[0] - else: - let z = newUint32Array(x) - y[0] = num - big(z[0]) + big(z[1]) shl big(32) - -proc hashWangYi1*(x: int64|uint64|Hash): Hash {.inline.} = - ## Wang Yi's hash_v1 for 64-bit ints (see https://github.com/rurban/smhasher for - ## more details). This passed all scrambling tests in Spring 2019 and is simple. - ## - ## **Note:** It's ok to define `proc(x: int16): Hash = hashWangYi1(Hash(x))`. - const P0 = 0xa0761d6478bd642f'u64 - const P1 = 0xe7037ed1a0b428db'u64 - const P58 = 0xeb44accab455d165'u64 xor 8'u64 - template h(x): untyped = hiXorLo(hiXorLo(P0, uint64(x) xor P1), P58) - when nimvm: - when defined(js): # Nim int64<->JS Number & VM match => JS gets 32-bit hash - result = cast[Hash](h(x)) and cast[Hash](0xFFFFFFFF) - else: - result = cast[Hash](h(x)) - else: - when defined(js): - if hasJsBigInt(): - result = hashWangYiJS(big(x)) - else: - result = cast[Hash](x) and cast[Hash](0xFFFFFFFF) - else: - result = cast[Hash](h(x)) - proc hashData*(data: pointer, size: int): Hash = ## Hashes an array of bytes of size `size`. var h: Hash = 0 when defined(js): var p: cstring - asm """`p` = `Data`""" + asm """`p` = `Data`;""" else: var p = cast[cstring](data) var i = 0 @@ -201,22 +86,12 @@ proc hashData*(data: pointer, size: int): Hash = dec(s) result = !$h -proc hashIdentity*[T: Ordinal|enum](x: T): Hash {.inline, since: (1, 3).} = - ## The identity hash, i.e. `hashIdentity(x) = x`. - cast[Hash](ord(x)) - -when defined(nimIntHash1): - proc hash*[T: Ordinal|enum](x: T): Hash {.inline.} = - ## Efficient hashing of integers. - cast[Hash](ord(x)) -else: - proc hash*[T: Ordinal|enum](x: T): Hash {.inline.} = - ## Efficient hashing of integers. - hashWangYi1(uint64(ord(x))) - when defined(js): var objectID = 0 - proc getObjectId(x: pointer): int = + +proc hash*(x: pointer): Hash {.inline.} = + ## Efficient hashing of pointers. + when defined(js): asm """ if (typeof `x` == "object") { if ("_NimID" in `x`) @@ -227,59 +102,48 @@ when defined(js): } } """ - -proc hash*(x: pointer): Hash {.inline.} = - ## Efficient `hash` overload. - when defined(js): - let y = getObjectId(x) else: - let y = cast[int](x) - hash(y) # consistent with code expecting scrambled hashes depending on `nimIntHash1`. + result = cast[Hash](cast[uint](x) shr 3) # skip the alignment -proc hash*[T](x: ptr[T]): Hash {.inline.} = - ## Efficient `hash` overload. - runnableExamples: - var a: array[10, uint8] - assert a[0].addr.hash != a[1].addr.hash - assert cast[pointer](a[0].addr).hash == a[0].addr.hash - hash(cast[pointer](x)) +proc hash*[T: proc](x: T): Hash {.inline.} = + ## Efficient hashing of proc vars. Closures are supported too. + when T is "closure": + result = hash(rawProc(x)) !& hash(rawEnv(x)) + else: + result = hash(pointer(x)) -when defined(nimPreviewHashRef) or defined(nimdoc): - proc hash*[T](x: ref[T]): Hash {.inline.} = - ## Efficient `hash` overload. - ## - ## .. important:: Use `-d:nimPreviewHashRef` to - ## enable hashing `ref`s. It is expected that this behavior - ## becomes the new default in upcoming versions. - runnableExamples("-d:nimPreviewHashRef"): - type A = ref object - x: int - let a = A(x: 3) - let ha = a.hash - assert ha != A(x: 3).hash # A(x: 3) is a different ref object from `a`. - a.x = 4 - assert ha == a.hash # the hash only depends on the address - runnableExamples("-d:nimPreviewHashRef"): - # you can overload `hash` if you want to customize semantics - type A[T] = ref object - x, y: T - proc hash(a: A): Hash = hash(a.x) - assert A[int](x: 3, y: 4).hash == A[int](x: 3, y: 5).hash - # xxx pending bug #17733, merge as `proc hash*(pointer | ref | ptr): Hash` - # or `proc hash*[T: ref | ptr](x: T): Hash` - hash(cast[pointer](x)) +const + prime = uint(11) + +proc hash*(x: int): Hash {.inline.} = + ## Efficient hashing of integers. + result = cast[Hash](cast[uint](x) * prime) + +proc hash*(x: int64): Hash {.inline.} = + ## Efficient hashing of `int64` integers. + result = cast[Hash](cast[uint](x) * prime) + +proc hash*(x: uint): Hash {.inline.} = + ## Efficient hashing of unsigned integers. + result = cast[Hash](x * prime) + +proc hash*(x: uint64): Hash {.inline.} = + ## Efficient hashing of `uint64` integers. + result = cast[Hash](cast[uint](x) * prime) + +proc hash*(x: char): Hash {.inline.} = + ## Efficient hashing of characters. + result = cast[Hash](cast[uint](ord(x)) * prime) + +proc hash*[T: Ordinal](x: T): Hash {.inline.} = + ## Efficient hashing of other ordinal types (e.g. enums). + result = cast[Hash](cast[uint](ord(x)) * prime) proc hash*(x: float): Hash {.inline.} = ## Efficient hashing of floats. - let y = x + 0.0 # for denormalization - when nimvm: - # workaround a JS VM bug: bug #16547 - result = hashWangYi1(cast[int64](float64(y))) - else: - when not defined(js): - result = hashWangYi1(cast[Hash](y)) - else: - result = hashWangYiJS(toBits(y)) + var y = x + 1.0 + result = cast[ptr Hash](addr(y))[] + # Forward declarations before methods that hash containers. This allows # containers to contain other containers @@ -322,7 +186,7 @@ proc murmurHash(x: openArray[byte]): Hash = # body while i < n * stepSize: var k1: uint32 - when defined(js) or defined(sparc) or defined(sparc64): + when defined(js): var j = stepSize while j > 0: dec j @@ -359,9 +223,6 @@ proc murmurHash(x: openArray[byte]): Hash = h1 = h1 xor (h1 shr 16) return cast[Hash](h1) -proc hashVmImpl(x: cstring, sPos, ePos: int): Hash = - doAssert false, "implementation override in compiler/vmops.nim" - proc hashVmImpl(x: string, sPos, ePos: int): Hash = doAssert false, "implementation override in compiler/vmops.nim" @@ -374,16 +235,22 @@ proc hashVmImplByte(x: openArray[byte], sPos, ePos: int): Hash = proc hash*(x: string): Hash = ## Efficient hashing of strings. ## - ## **See also:** + ## See also: ## * `hashIgnoreStyle <#hashIgnoreStyle,string>`_ ## * `hashIgnoreCase <#hashIgnoreCase,string>`_ runnableExamples: doAssert hash("abracadabra") != hash("AbracadabrA") - when nimvm: - result = hashVmImpl(x, 0, high(x)) + when not defined(nimToOpenArrayCString): + result = 0 + for c in x: + result = result !& ord(c) + result = !$result else: - result = murmurHash(toOpenArrayByte(x, 0, high(x))) + when nimvm: + result = hashVmImpl(x, 0, high(x)) + else: + result = murmurHash(toOpenArrayByte(x, 0, high(x))) proc hash*(x: cstring): Hash = ## Efficient hashing of null-terminated strings. @@ -392,10 +259,15 @@ proc hash*(x: cstring): Hash = doAssert hash(cstring"AbracadabrA") == hash("AbracadabrA") doAssert hash(cstring"abracadabra") != hash(cstring"AbracadabrA") - when nimvm: - hashVmImpl(x, 0, high(x)) + when not defined(nimToOpenArrayCString): + result = 0 + var i = 0 + while x[i] != '\0': + result = result !& ord(x[i]) + inc i + result = !$result else: - when not defined(js): + when not defined(js) and defined(nimToOpenArrayCString): murmurHash(toOpenArrayByte(x, 0, x.high)) else: let xx = $x @@ -405,19 +277,25 @@ proc hash*(sBuf: string, sPos, ePos: int): Hash = ## Efficient hashing of a string buffer, from starting ## position `sPos` to ending position `ePos` (included). ## - ## `hash(myStr, 0, myStr.high)` is equivalent to `hash(myStr)`. + ## ``hash(myStr, 0, myStr.high)`` is equivalent to ``hash(myStr)``. runnableExamples: var a = "abracadabra" doAssert hash(a, 0, 3) == hash(a, 7, 10) - murmurHash(toOpenArrayByte(sBuf, sPos, ePos)) + when not defined(nimToOpenArrayCString): + result = 0 + for i in sPos..ePos: + result = result !& ord(sBuf[i]) + result = !$result + else: + murmurHash(toOpenArrayByte(sBuf, sPos, ePos)) proc hashIgnoreStyle*(x: string): Hash = ## Efficient hashing of strings; style is ignored. ## - ## **Note:** This uses a different hashing algorithm than `hash(string)`. + ## **Note:** This uses different hashing algorithm than `hash(string)`. ## - ## **See also:** + ## See also: ## * `hashIgnoreCase <#hashIgnoreCase,string>`_ runnableExamples: doAssert hashIgnoreStyle("aBr_aCa_dAB_ra") == hashIgnoreStyle("abracadabra") @@ -441,10 +319,10 @@ proc hashIgnoreStyle*(sBuf: string, sPos, ePos: int): Hash = ## Efficient hashing of a string buffer, from starting ## position `sPos` to ending position `ePos` (included); style is ignored. ## - ## **Note:** This uses a different hashing algorithm than `hash(string)`. + ## **Note:** This uses different hashing algorithm than `hash(string)`. ## - ## `hashIgnoreStyle(myBuf, 0, myBuf.high)` is equivalent - ## to `hashIgnoreStyle(myBuf)`. + ## ``hashIgnoreStyle(myBuf, 0, myBuf.high)`` is equivalent + ## to ``hashIgnoreStyle(myBuf)``. runnableExamples: var a = "ABracada_b_r_a" doAssert hashIgnoreStyle(a, 0, 3) == hashIgnoreStyle(a, 7, a.high) @@ -465,9 +343,9 @@ proc hashIgnoreStyle*(sBuf: string, sPos, ePos: int): Hash = proc hashIgnoreCase*(x: string): Hash = ## Efficient hashing of strings; case is ignored. ## - ## **Note:** This uses a different hashing algorithm than `hash(string)`. + ## **Note:** This uses different hashing algorithm than `hash(string)`. ## - ## **See also:** + ## See also: ## * `hashIgnoreStyle <#hashIgnoreStyle,string>`_ runnableExamples: doAssert hashIgnoreCase("ABRAcaDABRA") == hashIgnoreCase("abRACAdabra") @@ -485,10 +363,10 @@ proc hashIgnoreCase*(sBuf: string, sPos, ePos: int): Hash = ## Efficient hashing of a string buffer, from starting ## position `sPos` to ending position `ePos` (included); case is ignored. ## - ## **Note:** This uses a different hashing algorithm than `hash(string)`. + ## **Note:** This uses different hashing algorithm than `hash(string)`. ## - ## `hashIgnoreCase(myBuf, 0, myBuf.high)` is equivalent - ## to `hashIgnoreCase(myBuf)`. + ## ``hashIgnoreCase(myBuf, 0, myBuf.high)`` is equivalent + ## to ``hashIgnoreCase(myBuf)``. runnableExamples: var a = "ABracadabRA" doAssert hashIgnoreCase(a, 0, 3) == hashIgnoreCase(a, 7, 10) @@ -501,49 +379,16 @@ proc hashIgnoreCase*(sBuf: string, sPos, ePos: int): Hash = h = h !& ord(c) result = !$h -proc hash*[T: tuple | object | proc](x: T): Hash = - ## Efficient `hash` overload. - runnableExamples: - # for `tuple|object`, `hash` must be defined for each component of `x`. - type Obj = object - x: int - y: string - type Obj2[T] = object - x: int - y: string - assert hash(Obj(x: 520, y: "Nim")) != hash(Obj(x: 520, y: "Nim2")) - # you can define custom hashes for objects (even if they're generic): - proc hash(a: Obj2): Hash = hash((a.x)) - assert hash(Obj2[float](x: 520, y: "Nim")) == hash(Obj2[float](x: 520, y: "Nim2")) - runnableExamples: - # proc - proc fn1() = discard - const fn1b = fn1 - assert hash(fn1b) == hash(fn1) - # closure - proc outer = - var a = 0 - proc fn2() = a.inc - assert fn2 is "closure" - let fn2b = fn2 - assert hash(fn2b) == hash(fn2) - assert hash(fn2) != hash(fn1) - outer() +proc hash*[T: tuple](x: T): Hash = + ## Efficient hashing of tuples. + for f in fields(x): + result = result !& hash(f) + result = !$result - when T is "closure": - result = hash((rawProc(x), rawEnv(x))) - elif T is (proc): - result = hash(pointer(x)) - else: - result = 0 - for f in fields(x): - result = result !& hash(f) - result = !$result proc hash*[A](x: openArray[A]): Hash = ## Efficient hashing of arrays and sequences. - ## There must be a `hash` proc defined for the element type `A`. when A is byte: result = murmurHash(x) elif A is char: @@ -552,7 +397,6 @@ proc hash*[A](x: openArray[A]): Hash = else: result = murmurHash(toOpenArrayByte(x, 0, x.high)) else: - result = 0 for a in x: result = result !& hash(a) result = !$result @@ -560,9 +404,8 @@ proc hash*[A](x: openArray[A]): Hash = proc hash*[A](aBuf: openArray[A], sPos, ePos: int): Hash = ## Efficient hashing of portions of arrays and sequences, from starting ## position `sPos` to ending position `ePos` (included). - ## There must be a `hash` proc defined for the element type `A`. ## - ## `hash(myBuf, 0, myBuf.high)` is equivalent to `hash(myBuf)`. + ## ``hash(myBuf, 0, myBuf.high)`` is equivalent to ``hash(myBuf)``. runnableExamples: let a = [1, 2, 5, 1, 2, 6] doAssert hash(a, 0, 1) == hash(a, 3, 4) @@ -584,8 +427,49 @@ proc hash*[A](aBuf: openArray[A], sPos, ePos: int): Hash = proc hash*[A](x: set[A]): Hash = ## Efficient hashing of sets. - ## There must be a `hash` proc defined for the element type `A`. - result = 0 for it in items(x): result = result !& hash(it) result = !$result + + +when isMainModule: + block empty: + var + a = "" + b = newSeq[char]() + c = newSeq[int]() + d = cstring"" + e = "abcd" + doAssert hash(a) == 0 + doAssert hash(b) == 0 + doAssert hash(c) == 0 + doAssert hash(d) == 0 + doAssert hashIgnoreCase(a) == 0 + doAssert hashIgnoreStyle(a) == 0 + doAssert hash(e, 3, 2) == 0 + block sameButDifferent: + doAssert hash("aa bb aaaa1234") == hash("aa bb aaaa1234", 0, 13) + doAssert hash("aa bb aaaa1234") == hash(cstring"aa bb aaaa1234") + doAssert hashIgnoreCase("aA bb aAAa1234") == hashIgnoreCase("aa bb aaaa1234") + doAssert hashIgnoreStyle("aa_bb_AAaa1234") == hashIgnoreCase("aaBBAAAa1234") + block smallSize: # no multibyte hashing + let + xx = @['H', 'i'] + ii = @[72'u8, 105] + ss = "Hi" + doAssert hash(xx) == hash(ii) + doAssert hash(xx) == hash(ss) + doAssert hash(xx) == hash(xx, 0, xx.high) + doAssert hash(ss) == hash(ss, 0, ss.high) + block largeSize: # longer than 4 characters + let + xx = @['H', 'e', 'l', 'l', 'o'] + xxl = @['H', 'e', 'l', 'l', 'o', 'w', 'e', 'e', 'n', 's'] + ssl = "Helloweens" + doAssert hash(xxl) == hash(ssl) + doAssert hash(xxl) == hash(xxl, 0, xxl.high) + doAssert hash(ssl) == hash(ssl, 0, ssl.high) + doAssert hash(xx) == hash(xxl, 0, 4) + doAssert hash(xx) == hash(ssl, 0, 4) + doAssert hash(xx, 0, 3) == hash(xxl, 0, 3) + doAssert hash(xx, 0, 3) == hash(ssl, 0, 3) diff --git a/lib/pure/htmlgen.nim b/lib/pure/htmlgen.nim index bf31c0239..eb9dd9a73 100644 --- a/lib/pure/htmlgen.nim +++ b/lib/pure/htmlgen.nim @@ -8,9 +8,9 @@ # ## Do yourself a favor and import the module -## as `from htmlgen import nil` and then fully qualify the macros. +## as ``from htmlgen import nil`` and then fully qualify the macros. ## -## *Note*: The Karax project (`nimble install karax`) has a better +## *Note*: The Karax project (``nimble install karax``) has a better ## way to achieve the same, see https://github.com/pragmagic/karax/blob/master/tests/nativehtmlgen.nim ## for an example. ## @@ -34,9 +34,9 @@ ## var nim = "Nim" ## echo h1(a(href="https://nim-lang.org", nim)) ## -## Writes the string: +## Writes the string:: ## -##

Nim

+##

Nim

## import @@ -56,7 +56,7 @@ const ariaAttr* = " role " ## HTML DOM Aria Attributes commonAttr* = coreAttr & eventAttr & ariaAttr ## HTML DOM Common Attributes -proc getIdent(e: NimNode): string = +proc getIdent(e: NimNode): string {.compileTime.} = case e.kind of nnkIdent: result = e.strVal.normalize @@ -64,7 +64,7 @@ proc getIdent(e: NimNode): string = result = getIdent(e[0]) for i in 1 .. e.len-1: result.add getIdent(e[i]) - else: error("cannot extract identifier from node: " & toStrLit(e).strVal, e) + else: error("cannot extract identifier from node: " & toStrLit(e).strVal) proc delete[T](s: var seq[T], attr: T): bool = var idx = find(s, attr) @@ -75,7 +75,7 @@ proc delete[T](s: var seq[T], attr: T): bool = result = true proc xmlCheckedTag*(argsList: NimNode, tag: string, optAttr = "", reqAttr = "", - isLeaf = false): NimNode = + isLeaf = false): NimNode {.compileTime.} = ## use this procedure to define a new XML tag # copy the attributes; when iterating over them these lists @@ -89,21 +89,21 @@ proc xmlCheckedTag*(argsList: NimNode, tag: string, optAttr = "", reqAttr = "", for i in 0 ..< argsList.len: if argsList[i].kind == nnkExprEqExpr: var name = getIdent(argsList[i][0]) - if name.startsWith("data-") or delete(req, name) or delete(opt, name): + if delete(req, name) or delete(opt, name): result.add(newStrLitNode(" ")) result.add(newStrLitNode(name)) result.add(newStrLitNode("=\"")) result.add(argsList[i][1]) result.add(newStrLitNode("\"")) else: - error("invalid attribute for '" & tag & "' element: " & name, argsList[i]) + error("invalid attribute for '" & tag & "' element: " & name) # check each required attribute exists: if req.len > 0: - error(req[0] & " attribute for '" & tag & "' element expected", argsList) + error(req[0] & " attribute for '" & tag & "' element expected") if isLeaf: for i in 0 ..< argsList.len: if argsList[i].kind != nnkExprEqExpr: - error("element " & tag & " cannot be nested", argsList[i]) + error("element " & tag & " cannot be nested") result.add(newStrLitNode(" />")) else: result.add(newStrLitNode(">")) @@ -113,233 +113,236 @@ proc xmlCheckedTag*(argsList: NimNode, tag: string, optAttr = "", reqAttr = "", result.add(newStrLitNode("")) - result = nestList(ident"&", result) + when compiles(nestList(ident"&", result)): + result = nestList(ident"&", result) + else: + result = nestList(!"&", result) macro a*(e: varargs[untyped]): untyped = - ## Generates the HTML `a` element. + ## generates the HTML ``a`` element. result = xmlCheckedTag(e, "a", "href target download rel hreflang type " & commonAttr) macro abbr*(e: varargs[untyped]): untyped = - ## Generates the HTML `abbr` element. + ## generates the HTML ``abbr`` element. result = xmlCheckedTag(e, "abbr", commonAttr) macro address*(e: varargs[untyped]): untyped = - ## Generates the HTML `address` element. + ## generates the HTML ``address`` element. result = xmlCheckedTag(e, "address", commonAttr) macro area*(e: varargs[untyped]): untyped = - ## Generates the HTML `area` element. + ## generates the HTML ``area`` element. result = xmlCheckedTag(e, "area", "coords download href hreflang rel " & "shape target type" & commonAttr, "alt", true) macro article*(e: varargs[untyped]): untyped = - ## Generates the HTML `article` element. + ## generates the HTML ``article`` element. result = xmlCheckedTag(e, "article", commonAttr) macro aside*(e: varargs[untyped]): untyped = - ## Generates the HTML `aside` element. + ## generates the HTML ``aside`` element. result = xmlCheckedTag(e, "aside", commonAttr) macro audio*(e: varargs[untyped]): untyped = - ## Generates the HTML `audio` element. + ## generates the HTML ``audio`` element. result = xmlCheckedTag(e, "audio", "src crossorigin preload " & "autoplay mediagroup loop muted controls" & commonAttr) macro b*(e: varargs[untyped]): untyped = - ## Generates the HTML `b` element. + ## generates the HTML ``b`` element. result = xmlCheckedTag(e, "b", commonAttr) macro base*(e: varargs[untyped]): untyped = - ## Generates the HTML `base` element. + ## generates the HTML ``base`` element. result = xmlCheckedTag(e, "base", "href target" & commonAttr, "", true) macro bdi*(e: varargs[untyped]): untyped = - ## Generates the HTML `bdi` element. + ## generates the HTML ``bdi`` element. result = xmlCheckedTag(e, "bdi", commonAttr) macro bdo*(e: varargs[untyped]): untyped = - ## Generates the HTML `bdo` element. + ## generates the HTML ``bdo`` element. result = xmlCheckedTag(e, "bdo", commonAttr) macro big*(e: varargs[untyped]): untyped = - ## Generates the HTML `big` element. + ## generates the HTML ``big`` element. result = xmlCheckedTag(e, "big", commonAttr) macro blockquote*(e: varargs[untyped]): untyped = - ## Generates the HTML `blockquote` element. + ## generates the HTML ``blockquote`` element. result = xmlCheckedTag(e, "blockquote", " cite" & commonAttr) macro body*(e: varargs[untyped]): untyped = - ## Generates the HTML `body` element. + ## generates the HTML ``body`` element. result = xmlCheckedTag(e, "body", "onafterprint onbeforeprint " & "onbeforeunload onhashchange onmessage onoffline ononline onpagehide " & "onpageshow onpopstate onstorage onunload" & commonAttr) macro br*(e: varargs[untyped]): untyped = - ## Generates the HTML `br` element. + ## generates the HTML ``br`` element. result = xmlCheckedTag(e, "br", commonAttr, "", true) macro button*(e: varargs[untyped]): untyped = - ## Generates the HTML `button` element. + ## generates the HTML ``button`` element. result = xmlCheckedTag(e, "button", "autofocus disabled form formaction " & "formenctype formmethod formnovalidate formtarget menu name type value" & commonAttr) macro canvas*(e: varargs[untyped]): untyped = - ## Generates the HTML `canvas` element. + ## generates the HTML ``canvas`` element. result = xmlCheckedTag(e, "canvas", "width height" & commonAttr) macro caption*(e: varargs[untyped]): untyped = - ## Generates the HTML `caption` element. + ## generates the HTML ``caption`` element. result = xmlCheckedTag(e, "caption", commonAttr) macro center*(e: varargs[untyped]): untyped = - ## Generates the HTML `center` element. + ## Generates the HTML ``center`` element. result = xmlCheckedTag(e, "center", commonAttr) macro cite*(e: varargs[untyped]): untyped = - ## Generates the HTML `cite` element. + ## generates the HTML ``cite`` element. result = xmlCheckedTag(e, "cite", commonAttr) macro code*(e: varargs[untyped]): untyped = - ## Generates the HTML `code` element. + ## generates the HTML ``code`` element. result = xmlCheckedTag(e, "code", commonAttr) macro col*(e: varargs[untyped]): untyped = - ## Generates the HTML `col` element. + ## generates the HTML ``col`` element. result = xmlCheckedTag(e, "col", "span" & commonAttr, "", true) macro colgroup*(e: varargs[untyped]): untyped = - ## Generates the HTML `colgroup` element. + ## generates the HTML ``colgroup`` element. result = xmlCheckedTag(e, "colgroup", "span" & commonAttr) macro data*(e: varargs[untyped]): untyped = - ## Generates the HTML `data` element. + ## generates the HTML ``data`` element. result = xmlCheckedTag(e, "data", "value" & commonAttr) macro datalist*(e: varargs[untyped]): untyped = - ## Generates the HTML `datalist` element. + ## generates the HTML ``datalist`` element. result = xmlCheckedTag(e, "datalist", commonAttr) macro dd*(e: varargs[untyped]): untyped = - ## Generates the HTML `dd` element. + ## generates the HTML ``dd`` element. result = xmlCheckedTag(e, "dd", commonAttr) macro del*(e: varargs[untyped]): untyped = - ## Generates the HTML `del` element. + ## generates the HTML ``del`` element. result = xmlCheckedTag(e, "del", "cite datetime" & commonAttr) macro details*(e: varargs[untyped]): untyped = - ## Generates the HTML `details` element. + ## Generates the HTML ``details`` element. result = xmlCheckedTag(e, "details", commonAttr & "open") macro dfn*(e: varargs[untyped]): untyped = - ## Generates the HTML `dfn` element. + ## generates the HTML ``dfn`` element. result = xmlCheckedTag(e, "dfn", commonAttr) macro dialog*(e: varargs[untyped]): untyped = - ## Generates the HTML `dialog` element. + ## Generates the HTML ``dialog`` element. result = xmlCheckedTag(e, "dialog", commonAttr & "open") macro `div`*(e: varargs[untyped]): untyped = - ## Generates the HTML `div` element. + ## generates the HTML ``div`` element. result = xmlCheckedTag(e, "div", commonAttr) macro dl*(e: varargs[untyped]): untyped = - ## Generates the HTML `dl` element. + ## generates the HTML ``dl`` element. result = xmlCheckedTag(e, "dl", commonAttr) macro dt*(e: varargs[untyped]): untyped = - ## Generates the HTML `dt` element. + ## generates the HTML ``dt`` element. result = xmlCheckedTag(e, "dt", commonAttr) macro em*(e: varargs[untyped]): untyped = - ## Generates the HTML `em` element. + ## generates the HTML ``em`` element. result = xmlCheckedTag(e, "em", commonAttr) macro embed*(e: varargs[untyped]): untyped = - ## Generates the HTML `embed` element. + ## generates the HTML ``embed`` element. result = xmlCheckedTag(e, "embed", "src type height width" & commonAttr, "", true) macro fieldset*(e: varargs[untyped]): untyped = - ## Generates the HTML `fieldset` element. + ## generates the HTML ``fieldset`` element. result = xmlCheckedTag(e, "fieldset", "disabled form name" & commonAttr) macro figure*(e: varargs[untyped]): untyped = - ## Generates the HTML `figure` element. + ## generates the HTML ``figure`` element. result = xmlCheckedTag(e, "figure", commonAttr) macro figcaption*(e: varargs[untyped]): untyped = - ## Generates the HTML `figcaption` element. + ## generates the HTML ``figcaption`` element. result = xmlCheckedTag(e, "figcaption", commonAttr) macro footer*(e: varargs[untyped]): untyped = - ## Generates the HTML `footer` element. + ## generates the HTML ``footer`` element. result = xmlCheckedTag(e, "footer", commonAttr) macro form*(e: varargs[untyped]): untyped = - ## Generates the HTML `form` element. + ## generates the HTML ``form`` element. result = xmlCheckedTag(e, "form", "accept-charset action autocomplete " & "enctype method name novalidate target" & commonAttr) macro h1*(e: varargs[untyped]): untyped = - ## Generates the HTML `h1` element. + ## generates the HTML ``h1`` element. result = xmlCheckedTag(e, "h1", commonAttr) macro h2*(e: varargs[untyped]): untyped = - ## Generates the HTML `h2` element. + ## generates the HTML ``h2`` element. result = xmlCheckedTag(e, "h2", commonAttr) macro h3*(e: varargs[untyped]): untyped = - ## Generates the HTML `h3` element. + ## generates the HTML ``h3`` element. result = xmlCheckedTag(e, "h3", commonAttr) macro h4*(e: varargs[untyped]): untyped = - ## Generates the HTML `h4` element. + ## generates the HTML ``h4`` element. result = xmlCheckedTag(e, "h4", commonAttr) macro h5*(e: varargs[untyped]): untyped = - ## Generates the HTML `h5` element. + ## generates the HTML ``h5`` element. result = xmlCheckedTag(e, "h5", commonAttr) macro h6*(e: varargs[untyped]): untyped = - ## Generates the HTML `h6` element. + ## generates the HTML ``h6`` element. result = xmlCheckedTag(e, "h6", commonAttr) macro head*(e: varargs[untyped]): untyped = - ## Generates the HTML `head` element. + ## generates the HTML ``head`` element. result = xmlCheckedTag(e, "head", commonAttr) macro header*(e: varargs[untyped]): untyped = - ## Generates the HTML `header` element. + ## generates the HTML ``header`` element. result = xmlCheckedTag(e, "header", commonAttr) macro html*(e: varargs[untyped]): untyped = - ## Generates the HTML `html` element. + ## generates the HTML ``html`` element. result = xmlCheckedTag(e, "html", "xmlns" & commonAttr, "") macro hr*(): untyped = - ## Generates the HTML `hr` element. - result = xmlCheckedTag(newNimNode(nnkArgList), "hr", commonAttr, "", true) + ## generates the HTML ``hr`` element. + result = xmlCheckedTag(newNimNode(nnkArglist), "hr", commonAttr, "", true) macro i*(e: varargs[untyped]): untyped = - ## Generates the HTML `i` element. + ## generates the HTML ``i`` element. result = xmlCheckedTag(e, "i", commonAttr) macro iframe*(e: varargs[untyped]): untyped = - ## Generates the HTML `iframe` element. - result = xmlCheckedTag(e, "iframe", "src srcdoc name sandbox width height loading" & + ## generates the HTML ``iframe`` element. + result = xmlCheckedTag(e, "iframe", "src srcdoc name sandbox width height" & commonAttr) macro img*(e: varargs[untyped]): untyped = - ## Generates the HTML `img` element. - result = xmlCheckedTag(e, "img", "crossorigin usemap ismap height width loading" & + ## generates the HTML ``img`` element. + result = xmlCheckedTag(e, "img", "crossorigin usemap ismap height width" & commonAttr, "src alt", true) macro input*(e: varargs[untyped]): untyped = - ## Generates the HTML `input` element. + ## generates the HTML ``input`` element. result = xmlCheckedTag(e, "input", "accept alt autocomplete autofocus " & "checked dirname disabled form formaction formenctype formmethod " & "formnovalidate formtarget height inputmode list max maxlength min " & @@ -347,401 +350,397 @@ macro input*(e: varargs[untyped]): untyped = "src step type value width" & commonAttr, "", true) macro ins*(e: varargs[untyped]): untyped = - ## Generates the HTML `ins` element. + ## generates the HTML ``ins`` element. result = xmlCheckedTag(e, "ins", "cite datetime" & commonAttr) macro kbd*(e: varargs[untyped]): untyped = - ## Generates the HTML `kbd` element. + ## generates the HTML ``kbd`` element. result = xmlCheckedTag(e, "kbd", commonAttr) macro keygen*(e: varargs[untyped]): untyped = - ## Generates the HTML `keygen` element. + ## generates the HTML ``keygen`` element. result = xmlCheckedTag(e, "keygen", "autofocus challenge disabled " & "form keytype name" & commonAttr) macro label*(e: varargs[untyped]): untyped = - ## Generates the HTML `label` element. + ## generates the HTML ``label`` element. result = xmlCheckedTag(e, "label", "form for" & commonAttr) macro legend*(e: varargs[untyped]): untyped = - ## Generates the HTML `legend` element. + ## generates the HTML ``legend`` element. result = xmlCheckedTag(e, "legend", commonAttr) macro li*(e: varargs[untyped]): untyped = - ## Generates the HTML `li` element. + ## generates the HTML ``li`` element. result = xmlCheckedTag(e, "li", "value" & commonAttr) macro link*(e: varargs[untyped]): untyped = - ## Generates the HTML `link` element. + ## generates the HTML ``link`` element. result = xmlCheckedTag(e, "link", "href crossorigin rel media hreflang " & "type sizes" & commonAttr, "", true) macro main*(e: varargs[untyped]): untyped = - ## Generates the HTML `main` element. + ## generates the HTML ``main`` element. result = xmlCheckedTag(e, "main", commonAttr) macro map*(e: varargs[untyped]): untyped = - ## Generates the HTML `map` element. + ## generates the HTML ``map`` element. result = xmlCheckedTag(e, "map", "name" & commonAttr) macro mark*(e: varargs[untyped]): untyped = - ## Generates the HTML `mark` element. + ## generates the HTML ``mark`` element. result = xmlCheckedTag(e, "mark", commonAttr) macro marquee*(e: varargs[untyped]): untyped = - ## Generates the HTML `marquee` element. + ## Generates the HTML ``marquee`` element. result = xmlCheckedTag(e, "marquee", coreAttr & "behavior bgcolor direction height hspace loop scrollamount " & "scrolldelay truespeed vspace width onbounce onfinish onstart") macro meta*(e: varargs[untyped]): untyped = - ## Generates the HTML `meta` element. + ## generates the HTML ``meta`` element. result = xmlCheckedTag(e, "meta", "name http-equiv content charset" & commonAttr, "", true) macro meter*(e: varargs[untyped]): untyped = - ## Generates the HTML `meter` element. + ## generates the HTML ``meter`` element. result = xmlCheckedTag(e, "meter", "value min max low high optimum" & commonAttr) macro nav*(e: varargs[untyped]): untyped = - ## Generates the HTML `nav` element. + ## generates the HTML ``nav`` element. result = xmlCheckedTag(e, "nav", commonAttr) macro noscript*(e: varargs[untyped]): untyped = - ## Generates the HTML `noscript` element. + ## generates the HTML ``noscript`` element. result = xmlCheckedTag(e, "noscript", commonAttr) macro `object`*(e: varargs[untyped]): untyped = - ## Generates the HTML `object` element. + ## generates the HTML ``object`` element. result = xmlCheckedTag(e, "object", "data type typemustmatch name usemap " & "form width height" & commonAttr) macro ol*(e: varargs[untyped]): untyped = - ## Generates the HTML `ol` element. + ## generates the HTML ``ol`` element. result = xmlCheckedTag(e, "ol", "reversed start type" & commonAttr) macro optgroup*(e: varargs[untyped]): untyped = - ## Generates the HTML `optgroup` element. + ## generates the HTML ``optgroup`` element. result = xmlCheckedTag(e, "optgroup", "disabled" & commonAttr, "label", false) macro option*(e: varargs[untyped]): untyped = - ## Generates the HTML `option` element. + ## generates the HTML ``option`` element. result = xmlCheckedTag(e, "option", "disabled label selected value" & commonAttr) macro output*(e: varargs[untyped]): untyped = - ## Generates the HTML `output` element. + ## generates the HTML ``output`` element. result = xmlCheckedTag(e, "output", "for form name" & commonAttr) macro p*(e: varargs[untyped]): untyped = - ## Generates the HTML `p` element. + ## generates the HTML ``p`` element. result = xmlCheckedTag(e, "p", commonAttr) macro param*(e: varargs[untyped]): untyped = - ## Generates the HTML `param` element. + ## generates the HTML ``param`` element. result = xmlCheckedTag(e, "param", commonAttr, "name value", true) macro picture*(e: varargs[untyped]): untyped = - ## Generates the HTML `picture` element. + ## Generates the HTML ``picture`` element. result = xmlCheckedTag(e, "picture", commonAttr) macro pre*(e: varargs[untyped]): untyped = - ## Generates the HTML `pre` element. + ## generates the HTML ``pre`` element. result = xmlCheckedTag(e, "pre", commonAttr) macro progress*(e: varargs[untyped]): untyped = - ## Generates the HTML `progress` element. + ## generates the HTML ``progress`` element. result = xmlCheckedTag(e, "progress", "value max" & commonAttr) macro q*(e: varargs[untyped]): untyped = - ## Generates the HTML `q` element. + ## generates the HTML ``q`` element. result = xmlCheckedTag(e, "q", "cite" & commonAttr) macro rb*(e: varargs[untyped]): untyped = - ## Generates the HTML `rb` element. + ## generates the HTML ``rb`` element. result = xmlCheckedTag(e, "rb", commonAttr) macro rp*(e: varargs[untyped]): untyped = - ## Generates the HTML `rp` element. + ## generates the HTML ``rp`` element. result = xmlCheckedTag(e, "rp", commonAttr) macro rt*(e: varargs[untyped]): untyped = - ## Generates the HTML `rt` element. + ## generates the HTML ``rt`` element. result = xmlCheckedTag(e, "rt", commonAttr) macro rtc*(e: varargs[untyped]): untyped = - ## Generates the HTML `rtc` element. + ## generates the HTML ``rtc`` element. result = xmlCheckedTag(e, "rtc", commonAttr) macro ruby*(e: varargs[untyped]): untyped = - ## Generates the HTML `ruby` element. + ## generates the HTML ``ruby`` element. result = xmlCheckedTag(e, "ruby", commonAttr) macro s*(e: varargs[untyped]): untyped = - ## Generates the HTML `s` element. + ## generates the HTML ``s`` element. result = xmlCheckedTag(e, "s", commonAttr) macro samp*(e: varargs[untyped]): untyped = - ## Generates the HTML `samp` element. + ## generates the HTML ``samp`` element. result = xmlCheckedTag(e, "samp", commonAttr) macro script*(e: varargs[untyped]): untyped = - ## Generates the HTML `script` element. + ## generates the HTML ``script`` element. result = xmlCheckedTag(e, "script", "src type charset async defer " & "crossorigin" & commonAttr) macro section*(e: varargs[untyped]): untyped = - ## Generates the HTML `section` element. + ## generates the HTML ``section`` element. result = xmlCheckedTag(e, "section", commonAttr) macro select*(e: varargs[untyped]): untyped = - ## Generates the HTML `select` element. + ## generates the HTML ``select`` element. result = xmlCheckedTag(e, "select", "autofocus disabled form multiple " & "name required size" & commonAttr) macro slot*(e: varargs[untyped]): untyped = - ## Generates the HTML `slot` element. + ## Generates the HTML ``slot`` element. result = xmlCheckedTag(e, "slot", commonAttr) macro small*(e: varargs[untyped]): untyped = - ## Generates the HTML `small` element. + ## generates the HTML ``small`` element. result = xmlCheckedTag(e, "small", commonAttr) macro source*(e: varargs[untyped]): untyped = - ## Generates the HTML `source` element. + ## generates the HTML ``source`` element. result = xmlCheckedTag(e, "source", "type" & commonAttr, "src", true) macro span*(e: varargs[untyped]): untyped = - ## Generates the HTML `span` element. + ## generates the HTML ``span`` element. result = xmlCheckedTag(e, "span", commonAttr) macro strong*(e: varargs[untyped]): untyped = - ## Generates the HTML `strong` element. + ## generates the HTML ``strong`` element. result = xmlCheckedTag(e, "strong", commonAttr) macro style*(e: varargs[untyped]): untyped = - ## Generates the HTML `style` element. + ## generates the HTML ``style`` element. result = xmlCheckedTag(e, "style", "media type" & commonAttr) macro sub*(e: varargs[untyped]): untyped = - ## Generates the HTML `sub` element. + ## generates the HTML ``sub`` element. result = xmlCheckedTag(e, "sub", commonAttr) macro summary*(e: varargs[untyped]): untyped = - ## Generates the HTML `summary` element. + ## Generates the HTML ``summary`` element. result = xmlCheckedTag(e, "summary", commonAttr) macro sup*(e: varargs[untyped]): untyped = - ## Generates the HTML `sup` element. + ## generates the HTML ``sup`` element. result = xmlCheckedTag(e, "sup", commonAttr) macro table*(e: varargs[untyped]): untyped = - ## Generates the HTML `table` element. + ## generates the HTML ``table`` element. result = xmlCheckedTag(e, "table", "border sortable" & commonAttr) macro tbody*(e: varargs[untyped]): untyped = - ## Generates the HTML `tbody` element. + ## generates the HTML ``tbody`` element. result = xmlCheckedTag(e, "tbody", commonAttr) macro td*(e: varargs[untyped]): untyped = - ## Generates the HTML `td` element. + ## generates the HTML ``td`` element. result = xmlCheckedTag(e, "td", "colspan rowspan headers" & commonAttr) macro `template`*(e: varargs[untyped]): untyped = - ## Generates the HTML `template` element. + ## generates the HTML ``template`` element. result = xmlCheckedTag(e, "template", commonAttr) macro textarea*(e: varargs[untyped]): untyped = - ## Generates the HTML `textarea` element. + ## generates the HTML ``textarea`` element. result = xmlCheckedTag(e, "textarea", "autocomplete autofocus cols " & "dirname disabled form inputmode maxlength minlength name placeholder " & "readonly required rows wrap" & commonAttr) macro tfoot*(e: varargs[untyped]): untyped = - ## Generates the HTML `tfoot` element. + ## generates the HTML ``tfoot`` element. result = xmlCheckedTag(e, "tfoot", commonAttr) macro th*(e: varargs[untyped]): untyped = - ## Generates the HTML `th` element. + ## generates the HTML ``th`` element. result = xmlCheckedTag(e, "th", "colspan rowspan headers abbr scope axis" & " sorted" & commonAttr) macro thead*(e: varargs[untyped]): untyped = - ## Generates the HTML `thead` element. + ## generates the HTML ``thead`` element. result = xmlCheckedTag(e, "thead", commonAttr) macro time*(e: varargs[untyped]): untyped = - ## Generates the HTML `time` element. + ## generates the HTML ``time`` element. result = xmlCheckedTag(e, "time", "datetime" & commonAttr) macro title*(e: varargs[untyped]): untyped = - ## Generates the HTML `title` element. + ## generates the HTML ``title`` element. result = xmlCheckedTag(e, "title", commonAttr) macro tr*(e: varargs[untyped]): untyped = - ## Generates the HTML `tr` element. + ## generates the HTML ``tr`` element. result = xmlCheckedTag(e, "tr", commonAttr) macro track*(e: varargs[untyped]): untyped = - ## Generates the HTML `track` element. + ## generates the HTML ``track`` element. result = xmlCheckedTag(e, "track", "kind srclang label default" & commonAttr, "src", true) macro tt*(e: varargs[untyped]): untyped = - ## Generates the HTML `tt` element. + ## generates the HTML ``tt`` element. result = xmlCheckedTag(e, "tt", commonAttr) macro u*(e: varargs[untyped]): untyped = - ## Generates the HTML `u` element. + ## generates the HTML ``u`` element. result = xmlCheckedTag(e, "u", commonAttr) macro ul*(e: varargs[untyped]): untyped = - ## Generates the HTML `ul` element. + ## generates the HTML ``ul`` element. result = xmlCheckedTag(e, "ul", commonAttr) macro `var`*(e: varargs[untyped]): untyped = - ## Generates the HTML `var` element. + ## generates the HTML ``var`` element. result = xmlCheckedTag(e, "var", commonAttr) macro video*(e: varargs[untyped]): untyped = - ## Generates the HTML `video` element. + ## generates the HTML ``video`` element. result = xmlCheckedTag(e, "video", "src crossorigin poster preload " & "autoplay mediagroup loop muted controls width height" & commonAttr) macro wbr*(e: varargs[untyped]): untyped = - ## Generates the HTML `wbr` element. + ## generates the HTML ``wbr`` element. result = xmlCheckedTag(e, "wbr", commonAttr, "", true) -macro portal*(e: varargs[untyped]): untyped = - ## Generates the HTML `portal` element. - result = xmlCheckedTag(e, "portal", "width height type src disabled" & commonAttr, "", false) - macro math*(e: varargs[untyped]): untyped = - ## Generates the HTML `math` element. MathML https://wikipedia.org/wiki/MathML + ## Generates the HTML ``math`` element. MathML https://wikipedia.org/wiki/MathML ## https://developer.mozilla.org/en-US/docs/Web/MathML/Element/math#Examples result = xmlCheckedTag(e, "math", "mathbackground mathcolor href overflow" & commonAttr) macro maction*(e: varargs[untyped]): untyped = - ## Generates the HTML `maction` element. MathML https://wikipedia.org/wiki/MathML + ## Generates the HTML ``maction`` element. MathML https://wikipedia.org/wiki/MathML ## https://developer.mozilla.org/en-US/docs/Web/MathML/Element/maction result = xmlCheckedTag(e, "maction", "mathbackground mathcolor href" & commonAttr) macro menclose*(e: varargs[untyped]): untyped = - ## Generates the HTML `menclose` element. MathML https://wikipedia.org/wiki/MathML + ## Generates the HTML ``menclose`` element. MathML https://wikipedia.org/wiki/MathML ## https://developer.mozilla.org/en-US/docs/Web/MathML/Element/menclose result = xmlCheckedTag(e, "menclose", "mathbackground mathcolor href notation" & commonAttr) macro merror*(e: varargs[untyped]): untyped = - ## Generates the HTML `merror` element. MathML https://wikipedia.org/wiki/MathML + ## Generates the HTML ``merror`` element. MathML https://wikipedia.org/wiki/MathML ## https://developer.mozilla.org/en-US/docs/Web/MathML/Element/merror result = xmlCheckedTag(e, "merror", "mathbackground mathcolor href" & commonAttr) macro mfenced*(e: varargs[untyped]): untyped = - ## Generates the HTML `mfenced` element. MathML https://wikipedia.org/wiki/MathML + ## Generates the HTML ``mfenced`` element. MathML https://wikipedia.org/wiki/MathML ## https://developer.mozilla.org/en-US/docs/Web/MathML/Element/mfenced result = xmlCheckedTag(e, "mfenced", "mathbackground mathcolor href open separators" & commonAttr) macro mfrac*(e: varargs[untyped]): untyped = - ## Generates the HTML `mfrac` element. MathML https://wikipedia.org/wiki/MathML + ## Generates the HTML ``mfrac`` element. MathML https://wikipedia.org/wiki/MathML ## https://developer.mozilla.org/en-US/docs/Web/MathML/Element/mfrac result = xmlCheckedTag(e, "mfrac", "mathbackground mathcolor href linethickness numalign" & commonAttr) macro mglyph*(e: varargs[untyped]): untyped = - ## Generates the HTML `mglyph` element. MathML https://wikipedia.org/wiki/MathML + ## Generates the HTML ``mglyph`` element. MathML https://wikipedia.org/wiki/MathML ## https://developer.mozilla.org/en-US/docs/Web/MathML/Element/mglyph result = xmlCheckedTag(e, "mglyph", "mathbackground mathcolor href src valign" & commonAttr) macro mi*(e: varargs[untyped]): untyped = - ## Generates the HTML `mi` element. MathML https://wikipedia.org/wiki/MathML + ## Generates the HTML ``mi`` element. MathML https://wikipedia.org/wiki/MathML ## https://developer.mozilla.org/en-US/docs/Web/MathML/Element/mi result = xmlCheckedTag(e, "mi", "mathbackground mathcolor href mathsize mathvariant" & commonAttr) macro mlabeledtr*(e: varargs[untyped]): untyped = - ## Generates the HTML `mlabeledtr` element. MathML https://wikipedia.org/wiki/MathML + ## Generates the HTML ``mlabeledtr`` element. MathML https://wikipedia.org/wiki/MathML ## https://developer.mozilla.org/en-US/docs/Web/MathML/Element/mlabeledtr result = xmlCheckedTag(e, "mlabeledtr", "mathbackground mathcolor href columnalign groupalign rowalign" & commonAttr) macro mmultiscripts*(e: varargs[untyped]): untyped = - ## Generates the HTML `mmultiscripts` element. MathML https://wikipedia.org/wiki/MathML + ## Generates the HTML ``mmultiscripts`` element. MathML https://wikipedia.org/wiki/MathML ## https://developer.mozilla.org/en-US/docs/Web/MathML/Element/mmultiscripts result = xmlCheckedTag(e, "mmultiscripts", "mathbackground mathcolor href subscriptshift superscriptshift" & commonAttr) macro mn*(e: varargs[untyped]): untyped = - ## Generates the HTML `mn` element. MathML https://wikipedia.org/wiki/MathML + ## Generates the HTML ``mn`` element. MathML https://wikipedia.org/wiki/MathML ## https://developer.mozilla.org/en-US/docs/Web/MathML/Element/mn result = xmlCheckedTag(e, "mn", "mathbackground mathcolor href mathsize mathvariant" & commonAttr) macro mo*(e: varargs[untyped]): untyped = - ## Generates the HTML `mo` element. MathML https://wikipedia.org/wiki/MathML + ## Generates the HTML ``mo`` element. MathML https://wikipedia.org/wiki/MathML ## https://developer.mozilla.org/en-US/docs/Web/MathML/Element/mo result = xmlCheckedTag(e, "mo", "mathbackground mathcolor fence form largeop lspace mathsize mathvariant movablelimits rspace separator stretchy symmetric" & commonAttr) macro mover*(e: varargs[untyped]): untyped = - ## Generates the HTML `mover` element. MathML https://wikipedia.org/wiki/MathML + ## Generates the HTML ``mover`` element. MathML https://wikipedia.org/wiki/MathML ## https://developer.mozilla.org/en-US/docs/Web/MathML/Element/mover result = xmlCheckedTag(e, "mover", "mathbackground mathcolor accent href" & commonAttr) macro mpadded*(e: varargs[untyped]): untyped = - ## Generates the HTML `mpadded` element. MathML https://wikipedia.org/wiki/MathML + ## Generates the HTML ``mpadded`` element. MathML https://wikipedia.org/wiki/MathML ## https://developer.mozilla.org/en-US/docs/Web/MathML/Element/mpadded result = xmlCheckedTag(e, "mpadded", "mathbackground mathcolor depth href lspace voffset" & commonAttr) macro mphantom*(e: varargs[untyped]): untyped = - ## Generates the HTML `mphantom` element. MathML https://wikipedia.org/wiki/MathML + ## Generates the HTML ``mphantom`` element. MathML https://wikipedia.org/wiki/MathML ## https://developer.mozilla.org/en-US/docs/Web/MathML/Element/mphantom result = xmlCheckedTag(e, "mphantom", "mathbackground" & commonAttr) macro mroot*(e: varargs[untyped]): untyped = - ## Generates the HTML `mroot` element. MathML https://wikipedia.org/wiki/MathML + ## Generates the HTML ``mroot`` element. MathML https://wikipedia.org/wiki/MathML ## https://developer.mozilla.org/en-US/docs/Web/MathML/Element/mroot result = xmlCheckedTag(e, "mroot", "mathbackground mathcolor href" & commonAttr) macro mrow*(e: varargs[untyped]): untyped = - ## Generates the HTML `mrow` element. MathML https://wikipedia.org/wiki/MathML + ## Generates the HTML ``mrow`` element. MathML https://wikipedia.org/wiki/MathML ## https://developer.mozilla.org/en-US/docs/Web/MathML/Element/mrow result = xmlCheckedTag(e, "mrow", "mathbackground mathcolor href" & commonAttr) macro ms*(e: varargs[untyped]): untyped = - ## Generates the HTML `ms` element. MathML https://wikipedia.org/wiki/MathML + ## Generates the HTML ``ms`` element. MathML https://wikipedia.org/wiki/MathML ## https://developer.mozilla.org/en-US/docs/Web/MathML/Element/ms result = xmlCheckedTag(e, "ms", "mathbackground mathcolor href lquote mathsize mathvariant rquote" & commonAttr) macro mspace*(e: varargs[untyped]): untyped = - ## Generates the HTML `mspace` element. MathML https://wikipedia.org/wiki/MathML + ## Generates the HTML ``mspace`` element. MathML https://wikipedia.org/wiki/MathML ## https://developer.mozilla.org/en-US/docs/Web/MathML/Element/mspace result = xmlCheckedTag(e, "mspace", "mathbackground mathcolor href linebreak" & commonAttr) macro msqrt*(e: varargs[untyped]): untyped = - ## Generates the HTML `msqrt` element. MathML https://wikipedia.org/wiki/MathML + ## Generates the HTML ``msqrt`` element. MathML https://wikipedia.org/wiki/MathML ## https://developer.mozilla.org/en-US/docs/Web/MathML/Element/msqrt result = xmlCheckedTag(e, "msqrt", "mathbackground mathcolor href" & commonAttr) macro mstyle*(e: varargs[untyped]): untyped = - ## Generates the HTML `mstyle` element. MathML https://wikipedia.org/wiki/MathML + ## Generates the HTML ``mstyle`` element. MathML https://wikipedia.org/wiki/MathML ## https://developer.mozilla.org/en-US/docs/Web/MathML/Element/mstyle result = xmlCheckedTag(e, "mstyle", ("mathbackground mathcolor href decimalpoint displaystyle " & "infixlinebreakstyle scriptlevel scriptminsize scriptsizemultiplier" & commonAttr)) macro msub*(e: varargs[untyped]): untyped = - ## Generates the HTML `msub` element. MathML https://wikipedia.org/wiki/MathML + ## Generates the HTML ``msub`` element. MathML https://wikipedia.org/wiki/MathML ## https://developer.mozilla.org/en-US/docs/Web/MathML/Element/msub result = xmlCheckedTag(e, "msub", "mathbackground mathcolor href subscriptshift" & commonAttr) macro msubsup*(e: varargs[untyped]): untyped = - ## Generates the HTML `msubsup` element. MathML https://wikipedia.org/wiki/MathML + ## Generates the HTML ``msubsup`` element. MathML https://wikipedia.org/wiki/MathML ## https://developer.mozilla.org/en-US/docs/Web/MathML/Element/msubsup result = xmlCheckedTag(e, "msubsup", "mathbackground mathcolor href subscriptshift superscriptshift" & commonAttr) macro msup*(e: varargs[untyped]): untyped = - ## Generates the HTML `msup` element. MathML https://wikipedia.org/wiki/MathML + ## Generates the HTML ``msup`` element. MathML https://wikipedia.org/wiki/MathML ## https://developer.mozilla.org/en-US/docs/Web/MathML/Element/msup result = xmlCheckedTag(e, "msup", "mathbackground mathcolor href superscriptshift" & commonAttr) macro mtable*(e: varargs[untyped]): untyped = - ## Generates the HTML `mtable` element. MathML https://wikipedia.org/wiki/MathML + ## Generates the HTML ``mtable`` element. MathML https://wikipedia.org/wiki/MathML ## https://developer.mozilla.org/en-US/docs/Web/MathML/Element/mtable result = xmlCheckedTag(e, "mtable", ("mathbackground mathcolor href align " & "alignmentscope columnalign columnlines columnspacing columnwidth " & @@ -749,38 +748,38 @@ macro mtable*(e: varargs[untyped]): untyped = "rowalign rowlines rowspacing side width" & commonAttr)) macro mtd*(e: varargs[untyped]): untyped = - ## Generates the HTML `mtd` element. MathML https://wikipedia.org/wiki/MathML + ## Generates the HTML ``mtd`` element. MathML https://wikipedia.org/wiki/MathML ## https://developer.mozilla.org/en-US/docs/Web/MathML/Element/mtd result = xmlCheckedTag(e, "mtd", "mathbackground mathcolor href columnalign columnspan groupalign rowalign rowspan" & commonAttr) macro mtext*(e: varargs[untyped]): untyped = - ## Generates the HTML `mtext` element. MathML https://wikipedia.org/wiki/MathML + ## Generates the HTML ``mtext`` element. MathML https://wikipedia.org/wiki/MathML ## https://developer.mozilla.org/en-US/docs/Web/MathML/Element/mtext result = xmlCheckedTag(e, "mtext", "mathbackground mathcolor href mathsize mathvariant" & commonAttr) macro munder*(e: varargs[untyped]): untyped = - ## Generates the HTML `munder` element. MathML https://wikipedia.org/wiki/MathML + ## Generates the HTML ``munder`` element. MathML https://wikipedia.org/wiki/MathML ## https://developer.mozilla.org/en-US/docs/Web/MathML/Element/munder result = xmlCheckedTag(e, "munder", "mathbackground mathcolor href accentunder align" & commonAttr) macro munderover*(e: varargs[untyped]): untyped = - ## Generates the HTML `munderover` element. MathML https://wikipedia.org/wiki/MathML + ## Generates the HTML ``munderover`` element. MathML https://wikipedia.org/wiki/MathML ## https://developer.mozilla.org/en-US/docs/Web/MathML/Element/munderover result = xmlCheckedTag(e, "munderover", "mathbackground mathcolor href accentunder accent align" & commonAttr) macro semantics*(e: varargs[untyped]): untyped = - ## Generates the HTML `semantics` element. MathML https://wikipedia.org/wiki/MathML + ## Generates the HTML ``semantics`` element. MathML https://wikipedia.org/wiki/MathML ## https://developer.mozilla.org/en-US/docs/Web/MathML/Element/semantics result = xmlCheckedTag(e, "semantics", "mathbackground mathcolor href definitionURL encoding cd src" & commonAttr) macro annotation*(e: varargs[untyped]): untyped = - ## Generates the HTML `annotation` element. MathML https://wikipedia.org/wiki/MathML + ## Generates the HTML ``annotation`` element. MathML https://wikipedia.org/wiki/MathML ## https://developer.mozilla.org/en-US/docs/Web/MathML/Element/semantics result = xmlCheckedTag(e, "annotation", "mathbackground mathcolor href definitionURL encoding cd src" & commonAttr) macro `annotation-xml`*(e: varargs[untyped]): untyped = - ## Generates the HTML `annotation-xml` element. MathML https://wikipedia.org/wiki/MathML + ## Generates the HTML ``annotation-xml`` element. MathML https://wikipedia.org/wiki/MathML ## https://developer.mozilla.org/en-US/docs/Web/MathML/Element/semantics result = xmlCheckedTag(e, "annotation", "mathbackground mathcolor href definitionURL encoding cd src" & commonAttr) diff --git a/lib/pure/htmlparser.nim b/lib/pure/htmlparser.nim index 24eab3abb..4b305cfd6 100644 --- a/lib/pure/htmlparser.nim +++ b/lib/pure/htmlparser.nim @@ -19,7 +19,7 @@ ## ## Every tag in the resulting tree is in lower case. ## -## **Note:** The resulting `XmlNode` already uses the `clientData` field, +## **Note:** The resulting ``XmlNode`` already uses the ``clientData`` field, ## so it cannot be used by clients of this library. ## ## Example: Transforming hyperlinks @@ -27,16 +27,16 @@ ## ## This code demonstrates how you can iterate over all the tags in an HTML file ## and write back the modified version. In this case we look for hyperlinks -## ending with the extension `.rst` and convert them to `.html`. +## ending with the extension ``.rst`` and convert them to ``.html``. ## ## .. code-block:: Nim ## :test: ## -## import std/htmlparser -## import std/xmltree # To use '$' for XmlNode -## import std/strtabs # To access XmlAttributes -## import std/os # To use splitFile -## import std/strutils # To use cmpIgnoreCase +## import htmlparser +## import xmltree # To use '$' for XmlNode +## import strtabs # To access XmlAttributes +## import os # To use splitFile +## import strutils # To use cmpIgnoreCase ## ## proc transformHyperlinks() = ## let html = loadHtml("input.html") @@ -51,136 +51,133 @@ import strutils, streams, parsexml, xmltree, unicode, strtabs -when defined(nimPreviewSlimSystem): - import std/syncio - type HtmlTag* = enum ## list of all supported HTML tags; order will always be ## alphabetically tagUnknown, ## unknown HTML element - tagA, ## the HTML `a` element - tagAbbr, ## the deprecated HTML `abbr` element - tagAcronym, ## the HTML `acronym` element - tagAddress, ## the HTML `address` element - tagApplet, ## the deprecated HTML `applet` element - tagArea, ## the HTML `area` element - tagArticle, ## the HTML `article` element - tagAside, ## the HTML `aside` element - tagAudio, ## the HTML `audio` element - tagB, ## the HTML `b` element - tagBase, ## the HTML `base` element - tagBdi, ## the HTML `bdi` element - tagBdo, ## the deprecated HTML `dbo` element - tagBasefont, ## the deprecated HTML `basefont` element - tagBig, ## the HTML `big` element - tagBlockquote, ## the HTML `blockquote` element - tagBody, ## the HTML `body` element - tagBr, ## the HTML `br` element - tagButton, ## the HTML `button` element - tagCanvas, ## the HTML `canvas` element - tagCaption, ## the HTML `caption` element - tagCenter, ## the deprecated HTML `center` element - tagCite, ## the HTML `cite` element - tagCode, ## the HTML `code` element - tagCol, ## the HTML `col` element - tagColgroup, ## the HTML `colgroup` element - tagCommand, ## the HTML `command` element - tagDatalist, ## the HTML `datalist` element - tagDd, ## the HTML `dd` element - tagDel, ## the HTML `del` element - tagDetails, ## the HTML `details` element - tagDfn, ## the HTML `dfn` element - tagDialog, ## the HTML `dialog` element - tagDiv, ## the HTML `div` element - tagDir, ## the deprecated HTLM `dir` element - tagDl, ## the HTML `dl` element - tagDt, ## the HTML `dt` element - tagEm, ## the HTML `em` element - tagEmbed, ## the HTML `embed` element - tagFieldset, ## the HTML `fieldset` element - tagFigcaption, ## the HTML `figcaption` element - tagFigure, ## the HTML `figure` element - tagFont, ## the deprecated HTML `font` element - tagFooter, ## the HTML `footer` element - tagForm, ## the HTML `form` element - tagFrame, ## the HTML `frame` element - tagFrameset, ## the deprecated HTML `frameset` element - tagH1, ## the HTML `h1` element - tagH2, ## the HTML `h2` element - tagH3, ## the HTML `h3` element - tagH4, ## the HTML `h4` element - tagH5, ## the HTML `h5` element - tagH6, ## the HTML `h6` element - tagHead, ## the HTML `head` element - tagHeader, ## the HTML `header` element - tagHgroup, ## the HTML `hgroup` element - tagHtml, ## the HTML `html` element - tagHr, ## the HTML `hr` element - tagI, ## the HTML `i` element - tagIframe, ## the deprecated HTML `iframe` element - tagImg, ## the HTML `img` element - tagInput, ## the HTML `input` element - tagIns, ## the HTML `ins` element - tagIsindex, ## the deprecated HTML `isindex` element - tagKbd, ## the HTML `kbd` element - tagKeygen, ## the HTML `keygen` element - tagLabel, ## the HTML `label` element - tagLegend, ## the HTML `legend` element - tagLi, ## the HTML `li` element - tagLink, ## the HTML `link` element - tagMap, ## the HTML `map` element - tagMark, ## the HTML `mark` element - tagMenu, ## the deprecated HTML `menu` element - tagMeta, ## the HTML `meta` element - tagMeter, ## the HTML `meter` element - tagNav, ## the HTML `nav` element - tagNobr, ## the deprecated HTML `nobr` element - tagNoframes, ## the deprecated HTML `noframes` element - tagNoscript, ## the HTML `noscript` element - tagObject, ## the HTML `object` element - tagOl, ## the HTML `ol` element - tagOptgroup, ## the HTML `optgroup` element - tagOption, ## the HTML `option` element - tagOutput, ## the HTML `output` element - tagP, ## the HTML `p` element - tagParam, ## the HTML `param` element - tagPre, ## the HTML `pre` element - tagProgress, ## the HTML `progress` element - tagQ, ## the HTML `q` element - tagRp, ## the HTML `rp` element - tagRt, ## the HTML `rt` element - tagRuby, ## the HTML `ruby` element - tagS, ## the deprecated HTML `s` element - tagSamp, ## the HTML `samp` element - tagScript, ## the HTML `script` element - tagSection, ## the HTML `section` element - tagSelect, ## the HTML `select` element - tagSmall, ## the HTML `small` element - tagSource, ## the HTML `source` element - tagSpan, ## the HTML `span` element - tagStrike, ## the deprecated HTML `strike` element - tagStrong, ## the HTML `strong` element - tagStyle, ## the HTML `style` element - tagSub, ## the HTML `sub` element - tagSummary, ## the HTML `summary` element - tagSup, ## the HTML `sup` element - tagTable, ## the HTML `table` element - tagTbody, ## the HTML `tbody` element - tagTd, ## the HTML `td` element - tagTextarea, ## the HTML `textarea` element - tagTfoot, ## the HTML `tfoot` element - tagTh, ## the HTML `th` element - tagThead, ## the HTML `thead` element - tagTime, ## the HTML `time` element - tagTitle, ## the HTML `title` element - tagTr, ## the HTML `tr` element - tagTrack, ## the HTML `track` element - tagTt, ## the HTML `tt` element - tagU, ## the deprecated HTML `u` element - tagUl, ## the HTML `ul` element - tagVar, ## the HTML `var` element - tagVideo, ## the HTML `video` element - tagWbr ## the HTML `wbr` element + tagA, ## the HTML ``a`` element + tagAbbr, ## the deprecated HTML ``abbr`` element + tagAcronym, ## the HTML ``acronym`` element + tagAddress, ## the HTML ``address`` element + tagApplet, ## the deprecated HTML ``applet`` element + tagArea, ## the HTML ``area`` element + tagArticle, ## the HTML ``article`` element + tagAside, ## the HTML ``aside`` element + tagAudio, ## the HTML ``audio`` element + tagB, ## the HTML ``b`` element + tagBase, ## the HTML ``base`` element + tagBdi, ## the HTML ``bdi`` element + tagBdo, ## the deprecated HTML ``dbo`` element + tagBasefont, ## the deprecated HTML ``basefont`` element + tagBig, ## the HTML ``big`` element + tagBlockquote, ## the HTML ``blockquote`` element + tagBody, ## the HTML ``body`` element + tagBr, ## the HTML ``br`` element + tagButton, ## the HTML ``button`` element + tagCanvas, ## the HTML ``canvas`` element + tagCaption, ## the HTML ``caption`` element + tagCenter, ## the deprecated HTML ``center`` element + tagCite, ## the HTML ``cite`` element + tagCode, ## the HTML ``code`` element + tagCol, ## the HTML ``col`` element + tagColgroup, ## the HTML ``colgroup`` element + tagCommand, ## the HTML ``command`` element + tagDatalist, ## the HTML ``datalist`` element + tagDd, ## the HTML ``dd`` element + tagDel, ## the HTML ``del`` element + tagDetails, ## the HTML ``details`` element + tagDfn, ## the HTML ``dfn`` element + tagDialog, ## the HTML ``dialog`` element + tagDiv, ## the HTML ``div`` element + tagDir, ## the deprecated HTLM ``dir`` element + tagDl, ## the HTML ``dl`` element + tagDt, ## the HTML ``dt`` element + tagEm, ## the HTML ``em`` element + tagEmbed, ## the HTML ``embed`` element + tagFieldset, ## the HTML ``fieldset`` element + tagFigcaption, ## the HTML ``figcaption`` element + tagFigure, ## the HTML ``figure`` element + tagFont, ## the deprecated HTML ``font`` element + tagFooter, ## the HTML ``footer`` element + tagForm, ## the HTML ``form`` element + tagFrame, ## the HTML ``frame`` element + tagFrameset, ## the deprecated HTML ``frameset`` element + tagH1, ## the HTML ``h1`` element + tagH2, ## the HTML ``h2`` element + tagH3, ## the HTML ``h3`` element + tagH4, ## the HTML ``h4`` element + tagH5, ## the HTML ``h5`` element + tagH6, ## the HTML ``h6`` element + tagHead, ## the HTML ``head`` element + tagHeader, ## the HTML ``header`` element + tagHgroup, ## the HTML ``hgroup`` element + tagHtml, ## the HTML ``html`` element + tagHr, ## the HTML ``hr`` element + tagI, ## the HTML ``i`` element + tagIframe, ## the deprecated HTML ``iframe`` element + tagImg, ## the HTML ``img`` element + tagInput, ## the HTML ``input`` element + tagIns, ## the HTML ``ins`` element + tagIsindex, ## the deprecated HTML ``isindex`` element + tagKbd, ## the HTML ``kbd`` element + tagKeygen, ## the HTML ``keygen`` element + tagLabel, ## the HTML ``label`` element + tagLegend, ## the HTML ``legend`` element + tagLi, ## the HTML ``li`` element + tagLink, ## the HTML ``link`` element + tagMap, ## the HTML ``map`` element + tagMark, ## the HTML ``mark`` element + tagMenu, ## the deprecated HTML ``menu`` element + tagMeta, ## the HTML ``meta`` element + tagMeter, ## the HTML ``meter`` element + tagNav, ## the HTML ``nav`` element + tagNobr, ## the deprecated HTML ``nobr`` element + tagNoframes, ## the deprecated HTML ``noframes`` element + tagNoscript, ## the HTML ``noscript`` element + tagObject, ## the HTML ``object`` element + tagOl, ## the HTML ``ol`` element + tagOptgroup, ## the HTML ``optgroup`` element + tagOption, ## the HTML ``option`` element + tagOutput, ## the HTML ``output`` element + tagP, ## the HTML ``p`` element + tagParam, ## the HTML ``param`` element + tagPre, ## the HTML ``pre`` element + tagProgress, ## the HTML ``progress`` element + tagQ, ## the HTML ``q`` element + tagRp, ## the HTML ``rp`` element + tagRt, ## the HTML ``rt`` element + tagRuby, ## the HTML ``ruby`` element + tagS, ## the deprecated HTML ``s`` element + tagSamp, ## the HTML ``samp`` element + tagScript, ## the HTML ``script`` element + tagSection, ## the HTML ``section`` element + tagSelect, ## the HTML ``select`` element + tagSmall, ## the HTML ``small`` element + tagSource, ## the HTML ``source`` element + tagSpan, ## the HTML ``span`` element + tagStrike, ## the deprecated HTML ``strike`` element + tagStrong, ## the HTML ``strong`` element + tagStyle, ## the HTML ``style`` element + tagSub, ## the HTML ``sub`` element + tagSummary, ## the HTML ``summary`` element + tagSup, ## the HTML ``sup`` element + tagTable, ## the HTML ``table`` element + tagTbody, ## the HTML ``tbody`` element + tagTd, ## the HTML ``td`` element + tagTextarea, ## the HTML ``textarea`` element + tagTfoot, ## the HTML ``tfoot`` element + tagTh, ## the HTML ``th`` element + tagThead, ## the HTML ``thead`` element + tagTime, ## the HTML ``time`` element + tagTitle, ## the HTML ``title`` element + tagTr, ## the HTML ``tr`` element + tagTrack, ## the HTML ``track`` element + tagTt, ## the HTML ``tt`` element + tagU, ## the deprecated HTML ``u`` element + tagUl, ## the HTML ``ul`` element + tagVar, ## the HTML ``var`` element + tagVideo, ## the HTML ``video`` element + tagWbr ## the HTML ``wbr`` element const tagToStr* = [ @@ -218,7 +215,7 @@ const tagMenu, tagNoframes} SingleTags* = {tagArea, tagBase, tagBasefont, tagBr, tagCol, tagFrame, tagHr, tagImg, tagIsindex, - tagLink, tagMeta, tagParam, tagWbr, tagSource} + tagLink, tagMeta, tagParam, tagWbr} proc allLower(s: string): bool = for c in s: @@ -354,13 +351,13 @@ proc toHtmlTag(s: string): HtmlTag = proc htmlTag*(n: XmlNode): HtmlTag = - ## Gets `n`'s tag as a `HtmlTag`. + ## Gets `n`'s tag as a ``HtmlTag``. if n.clientData == 0: n.clientData = toHtmlTag(n.tag).ord result = HtmlTag(n.clientData) proc htmlTag*(s: string): HtmlTag = - ## Converts `s` to a `HtmlTag`. If `s` is no HTML tag, `tagUnknown` is + ## Converts `s` to a ``HtmlTag``. If `s` is no HTML tag, ``tagUnknown`` is ## returned. let s = if allLower(s): s else: toLowerAscii(s) result = toHtmlTag(s) @@ -368,7 +365,7 @@ proc htmlTag*(s: string): HtmlTag = proc runeToEntity*(rune: Rune): string = ## converts a Rune to its numeric HTML entity equivalent. runnableExamples: - import std/unicode + import unicode doAssert runeToEntity(Rune(0)) == "" doAssert runeToEntity(Rune(-1)) == "" doAssert runeToEntity("Ü".runeAt(0)) == "#220" @@ -377,11 +374,11 @@ proc runeToEntity*(rune: Rune): string = else: result = '#' & $rune.ord proc entityToRune*(entity: string): Rune = - ## Converts an HTML entity name like `Ü` or values like `Ü` - ## or `Ü` to its UTF-8 equivalent. + ## Converts an HTML entity name like ``Ü`` or values like ``Ü`` + ## or ``Ü`` to its UTF-8 equivalent. ## Rune(0) is returned if the entity name is unknown. runnableExamples: - import std/unicode + import unicode doAssert entityToRune("") == Rune(0) doAssert entityToRune("a") == Rune(0) doAssert entityToRune("gt") == ">".runeAt(0) @@ -394,11 +391,11 @@ proc entityToRune*(entity: string): Rune = case entity[1] of '0'..'9': try: runeValue = parseInt(entity[1..^1]) - except ValueError: discard + except: discard of 'x', 'X': # not case sensitive here try: runeValue = parseHexInt(entity[2..^1]) - except ValueError: discard - else: discard # other entities are not defined with prefix `#` + except: discard + else: discard # other entities are not defined with prefix ``#`` if runeValue notin 0..0x10FFFF: runeValue = 0 # only return legal values return Rune(runeValue) case entity # entity names are case sensitive @@ -1870,8 +1867,8 @@ proc entityToRune*(entity: string): Rune = else: Rune(0) proc entityToUtf8*(entity: string): string = - ## Converts an HTML entity name like `Ü` or values like `Ü` - ## or `Ü` to its UTF-8 equivalent. + ## Converts an HTML entity name like ``Ü`` or values like ``Ü`` + ## or ``Ü`` to its UTF-8 equivalent. ## "" is returned if the entity name is unknown. The HTML parser ## already converts entities to UTF-8. runnableExamples: @@ -1908,7 +1905,7 @@ template adderr(x: untyped) = proc untilElementEnd(x: var XmlParser, result: XmlNode, errors: var seq[string]) = - # we parsed e.g. `
` and don't really expect a `
`: + # we parsed e.g. ``
`` and don't really expect a ``
``: if result.htmlTag in SingleTags: if x.kind != xmlElementEnd or cmpIgnoreCase(x.elemName, result.tag) != 0: return @@ -1917,8 +1914,8 @@ proc untilElementEnd(x: var XmlParser, result: XmlNode, of xmlElementStart, xmlElementOpen: case result.htmlTag of tagP, tagInput, tagOption: - # some tags are common to have no ``, like `
  • ` but - # allow `

    ` in `

    `, `
    ` and `
  • ` in next case + # some tags are common to have no ````, like ``
  • `` but + # allow ``

    `` in `

    `, `
    ` and ``
  • `` in next case if htmlTag(x.elemName) in {tagLi, tagP, tagDt, tagDd, tagInput, tagOption}: adderr(expected(x, result)) @@ -2015,7 +2012,7 @@ proc parse(x: var XmlParser, errors: var seq[string]): XmlNode = proc parseHtml*(s: Stream, filename: string, errors: var seq[string]): XmlNode = - ## Parses the XML from stream `s` and returns a `XmlNode`. Every + ## Parses the XML from stream `s` and returns a ``XmlNode``. Every ## occurred parsing error is added to the `errors` sequence. var x: XmlParser open(x, s, filename, {reportComments, reportWhitespace, allowUnquotedAttribs, @@ -2039,27 +2036,27 @@ proc parseHtml*(s: Stream, filename: string, result = result[0] proc parseHtml*(s: Stream): XmlNode = - ## Parses the HTML from stream `s` and returns a `XmlNode`. All parsing + ## Parses the HTML from stream `s` and returns a ``XmlNode``. All parsing ## errors are ignored. var errors: seq[string] = @[] result = parseHtml(s, "unknown_html_doc", errors) proc parseHtml*(html: string): XmlNode = - ## Parses the HTML from string `html` and returns a `XmlNode`. All parsing + ## Parses the HTML from string ``html`` and returns a ``XmlNode``. All parsing ## errors are ignored. parseHtml(newStringStream(html)) proc loadHtml*(path: string, errors: var seq[string]): XmlNode = - ## Loads and parses HTML from file specified by `path`, and returns - ## a `XmlNode`. Every occurred parsing error is added to + ## Loads and parses HTML from file specified by ``path``, and returns + ## a ``XmlNode``. Every occurred parsing error is added to ## the `errors` sequence. var s = newFileStream(path, fmRead) if s == nil: raise newException(IOError, "Unable to read file: " & path) result = parseHtml(s, path, errors) proc loadHtml*(path: string): XmlNode = - ## Loads and parses HTML from file specified by `path`, and returns - ## a `XmlNode`. All parsing errors are ignored. + ## Loads and parses HTML from file specified by ``path``, and returns + ## a ``XmlNode``. All parsing errors are ignored. var errors: seq[string] = @[] result = loadHtml(path, errors) diff --git a/lib/pure/httpclient.nim b/lib/pure/httpclient.nim index d2cf64149..7c062c2e1 100644 --- a/lib/pure/httpclient.nim +++ b/lib/pure/httpclient.nim @@ -14,47 +14,33 @@ ## ==================== ## ## This example uses HTTP GET to retrieve -## `http://google.com`: +## ``http://google.com``: ## ## .. code-block:: Nim -## import std/httpclient +## import httpClient ## var client = newHttpClient() -## try: -## echo client.getContent("http://google.com") -## finally: -## client.close() +## echo client.getContent("http://google.com") ## ## The same action can also be performed asynchronously, simply use the -## `AsyncHttpClient`: +## ``AsyncHttpClient``: ## ## .. code-block:: Nim -## import std/[asyncdispatch, httpclient] +## import httpClient +## var client = newAsyncHttpClient() +## echo await client.getContent("http://google.com") ## -## proc asyncProc(): Future[string] {.async.} = -## var client = newAsyncHttpClient() -## try: -## return await client.getContent("http://google.com") -## finally: -## client.close() -## -## echo waitFor asyncProc() -## -## The functionality implemented by `HttpClient` and `AsyncHttpClient` +## The functionality implemented by ``HttpClient`` and ``AsyncHttpClient`` ## is the same, so you can use whichever one suits you best in the examples ## shown here. ## -## **Note:** You need to run asynchronous examples in an async proc -## otherwise you will get an `Undeclared identifier: 'await'` error. -## -## **Note:** An asynchronous client instance can only deal with one -## request at a time. To send multiple requests in parallel, use -## multiple client instances. +## **Note:** You will need to run asynchronous examples in an async proc +## otherwise you will get an ``Undeclared identifier: 'await'`` error. ## ## Using HTTP POST ## =============== ## ## This example demonstrates the usage of the W3 HTML Validator, it -## uses `multipart/form-data` as the `Content-Type` to send the HTML to be +## uses ``multipart/form-data`` as the ``Content-Type`` to send the HTML to be ## validated to the server. ## ## .. code-block:: Nim @@ -63,43 +49,23 @@ ## data["output"] = "soap12" ## data["uploaded_file"] = ("test.html", "text/html", ## "

    test

    ") -## try: -## echo client.postContent("http://validator.w3.org/check", multipart=data) -## finally: -## client.close() ## -## To stream files from disk when performing the request, use `addFiles`. -## -## **Note:** This will allocate a new `Mimetypes` database every time you call -## it, you can pass your own via the `mimeDb` parameter to avoid this. -## -## .. code-block:: Nim -## let mimes = newMimetypes() -## var client = newHttpClient() -## var data = newMultipartData() -## data.addFiles({"uploaded_file": "test.html"}, mimeDb = mimes) -## try: -## echo client.postContent("http://validator.w3.org/check", multipart=data) -## finally: -## client.close() +## echo client.postContent("http://validator.w3.org/check", multipart=data) ## ## You can also make post requests with custom headers. -## This example sets `Content-Type` to `application/json` +## This example sets ``Content-Type`` to ``application/json`` ## and uses a json object for the body ## ## .. code-block:: Nim -## import std/[httpclient, json] +## import httpclient, json ## ## let client = newHttpClient() ## client.headers = newHttpHeaders({ "Content-Type": "application/json" }) ## let body = %*{ ## "data": "some text" ## } -## try: -## let response = client.request("http://some.api", httpMethod = HttpPost, body = $body) -## echo response.status -## finally: -## client.close() +## let response = client.request("http://some.api", httpMethod = HttpPost, body = $body) +## echo response.status ## ## Progress reporting ## ================== @@ -109,7 +75,7 @@ ## progress of the HTTP request. ## ## .. code-block:: Nim -## import std/[asyncdispatch, httpclient] +## import asyncdispatch, httpclient ## ## proc onProgressChanged(total, progress, speed: BiggestInt) {.async.} = ## echo("Downloaded ", progress, " of ", total) @@ -118,51 +84,27 @@ ## proc asyncProc() {.async.} = ## var client = newAsyncHttpClient() ## client.onProgressChanged = onProgressChanged -## try: -## discard await client.getContent("http://speedtest-ams2.digitalocean.com/100mb.test") -## finally: -## client.close() +## discard await client.getContent("http://speedtest-ams2.digitalocean.com/100mb.test") ## ## waitFor asyncProc() ## -## If you would like to remove the callback simply set it to `nil`. +## If you would like to remove the callback simply set it to ``nil``. ## ## .. code-block:: Nim ## client.onProgressChanged = nil ## -## .. warning:: The `total` reported by httpclient may be 0 in some cases. +## **Warning:** The ``total`` reported by httpclient may be 0 in some cases. ## ## ## SSL/TLS support ## =============== -## This requires the OpenSSL library. Fortunately it's widely used and installed +## This requires the OpenSSL library, fortunately it's widely used and installed ## on many operating systems. httpclient will use SSL automatically if you give -## any of the functions a url with the `https` schema, for example: -## `https://github.com/`. +## any of the functions a url with the ``https`` schema, for example: +## ``https://github.com/``. ## -## You will also have to compile with `ssl` defined like so: -## `nim c -d:ssl ...`. -## -## Certificate validation is performed by default. -## -## A set of directories and files from the `ssl_certs `_ -## module are scanned to locate CA certificates. -## -## Example of setting SSL verification parameters in a new client: -## -## .. code-block:: Nim -## import httpclient -## var client = newHttpClient(sslContext=newContext(verifyMode=CVerifyPeer)) -## -## There are three options for verify mode: -## -## * ``CVerifyNone``: certificates are not verified; -## * ``CVerifyPeer``: certificates are verified; -## * ``CVerifyPeerUseEnvVars``: certificates are verified and the optional -## environment variables SSL_CERT_FILE and SSL_CERT_DIR are also used to -## locate certificates -## -## See `newContext `_ to tweak or disable certificate validation. +## You will also have to compile with ``ssl`` defined like so: +## ``nim c -d:ssl ...``. ## ## Timeouts ## ======== @@ -177,12 +119,12 @@ ## individual internal calls on the socket are affected. In practice this means ## that as long as the server is sending data an exception will not be raised, ## if however data does not reach the client within the specified timeout a -## `TimeoutError` exception will be raised. +## ``TimeoutError`` exception will be raised. ## -## Here is how to set a timeout when creating an `HttpClient` instance: +## Here is how to set a timeout when creating an ``HttpClient`` instance: ## ## .. code-block:: Nim -## import std/httpclient +## import httpclient ## ## let client = newHttpClient(timeout = 42) ## @@ -190,29 +132,21 @@ ## ===== ## ## A proxy can be specified as a param to any of the procedures defined in -## this module. To do this, use the `newProxy` constructor. Unfortunately, +## this module. To do this, use the ``newProxy`` constructor. Unfortunately, ## only basic authentication is supported at the moment. ## -## Some examples on how to configure a Proxy for `HttpClient`: +## Some examples on how to configure a Proxy for ``HttpClient``: ## ## .. code-block:: Nim -## import std/httpclient +## import httpclient ## ## let myProxy = newProxy("http://myproxy.network") ## let client = newHttpClient(proxy = myProxy) ## -## Use proxies with basic authentication: -## -## .. code-block:: Nim -## import std/httpclient -## -## let myProxy = newProxy("http://myproxy.network", auth="user:password") -## let client = newHttpClient(proxy = myProxy) -## ## Get Proxy URL from environment variables: ## ## .. code-block:: Nim -## import std/httpclient +## import httpclient ## ## var url = "" ## try: @@ -229,30 +163,26 @@ ## Redirects ## ========= ## -## The maximum redirects can be set with the `maxRedirects` of `int` type, +## The maximum redirects can be set with the ``maxRedirects`` of ``int`` type, ## it specifies the maximum amount of redirects to follow, -## it defaults to `5`, you can set it to `0` to disable redirects. +## it defaults to ``5``, you can set it to ``0`` to disable redirects. ## -## Here you can see an example about how to set the `maxRedirects` of `HttpClient`: +## Here you can see an example about how to set the ``maxRedirects`` of ``HttpClient``: ## ## .. code-block:: Nim -## import std/httpclient +## import httpclient ## ## let client = newHttpClient(maxRedirects = 0) ## -import std/private/since +include "system/inclrtl" -import std/[ - net, strutils, uri, parseutils, base64, os, mimetypes, - math, random, httpcore, times, tables, streams, monotimes, - asyncnet, asyncdispatch, asyncfile, nativesockets, -] +import net, strutils, uri, parseutils, base64, os, mimetypes, + math, random, httpcore, times, tables, streams, std/monotimes +import asyncnet, asyncdispatch, asyncfile +import nativesockets -when defined(nimPreviewSlimSystem): - import std/[assertions, syncio] - -export httpcore except parseHeader # TODO: The `except` doesn't work +export httpcore except parseHeader # TODO: The ``except`` doesn't work type Response* = ref object @@ -270,14 +200,14 @@ type bodyStream*: FutureStream[string] proc code*(response: Response | AsyncResponse): HttpCode - {.raises: [ValueError, OverflowDefect].} = - ## Retrieves the specified response's `HttpCode`. + {.raises: [ValueError, OverflowError].} = + ## Retrieves the specified response's ``HttpCode``. ## - ## Raises a `ValueError` if the response's `status` does not have a - ## corresponding `HttpCode`. + ## Raises a ``ValueError`` if the response's ``status`` does not have a + ## corresponding ``HttpCode``. return response.status[0 .. 2].parseInt.HttpCode -proc contentType*(response: Response | AsyncResponse): string {.inline.} = +proc contentType*(response: Response | AsyncResponse): string = ## Retrieves the specified response's content type. ## ## This is effectively the value of the "Content-Type" header. @@ -288,17 +218,16 @@ proc contentLength*(response: Response | AsyncResponse): int = ## ## This is effectively the value of the "Content-Length" header. ## - ## A `ValueError` exception will be raised if the value is not an integer. - ## If the Content-Length header is not set in the response, ContentLength is set to the value -1. - var contentLengthHeader = response.headers.getOrDefault("Content-Length", @["-1"]) - result = contentLengthHeader.parseInt() + ## A ``ValueError`` exception will be raised if the value is not an integer. + var contentLengthHeader = response.headers.getOrDefault("Content-Length") + return contentLengthHeader.parseInt() proc lastModified*(response: Response | AsyncResponse): DateTime = ## Retrieves the specified response's last modified time. ## ## This is effectively the value of the "Last-Modified" header. ## - ## Raises a `ValueError` if the parsing fails or the value is not a correctly + ## Raises a ``ValueError`` if the parsing fails or the value is not a correctly ## formatted time. var lastModifiedHeader = response.headers.getOrDefault("last-modified") result = parse(lastModifiedHeader, "ddd, dd MMM yyyy HH:mm:ss 'GMT'", utc()) @@ -323,25 +252,16 @@ type url*: Uri auth*: string - MultipartEntry = object - name, content: string - case isFile: bool - of true: - filename, contentType: string - fileSize: int64 - isStream: bool - else: discard - MultipartEntries* = openArray[tuple[name, content: string]] MultipartData* = ref object - content: seq[MultipartEntry] + content: seq[string] ProtocolError* = object of IOError ## exception that is raised when server ## does not conform to the implemented ## protocol - HttpRequestError* = object of IOError ## Thrown in the `getContent` proc - ## and `postContent` proc, + HttpRequestError* = object of IOError ## Thrown in the ``getContent`` proc + ## and ``postContent`` proc, ## when the server returns an error const defUserAgent* = "Nim httpclient/" & NimVersion @@ -358,6 +278,7 @@ proc fileError(msg: string) = e.msg = msg raise e + when not defined(ssl): type SslContext = ref object var defaultSslContext {.threadvar.}: SslContext @@ -366,42 +287,34 @@ proc getDefaultSSL(): SslContext = result = defaultSslContext when defined(ssl): if result == nil: - defaultSslContext = newContext(verifyMode = CVerifyPeer) + defaultSslContext = newContext(verifyMode = CVerifyNone) result = defaultSslContext doAssert result != nil, "failure to initialize the SSL context" -proc newProxy*(url: string; auth = ""): Proxy = - ## Constructs a new `TProxy` object. +proc newProxy*(url: string, auth = ""): Proxy = + ## Constructs a new ``TProxy`` object. result = Proxy(url: parseUri(url), auth: auth) -proc newProxy*(url: Uri; auth = ""): Proxy = - ## Constructs a new `TProxy` object. - result = Proxy(url: url, auth: auth) +proc newMultipartData*: MultipartData = + ## Constructs a new ``MultipartData`` object. + MultipartData(content: @[]) -proc newMultipartData*: MultipartData {.inline.} = - ## Constructs a new `MultipartData` object. - MultipartData() proc `$`*(data: MultipartData): string {.since: (1, 1).} = ## convert MultipartData to string so it's human readable when echo ## see https://github.com/nim-lang/Nim/issues/11863 - const sep = "-".repeat(30) - for pos, entry in data.content: - result.add(sep & center($pos, 3) & sep) - result.add("\nname=\"" & entry.name & "\"") - if entry.isFile: - result.add("; filename=\"" & entry.filename & "\"\n") - result.add("Content-Type: " & entry.contentType) - result.add("\n\n" & entry.content & "\n") + const prefixLen = "Content-Disposition: form-data; ".len + for pos, item in data.content: + result &= "------------------------------ " + result.addInt pos + result &= " ------------------------------\n" + result &= item[prefixLen .. item.high] -proc add*(p: MultipartData, name, content: string, filename: string = "", - contentType: string = "", useStream = true) = - ## Add a value to the multipart data. - ## - ## When `useStream` is `false`, the file will be read into memory. - ## - ## Raises a `ValueError` exception if +proc add*(p: var MultipartData, name, content: string, filename: string = "", + contentType: string = "") = + ## Add a value to the multipart data. Raises a `ValueError` exception if ## `name`, `filename` or `contentType` contain newline characters. + if {'\c', '\L'} in name: raise newException(ValueError, "name contains a newline character") if {'\c', '\L'} in filename: @@ -409,20 +322,17 @@ proc add*(p: MultipartData, name, content: string, filename: string = "", if {'\c', '\L'} in contentType: raise newException(ValueError, "contentType contains a newline character") - var entry = MultipartEntry( - name: name, - content: content, - isFile: filename.len > 0 - ) + var str = "Content-Disposition: form-data; name=\"" & name & "\"" + if filename.len > 0: + str.add("; filename=\"" & filename & "\"") + str.add("\c\L") + if contentType.len > 0: + str.add("Content-Type: " & contentType & "\c\L") + str.add("\c\L" & content & "\c\L") - if entry.isFile: - entry.isStream = useStream - entry.filename = filename - entry.contentType = contentType + p.content.add(str) - p.content.add(entry) - -proc add*(p: MultipartData, xs: MultipartEntries): MultipartData +proc add*(p: var MultipartData, xs: MultipartEntries): MultipartData {.discardable.} = ## Add a list of multipart entries to the multipart data `p`. All values are ## added without a filename and without a content type. @@ -439,32 +349,28 @@ proc newMultipartData*(xs: MultipartEntries): MultipartData = ## ## .. code-block:: Nim ## var data = newMultipartData({"action": "login", "format": "json"}) - result = MultipartData() - for entry in xs: - result.add(entry.name, entry.content) + result = MultipartData(content: @[]) + result.add(xs) -proc addFiles*(p: MultipartData, xs: openArray[tuple[name, file: string]], - mimeDb = newMimetypes(), useStream = true): - MultipartData {.discardable.} = - ## Add files to a multipart data object. The files will be streamed from disk - ## when the request is being made. When `stream` is `false`, the files are - ## instead read into memory, but beware this is very memory ineffecient even - ## for small files. The MIME types will automatically be determined. - ## Raises an `IOError` if the file cannot be opened or reading fails. To - ## manually specify file content, filename and MIME type, use `[]=` instead. +proc addFiles*(p: var MultipartData, xs: openArray[tuple[name, file: string]]): + MultipartData {.discardable.} = + ## Add files to a multipart data object. The file will be opened from your + ## disk, read and sent with the automatically determined MIME type. Raises an + ## `IOError` if the file cannot be opened or reading fails. To manually + ## specify file content, filename and MIME type, use `[]=` instead. ## ## .. code-block:: Nim ## data.addFiles({"uploaded_file": "public/test.html"}) + var m = newMimetypes() for name, file in xs.items: var contentType: string let (_, fName, ext) = splitFile(file) if ext.len > 0: - contentType = mimeDb.getMimetype(ext[1..ext.high], "") - let content = if useStream: file else: readFile(file) - p.add(name, content, fName & ext, contentType, useStream = useStream) + contentType = m.getMimetype(ext[1..ext.high], "") + p.add(name, readFile(file).string, fName & ext, contentType) result = p -proc `[]=`*(p: MultipartData, name, content: string) {.inline.} = +proc `[]=`*(p: var MultipartData, name, content: string) = ## Add a multipart entry to the multipart data `p`. The value is added ## without a filename and without a content type. ## @@ -472,57 +378,60 @@ proc `[]=`*(p: MultipartData, name, content: string) {.inline.} = ## data["username"] = "NimUser" p.add(name, content) -proc `[]=`*(p: MultipartData, name: string, - file: tuple[name, contentType, content: string]) {.inline.} = - ## Add a file to the multipart data `p`, specifying filename, contentType - ## and content manually. +proc `[]=`*(p: var MultipartData, name: string, + file: tuple[name, contentType, content: string]) = + ## Add a file to the multipart data `p`, specifying filename, contentType and + ## content manually. ## ## .. code-block:: Nim ## data["uploaded_file"] = ("test.html", "text/html", ## "

    test

    ") - p.add(name, file.content, file.name, file.contentType, useStream = false) + p.add(name, file.content, file.name, file.contentType) -proc getBoundary(p: MultipartData): string = - if p == nil or p.content.len == 0: return +proc format(p: MultipartData): tuple[contentType, body: string] = + if p == nil or p.content.len == 0: + return ("", "") + + # Create boundary that is not in the data to be formatted + var bound: string while true: - result = $rand(int.high) - for i, entry in p.content: - if result in entry.content: break - elif i == p.content.high: return + bound = $random(int.high) + var found = false + for s in p.content: + if bound in s: + found = true + if not found: + break -proc sendFile(socket: Socket | AsyncSocket, - entry: MultipartEntry) {.multisync.} = - const chunkSize = 2^18 - let file = - when socket is AsyncSocket: openAsync(entry.content) - else: newFileStream(entry.content, fmRead) + result.contentType = "multipart/form-data; boundary=" & bound + result.body = "" + for s in p.content: + result.body.add("--" & bound & "\c\L" & s) + result.body.add("--" & bound & "--\c\L") - var buffer: string - while true: - buffer = - when socket is AsyncSocket: (await read(file, chunkSize)) - else: readStr(file, chunkSize) - if buffer.len == 0: break - await socket.send(buffer) - file.close() +proc redirection(status: string): bool = + const redirectionNRs = ["301", "302", "303", "307"] + for i in items(redirectionNRs): + if status.startsWith(i): + return true -proc getNewLocation(lastURL: Uri, headers: HttpHeaders): Uri = - let newLocation = headers.getOrDefault"Location" - if newLocation == "": httpError("location header expected") +proc getNewLocation(lastURL: string, headers: HttpHeaders): string = + result = headers.getOrDefault"Location" + if result == "": httpError("location header expected") # Relative URLs. (Not part of the spec, but soon will be.) - let parsedLocation = parseUri(newLocation) - if parsedLocation.hostname == "" and parsedLocation.path != "": - result = lastURL - result.path = parsedLocation.path - result.query = parsedLocation.query - result.anchor = parsedLocation.anchor - else: - result = parsedLocation + let r = parseUri(result) + if r.hostname == "" and r.path != "": + var parsed = parseUri(lastURL) + parsed.path = r.path + parsed.query = r.query + parsed.anchor = r.anchor + result = $parsed -proc generateHeaders(requestUrl: Uri, httpMethod: HttpMethod, headers: HttpHeaders, - proxy: Proxy): string = +proc generateHeaders(requestUrl: Uri, httpMethod: string, + headers: HttpHeaders, body: string, proxy: Proxy): string = # GET - result = $httpMethod + let upperMethod = httpMethod.toUpperAscii() + result = upperMethod result.add ' ' if proxy.isNil or requestUrl.scheme == "https": @@ -538,28 +447,34 @@ proc generateHeaders(requestUrl: Uri, httpMethod: HttpMethod, headers: HttpHeade result.add($modifiedUrl) # HTTP/1.1\c\l - result.add(" HTTP/1.1" & httpNewLine) + result.add(" HTTP/1.1\c\L") # Host header. if not headers.hasKey("Host"): if requestUrl.port == "": - add(result, "Host: " & requestUrl.hostname & httpNewLine) + add(result, "Host: " & requestUrl.hostname & "\c\L") else: - add(result, "Host: " & requestUrl.hostname & ":" & requestUrl.port & httpNewLine) + add(result, "Host: " & requestUrl.hostname & ":" & requestUrl.port & "\c\L") # Connection header. if not headers.hasKey("Connection"): - add(result, "Connection: Keep-Alive" & httpNewLine) + add(result, "Connection: Keep-Alive\c\L") + + # Content length header. + const requiresBody = ["POST", "PUT", "PATCH"] + let needsContentLength = body.len > 0 or upperMethod in requiresBody + if needsContentLength and not headers.hasKey("Content-Length"): + add(result, "Content-Length: " & $body.len & "\c\L") # Proxy auth header. if not proxy.isNil and proxy.auth != "": let auth = base64.encode(proxy.auth) - add(result, "Proxy-Authorization: Basic " & auth & httpNewLine) + add(result, "Proxy-Authorization: basic " & auth & "\c\L") for key, val in headers: - add(result, key & ": " & val & httpNewLine) + add(result, key & ": " & val & "\c\L") - add(result, httpNewLine) + add(result, "\c\L") type ProgressChangedProc*[ReturnType] = @@ -571,11 +486,11 @@ type connected: bool currentURL: Uri ## Where we are currently connected. headers*: HttpHeaders ## Headers to send in requests. - maxRedirects: Natural ## Maximum redirects, set to `0` to disable. + maxRedirects: Natural ## Maximum redirects, set to ``0`` to disable. userAgent: string timeout*: int ## Only used for blocking HttpClient for now. proxy: Proxy - ## `nil` or the callback to call when request progress changes. + ## ``nil`` or the callback to call when request progress changes. when SocketType is Socket: onProgressChanged*: ProgressChangedProc[void] else: @@ -596,34 +511,26 @@ type type HttpClient* = HttpClientBase[Socket] -proc newHttpClient*(userAgent = defUserAgent, maxRedirects = 5, - sslContext = getDefaultSSL(), proxy: Proxy = nil, - timeout = -1, headers = newHttpHeaders()): HttpClient = +proc newHttpClient*(userAgent = defUserAgent, + maxRedirects = 5, sslContext = getDefaultSSL(), proxy: Proxy = nil, + timeout = -1, headers = newHttpHeaders()): HttpClient = ## Creates a new HttpClient instance. ## - ## `userAgent` specifies the user agent that will be used when making + ## ``userAgent`` specifies the user agent that will be used when making ## requests. ## - ## `maxRedirects` specifies the maximum amount of redirects to follow, + ## ``maxRedirects`` specifies the maximum amount of redirects to follow, ## default is 5. ## - ## `sslContext` specifies the SSL context to use for HTTPS requests. - ## See `SSL/TLS support <#sslslashtls-support>`_ + ## ``sslContext`` specifies the SSL context to use for HTTPS requests. ## - ## `proxy` specifies an HTTP proxy to use for this HTTP client's + ## ``proxy`` specifies an HTTP proxy to use for this HTTP client's ## connections. ## - ## `timeout` specifies the number of milliseconds to allow before a - ## `TimeoutError` is raised. + ## ``timeout`` specifies the number of milliseconds to allow before a + ## ``TimeoutError`` is raised. ## - ## `headers` specifies the HTTP Headers. - runnableExamples: - import std/strutils - - let exampleHtml = newHttpClient().getContent("http://example.com") - assert "Example Domain" in exampleHtml - assert "Pizza" notin exampleHtml - + ## ``headers`` specifies the HTTP Headers. new result result.headers = headers result.userAgent = userAgent @@ -639,34 +546,23 @@ proc newHttpClient*(userAgent = defUserAgent, maxRedirects = 5, type AsyncHttpClient* = HttpClientBase[AsyncSocket] -proc newAsyncHttpClient*(userAgent = defUserAgent, maxRedirects = 5, - sslContext = getDefaultSSL(), proxy: Proxy = nil, - headers = newHttpHeaders()): AsyncHttpClient = +proc newAsyncHttpClient*(userAgent = defUserAgent, + maxRedirects = 5, sslContext = getDefaultSSL(), + proxy: Proxy = nil, headers = newHttpHeaders()): AsyncHttpClient = ## Creates a new AsyncHttpClient instance. ## - ## `userAgent` specifies the user agent that will be used when making + ## ``userAgent`` specifies the user agent that will be used when making ## requests. ## - ## `maxRedirects` specifies the maximum amount of redirects to follow, + ## ``maxRedirects`` specifies the maximum amount of redirects to follow, ## default is 5. ## - ## `sslContext` specifies the SSL context to use for HTTPS requests. + ## ``sslContext`` specifies the SSL context to use for HTTPS requests. ## - ## `proxy` specifies an HTTP proxy to use for this HTTP client's + ## ``proxy`` specifies an HTTP proxy to use for this HTTP client's ## connections. ## - ## `headers` specifies the HTTP Headers. - runnableExamples: - import std/[asyncdispatch, strutils] - - proc asyncProc(): Future[string] {.async.} = - let client = newAsyncHttpClient() - result = await client.getContent("http://example.com") - - let exampleHtml = waitFor asyncProc() - assert "Example Domain" in exampleHtml - assert "Pizza" notin exampleHtml - + ## ``headers`` specifies the HTTP Headers. new result result.headers = headers result.userAgent = userAgent @@ -685,7 +581,7 @@ proc close*(client: HttpClient | AsyncHttpClient) = client.socket.close() client.connected = false -proc getSocket*(client: HttpClient): Socket {.inline.} = +proc getSocket*(client: HttpClient): Socket = ## Get network socket, useful if you want to find out more details about the connection ## ## this example shows info about local and remote endpoints @@ -697,14 +593,14 @@ proc getSocket*(client: HttpClient): Socket {.inline.} = ## return client.socket -proc getSocket*(client: AsyncHttpClient): AsyncSocket {.inline.} = +proc getSocket*(client: AsyncHttpClient): AsyncSocket = return client.socket proc reportProgress(client: HttpClient | AsyncHttpClient, progress: BiggestInt) {.multisync.} = client.contentProgress += progress client.oneSecondProgress += progress - if (getMonoTime() - client.lastProgressReport).inSeconds >= 1: + if (getMonoTime() - client.lastProgressReport).inSeconds > 1: if not client.onProgressChanged.isNil: await client.onProgressChanged(client.contentTotal, client.contentProgress, @@ -742,7 +638,7 @@ proc parseChunks(client: HttpClient | AsyncHttpClient): Future[void] {.multisync.} = while true: var chunkSize = 0 - var chunkSizeStr = await client.socket.recvLine() + var chunkSizeStr = (await client.socket.recvLine()).string var i = 0 if chunkSizeStr == "": httpError("Server terminated connection prematurely") @@ -775,7 +671,8 @@ proc parseChunks(client: HttpClient | AsyncHttpClient): Future[void] # Trailer headers will only be sent if the request specifies that we want # them: http://tools.ietf.org/html/rfc2616#section-3.6.1 -proc parseBody(client: HttpClient | AsyncHttpClient, headers: HttpHeaders, +proc parseBody(client: HttpClient | AsyncHttpClient, + headers: HttpHeaders, httpVersion: string): Future[void] {.multisync.} = # Reset progress from previous requests. client.contentTotal = 0 @@ -802,7 +699,7 @@ proc parseBody(client: HttpClient | AsyncHttpClient, headers: HttpHeaders, httpError("Got disconnected while trying to read body.") if recvLen != length: httpError("Received length doesn't match expected length. Wanted " & - $length & " got: " & $recvLen) + $length & " got " & $recvLen) else: # (http://tools.ietf.org/html/rfc2616#section-4.4) NR.4 TODO @@ -841,14 +738,14 @@ proc parseResponse(client: HttpClient | AsyncHttpClient, while true: linei = 0 when client is HttpClient: - line = await client.socket.recvLine(client.timeout) + line = (await client.socket.recvLine(client.timeout)).string else: - line = await client.socket.recvLine() + line = (await client.socket.recvLine()).string if line == "": # We've been disconnected. client.close() break - if line == httpNewLine: + if line == "\c\L": fullyRead = true break if not parsedStatus: @@ -884,25 +781,17 @@ proc parseResponse(client: HttpClient | AsyncHttpClient, if not fullyRead: httpError("Connection was closed before full request has been made") - when client is HttpClient: - result.bodyStream = newStringStream() - else: - result.bodyStream = newFutureStream[string]("parseResponse") - - if getBody and result.code != Http204: - client.bodyStream = result.bodyStream + if getBody: when client is HttpClient: + client.bodyStream = newStringStream() + result.bodyStream = client.bodyStream parseBody(client, result.headers, result.version) else: + client.bodyStream = newFutureStream[string]("parseResponse") + result.bodyStream = client.bodyStream assert(client.parseBodyFut.isNil or client.parseBodyFut.finished) - # do not wait here for the body request to complete client.parseBodyFut = parseBody(client, result.headers, result.version) - client.parseBodyFut.addCallback do(): - if client.parseBodyFut.failed: - client.bodyStream.fail(client.parseBodyFut.error) - else: - when client is AsyncHttpClient: - result.bodyStream.complete() + # do not wait here for the body request to complete proc newConnection(client: HttpClient | AsyncHttpClient, url: Uri) {.multisync.} = @@ -956,8 +845,8 @@ proc newConnection(client: HttpClient | AsyncHttpClient, connectUrl.hostname = url.hostname connectUrl.port = if url.port != "": url.port else: "443" - let proxyHeaderString = generateHeaders(connectUrl, HttpConnect, - newHttpHeaders(), client.proxy) + let proxyHeaderString = generateHeaders(connectUrl, $HttpConnect, + newHttpHeaders(), "", client.proxy) await client.socket.send(proxyHeaderString) let proxyResp = await parseResponse(client, false) @@ -975,65 +864,25 @@ proc newConnection(client: HttpClient | AsyncHttpClient, client.currentURL = url client.connected = true -proc readFileSizes(client: HttpClient | AsyncHttpClient, - multipart: MultipartData) {.multisync.} = - for entry in multipart.content.mitems(): - if not entry.isFile: continue - if not entry.isStream: - entry.fileSize = entry.content.len - continue - - # TODO: look into making getFileSize work with async - let fileSize = getFileSize(entry.content) - entry.fileSize = fileSize - -proc format(entry: MultipartEntry, boundary: string): string = - result = "--" & boundary & httpNewLine - result.add("Content-Disposition: form-data; name=\"" & entry.name & "\"") - if entry.isFile: - result.add("; filename=\"" & entry.filename & "\"" & httpNewLine) - result.add("Content-Type: " & entry.contentType & httpNewLine) - else: - result.add(httpNewLine & httpNewLine & entry.content) - -proc format(client: HttpClient | AsyncHttpClient, - multipart: MultipartData): Future[seq[string]] {.multisync.} = - let bound = getBoundary(multipart) - client.headers["Content-Type"] = "multipart/form-data; boundary=" & bound - - await client.readFileSizes(multipart) - - var length: int64 - for entry in multipart.content: - result.add(format(entry, bound) & httpNewLine) - if entry.isFile: - length += entry.fileSize + httpNewLine.len - - result.add "--" & bound & "--" & httpNewLine - - for s in result: length += s.len - client.headers["Content-Length"] = $length - proc override(fallback, override: HttpHeaders): HttpHeaders = # Right-biased map union for `HttpHeaders` + if override.isNil: + return fallback result = newHttpHeaders() # Copy by value result.table[] = fallback.table[] - - if override.isNil: - # Return the copy of fallback so it does not get modified - return result - for k, vs in override.table: result[k] = vs -proc requestAux(client: HttpClient | AsyncHttpClient, url: Uri, - httpMethod: HttpMethod, body = "", headers: HttpHeaders = nil, - multipart: MultipartData = nil): Future[Response | AsyncResponse] +proc requestAux(client: HttpClient | AsyncHttpClient, url: string, + httpMethod: string, body = "", + headers: HttpHeaders = nil): Future[Response | AsyncResponse] {.multisync.} = # Helper that actually makes the request. Does not handle redirects. - if url.scheme == "": + let requestUrl = parseUri(url) + + if requestUrl.scheme == "": raise newException(ValueError, "No uri scheme supplied.") when client is AsyncHttpClient: @@ -1042,160 +891,68 @@ proc requestAux(client: HttpClient | AsyncHttpClient, url: Uri, await client.parseBodyFut client.parseBodyFut = nil - await newConnection(client, url) + await newConnection(client, requestUrl) - var newHeaders: HttpHeaders + let effectiveHeaders = client.headers.override(headers) - var data: seq[string] - if multipart != nil and multipart.content.len > 0: - # `format` modifies `client.headers`, see - # https://github.com/nim-lang/Nim/pull/18208#discussion_r647036979 - data = await client.format(multipart) - newHeaders = client.headers.override(headers) - else: - newHeaders = client.headers.override(headers) - # Only change headers if they have not been specified already - if not newHeaders.hasKey("Content-Length"): - if body.len != 0: - newHeaders["Content-Length"] = $body.len - elif httpMethod notin {HttpGet, HttpHead}: - newHeaders["Content-Length"] = "0" + if not effectiveHeaders.hasKey("user-agent") and client.userAgent != "": + effectiveHeaders["User-Agent"] = client.userAgent - if not newHeaders.hasKey("user-agent") and client.userAgent.len > 0: - newHeaders["User-Agent"] = client.userAgent + var headersString = generateHeaders(requestUrl, httpMethod, + effectiveHeaders, body, client.proxy) - let headerString = generateHeaders(url, httpMethod, newHeaders, - client.proxy) - await client.socket.send(headerString) - - if data.len > 0: - var buffer: string - for i, entry in multipart.content: - buffer.add data[i] - if not entry.isFile: continue - if buffer.len > 0: - await client.socket.send(buffer) - buffer.setLen(0) - if entry.isStream: - await client.socket.sendFile(entry) - else: - await client.socket.send(entry.content) - buffer.add httpNewLine - # send the rest and the last boundary - await client.socket.send(buffer & data[^1]) - elif body.len > 0: + await client.socket.send(headersString) + if body != "": await client.socket.send(body) - let getBody = httpMethod notin {HttpHead, HttpConnect} and + let getBody = httpMethod.toLowerAscii() notin ["head", "connect"] and client.getBody result = await parseResponse(client, getBody) -proc request*(client: HttpClient | AsyncHttpClient, url: Uri | string, - httpMethod: HttpMethod | string = HttpGet, body = "", - headers: HttpHeaders = nil, - multipart: MultipartData = nil): Future[Response | AsyncResponse] +proc request*(client: HttpClient | AsyncHttpClient, url: string, + httpMethod: string, body = "", + headers: HttpHeaders = nil): Future[Response | AsyncResponse] {.multisync.} = ## Connects to the hostname specified by the URL and performs a request - ## using the custom method string specified by `httpMethod`. + ## using the custom method string specified by ``httpMethod``. ## - ## Connection will be kept alive. Further requests on the same `client` to + ## Connection will be kept alive. Further requests on the same ``client`` to ## the same hostname will not require a new connection to be made. The - ## connection can be closed by using the `close` procedure. + ## connection can be closed by using the ``close`` procedure. ## ## This procedure will follow redirects up to a maximum number of redirects - ## specified in `client.maxRedirects`. - ## - ## You need to make sure that the `url` doesn't contain any newline - ## characters. Failing to do so will raise `AssertionDefect`. - ## - ## `headers` are HTTP headers that override the `client.headers` for - ## this specific request only and will not be persisted. - ## - ## **Deprecated since v1.5**: use HttpMethod enum instead; string parameter httpMethod is deprecated - when url is string: - doAssert(not url.contains({'\c', '\L'}), "url shouldn't contain any newline characters") - let url = parseUri(url) - - when httpMethod is string: - {.warning: - "Deprecated since v1.5; use HttpMethod enum instead; string parameter httpMethod is deprecated".} - let httpMethod = case httpMethod - of "HEAD": - HttpHead - of "GET": - HttpGet - of "POST": - HttpPost - of "PUT": - HttpPut - of "DELETE": - HttpDelete - of "TRACE": - HttpTrace - of "OPTIONS": - HttpOptions - of "CONNECT": - HttpConnect - of "PATCH": - HttpPatch - else: - raise newException(ValueError, "Invalid HTTP method name: " & httpMethod) - - result = await client.requestAux(url, httpMethod, body, headers, multipart) + ## specified in ``client.maxRedirects``. + result = await client.requestAux(url, httpMethod, body, headers) var lastURL = url for i in 1..client.maxRedirects: - let statusCode = result.code + if result.status.redirection(): + let redirectTo = getNewLocation(lastURL, result.headers) + # Guarantee method for HTTP 307: see https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/307 + var meth = if result.status == "307": httpMethod else: "GET" + result = await client.requestAux(redirectTo, meth, body, headers) + lastURL = redirectTo - if statusCode notin {Http301, Http302, Http303, Http307, Http308}: - break - let redirectTo = getNewLocation(lastURL, result.headers) - var redirectMethod: HttpMethod - var redirectBody: string - # For more informations about the redirect methods see: - # https://developer.mozilla.org/en-US/docs/Web/HTTP/Redirections - case statusCode - of Http301, Http302, Http303: - # The method is changed to GET unless it is GET or HEAD (RFC2616) - if httpMethod notin {HttpGet, HttpHead}: - redirectMethod = HttpGet - else: - redirectMethod = httpMethod - # The body is stripped away - redirectBody = "" - # Delete any header value associated with the body - if not headers.isNil(): - headers.del("Content-Length") - headers.del("Content-Type") - headers.del("Transfer-Encoding") - of Http307, Http308: - # The method and the body are unchanged - redirectMethod = httpMethod - redirectBody = body - else: - # Unreachable - doAssert(false) - - # Check if the redirection is to the same domain or a sub-domain (foo.com - # -> sub.foo.com) - if redirectTo.hostname != lastURL.hostname and - not redirectTo.hostname.endsWith("." & lastURL.hostname): - # Perform some cleanup of the header values - if headers != nil: - # Delete the Host header - headers.del("Host") - # Do not send any sensitive info to a unknown host - headers.del("Authorization") - - result = await client.requestAux(redirectTo, redirectMethod, redirectBody, - headers, multipart) - lastURL = redirectTo +proc request*(client: HttpClient | AsyncHttpClient, url: string, + httpMethod = HttpGet, body = "", + headers: HttpHeaders = nil): Future[Response | AsyncResponse] + {.multisync.} = + ## Connects to the hostname specified by the URL and performs a request + ## using the method specified. + ## + ## Connection will be kept alive. Further requests on the same ``client`` to + ## the same hostname will not require a new connection to be made. The + ## connection can be closed by using the ``close`` procedure. + ## + ## When a request is made to a different hostname, the current connection will + ## be closed. + result = await request(client, url, $httpMethod, body, headers) proc responseContent(resp: Response | AsyncResponse): Future[string] {.multisync.} = ## Returns the content of a response as a string. ## - ## A `HttpRequestError` will be raised if the server responds with a + ## A ``HttpRequestError`` will be raised if the server responds with a ## client error (status code 4xx) or a server error (status code 5xx). if resp.code.is4xx or resp.code.is5xx: raise newException(HttpRequestError, resp.status) @@ -1203,87 +960,106 @@ proc responseContent(resp: Response | AsyncResponse): Future[string] {.multisync return await resp.bodyStream.readAll() proc head*(client: HttpClient | AsyncHttpClient, - url: Uri | string): Future[Response | AsyncResponse] {.multisync.} = + url: string): Future[Response | AsyncResponse] {.multisync.} = ## Connects to the hostname specified by the URL and performs a HEAD request. ## - ## This procedure uses httpClient values such as `client.maxRedirects`. + ## This procedure uses httpClient values such as ``client.maxRedirects``. result = await client.request(url, HttpHead) proc get*(client: HttpClient | AsyncHttpClient, - url: Uri | string): Future[Response | AsyncResponse] {.multisync.} = + url: string): Future[Response | AsyncResponse] {.multisync.} = ## Connects to the hostname specified by the URL and performs a GET request. ## - ## This procedure uses httpClient values such as `client.maxRedirects`. + ## This procedure uses httpClient values such as ``client.maxRedirects``. result = await client.request(url, HttpGet) proc getContent*(client: HttpClient | AsyncHttpClient, - url: Uri | string): Future[string] {.multisync.} = + url: string): Future[string] {.multisync.} = ## Connects to the hostname specified by the URL and returns the content of a GET request. let resp = await get(client, url) return await responseContent(resp) proc delete*(client: HttpClient | AsyncHttpClient, - url: Uri | string): Future[Response | AsyncResponse] {.multisync.} = + url: string): Future[Response | AsyncResponse] {.multisync.} = ## Connects to the hostname specified by the URL and performs a DELETE request. - ## This procedure uses httpClient values such as `client.maxRedirects`. + ## This procedure uses httpClient values such as ``client.maxRedirects``. result = await client.request(url, HttpDelete) proc deleteContent*(client: HttpClient | AsyncHttpClient, - url: Uri | string): Future[string] {.multisync.} = + url: string): Future[string] {.multisync.} = ## Connects to the hostname specified by the URL and returns the content of a DELETE request. let resp = await delete(client, url) return await responseContent(resp) -proc post*(client: HttpClient | AsyncHttpClient, url: Uri | string, body = "", +proc makeRequestContent(body = "", multipart: MultipartData = nil): (string, HttpHeaders) = + let (mpContentType, mpBody) = format(multipart) + # TODO: Support FutureStream for `body` parameter. + template withNewLine(x): untyped = + if x.len > 0 and not x.endsWith("\c\L"): + x & "\c\L" + else: + x + var xb = mpBody.withNewLine() & body + var headers = newHttpHeaders() + if multipart != nil: + headers["Content-Type"] = mpContentType + headers["Content-Length"] = $len(xb) + return (xb, headers) + +proc post*(client: HttpClient | AsyncHttpClient, url: string, body = "", multipart: MultipartData = nil): Future[Response | AsyncResponse] {.multisync.} = ## Connects to the hostname specified by the URL and performs a POST request. - ## This procedure uses httpClient values such as `client.maxRedirects`. - result = await client.request(url, HttpPost, body, multipart=multipart) + ## This procedure uses httpClient values such as ``client.maxRedirects``. + var (xb, headers) = makeRequestContent(body, multipart) + result = await client.request(url, $HttpPost, xb, headers) -proc postContent*(client: HttpClient | AsyncHttpClient, url: Uri | string, body = "", +proc postContent*(client: HttpClient | AsyncHttpClient, url: string, + body = "", multipart: MultipartData = nil): Future[string] {.multisync.} = ## Connects to the hostname specified by the URL and returns the content of a POST request. let resp = await post(client, url, body, multipart) return await responseContent(resp) -proc put*(client: HttpClient | AsyncHttpClient, url: Uri | string, body = "", - multipart: MultipartData = nil): Future[Response | AsyncResponse] - {.multisync.} = +proc put*(client: HttpClient | AsyncHttpClient, url: string, body = "", + multipart: MultipartData = nil): Future[Response | AsyncResponse] + {.multisync.} = ## Connects to the hostname specified by the URL and performs a PUT request. - ## This procedure uses httpClient values such as `client.maxRedirects`. - result = await client.request(url, HttpPut, body, multipart=multipart) + ## This procedure uses httpClient values such as ``client.maxRedirects``. + var (xb, headers) = makeRequestContent(body, multipart) + result = await client.request(url, $HttpPut, xb, headers) -proc putContent*(client: HttpClient | AsyncHttpClient, url: Uri | string, body = "", - multipart: MultipartData = nil): Future[string] {.multisync.} = +proc putContent*(client: HttpClient | AsyncHttpClient, url: string, + body = "", + multipart: MultipartData = nil): Future[string] + {.multisync.} = ## Connects to the hostname specified by the URL andreturns the content of a PUT request. let resp = await put(client, url, body, multipart) return await responseContent(resp) -proc patch*(client: HttpClient | AsyncHttpClient, url: Uri | string, body = "", - multipart: MultipartData = nil): Future[Response | AsyncResponse] - {.multisync.} = +proc patch*(client: HttpClient | AsyncHttpClient, url: string, body = "", + multipart: MultipartData = nil): Future[Response | AsyncResponse] + {.multisync.} = ## Connects to the hostname specified by the URL and performs a PATCH request. - ## This procedure uses httpClient values such as `client.maxRedirects`. - result = await client.request(url, HttpPatch, body, multipart=multipart) + ## This procedure uses httpClient values such as ``client.maxRedirects``. + var (xb, headers) = makeRequestContent(body, multipart) + result = await client.request(url, $HttpPatch, xb, headers) -proc patchContent*(client: HttpClient | AsyncHttpClient, url: Uri | string, body = "", - multipart: MultipartData = nil): Future[string] +proc patchContent*(client: HttpClient | AsyncHttpClient, url: string, + body = "", + multipart: MultipartData = nil): Future[string] {.multisync.} = ## Connects to the hostname specified by the URL and returns the content of a PATCH request. let resp = await patch(client, url, body, multipart) return await responseContent(resp) -proc downloadFile*(client: HttpClient, url: Uri | string, filename: string) = - ## Downloads `url` and saves it to `filename`. +proc downloadFile*(client: HttpClient, url: string, filename: string) = + ## Downloads ``url`` and saves it to ``filename``. client.getBody = false defer: client.getBody = true let resp = client.get(url) - - if resp.code.is4xx or resp.code.is5xx: - raise newException(HttpRequestError, resp.status) client.bodyStream = newFileStream(filename, fmWrite) if client.bodyStream.isNil: @@ -1291,30 +1067,30 @@ proc downloadFile*(client: HttpClient, url: Uri | string, filename: string) = parseBody(client, resp.headers, resp.version) client.bodyStream.close() -proc downloadFileEx(client: AsyncHttpClient, - url: Uri | string, filename: string): Future[void] {.async.} = - ## Downloads `url` and saves it to `filename`. - client.getBody = false - let resp = await client.get(url) - if resp.code.is4xx or resp.code.is5xx: raise newException(HttpRequestError, resp.status) - client.bodyStream = newFutureStream[string]("downloadFile") - var file = openAsync(filename, fmWrite) - defer: file.close() - # Let `parseBody` write response data into client.bodyStream in the - # background. - let parseBodyFut = parseBody(client, resp.headers, resp.version) - parseBodyFut.addCallback do(): - if parseBodyFut.failed: - client.bodyStream.fail(parseBodyFut.error) - # The `writeFromStream` proc will complete once all the data in the - # `bodyStream` has been written to the file. - await file.writeFromStream(client.bodyStream) - -proc downloadFile*(client: AsyncHttpClient, url: Uri | string, +proc downloadFile*(client: AsyncHttpClient, url: string, filename: string): Future[void] = + proc downloadFileEx(client: AsyncHttpClient, + url, filename: string): Future[void] {.async.} = + ## Downloads ``url`` and saves it to ``filename``. + client.getBody = false + let resp = await client.get(url) + + client.bodyStream = newFutureStream[string]("downloadFile") + var file = openAsync(filename, fmWrite) + # Let `parseBody` write response data into client.bodyStream in the + # background. + asyncCheck parseBody(client, resp.headers, resp.version) + # The `writeFromStream` proc will complete once all the data in the + # `bodyStream` has been written to the file. + await file.writeFromStream(client.bodyStream) + file.close() + + if resp.code.is4xx or resp.code.is5xx: + raise newException(HttpRequestError, resp.status) + result = newFuture[void]("downloadFile") try: result = downloadFileEx(client, url, filename) diff --git a/lib/pure/httpcore.nim b/lib/pure/httpcore.nim index d639bef05..1e9a85a57 100644 --- a/lib/pure/httpcore.nim +++ b/lib/pure/httpcore.nim @@ -7,17 +7,16 @@ # distribution, for details about the copyright. # -## Contains functionality shared between the `httpclient` and -## `asynchttpserver` modules. +## Contains functionality shared between the ``httpclient`` and +## ``asynchttpserver`` modules. ## ## Unstable API. -import std/private/since + import tables, strutils, parseutils type HttpHeaders* = ref object table*: TableRef[string, seq[string]] - isTitleCase: bool HttpHeaderValues* = distinct seq[string] @@ -29,33 +28,29 @@ type HttpVer11, HttpVer10 - HttpMethod* = enum ## the requested HttpMethod - HttpHead = "HEAD" ## Asks for the response identical to the one that - ## would correspond to a GET request, but without - ## the response body. - HttpGet = "GET" ## Retrieves the specified resource. - HttpPost = "POST" ## Submits data to be processed to the identified - ## resource. The data is included in the body of - ## the request. - HttpPut = "PUT" ## Uploads a representation of the specified - ## resource. - HttpDelete = "DELETE" ## Deletes the specified resource. - HttpTrace = "TRACE" ## Echoes back the received request, so that a - ## client - ## can see what intermediate servers are adding or - ## changing in the request. - HttpOptions = "OPTIONS" ## Returns the HTTP methods that the server - ## supports for specified address. - HttpConnect = "CONNECT" ## Converts the request connection to a transparent - ## TCP/IP tunnel, usually used for proxies. - HttpPatch = "PATCH" ## Applies partial modifications to a resource. + HttpMethod* = enum ## the requested HttpMethod + HttpHead, ## Asks for the response identical to the one that would + ## correspond to a GET request, but without the response + ## body. + HttpGet, ## Retrieves the specified resource. + HttpPost, ## Submits data to be processed to the identified + ## resource. The data is included in the body of the + ## request. + HttpPut, ## Uploads a representation of the specified resource. + HttpDelete, ## Deletes the specified resource. + HttpTrace, ## Echoes back the received request, so that a client + ## can see what intermediate servers are adding or + ## changing in the request. + HttpOptions, ## Returns the HTTP methods that the server supports + ## for specified address. + HttpConnect, ## Converts the request connection to a transparent + ## TCP/IP tunnel, usually used for proxies. + HttpPatch ## Applies partial modifications to a resource. const Http100* = HttpCode(100) Http101* = HttpCode(101) - Http102* = HttpCode(102) ## https://tools.ietf.org/html/rfc2518.html WebDAV - Http103* = HttpCode(103) ## https://tools.ietf.org/html/rfc8297.html Early hints Http200* = HttpCode(200) Http201* = HttpCode(201) Http202* = HttpCode(202) @@ -63,9 +58,6 @@ const Http204* = HttpCode(204) Http205* = HttpCode(205) Http206* = HttpCode(206) - Http207* = HttpCode(207) ## https://tools.ietf.org/html/rfc4918.html WebDAV - Http208* = HttpCode(208) ## https://tools.ietf.org/html/rfc5842.html WebDAV, Section 7.1 - Http226* = HttpCode(226) ## https://tools.ietf.org/html/rfc3229.html Delta encoding, Section 10.4.1 Http300* = HttpCode(300) Http301* = HttpCode(301) Http302* = HttpCode(302) @@ -73,10 +65,8 @@ const Http304* = HttpCode(304) Http305* = HttpCode(305) Http307* = HttpCode(307) - Http308* = HttpCode(308) Http400* = HttpCode(400) Http401* = HttpCode(401) - Http402* = HttpCode(402) ## https://tools.ietf.org/html/rfc7231.html Payment required, Section 6.5.2 Http403* = HttpCode(403) Http404* = HttpCode(404) Http405* = HttpCode(405) @@ -95,9 +85,6 @@ const Http418* = HttpCode(418) Http421* = HttpCode(421) Http422* = HttpCode(422) - Http423* = HttpCode(423) ## https://tools.ietf.org/html/rfc4918.html WebDAV, Section 11.3 - Http424* = HttpCode(424) ## https://tools.ietf.org/html/rfc4918.html WebDAV, Section 11.3 - Http425* = HttpCode(425) ## https://tools.ietf.org/html/rfc8470.html Early data Http426* = HttpCode(426) Http428* = HttpCode(428) Http429* = HttpCode(429) @@ -109,97 +96,68 @@ const Http503* = HttpCode(503) Http504* = HttpCode(504) Http505* = HttpCode(505) - Http506* = HttpCode(506) ## https://tools.ietf.org/html/rfc2295.html Content negotiation, Section 8.1 - Http507* = HttpCode(507) ## https://tools.ietf.org/html/rfc4918.html WebDAV, Section 11.5 - Http508* = HttpCode(508) ## https://tools.ietf.org/html/rfc5842.html WebDAV, Section 7.2 - Http510* = HttpCode(510) ## https://tools.ietf.org/html/rfc2774.html Extension framework, Section 7 - Http511* = HttpCode(511) ## https://tools.ietf.org/html/rfc6585.html Additional status code, Section 6 - -const httpNewLine* = "\c\L" const headerLimit* = 10_000 -func toTitleCase(s: string): string = - result = newString(len(s)) - var upper = true - for i in 0..len(s) - 1: - result[i] = if upper: toUpperAscii(s[i]) else: toLowerAscii(s[i]) - upper = s[i] == '-' - -func toCaseInsensitive(headers: HttpHeaders, s: string): string {.inline.} = - return if headers.isTitleCase: toTitleCase(s) else: toLowerAscii(s) - -func newHttpHeaders*(titleCase=false): HttpHeaders = - ## Returns a new `HttpHeaders` object. if `titleCase` is set to true, - ## headers are passed to the server in title case (e.g. "Content-Length") - result = HttpHeaders(table: newTable[string, seq[string]](), isTitleCase: titleCase) - -func newHttpHeaders*(keyValuePairs: - openArray[tuple[key: string, val: string]], titleCase=false): HttpHeaders = - ## Returns a new `HttpHeaders` object from an array. if `titleCase` is set to true, - ## headers are passed to the server in title case (e.g. "Content-Length") - result = HttpHeaders(table: newTable[string, seq[string]](), isTitleCase: titleCase) +proc newHttpHeaders*(): HttpHeaders = + new result + result.table = newTable[string, seq[string]]() +proc newHttpHeaders*(keyValuePairs: + openArray[tuple[key: string, val: string]]): HttpHeaders = + var pairs: seq[tuple[key: string, val: seq[string]]] = @[] for pair in keyValuePairs: - let key = result.toCaseInsensitive(pair.key) - {.cast(noSideEffect).}: - if key in result.table: - result.table[key].add(pair.val) - else: - result.table[key] = @[pair.val] + pairs.add((pair.key.toLowerAscii(), @[pair.val])) + new result + result.table = newTable[string, seq[string]](pairs) -func `$`*(headers: HttpHeaders): string {.inline.} = - $headers.table +proc `$`*(headers: HttpHeaders): string = + return $headers.table -proc clear*(headers: HttpHeaders) {.inline.} = +proc clear*(headers: HttpHeaders) = headers.table.clear() -func `[]`*(headers: HttpHeaders, key: string): HttpHeaderValues = - ## Returns the values associated with the given `key`. If the returned - ## values are passed to a procedure expecting a `string`, the first +proc `[]`*(headers: HttpHeaders, key: string): HttpHeaderValues = + ## Returns the values associated with the given ``key``. If the returned + ## values are passed to a procedure expecting a ``string``, the first ## value is automatically picked. If there are ## no values associated with the key, an exception is raised. ## - ## To access multiple values of a key, use the overloaded `[]` below or - ## to get all of them access the `table` field directly. - {.cast(noSideEffect).}: - return headers.table[headers.toCaseInsensitive(key)].HttpHeaderValues + ## To access multiple values of a key, use the overloaded ``[]`` below or + ## to get all of them access the ``table`` field directly. + return headers.table[key.toLowerAscii].HttpHeaderValues converter toString*(values: HttpHeaderValues): string = return seq[string](values)[0] -func `[]`*(headers: HttpHeaders, key: string, i: int): string = - ## Returns the `i`'th value associated with the given key. If there are - ## no values associated with the key or the `i`'th value doesn't exist, +proc `[]`*(headers: HttpHeaders, key: string, i: int): string = + ## Returns the ``i``'th value associated with the given key. If there are + ## no values associated with the key or the ``i``'th value doesn't exist, ## an exception is raised. - {.cast(noSideEffect).}: - return headers.table[headers.toCaseInsensitive(key)][i] + return headers.table[key.toLowerAscii][i] proc `[]=`*(headers: HttpHeaders, key, value: string) = - ## Sets the header entries associated with `key` to the specified value. + ## Sets the header entries associated with ``key`` to the specified value. ## Replaces any existing values. - headers.table[headers.toCaseInsensitive(key)] = @[value] + headers.table[key.toLowerAscii] = @[value] proc `[]=`*(headers: HttpHeaders, key: string, value: seq[string]) = - ## Sets the header entries associated with `key` to the specified list of - ## values. Replaces any existing values. If `value` is empty, - ## deletes the header entries associated with `key`. - if value.len > 0: - headers.table[headers.toCaseInsensitive(key)] = value - else: - headers.table.del(headers.toCaseInsensitive(key)) + ## Sets the header entries associated with ``key`` to the specified list of + ## values. + ## Replaces any existing values. + headers.table[key.toLowerAscii] = value proc add*(headers: HttpHeaders, key, value: string) = ## Adds the specified value to the specified key. Appends to any existing ## values associated with the key. - if not headers.table.hasKey(headers.toCaseInsensitive(key)): - headers.table[headers.toCaseInsensitive(key)] = @[value] + if not headers.table.hasKey(key.toLowerAscii): + headers.table[key.toLowerAscii] = @[value] else: - headers.table[headers.toCaseInsensitive(key)].add(value) + headers.table[key.toLowerAscii].add(value) proc del*(headers: HttpHeaders, key: string) = - ## Deletes the header entries associated with `key` - headers.table.del(headers.toCaseInsensitive(key)) + ## Delete the header entries associated with ``key`` + headers.table.del(key.toLowerAscii) iterator pairs*(headers: HttpHeaders): tuple[key, value: string] = ## Yields each key, value pair. @@ -207,27 +165,27 @@ iterator pairs*(headers: HttpHeaders): tuple[key, value: string] = for value in v: yield (k, value) -func contains*(values: HttpHeaderValues, value: string): bool = - ## Determines if `value` is one of the values inside `values`. Comparison +proc contains*(values: HttpHeaderValues, value: string): bool = + ## Determines if ``value`` is one of the values inside ``values``. Comparison ## is performed without case sensitivity. for val in seq[string](values): if val.toLowerAscii == value.toLowerAscii: return true -func hasKey*(headers: HttpHeaders, key: string): bool = - return headers.table.hasKey(headers.toCaseInsensitive(key)) +proc hasKey*(headers: HttpHeaders, key: string): bool = + return headers.table.hasKey(key.toLowerAscii()) -func getOrDefault*(headers: HttpHeaders, key: string, +proc getOrDefault*(headers: HttpHeaders, key: string, default = @[""].HttpHeaderValues): HttpHeaderValues = - ## Returns the values associated with the given `key`. If there are no - ## values associated with the key, then `default` is returned. + ## Returns the values associated with the given ``key``. If there are no + ## values associated with the key, then ``default`` is returned. if headers.hasKey(key): return headers[key] else: return default -func len*(headers: HttpHeaders): int {.inline.} = headers.table.len +proc len*(headers: HttpHeaders): int = return headers.table.len -func parseList(line: string, list: var seq[string], start: int): int = +proc parseList(line: string, list: var seq[string], start: int): int = var i = 0 var current = "" while start+i < line.len and line[start + i] notin {'\c', '\l'}: @@ -238,27 +196,23 @@ func parseList(line: string, list: var seq[string], start: int): int = i.inc # Skip , current.setLen(0) -func parseHeader*(line: string): tuple[key: string, value: seq[string]] = +proc parseHeader*(line: string): tuple[key: string, value: seq[string]] = ## Parses a single raw header HTTP line into key value pairs. ## - ## Used by `asynchttpserver` and `httpclient` internally and should not + ## Used by ``asynchttpserver`` and ``httpclient`` internally and should not ## be used by you. result.value = @[] var i = 0 i = line.parseUntil(result.key, ':') inc(i) # skip : if i < len(line): - if cmpIgnoreCase(result.key, "cookie") == 0: - i += line.skipWhitespace(i) - result.value.add line.substr(i) - else: - i += parseList(line, result.value, i) + i += parseList(line, result.value, i) elif result.key.len > 0: result.value = @[""] else: result.value = @[] -func `==`*(protocol: tuple[orig: string, major, minor: int], +proc `==`*(protocol: tuple[orig: string, major, minor: int], ver: HttpVersion): bool = let major = case ver @@ -269,18 +223,19 @@ func `==`*(protocol: tuple[orig: string, major, minor: int], of HttpVer10: 0 result = protocol.major == major and protocol.minor == minor -func contains*(methods: set[HttpMethod], x: string): bool = +proc contains*(methods: set[HttpMethod], x: string): bool = return parseEnum[HttpMethod](x) in methods -func `$`*(code: HttpCode): string = - ## Converts the specified `HttpCode` into a HTTP status. - runnableExamples: - doAssert($Http404 == "404 Not Found") +proc `$`*(code: HttpCode): string = + ## Converts the specified ``HttpCode`` into a HTTP status. + ## + ## For example: + ## + ## .. code-block:: nim + ## doAssert($Http404 == "404 Not Found") case code.int of 100: "100 Continue" of 101: "101 Switching Protocols" - of 102: "102 Processing" - of 103: "103 Early Hints" of 200: "200 OK" of 201: "201 Created" of 202: "202 Accepted" @@ -288,9 +243,6 @@ func `$`*(code: HttpCode): string = of 204: "204 No Content" of 205: "205 Reset Content" of 206: "206 Partial Content" - of 207: "207 Multi-Status" - of 208: "208 Already Reported" - of 226: "226 IM Used" of 300: "300 Multiple Choices" of 301: "301 Moved Permanently" of 302: "302 Found" @@ -298,10 +250,8 @@ func `$`*(code: HttpCode): string = of 304: "304 Not Modified" of 305: "305 Use Proxy" of 307: "307 Temporary Redirect" - of 308: "308 Permanent Redirect" of 400: "400 Bad Request" of 401: "401 Unauthorized" - of 402: "402 Payment Required" of 403: "403 Forbidden" of 404: "404 Not Found" of 405: "405 Method Not Allowed" @@ -320,9 +270,6 @@ func `$`*(code: HttpCode): string = of 418: "418 I'm a teapot" of 421: "421 Misdirected Request" of 422: "422 Unprocessable Entity" - of 423: "423 Locked" - of 424: "424 Failed Dependency" - of 425: "425 Too Early" of 426: "426 Upgrade Required" of 428: "428 Precondition Required" of 429: "429 Too Many Requests" @@ -334,34 +281,46 @@ func `$`*(code: HttpCode): string = of 503: "503 Service Unavailable" of 504: "504 Gateway Timeout" of 505: "505 HTTP Version Not Supported" - of 506: "506 Variant Also Negotiates" - of 507: "507 Insufficient Storage" - of 508: "508 Loop Detected" - of 510: "510 Not Extended" - of 511: "511 Network Authentication Required" else: $(int(code)) -func `==`*(a, b: HttpCode): bool {.borrow.} +proc `==`*(a, b: HttpCode): bool {.borrow.} -func is1xx*(code: HttpCode): bool {.inline, since: (1, 5).} = - ## Determines whether `code` is a 1xx HTTP status code. - runnableExamples: - doAssert is1xx(HttpCode(103)) +proc `==`*(rawCode: string, code: HttpCode): bool = + return cmpIgnoreCase(rawCode, $code) == 0 - code.int in {100 .. 199} +proc is2xx*(code: HttpCode): bool = + ## Determines whether ``code`` is a 2xx HTTP status code. + return code.int in {200 .. 299} -func is2xx*(code: HttpCode): bool {.inline.} = - ## Determines whether `code` is a 2xx HTTP status code. - code.int in {200 .. 299} +proc is3xx*(code: HttpCode): bool = + ## Determines whether ``code`` is a 3xx HTTP status code. + return code.int in {300 .. 399} -func is3xx*(code: HttpCode): bool {.inline.} = - ## Determines whether `code` is a 3xx HTTP status code. - code.int in {300 .. 399} +proc is4xx*(code: HttpCode): bool = + ## Determines whether ``code`` is a 4xx HTTP status code. + return code.int in {400 .. 499} -func is4xx*(code: HttpCode): bool {.inline.} = - ## Determines whether `code` is a 4xx HTTP status code. - code.int in {400 .. 499} +proc is5xx*(code: HttpCode): bool = + ## Determines whether ``code`` is a 5xx HTTP status code. + return code.int in {500 .. 599} -func is5xx*(code: HttpCode): bool {.inline.} = - ## Determines whether `code` is a 5xx HTTP status code. - code.int in {500 .. 599} +proc `$`*(httpMethod: HttpMethod): string = + return (system.`$`(httpMethod))[4 .. ^1].toUpperAscii() + +when isMainModule: + var test = newHttpHeaders() + test["Connection"] = @["Upgrade", "Close"] + doAssert test["Connection", 0] == "Upgrade" + doAssert test["Connection", 1] == "Close" + test.add("Connection", "Test") + doAssert test["Connection", 2] == "Test" + doAssert "upgrade" in test["Connection"] + + # Bug #5344. + doAssert parseHeader("foobar: ") == ("foobar", @[""]) + let (key, value) = parseHeader("foobar: ") + test = newHttpHeaders() + test[key] = value + doAssert test["foobar"] == "" + + doAssert parseHeader("foobar:") == ("foobar", @[""]) diff --git a/lib/pure/includes/osenv.nim b/lib/pure/includes/osenv.nim new file mode 100644 index 000000000..c4c6669f9 --- /dev/null +++ b/lib/pure/includes/osenv.nim @@ -0,0 +1,229 @@ +# Include file that implements 'getEnv' and friends. Do not import it! + +when not declared(os) and not declared(ospaths): + {.error: "This is an include file for os.nim!".} + +when defined(windows): + from parseutils import skipIgnoreCase + +proc c_getenv(env: cstring): cstring {. + importc: "getenv", header: "".} +proc c_putenv(env: cstring): cint {. + importc: "putenv", header: "".} +proc c_unsetenv(env: cstring): cint {. + importc: "unsetenv", header: "".} + +# Environment handling cannot be put into RTL, because the ``envPairs`` +# iterator depends on ``environment``. + +var + envComputed {.threadvar.}: bool + environment {.threadvar.}: seq[string] + +when defined(nimV2): + proc unpairedEnvAllocs*(): int = + result = environment.len + if result > 0: inc result + +when defined(windows) and not defined(nimscript): + # because we support Windows GUI applications, things get really + # messy here... + when useWinUnicode: + when defined(cpp): + proc strEnd(cstr: WideCString, c = 0'i32): WideCString {. + importcpp: "(NI16*)wcschr((const wchar_t *)#, #)", header: "".} + else: + proc strEnd(cstr: WideCString, c = 0'i32): WideCString {. + importc: "wcschr", header: "".} + else: + proc strEnd(cstr: cstring, c = 0'i32): cstring {. + importc: "strchr", header: "".} + + proc getEnvVarsC() = + if not envComputed: + environment = @[] + when useWinUnicode: + var + env = getEnvironmentStringsW() + e = env + if e == nil: return # an error occurred + while true: + var eend = strEnd(e) + add(environment, $e) + e = cast[WideCString](cast[ByteAddress](eend)+2) + if eend[1].int == 0: break + discard freeEnvironmentStringsW(env) + else: + var + env = getEnvironmentStringsA() + e = env + if e == nil: return # an error occurred + while true: + var eend = strEnd(e) + add(environment, $e) + e = cast[cstring](cast[ByteAddress](eend)+1) + if eend[1] == '\0': break + discard freeEnvironmentStringsA(env) + envComputed = true + +else: + const + useNSGetEnviron = (defined(macosx) and not defined(ios) and not defined(emscripten)) or defined(nimscript) + + when useNSGetEnviron: + # From the manual: + # Shared libraries and bundles don't have direct access to environ, + # which is only available to the loader ld(1) when a complete program + # is being linked. + # The environment routines can still be used, but if direct access to + # environ is needed, the _NSGetEnviron() routine, defined in + # , can be used to retrieve the address of environ + # at runtime. + proc NSGetEnviron(): ptr cstringArray {. + importc: "_NSGetEnviron", header: "".} + else: + var gEnv {.importc: "environ".}: cstringArray + + proc getEnvVarsC() = + # retrieves the variables of char** env of C's main proc + if not envComputed: + environment = @[] + when useNSGetEnviron: + var gEnv = NSGetEnviron()[] + var i = 0 + while true: + if gEnv[i] == nil: break + add environment, $gEnv[i] + inc(i) + envComputed = true + +proc findEnvVar(key: string): int = + getEnvVarsC() + var temp = key & '=' + for i in 0..high(environment): + when defined(windows): + if skipIgnoreCase(environment[i], temp) == len(temp): return i + else: + if startsWith(environment[i], temp): return i + return -1 + +proc getEnv*(key: string, default = ""): TaintedString {.tags: [ReadEnvEffect].} = + ## Returns the value of the `environment variable`:idx: named `key`. + ## + ## If the variable does not exist, `""` is returned. To distinguish + ## whether a variable exists or it's value is just `""`, call + ## `existsEnv(key) proc <#existsEnv,string>`_. + ## + ## See also: + ## * `existsEnv proc <#existsEnv,string>`_ + ## * `putEnv proc <#putEnv,string,string>`_ + ## * `delEnv proc <#delEnv,string>`_ + ## * `envPairs iterator <#envPairs.i>`_ + runnableExamples: + assert getEnv("unknownEnv") == "" + assert getEnv("unknownEnv", "doesn't exist") == "doesn't exist" + + when nimvm: + discard "built into the compiler" + else: + var i = findEnvVar(key) + if i >= 0: + return TaintedString(substr(environment[i], find(environment[i], '=')+1)) + else: + var env = c_getenv(key) + if env == nil: return TaintedString(default) + result = TaintedString($env) + +proc existsEnv*(key: string): bool {.tags: [ReadEnvEffect].} = + ## Checks whether the environment variable named `key` exists. + ## Returns true if it exists, false otherwise. + ## + ## See also: + ## * `getEnv proc <#getEnv,string,string>`_ + ## * `putEnv proc <#putEnv,string,string>`_ + ## * `delEnv proc <#delEnv,string>`_ + ## * `envPairs iterator <#envPairs.i>`_ + runnableExamples: + assert not existsEnv("unknownEnv") + + when nimvm: + discard "built into the compiler" + else: + if c_getenv(key) != nil: return true + else: return findEnvVar(key) >= 0 + +proc putEnv*(key, val: string) {.tags: [WriteEnvEffect].} = + ## Sets the value of the `environment variable`:idx: named `key` to `val`. + ## If an error occurs, `OSError` is raised. + ## + ## See also: + ## * `getEnv proc <#getEnv,string,string>`_ + ## * `existsEnv proc <#existsEnv,string>`_ + ## * `delEnv proc <#delEnv,string>`_ + ## * `envPairs iterator <#envPairs.i>`_ + + # Note: by storing the string in the environment sequence, + # we guarantee that we don't free the memory before the program + # ends (this is needed for POSIX compliance). It is also needed so that + # the process itself may access its modified environment variables! + when nimvm: + discard "built into the compiler" + else: + var indx = findEnvVar(key) + if indx >= 0: + environment[indx] = key & '=' & val + else: + add environment, (key & '=' & val) + indx = high(environment) + when defined(windows) and not defined(nimscript): + when useWinUnicode: + var k = newWideCString(key) + var v = newWideCString(val) + if setEnvironmentVariableW(k, v) == 0'i32: raiseOSError(osLastError()) + else: + if setEnvironmentVariableA(key, val) == 0'i32: raiseOSError(osLastError()) + else: + if c_putenv(environment[indx]) != 0'i32: + raiseOSError(osLastError()) + +proc delEnv*(key: string) {.tags: [WriteEnvEffect].} = + ## Deletes the `environment variable`:idx: named `key`. + ## If an error occurs, `OSError` is raised. + ## + ## See also:ven + ## * `getEnv proc <#getEnv,string,string>`_ + ## * `existsEnv proc <#existsEnv,string>`_ + ## * `putEnv proc <#putEnv,string,string>`_ + ## * `envPairs iterator <#envPairs.i>`_ + when nimvm: + discard "built into the compiler" + else: + var indx = findEnvVar(key) + if indx < 0: return # Do nothing if the env var is not already set + when defined(windows) and not defined(nimscript): + when useWinUnicode: + var k = newWideCString(key) + if setEnvironmentVariableW(k, nil) == 0'i32: raiseOSError(osLastError()) + else: + if setEnvironmentVariableA(key, nil) == 0'i32: raiseOSError(osLastError()) + else: + if c_unsetenv(key) != 0'i32: + raiseOSError(osLastError()) + environment.delete(indx) + +iterator envPairs*(): tuple[key, value: TaintedString] {.tags: [ReadEnvEffect].} = + ## Iterate over all `environments variables`:idx:. + ## + ## In the first component of the tuple is the name of the current variable stored, + ## in the second its value. + ## + ## See also: + ## * `getEnv proc <#getEnv,string,string>`_ + ## * `existsEnv proc <#existsEnv,string>`_ + ## * `putEnv proc <#putEnv,string,string>`_ + ## * `delEnv proc <#delEnv,string>`_ + getEnvVarsC() + for i in 0..high(environment): + var p = find(environment[i], '=') + yield (TaintedString(substr(environment[i], 0, p-1)), + TaintedString(substr(environment[i], p+1))) diff --git a/lib/pure/includes/oserr.nim b/lib/pure/includes/oserr.nim new file mode 100644 index 000000000..138aa127d --- /dev/null +++ b/lib/pure/includes/oserr.nim @@ -0,0 +1,120 @@ +# Include file that implements 'osErrorMsg' and friends. Do not import it! + +when not declared(os) and not declared(ospaths): + {.error: "This is an include file for os.nim!".} + +when not defined(nimscript): + var errno {.importc, header: "".}: cint + + proc c_strerror(errnum: cint): cstring {. + importc: "strerror", header: "".} + + when defined(windows): + import winlean + +proc `==`*(err1, err2: OSErrorCode): bool {.borrow.} +proc `$`*(err: OSErrorCode): string {.borrow.} + +proc osErrorMsg*(errorCode: OSErrorCode): string = + ## Converts an OS error code into a human readable string. + ## + ## The error code can be retrieved using the `osLastError proc <#osLastError>`_. + ## + ## If conversion fails, or ``errorCode`` is ``0`` then ``""`` will be + ## returned. + ## + ## On Windows, the ``-d:useWinAnsi`` compilation flag can be used to + ## make this procedure use the non-unicode Win API calls to retrieve the + ## message. + ## + ## See also: + ## * `raiseOSError proc <#raiseOSError,OSErrorCode,string>`_ + ## * `osLastError proc <#osLastError>`_ + runnableExamples: + when defined(linux): + assert osErrorMsg(OSErrorCode(0)) == "" + assert osErrorMsg(OSErrorCode(1)) == "Operation not permitted" + assert osErrorMsg(OSErrorCode(2)) == "No such file or directory" + + result = "" + when defined(nimscript): + discard + elif defined(Windows): + if errorCode != OSErrorCode(0'i32): + when useWinUnicode: + var msgbuf: WideCString + if formatMessageW(0x00000100 or 0x00001000 or 0x00000200, + nil, errorCode.int32, 0, addr(msgbuf), 0, nil) != 0'i32: + result = $msgbuf + if msgbuf != nil: localFree(cast[pointer](msgbuf)) + else: + var msgbuf: cstring + if formatMessageA(0x00000100 or 0x00001000 or 0x00000200, + nil, errorCode.int32, 0, addr(msgbuf), 0, nil) != 0'i32: + result = $msgbuf + if msgbuf != nil: localFree(msgbuf) + else: + if errorCode != OSErrorCode(0'i32): + result = $c_strerror(errorCode.int32) + +proc newOSError*( + errorCode: OSErrorCode, additionalInfo = "" +): owned(ref OSError) {.noinline.} = + ## Creates a new `OSError exception `_. + ## + ## The ``errorCode`` will determine the + ## message, `osErrorMsg proc <#osErrorMsg,OSErrorCode>`_ will be used + ## to get this message. + ## + ## The error code can be retrieved using the `osLastError proc + ## <#osLastError>`_. + ## + ## If the error code is ``0`` or an error message could not be retrieved, + ## the message ``unknown OS error`` will be used. + ## + ## See also: + ## * `osErrorMsg proc <#osErrorMsg,OSErrorCode>`_ + ## * `osLastError proc <#osLastError>`_ + var e: owned(ref OSError); new(e) + e.errorCode = errorCode.int32 + e.msg = osErrorMsg(errorCode) + if additionalInfo.len > 0: + if e.msg.len > 0 and e.msg[^1] != '\n': e.msg.add '\n' + e.msg.add "Additional info: " + e.msg.addQuoted additionalInfo + if e.msg == "": + e.msg = "unknown OS error" + return e + +proc raiseOSError*(errorCode: OSErrorCode, additionalInfo = "") {.noinline.} = + ## Raises an `OSError exception `_. + ## + ## Read the description of the `newOSError proc <#newOSError,OSErrorCode,string>`_ to learn + ## how the exception object is created. + raise newOSError(errorCode, additionalInfo) + +{.push stackTrace:off.} +proc osLastError*(): OSErrorCode {.sideEffect.} = + ## Retrieves the last operating system error code. + ## + ## This procedure is useful in the event when an OS call fails. In that case + ## this procedure will return the error code describing the reason why the + ## OS call failed. The ``OSErrorMsg`` procedure can then be used to convert + ## this code into a string. + ## + ## **Warning**: + ## The behaviour of this procedure varies between Windows and POSIX systems. + ## On Windows some OS calls can reset the error code to ``0`` causing this + ## procedure to return ``0``. It is therefore advised to call this procedure + ## immediately after an OS call fails. On POSIX systems this is not a problem. + ## + ## See also: + ## * `osErrorMsg proc <#osErrorMsg,OSErrorCode>`_ + ## * `raiseOSError proc <#raiseOSError,OSErrorCode,string>`_ + when defined(nimscript): + discard + elif defined(windows): + result = OSErrorCode(getLastError()) + else: + result = OSErrorCode(errno) +{.pop.} diff --git a/lib/std/private/osseps.nim b/lib/pure/includes/osseps.nim similarity index 91% rename from lib/std/private/osseps.nim rename to lib/pure/includes/osseps.nim index f2d49d886..bafef686d 100644 --- a/lib/std/private/osseps.nim +++ b/lib/pure/includes/osseps.nim @@ -1,10 +1,8 @@ # Include file that implements 'DirSep' and friends. Do not import this when -# you also import `os.nim`! +# you also import ``os.nim``! # Improved based on info in 'compiler/platform.nim' -## .. importdoc:: ospaths2.nim - const doslikeFileSystem* = defined(windows) or defined(OS2) or defined(DOS) @@ -39,9 +37,9 @@ const when doslikeFileSystem: '/' else: DirSep ## An alternative character used by the operating system to separate - ## pathname components, or the same as DirSep_ if only one separator + ## pathname components, or the same as `DirSep <#DirSep>`_ if only one separator ## character exists. This is set to `'/'` on Windows systems - ## where DirSep_ is a backslash (`'\\'`). + ## where `DirSep <#DirSep>`_ is a backslash (`'\\'`). PathSep* = when defined(macos) or defined(RISCOS): ',' @@ -49,7 +47,7 @@ const elif defined(PalmOS) or defined(MorphOS): ':' # platform has ':' but osseps has ';' else: ':' ## The character conventionally used by the operating system to separate - ## search path components (as in PATH), such as `':'` for POSIX + ## search patch components (as in PATH), such as `':'` for POSIX ## or `';'` for Windows. FileSystemCaseSensitive* = @@ -57,7 +55,7 @@ const defined(PalmOS) or defined(MorphOS): false else: true ## True if the file system is case sensitive, false otherwise. Used by - ## `cmpPaths proc`_ to compare filenames properly. + ## `cmpPaths proc <#cmpPaths,string,string>`_ to compare filenames properly. ExeExt* = when doslikeFileSystem: "exe" @@ -90,7 +88,7 @@ const ExtSep* = '.' ## The character which separates the base filename from the extension; - ## for example, the `'.'` in `os.nim`. + ## for example, the `'.'` in ``os.nim``. # MacOS paths # =========== diff --git a/lib/pure/ioselects/ioselectors_epoll.nim b/lib/pure/ioselects/ioselectors_epoll.nim index 08cb6ed74..bf13cc83e 100644 --- a/lib/pure/ioselects/ioselectors_epoll.nim +++ b/lib/pure/ioselects/ioselectors_epoll.nim @@ -55,7 +55,7 @@ when hasThreadSupport: maxFD: int numFD: int fds: ptr SharedArray[SelectorKey[T]] - count*: int + count: int Selector*[T] = ptr SelectorImpl[T] else: type @@ -64,7 +64,7 @@ else: maxFD: int numFD: int fds: seq[SelectorKey[T]] - count*: int + count: int Selector*[T] = ref SelectorImpl[T] type SelectEventImpl = object @@ -72,18 +72,16 @@ type SelectEvent* = ptr SelectEventImpl proc newSelector*[T](): Selector[T] = - proc initialNumFD(): int {.inline.} = - when defined(nuttx): - result = NEPOLL_MAX - else: - result = 1024 # Retrieve the maximum fd count (for current OS) via getrlimit() - var maxFD = maxDescriptors() + var a = RLimit() + if getrlimit(posix.RLIMIT_NOFILE, a) != 0: + raiseOSError(osLastError()) + var maxFD = int(a.rlim_max) doAssert(maxFD > 0) # Start with a reasonable size, checkFd() will grow this on demand - let numFD = initialNumFD() + const numFD = 1024 - var epollFD = epoll_create1(O_CLOEXEC) + var epollFD = epoll_create(MAX_EPOLL_EVENTS) if epollFD < 0: raiseOSError(osLastError()) @@ -112,9 +110,10 @@ proc close*[T](s: Selector[T]) = raiseIOSelectorsError(osLastError()) proc newSelectEvent*(): SelectEvent = - let fdci = eventfd(0, O_CLOEXEC or O_NONBLOCK) + let fdci = eventfd(0, 0) if fdci == -1: raiseIOSelectorsError(osLastError()) + setNonBlocking(fdci) result = cast[SelectEvent](allocShared0(sizeof(SelectEventImpl))) result.efd = fdci @@ -270,9 +269,10 @@ proc registerTimer*[T](s: Selector[T], timeout: int, oneshot: bool, var newTs: Itimerspec oldTs: Itimerspec - let fdi = timerfd_create(CLOCK_MONOTONIC, O_CLOEXEC or O_NONBLOCK).int + let fdi = timerfd_create(CLOCK_MONOTONIC, 0).int if fdi == -1: raiseIOSelectorsError(osLastError()) + setNonBlocking(fdi.cint) s.checkFd(fdi) doAssert(s.fds[fdi].ident == InvalidIdent) @@ -314,9 +314,10 @@ when not defined(android): discard sigaddset(nmask, cint(signal)) blockSignals(nmask, omask) - let fdi = signalfd(-1, nmask, O_CLOEXEC or O_NONBLOCK).int + let fdi = signalfd(-1, nmask, 0).int if fdi == -1: raiseIOSelectorsError(osLastError()) + setNonBlocking(fdi.cint) s.checkFd(fdi) doAssert(s.fds[fdi].ident == InvalidIdent) @@ -340,9 +341,10 @@ when not defined(android): discard sigaddset(nmask, posix.SIGCHLD) blockSignals(nmask, omask) - let fdi = signalfd(-1, nmask, O_CLOEXEC or O_NONBLOCK).int + let fdi = signalfd(-1, nmask, 0).int if fdi == -1: raiseIOSelectorsError(osLastError()) + setNonBlocking(fdi.cint) s.checkFd(fdi) doAssert(s.fds[fdi].ident == InvalidIdent) @@ -516,7 +518,7 @@ template withData*[T](s: Selector[T], fd: SocketHandle|int, value, let fdi = int(fd) s.checkFd(fdi) if fdi in s: - var value = addr(s.fds[fdi].data) + var value = addr(s.getData(fdi)) body template withData*[T](s: Selector[T], fd: SocketHandle|int, value, body1, @@ -525,10 +527,10 @@ template withData*[T](s: Selector[T], fd: SocketHandle|int, value, body1, let fdi = int(fd) s.checkFd(fdi) if fdi in s: - var value = addr(s.fds[fdi].data) + var value = addr(s.getData(fdi)) body1 else: body2 proc getFd*[T](s: Selector[T]): int = - return s.epollFD.int + return s.epollFd.int diff --git a/lib/pure/ioselects/ioselectors_kqueue.nim b/lib/pure/ioselects/ioselectors_kqueue.nim index 68be969c7..83e15d479 100644 --- a/lib/pure/ioselects/ioselectors_kqueue.nim +++ b/lib/pure/ioselects/ioselectors_kqueue.nim @@ -9,7 +9,7 @@ # This module implements BSD kqueue(). -import posix, times, kqueue, nativesockets +import posix, times, kqueue const # Maximum number of events that can be returned. @@ -30,7 +30,7 @@ when defined(macosx) or defined(freebsd) or defined(dragonfly): proc sysctl(name: ptr cint, namelen: cuint, oldp: pointer, oldplen: ptr csize_t, newp: pointer, newplen: csize_t): cint {.importc: "sysctl",header: """#include - #include """.} + #include """} elif defined(netbsd) or defined(openbsd): # OpenBSD and NetBSD don't have KERN_MAXFILESPERPROC, so we are using # KERN_MAXFILES, because KERN_MAXFILES is always bigger, @@ -39,7 +39,7 @@ elif defined(netbsd) or defined(openbsd): proc sysctl(name: ptr cint, namelen: cuint, oldp: pointer, oldplen: ptr csize_t, newp: pointer, newplen: csize_t): cint {.importc: "sysctl",header: """#include - #include """.} + #include """} when hasThreadSupport: type @@ -48,7 +48,7 @@ when hasThreadSupport: maxFD: int changes: ptr SharedArray[KEvent] fds: ptr SharedArray[SelectorKey[T]] - count*: int + count: int changesLock: Lock changesSize: int changesLength: int @@ -61,7 +61,7 @@ else: maxFD: int changes: seq[KEvent] fds: seq[SelectorKey[T]] - count*: int + count: int sock: cint Selector*[T] = ref SelectorImpl[T] @@ -76,7 +76,7 @@ type proc getUnique[T](s: Selector[T]): int {.inline.} = # we create duplicated handles to get unique indexes for our `fds` array. - result = posix.fcntl(s.sock, F_DUPFD_CLOEXEC, s.sock) + result = posix.fcntl(s.sock, F_DUPFD, s.sock) if result == -1: raiseIOSelectorsError(osLastError()) @@ -96,8 +96,8 @@ proc newSelector*[T](): owned(Selector[T]) = # we allocating empty socket to duplicate it handle in future, to get unique # indexes for `fds` array. This is needed to properly identify # {Event.Timer, Event.Signal, Event.Process} events. - let usock = createNativeSocket(posix.AF_INET, posix.SOCK_STREAM, - posix.IPPROTO_TCP).cint + let usock = posix.socket(posix.AF_INET, posix.SOCK_STREAM, + posix.IPPROTO_TCP).cint if usock == -1: let err = osLastError() discard posix.close(kqFD) @@ -616,7 +616,7 @@ template withData*[T](s: Selector[T], fd: SocketHandle|int, value, let fdi = int(fd) s.checkFd(fdi) if fdi in s: - var value = addr(s.fds[fdi].data) + var value = addr(s.getData(fdi)) body template withData*[T](s: Selector[T], fd: SocketHandle|int, value, body1, @@ -625,7 +625,7 @@ template withData*[T](s: Selector[T], fd: SocketHandle|int, value, body1, let fdi = int(fd) s.checkFd(fdi) if fdi in s: - var value = addr(s.fds[fdi].data) + var value = addr(s.getData(fdi)) body1 else: body2 diff --git a/lib/pure/ioselects/ioselectors_poll.nim b/lib/pure/ioselects/ioselectors_poll.nim index 12812ac80..1af2a46db 100644 --- a/lib/pure/ioselects/ioselectors_poll.nim +++ b/lib/pure/ioselects/ioselectors_poll.nim @@ -14,12 +14,6 @@ import posix, times # Maximum number of events that can be returned const MAX_POLL_EVENTS = 64 -const hasEventFds = defined(zephyr) or defined(nimPollHasEventFds) - -when hasEventFds: - proc eventfd(count: cuint, flags: cint): cint - {.cdecl, importc: "eventfd", header: "".} - when hasThreadSupport: type SelectorImpl[T] = object @@ -27,7 +21,7 @@ when hasThreadSupport: pollcnt: int fds: ptr SharedArray[SelectorKey[T]] pollfds: ptr SharedArray[TPollFd] - count*: int + count: int lock: Lock Selector*[T] = ptr SelectorImpl[T] else: @@ -37,7 +31,7 @@ else: pollcnt: int fds: seq[SelectorKey[T]] pollfds: seq[TPollFd] - count*: int + count: int Selector*[T] = ref SelectorImpl[T] type @@ -59,7 +53,10 @@ else: body proc newSelector*[T](): Selector[T] = - var maxFD = maxDescriptors() + var a = RLimit() + if getrlimit(posix.RLIMIT_NOFILE, a) != 0: + raiseIOSelectorsError(osLastError()) + var maxFD = int(a.rlim_max) when hasThreadSupport: result = cast[Selector[T]](allocShared0(sizeof(SelectorImpl[T]))) @@ -190,22 +187,14 @@ proc unregister*[T](s: Selector[T], ev: SelectEvent) = s.pollRemove(fdi.cint) proc newSelectEvent*(): SelectEvent = - when not hasEventFds: - var fds: array[2, cint] - if posix.pipe(fds) != 0: - raiseIOSelectorsError(osLastError()) - setNonBlocking(fds[0]) - setNonBlocking(fds[1]) - result = cast[SelectEvent](allocShared0(sizeof(SelectEventImpl))) - result.rfd = fds[0] - result.wfd = fds[1] - else: - let fdci = eventfd(0, posix.O_NONBLOCK) - if fdci == -1: - raiseIOSelectorsError(osLastError()) - result = cast[SelectEvent](allocShared0(sizeof(SelectEventImpl))) - result.rfd = fdci - result.wfd = fdci + var fds: array[2, cint] + if posix.pipe(fds) != 0: + raiseIOSelectorsError(osLastError()) + setNonBlocking(fds[0]) + setNonBlocking(fds[1]) + result = cast[SelectEvent](allocShared0(sizeof(SelectEventImpl))) + result.rfd = fds[0] + result.wfd = fds[1] proc trigger*(ev: SelectEvent) = var data: uint64 = 1 @@ -214,16 +203,13 @@ proc trigger*(ev: SelectEvent) = proc close*(ev: SelectEvent) = let res1 = posix.close(ev.rfd) - let res2 = - when hasEventFds: 0 - else: posix.close(ev.wfd) - + let res2 = posix.close(ev.wfd) deallocShared(cast[pointer](ev)) if res1 != 0 or res2 != 0: raiseIOSelectorsError(osLastError()) proc selectInto*[T](s: Selector[T], timeout: int, - results: var openArray[ReadyKey]): int = + results: var openarray[ReadyKey]): int = var maxres = MAX_POLL_EVENTS if maxres > len(results): maxres = len(results) diff --git a/lib/pure/ioselects/ioselectors_select.nim b/lib/pure/ioselects/ioselectors_select.nim index a6f54e791..b90a01c06 100644 --- a/lib/pure/ioselects/ioselectors_select.nim +++ b/lib/pure/ioselects/ioselectors_select.nim @@ -26,27 +26,27 @@ else: #include #include """ type - FdSet {.importc: "fd_set", header: platformHeaders, pure, final.} = object + Fdset {.importc: "fd_set", header: platformHeaders, pure, final.} = object var FD_SETSIZE {.importc: "FD_SETSIZE", header: platformHeaders.}: cint -proc IOFD_SET(fd: SocketHandle, fdset: ptr FdSet) +proc IOFD_SET(fd: SocketHandle, fdset: ptr Fdset) {.cdecl, importc: "FD_SET", header: platformHeaders, inline.} -proc IOFD_CLR(fd: SocketHandle, fdset: ptr FdSet) +proc IOFD_CLR(fd: SocketHandle, fdset: ptr Fdset) {.cdecl, importc: "FD_CLR", header: platformHeaders, inline.} -proc IOFD_ZERO(fdset: ptr FdSet) +proc IOFD_ZERO(fdset: ptr Fdset) {.cdecl, importc: "FD_ZERO", header: platformHeaders, inline.} when defined(windows): - proc IOFD_ISSET(fd: SocketHandle, fdset: ptr FdSet): cint + proc IOFD_ISSET(fd: SocketHandle, fdset: ptr Fdset): cint {.stdcall, importc: "FD_ISSET", header: platformHeaders, inline.} - proc ioselect(nfds: cint, readFds, writeFds, exceptFds: ptr FdSet, + proc ioselect(nfds: cint, readFds, writeFds, exceptFds: ptr Fdset, timeout: ptr Timeval): cint {.stdcall, importc: "select", header: platformHeaders.} else: - proc IOFD_ISSET(fd: SocketHandle, fdset: ptr FdSet): cint + proc IOFD_ISSET(fd: SocketHandle, fdset: ptr Fdset): cint {.cdecl, importc: "FD_ISSET", header: platformHeaders, inline.} - proc ioselect(nfds: cint, readFds, writeFds, exceptFds: ptr FdSet, + proc ioselect(nfds: cint, readFds, writeFds, exceptFds: ptr Fdset, timeout: ptr Timeval): cint {.cdecl, importc: "select", header: platformHeaders.} @@ -58,7 +58,7 @@ when hasThreadSupport: eSet: FdSet maxFD: int fds: ptr SharedArray[SelectorKey[T]] - count*: int + count: int lock: Lock Selector*[T] = ptr SelectorImpl[T] else: @@ -69,7 +69,7 @@ else: eSet: FdSet maxFD: int fds: seq[SelectorKey[T]] - count*: int + count: int Selector*[T] = ref SelectorImpl[T] type @@ -110,12 +110,11 @@ proc close*[T](s: Selector[T]) = when hasThreadSupport: deallocSharedArray(s.fds) deallocShared(cast[pointer](s)) - deinitLock(s.lock) when defined(windows): proc newSelectEvent*(): SelectEvent = - var ssock = createNativeSocket() - var wsock = createNativeSocket() + var ssock = newNativeSocket() + var wsock = newNativeSocket() var rsock: SocketHandle = INVALID_SOCKET var saddr = Sockaddr_in() @@ -305,7 +304,7 @@ proc unregister*[T](s: Selector[T], ev: SelectEvent) = s.delKey(fd) proc selectInto*[T](s: Selector[T], timeout: int, - results: var openArray[ReadyKey]): int = + results: var openarray[ReadyKey]): int = var tv = Timeval() var ptv = addr tv var rset, wset, eset: FdSet @@ -313,7 +312,7 @@ proc selectInto*[T](s: Selector[T], timeout: int, verifySelectParams(timeout) if timeout != -1: - when defined(genode) or defined(freertos) or defined(zephyr) or defined(nuttx): + when defined(genode): tv.tv_sec = Time(timeout div 1_000) else: tv.tv_sec = timeout.int32 div 1_000 @@ -398,6 +397,18 @@ proc contains*[T](s: Selector[T], fd: SocketHandle|int): bool {.inline.} = if s.fds[i].ident == fdi: return true +when hasThreadSupport: + template withSelectLock[T](s: Selector[T], body: untyped) = + acquire(s.lock) + {.locks: [s.lock].}: + try: + body + finally: + release(s.lock) +else: + template withSelectLock[T](s: Selector[T], body: untyped) = + body + proc getData*[T](s: Selector[T], fd: SocketHandle|int): var T = s.withSelectLock(): let fdi = int(fd) diff --git a/lib/pure/json.nim b/lib/pure/json.nim index d91da3545..319a7b7ff 100644 --- a/lib/pure/json.nim +++ b/lib/pure/json.nim @@ -14,35 +14,27 @@ ## JSON is based on a subset of the JavaScript Programming Language, ## Standard ECMA-262 3rd Edition - December 1999. ## -## See also -## ======== -## * `std/parsejson `_ -## * `std/jsonutils `_ -## * `std/marshal `_ -## * `std/jscore `_ -## -## ## Overview ## ======== ## ## Parsing JSON ## ------------ ## -## JSON often arrives into your program (via an API or a file) as a `string`. +## JSON often arrives into your program (via an API or a file) as a ``string``. ## The first step is to change it from its serialized form into a nested object -## structure called a `JsonNode`. +## structure called a ``JsonNode``. ## -## The `parseJson` procedure takes a string containing JSON and returns a -## `JsonNode` object. This is an object variant and it is either a -## `JObject`, `JArray`, `JString`, `JInt`, `JFloat`, `JBool` or -## `JNull`. You check the kind of this object variant by using the `kind` +## The ``parseJson`` procedure takes a string containing JSON and returns a +## ``JsonNode`` object. This is an object variant and it is either a +## ``JObject``, ``JArray``, ``JString``, ``JInt``, ``JFloat``, ``JBool`` or +## ``JNull``. You check the kind of this object variant by using the ``kind`` ## accessor. ## -## For a `JsonNode` who's kind is `JObject`, you can access its fields using -## the `[]` operator. The following example shows how to do this: +## For a ``JsonNode`` who's kind is ``JObject``, you can access its fields using +## the ``[]`` operator. The following example shows how to do this: ## ## .. code-block:: Nim -## import std/json +## import json ## ## let jsonNode = parseJson("""{"key": 3.14}""") ## @@ -52,35 +44,35 @@ ## Reading values ## -------------- ## -## Once you have a `JsonNode`, retrieving the values can then be achieved +## Once you have a ``JsonNode``, retrieving the values can then be achieved ## by using one of the helper procedures, which include: ## -## * `getInt` -## * `getFloat` -## * `getStr` -## * `getBool` +## * ``getInt`` +## * ``getFloat`` +## * ``getStr`` +## * ``getBool`` ## -## To retrieve the value of `"key"` you can do the following: +## To retrieve the value of ``"key"`` you can do the following: ## ## .. code-block:: Nim -## import std/json +## import json ## ## let jsonNode = parseJson("""{"key": 3.14}""") ## ## doAssert jsonNode["key"].getFloat() == 3.14 ## -## **Important:** The `[]` operator will raise an exception when the +## **Important:** The ``[]`` operator will raise an exception when the ## specified field does not exist. ## ## Handling optional keys ## ---------------------- ## -## By using the `{}` operator instead of `[]`, it will return `nil` -## when the field is not found. The `get`-family of procedures will return a -## type's default value when called on `nil`. +## By using the ``{}`` operator instead of ``[]``, it will return ``nil`` +## when the field is not found. The ``get``-family of procedures will return a +## type's default value when called on ``nil``. ## ## .. code-block:: Nim -## import std/json +## import json ## ## let jsonNode = parseJson("{}") ## @@ -92,11 +84,11 @@ ## Using default values ## -------------------- ## -## The `get`-family helpers also accept an additional parameter which allow -## you to fallback to a default value should the key's values be `null`: +## The ``get``-family helpers also accept an additional parameter which allow +## you to fallback to a default value should the key's values be ``null``: ## ## .. code-block:: Nim -## import std/json +## import json ## ## let jsonNode = parseJson("""{"key": 3.14, "key2": null}""") ## @@ -108,34 +100,27 @@ ## ------------- ## ## In addition to reading dynamic data, Nim can also unmarshal JSON directly -## into a type with the `to` macro. -## -## Note: Use `Option `_ for keys sometimes missing in json -## responses, and backticks around keys with a reserved keyword as name. +## into a type with the ``to`` macro. ## ## .. code-block:: Nim -## import std/json -## import std/options +## import json ## ## type ## User = object ## name: string ## age: int -## `type`: Option[string] ## ## let userJson = parseJson("""{ "name": "Nim", "age": 12 }""") ## let user = to(userJson, User) -## if user.`type`.isSome(): -## assert user.`type`.get() != "robot" ## ## Creating JSON ## ============= ## -## This module can also be used to comfortably create JSON using the `%*` +## This module can also be used to comfortably create JSON using the ``%*`` ## operator: ## ## .. code-block:: nim -## import std/json +## import json ## ## var hisName = "John" ## let herAge = 31 @@ -148,9 +133,6 @@ ## var j2 = %* {"name": "Isaac", "books": ["Robot Dreams"]} ## j2["details"] = %* {"age":35, "pi":3.1415} ## echo j2 -## -## See also: std/jsonutils for hookable json serialization/deserialization -## of arbitrary types. runnableExamples: ## Note: for JObject, key ordering is preserved, unlike in some languages, @@ -159,13 +141,9 @@ runnableExamples: a1, a2, a0, a3, a4: int doAssert $(%* Foo()) == """{"a1":0,"a2":0,"a0":0,"a3":0,"a4":0}""" -import hashes, tables, strutils, lexbase, streams, macros, parsejson - -import options # xxx remove this dependency using same approach as https://github.com/nim-lang/Nim/pull/14563 -import std/private/since - -when defined(nimPreviewSlimSystem): - import std/[syncio, assertions, formatfloat] +import + hashes, tables, strutils, lexbase, streams, macros, parsejson, + options export tables.`$` @@ -173,7 +151,7 @@ export export parsejson.JsonEventKind, parsejson.JsonError, JsonParser, JsonKindError, open, close, str, getInt, getFloat, kind, getColumn, getLine, getFilename, - errorMsg, errorMsgExpected, next, JsonParsingError, raiseParseErr, nimIdentNormalize + errorMsg, errorMsgExpected, next, JsonParsingError, raiseParseErr type JsonNodeKind* = enum ## possible JSON node types @@ -187,8 +165,6 @@ type JsonNode* = ref JsonNodeObj ## JSON node JsonNodeObj* {.acyclic.} = object - isUnquoted: bool # the JString was a number-like token and - # so shouldn't be quoted case kind*: JsonNodeKind of JString: str*: string @@ -205,18 +181,13 @@ type of JArray: elems*: seq[JsonNode] -const DepthLimit = 1000 - proc newJString*(s: string): JsonNode = ## Creates a new `JString JsonNode`. result = JsonNode(kind: JString, str: s) -proc newJRawNumber(s: string): JsonNode = - ## Creates a "raw JS number", that is a number that does not - ## fit into Nim's `BiggestInt` field. This is really a `JString` - ## with the additional information that it should be converted back - ## to the string representation without the quotes. - result = JsonNode(kind: JString, str: s, isUnquoted: true) +proc newJStringMove(s: string): JsonNode = + result = JsonNode(kind: JString) + shallowCopy(result.str, s) proc newJInt*(n: BiggestInt): JsonNode = ## Creates a new `JInt JsonNode`. @@ -236,7 +207,7 @@ proc newJNull*(): JsonNode = proc newJObject*(): JsonNode = ## Creates a new `JObject JsonNode` - result = JsonNode(kind: JObject, fields: initOrderedTable[string, JsonNode](2)) + result = JsonNode(kind: JObject, fields: initOrderedTable[string, JsonNode](4)) proc newJArray*(): JsonNode = ## Creates a new `JArray JsonNode` @@ -245,28 +216,28 @@ proc newJArray*(): JsonNode = proc getStr*(n: JsonNode, default: string = ""): string = ## Retrieves the string value of a `JString JsonNode`. ## - ## Returns `default` if `n` is not a `JString`, or if `n` is nil. + ## Returns ``default`` if ``n`` is not a ``JString``, or if ``n`` is nil. if n.isNil or n.kind != JString: return default else: return n.str proc getInt*(n: JsonNode, default: int = 0): int = ## Retrieves the int value of a `JInt JsonNode`. ## - ## Returns `default` if `n` is not a `JInt`, or if `n` is nil. + ## Returns ``default`` if ``n`` is not a ``JInt``, or if ``n`` is nil. if n.isNil or n.kind != JInt: return default else: return int(n.num) proc getBiggestInt*(n: JsonNode, default: BiggestInt = 0): BiggestInt = ## Retrieves the BiggestInt value of a `JInt JsonNode`. ## - ## Returns `default` if `n` is not a `JInt`, or if `n` is nil. + ## Returns ``default`` if ``n`` is not a ``JInt``, or if ``n`` is nil. if n.isNil or n.kind != JInt: return default else: return n.num proc getFloat*(n: JsonNode, default: float = 0.0): float = ## Retrieves the float value of a `JFloat JsonNode`. ## - ## Returns `default` if `n` is not a `JFloat` or `JInt`, or if `n` is nil. + ## Returns ``default`` if ``n`` is not a ``JFloat`` or ``JInt``, or if ``n`` is nil. if n.isNil: return default case n.kind of JFloat: return n.fnum @@ -276,23 +247,23 @@ proc getFloat*(n: JsonNode, default: float = 0.0): float = proc getBool*(n: JsonNode, default: bool = false): bool = ## Retrieves the bool value of a `JBool JsonNode`. ## - ## Returns `default` if `n` is not a `JBool`, or if `n` is nil. + ## Returns ``default`` if ``n`` is not a ``JBool``, or if ``n`` is nil. if n.isNil or n.kind != JBool: return default else: return n.bval proc getFields*(n: JsonNode, - default = initOrderedTable[string, JsonNode](2)): + default = initOrderedTable[string, JsonNode](4)): OrderedTable[string, JsonNode] = ## Retrieves the key, value pairs of a `JObject JsonNode`. ## - ## Returns `default` if `n` is not a `JObject`, or if `n` is nil. + ## Returns ``default`` if ``n`` is not a ``JObject``, or if ``n`` is nil. if n.isNil or n.kind != JObject: return default else: return n.fields proc getElems*(n: JsonNode, default: seq[JsonNode] = @[]): seq[JsonNode] = ## Retrieves the array of a `JArray JsonNode`. ## - ## Returns `default` if `n` is not a `JArray`, or if `n` is nil. + ## Returns ``default`` if ``n`` is not a ``JArray``, or if ``n`` is nil. if n.isNil or n.kind != JArray: return default else: return n.elems @@ -312,10 +283,7 @@ proc `%`*(s: string): JsonNode = proc `%`*(n: uint): JsonNode = ## Generic constructor for JSON data. Creates a new `JInt JsonNode`. - if n > cast[uint](int.high): - result = newJRawNumber($n) - else: - result = JsonNode(kind: JInt, num: BiggestInt(n)) + result = JsonNode(kind: JInt, num: BiggestInt(n)) proc `%`*(n: int): JsonNode = ## Generic constructor for JSON data. Creates a new `JInt JsonNode`. @@ -323,10 +291,7 @@ proc `%`*(n: int): JsonNode = proc `%`*(n: BiggestUInt): JsonNode = ## Generic constructor for JSON data. Creates a new `JInt JsonNode`. - if n > cast[BiggestUInt](BiggestInt.high): - result = newJRawNumber($n) - else: - result = JsonNode(kind: JInt, num: BiggestInt(n)) + result = JsonNode(kind: JInt, num: BiggestInt(n)) proc `%`*(n: BiggestInt): JsonNode = ## Generic constructor for JSON data. Creates a new `JInt JsonNode`. @@ -334,16 +299,7 @@ proc `%`*(n: BiggestInt): JsonNode = proc `%`*(n: float): JsonNode = ## Generic constructor for JSON data. Creates a new `JFloat JsonNode`. - runnableExamples: - assert $(%[NaN, Inf, -Inf, 0.0, -0.0, 1.0, 1e-2]) == """["nan","inf","-inf",0.0,-0.0,1.0,0.01]""" - assert (%NaN).kind == JString - assert (%0.0).kind == JFloat - # for those special cases, we could also have used `newJRawNumber` but then - # it would've been inconsisten with the case of `parseJson` vs `%` for representing them. - if n != n: newJString("nan") - elif n == Inf: newJString("inf") - elif n == -Inf: newJString("-inf") - else: JsonNode(kind: JFloat, fnum: n) + result = JsonNode(kind: JFloat, fnum: n) proc `%`*(b: bool): JsonNode = ## Generic constructor for JSON data. Creates a new `JBool JsonNode`. @@ -363,13 +319,13 @@ proc `%`*[T](elements: openArray[T]): JsonNode = for elem in elements: result.add(%elem) proc `%`*[T](table: Table[string, T]|OrderedTable[string, T]): JsonNode = - ## Generic constructor for JSON data. Creates a new `JObject JsonNode`. + ## Generic constructor for JSON data. Creates a new ``JObject JsonNode``. result = newJObject() for k, v in table: result[k] = %v proc `%`*[T](opt: Option[T]): JsonNode = - ## Generic constructor for JSON data. Creates a new `JNull JsonNode` - ## if `opt` is empty, otherwise it delegates to the underlying value. + ## Generic constructor for JSON data. Creates a new ``JNull JsonNode`` + ## if ``opt`` is empty, otherwise it delegates to the underlying value. if opt.isSome: %opt.get else: newJNull() when false: @@ -378,8 +334,8 @@ when false: # causing problems later on. proc `%`*(elements: set[bool]): JsonNode = ## Generic constructor for JSON data. Creates a new `JObject JsonNode`. - ## This can only be used with the empty set `{}` and is supported - ## to prevent the gotcha `%*{}` which used to produce an empty + ## This can only be used with the empty set ``{}`` and is supported + ## to prevent the gotcha ``%*{}`` which used to produce an empty ## JSON array. result = newJObject() assert false notin elements, "usage error: only empty sets allowed" @@ -404,23 +360,23 @@ proc `%`*(o: ref object): JsonNode = proc `%`*(o: enum): JsonNode = ## Construct a JsonNode that represents the specified enum value as a - ## string. Creates a new `JString JsonNode`. + ## string. Creates a new ``JString JsonNode``. result = %($o) -proc toJsonImpl(x: NimNode): NimNode = +proc toJson(x: NimNode): NimNode {.compileTime.} = case x.kind of nnkBracket: # array if x.len == 0: return newCall(bindSym"newJArray") result = newNimNode(nnkBracket) for i in 0 ..< x.len: - result.add(toJsonImpl(x[i])) + result.add(toJson(x[i])) result = newCall(bindSym("%", brOpen), result) of nnkTableConstr: # object if x.len == 0: return newCall(bindSym"newJObject") result = newNimNode(nnkTableConstr) for i in 0 ..< x.len: x[i].expectKind nnkExprColonExpr - result.add newTree(nnkExprColonExpr, x[i][0], toJsonImpl(x[i][1])) + result.add newTree(nnkExprColonExpr, x[i][0], toJson(x[i][1])) result = newCall(bindSym("%", brOpen), result) of nnkCurly: # empty object x.expectLen(0) @@ -428,7 +384,7 @@ proc toJsonImpl(x: NimNode): NimNode = of nnkNilLit: result = newCall(bindSym"newJNull") of nnkPar: - if x.len == 1: result = toJsonImpl(x[0]) + if x.len == 1: result = toJson(x[0]) else: result = newCall(bindSym("%", brOpen), x) else: result = newCall(bindSym("%", brOpen), x) @@ -436,9 +392,9 @@ proc toJsonImpl(x: NimNode): NimNode = macro `%*`*(x: untyped): untyped = ## Convert an expression to a JsonNode directly, without having to specify ## `%` for every element. - result = toJsonImpl(x) + result = toJson(x) -proc `==`*(a, b: JsonNode): bool {.noSideEffect.} = +proc `==`*(a, b: JsonNode): bool = ## Check two nodes for equality if a.isNil: if b.isNil: return true @@ -465,17 +421,12 @@ proc `==`*(a, b: JsonNode): bool {.noSideEffect.} = if a.fields.len != b.fields.len: return false for key, val in a.fields: if not b.fields.hasKey(key): return false - {.cast(raises: []).}: - when defined(nimHasEffectsOf): - {.noSideEffect.}: - if b.fields[key] != val: return false - else: - if b.fields[key] != val: return false + if b.fields[key] != val: return false result = true proc hash*(n: OrderedTable[string, JsonNode]): Hash {.noSideEffect.} -proc hash*(n: JsonNode): Hash {.noSideEffect.} = +proc hash*(n: JsonNode): Hash = ## Compute the hash for a JSON node case n.kind of JArray: @@ -524,37 +475,6 @@ proc `[]`*(node: JsonNode, index: int): JsonNode {.inline.} = assert(node.kind == JArray) return node.elems[index] -proc `[]`*(node: JsonNode, index: BackwardsIndex): JsonNode {.inline, since: (1, 5, 1).} = - ## Gets the node at `array.len-i` in an array through the `^` operator. - ## - ## i.e. `j[^i]` is a shortcut for `j[j.len-i]`. - runnableExamples: - let - j = parseJson("[1,2,3,4,5]") - - doAssert j[^1].getInt == 5 - doAssert j[^2].getInt == 4 - - `[]`(node, node.len - int(index)) - -proc `[]`*[U, V](a: JsonNode, x: HSlice[U, V]): JsonNode = - ## Slice operation for JArray. - ## - ## Returns the inclusive range `[a[x.a], a[x.b]]`: - runnableExamples: - import json - let arr = %[0,1,2,3,4,5] - doAssert arr[2..4] == %[2,3,4] - doAssert arr[2..^2] == %[2,3,4] - doAssert arr[^4..^2] == %[2,3,4] - - assert(a.kind == JArray) - result = newJArray() - let xa = (when x.a is BackwardsIndex: a.len - int(x.a) else: int(x.a)) - let L = (when x.b is BackwardsIndex: a.len - int(x.b) else: int(x.b)) - xa + 1 - for i in 0.. DepthLimit: - raiseParseErr(p, "}") result = newJObject() discard getTok(p) while p.tok != tkCurlyRi: @@ -901,81 +801,69 @@ proc parseJson(p: var JsonParser; rawIntegers, rawFloats: bool, depth = 0): Json var key = p.a discard getTok(p) eat(p, tkColon) - var val = parseJson(p, rawIntegers, rawFloats, depth+1) + var val = parseJson(p) result[key] = val if p.tok != tkComma: break discard getTok(p) eat(p, tkCurlyRi) of tkBracketLe: - if depth > DepthLimit: - raiseParseErr(p, "]") result = newJArray() discard getTok(p) while p.tok != tkBracketRi: - result.add(parseJson(p, rawIntegers, rawFloats, depth+1)) + result.add(parseJson(p)) if p.tok != tkComma: break discard getTok(p) eat(p, tkBracketRi) of tkError, tkCurlyRi, tkBracketRi, tkColon, tkComma, tkEof: raiseParseErr(p, "{") -iterator parseJsonFragments*(s: Stream, filename: string = ""; rawIntegers = false, rawFloats = false): JsonNode = +iterator parseJsonFragments*(s: Stream, filename: string = ""): JsonNode = ## Parses from a stream `s` into `JsonNodes`. `filename` is only needed ## for nice error messages. ## The JSON fragments are separated by whitespace. This can be substantially ## faster than the comparable loop - ## `for x in splitWhitespace(s): yield parseJson(x)`. + ## ``for x in splitWhitespace(s): yield parseJson(x)``. ## This closes the stream `s` after it's done. - ## If `rawIntegers` is true, integer literals will not be converted to a `JInt` - ## field but kept as raw numbers via `JString`. - ## If `rawFloats` is true, floating point literals will not be converted to a `JFloat` - ## field but kept as raw numbers via `JString`. var p: JsonParser p.open(s, filename) try: discard getTok(p) # read first token while p.tok != tkEof: - yield p.parseJson(rawIntegers, rawFloats) + yield p.parseJson() finally: p.close() -proc parseJson*(s: Stream, filename: string = ""; rawIntegers = false, rawFloats = false): JsonNode = +proc parseJson*(s: Stream, filename: string = ""): JsonNode = ## Parses from a stream `s` into a `JsonNode`. `filename` is only needed ## for nice error messages. ## If `s` contains extra data, it will raise `JsonParsingError`. ## This closes the stream `s` after it's done. - ## If `rawIntegers` is true, integer literals will not be converted to a `JInt` - ## field but kept as raw numbers via `JString`. - ## If `rawFloats` is true, floating point literals will not be converted to a `JFloat` - ## field but kept as raw numbers via `JString`. var p: JsonParser p.open(s, filename) try: discard getTok(p) # read first token - result = p.parseJson(rawIntegers, rawFloats) + result = p.parseJson() eat(p, tkEof) # check if there is no extra data finally: p.close() when defined(js): from math import `mod` - from std/jsffi import JsObject, `[]`, to - from std/private/jsutils import getProtoName, isInteger, isSafeInteger + type + JSObject = object - proc parseNativeJson(x: cstring): JsObject {.importjs: "JSON.parse(#)".} + proc parseNativeJson(x: cstring): JSObject {.importc: "JSON.parse".} - proc getVarType(x: JsObject, isRawNumber: var bool): JsonNodeKind = + proc getVarType(x: JSObject): JsonNodeKind = result = JNull + proc getProtoName(y: JSObject): cstring + {.importc: "Object.prototype.toString.call".} case $getProtoName(x) # TODO: Implicit returns fail here. of "[object Array]": return JArray of "[object Object]": return JObject of "[object Number]": - if isInteger(x) and 1.0 / cast[float](x) != -Inf: # preserve -0.0 as float - if isSafeInteger(x): - return JInt - else: - isRawNumber = true - return JString + if cast[float](x) mod 1.0 == 0: + return JInt else: return JFloat of "[object Boolean]": return JBool @@ -983,14 +871,26 @@ when defined(js): of "[object String]": return JString else: assert false - proc len(x: JsObject): int = + proc len(x: JSObject): int = + assert x.getVarType == JArray asm """ `result` = `x`.length; """ - proc convertObject(x: JsObject): JsonNode = - var isRawNumber = false - case getVarType(x, isRawNumber) + proc `[]`(x: JSObject, y: string): JSObject = + assert x.getVarType == JObject + asm """ + `result` = `x`[`y`]; + """ + + proc `[]`(x: JSObject, y: int): JSObject = + assert x.getVarType == JArray + asm """ + `result` = `x`[`y`]; + """ + + proc convertObject(x: JSObject): JsonNode = + case getVarType(x) of JArray: result = newJArray() for i in 0 ..< x.len: @@ -1001,24 +901,18 @@ when defined(js): if (`x`.hasOwnProperty(property)) { """ var nimProperty: cstring - var nimValue: JsObject + var nimValue: JSObject asm "`nimProperty` = property; `nimValue` = `x`[property];" result[$nimProperty] = nimValue.convertObject() asm "}}" of JInt: - result = newJInt(x.to(int)) + result = newJInt(cast[int](x)) of JFloat: - result = newJFloat(x.to(float)) + result = newJFloat(cast[float](x)) of JString: - # Dunno what to do with isUnquoted here - if isRawNumber: - var value: cstring - {.emit: "`value` = `x`.toString();".} - result = newJRawNumber($value) - else: - result = newJString($x.to(cstring)) + result = newJString($cast[cstring](x)) of JBool: - result = newJBool(x.to(bool)) + result = newJBool(cast[bool](x)) of JNull: result = newJNull() @@ -1029,14 +923,10 @@ when defined(js): return parseNativeJson(buffer).convertObject() else: - proc parseJson*(buffer: string; rawIntegers = false, rawFloats = false): JsonNode = + proc parseJson*(buffer: string): JsonNode = ## Parses JSON from `buffer`. ## If `buffer` contains extra data, it will raise `JsonParsingError`. - ## If `rawIntegers` is true, integer literals will not be converted to a `JInt` - ## field but kept as raw numbers via `JString`. - ## If `rawFloats` is true, floating point literals will not be converted to a `JFloat` - ## field but kept as raw numbers via `JString`. - result = parseJson(newStringStream(buffer), "input", rawIntegers, rawFloats) + result = parseJson(newStringStream(buffer), "input") proc parseFile*(filename: string): JsonNode = ## Parses `file` into a `JsonNode`. @@ -1044,7 +934,7 @@ else: var stream = newFileStream(filename, fmRead) if stream == nil: raise newException(IOError, "cannot read from file: " & filename) - result = parseJson(stream, filename, rawIntegers=false, rawFloats=false) + result = parseJson(stream, filename) # -- Json deserialiser. -- @@ -1060,309 +950,283 @@ template verifyJsonKind(node: JsonNode, kinds: set[JsonNodeKind], ] raise newException(JsonKindError, msg) -macro isRefSkipDistinct*(arg: typed): untyped = - ## internal only, do not use - var impl = getTypeImpl(arg) - if impl.kind == nnkBracketExpr and impl[0].eqIdent("typeDesc"): - impl = getTypeImpl(impl[1]) - while impl.kind == nnkDistinctTy: - impl = getTypeImpl(impl[0]) - result = newLit(impl.kind == nnkRefTy) +when defined(nimFixedForwardGeneric): -# The following forward declarations don't work in older versions of Nim + macro isRefSkipDistinct(arg: typed): untyped = + var impl = getTypeImpl(arg) + if impl.kind == nnkBracketExpr and impl[0].eqIdent("typeDesc"): + impl = getTypeImpl(impl[1]) + while impl.kind == nnkDistinctTy: + impl = getTypeImpl(impl[0]) + result = newLit(impl.kind == nnkRefTy) -# forward declare all initFromJson + # The following forward declarations don't work in older versions of Nim -proc initFromJson(dst: var string; jsonNode: JsonNode; jsonPath: var string) -proc initFromJson(dst: var bool; jsonNode: JsonNode; jsonPath: var string) -proc initFromJson(dst: var JsonNode; jsonNode: JsonNode; jsonPath: var string) -proc initFromJson[T: SomeInteger](dst: var T; jsonNode: JsonNode, jsonPath: var string) -proc initFromJson[T: SomeFloat](dst: var T; jsonNode: JsonNode; jsonPath: var string) -proc initFromJson[T: enum](dst: var T; jsonNode: JsonNode; jsonPath: var string) -proc initFromJson[T](dst: var seq[T]; jsonNode: JsonNode; jsonPath: var string) -proc initFromJson[S, T](dst: var array[S, T]; jsonNode: JsonNode; jsonPath: var string) -proc initFromJson[T](dst: var Table[string, T]; jsonNode: JsonNode; jsonPath: var string) -proc initFromJson[T](dst: var OrderedTable[string, T]; jsonNode: JsonNode; jsonPath: var string) -proc initFromJson[T](dst: var ref T; jsonNode: JsonNode; jsonPath: var string) -proc initFromJson[T](dst: var Option[T]; jsonNode: JsonNode; jsonPath: var string) -proc initFromJson[T: distinct](dst: var T; jsonNode: JsonNode; jsonPath: var string) -proc initFromJson[T: object|tuple](dst: var T; jsonNode: JsonNode; jsonPath: var string) + # forward declare all initFromJson -# initFromJson definitions + proc initFromJson(dst: var string; jsonNode: JsonNode; jsonPath: var string) + proc initFromJson(dst: var bool; jsonNode: JsonNode; jsonPath: var string) + proc initFromJson(dst: var JsonNode; jsonNode: JsonNode; jsonPath: var string) + proc initFromJson[T: SomeInteger](dst: var T; jsonNode: JsonNode, jsonPath: var string) + proc initFromJson[T: SomeFloat](dst: var T; jsonNode: JsonNode; jsonPath: var string) + proc initFromJson[T: enum](dst: var T; jsonNode: JsonNode; jsonPath: var string) + proc initFromJson[T](dst: var seq[T]; jsonNode: JsonNode; jsonPath: var string) + proc initFromJson[S,T](dst: var array[S,T]; jsonNode: JsonNode; jsonPath: var string) + proc initFromJson[T](dst: var Table[string,T];jsonNode: JsonNode; jsonPath: var string) + proc initFromJson[T](dst: var OrderedTable[string,T];jsonNode: JsonNode; jsonPath: var string) + proc initFromJson[T](dst: var ref T; jsonNode: JsonNode; jsonPath: var string) + proc initFromJson[T](dst: var Option[T]; jsonNode: JsonNode; jsonPath: var string) + proc initFromJson[T: distinct](dst: var T;jsonNode: JsonNode; jsonPath: var string) + proc initFromJson[T: object|tuple](dst: var T; jsonNode: JsonNode; jsonPath: var string) -proc initFromJson(dst: var string; jsonNode: JsonNode; jsonPath: var string) = - verifyJsonKind(jsonNode, {JString, JNull}, jsonPath) - # since strings don't have a nil state anymore, this mapping of - # JNull to the default string is questionable. `none(string)` and - # `some("")` have the same potentional json value `JNull`. - if jsonNode.kind == JNull: - dst = "" - else: - dst = jsonNode.str + # initFromJson definitions -proc initFromJson(dst: var bool; jsonNode: JsonNode; jsonPath: var string) = - verifyJsonKind(jsonNode, {JBool}, jsonPath) - dst = jsonNode.bval - -proc initFromJson(dst: var JsonNode; jsonNode: JsonNode; jsonPath: var string) = - if jsonNode == nil: - raise newException(KeyError, "key not found: " & jsonPath) - dst = jsonNode.copy - -proc initFromJson[T: SomeInteger](dst: var T; jsonNode: JsonNode, jsonPath: var string) = - when T is uint|uint64 or (not defined(js) and int.sizeof == 4): - verifyJsonKind(jsonNode, {JInt, JString}, jsonPath) - case jsonNode.kind - of JString: - let x = parseBiggestUInt(jsonNode.str) - dst = cast[T](x) + proc initFromJson(dst: var string; jsonNode: JsonNode; jsonPath: var string) = + verifyJsonKind(jsonNode, {JString, JNull}, jsonPath) + # since strings don't have a nil state anymore, this mapping of + # JNull to the default string is questionable. `none(string)` and + # `some("")` have the same potentional json value `JNull`. + if jsonNode.kind == JNull: + dst = "" else: - dst = T(jsonNode.num) - else: - verifyJsonKind(jsonNode, {JInt}, jsonPath) - dst = cast[T](jsonNode.num) + dst = jsonNode.str -proc initFromJson[T: SomeFloat](dst: var T; jsonNode: JsonNode; jsonPath: var string) = - if jsonNode.kind == JString: - case jsonNode.str - of "nan": - let b = NaN - dst = T(b) - # dst = NaN # would fail some tests because range conversions would cause CT error - # in some cases; but this is not a hot-spot inside this branch and backend can optimize this. - of "inf": - let b = Inf - dst = T(b) - of "-inf": - let b = -Inf - dst = T(b) - else: raise newException(JsonKindError, "expected 'nan|inf|-inf', got " & jsonNode.str) - else: + proc initFromJson(dst: var bool; jsonNode: JsonNode; jsonPath: var string) = + verifyJsonKind(jsonNode, {JBool}, jsonPath) + dst = jsonNode.bval + + proc initFromJson(dst: var JsonNode; jsonNode: JsonNode; jsonPath: var string) = + dst = jsonNode.copy + + proc initFromJson[T: SomeInteger](dst: var T; jsonNode: JsonNode, jsonPath: var string) = + verifyJsonKind(jsonNode, {JInt}, jsonPath) + dst = T(jsonNode.num) + + proc initFromJson[T: SomeFloat](dst: var T; jsonNode: JsonNode; jsonPath: var string) = verifyJsonKind(jsonNode, {JInt, JFloat}, jsonPath) if jsonNode.kind == JFloat: dst = T(jsonNode.fnum) else: dst = T(jsonNode.num) -proc initFromJson[T: enum](dst: var T; jsonNode: JsonNode; jsonPath: var string) = - verifyJsonKind(jsonNode, {JString}, jsonPath) - dst = parseEnum[T](jsonNode.getStr) + proc initFromJson[T: enum](dst: var T; jsonNode: JsonNode; jsonPath: var string) = + verifyJsonKind(jsonNode, {JString}, jsonPath) + dst = parseEnum[T](jsonNode.getStr) -proc initFromJson[T](dst: var seq[T]; jsonNode: JsonNode; jsonPath: var string) = - verifyJsonKind(jsonNode, {JArray}, jsonPath) - dst.setLen jsonNode.len - let orignalJsonPathLen = jsonPath.len - for i in 0 ..< jsonNode.len: - jsonPath.add '[' - jsonPath.addInt i - jsonPath.add ']' - initFromJson(dst[i], jsonNode[i], jsonPath) - jsonPath.setLen orignalJsonPathLen + proc initFromJson[T](dst: var seq[T]; jsonNode: JsonNode; jsonPath: var string) = + verifyJsonKind(jsonNode, {JArray}, jsonPath) + dst.setLen jsonNode.len + let orignalJsonPathLen = jsonPath.len + for i in 0 ..< jsonNode.len: + jsonPath.add '[' + jsonPath.addInt i + jsonPath.add ']' + initFromJson(dst[i], jsonNode[i], jsonPath) + jsonPath.setLen orignalJsonPathLen -proc initFromJson[S,T](dst: var array[S,T]; jsonNode: JsonNode; jsonPath: var string) = - verifyJsonKind(jsonNode, {JArray}, jsonPath) - let originalJsonPathLen = jsonPath.len - for i in 0 ..< jsonNode.len: - jsonPath.add '[' - jsonPath.addInt i - jsonPath.add ']' - initFromJson(dst[i.S], jsonNode[i], jsonPath) # `.S` for enum indexed arrays - jsonPath.setLen originalJsonPathLen + proc initFromJson[S,T](dst: var array[S,T]; jsonNode: JsonNode; jsonPath: var string) = + verifyJsonKind(jsonNode, {JArray}, jsonPath) + let originalJsonPathLen = jsonPath.len + for i in 0 ..< jsonNode.len: + jsonPath.add '[' + jsonPath.addInt i + jsonPath.add ']' + initFromJson(dst[i], jsonNode[i], jsonPath) + jsonPath.setLen originalJsonPathLen -proc initFromJson[T](dst: var Table[string,T]; jsonNode: JsonNode; jsonPath: var string) = - dst = initTable[string, T]() - verifyJsonKind(jsonNode, {JObject}, jsonPath) - let originalJsonPathLen = jsonPath.len - for key in keys(jsonNode.fields): - jsonPath.add '.' - jsonPath.add key - initFromJson(mgetOrPut(dst, key, default(T)), jsonNode[key], jsonPath) - jsonPath.setLen originalJsonPathLen + proc initFromJson[T](dst: var Table[string,T];jsonNode: JsonNode; jsonPath: var string) = + dst = initTable[string, T]() + verifyJsonKind(jsonNode, {JObject}, jsonPath) + let originalJsonPathLen = jsonPath.len + for key in keys(jsonNode.fields): + jsonPath.add '.' + jsonPath.add key + initFromJson(mgetOrPut(dst, key, default(T)), jsonNode[key], jsonPath) + jsonPath.setLen originalJsonPathLen -proc initFromJson[T](dst: var OrderedTable[string,T]; jsonNode: JsonNode; jsonPath: var string) = - dst = initOrderedTable[string,T]() - verifyJsonKind(jsonNode, {JObject}, jsonPath) - let originalJsonPathLen = jsonPath.len - for key in keys(jsonNode.fields): - jsonPath.add '.' - jsonPath.add key - initFromJson(mgetOrPut(dst, key, default(T)), jsonNode[key], jsonPath) - jsonPath.setLen originalJsonPathLen + proc initFromJson[T](dst: var OrderedTable[string,T];jsonNode: JsonNode; jsonPath: var string) = + dst = initOrderedTable[string,T]() + verifyJsonKind(jsonNode, {JObject}, jsonPath) + let originalJsonPathLen = jsonPath.len + for key in keys(jsonNode.fields): + jsonPath.add '.' + jsonPath.add key + initFromJson(mgetOrPut(dst, key, default(T)), jsonNode[key], jsonPath) + jsonPath.setLen originalJsonPathLen -proc initFromJson[T](dst: var ref T; jsonNode: JsonNode; jsonPath: var string) = - verifyJsonKind(jsonNode, {JObject, JNull}, jsonPath) - if jsonNode.kind == JNull: - dst = nil - else: - dst = new(T) - initFromJson(dst[], jsonNode, jsonPath) - -proc initFromJson[T](dst: var Option[T]; jsonNode: JsonNode; jsonPath: var string) = - if jsonNode != nil and jsonNode.kind != JNull: - when T is ref: - dst = some(new(T)) + proc initFromJson[T](dst: var ref T; jsonNode: JsonNode; jsonPath: var string) = + verifyJsonKind(jsonNode, {JObject, JNull}, jsonPath) + if jsonNode.kind == JNull: + dst = nil else: + dst = new(T) + initFromJson(dst[], jsonNode, jsonPath) + + proc initFromJson[T](dst: var Option[T]; jsonNode: JsonNode; jsonPath: var string) = + if jsonNode != nil and jsonNode.kind != JNull: dst = some(default(T)) - initFromJson(dst.get, jsonNode, jsonPath) + initFromJson(dst.get, jsonNode, jsonPath) -macro assignDistinctImpl[T: distinct](dst: var T;jsonNode: JsonNode; jsonPath: var string) = - let typInst = getTypeInst(dst) - let typImpl = getTypeImpl(dst) - let baseTyp = typImpl[0] + macro assignDistinctImpl[T : distinct](dst: var T;jsonNode: JsonNode; jsonPath: var string) = + let typInst = getTypeInst(dst) + let typImpl = getTypeImpl(dst) + let baseTyp = typImpl[0] - result = quote do: - when nimvm: - # workaround #12282 - var tmp: `baseTyp` - initFromJson( tmp, `jsonNode`, `jsonPath`) - `dst` = `typInst`(tmp) - else: - initFromJson( `baseTyp`(`dst`), `jsonNode`, `jsonPath`) - -proc initFromJson[T: distinct](dst: var T; jsonNode: JsonNode; jsonPath: var string) = - assignDistinctImpl(dst, jsonNode, jsonPath) - -proc detectIncompatibleType(typeExpr, lineinfoNode: NimNode) = - if typeExpr.kind == nnkTupleConstr: - error("Use a named tuple instead of: " & typeExpr.repr, lineinfoNode) - -proc foldObjectBody(dst, typeNode, tmpSym, jsonNode, jsonPath, originalJsonPathLen: NimNode) = - case typeNode.kind - of nnkEmpty: - discard - of nnkRecList, nnkTupleTy: - for it in typeNode: - foldObjectBody(dst, it, tmpSym, jsonNode, jsonPath, originalJsonPathLen) - - of nnkIdentDefs: - typeNode.expectLen 3 - let fieldSym = typeNode[0] - let fieldNameLit = newLit(fieldSym.strVal) - let fieldPathLit = newLit("." & fieldSym.strVal) - let fieldType = typeNode[1] - - # Detecting incompatiple tuple types in `assignObjectImpl` only - # would be much cleaner, but the ast for tuple types does not - # contain usable type information. - detectIncompatibleType(fieldType, fieldSym) - - dst.add quote do: - jsonPath.add `fieldPathLit` + result = quote do: when nimvm: - when isRefSkipDistinct(`tmpSym`.`fieldSym`): - # workaround #12489 - var tmp: `fieldType` - initFromJson(tmp, getOrDefault(`jsonNode`,`fieldNameLit`), `jsonPath`) - `tmpSym`.`fieldSym` = tmp + # workaround #12282 + var tmp: `baseTyp` + initFromJson( tmp, `jsonNode`, `jsonPath`) + `dst` = `typInst`(tmp) + else: + initFromJson( `baseTyp`(`dst`), `jsonNode`, `jsonPath`) + + proc initFromJson[T : distinct](dst: var T; jsonNode: JsonNode; jsonPath: var string) = + assignDistinctImpl(dst, jsonNode, jsonPath) + + proc detectIncompatibleType(typeExpr, lineinfoNode: NimNode): void = + if typeExpr.kind == nnkTupleConstr: + error("Use a named tuple instead of: " & typeExpr.repr, lineinfoNode) + + proc foldObjectBody(dst, typeNode, tmpSym, jsonNode, jsonPath, originalJsonPathLen: NimNode): void {.compileTime.} = + case typeNode.kind + of nnkEmpty: + discard + of nnkRecList, nnkTupleTy: + for it in typeNode: + foldObjectBody(dst, it, tmpSym, jsonNode, jsonPath, originalJsonPathLen) + + of nnkIdentDefs: + typeNode.expectLen 3 + let fieldSym = typeNode[0] + let fieldNameLit = newLit(fieldSym.strVal) + let fieldPathLit = newLit("." & fieldSym.strVal) + let fieldType = typeNode[1] + + # Detecting incompatiple tuple types in `assignObjectImpl` only + # would be much cleaner, but the ast for tuple types does not + # contain usable type information. + detectIncompatibleType(fieldType, fieldSym) + + dst.add quote do: + jsonPath.add `fieldPathLit` + when nimvm: + when isRefSkipDistinct(`tmpSym`.`fieldSym`): + # workaround #12489 + var tmp: `fieldType` + initFromJson(tmp, getOrDefault(`jsonNode`,`fieldNameLit`), `jsonPath`) + `tmpSym`.`fieldSym` = tmp + else: + initFromJson(`tmpSym`.`fieldSym`, getOrDefault(`jsonNode`,`fieldNameLit`), `jsonPath`) else: initFromJson(`tmpSym`.`fieldSym`, getOrDefault(`jsonNode`,`fieldNameLit`), `jsonPath`) - else: - initFromJson(`tmpSym`.`fieldSym`, getOrDefault(`jsonNode`,`fieldNameLit`), `jsonPath`) - jsonPath.setLen `originalJsonPathLen` + jsonPath.setLen `originalJsonPathLen` - of nnkRecCase: - let kindSym = typeNode[0][0] - let kindNameLit = newLit(kindSym.strVal) - let kindPathLit = newLit("." & kindSym.strVal) - let kindType = typeNode[0][1] - let kindOffsetLit = newLit(uint(getOffset(kindSym))) - dst.add quote do: - var kindTmp: `kindType` - jsonPath.add `kindPathLit` - initFromJson(kindTmp, `jsonNode`[`kindNameLit`], `jsonPath`) - jsonPath.setLen `originalJsonPathLen` - when defined js: - `tmpSym`.`kindSym` = kindTmp - else: - when nimvm: + of nnkRecCase: + let kindSym = typeNode[0][0] + let kindNameLit = newLit(kindSym.strVal) + let kindPathLit = newLit("." & kindSym.strVal) + let kindType = typeNode[0][1] + let kindOffsetLit = newLit(uint(getOffset(kindSym))) + dst.add quote do: + var kindTmp: `kindType` + jsonPath.add `kindPathLit` + initFromJson(kindTmp, `jsonNode`[`kindNameLit`], `jsonPath`) + jsonPath.setLen `originalJsonPathLen` + when defined js: `tmpSym`.`kindSym` = kindTmp else: - # fuck it, assign kind field anyway - ((cast[ptr `kindType`](cast[uint](`tmpSym`.addr) + `kindOffsetLit`))[]) = kindTmp - dst.add nnkCaseStmt.newTree(nnkDotExpr.newTree(tmpSym, kindSym)) - for i in 1 ..< typeNode.len: - foldObjectBody(dst, typeNode[i], tmpSym, jsonNode, jsonPath, originalJsonPathLen) + when nimvm: + `tmpSym`.`kindSym` = kindTmp + else: + # fuck it, assign kind field anyway + ((cast[ptr `kindType`](cast[uint](`tmpSym`.addr) + `kindOffsetLit`))[]) = kindTmp + dst.add nnkCaseStmt.newTree(nnkDotExpr.newTree(tmpSym, kindSym)) + for i in 1 ..< typeNode.len: + foldObjectBody(dst, typeNode[i], tmpSym, jsonNode, jsonPath, originalJsonPathLen) - of nnkOfBranch, nnkElse: - let ofBranch = newNimNode(typeNode.kind) - for i in 0 ..< typeNode.len-1: - ofBranch.add copyNimTree(typeNode[i]) - let dstInner = newNimNode(nnkStmtListExpr) - foldObjectBody(dstInner, typeNode[^1], tmpSym, jsonNode, jsonPath, originalJsonPathLen) - # resOuter now contains the inner stmtList - ofBranch.add dstInner - dst[^1].expectKind nnkCaseStmt - dst[^1].add ofBranch + of nnkOfBranch, nnkElse: + let ofBranch = newNimNode(typeNode.kind) + for i in 0 ..< typeNode.len-1: + ofBranch.add copyNimTree(typeNode[i]) + let dstInner = newNimNode(nnkStmtListExpr) + foldObjectBody(dstInner, typeNode[^1], tmpSym, jsonNode, jsonPath, originalJsonPathLen) + # resOuter now contains the inner stmtList + ofBranch.add dstInner + dst[^1].expectKind nnkCaseStmt + dst[^1].add ofBranch - of nnkObjectTy: - typeNode[0].expectKind nnkEmpty - typeNode[1].expectKind {nnkEmpty, nnkOfInherit} - if typeNode[1].kind == nnkOfInherit: - let base = typeNode[1][0] - var impl = getTypeImpl(base) - while impl.kind in {nnkRefTy, nnkPtrTy}: - impl = getTypeImpl(impl[0]) - foldObjectBody(dst, impl, tmpSym, jsonNode, jsonPath, originalJsonPathLen) - let body = typeNode[2] - foldObjectBody(dst, body, tmpSym, jsonNode, jsonPath, originalJsonPathLen) + of nnkObjectTy: + typeNode[0].expectKind nnkEmpty + typeNode[1].expectKind {nnkEmpty, nnkOfInherit} + if typeNode[1].kind == nnkOfInherit: + let base = typeNode[1][0] + var impl = getTypeImpl(base) + while impl.kind in {nnkRefTy, nnkPtrTy}: + impl = getTypeImpl(impl[0]) + foldObjectBody(dst, impl, tmpSym, jsonNode, jsonPath, originalJsonPathLen) + let body = typeNode[2] + foldObjectBody(dst, body, tmpSym, jsonNode, jsonPath, originalJsonPathLen) - else: - error("unhandled kind: " & $typeNode.kind, typeNode) + else: + error("unhandled kind: " & $typeNode.kind, typeNode) -macro assignObjectImpl[T](dst: var T; jsonNode: JsonNode; jsonPath: var string) = - let typeSym = getTypeInst(dst) - let originalJsonPathLen = genSym(nskLet, "originalJsonPathLen") - result = newStmtList() - result.add quote do: - let `originalJsonPathLen` = len(`jsonPath`) - if typeSym.kind in {nnkTupleTy, nnkTupleConstr}: - # both, `dst` and `typeSym` don't have good lineinfo. But nothing - # else is available here. - detectIncompatibleType(typeSym, dst) - foldObjectBody(result, typeSym, dst, jsonNode, jsonPath, originalJsonPathLen) - else: - foldObjectBody(result, typeSym.getTypeImpl, dst, jsonNode, jsonPath, originalJsonPathLen) -proc initFromJson[T: object|tuple](dst: var T; jsonNode: JsonNode; jsonPath: var string) = - assignObjectImpl(dst, jsonNode, jsonPath) + macro assignObjectImpl[T](dst: var T; jsonNode: JsonNode; jsonPath: var string) = + let typeSym = getTypeInst(dst) + let originalJsonPathLen = genSym(nskLet, "originalJsonPathLen") + result = newStmtList() + result.add quote do: + let `originalJsonPathLen` = len(`jsonPath`) + if typeSym.kind in {nnkTupleTy, nnkTupleConstr}: + # both, `dst` and `typeSym` don't have good lineinfo. But nothing + # else is available here. + detectIncompatibleType(typeSym, dst) + foldObjectBody(result, typeSym, dst, jsonNode, jsonPath, originalJsonPathLen) + else: + foldObjectBody(result, typeSym.getTypeImpl, dst, jsonNode, jsonPath, originalJsonPathLen) -proc to*[T](node: JsonNode, t: typedesc[T]): T = - ## `Unmarshals`:idx: the specified node into the object type specified. - ## - ## Known limitations: - ## - ## * Heterogeneous arrays are not supported. - ## * Sets in object variants are not supported. - ## * Not nil annotations are not supported. - ## - runnableExamples: - let jsonNode = parseJson(""" - { - "person": { - "name": "Nimmer", - "age": 21 - }, - "list": [1, 2, 3, 4] - } - """) + proc initFromJson[T : object|tuple](dst: var T; jsonNode: JsonNode; jsonPath: var string) = + assignObjectImpl(dst, jsonNode, jsonPath) - type - Person = object - name: string - age: int + proc to*[T](node: JsonNode, t: typedesc[T]): T = + ## `Unmarshals`:idx: the specified node into the object type specified. + ## + ## Known limitations: + ## + ## * Heterogeneous arrays are not supported. + ## * Sets in object variants are not supported. + ## * Not nil annotations are not supported. + ## + ## Example: + ## + ## .. code-block:: Nim + ## let jsonNode = parseJson(""" + ## { + ## "person": { + ## "name": "Nimmer", + ## "age": 21 + ## }, + ## "list": [1, 2, 3, 4] + ## } + ## """) + ## + ## type + ## Person = object + ## name: string + ## age: int + ## + ## Data = object + ## person: Person + ## list: seq[int] + ## + ## var data = to(jsonNode, Data) + ## doAssert data.person.name == "Nimmer" + ## doAssert data.person.age == 21 + ## doAssert data.list == @[1, 2, 3, 4] - Data = object - person: Person - list: seq[int] - - var data = to(jsonNode, Data) - doAssert data.person.name == "Nimmer" - doAssert data.person.age == 21 - doAssert data.list == @[1, 2, 3, 4] - - var jsonPath = "" - result = default(T) - initFromJson(result, node, jsonPath) + var jsonPath = "" + initFromJson(result, node, jsonPath) when false: import os @@ -1390,3 +1254,235 @@ when false: # { "json": 5 } # To get that we shall use, obj["json"] + +when isMainModule: + # Note: Macro tests are in tests/stdlib/tjsonmacro.nim + + let testJson = parseJson"""{ "a": [1, 2, 3, 4], "b": "asd", "c": "\ud83c\udf83", "d": "\u00E6"}""" + # nil passthrough + doAssert(testJson{"doesnt_exist"}{"anything"}.isNil) + testJson{["e", "f"]} = %true + doAssert(testJson["e"]["f"].bval) + + # make sure UTF-16 decoding works. + doAssert(testJson["c"].str == "🎃") + doAssert(testJson["d"].str == "æ") + + # make sure no memory leek when parsing invalid string + let startMemory = getOccupiedMem() + for i in 0 .. 10000: + try: + discard parseJson"""{ invalid""" + except: + discard + # memory diff should less than 4M + doAssert(abs(getOccupiedMem() - startMemory) < 4 * 1024 * 1024) + + + # test `$` + let stringified = $testJson + let parsedAgain = parseJson(stringified) + doAssert(parsedAgain["b"].str == "asd") + + parsedAgain["abc"] = %5 + doAssert parsedAgain["abc"].num == 5 + + # Bounds checking + when compileOption("boundChecks"): + try: + let a = testJson["a"][9] + doAssert(false, "IndexError not thrown") + except IndexError: + discard + try: + let a = testJson["a"][-1] + doAssert(false, "IndexError not thrown") + except IndexError: + discard + try: + doAssert(testJson["a"][0].num == 1, "Index doesn't correspond to its value") + except: + doAssert(false, "IndexError thrown for valid index") + + doAssert(testJson{"b"}.getStr() == "asd", "Couldn't fetch a singly nested key with {}") + doAssert(isNil(testJson{"nonexistent"}), "Non-existent keys should return nil") + doAssert(isNil(testJson{"a", "b"}), "Indexing through a list should return nil") + doAssert(isNil(testJson{"a", "b"}), "Indexing through a list should return nil") + doAssert(testJson{"a"} == parseJson"[1, 2, 3, 4]", "Didn't return a non-JObject when there was one to be found") + doAssert(isNil(parseJson("[1, 2, 3]"){"foo"}), "Indexing directly into a list should return nil") + + # Generator: + var j = %* [{"name": "John", "age": 30}, {"name": "Susan", "age": 31}] + doAssert j == %[%{"name": %"John", "age": %30}, %{"name": %"Susan", "age": %31}] + + var j2 = %* + [ + { + "name": "John", + "age": 30 + }, + { + "name": "Susan", + "age": 31 + } + ] + doAssert j2 == %[%{"name": %"John", "age": %30}, %{"name": %"Susan", "age": %31}] + + var name = "John" + let herAge = 30 + const hisAge = 31 + + var j3 = %* + [ {"name": "John" + , "age": herAge + } + , {"name": "Susan" + , "age": hisAge + } + ] + doAssert j3 == %[%{"name": %"John", "age": %30}, %{"name": %"Susan", "age": %31}] + + var j4 = %*{"test": nil} + doAssert j4 == %{"test": newJNull()} + + let seqOfNodes = @[%1, %2] + let jSeqOfNodes = %seqOfNodes + doAssert(jSeqOfNodes[1].num == 2) + + type MyObj = object + a, b: int + s: string + f32: float32 + f64: float64 + next: ref MyObj + var m: MyObj + m.s = "hi" + m.a = 5 + let jMyObj = %m + doAssert(jMyObj["a"].num == 5) + doAssert(jMyObj["s"].str == "hi") + + # Test loading of file. + when not defined(js): + var parsed = parseFile("tests/testdata/jsontest.json") + + try: + discard parsed["key2"][12123] + doAssert(false) + except IndexError: doAssert(true) + + var parsed2 = parseFile("tests/testdata/jsontest2.json") + doAssert(parsed2{"repository", "description"}.str == + "IRC Library for Haskell", "Couldn't fetch via multiply nested key using {}") + + doAssert escapeJsonUnquoted("\10Foo🎃barÄ") == "\\nFoo🎃barÄ" + doAssert escapeJsonUnquoted("\0\7\20") == "\\u0000\\u0007\\u0014" # for #7887 + doAssert escapeJson("\10Foo🎃barÄ") == "\"\\nFoo🎃barÄ\"" + doAssert escapeJson("\0\7\20") == "\"\\u0000\\u0007\\u0014\"" # for #7887 + + # Test with extra data + when not defined(js): + try: + discard parseJson("123 456") + doAssert(false) + except JsonParsingError: + doAssert getCurrentExceptionMsg().contains(errorMessages[errEofExpected]) + + try: + discard parseFile("tests/testdata/jsonwithextradata.json") + doAssert(false) + except JsonParsingError: + doAssert getCurrentExceptionMsg().contains(errorMessages[errEofExpected]) + + # bug #6438 + doAssert($ %*[] == "[]") + doAssert($ %*{} == "{}") + + doAssert(not compiles(%{"error": "No messages"})) + + # bug #9111 + block: + type + Bar = string + Foo = object + a: int + b: Bar + + let + js = """{"a": 123, "b": "abc"}""".parseJson + foo = js.to Foo + + doAssert(foo.b == "abc") + + # Generate constructors for range[T] types + block: + type + Q1 = range[0'u8 .. 50'u8] + Q2 = range[0'u16 .. 50'u16] + Q3 = range[0'u32 .. 50'u32] + Q4 = range[0'i8 .. 50'i8] + Q5 = range[0'i16 .. 50'i16] + Q6 = range[0'i32 .. 50'i32] + Q7 = range[0'f32 .. 50'f32] + Q8 = range[0'f64 .. 50'f64] + Q9 = range[0 .. 50] + + X = object + m1: Q1 + m2: Q2 + m3: Q3 + m4: Q4 + m5: Q5 + m6: Q6 + m7: Q7 + m8: Q8 + m9: Q9 + + let obj = X( + m1: Q1(42), + m2: Q2(42), + m3: Q3(42), + m4: Q4(42), + m5: Q5(42), + m6: Q6(42), + m7: Q7(42), + m8: Q8(42), + m9: Q9(42) + ) + + doAssert(obj == to(%obj, type(obj))) + + when not defined(js): + const fragments = """[1,2,3] {"hi":3} 12 [] """ + var res = "" + for x in parseJsonFragments(newStringStream(fragments)): + res.add($x) + res.add " " + doAssert res == fragments + + + # test isRefSkipDistinct + type + MyRef = ref object + MyObject = object + MyDistinct = distinct MyRef + MyOtherDistinct = distinct MyRef + + var x0: ref int + var x1: MyRef + var x2: MyObject + var x3: MyDistinct + var x4: MyOtherDistinct + + doAssert isRefSkipDistinct(x0) + doAssert isRefSkipDistinct(x1) + doAssert not isRefSkipDistinct(x2) + doAssert isRefSkipDistinct(x3) + doAssert isRefSkipDistinct(x4) + + + doAssert isRefSkipDistinct(ref int) + doAssert isRefSkipDistinct(MyRef) + doAssert not isRefSkipDistinct(MyObject) + doAssert isRefSkipDistinct(MyDistinct) + doAssert isRefSkipDistinct(MyOtherDistinct) diff --git a/lib/pure/lenientops.nim b/lib/pure/lenientops.nim index a8fc78e39..cdea780a2 100644 --- a/lib/pure/lenientops.nim +++ b/lib/pure/lenientops.nim @@ -8,49 +8,51 @@ # ## This module offers implementations of common binary operations -## like `+`, `-`, `*`, `/` and comparison operations, +## like ``+``, ``-``, ``*``, ``/`` and comparison operations, ## which work for mixed float/int operands. ## All operations convert the integer operand into the ## type of the float operand. For numerical expressions, the return ## type is always the type of the float involved in the expression, ## i.e., there is no auto conversion from float32 to float64. ## -## **Note:** In general, auto-converting from int to float loses +## Note: In general, auto-converting from int to float loses ## information, which is why these operators live in a separate ## module. Use with care. ## ## Regarding binary comparison, this module only provides unequal operators. -## The equality operator `==` is omitted, because depending on the use case +## The equality operator ``==`` is omitted, because depending on the use case ## either casting to float or rounding to int might be preferred, and users ## should make an explicit choice. -func `+`*[I: SomeInteger, F: SomeFloat](i: I, f: F): F {.inline.} = +import typetraits + +proc `+`*[I: SomeInteger, F: SomeFloat](i: I, f: F): F {.noSideEffect, inline.} = F(i) + f -func `+`*[I: SomeInteger, F: SomeFloat](f: F, i: I): F {.inline.} = +proc `+`*[I: SomeInteger, F: SomeFloat](f: F, i: I): F {.noSideEffect, inline.} = f + F(i) -func `-`*[I: SomeInteger, F: SomeFloat](i: I, f: F): F {.inline.} = +proc `-`*[I: SomeInteger, F: SomeFloat](i: I, f: F): F {.noSideEffect, inline.} = F(i) - f -func `-`*[I: SomeInteger, F: SomeFloat](f: F, i: I): F {.inline.} = +proc `-`*[I: SomeInteger, F: SomeFloat](f: F, i: I): F {.noSideEffect, inline.} = f - F(i) -func `*`*[I: SomeInteger, F: SomeFloat](i: I, f: F): F {.inline.} = +proc `*`*[I: SomeInteger, F: SomeFloat](i: I, f: F): F {.noSideEffect, inline.} = F(i) * f -func `*`*[I: SomeInteger, F: SomeFloat](f: F, i: I): F {.inline.} = +proc `*`*[I: SomeInteger, F: SomeFloat](f: F, i: I): F {.noSideEffect, inline.} = f * F(i) -func `/`*[I: SomeInteger, F: SomeFloat](i: I, f: F): F {.inline.} = +proc `/`*[I: SomeInteger, F: SomeFloat](i: I, f: F): F {.noSideEffect, inline.} = F(i) / f -func `/`*[I: SomeInteger, F: SomeFloat](f: F, i: I): F {.inline.} = +proc `/`*[I: SomeInteger, F: SomeFloat](f: F, i: I): F {.noSideEffect, inline.} = f / F(i) -func `<`*[I: SomeInteger, F: SomeFloat](i: I, f: F): bool {.inline.} = +proc `<`*[I: SomeInteger, F: SomeFloat](i: I, f: F): bool {.noSideEffect, inline.} = F(i) < f -func `<`*[I: SomeInteger, F: SomeFloat](f: F, i: I): bool {.inline.} = +proc `<`*[I: SomeInteger, F: SomeFloat](f: F, i: I): bool {.noSideEffect, inline.} = f < F(i) -func `<=`*[I: SomeInteger, F: SomeFloat](i: I, f: F): bool {.inline.} = +proc `<=`*[I: SomeInteger, F: SomeFloat](i: I, f: F): bool {.noSideEffect, inline.} = F(i) <= f -func `<=`*[I: SomeInteger, F: SomeFloat](f: F, i: I): bool {.inline.} = +proc `<=`*[I: SomeInteger, F: SomeFloat](f: F, i: I): bool {.noSideEffect, inline.} = f <= F(i) # Note that we must not defined `>=` and `>`, because system.nim already has a diff --git a/lib/pure/lexbase.nim b/lib/pure/lexbase.nim index 336a57ec1..8bc96c82c 100644 --- a/lib/pure/lexbase.nim +++ b/lib/pure/lexbase.nim @@ -1,6 +1,6 @@ # # -# Nim's Runtime Library +# The Nim Compiler # (c) Copyright 2009 Andreas Rumpf # # See the file "copying.txt", included in this @@ -14,9 +14,6 @@ import strutils, streams -when defined(nimPreviewSlimSystem): - import std/assertions - const EndOfFile* = '\0' ## end of file marker NewLines* = {'\c', '\L'} @@ -36,7 +33,7 @@ type lineNumber*: int ## the current line number sentinel: int lineStart: int # index of last line start in buffer - offsetBase*: int # use `offsetBase + bufpos` to get the offset + offsetBase*: int # use ``offsetBase + bufpos`` to get the offset refillChars: set[char] proc close*(L: var BaseLexer) = @@ -55,8 +52,7 @@ proc fillBuffer(L: var BaseLexer) = toCopy = L.buf.len - (L.sentinel + 1) assert(toCopy >= 0) if toCopy > 0: - when defined(js) or defined(nimscript): - # nimscript has to be here to avoid compiling other branch (moveMem) + when defined(js): for i in 0 ..< toCopy: L.buf[i] = L.buf[L.sentinel + 1 + i] else: diff --git a/lib/pure/logging.nim b/lib/pure/logging.nim index 46b59b750..2637fdf9d 100644 --- a/lib/pure/logging.nim +++ b/lib/pure/logging.nim @@ -18,7 +18,7 @@ ## To get started, first create a logger: ## ## .. code-block:: -## import std/logging +## import logging ## ## var logger = newConsoleLogger() ## @@ -45,10 +45,11 @@ ## ``levelThreshold`` field and the global log filter. The latter can be changed ## with the `setLogFilter proc<#setLogFilter,Level>`_. ## -## .. warning:: -## For loggers that log to a console or to files, only error and fatal -## messages will cause their output buffers to be flushed immediately by default. -## set ``flushThreshold`` when creating the logger to change this. +## **Warning:** +## * For loggers that log to a console or to files, only error and fatal +## messages will cause their output buffers to be flushed immediately. +## Use the `flushFile proc `_ to flush the buffer +## manually if needed. ## ## Handlers ## -------- @@ -59,7 +60,7 @@ ## in the following example: ## ## .. code-block:: -## import std/logging +## import logging ## ## var consoleLog = newConsoleLogger() ## var fileLog = newFileLogger("errors.log", levelThreshold=lvlError) @@ -117,7 +118,7 @@ ## The following example illustrates how to use format strings: ## ## .. code-block:: -## import std/logging +## import logging ## ## var logger = newConsoleLogger(fmtStr="[$time] - $levelname: ") ## logger.log(lvlInfo, "this is a message") @@ -145,9 +146,6 @@ import strutils, times when not defined(js): import os -when defined(nimPreviewSlimSystem): - import std/syncio - type Level* = enum ## \ ## Enumeration of logging levels. @@ -199,15 +197,6 @@ const ## If a different format string is preferred, refer to the ## `documentation about format strings<#basic-usage-format-strings>`_ ## for more information, including a list of available variables. - defaultFlushThreshold = when NimMajor >= 2: - when defined(nimV1LogFlushBehavior): lvlError else: lvlAll - else: - when defined(nimFlushAllLogs): lvlAll else: lvlError - ## The threshold above which log messages to file-like loggers - ## are automatically flushed. - ## - ## By default, only error and fatal messages are logged, - ## but defining ``-d:nimFlushAllLogs`` will make all levels be flushed type Logger* = ref object of RootObj @@ -236,8 +225,6 @@ type ## * `FileLogger<#FileLogger>`_ ## * `RollingFileLogger<#RollingFileLogger>`_ useStderr*: bool ## If true, writes to stderr; otherwise, writes to stdout - flushThreshold*: Level ## Only messages that are at or above this - ## threshold will be flushed immediately when not defined(js): type @@ -253,15 +240,13 @@ when not defined(js): ## * `ConsoleLogger<#ConsoleLogger>`_ ## * `RollingFileLogger<#RollingFileLogger>`_ file*: File ## The wrapped file - flushThreshold*: Level ## Only messages that are at or above this - ## threshold will be flushed immediately RollingFileLogger* = ref object of FileLogger ## A logger that writes log messages to a file while performing log ## rotation. ## ## Create a new ``RollingFileLogger`` with the `newRollingFileLogger proc - ## <#newRollingFileLogger,FileMode,Positive,int>`_. + ## <#newRollingFileLogger,FileMode,int,int>`_. ## ## **Note:** This logger is not available for the JavaScript backend. ## @@ -302,7 +287,6 @@ proc substituteLog*(frmt: string, level: Level, runnableExamples: doAssert substituteLog(defaultFmtStr, lvlInfo, "a message") == "INFO a message" doAssert substituteLog("$levelid - ", lvlError, "an error") == "E - an error" - doAssert substituteLog("$levelid", lvlDebug, "error") == "Derror" var msgLen = 0 for arg in args: msgLen += arg.len @@ -316,7 +300,7 @@ proc substituteLog*(frmt: string, level: Level, inc(i) var v = "" let app = when defined(js): "" else: getAppFilename() - while i < frmt.len and frmt[i] in IdentChars: + while frmt[i] in IdentChars: v.add(toLowerAscii(frmt[i])) inc(i) case v @@ -360,8 +344,8 @@ method log*(logger: ConsoleLogger, level: Level, args: varargs[string, `$`]) = ## `setLogFilter proc<#setLogFilter,Level>`_. ## ## **Note:** Only error and fatal messages will cause the output buffer - ## to be flushed immediately by default. Set ``flushThreshold`` when creating - ## the logger to change this. + ## to be flushed immediately. Use the `flushFile proc + ## `_ to flush the buffer manually if needed. ## ## See also: ## * `log method<#log.e,FileLogger,Level,varargs[string,]>`_ @@ -379,25 +363,20 @@ method log*(logger: ConsoleLogger, level: Level, args: varargs[string, `$`]) = if level >= logging.level and level >= logger.levelThreshold: let ln = substituteLog(logger.fmtStr, level, args) when defined(js): - let cln = ln.cstring - case level - of lvlDebug: {.emit: "console.debug(`cln`);".} - of lvlInfo: {.emit: "console.info(`cln`);".} - of lvlWarn: {.emit: "console.warn(`cln`);".} - of lvlError: {.emit: "console.error(`cln`);".} - else: {.emit: "console.log(`cln`);".} + let cln: cstring = ln + {.emit: "console.log(`cln`);".} else: try: var handle = stdout if logger.useStderr: handle = stderr writeLine(handle, ln) - if level >= logger.flushThreshold: flushFile(handle) + if level in {lvlError, lvlFatal}: flushFile(handle) except IOError: discard proc newConsoleLogger*(levelThreshold = lvlAll, fmtStr = defaultFmtStr, - useStderr = false, flushThreshold = defaultFlushThreshold): ConsoleLogger = + useStderr = false): ConsoleLogger = ## Creates a new `ConsoleLogger<#ConsoleLogger>`_. ## ## By default, log messages are written to ``stdout``. If ``useStderr`` is @@ -410,7 +389,7 @@ proc newConsoleLogger*(levelThreshold = lvlAll, fmtStr = defaultFmtStr, ## * `newFileLogger proc<#newFileLogger,File>`_ that uses a file handle ## * `newFileLogger proc<#newFileLogger,FileMode,int>`_ ## that accepts a filename - ## * `newRollingFileLogger proc<#newRollingFileLogger,FileMode,Positive,int>`_ + ## * `newRollingFileLogger proc<#newRollingFileLogger,FileMode,int,int>`_ ## ## **Examples:** ## @@ -421,7 +400,6 @@ proc newConsoleLogger*(levelThreshold = lvlAll, fmtStr = defaultFmtStr, new result result.fmtStr = fmtStr result.levelThreshold = levelThreshold - result.flushThreshold = flushThreshold result.useStderr = useStderr when not defined(js): @@ -437,8 +415,8 @@ when not defined(js): ## ## **Notes:** ## * Only error and fatal messages will cause the output buffer - ## to be flushed immediately by default. Set ``flushThreshold`` when creating - ## the logger to change this. + ## to be flushed immediately. Use the `flushFile proc + ## `_ to flush the buffer manually if needed. ## * This method is not available for the JavaScript backend. ## ## See also: @@ -456,7 +434,7 @@ when not defined(js): ## fileLog.log(lvlError, "error code is: ", 404) if level >= logging.level and level >= logger.levelThreshold: writeLine(logger.file, substituteLog(logger.fmtStr, level, args)) - if level >= logger.flushThreshold: flushFile(logger.file) + if level in {lvlError, lvlFatal}: flushFile(logger.file) proc defaultFilename*(): string = ## Returns the filename that is used by default when naming log files. @@ -467,8 +445,7 @@ when not defined(js): proc newFileLogger*(file: File, levelThreshold = lvlAll, - fmtStr = defaultFmtStr, - flushThreshold = defaultFlushThreshold): FileLogger = + fmtStr = defaultFmtStr): FileLogger = ## Creates a new `FileLogger<#FileLogger>`_ that uses the given file handle. ## ## **Note:** This proc is not available for the JavaScript backend. @@ -477,7 +454,7 @@ when not defined(js): ## * `newConsoleLogger proc<#newConsoleLogger>`_ ## * `newFileLogger proc<#newFileLogger,FileMode,int>`_ ## that accepts a filename - ## * `newRollingFileLogger proc<#newRollingFileLogger,FileMode,Positive,int>`_ + ## * `newRollingFileLogger proc<#newRollingFileLogger,FileMode,int,int>`_ ## ## **Examples:** ## @@ -492,15 +469,13 @@ when not defined(js): new(result) result.file = file result.levelThreshold = levelThreshold - result.flushThreshold = flushThreshold result.fmtStr = fmtStr proc newFileLogger*(filename = defaultFilename(), mode: FileMode = fmAppend, levelThreshold = lvlAll, fmtStr = defaultFmtStr, - bufSize: int = -1, - flushThreshold = defaultFlushThreshold): FileLogger = + bufSize: int = -1): FileLogger = ## Creates a new `FileLogger<#FileLogger>`_ that logs to a file with the ## given filename. ## @@ -515,7 +490,7 @@ when not defined(js): ## See also: ## * `newConsoleLogger proc<#newConsoleLogger>`_ ## * `newFileLogger proc<#newFileLogger,File>`_ that uses a file handle - ## * `newRollingFileLogger proc<#newRollingFileLogger,FileMode,Positive,int>`_ + ## * `newRollingFileLogger proc<#newRollingFileLogger,FileMode,int,int>`_ ## ## **Examples:** ## @@ -524,11 +499,12 @@ when not defined(js): ## var formatLog = newFileLogger("formatted.log", fmtStr=verboseFmtStr) ## var errorLog = newFileLogger("errors.log", levelThreshold=lvlError) let file = open(filename, mode, bufSize = bufSize) - newFileLogger(file, levelThreshold, fmtStr, flushThreshold) + newFileLogger(file, levelThreshold, fmtStr) # ------ proc countLogLines(logger: RollingFileLogger): int = + result = 0 let fp = open(logger.baseName, fmRead) for line in fp.lines(): result.inc() @@ -555,9 +531,8 @@ when not defined(js): mode: FileMode = fmReadWrite, levelThreshold = lvlAll, fmtStr = defaultFmtStr, - maxLines: Positive = 1000, - bufSize: int = -1, - flushThreshold = defaultFlushThreshold): RollingFileLogger = + maxLines = 1000, + bufSize: int = -1): RollingFileLogger = ## Creates a new `RollingFileLogger<#RollingFileLogger>`_. ## ## Once the current log file being written to contains ``maxLines`` lines, @@ -593,7 +568,6 @@ when not defined(js): result.curLine = 0 result.baseName = filename result.baseMode = mode - result.flushThreshold = flushThreshold result.logFiles = countFiles(filename) @@ -620,8 +594,8 @@ when not defined(js): ## ## **Notes:** ## * Only error and fatal messages will cause the output buffer - ## to be flushed immediately by default. Set ``flushThreshold`` when creating - ## the logger to change this. + ## to be flushed immediately. Use the `flushFile proc + ## `_ to flush the buffer manually if needed. ## * This method is not available for the JavaScript backend. ## ## See also: @@ -647,7 +621,7 @@ when not defined(js): bufSize = logger.bufSize) writeLine(logger.file, substituteLog(logger.fmtStr, level, args)) - if level >= logger.flushThreshold: flushFile(logger.file) + if level in {lvlError, lvlFatal}: flushFile(logger.file) logger.curLine.inc # -------- @@ -815,9 +789,9 @@ template fatal*(args: varargs[string, `$`]) = proc addHandler*(handler: Logger) = ## Adds a logger to the list of registered handlers. ## - ## .. warning:: The list of handlers is a thread-local variable. If the given - ## handler will be used in multiple threads, this proc should be called in - ## each of those threads. + ## **Warning:** The list of handlers is a thread-local variable. If the given + ## handler will be used in multiple threads, this proc should be called in + ## each of those threads. ## ## See also: ## * `getHandlers proc<#getHandlers>`_ @@ -841,10 +815,10 @@ proc setLogFilter*(lvl: Level) = ## individual logger's ``levelThreshold``. By default, all messages are ## logged. ## - ## .. warning:: The global log filter is a thread-local variable. If logging - ## is being performed in multiple threads, this proc should be called in each - ## thread unless it is intended that different threads should log at different - ## logging levels. + ## **Warning:** The global log filter is a thread-local variable. If logging + ## is being performed in multiple threads, this proc should be called in each + ## thread unless it is intended that different threads should log at different + ## logging levels. ## ## See also: ## * `getLogFilter proc<#getLogFilter>`_ diff --git a/lib/pure/marshal.nim b/lib/pure/marshal.nim index 848d7e3fb..cf262b5f0 100644 --- a/lib/pure/marshal.nim +++ b/lib/pure/marshal.nim @@ -10,7 +10,7 @@ ## This module contains procs for `serialization`:idx: and `deserialization`:idx: ## of arbitrary Nim data structures. The serialization format uses `JSON`:idx:. ## -## **Restriction:** For objects, their type is **not** serialized. This means +## **Restriction**: For objects their type is **not** serialized. This means ## essentially that it does not work if the object has some other runtime ## type than its compiletime type. ## @@ -18,24 +18,31 @@ ## Basic usage ## =========== ## -runnableExamples: - type - A = object of RootObj - B = object of A - f: int - - let a: ref A = new(B) - assert $$a[] == "{}" # not "{f: 0}" - - # unmarshal - let c = to[B]("""{"f": 2}""") - assert typeof(c) is B - assert c.f == 2 - - # marshal - assert $$c == """{"f": 2}""" - -## **Note:** The `to` and `$$` operations are available at compile-time! +## .. code-block:: nim +## +## type +## A = object of RootObj +## B = object of A +## f: int +## +## var +## a: ref A +## b: ref B +## +## new(b) +## a = b +## echo($$a[]) # produces "{}", not "{f: 0}" +## +## # unmarshal +## let c = to[B]("""{"f": 2}""") +## assert typeof(c) is B +## assert c.f == 2 +## +## # marshal +## let s = $$c +## assert s == """{"f": 2}""" +## +## **Note**: The ``to`` and ``$$`` operations are available at compile-time! ## ## ## See also @@ -43,22 +50,9 @@ runnableExamples: ## * `streams module `_ ## * `json module `_ -const unsupportedPlatform = - when defined(js): "javascript" - elif defined(nimscript): "nimscript" - else: "" - -when unsupportedPlatform != "": - {.error: "marshal module is not supported in " & unsupportedPlatform & """. -Please use alternative packages for serialization. -It is possible to reimplement this module using generics and type traits. -Please contribute a new implementation.""".} import streams, typeinfo, json, intsets, tables, unicode -when defined(nimPreviewSlimSystem): - import std/[assertions, formatfloat] - proc ptrToInt(x: pointer): int {.inline.} = result = cast[int](x) # don't skip alignment @@ -166,10 +160,7 @@ proc loadAny(p: var JsonParser, a: Any, t: var Table[BiggestInt, pointer]) = of akSequence: case p.kind of jsonNull: - when defined(nimSeqsV2): - invokeNewSeq(a, 0) - else: - setPointer(a, nil) + setPointer(a, nil) next(p) of jsonArrayStart: next(p) @@ -236,10 +227,7 @@ proc loadAny(p: var JsonParser, a: Any, t: var Table[BiggestInt, pointer]) = of akString: case p.kind of jsonNull: - when defined(nimSeqsV2): - setString(a, "") - else: - setPointer(a, nil) + setPointer(a, nil) next(p) of jsonString: setString(a, p.str) @@ -281,8 +269,7 @@ proc loadAny(s: Stream, a: Any, t: var Table[BiggestInt, pointer]) = proc load*[T](s: Stream, data: var T) = ## Loads `data` from the stream `s`. Raises `IOError` in case of an error. runnableExamples: - import std/streams - + import marshal, streams var s = newStringStream("[1, 3, 5]") var a: array[3, int] load(s, a) @@ -291,11 +278,10 @@ proc load*[T](s: Stream, data: var T) = var tab = initTable[BiggestInt, pointer]() loadAny(s, toAny(data), tab) -proc store*[T](s: Stream, data: sink T) = +proc store*[T](s: Stream, data: T) = ## Stores `data` into the stream `s`. Raises `IOError` in case of an error. runnableExamples: - import std/streams - + import marshal, streams var s = newStringStream("") var a = [1, 3, 5] store(s, a) @@ -304,20 +290,13 @@ proc store*[T](s: Stream, data: sink T) = var stored = initIntSet() var d: T - when defined(gcArc) or defined(gcOrc): - d = data - else: - shallowCopy(d, data) + shallowCopy(d, data) storeAny(s, toAny(d), stored) -proc loadVM[T](typ: typedesc[T], x: T): string = - discard "the implementation is in the compiler/vmops" - -proc `$$`*[T](x: sink T): string = +proc `$$`*[T](x: T): string = ## Returns a string representation of `x` (serialization, marshalling). ## - ## **Note:** to serialize `x` to JSON use `%x` from the `json` module - ## or `jsonutils.toJson(x)`. + ## **Note:** to serialize `x` to JSON use `$(%x)` from the ``json`` module. runnableExamples: type Foo = object @@ -328,24 +307,15 @@ proc `$$`*[T](x: sink T): string = let y = $$x assert y == """{"id": 1, "bar": "baz"}""" - when nimvm: - result = loadVM(T, x) - else: - var stored = initIntSet() - var d: T - when defined(gcArc) or defined(gcOrc): - d = x - else: - shallowCopy(d, x) - var s = newStringStream() - storeAny(s, toAny(d), stored) - result = s.data - -proc toVM[T](typ: typedesc[T], data: string): T = - discard "the implementation is in the compiler/vmops" + var stored = initIntSet() + var d: T + shallowCopy(d, x) + var s = newStringStream() + storeAny(s, toAny(d), stored) + result = s.data proc to*[T](data: string): T = - ## Reads data and transforms it to a type `T` (deserialization, unmarshalling). + ## Reads data and transforms it to a type ``T`` (deserialization, unmarshalling). runnableExamples: type Foo = object @@ -359,8 +329,79 @@ proc to*[T](data: string): T = assert z.id == 1 assert z.bar == "baz" - when nimvm: - result = toVM(T, data) - else: - var tab = initTable[BiggestInt, pointer]() - loadAny(newStringStream(data), toAny(result), tab) + var tab = initTable[BiggestInt, pointer]() + loadAny(newStringStream(data), toAny(result), tab) + + +when not defined(testing) and isMainModule: + template testit(x: untyped) = echo($$to[type(x)]($$x)) + + var x: array[0..4, array[0..4, string]] = [ + ["test", "1", "2", "3", "4"], ["test", "1", "2", "3", "4"], + ["test", "1", "2", "3", "4"], ["test", "1", "2", "3", "4"], + ["test", "1", "2", "3", "4"]] + testit(x) + var test2: tuple[name: string, s: uint] = ("tuple test", 56u) + testit(test2) + + type + TE = enum + blah, blah2 + + TestObj = object + test, asd: int + case test2: TE + of blah: + help: string + else: + nil + + PNode = ref Node + Node = object + next, prev: PNode + data: string + + proc buildList(): PNode = + new(result) + new(result.next) + new(result.prev) + result.data = "middle" + result.next.data = "next" + result.prev.data = "prev" + result.next.next = result.prev + result.next.prev = result + result.prev.next = result + result.prev.prev = result.next + + var test3: TestObj + test3.test = 42 + test3 = TestObj(test2: blah) + testit(test3) + + var test4: ref tuple[a, b: string] + new(test4) + test4.a = "ref string test: A" + test4.b = "ref string test: B" + testit(test4) + + var test5 = @[(0, 1), (2, 3), (4, 5)] + testit(test5) + + var test6: set[char] = {'A'..'Z', '_'} + testit(test6) + + var test7 = buildList() + echo($$test7) + testit(test7) + + type + A {.inheritable.} = object + B = object of A + f: int + + var + a: ref A + b: ref B + new(b) + a = b + echo($$a[]) # produces "{}", not "{f: 0}" diff --git a/lib/pure/math.nim b/lib/pure/math.nim index bea655a0e..c8a433559 100644 --- a/lib/pure/math.nim +++ b/lib/pure/math.nim @@ -12,101 +12,80 @@ ## Basic math routines for Nim. ## ## Note that the trigonometric functions naturally operate on radians. -## The helper functions `degToRad <#degToRad,T>`_ and `radToDeg <#radToDeg,T>`_ +## The helper functions `degToRad<#degToRad,T>`_ and `radToDeg<#radToDeg,T>`_ ## provide conversion between radians and degrees. - -runnableExamples: - from std/fenv import epsilon - from std/random import rand - - proc generateGaussianNoise(mu: float = 0.0, sigma: float = 1.0): (float, float) = - # Generates values from a normal distribution. - # Translated from https://en.wikipedia.org/wiki/Box%E2%80%93Muller_transform#Implementation. - var u1: float - var u2: float - while true: - u1 = rand(1.0) - u2 = rand(1.0) - if u1 > epsilon(float): break - let mag = sigma * sqrt(-2 * ln(u1)) - let z0 = mag * cos(2 * PI * u2) + mu - let z1 = mag * sin(2 * PI * u2) + mu - (z0, z1) - - echo generateGaussianNoise() - +## +## .. code-block:: +## +## import math +## from sequtils import map +## +## let a = [0.0, PI/6, PI/4, PI/3, PI/2] +## +## echo a.map(sin) +## # @[0.0, 0.499…, 0.707…, 0.866…, 1.0] +## +## echo a.map(tan) +## # @[0.0, 0.577…, 0.999…, 1.732…, 1.633…e+16] +## +## echo cos(degToRad(180.0)) +## # -1.0 +## +## echo sqrt(-1.0) +## # nan (use `complex` module) +## ## This module is available for the `JavaScript target ## `_. ## -## See also -## ======== -## * `complex module `_ for complex numbers and their +## **See also:** +## * `complex module`_ for complex numbers and their ## mathematical operations -## * `rationals module `_ for rational numbers and their +## * `rationals module`_ for rational numbers and their ## mathematical operations -## * `fenv module `_ for handling of floating-point rounding +## * `fenv module`_ for handling of floating-point rounding ## and exceptions (overflow, zero-divide, etc.) -## * `random module `_ for a fast and tiny random number generator -## * `stats module `_ for statistical analysis -## * `strformat module `_ for formatting floats for printing -## * `system module `_ for some very basic and trivial math operators -## (`shr`, `shl`, `xor`, `clamp`, etc.) +## * `random module`_ for fast and tiny random number generator +## * `mersenne module`_ for Mersenne twister random number generator +## * `stats module`_ for statistical analysis +## * `strformat module`_ for formatting floats for print +## * `system module`_ Some very basic and trivial math operators +## are on system directly, to name a few ``shr``, ``shl``, ``xor``, ``clamp``, etc. -import std/private/since +include "system/inclrtl" {.push debugger: off.} # the user does not want to trace a part # of the standard library! -import bitops, fenv +import bitops -when defined(nimPreviewSlimSystem): - import std/assertions - - -when defined(c) or defined(cpp): - proc c_isnan(x: float): bool {.importc: "isnan", header: "".} - # a generic like `x: SomeFloat` might work too if this is implemented via a C macro. - - proc c_copysign(x, y: cfloat): cfloat {.importc: "copysignf", header: "".} - proc c_copysign(x, y: cdouble): cdouble {.importc: "copysign", header: "".} - - proc c_signbit(x: SomeFloat): cint {.importc: "signbit", header: "".} - - # don't export `c_frexp` in the future and remove `c_frexp2`. - func c_frexp2(x: cfloat, exponent: var cint): cfloat {. - importc: "frexpf", header: "".} - func c_frexp2(x: cdouble, exponent: var cint): cdouble {. - importc: "frexp", header: "".} - -func binom*(n, k: int): int = - ## Computes the [binomial coefficient](https://en.wikipedia.org/wiki/Binomial_coefficient). +proc binom*(n, k: int): int {.noSideEffect.} = + ## Computes the `binomial coefficient `_. runnableExamples: + doAssert binom(6, 2) == binom(6, 4) doAssert binom(6, 2) == 15 doAssert binom(-6, 2) == 1 doAssert binom(6, 0) == 1 - if k <= 0: return 1 - if 2 * k > n: return binom(n, n - k) + if 2*k > n: return binom(n, n-k) result = n for i in countup(2, k): result = (result * (n + 1 - i)) div i -func createFactTable[N: static[int]]: array[N, int] = +proc createFactTable[N: static[int]]: array[N, int] = result[0] = 1 for i in 1 ..< N: result[i] = result[i - 1] * i -func fac*(n: int): int = - ## Computes the [factorial](https://en.wikipedia.org/wiki/Factorial) of - ## a non-negative integer `n`. +proc fac*(n: int): int = + ## Computes the `factorial `_ of + ## a non-negative integer ``n``. ## - ## **See also:** - ## * `prod func <#prod,openArray[T]>`_ + ## See also: + ## * `prod proc <#prod,openArray[T]>`_ runnableExamples: - doAssert fac(0) == 1 + doAssert fac(3) == 6 doAssert fac(4) == 24 doAssert fac(10) == 3628800 - const factTable = when sizeof(int) == 2: createFactTable[5]() @@ -120,136 +99,58 @@ func fac*(n: int): int = {.push checks: off, line_dir: off, stack_trace: off.} -when defined(posix) and not defined(genode): +when defined(Posix) and not defined(genode): {.passl: "-lm".} const - PI* = 3.1415926535897932384626433 ## The circle constant PI (Ludolph's number). - TAU* = 2.0 * PI ## The circle constant TAU (= 2 * PI). - E* = 2.71828182845904523536028747 ## Euler's number. + PI* = 3.1415926535897932384626433 ## The circle constant PI (Ludolph's number) + TAU* = 2.0 * PI ## The circle constant TAU (= 2 * PI) + E* = 2.71828182845904523536028747 ## Euler's number MaxFloat64Precision* = 16 ## Maximum number of meaningful digits ## after the decimal point for Nim's - ## `float64` type. + ## ``float64`` type. MaxFloat32Precision* = 8 ## Maximum number of meaningful digits ## after the decimal point for Nim's - ## `float32` type. + ## ``float32`` type. MaxFloatPrecision* = MaxFloat64Precision ## Maximum number of ## meaningful digits ## after the decimal point - ## for Nim's `float` type. + ## for Nim's ``float`` type. MinFloatNormal* = 2.225073858507201e-308 ## Smallest normal number for Nim's - ## `float` type (= 2^-1022). - RadPerDeg = PI / 180.0 ## Number of radians per degree. + ## ``float`` type. (= 2^-1022). + RadPerDeg = PI / 180.0 ## Number of radians per degree type FloatClass* = enum ## Describes the class a floating point value belongs to. - ## This is the type that is returned by the - ## `classify func <#classify,float>`_. + ## This is the type that is returned by + ## `classify proc <#classify,float>`_. fcNormal, ## value is an ordinary nonzero floating point value fcSubnormal, ## value is a subnormal (a very small) floating point value fcZero, ## value is zero fcNegZero, ## value is the negative zero - fcNan, ## value is Not a Number (NaN) + fcNan, ## value is Not-A-Number (NAN) fcInf, ## value is positive infinity fcNegInf ## value is negative infinity -func isNaN*(x: SomeFloat): bool {.inline, since: (1,5,1).} = - ## Returns whether `x` is a `NaN`, more efficiently than via `classify(x) == fcNan`. - ## Works even with `--passc:-ffast-math`. - runnableExamples: - doAssert NaN.isNaN - doAssert not Inf.isNaN - doAssert not isNaN(3.1415926) - - template fn: untyped = result = x != x - when nimvm: fn() - else: - when defined(js): fn() - else: result = c_isnan(x) - -when defined(js): - import std/private/jsutils - - proc toBitsImpl(x: float): array[2, uint32] = - let buffer = newArrayBuffer(8) - let a = newFloat64Array(buffer) - let b = newUint32Array(buffer) - a[0] = x - {.emit: "`result` = `b`;".} - # result = cast[array[2, uint32]](b) - - proc jsSetSign(x: float, sgn: bool): float = - let buffer = newArrayBuffer(8) - let a = newFloat64Array(buffer) - let b = newUint32Array(buffer) - a[0] = x - asm """ - function updateBit(num, bitPos, bitVal) { - return (num & ~(1 << bitPos)) | (bitVal << bitPos); - } - `b`[1] = updateBit(`b`[1], 31, `sgn`); - `result` = `a`[0] - """ - -proc signbit*(x: SomeFloat): bool {.inline, since: (1, 5, 1).} = - ## Returns true if `x` is negative, false otherwise. - runnableExamples: - doAssert not signbit(0.0) - doAssert signbit(-0.0) - doAssert signbit(-0.1) - doAssert not signbit(0.1) - - when defined(js): - let uintBuffer = toBitsImpl(x) - result = (uintBuffer[1] shr 31) != 0 - else: - result = c_signbit(x) != 0 - -func copySign*[T: SomeFloat](x, y: T): T {.inline, since: (1, 5, 1).} = - ## Returns a value with the magnitude of `x` and the sign of `y`; - ## this works even if x or y are NaN, infinity or zero, all of which can carry a sign. - runnableExamples: - doAssert copySign(10.0, 1.0) == 10.0 - doAssert copySign(10.0, -1.0) == -10.0 - doAssert copySign(-Inf, -0.0) == -Inf - doAssert copySign(NaN, 1.0).isNaN - doAssert copySign(1.0, copySign(NaN, -1.0)) == -1.0 - - # TODO: use signbit for examples - when defined(js): - let uintBuffer = toBitsImpl(y) - let sgn = (uintBuffer[1] shr 31) != 0 - result = jsSetSign(x, sgn) - else: - when nimvm: # not exact but we have a vmops for recent enough nim - if y > 0.0 or (y == 0.0 and 1.0 / y > 0.0): - result = abs(x) - elif y <= 0.0: - result = -abs(x) - else: # must be NaN - result = abs(x) - else: result = c_copysign(x, y) - -func classify*(x: float): FloatClass = +proc classify*(x: float): FloatClass = ## Classifies a floating point value. ## - ## Returns `x`'s class as specified by the `FloatClass enum<#FloatClass>`_. - ## Doesn't work with `--passc:-ffast-math`. + ## Returns ``x``'s class as specified by `FloatClass enum<#FloatClass>`_. runnableExamples: doAssert classify(0.3) == fcNormal doAssert classify(0.0) == fcZero - doAssert classify(0.3 / 0.0) == fcInf - doAssert classify(-0.3 / 0.0) == fcNegInf + doAssert classify(0.3/0.0) == fcInf + doAssert classify(-0.3/0.0) == fcNegInf doAssert classify(5.0e-324) == fcSubnormal # JavaScript and most C compilers have no classify: if x == 0.0: - if 1.0 / x == Inf: + if 1.0/x == Inf: return fcZero else: return fcNegZero - if x * 0.5 == x: + if x*0.5 == x: if x > 0.0: return fcInf else: return fcNegInf if x != x: return fcNan @@ -257,63 +158,32 @@ func classify*(x: float): FloatClass = return fcSubnormal return fcNormal -func almostEqual*[T: SomeFloat](x, y: T; unitsInLastPlace: Natural = 4): bool {. - since: (1, 5), inline.} = - ## Checks if two float values are almost equal, using the - ## [machine epsilon](https://en.wikipedia.org/wiki/Machine_epsilon). - ## - ## `unitsInLastPlace` is the max number of - ## [units in the last place](https://en.wikipedia.org/wiki/Unit_in_the_last_place) - ## difference tolerated when comparing two numbers. The larger the value, the - ## more error is allowed. A `0` value means that two numbers must be exactly the - ## same to be considered equal. - ## - ## The machine epsilon has to be scaled to the magnitude of the values used - ## and multiplied by the desired precision in ULPs unless the difference is - ## subnormal. - ## - # taken from: https://en.cppreference.com/w/cpp/types/numeric_limits/epsilon - runnableExamples: - doAssert almostEqual(PI, 3.14159265358979) - doAssert almostEqual(Inf, Inf) - doAssert not almostEqual(NaN, NaN) - - if x == y: - # short circuit exact equality -- needed to catch two infinities of - # the same sign. And perhaps speeds things up a bit sometimes. - return true - let diff = abs(x - y) - result = diff <= epsilon(T) * abs(x + y) * T(unitsInLastPlace) or - diff < minimumPositiveValue(T) - -func isPowerOfTwo*(x: int): bool = - ## Returns `true`, if `x` is a power of two, `false` otherwise. +proc isPowerOfTwo*(x: int): bool {.noSideEffect.} = + ## Returns ``true``, if ``x`` is a power of two, ``false`` otherwise. ## ## Zero and negative numbers are not a power of two. ## - ## **See also:** - ## * `nextPowerOfTwo func <#nextPowerOfTwo,int>`_ + ## See also: + ## * `nextPowerOfTwo proc<#nextPowerOfTwo,int>`_ runnableExamples: - doAssert isPowerOfTwo(16) - doAssert not isPowerOfTwo(5) - doAssert not isPowerOfTwo(0) - doAssert not isPowerOfTwo(-16) - + doAssert isPowerOfTwo(16) == true + doAssert isPowerOfTwo(5) == false + doAssert isPowerOfTwo(0) == false + doAssert isPowerOfTwo(-16) == false return (x > 0) and ((x and (x - 1)) == 0) -func nextPowerOfTwo*(x: int): int = - ## Returns `x` rounded up to the nearest power of two. +proc nextPowerOfTwo*(x: int): int {.noSideEffect.} = + ## Returns ``x`` rounded up to the nearest power of two. ## ## Zero and negative numbers get rounded up to 1. ## - ## **See also:** - ## * `isPowerOfTwo func <#isPowerOfTwo,int>`_ + ## See also: + ## * `isPowerOfTwo proc<#isPowerOfTwo,int>`_ runnableExamples: doAssert nextPowerOfTwo(16) == 16 doAssert nextPowerOfTwo(5) == 8 doAssert nextPowerOfTwo(0) == 1 doAssert nextPowerOfTwo(-16) == 1 - result = x - 1 when defined(cpu64): result = result or (result shr 32) @@ -326,408 +196,476 @@ func nextPowerOfTwo*(x: int): int = result = result or (result shr 1) result += 1 + ord(x <= 0) -func sum*[T](x: openArray[T]): T = - ## Computes the sum of the elements in `x`. +proc countBits32*(n: int32): int {.noSideEffect, deprecated: + "Deprecated since v0.20.0; use 'bitops.countSetBits' instead".} = + runnableExamples: + doAssert countBits32(7) == 3 + doAssert countBits32(8) == 1 + doAssert countBits32(15) == 4 + doAssert countBits32(16) == 1 + doAssert countBits32(17) == 2 + + bitops.countSetBits(n) + +proc sum*[T](x: openArray[T]): T {.noSideEffect.} = + ## Computes the sum of the elements in ``x``. ## - ## If `x` is empty, 0 is returned. + ## If ``x`` is empty, 0 is returned. ## - ## **See also:** - ## * `prod func <#prod,openArray[T]>`_ - ## * `cumsum func <#cumsum,openArray[T]>`_ - ## * `cumsummed func <#cumsummed,openArray[T]>`_ + ## See also: + ## * `prod proc <#prod,openArray[T]>`_ + ## * `cumsum proc <#cumsum,openArray[T]>`_ + ## * `cumsummed proc <#cumsummed,openArray[T]>`_ runnableExamples: doAssert sum([1, 2, 3, 4]) == 10 - doAssert sum([-4, 3, 5]) == 4 - + doAssert sum([-1.5, 2.7, -0.1]) == 1.1 for i in items(x): result = result + i -func prod*[T](x: openArray[T]): T = - ## Computes the product of the elements in `x`. +proc prod*[T](x: openArray[T]): T {.noSideEffect.} = + ## Computes the product of the elements in ``x``. ## - ## If `x` is empty, 1 is returned. + ## If ``x`` is empty, 1 is returned. ## - ## **See also:** - ## * `sum func <#sum,openArray[T]>`_ - ## * `fac func <#fac,int>`_ + ## See also: + ## * `sum proc <#sum,openArray[T]>`_ + ## * `fac proc <#fac,int>`_ runnableExamples: doAssert prod([1, 2, 3, 4]) == 24 doAssert prod([-4, 3, 5]) == -60 - - result = T(1) + result = 1.T for i in items(x): result = result * i -func cumsummed*[T](x: openArray[T]): seq[T] = - ## Returns the cumulative (aka prefix) summation of `x`. +proc cumsummed*[T](x: openArray[T]): seq[T] = + ## Return cumulative (aka prefix) summation of ``x``. ## - ## If `x` is empty, `@[]` is returned. - ## - ## **See also:** - ## * `sum func <#sum,openArray[T]>`_ - ## * `cumsum func <#cumsum,openArray[T]>`_ for the in-place version + ## See also: + ## * `sum proc <#sum,openArray[T]>`_ + ## * `cumsum proc <#cumsum,openArray[T]>`_ for the in-place version runnableExamples: - doAssert cumsummed([1, 2, 3, 4]) == @[1, 3, 6, 10] - - let xLen = x.len - if xLen == 0: - return @[] - result.setLen(xLen) + let a = [1, 2, 3, 4] + doAssert cumsummed(a) == @[1, 3, 6, 10] + result.setLen(x.len) result[0] = x[0] - for i in 1 ..< xLen: result[i] = result[i - 1] + x[i] + for i in 1 ..< x.len: result[i] = result[i-1] + x[i] -func cumsum*[T](x: var openArray[T]) = - ## Transforms `x` in-place (must be declared as `var`) into its +proc cumsum*[T](x: var openArray[T]) = + ## Transforms ``x`` in-place (must be declared as `var`) into its ## cumulative (aka prefix) summation. ## - ## **See also:** - ## * `sum func <#sum,openArray[T]>`_ - ## * `cumsummed func <#cumsummed,openArray[T]>`_ for a version which - ## returns a cumsummed sequence + ## See also: + ## * `sum proc <#sum,openArray[T]>`_ + ## * `cumsummed proc <#cumsummed,openArray[T]>`_ for a version which + ## returns cumsummed sequence runnableExamples: var a = [1, 2, 3, 4] cumsum(a) doAssert a == @[1, 3, 6, 10] + for i in 1 ..< x.len: x[i] = x[i-1] + x[i] - for i in 1 ..< x.len: x[i] = x[i - 1] + x[i] - +{.push noSideEffect.} when not defined(js): # C - func sqrt*(x: float32): float32 {.importc: "sqrtf", header: "".} - func sqrt*(x: float64): float64 {.importc: "sqrt", header: "".} = - ## Computes the square root of `x`. + proc sqrt*(x: float32): float32 {.importc: "sqrtf", header: "".} + proc sqrt*(x: float64): float64 {.importc: "sqrt", header: "".} + ## Computes the square root of ``x``. ## - ## **See also:** - ## * `cbrt func <#cbrt,float64>`_ for the cube root - runnableExamples: - doAssert almostEqual(sqrt(4.0), 2.0) - doAssert almostEqual(sqrt(1.44), 1.2) - func cbrt*(x: float32): float32 {.importc: "cbrtf", header: "".} - func cbrt*(x: float64): float64 {.importc: "cbrt", header: "".} = - ## Computes the cube root of `x`. + ## See also: + ## * `cbrt proc <#cbrt,float64>`_ for cubic root ## - ## **See also:** - ## * `sqrt func <#sqrt,float64>`_ for the square root - runnableExamples: - doAssert almostEqual(cbrt(8.0), 2.0) - doAssert almostEqual(cbrt(2.197), 1.3) - doAssert almostEqual(cbrt(-27.0), -3.0) - func ln*(x: float32): float32 {.importc: "logf", header: "".} - func ln*(x: float64): float64 {.importc: "log", header: "".} = - ## Computes the [natural logarithm](https://en.wikipedia.org/wiki/Natural_logarithm) - ## of `x`. + ## .. code-block:: nim + ## echo sqrt(4.0) ## 2.0 + ## echo sqrt(1.44) ## 1.2 + ## echo sqrt(-4.0) ## nan + proc cbrt*(x: float32): float32 {.importc: "cbrtf", header: "".} + proc cbrt*(x: float64): float64 {.importc: "cbrt", header: "".} + ## Computes the cubic root of ``x``. ## - ## **See also:** - ## * `log func <#log,T,T>`_ - ## * `log10 func <#log10,float64>`_ - ## * `log2 func <#log2,float64>`_ - ## * `exp func <#exp,float64>`_ - runnableExamples: - doAssert almostEqual(ln(exp(4.0)), 4.0) - doAssert almostEqual(ln(1.0), 0.0) - doAssert almostEqual(ln(0.0), -Inf) - doAssert ln(-7.0).isNaN + ## See also: + ## * `sqrt proc <#sqrt,float64>`_ for square root + ## + ## .. code-block:: nim + ## echo cbrt(8.0) ## 2.0 + ## echo cbrt(2.197) ## 1.3 + ## echo cbrt(-27.0) ## -3.0 + proc ln*(x: float32): float32 {.importc: "logf", header: "".} + proc ln*(x: float64): float64 {.importc: "log", header: "".} + ## Computes the `natural logarithm `_ + ## of ``x``. + ## + ## See also: + ## * `log proc <#log,T,T>`_ + ## * `log10 proc <#log10,float64>`_ + ## * `log2 proc <#log2,float64>`_ + ## * `exp proc <#exp,float64>`_ + ## + ## .. code-block:: nim + ## echo ln(exp(4.0)) ## 4.0 + ## echo ln(1.0)) ## 0.0 + ## echo ln(0.0) ## -inf + ## echo ln(-7.0) ## nan else: # JS - func sqrt*(x: float32): float32 {.importc: "Math.sqrt", nodecl.} - func sqrt*(x: float64): float64 {.importc: "Math.sqrt", nodecl.} + proc sqrt*(x: float32): float32 {.importc: "Math.sqrt", nodecl.} + proc sqrt*(x: float64): float64 {.importc: "Math.sqrt", nodecl.} - func cbrt*(x: float32): float32 {.importc: "Math.cbrt", nodecl.} - func cbrt*(x: float64): float64 {.importc: "Math.cbrt", nodecl.} + proc cbrt*(x: float32): float32 {.importc: "Math.cbrt", nodecl.} + proc cbrt*(x: float64): float64 {.importc: "Math.cbrt", nodecl.} - func ln*(x: float32): float32 {.importc: "Math.log", nodecl.} - func ln*(x: float64): float64 {.importc: "Math.log", nodecl.} + proc ln*(x: float32): float32 {.importc: "Math.log", nodecl.} + proc ln*(x: float64): float64 {.importc: "Math.log", nodecl.} -func log*[T: SomeFloat](x, base: T): T = - ## Computes the logarithm of `x` to base `base`. +proc log*[T: SomeFloat](x, base: T): T = + ## Computes the logarithm of ``x`` to base ``base``. ## - ## **See also:** - ## * `ln func <#ln,float64>`_ - ## * `log10 func <#log10,float64>`_ - ## * `log2 func <#log2,float64>`_ - runnableExamples: - doAssert almostEqual(log(9.0, 3.0), 2.0) - doAssert almostEqual(log(0.0, 2.0), -Inf) - doAssert log(-7.0, 4.0).isNaN - doAssert log(8.0, -2.0).isNaN - + ## See also: + ## * `ln proc <#ln,float64>`_ + ## * `log10 proc <#log10,float64>`_ + ## * `log2 proc <#log2,float64>`_ + ## * `exp proc <#exp,float64>`_ + ## + ## .. code-block:: nim + ## echo log(9.0, 3.0) ## 2.0 + ## echo log(32.0, 2.0) ## 5.0 + ## echo log(0.0, 2.0) ## -inf + ## echo log(-7.0, 4.0) ## nan + ## echo log(8.0, -2.0) ## nan ln(x) / ln(base) when not defined(js): # C - func log10*(x: float32): float32 {.importc: "log10f", header: "".} - func log10*(x: float64): float64 {.importc: "log10", header: "".} = - ## Computes the common logarithm (base 10) of `x`. + proc log10*(x: float32): float32 {.importc: "log10f", header: "".} + proc log10*(x: float64): float64 {.importc: "log10", header: "".} + ## Computes the common logarithm (base 10) of ``x``. ## - ## **See also:** - ## * `ln func <#ln,float64>`_ - ## * `log func <#log,T,T>`_ - ## * `log2 func <#log2,float64>`_ - runnableExamples: - doAssert almostEqual(log10(100.0) , 2.0) - doAssert almostEqual(log10(0.0), -Inf) - doAssert log10(-100.0).isNaN - func exp*(x: float32): float32 {.importc: "expf", header: "".} - func exp*(x: float64): float64 {.importc: "exp", header: "".} = - ## Computes the exponential function of `x` (`e^x`). + ## See also: + ## * `ln proc <#ln,float64>`_ + ## * `log proc <#log,T,T>`_ + ## * `log2 proc <#log2,float64>`_ + ## * `exp proc <#exp,float64>`_ ## - ## **See also:** - ## * `ln func <#ln,float64>`_ - runnableExamples: - doAssert almostEqual(exp(1.0), E) - doAssert almostEqual(ln(exp(4.0)), 4.0) - doAssert almostEqual(exp(0.0), 1.0) - func sin*(x: float32): float32 {.importc: "sinf", header: "".} - func sin*(x: float64): float64 {.importc: "sin", header: "".} = - ## Computes the sine of `x`. + ## .. code-block:: nim + ## echo log10(100.0) ## 2.0 + ## echo log10(0.0) ## nan + ## echo log10(-100.0) ## -inf + proc exp*(x: float32): float32 {.importc: "expf", header: "".} + proc exp*(x: float64): float64 {.importc: "exp", header: "".} + ## Computes the exponential function of ``x`` (e^x). ## - ## **See also:** - ## * `arcsin func <#arcsin,float64>`_ - runnableExamples: - doAssert almostEqual(sin(PI / 6), 0.5) - doAssert almostEqual(sin(degToRad(90.0)), 1.0) - func cos*(x: float32): float32 {.importc: "cosf", header: "".} - func cos*(x: float64): float64 {.importc: "cos", header: "".} = - ## Computes the cosine of `x`. + ## See also: + ## * `ln proc <#ln,float64>`_ + ## * `log proc <#log,T,T>`_ + ## * `log10 proc <#log10,float64>`_ + ## * `log2 proc <#log2,float64>`_ ## - ## **See also:** - ## * `arccos func <#arccos,float64>`_ - runnableExamples: - doAssert almostEqual(cos(2 * PI), 1.0) - doAssert almostEqual(cos(degToRad(60.0)), 0.5) - func tan*(x: float32): float32 {.importc: "tanf", header: "".} - func tan*(x: float64): float64 {.importc: "tan", header: "".} = - ## Computes the tangent of `x`. + ## .. code-block:: nim + ## echo exp(1.0) ## 2.718281828459045 + ## echo ln(exp(4.0)) ## 4.0 + ## echo exp(0.0) ## 1.0 + ## echo exp(-1.0) ## 0.3678794411714423 + proc sin*(x: float32): float32 {.importc: "sinf", header: "".} + proc sin*(x: float64): float64 {.importc: "sin", header: "".} + ## Computes the sine of ``x``. ## - ## **See also:** - ## * `arctan func <#arctan,float64>`_ - runnableExamples: - doAssert almostEqual(tan(degToRad(45.0)), 1.0) - doAssert almostEqual(tan(PI / 4), 1.0) - func sinh*(x: float32): float32 {.importc: "sinhf", header: "".} - func sinh*(x: float64): float64 {.importc: "sinh", header: "".} = - ## Computes the [hyperbolic sine](https://en.wikipedia.org/wiki/Hyperbolic_function#Definitions) of `x`. + ## See also: + ## * `cos proc <#cos,float64>`_ + ## * `tan proc <#tan,float64>`_ + ## * `arcsin proc <#arcsin,float64>`_ + ## * `sinh proc <#sinh,float64>`_ ## - ## **See also:** - ## * `arcsinh func <#arcsinh,float64>`_ - runnableExamples: - doAssert almostEqual(sinh(0.0), 0.0) - doAssert almostEqual(sinh(1.0), 1.175201193643801) - func cosh*(x: float32): float32 {.importc: "coshf", header: "".} - func cosh*(x: float64): float64 {.importc: "cosh", header: "".} = - ## Computes the [hyperbolic cosine](https://en.wikipedia.org/wiki/Hyperbolic_function#Definitions) of `x`. + ## .. code-block:: nim + ## echo sin(PI / 6) ## 0.4999999999999999 + ## echo sin(degToRad(90.0)) ## 1.0 + proc cos*(x: float32): float32 {.importc: "cosf", header: "".} + proc cos*(x: float64): float64 {.importc: "cos", header: "".} + ## Computes the cosine of ``x``. ## - ## **See also:** - ## * `arccosh func <#arccosh,float64>`_ - runnableExamples: - doAssert almostEqual(cosh(0.0), 1.0) - doAssert almostEqual(cosh(1.0), 1.543080634815244) - func tanh*(x: float32): float32 {.importc: "tanhf", header: "".} - func tanh*(x: float64): float64 {.importc: "tanh", header: "".} = - ## Computes the [hyperbolic tangent](https://en.wikipedia.org/wiki/Hyperbolic_function#Definitions) of `x`. + ## See also: + ## * `sin proc <#sin,float64>`_ + ## * `tan proc <#tan,float64>`_ + ## * `arccos proc <#arccos,float64>`_ + ## * `cosh proc <#cosh,float64>`_ ## - ## **See also:** - ## * `arctanh func <#arctanh,float64>`_ - runnableExamples: - doAssert almostEqual(tanh(0.0), 0.0) - doAssert almostEqual(tanh(1.0), 0.7615941559557649) - func arcsin*(x: float32): float32 {.importc: "asinf", header: "".} - func arcsin*(x: float64): float64 {.importc: "asin", header: "".} = - ## Computes the arc sine of `x`. + ## .. code-block:: nim + ## echo cos(2 * PI) ## 1.0 + ## echo cos(degToRad(60.0)) ## 0.5000000000000001 + proc tan*(x: float32): float32 {.importc: "tanf", header: "".} + proc tan*(x: float64): float64 {.importc: "tan", header: "".} + ## Computes the tangent of ``x``. ## - ## **See also:** - ## * `sin func <#sin,float64>`_ - runnableExamples: - doAssert almostEqual(radToDeg(arcsin(0.0)), 0.0) - doAssert almostEqual(radToDeg(arcsin(1.0)), 90.0) - func arccos*(x: float32): float32 {.importc: "acosf", header: "".} - func arccos*(x: float64): float64 {.importc: "acos", header: "".} = - ## Computes the arc cosine of `x`. + ## See also: + ## * `sin proc <#sin,float64>`_ + ## * `cos proc <#cos,float64>`_ + ## * `arctan proc <#arctan,float64>`_ + ## * `tanh proc <#tanh,float64>`_ ## - ## **See also:** - ## * `cos func <#cos,float64>`_ - runnableExamples: - doAssert almostEqual(radToDeg(arccos(0.0)), 90.0) - doAssert almostEqual(radToDeg(arccos(1.0)), 0.0) - func arctan*(x: float32): float32 {.importc: "atanf", header: "".} - func arctan*(x: float64): float64 {.importc: "atan", header: "".} = - ## Calculate the arc tangent of `x`. + ## .. code-block:: nim + ## echo tan(degToRad(45.0)) ## 0.9999999999999999 + ## echo tan(PI / 4) ## 0.9999999999999999 + proc sinh*(x: float32): float32 {.importc: "sinhf", header: "".} + proc sinh*(x: float64): float64 {.importc: "sinh", header: "".} + ## Computes the `hyperbolic sine `_ of ``x``. ## - ## **See also:** - ## * `arctan2 func <#arctan2,float64,float64>`_ - ## * `tan func <#tan,float64>`_ - runnableExamples: - doAssert almostEqual(arctan(1.0), 0.7853981633974483) - doAssert almostEqual(radToDeg(arctan(1.0)), 45.0) - func arctan2*(y, x: float32): float32 {.importc: "atan2f", header: "".} - func arctan2*(y, x: float64): float64 {.importc: "atan2", header: "".} = - ## Calculate the arc tangent of `y/x`. + ## See also: + ## * `cosh proc <#cosh,float64>`_ + ## * `tanh proc <#tanh,float64>`_ + ## * `arcsinh proc <#arcsinh,float64>`_ + ## * `sin proc <#sin,float64>`_ + ## + ## .. code-block:: nim + ## echo sinh(0.0) ## 0.0 + ## echo sinh(1.0) ## 1.175201193643801 + ## echo sinh(degToRad(90.0)) ## 2.301298902307295 + proc cosh*(x: float32): float32 {.importc: "coshf", header: "".} + proc cosh*(x: float64): float64 {.importc: "cosh", header: "".} + ## Computes the `hyperbolic cosine `_ of ``x``. + ## + ## See also: + ## * `sinh proc <#sinh,float64>`_ + ## * `tanh proc <#tanh,float64>`_ + ## * `arccosh proc <#arccosh,float64>`_ + ## * `cos proc <#cos,float64>`_ + ## + ## .. code-block:: nim + ## echo cosh(0.0) ## 1.0 + ## echo cosh(1.0) ## 1.543080634815244 + ## echo cosh(degToRad(90.0)) ## 2.509178478658057 + proc tanh*(x: float32): float32 {.importc: "tanhf", header: "".} + proc tanh*(x: float64): float64 {.importc: "tanh", header: "".} + ## Computes the `hyperbolic tangent `_ of ``x``. + ## + ## See also: + ## * `sinh proc <#sinh,float64>`_ + ## * `cosh proc <#cosh,float64>`_ + ## * `arctanh proc <#arctanh,float64>`_ + ## * `tan proc <#tan,float64>`_ + ## + ## .. code-block:: nim + ## echo tanh(0.0) ## 0.0 + ## echo tanh(1.0) ## 0.7615941559557649 + ## echo tanh(degToRad(90.0)) ## 0.9171523356672744 + + proc arccos*(x: float32): float32 {.importc: "acosf", header: "".} + proc arccos*(x: float64): float64 {.importc: "acos", header: "".} + ## Computes the arc cosine of ``x``. + ## + ## See also: + ## * `arcsin proc <#arcsin,float64>`_ + ## * `arctan proc <#arctan,float64>`_ + ## * `arctan2 proc <#arctan2,float64,float64>`_ + ## * `cos proc <#cos,float64>`_ + ## + ## .. code-block:: nim + ## echo radToDeg(arccos(0.0)) ## 90.0 + ## echo radToDeg(arccos(1.0)) ## 0.0 + proc arcsin*(x: float32): float32 {.importc: "asinf", header: "".} + proc arcsin*(x: float64): float64 {.importc: "asin", header: "".} + ## Computes the arc sine of ``x``. + ## + ## See also: + ## * `arccos proc <#arccos,float64>`_ + ## * `arctan proc <#arctan,float64>`_ + ## * `arctan2 proc <#arctan2,float64,float64>`_ + ## * `sin proc <#sin,float64>`_ + ## + ## .. code-block:: nim + ## echo radToDeg(arcsin(0.0)) ## 0.0 + ## echo radToDeg(arcsin(1.0)) ## 90.0 + proc arctan*(x: float32): float32 {.importc: "atanf", header: "".} + proc arctan*(x: float64): float64 {.importc: "atan", header: "".} + ## Calculate the arc tangent of ``x``. + ## + ## See also: + ## * `arcsin proc <#arcsin,float64>`_ + ## * `arccos proc <#arccos,float64>`_ + ## * `arctan2 proc <#arctan2,float64,float64>`_ + ## * `tan proc <#tan,float64>`_ + ## + ## .. code-block:: nim + ## echo arctan(1.0) ## 0.7853981633974483 + ## echo radToDeg(arctan(1.0)) ## 45.0 + proc arctan2*(y, x: float32): float32 {.importc: "atan2f", + header: "".} + proc arctan2*(y, x: float64): float64 {.importc: "atan2", header: "".} + ## Calculate the arc tangent of ``y`` / ``x``. ## ## It produces correct results even when the resulting angle is near - ## `PI/2` or `-PI/2` (`x` near 0). + ## pi/2 or -pi/2 (``x`` near 0). ## - ## **See also:** - ## * `arctan func <#arctan,float64>`_ - runnableExamples: - doAssert almostEqual(arctan2(1.0, 0.0), PI / 2.0) - doAssert almostEqual(radToDeg(arctan2(1.0, 0.0)), 90.0) - func arcsinh*(x: float32): float32 {.importc: "asinhf", header: "".} - func arcsinh*(x: float64): float64 {.importc: "asinh", header: "".} - ## Computes the inverse hyperbolic sine of `x`. + ## See also: + ## * `arcsin proc <#arcsin,float64>`_ + ## * `arccos proc <#arccos,float64>`_ + ## * `arctan proc <#arctan,float64>`_ + ## * `tan proc <#tan,float64>`_ ## - ## **See also:** - ## * `sinh func <#sinh,float64>`_ - func arccosh*(x: float32): float32 {.importc: "acoshf", header: "".} - func arccosh*(x: float64): float64 {.importc: "acosh", header: "".} - ## Computes the inverse hyperbolic cosine of `x`. - ## - ## **See also:** - ## * `cosh func <#cosh,float64>`_ - func arctanh*(x: float32): float32 {.importc: "atanhf", header: "".} - func arctanh*(x: float64): float64 {.importc: "atanh", header: "".} - ## Computes the inverse hyperbolic tangent of `x`. - ## - ## **See also:** - ## * `tanh func <#tanh,float64>`_ + ## .. code-block:: nim + ## echo arctan2(1.0, 0.0) ## 1.570796326794897 + ## echo radToDeg(arctan2(1.0, 0.0)) ## 90.0 + proc arcsinh*(x: float32): float32 {.importc: "asinhf", header: "".} + proc arcsinh*(x: float64): float64 {.importc: "asinh", header: "".} + ## Computes the inverse hyperbolic sine of ``x``. + proc arccosh*(x: float32): float32 {.importc: "acoshf", header: "".} + proc arccosh*(x: float64): float64 {.importc: "acosh", header: "".} + ## Computes the inverse hyperbolic cosine of ``x``. + proc arctanh*(x: float32): float32 {.importc: "atanhf", header: "".} + proc arctanh*(x: float64): float64 {.importc: "atanh", header: "".} + ## Computes the inverse hyperbolic tangent of ``x``. else: # JS - func log10*(x: float32): float32 {.importc: "Math.log10", nodecl.} - func log10*(x: float64): float64 {.importc: "Math.log10", nodecl.} - func log2*(x: float32): float32 {.importc: "Math.log2", nodecl.} - func log2*(x: float64): float64 {.importc: "Math.log2", nodecl.} - func exp*(x: float32): float32 {.importc: "Math.exp", nodecl.} - func exp*(x: float64): float64 {.importc: "Math.exp", nodecl.} + proc log10*(x: float32): float32 {.importc: "Math.log10", nodecl.} + proc log10*(x: float64): float64 {.importc: "Math.log10", nodecl.} + proc log2*(x: float32): float32 {.importc: "Math.log2", nodecl.} + proc log2*(x: float64): float64 {.importc: "Math.log2", nodecl.} + proc exp*(x: float32): float32 {.importc: "Math.exp", nodecl.} + proc exp*(x: float64): float64 {.importc: "Math.exp", nodecl.} - func sin*[T: float32|float64](x: T): T {.importc: "Math.sin", nodecl.} - func cos*[T: float32|float64](x: T): T {.importc: "Math.cos", nodecl.} - func tan*[T: float32|float64](x: T): T {.importc: "Math.tan", nodecl.} + proc sin*[T: float32|float64](x: T): T {.importc: "Math.sin", nodecl.} + proc cos*[T: float32|float64](x: T): T {.importc: "Math.cos", nodecl.} + proc tan*[T: float32|float64](x: T): T {.importc: "Math.tan", nodecl.} - func sinh*[T: float32|float64](x: T): T {.importc: "Math.sinh", nodecl.} - func cosh*[T: float32|float64](x: T): T {.importc: "Math.cosh", nodecl.} - func tanh*[T: float32|float64](x: T): T {.importc: "Math.tanh", nodecl.} + proc sinh*[T: float32|float64](x: T): T {.importc: "Math.sinh", nodecl.} + proc cosh*[T: float32|float64](x: T): T {.importc: "Math.cosh", nodecl.} + proc tanh*[T: float32|float64](x: T): T {.importc: "Math.tanh", nodecl.} - func arcsin*[T: float32|float64](x: T): T {.importc: "Math.asin", nodecl.} - # keep this as generic or update test in `tvmops.nim` to make sure we - # keep testing that generic importc procs work - func arccos*[T: float32|float64](x: T): T {.importc: "Math.acos", nodecl.} - func arctan*[T: float32|float64](x: T): T {.importc: "Math.atan", nodecl.} - func arctan2*[T: float32|float64](y, x: T): T {.importc: "Math.atan2", nodecl.} + proc arcsin*[T: float32|float64](x: T): T {.importc: "Math.asin", nodecl.} + proc arccos*[T: float32|float64](x: T): T {.importc: "Math.acos", nodecl.} + proc arctan*[T: float32|float64](x: T): T {.importc: "Math.atan", nodecl.} + proc arctan2*[T: float32|float64](y, x: T): T {.importc: "Math.atan2", nodecl.} - func arcsinh*[T: float32|float64](x: T): T {.importc: "Math.asinh", nodecl.} - func arccosh*[T: float32|float64](x: T): T {.importc: "Math.acosh", nodecl.} - func arctanh*[T: float32|float64](x: T): T {.importc: "Math.atanh", nodecl.} + proc arcsinh*[T: float32|float64](x: T): T {.importc: "Math.asinh", nodecl.} + proc arccosh*[T: float32|float64](x: T): T {.importc: "Math.acosh", nodecl.} + proc arctanh*[T: float32|float64](x: T): T {.importc: "Math.atanh", nodecl.} -func cot*[T: float32|float64](x: T): T = 1.0 / tan(x) - ## Computes the cotangent of `x` (`1/tan(x)`). -func sec*[T: float32|float64](x: T): T = 1.0 / cos(x) - ## Computes the secant of `x` (`1/cos(x)`). -func csc*[T: float32|float64](x: T): T = 1.0 / sin(x) - ## Computes the cosecant of `x` (`1/sin(x)`). +proc cot*[T: float32|float64](x: T): T = 1.0 / tan(x) + ## Computes the cotangent of ``x`` (1 / tan(x)). +proc sec*[T: float32|float64](x: T): T = 1.0 / cos(x) + ## Computes the secant of ``x`` (1 / cos(x)). +proc csc*[T: float32|float64](x: T): T = 1.0 / sin(x) + ## Computes the cosecant of ``x`` (1 / sin(x)). -func coth*[T: float32|float64](x: T): T = 1.0 / tanh(x) - ## Computes the hyperbolic cotangent of `x` (`1/tanh(x)`). -func sech*[T: float32|float64](x: T): T = 1.0 / cosh(x) - ## Computes the hyperbolic secant of `x` (`1/cosh(x)`). -func csch*[T: float32|float64](x: T): T = 1.0 / sinh(x) - ## Computes the hyperbolic cosecant of `x` (`1/sinh(x)`). +proc coth*[T: float32|float64](x: T): T = 1.0 / tanh(x) + ## Computes the hyperbolic cotangent of ``x`` (1 / tanh(x)). +proc sech*[T: float32|float64](x: T): T = 1.0 / cosh(x) + ## Computes the hyperbolic secant of ``x`` (1 / cosh(x)). +proc csch*[T: float32|float64](x: T): T = 1.0 / sinh(x) + ## Computes the hyperbolic cosecant of ``x`` (1 / sinh(x)). -func arccot*[T: float32|float64](x: T): T = arctan(1.0 / x) - ## Computes the inverse cotangent of `x` (`arctan(1/x)`). -func arcsec*[T: float32|float64](x: T): T = arccos(1.0 / x) - ## Computes the inverse secant of `x` (`arccos(1/x)`). -func arccsc*[T: float32|float64](x: T): T = arcsin(1.0 / x) - ## Computes the inverse cosecant of `x` (`arcsin(1/x)`). +proc arccot*[T: float32|float64](x: T): T = arctan(1.0 / x) + ## Computes the inverse cotangent of ``x``. +proc arcsec*[T: float32|float64](x: T): T = arccos(1.0 / x) + ## Computes the inverse secant of ``x``. +proc arccsc*[T: float32|float64](x: T): T = arcsin(1.0 / x) + ## Computes the inverse cosecant of ``x``. -func arccoth*[T: float32|float64](x: T): T = arctanh(1.0 / x) - ## Computes the inverse hyperbolic cotangent of `x` (`arctanh(1/x)`). -func arcsech*[T: float32|float64](x: T): T = arccosh(1.0 / x) - ## Computes the inverse hyperbolic secant of `x` (`arccosh(1/x)`). -func arccsch*[T: float32|float64](x: T): T = arcsinh(1.0 / x) - ## Computes the inverse hyperbolic cosecant of `x` (`arcsinh(1/x)`). +proc arccoth*[T: float32|float64](x: T): T = arctanh(1.0 / x) + ## Computes the inverse hyperbolic cotangent of ``x``. +proc arcsech*[T: float32|float64](x: T): T = arccosh(1.0 / x) + ## Computes the inverse hyperbolic secant of ``x``. +proc arccsch*[T: float32|float64](x: T): T = arcsinh(1.0 / x) + ## Computes the inverse hyperbolic cosecant of ``x``. const windowsCC89 = defined(windows) and defined(bcc) when not defined(js): # C - func hypot*(x, y: float32): float32 {.importc: "hypotf", header: "".} - func hypot*(x, y: float64): float64 {.importc: "hypot", header: "".} = - ## Computes the length of the hypotenuse of a right-angle triangle with - ## `x` as its base and `y` as its height. Equivalent to `sqrt(x*x + y*y)`. - runnableExamples: - doAssert almostEqual(hypot(3.0, 4.0), 5.0) - func pow*(x, y: float32): float32 {.importc: "powf", header: "".} - func pow*(x, y: float64): float64 {.importc: "pow", header: "".} = - ## Computes `x` raised to the power of `y`. + proc hypot*(x, y: float32): float32 {.importc: "hypotf", header: "".} + proc hypot*(x, y: float64): float64 {.importc: "hypot", header: "".} + ## Computes the hypotenuse of a right-angle triangle with ``x`` and + ## ``y`` as its base and height. Equivalent to ``sqrt(x*x + y*y)``. ## - ## To compute the power between integers (e.g. 2^6), - ## use the `^ func <#^,T,Natural>`_. + ## .. code-block:: nim + ## echo hypot(4.0, 3.0) ## 5.0 + proc pow*(x, y: float32): float32 {.importc: "powf", header: "".} + proc pow*(x, y: float64): float64 {.importc: "pow", header: "".} + ## Computes x to power raised of y. ## - ## **See also:** - ## * `^ func <#^,T,Natural>`_ - ## * `sqrt func <#sqrt,float64>`_ - ## * `cbrt func <#cbrt,float64>`_ - runnableExamples: - doAssert almostEqual(pow(100, 1.5), 1000.0) - doAssert almostEqual(pow(16.0, 0.5), 4.0) + ## To compute power between integers (e.g. 2^6), use `^ proc<#^,T,Natural>`_. + ## + ## See also: + ## * `^ proc<#^,T,Natural>`_ + ## * `sqrt proc <#sqrt,float64>`_ + ## * `cbrt proc <#cbrt,float64>`_ + ## + ## .. code-block:: nim + ## echo pow(100, 1.5) ## 1000.0 + ## echo pow(16.0, 0.5) ## 4.0 # TODO: add C89 version on windows when not windowsCC89: - func erf*(x: float32): float32 {.importc: "erff", header: "".} - func erf*(x: float64): float64 {.importc: "erf", header: "".} - ## Computes the [error function](https://en.wikipedia.org/wiki/Error_function) for `x`. + proc erf*(x: float32): float32 {.importc: "erff", header: "".} + proc erf*(x: float64): float64 {.importc: "erf", header: "".} + ## Computes the `error function `_ for ``x``. ## - ## **Note:** Not available for the JS backend. - func erfc*(x: float32): float32 {.importc: "erfcf", header: "".} - func erfc*(x: float64): float64 {.importc: "erfc", header: "".} - ## Computes the [complementary error function](https://en.wikipedia.org/wiki/Error_function#Complementary_error_function) for `x`. + ## Note: Not available for JS backend. + proc erfc*(x: float32): float32 {.importc: "erfcf", header: "".} + proc erfc*(x: float64): float64 {.importc: "erfc", header: "".} + ## Computes the `complementary error function `_ for ``x``. ## - ## **Note:** Not available for the JS backend. - func gamma*(x: float32): float32 {.importc: "tgammaf", header: "".} - func gamma*(x: float64): float64 {.importc: "tgamma", header: "".} = - ## Computes the [gamma function](https://en.wikipedia.org/wiki/Gamma_function) for `x`. + ## Note: Not available for JS backend. + proc gamma*(x: float32): float32 {.importc: "tgammaf", header: "".} + proc gamma*(x: float64): float64 {.importc: "tgamma", header: "".} + ## Computes the the `gamma function `_ for ``x``. ## - ## **Note:** Not available for the JS backend. + ## Note: Not available for JS backend. ## - ## **See also:** - ## * `lgamma func <#lgamma,float64>`_ for the natural logarithm of the gamma function - runnableExamples: - doAssert almostEqual(gamma(1.0), 1.0) - doAssert almostEqual(gamma(4.0), 6.0) - doAssert almostEqual(gamma(11.0), 3628800.0) - func lgamma*(x: float32): float32 {.importc: "lgammaf", header: "".} - func lgamma*(x: float64): float64 {.importc: "lgamma", header: "".} = - ## Computes the natural logarithm of the gamma function for `x`. + ## See also: + ## * `lgamma proc <#lgamma,float64>`_ for a natural log of gamma function ## - ## **Note:** Not available for the JS backend. + ## .. code-block:: Nim + ## echo gamma(1.0) # 1.0 + ## echo gamma(4.0) # 6.0 + ## echo gamma(11.0) # 3628800.0 + ## echo gamma(-1.0) # nan + proc tgamma*(x: float32): float32 + {.deprecated: "Deprecated since v0.19.0; use 'gamma' instead", + importc: "tgammaf", header: "".} + proc tgamma*(x: float64): float64 + {.deprecated: "Deprecated since v0.19.0; use 'gamma' instead", + importc: "tgamma", header: "".} + ## The gamma function + proc lgamma*(x: float32): float32 {.importc: "lgammaf", header: "".} + proc lgamma*(x: float64): float64 {.importc: "lgamma", header: "".} + ## Computes the natural log of the gamma function for ``x``. ## - ## **See also:** - ## * `gamma func <#gamma,float64>`_ for gamma function + ## Note: Not available for JS backend. + ## + ## See also: + ## * `gamma proc <#gamma,float64>`_ for gamma function + ## + ## .. code-block:: Nim + ## echo lgamma(1.0) # 1.0 + ## echo lgamma(4.0) # 1.791759469228055 + ## echo lgamma(11.0) # 15.10441257307552 + ## echo lgamma(-1.0) # inf - func floor*(x: float32): float32 {.importc: "floorf", header: "".} - func floor*(x: float64): float64 {.importc: "floor", header: "".} = - ## Computes the floor function (i.e. the largest integer not greater than `x`). + proc floor*(x: float32): float32 {.importc: "floorf", header: "".} + proc floor*(x: float64): float64 {.importc: "floor", header: "".} + ## Computes the floor function (i.e., the largest integer not greater than ``x``). ## - ## **See also:** - ## * `ceil func <#ceil,float64>`_ - ## * `round func <#round,float64>`_ - ## * `trunc func <#trunc,float64>`_ - runnableExamples: - doAssert floor(2.1) == 2.0 - doAssert floor(2.9) == 2.0 - doAssert floor(-3.5) == -4.0 + ## See also: + ## * `ceil proc <#ceil,float64>`_ + ## * `round proc <#round,float64>`_ + ## * `trunc proc <#trunc,float64>`_ + ## + ## .. code-block:: nim + ## echo floor(2.1) ## 2.0 + ## echo floor(2.9) ## 2.0 + ## echo floor(-3.5) ## -4.0 - func ceil*(x: float32): float32 {.importc: "ceilf", header: "".} - func ceil*(x: float64): float64 {.importc: "ceil", header: "".} = - ## Computes the ceiling function (i.e. the smallest integer not smaller - ## than `x`). + proc ceil*(x: float32): float32 {.importc: "ceilf", header: "".} + proc ceil*(x: float64): float64 {.importc: "ceil", header: "".} + ## Computes the ceiling function (i.e., the smallest integer not smaller + ## than ``x``). ## - ## **See also:** - ## * `floor func <#floor,float64>`_ - ## * `round func <#round,float64>`_ - ## * `trunc func <#trunc,float64>`_ - runnableExamples: - doAssert ceil(2.1) == 3.0 - doAssert ceil(2.9) == 3.0 - doAssert ceil(-2.1) == -2.0 + ## See also: + ## * `floor proc <#floor,float64>`_ + ## * `round proc <#round,float64>`_ + ## * `trunc proc <#trunc,float64>`_ + ## + ## .. code-block:: nim + ## echo ceil(2.1) ## 3.0 + ## echo ceil(2.9) ## 3.0 + ## echo ceil(-2.1) ## -2.0 when windowsCC89: # MSVC 2010 don't have trunc/truncf # this implementation was inspired by Go-lang Math.Trunc - func truncImpl(f: float64): float64 = + proc truncImpl(f: float64): float64 = const mask: uint64 = 0x7FF shift: uint64 = 64 - 12 @@ -742,12 +680,12 @@ when not defined(js): # C let e = (x shr shift) and mask - bias # Keep the top 12+e bits, the integer part; clear the rest. - if e < 64 - 12: - x = x and (not (1'u64 shl (64'u64 - 12'u64 - e) - 1'u64)) + if e < 64-12: + x = x and (not (1'u64 shl (64'u64-12'u64-e) - 1'u64)) result = cast[float64](x) - func truncImpl(f: float32): float32 = + proc truncImpl(f: float32): float32 = const mask: uint32 = 0xFF shift: uint32 = 32 - 9 @@ -762,330 +700,240 @@ when not defined(js): # C let e = (x shr shift) and mask - bias # Keep the top 9+e bits, the integer part; clear the rest. - if e < 32 - 9: - x = x and (not (1'u32 shl (32'u32 - 9'u32 - e) - 1'u32)) + if e < 32-9: + x = x and (not (1'u32 shl (32'u32-9'u32-e) - 1'u32)) result = cast[float32](x) - func trunc*(x: float64): float64 = + proc trunc*(x: float64): float64 = if classify(x) in {fcZero, fcNegZero, fcNan, fcInf, fcNegInf}: return x result = truncImpl(x) - func trunc*(x: float32): float32 = + proc trunc*(x: float32): float32 = if classify(x) in {fcZero, fcNegZero, fcNan, fcInf, fcNegInf}: return x result = truncImpl(x) - func round*[T: float32|float64](x: T): T = + proc round*[T: float32|float64](x: T): T = ## Windows compilers prior to MSVC 2012 do not implement 'round', ## 'roundl' or 'roundf'. result = if x < 0.0: ceil(x - T(0.5)) else: floor(x + T(0.5)) else: - func round*(x: float32): float32 {.importc: "roundf", header: "".} - func round*(x: float64): float64 {.importc: "round", header: "".} = + proc round*(x: float32): float32 {.importc: "roundf", header: "".} + proc round*(x: float64): float64 {.importc: "round", header: "".} ## Rounds a float to zero decimal places. ## - ## Used internally by the `round func <#round,T,int>`_ + ## Used internally by the `round proc <#round,T,int>`_ ## when the specified number of places is 0. ## - ## **See also:** - ## * `round func <#round,T,int>`_ for rounding to the specific + ## See also: + ## * `round proc <#round,T,int>`_ for rounding to the specific ## number of decimal places - ## * `floor func <#floor,float64>`_ - ## * `ceil func <#ceil,float64>`_ - ## * `trunc func <#trunc,float64>`_ - runnableExamples: - doAssert round(3.4) == 3.0 - doAssert round(3.5) == 4.0 - doAssert round(4.5) == 5.0 - - func trunc*(x: float32): float32 {.importc: "truncf", header: "".} - func trunc*(x: float64): float64 {.importc: "trunc", header: "".} = - ## Truncates `x` to the decimal point. + ## * `floor proc <#floor,float64>`_ + ## * `ceil proc <#ceil,float64>`_ + ## * `trunc proc <#trunc,float64>`_ ## - ## **See also:** - ## * `floor func <#floor,float64>`_ - ## * `ceil func <#ceil,float64>`_ - ## * `round func <#round,float64>`_ - runnableExamples: - doAssert trunc(PI) == 3.0 - doAssert trunc(-1.85) == -1.0 + ## .. code-block:: nim + ## echo round(3.4) ## 3.0 + ## echo round(3.5) ## 4.0 + ## echo round(4.5) ## 5.0 - func `mod`*(x, y: float32): float32 {.importc: "fmodf", header: "".} - func `mod`*(x, y: float64): float64 {.importc: "fmod", header: "".} = - ## Computes the modulo operation for float values (the remainder of `x` divided by `y`). + proc trunc*(x: float32): float32 {.importc: "truncf", header: "".} + proc trunc*(x: float64): float64 {.importc: "trunc", header: "".} + ## Truncates ``x`` to the decimal point. + ## + ## See also: + ## * `floor proc <#floor,float64>`_ + ## * `ceil proc <#ceil,float64>`_ + ## * `round proc <#round,float64>`_ + ## + ## .. code-block:: nim + ## echo trunc(PI) # 3.0 + ## echo trunc(-1.85) # -1.0 + + proc fmod*(x, y: float32): float32 {.deprecated: "Deprecated since v0.19.0; use 'mod' instead", + importc: "fmodf", header: "".} + proc fmod*(x, y: float64): float64 {.deprecated: "Deprecated since v0.19.0; use 'mod' instead", + importc: "fmod", header: "".} + ## Computes the remainder of ``x`` divided by ``y``. + + proc `mod`*(x, y: float32): float32 {.importc: "fmodf", header: "".} + proc `mod`*(x, y: float64): float64 {.importc: "fmod", header: "".} + ## Computes the modulo operation for float values (the remainder of ``x`` divided by ``y``). ## - ## **See also:** - ## * `floorMod func <#floorMod,T,T>`_ for Python-like (`%` operator) behavior - runnableExamples: - doAssert 6.5 mod 2.5 == 1.5 - doAssert -6.5 mod 2.5 == -1.5 - doAssert 6.5 mod -2.5 == 1.5 - doAssert -6.5 mod -2.5 == -1.5 + ## See also: + ## * `floorMod proc <#floorMod,T,T>`_ for Python-like (% operator) behavior + ## + ## .. code-block:: nim + ## ( 6.5 mod 2.5) == 1.5 + ## (-6.5 mod 2.5) == -1.5 + ## ( 6.5 mod -2.5) == 1.5 + ## (-6.5 mod -2.5) == -1.5 else: # JS - func hypot*(x, y: float32): float32 {.importc: "Math.hypot", varargs, nodecl.} - func hypot*(x, y: float64): float64 {.importc: "Math.hypot", varargs, nodecl.} - func pow*(x, y: float32): float32 {.importc: "Math.pow", nodecl.} - func pow*(x, y: float64): float64 {.importc: "Math.pow", nodecl.} - func floor*(x: float32): float32 {.importc: "Math.floor", nodecl.} - func floor*(x: float64): float64 {.importc: "Math.floor", nodecl.} - func ceil*(x: float32): float32 {.importc: "Math.ceil", nodecl.} - func ceil*(x: float64): float64 {.importc: "Math.ceil", nodecl.} + proc hypot*(x, y: float32): float32 {.importc: "Math.hypot", varargs, nodecl.} + proc hypot*(x, y: float64): float64 {.importc: "Math.hypot", varargs, nodecl.} + proc pow*(x, y: float32): float32 {.importc: "Math.pow", nodecl.} + proc pow*(x, y: float64): float64 {.importc: "Math.pow", nodecl.} + proc floor*(x: float32): float32 {.importc: "Math.floor", nodecl.} + proc floor*(x: float64): float64 {.importc: "Math.floor", nodecl.} + proc ceil*(x: float32): float32 {.importc: "Math.ceil", nodecl.} + proc ceil*(x: float64): float64 {.importc: "Math.ceil", nodecl.} + proc round*(x: float): float {.importc: "Math.round", nodecl.} + proc trunc*(x: float32): float32 {.importc: "Math.trunc", nodecl.} + proc trunc*(x: float64): float64 {.importc: "Math.trunc", nodecl.} - when (NimMajor, NimMinor) < (1, 5) or defined(nimLegacyJsRound): - func round*(x: float): float {.importc: "Math.round", nodecl.} - else: - func jsRound(x: float): float {.importc: "Math.round", nodecl.} - func round*[T: float64 | float32](x: T): T = - if x >= 0: result = jsRound(x) - else: - result = ceil(x) - if result - x >= T(0.5): - result -= T(1.0) - func trunc*(x: float32): float32 {.importc: "Math.trunc", nodecl.} - func trunc*(x: float64): float64 {.importc: "Math.trunc", nodecl.} + proc `mod`*(x, y: float32): float32 {.importcpp: "# % #".} + proc `mod`*(x, y: float64): float64 {.importcpp: "# % #".} + ## Computes the modulo operation for float values (the remainder of ``x`` divided by ``y``). + ## + ## .. code-block:: nim + ## ( 6.5 mod 2.5) == 1.5 + ## (-6.5 mod 2.5) == -1.5 + ## ( 6.5 mod -2.5) == 1.5 + ## (-6.5 mod -2.5) == -1.5 - func `mod`*(x, y: float32): float32 {.importjs: "(# % #)".} - func `mod`*(x, y: float64): float64 {.importjs: "(# % #)".} = - ## Computes the modulo operation for float values (the remainder of `x` divided by `y`). - runnableExamples: - doAssert 6.5 mod 2.5 == 1.5 - doAssert -6.5 mod 2.5 == -1.5 - doAssert 6.5 mod -2.5 == 1.5 - doAssert -6.5 mod -2.5 == -1.5 - -func round*[T: float32|float64](x: T, places: int): T = +proc round*[T: float32|float64](x: T, places: int): T {. + deprecated: "use strformat module instead".} = ## Decimal rounding on a binary floating point number. ## ## This function is NOT reliable. Floating point numbers cannot hold - ## non integer decimals precisely. If `places` is 0 (or omitted), + ## non integer decimals precisely. If ``places`` is 0 (or omitted), ## round to the nearest integral value following normal mathematical - ## rounding rules (e.g. `round(54.5) -> 55.0`). If `places` is + ## rounding rules (e.g. ``round(54.5) -> 55.0``). If ``places`` is ## greater than 0, round to the given number of decimal places, - ## e.g. `round(54.346, 2) -> 54.350000000000001421…`. If `places` is negative, round - ## to the left of the decimal place, e.g. `round(537.345, -1) -> 540.0`. - runnableExamples: - doAssert round(PI, 2) == 3.14 - doAssert round(PI, 4) == 3.1416 - + ## e.g. ``round(54.346, 2) -> 54.350000000000001421…``. If ``places`` is negative, round + ## to the left of the decimal place, e.g. ``round(537.345, -1) -> + ## 540.0`` + ## + ## .. code-block:: Nim + ## echo round(PI, 2) ## 3.14 + ## echo round(PI, 4) ## 3.1416 if places == 0: result = round(x) else: - var mult = pow(10.0, T(places)) - result = round(x * mult) / mult + var mult = pow(10.0, places.T) + result = round(x*mult)/mult -func floorDiv*[T: SomeInteger](x, y: T): T = - ## Floor division is conceptually defined as `floor(x / y)`. +proc floorDiv*[T: SomeInteger](x, y: T): T = + ## Floor division is conceptually defined as ``floor(x / y)``. ## ## This is different from the `system.div `_ - ## operator, which is defined as `trunc(x / y)`. - ## That is, `div` rounds towards `0` and `floorDiv` rounds down. + ## operator, which is defined as ``trunc(x / y)``. + ## That is, ``div`` rounds towards ``0`` and ``floorDiv`` rounds down. ## - ## **See also:** + ## See also: ## * `system.div proc `_ for integer division - ## * `floorMod func <#floorMod,T,T>`_ for Python-like (`%` operator) behavior - runnableExamples: - doAssert floorDiv( 13, 3) == 4 - doAssert floorDiv(-13, 3) == -5 - doAssert floorDiv( 13, -3) == -5 - doAssert floorDiv(-13, -3) == 4 - + ## * `floorMod proc <#floorMod,T,T>`_ for Python-like (% operator) behavior + ## + ## .. code-block:: nim + ## echo floorDiv( 13, 3) # 4 + ## echo floorDiv(-13, 3) # -5 + ## echo floorDiv( 13, -3) # -5 + ## echo floorDiv(-13, -3) # 4 result = x div y let r = x mod y if (r > 0 and y < 0) or (r < 0 and y > 0): result.dec 1 -func floorMod*[T: SomeNumber](x, y: T): T = - ## Floor modulo is conceptually defined as `x - (floorDiv(x, y) * y)`. +proc floorMod*[T: SomeNumber](x, y: T): T = + ## Floor modulus is conceptually defined as ``x - (floorDiv(x, y) * y)``. ## - ## This func behaves the same as the `%` operator in Python. + ## This proc behaves the same as the ``%`` operator in Python. ## - ## **See also:** - ## * `mod func <#mod,float64,float64>`_ - ## * `floorDiv func <#floorDiv,T,T>`_ - runnableExamples: - doAssert floorMod( 13, 3) == 1 - doAssert floorMod(-13, 3) == 2 - doAssert floorMod( 13, -3) == -2 - doAssert floorMod(-13, -3) == -1 - + ## See also: + ## * `mod proc <#mod,float64,float64>`_ + ## * `floorDiv proc <#floorDiv,T,T>`_ + ## + ## .. code-block:: nim + ## echo floorMod( 13, 3) # 1 + ## echo floorMod(-13, 3) # 2 + ## echo floorMod( 13, -3) # -2 + ## echo floorMod(-13, -3) # -1 result = x mod y if (result > 0 and y < 0) or (result < 0 and y > 0): result += y -func euclDiv*[T: SomeInteger](x, y: T): T {.since: (1, 5, 1).} = - ## Returns euclidean division of `x` by `y`. - runnableExamples: - doAssert euclDiv(13, 3) == 4 - doAssert euclDiv(-13, 3) == -5 - doAssert euclDiv(13, -3) == -4 - doAssert euclDiv(-13, -3) == 5 - - result = x div y - if x mod y < 0: - if y > 0: - dec result - else: - inc result - -func euclMod*[T: SomeNumber](x, y: T): T {.since: (1, 5, 1).} = - ## Returns euclidean modulo of `x` by `y`. - ## `euclMod(x, y)` is non-negative. - runnableExamples: - doAssert euclMod(13, 3) == 1 - doAssert euclMod(-13, 3) == 2 - doAssert euclMod(13, -3) == 1 - doAssert euclMod(-13, -3) == 2 - - result = x mod y - if result < 0: - result += abs(y) - -func ceilDiv*[T: SomeInteger](x, y: T): T {.inline, since: (1, 5, 1).} = - ## Ceil division is conceptually defined as `ceil(x / y)`. - ## - ## Assumes `x >= 0` and `y > 0` (and `x + y - 1 <= high(T)` if T is SomeUnsignedInt). - ## - ## This is different from the `system.div `_ - ## operator, which works like `trunc(x / y)`. - ## That is, `div` rounds towards `0` and `ceilDiv` rounds up. - ## - ## This function has the above input limitation, because that allows the - ## compiler to generate faster code and it is rarely used with - ## negative values or unsigned integers close to `high(T)/2`. - ## If you need a `ceilDiv` that works with any input, see: - ## https://github.com/demotomohiro/divmath. - ## - ## **See also:** - ## * `system.div proc `_ for integer division - ## * `floorDiv func <#floorDiv,T,T>`_ for integer division which rounds down. - runnableExamples: - assert ceilDiv(12, 3) == 4 - assert ceilDiv(13, 3) == 5 - - when sizeof(T) == 8: - type UT = uint64 - elif sizeof(T) == 4: - type UT = uint32 - elif sizeof(T) == 2: - type UT = uint16 - elif sizeof(T) == 1: - type UT = uint8 - else: - {.fatal: "Unsupported int type".} - - assert x >= 0 and y > 0 - when T is SomeUnsignedInt: - assert x + y - 1 >= x - - # If the divisor is const, the backend C/C++ compiler generates code without a `div` - # instruction, as it is slow on most CPUs. - # If the divisor is a power of 2 and a const unsigned integer type, the - # compiler generates faster code. - # If the divisor is const and a signed integer, generated code becomes slower - # than the code with unsigned integers, because division with signed integers - # need to works for both positive and negative value without `idiv`/`sdiv`. - # That is why this code convert parameters to unsigned. - # This post contains a comparison of the performance of signed/unsigned integers: - # https://github.com/nim-lang/Nim/pull/18596#issuecomment-894420984. - # If signed integer arguments were not converted to unsigned integers, - # `ceilDiv` wouldn't work for any positive signed integer value, because - # `x + (y - 1)` can overflow. - ((x.UT + (y.UT - 1.UT)) div y.UT).T - -func frexp*[T: float32|float64](x: T): tuple[frac: T, exp: int] {.inline.} = - ## Splits `x` into a normalized fraction `frac` and an integral power of 2 `exp`, - ## such that `abs(frac) in 0.5..<1` and `x == frac * 2 ^ exp`, except for special - ## cases shown below. - runnableExamples: - doAssert frexp(8.0) == (0.5, 4) - doAssert frexp(-8.0) == (-0.5, 4) - doAssert frexp(0.0) == (0.0, 0) - - # special cases: - when sizeof(int) == 8: - doAssert frexp(-0.0).frac.signbit # signbit preserved for +-0 - doAssert frexp(Inf).frac == Inf # +- Inf preserved - doAssert frexp(NaN).frac.isNaN - - when not defined(js): - var exp: cint - result.frac = c_frexp2(x, exp) - result.exp = exp - else: - if x == 0.0: - # reuse signbit implementation - let uintBuffer = toBitsImpl(x) - if (uintBuffer[1] shr 31) != 0: - # x is -0.0 - result = (-0.0, 0) - else: - result = (0.0, 0) - elif x < 0.0: - result = frexp(-x) - result.frac = -result.frac - else: - var ex = trunc(log2(x)) - result.exp = int(ex) - result.frac = x / pow(2.0, ex) - if abs(result.frac) >= 1: - inc(result.exp) - result.frac = result.frac / 2 - if result.exp == 1024 and result.frac == 0.0: - result.frac = 0.99999999999999988898 - -func frexp*[T: float32|float64](x: T, exponent: var int): T {.inline.} = - ## Overload of `frexp` that calls `(result, exponent) = frexp(x)`. - runnableExamples: - var x: int - doAssert frexp(5.0, x) == 0.625 - doAssert x == 3 - - (result, exponent) = frexp(x) - - when not defined(js): + proc c_frexp*(x: float32, exponent: var int32): float32 {. + importc: "frexp", header: "".} + proc c_frexp*(x: float64, exponent: var int32): float64 {. + importc: "frexp", header: "".} + proc frexp*[T, U](x: T, exponent: var U): T = + ## Split a number into mantissa and exponent. + ## + ## ``frexp`` calculates the mantissa m (a float greater than or equal to 0.5 + ## and less than 1) and the integer value n such that ``x`` (the original + ## float value) equals ``m * 2**n``. frexp stores n in `exponent` and returns + ## m. + ## + ## .. code-block:: nim + ## var x: int + ## echo frexp(5.0, x) # 0.625 + ## echo x # 3 + var exp: int32 + result = c_frexp(x, exp) + exponent = exp + when windowsCC89: # taken from Go-lang Math.Log2 const ln2 = 0.693147180559945309417232121458176568075500134360255254120680009 template log2Impl[T](x: T): T = - var exp: int + var exp: int32 var frac = frexp(x, exp) # Make sure exact powers of two give an exact answer. # Don't depend on Log(0.5)*(1/Ln2)+exp being exactly exp-1. if frac == 0.5: return T(exp - 1) - log10(frac) * (1 / ln2) + T(exp) + log10(frac)*(1/ln2) + T(exp) - func log2*(x: float32): float32 = log2Impl(x) - func log2*(x: float64): float64 = log2Impl(x) + proc log2*(x: float32): float32 = log2Impl(x) + proc log2*(x: float64): float64 = log2Impl(x) ## Log2 returns the binary logarithm of x. ## The special cases are the same as for Log. else: - func log2*(x: float32): float32 {.importc: "log2f", header: "".} - func log2*(x: float64): float64 {.importc: "log2", header: "".} = - ## Computes the binary logarithm (base 2) of `x`. + proc log2*(x: float32): float32 {.importc: "log2f", header: "".} + proc log2*(x: float64): float64 {.importc: "log2", header: "".} + ## Computes the binary logarithm (base 2) of ``x``. ## - ## **See also:** - ## * `log func <#log,T,T>`_ - ## * `log10 func <#log10,float64>`_ - ## * `ln func <#ln,float64>`_ - runnableExamples: - doAssert almostEqual(log2(8.0), 3.0) - doAssert almostEqual(log2(1.0), 0.0) - doAssert almostEqual(log2(0.0), -Inf) - doAssert log2(-2.0).isNaN + ## See also: + ## * `log proc <#log,T,T>`_ + ## * `log10 proc <#log10,float64>`_ + ## * `ln proc <#ln,float64>`_ + ## * `exp proc <#exp,float64>`_ + ## + ## .. code-block:: Nim + ## echo log2(8.0) # 3.0 + ## echo log2(1.0) # 0.0 + ## echo log2(0.0) # -inf + ## echo log2(-2.0) # nan -func splitDecimal*[T: float32|float64](x: T): tuple[intpart: T, floatpart: T] = - ## Breaks `x` into an integer and a fractional part. +else: + proc frexp*[T: float32|float64](x: T, exponent: var int): T = + if x == 0.0: + exponent = 0 + result = 0.0 + elif x < 0.0: + result = -frexp(-x, exponent) + else: + var ex = trunc(log2(x)) + exponent = int(ex) + result = x / pow(2.0, ex) + if abs(result) >= 1: + inc(exponent) + result = result / 2 + if exponent == 1024 and result == 0.0: + result = 0.99999999999999988898 + +proc splitDecimal*[T: float32|float64](x: T): tuple[intpart: T, floatpart: T] = + ## Breaks ``x`` into an integer and a fractional part. ## - ## Returns a tuple containing `intpart` and `floatpart`, representing - ## the integer part and the fractional part, respectively. + ## Returns a tuple containing ``intpart`` and ``floatpart`` representing + ## the integer part and the fractional part respectively. ## - ## Both parts have the same sign as `x`. Analogous to the `modf` + ## Both parts have the same sign as ``x``. Analogous to the ``modf`` ## function in C. - runnableExamples: - doAssert splitDecimal(5.25) == (intpart: 5.0, floatpart: 0.25) - doAssert splitDecimal(-2.73) == (intpart: -2.0, floatpart: -0.73) - + ## + ## .. code-block:: nim + ## echo splitDecimal(5.25) # (intpart: 5.0, floatpart: 0.25) + ## echo splitDecimal(-2.73) # (intpart: -2.0, floatpart: -0.73) var absolute: T absolute = abs(x) @@ -1095,59 +943,63 @@ func splitDecimal*[T: float32|float64](x: T): tuple[intpart: T, floatpart: T] = result.intpart = -result.intpart result.floatpart = -result.floatpart +{.pop.} -func degToRad*[T: float32|float64](d: T): T {.inline.} = - ## Converts from degrees to radians. +proc degToRad*[T: float32|float64](d: T): T {.inline.} = + ## Convert from degrees to radians. ## - ## **See also:** - ## * `radToDeg func <#radToDeg,T>`_ - runnableExamples: - doAssert almostEqual(degToRad(180.0), PI) - - result = d * T(RadPerDeg) - -func radToDeg*[T: float32|float64](d: T): T {.inline.} = - ## Converts from radians to degrees. + ## See also: + ## * `radToDeg proc <#radToDeg,T>`_ ## - ## **See also:** - ## * `degToRad func <#degToRad,T>`_ - runnableExamples: - doAssert almostEqual(radToDeg(2 * PI), 360.0) + ## .. code-block:: nim + ## echo degToRad(180.0) # 3.141592653589793 + result = T(d) * RadPerDeg - result = d / T(RadPerDeg) +proc radToDeg*[T: float32|float64](d: T): T {.inline.} = + ## Convert from radians to degrees. + ## + ## See also: + ## * `degToRad proc <#degToRad,T>`_ + ## + ## .. code-block:: nim + ## echo degToRad(2 * PI) # 360.0 + result = T(d) / RadPerDeg -func sgn*[T: SomeNumber](x: T): int {.inline.} = +proc sgn*[T: SomeNumber](x: T): int {.inline.} = ## Sign function. ## ## Returns: - ## * `-1` for negative numbers and `NegInf`, - ## * `1` for positive numbers and `Inf`, - ## * `0` for positive zero, negative zero and `NaN` - runnableExamples: - doAssert sgn(5) == 1 - doAssert sgn(0) == 0 - doAssert sgn(-4.1) == -1 - + ## * `-1` for negative numbers and ``NegInf``, + ## * `1` for positive numbers and ``Inf``, + ## * `0` for positive zero, negative zero and ``NaN`` + ## + ## .. code-block:: nim + ## echo sgn(5) # 1 + ## echo sgn(0) # 0 + ## echo sgn(-4.1) # -1 ord(T(0) < x) - ord(x < T(0)) {.pop.} {.pop.} -func `^`*[T: SomeNumber](x: T, y: Natural): T = - ## Computes `x` to the power of `y`. +proc `^`*[T](x: T, y: Natural): T = + ## Computes ``x`` to the power ``y``. ## - ## The exponent `y` must be non-negative, use - ## `pow <#pow,float64,float64>`_ for negative exponents. + ## Exponent ``y`` must be non-negative, use + ## `pow proc <#pow,float64,float64>`_ for negative exponents. ## - ## **See also:** - ## * `pow func <#pow,float64,float64>`_ for negative exponent or + ## See also: + ## * `pow proc <#pow,float64,float64>`_ for negative exponent or ## floats - ## * `sqrt func <#sqrt,float64>`_ - ## * `cbrt func <#cbrt,float64>`_ + ## * `sqrt proc <#sqrt,float64>`_ + ## * `cbrt proc <#cbrt,float64>`_ + ## runnableExamples: - doAssert -3 ^ 0 == 1 - doAssert -3 ^ 1 == -3 - doAssert -3 ^ 2 == 9 + assert -3.0^0 == 1.0 + assert -3^1 == -3 + assert -3^2 == 9 + assert -3.0^3 == -27.0 + assert -3.0^4 == 81.0 case y of 0: result = 1 @@ -1165,36 +1017,34 @@ func `^`*[T: SomeNumber](x: T, y: Natural): T = break x *= x -func gcd*[T](x, y: T): T = - ## Computes the greatest common (positive) divisor of `x` and `y`. +proc gcd*[T](x, y: T): T = + ## Computes the greatest common (positive) divisor of ``x`` and ``y``. ## ## Note that for floats, the result cannot always be interpreted as - ## "greatest decimal `z` such that `z*N == x and z*M == y` - ## where N and M are positive integers". + ## "greatest decimal `z` such that ``z*N == x and z*M == y`` + ## where N and M are positive integers." ## - ## **See also:** - ## * `gcd func <#gcd,SomeInteger,SomeInteger>`_ for an integer version - ## * `lcm func <#lcm,T,T>`_ + ## See also: + ## * `gcd proc <#gcd,SomeInteger,SomeInteger>`_ for integer version + ## * `lcm proc <#lcm,T,T>`_ runnableExamples: doAssert gcd(13.5, 9.0) == 4.5 - var (x, y) = (x, y) while y != 0: x = x mod y swap x, y abs x -func gcd*(x, y: SomeInteger): SomeInteger = - ## Computes the greatest common (positive) divisor of `x` and `y`, - ## using the binary GCD (aka Stein's) algorithm. +proc gcd*(x, y: SomeInteger): SomeInteger = + ## Computes the greatest common (positive) divisor of ``x`` and ``y``, + ## using binary GCD (aka Stein's) algorithm. ## - ## **See also:** - ## * `gcd func <#gcd,T,T>`_ for a float version - ## * `lcm func <#lcm,T,T>`_ + ## See also: + ## * `gcd proc <#gcd,T,T>`_ for floats version + ## * `lcm proc <#lcm,T,T>`_ runnableExamples: doAssert gcd(12, 8) == 4 doAssert gcd(17, 63) == 1 - when x is SomeSignedInt: var x = abs(x) else: @@ -1218,49 +1068,178 @@ func gcd*(x, y: SomeInteger): SomeInteger = x -= y y shl shift -func gcd*[T](x: openArray[T]): T {.since: (1, 1).} = - ## Computes the greatest common (positive) divisor of the elements of `x`. +proc gcd*[T](x: openArray[T]): T {.since: (1, 1).} = + ## Computes the greatest common (positive) divisor of the elements of ``x``. ## - ## **See also:** - ## * `gcd func <#gcd,T,T>`_ for a version with two arguments + ## See also: + ## * `gcd proc <#gcd,T,T>`_ for integer version runnableExamples: doAssert gcd(@[13.5, 9.0]) == 4.5 - result = x[0] - for i in 1 ..< x.len: + var i = 1 + while i < x.len: result = gcd(result, x[i]) + inc(i) -func lcm*[T](x, y: T): T = - ## Computes the least common multiple of `x` and `y`. +proc lcm*[T](x, y: T): T = + ## Computes the least common multiple of ``x`` and ``y``. ## - ## **See also:** - ## * `gcd func <#gcd,T,T>`_ + ## See also: + ## * `gcd proc <#gcd,T,T>`_ runnableExamples: doAssert lcm(24, 30) == 120 doAssert lcm(13, 39) == 39 - x div gcd(x, y) * y -func clamp*[T](val: T, bounds: Slice[T]): T {.since: (1, 5), inline.} = - ## Like `system.clamp`, but takes a slice, so you can easily clamp within a range. - runnableExamples: - assert clamp(10, 1 .. 5) == 5 - assert clamp(1, 1 .. 3) == 1 - type A = enum a0, a1, a2, a3, a4, a5 - assert a1.clamp(a2..a4) == a2 - assert clamp((3, 0), (1, 0) .. (2, 9)) == (2, 9) - doAssertRaises(AssertionDefect): discard clamp(1, 3..2) # invalid bounds - assert bounds.a <= bounds.b, $(bounds.a, bounds.b) - clamp(val, bounds.a, bounds.b) - -func lcm*[T](x: openArray[T]): T {.since: (1, 1).} = - ## Computes the least common multiple of the elements of `x`. +proc lcm*[T](x: openArray[T]): T {.since: (1, 1).} = + ## Computes the least common multiple of the elements of ``x``. ## - ## **See also:** - ## * `lcm func <#lcm,T,T>`_ for a version with two arguments + ## See also: + ## * `gcd proc <#gcd,T,T>`_ for integer version runnableExamples: doAssert lcm(@[24, 30]) == 120 - result = x[0] - for i in 1 ..< x.len: + var i = 1 + while i < x.len: result = lcm(result, x[i]) + inc(i) + +when isMainModule and not defined(js) and not windowsCC89: + # Check for no side effect annotation + proc mySqrt(num: float): float {.noSideEffect.} = + return sqrt(num) + + # check gamma function + assert(gamma(5.0) == 24.0) # 4! + assert($tgamma(5.0) == $24.0) # 4! + assert(lgamma(1.0) == 0.0) # ln(1.0) == 0.0 + assert(erf(6.0) > erf(5.0)) + assert(erfc(6.0) < erfc(5.0)) + +when isMainModule: + # Function for approximate comparison of floats + proc `==~`(x, y: float): bool = (abs(x-y) < 1e-9) + + block: # prod + doAssert prod([1, 2, 3, 4]) == 24 + doAssert prod([1.5, 3.4]) == 5.1 + let x: seq[float] = @[] + doAssert prod(x) == 1.0 + + block: # round() tests + # Round to 0 decimal places + doAssert round(54.652) ==~ 55.0 + doAssert round(54.352) ==~ 54.0 + doAssert round(-54.652) ==~ -55.0 + doAssert round(-54.352) ==~ -54.0 + doAssert round(0.0) ==~ 0.0 + # Round to positive decimal places + doAssert round(-547.652, 1) ==~ -547.7 + doAssert round(547.652, 1) ==~ 547.7 + doAssert round(-547.652, 2) ==~ -547.65 + doAssert round(547.652, 2) ==~ 547.65 + # Round to negative decimal places + doAssert round(547.652, -1) ==~ 550.0 + doAssert round(547.652, -2) ==~ 500.0 + doAssert round(547.652, -3) ==~ 1000.0 + doAssert round(547.652, -4) ==~ 0.0 + doAssert round(-547.652, -1) ==~ -550.0 + doAssert round(-547.652, -2) ==~ -500.0 + doAssert round(-547.652, -3) ==~ -1000.0 + doAssert round(-547.652, -4) ==~ 0.0 + + block: # splitDecimal() tests + doAssert splitDecimal(54.674).intpart ==~ 54.0 + doAssert splitDecimal(54.674).floatpart ==~ 0.674 + doAssert splitDecimal(-693.4356).intpart ==~ -693.0 + doAssert splitDecimal(-693.4356).floatpart ==~ -0.4356 + doAssert splitDecimal(0.0).intpart ==~ 0.0 + doAssert splitDecimal(0.0).floatpart ==~ 0.0 + + block: # trunc tests for vcc + doAssert(trunc(-1.1) == -1) + doAssert(trunc(1.1) == 1) + doAssert(trunc(-0.1) == -0) + doAssert(trunc(0.1) == 0) + + #special case + doAssert(classify(trunc(1e1000000)) == fcInf) + doAssert(classify(trunc(-1e1000000)) == fcNegInf) + doAssert(classify(trunc(0.0/0.0)) == fcNan) + doAssert(classify(trunc(0.0)) == fcZero) + + #trick the compiler to produce signed zero + let + f_neg_one = -1.0 + f_zero = 0.0 + f_nan = f_zero / f_zero + + doAssert(classify(trunc(f_neg_one*f_zero)) == fcNegZero) + + doAssert(trunc(-1.1'f32) == -1) + doAssert(trunc(1.1'f32) == 1) + doAssert(trunc(-0.1'f32) == -0) + doAssert(trunc(0.1'f32) == 0) + doAssert(classify(trunc(1e1000000'f32)) == fcInf) + doAssert(classify(trunc(-1e1000000'f32)) == fcNegInf) + doAssert(classify(trunc(f_nan.float32)) == fcNan) + doAssert(classify(trunc(0.0'f32)) == fcZero) + + block: # sgn() tests + assert sgn(1'i8) == 1 + assert sgn(1'i16) == 1 + assert sgn(1'i32) == 1 + assert sgn(1'i64) == 1 + assert sgn(1'u8) == 1 + assert sgn(1'u16) == 1 + assert sgn(1'u32) == 1 + assert sgn(1'u64) == 1 + assert sgn(-12342.8844'f32) == -1 + assert sgn(123.9834'f64) == 1 + assert sgn(0'i32) == 0 + assert sgn(0'f32) == 0 + assert sgn(NegInf) == -1 + assert sgn(Inf) == 1 + assert sgn(NaN) == 0 + + block: # fac() tests + try: + discard fac(-1) + except AssertionError: + discard + + doAssert fac(0) == 1 + doAssert fac(1) == 1 + doAssert fac(2) == 2 + doAssert fac(3) == 6 + doAssert fac(4) == 24 + + block: # floorMod/floorDiv + doAssert floorDiv(8, 3) == 2 + doAssert floorMod(8, 3) == 2 + + doAssert floorDiv(8, -3) == -3 + doAssert floorMod(8, -3) == -1 + + doAssert floorDiv(-8, 3) == -3 + doAssert floorMod(-8, 3) == 1 + + doAssert floorDiv(-8, -3) == 2 + doAssert floorMod(-8, -3) == -2 + + doAssert floorMod(8.0, -3.0) ==~ -1.0 + doAssert floorMod(-8.5, 3.0) ==~ 0.5 + + block: # log + doAssert log(4.0, 3.0) ==~ ln(4.0) / ln(3.0) + doAssert log2(8.0'f64) == 3.0'f64 + doAssert log2(4.0'f64) == 2.0'f64 + doAssert log2(2.0'f64) == 1.0'f64 + doAssert log2(1.0'f64) == 0.0'f64 + doAssert classify(log2(0.0'f64)) == fcNegInf + + doAssert log2(8.0'f32) == 3.0'f32 + doAssert log2(4.0'f32) == 2.0'f32 + doAssert log2(2.0'f32) == 1.0'f32 + doAssert log2(1.0'f32) == 0.0'f32 + doAssert classify(log2(0.0'f32)) == fcNegInf diff --git a/lib/pure/md5.nim b/lib/pure/md5.nim index cd4d1e6b8..1ea71afd2 100644 --- a/lib/pure/md5.nim +++ b/lib/pure/md5.nim @@ -7,14 +7,11 @@ # distribution, for details about the copyright. # -## Module for computing [MD5 checksums](https://en.wikipedia.org/wiki/MD5). +## Module for computing `MD5 checksums `_. ## -## This module also works at compile time and in JavaScript. -## -## See also -## ======== -## * `base64 module`_ for a Base64 encoder and decoder -## * `std/sha1 module `_ for the SHA-1 checksum algorithm +## **See also:** +## * `base64 module`_ implements a base64 encoder and decoder +## * `std/sha1 module `_ for a sha1 encoder and decoder ## * `hashes module`_ for efficient computations of hash values ## for diverse Nim types @@ -25,8 +22,8 @@ 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>`_. + MD5Digest* = array[0..15, uint8] ## \ + ## MD5 checksum of a string, obtained with `toMD5 proc <#toMD5,string>`_. MD5Buffer = array[0..63, uint8] MD5Context* {.final.} = object state: MD5State @@ -34,16 +31,15 @@ type 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 - ] + padding: cstring = "\x80\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) @@ -80,7 +76,7 @@ proc II(a: var uint32, b, c, d, x: uint32, s: uint8, ac: uint32) = rot(a, s) a = a + b -proc encode(dest: var MD5Block, src: openArray[uint8]) = +proc encode(dest: var MD5Block, src: cstring) = var j = 0 for i in 0..high(dest): dest[i] = uint32(ord(src[j])) or @@ -98,48 +94,10 @@ proc decode(dest: var openArray[uint8], src: openArray[uint32]) = dest[i+3] = uint8(src[j] shr 24 and 0xff'u32) inc(i, 4) -template slice(s: string, a, b): openArray[uint8] = - when nimvm: - # toOpenArray is not implemented in VM - var s2 = newSeq[uint8](s.len) - for i in 0 ..< s2.len: - s2[i] = uint8(s[i]) - s2 - else: - s.toOpenArrayByte(a, b) - -template slice(s: cstring, a, b): openArray[uint8] = - when nimvm: - # toOpenArray is not implemented in VM - slice($s, a, b) - else: - when defined(js): - # toOpenArrayByte for cstring is not implemented in JS - slice($s, a, b) - else: - s.toOpenArrayByte(a, b) - -template slice(s: openArray[uint8], a, b): openArray[uint8] = - when nimvm: - s[a .. b] - else: - s.toOpenArray(a, b) - -const useMem = declared(copyMem) - -template memOrNot(withMem, withoutMem): untyped = - when nimvm: - withoutMem - else: - when useMem: - withMem - else: - withoutMem - -proc transform(buffer: openArray[uint8], state: var MD5State) = +proc transform(buffer: pointer, state: var MD5State) = var myBlock: MD5Block - encode(myBlock, buffer) + encode(myBlock, cast[cstring](buffer)) var a = state[0] var b = state[1] var c = state[2] @@ -214,23 +172,15 @@ proc transform(buffer: openArray[uint8], state: var MD5State) = state[3] = state[3] + d proc md5Init*(c: var MD5Context) {.raises: [], tags: [], gcsafe.} -proc md5Update*(c: var MD5Context, input: openArray[uint8]) {.raises: [], +proc md5Update*(c: var MD5Context, input: cstring, len: int) {.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:** + ## See also: ## * `getMD5 proc <#getMD5,string>`_ which returns a string representation ## of the `MD5Digest` ## * `$ proc <#$,MD5Digest>`_ for converting MD5Digest to string @@ -239,7 +189,7 @@ proc toMD5*(s: string): MD5Digest = var c: MD5Context md5Init(c) - md5Update(c, s.slice(0, s.len - 1)) + md5Update(c, cstring(s), len(s)) md5Final(c, result) proc `$`*(d: MD5Digest): string = @@ -252,8 +202,10 @@ proc `$`*(d: MD5Digest): string = proc getMD5*(s: string): string = ## Computes an MD5 value of `s` and returns its string representation. + ## .. note:: + ## available at compile time ## - ## **See also:** + ## See also: ## * `toMD5 proc <#toMD5,string>`_ which returns the `MD5Digest` of a string runnableExamples: assert getMD5("abc") == "900150983cd24fb0d6963f7d28e17f72" @@ -262,7 +214,7 @@ proc getMD5*(s: string): string = c: MD5Context d: MD5Digest md5Init(c) - md5Update(c, s.slice(0, s.len - 1)) + md5Update(c, cstring(s), len(s)) md5Final(c, d) result = $d @@ -273,16 +225,10 @@ proc `==`*(D1, D2: MD5Digest): bool = return true -proc clearBuffer(c: var MD5Context) {.inline.} = - memOrNot: - zeroMem(addr(c.buffer), sizeof(MD5Buffer)) - do: - reset(c.buffer) - proc md5Init*(c: var MD5Context) = - ## Initializes an `MD5Context`. + ## Initializes a `MD5Context`. ## - ## If you use the `toMD5 proc <#toMD5,string>`_, there's no need to call this + ## If you use `toMD5 proc <#toMD5,string>`_ there's no need to call this ## function explicitly. c.state[0] = 0x67452301'u32 c.state[1] = 0xEFCDAB89'u32 @@ -290,44 +236,34 @@ proc md5Init*(c: var MD5Context) = c.state[3] = 0x10325476'u32 c.count[0] = 0'u32 c.count[1] = 0'u32 - clearBuffer(c) + zeroMem(addr(c.buffer), sizeof(MD5Buffer)) -proc writeBuffer(c: var MD5Context, index: int, - input: openArray[uint8], inputIndex, len: int) {.inline.} = - memOrNot: - copyMem(addr(c.buffer[index]), unsafeAddr(input[inputIndex]), len) - do: - # cannot use system.`[]=` for arrays and openarrays as - # it can raise RangeDefect which gets tracked - for i in 0..`_, there's no need to call this + ## If you use `toMD5 proc <#toMD5,string>`_ there's no need to call this ## function explicitly. + var input = input 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) + c.count[0] = c.count[0] + (uint32(len) shl 3) + if c.count[0] < (uint32(len) shl 3): c.count[1] = c.count[1] + 1'u32 + c.count[1] = c.count[1] + (uint32(len) shr 29) var PartLen = 64 - Index - if input.len >= PartLen: - writeBuffer(c, Index, input, 0, PartLen) - transform(c.buffer, c.state) + if len >= PartLen: + copyMem(addr(c.buffer[Index]), input, PartLen) + transform(addr(c.buffer), c.state) var i = PartLen - while i + 63 < input.len: - transform(input.slice(i, i + 63), c.state) + while i + 63 < len: + transform(addr(input[i]), 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) + copyMem(addr(c.buffer[0]), addr(input[i]), len-i) + else: + copyMem(addr(c.buffer[Index]), addr(input[0]), 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 + ## If you use `toMD5 proc <#toMD5,string>`_ there's no need to call this ## function explicitly. var Bits: MD5CBits @@ -336,11 +272,18 @@ proc md5Final*(c: var MD5Context, digest: var MD5Digest) = 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) + md5Update(c, padding, PadLen) + md5Update(c, cast[cstring](addr(Bits)), 8) decode(digest, c.state) - clearBuffer(c) + zeroMem(addr(c), sizeof(MD5Context)) +when isMainModule: + assert(getMD5("Franz jagt im komplett verwahrlosten Taxi quer durch Bayern") == + "a3cca2b2aa1e3b5b3b5aad99a8529074") + assert(getMD5("Frank jagt im komplett verwahrlosten Taxi quer durch Bayern") == + "7e716d0e702df0505fc72e2b89467910") + assert($toMD5("") == "d41d8cd98f00b204e9800998ecf8427e") + when defined(nimHasStyleChecks): {.pop.} #{.push styleChecks: off.} diff --git a/lib/pure/memfiles.nim b/lib/pure/memfiles.nim index 74065bc2e..152b03ec6 100644 --- a/lib/pure/memfiles.nim +++ b/lib/pure/memfiles.nim @@ -17,49 +17,17 @@ when defined(windows): import winlean - when defined(nimPreviewSlimSystem): - import std/widestrs elif defined(posix): import posix else: {.error: "the memfiles module is not supported on your operating system!".} -import streams -import std/oserrors - -when defined(nimPreviewSlimSystem): - import std/[syncio, assertions] - +import os, streams proc newEIO(msg: string): ref IOError = new(result) result.msg = msg -proc setFileSize(fh: FileHandle, newFileSize = -1): OSErrorCode = - ## Set the size of open file pointed to by `fh` to `newFileSize` if != -1. - ## Space is only allocated if that is cheaper than writing to the file. This - ## routine returns the last OSErrorCode found rather than raising to support - ## old rollback/clean-up code style. [ Should maybe move to std/osfiles. ] - if newFileSize == -1: - return - when defined(windows): - var sizeHigh = int32(newFileSize shr 32) - let sizeLow = int32(newFileSize and 0xffffffff) - let status = setFilePointer(fh, sizeLow, addr(sizeHigh), FILE_BEGIN) - let lastErr = osLastError() - if (status == INVALID_SET_FILE_POINTER and lastErr.int32 != NO_ERROR) or - setEndOfFile(fh) == 0: - result = lastErr - else: - var e: cint # posix_fallocate truncates up when needed. - when declared(posix_fallocate): - while (e = posix_fallocate(fh, 0, newFileSize); e == EINTR): - discard - if e in [EINVAL, EOPNOTSUPP] and ftruncate(fh, newFileSize) == -1: - result = osLastError() # fallback arguable; Most portable, but allows SEGV - elif e != 0: - result = osLastError() - type MemFile* = object ## represents a memory mapped file mem*: pointer ## a pointer to the memory mapped file. The pointer @@ -80,8 +48,8 @@ proc mapMem*(m: var MemFile, mode: FileMode = fmRead, mappedSize = -1, offset = 0, mapFlags = cint(-1)): pointer = ## returns a pointer to a mapped portion of MemFile `m` ## - ## `mappedSize` of `-1` maps to the whole file, and - ## `offset` must be multiples of the PAGE SIZE of your OS + ## ``mappedSize`` of ``-1`` maps to the whole file, and + ## ``offset`` must be multiples of the PAGE SIZE of your OS if mode == fmAppend: raise newEIO("The append mode is not supported.") @@ -115,12 +83,12 @@ proc mapMem*(m: var MemFile, mode: FileMode = fmRead, proc unmapMem*(f: var MemFile, p: pointer, size: int) = - ## unmaps the memory region `(p, allocated. - if (let e = setFileSize(f.fHandle.FileHandle, newFileSize); - e != 0.OSErrorCode): raiseOSError(e) - f.mapHandle = createFileMappingW(f.fHandle, nil, PAGE_READWRITE, 0,0,nil) - if f.mapHandle == 0: # Re-do map - raiseOSError(osLastError()) - if (let m = mapViewOfFileEx(f.mapHandle, FILE_MAP_READ or FILE_MAP_WRITE, - 0, 0, WinSizeT(newFileSize), nil); m != nil): - f.mem = m +when defined(posix) or defined(nimdoc): + proc resize*(f: var MemFile, newFileSize: int) {.raises: [IOError, OSError].} = + ## resize and re-map the file underlying an ``allowRemap MemFile``. + ## **Note**: this assumes the entire file is mapped read-write at offset zero. + ## Also, the value of ``.mem`` will probably change. + ## **Note**: This is not (yet) available on Windows. + when defined(posix): + if f.handle == -1: + raise newException(IOError, + "Cannot resize MemFile opened with allowRemap=false") + if ftruncate(f.handle, newFileSize) == -1: + raiseOSError(osLastError()) + when defined(linux): #Maybe NetBSD, too? + #On Linux this can be over 100 times faster than a munmap,mmap cycle. + proc mremap(old: pointer; oldSize, newSize: csize; flags: cint): + pointer {.importc: "mremap", header: "".} + let newAddr = mremap(f.mem, csize(f.size), csize(newFileSize), cint(1)) + if newAddr == cast[pointer](MAP_FAILED): + raiseOSError(osLastError()) + else: + if munmap(f.mem, f.size) != 0: + raiseOSError(osLastError()) + let newAddr = mmap(nil, newFileSize, PROT_READ or PROT_WRITE, + f.flags, f.handle, 0) + if newAddr == cast[pointer](MAP_FAILED): + raiseOSError(osLastError()) + f.mem = newAddr f.size = newFileSize - else: - raiseOSError(osLastError()) - elif defined(posix): - if f.handle == -1: - raise newException(IOError, - "Cannot resize MemFile opened with allowRemap=false") - if newFileSize != f.size: - if (let e = setFileSize(f.handle.FileHandle, newFileSize); - e != 0.OSErrorCode): raiseOSError(e) - when defined(linux): #Maybe NetBSD, too? - # On Linux this can be over 100 times faster than a munmap,mmap cycle. - proc mremap(old: pointer; oldSize, newSize: csize_t; flags: cint): - pointer {.importc: "mremap", header: "".} - let newAddr = mremap(f.mem, csize_t(f.size), csize_t(newFileSize), 1.cint) - if newAddr == cast[pointer](MAP_FAILED): - raiseOSError(osLastError()) - else: - if munmap(f.mem, f.size) != 0: - raiseOSError(osLastError()) - let newAddr = mmap(nil, newFileSize, PROT_READ or PROT_WRITE, - f.flags, f.handle, 0) - if newAddr == cast[pointer](MAP_FAILED): - raiseOSError(osLastError()) - f.mem = newAddr - f.size = newFileSize proc close*(f: var MemFile) = ## closes the memory mapped file `f`. All changes are written back to the @@ -420,7 +377,7 @@ proc `$`*(ms: MemSlice): string {.inline.} = copyMem(addr(result[0]), ms.data, ms.size) iterator memSlices*(mfile: MemFile, delim = '\l', eat = '\r'): MemSlice {.inline.} = - ## Iterates over \[optional `eat`] `delim`-delimited slices in MemFile `mfile`. + ## Iterates over [optional `eat`] `delim`-delimited slices in MemFile `mfile`. ## ## Default parameters parse lines ending in either Unix(\\l) or Windows(\\r\\l) ## style on on a line-by-line basis. I.e., not every line needs the same ending. @@ -451,7 +408,7 @@ iterator memSlices*(mfile: MemFile, delim = '\l', eat = '\r'): MemSlice {.inline ## inc(count) ## echo count - proc c_memchr(cstr: pointer, c: char, n: csize_t): pointer {. + proc c_memchr(cstr: pointer, c: char, n: csize): pointer {. importc: "memchr", header: "".} proc `-!`(p, q: pointer): int {.inline.} = return cast[int](p) -% cast[int](q) var ms: MemSlice @@ -459,7 +416,7 @@ iterator memSlices*(mfile: MemFile, delim = '\l', eat = '\r'): MemSlice {.inline ms.data = mfile.mem var remaining = mfile.size while remaining > 0: - ending = c_memchr(ms.data, delim, csize_t(remaining)) + ending = c_memchr(ms.data, delim, remaining) if ending == nil: # unterminated final slice ms.size = remaining # Weird case..check eat? yield ms @@ -471,29 +428,29 @@ iterator memSlices*(mfile: MemFile, delim = '\l', eat = '\r'): MemSlice {.inline ms.data = cast[pointer](cast[int](ending) +% 1) # skip delim remaining = mfile.size - (ms.data -! mfile.mem) -iterator lines*(mfile: MemFile, buf: var string, delim = '\l', - eat = '\r'): string {.inline.} = +iterator lines*(mfile: MemFile, buf: var TaintedString, delim = '\l', + eat = '\r'): TaintedString {.inline.} = ## Replace contents of passed buffer with each new line, like - ## `readLine(File) `_. + ## `readLine(File) `_. ## `delim`, `eat`, and delimiting logic is exactly as for `memSlices ## <#memSlices.i,MemFile,char,char>`_, but Nim strings are returned. ## ## Example: ## ## .. code-block:: nim - ## var buffer: string = "" + ## var buffer: TaintedString = "" ## for line in lines(memfiles.open("foo"), buffer): ## echo line for ms in memSlices(mfile, delim, eat): - setLen(buf, ms.size) + setLen(buf.string, ms.size) if ms.size > 0: copyMem(addr buf[0], ms.data, ms.size) yield buf -iterator lines*(mfile: MemFile, delim = '\l', eat = '\r'): string {.inline.} = +iterator lines*(mfile: MemFile, delim = '\l', eat = '\r'): TaintedString {.inline.} = ## Return each line in a file as a Nim string, like - ## `lines(File) `_. + ## `lines(File) `_. ## `delim`, `eat`, and delimiting logic is exactly as for `memSlices ## <#memSlices.i,MemFile,char,char>`_, but Nim strings are returned. ## @@ -503,7 +460,7 @@ iterator lines*(mfile: MemFile, delim = '\l', eat = '\r'): string {.inline.} = ## for line in lines(memfiles.open("foo")): ## echo line - var buf = newStringOfCap(80) + var buf = TaintedString(newStringOfCap(80)) for line in lines(mfile, buf, delim, eat): yield buf @@ -531,8 +488,8 @@ proc mmsSetPosition(s: Stream, pos: int) = proc mmsGetPosition(s: Stream): int = MemMapFileStream(s).pos proc mmsPeekData(s: Stream, buffer: pointer, bufLen: int): int = - let startAddress = cast[int](MemMapFileStream(s).mf.mem) - let p = cast[int](MemMapFileStream(s).pos) + let startAddress = cast[ByteAddress](MemMapFileStream(s).mf.mem) + let p = cast[ByteAddress](MemMapFileStream(s).pos) let l = min(bufLen, MemMapFileStream(s).mf.size - p) moveMem(buffer, cast[pointer](startAddress + p), l) result = l @@ -547,8 +504,8 @@ proc mmsWriteData(s: Stream, buffer: pointer, bufLen: int) = let size = MemMapFileStream(s).mf.size if MemMapFileStream(s).pos + bufLen > size: raise newEIO("cannot write to stream") - let p = cast[int](MemMapFileStream(s).mf.mem) + - cast[int](MemMapFileStream(s).pos) + let p = cast[ByteAddress](MemMapFileStream(s).mf.mem) + + cast[ByteAddress](MemMapFileStream(s).pos) moveMem(cast[pointer](p), buffer, bufLen) inc(MemMapFileStream(s).pos, bufLen) @@ -557,7 +514,7 @@ proc newMemMapFileStream*(filename: string, mode: FileMode = fmRead, ## creates a new stream from the file named `filename` with the mode `mode`. ## Raises ## `OSError` if the file cannot be opened. See the `system ## `_ module for a list of available FileMode enums. - ## `fileSize` can only be set if the file does not exist and is opened + ## ``fileSize`` can only be set if the file does not exist and is opened ## with write access (e.g., with fmReadWrite). var mf: MemFile = open(filename, mode, newFileSize = fileSize) new(result) diff --git a/lib/deprecated/pure/mersenne.nim b/lib/pure/mersenne.nim similarity index 66% rename from lib/deprecated/pure/mersenne.nim rename to lib/pure/mersenne.nim index 37c5085b1..a2b8914d9 100644 --- a/lib/deprecated/pure/mersenne.nim +++ b/lib/pure/mersenne.nim @@ -2,28 +2,17 @@ # # Nim's Runtime Library # (c) Copyright 2015 Nim Contributors +# # See the file "copying.txt", included in this # distribution, for details about the copyright. -## The [Mersenne Twister](https://en.wikipedia.org/wiki/Mersenne_Twister) -## random number generator. -## .. note:: The procs in this module work at compile-time. +# -{.deprecated: "use `std/random` instead".} - -runnableExamples: - var rand = newMersenneTwister(uint32.high) ## must be "var" - doAssert rand.getNum() != rand.getNum() ## pseudorandom number -## See also -## ======== -## * `random module`_ for Nim's standard random number generator type MersenneTwister* = object - ## The Mersenne Twister. mt: array[0..623, uint32] index: int proc newMersenneTwister*(seed: uint32): MersenneTwister = - ## Creates a new `MersenneTwister` with seed `seed`. result.index = 0 result.mt[0] = seed for i in 1'u32 .. 623'u32: @@ -31,7 +20,6 @@ proc newMersenneTwister*(seed: uint32): MersenneTwister = (result.mt[i-1] shr 30'u32)) + i) proc generateNumbers(m: var MersenneTwister) = - for i in 0..623: var y = (m.mt[i] and 0x80000000'u32) + (m.mt[(i+1) mod 624] and 0x7fffffff'u32) @@ -40,12 +28,20 @@ proc generateNumbers(m: var MersenneTwister) = m.mt[i] = m.mt[i] xor 0x9908b0df'u32 proc getNum*(m: var MersenneTwister): uint32 = - ## Returns the next pseudorandom `uint32`. + ## Returns the next pseudo random number ranging from 0 to high(uint32) if m.index == 0: generateNumbers(m) result = m.mt[m.index] m.index = (m.index + 1) mod m.mt.len + result = result xor (result shr 11'u32) result = result xor ((result shl 7'u32) and 0x9d2c5680'u32) result = result xor ((result shl 15'u32) and 0xefc60000'u32) result = result xor (result shr 18'u32) + +# Test +when not defined(testing) and isMainModule: + var mt = newMersenneTwister(2525) + + for i in 0..99: + echo mt.getNum diff --git a/lib/pure/mimetypes.nim b/lib/pure/mimetypes.nim index 346fb39ee..f3f6e9324 100644 --- a/lib/pure/mimetypes.nim +++ b/lib/pure/mimetypes.nim @@ -8,34 +8,12 @@ # ## This module implements a mimetypes database - -runnableExamples: - var m = newMimetypes() - doAssert m.getMimetype("mp4") == "video/mp4" - doAssert m.getExt("text/html") == "html" - ## Values can be uppercase too. - doAssert m.getMimetype("MP4") == "video/mp4" - doAssert m.getExt("TEXT/HTML") == "html" - ## If values are invalid then `default` is returned. - doAssert m.getMimetype("INVALID") == "text/plain" - doAssert m.getExt("INVALID/NONEXISTENT") == "txt" - doAssert m.getMimetype("") == "text/plain" - doAssert m.getExt("") == "txt" - ## Register new Mimetypes. - m.register(ext = "fakext", mimetype = "text/fakelang") - doAssert m.getMimetype("fakext") == "text/fakelang" - doAssert m.getMimetype("FaKeXT") == "text/fakelang" - -import tables +import strtabs from strutils import startsWith, toLowerAscii, strip -when defined(nimPreviewSlimSystem): - import std/assertions - - type MimeDB* = object - mimes: OrderedTable[string, string] + mimes: StringTableRef const mimes* = { "123": "application/vnd.lotus-1-2-3", @@ -1907,13 +1885,12 @@ const mimes* = { func newMimetypes*(): MimeDB = ## Creates a new Mimetypes database. The database will contain the most ## common mimetypes. - {.cast(noSideEffect).}: - result.mimes = mimes.toOrderedTable() + result.mimes = mimes.newStringTable() func getMimetype*(mimedb: MimeDB, ext: string, default = "text/plain"): string = - ## Gets mimetype which corresponds to `ext`. Returns `default` if `ext` - ## could not be found. `ext` can start with an optional dot which is ignored. - ## `ext` is lowercased before querying `mimedb`. + ## Gets mimetype which corresponds to ``ext``. Returns ``default`` if ``ext`` + ## could not be found. ``ext`` can start with an optional dot which is ignored. + ## ``ext`` is lowercased before querying ``mimedb``. if ext.startsWith("."): result = mimedb.mimes.getOrDefault(ext.toLowerAscii.substr(1)) else: @@ -1922,9 +1899,9 @@ func getMimetype*(mimedb: MimeDB, ext: string, default = "text/plain"): string = return default func getExt*(mimedb: MimeDB, mimetype: string, default = "txt"): string = - ## Gets extension which corresponds to `mimetype`. Returns `default` if - ## `mimetype` could not be found. Extensions are returned without the - ## leading dot. `mimetype` is lowercased before querying `mimedb`. + ## Gets extension which corresponds to ``mimetype``. Returns ``default`` if + ## ``mimetype`` could not be found. Extensions are returned without the + ## leading dot. ``mimetype`` is lowercased before querying ``mimedb``. result = default let mimeLowered = mimetype.toLowerAscii() for e, m in mimedb.mimes: @@ -1933,9 +1910,25 @@ func getExt*(mimedb: MimeDB, mimetype: string, default = "txt"): string = break func register*(mimedb: var MimeDB, ext: string, mimetype: string) = - ## Adds `mimetype` to the `mimedb`. - ## `mimetype` and `ext` are lowercased before registering on `mimedb`. + ## Adds ``mimetype`` to the ``mimedb``. + ## ``mimetype`` and ``ext`` are lowercased before registering on ``mimedb``. assert ext.strip.len > 0, "ext argument can not be empty string" assert mimetype.strip.len > 0, "mimetype argument can not be empty string" - {.noSideEffect.}: - mimedb.mimes[ext.toLowerAscii()] = mimetype.toLowerAscii() + mimedb.mimes[ext.toLowerAscii()] = mimetype.toLowerAscii() + +runnableExamples: + var m = newMimetypes() + assert m.getMimetype("mp4") == "video/mp4" + assert m.getExt("text/html") == "html" + ## Values can be uppercase too. + assert m.getMimetype("MP4") == "video/mp4" + assert m.getExt("TEXT/HTML") == "html" + ## If values are invalid then ``default`` is returned. + assert m.getMimetype("INVALID") == "text/plain" + assert m.getExt("INVALID/NONEXISTENT") == "txt" + assert m.getMimetype("") == "text/plain" + assert m.getExt("") == "txt" + ## Register new Mimetypes. + m.register(ext = "fakext", mimetype = "text/fakelang") + assert m.getMimetype("fakext") == "text/fakelang" + assert m.getMimetype("FaKeXT") == "text/fakelang" diff --git a/lib/pure/nativesockets.nim b/lib/pure/nativesockets.nim index b3465ef14..d9256a921 100644 --- a/lib/pure/nativesockets.nim +++ b/lib/pure/nativesockets.nim @@ -8,23 +8,16 @@ # ## This module implements a low-level cross-platform sockets interface. Look -## at the `net` module for the higher-level version. +## at the ``net`` module for the higher-level version. # TODO: Clean up the exports a bit and everything else in general. import os, options -import std/private/since -import std/strbasics - -when defined(nimPreviewSlimSystem): - import std/[assertions, syncio] when hostOS == "solaris": {.passl: "-lsocket -lnsl".} -const useWinVersion = defined(windows) or defined(nimdoc) -const useNimNetLite = defined(nimNetLite) or defined(freertos) or defined(zephyr) or - defined(nuttx) +const useWinVersion = defined(Windows) or defined(nimdoc) when useWinVersion: import winlean @@ -39,12 +32,9 @@ else: export SocketHandle, Sockaddr_in, Addrinfo, INADDR_ANY, SockAddr, SockLen, Sockaddr_in6, Sockaddr_storage, - recv, `==`, connect, send, accept, recvfrom, sendto, + inet_ntoa, recv, `==`, connect, send, accept, recvfrom, sendto, freeAddrInfo -when not useNimNetLite: - export inet_ntoa - export SO_ERROR, SOL_SOCKET, @@ -78,11 +68,11 @@ type Protocol* = enum ## third argument to `socket` proc IPPROTO_TCP = 6, ## Transmission control protocol. IPPROTO_UDP = 17, ## User datagram protocol. - IPPROTO_IP, ## Internet protocol. - IPPROTO_IPV6, ## Internet Protocol Version 6. + IPPROTO_IP, ## Internet protocol. Unsupported on Windows. + IPPROTO_IPV6, ## Internet Protocol Version 6. Unsupported on Windows. IPPROTO_RAW, ## Raw IP Packets Protocol. Unsupported on Windows. - IPPROTO_ICMP ## Internet Control message protocol. - IPPROTO_ICMPV6 ## Internet Control message protocol for IPv6. + IPPROTO_ICMP ## Control message protocol. Unsupported on Windows. + IPPROTO_ICMPV6 ## Control message protocol for IPv6. Unsupported on Windows. Servent* = object ## information about a service name*: string @@ -120,19 +110,19 @@ else: nativeAfUnix = posix.AF_UNIX proc `==`*(a, b: Port): bool {.borrow.} - ## `==` for ports. + ## ``==`` for ports. proc `$`*(p: Port): string {.borrow.} - ## Returns the port number as a string + ## returns the port number as a string proc toInt*(domain: Domain): cint - ## Converts the Domain enum to a platform-dependent `cint`. + ## Converts the Domain enum to a platform-dependent ``cint``. proc toInt*(typ: SockType): cint - ## Converts the SockType enum to a platform-dependent `cint`. + ## Converts the SockType enum to a platform-dependent ``cint``. proc toInt*(p: Protocol): cint - ## Converts the Protocol enum to a platform-dependent `cint`. + ## Converts the Protocol enum to a platform-dependent ``cint``. when not useWinVersion: proc toInt(domain: Domain): cint = @@ -143,8 +133,8 @@ when not useWinVersion: of AF_INET6: result = posix.AF_INET6.cint proc toKnownDomain*(family: cint): Option[Domain] = - ## Converts the platform-dependent `cint` to the Domain or none(), - ## if the `cint` is not known. + ## Converts the platform-dependent ``cint`` to the Domain or none(), + ## if the ``cint`` is not known. result = if family == posix.AF_UNSPEC: some(Domain.AF_UNSPEC) elif family == posix.AF_UNIX: some(Domain.AF_UNIX) elif family == posix.AF_INET: some(Domain.AF_INET) @@ -170,11 +160,11 @@ when not useWinVersion: else: proc toInt(domain: Domain): cint = - result = cast[cint](uint32(ord(domain))) + result = toU32(ord(domain)).cint proc toKnownDomain*(family: cint): Option[Domain] = - ## Converts the platform-dependent `cint` to the Domain or none(), - ## if the `cint` is not known. + ## Converts the platform-dependent ``cint`` to the Domain or none(), + ## if the ``cint`` is not known. result = if family == winlean.AF_UNSPEC: some(Domain.AF_UNSPEC) elif family == winlean.AF_INET: some(Domain.AF_INET) elif family == winlean.AF_INET6: some(Domain.AF_INET6) @@ -184,21 +174,7 @@ else: result = cint(ord(typ)) proc toInt(p: Protocol): cint = - case p - of IPPROTO_IP: - result = 0.cint - of IPPROTO_ICMP: - result = 1.cint - of IPPROTO_TCP: - result = 6.cint - of IPPROTO_UDP: - result = 17.cint - of IPPROTO_IPV6: - result = 41.cint - of IPPROTO_ICMPV6: - result = 58.cint - else: - result = cint(ord(p)) + result = cint(ord(p)) proc toSockType*(protocol: Protocol): SockType = result = case protocol @@ -209,20 +185,38 @@ proc toSockType*(protocol: Protocol): SockType = of IPPROTO_IP, IPPROTO_IPV6, IPPROTO_RAW, IPPROTO_ICMP, IPPROTO_ICMPV6: SOCK_RAW -proc getProtoByName*(name: string): int {.since: (1, 3, 5).} = - ## Returns a protocol code from the database that matches the protocol `name`. - when useWinVersion: - let protoent = winlean.getprotobyname(name.cstring) - else: - let protoent = posix.getprotobyname(name.cstring) +proc createNativeSocket*(domain: Domain = AF_INET, + sockType: SockType = SOCK_STREAM, + protocol: Protocol = IPPROTO_TCP): SocketHandle = + ## Creates a new socket; returns `osInvalidSocket` if an error occurs. + socket(toInt(domain), toInt(sockType), toInt(protocol)) - if protoent == nil: - raise newException(OSError, "protocol not found: " & name) +proc createNativeSocket*(domain: cint, sockType: cint, + protocol: cint): SocketHandle = + ## Creates a new socket; returns `osInvalidSocket` if an error occurs. + ## + ## Use this overload if one of the enums specified above does + ## not contain what you need. + socket(domain, sockType, protocol) - result = protoent.p_proto.int +proc newNativeSocket*(domain: Domain = AF_INET, + sockType: SockType = SOCK_STREAM, + protocol: Protocol = IPPROTO_TCP): SocketHandle + {.deprecated: "deprecated since v0.18.0; use 'createNativeSocket' instead".} = + ## Creates a new socket; returns `osInvalidSocket` if an error occurs. + createNativeSocket(domain, sockType, protocol) + +proc newNativeSocket*(domain: cint, sockType: cint, + protocol: cint): SocketHandle + {.deprecated: "deprecated since v0.18.0; use 'createNativeSocket' instead".} = + ## Creates a new socket; returns `osInvalidSocket` if an error occurs. + ## + ## Use this overload if one of the enums specified above does + ## not contain what you need. + createNativeSocket(domain, sockType, protocol) proc close*(socket: SocketHandle) = - ## Closes a socket. + ## closes a socket. when useWinVersion: discard winlean.closesocket(socket) else: @@ -230,53 +224,14 @@ proc close*(socket: SocketHandle) = # TODO: These values should not be discarded. An OSError should be raised. # http://stackoverflow.com/questions/12463473/what-happens-if-you-call-close-on-a-bsd-socket-multiple-times -when declared(setInheritable) or defined(nimdoc): - proc setInheritable*(s: SocketHandle, inheritable: bool): bool {.inline.} = - ## Set whether a socket is inheritable by child processes. Returns `true` - ## on success. - ## - ## This function is not implemented on all platform, test for availability - ## with `declared() `. - setInheritable(FileHandle s, inheritable) - -proc createNativeSocket*(domain: cint, sockType: cint, protocol: cint, - inheritable: bool = defined(nimInheritHandles)): SocketHandle = - ## Creates a new socket; returns `osInvalidSocket` if an error occurs. - ## - ## `inheritable` decides if the resulting SocketHandle can be inherited - ## by child processes. - ## - ## Use this overload if one of the enums specified above does - ## not contain what you need. - let sockType = - when (defined(linux) or defined(bsd)) and not defined(nimdoc): - if inheritable: sockType and not SOCK_CLOEXEC else: sockType or SOCK_CLOEXEC - else: - sockType - result = socket(domain, sockType, protocol) - when declared(setInheritable) and not (defined(linux) or defined(bsd)): - if not setInheritable(result, inheritable): - close result - return osInvalidSocket - -proc createNativeSocket*(domain: Domain = AF_INET, - sockType: SockType = SOCK_STREAM, - protocol: Protocol = IPPROTO_TCP, - inheritable: bool = defined(nimInheritHandles)): SocketHandle = - ## Creates a new socket; returns `osInvalidSocket` if an error occurs. - ## - ## `inheritable` decides if the resulting SocketHandle can be inherited - ## by child processes. - createNativeSocket(toInt(domain), toInt(sockType), toInt(protocol), inheritable) - proc bindAddr*(socket: SocketHandle, name: ptr SockAddr, namelen: SockLen): cint = result = bindSocket(socket, name, namelen) proc listen*(socket: SocketHandle, backlog = SOMAXCONN): cint {.tags: [ ReadIOEffect].} = - ## Marks `socket` as accepting connections. - ## `Backlog` specifies the maximum length of the + ## Marks ``socket`` as accepting connections. + ## ``Backlog`` specifies the maximum length of the ## queue of pending connections. when useWinVersion: result = winlean.listen(socket, cint(backlog)) @@ -288,7 +243,7 @@ proc getAddrInfo*(address: string, port: Port, domain: Domain = AF_INET, protocol: Protocol = IPPROTO_TCP): ptr AddrInfo = ## ## - ## .. warning:: The resulting `ptr AddrInfo` must be freed using `freeAddrInfo`! + ## **Warning**: The resulting ``ptr AddrInfo`` must be freed using ``freeAddrInfo``! var hints: AddrInfo result = nil hints.ai_family = toInt(domain) @@ -303,9 +258,9 @@ proc getAddrInfo*(address: string, port: Port, domain: Domain = AF_INET, if domain == AF_INET6: hints.ai_flags = AI_V4MAPPED let socketPort = if sockType == SOCK_RAW: "" else: $port - var gaiResult = getaddrinfo(address, socketPort.cstring, addr(hints), result) + var gaiResult = getaddrinfo(address, socketPort, addr(hints), result) if gaiResult != 0'i32: - when useWinVersion or defined(freertos) or defined(nuttx): + when useWinVersion: raiseOSError(osLastError()) else: raiseOSError(osLastError(), $gai_strerror(gaiResult)) @@ -339,367 +294,258 @@ template htons*(x: uint16): untyped = ## order, this is a no-op; otherwise, it performs a 2-byte swap operation. nativesockets.ntohs(x) +proc getServByName*(name, proto: string): Servent {.tags: [ReadIOEffect].} = + ## Searches the database from the beginning and finds the first entry for + ## which the service name specified by ``name`` matches the s_name member + ## and the protocol name specified by ``proto`` matches the s_proto member. + ## + ## On posix this will search through the ``/etc/services`` file. + when useWinVersion: + var s = winlean.getservbyname(name, proto) + else: + var s = posix.getservbyname(name, proto) + if s == nil: raiseOSError(osLastError(), "Service not found.") + result.name = $s.s_name + result.aliases = cstringArrayToSeq(s.s_aliases) + result.port = Port(s.s_port) + result.proto = $s.s_proto + +proc getServByPort*(port: Port, proto: string): Servent {.tags: [ReadIOEffect].} = + ## Searches the database from the beginning and finds the first entry for + ## which the port specified by ``port`` matches the s_port member and the + ## protocol name specified by ``proto`` matches the s_proto member. + ## + ## On posix this will search through the ``/etc/services`` file. + when useWinVersion: + var s = winlean.getservbyport(ze(int16(port)).cint, proto) + else: + var s = posix.getservbyport(ze(int16(port)).cint, proto) + if s == nil: raiseOSError(osLastError(), "Service not found.") + result.name = $s.s_name + result.aliases = cstringArrayToSeq(s.s_aliases) + result.port = Port(s.s_port) + result.proto = $s.s_proto + +proc getHostByAddr*(ip: string): Hostent {.tags: [ReadIOEffect].} = + ## This function will lookup the hostname of an IP Address. + var myaddr: InAddr + myaddr.s_addr = inet_addr(ip) + + when useWinVersion: + var s = winlean.gethostbyaddr(addr(myaddr), sizeof(myaddr).cuint, + cint(AF_INET)) + if s == nil: raiseOSError(osLastError()) + else: + var s = + when defined(android4): + posix.gethostbyaddr(cast[cstring](addr(myaddr)), sizeof(myaddr).cint, + cint(posix.AF_INET)) + else: + posix.gethostbyaddr(addr(myaddr), sizeof(myaddr).SockLen, + cint(posix.AF_INET)) + if s == nil: + raiseOSError(osLastError(), $hstrerror(h_errno)) + + result.name = $s.h_name + result.aliases = cstringArrayToSeq(s.h_aliases) + when useWinVersion: + result.addrtype = Domain(s.h_addrtype) + else: + if s.h_addrtype == posix.AF_INET: + result.addrtype = AF_INET + elif s.h_addrtype == posix.AF_INET6: + result.addrtype = AF_INET6 + else: + raiseOSError(osLastError(), "unknown h_addrtype") + if result.addrtype == AF_INET: + result.addrList = @[] + var i = 0 + while not isNil(s.h_addr_list[i]): + var inaddrPtr = cast[ptr InAddr](s.h_addr_list[i]) + result.addrList.add($inet_ntoa(inaddrPtr[])) + inc(i) + else: + result.addrList = cstringArrayToSeq(s.h_addr_list) + result.length = int(s.h_length) + +proc getHostByName*(name: string): Hostent {.tags: [ReadIOEffect].} = + ## This function will lookup the IP address of a hostname. + when useWinVersion: + var s = winlean.gethostbyname(name) + else: + var s = posix.gethostbyname(name) + if s == nil: raiseOSError(osLastError()) + result.name = $s.h_name + result.aliases = cstringArrayToSeq(s.h_aliases) + when useWinVersion: + result.addrtype = Domain(s.h_addrtype) + else: + if s.h_addrtype == posix.AF_INET: + result.addrtype = AF_INET + elif s.h_addrtype == posix.AF_INET6: + result.addrtype = AF_INET6 + else: + raiseOSError(osLastError(), "unknown h_addrtype") + if result.addrtype == AF_INET: + result.addrList = @[] + var i = 0 + while not isNil(s.h_addr_list[i]): + var inaddrPtr = cast[ptr InAddr](s.h_addr_list[i]) + result.addrList.add($inet_ntoa(inaddrPtr[])) + inc(i) + else: + result.addrList = cstringArrayToSeq(s.h_addr_list) + result.length = int(s.h_length) + +proc getHostname*(): string {.tags: [ReadIOEffect].} = + ## Returns the local hostname (not the FQDN) + # https://tools.ietf.org/html/rfc1035#section-2.3.1 + # https://tools.ietf.org/html/rfc2181#section-11 + const size = 64 + result = newString(size) + when useWinVersion: + let success = winlean.gethostname(result, size) + else: + # Posix + let success = posix.gethostname(result, size) + if success != 0.cint: + raiseOSError(osLastError()) + let x = len(cstring(result)) + result.setLen(x) + proc getSockDomain*(socket: SocketHandle): Domain = - ## Returns the socket's domain (AF_INET or AF_INET6). + ## returns the socket's domain (AF_INET or AF_INET6). var name: Sockaddr_in6 var namelen = sizeof(name).SockLen if getsockname(socket, cast[ptr SockAddr](addr(name)), addr(namelen)) == -1'i32: raiseOSError(osLastError()) - let knownDomain = toKnownDomain(name.sin6_family.cint) - if knownDomain.isSome: - result = knownDomain.get() - else: + try: + result = toKnownDomain(name.sin6_family.cint).get() + except UnpackError: raise newException(IOError, "Unknown socket family in getSockDomain") -when not useNimNetLite: - proc getServByName*(name, proto: string): Servent {.tags: [ReadIOEffect].} = - ## Searches the database from the beginning and finds the first entry for - ## which the service name specified by `name` matches the s_name member - ## and the protocol name specified by `proto` matches the s_proto member. - ## - ## On posix this will search through the `/etc/services` file. - when useWinVersion: - var s = winlean.getservbyname(name, proto) +proc getAddrString*(sockAddr: ptr SockAddr): string = + ## return the string representation of address within sockAddr + if sockAddr.sa_family.cint == nativeAfInet: + result = $inet_ntoa(cast[ptr Sockaddr_in](sockAddr).sin_addr) + elif sockAddr.sa_family.cint == nativeAfInet6: + let addrLen = when not useWinVersion: posix.INET6_ADDRSTRLEN + else: 46 # it's actually 46 in both cases + result = newString(addrLen) + let addr6 = addr cast[ptr Sockaddr_in6](sockAddr).sin6_addr + when not useWinVersion: + if posix.inet_ntop(posix.AF_INET6, addr6, addr result[0], + result.len.int32) == nil: + raiseOSError(osLastError()) + if posix.IN6_IS_ADDR_V4MAPPED(addr6) != 0: + result = result.substr("::ffff:".len) else: - var s = posix.getservbyname(name, proto) - if s == nil: raiseOSError(osLastError(), "Service not found.") - result.name = $s.s_name - result.aliases = cstringArrayToSeq(s.s_aliases) - result.port = Port(s.s_port) - result.proto = $s.s_proto + if winlean.inet_ntop(winlean.AF_INET6, addr6, addr result[0], + result.len.int32) == nil: + raiseOSError(osLastError()) + setLen(result, len(cstring(result))) + else: + when defined(posix) and not defined(nimdoc): + if sockAddr.sa_family.cint == nativeAfUnix: + return "unix" + raise newException(IOError, "Unknown socket family in getAddrString") - proc getServByPort*(port: Port, proto: string): Servent {.tags: [ReadIOEffect].} = - ## Searches the database from the beginning and finds the first entry for - ## which the port specified by `port` matches the s_port member and the - ## protocol name specified by `proto` matches the s_proto member. - ## - ## On posix this will search through the `/etc/services` file. - when useWinVersion: - var s = winlean.getservbyport(uint16(port).cint, proto) - else: - var s = posix.getservbyport(uint16(port).cint, proto) - if s == nil: raiseOSError(osLastError(), "Service not found.") - result.name = $s.s_name - result.aliases = cstringArrayToSeq(s.s_aliases) - result.port = Port(s.s_port) - result.proto = $s.s_proto +when defined(posix) and not defined(nimdoc): + proc makeUnixAddr*(path: string): Sockaddr_un = + result.sun_family = AF_UNIX.TSa_Family + if path.len >= Sockaddr_un_path_length: + raise newException(ValueError, "socket path too long") + copyMem(addr result.sun_path, path.cstring, path.len + 1) - proc getHostByAddr*(ip: string): Hostent {.tags: [ReadIOEffect].} = - ## This function will lookup the hostname of an IP Address. - var myaddr: InAddr - myaddr.s_addr = inet_addr(ip) +proc getSockName*(socket: SocketHandle): Port = + ## returns the socket's associated port number. + var name: Sockaddr_in + when useWinVersion: + name.sin_family = uint16(ord(AF_INET)) + else: + name.sin_family = TSa_Family(posix.AF_INET) + #name.sin_port = htons(cint16(port)) + #name.sin_addr.s_addr = htonl(INADDR_ANY) + var namelen = sizeof(name).SockLen + if getsockname(socket, cast[ptr SockAddr](addr(name)), + addr(namelen)) == -1'i32: + raiseOSError(osLastError()) + result = Port(nativesockets.ntohs(name.sin_port)) - when useWinVersion: - var s = winlean.gethostbyaddr(addr(myaddr), sizeof(myaddr).cuint, - cint(AF_INET)) - if s == nil: raiseOSError(osLastError()) - else: - var s = - when defined(android4): - posix.gethostbyaddr(cast[cstring](addr(myaddr)), sizeof(myaddr).cint, - cint(posix.AF_INET)) - else: - posix.gethostbyaddr(addr(myaddr), sizeof(myaddr).SockLen, - cint(posix.AF_INET)) - if s == nil: - raiseOSError(osLastError(), $hstrerror(h_errno)) - - result.name = $s.h_name - result.aliases = cstringArrayToSeq(s.h_aliases) - when useWinVersion: - result.addrtype = Domain(s.h_addrtype) - else: - if s.h_addrtype == posix.AF_INET: - result.addrtype = AF_INET - elif s.h_addrtype == posix.AF_INET6: - result.addrtype = AF_INET6 - else: - raiseOSError(osLastError(), "unknown h_addrtype") - if result.addrtype == AF_INET: - result.addrList = @[] - var i = 0 - while not isNil(s.h_addr_list[i]): - var inaddrPtr = cast[ptr InAddr](s.h_addr_list[i]) - result.addrList.add($inet_ntoa(inaddrPtr[])) - inc(i) - else: - result.addrList = cstringArrayToSeq(s.h_addr_list) - result.length = int(s.h_length) - - proc getHostByName*(name: string): Hostent {.tags: [ReadIOEffect].} = - ## This function will lookup the IP address of a hostname. - when useWinVersion: - var s = winlean.gethostbyname(name) - else: - var s = posix.gethostbyname(name) - if s == nil: raiseOSError(osLastError()) - result.name = $s.h_name - result.aliases = cstringArrayToSeq(s.h_aliases) - when useWinVersion: - result.addrtype = Domain(s.h_addrtype) - else: - if s.h_addrtype == posix.AF_INET: - result.addrtype = AF_INET - elif s.h_addrtype == posix.AF_INET6: - result.addrtype = AF_INET6 - else: - raiseOSError(osLastError(), "unknown h_addrtype") - if result.addrtype == AF_INET: - result.addrList = @[] - var i = 0 - while not isNil(s.h_addr_list[i]): - var inaddrPtr = cast[ptr InAddr](s.h_addr_list[i]) - result.addrList.add($inet_ntoa(inaddrPtr[])) - inc(i) - else: - result.addrList = cstringArrayToSeq(s.h_addr_list) - result.length = int(s.h_length) - - proc getHostname*(): string {.tags: [ReadIOEffect].} = - ## Returns the local hostname (not the FQDN) - # https://tools.ietf.org/html/rfc1035#section-2.3.1 - # https://tools.ietf.org/html/rfc2181#section-11 - const size = 256 - result = newString(size) - when useWinVersion: - let success = winlean.gethostname(result.cstring, size) - else: - # Posix - let success = posix.gethostname(result.cstring, size) - if success != 0.cint: - raiseOSError(osLastError()) - let x = len(cstring(result)) - result.setLen(x) - - proc getAddrString*(sockAddr: ptr SockAddr): string = - ## Returns the string representation of address within sockAddr - if sockAddr.sa_family.cint == nativeAfInet: - result = $inet_ntoa(cast[ptr Sockaddr_in](sockAddr).sin_addr) - elif sockAddr.sa_family.cint == nativeAfInet6: - let addrLen = when not useWinVersion: posix.INET6_ADDRSTRLEN.int - else: 46 # it's actually 46 in both cases - result = newString(addrLen) - let addr6 = addr cast[ptr Sockaddr_in6](sockAddr).sin6_addr - when not useWinVersion: - if posix.inet_ntop(posix.AF_INET6, addr6, cast[cstring](addr result[0]), - result.len.int32) == nil: - raiseOSError(osLastError()) - if posix.IN6_IS_ADDR_V4MAPPED(addr6) != 0: - result.setSlice("::ffff:".len..= Sockaddr_un_path_length: - raise newException(ValueError, "socket path too long") - copyMem(addr result.sun_path, path.cstring, path.len + 1) - - proc getSockName*(socket: SocketHandle): Port = - ## Returns the socket's associated port number. +proc getLocalAddr*(socket: SocketHandle, domain: Domain): (string, Port) = + ## returns the socket's local address and port number. + ## + ## Similar to POSIX's `getsockname`:idx:. + case domain + of AF_INET: var name: Sockaddr_in when useWinVersion: name.sin_family = uint16(ord(AF_INET)) else: name.sin_family = TSa_Family(posix.AF_INET) - #name.sin_port = htons(cint16(port)) - #name.sin_addr.s_addr = htonl(INADDR_ANY) var namelen = sizeof(name).SockLen if getsockname(socket, cast[ptr SockAddr](addr(name)), - addr(namelen)) == -1'i32: + addr(namelen)) == -1'i32: raiseOSError(osLastError()) - result = Port(nativesockets.ntohs(name.sin_port)) - - proc getLocalAddr*(socket: SocketHandle, domain: Domain): (string, Port) = - ## Returns the socket's local address and port number. - ## - ## Similar to POSIX's `getsockname`:idx:. - case domain - of AF_INET: - var name: Sockaddr_in - when useWinVersion: - name.sin_family = uint16(ord(AF_INET)) - else: - name.sin_family = TSa_Family(posix.AF_INET) - var namelen = sizeof(name).SockLen - if getsockname(socket, cast[ptr SockAddr](addr(name)), - addr(namelen)) == -1'i32: - raiseOSError(osLastError()) - result = ($inet_ntoa(name.sin_addr), - Port(nativesockets.ntohs(name.sin_port))) - of AF_INET6: - var name: Sockaddr_in6 - when useWinVersion: - name.sin6_family = uint16(ord(AF_INET6)) - else: - name.sin6_family = TSa_Family(posix.AF_INET6) - var namelen = sizeof(name).SockLen - if getsockname(socket, cast[ptr SockAddr](addr(name)), - addr(namelen)) == -1'i32: - raiseOSError(osLastError()) - # Cannot use INET6_ADDRSTRLEN here, because it's a C define. - result[0] = newString(64) - if inet_ntop(name.sin6_family.cint, - addr name.sin6_addr, cast[cstring](addr result[0][0]), (result[0].len+1).int32).isNil: - raiseOSError(osLastError()) - setLen(result[0], result[0].cstring.len) - result[1] = Port(nativesockets.ntohs(name.sin6_port)) + result = ($inet_ntoa(name.sin_addr), + Port(nativesockets.ntohs(name.sin_port))) + of AF_INET6: + var name: Sockaddr_in6 + when useWinVersion: + name.sin6_family = uint16(ord(AF_INET6)) else: - raiseOSError(OSErrorCode(-1), "invalid socket family in getLocalAddr") - - proc getPeerAddr*(socket: SocketHandle, domain: Domain): (string, Port) = - ## Returns the socket's peer address and port number. - ## - ## Similar to POSIX's `getpeername`:idx: - case domain - of AF_INET: - var name: Sockaddr_in - when useWinVersion: - name.sin_family = uint16(ord(AF_INET)) - else: - name.sin_family = TSa_Family(posix.AF_INET) - var namelen = sizeof(name).SockLen - if getpeername(socket, cast[ptr SockAddr](addr(name)), - addr(namelen)) == -1'i32: - raiseOSError(osLastError()) - result = ($inet_ntoa(name.sin_addr), - Port(nativesockets.ntohs(name.sin_port))) - of AF_INET6: - var name: Sockaddr_in6 - when useWinVersion: - name.sin6_family = uint16(ord(AF_INET6)) - else: - name.sin6_family = TSa_Family(posix.AF_INET6) - var namelen = sizeof(name).SockLen - if getpeername(socket, cast[ptr SockAddr](addr(name)), - addr(namelen)) == -1'i32: - raiseOSError(osLastError()) - # Cannot use INET6_ADDRSTRLEN here, because it's a C define. - result[0] = newString(64) - if inet_ntop(name.sin6_family.cint, - addr name.sin6_addr, cast[cstring](addr result[0][0]), (result[0].len+1).int32).isNil: - raiseOSError(osLastError()) - setLen(result[0], result[0].cstring.len) - result[1] = Port(nativesockets.ntohs(name.sin6_port)) - else: - raiseOSError(OSErrorCode(-1), "invalid socket family in getLocalAddr") - -when useNimNetLite: - - when useWinVersion: - const - INET_ADDRSTRLEN = 16 - INET6_ADDRSTRLEN = 46 # it's actually 46 in both cases - - proc sockAddrToStr(sa: ptr SockAddr): string {.noinit.} = - let af_family = sa.sa_family - var nl, v4Slice: cint - var si_addr: ptr InAddr - - if af_family == AF_INET.TSa_Family: - nl = INET_ADDRSTRLEN - si_addr = cast[ptr Sockaddr_in](sa).sin_addr.addr() - elif af_family == AF_INET6.TSa_Family: - nl = INET6_ADDRSTRLEN - let si6_addr = cast[ptr Sockaddr_in6](sa).sin6_addr.addr() - si_addr = cast[ptr InAddr](si6_addr) # let's us reuse logic below - when defined(posix) and not defined(nimdoc) and not defined(zephyr): - if posix.IN6_IS_ADDR_V4MAPPED(si6_addr) != 0: - v4Slice = "::ffff:".len() - else: - when defined(posix) and not defined(nimdoc): - if af_family.cint == nativeAfUnix: - return "unix" - return "" - - result = newString(nl) - let namePtr = result.cstring() - if namePtr == inet_ntop(af_family.cint, si_addr, namePtr, nl): - result.setLen(len(namePtr)) - if v4Slice > 0: result.setSlice(v4Slice.int ..< nl.int) - else: - return "" - - proc sockAddrToStr(sa: var Sockaddr_in | var Sockaddr_in6): string = - result = sockAddrToStr(cast[ptr SockAddr](unsafeAddr(sa))) - - proc getAddrString*(sockAddr: ptr SockAddr): string = - result = sockAddrToStr(sockAddr) - if result.len() == 0: + name.sin6_family = TSa_Family(posix.AF_INET6) + var namelen = sizeof(name).SockLen + if getsockname(socket, cast[ptr SockAddr](addr(name)), + addr(namelen)) == -1'i32: raiseOSError(osLastError()) + # Cannot use INET6_ADDRSTRLEN here, because it's a C define. + result[0] = newString(64) + if inet_ntop(name.sin6_family.cint, + addr name.sin6_addr, addr result[0][0], (result[0].len+1).int32).isNil: + raiseOSError(osLastError()) + setLen(result[0], result[0].cstring.len) + result[1] = Port(nativesockets.ntohs(name.sin6_port)) + else: + raiseOSError(OSErrorCode(-1), "invalid socket family in getLocalAddr") - proc getAddrString*(sockAddr: ptr SockAddr, strAddress: var string) {.noinit.} = - strAddress = getAddrString(sockAddr) - - proc getLocalAddr*(socket: SocketHandle, domain: Domain): (string, Port) = - ## Returns the socket's local address and port number. - ## - ## Similar to POSIX's `getsockname`:idx:. - template sockGetNameOrRaiseError(socket: untyped, name: untyped) = - var namelen = sizeof(socket).SockLen - if getsockname(socket, cast[ptr SockAddr](addr(name)), - addr(namelen)) == -1'i32: - raiseOSError(osLastError()) - - case domain - of AF_INET: - var name = Sockaddr_in(sin_family: TSa_Family(posix.AF_INET)) - sockGetNameOrRaiseError(socket, name) - result = (sockAddrToStr(name), - Port(nativesockets.ntohs(name.sin_port))) - of AF_INET6: - var name = Sockaddr_in6(sin6_family: TSa_Family(posix.AF_INET6)) - sockGetNameOrRaiseError(socket, name) - result = (sockAddrToStr(name), - Port(nativesockets.ntohs(name.sin6_port))) +proc getPeerAddr*(socket: SocketHandle, domain: Domain): (string, Port) = + ## returns the socket's peer address and port number. + ## + ## Similar to POSIX's `getpeername`:idx: + case domain + of AF_INET: + var name: Sockaddr_in + when useWinVersion: + name.sin_family = uint16(ord(AF_INET)) else: - raiseOSError(OSErrorCode(-1), "invalid socket family in getLocalAddr") - + name.sin_family = TSa_Family(posix.AF_INET) + var namelen = sizeof(name).SockLen + if getpeername(socket, cast[ptr SockAddr](addr(name)), + addr(namelen)) == -1'i32: + raiseOSError(osLastError()) + result = ($inet_ntoa(name.sin_addr), + Port(nativesockets.ntohs(name.sin_port))) + of AF_INET6: + var name: Sockaddr_in6 + when useWinVersion: + name.sin6_family = uint16(ord(AF_INET6)) + else: + name.sin6_family = TSa_Family(posix.AF_INET6) + var namelen = sizeof(name).SockLen + if getpeername(socket, cast[ptr SockAddr](addr(name)), + addr(namelen)) == -1'i32: + raiseOSError(osLastError()) + # Cannot use INET6_ADDRSTRLEN here, because it's a C define. + result[0] = newString(64) + if inet_ntop(name.sin6_family.cint, + addr name.sin6_addr, addr result[0][0], (result[0].len+1).int32).isNil: + raiseOSError(osLastError()) + setLen(result[0], result[0].cstring.len) + result[1] = Port(nativesockets.ntohs(name.sin6_port)) + else: + raiseOSError(OSErrorCode(-1), "invalid socket family in getLocalAddr") proc getSockOptInt*(socket: SocketHandle, level, optname: int): int {. tags: [ReadIOEffect].} = @@ -764,12 +610,12 @@ proc pruneSocketSet(s: var seq[SocketHandle], fd: var TFdSet) = setLen(s, L) proc selectRead*(readfds: var seq[SocketHandle], timeout = 500): int = - ## When a socket in `readfds` is ready to be read from then a non-zero + ## When a socket in ``readfds`` is ready to be read from then a non-zero ## value will be returned specifying the count of the sockets which can be - ## read from. The sockets which cannot be read from will also be removed - ## from `readfds`. + ## read from. The sockets which can be read from will also be removed + ## from ``readfds``. ## - ## `timeout` is specified in milliseconds and `-1` can be specified for + ## ``timeout`` is specified in milliseconds and ``-1`` can be specified for ## an unlimited time. var tv {.noinit.}: Timeval = timeValFromMilliseconds(timeout) @@ -786,12 +632,12 @@ proc selectRead*(readfds: var seq[SocketHandle], timeout = 500): int = proc selectWrite*(writefds: var seq[SocketHandle], timeout = 500): int {.tags: [ReadIOEffect].} = - ## When a socket in `writefds` is ready to be written to then a non-zero + ## When a socket in ``writefds`` is ready to be written to then a non-zero ## value will be returned specifying the count of the sockets which can be - ## written to. The sockets which cannot be written to will also be removed - ## from `writefds`. + ## written to. The sockets which can be written to will also be removed + ## from ``writefds``. ## - ## `timeout` is specified in milliseconds and `-1` can be specified for + ## ``timeout`` is specified in milliseconds and ``-1`` can be specified for ## an unlimited time. var tv {.noinit.}: Timeval = timeValFromMilliseconds(timeout) @@ -806,34 +652,19 @@ proc selectWrite*(writefds: var seq[SocketHandle], pruneSocketSet(writefds, (wr)) -proc accept*(fd: SocketHandle, inheritable = defined(nimInheritHandles)): (SocketHandle, string) = +proc accept*(fd: SocketHandle): (SocketHandle, string) = ## Accepts a new client connection. ## - ## `inheritable` decides if the resulting SocketHandle can be inherited by - ## child processes. - ## ## Returns (osInvalidSocket, "") if an error occurred. - var sockAddress: SockAddr + var sockAddress: Sockaddr_in var addrLen = sizeof(sockAddress).SockLen - var sock = - when (defined(linux) or defined(bsd)) and not defined(nimdoc): - accept4(fd, addr(sockAddress), addr(addrLen), - if inheritable: 0 else: SOCK_CLOEXEC) - else: - accept(fd, addr(sockAddress), addr(addrLen)) - when declared(setInheritable) and not (defined(linux) or defined(bsd)): - if not setInheritable(sock, inheritable): - close sock - sock = osInvalidSocket + var sock = accept(fd, cast[ptr SockAddr](addr(sockAddress)), + addr(addrLen)) if sock == osInvalidSocket: return (osInvalidSocket, "") else: - when useNimNetLite: - var name = sockAddrToStr(addr sockAddress) - return (sock, name) - else: - return (sock, $inet_ntoa(cast[Sockaddr_in](sockAddress).sin_addr)) + return (sock, $inet_ntoa(sockAddress.sin_addr)) -when defined(windows): +when defined(Windows): var wsa: WSAData if wsaStartup(0x0101'i16, addr wsa) != 0: raiseOSError(osLastError()) diff --git a/lib/pure/net.nim b/lib/pure/net.nim index d3a767eed..0d4440242 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -9,31 +9,18 @@ ## This module implements a high-level cross-platform sockets interface. ## The procedures implemented in this module are primarily for blocking sockets. -## For asynchronous non-blocking sockets use the `asyncnet` module together -## with the `asyncdispatch` module. +## For asynchronous non-blocking sockets use the ``asyncnet`` module together +## with the ``asyncdispatch`` module. ## ## The first thing you will always need to do in order to start using sockets, -## is to create a new instance of the `Socket` type using the `newSocket` +## is to create a new instance of the ``Socket`` type using the ``newSocket`` ## procedure. ## ## SSL ## ==== ## ## In order to use the SSL procedures defined in this module, you will need to -## compile your application with the `-d:ssl` flag. See the -## `newContext`_ -## procedure for additional details. -## -## -## SSL on Windows -## ============== -## -## On Windows the SSL library checks for valid certificates. -## It uses the `cacert.pem` file for this purpose which was extracted -## from `https://curl.se/ca/cacert.pem`. Besides -## the OpenSSL DLLs (e.g. libssl-1_1-x64.dll, libcrypto-1_1-x64.dll) you -## also need to ship `cacert.pem` with your `.exe` file. -## +## compile your application with the ``-d:ssl`` flag. ## ## Examples ## ======== @@ -41,87 +28,62 @@ ## Connecting to a server ## ---------------------- ## -## After you create a socket with the `newSocket` procedure, you can easily +## After you create a socket with the ``newSocket`` procedure, you can easily ## connect it to a server running at a known hostname (or IP address) and port. ## To do so over TCP, use the example below. - -runnableExamples("-r:off"): - let socket = newSocket() - socket.connect("google.com", Port(80)) - -## For SSL, use the following example: - -runnableExamples("-r:off -d:ssl"): - let socket = newSocket() - let ctx = newContext() - wrapSocket(ctx, socket) - socket.connect("google.com", Port(443)) - +## +## .. code-block:: Nim +## var socket = newSocket() +## socket.connect("google.com", Port(80)) +## ## UDP is a connectionless protocol, so UDP sockets don't have to explicitly -## call the `connect `_ procedure. They can -## simply start sending data immediately. - -runnableExamples("-r:off"): - let socket = newSocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP) - socket.sendTo("192.168.0.1", Port(27960), "status\n") - -runnableExamples("-r:off"): - let socket = newSocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP) - let ip = parseIpAddress("192.168.0.1") - doAssert socket.sendTo(ip, Port(27960), "status\c\l") == 8 - +## call the ``connect`` procedure. They can simply start sending data +## immediately. +## +## .. code-block:: Nim +## var socket = newSocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP) +## socket.sendTo("192.168.0.1", Port(27960), "status\n") +## ## Creating a server ## ----------------- ## -## After you create a socket with the `newSocket` procedure, you can create a -## TCP server by calling the `bindAddr` and `listen` procedures. +## After you create a socket with the ``newSocket`` procedure, you can create a +## TCP server by calling the ``bindAddr`` and ``listen`` procedures. +## +## .. code-block:: Nim +## var socket = newSocket() +## socket.bindAddr(Port(1234)) +## socket.listen() +## +## You can then begin accepting connections using the ``accept`` procedure. +## +## .. code-block:: Nim +## var client: Socket +## var address = "" +## while true: +## socket.acceptAddr(client, address) +## echo("Client connected from: ", address) -runnableExamples("-r:off"): - let socket = newSocket() - socket.bindAddr(Port(1234)) - socket.listen() - - # You can then begin accepting connections using the `accept` procedure. - var client: Socket - var address = "" - while true: - socket.acceptAddr(client, address) - echo "Client connected from: ", address - -import std/private/since - -when defined(nimPreviewSlimSystem): - import std/assertions - -import nativesockets -import os, strutils, times, sets, options, std/monotimes -import ssl_config +{.deadCodeElim: on.} # dce option deprecated +import nativesockets, os, strutils, parseutils, times, sets, options, + std/monotimes export nativesockets.Port, nativesockets.`$`, nativesockets.`==` export Domain, SockType, Protocol -const useWinVersion = defined(windows) or defined(nimdoc) -const useNimNetLite = defined(nimNetLite) or defined(freertos) or defined(zephyr) or - defined(nuttx) +const useWinVersion = defined(Windows) or defined(nimdoc) const defineSsl = defined(ssl) or defined(nimdoc) -when useWinVersion: - from winlean import WSAESHUTDOWN - when defineSsl: import openssl - when not defined(nimDisableCertificateValidation): - from ssl_certs import scanSSLCertificates # Note: The enumerations are mapped to Window's constants. when defineSsl: type - Certificate* = string ## DER encoded certificate - - SslError* = object of CatchableError + SslError* = object of Exception SslCVerifyMode* = enum - CVerifyNone, CVerifyPeer, CVerifyPeerUseEnvVars + CVerifyNone, CVerifyPeer SslProtVersion* = enum protSSLv2, protSSLv3, protTLSv1, protSSLv23 @@ -147,7 +109,7 @@ when defineSsl: else: type - SslContext* = ref object # TODO: Workaround #4797. + SslContext* = void # TODO: Workaround #4797. const BufferSize*: int = 4000 ## size of a buffered socket's buffer @@ -167,7 +129,6 @@ type sslNoHandshake: bool # True if needs handshake. sslHasPeekChar: bool sslPeekChar: char - sslNoShutdown: bool # True if shutdown shouldn't be done. lastError: OSErrorCode ## stores the last error on this socket domain: Domain sockType: SockType @@ -182,7 +143,7 @@ type ReadLineResult* = enum ## result for readLineAsync ReadFullLine, ReadPartialLine, ReadDisconnected, ReadNone - TimeoutError* = object of CatchableError + TimeoutError* = object of Exception SocketFlag* {.pure.} = enum Peek, @@ -207,51 +168,20 @@ type when defined(nimHasStyleChecks): {.pop.} - -when defined(posix) and not defined(lwip): - from posix import TPollfd, POLLIN, POLLPRI, POLLOUT, POLLWRBAND, Tnfds - - template monitorPollEvent(x: var SocketHandle, y: cint, timeout: int): int = - var tpollfd: TPollfd - tpollfd.fd = cast[cint](x) - tpollfd.events = y - posix.poll(addr(tpollfd), Tnfds(1), timeout) - -proc timeoutRead(fd: var SocketHandle, timeout = 500): int = - when defined(windows) or defined(lwip): - var fds = @[fd] - selectRead(fds, timeout) - else: - monitorPollEvent(fd, POLLIN or POLLPRI, timeout) - -proc timeoutWrite(fd: var SocketHandle, timeout = 500): int = - when defined(windows) or defined(lwip): - var fds = @[fd] - selectWrite(fds, timeout) - else: - monitorPollEvent(fd, POLLOUT or POLLWRBAND, timeout) - proc socketError*(socket: Socket, err: int = -1, async = false, - lastError = (-1).OSErrorCode, - flags: set[SocketFlag] = {}) {.gcsafe.} + lastError = (-1).OSErrorCode): void {.gcsafe.} proc isDisconnectionError*(flags: set[SocketFlag], lastError: OSErrorCode): bool = - ## Determines whether `lastError` is a disconnection error. Only does this - ## if flags contains `SafeDisconn`. + ## Determines whether ``lastError`` is a disconnection error. Only does this + ## if flags contains ``SafeDisconn``. when useWinVersion: SocketFlag.SafeDisconn in flags and - (lastError.int32 == WSAECONNRESET or - lastError.int32 == WSAECONNABORTED or - lastError.int32 == WSAENETRESET or - lastError.int32 == WSAEDISCON or - lastError.int32 == WSAESHUTDOWN or - lastError.int32 == ERROR_NETNAME_DELETED) + lastError.int32 in {WSAECONNRESET, WSAECONNABORTED, WSAENETRESET, + WSAEDISCON, ERROR_NETNAME_DELETED} else: SocketFlag.SafeDisconn in flags and - (lastError.int32 == ECONNRESET or - lastError.int32 == EPIPE or - lastError.int32 == ENETRESET) + lastError.int32 in {ECONNRESET, EPIPE, ENETRESET} proc toOSFlags*(socketFlags: set[SocketFlag]): cint = ## Converts the flags into the underlying OS representation. @@ -279,32 +209,22 @@ proc newSocket*(fd: SocketHandle, domain: Domain = AF_INET, when defined(macosx) and not defined(nimdoc): setSockOptInt(fd, SOL_SOCKET, SO_NOSIGPIPE, 1) -proc newSocket*(domain, sockType, protocol: cint, buffered = true, - inheritable = defined(nimInheritHandles)): owned(Socket) = +proc newSocket*(domain, sockType, protocol: cint, buffered = true): owned(Socket) = ## Creates a new socket. ## - ## The SocketHandle associated with the resulting Socket will not be - ## inheritable by child processes by default. This can be changed via - ## the `inheritable` parameter. - ## ## If an error occurs OSError will be raised. - let fd = createNativeSocket(domain, sockType, protocol, inheritable) + let fd = createNativeSocket(domain, sockType, protocol) if fd == osInvalidSocket: raiseOSError(osLastError()) result = newSocket(fd, domain.Domain, sockType.SockType, protocol.Protocol, buffered) proc newSocket*(domain: Domain = AF_INET, sockType: SockType = SOCK_STREAM, - protocol: Protocol = IPPROTO_TCP, buffered = true, - inheritable = defined(nimInheritHandles)): owned(Socket) = + protocol: Protocol = IPPROTO_TCP, buffered = true): owned(Socket) = ## Creates a new socket. ## - ## The SocketHandle associated with the resulting Socket will not be - ## inheritable by child processes by default. This can be changed via - ## the `inheritable` parameter. - ## ## If an error occurs OSError will be raised. - let fd = createNativeSocket(domain, sockType, protocol, inheritable) + let fd = createNativeSocket(domain, sockType, protocol) if fd == osInvalidSocket: raiseOSError(osLastError()) result = newSocket(fd, domain, sockType, protocol, buffered) @@ -316,20 +236,14 @@ proc parseIPv4Address(addressStr: string): IpAddress = byteCount = 0 currentByte: uint16 = 0 separatorValid = false - leadingZero = false result = IpAddress(family: IpAddressFamily.IPv4) for i in 0 .. high(addressStr): if addressStr[i] in strutils.Digits: # Character is a number - if leadingZero: - raise newException(ValueError, - "Invalid IP address. Octal numbers are not allowed") currentByte = currentByte * 10 + cast[uint16](ord(addressStr[i]) - ord('0')) - if currentByte == 0'u16: - leadingZero = true - elif currentByte > 255'u16: + if currentByte > 255'u16: raise newException(ValueError, "Invalid IP Address. Value is out of range") separatorValid = true @@ -341,7 +255,6 @@ proc parseIPv4Address(addressStr: string): IpAddress = currentByte = 0 byteCount.inc separatorValid = false - leadingZero = false else: raise newException(ValueError, "Invalid IP Address. Address contains an invalid character") @@ -430,16 +343,10 @@ proc parseIPv6Address(addressStr: string): IpAddress = result.address_v6[groupCount*2+1] = cast[uint8](currentShort and 0xFF) groupCount.inc() else: # Must parse IPv4 address - var leadingZero = false for i, c in addressStr[v4StartPos..high(addressStr)]: if c in strutils.Digits: # Character is a number - if leadingZero: - raise newException(ValueError, - "Invalid IP address. Octal numbers not allowed") currentShort = currentShort * 10 + cast[uint32](ord(c) - ord('0')) - if currentShort == 0'u32: - leadingZero = true - elif currentShort > 255'u32: + if currentShort > 255'u32: raise newException(ValueError, "Invalid IP Address. Value is out of range") separatorValid = true @@ -450,7 +357,6 @@ proc parseIPv6Address(addressStr: string): IpAddress = currentShort = 0 byteCount.inc() separatorValid = false - leadingZero = false else: # Invalid character raise newException(ValueError, "Invalid IP Address. Address contains an invalid character") @@ -480,12 +386,7 @@ proc parseIPv6Address(addressStr: string): IpAddress = proc parseIpAddress*(addressStr: string): IpAddress = ## Parses an IP address - ## - ## Raises ValueError on error. - ## - ## For IPv4 addresses, only the strict form as - ## defined in RFC 6943 is considered valid, see - ## https://datatracker.ietf.org/doc/html/rfc6943#section-3.1.1. + ## Raises ValueError on error if addressStr.len == 0: raise newException(ValueError, "IP Address string is empty") if addressStr.contains(':'): @@ -510,14 +411,14 @@ proc toSockAddr*(address: IpAddress, port: Port, sa: var Sockaddr_storage, of IpAddressFamily.IPv4: sl = sizeof(Sockaddr_in).SockLen let s = cast[ptr Sockaddr_in](addr sa) - s.sin_family = typeof(s.sin_family)(toInt(AF_INET)) + s.sin_family = type(s.sin_family)(toInt(AF_INET)) s.sin_port = port copyMem(addr s.sin_addr, unsafeAddr address.address_v4[0], sizeof(s.sin_addr)) of IpAddressFamily.IPv6: sl = sizeof(Sockaddr_in6).SockLen let s = cast[ptr Sockaddr_in6](addr sa) - s.sin6_family = typeof(s.sin6_family)(toInt(AF_INET6)) + s.sin6_family = type(s.sin6_family)(toInt(AF_INET6)) s.sin6_port = port copyMem(addr s.sin6_addr, unsafeAddr address.address_v6[0], sizeof(s.sin6_addr)) @@ -543,30 +444,25 @@ proc fromSockAddrAux(sa: ptr Sockaddr_storage, sl: SockLen, proc fromSockAddr*(sa: Sockaddr_storage | SockAddr | Sockaddr_in | Sockaddr_in6, sl: SockLen, address: var IpAddress, port: var Port) {.inline.} = ## Converts `SockAddr` and `SockLen` to `IpAddress` and `Port`. Raises - ## `ObjectConversionDefect` in case of invalid `sa` and `sl` arguments. + ## `ObjectConversionError` in case of invalid `sa` and `sl` arguments. fromSockAddrAux(cast[ptr Sockaddr_storage](unsafeAddr sa), sl, address, port) when defineSsl: - # OpenSSL >= 1.1.0 does not need explicit init. - when not useOpenssl3: - CRYPTO_malloc_init() - doAssert SslLibraryInit() == 1 - SSL_load_error_strings() - ERR_load_BIO_strings() - OpenSSL_add_all_algorithms() + CRYPTO_malloc_init() + doAssert SslLibraryInit() == 1 + SSL_load_error_strings() + ERR_load_BIO_strings() + OpenSSL_add_all_algorithms() - proc sslHandle*(self: Socket): SslPtr = - ## Retrieve the ssl pointer of `socket`. - ## Useful for interfacing with `openssl`. - self.sslHandle - - proc raiseSSLError*(s = "") {.raises: [SslError].}= + proc raiseSSLError*(s = "") = ## Raises a new SSL error. if s != "": raise newException(SslError, s) let err = ERR_peek_last_error() if err == 0: raise newException(SslError, "No error reported.") + if err == -1: + raiseOSError(osLastError()) var errStr = $ERR_error_string(err, nil) case err of 336032814, 336032784: @@ -579,7 +475,7 @@ when defineSsl: proc getExtraData*(ctx: SslContext, index: int): RootRef = ## Retrieves arbitrary data stored inside SslContext. if index notin ctx.referencedData: - raise newException(IndexDefect, "No data with that index.") + raise newException(IndexError, "No data with that index.") let res = ctx.context.SSL_CTX_get_ex_data(index.cint) if cast[int](res) == 0: raiseSSLError() @@ -600,10 +496,10 @@ when defineSsl: # http://simplestcodings.blogspot.co.uk/2010/08/secure-server-client-using-openssl-in-c.html proc loadCertificates(ctx: SslCtx, certFile, keyFile: string) = - if certFile != "" and not fileExists(certFile): + if certFile != "" and not existsFile(certFile): raise newException(system.IOError, "Certificate file could not be found: " & certFile) - if keyFile != "" and not fileExists(keyFile): + if keyFile != "" and not existsFile(keyFile): raise newException(system.IOError, "Key file could not be found: " & keyFile) if certFile != "": @@ -621,115 +517,51 @@ when defineSsl: raiseSSLError("Verification of private key file failed.") proc newContext*(protVersion = protSSLv23, verifyMode = CVerifyPeer, - certFile = "", keyFile = "", cipherList = CiphersIntermediate, - caDir = "", caFile = "", ciphersuites = CiphersModern): SslContext = + certFile = "", keyFile = "", cipherList = "ALL"): SslContext = ## Creates an SSL context. ## - ## Protocol version is currently ignored by default and TLS is used. - ## With `-d:openssl10`, only SSLv23 and TLSv1 may be used. + ## Protocol version specifies the protocol to use. SSLv2, SSLv3, TLSv1 + ## are available with the addition of ``protSSLv23`` which allows for + ## compatibility with all of them. ## - ## There are three options for verify mode: - ## `CVerifyNone`: certificates are not verified; - ## `CVerifyPeer`: certificates are verified; - ## `CVerifyPeerUseEnvVars`: certificates are verified and the optional - ## environment variables SSL_CERT_FILE and SSL_CERT_DIR are also used to - ## locate certificates - ## - ## The `nimDisableCertificateValidation` define overrides verifyMode and - ## disables certificate verification globally! - ## - ## CA certificates will be loaded, in the following order, from: - ## - ## - caFile, caDir, parameters, if set - ## - if `verifyMode` is set to `CVerifyPeerUseEnvVars`, - ## the SSL_CERT_FILE and SSL_CERT_DIR environment variables are used - ## - a set of files and directories from the `ssl_certs `_ file. + ## There are currently only two options for verify mode; + ## one is ``CVerifyNone`` and with it certificates will not be verified + ## the other is ``CVerifyPeer`` and certificates will be verified for + ## it, ``CVerifyPeer`` is the safest choice. ## ## The last two parameters specify the certificate file path and the key file ## path, a server socket will most likely not work without these. ## ## Certificates can be generated using the following command: - ## - `openssl req -x509 -nodes -days 365 -newkey rsa:4096 -keyout mykey.pem -out mycert.pem` + ## - ``openssl req -x509 -nodes -days 365 -newkey rsa:4096 -keyout mykey.pem -out mycert.pem`` ## or using ECDSA: - ## - `openssl ecparam -out mykey.pem -name secp256k1 -genkey` - ## - `openssl req -new -key mykey.pem -x509 -nodes -days 365 -out mycert.pem` - var mtd: PSSL_METHOD - when defined(openssl10): - case protVersion - of protSSLv23: - mtd = SSLv23_method() - of protSSLv2: - raiseSSLError("SSLv2 is no longer secure and has been deprecated, use protSSLv23") - of protSSLv3: - raiseSSLError("SSLv3 is no longer secure and has been deprecated, use protSSLv23") - of protTLSv1: - mtd = TLSv1_method() - else: - mtd = TLS_method() - if mtd == nil: - raiseSSLError("Failed to create TLS context") - var newCTX = SSL_CTX_new(mtd) - if newCTX == nil: - raiseSSLError("Failed to create TLS context") + ## - ``openssl ecparam -out mykey.pem -name secp256k1 -genkey`` + ## - ``openssl req -new -key mykey.pem -x509 -nodes -days 365 -out mycert.pem`` + var newCTX: SslCtx + case protVersion + of protSSLv23: + newCTX = SSL_CTX_new(SSLv23_method()) # SSlv2,3 and TLS1 support. + of protSSLv2: + raiseSSLError("SSLv2 is no longer secure and has been deprecated, use protSSLv23") + of protSSLv3: + raiseSSLError("SSLv3 is no longer secure and has been deprecated, use protSSLv23") + of protTLSv1: + newCTX = SSL_CTX_new(TLSv1_method()) if newCTX.SSL_CTX_set_cipher_list(cipherList) != 1: raiseSSLError() - when not defined(openssl10) and not defined(libressl): - let sslVersion = getOpenSSLVersion() - if sslVersion >= 0x010101000 and sslVersion != 0x020000000: - # In OpenSSL >= 1.1.1, TLSv1.3 cipher suites can only be configured via - # this API. - if newCTX.SSL_CTX_set_ciphersuites(ciphersuites) != 1: - raiseSSLError() - # Automatically the best ECDH curve for client exchange. Without this, ECDH - # ciphers will be ignored by the server. - # - # From OpenSSL >= 1.1.0, this setting is set by default and can't be - # overriden. - if newCTX.SSL_CTX_set_ecdh_auto(1) != 1: - raiseSSLError() - - when defined(nimDisableCertificateValidation): + case verifyMode + of CVerifyPeer: + newCTX.SSL_CTX_set_verify(SSL_VERIFY_PEER, nil) + of CVerifyNone: newCTX.SSL_CTX_set_verify(SSL_VERIFY_NONE, nil) - else: - case verifyMode - of CVerifyPeer, CVerifyPeerUseEnvVars: - newCTX.SSL_CTX_set_verify(SSL_VERIFY_PEER, nil) - of CVerifyNone: - newCTX.SSL_CTX_set_verify(SSL_VERIFY_NONE, nil) - if newCTX == nil: raiseSSLError() discard newCTX.SSLCTXSetMode(SSL_MODE_AUTO_RETRY) newCTX.loadCertificates(certFile, keyFile) - const VerifySuccess = 1 # SSL_CTX_load_verify_locations returns 1 on success. - - when not defined(nimDisableCertificateValidation): - if verifyMode != CVerifyNone: - # Use the caDir and caFile parameters if set - if caDir != "" or caFile != "": - if newCTX.SSL_CTX_load_verify_locations(if caFile == "": nil else: caFile.cstring, if caDir == "": nil else: caDir.cstring) != VerifySuccess: - raise newException(IOError, "Failed to load SSL/TLS CA certificate(s).") - - else: - # Scan for certs in known locations. For CVerifyPeerUseEnvVars also scan - # the SSL_CERT_FILE and SSL_CERT_DIR env vars - var found = false - let useEnvVars = (if verifyMode == CVerifyPeerUseEnvVars: true else: false) - for fn in scanSSLCertificates(useEnvVars = useEnvVars): - if fn.extractFilename == "": - if newCTX.SSL_CTX_load_verify_locations(nil, cstring(fn.normalizePathEnd(false))) == VerifySuccess: - found = true - break - elif newCTX.SSL_CTX_load_verify_locations(cstring(fn), nil) == VerifySuccess: - found = true - break - if not found: - raise newException(IOError, "No SSL/TLS CA certificates found.") - - result = SslContext(context: newCTX, referencedData: initHashSet[int](), + result = SslContext(context: newCTX, referencedData: initSet[int](), extraInternal: new(SslContextExtraInternal)) proc getExtraInternal(ctx: SslContext): SslContextExtraInternal = @@ -742,7 +574,7 @@ when defineSsl: # That means we can assume that the next internal index is the length of # extra data indexes. for i in ctx.referencedData: - GC_unref(getExtraData(ctx, i)) + GC_unref(getExtraData(ctx, i).RootRef) ctx.context.SSL_CTX_free() proc `pskIdentityHint=`*(ctx: SslContext, hint: string) = @@ -756,16 +588,17 @@ when defineSsl: return ctx.getExtraInternal().clientGetPskFunc proc pskClientCallback(ssl: SslPtr; hint: cstring; identity: cstring; - max_identity_len: cuint; psk: ptr uint8; + max_identity_len: cuint; psk: ptr cuchar; max_psk_len: cuint): cuint {.cdecl.} = let ctx = SslContext(context: ssl.SSL_get_SSL_CTX) let hintString = if hint == nil: "" else: $hint let (identityString, pskString) = (ctx.clientGetPskFunc)(hintString) - if pskString.len.cuint > max_psk_len: + if psk.len.cuint > max_psk_len: return 0 if identityString.len.cuint >= max_identity_len: return 0 - copyMem(identity, identityString.cstring, identityString.len + 1) # with the last zero byte + + copyMem(identity, identityString.cstring, pskString.len + 1) # with the last zero byte copyMem(psk, pskString.cstring, pskString.len) return pskString.len.cuint @@ -782,11 +615,11 @@ when defineSsl: proc serverGetPskFunc*(ctx: SslContext): SslServerGetPskFunc = return ctx.getExtraInternal().serverGetPskFunc - proc pskServerCallback(ssl: SslCtx; identity: cstring; psk: ptr uint8; + proc pskServerCallback(ssl: SslCtx; identity: cstring; psk: ptr cuchar; max_psk_len: cint): cuint {.cdecl.} = let ctx = SslContext(context: ssl.SSL_get_SSL_CTX) let pskString = (ctx.serverGetPskFunc)($identity) - if pskString.len.cint > max_psk_len: + if psk.len.cint > max_psk_len: return 0 copyMem(psk, pskString.cstring, pskString.len) @@ -807,12 +640,11 @@ when defineSsl: proc wrapSocket*(ctx: SslContext, socket: Socket) = ## Wraps a socket in an SSL context. This function effectively turns - ## `socket` into an SSL socket. + ## ``socket`` into an SSL socket. ## ## This must be called on an unconnected socket; an SSL session will ## be started when the socket is connected. ## - ## FIXME: ## **Disclaimer**: This code is not well tested, may be very unsafe and ## prone to security vulnerabilities. @@ -822,48 +654,23 @@ when defineSsl: socket.sslHandle = SSL_new(socket.sslContext.context) socket.sslNoHandshake = false socket.sslHasPeekChar = false - socket.sslNoShutdown = false if socket.sslHandle == nil: raiseSSLError() if SSL_set_fd(socket.sslHandle, socket.fd) != 1: raiseSSLError() - proc checkCertName(socket: Socket, hostname: string) {.raises: [SslError], tags:[RootEffect].} = - ## Check if the certificate Subject Alternative Name (SAN) or Subject CommonName (CN) matches hostname. - ## Wildcards match only in the left-most label. - ## When name starts with a dot it will be matched by a certificate valid for any subdomain - when not defined(nimDisableCertificateValidation) and not defined(windows): - assert socket.isSsl - try: - let certificate = socket.sslHandle.SSL_get_peer_certificate() - if certificate.isNil: - raiseSSLError("No SSL certificate found.") - - const X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT = 0x1.cuint - # https://www.openssl.org/docs/man1.1.1/man3/X509_check_host.html - let match = certificate.X509_check_host(hostname.cstring, hostname.len.cint, - X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT, nil) - # https://www.openssl.org/docs/man1.1.1/man3/SSL_get_peer_certificate.html - X509_free(certificate) - if match != 1: - raiseSSLError("SSL Certificate check failed.") - - except LibraryError: - raiseSSLError("SSL import failed") - proc wrapConnectedSocket*(ctx: SslContext, socket: Socket, handshake: SslHandshakeType, hostname: string = "") = ## Wraps a connected socket in an SSL context. This function effectively - ## turns `socket` into an SSL socket. - ## `hostname` should be specified so that the client knows which hostname + ## turns ``socket`` into an SSL socket. + ## ``hostname`` should be specified so that the client knows which hostname ## the server certificate should be validated against. ## ## This should be called on a connected socket, and will perform ## an SSL handshake immediately. ## - ## FIXME: ## **Disclaimer**: This code is not well tested, may be very unsafe and ## prone to security vulnerabilities. wrapSocket(ctx, socket) @@ -873,66 +680,14 @@ when defineSsl: # Discard result in case OpenSSL version doesn't support SNI, or we're # not using TLSv1+ discard SSL_set_tlsext_host_name(socket.sslHandle, hostname) - ErrClearError() let ret = SSL_connect(socket.sslHandle) socketError(socket, ret) - when not defined(nimDisableCertificateValidation) and not defined(windows): - # FIXME: this should be skipped on CVerifyNone - if hostname.len > 0 and not isIpAddress(hostname): - socket.checkCertName(hostname) of handshakeAsServer: - ErrClearError() let ret = SSL_accept(socket.sslHandle) socketError(socket, ret) - proc getPeerCertificates*(sslHandle: SslPtr): seq[Certificate] {.since: (1, 1).} = - ## Returns the certificate chain received by the peer we are connected to - ## through the OpenSSL connection represented by `sslHandle`. - ## The handshake must have been completed and the certificate chain must - ## have been verified successfully or else an empty sequence is returned. - ## The chain is ordered from leaf certificate to root certificate. - result = newSeq[Certificate]() - if SSL_get_verify_result(sslHandle) != X509_V_OK: - return - let stack = SSL_get0_verified_chain(sslHandle) - if stack == nil: - return - let length = OPENSSL_sk_num(stack) - if length == 0: - return - for i in 0 .. length - 1: - let x509 = cast[PX509](OPENSSL_sk_value(stack, i)) - result.add(i2d_X509(x509)) - - proc getPeerCertificates*(socket: Socket): seq[Certificate] {.since: (1, 1).} = - ## Returns the certificate chain received by the peer we are connected to - ## through the given socket. - ## The handshake must have been completed and the certificate chain must - ## have been verified successfully or else an empty sequence is returned. - ## The chain is ordered from leaf certificate to root certificate. - if not socket.isSsl: - result = newSeq[Certificate]() - else: - result = getPeerCertificates(socket.sslHandle) - - proc `sessionIdContext=`*(ctx: SslContext, sidCtx: string) = - ## Sets the session id context in which a session can be reused. - ## Used for permitting clients to reuse a session id instead of - ## doing a new handshake. - ## - ## TLS clients might attempt to resume a session using the session id context, - ## thus it must be set if verifyMode is set to CVerifyPeer or CVerifyPeerUseEnvVars, - ## otherwise the connection will fail and SslError will be raised if resumption occurs. - ## - ## - Only useful if set server-side. - ## - Should be unique per-application to prevent clients from malfunctioning. - ## - sidCtx must be at most 32 characters in length. - if sidCtx.len > 32: - raiseSSLError("sessionIdContext must be shorter than 32 characters") - SSL_CTX_set_session_id_context(ctx.context, sidCtx, sidCtx.len) - proc getSocketError*(socket: Socket): OSErrorCode = - ## Checks `osLastError` for a valid error. If it has been reset it uses + ## Checks ``osLastError`` for a valid error. If it has been reset it uses ## the last error stored in the socket object. result = osLastError() if result == 0.OSErrorCode: @@ -941,18 +696,14 @@ proc getSocketError*(socket: Socket): OSErrorCode = raiseOSError(result, "No valid socket error code available") proc socketError*(socket: Socket, err: int = -1, async = false, - lastError = (-1).OSErrorCode, - flags: set[SocketFlag] = {}) = - ## Raises an OSError based on the error code returned by `SSL_get_error` - ## (for SSL sockets) and `osLastError` otherwise. + lastError = (-1).OSErrorCode) = + ## Raises an OSError based on the error code returned by ``SSL_get_error`` + ## (for SSL sockets) and ``osLastError`` otherwise. ## - ## If `async` is `true` no error will be thrown in the case when the + ## If ``async`` is ``true`` no error will be thrown in the case when the ## error was caused by no data being available to be read. ## - ## If `err` is not lower than 0 no exception will be raised. - ## - ## If `flags` contains `SafeDisconn`, no exception will be raised - ## when the error was caused by a peer disconnection. + ## If ``err`` is not lower than 0 no exception will be raised. when defineSsl: if socket.isSsl: if err <= 0: @@ -971,43 +722,37 @@ proc socketError*(socket: Socket, err: int = -1, async = false, of SSL_ERROR_WANT_X509_LOOKUP: raiseSSLError("Function for x509 lookup has been called.") of SSL_ERROR_SYSCALL: - # SSL shutdown must not be done if a fatal error occurred. - socket.sslNoShutdown = true + var errStr = "IO error has occurred " + let sslErr = ERR_peek_last_error() + if sslErr == 0 and err == 0: + errStr.add "because an EOF was observed that violates the protocol" + elif sslErr == 0 and err == -1: + errStr.add "in the BIO layer" + else: + let errStr = $ERR_error_string(sslErr, nil) + raiseSSLError(errStr & ": " & errStr) let osErr = osLastError() - if not flags.isDisconnectionError(osErr): - var errStr = "IO error has occurred " - let sslErr = ERR_peek_last_error() - if sslErr == 0 and err == 0: - errStr.add "because an EOF was observed that violates the protocol" - elif sslErr == 0 and err == -1: - errStr.add "in the BIO layer" - else: - let errStr = $ERR_error_string(sslErr, nil) - raiseSSLError(errStr & ": " & errStr) - raiseOSError(osErr, errStr) + raiseOSError(osErr, errStr) of SSL_ERROR_SSL: - # SSL shutdown must not be done if a fatal error occurred. - socket.sslNoShutdown = true raiseSSLError() else: raiseSSLError("Unknown Error") if err == -1 and not (when defineSsl: socket.isSsl else: false): var lastE = if lastError.int == -1: getSocketError(socket) else: lastError - if not flags.isDisconnectionError(lastE): - if async: - when useWinVersion: - if lastE.int32 == WSAEWOULDBLOCK: - return - else: raiseOSError(lastE) - else: - if lastE.int32 == EAGAIN or lastE.int32 == EWOULDBLOCK: - return - else: raiseOSError(lastE) - else: raiseOSError(lastE) + if async: + when useWinVersion: + if lastE.int32 == WSAEWOULDBLOCK: + return + else: raiseOSError(lastE) + else: + if lastE.int32 == EAGAIN or lastE.int32 == EWOULDBLOCK: + return + else: raiseOSError(lastE) + else: raiseOSError(lastE) proc listen*(socket: Socket, backlog = SOMAXCONN) {.tags: [ReadIOEffect].} = - ## Marks `socket` as accepting connections. - ## `Backlog` specifies the maximum length of the + ## Marks ``socket`` as accepting connections. + ## ``Backlog`` specifies the maximum length of the ## queue of pending connections. ## ## Raises an OSError error upon failure. @@ -1016,9 +761,9 @@ proc listen*(socket: Socket, backlog = SOMAXCONN) {.tags: [ReadIOEffect].} = proc bindAddr*(socket: Socket, port = Port(0), address = "") {. tags: [ReadIOEffect].} = - ## Binds `address`:`port` to the socket. + ## Binds ``address``:``port`` to the socket. ## - ## If `address` is "" then ADDR_ANY will be bound. + ## If ``address`` is "" then ADDR_ANY will be bound. var realaddr = address if realaddr == "": case socket.domain @@ -1030,41 +775,34 @@ proc bindAddr*(socket: Socket, port = Port(0), address = "") {. var aiList = getAddrInfo(realaddr, port, socket.domain) if bindAddr(socket.fd, aiList.ai_addr, aiList.ai_addrlen.SockLen) < 0'i32: - freeAddrInfo(aiList) - var address2: string - address2.addQuoted address - raiseOSError(osLastError(), "address: $# port: $#" % [address2, $port]) - freeAddrInfo(aiList) + freeaddrinfo(aiList) + raiseOSError(osLastError()) + freeaddrinfo(aiList) proc acceptAddr*(server: Socket, client: var owned(Socket), address: var string, - flags = {SocketFlag.SafeDisconn}, - inheritable = defined(nimInheritHandles)) {. - tags: [ReadIOEffect], gcsafe.} = + flags = {SocketFlag.SafeDisconn}) {. + tags: [ReadIOEffect], gcsafe, locks: 0.} = ## Blocks until a connection is being made from a client. When a connection - ## is made sets `client` to the client socket and `address` to the address + ## is made sets ``client`` to the client socket and ``address`` to the address ## of the connecting client. ## This function will raise OSError if an error occurs. ## ## The resulting client will inherit any properties of the server socket. For ## example: whether the socket is buffered or not. ## - ## The SocketHandle associated with the resulting client will not be - ## inheritable by child processes by default. This can be changed via - ## the `inheritable` parameter. - ## - ## The `accept` call may result in an error if the connecting socket - ## disconnects during the duration of the `accept`. If the `SafeDisconn` + ## The ``accept`` call may result in an error if the connecting socket + ## disconnects during the duration of the ``accept``. If the ``SafeDisconn`` ## flag is specified then this error will not be raised and instead ## accept will be called again. if client.isNil: new(client) - let ret = accept(server.fd, inheritable) + let ret = accept(server.fd) let sock = ret[0] if sock == osInvalidSocket: let err = osLastError() if flags.isDisconnectionError(err): - acceptAddr(server, client, address, flags, inheritable) + acceptAddr(server, client, address, flags) raiseOSError(err) else: address = ret[1] @@ -1078,7 +816,6 @@ proc acceptAddr*(server: Socket, client: var owned(Socket), address: var string, # We must wrap the client sock in a ssl context. server.sslContext.wrapSocket(client) - ErrClearError() let ret = SSL_accept(client.sslHandle) socketError(client, ret, false) @@ -1089,16 +826,16 @@ when false: #defineSsl: ## This procedure should only be used for non-blocking **SSL** sockets. ## It will immediately return with one of the following values: ## - ## `AcceptSuccess` will be returned when a client has been successfully + ## ``AcceptSuccess`` will be returned when a client has been successfully ## accepted and the handshake has been successfully performed between - ## `server` and the newly connected client. + ## ``server`` and the newly connected client. ## - ## `AcceptNoHandshake` will be returned when a client has been accepted + ## ``AcceptNoHandshake`` will be returned when a client has been accepted ## but no handshake could be performed. This can happen when the client ## connects but does not yet initiate a handshake. In this case - ## `acceptAddrSSL` should be called again with the same parameters. + ## ``acceptAddrSSL`` should be called again with the same parameters. ## - ## `AcceptNoClient` will be returned when no client is currently attempting + ## ``AcceptNoClient`` will be returned when no client is currently attempting ## to connect. template doHandshake(): untyped = when defineSsl: @@ -1108,7 +845,6 @@ when false: #defineSsl: if not client.isSsl or client.sslHandle == nil: server.sslContext.wrapSocket(client) - ErrClearError() let ret = SSL_accept(client.sslHandle) while ret <= 0: let err = SSL_get_error(client.sslHandle, ret) @@ -1136,128 +872,32 @@ when false: #defineSsl: doHandshake() proc accept*(server: Socket, client: var owned(Socket), - flags = {SocketFlag.SafeDisconn}, - inheritable = defined(nimInheritHandles)) - {.tags: [ReadIOEffect].} = - ## Equivalent to `acceptAddr` but doesn't return the address, only the + flags = {SocketFlag.SafeDisconn}) {.tags: [ReadIOEffect].} = + ## Equivalent to ``acceptAddr`` but doesn't return the address, only the ## socket. ## - ## The SocketHandle associated with the resulting client will not be - ## inheritable by child processes by default. This can be changed via - ## the `inheritable` parameter. - ## - ## The `accept` call may result in an error if the connecting socket - ## disconnects during the duration of the `accept`. If the `SafeDisconn` + ## The ``accept`` call may result in an error if the connecting socket + ## disconnects during the duration of the ``accept``. If the ``SafeDisconn`` ## flag is specified then this error will not be raised and instead ## accept will be called again. var addrDummy = "" acceptAddr(server, client, addrDummy, flags) -when defined(posix) and not defined(lwip): - from posix import Sigset, sigwait, sigismember, sigemptyset, sigaddset, - sigprocmask, pthread_sigmask, SIGPIPE, SIG_BLOCK, SIG_UNBLOCK - -template blockSigpipe(body: untyped): untyped = - ## Temporary block SIGPIPE within the provided code block. If SIGPIPE is - ## raised for the duration of the code block, it will be queued and will be - ## raised once the block ends. - ## - ## Within the block a `selectSigpipe()` template is provided which can be - ## used to remove SIGPIPE from the queue. Note that if SIGPIPE is **not** - ## raised at the time of call, it will block until SIGPIPE is raised. - ## - ## If SIGPIPE has already been blocked at the time of execution, the - ## signal mask is left as-is and `selectSigpipe()` will become a no-op. - ## - ## For convenience, this template is also available for non-POSIX system, - ## where `body` will be executed as-is. - when not defined(posix) or defined(lwip): - body - else: - template sigmask(how: cint, set, oset: var Sigset): untyped {.gensym.} = - ## Alias for pthread_sigmask or sigprocmask depending on the status - ## of --threads - when compileOption("threads"): - pthread_sigmask(how, set, oset) - else: - sigprocmask(how, set, oset) - - var oldSet, watchSet: Sigset - if sigemptyset(oldSet) == -1: - raiseOSError(osLastError()) - if sigemptyset(watchSet) == -1: - raiseOSError(osLastError()) - - if sigaddset(watchSet, SIGPIPE) == -1: - raiseOSError(osLastError(), "Couldn't add SIGPIPE to Sigset") - - if sigmask(SIG_BLOCK, watchSet, oldSet) == -1: - raiseOSError(osLastError(), "Couldn't block SIGPIPE") - - let alreadyBlocked = sigismember(oldSet, SIGPIPE) == 1 - - template selectSigpipe(): untyped {.used.} = - if not alreadyBlocked: - var signal: cint - let err = sigwait(watchSet, signal) - if err != 0: - raiseOSError(err.OSErrorCode, "Couldn't select SIGPIPE") - assert signal == SIGPIPE - - try: - body - finally: - if not alreadyBlocked: - if sigmask(SIG_UNBLOCK, watchSet, oldSet) == -1: - raiseOSError(osLastError(), "Couldn't unblock SIGPIPE") - -proc close*(socket: Socket, flags = {SocketFlag.SafeDisconn}) = +proc close*(socket: Socket) = ## Closes a socket. - ## - ## If `socket` is an SSL/TLS socket, this proc will also send a closure - ## notification to the peer. If `SafeDisconn` is in `flags`, failure to do so - ## due to disconnections will be ignored. This is generally safe in - ## practice. See - ## `here `_ for more details. try: when defineSsl: if socket.isSsl and socket.sslHandle != nil: - # Don't call SSL_shutdown if the connection has not been fully - # established, see: - # https://github.com/openssl/openssl/issues/710#issuecomment-253897666 - if not socket.sslNoShutdown and SSL_in_init(socket.sslHandle) == 0: - # As we are closing the underlying socket immediately afterwards, - # it is valid, under the TLS standard, to perform a unidirectional - # shutdown i.e not wait for the peers "close notify" alert with a second - # call to SSL_shutdown - blockSigpipe: - ErrClearError() - let res = SSL_shutdown(socket.sslHandle) - if res == 0: - discard - elif res != 1: - let - err = osLastError() - sslError = SSL_get_error(socket.sslHandle, res) - - # If a close notification is received, failures outside of the - # protocol will be returned as SSL_ERROR_ZERO_RETURN instead - # of SSL_ERROR_SYSCALL. This fact is deduced by digging into - # SSL_get_error() source code. - if sslError == SSL_ERROR_ZERO_RETURN or - sslError == SSL_ERROR_SYSCALL: - when defined(posix) and not defined(macosx) and - not defined(nimdoc): - if err == EPIPE.OSErrorCode: - # Clear the SIGPIPE that's been raised due to - # the disconnection. - selectSigpipe() - else: - discard - if not flags.isDisconnectionError(err): - socketError(socket, res, lastError = err, flags = flags) - else: - socketError(socket, res, lastError = err, flags = flags) + ErrClearError() + # As we are closing the underlying socket immediately afterwards, + # it is valid, under the TLS standard, to perform a unidirectional + # shutdown i.e not wait for the peers "close notify" alert with a second + # call to SSL_shutdown + let res = SSL_shutdown(socket.sslHandle) + if res == 0: + discard + elif res != 1: + socketError(socket, res) finally: when defineSsl: if socket.isSsl and socket.sslHandle != nil: @@ -1273,7 +913,7 @@ else: from winlean import TCP_NODELAY proc toCInt*(opt: SOBool): cint = - ## Converts a `SOBool` into its Socket Option cint representation. + ## Converts a ``SOBool`` into its Socket Option cint representation. case opt of OptAcceptConn: SO_ACCEPTCONN of OptBroadcast: SO_BROADCAST @@ -1287,7 +927,7 @@ proc toCInt*(opt: SOBool): cint = proc getSockOpt*(socket: Socket, opt: SOBool, level = SOL_SOCKET): bool {. tags: [ReadIOEffect].} = - ## Retrieves option `opt` as a boolean value. + ## Retrieves option ``opt`` as a boolean value. var res = getSockOptInt(socket.fd, cint(level), toCInt(opt)) result = res != 0 @@ -1297,24 +937,25 @@ proc getLocalAddr*(socket: Socket): (string, Port) = ## This is high-level interface for `getsockname`:idx:. getLocalAddr(socket.fd, socket.domain) -when not useNimNetLite: - proc getPeerAddr*(socket: Socket): (string, Port) = - ## Get the socket's peer address and port number. - ## - ## This is high-level interface for `getpeername`:idx:. - getPeerAddr(socket.fd, socket.domain) +proc getPeerAddr*(socket: Socket): (string, Port) = + ## Get the socket's peer address and port number. + ## + ## This is high-level interface for `getpeername`:idx:. + getPeerAddr(socket.fd, socket.domain) proc setSockOpt*(socket: Socket, opt: SOBool, value: bool, level = SOL_SOCKET) {.tags: [WriteIOEffect].} = - ## Sets option `opt` to a boolean value specified by `value`. - runnableExamples("-r:off"): - let socket = newSocket() - socket.setSockOpt(OptReusePort, true) - socket.setSockOpt(OptNoDelay, true, level = IPPROTO_TCP.cint) + ## Sets option ``opt`` to a boolean value specified by ``value``. + ## + ## .. code-block:: Nim + ## var socket = newSocket() + ## socket.setSockOpt(OptReusePort, true) + ## socket.setSockOpt(OptNoDelay, true, level=IPPROTO_TCP.toInt) + ## var valuei = cint(if value: 1 else: 0) setSockOptInt(socket.fd, cint(level), toCInt(opt), valuei) -when defined(nimdoc) or (defined(posix) and not useNimNetLite): +when defined(posix) or defined(nimdoc): proc connectUnix*(socket: Socket, path: string) = ## Connects to Unix socket on `path`. ## This only works on Unix-style systems: Mac OS X, BSD and Linux @@ -1333,12 +974,12 @@ when defined(nimdoc) or (defined(posix) and not useNimNetLite): (sizeof(socketAddr.sun_family) + path.len).SockLen) != 0'i32: raiseOSError(osLastError()) -when defineSsl: +when defined(ssl): proc gotHandshake*(socket: Socket): bool = - ## Determines whether a handshake has occurred between a client (`socket`) - ## and the server that `socket` is connected to. + ## Determines whether a handshake has occurred between a client (``socket``) + ## and the server that ``socket`` is connected to. ## - ## Throws SslError if `socket` is not an SSL socket. + ## Throws SslError if ``socket`` is not an SSL socket. if socket.isSsl: return not socket.sslNoHandshake else: @@ -1354,6 +995,14 @@ proc hasDataBuffered*(s: Socket): bool = if s.isSsl and not result: result = s.sslHasPeekChar +proc select(readfd: Socket, timeout = 500): int = + ## Used for socket operation timeouts. + if readfd.hasDataBuffered: + return 1 + + var fds = @[readfd.fd] + result = selectRead(fds, timeout) + proc isClosed(socket: Socket): bool = socket.fd == osInvalidSocket @@ -1366,7 +1015,6 @@ proc uniRecv(socket: Socket, buffer: pointer, size, flags: cint): int = assert(not socket.isClosed, "Cannot `recv` on a closed socket") when defineSsl: if socket.isSsl: - ErrClearError() return SSL_read(socket.sslHandle, buffer, size) return recv(socket.fd, buffer, size, flags) @@ -1398,7 +1046,7 @@ proc recv*(socket: Socket, data: pointer, size: int): int {.tags: [ ## Receives data from a socket. ## ## **Note**: This is a low-level function, you may be interested in the higher - ## level versions of this function which are also named `recv`. + ## level versions of this function which are also named ``recv``. if size == 0: return if socket.isBuffered: if socket.bufLen == 0: @@ -1441,11 +1089,11 @@ proc recv*(socket: Socket, data: pointer, size: int): int {.tags: [ proc waitFor(socket: Socket, waited: var Duration, timeout, size: int, funcName: string): int {.tags: [TimeEffect].} = ## determines the amount of characters that can be read. Result will never - ## be larger than `size`. For unbuffered sockets this will be `1`. - ## For buffered sockets it can be as big as `BufferSize`. + ## be larger than ``size``. For unbuffered sockets this will be ``1``. + ## For buffered sockets it can be as big as ``BufferSize``. ## ## If this function does not determine that there is data on the socket - ## within `timeout` ms, a TimeoutError error will be raised. + ## within ``timeout`` ms, a TimeoutError error will be raised. result = 1 if size <= 0: assert false if timeout == -1: return size @@ -1467,9 +1115,7 @@ proc waitFor(socket: Socket, waited: var Duration, timeout, size: int, return min(sslPending, size) var startTime = getMonoTime() - let selRet = if socket.hasDataBuffered: 1 - else: - timeoutRead(socket.fd, (timeout - waited.inMilliseconds).int) + let selRet = select(socket, (timeout - waited.inMilliseconds).int) if selRet < 0: raiseOSError(osLastError()) if selRet != 1: raise newException(TimeoutError, "Call to '" & funcName & "' timed out.") @@ -1477,7 +1123,7 @@ proc waitFor(socket: Socket, waited: var Duration, timeout, size: int, proc recv*(socket: Socket, data: pointer, size: int, timeout: int): int {. tags: [ReadIOEffect, TimeEffect].} = - ## overload with a `timeout` parameter in milliseconds. + ## overload with a ``timeout`` parameter in milliseconds. var waited: Duration # duration already waited var read = 0 @@ -1495,12 +1141,12 @@ proc recv*(socket: Socket, data: pointer, size: int, timeout: int): int {. proc recv*(socket: Socket, data: var string, size: int, timeout = -1, flags = {SocketFlag.SafeDisconn}): int = - ## Higher-level version of `recv`. + ## Higher-level version of ``recv``. ## - ## Reads **up to** `size` bytes from `socket` into `data`. + ## Reads **up to** ``size`` bytes from ``socket`` into ``buf``. ## ## For buffered sockets this function will attempt to read all the requested - ## data. It will read this data in `BufferSize` chunks. + ## data. It will read this data in ``BufferSize`` chunks. ## ## For unbuffered sockets this function makes no effort to read ## all the data requested. It will return as much data as the operating system @@ -1514,7 +1160,9 @@ proc recv*(socket: Socket, data: var string, size: int, timeout = -1, ## A timeout may be specified in milliseconds, if enough data is not received ## within the time specified a TimeoutError exception will be raised. ## - ## .. warning:: Only the `SafeDisconn` flag is currently supported. + ## **Note**: ``data`` must be initialised. + ## + ## **Warning**: Only the ``SafeDisconn`` flag is currently supported. data.setLen(size) result = if timeout == -1: @@ -1524,24 +1172,24 @@ proc recv*(socket: Socket, data: var string, size: int, timeout = -1, if result < 0: data.setLen(0) let lastError = getSocketError(socket) - socket.socketError(result, lastError = lastError, flags = flags) - else: - data.setLen(result) + if flags.isDisconnectionError(lastError): return + socket.socketError(result, lastError = lastError) + data.setLen(result) proc recv*(socket: Socket, size: int, timeout = -1, flags = {SocketFlag.SafeDisconn}): string {.inline.} = - ## Higher-level version of `recv` which returns a string. + ## Higher-level version of ``recv`` which returns a string. ## - ## Reads **up to** `size` bytes from `socket` into the result. + ## Reads **up to** ``size`` bytes from ``socket`` into ``buf``. ## ## For buffered sockets this function will attempt to read all the requested - ## data. It will read this data in `BufferSize` chunks. + ## data. It will read this data in ``BufferSize`` chunks. ## ## For unbuffered sockets this function makes no effort to read ## all the data requested. It will return as much data as the operating system ## gives it. ## - ## When `""` is returned the socket's connection has been closed. + ## When ``""`` is returned the socket's connection has been closed. ## ## This function will throw an OSError exception when an error occurs. ## @@ -1549,7 +1197,7 @@ proc recv*(socket: Socket, size: int, timeout = -1, ## within the time specified a TimeoutError exception will be raised. ## ## - ## .. warning:: Only the `SafeDisconn` flag is currently supported. + ## **Warning**: Only the ``SafeDisconn`` flag is currently supported. result = newString(size) discard recv(socket, result, size, timeout, flags) @@ -1573,47 +1221,45 @@ proc peekChar(socket: Socket, c: var char): int {.tags: [ReadIOEffect].} = return result = recv(socket.fd, addr(c), 1, MSG_PEEK) -proc readLine*(socket: Socket, line: var string, timeout = -1, +proc readLine*(socket: Socket, line: var TaintedString, timeout = -1, flags = {SocketFlag.SafeDisconn}, maxLength = MaxLineLength) {. tags: [ReadIOEffect, TimeEffect].} = - ## Reads a line of data from `socket`. + ## Reads a line of data from ``socket``. ## - ## If a full line is read `\r\L` is not - ## added to `line`, however if solely `\r\L` is read then `line` + ## If a full line is read ``\r\L`` is not + ## added to ``line``, however if solely ``\r\L`` is read then ``line`` ## will be set to it. ## - ## If the socket is disconnected, `line` will be set to `""`. + ## If the socket is disconnected, ``line`` will be set to ``""``. ## ## An OSError exception will be raised in the case of a socket error. ## ## A timeout can be specified in milliseconds, if data is not received within ## the specified time a TimeoutError exception will be raised. ## - ## The `maxLength` parameter determines the maximum amount of characters + ## The ``maxLength`` parameter determines the maximum amount of characters ## that can be read. The result is truncated after that. ## - ## .. warning:: Only the `SafeDisconn` flag is currently supported. + ## **Warning**: Only the ``SafeDisconn`` flag is currently supported. template addNLIfEmpty() = if line.len == 0: - line.add("\c\L") + line.string.add("\c\L") template raiseSockError() {.dirty.} = let lastError = getSocketError(socket) - if flags.isDisconnectionError(lastError): - setLen(line, 0) - socket.socketError(n, lastError = lastError, flags = flags) - return + if flags.isDisconnectionError(lastError): setLen(line.string, 0); return + socket.socketError(n, lastError = lastError) var waited: Duration - setLen(line, 0) + setLen(line.string, 0) while true: var c: char discard waitFor(socket, waited, timeout, 1, "readLine") var n = recv(socket, addr(c), 1) if n < 0: raiseSockError() - elif n == 0: setLen(line, 0); return + elif n == 0: setLen(line.string, 0); return if c == '\r': discard waitFor(socket, waited, timeout, 1, "readLine") n = peekChar(socket, c) @@ -1625,84 +1271,65 @@ proc readLine*(socket: Socket, line: var string, timeout = -1, elif c == '\L': addNLIfEmpty() return - add(line, c) + add(line.string, c) # Verify that this isn't a DOS attack: #3847. - if line.len > maxLength: break + if line.string.len > maxLength: break proc recvLine*(socket: Socket, timeout = -1, flags = {SocketFlag.SafeDisconn}, - maxLength = MaxLineLength): string = - ## Reads a line of data from `socket`. + maxLength = MaxLineLength): TaintedString = + ## Reads a line of data from ``socket``. ## - ## If a full line is read `\r\L` is not - ## added to the result, however if solely `\r\L` is read then the result + ## If a full line is read ``\r\L`` is not + ## added to the result, however if solely ``\r\L`` is read then the result ## will be set to it. ## - ## If the socket is disconnected, the result will be set to `""`. + ## If the socket is disconnected, the result will be set to ``""``. ## ## An OSError exception will be raised in the case of a socket error. ## ## A timeout can be specified in milliseconds, if data is not received within ## the specified time a TimeoutError exception will be raised. ## - ## The `maxLength` parameter determines the maximum amount of characters + ## The ``maxLength`` parameter determines the maximum amount of characters ## that can be read. The result is truncated after that. ## - ## .. warning:: Only the `SafeDisconn` flag is currently supported. - result = "" + ## **Warning**: Only the ``SafeDisconn`` flag is currently supported. + result = "".TaintedString readLine(socket, result, timeout, flags, maxLength) -proc recvFrom*[T: string | IpAddress](socket: Socket, data: var string, length: int, - address: var T, port: var Port, flags = 0'i32): int {. +proc recvFrom*(socket: Socket, data: var string, length: int, + address: var string, port: var Port, flags = 0'i32): int {. tags: [ReadIOEffect].} = - ## Receives data from `socket`. This function should normally be used with - ## connection-less sockets (UDP sockets). The source address of the data - ## packet is stored in the `address` argument as either a string or an IpAddress. + ## Receives data from ``socket``. This function should normally be used with + ## connection-less sockets (UDP sockets). ## ## If an error occurs an OSError exception will be raised. Otherwise the return ## value will be the length of data received. ## - ## .. warning:: This function does not yet have a buffered implementation, - ## so when `socket` is buffered the non-buffered implementation will be - ## used. Therefore if `socket` contains something in its buffer this - ## function will make no effort to return it. - template adaptRecvFromToDomain(sockAddress: untyped, domain: Domain) = - var addrLen = SockLen(sizeof(sockAddress)) - result = recvfrom(socket.fd, cstring(data), length.cint, flags.cint, - cast[ptr SockAddr](addr(sockAddress)), addr(addrLen)) - - if result != -1: - data.setLen(result) - - when typeof(address) is string: - address = getAddrString(cast[ptr SockAddr](addr(sockAddress))) - when domain == AF_INET6: - port = ntohs(sockAddress.sin6_port).Port - else: - port = ntohs(sockAddress.sin_port).Port - else: - data.setLen(result) - sockAddress.fromSockAddr(addrLen, address, port) - else: - raiseOSError(osLastError()) + ## **Warning:** This function does not yet have a buffered implementation, + ## so when ``socket`` is buffered the non-buffered implementation will be + ## used. Therefore if ``socket`` contains something in its buffer this + ## function will make no effort to return it. assert(socket.protocol != IPPROTO_TCP, "Cannot `recvFrom` on a TCP socket") # TODO: Buffered sockets data.setLen(length) + var sockAddress: Sockaddr_in + var addrLen = sizeof(sockAddress).SockLen + result = recvfrom(socket.fd, cstring(data), length.cint, flags.cint, + cast[ptr SockAddr](addr(sockAddress)), addr(addrLen)) - case socket.domain - of AF_INET6: - var sockAddress: Sockaddr_in6 - adaptRecvFromToDomain(sockAddress, AF_INET6) - of AF_INET: - var sockAddress: Sockaddr_in - adaptRecvFromToDomain(sockAddress, AF_INET) + if result != -1: + data.setLen(result) + address = getAddrString(cast[ptr SockAddr](addr(sockAddress))) + port = ntohs(sockAddress.sin_port).Port else: - raise newException(ValueError, "Unknown socket address family") + raiseOSError(osLastError()) proc skip*(socket: Socket, size: int, timeout = -1) = - ## Skips `size` amount of bytes. + ## Skips ``size`` amount of bytes. ## ## An optional timeout can be specified in milliseconds, if skipping the ## bytes takes longer than specified a TimeoutError exception will be raised. @@ -1720,12 +1347,11 @@ proc send*(socket: Socket, data: pointer, size: int): int {. tags: [WriteIOEffect].} = ## Sends data to a socket. ## - ## **Note**: This is a low-level version of `send`. You likely should use + ## **Note**: This is a low-level version of ``send``. You likely should use ## the version below. assert(not socket.isClosed, "Cannot `send` on a closed socket") when defineSsl: if socket.isSsl: - ErrClearError() return SSL_write(socket.sslHandle, cast[cstring](data), size) when useWinVersion or defined(macosx): @@ -1736,53 +1362,32 @@ proc send*(socket: Socket, data: pointer, size: int): int {. result = send(socket.fd, data, size, int32(MSG_NOSIGNAL)) proc send*(socket: Socket, data: string, - flags = {SocketFlag.SafeDisconn}, maxRetries = 100) {.tags: [WriteIOEffect].} = - ## Sends data to a socket. Will try to send all the data by handling interrupts - ## and incomplete writes up to `maxRetries`. - var written = 0 - var attempts = 0 - while data.len - written > 0: - let sent = send(socket, cstring(data), data.len) + flags = {SocketFlag.SafeDisconn}) {.tags: [WriteIOEffect].} = + ## sends data to a socket. + let sent = send(socket, cstring(data), data.len) + if sent < 0: + let lastError = osLastError() + if flags.isDisconnectionError(lastError): return + socketError(socket, lastError = lastError) - if sent < 0: - let lastError = osLastError() - let isBlockingErr = - when defined(nimdoc): - false - elif useWinVersion: - lastError.int32 == WSAEINTR or - lastError.int32 == WSAEWOULDBLOCK - else: - lastError.int32 == EINTR or - lastError.int32 == EWOULDBLOCK or - lastError.int32 == EAGAIN - - if not isBlockingErr: - let lastError = osLastError() - socketError(socket, lastError = lastError, flags = flags) - else: - attempts.inc() - if attempts > maxRetries: - raiseOSError(osLastError(), "Could not send all data.") - else: - written.inc(sent) + if sent != data.len: + raiseOSError(osLastError(), "Could not send all data.") template `&=`*(socket: Socket; data: typed) = ## an alias for 'send'. send(socket, data) proc trySend*(socket: Socket, data: string): bool {.tags: [WriteIOEffect].} = - ## Safe alternative to `send`. Does not raise an OSError when an error occurs, - ## and instead returns `false` on failure. + ## Safe alternative to ``send``. Does not raise an OSError when an error occurs, + ## and instead returns ``false`` on failure. result = send(socket, cstring(data), data.len) == data.len proc sendTo*(socket: Socket, address: string, port: Port, data: pointer, size: int, af: Domain = AF_INET, flags = 0'i32) {. tags: [WriteIOEffect].} = - ## This proc sends `data` to the specified `address`, + ## This proc sends ``data`` to the specified ``address``, ## which may be an IP address or a hostname, if a hostname is specified - ## this function will try each IP of that hostname. This function - ## should normally be used with connection-less sockets (UDP sockets). + ## this function will try each IP of that hostname. ## ## If an error occurs an OSError exception will be raised. ## @@ -1806,51 +1411,25 @@ proc sendTo*(socket: Socket, address: string, port: Port, data: pointer, it = it.ai_next let osError = osLastError() - freeAddrInfo(aiList) + freeaddrinfo(aiList) if not success: raiseOSError(osError) proc sendTo*(socket: Socket, address: string, port: Port, data: string) {.tags: [WriteIOEffect].} = - ## This proc sends `data` to the specified `address`, + ## This proc sends ``data`` to the specified ``address``, ## which may be an IP address or a hostname, if a hostname is specified ## this function will try each IP of that hostname. ## - ## Generally for use with connection-less (UDP) sockets. - ## ## If an error occurs an OSError exception will be raised. ## - ## This is the high-level version of the above `sendTo` function. + ## This is the high-level version of the above ``sendTo`` function. socket.sendTo(address, port, cstring(data), data.len, socket.domain) -proc sendTo*(socket: Socket, address: IpAddress, port: Port, - data: string, flags = 0'i32): int {. - discardable, tags: [WriteIOEffect].} = - ## This proc sends `data` to the specified `IpAddress` and returns - ## the number of bytes written. - ## - ## Generally for use with connection-less (UDP) sockets. - ## - ## If an error occurs an OSError exception will be raised. - ## - ## This is the high-level version of the above `sendTo` function. - assert(socket.protocol != IPPROTO_TCP, "Cannot `sendTo` on a TCP socket") - assert(not socket.isClosed, "Cannot `sendTo` on a closed socket") - - var sa: Sockaddr_storage - var sl: SockLen - toSockAddr(address, port, sa, sl) - result = sendto(socket.fd, cstring(data), data.len().cint, flags.cint, - cast[ptr SockAddr](addr sa), sl) - - if result == -1'i32: - let osError = osLastError() - raiseOSError(osError) - proc isSsl*(socket: Socket): bool = - ## Determines whether `socket` is a SSL socket. + ## Determines whether ``socket`` is a SSL socket. when defineSsl: result = socket.isSsl else: @@ -1859,16 +1438,6 @@ proc isSsl*(socket: Socket): bool = proc getFd*(socket: Socket): SocketHandle = return socket.fd ## Returns the socket's file descriptor -when defined(zephyr) or defined(nimNetSocketExtras): # Remove in future - proc getDomain*(socket: Socket): Domain = return socket.domain - ## Returns the socket's domain - - proc getType*(socket: Socket): SockType = return socket.sockType - ## Returns the socket's type - - proc getProtocol*(socket: Socket): Protocol = return socket.protocol - ## Returns the socket's protocol - when defined(nimHasStyleChecks): {.push styleChecks: off.} @@ -1920,18 +1489,14 @@ proc `==`*(lhs, rhs: IpAddress): bool = proc `$`*(address: IpAddress): string = ## Converts an IpAddress into the textual representation + result = "" case address.family of IpAddressFamily.IPv4: - result = newStringOfCap(15) - result.addInt address.address_v4[0] - result.add '.' - result.addInt address.address_v4[1] - result.add '.' - result.addInt address.address_v4[2] - result.add '.' - result.addInt address.address_v4[3] + for i in 0 .. 3: + if i != 0: + result.add('.') + result.add($address.address_v4[i]) of IpAddressFamily.IPv6: - result = newStringOfCap(39) var currentZeroStart = -1 currentZeroCount = 0 @@ -1980,18 +1545,14 @@ proc `$`*(address: IpAddress): string = result.add(chr(uint16(ord('a'))+val-0xA)) afterLeadingZeros = true mask = mask shr 4 - - if not afterLeadingZeros: - result.add '0' - printedLastGroup = true proc dial*(address: string, port: Port, protocol = IPPROTO_TCP, buffered = true): owned(Socket) {.tags: [ReadIOEffect, WriteIOEffect].} = - ## Establishes connection to the specified `address`:`port` pair via the + ## Establishes connection to the specified ``address``:``port`` pair via the ## specified protocol. The procedure iterates through possible - ## resolutions of the `address` until it succeeds, meaning that it + ## resolutions of the ``address`` until it succeeds, meaning that it ## seamlessly works with both IPv4 and IPv6. ## Returns Socket ready to send or receive data. let sockType = protocol.toSockType() @@ -2025,7 +1586,7 @@ proc dial*(address: string, port: Port, # network system problem (e.g. not enough FDs), and not an unreachable # address. let err = osLastError() - freeAddrInfo(aiList) + freeaddrinfo(aiList) closeUnusedFds() raiseOSError(err) fdPerDomain[ord(domain)] = lastFd @@ -2034,24 +1595,24 @@ proc dial*(address: string, port: Port, break lastError = osLastError() it = it.ai_next - freeAddrInfo(aiList) + freeaddrinfo(aiList) closeUnusedFds(ord(domain)) if success: - result = newSocket(lastFd, domain, sockType, protocol, buffered) + result = newSocket(lastFd, domain, sockType, protocol) elif lastError != 0.OSErrorCode: raiseOSError(lastError) else: raise newException(IOError, "Couldn't resolve address: " & address) proc connect*(socket: Socket, address: string, - port = Port(0)) {.tags: [ReadIOEffect, RootEffect].} = - ## Connects socket to `address`:`port`. `Address` can be an IP address or a - ## host name. If `address` is a host name, this function will try each IP - ## of that host name. `htons` is already performed on `port` so you must + port = Port(0)) {.tags: [ReadIOEffect].} = + ## Connects socket to ``address``:``port``. ``Address`` can be an IP address or a + ## host name. If ``address`` is a host name, this function will try each IP + ## of that host name. ``htons`` is already performed on ``port`` so you must ## not do it. ## - ## If `socket` is an SSL socket a handshake will be automatically performed. + ## If ``socket`` is an SSL socket a handshake will be automatically performed. var aiList = getAddrInfo(address, port, socket.domain) # try all possibilities: var success = false @@ -2064,7 +1625,7 @@ proc connect*(socket: Socket, address: string, else: lastError = osLastError() it = it.ai_next - freeAddrInfo(aiList) + freeaddrinfo(aiList) if not success: raiseOSError(lastError) when defineSsl: @@ -2075,22 +1636,18 @@ proc connect*(socket: Socket, address: string, # not using TLSv1+ discard SSL_set_tlsext_host_name(socket.sslHandle, address) - ErrClearError() let ret = SSL_connect(socket.sslHandle) socketError(socket, ret) - when not defined(nimDisableCertificateValidation) and not defined(windows): - if not isIpAddress(address): - socket.checkCertName(address) proc connectAsync(socket: Socket, name: string, port = Port(0), af: Domain = AF_INET) {.tags: [ReadIOEffect].} = - ## A variant of `connect` for non-blocking sockets. + ## A variant of ``connect`` for non-blocking sockets. ## ## This procedure will immediately return, it will not block until a connection ## is made. It is up to the caller to make sure the connection has been established - ## by checking (using `select`) whether the socket is writeable. + ## by checking (using ``select``) whether the socket is writeable. ## - ## **Note**: For SSL sockets, the `handshake` procedure must be called + ## **Note**: For SSL sockets, the ``handshake`` procedure must be called ## whenever the socket successfully connects to a server. var aiList = getAddrInfo(name, port, af) # try all possibilities: @@ -2116,19 +1673,20 @@ proc connectAsync(socket: Socket, name: string, port = Port(0), it = it.ai_next - freeAddrInfo(aiList) + freeaddrinfo(aiList) if not success: raiseOSError(lastError) proc connect*(socket: Socket, address: string, port = Port(0), - timeout: int) {.tags: [ReadIOEffect, WriteIOEffect, RootEffect].} = - ## Connects to server as specified by `address` on port specified by `port`. + timeout: int) {.tags: [ReadIOEffect, WriteIOEffect].} = + ## Connects to server as specified by ``address`` on port specified by ``port``. ## - ## The `timeout` parameter specifies the time in milliseconds to allow for + ## The ``timeout`` parameter specifies the time in milliseconds to allow for ## the connection to the server to be made. socket.fd.setBlocking(false) socket.connectAsync(address, port, socket.domain) - if timeoutWrite(socket.fd, timeout) != 1: + var s = @[socket.fd] + if selectWrite(s, timeout) != 1: raise newException(TimeoutError, "Call to 'connect' timed out.") else: let res = getSockOptInt(socket.fd, SOL_SOCKET, SO_ERROR) @@ -2137,18 +1695,7 @@ proc connect*(socket: Socket, address: string, port = Port(0), when defineSsl and not defined(nimdoc): if socket.isSsl: socket.fd.setBlocking(true) - # RFC3546 for SNI specifies that IP addresses are not allowed. - if not isIpAddress(address): - # Discard result in case OpenSSL version doesn't support SNI, or we're - # not using TLSv1+ - discard SSL_set_tlsext_host_name(socket.sslHandle, address) - - ErrClearError() - let ret = SSL_connect(socket.sslHandle) - socketError(socket, ret) - when not defined(nimDisableCertificateValidation): - if not isIpAddress(address): - socket.checkCertName(address) + doAssert socket.gotHandshake() socket.fd.setBlocking(true) proc getPrimaryIPAddr*(dest = parseIpAddress("8.8.8.8")): IpAddress = @@ -2159,15 +1706,14 @@ proc getPrimaryIPAddr*(dest = parseIpAddress("8.8.8.8")): IpAddress = ## ## Supports IPv4 and v6. ## Raises OSError if external networking is not set up. - runnableExamples("-r:off"): - echo getPrimaryIPAddr() # "192.168.1.2" + ## + ## .. code-block:: Nim + ## echo $getPrimaryIPAddr() # "192.168.1.2" + let socket = if dest.family == IpAddressFamily.IPv4: newSocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP) else: newSocket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP) - try: - socket.connect($dest, 80.Port) - result = socket.getLocalAddr()[0].parseIpAddress() - finally: - socket.close() + socket.connect($dest, 80.Port) + socket.getLocalAddr()[0].parseIpAddress() diff --git a/lib/pure/nimprof.nim b/lib/pure/nimprof.nim index 9849e42db..fad8b66a1 100644 --- a/lib/pure/nimprof.nim +++ b/lib/pure/nimprof.nim @@ -8,23 +8,20 @@ # ## Profiling support for Nim. This is an embedded profiler that requires -## `--profiler:on`. You only need to import this module to get a profiling -## report at program exit. See `Embedded Stack Trace Profiler `_ -## for usage. +## ``--profiler:on``. You only need to import this module to get a profiling +## report at program exit. when not defined(profiler) and not defined(memProfiler): {.error: "Profiling support is turned off! Enable profiling by passing `--profiler:on --stackTrace:on` to the compiler (see the Nim Compiler User Guide for more options).".} -{.used.} +when defined(nimHasUsed): + {.used.} # We don't want to profile the profiling code ... {.push profiler: off.} import hashes, algorithm, strutils, tables, sets -when defined(nimPreviewSlimSystem): - import std/[syncio, sysatomics] - when not defined(memProfiler): include "system/timers" @@ -124,13 +121,13 @@ when defined(memProfiler): var gTicker {.threadvar.}: int - proc requestedHook(): bool {.nimcall.} = + proc requestedHook(): bool {.nimcall, locks: 0.} = if gTicker == 0: gTicker = SamplingInterval result = true dec gTicker - proc hook(st: StackTrace, size: int) {.nimcall.} = + proc hook(st: StackTrace, size: int) {.nimcall, locks: 0.} = when defined(ignoreAllocationSize): hookAux(st, 1) else: @@ -142,7 +139,7 @@ else: gTicker: int # we use an additional counter to # avoid calling 'getTicks' too frequently - proc requestedHook(): bool {.nimcall.} = + proc requestedHook(): bool {.nimcall, locks: 0.} = if interval == 0: result = true elif gTicker == 0: gTicker = 500 @@ -151,7 +148,7 @@ else: else: dec gTicker - proc hook(st: StackTrace) {.nimcall.} = + proc hook(st: StackTrace) {.nimcall, locks: 0.} = #echo "profiling! ", interval if interval == 0: hookAux(st, 1) @@ -184,7 +181,7 @@ proc writeProfile() {.noconv.} = var perProc = initCountTable[string]() for i in 0..entries-1: - var dups = initHashSet[string]() + var dups = initSet[string]() for ii in 0..high(StackTrace.lines): let procname = profileData[i].st[ii] if isNil(procname): break @@ -225,9 +222,8 @@ proc enableProfiling*() = system.profilingRequestedHook = requestedHook when declared(system.StackTrace): - import std/exitprocs system.profilingRequestedHook = requestedHook system.profilerHook = hook - addExitProc(writeProfile) + addQuitProc(writeProfile) {.pop.} diff --git a/lib/pure/nimtracker.nim b/lib/pure/nimtracker.nim new file mode 100644 index 000000000..a66dfc2ea --- /dev/null +++ b/lib/pure/nimtracker.nim @@ -0,0 +1,88 @@ +# +# +# Nim's Runtime Library +# (c) Copyright 2016 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +## Memory tracking support for Nim. + +when not defined(memTracker) and not isMainModule: + {.error: "Memory tracking support is turned off!".} + +{.push memtracker: off.} +# we import the low level wrapper and are careful not to use Nim's +# memory manager for anything here. +import sqlite3 + +var + dbHandle: PSqlite3 + insertStmt {.threadvar.}: Pstmt + +const insertQuery = "INSERT INTO tracking(op, address, size, file, line) values (?, ?, ?, ?, ?)" + +template sbind(x: int; value) = + when value is cstring: + let ret = insertStmt.bindText(x, value, value.len.int32, SQLITE_TRANSIENT) + if ret != SQLITE_OK: + quit "could not bind value" + else: + let ret = insertStmt.bindInt64(x, value) + if ret != SQLITE_OK: + quit "could not bind value" + +when defined(memTracker): + proc logEntries(log: TrackLog) {.nimcall, locks: 0, tags: [], gcsafe.} = + if insertStmt.isNil: + if prepare_v2(dbHandle, insertQuery, + insertQuery.len, insertStmt, nil) != SQLITE_OK: + quit "could not bind query to insertStmt " & $sqlite3.errmsg(dbHandle) + for i in 0..log.count-1: + var success = false + let e = log.data[i] + discard sqlite3.reset(insertStmt) + discard clearBindings(insertStmt) + sbind 1, e.op + sbind(2, cast[int](e.address)) + sbind 3, e.size + sbind 4, e.file + sbind 5, e.line + if step(insertStmt) == SQLITE_DONE: + success = true + if not success: + quit "could not write to database! " & $sqlite3.errmsg(dbHandle) + +proc execQuery(q: string) = + var s: Pstmt + if prepare_v2(dbHandle, q, q.len.int32, s, nil) == SQLITE_OK: + discard step(s) + if finalize(s) != SQLITE_OK: + quit "could not finalize " & $sqlite3.errmsg(dbHandle) + else: + quit "could not prepare statement " & $sqlite3.errmsg(dbHandle) + +proc setupDb() = + execQuery """create table if not exists tracking( + id integer primary key, + op varchar not null, + address integer not null, + size integer not null, + file varchar not null, + line integer not null + )""" + execQuery "delete from tracking" + +if sqlite3.open("memtrack.db", dbHandle) == SQLITE_OK: + setupDb() + const query = "INSERT INTO tracking(op, address, size, file, line) values (?, ?, ?, ?, ?)" + if prepare_v2(dbHandle, insertQuery, + insertQuery.len, insertStmt, nil) == SQLITE_OK: + when defined(memTracker): + setTrackLogger logEntries + else: + quit "could not prepare statement B " & $sqlite3.errmsg(dbHandle) +else: + quit "could not setup sqlite " & $sqlite3.errmsg(dbHandle) +{.pop.} diff --git a/lib/pure/oids.nim b/lib/pure/oids.nim index ad8eeefd7..d3a7c4fb6 100644 --- a/lib/pure/oids.nim +++ b/lib/pure/oids.nim @@ -9,91 +9,92 @@ ## Nim OID support. An OID is a global ID that consists of a timestamp, ## a unique counter and a random value. This combination should suffice to -## produce a globally distributed unique ID. +## produce a globally distributed unique ID. This implementation was extracted +## from the Mongodb interface and it thus binary compatible with a Mongo OID. ## -## This implementation calls `initRand()` for the first call of -## `genOid`. +## This implementation calls ``math.randomize()`` for the first call of +## ``genOid``. -import hashes, times, endians, random -from std/private/decode_helpers import handleHexChar - -when defined(nimPreviewSlimSystem): - import std/sysatomics +import hashes, times, endians type - Oid* = object ## An OID. - time: int64 - fuzz: int32 - count: int32 + Oid* = object ## an OID + time: int32 ## + fuzz: int32 ## + count: int32 ## -proc `==`*(oid1: Oid, oid2: Oid): bool {.inline.} = - ## Compares two OIDs for equality. - result = (oid1.time == oid2.time) and (oid1.fuzz == oid2.fuzz) and +proc `==`*(oid1: Oid, oid2: Oid): bool = + ## Compare two Mongo Object IDs for equality + return (oid1.time == oid2.time) and (oid1.fuzz == oid2.fuzz) and (oid1.count == oid2.count) proc hash*(oid: Oid): Hash = - ## Generates the hash of an OID for use in hashtables. + ## Generate hash of Oid for use in hashtables var h: Hash = 0 h = h !& hash(oid.time) h = h !& hash(oid.fuzz) h = h !& hash(oid.count) result = !$h -proc hexbyte*(hex: char): int {.inline.} = - result = handleHexChar(hex) +proc hexbyte*(hex: char): int = + case hex + of '0'..'9': result = (ord(hex) - ord('0')) + of 'a'..'f': result = (ord(hex) - ord('a') + 10) + of 'A'..'F': result = (ord(hex) - ord('A') + 10) + else: discard proc parseOid*(str: cstring): Oid = - ## Parses an OID. - var bytes = cast[cstring](cast[pointer](cast[int](addr(result.time)) + 4)) + ## parses an OID. + var bytes = cast[cstring](addr(result.time)) var i = 0 while i < 12: bytes[i] = chr((hexbyte(str[2 * i]) shl 4) or hexbyte(str[2 * i + 1])) inc(i) -proc `$`*(oid: Oid): string = - ## Converts an OID to a string. +proc oidToString*(oid: Oid, str: cstring) = const hex = "0123456789abcdef" - - result.setLen 24 - + # work around a compiler bug: + var str = str var o = oid - var bytes = cast[cstring](cast[pointer](cast[int](addr(o)) + 4)) + var bytes = cast[cstring](addr(o)) var i = 0 while i < 12: let b = bytes[i].ord - result[2 * i] = hex[(b and 0xF0) shr 4] - result[2 * i + 1] = hex[b and 0xF] + str[2 * i] = hex[(b and 0xF0) shr 4] + str[2 * i + 1] = hex[b and 0xF] inc(i) + str[24] = '\0' -let - t = getTime().toUnix +proc `$`*(oid: Oid): string = + result = newString(24) + oidToString(oid, result) + +proc rand(): cint {.importc: "rand", header: "", nodecl.} +proc srand(seed: cint) {.importc: "srand", header: "", nodecl.} + +var t = getTime().toUnix.int32 +srand(t) var - seed = initRand(t) - incr: int = seed.rand(int.high) + incr: int = rand() + fuzz: int32 = rand() -let fuzz = cast[int32](seed.rand(high(int))) +proc genOid*(): Oid = + ## generates a new OID. + t = getTime().toUnix.int32 + var i = int32(atomicInc(incr)) - -template genOid(result: var Oid, incr: var int, fuzz: int32) = - var time = getTime().toUnix - var i = cast[int32](atomicInc(incr)) - - bigEndian64(addr result.time, addr(time)) + bigEndian32(addr result.time, addr(t)) result.fuzz = fuzz bigEndian32(addr result.count, addr(i)) -proc genOid*(): Oid = - ## Generates a new OID. - runnableExamples: - doAssert ($genOid()).len == 24 - runnableExamples("-r:off"): - echo $genOid() # for example, "5fc7f546ddbbc84800006aaf" - genOid(result, incr, fuzz) - proc generatedTime*(oid: Oid): Time = - ## Returns the generated timestamp of the OID. - var tmp: int64 + ## returns the generated timestamp of the OID. + var tmp: int32 var dummy = oid.time - bigEndian64(addr(tmp), addr(dummy)) + bigEndian32(addr(tmp), addr(dummy)) result = fromUnix(tmp) + +when not defined(testing) and isMainModule: + let xo = genOid() + echo xo.generatedTime diff --git a/lib/pure/options.nim b/lib/pure/options.nim index 9dc4e096b..28c4e4984 100644 --- a/lib/pure/options.nim +++ b/lib/pure/options.nim @@ -7,165 +7,143 @@ # distribution, for details about the copyright. # -##[ -This module implements types which encapsulate an optional value. - -A value of type `Option[T]` either contains a value `x` (represented as -`some(x)`) or is empty (`none(T)`). - -This can be useful when you have a value that can be present or not. The -absence of a value is often represented by `nil`, but that is not always -available, nor is it always a good solution. - - -Basic usage -=========== - -Let's start with an example: a procedure that finds the index of a character -in a string. -]## - -runnableExamples: - proc find(haystack: string, needle: char): Option[int] = - for i, c in haystack: - if c == needle: - return some(i) - return none(int) # This line is actually optional, - # because the default is empty - - let found = "abc".find('c') - assert found.isSome and found.get() == 2 - -##[ -The `get` operation demonstrated above returns the underlying value, or -raises `UnpackDefect` if there is no value. Note that `UnpackDefect` -inherits from `system.Defect` and should therefore never be caught. -Instead, rely on checking if the option contains a value with the -`isSome <#isSome,Option[T]>`_ and `isNone <#isNone,Option[T]>`_ procs. - - -Pattern matching -================ - -.. note:: This requires the [fusion](https://github.com/nim-lang/fusion) package. - -[fusion/matching](https://nim-lang.github.io/fusion/src/fusion/matching.html) -supports pattern matching on `Option`s, with the `Some()` and -`None()` patterns. - -.. code-block:: nim - {.experimental: "caseStmtMacros".} - - import fusion/matching - - case some(42) - of Some(@a): - assert a == 42 - of None(): - assert false - - assertMatch(some(some(none(int))), Some(Some(None()))) -]## -# xxx pending https://github.com/timotheecour/Nim/issues/376 use `runnableExamples` and `whichModule` - -when defined(nimHasEffectsOf): - {.experimental: "strictEffects".} -else: - {.pragma: effectsOf.} +## This module implements types which encapsulate an optional value. +## +## A value of type `Option[T]` either contains a value `x` (represented as +## `some(x)`) or is empty (`none(T)`). +## +## This can be useful when you have a value that can be present or not. The +## absence of a value is often represented by `nil`, but it is not always +## available, nor is it always a good solution. +## +## +## Basic usage +## =========== +## +## Let's start with an example: a procedure that finds the index of a character +## in a string. +## +## .. code-block:: nim +## +## import options +## +## proc find(haystack: string, needle: char): Option[int] = +## for i, c in haystack: +## if c == needle: +## return some(i) +## return none(int) # This line is actually optional, +## # because the default is empty +## +## .. code-block:: nim +## +## let found = "abc".find('c') +## assert found.isSome and found.get() == 2 +## +## The `get` operation demonstrated above returns the underlying value, or +## raises `UnpackError` if there is no value. Note that `UnpackError` +## inherits from `system.Defect`, and should therefore never be caught. +## Instead, rely on checking if the option contains a value with +## `isSome <#isSome,Option[T]>`_ and `isNone <#isNone,Option[T]>`_ procs. +## +## How to deal with an absence of a value: +## +## .. code-block:: nim +## +## let result = "team".find('i') +## +## # Nothing was found, so the result is `none`. +## assert(result == none(int)) +## # It has no value: +## assert(result.isNone) import typetraits -when defined(nimPreviewSlimSystem): - import std/assertions - - -when (NimMajor, NimMinor) >= (1, 1): - type - SomePointer = ref | ptr | pointer | proc -else: - type - SomePointer = ref | ptr | pointer +type + SomePointer = ref | ptr | pointer type Option*[T] = object - ## An optional type that may or may not contain a value of type `T`. - ## When `T` is a a pointer type (`ptr`, `pointer`, `ref` or `proc`), - ## `none(T)` is represented as `nil`. + ## An optional type that stores its value and state separately in a boolean. when T is SomePointer: val: T else: val: T has: bool - UnpackDefect* = object of Defect - UnpackError* {.deprecated: "See corresponding Defect".} = UnpackDefect + UnpackError* = object of Defect -proc option*[T](val: sink T): Option[T] {.inline.} = - ## Can be used to convert a pointer type (`ptr`, `pointer`, `ref` or `proc`) to an option type. - ## It converts `nil` to `none(T)`. When `T` is no pointer type, this is equivalent to `some(val)`. + +proc option*[T](val: T): Option[T] = + ## Can be used to convert a pointer type (`ptr` or `ref`) to an option type. + ## It converts `nil` to `None`. ## - ## **See also:** - ## * `some proc <#some,T>`_ - ## * `none proc <#none,typedesc>`_ + ## See also: + ## * `some <#some,T>`_ + ## * `none <#none,typedesc>`_ runnableExamples: type Foo = ref object a: int b: string - - assert option[Foo](nil).isNone - assert option(42).isSome + var c: Foo + assert c.isNil + var d = option(c) + assert d.isNone result.val = val when T isnot SomePointer: result.has = true -proc some*[T](val: sink T): Option[T] {.inline.} = +proc some*[T](val: T): Option[T] = ## Returns an `Option` that has the value `val`. ## - ## **See also:** - ## * `option proc <#option,T>`_ - ## * `none proc <#none,typedesc>`_ - ## * `isSome proc <#isSome,Option[T]>`_ + ## See also: + ## * `option <#option,T>`_ + ## * `none <#none,typedesc>`_ + ## * `isSome <#isSome,Option[T]>`_ runnableExamples: - let a = some("abc") - - assert a.isSome + var + a = some("abc") + b = some(42) + assert $type(a) == "Option[system.string]" + assert b.isSome assert a.get == "abc" + assert $b == "Some(42)" when T is SomePointer: - assert not val.isNil + assert(not val.isNil) result.val = val else: result.has = true result.val = val -proc none*(T: typedesc): Option[T] {.inline.} = +proc none*(T: typedesc): Option[T] = ## Returns an `Option` for this type that has no value. ## - ## **See also:** - ## * `option proc <#option,T>`_ - ## * `some proc <#some,T>`_ - ## * `isNone proc <#isNone,Option[T]>`_ + ## See also: + ## * `option <#option,T>`_ + ## * `some <#some,T>`_ + ## * `isNone <#isNone,Option[T]>`_ runnableExamples: - assert none(int).isNone + var a = none(int) + assert a.isNone + assert $type(a) == "Option[system.int]" # the default is the none type discard -proc none*[T]: Option[T] {.inline.} = - ## Alias for `none(T) <#none,typedesc>`_. +proc none*[T]: Option[T] = + ## Alias for `none(T) proc <#none,typedesc>`_. none(T) proc isSome*[T](self: Option[T]): bool {.inline.} = ## Checks if an `Option` contains a value. - ## - ## **See also:** - ## * `isNone proc <#isNone,Option[T]>`_ - ## * `some proc <#some,T>`_ runnableExamples: - assert some(42).isSome - assert not none(string).isSome + var + a = some(42) + b = none(string) + assert a.isSome + assert not b.isSome when T is SomePointer: not self.val.isNil @@ -174,124 +152,136 @@ proc isSome*[T](self: Option[T]): bool {.inline.} = proc isNone*[T](self: Option[T]): bool {.inline.} = ## Checks if an `Option` is empty. - ## - ## **See also:** - ## * `isSome proc <#isSome,Option[T]>`_ - ## * `none proc <#none,typedesc>`_ runnableExamples: - assert not some(42).isNone - assert none(string).isNone - + var + a = some(42) + b = none(string) + assert not a.isNone + assert b.isNone when T is SomePointer: self.val.isNil else: not self.has -proc get*[T](self: Option[T]): lent T {.inline.} = - ## Returns the content of an `Option`. If it has no value, - ## an `UnpackDefect` exception is raised. +proc get*[T](self: Option[T]): T = + ## Returns contents of an `Option`. If it is `None`, then an exception is + ## thrown. ## - ## **See also:** - ## * `get proc <#get,Option[T],T>`_ with a default return value + ## See also: + ## * `get proc <#get,Option[T],T>`_ with the default return value runnableExamples: - assert some(42).get == 42 - doAssertRaises(UnpackDefect): - echo none(string).get + let + a = some(42) + b = none(string) + assert a.get == 42 + doAssertRaises(UnpackError): + echo b.get if self.isNone: - raise newException(UnpackDefect, "Can't obtain a value from a `none`") - result = self.val + raise newException(UnpackError, "Can't obtain a value from a `none`") + self.val -proc get*[T](self: Option[T], otherwise: T): T {.inline.} = - ## Returns the content of the `Option` or `otherwise` if - ## the `Option` has no value. +proc get*[T](self: Option[T], otherwise: T): T = + ## Returns the contents of the `Option` or an `otherwise` value if + ## the `Option` is `None`. runnableExamples: - assert some(42).get(9999) == 42 - assert none(int).get(9999) == 9999 + var + a = some(42) + b = none(int) + assert a.get(9999) == 42 + assert b.get(9999) == 9999 if self.isSome: self.val else: otherwise -proc get*[T](self: var Option[T]): var T {.inline.} = - ## Returns the content of the `var Option` mutably. If it has no value, - ## an `UnpackDefect` exception is raised. +proc get*[T](self: var Option[T]): var T = + ## Returns contents of the `var Option`. If it is `None`, then an exception + ## is thrown. runnableExamples: - var + let a = some(42) b = none(string) - inc(a.get) - assert a.get == 43 - doAssertRaises(UnpackDefect): + assert a.get == 42 + doAssertRaises(UnpackError): echo b.get if self.isNone: - raise newException(UnpackDefect, "Can't obtain a value from a `none`") + raise newException(UnpackError, "Can't obtain a value from a `none`") return self.val -proc map*[T](self: Option[T], callback: proc (input: T)) {.inline, effectsOf: callback.} = +proc map*[T](self: Option[T], callback: proc (input: T)) = ## Applies a `callback` function to the value of the `Option`, if it has one. ## - ## **See also:** + ## See also: ## * `map proc <#map,Option[T],proc(T)_2>`_ for a version with a callback ## which returns a value + ## * `filter proc <#filter,Option[T],proc(T)>`_ runnableExamples: var d = 0 proc saveDouble(x: int) = - d = 2 * x + d = 2*x - none(int).map(saveDouble) + let + a = some(42) + b = none(int) + + b.map(saveDouble) assert d == 0 - some(42).map(saveDouble) + a.map(saveDouble) assert d == 84 if self.isSome: callback(self.val) -proc map*[T, R](self: Option[T], callback: proc (input: T): R): Option[R] {.inline, effectsOf: callback.} = +proc map*[T, R](self: Option[T], callback: proc (input: T): R): Option[R] = ## Applies a `callback` function to the value of the `Option` and returns an ## `Option` containing the new value. ## - ## If the `Option` has no value, `none(R)` will be returned. + ## If the `Option` is `None`, `None` of the return type of the `callback` + ## will be returned. ## - ## **See also:** - ## * `map proc <#map,Option[T],proc(T)>`_ - ## * `flatMap proc <#flatMap,Option[T],proc(T)>`_ for a version with a - ## callback that returns an `Option` + ## See also: + ## * `flatMap proc <#flatMap,Option[A],proc(A)>`_ for a version with a + ## callback which returns an `Option` + ## * `filter proc <#filter,Option[T],proc(T)>`_ runnableExamples: + var + a = some(42) + b = none(int) + proc isEven(x: int): bool = x mod 2 == 0 - assert some(42).map(isEven) == some(true) - assert none(int).map(isEven) == none(bool) + assert $(a.map(isEven)) == "Some(true)" + assert $(b.map(isEven)) == "None[bool]" if self.isSome: some[R](callback(self.val)) else: none(R) -proc flatten*[T](self: Option[Option[T]]): Option[T] {.inline.} = +proc flatten*[A](self: Option[Option[A]]): Option[A] = ## Remove one level of structure in a nested `Option`. - ## - ## **See also:** - ## * `flatMap proc <#flatMap,Option[T],proc(T)>`_ runnableExamples: - assert flatten(some(some(42))) == some(42) - assert flatten(none(Option[int])) == none(int) + let a = some(some(42)) + assert $flatten(a) == "Some(42)" if self.isSome: self.val else: - none(T) + none(A) -proc flatMap*[T, R](self: Option[T], - callback: proc (input: T): Option[R]): Option[R] {.inline, effectsOf: callback.} = - ## Applies a `callback` function to the value of the `Option` and returns the new value. +proc flatMap*[A, B](self: Option[A], + callback: proc (input: A): Option[B]): Option[B] = + ## Applies a `callback` function to the value of the `Option` and returns an + ## `Option` containing the new value. ## - ## If the `Option` has no value, `none(R)` will be returned. + ## If the `Option` is `None`, `None` of the return type of the `callback` + ## will be returned. ## - ## This is similar to `map`, with the difference that the `callback` returns an + ## Similar to `map`, with the difference that the `callback` returns an ## `Option`, not a raw value. This allows multiple procs with a ## signature of `A -> Option[B]` to be chained together. ## @@ -301,40 +291,47 @@ proc flatMap*[T, R](self: Option[T], runnableExamples: proc doublePositives(x: int): Option[int] = if x > 0: - some(2 * x) + return some(2*x) else: - none(int) - - assert some(42).flatMap(doublePositives) == some(84) - assert none(int).flatMap(doublePositives) == none(int) - assert some(-11).flatMap(doublePositives) == none(int) + return none(int) + let + a = some(42) + b = none(int) + c = some(-11) + assert a.flatMap(doublePositives) == some(84) + assert b.flatMap(doublePositives) == none(int) + assert c.flatMap(doublePositives) == none(int) map(self, callback).flatten() -proc filter*[T](self: Option[T], callback: proc (input: T): bool): Option[T] {.inline, effectsOf: callback.} = +proc filter*[T](self: Option[T], callback: proc (input: T): bool): Option[T] = ## Applies a `callback` to the value of the `Option`. ## - ## If the `callback` returns `true`, the option is returned as `some`. - ## If it returns `false`, it is returned as `none`. + ## If the `callback` returns `true`, the option is returned as `Some`. + ## If it returns `false`, it is returned as `None`. ## - ## **See also:** + ## See also: + ## * `map proc <#map,Option[T],proc(T)_2>`_ ## * `flatMap proc <#flatMap,Option[A],proc(A)>`_ runnableExamples: proc isEven(x: int): bool = x mod 2 == 0 - - assert some(42).filter(isEven) == some(42) - assert none(int).filter(isEven) == none(int) - assert some(-11).filter(isEven) == none(int) + let + a = some(42) + b = none(int) + c = some(-11) + assert a.filter(isEven) == some(42) + assert b.filter(isEven) == none(int) + assert c.filter(isEven) == none(int) if self.isSome and not callback(self.val): none(T) else: self -proc `==`*[T](a, b: Option[T]): bool {.inline.} = - ## Returns `true` if both `Option`s are `none`, - ## or if they are both `some` and have equal values. +proc `==`*(a, b: Option): bool = + ## Returns `true` if both `Option`s are `None`, + ## or if they are both `Some` and have equal values. runnableExamples: let a = some(42) @@ -346,35 +343,165 @@ proc `==`*[T](a, b: Option[T]): bool {.inline.} = assert b == d assert not (a == b) - when T is SomePointer: - a.val == b.val - else: - (a.isSome and b.isSome and a.val == b.val) or (a.isNone and b.isNone) + (a.isSome and b.isSome and a.val == b.val) or (not a.isSome and not b.isSome) proc `$`*[T](self: Option[T]): string = ## Get the string representation of the `Option`. - runnableExamples: - assert $some(42) == "some(42)" - assert $none(int) == "none(int)" - + ## + ## If the `Option` has a value, the result will be `Some(x)` where `x` + ## is the string representation of the contained value. + ## If the `Option` does not have a value, the result will be `None[T]` + ## where `T` is the name of the type contained in the `Option`. if self.isSome: - when defined(nimLagacyOptionsDollar): - result = "Some(" - else: - result = "some(" + result = "Some(" result.addQuoted self.val result.add ")" else: - when defined(nimLagacyOptionsDollar): - result = "None[" & name(T) & "]" - else: - result = "none(" & name(T) & ")" + result = "None[" & name(T) & "]" -proc unsafeGet*[T](self: Option[T]): lent T {.inline.}= - ## Returns the value of a `some`. The behavior is undefined for `none`. +proc unsafeGet*[T](self: Option[T]): T = + ## Returns the value of a `some`. Behavior is undefined for `none`. ## - ## **Note:** Use this only when you are **absolutely sure** the value is present - ## (e.g. after checking with `isSome <#isSome,Option[T]>`_). - ## Generally, using the `get proc <#get,Option[T]>`_ is preferred. + ## **Note:** Use it only when you are **absolutely sure** the value is present + ## (e.g. after checking `isSome <#isSome,Option[T]>`_). + ## Generally, using `get proc <#get,Option[T]>`_ is preferred. assert self.isSome - result = self.val + self.val + + +when isMainModule: + import unittest, sequtils + + # RefPerson is used to test that overloaded `==` operator is not called by + # options. It is defined here in the global scope, because otherwise the test + # will not even consider the `==` operator. Different bug? + type RefPerson = ref object + name: string + + proc `==`(a, b: RefPerson): bool = + assert(not a.isNil and not b.isNil) + a.name == b.name + + suite "options": + # work around a bug in unittest + let intNone = none(int) + let stringNone = none(string) + + test "example": + proc find(haystack: string, needle: char): Option[int] = + for i, c in haystack: + if c == needle: + return some i + + check("abc".find('c').get() == 2) + + let result = "team".find('i') + + check result == intNone + check result.isNone + + test "some": + check some(6).get() == 6 + check some("a").unsafeGet() == "a" + check some(6).isSome + check some("a").isSome + + test "none": + expect UnpackError: + discard none(int).get() + check(none(int).isNone) + check(not none(string).isSome) + + test "equality": + check some("a") == some("a") + check some(7) != some(6) + check some("a") != stringNone + check intNone == intNone + + when compiles(some("a") == some(5)): + check false + when compiles(none(string) == none(int)): + check false + + test "get with a default value": + check(some("Correct").get("Wrong") == "Correct") + check(stringNone.get("Correct") == "Correct") + + test "$": + check($(some("Correct")) == "Some(\"Correct\")") + check($(stringNone) == "None[string]") + + test "map with a void result": + var procRan = 0 + some(123).map(proc (v: int) = procRan = v) + check procRan == 123 + intNone.map(proc (v: int) = check false) + + test "map": + check(some(123).map(proc (v: int): int = v * 2) == some(246)) + check(intNone.map(proc (v: int): int = v * 2).isNone) + + test "filter": + check(some(123).filter(proc (v: int): bool = v == 123) == some(123)) + check(some(456).filter(proc (v: int): bool = v == 123).isNone) + check(intNone.filter(proc (v: int): bool = check false).isNone) + + test "flatMap": + proc addOneIfNotZero(v: int): Option[int] = + if v != 0: + result = some(v + 1) + else: + result = none(int) + + check(some(1).flatMap(addOneIfNotZero) == some(2)) + check(some(0).flatMap(addOneIfNotZero) == none(int)) + check(some(1).flatMap(addOneIfNotZero).flatMap(addOneIfNotZero) == some(3)) + + proc maybeToString(v: int): Option[string] = + if v != 0: + result = some($v) + else: + result = none(string) + + check(some(1).flatMap(maybeToString) == some("1")) + + proc maybeExclaim(v: string): Option[string] = + if v != "": + result = some v & "!" + else: + result = none(string) + + check(some(1).flatMap(maybeToString).flatMap(maybeExclaim) == some("1!")) + check(some(0).flatMap(maybeToString).flatMap(maybeExclaim) == none(string)) + + test "SomePointer": + var intref: ref int + check(option(intref).isNone) + intref.new + check(option(intref).isSome) + + let tmp = option(intref) + check(sizeof(tmp) == sizeof(ptr int)) + + test "none[T]": + check(none[int]().isNone) + check(none(int) == none[int]()) + + test "$ on typed with .name": + type Named = object + name: string + + let nobody = none(Named) + check($nobody == "None[Named]") + + test "$ on type with name()": + type Person = object + myname: string + + let noperson = none(Person) + check($noperson == "None[Person]") + + test "Ref type with overloaded `==`": + let p = some(RefPerson.new()) + check p.isSome + diff --git a/lib/pure/os.nim b/lib/pure/os.nim index 0569e6cab..452c856a6 100644 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -8,70 +8,46 @@ # ## This module contains basic operating system facilities like -## retrieving environment variables, working with directories, -## running shell commands, etc. - -## .. importdoc:: symlinks.nim, appdirs.nim, dirs.nim, ospaths2.nim - -runnableExamples: - let myFile = "/path/to/my/file.nim" - assert splitPath(myFile) == (head: "/path/to/my", tail: "file.nim") - when defined(posix): - assert parentDir(myFile) == "/path/to/my" - assert splitFile(myFile) == (dir: "/path/to/my", name: "file", ext: ".nim") - assert myFile.changeFileExt("c") == "/path/to/my/file.c" +## retrieving environment variables, reading command line arguments, +## working with directories, running shell commands, etc. +## +## .. code-block:: +## import os +## +## let myFile = "/path/to/my/file.nim" +## +## let pathSplit = splitPath(myFile) +## assert pathSplit.head == "/path/to/my" +## assert pathSplit.tail == "file.nim" +## +## assert parentDir(myFile) == "/path/to/my" +## +## let fileSplit = splitFile(myFile) +## assert fileSplit.dir == "/path/to/my" +## assert fileSplit.name == "file" +## assert fileSplit.ext == ".nim" +## +## assert myFile.changeFileExt("c") == "/path/to/my/file.c" +## +## ## **See also:** ## * `osproc module `_ for process communication beyond -## `execShellCmd proc`_ +## `execShellCmd proc <#execShellCmd,string>`_ +## * `parseopt module `_ for command-line parser beyond +## `parseCmdLine proc <#parseCmdLine,string>`_ ## * `uri module `_ ## * `distros module `_ ## * `dynlib module `_ ## * `streams module `_ -import std/private/ospaths2 -export ospaths2 -import std/private/osfiles -export osfiles +include "system/inclrtl" -import std/private/osdirs -export osdirs - -import std/private/ossymlinks -export ossymlinks - -import std/private/osappdirs -export osappdirs - -import std/private/oscommon - -include system/inclrtl -import std/private/since - -import std/cmdline -export cmdline - -import strutils, pathnorm - -when defined(nimPreviewSlimSystem): - import std/[syncio, assertions, widestrs] +import + strutils, pathnorm const weirdTarget = defined(nimscript) or defined(js) -since (1, 1): - const - invalidFilenameChars* = {'/', '\\', ':', '*', '?', '"', '<', '>', '|', '^', '\0'} ## \ - ## Characters that may produce invalid filenames across Linux, Windows and Mac. - ## You can check if your filename contains any of these chars and strip them for safety. - ## Mac bans ``':'``, Linux bans ``'/'``, Windows bans all others. - invalidFilenames* = [ - "CON", "PRN", "AUX", "NUL", - "COM0", "COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9", - "LPT0", "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9"] ## \ - ## Filenames that may be invalid across Linux, Windows, Mac, etc. - ## You can check if your filename match these and rename it for safety - ## (Currently all invalid filenames are from Windows only). - when weirdTarget: discard elif defined(windows): @@ -84,44 +60,864 @@ elif defined(posix): else: {.error: "OS module not ported to your operating system!".} -when weirdTarget: - {.pragma: noWeirdTarget, error: "this proc is not available on the NimScript/js target".} +when weirdTarget and defined(nimErrorProcCanHaveBody): + {.pragma: noNimScript, error: "this proc is not available on the NimScript target".} else: - {.pragma: noWeirdTarget.} + {.pragma: noNimScript.} -when defined(nimscript): - # for procs already defined in scriptconfig.nim - template noNimJs(body): untyped = discard -elif defined(js): - {.pragma: noNimJs, error: "this proc is not available on the js target".} +type + ReadEnvEffect* = object of ReadIOEffect ## Effect that denotes a read + ## from an environment variable. + WriteEnvEffect* = object of WriteIOEffect ## Effect that denotes a write + ## to an environment variable. + + ReadDirEffect* = object of ReadIOEffect ## Effect that denotes a read + ## operation from the directory + ## structure. + WriteDirEffect* = object of WriteIOEffect ## Effect that denotes a write + ## operation to + ## the directory structure. + + OSErrorCode* = distinct int32 ## Specifies an OS Error Code. + +include "includes/osseps" + +proc normalizePathEnd(path: var string, trailingSep = false) = + ## Ensures ``path`` has exactly 0 or 1 trailing `DirSep`, depending on + ## ``trailingSep``, and taking care of edge cases: it preservers whether + ## a path is absolute or relative, and makes sure trailing sep is `DirSep`, + ## not `AltSep`. Trailing `/.` are compressed, see examples. + if path.len == 0: return + var i = path.len + while i >= 1: + if path[i-1] in {DirSep, AltSep}: dec(i) + elif path[i-1] == '.' and i >= 2 and path[i-2] in {DirSep, AltSep}: dec(i) + else: break + if trailingSep: + # foo// => foo + path.setLen(i) + # foo => foo/ + path.add DirSep + elif i > 0: + # foo// => foo + path.setLen(i) + else: + # // => / (empty case was already taken care of) + path = $DirSep + +proc normalizePathEnd(path: string, trailingSep = false): string = + ## outplace overload + runnableExamples: + when defined(posix): + assert normalizePathEnd("/lib//.//", trailingSep = true) == "/lib/" + assert normalizePathEnd("lib/./.", trailingSep = false) == "lib" + assert normalizePathEnd(".//./.", trailingSep = false) == "." + assert normalizePathEnd("", trailingSep = true) == "" # not / ! + assert normalizePathEnd("/", trailingSep = false) == "/" # not "" ! + result = path + result.normalizePathEnd(trailingSep) + +since((1, 1)): + export normalizePathEnd + +proc joinPath*(head, tail: string): string {. + noSideEffect, rtl, extern: "nos$1".} = + ## Joins two directory names to one. + ## + ## If `head` is the empty string, `tail` is returned. If `tail` is the empty + ## string, `head` is returned with a trailing path separator. If `tail` starts + ## with a path separator it will be removed when concatenated to `head`. + ## Path separators will be normalized. + ## + ## See also: + ## * `joinPath(varargs) proc <#joinPath,varargs[string]>`_ + ## * `/ proc <#/,string,string>`_ + ## * `splitPath proc <#splitPath,string>`_ + ## * `uri.combine proc `_ + ## * `uri./ proc `_ + runnableExamples: + when defined(posix): + assert joinPath("usr", "lib") == "usr/lib" + assert joinPath("usr", "") == "usr/" + assert joinPath("", "lib") == "lib" + assert joinPath("", "/lib") == "/lib" + assert joinPath("usr/", "/lib") == "usr/lib" + assert joinPath("usr/lib", "../bin") == "usr/bin" + + result = newStringOfCap(head.len + tail.len) + var state = 0 + addNormalizePath(head, result, state, DirSep) + if tail.len == 0: + result.add DirSep + else: + addNormalizePath(tail, result, state, DirSep) + when false: + if len(head) == 0: + result = tail + elif head[len(head)-1] in {DirSep, AltSep}: + if tail.len > 0 and tail[0] in {DirSep, AltSep}: + result = head & substr(tail, 1) + else: + result = head & tail + else: + if tail.len > 0 and tail[0] in {DirSep, AltSep}: + result = head & tail + else: + result = head & DirSep & tail + +proc joinPath*(parts: varargs[string]): string {.noSideEffect, + rtl, extern: "nos$1OpenArray".} = + ## The same as `joinPath(head, tail) proc <#joinPath,string,string>`_, + ## but works with any number of directory parts. + ## + ## You need to pass at least one element or the proc + ## will assert in debug builds and crash on release builds. + ## + ## See also: + ## * `joinPath(head, tail) proc <#joinPath,string,string>`_ + ## * `/ proc <#/,string,string>`_ + ## * `/../ proc <#/../,string,string>`_ + ## * `splitPath proc <#splitPath,string>`_ + runnableExamples: + when defined(posix): + assert joinPath("a") == "a" + assert joinPath("a", "b", "c") == "a/b/c" + assert joinPath("usr/lib", "../../var", "log") == "var/log" + + var estimatedLen = 0 + for p in parts: estimatedLen += p.len + result = newStringOfCap(estimatedLen) + var state = 0 + for i in 0..high(parts): + addNormalizePath(parts[i], result, state, DirSep) + +proc `/`*(head, tail: string): string {.noSideEffect.} = + ## The same as `joinPath(head, tail) proc <#joinPath,string,string>`_. + ## + ## See also: + ## * `/../ proc <#/../,string,string>`_ + ## * `joinPath(head, tail) proc <#joinPath,string,string>`_ + ## * `joinPath(varargs) proc <#joinPath,varargs[string]>`_ + ## * `splitPath proc <#splitPath,string>`_ + ## * `uri.combine proc `_ + ## * `uri./ proc `_ + runnableExamples: + when defined(posix): + assert "usr" / "" == "usr/" + assert "" / "lib" == "lib" + assert "" / "/lib" == "/lib" + assert "usr/" / "/lib" == "usr/lib" + assert "usr" / "lib" / "../bin" == "usr/bin" + + return joinPath(head, tail) + +proc splitPath*(path: string): tuple[head, tail: string] {. + noSideEffect, rtl, extern: "nos$1".} = + ## Splits a directory into `(head, tail)` tuple, so that + ## ``head / tail == path`` (except for edge cases like "/usr"). + ## + ## See also: + ## * `joinPath(head, tail) proc <#joinPath,string,string>`_ + ## * `joinPath(varargs) proc <#joinPath,varargs[string]>`_ + ## * `/ proc <#/,string,string>`_ + ## * `/../ proc <#/../,string,string>`_ + ## * `relativePath proc <#relativePath,string,string>`_ + runnableExamples: + assert splitPath("usr/local/bin") == ("usr/local", "bin") + assert splitPath("usr/local/bin/") == ("usr/local/bin", "") + assert splitPath("/bin/") == ("/bin", "") + when (NimMajor, NimMinor) <= (1, 0): + assert splitPath("/bin") == ("", "bin") + else: + assert splitPath("/bin") == ("/", "bin") + assert splitPath("bin") == ("", "bin") + assert splitPath("") == ("", "") + + var sepPos = -1 + for i in countdown(len(path)-1, 0): + if path[i] in {DirSep, AltSep}: + sepPos = i + break + if sepPos >= 0: + result.head = substr(path, 0, + when (NimMajor, NimMinor) <= (1, 0): + sepPos-1 + else: + if likely(sepPos >= 1): sepPos-1 else: 0 + ) + result.tail = substr(path, sepPos+1) + else: + result.head = "" + result.tail = path + +proc isAbsolute*(path: string): bool {.rtl, noSideEffect, extern: "nos$1", raises: [].} = + ## Checks whether a given `path` is absolute. + ## + ## On Windows, network paths are considered absolute too. + runnableExamples: + assert not "".isAbsolute + assert not ".".isAbsolute + when defined(posix): + assert "/".isAbsolute + assert not "a/".isAbsolute + assert "/a/".isAbsolute + + if len(path) == 0: return false + + when doslikeFileSystem: + var len = len(path) + result = (path[0] in {'/', '\\'}) or + (len > 1 and path[0] in {'a'..'z', 'A'..'Z'} and path[1] == ':') + elif defined(macos): + # according to https://perldoc.perl.org/File/Spec/Mac.html `:a` is a relative path + result = path[0] != ':' + elif defined(RISCOS): + result = path[0] == '$' + elif defined(posix): + result = path[0] == '/' + +when FileSystemCaseSensitive: + template `!=?`(a, b: char): bool = a != b else: - {.pragma: noNimJs.} + template `!=?`(a, b: char): bool = toLowerAscii(a) != toLowerAscii(b) +when doslikeFileSystem: + proc isAbsFromCurrentDrive(path: string): bool {.noSideEffect, raises: []} = + ## An absolute path from the root of the current drive (e.g. "\foo") + path.len > 0 and + (path[0] == AltSep or + (path[0] == DirSep and + (path.len == 1 or path[1] notin {DirSep, AltSep, ':'}))) -import std/oserrors -export oserrors -import std/envvars -export envvars + proc isUNCPrefix(path: string): bool {.noSideEffect, raises: []} = + path[0] == DirSep and path[1] == DirSep -import std/private/osseps -export osseps + proc sameRoot(path1, path2: string): bool {.noSideEffect, raises: []} = + ## Return true if path1 and path2 have a same root. + ## + ## Detail of windows path formats: + ## https://docs.microsoft.com/en-us/dotnet/standard/io/file-path-formats + assert(isAbsolute(path1)) + assert(isAbsolute(path2)) + let + len1 = path1.len + len2 = path2.len + assert(len1 != 0 and len2 != 0) + + if isAbsFromCurrentDrive(path1) and isAbsFromCurrentDrive(path2): + return true + elif len1 == 1 or len2 == 1: + return false + else: + if path1[1] == ':' and path2[1] == ':': + return path1[0].toLowerAscii() == path2[0].toLowerAscii() + else: + var + p1, p2: PathIter + pp1 = next(p1, path1) + pp2 = next(p2, path2) + if pp1[1] - pp1[0] == 1 and pp2[1] - pp2[0] == 1 and + isUNCPrefix(path1) and isUNCPrefix(path2): + #UNC + var h = 0 + while p1.hasNext(path1) and p2.hasNext(path2) and h < 2: + pp1 = next(p1, path1) + pp2 = next(p2, path2) + let diff = pp1[1] - pp1[0] + if diff != pp2[1] - pp2[0]: + return false + for i in 0..diff: + if path1[i + pp1[0]] !=? path2[i + pp2[0]]: + return false + inc h + return h == 2 + else: + return false + +proc relativePath*(path, base: string; sep = DirSep): string {. + noSideEffect, rtl, extern: "nos$1", raises: [].} = + ## Converts `path` to a path relative to `base`. + ## + ## The `sep` (default: `DirSep <#DirSep>`_) is used for the path normalizations, + ## this can be useful to ensure the relative path only contains `'/'` + ## so that it can be used for URL constructions. + ## + ## On windows, if a root of `path` and a root of `base` are different, + ## returns `path` as is because it is impossible to make a relative path. + ## That means an absolute path can be returned. + ## + ## See also: + ## * `splitPath proc <#splitPath,string>`_ + ## * `parentDir proc <#parentDir,string>`_ + ## * `tailDir proc <#tailDir,string>`_ + runnableExamples: + assert relativePath("/Users/me/bar/z.nim", "/Users/other/bad", '/') == "../../me/bar/z.nim" + assert relativePath("/Users/me/bar/z.nim", "/Users/other", '/') == "../me/bar/z.nim" + assert relativePath("/Users///me/bar//z.nim", "//Users/", '/') == "me/bar/z.nim" + assert relativePath("/Users/me/bar/z.nim", "/Users/me", '/') == "bar/z.nim" + assert relativePath("", "/users/moo", '/') == "" + assert relativePath("foo", ".", '/') == "foo" + + if path.len == 0: return "" + let base = if base == ".": "" else: base + + when doslikeFileSystem: + if isAbsolute(path) and isAbsolute(base): + if not sameRoot(path, base): + return path + + var f, b: PathIter + var ff = (0, -1) + var bb = (0, -1) # (int, int) + result = newStringOfCap(path.len) + # skip the common prefix: + while f.hasNext(path) and b.hasNext(base): + ff = next(f, path) + bb = next(b, base) + let diff = ff[1] - ff[0] + if diff != bb[1] - bb[0]: break + var same = true + for i in 0..diff: + if path[i + ff[0]] !=? base[i + bb[0]]: + same = false + break + if not same: break + ff = (0, -1) + bb = (0, -1) + # for i in 0..diff: + # result.add base[i + bb[0]] + + # /foo/bar/xxx/ -- base + # /foo/bar/baz -- path path + # ../baz + # every directory that is in 'base', needs to add '..' + while true: + if bb[1] >= bb[0]: + if result.len > 0 and result[^1] != sep: + result.add sep + result.add ".." + if not b.hasNext(base): break + bb = b.next(base) + + # add the rest of 'path': + while true: + if ff[1] >= ff[0]: + if result.len > 0 and result[^1] != sep: + result.add sep + for i in 0..ff[1] - ff[0]: + result.add path[i + ff[0]] + if not f.hasNext(path): break + ff = f.next(path) + +proc isRelativeTo*(path: string, base: string): bool {.since: (1, 1).} = + ## Returns true if `path` is relative to `base`. + runnableExamples: + doAssert isRelativeTo("./foo//bar", "foo") + doAssert isRelativeTo("foo/bar", ".") + doAssert isRelativeTo("/foo/bar.nim", "/foo/bar.nim") + doAssert not isRelativeTo("foo/bar.nims", "foo/bar.nim") + let path = path.normalizePath + let base = base.normalizePath + let ret = relativePath(path, base) + result = path.len > 0 and not ret.startsWith ".." + +proc parentDirPos(path: string): int = + var q = 1 + if len(path) >= 1 and path[len(path)-1] in {DirSep, AltSep}: q = 2 + for i in countdown(len(path)-q, 0): + if path[i] in {DirSep, AltSep}: return i + result = -1 + +proc parentDir*(path: string): string {. + noSideEffect, rtl, extern: "nos$1".} = + ## Returns the parent directory of `path`. + ## + ## This is similar to ``splitPath(path).head`` when ``path`` doesn't end + ## in a dir separator, but also takes care of path normalizations. + ## The remainder can be obtained with `lastPathPart(path) proc + ## <#lastPathPart,string>`_. + ## + ## See also: + ## * `relativePath proc <#relativePath,string,string>`_ + ## * `splitPath proc <#splitPath,string>`_ + ## * `tailDir proc <#tailDir,string>`_ + ## * `parentDirs iterator <#parentDirs.i,string>`_ + runnableExamples: + assert parentDir("") == "" + when defined(posix): + assert parentDir("/usr/local/bin") == "/usr/local" + assert parentDir("foo/bar//") == "foo" + assert parentDir("//foo//bar//.") == "/foo" + assert parentDir("./foo") == "." + assert parentDir("/./foo//./") == "/" + assert parentDir("a//./") == "." + assert parentDir("a/b/c/..") == "a" + result = pathnorm.normalizePath(path) + var sepPos = parentDirPos(result) + if sepPos >= 0: + result = substr(result, 0, sepPos) + normalizePathEnd(result) + elif result == ".." or result == "." or result.len == 0 or result[^1] in {DirSep, AltSep}: + # `.` => `..` and .. => `../..`(etc) would be a sensible alternative + # `/` => `/` (as done with splitFile) would be a sensible alternative + result = "" + else: + result = "." + +proc tailDir*(path: string): string {. + noSideEffect, rtl, extern: "nos$1".} = + ## Returns the tail part of `path`. + ## + ## See also: + ## * `relativePath proc <#relativePath,string,string>`_ + ## * `splitPath proc <#splitPath,string>`_ + ## * `parentDir proc <#parentDir,string>`_ + runnableExamples: + assert tailDir("/bin") == "bin" + assert tailDir("bin") == "" + assert tailDir("bin/") == "" + assert tailDir("/usr/local/bin") == "usr/local/bin" + assert tailDir("//usr//local//bin//") == "usr//local//bin//" + assert tailDir("./usr/local/bin") == "usr/local/bin" + assert tailDir("usr/local/bin") == "local/bin" + + var i = 0 + while i < len(path): + if path[i] in {DirSep, AltSep}: + while i < len(path) and path[i] in {DirSep, AltSep}: inc i + return substr(path, i) + inc i + result = "" + +proc isRootDir*(path: string): bool {. + noSideEffect, rtl, extern: "nos$1".} = + ## Checks whether a given `path` is a root directory. + runnableExamples: + assert isRootDir("") + assert isRootDir(".") + assert isRootDir("/") + assert isRootDir("a") + assert not isRootDir("/a") + assert not isRootDir("a/b/c") + + result = parentDirPos(path) < 0 + +iterator parentDirs*(path: string, fromRoot=false, inclusive=true): string = + ## Walks over all parent directories of a given `path`. + ## + ## If `fromRoot` is true (default: false), the traversal will start from + ## the file system root directory. + ## If `inclusive` is true (default), the original argument will be included + ## in the traversal. + ## + ## Relative paths won't be expanded by this iterator. Instead, it will traverse + ## only the directories appearing in the relative path. + ## + ## See also: + ## * `parentDir proc <#parentDir,string>`_ + ## + ## **Examples:** + ## + ## .. code-block:: + ## let g = "a/b/c" + ## + ## for p in g.parentDirs: + ## echo p + ## # a/b/c + ## # a/b + ## # a + ## + ## for p in g.parentDirs(fromRoot=true): + ## echo p + ## # a/ + ## # a/b/ + ## # a/b/c + ## + ## for p in g.parentDirs(inclusive=false): + ## echo p + ## # a/b + ## # a + + if not fromRoot: + var current = path + if inclusive: yield path + while true: + if current.isRootDir: break + current = current.parentDir + yield current + else: + for i in countup(0, path.len - 2): # ignore the last / + # deal with non-normalized paths such as /foo//bar//baz + if path[i] in {DirSep, AltSep} and + (i == 0 or path[i-1] notin {DirSep, AltSep}): + yield path.substr(0, i) + + if inclusive: yield path + +proc `/../`*(head, tail: string): string {.noSideEffect.} = + ## The same as ``parentDir(head) / tail``, unless there is no parent + ## directory. Then ``head / tail`` is performed instead. + ## + ## See also: + ## * `/ proc <#/,string,string>`_ + ## * `parentDir proc <#parentDir,string>`_ + runnableExamples: + when defined(posix): + assert "a/b/c" /../ "d/e" == "a/b/d/e" + assert "a" /../ "d/e" == "a/d/e" + + let sepPos = parentDirPos(head) + if sepPos >= 0: + result = substr(head, 0, sepPos-1) / tail + else: + result = head / tail + +proc normExt(ext: string): string = + if ext == "" or ext[0] == ExtSep: result = ext # no copy needed here + else: result = ExtSep & ext + +proc searchExtPos*(path: string): int = + ## Returns index of the `'.'` char in `path` if it signifies the beginning + ## of extension. Returns -1 otherwise. + ## + ## See also: + ## * `splitFile proc <#splitFile,string>`_ + ## * `extractFilename proc <#extractFilename,string>`_ + ## * `lastPathPart proc <#lastPathPart,string>`_ + ## * `changeFileExt proc <#changeFileExt,string,string>`_ + ## * `addFileExt proc <#addFileExt,string,string>`_ + runnableExamples: + assert searchExtPos("a/b/c") == -1 + assert searchExtPos("c.nim") == 1 + assert searchExtPos("a/b/c.nim") == 5 + assert searchExtPos("a.b.c.nim") == 5 + + # BUGFIX: do not search until 0! .DS_Store is no file extension! + result = -1 + for i in countdown(len(path)-1, 1): + if path[i] == ExtSep: + result = i + break + elif path[i] in {DirSep, AltSep}: + break # do not skip over path + +proc splitFile*(path: string): tuple[dir, name, ext: string] {. + noSideEffect, rtl, extern: "nos$1".} = + ## Splits a filename into `(dir, name, extension)` tuple. + ## + ## `dir` does not end in `DirSep <#DirSep>`_ unless it's `/`. + ## `extension` includes the leading dot. + ## + ## If `path` has no extension, `ext` is the empty string. + ## If `path` has no directory component, `dir` is the empty string. + ## If `path` has no filename component, `name` and `ext` are empty strings. + ## + ## See also: + ## * `searchExtPos proc <#searchExtPos,string>`_ + ## * `extractFilename proc <#extractFilename,string>`_ + ## * `lastPathPart proc <#lastPathPart,string>`_ + ## * `changeFileExt proc <#changeFileExt,string,string>`_ + ## * `addFileExt proc <#addFileExt,string,string>`_ + runnableExamples: + var (dir, name, ext) = splitFile("usr/local/nimc.html") + assert dir == "usr/local" + assert name == "nimc" + assert ext == ".html" + (dir, name, ext) = splitFile("/usr/local/os") + assert dir == "/usr/local" + assert name == "os" + assert ext == "" + (dir, name, ext) = splitFile("/usr/local/") + assert dir == "/usr/local" + assert name == "" + assert ext == "" + (dir, name, ext) = splitFile("/tmp.txt") + assert dir == "/" + assert name == "tmp" + assert ext == ".txt" + + var namePos = 0 + var dotPos = 0 + for i in countdown(len(path) - 1, 0): + if path[i] in {DirSep, AltSep} or i == 0: + if path[i] in {DirSep, AltSep}: + result.dir = substr(path, 0, if likely(i >= 1): i - 1 else: 0) + namePos = i + 1 + if dotPos > i: + result.name = substr(path, namePos, dotPos - 1) + result.ext = substr(path, dotPos) + else: + result.name = substr(path, namePos) + break + elif path[i] == ExtSep and i > 0 and i < len(path) - 1 and + path[i - 1] notin {DirSep, AltSep} and + path[i + 1] != ExtSep and dotPos == 0: + dotPos = i + +proc extractFilename*(path: string): string {. + noSideEffect, rtl, extern: "nos$1".} = + ## Extracts the filename of a given `path`. + ## + ## This is the same as ``name & ext`` from `splitFile(path) proc + ## <#splitFile,string>`_. + ## + ## See also: + ## * `searchExtPos proc <#searchExtPos,string>`_ + ## * `splitFile proc <#splitFile,string>`_ + ## * `lastPathPart proc <#lastPathPart,string>`_ + ## * `changeFileExt proc <#changeFileExt,string,string>`_ + ## * `addFileExt proc <#addFileExt,string,string>`_ + runnableExamples: + assert extractFilename("foo/bar/") == "" + assert extractFilename("foo/bar") == "bar" + assert extractFilename("foo/bar.baz") == "bar.baz" + + if path.len == 0 or path[path.len-1] in {DirSep, AltSep}: + result = "" + else: + result = splitPath(path).tail + +proc lastPathPart*(path: string): string {. + noSideEffect, rtl, extern: "nos$1".} = + ## Like `extractFilename proc <#extractFilename,string>`_, but ignores + ## trailing dir separator; aka: `baseName`:idx: in some other languages. + ## + ## See also: + ## * `searchExtPos proc <#searchExtPos,string>`_ + ## * `splitFile proc <#splitFile,string>`_ + ## * `extractFilename proc <#extractFilename,string>`_ + ## * `changeFileExt proc <#changeFileExt,string,string>`_ + ## * `addFileExt proc <#addFileExt,string,string>`_ + runnableExamples: + assert lastPathPart("foo/bar/") == "bar" + assert lastPathPart("foo/bar") == "bar" + + let path = path.normalizePathEnd(trailingSep = false) + result = extractFilename(path) + +proc changeFileExt*(filename, ext: string): string {. + noSideEffect, rtl, extern: "nos$1".} = + ## Changes the file extension to `ext`. + ## + ## If the `filename` has no extension, `ext` will be added. + ## If `ext` == "" then any extension is removed. + ## + ## `Ext` should be given without the leading `'.'`, because some + ## filesystems may use a different character. (Although I know + ## of none such beast.) + ## + ## See also: + ## * `searchExtPos proc <#searchExtPos,string>`_ + ## * `splitFile proc <#splitFile,string>`_ + ## * `extractFilename proc <#extractFilename,string>`_ + ## * `lastPathPart proc <#lastPathPart,string>`_ + ## * `addFileExt proc <#addFileExt,string,string>`_ + runnableExamples: + assert changeFileExt("foo.bar", "baz") == "foo.baz" + assert changeFileExt("foo.bar", "") == "foo" + assert changeFileExt("foo", "baz") == "foo.baz" + + var extPos = searchExtPos(filename) + if extPos < 0: result = filename & normExt(ext) + else: result = substr(filename, 0, extPos-1) & normExt(ext) + +proc addFileExt*(filename, ext: string): string {. + noSideEffect, rtl, extern: "nos$1".} = + ## Adds the file extension `ext` to `filename`, unless + ## `filename` already has an extension. + ## + ## `Ext` should be given without the leading `'.'`, because some + ## filesystems may use a different character. + ## (Although I know of none such beast.) + ## + ## See also: + ## * `searchExtPos proc <#searchExtPos,string>`_ + ## * `splitFile proc <#splitFile,string>`_ + ## * `extractFilename proc <#extractFilename,string>`_ + ## * `lastPathPart proc <#lastPathPart,string>`_ + ## * `changeFileExt proc <#changeFileExt,string,string>`_ + runnableExamples: + assert addFileExt("foo.bar", "baz") == "foo.bar" + assert addFileExt("foo.bar", "") == "foo.bar" + assert addFileExt("foo", "baz") == "foo.baz" + + var extPos = searchExtPos(filename) + if extPos < 0: result = filename & normExt(ext) + else: result = filename + +proc cmpPaths*(pathA, pathB: string): int {. + noSideEffect, rtl, extern: "nos$1".} = + ## Compares two paths. + ## + ## On a case-sensitive filesystem this is done + ## case-sensitively otherwise case-insensitively. Returns: + ## + ## | 0 iff pathA == pathB + ## | < 0 iff pathA < pathB + ## | > 0 iff pathA > pathB + runnableExamples: + when defined(macosx): + assert cmpPaths("foo", "Foo") == 0 + elif defined(posix): + assert cmpPaths("foo", "Foo") > 0 + + let a = normalizePath(pathA) + let b = normalizePath(pathB) + if FileSystemCaseSensitive: + result = cmp(a, b) + else: + when defined(nimscript): + result = cmpic(a, b) + elif defined(nimdoc): discard + else: + result = cmpIgnoreCase(a, b) + +proc unixToNativePath*(path: string, drive=""): string {. + noSideEffect, rtl, extern: "nos$1".} = + ## Converts an UNIX-like path to a native one. + ## + ## On an UNIX system this does nothing. Else it converts + ## `'/'`, `'.'`, `'..'` to the appropriate things. + ## + ## On systems with a concept of "drives", `drive` is used to determine + ## which drive label to use during absolute path conversion. + ## `drive` defaults to the drive of the current working directory, and is + ## ignored on systems that do not have a concept of "drives". + when defined(unix): + result = path + else: + if path.len == 0: return "" + + var start: int + if path[0] == '/': + # an absolute path + when doslikeFileSystem: + if drive != "": + result = drive & ":" & DirSep + else: + result = $DirSep + elif defined(macos): + result = "" # must not start with ':' + else: + result = $DirSep + start = 1 + elif path[0] == '.' and (path.len == 1 or path[1] == '/'): + # current directory + result = $CurDir + start = when doslikeFileSystem: 1 else: 2 + else: + result = "" + start = 0 + + var i = start + while i < len(path): # ../../../ --> :::: + if i+2 < path.len and path[i] == '.' and path[i+1] == '.' and path[i+2] == '/': + # parent directory + when defined(macos): + if result[high(result)] == ':': + add result, ':' + else: + add result, ParDir + else: + add result, ParDir & DirSep + inc(i, 3) + elif path[i] == '/': + add result, DirSep + inc(i) + else: + add result, path[i] + inc(i) + +include "includes/oserr" +when not defined(nimscript): + include "includes/osenv" + +proc getHomeDir*(): string {.rtl, extern: "nos$1", + tags: [ReadEnvEffect, ReadIOEffect].} = + ## Returns the home directory of the current user. + ## + ## This proc is wrapped by the `expandTilde proc <#expandTilde,string>`_ + ## for the convenience of processing paths coming from user configuration files. + ## + ## See also: + ## * `getConfigDir proc <#getConfigDir>`_ + ## * `getTempDir proc <#getTempDir>`_ + ## * `expandTilde proc <#expandTilde,string>`_ + ## * `getCurrentDir proc <#getCurrentDir>`_ + ## * `setCurrentDir proc <#setCurrentDir,string>`_ + runnableExamples: + assert getHomeDir() == expandTilde("~") + + when defined(windows): return string(getEnv("USERPROFILE")) & "\\" + else: return string(getEnv("HOME")) & "/" + +proc getConfigDir*(): string {.rtl, extern: "nos$1", + tags: [ReadEnvEffect, ReadIOEffect].} = + ## Returns the config directory of the current user for applications. + ## + ## On non-Windows OSs, this proc conforms to the XDG Base Directory + ## spec. Thus, this proc returns the value of the `XDG_CONFIG_HOME` environment + ## variable if it is set, otherwise it returns the default configuration + ## directory ("~/.config/"). + ## + ## An OS-dependent trailing slash is always present at the end of the + ## returned string: `\\` on Windows and `/` on all other OSs. + ## + ## See also: + ## * `getHomeDir proc <#getHomeDir>`_ + ## * `getTempDir proc <#getTempDir>`_ + ## * `expandTilde proc <#expandTilde,string>`_ + ## * `getCurrentDir proc <#getCurrentDir>`_ + ## * `setCurrentDir proc <#setCurrentDir,string>`_ + when defined(windows): + result = getEnv("APPDATA").string + else: + result = getEnv("XDG_CONFIG_HOME", getEnv("HOME").string / ".config").string + result.normalizePathEnd(trailingSep = true) + +proc getTempDir*(): string {.rtl, extern: "nos$1", + tags: [ReadEnvEffect, ReadIOEffect].} = + ## Returns the temporary directory of the current user for applications to + ## save temporary files in. + ## + ## **Please do not use this**: On Android, it currently + ## returns ``getHomeDir()``, and on other Unix based systems it can cause + ## security problems too. That said, you can override this implementation + ## by adding ``-d:tempDir=mytempname`` to your compiler invocation. + ## + ## See also: + ## * `getHomeDir proc <#getHomeDir>`_ + ## * `getConfigDir proc <#getConfigDir>`_ + ## * `expandTilde proc <#expandTilde,string>`_ + ## * `getCurrentDir proc <#getCurrentDir>`_ + ## * `setCurrentDir proc <#setCurrentDir,string>`_ + const tempDirDefault = "/tmp" + result = tempDirDefault + when defined(tempDir): + const tempDir {.strdefine.}: string = tempDirDefault + result = tempDir + elif defined(windows): result = string(getEnv("TEMP")) + elif defined(android): result = getHomeDir() + else: + if existsEnv("TMPDIR"): result = string(getEnv("TMPDIR")) + normalizePathEnd(result, trailingSep=true) proc expandTilde*(path: string): string {. tags: [ReadEnvEffect, ReadIOEffect].} = ## Expands ``~`` or a path starting with ``~/`` to a full path, replacing - ## ``~`` with `getHomeDir()`_ (otherwise returns ``path`` unmodified). + ## ``~`` with `getHomeDir() <#getHomeDir>`_ (otherwise returns ``path`` unmodified). ## - ## Windows: this is still supported despite the Windows platform not having this + ## Windows: this is still supported despite Windows platform not having this ## convention; also, both ``~/`` and ``~\`` are handled. ## ## See also: - ## * `getHomeDir proc`_ - ## * `getConfigDir proc`_ - ## * `getTempDir proc`_ - ## * `getCurrentDir proc`_ - ## * `setCurrentDir proc`_ + ## * `getHomeDir proc <#getHomeDir>`_ + ## * `getConfigDir proc <#getConfigDir>`_ + ## * `getTempDir proc <#getTempDir>`_ + ## * `getCurrentDir proc <#getCurrentDir>`_ + ## * `setCurrentDir proc <#setCurrentDir,string>`_ runnableExamples: assert expandTilde("~" / "appname.cfg") == getHomeDir() / "appname.cfg" assert expandTilde("~/foo/bar") == getHomeDir() / "foo/bar" @@ -137,12 +933,15 @@ proc expandTilde*(path: string): string {. # TODO: handle `~bob` and `~bob/` which means home of bob result = path +# TODO: consider whether quoteShellPosix, quoteShellWindows, quoteShell, quoteShellCommand +# belong in `strutils` instead; they are not specific to paths proc quoteShellWindows*(s: string): string {.noSideEffect, rtl, extern: "nosp$1".} = ## Quote `s`, so it can be safely passed to Windows API. ## ## Based on Python's `subprocess.list2cmdline`. ## See `this link `_ ## for more details. + let needQuote = {' ', '\t'} in s or s.len == 0 result = "" var backslashBuff = "" @@ -153,8 +952,8 @@ proc quoteShellWindows*(s: string): string {.noSideEffect, rtl, extern: "nosp$1" if c == '\\': backslashBuff.add(c) elif c == '\"': - for i in 0.. 0: - result.add(backslashBuff) if needQuote: - result.add(backslashBuff) result.add("\"") - proc quoteShellPosix*(s: string): string {.noSideEffect, rtl, extern: "nosp$1".} = ## Quote ``s``, so it can be safely passed to POSIX shell. + ## Based on Python's `pipes.quote`. const safeUnixChars = {'%', '+', '-', '.', '/', '_', ':', '=', '@', '0'..'9', 'A'..'Z', 'a'..'z'} if s.len == 0: - result = "''" - elif s.allCharsInSet(safeUnixChars): - result = s + return "''" + + let safe = s.allCharsInSet(safeUnixChars) + + if safe: + return s else: - result = "'" & s.replace("'", "'\"'\"'") & "'" + return "'" & s.replace("'", "'\"'\"'") & "'" when defined(windows) or defined(posix) or defined(nintendoswitch): proc quoteShell*(s: string): string {.noSideEffect, rtl, extern: "nosp$1".} = ## Quote ``s``, so it can be safely passed to shell. ## - ## When on Windows, it calls `quoteShellWindows proc`_. - ## Otherwise, calls `quoteShellPosix proc`_. + ## When on Windows, it calls `quoteShellWindows proc + ## <#quoteShellWindows,string>`_. Otherwise, calls `quoteShellPosix proc + ## <#quoteShellPosix,string>`_. when defined(windows): - result = quoteShellWindows(s) + return quoteShellWindows(s) else: - result = quoteShellPosix(s) + return quoteShellPosix(s) proc quoteShellCommand*(args: openArray[string]): string = ## Concatenates and quotes shell arguments `args`. @@ -201,19 +1001,128 @@ when defined(windows) or defined(posix) or defined(nintendoswitch): assert quoteShellCommand(["aaa", "", "c d"]) == "aaa \"\" \"c d\"" # can't use `map` pending https://github.com/nim-lang/Nim/issues/8303 - result = "" for i in 0.. 0: result.add " " result.add quoteShell(args[i]) when not weirdTarget: + proc c_rename(oldname, newname: cstring): cint {. + importc: "rename", header: "".} proc c_system(cmd: cstring): cint {. importc: "system", header: "".} + proc c_strlen(a: cstring): cint {. + importc: "strlen", header: "", noSideEffect.} + proc c_free(p: pointer) {. + importc: "free", header: "".} - when not defined(windows): - proc c_free(p: pointer) {. - importc: "free", header: "".} +when defined(windows) and not weirdTarget: + when useWinUnicode: + template wrapUnary(varname, winApiProc, arg: untyped) = + var varname = winApiProc(newWideCString(arg)) + + template wrapBinary(varname, winApiProc, arg, arg2: untyped) = + var varname = winApiProc(newWideCString(arg), arg2) + proc findFirstFile(a: string, b: var WIN32_FIND_DATA): Handle = + result = findFirstFileW(newWideCString(a), b) + template findNextFile(a, b: untyped): untyped = findNextFileW(a, b) + template getCommandLine(): untyped = getCommandLineW() + + template getFilename(f: untyped): untyped = + $cast[WideCString](addr(f.cFileName[0])) + else: + template findFirstFile(a, b: untyped): untyped = findFirstFileA(a, b) + template findNextFile(a, b: untyped): untyped = findNextFileA(a, b) + template getCommandLine(): untyped = getCommandLineA() + + template getFilename(f: untyped): untyped = $f.cFileName + + proc skipFindData(f: WIN32_FIND_DATA): bool {.inline.} = + # Note - takes advantage of null delimiter in the cstring + const dot = ord('.') + result = f.cFileName[0].int == dot and (f.cFileName[1].int == 0 or + f.cFileName[1].int == dot and f.cFileName[2].int == 0) + +proc existsFile*(filename: string): bool {.rtl, extern: "nos$1", + tags: [ReadDirEffect], noNimScript.} = + ## Returns true if `filename` exists and is a regular file or symlink. + ## + ## Directories, device files, named pipes and sockets return false. + ## + ## See also: + ## * `existsDir proc <#existsDir,string>`_ + ## * `symlinkExists proc <#symlinkExists,string>`_ + when defined(windows): + when useWinUnicode: + wrapUnary(a, getFileAttributesW, filename) + else: + var a = getFileAttributesA(filename) + if a != -1'i32: + result = (a and FILE_ATTRIBUTE_DIRECTORY) == 0'i32 + else: + var res: Stat + return stat(filename, res) >= 0'i32 and S_ISREG(res.st_mode) + +proc existsDir*(dir: string): bool {.rtl, extern: "nos$1", tags: [ReadDirEffect], + noNimScript.} = + ## Returns true iff the directory `dir` exists. If `dir` is a file, false + ## is returned. Follows symlinks. + ## + ## See also: + ## * `existsFile proc <#existsFile,string>`_ + ## * `symlinkExists proc <#symlinkExists,string>`_ + when defined(windows): + when useWinUnicode: + wrapUnary(a, getFileAttributesW, dir) + else: + var a = getFileAttributesA(dir) + if a != -1'i32: + result = (a and FILE_ATTRIBUTE_DIRECTORY) != 0'i32 + else: + var res: Stat + return stat(dir, res) >= 0'i32 and S_ISDIR(res.st_mode) + +proc symlinkExists*(link: string): bool {.rtl, extern: "nos$1", + tags: [ReadDirEffect], + noNimScript.} = + ## Returns true iff the symlink `link` exists. Will return true + ## regardless of whether the link points to a directory or file. + ## + ## See also: + ## * `existsFile proc <#existsFile,string>`_ + ## * `existsDir proc <#existsDir,string>`_ + when defined(windows): + when useWinUnicode: + wrapUnary(a, getFileAttributesW, link) + else: + var a = getFileAttributesA(link) + if a != -1'i32: + result = (a and FILE_ATTRIBUTE_REPARSE_POINT) != 0'i32 + else: + var res: Stat + return lstat(link, res) >= 0'i32 and S_ISLNK(res.st_mode) + +proc fileExists*(filename: string): bool {.inline, noNimScript.} = + ## Alias for `existsFile proc <#existsFile,string>`_. + ## + ## See also: + ## * `existsDir proc <#existsDir,string>`_ + ## * `symlinkExists proc <#symlinkExists,string>`_ + existsFile(filename) + +proc dirExists*(dir: string): bool {.inline, noNimScript.} = + ## Alias for `existsDir proc <#existsDir,string>`_. + ## + ## See also: + ## * `existsFile proc <#existsFile,string>`_ + ## * `symlinkExists proc <#symlinkExists,string>`_ + existsDir(dir) + +when not defined(windows) and not weirdTarget: + proc checkSymlink(path: string): bool = + var rawInfo: Stat + if lstat(path, rawInfo) < 0'i32: result = false + else: result = S_ISLNK(rawInfo.st_mode) const ExeExts* = ## Platform specific file extension for executables. @@ -222,12 +1131,12 @@ const proc findExe*(exe: string, followSymlinks: bool = true; extensions: openArray[string]=ExeExts): string {. - tags: [ReadDirEffect, ReadEnvEffect, ReadIOEffect], noNimJs.} = + tags: [ReadDirEffect, ReadEnvEffect, ReadIOEffect], noNimScript.} = ## Searches for `exe` in the current working directory and then ## in directories listed in the ``PATH`` environment variable. ## ## Returns `""` if the `exe` cannot be found. `exe` - ## is added the `ExeExts`_ file extensions if it has none. + ## is added the `ExeExts <#ExeExts>`_ file extensions if it has none. ## ## If the system supports symlinks it also resolves them until it ## meets the actual file. This behavior can be disabled if desired @@ -237,12 +1146,12 @@ proc findExe*(exe: string, followSymlinks: bool = true; template checkCurrentDir() = for ext in extensions: result = addFileExt(exe, ext) - if fileExists(result): return + if existsFile(result): return when defined(posix): if '/' in exe: checkCurrentDir() else: checkCurrentDir() - let path = getEnv("PATH") + let path = string(getEnv("PATH")) for candidate in split(path, PathSep): if candidate.len == 0: continue when defined(windows): @@ -253,17 +1162,17 @@ proc findExe*(exe: string, followSymlinks: bool = true; var x = expandTilde(candidate) / exe for ext in extensions: var x = addFileExt(x, ext) - if fileExists(x): - when not (defined(windows) or defined(nintendoswitch)): + if existsFile(x): + when not defined(windows): while followSymlinks: # doubles as if here - if x.symlinkExists: - var r = newString(maxSymlinkLen) - var len = readlink(x.cstring, r.cstring, maxSymlinkLen) + if x.checkSymlink: + var r = newString(256) + var len = readlink(x, r, 256) if len < 0: raiseOSError(osLastError(), exe) - if len > maxSymlinkLen: + if len > 256: r = newString(len+1) - len = readlink(x.cstring, r.cstring, len) + len = readlink(x, r, len) setLen(r, len) if isAbsolute(r): x = r @@ -278,13 +1187,13 @@ when weirdTarget: const times = "fake const" template Time(x: untyped): untyped = string -proc getLastModificationTime*(file: string): times.Time {.rtl, extern: "nos$1", noWeirdTarget.} = +proc getLastModificationTime*(file: string): times.Time {.rtl, extern: "nos$1", noNimScript.} = ## Returns the `file`'s last modification time. ## ## See also: - ## * `getLastAccessTime proc`_ - ## * `getCreationTime proc`_ - ## * `fileNewer proc`_ + ## * `getLastAccessTime proc <#getLastAccessTime,string>`_ + ## * `getCreationTime proc <#getCreationTime,string>`_ + ## * `fileNewer proc <#fileNewer,string,string>`_ when defined(posix): var res: Stat if stat(file, res) < 0'i32: raiseOSError(osLastError(), file) @@ -296,13 +1205,13 @@ proc getLastModificationTime*(file: string): times.Time {.rtl, extern: "nos$1", result = fromWinTime(rdFileTime(f.ftLastWriteTime)) findClose(h) -proc getLastAccessTime*(file: string): times.Time {.rtl, extern: "nos$1", noWeirdTarget.} = +proc getLastAccessTime*(file: string): times.Time {.rtl, extern: "nos$1", noNimScript.} = ## Returns the `file`'s last read or write access time. ## ## See also: - ## * `getLastModificationTime proc`_ - ## * `getCreationTime proc`_ - ## * `fileNewer proc`_ + ## * `getLastModificationTime proc <#getLastModificationTime,string>`_ + ## * `getCreationTime proc <#getCreationTime,string>`_ + ## * `fileNewer proc <#fileNewer,string,string>`_ when defined(posix): var res: Stat if stat(file, res) < 0'i32: raiseOSError(osLastError(), file) @@ -314,7 +1223,7 @@ proc getLastAccessTime*(file: string): times.Time {.rtl, extern: "nos$1", noWeir result = fromWinTime(rdFileTime(f.ftLastAccessTime)) findClose(h) -proc getCreationTime*(file: string): times.Time {.rtl, extern: "nos$1", noWeirdTarget.} = +proc getCreationTime*(file: string): times.Time {.rtl, extern: "nos$1", noNimScript.} = ## Returns the `file`'s creation time. ## ## **Note:** Under POSIX OS's, the returned time may actually be the time at @@ -322,9 +1231,9 @@ proc getCreationTime*(file: string): times.Time {.rtl, extern: "nos$1", noWeirdT ## `here `_ for details. ## ## See also: - ## * `getLastModificationTime proc`_ - ## * `getLastAccessTime proc`_ - ## * `fileNewer proc`_ + ## * `getLastModificationTime proc <#getLastModificationTime,string>`_ + ## * `getLastAccessTime proc <#getLastAccessTime,string>`_ + ## * `fileNewer proc <#fileNewer,string,string>`_ when defined(posix): var res: Stat if stat(file, res) < 0'i32: raiseOSError(osLastError(), file) @@ -336,14 +1245,14 @@ proc getCreationTime*(file: string): times.Time {.rtl, extern: "nos$1", noWeirdT result = fromWinTime(rdFileTime(f.ftCreationTime)) findClose(h) -proc fileNewer*(a, b: string): bool {.rtl, extern: "nos$1", noWeirdTarget.} = +proc fileNewer*(a, b: string): bool {.rtl, extern: "nos$1", noNimScript.} = ## Returns true if the file `a` is newer than file `b`, i.e. if `a`'s ## modification time is later than `b`'s. ## ## See also: - ## * `getLastModificationTime proc`_ - ## * `getLastAccessTime proc`_ - ## * `getCreationTime proc`_ + ## * `getLastModificationTime proc <#getLastModificationTime,string>`_ + ## * `getLastAccessTime proc <#getLastAccessTime,string>`_ + ## * `getCreationTime proc <#getCreationTime,string>`_ when defined(posix): # If we don't have access to nanosecond resolution, use '>=' when not StatHasNanoseconds: @@ -353,38 +1262,527 @@ proc fileNewer*(a, b: string): bool {.rtl, extern: "nos$1", noWeirdTarget.} = else: result = getLastModificationTime(a) > getLastModificationTime(b) - -proc isAdmin*: bool {.noWeirdTarget.} = - ## Returns whether the caller's process is a member of the Administrators local - ## group (on Windows) or a root (on POSIX), via `geteuid() == 0`. +proc getCurrentDir*(): string {.rtl, extern: "nos$1", tags: [], noNimScript.} = + ## Returns the `current working directory`:idx: i.e. where the built + ## binary is run. + ## + ## So the path returned by this proc is determined at run time. + ## + ## See also: + ## * `getHomeDir proc <#getHomeDir>`_ + ## * `getConfigDir proc <#getConfigDir>`_ + ## * `getTempDir proc <#getTempDir>`_ + ## * `setCurrentDir proc <#setCurrentDir,string>`_ + ## * `currentSourcePath template `_ + ## * `getProjectPath proc `_ when defined(windows): - # Rewrite of the example from Microsoft Docs: - # https://docs.microsoft.com/en-us/windows/win32/api/securitybaseapi/nf-securitybaseapi-checktokenmembership#examples - # and corresponding PostgreSQL function: - # https://doxygen.postgresql.org/win32security_8c.html#ae6b61e106fa5d6c5d077a9d14ee80569 - var ntAuthority = SID_IDENTIFIER_AUTHORITY(value: SECURITY_NT_AUTHORITY) - var administratorsGroup: PSID - if not isSuccess(allocateAndInitializeSid(addr ntAuthority, - BYTE(2), - SECURITY_BUILTIN_DOMAIN_RID, - DOMAIN_ALIAS_RID_ADMINS, - 0, 0, 0, 0, 0, 0, - addr administratorsGroup)): - raiseOSError(osLastError(), "could not get SID for Administrators group") - - try: - var b: WINBOOL - if not isSuccess(checkTokenMembership(0, administratorsGroup, addr b)): - raiseOSError(osLastError(), "could not check access token membership") - - result = isSuccess(b) - finally: - if freeSid(administratorsGroup) != nil: - raiseOSError(osLastError(), "failed to free SID for Administrators group") - + var bufsize = MAX_PATH.int32 + when useWinUnicode: + var res = newWideCString("", bufsize) + while true: + var L = getCurrentDirectoryW(bufsize, res) + if L == 0'i32: + raiseOSError(osLastError()) + elif L > bufsize: + res = newWideCString("", L) + bufsize = L + else: + result = res$L + break + else: + result = newString(bufsize) + while true: + var L = getCurrentDirectoryA(bufsize, result) + if L == 0'i32: + raiseOSError(osLastError()) + elif L > bufsize: + result = newString(L) + bufsize = L + else: + setLen(result, L) + break else: - result = geteuid() == 0 + var bufsize = 1024 # should be enough + result = newString(bufsize) + while true: + if getcwd(result, bufsize) != nil: + setLen(result, c_strlen(result)) + break + else: + let err = osLastError() + if err.int32 == ERANGE: + bufsize = bufsize shl 1 + doAssert(bufsize >= 0) + result = newString(bufsize) + else: + raiseOSError(osLastError()) +proc setCurrentDir*(newDir: string) {.inline, tags: [], noNimScript.} = + ## Sets the `current working directory`:idx:; `OSError` + ## is raised if `newDir` cannot been set. + ## + ## See also: + ## * `getHomeDir proc <#getHomeDir>`_ + ## * `getConfigDir proc <#getConfigDir>`_ + ## * `getTempDir proc <#getTempDir>`_ + ## * `getCurrentDir proc <#getCurrentDir>`_ + when defined(Windows): + when useWinUnicode: + if setCurrentDirectoryW(newWideCString(newDir)) == 0'i32: + raiseOSError(osLastError(), newDir) + else: + if setCurrentDirectoryA(newDir) == 0'i32: raiseOSError(osLastError(), newDir) + else: + if chdir(newDir) != 0'i32: raiseOSError(osLastError(), newDir) + +when not weirdTarget: + proc absolutePath*(path: string, root = getCurrentDir()): string {.noNimScript.} = + ## Returns the absolute path of `path`, rooted at `root` (which must be absolute; + ## default: current directory). + ## If `path` is absolute, return it, ignoring `root`. + ## + ## See also: + ## * `normalizedPath proc <#normalizedPath,string>`_ + ## * `normalizePath proc <#normalizePath,string>`_ + runnableExamples: + assert absolutePath("a") == getCurrentDir() / "a" + + if isAbsolute(path): path + else: + if not root.isAbsolute: + raise newException(ValueError, "The specified root is not absolute: " & root) + joinPath(root, path) + +proc normalizePath*(path: var string) {.rtl, extern: "nos$1", tags: [], noNimScript.} = + ## Normalize a path. + ## + ## Consecutive directory separators are collapsed, including an initial double slash. + ## + ## On relative paths, double dot (`..`) sequences are collapsed if possible. + ## On absolute paths they are always collapsed. + ## + ## Warning: URL-encoded and Unicode attempts at directory traversal are not detected. + ## Triple dot is not handled. + ## + ## See also: + ## * `absolutePath proc <#absolutePath,string>`_ + ## * `normalizedPath proc <#normalizedPath,string>`_ for a version which returns + ## a new string + runnableExamples: + when defined(posix): + var a = "a///b//..//c///d" + a.normalizePath() + assert a == "a/c/d" + + path = pathnorm.normalizePath(path) + when false: + let isAbs = isAbsolute(path) + var stack: seq[string] = @[] + for p in split(path, {DirSep}): + case p + of "", ".": + continue + of "..": + if stack.len == 0: + if isAbs: + discard # collapse all double dots on absoluta paths + else: + stack.add(p) + elif stack[^1] == "..": + stack.add(p) + else: + discard stack.pop() + else: + stack.add(p) + + if isAbs: + path = DirSep & join(stack, $DirSep) + elif stack.len > 0: + path = join(stack, $DirSep) + else: + path = "." + +proc normalizedPath*(path: string): string {.rtl, extern: "nos$1", tags: [], noNimScript.} = + ## Returns a normalized path for the current OS. + ## + ## See also: + ## * `absolutePath proc <#absolutePath,string>`_ + ## * `normalizePath proc <#normalizePath,string>`_ for the in-place version + runnableExamples: + when defined(posix): + assert normalizedPath("a///b//..//c///d") == "a/c/d" + result = pathnorm.normalizePath(path) + +when defined(Windows) and not weirdTarget: + proc openHandle(path: string, followSymlink=true, writeAccess=false): Handle = + var flags = FILE_FLAG_BACKUP_SEMANTICS or FILE_ATTRIBUTE_NORMAL + if not followSymlink: + flags = flags or FILE_FLAG_OPEN_REPARSE_POINT + let access = if writeAccess: GENERIC_WRITE else: 0'i32 + + when useWinUnicode: + result = createFileW( + newWideCString(path), access, + FILE_SHARE_DELETE or FILE_SHARE_READ or FILE_SHARE_WRITE, + nil, OPEN_EXISTING, flags, 0 + ) + else: + result = createFileA( + path, access, + FILE_SHARE_DELETE or FILE_SHARE_READ or FILE_SHARE_WRITE, + nil, OPEN_EXISTING, flags, 0 + ) + +proc sameFile*(path1, path2: string): bool {.rtl, extern: "nos$1", + tags: [ReadDirEffect], noNimScript.} = + ## Returns true if both pathname arguments refer to the same physical + ## file or directory. + ## + ## Raises `OSError` if any of the files does not + ## exist or information about it can not be obtained. + ## + ## This proc will return true if given two alternative hard-linked or + ## sym-linked paths to the same file or directory. + ## + ## See also: + ## * `sameFileContent proc <#sameFileContent,string,string>`_ + when defined(Windows): + var success = true + var f1 = openHandle(path1) + var f2 = openHandle(path2) + + var lastErr: OSErrorCode + if f1 != INVALID_HANDLE_VALUE and f2 != INVALID_HANDLE_VALUE: + var fi1, fi2: BY_HANDLE_FILE_INFORMATION + + if getFileInformationByHandle(f1, addr(fi1)) != 0 and + getFileInformationByHandle(f2, addr(fi2)) != 0: + result = fi1.dwVolumeSerialNumber == fi2.dwVolumeSerialNumber and + fi1.nFileIndexHigh == fi2.nFileIndexHigh and + fi1.nFileIndexLow == fi2.nFileIndexLow + else: + lastErr = osLastError() + success = false + else: + lastErr = osLastError() + success = false + + discard closeHandle(f1) + discard closeHandle(f2) + + if not success: raiseOSError(lastErr, $(path1, path2)) + else: + var a, b: Stat + if stat(path1, a) < 0'i32 or stat(path2, b) < 0'i32: + raiseOSError(osLastError(), $(path1, path2)) + else: + result = a.st_dev == b.st_dev and a.st_ino == b.st_ino + +proc sameFileContent*(path1, path2: string): bool {.rtl, extern: "nos$1", + tags: [ReadIOEffect], noNimScript.} = + ## Returns true if both pathname arguments refer to files with identical + ## binary content. + ## + ## See also: + ## * `sameFile proc <#sameFile,string,string>`_ + const + bufSize = 8192 # 8K buffer + var + a, b: File + if not open(a, path1): return false + if not open(b, path2): + close(a) + return false + var bufA = alloc(bufSize) + var bufB = alloc(bufSize) + while true: + var readA = readBuffer(a, bufA, bufSize) + var readB = readBuffer(b, bufB, bufSize) + if readA != readB: + result = false + break + if readA == 0: + result = true + break + result = equalMem(bufA, bufB, readA) + if not result: break + if readA != bufSize: break # end of file + dealloc(bufA) + dealloc(bufB) + close(a) + close(b) + +type + FilePermission* = enum ## File access permission, modelled after UNIX. + ## + ## See also: + ## * `getFilePermissions <#getFilePermissions,string>`_ + ## * `setFilePermissions <#setFilePermissions,string,set[FilePermission]>`_ + ## * `FileInfo object <#FileInfo>`_ + fpUserExec, ## execute access for the file owner + fpUserWrite, ## write access for the file owner + fpUserRead, ## read access for the file owner + fpGroupExec, ## execute access for the group + fpGroupWrite, ## write access for the group + fpGroupRead, ## read access for the group + fpOthersExec, ## execute access for others + fpOthersWrite, ## write access for others + fpOthersRead ## read access for others + +proc getFilePermissions*(filename: string): set[FilePermission] {. + rtl, extern: "nos$1", tags: [ReadDirEffect], noNimScript.} = + ## Retrieves file permissions for `filename`. + ## + ## `OSError` is raised in case of an error. + ## On Windows, only the ``readonly`` flag is checked, every other + ## permission is available in any case. + ## + ## See also: + ## * `setFilePermissions proc <#setFilePermissions,string,set[FilePermission]>`_ + ## * `FilePermission enum <#FilePermission>`_ + when defined(posix): + var a: Stat + if stat(filename, a) < 0'i32: raiseOSError(osLastError(), filename) + result = {} + if (a.st_mode and S_IRUSR.Mode) != 0.Mode: result.incl(fpUserRead) + if (a.st_mode and S_IWUSR.Mode) != 0.Mode: result.incl(fpUserWrite) + if (a.st_mode and S_IXUSR.Mode) != 0.Mode: result.incl(fpUserExec) + + if (a.st_mode and S_IRGRP.Mode) != 0.Mode: result.incl(fpGroupRead) + if (a.st_mode and S_IWGRP.Mode) != 0.Mode: result.incl(fpGroupWrite) + if (a.st_mode and S_IXGRP.Mode) != 0.Mode: result.incl(fpGroupExec) + + if (a.st_mode and S_IROTH.Mode) != 0.Mode: result.incl(fpOthersRead) + if (a.st_mode and S_IWOTH.Mode) != 0.Mode: result.incl(fpOthersWrite) + if (a.st_mode and S_IXOTH.Mode) != 0.Mode: result.incl(fpOthersExec) + else: + when useWinUnicode: + wrapUnary(res, getFileAttributesW, filename) + else: + var res = getFileAttributesA(filename) + if res == -1'i32: raiseOSError(osLastError(), filename) + if (res and FILE_ATTRIBUTE_READONLY) != 0'i32: + result = {fpUserExec, fpUserRead, fpGroupExec, fpGroupRead, + fpOthersExec, fpOthersRead} + else: + result = {fpUserExec..fpOthersRead} + +proc setFilePermissions*(filename: string, permissions: set[FilePermission]) {. + rtl, extern: "nos$1", tags: [WriteDirEffect], noNimScript.} = + ## Sets the file permissions for `filename`. + ## + ## `OSError` is raised in case of an error. + ## On Windows, only the ``readonly`` flag is changed, depending on + ## ``fpUserWrite`` permission. + ## + ## See also: + ## * `getFilePermissions <#getFilePermissions,string>`_ + ## * `FilePermission enum <#FilePermission>`_ + when defined(posix): + var p = 0.Mode + if fpUserRead in permissions: p = p or S_IRUSR.Mode + if fpUserWrite in permissions: p = p or S_IWUSR.Mode + if fpUserExec in permissions: p = p or S_IXUSR.Mode + + if fpGroupRead in permissions: p = p or S_IRGRP.Mode + if fpGroupWrite in permissions: p = p or S_IWGRP.Mode + if fpGroupExec in permissions: p = p or S_IXGRP.Mode + + if fpOthersRead in permissions: p = p or S_IROTH.Mode + if fpOthersWrite in permissions: p = p or S_IWOTH.Mode + if fpOthersExec in permissions: p = p or S_IXOTH.Mode + + if chmod(filename, cast[Mode](p)) != 0: raiseOSError(osLastError(), $(filename, permissions)) + else: + when useWinUnicode: + wrapUnary(res, getFileAttributesW, filename) + else: + var res = getFileAttributesA(filename) + if res == -1'i32: raiseOSError(osLastError(), filename) + if fpUserWrite in permissions: + res = res and not FILE_ATTRIBUTE_READONLY + else: + res = res or FILE_ATTRIBUTE_READONLY + when useWinUnicode: + wrapBinary(res2, setFileAttributesW, filename, res) + else: + var res2 = setFileAttributesA(filename, res) + if res2 == - 1'i32: raiseOSError(osLastError(), $(filename, permissions)) + +proc copyFile*(source, dest: string) {.rtl, extern: "nos$1", + tags: [ReadIOEffect, WriteIOEffect], noNimScript.} = + ## Copies a file from `source` to `dest`. + ## + ## If this fails, `OSError` is raised. + ## + ## On the Windows platform this proc will + ## copy the source file's attributes into dest. + ## + ## On other platforms you need + ## to use `getFilePermissions <#getFilePermissions,string>`_ and + ## `setFilePermissions <#setFilePermissions,string,set[FilePermission]>`_ procs + ## to copy them by hand (or use the convenience `copyFileWithPermissions + ## proc <#copyFileWithPermissions,string,string>`_), + ## otherwise `dest` will inherit the default permissions of a newly + ## created file for the user. + ## + ## If `dest` already exists, the file attributes + ## will be preserved and the content overwritten. + ## + ## See also: + ## * `copyDir proc <#copyDir,string,string>`_ + ## * `copyFileWithPermissions proc <#copyFileWithPermissions,string,string>`_ + ## * `tryRemoveFile proc <#tryRemoveFile,string>`_ + ## * `removeFile proc <#removeFile,string>`_ + ## * `moveFile proc <#moveFile,string,string>`_ + + when defined(Windows): + when useWinUnicode: + let s = newWideCString(source) + let d = newWideCString(dest) + if copyFileW(s, d, 0'i32) == 0'i32: raiseOSError(osLastError(), $(source, dest)) + else: + if copyFileA(source, dest, 0'i32) == 0'i32: raiseOSError(osLastError(), $(source, dest)) + else: + # generic version of copyFile which works for any platform: + const bufSize = 8000 # better for memory manager + var d, s: File + if not open(s, source): raiseOSError(osLastError(), source) + if not open(d, dest, fmWrite): + close(s) + raiseOSError(osLastError(), dest) + var buf = alloc(bufSize) + while true: + var bytesread = readBuffer(s, buf, bufSize) + if bytesread > 0: + var byteswritten = writeBuffer(d, buf, bytesread) + if bytesread != byteswritten: + dealloc(buf) + close(s) + close(d) + raiseOSError(osLastError(), dest) + if bytesread != bufSize: break + dealloc(buf) + close(s) + flushFile(d) + close(d) + +when not declared(ENOENT) and not defined(Windows): + when NoFakeVars: + when not defined(haiku): + const ENOENT = cint(2) # 2 on most systems including Solaris + else: + const ENOENT = cint(-2147459069) + else: + var ENOENT {.importc, header: "".}: cint + +when defined(Windows) and not weirdTarget: + when useWinUnicode: + template deleteFile(file: untyped): untyped = deleteFileW(file) + template setFileAttributes(file, attrs: untyped): untyped = + setFileAttributesW(file, attrs) + else: + template deleteFile(file: untyped): untyped = deleteFileA(file) + template setFileAttributes(file, attrs: untyped): untyped = + setFileAttributesA(file, attrs) + +proc tryRemoveFile*(file: string): bool {.rtl, extern: "nos$1", tags: [WriteDirEffect], noNimScript.} = + ## Removes the `file`. + ## + ## If this fails, returns `false`. This does not fail + ## if the file never existed in the first place. + ## + ## On Windows, ignores the read-only attribute. + ## + ## See also: + ## * `copyFile proc <#copyFile,string,string>`_ + ## * `copyFileWithPermissions proc <#copyFileWithPermissions,string,string>`_ + ## * `removeFile proc <#removeFile,string>`_ + ## * `moveFile proc <#moveFile,string,string>`_ + result = true + when defined(Windows): + when useWinUnicode: + let f = newWideCString(file) + else: + let f = file + if deleteFile(f) == 0: + result = false + let err = getLastError() + if err == ERROR_FILE_NOT_FOUND or err == ERROR_PATH_NOT_FOUND: + result = true + elif err == ERROR_ACCESS_DENIED and + setFileAttributes(f, FILE_ATTRIBUTE_NORMAL) != 0 and + deleteFile(f) != 0: + result = true + else: + if unlink(file) != 0'i32 and errno != ENOENT: + result = false + +proc removeFile*(file: string) {.rtl, extern: "nos$1", tags: [WriteDirEffect], noNimScript.} = + ## Removes the `file`. + ## + ## If this fails, `OSError` is raised. This does not fail + ## if the file never existed in the first place. + ## + ## On Windows, ignores the read-only attribute. + ## + ## See also: + ## * `removeDir proc <#removeDir,string>`_ + ## * `copyFile proc <#copyFile,string,string>`_ + ## * `copyFileWithPermissions proc <#copyFileWithPermissions,string,string>`_ + ## * `tryRemoveFile proc <#tryRemoveFile,string>`_ + ## * `moveFile proc <#moveFile,string,string>`_ + if not tryRemoveFile(file): + raiseOSError(osLastError(), file) + +proc tryMoveFSObject(source, dest: string): bool {.noNimScript.} = + ## Moves a file or directory from `source` to `dest`. + ## + ## Returns false in case of `EXDEV` error. + ## In case of other errors `OSError` is raised. + ## Returns true in case of success. + when defined(Windows): + when useWinUnicode: + let s = newWideCString(source) + let d = newWideCString(dest) + if moveFileExW(s, d, MOVEFILE_COPY_ALLOWED) == 0'i32: raiseOSError(osLastError(), $(source, dest)) + else: + if moveFileExA(source, dest, MOVEFILE_COPY_ALLOWED) == 0'i32: raiseOSError(osLastError(), $(source, dest)) + else: + if c_rename(source, dest) != 0'i32: + let err = osLastError() + if err == EXDEV.OSErrorCode: + return false + else: + # see whether `strerror(errno)` is redundant with what raiseOSError already shows + raiseOSError(err, $(source, dest, strerror(errno))) + return true + +proc moveFile*(source, dest: string) {.rtl, extern: "nos$1", + tags: [ReadIOEffect, WriteIOEffect], noNimScript.} = + ## Moves a file from `source` to `dest`. + ## + ## If this fails, `OSError` is raised. + ## If `dest` already exists, it will be overwritten. + ## + ## Can be used to `rename files`:idx:. + ## + ## See also: + ## * `moveDir proc <#moveDir,string,string>`_ + ## * `copyFile proc <#copyFile,string,string>`_ + ## * `copyFileWithPermissions proc <#copyFileWithPermissions,string,string>`_ + ## * `removeFile proc <#removeFile,string>`_ + ## * `tryRemoveFile proc <#tryRemoveFile,string>`_ + + if not tryMoveFSObject(source, dest): + when not defined(windows): + # Fallback to copy & del + copyFile(source, dest) + try: + removeFile(source) + except: + discard tryRemoveFile(dest) + raise proc exitStatusLikeShell*(status: cint): cint = ## Converts exit code from `c_system` into a shell exit code. @@ -398,7 +1796,7 @@ proc exitStatusLikeShell*(status: cint): cint = status proc execShellCmd*(command: string): int {.rtl, extern: "nos$1", - tags: [ExecIOEffect], noWeirdTarget.} = + tags: [ExecIOEffect], noNimScript.} = ## Executes a `shell command`:idx:. ## ## Command has the form 'program args' where args are the command @@ -415,30 +1813,143 @@ proc execShellCmd*(command: string): int {.rtl, extern: "nos$1", ## discard execShellCmd("ls -la") result = exitStatusLikeShell(c_system(command)) +# Templates for filtering directories and files +when defined(windows) and not weirdTarget: + template isDir(f: WIN32_FIND_DATA): bool = + (f.dwFileAttributes and FILE_ATTRIBUTE_DIRECTORY) != 0'i32 + template isFile(f: WIN32_FIND_DATA): bool = + not isDir(f) +else: + template isDir(f: string): bool {.dirty.} = + dirExists(f) + template isFile(f: string): bool {.dirty.} = + fileExists(f) + +template defaultWalkFilter(item): bool = + ## Walk filter used to return true on both + ## files and directories + true + +template walkCommon(pattern: string, filter) = + ## Common code for getting the files and directories with the + ## specified `pattern` + when defined(windows): + var + f: WIN32_FIND_DATA + res: int + res = findFirstFile(pattern, f) + if res != -1: + defer: findClose(res) + let dotPos = searchExtPos(pattern) + while true: + if not skipFindData(f) and filter(f): + # Windows bug/gotcha: 't*.nim' matches 'tfoo.nims' -.- so we check + # that the file extensions have the same length ... + let ff = getFilename(f) + let idx = ff.len - pattern.len + dotPos + if dotPos < 0 or idx >= ff.len or (idx >= 0 and ff[idx] == '.') or + (dotPos >= 0 and dotPos+1 < pattern.len and pattern[dotPos+1] == '*'): + yield splitFile(pattern).dir / extractFilename(ff) + if findNextFile(res, f) == 0'i32: + let errCode = getLastError() + if errCode == ERROR_NO_MORE_FILES: break + else: raiseOSError(errCode.OSErrorCode) + else: # here we use glob + var + f: Glob + res: int + f.gl_offs = 0 + f.gl_pathc = 0 + f.gl_pathv = nil + res = glob(pattern, 0, nil, addr(f)) + defer: globfree(addr(f)) + if res == 0: + for i in 0.. f.gl_pathc - 1: + assert(f.gl_pathv[i] != nil) + let path = $f.gl_pathv[i] + if filter(path): + yield path + +iterator walkPattern*(pattern: string): string {.tags: [ReadDirEffect], noNimScript.} = + ## Iterate over all the files and directories that match the `pattern`. + ## + ## On POSIX this uses the `glob`:idx: call. + ## `pattern` is OS dependent, but at least the `"\*.ext"` + ## notation is supported. + ## + ## See also: + ## * `walkFiles iterator <#walkFiles.i,string>`_ + ## * `walkDirs iterator <#walkDirs.i,string>`_ + ## * `walkDir iterator <#walkDir.i,string>`_ + ## * `walkDirRec iterator <#walkDirRec.i,string>`_ + walkCommon(pattern, defaultWalkFilter) + +iterator walkFiles*(pattern: string): string {.tags: [ReadDirEffect], noNimScript.} = + ## Iterate over all the files that match the `pattern`. + ## + ## On POSIX this uses the `glob`:idx: call. + ## `pattern` is OS dependent, but at least the `"\*.ext"` + ## notation is supported. + ## + ## See also: + ## * `walkPattern iterator <#walkPattern.i,string>`_ + ## * `walkDirs iterator <#walkDirs.i,string>`_ + ## * `walkDir iterator <#walkDir.i,string>`_ + ## * `walkDirRec iterator <#walkDirRec.i,string>`_ + walkCommon(pattern, isFile) + +iterator walkDirs*(pattern: string): string {.tags: [ReadDirEffect], noNimScript.} = + ## Iterate over all the directories that match the `pattern`. + ## + ## On POSIX this uses the `glob`:idx: call. + ## `pattern` is OS dependent, but at least the `"\*.ext"` + ## notation is supported. + ## + ## See also: + ## * `walkPattern iterator <#walkPattern.i,string>`_ + ## * `walkFiles iterator <#walkFiles.i,string>`_ + ## * `walkDir iterator <#walkDir.i,string>`_ + ## * `walkDirRec iterator <#walkDirRec.i,string>`_ + walkCommon(pattern, isDir) + proc expandFilename*(filename: string): string {.rtl, extern: "nos$1", - tags: [ReadDirEffect], noWeirdTarget.} = + tags: [ReadDirEffect], noNimScript.} = ## Returns the full (`absolute`:idx:) path of an existing file `filename`. ## ## Raises `OSError` in case of an error. Follows symlinks. when defined(windows): var bufsize = MAX_PATH.int32 - var unused: WideCString = nil - var res = newWideCString("", bufsize) - while true: - var L = getFullPathNameW(newWideCString(filename), bufsize, res, unused) - if L == 0'i32: - raiseOSError(osLastError(), filename) - elif L > bufsize: - res = newWideCString("", L) - bufsize = L - else: - result = res$L - break + when useWinUnicode: + var unused: WideCString = nil + var res = newWideCString("", bufsize) + while true: + var L = getFullPathNameW(newWideCString(filename), bufsize, res, unused) + if L == 0'i32: + raiseOSError(osLastError(), filename) + elif L > bufsize: + res = newWideCString("", L) + bufsize = L + else: + result = res$L + break + else: + var unused: cstring = nil + result = newString(bufsize) + while true: + var L = getFullPathNameA(filename, bufsize, result, unused) + if L == 0'i32: + raiseOSError(osLastError(), filename) + elif L > bufsize: + result = newString(L) + bufsize = L + else: + setLen(result, L) + break # getFullPathName doesn't do case corrections, so we have to use this convoluted # way of retrieving the true filename for x in walkFiles(result): result = x - if not fileExists(result) and not dirExists(result): + if not existsFile(result) and not existsDir(result): # consider using: `raiseOSError(osLastError(), result)` raise newException(OSError, "file '" & result & "' does not exist") else: @@ -451,35 +1962,488 @@ proc expandFilename*(filename: string): string {.rtl, extern: "nos$1", result = $r c_free(cast[pointer](r)) +type + PathComponent* = enum ## Enumeration specifying a path component. + ## + ## See also: + ## * `walkDirRec iterator <#walkDirRec.i,string>`_ + ## * `FileInfo object <#FileInfo>`_ + pcFile, ## path refers to a file + pcLinkToFile, ## path refers to a symbolic link to a file + pcDir, ## path refers to a directory + pcLinkToDir ## path refers to a symbolic link to a directory + proc getCurrentCompilerExe*(): string {.compileTime.} = discard - ## This is `getAppFilename()`_ at compile time. + ## This is `getAppFilename() <#getAppFilename>`_ at compile time. ## ## Can be used to retrieve the currently executing ## Nim compiler from a Nim or nimscript program, or the nimble binary ## inside a nimble program (likewise with other binaries built from ## compiler API). -proc createHardlink*(src, dest: string) {.noWeirdTarget.} = +when defined(posix) and not weirdTarget: + proc getSymlinkFileKind(path: string): PathComponent = + # Helper function. + var s: Stat + assert(path != "") + if stat(path, s) == 0'i32 and S_ISDIR(s.st_mode): + result = pcLinkToDir + else: + result = pcLinkToFile + +proc staticWalkDir(dir: string; relative: bool): seq[ + tuple[kind: PathComponent, path: string]] = + discard + +iterator walkDir*(dir: string; relative=false): tuple[kind: PathComponent, path: string] {. + tags: [ReadDirEffect].} = + ## Walks over the directory `dir` and yields for each directory or file in + ## `dir`. The component type and full path for each item are returned. + ## + ## Walking is not recursive. If ``relative`` is true (default: false) + ## the resulting path is shortened to be relative to ``dir``. + ## Example: This directory structure:: + ## dirA / dirB / fileB1.txt + ## / dirC + ## / fileA1.txt + ## / fileA2.txt + ## + ## and this code: + ## + ## .. code-block:: Nim + ## for kind, path in walkDir("dirA"): + ## echo(path) + ## + ## produce this output (but not necessarily in this order!):: + ## dirA/dirB + ## dirA/dirC + ## dirA/fileA1.txt + ## dirA/fileA2.txt + ## + ## See also: + ## * `walkPattern iterator <#walkPattern.i,string>`_ + ## * `walkFiles iterator <#walkFiles.i,string>`_ + ## * `walkDirs iterator <#walkDirs.i,string>`_ + ## * `walkDirRec iterator <#walkDirRec.i,string>`_ + + when nimvm: + for k, v in items(staticWalkDir(dir, relative)): + yield (k, v) + else: + when weirdTarget: + for k, v in items(staticWalkDir(dir, relative)): + yield (k, v) + elif defined(windows): + var f: WIN32_FIND_DATA + var h = findFirstFile(dir / "*", f) + if h != -1: + defer: findClose(h) + while true: + var k = pcFile + if not skipFindData(f): + if (f.dwFileAttributes and FILE_ATTRIBUTE_DIRECTORY) != 0'i32: + k = pcDir + if (f.dwFileAttributes and FILE_ATTRIBUTE_REPARSE_POINT) != 0'i32: + k = succ(k) + let xx = if relative: extractFilename(getFilename(f)) + else: dir / extractFilename(getFilename(f)) + yield (k, xx) + if findNextFile(h, f) == 0'i32: + let errCode = getLastError() + if errCode == ERROR_NO_MORE_FILES: break + else: raiseOSError(errCode.OSErrorCode) + else: + var d = opendir(dir) + if d != nil: + defer: discard closedir(d) + while true: + var x = readdir(d) + if x == nil: break + when defined(nimNoArrayToCstringConversion): + var y = $cstring(addr x.d_name) + else: + var y = $x.d_name.cstring + if y != "." and y != "..": + var s: Stat + let path = dir / y + if not relative: + y = path + var k = pcFile + + when defined(linux) or defined(macosx) or + defined(bsd) or defined(genode) or defined(nintendoswitch): + if x.d_type != DT_UNKNOWN: + if x.d_type == DT_DIR: k = pcDir + if x.d_type == DT_LNK: + if dirExists(path): k = pcLinkToDir + else: k = pcLinkToFile + yield (k, y) + continue + + if lstat(path, s) < 0'i32: break + if S_ISDIR(s.st_mode): + k = pcDir + elif S_ISLNK(s.st_mode): + k = getSymlinkFileKind(path) + yield (k, y) + +iterator walkDirRec*(dir: string, + yieldFilter = {pcFile}, followFilter = {pcDir}, + relative = false): string {.tags: [ReadDirEffect].} = + ## Recursively walks over the directory `dir` and yields for each file + ## or directory in `dir`. + ## + ## If ``relative`` is true (default: false) the resulting path is + ## shortened to be relative to ``dir``, otherwise the full path is returned. + ## + ## **Warning**: + ## Modifying the directory structure while the iterator + ## is traversing may result in undefined behavior! + ## + ## Walking is recursive. `followFilter` controls the behaviour of the iterator: + ## + ## --------------------- --------------------------------------------- + ## yieldFilter meaning + ## --------------------- --------------------------------------------- + ## ``pcFile`` yield real files (default) + ## ``pcLinkToFile`` yield symbolic links to files + ## ``pcDir`` yield real directories + ## ``pcLinkToDir`` yield symbolic links to directories + ## --------------------- --------------------------------------------- + ## + ## --------------------- --------------------------------------------- + ## followFilter meaning + ## --------------------- --------------------------------------------- + ## ``pcDir`` follow real directories (default) + ## ``pcLinkToDir`` follow symbolic links to directories + ## --------------------- --------------------------------------------- + ## + ## + ## See also: + ## * `walkPattern iterator <#walkPattern.i,string>`_ + ## * `walkFiles iterator <#walkFiles.i,string>`_ + ## * `walkDirs iterator <#walkDirs.i,string>`_ + ## * `walkDir iterator <#walkDir.i,string>`_ + + var stack = @[""] + while stack.len > 0: + let d = stack.pop() + for k, p in walkDir(dir / d, relative = true): + let rel = d / p + if k in {pcDir, pcLinkToDir} and k in followFilter: + stack.add rel + if k in yieldFilter: + yield if relative: rel else: dir / rel + +proc rawRemoveDir(dir: string) {.noNimScript.} = + when defined(windows): + when useWinUnicode: + wrapUnary(res, removeDirectoryW, dir) + else: + var res = removeDirectoryA(dir) + let lastError = osLastError() + if res == 0'i32 and lastError.int32 != 3'i32 and + lastError.int32 != 18'i32 and lastError.int32 != 2'i32: + raiseOSError(lastError, dir) + else: + if rmdir(dir) != 0'i32 and errno != ENOENT: raiseOSError(osLastError(), dir) + +proc removeDir*(dir: string) {.rtl, extern: "nos$1", tags: [ + WriteDirEffect, ReadDirEffect], benign, noNimScript.} = + ## Removes the directory `dir` including all subdirectories and files + ## in `dir` (recursively). + ## + ## If this fails, `OSError` is raised. This does not fail if the directory never + ## existed in the first place. + ## + ## See also: + ## * `tryRemoveFile proc <#tryRemoveFile,string>`_ + ## * `removeFile proc <#removeFile,string>`_ + ## * `existsOrCreateDir proc <#existsOrCreateDir,string>`_ + ## * `createDir proc <#createDir,string>`_ + ## * `copyDir proc <#copyDir,string,string>`_ + ## * `copyDirWithPermissions proc <#copyDirWithPermissions,string,string>`_ + ## * `moveDir proc <#moveDir,string,string>`_ + for kind, path in walkDir(dir): + case kind + of pcFile, pcLinkToFile, pcLinkToDir: removeFile(path) + of pcDir: removeDir(path) + rawRemoveDir(dir) + +proc rawCreateDir(dir: string): bool {.noNimScript.} = + # Try to create one directory (not the whole path). + # returns `true` for success, `false` if the path has previously existed + # + # This is a thin wrapper over mkDir (or alternatives on other systems), + # so in case of a pre-existing path we don't check that it is a directory. + when defined(solaris): + let res = mkdir(dir, 0o777) + if res == 0'i32: + result = true + elif errno in {EEXIST, ENOSYS}: + result = false + else: + raiseOSError(osLastError(), dir) + elif defined(haiku): + let res = mkdir(dir, 0o777) + if res == 0'i32: + result = true + elif errno == EEXIST or errno == EROFS: + result = false + else: + raiseOSError(osLastError(), dir) + elif defined(posix): + let res = mkdir(dir, 0o777) + if res == 0'i32: + result = true + elif errno == EEXIST: + result = false + else: + #echo res + raiseOSError(osLastError(), dir) + else: + when useWinUnicode: + wrapUnary(res, createDirectoryW, dir) + else: + let res = createDirectoryA(dir) + + if res != 0'i32: + result = true + elif getLastError() == 183'i32: + result = false + else: + raiseOSError(osLastError(), dir) + +proc existsOrCreateDir*(dir: string): bool {.rtl, extern: "nos$1", + tags: [WriteDirEffect, ReadDirEffect], noNimScript.} = + ## Check if a `directory`:idx: `dir` exists, and create it otherwise. + ## + ## Does not create parent directories (fails if parent does not exist). + ## Returns `true` if the directory already exists, and `false` + ## otherwise. + ## + ## See also: + ## * `removeDir proc <#removeDir,string>`_ + ## * `createDir proc <#createDir,string>`_ + ## * `copyDir proc <#copyDir,string,string>`_ + ## * `copyDirWithPermissions proc <#copyDirWithPermissions,string,string>`_ + ## * `moveDir proc <#moveDir,string,string>`_ + result = not rawCreateDir(dir) + if result: + # path already exists - need to check that it is indeed a directory + if not existsDir(dir): + raise newException(IOError, "Failed to create '" & dir & "'") + +proc createDir*(dir: string) {.rtl, extern: "nos$1", + tags: [WriteDirEffect, ReadDirEffect], noNimScript.} = + ## Creates the `directory`:idx: `dir`. + ## + ## The directory may contain several subdirectories that do not exist yet. + ## The full path is created. If this fails, `OSError` is raised. + ## + ## It does **not** fail if the directory already exists because for + ## most usages this does not indicate an error. + ## + ## See also: + ## * `removeDir proc <#removeDir,string>`_ + ## * `existsOrCreateDir proc <#existsOrCreateDir,string>`_ + ## * `copyDir proc <#copyDir,string,string>`_ + ## * `copyDirWithPermissions proc <#copyDirWithPermissions,string,string>`_ + ## * `moveDir proc <#moveDir,string,string>`_ + var omitNext = false + when doslikeFileSystem: + omitNext = isAbsolute(dir) + for i in 1.. dir.len-1: + if dir[i] in {DirSep, AltSep}: + if omitNext: + omitNext = false + else: + discard existsOrCreateDir(substr(dir, 0, i-1)) + + # The loop does not create the dir itself if it doesn't end in separator + if dir.len > 0 and not omitNext and + dir[^1] notin {DirSep, AltSep}: + discard existsOrCreateDir(dir) + +proc copyDir*(source, dest: string) {.rtl, extern: "nos$1", + tags: [WriteIOEffect, ReadIOEffect], benign, noNimScript.} = + ## Copies a directory from `source` to `dest`. + ## + ## If this fails, `OSError` is raised. + ## + ## On the Windows platform this proc will copy the attributes from + ## `source` into `dest`. + ## + ## On other platforms created files and directories will inherit the + ## default permissions of a newly created file/directory for the user. + ## Use `copyDirWithPermissions proc <#copyDirWithPermissions,string,string>`_ + ## to preserve attributes recursively on these platforms. + ## + ## See also: + ## * `copyDirWithPermissions proc <#copyDirWithPermissions,string,string>`_ + ## * `copyFile proc <#copyFile,string,string>`_ + ## * `copyFileWithPermissions proc <#copyFileWithPermissions,string,string>`_ + ## * `removeDir proc <#removeDir,string>`_ + ## * `existsOrCreateDir proc <#existsOrCreateDir,string>`_ + ## * `createDir proc <#createDir,string>`_ + ## * `moveDir proc <#moveDir,string,string>`_ + createDir(dest) + for kind, path in walkDir(source): + var noSource = splitPath(path).tail + case kind + of pcFile: + copyFile(path, dest / noSource) + of pcDir: + copyDir(path, dest / noSource) + else: discard + +proc moveDir*(source, dest: string) {.tags: [ReadIOEffect, WriteIOEffect], noNimScript.} = + ## Moves a directory from `source` to `dest`. + ## + ## If this fails, `OSError` is raised. + ## + ## See also: + ## * `moveFile proc <#moveFile,string,string>`_ + ## * `copyDir proc <#copyDir,string,string>`_ + ## * `copyDirWithPermissions proc <#copyDirWithPermissions,string,string>`_ + ## * `removeDir proc <#removeDir,string>`_ + ## * `existsOrCreateDir proc <#existsOrCreateDir,string>`_ + ## * `createDir proc <#createDir,string>`_ + if not tryMoveFSObject(source, dest): + when not defined(windows): + # Fallback to copy & del + copyDir(source, dest) + removeDir(source) + +proc createSymlink*(src, dest: string) {.noNimScript.} = + ## Create a symbolic link at `dest` which points to the item specified + ## by `src`. On most operating systems, will fail if a link already exists. + ## + ## **Warning**: + ## Some OS's (such as Microsoft Windows) restrict the creation + ## of symlinks to root users (administrators). + ## + ## See also: + ## * `createHardlink proc <#createHardlink,string,string>`_ + ## * `expandSymlink proc <#expandSymlink,string>`_ + + when defined(Windows): + # 2 is the SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE. This allows + # anyone with developer mode on to create a link + let flag = dirExists(src).int32 or 2 + when useWinUnicode: + var wSrc = newWideCString(src) + var wDst = newWideCString(dest) + if createSymbolicLinkW(wDst, wSrc, flag) == 0 or getLastError() != 0: + raiseOSError(osLastError(), $(src, dest)) + else: + if createSymbolicLinkA(dest, src, flag) == 0 or getLastError() != 0: + raiseOSError(osLastError(), $(src, dest)) + else: + if symlink(src, dest) != 0: + raiseOSError(osLastError(), $(src, dest)) + +proc createHardlink*(src, dest: string) {.noNimScript.} = ## Create a hard link at `dest` which points to the item specified ## by `src`. ## - ## .. warning:: Some OS's restrict the creation of hard links to - ## root users (administrators). + ## **Warning**: Some OS's restrict the creation of hard links to + ## root users (administrators). ## ## See also: - ## * `createSymlink proc`_ - when defined(windows): - var wSrc = newWideCString(src) - var wDst = newWideCString(dest) - if createHardLinkW(wDst, wSrc, nil) == 0: - raiseOSError(osLastError(), $(src, dest)) + ## * `createSymlink proc <#createSymlink,string,string>`_ + when defined(Windows): + when useWinUnicode: + var wSrc = newWideCString(src) + var wDst = newWideCString(dest) + if createHardLinkW(wDst, wSrc, nil) == 0: + raiseOSError(osLastError(), $(src, dest)) + else: + if createHardLinkA(dest, src, nil) == 0: + raiseOSError(osLastError(), $(src, dest)) else: if link(src, dest) != 0: raiseOSError(osLastError(), $(src, dest)) +proc copyFileWithPermissions*(source, dest: string, + ignorePermissionErrors = true) {.noNimScript.} = + ## Copies a file from `source` to `dest` preserving file permissions. + ## + ## This is a wrapper proc around `copyFile <#copyFile,string,string>`_, + ## `getFilePermissions <#getFilePermissions,string>`_ and + ## `setFilePermissions<#setFilePermissions,string,set[FilePermission]>`_ + ## procs on non-Windows platforms. + ## + ## On Windows this proc is just a wrapper for `copyFile proc + ## <#copyFile,string,string>`_ since that proc already copies attributes. + ## + ## On non-Windows systems permissions are copied after the file itself has + ## been copied, which won't happen atomically and could lead to a race + ## condition. If `ignorePermissionErrors` is true (default), errors while + ## reading/setting file attributes will be ignored, otherwise will raise + ## `OSError`. + ## + ## See also: + ## * `copyFile proc <#copyFile,string,string>`_ + ## * `copyDir proc <#copyDir,string,string>`_ + ## * `tryRemoveFile proc <#tryRemoveFile,string>`_ + ## * `removeFile proc <#removeFile,string>`_ + ## * `moveFile proc <#moveFile,string,string>`_ + ## * `copyDirWithPermissions proc <#copyDirWithPermissions,string,string>`_ + copyFile(source, dest) + when not defined(Windows): + try: + setFilePermissions(dest, getFilePermissions(source)) + except: + if not ignorePermissionErrors: + raise + +proc copyDirWithPermissions*(source, dest: string, + ignorePermissionErrors = true) {.rtl, extern: "nos$1", + tags: [WriteIOEffect, ReadIOEffect], benign, noNimScript.} = + ## Copies a directory from `source` to `dest` preserving file permissions. + ## + ## If this fails, `OSError` is raised. This is a wrapper proc around `copyDir + ## <#copyDir,string,string>`_ and `copyFileWithPermissions + ## <#copyFileWithPermissions,string,string>`_ procs + ## on non-Windows platforms. + ## + ## On Windows this proc is just a wrapper for `copyDir proc + ## <#copyDir,string,string>`_ since that proc already copies attributes. + ## + ## On non-Windows systems permissions are copied after the file or directory + ## itself has been copied, which won't happen atomically and could lead to a + ## race condition. If `ignorePermissionErrors` is true (default), errors while + ## reading/setting file attributes will be ignored, otherwise will raise + ## `OSError`. + ## + ## See also: + ## * `copyDir proc <#copyDir,string,string>`_ + ## * `copyFile proc <#copyFile,string,string>`_ + ## * `copyFileWithPermissions proc <#copyFileWithPermissions,string,string>`_ + ## * `removeDir proc <#removeDir,string>`_ + ## * `moveDir proc <#moveDir,string,string>`_ + ## * `existsOrCreateDir proc <#existsOrCreateDir,string>`_ + ## * `createDir proc <#createDir,string>`_ + createDir(dest) + when not defined(Windows): + try: + setFilePermissions(dest, getFilePermissions(source)) + except: + if not ignorePermissionErrors: + raise + for kind, path in walkDir(source): + var noSource = splitPath(path).tail + case kind + of pcFile: + copyFileWithPermissions(path, dest / noSource, ignorePermissionErrors) + of pcDir: + copyDirWithPermissions(path, dest / noSource, ignorePermissionErrors) + else: discard + proc inclFilePermissions*(filename: string, permissions: set[FilePermission]) {. - rtl, extern: "nos$1", tags: [ReadDirEffect, WriteDirEffect], noWeirdTarget.} = + rtl, extern: "nos$1", tags: [ReadDirEffect, WriteDirEffect], noNimScript.} = ## A convenience proc for: ## ## .. code-block:: nim @@ -488,18 +2452,282 @@ proc inclFilePermissions*(filename: string, proc exclFilePermissions*(filename: string, permissions: set[FilePermission]) {. - rtl, extern: "nos$1", tags: [ReadDirEffect, WriteDirEffect], noWeirdTarget.} = + rtl, extern: "nos$1", tags: [ReadDirEffect, WriteDirEffect], noNimScript.} = ## A convenience proc for: ## ## .. code-block:: nim ## setFilePermissions(filename, getFilePermissions(filename)-permissions) setFilePermissions(filename, getFilePermissions(filename)-permissions) -when not weirdTarget and (defined(freebsd) or defined(dragonfly) or defined(netbsd)): +proc expandSymlink*(symlinkPath: string): string {.noNimScript.} = + ## Returns a string representing the path to which the symbolic link points. + ## + ## On Windows this is a noop, ``symlinkPath`` is simply returned. + ## + ## See also: + ## * `createSymlink proc <#createSymlink,string,string>`_ + when defined(windows): + result = symlinkPath + else: + result = newString(256) + var len = readlink(symlinkPath, result, 256) + if len < 0: + raiseOSError(osLastError(), symlinkPath) + if len > 256: + result = newString(len+1) + len = readlink(symlinkPath, result, len) + setLen(result, len) + +proc parseCmdLine*(c: string): seq[string] {. + noSideEffect, rtl, extern: "nos$1".} = + ## Splits a `command line`:idx: into several components. + ## + ## **Note**: This proc is only occasionally useful, better use the + ## `parseopt module `_. + ## + ## On Windows, it uses the `following parsing rules + ## `_: + ## + ## * Arguments are delimited by white space, which is either a space or a tab. + ## * The caret character (^) is not recognized as an escape character or + ## delimiter. The character is handled completely by the command-line parser + ## in the operating system before being passed to the argv array in the + ## program. + ## * A string surrounded by double quotation marks ("string") is interpreted + ## as a single argument, regardless of white space contained within. A + ## quoted string can be embedded in an argument. + ## * A double quotation mark preceded by a backslash (\") is interpreted as a + ## literal double quotation mark character ("). + ## * Backslashes are interpreted literally, unless they immediately precede + ## a double quotation mark. + ## * If an even number of backslashes is followed by a double quotation mark, + ## one backslash is placed in the argv array for every pair of backslashes, + ## and the double quotation mark is interpreted as a string delimiter. + ## * If an odd number of backslashes is followed by a double quotation mark, + ## one backslash is placed in the argv array for every pair of backslashes, + ## and the double quotation mark is "escaped" by the remaining backslash, + ## causing a literal double quotation mark (") to be placed in argv. + ## + ## On Posix systems, it uses the following parsing rules: + ## Components are separated by whitespace unless the whitespace + ## occurs within ``"`` or ``'`` quotes. + ## + ## See also: + ## * `parseopt module `_ + ## * `paramCount proc <#paramCount>`_ + ## * `paramStr proc <#paramStr,int>`_ + ## * `commandLineParams proc <#commandLineParams>`_ + + result = @[] + var i = 0 + var a = "" + while true: + setLen(a, 0) + # eat all delimiting whitespace + while i < c.len and c[i] in {' ', '\t', '\l', '\r'}: inc(i) + if i >= c.len: break + when defined(windows): + # parse a single argument according to the above rules: + var inQuote = false + while i < c.len: + case c[i] + of '\\': + var j = i + while j < c.len and c[j] == '\\': inc(j) + if j < c.len and c[j] == '"': + for k in 1..(j-i) div 2: a.add('\\') + if (j-i) mod 2 == 0: + i = j + else: + a.add('"') + i = j+1 + else: + a.add(c[i]) + inc(i) + of '"': + inc(i) + if not inQuote: inQuote = true + elif i < c.len and c[i] == '"': + a.add(c[i]) + inc(i) + else: + inQuote = false + break + of ' ', '\t': + if not inQuote: break + a.add(c[i]) + inc(i) + else: + a.add(c[i]) + inc(i) + else: + case c[i] + of '\'', '\"': + var delim = c[i] + inc(i) # skip ' or " + while i < c.len and c[i] != delim: + add a, c[i] + inc(i) + if i < c.len: inc(i) + else: + while i < c.len and c[i] > ' ': + add(a, c[i]) + inc(i) + add(result, a) + +when defined(nimdoc): + # Common forward declaration docstring block for parameter retrieval procs. + proc paramCount*(): int {.tags: [ReadIOEffect].} = + ## Returns the number of `command line arguments`:idx: given to the + ## application. + ## + ## Unlike `argc`:idx: in C, if your binary was called without parameters this + ## will return zero. + ## You can query each individual parameter with `paramStr proc <#paramStr,int>`_ + ## or retrieve all of them in one go with `commandLineParams proc + ## <#commandLineParams>`_. + ## + ## **Availability**: When generating a dynamic library (see `--app:lib`) on + ## Posix this proc is not defined. + ## Test for availability using `declared() `_. + ## + ## See also: + ## * `parseopt module `_ + ## * `parseCmdLine proc <#parseCmdLine,string>`_ + ## * `paramStr proc <#paramStr,int>`_ + ## * `commandLineParams proc <#commandLineParams>`_ + ## + ## **Examples:** + ## + ## .. code-block:: nim + ## when declared(paramCount): + ## # Use paramCount() here + ## else: + ## # Do something else! + + proc paramStr*(i: int): TaintedString {.tags: [ReadIOEffect].} = + ## Returns the `i`-th `command line argument`:idx: given to the application. + ## + ## `i` should be in the range `1..paramCount()`, the `IndexError` + ## exception will be raised for invalid values. Instead of iterating over + ## `paramCount() <#paramCount>`_ with this proc you can call the + ## convenience `commandLineParams() <#commandLineParams>`_. + ## + ## Similarly to `argv`:idx: in C, + ## it is possible to call ``paramStr(0)`` but this will return OS specific + ## contents (usually the name of the invoked executable). You should avoid + ## this and call `getAppFilename() <#getAppFilename>`_ instead. + ## + ## **Availability**: When generating a dynamic library (see `--app:lib`) on + ## Posix this proc is not defined. + ## Test for availability using `declared() `_. + ## + ## See also: + ## * `parseopt module `_ + ## * `parseCmdLine proc <#parseCmdLine,string>`_ + ## * `paramCount proc <#paramCount>`_ + ## * `commandLineParams proc <#commandLineParams>`_ + ## * `getAppFilename proc <#getAppFilename>`_ + ## + ## **Examples:** + ## + ## .. code-block:: nim + ## when declared(paramStr): + ## # Use paramStr() here + ## else: + ## # Do something else! + +elif defined(nintendoswitch) or weirdTarget: + proc paramStr*(i: int): TaintedString {.tags: [ReadIOEffect].} = + raise newException(OSError, "paramStr is not implemented on Nintendo Switch") + + proc paramCount*(): int {.tags: [ReadIOEffect].} = + raise newException(OSError, "paramCount is not implemented on Nintendo Switch") + +elif defined(windows): + # Since we support GUI applications with Nim, we sometimes generate + # a WinMain entry proc. But a WinMain proc has no access to the parsed + # command line arguments. The way to get them differs. Thus we parse them + # ourselves. This has the additional benefit that the program's behaviour + # is always the same -- independent of the used C compiler. + var + ownArgv {.threadvar.}: seq[string] + ownParsedArgv {.threadvar.}: bool + + proc paramCount*(): int {.rtl, extern: "nos$1", tags: [ReadIOEffect].} = + # Docstring in nimdoc block. + if not ownParsedArgv: + ownArgv = parseCmdLine($getCommandLine()) + ownParsedArgv = true + result = ownArgv.len-1 + + proc paramStr*(i: int): TaintedString {.rtl, extern: "nos$1", + tags: [ReadIOEffect].} = + # Docstring in nimdoc block. + if not ownParsedArgv: + ownArgv = parseCmdLine($getCommandLine()) + ownParsedArgv = true + if i < ownArgv.len and i >= 0: return TaintedString(ownArgv[i]) + raise newException(IndexError, formatErrorIndexBound(i, ownArgv.len-1)) + +elif defined(genode): + proc paramStr*(i: int): TaintedString = + raise newException(OSError, "paramStr is not implemented on Genode") + + proc paramCount*(): int = + raise newException(OSError, "paramCount is not implemented on Genode") + +elif not defined(createNimRtl) and + not(defined(posix) and appType == "lib"): + # On Posix, there is no portable way to get the command line from a DLL. + var + cmdCount {.importc: "cmdCount".}: cint + cmdLine {.importc: "cmdLine".}: cstringArray + + proc paramStr*(i: int): TaintedString {.tags: [ReadIOEffect].} = + # Docstring in nimdoc block. + if i < cmdCount and i >= 0: return TaintedString($cmdLine[i]) + raise newException(IndexError, formatErrorIndexBound(i, cmdCount-1)) + + proc paramCount*(): int {.tags: [ReadIOEffect].} = + # Docstring in nimdoc block. + result = cmdCount-1 + +when declared(paramCount) or defined(nimdoc): + proc commandLineParams*(): seq[TaintedString] = + ## Convenience proc which returns the command line parameters. + ## + ## This returns **only** the parameters. If you want to get the application + ## executable filename, call `getAppFilename() <#getAppFilename>`_. + ## + ## **Availability**: On Posix there is no portable way to get the command + ## line from a DLL and thus the proc isn't defined in this environment. You + ## can test for its availability with `declared() + ## `_. + ## + ## See also: + ## * `parseopt module `_ + ## * `parseCmdLine proc <#parseCmdLine,string>`_ + ## * `paramCount proc <#paramCount>`_ + ## * `paramStr proc <#paramStr,int>`_ + ## * `getAppFilename proc <#getAppFilename>`_ + ## + ## **Examples:** + ## + ## .. code-block:: nim + ## when declared(commandLineParams): + ## # Use commandLineParams() here + ## else: + ## # Do something else! + result = @[] + for i in 1..paramCount(): + result.add(paramStr(i)) + +when not weirdTarget and (defined(freebsd) or defined(dragonfly)): proc sysctl(name: ptr cint, namelen: cuint, oldp: pointer, oldplen: ptr csize_t, newp: pointer, newplen: csize_t): cint {.importc: "sysctl",header: """#include - #include """.} + #include """} const CTL_KERN = 1 KERN_PROC = 14 @@ -507,45 +2735,42 @@ when not weirdTarget and (defined(freebsd) or defined(dragonfly) or defined(netb when defined(freebsd): const KERN_PROC_PATHNAME = 12 - elif defined(netbsd): - const KERN_PROC_ARGS = 48 - const KERN_PROC_PATHNAME = 5 else: const KERN_PROC_PATHNAME = 9 proc getApplFreebsd(): string = - var pathLength = csize_t(0) - - when defined(netbsd): - var req = [CTL_KERN.cint, KERN_PROC_ARGS.cint, -1.cint, KERN_PROC_PATHNAME.cint] - else: - var req = [CTL_KERN.cint, KERN_PROC.cint, KERN_PROC_PATHNAME.cint, -1.cint] - - # first call to get the required length - var res = sysctl(addr req[0], 4, nil, addr pathLength, nil, 0) - - if res < 0: - return "" - - result.setLen(pathLength) - res = sysctl(addr req[0], 4, addr result[0], addr pathLength, nil, 0) - - if res < 0: - return "" - - let realLen = len(cstring(result)) - setLen(result, realLen) + var pathLength = csize_t(MAX_PATH) + result = newString(pathLength) + var req = [CTL_KERN.cint, KERN_PROC.cint, KERN_PROC_PATHNAME.cint, -1.cint] + while true: + let res = sysctl(addr req[0], 4, cast[pointer](addr result[0]), + addr pathLength, nil, 0) + if res < 0: + let err = osLastError() + if err.int32 == ENOMEM: + result = newString(pathLength) + else: + result.setLen(0) # error! + break + else: + # trim the trailing null byte, as the result is a string not a cstring + result.setLen(pathLength-1) + break when not weirdTarget and (defined(linux) or defined(solaris) or defined(bsd) or defined(aix)): proc getApplAux(procPath: string): string = - result = newString(maxSymlinkLen) - var len = readlink(procPath, result.cstring, maxSymlinkLen) - if len > maxSymlinkLen: + result = newString(256) + var len = readlink(procPath, result, 256) + if len > 256: result = newString(len+1) - len = readlink(procPath, result.cstring, len) + len = readlink(procPath, result, len) setLen(result, len) -when not weirdTarget and defined(openbsd): +when defined(openbsd): + proc isExecutable(path: string): bool = + let p = getFilePermissions(path) + result = fpUserExec in p and fpGroupExec in p and fpOthersExec in p + proc getApplOpenBsd(): string = # similar to getApplHeuristic, but checks current working directory when declared(paramStr): @@ -553,7 +2778,7 @@ when not weirdTarget and defined(openbsd): # POSIX guaranties that this contains the executable # as it has been executed by the calling process - let exePath = paramStr(0) + let exePath = string(paramStr(0)) if len(exePath) == 0: return "" @@ -569,12 +2794,15 @@ when not weirdTarget and defined(openbsd): break if len(result) > 0: - return expandFilename(result) + if isExecutable(result): + return expandFilename(result) + + return "" # search in path - for p in split(getEnv("PATH"), {PathSep}): + for p in split(string(getEnv("PATH")), {PathSep}): var x = joinPath(p, exePath) - if fileExists(x): + if existsFile(x) and isExecutable(x): return expandFilename(x) else: result = "" @@ -582,14 +2810,14 @@ when not weirdTarget and defined(openbsd): when not (defined(windows) or defined(macosx) or weirdTarget): proc getApplHeuristic(): string = when declared(paramStr): - result = paramStr(0) + result = string(paramStr(0)) # POSIX guaranties that this contains the executable # as it has been executed by the calling process if len(result) > 0 and result[0] != DirSep: # not an absolute path? # iterate over any path in the $PATH environment variable - for p in split(getEnv("PATH"), {PathSep}): + for p in split(string(getEnv("PATH")), {PathSep}): var x = joinPath(p, result) - if fileExists(x): return x + if existsFile(x): return x else: result = "" @@ -611,7 +2839,7 @@ when defined(haiku): B_FIND_PATH_IMAGE_PATH = 1000 proc find_path(codePointer: pointer, baseDirectory: cint, subPath: cstring, - pathBuffer: cstring, bufferSize: csize_t): int32 + pathBuffer: cstring, bufferSize: csize): int32 {.importc, header: "".} proc getApplHaiku(): string = @@ -623,13 +2851,13 @@ when defined(haiku): else: result = "" -proc getAppFilename*(): string {.rtl, extern: "nos$1", tags: [ReadIOEffect], noWeirdTarget.} = +proc getAppFilename*(): string {.rtl, extern: "nos$1", tags: [ReadIOEffect], noNimScript.} = ## Returns the filename of the application's executable. ## This proc will resolve symlinks. ## ## See also: - ## * `getAppDir proc`_ - ## * `getCurrentCompilerExe proc`_ + ## * `getAppDir proc <#getAppDir>`_ + ## * `getCurrentCompilerExe proc <#getCurrentCompilerExe>`_ # Linux: /proc//exe # Solaris: @@ -637,54 +2865,66 @@ proc getAppFilename*(): string {.rtl, extern: "nos$1", tags: [ReadIOEffect], noW # /proc//path/a.out (complete pathname) when defined(windows): var bufsize = int32(MAX_PATH) - var buf = newWideCString("", bufsize) - while true: - var L = getModuleFileNameW(0, buf, bufsize) - if L == 0'i32: - result = "" # error! - break - elif L > bufsize: - buf = newWideCString("", L) - bufsize = L - else: - result = buf$L - break + when useWinUnicode: + var buf = newWideCString("", bufsize) + while true: + var L = getModuleFileNameW(0, buf, bufsize) + if L == 0'i32: + result = "" # error! + break + elif L > bufsize: + buf = newWideCString("", L) + bufsize = L + else: + result = buf$L + break + else: + result = newString(bufsize) + while true: + var L = getModuleFileNameA(0, result, bufsize) + if L == 0'i32: + result = "" # error! + break + elif L > bufsize: + result = newString(L) + bufsize = L + else: + setLen(result, L) + break elif defined(macosx): - var size = cuint32(0) + var size: cuint32 getExecPath1(nil, size) result = newString(int(size)) - if getExecPath2(result.cstring, size): + if getExecPath2(result, size): result = "" # error! if result.len > 0: result = result.expandFilename else: - when defined(linux) or defined(aix): + when defined(linux) or defined(aix) or defined(netbsd): result = getApplAux("/proc/self/exe") elif defined(solaris): result = getApplAux("/proc/" & $getpid() & "/path/a.out") - elif defined(genode): + elif defined(genode) or defined(nintendoswitch): raiseOSError(OSErrorCode(-1), "POSIX command line not supported") - elif defined(freebsd) or defined(dragonfly) or defined(netbsd): + elif defined(freebsd) or defined(dragonfly): result = getApplFreebsd() elif defined(haiku): result = getApplHaiku() elif defined(openbsd): result = getApplOpenBsd() - elif defined(nintendoswitch): - result = "" # little heuristic that may work on other POSIX-like systems: if result.len == 0: result = getApplHeuristic() -proc getAppDir*(): string {.rtl, extern: "nos$1", tags: [ReadIOEffect], noWeirdTarget.} = +proc getAppDir*(): string {.rtl, extern: "nos$1", tags: [ReadIOEffect], noNimScript.} = ## Returns the directory of the application's executable. ## ## See also: - ## * `getAppFilename proc`_ + ## * `getAppFilename proc <#getAppFilename>`_ result = splitFile(getAppFilename()).dir -proc sleep*(milsecs: int) {.rtl, extern: "nos$1", tags: [TimeEffect], noWeirdTarget.} = +proc sleep*(milsecs: int) {.rtl, extern: "nos$1", tags: [TimeEffect], noNimScript.} = ## Sleeps `milsecs` milliseconds. when defined(windows): winlean.sleep(int32(milsecs)) @@ -695,7 +2935,7 @@ proc sleep*(milsecs: int) {.rtl, extern: "nos$1", tags: [TimeEffect], noWeirdTar discard posix.nanosleep(a, b) proc getFileSize*(file: string): BiggestInt {.rtl, extern: "nos$1", - tags: [ReadIOEffect], noWeirdTarget.} = + tags: [ReadIOEffect], noNimScript.} = ## Returns the file size of `file` (in bytes). ``OSError`` is ## raised in case of an error. when defined(windows): @@ -705,12 +2945,13 @@ proc getFileSize*(file: string): BiggestInt {.rtl, extern: "nos$1", result = rdFileSize(a) findClose(resA) else: - var rawInfo: Stat - if stat(file, rawInfo) < 0'i32: - raiseOSError(osLastError(), file) - rawInfo.st_size + var f: File + if open(f, file): + result = getFileSize(f) + close(f) + else: raiseOSError(osLastError(), file) -when defined(windows) or weirdTarget: +when defined(Windows) or weirdTarget: type DeviceId* = int32 FileId* = int64 @@ -724,9 +2965,9 @@ type ## Contains information associated with a file object. ## ## See also: - ## * `getFileInfo(handle) proc`_ - ## * `getFileInfo(file) proc`_ - ## * `getFileInfo(path, followSymlink) proc`_ + ## * `getFileInfo(handle) proc <#getFileInfo,FileHandle>`_ + ## * `getFileInfo(file) proc <#getFileInfo,File>`_ + ## * `getFileInfo(path) proc <#getFileInfo,string>`_ id*: tuple[device: DeviceId, file: FileId] ## Device and file id. kind*: PathComponent ## Kind of file object - directory, symlink, etc. size*: BiggestInt ## Size of file. @@ -735,24 +2976,13 @@ type lastAccessTime*: times.Time ## Time file was last accessed. lastWriteTime*: times.Time ## Time file was last modified/written to. creationTime*: times.Time ## Time file was created. Not supported on all systems! - blockSize*: int ## Preferred I/O block size for this object. - ## In some filesystems, this may vary from file to file. - isSpecial*: bool ## Is file special? (on Unix some "files" - ## can be special=non-regular like FIFOs, - ## devices); for directories `isSpecial` - ## is always `false`, for symlinks it is - ## the same as for the link's target. template rawToFormalFileInfo(rawInfo, path, formalInfo): untyped = ## Transforms the native file info structure into the one nim uses. ## 'rawInfo' is either a 'BY_HANDLE_FILE_INFORMATION' structure on Windows, ## or a 'Stat' structure on posix - when defined(windows): - template merge(a, b): untyped = - int64( - (uint64(cast[uint32](a))) or - (uint64(cast[uint32](b)) shl 32) - ) + when defined(Windows): + template merge(a, b): untyped = a or (b shl 32) formalInfo.id.device = rawInfo.dwVolumeSerialNumber formalInfo.id.file = merge(rawInfo.nFileIndexLow, rawInfo.nFileIndexHigh) formalInfo.size = merge(rawInfo.nFileSizeLow, rawInfo.nFileSizeHigh) @@ -760,22 +2990,20 @@ template rawToFormalFileInfo(rawInfo, path, formalInfo): untyped = formalInfo.lastAccessTime = fromWinTime(rdFileTime(rawInfo.ftLastAccessTime)) formalInfo.lastWriteTime = fromWinTime(rdFileTime(rawInfo.ftLastWriteTime)) formalInfo.creationTime = fromWinTime(rdFileTime(rawInfo.ftCreationTime)) - formalInfo.blockSize = 8192 # xxx use Windows API instead of hardcoding # Retrieve basic permissions if (rawInfo.dwFileAttributes and FILE_ATTRIBUTE_READONLY) != 0'i32: formalInfo.permissions = {fpUserExec, fpUserRead, fpGroupExec, fpGroupRead, fpOthersExec, fpOthersRead} else: - formalInfo.permissions = {fpUserExec..fpOthersRead} + result.permissions = {fpUserExec..fpOthersRead} # Retrieve basic file kind + result.kind = pcFile if (rawInfo.dwFileAttributes and FILE_ATTRIBUTE_DIRECTORY) != 0'i32: formalInfo.kind = pcDir - else: - formalInfo.kind = pcFile if (rawInfo.dwFileAttributes and FILE_ATTRIBUTE_REPARSE_POINT) != 0'i32: - formalInfo.kind = succ(formalInfo.kind) + formalInfo.kind = succ(result.kind) else: template checkAndIncludeMode(rawMode, formalMode: untyped) = @@ -787,9 +3015,8 @@ template rawToFormalFileInfo(rawInfo, path, formalInfo): untyped = formalInfo.lastAccessTime = rawInfo.st_atim.toTime formalInfo.lastWriteTime = rawInfo.st_mtim.toTime formalInfo.creationTime = rawInfo.st_ctim.toTime - formalInfo.blockSize = rawInfo.st_blksize - formalInfo.permissions = {} + result.permissions = {} checkAndIncludeMode(S_IRUSR, fpUserRead) checkAndIncludeMode(S_IWUSR, fpUserWrite) checkAndIncludeMode(S_IXUSR, fpUserExec) @@ -802,14 +3029,12 @@ template rawToFormalFileInfo(rawInfo, path, formalInfo): untyped = checkAndIncludeMode(S_IWOTH, fpOthersWrite) checkAndIncludeMode(S_IXOTH, fpOthersExec) - (formalInfo.kind, formalInfo.isSpecial) = - if S_ISDIR(rawInfo.st_mode): - (pcDir, false) - elif S_ISLNK(rawInfo.st_mode): - assert(path != "") # symlinks can't occur for file handles - getSymlinkFileKind(path) - else: - (pcFile, not S_ISREG(rawInfo.st_mode)) + formalInfo.kind = pcFile + if S_ISDIR(rawInfo.st_mode): + formalInfo.kind = pcDir + elif S_ISLNK(rawInfo.st_mode): + assert(path != "") # symlinks can't occur for file handles + formalInfo.kind = getSymlinkFileKind(path) when defined(js): when not declared(FileHandle): @@ -817,7 +3042,7 @@ when defined(js): when not declared(File): type File = object -proc getFileInfo*(handle: FileHandle): FileInfo {.noWeirdTarget.} = +proc getFileInfo*(handle: FileHandle): FileInfo {.noNimScript.} = ## Retrieves file information for the file object represented by the given ## handle. ## @@ -825,11 +3050,11 @@ proc getFileInfo*(handle: FileHandle): FileInfo {.noWeirdTarget.} = ## is invalid, `OSError` is raised. ## ## See also: - ## * `getFileInfo(file) proc`_ - ## * `getFileInfo(path, followSymlink) proc`_ + ## * `getFileInfo(file) proc <#getFileInfo,File>`_ + ## * `getFileInfo(path) proc <#getFileInfo,string>`_ # Done: ID, Kind, Size, Permissions, Link Count - when defined(windows): + when defined(Windows): var rawInfo: BY_HANDLE_FILE_INFORMATION # We have to use the super special '_get_osfhandle' call (wrapped above) # To transform the C file descriptor to a native file handle. @@ -843,36 +3068,35 @@ proc getFileInfo*(handle: FileHandle): FileInfo {.noWeirdTarget.} = raiseOSError(osLastError(), $handle) rawToFormalFileInfo(rawInfo, "", result) -proc getFileInfo*(file: File): FileInfo {.noWeirdTarget.} = +proc getFileInfo*(file: File): FileInfo {.noNimScript.} = ## Retrieves file information for the file object. ## ## See also: - ## * `getFileInfo(handle) proc`_ - ## * `getFileInfo(path, followSymlink) proc`_ + ## * `getFileInfo(handle) proc <#getFileInfo,FileHandle>`_ + ## * `getFileInfo(path) proc <#getFileInfo,string>`_ if file.isNil: raise newException(IOError, "File is nil") result = getFileInfo(file.getFileHandle()) -proc getFileInfo*(path: string, followSymlink = true): FileInfo {.noWeirdTarget.} = +proc getFileInfo*(path: string, followSymlink = true): FileInfo {.noNimScript.} = ## Retrieves file information for the file object pointed to by `path`. ## ## Due to intrinsic differences between operating systems, the information - ## contained by the returned `FileInfo object`_ will be slightly + ## contained by the returned `FileInfo object <#FileInfo>`_ will be slightly ## different across platforms, and in some cases, incomplete or inaccurate. ## ## When `followSymlink` is true (default), symlinks are followed and the ## information retrieved is information related to the symlink's target. - ## Otherwise, information on the symlink itself is retrieved (however, - ## field `isSpecial` is still determined from the target on Unix). + ## Otherwise, information on the symlink itself is retrieved. ## ## If the information cannot be retrieved, such as when the path doesn't ## exist, or when permission restrictions prevent the program from retrieving ## file information, `OSError` is raised. ## ## See also: - ## * `getFileInfo(handle) proc`_ - ## * `getFileInfo(file) proc`_ - when defined(windows): + ## * `getFileInfo(handle) proc <#getFileInfo,FileHandle>`_ + ## * `getFileInfo(file) proc <#getFileInfo,File>`_ + when defined(Windows): var handle = openHandle(path, followSymlink) rawInfo: BY_HANDLE_FILE_INFORMATION @@ -892,40 +3116,7 @@ proc getFileInfo*(path: string, followSymlink = true): FileInfo {.noWeirdTarget. raiseOSError(osLastError(), path) rawToFormalFileInfo(rawInfo, path, result) -proc sameFileContent*(path1, path2: string): bool {.rtl, extern: "nos$1", - tags: [ReadIOEffect], noWeirdTarget.} = - ## Returns true if both pathname arguments refer to files with identical - ## binary content. - ## - ## See also: - ## * `sameFile proc`_ - var - a, b: File - if not open(a, path1): return false - if not open(b, path2): - close(a) - return false - let bufSize = getFileInfo(a).blockSize - var bufA = alloc(bufSize) - var bufB = alloc(bufSize) - while true: - var readA = readBuffer(a, bufA, bufSize) - var readB = readBuffer(b, bufB, bufSize) - if readA != readB: - result = false - break - if readA == 0: - result = true - break - result = equalMem(bufA, bufB, readA) - if not result: break - if readA != bufSize: break # end of file - dealloc(bufA) - dealloc(bufB) - close(a) - close(b) - -proc isHidden*(path: string): bool {.noWeirdTarget.} = +proc isHidden*(path: string): bool {.noNimScript.} = ## Determines whether ``path`` is hidden or not, using `this ## reference `_. ## @@ -944,15 +3135,18 @@ proc isHidden*(path: string): bool {.noWeirdTarget.} = assert not "".isHidden assert ".foo/".isHidden - when defined(windows): - wrapUnary(attributes, getFileAttributesW, path) + when defined(Windows): + when useWinUnicode: + wrapUnary(attributes, getFileAttributesW, path) + else: + var attributes = getFileAttributesA(path) if attributes != -1'i32: result = (attributes and FILE_ATTRIBUTE_HIDDEN) != 0'i32 else: let fileName = lastPathPart(path) result = len(fileName) >= 2 and fileName[0] == '.' and fileName != ".." -proc getCurrentProcessId*(): int {.noWeirdTarget.} = +proc getCurrentProcessId*(): int {.noNimScript.} = ## Return current process ID. ## ## See also: @@ -964,7 +3158,7 @@ proc getCurrentProcessId*(): int {.noWeirdTarget.} = else: result = getpid() -proc setLastModificationTime*(file: string, t: times.Time) {.noWeirdTarget.} = +proc setLastModificationTime*(file: string, t: times.Time) {.noNimScript.} = ## Sets the `file`'s last modification time. `OSError` is raised in case of ## an error. when defined(posix): @@ -982,44 +3176,36 @@ proc setLastModificationTime*(file: string, t: times.Time) {.noWeirdTarget.} = if res == 0'i32: raiseOSError(osLastError(), file) -func isValidFilename*(filename: string, maxLen = 259.Positive): bool {.since: (1, 1).} = - ## Returns `true` if `filename` is valid for crossplatform use. - ## - ## This is useful if you want to copy or save files across Windows, Linux, Mac, etc. - ## It uses `invalidFilenameChars`, `invalidFilenames` and `maxLen` to verify the specified `filename`. - ## - ## See also: - ## - ## * https://docs.microsoft.com/en-us/dotnet/api/system.io.pathtoolongexception - ## * https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file - ## * https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247%28v=vs.85%29.aspx - ## - ## .. warning:: This only checks filenames, not whole paths - ## (because basically you can mount anything as a path on Linux). - runnableExamples: - assert not isValidFilename(" foo") # Leading white space - assert not isValidFilename("foo ") # Trailing white space - assert not isValidFilename("foo.") # Ends with dot - assert not isValidFilename("con.txt") # "CON" is invalid (Windows) - assert not isValidFilename("OwO:UwU") # ":" is invalid (Mac) - assert not isValidFilename("aux.bat") # "AUX" is invalid (Windows) - assert not isValidFilename("") # Empty string - assert not isValidFilename("foo/") # Filename is empty +when isMainModule: + assert quoteShellWindows("aaa") == "aaa" + assert quoteShellWindows("aaa\"") == "aaa\\\"" + assert quoteShellWindows("") == "\"\"" - result = true - let f = filename.splitFile() - if unlikely(f.name.len + f.ext.len > maxLen or f.name.len == 0 or - f.name[0] == ' ' or f.name[^1] == ' ' or f.name[^1] == '.' or - find(f.name, invalidFilenameChars) != -1): return false - for invalid in invalidFilenames: - if cmpIgnoreCase(f.name, invalid) == 0: return false + assert quoteShellPosix("aaa") == "aaa" + assert quoteShellPosix("aaa a") == "'aaa a'" + assert quoteShellPosix("") == "''" + assert quoteShellPosix("a'a") == "'a'\"'\"'a'" + when defined(posix): + assert quoteShell("") == "''" -# deprecated declarations -when not defined(nimscript): - when not defined(js): # `noNimJs` doesn't work with templates, this should improve. - template existsFile*(args: varargs[untyped]): untyped {.deprecated: "use fileExists".} = - fileExists(args) - template existsDir*(args: varargs[untyped]): untyped {.deprecated: "use dirExists".} = - dirExists(args) - # {.deprecated: [existsFile: fileExists].} # pending bug #14819; this would avoid above mentioned issue + block normalizePathEndTest: + # handle edge cases correctly: shouldn't affect whether path is + # absolute/relative + doAssert "".normalizePathEnd(true) == "" + doAssert "".normalizePathEnd(false) == "" + doAssert "/".normalizePathEnd(true) == $DirSep + doAssert "/".normalizePathEnd(false) == $DirSep + + when defined(posix): + doAssert "//".normalizePathEnd(false) == "/" + doAssert "foo.bar//".normalizePathEnd == "foo.bar" + doAssert "bar//".normalizePathEnd(trailingSep = true) == "bar/" + when defined(Windows): + doAssert r"C:\foo\\".normalizePathEnd == r"C:\foo" + doAssert r"C:\foo".normalizePathEnd(trailingSep = true) == r"C:\foo\" + # this one is controversial: we could argue for returning `D:\` instead, + # but this is simplest. + doAssert r"D:\".normalizePathEnd == r"D:" + doAssert r"E:/".normalizePathEnd(trailingSep = true) == r"E:\" + doAssert "/".normalizePathEnd == r"\" diff --git a/lib/pure/osproc.nim b/lib/pure/osproc.nim index 915337f12..9b11d440b 100644 --- a/lib/pure/osproc.nim +++ b/lib/pure/osproc.nim @@ -18,8 +18,7 @@ include "system/inclrtl" import - strutils, os, strtabs, streams, cpuinfo, streamwrapper, - std/private/since + strutils, os, strtabs, streams, cpuinfo export quoteShell, quoteShellWindows, quoteShellPosix @@ -31,12 +30,6 @@ else: when defined(linux) and defined(useClone): import linux -when defined(nimPreviewSlimSystem): - import std/[syncio, assertions] - when defined(windows): - import std/widestrs - - type ProcessOption* = enum ## Options that can be passed to `startProcess proc ## <#startProcess,string,string,openArray[string],StringTableRef,set[ProcessOption]>`_. @@ -72,17 +65,23 @@ type Process* = ref ProcessObj ## Represents an operating system process. +const poDemon* {.deprecated.} = poDaemon ## Nim versions before 0.20 + ## used the wrong spelling ("demon"). + ## Now `ProcessOption` uses the correct spelling ("daemon"), + ## and this is needed just for backward compatibility. + proc execProcess*(command: string, workingDir: string = "", args: openArray[string] = [], env: StringTableRef = nil, options: set[ProcessOption] = {poStdErrToStdOut, poUsePath, poEvalCommand}): - string {.rtl, extern: "nosp$1", raises: [OSError, IOError], + TaintedString {.rtl, extern: "nosp$1", tags: [ExecIOEffect, ReadIOEffect, RootEffect].} ## A convenience procedure that executes ``command`` with ``startProcess`` ## and returns its output as a string. ## - ## .. warning:: This function uses `poEvalCommand` by default for backwards - ## compatibility. Make sure to pass options explicitly. + ## **WARNING:** This function uses `poEvalCommand` by default for backward + ## compatibility. + ## Make sure to pass options explicitly. ## ## See also: ## * `startProcess proc @@ -106,7 +105,7 @@ proc execCmd*(command: string): int {.rtl, extern: "nosp$1", ## This operation is also often called `system`:idx:. ## ## See also: - ## * `execCmdEx proc <#execCmdEx,string,set[ProcessOption],StringTableRef,string,string>`_ + ## * `execCmdEx proc <#execCmdEx,string,set[ProcessOption]>`_ ## * `startProcess proc ## <#startProcess,string,string,openArray[string],StringTableRef,set[ProcessOption]>`_ ## * `execProcess proc @@ -120,7 +119,7 @@ proc execCmd*(command: string): int {.rtl, extern: "nosp$1", proc startProcess*(command: string, workingDir: string = "", args: openArray[string] = [], env: StringTableRef = nil, options: set[ProcessOption] = {poStdErrToStdOut}): - owned(Process) {.rtl, extern: "nosp$1", raises: [OSError, IOError], + owned(Process) {.rtl, extern: "nosp$1", tags: [ExecIOEffect, ReadEnvEffect, RootEffect].} ## Starts a process. `Command` is the executable file, `workingDir` is the ## process's working directory. If ``workingDir == ""`` the current directory @@ -152,12 +151,12 @@ proc startProcess*(command: string, workingDir: string = "", ## <#execProcess,string,string,openArray[string],StringTableRef,set[ProcessOption]>`_ ## * `execCmd proc <#execCmd,string>`_ -proc close*(p: Process) {.rtl, extern: "nosp$1", raises: [IOError, OSError], tags: [WriteIOEffect].} +proc close*(p: Process) {.rtl, extern: "nosp$1", tags: [WriteIOEffect].} ## When the process has finished executing, cleanup related handles. ## - ## .. warning:: If the process has not finished executing, this will forcibly - ## terminate the process. Doing so may result in zombie processes and - ## `pty leaks `_. + ## **WARNING:** If the process has not finished executing, this will forcibly + ## terminate the process. Doing so may result in zombie processes and + ## `pty leaks `_. proc suspend*(p: Process) {.rtl, extern: "nosp$1", tags: [].} ## Suspends the process `p`. @@ -187,7 +186,6 @@ proc terminate*(p: Process) {.rtl, extern: "nosp$1", tags: [].} ## * `suspend proc <#suspend,Process>`_ ## * `resume proc <#resume,Process>`_ ## * `kill proc <#kill,Process>`_ - ## * `posix_utils.sendSignal(pid: Pid, signal: int) `_ proc kill*(p: Process) {.rtl, extern: "nosp$1", tags: [].} ## Kill the process `p`. @@ -199,10 +197,9 @@ proc kill*(p: Process) {.rtl, extern: "nosp$1", tags: [].} ## * `suspend proc <#suspend,Process>`_ ## * `resume proc <#resume,Process>`_ ## * `terminate proc <#terminate,Process>`_ - ## * `posix_utils.sendSignal(pid: Pid, signal: int) `_ -proc running*(p: Process): bool {.rtl, extern: "nosp$1", raises: [OSError], tags: [].} - ## Returns true if the process `p` is still running. Returns immediately. +proc running*(p: Process): bool {.rtl, extern: "nosp$1", tags: [].} + ## Returns true iff the process `p` is still running. Returns immediately. proc processID*(p: Process): int {.rtl, extern: "nosp$1".} = ## Returns `p`'s process ID. @@ -212,20 +209,16 @@ proc processID*(p: Process): int {.rtl, extern: "nosp$1".} = return p.id proc waitForExit*(p: Process, timeout: int = -1): int {.rtl, - extern: "nosp$1", raises: [OSError, ValueError], tags: [].} + extern: "nosp$1", tags: [].} ## Waits for the process to finish and returns `p`'s error code. ## - ## .. warning:: Be careful when using `waitForExit` for processes created without - ## `poParentStreams` because they may fill output buffers, causing deadlock. + ## **WARNING**: Be careful when using `waitForExit` for processes created without + ## `poParentStreams` because they may fill output buffers, causing deadlock. ## ## On posix, if the process has exited because of a signal, 128 + signal ## number will be returned. - ## - ## .. warning:: When working with `timeout` parameters, remember that the value is - ## typically expressed in milliseconds, and ensure that the correct unit of time - ## is used to avoid unexpected behavior. -proc peekExitCode*(p: Process): int {.rtl, extern: "nosp$1", raises: [OSError], tags: [].} +proc peekExitCode*(p: Process): int {.rtl, extern: "nosp$1", tags: [].} ## Return `-1` if the process is still running. Otherwise the process' exit code. ## ## On posix, if the process has exited because of a signal, 128 + signal @@ -234,22 +227,18 @@ proc peekExitCode*(p: Process): int {.rtl, extern: "nosp$1", raises: [OSError], proc inputStream*(p: Process): Stream {.rtl, extern: "nosp$1", tags: [].} ## Returns ``p``'s input stream for writing to. ## - ## .. warning:: The returned `Stream` should not be closed manually as it - ## is closed when closing the Process ``p``. + ## **WARNING**: The returned `Stream` should not be closed manually as it + ## is closed when closing the Process ``p``. ## ## See also: ## * `outputStream proc <#outputStream,Process>`_ ## * `errorStream proc <#errorStream,Process>`_ -proc outputStream*(p: Process): Stream {.rtl, extern: "nosp$1", raises: [IOError, OSError], tags: [].} +proc outputStream*(p: Process): Stream {.rtl, extern: "nosp$1", tags: [].} ## Returns ``p``'s output stream for reading from. ## - ## You cannot perform peek/write/setOption operations to this stream. - ## Use `peekableOutputStream proc <#peekableOutputStream,Process>`_ - ## if you need to peek stream. - ## - ## .. warning:: The returned `Stream` should not be closed manually as it - ## is closed when closing the Process ``p``. + ## **WARNING**: The returned `Stream` should not be closed manually as it + ## is closed when closing the Process ``p``. ## ## See also: ## * `inputStream proc <#inputStream,Process>`_ @@ -258,47 +247,19 @@ proc outputStream*(p: Process): Stream {.rtl, extern: "nosp$1", raises: [IOError proc errorStream*(p: Process): Stream {.rtl, extern: "nosp$1", tags: [].} ## Returns ``p``'s error stream for reading from. ## - ## You cannot perform peek/write/setOption operations to this stream. - ## Use `peekableErrorStream proc <#peekableErrorStream,Process>`_ - ## if you need to peek stream. - ## - ## .. warning:: The returned `Stream` should not be closed manually as it - ## is closed when closing the Process ``p``. + ## **WARNING**: The returned `Stream` should not be closed manually as it + ## is closed when closing the Process ``p``. ## ## See also: ## * `inputStream proc <#inputStream,Process>`_ ## * `outputStream proc <#outputStream,Process>`_ -proc peekableOutputStream*(p: Process): Stream {.rtl, extern: "nosp$1", tags: [], since: (1, 3).} - ## Returns ``p``'s output stream for reading from. - ## - ## You can peek returned stream. - ## - ## .. warning:: The returned `Stream` should not be closed manually as it - ## is closed when closing the Process ``p``. - ## - ## See also: - ## * `outputStream proc <#outputStream,Process>`_ - ## * `peekableErrorStream proc <#peekableErrorStream,Process>`_ - -proc peekableErrorStream*(p: Process): Stream {.rtl, extern: "nosp$1", tags: [], since: (1, 3).} - ## Returns ``p``'s error stream for reading from. - ## - ## You can run peek operation to returned stream. - ## - ## .. warning:: The returned `Stream` should not be closed manually as it - ## is closed when closing the Process ``p``. - ## - ## See also: - ## * `errorStream proc <#errorStream,Process>`_ - ## * `peekableOutputStream proc <#peekableOutputStream,Process>`_ - -proc inputHandle*(p: Process): FileHandle {.rtl, raises: [], extern: "nosp$1", +proc inputHandle*(p: Process): FileHandle {.rtl, extern: "nosp$1", tags: [].} = ## Returns ``p``'s input file handle for writing to. ## - ## .. warning:: The returned `FileHandle` should not be closed manually as - ## it is closed when closing the Process ``p``. + ## **WARNING**: The returned `FileHandle` should not be closed manually as + ## it is closed when closing the Process ``p``. ## ## See also: ## * `outputHandle proc <#outputHandle,Process>`_ @@ -306,11 +267,11 @@ proc inputHandle*(p: Process): FileHandle {.rtl, raises: [], extern: "nosp$1", result = p.inHandle proc outputHandle*(p: Process): FileHandle {.rtl, extern: "nosp$1", - raises: [], tags: [].} = + tags: [].} = ## Returns ``p``'s output file handle for reading from. ## - ## .. warning:: The returned `FileHandle` should not be closed manually as - ## it is closed when closing the Process ``p``. + ## **WARNING**: The returned `FileHandle` should not be closed manually as + ## it is closed when closing the Process ``p``. ## ## See also: ## * `inputHandle proc <#inputHandle,Process>`_ @@ -318,34 +279,28 @@ proc outputHandle*(p: Process): FileHandle {.rtl, extern: "nosp$1", result = p.outHandle proc errorHandle*(p: Process): FileHandle {.rtl, extern: "nosp$1", - raises: [], tags: [].} = + tags: [].} = ## Returns ``p``'s error file handle for reading from. ## - ## .. warning:: The returned `FileHandle` should not be closed manually as - ## it is closed when closing the Process ``p``. + ## **WARNING**: The returned `FileHandle` should not be closed manually as + ## it is closed when closing the Process ``p``. ## ## See also: ## * `inputHandle proc <#inputHandle,Process>`_ ## * `outputHandle proc <#outputHandle,Process>`_ result = p.errHandle -proc countProcessors*(): int {.rtl, extern: "nosp$1", raises: [].} = +proc countProcessors*(): int {.rtl, extern: "nosp$1".} = ## Returns the number of the processors/cores the machine has. ## Returns 0 if it cannot be detected. - ## It is implemented just calling `cpuinfo.countProcessors`. result = cpuinfo.countProcessors() -when not defined(nimHasEffectsOf): - {.pragma: effectsOf.} - proc execProcesses*(cmds: openArray[string], options = {poStdErrToStdOut, poParentStreams}, n = countProcessors(), beforeRunEvent: proc(idx: int) = nil, afterRunEvent: proc(idx: int, p: Process) = nil): int {.rtl, extern: "nosp$1", - raises: [ValueError, OSError, IOError], - tags: [ExecIOEffect, TimeEffect, ReadEnvEffect, RootEffect], - effectsOf: [beforeRunEvent, afterRunEvent].} = + tags: [ExecIOEffect, TimeEffect, ReadEnvEffect, RootEffect].} = ## Executes the commands `cmds` in parallel. ## Creates `n` processes that execute in parallel. ## @@ -425,8 +380,6 @@ proc execProcesses*(cmds: openArray[string], raiseOSError(err) if rexit >= 0: - when defined(windows): - let processHandle = q[rexit].fProcessHandle result = max(result, abs(q[rexit].peekExitCode())) if afterRunEvent != nil: afterRunEvent(idxs[rexit], q[rexit]) close(q[rexit]) @@ -441,7 +394,7 @@ proc execProcesses*(cmds: openArray[string], else: when defined(windows): for k in 0..wcount - 1: - if w[k] == processHandle: + if w[k] == q[rexit].fProcessHandle: w[k] = w[wcount - 1] w[wcount - 1] = 0 dec(wcount) @@ -457,101 +410,37 @@ proc execProcesses*(cmds: openArray[string], if afterRunEvent != nil: afterRunEvent(i, p) close(p) -iterator lines*(p: Process, keepNewLines = false): string {.since: (1, 3), raises: [OSError, IOError, ValueError], tags: [ReadIOEffect].} = - ## Convenience iterator for working with `startProcess` to read data from a - ## background process. - ## - ## See also: - ## * `readLines proc <#readLines,Process>`_ - ## - ## Example: - ## - ## .. code-block:: Nim - ## const opts = {poUsePath, poDaemon, poStdErrToStdOut} - ## var ps: seq[Process] - ## for prog in ["a", "b"]: # run 2 progs in parallel - ## ps.add startProcess("nim", "", ["r", prog], nil, opts) - ## for p in ps: - ## var i = 0 - ## for line in p.lines: - ## echo line - ## i.inc - ## if i > 100: break - ## p.close - var outp = p.outputStream - var line = newStringOfCap(120) - while outp.readLine(line): - if keepNewLines: - line.add("\n") - yield line - discard waitForExit(p) - -proc readLines*(p: Process): (seq[string], int) {.since: (1, 3), - raises: [OSError, IOError, ValueError], tags: [ReadIOEffect].} = - ## Convenience function for working with `startProcess` to read data from a - ## background process. - ## - ## See also: - ## * `lines iterator <#lines.i,Process>`_ - ## - ## Example: - ## - ## .. code-block:: Nim - ## const opts = {poUsePath, poDaemon, poStdErrToStdOut} - ## var ps: seq[Process] - ## for prog in ["a", "b"]: # run 2 progs in parallel - ## ps.add startProcess("nim", "", ["r", prog], nil, opts) - ## for p in ps: - ## let (lines, exCode) = p.readLines - ## if exCode != 0: - ## for line in lines: echo line - ## p.close - for line in p.lines: result[0].add(line) - result[1] = p.peekExitCode - when not defined(useNimRtl): proc execProcess(command: string, workingDir: string = "", args: openArray[string] = [], env: StringTableRef = nil, options: set[ProcessOption] = {poStdErrToStdOut, poUsePath, poEvalCommand}): - string = + TaintedString = var p = startProcess(command, workingDir = workingDir, args = args, env = env, options = options) var outp = outputStream(p) - result = "" - var line = newStringOfCap(120) - # consider `p.lines(keepNewLines=true)` to circumvent `running` busy-wait + result = TaintedString"" + var line = newStringOfCap(120).TaintedString while true: # FIXME: converts CR-LF to LF. if outp.readLine(line): - result.add(line) - result.add("\n") + result.string.add(line.string) + result.string.add("\n") elif not running(p): break close(p) template streamAccess(p) = assert poParentStreams notin p.options, "API usage error: stream access not allowed when you use poParentStreams" -when defined(windows) and not defined(useNimRtl): +when defined(Windows) and not defined(useNimRtl): # We need to implement a handle stream for Windows: type FileHandleStream = ref object of StreamObj handle: Handle atTheEnd: bool - proc closeHandleCheck(handle: Handle) {.inline.} = - if handle.closeHandle() == 0: - raiseOSError(osLastError()) - - proc fileClose[T: Handle | FileHandle](h: var T) {.inline.} = - if h > 4: - closeHandleCheck(h) - h = INVALID_HANDLE_VALUE.T - - proc hsClose(s: Stream) = - FileHandleStream(s).handle.fileClose() - + proc hsClose(s: Stream) = discard # nothing to do here proc hsAtEnd(s: Stream): bool = return FileHandleStream(s).atTheEnd proc hsReadData(s: Stream, buffer: pointer, bufLen: int): int = @@ -574,8 +463,12 @@ when defined(windows) and not defined(useNimRtl): if a == 0: raiseOSError(osLastError()) proc newFileHandleStream(handle: Handle): owned FileHandleStream = - result = FileHandleStream(handle: handle, closeImpl: hsClose, atEndImpl: hsAtEnd, - readDataImpl: hsReadData, writeDataImpl: hsWriteData) + new(result) + result.handle = handle + result.closeImpl = hsClose + result.atEndImpl = hsAtEnd + result.readDataImpl = hsReadData + result.writeDataImpl = hsWriteData proc buildCommandLine(a: string, args: openArray[string]): string = result = quoteShell(a) @@ -651,8 +544,8 @@ when defined(windows) and not defined(useNimRtl): stdin = myDup(pipeIn, 0) stdout = myDup(pipeOut, 0) - closeHandleCheck(pipeIn) - closeHandleCheck(pipeOut) + discard closeHandle(pipeIn) + discard closeHandle(pipeOut) stderr = stdout proc createPipeHandles(rdHandle, wrHandle: var Handle) = @@ -663,6 +556,9 @@ when defined(windows) and not defined(useNimRtl): if createPipe(rdHandle, wrHandle, sa, 0) == 0'i32: raiseOSError(osLastError()) + proc fileClose(h: Handle) {.inline.} = + if h > 4: discard closeHandle(h) + proc startProcess(command: string, workingDir: string = "", args: openArray[string] = [], env: StringTableRef = nil, options: set[ProcessOption] = {poStdErrToStdOut}): @@ -718,15 +614,19 @@ when defined(windows) and not defined(useNimRtl): if len(workingDir) > 0: wd = workingDir if env != nil: e = buildEnv(env) if poEchoCmd in options: echo($cmdl) - var tmp = newWideCString(cmdl) - var ee = - if e.str.isNil: newWideCString(cstring(nil)) - else: newWideCString(e.str, e.len) - var wwd = newWideCString(wd) - var flags = NORMAL_PRIORITY_CLASS or CREATE_UNICODE_ENVIRONMENT - if poDaemon in options: flags = flags or CREATE_NO_WINDOW - success = winlean.createProcessW(nil, tmp, nil, nil, 1, flags, - ee, wwd, si, procInfo) + when useWinUnicode: + var tmp = newWideCString(cmdl) + var ee = + if e.str.isNil: newWideCString(cstring(nil)) + else: newWideCString(e.str, e.len) + var wwd = newWideCString(wd) + var flags = NORMAL_PRIORITY_CLASS or CREATE_UNICODE_ENVIRONMENT + if poDaemon in options: flags = flags or CREATE_NO_WINDOW + success = winlean.createProcessW(nil, tmp, nil, nil, 1, flags, + ee, wwd, si, procInfo) + else: + success = winlean.createProcessA(nil, + cmdl, nil, nil, 1, NORMAL_PRIORITY_CLASS, e, wd, si, procInfo) let lastError = osLastError() if poParentStreams notin options: @@ -742,7 +642,7 @@ when defined(windows) and not defined(useNimRtl): const errFileNotFound = 2.int if lastError.int in {errInvalidParameter, errFileNotFound}: raiseOSError(lastError, - "Requested command not found: '" & command & "'. OS error:") + "Requested command not found: '$1'. OS error:" % command) else: raiseOSError(lastError, command) result.fProcessHandle = procInfo.hProcess @@ -750,31 +650,13 @@ when defined(windows) and not defined(useNimRtl): result.id = procInfo.dwProcessId result.exitFlag = false - proc closeThreadAndProcessHandle(p: Process) = - if p.fThreadHandle != 0: - closeHandleCheck(p.fThreadHandle) - p.fThreadHandle = 0 - - if p.fProcessHandle != 0: - closeHandleCheck(p.fProcessHandle) - p.fProcessHandle = 0 - proc close(p: Process) = if poParentStreams notin p.options: - if p.inStream == nil: - p.inHandle.fileClose() - else: - # p.inHandle can be already closed via inputStream. - p.inStream.close - - # You may NOT close outputStream and errorStream. - assert p.outStream == nil or FileHandleStream(p.outStream).handle != INVALID_HANDLE_VALUE - assert p.errStream == nil or FileHandleStream(p.errStream).handle != INVALID_HANDLE_VALUE - - if p.outHandle != p.errHandle: - p.errHandle.fileClose() - p.outHandle.fileClose() - p.closeThreadAndProcessHandle() + discard closeHandle(p.inHandle) + discard closeHandle(p.outHandle) + discard closeHandle(p.errHandle) + discard closeHandle(p.fThreadHandle) + discard closeHandle(p.fProcessHandle) proc suspend(p: Process) = discard suspendThread(p.fThreadHandle) @@ -808,7 +690,8 @@ when defined(windows) and not defined(useNimRtl): if status != STILL_ACTIVE: p.exitFlag = true p.exitStatus = status - p.closeThreadAndProcessHandle() + discard closeHandle(p.fThreadHandle) + discard closeHandle(p.fProcessHandle) result = status else: result = -1 @@ -824,7 +707,8 @@ when defined(windows) and not defined(useNimRtl): discard getExitCodeProcess(p.fProcessHandle, status) p.exitFlag = true p.exitStatus = status - p.closeThreadAndProcessHandle() + discard closeHandle(p.fThreadHandle) + discard closeHandle(p.fProcessHandle) result = status proc inputStream(p: Process): Stream = @@ -845,18 +729,6 @@ when defined(windows) and not defined(useNimRtl): p.errStream = newFileHandleStream(p.errHandle) result = p.errStream - proc peekableOutputStream(p: Process): Stream = - streamAccess(p) - if p.outStream == nil: - p.outStream = newFileHandleStream(p.outHandle).newPipeOutStream - result = p.outStream - - proc peekableErrorStream(p: Process): Stream = - streamAccess(p) - if p.errStream == nil: - p.errStream = newFileHandleStream(p.errHandle).newPipeOutStream - result = p.errStream - proc execCmd(command: string): int = var si: STARTUPINFO @@ -867,9 +739,13 @@ when defined(windows) and not defined(useNimRtl): si.hStdError = getStdHandle(STD_ERROR_HANDLE) si.hStdInput = getStdHandle(STD_INPUT_HANDLE) si.hStdOutput = getStdHandle(STD_OUTPUT_HANDLE) - var c = newWideCString(command) - var res = winlean.createProcessW(nil, c, nil, nil, 0, - NORMAL_PRIORITY_CLASS, nil, nil, si, procInfo) + when useWinUnicode: + var c = newWideCString(command) + var res = winlean.createProcessW(nil, c, nil, nil, 0, + NORMAL_PRIORITY_CLASS, nil, nil, si, procInfo) + else: + var res = winlean.createProcessA(nil, command, nil, nil, 0, + NORMAL_PRIORITY_CLASS, nil, nil, si, procInfo) if res == 0: raiseOSError(osLastError()) else: @@ -928,7 +804,7 @@ elif not defined(useNimRtl): result = cast[cstringArray](alloc0((counter + 1) * sizeof(cstring))) var i = 0 for key, val in envPairs(): - var x = key & "=" & val + var x = key.string & "=" & val.string result[i] = cast[cstring](alloc(x.len+1)) copyMem(result[i], addr(x[0]), x.len+1) inc(i) @@ -946,14 +822,14 @@ elif not defined(useNimRtl): not defined(useClone) and not defined(linux) when useProcessAuxSpawn: proc startProcessAuxSpawn(data: StartProcessData): Pid {. - raises: [OSError], tags: [ExecIOEffect, ReadEnvEffect, ReadDirEffect, RootEffect], gcsafe.} + tags: [ExecIOEffect, ReadEnvEffect, ReadDirEffect, RootEffect], gcsafe.} else: proc startProcessAuxFork(data: StartProcessData): Pid {. - raises: [OSError], tags: [ExecIOEffect, ReadEnvEffect, ReadDirEffect, RootEffect], gcsafe.} - {.push stacktrace: off, profiler: off.} - proc startProcessAfterFork(data: ptr StartProcessData) {. - raises: [OSError], tags: [ExecIOEffect, ReadEnvEffect, ReadDirEffect, RootEffect], cdecl, gcsafe.} - {.pop.} + tags: [ExecIOEffect, ReadEnvEffect, ReadDirEffect, RootEffect], gcsafe.} + {.push stacktrace: off, profiler: off.} + proc startProcessAfterFork(data: ptr StartProcessData) {. + tags: [ExecIOEffect, ReadEnvEffect, ReadDirEffect, RootEffect], cdecl, gcsafe.} + {.pop.} proc startProcess(command: string, workingDir: string = "", args: openArray[string] = [], env: StringTableRef = nil, @@ -977,7 +853,7 @@ elif not defined(useNimRtl): when not defined(android): "/bin/sh" else: "/system/bin/sh" data.sysCommand = useShPath - sysArgsRaw = @[useShPath, "-c", command] + sysArgsRaw = @[data.sysCommand, "-c", command] assert args.len == 0, "`args` has to be empty when using poEvalCommand." else: data.sysCommand = command @@ -1015,7 +891,7 @@ elif not defined(useNimRtl): # Parent process. Copy process information. if poEchoCmd in options: - echo(command, " ", join(args, " ")) + when declared(echo): echo(command, " ", join(args, " ")) result.id = pid result.exitFlag = false @@ -1079,9 +955,9 @@ elif not defined(useNimRtl): var pid: Pid if (poUsePath in data.options): - res = posix_spawnp(pid, data.sysCommand.cstring, fops, attr, data.sysArgs, data.sysEnv) + res = posix_spawnp(pid, data.sysCommand, fops, attr, data.sysArgs, data.sysEnv) else: - res = posix_spawn(pid, data.sysCommand.cstring, fops, attr, data.sysArgs, data.sysEnv) + res = posix_spawn(pid, data.sysCommand, fops, attr, data.sysArgs, data.sysEnv) discard posix_spawn_file_actions_destroy(fops) discard posix_spawnattr_destroy(attr) @@ -1122,61 +998,61 @@ elif not defined(useNimRtl): let sizeRead = read(data.pErrorPipe[readIdx], addr error, sizeof(error)) if sizeRead == sizeof(error): raiseOSError(osLastError(), - "Could not find command: '" & $data.sysCommand & "'. OS error: " & $strerror(error)) + "Could not find command: '$1'. OS error: $2" % + [$data.sysCommand, $strerror(error)]) return pid - {.push stacktrace: off, profiler: off.} - proc startProcessFail(data: ptr StartProcessData) = - var error: cint = errno - discard write(data.pErrorPipe[writeIdx], addr error, sizeof(error)) - exitnow(1) + {.push stacktrace: off, profiler: off.} + proc startProcessFail(data: ptr StartProcessData) = + var error: cint = errno + discard write(data.pErrorPipe[writeIdx], addr error, sizeof(error)) + exitnow(1) - when not defined(uClibc) and (not defined(linux) or defined(android)) and - not defined(haiku): - var environ {.importc.}: cstringArray + when not defined(uClibc) and (not defined(linux) or defined(android)): + var environ {.importc.}: cstringArray - proc startProcessAfterFork(data: ptr StartProcessData) = - # Warning: no GC here! - # Or anything that touches global structures - all called nim procs - # must be marked with stackTrace:off. Inspect C code after making changes. - if not (poParentStreams in data.options): - discard close(data.pStdin[writeIdx]) - if dup2(data.pStdin[readIdx], readIdx) < 0: + proc startProcessAfterFork(data: ptr StartProcessData) = + # Warning: no GC here! + # Or anything that touches global structures - all called nim procs + # must be marked with stackTrace:off. Inspect C code after making changes. + if not (poParentStreams in data.options): + discard close(data.pStdin[writeIdx]) + if dup2(data.pStdin[readIdx], readIdx) < 0: + startProcessFail(data) + discard close(data.pStdout[readIdx]) + if dup2(data.pStdout[writeIdx], writeIdx) < 0: + startProcessFail(data) + discard close(data.pStderr[readIdx]) + if (poStdErrToStdOut in data.options): + if dup2(data.pStdout[writeIdx], 2) < 0: startProcessFail(data) - discard close(data.pStdout[readIdx]) - if dup2(data.pStdout[writeIdx], writeIdx) < 0: - startProcessFail(data) - discard close(data.pStderr[readIdx]) - if (poStdErrToStdOut in data.options): - if dup2(data.pStdout[writeIdx], 2) < 0: - startProcessFail(data) - else: - if dup2(data.pStderr[writeIdx], 2) < 0: - startProcessFail(data) - - if data.workingDir.len > 0: - if chdir(data.workingDir) < 0: - startProcessFail(data) - - discard close(data.pErrorPipe[readIdx]) - discard fcntl(data.pErrorPipe[writeIdx], F_SETFD, FD_CLOEXEC) - - if (poUsePath in data.options): - when defined(uClibc) or defined(linux) or defined(haiku): - # uClibc environment (OpenWrt included) doesn't have the full execvpe - let exe = findExe(data.sysCommand) - discard execve(exe.cstring, data.sysArgs, data.sysEnv) - else: - # MacOSX doesn't have execvpe, so we need workaround. - # On MacOSX we can arrive here only from fork, so this is safe: - environ = data.sysEnv - discard execvp(data.sysCommand.cstring, data.sysArgs) else: - discard execve(data.sysCommand.cstring, data.sysArgs, data.sysEnv) + if dup2(data.pStderr[writeIdx], 2) < 0: + startProcessFail(data) - startProcessFail(data) - {.pop.} + if data.workingDir.len > 0: + if chdir(data.workingDir) < 0: + startProcessFail(data) + + discard close(data.pErrorPipe[readIdx]) + discard fcntl(data.pErrorPipe[writeIdx], F_SETFD, FD_CLOEXEC) + + if (poUsePath in data.options): + when defined(uClibc) or defined(linux): + # uClibc environment (OpenWrt included) doesn't have the full execvpe + let exe = findExe(data.sysCommand) + discard execve(exe, data.sysArgs, data.sysEnv) + else: + # MacOSX doesn't have execvpe, so we need workaround. + # On MacOSX we can arrive here only from fork, so this is safe: + environ = data.sysEnv + discard execvp(data.sysCommand, data.sysArgs) + else: + discard execve(data.sysCommand, data.sysArgs, data.sysEnv) + + startProcessFail(data) + {.pop.} proc close(p: Process) = if poParentStreams notin p.options: @@ -1229,7 +1105,7 @@ elif not defined(useNimRtl): when defined(macosx) or defined(freebsd) or defined(netbsd) or defined(openbsd) or defined(dragonfly): - import kqueue + import kqueue, times proc waitForExit(p: Process, timeout: int = -1): int = if p.exitFlag: @@ -1289,67 +1165,6 @@ elif not defined(useNimRtl): discard posix.close(kqFD) result = exitStatusLikeShell(p.exitStatus) - elif defined(haiku): - const - B_OBJECT_TYPE_THREAD = 3 - B_EVENT_INVALID = 0x1000 - B_RELATIVE_TIMEOUT = 0x8 - - type - ObjectWaitInfo {.importc: "object_wait_info", header: "OS.h".} = object - obj {.importc: "object".}: int32 - typ {.importc: "type".}: uint16 - events: uint16 - - proc waitForObjects(infos: ptr ObjectWaitInfo, numInfos: cint, flags: uint32, - timeout: int64): clong - {.importc: "wait_for_objects_etc", header: "OS.h".} - - proc waitForExit(p: Process, timeout: int = -1): int = - if p.exitFlag: - return exitStatusLikeShell(p.exitStatus) - - if timeout == -1: - var status: cint = 1 - if waitpid(p.id, status, 0) < 0: - raiseOSError(osLastError()) - p.exitFlag = true - p.exitStatus = status - else: - var info = ObjectWaitInfo( - obj: p.id, # Haiku's PID is actually the main thread ID. - typ: B_OBJECT_TYPE_THREAD, - events: B_EVENT_INVALID # notify when the thread die. - ) - - while true: - var status: cint = 1 - let count = waitForObjects(addr info, 1, B_RELATIVE_TIMEOUT, timeout) - - if count < 0: - let err = count.cint - if err == ETIMEDOUT: - # timeout expired, so we try to kill the process - if posix.kill(p.id, SIGKILL) == -1: - raiseOSError(osLastError()) - if waitpid(p.id, status, 0) < 0: - raiseOSError(osLastError()) - p.exitFlag = true - p.exitStatus = status - break - elif err != EINTR: - raiseOSError(err.OSErrorCode) - elif count > 0: - if waitpid(p.id, status, 0) < 0: - raiseOSError(osLastError()) - p.exitFlag = true - p.exitStatus = status - break - else: - doAssert false, "unreachable!" - - result = exitStatusLikeShell(p.exitStatus) - else: import times @@ -1475,47 +1290,35 @@ elif not defined(useNimRtl): p.exitStatus = status result = exitStatusLikeShell(status) - proc createStream(handle: var FileHandle, - fileMode: FileMode): owned FileStream = + proc createStream(stream: var owned(Stream), handle: var FileHandle, + fileMode: FileMode) = var f: File if not open(f, handle, fileMode): raiseOSError(osLastError()) - return newFileStream(f) + stream = newFileStream(f) proc inputStream(p: Process): Stream = streamAccess(p) if p.inStream == nil: - p.inStream = createStream(p.inHandle, fmWrite) + createStream(p.inStream, p.inHandle, fmWrite) return p.inStream proc outputStream(p: Process): Stream = streamAccess(p) if p.outStream == nil: - p.outStream = createStream(p.outHandle, fmRead) + createStream(p.outStream, p.outHandle, fmRead) return p.outStream proc errorStream(p: Process): Stream = streamAccess(p) if p.errStream == nil: - p.errStream = createStream(p.errHandle, fmRead) - return p.errStream - - proc peekableOutputStream(p: Process): Stream = - streamAccess(p) - if p.outStream == nil: - p.outStream = createStream(p.outHandle, fmRead).newPipeOutStream - return p.outStream - - proc peekableErrorStream(p: Process): Stream = - streamAccess(p) - if p.errStream == nil: - p.errStream = createStream(p.errHandle, fmRead).newPipeOutStream + createStream(p.errStream, p.errHandle, fmRead) return p.errStream proc csystem(cmd: cstring): cint {.nodecl, importc: "system", header: "".} proc execCmd(command: string): int = - when defined(posix): + when defined(linux): let tmp = csystem(command) result = if tmp == -1: tmp else: exitStatusLikeShell(tmp) else: @@ -1565,17 +1368,12 @@ elif not defined(useNimRtl): proc execCmdEx*(command: string, options: set[ProcessOption] = { - poStdErrToStdOut, poUsePath}, env: StringTableRef = nil, - workingDir = "", input = ""): tuple[ - output: string, - exitCode: int] {.raises: [OSError, IOError], tags: + poStdErrToStdOut, poUsePath}): tuple[ + output: TaintedString, + exitCode: int] {.tags: [ExecIOEffect, ReadIOEffect, RootEffect], gcsafe.} = - ## A convenience proc that runs the `command`, and returns its `output` and - ## `exitCode`. `env` and `workingDir` params behave as for `startProcess`. - ## If `input.len > 0`, it is passed as stdin. - ## - ## Note: this could block if `input.len` is greater than your OS's maximum - ## pipe buffer size. + ## A convenience proc that runs the `command`, grabs all its output and + ## exit code and returns both. ## ## See also: ## * `execCmd proc <#execCmd,string>`_ @@ -1587,40 +1385,22 @@ proc execCmdEx*(command: string, options: set[ProcessOption] = { ## Example: ## ## .. code-block:: Nim - ## var result = execCmdEx("nim r --hints:off -", options = {}, input = "echo 3*4") - ## import std/[strutils, strtabs] - ## stripLineEnd(result[0]) ## portable way to remove trailing newline, if any - ## doAssert result == ("12", 0) - ## doAssert execCmdEx("ls --nonexistent").exitCode != 0 - ## when defined(posix): - ## assert execCmdEx("echo $FO", env = newStringTable({"FO": "B"})) == ("B\n", 0) - ## assert execCmdEx("echo $PWD", workingDir = "/") == ("/\n", 0) + ## let (outp, errC) = execCmdEx("nim c -r mytestfile.nim") - when (NimMajor, NimMinor, NimPatch) < (1, 3, 5): - doAssert input.len == 0 - doAssert workingDir.len == 0 - doAssert env == nil - - var p = startProcess(command, options = options + {poEvalCommand}, - workingDir = workingDir, env = env) + var p = startProcess(command, options = options + {poEvalCommand}) var outp = outputStream(p) - if input.len > 0: - # There is no way to provide input for the child process - # anymore. Closing it will create EOF on stdin instead of eternal - # blocking. - # Writing in chunks would require a selectors (eg kqueue/epoll) to avoid - # blocking on io. - inputStream(p).write(input) + # There is no way to provide input for the child process + # anymore. Closing it will create EOF on stdin instead of eternal + # blocking. close inputStream(p) - # consider `p.lines(keepNewLines=true)` to avoid exit code test - result = ("", -1) - var line = newStringOfCap(120) + result = (TaintedString"", -1) + var line = newStringOfCap(120).TaintedString while true: if outp.readLine(line): - result[0].add(line) - result[0].add("\n") + result[0].string.add(line.string) + result[0].string.add("\n") else: result[1] = peekExitCode(p) if result[1] != -1: break diff --git a/lib/pure/oswalkdir.nim b/lib/pure/oswalkdir.nim new file mode 100644 index 000000000..1cf561c22 --- /dev/null +++ b/lib/pure/oswalkdir.nim @@ -0,0 +1,36 @@ +# +# +# Nim's Runtime Library +# (c) Copyright 2015 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +## Compile-time only version for walkDir if you need it at compile-time +## for JavaScript. + +type + PathComponent* = enum ## Enumeration specifying a path component. + pcFile, ## path refers to a file + pcLinkToFile, ## path refers to a symbolic link to a file + pcDir, ## path refers to a directory + pcLinkToDir ## path refers to a symbolic link to a directory + +proc staticWalkDir(dir: string; relative: bool): seq[ + tuple[kind: PathComponent; path: string]] = + discard + +iterator walkDir*(dir: string; relative = false): tuple[kind: PathComponent; + path: string] = + for k, v in items(staticWalkDir(dir, relative)): + yield (k, v) + +iterator walkDirRec*(dir: string; filter = {pcFile, pcDir}): string = + var stack = @[dir] + while stack.len > 0: + for k, p in walkDir(stack.pop()): + if k in filter: + case k + of pcFile, pcLinkToFile: yield p + of pcDir, pcLinkToDir: stack.add(p) diff --git a/lib/pure/parsecfg.nim b/lib/pure/parsecfg.nim index 54584a253..c8e936ef1 100644 --- a/lib/pure/parsecfg.nim +++ b/lib/pure/parsecfg.nim @@ -7,8 +7,8 @@ # distribution, for details about the copyright. # -## The `parsecfg` module implements a high performance configuration file -## parser. The configuration file's syntax is similar to the Windows `.ini` +## The ``parsecfg`` module implements a high performance configuration file +## parser. The configuration file's syntax is similar to the Windows ``.ini`` ## format, but much more powerful, as it is not a line based parser. String ## literals, raw string literals and triple quoted string literals are supported ## as in the Nim programming language. @@ -19,32 +19,37 @@ ## :literal: ## ## Here is an example of how to use the configuration file parser: -runnableExamples("-r:off"): - import std/[strutils, streams] - - let configFile = "example.ini" - var f = newFileStream(configFile, fmRead) - assert f != nil, "cannot open " & configFile - var p: CfgParser - open(p, f, configFile) - while true: - var e = next(p) - case e.kind - of cfgEof: break - of cfgSectionStart: ## a `[section]` has been parsed - echo "new section: " & e.section - of cfgKeyValuePair: - echo "key-value-pair: " & e.key & ": " & e.value - of cfgOption: - echo "command: " & e.key & ": " & e.value - of cfgError: - echo e.msg - close(p) - -##[ +## +## .. code-block:: nim +## +## import os, parsecfg, strutils, streams +## +## var f = newFileStream(paramStr(1), fmRead) +## if f != nil: +## var p: CfgParser +## open(p, f, paramStr(1)) +## while true: +## var e = next(p) +## case e.kind +## of cfgEof: break +## of cfgSectionStart: ## a ``[section]`` has been parsed +## echo("new section: " & e.section) +## of cfgKeyValuePair: +## echo("key-value-pair: " & e.key & ": " & e.value) +## of cfgOption: +## echo("command: " & e.key & ": " & e.value) +## of cfgError: +## echo(e.msg) +## close(p) +## else: +## echo("cannot open: " & paramStr(1)) +## +## +## Examples +## ======== +## ## Configuration file example -]## - +## -------------------------- ## ## .. code-block:: nim ## @@ -53,140 +58,67 @@ runnableExamples("-r:off"): ## name = "hello" ## --threads:on ## [Author] -## name = "nim-lang" -## website = "nim-lang.org" - -##[ +## name = "lihf8515" +## qq = "10214028" +## email = "lihaifeng@wxm.com" +## ## Creating a configuration file -]## - -runnableExamples: - var dict = newConfig() - dict.setSectionKey("","charset", "utf-8") - dict.setSectionKey("Package", "name", "hello") - dict.setSectionKey("Package", "--threads", "on") - dict.setSectionKey("Author", "name", "nim-lang") - dict.setSectionKey("Author", "website", "nim-lang.org") - assert $dict == """ -charset=utf-8 -[Package] -name=hello ---threads:on -[Author] -name=nim-lang -website=nim-lang.org -""" - -##[ +## ----------------------------- +## .. code-block:: nim +## +## import parsecfg +## var dict=newConfig() +## dict.setSectionKey("","charset","utf-8") +## dict.setSectionKey("Package","name","hello") +## dict.setSectionKey("Package","--threads","on") +## dict.setSectionKey("Author","name","lihf8515") +## dict.setSectionKey("Author","qq","10214028") +## dict.setSectionKey("Author","email","lihaifeng@wxm.com") +## dict.writeConfig("config.ini") +## ## Reading a configuration file -]## - -runnableExamples("-r:off"): - let dict = loadConfig("config.ini") - let charset = dict.getSectionValue("","charset") - let threads = dict.getSectionValue("Package","--threads") - let pname = dict.getSectionValue("Package","name") - let name = dict.getSectionValue("Author","name") - let website = dict.getSectionValue("Author","website") - echo pname & "\n" & name & "\n" & website - -##[ +## ---------------------------- +## .. code-block:: nim +## +## import parsecfg +## var dict = loadConfig("config.ini") +## var charset = dict.getSectionValue("","charset") +## var threads = dict.getSectionValue("Package","--threads") +## var pname = dict.getSectionValue("Package","name") +## var name = dict.getSectionValue("Author","name") +## var qq = dict.getSectionValue("Author","qq") +## var email = dict.getSectionValue("Author","email") +## echo pname & "\n" & name & "\n" & qq & "\n" & email +## ## Modifying a configuration file -]## - -runnableExamples("-r:off"): - var dict = loadConfig("config.ini") - dict.setSectionKey("Author", "name", "nim-lang") - dict.writeConfig("config.ini") - -##[ +## ------------------------------ +## .. code-block:: nim +## +## import parsecfg +## var dict = loadConfig("config.ini") +## dict.setSectionKey("Author","name","lhf") +## dict.writeConfig("config.ini") +## ## Deleting a section key in a configuration file -]## +## ---------------------------------------------- +## .. code-block:: nim +## +## import parsecfg +## var dict = loadConfig("config.ini") +## dict.delSectionKey("Author","email") +## dict.writeConfig("config.ini") -runnableExamples("-r:off"): - var dict = loadConfig("config.ini") - dict.delSectionKey("Author", "website") - dict.writeConfig("config.ini") - -##[ -## Supported INI File structure -]## - -# taken from https://docs.python.org/3/library/configparser.html#supported-ini-file-structure -runnableExamples: - import std/streams - - var dict = loadConfig(newStringStream("""[Simple Values] - key=value - spaces in keys=allowed - spaces in values=allowed as well - spaces around the delimiter = obviously - you can also use : to delimit keys from values - [All Values Are Strings] - values like this: 19990429 - or this: 3.14159265359 - are they treated as numbers : no - integers floats and booleans are held as: strings - can use the API to get converted values directly: true - [No Values] - key_without_value - # empty string value is not allowed = - [ Seletion A ] - space around section name will be ignored - [You can use comments] - # like this - ; or this - # By default only in an empty line. - # Inline comments can be harmful because they prevent users - # from using the delimiting characters as parts of values. - # That being said, this can be customized. - [Sections Can Be Indented] - can_values_be_as_well = True - does_that_mean_anything_special = False - purpose = formatting for readability - # Did I mention we can indent comments, too? - """) - ) - - let section1 = "Simple Values" - assert dict.getSectionValue(section1, "key") == "value" - assert dict.getSectionValue(section1, "spaces in keys") == "allowed" - assert dict.getSectionValue(section1, "spaces in values") == "allowed as well" - assert dict.getSectionValue(section1, "spaces around the delimiter") == "obviously" - assert dict.getSectionValue(section1, "you can also use") == "to delimit keys from values" - - let section2 = "All Values Are Strings" - assert dict.getSectionValue(section2, "values like this") == "19990429" - assert dict.getSectionValue(section2, "or this") == "3.14159265359" - assert dict.getSectionValue(section2, "are they treated as numbers") == "no" - assert dict.getSectionValue(section2, "integers floats and booleans are held as") == "strings" - assert dict.getSectionValue(section2, "can use the API to get converted values directly") == "true" - - let section3 = "Seletion A" - assert dict.getSectionValue(section3, - "space around section name will be ignored", "not an empty value") == "" - - let section4 = "Sections Can Be Indented" - assert dict.getSectionValue(section4, "can_values_be_as_well") == "True" - assert dict.getSectionValue(section4, "does_that_mean_anything_special") == "False" - assert dict.getSectionValue(section4, "purpose") == "formatting for readability" - -import strutils, lexbase, streams, tables -import std/private/decode_helpers -import std/private/since - -when defined(nimPreviewSlimSystem): - import std/syncio +import + strutils, lexbase, streams, tables include "system/inclrtl" - type CfgEventKind* = enum ## enumeration of all events that may occur when parsing cfgEof, ## end of file reached - cfgSectionStart, ## a `[section]` has been parsed - cfgKeyValuePair, ## a `key=value` pair has been detected - cfgOption, ## a `--key=value` command line option + cfgSectionStart, ## a ``[section]`` has been parsed + cfgKeyValuePair, ## a ``key=value`` pair has been detected + cfgOption, ## a ``--key=value`` command line option cfgError ## an error occurred during parsing CfgEvent* = object of RootObj ## describes a parsing event @@ -194,12 +126,12 @@ type of cfgEof: nil of cfgSectionStart: section*: string ## `section` contains the name of the - ## parsed section start (syntax: `[section]`) + ## parsed section start (syntax: ``[section]``) of cfgKeyValuePair, cfgOption: key*, value*: string ## contains the (key, value) pair if an option - ## of the form `--key: value` or an ordinary - ## `key= value` pair has been parsed. - ## `value==""` if it was not specified in the + ## of the form ``--key: value`` or an ordinary + ## ``key= value`` pair has been parsed. + ## ``value==""`` if it was not specified in the ## configuration file. of cfgError: ## the parser encountered an error: `msg` msg*: string ## contains the error message. No exceptions @@ -219,13 +151,13 @@ type # implementation const - SymChars = {'a'..'z', 'A'..'Z', '0'..'9', '_', ' ', '\x80'..'\xFF', '.', '/', '\\', '-'} + SymChars = {'a'..'z', 'A'..'Z', '0'..'9', '_', '\x80'..'\xFF', '.', '/', '\\', '-'} proc rawGetTok(c: var CfgParser, tok: var Token) {.gcsafe.} proc open*(c: var CfgParser, input: Stream, filename: string, lineOffset = 0) {.rtl, extern: "npc$1".} = - ## Initializes the parser with an input stream. `Filename` is only used + ## initializes the parser with an input stream. `Filename` is only used ## for nice error messages. `lineOffset` can be used to influence the line ## number information in the generated error messages. lexbase.open(c, input) @@ -236,21 +168,35 @@ proc open*(c: var CfgParser, input: Stream, filename: string, rawGetTok(c, c.tok) proc close*(c: var CfgParser) {.rtl, extern: "npc$1".} = - ## Closes the parser `c` and its associated input stream. + ## closes the parser `c` and its associated input stream. lexbase.close(c) proc getColumn*(c: CfgParser): int {.rtl, extern: "npc$1".} = - ## Gets the current column the parser has arrived at. + ## get the current column the parser has arrived at. result = getColNumber(c, c.bufpos) proc getLine*(c: CfgParser): int {.rtl, extern: "npc$1".} = - ## Gets the current line the parser has arrived at. + ## get the current line the parser has arrived at. result = c.lineNumber proc getFilename*(c: CfgParser): string {.rtl, extern: "npc$1".} = - ## Gets the filename of the file that the parser processes. + ## get the filename of the file that the parser processes. result = c.filename +proc handleHexChar(c: var CfgParser, xi: var int) = + case c.buf[c.bufpos] + of '0'..'9': + xi = (xi shl 4) or (ord(c.buf[c.bufpos]) - ord('0')) + inc(c.bufpos) + of 'a'..'f': + xi = (xi shl 4) or (ord(c.buf[c.bufpos]) - ord('a') + 10) + inc(c.bufpos) + of 'A'..'F': + xi = (xi shl 4) or (ord(c.buf[c.bufpos]) - ord('A') + 10) + inc(c.bufpos) + else: + discard + proc handleDecChars(c: var CfgParser, xi: var int) = while c.buf[c.bufpos] in {'0'..'9'}: xi = (xi * 10) + (ord(c.buf[c.bufpos]) - ord('0')) @@ -295,10 +241,8 @@ proc getEscapedChar(c: var CfgParser, tok: var Token) = of 'x', 'X': inc(c.bufpos) var xi = 0 - if handleHexChar(c.buf[c.bufpos], xi): - inc(c.bufpos) - if handleHexChar(c.buf[c.bufpos], xi): - inc(c.bufpos) + handleHexChar(c, xi) + handleHexChar(c, xi) add(tok.literal, chr(xi)) of '0'..'9': var xi = 0 @@ -362,10 +306,6 @@ proc getSymbol(c: var CfgParser, tok: var Token) = add(tok.literal, c.buf[pos]) inc(pos) if not (c.buf[pos] in SymChars): break - - while tok.literal.len > 0 and tok.literal[^1] == ' ': - tok.literal.setLen(tok.literal.len - 1) - c.bufpos = pos tok.kind = tkSymbol @@ -427,19 +367,19 @@ proc rawGetTok(c: var CfgParser, tok: var Token) = else: getSymbol(c, tok) proc errorStr*(c: CfgParser, msg: string): string {.rtl, extern: "npc$1".} = - ## Returns a properly formatted error message containing current line and + ## returns a properly formatted error message containing current line and ## column information. result = `%`("$1($2, $3) Error: $4", [c.filename, $getLine(c), $getColumn(c), msg]) proc warningStr*(c: CfgParser, msg: string): string {.rtl, extern: "npc$1".} = - ## Returns a properly formatted warning message containing current line and + ## returns a properly formatted warning message containing current line and ## column information. result = `%`("$1($2, $3) Warning: $4", [c.filename, $getLine(c), $getColumn(c), msg]) proc ignoreMsg*(c: CfgParser, e: CfgEvent): string {.rtl, extern: "npc$1".} = - ## Returns a properly formatted warning message containing that + ## returns a properly formatted warning message containing that ## an entry is ignored. case e.kind of cfgSectionStart: result = c.warningStr("section ignored: " & e.section) @@ -470,7 +410,7 @@ proc getKeyValPair(c: var CfgParser, kind: CfgEventKind): CfgEvent = rawGetTok(c, c.tok) proc next*(c: var CfgParser): CfgEvent {.rtl, extern: "npc$1".} = - ## Retrieves the first/next event. This controls the parser. + ## retrieves the first/next event. This controls the parser. case c.tok.kind of tkEof: result = CfgEvent(kind: cfgEof) @@ -499,17 +439,17 @@ proc next*(c: var CfgParser): CfgEvent {.rtl, extern: "npc$1".} = # ---------------- Configuration file related operations ---------------- type - Config* = OrderedTableRef[string, OrderedTableRef[string, string]] + Config* = OrderedTableRef[string, OrderedTableRef[string, string]] proc newConfig*(): Config = - ## Creates a new configuration table. + ## Create a new configuration table. ## Useful when wanting to create a configuration file. - result = newOrderedTable[string, OrderedTableRef[string, string]]() + result = newOrderedTable[string, OrderedTableRef[string, string]]() -proc loadConfig*(stream: Stream, filename: string = "[stream]"): Config = - ## Loads the specified configuration from stream into a new Config instance. +proc loadConfig*(stream: Stream, filename: string = "[stream]"): Config = + ## Load the specified configuration from stream into a new Config instance. ## `filename` parameter is only used for nicer error messages. - var dict = newOrderedTable[string, OrderedTableRef[string, string]]() + var dict = newOrderedTable[string, OrderedTableRef[string, string]]() var curSection = "" ## Current section, ## the default value of the current section is "", ## which means that the current section is a common @@ -539,8 +479,8 @@ proc loadConfig*(stream: Stream, filename: string = "[stream]"): Config = close(p) result = dict -proc loadConfig*(filename: string): Config = - ## Loads the specified configuration file into a new Config instance. +proc loadConfig*(filename: string): Config = + ## Load the specified configuration file into a new Config instance. let file = open(filename, fmRead) let fileStream = newFileStream(file) defer: fileStream.close() @@ -565,9 +505,9 @@ proc replace(s: string): string = result = d proc writeConfig*(dict: Config, stream: Stream) = - ## Writes the contents of the table to the specified stream. + ## Writes the contents of the table to the specified stream ## - ## .. note:: Comment statement will be ignored. + ## **Note:** Comment statement will be ignored. for section, sectionData in dict.pairs(): if section != "": ## Not general section if not allCharsInSet(section, SymChars): ## Non system character @@ -606,8 +546,7 @@ proc writeConfig*(dict: Config, stream: Stream) = proc `$`*(dict: Config): string = ## Writes the contents of the table to string. - ## - ## .. note:: Comment statement will be ignored. + ## Note: Comment statement will be ignored. let stream = newStringStream() defer: stream.close() dict.writeConfig(stream) @@ -615,23 +554,21 @@ proc `$`*(dict: Config): string = proc writeConfig*(dict: Config, filename: string) = ## Writes the contents of the table to the specified configuration file. - ## - ## .. note:: Comment statement will be ignored. + ## Note: Comment statement will be ignored. let file = open(filename, fmWrite) defer: file.close() let fileStream = newFileStream(file) dict.writeConfig(fileStream) -proc getSectionValue*(dict: Config, section, key: string, defaultVal = ""): string = - ## Gets the key value of the specified Section. - ## Returns the specified default value if the specified key does not exist. +proc getSectionValue*(dict: Config, section, key: string): string = + ## Gets the Key value of the specified Section, returns an empty string if the key does not exist. if dict.hasKey(section): if dict[section].hasKey(key): result = dict[section][key] else: - result = defaultVal + result = "" else: - result = defaultVal + result = "" proc setSectionKey*(dict: var Config, section, key, value: string) = ## Sets the Key value of the specified Section. @@ -646,15 +583,10 @@ proc delSection*(dict: var Config, section: string) = dict.del(section) proc delSectionKey*(dict: var Config, section, key: string) = - ## Deletes the key of the specified section. + ## Delete the key of the specified section. if dict.hasKey(section): if dict[section].hasKey(key): if dict[section].len == 1: dict.del(section) else: dict[section].del(key) - -iterator sections*(dict: Config): lent string {.since: (1, 5).} = - ## Iterates through the sections in the `dict`. - for section in dict.keys: - yield section diff --git a/lib/pure/parsecsv.nim b/lib/pure/parsecsv.nim index a8d1cfaab..44703e3f8 100644 --- a/lib/pure/parsecsv.nim +++ b/lib/pure/parsecsv.nim @@ -14,9 +14,9 @@ ## =========== ## ## .. code-block:: nim -## import std/parsecsv -## from std/os import paramStr -## from std/streams import newFileStream +## import parsecsv +## from os import paramStr +## from streams import newFileStream ## ## var s = newFileStream(paramStr(1), fmRead) ## if s == nil: @@ -34,7 +34,7 @@ ## reference for item access with `rowEntry <#rowEntry,CsvParser,string>`_: ## ## .. code-block:: nim -## import std/parsecsv +## import parsecsv ## ## # Prepare a file ## let content = """One,Two,Three,Four @@ -65,10 +65,8 @@ ## * `parsesql module `_ for a SQL parser ## * `other parsers `_ for other parsers -import lexbase, streams - -when defined(nimPreviewSlimSystem): - import std/syncio +import + lexbase, streams type CsvRow* = seq[string] ## A row in a CSV file. @@ -99,10 +97,10 @@ proc raiseEInvalidCsv(filename: string, line, col: int, e.msg = filename & "(" & $line & ", " & $col & ") Error: " & msg raise e -proc error(self: CsvParser, pos: int, msg: string) = - raiseEInvalidCsv(self.filename, self.lineNumber, getColNumber(self, pos), msg) +proc error(my: CsvParser, pos: int, msg: string) = + raiseEInvalidCsv(my.filename, my.lineNumber, getColNumber(my, pos), msg) -proc open*(self: var CsvParser, input: Stream, filename: string, +proc open*(my: var CsvParser, input: Stream, filename: string, separator = ',', quote = '"', escape = '\0', skipInitialSpace = false) = ## Initializes the parser with an input stream. `Filename` is only used @@ -110,10 +108,10 @@ proc open*(self: var CsvParser, input: Stream, filename: string, ## the diverse optional parameters: ## - `separator`: character used to separate fields ## - `quote`: Used to quote fields containing special characters like - ## `separator`, `quote` or new-line characters. '\\0' disables the parsing + ## `separator`, `quote` or new-line characters. '\0' disables the parsing ## of quotes. ## - `escape`: removes any special meaning from the following character; - ## '\\0' disables escaping; if escaping is disabled and `quote` is not '\\0', + ## '\0' disables escaping; if escaping is disabled and `quote` is not '\0', ## two `quote` characters are parsed one literal `quote` character. ## - `skipInitialSpace`: If true, whitespace immediately following the ## `separator` is ignored. @@ -122,27 +120,29 @@ proc open*(self: var CsvParser, input: Stream, filename: string, ## * `open proc <#open,CsvParser,string,char,char,char>`_ which creates the ## file stream for you runnableExamples: - import std/streams + import streams var strm = newStringStream("One,Two,Three\n1,2,3\n10,20,30") var parser: CsvParser parser.open(strm, "tmp.csv") parser.close() strm.close() - lexbase.open(self, input) - self.filename = filename - self.sep = separator - self.quote = quote - self.esc = escape - self.skipWhite = skipInitialSpace + lexbase.open(my, input) + my.filename = filename + my.sep = separator + my.quote = quote + my.esc = escape + my.skipWhite = skipInitialSpace + my.row = @[] + my.currRow = 0 -proc open*(self: var CsvParser, filename: string, +proc open*(my: var CsvParser, filename: string, separator = ',', quote = '"', escape = '\0', skipInitialSpace = false) = ## Similar to the `other open proc<#open,CsvParser,Stream,string,char,char,char>`_, ## but creates the file stream for you. runnableExamples: - from std/os import removeFile + from os import removeFile writeFile("tmp.csv", "One,Two,Three\n1,2,3\n10,20,300") var parser: CsvParser parser.open("tmp.csv") @@ -150,60 +150,60 @@ proc open*(self: var CsvParser, filename: string, removeFile("tmp.csv") var s = newFileStream(filename, fmRead) - if s == nil: self.error(0, "cannot open: " & filename) - open(self, s, filename, separator, + if s == nil: my.error(0, "cannot open: " & filename) + open(my, s, filename, separator, quote, escape, skipInitialSpace) -proc parseField(self: var CsvParser, a: var string) = - var pos = self.bufpos - if self.skipWhite: - while self.buf[pos] in {' ', '\t'}: inc(pos) +proc parseField(my: var CsvParser, a: var string) = + var pos = my.bufpos + if my.skipWhite: + while my.buf[pos] in {' ', '\t'}: inc(pos) setLen(a, 0) # reuse memory - if self.buf[pos] == self.quote and self.quote != '\0': + if my.buf[pos] == my.quote and my.quote != '\0': inc(pos) while true: - let c = self.buf[pos] + let c = my.buf[pos] if c == '\0': - self.bufpos = pos # can continue after exception? - error(self, pos, self.quote & " expected") + my.bufpos = pos # can continue after exception? + error(my, pos, my.quote & " expected") break - elif c == self.quote: - if self.esc == '\0' and self.buf[pos + 1] == self.quote: - add(a, self.quote) + elif c == my.quote: + if my.esc == '\0' and my.buf[pos+1] == my.quote: + add(a, my.quote) inc(pos, 2) else: inc(pos) break - elif c == self.esc: - add(a, self.buf[pos + 1]) + elif c == my.esc: + add(a, my.buf[pos+1]) inc(pos, 2) else: case c of '\c': - pos = handleCR(self, pos) + pos = handleCR(my, pos) add(a, "\n") of '\l': - pos = handleLF(self, pos) + pos = handleLF(my, pos) add(a, "\n") else: add(a, c) inc(pos) else: while true: - let c = self.buf[pos] - if c == self.sep: break + let c = my.buf[pos] + if c == my.sep: break if c in {'\c', '\l', '\0'}: break add(a, c) inc(pos) - self.bufpos = pos + my.bufpos = pos -proc processedRows*(self: var CsvParser): int {.inline.} = +proc processedRows*(my: var CsvParser): int = ## Returns number of the processed rows. ## ## But even if `readRow <#readRow,CsvParser,int>`_ arrived at EOF then ## processed rows counter is incremented. runnableExamples: - import std/streams + import streams var strm = newStringStream("One,Two,Three\n1,2,3") var parser: CsvParser @@ -220,16 +220,16 @@ proc processedRows*(self: var CsvParser): int {.inline.} = parser.close() strm.close() - self.currRow + return my.currRow -proc readRow*(self: var CsvParser, columns = 0): bool = +proc readRow*(my: var CsvParser, columns = 0): bool = ## Reads the next row; if `columns` > 0, it expects the row to have ## exactly this many columns. Returns false if the end of the file ## has been encountered else true. ## ## Blank lines are skipped. runnableExamples: - import std/streams + import streams var strm = newStringStream("One,Two,Three\n1,2,3\n\n10,20,30") var parser: CsvParser parser.open(strm, "tmp.csv") @@ -251,52 +251,52 @@ proc readRow*(self: var CsvParser, columns = 0): bool = strm.close() var col = 0 # current column - let oldpos = self.bufpos + let oldpos = my.bufpos # skip initial empty lines #8365 while true: - case self.buf[self.bufpos] - of '\c': self.bufpos = handleCR(self, self.bufpos) - of '\l': self.bufpos = handleLF(self, self.bufpos) + case my.buf[my.bufpos] + of '\c': my.bufpos = handleCR(my, my.bufpos) + of '\l': my.bufpos = handleLF(my, my.bufpos) else: break - while self.buf[self.bufpos] != '\0': - let oldlen = self.row.len - if oldlen < col + 1: - setLen(self.row, col + 1) - self.row[col] = "" - parseField(self, self.row[col]) + while my.buf[my.bufpos] != '\0': + let oldlen = my.row.len + if oldlen < col+1: + setLen(my.row, col+1) + my.row[col] = "" + parseField(my, my.row[col]) inc(col) - if self.buf[self.bufpos] == self.sep: - inc(self.bufpos) + if my.buf[my.bufpos] == my.sep: + inc(my.bufpos) else: - case self.buf[self.bufpos] + case my.buf[my.bufpos] of '\c', '\l': # skip empty lines: while true: - case self.buf[self.bufpos] - of '\c': self.bufpos = handleCR(self, self.bufpos) - of '\l': self.bufpos = handleLF(self, self.bufpos) + case my.buf[my.bufpos] + of '\c': my.bufpos = handleCR(my, my.bufpos) + of '\l': my.bufpos = handleLF(my, my.bufpos) else: break of '\0': discard - else: error(self, self.bufpos, self.sep & " expected") + else: error(my, my.bufpos, my.sep & " expected") break - setLen(self.row, col) + setLen(my.row, col) result = col > 0 if result and col != columns and columns > 0: - error(self, oldpos + 1, $columns & " columns expected, but found " & + error(my, oldpos+1, $columns & " columns expected, but found " & $col & " columns") - inc(self.currRow) + inc(my.currRow) -proc close*(self: var CsvParser) {.inline.} = - ## Closes the parser `self` and its associated input stream. - lexbase.close(self) +proc close*(my: var CsvParser) {.inline.} = + ## Closes the parser `my` and its associated input stream. + lexbase.close(my) -proc readHeaderRow*(self: var CsvParser) = +proc readHeaderRow*(my: var CsvParser) = ## Reads the first row and creates a look-up table for column numbers ## See also: ## * `rowEntry proc <#rowEntry,CsvParser,string>`_ runnableExamples: - import std/streams + import streams var strm = newStringStream("One,Two,Three\n1,2,3") var parser: CsvParser @@ -313,38 +313,33 @@ proc readHeaderRow*(self: var CsvParser) = parser.close() strm.close() - let present = self.readRow() + let present = my.readRow() if present: - self.headers = self.row + my.headers = my.row -proc rowEntry*(self: var CsvParser, entry: string): var string = +proc rowEntry*(my: var CsvParser, entry: string): var string = ## Accesses a specified `entry` from the current row. ## ## Assumes that `readHeaderRow <#readHeaderRow,CsvParser>`_ has already been ## called. - ## - ## If specified `entry` does not exist, raises KeyError. runnableExamples: - import std/streams + import streams var strm = newStringStream("One,Two,Three\n1,2,3\n\n10,20,30") var parser: CsvParser parser.open(strm, "tmp.csv") - ## Requires calling `readHeaderRow`. + ## Need calling `readHeaderRow`. parser.readHeaderRow() doAssert parser.readRow() doAssert parser.rowEntry("One") == "1" doAssert parser.rowEntry("Two") == "2" doAssert parser.rowEntry("Three") == "3" - doAssertRaises(KeyError): - discard parser.rowEntry("NonexistentEntry") + ## `parser.rowEntry("NotExistEntry")` causes SIGSEGV fault. parser.close() strm.close() - let index = self.headers.find(entry) + let index = my.headers.find(entry) if index >= 0: - result = self.row[index] - else: - raise newException(KeyError, "Entry `" & entry & "` doesn't exist") + result = my.row[index] when not defined(testing) and isMainModule: import os @@ -357,3 +352,35 @@ when not defined(testing) and isMainModule: for val in items(x.row): echo "##", val, "##" close(x) + +when isMainModule: + import os + import strutils + block: # Tests for reading the header row + let content = "\nOne,Two,Three,Four\n1,2,3,4\n10,20,30,40,\n100,200,300,400\n" + writeFile("temp.csv", content) + + var p: CsvParser + p.open("temp.csv") + p.readHeaderRow() + while p.readRow(): + let zeros = repeat('0', p.currRow-2) + doAssert p.rowEntry("One") == "1" & zeros + doAssert p.rowEntry("Two") == "2" & zeros + doAssert p.rowEntry("Three") == "3" & zeros + doAssert p.rowEntry("Four") == "4" & zeros + p.close() + + when not defined(testing): + var parser: CsvParser + parser.open("temp.csv") + parser.readHeaderRow() + while parser.readRow(): + echo "new row: " + for col in items(parser.headers): + echo "##", col, ":", parser.rowEntry(col), "##" + parser.close() + removeFile("temp.csv") + + # Tidy up + removeFile("temp.csv") diff --git a/lib/pure/parsejson.nim b/lib/pure/parsejson.nim index fcbcf8e36..0d7d7093e 100644 --- a/lib/pure/parsejson.nim +++ b/lib/pure/parsejson.nim @@ -8,14 +8,11 @@ # ## This module implements a json parser. It is used -## and exported by the `json` standard library +## and exported by the ``json`` standard library ## module, but can also be used in its own right. -import strutils, lexbase, streams, unicode -import std/private/decode_helpers - -when defined(nimPreviewSlimSystem): - import std/assertions +import + strutils, lexbase, streams, unicode type JsonEventKind* = enum ## enumeration of all events that may occur when parsing @@ -24,13 +21,13 @@ type jsonString, ## a string literal jsonInt, ## an integer literal jsonFloat, ## a float literal - jsonTrue, ## the value `true` - jsonFalse, ## the value `false` - jsonNull, ## the value `null` - jsonObjectStart, ## start of an object: the `{` token - jsonObjectEnd, ## end of an object: the `}` token - jsonArrayStart, ## start of an array: the `[` token - jsonArrayEnd ## end of an array: the `]` token + jsonTrue, ## the value ``true`` + jsonFalse, ## the value ``false`` + jsonNull, ## the value ``null`` + jsonObjectStart, ## start of an object: the ``{`` token + jsonObjectEnd, ## end of an object: the ``}`` token + jsonArrayStart, ## start of an array: the ``[`` token + jsonArrayEnd ## start of an array: the ``]`` token TokKind* = enum # must be synchronized with TJsonEventKind! tkError, @@ -52,12 +49,12 @@ type errNone, ## no error errInvalidToken, ## invalid token errStringExpected, ## string expected - errColonExpected, ## `:` expected - errCommaExpected, ## `,` expected - errBracketRiExpected, ## `]` expected - errCurlyRiExpected, ## `}` expected - errQuoteExpected, ## `"` or `'` expected - errEOC_Expected, ## `*/` expected + errColonExpected, ## ``:`` expected + errCommaExpected, ## ``,`` expected + errBracketRiExpected, ## ``]`` expected + errCurlyRiExpected, ## ``}`` expected + errQuoteExpected, ## ``"`` or ``'`` expected + errEOC_Expected, ## ``*/`` expected errEofExpected, ## EOF expected errExprExpected ## expr expected @@ -74,7 +71,7 @@ type filename: string rawStringLiterals: bool - JsonKindError* = object of ValueError ## raised by the `to` macro if the + JsonKindError* = object of ValueError ## raised by the ``to`` macro if the ## JSON kind is incorrect. JsonParsingError* = object of ValueError ## is raised for a JSON error @@ -122,18 +119,18 @@ proc close*(my: var JsonParser) {.inline.} = lexbase.close(my) proc str*(my: JsonParser): string {.inline.} = - ## returns the character data for the events: `jsonInt`, `jsonFloat`, - ## `jsonString` + ## returns the character data for the events: ``jsonInt``, ``jsonFloat``, + ## ``jsonString`` assert(my.kind in {jsonInt, jsonFloat, jsonString}) return my.a proc getInt*(my: JsonParser): BiggestInt {.inline.} = - ## returns the number for the event: `jsonInt` + ## returns the number for the event: ``jsonInt`` assert(my.kind == jsonInt) return parseBiggestInt(my.a) proc getFloat*(my: JsonParser): float {.inline.} = - ## returns the number for the event: `jsonFloat` + ## returns the number for the event: ``jsonFloat`` assert(my.kind == jsonFloat) return parseFloat(my.a) @@ -154,7 +151,7 @@ proc getFilename*(my: JsonParser): string {.inline.} = result = my.filename proc errorMsg*(my: JsonParser): string = - ## returns a helpful error message for the event `jsonError` + ## returns a helpful error message for the event ``jsonError`` assert(my.kind == jsonError) result = "$1($2, $3) Error: $4" % [ my.filename, $getLine(my), $getColumn(my), errorMessages[my.err]] @@ -165,11 +162,18 @@ proc errorMsgExpected*(my: JsonParser, e: string): string = result = "$1($2, $3) Error: $4" % [ my.filename, $getLine(my), $getColumn(my), e & " expected"] +proc handleHexChar(c: char, x: var int): bool = + result = true # Success + case c + of '0'..'9': x = (x shl 4) or (ord(c) - ord('0')) + of 'a'..'f': x = (x shl 4) or (ord(c) - ord('a') + 10) + of 'A'..'F': x = (x shl 4) or (ord(c) - ord('A') + 10) + else: result = false # error + proc parseEscapedUTF16*(buf: cstring, pos: var int): int = result = 0 #UTF-16 escape is always 4 bytes. for _ in 0..3: - # if char in '0' .. '9', 'a' .. 'f', 'A' .. 'F' if handleHexChar(buf[pos], result): inc(pos) else: @@ -221,7 +225,7 @@ proc parseString(my: var JsonParser): TokKind = add(my.a, 'u') inc(pos, 2) var pos2 = pos - var r = parseEscapedUTF16(cstring(my.buf), pos) + var r = parseEscapedUTF16(my.buf, pos) if r < 0: my.err = errInvalidToken break @@ -231,7 +235,7 @@ proc parseString(my: var JsonParser): TokKind = my.err = errInvalidToken break inc(pos, 2) - var s = parseEscapedUTF16(cstring(my.buf), pos) + var s = parseEscapedUTF16(my.buf, pos) if (s and 0xfc00) == 0xdc00 and s > 0: r = 0x10000 + (((r - 0xd800) shl 10) or (s - 0xdc00)) else: diff --git a/lib/pure/parseopt.nim b/lib/pure/parseopt.nim index 059f8e0f5..a95a5b48d 100644 --- a/lib/pure/parseopt.nim +++ b/lib/pure/parseopt.nim @@ -14,21 +14,21 @@ ## Supported Syntax ## ================ ## -## The following syntax is supported when arguments for the `shortNoVal` and -## `longNoVal` parameters, which are -## `described later<#nimshortnoval-and-nimlongnoval>`_, are not provided: +## The following syntax is supported when arguments for the ``shortNoVal`` and +## ``longNoVal`` parameters, which are +## `described later<#shortnoval-and-longnoval>`_, are not provided: ## -## 1. Short options: `-abcd`, `-e:5`, `-e=5` -## 2. Long options: `--foo:bar`, `--foo=bar`, `--foo` -## 3. Arguments: everything that does not start with a `-` +## 1. Short options: ``-abcd``, ``-e:5``, ``-e=5`` +## 2. Long options: ``--foo:bar``, ``--foo=bar``, ``--foo`` +## 3. Arguments: everything that does not start with a ``-`` ## ## These three kinds of tokens are enumerated in the ## `CmdLineKind enum<#CmdLineKind>`_. ## ## When option values begin with ':' or '=', they need to be doubled up (as in -## `--delim::`) or alternated (as in `--delim=:`). +## ``--delim::``) or alternated (as in ``--delim=:``). ## -## The `--` option, commonly used to denote that every token that follows is +## The ``--`` option, commonly used to denote that every token that follows is ## an argument, is interpreted as a long option, and its name is the empty ## string. ## @@ -39,17 +39,17 @@ ## created with `initOptParser<#initOptParser,string,set[char],seq[string]>`_, ## and `next<#next,OptParser>`_ advances the parser by one token. ## -## For each token, the parser's `kind`, `key`, and `val` fields give -## information about that token. If the token is a long or short option, `key` -## is the option's name, and `val` is either the option's value, if provided, -## or the empty string. For arguments, the `key` field contains the argument -## itself, and `val` is unused. To check if the end of the command line has -## been reached, check if `kind` is equal to `cmdEnd`. +## For each token, the parser's ``kind``, ``key``, and ``val`` fields give +## information about that token. If the token is a long or short option, ``key`` +## is the option's name, and ``val`` is either the option's value, if provided, +## or the empty string. For arguments, the ``key`` field contains the argument +## itself, and ``val`` is unused. To check if the end of the command line has +## been reached, check if ``kind`` is equal to ``cmdEnd``. ## ## Here is an example: ## ## .. code-block:: -## import std/parseopt +## import parseopt ## ## var p = initOptParser("-ab -e:5 --foo --bar=20 file.txt") ## while true: @@ -75,52 +75,31 @@ ## The `getopt iterator<#getopt.i,OptParser>`_, which is provided for ## convenience, can be used to iterate through all command line options as well. ## -## To set a default value for a variable assigned through `getopt` and accept arguments from the cmd line. -## Assign the default value to a variable before parsing. -## Then set the variable to the new value while parsing. +## ``shortNoVal`` and ``longNoVal`` +## ================================ ## -## Here is an example: -## .. code-block:: -## import std/parseopt -## -## var varName: string = "defaultValue" -## -## for kind, key, val in getopt(): -## case kind -## of cmdArgument: -## discard -## of cmdLongOption, cmdShortOption: -## case key: -## of "varName": # --varName: in the console when executing -## varName = val # do input sanitization in production systems -## of cmdEnd: -## discard -## -## `shortNoVal` and `longNoVal` -## ============================ -## -## The optional `shortNoVal` and `longNoVal` parameters present in +## The optional ``shortNoVal`` and ``longNoVal`` parameters present in ## `initOptParser<#initOptParser,string,set[char],seq[string]>`_ are for ## specifying which short and long options do not accept values. ## -## When `shortNoVal` is non-empty, users are not required to separate short +## When ``shortNoVal`` is non-empty, users are not required to separate short ## options and their values with a ':' or '=' since the parser knows which ## options accept values and which ones do not. This behavior also applies for -## long options if `longNoVal` is non-empty. For short options, `-j4` -## becomes supported syntax, and for long options, `--foo bar` becomes +## long options if ``longNoVal`` is non-empty. For short options, ``-j4`` +## becomes supported syntax, and for long options, ``--foo bar`` becomes ## supported. This is in addition to the `previously mentioned ## syntax<#supported-syntax>`_. Users can still separate options and their ## values with ':' or '=', but that becomes optional. ## ## As more options which do not accept values are added to your program, -## remember to amend `shortNoVal` and `longNoVal` accordingly. +## remember to amend ``shortNoVal`` and ``longNoVal`` accordingly. ## ## The following example illustrates the difference between having an empty -## `shortNoVal` and `longNoVal`, which is the default, and providing +## ``shortNoVal`` and ``longNoVal``, which is the default, and providing ## arguments for those two parameters: ## ## .. code-block:: -## import std/parseopt +## import parseopt ## ## proc printToken(kind: CmdLineKind, key: string, val: string) = ## case kind @@ -185,7 +164,7 @@ type ## ## To initialize it, use the ## `initOptParser proc<#initOptParser,string,set[char],seq[string]>`_. - pos: int + pos*: int inShortState: bool allowWhitespaceAfterColon: bool shortNoVal: set[char] @@ -193,7 +172,7 @@ type cmds: seq[string] idx: int kind*: CmdLineKind ## The detected command line token - key*, val*: string ## Key and value pair; the key is the option + key*, val*: TaintedString ## Key and value pair; the key is the option ## or the argument, and the value is not "" if ## the option was given a value @@ -213,93 +192,101 @@ proc parseWord(s: string, i: int, w: var string, add(w, s[result]) inc(result) -proc initOptParser*(cmdline: seq[string], shortNoVal: set[char] = {}, - longNoVal: seq[string] = @[]; - allowWhitespaceAfterColon = true): OptParser = - ## Initializes the command line parser. - ## - ## If `cmdline.len == 0`, the real command line as provided by the - ## `os` module is retrieved instead if it is available. If the - ## command line is not available, a `ValueError` will be raised. - ## Behavior of the other parameters remains the same as in - ## `initOptParser(string, ...) - ## <#initOptParser,string,set[char],seq[string]>`_. - ## - ## See also: - ## * `getopt iterator<#getopt.i,seq[string],set[char],seq[string]>`_ - runnableExamples: - var p = initOptParser() - p = initOptParser(@["--left", "--debug:3", "-l", "-r:2"]) - p = initOptParser(@["--left", "--debug:3", "-l", "-r:2"], - shortNoVal = {'l'}, longNoVal = @["left"]) +when declared(os.paramCount): + # we cannot provide this for NimRtl creation on Posix, because we can't + # access the command line arguments then! - result.pos = 0 - result.idx = 0 - result.inShortState = false - result.shortNoVal = shortNoVal - result.longNoVal = longNoVal - result.allowWhitespaceAfterColon = allowWhitespaceAfterColon - if cmdline.len != 0: - result.cmds = newSeq[string](cmdline.len) - for i in 0..`_ for more information on + ## how this affects parsing. + ## + ## See also: + ## * `getopt iterator<#getopt.i,OptParser>`_ + runnableExamples: + var p = initOptParser() + p = initOptParser("--left --debug:3 -l -r:2") + p = initOptParser("--left --debug:3 -l -r:2", + shortNoVal = {'l'}, longNoVal = @["left"]) + + result.pos = 0 + result.idx = 0 + result.inShortState = false + result.shortNoVal = shortNoVal + result.longNoVal = longNoVal + result.allowWhitespaceAfterColon = allowWhitespaceAfterColon + if cmdline != "": + result.cmds = parseCmdLine(cmdline) else: - # we cannot provide this for NimRtl creation on Posix, because we can't - # access the command line arguments then! - doAssert false, "empty command line given but" & - " real command line is not accessible" - result.kind = cmdEnd - result.key = "" - result.val = "" + result.cmds = newSeq[string](os.paramCount()) + for i in countup(1, os.paramCount()): + result.cmds[i-1] = os.paramStr(i).string -proc initOptParser*(cmdline = "", shortNoVal: set[char] = {}, - longNoVal: seq[string] = @[]; - allowWhitespaceAfterColon = true): OptParser = - ## Initializes the command line parser. - ## - ## If `cmdline == ""`, the real command line as provided by the - ## `os` module is retrieved instead if it is available. If the - ## command line is not available, a `ValueError` will be raised. - ## - ## `shortNoVal` and `longNoVal` are used to specify which options - ## do not take values. See the `documentation about these - ## parameters<#nimshortnoval-and-nimlongnoval>`_ for more information on - ## how this affects parsing. - ## - ## This does not provide a way of passing default values to arguments. - ## - ## See also: - ## * `getopt iterator<#getopt.i,OptParser>`_ - runnableExamples: - var p = initOptParser() - p = initOptParser("--left --debug:3 -l -r:2") - p = initOptParser("--left --debug:3 -l -r:2", - shortNoVal = {'l'}, longNoVal = @["left"]) + result.kind = cmdEnd + result.key = TaintedString"" + result.val = TaintedString"" - initOptParser(parseCmdLine(cmdline), shortNoVal, longNoVal, allowWhitespaceAfterColon) + proc initOptParser*(cmdline: seq[TaintedString], shortNoVal: set[char] = {}, + longNoVal: seq[string] = @[]; + allowWhitespaceAfterColon = true): OptParser = + ## Initializes the command line parser. + ## + ## If ``cmdline.len == 0``, the real command line as provided by the + ## ``os`` module is retrieved instead. Behavior of the other parameters + ## remains the same as in `initOptParser(string, ...) + ## <#initOptParser,string,set[char],seq[string]>`_. + ## + ## See also: + ## * `getopt iterator<#getopt.i,seq[TaintedString],set[char],seq[string]>`_ + runnableExamples: + var p = initOptParser() + p = initOptParser(@["--left", "--debug:3", "-l", "-r:2"]) + p = initOptParser(@["--left", "--debug:3", "-l", "-r:2"], + shortNoVal = {'l'}, longNoVal = @["left"]) + + result.pos = 0 + result.idx = 0 + result.inShortState = false + result.shortNoVal = shortNoVal + result.longNoVal = longNoVal + result.allowWhitespaceAfterColon = allowWhitespaceAfterColon + if cmdline.len != 0: + result.cmds = newSeq[string](cmdline.len) + for i in 0..= p.cmds[p.idx].len: @@ -351,7 +338,7 @@ proc next*(p: var OptParser) {.rtl, extern: "npo$1".} = if i < p.cmds[p.idx].len and p.cmds[p.idx][i] == '-': p.kind = cmdLongOption inc(i) - i = parseWord(p.cmds[p.idx], i, p.key, {' ', '\t', ':', '='}) + i = parseWord(p.cmds[p.idx], i, p.key.string, {' ', '\t', ':', '='}) while i < p.cmds[p.idx].len and p.cmds[p.idx][i] in {'\t', ' '}: inc(i) if i < p.cmds[p.idx].len and p.cmds[p.idx][i] in {':', '='}: inc(i) @@ -362,12 +349,12 @@ proc next*(p: var OptParser) {.rtl, extern: "npo$1".} = inc p.idx i = 0 if p.idx < p.cmds.len: - p.val = p.cmds[p.idx].substr(i) - elif len(p.longNoVal) > 0 and p.key notin p.longNoVal and p.idx+1 < p.cmds.len: - p.val = p.cmds[p.idx+1] + p.val = TaintedString p.cmds[p.idx].substr(i) + elif len(p.longNoVal) > 0 and p.key.string notin p.longNoVal and p.idx+1 < p.cmds.len: + p.val = TaintedString p.cmds[p.idx+1] inc p.idx else: - p.val = "" + p.val = TaintedString"" inc p.idx p.pos = 0 else: @@ -375,29 +362,29 @@ proc next*(p: var OptParser) {.rtl, extern: "npo$1".} = handleShortOption(p, p.cmds[p.idx]) else: p.kind = cmdArgument - p.key = p.cmds[p.idx] + p.key = TaintedString p.cmds[p.idx] inc p.idx p.pos = 0 -when declared(quoteShellCommand): - proc cmdLineRest*(p: OptParser): string {.rtl, extern: "npo$1".} = - ## Retrieves the rest of the command line that has not been parsed yet. - ## - ## See also: - ## * `remainingArgs proc<#remainingArgs,OptParser>`_ - ## - ## **Examples:** - ## - ## .. code-block:: - ## var p = initOptParser("--left -r:2 -- foo.txt bar.txt") - ## while true: - ## p.next() - ## if p.kind == cmdLongOption and p.key == "": # Look for "--" - ## break - ## doAssert p.cmdLineRest == "foo.txt bar.txt" - result = p.cmds[p.idx .. ^1].quoteShellCommand +proc cmdLineRest*(p: OptParser): TaintedString {.rtl, extern: "npo$1".} = + ## Retrieves the rest of the command line that has not been parsed yet. + ## + ## See also: + ## * `remainingArgs proc<#remainingArgs,OptParser>`_ + ## + ## **Examples:** + ## + ## .. code-block:: + ## var p = initOptParser("--left -r:2 -- foo.txt bar.txt") + ## while true: + ## p.next() + ## if p.kind == cmdLongOption and p.key == "": # Look for "--" + ## break + ## else: continue + ## doAssert p.cmdLineRest == "foo.txt bar.txt" + result = p.cmds[p.idx .. ^1].quoteShellCommand.TaintedString -proc remainingArgs*(p: OptParser): seq[string] {.rtl, extern: "npo$1".} = +proc remainingArgs*(p: OptParser): seq[TaintedString] {.rtl, extern: "npo$1".} = ## Retrieves a sequence of the arguments that have not been parsed yet. ## ## See also: @@ -411,17 +398,17 @@ proc remainingArgs*(p: OptParser): seq[string] {.rtl, extern: "npo$1".} = ## p.next() ## if p.kind == cmdLongOption and p.key == "": # Look for "--" ## break + ## else: continue ## doAssert p.remainingArgs == @["foo.txt", "bar.txt"] result = @[] - for i in p.idx..`_. ## - ## There is no need to check for `cmdEnd` while iterating. If using `getopt` - ## with case switching, checking for `cmdEnd` is required. + ## There is no need to check for ``cmdEnd`` while iterating. ## ## See also: ## * `initOptParser proc<#initOptParser,string,set[char],seq[string]>`_ @@ -455,54 +442,54 @@ iterator getopt*(p: var OptParser): tuple[kind: CmdLineKind, key, if p.kind == cmdEnd: break yield (p.kind, p.key, p.val) -iterator getopt*(cmdline: seq[string] = @[], - shortNoVal: set[char] = {}, longNoVal: seq[string] = @[]): - tuple[kind: CmdLineKind, key, val: string] = - ## Convenience iterator for iterating over command line arguments. - ## - ## This creates a new `OptParser<#OptParser>`_. If no command line - ## arguments are provided, the real command line as provided by the - ## `os` module is retrieved instead. - ## - ## `shortNoVal` and `longNoVal` are used to specify which options - ## do not take values. See the `documentation about these - ## parameters<#nimshortnoval-and-nimlongnoval>`_ for more information on - ## how this affects parsing. - ## - ## There is no need to check for `cmdEnd` while iterating. If using `getopt` - ## with case switching, checking for `cmdEnd` is required. - ## - ## See also: - ## * `initOptParser proc<#initOptParser,seq[string],set[char],seq[string]>`_ - ## - ## **Examples:** - ## - ## .. code-block:: - ## - ## # these are placeholders, of course - ## proc writeHelp() = discard - ## proc writeVersion() = discard - ## - ## var filename: string - ## let params = @["--left", "--debug:3", "-l", "-r:2"] - ## - ## for kind, key, val in getopt(params): - ## case kind - ## of cmdArgument: - ## filename = key - ## of cmdLongOption, cmdShortOption: - ## case key - ## of "help", "h": writeHelp() - ## of "version", "v": writeVersion() - ## of cmdEnd: assert(false) # cannot happen - ## if filename == "": - ## # no filename has been written, so we show the help - ## writeHelp() - var p = initOptParser(cmdline, shortNoVal = shortNoVal, - longNoVal = longNoVal) - while true: - next(p) - if p.kind == cmdEnd: break - yield (p.kind, p.key, p.val) +when declared(initOptParser): + iterator getopt*(cmdline: seq[TaintedString] = commandLineParams(), + shortNoVal: set[char] = {}, longNoVal: seq[string] = @[]): + tuple[kind: CmdLineKind, key, val: TaintedString] = + ## Convenience iterator for iterating over command line arguments. + ## + ## This creates a new `OptParser<#OptParser>`_. If no command line + ## arguments are provided, the real command line as provided by the + ## ``os`` module is retrieved instead. + ## + ## ``shortNoVal`` and ``longNoVal`` are used to specify which options + ## do not take values. See the `documentation about these + ## parameters<#shortnoval-and-longnoval>`_ for more information on + ## how this affects parsing. + ## + ## There is no need to check for ``cmdEnd`` while iterating. + ## + ## See also: + ## * `initOptParser proc<#initOptParser,seq[TaintedString],set[char],seq[string]>`_ + ## + ## **Examples:** + ## + ## .. code-block:: + ## + ## # these are placeholders, of course + ## proc writeHelp() = discard + ## proc writeVersion() = discard + ## + ## var filename: string + ## let params = @["--left", "--debug:3", "-l", "-r:2"] + ## + ## for kind, key, val in getopt(params): + ## case kind + ## of cmdArgument: + ## filename = key + ## of cmdLongOption, cmdShortOption: + ## case key + ## of "help", "h": writeHelp() + ## of "version", "v": writeVersion() + ## of cmdEnd: assert(false) # cannot happen + ## if filename == "": + ## # no filename has been written, so we show the help + ## writeHelp() + var p = initOptParser(cmdline, shortNoVal = shortNoVal, + longNoVal = longNoVal) + while true: + next(p) + if p.kind == cmdEnd: break + yield (p.kind, p.key, p.val) {.pop.} diff --git a/lib/pure/parsesql.nim b/lib/pure/parsesql.nim index 074faf64c..b84c1a744 100644 --- a/lib/pure/parsesql.nim +++ b/lib/pure/parsesql.nim @@ -7,16 +7,13 @@ # distribution, for details about the copyright. # -## The `parsesql` module implements a high performance SQL file +## The ``parsesql`` module implements a high performance SQL file ## parser. It parses PostgreSQL syntax and the SQL ANSI standard. ## ## Unstable API. -import strutils, lexbase -import std/private/decode_helpers - -when defined(nimPreviewSlimSystem): - import std/assertions +import + strutils, lexbase # ------------------- scanner ------------------------------------------------- @@ -60,7 +57,7 @@ const reservedKeywords = @[ # statements - "select", "from", "where", "group", "limit", "offset", "having", + "select", "from", "where", "group", "limit", "having", # functions "count", ] @@ -75,6 +72,20 @@ proc getColumn(L: SqlLexer): int = proc getLine(L: SqlLexer): int = result = L.lineNumber +proc handleHexChar(c: var SqlLexer, xi: var int) = + case c.buf[c.bufpos] + of '0'..'9': + xi = (xi shl 4) or (ord(c.buf[c.bufpos]) - ord('0')) + inc(c.bufpos) + of 'a'..'f': + xi = (xi shl 4) or (ord(c.buf[c.bufpos]) - ord('a') + 10) + inc(c.bufpos) + of 'A'..'F': + xi = (xi shl 4) or (ord(c.buf[c.bufpos]) - ord('A') + 10) + inc(c.bufpos) + else: + discard + proc handleOctChar(c: var SqlLexer, xi: var int) = if c.buf[c.bufpos] in {'0'..'7'}: xi = (xi shl 3) or (ord(c.buf[c.bufpos]) - ord('0')) @@ -119,10 +130,8 @@ proc getEscapedChar(c: var SqlLexer, tok: var Token) = of 'x', 'X': inc(c.bufpos) var xi = 0 - if handleHexChar(c.buf[c.bufpos], xi): - inc(c.bufpos) - if handleHexChar(c.buf[c.bufpos], xi): - inc(c.bufpos) + handleHexChar(c, xi) + handleHexChar(c, xi) add(tok.literal, chr(xi)) of '0'..'7': var xi = 0 @@ -509,7 +518,6 @@ type nkFromItemPair, nkGroup, nkLimit, - nkOffset, nkHaving, nkOrder, nkJoin, @@ -549,14 +557,7 @@ type tok: Token proc newNode*(k: SqlNodeKind): SqlNode = - when defined(js): # bug #14117 - case k - of LiteralNodes: - result = SqlNode(kind: k, strVal: "") - else: - result = SqlNode(kind: k, sons: @[]) - else: - result = SqlNode(kind: k) + result = SqlNode(kind: k) proc newNode*(k: SqlNodeKind, s: string): SqlNode = result = SqlNode(kind: k) @@ -671,8 +672,8 @@ proc getPrecedence(p: SqlParser): int = else: result = - 1 -proc parseExpr(p: var SqlParser): SqlNode {.gcsafe.} -proc parseSelect(p: var SqlParser): SqlNode {.gcsafe.} +proc parseExpr(p: var SqlParser): SqlNode +proc parseSelect(p: var SqlParser): SqlNode proc identOrLiteral(p: var SqlParser): SqlNode = case p.tok.kind @@ -986,7 +987,7 @@ proc parseInsert(p: var SqlParser): SqlNode = parseParIdentList(p, n) result.add n else: - result.add(newNode(nkNone)) + result.add(nil) if isKeyw(p, "default"): getTok(p) eat(p, "values") @@ -1021,7 +1022,7 @@ proc parseUpdate(p: var SqlParser): SqlNode = if isKeyw(p, "where"): result.add(parseWhere(p)) else: - result.add(newNode(nkNone)) + result.add(nil) proc parseDelete(p: var SqlParser): SqlNode = getTok(p) @@ -1033,7 +1034,7 @@ proc parseDelete(p: var SqlParser): SqlNode = if isKeyw(p, "where"): result.add(parseWhere(p)) else: - result.add(newNode(nkNone)) + result.add(nil) proc parseSelect(p: var SqlParser): SqlNode = getTok(p) @@ -1127,11 +1128,6 @@ proc parseSelect(p: var SqlParser): SqlNode = var l = newNode(nkLimit) l.add(parseExpr(p)) result.add(l) - if isKeyw(p, "offset"): - getTok(p) - var o = newNode(nkOffset) - o.add(parseExpr(p)) - result.add(o) proc parseStmt(p: var SqlParser; parent: SqlNode) = if isKeyw(p, "create"): @@ -1188,12 +1184,9 @@ type proc add(s: var SqlWriter, thing: char) = s.buffer.add(thing) -proc prepareAdd(s: var SqlWriter) {.inline.} = +proc add(s: var SqlWriter, thing: string) = if s.buffer.len > 0 and s.buffer[^1] notin {' ', '\L', '(', '.'}: s.buffer.add(" ") - -proc add(s: var SqlWriter, thing: string) = - s.prepareAdd s.buffer.add(thing) proc addKeyw(s: var SqlWriter, thing: string) = @@ -1208,7 +1201,7 @@ proc addIden(s: var SqlWriter, thing: string) = iden = '"' & iden & '"' s.add(iden) -proc ra(n: SqlNode, s: var SqlWriter) {.gcsafe.} +proc ra(n: SqlNode, s: var SqlWriter) proc rs(n: SqlNode, s: var SqlWriter, prefix = "(", suffix = ")", sep = ", ") = if n.len > 0: @@ -1235,17 +1228,6 @@ proc addMulti(s: var SqlWriter, n: SqlNode, sep = ',', prefix, suffix: char) = proc quoted(s: string): string = "\"" & replace(s, "\"", "\"\"") & "\"" -func escape(result: var string; s: string) = - result.add('\'') - for c in items(s): - case c - of '\0'..'\31': - result.add("\\x") - result.add(toHex(ord(c), 2)) - of '\'': result.add("''") - else: result.add(c) - result.add('\'') - proc ra(n: SqlNode, s: var SqlWriter) = if n == nil: return case n.kind @@ -1258,8 +1240,7 @@ proc ra(n: SqlNode, s: var SqlWriter) = of nkQuotedIdent: s.add(quoted(n.strVal)) of nkStringLit: - s.prepareAdd - s.buffer.escape(n.strVal) + s.add(escape(n.strVal, "'", "'")) of nkBitStringLit: s.add("b'" & n.strVal & "'") of nkHexStringLit: @@ -1394,9 +1375,6 @@ proc ra(n: SqlNode, s: var SqlWriter) = of nkLimit: s.addKeyw("limit") s.addMulti(n) - of nkOffset: - s.addKeyw("offset") - s.addMulti(n) of nkHaving: s.addKeyw("having") s.addMulti(n) @@ -1463,7 +1441,7 @@ proc ra(n: SqlNode, s: var SqlWriter) = s.addKeyw("enum") rs(n, s) -proc renderSql*(n: SqlNode, upperCase = false): string = +proc renderSQL*(n: SqlNode, upperCase = false): string = ## Converts an SQL abstract syntax tree to its string representation. var s: SqlWriter s.buffer = "" @@ -1472,8 +1450,8 @@ proc renderSql*(n: SqlNode, upperCase = false): string = return s.buffer proc `$`*(n: SqlNode): string = - ## an alias for `renderSql`. - renderSql(n) + ## an alias for `renderSQL`. + renderSQL(n) proc treeReprAux(s: SqlNode, level: int, result: var string) = result.add('\n') @@ -1491,33 +1469,34 @@ proc treeRepr*(s: SqlNode): string = result = newStringOfCap(128) treeReprAux(s, 0, result) -import streams +when not defined(js): + import streams -proc open(L: var SqlLexer, input: Stream, filename: string) = - lexbase.open(L, input) - L.filename = filename + proc open(L: var SqlLexer, input: Stream, filename: string) = + lexbase.open(L, input) + L.filename = filename -proc open(p: var SqlParser, input: Stream, filename: string) = - ## opens the parser `p` and assigns the input stream `input` to it. - ## `filename` is only used for error messages. - open(SqlLexer(p), input, filename) - p.tok.kind = tkInvalid - p.tok.literal = "" - getTok(p) + proc open(p: var SqlParser, input: Stream, filename: string) = + ## opens the parser `p` and assigns the input stream `input` to it. + ## `filename` is only used for error messages. + open(SqlLexer(p), input, filename) + p.tok.kind = tkInvalid + p.tok.literal = "" + getTok(p) -proc parseSql*(input: Stream, filename: string): SqlNode = - ## parses the SQL from `input` into an AST and returns the AST. - ## `filename` is only used for error messages. - ## Syntax errors raise an `SqlParseError` exception. - var p: SqlParser - open(p, input, filename) - try: - result = parse(p) - finally: - close(p) + proc parseSQL*(input: Stream, filename: string): SqlNode = + ## parses the SQL from `input` into an AST and returns the AST. + ## `filename` is only used for error messages. + ## Syntax errors raise an `SqlParseError` exception. + var p: SqlParser + open(p, input, filename) + try: + result = parse(p) + finally: + close(p) -proc parseSql*(input: string, filename = ""): SqlNode = - ## parses the SQL from `input` into an AST and returns the AST. - ## `filename` is only used for error messages. - ## Syntax errors raise an `SqlParseError` exception. - parseSql(newStringStream(input), "") + proc parseSQL*(input: string, filename = ""): SqlNode = + ## parses the SQL from `input` into an AST and returns the AST. + ## `filename` is only used for error messages. + ## Syntax errors raise an `SqlParseError` exception. + parseSQL(newStringStream(input), "") diff --git a/lib/pure/parseutils.nim b/lib/pure/parseutils.nim index c4d59d892..2c21c4952 100644 --- a/lib/pure/parseutils.nim +++ b/lib/pure/parseutils.nim @@ -26,7 +26,7 @@ ## ## .. code-block:: nim ## :test: -## from std/strutils import Digits, parseInt +## from strutils import Digits, parseInt ## ## let ## input1 = "2019 school start" @@ -45,13 +45,14 @@ ## * `parsexml module`_ for a XML / HTML parser ## * `other parsers`_ for other parsers + +{.deadCodeElim: on.} # dce option deprecated + {.push debugger: off.} # the user does not want to trace a part # of the standard library! include "system/inclrtl" -template toOa(s: string): openArray[char] = openArray[char](s) - const Whitespace = {' ', '\t', '\v', '\r', '\l', '\f'} IdentChars = {'a'..'z', 'A'..'Z', '0'..'9', '_'} @@ -61,7 +62,8 @@ const proc toLower(c: char): char {.inline.} = result = if c in {'A'..'Z'}: chr(ord(c)-ord('A')+ord('a')) else: c -proc parseBin*[T: SomeInteger](s: openArray[char], number: var T, maxLen = 0): int {.noSideEffect.} = +proc parseBin*[T: SomeInteger](s: string, number: var T, start = 0, + maxLen = 0): int {.noSideEffect.} = ## Parses a binary number and stores its value in ``number``. ## ## Returns the number of the parsed characters or 0 in case of an error. @@ -90,7 +92,7 @@ proc parseBin*[T: SomeInteger](s: openArray[char], number: var T, maxLen = 0): i var num64: int64 doAssert parseBin("0100111001101001111011010100111001101001", num64) == 40 doAssert num64 == 336784608873 - var i = 0 + var i = start var output = T(0) var foundDigit = false let last = min(s.len, if maxLen == 0: s.len else: i + maxLen) @@ -105,9 +107,10 @@ proc parseBin*[T: SomeInteger](s: openArray[char], number: var T, maxLen = 0): i inc(i) if foundDigit: number = output - result = i + result = i - start -proc parseOct*[T: SomeInteger](s: openArray[char], number: var T, maxLen = 0): int {.noSideEffect.} = +proc parseOct*[T: SomeInteger](s: string, number: var T, start = 0, + maxLen = 0): int {.noSideEffect.} = ## Parses an octal number and stores its value in ``number``. ## ## Returns the number of the parsed characters or 0 in case of an error. @@ -136,7 +139,7 @@ proc parseOct*[T: SomeInteger](s: openArray[char], number: var T, maxLen = 0): i var num64: int64 doAssert parseOct("2346475523464755", num64) == 16 doAssert num64 == 86216859871725 - var i = 0 + var i = start var output = T(0) var foundDigit = false let last = min(s.len, if maxLen == 0: s.len else: i + maxLen) @@ -151,9 +154,10 @@ proc parseOct*[T: SomeInteger](s: openArray[char], number: var T, maxLen = 0): i inc(i) if foundDigit: number = output - result = i + result = i - start -proc parseHex*[T: SomeInteger](s: openArray[char], number: var T, maxLen = 0): int {.noSideEffect.} = +proc parseHex*[T: SomeInteger](s: string, number: var T, start = 0, + maxLen = 0): int {.noSideEffect.} = ## Parses a hexadecimal number and stores its value in ``number``. ## ## Returns the number of the parsed characters or 0 in case of an error. @@ -183,7 +187,7 @@ proc parseHex*[T: SomeInteger](s: openArray[char], number: var T, maxLen = 0): i var num64: int64 doAssert parseHex("4E69ED4E69ED", num64) == 12 doAssert num64 == 86216859871725 - var i = 0 + var i = start var output = T(0) var foundDigit = false let last = min(s.len, if maxLen == 0: s.len else: i + maxLen) @@ -205,12 +209,11 @@ proc parseHex*[T: SomeInteger](s: openArray[char], number: var T, maxLen = 0): i inc(i) if foundDigit: number = output - result = i + result = i - start -proc parseIdent*(s: openArray[char], ident: var string): int = +proc parseIdent*(s: string, ident: var string, start = 0): int = ## Parses an identifier and stores it in ``ident``. Returns ## the number of the parsed characters or 0 in case of an error. - ## If error, the value of `ident` is not changed. runnableExamples: var res: string doAssert parseIdent("Hello World", res, 0) == 5 @@ -219,14 +222,14 @@ proc parseIdent*(s: openArray[char], ident: var string): int = doAssert res == "ello" doAssert parseIdent("Hello World", res, 6) == 5 doAssert res == "World" - var i = 0 + var i = start if i < s.len and s[i] in IdentStartChars: inc(i) while i < s.len and s[i] in IdentChars: inc(i) - ident = substr(s.toOpenArray(0, i-1)) - result = i + ident = substr(s, start, i-1) + result = i-start -proc parseIdent*(s: openArray[char]): string = +proc parseIdent*(s: string, start = 0): string = ## Parses an identifier and returns it or an empty string in ## case of an error. runnableExamples: @@ -235,27 +238,13 @@ proc parseIdent*(s: openArray[char]): string = doAssert parseIdent("Hello World", 5) == "" doAssert parseIdent("Hello World", 6) == "World" result = "" - var i = 0 + var i = start if i < s.len and s[i] in IdentStartChars: inc(i) while i < s.len and s[i] in IdentChars: inc(i) - result = substr(s.toOpenArray(0, i - 1)) + result = substr(s, start, i-1) -proc parseChar*(s: openArray[char], c: var char): int = - ## Parses a single character, stores it in `c` and returns 1. - ## In case of error (if start >= s.len) it returns 0 - ## and the value of `c` is unchanged. - runnableExamples: - var c: char - doAssert "nim".parseChar(c, 3) == 0 - doAssert c == '\0' - doAssert "nim".parseChar(c, 0) == 1 - doAssert c == 'n' - if s.len > 0: - c = s[0] - result = 1 - -proc skipWhitespace*(s: openArray[char]): int {.inline.} = +proc skipWhitespace*(s: string, start = 0): int {.inline.} = ## Skips the whitespace starting at ``s[start]``. Returns the number of ## skipped characters. runnableExamples: @@ -263,10 +252,9 @@ proc skipWhitespace*(s: openArray[char]): int {.inline.} = doAssert skipWhitespace(" Hello World", 0) == 1 doAssert skipWhitespace("Hello World", 5) == 1 doAssert skipWhitespace("Hello World", 5) == 2 - result = 0 - while result < s.len and s[result] in Whitespace: inc(result) + while start+result < s.len and s[start+result] in Whitespace: inc(result) -proc skip*(s, token: openArray[char]): int {.inline.} = +proc skip*(s, token: string, start = 0): int {.inline.} = ## Skips the `token` starting at ``s[start]``. Returns the length of `token` ## or 0 if there was no `token` at ``s[start]``. runnableExamples: @@ -275,23 +263,21 @@ proc skip*(s, token: openArray[char]): int {.inline.} = doAssert skip("2019-01-22", "19", 2) == 2 doAssert skip("CAPlow", "CAP", 0) == 3 doAssert skip("CAPlow", "cap", 0) == 0 - result = 0 - while result < s.len and result < token.len and - s[result] == token[result]: + while start+result < s.len and result < token.len and + s[result+start] == token[result]: inc(result) if result != token.len: result = 0 -proc skipIgnoreCase*(s, token: openArray[char]): int = +proc skipIgnoreCase*(s, token: string, start = 0): int = ## Same as `skip` but case is ignored for token matching. runnableExamples: doAssert skipIgnoreCase("CAPlow", "CAP", 0) == 3 doAssert skipIgnoreCase("CAPlow", "cap", 0) == 3 - result = 0 - while result < s.len and result < token.len and - toLower(s[result]) == toLower(token[result]): inc(result) + while start+result < s.len and result < token.len and + toLower(s[result+start]) == toLower(token[result]): inc(result) if result != token.len: result = 0 -proc skipUntil*(s: openArray[char], until: set[char]): int {.inline.} = +proc skipUntil*(s: string, until: set[char], start = 0): int {.inline.} = ## Skips all characters until one char from the set `until` is found ## or the end is reached. ## Returns number of characters skipped. @@ -299,10 +285,9 @@ proc skipUntil*(s: openArray[char], until: set[char]): int {.inline.} = doAssert skipUntil("Hello World", {'W', 'e'}, 0) == 1 doAssert skipUntil("Hello World", {'W'}, 0) == 6 doAssert skipUntil("Hello World", {'W', 'd'}, 0) == 6 - result = 0 - while result < s.len and s[result] notin until: inc(result) + while start+result < s.len and s[result+start] notin until: inc(result) -proc skipUntil*(s: openArray[char], until: char): int {.inline.} = +proc skipUntil*(s: string, until: char, start = 0): int {.inline.} = ## Skips all characters until the char `until` is found ## or the end is reached. ## Returns number of characters skipped. @@ -311,24 +296,19 @@ proc skipUntil*(s: openArray[char], until: char): int {.inline.} = doAssert skipUntil("Hello World", 'o', 4) == 0 doAssert skipUntil("Hello World", 'W', 0) == 6 doAssert skipUntil("Hello World", 'w', 0) == 11 - result = 0 - while result < s.len and s[result] != until: inc(result) + while start+result < s.len and s[result+start] != until: inc(result) -proc skipWhile*(s: openArray[char], toSkip: set[char]): int {.inline.} = - ## Skips all characters while one char from the set `toSkip` is found. +proc skipWhile*(s: string, toSkip: set[char], start = 0): int {.inline.} = + ## Skips all characters while one char from the set `token` is found. ## Returns number of characters skipped. runnableExamples: doAssert skipWhile("Hello World", {'H', 'e'}) == 2 doAssert skipWhile("Hello World", {'e'}) == 0 doAssert skipWhile("Hello World", {'W', 'o', 'r'}, 6) == 3 - result = 0 - while result < s.len and s[result] in toSkip: inc(result) + while start+result < s.len and s[result+start] in toSkip: inc(result) -proc fastSubstr(s: openArray[char]; token: var string; length: int) = - token.setLen length - for i in 0 ..< length: token[i] = s[i] - -proc parseUntil*(s: openArray[char], token: var string, until: set[char]): int {.inline.} = +proc parseUntil*(s: string, token: var string, until: set[char], + start = 0): int {.inline.} = ## Parses a token and stores it in ``token``. Returns ## the number of the parsed characters or 0 in case of an error. A token ## consists of the characters notin `until`. @@ -340,13 +320,13 @@ proc parseUntil*(s: openArray[char], token: var string, until: set[char]): int { doAssert myToken == "Hello " doAssert parseUntil("Hello World", myToken, {'W', 'r'}, 3) == 3 doAssert myToken == "lo " - var i = 0 + var i = start while i < s.len and s[i] notin until: inc(i) - result = i - fastSubstr(s, token, result) - #token = substr(s, start, i-1) + result = i-start + token = substr(s, start, i-1) -proc parseUntil*(s: openArray[char], token: var string, until: char): int {.inline.} = +proc parseUntil*(s: string, token: var string, until: char, + start = 0): int {.inline.} = ## Parses a token and stores it in ``token``. Returns ## the number of the parsed characters or 0 in case of an error. A token ## consists of any character that is not the `until` character. @@ -358,13 +338,13 @@ proc parseUntil*(s: openArray[char], token: var string, until: char): int {.inli doAssert myToken == "Hell" doAssert parseUntil("Hello World", myToken, 'o', 2) == 2 doAssert myToken == "ll" - var i = 0 + var i = start while i < s.len and s[i] != until: inc(i) - result = i - fastSubstr(s, token, result) - #token = substr(s, start, i-1) + result = i-start + token = substr(s, start, i-1) -proc parseUntil*(s: openArray[char], token: var string, until: string): int {.inline.} = +proc parseUntil*(s: string, token: var string, until: string, + start = 0): int {.inline.} = ## Parses a token and stores it in ``token``. Returns ## the number of the parsed characters or 0 in case of an error. A token ## consists of any character that comes before the `until` token. @@ -374,23 +354,22 @@ proc parseUntil*(s: openArray[char], token: var string, until: string): int {.in doAssert myToken == "Hello " doAssert parseUntil("Hello World", myToken, "Wor", 2) == 4 doAssert myToken == "llo " - when (NimMajor, NimMinor) <= (1, 0): - if until.len == 0: - token.setLen(0) - return 0 - var i = 0 + if until.len == 0: + token.setLen(0) + return 0 + var i = start while i < s.len: - if until.len > 0 and s[i] == until[0]: + if s[i] == until[0]: var u = 1 while i+u < s.len and u < until.len and s[i+u] == until[u]: inc u if u >= until.len: break inc(i) - result = i - fastSubstr(s, token, result) - #token = substr(s, start, i-1) + result = i-start + token = substr(s, start, i-1) -proc parseWhile*(s: openArray[char], token: var string, validChars: set[char]): int {.inline.} = +proc parseWhile*(s: string, token: var string, validChars: set[char], + start = 0): int {.inline.} = ## Parses a token and stores it in ``token``. Returns ## the number of the parsed characters or 0 in case of an error. A token ## consists of the characters in `validChars`. @@ -400,22 +379,21 @@ proc parseWhile*(s: openArray[char], token: var string, validChars: set[char]): doAssert myToken.len() == 0 doAssert parseWhile("Hello World", myToken, {'W', 'o', 'r'}, 6) == 3 doAssert myToken == "Wor" - var i = 0 + var i = start while i < s.len and s[i] in validChars: inc(i) - result = i - fastSubstr(s, token, result) - #token = substr(s, start, i-1) + result = i-start + token = substr(s, start, i-1) -proc captureBetween*(s: openArray[char], first: char, second = '\0'): string = +proc captureBetween*(s: string, first: char, second = '\0', start = 0): string = ## Finds the first occurrence of ``first``, then returns everything from there ## up to ``second`` (if ``second`` is '\0', then ``first`` is used). runnableExamples: doAssert captureBetween("Hello World", 'e') == "llo World" doAssert captureBetween("Hello World", 'e', 'r') == "llo Wo" - doAssert captureBetween("Hello World".toOpenArray(6, "Hello World".high), 'l') == "d" - var i = skipUntil(s, first) + 1 + doAssert captureBetween("Hello World", 'l', start = 6) == "d" + var i = skipUntil(s, first, start)+1+start result = "" - discard parseUntil(s.toOpenArray(i, s.high), result, if second == '\0': first else: second) + discard s.parseUntil(result, if second == '\0': first else: second, i) proc integerOutOfRangeError() {.noinline.} = raise newException(ValueError, "Parsed integer outside of valid range") @@ -424,10 +402,10 @@ proc integerOutOfRangeError() {.noinline.} = when defined(js): {.push overflowChecks: off.} -proc rawParseInt(s: openArray[char], b: var BiggestInt): int = +proc rawParseInt(s: string, b: var BiggestInt, start = 0): int = var sign: BiggestInt = -1 - i = 0 + i = start if i < s.len: if s[i] == '+': inc(i) elif s[i] == '-': @@ -447,30 +425,30 @@ proc rawParseInt(s: openArray[char], b: var BiggestInt): int = integerOutOfRangeError() else: b = b * sign - result = i + result = i - start when defined(js): {.pop.} # overflowChecks: off -proc parseBiggestInt*(s: openArray[char], number: var BiggestInt): int {. +proc parseBiggestInt*(s: string, number: var BiggestInt, start = 0): int {. rtl, extern: "npuParseBiggestInt", noSideEffect, raises: [ValueError].} = - ## Parses an integer and stores the value into `number`. + ## Parses an integer starting at `start` and stores the value into `number`. ## Result is the number of processed chars or 0 if there is no integer. ## `ValueError` is raised if the parsed integer is out of the valid range. runnableExamples: var res: BiggestInt - doAssert parseBiggestInt("9223372036854775807", res) == 19 + doAssert parseBiggestInt("9223372036854775807", res, 0) == 19 doAssert res == 9223372036854775807 - var res = BiggestInt(0) + var res: BiggestInt # use 'res' for exception safety (don't write to 'number' in case of an # overflow exception): - result = rawParseInt(s, res) + result = rawParseInt(s, res, start) if result != 0: number = res -proc parseInt*(s: openArray[char], number: var int): int {. +proc parseInt*(s: string, number: var int, start = 0): int {. rtl, extern: "npuParseInt", noSideEffect, raises: [ValueError].} = - ## Parses an integer and stores the value into `number`. + ## Parses an integer starting at `start` and stores the value into `number`. ## Result is the number of processed chars or 0 if there is no integer. ## `ValueError` is raised if the parsed integer is out of the valid range. runnableExamples: @@ -479,15 +457,15 @@ proc parseInt*(s: openArray[char], number: var int): int {. doAssert res == 2019 doAssert parseInt("2019", res, 2) == 2 doAssert res == 19 - var res = BiggestInt(0) - result = parseBiggestInt(s, res) + var res: BiggestInt + result = parseBiggestInt(s, res, start) when sizeof(int) <= 4: if res < low(int) or res > high(int): integerOutOfRangeError() if result != 0: number = int(res) -proc parseSaturatedNatural*(s: openArray[char], b: var int): int {. +proc parseSaturatedNatural*(s: string, b: var int, start = 0): int {. raises: [].} = ## Parses a natural number into ``b``. This cannot raise an overflow ## error. ``high(int)`` is returned for an overflow. @@ -497,7 +475,7 @@ proc parseSaturatedNatural*(s: openArray[char], b: var int): int {. var res = 0 discard parseSaturatedNatural("848", res) doAssert res == 848 - var i = 0 + var i = start if i < s.len and s[i] == '+': inc(i) if i < s.len and s[i] in {'0'..'9'}: b = 0 @@ -509,13 +487,13 @@ proc parseSaturatedNatural*(s: openArray[char], b: var int): int {. b = high(int) inc(i) while i < s.len and s[i] == '_': inc(i) # underscores are allowed and ignored - result = i + result = i - start -proc rawParseUInt(s: openArray[char], b: var BiggestUInt): int = +proc rawParseUInt(s: string, b: var BiggestUInt, start = 0): int = var res = 0.BiggestUInt prev = 0.BiggestUInt - i = 0 + i = start if i < s.len - 1 and s[i] == '-' and s[i + 1] in {'0'..'9'}: integerOutOfRangeError() if i < s.len and s[i] == '+': inc(i) # Allow @@ -529,11 +507,11 @@ proc rawParseUInt(s: openArray[char], b: var BiggestUInt): int = inc(i) while i < s.len and s[i] == '_': inc(i) # underscores are allowed and ignored b = res - result = i + result = i - start -proc parseBiggestUInt*(s: openArray[char], number: var BiggestUInt): int {. +proc parseBiggestUInt*(s: string, number: var BiggestUInt, start = 0): int {. rtl, extern: "npuParseBiggestUInt", noSideEffect, raises: [ValueError].} = - ## Parses an unsigned integer and stores the value + ## Parses an unsigned integer starting at `start` and stores the value ## into `number`. ## `ValueError` is raised if the parsed integer is out of the valid range. runnableExamples: @@ -542,16 +520,16 @@ proc parseBiggestUInt*(s: openArray[char], number: var BiggestUInt): int {. doAssert res == 12 doAssert parseBiggestUInt("1111111111111111111", res, 0) == 19 doAssert res == 1111111111111111111'u64 - var res = BiggestUInt(0) + var res: BiggestUInt # use 'res' for exception safety (don't write to 'number' in case of an # overflow exception): - result = rawParseUInt(s, res) + result = rawParseUInt(s, res, start) if result != 0: number = res -proc parseUInt*(s: openArray[char], number: var uint): int {. +proc parseUInt*(s: string, number: var uint, start = 0): int {. rtl, extern: "npuParseUInt", noSideEffect, raises: [ValueError].} = - ## Parses an unsigned integer and stores the value + ## Parses an unsigned integer starting at `start` and stores the value ## into `number`. ## `ValueError` is raised if the parsed integer is out of the valid range. runnableExamples: @@ -560,23 +538,23 @@ proc parseUInt*(s: openArray[char], number: var uint): int {. doAssert res == 3450 doAssert parseUInt("3450", res, 2) == 2 doAssert res == 50 - var res = BiggestUInt(0) - result = parseBiggestUInt(s, res) + var res: BiggestUInt + result = parseBiggestUInt(s, res, start) when sizeof(BiggestUInt) > sizeof(uint) and sizeof(uint) <= 4: if res > 0xFFFF_FFFF'u64: integerOutOfRangeError() if result != 0: number = uint(res) -proc parseBiggestFloat*(s: openArray[char], number: var BiggestFloat): int {. +proc parseBiggestFloat*(s: string, number: var BiggestFloat, start = 0): int {. magic: "ParseBiggestFloat", importc: "nimParseBiggestFloat", noSideEffect.} - ## Parses a float and stores the value into `number`. + ## Parses a float starting at `start` and stores the value into `number`. ## Result is the number of processed chars or 0 if a parsing error ## occurred. -proc parseFloat*(s: openArray[char], number: var float): int {. +proc parseFloat*(s: string, number: var float, start = 0): int {. rtl, extern: "npuParseFloat", noSideEffect.} = - ## Parses a float and stores the value into `number`. + ## Parses a float starting at `start` and stores the value into `number`. ## Result is the number of processed chars or 0 if there occurred a parsing ## error. runnableExamples: @@ -587,76 +565,11 @@ proc parseFloat*(s: openArray[char], number: var float): int {. doAssert res == 32.57 doAssert parseFloat("32.57", res, 3) == 2 doAssert res == 57.00 - var bf = BiggestFloat(0.0) - result = parseBiggestFloat(s, bf) + var bf: BiggestFloat + result = parseBiggestFloat(s, bf, start) if result != 0: number = bf -func toLowerAscii(c: char): char = - if c in {'A'..'Z'}: char(uint8(c) xor 0b0010_0000'u8) else: c - -func parseSize*(s: openArray[char], size: var int64, alwaysBin=false): int = - ## Parse a size qualified by binary or metric units into `size`. This format - ## is often called "human readable". Result is the number of processed chars - ## or 0 on parse errors and size is rounded to the nearest integer. Trailing - ## garbage like "/s" in "1k/s" is allowed and detected by `result < s.len`. - ## - ## To simplify use, following non-rare wild conventions, and since fractional - ## data like milli-bytes is so rare, unit matching is case-insensitive but for - ## the 'i' distinguishing binary-metric from metric (which cannot be 'I'). - ## - ## An optional trailing 'B|b' is ignored but processed. I.e., you must still - ## know if units are bytes | bits or infer this fact via the case of s[^1] (if - ## users can even be relied upon to use 'B' for byte and 'b' for bit or have - ## that be s[^1]). - ## - ## If `alwaysBin==true` then scales are always binary-metric, but e.g. "KiB" - ## is still accepted for clarity. If the value would exceed the range of - ## `int64`, `size` saturates to `int64.high`. Supported metric prefix chars - ## include k, m, g, t, p, e, z, y (but z & y saturate unless the number is a - ## small fraction). - ## - ## **See also:** - ## * https://en.wikipedia.org/wiki/Binary_prefix - ## * `formatSize module`_ for formatting - runnableExamples: - var res: int64 # caller must still know if 'b' refers to bytes|bits - doAssert parseSize("10.5 MB", res) == 7 - doAssert res == 10_500_000 # decimal metric Mega prefix - doAssert parseSize("64 mib", res) == 6 - doAssert res == 67108864 # 64 shl 20 - doAssert parseSize("1G/h", res, true) == 2 # '/' stops parse - doAssert res == 1073741824 # 1 shl 30, forced binary metric - const prefix = "b" & "kmgtpezy" # byte|bit & lowCase metric-ish prefixes - const scaleM = [1.0, 1e3, 1e6, 1e9, 1e12, 1e15, 1e18, 1e21, 1e24] # 10^(3*idx) - const scaleB = [1.0, 1024, 1048576, 1073741824, 1099511627776.0, # 2^(10*idx) - 1125899906842624.0, 1152921504606846976.0, # ldexp? - 1.180591620717411303424e21, 1.208925819614629174706176e24] - var number: float - var scale = 1.0 - result = parseFloat(s, number) - if number < 0: # While parseFloat accepts negatives .. - result = 0 #.. we do not since sizes cannot be < 0 - if result > 0: - let start = result # Save spot to maybe unwind white to EOS - while result < s.len and s[result] in Whitespace: - inc result - if result < s.len: # Illegal starting char => unity - if (let si = prefix.find(s[result].toLowerAscii); si >= 0): - inc result # Now parse the scale - scale = if alwaysBin: scaleB[si] else: scaleM[si] - if result < s.len and s[result] == 'i': - scale = scaleB[si] # Switch from default to binary-metric - inc result - if result < s.len and s[result].toLowerAscii == 'b': - inc result # Skip optional '[bB]' - else: # Unwind result advancement when there.. - result = start #..is no unit to the end of `s`. - var sizeF = number * scale + 0.5 # Saturate to int64.high when too big - size = if sizeF > 9223372036854774784.0: int64.high else: sizeF.int64 -# Above constant=2^63-1024 avoids C UB; github.com/nim-lang/Nim/issues/20102 or -# stackoverflow.com/questions/20923556/math-pow2-63-1-math-pow2-63-512-is-true - type InterpolatedKind* = enum ## Describes for `interpolatedFragments` ## which part of the interpolated string is @@ -666,7 +579,7 @@ type ikVar, ## ``var`` part of the interpolated string ikExpr ## ``expr`` part of the interpolated string -iterator interpolatedFragments*(s: openArray[char]): tuple[kind: InterpolatedKind, +iterator interpolatedFragments*(s: string): tuple[kind: InterpolatedKind, value: string] = ## Tokenizes the string `s` into substrings for interpolation purposes. ## @@ -701,7 +614,7 @@ iterator interpolatedFragments*(s: openArray[char]): tuple[kind: InterpolatedKin else: discard inc j raise newException(ValueError, - "Expected closing '}': " & substr(s.toOpenArray(i, s.high))) + "Expected closing '}': " & substr(s, i, s.high)) inc i, 2 # skip ${ kind = ikExpr elif j+1 < s.len and s[j+1] in IdentStartChars: @@ -715,370 +628,58 @@ iterator interpolatedFragments*(s: openArray[char]): tuple[kind: InterpolatedKin kind = ikDollar else: raise newException(ValueError, - "Unable to parse a variable name at " & substr(s.toOpenArray(i, s.high))) + "Unable to parse a variable name at " & substr(s, i, s.high)) else: while j < s.len and s[j] != '$': inc j kind = ikStr if j > i: # do not copy the trailing } for ikExpr: - yield (kind, substr(s.toOpenArray(i, j-1-ord(kind == ikExpr)))) + yield (kind, substr(s, i, j-1-ord(kind == ikExpr))) else: break i = j +when isMainModule: + import sequtils + let input = "$test{} $this is ${an{ example}} " + let expected = @[(ikVar, "test"), (ikStr, "{} "), (ikVar, "this"), + (ikStr, " is "), (ikExpr, "an{ example}"), (ikStr, " ")] + doAssert toSeq(interpolatedFragments(input)) == expected + + var value = 0 + discard parseHex("0x38", value) + doAssert value == 56 + + value = -1 + doAssert(parseSaturatedNatural("848", value) == 3) + doAssert value == 848 + + value = -1 + discard parseSaturatedNatural("84899999999999999999324234243143142342135435342532453", value) + doAssert value == high(int) + + value = -1 + discard parseSaturatedNatural("9223372036854775808", value) + doAssert value == high(int) + + value = -1 + discard parseSaturatedNatural("9223372036854775807", value) + doAssert value == high(int) + + value = -1 + discard parseSaturatedNatural("18446744073709551616", value) + doAssert value == high(int) + + value = -1 + discard parseSaturatedNatural("18446744073709551615", value) + doAssert value == high(int) + + value = -1 + doAssert(parseSaturatedNatural("1_000_000", value) == 9) + doAssert value == 1_000_000 + + var i64Value: int64 + discard parseBiggestInt("9223372036854775807", i64Value) + doAssert i64Value == 9223372036854775807 + {.pop.} - - -proc parseBin*[T: SomeInteger](s: string, number: var T, start = 0, - maxLen = 0): int {.noSideEffect.} = - ## Parses a binary number and stores its value in ``number``. - ## - ## Returns the number of the parsed characters or 0 in case of an error. - ## If error, the value of ``number`` is not changed. - ## - ## If ``maxLen == 0``, the parsing continues until the first non-bin character - ## or to the end of the string. Otherwise, no more than ``maxLen`` characters - ## are parsed starting from the ``start`` position. - ## - ## It does not check for overflow. If the value represented by the string is - ## too big to fit into ``number``, only the value of last fitting characters - ## will be stored in ``number`` without producing an error. - runnableExamples: - var num: int - doAssert parseBin("0100_1110_0110_1001_1110_1101", num) == 29 - doAssert num == 5138925 - doAssert parseBin("3", num) == 0 - var num8: int8 - doAssert parseBin("0b_0100_1110_0110_1001_1110_1101", num8) == 32 - doAssert num8 == 0b1110_1101'i8 - doAssert parseBin("0b_0100_1110_0110_1001_1110_1101", num8, 3, 9) == 9 - doAssert num8 == 0b0100_1110'i8 - var num8u: uint8 - doAssert parseBin("0b_0100_1110_0110_1001_1110_1101", num8u) == 32 - doAssert num8u == 237 - var num64: int64 - doAssert parseBin("0100111001101001111011010100111001101001", num64) == 40 - doAssert num64 == 336784608873 - parseBin(s.toOpenArray(start, s.high), number, maxLen) - -proc parseOct*[T: SomeInteger](s: string, number: var T, start = 0, - maxLen = 0): int {.noSideEffect.} = - ## Parses an octal number and stores its value in ``number``. - ## - ## Returns the number of the parsed characters or 0 in case of an error. - ## If error, the value of ``number`` is not changed. - ## - ## If ``maxLen == 0``, the parsing continues until the first non-oct character - ## or to the end of the string. Otherwise, no more than ``maxLen`` characters - ## are parsed starting from the ``start`` position. - ## - ## It does not check for overflow. If the value represented by the string is - ## too big to fit into ``number``, only the value of last fitting characters - ## will be stored in ``number`` without producing an error. - runnableExamples: - var num: int - doAssert parseOct("0o23464755", num) == 10 - doAssert num == 5138925 - doAssert parseOct("8", num) == 0 - var num8: int8 - doAssert parseOct("0o_1464_755", num8) == 11 - doAssert num8 == -19 - doAssert parseOct("0o_1464_755", num8, 3, 3) == 3 - doAssert num8 == 102 - var num8u: uint8 - doAssert parseOct("1464755", num8u) == 7 - doAssert num8u == 237 - var num64: int64 - doAssert parseOct("2346475523464755", num64) == 16 - doAssert num64 == 86216859871725 - parseOct(s.toOpenArray(start, s.high), number, maxLen) - -proc parseHex*[T: SomeInteger](s: string, number: var T, start = 0, - maxLen = 0): int {.noSideEffect.} = - ## Parses a hexadecimal number and stores its value in ``number``. - ## - ## Returns the number of the parsed characters or 0 in case of an error. - ## If error, the value of ``number`` is not changed. - ## - ## If ``maxLen == 0``, the parsing continues until the first non-hex character - ## or to the end of the string. Otherwise, no more than ``maxLen`` characters - ## are parsed starting from the ``start`` position. - ## - ## It does not check for overflow. If the value represented by the string is - ## too big to fit into ``number``, only the value of last fitting characters - ## will be stored in ``number`` without producing an error. - runnableExamples: - var num: int - doAssert parseHex("4E_69_ED", num) == 8 - doAssert num == 5138925 - doAssert parseHex("X", num) == 0 - doAssert parseHex("#ABC", num) == 4 - var num8: int8 - doAssert parseHex("0x_4E_69_ED", num8) == 11 - doAssert num8 == 0xED'i8 - doAssert parseHex("0x_4E_69_ED", num8, 3, 2) == 2 - doAssert num8 == 0x4E'i8 - var num8u: uint8 - doAssert parseHex("0x_4E_69_ED", num8u) == 11 - doAssert num8u == 237 - var num64: int64 - doAssert parseHex("4E69ED4E69ED", num64) == 12 - doAssert num64 == 86216859871725 - parseHex(s.toOpenArray(start, s.high), number, maxLen) - -proc parseIdent*(s: string, ident: var string, start = 0): int = - ## Parses an identifier and stores it in ``ident``. Returns - ## the number of the parsed characters or 0 in case of an error. - ## If error, the value of `ident` is not changed. - runnableExamples: - var res: string - doAssert parseIdent("Hello World", res, 0) == 5 - doAssert res == "Hello" - doAssert parseIdent("Hello World", res, 1) == 4 - doAssert res == "ello" - doAssert parseIdent("Hello World", res, 6) == 5 - doAssert res == "World" - parseIdent(s.toOpenArray(start, s.high), ident) - -proc parseIdent*(s: string, start = 0): string = - ## Parses an identifier and returns it or an empty string in - ## case of an error. - runnableExamples: - doAssert parseIdent("Hello World", 0) == "Hello" - doAssert parseIdent("Hello World", 1) == "ello" - doAssert parseIdent("Hello World", 5) == "" - doAssert parseIdent("Hello World", 6) == "World" - parseIdent(s.toOpenArray(start, s.high)) - -proc parseChar*(s: string, c: var char, start = 0): int = - ## Parses a single character, stores it in `c` and returns 1. - ## In case of error (if start >= s.len) it returns 0 - ## and the value of `c` is unchanged. - runnableExamples: - var c: char - doAssert "nim".parseChar(c, 3) == 0 - doAssert c == '\0' - doAssert "nim".parseChar(c, 0) == 1 - doAssert c == 'n' - parseChar(s.toOpenArray(start, s.high), c) - -proc skipWhitespace*(s: string, start = 0): int {.inline.} = - ## Skips the whitespace starting at ``s[start]``. Returns the number of - ## skipped characters. - runnableExamples: - doAssert skipWhitespace("Hello World", 0) == 0 - doAssert skipWhitespace(" Hello World", 0) == 1 - doAssert skipWhitespace("Hello World", 5) == 1 - doAssert skipWhitespace("Hello World", 5) == 2 - skipWhitespace(s.toOpenArray(start, s.high)) - -proc skip*(s, token: string, start = 0): int {.inline.} = - ## Skips the `token` starting at ``s[start]``. Returns the length of `token` - ## or 0 if there was no `token` at ``s[start]``. - runnableExamples: - doAssert skip("2019-01-22", "2019", 0) == 4 - doAssert skip("2019-01-22", "19", 0) == 0 - doAssert skip("2019-01-22", "19", 2) == 2 - doAssert skip("CAPlow", "CAP", 0) == 3 - doAssert skip("CAPlow", "cap", 0) == 0 - skip(s.toOpenArray(start, s.high), token) - -proc skipIgnoreCase*(s, token: string, start = 0): int = - ## Same as `skip` but case is ignored for token matching. - runnableExamples: - doAssert skipIgnoreCase("CAPlow", "CAP", 0) == 3 - doAssert skipIgnoreCase("CAPlow", "cap", 0) == 3 - skipIgnoreCase(s.toOpenArray(start, s.high), token) - -proc skipUntil*(s: string, until: set[char], start = 0): int {.inline.} = - ## Skips all characters until one char from the set `until` is found - ## or the end is reached. - ## Returns number of characters skipped. - runnableExamples: - doAssert skipUntil("Hello World", {'W', 'e'}, 0) == 1 - doAssert skipUntil("Hello World", {'W'}, 0) == 6 - doAssert skipUntil("Hello World", {'W', 'd'}, 0) == 6 - skipUntil(s.toOpenArray(start, s.high), until) - -proc skipUntil*(s: string, until: char, start = 0): int {.inline.} = - ## Skips all characters until the char `until` is found - ## or the end is reached. - ## Returns number of characters skipped. - runnableExamples: - doAssert skipUntil("Hello World", 'o', 0) == 4 - doAssert skipUntil("Hello World", 'o', 4) == 0 - doAssert skipUntil("Hello World", 'W', 0) == 6 - doAssert skipUntil("Hello World", 'w', 0) == 11 - skipUntil(s.toOpenArray(start, s.high), until) - -proc skipWhile*(s: string, toSkip: set[char], start = 0): int {.inline.} = - ## Skips all characters while one char from the set `toSkip` is found. - ## Returns number of characters skipped. - runnableExamples: - doAssert skipWhile("Hello World", {'H', 'e'}) == 2 - doAssert skipWhile("Hello World", {'e'}) == 0 - doAssert skipWhile("Hello World", {'W', 'o', 'r'}, 6) == 3 - skipWhile(s.toOpenArray(start, s.high), toSkip) - -proc parseUntil*(s: string, token: var string, until: set[char], - start = 0): int {.inline.} = - ## Parses a token and stores it in ``token``. Returns - ## the number of the parsed characters or 0 in case of an error. A token - ## consists of the characters notin `until`. - runnableExamples: - var myToken: string - doAssert parseUntil("Hello World", myToken, {'W', 'o', 'r'}) == 4 - doAssert myToken == "Hell" - doAssert parseUntil("Hello World", myToken, {'W', 'r'}) == 6 - doAssert myToken == "Hello " - doAssert parseUntil("Hello World", myToken, {'W', 'r'}, 3) == 3 - doAssert myToken == "lo " - parseUntil(s.toOpenArray(start, s.high), token, until) - -proc parseUntil*(s: string, token: var string, until: char, - start = 0): int {.inline.} = - ## Parses a token and stores it in ``token``. Returns - ## the number of the parsed characters or 0 in case of an error. A token - ## consists of any character that is not the `until` character. - runnableExamples: - var myToken: string - doAssert parseUntil("Hello World", myToken, 'W') == 6 - doAssert myToken == "Hello " - doAssert parseUntil("Hello World", myToken, 'o') == 4 - doAssert myToken == "Hell" - doAssert parseUntil("Hello World", myToken, 'o', 2) == 2 - doAssert myToken == "ll" - parseUntil(s.toOpenArray(start, s.high), token, until) - -proc parseUntil*(s: string, token: var string, until: string, - start = 0): int {.inline.} = - ## Parses a token and stores it in ``token``. Returns - ## the number of the parsed characters or 0 in case of an error. A token - ## consists of any character that comes before the `until` token. - runnableExamples: - var myToken: string - doAssert parseUntil("Hello World", myToken, "Wor") == 6 - doAssert myToken == "Hello " - doAssert parseUntil("Hello World", myToken, "Wor", 2) == 4 - doAssert myToken == "llo " - parseUntil(s.toOpenArray(start, s.high), token, until) - -proc parseWhile*(s: string, token: var string, validChars: set[char], - start = 0): int {.inline.} = - ## Parses a token and stores it in ``token``. Returns - ## the number of the parsed characters or 0 in case of an error. A token - ## consists of the characters in `validChars`. - runnableExamples: - var myToken: string - doAssert parseWhile("Hello World", myToken, {'W', 'o', 'r'}, 0) == 0 - doAssert myToken.len() == 0 - doAssert parseWhile("Hello World", myToken, {'W', 'o', 'r'}, 6) == 3 - doAssert myToken == "Wor" - parseWhile(s.toOpenArray(start, s.high), token, validChars) - -proc captureBetween*(s: string, first: char, second = '\0', start = 0): string = - ## Finds the first occurrence of ``first``, then returns everything from there - ## up to ``second`` (if ``second`` is '\0', then ``first`` is used). - runnableExamples: - doAssert captureBetween("Hello World", 'e') == "llo World" - doAssert captureBetween("Hello World", 'e', 'r') == "llo Wo" - doAssert captureBetween("Hello World", 'l', start = 6) == "d" - captureBetween(s.toOpenArray(start, s.high), first, second) - -proc parseBiggestInt*(s: string, number: var BiggestInt, start = 0): int {.noSideEffect, raises: [ValueError].} = - ## Parses an integer starting at `start` and stores the value into `number`. - ## Result is the number of processed chars or 0 if there is no integer. - ## `ValueError` is raised if the parsed integer is out of the valid range. - runnableExamples: - var res: BiggestInt - doAssert parseBiggestInt("9223372036854775807", res, 0) == 19 - doAssert res == 9223372036854775807 - parseBiggestInt(s.toOpenArray(start, s.high), number) - -proc parseInt*(s: string, number: var int, start = 0): int {.noSideEffect, raises: [ValueError].} = - ## Parses an integer starting at `start` and stores the value into `number`. - ## Result is the number of processed chars or 0 if there is no integer. - ## `ValueError` is raised if the parsed integer is out of the valid range. - runnableExamples: - var res: int - doAssert parseInt("2019", res, 0) == 4 - doAssert res == 2019 - doAssert parseInt("2019", res, 2) == 2 - doAssert res == 19 - parseInt(s.toOpenArray(start, s.high), number) - - -proc parseSaturatedNatural*(s: string, b: var int, start = 0): int {. - raises: [].} = - ## Parses a natural number into ``b``. This cannot raise an overflow - ## error. ``high(int)`` is returned for an overflow. - ## The number of processed character is returned. - ## This is usually what you really want to use instead of `parseInt`:idx:. - runnableExamples: - var res = 0 - discard parseSaturatedNatural("848", res) - doAssert res == 848 - parseSaturatedNatural(s.toOpenArray(start, s.high), b) - - -proc parseBiggestUInt*(s: string, number: var BiggestUInt, start = 0): int {.noSideEffect, raises: [ValueError].} = - ## Parses an unsigned integer starting at `start` and stores the value - ## into `number`. - ## `ValueError` is raised if the parsed integer is out of the valid range. - runnableExamples: - var res: BiggestUInt - doAssert parseBiggestUInt("12", res, 0) == 2 - doAssert res == 12 - doAssert parseBiggestUInt("1111111111111111111", res, 0) == 19 - doAssert res == 1111111111111111111'u64 - parseBiggestUInt(s.toOpenArray(start, s.high), number) - -proc parseUInt*(s: string, number: var uint, start = 0): int {.noSideEffect, raises: [ValueError].} = - ## Parses an unsigned integer starting at `start` and stores the value - ## into `number`. - ## `ValueError` is raised if the parsed integer is out of the valid range. - runnableExamples: - var res: uint - doAssert parseUInt("3450", res) == 4 - doAssert res == 3450 - doAssert parseUInt("3450", res, 2) == 2 - doAssert res == 50 - parseUInt(s.toOpenArray(start, s.high), number) - -proc parseBiggestFloat*(s: string, number: var BiggestFloat, start = 0): int {.noSideEffect.} = - ## Parses a float starting at `start` and stores the value into `number`. - ## Result is the number of processed chars or 0 if a parsing error - ## occurred. - parseFloat(s.toOpenArray(start, s.high), number) - -proc parseFloat*(s: string, number: var float, start = 0): int {.noSideEffect.} = - ## Parses a float starting at `start` and stores the value into `number`. - ## Result is the number of processed chars or 0 if there occurred a parsing - ## error. - runnableExamples: - var res: float - doAssert parseFloat("32", res, 0) == 2 - doAssert res == 32.0 - doAssert parseFloat("32.57", res, 0) == 5 - doAssert res == 32.57 - doAssert parseFloat("32.57", res, 3) == 2 - doAssert res == 57.00 - parseFloat(s.toOpenArray(start, s.high), number) - -iterator interpolatedFragments*(s: string): tuple[kind: InterpolatedKind, - value: string] = - ## Tokenizes the string `s` into substrings for interpolation purposes. - ## - runnableExamples: - var outp: seq[tuple[kind: InterpolatedKind, value: string]] - for k, v in interpolatedFragments(" $this is ${an example} $$"): - outp.add (k, v) - doAssert outp == @[(ikStr, " "), - (ikVar, "this"), - (ikStr, " is "), - (ikExpr, "an example"), - (ikStr, " "), - (ikDollar, "$")] - for x in s.toOa.interpolatedFragments: - yield x - diff --git a/lib/pure/parsexml.nim b/lib/pure/parsexml.nim index 884f258f3..a8e7aaab8 100644 --- a/lib/pure/parsexml.nim +++ b/lib/pure/parsexml.nim @@ -149,9 +149,6 @@ an HTML document contains. import strutils, lexbase, streams, unicode -when defined(nimPreviewSlimSystem): - import std/[assertions, syncio] - # the parser treats ``
    `` as ``

    `` # xmlElementCloseEnd, ## ``/>`` @@ -302,15 +299,21 @@ template piRest*(my: XmlParser): string = assert(my.kind == xmlPI) my.b -proc rawData*(my: var XmlParser): lent string {.inline.} = +proc rawData*(my: var XmlParser): string {.inline.} = ## returns the underlying 'data' string by reference. ## This is only used for speed hacks. - result = my.a + when defined(gcDestructors): + result = move(my.a) + else: + shallowCopy(result, my.a) -proc rawData2*(my: var XmlParser): lent string {.inline.} = +proc rawData2*(my: var XmlParser): string {.inline.} = ## returns the underlying second 'data' string by reference. ## This is only used for speed hacks. - result = my.b + when defined(gcDestructors): + result = move(my.b) + else: + shallowCopy(result, my.b) proc getColumn*(my: XmlParser): int {.inline.} = ## get the current column the parser has arrived at. @@ -669,9 +672,6 @@ proc parseAttribute(my: var XmlParser) = parseEntity(my, my.b) my.kind = xmlAttribute # parseEntity overwrites my.kind! pos = my.bufpos - elif c == '/': - pos = lexbase.handleRefillChar(my, pos) - add(my.b, '/') else: add(my.b, c) inc(pos) diff --git a/lib/pure/pathnorm.nim b/lib/pure/pathnorm.nim index 4cdc02303..407ec156c 100644 --- a/lib/pure/pathnorm.nim +++ b/lib/pure/pathnorm.nim @@ -7,14 +7,14 @@ # distribution, for details about the copyright. # -## OS-Path normalization. Used by `os.nim` but also +## OS-Path normalization. Used by ``os.nim`` but also ## generally useful for dealing with paths. ## ## Unstable API. # Yes, this uses import here, not include so that # we don't end up exporting these symbols from pathnorm and os: -import std/private/osseps +import "includes/osseps" type PathIter* = object @@ -29,6 +29,10 @@ proc next*(it: var PathIter; x: string): (int, int) = if not it.notFirst and x[it.i] in {DirSep, AltSep}: # absolute path: inc it.i + when doslikeFileSystem: # UNC paths have leading `\\` + if hasNext(it, x) and x[it.i] == DirSep and + it.i+1 < x.len and x[it.i+1] != DirSep: + inc it.i else: while it.i < x.len and x[it.i] notin {DirSep, AltSep}: inc it.i if it.i > it.prev: @@ -40,7 +44,7 @@ proc next*(it: var PathIter; x: string): (int, int) = it.notFirst = true iterator dirs(x: string): (int, int) = - var it = default PathIter + var it: PathIter while hasNext(it, x): yield next(it, x) proc isDot(x: string; bounds: (int, int)): bool = @@ -52,23 +56,10 @@ proc isDotDot(x: string; bounds: (int, int)): bool = proc isSlash(x: string; bounds: (int, int)): bool = bounds[1] == bounds[0] and x[bounds[0]] in {DirSep, AltSep} -when doslikeFileSystem: - import std/private/ntpath - proc addNormalizePath*(x: string; result: var string; state: var int; dirSep = DirSep) = ## Low level proc. Undocumented. - when doslikeFileSystem: # Add Windows drive at start without normalization - var x = x - if result == "": - let (drive, file) = splitDrive(x) - x = file - result.add drive - for c in result.mitems: - if c in {DirSep, AltSep}: - c = dirSep - # state: 0th bit set if isAbsolute path. Other bits count # the number of path components. var it: PathIter @@ -78,44 +69,40 @@ proc addNormalizePath*(x: string; result: var string; state: var int; while hasNext(it, x): let b = next(it, x) if (state shr 1 == 0) and isSlash(x, b): - if result.len == 0 or result[result.len - 1] notin {DirSep, AltSep}: - result.add dirSep + result.add dirSep state = state or 1 elif isDotDot(x, b): if (state shr 1) >= 1: var d = result.len # f/.. - # We could handle stripping trailing sep here: foo// => foo like this: - # while (d-1) > (state and 1) and result[d-1] in {DirSep, AltSep}: dec d - # but right now we instead handle it inside os.joinPath - - # strip path component: foo/bar => foo while (d-1) > (state and 1) and result[d-1] notin {DirSep, AltSep}: dec d if d > 0: setLen(result, d-1) dec state, 2 else: - if result.len > 0 and result[result.len - 1] notin {DirSep, AltSep}: + if result.len > 0 and result[^1] notin {DirSep, AltSep}: result.add dirSep result.add substr(x, b[0], b[1]) elif isDot(x, b): discard "discard the dot" elif b[1] >= b[0]: - if result.len > 0 and result[result.len - 1] notin {DirSep, AltSep}: + if result.len > 0 and result[^1] notin {DirSep, AltSep}: result.add dirSep result.add substr(x, b[0], b[1]) inc state, 2 if result == "" and x != "": result = "." proc normalizePath*(path: string; dirSep = DirSep): string = - runnableExamples: - when defined(posix): - doAssert normalizePath("./foo//bar/../baz") == "foo/baz" - + ## Example: + ## + ## .. code-block:: nim + ## assert normalizePath("./foo//bar/../baz") == "foo/baz" + ## + ## ## - Turns multiple slashes into single slashes. - ## - Resolves `'/foo/../bar'` to `'/bar'`. - ## - Removes `'./'` from the path, but `"foo/.."` becomes `"."`. + ## - Resolves '/foo/../bar' to '/bar'. + ## - Removes './' from the path (but "foo/.." becomes ".") result = newStringOfCap(path.len) var state = 0 addNormalizePath(path, result, state, dirSep) diff --git a/lib/pure/pegs.nim b/lib/pure/pegs.nim index 86ad9c0f6..3c3941285 100644 --- a/lib/pure/pegs.nim +++ b/lib/pure/pegs.nim @@ -16,14 +16,11 @@ ## include "system/inclrtl" -when defined(nimPreviewSlimSystem): - import std/[syncio, assertions] const useUnicode = true ## change this to deactivate proper UTF-8 support import strutils, macros -import std/private/decode_helpers when useUnicode: import unicode @@ -85,30 +82,30 @@ type of pkChar, pkGreedyRepChar: ch: char of pkCharChoice, pkGreedyRepSet: charChoice: ref set[char] of pkNonTerminal: nt: NonTerminal - of pkBackRef..pkBackRefIgnoreStyle: index: range[-MaxSubpatterns..MaxSubpatterns-1] + of pkBackRef..pkBackRefIgnoreStyle: index: range[0..MaxSubpatterns] else: sons: seq[Peg] NonTerminal* = ref NonTerminalObj -func kind*(p: Peg): PegKind = p.kind +proc kind*(p: Peg): PegKind = p.kind ## Returns the *PegKind* of a given *Peg* object. -func term*(p: Peg): string = p.term +proc term*(p: Peg): string = p.term ## Returns the *string* representation of a given *Peg* variant object ## where present. -func ch*(p: Peg): char = p.ch +proc ch*(p: Peg): char = p.ch ## Returns the *char* representation of a given *Peg* variant object ## where present. -func charChoice*(p: Peg): ref set[char] = p.charChoice +proc charChoice*(p: Peg): ref set[char] = p.charChoice ## Returns the *charChoice* field of a given *Peg* variant object ## where present. -func nt*(p: Peg): NonTerminal = p.nt +proc nt*(p: Peg): NonTerminal = p.nt ## Returns the *NonTerminal* object of a given *Peg* variant object ## where present. -func index*(p: Peg): range[-MaxSubpatterns..MaxSubpatterns-1] = p.index +proc index*(p: Peg): range[0..MaxSubpatterns] = p.index ## Returns the back-reference index of a captured sub-pattern in the ## *Captures* object for a given *Peg* variant object where present. @@ -122,60 +119,59 @@ iterator pairs*(p: Peg): (int, Peg) {.inline.} = for i in 0 ..< p.sons.len: yield (i, p.sons[i]) -func name*(nt: NonTerminal): string = nt.name +proc name*(nt: NonTerminal): string = nt.name ## Gets the name of the symbol represented by the parent *Peg* object variant ## of a given *NonTerminal*. -func line*(nt: NonTerminal): int = nt.line +proc line*(nt: NonTerminal): int = nt.line ## Gets the line number of the definition of the parent *Peg* object variant ## of a given *NonTerminal*. -func col*(nt: NonTerminal): int = nt.col +proc col*(nt: NonTerminal): int = nt.col ## Gets the column number of the definition of the parent *Peg* object variant ## of a given *NonTerminal*. -func flags*(nt: NonTerminal): set[NonTerminalFlag] = nt.flags +proc flags*(nt: NonTerminal): set[NonTerminalFlag] = nt.flags ## Gets the *NonTerminalFlag*-typed flags field of the parent *Peg* variant ## object of a given *NonTerminal*. -func rule*(nt: NonTerminal): Peg = nt.rule +proc rule*(nt: NonTerminal): Peg = nt.rule ## Gets the *Peg* object representing the rule definition of the parent *Peg* ## object variant of a given *NonTerminal*. -func term*(t: string): Peg {.rtl, extern: "npegs$1Str".} = +proc term*(t: string): Peg {.noSideEffect, rtl, extern: "npegs$1Str".} = ## constructs a PEG from a terminal string if t.len != 1: result = Peg(kind: pkTerminal, term: t) else: result = Peg(kind: pkChar, ch: t[0]) -func termIgnoreCase*(t: string): Peg {. - rtl, extern: "npegs$1".} = +proc termIgnoreCase*(t: string): Peg {. + noSideEffect, rtl, extern: "npegs$1".} = ## constructs a PEG from a terminal string; ignore case for matching result = Peg(kind: pkTerminalIgnoreCase, term: t) -func termIgnoreStyle*(t: string): Peg {. - rtl, extern: "npegs$1".} = +proc termIgnoreStyle*(t: string): Peg {. + noSideEffect, rtl, extern: "npegs$1".} = ## constructs a PEG from a terminal string; ignore style for matching result = Peg(kind: pkTerminalIgnoreStyle, term: t) -func term*(t: char): Peg {.rtl, extern: "npegs$1Char".} = +proc term*(t: char): Peg {.noSideEffect, rtl, extern: "npegs$1Char".} = ## constructs a PEG from a terminal char assert t != '\0' result = Peg(kind: pkChar, ch: t) -func charSet*(s: set[char]): Peg {.rtl, extern: "npegs$1".} = +proc charSet*(s: set[char]): Peg {.noSideEffect, rtl, extern: "npegs$1".} = ## constructs a PEG from a character set `s` assert '\0' notin s result = Peg(kind: pkCharChoice) - {.cast(noSideEffect).}: - new(result.charChoice) - result.charChoice[] = s + new(result.charChoice) + result.charChoice[] = s -func len(a: Peg): int {.inline.} = return a.sons.len -func add(d: var Peg, s: Peg) {.inline.} = add(d.sons, s) +proc len(a: Peg): int {.inline.} = return a.sons.len +proc add(d: var Peg, s: Peg) {.inline.} = add(d.sons, s) -func addChoice(dest: var Peg, elem: Peg) = +proc addChoice(dest: var Peg, elem: Peg) = var L = dest.len-1 if L >= 0 and dest.sons[L].kind == pkCharChoice: # caution! Do not introduce false aliasing here! @@ -198,12 +194,12 @@ template multipleOp(k: PegKind, localOpt: untyped) = if result.len == 1: result = result.sons[0] -func `/`*(a: varargs[Peg]): Peg {. - rtl, extern: "npegsOrderedChoice".} = +proc `/`*(a: varargs[Peg]): Peg {. + noSideEffect, rtl, extern: "npegsOrderedChoice".} = ## constructs an ordered choice with the PEGs in `a` multipleOp(pkOrderedChoice, addChoice) -func addSequence(dest: var Peg, elem: Peg) = +proc addSequence(dest: var Peg, elem: Peg) = var L = dest.len-1 if L >= 0 and dest.sons[L].kind == pkTerminal: # caution! Do not introduce false aliasing here! @@ -215,12 +211,12 @@ func addSequence(dest: var Peg, elem: Peg) = else: add(dest, elem) else: add(dest, elem) -func sequence*(a: varargs[Peg]): Peg {. - rtl, extern: "npegs$1".} = +proc sequence*(a: varargs[Peg]): Peg {. + noSideEffect, rtl, extern: "npegs$1".} = ## constructs a sequence with all the PEGs from `a` multipleOp(pkSequence, addSequence) -func `?`*(a: Peg): Peg {.rtl, extern: "npegsOptional".} = +proc `?`*(a: Peg): Peg {.noSideEffect, rtl, extern: "npegsOptional".} = ## constructs an optional for the PEG `a` if a.kind in {pkOption, pkGreedyRep, pkGreedyAny, pkGreedyRepChar, pkGreedyRepSet}: @@ -230,7 +226,7 @@ func `?`*(a: Peg): Peg {.rtl, extern: "npegsOptional".} = else: result = Peg(kind: pkOption, sons: @[a]) -func `*`*(a: Peg): Peg {.rtl, extern: "npegsGreedyRep".} = +proc `*`*(a: Peg): Peg {.noSideEffect, rtl, extern: "npegsGreedyRep".} = ## constructs a "greedy repetition" for the PEG `a` case a.kind of pkGreedyRep, pkGreedyRepChar, pkGreedyRepSet, pkGreedyAny, pkOption: @@ -245,99 +241,96 @@ func `*`*(a: Peg): Peg {.rtl, extern: "npegsGreedyRep".} = else: result = Peg(kind: pkGreedyRep, sons: @[a]) -func `!*`*(a: Peg): Peg {.rtl, extern: "npegsSearch".} = +proc `!*`*(a: Peg): Peg {.noSideEffect, rtl, extern: "npegsSearch".} = ## constructs a "search" for the PEG `a` result = Peg(kind: pkSearch, sons: @[a]) -func `!*\`*(a: Peg): Peg {.rtl, +proc `!*\`*(a: Peg): Peg {.noSideEffect, rtl, extern: "npgegsCapturedSearch".} = ## constructs a "captured search" for the PEG `a` result = Peg(kind: pkCapturedSearch, sons: @[a]) -func `+`*(a: Peg): Peg {.rtl, extern: "npegsGreedyPosRep".} = +proc `+`*(a: Peg): Peg {.noSideEffect, rtl, extern: "npegsGreedyPosRep".} = ## constructs a "greedy positive repetition" with the PEG `a` return sequence(a, *a) -func `&`*(a: Peg): Peg {.rtl, extern: "npegsAndPredicate".} = +proc `&`*(a: Peg): Peg {.noSideEffect, rtl, extern: "npegsAndPredicate".} = ## constructs an "and predicate" with the PEG `a` result = Peg(kind: pkAndPredicate, sons: @[a]) -func `!`*(a: Peg): Peg {.rtl, extern: "npegsNotPredicate".} = +proc `!`*(a: Peg): Peg {.noSideEffect, rtl, extern: "npegsNotPredicate".} = ## constructs a "not predicate" with the PEG `a` result = Peg(kind: pkNotPredicate, sons: @[a]) -func any*: Peg {.inline.} = +proc any*: Peg {.inline.} = ## constructs the PEG `any character`:idx: (``.``) result = Peg(kind: pkAny) -func anyRune*: Peg {.inline.} = +proc anyRune*: Peg {.inline.} = ## constructs the PEG `any rune`:idx: (``_``) result = Peg(kind: pkAnyRune) -func newLine*: Peg {.inline.} = +proc newLine*: Peg {.inline.} = ## constructs the PEG `newline`:idx: (``\n``) result = Peg(kind: pkNewLine) -func unicodeLetter*: Peg {.inline.} = +proc unicodeLetter*: Peg {.inline.} = ## constructs the PEG ``\letter`` which matches any Unicode letter. result = Peg(kind: pkLetter) -func unicodeLower*: Peg {.inline.} = +proc unicodeLower*: Peg {.inline.} = ## constructs the PEG ``\lower`` which matches any Unicode lowercase letter. result = Peg(kind: pkLower) -func unicodeUpper*: Peg {.inline.} = +proc unicodeUpper*: Peg {.inline.} = ## constructs the PEG ``\upper`` which matches any Unicode uppercase letter. result = Peg(kind: pkUpper) -func unicodeTitle*: Peg {.inline.} = +proc unicodeTitle*: Peg {.inline.} = ## constructs the PEG ``\title`` which matches any Unicode title letter. result = Peg(kind: pkTitle) -func unicodeWhitespace*: Peg {.inline.} = +proc unicodeWhitespace*: Peg {.inline.} = ## constructs the PEG ``\white`` which matches any Unicode ## whitespace character. result = Peg(kind: pkWhitespace) -func startAnchor*: Peg {.inline.} = +proc startAnchor*: Peg {.inline.} = ## constructs the PEG ``^`` which matches the start of the input. result = Peg(kind: pkStartAnchor) -func endAnchor*: Peg {.inline.} = +proc endAnchor*: Peg {.inline.} = ## constructs the PEG ``$`` which matches the end of the input. result = !any() -func capture*(a: Peg = Peg(kind: pkEmpty)): Peg {.rtl, extern: "npegsCapture".} = +proc capture*(a: Peg): Peg {.noSideEffect, rtl, extern: "npegsCapture".} = ## constructs a capture with the PEG `a` result = Peg(kind: pkCapture, sons: @[a]) -func backref*(index: range[1..MaxSubpatterns], reverse: bool = false): Peg {. - rtl, extern: "npegs$1".} = +proc backref*(index: range[1..MaxSubpatterns]): Peg {. + noSideEffect, rtl, extern: "npegs$1".} = ## constructs a back reference of the given `index`. `index` starts counting - ## from 1. `reverse` specifies wether indexing starts from the end of the - ## capture list. - result = Peg(kind: pkBackRef, index: (if reverse: -index else: index - 1)) + ## from 1. + result = Peg(kind: pkBackRef, index: index-1) -func backrefIgnoreCase*(index: range[1..MaxSubpatterns], reverse: bool = false): Peg {. - rtl, extern: "npegs$1".} = +proc backrefIgnoreCase*(index: range[1..MaxSubpatterns]): Peg {. + noSideEffect, rtl, extern: "npegs$1".} = ## constructs a back reference of the given `index`. `index` starts counting - ## from 1. `reverse` specifies wether indexing starts from the end of the - ## capture list. Ignores case for matching. - result = Peg(kind: pkBackRefIgnoreCase, index: (if reverse: -index else: index - 1)) + ## from 1. Ignores case for matching. + result = Peg(kind: pkBackRefIgnoreCase, index: index-1) -func backrefIgnoreStyle*(index: range[1..MaxSubpatterns], reverse: bool = false): Peg {. - rtl, extern: "npegs$1".} = +proc backrefIgnoreStyle*(index: range[1..MaxSubpatterns]): Peg {. + noSideEffect, rtl, extern: "npegs$1".} = ## constructs a back reference of the given `index`. `index` starts counting - ## from 1. `reverse` specifies wether indexing starts from the end of the - ## capture list. Ignores style for matching. - result = Peg(kind: pkBackRefIgnoreStyle, index: (if reverse: -index else: index - 1)) + ## from 1. Ignores style for matching. + result = Peg(kind: pkBackRefIgnoreStyle, index: index-1) -func spaceCost(n: Peg): int = +proc spaceCost(n: Peg): int = case n.kind of pkEmpty: discard of pkTerminal, pkTerminalIgnoreCase, pkTerminalIgnoreStyle, pkChar, pkGreedyRepChar, pkCharChoice, pkGreedyRepSet, - pkAny..pkWhitespace, pkGreedyAny, pkBackRef..pkBackRefIgnoreStyle: + pkAny..pkWhitespace, pkGreedyAny: result = 1 of pkNonTerminal: # we cannot inline a rule with a non-terminal @@ -347,8 +340,8 @@ func spaceCost(n: Peg): int = inc(result, spaceCost(n.sons[i])) if result >= InlineThreshold: break -func nonterminal*(n: NonTerminal): Peg {. - rtl, extern: "npegs$1".} = +proc nonterminal*(n: NonTerminal): Peg {. + noSideEffect, rtl, extern: "npegs$1".} = ## constructs a PEG that consists of the nonterminal symbol assert n != nil if ntDeclared in n.flags and spaceCost(n.rule) < InlineThreshold: @@ -357,8 +350,8 @@ func nonterminal*(n: NonTerminal): Peg {. else: result = Peg(kind: pkNonTerminal, nt: n) -func newNonTerminal*(name: string, line, column: int): NonTerminal {. - rtl, extern: "npegs$1".} = +proc newNonTerminal*(name: string, line, column: int): NonTerminal {. + noSideEffect, rtl, extern: "npegs$1".} = ## constructs a nonterminal symbol result = NonTerminal(name: name, line: line, col: column) @@ -393,7 +386,7 @@ template natural*: Peg = # ------------------------- debugging ----------------------------------------- -func esc(c: char, reserved = {'\0'..'\255'}): string = +proc esc(c: char, reserved = {'\0'..'\255'}): string = case c of '\b': result = "\\b" of '\t': result = "\\t" @@ -409,14 +402,14 @@ func esc(c: char, reserved = {'\0'..'\255'}): string = elif c in reserved: result = '\\' & c else: result = $c -func singleQuoteEsc(c: char): string = return "'" & esc(c, {'\''}) & "'" +proc singleQuoteEsc(c: char): string = return "'" & esc(c, {'\''}) & "'" -func singleQuoteEsc(str: string): string = +proc singleQuoteEsc(str: string): string = result = "'" for c in items(str): add result, esc(c, {'\''}) add result, '\'' -func charSetEscAux(cc: set[char]): string = +proc charSetEscAux(cc: set[char]): string = const reserved = {'^', '-', ']'} result = "" var c1 = 0 @@ -433,13 +426,13 @@ func charSetEscAux(cc: set[char]): string = c1 = c2 inc(c1) -func charSetEsc(cc: set[char]): string = +proc charSetEsc(cc: set[char]): string = if card(cc) >= 128+64: result = "[^" & charSetEscAux({'\1'..'\xFF'} - cc) & ']' else: result = '[' & charSetEscAux(cc) & ']' -func toStrAux(r: Peg, res: var string) = +proc toStrAux(r: Peg, res: var string) = case r.kind of pkEmpty: add(res, "()") of pkAny: add(res, '.') @@ -525,7 +518,7 @@ func toStrAux(r: Peg, res: var string) = of pkStartAnchor: add(res, '^') -func `$` *(r: Peg): string {.rtl, extern: "npegsToString".} = +proc `$` *(r: Peg): string {.noSideEffect, rtl, extern: "npegsToString".} = ## converts a PEG to its string representation result = "" toStrAux(r, result) @@ -538,7 +531,7 @@ type ml: int origStart: int -func bounds*(c: Captures, +proc bounds*(c: Captures, i: range[0..MaxSubpatterns-1]): tuple[first, last: int] = ## returns the bounds ``[first..last]`` of the `i`'th capture. result = c.matches[i] @@ -551,26 +544,24 @@ when not useUnicode: inc(i) template runeLenAt(s, i): untyped = 1 - func isAlpha(a: char): bool {.inline.} = return a in {'a'..'z', 'A'..'Z'} - func isUpper(a: char): bool {.inline.} = return a in {'A'..'Z'} - func isLower(a: char): bool {.inline.} = return a in {'a'..'z'} - func isTitle(a: char): bool {.inline.} = return false - func isWhiteSpace(a: char): bool {.inline.} = return a in {' ', '\9'..'\13'} + proc isAlpha(a: char): bool {.inline.} = return a in {'a'..'z', 'A'..'Z'} + proc isUpper(a: char): bool {.inline.} = return a in {'A'..'Z'} + proc isLower(a: char): bool {.inline.} = return a in {'a'..'z'} + proc isTitle(a: char): bool {.inline.} = return false + proc isWhiteSpace(a: char): bool {.inline.} = return a in {' ', '\9'..'\13'} template matchOrParse(mopProc: untyped) = # Used to make the main matcher proc *rawMatch* as well as event parser # procs. For the former, *enter* and *leave* event handler code generators # are provided which just return *discard*. - proc mopProc(s: string, p: Peg, start: int, c: var Captures): int {.gcsafe.} = + proc mopProc(s: string, p: Peg, start: int, c: var Captures): int = proc matchBackRef(s: string, p: Peg, start: int, c: var Captures): int = # Parse handler code must run in an *of* clause of its own for each # *PegKind*, so we encapsulate the identical clause body for # *pkBackRef..pkBackRefIgnoreStyle* here. - var index = p.index - if index < 0: index.inc(c.ml) - if index < 0 or index >= c.ml: return -1 - var (a, b) = c.matches[index] + if p.index >= c.ml: return -1 + var (a, b) = c.matches[p.index] var n: Peg case p.kind of pkBackRef: @@ -830,22 +821,15 @@ template matchOrParse(mopProc: untyped) = leave(pkNotPredicate, s, p, start, result) of pkCapture: enter(pkCapture, s, p, start) - if p.sons.len == 0 or p.sons[0].kind == pkEmpty: - # empty capture removes last match - dec(c.ml) - c.matches[c.ml] = (0, 0) - result = 0 # match of length 0 + var idx = c.ml # reserve a slot for the subpattern + inc(c.ml) + result = mopProc(s, p.sons[0], start, c) + if result >= 0: + if idx < MaxSubpatterns: + c.matches[idx] = (start, start+result-1) + #else: silently ignore the capture else: - var idx = c.ml # reserve a slot for the subpattern - result = mopProc(s, p.sons[0], start, c) - if result >= 0: - if idx < MaxSubpatterns: - if idx != c.ml: - for i in countdown(c.ml, idx): - c.matches[i+1] = c.matches[i] - c.matches[idx] = (start, start+result-1) - #else: silently ignore the capture - inc(c.ml) + c.ml = idx leave(pkCapture, s, p, start, result) of pkBackRef: enter(pkBackRef, s, p, start) @@ -866,8 +850,8 @@ template matchOrParse(mopProc: untyped) = leave(pkStartAnchor, s, p, start, result) of pkRule, pkList: assert false -func rawMatch*(s: string, p: Peg, start: int, c: var Captures): int - {.rtl, extern: "npegs$1".} = +proc rawMatch*(s: string, p: Peg, start: int, c: var Captures): int + {.noSideEffect, rtl, extern: "npegs$1".} = ## low-level matching proc that implements the PEG interpreter. Use this ## for maximum efficiency (every other PEG operation ends up calling this ## proc). @@ -879,38 +863,34 @@ func rawMatch*(s: string, p: Peg, start: int, c: var Captures): int template leave(pk, s, p, start, length) = discard matchOrParse(matchIt) - {.cast(noSideEffect).}: - # This cast is allowed because the `matchOrParse` template is used for - # both matching and parsing, but side effects are only possible when it's - # used by `eventParser`. - result = matchIt(s, p, start, c) + result = matchIt(s, p, start, c) macro mkHandlerTplts(handlers: untyped): untyped = # Transforms the handler spec in *handlers* into handler templates. # The AST structure of *handlers[0]*: # # .. code-block:: - # StmtList - # Call - # Ident "pkNonTerminal" - # StmtList - # Call - # Ident "enter" - # StmtList - # - # Call - # Ident "leave" - # StmtList - # - # Call - # Ident "pkChar" - # StmtList - # Call - # Ident "leave" - # StmtList - # - # ... - func mkEnter(hdName, body: NimNode): NimNode = + # StmtList + # Call + # Ident "pkNonTerminal" + # StmtList + # Call + # Ident "enter" + # StmtList + # + # Call + # Ident "leave" + # StmtList + # + # Call + # Ident "pkChar" + # StmtList + # Call + # Ident "leave" + # StmtList + # + # ... + proc mkEnter(hdName, body: NimNode): NimNode = template helper(hdName, body) {.dirty.} = template hdName(s, p, start) = let s {.inject.} = s @@ -927,16 +907,16 @@ macro mkHandlerTplts(handlers: untyped): untyped = result = newStmtList() for topCall in handlers[0]: - if topCall.kind notin nnkCallKinds: + if nnkCall != topCall.kind: error("Call syntax expected.", topCall) let pegKind = topCall[0] - if pegKind.kind notin {nnkIdent, nnkSym}: + if nnkIdent != pegKind.kind: error("PegKind expected.", pegKind) if 2 == topCall.len: for hdDef in topCall[1]: - if hdDef.kind notin nnkCallKinds: + if nnkCall != hdDef.kind: error("Call syntax expected.", hdDef) - if hdDef[0].kind notin {nnkIdent, nnkSym}: + if nnkIdent != hdDef[0].kind: error("Handler identifier expected.", hdDef[0]) if 2 == hdDef.len: let hdPostf = substr(pegKind.strVal, 2) @@ -960,7 +940,7 @@ template eventParser*(pegAst, handlers: untyped): (proc(s: string): int) = ## evaluates an arithmetic expression defined by a simple PEG: ## ## .. code-block:: nim - ## import std/[strutils, pegs] + ## import strutils, pegs ## ## let ## pegAst = """ @@ -1027,7 +1007,7 @@ template eventParser*(pegAst, handlers: untyped): (proc(s: string): int) = ## Symbols declared in an *enter* handler can be made visible in the ## corresponding *leave* handler by annotating them with an *inject* pragma. proc rawParse(s: string, p: Peg, start: int, c: var Captures): int - {.gensym.} = + {.genSym.} = # binding from *macros* bind strVal @@ -1062,7 +1042,7 @@ template eventParser*(pegAst, handlers: untyped): (proc(s: string): int) = matchOrParse(parseIt) parseIt(s, p, start, c) - proc parser(s: string): int {.gensym.} = + proc parser(s: string): int {.genSym.} = # the proc to be returned var ms: array[MaxSubpatterns, (int, int)] @@ -1079,8 +1059,8 @@ template fillMatches(s, caps, c) = else: caps[k] = "" -func matchLen*(s: string, pattern: Peg, matches: var openArray[string], - start = 0): int {.rtl, extern: "npegs$1Capture".} = +proc matchLen*(s: string, pattern: Peg, matches: var openArray[string], + start = 0): int {.noSideEffect, rtl, extern: "npegs$1Capture".} = ## the same as ``match``, but it returns the length of the match, ## if there is no match, -1 is returned. Note that a match length ## of zero can happen. It's possible that a suffix of `s` remains @@ -1090,8 +1070,8 @@ func matchLen*(s: string, pattern: Peg, matches: var openArray[string], result = rawMatch(s, pattern, start, c) if result >= 0: fillMatches(s, matches, c) -func matchLen*(s: string, pattern: Peg, - start = 0): int {.rtl, extern: "npegs$1".} = +proc matchLen*(s: string, pattern: Peg, + start = 0): int {.noSideEffect, rtl, extern: "npegs$1".} = ## the same as ``match``, but it returns the length of the match, ## if there is no match, -1 is returned. Note that a match length ## of zero can happen. It's possible that a suffix of `s` remains @@ -1100,22 +1080,22 @@ func matchLen*(s: string, pattern: Peg, c.origStart = start result = rawMatch(s, pattern, start, c) -func match*(s: string, pattern: Peg, matches: var openArray[string], - start = 0): bool {.rtl, extern: "npegs$1Capture".} = +proc match*(s: string, pattern: Peg, matches: var openArray[string], + start = 0): bool {.noSideEffect, rtl, extern: "npegs$1Capture".} = ## returns ``true`` if ``s[start..]`` matches the ``pattern`` and ## the captured substrings in the array ``matches``. If it does not ## match, nothing is written into ``matches`` and ``false`` is ## returned. result = matchLen(s, pattern, matches, start) != -1 -func match*(s: string, pattern: Peg, - start = 0): bool {.rtl, extern: "npegs$1".} = +proc match*(s: string, pattern: Peg, + start = 0): bool {.noSideEffect, rtl, extern: "npegs$1".} = ## returns ``true`` if ``s`` matches the ``pattern`` beginning from ``start``. result = matchLen(s, pattern, start) != -1 -func find*(s: string, pattern: Peg, matches: var openArray[string], - start = 0): int {.rtl, extern: "npegs$1Capture".} = +proc find*(s: string, pattern: Peg, matches: var openArray[string], + start = 0): int {.noSideEffect, rtl, extern: "npegs$1Capture".} = ## returns the starting position of ``pattern`` in ``s`` and the captured ## substrings in the array ``matches``. If it does not match, nothing ## is written into ``matches`` and -1 is returned. @@ -1129,9 +1109,9 @@ func find*(s: string, pattern: Peg, matches: var openArray[string], return -1 # could also use the pattern here: (!P .)* P -func findBounds*(s: string, pattern: Peg, matches: var openArray[string], +proc findBounds*(s: string, pattern: Peg, matches: var openArray[string], start = 0): tuple[first, last: int] {. - rtl, extern: "npegs$1Capture".} = + noSideEffect, rtl, extern: "npegs$1Capture".} = ## returns the starting position and end position of ``pattern`` in ``s`` ## and the captured ## substrings in the array ``matches``. If it does not match, nothing @@ -1146,8 +1126,8 @@ func findBounds*(s: string, pattern: Peg, matches: var openArray[string], return (i, i+L-1) return (-1, 0) -func find*(s: string, pattern: Peg, - start = 0): int {.rtl, extern: "npegs$1".} = +proc find*(s: string, pattern: Peg, + start = 0): int {.noSideEffect, rtl, extern: "npegs$1".} = ## returns the starting position of ``pattern`` in ``s``. If it does not ## match, -1 is returned. var c: Captures @@ -1170,13 +1150,16 @@ iterator findAll*(s: string, pattern: Peg, start = 0): string = yield substr(s, i, i+L-1) inc(i, L) -func findAll*(s: string, pattern: Peg, start = 0): seq[string] {. - rtl, extern: "npegs$1".} = +proc findAll*(s: string, pattern: Peg, start = 0): seq[string] {. + noSideEffect, rtl, extern: "npegs$1".} = ## returns all matching *substrings* of `s` that match `pattern`. - ## If it does not match, `@[]` is returned. + ## If it does not match, @[] is returned. result = @[] for it in findAll(s, pattern, start): result.add it +when not defined(nimhygiene): + {.pragma: inject.} + template `=~`*(s: string, pattern: Peg): bool = ## This calls ``match`` with an implicit declared ``matches`` array that ## can be used in the scope of the ``=~`` call: @@ -1202,31 +1185,31 @@ template `=~`*(s: string, pattern: Peg): bool = # ------------------------- more string handling ------------------------------ -func contains*(s: string, pattern: Peg, start = 0): bool {. - rtl, extern: "npegs$1".} = +proc contains*(s: string, pattern: Peg, start = 0): bool {. + noSideEffect, rtl, extern: "npegs$1".} = ## same as ``find(s, pattern, start) >= 0`` return find(s, pattern, start) >= 0 -func contains*(s: string, pattern: Peg, matches: var openArray[string], - start = 0): bool {.rtl, extern: "npegs$1Capture".} = +proc contains*(s: string, pattern: Peg, matches: var openArray[string], + start = 0): bool {.noSideEffect, rtl, extern: "npegs$1Capture".} = ## same as ``find(s, pattern, matches, start) >= 0`` return find(s, pattern, matches, start) >= 0 -func startsWith*(s: string, prefix: Peg, start = 0): bool {. - rtl, extern: "npegs$1".} = +proc startsWith*(s: string, prefix: Peg, start = 0): bool {. + noSideEffect, rtl, extern: "npegs$1".} = ## returns true if `s` starts with the pattern `prefix` result = matchLen(s, prefix, start) >= 0 -func endsWith*(s: string, suffix: Peg, start = 0): bool {. - rtl, extern: "npegs$1".} = +proc endsWith*(s: string, suffix: Peg, start = 0): bool {. + noSideEffect, rtl, extern: "npegs$1".} = ## returns true if `s` ends with the pattern `suffix` var c: Captures c.origStart = start for i in start .. s.len-1: if rawMatch(s, suffix, i, c) == s.len - i: return true -func replacef*(s: string, sub: Peg, by: string): string {. - rtl, extern: "npegs$1".} = +proc replacef*(s: string, sub: Peg, by: string): string {. + noSideEffect, rtl, extern: "npegs$1".} = ## Replaces `sub` in `s` by the string `by`. Captures can be accessed in `by` ## with the notation ``$i`` and ``$#`` (see strutils.`%`). Examples: ## @@ -1254,8 +1237,8 @@ func replacef*(s: string, sub: Peg, by: string): string {. inc(i, x) add(result, substr(s, i)) -func replace*(s: string, sub: Peg, by = ""): string {. - rtl, extern: "npegs$1".} = +proc replace*(s: string, sub: Peg, by = ""): string {. + noSideEffect, rtl, extern: "npegs$1".} = ## Replaces `sub` in `s` by the string `by`. Captures cannot be accessed ## in `by`. result = "" @@ -1271,9 +1254,9 @@ func replace*(s: string, sub: Peg, by = ""): string {. inc(i, x) add(result, substr(s, i)) -func parallelReplace*(s: string, subs: varargs[ +proc parallelReplace*(s: string, subs: varargs[ tuple[pattern: Peg, repl: string]]): string {. - rtl, extern: "npegs$1".} = + noSideEffect, rtl, extern: "npegs$1".} = ## Returns a modified copy of `s` with the substitutions in `subs` ## applied in parallel. result = "" @@ -1295,19 +1278,16 @@ func parallelReplace*(s: string, subs: varargs[ # copy the rest: add(result, substr(s, i)) -when not defined(nimHasEffectsOf): - {.pragma: effectsOf.} - -func replace*(s: string, sub: Peg, cb: proc( +proc replace*(s: string, sub: Peg, cb: proc( match: int, cnt: int, caps: openArray[string]): string): string {. - rtl, extern: "npegs$1cb", effectsOf: cb.} = + rtl, extern: "npegs$1cb".} = ## Replaces `sub` in `s` by the resulting strings from the callback. ## The callback proc receives the index of the current match (starting with 0), ## the count of captures and an open array with the captures of each match. Examples: ## ## .. code-block:: nim ## - ## func handleMatches*(m: int, n: int, c: openArray[string]): string = + ## proc handleMatches*(m: int, n: int, c: openArray[string]): string = ## result = "" ## if m > 0: ## result.add ", " @@ -1351,7 +1331,7 @@ when not defined(js): ## error occurs. This is supposed to be used for quick scripting. ## ## **Note**: this proc does not exist while using the JS backend. - var x = readFile(infile) + var x = readFile(infile).string writeFile(outfile, x.parallelReplace(subs)) @@ -1390,8 +1370,8 @@ iterator split*(s: string, sep: Peg): string = if first < last: yield substr(s, first, last-1) -func split*(s: string, sep: Peg): seq[string] {. - rtl, extern: "npegs$1".} = +proc split*(s: string, sep: Peg): seq[string] {. + noSideEffect, rtl, extern: "npegs$1".} = ## Splits the string `s` into substrings. result = @[] for it in split(s, sep): result.add it @@ -1417,7 +1397,6 @@ type tkCurlyLe, ## '{' tkCurlyRi, ## '}' tkCurlyAt, ## '{@}' - tkEmptyCurl, ## '{}' tkArrow, ## '<-' tkBar, ## '/' tkStar, ## '*' @@ -1441,7 +1420,7 @@ type PegLexer {.inheritable.} = object ## the lexer object. bufpos: int ## the current position within the buffer - buf: string ## the buffer itself + buf: cstring ## the buffer itself lineNumber: int ## the current line number lineStart: int ## index of last line start in buffer colOffset: int ## column to add @@ -1450,25 +1429,25 @@ type const tokKindToStr: array[TokKind, string] = [ "invalid", "[EOF]", ".", "_", "identifier", "string literal", - "character set", "(", ")", "{", "}", "{@}", "{}", + "character set", "(", ")", "{", "}", "{@}", "<-", "/", "*", "+", "&", "!", "?", "@", "built-in", "escaped", "$", "$", "^" ] -func handleCR(L: var PegLexer, pos: int): int = +proc handleCR(L: var PegLexer, pos: int): int = assert(L.buf[pos] == '\c') inc(L.lineNumber) result = pos+1 if result < L.buf.len and L.buf[result] == '\L': inc(result) L.lineStart = result -func handleLF(L: var PegLexer, pos: int): int = +proc handleLF(L: var PegLexer, pos: int): int = assert(L.buf[pos] == '\L') inc(L.lineNumber) result = pos+1 L.lineStart = result -func init(L: var PegLexer, input, filename: string, line = 1, col = 0) = +proc init(L: var PegLexer, input, filename: string, line = 1, col = 0) = L.buf = input L.bufpos = 0 L.lineNumber = line @@ -1476,22 +1455,32 @@ func init(L: var PegLexer, input, filename: string, line = 1, col = 0) = L.lineStart = 0 L.filename = filename -func getColumn(L: PegLexer): int {.inline.} = +proc getColumn(L: PegLexer): int {.inline.} = result = abs(L.bufpos - L.lineStart) + L.colOffset -func getLine(L: PegLexer): int {.inline.} = +proc getLine(L: PegLexer): int {.inline.} = result = L.lineNumber -func errorStr(L: PegLexer, msg: string, line = -1, col = -1): string = +proc errorStr(L: PegLexer, msg: string, line = -1, col = -1): string = var line = if line < 0: getLine(L) else: line var col = if col < 0: getColumn(L) else: col result = "$1($2, $3) Error: $4" % [L.filename, $line, $col, msg] -func getEscapedChar(c: var PegLexer, tok: var Token) = +proc handleHexChar(c: var PegLexer, xi: var int) = + case c.buf[c.bufpos] + of '0'..'9': + xi = (xi shl 4) or (ord(c.buf[c.bufpos]) - ord('0')) + inc(c.bufpos) + of 'a'..'f': + xi = (xi shl 4) or (ord(c.buf[c.bufpos]) - ord('a') + 10) + inc(c.bufpos) + of 'A'..'F': + xi = (xi shl 4) or (ord(c.buf[c.bufpos]) - ord('A') + 10) + inc(c.bufpos) + else: discard + +proc getEscapedChar(c: var PegLexer, tok: var Token) = inc(c.bufpos) - if c.bufpos >= len(c.buf): - tok.kind = tkInvalid - return case c.buf[c.bufpos] of 'r', 'R', 'c', 'C': add(tok.literal, '\c') @@ -1519,21 +1508,16 @@ func getEscapedChar(c: var PegLexer, tok: var Token) = inc(c.bufpos) of 'x', 'X': inc(c.bufpos) - if c.bufpos >= len(c.buf): - tok.kind = tkInvalid - return var xi = 0 - if handleHexChar(c.buf[c.bufpos], xi): - inc(c.bufpos) - if handleHexChar(c.buf[c.bufpos], xi): - inc(c.bufpos) + handleHexChar(c, xi) + handleHexChar(c, xi) if xi == 0: tok.kind = tkInvalid else: add(tok.literal, chr(xi)) of '0'..'9': var val = ord(c.buf[c.bufpos]) - ord('0') inc(c.bufpos) var i = 1 - while (c.bufpos < len(c.buf)) and (i <= 3) and (c.buf[c.bufpos] in {'0'..'9'}): + while (i <= 3) and (c.buf[c.bufpos] in {'0'..'9'}): val = val * 10 + ord(c.buf[c.bufpos]) - ord('0') inc(c.bufpos) inc(i) @@ -1547,7 +1531,7 @@ func getEscapedChar(c: var PegLexer, tok: var Token) = add(tok.literal, c.buf[c.bufpos]) inc(c.bufpos) -func skip(c: var PegLexer) = +proc skip(c: var PegLexer) = var pos = c.bufpos while pos < c.buf.len: case c.buf[pos] @@ -1564,7 +1548,7 @@ func skip(c: var PegLexer) = break # EndOfFile also leaves the loop c.bufpos = pos -func getString(c: var PegLexer, tok: var Token) = +proc getString(c: var PegLexer, tok: var Token) = tok.kind = tkStringLit var pos = c.bufpos + 1 var quote = c.buf[pos-1] @@ -1585,84 +1569,75 @@ func getString(c: var PegLexer, tok: var Token) = inc(pos) c.bufpos = pos -func getDollar(c: var PegLexer, tok: var Token) = +proc getDollar(c: var PegLexer, tok: var Token) = var pos = c.bufpos + 1 - var neg = false - if pos < c.buf.len and c.buf[pos] == '^': - neg = true - inc(pos) - if pos < c.buf.len and c.buf[pos] in {'0'..'9'}: + if c.buf[pos] in {'0'..'9'}: tok.kind = tkBackref tok.index = 0 while pos < c.buf.len and c.buf[pos] in {'0'..'9'}: tok.index = tok.index * 10 + ord(c.buf[pos]) - ord('0') inc(pos) - if neg: - tok.index = -tok.index else: - if neg: - dec(pos) tok.kind = tkDollar c.bufpos = pos -func getCharSet(c: var PegLexer, tok: var Token) = +proc getCharSet(c: var PegLexer, tok: var Token) = tok.kind = tkCharSet tok.charset = {} var pos = c.bufpos + 1 var caret = false - if pos < c.buf.len: - if c.buf[pos] == '^': + if c.buf[pos] == '^': + inc(pos) + caret = true + while pos < c.buf.len: + var ch: char + case c.buf[pos] + of ']': + if pos < c.buf.len: inc(pos) + break + of '\\': + c.bufpos = pos + getEscapedChar(c, tok) + pos = c.bufpos + ch = tok.literal[tok.literal.len-1] + of '\C', '\L', '\0': + tok.kind = tkInvalid + break + else: + ch = c.buf[pos] inc(pos) - caret = true - while pos < c.buf.len: - var ch: char - case c.buf[pos] - of ']': - if pos < c.buf.len: inc(pos) - break - of '\\': - c.bufpos = pos - getEscapedChar(c, tok) - pos = c.bufpos - ch = tok.literal[tok.literal.len-1] - of '\C', '\L', '\0': - tok.kind = tkInvalid - break - else: - ch = c.buf[pos] + incl(tok.charset, ch) + if c.buf[pos] == '-': + if pos+1 < c.buf.len and c.buf[pos+1] == ']': + incl(tok.charset, '-') inc(pos) - incl(tok.charset, ch) - if c.buf[pos] == '-': - if pos+1 < c.buf.len and c.buf[pos+1] == ']': - incl(tok.charset, '-') + else: + if pos+1 < c.buf.len: inc(pos) + else: + break + var ch2: char + case c.buf[pos] + of '\\': + c.bufpos = pos + getEscapedChar(c, tok) + pos = c.bufpos + ch2 = tok.literal[tok.literal.len-1] + of '\C', '\L', '\0': + tok.kind = tkInvalid + break else: if pos+1 < c.buf.len: + ch2 = c.buf[pos] inc(pos) else: break - var ch2: char - case c.buf[pos] - of '\\': - c.bufpos = pos - getEscapedChar(c, tok) - pos = c.bufpos - ch2 = tok.literal[tok.literal.len-1] - of '\C', '\L', '\0': - tok.kind = tkInvalid - break - else: - if pos+1 < c.buf.len: - ch2 = c.buf[pos] - inc(pos) - else: - break - for i in ord(ch)+1 .. ord(ch2): - incl(tok.charset, chr(i)) + for i in ord(ch)+1 .. ord(ch2): + incl(tok.charset, chr(i)) c.bufpos = pos if caret: tok.charset = {'\1'..'\xFF'} - tok.charset -func getSymbol(c: var PegLexer, tok: var Token) = +proc getSymbol(c: var PegLexer, tok: var Token) = var pos = c.bufpos while pos < c.buf.len: add(tok.literal, c.buf[pos]) @@ -1671,7 +1646,7 @@ func getSymbol(c: var PegLexer, tok: var Token) = c.bufpos = pos tok.kind = tkIdentifier -func getBuiltin(c: var PegLexer, tok: var Token) = +proc getBuiltin(c: var PegLexer, tok: var Token) = if c.bufpos+1 < c.buf.len and c.buf[c.bufpos+1] in strutils.Letters: inc(c.bufpos) getSymbol(c, tok) @@ -1680,19 +1655,12 @@ func getBuiltin(c: var PegLexer, tok: var Token) = tok.kind = tkEscaped getEscapedChar(c, tok) # may set tok.kind to tkInvalid -func getTok(c: var PegLexer, tok: var Token) = +proc getTok(c: var PegLexer, tok: var Token) = tok.kind = tkInvalid tok.modifier = modNone setLen(tok.literal, 0) skip(c) - if c.bufpos >= c.buf.len: - tok.kind = tkEof - tok.literal = "[EOF]" - add(tok.literal, '\0') - inc(c.bufpos) - return - case c.buf[c.bufpos] of '{': inc(c.bufpos) @@ -1701,10 +1669,6 @@ func getTok(c: var PegLexer, tok: var Token) = tok.kind = tkCurlyAt inc(c.bufpos, 2) add(tok.literal, "{@}") - elif c.buf[c.bufpos] == '}' and c.bufpos < c.buf.len: - tok.kind = tkEmptyCurl - inc(c.bufpos) - add(tok.literal, "{}") else: tok.kind = tkCurlyLe add(tok.literal, '{') @@ -1736,11 +1700,9 @@ func getTok(c: var PegLexer, tok: var Token) = of '$': getDollar(c, tok) of 'a'..'z', 'A'..'Z', '\128'..'\255': getSymbol(c, tok) - if c.bufpos >= c.buf.len: - return if c.buf[c.bufpos] in {'\'', '"'} or c.buf[c.bufpos] == '$' and c.bufpos+1 < c.buf.len and - c.buf[c.bufpos+1] in {'^', '0'..'9'}: + c.buf[c.bufpos+1] in {'0'..'9'}: case tok.literal of "i": tok.modifier = modIgnoreCase of "y": tok.modifier = modIgnoreStyle @@ -1802,13 +1764,11 @@ func getTok(c: var PegLexer, tok: var Token) = add(tok.literal, c.buf[c.bufpos]) inc(c.bufpos) -func arrowIsNextTok(c: PegLexer): bool = +proc arrowIsNextTok(c: PegLexer): bool = # the only look ahead we need var pos = c.bufpos while pos < c.buf.len and c.buf[pos] in {'\t', ' '}: inc(pos) - if pos+1 >= c.buf.len: - return - result = c.buf[pos] == '<' and c.buf[pos+1] == '-' + result = c.buf[pos] == '<' and (pos+1 < c.buf.len) and c.buf[pos+1] == '-' # ----------------------------- parser ---------------------------------------- @@ -1823,21 +1783,23 @@ type identIsVerbatim: bool skip: Peg -func pegError(p: PegParser, msg: string, line = -1, col = -1) = - var e = (ref EInvalidPeg)(msg: errorStr(p, msg, line, col)) +proc pegError(p: PegParser, msg: string, line = -1, col = -1) = + var e: ref EInvalidPeg + new(e) + e.msg = errorStr(p, msg, line, col) raise e -func getTok(p: var PegParser) = +proc getTok(p: var PegParser) = getTok(p, p.tok) if p.tok.kind == tkInvalid: pegError(p, "'" & p.tok.literal & "' is invalid token") -func eat(p: var PegParser, kind: TokKind) = +proc eat(p: var PegParser, kind: TokKind) = if p.tok.kind == kind: getTok(p) else: pegError(p, tokKindToStr[kind] & " expected") -func parseExpr(p: var PegParser): Peg {.gcsafe.} +proc parseExpr(p: var PegParser): Peg {.gcsafe.} -func getNonTerminal(p: var PegParser, name: string): NonTerminal = +proc getNonTerminal(p: var PegParser, name: string): NonTerminal = for i in 0..high(p.nonterms): result = p.nonterms[i] if cmpIgnoreStyle(result.name, name) == 0: return @@ -1845,22 +1807,19 @@ func getNonTerminal(p: var PegParser, name: string): NonTerminal = result = newNonTerminal(name, getLine(p), getColumn(p)) add(p.nonterms, result) -func modifiedTerm(s: string, m: Modifier): Peg = +proc modifiedTerm(s: string, m: Modifier): Peg = case m of modNone, modVerbatim: result = term(s) of modIgnoreCase: result = termIgnoreCase(s) of modIgnoreStyle: result = termIgnoreStyle(s) -func modifiedBackref(s: int, m: Modifier): Peg = - var - reverse = s < 0 - index = if reverse: -s else: s +proc modifiedBackref(s: int, m: Modifier): Peg = case m - of modNone, modVerbatim: result = backref(index, reverse) - of modIgnoreCase: result = backrefIgnoreCase(index, reverse) - of modIgnoreStyle: result = backrefIgnoreStyle(index, reverse) + of modNone, modVerbatim: result = backref(s) + of modIgnoreCase: result = backrefIgnoreCase(s) + of modIgnoreStyle: result = backrefIgnoreStyle(s) -func builtin(p: var PegParser): Peg = +proc builtin(p: var PegParser): Peg = # do not use "y", "skip" or "i" as these would be ambiguous case p.tok.literal of "n": result = newLine() @@ -1880,11 +1839,11 @@ func builtin(p: var PegParser): Peg = of "white": result = unicodeWhitespace() else: pegError(p, "unknown built-in: " & p.tok.literal) -func token(terminal: Peg, p: PegParser): Peg = +proc token(terminal: Peg, p: PegParser): Peg = if p.skip.kind == pkEmpty: result = terminal else: result = sequence(p.skip, terminal) -func primary(p: var PegParser): Peg = +proc primary(p: var PegParser): Peg = case p.tok.kind of tkAmp: getTok(p) @@ -1908,8 +1867,7 @@ func primary(p: var PegParser): Peg = getTok(p) elif not arrowIsNextTok(p): var nt = getNonTerminal(p, p.tok.literal) - {.cast(noSideEffect).}: - incl(nt.flags, ntUsed) + incl(nt.flags, ntUsed) result = nonterminal(nt).token(p) getTok(p) else: @@ -1933,9 +1891,6 @@ func primary(p: var PegParser): Peg = result = capture(parseExpr(p)).token(p) eat(p, tkCurlyRi) inc(p.captures) - of tkEmptyCurl: - result = capture() - getTok(p) of tkAny: result = any().token(p) getTok(p) @@ -1955,11 +1910,11 @@ func primary(p: var PegParser): Peg = result = startAnchor() getTok(p) of tkBackref: - if abs(p.tok.index) > p.captures or p.tok.index == 0: - pegError(p, "invalid back reference index: " & $p.tok.index) var m = p.tok.modifier if m == modNone: m = p.modifier result = modifiedBackref(p.tok.index, m).token(p) + if p.tok.index < 0 or p.tok.index > p.captures: + pegError(p, "invalid back reference index: " & $p.tok.index) getTok(p) else: pegError(p, "expression expected, but found: " & p.tok.literal) @@ -1977,13 +1932,13 @@ func primary(p: var PegParser): Peg = getTok(p) else: break -func seqExpr(p: var PegParser): Peg = +proc seqExpr(p: var PegParser): Peg = result = primary(p) while true: case p.tok.kind of tkAmp, tkNot, tkAt, tkStringLit, tkCharSet, tkParLe, tkCurlyLe, tkAny, tkAnyRune, tkBuiltin, tkEscaped, tkDollar, tkBackref, - tkHat, tkCurlyAt, tkEmptyCurl: + tkHat, tkCurlyAt: result = sequence(result, primary(p)) of tkIdentifier: if not arrowIsNextTok(p): @@ -1991,29 +1946,27 @@ func seqExpr(p: var PegParser): Peg = else: break else: break -func parseExpr(p: var PegParser): Peg = +proc parseExpr(p: var PegParser): Peg = result = seqExpr(p) while p.tok.kind == tkBar: getTok(p) result = result / seqExpr(p) -func parseRule(p: var PegParser): NonTerminal = +proc parseRule(p: var PegParser): NonTerminal = if p.tok.kind == tkIdentifier and arrowIsNextTok(p): result = getNonTerminal(p, p.tok.literal) if ntDeclared in result.flags: pegError(p, "attempt to redefine: " & result.name) - {.cast(noSideEffect).}: - result.line = getLine(p) - result.col = getColumn(p) + result.line = getLine(p) + result.col = getColumn(p) getTok(p) eat(p, tkArrow) - {.cast(noSideEffect).}: - result.rule = parseExpr(p) - incl(result.flags, ntDeclared) # NOW inlining may be attempted + result.rule = parseExpr(p) + incl(result.flags, ntDeclared) # NOW inlining may be attempted else: pegError(p, "rule expected, but found: " & p.tok.literal) -func rawParse(p: var PegParser): Peg = +proc rawParse(p: var PegParser): Peg = ## parses a rule or a PEG expression while p.tok.kind == tkBuiltin: case p.tok.literal @@ -2043,7 +1996,7 @@ func rawParse(p: var PegParser): Peg = elif ntUsed notin nt.flags and i > 0: pegError(p, "unused rule: " & nt.name, nt.line, nt.col) -func parsePeg*(pattern: string, filename = "pattern", line = 1, col = 0): Peg = +proc parsePeg*(pattern: string, filename = "pattern", line = 1, col = 0): Peg = ## constructs a Peg object from `pattern`. `filename`, `line`, `col` are ## used for error messages, but they only provide start offsets. `parsePeg` ## keeps track of line and column numbers within `pattern`. @@ -2058,14 +2011,14 @@ func parsePeg*(pattern: string, filename = "pattern", line = 1, col = 0): Peg = getTok(p) result = rawParse(p) -func peg*(pattern: string): Peg = +proc peg*(pattern: string): Peg = ## constructs a Peg object from the `pattern`. The short name has been - ## chosen to encourage its use as a raw string modifier: + ## chosen to encourage its use as a raw string modifier:: ## - ## peg"{\ident} \s* '=' \s* {.*}" + ## peg"{\ident} \s* '=' \s* {.*}" result = parsePeg(pattern, "pattern") -func escapePeg*(s: string): string = +proc escapePeg*(s: string): string = ## escapes `s` so that it is matched verbatim when used as a peg. result = "" var inQuote = false @@ -2083,3 +2036,143 @@ func escapePeg*(s: string): string = inQuote = true result.add(c) if inQuote: result.add('\'') + +when isMainModule: + assert escapePeg("abc''def'") == r"'abc'\x27\x27'def'\x27" + assert match("(a b c)", peg"'(' @ ')'") + assert match("W_HI_Le", peg"\y 'while'") + assert(not match("W_HI_L", peg"\y 'while'")) + assert(not match("W_HI_Le", peg"\y v'while'")) + assert match("W_HI_Le", peg"y'while'") + + assert($ +digits == $peg"\d+") + assert "0158787".match(peg"\d+") + assert "ABC 0232".match(peg"\w+\s+\d+") + assert "ABC".match(peg"\d+ / \w+") + + var accum: seq[string] = @[] + for word in split("00232this02939is39an22example111", peg"\d+"): + accum.add(word) + assert(accum == @["this", "is", "an", "example"]) + + assert matchLen("key", ident) == 3 + + var pattern = sequence(ident, *whitespace, term('='), *whitespace, ident) + assert matchLen("key1= cal9", pattern) == 11 + + var ws = newNonTerminal("ws", 1, 1) + ws.rule = *whitespace + + var expr = newNonTerminal("expr", 1, 1) + expr.rule = sequence(capture(ident), *sequence( + nonterminal(ws), term('+'), nonterminal(ws), nonterminal(expr))) + + var c: Captures + var s = "a+b + c +d+e+f" + assert rawMatch(s, expr.rule, 0, c) == len(s) + var a = "" + for i in 0..c.ml-1: + a.add(substr(s, c.matches[i][0], c.matches[i][1])) + assert a == "abcdef" + #echo expr.rule + + #const filename = "lib/devel/peg/grammar.txt" + #var grammar = parsePeg(newFileStream(filename, fmRead), filename) + #echo "a <- [abc]*?".match(grammar) + assert find("_____abc_______", term("abc"), 2) == 5 + assert match("_______ana", peg"A <- 'ana' / . A") + assert match("abcs%%%", peg"A <- ..A / .A / '%'") + + var matches: array[0..MaxSubpatterns-1, string] + if "abc" =~ peg"{'a'}'bc' 'xyz' / {\ident}": + assert matches[0] == "abc" + else: + assert false + + var g2 = peg"""S <- A B / C D + A <- 'a'+ + B <- 'b'+ + C <- 'c'+ + D <- 'd'+ + """ + assert($g2 == "((A B) / (C D))") + assert match("cccccdddddd", g2) + assert("var1=key; var2=key2".replacef(peg"{\ident}'='{\ident}", "$1<-$2$2") == + "var1<-keykey; var2<-key2key2") + assert("var1=key; var2=key2".replace(peg"{\ident}'='{\ident}", "$1<-$2$2") == + "$1<-$2$2; $1<-$2$2") + assert "var1=key; var2=key2".endsWith(peg"{\ident}'='{\ident}") + + if "aaaaaa" =~ peg"'aa' !. / ({'a'})+": + assert matches[0] == "a" + else: + assert false + + if match("abcdefg", peg"c {d} ef {g}", matches, 2): + assert matches[0] == "d" + assert matches[1] == "g" + else: + assert false + + accum = @[] + for x in findAll("abcdef", peg".", 3): + accum.add(x) + assert(accum == @["d", "e", "f"]) + + for x in findAll("abcdef", peg"^{.}", 3): + assert x == "d" + + if "f(a, b)" =~ peg"{[0-9]+} / ({\ident} '(' {@} ')')": + assert matches[0] == "f" + assert matches[1] == "a, b" + else: + assert false + + assert match("eine übersicht und außerdem", peg"(\letter \white*)+") + # ß is not a lower cased letter?! + assert match("eine übersicht und auerdem", peg"(\lower \white*)+") + assert match("EINE ÜBERSICHT UND AUSSERDEM", peg"(\upper \white*)+") + assert(not match("456678", peg"(\letter)+")) + + assert("var1 = key; var2 = key2".replacef( + peg"\skip(\s*) {\ident}'='{\ident}", "$1<-$2$2") == + "var1<-keykey;var2<-key2key2") + + assert match("prefix/start", peg"^start$", 7) + + if "foo" =~ peg"{'a'}?.*": + assert matches[0].len == 0 + else: assert false + + if "foo" =~ peg"{''}.*": + assert matches[0] == "" + else: assert false + + if "foo" =~ peg"{'foo'}": + assert matches[0] == "foo" + else: assert false + + let empty_test = peg"^\d*" + let str = "XYZ" + + assert(str.find(empty_test) == 0) + assert(str.match(empty_test)) + + proc handleMatches*(m: int, n: int, c: openArray[string]): string = + result = "" + + if m > 0: + result.add ", " + + result.add case n: + of 2: toLowerAscii(c[0]) & ": '" & c[1] & "'" + of 1: toLowerAscii(c[0]) & ": ''" + else: "" + + assert("Var1=key1;var2=Key2; VAR3". + replace(peg"{\ident}('='{\ident})* ';'* \s*", + handleMatches) == "var1: 'key1', var2: 'Key2', var3: ''") + + + doAssert "test1".match(peg"""{@}$""") + doAssert "test2".match(peg"""{(!$ .)*} $""") diff --git a/lib/pure/prelude.nim b/lib/pure/prelude.nim deleted file mode 100644 index 9428f29eb..000000000 --- a/lib/pure/prelude.nim +++ /dev/null @@ -1,28 +0,0 @@ -# -# -# Nim's Runtime Library -# (c) Copyright 2012 Andreas Rumpf -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# - -when defined(nimdoc) and isMainModule: - from std/compileSettings import nil - when compileSettings.querySetting(compileSettings.SingleValueSetting.projectFull) == currentSourcePath: - ## This is an include file that simply imports common modules for your convenience. - runnableExamples: - include std/prelude - # same as: - # import std/[os, strutils, times, parseutils, hashes, tables, sets, sequtils, parseopt, strformat] - let x = 1 - assert "foo $# $#" % [$x, "bar"] == "foo 1 bar" - assert toSeq(1..3) == @[1, 2, 3] - when not defined(js) or defined(nodejs): - assert getCurrentDir().len > 0 - assert ($now()).startsWith "20" - - # xxx `nim doc -b:js -d:nodejs --doccmd:-d:nodejs lib/pure/prelude.nim` fails for some reason - # specific to `nim doc`, but the code otherwise works with nodejs. - -import std/[os, strutils, times, parseutils, hashes, tables, sets, sequtils, parseopt, strformat] diff --git a/lib/pure/punycode.nim b/lib/pure/punycode.nim new file mode 100644 index 000000000..ce80a37fa --- /dev/null +++ b/lib/pure/punycode.nim @@ -0,0 +1,177 @@ +# +# +# Nim's Runtime Library +# (c) Copyright 2016 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +## Implements a representation of Unicode with the limited +## ASCII character subset. + +import strutils +import unicode + +# issue #3045 + +const + Base = 36 + TMin = 1 + TMax = 26 + Skew = 38 + Damp = 700 + InitialBias = 72 + InitialN = 128 + Delimiter = '-' + +type + PunyError* = object of ValueError + +proc decodeDigit(x: char): int {.raises: [PunyError].} = + if '0' <= x and x <= '9': + result = ord(x) - (ord('0') - 26) + elif 'A' <= x and x <= 'Z': + result = ord(x) - ord('A') + elif 'a' <= x and x <= 'z': + result = ord(x) - ord('a') + else: + raise newException(PunyError, "Bad input") + +proc encodeDigit(digit: int): Rune {.raises: [PunyError].} = + if 0 <= digit and digit < 26: + result = Rune(digit + ord('a')) + elif 26 <= digit and digit < 36: + result = Rune(digit + (ord('0') - 26)) + else: + raise newException(PunyError, "internal error in punycode encoding") + +proc isBasic(c: char): bool = ord(c) < 0x80 +proc isBasic(r: Rune): bool = int(r) < 0x80 + +proc adapt(delta, numPoints: int, first: bool): int = + var d = if first: delta div Damp else: delta div 2 + d += d div numPoints + var k = 0 + while d > ((Base-TMin)*TMax) div 2: + d = d div (Base - TMin) + k += Base + result = k + (Base - TMin + 1) * d div (d + Skew) + +proc encode*(prefix, s: string): string {.raises: [PunyError].} = + ## Encode a string that may contain Unicode. + ## Prepend `prefix` to the result + result = prefix + var (d, n, bias) = (0, InitialN, InitialBias) + var (b, remaining) = (0, 0) + for r in s.runes: + if r.isBasic: + # basic Ascii character + inc b + result.add($r) + else: + # special character + inc remaining + + var h = b + if b > 0: + result.add(Delimiter) # we have some Ascii chars + while remaining != 0: + var m: int = high(int32) + for r in s.runes: + if m > int(r) and int(r) >= n: + m = int(r) + d += (m - n) * (h + 1) + if d < 0: + raise newException(PunyError, "invalid label " & s) + n = m + for r in s.runes: + if int(r) < n: + inc d + if d < 0: + raise newException(PunyError, "invalid label " & s) + continue + if int(r) > n: + continue + var q = d + var k = Base + while true: + var t = k - bias + if t < TMin: + t = TMin + elif t > TMax: + t = TMax + if q < t: + break + result.add($encodeDigit(t + (q - t) mod (Base - t))) + q = (q - t) div (Base - t) + k += Base + result.add($encodeDigit(q)) + bias = adapt(d, h + 1, h == b) + d = 0 + inc h + dec remaining + inc d + inc n + +proc encode*(s: string): string {.raises: [PunyError].} = + ## Encode a string that may contain Unicode. Prefix is empty. + result = encode("", s) + +proc decode*(encoded: string): string {.raises: [PunyError].} = + ## Decode a Punycode-encoded string + var + n = InitialN + i = 0 + bias = InitialBias + var d = rfind(encoded, Delimiter) + result = "" + + if d > 0: + # found Delimiter + for j in 0.. (high(int32) - i) div w: + raise newException(PunyError, "Too large a value: " & $digit) + i += digit * w + var t: int + if k <= bias: + t = TMin + elif k >= bias + TMax: + t = TMax + else: + t = k - bias + if digit < t: + break + w *= Base - t + k += Base + bias = adapt(i - oldi, runelen(result) + 1, oldi == 0) + + if i div (runelen(result) + 1) > high(int32) - n: + raise newException(PunyError, "Value too large") + + n += i div (runelen(result) + 1) + i = i mod (runelen(result) + 1) + insert(result, $Rune(n), i) + inc i + +when isMainModule: + assert(decode(encode("", "bücher")) == "bücher") + assert(decode(encode("münchen")) == "münchen") + assert encode("xn--", "münchen") == "xn--mnchen-3ya" diff --git a/lib/pure/random.nim b/lib/pure/random.nim index c36ab445b..1237e5d0a 100644 --- a/lib/pure/random.nim +++ b/lib/pure/random.nim @@ -7,11 +7,11 @@ # distribution, for details about the copyright. # -## Nim's standard random number generator (RNG). +## Nim's standard random number generator. ## -## Its implementation is based on the `xoroshiro128+` +## Its implementation is based on the ``xoroshiro128+`` ## (xor/rotate/shift/rotate) library. -## * More information: http://xoroshiro.di.unimi.it +## * More information: http://xoroshiro.di.unimi.it/ ## * C implementation: http://xoroshiro.di.unimi.it/xoroshiro128plus.c ## ## **Do not use this module for cryptographic purposes!** @@ -19,65 +19,68 @@ ## Basic usage ## =========== ## -runnableExamples: - # Call randomize() once to initialize the default random number generator. - # If this is not called, the same results will occur every time these - # examples are run. - randomize() - - # Pick a number in 0..100. - let num = rand(100) - doAssert num in 0..100 - - # Roll a six-sided die. - let roll = rand(1..6) - doAssert roll in 1..6 - - # Pick a marble from a bag. - let marbles = ["red", "blue", "green", "yellow", "purple"] - let pick = sample(marbles) - doAssert pick in marbles - - # Shuffle some cards. - var cards = ["Ace", "King", "Queen", "Jack", "Ten"] - shuffle(cards) - doAssert cards.len == 5 - -## These examples all use the default RNG. The -## `Rand type <#Rand>`_ represents the state of an RNG. +## To get started, here are some examples: +## +## .. code-block:: +## +## import random +## +## # Call randomize() once to initialize the default random number generator +## # If this is not called, the same results will occur every time these +## # examples are run +## randomize() +## +## # Pick a number between 0 and 100 +## let num = rand(100) +## echo num +## +## # Roll a six-sided die +## let roll = rand(1..6) +## echo roll +## +## # Pick a marble from a bag +## let marbles = ["red", "blue", "green", "yellow", "purple"] +## let pick = sample(marbles) +## echo pick +## +## # Shuffle some cards +## var cards = ["Ace", "King", "Queen", "Jack", "Ten"] +## shuffle(cards) +## echo cards +## +## These examples all use the default random number generator. The +## `Rand type<#Rand>`_ represents the state of a random number generator. ## For convenience, this module contains a default Rand state that corresponds -## to the default RNG. Most procs in this module which do +## to the default random number generator. Most procs in this module which do ## not take in a Rand parameter, including those called in the above examples, ## use the default generator. Those procs are **not** thread-safe. ## ## Note that the default generator always starts in the same state. -## The `randomize proc <#randomize>`_ can be called to initialize the default +## The `randomize proc<#randomize>`_ can be called to initialize the default ## generator with a seed based on the current time, and it only needs to be ## called once before the first usage of procs from this module. If -## `randomize` is not called, the default generator will always produce +## ``randomize`` is not called, then the default generator will always produce ## the same results. ## -## RNGs that are independent of the default one can be created with the -## `initRand proc <#initRand,int64>`_. +## Generators that are independent of the default one can be created with the +## `initRand proc<#initRand,int64>`_. ## ## Again, it is important to remember that this module must **not** be used for ## cryptographic applications. ## ## See also ## ======== -## * `std/sysrand module `_ for a cryptographically secure pseudorandom number generator -## * `math module `_ for basic math routines -## * `stats module `_ for statistical analysis -## * `list of cryptographic and hashing modules `_ +## * `math module`_ for basic math routines +## * `mersenne module`_ for the Mersenne Twister random number +## generator +## * `stats module`_ for statistical analysis +## * `list of cryptographic and hashing modules +## `_ ## in the standard library -import algorithm, math -import std/private/since +import algorithm #For upperBound -when defined(nimPreviewSlimSystem): - import std/[assertions] - -include system/inclrtl +include "system/inclrtl" {.push debugger: off.} when defined(js): @@ -92,12 +95,12 @@ else: type Rand* = object ## State of a random number generator. ## - ## Create a new Rand state using the `initRand proc <#initRand,int64>`_. + ## Create a new Rand state using the `initRand proc<#initRand,int64>`_. ## ## The module contains a default Rand state for convenience. - ## It corresponds to the default RNG's state. + ## It corresponds to the default random number generator's state. ## The default Rand state always starts with the same values, but the - ## `randomize proc <#randomize>`_ can be used to seed the default generator + ## `randomize proc<#randomize>`_ can be used to seed the default generator ## with a value based on the current time. ## ## Many procs have two variations: one that takes in a Rand parameter and @@ -110,45 +113,29 @@ when defined(js): a0: 0x69B4C98Cu32, a1: 0xFED1DD30u32) # global for backwards compatibility else: - const DefaultRandSeed = Rand( - a0: 0x69B4C98CB8530805u64, - a1: 0xFED1DD3004688D67CAu64) - # racy for multi-threading but good enough for now: - var state = DefaultRandSeed # global for backwards compatibility - -func isValid(r: Rand): bool {.inline.} = - ## Check whether state of `r` is valid. - ## - ## In `xoroshiro128+`, if all bits of `a0` and `a1` are zero, - ## they are always zero after calling `next(r: var Rand)`. - not (r.a0 == 0 and r.a1 == 0) - -since (1, 5): - template randState*(): untyped = - ## Makes the default Rand state accessible from other modules. - ## Useful for module authors. - state + var state = Rand( + a0: 0x69B4C98CB8530805u64, + a1: 0xFED1DD3004688D67CAu64) # global for backwards compatibility proc rotl(x, k: Ui): Ui = result = (x shl k) or (x shr (Ui(64) - k)) proc next*(r: var Rand): uint64 = - ## Computes a random `uint64` number using the given state. + ## Computes a random ``uint64`` number using the given state. ## - ## **See also:** + ## See also: ## * `rand proc<#rand,Rand,Natural>`_ that returns an integer between zero and ## a given upper bound ## * `rand proc<#rand,Rand,range[]>`_ that returns a float - ## * `rand proc<#rand,Rand,HSlice[T: Ordinal or float or float32 or float64,T: Ordinal or float or float32 or float64]>`_ - ## that accepts a slice + ## * `rand proc<#rand,Rand,HSlice[T,T]>`_ that accepts a slice ## * `rand proc<#rand,typedesc[T]>`_ that accepts an integer or range type ## * `skipRandomNumbers proc<#skipRandomNumbers,Rand>`_ - runnableExamples("-r:off"): + runnableExamples: var r = initRand(2019) - assert r.next() == 13223559681708962501'u64 # implementation defined - assert r.next() == 7229677234260823147'u64 # ditto - + doAssert r.next() == 138_744_656_611_299'u64 + doAssert r.next() == 979_810_537_855_049_344'u64 + doAssert r.next() == 3_628_232_584_225_300_704'u64 let s0 = r.a0 var s1 = r.a1 result = s0 + s1 @@ -159,12 +146,12 @@ proc next*(r: var Rand): uint64 = proc skipRandomNumbers*(s: var Rand) = ## The jump function for the generator. ## - ## This proc is equivalent to `2^64` calls to `next <#next,Rand>`_, and it can - ## be used to generate `2^64` non-overlapping subsequences for parallel + ## This proc is equivalent to 2^64 calls to `next<#next,Rand>`_, and it can + ## be used to generate 2^64 non-overlapping subsequences for parallel ## computations. ## ## When multiple threads are generating random numbers, each thread must - ## own the `Rand <#Rand>`_ state it is using so that the thread can safely + ## own the `Rand<#Rand>`_ state it is using so that the thread can safely ## obtain random numbers. However, if each thread creates its own Rand state, ## the subsequences of random numbers that each thread generates may overlap, ## even if the provided seeds are unique. This is more likely to happen as the @@ -175,39 +162,34 @@ proc skipRandomNumbers*(s: var Rand) = ## Rand state to a thread, call this proc before passing it to the next one. ## By using the Rand state this way, the subsequences of random numbers ## generated in each thread will never overlap as long as no thread generates - ## more than `2^64` random numbers. + ## more than 2^64 random numbers. ## - ## **See also:** + ## The following example below demonstrates this pattern: + ## + ## .. code-block:: + ## # Compile this example with --threads:on + ## import random + ## import threadpool + ## + ## const spawns = 4 + ## const numbers = 100000 + ## + ## proc randomSum(rand: Rand): int = + ## var r = rand + ## for i in 1..numbers: + ## result += rand(1..10) + ## + ## var r = initRand(2019) + ## var vals: array[spawns, FlowVar[int]] + ## for val in vals.mitems: + ## val = spawn(randomSum(r)) + ## r.skipRandomNumbers() + ## + ## for val in vals: + ## echo ^val + ## + ## See also: ## * `next proc<#next,Rand>`_ - runnableExamples("--threads:on"): - import std/random - - const numbers = 100000 - - var - thr: array[0..3, Thread[(Rand, int)]] - vals: array[0..3, int] - - proc randomSum(params: tuple[r: Rand, index: int]) {.thread.} = - var r = params.r - var s = 0 # avoid cache thrashing - for i in 1..numbers: - s += r.rand(0..10) - vals[params.index] = s - - var r = initRand(2019) - for i in 0..`_ that returns an integer using the default RNG + ## See also: + ## * `rand proc<#rand,int>`_ that returns an integer using the default + ## random number generator ## * `rand proc<#rand,Rand,range[]>`_ that returns a float - ## * `rand proc<#rand,Rand,HSlice[T: Ordinal or float or float32 or float64,T: Ordinal or float or float32 or float64]>`_ - ## that accepts a slice + ## * `rand proc<#rand,Rand,HSlice[T,T]>`_ that accepts a slice ## * `rand proc<#rand,typedesc[T]>`_ that accepts an integer or range type runnableExamples: var r = initRand(123) - if false: - assert r.rand(100) == 96 # implementation defined - # bootstrap: can't use `runnableExamples("-r:off")` - cast[int](rand(r, uint64(max))) - # xxx toUnsigned pending https://github.com/nim-lang/Nim/pull/18445 + doAssert r.rand(100) == 0 + doAssert r.rand(100) == 96 + doAssert r.rand(100) == 66 + if max == 0: return + while true: + let x = next(r) + if x <= randMax - (randMax mod Ui(max)): + return int(x mod (uint64(max)+1u64)) proc rand*(max: int): int {.benign.} = ## Returns a random integer in the range `0..max`. ## - ## If `randomize <#randomize>`_ has not been called, the sequence of random + ## If `randomize<#randomize>`_ has not been called, the sequence of random ## numbers returned from this proc will always be the same. ## - ## This proc uses the default RNG. Thus, it is **not** thread-safe. + ## This proc uses the default random number generator. Thus, it is **not** + ## thread-safe. ## - ## **See also:** + ## See also: ## * `rand proc<#rand,Rand,Natural>`_ that returns an integer using a ## provided state ## * `rand proc<#rand,float>`_ that returns a float - ## * `rand proc<#rand,HSlice[T: Ordinal or float or float32 or float64,T: Ordinal or float or float32 or float64]>`_ - ## that accepts a slice + ## * `rand proc<#rand,HSlice[T,T]>`_ that accepts a slice ## * `rand proc<#rand,typedesc[T]>`_ that accepts an integer or range type - runnableExamples("-r:off"): + runnableExamples: randomize(123) - assert [rand(100), rand(100)] == [96, 63] # implementation defined - + doAssert rand(100) == 0 + doAssert rand(100) == 96 + doAssert rand(100) == 66 rand(state, max) proc rand*(r: var Rand; max: range[0.0 .. high(float)]): float {.benign.} = ## Returns a random floating point number in the range `0.0..max` ## using the given state. ## - ## **See also:** - ## * `rand proc<#rand,float>`_ that returns a float using the default RNG + ## See also: + ## * `rand proc<#rand,float>`_ that returns a float using the default + ## random number generator ## * `rand proc<#rand,Rand,Natural>`_ that returns an integer - ## * `rand proc<#rand,Rand,HSlice[T: Ordinal or float or float32 or float64,T: Ordinal or float or float32 or float64]>`_ - ## that accepts a slice + ## * `rand proc<#rand,Rand,HSlice[T,T]>`_ that accepts a slice ## * `rand proc<#rand,typedesc[T]>`_ that accepts an integer or range type runnableExamples: var r = initRand(234) - let f = r.rand(1.0) # 8.717181376738381e-07 - + let f = r.rand(1.0) + ## f = 8.717181376738381e-07 let x = next(r) when defined(js): result = (float(x) / float(high(uint32))) * max @@ -299,22 +296,22 @@ proc rand*(r: var Rand; max: range[0.0 .. high(float)]): float {.benign.} = proc rand*(max: float): float {.benign.} = ## Returns a random floating point number in the range `0.0..max`. ## - ## If `randomize <#randomize>`_ has not been called, the sequence of random + ## If `randomize<#randomize>`_ has not been called, the sequence of random ## numbers returned from this proc will always be the same. ## - ## This proc uses the default RNG. Thus, it is **not** thread-safe. + ## This proc uses the default random number generator. Thus, it is **not** + ## thread-safe. ## - ## **See also:** + ## See also: ## * `rand proc<#rand,Rand,range[]>`_ that returns a float using a ## provided state ## * `rand proc<#rand,int>`_ that returns an integer - ## * `rand proc<#rand,HSlice[T: Ordinal or float or float32 or float64,T: Ordinal or float or float32 or float64]>`_ - ## that accepts a slice + ## * `rand proc<#rand,HSlice[T,T]>`_ that accepts a slice ## * `rand proc<#rand,typedesc[T]>`_ that accepts an integer or range type runnableExamples: randomize(234) - let f = rand(1.0) # 8.717181376738381e-07 - + let f = rand(1.0) + ## f = 8.717181376738381e-07 rand(state, max) proc rand*[T: Ordinal or SomeFloat](r: var Rand; x: HSlice[T, T]): T = @@ -323,109 +320,100 @@ proc rand*[T: Ordinal or SomeFloat](r: var Rand; x: HSlice[T, T]): T = ## ## Allowed types for `T` are integers, floats, and enums without holes. ## - ## **See also:** - ## * `rand proc<#rand,HSlice[T: Ordinal or float or float32 or float64,T: Ordinal or float or float32 or float64]>`_ - ## that accepts a slice and uses the default RNG + ## See also: + ## * `rand proc<#rand,HSlice[T,T]>`_ that accepts a slice and uses the + ## default random number generator ## * `rand proc<#rand,Rand,Natural>`_ that returns an integer ## * `rand proc<#rand,Rand,range[]>`_ that returns a float ## * `rand proc<#rand,typedesc[T]>`_ that accepts an integer or range type runnableExamples: var r = initRand(345) - assert r.rand(1..5) <= 5 - assert r.rand(-1.1 .. 1.2) >= -1.1 - assert x.a <= x.b + doAssert r.rand(1..6) == 4 + doAssert r.rand(1..6) == 4 + doAssert r.rand(1..6) == 6 + let f = r.rand(-1.0 .. 1.0) + ## f = 0.8741183448756229 when T is SomeFloat: result = rand(r, x.b - x.a) + x.a else: # Integers and Enum types - when defined(js): - result = cast[T](rand(r, cast[uint](x.b) - cast[uint](x.a)) + cast[uint](x.a)) - else: - result = cast[T](rand(r, cast[uint64](x.b) - cast[uint64](x.a)) + cast[uint64](x.a)) + result = T(rand(r, int(x.b) - int(x.a)) + int(x.a)) proc rand*[T: Ordinal or SomeFloat](x: HSlice[T, T]): T = ## For a slice `a..b`, returns a value in the range `a..b`. ## ## Allowed types for `T` are integers, floats, and enums without holes. ## - ## If `randomize <#randomize>`_ has not been called, the sequence of random + ## If `randomize<#randomize>`_ has not been called, the sequence of random ## numbers returned from this proc will always be the same. ## - ## This proc uses the default RNG. Thus, it is **not** thread-safe. + ## This proc uses the default random number generator. Thus, it is **not** + ## thread-safe. ## - ## **See also:** - ## * `rand proc<#rand,Rand,HSlice[T: Ordinal or float or float32 or float64,T: Ordinal or float or float32 or float64]>`_ - ## that accepts a slice and uses a provided state + ## See also: + ## * `rand proc<#rand,Rand,HSlice[T,T]>`_ that accepts a slice and uses + ## a provided state ## * `rand proc<#rand,int>`_ that returns an integer ## * `rand proc<#rand,float>`_ that returns a floating point number ## * `rand proc<#rand,typedesc[T]>`_ that accepts an integer or range type runnableExamples: randomize(345) - assert rand(1..6) <= 6 - + doAssert rand(1..6) == 4 + doAssert rand(1..6) == 4 + doAssert rand(1..6) == 6 result = rand(state, x) -proc rand*[T: Ordinal](r: var Rand; t: typedesc[T]): T {.since: (1, 7, 1).} = - ## Returns a random Ordinal in the range `low(T)..high(T)`. - ## - ## If `randomize <#randomize>`_ has not been called, the sequence of random - ## numbers returned from this proc will always be the same. - ## - ## **See also:** - ## * `rand proc<#rand,int>`_ that returns an integer - ## * `rand proc<#rand,float>`_ that returns a floating point number - ## * `rand proc<#rand,HSlice[T: Ordinal or float or float32 or float64,T: Ordinal or float or float32 or float64]>`_ - ## that accepts a slice - when T is range or T is enum: - result = rand(r, low(T)..high(T)) - elif T is bool: - when defined(js): - result = (r.next or 0) < 0 - else: - result = cast[int64](r.next) < 0 - else: - when defined(js): - result = cast[T](r.next shr (sizeof(uint)*8 - sizeof(T)*8)) - else: - result = cast[T](r.next shr (sizeof(uint64)*8 - sizeof(T)*8)) +proc rand*[T](r: var Rand; a: openArray[T]): T {.deprecated: + "Deprecated since v0.20.0; use 'sample' instead".} = + result = a[rand(r, a.low..a.high)] -proc rand*[T: Ordinal](t: typedesc[T]): T = - ## Returns a random Ordinal in the range `low(T)..high(T)`. +proc rand*[T: SomeInteger](t: typedesc[T]): T = + ## Returns a random integer in the range `low(T)..high(T)`. ## - ## If `randomize <#randomize>`_ has not been called, the sequence of random + ## If `randomize<#randomize>`_ has not been called, the sequence of random ## numbers returned from this proc will always be the same. ## - ## This proc uses the default RNG. Thus, it is **not** thread-safe. + ## This proc uses the default random number generator. Thus, it is **not** + ## thread-safe. ## - ## **See also:** + ## See also: ## * `rand proc<#rand,int>`_ that returns an integer ## * `rand proc<#rand,float>`_ that returns a floating point number - ## * `rand proc<#rand,HSlice[T: Ordinal or float or float32 or float64,T: Ordinal or float or float32 or float64]>`_ - ## that accepts a slice + ## * `rand proc<#rand,HSlice[T,T]>`_ that accepts a slice runnableExamples: randomize(567) - type E = enum a, b, c, d + doAssert rand(int8) == 55 + doAssert rand(int8) == -42 + doAssert rand(int8) == 43 + doAssert rand(uint32) == 578980729'u32 + doAssert rand(uint32) == 4052940463'u32 + doAssert rand(uint32) == 2163872389'u32 + doAssert rand(range[1..16]) == 11 + doAssert rand(range[1..16]) == 4 + doAssert rand(range[1..16]) == 16 + when T is range: + result = rand(state, low(T)..high(T)) + else: + result = cast[T](state.next) - assert rand(E) in a..d - assert rand(char) in low(char)..high(char) - assert rand(int8) in low(int8)..high(int8) - assert rand(uint32) in low(uint32)..high(uint32) - assert rand(range[1..16]) in 1..16 - - result = rand(state, t) +proc rand*[T](a: openArray[T]): T {.deprecated: + "Deprecated since v0.20.0; use 'sample' instead".} = + result = a[rand(a.low..a.high)] proc sample*[T](r: var Rand; s: set[T]): T = - ## Returns a random element from the set `s` using the given state. + ## Returns a random element from the set ``s`` using the given state. ## - ## **See also:** - ## * `sample proc<#sample,set[T]>`_ that uses the default RNG - ## * `sample proc<#sample,Rand,openArray[T]>`_ for `openArray`s + ## See also: + ## * `sample proc<#sample,set[T]>`_ that uses the default random number + ## generator + ## * `sample proc<#sample,Rand,openArray[T]>`_ for openarrays ## * `sample proc<#sample,Rand,openArray[T],openArray[U]>`_ that uses a ## cumulative distribution function runnableExamples: var r = initRand(987) let s = {1, 3, 5, 7, 9} - assert r.sample(s) in s - + doAssert r.sample(s) == 5 + doAssert r.sample(s) == 7 + doAssert r.sample(s) == 1 assert card(s) != 0 var i = rand(r, card(s) - 1) for e in s: @@ -433,49 +421,54 @@ proc sample*[T](r: var Rand; s: set[T]): T = dec(i) proc sample*[T](s: set[T]): T = - ## Returns a random element from the set `s`. + ## Returns a random element from the set ``s``. ## - ## If `randomize <#randomize>`_ has not been called, the order of outcomes + ## If `randomize<#randomize>`_ has not been called, the order of outcomes ## from this proc will always be the same. ## - ## This proc uses the default RNG. Thus, it is **not** thread-safe. + ## This proc uses the default random number generator. Thus, it is **not** + ## thread-safe. ## - ## **See also:** + ## See also: ## * `sample proc<#sample,Rand,set[T]>`_ that uses a provided state - ## * `sample proc<#sample,openArray[T]>`_ for `openArray`s + ## * `sample proc<#sample,openArray[T]>`_ for openarrays ## * `sample proc<#sample,openArray[T],openArray[U]>`_ that uses a ## cumulative distribution function runnableExamples: randomize(987) let s = {1, 3, 5, 7, 9} - assert sample(s) in s - + doAssert sample(s) == 5 + doAssert sample(s) == 7 + doAssert sample(s) == 1 sample(state, s) proc sample*[T](r: var Rand; a: openArray[T]): T = - ## Returns a random element from `a` using the given state. + ## Returns a random element from ``a`` using the given state. ## - ## **See also:** - ## * `sample proc<#sample,openArray[T]>`_ that uses the default RNG + ## See also: + ## * `sample proc<#sample,openArray[T]>`_ that uses the default + ## random number generator ## * `sample proc<#sample,Rand,openArray[T],openArray[U]>`_ that uses a ## cumulative distribution function ## * `sample proc<#sample,Rand,set[T]>`_ for sets runnableExamples: let marbles = ["red", "blue", "green", "yellow", "purple"] var r = initRand(456) - assert r.sample(marbles) in marbles - + doAssert r.sample(marbles) == "blue" + doAssert r.sample(marbles) == "yellow" + doAssert r.sample(marbles) == "red" result = a[r.rand(a.low..a.high)] -proc sample*[T](a: openArray[T]): lent T = - ## Returns a random element from `a`. +proc sample*[T](a: openArray[T]): T = + ## Returns a random element from ``a``. ## - ## If `randomize <#randomize>`_ has not been called, the order of outcomes + ## If `randomize<#randomize>`_ has not been called, the order of outcomes ## from this proc will always be the same. ## - ## This proc uses the default RNG. Thus, it is **not** thread-safe. + ## This proc uses the default random number generator. Thus, it is **not** + ## thread-safe. ## - ## **See also:** + ## See also: ## * `sample proc<#sample,Rand,openArray[T]>`_ that uses a provided state ## * `sample proc<#sample,openArray[T],openArray[U]>`_ that uses a ## cumulative distribution function @@ -483,160 +476,133 @@ proc sample*[T](a: openArray[T]): lent T = runnableExamples: let marbles = ["red", "blue", "green", "yellow", "purple"] randomize(456) - assert sample(marbles) in marbles - + doAssert sample(marbles) == "blue" + doAssert sample(marbles) == "yellow" + doAssert sample(marbles) == "red" result = a[rand(a.low..a.high)] proc sample*[T, U](r: var Rand; a: openArray[T]; cdf: openArray[U]): T = - ## Returns an element from `a` using a cumulative distribution function + ## Returns an element from ``a`` using a cumulative distribution function ## (CDF) and the given state. ## - ## The `cdf` argument does not have to be normalized, and it could contain - ## any type of elements that can be converted to a `float`. It must be - ## the same length as `a`. Each element in `cdf` should be greater than + ## The ``cdf`` argument does not have to be normalized, and it could contain + ## any type of elements that can be converted to a ``float``. It must be + ## the same length as ``a``. Each element in ``cdf`` should be greater than ## or equal to the previous element. ## ## The outcome of the `cumsum`_ proc and the ## return value of the `cumsummed`_ proc, - ## which are both in the math module, can be used as the `cdf` argument. + ## which are both in the math module, can be used as the ``cdf`` argument. ## - ## **See also:** + ## See also: ## * `sample proc<#sample,openArray[T],openArray[U]>`_ that also utilizes - ## a CDF but uses the default RNG + ## a CDF but uses the default random number generator ## * `sample proc<#sample,Rand,openArray[T]>`_ that does not use a CDF ## * `sample proc<#sample,Rand,set[T]>`_ for sets runnableExamples: - from std/math import cumsummed + from math import cumsummed let marbles = ["red", "blue", "green", "yellow", "purple"] let count = [1, 6, 8, 3, 4] let cdf = count.cumsummed var r = initRand(789) - assert r.sample(marbles, cdf) in marbles - + doAssert r.sample(marbles, cdf) == "red" + doAssert r.sample(marbles, cdf) == "green" + doAssert r.sample(marbles, cdf) == "blue" assert(cdf.len == a.len) # Two basic sanity checks. assert(float(cdf[^1]) > 0.0) - # While we could check cdf[i-1] <= cdf[i] for i in 1..cdf.len, that could get - # awfully expensive even in debugging modes. + #While we could check cdf[i-1] <= cdf[i] for i in 1..cdf.len, that could get + #awfully expensive even in debugging modes. let u = r.rand(float(cdf[^1])) a[cdf.upperBound(U(u))] proc sample*[T, U](a: openArray[T]; cdf: openArray[U]): T = - ## Returns an element from `a` using a cumulative distribution function + ## Returns an element from ``a`` using a cumulative distribution function ## (CDF). ## ## This proc works similarly to - ## `sample <#sample,Rand,openArray[T],openArray[U]>`_. + ## `sample[T, U](Rand, openArray[T], openArray[U]) + ## <#sample,Rand,openArray[T],openArray[U]>`_. ## See that proc's documentation for more details. ## - ## If `randomize <#randomize>`_ has not been called, the order of outcomes + ## If `randomize<#randomize>`_ has not been called, the order of outcomes ## from this proc will always be the same. ## - ## This proc uses the default RNG. Thus, it is **not** thread-safe. + ## This proc uses the default random number generator. Thus, it is **not** + ## thread-safe. ## - ## **See also:** + ## See also: ## * `sample proc<#sample,Rand,openArray[T],openArray[U]>`_ that also utilizes ## a CDF but uses a provided state ## * `sample proc<#sample,openArray[T]>`_ that does not use a CDF ## * `sample proc<#sample,set[T]>`_ for sets runnableExamples: - from std/math import cumsummed + from math import cumsummed let marbles = ["red", "blue", "green", "yellow", "purple"] let count = [1, 6, 8, 3, 4] let cdf = count.cumsummed randomize(789) - assert sample(marbles, cdf) in marbles - + doAssert sample(marbles, cdf) == "red" + doAssert sample(marbles, cdf) == "green" + doAssert sample(marbles, cdf) == "blue" state.sample(a, cdf) -proc gauss*(r: var Rand; mu = 0.0; sigma = 1.0): float {.since: (1, 3).} = - ## Returns a Gaussian random variate, - ## with mean `mu` and standard deviation `sigma` - ## using the given state. - # Ratio of uniforms method for normal - # https://www2.econ.osaka-u.ac.jp/~tanizaki/class/2013/econome3/13.pdf - const K = sqrt(2 / E) - var - a = 0.0 - b = 0.0 - while true: - a = rand(r, 1.0) - b = (2.0 * rand(r, 1.0) - 1.0) * K - if b * b <= -4.0 * a * a * ln(a): break - result = mu + sigma * (b / a) - -proc gauss*(mu = 0.0, sigma = 1.0): float {.since: (1, 3).} = - ## Returns a Gaussian random variate, - ## with mean `mu` and standard deviation `sigma`. - ## - ## If `randomize <#randomize>`_ has not been called, the order of outcomes - ## from this proc will always be the same. - ## - ## This proc uses the default RNG. Thus, it is **not** thread-safe. - result = gauss(state, mu, sigma) - proc initRand*(seed: int64): Rand = - ## Initializes a new `Rand <#Rand>`_ state using the given seed. + ## Initializes a new `Rand<#Rand>`_ state using the given seed. ## - ## Providing a specific seed will produce the same results for that seed each time. + ## `seed` must not be zero. Providing a specific seed will produce + ## the same results for that seed each time. ## - ## The resulting state is independent of the default RNG's state. When `seed == 0`, - ## we internally set the seed to an implementation defined non-zero value. + ## The resulting state is independent of the default random number + ## generator's state. ## - ## **See also:** - ## * `initRand proc<#initRand>`_ that uses the current time - ## * `randomize proc<#randomize,int64>`_ that accepts a seed for the default RNG - ## * `randomize proc<#randomize>`_ that initializes the default RNG using the current time + ## See also: + ## * `randomize proc<#randomize,int64>`_ that accepts a seed for the default + ## random number generator + ## * `randomize proc<#randomize>`_ that initializes the default random + ## number generator using the current time runnableExamples: - from std/times import getTime, toUnix, nanosecond + from times import getTime, toUnix, nanosecond var r1 = initRand(123) + let now = getTime() var r2 = initRand(now.toUnix * 1_000_000_000 + now.nanosecond) - const seedFallback0 = int32.high # arbitrary - let seed = if seed != 0: seed else: seedFallback0 # because 0 is a fixed point + doAssert seed != 0 # 0 causes `rand(int)` to always return 0 for example. result.a0 = Ui(seed shr 16) result.a1 = Ui(seed and 0xffff) - when not defined(nimLegacyRandomInitRand): - # calling `discard next(result)` (even a few times) would still produce - # skewed numbers for the 1st call to `rand()`. - skipRandomNumbers(result) discard next(result) proc randomize*(seed: int64) {.benign.} = ## Initializes the default random number generator with the given seed. ## - ## Providing a specific seed will produce the same results for that seed each time. + ## `seed` must not be zero. Providing a specific seed will produce + ## the same results for that seed each time. ## - ## **See also:** - ## * `initRand proc<#initRand,int64>`_ that initializes a Rand state - ## with a given seed + ## See also: + ## * `initRand proc<#initRand,int64>`_ ## * `randomize proc<#randomize>`_ that uses the current time instead - ## * `initRand proc<#initRand>`_ that initializes a Rand state using - ## the current time runnableExamples: - from std/times import getTime, toUnix, nanosecond + from times import getTime, toUnix, nanosecond randomize(123) let now = getTime() randomize(now.toUnix * 1_000_000_000 + now.nanosecond) - state = initRand(seed) proc shuffle*[T](r: var Rand; x: var openArray[T]) = ## Shuffles a sequence of elements in-place using the given state. ## - ## **See also:** - ## * `shuffle proc<#shuffle,openArray[T]>`_ that uses the default RNG + ## See also: + ## * `shuffle proc<#shuffle,openArray[T]>`_ that uses the default + ## random number generator runnableExamples: var cards = ["Ace", "King", "Queen", "Jack", "Ten"] var r = initRand(678) r.shuffle(cards) - import std/algorithm - assert cards.sorted == @["Ace", "Jack", "King", "Queen", "Ten"] - + doAssert cards == ["King", "Ace", "Queen", "Ten", "Jack"] for i in countdown(x.high, 1): let j = r.rand(i) swap(x[i], x[j]) @@ -644,104 +610,83 @@ proc shuffle*[T](r: var Rand; x: var openArray[T]) = proc shuffle*[T](x: var openArray[T]) = ## Shuffles a sequence of elements in-place. ## - ## If `randomize <#randomize>`_ has not been called, the order of outcomes + ## If `randomize<#randomize>`_ has not been called, the order of outcomes ## from this proc will always be the same. ## - ## This proc uses the default RNG. Thus, it is **not** thread-safe. + ## This proc uses the default random number generator. Thus, it is **not** + ## thread-safe. ## - ## **See also:** + ## See also: ## * `shuffle proc<#shuffle,Rand,openArray[T]>`_ that uses a provided state runnableExamples: var cards = ["Ace", "King", "Queen", "Jack", "Ten"] randomize(678) shuffle(cards) - import std/algorithm - assert cards.sorted == @["Ace", "Jack", "King", "Queen", "Ten"] - + doAssert cards == ["King", "Ace", "Queen", "Ten", "Jack"] shuffle(state, x) -when not defined(standalone): - when defined(js): - import std/times - else: - when defined(nimscript): - import std/hashes - else: - import std/[hashes, os, sysrand, monotimes] - - when compileOption("threads"): - import locks - var baseSeedLock: Lock - baseSeedLock.initLock - - var baseState: Rand - - proc initRand(): Rand = - ## Initializes a new Rand state. - ## - ## The resulting state is independent of the default RNG's state. - ## - ## **Note:** Does not work for the compile-time VM. - ## - ## See also: - ## * `initRand proc<#initRand,int64>`_ that accepts a seed for a new Rand state - ## * `randomize proc<#randomize>`_ that initializes the default RNG using the current time - ## * `randomize proc<#randomize,int64>`_ that accepts a seed for the default RNG - when defined(js): - let time = int64(times.epochTime() * 1000) and 0x7fff_ffff - result = initRand(time) - else: - proc getRandomState(): Rand = - when defined(nimscript): - result = Rand( - a0: CompileTime.hash.Ui, - a1: CompileDate.hash.Ui) - if not result.isValid: - result = DefaultRandSeed - else: - var urand: array[sizeof(Rand), byte] - - for i in 0 .. 7: - if sysrand.urandom(urand): - copyMem(result.addr, urand[0].addr, sizeof(Rand)) - if result.isValid: - break - - if not result.isValid: - # Don't try to get alternative random values from other source like time or process/thread id, - # because such code would be never tested and is a liability for security. - quit("Failed to initializes baseState in random module as sysrand.urandom doesn't work.") - - when compileOption("threads"): - baseSeedLock.withLock: - if not baseState.isValid: - baseState = getRandomState() - result = baseState - baseState.skipRandomNumbers - else: - if not baseState.isValid: - baseState = getRandomState() - result = baseState - baseState.skipRandomNumbers - - since (1, 5, 1): - export initRand +when not defined(nimscript) and not defined(standalone): + import times proc randomize*() {.benign.} = - ## Initializes the default random number generator with a seed based on - ## random number source. + ## Initializes the default random number generator with a value based on + ## the current time. ## ## This proc only needs to be called once, and it should be called before - ## the first usage of procs from this module that use the default RNG. + ## the first usage of procs from this module that use the default random + ## number generator. ## - ## **Note:** Does not work for the compile-time VM. + ## **Note:** Does not work for NimScript. ## - ## **See also:** + ## See also: ## * `randomize proc<#randomize,int64>`_ that accepts a seed - ## * `initRand proc<#initRand>`_ that initializes a Rand state using - ## the current time - ## * `initRand proc<#initRand,int64>`_ that initializes a Rand state - ## with a given seed - state = initRand() + ## * `initRand proc<#initRand,int64>`_ + when defined(js): + let time = int64(times.epochTime() * 1000) and 0x7fff_ffff + randomize(time) + else: + let now = times.getTime() + randomize(convert(Seconds, Nanoseconds, now.toUnix) + now.nanosecond) {.pop.} + +when isMainModule: + proc main = + var occur: array[1000, int] + + var x = 8234 + for i in 0..100_000: + x = rand(high(occur)) + inc occur[x] + for i, oc in occur: + if oc < 69: + doAssert false, "too few occurrences of " & $i + elif oc > 150: + doAssert false, "too many occurrences of " & $i + + var a = [0, 1] + shuffle(a) + doAssert a[0] == 1 + doAssert a[1] == 0 + + doAssert rand(0) == 0 + doAssert sample("a") == 'a' + + when compileOption("rangeChecks"): + try: + discard rand(-1) + doAssert false + except RangeError: + discard + + try: + discard rand(-1.0) + doAssert false + except RangeError: + discard + + + # don't use causes integer overflow + doAssert compiles(random[int](low(int) .. high(int))) + + main() diff --git a/lib/pure/rationals.nim b/lib/pure/rationals.nim index aba0f4ce4..b668a9f71 100644 --- a/lib/pure/rationals.nim +++ b/lib/pure/rationals.nim @@ -8,95 +8,56 @@ # -## This module implements rational numbers, consisting of a numerator and -## a denominator. The denominator can not be 0. +## This module implements rational numbers, consisting of a numerator `num` and +## a denominator `den`, both of type int. The denominator can not be 0. -runnableExamples: - let - r1 = 1 // 2 - r2 = -3 // 4 - - doAssert r1 + r2 == -1 // 4 - doAssert r1 - r2 == 5 // 4 - doAssert r1 * r2 == -3 // 8 - doAssert r1 / r2 == -2 // 3 - -import math, hashes -when defined(nimPreviewSlimSystem): - import std/assertions +import math +import hashes type Rational*[T] = object - ## A rational number, consisting of a numerator `num` and a denominator `den`. + ## a rational number, consisting of a numerator and denominator num*, den*: T -func reduce*[T: SomeInteger](x: var Rational[T]) = - ## Reduces the rational number `x`, so that the numerator and denominator - ## have no common divisors other than 1 (and -1). - ## If `x` is 0, raises `DivByZeroDefect`. - ## - ## **Note:** This is called automatically by the various operations on rationals. - runnableExamples: - var r = Rational[int](num: 2, den: 4) # 1/2 - reduce(r) - doAssert r.num == 1 - doAssert r.den == 2 - - let common = gcd(x.num, x.den) - if x.den > 0: - x.num = x.num div common - x.den = x.den div common - elif x.den < 0: - x.num = -x.num div common - x.den = -x.den div common - else: - raise newException(DivByZeroDefect, "division by zero") - -func initRational*[T: SomeInteger](num, den: T): Rational[T] = - ## Creates a new rational number with numerator `num` and denominator `den`. - ## `den` must not be 0. - ## - ## **Note:** `den != 0` is not checked when assertions are turned off. - assert(den != 0, "a denominator of zero is invalid") +proc initRational*[T: SomeInteger](num, den: T): Rational[T] = + ## Create a new rational number. + assert(den != 0, "a denominator of zero value is invalid") result.num = num result.den = den - reduce(result) -func `//`*[T](num, den: T): Rational[T] = - ## A friendlier version of `initRational <#initRational,T,T>`_. - runnableExamples: - let x = 1 // 3 + 1 // 5 - doAssert x == 8 // 15 - - initRational[T](num, den) - -func `$`*[T](x: Rational[T]): string = - ## Turns a rational number into a string. - runnableExamples: - doAssert $(1 // 2) == "1/2" +proc `//`*[T](num, den: T): Rational[T] = initRational[T](num, den) + ## A friendlier version of `initRational`. Example usage: + ## + ## .. code-block:: nim + ## var x = 1//3 + 1//5 +proc `$`*[T](x: Rational[T]): string = + ## Turn a rational number into a string. result = $x.num & "/" & $x.den -func toRational*[T: SomeInteger](x: T): Rational[T] = - ## Converts some integer `x` to a rational number. - runnableExamples: - doAssert toRational(42) == 42 // 1 - +proc toRational*[T: SomeInteger](x: T): Rational[T] = + ## Convert some integer `x` to a rational number. result.num = x result.den = 1 -func toRational*(x: float, +proc toRational*(x: float, n: int = high(int) shr (sizeof(int) div 2 * 8)): Rational[int] = - ## Calculates the best rational approximation of `x`, - ## where the denominator is smaller than `n` - ## (default is the largest possible `int` for maximal resolution). + ## Calculates the best rational numerator and denominator + ## that approximates to `x`, where the denominator is + ## smaller than `n` (default is the largest possible + ## int to give maximum resolution). ## ## The algorithm is based on the theory of continued fractions. + ## + ## .. code-block:: Nim + ## import math, rationals + ## for i in 1..10: + ## let t = (10 ^ (i+3)).int + ## let x = toRational(PI, t) + ## let newPI = x.num / x.den + ## echo x, " ", newPI, " error: ", PI - newPI, " ", t + # David Eppstein / UC Irvine / 8 Aug 1993 # With corrections from Arno Formella, May 2008 - runnableExamples: - let x = 1.2 - doAssert x.toRational.toFloat == x - var m11, m22 = 1 m12, m21 = 0 @@ -108,113 +69,124 @@ func toRational*(x: float, m11 = m12 * ai + m11 m21 = m22 * ai + m21 if x == float(ai): break # division by zero - x = 1 / (x - float(ai)) + x = 1/(x - float(ai)) if x > float(high(int32)): break # representation failure ai = int(x) result = m11 // m21 -func toFloat*[T](x: Rational[T]): float = - ## Converts a rational number `x` to a `float`. +proc toFloat*[T](x: Rational[T]): float = + ## Convert a rational number `x` to a float. x.num / x.den -func toInt*[T](x: Rational[T]): int = - ## Converts a rational number `x` to an `int`. Conversion rounds towards 0 if +proc toInt*[T](x: Rational[T]): int = + ## Convert a rational number `x` to an int. Conversion rounds towards 0 if ## `x` does not contain an integer value. x.num div x.den -func `+`*[T](x, y: Rational[T]): Rational[T] = - ## Adds two rational numbers. +proc reduce*[T: SomeInteger](x: var Rational[T]) = + ## Reduce rational `x`. + let common = gcd(x.num, x.den) + if x.den > 0: + x.num = x.num div common + x.den = x.den div common + elif x.den < 0: + x.num = -x.num div common + x.den = -x.den div common + else: + raise newException(DivByZeroError, "division by zero") + +proc `+` *[T](x, y: Rational[T]): Rational[T] = + ## Add two rational numbers. let common = lcm(x.den, y.den) result.num = common div x.den * x.num + common div y.den * y.num result.den = common reduce(result) -func `+`*[T](x: Rational[T], y: T): Rational[T] = - ## Adds the rational `x` to the int `y`. +proc `+` *[T](x: Rational[T], y: T): Rational[T] = + ## Add rational `x` to int `y`. result.num = x.num + y * x.den result.den = x.den -func `+`*[T](x: T, y: Rational[T]): Rational[T] = - ## Adds the int `x` to the rational `y`. +proc `+` *[T](x: T, y: Rational[T]): Rational[T] = + ## Add int `x` to rational `y`. result.num = x * y.den + y.num result.den = y.den -func `+=`*[T](x: var Rational[T], y: Rational[T]) = - ## Adds the rational `y` to the rational `x` in-place. +proc `+=` *[T](x: var Rational[T], y: Rational[T]) = + ## Add rational `y` to rational `x`. let common = lcm(x.den, y.den) x.num = common div x.den * x.num + common div y.den * y.num x.den = common reduce(x) -func `+=`*[T](x: var Rational[T], y: T) = - ## Adds the int `y` to the rational `x` in-place. +proc `+=` *[T](x: var Rational[T], y: T) = + ## Add int `y` to rational `x`. x.num += y * x.den -func `-`*[T](x: Rational[T]): Rational[T] = +proc `-` *[T](x: Rational[T]): Rational[T] = ## Unary minus for rational numbers. result.num = -x.num result.den = x.den -func `-`*[T](x, y: Rational[T]): Rational[T] = - ## Subtracts two rational numbers. +proc `-` *[T](x, y: Rational[T]): Rational[T] = + ## Subtract two rational numbers. let common = lcm(x.den, y.den) result.num = common div x.den * x.num - common div y.den * y.num result.den = common reduce(result) -func `-`*[T](x: Rational[T], y: T): Rational[T] = - ## Subtracts the int `y` from the rational `x`. +proc `-` *[T](x: Rational[T], y: T): Rational[T] = + ## Subtract int `y` from rational `x`. result.num = x.num - y * x.den result.den = x.den -func `-`*[T](x: T, y: Rational[T]): Rational[T] = - ## Subtracts the rational `y` from the int `x`. +proc `-` *[T](x: T, y: Rational[T]): Rational[T] = + ## Subtract rational `y` from int `x`. result.num = x * y.den - y.num result.den = y.den -func `-=`*[T](x: var Rational[T], y: Rational[T]) = - ## Subtracts the rational `y` from the rational `x` in-place. +proc `-=` *[T](x: var Rational[T], y: Rational[T]) = + ## Subtract rational `y` from rational `x`. let common = lcm(x.den, y.den) x.num = common div x.den * x.num - common div y.den * y.num x.den = common reduce(x) -func `-=`*[T](x: var Rational[T], y: T) = - ## Subtracts the int `y` from the rational `x` in-place. +proc `-=` *[T](x: var Rational[T], y: T) = + ## Subtract int `y` from rational `x`. x.num -= y * x.den -func `*`*[T](x, y: Rational[T]): Rational[T] = - ## Multiplies two rational numbers. +proc `*` *[T](x, y: Rational[T]): Rational[T] = + ## Multiply two rational numbers. result.num = x.num * y.num result.den = x.den * y.den reduce(result) -func `*`*[T](x: Rational[T], y: T): Rational[T] = - ## Multiplies the rational `x` with the int `y`. +proc `*` *[T](x: Rational[T], y: T): Rational[T] = + ## Multiply rational `x` with int `y`. result.num = x.num * y result.den = x.den reduce(result) -func `*`*[T](x: T, y: Rational[T]): Rational[T] = - ## Multiplies the int `x` with the rational `y`. +proc `*` *[T](x: T, y: Rational[T]): Rational[T] = + ## Multiply int `x` with rational `y`. result.num = x * y.num result.den = y.den reduce(result) -func `*=`*[T](x: var Rational[T], y: Rational[T]) = - ## Multiplies the rational `x` by `y` in-place. +proc `*=` *[T](x: var Rational[T], y: Rational[T]) = + ## Multiply rationals `y` to `x`. x.num *= y.num x.den *= y.den reduce(x) -func `*=`*[T](x: var Rational[T], y: T) = - ## Multiplies the rational `x` by the int `y` in-place. +proc `*=` *[T](x: var Rational[T], y: T) = + ## Multiply int `y` to rational `x`. x.num *= y reduce(x) -func reciprocal*[T](x: Rational[T]): Rational[T] = - ## Calculates the reciprocal of `x` (`1/x`). - ## If `x` is 0, raises `DivByZeroDefect`. +proc reciprocal*[T](x: Rational[T]): Rational[T] = + ## Calculate the reciprocal of `x`. (1/x) if x.num > 0: result.num = x.den result.den = x.num @@ -222,94 +194,83 @@ func reciprocal*[T](x: Rational[T]): Rational[T] = result.num = -x.den result.den = -x.num else: - raise newException(DivByZeroDefect, "division by zero") + raise newException(DivByZeroError, "division by zero") -func `/`*[T](x, y: Rational[T]): Rational[T] = - ## Divides the rational `x` by the rational `y`. +proc `/`*[T](x, y: Rational[T]): Rational[T] = + ## Divide rationals `x` by `y`. result.num = x.num * y.den result.den = x.den * y.num reduce(result) -func `/`*[T](x: Rational[T], y: T): Rational[T] = - ## Divides the rational `x` by the int `y`. +proc `/`*[T](x: Rational[T], y: T): Rational[T] = + ## Divide rational `x` by int `y`. result.num = x.num result.den = x.den * y reduce(result) -func `/`*[T](x: T, y: Rational[T]): Rational[T] = - ## Divides the int `x` by the rational `y`. +proc `/`*[T](x: T, y: Rational[T]): Rational[T] = + ## Divide int `x` by Rational `y`. result.num = x * y.den result.den = y.num reduce(result) -func `/=`*[T](x: var Rational[T], y: Rational[T]) = - ## Divides the rational `x` by the rational `y` in-place. +proc `/=`*[T](x: var Rational[T], y: Rational[T]) = + ## Divide rationals `x` by `y` in place. x.num *= y.den x.den *= y.num reduce(x) -func `/=`*[T](x: var Rational[T], y: T) = - ## Divides the rational `x` by the int `y` in-place. +proc `/=`*[T](x: var Rational[T], y: T) = + ## Divide rational `x` by int `y` in place. x.den *= y reduce(x) -func cmp*(x, y: Rational): int = - ## Compares two rationals. Returns - ## * a value less than zero, if `x < y` - ## * a value greater than zero, if `x > y` - ## * zero, if `x == y` +proc cmp*(x, y: Rational): int {.procvar.} = + ## Compares two rationals. (x - y).num -func `<`*(x, y: Rational): bool = - ## Returns true if `x` is less than `y`. +proc `<` *(x, y: Rational): bool = (x - y).num < 0 -func `<=`*(x, y: Rational): bool = - ## Returns tue if `x` is less than or equal to `y`. +proc `<=` *(x, y: Rational): bool = (x - y).num <= 0 -func `==`*(x, y: Rational): bool = - ## Compares two rationals for equality. +proc `==` *(x, y: Rational): bool = (x - y).num == 0 -func abs*[T](x: Rational[T]): Rational[T] = - ## Returns the absolute value of `x`. - runnableExamples: - doAssert abs(1 // 2) == 1 // 2 - doAssert abs(-1 // 2) == 1 // 2 - +proc abs*[T](x: Rational[T]): Rational[T] = result.num = abs x.num result.den = abs x.den -func `div`*[T: SomeInteger](x, y: Rational[T]): T = +proc `div`*[T: SomeInteger](x, y: Rational[T]): T = ## Computes the rational truncated division. (x.num * y.den) div (y.num * x.den) -func `mod`*[T: SomeInteger](x, y: Rational[T]): Rational[T] = +proc `mod`*[T: SomeInteger](x, y: Rational[T]): Rational[T] = ## Computes the rational modulo by truncated division (remainder). - ## This is same as `x - (x div y) * y`. + ## This is same as ``x - (x div y) * y``. result = ((x.num * y.den) mod (y.num * x.den)) // (x.den * y.den) reduce(result) -func floorDiv*[T: SomeInteger](x, y: Rational[T]): T = +proc floorDiv*[T: SomeInteger](x, y: Rational[T]): T = ## Computes the rational floor division. ## - ## Floor division is conceptually defined as `floor(x / y)`. - ## This is different from the `div` operator, which is defined - ## as `trunc(x / y)`. That is, `div` rounds towards 0 and `floorDiv` + ## Floor division is conceptually defined as ``floor(x / y)``. + ## This is different from the ``div`` operator, which is defined + ## as ``trunc(x / y)``. That is, ``div`` rounds towards ``0`` and ``floorDiv`` ## rounds down. floorDiv(x.num * y.den, y.num * x.den) -func floorMod*[T: SomeInteger](x, y: Rational[T]): Rational[T] = +proc floorMod*[T: SomeInteger](x, y: Rational[T]): Rational[T] = ## Computes the rational modulo by floor division (modulo). ## - ## This is same as `x - floorDiv(x, y) * y`. - ## This func behaves the same as the `%` operator in Python. + ## This is same as ``x - floorDiv(x, y) * y``. + ## This proc behaves the same as the ``%`` operator in python. result = floorMod(x.num * y.den, y.num * x.den) // (x.den * y.den) reduce(result) -func hash*[T](x: Rational[T]): Hash = - ## Computes the hash for the rational `x`. +proc hash*[T](x: Rational[T]): Hash = + ## Computes hash for rational `x` # reduce first so that hash(x) == hash(y) for x == y var copy = x reduce(copy) @@ -318,3 +279,100 @@ func hash*[T](x: Rational[T]): Hash = h = h !& hash(copy.num) h = h !& hash(copy.den) result = !$h + +when isMainModule: + var + z = Rational[int](num: 0, den: 1) + o = initRational(num = 1, den = 1) + a = initRational(1, 2) + b = -1 // -2 + m1 = -1 // 1 + tt = 10 // 2 + + assert(a == a) + assert( (a-a) == z) + assert( (a+b) == o) + assert( (a/b) == o) + assert( (a*b) == 1 // 4) + assert( (3/a) == 6 // 1) + assert( (a/3) == 1 // 6) + assert(a*b == 1 // 4) + assert(tt*z == z) + assert(10*a == tt) + assert(a*10 == tt) + assert(tt/10 == a) + assert(a-m1 == 3 // 2) + assert(a+m1 == -1 // 2) + assert(m1+tt == 16 // 4) + assert(m1-tt == 6 // -1) + + assert(z < o) + assert(z <= o) + assert(z == z) + assert(cmp(z, o) < 0) + assert(cmp(o, z) > 0) + + assert(o == o) + assert(o >= o) + assert(not(o > o)) + assert(cmp(o, o) == 0) + assert(cmp(z, z) == 0) + assert(hash(o) == hash(o)) + + assert(a == b) + assert(a >= b) + assert(not(b > a)) + assert(cmp(a, b) == 0) + assert(hash(a) == hash(b)) + + var x = 1//3 + + x *= 5//1 + assert(x == 5//3) + x += 2 // 9 + assert(x == 17//9) + x -= 9//18 + assert(x == 25//18) + x /= 1//2 + assert(x == 50//18) + + var y = 1//3 + + y *= 4 + assert(y == 4//3) + y += 5 + assert(y == 19//3) + y -= 2 + assert(y == 13//3) + y /= 9 + assert(y == 13//27) + + assert toRational(5) == 5//1 + assert abs(toFloat(y) - 0.4814814814814815) < 1.0e-7 + assert toInt(z) == 0 + + when sizeof(int) == 8: + assert toRational(0.98765432) == 2111111029 // 2137499919 + assert toRational(PI) == 817696623 // 260280919 + when sizeof(int) == 4: + assert toRational(0.98765432) == 80 // 81 + assert toRational(PI) == 355 // 113 + + assert toRational(0.1) == 1 // 10 + assert toRational(0.9) == 9 // 10 + + assert toRational(0.0) == 0 // 1 + assert toRational(-0.25) == 1 // -4 + assert toRational(3.2) == 16 // 5 + assert toRational(0.33) == 33 // 100 + assert toRational(0.22) == 11 // 50 + assert toRational(10.0) == 10 // 1 + + assert (1//1) div (3//10) == 3 + assert (-1//1) div (3//10) == -3 + assert (3//10) mod (1//1) == 3//10 + assert (-3//10) mod (1//1) == -3//10 + assert floorDiv(1//1, 3//10) == 3 + assert floorDiv(-1//1, 3//10) == -4 + assert floorMod(3//10, 1//1) == 3//10 + assert floorMod(-3//10, 1//1) == 7//10 diff --git a/lib/pure/reservedmem.nim b/lib/pure/reservedmem.nim index 528b0095c..85a6e324f 100644 --- a/lib/pure/reservedmem.nim +++ b/lib/pure/reservedmem.nim @@ -9,7 +9,7 @@ ## :Authors: Zahary Karadjov ## -## This module provides utilities for reserving portions of the +## This module provides utilities for reserving a portions of the ## address space of a program without consuming physical memory. ## It can be used to implement a dynamically resizable buffer that ## is guaranteed to remain in the same memory location. The buffer @@ -18,10 +18,7 @@ ## ## Unstable API. -from std/oserrors import raiseOSError, osLastError - -when defined(nimPreviewSlimSystem): - import std/assertions +from ospaths import raiseOSError, osLastError template distance*(lhs, rhs: pointer): int = cast[int](rhs) - cast[int](lhs) @@ -45,10 +42,25 @@ type when defined(windows): import winlean - import std/private/win_getsysteminfo + + type + SYSTEM_INFO {.final, pure.} = object + u1: uint32 + dwPageSize: uint32 + lpMinimumApplicationAddress: pointer + lpMaximumApplicationAddress: pointer + dwActiveProcessorMask: ptr uint32 + dwNumberOfProcessors: uint32 + dwProcessorType: uint32 + dwAllocationGranularity: uint32 + wProcessorLevel: uint16 + wProcessorRevision: uint16 + + proc getSystemInfo(lpSystemInfo: ptr SYSTEM_INFO) {.stdcall, + dynlib: "kernel32", importc: "GetSystemInfo".} proc getAllocationGranularity: uint = - var sysInfo: SystemInfo + var sysInfo: SYSTEM_INFO getSystemInfo(addr sysInfo) return uint(sysInfo.dwAllocationGranularity) @@ -64,7 +76,7 @@ when defined(windows): template check(expr) = let r = expr - if r == cast[typeof(r)](0): + if r == cast[type(r)](0): raiseOSError(osLastError()) else: diff --git a/lib/pure/ropes.nim b/lib/pure/ropes.nim index b973fd222..1205584db 100644 --- a/lib/pure/ropes.nim +++ b/lib/pure/ropes.nim @@ -8,19 +8,18 @@ # ## This module contains support for a `rope`:idx: data type. -## Ropes can represent very long strings efficiently; in particular, concatenation +## Ropes can represent very long strings efficiently; especially concatenation ## is done in O(1) instead of O(n). They are essentially concatenation ## trees that are only flattened when converting to a native Nim -## string. The empty string is represented by `nil`. Ropes are immutable and +## string. The empty string is represented by ``nil``. Ropes are immutable and ## subtrees can be shared without copying. ## Leaves can be cached for better memory efficiency at the cost of ## runtime efficiency. -include system/inclrtl +include "system/inclrtl" import streams -when defined(nimPreviewSlimSystem): - import std/[syncio, formatfloat, assertions] +{.deadCodeElim: on.} # dce option deprecated {.push debugger: off.} # the user does not want to trace a part # of the standard library! @@ -32,11 +31,11 @@ var cacheEnabled = false type - Rope* {.acyclic.} = ref object - ## A rope data type. The empty rope is represented by `nil`. + Rope* = ref RopeObj ## empty rope is represented by nil + RopeObj {.acyclic.} = object left, right: Rope length: int - data: string # not empty if a leaf + data: string # != nil if a leaf # Note that the left and right pointers are not needed for leafs. # Leaves have relatively high memory overhead (~30 bytes on a 32 @@ -47,8 +46,9 @@ type # pointers. proc len*(a: Rope): int {.rtl, extern: "nro$1".} = - ## The rope's length. - if a == nil: 0 else: a.length + ## the rope's length + if a == nil: result = 0 + else: result = a.length proc newRope(): Rope = new(result) proc newRope(data: string): Rope = @@ -129,10 +129,6 @@ proc insertInCache(s: string, tree: Rope): Rope = proc rope*(s: string = ""): Rope {.rtl, extern: "nro$1Str".} = ## Converts a string to a rope. - runnableExamples: - let r = rope("I'm a rope") - doAssert $r == "I'm a rope" - if s.len == 0: result = nil else: @@ -148,18 +144,10 @@ proc rope*(s: string = ""): Rope {.rtl, extern: "nro$1Str".} = proc rope*(i: BiggestInt): Rope {.rtl, extern: "nro$1BiggestInt".} = ## Converts an int to a rope. - runnableExamples: - let r = rope(429) - doAssert $r == "429" - result = rope($i) proc rope*(f: BiggestFloat): Rope {.rtl, extern: "nro$1BiggestFloat".} = ## Converts a float to a rope. - runnableExamples: - let r = rope(4.29) - doAssert $r == "4.29" - result = rope($f) proc enableCache*() {.rtl, extern: "nro$1".} = @@ -168,16 +156,12 @@ proc enableCache*() {.rtl, extern: "nro$1".} = cacheEnabled = true proc disableCache*() {.rtl, extern: "nro$1".} = - ## The cache is discarded and disabled. The GC will reuse its used memory. + ## the cache is discarded and disabled. The GC will reuse its used memory. cache = nil cacheEnabled = false proc `&`*(a, b: Rope): Rope {.rtl, extern: "nroConcRopeRope".} = - ## The concatenation operator for ropes. - runnableExamples: - let r = rope("Hello, ") & rope("Nim!") - doAssert $r == "Hello, Nim!" - + ## the concatenation operator for ropes. if a == nil: result = b elif b == nil: @@ -189,81 +173,44 @@ proc `&`*(a, b: Rope): Rope {.rtl, extern: "nroConcRopeRope".} = result.right = b proc `&`*(a: Rope, b: string): Rope {.rtl, extern: "nroConcRopeStr".} = - ## The concatenation operator for ropes. - runnableExamples: - let r = rope("Hello, ") & "Nim!" - doAssert $r == "Hello, Nim!" - + ## the concatenation operator for ropes. result = a & rope(b) proc `&`*(a: string, b: Rope): Rope {.rtl, extern: "nroConcStrRope".} = - ## The concatenation operator for ropes. - runnableExamples: - let r = "Hello, " & rope("Nim!") - doAssert $r == "Hello, Nim!" - + ## the concatenation operator for ropes. result = rope(a) & b proc `&`*(a: openArray[Rope]): Rope {.rtl, extern: "nroConcOpenArray".} = - ## The concatenation operator for an `openArray` of ropes. - runnableExamples: - let r = &[rope("Hello, "), rope("Nim"), rope("!")] - doAssert $r == "Hello, Nim!" - - for item in a: result = result & item + ## the concatenation operator for an openarray of ropes. + for i in countup(0, high(a)): result = result & a[i] proc add*(a: var Rope, b: Rope) {.rtl, extern: "nro$1Rope".} = - ## Adds `b` to the rope `a`. - runnableExamples: - var r = rope("Hello, ") - r.add(rope("Nim!")) - doAssert $r == "Hello, Nim!" - + ## adds `b` to the rope `a`. a = a & b proc add*(a: var Rope, b: string) {.rtl, extern: "nro$1Str".} = - ## Adds `b` to the rope `a`. - runnableExamples: - var r = rope("Hello, ") - r.add("Nim!") - doAssert $r == "Hello, Nim!" - + ## adds `b` to the rope `a`. a = a & b proc `[]`*(r: Rope, i: int): char {.rtl, extern: "nroCharAt".} = - ## Returns the character at position `i` in the rope `r`. This is quite - ## expensive! Worst-case: O(n). If `i >= r.len or i < 0`, `\0` is returned. - runnableExamples: - let r = rope("Hello, Nim!") - - doAssert r[0] == 'H' - doAssert r[7] == 'N' - doAssert r[22] == '\0' - + ## returns the character at position `i` in the rope `r`. This is quite + ## expensive! Worst-case: O(n). If ``i >= r.len``, ``\0`` is returned. var x = r var j = i - if x == nil or i < 0 or i >= r.len: return + if x == nil: return while true: if x != nil and x.data.len > 0: - # leaf - return x.data[j] + if j < x.data.len: return x.data[j] + return '\0' else: if x.left.length > j: x = x.left else: - dec(j, x.left.length) x = x.right + dec(j, x.len) iterator leaves*(r: Rope): string = - ## Iterates over any leaf string in the rope `r`. - runnableExamples: - let r = rope("Hello") & rope(", Nim!") - let s = ["Hello", ", Nim!"] - var index = 0 - for leave in r.leaves: - doAssert leave == s[index] - inc(index) - + ## iterates over any leaf string in the rope `r`. if r != nil: var stack = @[r] while stack.len > 0: @@ -276,36 +223,27 @@ iterator leaves*(r: Rope): string = yield it.data iterator items*(r: Rope): char = - ## Iterates over any character in the rope `r`. + ## iterates over any character in the rope `r`. for s in leaves(r): for c in items(s): yield c proc write*(f: File, r: Rope) {.rtl, extern: "nro$1".} = - ## Writes a rope to a file. + ## writes a rope to a file. for s in leaves(r): write(f, s) proc write*(s: Stream, r: Rope) {.rtl, extern: "nroWriteStream".} = - ## Writes a rope to a stream. + ## writes a rope to a stream. for rs in leaves(r): write(s, rs) proc `$`*(r: Rope): string {.rtl, extern: "nroToString".} = - ## Converts a rope back to a string. + ## converts a rope back to a string. result = newStringOfCap(r.len) for s in leaves(r): add(result, s) -proc `%`*(frmt: string, args: openArray[Rope]): Rope {.rtl, extern: "nroFormat".} = - ## `%` substitution operator for ropes. Does not support the `$identifier` - ## nor `${identifier}` notations. - runnableExamples: - let r1 = "$1 $2 $3" % [rope("Nim"), rope("is"), rope("a great language")] - doAssert $r1 == "Nim is a great language" - - let r2 = "$# $# $#" % [rope("Nim"), rope("is"), rope("a great language")] - doAssert $r2 == "Nim is a great language" - - let r3 = "${1} ${2} ${3}" % [rope("Nim"), rope("is"), rope("a great language")] - doAssert $r3 == "Nim is a great language" - +proc `%`*(frmt: string, args: openArray[Rope]): Rope {. + rtl, extern: "nroFormat".} = + ## `%` substitution operator for ropes. Does not support the ``$identifier`` + ## nor ``${identifier}`` notations. var i = 0 var length = len(frmt) result = nil @@ -326,7 +264,7 @@ proc `%`*(frmt: string, args: openArray[Rope]): Rope {.rtl, extern: "nroFormat". while true: j = j * 10 + ord(frmt[i]) - ord('0') inc(i) - if i >= frmt.len or frmt[i] notin {'0'..'9'}: break + if frmt[i] notin {'0'..'9'}: break add(result, args[j-1]) of '{': inc(i) @@ -346,54 +284,51 @@ proc `%`*(frmt: string, args: openArray[Rope]): Rope {.rtl, extern: "nroFormat". if i - 1 >= start: add(result, substr(frmt, start, i - 1)) -proc addf*(c: var Rope, frmt: string, args: openArray[Rope]) {.rtl, extern: "nro$1".} = - ## Shortcut for `add(c, frmt % args)`. - runnableExamples: - var r = rope("Dash: ") - r.addf "$1 $2 $3", [rope("Nim"), rope("is"), rope("a great language")] - doAssert $r == "Dash: Nim is a great language" - +proc addf*(c: var Rope, frmt: string, args: openArray[Rope]) {. + rtl, extern: "nro$1".} = + ## shortcut for ``add(c, frmt % args)``. add(c, frmt % args) -when not defined(js) and not defined(nimscript): - const - bufSize = 1024 # 1 KB is reasonable +const + bufSize = 1024 # 1 KB is reasonable - proc equalsFile*(r: Rope, f: File): bool {.rtl, extern: "nro$1File".} = - ## Returns true if the contents of the file `f` equal `r`. - var - buf: array[bufSize, char] - bpos = buf.len - blen = buf.len +proc equalsFile*(r: Rope, f: File): bool {.rtl, extern: "nro$1File".} = + ## returns true if the contents of the file `f` equal `r`. + var + buf: array[bufSize, char] + bpos = buf.len + blen = buf.len - for s in leaves(r): - var spos = 0 - let slen = s.len - while spos < slen: - if bpos == blen: - # Read more data - bpos = 0 - blen = readBuffer(f, addr(buf[0]), buf.len) - if blen == 0: # no more data in file - return false - let n = min(blen - bpos, slen - spos) - # TODO: There's gotta be a better way of comparing here... - if not equalMem(addr(buf[bpos]), - cast[pointer](cast[int](cstring(s)) + spos), n): - return false - spos += n - bpos += n + for s in leaves(r): + var spos = 0 + let slen = s.len + while spos < slen: + if bpos == blen: + # Read more data + bpos = 0 + blen = readBuffer(f, addr(buf[0]), buf.len) + if blen == 0: # no more data in file + result = false + return + let n = min(blen - bpos, slen - spos) + # TODO There's gotta be a better way of comparing here... + if not equalMem(addr(buf[bpos]), + cast[pointer](cast[int](cstring(s))+spos), n): + result = false + return + spos += n + bpos += n - result = readBuffer(f, addr(buf[0]), 1) == 0 # check that we've read all + result = readBuffer(f, addr(buf[0]), 1) == 0 # check that we've read all - proc equalsFile*(r: Rope, filename: string): bool {.rtl, extern: "nro$1Str".} = - ## Returns true if the contents of the file `f` equal `r`. If `f` does not - ## exist, false is returned. - var f: File - result = open(f, filename) - if result: - result = equalsFile(r, f) - close(f) +proc equalsFile*(r: Rope, filename: string): bool {.rtl, extern: "nro$1Str".} = + ## returns true if the contents of the file `f` equal `r`. If `f` does not + ## exist, false is returned. + var f: File + result = open(f, filename) + if result: + result = equalsFile(r, f) + close(f) new(N) # init dummy node for splay algorithm diff --git a/lib/pure/segfaults.nim b/lib/pure/segfaults.nim index b0eac2299..2378fce17 100644 --- a/lib/pure/segfaults.nim +++ b/lib/pure/segfaults.nim @@ -8,19 +8,17 @@ # ## This modules registers a signal handler that turns access violations / -## segfaults into a ``NilAccessDefect`` exception. To be able to catch -## a NilAccessDefect all you have to do is to import this module. +## segfaults into a ``NilAccessError`` exception. To be able to catch +## a NilAccessError all you have to do is to import this module. ## ## Tested on these OSes: Linux, Windows, OSX -# xxx possibly broken on arm64, see bug #17178 - {.used.} # do allocate memory upfront: -var se: ref NilAccessDefect +var se: ref NilAccessError new(se) -se.name = "NilAccessDefect" +se.name = "NilAccessError" se.msg = "Could not access value because it is nil." when defined(windows): @@ -30,7 +28,7 @@ when defined(windows): const EXCEPTION_ACCESS_VIOLATION = DWORD(0xc0000005'i32) - EXCEPTION_CONTINUE_SEARCH = LONG(0) + EXCEPTION_CONTINUE_SEARCH = Long(0) type PEXCEPTION_RECORD = ptr object diff --git a/lib/pure/selectors.nim b/lib/pure/selectors.nim index b15a25a1d..0ab1e7754 100644 --- a/lib/pure/selectors.nim +++ b/lib/pure/selectors.nim @@ -9,11 +9,11 @@ ## This module allows high-level and efficient I/O multiplexing. ## -## Supported OS primitives: `epoll`, `kqueue`, `poll` and -## Windows `select`. +## Supported OS primitives: ``epoll``, ``kqueue``, ``poll`` and +## Windows ``select``. ## ## To use threadsafe version of this module, it needs to be compiled -## with both `-d:threadsafe` and `--threads:on` options. +## with both ``-d:threadsafe`` and ``--threads:on`` options. ## ## Supported features: files, sockets, pipes, timers, processes, signals ## and user events. @@ -25,22 +25,18 @@ ## Solaris (files, sockets, handles and user events). ## Android (files, sockets, handles and user events). ## -## TODO: `/dev/poll`, `event ports` and filesystem events. +## TODO: ``/dev/poll``, ``event ports`` and filesystem events. -import nativesockets -import std/oserrors - -when defined(nimPreviewSlimSystem): - import std/assertions +import os, strutils, nativesockets const hasThreadSupport = compileOption("threads") and defined(threadsafe) const ioselSupportedPlatform* = defined(macosx) or defined(freebsd) or defined(netbsd) or defined(openbsd) or - defined(dragonfly) or defined(nuttx) or - (defined(linux) and not defined(android) and not defined(emscripten)) + defined(dragonfly) or + (defined(linux) and not defined(android)) ## This constant is used to determine whether the destination platform is - ## fully supported by `ioselectors` module. + ## fully supported by ``ioselectors`` module. const bsdPlatform = defined(macosx) or defined(freebsd) or defined(netbsd) or defined(openbsd) or @@ -51,9 +47,6 @@ when defined(nimdoc): Selector*[T] = ref object ## An object which holds descriptors to be checked for read/write status - IOSelectorsException* = object of CatchableError - ## Exception that is raised if an IOSelectors error occurs. - Event* {.pure.} = enum ## An enum which hold event types Read, ## Descriptor is available for read @@ -90,62 +83,62 @@ when defined(nimdoc): proc registerHandle*[T](s: Selector[T], fd: int | SocketHandle, events: set[Event], data: T) = - ## Registers file/socket descriptor `fd` to selector `s` - ## with events set in `events`. The `data` is application-defined + ## Registers file/socket descriptor ``fd`` to selector ``s`` + ## with events set in ``events``. The ``data`` is application-defined ## data, which will be passed when an event is triggered. proc updateHandle*[T](s: Selector[T], fd: int | SocketHandle, events: set[Event]) = - ## Update file/socket descriptor `fd`, registered in selector - ## `s` with new events set `event`. + ## Update file/socket descriptor ``fd``, registered in selector + ## ``s`` with new events set ``event``. proc registerTimer*[T](s: Selector[T], timeout: int, oneshot: bool, data: T): int {.discardable.} = - ## Registers timer notification with `timeout` (in milliseconds) - ## to selector `s`. + ## Registers timer notification with ``timeout`` (in milliseconds) + ## to selector ``s``. ## - ## If `oneshot` is `true`, timer will be notified only once. + ## If ``oneshot`` is ``true``, timer will be notified only once. ## - ## Set `oneshot` to `false` if you want periodic notifications. + ## Set ``oneshot`` to ``false`` if you want periodic notifications. ## - ## The `data` is application-defined data, which will be passed, when + ## The ``data`` is application-defined data, which will be passed, when ## the timer is triggered. ## ## Returns the file descriptor for the registered timer. proc registerSignal*[T](s: Selector[T], signal: int, data: T): int {.discardable.} = - ## Registers Unix signal notification with `signal` to selector - ## `s`. + ## Registers Unix signal notification with ``signal`` to selector + ## ``s``. ## - ## The `data` is application-defined data, which will be + ## The ``data`` is application-defined data, which will be ## passed when signal raises. ## ## Returns the file descriptor for the registered signal. ## - ## **Note:** This function is not supported on `Windows`. + ## **Note:** This function is not supported on ``Windows``. proc registerProcess*[T](s: Selector[T], pid: int, data: T): int {.discardable.} = ## Registers a process id (pid) notification (when process has - ## exited) in selector `s`. + ## exited) in selector ``s``. ## - ## The `data` is application-defined data, which will be passed when - ## process with `pid` has exited. + ## The ``data`` is application-defined data, which will be passed when + ## process with ``pid`` has exited. ## ## Returns the file descriptor for the registered signal. proc registerEvent*[T](s: Selector[T], ev: SelectEvent, data: T) = - ## Registers selector event `ev` in selector `s`. + ## Registers selector event ``ev`` in selector ``s``. ## - ## The `data` is application-defined data, which will be passed when - ## `ev` happens. + ## The ``data`` is application-defined data, which will be passed when + ## ``ev`` happens. proc registerVnode*[T](s: Selector[T], fd: cint, events: set[Event], data: T) = ## Registers selector BSD/MacOSX specific vnode events for file - ## descriptor `fd` and events `events`. - ## `data` application-defined data, which to be passed, when + ## descriptor ``fd`` and events ``events``. + ## ``data`` application-defined data, which to be passed, when ## vnode event happens. ## ## **Note:** This function is supported only by BSD and MacOSX. @@ -154,77 +147,77 @@ when defined(nimdoc): ## Creates a new user-defined event. proc trigger*(ev: SelectEvent) = - ## Trigger event `ev`. + ## Trigger event ``ev``. proc close*(ev: SelectEvent) = - ## Closes user-defined event `ev`. + ## Closes user-defined event ``ev``. proc unregister*[T](s: Selector[T], ev: SelectEvent) = - ## Unregisters user-defined event `ev` from selector `s`. + ## Unregisters user-defined event ``ev`` from selector ``s``. proc unregister*[T](s: Selector[T], fd: int|SocketHandle|cint) = - ## Unregisters file/socket descriptor `fd` from selector `s`. + ## Unregisters file/socket descriptor ``fd`` from selector ``s``. proc selectInto*[T](s: Selector[T], timeout: int, - results: var openArray[ReadyKey]): int = - ## Waits for events registered in selector `s`. + results: var openarray[ReadyKey]): int = + ## Waits for events registered in selector ``s``. ## - ## The `timeout` argument specifies the maximum number of milliseconds + ## The ``timeout`` argument specifies the maximum number of milliseconds ## the function will be blocked for if no events are ready. Specifying a - ## timeout of `-1` causes the function to block indefinitely. - ## All available events will be stored in `results` array. + ## timeout of ``-1`` causes the function to block indefinitely. + ## All available events will be stored in ``results`` array. ## ## Returns number of triggered events. proc select*[T](s: Selector[T], timeout: int): seq[ReadyKey] = - ## Waits for events registered in selector `s`. + ## Waits for events registered in selector ``s``. ## - ## The `timeout` argument specifies the maximum number of milliseconds + ## The ``timeout`` argument specifies the maximum number of milliseconds ## the function will be blocked for if no events are ready. Specifying a - ## timeout of `-1` causes the function to block indefinitely. + ## timeout of ``-1`` causes the function to block indefinitely. ## ## Returns a list of triggered events. proc getData*[T](s: Selector[T], fd: SocketHandle|int): var T = - ## Retrieves application-defined `data` associated with descriptor `fd`. - ## If specified descriptor `fd` is not registered, empty/default value + ## Retrieves application-defined ``data`` associated with descriptor ``fd``. + ## If specified descriptor ``fd`` is not registered, empty/default value ## will be returned. proc setData*[T](s: Selector[T], fd: SocketHandle|int, data: var T): bool = - ## Associate application-defined `data` with descriptor `fd`. + ## Associate application-defined ``data`` with descriptor ``fd``. ## - ## Returns `true`, if data was successfully updated, `false` otherwise. + ## Returns ``true``, if data was successfully updated, ``false`` otherwise. template isEmpty*[T](s: Selector[T]): bool = # TODO: Why is this a template? - ## Returns `true`, if there are no registered events or descriptors + ## Returns ``true``, if there are no registered events or descriptors ## in selector. template withData*[T](s: Selector[T], fd: SocketHandle|int, value, body: untyped) = - ## Retrieves the application-data assigned with descriptor `fd` - ## to `value`. This `value` can be modified in the scope of - ## the `withData` call. + ## Retrieves the application-data assigned with descriptor ``fd`` + ## to ``value``. This ``value`` can be modified in the scope of + ## the ``withData`` call. ## ## .. code-block:: nim ## ## s.withData(fd, value) do: - ## # block is executed only if `fd` registered in selector `s` + ## # block is executed only if ``fd`` registered in selector ``s`` ## value.uid = 1000 ## template withData*[T](s: Selector[T], fd: SocketHandle|int, value, body1, body2: untyped) = - ## Retrieves the application-data assigned with descriptor `fd` - ## to `value`. This `value` can be modified in the scope of - ## the `withData` call. + ## Retrieves the application-data assigned with descriptor ``fd`` + ## to ``value``. This ``value`` can be modified in the scope of + ## the ``withData`` call. ## ## .. code-block:: nim ## ## s.withData(fd, value) do: - ## # block is executed only if `fd` registered in selector `s`. + ## # block is executed only if ``fd`` registered in selector ``s``. ## value.uid = 1000 ## do: - ## # block is executed if `fd` not registered in selector `s`. + ## # block is executed if ``fd`` not registered in selector ``s``. ## raise ## @@ -234,10 +227,9 @@ when defined(nimdoc): proc getFd*[T](s: Selector[T]): int = ## Retrieves the underlying selector's file descriptor. ## - ## For *poll* and *select* selectors `-1` is returned. + ## For *poll* and *select* selectors ``-1`` is returned. else: - import strutils when hasThreadSupport: import locks @@ -259,10 +251,10 @@ else: VnodeRename, VnodeRevoke type - IOSelectorsException* = object of CatchableError + IOSelectorsException* = object of Exception ReadyKey* = object - fd*: int + fd* : int events*: set[Event] errorCode*: OSErrorCode @@ -297,7 +289,7 @@ else: skey.ident = pident skey.events = pevents skey.param = pparam - skey.data = pdata + skey.data = data when ioselSupportedPlatform: template blockSignals(newmask: var Sigset, oldmask: var Sigset) = @@ -325,26 +317,9 @@ else: proc verifySelectParams(timeout: int) = # Timeout of -1 means: wait forever # Anything higher is the time to wait in milliseconds. - doAssert(timeout >= -1, "Cannot select with a negative value, got: " & $timeout) + doAssert(timeout >= -1, "Cannot select with a negative value, got " & $timeout) - when defined(linux) or defined(windows) or defined(macosx) or defined(bsd) or - defined(solaris) or defined(zephyr) or defined(freertos) or defined(nuttx): - template maxDescriptors*(): int = - ## Returns the maximum number of active file descriptors for the current - ## process. This involves a system call. For now `maxDescriptors` is - ## supported on the following OSes: Windows, Linux, OSX, BSD, Solaris. - when defined(windows): - 16_700_000 - elif defined(zephyr) or defined(freertos): - FD_MAX - else: - var fdLim: RLimit - var res = int(getrlimit(RLIMIT_NOFILE, fdLim)) - if res >= 0: - res = int(fdLim.rlim_cur) - 1 - res - - when defined(linux) and not defined(emscripten): + when defined(linux): include ioselects/ioselectors_epoll elif bsdPlatform: include ioselects/ioselectors_kqueue @@ -356,11 +331,24 @@ else: include ioselects/ioselectors_select # TODO: use the native VFS layer elif defined(nintendoswitch): include ioselects/ioselectors_select - elif defined(freertos) or defined(lwip): - include ioselects/ioselectors_select - elif defined(zephyr): - include ioselects/ioselectors_poll - elif defined(nuttx): - include ioselects/ioselectors_epoll else: include ioselects/ioselectors_poll + +proc register*[T](s: Selector[T], fd: int | SocketHandle, + events: set[Event], data: T) {.deprecated: "use registerHandle instead".} = + ## **Deprecated since v0.18.0:** Use ``registerHandle`` instead. + s.registerHandle(fd, events, data) + +proc setEvent*(ev: SelectEvent) {.deprecated: "use trigger instead".} = + ## Trigger event ``ev``. + ## + ## **Deprecated since v0.18.0:** Use ``trigger`` instead. + ev.trigger() + +proc update*[T](s: Selector[T], fd: int | SocketHandle, + events: set[Event]) {.deprecated: "use updateHandle instead".} = + ## Update file/socket descriptor ``fd``, registered in selector + ## ``s`` with new events set ``event``. + ## + ## **Deprecated since v0.18.0:** Use ``updateHandle`` instead. + s.updateHandle() diff --git a/lib/pure/smtp.nim b/lib/pure/smtp.nim new file mode 100644 index 000000000..1a9e22029 --- /dev/null +++ b/lib/pure/smtp.nim @@ -0,0 +1,279 @@ +# +# +# Nim's Runtime Library +# (c) Copyright 2012 Dominik Picheta +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +## This module implements the SMTP client protocol as specified by RFC 5321, +## this can be used to send mail to any SMTP Server. +## +## This module also implements the protocol used to format messages, +## as specified by RFC 2822. +## +## Example gmail use: +## +## +## .. code-block:: Nim +## var msg = createMessage("Hello from Nim's SMTP", +## "Hello!.\n Is this awesome or what?", +## @["foo@gmail.com"]) +## let smtpConn = newSmtp(useSsl = true, debug=true) +## smtpConn.connect("smtp.gmail.com", Port 465) +## smtpConn.auth("username", "password") +## smtpConn.sendmail("username@gmail.com", @["foo@gmail.com"], $msg) +## +## +## Example for startTls use: +## +## +## .. code-block:: Nim +## var msg = createMessage("Hello from Nim's SMTP", +## "Hello!.\n Is this awesome or what?", +## @["foo@gmail.com"]) +## let smtpConn = newSmtp(debug=true) +## smtpConn.connect("smtp.mailtrap.io", Port 2525) +## smtpConn.startTls() +## smtpConn.auth("username", "password") +## smtpConn.sendmail("username@gmail.com", @["foo@gmail.com"], $msg) +## +## +## For SSL support this module relies on OpenSSL. If you want to +## enable SSL, compile with ``-d:ssl``. + +import net, strutils, strtabs, base64, os +import asyncnet, asyncdispatch + +export Port + +type + Message* = object + msgTo: seq[string] + msgCc: seq[string] + msgSubject: string + msgOtherHeaders: StringTableRef + msgBody: string + + ReplyError* = object of IOError + + SmtpBase[SocketType] = ref object + sock: SocketType + debug: bool + + Smtp* = SmtpBase[Socket] + AsyncSmtp* = SmtpBase[AsyncSocket] + +proc debugSend(smtp: Smtp | AsyncSmtp, cmd: string) {.multisync.} = + if smtp.debug: + echo("C:" & cmd) + await smtp.sock.send(cmd) + +proc debugRecv(smtp: Smtp | AsyncSmtp): Future[TaintedString] {.multisync.} = + result = await smtp.sock.recvLine() + if smtp.debug: + echo("S:" & result.string) + +proc quitExcpt(smtp: Smtp, msg: string) = + smtp.debugSend("QUIT") + raise newException(ReplyError, msg) + +const compiledWithSsl = defined(ssl) + +when not defined(ssl): + type PSSLContext = ref object + let defaultSSLContext: PSSLContext = nil +else: + var defaultSSLContext {.threadvar.}: SSLContext + + proc getSSLContext(): SSLContext = + if defaultSSLContext == nil: + defaultSSLContext = newContext(verifyMode = CVerifyNone) + result = defaultSSLContext + +proc createMessage*(mSubject, mBody: string, mTo, mCc: seq[string], + otherHeaders: openarray[tuple[name, value: string]]): Message = + ## Creates a new MIME compliant message. + result.msgTo = mTo + result.msgCc = mCc + result.msgSubject = mSubject + result.msgBody = mBody + result.msgOtherHeaders = newStringTable() + for n, v in items(otherHeaders): + result.msgOtherHeaders[n] = v + +proc createMessage*(mSubject, mBody: string, mTo, + mCc: seq[string] = @[]): Message = + ## Alternate version of the above. + result.msgTo = mTo + result.msgCc = mCc + result.msgSubject = mSubject + result.msgBody = mBody + result.msgOtherHeaders = newStringTable() + +proc `$`*(msg: Message): string = + ## stringify for ``Message``. + result = "" + if msg.msgTo.len() > 0: + result = "TO: " & msg.msgTo.join(", ") & "\c\L" + if msg.msgCc.len() > 0: + result.add("CC: " & msg.msgCc.join(", ") & "\c\L") + # TODO: Folding? i.e when a line is too long, shorten it... + result.add("Subject: " & msg.msgSubject & "\c\L") + for key, value in pairs(msg.msgOtherHeaders): + result.add(key & ": " & value & "\c\L") + + result.add("\c\L") + result.add(msg.msgBody) + +proc newSmtp*(useSsl = false, debug = false, + sslContext: SSLContext = nil): Smtp = + ## Creates a new ``Smtp`` instance. + new result + result.debug = debug + result.sock = newSocket() + if useSsl: + when compiledWithSsl: + if sslContext == nil: + getSSLContext().wrapSocket(result.sock) + else: + sslContext.wrapSocket(result.sock) + else: + {.error: "SMTP module compiled without SSL support".} + +proc newAsyncSmtp*(useSsl = false, debug = false, + sslContext: SSLContext = nil): AsyncSmtp = + ## Creates a new ``AsyncSmtp`` instance. + new result + result.debug = debug + + result.sock = newAsyncSocket() + if useSsl: + when compiledWithSsl: + if sslContext == nil: + getSSLContext().wrapSocket(result.sock) + else: + sslContext.wrapSocket(result.sock) + else: + {.error: "SMTP module compiled without SSL support".} + +proc quitExcpt(smtp: AsyncSmtp, msg: string): Future[void] = + var retFuture = newFuture[void]() + var sendFut = smtp.debugSend("QUIT") + sendFut.callback = + proc () = + retFuture.fail(newException(ReplyError, msg)) + return retFuture + +proc checkReply(smtp: Smtp | AsyncSmtp, reply: string) {.multisync.} = + var line = await smtp.debugRecv() + if not line.startswith(reply): + await quitExcpt(smtp, "Expected " & reply & " reply, got: " & line) + +proc connect*(smtp: Smtp | AsyncSmtp, + address: string, port: Port) {.multisync.} = + ## Establishes a connection with a SMTP server. + ## May fail with ReplyError or with a socket error. + await smtp.sock.connect(address, port) + + await smtp.checkReply("220") + await smtp.debugSend("HELO " & address & "\c\L") + await smtp.checkReply("250") + +proc startTls*(smtp: Smtp | AsyncSmtp, sslContext: SSLContext = nil) {.multisync.} = + ## Put the SMTP connection in TLS (Transport Layer Security) mode. + ## May fail with ReplyError + await smtp.debugSend("STARTTLS\c\L") + await smtp.checkReply("220") + when compiledWithSsl: + if sslContext == nil: + getSSLContext().wrapConnectedSocket(smtp.sock, handshakeAsClient) + else: + sslContext.wrapConnectedSocket(smtp.sock, handshakeAsClient) + else: + {.error: "SMTP module compiled without SSL support".} + +proc auth*(smtp: Smtp | AsyncSmtp, username, password: string) {.multisync.} = + ## Sends an AUTH command to the server to login as the `username` + ## using `password`. + ## May fail with ReplyError. + + await smtp.debugSend("AUTH LOGIN\c\L") + await smtp.checkReply("334") # TODO: Check whether it's asking for the "Username:" + # i.e "334 VXNlcm5hbWU6" + await smtp.debugSend(encode(username) & "\c\L") + await smtp.checkReply("334") # TODO: Same as above, only "Password:" (I think?) + + await smtp.debugSend(encode(password) & "\c\L") + await smtp.checkReply("235") # Check whether the authentication was successful. + +proc sendMail*(smtp: Smtp | AsyncSmtp, fromAddr: string, + toAddrs: seq[string], msg: string) {.multisync.} = + ## Sends ``msg`` from ``fromAddr`` to the addresses specified in ``toAddrs``. + ## Messages may be formed using ``createMessage`` by converting the + ## Message into a string. + + await smtp.debugSend("MAIL FROM:<" & fromAddr & ">\c\L") + await smtp.checkReply("250") + for address in items(toAddrs): + await smtp.debugSend("RCPT TO:<" & address & ">\c\L") + await smtp.checkReply("250") + + # Send the message + await smtp.debugSend("DATA " & "\c\L") + await smtp.checkReply("354") + await smtp.sock.send(msg & "\c\L") + await smtp.debugSend(".\c\L") + await smtp.checkReply("250") + +proc close*(smtp: Smtp | AsyncSmtp) {.multisync.} = + ## Disconnects from the SMTP server and closes the socket. + await smtp.debugSend("QUIT\c\L") + smtp.sock.close() + +when not defined(testing) and isMainModule: + # To test with a real SMTP service, create a smtp.ini file, e.g.: + # username = "" + # password = "" + # smtphost = "smtp.gmail.com" + # port = 465 + # use_tls = true + # sender = "" + # recipient = "" + + import parsecfg + + proc `[]`(c: Config, key: string): string = c.getSectionValue("", key) + + let + conf = loadConfig("smtp.ini") + msg = createMessage("Hello from Nim's SMTP!", + "Hello!\n Is this awesome or what?", @[conf["recipient"]]) + + assert conf["smtphost"] != "" + + proc async_test() {.async.} = + let client = newAsyncSmtp( + conf["use_tls"].parseBool, + debug = true + ) + await client.connect(conf["smtphost"], conf["port"].parseInt.Port) + await client.auth(conf["username"], conf["password"]) + await client.sendMail(conf["sender"], @[conf["recipient"]], $msg) + await client.close() + echo "async email sent" + + proc sync_test() = + var smtpConn = newSmtp( + conf["use_tls"].parseBool, + debug = true + ) + smtpConn.connect(conf["smtphost"], conf["port"].parseInt.Port) + smtpConn.auth(conf["username"], conf["password"]) + smtpConn.sendMail(conf["sender"], @[conf["recipient"]], $msg) + smtpConn.close() + echo "sync email sent" + + waitFor async_test() + sync_test() diff --git a/lib/pure/ssl_certs.nim b/lib/pure/ssl_certs.nim deleted file mode 100644 index dd09848be..000000000 --- a/lib/pure/ssl_certs.nim +++ /dev/null @@ -1,172 +0,0 @@ -# -# -# Nim's Runtime Library -# (c) Copyright 2017 Nim contributors -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# -## Scan for SSL/TLS CA certificates on disk -## The default locations can be overridden using the SSL_CERT_FILE and -## SSL_CERT_DIR environment variables. - -import os, strutils - -# FWIW look for files before scanning entire dirs. - -when defined(macosx): - const certificatePaths = [ - "/etc/ssl/cert.pem", - "/System/Library/OpenSSL/certs/cert.pem" - ] -elif defined(linux): - const certificatePaths = [ - # Debian, Ubuntu, Arch: maintained by update-ca-certificates, SUSE, Gentoo - # NetBSD (security/mozilla-rootcerts) - # SLES10/SLES11, https://golang.org/issue/12139 - "/etc/ssl/certs/ca-certificates.crt", - # OpenSUSE - "/etc/ssl/ca-bundle.pem", - # Red Hat 5+, Fedora, Centos - "/etc/pki/tls/certs/ca-bundle.crt", - # Red Hat 4 - "/usr/share/ssl/certs/ca-bundle.crt", - # Fedora/RHEL - "/etc/pki/tls/certs", - # Android - "/data/data/com.termux/files/usr/etc/tls/cert.pem", - "/system/etc/security/cacerts", - ] -elif defined(bsd): - const certificatePaths = [ - # Debian, Ubuntu, Arch: maintained by update-ca-certificates, SUSE, Gentoo - # NetBSD (security/mozilla-rootcerts) - # SLES10/SLES11, https://golang.org/issue/12139 - "/etc/ssl/certs/ca-certificates.crt", - # FreeBSD (security/ca-root-nss package) - "/usr/local/share/certs/ca-root-nss.crt", - # OpenBSD, FreeBSD (optional symlink) - "/etc/ssl/cert.pem", - # FreeBSD - "/usr/local/share/certs", - # NetBSD - "/etc/openssl/certs", - ] -else: - const certificatePaths = [ - # Debian, Ubuntu, Arch: maintained by update-ca-certificates, SUSE, Gentoo - # NetBSD (security/mozilla-rootcerts) - # SLES10/SLES11, https://golang.org/issue/12139 - "/etc/ssl/certs/ca-certificates.crt", - # OpenSUSE - "/etc/ssl/ca-bundle.pem", - # Red Hat 5+, Fedora, Centos - "/etc/pki/tls/certs/ca-bundle.crt", - # Red Hat 4 - "/usr/share/ssl/certs/ca-bundle.crt", - # FreeBSD (security/ca-root-nss package) - "/usr/local/share/certs/ca-root-nss.crt", - # CentOS/RHEL 7 - "/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem", - # OpenBSD, FreeBSD (optional symlink) - "/etc/ssl/cert.pem", - # Fedora/RHEL - "/etc/pki/tls/certs", - # Android - "/system/etc/security/cacerts", - # FreeBSD - "/usr/local/share/certs", - # NetBSD - "/etc/openssl/certs", - ] - -when defined(haiku): - const - B_FIND_PATH_EXISTING_ONLY = 0x4 - B_FIND_PATH_DATA_DIRECTORY = 6 - - proc find_paths_etc(architecture: cstring, baseDirectory: cint, - subPath: cstring, flags: uint32, - paths: var ptr UncheckedArray[cstring], - pathCount: var csize_t): int32 - {.importc, header: "".} - proc free(p: pointer) {.importc, header: "".} - -iterator scanSSLCertificates*(useEnvVars = false): string = - ## Scan for SSL/TLS CA certificates on disk. - ## - ## if `useEnvVars` is true, the SSL_CERT_FILE and SSL_CERT_DIR - ## environment variables can be used to override the certificate - ## directories to scan or specify a CA certificate file. - if useEnvVars and existsEnv("SSL_CERT_FILE"): - yield getEnv("SSL_CERT_FILE") - - elif useEnvVars and existsEnv("SSL_CERT_DIR"): - let p = getEnv("SSL_CERT_DIR") - for fn in joinPath(p, "*").walkFiles(): - yield fn - - else: - when defined(windows): - const cacert = "cacert.pem" - let pem = getAppDir() / cacert - if fileExists(pem): - yield pem - else: - let path = getEnv("PATH") - for candidate in split(path, PathSep): - if candidate.len != 0: - let x = (if candidate[0] == '"' and candidate[^1] == '"': - substr(candidate, 1, candidate.len-2) else: candidate) / cacert - if fileExists(x): - yield x - elif not defined(haiku): - for p in certificatePaths: - if p.endsWith(".pem") or p.endsWith(".crt"): - if fileExists(p): - yield p - elif dirExists(p): - # check if it's a dir where each cert is one file - # named by it's hasg - for fn in joinPath(p, "*.0").walkFiles: - yield p.normalizePathEnd(true) - break - for fn in joinPath(p, "*").walkFiles(): - - yield fn - else: - var - paths: ptr UncheckedArray[cstring] - size: csize_t - let err = find_paths_etc( - nil, B_FIND_PATH_DATA_DIRECTORY, "ssl/CARootCertificates.pem", - B_FIND_PATH_EXISTING_ONLY, paths, size - ) - if err == 0: - defer: free(paths) - for i in 0 ..< size: - yield $paths[i] - -# Certificates management on windows -# when defined(windows) or defined(nimdoc): -# -# import openssl -# -# type -# PCCertContext {.final, pure.} = pointer -# X509 {.final, pure.} = pointer -# CertStore {.final, pure.} = pointer -# -# # OpenSSL cert store -# -# {.push stdcall, dynlib: "kernel32", importc.} -# -# proc CertOpenSystemStore*(hprov: pointer=nil, szSubsystemProtocol: cstring): CertStore -# -# proc CertEnumCertificatesInStore*(hCertStore: CertStore, pPrevCertContext: PCCertContext): pointer -# -# proc CertFreeCertificateContext*(pContext: PCCertContext): bool -# -# proc CertCloseStore*(hCertStore:CertStore, flags:cint): bool -# -# {.pop.} diff --git a/lib/pure/ssl_config.nim b/lib/pure/ssl_config.nim deleted file mode 100644 index 14f66ede4..000000000 --- a/lib/pure/ssl_config.nim +++ /dev/null @@ -1,51 +0,0 @@ -# This file was automatically generated by tools/ssl_config_parser on 2020-06-03T22:02:05Z. DO NOT EDIT. - -## This module contains SSL configuration parameters obtained from -## `Mozilla OpSec `_. -## -## The configuration file used to generate this module: https://ssl-config.mozilla.org/guidelines/5.4.json - -const CiphersModern* = "TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256" - ## An OpenSSL-compatible list of secure ciphers for ``modern`` compatibility - ## per Mozilla's recommendations. - ## - ## Oldest clients supported by this list: - ## * Firefox 63 - ## * Android 10.0 - ## * Chrome 70 - ## * Edge 75 - ## * Java 11 - ## * OpenSSL 1.1.1 - ## * Opera 57 - ## * Safari 12.1 - -const CiphersIntermediate* = "TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384" - ## An OpenSSL-compatible list of secure ciphers for ``intermediate`` compatibility - ## per Mozilla's recommendations. - ## - ## Oldest clients supported by this list: - ## * Firefox 27 - ## * Android 4.4.2 - ## * Chrome 31 - ## * Edge - ## * IE 11 on Windows 7 - ## * Java 8u31 - ## * OpenSSL 1.0.1 - ## * Opera 20 - ## * Safari 9 - -const CiphersOld* = "TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA256:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA" - ## An OpenSSL-compatible list of secure ciphers for ``old`` compatibility - ## per Mozilla's recommendations. - ## - ## Oldest clients supported by this list: - ## * Firefox 1 - ## * Android 2.3 - ## * Chrome 1 - ## * Edge 12 - ## * IE8 on Windows XP - ## * Java 6 - ## * OpenSSL 0.9.8 - ## * Opera 5 - ## * Safari 1 - diff --git a/lib/pure/stats.nim b/lib/pure/stats.nim index 7f797529d..d62276da9 100644 --- a/lib/pure/stats.nim +++ b/lib/pure/stats.nim @@ -9,77 +9,67 @@ ## Statistical analysis framework for performing ## basic statistical analysis of data. -## The data is analysed in a single pass, when it -## is pushed to a `RunningStat` or `RunningRegress` object. +## The data is analysed in a single pass, when a data value +## is pushed to the ``RunningStat`` or ``RunningRegress`` objects ## -## `RunningStat` calculates for a single data set +## ``RunningStat`` calculates for a single data set ## - n (data count) -## - min (smallest value) -## - max (largest value) +## - min (smallest value) +## - max (largest value) ## - sum ## - mean ## - variance -## - varianceS (sample variance) +## - varianceS (sample var) ## - standardDeviation -## - standardDeviationS (sample standard deviation) +## - standardDeviationS (sample stddev) ## - skewness (the third statistical moment) ## - kurtosis (the fourth statistical moment) ## -## `RunningRegress` calculates for two sets of data -## - n (data count) +## ``RunningRegress`` calculates for two sets of data +## - n ## - slope ## - intercept ## - correlation ## -## Procs are provided to calculate statistics on `openArray`s. +## Procs have been provided to calculate statistics on arrays and sequences. ## ## However, if more than a single statistical calculation is required, it is more -## efficient to push the data once to a `RunningStat` object and then -## call the numerous statistical procs for the `RunningStat` object: - -runnableExamples: - from std/math import almostEqual - - template `~=`(a, b: float): bool = almostEqual(a, b) - - var statistics: RunningStat # must be var - statistics.push(@[1.0, 2.0, 1.0, 4.0, 1.0, 4.0, 1.0, 2.0]) - doAssert statistics.n == 8 - doAssert statistics.mean() ~= 2.0 - doAssert statistics.variance() ~= 1.5 - doAssert statistics.varianceS() ~= 1.714285714285715 - doAssert statistics.skewness() ~= 0.8164965809277261 - doAssert statistics.skewnessS() ~= 1.018350154434631 - doAssert statistics.kurtosis() ~= -1.0 - doAssert statistics.kurtosisS() ~= -0.7000000000000008 +## efficient to push the data once to the RunningStat object, and +## call the numerous statistical procs for the RunningStat object. +## +## .. code-block:: Nim +## +## var rs: RunningStat +## rs.push(MySeqOfData) +## rs.mean() +## rs.variance() +## rs.skewness() +## rs.kurtosis() from math import FloatClass, sqrt, pow, round -when defined(nimPreviewSlimSystem): - import std/[assertions, formatfloat] - {.push debugger: off.} # the user does not want to trace a part # of the standard library! {.push checks: off, line_dir: off, stack_trace: off.} type - RunningStat* = object ## An accumulator for statistical data. - n*: int ## amount of pushed data + RunningStat* = object ## an accumulator for statistical data + n*: int ## number of pushed data min*, max*, sum*: float ## self-explaining mom1, mom2, mom3, mom4: float ## statistical moments, mom1 is mean - RunningRegress* = object ## An accumulator for regression calculations. - n*: int ## amount of pushed data - x_stats*: RunningStat ## stats for the first set of data - y_stats*: RunningStat ## stats for the second set of data + + RunningRegress* = object ## an accumulator for regression calculations + n*: int ## number of pushed data + x_stats*: RunningStat ## stats for first set of data + y_stats*: RunningStat ## stats for second set of data s_xy: float ## accumulated data for combined xy # ----------- RunningStat -------------------------- - proc clear*(s: var RunningStat) = - ## Resets `s`. + ## reset `s` s.n = 0 - s.min = 0.0 + s.min = toBiggestFloat(int.high) s.max = 0.0 s.sum = 0.0 s.mom1 = 0.0 @@ -88,15 +78,12 @@ proc clear*(s: var RunningStat) = s.mom4 = 0.0 proc push*(s: var RunningStat, x: float) = - ## Pushes a value `x` for processing. - if s.n == 0: - s.min = x - s.max = x - else: - if s.min > x: s.min = x - if s.max < x: s.max = x + ## pushes a value `x` for processing + if s.n == 0: s.min = x inc(s.n) # See Knuth TAOCP vol 2, 3rd edition, page 232 + if s.min > x: s.min = x + if s.max < x: s.max = x s.sum += x let n = toFloat(s.n) let delta = x - s.mom1 @@ -110,63 +97,63 @@ proc push*(s: var RunningStat, x: float) = s.mom1 += delta_n proc push*(s: var RunningStat, x: int) = - ## Pushes a value `x` for processing. + ## pushes a value `x` for processing. ## - ## `x` is simply converted to `float` + ## `x` is simply converted to ``float`` ## and the other push operation is called. s.push(toFloat(x)) -proc push*(s: var RunningStat, x: openArray[float|int]) = - ## Pushes all values of `x` for processing. +proc push*(s: var RunningStat, x: openarray[float|int]) = + ## pushes all values of `x` for processing. ## - ## Int values of `x` are simply converted to `float` and + ## Int values of `x` are simply converted to ``float`` and ## the other push operation is called. for val in x: s.push(val) proc mean*(s: RunningStat): float = - ## Computes the current mean of `s`. + ## computes the current mean of `s` result = s.mom1 proc variance*(s: RunningStat): float = - ## Computes the current population variance of `s`. + ## computes the current population variance of `s` result = s.mom2 / toFloat(s.n) proc varianceS*(s: RunningStat): float = - ## Computes the current sample variance of `s`. + ## computes the current sample variance of `s` if s.n > 1: result = s.mom2 / toFloat(s.n - 1) proc standardDeviation*(s: RunningStat): float = - ## Computes the current population standard deviation of `s`. + ## computes the current population standard deviation of `s` result = sqrt(variance(s)) proc standardDeviationS*(s: RunningStat): float = - ## Computes the current sample standard deviation of `s`. + ## computes the current sample standard deviation of `s` result = sqrt(varianceS(s)) proc skewness*(s: RunningStat): float = - ## Computes the current population skewness of `s`. + ## computes the current population skewness of `s` result = sqrt(toFloat(s.n)) * s.mom3 / pow(s.mom2, 1.5) proc skewnessS*(s: RunningStat): float = - ## Computes the current sample skewness of `s`. + ## computes the current sample skewness of `s` let s2 = skewness(s) result = sqrt(toFloat(s.n*(s.n-1)))*s2 / toFloat(s.n-2) proc kurtosis*(s: RunningStat): float = - ## Computes the current population kurtosis of `s`. + ## computes the current population kurtosis of `s` result = toFloat(s.n) * s.mom4 / (s.mom2 * s.mom2) - 3.0 proc kurtosisS*(s: RunningStat): float = - ## Computes the current sample kurtosis of `s`. + ## computes the current sample kurtosis of `s` result = toFloat(s.n-1) / toFloat((s.n-2)*(s.n-3)) * (toFloat(s.n+1)*kurtosis(s) + 6) proc `+`*(a, b: RunningStat): RunningStat = - ## Combines two `RunningStat`s. + ## combine two RunningStats. ## - ## Useful when performing parallel analysis of data series - ## and needing to re-combine parallel result sets. + ## Useful if performing parallel analysis of data series + ## and need to re-combine parallel result sets result.clear() result.n = a.n + b.n @@ -191,11 +178,11 @@ proc `+`*(a, b: RunningStat): RunningStat = result.min = min(a.min, b.min) proc `+=`*(a: var RunningStat, b: RunningStat) {.inline.} = - ## Adds the `RunningStat` `b` to `a`. + ## add a second RunningStats `b` to `a` a = a + b proc `$`*(a: RunningStat): string = - ## Produces a string representation of the `RunningStat`. The exact + ## produces a string representation of the ``RunningStat``. The exact ## format is currently unspecified and subject to change. Currently ## it contains: ## @@ -212,57 +199,56 @@ proc `$`*(a: RunningStat): string = result.add ")" # ---------------------- standalone array/seq stats --------------------- - proc mean*[T](x: openArray[T]): float = - ## Computes the mean of `x`. + ## computes the mean of `x` var rs: RunningStat rs.push(x) result = rs.mean() proc variance*[T](x: openArray[T]): float = - ## Computes the population variance of `x`. + ## computes the population variance of `x` var rs: RunningStat rs.push(x) result = rs.variance() proc varianceS*[T](x: openArray[T]): float = - ## Computes the sample variance of `x`. + ## computes the sample variance of `x` var rs: RunningStat rs.push(x) result = rs.varianceS() proc standardDeviation*[T](x: openArray[T]): float = - ## Computes the population standard deviation of `x`. + ## computes the population standardDeviation of `x` var rs: RunningStat rs.push(x) result = rs.standardDeviation() proc standardDeviationS*[T](x: openArray[T]): float = - ## Computes the sample standard deviation of `x`. + ## computes the sample standardDeviation of `x` var rs: RunningStat rs.push(x) result = rs.standardDeviationS() proc skewness*[T](x: openArray[T]): float = - ## Computes the population skewness of `x`. + ## computes the population skewness of `x` var rs: RunningStat rs.push(x) result = rs.skewness() proc skewnessS*[T](x: openArray[T]): float = - ## Computes the sample skewness of `x`. + ## computes the sample skewness of `x` var rs: RunningStat rs.push(x) result = rs.skewnessS() proc kurtosis*[T](x: openArray[T]): float = - ## Computes the population kurtosis of `x`. + ## computes the population kurtosis of `x` var rs: RunningStat rs.push(x) result = rs.kurtosis() proc kurtosisS*[T](x: openArray[T]): float = - ## Computes the sample kurtosis of `x`. + ## computes the sample kurtosis of `x` var rs: RunningStat rs.push(x) result = rs.kurtosisS() @@ -270,14 +256,14 @@ proc kurtosisS*[T](x: openArray[T]): float = # ---------------------- Running Regression ----------------------------- proc clear*(r: var RunningRegress) = - ## Resets `r`. + ## reset `r` r.x_stats.clear() r.y_stats.clear() r.s_xy = 0.0 r.n = 0 proc push*(r: var RunningRegress, x, y: float) = - ## Pushes two values `x` and `y` for processing. + ## pushes two values `x` and `y` for processing r.s_xy += (r.x_stats.mean() - x)*(r.y_stats.mean() - y) * toFloat(r.n) / toFloat(r.n + 1) r.x_stats.push(x) @@ -285,38 +271,38 @@ proc push*(r: var RunningRegress, x, y: float) = inc(r.n) proc push*(r: var RunningRegress, x, y: int) {.inline.} = - ## Pushes two values `x` and `y` for processing. + ## pushes two values `x` and `y` for processing. ## - ## `x` and `y` are converted to `float` + ## `x` and `y` are converted to ``float`` ## and the other push operation is called. r.push(toFloat(x), toFloat(y)) -proc push*(r: var RunningRegress, x, y: openArray[float|int]) = - ## Pushes two sets of values `x` and `y` for processing. +proc push*(r: var RunningRegress, x, y: openarray[float|int]) = + ## pushes two sets of values `x` and `y` for processing. assert(x.len == y.len) for i in 0..`_ -## * `io module `_ for `FileMode enum `_ +## * `io module `_ for `FileMode enum `_ -import std/private/since +include "system/inclrtl" -when defined(nimPreviewSlimSystem): - import std/syncio - export FileMode +const taintMode = compileOption("taintmode") proc newEIO(msg: string): owned(ref IOError) = new(result) @@ -115,7 +113,7 @@ type ## * That these fields here shouldn't be used directly. ## They are accessible so that a stream implementation can override them. closeImpl*: proc (s: Stream) - {.nimcall, raises: [IOError, OSError], tags: [WriteIOEffect], gcsafe.} + {.nimcall, raises: [Exception, IOError, OSError], tags: [WriteIOEffect], gcsafe.} atEndImpl*: proc (s: Stream): bool {.nimcall, raises: [Defect, IOError, OSError], tags: [], gcsafe.} setPositionImpl*: proc (s: Stream, pos: int) @@ -126,7 +124,7 @@ type readDataStrImpl*: proc (s: Stream, buffer: var string, slice: Slice[int]): int {.nimcall, raises: [Defect, IOError, OSError], tags: [ReadIOEffect], gcsafe.} - readLineImpl*: proc(s: Stream, line: var string): bool + readLineImpl*: proc(s: Stream, line: var TaintedString): bool {.nimcall, raises: [Defect, IOError, OSError], tags: [ReadIOEffect], gcsafe.} readDataImpl*: proc (s: Stream, buffer: pointer, bufLen: int): int @@ -148,7 +146,7 @@ proc flush*(s: Stream) = ## See also: ## * `close proc <#close,Stream>`_ runnableExamples: - from std/os import removeFile + from os import removeFile var strm = newFileStream("somefile.txt", fmWrite) @@ -174,20 +172,10 @@ proc close*(s: Stream) = ## See also: ## * `flush proc <#flush,Stream>`_ runnableExamples: - block: - let strm = newStringStream("The first line\nthe second line\nthe third line") - ## do something... - strm.close() - - block: - let strm = newFileStream("amissingfile.txt") - # deferring works even if newFileStream fails - defer: strm.close() - if not isNil(strm): - ## do something... - - if not isNil(s) and not isNil(s.closeImpl): - s.closeImpl(s) + var strm = newStringStream("The first line\nthe second line\nthe third line") + ## do something... + strm.close() + if not isNil(s.closeImpl): s.closeImpl(s) proc atEnd*(s: Stream): bool = ## Checks if more data can be read from `s`. Returns ``true`` if all data has @@ -228,9 +216,6 @@ proc getPosition*(s: Stream): int = proc readData*(s: Stream, buffer: pointer, bufLen: int): int = ## Low level proc that reads data into an untyped `buffer` of `bufLen` size. - ## - ## **JS note:** `buffer` is treated as a ``ptr string`` and written to between - ## ``0..= (1, 3) or not defined(js): +when not defined(js): proc readAll*(s: Stream): string = ## Reads all available data. + ## + ## **Note:** Not available for JS backend. runnableExamples: var strm = newStringStream("The first line\nthe second line\nthe third line") doAssert strm.readAll() == "The first line\nthe second line\nthe third line" @@ -281,7 +253,7 @@ when (NimMajor, NimMinor) >= (1, 3) or not defined(js): strm.close() const bufferSize = 1024 - jsOrVmBlock: + when nimvm: var buffer2: string buffer2.setLen(bufferSize) while true: @@ -293,7 +265,7 @@ when (NimMajor, NimMinor) >= (1, 3) or not defined(js): result[prevLen..= (1, 3) or not defined(js): proc peekData*(s: Stream, buffer: pointer, bufLen: int): int = ## Low level proc that reads data into an untyped `buffer` of `bufLen` size ## without moving stream position. - ## - ## **JS note:** `buffer` is treated as a ``ptr string`` and written to between - ## ``0..`_ for now. - ## ## .. code-block:: Nim ## ## s.writeData(s, unsafeAddr(x), sizeof(x)) @@ -361,7 +324,7 @@ proc write*[T](s: Stream, x: T) = writeData(s, unsafeAddr(x), sizeof(x)) proc write*(s: Stream, x: string) = - ## Writes the string `x` to the stream `s`. No length field or + ## Writes the string `x` to the the stream `s`. No length field or ## terminating zero is written. runnableExamples: var strm = newStringStream("") @@ -373,12 +336,7 @@ proc write*(s: Stream, x: string) = when nimvm: writeData(s, cstring(x), x.len) else: - if x.len > 0: - when defined(js): - var x = x - writeData(s, addr(x), x.len) - else: - writeData(s, cstring(x), x.len) + if x.len > 0: writeData(s, cstring(x), x.len) proc write*(s: Stream, args: varargs[string, `$`]) = ## Writes one or more strings to the the stream. No length fields or @@ -408,8 +366,6 @@ proc writeLine*(s: Stream, args: varargs[string, `$`]) = proc read*[T](s: Stream, result: var T) = ## Generic read procedure. Reads `result` from the stream `s`. - ## - ## **Note:** Not available for JS backend. Use `readStr <#readStr,Stream,int>`_ for now. runnableExamples: var strm = newStringStream("012") ## readInt @@ -427,8 +383,6 @@ proc read*[T](s: Stream, result: var T) = proc peek*[T](s: Stream, result: var T) = ## Generic peek procedure. Peeks `result` from the stream `s`. - ## - ## **Note:** Not available for JS backend. Use `peekStr <#peekStr,Stream,int>`_ for now. runnableExamples: var strm = newStringStream("012") ## peekInt @@ -458,11 +412,11 @@ proc readChar*(s: Stream): char = doAssert strm.readChar() == '\x00' strm.close() - jsOrVmBlock: + when nimvm: var str = " " - if readDataStr(s, str, 0..0) != 1: result = '\0' + if readDataStr(s, str, 0..`_ for now. runnableExamples: var strm = newStringStream() ## setup for reading data @@ -514,8 +461,6 @@ proc peekBool*(s: Stream): bool = ## A bool is one byte long and it is `true` for every non-zero ## (`0000_0000`) value. ## Raises `IOError` if an error occurred. - ## - ## **Note:** Not available for JS backend. Use `peekStr <#peekStr,Stream,int>`_ for now. runnableExamples: var strm = newStringStream() ## setup for reading data @@ -537,8 +482,6 @@ proc peekBool*(s: Stream): bool = proc readInt8*(s: Stream): int8 = ## Reads an int8 from the stream `s`. Raises `IOError` if an error occurred. - ## - ## **Note:** Not available for JS backend. Use `readStr <#readStr,Stream,int>`_ for now. runnableExamples: var strm = newStringStream() ## setup for reading data @@ -556,8 +499,6 @@ proc readInt8*(s: Stream): int8 = proc peekInt8*(s: Stream): int8 = ## Peeks an int8 from the stream `s`. Raises `IOError` if an error occurred. - ## - ## **Note:** Not available for JS backend. Use `peekStr <#peekStr,Stream,int>`_ for now. runnableExamples: var strm = newStringStream() ## setup for reading data @@ -577,8 +518,6 @@ proc peekInt8*(s: Stream): int8 = proc readInt16*(s: Stream): int16 = ## Reads an int16 from the stream `s`. Raises `IOError` if an error occurred. - ## - ## **Note:** Not available for JS backend. Use `readStr <#readStr,Stream,int>`_ for now. runnableExamples: var strm = newStringStream() ## setup for reading data @@ -596,8 +535,6 @@ proc readInt16*(s: Stream): int16 = proc peekInt16*(s: Stream): int16 = ## Peeks an int16 from the stream `s`. Raises `IOError` if an error occurred. - ## - ## **Note:** Not available for JS backend. Use `peekStr <#peekStr,Stream,int>`_ for now. runnableExamples: var strm = newStringStream() ## setup for reading data @@ -617,8 +554,6 @@ proc peekInt16*(s: Stream): int16 = proc readInt32*(s: Stream): int32 = ## Reads an int32 from the stream `s`. Raises `IOError` if an error occurred. - ## - ## **Note:** Not available for JS backend. Use `readStr <#readStr,Stream,int>`_ for now. runnableExamples: var strm = newStringStream() ## setup for reading data @@ -636,8 +571,6 @@ proc readInt32*(s: Stream): int32 = proc peekInt32*(s: Stream): int32 = ## Peeks an int32 from the stream `s`. Raises `IOError` if an error occurred. - ## - ## **Note:** Not available for JS backend. Use `peekStr <#peekStr,Stream,int>`_ for now. runnableExamples: var strm = newStringStream() ## setup for reading data @@ -657,8 +590,6 @@ proc peekInt32*(s: Stream): int32 = proc readInt64*(s: Stream): int64 = ## Reads an int64 from the stream `s`. Raises `IOError` if an error occurred. - ## - ## **Note:** Not available for JS backend. Use `readStr <#readStr,Stream,int>`_ for now. runnableExamples: var strm = newStringStream() ## setup for reading data @@ -676,8 +607,6 @@ proc readInt64*(s: Stream): int64 = proc peekInt64*(s: Stream): int64 = ## Peeks an int64 from the stream `s`. Raises `IOError` if an error occurred. - ## - ## **Note:** Not available for JS backend. Use `peekStr <#peekStr,Stream,int>`_ for now. runnableExamples: var strm = newStringStream() ## setup for reading data @@ -697,8 +626,6 @@ proc peekInt64*(s: Stream): int64 = proc readUint8*(s: Stream): uint8 = ## Reads an uint8 from the stream `s`. Raises `IOError` if an error occurred. - ## - ## **Note:** Not available for JS backend. Use `readStr <#readStr,Stream,int>`_ for now. runnableExamples: var strm = newStringStream() ## setup for reading data @@ -716,8 +643,6 @@ proc readUint8*(s: Stream): uint8 = proc peekUint8*(s: Stream): uint8 = ## Peeks an uint8 from the stream `s`. Raises `IOError` if an error occurred. - ## - ## **Note:** Not available for JS backend. Use `peekStr <#peekStr,Stream,int>`_ for now. runnableExamples: var strm = newStringStream() ## setup for reading data @@ -737,8 +662,6 @@ proc peekUint8*(s: Stream): uint8 = proc readUint16*(s: Stream): uint16 = ## Reads an uint16 from the stream `s`. Raises `IOError` if an error occurred. - ## - ## **Note:** Not available for JS backend. Use `readStr <#readStr,Stream,int>`_ for now. runnableExamples: var strm = newStringStream() ## setup for reading data @@ -756,8 +679,6 @@ proc readUint16*(s: Stream): uint16 = proc peekUint16*(s: Stream): uint16 = ## Peeks an uint16 from the stream `s`. Raises `IOError` if an error occurred. - ## - ## **Note:** Not available for JS backend. Use `peekStr <#peekStr,Stream,int>`_ for now. runnableExamples: var strm = newStringStream() ## setup for reading data @@ -777,8 +698,6 @@ proc peekUint16*(s: Stream): uint16 = proc readUint32*(s: Stream): uint32 = ## Reads an uint32 from the stream `s`. Raises `IOError` if an error occurred. - ## - ## **Note:** Not available for JS backend. Use `readStr <#readStr,Stream,int>`_ for now. runnableExamples: var strm = newStringStream() ## setup for reading data @@ -797,8 +716,6 @@ proc readUint32*(s: Stream): uint32 = proc peekUint32*(s: Stream): uint32 = ## Peeks an uint32 from the stream `s`. Raises `IOError` if an error occurred. - ## - ## **Note:** Not available for JS backend. Use `peekStr <#peekStr,Stream,int>`_ for now. runnableExamples: var strm = newStringStream() ## setup for reading data @@ -818,8 +735,6 @@ proc peekUint32*(s: Stream): uint32 = proc readUint64*(s: Stream): uint64 = ## Reads an uint64 from the stream `s`. Raises `IOError` if an error occurred. - ## - ## **Note:** Not available for JS backend. Use `readStr <#readStr,Stream,int>`_ for now. runnableExamples: var strm = newStringStream() ## setup for reading data @@ -837,8 +752,6 @@ proc readUint64*(s: Stream): uint64 = proc peekUint64*(s: Stream): uint64 = ## Peeks an uint64 from the stream `s`. Raises `IOError` if an error occurred. - ## - ## **Note:** Not available for JS backend. Use `peekStr <#peekStr,Stream,int>`_ for now. runnableExamples: var strm = newStringStream() ## setup for reading data @@ -858,8 +771,6 @@ proc peekUint64*(s: Stream): uint64 = proc readFloat32*(s: Stream): float32 = ## Reads a float32 from the stream `s`. Raises `IOError` if an error occurred. - ## - ## **Note:** Not available for JS backend. Use `readStr <#readStr,Stream,int>`_ for now. runnableExamples: var strm = newStringStream() ## setup for reading data @@ -877,8 +788,6 @@ proc readFloat32*(s: Stream): float32 = proc peekFloat32*(s: Stream): float32 = ## Peeks a float32 from the stream `s`. Raises `IOError` if an error occurred. - ## - ## **Note:** Not available for JS backend. Use `peekStr <#peekStr,Stream,int>`_ for now. runnableExamples: var strm = newStringStream() ## setup for reading data @@ -898,8 +807,6 @@ proc peekFloat32*(s: Stream): float32 = proc readFloat64*(s: Stream): float64 = ## Reads a float64 from the stream `s`. Raises `IOError` if an error occurred. - ## - ## **Note:** Not available for JS backend. Use `readStr <#readStr,Stream,int>`_ for now. runnableExamples: var strm = newStringStream() ## setup for reading data @@ -917,8 +824,6 @@ proc readFloat64*(s: Stream): float64 = proc peekFloat64*(s: Stream): float64 = ## Peeks a float64 from the stream `s`. Raises `IOError` if an error occurred. - ## - ## **Note:** Not available for JS backend. Use `peekStr <#peekStr,Stream,int>`_ for now. runnableExamples: var strm = newStringStream() ## setup for reading data @@ -936,20 +841,7 @@ proc peekFloat64*(s: Stream): float64 = peek(s, result) -proc readStrPrivate(s: Stream, length: int, str: var string) = - if length > len(str): setLen(str, length) - when defined(js): - let L = readData(s, addr(str), length) - else: - let L = readData(s, cstring(str), length) - if L != len(str): setLen(str, L) - -proc readStr*(s: Stream, length: int, str: var string) {.since: (1, 3).} = - ## Reads a string of length `length` from the stream `s`. Raises `IOError` if - ## an error occurred. - readStrPrivate(s, length, str) - -proc readStr*(s: Stream, length: int): string = +proc readStr*(s: Stream, length: int): TaintedString = ## Reads a string of length `length` from the stream `s`. Raises `IOError` if ## an error occurred. runnableExamples: @@ -959,23 +851,12 @@ proc readStr*(s: Stream, length: int): string = doAssert strm.readStr(2) == "e" doAssert strm.readStr(2) == "" strm.close() - result = newString(length) - readStrPrivate(s, length, result) -proc peekStrPrivate(s: Stream, length: int, str: var string) = - if length > len(str): setLen(str, length) - when defined(js): - let L = peekData(s, addr(str), length) - else: - let L = peekData(s, cstring(str), length) - if L != len(str): setLen(str, L) + result = newString(length).TaintedString + var L = readData(s, cstring(result), length) + if L != length: setLen(result.string, L) -proc peekStr*(s: Stream, length: int, str: var string) {.since: (1, 3).} = - ## Peeks a string of length `length` from the stream `s`. Raises `IOError` if - ## an error occurred. - peekStrPrivate(s, length, str) - -proc peekStr*(s: Stream, length: int): string = +proc peekStr*(s: Stream, length: int): TaintedString = ## Peeks a string of length `length` from the stream `s`. Raises `IOError` if ## an error occurred. runnableExamples: @@ -986,10 +867,12 @@ proc peekStr*(s: Stream, length: int): string = doAssert strm.readStr(2) == "ab" doAssert strm.peekStr(2) == "cd" strm.close() - result = newString(length) - peekStrPrivate(s, length, result) -proc readLine*(s: Stream, line: var string): bool = + result = newString(length).TaintedString + var L = peekData(s, cstring(result), length) + if L != length: setLen(result.string, L) + +proc readLine*(s: Stream, line: var TaintedString): bool = ## Reads a line of text from the stream `s` into `line`. `line` must not be ## ``nil``! May throw an IO exception. ## @@ -1001,7 +884,7 @@ proc readLine*(s: Stream, line: var string): bool = ## See also: ## * `readLine(Stream) proc <#readLine,Stream>`_ ## * `peekLine(Stream) proc <#peekLine,Stream>`_ - ## * `peekLine(Stream, string) proc <#peekLine,Stream,string>`_ + ## * `peekLine(Stream, TaintedString) proc <#peekLine,Stream,TaintedString>`_ runnableExamples: var strm = newStringStream("The first line\nthe second line\nthe third line") var line = "" @@ -1019,7 +902,13 @@ proc readLine*(s: Stream, line: var string): bool = result = s.readLineImpl(s, line) else: # fallback - line.setLen(0) + when nimvm: #Bug #12282 + when taintMode: + line.string.setLen(0) + else: + line.setLen(0) + else: + line.string.setLen(0) while true: var c = readChar(s) if c == '\c': @@ -1029,10 +918,16 @@ proc readLine*(s: Stream, line: var string): bool = elif c == '\0': if line.len > 0: break else: return false - line.add(c) + when nimvm: #Bug #12282 + when taintMode: + line.string.add(c) + else: + line.add(c) + else: + line.string.add(c) result = true -proc peekLine*(s: Stream, line: var string): bool = +proc peekLine*(s: Stream, line: var TaintedString): bool = ## Peeks a line of text from the stream `s` into `line`. `line` must not be ## ``nil``! May throw an IO exception. ## @@ -1043,7 +938,7 @@ proc peekLine*(s: Stream, line: var string): bool = ## ## See also: ## * `readLine(Stream) proc <#readLine,Stream>`_ - ## * `readLine(Stream, string) proc <#readLine,Stream,string>`_ + ## * `readLine(Stream, TaintedString) proc <#readLine,Stream,TaintedString>`_ ## * `peekLine(Stream) proc <#peekLine,Stream>`_ runnableExamples: var strm = newStringStream("The first line\nthe second line\nthe third line") @@ -1063,15 +958,15 @@ proc peekLine*(s: Stream, line: var string): bool = defer: setPosition(s, pos) result = readLine(s, line) -proc readLine*(s: Stream): string = +proc readLine*(s: Stream): TaintedString = ## Reads a line from a stream `s`. Raises `IOError` if an error occurred. ## ## **Note:** This is not very efficient. ## ## See also: - ## * `readLine(Stream, string) proc <#readLine,Stream,string>`_ + ## * `readLine(Stream, TaintedString) proc <#readLine,Stream,TaintedString>`_ ## * `peekLine(Stream) proc <#peekLine,Stream>`_ - ## * `peekLine(Stream, string) proc <#peekLine,Stream,string>`_ + ## * `peekLine(Stream, TaintedString) proc <#peekLine,Stream,TaintedString>`_ runnableExamples: var strm = newStringStream("The first line\nthe second line\nthe third line") doAssert strm.readLine() == "The first line" @@ -1080,7 +975,7 @@ proc readLine*(s: Stream): string = doAssertRaises(IOError): discard strm.readLine() strm.close() - result = "" + result = TaintedString"" if s.atEnd: raise newEIO("cannot read from stream") while true: @@ -1091,17 +986,17 @@ proc readLine*(s: Stream): string = if c == '\L' or c == '\0': break else: - result.add(c) + result.string.add(c) -proc peekLine*(s: Stream): string = +proc peekLine*(s: Stream): TaintedString = ## Peeks a line from a stream `s`. Raises `IOError` if an error occurred. ## ## **Note:** This is not very efficient. ## ## See also: ## * `readLine(Stream) proc <#readLine,Stream>`_ - ## * `readLine(Stream, string) proc <#readLine,Stream,string>`_ - ## * `peekLine(Stream, string) proc <#peekLine,Stream,string>`_ + ## * `readLine(Stream, TaintedString) proc <#readLine,Stream,TaintedString>`_ + ## * `peekLine(Stream, TaintedString) proc <#peekLine,Stream,TaintedString>`_ runnableExamples: var strm = newStringStream("The first line\nthe second line\nthe third line") doAssert strm.peekLine() == "The first line" @@ -1115,13 +1010,13 @@ proc peekLine*(s: Stream): string = defer: setPosition(s, pos) result = readLine(s) -iterator lines*(s: Stream): string = +iterator lines*(s: Stream): TaintedString = ## Iterates over every line in the stream. ## The iteration is based on ``readLine``. ## ## See also: ## * `readLine(Stream) proc <#readLine,Stream>`_ - ## * `readLine(Stream, string) proc <#readLine,Stream,string>`_ + ## * `readLine(Stream, TaintedString) proc <#readLine,Stream,TaintedString>`_ runnableExamples: var strm = newStringStream("The first line\nthe second line\nthe third line") var lines: seq[string] @@ -1130,20 +1025,24 @@ iterator lines*(s: Stream): string = doAssert lines == @["The first line", "the second line", "the third line"] strm.close() - var line: string + var line: TaintedString while s.readLine(line): yield line type StringStream* = ref StringStreamObj ## A stream that encapsulates a string. + ## + ## **Note:** Not available for JS backend. StringStreamObj* = object of StreamObj ## A string stream object. + ## + ## **Note:** Not available for JS backend. data*: string ## A string data. ## This is updated when called `writeLine` etc. pos: int -when (NimMajor, NimMinor) < (1, 3) and defined(js): +when defined(js): #This section exists so that string streams work at compile time for the js backend proc ssAtEnd(s: Stream): bool {.compileTime.} = var s = StringStream(s) return s.pos >= s.data.len @@ -1167,7 +1066,10 @@ when (NimMajor, NimMinor) < (1, 3) and defined(js): proc ssClose(s: Stream) {.compileTime.} = var s = StringStream(s) - s.data = "" + when defined(nimNoNilSeqs): + s.data = "" + else: + s.data = nil proc newStringStream*(s: string = ""): owned StringStream {.compileTime.} = new(result) @@ -1193,7 +1095,7 @@ when (NimMajor, NimMinor) < (1, 3) and defined(js): if readBytes < bufferSize: break -else: # after 1.3 or JS not defined +else: proc ssAtEnd(s: Stream): bool = var s = StringStream(s) return s.pos >= s.data.len @@ -1208,16 +1110,11 @@ else: # after 1.3 or JS not defined proc ssReadDataStr(s: Stream, buffer: var string, slice: Slice[int]): int = var s = StringStream(s) - when nimvm: - discard - else: - when declared(prepareMutation): - prepareMutation(buffer) # buffer might potentially be a CoW literal with ARC result = min(slice.b + 1 - slice.a, s.data.len - s.pos) if result > 0: - jsOrVmBlock: + when nimvm: buffer[slice.a.. 0: - when defined(js): - try: - cast[ptr string](buffer)[][0.. 0: - when defined(js): - try: - cast[ptr string](buffer)[][0.. s.data.len: setLen(s.data, s.pos + bufLen) - when defined(js): - try: - s.data[s.pos..`_ creates a file stream from ## opened File. @@ -1293,176 +1174,168 @@ else: # after 1.3 or JS not defined new(result) result.data = s - when nimvm: - discard - else: - when declared(prepareMutation): - prepareMutation(result.data) # Allows us to mutate using `addr` logic like `copyMem`, otherwise it errors. result.pos = 0 result.closeImpl = ssClose result.atEndImpl = ssAtEnd result.setPositionImpl = ssSetPosition result.getPositionImpl = ssGetPosition + result.readDataImpl = ssReadData + result.peekDataImpl = ssPeekData + result.writeDataImpl = ssWriteData result.readDataStrImpl = ssReadDataStr - when nimvm: - discard - else: - result.readDataImpl = ssReadData - result.peekDataImpl = ssPeekData - result.writeDataImpl = ssWriteData -type - FileStream* = ref FileStreamObj - ## A stream that encapsulates a `File`. + type + FileStream* = ref FileStreamObj + ## A stream that encapsulates a `File`. + ## + ## **Note:** Not available for JS backend. + FileStreamObj* = object of Stream + ## A file stream object. + ## + ## **Note:** Not available for JS backend. + f: File + + proc fsClose(s: Stream) = + if FileStream(s).f != nil: + close(FileStream(s).f) + FileStream(s).f = nil + proc fsFlush(s: Stream) = flushFile(FileStream(s).f) + proc fsAtEnd(s: Stream): bool = return endOfFile(FileStream(s).f) + proc fsSetPosition(s: Stream, pos: int) = setFilePos(FileStream(s).f, pos) + proc fsGetPosition(s: Stream): int = return int(getFilePos(FileStream(s).f)) + + proc fsReadData(s: Stream, buffer: pointer, bufLen: int): int = + result = readBuffer(FileStream(s).f, buffer, bufLen) + + proc fsReadDataStr(s: Stream, buffer: var string, slice: Slice[int]): int = + result = readBuffer(FileStream(s).f, addr buffer[slice.a], slice.b + 1 - slice.a) + + proc fsPeekData(s: Stream, buffer: pointer, bufLen: int): int = + let pos = fsGetPosition(s) + defer: fsSetPosition(s, pos) + result = readBuffer(FileStream(s).f, buffer, bufLen) + + proc fsWriteData(s: Stream, buffer: pointer, bufLen: int) = + if writeBuffer(FileStream(s).f, buffer, bufLen) != bufLen: + raise newEIO("cannot write to stream") + + proc fsReadLine(s: Stream, line: var TaintedString): bool = + result = readLine(FileStream(s).f, line) + + proc newFileStream*(f: File): owned FileStream = + ## Creates a new stream from the file `f`. ## ## **Note:** Not available for JS backend. - FileStreamObj* = object of Stream - ## A file stream object. ## - ## **Note:** Not available for JS backend. - f: File - -proc fsClose(s: Stream) = - if FileStream(s).f != nil: - close(FileStream(s).f) - FileStream(s).f = nil -proc fsFlush(s: Stream) = flushFile(FileStream(s).f) -proc fsAtEnd(s: Stream): bool = return endOfFile(FileStream(s).f) -proc fsSetPosition(s: Stream, pos: int) = setFilePos(FileStream(s).f, pos) -proc fsGetPosition(s: Stream): int = return int(getFilePos(FileStream(s).f)) - -proc fsReadData(s: Stream, buffer: pointer, bufLen: int): int = - result = readBuffer(FileStream(s).f, buffer, bufLen) - -proc fsReadDataStr(s: Stream, buffer: var string, slice: Slice[int]): int = - result = readBuffer(FileStream(s).f, addr buffer[slice.a], slice.b + 1 - slice.a) - -proc fsPeekData(s: Stream, buffer: pointer, bufLen: int): int = - let pos = fsGetPosition(s) - defer: fsSetPosition(s, pos) - result = readBuffer(FileStream(s).f, buffer, bufLen) - -proc fsWriteData(s: Stream, buffer: pointer, bufLen: int) = - if writeBuffer(FileStream(s).f, buffer, bufLen) != bufLen: - raise newEIO("cannot write to stream") - -proc fsReadLine(s: Stream, line: var string): bool = - result = readLine(FileStream(s).f, line) - -proc newFileStream*(f: File): owned FileStream = - ## Creates a new stream from the file `f`. - ## - ## **Note:** Not available for JS backend. - ## - ## See also: - ## * `newStringStream proc <#newStringStream,string>`_ creates a new stream - ## from string. - ## * `newFileStream proc <#newFileStream,string,FileMode,int>`_ is the same - ## as using `open proc `_ - ## on Examples. - ## * `openFileStream proc <#openFileStream,string,FileMode,int>`_ creates a - ## file stream from the file name and the mode. - runnableExamples: - ## Input (somefile.txt): - ## The first line - ## the second line - ## the third line - var f: File - if open(f, "somefile.txt", fmRead, -1): - var strm = newFileStream(f) - var line = "" - while strm.readLine(line): - echo line - ## Output: - ## The first line - ## the second line - ## the third line - strm.close() - - new(result) - result.f = f - result.closeImpl = fsClose - result.atEndImpl = fsAtEnd - result.setPositionImpl = fsSetPosition - result.getPositionImpl = fsGetPosition - result.readDataStrImpl = fsReadDataStr - result.readDataImpl = fsReadData - result.readLineImpl = fsReadLine - result.peekDataImpl = fsPeekData - result.writeDataImpl = fsWriteData - result.flushImpl = fsFlush - -proc newFileStream*(filename: string, mode: FileMode = fmRead, - bufSize: int = -1): owned FileStream = - ## Creates a new stream from the file named `filename` with the mode `mode`. - ## - ## If the file cannot be opened, `nil` is returned. See the `io module - ## `_ for a list of available `FileMode enums `_. - ## - ## **Note:** - ## * **This function returns nil in case of failure.** - ## To prevent unexpected behavior and ensure proper error handling, - ## use `openFileStream proc <#openFileStream,string,FileMode,int>`_ - ## instead. - ## * Not available for JS backend. - ## - ## See also: - ## * `newStringStream proc <#newStringStream,string>`_ creates a new stream - ## from string. - ## * `newFileStream proc <#newFileStream,File>`_ creates a file stream from - ## opened File. - ## * `openFileStream proc <#openFileStream,string,FileMode,int>`_ creates a - ## file stream from the file name and the mode. - runnableExamples: - from std/os import removeFile - var strm = newFileStream("somefile.txt", fmWrite) - if not isNil(strm): - strm.writeLine("The first line") - strm.writeLine("the second line") - strm.writeLine("the third line") - strm.close() - ## Output (somefile.txt) - ## The first line - ## the second line - ## the third line - removeFile("somefile.txt") - - var f: File - if open(f, filename, mode, bufSize): result = newFileStream(f) - -proc openFileStream*(filename: string, mode: FileMode = fmRead, - bufSize: int = -1): owned FileStream = - ## Creates a new stream from the file named `filename` with the mode `mode`. - ## If the file cannot be opened, an IO exception is raised. - ## - ## **Note:** Not available for JS backend. - ## - ## See also: - ## * `newStringStream proc <#newStringStream,string>`_ creates a new stream - ## from string. - ## * `newFileStream proc <#newFileStream,File>`_ creates a file stream from - ## opened File. - ## * `newFileStream proc <#newFileStream,string,FileMode,int>`_ creates a - ## file stream from the file name and the mode. - runnableExamples: - try: + ## See also: + ## * `newStringStream proc <#newStringStream,string>`_ creates a new stream + ## from string. + ## * `newFileStream proc <#newFileStream,string,FileMode,int>`_ is the same + ## as using `open proc `_ + ## on Examples. + ## * `openFileStream proc <#openFileStream,string,FileMode,int>`_ creates a + ## file stream from the file name and the mode. + runnableExamples: ## Input (somefile.txt): ## The first line ## the second line ## the third line - var strm = openFileStream("somefile.txt") - echo strm.readLine() - ## Output: - ## The first line - strm.close() - except: - stderr.write getCurrentExceptionMsg() + var f: File + if open(f, "somefile.txt", fmRead, -1): + var strm = newFileStream(f) + var line = "" + while strm.readLine(line): + echo line + ## Output: + ## The first line + ## the second line + ## the third line + strm.close() - var f: File - if open(f, filename, mode, bufSize): - return newFileStream(f) - else: - raise newEIO("cannot open file stream: " & filename) + new(result) + result.f = f + result.closeImpl = fsClose + result.atEndImpl = fsAtEnd + result.setPositionImpl = fsSetPosition + result.getPositionImpl = fsGetPosition + result.readDataStrImpl = fsReadDataStr + result.readDataImpl = fsReadData + result.readLineImpl = fsReadLine + result.peekDataImpl = fsPeekData + result.writeDataImpl = fsWriteData + result.flushImpl = fsFlush + + proc newFileStream*(filename: string, mode: FileMode = fmRead, + bufSize: int = -1): owned FileStream = + ## Creates a new stream from the file named `filename` with the mode `mode`. + ## + ## If the file cannot be opened, `nil` is returned. See the `io module + ## `_ for a list of available `FileMode enums `_. + ## + ## **Note:** + ## * **This function returns nil in case of failure.** + ## To prevent unexpected behavior and ensure proper error handling, + ## use `openFileStream proc <#openFileStream,string,FileMode,int>`_ + ## instead. + ## * Not available for JS backend. + ## + ## See also: + ## * `newStringStream proc <#newStringStream,string>`_ creates a new stream + ## from string. + ## * `newFileStream proc <#newFileStream,File>`_ creates a file stream from + ## opened File. + ## * `openFileStream proc <#openFileStream,string,FileMode,int>`_ creates a + ## file stream from the file name and the mode. + runnableExamples: + from os import removeFile + var strm = newFileStream("somefile.txt", fmWrite) + if not isNil(strm): + strm.writeLine("The first line") + strm.writeLine("the second line") + strm.writeLine("the third line") + strm.close() + ## Output (somefile.txt) + ## The first line + ## the second line + ## the third line + removeFile("somefile.txt") + + var f: File + if open(f, filename, mode, bufSize): result = newFileStream(f) + + proc openFileStream*(filename: string, mode: FileMode = fmRead, + bufSize: int = -1): owned FileStream = + ## Creates a new stream from the file named `filename` with the mode `mode`. + ## If the file cannot be opened, an IO exception is raised. + ## + ## **Note:** Not available for JS backend. + ## + ## See also: + ## * `newStringStream proc <#newStringStream,string>`_ creates a new stream + ## from string. + ## * `newFileStream proc <#newFileStream,File>`_ creates a file stream from + ## opened File. + ## * `newFileStream proc <#newFileStream,string,FileMode,int>`_ creates a + ## file stream from the file name and the mode. + runnableExamples: + try: + ## Input (somefile.txt): + ## The first line + ## the second line + ## the third line + var strm = openFileStream("somefile.txt") + echo strm.readLine() + ## Output: + ## The first line + strm.close() + except: + stderr.write getCurrentExceptionMsg() + + var f: File + if open(f, filename, mode, bufSize): + return newFileStream(f) + else: + raise newEIO("cannot open file stream: " & filename) when false: type @@ -1530,7 +1403,20 @@ when false: of fmReadWrite: flags = O_RDWR or int(O_CREAT) of fmReadWriteExisting: flags = O_RDWR of fmAppend: flags = O_WRONLY or int(O_CREAT) or O_APPEND - static: doAssert false # handle bug #17888 var handle = open(filename, flags) if handle < 0: raise newEOS("posix.open() call failed") result = newFileHandleStream(handle) + +when isMainModule and defined(testing): + var ss = newStringStream("The quick brown fox jumped over the lazy dog.\nThe lazy dog ran") + assert(ss.getPosition == 0) + assert(ss.peekStr(5) == "The q") + assert(ss.getPosition == 0) # haven't moved + assert(ss.readStr(5) == "The q") + assert(ss.getPosition == 5) # did move + assert(ss.peekLine() == "uick brown fox jumped over the lazy dog.") + assert(ss.getPosition == 5) # haven't moved + var str = newString(100) + assert(ss.peekLine(str)) + assert(str == "uick brown fox jumped over the lazy dog.") + assert(ss.getPosition == 5) # haven't moved diff --git a/lib/pure/streamwrapper.nim b/lib/pure/streamwrapper.nim deleted file mode 100644 index a6c1901d2..000000000 --- a/lib/pure/streamwrapper.nim +++ /dev/null @@ -1,121 +0,0 @@ -# -# -# Nim's Runtime Library -# (c) Copyright 2020 Andreas Rumpf -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# - -## This module implements stream wrapper. -## -## **Since** version 1.2. - -import deques, streams - -when defined(nimPreviewSlimSystem): - import std/assertions - - -type - PipeOutStream*[T] = ref object of T - # When stream peek operation is called, it reads from base stream - # type using `baseReadDataImpl` and stores the content to this buffer. - # Next stream read operation returns data in the buffer so that previus peek - # operation looks like didn't changed read positon. - # When stream read operation that returns N byte data is called and the size is smaller than buffer size, - # first N elements are removed from buffer. - # Deque type can do such operation more efficiently than seq type. - buffer: Deque[char] - baseReadLineImpl: typeof(StreamObj.readLineImpl) - baseReadDataImpl: typeof(StreamObj.readDataImpl) - -proc posReadLine[T](s: Stream, line: var string): bool = - var s = PipeOutStream[T](s) - assert s.baseReadLineImpl != nil - - let n = s.buffer.len - line.setLen(0) - for i in 0.. 0 - line.add(c) - - var line2: string - result = s.baseReadLineImpl(s, line2) - line.add line2 - -proc posReadData[T](s: Stream, buffer: pointer, bufLen: int): int = - var s = PipeOutStream[T](s) - assert s.baseReadDataImpl != nil - - let - dest = cast[ptr UncheckedArray[char]](buffer) - n = min(s.buffer.len, bufLen) - result = n - for i in 0.. n: - result += s.baseReadDataImpl(s, addr dest[n], bufLen - n) - -proc posReadDataStr[T](s: Stream, buffer: var string, slice: Slice[int]): int = - posReadData[T](s, addr buffer[slice.a], slice.len) - -proc posPeekData[T](s: Stream, buffer: pointer, bufLen: int): int = - var s = PipeOutStream[T](s) - assert s.baseReadDataImpl != nil - - let - dest = cast[ptr UncheckedArray[char]](buffer) - n = min(s.buffer.len, bufLen) - - result = n - for i in 0.. n: - let - newDataNeeded = bufLen - n - numRead = s.baseReadDataImpl(s, addr dest[n], newDataNeeded) - result += numRead - for i in 0..`_. This has some surprising effects: -]## -runnableExamples: - let msg = "hello" - assert fmt"{msg}\n" == "hello\\n" +.. code-block:: nim -##[ -Because the literal is a raw string literal, the `\n` is not interpreted as + import strformat + let msg = "hello" + doAssert fmt"{msg}\n" == "hello\\n" + +Because the literal is a raw string literal, the ``\n`` is not interpreted as an escape sequence. -There are multiple ways to get around this, including the use of the `&` operator: -]## +There are multiple ways to get around this, including the use of the ``&`` +operator: -runnableExamples: - let msg = "hello" +.. code-block:: nim - assert &"{msg}\n" == "hello\n" + import strformat + let msg = "hello" - assert fmt"{msg}{'\n'}" == "hello\n" - assert fmt("{msg}\n") == "hello\n" - assert "{msg}\n".fmt == "hello\n" + doAssert &"{msg}\n" == "hello\n" + + doAssert fmt"{msg}{'\n'}" == "hello\n" + doAssert fmt("{msg}\n") == "hello\n" + doAssert "{msg}\n".fmt == "hello\n" -##[ The choice of style is up to you. -# Formatting strings -]## +Formatting strings +================== -runnableExamples: - assert &"""{"abc":>4}""" == " abc" - assert &"""{"abc":<4}""" == "abc " +.. code-block:: nim -##[ -# Formatting floats -]## + import strformat -runnableExamples: - assert fmt"{-12345:08}" == "-0012345" - assert fmt"{-1:3}" == " -1" - assert fmt"{-1:03}" == "-01" - assert fmt"{16:#X}" == "0x10" + doAssert &"""{"abc":>4}""" == " abc" + doAssert &"""{"abc":<4}""" == "abc " - assert fmt"{123.456}" == "123.456" - assert fmt"{123.456:>9.3f}" == " 123.456" - assert fmt"{123.456:9.3f}" == " 123.456" - assert fmt"{123.456:9.4f}" == " 123.4560" - assert fmt"{123.456:>9.0f}" == " 123." - assert fmt"{123.456:<9.4f}" == "123.4560 " +Formatting floats +================= - assert fmt"{123.456:e}" == "1.234560e+02" - assert fmt"{123.456:>13e}" == " 1.234560e+02" - assert fmt"{123.456:13e}" == " 1.234560e+02" +.. code-block:: nim -##[ -# Expressions -]## -runnableExamples: - let x = 3.14 - assert fmt"{(if x!=0: 1.0/x else: 0):.5}" == "0.31847" - assert fmt"""{(block: - var res: string - for i in 1..15: - res.add (if i mod 15 == 0: "FizzBuzz" - elif i mod 5 == 0: "Buzz" - elif i mod 3 == 0: "Fizz" - else: $i) & " " - res)}""" == "1 2 Fizz 4 Buzz Fizz 7 8 Fizz Buzz 11 Fizz 13 14 FizzBuzz " -##[ -# Debugging strings + import strformat -`fmt"{expr=}"` expands to `fmt"expr={expr}"` namely the text of the expression, -an equal sign and the results of evaluated expression. -]## + doAssert fmt"{-12345:08}" == "-0012345" + doAssert fmt"{-1:3}" == " -1" + doAssert fmt"{-1:03}" == "-01" + doAssert fmt"{16:#X}" == "0x10" -runnableExamples: - assert fmt"{123.456=}" == "123.456=123.456" - assert fmt"{123.456=:>9.3f}" == "123.456= 123.456" + doAssert fmt"{123.456}" == "123.456" + doAssert fmt"{123.456:>9.3f}" == " 123.456" + doAssert fmt"{123.456:9.3f}" == " 123.456" + doAssert fmt"{123.456:9.4f}" == " 123.4560" + doAssert fmt"{123.456:>9.0f}" == " 123." + doAssert fmt"{123.456:<9.4f}" == "123.4560 " - let x = "hello" - assert fmt"{x=}" == "x=hello" - assert fmt"{x =}" == "x =hello" + doAssert fmt"{123.456:e}" == "1.234560e+02" + doAssert fmt"{123.456:>13e}" == " 1.234560e+02" + doAssert fmt"{123.456:13e}" == " 1.234560e+02" - let y = 3.1415926 - assert fmt"{y=:.2f}" == fmt"y={y:.2f}" - assert fmt"{y=}" == fmt"y={y}" - assert fmt"{y = : <8}" == fmt"y = 3.14159 " - proc hello(a: string, b: float): int = 12 - assert fmt"{hello(x, y) = }" == "hello(x, y) = 12" - assert fmt"{x.hello(y) = }" == "x.hello(y) = 12" - assert fmt"{hello x, y = }" == "hello x, y = 12" +Implementation details +====================== -##[ -Note that it is space sensitive: -]## - -runnableExamples: - let x = "12" - assert fmt"{x=}" == "x=12" - assert fmt"{x =:}" == "x =12" - assert fmt"{x =}" == "x =12" - assert fmt"{x= :}" == "x= 12" - assert fmt"{x= }" == "x= 12" - assert fmt"{x = :}" == "x = 12" - assert fmt"{x = }" == "x = 12" - assert fmt"{x = :}" == "x = 12" - assert fmt"{x = }" == "x = 12" - -##[ -# Implementation details - -An expression like `&"{key} is {value:arg} {{z}}"` is transformed into: +An expression like ``&"{key} is {value:arg} {{z}}"`` is transformed into: .. code-block:: nim var temp = newStringOfCap(educatedCapGuess) - temp.formatValue(key, "") - temp.add(" is ") - temp.formatValue(value, arg) - temp.add(" {z}") + temp.formatValue key, "" + temp.add " is " + temp.formatValue value, arg + temp.add " {z}" temp Parts of the string that are enclosed in the curly braces are interpreted -as Nim code. To escape a `{` or `}`, double it. +as Nim code, to escape an ``{`` or ``}`` double it. -Within a curly expression, however, `{`, `}`, must be escaped with a backslash. - -To enable evaluating Nim expressions within curlies, colons inside parentheses -do not need to be escaped. -]## - -runnableExamples: - let x = "hello" - assert fmt"""{ "\{(" & x & ")\}" }""" == "{(hello)}" - assert fmt"""{{({ x })}}""" == "{(hello)}" - assert fmt"""{ $(\{x:1,"world":2\}) }""" == """[("hello", 1), ("world", 2)]""" - -##[ -`&` delegates most of the work to an open overloaded set -of `formatValue` procs. The required signature for a type `T` that supports -formatting is usually `proc formatValue(result: var string; x: T; specifier: string)`. +``&`` delegates most of the work to an open overloaded set +of ``formatValue`` procs. The required signature for a type ``T`` that supports +formatting is usually ``proc formatValue(result: var string; x: T; specifier: string)``. The subexpression after the colon -(`arg` in `&"{key} is {value:arg} {{z}}"`) is optional. It will be passed as -the last argument to `formatValue`. When the colon with the subexpression it is +(``arg`` in ``&"{key} is {value:arg} {{z}}"``) is optional. It will be passed as +the last argument to ``formatValue``. When the colon with the subexpression it is left out, an empty string will be taken instead. For strings and numeric types the optional argument is a so-called "standard format specifier". -# Standard format specifiers for strings, integers and floats -The general form of a standard format specifier is: +Standard format specifier for strings, integers and floats +========================================================== - [[fill]align][sign][#][0][minimumwidth][.precision][type] -The square brackets `[]` indicate an optional element. +The general form of a standard format specifier is:: -The optional `align` flag can be one of the following: + [[fill]align][sign][#][0][minimumwidth][.precision][type] -`<` -: Forces the field to be left-aligned within the available +The square brackets ``[]`` indicate an optional element. + +The optional align flag can be one of the following: + +'<' + Forces the field to be left-aligned within the available space. (This is the default for strings.) -`>` -: Forces the field to be right-aligned within the available space. +'>' + Forces the field to be right-aligned within the available space. (This is the default for numbers.) -`^` -: Forces the field to be centered within the available space. +'^' + Forces the field to be centered within the available space. Note that unless a minimum field width is defined, the field width will always be the same size as the data to fill it, so that the alignment option has no meaning in this case. -The optional `fill` character defines the character to be used to pad +The optional 'fill' character defines the character to be used to pad the field to the minimum width. The fill character, if present, must be followed by an alignment flag. -The `sign` option is only valid for numeric types, and can be one of the following: +The 'sign' option is only valid for numeric types, and can be one of the following: ================= ==================================================== Sign Meaning ================= ==================================================== -`+` Indicates that a sign should be used for both +``+`` Indicates that a sign should be used for both positive as well as negative numbers. -`-` Indicates that a sign should be used only for +``-`` Indicates that a sign should be used only for negative numbers (this is the default behavior). (space) Indicates that a leading space should be used on positive numbers. ================= ==================================================== -If the `#` character is present, integers use the 'alternate form' for formatting. -This means that binary, octal and hexadecimal output will be prefixed -with `0b`, `0o` and `0x`, respectively. +If the '#' character is present, integers use the 'alternate form' for formatting. +This means that binary, octal, and hexadecimal output will be prefixed +with '0b', '0o', and '0x', respectively. -`width` is a decimal integer defining the minimum field width. If not specified, +'width' is a decimal integer defining the minimum field width. If not specified, then the field width will be determined by the content. -If the width field is preceded by a zero (`0`) character, this enables +If the width field is preceded by a zero ('0') character, this enables zero-padding. -The `precision` is a decimal number indicating how many digits should be displayed +The 'precision' is a decimal number indicating how many digits should be displayed after the decimal point in a floating point conversion. For non-numeric types the field indicates the maximum field size - in other words, how many characters will be used from the field content. The precision is ignored for integer conversions. -Finally, the `type` determines how the data should be presented. +Finally, the 'type' determines how the data should be presented. The available integer presentation types are: + ================= ==================================================== Type Result ================= ==================================================== -`b` Binary. Outputs the number in base 2. -`d` Decimal Integer. Outputs the number in base 10. -`o` Octal format. Outputs the number in base 8. -`x` Hex format. Outputs the number in base 16, using +``b`` Binary. Outputs the number in base 2. +``d`` Decimal Integer. Outputs the number in base 10. +``o`` Octal format. Outputs the number in base 8. +``x`` Hex format. Outputs the number in base 16, using lower-case letters for the digits above 9. -`X` Hex format. Outputs the number in base 16, using +``X`` Hex format. Outputs the number in base 16, using uppercase letters for the digits above 9. -(None) The same as `d`. +(None) the same as 'd' ================= ==================================================== + The available floating point presentation types are: ================= ==================================================== Type Result ================= ==================================================== -`e` Exponent notation. Prints the number in scientific - notation using the letter `e` to indicate the +``e`` Exponent notation. Prints the number in scientific + notation using the letter 'e' to indicate the exponent. -`E` Exponent notation. Same as `e` except it converts +``E`` Exponent notation. Same as 'e' except it converts the number to uppercase. -`f` Fixed point. Displays the number as a fixed-point +``f`` Fixed point. Displays the number as a fixed-point number. -`F` Fixed point. Same as `f` except it converts the +``F`` Fixed point. Same as 'f' except it converts the number to uppercase. -`g` General format. This prints the number as a +``g`` General format. This prints the number as a fixed-point number, unless the number is too - large, in which case it switches to `e` + large, in which case it switches to 'e' exponent notation. -`G` General format. Same as `g` except it switches to `E` +``G`` General format. Same as 'g' except switches to 'E' if the number gets to large. -(None) Similar to `g`, except that it prints at least one +(None) similar to 'g', except that it prints at least one digit after the decimal point. ================= ==================================================== -# Limitations + +Limitations +=========== Because of the well defined order how templates and macros are expanded, strformat cannot expand template arguments: @@ -280,46 +227,45 @@ expanded, strformat cannot expand template arguments: let x = "abc" myTemplate(x) -First the template `myTemplate` is expanded, where every identifier -`arg` is substituted with its argument. The `arg` inside the +First the template ``myTemplate`` is expanded, where every identifier +``arg`` is substituted with its argument. The ``arg`` inside the format string is not seen by this process, because it is part of a quoted string literal. It is not an identifier yet. Then the strformat -macro creates the `arg` identifier from the string literal, an +macro creates the ``arg`` identifier from the string literal. An identifier that cannot be resolved anymore. The workaround for this is to bind the template argument to a new local variable. .. code-block:: nim + template myTemplate(arg: untyped): untyped = block: let arg1 {.inject.} = arg echo "arg is: ", arg1 echo &"--- {arg1} ---" -The use of `{.inject.}` here is necessary again because of template +The use of ``{.inject.}`` here is necessary again because of template expansion order and hygienic templates. But since we generally want to -keep the hygiene of `myTemplate`, and we do not want `arg1` -to be injected into the context where `myTemplate` is expanded, -everything is wrapped in a `block`. +keep the hygienicness of ``myTemplate``, and we do not want ``arg1`` +to be injected into the context where ``myTemplate`` is expanded, +everything is wrapped in a ``block``. -# Future directions +Future directions +================= -A curly expression with commas in it like `{x, argA, argB}` could be -transformed to `formatValue(result, x, argA, argB)` in order to support +A curly expression with commas in it like ``{x, argA, argB}`` could be +transformed to ``formatValue(result, x, argA, argB)`` in order to support formatters that do not need to parse a custom language within a custom -language but instead prefer to use Nim's existing syntax. This would also -help with readability, since there is only so much you can cram into +language but instead prefer to use Nim's existing syntax. This also +helps in readability since there is only so much you can cram into single letter DSLs. + ]## import macros, parseutils, unicode import strutils except format -when defined(nimPreviewSlimSystem): - import std/assertions - - proc mkDigit(v: int, typ: char): string {.inline.} = assert(v < 26) if v < 10: @@ -327,9 +273,10 @@ proc mkDigit(v: int, typ: char): string {.inline.} = else: result = $chr(ord(if typ == 'x': 'a' else: 'A') + v - 10) -proc alignString*(s: string, minimumWidth: int; align = '\0'; fill = ' '): string = - ## Aligns `s` using the `fill` char. - ## This is only of interest if you want to write a custom `format` proc that +proc alignString*(s: string, minimumWidth: int; align = '\0'; + fill = ' '): string = + ## Aligns ``s`` using ``fill`` char. + ## This is only of interest if you want to write a custom ``format`` proc that ## should support the standard format specifiers. if minimumWidth == 0: result = s @@ -351,30 +298,28 @@ type fill*, align*: char ## Desired fill and alignment. sign*: char ## Desired sign. alternateForm*: bool ## Whether to prefix binary, octal and hex numbers - ## with `0b`, `0o`, `0x`. + ## with ``0b``, ``0o``, ``0x``. padWithZero*: bool ## Whether to pad with zeros rather than spaces. minimumWidth*, precision*: int ## Desired minimum width and precision. typ*: char ## Type like 'f', 'g' or 'd'. endPosition*: int ## End position in the format specifier after - ## `parseStandardFormatSpecifier` returned. + ## ``parseStandardFormatSpecifier`` returned. -proc formatInt(n: SomeNumber; radix: int; spec: StandardFormatSpecifier): string = - ## Converts `n` to a string. If `n` is `SomeFloat`, it casts to `int64`. - ## Conversion is done using `radix`. If result's length is less than - ## `minimumWidth`, it aligns result to the right or left (depending on `a`) - ## with the `fill` char. +proc formatInt(n: SomeNumber; radix: int; + spec: StandardFormatSpecifier): string = + ## Converts ``n`` to string. If ``n`` is `SomeFloat`, it casts to `int64`. + ## Conversion is done using ``radix``. If result's length is lesser than + ## ``minimumWidth``, it aligns result to the right or left (depending on ``a``) + ## with ``fill`` char. when n is SomeUnsignedInt: var v = n.uint64 let negative = false else: - let n = n.int64 - let negative = n < 0 - var v = - if negative: - # `uint64(-n)`, but accounts for `n == low(int64)` - uint64(not n) + 1 - else: - uint64(n) + var v = n.int64 + let negative = v.int64 < 0 + if negative: + # FIXME: overflow error for low(int64) + v = v * -1 var xx = "" if spec.alternateForm: @@ -389,9 +334,9 @@ proc formatInt(n: SomeNumber; radix: int; spec: StandardFormatSpecifier): string result = "0" else: result = "" - while v > typeof(v)(0): - let d = v mod typeof(v)(radix) - v = v div typeof(v)(radix) + while v > type(v)(0): + let d = v mod type(v)(radix) + v = v div type(v)(radix) result.add(mkDigit(d.int, spec.typ)) for idx in 0..<(result.len div 2): swap result[idx], result[result.len - idx - 1] @@ -423,13 +368,13 @@ proc formatInt(n: SomeNumber; radix: int; spec: StandardFormatSpecifier): string proc parseStandardFormatSpecifier*(s: string; start = 0; ignoreUnknownSuffix = false): StandardFormatSpecifier = ## An exported helper proc that parses the "standard format specifiers", - ## as specified by the grammar: + ## as specified by the grammar:: ## - ## [[fill]align][sign][#][0][minimumwidth][.precision][type] + ## [[fill]align][sign][#][0][minimumwidth][.precision][type] ## - ## This is only of interest if you want to write a custom `format` proc that - ## should support the standard format specifiers. If `ignoreUnknownSuffix` is true, - ## an unknown suffix after the `type` field is not an error. + ## This is only of interest if you want to write a custom ``format`` proc that + ## should support the standard format specifiers. If ``ignoreUnknownSuffix`` is true, + ## an unknown suffix after the ``type`` field is not an error. const alignChars = {'<', '>', '^'} result.fill = ' ' result.align = '\0' @@ -451,7 +396,7 @@ proc parseStandardFormatSpecifier*(s: string; start = 0; result.alternateForm = true inc i - if i + 1 < s.len and s[i] == '0' and s[i+1] in {'0'..'9'}: + if i+1 < s.len and s[i] == '0' and s[i+1] in {'0'..'9'}: result.padWithZero = true inc i @@ -473,10 +418,10 @@ proc parseStandardFormatSpecifier*(s: string; start = 0; "invalid format string, cannot parse: " & s[i..^1]) proc formatValue*[T: SomeInteger](result: var string; value: T; - specifier: string) = - ## Standard format implementation for `SomeInteger`. It makes little + specifier: string) = + ## Standard format implementation for ``SomeInteger``. It makes little ## sense to call this directly, but it is required to exist - ## by the `&` macro. + ## by the ``&`` macro. if specifier.len == 0: result.add $value return @@ -494,9 +439,9 @@ proc formatValue*[T: SomeInteger](result: var string; value: T; result.add formatInt(value, radix, spec) proc formatValue*(result: var string; value: SomeFloat; specifier: string) = - ## Standard format implementation for `SomeFloat`. It makes little + ## Standard format implementation for ``SomeFloat``. It makes little ## sense to call this directly, but it is required to exist - ## by the `&` macro. + ## by the ``&`` macro. if specifier.len == 0: result.add $value return @@ -551,9 +496,9 @@ proc formatValue*(result: var string; value: SomeFloat; specifier: string) = result.add res proc formatValue*(result: var string; value: string; specifier: string) = - ## Standard format implementation for `string`. It makes little + ## Standard format implementation for ``string``. It makes little ## sense to call this directly, but it is required to exist - ## by the `&` macro. + ## by the ``&`` macro. let spec = parseStandardFormatSpecifier(specifier) var value = value case spec.typ @@ -567,7 +512,8 @@ proc formatValue*(result: var string; value: string; specifier: string) = setLen(value, runeOffset(value, spec.precision)) result.add alignString(value, spec.minimumWidth, spec.align, spec.fill) -proc formatValue[T: not SomeInteger](result: var string; value: T; specifier: string) = +proc formatValue[T: not SomeInteger](result: var string; value: T; + specifier: string) = mixin `$` formatValue(result, $value, specifier) @@ -577,19 +523,19 @@ template formatValue(result: var string; value: char; specifier: string) = template formatValue(result: var string; value: cstring; specifier: string) = result.add value -proc strformatImpl(f: string; openChar, closeChar: char): NimNode = - template missingCloseChar = - error("invalid format string: missing closing character '" & closeChar & "'") - +proc strformatImpl(pattern: NimNode; openChar, closeChar: char): NimNode = + if pattern.kind notin {nnkStrLit..nnkTripleStrLit}: + error "string formatting (fmt(), &) only works with string literals", pattern if openChar == ':' or closeChar == ':': error "openChar and closeChar must not be ':'" + let f = pattern.strVal var i = 0 let res = genSym(nskVar, "fmtRes") - result = newNimNode(nnkStmtListExpr) + result = newNimNode(nnkStmtListExpr, lineInfoFrom = pattern) # XXX: https://github.com/nim-lang/Nim/issues/8405 # When compiling with -d:useNimRtl, certain procs such as `count` from the strutils # module are not accessible at compile-time: - let expectedGrowth = when defined(useNimRtl): 0 else: count(f, openChar) * 10 + let expectedGrowth = when defined(useNimRtl): 0 else: count(f, '{') * 10 result.add newVarStmt(res, newCall(bindSym"newStringOfCap", newLit(f.len + expectedGrowth))) var strlit = "" @@ -605,45 +551,18 @@ proc strformatImpl(f: string; openChar, closeChar: char): NimNode = strlit = "" var subexpr = "" - var inParens = 0 - var inSingleQuotes = false - var inDoubleQuotes = false - template notEscaped:bool = f[i-1]!='\\' - while i < f.len and f[i] != closeChar and (f[i] != ':' or inParens != 0): - case f[i] - of '\\': - if i < f.len-1 and f[i+1] in {openChar,closeChar,':'}: inc i - of '\'': - if not inDoubleQuotes and notEscaped: inSingleQuotes = not inSingleQuotes - of '\"': - if notEscaped: inDoubleQuotes = not inDoubleQuotes - of '(': - if not (inSingleQuotes or inDoubleQuotes): inc inParens - of ')': - if not (inSingleQuotes or inDoubleQuotes): dec inParens - of '=': - let start = i - inc i - i += f.skipWhitespace(i) - if i == f.len: - missingCloseChar - if f[i] == closeChar or f[i] == ':': - result.add newCall(bindSym"add", res, newLit(subexpr & f[start ..< i])) - else: - subexpr.add f[start ..< i] - continue - else: discard + while i < f.len and f[i] != closeChar and f[i] != ':': subexpr.add f[i] inc i - - if i == f.len: - missingCloseChar - var x: NimNode try: x = parseExpr(subexpr) - except ValueError as e: - error("could not parse `$#` in `$#`.\n$#" % [subexpr, f, e.msg]) + except ValueError: + when declared(getCurrentExceptionMsg): + let msg = getCurrentExceptionMsg() + error("could not parse `" & subexpr & "`.\n" & msg, pattern) + else: + error("could not parse `" & subexpr & "`.\n", pattern) let formatSym = bindSym("formatValue", brOpen) var options = "" if f[i] == ':': @@ -651,17 +570,17 @@ proc strformatImpl(f: string; openChar, closeChar: char): NimNode = while i < f.len and f[i] != closeChar: options.add f[i] inc i - if i == f.len: - missingCloseChar if f[i] == closeChar: inc i + else: + doAssert false, "invalid format string: missing '}'" result.add newCall(formatSym, res, x, newLit(options)) elif f[i] == closeChar: - if i".fmt('<', '>') == "7" - assert "<<>>".fmt('<', '>') == "<7>" - assert "`x`".fmt('`', '`') == "7" - strformatImpl(pattern, openChar, closeChar) +macro fmt*(pattern: string): untyped = strformatImpl(pattern, '{', '}') + ## An alias for ``&``. -template fmt*(pattern: static string): untyped = - ## Alias for `fmt(pattern, '{', '}')`. - fmt(pattern, '{', '}') - -macro `&`*(pattern: string{lit}): string = - ## `&pattern` is the same as `pattern.fmt`. - ## For a specification of the `&` macro, see the module level documentation. - # pending bug #18275, bug #18278, use `pattern: static string` - # consider deprecating this, it's redundant with `fmt` and `fmt` is strictly - # more flexible, readable (no confusion with the binary `&`), self-documenting, - # not to mention #18275, bug #18278. +macro fmt*(pattern: string; openChar, closeChar: char): untyped = + ## Use ``openChar`` instead of '{' and ``closeChar`` instead of '}' runnableExamples: - let x = 7 - assert &"{x}\n" == "7\n" # regular string literal - assert &"{x}\n" == "{x}\n".fmt # `fmt` can be used instead - assert &"{x}\n" != fmt"{x}\n" # see `fmt` docs, this would use a raw string literal - strformatImpl(pattern.strVal, '{', '}') + let testInt = 123 + doAssert "".fmt('<', '>') == "123" + doAssert """(()"foo" & "bar"())""".fmt(')', '(') == "(foobar)" + doAssert """ ""{"123+123"}"" """.fmt('"', '"') == " \"{246}\" " + strformatImpl(pattern, openChar.intVal.char, closeChar.intVal.char) + +when isMainModule: + template check(actual, expected: string) = + doAssert actual == expected + + from strutils import toUpperAscii, repeat + + # Basic tests + let s = "string" + check &"{0} {s}", "0 string" + check &"{s[0..2].toUpperAscii}", "STR" + check &"{-10:04}", "-010" + check &"{-10:<04}", "-010" + check &"{-10:>04}", "-010" + check &"0x{10:02X}", "0x0A" + + check &"{10:#04X}", "0x0A" + + check &"""{"test":#>5}""", "#test" + check &"""{"test":>5}""", " test" + + check &"""{"test":#^7}""", "#test##" + + check &"""{"test": <5}""", "test " + check &"""{"test":<5}""", "test " + check &"{1f:.3f}", "1.000" + check &"Hello, {s}!", "Hello, string!" + + # Tests for identifiers without parenthesis + check &"{s} works{s}", "string worksstring" + check &"{s:>7}", " string" + doAssert(not compiles(&"{s_works}")) # parsed as identifier `s_works` + + # Misc general tests + check &"{{}}", "{}" + check &"{0}%", "0%" + check &"{0}%asdf", "0%asdf" + check &("\n{\"\\n\"}\n"), "\n\n\n" + check &"""{"abc"}s""", "abcs" + + # String tests + check &"""{"abc"}""", "abc" + check &"""{"abc":>4}""", " abc" + check &"""{"abc":<4}""", "abc " + check &"""{"":>4}""", " " + check &"""{"":<4}""", " " + + # Int tests + check &"{12345}", "12345" + check &"{ - 12345}", "-12345" + check &"{12345:6}", " 12345" + check &"{12345:>6}", " 12345" + check &"{12345:4}", "12345" + check &"{12345:08}", "00012345" + check &"{-12345:08}", "-0012345" + check &"{0:0}", "0" + check &"{0:02}", "00" + check &"{-1:3}", " -1" + check &"{-1:03}", "-01" + check &"{10}", "10" + check &"{16:#X}", "0x10" + check &"{16:^#7X}", " 0x10 " + check &"{16:^+#7X}", " +0x10 " + + # Hex tests + check &"{0:x}", "0" + check &"{-0:x}", "0" + check &"{255:x}", "ff" + check &"{255:X}", "FF" + check &"{-255:x}", "-ff" + check &"{-255:X}", "-FF" + check &"{255:x} uNaffeCteD CaSe", "ff uNaffeCteD CaSe" + check &"{255:X} uNaffeCteD CaSe", "FF uNaffeCteD CaSe" + check &"{255:4x}", " ff" + check &"{255:04x}", "00ff" + check &"{-255:4x}", " -ff" + check &"{-255:04x}", "-0ff" + + # Float tests + check &"{123.456}", "123.456" + check &"{-123.456}", "-123.456" + check &"{123.456:.3f}", "123.456" + check &"{123.456:+.3f}", "+123.456" + check &"{-123.456:+.3f}", "-123.456" + check &"{-123.456:.3f}", "-123.456" + check &"{123.456:1g}", "123.456" + check &"{123.456:.1f}", "123.5" + check &"{123.456:.0f}", "123" + check &"{123.456:>9.3f}", " 123.456" + check &"{123.456:9.3f}", " 123.456" + check &"{123.456:>9.4f}", " 123.4560" + check &"{123.456:>9.0f}", " 123" + check &"{123.456:<9.4f}", "123.4560 " + + # Float (scientific) tests + check &"{123.456:e}", "1.234560e+02" + check &"{123.456:>13e}", " 1.234560e+02" + check &"{123.456:<13e}", "1.234560e+02 " + check &"{123.456:.1e}", "1.2e+02" + check &"{123.456:.2e}", "1.23e+02" + check &"{123.456:.3e}", "1.235e+02" + + # Note: times.format adheres to the format protocol. Test that this + # works: + import times + + var dt = initDateTime(01, mJan, 2000, 00, 00, 00) + check &"{dt:yyyy-MM-dd}", "2000-01-01" + + var tm = fromUnix(0) + discard &"{tm}" + + var noww = now() + check &"{noww}", $noww + + # Unicode string tests + check &"""{"αβγ"}""", "αβγ" + check &"""{"αβγ":>5}""", " αβγ" + check &"""{"αβγ":<5}""", "αβγ " + check &"""a{"a"}α{"α"}€{"€"}𐍈{"𐍈"}""", "aaαα€€𐍈𐍈" + check &"""a{"a":2}α{"α":2}€{"€":2}𐍈{"𐍈":2}""", "aa αα €€ 𐍈𐍈 " + # Invalid unicode sequences should be handled as plain strings. + # Invalid examples taken from: https://stackoverflow.com/a/3886015/1804173 + let invalidUtf8 = [ + "\xc3\x28", "\xa0\xa1", + "\xe2\x28\xa1", "\xe2\x82\x28", + "\xf0\x28\x8c\xbc", "\xf0\x90\x28\xbc", "\xf0\x28\x8c\x28" + ] + for s in invalidUtf8: + check &"{s:>5}", repeat(" ", 5-s.len) & s + + # bug #11089 + let flfoo: float = 1.0 + check &"{flfoo}", "1.0" + + # bug #11092 + check &"{high(int64)}", "9223372036854775807" + check &"{low(int64)}", "-9223372036854775808" + + import json + + doAssert fmt"{'a'} {'b'}" == "a b" + + echo("All tests ok") diff --git a/lib/pure/strmisc.nim b/lib/pure/strmisc.nim index c8cd839be..43437ddb4 100644 --- a/lib/pure/strmisc.nim +++ b/lib/pure/strmisc.nim @@ -8,12 +8,15 @@ # ## This module contains various string utility routines that are uncommonly -## used in comparison to the ones in `strutils `_. +## used in comparison to `strutils `_. -import std/strutils +import strutils -func expandTabs*(s: string, tabSize: int = 8): string = - ## Expands tab characters in `s`, replacing them by spaces. +{.deadCodeElim: on.} # dce option deprecated + +proc expandTabs*(s: string, tabSize: int = 8): string {.noSideEffect, + procvar.} = + ## Expand tab characters in `s` replacing them by spaces. ## ## The amount of inserted spaces for each tab character is the difference ## between the current column number and the next tab position. Tab positions @@ -24,7 +27,9 @@ func expandTabs*(s: string, tabSize: int = 8): string = runnableExamples: doAssert expandTabs("\t", 4) == " " doAssert expandTabs("\tfoo\t", 4) == " foo " - doAssert expandTabs("a\tb\n\txy\t", 3) == "a b\n xy " + doAssert expandTabs("\tfoo\tbar", 4) == " foo bar" + doAssert expandTabs("\tfoo\tbar\t", 4) == " foo bar " + doAssert expandTabs("ab\tcd\n\txy\t", 3) == "ab cd\n xy " result = newStringOfCap(s.len + s.len shr 2) var pos = 0 @@ -48,39 +53,58 @@ func expandTabs*(s: string, tabSize: int = 8): string = if c == '\l': pos = 0 -func partition*(s: string, sep: string, - right: bool = false): (string, string, string) = - ## Splits the string at the first (if `right` is false) - ## or last (if `right` is true) occurrence of `sep` into a 3-tuple. +proc partition*(s: string, sep: string, + right: bool = false): (string, string, string) + {.noSideEffect, procvar.} = + ## Split the string at the first or last occurrence of `sep` into a 3-tuple ## - ## Returns a 3-tuple of strings, `(beforeSep, sep, afterSep)` or - ## `(s, "", "")` if `sep` is not found and `right` is false or - ## `("", "", s)` if `sep` is not found and `right` is true. - ## - ## **See also:** - ## * `rpartition proc <#rpartition,string,string>`_ + ## Returns a 3 string tuple of (beforeSep, `sep`, afterSep) or + ## (`s`, "", "") if `sep` is not found and `right` is false or + ## ("", "", `s`) if `sep` is not found and `right` is true runnableExamples: - doAssert partition("foo:bar:baz", ":") == ("foo", ":", "bar:baz") - doAssert partition("foo:bar:baz", ":", right = true) == ("foo:bar", ":", "baz") - doAssert partition("foobar", ":") == ("foobar", "", "") - doAssert partition("foobar", ":", right = true) == ("", "", "foobar") + doAssert partition("foo:bar", ":") == ("foo", ":", "bar") + doAssert partition("foobarbar", "bar") == ("foo", "bar", "bar") + doAssert partition("foobarbar", "bank") == ("foobarbar", "", "") + doAssert partition("foobarbar", "foo") == ("", "foo", "barbar") + doAssert partition("foofoobar", "bar") == ("foofoo", "bar", "") let position = if right: s.rfind(sep) else: s.find(sep) if position != -1: return (s[0 ..< position], sep, s[position + sep.len ..< s.len]) return if right: ("", "", s) else: (s, "", "") -func rpartition*(s: string, sep: string): (string, string, string) = - ## Splits the string at the last occurrence of `sep` into a 3-tuple. +proc rpartition*(s: string, sep: string): (string, string, string) + {.noSideEffect, procvar.} = + ## Split the string at the last occurrence of `sep` into a 3-tuple ## - ## Returns a 3-tuple of strings, `(beforeSep, sep, afterSep)` or - ## `("", "", s)` if `sep` is not found. This is the same as - ## `partition(s, sep, right = true)`. - ## - ## **See also:** - ## * `partition proc <#partition,string,string,bool>`_ + ## Returns a 3 string tuple of (beforeSep, `sep`, afterSep) or + ## ("", "", `s`) if `sep` is not found runnableExamples: - doAssert rpartition("foo:bar:baz", ":") == ("foo:bar", ":", "baz") - doAssert rpartition("foobar", ":") == ("", "", "foobar") + doAssert rpartition("foo:bar", ":") == ("foo", ":", "bar") + doAssert rpartition("foobarbar", "bar") == ("foobar", "bar", "") + doAssert rpartition("foobarbar", "bank") == ("", "", "foobarbar") + doAssert rpartition("foobarbar", "foo") == ("", "foo", "barbar") + doAssert rpartition("foofoobar", "bar") == ("foofoo", "bar", "") - partition(s, sep, right = true) + return partition(s, sep, right = true) + +when isMainModule: + doAssert expandTabs("\t", 4) == " " + doAssert expandTabs("\tfoo\t", 4) == " foo " + doAssert expandTabs("\tfoo\tbar", 4) == " foo bar" + doAssert expandTabs("\tfoo\tbar\t", 4) == " foo bar " + doAssert expandTabs("", 4) == "" + doAssert expandTabs("", 0) == "" + doAssert expandTabs("\t\t\t", 0) == "" + + doAssert partition("foo:bar", ":") == ("foo", ":", "bar") + doAssert partition("foobarbar", "bar") == ("foo", "bar", "bar") + doAssert partition("foobarbar", "bank") == ("foobarbar", "", "") + doAssert partition("foobarbar", "foo") == ("", "foo", "barbar") + doAssert partition("foofoobar", "bar") == ("foofoo", "bar", "") + + doAssert rpartition("foo:bar", ":") == ("foo", ":", "bar") + doAssert rpartition("foobarbar", "bar") == ("foobar", "bar", "") + doAssert rpartition("foobarbar", "bank") == ("", "", "foobarbar") + doAssert rpartition("foobarbar", "foo") == ("", "foo", "barbar") + doAssert rpartition("foofoobar", "bar") == ("foofoo", "bar", "") diff --git a/lib/pure/strscans.nim b/lib/pure/strscans.nim index 8a1ea125f..0125a1926 100644 --- a/lib/pure/strscans.nim +++ b/lib/pure/strscans.nim @@ -35,9 +35,8 @@ substrings starting with ``$``. These constructions are available: ``$o`` Matches an octal integer. This uses ``parseutils.parseOct``. ``$i`` Matches a decimal integer. This uses ``parseutils.parseInt``. ``$h`` Matches a hex integer. This uses ``parseutils.parseHex``. -``$f`` Matches a floating-point number. Uses ``parseFloat``. +``$f`` Matches a floating pointer number. Uses ``parseFloat``. ``$w`` Matches an ASCII identifier: ``[A-Za-z_][A-Za-z_0-9]*``. -``$c`` Matches a single ASCII character. ``$s`` Skips optional whitespace. ``$$`` Matches a single dollar sign. ``$.`` Matches if the end of the input string has been reached. @@ -52,7 +51,7 @@ substrings starting with ``$``. These constructions are available: ================= ======================================================== Even though ``$*`` and ``$+`` look similar to the regular expressions ``.*`` -and ``.+``, they work quite differently. There is no non-deterministic +and ``.+`` they work quite differently, there is no non-deterministic state machine involved and the matches are non-greedy. ``[$*]`` matches ``[xyz]`` via ``parseutils.parseUntil``. @@ -175,7 +174,7 @@ overloaded to handle both single characters and sets of character. .. code-block:: nim - import std/streams + import streams template atom(input: Stream; idx: int; c: char): bool = ## Used in scanp for the matching of atoms (usually chars). @@ -284,11 +283,6 @@ efficiency and perform different checks. import macros, parseutils -import std/private/since - -when defined(nimPreviewSlimSystem): - import std/assertions - proc conditionsToIfChain(n, idx, res: NimNode; start: int): NimNode = assert n.kind == nnkStmtList @@ -351,12 +345,6 @@ macro scanf*(input: string; pattern: static[string]; results: varargs[typed]): b else: matchError inc i - of 'c': - if i < results.len and getType(results[i]).typeKind == ntyChar: - matchBind "parseChar" - else: - matchError - inc i of 'b': if i < results.len and getType(results[i]).typeKind == ntyInt: matchBind "parseBin" @@ -408,7 +396,7 @@ macro scanf*(input: string; pattern: static[string]; results: varargs[typed]): b var resLen = genSym(nskLet, "resLen") conds.add newLetStmt(resLen, newCall(bindSym"parseUntil", inp, results[i], newLit(token), idx)) - conds.add newCall(bindSym">=", resLen, newLit min) + conds.add newCall(bindSym"!=", resLen, newLit min) conds.add resLen else: matchError @@ -470,54 +458,6 @@ macro scanf*(input: string; pattern: static[string]; results: varargs[typed]): b else: result.add res -macro scanTuple*(input: untyped; pattern: static[string]; matcherTypes: varargs[untyped]): untyped {.since: (1, 5).}= - ## Works identically as scanf, but instead of predeclaring variables it returns a tuple. - ## Tuple is started with a bool which indicates if the scan was successful - ## followed by the requested data. - ## If using a user defined matcher, provide the types in order they appear after pattern: - ## `line.scanTuple("${yourMatcher()}", int)` - runnableExamples: - let (success, year, month, day, time) = scanTuple("1000-01-01 00:00:00", "$i-$i-$i$s$+") - if success: - assert year == 1000 - assert month == 1 - assert day == 1 - assert time == "00:00:00" - var - p = 0 - userMatches = 0 - arguments: seq[NimNode] - result = newStmtList() - template addVar(typ: string) = - let varIdent = ident("temp" & $arguments.len) - result.add(newNimNode(nnkVarSection).add(newIdentDefs(varIdent, ident(typ), newEmptyNode()))) - arguments.add(varIdent) - while p < pattern.len: - if pattern[p] == '$': - inc p - case pattern[p] - of 'w', '*', '+': - addVar("string") - of 'c': - addVar("char") - of 'b', 'o', 'i', 'h': - addVar("int") - of 'f': - addVar("float") - of '{': - if userMatches < matcherTypes.len: - let varIdent = ident("temp" & $arguments.len) - result.add(newNimNode(nnkVarSection).add(newIdentDefs(varIdent, matcherTypes[userMatches], newEmptyNode()))) - arguments.add(varIdent) - inc userMatches - else: discard - inc p - result.add nnkTupleConstr.newTree(newCall(ident("scanf"), input, newStrLitNode(pattern))) - for arg in arguments: - result[^1][0].add arg - result[^1].add arg - result = newBlockStmt(result) - template atom*(input: string; idx: int; c: char): bool = ## Used in scanp for the matching of atoms (usually chars). ## EOF is matched as ``'\0'``. @@ -581,14 +521,13 @@ macro scanp*(input, idx: typed; pattern: varargs[untyped]): bool = of nnkCallKinds: # *{'A'..'Z'} !! s.add(!_) template buildWhile(input, idx, init, cond, action): untyped = - mixin hasNxt while hasNxt(input, idx): init if not cond: break action # (x) a # bind action a to (x) - if it[0].kind in {nnkPar, nnkTupleConstr} and it.len == 2: + if it[0].kind == nnkPar and it.len == 2: result = atm(it[0], input, idx, placeholder(it[1], input, idx)) elif it.kind == nnkInfix and it[0].eqIdent"->": # bind matching to some action: @@ -694,3 +633,115 @@ macro scanp*(input, idx: typed; pattern: varargs[untyped]): bool = result.add res when defined(debugScanp): echo repr result + + +when isMainModule: + proc twoDigits(input: string; x: var int; start: int): int = + if start+1 < input.len and input[start] == '0' and input[start+1] == '0': + result = 2 + x = 13 + else: + result = 0 + + proc someSep(input: string; start: int; seps: set[char] = {';', ',', '-', '.'}): int = + result = 0 + while start+result < input.len and input[start+result] in seps: inc result + + proc demangle(s: string; res: var string; start: int): int = + while result+start < s.len and s[result+start] in {'_', '@'}: inc result + res = "" + while result+start < s.len and s[result+start] > ' ' and s[result+start] != '_': + res.add s[result+start] + inc result + while result+start < s.len and s[result+start] > ' ': + inc result + + proc parseGDB(resp: string): seq[string] = + const + digits = {'0'..'9'} + hexdigits = digits + {'a'..'f', 'A'..'F'} + whites = {' ', '\t', '\C', '\L'} + result = @[] + var idx = 0 + while true: + var prc = "" + var info = "" + if scanp(resp, idx, *`whites`, '#', *`digits`, +`whites`, ?("0x", *`hexdigits`, " in "), + demangle($input, prc, $index), *`whites`, '(', * ~ ')', ')', + *`whites`, "at ", +(~{'\C', '\L'} -> info.add($_))): + result.add prc & " " & info + else: + break + + var key, val: string + var intval: int + var floatval: float + doAssert scanf("abc:: xyz 89 33.25", "$w$s::$s$w$s$i $f", key, val, intval, floatVal) + doAssert key == "abc" + doAssert val == "xyz" + doAssert intval == 89 + doAssert floatVal == 33.25 + + var binval: int + var octval: int + var hexval: int + doAssert scanf("0b0101 0o1234 0xabcd", "$b$s$o$s$h", binval, octval, hexval) + doAssert binval == 0b0101 + doAssert octval == 0o1234 + doAssert hexval == 0xabcd + + let xx = scanf("$abc", "$$$i", intval) + doAssert xx == false + + + let xx2 = scanf("$1234", "$$$i", intval) + doAssert xx2 + + let yy = scanf(";.--Breakpoint00 [output]", + "$[someSep]Breakpoint${twoDigits}$[someSep({';','.','-'})] [$+]$.", + intVal, key) + doAssert yy + doAssert key == "output" + doAssert intVal == 13 + + var ident = "" + var idx = 0 + let zz = scanp("foobar x x x xWZ", idx, +{'a'..'z'} -> add(ident, $_), *(*{ + ' ', '\t'}, "x"), ~'U', "Z") + doAssert zz + doAssert ident == "foobar" + + const digits = {'0'..'9'} + var year = 0 + var idx2 = 0 + if scanp("201655-8-9", idx2, `digits`{4, 6} -> (year = year * 10 + ord($_) - + ord('0')), "-8", "-9"): + doAssert year == 201655 + + const gdbOut = """ + #0 @foo_96013_1208911747@8 (x0=...) + at c:/users/anwender/projects/nim/temp.nim:11 + #1 0x00417754 in tempInit000 () at c:/users/anwender/projects/nim/temp.nim:13 + #2 0x0041768d in NimMainInner () + at c:/users/anwender/projects/nim/lib/system.nim:2605 + #3 0x004176b1 in NimMain () + at c:/users/anwender/projects/nim/lib/system.nim:2613 + #4 0x004176db in main (argc=1, args=0x712cc8, env=0x711ca8) + at c:/users/anwender/projects/nim/lib/system.nim:2620""" + const result = @["foo c:/users/anwender/projects/nim/temp.nim:11", + "tempInit000 c:/users/anwender/projects/nim/temp.nim:13", + "NimMainInner c:/users/anwender/projects/nim/lib/system.nim:2605", + "NimMain c:/users/anwender/projects/nim/lib/system.nim:2613", + "main c:/users/anwender/projects/nim/lib/system.nim:2620"] + #doAssert parseGDB(gdbOut) == result + + # bug #6487 + var count = 0 + + proc test(): string = + inc count + result = ",123123" + + var a: int + discard scanf(test(), ",$i", a) + doAssert count == 1 diff --git a/lib/pure/strtabs.nim b/lib/pure/strtabs.nim index 11d5015cb..c6b44a3ca 100644 --- a/lib/pure/strtabs.nim +++ b/lib/pure/strtabs.nim @@ -48,20 +48,15 @@ runnableExamples: ## * `json module`_ for table-like structure which allows ## heterogeneous members -import std/private/since import hashes, strutils -when defined(nimPreviewSlimSystem): - import std/assertions - - -when defined(js) or defined(nimscript) or defined(Standalone): +when defined(js): {.pragma: rtlFunc.} else: {.pragma: rtlFunc, rtl.} - import std/envvars + import os include "system/inclrtl" @@ -93,7 +88,6 @@ const growthFactor = 2 startSize = 64 -proc mode*(t: StringTableRef): StringTableMode {.inline.} = t.mode iterator pairs*(t: StringTableRef): tuple[key, value: string] = ## Iterates over every `(key, value)` pair in the table `t`. @@ -145,8 +139,10 @@ template get(t: StringTableRef, key: string) = var index = rawGet(t, key) if index >= 0: result = t.data[index].val else: - raise newException(KeyError, "key not found: " & key) - + when compiles($key): + raise newException(KeyError, "key not found: " & $key) + else: + raise newException(KeyError, "key not found") proc len*(t: StringTableRef): int {.rtlFunc, extern: "nst$1".} = ## Returns the number of keys in `t`. @@ -231,11 +227,11 @@ proc enlarge(t: StringTableRef) = var n: KeyValuePairSeq newSeq(n, len(t.data) * growthFactor) for i in countup(0, high(t.data)): - if t.data[i].hasValue: rawInsert(t, n, move t.data[i].key, move t.data[i].val) + if t.data[i].hasValue: rawInsert(t, n, t.data[i].key, t.data[i].val) swap(t.data, n) proc `[]=`*(t: StringTableRef, key, val: string) {. - rtlFunc, extern: "nstPut".} = + rtlFunc, extern: "nstPut", noSideEffect.} = ## Inserts a `(key, value)` pair into `t`. ## ## See also: @@ -255,17 +251,20 @@ proc `[]=`*(t: StringTableRef, key, val: string) {. inc(t.counter) proc newStringTable*(mode: StringTableMode): owned(StringTableRef) {. - rtlFunc, extern: "nst$1", noSideEffect.} = + rtlFunc, extern: "nst$1".} = ## Creates a new empty string table. ## ## See also: ## * `newStringTable(keyValuePairs) proc ## <#newStringTable,varargs[tuple[string,string]],StringTableMode>`_ - result = StringTableRef(mode: mode, counter: 0, data: newSeq[KeyValuePair](startSize)) + new(result) + result.mode = mode + result.counter = 0 + newSeq(result.data, startSize) proc newStringTable*(keyValuePairs: varargs[string], mode: StringTableMode): owned(StringTableRef) {. - rtlFunc, extern: "nst$1WithPairs", noSideEffect.} = + rtlFunc, extern: "nst$1WithPairs".} = ## Creates a new string table with given `key, value` string pairs. ## ## `StringTableMode` must be specified. @@ -276,13 +275,12 @@ proc newStringTable*(keyValuePairs: varargs[string], result = newStringTable(mode) var i = 0 while i < high(keyValuePairs): - {.noSideEffect.}: - result[keyValuePairs[i]] = keyValuePairs[i + 1] + result[keyValuePairs[i]] = keyValuePairs[i + 1] inc(i, 2) proc newStringTable*(keyValuePairs: varargs[tuple[key, val: string]], mode: StringTableMode = modeCaseSensitive): owned(StringTableRef) {. - rtlFunc, extern: "nst$1WithTableConstr", noSideEffect.} = + rtlFunc, extern: "nst$1WithTableConstr".} = ## Creates a new string table with given `(key, value)` tuple pairs. ## ## The default mode is case sensitive. @@ -292,19 +290,18 @@ proc newStringTable*(keyValuePairs: varargs[tuple[key, val: string]], mytab2 = newStringTable([("key3", "val3"), ("key4", "val4")]) result = newStringTable(mode) - for key, val in items(keyValuePairs): - {.noSideEffect.}: - result[key] = val + for key, val in items(keyValuePairs): result[key] = val proc raiseFormatException(s: string) = raise newException(ValueError, "format string: key not found: " & s) proc getValue(t: StringTableRef, flags: set[FormatFlag], key: string): string = if hasKey(t, key): return t.getOrDefault(key) - when defined(js) or defined(nimscript) or defined(Standalone): + # hm difficult: assume safety in taint mode here. XXX This is dangerous! + when defined(js): result = "" else: - if useEnvironment in flags: result = getEnv(key) + if useEnvironment in flags: result = os.getEnv(key).string else: result = "" if result.len == 0: if useKey in flags: result = '$' & key @@ -420,3 +417,16 @@ proc `%`*(f: string, t: StringTableRef, flags: set[FormatFlag] = {}): string {. else: add(result, f[i]) inc(i) + + +when isMainModule: + var x = {"k": "v", "11": "22", "565": "67"}.newStringTable + assert x["k"] == "v" + assert x["11"] == "22" + assert x["565"] == "67" + x["11"] = "23" + assert x["11"] == "23" + + x.clear(modeCaseInsensitive) + x["11"] = "22" + assert x["11"] == "22" diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim index c458d605e..535af2b31 100644 --- a/lib/pure/strutils.nim +++ b/lib/pure/strutils.nim @@ -9,43 +9,46 @@ ## The system module defines several common functions for working with strings, ## such as: -## * `$` for converting other data-types to strings -## * `&` for string concatenation -## * `add` for adding a new character or a string to the existing one -## * `in` (alias for `contains`) and `notin` for checking if a character +## * ``$`` for converting other data-types to strings +## * ``&`` for string concatenation +## * ``add`` for adding a new character or a string to the existing one +## * ``in`` (alias for ``contains``) and ``notin`` for checking if a character ## is in a string ## ## This module builds upon that, providing additional functionality in form of ## procedures, iterators and templates for strings. - -runnableExamples: - let - numbers = @[867, 5309] - multiLineString = "first line\nsecond line\nthird line" - - let jenny = numbers.join("-") - assert jenny == "867-5309" - - assert splitLines(multiLineString) == - @["first line", "second line", "third line"] - assert split(multiLineString) == @["first", "line", "second", - "line", "third", "line"] - assert indent(multiLineString, 4) == - " first line\n second line\n third line" - assert 'z'.repeat(5) == "zzzzz" - +## +## .. code-block:: +## import strutils +## +## let +## numbers = @[867, 5309] +## multiLineString = "first line\nsecond line\nthird line" +## +## let jenny = numbers.join("-") +## assert jenny == "867-5309" +## +## assert splitLines(multiLineString) == +## @["first line", "second line", "third line"] +## assert split(multiLineString) == @["first", "line", "second", +## "line", "third", "line"] +## assert indent(multiLineString, 4) == +## " first line\n second line\n third line" +## assert 'z'.repeat(5) == "zzzzz" +## ## The chaining of functions is possible thanks to the ## `method call syntax`_: - -runnableExamples: - from std/sequtils import map - - let jenny = "867-5309" - assert jenny.split('-').map(parseInt) == @[867, 5309] - - assert "Beetlejuice".indent(1).repeat(3).strip == - "Beetlejuice Beetlejuice Beetlejuice" - +## +## .. code-block:: +## import strutils +## from sequtils import map +## +## let jenny = "867-5309" +## assert jenny.split('-').map(parseInt) == @[867, 5309] +## +## assert "Beetlejuice".indent(1).repeat(3).strip == +## "Beetlejuice Beetlejuice Beetlejuice" +## ## This module is available for the `JavaScript target ## `_. ## @@ -56,78 +59,58 @@ runnableExamples: ## * `unicode module`_ for Unicode UTF-8 handling ## * `sequtils module`_ for operations on container ## types (including strings) -## * `parsecsv module`_ for a high-performance CSV parser ## * `parseutils module`_ for lower-level parsing of tokens, ## numbers, identifiers, etc. ## * `parseopt module`_ for command-line parsing -## * `pegs module`_ for PEG (Parsing Expression Grammar) support ## * `strtabs module`_ for efficient hash tables ## (dictionaries, in some programming languages) mapping from strings to strings +## * `pegs module`_ for PEG (Parsing Expression Grammar) support ## * `ropes module`_ for rope data type, which can represent very ## long strings efficiently ## * `re module`_ for regular expression (regex) support -## * `strscans`_ for `scanf` and `scanp` macros, which offer +## * `strscans`_ for ``scanf`` and ``scanp`` macros, which offer ## easier substring extraction than regular expressions import parseutils from math import pow, floor, log10 -from algorithm import fill, reverse -import std/enumutils +from algorithm import reverse -from unicode import toLower, toUpper -export toLower, toUpper +when defined(nimVmExportFixed): + from unicode import toLower, toUpper + export toLower, toUpper include "system/inclrtl" -import std/private/since -from std/private/strimpl import cmpIgnoreStyleImpl, cmpIgnoreCaseImpl, - startsWithImpl, endsWithImpl - -when defined(nimPreviewSlimSystem): - import std/assertions - const Whitespace* = {' ', '\t', '\v', '\r', '\l', '\f'} ## All the characters that count as whitespace (space, tab, vertical tab, - ## carriage return, new line, form feed). + ## carriage return, new line, form feed) Letters* = {'A'..'Z', 'a'..'z'} - ## The set of letters. - - UppercaseLetters* = {'A'..'Z'} - ## The set of uppercase ASCII letters. - - LowercaseLetters* = {'a'..'z'} - ## The set of lowercase ASCII letters. - - PunctuationChars* = {'!'..'/', ':'..'@', '['..'`', '{'..'~'} - ## The set of all ASCII punctuation characters. + ## the set of letters Digits* = {'0'..'9'} - ## The set of digits. + ## the set of digits HexDigits* = {'0'..'9', 'A'..'F', 'a'..'f'} - ## The set of hexadecimal digits. + ## the set of hexadecimal digits IdentChars* = {'a'..'z', 'A'..'Z', '0'..'9', '_'} - ## The set of characters an identifier can consist of. + ## the set of characters an identifier can consist of IdentStartChars* = {'a'..'z', 'A'..'Z', '_'} - ## The set of characters an identifier can start with. + ## the set of characters an identifier can start with Newlines* = {'\13', '\10'} - ## The set of characters a newline terminator can start with (carriage - ## return, line feed). - - PrintableChars* = Letters + Digits + PunctuationChars + Whitespace - ## The set of all printable ASCII characters (letters, digits, whitespace, and punctuation characters). + ## the set of characters a newline terminator can start with (carriage + ## return, line feed) AllChars* = {'\x00'..'\xFF'} ## A set with all the possible characters. ## ## Not very useful by its own, you can use it to create *inverted* sets to - ## make the `find func<#find,string,set[char],Natural,int>`_ + ## make the `find proc<#find,string,set[char],Natural,int>`_ ## find **invalid** characters in strings. Example: ## ## .. code-block:: nim @@ -135,7 +118,8 @@ const ## doAssert "01234".find(invalid) == -1 ## doAssert "01A34".find(invalid) == 2 -func isAlphaAscii*(c: char): bool {.rtl, extern: "nsuIsAlphaAsciiChar".} = +proc isAlphaAscii*(c: char): bool {.noSideEffect, procvar, + rtl, extern: "nsuIsAlphaAsciiChar".} = ## Checks whether or not character `c` is alphabetical. ## ## This checks a-z, A-Z ASCII characters only. @@ -146,7 +130,8 @@ func isAlphaAscii*(c: char): bool {.rtl, extern: "nsuIsAlphaAsciiChar".} = doAssert isAlphaAscii('8') == false return c in Letters -func isAlphaNumeric*(c: char): bool {.rtl, extern: "nsuIsAlphaNumericChar".} = +proc isAlphaNumeric*(c: char): bool {.noSideEffect, procvar, + rtl, extern: "nsuIsAlphaNumericChar".} = ## Checks whether or not `c` is alphanumeric. ## ## This checks a-z, A-Z, 0-9 ASCII characters only. @@ -156,7 +141,8 @@ func isAlphaNumeric*(c: char): bool {.rtl, extern: "nsuIsAlphaNumericChar".} = doAssert isAlphaNumeric(' ') == false return c in Letters+Digits -func isDigit*(c: char): bool {.rtl, extern: "nsuIsDigitChar".} = +proc isDigit*(c: char): bool {.noSideEffect, procvar, + rtl, extern: "nsuIsDigitChar".} = ## Checks whether or not `c` is a number. ## ## This checks 0-9 ASCII characters only. @@ -165,7 +151,8 @@ func isDigit*(c: char): bool {.rtl, extern: "nsuIsDigitChar".} = doAssert isDigit('8') == true return c in Digits -func isSpaceAscii*(c: char): bool {.rtl, extern: "nsuIsSpaceAsciiChar".} = +proc isSpaceAscii*(c: char): bool {.noSideEffect, procvar, + rtl, extern: "nsuIsSpaceAsciiChar".} = ## Checks whether or not `c` is a whitespace character. runnableExamples: doAssert isSpaceAscii('n') == false @@ -173,49 +160,53 @@ func isSpaceAscii*(c: char): bool {.rtl, extern: "nsuIsSpaceAsciiChar".} = doAssert isSpaceAscii('\t') == true return c in Whitespace -func isLowerAscii*(c: char): bool {.rtl, extern: "nsuIsLowerAsciiChar".} = +proc isLowerAscii*(c: char): bool {.noSideEffect, procvar, + rtl, extern: "nsuIsLowerAsciiChar".} = ## Checks whether or not `c` is a lower case character. ## ## This checks ASCII characters only. ## Use `Unicode module`_ for UTF-8 support. ## ## See also: - ## * `toLowerAscii func<#toLowerAscii,char>`_ + ## * `toLowerAscii proc<#toLowerAscii,char>`_ runnableExamples: doAssert isLowerAscii('e') == true doAssert isLowerAscii('E') == false doAssert isLowerAscii('7') == false - return c in LowercaseLetters + return c in {'a'..'z'} -func isUpperAscii*(c: char): bool {.rtl, extern: "nsuIsUpperAsciiChar".} = +proc isUpperAscii*(c: char): bool {.noSideEffect, procvar, + rtl, extern: "nsuIsUpperAsciiChar".} = ## Checks whether or not `c` is an upper case character. ## ## This checks ASCII characters only. ## Use `Unicode module`_ for UTF-8 support. ## ## See also: - ## * `toUpperAscii func<#toUpperAscii,char>`_ + ## * `toUpperAscii proc<#toUpperAscii,char>`_ runnableExamples: doAssert isUpperAscii('e') == false doAssert isUpperAscii('E') == true doAssert isUpperAscii('7') == false - return c in UppercaseLetters + return c in {'A'..'Z'} -func toLowerAscii*(c: char): char {.rtl, extern: "nsuToLowerAsciiChar".} = - ## Returns the lower case version of character `c`. + +proc toLowerAscii*(c: char): char {.noSideEffect, procvar, + rtl, extern: "nsuToLowerAsciiChar".} = + ## Returns the lower case version of character ``c``. ## - ## This works only for the letters `A-Z`. See `unicode.toLower + ## This works only for the letters ``A-Z``. See `unicode.toLower ## `_ for a version that works for any Unicode ## character. ## ## See also: - ## * `isLowerAscii func<#isLowerAscii,char>`_ - ## * `toLowerAscii func<#toLowerAscii,string>`_ for converting a string + ## * `isLowerAscii proc<#isLowerAscii,char>`_ + ## * `toLowerAscii proc<#toLowerAscii,string>`_ for converting a string runnableExamples: doAssert toLowerAscii('A') == 'a' doAssert toLowerAscii('e') == 'e' - if c in UppercaseLetters: - result = char(uint8(c) xor 0b0010_0000'u8) + if c in {'A'..'Z'}: + result = chr(ord(c) + (ord('a') - ord('A'))) else: result = c @@ -224,106 +215,85 @@ template toImpl(call) = for i in 0..len(s) - 1: result[i] = call(s[i]) -func toLowerAscii*(s: string): string {.rtl, extern: "nsuToLowerAsciiStr".} = +proc toLowerAscii*(s: string): string {.noSideEffect, procvar, + rtl, extern: "nsuToLowerAsciiStr".} = ## Converts string `s` into lower case. ## - ## This works only for the letters `A-Z`. See `unicode.toLower + ## This works only for the letters ``A-Z``. See `unicode.toLower ## `_ for a version that works for any Unicode ## character. ## ## See also: - ## * `normalize func<#normalize,string>`_ + ## * `normalize proc<#normalize,string>`_ runnableExamples: doAssert toLowerAscii("FooBar!") == "foobar!" toImpl toLowerAscii -func toUpperAscii*(c: char): char {.rtl, extern: "nsuToUpperAsciiChar".} = +proc toUpperAscii*(c: char): char {.noSideEffect, procvar, + rtl, extern: "nsuToUpperAsciiChar".} = ## Converts character `c` into upper case. ## - ## This works only for the letters `A-Z`. See `unicode.toUpper + ## This works only for the letters ``A-Z``. See `unicode.toUpper ## `_ for a version that works for any Unicode ## character. ## ## See also: - ## * `isUpperAscii func<#isUpperAscii,char>`_ - ## * `toUpperAscii func<#toUpperAscii,string>`_ for converting a string - ## * `capitalizeAscii func<#capitalizeAscii,string>`_ + ## * `isLowerAscii proc<#isLowerAscii,char>`_ + ## * `toUpperAscii proc<#toUpperAscii,string>`_ for converting a string + ## * `capitalizeAscii proc<#capitalizeAscii,string>`_ runnableExamples: doAssert toUpperAscii('a') == 'A' doAssert toUpperAscii('E') == 'E' - if c in LowercaseLetters: - result = char(uint8(c) xor 0b0010_0000'u8) + if c in {'a'..'z'}: + result = chr(ord(c) - (ord('a') - ord('A'))) else: result = c -func toUpperAscii*(s: string): string {.rtl, extern: "nsuToUpperAsciiStr".} = +proc toUpperAscii*(s: string): string {.noSideEffect, procvar, + rtl, extern: "nsuToUpperAsciiStr".} = ## Converts string `s` into upper case. ## - ## This works only for the letters `A-Z`. See `unicode.toUpper + ## This works only for the letters ``A-Z``. See `unicode.toUpper ## `_ for a version that works for any Unicode ## character. ## ## See also: - ## * `capitalizeAscii func<#capitalizeAscii,string>`_ + ## * `capitalizeAscii proc<#capitalizeAscii,string>`_ runnableExamples: doAssert toUpperAscii("FooBar!") == "FOOBAR!" toImpl toUpperAscii -func capitalizeAscii*(s: string): string {.rtl, extern: "nsuCapitalizeAscii".} = +proc capitalizeAscii*(s: string): string {.noSideEffect, procvar, + rtl, extern: "nsuCapitalizeAscii".} = ## Converts the first character of string `s` into upper case. ## - ## This works only for the letters `A-Z`. + ## This works only for the letters ``A-Z``. ## Use `Unicode module`_ for UTF-8 support. ## ## See also: - ## * `toUpperAscii func<#toUpperAscii,char>`_ + ## * `toUpperAscii proc<#toUpperAscii,char>`_ runnableExamples: doAssert capitalizeAscii("foo") == "Foo" doAssert capitalizeAscii("-bar") == "-bar" if s.len == 0: result = "" else: result = toUpperAscii(s[0]) & substr(s, 1) -func nimIdentNormalize*(s: string): string = - ## Normalizes the string `s` as a Nim identifier. - ## - ## That means to convert to lower case and remove any '_' on all characters - ## except first one. - ## - ## .. Warning:: Backticks (`) are not handled: they remain *as is* and - ## spaces are preserved. See `nimIdentBackticksNormalize - ## `_ for - ## an alternative approach. - runnableExamples: - doAssert nimIdentNormalize("Foo_bar") == "Foobar" - result = newString(s.len) - if s.len == 0: - return - result[0] = s[0] - var j = 1 - for i in 1..len(s) - 1: - if s[i] in UppercaseLetters: - result[j] = chr(ord(s[i]) + (ord('a') - ord('A'))) - inc j - elif s[i] != '_': - result[j] = s[i] - inc j - if j != s.len: setLen(result, j) - -func normalize*(s: string): string {.rtl, extern: "nsuNormalize".} = +proc normalize*(s: string): string {.noSideEffect, procvar, + rtl, extern: "nsuNormalize".} = ## Normalizes the string `s`. ## ## That means to convert it to lower case and remove any '_'. This ## should NOT be used to normalize Nim identifier names. ## ## See also: - ## * `toLowerAscii func<#toLowerAscii,string>`_ + ## * `toLowerAscii proc<#toLowerAscii,string>`_ runnableExamples: doAssert normalize("Foo_bar") == "foobar" doAssert normalize("Foo Bar") == "foo bar" result = newString(s.len) var j = 0 for i in 0..len(s) - 1: - if s[i] in UppercaseLetters: + if s[i] in {'A'..'Z'}: result[j] = chr(ord(s[i]) + (ord('a') - ord('A'))) inc j elif s[i] != '_': @@ -331,7 +301,8 @@ func normalize*(s: string): string {.rtl, extern: "nsuNormalize".} = inc j if j != s.len: setLen(result, j) -func cmpIgnoreCase*(a, b: string): int {.rtl, extern: "nsuCmpIgnoreCase".} = +proc cmpIgnoreCase*(a, b: string): int {.noSideEffect, + rtl, extern: "nsuCmpIgnoreCase", procvar.} = ## Compares two strings in a case insensitive manner. Returns: ## ## | 0 if a == b @@ -341,13 +312,20 @@ func cmpIgnoreCase*(a, b: string): int {.rtl, extern: "nsuCmpIgnoreCase".} = doAssert cmpIgnoreCase("FooBar", "foobar") == 0 doAssert cmpIgnoreCase("bar", "Foo") < 0 doAssert cmpIgnoreCase("Foo5", "foo4") > 0 - cmpIgnoreCaseImpl(a, b) + var i = 0 + var m = min(a.len, b.len) + while i < m: + result = ord(toLowerAscii(a[i])) - ord(toLowerAscii(b[i])) + if result != 0: return + inc(i) + result = a.len - b.len {.push checks: off, line_trace: off.} # this is a hot-spot in the compiler! # thus we compile without checks here -func cmpIgnoreStyle*(a, b: string): int {.rtl, extern: "nsuCmpIgnoreStyle".} = - ## Semantically the same as `cmp(normalize(a), normalize(b))`. It +proc cmpIgnoreStyle*(a, b: string): int {.noSideEffect, + rtl, extern: "nsuCmpIgnoreStyle", procvar.} = + ## Semantically the same as ``cmp(normalize(a), normalize(b))``. It ## is just optimized to not allocate temporary strings. This should ## NOT be used to compare Nim identifier names. ## Use `macros.eqIdent`_ for that. @@ -360,12 +338,30 @@ func cmpIgnoreStyle*(a, b: string): int {.rtl, extern: "nsuCmpIgnoreStyle".} = runnableExamples: doAssert cmpIgnoreStyle("foo_bar", "FooBar") == 0 doAssert cmpIgnoreStyle("foo_bar_5", "FooBar4") > 0 - cmpIgnoreStyleImpl(a, b) + var i = 0 + var j = 0 + while true: + while i < a.len and a[i] == '_': inc i + while j < b.len and b[j] == '_': inc j + var aa = if i < a.len: toLowerAscii(a[i]) else: '\0' + var bb = if j < b.len: toLowerAscii(b[j]) else: '\0' + result = ord(aa) - ord(bb) + if result != 0: return result + # the characters are identical: + if i >= a.len: + # both cursors at the end: + if j >= b.len: return 0 + # not yet at the end of 'b': + return -1 + elif j >= b.len: + return 1 + inc i + inc j {.pop.} # --------- Private templates for different split separators ----------- -func substrEq(s: string, pos: int, substr: string): bool = +proc substrEq(s: string, pos: int, substr: string): bool = var i = 0 var length = substr.len while i < length and pos+i < s.len and s[pos+i] == substr[i]: @@ -443,7 +439,7 @@ iterator split*(s: string, sep: char, maxsplit: int = -1): string = ## * `rsplit iterator<#rsplit.i,string,char,int>`_ ## * `splitLines iterator<#splitLines.i,string>`_ ## * `splitWhitespace iterator<#splitWhitespace.i,string,int>`_ - ## * `split func<#split,string,char,int>`_ + ## * `split proc<#split,string,char,int>`_ splitCommon(s, sep, maxsplit, 1) iterator split*(s: string, seps: set[char] = Whitespace, @@ -492,7 +488,7 @@ iterator split*(s: string, seps: set[char] = Whitespace, ## * `rsplit iterator<#rsplit.i,string,set[char],int>`_ ## * `splitLines iterator<#splitLines.i,string>`_ ## * `splitWhitespace iterator<#splitWhitespace.i,string,int>`_ - ## * `split func<#split,string,set[char],int>`_ + ## * `split proc<#split,string,set[char],int>`_ splitCommon(s, seps, maxsplit, 1) iterator split*(s: string, sep: string, maxsplit: int = -1): string = @@ -516,7 +512,7 @@ iterator split*(s: string, sep: string, maxsplit: int = -1): string = ## * `rsplit iterator<#rsplit.i,string,string,int,bool>`_ ## * `splitLines iterator<#splitLines.i,string>`_ ## * `splitWhitespace iterator<#splitWhitespace.i,string,int>`_ - ## * `split func<#split,string,string,int>`_ + ## * `split proc<#split,string,string,int>`_ splitCommon(s, sep, maxsplit, sep.len) @@ -566,7 +562,7 @@ iterator rsplit*(s: string, sep: char, ## * `split iterator<#split.i,string,char,int>`_ ## * `splitLines iterator<#splitLines.i,string>`_ ## * `splitWhitespace iterator<#splitWhitespace.i,string,int>`_ - ## * `rsplit func<#rsplit,string,char,int>`_ + ## * `rsplit proc<#rsplit,string,char,int>`_ rsplitCommon(s, sep, maxsplit, 1) iterator rsplit*(s: string, seps: set[char] = Whitespace, @@ -591,7 +587,7 @@ iterator rsplit*(s: string, seps: set[char] = Whitespace, ## * `split iterator<#split.i,string,set[char],int>`_ ## * `splitLines iterator<#splitLines.i,string>`_ ## * `splitWhitespace iterator<#splitWhitespace.i,string,int>`_ - ## * `rsplit func<#rsplit,string,set[char],int>`_ + ## * `rsplit proc<#rsplit,string,set[char],int>`_ rsplitCommon(s, seps, maxsplit, 1) iterator rsplit*(s: string, sep: string, maxsplit: int = -1, @@ -616,7 +612,7 @@ iterator rsplit*(s: string, sep: string, maxsplit: int = -1, ## * `split iterator<#split.i,string,string,int>`_ ## * `splitLines iterator<#splitLines.i,string>`_ ## * `splitWhitespace iterator<#splitWhitespace.i,string,int>`_ - ## * `rsplit func<#rsplit,string,string,int>`_ + ## * `rsplit proc<#rsplit,string,string,int>`_ rsplitCommon(s, sep, maxsplit, sep.len) iterator splitLines*(s: string, keepEol = false): string = @@ -624,8 +620,8 @@ iterator splitLines*(s: string, keepEol = false): string = ## ## Every `character literal `_ ## newline combination (CR, LF, CR-LF) is supported. The result strings - ## contain no trailing end of line characters unless the parameter `keepEol` - ## is set to `true`. + ## contain no trailing end of line characters unless parameter ``keepEol`` + ## is set to ``true``. ## ## Example: ## @@ -646,7 +642,7 @@ iterator splitLines*(s: string, keepEol = false): string = ## ## See also: ## * `splitWhitespace iterator<#splitWhitespace.i,string,int>`_ - ## * `splitLines func<#splitLines,string>`_ + ## * `splitLines proc<#splitLines,string>`_ var first = 0 var last = 0 var eolpos = 0 @@ -669,9 +665,9 @@ iterator splitLines*(s: string, keepEol = false): string = first = last iterator splitWhitespace*(s: string, maxsplit: int = -1): string = - ## Splits the string `s` at whitespace stripping leading and trailing - ## whitespace if necessary. If `maxsplit` is specified and is positive, - ## no more than `maxsplit` splits is made. + ## Splits the string ``s`` at whitespace stripping leading and trailing + ## whitespace if necessary. If ``maxsplit`` is specified and is positive, + ## no more than ``maxsplit`` splits is made. ## ## The following code: ## @@ -703,43 +699,43 @@ iterator splitWhitespace*(s: string, maxsplit: int = -1): string = ## ## See also: ## * `splitLines iterator<#splitLines.i,string>`_ - ## * `splitWhitespace func<#splitWhitespace,string,int>`_ + ## * `splitWhitespace proc<#splitWhitespace,string,int>`_ oldSplit(s, Whitespace, maxsplit) -func split*(s: string, sep: char, maxsplit: int = -1): seq[string] {.rtl, - extern: "nsuSplitChar".} = +proc split*(s: string, sep: char, maxsplit: int = -1): seq[string] {.noSideEffect, + rtl, extern: "nsuSplitChar".} = ## The same as the `split iterator <#split.i,string,char,int>`_ (see its - ## documentation), but is a func that returns a sequence of substrings. + ## documentation), but is a proc that returns a sequence of substrings. ## ## See also: ## * `split iterator <#split.i,string,char,int>`_ - ## * `rsplit func<#rsplit,string,char,int>`_ - ## * `splitLines func<#splitLines,string>`_ - ## * `splitWhitespace func<#splitWhitespace,string,int>`_ + ## * `rsplit proc<#rsplit,string,char,int>`_ + ## * `splitLines proc<#splitLines,string>`_ + ## * `splitWhitespace proc<#splitWhitespace,string,int>`_ runnableExamples: doAssert "a,b,c".split(',') == @["a", "b", "c"] doAssert "".split(' ') == @[""] accResult(split(s, sep, maxsplit)) -func split*(s: string, seps: set[char] = Whitespace, maxsplit: int = -1): seq[ - string] {.rtl, extern: "nsuSplitCharSet".} = +proc split*(s: string, seps: set[char] = Whitespace, maxsplit: int = -1): seq[string] {. + noSideEffect, rtl, extern: "nsuSplitCharSet".} = ## The same as the `split iterator <#split.i,string,set[char],int>`_ (see its - ## documentation), but is a func that returns a sequence of substrings. + ## documentation), but is a proc that returns a sequence of substrings. ## ## See also: ## * `split iterator <#split.i,string,set[char],int>`_ - ## * `rsplit func<#rsplit,string,set[char],int>`_ - ## * `splitLines func<#splitLines,string>`_ - ## * `splitWhitespace func<#splitWhitespace,string,int>`_ + ## * `rsplit proc<#rsplit,string,set[char],int>`_ + ## * `splitLines proc<#splitLines,string>`_ + ## * `splitWhitespace proc<#splitWhitespace,string,int>`_ runnableExamples: doAssert "a,b;c".split({',', ';'}) == @["a", "b", "c"] doAssert "".split({' '}) == @[""] accResult(split(s, seps, maxsplit)) -func split*(s: string, sep: string, maxsplit: int = -1): seq[string] {.rtl, - extern: "nsuSplitString".} = +proc split*(s: string, sep: string, maxsplit: int = -1): seq[string] {.noSideEffect, + rtl, extern: "nsuSplitString".} = ## Splits the string `s` into substrings using a string separator. ## ## Substrings are separated by the string `sep`. This is a wrapper around the @@ -747,9 +743,9 @@ func split*(s: string, sep: string, maxsplit: int = -1): seq[string] {.rtl, ## ## See also: ## * `split iterator <#split.i,string,string,int>`_ - ## * `rsplit func<#rsplit,string,string,int>`_ - ## * `splitLines func<#splitLines,string>`_ - ## * `splitWhitespace func<#splitWhitespace,string,int>`_ + ## * `rsplit proc<#rsplit,string,string,int>`_ + ## * `splitLines proc<#splitLines,string>`_ + ## * `splitWhitespace proc<#splitWhitespace,string,int>`_ runnableExamples: doAssert "a,b,c".split(",") == @["a", "b", "c"] doAssert "a man a plan a canal panama".split("a ") == @["", "man ", "plan ", "canal panama"] @@ -761,9 +757,9 @@ func split*(s: string, sep: string, maxsplit: int = -1): seq[string] {.rtl, accResult(split(s, sep, maxsplit)) -func rsplit*(s: string, sep: char, maxsplit: int = -1): seq[string] {.rtl, - extern: "nsuRSplitChar".} = - ## The same as the `rsplit iterator <#rsplit.i,string,char,int>`_, but is a func +proc rsplit*(s: string, sep: char, maxsplit: int = -1): seq[string] + {.noSideEffect, rtl, extern: "nsuRSplitChar".} = + ## The same as the `rsplit iterator <#rsplit.i,string,char,int>`_, but is a proc ## that returns a sequence of substrings. ## ## A possible common use case for `rsplit` is path manipulation, @@ -782,17 +778,17 @@ func rsplit*(s: string, sep: char, maxsplit: int = -1): seq[string] {.rtl, ## ## See also: ## * `rsplit iterator <#rsplit.i,string,char,int>`_ - ## * `split func<#split,string,char,int>`_ - ## * `splitLines func<#splitLines,string>`_ - ## * `splitWhitespace func<#splitWhitespace,string,int>`_ + ## * `split proc<#split,string,char,int>`_ + ## * `splitLines proc<#splitLines,string>`_ + ## * `splitWhitespace proc<#splitWhitespace,string,int>`_ accResult(rsplit(s, sep, maxsplit)) result.reverse() -func rsplit*(s: string, seps: set[char] = Whitespace, +proc rsplit*(s: string, seps: set[char] = Whitespace, maxsplit: int = -1): seq[string] - {.rtl, extern: "nsuRSplitCharSet".} = + {.noSideEffect, rtl, extern: "nsuRSplitCharSet".} = ## The same as the `rsplit iterator <#rsplit.i,string,set[char],int>`_, but is a - ## func that returns a sequence of substrings. + ## proc that returns a sequence of substrings. ## ## A possible common use case for `rsplit` is path manipulation, ## particularly on systems that don't use a common delimiter. @@ -810,15 +806,15 @@ func rsplit*(s: string, seps: set[char] = Whitespace, ## ## See also: ## * `rsplit iterator <#rsplit.i,string,set[char],int>`_ - ## * `split func<#split,string,set[char],int>`_ - ## * `splitLines func<#splitLines,string>`_ - ## * `splitWhitespace func<#splitWhitespace,string,int>`_ + ## * `split proc<#split,string,set[char],int>`_ + ## * `splitLines proc<#splitLines,string>`_ + ## * `splitWhitespace proc<#splitWhitespace,string,int>`_ accResult(rsplit(s, seps, maxsplit)) result.reverse() -func rsplit*(s: string, sep: string, maxsplit: int = -1): seq[string] {.rtl, - extern: "nsuRSplitString".} = - ## The same as the `rsplit iterator <#rsplit.i,string,string,int,bool>`_, but is a func +proc rsplit*(s: string, sep: string, maxsplit: int = -1): seq[string] + {.noSideEffect, rtl, extern: "nsuRSplitString".} = + ## The same as the `rsplit iterator <#rsplit.i,string,string,int,bool>`_, but is a proc ## that returns a sequence of substrings. ## ## A possible common use case for `rsplit` is path manipulation, @@ -837,9 +833,9 @@ func rsplit*(s: string, sep: string, maxsplit: int = -1): seq[string] {.rtl, ## ## See also: ## * `rsplit iterator <#rsplit.i,string,string,int,bool>`_ - ## * `split func<#split,string,string,int>`_ - ## * `splitLines func<#splitLines,string>`_ - ## * `splitWhitespace func<#splitWhitespace,string,int>`_ + ## * `split proc<#split,string,string,int>`_ + ## * `splitLines proc<#splitLines,string>`_ + ## * `splitWhitespace proc<#splitWhitespace,string,int>`_ runnableExamples: doAssert "a largely spaced sentence".rsplit(" ", maxsplit = 1) == @[ "a largely spaced", "sentence"] @@ -852,31 +848,32 @@ func rsplit*(s: string, sep: string, maxsplit: int = -1): seq[string] {.rtl, accResult(rsplit(s, sep, maxsplit)) result.reverse() -func splitLines*(s: string, keepEol = false): seq[string] {.rtl, - extern: "nsuSplitLines".} = +proc splitLines*(s: string, keepEol = false): seq[string] {.noSideEffect, + rtl, extern: "nsuSplitLines".} = ## The same as the `splitLines iterator<#splitLines.i,string>`_ (see its - ## documentation), but is a func that returns a sequence of substrings. + ## documentation), but is a proc that returns a sequence of substrings. ## ## See also: ## * `splitLines iterator<#splitLines.i,string>`_ - ## * `splitWhitespace func<#splitWhitespace,string,int>`_ - ## * `countLines func<#countLines,string>`_ + ## * `splitWhitespace proc<#splitWhitespace,string,int>`_ + ## * `countLines proc<#countLines,string>`_ accResult(splitLines(s, keepEol = keepEol)) -func splitWhitespace*(s: string, maxsplit: int = -1): seq[string] {.rtl, - extern: "nsuSplitWhitespace".} = +proc splitWhitespace*(s: string, maxsplit: int = -1): seq[string] {.noSideEffect, + rtl, extern: "nsuSplitWhitespace".} = ## The same as the `splitWhitespace iterator <#splitWhitespace.i,string,int>`_ - ## (see its documentation), but is a func that returns a sequence of substrings. + ## (see its documentation), but is a proc that returns a sequence of substrings. ## ## See also: ## * `splitWhitespace iterator <#splitWhitespace.i,string,int>`_ - ## * `splitLines func<#splitLines,string>`_ + ## * `splitLines proc<#splitLines,string>`_ accResult(splitWhitespace(s, maxsplit)) -func toBin*(x: BiggestInt, len: Positive): string {.rtl, extern: "nsuToBin".} = +proc toBin*(x: BiggestInt, len: Positive): string {.noSideEffect, + rtl, extern: "nsuToBin".} = ## Converts `x` into its binary representation. ## - ## The resulting string is always `len` characters long. No leading `0b` + ## The resulting string is always `len` characters long. No leading ``0b`` ## prefix is generated. runnableExamples: let @@ -895,13 +892,14 @@ func toBin*(x: BiggestInt, len: Positive): string {.rtl, extern: "nsuToBin".} = inc shift mask = mask shl BiggestUInt(1) -func toOct*(x: BiggestInt, len: Positive): string {.rtl, extern: "nsuToOct".} = +proc toOct*(x: BiggestInt, len: Positive): string {.noSideEffect, + rtl, extern: "nsuToOct".} = ## Converts `x` into its octal representation. ## - ## The resulting string is always `len` characters long. No leading `0o` + ## The resulting string is always `len` characters long. No leading ``0o`` ## prefix is generated. ## - ## Do not confuse it with `toOctal func<#toOctal,char>`_. + ## Do not confuse it with `toOctal proc<#toOctal,char>`_. runnableExamples: let a = 62 @@ -919,60 +917,44 @@ func toOct*(x: BiggestInt, len: Positive): string {.rtl, extern: "nsuToOct".} = inc shift, 3 mask = mask shl BiggestUInt(3) -func toHexImpl(x: BiggestUInt, len: Positive, handleNegative: bool): string = +proc toHex*(x: BiggestInt, len: Positive): string {.noSideEffect, + rtl, extern: "nsuToHex".} = + ## Converts `x` to its hexadecimal representation. + ## + ## The resulting string will be exactly `len` characters long. No prefix like + ## ``0x`` is generated. `x` is treated as an unsigned value. + runnableExamples: + let + a = 62 + b = 4097 + doAssert a.toHex(3) == "03E" + doAssert b.toHex(3) == "001" + doAssert b.toHex(4) == "1001" const HexChars = "0123456789ABCDEF" - var n = x + var + n = x result = newString(len) for j in countdown(len-1, 0): result[j] = HexChars[int(n and 0xF)] n = n shr 4 # handle negative overflow - if n == 0 and handleNegative: n = not(BiggestUInt 0) + if n == 0 and x < 0: n = -1 -func toHex*[T: SomeInteger](x: T, len: Positive): string = - ## Converts `x` to its hexadecimal representation. - ## - ## The resulting string will be exactly `len` characters long. No prefix like - ## `0x` is generated. `x` is treated as an unsigned value. - runnableExamples: - let - a = 62'u64 - b = 4097'u64 - doAssert a.toHex(3) == "03E" - doAssert b.toHex(3) == "001" - doAssert b.toHex(4) == "1001" - doAssert toHex(62, 3) == "03E" - doAssert toHex(-8, 6) == "FFFFF8" - when defined(js): - toHexImpl(cast[BiggestUInt](x), len, x < 0) - else: - when T is SomeSignedInt: - toHexImpl(cast[BiggestUInt](BiggestInt(x)), len, x < 0) - else: - toHexImpl(BiggestUInt(x), len, x < 0) - -func toHex*[T: SomeInteger](x: T): string = - ## Shortcut for `toHex(x, T.sizeof * 2)` +proc toHex*[T: SomeInteger](x: T): string = + ## Shortcut for ``toHex(x, T.sizeof * 2)`` runnableExamples: doAssert toHex(1984'i64) == "00000000000007C0" - doAssert toHex(1984'i16) == "07C0" - when defined(js): - toHexImpl(cast[BiggestUInt](x), 2*sizeof(T), x < 0) - else: - when T is SomeSignedInt: - toHexImpl(cast[BiggestUInt](BiggestInt(x)), 2*sizeof(T), x < 0) - else: - toHexImpl(BiggestUInt(x), 2*sizeof(T), x < 0) + toHex(BiggestInt(x), T.sizeof * 2) -func toHex*(s: string): string {.rtl.} = +proc toHex*(s: string): string {.noSideEffect, rtl.} = ## Converts a bytes string to its hexadecimal representation. ## ## The output is twice the input long. No prefix like - ## `0x` is generated. + ## ``0x`` is generated. ## ## See also: - ## * `parseHexStr func<#parseHexStr,string>`_ for the reverse operation + ## * `parseHexStr proc<#parseHexStr,string>`_ for the reverse operation runnableExamples: let a = "1" @@ -990,13 +972,13 @@ func toHex*(s: string): string {.rtl.} = n = n shr 4 result[pos * 2] = HexChars[n] -func toOctal*(c: char): string {.rtl, extern: "nsuToOctal".} = +proc toOctal*(c: char): string {.noSideEffect, rtl, extern: "nsuToOctal".} = ## Converts a character `c` to its octal representation. ## ## The resulting string may not have a leading zero. Its length is always ## exactly 3. ## - ## Do not confuse it with `toOct func<#toOct,BiggestInt,Positive>`_. + ## Do not confuse it with `toOct proc<#toOct,BiggestInt,Positive>`_. runnableExamples: doAssert toOctal('1') == "061" doAssert toOctal('A') == "101" @@ -1009,7 +991,7 @@ func toOctal*(c: char): string {.rtl, extern: "nsuToOctal".} = result[i] = chr(val mod 8 + ord('0')) val = val div 8 -func fromBin*[T: SomeInteger](s: string): T = +proc fromBin*[T: SomeInteger](s: string): T = ## Parses a binary integer value from a string `s`. ## ## If `s` is not a valid binary integer, `ValueError` is raised. `s` can have @@ -1032,7 +1014,7 @@ func fromBin*[T: SomeInteger](s: string): T = if p != s.len or p == 0: raise newException(ValueError, "invalid binary integer: " & s) -func fromOct*[T: SomeInteger](s: string): T = +proc fromOct*[T: SomeInteger](s: string): T = ## Parses an octal integer value from a string `s`. ## ## If `s` is not a valid octal integer, `ValueError` is raised. `s` can have @@ -1055,7 +1037,7 @@ func fromOct*[T: SomeInteger](s: string): T = if p != s.len or p == 0: raise newException(ValueError, "invalid oct integer: " & s) -func fromHex*[T: SomeInteger](s: string): T = +proc fromHex*[T: SomeInteger](s: string): T = ## Parses a hex integer value from a string `s`. ## ## If `s` is not a valid hex integer, `ValueError` is raised. `s` can have @@ -1078,8 +1060,8 @@ func fromHex*[T: SomeInteger](s: string): T = if p != s.len or p == 0: raise newException(ValueError, "invalid hex integer: " & s) -func intToStr*(x: int, minchars: Positive = 1): string {.rtl, - extern: "nsuIntToStr".} = +proc intToStr*(x: int, minchars: Positive = 1): string {.noSideEffect, + rtl, extern: "nsuIntToStr".} = ## Converts `x` to its decimal representation. ## ## The resulting string will be minimally `minchars` characters long. This is @@ -1093,64 +1075,63 @@ func intToStr*(x: int, minchars: Positive = 1): string {.rtl, if x < 0: result = '-' & result -func parseInt*(s: string): int {.rtl, extern: "nsuParseInt".} = +proc parseInt*(s: string): int {.noSideEffect, procvar, + rtl, extern: "nsuParseInt".} = ## Parses a decimal integer value contained in `s`. ## ## If `s` is not a valid integer, `ValueError` is raised. runnableExamples: doAssert parseInt("-0042") == -42 - result = 0 let L = parseutils.parseInt(s, result, 0) if L != s.len or L == 0: raise newException(ValueError, "invalid integer: " & s) -func parseBiggestInt*(s: string): BiggestInt {.rtl, - extern: "nsuParseBiggestInt".} = +proc parseBiggestInt*(s: string): BiggestInt {.noSideEffect, procvar, + rtl, extern: "nsuParseBiggestInt".} = ## Parses a decimal integer value contained in `s`. ## ## If `s` is not a valid integer, `ValueError` is raised. - result = BiggestInt(0) let L = parseutils.parseBiggestInt(s, result, 0) if L != s.len or L == 0: raise newException(ValueError, "invalid integer: " & s) -func parseUInt*(s: string): uint {.rtl, extern: "nsuParseUInt".} = +proc parseUInt*(s: string): uint {.noSideEffect, procvar, + rtl, extern: "nsuParseUInt".} = ## Parses a decimal unsigned integer value contained in `s`. ## ## If `s` is not a valid integer, `ValueError` is raised. - result = uint(0) let L = parseutils.parseUInt(s, result, 0) if L != s.len or L == 0: raise newException(ValueError, "invalid unsigned integer: " & s) -func parseBiggestUInt*(s: string): BiggestUInt {.rtl, - extern: "nsuParseBiggestUInt".} = +proc parseBiggestUInt*(s: string): BiggestUInt {.noSideEffect, procvar, + rtl, extern: "nsuParseBiggestUInt".} = ## Parses a decimal unsigned integer value contained in `s`. ## ## If `s` is not a valid integer, `ValueError` is raised. - result = BiggestUInt(0) let L = parseutils.parseBiggestUInt(s, result, 0) if L != s.len or L == 0: raise newException(ValueError, "invalid unsigned integer: " & s) -func parseFloat*(s: string): float {.rtl, extern: "nsuParseFloat".} = +proc parseFloat*(s: string): float {.noSideEffect, procvar, + rtl, extern: "nsuParseFloat".} = ## Parses a decimal floating point value contained in `s`. ## ## If `s` is not a valid floating point number, `ValueError` is raised. - ##`NAN`, `INF`, `-INF` are also supported (case insensitive comparison). + ##``NAN``, ``INF``, ``-INF`` are also supported (case insensitive comparison). runnableExamples: doAssert parseFloat("3.14") == 3.14 doAssert parseFloat("inf") == 1.0/0 - result = 0.0 let L = parseutils.parseFloat(s, result, 0) if L != s.len or L == 0: raise newException(ValueError, "invalid float: " & s) -func parseBinInt*(s: string): int {.rtl, extern: "nsuParseBinInt".} = +proc parseBinInt*(s: string): int {.noSideEffect, procvar, + rtl, extern: "nsuParseBinInt".} = ## Parses a binary integer value contained in `s`. ## ## If `s` is not a valid binary integer, `ValueError` is raised. `s` can have - ## one of the following optional prefixes: `0b`, `0B`. Underscores within + ## one of the following optional prefixes: ``0b``, ``0B``. Underscores within ## `s` are ignored. runnableExamples: let @@ -1159,56 +1140,56 @@ func parseBinInt*(s: string): int {.rtl, extern: "nsuParseBinInt".} = doAssert a.parseBinInt() == 53 doAssert b.parseBinInt() == 7 - result = 0 let L = parseutils.parseBin(s, result, 0) if L != s.len or L == 0: raise newException(ValueError, "invalid binary integer: " & s) -func parseOctInt*(s: string): int {.rtl, extern: "nsuParseOctInt".} = +proc parseOctInt*(s: string): int {.noSideEffect, + rtl, extern: "nsuParseOctInt".} = ## Parses an octal integer value contained in `s`. ## ## If `s` is not a valid oct integer, `ValueError` is raised. `s` can have one - ## of the following optional prefixes: `0o`, `0O`. Underscores within + ## of the following optional prefixes: ``0o``, ``0O``. Underscores within ## `s` are ignored. - result = 0 let L = parseutils.parseOct(s, result, 0) if L != s.len or L == 0: raise newException(ValueError, "invalid oct integer: " & s) -func parseHexInt*(s: string): int {.rtl, extern: "nsuParseHexInt".} = +proc parseHexInt*(s: string): int {.noSideEffect, procvar, + rtl, extern: "nsuParseHexInt".} = ## Parses a hexadecimal integer value contained in `s`. ## ## If `s` is not a valid hex integer, `ValueError` is raised. `s` can have one - ## of the following optional prefixes: `0x`, `0X`, `#`. Underscores + ## of the following optional prefixes: ``0x``, ``0X``, ``#``. Underscores ## within `s` are ignored. - result = 0 let L = parseutils.parseHex(s, result, 0) if L != s.len or L == 0: raise newException(ValueError, "invalid hex integer: " & s) -func generateHexCharToValueMap(): string = - ## Generates a string to map a hex digit to uint value. +proc generateHexCharToValueMap(): string = + ## Generate a string to map a hex digit to uint value result = "" for inp in 0..255: let ch = chr(inp) let o = - case ch - of '0'..'9': inp - ord('0') - of 'a'..'f': inp - ord('a') + 10 - of 'A'..'F': inp - ord('A') + 10 - else: 17 # indicates an invalid hex char + case ch: + of '0'..'9': inp - ord('0') + of 'a'..'f': inp - ord('a') + 10 + of 'A'..'F': inp - ord('A') + 10 + else: 17 # indicates an invalid hex char result.add chr(o) const hexCharToValueMap = generateHexCharToValueMap() -func parseHexStr*(s: string): string {.rtl, extern: "nsuParseHexStr".} = - ## Converts hex-encoded string to byte string, e.g.: +proc parseHexStr*(s: string): string {.noSideEffect, procvar, + rtl, extern: "nsuParseHexStr".} = + ## Convert hex-encoded string to byte string, e.g.: ## - ## Raises `ValueError` for an invalid hex values. The comparison is + ## Raises ``ValueError`` for an invalid hex values. The comparison is ## case-insensitive. ## ## See also: - ## * `toHex func<#toHex,string>`_ for the reverse operation + ## * `toHex proc<#toHex,string>`_ for the reverse operation runnableExamples: let a = "41" @@ -1232,13 +1213,13 @@ func parseHexStr*(s: string): string {.rtl, extern: "nsuParseHexStr".} = else: result[pos div 2] = chr(val + buf shl 4) -func parseBool*(s: string): bool = +proc parseBool*(s: string): bool = ## Parses a value into a `bool`. ## - ## If `s` is one of the following values: `y, yes, true, 1, on`, then - ## returns `true`. If `s` is one of the following values: `n, no, false, - ## 0, off`, then returns `false`. If `s` is something else a - ## `ValueError` exception is raised. + ## If ``s`` is one of the following values: ``y, yes, true, 1, on``, then + ## returns `true`. If ``s`` is one of the following values: ``n, no, false, + ## 0, off``, then returns `false`. If ``s`` is something else a + ## ``ValueError`` exception is raised. runnableExamples: let a = "n" doAssert parseBool(a) == false @@ -1248,11 +1229,10 @@ func parseBool*(s: string): bool = of "n", "no", "false", "0", "off": result = false else: raise newException(ValueError, "cannot interpret as a bool: " & s) -func parseEnum*[T: enum](s: string): T = - ## Parses an enum `T`. This errors at compile time, if the given enum - ## type contains multiple fields with the same string value. +proc parseEnum*[T: enum](s: string): T = + ## Parses an enum ``T``. ## - ## Raises `ValueError` for an invalid value in `s`. The comparison is + ## Raises ``ValueError`` for an invalid value in `s`. The comparison is ## done in a style insensitive way. runnableExamples: type @@ -1266,11 +1246,13 @@ func parseEnum*[T: enum](s: string): T = doAssertRaises(ValueError): echo parseEnum[MyEnum]("third") - genEnumCaseStmt(T, s, default = nil, ord(low(T)), ord(high(T)), nimIdentNormalize) + for e in low(T)..high(T): + if cmpIgnoreStyle(s, $e) == 0: + return e + raise newException(ValueError, "invalid enum value: " & s) -func parseEnum*[T: enum](s: string, default: T): T = - ## Parses an enum `T`. This errors at compile time, if the given enum - ## type contains multiple fields with the same string value. +proc parseEnum*[T: enum](s: string, default: T): T = + ## Parses an enum ``T``. ## ## Uses `default` for an invalid value in `s`. The comparison is done in a ## style insensitive way. @@ -1285,9 +1267,13 @@ func parseEnum*[T: enum](s: string, default: T): T = doAssert parseEnum[MyEnum]("second") == second doAssert parseEnum[MyEnum]("last", third) == third - genEnumCaseStmt(T, s, default, ord(low(T)), ord(high(T)), nimIdentNormalize) + for e in low(T)..high(T): + if cmpIgnoreStyle(s, $e) == 0: + return e + result = default -func repeat*(c: char, count: Natural): string {.rtl, extern: "nsuRepeatChar".} = +proc repeat*(c: char, count: Natural): string {.noSideEffect, + rtl, extern: "nsuRepeatChar".} = ## Returns a string of length `count` consisting only of ## the character `c`. runnableExamples: @@ -1296,7 +1282,8 @@ func repeat*(c: char, count: Natural): string {.rtl, extern: "nsuRepeatChar".} = result = newString(count) for i in 0..count-1: result[i] = c -func repeat*(s: string, n: Natural): string {.rtl, extern: "nsuRepeatStr".} = +proc repeat*(s: string, n: Natural): string {.noSideEffect, + rtl, extern: "nsuRepeatStr".} = ## Returns string `s` concatenated `n` times. runnableExamples: doAssert "+ foo +".repeat(3) == "+ foo ++ foo ++ foo +" @@ -1304,15 +1291,15 @@ func repeat*(s: string, n: Natural): string {.rtl, extern: "nsuRepeatStr".} = result = newStringOfCap(n * s.len) for i in 1..n: result.add(s) -func spaces*(n: Natural): string {.inline.} = - ## Returns a string with `n` space characters. You can use this func +proc spaces*(n: Natural): string {.inline.} = + ## Returns a string with `n` space characters. You can use this proc ## to left align strings. ## ## See also: - ## * `align func<#align,string,Natural,char>`_ - ## * `alignLeft func<#alignLeft,string,Natural,char>`_ - ## * `indent func<#indent,string,Natural,string>`_ - ## * `center func<#center,string,int,char>`_ + ## * `align proc<#align,string,Natural,char>`_ + ## * `alignLeft proc<#alignLeft,string,Natural,char>`_ + ## * `indent proc<#indent,string,Natural,string>`_ + ## * `center proc<#center,string,int,char>`_ runnableExamples: let width = 15 @@ -1324,20 +1311,20 @@ func spaces*(n: Natural): string {.inline.} = "This is a very long string|" repeat(' ', n) -func align*(s: string, count: Natural, padding = ' '): string {.rtl, - extern: "nsuAlignString".} = +proc align*(s: string, count: Natural, padding = ' '): string {. + noSideEffect, rtl, extern: "nsuAlignString".} = ## Aligns a string `s` with `padding`, so that it is of length `count`. ## ## `padding` characters (by default spaces) are added before `s` resulting in - ## right alignment. If `s.len >= count`, no spaces are added and `s` is + ## right alignment. If ``s.len >= count``, no spaces are added and `s` is ## returned unchanged. If you need to left align a string use the `alignLeft - ## func<#alignLeft,string,Natural,char>`_. + ## proc <#alignLeft,string,Natural,char>`_. ## ## See also: - ## * `alignLeft func<#alignLeft,string,Natural,char>`_ - ## * `spaces func<#spaces,Natural>`_ - ## * `indent func<#indent,string,Natural,string>`_ - ## * `center func<#center,string,int,char>`_ + ## * `alignLeft proc<#alignLeft,string,Natural,char>`_ + ## * `spaces proc<#spaces,Natural>`_ + ## * `indent proc<#indent,string,Natural,string>`_ + ## * `center proc<#center,string,int,char>`_ runnableExamples: assert align("abc", 4) == " abc" assert align("a", 0) == "a" @@ -1351,19 +1338,20 @@ func align*(s: string, count: Natural, padding = ' '): string {.rtl, else: result = s -func alignLeft*(s: string, count: Natural, padding = ' '): string = +proc alignLeft*(s: string, count: Natural, padding = ' '): string {. + noSideEffect.} = ## Left-Aligns a string `s` with `padding`, so that it is of length `count`. ## ## `padding` characters (by default spaces) are added after `s` resulting in - ## left alignment. If `s.len >= count`, no spaces are added and `s` is + ## left alignment. If ``s.len >= count``, no spaces are added and `s` is ## returned unchanged. If you need to right align a string use the `align - ## func<#align,string,Natural,char>`_. + ## proc <#align,string,Natural,char>`_. ## ## See also: - ## * `align func<#align,string,Natural,char>`_ - ## * `spaces func<#spaces,Natural>`_ - ## * `indent func<#indent,string,Natural,string>`_ - ## * `center func<#center,string,int,char>`_ + ## * `align proc<#align,string,Natural,char>`_ + ## * `spaces proc<#spaces,Natural>`_ + ## * `indent proc<#indent,string,Natural,string>`_ + ## * `center proc<#center,string,int,char>`_ runnableExamples: assert alignLeft("abc", 4) == "abc " assert alignLeft("a", 0) == "a" @@ -1378,8 +1366,8 @@ func alignLeft*(s: string, count: Natural, padding = ' '): string = else: result = s -func center*(s: string, width: int, fillChar: char = ' '): string {.rtl, - extern: "nsuCenterString".} = +proc center*(s: string, width: int, fillChar: char = ' '): string {. + noSideEffect, rtl, extern: "nsuCenterString".} = ## Return the contents of `s` centered in a string `width` long using ## `fillChar` (default: space) as padding. ## @@ -1387,10 +1375,10 @@ func center*(s: string, width: int, fillChar: char = ' '): string {.rtl, ## to `s.len`. ## ## See also: - ## * `align func<#align,string,Natural,char>`_ - ## * `alignLeft func<#alignLeft,string,Natural,char>`_ - ## * `spaces func<#spaces,Natural>`_ - ## * `indent func<#indent,string,Natural,string>`_ + ## * `align proc<#align,string,Natural,char>`_ + ## * `alignLeft proc<#alignLeft,string,Natural,char>`_ + ## * `spaces proc<#spaces,Natural>`_ + ## * `indent proc<#indent,string,Natural,string>`_ runnableExamples: let a = "foo" doAssert a.center(2) == "foo" @@ -1413,18 +1401,17 @@ func center*(s: string, width: int, fillChar: char = ' '): string {.rtl, # the string s should go result[i] = fillChar -func indent*(s: string, count: Natural, padding: string = " "): string {.rtl, - extern: "nsuIndent".} = - ## Indents each line in `s` by `count` amount of `padding`. +proc indent*(s: string, count: Natural, padding: string = " "): string + {.noSideEffect, rtl, extern: "nsuIndent".} = + ## Indents each line in ``s`` by ``count`` amount of ``padding``. ## - ## **Note:** This does not preserve the new line characters used in `s`. + ## **Note:** This does not preserve the new line characters used in ``s``. ## ## See also: - ## * `align func<#align,string,Natural,char>`_ - ## * `alignLeft func<#alignLeft,string,Natural,char>`_ - ## * `spaces func<#spaces,Natural>`_ - ## * `unindent func<#unindent,string,Natural,string>`_ - ## * `dedent func<#dedent,string,Natural>`_ + ## * `align proc<#align,string,Natural,char>`_ + ## * `alignLeft proc<#alignLeft,string,Natural,char>`_ + ## * `spaces proc<#spaces,Natural>`_ + ## * `unindent proc<#unindent,string,Natural,string>`_ runnableExamples: doAssert indent("First line\c\l and second line.", 2) == " First line\l and second line." @@ -1438,25 +1425,21 @@ func indent*(s: string, count: Natural, padding: string = " "): string {.rtl, result.add(line) i.inc -func unindent*(s: string, count: Natural = int.high, - padding: string = " "): string {.rtl, extern: "nsuUnindent".} = - ## Unindents each line in `s` by `count` amount of `padding`. +proc unindent*(s: string, count: Natural, padding: string = " "): string + {.noSideEffect, rtl, extern: "nsuUnindent".} = + ## Unindents each line in ``s`` by ``count`` amount of ``padding``. + ## Sometimes called `dedent`:idx: ## - ## **Note:** This does not preserve the new line characters used in `s`. + ## **Note:** This does not preserve the new line characters used in ``s``. ## ## See also: - ## * `dedent func<#dedent,string,Natural>`_ - ## * `align func<#align,string,Natural,char>`_ - ## * `alignLeft func<#alignLeft,string,Natural,char>`_ - ## * `spaces func<#spaces,Natural>`_ - ## * `indent func<#indent,string,Natural,string>`_ + ## * `align proc<#align,string,Natural,char>`_ + ## * `alignLeft proc<#alignLeft,string,Natural,char>`_ + ## * `spaces proc<#spaces,Natural>`_ + ## * `indent proc<#indent,string,Natural,string>`_ runnableExamples: - let x = """ - Hello - There - """.unindent() - - doAssert x == "Hello\nThere\n" + doAssert unindent(" First line\l and second line", 3) == + "First line\land second line" result = "" var i = 0 for line in s.splitLines(): @@ -1471,78 +1454,31 @@ func unindent*(s: string, count: Natural = int.high, result.add(line[indentCount*padding.len .. ^1]) i.inc -func indentation*(s: string): Natural {.since: (1, 3).} = - ## Returns the amount of indentation all lines of `s` have in common, - ## ignoring lines that consist only of whitespace. - result = int.high - for line in s.splitLines: - for i, c in line: - if i >= result: break - elif c != ' ': - result = i - break - if result == int.high: - result = 0 - -func dedent*(s: string, count: Natural = indentation(s)): string {.rtl, - extern: "nsuDedent", since: (1, 3).} = - ## Unindents each line in `s` by `count` amount of `padding`. - ## The only difference between this and the - ## `unindent func<#unindent,string,Natural,string>`_ is that this by default - ## only cuts off the amount of indentation that all lines of `s` share as - ## opposed to all indentation. It only supports spaces as padding. - ## - ## **Note:** This does not preserve the new line characters used in `s`. +proc unindent*(s: string): string + {.noSideEffect, rtl, extern: "nsuUnindentAll".} = + ## Removes all indentation composed of whitespace from each line in ``s``. ## ## See also: - ## * `unindent func<#unindent,string,Natural,string>`_ - ## * `align func<#align,string,Natural,char>`_ - ## * `alignLeft func<#alignLeft,string,Natural,char>`_ - ## * `spaces func<#spaces,Natural>`_ - ## * `indent func<#indent,string,Natural,string>`_ + ## * `align proc<#align,string,Natural,char>`_ + ## * `alignLeft proc<#alignLeft,string,Natural,char>`_ + ## * `spaces proc<#spaces,Natural>`_ + ## * `indent proc<#indent,string,Natural,string>`_ runnableExamples: let x = """ Hello - There - """.dedent() + There + """.unindent() - doAssert x == "Hello\n There\n" - unindent(s, count, " ") + doAssert x == "Hello\nThere\n" + unindent(s, 1000) # TODO: Passing a 1000 is a bit hackish. -func delete*(s: var string, slice: Slice[int]) = - ## Deletes the items `s[slice]`, raising `IndexDefect` if the slice contains - ## elements out of range. +proc delete*(s: var string, first, last: int) {.noSideEffect, + rtl, extern: "nsuDelete".} = + ## Deletes in `s` (must be declared as ``var``) the characters at positions + ## ``first ..last`` (both ends included). ## - ## This operation moves all elements after `s[slice]` in linear time, and - ## is the string analog to `sequtils.delete`. + ## This modifies `s` itself, it does not return a copy. runnableExamples: - var a = "abcde" - doAssertRaises(IndexDefect): a.delete(4..5) - assert a == "abcde" - a.delete(4..4) - assert a == "abcd" - a.delete(1..2) - assert a == "ad" - a.delete(1..<1) # empty slice - assert a == "ad" - when compileOption("boundChecks"): - if not (slice.a < s.len and slice.a >= 0 and slice.b < s.len): - raise newException(IndexDefect, $(slice: slice, len: s.len)) - if slice.b >= slice.a: - var i = slice.a - var j = slice.b + 1 - var newLen = s.len - j + i - # if j < s.len: moveMem(addr s[i], addr s[j], s.len - j) # pending benchmark - while i < newLen: - s[i] = s[j] - inc(i) - inc(j) - setLen(s, newLen) - -func delete*(s: var string, first, last: int) {.rtl, extern: "nsuDelete", - deprecated: "use `delete(s, first..last)`".} = - ## Deletes in `s` the characters at positions `first .. last` (both ends included). - runnableExamples("--warning:deprecated:off"): var a = "abracadabra" a.delete(4, 5) @@ -1563,71 +1499,83 @@ func delete*(s: var string, first, last: int) {.rtl, extern: "nsuDelete", inc(j) setLen(s, newLen) -func startsWith*(s: string, prefix: char): bool {.inline.} = - ## Returns true if `s` starts with character `prefix`. + +proc startsWith*(s: string, prefix: char): bool {.noSideEffect, inline.} = + ## Returns true if ``s`` starts with character ``prefix``. ## ## See also: - ## * `endsWith func<#endsWith,string,char>`_ - ## * `continuesWith func<#continuesWith,string,string,Natural>`_ - ## * `removePrefix func<#removePrefix,string,char>`_ + ## * `endsWith proc<#endsWith,string,char>`_ + ## * `continuesWith proc<#continuesWith,string,string,Natural>`_ + ## * `removePrefix proc<#removePrefix,string,char>`_ runnableExamples: let a = "abracadabra" doAssert a.startsWith('a') == true doAssert a.startsWith('b') == false result = s.len > 0 and s[0] == prefix -func startsWith*(s, prefix: string): bool {.rtl, extern: "nsuStartsWith".} = - ## Returns true if `s` starts with string `prefix`. +proc startsWith*(s, prefix: string): bool {.noSideEffect, + rtl, extern: "nsuStartsWith".} = + ## Returns true if ``s`` starts with string ``prefix``. ## - ## If `prefix == ""` true is returned. + ## If ``prefix == ""`` true is returned. ## ## See also: - ## * `endsWith func<#endsWith,string,string>`_ - ## * `continuesWith func<#continuesWith,string,string,Natural>`_ - ## * `removePrefix func<#removePrefix,string,string>`_ + ## * `endsWith proc<#endsWith,string,string>`_ + ## * `continuesWith proc<#continuesWith,string,string,Natural>`_ + ## * `removePrefix proc<#removePrefix,string,string>`_ runnableExamples: let a = "abracadabra" doAssert a.startsWith("abra") == true doAssert a.startsWith("bra") == false - startsWithImpl(s, prefix) + var i = 0 + while true: + if i >= prefix.len: return true + if i >= s.len or s[i] != prefix[i]: return false + inc(i) -func endsWith*(s: string, suffix: char): bool {.inline.} = - ## Returns true if `s` ends with `suffix`. +proc endsWith*(s: string, suffix: char): bool {.noSideEffect, inline.} = + ## Returns true if ``s`` ends with ``suffix``. ## ## See also: - ## * `startsWith func<#startsWith,string,char>`_ - ## * `continuesWith func<#continuesWith,string,string,Natural>`_ - ## * `removeSuffix func<#removeSuffix,string,char>`_ + ## * `startsWith proc<#startsWith,string,char>`_ + ## * `continuesWith proc<#continuesWith,string,string,Natural>`_ + ## * `removeSuffix proc<#removeSuffix,string,char>`_ runnableExamples: let a = "abracadabra" doAssert a.endsWith('a') == true doAssert a.endsWith('b') == false result = s.len > 0 and s[s.high] == suffix -func endsWith*(s, suffix: string): bool {.rtl, extern: "nsuEndsWith".} = - ## Returns true if `s` ends with `suffix`. +proc endsWith*(s, suffix: string): bool {.noSideEffect, + rtl, extern: "nsuEndsWith".} = + ## Returns true if ``s`` ends with ``suffix``. ## - ## If `suffix == ""` true is returned. + ## If ``suffix == ""`` true is returned. ## ## See also: - ## * `startsWith func<#startsWith,string,string>`_ - ## * `continuesWith func<#continuesWith,string,string,Natural>`_ - ## * `removeSuffix func<#removeSuffix,string,string>`_ + ## * `startsWith proc<#startsWith,string,string>`_ + ## * `continuesWith proc<#continuesWith,string,string,Natural>`_ + ## * `removeSuffix proc<#removeSuffix,string,string>`_ runnableExamples: let a = "abracadabra" doAssert a.endsWith("abra") == true doAssert a.endsWith("dab") == false - endsWithImpl(s, suffix) + var i = 0 + var j = len(s) - len(suffix) + while i+j >= 0 and i+j < s.len: + if s[i+j] != suffix[i]: return false + inc(i) + if i >= suffix.len: return true -func continuesWith*(s, substr: string, start: Natural): bool {.rtl, - extern: "nsuContinuesWith".} = - ## Returns true if `s` continues with `substr` at position `start`. +proc continuesWith*(s, substr: string, start: Natural): bool {.noSideEffect, + rtl, extern: "nsuContinuesWith".} = + ## Returns true if ``s`` continues with ``substr`` at position ``start``. ## - ## If `substr == ""` true is returned. + ## If ``substr == ""`` true is returned. ## ## See also: - ## * `startsWith func<#startsWith,string,string>`_ - ## * `endsWith func<#endsWith,string,string>`_ + ## * `startsWith proc<#startsWith,string,string>`_ + ## * `endsWith proc<#endsWith,string,string>`_ runnableExamples: let a = "abracadabra" doAssert a.continuesWith("ca", 4) == true @@ -1640,13 +1588,13 @@ func continuesWith*(s, substr: string, start: Natural): bool {.rtl, inc(i) -func removePrefix*(s: var string, chars: set[char] = Newlines) {.rtl, - extern: "nsuRemovePrefixCharSet".} = +proc removePrefix*(s: var string, chars: set[char] = Newlines) {. + rtl, extern: "nsuRemovePrefixCharSet".} = ## Removes all characters from `chars` from the start of the string `s` ## (in-place). ## ## See also: - ## * `removeSuffix func<#removeSuffix,string,set[char]>`_ + ## * `removeSuffix proc<#removeSuffix,string,set[char]>`_ runnableExamples: var userInput = "\r\n*~Hello World!" userInput.removePrefix @@ -1660,43 +1608,43 @@ func removePrefix*(s: var string, chars: set[char] = Newlines) {.rtl, var start = 0 while start < s.len and s[start] in chars: start += 1 - if start > 0: s.delete(0..start - 1) + if start > 0: s.delete(0, start - 1) -func removePrefix*(s: var string, c: char) {.rtl, - extern: "nsuRemovePrefixChar".} = +proc removePrefix*(s: var string, c: char) {. + rtl, extern: "nsuRemovePrefixChar".} = ## Removes all occurrences of a single character (in-place) from the start ## of a string. ## ## See also: - ## * `removeSuffix func<#removeSuffix,string,char>`_ - ## * `startsWith func<#startsWith,string,char>`_ + ## * `removeSuffix proc<#removeSuffix,string,char>`_ + ## * `startsWith proc<#startsWith,string,char>`_ runnableExamples: var ident = "pControl" ident.removePrefix('p') doAssert ident == "Control" removePrefix(s, chars = {c}) -func removePrefix*(s: var string, prefix: string) {.rtl, - extern: "nsuRemovePrefixString".} = +proc removePrefix*(s: var string, prefix: string) {. + rtl, extern: "nsuRemovePrefixString".} = ## Remove the first matching prefix (in-place) from a string. ## ## See also: - ## * `removeSuffix func<#removeSuffix,string,string>`_ - ## * `startsWith func<#startsWith,string,string>`_ + ## * `removeSuffix proc<#removeSuffix,string,string>`_ + ## * `startsWith proc<#startsWith,string,string>`_ runnableExamples: var answers = "yesyes" answers.removePrefix("yes") doAssert answers == "yes" - if s.startsWith(prefix) and prefix.len > 0: - s.delete(0..prefix.len - 1) + if s.startsWith(prefix): + s.delete(0, prefix.len - 1) -func removeSuffix*(s: var string, chars: set[char] = Newlines) {.rtl, - extern: "nsuRemoveSuffixCharSet".} = +proc removeSuffix*(s: var string, chars: set[char] = Newlines) {. + rtl, extern: "nsuRemoveSuffixCharSet".} = ## Removes all characters from `chars` from the end of the string `s` ## (in-place). ## ## See also: - ## * `removePrefix func<#removePrefix,string,set[char]>`_ + ## * `removePrefix proc<#removePrefix,string,set[char]>`_ runnableExamples: var userInput = "Hello World!*~\r\n" userInput.removeSuffix @@ -1713,14 +1661,14 @@ func removeSuffix*(s: var string, chars: set[char] = Newlines) {.rtl, while last > -1 and s[last] in chars: last -= 1 s.setLen(last + 1) -func removeSuffix*(s: var string, c: char) {.rtl, - extern: "nsuRemoveSuffixChar".} = +proc removeSuffix*(s: var string, c: char) {. + rtl, extern: "nsuRemoveSuffixChar".} = ## Removes all occurrences of a single character (in-place) from the end ## of a string. ## ## See also: - ## * `removePrefix func<#removePrefix,string,char>`_ - ## * `endsWith func<#endsWith,string,char>`_ + ## * `removePrefix proc<#removePrefix,string,char>`_ + ## * `endsWith proc<#endsWith,string,char>`_ runnableExamples: var table = "users" table.removeSuffix('s') @@ -1732,13 +1680,13 @@ func removeSuffix*(s: var string, c: char) {.rtl, removeSuffix(s, chars = {c}) -func removeSuffix*(s: var string, suffix: string) {.rtl, - extern: "nsuRemoveSuffixString".} = +proc removeSuffix*(s: var string, suffix: string) {. + rtl, extern: "nsuRemoveSuffixString".} = ## Remove the first matching suffix (in-place) from a string. ## ## See also: - ## * `removePrefix func<#removePrefix,string,string>`_ - ## * `endsWith func<#endsWith,string,string>`_ + ## * `removePrefix proc<#removePrefix,string,string>`_ + ## * `endsWith proc<#endsWith,string,string>`_ runnableExamples: var answers = "yeses" answers.removeSuffix("es") @@ -1749,7 +1697,8 @@ func removeSuffix*(s: var string, suffix: string) {.rtl, s.setLen(newLen) -func addSep*(dest: var string, sep = ", ", startLen: Natural = 0) {.inline.} = +proc addSep*(dest: var string, sep = ", ", startLen: Natural = 0) + {.noSideEffect, inline.} = ## Adds a separator to `dest` only if its length is bigger than `startLen`. ## ## A shorthand for: @@ -1771,7 +1720,7 @@ func addSep*(dest: var string, sep = ", ", startLen: Natural = 0) {.inline.} = if dest.len > startLen: add(dest, sep) -func allCharsInSet*(s: string, theSet: set[char]): bool = +proc allCharsInSet*(s: string, theSet: set[char]): bool = ## Returns true if every character of `s` is in the set `theSet`. runnableExamples: doAssert allCharsInSet("aeea", {'a', 'e'}) == true @@ -1781,9 +1730,9 @@ func allCharsInSet*(s: string, theSet: set[char]): bool = if c notin theSet: return false return true -func abbrev*(s: string, possibilities: openArray[string]): int = - ## Returns the index of the first item in `possibilities` which starts - ## with `s`, if not ambiguous. +proc abbrev*(s: string, possibilities: openArray[string]): int = + ## Returns the index of the first item in ``possibilities`` which starts + ## with ``s``, if not ambiguous. ## ## Returns -1 if no item has been found and -2 if multiple items match. runnableExamples: @@ -1803,8 +1752,8 @@ func abbrev*(s: string, possibilities: openArray[string]): int = # --------------------------------------------------------------------------- -func join*(a: openArray[string], sep: string = ""): string {.rtl, - extern: "nsuJoinSep".} = +proc join*(a: openArray[string], sep: string = ""): string {. + noSideEffect, rtl, extern: "nsuJoinSep".} = ## Concatenates all strings in the container `a`, separating them with `sep`. runnableExamples: doAssert join(["A", "B", "Conclusion"], " -> ") == "A -> B -> Conclusion" @@ -1820,7 +1769,8 @@ func join*(a: openArray[string], sep: string = ""): string {.rtl, else: result = "" -func join*[T: not string](a: openArray[T], sep: string = ""): string = +proc join*[T: not string](a: openArray[T], sep: string = ""): string {. + noSideEffect, rtl.} = ## Converts all elements in the container `a` to strings using `$`, ## and concatenates them with `sep`. runnableExamples: @@ -1833,44 +1783,36 @@ func join*[T: not string](a: openArray[T], sep: string = ""): string = add(result, $x) type - SkipTable* = array[char, int] ## Character table for efficient substring search. + SkipTable* = array[char, int] -func initSkipTable*(a: var SkipTable, sub: string) {.rtl, - extern: "nsuInitSkipTable".} = - ## Initializes table `a` for efficient search of substring `sub`. - ## - ## See also: - ## * `initSkipTable func<#initSkipTable,string>`_ - ## * `find func<#find,SkipTable,string,string,Natural,int>`_ - # TODO: this should be the `default()` initializer for the type. +proc initSkipTable*(a: var SkipTable, sub: string) + {.noSideEffect, rtl, extern: "nsuInitSkipTable".} = + ## Preprocess table `a` for `sub`. let m = len(sub) - fill(a, m) + var i = 0 + while i <= 0xff-7: + a[chr(i + 0)] = m + a[chr(i + 1)] = m + a[chr(i + 2)] = m + a[chr(i + 3)] = m + a[chr(i + 4)] = m + a[chr(i + 5)] = m + a[chr(i + 6)] = m + a[chr(i + 7)] = m + i += 8 for i in 0 ..< m - 1: a[sub[i]] = m - 1 - i -func initSkipTable*(sub: string): SkipTable {.noinit, rtl, - extern: "nsuInitNewSkipTable".} = - ## Returns a new table initialized for `sub`. - ## - ## See also: - ## * `initSkipTable func<#initSkipTable,SkipTable,string>`_ - ## * `find func<#find,SkipTable,string,string,Natural,int>`_ - initSkipTable(result, sub) - -func find*(a: SkipTable, s, sub: string, start: Natural = 0, last = -1): int {. - rtl, extern: "nsuFindStrA".} = - ## Searches for `sub` in `s` inside range `start..last` using preprocessed +proc find*(a: SkipTable, s, sub: string, start: Natural = 0, last = 0): int + {.noSideEffect, rtl, extern: "nsuFindStrA".} = + ## Searches for `sub` in `s` inside range `start`..`last` using preprocessed ## table `a`. If `last` is unspecified, it defaults to `s.high` (the last ## element). ## ## Searching is case-sensitive. If `sub` is not in `s`, -1 is returned. - ## - ## See also: - ## * `initSkipTable func<#initSkipTable,string>`_ - ## * `initSkipTable func<#initSkipTable,SkipTable,string>`_ let - last = if last < 0: s.high else: last + last = if last == 0: s.high else: last subLast = sub.len - 1 if subLast == -1: @@ -1880,7 +1822,6 @@ func find*(a: SkipTable, s, sub: string, start: Natural = 0, last = -1): int {. # This is an implementation of the Boyer-Moore Horspool algorithms # https://en.wikipedia.org/wiki/Boyer%E2%80%93Moore%E2%80%93Horspool_algorithm - result = -1 var skip = start while last - skip >= subLast: @@ -1890,162 +1831,130 @@ func find*(a: SkipTable, s, sub: string, start: Natural = 0, last = -1): int {. return skip dec i inc skip, a[s[skip + subLast]] + return -1 when not (defined(js) or defined(nimdoc) or defined(nimscript)): - func c_memchr(cstr: pointer, c: char, n: csize_t): pointer {. + proc c_memchr(cstr: pointer, c: char, n: csize_t): pointer {. importc: "memchr", header: "".} const hasCStringBuiltin = true else: const hasCStringBuiltin = false -func find*(s: string, sub: char, start: Natural = 0, last = -1): int {.rtl, - extern: "nsuFindChar".} = - ## Searches for `sub` in `s` inside range `start..last` (both ends included). - ## If `last` is unspecified or negative, it defaults to `s.high` (the last element). +proc find*(s: string, sub: char, start: Natural = 0, last = 0): int {.noSideEffect, + rtl, extern: "nsuFindChar".} = + ## Searches for `sub` in `s` inside range ``start..last`` (both ends included). + ## If `last` is unspecified, it defaults to `s.high` (the last element). ## ## Searching is case-sensitive. If `sub` is not in `s`, -1 is returned. - ## Otherwise the index returned is relative to `s[0]`, not `start`. - ## Subtract `start` from the result for a `start`-origin index. + ## Otherwise the index returned is relative to ``s[0]``, not ``start``. + ## Use `s[start..last].rfind` for a ``start``-origin index. ## ## See also: - ## * `rfind func<#rfind,string,char,Natural,int>`_ - ## * `replace func<#replace,string,char,char>`_ - result = -1 - let last = if last < 0: s.high else: last - - template findImpl = - for i in int(start)..last: - if s[i] == sub: - return i - + ## * `rfind proc<#rfind,string,char,Natural,int>`_ + ## * `replace proc<#replace,string,char,char>`_ + let last = if last == 0: s.high else: last when nimvm: - findImpl() + for i in int(start)..last: + if sub == s[i]: return i else: when hasCStringBuiltin: - let length = last-start+1 - if length > 0: - let found = c_memchr(s[start].unsafeAddr, sub, cast[csize_t](length)) + let L = last-start+1 + if L > 0: + let found = c_memchr(s[start].unsafeAddr, sub, cast[csize_t](L)) if not found.isNil: - return cast[int](found) -% cast[int](s.cstring) + return cast[ByteAddress](found) -% cast[ByteAddress](s.cstring) else: - findImpl() + for i in int(start)..last: + if sub == s[i]: return i + return -1 -func find*(s: string, chars: set[char], start: Natural = 0, last = -1): int {. - rtl, extern: "nsuFindCharSet".} = - ## Searches for `chars` in `s` inside range `start..last` (both ends included). - ## If `last` is unspecified or negative, it defaults to `s.high` (the last element). +proc find*(s: string, chars: set[char], start: Natural = 0, last = 0): int {.noSideEffect, + rtl, extern: "nsuFindCharSet".} = + ## Searches for `chars` in `s` inside range ``start..last`` (both ends included). + ## If `last` is unspecified, it defaults to `s.high` (the last element). ## ## If `s` contains none of the characters in `chars`, -1 is returned. - ## Otherwise the index returned is relative to `s[0]`, not `start`. - ## Subtract `start` from the result for a `start`-origin index. + ## Otherwise the index returned is relative to ``s[0]``, not ``start``. + ## Use `s[start..last].find` for a ``start``-origin index. ## ## See also: - ## * `rfind func<#rfind,string,set[char],Natural,int>`_ - ## * `multiReplace func<#multiReplace,string,varargs[]>`_ - result = -1 - let last = if last < 0: s.high else: last + ## * `rfind proc<#rfind,string,set[char],Natural,int>`_ + ## * `multiReplace proc<#multiReplace,string,varargs[]>`_ + let last = if last == 0: s.high else: last for i in int(start)..last: - if s[i] in chars: - return i + if s[i] in chars: return i + return -1 -when defined(linux): - proc memmem(haystack: pointer, haystacklen: csize_t, - needle: pointer, needlelen: csize_t): pointer {.importc, header: """#define _GNU_SOURCE -#include """.} -elif defined(bsd) or (defined(macosx) and not defined(ios)): - proc memmem(haystack: pointer, haystacklen: csize_t, - needle: pointer, needlelen: csize_t): pointer {.importc, header: "#include ".} - -func find*(s, sub: string, start: Natural = 0, last = -1): int {.rtl, - extern: "nsuFindStr".} = - ## Searches for `sub` in `s` inside range `start..last` (both ends included). - ## If `last` is unspecified or negative, it defaults to `s.high` (the last element). +proc find*(s, sub: string, start: Natural = 0, last = 0): int {.noSideEffect, + rtl, extern: "nsuFindStr".} = + ## Searches for `sub` in `s` inside range ``start..last`` (both ends included). + ## If `last` is unspecified, it defaults to `s.high` (the last element). ## ## Searching is case-sensitive. If `sub` is not in `s`, -1 is returned. - ## Otherwise the index returned is relative to `s[0]`, not `start`. - ## Subtract `start` from the result for a `start`-origin index. + ## Otherwise the index returned is relative to ``s[0]``, not ``start``. + ## Use `s[start..last].find` for a ``start``-origin index. ## ## See also: - ## * `rfind func<#rfind,string,string,Natural,int>`_ - ## * `replace func<#replace,string,string,string>`_ - if sub.len > s.len - start: return -1 + ## * `rfind proc<#rfind,string,string,Natural,int>`_ + ## * `replace proc<#replace,string,string,string>`_ + if sub.len > s.len: return -1 if sub.len == 1: return find(s, sub[0], start, last) + var a {.noinit.}: SkipTable + initSkipTable(a, sub) + result = find(a, s, sub, start, last) - template useSkipTable = - result = find(initSkipTable(sub), s, sub, start, last) - - when nimvm: - useSkipTable() - else: - when declared(memmem): - let subLen = sub.len - if last < 0 and start < s.len and subLen != 0: - let found = memmem(s[start].unsafeAddr, csize_t(s.len - start), sub.cstring, csize_t(subLen)) - result = if not found.isNil: - cast[int](found) -% cast[int](s.cstring) - else: - -1 - else: - useSkipTable() - else: - useSkipTable() - -func rfind*(s: string, sub: char, start: Natural = 0, last = -1): int {.rtl, - extern: "nsuRFindChar".} = - ## Searches for `sub` in `s` inside range `start..last` (both ends included) +proc rfind*(s: string, sub: char, start: Natural = 0, last = -1): int {.noSideEffect, + rtl, extern: "nsuRFindChar".} = + ## Searches for `sub` in `s` inside range ``start..last`` (both ends included) ## in reverse -- starting at high indexes and moving lower to the first - ## character or `start`. If `last` is unspecified, it defaults to `s.high` + ## character or ``start``. If `last` is unspecified, it defaults to `s.high` ## (the last element). ## ## Searching is case-sensitive. If `sub` is not in `s`, -1 is returned. - ## Otherwise the index returned is relative to `s[0]`, not `start`. - ## Subtract `start` from the result for a `start`-origin index. + ## Otherwise the index returned is relative to ``s[0]``, not ``start``. + ## Use `s[start..last].find` for a ``start``-origin index. ## ## See also: - ## * `find func<#find,string,char,Natural,int>`_ + ## * `find proc<#find,string,char,Natural,int>`_ let last = if last == -1: s.high else: last for i in countdown(last, start): if sub == s[i]: return i return -1 -func rfind*(s: string, chars: set[char], start: Natural = 0, last = -1): int {. - rtl, extern: "nsuRFindCharSet".} = - ## Searches for `chars` in `s` inside range `start..last` (both ends +proc rfind*(s: string, chars: set[char], start: Natural = 0, last = -1): int {.noSideEffect, + rtl, extern: "nsuRFindCharSet".} = + ## Searches for `chars` in `s` inside range ``start..last`` (both ends ## included) in reverse -- starting at high indexes and moving lower to the - ## first character or `start`. If `last` is unspecified, it defaults to + ## first character or ``start``. If `last` is unspecified, it defaults to ## `s.high` (the last element). ## ## If `s` contains none of the characters in `chars`, -1 is returned. - ## Otherwise the index returned is relative to `s[0]`, not `start`. - ## Subtract `start` from the result for a `start`-origin index. + ## Otherwise the index returned is relative to ``s[0]``, not ``start``. + ## Use `s[start..last].rfind` for a ``start``-origin index. ## ## See also: - ## * `find func<#find,string,set[char],Natural,int>`_ + ## * `find proc<#find,string,set[char],Natural,int>`_ let last = if last == -1: s.high else: last for i in countdown(last, start): if s[i] in chars: return i return -1 -func rfind*(s, sub: string, start: Natural = 0, last = -1): int {.rtl, - extern: "nsuRFindStr".} = - ## Searches for `sub` in `s` inside range `start..last` (both ends included) +proc rfind*(s, sub: string, start: Natural = 0, last = -1): int {.noSideEffect, + rtl, extern: "nsuRFindStr".} = + ## Searches for `sub` in `s` inside range ``start..last`` (both ends included) ## included) in reverse -- starting at high indexes and moving lower to the - ## first character or `start`. If `last` is unspecified, it defaults to + ## first character or ``start``. If `last` is unspecified, it defaults to ## `s.high` (the last element). ## ## Searching is case-sensitive. If `sub` is not in `s`, -1 is returned. - ## Otherwise the index returned is relative to `s[0]`, not `start`. - ## Subtract `start` from the result for a `start`-origin index. + ## Otherwise the index returned is relative to ``s[0]``, not ``start``. + ## Use `s[start..last].rfind` for a ``start``-origin index. ## ## See also: - ## * `find func<#find,string,string,Natural,int>`_ + ## * `find proc<#find,string,string,Natural,int>`_ if sub.len == 0: - let rightIndex: Natural = if last < 0: s.len else: last - return max(start, rightIndex) - if sub.len > s.len - start: return -1 let last = if last == -1: s.high else: last - result = 0 for i in countdown(last - sub.len + 1, start): for j in 0..sub.len-1: result = i @@ -2056,36 +1965,34 @@ func rfind*(s, sub: string, start: Natural = 0, last = -1): int {.rtl, return -1 -func count*(s: string, sub: char): int {.rtl, extern: "nsuCountChar".} = - ## Counts the occurrences of the character `sub` in the string `s`. +proc count*(s: string, sub: char): int {.noSideEffect, + rtl, extern: "nsuCountChar".} = + ## Count the occurrences of the character `sub` in the string `s`. ## ## See also: - ## * `countLines func<#countLines,string>`_ - result = 0 + ## * `countLines proc<#countLines,string>`_ for c in s: if c == sub: inc result -func count*(s: string, subs: set[char]): int {.rtl, - extern: "nsuCountCharSet".} = - ## Counts the occurrences of the group of character `subs` in the string `s`. +proc count*(s: string, subs: set[char]): int {.noSideEffect, + rtl, extern: "nsuCountCharSet".} = + ## Count the occurrences of the group of character `subs` in the string `s`. ## ## See also: - ## * `countLines func<#countLines,string>`_ + ## * `countLines proc<#countLines,string>`_ doAssert card(subs) > 0 - result = 0 for c in s: if c in subs: inc result -func count*(s: string, sub: string, overlapping: bool = false): int {.rtl, - extern: "nsuCountString".} = - ## Counts the occurrences of a substring `sub` in the string `s`. +proc count*(s: string, sub: string, overlapping: bool = false): int {. + noSideEffect, rtl, extern: "nsuCountString".} = + ## Count the occurrences of a substring `sub` in the string `s`. ## Overlapping occurrences of `sub` only count when `overlapping` ## is set to true (default: false). ## ## See also: - ## * `countLines func<#countLines,string>`_ + ## * `countLines proc<#countLines,string>`_ doAssert sub.len > 0 - result = 0 var i = 0 while true: i = s.find(sub, i) @@ -2094,11 +2001,12 @@ func count*(s: string, sub: string, overlapping: bool = false): int {.rtl, else: i += sub.len inc result -func countLines*(s: string): int {.rtl, extern: "nsuCountLines".} = +proc countLines*(s: string): int {.noSideEffect, + rtl, extern: "nsuCountLines".} = ## Returns the number of lines in the string `s`. ## - ## This is the same as `len(splitLines(s))`, but much more efficient - ## because it doesn't modify the string creating temporary objects. Every + ## This is the same as ``len(splitLines(s))``, but much more efficient + ## because it doesn't modify the string creating temporal objects. Every ## `character literal `_ ## newline combination (CR, LF, CR-LF) is supported. ## @@ -2106,7 +2014,7 @@ func countLines*(s: string): int {.rtl, extern: "nsuCountLines".} = ## A line can be an empty string. ## ## See also: - ## * `splitLines func<#splitLines,string>`_ + ## * `splitLines proc<#splitLines,string>`_ runnableExamples: doAssert countLines("First line\l and second line.") == 2 result = 1 @@ -2121,30 +2029,30 @@ func countLines*(s: string): int {.rtl, extern: "nsuCountLines".} = inc i -func contains*(s, sub: string): bool = - ## Same as `find(s, sub) >= 0`. +proc contains*(s, sub: string): bool {.noSideEffect.} = + ## Same as ``find(s, sub) >= 0``. ## ## See also: - ## * `find func<#find,string,string,Natural,int>`_ + ## * `find proc<#find,string,string,Natural,int>`_ return find(s, sub) >= 0 -func contains*(s: string, chars: set[char]): bool = - ## Same as `find(s, chars) >= 0`. +proc contains*(s: string, chars: set[char]): bool {.noSideEffect.} = + ## Same as ``find(s, chars) >= 0``. ## ## See also: - ## * `find func<#find,string,set[char],Natural,int>`_ + ## * `find proc<#find,string,set[char],Natural,int>`_ return find(s, chars) >= 0 -func replace*(s, sub: string, by = ""): string {.rtl, - extern: "nsuReplaceStr".} = - ## Replaces every occurrence of the string `sub` in `s` with the string `by`. +proc replace*(s, sub: string, by = ""): string {.noSideEffect, + rtl, extern: "nsuReplaceStr".} = + ## Replaces `sub` in `s` by the string `by`. ## ## See also: - ## * `find func<#find,string,string,Natural,int>`_ - ## * `replace func<#replace,string,char,char>`_ for replacing + ## * `find proc<#find,string,string,Natural,int>`_ + ## * `replace proc<#replace,string,char,char>`_ for replacing ## single characters - ## * `replaceWord func<#replaceWord,string,string,string>`_ - ## * `multiReplace func<#multiReplace,string,varargs[]>`_ + ## * `replaceWord proc<#replaceWord,string,string,string>`_ + ## * `multiReplace proc<#multiReplace,string,varargs[]>`_ result = "" let subLen = sub.len if subLen == 0: @@ -2164,7 +2072,8 @@ func replace*(s, sub: string, by = ""): string {.rtl, # copy the rest: add result, substr(s, i) else: - var a = initSkipTable(sub) + var a {.noinit.}: SkipTable + initSkipTable(a, sub) let last = s.high var i = 0 while true: @@ -2176,18 +2085,17 @@ func replace*(s, sub: string, by = ""): string {.rtl, # copy the rest: add result, substr(s, i) -func replace*(s: string, sub, by: char): string {.rtl, - extern: "nsuReplaceChar".} = - ## Replaces every occurrence of the character `sub` in `s` with the character - ## `by`. +proc replace*(s: string, sub, by: char): string {.noSideEffect, + rtl, extern: "nsuReplaceChar".} = + ## Replaces `sub` in `s` by the character `by`. ## ## Optimized version of `replace <#replace,string,string,string>`_ for ## characters. ## ## See also: - ## * `find func<#find,string,char,Natural,int>`_ - ## * `replaceWord func<#replaceWord,string,string,string>`_ - ## * `multiReplace func<#multiReplace,string,varargs[]>`_ + ## * `find proc<#find,string,char,Natural,int>`_ + ## * `replaceWord proc<#replaceWord,string,string,string>`_ + ## * `multiReplace proc<#multiReplace,string,varargs[]>`_ result = newString(s.len) var i = 0 while i < s.len: @@ -2195,17 +2103,18 @@ func replace*(s: string, sub, by: char): string {.rtl, else: result[i] = s[i] inc(i) -func replaceWord*(s, sub: string, by = ""): string {.rtl, - extern: "nsuReplaceWord".} = - ## Replaces every occurrence of the string `sub` in `s` with the string `by`. +proc replaceWord*(s, sub: string, by = ""): string {.noSideEffect, + rtl, extern: "nsuReplaceWord".} = + ## Replaces `sub` in `s` by the string `by`. ## ## Each occurrence of `sub` has to be surrounded by word boundaries - ## (comparable to `\b` in regular expressions), otherwise it is not + ## (comparable to ``\b`` in regular expressions), otherwise it is not ## replaced. if sub.len == 0: return s const wordChars = {'a'..'z', 'A'..'Z', '0'..'9', '_', '\128'..'\255'} + var a {.noinit.}: SkipTable result = "" - var a = initSkipTable(sub) + initSkipTable(a, sub) var i = 0 let last = s.high let sublen = sub.len @@ -2225,7 +2134,8 @@ func replaceWord*(s, sub: string, by = ""): string {.rtl, # copy the rest: add result, substr(s, i) -func multiReplace*(s: string, replacements: varargs[(string, string)]): string = +proc multiReplace*(s: string, replacements: varargs[(string, string)]): + string {.noSideEffect.} = ## Same as replace, but specialized for doing multiple replacements in a single ## pass through the input string. ## @@ -2260,8 +2170,8 @@ func multiReplace*(s: string, replacements: varargs[(string, string)]): string = -func insertSep*(s: string, sep = '_', digits = 3): string {.rtl, - extern: "nsuInsertSep".} = +proc insertSep*(s: string, sep = '_', digits = 3): string {.noSideEffect, + rtl, extern: "nsuInsertSep".} = ## Inserts the separator `sep` after `digits` characters (default: 3) ## from right to left. ## @@ -2269,50 +2179,31 @@ func insertSep*(s: string, sep = '_', digits = 3): string {.rtl, ## if `s` contains a number. runnableExamples: doAssert insertSep("1000000") == "1_000_000" - result = newStringOfCap(s.len) - let hasPrefix = isDigit(s[s.low]) == false - var idx: int - if hasPrefix: - result.add s[s.low] - for i in (s.low + 1)..s.high: - idx = i - if not isDigit(s[i]): - result.add s[i] - else: - break - let partsLen = s.len - idx - var L = (partsLen-1) div digits + partsLen - result.setLen(L + idx) + + var L = (s.len-1) div digits + s.len + result = newString(L) var j = 0 dec(L) - for i in countdown(partsLen-1, 0): + for i in countdown(len(s)-1, 0): if j == digits: - result[L + idx] = sep + result[L] = sep dec(L) j = 0 - result[L + idx] = s[i + idx] + result[L] = s[i] inc(j) dec(L) -func escape*(s: string, prefix = "\"", suffix = "\""): string {.rtl, - extern: "nsuEscape".} = - ## Escapes a string `s`. - ## - ## .. note:: The escaping scheme is different from - ## `system.addEscapedChar`. - ## - ## * replaces `'\0'..'\31'` and `'\127'..'\255'` by `\xHH` where `HH` is its hexadecimal value - ## * replaces ``\`` by `\\` - ## * replaces `'` by `\'` - ## * replaces `"` by `\"` +proc escape*(s: string, prefix = "\"", suffix = "\""): string {.noSideEffect, + rtl, extern: "nsuEscape".} = + ## Escapes a string `s`. See `system.addEscapedChar + ## `_ for the escaping scheme. ## ## The resulting string is prefixed with `prefix` and suffixed with `suffix`. ## Both may be empty strings. ## ## See also: - ## * `addEscapedChar proc`_ - ## * `unescape func<#unescape,string,string,string>`_ for the opposite - ## operation + ## * `unescape proc<#unescape,string,string,string>`_ for the opposite + ## operation result = newStringOfCap(s.len + s.len shr 2) result.add(prefix) for c in items(s): @@ -2326,14 +2217,14 @@ func escape*(s: string, prefix = "\"", suffix = "\""): string {.rtl, else: add(result, c) add(result, suffix) -func unescape*(s: string, prefix = "\"", suffix = "\""): string {.rtl, - extern: "nsuUnescape".} = +proc unescape*(s: string, prefix = "\"", suffix = "\""): string {.noSideEffect, + rtl, extern: "nsuUnescape".} = ## Unescapes a string `s`. ## - ## This complements `escape func<#escape,string,string,string>`_ + ## This complements `escape proc<#escape,string,string,string>`_ ## as it performs the opposite operations. ## - ## If `s` does not begin with `prefix` and end with `suffix` a + ## If `s` does not begin with ``prefix`` and end with ``suffix`` a ## ValueError exception will be raised. result = newStringOfCap(s.len) var i = prefix.len @@ -2349,7 +2240,7 @@ func unescape*(s: string, prefix = "\"", suffix = "\""): string {.rtl, case s[i+1]: of 'x': inc i, 2 - var c = 0 + var c: int i += parseutils.parseHex(s, c, i, maxLen = 2) result.add(chr(c)) dec i, 2 @@ -2369,7 +2260,8 @@ func unescape*(s: string, prefix = "\"", suffix = "\""): string {.rtl, raise newException(ValueError, "String does not end in: " & suffix) -func validIdentifier*(s: string): bool {.rtl, extern: "nsuValidIdentifier".} = +proc validIdentifier*(s: string): bool {.noSideEffect, + rtl, extern: "nsuValidIdentifier".} = ## Returns true if `s` is a valid identifier. ## ## A valid identifier starts with a character of the set `IdentStartChars` @@ -2385,105 +2277,113 @@ func validIdentifier*(s: string): bool {.rtl, extern: "nsuValidIdentifier".} = # floating point formatting: when not defined(js): - func c_sprintf(buf, frmt: cstring): cint {.header: "", - importc: "sprintf", varargs.} + proc c_sprintf(buf, frmt: cstring): cint {.header: "", + importc: "sprintf", varargs, noSideEffect.} type FloatFormatMode* = enum - ## The different modes of floating point formatting. + ## the different modes of floating point formatting ffDefault, ## use the shorter floating point notation ffDecimal, ## use decimal floating point notation - ffScientific ## use scientific notation (using `e` character) + ffScientific ## use scientific notation (using ``e`` character) -func formatBiggestFloat*(f: BiggestFloat, format: FloatFormatMode = ffDefault, +proc formatBiggestFloat*(f: BiggestFloat, format: FloatFormatMode = ffDefault, precision: range[-1..32] = 16; - decimalSep = '.'): string {.rtl, extern: "nsu$1".} = + decimalSep = '.'): string {. + noSideEffect, rtl, extern: "nsu$1".} = ## Converts a floating point value `f` to a string. ## - ## If `format == ffDecimal` then precision is the number of digits to + ## If ``format == ffDecimal`` then precision is the number of digits to ## be printed after the decimal point. - ## If `format == ffScientific` then precision is the maximum number + ## If ``format == ffScientific`` then precision is the maximum number ## of significant digits to be printed. ## `precision`'s default value is the maximum number of meaningful digits - ## after the decimal point for Nim's `biggestFloat` type. + ## after the decimal point for Nim's ``biggestFloat`` type. ## - ## If `precision == -1`, it tries to format it nicely. + ## If ``precision == -1``, it tries to format it nicely. runnableExamples: let x = 123.456 doAssert x.formatBiggestFloat() == "123.4560000000000" doAssert x.formatBiggestFloat(ffDecimal, 4) == "123.4560" doAssert x.formatBiggestFloat(ffScientific, 2) == "1.23e+02" - when nimvm: - discard "implemented in the vmops" + when defined(js): + var precision = precision + if precision == -1: + # use the same default precision as c_sprintf + precision = 6 + var res: cstring + case format + of ffDefault: + {.emit: "`res` = `f`.toString();".} + of ffDecimal: + {.emit: "`res` = `f`.toFixed(`precision`);".} + of ffScientific: + {.emit: "`res` = `f`.toExponential(`precision`);".} + result = $res + if 1.0 / f == -Inf: + # JavaScript removes the "-" from negative Zero, add it back here + result = "-" & $res + for i in 0 ..< result.len: + # Depending on the locale either dot or comma is produced, + # but nothing else is possible: + if result[i] in {'.', ','}: result[i] = decimalSep else: - when defined(js): - var precision = precision - if precision == -1: - # use the same default precision as c_sprintf - precision = 6 - var res: cstring - case format - of ffDefault: - {.emit: "`res` = `f`.toString();".} - of ffDecimal: - {.emit: "`res` = `f`.toFixed(`precision`);".} - of ffScientific: - {.emit: "`res` = `f`.toExponential(`precision`);".} - result = $res - if 1.0 / f == -Inf: - # JavaScript removes the "-" from negative Zero, add it back here - result = "-" & $res - for i in 0 ..< result.len: - # Depending on the locale either dot or comma is produced, - # but nothing else is possible: - if result[i] in {'.', ','}: result[i] = decimalSep - else: - const floatFormatToChar: array[FloatFormatMode, char] = ['g', 'f', 'e'] - var - frmtstr {.noinit.}: array[0..5, char] - buf {.noinit.}: array[0..2500, char] - L: cint - frmtstr[0] = '%' - if precision >= 0: - frmtstr[1] = '#' - frmtstr[2] = '.' - frmtstr[3] = '*' - frmtstr[4] = floatFormatToChar[format] - frmtstr[5] = '\0' - L = c_sprintf(cast[cstring](addr buf), cast[cstring](addr frmtstr), precision, f) + const floatFormatToChar: array[FloatFormatMode, char] = ['g', 'f', 'e'] + var + frmtstr {.noinit.}: array[0..5, char] + buf {.noinit.}: array[0..2500, char] + L: cint + frmtstr[0] = '%' + if precision >= 0: + frmtstr[1] = '#' + frmtstr[2] = '.' + frmtstr[3] = '*' + frmtstr[4] = floatFormatToChar[format] + frmtstr[5] = '\0' + when defined(nimNoArrayToCstringConversion): + L = c_sprintf(addr buf, addr frmtstr, precision, f) else: - frmtstr[1] = floatFormatToChar[format] - frmtstr[2] = '\0' - L = c_sprintf(cast[cstring](addr buf), cast[cstring](addr frmtstr), f) - result = newString(L) - for i in 0 ..< L: - # Depending on the locale either dot or comma is produced, - # but nothing else is possible: - if buf[i] in {'.', ','}: result[i] = decimalSep - else: result[i] = buf[i] - when defined(windows): - # VS pre 2015 violates the C standard: "The exponent always contains at - # least two digits, and only as many more digits as necessary to - # represent the exponent." [C11 §7.21.6.1] - # The following post-processing fixes this behavior. - if result.len > 4 and result[^4] == '+' and result[^3] == '0': - result[^3] = result[^2] - result[^2] = result[^1] - result.setLen(result.len - 1) + L = c_sprintf(buf, frmtstr, precision, f) + else: + frmtstr[1] = floatFormatToChar[format] + frmtstr[2] = '\0' + when defined(nimNoArrayToCstringConversion): + L = c_sprintf(addr buf, addr frmtstr, f) + else: + L = c_sprintf(buf, frmtstr, f) + result = newString(L) + for i in 0 ..< L: + # Depending on the locale either dot or comma is produced, + # but nothing else is possible: + if buf[i] in {'.', ','}: result[i] = decimalSep + else: result[i] = buf[i] + since (1, 1): + # remove trailing dot, compatible with Python's formatter and JS backend + if result[^1] == decimalSep: + result.setLen(len(result)-1) + when defined(windows): + # VS pre 2015 violates the C standard: "The exponent always contains at + # least two digits, and only as many more digits as necessary to + # represent the exponent." [C11 §7.21.6.1] + # The following post-processing fixes this behavior. + if result.len > 4 and result[^4] == '+' and result[^3] == '0': + result[^3] = result[^2] + result[^2] = result[^1] + result.setLen(result.len - 1) -func formatFloat*(f: float, format: FloatFormatMode = ffDefault, +proc formatFloat*(f: float, format: FloatFormatMode = ffDefault, precision: range[-1..32] = 16; decimalSep = '.'): string {. - rtl, extern: "nsu$1".} = + noSideEffect, rtl, extern: "nsu$1".} = ## Converts a floating point value `f` to a string. ## - ## If `format == ffDecimal` then precision is the number of digits to + ## If ``format == ffDecimal`` then precision is the number of digits to ## be printed after the decimal point. - ## If `format == ffScientific` then precision is the maximum number + ## If ``format == ffScientific`` then precision is the maximum number ## of significant digits to be printed. ## `precision`'s default value is the maximum number of meaningful digits - ## after the decimal point for Nim's `float` type. + ## after the decimal point for Nim's ``float`` type. ## - ## If `precision == -1`, it tries to format it nicely. + ## If ``precision == -1``, it tries to format it nicely. runnableExamples: let x = 123.456 doAssert x.formatFloat() == "123.4560000000000" @@ -2492,9 +2392,9 @@ func formatFloat*(f: float, format: FloatFormatMode = ffDefault, result = formatBiggestFloat(f, format, precision, decimalSep) -func trimZeros*(x: var string; decimalSep = '.') = +proc trimZeros*(x: var string; decimalSep = '.') {.noSideEffect.} = ## Trim trailing zeros from a formatted floating point - ## value `x` (must be declared as `var`). + ## value `x` (must be declared as ``var``). ## ## This modifies `x` itself, it does not return a copy. runnableExamples: @@ -2509,18 +2409,17 @@ func trimZeros*(x: var string; decimalSep = '.') = var pos = last while pos >= 0 and x[pos] == '0': dec(pos) if pos > sPos: inc(pos) - if last >= pos: - x.delete(pos..last) + x.delete(pos, last) type - BinaryPrefixMode* = enum ## The different names for binary prefixes. + BinaryPrefixMode* = enum ## the different names for binary prefixes bpIEC, # use the IEC/ISO standard prefixes such as kibi bpColloquial # use the colloquial kilo, mega etc -func formatSize*(bytes: int64, +proc formatSize*(bytes: int64, decimalSep = '.', prefix = bpIEC, - includeSpace = false): string = + includeSpace = false): string {.noSideEffect.} = ## Rounds and formats `bytes`. ## ## By default, uses the IEC/ISO standard binary prefixes, so 1024 will be @@ -2546,7 +2445,7 @@ func formatSize*(bytes: int64, xb: int64 = bytes fbytes: float lastXb: int64 = bytes - matchedIndex = 0 + matchedIndex: int prefixes: array[9, string] if prefix == bpColloquial: prefixes = collPrefixes @@ -2573,13 +2472,13 @@ func formatSize*(bytes: int64, result &= prefixes[matchedIndex] result &= "B" -func formatEng*(f: BiggestFloat, +proc formatEng*(f: BiggestFloat, precision: range[0..32] = 10, trim: bool = true, siPrefix: bool = false, unit: string = "", decimalSep = '.', - useUnitSpace = false): string = + useUnitSpace = false): string {.noSideEffect.} = ## Converts a floating point value `f` to a string using engineering notation. ## ## Numbers in of the range -1000.0 a.high: invalidFormatString(formatstr) + if num > a.high: invalidFormatString() add s, a[num] inc i, 2 inc num @@ -2750,7 +2649,7 @@ func addf*(s: var string, formatstr: string, a: varargs[string, `$`]) {.rtl, j = j * 10 + ord(formatstr[i]) - ord('0') inc(i) let idx = if not negative: j-1 else: a.len-j - if idx < 0 or idx > a.high: invalidFormatString(formatstr) + if idx < 0 or idx > a.high: invalidFormatString() add s, a[idx] of '{': var j = i+2 @@ -2767,28 +2666,28 @@ func addf*(s: var string, formatstr: string, a: varargs[string, `$`]) {.rtl, inc(j) if isNumber == 1: let idx = if not negative: k-1 else: a.len-k - if idx < 0 or idx > a.high: invalidFormatString(formatstr) + if idx < 0 or idx > a.high: invalidFormatString() add s, a[idx] else: var x = findNormalized(substr(formatstr, i+2, j-1), a) if x >= 0 and x < high(a): add s, a[x+1] - else: invalidFormatString(formatstr) + else: invalidFormatString() i = j+1 of 'a'..'z', 'A'..'Z', '\128'..'\255', '_': var j = i+1 while j < formatstr.len and formatstr[j] in PatternChars: inc(j) var x = findNormalized(substr(formatstr, i+1, j-1), a) if x >= 0 and x < high(a): add s, a[x+1] - else: invalidFormatString(formatstr) + else: invalidFormatString() i = j else: - invalidFormatString(formatstr) + invalidFormatString() else: add s, formatstr[i] inc(i) -func `%`*(formatstr: string, a: openArray[string]): string {.rtl, - extern: "nsuFormatOpenArray".} = +proc `%` *(formatstr: string, a: openArray[string]): string {.noSideEffect, + rtl, extern: "nsuFormatOpenArray".} = ## Interpolates a format string with the values from `a`. ## ## The `substitution`:idx: operator performs string substitutions in @@ -2805,17 +2704,17 @@ func `%`*(formatstr: string, a: openArray[string]): string {.rtl, ## .. code-block:: nim ## "The cat eats fish." ## - ## The substitution variables (the thing after the `$`) are enumerated - ## from 1 to `a.len`. - ## To produce a verbatim `$`, use `$$`. - ## The notation `$#` can be used to refer to the next substitution + ## The substitution variables (the thing after the ``$``) are enumerated + ## from 1 to ``a.len``. + ## To produce a verbatim ``$``, use ``$$``. + ## The notation ``$#`` can be used to refer to the next substitution ## variable: ## ## .. code-block:: nim ## "$# eats $#." % ["The cat", "fish"] ## ## Substitution variables can also be words (that is - ## `[A-Za-z_]+[A-Za-z0-9_]*`) in which case the arguments in `a` with even + ## ``[A-Za-z_]+[A-Za-z0-9_]*``) in which case the arguments in `a` with even ## indices are keys and with odd indices are the corresponding values. ## An example: ## @@ -2835,17 +2734,17 @@ func `%`*(formatstr: string, a: openArray[string]): string {.rtl, result = newStringOfCap(formatstr.len + a.len shl 4) addf(result, formatstr, a) -func `%`*(formatstr, a: string): string {.rtl, - extern: "nsuFormatSingleElem".} = - ## This is the same as `formatstr % [a]` (see - ## `% func<#%25,string,openArray[string]>`_). +proc `%` *(formatstr, a: string): string {.noSideEffect, + rtl, extern: "nsuFormatSingleElem".} = + ## This is the same as ``formatstr % [a]`` (see + ## `% proc<#%25,string,openArray[string]>`_). result = newStringOfCap(formatstr.len + a.len) addf(result, formatstr, [a]) -func format*(formatstr: string, a: varargs[string, `$`]): string {.rtl, - extern: "nsuFormatVarargs".} = - ## This is the same as `formatstr % a` (see - ## `% func<#%25,string,openArray[string]>`_) except that it supports +proc format*(formatstr: string, a: varargs[string, `$`]): string {.noSideEffect, + rtl, extern: "nsuFormatVarargs".} = + ## This is the same as ``formatstr % a`` (see + ## `% proc<#%25,string,openArray[string]>`_) except that it supports ## auto stringification. ## ## See also: @@ -2854,8 +2753,9 @@ func format*(formatstr: string, a: varargs[string, `$`]): string {.rtl, addf(result, formatstr, a) -func strip*(s: string, leading = true, trailing = true, - chars: set[char] = Whitespace): string {.rtl, extern: "nsuStrip".} = +proc strip*(s: string, leading = true, trailing = true, + chars: set[char] = Whitespace): string + {.noSideEffect, rtl, extern: "nsuStrip".} = ## Strips leading or trailing `chars` (default: whitespace characters) ## from `s` and returns the resulting string. ## @@ -2864,8 +2764,7 @@ func strip*(s: string, leading = true, trailing = true, ## If both are false, the string is returned unchanged. ## ## See also: - ## * `strip proc`_ Inplace version. - ## * `stripLineEnd func<#stripLineEnd,string>`_ + ## * `stripLineEnd proc<#stripLineEnd,string>`_ runnableExamples: let a = " vhellov " let b = strip(a) @@ -2887,13 +2786,13 @@ func strip*(s: string, leading = true, trailing = true, if leading: while first <= last and s[first] in chars: inc(first) if trailing: - while last >= first and s[last] in chars: dec(last) + while last >= 0 and s[last] in chars: dec(last) result = substr(s, first, last) -func stripLineEnd*(s: var string) = - ## Strips one of these suffixes from `s` in-place: - ## `\r, \n, \r\n, \f, \v` (at most once instance). - ## For example, can be useful in conjunction with `osproc.execCmdEx`. +proc stripLineEnd*(s: var string) = + ## Returns ``s`` stripped from one of these suffixes: + ## ``\r, \n, \r\n, \f, \v`` (at most once instance). + ## For example, can be useful in conjunction with ``osproc.execCmdEx``. ## aka: `chomp`:idx: runnableExamples: var s = "foo\n\n" @@ -2950,7 +2849,228 @@ iterator tokenize*(s: string, seps: set[char] = Whitespace): tuple[ break i = j -func isEmptyOrWhitespace*(s: string): bool {.rtl, +proc isEmptyOrWhitespace*(s: string): bool {.noSideEffect, procvar, rtl, extern: "nsuIsEmptyOrWhitespace".} = ## Checks if `s` is empty or consists entirely of whitespace characters. result = s.allCharsInSet(Whitespace) + +proc isNilOrWhitespace*(s: string): bool {.noSideEffect, procvar, rtl, + extern: "nsuIsNilOrWhitespace", + deprecated: "use isEmptyOrWhitespace instead".} = + ## Alias for isEmptyOrWhitespace + result = isEmptyOrWhitespace(s) + +when isMainModule: + proc nonStaticTests = + doAssert formatBiggestFloat(1234.567, ffDecimal, -1) == "1234.567000" + doAssert formatBiggestFloat(1234.567, ffDecimal, 0) == "1235" # bugs 8242, 12586 + doAssert formatBiggestFloat(1234.567, ffDecimal, 1) == "1234.6" + doAssert formatBiggestFloat(0.00000000001, ffDecimal, 11) == "0.00000000001" + doAssert formatBiggestFloat(0.00000000001, ffScientific, 1, ',') in + ["1,0e-11", "1,0e-011"] + # bug #6589 + when not defined(js): + doAssert formatFloat(123.456, ffScientific, precision = -1) == "1.234560e+02" + + doAssert "$# $3 $# $#" % ["a", "b", "c"] == "a c b c" + doAssert "${1}12 ${-1}$2" % ["a", "b"] == "a12 bb" + + block: # formatSize tests + when not defined(js): + doAssert formatSize((1'i64 shl 31) + (300'i64 shl 20)) == "2.293GiB" # <=== bug #8231 + doAssert formatSize((2.234*1024*1024).int) == "2.234MiB" + doAssert formatSize(4096) == "4KiB" + doAssert formatSize(4096, prefix = bpColloquial, includeSpace = true) == "4 kB" + doAssert formatSize(4096, includeSpace = true) == "4 KiB" + doAssert formatSize(5_378_934, prefix = bpColloquial, decimalSep = ',') == "5,13MB" + + block: # formatEng tests + doAssert formatEng(0, 2, trim = false) == "0.00" + doAssert formatEng(0, 2) == "0" + doAssert formatEng(53, 2, trim = false) == "53.00" + doAssert formatEng(0.053, 2, trim = false) == "53.00e-3" + doAssert formatEng(0.053, 4, trim = false) == "53.0000e-3" + doAssert formatEng(0.053, 4, trim = true) == "53e-3" + doAssert formatEng(0.053, 0) == "53e-3" + doAssert formatEng(52731234) == "52.731234e6" + doAssert formatEng(-52731234) == "-52.731234e6" + doAssert formatEng(52731234, 1) == "52.7e6" + doAssert formatEng(-52731234, 1) == "-52.7e6" + doAssert formatEng(52731234, 1, decimalSep = ',') == "52,7e6" + doAssert formatEng(-52731234, 1, decimalSep = ',') == "-52,7e6" + + doAssert formatEng(4100, siPrefix = true, unit = "V") == "4.1 kV" + doAssert formatEng(4.1, siPrefix = true, unit = "V", + useUnitSpace = true) == "4.1 V" + doAssert formatEng(4.1, siPrefix = true) == "4.1" # Note lack of space + doAssert formatEng(4100, siPrefix = true) == "4.1 k" + doAssert formatEng(4.1, siPrefix = true, unit = "", + useUnitSpace = true) == "4.1 " # Includes space + doAssert formatEng(4100, siPrefix = true, unit = "") == "4.1 k" + doAssert formatEng(4100) == "4.1e3" + doAssert formatEng(4100, unit = "V", useUnitSpace = true) == "4.1e3 V" + doAssert formatEng(4100, unit = "", useUnitSpace = true) == "4.1e3 " + # Don't use SI prefix as number is too big + doAssert formatEng(3.1e22, siPrefix = true, unit = "a", + useUnitSpace = true) == "31e21 a" + # Don't use SI prefix as number is too small + doAssert formatEng(3.1e-25, siPrefix = true, unit = "A", + useUnitSpace = true) == "310e-27 A" + + proc staticTests = + doAssert align("abc", 4) == " abc" + doAssert align("a", 0) == "a" + doAssert align("1232", 6) == " 1232" + doAssert align("1232", 6, '#') == "##1232" + + doAssert alignLeft("abc", 4) == "abc " + doAssert alignLeft("a", 0) == "a" + doAssert alignLeft("1232", 6) == "1232 " + doAssert alignLeft("1232", 6, '#') == "1232##" + + doAssert "$animal eats $food." % ["animal", "The cat", "food", "fish"] == + "The cat eats fish." + + doAssert "-ld a-ldz -ld".replaceWord("-ld") == " a-ldz " + doAssert "-lda-ldz -ld abc".replaceWord("-ld") == "-lda-ldz abc" + + doAssert "-lda-ldz -ld abc".replaceWord("") == "-lda-ldz -ld abc" + doAssert "oo".replace("", "abc") == "oo" + + type MyEnum = enum enA, enB, enC, enuD, enE + doAssert parseEnum[MyEnum]("enu_D") == enuD + + doAssert parseEnum("invalid enum value", enC) == enC + + doAssert center("foo", 13) == " foo " + doAssert center("foo", 0) == "foo" + doAssert center("foo", 3, fillChar = 'a') == "foo" + doAssert center("foo", 10, fillChar = '\t') == "\t\t\tfoo\t\t\t\t" + + doAssert count("foofoofoo", "foofoo") == 1 + doAssert count("foofoofoo", "foofoo", overlapping = true) == 2 + doAssert count("foofoofoo", 'f') == 3 + doAssert count("foofoofoobar", {'f', 'b'}) == 4 + + doAssert strip(" foofoofoo ") == "foofoofoo" + doAssert strip("sfoofoofoos", chars = {'s'}) == "foofoofoo" + doAssert strip("barfoofoofoobar", chars = {'b', 'a', 'r'}) == "foofoofoo" + doAssert strip("stripme but don't strip this stripme", + chars = {'s', 't', 'r', 'i', 'p', 'm', 'e'}) == + " but don't strip this " + doAssert strip("sfoofoofoos", leading = false, chars = {'s'}) == "sfoofoofoo" + doAssert strip("sfoofoofoos", trailing = false, chars = {'s'}) == "foofoofoos" + + doAssert " foo\n bar".indent(4, "Q") == "QQQQ foo\nQQQQ bar" + + doAssert "abba".multiReplace(("a", "b"), ("b", "a")) == "baab" + doAssert "Hello World.".multiReplace(("ello", "ELLO"), ("World.", + "PEOPLE!")) == "HELLO PEOPLE!" + doAssert "aaaa".multiReplace(("a", "aa"), ("aa", "bb")) == "aaaaaaaa" + + doAssert isAlphaAscii('r') + doAssert isAlphaAscii('A') + doAssert(not isAlphaAscii('$')) + + doAssert isAlphaNumeric('3') + doAssert isAlphaNumeric('R') + doAssert(not isAlphaNumeric('!')) + + doAssert isDigit('3') + doAssert(not isDigit('a')) + doAssert(not isDigit('%')) + + doAssert isSpaceAscii('\t') + doAssert isSpaceAscii('\l') + doAssert(not isSpaceAscii('A')) + + doAssert(isEmptyOrWhitespace("")) + doAssert(isEmptyOrWhitespace(" ")) + doAssert(isEmptyOrWhitespace("\t\l \v\r\f")) + doAssert(not isEmptyOrWhitespace("ABc \td")) + + doAssert isLowerAscii('a') + doAssert isLowerAscii('z') + doAssert(not isLowerAscii('A')) + doAssert(not isLowerAscii('5')) + doAssert(not isLowerAscii('&')) + doAssert(not isLowerAscii(' ')) + + doAssert isUpperAscii('A') + doAssert(not isUpperAscii('b')) + doAssert(not isUpperAscii('5')) + doAssert(not isUpperAscii('%')) + + doAssert rsplit("foo bar", seps = Whitespace) == @["foo", "bar"] + doAssert rsplit(" foo bar", seps = Whitespace, maxsplit = 1) == @[" foo", "bar"] + doAssert rsplit(" foo bar ", seps = Whitespace, maxsplit = 1) == @[ + " foo bar", ""] + doAssert rsplit(":foo:bar", sep = ':') == @["", "foo", "bar"] + doAssert rsplit(":foo:bar", sep = ':', maxsplit = 2) == @["", "foo", "bar"] + doAssert rsplit(":foo:bar", sep = ':', maxsplit = 3) == @["", "foo", "bar"] + doAssert rsplit("foothebar", sep = "the") == @["foo", "bar"] + + doAssert(unescape(r"\x013", "", "") == "\x013") + + doAssert join(["foo", "bar", "baz"]) == "foobarbaz" + doAssert join(@["foo", "bar", "baz"], ", ") == "foo, bar, baz" + doAssert join([1, 2, 3]) == "123" + doAssert join(@[1, 2, 3], ", ") == "1, 2, 3" + + doAssert """~~!!foo +~~!!bar +~~!!baz""".unindent(2, "~~!!") == "foo\nbar\nbaz" + + doAssert """~~!!foo +~~!!bar +~~!!baz""".unindent(2, "~~!!aa") == "~~!!foo\n~~!!bar\n~~!!baz" + doAssert """~~foo +~~ bar +~~ baz""".unindent(4, "~") == "foo\n bar\n baz" + doAssert """foo +bar + baz + """.unindent(4) == "foo\nbar\nbaz\n" + doAssert """foo + bar + baz + """.unindent(2) == "foo\n bar\n baz\n" + doAssert """foo + bar + baz + """.unindent(100) == "foo\nbar\nbaz\n" + + doAssert """foo + foo + bar + """.unindent() == "foo\nfoo\nbar\n" + + let s = " this is an example " + let s2 = ":this;is;an:example;;" + + doAssert s.split() == @["", "this", "is", "an", "example", "", ""] + doAssert s2.split(seps = {':', ';'}) == @["", "this", "is", "an", "example", + "", ""] + doAssert s.split(maxsplit = 4) == @["", "this", "is", "an", "example "] + doAssert s.split(' ', maxsplit = 1) == @["", "this is an example "] + doAssert s.split(" ", maxsplit = 4) == @["", "this", "is", "an", "example "] + + doAssert s.splitWhitespace() == @["this", "is", "an", "example"] + doAssert s.splitWhitespace(maxsplit = 1) == @["this", "is an example "] + doAssert s.splitWhitespace(maxsplit = 2) == @["this", "is", "an example "] + doAssert s.splitWhitespace(maxsplit = 3) == @["this", "is", "an", "example "] + doAssert s.splitWhitespace(maxsplit = 4) == @["this", "is", "an", "example"] + + block: # startsWith / endsWith char tests + var s = "abcdef" + doAssert s.startsWith('a') + doAssert s.startsWith('b') == false + doAssert s.endsWith('f') + doAssert s.endsWith('a') == false + doAssert s.endsWith('\0') == false + + #echo("strutils tests passed") + + nonStaticTests() + staticTests() + static: staticTests() diff --git a/lib/pure/sugar.nim b/lib/pure/sugar.nim index d8e00d1f8..fa28ffcf4 100644 --- a/lib/pure/sugar.nim +++ b/lib/pure/sugar.nim @@ -10,23 +10,18 @@ ## This module implements nice syntactic sugar based on Nim's ## macro system. -import std/private/since +include system/inclrtl + import macros +import typetraits -proc checkPragma(ex, prag: var NimNode) = - since (1, 3): - if ex.kind == nnkPragmaExpr: - prag = ex[1] - ex = ex[0] - -proc createProcType(p, b: NimNode): NimNode = +proc createProcType(p, b: NimNode): NimNode {.compileTime.} = + #echo treeRepr(p) + #echo treeRepr(b) result = newNimNode(nnkProcTy) - var - formalParams = newNimNode(nnkFormalParams).add(b) - p = p - prag = newEmptyNode() + var formalParams = newNimNode(nnkFormalParams) - checkPragma(p, prag) + formalParams.add b case p.kind of nnkPar, nnkTupleConstr: @@ -50,152 +45,105 @@ proc createProcType(p, b: NimNode): NimNode = formalParams.add identDefs result.add formalParams - result.add prag + result.add newEmptyNode() + #echo(treeRepr(result)) + #echo(result.toStrLit()) macro `=>`*(p, b: untyped): untyped = - ## Syntax sugar for anonymous procedures. It also supports pragmas. + ## Syntax sugar for anonymous procedures. ## - ## .. warning:: Semicolons can not be used to separate procedure arguments. - runnableExamples: - proc passTwoAndTwo(f: (int, int) -> int): int = f(2, 2) + ## .. code-block:: nim + ## + ## proc passTwoAndTwo(f: (int, int) -> int): int = + ## f(2, 2) + ## + ## passTwoAndTwo((x, y) => x + y) # 4 - assert passTwoAndTwo((x, y) => x + y) == 4 - - type - Bot = object - call: (string {.noSideEffect.} -> string) - - var myBot = Bot() - - myBot.call = (name: string) {.noSideEffect.} => "Hello " & name & ", I'm a bot." - assert myBot.call("John") == "Hello John, I'm a bot." - - let f = () => (discard) # simplest proc that returns void - f() - - var - params = @[ident"auto"] - name = newEmptyNode() - kind = nnkLambda - pragma = newEmptyNode() - p = p - - checkPragma(p, pragma) - - if p.kind == nnkInfix and p[0].kind == nnkIdent and p[0].eqIdent"->": - params[0] = p[2] - p = p[1] - - checkPragma(p, pragma) # check again after -> transform + #echo treeRepr(p) + #echo(treeRepr(b)) + var params: seq[NimNode] = @[newIdentNode("auto")] case p.kind of nnkPar, nnkTupleConstr: - var untypedBeforeColon = 0 - for i, c in p: + for c in children(p): var identDefs = newNimNode(nnkIdentDefs) case c.kind of nnkExprColonExpr: - let t = c[1] - since (1, 3): - # + 1 here because of return type in params - for j in (i - untypedBeforeColon + 1) .. i: - params[j][1] = t - untypedBeforeColon = 0 identDefs.add(c[0]) - identDefs.add(t) + identDefs.add(c[1]) identDefs.add(newEmptyNode()) of nnkIdent: identDefs.add(c) identDefs.add(newIdentNode("auto")) identDefs.add(newEmptyNode()) - inc untypedBeforeColon of nnkInfix: - if c[0].kind == nnkIdent and c[0].eqIdent"->": + if c[0].kind == nnkIdent and c[0].ident == !"->": var procTy = createProcType(c[1], c[2]) params[0] = procTy[0][0] for i in 1 ..< procTy[0].len: params.add(procTy[0][i]) else: - error("Expected proc type (->) got (" & c[0].strVal & ").", c) + error("Expected proc type (->) got (" & $c[0].ident & ").") break else: - error("Incorrect procedure parameter.", c) + echo treeRepr c + error("Incorrect procedure parameter list.") params.add(identDefs) - of nnkIdent, nnkOpenSymChoice, nnkClosedSymChoice, nnkSym: + of nnkIdent: var identDefs = newNimNode(nnkIdentDefs) - identDefs.add(ident $p) - identDefs.add(ident"auto") + identDefs.add(p) + identDefs.add(newIdentNode("auto")) identDefs.add(newEmptyNode()) params.add(identDefs) + of nnkInfix: + if p[0].kind == nnkIdent and p[0].ident == !"->": + var procTy = createProcType(p[1], p[2]) + params[0] = procTy[0][0] + for i in 1 ..< procTy[0].len: + params.add(procTy[0][i]) + else: + error("Expected proc type (->) got (" & $p[0].ident & ").") else: - error("Incorrect procedure parameter list.", p) - result = newProc(body = b, params = params, - pragmas = pragma, name = name, - procType = kind) + error("Incorrect procedure parameter list.") + result = newProc(params = params, body = b, procType = nnkLambda) + #echo(result.treeRepr) + #echo(result.toStrLit()) + #return result # TODO: Bug? macro `->`*(p, b: untyped): untyped = - ## Syntax sugar for procedure types. It also supports pragmas. + ## Syntax sugar for procedure types. ## - ## .. warning:: Semicolons can not be used to separate procedure arguments. - runnableExamples: - proc passTwoAndTwo(f: (int, int) -> int): int = f(2, 2) - # is the same as: - # proc passTwoAndTwo(f: proc (x, y: int): int): int = f(2, 2) - - assert passTwoAndTwo((x, y) => x + y) == 4 - - proc passOne(f: (int {.noSideEffect.} -> int)): int = f(1) - # is the same as: - # proc passOne(f: proc (x: int): int {.noSideEffect.}): int = f(1) - - assert passOne(x {.noSideEffect.} => x + 1) == 2 + ## .. code-block:: nim + ## + ## proc pass2(f: (float, float) -> float): float = + ## f(2, 2) + ## + ## # is the same as: + ## + ## proc pass2(f: proc (x, y: float): float): float = + ## f(2, 2) result = createProcType(p, b) -macro dump*(x: untyped): untyped = +macro dump*(x: typed): untyped = ## Dumps the content of an expression, useful for debugging. ## It accepts any expression and prints a textual representation ## of the tree representing the expression - as it would appear in ## source code - together with the value of the expression. ## - ## See also: `dumpToString` which is more convenient and useful since - ## it expands intermediate templates/macros, returns a string instead of - ## calling `echo`, and works with statements and expressions. - runnableExamples("-r:off"): - let - x = 10 - y = 20 - dump(x + y) # prints: `x + y = 30` - + ## As an example, + ## + ## .. code-block:: nim + ## let + ## x = 10 + ## y = 20 + ## dump(x + y) + ## + ## will print ``x + y = 30``. let s = x.toStrLit - result = quote do: + let r = quote do: debugEcho `s`, " = ", `x` - -macro dumpToStringImpl(s: static string, x: typed): string = - let s2 = x.toStrLit - if x.typeKind == ntyVoid: - result = quote do: - `s` & ": " & `s2` - else: - result = quote do: - `s` & ": " & `s2` & " = " & $`x` - -macro dumpToString*(x: untyped): string = - ## Returns the content of a statement or expression `x` after semantic analysis, - ## useful for debugging. - runnableExamples: - const a = 1 - let x = 10 - assert dumpToString(a + 2) == "a + 2: 3 = 3" - assert dumpToString(a + x) == "a + x: 1 + x = 11" - template square(x): untyped = x * x - assert dumpToString(square(x)) == "square(x): x * x = 100" - assert not compiles dumpToString(1 + nonexistent) - import std/strutils - assert "failedAssertImpl" in dumpToString(assert true) # example with a statement - result = newCall(bindSym"dumpToStringImpl") - result.add newLit repr(x) - result.add x + return r # TODO: consider exporting this in macros.nim proc freshIdentNodes(ast: NimNode): NimNode = @@ -213,216 +161,206 @@ proc freshIdentNodes(ast: NimNode): NimNode = result.add inspect(child) result = inspect(ast) -macro capture*(locals: varargs[typed], body: untyped): untyped {.since: (1, 1).} = +template distinctBase*(T: typedesc): typedesc {.deprecated: "use distinctBase from typetraits instead".} = + ## reverses ``type T = distinct A``; works recursively. + typetraits.distinctBase(T) + +macro capture*(locals: openArray[typed], body: untyped): untyped {.since: (1, 1).} = ## Useful when creating a closure in a loop to capture some local loop variables - ## by their current iteration values. - runnableExamples: - import std/strformat - - var myClosure: () -> string - for i in 5..7: - for j in 7..9: - if i * j == 42: - capture i, j: - myClosure = () => fmt"{i} * {j} = 42" - assert myClosure() == "6 * 7 = 42" - + ## by their current iteration values. Example: + ## + ## .. code-block:: Nim + ## import strformat, sequtils, sugar + ## var myClosure : proc() + ## for i in 5..7: + ## for j in 7..9: + ## if i * j == 42: + ## capture [i, j]: + ## myClosure = proc () = echo fmt"{i} * {j} = 42" + ## myClosure() # output: 6 * 7 == 42 + ## let m = @[proc (s: string): string = "to " & s, proc (s: string): string = "not to " & s] + ## var l = m.mapIt(capture([it], proc (s: string): string = it(s))) + ## let r = l.mapIt(it("be")) + ## echo r[0] & ", or " & r[1] # output: to be, or not to be var params = @[newIdentNode("auto")] - let locals = if locals.len == 1 and locals[0].kind == nnkBracket: locals[0] - else: locals for arg in locals: - proc getIdent(n: NimNode): NimNode = - case n.kind - of nnkIdent, nnkSym: - let nStr = n.strVal - if nStr == "result": - error("The variable name cannot be `result`!", n) - result = ident(nStr) - of nnkHiddenDeref: result = n[0].getIdent() - else: - error("The argument to be captured `" & n.repr & "` is not a pure identifier. " & - "It is an unsupported `" & $n.kind & "` node.", n) - let argName = getIdent(arg) - params.add(newIdentDefs(argName, freshIdentNodes getTypeInst arg)) + params.add(newIdentDefs(ident(arg.strVal), freshIdentNodes getTypeInst arg)) result = newNimNode(nnkCall) - result.add(newProc(newEmptyNode(), params, body, nnkLambda)) + result.add(newProc(newEmptyNode(), params, body, nnkProcDef)) for arg in locals: result.add(arg) -since (1, 1): - import std/private/underscored_calls +macro outplace*[T](arg: T, call: untyped; inplaceArgPosition: static[int] = 1): T {.since: (1, 1).} = + ## Turns an `in-place`:idx: algorithm into one that works on + ## a copy and returns this copy. The second parameter is the + ## index of the calling expression that is replaced by a copy + ## of this expression. + ## **Since**: Version 1.2. + runnableExamples: + import algorithm - macro dup*[T](arg: T, calls: varargs[untyped]): T = - ## Turns an `in-place`:idx: algorithm into one that works on - ## a copy and returns this copy, without modifying its input. - ## - ## This macro also allows for (otherwise in-place) function chaining. - ## - ## **Since:** Version 1.2. - runnableExamples: - import std/algorithm + var a = @[1, 2, 3, 4, 5, 6, 7, 8, 9] + doAssert a.outplace(sort()) == sorted(a) + #Chaining: + var aCopy = a + aCopy.insert(10) - let a = @[1, 2, 3, 4, 5, 6, 7, 8, 9] - assert a.dup(sort) == sorted(a) + doAssert a.outplace(insert(10)).outplace(sort()) == sorted(aCopy) - # Chaining: - var aCopy = a - aCopy.insert(10) - assert a.dup(insert(10), sort) == sorted(aCopy) + expectKind call, nnkCallKinds + let tmp = genSym(nskVar, "outplaceResult") + var callsons = call[0..^1] + callsons.insert(tmp, inplaceArgPosition) + result = newTree(nnkStmtListExpr, + newVarStmt(tmp, arg), + copyNimNode(call).add callsons, + tmp) - let s1 = "abc" - let s2 = "xyz" - assert s1 & s2 == s1.dup(&= s2) - - # An underscore (_) can be used to denote the place of the argument you're passing: - assert "".dup(addQuoted(_, "foo")) == "\"foo\"" - # but `_` is optional here since the substitution is in 1st position: - assert "".dup(addQuoted("foo")) == "\"foo\"" - - proc makePalindrome(s: var string) = - for i in countdown(s.len-2, 0): - s.add(s[i]) - - let c = "xyz" - - # chaining: - let d = dup c: - makePalindrome # xyzyx - sort(_, SortOrder.Descending) # zyyxx - makePalindrome # zyyxxxyyz - assert d == "zyyxxxyyz" - - result = newNimNode(nnkStmtListExpr, arg) - let tmp = genSym(nskVar, "dupResult") - result.add newVarStmt(tmp, arg) - underscoredCalls(result, calls, tmp) - result.add tmp - -proc trans(n, res, bracketExpr: NimNode): (NimNode, NimNode, NimNode) {.since: (1, 1).} = +proc transLastStmt(n, res, bracketExpr: NimNode): (NimNode, NimNode, NimNode) {.since: (1, 1).} = # Looks for the last statement of the last statement, etc... case n.kind - of nnkIfExpr, nnkIfStmt, nnkTryStmt, nnkCaseStmt, nnkWhenStmt: + of nnkIfExpr, nnkIfStmt, nnkTryStmt, nnkCaseStmt: result[0] = copyNimTree(n) result[1] = copyNimTree(n) result[2] = copyNimTree(n) - for i in ord(n.kind == nnkCaseStmt) ..< n.len: - (result[0][i], result[1][^1], result[2][^1]) = trans(n[i], res, bracketExpr) + for i in ord(n.kind == nnkCaseStmt)..= 1: - (result[0][^1], result[1][^1], result[2][^1]) = trans(n[^1], - res, bracketExpr) + (result[0][^1], result[1][^1], result[2][^1]) = transLastStmt(n[^1], res, bracketExpr) of nnkTableConstr: result[1] = n[0][0] result[2] = n[0][1] - if bracketExpr.len == 0: - bracketExpr.add(ident"initTable") # don't import tables if bracketExpr.len == 1: - bracketExpr.add([newCall(bindSym"typeof", - newEmptyNode()), newCall(bindSym"typeof", newEmptyNode())]) + bracketExpr.add([newCall(bindSym"typeof", newEmptyNode()), newCall( + bindSym"typeof", newEmptyNode())]) template adder(res, k, v) = res[k] = v result[0] = getAst(adder(res, n[0][0], n[0][1])) of nnkCurly: result[2] = n[0] - if bracketExpr.len == 0: - bracketExpr.add(ident"initHashSet") if bracketExpr.len == 1: bracketExpr.add(newCall(bindSym"typeof", newEmptyNode())) template adder(res, v) = res.incl(v) result[0] = getAst(adder(res, n[0])) else: result[2] = n - if bracketExpr.len == 0: - bracketExpr.add(bindSym"newSeq") if bracketExpr.len == 1: bracketExpr.add(newCall(bindSym"typeof", newEmptyNode())) template adder(res, v) = res.add(v) result[0] = getAst(adder(res, n)) -proc collectImpl(init, body: NimNode): NimNode {.since: (1, 1).} = +macro collect*(init, body: untyped): untyped {.since: (1, 1).} = + ## Comprehension for seq/set/table collections. ``init`` is + ## the init call, and so custom collections are supported. + ## + ## The last statement of ``body`` has special syntax that specifies + ## the collection's add operation. Use ``{e}`` for set's ``incl``, + ## ``{k: v}`` for table's ``[]=`` and ``e`` for seq's ``add``. + ## + ## The ``init`` proc can be called with any number of arguments, + ## i.e. ``initTable(initialSize)``. + runnableExamples: + import sets, tables + let data = @["bird", "word"] + ## seq: + let k = collect(newSeq): + for i, d in data.pairs: + if i mod 2 == 0: d + + assert k == @["bird"] + ## seq with initialSize: + let x = collect(newSeqOfCap(4)): + for i, d in data.pairs: + if i mod 2 == 0: d + + assert x == @["bird"] + ## HashSet: + let y = initHashSet.collect: + for d in data.items: {d} + + assert y == data.toHashSet + ## Table: + let z = collect(initTable(2)): + for i, d in data.pairs: {i: d} + + assert z == {1: "word", 0: "bird"}.toTable + # analyse the body, find the deepest expression 'it' and replace it via + # 'result.add it' let res = genSym(nskVar, "collectResult") - var bracketExpr: NimNode - if init != nil: - expectKind init, {nnkCall, nnkIdent, nnkSym} - bracketExpr = newTree(nnkBracketExpr, - if init.kind == nnkCall: freshIdentNodes(init[0]) else: freshIdentNodes(init)) - else: - bracketExpr = newTree(nnkBracketExpr) - let (resBody, keyType, valueType) = trans(body, res, bracketExpr) + expectKind init, {nnkCall, nnkIdent, nnkSym} + let bracketExpr = newTree(nnkBracketExpr, + if init.kind == nnkCall: init[0] else: init) + let (resBody, keyType, valueType) = transLastStmt(body, res, bracketExpr) if bracketExpr.len == 3: bracketExpr[1][1] = keyType bracketExpr[2][1] = valueType else: bracketExpr[1][1] = valueType let call = newTree(nnkCall, bracketExpr) - if init != nil and init.kind == nnkCall: + if init.kind == nnkCall: for i in 1 ..< init.len: call.add init[i] result = newTree(nnkStmtListExpr, newVarStmt(res, call), resBody, res) -macro collect*(init, body: untyped): untyped {.since: (1, 1).} = - ## Comprehension for seqs/sets/tables. - ## - ## The last expression of `body` has special syntax that specifies - ## the collection's add operation. Use `{e}` for set's `incl`, - ## `{k: v}` for table's `[]=` and `e` for seq's `add`. - # analyse the body, find the deepest expression 'it' and replace it via - # 'result.add it' - runnableExamples: - import std/[sets, tables] +when isMainModule: + since (1, 1): + import algorithm - let data = @["bird", "word"] + var a = @[1, 2, 3, 4, 5, 6, 7, 8, 9] + doAssert outplace(a, sort()) == sorted(a) + doAssert a.outplace(sort()) == sorted(a) + #Chaining: + var aCopy = a + aCopy.insert(10) + doAssert a.outplace(insert(10)).outplace(sort()) == sorted(aCopy) - ## seq: - let k = collect(newSeq): - for i, d in data.pairs: - if i mod 2 == 0: d - assert k == @["bird"] + import random + + const b = @[0, 1, 2] + let c = b.outplace shuffle() + doAssert c[0] == 1 + doAssert c[1] == 0 + + #test collect + import sets, tables + + let data = @["bird", "word"] # if this gets stuck in your head, its not my fault + assert collect(newSeq, for (i, d) in data.pairs: (if i mod 2 == 0: d)) == @["bird"] + assert collect(initTable(2), for (i, d) in data.pairs: {i: d}) == {1: "word", + 0: "bird"}.toTable + assert initHashSet.collect(for d in data.items: {d}) == data.toHashSet - ## seq with initialSize: let x = collect(newSeqOfCap(4)): - for i, d in data.pairs: - if i mod 2 == 0: d + for (i, d) in data.pairs: + if i mod 2 == 0: d assert x == @["bird"] - ## HashSet: - let y = collect(initHashSet()): - for d in data.items: {d} - assert y == data.toHashSet + # bug #12874 - ## Table: - let z = collect(initTable(2)): - for i, d in data.pairs: {i: d} - assert z == {0: "bird", 1: "word"}.toTable + let bug1 = collect( + newSeq, + for (i, d) in data.pairs:( + block: + if i mod 2 == 0: + d + else: + d & d + ) + ) + assert bug1 == @["bird", "wordword"] - result = collectImpl(init, body) + import strutils + let y = collect(newSeq): + for (i, d) in data.pairs: + try: parseInt(d) except: 0 + assert y == @[0, 0] -macro collect*(body: untyped): untyped {.since: (1, 5).} = - ## Same as `collect` but without an `init` parameter. - ## - ## **See also:** - ## * `sequtils.toSeq proc`_ - ## * `sequtils.mapIt template`_ - runnableExamples: - import std/[sets, tables] - let data = @["bird", "word"] - - # seq: - let k = collect: - for i, d in data.pairs: - if i mod 2 == 0: d - assert k == @["bird"] - - ## HashSet: - let n = collect: - for d in data.items: {d} - assert n == data.toHashSet - - ## Table: - let m = collect: - for i, d in data.pairs: {i: d} - assert m == {0: "bird", 1: "word"}.toTable - - result = collectImpl(nil, body) + let z = collect(newSeq): + for (i, d) in data.pairs: + case d + of "bird": "word" + else: d + assert z == @["word", "word"] diff --git a/lib/pure/terminal.nim b/lib/pure/terminal.nim index daf470b09..e798bbaf1 100644 --- a/lib/pure/terminal.nim +++ b/lib/pure/terminal.nim @@ -12,51 +12,9 @@ ## sequences and does not depend on any other module, on Windows it uses the ## Windows API. ## Changing the style is permanent even after program termination! Use the -## code `exitprocs.addExitProc(resetAttributes)` to restore the defaults. +## code ``system.addQuitProc(resetAttributes)`` to restore the defaults. ## Similarly, if you hide the cursor, make sure to unhide it with -## `showCursor` before quitting. -## -## Progress bar -## ============ -## -## Basic progress bar example: -runnableExamples("-r:off"): - import std/[os, strutils] - - for i in 0..100: - stdout.styledWriteLine(fgRed, "0% ", fgWhite, '#'.repeat i, if i > 50: fgGreen else: fgYellow, "\t", $i , "%") - sleep 42 - cursorUp 1 - eraseLine() - - stdout.resetAttributes() - -##[ -## Playing with colorful and styled text -]## - -## Procs like `styledWriteLine`, `styledEcho` etc. have a temporary effect on -## text parameters. Style parameters only affect the text parameter right after them. -## After being called, these procs will reset the default style of the terminal. -## While `setBackGroundColor`, `setForeGroundColor` etc. have a lasting -## influence on the terminal, you can use `resetAttributes` to -## reset the default style of the terminal. -runnableExamples("-r:off"): - stdout.styledWriteLine({styleBright, styleBlink, styleUnderscore}, "styled text ") - stdout.styledWriteLine(fgRed, "red text ") - stdout.styledWriteLine(fgWhite, bgRed, "white text in red background") - stdout.styledWriteLine(" ordinary text without style ") - - stdout.setBackGroundColor(bgCyan, true) - stdout.setForeGroundColor(fgBlue) - stdout.write("blue text in cyan background") - stdout.resetAttributes() - - # You can specify multiple text parameters. Style parameters - # only affect the text parameter right after them. - styledEcho styleBright, fgGreen, "[PASS]", resetStyle, fgGreen, " Yay!" - - stdout.styledWriteLine(fgRed, "red text ", styleBright, "bold red", fgDefault, " bold text") +## ``showCursor`` before quitting. import macros import strformat @@ -66,9 +24,6 @@ import colors when defined(windows): import winlean -when defined(nimPreviewSlimSystem): - import std/[syncio, assertions] - type PTerminal = ref object trueColorIsSupported: bool @@ -82,10 +37,7 @@ type var gTerm {.threadvar.}: owned(PTerminal) -when defined(windows) and defined(consoleapp): - proc newTerminal(): owned(PTerminal) {.gcsafe, raises: [OSError].} -else: - proc newTerminal(): owned(PTerminal) {.gcsafe, raises: [].} +proc newTerminal(): owned(PTerminal) {.gcsafe.} proc getTerminal(): PTerminal {.inline.} = if isNil(gTerm): @@ -93,8 +45,8 @@ proc getTerminal(): PTerminal {.inline.} = result = gTerm const - fgPrefix = "\e[38;2;" - bgPrefix = "\e[48;2;" + fgPrefix = "\x1b[38;2;" + bgPrefix = "\x1b[48;2;" ansiResetCode* = "\e[0m" stylePrefix = "\e[" @@ -173,7 +125,6 @@ when defined(windows): return 0 proc terminalWidth*(): int = - ## Returns the terminal width in columns. var w: int = 0 w = terminalWidthIoctl([getStdHandle(STD_INPUT_HANDLE), getStdHandle(STD_OUTPUT_HANDLE), @@ -182,7 +133,6 @@ when defined(windows): return 80 proc terminalHeight*(): int = - ## Returns the terminal height in rows. var h: int = 0 h = terminalHeightIoctl([getStdHandle(STD_INPUT_HANDLE), getStdHandle(STD_OUTPUT_HANDLE), @@ -300,7 +250,7 @@ else: discard close(fd) if w > 0: return w var s = getEnv("COLUMNS") #Try standard env var - if len(s) > 0 and parseInt(s, w) > 0 and w > 0: + if len(s) > 0 and parseInt(string(s), w) > 0 and w > 0: return w return 80 #Finally default to venerable value @@ -318,7 +268,7 @@ else: discard close(fd) if h > 0: return h var s = getEnv("LINES") # Try standard env var - if len(s) > 0 and parseInt(s, h) > 0 and h > 0: + if len(s) > 0 and parseInt(string(s), h) > 0 and h > 0: return h return 0 # Could not determine height @@ -379,7 +329,7 @@ when defined(windows): proc setCursorYPos*(f: File, y: int) = ## Sets the terminal's cursor to the y position. ## The x position is not changed. - ## .. warning:: This is not supported on UNIX! + ## **Warning**: This is not supported on UNIX! when defined(windows): let h = conHandle(f) var scrbuf: CONSOLE_SCREEN_BUFFER_INFO @@ -394,9 +344,6 @@ when defined(windows): proc cursorUp*(f: File, count = 1) = ## Moves the cursor up by `count` rows. - runnableExamples("-r:off"): - stdout.cursorUp(2) - write(stdout, "Hello World!") # anything written at that location will be erased/replaced with this when defined(windows): let h = conHandle(f) var p = getCursorPos(h) @@ -407,9 +354,6 @@ proc cursorUp*(f: File, count = 1) = proc cursorDown*(f: File, count = 1) = ## Moves the cursor down by `count` rows. - runnableExamples("-r:off"): - stdout.cursorDown(2) - write(stdout, "Hello World!") # anything written at that location will be erased/replaced with this when defined(windows): let h = conHandle(f) var p = getCursorPos(h) @@ -420,9 +364,6 @@ proc cursorDown*(f: File, count = 1) = proc cursorForward*(f: File, count = 1) = ## Moves the cursor forward by `count` columns. - runnableExamples("-r:off"): - stdout.cursorForward(2) - write(stdout, "Hello World!") # anything written at that location will be erased/replaced with this when defined(windows): let h = conHandle(f) var p = getCursorPos(h) @@ -433,9 +374,6 @@ proc cursorForward*(f: File, count = 1) = proc cursorBackward*(f: File, count = 1) = ## Moves the cursor backward by `count` columns. - runnableExamples("-r:off"): - stdout.cursorBackward(2) - write(stdout, "Hello World!") # anything written at that location will be erased/replaced with this when defined(windows): let h = conHandle(f) var p = getCursorPos(h) @@ -477,9 +415,6 @@ else: proc eraseLine*(f: File) = ## Erases the entire current line. - runnableExamples("-r:off"): - write(stdout, "never mind") - stdout.eraseLine() # nothing will be printed on the screen when defined(windows): let h = conHandle(f) var scrbuf: CONSOLE_SCREEN_BUFFER_INFO @@ -542,7 +477,7 @@ proc resetAttributes*(f: File) = gBG = 0 type - Style* = enum ## Different styles for text output. + Style* = enum ## different styles for text output styleBright = 1, ## bright text styleDim, ## dim text styleItalic, ## italic (or reverse on terminals not supporting) @@ -596,7 +531,7 @@ proc writeStyled*(txt: string, style: set[Style] = {styleBright}) = stdout.write(ansiStyleCode(gBG)) type - ForegroundColor* = enum ## Terminal's foreground colors. + ForegroundColor* = enum ## terminal's foreground colors fgBlack = 30, ## black fgRed, ## red fgGreen, ## green @@ -605,10 +540,10 @@ type fgMagenta, ## magenta fgCyan, ## cyan fgWhite, ## white - fg8Bit, ## 256-color (not supported, see `enableTrueColors` instead.) + fg8Bit, ## 256-color (not supported, see ``enableTrueColors`` instead.) fgDefault ## default terminal foreground color - BackgroundColor* = enum ## Terminal's background colors. + BackgroundColor* = enum ## terminal's background colors bgBlack = 40, ## black bgRed, ## red bgGreen, ## green @@ -617,7 +552,7 @@ type bgMagenta, ## magenta bgCyan, ## cyan bgWhite, ## white - bg8Bit, ## 256-color (not supported, see `enableTrueColors` instead.) + bg8Bit, ## 256-color (not supported, see ``enableTrueColors`` instead.) bgDefault ## default terminal background color when defined(windows): @@ -641,12 +576,12 @@ proc setForegroundColor*(f: File, fg: ForegroundColor, bright = false) = (FOREGROUND_RED or FOREGROUND_BLUE), (FOREGROUND_BLUE or FOREGROUND_GREEN), (FOREGROUND_BLUE or FOREGROUND_GREEN or FOREGROUND_RED), - 0, # fg8Bit not supported, see `enableTrueColors` instead. + 0, # fg8Bit not supported, see ``enableTrueColors`` instead. 0] # unused if fg == fgDefault: - discard setConsoleTextAttribute(h, cast[int16](cast[uint16](old) or cast[uint16](defaultForegroundColor))) + discard setConsoleTextAttribute(h, toU16(old or defaultForegroundColor)) else: - discard setConsoleTextAttribute(h, cast[int16](cast[uint16](old) or cast[uint16](lookup[fg]))) + discard setConsoleTextAttribute(h, toU16(old or lookup[fg])) else: gFG = ord(fg) if bright: inc(gFG, 60) @@ -670,12 +605,12 @@ proc setBackgroundColor*(f: File, bg: BackgroundColor, bright = false) = (BACKGROUND_RED or BACKGROUND_BLUE), (BACKGROUND_BLUE or BACKGROUND_GREEN), (BACKGROUND_BLUE or BACKGROUND_GREEN or BACKGROUND_RED), - 0, # bg8Bit not supported, see `enableTrueColors` instead. + 0, # bg8Bit not supported, see ``enableTrueColors`` instead. 0] # unused if bg == bgDefault: - discard setConsoleTextAttribute(h, cast[int16](cast[uint16](old) or cast[uint16](defaultBackgroundColor))) + discard setConsoleTextAttribute(h, toU16(old or defaultBackgroundColor)) else: - discard setConsoleTextAttribute(h, cast[int16](cast[uint16](old) or cast[uint16](lookup[bg]))) + discard setConsoleTextAttribute(h, toU16(old or lookup[bg])) else: gBG = ord(bg) if bright: inc(gBG, 60) @@ -754,19 +689,24 @@ template styledEchoProcessArg(f: File, color: Color) = template styledEchoProcessArg(f: File, cmd: TerminalCmd) = when cmd == resetStyle: resetAttributes(f) - elif cmd in {fgColor, bgColor}: - let term = getTerminal() - term.fgSetColor = cmd == fgColor + when cmd == fgColor: + fgSetColor = true + when cmd == bgColor: + fgSetColor = false macro styledWrite*(f: File, m: varargs[typed]): untyped = - ## Similar to `write`, but treating terminal style arguments specially. - ## When some argument is `Style`, `set[Style]`, `ForegroundColor`, - ## `BackgroundColor` or `TerminalCmd` then it is not sent directly to - ## `f`, but instead corresponding terminal style proc is called. - runnableExamples("-r:off"): - stdout.styledWrite(fgRed, "red text ") - stdout.styledWrite(fgGreen, "green text") - + ## Similar to ``write``, but treating terminal style arguments specially. + ## When some argument is ``Style``, ``set[Style]``, ``ForegroundColor``, + ## ``BackgroundColor`` or ``TerminalCmd`` then it is not sent directly to + ## ``f``, but instead corresponding terminal style proc is called. + ## + ## Example: + ## + ## .. code-block:: nim + ## + ## stdout.styledWrite(fgRed, "red text ") + ## stdout.styledWrite(fgGreen, "green text") + ## var reset = false result = newNimNode(nnkStmtList) @@ -788,20 +728,24 @@ macro styledWrite*(f: File, m: varargs[typed]): untyped = if reset: result.add(newCall(bindSym"resetAttributes", f)) template styledWriteLine*(f: File, args: varargs[untyped]) = - ## Calls `styledWrite` and appends a newline at the end. - runnableExamples: - proc error(msg: string) = - styledWriteLine(stderr, fgRed, "Error: ", resetStyle, msg) - + ## Calls ``styledWrite`` and appends a newline at the end. + ## + ## Example: + ## + ## .. code-block:: nim + ## + ## proc error(msg: string) = + ## styledWriteLine(stderr, fgRed, "Error: ", resetStyle, msg) + ## styledWrite(f, args) write(f, "\n") template styledEcho*(args: varargs[untyped]) = - ## Echoes styles arguments to stdout using `styledWriteLine`. + ## Echoes styles arguments to stdout using ``styledWriteLine``. stdout.styledWriteLine(args) proc getch*(): char = - ## Reads a single character from the terminal, blocking until it is entered. + ## Read a single character from the terminal, blocking until it is entered. ## The character is not printed to the terminal. when defined(windows): let fd = getStdHandle(STD_INPUT_HANDLE) @@ -823,35 +767,42 @@ proc getch*(): char = discard fd.tcSetAttr(TCSADRAIN, addr oldMode) when defined(windows): - proc readPasswordFromStdin*(prompt: string, password: var string): + from unicode import toUTF8, Rune, runeLenAt + + proc readPasswordFromStdin*(prompt: string, password: var TaintedString): bool {.tags: [ReadIOEffect, WriteIOEffect].} = ## Reads a `password` from stdin without printing it. `password` must not - ## be `nil`! Returns `false` if the end of the file has been reached, - ## `true` otherwise. - password.setLen(0) + ## be ``nil``! Returns ``false`` if the end of the file has been reached, + ## ``true`` otherwise. + password.string.setLen(0) stdout.write(prompt) - let hi = createFileA("CONIN$", - GENERIC_READ or GENERIC_WRITE, 0, nil, OPEN_EXISTING, 0, 0) - var mode = DWORD 0 - discard getConsoleMode(hi, addr mode) - let origMode = mode - const - ENABLE_PROCESSED_INPUT = 1 - ENABLE_ECHO_INPUT = 4 - mode = (mode or ENABLE_PROCESSED_INPUT) and not ENABLE_ECHO_INPUT - - discard setConsoleMode(hi, mode) - result = readLine(stdin, password) - discard setConsoleMode(hi, origMode) - discard closeHandle(hi) + while true: + let c = getch() + case c.char + of '\r', chr(0xA): + break + of '\b': + # ensure we delete the whole UTF-8 character: + var i = 0 + var x = 1 + while i < password.len: + x = runeLenAt(password.string, i) + inc i, x + password.string.setLen(max(password.len - x, 0)) + of chr(0x0): + # modifier key - ignore - for details see + # https://github.com/nim-lang/Nim/issues/7764 + continue + else: + password.string.add(toUTF8(c.Rune)) stdout.write "\n" else: import termios - proc readPasswordFromStdin*(prompt: string, password: var string): + proc readPasswordFromStdin*(prompt: string, password: var TaintedString): bool {.tags: [ReadIOEffect, WriteIOEffect].} = - password.setLen(0) + password.string.setLen(0) let fd = stdin.getFileHandle() var cur, old: Termios discard fd.tcGetAttr(cur.addr) @@ -863,9 +814,9 @@ else: stdout.write "\n" discard fd.tcSetAttr(TCSADRAIN, old.addr) -proc readPasswordFromStdin*(prompt = "password: "): string = +proc readPasswordFromStdin*(prompt = "password: "): TaintedString = ## Reads a password from stdin without printing it. - result = "" + result = TaintedString("") discard readPasswordFromStdin(prompt, result) @@ -895,7 +846,7 @@ template setBackgroundColor*(color: Color) = proc resetAttributes*() {.noconv.} = ## Resets all attributes on stdout. ## It is advisable to register this as a quit proc with - ## `exitprocs.addExitProc(resetAttributes)`. + ## ``system.addQuitProc(resetAttributes)``. resetAttributes(stdout) proc isTrueColorSupported*(): bool = @@ -906,7 +857,7 @@ when defined(windows): import os proc enableTrueColors*() = - ## Enables true color. + ## Enable true color. var term = getTerminal() when defined(windows): var @@ -934,12 +885,12 @@ proc enableTrueColors*() = else: term.trueColorIsEnabled = true else: - term.trueColorIsSupported = getEnv("COLORTERM").toLowerAscii() in [ + term.trueColorIsSupported = string(getEnv("COLORTERM")).toLowerAscii() in [ "truecolor", "24bit"] term.trueColorIsEnabled = term.trueColorIsSupported proc disableTrueColors*() = - ## Disables true color. + ## Disable true color. var term = getTerminal() when defined(windows): if term.trueColorIsSupported: @@ -956,3 +907,51 @@ proc newTerminal(): owned(PTerminal) = new result when defined(windows): initTerminal(result) + +when not defined(testing) and isMainModule: + assert ansiStyleCode(styleBright) == "\e[1m" + assert ansiStyleCode(styleStrikethrough) == "\e[9m" + #system.addQuitProc(resetAttributes) + write(stdout, "never mind") + stdout.eraseLine() + stdout.styledWriteLine({styleBright, styleBlink, styleUnderscore}, "styled text ") + stdout.styledWriteLine("italic text ", {styleItalic}) + stdout.setBackGroundColor(bgCyan, true) + stdout.setForeGroundColor(fgBlue) + stdout.write("blue text in cyan background") + stdout.resetAttributes() + echo "" + stdout.writeLine("ordinary text") + echo "more ordinary text" + styledEcho styleBright, fgGreen, "[PASS]", resetStyle, fgGreen, " Yay!" + echo "ordinary text again" + styledEcho styleBright, fgRed, "[FAIL]", resetStyle, fgRed, " Nay :(" + echo "ordinary text again" + setForeGroundColor(fgGreen) + echo "green text" + echo "more green text" + setForeGroundColor(fgBlue) + echo "blue text" + resetAttributes() + echo "ordinary text" + + stdout.styledWriteLine(fgRed, "red text ") + stdout.styledWriteLine(fgWhite, bgRed, "white text in red background") + stdout.styledWriteLine(" ordinary text ") + stdout.styledWriteLine(fgGreen, "green text") + + writeStyled("underscored text", {styleUnderscore}) + stdout.styledWrite(fgRed, " red text ") + writeStyled("bright text ", {styleBright}) + echo "ordinary text" + + stdout.styledWrite(fgRed, "red text ") + stdout.styledWrite(fgWhite, bgRed, "white text in red background") + stdout.styledWrite(" ordinary text ") + stdout.styledWrite(fgGreen, "green text") + echo "" + echo "ordinary text" + stdout.styledWriteLine(fgRed, "red text ", styleBright, "bold red", fgDefault, " bold text") + stdout.styledWriteLine(bgYellow, "text in yellow bg", styleBright, + " bold text in yellow bg", bgDefault, " bold text") + echo "ordinary text" diff --git a/lib/pure/times.nim b/lib/pure/times.nim index 138f2d9ec..3fc4d69df 100644 --- a/lib/pure/times.nim +++ b/lib/pure/times.nim @@ -8,20 +8,20 @@ # ##[ - The `times` module contains routines and types for dealing with time using + The ``times`` module contains routines and types for dealing with time using the `proleptic Gregorian calendar`_. It's also available for the `JavaScript target `_. - Although the `times` module supports nanosecond time resolution, the - resolution used by `getTime()` depends on the platform and backend + Although the ``times`` module supports nanosecond time resolution, the + resolution used by ``getTime()`` depends on the platform and backend (JS is limited to millisecond precision). Examples ======== .. code-block:: nim - import std/[times, os] + import times, os # Simple benchmarking let time = cpuTime() sleep(100) # Replace this with something to be timed @@ -41,8 +41,8 @@ Parsing and Formatting Dates ============================ - The `DateTime` type can be parsed and formatted using the different - `parse` and `format` procedures. + The ``DateTime`` type can be parsed and formatted using the different + ``parse`` and ``format`` procedures. .. code-block:: nim @@ -51,128 +51,124 @@ The different format patterns that are supported are documented below. - =========== ================================================================================= ============================================== - Pattern Description Example - =========== ================================================================================= ============================================== - `d` Numeric value representing the day of the month, | `1/04/2012 -> 1` - it will be either one or two digits long. | `21/04/2012 -> 21` - `dd` Same as above, but is always two digits. | `1/04/2012 -> 01` - | `21/04/2012 -> 21` - `ddd` Three letter string which indicates the day of the week. | `Saturday -> Sat` - | `Monday -> Mon` - `dddd` Full string for the day of the week. | `Saturday -> Saturday` - | `Monday -> Monday` - `h` The hours in one digit if possible. Ranging from 1-12. | `5pm -> 5` - | `2am -> 2` - `hh` The hours in two digits always. If the hour is one digit, 0 is prepended. | `5pm -> 05` - | `11am -> 11` - `H` The hours in one digit if possible, ranging from 0-23. | `5pm -> 17` - | `2am -> 2` - `HH` The hours in two digits always. 0 is prepended if the hour is one digit. | `5pm -> 17` - | `2am -> 02` - `m` The minutes in one digit if possible. | `5:30 -> 30` - | `2:01 -> 1` - `mm` Same as above but always two digits, 0 is prepended if the minute is one digit. | `5:30 -> 30` - | `2:01 -> 01` - `M` The month in one digit if possible. | `September -> 9` - | `December -> 12` - `MM` The month in two digits always. 0 is prepended if the month value is one digit. | `September -> 09` - | `December -> 12` - `MMM` Abbreviated three-letter form of the month. | `September -> Sep` - | `December -> Dec` - `MMMM` Full month string, properly capitalized. | `September -> September` - `s` Seconds as one digit if possible. | `00:00:06 -> 6` - `ss` Same as above but always two digits. 0 is prepended if the second is one digit. | `00:00:06 -> 06` - `t` `A` when time is in the AM. `P` when time is in the PM. | `5pm -> P` - | `2am -> A` - `tt` Same as above, but `AM` and `PM` instead of `A` and `P` respectively. | `5pm -> PM` - | `2am -> AM` - `yy` The last two digits of the year. When parsing, the current century is assumed. | `2012 AD -> 12` - `yyyy` The year, padded to at least four digits. | `2012 AD -> 2012` - Is always positive, even when the year is BC. | `24 AD -> 0024` - When the year is more than four digits, '+' is prepended. | `24 BC -> 00024` - | `12345 AD -> +12345` - `YYYY` The year without any padding. | `2012 AD -> 2012` - Is always positive, even when the year is BC. | `24 AD -> 24` - | `24 BC -> 24` - | `12345 AD -> 12345` - `uuuu` The year, padded to at least four digits. Will be negative when the year is BC. | `2012 AD -> 2012` - When the year is more than four digits, '+' is prepended unless the year is BC. | `24 AD -> 0024` - | `24 BC -> -0023` - | `12345 AD -> +12345` - `UUUU` The year without any padding. Will be negative when the year is BC. | `2012 AD -> 2012` - | `24 AD -> 24` - | `24 BC -> -23` - | `12345 AD -> 12345` - `z` Displays the timezone offset from UTC. | `UTC+7 -> +7` - | `UTC-5 -> -5` - `zz` Same as above but with leading 0. | `UTC+7 -> +07` - | `UTC-5 -> -05` - `zzz` Same as above but with `:mm` where *mm* represents minutes. | `UTC+7 -> +07:00` - | `UTC-5 -> -05:00` - `ZZZ` Same as above but with `mm` where *mm* represents minutes. | `UTC+7 -> +0700` - | `UTC-5 -> -0500` - `zzzz` Same as above but with `:ss` where *ss* represents seconds. | `UTC+7 -> +07:00:00` - | `UTC-5 -> -05:00:00` - `ZZZZ` Same as above but with `ss` where *ss* represents seconds. | `UTC+7 -> +070000` - | `UTC-5 -> -050000` - `g` Era: AD or BC | `300 AD -> AD` - | `300 BC -> BC` - `fff` Milliseconds display | `1000000 nanoseconds -> 1` - `ffffff` Microseconds display | `1000000 nanoseconds -> 1000` - `fffffffff` Nanoseconds display | `1000000 nanoseconds -> 1000000` - =========== ================================================================================= ============================================== + ============= ================================================================================= ================================================ + Pattern Description Example + ============= ================================================================================= ================================================ + ``d`` Numeric value representing the day of the month, | ``1/04/2012 -> 1`` + it will be either one or two digits long. | ``21/04/2012 -> 21`` + ``dd`` Same as above, but is always two digits. | ``1/04/2012 -> 01`` + | ``21/04/2012 -> 21`` + ``ddd`` Three letter string which indicates the day of the week. | ``Saturday -> Sat`` + | ``Monday -> Mon`` + ``dddd`` Full string for the day of the week. | ``Saturday -> Saturday`` + | ``Monday -> Monday`` + ``h`` The hours in one digit if possible. Ranging from 1-12. | ``5pm -> 5`` + | ``2am -> 2`` + ``hh`` The hours in two digits always. If the hour is one digit, 0 is prepended. | ``5pm -> 05`` + | ``11am -> 11`` + ``H`` The hours in one digit if possible, ranging from 0-23. | ``5pm -> 17`` + | ``2am -> 2`` + ``HH`` The hours in two digits always. 0 is prepended if the hour is one digit. | ``5pm -> 17`` + | ``2am -> 02`` + ``m`` The minutes in one digit if possible. | ``5:30 -> 30`` + | ``2:01 -> 1`` + ``mm`` Same as above but always two digits, 0 is prepended if the minute is one digit. | ``5:30 -> 30`` + | ``2:01 -> 01`` + ``M`` The month in one digit if possible. | ``September -> 9`` + | ``December -> 12`` + ``MM`` The month in two digits always. 0 is prepended if the month value is one digit. | ``September -> 09`` + | ``December -> 12`` + ``MMM`` Abbreviated three-letter form of the month. | ``September -> Sep`` + | ``December -> Dec`` + ``MMMM`` Full month string, properly capitalized. | ``September -> September`` + ``s`` Seconds as one digit if possible. | ``00:00:06 -> 6`` + ``ss`` Same as above but always two digits. 0 is prepended if the second is one digit. | ``00:00:06 -> 06`` + ``t`` ``A`` when time is in the AM. ``P`` when time is in the PM. | ``5pm -> P`` + | ``2am -> A`` + ``tt`` Same as above, but ``AM`` and ``PM`` instead of ``A`` and ``P`` respectively. | ``5pm -> PM`` + | ``2am -> AM`` + ``yy`` The last two digits of the year. When parsing, the current century is assumed. | ``2012 AD -> 12`` + ``yyyy`` The year, padded to at least four digits. | ``2012 AD -> 2012`` + Is always positive, even when the year is BC. | ``24 AD -> 0024`` + When the year is more than four digits, '+' is prepended. | ``24 BC -> 00024`` + | ``12345 AD -> +12345`` + ``YYYY`` The year without any padding. | ``2012 AD -> 2012`` + Is always positive, even when the year is BC. | ``24 AD -> 24`` + | ``24 BC -> 24`` + | ``12345 AD -> 12345`` + ``uuuu`` The year, padded to at least four digits. Will be negative when the year is BC. | ``2012 AD -> 2012`` + When the year is more than four digits, '+' is prepended unless the year is BC. | ``24 AD -> 0024`` + | ``24 BC -> -0023`` + | ``12345 AD -> +12345`` + ``UUUU`` The year without any padding. Will be negative when the year is BC. | ``2012 AD -> 2012`` + | ``24 AD -> 24`` + | ``24 BC -> -23`` + | ``12345 AD -> 12345`` + ``z`` Displays the timezone offset from UTC. | ``UTC+7 -> +7`` + | ``UTC-5 -> -5`` + ``zz`` Same as above but with leading 0. | ``UTC+7 -> +07`` + | ``UTC-5 -> -05`` + ``zzz`` Same as above but with ``:mm`` where *mm* represents minutes. | ``UTC+7 -> +07:00`` + | ``UTC-5 -> -05:00`` + ``zzzz`` Same as above but with ``:ss`` where *ss* represents seconds. | ``UTC+7 -> +07:00:00`` + | ``UTC-5 -> -05:00:00`` + ``g`` Era: AD or BC | ``300 AD -> AD`` + | ``300 BC -> BC`` + ``fff`` Milliseconds display | ``1000000 nanoseconds -> 1`` + ``ffffff`` Microseconds display | ``1000000 nanoseconds -> 1000`` + ``fffffffff`` Nanoseconds display | ``1000000 nanoseconds -> 1000000`` + ============= ================================================================================= ================================================ - Other strings can be inserted by putting them in `''`. For example - `hh'->'mm` will give `01->56`. The following characters can be - inserted without quoting them: `:` `-` `(` `)` `/` `[` `]` - `,`. A literal `'` can be specified with `''`. + Other strings can be inserted by putting them in ``''``. For example + ``hh'->'mm`` will give ``01->56``. The following characters can be + inserted without quoting them: ``:`` ``-`` ``(`` ``)`` ``/`` ``[`` ``]`` + ``,``. A literal ``'`` can be specified with ``''``. However you don't need to necessarily separate format patterns, as an - unambiguous format string like `yyyyMMddhhmmss` is also valid (although + unambiguous format string like ``yyyyMMddhhmmss`` is also valid (although only for years in the range 1..9999). Duration vs TimeInterval ============================ - The `times` module exports two similar types that are both used to + The ``times`` module exports two similar types that are both used to represent some amount of time: `Duration <#Duration>`_ and `TimeInterval <#TimeInterval>`_. This section explains how they differ and when one should be preferred over the - other (short answer: use `Duration` unless support for months and years is + other (short answer: use ``Duration`` unless support for months and years is needed). Duration ---------------------------- - A `Duration` represents a duration of time stored as seconds and - nanoseconds. A `Duration` is always fully normalized, so - `initDuration(hours = 1)` and `initDuration(minutes = 60)` are equivalent. + A ``Duration`` represents a duration of time stored as seconds and + nanoseconds. A ``Duration`` is always fully normalized, so +``initDuration(hours = 1)`` and ``initDuration(minutes = 60)`` are equivalent. - Arithmetic with a `Duration` is very fast, especially when used with the - `Time` type, since it only involves basic arithmetic. Because `Duration` + Arithmetic with a ``Duration`` is very fast, especially when used with the + ``Time`` type, since it only involves basic arithmetic. Because ``Duration`` is more performant and easier to understand it should generally preferred. TimeInterval ---------------------------- - A `TimeInterval` represents an amount of time expressed in calendar + A ``TimeInterval`` represents an amount of time expressed in calendar units, for example "1 year and 2 days". Since some units cannot be normalized (the length of a year is different for leap years for example), - the `TimeInterval` type uses separate fields for every unit. The - `TimeInterval`'s returned from this module generally don't normalize + the ``TimeInterval`` type uses separate fields for every unit. The + ``TimeInterval``'s returned from this module generally don't normalize **anything**, so even units that could be normalized (like seconds, milliseconds and so on) are left untouched. - Arithmetic with a `TimeInterval` can be very slow, because it requires + Arithmetic with a ``TimeInterval`` can be very slow, because it requires timezone information. - Since it's slower and more complex, the `TimeInterval` type should be + Since it's slower and more complex, the ``TimeInterval`` type should be avoided unless the program explicitly needs the features it offers that - `Duration` doesn't have. + ``Duration`` doesn't have. How long is a day? ---------------------------- It should be especially noted that the handling of days differs between - `TimeInterval` and `Duration`. The `Duration` type always treats a day - as exactly 86400 seconds. For `TimeInterval`, it's more complex. + ``TimeInterval`` and ``Duration``. The ``Duration`` type always treats a day + as exactly 86400 seconds. For ``TimeInterval``, it's more complex. As an example, consider the amount of time between these two timestamps, both in the same timezone: @@ -186,8 +182,8 @@ timezones that use daylight savings time. Because of this change, the amount of time that has passed is actually 25 hours. - The `TimeInterval` type uses calendar units, and will say that exactly one - day has passed. The `Duration` type on the other hand normalizes everything + The ``TimeInterval`` type uses calendar units, and will say that exactly one + day has passed. The ``Duration`` type on the other hand normalizes everything to seconds, and will therefore say that 90000 seconds has passed, which is the same as 25 hours. @@ -198,13 +194,8 @@ import strutils, math, options -import std/private/since include "system/inclrtl" -when defined(nimPreviewSlimSystem): - import std/assertions - - when defined(js): import jscore @@ -234,6 +225,11 @@ elif defined(posix): type CTime = posix.Time + when not defined(freebsd) and not defined(netbsd) and not defined(openbsd): + var timezone {.importc, header: "".}: int + when not defined(valgrind_workaround_10121): + tzset() + when defined(macosx): proc gettimeofday(tp: var Timeval, unused: pointer = nil) {.importc: "gettimeofday", header: "", sideEffect.} @@ -241,8 +237,12 @@ elif defined(posix): elif defined(windows): import winlean, std/time_t + type CTime = time_t.Time + + # visual c's c runtime exposes these under a different name + var timezone {.importc: "_timezone", header: "".}: int + type - CTime = time_t.Time Tm {.importc: "struct tm", header: "", final, pure.} = object tm_sec*: cint ## Seconds [0,60]. tm_min*: cint ## Minutes [0,59]. @@ -257,9 +257,9 @@ elif defined(windows): proc localtime(a1: var CTime): ptr Tm {.importc, header: "", sideEffect.} type - Month* = enum ## Represents a month. Note that the enum starts at `1`, - ## so `ord(month)` will give the month number in the - ## range `1..12`. + Month* = enum ## Represents a month. Note that the enum starts at ``1``, + ## so ``ord(month)`` will give the month number in the + ## range ``1..12``. mJan = (1, "January") mFeb = "February" mMar = "March" @@ -282,53 +282,78 @@ type dSat = "Saturday" dSun = "Sunday" +when defined(nimHasStyleChecks): + {.push styleChecks: off.} + +type + DateTimeLocale* = object + MMM*: array[mJan..mDec, string] + MMMM*: array[mJan..mDec, string] + ddd*: array[dMon..dSun, string] + dddd*: array[dMon..dSun, string] + +when defined(nimHasStyleChecks): + {.pop.} + type MonthdayRange* = range[1..31] HourRange* = range[0..23] MinuteRange* = range[0..59] - SecondRange* = range[0..60] ## \ - ## Includes the value 60 to allow for a leap second. Note however - ## that the `second` of a `DateTime` will never be a leap second. + SecondRange* = range[0..60] YeardayRange* = range[0..365] NanosecondRange* = range[0..999_999_999] - IsoWeekRange* = range[1 .. 53] - ## An ISO 8601 calendar week number. - IsoYear* = distinct int - ## An ISO 8601 calendar year number. - ## - ## .. warning:: The ISO week-based year can correspond to the following or previous year from 29 December to January 3. - Time* = object ## Represents a point in time. seconds: int64 nanosecond: NanosecondRange DateTime* = object of RootObj ## \ - ## Represents a time in different parts. Although this type can represent - ## leap seconds, they are generally not supported in this module. They are - ## not ignored, but the `DateTime`'s returned by procedures in this - ## module will never have a leap second. - nanosecond: NanosecondRange - second: SecondRange - minute: MinuteRange - hour: HourRange - monthdayZero: int - monthZero: int - year: int - weekday: WeekDay - yearday: YeardayRange - isDst: bool - timezone: Timezone - utcOffset: int + ## Represents a time in different parts. Although this type can represent + ## leap seconds, they are generally not supported in this module. They are + ## not ignored, but the ``DateTime``'s returned by procedures in this + ## module will never have a leap second. + ## + ## **Warning**: even though the fields of ``DateTime`` are exported, + ## they should never be mutated directly. Doing so is unsafe and will + ## result in the ``DateTime`` ending up in an invalid state. + ## + ## Instead of mutating the fields directly, use the `Duration <#Duration>`_ + ## and `TimeInterval <#TimeInterval>`_ types for arithmetic and use the + ## `initDateTime proc <#initDateTime,MonthdayRange,Month,int,HourRange,MinuteRange,SecondRange,NanosecondRange,Timezone>`_ + ## for changing a specific field. + nanosecond*: NanosecondRange ## The number of nanoseconds after the second, + ## in the range 0 to 999_999_999. + second*: SecondRange ## The number of seconds after the minute, + ## normally in the range 0 to 59, but can + ## be up to 60 to allow for a leap second. + minute*: MinuteRange ## The number of minutes after the hour, + ## in the range 0 to 59. + hour*: HourRange ## The number of hours past midnight, + ## in the range 0 to 23. + monthday*: MonthdayRange ## The day of the month, in the range 1 to 31. + month*: Month ## The month. + year*: int ## The year, using astronomical year numbering + ## (meaning that before year 1 is year 0, + ## then year -1 and so on). + weekday*: WeekDay ## The day of the week. + yearday*: YeardayRange ## The number of days since January 1, + ## in the range 0 to 365. + isDst*: bool ## Determines whether DST is in effect. + ## Always false for the JavaScript backend. + timezone*: Timezone ## The timezone represented as an implementation + ## of ``Timezone``. + utcOffset*: int ## The offset in seconds west of UTC, including + ## any offset due to DST. Note that the sign of + ## this number is the opposite of the one in a + ## formatted offset string like ``+01:00`` (which + ## would be equivalent to the UTC offset + ## ``-3600``). Duration* = object ## Represents a fixed duration of time, meaning a duration ## that has constant length independent of the context. ## - ## To create a new `Duration`, use `initDuration + ## To create a new ``Duration``, use `initDuration proc ## <#initDuration,int64,int64,int64,int64,int64,int64,int64,int64>`_. - ## Instead of trying to access the private attributes, use - ## `inSeconds <#inSeconds,Duration>`_ for converting to seconds and - ## `inNanoseconds <#inNanoseconds,Duration>`_ for converting to nanoseconds. seconds: int64 nanosecond: NanosecondRange @@ -337,23 +362,23 @@ type Weeks, Months, Years FixedTimeUnit* = range[Nanoseconds..Weeks] ## \ - ## Subrange of `TimeUnit` that only includes units of fixed duration. - ## These are the units that can be represented by a `Duration`. + ## Subrange of ``TimeUnit`` that only includes units of fixed duration. + ## These are the units that can be represented by a ``Duration``. TimeInterval* = object ## \ ## Represents a non-fixed duration of time. Can be used to add and ## subtract non-fixed time units from a `DateTime <#DateTime>`_ or ## `Time <#Time>`_. ## - ## Create a new `TimeInterval` with `initTimeInterval proc + ## Create a new ``TimeInterval`` with `initTimeInterval proc ## <#initTimeInterval,int,int,int,int,int,int,int,int,int,int>`_. ## - ## Note that `TimeInterval` doesn't represent a fixed duration of time, + ## Note that ``TimeInterval`` doesn't represent a fixed duration of time, ## since the duration of some units depend on the context (e.g a year ## can be either 365 or 366 days long). The non-fixed time units are ## years, months, days and week. ## - ## Note that `TimeInterval`'s returned from the `times` module are + ## Note that ``TimeInterval``'s returned from the ``times`` module are ## never normalized. If you want to normalize a time unit, ## `Duration <#Duration>`_ should be used instead. nanoseconds*: int ## The number of nanoseconds @@ -369,8 +394,8 @@ type Timezone* = ref object ## \ ## Timezone interface for supporting `DateTime <#DateTime>`_\s of arbitrary - ## timezones. The `times` module only supplies implementations for the - ## system's local time and UTC. + ## timezones. The ``times`` module only supplies implementations for the + ## systems local time and UTC. zonedTimeFromTimeImpl: proc (x: Time): ZonedTime {.tags: [], raises: [], benign.} zonedTimeFromAdjTimeImpl: proc (x: Time): ZonedTime @@ -387,6 +412,7 @@ type DurationParts* = array[FixedTimeUnit, int64] # Array of Duration parts starts TimeIntervalParts* = array[TimeUnit, int] # Array of Duration parts starts + TimesMutableTypes = DateTime | Time | Duration | TimeInterval const secondsInMin = 60 @@ -408,21 +434,15 @@ const unitWeights: array[FixedTimeUnit, int64] = [ 7 * secondsInDay * 1e9.int64, ] -when (NimMajor, NimMinor) >= (1, 4): - # Newer versions of Nim don't track defects - {.pragma: parseFormatRaises, raises: [TimeParseError, TimeFormatParseError].} - {.pragma: parseRaises, raises: [TimeParseError].} -else: - # Still track when using older versions - {.pragma: parseFormatRaises, raises: [TimeParseError, TimeFormatParseError, Defect].} - {.pragma: parseRaises, raises: [TimeParseError, Defect].} - - -# -# Helper procs -# - -{.pragma: operator, rtl, noSideEffect, benign.} +const DefaultLocale* = DateTimeLocale( + MMM: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", + "Nov", "Dec"], + MMMM: ["January", "February", "March", "April", "May", "June", "July", + "August", "September", "October", "November", "December"], + ddd: ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"], + dddd: ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", + "Sunday"], +) proc convert*[T: SomeInteger](unitFrom, unitTo: FixedTimeUnit, quantity: T): T {.inline.} = @@ -439,8 +459,8 @@ proc convert*[T: SomeInteger](unitFrom, unitTo: FixedTimeUnit, quantity: T): T proc normalize[T: Duration|Time](seconds, nanoseconds: int64): T = ## Normalize a (seconds, nanoseconds) pair and return it as either - ## a `Duration` or `Time`. A normalized `Duration|Time` has a - ## positive nanosecond part in the range `NanosecondRange`. + ## a ``Duration`` or ``Time``. A normalized ``Duration|Time`` has a + ## positive nanosecond part in the range ``NanosecondRange``. result.seconds = seconds + convert(Nanoseconds, Seconds, nanoseconds) var nanosecond = nanoseconds mod convert(Seconds, Nanoseconds, 1) if nanosecond < 0: @@ -448,15 +468,177 @@ proc normalize[T: Duration|Time](seconds, nanoseconds: int64): T = result.seconds -= 1 result.nanosecond = nanosecond.int +# Forward declarations +proc utcTzInfo(time: Time): ZonedTime + {.tags: [], raises: [], benign.} +proc localZonedTimeFromTime(time: Time): ZonedTime + {.tags: [], raises: [], benign.} +proc localZonedTimeFromAdjTime(adjTime: Time): ZonedTime + {.tags: [], raises: [], benign.} +proc initTime*(unix: int64, nanosecond: NanosecondRange): Time + {.tags: [], raises: [], benign, noSideEffect.} + +proc nanosecond*(time: Time): NanosecondRange = + ## Get the fractional part of a ``Time`` as the number + ## of nanoseconds of the second. + time.nanosecond + +proc initDuration*(nanoseconds, microseconds, milliseconds, + seconds, minutes, hours, days, weeks: int64 = 0): Duration = + ## Create a new `Duration <#Duration>`_. + runnableExamples: + let dur = initDuration(seconds = 1, milliseconds = 1) + doAssert dur.milliseconds == 1 + doAssert dur.seconds == 1 + + let seconds = convert(Weeks, Seconds, weeks) + + convert(Days, Seconds, days) + + convert(Minutes, Seconds, minutes) + + convert(Hours, Seconds, hours) + + convert(Seconds, Seconds, seconds) + + convert(Milliseconds, Seconds, milliseconds) + + convert(Microseconds, Seconds, microseconds) + + convert(Nanoseconds, Seconds, nanoseconds) + let nanoseconds = (convert(Milliseconds, Nanoseconds, milliseconds mod 1000) + + convert(Microseconds, Nanoseconds, microseconds mod 1_000_000) + + nanoseconds mod 1_000_000_000).int + # Nanoseconds might be negative so we must normalize. + result = normalize[Duration](seconds, nanoseconds) + +template convert(dur: Duration, unit: static[FixedTimeUnit]): int64 = + # The correction is required due to how durations are normalized. + # For example,` initDuration(nanoseconds = -1)` is stored as + # { seconds = -1, nanoseconds = 999999999 }. + when unit == Nanoseconds: + dur.seconds * 1_000_000_000 + dur.nanosecond + else: + let correction = dur.seconds < 0 and dur.nanosecond > 0 + when unit >= Seconds: + convert(Seconds, unit, dur.seconds + ord(correction)) + else: + if correction: + convert(Seconds, unit, dur.seconds + 1) - + convert(Nanoseconds, unit, + convert(Seconds, Nanoseconds, 1) - dur.nanosecond) + else: + convert(Seconds, unit, dur.seconds) + + convert(Nanoseconds, unit, dur.nanosecond) + +proc inWeeks*(dur: Duration): int64 = + ## Convert the duration to the number of whole weeks. + runnableExamples: + let dur = initDuration(days = 8) + doAssert dur.inWeeks == 1 + dur.convert(Weeks) + +proc inDays*(dur: Duration): int64 = + ## Convert the duration to the number of whole days. + runnableExamples: + let dur = initDuration(hours = -50) + doAssert dur.inDays == -2 + dur.convert(Days) + +proc inHours*(dur: Duration): int64 = + ## Convert the duration to the number of whole hours. + runnableExamples: + let dur = initDuration(minutes = 60, days = 2) + doAssert dur.inHours == 49 + dur.convert(Hours) + +proc inMinutes*(dur: Duration): int64 = + ## Convert the duration to the number of whole minutes. + runnableExamples: + let dur = initDuration(hours = 2, seconds = 10) + doAssert dur.inMinutes == 120 + dur.convert(Minutes) + +proc inSeconds*(dur: Duration): int64 = + ## Convert the duration to the number of whole seconds. + runnableExamples: + let dur = initDuration(hours = 2, milliseconds = 10) + doAssert dur.inSeconds == 2 * 60 * 60 + dur.convert(Seconds) + +proc inMilliseconds*(dur: Duration): int64 = + ## Convert the duration to the number of whole milliseconds. + runnableExamples: + let dur = initDuration(seconds = -2) + doAssert dur.inMilliseconds == -2000 + dur.convert(Milliseconds) + +proc inMicroseconds*(dur: Duration): int64 = + ## Convert the duration to the number of whole microseconds. + runnableExamples: + let dur = initDuration(seconds = -2) + doAssert dur.inMicroseconds == -2000000 + dur.convert(Microseconds) + +proc inNanoseconds*(dur: Duration): int64 = + ## Convert the duration to the number of whole nanoseconds. + runnableExamples: + let dur = initDuration(seconds = -2) + doAssert dur.inNanoseconds == -2000000000 + dur.convert(Nanoseconds) + +proc fromUnix*(unix: int64): Time + {.benign, tags: [], raises: [], noSideEffect.} = + ## Convert a unix timestamp (seconds since ``1970-01-01T00:00:00Z``) + ## to a ``Time``. + runnableExamples: + doAssert $fromUnix(0).utc == "1970-01-01T00:00:00Z" + initTime(unix, 0) + +proc toUnix*(t: Time): int64 {.benign, tags: [], raises: [], noSideEffect.} = + ## Convert ``t`` to a unix timestamp (seconds since ``1970-01-01T00:00:00Z``). + ## See also `toUnixFloat` for subsecond resolution. + runnableExamples: + doAssert fromUnix(0).toUnix() == 0 + t.seconds + +proc fromUnixFloat(seconds: float): Time {.benign, tags: [], raises: [], noSideEffect.} = + ## Convert a unix timestamp in seconds to a `Time`; same as `fromUnix` + ## but with subsecond resolution. + runnableExamples: + doAssert fromUnixFloat(123456.0) == fromUnixFloat(123456) + doAssert fromUnixFloat(-123456.0) == fromUnixFloat(-123456) + let secs = seconds.floor + let nsecs = (seconds - secs) * 1e9 + initTime(secs.int64, nsecs.NanosecondRange) + +proc toUnixFloat(t: Time): float {.benign, tags: [], raises: [].} = + ## Same as `toUnix` but using subsecond resolution. + runnableExamples: + let t = getTime() + # `<` because of rounding errors + doAssert abs(t.toUnixFloat().fromUnixFloat - t) < initDuration(nanoseconds = 1000) + t.seconds.float + t.nanosecond / convert(Seconds, Nanoseconds, 1) + +since((1, 1)): + export fromUnixFloat + export toUnixFloat + +proc fromWinTime*(win: int64): Time = + ## Convert a Windows file time (100-nanosecond intervals since + ## ``1601-01-01T00:00:00Z``) to a ``Time``. + const hnsecsPerSec = convert(Seconds, Nanoseconds, 1) div 100 + let nanos = floorMod(win, hnsecsPerSec) * 100 + let seconds = floorDiv(win - epochDiff, hnsecsPerSec) + result = initTime(seconds, nanos) + +proc toWinTime*(t: Time): int64 = + ## Convert ``t`` to a Windows file time (100-nanosecond intervals + ## since ``1601-01-01T00:00:00Z``). + result = t.seconds * rateDiff + epochDiff + t.nanosecond div 100 + proc isLeapYear*(year: int): bool = - ## Returns true if `year` is a leap year. + ## Returns true if ``year`` is a leap year. runnableExamples: doAssert isLeapYear(2000) doAssert not isLeapYear(1900) year mod 4 == 0 and (year mod 100 != 0 or year mod 400 == 0) proc getDaysInMonth*(month: Month, year: int): int = - ## Get the number of days in `month` of `year`. + ## Get the number of days in ``month`` of ``year``. # http://www.dispersiondesign.com/articles/time/number_of_days_in_a_month runnableExamples: doAssert getDaysInMonth(mFeb, 2000) == 29 @@ -466,6 +648,13 @@ proc getDaysInMonth*(month: Month, year: int): int = of mApr, mJun, mSep, mNov: result = 30 else: result = 31 +proc getDaysInYear*(year: int): int = + ## Get the number of days in a ``year`` + runnableExamples: + doAssert getDaysInYear(2000) == 366 + doAssert getDaysInYear(2001) == 365 + result = 365 + (if isLeapYear(year): 1 else: 0) + proc assertValidDate(monthday: MonthdayRange, month: Month, year: int) {.inline.} = assert monthday <= getDaysInMonth(month, year), @@ -509,7 +698,7 @@ proc fromEpochDay(epochday: int64): proc getDayOfYear*(monthday: MonthdayRange, month: Month, year: int): YeardayRange {.tags: [], raises: [], benign.} = ## Returns the day of the year. - ## Equivalent with `dateTime(year, month, monthday, 0, 0, 0, 0).yearday`. + ## Equivalent with ``initDateTime(monthday, month, year, 0, 0, 0).yearday``. runnableExamples: doAssert getDayOfYear(1, mJan, 2000) == 0 doAssert getDayOfYear(10, mJan, 2000) == 9 @@ -529,7 +718,7 @@ proc getDayOfYear*(monthday: MonthdayRange, month: Month, year: int): proc getDayOfWeek*(monthday: MonthdayRange, month: Month, year: int): WeekDay {.tags: [], raises: [], benign.} = ## Returns the day of the week enum from day, month and year. - ## Equivalent with `dateTime(year, month, monthday, 0, 0, 0, 0).weekday`. + ## Equivalent with ``initDateTime(monthday, month, year, 0, 0, 0).weekday``. runnableExamples: doAssert getDayOfWeek(13, mJun, 1990) == dWed doAssert $getDayOfWeek(13, mJun, 1990) == "Wednesday" @@ -543,85 +732,7 @@ proc getDayOfWeek*(monthday: MonthdayRange, month: Month, year: int): WeekDay # so we must correct for the WeekDay type. result = if wd == 0: dSun else: WeekDay(wd - 1) -proc getDaysInYear*(year: int): int = - ## Get the number of days in a `year` - runnableExamples: - doAssert getDaysInYear(2000) == 366 - doAssert getDaysInYear(2001) == 365 - result = 365 + (if isLeapYear(year): 1 else: 0) - -proc `==`*(a, b: IsoYear): bool {.borrow.} -proc `$`*(p: IsoYear): string {.borrow.} - -proc getWeeksInIsoYear*(y: IsoYear): IsoWeekRange {.since: (1, 5).} = - ## Returns the number of weeks in the specified ISO 8601 week-based year, which can be - ## either 53 or 52. - runnableExamples: - assert getWeeksInIsoYear(IsoYear(2019)) == 52 - assert getWeeksInIsoYear(IsoYear(2020)) == 53 - - var y = int(y) - - # support negative years - y = if y < 0: 400 + y mod 400 else: y - - # source: https://webspace.science.uu.nl/~gent0113/calendar/isocalendar.htm - let p = (y + (y div 4) - (y div 100) + (y div 400)) mod 7 - let y1 = y - 1 - let p1 = (y1 + (y1 div 4) - (y1 div 100) + (y1 div 400)) mod 7 - if p == 4 or p1 == 3: 53 else: 52 - -proc getIsoWeekAndYear*(dt: DateTime): - tuple[isoweek: IsoWeekRange, isoyear: IsoYear] {.since: (1, 5).} = - ## Returns the ISO 8601 week and year. - ## - ## .. warning:: The ISO week-based year can correspond to the following or previous year from 29 December to January 3. - runnableExamples: - assert getIsoWeekAndYear(initDateTime(21, mApr, 2018, 00, 00, 00)) == (isoweek: 16.IsoWeekRange, isoyear: 2018.IsoYear) - block: - let (w, y) = getIsoWeekAndYear(initDateTime(30, mDec, 2019, 00, 00, 00)) - assert w == 01.IsoWeekRange - assert y == 2020.IsoYear - assert getIsoWeekAndYear(initDateTime(13, mSep, 2020, 00, 00, 00)) == (isoweek: 37.IsoWeekRange, isoyear: 2020.IsoYear) - block: - let (w, y) = getIsoWeekAndYear(initDateTime(2, mJan, 2021, 00, 00, 00)) - assert w.int > 52 - assert w.int < 54 - assert y.int mod 100 == 20 - - # source: https://webspace.science.uu.nl/~gent0113/calendar/isocalendar.htm - var w = (dt.yearday.int - dt.weekday.int + 10) div 7 - if w < 1: - (isoweek: getWeeksInIsoYear(IsoYear(dt.year - 1)), isoyear: IsoYear(dt.year - 1)) - elif (w > getWeeksInIsoYear(IsoYear(dt.year))): - (isoweek: IsoWeekRange(1), isoyear: IsoYear(dt.year + 1)) - else: - (isoweek: IsoWeekRange(w), isoyear: IsoYear(dt.year)) - -proc stringifyUnit(value: int | int64, unit: TimeUnit): string = - ## Stringify time unit with it's name, lowercased - let strUnit = $unit - result = "" - result.add($value) - result.add(" ") - if abs(value) != 1: - result.add(strUnit.toLowerAscii()) - else: - result.add(strUnit[0..^2].toLowerAscii()) - -proc humanizeParts(parts: seq[string]): string = - ## Make date string parts human-readable - result = "" - if parts.len == 0: - result.add "0 nanoseconds" - elif parts.len == 1: - result = parts[0] - elif parts.len == 2: - result = parts[0] & " and " & parts[1] - else: - for i in 0..high(parts)-1: - result.add parts[i] & ", " - result.add "and " & parts[high(parts)] +{.pragma: operator, rtl, noSideEffect, benign.} template subImpl[T: Duration|Time](a: Duration|Time, b: Duration|Time): T = normalize[T](a.seconds - b.seconds, a.nanosecond - b.nanosecond) @@ -639,12 +750,7 @@ template lqImpl(a: Duration|Time, b: Duration|Time): bool = template eqImpl(a: Duration|Time, b: Duration|Time): bool = a.seconds == b.seconds and a.nanosecond == b.nanosecond - -# -# Duration -# - -const DurationZero* = Duration() ## \ +const DurationZero* = initDuration() ## \ ## Zero value for durations. Useful for comparisons. ## ## .. code-block:: nim @@ -652,110 +758,13 @@ const DurationZero* = Duration() ## \ ## doAssert initDuration(seconds = 1) > DurationZero ## doAssert initDuration(seconds = 0) == DurationZero -proc initDuration*(nanoseconds, microseconds, milliseconds, - seconds, minutes, hours, days, weeks: int64 = 0): Duration = - ## Create a new `Duration <#Duration>`_. - runnableExamples: - let dur = initDuration(seconds = 1, milliseconds = 1) - doAssert dur.inMilliseconds == 1001 - doAssert dur.inSeconds == 1 - - let seconds = convert(Weeks, Seconds, weeks) + - convert(Days, Seconds, days) + - convert(Minutes, Seconds, minutes) + - convert(Hours, Seconds, hours) + - convert(Seconds, Seconds, seconds) + - convert(Milliseconds, Seconds, milliseconds) + - convert(Microseconds, Seconds, microseconds) + - convert(Nanoseconds, Seconds, nanoseconds) - let nanoseconds = (convert(Milliseconds, Nanoseconds, milliseconds mod 1000) + - convert(Microseconds, Nanoseconds, microseconds mod 1_000_000) + - nanoseconds mod 1_000_000_000).int - # Nanoseconds might be negative so we must normalize. - result = normalize[Duration](seconds, nanoseconds) - -template convert(dur: Duration, unit: static[FixedTimeUnit]): int64 = - # The correction is required due to how durations are normalized. - # For example,` initDuration(nanoseconds = -1)` is stored as - # { seconds = -1, nanoseconds = 999999999 }. - when unit == Nanoseconds: - dur.seconds * 1_000_000_000 + dur.nanosecond - else: - let correction = dur.seconds < 0 and dur.nanosecond > 0 - when unit >= Seconds: - convert(Seconds, unit, dur.seconds + ord(correction)) - else: - if correction: - convert(Seconds, unit, dur.seconds + 1) - - convert(Nanoseconds, unit, - convert(Seconds, Nanoseconds, 1) - dur.nanosecond) - else: - convert(Seconds, unit, dur.seconds) + - convert(Nanoseconds, unit, dur.nanosecond) - -proc inWeeks*(dur: Duration): int64 = - ## Converts the duration to the number of whole weeks. - runnableExamples: - let dur = initDuration(days = 8) - doAssert dur.inWeeks == 1 - dur.convert(Weeks) - -proc inDays*(dur: Duration): int64 = - ## Converts the duration to the number of whole days. - runnableExamples: - let dur = initDuration(hours = -50) - doAssert dur.inDays == -2 - dur.convert(Days) - -proc inHours*(dur: Duration): int64 = - ## Converts the duration to the number of whole hours. - runnableExamples: - let dur = initDuration(minutes = 60, days = 2) - doAssert dur.inHours == 49 - dur.convert(Hours) - -proc inMinutes*(dur: Duration): int64 = - ## Converts the duration to the number of whole minutes. - runnableExamples: - let dur = initDuration(hours = 2, seconds = 10) - doAssert dur.inMinutes == 120 - dur.convert(Minutes) - -proc inSeconds*(dur: Duration): int64 = - ## Converts the duration to the number of whole seconds. - runnableExamples: - let dur = initDuration(hours = 2, milliseconds = 10) - doAssert dur.inSeconds == 2 * 60 * 60 - dur.convert(Seconds) - -proc inMilliseconds*(dur: Duration): int64 = - ## Converts the duration to the number of whole milliseconds. - runnableExamples: - let dur = initDuration(seconds = -2) - doAssert dur.inMilliseconds == -2000 - dur.convert(Milliseconds) - -proc inMicroseconds*(dur: Duration): int64 = - ## Converts the duration to the number of whole microseconds. - runnableExamples: - let dur = initDuration(seconds = -2) - doAssert dur.inMicroseconds == -2000000 - dur.convert(Microseconds) - -proc inNanoseconds*(dur: Duration): int64 = - ## Converts the duration to the number of whole nanoseconds. - runnableExamples: - let dur = initDuration(seconds = -2) - doAssert dur.inNanoseconds == -2000000000 - dur.convert(Nanoseconds) - proc toParts*(dur: Duration): DurationParts = ## Converts a duration into an array consisting of fixed time units. ## ## Each value in the array gives information about a specific unit of - ## time, for example `result[Days]` gives a count of days. + ## time, for example ``result[Days]`` gives a count of days. ## - ## This procedure is useful for converting `Duration` values to strings. + ## This procedure is useful for converting ``Duration`` values to strings. runnableExamples: var dp = toParts(initDuration(weeks = 2, days = 1)) doAssert dp[Days] == 1 @@ -784,8 +793,33 @@ proc toParts*(dur: Duration): DurationParts = result[unit] = quantity +proc stringifyUnit(value: int | int64, unit: TimeUnit): string = + ## Stringify time unit with it's name, lowercased + let strUnit = $unit + result = "" + result.add($value) + result.add(" ") + if abs(value) != 1: + result.add(strUnit.toLowerAscii()) + else: + result.add(strUnit[0..^2].toLowerAscii()) + +proc humanizeParts(parts: seq[string]): string = + ## Make date string parts human-readable + result = "" + if parts.len == 0: + result.add "0 nanoseconds" + elif parts.len == 1: + result = parts[0] + elif parts.len == 2: + result = parts[0] & " and " & parts[1] + else: + for i in 0..high(parts)-1: + result.add parts[i] & ", " + result.add "and " & parts[high(parts)] + proc `$`*(dur: Duration): string = - ## Human friendly string representation of a `Duration`. + ## Human friendly string representation of a ``Duration``. runnableExamples: doAssert $initDuration(seconds = 2) == "2 seconds" doAssert $initDuration(weeks = 1, days = 2) == "1 week and 2 days" @@ -825,9 +859,9 @@ proc `-`*(a: Duration): Duration {.operator, extern: "ntReverseDuration".} = proc `<`*(a, b: Duration): bool {.operator, extern: "ntLtDuration".} = ## Note that a duration can be negative, - ## so even if `a < b` is true `a` might + ## so even if ``a < b`` is true ``a`` might ## represent a larger absolute duration. - ## Use `abs(a) < abs(b)` to compare the absolute + ## Use ``abs(a) < abs(b)`` to compare the absolute ## duration. runnableExamples: doAssert initDuration(seconds = 1) < initDuration(seconds = 2) @@ -862,15 +896,6 @@ proc `*`*(a: Duration, b: int64): Duration {.operator, doAssert initDuration(minutes = 45) * 3 == initDuration(hours = 2, minutes = 15) b * a -proc `+=`*(d1: var Duration, d2: Duration) = - d1 = d1 + d2 - -proc `-=`*(dt: var Duration, ti: Duration) = - dt = dt - ti - -proc `*=`*(a: var Duration, b: int) = - a = a * b - proc `div`*(a: Duration, b: int64): Duration {.operator, extern: "ntDivDuration".} = ## Integer division for durations. @@ -884,6 +909,50 @@ proc `div`*(a: Duration, b: int64): Duration {.operator, let carryOver = convert(Seconds, Nanoseconds, a.seconds mod b) normalize[Duration](a.seconds div b, (a.nanosecond + carryOver) div b) +proc initTime*(unix: int64, nanosecond: NanosecondRange): Time = + ## Create a `Time <#Time>`_ from a unix timestamp and a nanosecond part. + result.seconds = unix + result.nanosecond = nanosecond + +proc `-`*(a, b: Time): Duration {.operator, extern: "ntDiffTime".} = + ## Computes the duration between two points in time. + runnableExamples: + doAssert initTime(1000, 100) - initTime(500, 20) == + initDuration(minutes = 8, seconds = 20, nanoseconds = 80) + subImpl[Duration](a, b) + +proc `+`*(a: Time, b: Duration): Time {.operator, extern: "ntAddTime".} = + ## Add a duration of time to a ``Time``. + runnableExamples: + doAssert (fromUnix(0) + initDuration(seconds = 1)) == fromUnix(1) + addImpl[Time](a, b) + +proc `-`*(a: Time, b: Duration): Time {.operator, extern: "ntSubTime".} = + ## Subtracts a duration of time from a ``Time``. + runnableExamples: + doAssert (fromUnix(0) - initDuration(seconds = 1)) == fromUnix(-1) + subImpl[Time](a, b) + +proc `<`*(a, b: Time): bool {.operator, extern: "ntLtTime".} = + ## Returns true if ``a < b``, that is if ``a`` happened before ``b``. + runnableExamples: + doAssert initTime(50, 0) < initTime(99, 0) + ltImpl(a, b) + +proc `<=`*(a, b: Time): bool {.operator, extern: "ntLeTime".} = + ## Returns true if ``a <= b``. + lqImpl(a, b) + +proc `==`*(a, b: Time): bool {.operator, extern: "ntEqTime".} = + ## Returns true if ``a == b``, that is if both times represent the same point in time. + eqImpl(a, b) + +proc high*(typ: typedesc[Time]): Time = + initTime(high(int64), high(NanosecondRange)) + +proc low*(typ: typedesc[Time]): Time = + initTime(low(int64), 0) + proc high*(typ: typedesc[Duration]): Duration = ## Get the longest representable duration. initDuration(seconds = high(int64), nanoseconds = high(NanosecondRange)) @@ -898,256 +967,8 @@ proc abs*(a: Duration): Duration = initDuration(milliseconds = 1500) initDuration(seconds = abs(a.seconds), nanoseconds = -a.nanosecond) -# -# Time -# - -proc initTime*(unix: int64, nanosecond: NanosecondRange): Time = - ## Create a `Time <#Time>`_ from a unix timestamp and a nanosecond part. - result.seconds = unix - result.nanosecond = nanosecond - -proc nanosecond*(time: Time): NanosecondRange = - ## Get the fractional part of a `Time` as the number - ## of nanoseconds of the second. - time.nanosecond - -proc fromUnix*(unix: int64): Time - {.benign, tags: [], raises: [], noSideEffect.} = - ## Convert a unix timestamp (seconds since `1970-01-01T00:00:00Z`) - ## to a `Time`. - runnableExamples: - doAssert $fromUnix(0).utc == "1970-01-01T00:00:00Z" - initTime(unix, 0) - -proc toUnix*(t: Time): int64 {.benign, tags: [], raises: [], noSideEffect.} = - ## Convert `t` to a unix timestamp (seconds since `1970-01-01T00:00:00Z`). - ## See also `toUnixFloat` for subsecond resolution. - runnableExamples: - doAssert fromUnix(0).toUnix() == 0 - t.seconds - -proc fromUnixFloat(seconds: float): Time {.benign, tags: [], raises: [], noSideEffect.} = - ## Convert a unix timestamp in seconds to a `Time`; same as `fromUnix` - ## but with subsecond resolution. - runnableExamples: - doAssert fromUnixFloat(123456.0) == fromUnixFloat(123456) - doAssert fromUnixFloat(-123456.0) == fromUnixFloat(-123456) - let secs = seconds.floor - let nsecs = (seconds - secs) * 1e9 - initTime(secs.int64, nsecs.NanosecondRange) - -proc toUnixFloat(t: Time): float {.benign, tags: [], raises: [].} = - ## Same as `toUnix` but using subsecond resolution. - runnableExamples: - let t = getTime() - # `<` because of rounding errors - doAssert abs(t.toUnixFloat().fromUnixFloat - t) < initDuration(nanoseconds = 1000) - t.seconds.float + t.nanosecond / convert(Seconds, Nanoseconds, 1) - -since((1, 1)): - export fromUnixFloat - export toUnixFloat - - -proc fromWinTime*(win: int64): Time = - ## Convert a Windows file time (100-nanosecond intervals since - ## `1601-01-01T00:00:00Z`) to a `Time`. - const hnsecsPerSec = convert(Seconds, Nanoseconds, 1) div 100 - let nanos = floorMod(win, hnsecsPerSec) * 100 - let seconds = floorDiv(win - epochDiff, hnsecsPerSec) - result = initTime(seconds, nanos) - -proc toWinTime*(t: Time): int64 = - ## Convert `t` to a Windows file time (100-nanosecond intervals - ## since `1601-01-01T00:00:00Z`). - result = t.seconds * rateDiff + epochDiff + t.nanosecond div 100 - -proc getTimeImpl(typ: typedesc[Time]): Time = - discard "implemented in the vm" - -proc getTime*(): Time {.tags: [TimeEffect], benign.} = - ## Gets the current time as a `Time` with up to nanosecond resolution. - when nimvm: - result = getTimeImpl(Time) - else: - when defined(js): - let millis = newDate().getTime() - let seconds = convert(Milliseconds, Seconds, millis) - let nanos = convert(Milliseconds, Nanoseconds, - millis mod convert(Seconds, Milliseconds, 1).int) - result = initTime(seconds, nanos) - elif defined(macosx): - var a {.noinit.}: Timeval - gettimeofday(a) - result = initTime(a.tv_sec.int64, - convert(Microseconds, Nanoseconds, a.tv_usec.int)) - elif defined(posix): - var ts {.noinit.}: Timespec - discard clock_gettime(CLOCK_REALTIME, ts) - result = initTime(ts.tv_sec.int64, ts.tv_nsec.int) - elif defined(windows): - var f {.noinit.}: FILETIME - getSystemTimeAsFileTime(f) - result = fromWinTime(rdFileTime(f)) - -proc `-`*(a, b: Time): Duration {.operator, extern: "ntDiffTime".} = - ## Computes the duration between two points in time. - runnableExamples: - doAssert initTime(1000, 100) - initTime(500, 20) == - initDuration(minutes = 8, seconds = 20, nanoseconds = 80) - subImpl[Duration](a, b) - -proc `+`*(a: Time, b: Duration): Time {.operator, extern: "ntAddTime".} = - ## Add a duration of time to a `Time`. - runnableExamples: - doAssert (fromUnix(0) + initDuration(seconds = 1)) == fromUnix(1) - addImpl[Time](a, b) - -proc `-`*(a: Time, b: Duration): Time {.operator, extern: "ntSubTime".} = - ## Subtracts a duration of time from a `Time`. - runnableExamples: - doAssert (fromUnix(0) - initDuration(seconds = 1)) == fromUnix(-1) - subImpl[Time](a, b) - -proc `<`*(a, b: Time): bool {.operator, extern: "ntLtTime".} = - ## Returns true if `a < b`, that is if `a` happened before `b`. - runnableExamples: - doAssert initTime(50, 0) < initTime(99, 0) - ltImpl(a, b) - -proc `<=`*(a, b: Time): bool {.operator, extern: "ntLeTime".} = - ## Returns true if `a <= b`. - lqImpl(a, b) - -proc `==`*(a, b: Time): bool {.operator, extern: "ntEqTime".} = - ## Returns true if `a == b`, that is if both times represent the same point in time. - eqImpl(a, b) - -proc `+=`*(t: var Time, b: Duration) = - t = t + b - -proc `-=`*(t: var Time, b: Duration) = - t = t - b - -proc high*(typ: typedesc[Time]): Time = - initTime(high(int64), high(NanosecondRange)) - -proc low*(typ: typedesc[Time]): Time = - initTime(0, 0) - -# -# DateTime & Timezone -# - -template assertDateTimeInitialized(dt: DateTime) = - assert dt.monthdayZero != 0, "Uninitialized datetime" - -proc nanosecond*(dt: DateTime): NanosecondRange {.inline.} = - ## The number of nanoseconds after the second, - ## in the range 0 to 999_999_999. - assertDateTimeInitialized(dt) - dt.nanosecond - -proc second*(dt: DateTime): SecondRange {.inline.} = - ## The number of seconds after the minute, - ## in the range 0 to 59. - assertDateTimeInitialized(dt) - dt.second - -proc minute*(dt: DateTime): MinuteRange {.inline.} = - ## The number of minutes after the hour, - ## in the range 0 to 59. - assertDateTimeInitialized(dt) - dt.minute - -proc hour*(dt: DateTime): HourRange {.inline.} = - ## The number of hours past midnight, - ## in the range 0 to 23. - assertDateTimeInitialized(dt) - dt.hour - -proc monthday*(dt: DateTime): MonthdayRange {.inline.} = - ## The day of the month, in the range 1 to 31. - assertDateTimeInitialized(dt) - # 'cast' to avoid extra range check - cast[MonthdayRange](dt.monthdayZero) - -proc month*(dt: DateTime): Month = - ## The month as an enum, the ordinal value - ## is in the range 1 to 12. - assertDateTimeInitialized(dt) - # 'cast' to avoid extra range check - cast[Month](dt.monthZero) - -proc year*(dt: DateTime): int {.inline.} = - ## The year, using astronomical year numbering - ## (meaning that before year 1 is year 0, - ## then year -1 and so on). - assertDateTimeInitialized(dt) - dt.year - -proc weekday*(dt: DateTime): WeekDay {.inline.} = - ## The day of the week as an enum, the ordinal - ## value is in the range 0 (monday) to 6 (sunday). - assertDateTimeInitialized(dt) - dt.weekday - -proc yearday*(dt: DateTime): YeardayRange {.inline.} = - ## The number of days since January 1, - ## in the range 0 to 365. - assertDateTimeInitialized(dt) - dt.yearday - -proc isDst*(dt: DateTime): bool {.inline.} = - ## Determines whether DST is in effect. - ## Always false for the JavaScript backend. - assertDateTimeInitialized(dt) - dt.isDst - -proc timezone*(dt: DateTime): Timezone {.inline.} = - ## The timezone represented as an implementation - ## of `Timezone`. - assertDateTimeInitialized(dt) - dt.timezone - -proc utcOffset*(dt: DateTime): int {.inline.} = - ## The offset in seconds west of UTC, including - ## any offset due to DST. Note that the sign of - ## this number is the opposite of the one in a - ## formatted offset string like `+01:00` (which - ## would be equivalent to the UTC offset - ## `-3600`). - assertDateTimeInitialized(dt) - dt.utcOffset - -proc isInitialized(dt: DateTime): bool = - # Returns true if `dt` is not the (invalid) default value for `DateTime`. - runnableExamples: - doAssert now().isInitialized - doAssert not default(DateTime).isInitialized - dt.monthZero != 0 - -since((1, 3)): - export isInitialized - -proc isLeapDay*(dt: DateTime): bool {.since: (1, 1).} = - ## Returns whether `t` is a leap day, i.e. Feb 29 in a leap year. This matters - ## as it affects time offset calculations. - runnableExamples: - let dt = dateTime(2020, mFeb, 29, 00, 00, 00, 00, utc()) - doAssert dt.isLeapDay - doAssert dt+1.years-1.years != dt - let dt2 = dateTime(2020, mFeb, 28, 00, 00, 00, 00, utc()) - doAssert not dt2.isLeapDay - doAssert dt2+1.years-1.years == dt2 - doAssertRaises(Exception): discard dateTime(2021, mFeb, 29, 00, 00, 00, 00, utc()) - assertDateTimeInitialized dt - dt.year.isLeapYear and dt.month == mFeb and dt.monthday == 29 - proc toTime*(dt: DateTime): Time {.tags: [], raises: [], benign.} = - ## Converts a `DateTime` to a `Time` representing the same point in time. - assertDateTimeInitialized dt + ## Converts a ``DateTime`` to a ``Time`` representing the same point in time. let epochDay = toEpochDay(dt.monthday, dt.month, dt.year) var seconds = epochDay * secondsInDay seconds.inc dt.hour * secondsInHour @@ -1157,7 +978,7 @@ proc toTime*(dt: DateTime): Time {.tags: [], raises: [], benign.} = result = initTime(seconds, dt.nanosecond) proc initDateTime(zt: ZonedTime, zone: Timezone): DateTime = - ## Create a new `DateTime` using `ZonedTime` in the specified timezone. + ## Create a new ``DateTime`` using ``ZonedTime`` in the specified timezone. let adjTime = zt.time - initDuration(seconds = zt.utcOffset) let s = adjTime.seconds let epochday = floorDiv(s, secondsInDay) @@ -1172,8 +993,8 @@ proc initDateTime(zt: ZonedTime, zone: Timezone): DateTime = DateTime( year: y, - monthZero: m.int, - monthdayZero: d, + month: m, + monthday: d, hour: hour, minute: minute, second: second, @@ -1192,11 +1013,11 @@ proc newTimezone*( zonedTimeFromAdjTimeImpl: proc (adjTime: Time): ZonedTime {.tags: [], raises: [], benign.} ): owned Timezone = - ## Create a new `Timezone`. + ## Create a new ``Timezone``. ## - ## `zonedTimeFromTimeImpl` and `zonedTimeFromAdjTimeImpl` is used - ## as the underlying implementations for `zonedTimeFromTime` and - ## `zonedTimeFromAdjTime`. + ## ``zonedTimeFromTimeImpl`` and ``zonedTimeFromAdjTimeImpl`` is used + ## as the underlying implementations for ``zonedTimeFromTime`` and + ## ``zonedTimeFromAdjTime``. ## ## If possible, the name parameter should match the name used in the ## tz database. If the timezone doesn't exist in the tz database, or if the @@ -1220,48 +1041,48 @@ proc name*(zone: Timezone): string = ## If the timezone doesn't exist in the tz database, or if the timezone ## name is unknown, then any string that describes the timezone ## unambiguously might be used. For example, the string "LOCAL" is used - ## for the system's local timezone. + ## for the systems local timezone. ## ## See also: https://en.wikipedia.org/wiki/Tz_database zone.name proc zonedTimeFromTime*(zone: Timezone, time: Time): ZonedTime = - ## Returns the `ZonedTime` for some point in time. + ## Returns the ``ZonedTime`` for some point in time. zone.zonedTimeFromTimeImpl(time) proc zonedTimeFromAdjTime*(zone: Timezone, adjTime: Time): ZonedTime = - ## Returns the `ZonedTime` for some local time. + ## Returns the ``ZonedTime`` for some local time. ## - ## Note that the `Time` argument does not represent a point in time, it - ## represent a local time! E.g if `adjTime` is `fromUnix(0)`, it should be - ## interpreted as 1970-01-01T00:00:00 in the `zone` timezone, not in UTC. + ## Note that the ``Time`` argument does not represent a point in time, it + ## represent a local time! E.g if ``adjTime`` is ``fromUnix(0)``, it should be + ## interpreted as 1970-01-01T00:00:00 in the ``zone`` timezone, not in UTC. zone.zonedTimeFromAdjTimeImpl(adjTime) proc `$`*(zone: Timezone): string = ## Returns the name of the timezone. - if zone != nil: result = zone.name + zone.name proc `==`*(zone1, zone2: Timezone): bool = - ## Two `Timezone`'s are considered equal if their name is equal. - runnableExamples: - doAssert local() == local() - doAssert local() != utc() + ## Two ``Timezone``'s are considered equal if their name is equal. if system.`==`(zone1, zone2): return true if zone1.isNil or zone2.isNil: return false + + runnableExamples: + doAssert local() == local() + doAssert local() != utc() zone1.name == zone2.name proc inZone*(time: Time, zone: Timezone): DateTime {.tags: [], raises: [], benign.} = - ## Convert `time` into a `DateTime` using `zone` as the timezone. + ## Convert ``time`` into a ``DateTime`` using ``zone`` as the timezone. result = initDateTime(zone.zonedTimeFromTime(time), zone) proc inZone*(dt: DateTime, zone: Timezone): DateTime {.tags: [], raises: [], benign.} = - ## Returns a `DateTime` representing the same point in time as `dt` but - ## using `zone` as the timezone. - assertDateTimeInitialized dt + ## Returns a ``DateTime`` representing the same point in time as ``dt`` but + ## using ``zone`` as the timezone. dt.toTime.inZone(zone) proc toAdjTime(dt: DateTime): Time = @@ -1273,14 +1094,14 @@ proc toAdjTime(dt: DateTime): Time = result = initTime(seconds, dt.nanosecond) when defined(js): - proc localZonedTimeFromTime(time: Time): ZonedTime {.benign.} = + proc localZonedTimeFromTime(time: Time): ZonedTime = let jsDate = newDate(time.seconds * 1000) let offset = jsDate.getTimezoneOffset() * secondsInMin result.time = time result.utcOffset = offset result.isDst = false - proc localZonedTimeFromAdjTime(adjTime: Time): ZonedTime {.benign.} = + proc localZonedTimeFromAdjTime(adjTime: Time): ZonedTime = let utcDate = newDate(adjTime.seconds * 1000) let localDate = newDate(utcDate.getUTCFullYear(), utcDate.getUTCMonth(), utcDate.getUTCDate(), utcDate.getUTCHours(), utcDate.getUTCMinutes(), @@ -1327,13 +1148,13 @@ else: return ((a.int64 - tm.toAdjUnix).int, tm.tm_isdst > 0) return (0, false) - proc localZonedTimeFromTime(time: Time): ZonedTime {.benign.} = + proc localZonedTimeFromTime(time: Time): ZonedTime = let (offset, dst) = getLocalOffsetAndDst(time.seconds) result.time = time result.utcOffset = offset result.isDst = dst - proc localZonedTimeFromAdjTime(adjTime: Time): ZonedTime {.benign.} = + proc localZonedTimeFromAdjTime(adjTime: Time): ZonedTime = var adjUnix = adjTime.seconds let past = adjUnix - secondsInDay let (pastOffset, _) = getLocalOffsetAndDst(past) @@ -1366,7 +1187,7 @@ var utcInstance {.threadvar.}: Timezone var localInstance {.threadvar.}: Timezone proc utc*(): Timezone = - ## Get the `Timezone` implementation for the UTC timezone. + ## Get the ``Timezone`` implementation for the UTC timezone. runnableExamples: doAssert now().utc.timezone == utc() doAssert utc().name == "Etc/UTC" @@ -1375,7 +1196,7 @@ proc utc*(): Timezone = result = utcInstance proc local*(): Timezone = - ## Get the `Timezone` implementation for the local timezone. + ## Get the ``Timezone`` implementation for the local timezone. runnableExamples: doAssert now().timezone == local() doAssert local().name == "LOCAL" @@ -1385,42 +1206,272 @@ proc local*(): Timezone = result = localInstance proc utc*(dt: DateTime): DateTime = - ## Shorthand for `dt.inZone(utc())`. + ## Shorthand for ``dt.inZone(utc())``. dt.inZone(utc()) proc local*(dt: DateTime): DateTime = - ## Shorthand for `dt.inZone(local())`. + ## Shorthand for ``dt.inZone(local())``. dt.inZone(local()) proc utc*(t: Time): DateTime = - ## Shorthand for `t.inZone(utc())`. + ## Shorthand for ``t.inZone(utc())``. t.inZone(utc()) proc local*(t: Time): DateTime = - ## Shorthand for `t.inZone(local())`. + ## Shorthand for ``t.inZone(local())``. t.inZone(local()) +proc getTime*(): Time {.tags: [TimeEffect], benign.} = + ## Gets the current time as a ``Time`` with up to nanosecond resolution. + when defined(js): + let millis = newDate().getTime() + let seconds = convert(Milliseconds, Seconds, millis) + let nanos = convert(Milliseconds, Nanoseconds, + millis mod convert(Seconds, Milliseconds, 1).int) + result = initTime(seconds, nanos) + elif defined(macosx): + var a: Timeval + gettimeofday(a) + result = initTime(a.tv_sec.int64, + convert(Microseconds, Nanoseconds, a.tv_usec.int)) + elif defined(posix): + var ts: Timespec + discard clock_gettime(CLOCK_REALTIME, ts) + result = initTime(ts.tv_sec.int64, ts.tv_nsec.int) + elif defined(windows): + var f: FILETIME + getSystemTimeAsFileTime(f) + result = fromWinTime(rdFileTime(f)) + proc now*(): DateTime {.tags: [TimeEffect], benign.} = - ## Get the current time as a `DateTime` in the local timezone. - ## Shorthand for `getTime().local`. + ## Get the current time as a ``DateTime`` in the local timezone. ## - ## .. warning:: Unsuitable for benchmarking, use `monotimes.getMonoTime` or - ## `cpuTime` instead, depending on the use case. + ## Shorthand for ``getTime().local``. getTime().local -proc dateTime*(year: int, month: Month, monthday: MonthdayRange, - hour: HourRange = 0, minute: MinuteRange = 0, second: SecondRange = 0, - nanosecond: NanosecondRange = 0, - zone: Timezone = local()): DateTime = +proc initTimeInterval*(nanoseconds, microseconds, milliseconds, + seconds, minutes, hours, + days, weeks, months, years: int = 0): TimeInterval = + ## Creates a new `TimeInterval <#TimeInterval>`_. + ## + ## This proc doesn't perform any normalization! For example, + ## ``initTimeInterval(hours = 24)`` and ``initTimeInterval(days = 1)`` are + ## not equal. + ## + ## You can also use the convenience procedures called ``milliseconds``, + ## ``seconds``, ``minutes``, ``hours``, ``days``, ``months``, and ``years``. + runnableExamples: + let day = initTimeInterval(hours = 24) + let dt = initDateTime(01, mJan, 2000, 12, 00, 00, utc()) + doAssert $(dt + day) == "2000-01-02T12:00:00Z" + doAssert initTimeInterval(hours = 24) != initTimeInterval(days = 1) + result.nanoseconds = nanoseconds + result.microseconds = microseconds + result.milliseconds = milliseconds + result.seconds = seconds + result.minutes = minutes + result.hours = hours + result.days = days + result.weeks = weeks + result.months = months + result.years = years + +proc `+`*(ti1, ti2: TimeInterval): TimeInterval = + ## Adds two ``TimeInterval`` objects together. + result.nanoseconds = ti1.nanoseconds + ti2.nanoseconds + result.microseconds = ti1.microseconds + ti2.microseconds + result.milliseconds = ti1.milliseconds + ti2.milliseconds + result.seconds = ti1.seconds + ti2.seconds + result.minutes = ti1.minutes + ti2.minutes + result.hours = ti1.hours + ti2.hours + result.days = ti1.days + ti2.days + result.weeks = ti1.weeks + ti2.weeks + result.months = ti1.months + ti2.months + result.years = ti1.years + ti2.years + +proc `-`*(ti: TimeInterval): TimeInterval = + ## Reverses a time interval + runnableExamples: + let day = -initTimeInterval(hours = 24) + doAssert day.hours == -24 + + result = TimeInterval( + nanoseconds: -ti.nanoseconds, + microseconds: -ti.microseconds, + milliseconds: -ti.milliseconds, + seconds: -ti.seconds, + minutes: -ti.minutes, + hours: -ti.hours, + days: -ti.days, + weeks: -ti.weeks, + months: -ti.months, + years: -ti.years + ) + +proc `-`*(ti1, ti2: TimeInterval): TimeInterval = + ## Subtracts TimeInterval ``ti1`` from ``ti2``. + ## + ## Time components are subtracted one-by-one, see output: + runnableExamples: + let ti1 = initTimeInterval(hours = 24) + let ti2 = initTimeInterval(hours = 4) + doAssert (ti1 - ti2) == initTimeInterval(hours = 20) + + result = ti1 + (-ti2) + +proc getDateStr*(dt = now()): string {.rtl, extern: "nt$1", tags: [TimeEffect].} = + ## Gets the current local date as a string of the format ``YYYY-MM-DD``. + runnableExamples: + echo getDateStr(now() - 1.months) + result = $dt.year & '-' & intToStr(ord(dt.month), 2) & + '-' & intToStr(dt.monthday, 2) + +proc getClockStr*(dt = now()): string {.rtl, extern: "nt$1", tags: [TimeEffect].} = + ## Gets the current local clock time as a string of the format ``HH:mm:ss``. + runnableExamples: + echo getClockStr(now() - 1.hours) + result = intToStr(dt.hour, 2) & ':' & intToStr(dt.minute, 2) & + ':' & intToStr(dt.second, 2) + +proc toParts*(ti: TimeInterval): TimeIntervalParts = + ## Converts a ``TimeInterval`` into an array consisting of its time units, + ## starting with nanoseconds and ending with years. + ## + ## This procedure is useful for converting ``TimeInterval`` values to strings. + ## E.g. then you need to implement custom interval printing + runnableExamples: + var tp = toParts(initTimeInterval(years = 1, nanoseconds = 123)) + doAssert tp[Years] == 1 + doAssert tp[Nanoseconds] == 123 + + var index = 0 + for name, value in fieldPairs(ti): + result[index.TimeUnit()] = value + index += 1 + +proc `$`*(ti: TimeInterval): string = + ## Get string representation of ``TimeInterval``. + runnableExamples: + doAssert $initTimeInterval(years = 1, nanoseconds = 123) == + "1 year and 123 nanoseconds" + doAssert $initTimeInterval() == "0 nanoseconds" + + var parts: seq[string] = @[] + var tiParts = toParts(ti) + for unit in countdown(Years, Nanoseconds): + if tiParts[unit] != 0: + parts.add(stringifyUnit(tiParts[unit], unit)) + + result = humanizeParts(parts) + +proc nanoseconds*(nanos: int): TimeInterval {.inline.} = + ## TimeInterval of ``nanos`` nanoseconds. + initTimeInterval(nanoseconds = nanos) + +proc microseconds*(micros: int): TimeInterval {.inline.} = + ## TimeInterval of ``micros`` microseconds. + initTimeInterval(microseconds = micros) + +proc milliseconds*(ms: int): TimeInterval {.inline.} = + ## TimeInterval of ``ms`` milliseconds. + initTimeInterval(milliseconds = ms) + +proc seconds*(s: int): TimeInterval {.inline.} = + ## TimeInterval of ``s`` seconds. + ## + ## ``echo getTime() + 5.seconds`` + initTimeInterval(seconds = s) + +proc minutes*(m: int): TimeInterval {.inline.} = + ## TimeInterval of ``m`` minutes. + ## + ## ``echo getTime() + 5.minutes`` + initTimeInterval(minutes = m) + +proc hours*(h: int): TimeInterval {.inline.} = + ## TimeInterval of ``h`` hours. + ## + ## ``echo getTime() + 2.hours`` + initTimeInterval(hours = h) + +proc days*(d: int): TimeInterval {.inline.} = + ## TimeInterval of ``d`` days. + ## + ## ``echo getTime() + 2.days`` + initTimeInterval(days = d) + +proc weeks*(w: int): TimeInterval {.inline.} = + ## TimeInterval of ``w`` weeks. + ## + ## ``echo getTime() + 2.weeks`` + initTimeInterval(weeks = w) + +proc months*(m: int): TimeInterval {.inline.} = + ## TimeInterval of ``m`` months. + ## + ## ``echo getTime() + 2.months`` + initTimeInterval(months = m) + +proc years*(y: int): TimeInterval {.inline.} = + ## TimeInterval of ``y`` years. + ## + ## ``echo getTime() + 2.years`` + initTimeInterval(years = y) + +proc evaluateInterval(dt: DateTime, interval: TimeInterval): + tuple[adjDur, absDur: Duration] = + ## Evaluates how many nanoseconds the interval is worth + ## in the context of ``dt``. + ## The result in split into an adjusted diff and an absolute diff. + var months = interval.years * 12 + interval.months + var curYear = dt.year + var curMonth = dt.month + # Subtracting + if months < 0: + for mth in countdown(-1 * months, 1): + if curMonth == mJan: + curMonth = mDec + curYear.dec + else: + curMonth.dec() + let days = getDaysInMonth(curMonth, curYear) + result.adjDur = result.adjDur - initDuration(days = days) + # Adding + else: + for mth in 1 .. months: + let days = getDaysInMonth(curMonth, curYear) + result.adjDur = result.adjDur + initDuration(days = days) + if curMonth == mDec: + curMonth = mJan + curYear.inc + else: + curMonth.inc() + + result.adjDur = result.adjDur + initDuration( + days = interval.days, + weeks = interval.weeks) + result.absDur = initDuration( + nanoseconds = interval.nanoseconds, + microseconds = interval.microseconds, + milliseconds = interval.milliseconds, + seconds = interval.seconds, + minutes = interval.minutes, + hours = interval.hours) + +proc initDateTime*(monthday: MonthdayRange, month: Month, year: int, + hour: HourRange, minute: MinuteRange, second: SecondRange, + nanosecond: NanosecondRange, + zone: Timezone = local()): DateTime = ## Create a new `DateTime <#DateTime>`_ in the specified timezone. runnableExamples: - assert $dateTime(2017, mMar, 30, zone = utc()) == "2017-03-30T00:00:00Z" + let dt1 = initDateTime(30, mMar, 2017, 00, 00, 00, 00, utc()) + doAssert $dt1 == "2017-03-30T00:00:00Z" assertValidDate monthday, month, year let dt = DateTime( - monthdayZero: monthday, + monthday: monthday, year: year, - monthZero: month.int, + month: month, hour: hour, minute: minute, second: second, @@ -1430,24 +1481,57 @@ proc dateTime*(year: int, month: Month, monthday: MonthdayRange, proc initDateTime*(monthday: MonthdayRange, month: Month, year: int, hour: HourRange, minute: MinuteRange, second: SecondRange, - nanosecond: NanosecondRange, - zone: Timezone = local()): DateTime {.deprecated: "use `dateTime`".} = + zone: Timezone = local()): DateTime = ## Create a new `DateTime <#DateTime>`_ in the specified timezone. - runnableExamples("--warning:deprecated:off"): - assert $initDateTime(30, mMar, 2017, 00, 00, 00, 00, utc()) == "2017-03-30T00:00:00Z" - dateTime(year, month, monthday, hour, minute, second, nanosecond, zone) + runnableExamples: + let dt1 = initDateTime(30, mMar, 2017, 00, 00, 00, utc()) + doAssert $dt1 == "2017-03-30T00:00:00Z" + initDateTime(monthday, month, year, hour, minute, second, 0, zone) -proc initDateTime*(monthday: MonthdayRange, month: Month, year: int, - hour: HourRange, minute: MinuteRange, second: SecondRange, - zone: Timezone = local()): DateTime {.deprecated: "use `dateTime`".} = - ## Create a new `DateTime <#DateTime>`_ in the specified timezone. - runnableExamples("--warning:deprecated:off"): - assert $initDateTime(30, mMar, 2017, 00, 00, 00, utc()) == "2017-03-30T00:00:00Z" - dateTime(year, month, monthday, hour, minute, second, 0, zone) + +proc `+`*(dt: DateTime, interval: TimeInterval): DateTime = + ## Adds ``interval`` to ``dt``. Components from ``interval`` are added + ## in the order of their size, i.e. first the ``years`` component, then the + ## ``months`` component and so on. The returned ``DateTime`` will have the + ## same timezone as the input. + ## + ## Note that when adding months, monthday overflow is allowed. This means that + ## if the resulting month doesn't have enough days it, the month will be + ## incremented and the monthday will be set to the number of days overflowed. + ## So adding one month to `31 October` will result in `31 November`, which + ## will overflow and result in `1 December`. + runnableExamples: + let dt = initDateTime(30, mMar, 2017, 00, 00, 00, utc()) + doAssert $(dt + 1.months) == "2017-04-30T00:00:00Z" + # This is correct and happens due to monthday overflow. + doAssert $(dt - 1.months) == "2017-03-02T00:00:00Z" + let (adjDur, absDur) = evaluateInterval(dt, interval) + + if adjDur != DurationZero: + var zt = dt.timezone.zonedTimeFromAdjTime(dt.toAdjTime + adjDur) + if absDur != DurationZero: + zt = dt.timezone.zonedTimeFromTime(zt.time + absDur) + result = initDateTime(zt, dt.timezone) + else: + result = initDateTime(zt, dt.timezone) + else: + var zt = dt.timezone.zonedTimeFromTime(dt.toTime + absDur) + result = initDateTime(zt, dt.timezone) + +proc `-`*(dt: DateTime, interval: TimeInterval): DateTime = + ## Subtract ``interval`` from ``dt``. Components from ``interval`` are + ## subtracted in the order of their size, i.e. first the ``years`` component, + ## then the ``months`` component and so on. The returned ``DateTime`` will + ## have the same timezone as the input. + runnableExamples: + let dt = initDateTime(30, mMar, 2017, 00, 00, 00, utc()) + doAssert $(dt - 5.days) == "2017-03-25T00:00:00Z" + + dt + (-interval) proc `+`*(dt: DateTime, dur: Duration): DateTime = runnableExamples: - let dt = dateTime(2017, mMar, 30, 00, 00, 00, 00, utc()) + let dt = initDateTime(30, mMar, 2017, 00, 00, 00, utc()) let dur = initDuration(hours = 5) doAssert $(dt + dur) == "2017-03-30T05:00:00Z" @@ -1455,75 +1539,206 @@ proc `+`*(dt: DateTime, dur: Duration): DateTime = proc `-`*(dt: DateTime, dur: Duration): DateTime = runnableExamples: - let dt = dateTime(2017, mMar, 30, 00, 00, 00, 00, utc()) + let dt = initDateTime(30, mMar, 2017, 00, 00, 00, utc()) let dur = initDuration(days = 5) doAssert $(dt - dur) == "2017-03-25T00:00:00Z" (dt.toTime - dur).inZone(dt.timezone) proc `-`*(dt1, dt2: DateTime): Duration = - ## Compute the duration between `dt1` and `dt2`. + ## Compute the duration between ``dt1`` and ``dt2``. runnableExamples: - let dt1 = dateTime(2017, mMar, 30, 00, 00, 00, 00, utc()) - let dt2 = dateTime(2017, mMar, 25, 00, 00, 00, 00, utc()) + let dt1 = initDateTime(30, mMar, 2017, 00, 00, 00, utc()) + let dt2 = initDateTime(25, mMar, 2017, 00, 00, 00, utc()) doAssert dt1 - dt2 == initDuration(days = 5) dt1.toTime - dt2.toTime proc `<`*(a, b: DateTime): bool = - ## Returns true if `a` happened before `b`. + ## Returns true if ``a`` happened before ``b``. return a.toTime < b.toTime proc `<=`*(a, b: DateTime): bool = - ## Returns true if `a` happened before or at the same time as `b`. + ## Returns true if ``a`` happened before or at the same time as ``b``. return a.toTime <= b.toTime proc `==`*(a, b: DateTime): bool = - ## Returns true if `a` and `b` represent the same point in time. - if not a.isInitialized: not b.isInitialized - elif not b.isInitialized: false - else: a.toTime == b.toTime + ## Returns true if ``a`` and ``b`` represent the same point in time. + return a.toTime == b.toTime -proc `+=`*(a: var DateTime, b: Duration) = +proc isStaticInterval(interval: TimeInterval): bool = + interval.years == 0 and interval.months == 0 and + interval.days == 0 and interval.weeks == 0 + +proc evaluateStaticInterval(interval: TimeInterval): Duration = + assert interval.isStaticInterval + initDuration(nanoseconds = interval.nanoseconds, + microseconds = interval.microseconds, + milliseconds = interval.milliseconds, + seconds = interval.seconds, + minutes = interval.minutes, + hours = interval.hours) + +proc between*(startDt, endDt: DateTime): TimeInterval = + ## Gives the difference between ``startDt`` and ``endDt`` as a + ## ``TimeInterval``. The following guarantees about the result is given: + ## + ## - All fields will have the same sign. + ## - If `startDt.timezone == endDt.timezone`, it is guaranteed that + ## `startDt + between(startDt, endDt) == endDt`. + ## - If `startDt.timezone != endDt.timezone`, then the result will be + ## equivalent to `between(startDt.utc, endDt.utc)`. + runnableExamples: + var a = initDateTime(25, mMar, 2015, 12, 0, 0, utc()) + var b = initDateTime(1, mApr, 2017, 15, 0, 15, utc()) + var ti = initTimeInterval(years = 2, weeks = 1, hours = 3, seconds = 15) + doAssert between(a, b) == ti + doAssert between(a, b) == -between(b, a) + + if startDt.timezone != endDt.timezone: + return between(startDt.utc, endDt.utc) + elif endDt < startDt: + return -between(endDt, startDt) + + type Date = tuple[year, month, monthday: int] + var startDate: Date = (startDt.year, startDt.month.ord, startDt.monthday) + var endDate: Date = (endDt.year, endDt.month.ord, endDt.monthday) + + # Subtract one day from endDate if time of day is earlier than startDay + # The subtracted day will be counted by fixed units (hour and lower) + # at the end of this proc + if (endDt.hour, endDt.minute, endDt.second, endDt.nanosecond) < + (startDt.hour, startDt.minute, startDt.second, startDt.nanosecond): + if endDate.month == 1 and endDate.monthday == 1: + endDate.year.dec + endDate.monthday = 31 + endDate.month = 12 + elif endDate.monthday == 1: + endDate.month.dec + endDate.monthday = getDaysInMonth(endDate.month.Month, endDate.year) + else: + endDate.monthday.dec + + # Years + result.years.inc endDate.year - startDate.year - 1 + if (startDate.month, startDate.monthday) <= (endDate.month, endDate.monthday): + result.years.inc + startDate.year.inc result.years + + # Months + if startDate.year < endDate.year: + result.months.inc 12 - startDate.month # Move to dec + if endDate.month != 1 or (startDate.monthday <= endDate.monthday): + result.months.inc + startDate.year = endDate.year + startDate.month = 1 + else: + startDate.month = 12 + if startDate.year == endDate.year: + if (startDate.monthday <= endDate.monthday): + result.months.inc endDate.month - startDate.month + startDate.month = endDate.month + elif endDate.month != 1: + let month = endDate.month - 1 + let daysInMonth = getDaysInMonth(month.Month, startDate.year) + if daysInMonth < startDate.monthday: + if startDate.monthday - daysInMonth < endDate.monthday: + result.months.inc endDate.month - startDate.month - 1 + startDate.month = endDate.month + startDate.monthday = startDate.monthday - daysInMonth + else: + result.months.inc endDate.month - startDate.month - 2 + startDate.month = endDate.month - 2 + else: + result.months.inc endDate.month - startDate.month - 1 + startDate.month = endDate.month - 1 + + # Days + # This means that start = dec and end = jan + if startDate.year < endDate.year: + result.days.inc 31 - startDate.monthday + endDate.monthday + startDate = endDate + else: + while startDate.month < endDate.month: + let daysInMonth = getDaysInMonth(startDate.month.Month, startDate.year) + result.days.inc daysInMonth - startDate.monthday + 1 + startDate.month.inc + startDate.monthday = 1 + result.days.inc endDate.monthday - startDate.monthday + result.weeks = result.days div 7 + result.days = result.days mod 7 + startDate = endDate + + # Handle hours, minutes, seconds, milliseconds, microseconds and nanoseconds + let newStartDt = initDateTime(startDate.monthday, startDate.month.Month, + startDate.year, startDt.hour, startDt.minute, startDt.second, + startDt.nanosecond, startDt.timezone) + let dur = endDt - newStartDt + let parts = toParts(dur) + # There can still be a full day in `parts` since `Duration` and `TimeInterval` + # models days differently. + result.hours = parts[Hours].int + parts[Days].int * 24 + result.minutes = parts[Minutes].int + result.seconds = parts[Seconds].int + result.milliseconds = parts[Milliseconds].int + result.microseconds = parts[Microseconds].int + result.nanoseconds = parts[Nanoseconds].int + +proc `+`*(time: Time, interval: TimeInterval): Time = + ## Adds `interval` to `time`. + ## If `interval` contains any years, months, weeks or days the operation + ## is performed in the local timezone. + runnableExamples: + let tm = fromUnix(0) + doAssert tm + 5.seconds == fromUnix(5) + + if interval.isStaticInterval: + time + evaluateStaticInterval(interval) + else: + toTime(time.local + interval) + +proc `-`*(time: Time, interval: TimeInterval): Time = + ## Subtracts `interval` from Time `time`. + ## If `interval` contains any years, months, weeks or days the operation + ## is performed in the local timezone. + runnableExamples: + let tm = fromUnix(5) + doAssert tm - 5.seconds == fromUnix(0) + + if interval.isStaticInterval: + time - evaluateStaticInterval(interval) + else: + toTime(time.local - interval) + +proc `+=`*[T, U: TimesMutableTypes](a: var T, b: U) = + ## Modify ``a`` in place by adding ``b``. + runnableExamples: + var tm = fromUnix(0) + tm += initDuration(seconds = 1) + doAssert tm == fromUnix(1) a = a + b -proc `-=`*(a: var DateTime, b: Duration) = +proc `-=`*[T, U: TimesMutableTypes](a: var T, b: U) = + ## Modify ``a`` in place by subtracting ``b``. + runnableExamples: + var tm = fromUnix(5) + tm -= initDuration(seconds = 5) + doAssert tm == fromUnix(0) a = a - b -proc getDateStr*(dt = now()): string {.rtl, extern: "nt$1", tags: [TimeEffect].} = - ## Gets the current local date as a string of the format `YYYY-MM-DD`. +proc `*=`*[T: TimesMutableTypes, U](a: var T, b: U) = + # Mutable type is often multiplied by number runnableExamples: - echo getDateStr(now() - 1.months) - assertDateTimeInitialized dt - result = $dt.year & '-' & intToStr(dt.monthZero, 2) & - '-' & intToStr(dt.monthday, 2) - -proc getClockStr*(dt = now()): string {.rtl, extern: "nt$1", tags: [TimeEffect].} = - ## Gets the current local clock time as a string of the format `HH:mm:ss`. - runnableExamples: - echo getClockStr(now() - 1.hours) - assertDateTimeInitialized dt - result = intToStr(dt.hour, 2) & ':' & intToStr(dt.minute, 2) & - ':' & intToStr(dt.second, 2) + var dur = initDuration(seconds = 1) + dur *= 5 + doAssert dur == initDuration(seconds = 5) + a = a * b # -# TimeFormat +# Parse & format implementation # -when defined(nimHasStyleChecks): - {.push styleChecks: off.} - -type - DateTimeLocale* = object - MMM*: array[mJan..mDec, string] - MMMM*: array[mJan..mDec, string] - ddd*: array[dMon..dSun, string] - dddd*: array[dMon..dSun, string] - -when defined(nimHasStyleChecks): - {.pop.} - type AmPm = enum apUnknown, apAm, apPm @@ -1556,52 +1771,40 @@ type s, ss fff, ffffff, fffffffff t, tt - yy, yyyy + y, yy, yyy, yyyy, yyyyy YYYY uuuu UUUU z, zz, zzz, zzzz - ZZZ, ZZZZ g # This is a special value used to mark literal format values. - # See the doc comment for `TimeFormat.patterns`. + # See the doc comment for ``TimeFormat.patterns``. Lit TimeFormat* = object ## Represents a format for parsing and printing ## time types. ## - ## To create a new `TimeFormat` use `initTimeFormat proc + ## To create a new ``TimeFormat`` use `initTimeFormat proc ## <#initTimeFormat,string>`_. patterns: seq[byte] ## \ ## Contains the patterns encoded as bytes. ## Literal values are encoded in a special way. - ## They start with `Lit.byte`, then the length of the literal, then the + ## They start with ``Lit.byte``, then the length of the literal, then the ## raw char values of the literal. For example, the literal `foo` would - ## be encoded as `@[Lit.byte, 3.byte, 'f'.byte, 'o'.byte, 'o'.byte]`. + ## be encoded as ``@[Lit.byte, 3.byte, 'f'.byte, 'o'.byte, 'o'.byte]``. formatStr: string TimeParseError* = object of ValueError ## \ - ## Raised when parsing input using a `TimeFormat` fails. + ## Raised when parsing input using a ``TimeFormat`` fails. TimeFormatParseError* = object of ValueError ## \ - ## Raised when parsing a `TimeFormat` string fails. + ## Raised when parsing a ``TimeFormat`` string fails. -const - DefaultLocale* = DateTimeLocale( - MMM: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", - "Nov", "Dec"], - MMMM: ["January", "February", "March", "April", "May", "June", "July", - "August", "September", "October", "November", "December"], - ddd: ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"], - dddd: ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", - "Sunday"], - ) - - FormatLiterals = {' ', '-', '/', ':', '(', ')', '[', ']', ','} +const FormatLiterals = {' ', '-', '/', ':', '(', ')', '[', ']', ','} proc `$`*(f: TimeFormat): string = - ## Returns the format string that was used to construct `f`. + ## Returns the format string that was used to construct ``f``. runnableExamples: let f = initTimeFormat("yyyy-MM-dd") doAssert $f == "yyyy-MM-dd" @@ -1705,8 +1908,11 @@ proc stringToPattern(str: string): FormatPattern = of "fffffffff": result = fffffffff of "t": result = t of "tt": result = tt + of "y": result = y of "yy": result = yy + of "yyy": result = yyy of "yyyy": result = yyyy + of "yyyyy": result = yyyyy of "YYYY": result = YYYY of "uuuu": result = uuuu of "UUUU": result = UUUU @@ -1714,8 +1920,6 @@ proc stringToPattern(str: string): FormatPattern = of "zz": result = zz of "zzz": result = zzz of "zzzz": result = zzzz - of "ZZZ": result = ZZZ - of "ZZZZ": result = ZZZZ of "g": result = g else: raise newException(TimeFormatParseError, "'" & str & "' is not a valid pattern") @@ -1724,7 +1928,7 @@ proc initTimeFormat*(format: string): TimeFormat = ## Construct a new time format for parsing & formatting time types. ## ## See `Parsing and formatting dates`_ for documentation of the - ## `format` argument. + ## ``format`` argument. runnableExamples: let f = initTimeFormat("yyyy-MM-dd") doAssert "2000-01-01" == "2000-01-01".parse(f).format(f) @@ -1801,14 +2005,20 @@ proc formatPattern(dt: DateTime, pattern: FormatPattern, result: var string, result.add if dt.hour >= 12: "P" else: "A" of tt: result.add if dt.hour >= 12: "PM" else: "AM" + of y: # Deprecated + result.add $(dt.yearOfEra mod 10) of yy: result.add (dt.yearOfEra mod 100).intToStr(2) + of yyy: # Deprecated + result.add (dt.yearOfEra mod 1000).intToStr(3) of yyyy: let year = dt.yearOfEra if year < 10000: result.add year.intToStr(4) else: result.add '+' & $year + of yyyyy: # Deprecated + result.add (dt.yearOfEra mod 100_000).intToStr(5) of YYYY: if dt.year < 1: result.add $(abs(dt.year) + 1) @@ -1822,7 +2032,7 @@ proc formatPattern(dt: DateTime, pattern: FormatPattern, result: var string, result.add '+' & $year of UUUU: result.add $dt.year - of z, zz, zzz, zzzz, ZZZ, ZZZZ: + of z, zz, zzz, zzzz: if dt.timezone != nil and dt.timezone.name == "Etc/UTC": result.add 'Z' else: @@ -1833,18 +2043,16 @@ proc formatPattern(dt: DateTime, pattern: FormatPattern, result: var string, result.add $(absOffset div 3600) of zz: result.add (absOffset div 3600).intToStr(2) - of zzz, ZZZ: + of zzz: let h = (absOffset div 3600).intToStr(2) let m = ((absOffset div 60) mod 60).intToStr(2) - let sep = if pattern == zzz: ":" else: "" - result.add h & sep & m - of zzzz, ZZZZ: + result.add h & ":" & m + of zzzz: let absOffset = abs(dt.utcOffset) let h = (absOffset div 3600).intToStr(2) let m = ((absOffset div 60) mod 60).intToStr(2) let s = (absOffset mod 60).intToStr(2) - let sep = if pattern == zzzz: ":" else: "" - result.add h & sep & m & sep & s + result.add h & ":" & m & ":" & s else: assert false of g: result.add if dt.year < 1: "BC" else: "AD" @@ -1853,7 +2061,7 @@ proc formatPattern(dt: DateTime, pattern: FormatPattern, result: var string, proc parsePattern(input: string, pattern: FormatPattern, i: var int, parsed: var ParsedTime, loc: DateTimeLocale): bool = template takeInt(allowedWidth: Slice[int], allowSign = false): int = - var sv = 0 + var sv: int var pd = parseInt(input, sv, i, allowedWidth.b, allowSign) if pd < allowedWidth.a: return false @@ -1978,7 +2186,7 @@ proc parsePattern(input: string, pattern: FormatPattern, i: var int, parsed.year = some(year) of UUUU: parsed.year = some(takeInt(1..high(int), allowSign = true)) - of z, zz, zzz, zzzz, ZZZ, ZZZZ: + of z, zz, zzz, zzzz: case input[i] of '+', '-': let sign = if input[i] == '-': 1 else: -1 @@ -1989,24 +2197,21 @@ proc parsePattern(input: string, pattern: FormatPattern, i: var int, offset = takeInt(1..2) * 3600 of zz: offset = takeInt(2..2) * 3600 - of zzz, ZZZ: + of zzz: offset.inc takeInt(2..2) * 3600 - if pattern == zzz: - if input[i] != ':': - return false - i.inc + if input[i] != ':': + return false + i.inc offset.inc takeInt(2..2) * 60 - of zzzz, ZZZZ: + of zzzz: offset.inc takeInt(2..2) * 3600 - if pattern == zzzz: - if input[i] != ':': - return false - i.inc + if input[i] != ':': + return false + i.inc offset.inc takeInt(2..2) * 60 - if pattern == zzzz: - if input[i] != ':': - return false - i.inc + if input[i] != ':': + return false + i.inc offset.inc takeInt(2..2) else: assert false parsed.utcOffset = some(offset * sign) @@ -2024,13 +2229,25 @@ proc parsePattern(input: string, pattern: FormatPattern, i: var int, i.inc 2 else: result = false + of y, yyy, yyyyy: + raiseAssert "Pattern is invalid for parsing: " & $pattern of Lit: doAssert false, "Can't happen" proc toDateTime(p: ParsedTime, zone: Timezone, f: TimeFormat, input: string): DateTime = - var year = p.year.get(0) - var month = p.month.get(1).Month - var monthday = p.monthday.get(1) + var month = mJan + var year: int + var monthday: int + # `now()` is an expensive call, so we avoid it when possible + (year, month, monthday) = + if p.year.isNone or p.month.isNone or p.monthday.isNone: + let n = now() + (p.year.get(n.year), + p.month.get(n.month.int).Month, + p.monthday.get(n.monthday)) + else: + (p.year.get(), p.month.get().Month, p.monthday.get()) + year = case p.era of eraUnknown: @@ -2071,23 +2288,26 @@ proc toDateTime(p: ParsedTime, zone: Timezone, f: TimeFormat, $year & "-" & ord(month).intToStr(2) & "-" & $monthday & " is not a valid date") + result = DateTime( + year: year, month: month, monthday: monthday, + hour: hour, minute: minute, second: second, nanosecond: nanosecond + ) + if p.utcOffset.isNone: # No timezone parsed - assume timezone is `zone` - result = dateTime(year, month, monthday, hour, minute, second, nanosecond, zone) + result = initDateTime(zone.zonedTimeFromAdjTime(result.toAdjTime), zone) else: # Otherwise convert to `zone` - result = (dateTime(year, month, monthday, hour, minute, second, nanosecond, utc()).toTime + - initDuration(seconds = p.utcOffset.get())).inZone(zone) + result.utcOffset = p.utcOffset.get() + result = result.toTime.inZone(zone) proc format*(dt: DateTime, f: TimeFormat, loc: DateTimeLocale = DefaultLocale): string {.raises: [].} = - ## Format `dt` using the format specified by `f`. + ## Format ``dt`` using the format specified by ``f``. runnableExamples: let f = initTimeFormat("yyyy-MM-dd") - let dt = dateTime(2000, mJan, 01, 00, 00, 00, 00, utc()) + let dt = initDateTime(01, mJan, 2000, 00, 00, 00, utc()) doAssert "2000-01-01" == dt.format(f) - assertDateTimeInitialized dt - result = "" var idx = 0 while idx <= f.patterns.high: case f.patterns[idx].FormatPattern @@ -2104,56 +2324,61 @@ proc format*(dt: DateTime, f: TimeFormat, proc format*(dt: DateTime, f: string, loc: DateTimeLocale = DefaultLocale): string {.raises: [TimeFormatParseError].} = - ## Shorthand for constructing a `TimeFormat` and using it to format `dt`. + ## Shorthand for constructing a ``TimeFormat`` and using it to format ``dt``. ## ## See `Parsing and formatting dates`_ for documentation of the - ## `format` argument. + ## ``format`` argument. runnableExamples: - let dt = dateTime(2000, mJan, 01, 00, 00, 00, 00, utc()) + let dt = initDateTime(01, mJan, 2000, 00, 00, 00, utc()) doAssert "2000-01-01" == format(dt, "yyyy-MM-dd") let dtFormat = initTimeFormat(f) result = dt.format(dtFormat, loc) proc format*(dt: DateTime, f: static[string]): string {.raises: [].} = - ## Overload that validates `format` at compile time. + ## Overload that validates ``format`` at compile time. const f2 = initTimeFormat(f) result = dt.format(f2) -proc formatValue*(result: var string; value: DateTime | Time, specifier: string) = +proc formatValue*(result: var string; value: DateTime, specifier: string) = ## adapter for strformat. Not intended to be called directly. result.add format(value, if specifier.len == 0: "yyyy-MM-dd'T'HH:mm:sszzz" else: specifier) proc format*(time: Time, f: string, zone: Timezone = local()): string {.raises: [TimeFormatParseError].} = - ## Shorthand for constructing a `TimeFormat` and using it to format - ## `time`. Will use the timezone specified by `zone`. + ## Shorthand for constructing a ``TimeFormat`` and using it to format + ## ``time``. Will use the timezone specified by ``zone``. ## ## See `Parsing and formatting dates`_ for documentation of the - ## `f` argument. + ## ``f`` argument. runnableExamples: - var dt = dateTime(1970, mJan, 01, 00, 00, 00, 00, utc()) + var dt = initDateTime(01, mJan, 1970, 00, 00, 00, utc()) var tm = dt.toTime() doAssert format(tm, "yyyy-MM-dd'T'HH:mm:ss", utc()) == "1970-01-01T00:00:00" time.inZone(zone).format(f) proc format*(time: Time, f: static[string], zone: Timezone = local()): string {.raises: [].} = - ## Overload that validates `f` at compile time. + ## Overload that validates ``f`` at compile time. const f2 = initTimeFormat(f) result = time.inZone(zone).format(f2) +template formatValue*(result: var string; value: Time, specifier: string) = + ## adapter for ``strformat``. Not intended to be called directly. + result.add format(value, specifier) + proc parse*(input: string, f: TimeFormat, zone: Timezone = local(), - loc: DateTimeLocale = DefaultLocale): DateTime {.parseRaises.} = - ## Parses `input` as a `DateTime` using the format specified by `f`. - ## If no UTC offset was parsed, then `input` is assumed to be specified in - ## the `zone` timezone. If a UTC offset was parsed, the result will be - ## converted to the `zone` timezone. + loc: DateTimeLocale = DefaultLocale): DateTime + {.raises: [TimeParseError, Defect].} = + ## Parses ``input`` as a ``DateTime`` using the format specified by ``f``. + ## If no UTC offset was parsed, then ``input`` is assumed to be specified in + ## the ``zone`` timezone. If a UTC offset was parsed, the result will be + ## converted to the ``zone`` timezone. ## - ## Month and day names from the passed in `loc` are used. + ## Month and day names from the passed in ``loc`` are used. runnableExamples: let f = initTimeFormat("yyyy-MM-dd") - let dt = dateTime(2000, mJan, 01, 00, 00, 00, 00, utc()) + let dt = initDateTime(01, mJan, 2000, 00, 00, 00, utc()) doAssert dt == "2000-01-01".parse(f, utc()) var inpIdx = 0 # Input index var patIdx = 0 # Pattern index @@ -2187,525 +2412,115 @@ proc parse*(input: string, f: TimeFormat, zone: Timezone = local(), result = toDateTime(parsed, zone, f, input) proc parse*(input, f: string, tz: Timezone = local(), - loc: DateTimeLocale = DefaultLocale): DateTime {.parseFormatRaises.} = - ## Shorthand for constructing a `TimeFormat` and using it to parse - ## `input` as a `DateTime`. + loc: DateTimeLocale = DefaultLocale): DateTime + {.raises: [TimeParseError, TimeFormatParseError, Defect].} = + ## Shorthand for constructing a ``TimeFormat`` and using it to parse + ## ``input`` as a ``DateTime``. ## ## See `Parsing and formatting dates`_ for documentation of the - ## `f` argument. + ## ``f`` argument. runnableExamples: - let dt = dateTime(2000, mJan, 01, 00, 00, 00, 00, utc()) + let dt = initDateTime(01, mJan, 2000, 00, 00, 00, utc()) doAssert dt == parse("2000-01-01", "yyyy-MM-dd", utc()) let dtFormat = initTimeFormat(f) result = input.parse(dtFormat, tz, loc = loc) proc parse*(input: string, f: static[string], zone: Timezone = local(), - loc: DateTimeLocale = DefaultLocale): DateTime {.parseRaises.} = - ## Overload that validates `f` at compile time. + loc: DateTimeLocale = DefaultLocale): + DateTime {.raises: [TimeParseError, Defect].} = + ## Overload that validates ``f`` at compile time. const f2 = initTimeFormat(f) result = input.parse(f2, zone, loc = loc) -proc parseTime*(input, f: string, zone: Timezone): Time {.parseFormatRaises.} = - ## Shorthand for constructing a `TimeFormat` and using it to parse - ## `input` as a `DateTime`, then converting it a `Time`. +proc parseTime*(input, f: string, zone: Timezone): Time + {.raises: [TimeParseError, TimeFormatParseError, Defect].} = + ## Shorthand for constructing a ``TimeFormat`` and using it to parse + ## ``input`` as a ``DateTime``, then converting it a ``Time``. ## ## See `Parsing and formatting dates`_ for documentation of the - ## `format` argument. + ## ``format`` argument. runnableExamples: let tStr = "1970-01-01T00:00:00+00:00" doAssert parseTime(tStr, "yyyy-MM-dd'T'HH:mm:sszzz", utc()) == fromUnix(0) parse(input, f, zone).toTime() proc parseTime*(input: string, f: static[string], zone: Timezone): Time - {.parseRaises.} = - ## Overload that validates `format` at compile time. + {.raises: [TimeParseError, Defect].} = + ## Overload that validates ``format`` at compile time. const f2 = initTimeFormat(f) result = input.parse(f2, zone).toTime() +# +# End of parse & format implementation +# + proc `$`*(dt: DateTime): string {.tags: [], raises: [], benign.} = ## Converts a `DateTime` object to a string representation. - ## It uses the format `yyyy-MM-dd'T'HH:mm:sszzz`. + ## It uses the format ``yyyy-MM-dd'T'HH:mm:sszzz``. runnableExamples: - let dt = dateTime(2000, mJan, 01, 12, 00, 00, 00, utc()) + let dt = initDateTime(01, mJan, 2000, 12, 00, 00, utc()) doAssert $dt == "2000-01-01T12:00:00Z" - doAssert $default(DateTime) == "Uninitialized DateTime" - if not dt.isInitialized: - result = "Uninitialized DateTime" - else: - result = format(dt, "yyyy-MM-dd'T'HH:mm:sszzz") + result = format(dt, "yyyy-MM-dd'T'HH:mm:sszzz") proc `$`*(time: Time): string {.tags: [], raises: [], benign.} = ## Converts a `Time` value to a string representation. It will use the local - ## time zone and use the format `yyyy-MM-dd'T'HH:mm:sszzz`. + ## time zone and use the format ``yyyy-MM-dd'T'HH:mm:sszzz``. runnableExamples: - let dt = dateTime(1970, mJan, 01, 00, 00, 00, 00, local()) + let dt = initDateTime(01, mJan, 1970, 00, 00, 00, local()) let tm = dt.toTime() doAssert $tm == "1970-01-01T00:00:00" & format(dt, "zzz") $time.local -# -# TimeInterval -# +proc countLeapYears*(yearSpan: int): int + {.deprecated.} = + ## Returns the number of leap years spanned by a given number of years. + ## + ## **Note:** For leap years, start date is assumed to be 1 AD. + ## counts the number of leap years up to January 1st of a given year. + ## Keep in mind that if specified year is a leap year, the leap day + ## has not happened before January 1st of that year. + ## + ## **Deprecated since v0.20.0**. + (yearSpan - 1) div 4 - (yearSpan - 1) div 100 + (yearSpan - 1) div 400 -proc initTimeInterval*(nanoseconds, microseconds, milliseconds, - seconds, minutes, hours, - days, weeks, months, years: int = 0): TimeInterval = - ## Creates a new `TimeInterval <#TimeInterval>`_. +proc countDays*(yearSpan: int): int + {.deprecated.} = + ## Returns the number of days spanned by a given number of years. ## - ## This proc doesn't perform any normalization! For example, - ## `initTimeInterval(hours = 24)` and `initTimeInterval(days = 1)` are - ## not equal. + ## **Deprecated since v0.20.0**. + (yearSpan - 1) * 365 + countLeapYears(yearSpan) + +proc countYears*(daySpan: int): int + {.deprecated.} = + ## Returns the number of years spanned by a given number of days. ## - ## You can also use the convenience procedures called `milliseconds`, - ## `seconds`, `minutes`, `hours`, `days`, `months`, and `years`. + ## **Deprecated since v0.20.0**. + ((daySpan - countLeapYears(daySpan div 365)) div 365) + +proc countYearsAndDays*(daySpan: int): tuple[years: int, days: int] + {.deprecated.} = + ## Returns the number of years spanned by a given number of days and the + ## remainder as days. + ## + ## **Deprecated since v0.20.0**. + let days = daySpan - countLeapYears(daySpan div 365) + result.years = days div 365 + result.days = days mod 365 + +proc toTimeInterval*(time: Time): TimeInterval + {.deprecated: "Use `between` instead".} = + ## Converts a Time to a TimeInterval. To be used when diffing times. + ## + ## **Deprecated since version 0.20.0:** Use the `between proc + ## <#between,DateTime,DateTime>`_ instead. runnableExamples: - let day = initTimeInterval(hours = 24) - let dt = dateTime(2000, mJan, 01, 12, 00, 00, 00, utc()) - doAssert $(dt + day) == "2000-01-02T12:00:00Z" - doAssert initTimeInterval(hours = 24) != initTimeInterval(days = 1) - result.nanoseconds = nanoseconds - result.microseconds = microseconds - result.milliseconds = milliseconds - result.seconds = seconds - result.minutes = minutes - result.hours = hours - result.days = days - result.weeks = weeks - result.months = months - result.years = years - -proc `+`*(ti1, ti2: TimeInterval): TimeInterval = - ## Adds two `TimeInterval` objects together. - result.nanoseconds = ti1.nanoseconds + ti2.nanoseconds - result.microseconds = ti1.microseconds + ti2.microseconds - result.milliseconds = ti1.milliseconds + ti2.milliseconds - result.seconds = ti1.seconds + ti2.seconds - result.minutes = ti1.minutes + ti2.minutes - result.hours = ti1.hours + ti2.hours - result.days = ti1.days + ti2.days - result.weeks = ti1.weeks + ti2.weeks - result.months = ti1.months + ti2.months - result.years = ti1.years + ti2.years - -proc `-`*(ti: TimeInterval): TimeInterval = - ## Reverses a time interval - runnableExamples: - let day = -initTimeInterval(hours = 24) - doAssert day.hours == -24 - - result = TimeInterval( - nanoseconds: -ti.nanoseconds, - microseconds: -ti.microseconds, - milliseconds: -ti.milliseconds, - seconds: -ti.seconds, - minutes: -ti.minutes, - hours: -ti.hours, - days: -ti.days, - weeks: -ti.weeks, - months: -ti.months, - years: -ti.years - ) - -proc `-`*(ti1, ti2: TimeInterval): TimeInterval = - ## Subtracts TimeInterval `ti1` from `ti2`. - ## - ## Time components are subtracted one-by-one, see output: - runnableExamples: - let ti1 = initTimeInterval(hours = 24) - let ti2 = initTimeInterval(hours = 4) - doAssert (ti1 - ti2) == initTimeInterval(hours = 20) - - result = ti1 + (-ti2) - -proc `+=`*(a: var TimeInterval, b: TimeInterval) = - a = a + b - -proc `-=`*(a: var TimeInterval, b: TimeInterval) = - a = a - b - -proc isStaticInterval(interval: TimeInterval): bool = - interval.years == 0 and interval.months == 0 and - interval.days == 0 and interval.weeks == 0 - -proc evaluateStaticInterval(interval: TimeInterval): Duration = - assert interval.isStaticInterval - initDuration(nanoseconds = interval.nanoseconds, - microseconds = interval.microseconds, - milliseconds = interval.milliseconds, - seconds = interval.seconds, - minutes = interval.minutes, - hours = interval.hours) - -proc between*(startDt, endDt: DateTime): TimeInterval = - ## Gives the difference between `startDt` and `endDt` as a - ## `TimeInterval`. The following guarantees about the result is given: - ## - ## - All fields will have the same sign. - ## - If `startDt.timezone == endDt.timezone`, it is guaranteed that - ## `startDt + between(startDt, endDt) == endDt`. - ## - If `startDt.timezone != endDt.timezone`, then the result will be - ## equivalent to `between(startDt.utc, endDt.utc)`. - runnableExamples: - var a = dateTime(2015, mMar, 25, 12, 0, 0, 00, utc()) - var b = dateTime(2017, mApr, 1, 15, 0, 15, 00, utc()) - var ti = initTimeInterval(years = 2, weeks = 1, hours = 3, seconds = 15) - doAssert between(a, b) == ti - doAssert between(a, b) == -between(b, a) - - if startDt.timezone != endDt.timezone: - return between(startDt.utc, endDt.utc) - elif endDt < startDt: - return -between(endDt, startDt) - - type Date = tuple[year, month, monthday: int] - var startDate: Date = (startDt.year, startDt.month.ord, startDt.monthday) - var endDate: Date = (endDt.year, endDt.month.ord, endDt.monthday) - - # Subtract one day from endDate if time of day is earlier than startDay - # The subtracted day will be counted by fixed units (hour and lower) - # at the end of this proc - if (endDt.hour, endDt.minute, endDt.second, endDt.nanosecond) < - (startDt.hour, startDt.minute, startDt.second, startDt.nanosecond): - if endDate.month == 1 and endDate.monthday == 1: - endDate.year.dec - endDate.monthday = 31 - endDate.month = 12 - elif endDate.monthday == 1: - endDate.month.dec - endDate.monthday = getDaysInMonth(endDate.month.Month, endDate.year) - else: - endDate.monthday.dec - - # Years - result.years = endDate.year - startDate.year - 1 - if (startDate.month, startDate.monthday) <= (endDate.month, endDate.monthday): - result.years.inc - startDate.year.inc result.years - - # Months - if startDate.year < endDate.year: - result.months.inc 12 - startDate.month # Move to dec - if endDate.month != 1 or (startDate.monthday <= endDate.monthday): - result.months.inc - startDate.year = endDate.year - startDate.month = 1 - else: - startDate.month = 12 - if startDate.year == endDate.year: - if (startDate.monthday <= endDate.monthday): - result.months.inc endDate.month - startDate.month - startDate.month = endDate.month - elif endDate.month != 1: - let month = endDate.month - 1 - let daysInMonth = getDaysInMonth(month.Month, startDate.year) - if daysInMonth < startDate.monthday: - if startDate.monthday - daysInMonth < endDate.monthday: - result.months.inc endDate.month - startDate.month - 1 - startDate.month = endDate.month - startDate.monthday = startDate.monthday - daysInMonth - else: - result.months.inc endDate.month - startDate.month - 2 - startDate.month = endDate.month - 2 - else: - result.months.inc endDate.month - startDate.month - 1 - startDate.month = endDate.month - 1 - - # Days - # This means that start = dec and end = jan - if startDate.year < endDate.year: - result.days.inc 31 - startDate.monthday + endDate.monthday - startDate = endDate - else: - while startDate.month < endDate.month: - let daysInMonth = getDaysInMonth(startDate.month.Month, startDate.year) - result.days.inc daysInMonth - startDate.monthday + 1 - startDate.month.inc - startDate.monthday = 1 - result.days.inc endDate.monthday - startDate.monthday - result.weeks = result.days div 7 - result.days = result.days mod 7 - startDate = endDate - - # Handle hours, minutes, seconds, milliseconds, microseconds and nanoseconds - let newStartDt = dateTime(startDate.year, startDate.month.Month, - startDate.monthday, startDt.hour, startDt.minute, startDt.second, - startDt.nanosecond, startDt.timezone) - let dur = endDt - newStartDt - let parts = toParts(dur) - # There can still be a full day in `parts` since `Duration` and `TimeInterval` - # models days differently. - result.hours = parts[Hours].int + parts[Days].int * 24 - result.minutes = parts[Minutes].int - result.seconds = parts[Seconds].int - result.milliseconds = parts[Milliseconds].int - result.microseconds = parts[Microseconds].int - result.nanoseconds = parts[Nanoseconds].int - -proc toParts*(ti: TimeInterval): TimeIntervalParts = - ## Converts a `TimeInterval` into an array consisting of its time units, - ## starting with nanoseconds and ending with years. - ## - ## This procedure is useful for converting `TimeInterval` values to strings. - ## E.g. then you need to implement custom interval printing - runnableExamples: - var tp = toParts(initTimeInterval(years = 1, nanoseconds = 123)) - doAssert tp[Years] == 1 - doAssert tp[Nanoseconds] == 123 - - var index = 0 - for name, value in fieldPairs(ti): - result[index.TimeUnit()] = value - index += 1 - -proc `$`*(ti: TimeInterval): string = - ## Get string representation of `TimeInterval`. - runnableExamples: - doAssert $initTimeInterval(years = 1, nanoseconds = 123) == - "1 year and 123 nanoseconds" - doAssert $initTimeInterval() == "0 nanoseconds" - - var parts: seq[string] = @[] - var tiParts = toParts(ti) - for unit in countdown(Years, Nanoseconds): - if tiParts[unit] != 0: - parts.add(stringifyUnit(tiParts[unit], unit)) - - result = humanizeParts(parts) - -proc nanoseconds*(nanos: int): TimeInterval {.inline.} = - ## TimeInterval of `nanos` nanoseconds. - initTimeInterval(nanoseconds = nanos) - -proc microseconds*(micros: int): TimeInterval {.inline.} = - ## TimeInterval of `micros` microseconds. - initTimeInterval(microseconds = micros) - -proc milliseconds*(ms: int): TimeInterval {.inline.} = - ## TimeInterval of `ms` milliseconds. - initTimeInterval(milliseconds = ms) - -proc seconds*(s: int): TimeInterval {.inline.} = - ## TimeInterval of `s` seconds. - ## - ## `echo getTime() + 5.seconds` - initTimeInterval(seconds = s) - -proc minutes*(m: int): TimeInterval {.inline.} = - ## TimeInterval of `m` minutes. - ## - ## `echo getTime() + 5.minutes` - initTimeInterval(minutes = m) - -proc hours*(h: int): TimeInterval {.inline.} = - ## TimeInterval of `h` hours. - ## - ## `echo getTime() + 2.hours` - initTimeInterval(hours = h) - -proc days*(d: int): TimeInterval {.inline.} = - ## TimeInterval of `d` days. - ## - ## `echo getTime() + 2.days` - initTimeInterval(days = d) - -proc weeks*(w: int): TimeInterval {.inline.} = - ## TimeInterval of `w` weeks. - ## - ## `echo getTime() + 2.weeks` - initTimeInterval(weeks = w) - -proc months*(m: int): TimeInterval {.inline.} = - ## TimeInterval of `m` months. - ## - ## `echo getTime() + 2.months` - initTimeInterval(months = m) - -proc years*(y: int): TimeInterval {.inline.} = - ## TimeInterval of `y` years. - ## - ## `echo getTime() + 2.years` - initTimeInterval(years = y) - -proc evaluateInterval(dt: DateTime, interval: TimeInterval): - tuple[adjDur, absDur: Duration] = - ## Evaluates how many nanoseconds the interval is worth - ## in the context of `dt`. - ## The result in split into an adjusted diff and an absolute diff. - var months = interval.years * 12 + interval.months - var curYear = dt.year - var curMonth = dt.month - result = default(tuple[adjDur, absDur: Duration]) - # Subtracting - if months < 0: - for mth in countdown(-1 * months, 1): - if curMonth == mJan: - curMonth = mDec - curYear.dec - else: - curMonth.dec() - let days = getDaysInMonth(curMonth, curYear) - result.adjDur = result.adjDur - initDuration(days = days) - # Adding - else: - for mth in 1 .. months: - let days = getDaysInMonth(curMonth, curYear) - result.adjDur = result.adjDur + initDuration(days = days) - if curMonth == mDec: - curMonth = mJan - curYear.inc - else: - curMonth.inc() - - result.adjDur = result.adjDur + initDuration( - days = interval.days, - weeks = interval.weeks) - result.absDur = initDuration( - nanoseconds = interval.nanoseconds, - microseconds = interval.microseconds, - milliseconds = interval.milliseconds, - seconds = interval.seconds, - minutes = interval.minutes, - hours = interval.hours) - -proc `+`*(dt: DateTime, interval: TimeInterval): DateTime = - ## Adds `interval` to `dt`. Components from `interval` are added - ## in the order of their size, i.e. first the `years` component, then the - ## `months` component and so on. The returned `DateTime` will have the - ## same timezone as the input. - ## - ## Note that when adding months, monthday overflow is allowed. This means that - ## if the resulting month doesn't have enough days it, the month will be - ## incremented and the monthday will be set to the number of days overflowed. - ## So adding one month to `31 October` will result in `31 November`, which - ## will overflow and result in `1 December`. - runnableExamples: - let dt = dateTime(2017, mMar, 30, 00, 00, 00, 00, utc()) - doAssert $(dt + 1.months) == "2017-04-30T00:00:00Z" - # This is correct and happens due to monthday overflow. - doAssert $(dt - 1.months) == "2017-03-02T00:00:00Z" - let (adjDur, absDur) = evaluateInterval(dt, interval) - - if adjDur != DurationZero: - var zt = dt.timezone.zonedTimeFromAdjTime(dt.toAdjTime + adjDur) - if absDur != DurationZero: - zt = dt.timezone.zonedTimeFromTime(zt.time + absDur) - result = initDateTime(zt, dt.timezone) - else: - result = initDateTime(zt, dt.timezone) - else: - var zt = dt.timezone.zonedTimeFromTime(dt.toTime + absDur) - result = initDateTime(zt, dt.timezone) - -proc `-`*(dt: DateTime, interval: TimeInterval): DateTime = - ## Subtract `interval` from `dt`. Components from `interval` are - ## subtracted in the order of their size, i.e. first the `years` component, - ## then the `months` component and so on. The returned `DateTime` will - ## have the same timezone as the input. - runnableExamples: - let dt = dateTime(2017, mMar, 30, 00, 00, 00, 00, utc()) - doAssert $(dt - 5.days) == "2017-03-25T00:00:00Z" - - dt + (-interval) - -proc `+`*(time: Time, interval: TimeInterval): Time = - ## Adds `interval` to `time`. - ## If `interval` contains any years, months, weeks or days the operation - ## is performed in the local timezone. - runnableExamples: - let tm = fromUnix(0) - doAssert tm + 5.seconds == fromUnix(5) - - if interval.isStaticInterval: - time + evaluateStaticInterval(interval) - else: - toTime(time.local + interval) - -proc `-`*(time: Time, interval: TimeInterval): Time = - ## Subtracts `interval` from Time `time`. - ## If `interval` contains any years, months, weeks or days the operation - ## is performed in the local timezone. - runnableExamples: - let tm = fromUnix(5) - doAssert tm - 5.seconds == fromUnix(0) - - if interval.isStaticInterval: - time - evaluateStaticInterval(interval) - else: - toTime(time.local - interval) - -proc `+=`*(a: var DateTime, b: TimeInterval) = - a = a + b - -proc `-=`*(a: var DateTime, b: TimeInterval) = - a = a - b - -proc `+=`*(t: var Time, b: TimeInterval) = - t = t + b - -proc `-=`*(t: var Time, b: TimeInterval) = - t = t - b - -# -# Day of year -# - -proc initDateTime*(weekday: WeekDay, isoweek: IsoWeekRange, isoyear: IsoYear, - hour: HourRange, minute: MinuteRange, second: SecondRange, - nanosecond: NanosecondRange, - zone: Timezone = local()): DateTime {.since: (1, 5).} = - ## Create a new `DateTime <#DateTime>`_ from a weekday and an ISO 8601 week number and year - ## in the specified timezone. - ## - ## .. warning:: The ISO week-based year can correspond to the following or previous year from 29 December to January 3. - runnableExamples: - assert initDateTime(21, mApr, 2018, 00, 00, 00) == initDateTime(dSat, 16, 2018.IsoYear, 00, 00, 00) - assert initDateTime(30, mDec, 2019, 00, 00, 00) == initDateTime(dMon, 01, 2020.IsoYear, 00, 00, 00) - assert initDateTime(13, mSep, 2020, 00, 00, 00) == initDateTime(dSun, 37, 2020.IsoYear, 00, 00, 00) - assert initDateTime(2, mJan, 2021, 00, 00, 00) == initDateTime(dSat, 53, 2020.IsoYear, 00, 00, 00) - - # source https://webspace.science.uu.nl/~gent0113/calendar/isocalendar.htm - let d = isoweek * 7 + weekday.int - initDateTime(4, mJan, isoyear.int, 00, 00, 00).weekday.int - 4 - initDateTime(1, mJan, isoyear.int, hour, minute, second, nanosecond, zone) + initTimeInterval(days=d) - -proc initDateTime*(weekday: WeekDay, isoweek: IsoWeekRange, isoyear: IsoYear, - hour: HourRange, minute: MinuteRange, second: SecondRange, - zone: Timezone = local()): DateTime {.since: (1, 5).} = - initDateTime(weekday, isoweek, isoyear, hour, minute, second, 0, zone) - -# -# Other -# - -proc epochTime*(): float {.tags: [TimeEffect].} = - ## Gets time after the UNIX epoch (1970) in seconds. It is a float - ## because sub-second resolution is likely to be supported (depending - ## on the hardware/OS). - ## - ## `getTime` should generally be preferred over this proc. - ## - ## .. warning:: Unsuitable for benchmarking (but still better than `now`), - ## use `monotimes.getMonoTime` or `cpuTime` instead, depending on the use case. - when defined(macosx): - var a {.noinit.}: Timeval - gettimeofday(a) - result = toBiggestFloat(a.tv_sec.int64) + toBiggestFloat( - a.tv_usec)*0.00_0001 - elif defined(posix): - var ts {.noinit.}: Timespec - discard clock_gettime(CLOCK_REALTIME, ts) - result = toBiggestFloat(ts.tv_sec.int64) + - toBiggestFloat(ts.tv_nsec.int64) / 1_000_000_000 - elif defined(windows): - var f {.noinit.}: winlean.FILETIME - getSystemTimeAsFileTime(f) - var i64 = rdFileTime(f) - epochDiff - var secs = i64 div rateDiff - var subsecs = i64 mod rateDiff - result = toFloat(int(secs)) + toFloat(int(subsecs)) * 0.0000001 - elif defined(js): - result = newDate().getTime() / 1000 - else: - {.error: "unknown OS".} + let a = fromUnix(10) + let b = fromUnix(1_500_000_000) + let ti = b.toTimeInterval() - a.toTimeInterval() + doAssert a + ti == b + var dt = time.local + initTimeInterval(dt.nanosecond, 0, 0, dt.second, dt.minute, dt.hour, + dt.monthday, 0, dt.month.ord - 1, dt.year) when not defined(js): type @@ -2718,12 +2533,12 @@ when not defined(js): clocksPerSec {.importc: "CLOCKS_PER_SEC", nodecl, used.}: int proc cpuTime*(): float {.tags: [TimeEffect].} = - ## Gets time spent that the CPU spent to run the current process in - ## seconds. This may be more useful for benchmarking than `epochTime`. + ## gets time spent that the CPU spent to run the current process in + ## seconds. This may be more useful for benchmarking than ``epochTime``. ## However, it may measure the real time instead (depending on the OS). ## The value of the result has no meaning. ## To generate useful timing values, take the difference between - ## the results of two `cpuTime` calls: + ## the results of two ``cpuTime`` calls: runnableExamples: var t0 = cpuTime() # some useless work here (calculate fibonacci) @@ -2732,8 +2547,6 @@ when not defined(js): fib.add(fib[^1] + fib[^2]) echo "CPU time [s] ", cpuTime() - t0 echo "Fib is [s] ", fib - ## When the flag `--benchmarkVM` is passed to the compiler, this proc is - ## also available at compile time when defined(posix) and not defined(osx) and declared(CLOCK_THREAD_CPUTIME_ID): # 'clocksPerSec' is a compile-time constant, possibly a # rather awful one, so use clock_gettime instead @@ -2744,43 +2557,243 @@ when not defined(js): else: result = toFloat(int(getClock())) / toFloat(clocksPerSec) + proc epochTime*(): float {.tags: [TimeEffect].} = + ## gets time after the UNIX epoch (1970) in seconds. It is a float + ## because sub-second resolution is likely to be supported (depending + ## on the hardware/OS). + ## + ## ``getTime`` should generally be preferred over this proc. + when defined(macosx): + var a: Timeval + gettimeofday(a) + result = toBiggestFloat(a.tv_sec.int64) + toBiggestFloat( + a.tv_usec)*0.00_0001 + elif defined(posix): + var ts: Timespec + discard clock_gettime(CLOCK_REALTIME, ts) + result = toBiggestFloat(ts.tv_sec.int64) + + toBiggestFloat(ts.tv_nsec.int64) / 1_000_000_000 + elif defined(windows): + var f: winlean.FILETIME + getSystemTimeAsFileTime(f) + var i64 = rdFileTime(f) - epochDiff + var secs = i64 div rateDiff + var subsecs = i64 mod rateDiff + result = toFloat(int(secs)) + toFloat(int(subsecs)) * 0.0000001 + else: + {.error: "unknown OS".} -# -# Deprecations -# +when defined(js): + proc epochTime*(): float {.tags: [TimeEffect].} = + newDate().getTime() / 1000 -proc `nanosecond=`*(dt: var DateTime, value: NanosecondRange) {.deprecated: "Deprecated since v1.3.1".} = - dt.nanosecond = value +# Deprecated procs -proc `second=`*(dt: var DateTime, value: SecondRange) {.deprecated: "Deprecated since v1.3.1".} = - dt.second = value +proc weeks*(dur: Duration): int64 + {.inline, deprecated: "Use `inWeeks` instead".} = + ## Number of whole weeks represented by the duration. + ## + ## **Deprecated since version v0.20.0**: Use the `inWeeks proc + ## <#inWeeks,Duration>`_ instead. + runnableExamples: + let dur = initDuration(weeks = 1, days = 2, hours = 3, minutes = 4) + doAssert dur.weeks == 1 + dur.inWeeks -proc `minute=`*(dt: var DateTime, value: MinuteRange) {.deprecated: "Deprecated since v1.3.1".} = - dt.minute = value +proc days*(dur: Duration): int64 + {.inline, deprecated: "Use `inDays` instead".} = + ## Number of whole days represented by the duration. + ## + ## **Deprecated since version v0.20.0**: Use the `inDays proc + ## <#inDays,Duration>`_ instead. + runnableExamples: + let dur = initDuration(weeks = 1, days = 2, hours = 3, minutes = 4) + doAssert dur.days == 9 + dur.inDays -proc `hour=`*(dt: var DateTime, value: HourRange) {.deprecated: "Deprecated since v1.3.1".} = - dt.hour = value +proc hours*(dur: Duration): int64 + {.inline, deprecated: "Use `inHours` instead".} = + ## Number of whole hours represented by the duration. + ## + ## **Deprecated since version v0.20.0**: Use the `inHours proc + ## <#inHours,Duration>`_ instead. + runnableExamples: + let dur = initDuration(days = 1, hours = 2, minutes = 3) + doAssert dur.hours == 26 + dur.inHours -proc `monthdayZero=`*(dt: var DateTime, value: int) {.deprecated: "Deprecated since v1.3.1".} = - dt.monthdayZero = value +proc minutes*(dur: Duration): int64 + {.inline, deprecated: "Use `inMinutes` instead".} = + ## Number of whole minutes represented by the duration. + ## + ## **Deprecated since version v0.20.0**: Use the `inMinutes proc + ## <#inMinutes,Duration>`_ instead. + runnableExamples: + let dur = initDuration(days = 1, hours = 2, minutes = 3) + doAssert dur.minutes == 1563 + dur.inMinutes -proc `monthZero=`*(dt: var DateTime, value: int) {.deprecated: "Deprecated since v1.3.1".} = - dt.monthZero = value +proc seconds*(dur: Duration): int64 + {.inline, deprecated: "Use `inSeconds` instead".} = + ## Number of whole seconds represented by the duration. + ## + ## **Deprecated since version v0.20.0**: Use the `inSeconds proc + ## <#inSeconds,Duration>`_ instead. + runnableExamples: + let dur = initDuration(minutes = 10, seconds = 30) + doAssert dur.seconds == 630 + dur.inSeconds -proc `year=`*(dt: var DateTime, value: int) {.deprecated: "Deprecated since v1.3.1".} = - dt.year = value +proc milliseconds*(dur: Duration): int {.inline, deprecated.} = + ## Number of whole milliseconds represented by the **fractional** + ## part of the duration. + ## + ## **Deprecated since version v0.20.0**. + runnableExamples: + let dur = initDuration(minutes = 5, seconds = 6, milliseconds = 7, + microseconds = 8, nanoseconds = 9) + doAssert dur.milliseconds == 7 + result = convert(Nanoseconds, Milliseconds, dur.nanosecond) -proc `weekday=`*(dt: var DateTime, value: WeekDay) {.deprecated: "Deprecated since v1.3.1".} = - dt.weekday = value +proc microseconds*(dur: Duration): int {.inline, deprecated.} = + ## Number of whole microseconds represented by the **fractional** + ## part of the duration. + ## + ## **Deprecated since version v0.20.0**. + runnableExamples: + let dur = initDuration(minutes = 5, seconds = 6, milliseconds = 7, + microseconds = 8, nanoseconds = 9) + doAssert dur.microseconds == 7008 + result = convert(Nanoseconds, Microseconds, dur.nanosecond) -proc `yearday=`*(dt: var DateTime, value: YeardayRange) {.deprecated: "Deprecated since v1.3.1".} = - dt.yearday = value +proc nanoseconds*(dur: Duration): NanosecondRange {.inline, deprecated.} = + ## Number of whole microseconds represented by the **fractional** + ## part of the duration. + ## + ## **Deprecated since version v0.20.0**. + runnableExamples: + let dur = initDuration(minutes = 5, seconds = 6, milliseconds = 7, + microseconds = 8, nanoseconds = 9) + doAssert dur.nanoseconds == 7008009 + dur.nanosecond -proc `isDst=`*(dt: var DateTime, value: bool) {.deprecated: "Deprecated since v1.3.1".} = - dt.isDst = value +proc fractional*(dur: Duration): Duration {.inline, deprecated.} = + ## The fractional part of `dur`, as a duration. + ## + ## **Deprecated since version v0.20.0**. + runnableExamples: + let dur = initDuration(minutes = 5, seconds = 6, milliseconds = 7, + microseconds = 8, nanoseconds = 9) + doAssert dur.fractional == initDuration(milliseconds = 7, microseconds = 8, + nanoseconds = 9) + initDuration(nanoseconds = dur.nanosecond) -proc `timezone=`*(dt: var DateTime, value: Timezone) {.deprecated: "Deprecated since v1.3.1".} = - dt.timezone = value +when not defined(js): + proc unixTimeToWinTime*(time: CTime): int64 + {.deprecated: "Use toWinTime instead".} = + ## Converts a UNIX `Time` (``time_t``) to a Windows file time + ## + ## **Deprecated:** use ``toWinTime`` instead. + result = int64(time) * rateDiff + epochDiff -proc `utcOffset=`*(dt: var DateTime, value: int) {.deprecated: "Deprecated since v1.3.1".} = - dt.utcOffset = value + proc winTimeToUnixTime*(time: int64): CTime + {.deprecated: "Use fromWinTime instead".} = + ## Converts a Windows time to a UNIX `Time` (``time_t``) + ## + ## **Deprecated:** use ``fromWinTime`` instead. + result = CTime((time - epochDiff) div rateDiff) + +proc initInterval*(seconds, minutes, hours, days, months, years: int = 0): + TimeInterval {.deprecated.} = + ## **Deprecated since v0.18.0:** use ``initTimeInterval`` instead. + initTimeInterval(0, 0, 0, seconds, minutes, hours, days, 0, months, years) + +proc fromSeconds*(since1970: float): Time + {.tags: [], raises: [], benign, deprecated: "Use fromUnixFloat or fromUnix".} = + ## Takes a float which contains the number of seconds since the unix epoch and + ## returns a time object. + ## + ## **Deprecated since v0.18.0:** use ``fromUnix`` instead + fromUnixFloat(since1970) + +proc fromSeconds*(since1970: int64): Time + {.tags: [], raises: [], benign, deprecated.} = + ## Takes an int which contains the number of seconds since the unix epoch and + ## returns a time object. + ## + ## **Deprecated since v0.18.0:** use ``fromUnix`` instead + fromUnix(since1970) + +proc toSeconds*(time: Time): float + {.tags: [], raises: [], benign, deprecated: "Use toUnixFloat or toUnix".} = + ## Returns the time in seconds since the unix epoch, with subsecond resolution. + toUnixFloat(time) + +proc getLocalTime*(time: Time): DateTime + {.tags: [], raises: [], benign, deprecated.} = + ## Converts the calendar time `time` to broken-time representation, + ## expressed relative to the user's specified time zone. + ## + ## **Deprecated since v0.18.0:** use ``local`` instead + time.local + +proc getGMTime*(time: Time): DateTime + {.tags: [], raises: [], benign, deprecated.} = + ## Converts the calendar time `time` to broken-down time representation, + ## expressed in Coordinated Universal Time (UTC). + ## + ## **Deprecated since v0.18.0:** use ``utc`` instead + time.utc + +proc getTimezone*(): int + {.tags: [TimeEffect], raises: [], benign, deprecated.} = + ## Returns the offset of the local (non-DST) timezone in seconds west of UTC. + ## + ## **Deprecated since v0.18.0:** use ``now().utcOffset`` to get the current + ## utc offset (including DST). + when defined(js): + return newDate().getTimezoneOffset() * 60 + elif defined(freebsd) or defined(netbsd) or defined(openbsd): + # This is wrong since it will include DST offsets, but the behavior has + # always been wrong for bsd and the proc is deprecated so lets ignore it. + return now().utcOffset + else: + return timezone + +proc getDayOfWeek*(day, month, year: int): WeekDay + {.tags: [], raises: [], benign, deprecated.} = + ## **Deprecated since v0.18.0:** use + ## ``getDayOfWeek(monthday: MonthdayRange; month: Month; year: int)`` instead. + getDayOfWeek(day, month.Month, year) + +proc getDayOfWeekJulian*(day, month, year: int): WeekDay {.deprecated.} = + ## Returns the day of the week enum from day, month and year, + ## according to the Julian calendar. + ## **Deprecated since v0.18.0** + # Day & month start from one. + let + a = (14 - month) div 12 + y = year - a + m = month + (12*a) - 2 + d = (5 + day + y + (y div 4) + (31*m) div 12) mod 7 + result = d.WeekDay + +proc adjTime*(zt: ZonedTime): Time + {.deprecated: "Use zt.time instead".} = + ## **Deprecated since v0.19.0:** use the ``time`` field instead. + zt.time - initDuration(seconds = zt.utcOffset) + +proc `adjTime=`*(zt: var ZonedTime, adjTime: Time) + {.deprecated: "Use zt.time instead".} = + ## **Deprecated since v0.19.0:** use the ``time`` field instead. + zt.time = adjTime + initDuration(seconds = zt.utcOffset) + +proc zoneInfoFromUtc*(zone: Timezone, time: Time): ZonedTime + {.deprecated: "Use zonedTimeFromTime instead".} = + ## **Deprecated since v0.19.0:** use ``zonedTimeFromTime`` instead. + zone.zonedTimeFromTime(time) + +proc zoneInfoFromTz*(zone: Timezone, adjTime: Time): ZonedTime + {.deprecated: "Use zonedTimeFromAdjTime instead".} = + ## **Deprecated since v0.19.0:** use the ``zonedTimeFromAdjTime`` instead. + zone.zonedTimeFromAdjTime(adjTime) diff --git a/lib/pure/typetraits.nim b/lib/pure/typetraits.nim index c20f9e645..fd729b59e 100644 --- a/lib/pure/typetraits.nim +++ b/lib/pure/typetraits.nim @@ -12,314 +12,122 @@ ## ## Unstable API. -import std/private/since export system.`$` # for backward compatibility -when defined(nimPreviewSlimSystem): - import std/assertions +include "system/inclrtl" - -type HoleyEnum* = (not Ordinal) and enum ## Enum with holes. -type OrdinalEnum* = Ordinal and enum ## Enum without holes. - -runnableExamples: - type A = enum a0 = 2, a1 = 4, a2 - type B = enum b0 = 2, b1, b2 - assert A is enum - assert A is HoleyEnum - assert A isnot OrdinalEnum - assert B isnot HoleyEnum - assert B is OrdinalEnum - assert int isnot HoleyEnum - type C[T] = enum h0 = 2, h1 = 4 - assert C[float] is HoleyEnum - -proc name*(t: typedesc): string {.magic: "TypeTrait".} = - ## Returns the name of `t`. +proc name*(t: typedesc): string {.magic: "TypeTrait".} + ## Returns the name of the given type. ## - ## Alias for `system.\`$\`(t) `_ since Nim v0.20. - runnableExamples: - doAssert name(int) == "int" - doAssert name(seq[string]) == "seq[string]" + ## Alias for system.`$`(t) since Nim v0.20. proc arity*(t: typedesc): int {.magic: "TypeTrait".} = - ## Returns the arity of `t`. This is the number of "type" - ## components or the number of generic parameters a given type `t` has. + ## Returns the arity of the given type. This is the number of "type" + ## components or the number of generic parameters a given type ``t`` has. runnableExamples: - doAssert arity(int) == 0 - doAssert arity(seq[string]) == 1 - doAssert arity(array[3, int]) == 2 - doAssert arity((int, int, float, string)) == 4 + assert arity(seq[string]) == 1 + assert arity(array[3, int]) == 2 + assert arity((int, int, float, string)) == 4 -proc genericHead*(t: typedesc): typedesc {.magic: "TypeTrait".} = +proc genericHead*(t: typedesc): typedesc {.magic: "TypeTrait".} ## Accepts an instantiated generic type and returns its ## uninstantiated form. + ## + ## For example: + ## * `seq[int].genericHead` will be just `seq` + ## * `seq[int].genericHead[float]` will be `seq[float]` + ## ## A compile-time error will be produced if the supplied type ## is not generic. ## - ## **See also:** - ## * `stripGenericParams proc <#stripGenericParams,typedesc>`_ - runnableExamples: - type - Foo[T] = object - FooInst = Foo[int] - Foo2 = genericHead(FooInst) + ## See also: + ## * `stripGenericParams <#stripGenericParams,typedesc>`_ + ## + ## Example: + ## + ## .. code-block:: nim + ## type + ## Functor[A] = concept f + ## type MatchedGenericType = genericHead(f.type) + ## # `f` will be a value of a type such as `Option[T]` + ## # `MatchedGenericType` will become the `Option` type - doAssert Foo2 is Foo and Foo is Foo2 - doAssert genericHead(Foo[seq[string]]) is Foo - doAssert not compiles(genericHead(int)) - type Generic = concept f - type _ = genericHead(typeof(f)) - - proc bar(a: Generic): typeof(a) = a - - doAssert bar(Foo[string].default) == Foo[string]() - doAssert not compiles bar(string.default) - - when false: # these don't work yet - doAssert genericHead(Foo[int])[float] is Foo[float] - doAssert seq[int].genericHead is seq - -proc stripGenericParams*(t: typedesc): typedesc {.magic: "TypeTrait".} = +proc stripGenericParams*(t: typedesc): typedesc {.magic: "TypeTrait".} ## This trait is similar to `genericHead <#genericHead,typedesc>`_, but - ## instead of producing an error for non-generic types, it will just return + ## instead of producing error for non-generic types, it will just return ## them unmodified. - runnableExamples: - type Foo[T] = object - - doAssert stripGenericParams(Foo[string]) is Foo - doAssert stripGenericParams(int) is int proc supportsCopyMem*(t: typedesc): bool {.magic: "TypeTrait".} - ## Returns true if `t` is safe to use for `copyMem`:idx:. + ## This trait returns true iff the type ``t`` is safe to use for + ## `copyMem`:idx:. ## ## Other languages name a type like these `blob`:idx:. -proc isNamedTuple*(T: typedesc): bool {.magic: "TypeTrait".} = - ## Returns true for named tuples, false for any other type. - runnableExamples: - doAssert not isNamedTuple(int) - doAssert not isNamedTuple((string, int)) - doAssert isNamedTuple(tuple[name: string, age: int]) +proc isNamedTuple*(T: typedesc): bool {.magic: "TypeTrait".} + ## Return true for named tuples, false for any other type. -template pointerBase*[T](_: typedesc[ptr T | ref T]): typedesc = - ## Returns `T` for `ref T | ptr T`. - runnableExamples: - assert (ref int).pointerBase is int - type A = ptr seq[float] - assert A.pointerBase is seq[float] - assert (ref A).pointerBase is A # not seq[float] - assert (var s = "abc"; s[0].addr).typeof.pointerBase is char - T +proc distinctBase*(T: typedesc): typedesc {.magic: "TypeTrait".} + ## Returns base type for distinct types, works only for distinct types. + ## compile time error otherwise -proc distinctBase*(T: typedesc, recursive: static bool = true): typedesc {.magic: "TypeTrait".} = - ## Returns the base type for distinct types, or the type itself otherwise. - ## If `recursive` is false, only the immediate distinct base will be returned. - ## - ## **See also:** - ## * `distinctBase template <#distinctBase.t,T,static[bool]>`_ - runnableExamples: - type MyInt = distinct int - type MyOtherInt = distinct MyInt - doAssert distinctBase(MyInt) is int - doAssert distinctBase(MyOtherInt) is int - doAssert distinctBase(MyOtherInt, false) is MyInt - doAssert distinctBase(int) is int +import std/macros + +macro lenTuple*(t: tuple): int {.since: (1, 1).} = + ## Return number of elements of `t` + newLit t.len + +macro lenTuple*(t: typedesc[tuple]): int {.since: (1, 1).} = + ## Return number of elements of `T` + newLit t.len since (1, 1): - template distinctBase*[T](a: T, recursive: static bool = true): untyped = - ## Overload of `distinctBase <#distinctBase,typedesc,static[bool]>`_ for values. - runnableExamples: - type MyInt = distinct int - type MyOtherInt = distinct MyInt - doAssert 12.MyInt.distinctBase == 12 - doAssert 12.MyOtherInt.distinctBase == 12 - doAssert 12.MyOtherInt.distinctBase(false) is MyInt - doAssert 12.distinctBase == 12 - when T is distinct: - distinctBase(typeof(a), recursive)(a) - else: # avoids hint ConvFromXtoItselfNotNeeded - a - - proc tupleLen*(T: typedesc[tuple]): int {.magic: "TypeTrait".} = - ## Returns the number of elements of the tuple type `T`. - ## - ## **See also:** - ## * `tupleLen template <#tupleLen.t>`_ - runnableExamples: - doAssert tupleLen((int, int, float, string)) == 4 - doAssert tupleLen(tuple[name: string, age: int]) == 2 - - template tupleLen*(t: tuple): int = - ## Returns the number of elements of the tuple `t`. - ## - ## **See also:** - ## * `tupleLen proc <#tupleLen,typedesc>`_ - runnableExamples: - doAssert tupleLen((1, 2)) == 2 - - tupleLen(typeof(t)) - template get*(T: typedesc[tuple], i: static int): untyped = - ## Returns the `i`-th element of `T`. + ## Return `i`th element of `T` # Note: `[]` currently gives: `Error: no generic parameters allowed for ...` - runnableExamples: - doAssert get((int, int, float, string), 2) is float + type(default(T)[i]) - typeof(default(T)[i]) - - type StaticParam*[value: static type] = object - ## Used to wrap a static value in `genericParams <#genericParams.t,typedesc>`_. - -since (1, 3, 5): - template elementType*(a: untyped): typedesc = - ## Returns the element type of `a`, which can be any iterable (over which you - ## can iterate). - runnableExamples: - iterator myiter(n: int): auto = - for i in 0 ..< n: - yield i - - doAssert elementType(@[1,2]) is int - doAssert elementType("asdf") is char - doAssert elementType(myiter(3)) is int - - typeof(block: (for ai in a: ai)) - -import macros - -macro enumLen*(T: typedesc[enum]): int = - ## Returns the number of items in the enum `T`. +macro genericParams*(T: typedesc): untyped {.since: (1, 1).} = + ## return tuple of generic params for generic `T` runnableExamples: - type Foo = enum - fooItem1 - fooItem2 - - doAssert Foo.enumLen == 2 - - let bracketExpr = getType(T) - expectKind(bracketExpr, nnkBracketExpr) - let enumTy = bracketExpr[1] - expectKind(enumTy, nnkEnumTy) - result = newLit(enumTy.len - 1) - -macro genericParamsImpl(T: typedesc): untyped = - # auxiliary macro needed, can't do it directly in `genericParams` + type Foo[T1, T2]=object + doAssert genericParams(Foo[float, string]) is (float, string) result = newNimNode(nnkTupleConstr) var impl = getTypeImpl(T) expectKind(impl, nnkBracketExpr) impl = impl[1] while true: case impl.kind - of nnkSym: - impl = impl.getImpl - of nnkTypeDef: - impl = impl[2] - of nnkTypeOfExpr: - impl = getTypeInst(impl[0]) - of nnkBracketExpr: - for i in 1..`_ ## * `encodings module `_ -include "system/inclrtl" -import std/strbasics -template toOa(s: string): auto = s.toOpenArray(0, s.high) -proc substr(s: openArray[char] , first, last: int): string = - # Copied substr from system - let first = max(first, 0) - let L = max(min(last, high(s)) - first + 1, 0) - result = newString(L) - for i in 0 .. L-1: - result[i] = s[i+first] +{.deadCodeElim: on.} # dce option deprecated + +include "system/inclrtl" type RuneImpl = int32 # underlying type of Rune @@ -38,18 +31,16 @@ type ## Type that can hold a single Unicode code point. ## ## A Rune may be composed with other Runes to a character on the screen. - ## `RuneImpl` is the underlying type used to store Runes, currently `int32`. template ones(n: untyped): untyped = ((1 shl n)-1) -proc runeLen*(s: openArray[char]): int {.rtl, extern: "nuc$1".} = +proc runeLen*(s: string): int {.rtl, extern: "nuc$1".} = ## Returns the number of runes of the string ``s``. runnableExamples: let a = "añyóng" doAssert a.runeLen == 6 ## note: a.len == 8 - result = 0 var i = 0 while i < len(s): if uint(s[i]) <= 127: inc(i) @@ -61,7 +52,7 @@ proc runeLen*(s: openArray[char]): int {.rtl, extern: "nuc$1".} = else: inc i inc(result) -proc runeLenAt*(s: openArray[char], i: Natural): int = +proc runeLenAt*(s: string, i: Natural): int = ## Returns the number of bytes the rune starting at ``s[i]`` takes. ## ## See also: @@ -81,7 +72,7 @@ proc runeLenAt*(s: openArray[char], i: Natural): int = const replRune = Rune(0xFFFD) -template fastRuneAt*(s: openArray[char] or string, i: int, result: untyped, doInc = true) = +template fastRuneAt*(s: string, i: int, result: untyped, doInc = true) = ## Returns the rune ``s[i]`` in ``result``. ## ## If ``doInc == true`` (default), ``i`` is incremented by the number @@ -159,7 +150,7 @@ template fastRuneAt*(s: openArray[char] or string, i: int, result: untyped, doIn result = Rune(uint(s[i])) when doInc: inc(i) -proc runeAt*(s: openArray[char], i: Natural): Rune = +proc runeAt*(s: string, i: Natural): Rune = ## Returns the rune in ``s`` at **byte index** ``i``. ## ## See also: @@ -173,7 +164,7 @@ proc runeAt*(s: openArray[char], i: Natural): Rune = doAssert a.runeAt(3) == "y".runeAt(0) fastRuneAt(s, i, result, false) -proc validateUtf8*(s: openArray[char]): int = +proc validateUtf8*(s: string): int = ## Returns the position of the invalid byte in ``s`` if the string ``s`` does ## not hold valid UTF-8 data. Otherwise ``-1`` is returned. ## @@ -310,7 +301,7 @@ proc `$`*(runes: seq[Rune]): string = for rune in runes: result.add rune -proc runeOffset*(s: openArray[char], pos: Natural, start: Natural = 0): int = +proc runeOffset*(s: string, pos: Natural, start: Natural = 0): int = ## Returns the byte position of rune ## at position ``pos`` in ``s`` with an optional start byte position. ## Returns the special value -1 if it runs out of the string. @@ -337,13 +328,13 @@ proc runeOffset*(s: openArray[char], pos: Natural, start: Natural = 0): int = inc i return o -proc runeReverseOffset*(s: openArray[char], rev: Positive): (int, int) = +proc runeReverseOffset*(s: string, rev: Positive): (int, int) = ## Returns a tuple with the byte offset of the ## rune at position ``rev`` in ``s``, counting ## from the end (starting with 1) and the total ## number of runes in the string. ## - ## Returns a negative value for offset if there are too few runes in + ## Returns a negative value for offset if there are to few runes in ## the string to satisfy the request. ## ## **Beware:** This can lead to unoptimized code and slow execution! @@ -356,16 +347,18 @@ proc runeReverseOffset*(s: openArray[char], rev: Positive): (int, int) = a = rev.int o = 0 x = 0 - let times = 2*rev.int-s.runeLen # transformed from rev.int - a < s.runeLen - rev.int while o < s.len: let r = runeLenAt(s, o) o += r - if a > times: + if a < 0: x += r dec a - result = if a > 0: (-a, rev.int-a) else: (x, -a+rev.int) -proc runeAtPos*(s: openArray[char], pos: int): Rune = + if a > 0: + return (-a, rev.int-a) + return (x, -a+rev.int) + +proc runeAtPos*(s: string, pos: int): Rune = ## Returns the rune at position ``pos``. ## ## **Beware:** This can lead to unoptimized code and slow execution! @@ -378,7 +371,7 @@ proc runeAtPos*(s: openArray[char], pos: int): Rune = ## * `fastRuneAt template <#fastRuneAt.t,string,int,untyped>`_ fastRuneAt(s, runeOffset(s, pos), result, false) -proc runeStrAtPos*(s: openArray[char], pos: Natural): string = +proc runeStrAtPos*(s: string, pos: Natural): string = ## Returns the rune at position ``pos`` as UTF8 String. ## ## **Beware:** This can lead to unoptimized code and slow execution! @@ -390,9 +383,9 @@ proc runeStrAtPos*(s: openArray[char], pos: Natural): string = ## * `runeAtPos proc <#runeAtPos,string,int>`_ ## * `fastRuneAt template <#fastRuneAt.t,string,int,untyped>`_ let o = runeOffset(s, pos) - substr(s.toOpenArray(o, (o+runeLenAt(s, o)-1))) + s[o .. (o+runeLenAt(s, o)-1)] -proc runeSubStr*(s: openArray[char], pos: int, len: int = int.high): string = +proc runeSubStr*(s: string, pos: int, len: int = int.high): string = ## Returns the UTF-8 substring starting at code point ``pos`` ## with ``len`` code points. ## @@ -411,7 +404,7 @@ proc runeSubStr*(s: openArray[char], pos: int, len: int = int.high): string = if pos < 0: let (o, rl) = runeReverseOffset(s, -pos) if len >= rl: - result = s.substr(o, s.high) + result = s.substr(o, s.len-1) elif len < 0: let e = rl + len if e < 0: @@ -479,7 +472,7 @@ proc binarySearch(c: RuneImpl, tab: openArray[int], len, stride: int): int = return t return -1 -proc toLower*(c: Rune): Rune {.rtl, extern: "nuc$1".} = +proc toLower*(c: Rune): Rune {.rtl, extern: "nuc$1", procvar.} = ## Converts ``c`` into lower case. This works for any rune. ## ## If possible, prefer ``toLower`` over ``toUpper``. @@ -497,7 +490,7 @@ proc toLower*(c: Rune): Rune {.rtl, extern: "nuc$1".} = return Rune(c + toLowerSinglets[p+1] - 500) return Rune(c) -proc toUpper*(c: Rune): Rune {.rtl, extern: "nuc$1".} = +proc toUpper*(c: Rune): Rune {.rtl, extern: "nuc$1", procvar.} = ## Converts ``c`` into upper case. This works for any rune. ## ## If possible, prefer ``toLower`` over ``toUpper``. @@ -515,7 +508,7 @@ proc toUpper*(c: Rune): Rune {.rtl, extern: "nuc$1".} = return Rune(c + toUpperSinglets[p+1] - 500) return Rune(c) -proc toTitle*(c: Rune): Rune {.rtl, extern: "nuc$1".} = +proc toTitle*(c: Rune): Rune {.rtl, extern: "nuc$1", procvar.} = ## Converts ``c`` to title case. ## ## See also: @@ -528,7 +521,7 @@ proc toTitle*(c: Rune): Rune {.rtl, extern: "nuc$1".} = return Rune(c + toTitleSinglets[p+1] - 500) return Rune(c) -proc isLower*(c: Rune): bool {.rtl, extern: "nuc$1".} = +proc isLower*(c: Rune): bool {.rtl, extern: "nuc$1", procvar.} = ## Returns true if ``c`` is a lower case rune. ## ## If possible, prefer ``isLower`` over ``isUpper``. @@ -546,7 +539,7 @@ proc isLower*(c: Rune): bool {.rtl, extern: "nuc$1".} = if p >= 0 and c == toUpperSinglets[p]: return true -proc isUpper*(c: Rune): bool {.rtl, extern: "nuc$1".} = +proc isUpper*(c: Rune): bool {.rtl, extern: "nuc$1", procvar.} = ## Returns true if ``c`` is a upper case rune. ## ## If possible, prefer ``isLower`` over ``isUpper``. @@ -566,7 +559,7 @@ proc isUpper*(c: Rune): bool {.rtl, extern: "nuc$1".} = if p >= 0 and c == toLowerSinglets[p]: return true -proc isAlpha*(c: Rune): bool {.rtl, extern: "nuc$1".} = +proc isAlpha*(c: Rune): bool {.rtl, extern: "nuc$1", procvar.} = ## Returns true if ``c`` is an *alpha* rune (i.e., a letter). ## ## See also: @@ -585,7 +578,7 @@ proc isAlpha*(c: Rune): bool {.rtl, extern: "nuc$1".} = if p >= 0 and c == alphaSinglets[p]: return true -proc isTitle*(c: Rune): bool {.rtl, extern: "nuc$1".} = +proc isTitle*(c: Rune): bool {.rtl, extern: "nuc$1", procvar.} = ## Returns true if ``c`` is a Unicode titlecase code point. ## ## See also: @@ -596,7 +589,7 @@ proc isTitle*(c: Rune): bool {.rtl, extern: "nuc$1".} = ## * `isWhiteSpace proc <#isWhiteSpace,Rune>`_ return isUpper(c) and isLower(c) -proc isWhiteSpace*(c: Rune): bool {.rtl, extern: "nuc$1".} = +proc isWhiteSpace*(c: Rune): bool {.rtl, extern: "nuc$1", procvar.} = ## Returns true if ``c`` is a Unicode whitespace code point. ## ## See also: @@ -609,7 +602,7 @@ proc isWhiteSpace*(c: Rune): bool {.rtl, extern: "nuc$1".} = if p >= 0 and c >= spaceRanges[p] and c <= spaceRanges[p+1]: return true -proc isCombining*(c: Rune): bool {.rtl, extern: "nuc$1".} = +proc isCombining*(c: Rune): bool {.rtl, extern: "nuc$1", procvar.} = ## Returns true if ``c`` is a Unicode combining code unit. ## ## See also: @@ -636,7 +629,7 @@ template runeCheck(s, runeProc) = fastRuneAt(s, i, rune, doInc = true) result = runeProc(rune) and result -proc isAlpha*(s: openArray[char]): bool {.noSideEffect, +proc isAlpha*(s: string): bool {.noSideEffect, procvar, rtl, extern: "nuc$1Str".} = ## Returns true if ``s`` contains all alphabetic runes. runnableExamples: @@ -644,7 +637,7 @@ proc isAlpha*(s: openArray[char]): bool {.noSideEffect, doAssert a.isAlpha runeCheck(s, isAlpha) -proc isSpace*(s: openArray[char]): bool {.noSideEffect, +proc isSpace*(s: string): bool {.noSideEffect, procvar, rtl, extern: "nuc$1Str".} = ## Returns true if ``s`` contains all whitespace runes. runnableExamples: @@ -665,21 +658,21 @@ template convertRune(s, runeProc) = rune = runeProc(rune) fastToUTF8Copy(rune, result, resultIndex, doInc = true) -proc toUpper*(s: openArray[char]): string {.noSideEffect, +proc toUpper*(s: string): string {.noSideEffect, procvar, rtl, extern: "nuc$1Str".} = ## Converts ``s`` into upper-case runes. runnableExamples: doAssert toUpper("abγ") == "ABΓ" convertRune(s, toUpper) -proc toLower*(s: openArray[char]): string {.noSideEffect, +proc toLower*(s: string): string {.noSideEffect, procvar, rtl, extern: "nuc$1Str".} = ## Converts ``s`` into lower-case runes. runnableExamples: doAssert toLower("ABΓ") == "abγ" convertRune(s, toLower) -proc swapCase*(s: openArray[char]): string {.noSideEffect, +proc swapCase*(s: string): string {.noSideEffect, procvar, rtl, extern: "nuc$1".} = ## Swaps the case of runes in ``s``. ## @@ -701,25 +694,22 @@ proc swapCase*(s: openArray[char]): string {.noSideEffect, rune = rune.toUpper() fastToUTF8Copy(rune, result, resultIndex, doInc = true) -proc capitalize*(s: openArray[char]): string {.noSideEffect, +proc capitalize*(s: string): string {.noSideEffect, procvar, rtl, extern: "nuc$1".} = ## Converts the first character of ``s`` into an upper-case rune. runnableExamples: doAssert capitalize("βeta") == "Βeta" if len(s) == 0: - return "" + return s var rune: Rune i = 0 fastRuneAt(s, i, rune, doInc = true) - result = $toUpper(rune) & substr(s.toOpenArray(i, s.high)) + result = $toUpper(rune) & substr(s, i) -when not defined(nimHasEffectsOf): - {.pragma: effectsOf.} - -proc translate*(s: openArray[char], replacements: proc(key: string): string): string {. - rtl, extern: "nuc$1", effectsOf: replacements.} = +proc translate*(s: string, replacements: proc(key: string): string): string {. + rtl, extern: "nuc$1".} = ## Translates words in a string using the ``replacements`` proc to substitute ## words inside ``s`` with their replacements. ## @@ -753,7 +743,7 @@ proc translate*(s: openArray[char], replacements: proc(key: string): string): st if whiteSpace and inWord: # If we've reached the end of a word - let word = substr(s.toOpenArray(wordStart, lastIndex - 1)) + let word = s[wordStart ..< lastIndex] result.add(replacements(word)) result.add($rune) inWord = false @@ -768,10 +758,10 @@ proc translate*(s: openArray[char], replacements: proc(key: string): string): st if wordStart < len(s) and inWord: # Get the trailing word at the end - let word = substr(s.toOpenArray(wordStart, s.high)) + let word = s[wordStart .. ^1] result.add(replacements(word)) -proc title*(s: openArray[char]): string {.noSideEffect, +proc title*(s: string): string {.noSideEffect, procvar, rtl, extern: "nuc$1".} = ## Converts ``s`` to a unicode title. ## @@ -797,7 +787,7 @@ proc title*(s: openArray[char]): string {.noSideEffect, fastToUTF8Copy(rune, result, resultIndex, doInc = true) -iterator runes*(s: openArray[char]): Rune = +iterator runes*(s: string): Rune = ## Iterates over any rune of the string ``s`` returning runes. var i = 0 @@ -806,7 +796,7 @@ iterator runes*(s: openArray[char]): Rune = fastRuneAt(s, i, result, true) yield result -iterator utf8*(s: openArray[char]): string = +iterator utf8*(s: string): string = ## Iterates over any rune of the string ``s`` returning utf8 values. ## ## See also: @@ -817,14 +807,14 @@ iterator utf8*(s: openArray[char]): string = var o = 0 while o < s.len: let n = runeLenAt(s, o) - yield substr(s.toOpenArray(o, (o+n-1))) + yield s[o .. (o+n-1)] o += n -proc toRunes*(s: openArray[char]): seq[Rune] = +proc toRunes*(s: string): seq[Rune] = ## Obtains a sequence containing the Runes in ``s``. ## ## See also: - ## * `$ proc <#$,Rune>`_ for a reverse operation + ## * `$ proc <#$,seq[T][Rune]>`_ for a reverse operation runnableExamples: let a = toRunes("aáä") doAssert a == @["a".runeAt(0), "á".runeAt(0), "ä".runeAt(0)] @@ -833,7 +823,7 @@ proc toRunes*(s: openArray[char]): seq[Rune] = for r in s.runes: result.add(r) -proc cmpRunesIgnoreCase*(a, b: openArray[char]): int {.rtl, extern: "nuc$1".} = +proc cmpRunesIgnoreCase*(a, b: string): int {.rtl, extern: "nuc$1", procvar.} = ## Compares two UTF-8 strings and ignores the case. Returns: ## ## | 0 if a == b @@ -850,7 +840,7 @@ proc cmpRunesIgnoreCase*(a, b: openArray[char]): int {.rtl, extern: "nuc$1".} = if result != 0: return result = a.len - b.len -proc reversed*(s: openArray[char]): string = +proc reversed*(s: string): string = ## Returns the reverse of ``s``, interpreting it as runes. ## ## Unicode combining characters are correctly interpreted as well. @@ -885,9 +875,9 @@ proc reversed*(s: openArray[char]): string = reverseUntil(len(s)) -proc graphemeLen*(s: openArray[char]; i: Natural): Natural = +proc graphemeLen*(s: string; i: Natural): Natural = ## The number of bytes belonging to byte index ``s[i]``, - ## including following combining code units. + ## including following combining code unit. runnableExamples: let a = "añyóng" doAssert a.graphemeLen(1) == 2 ## ñ @@ -904,7 +894,7 @@ proc graphemeLen*(s: openArray[char]; i: Natural): Natural = if not isCombining(r2): break result = j-i -proc lastRune*(s: openArray[char]; last: int): (Rune, int) = +proc lastRune*(s: string; last: int): (Rune, int) = ## Length of the last rune in ``s[0..last]``. Returns the rune and its length ## in bytes. if s[last] <= chr(127): @@ -933,61 +923,83 @@ proc size*(r: Rune): int {.noSideEffect.} = else: result = 1 # --------- Private templates for different split separators ----------- -proc stringHasSep(s: openArray[char], index: int, seps: openArray[Rune]): bool = +proc stringHasSep(s: string, index: int, seps: openArray[Rune]): bool = var rune: Rune fastRuneAt(s, index, rune, false) return seps.contains(rune) -proc stringHasSep(s: openArray[char], index: int, sep: Rune): bool = +proc stringHasSep(s: string, index: int, sep: Rune): bool = var rune: Rune fastRuneAt(s, index, rune, false) return sep == rune -template splitCommon(s, sep, maxsplit: untyped) = +template splitCommon(s, sep, maxsplit: untyped, sepLen: int = -1) = ## Common code for split procedures. - let - sLen = len(s) var last = 0 splits = maxsplit - if sLen > 0: - while last <= sLen: + if len(s) > 0: + while last <= len(s): var first = last - while last < sLen and not stringHasSep(s, last, sep): - inc(last, runeLenAt(s, last)) - if splits == 0: last = sLen - yield substr(s.toOpenArray(first, (last - 1))) + while last < len(s) and not stringHasSep(s, last, sep): + when sep is Rune: + inc(last, sepLen) + else: + inc(last, runeLenAt(s, last)) + if splits == 0: last = len(s) + yield s[first .. (last - 1)] if splits == 0: break dec(splits) - inc(last, if last < sLen: runeLenAt(s, last) else: 1) + when sep is Rune: + inc(last, sepLen) + else: + inc(last, if last < len(s): runeLenAt(s, last) else: 1) -iterator split*(s: openArray[char], seps: openArray[Rune] = unicodeSpaces, +iterator split*(s: string, seps: openArray[Rune] = unicodeSpaces, maxsplit: int = -1): string = ## Splits the unicode string ``s`` into substrings using a group of separators. ## ## Substrings are separated by a substring containing only ``seps``. - runnableExamples: - import std/sequtils - - assert toSeq("hÃllo\lthis\lis an\texample\l是".split) == - @["hÃllo", "this", "is", "an", "example", "是"] - - # And the following code splits the same string using a sequence of Runes. - assert toSeq(split("añyóng:hÃllo;是$example", ";:$".toRunes)) == - @["añyóng", "hÃllo", "是", "example"] - - # example with a `Rune` separator and unused one `;`: - assert toSeq(split("ab是de:f:", ";:是".toRunes)) == @["ab", "de", "f", ""] - - # Another example that splits a string containing a date. - let date = "2012-11-20T22:08:08.398990" - - assert toSeq(split(date, " -:T".toRunes)) == - @["2012", "11", "20", "22", "08", "08.398990"] - + ## + ## .. code-block:: nim + ## for word in split("this\lis an\texample"): + ## writeLine(stdout, word) + ## + ## ...generates this output: + ## + ## .. code-block:: + ## "this" + ## "is" + ## "an" + ## "example" + ## + ## And the following code: + ## + ## .. code-block:: nim + ## for word in split("this:is;an$example", {';', ':', '$'}): + ## writeLine(stdout, word) + ## + ## ...produces the same output as the first example. The code: + ## + ## .. code-block:: nim + ## let date = "2012-11-20T22:08:08.398990" + ## let separators = {' ', '-', ':', 'T'} + ## for number in split(date, separators): + ## writeLine(stdout, number) + ## + ## ...results in: + ## + ## .. code-block:: + ## "2012" + ## "11" + ## "20" + ## "22" + ## "08" + ## "08.398990" + ## splitCommon(s, seps, maxsplit) -iterator splitWhitespace*(s: openArray[char]): string = +iterator splitWhitespace*(s: string): string = ## Splits a unicode string at whitespace runes. splitCommon(s, unicodeSpaces, -1) @@ -995,36 +1007,51 @@ template accResult(iter: untyped) = result = @[] for x in iter: add(result, x) -proc splitWhitespace*(s: openArray[char]): seq[string] {.noSideEffect, +proc splitWhitespace*(s: string): seq[string] {.noSideEffect, rtl, extern: "ncuSplitWhitespace".} = ## The same as the `splitWhitespace <#splitWhitespace.i,string>`_ ## iterator, but is a proc that returns a sequence of substrings. accResult(splitWhitespace(s)) -iterator split*(s: openArray[char], sep: Rune, maxsplit: int = -1): string = +iterator split*(s: string, sep: Rune, maxsplit: int = -1): string = ## Splits the unicode string ``s`` into substrings using a single separator. + ## ## Substrings are separated by the rune ``sep``. - runnableExamples: - import std/sequtils + ## The code: + ## + ## .. code-block:: nim + ## for word in split(";;this;is;an;;example;;;", ';'): + ## writeLine(stdout, word) + ## + ## Results in: + ## + ## .. code-block:: + ## "" + ## "" + ## "this" + ## "is" + ## "an" + ## "" + ## "example" + ## "" + ## "" + ## "" + ## + splitCommon(s, sep, maxsplit, sep.size) - assert toSeq(split(";;hÃllo;this;is;an;;example;;;是", ";".runeAt(0))) == - @["", "", "hÃllo", "this", "is", "an", "", "example", "", "", "是"] - - splitCommon(s, sep, maxsplit) - -proc split*(s: openArray[char], seps: openArray[Rune] = unicodeSpaces, maxsplit: int = -1): +proc split*(s: string, seps: openArray[Rune] = unicodeSpaces, maxsplit: int = -1): seq[string] {.noSideEffect, rtl, extern: "nucSplitRunes".} = ## The same as the `split iterator <#split.i,string,openArray[Rune],int>`_, ## but is a proc that returns a sequence of substrings. accResult(split(s, seps, maxsplit)) -proc split*(s: openArray[char], sep: Rune, maxsplit: int = -1): seq[string] {.noSideEffect, +proc split*(s: string, sep: Rune, maxsplit: int = -1): seq[string] {.noSideEffect, rtl, extern: "nucSplitRune".} = ## The same as the `split iterator <#split.i,string,Rune,int>`_, but is a proc ## that returns a sequence of substrings. accResult(split(s, sep, maxsplit)) -proc strip*(s: openArray[char], leading = true, trailing = true, +proc strip*(s: string, leading = true, trailing = true, runes: openArray[Rune] = unicodeSpaces): string {.noSideEffect, rtl, extern: "nucStrip".} = ## Strips leading or trailing ``runes`` from ``s`` and returns @@ -1079,7 +1106,7 @@ proc strip*(s: openArray[char], leading = true, trailing = true, let newLen = eI - sI + 1 result = newStringOfCap(newLen) if newLen > 0: - result.add substr(s.toOpenArray(sI, eI)) + result.add s[sI .. eI] proc repeat*(c: Rune, count: Natural): string {.noSideEffect, rtl, extern: "nucRepeatRune".} = @@ -1095,7 +1122,7 @@ proc repeat*(c: Rune, count: Natural): string {.noSideEffect, for i in 0 ..< count: result.add s -proc align*(s: openArray[char], count: Natural, padding = ' '.Rune): string {. +proc align*(s: string, count: Natural, padding = ' '.Rune): string {. noSideEffect, rtl, extern: "nucAlignString".} = ## Aligns a unicode string ``s`` with ``padding``, so that it has a rune-length ## of ``count``. @@ -1120,9 +1147,9 @@ proc align*(s: openArray[char], count: Natural, padding = ' '.Rune): string {. for i in 0 ..< spaces: result.add padStr result.add s else: - result = s.substr + result = s -proc alignLeft*(s: openArray[char], count: Natural, padding = ' '.Rune): string {. +proc alignLeft*(s: string, count: Natural, padding = ' '.Rune): string {. noSideEffect.} = ## Left-aligns a unicode string ``s`` with ``padding``, so that it has a ## rune-length of ``count``. @@ -1146,365 +1173,301 @@ proc alignLeft*(s: openArray[char], count: Natural, padding = ' '.Rune): string for i in sLen ..< count: result.add padStr else: - result = s.substr + result = s +# ----------------------------------------------------------------------------- +# deprecated -proc runeLen*(s: string): int {.inline.} = - ## Returns the number of runes of the string ``s``. - runnableExamples: - let a = "añyóng" - doAssert a.runeLen == 6 - ## note: a.len == 8 - runeLen(toOa(s)) +template runeCaseCheck(s, runeProc, skipNonAlpha) = + ## Common code for rune.isLower and rune.isUpper. + if len(s) == 0: return false + var + i = 0 + rune: Rune + hasAtleastOneAlphaRune = false + while i < len(s): + fastRuneAt(s, i, rune, doInc = true) + if skipNonAlpha: + var runeIsAlpha = isAlpha(rune) + if not hasAtleastOneAlphaRune: + hasAtleastOneAlphaRune = runeIsAlpha + if runeIsAlpha and (not runeProc(rune)): + return false + else: + if not runeProc(rune): + return false + return if skipNonAlpha: hasAtleastOneAlphaRune else: true -proc runeLenAt*(s: string, i: Natural): int {.inline.} = - ## Returns the number of bytes the rune starting at ``s[i]`` takes. +proc isLower*(s: string, skipNonAlpha: bool): bool {. + deprecated: "Deprecated since version 0.20 since its semantics are unclear".} = + ## **Deprecated since version 0.20 since its semantics are unclear** ## - ## See also: - ## * `fastRuneAt template <#fastRuneAt.t,string,int,untyped>`_ - runnableExamples: - let a = "añyóng" - doAssert a.runeLenAt(0) == 1 - doAssert a.runeLenAt(1) == 2 - runeLenAt(toOa(s), i) - -proc runeAt*(s: string, i: Natural): Rune {.inline.} = - ## Returns the rune in ``s`` at **byte index** ``i``. + ## Checks whether ``s`` is lower case. ## - ## See also: - ## * `runeAtPos proc <#runeAtPos,string,int>`_ - ## * `runeStrAtPos proc <#runeStrAtPos,string,Natural>`_ - ## * `fastRuneAt template <#fastRuneAt.t,string,int,untyped>`_ - runnableExamples: - let a = "añyóng" - doAssert a.runeAt(1) == "ñ".runeAt(0) - doAssert a.runeAt(2) == "ñ".runeAt(1) - doAssert a.runeAt(3) == "y".runeAt(0) - fastRuneAt(s, i, result, false) - -proc validateUtf8*(s: string): int {.inline.} = - ## Returns the position of the invalid byte in ``s`` if the string ``s`` does - ## not hold valid UTF-8 data. Otherwise ``-1`` is returned. + ## If ``skipNonAlpha`` is true, returns true if all alphabetical + ## runes in ``s`` are lower case. Returns false if none of the + ## runes in ``s`` are alphabetical. ## - ## See also: - ## * `toUTF8 proc <#toUTF8,Rune>`_ - ## * `$ proc <#$,Rune>`_ alias for `toUTF8` - ## * `fastToUTF8Copy template <#fastToUTF8Copy.t,Rune,string,int>`_ - validateUtf8(toOa(s)) - -proc runeOffset*(s: string, pos: Natural, start: Natural = 0): int {.inline.} = - ## Returns the byte position of rune - ## at position ``pos`` in ``s`` with an optional start byte position. - ## Returns the special value -1 if it runs out of the string. + ## If ``skipNonAlpha`` is false, returns true only if all runes in + ## ``s`` are alphabetical and lower case. ## - ## **Beware:** This can lead to unoptimized code and slow execution! - ## Most problems can be solved more efficiently by using an iterator - ## or conversion to a seq of Rune. + ## For either value of ``skipNonAlpha``, returns false if ``s`` is + ## an empty string. + runeCaseCheck(s, isLower, skipNonAlpha) + +proc isUpper*(s: string, skipNonAlpha: bool): bool {. + deprecated: "Deprecated since version 0.20 since its semantics are unclear".} = + ## **Deprecated since version 0.20 since its semantics are unclear** ## - ## See also: - ## * `runeReverseOffset proc <#runeReverseOffset,string,Positive>`_ - runnableExamples: - let a = "añyóng" - doAssert a.runeOffset(1) == 1 - doAssert a.runeOffset(3) == 4 - doAssert a.runeOffset(4) == 6 - runeOffset(toOa(s), pos, start) - -proc runeReverseOffset*(s: string, rev: Positive): (int, int) {.inline.} = - ## Returns a tuple with the byte offset of the - ## rune at position ``rev`` in ``s``, counting - ## from the end (starting with 1) and the total - ## number of runes in the string. + ## Checks whether ``s`` is upper case. ## - ## Returns a negative value for offset if there are too few runes in - ## the string to satisfy the request. + ## If ``skipNonAlpha`` is true, returns true if all alphabetical + ## runes in ``s`` are upper case. Returns false if none of the + ## runes in ``s`` are alphabetical. ## - ## **Beware:** This can lead to unoptimized code and slow execution! - ## Most problems can be solved more efficiently by using an iterator - ## or conversion to a seq of Rune. + ## If ``skipNonAlpha`` is false, returns true only if all runes in + ## ``s`` are alphabetical and upper case. ## - ## See also: - ## * `runeOffset proc <#runeOffset,string,Natural,Natural>`_ - runeReverseOffset(toOa(s), rev) + ## For either value of ``skipNonAlpha``, returns false if ``s`` is + ## an empty string. + runeCaseCheck(s, isUpper, skipNonAlpha) -proc runeAtPos*(s: string, pos: int): Rune {.inline.} = - ## Returns the rune at position ``pos``. +proc isTitle*(s: string): bool {.noSideEffect, procvar, rtl, extern: "nuc$1Str", + deprecated: "Deprecated since version 0.20 since its semantics are unclear".} = + ## **Deprecated since version 0.20 since its semantics are unclear** ## - ## **Beware:** This can lead to unoptimized code and slow execution! - ## Most problems can be solved more efficiently by using an iterator - ## or conversion to a seq of Rune. + ## Checks whether or not ``s`` is a unicode title. ## - ## See also: - ## * `runeAt proc <#runeAt,string,Natural>`_ - ## * `runeStrAtPos proc <#runeStrAtPos,string,Natural>`_ - ## * `fastRuneAt template <#fastRuneAt.t,string,int,untyped>`_ - fastRuneAt(toOa(s), runeOffset(s, pos), result, false) + ## Returns true if the first character in each word inside ``s`` + ## are upper case and there is at least one character in ``s``. + if s.len == 0: + return false + result = true + var + i = 0 + rune: Rune + var firstRune = true -proc runeStrAtPos*(s: string, pos: Natural): string {.inline.} = - ## Returns the rune at position ``pos`` as UTF8 String. - ## - ## **Beware:** This can lead to unoptimized code and slow execution! - ## Most problems can be solved more efficiently by using an iterator - ## or conversion to a seq of Rune. - ## - ## See also: - ## * `runeAt proc <#runeAt,string,Natural>`_ - ## * `runeAtPos proc <#runeAtPos,string,int>`_ - ## * `fastRuneAt template <#fastRuneAt.t,string,int,untyped>`_ - let o = runeOffset(s, pos) - substr(s.toOpenArray(o, (o+runeLenAt(s, o)-1))) - -proc runeSubStr*(s: string, pos: int, len: int = int.high): string {.inline.} = - ## Returns the UTF-8 substring starting at code point ``pos`` - ## with ``len`` code points. - ## - ## If ``pos`` or ``len`` is negative they count from - ## the end of the string. If ``len`` is not given it means the longest - ## possible string. - runnableExamples: - let s = "Hänsel ««: 10,00€" - doAssert(runeSubStr(s, 0, 2) == "Hä") - doAssert(runeSubStr(s, 10, 1) == ":") - doAssert(runeSubStr(s, -6) == "10,00€") - doAssert(runeSubStr(s, 10) == ": 10,00€") - doAssert(runeSubStr(s, 12, 5) == "10,00") - doAssert(runeSubStr(s, -6, 3) == "10,") - runeSubStr(toOa(s), pos, len) + while i < len(s) and result: + fastRuneAt(s, i, rune, doInc = true) + if not rune.isWhiteSpace() and firstRune: + result = rune.isUpper() and result + firstRune = false + elif rune.isWhiteSpace(): + firstRune = true -proc isAlpha*(s: string): bool {.noSideEffect, inline.} = - ## Returns true if ``s`` contains all alphabetic runes. - runnableExamples: - let a = "añyóng" - doAssert a.isAlpha - isAlpha(toOa(s)) -proc isSpace*(s: string): bool {.noSideEffect, inline.} = - ## Returns true if ``s`` contains all whitespace runes. - runnableExamples: - let a = "\t\l \v\r\f" - doAssert a.isSpace - isSpace(toOa(s)) +when isMainModule: + proc asRune(s: static[string]): Rune = + ## Compile-time conversion proc for converting string literals to a Rune + ## value. Returns the first Rune of the specified string. + ## + ## Shortcuts code like ``"å".runeAt(0)`` to ``"å".asRune`` and returns a + ## compile-time constant. + if s.len == 0: Rune(0) + else: s.runeAt(0) -proc toUpper*(s: string): string {.noSideEffect, inline.} = - ## Converts ``s`` into upper-case runes. - runnableExamples: - doAssert toUpper("abγ") == "ABΓ" - toUpper(toOa(s)) + let + someString = "öÑ" + someRunes = toRunes(someString) + compared = (someString == $someRunes) + doAssert compared == true -proc toLower*(s: string): string {.noSideEffect, inline.} = - ## Converts ``s`` into lower-case runes. - runnableExamples: - doAssert toLower("ABΓ") == "abγ" - toLower(toOa(s)) + proc testReplacements(word: string): string = + case word + of "two": + return "2" + of "foo": + return "BAR" + of "βeta": + return "beta" + of "alpha": + return "αlpha" + else: + return "12345" -proc swapCase*(s: string): string {.noSideEffect, inline.} = - ## Swaps the case of runes in ``s``. - ## - ## Returns a new string such that the cases of all runes - ## are swapped if possible. - runnableExamples: - doAssert swapCase("Αlpha Βeta Γamma") == "αLPHA βETA γAMMA" - swapCase(toOa(s)) + doAssert translate("two not alpha foo βeta", testReplacements) == "2 12345 αlpha BAR beta" + doAssert translate(" two not foo βeta ", testReplacements) == " 2 12345 BAR beta " -proc capitalize*(s: string): string {.noSideEffect.} = - ## Converts the first character of ``s`` into an upper-case rune. - runnableExamples: - doAssert capitalize("βeta") == "Βeta" - capitalize(toOa(s)) + doAssert title("foo bar") == "Foo Bar" + doAssert title("αlpha βeta γamma") == "Αlpha Βeta Γamma" + doAssert title("") == "" + doAssert capitalize("βeta") == "Βeta" + doAssert capitalize("foo") == "Foo" + doAssert capitalize("") == "" -proc translate*(s: string, replacements: proc(key: string): string): string {.effectsOf: replacements, inline.} = - ## Translates words in a string using the ``replacements`` proc to substitute - ## words inside ``s`` with their replacements. - ## - ## ``replacements`` is any proc that takes a word and returns - ## a new word to fill it's place. - runnableExamples: - proc wordToNumber(s: string): string = - case s - of "one": "1" - of "two": "2" - else: s - let a = "one two three four" - doAssert a.translate(wordToNumber) == "1 2 three four" - translate(toOa(s), replacements) + doAssert swapCase("FooBar") == "fOObAR" + doAssert swapCase(" ") == " " + doAssert swapCase("Αlpha Βeta Γamma") == "αLPHA βETA γAMMA" + doAssert swapCase("a✓B") == "A✓b" + doAssert swapCase("Јамогујестистаклоитоминештети") == "јАМОГУЈЕСТИСТАКЛОИТОМИНЕШТЕТИ" + doAssert swapCase("ὕαλονϕαγεῖνδύναμαιτοῦτοοὔμεβλάπτει") == "ὝΑΛΟΝΦΑΓΕῖΝΔΎΝΑΜΑΙΤΟῦΤΟΟὔΜΕΒΛΆΠΤΕΙ" + doAssert swapCase("Կրնամապակիուտեևինծիանհանգիստչըներ") == "կՐՆԱՄԱՊԱԿԻՈՒՏԵևԻՆԾԻԱՆՀԱՆԳԻՍՏՉԸՆԵՐ" + doAssert swapCase("") == "" -proc title*(s: string): string {.noSideEffect, inline.} = - ## Converts ``s`` to a unicode title. - ## - ## Returns a new string such that the first character - ## in each word inside ``s`` is capitalized. - runnableExamples: - doAssert title("αlpha βeta γamma") == "Αlpha Βeta Γamma" - title(toOa(s)) + doAssert isAlpha("r") + doAssert isAlpha("α") + doAssert isAlpha("ϙ") + doAssert isAlpha("ஶ") + doAssert(not isAlpha("$")) + doAssert(not isAlpha("")) + doAssert isAlpha("Βeta") + doAssert isAlpha("Args") + doAssert isAlpha("𐌼𐌰𐌲𐌲𐌻𐌴𐍃𐍄𐌰𐌽") + doAssert isAlpha("ὕαλονϕαγεῖνδύναμαιτοῦτοοὔμεβλάπτει") + doAssert isAlpha("Јамогујестистаклоитоминештети") + doAssert isAlpha("Կրնամապակիուտեևինծիանհանգիստչըներ") + doAssert(not isAlpha("$Foo✓")) + doAssert(not isAlpha("⠙⠕⠑⠎⠝⠞")) -iterator runes*(s: string): Rune = - ## Iterates over any rune of the string ``s`` returning runes. - for rune in runes(toOa(s)): - yield rune + doAssert isSpace("\t") + doAssert isSpace("\l") + doAssert(not isSpace("Β")) + doAssert(not isSpace("Βeta")) -iterator utf8*(s: string): string = - ## Iterates over any rune of the string ``s`` returning utf8 values. - ## - ## See also: - ## * `validateUtf8 proc <#validateUtf8,string>`_ - ## * `toUTF8 proc <#toUTF8,Rune>`_ - ## * `$ proc <#$,Rune>`_ alias for `toUTF8` - ## * `fastToUTF8Copy template <#fastToUTF8Copy.t,Rune,string,int>`_ - for str in utf8(toOa(s)): - yield str + doAssert isSpace("\t\l \v\r\f") + doAssert isSpace(" ") + doAssert(not isSpace("")) + doAssert(not isSpace("ΑΓc \td")) -proc toRunes*(s: string): seq[Rune] {.inline.} = - ## Obtains a sequence containing the Runes in ``s``. - ## - ## See also: - ## * `$ proc <#$,Rune>`_ for a reverse operation - runnableExamples: - let a = toRunes("aáä") - doAssert a == @["a".runeAt(0), "á".runeAt(0), "ä".runeAt(0)] - toRunes(toOa(s)) + doAssert(not isLower(' '.Rune)) -proc cmpRunesIgnoreCase*(a, b: string): int {.inline.} = - ## Compares two UTF-8 strings and ignores the case. Returns: - ## - ## | 0 if a == b - ## | < 0 if a < b - ## | > 0 if a > b - cmpRunesIgnoreCase(a.toOa(), b.toOa()) + doAssert(not isUpper(' '.Rune)) -proc reversed*(s: string): string {.inline.} = - ## Returns the reverse of ``s``, interpreting it as runes. - ## - ## Unicode combining characters are correctly interpreted as well. - runnableExamples: - assert reversed("Reverse this!") == "!siht esreveR" - assert reversed("先秦兩漢") == "漢兩秦先" - assert reversed("as⃝df̅") == "f̅ds⃝a" - assert reversed("a⃞b⃞c⃞") == "c⃞b⃞a⃞" - reversed(toOa(s)) + doAssert toUpper("Γ") == "Γ" + doAssert toUpper("b") == "B" + doAssert toUpper("α") == "Α" + doAssert toUpper("✓") == "✓" + doAssert toUpper("ϙ") == "Ϙ" + doAssert toUpper("") == "" -proc graphemeLen*(s: string; i: Natural): Natural {.inline.} = - ## The number of bytes belonging to byte index ``s[i]``, - ## including following combining code unit. - runnableExamples: - let a = "añyóng" - doAssert a.graphemeLen(1) == 2 ## ñ - doAssert a.graphemeLen(2) == 1 - doAssert a.graphemeLen(4) == 2 ## ó - graphemeLen(toOa(s), i) + doAssert toUpper("ΑΒΓ") == "ΑΒΓ" + doAssert toUpper("AAccβ") == "AACCΒ" + doAssert toUpper("A✓$β") == "A✓$Β" -proc lastRune*(s: string; last: int): (Rune, int) {.inline.} = - ## Length of the last rune in ``s[0..last]``. Returns the rune and its length - ## in bytes. - lastRune(toOa(s), last) + doAssert toLower("a") == "a" + doAssert toLower("γ") == "γ" + doAssert toLower("Γ") == "γ" + doAssert toLower("4") == "4" + doAssert toLower("Ϙ") == "ϙ" + doAssert toLower("") == "" -iterator split*(s: string, seps: openArray[Rune] = unicodeSpaces, - maxsplit: int = -1): string = - ## Splits the unicode string ``s`` into substrings using a group of separators. - ## - ## Substrings are separated by a substring containing only ``seps``. - runnableExamples: - import std/sequtils + doAssert toLower("abcdγ") == "abcdγ" + doAssert toLower("abCDΓ") == "abcdγ" + doAssert toLower("33aaΓ") == "33aaγ" - assert toSeq("hÃllo\lthis\lis an\texample\l是".split) == - @["hÃllo", "this", "is", "an", "example", "是"] + doAssert reversed("Reverse this!") == "!siht esreveR" + doAssert reversed("先秦兩漢") == "漢兩秦先" + doAssert reversed("as⃝df̅") == "f̅ds⃝a" + doAssert reversed("a⃞b⃞c⃞") == "c⃞b⃞a⃞" + doAssert reversed("ὕαλονϕαγεῖνδύναμαιτοῦτοοὔμεβλάπτει") == "ιετπάλβεμὔοοτῦοτιαμανύδνῖεγαϕνολαὕ" + doAssert reversed("Јамогујестистаклоитоминештети") == "итетшенимотиолкатситсејугомаЈ" + doAssert reversed("Կրնամապակիուտեևինծիանհանգիստչըներ") == "րենըչտսիգնահնաիծնիևետւոիկապամանրԿ" + doAssert len(toRunes("as⃝df̅")) == runeLen("as⃝df̅") + const test = "as⃝" + doAssert lastRune(test, test.len-1)[1] == 3 + doAssert graphemeLen("è", 0) == 2 - # And the following code splits the same string using a sequence of Runes. - assert toSeq(split("añyóng:hÃllo;是$example", ";:$".toRunes)) == - @["añyóng", "hÃllo", "是", "example"] + # test for rune positioning and runeSubStr() + let s = "Hänsel ««: 10,00€" - # example with a `Rune` separator and unused one `;`: - assert toSeq(split("ab是de:f:", ";:是".toRunes)) == @["ab", "de", "f", ""] + var t = "" + for c in s.utf8: + t.add c - # Another example that splits a string containing a date. - let date = "2012-11-20T22:08:08.398990" + doAssert(s == t) - assert toSeq(split(date, " -:T".toRunes)) == - @["2012", "11", "20", "22", "08", "08.398990"] + doAssert(runeReverseOffset(s, 1) == (20, 18)) + doAssert(runeReverseOffset(s, 19) == (-1, 18)) - splitCommon(toOa(s), seps, maxsplit) + doAssert(runeStrAtPos(s, 0) == "H") + doAssert(runeSubStr(s, 0, 1) == "H") + doAssert(runeStrAtPos(s, 10) == ":") + doAssert(runeSubStr(s, 10, 1) == ":") + doAssert(runeStrAtPos(s, 9) == "«") + doAssert(runeSubStr(s, 9, 1) == "«") + doAssert(runeStrAtPos(s, 17) == "€") + doAssert(runeSubStr(s, 17, 1) == "€") + # echo runeStrAtPos(s, 18) # index error -iterator splitWhitespace*(s: string): string = - ## Splits a unicode string at whitespace runes. - splitCommon(s.toOa(), unicodeSpaces, -1) + doAssert(runeSubStr(s, 0) == "Hänsel ««: 10,00€") + doAssert(runeSubStr(s, -18) == "Hänsel ««: 10,00€") + doAssert(runeSubStr(s, 10) == ": 10,00€") + doAssert(runeSubStr(s, 18) == "") + doAssert(runeSubStr(s, 0, 10) == "Hänsel ««") + doAssert(runeSubStr(s, 12) == "10,00€") + doAssert(runeSubStr(s, -6) == "10,00€") -proc splitWhitespace*(s: string): seq[string] {.noSideEffect, inline.}= - ## The same as the `splitWhitespace <#splitWhitespace.i,string>`_ - ## iterator, but is a proc that returns a sequence of substrings. - accResult(splitWhitespace(toOa(s))) + doAssert(runeSubStr(s, 12, 5) == "10,00") + doAssert(runeSubStr(s, 12, -1) == "10,00") + doAssert(runeSubStr(s, -6, 5) == "10,00") + doAssert(runeSubStr(s, -6, -1) == "10,00") -iterator split*(s: string, sep: Rune, maxsplit: int = -1): string = - ## Splits the unicode string ``s`` into substrings using a single separator. - ## Substrings are separated by the rune ``sep``. - runnableExamples: - import std/sequtils + doAssert(runeSubStr(s, 0, 100) == "Hänsel ««: 10,00€") + doAssert(runeSubStr(s, -100, 100) == "Hänsel ««: 10,00€") + doAssert(runeSubStr(s, 0, -100) == "") + doAssert(runeSubStr(s, 100, -100) == "") - assert toSeq(split(";;hÃllo;this;is;an;;example;;;是", ";".runeAt(0))) == - @["", "", "hÃllo", "this", "is", "an", "", "example", "", "", "是"] + block splitTests: + let s = " this is an example " + let s2 = ":this;is;an:example;;" + let s3 = ":this×is×an:example××" + doAssert s.split() == @["", "this", "is", "an", "example", "", ""] + doAssert s2.split(seps = [':'.Rune, ';'.Rune]) == @["", "this", "is", "an", + "example", "", ""] + doAssert s3.split(seps = [':'.Rune, "×".asRune]) == @["", "this", "is", + "an", "example", "", ""] + doAssert s.split(maxsplit = 4) == @["", "this", "is", "an", "example "] + doAssert s.split(' '.Rune, maxsplit = 1) == @["", "this is an example "] - splitCommon(toOa(s), sep, maxsplit) + block stripTests: + doAssert(strip("") == "") + doAssert(strip(" ") == "") + doAssert(strip("y") == "y") + doAssert(strip(" foofoofoo ") == "foofoofoo") + doAssert(strip("sfoofoofoos", runes = ['s'.Rune]) == "foofoofoo") -proc split*(s: string, seps: openArray[Rune] = unicodeSpaces, maxsplit: int = -1): - seq[string] {.noSideEffect, inline.} = - ## The same as the `split iterator <#split.i,string,openArray[Rune],int>`_, - ## but is a proc that returns a sequence of substrings. - accResult(split(toOa(s), seps, maxsplit)) + block: + let stripTestRunes = ['b'.Rune, 'a'.Rune, 'r'.Rune] + doAssert(strip("barfoofoofoobar", runes = stripTestRunes) == "foofoofoo") + doAssert(strip("sfoofoofoos", leading = false, runes = ['s'.Rune]) == "sfoofoofoo") + doAssert(strip("sfoofoofoos", trailing = false, runes = ['s'.Rune]) == "foofoofoos") -proc split*(s: string, sep: Rune, maxsplit: int = -1): seq[string] {.noSideEffect, inline.} = - ## The same as the `split iterator <#split.i,string,Rune,int>`_, but is a proc - ## that returns a sequence of substrings. - accResult(split(toOa(s), sep, maxsplit)) + block: + let stripTestRunes = ["«".asRune, "»".asRune] + doAssert(strip("«TEXT»", runes = stripTestRunes) == "TEXT") + doAssert(strip("copyright©", leading = false, runes = ["©".asRune]) == "copyright") + doAssert(strip("¿Question?", trailing = false, runes = ["¿".asRune]) == "Question?") + doAssert(strip("×text×", leading = false, runes = ["×".asRune]) == "×text") + doAssert(strip("×text×", trailing = false, runes = ["×".asRune]) == "text×") -proc strip*(s: string, leading = true, trailing = true, - runes: openArray[Rune] = unicodeSpaces): string {.noSideEffect, inline.} = - ## Strips leading or trailing ``runes`` from ``s`` and returns - ## the resulting string. - ## - ## If ``leading`` is true (default), leading ``runes`` are stripped. - ## If ``trailing`` is true (default), trailing ``runes`` are stripped. - ## If both are false, the string is returned unchanged. - runnableExamples: - let a = "\táñyóng " - doAssert a.strip == "áñyóng" - doAssert a.strip(leading = false) == "\táñyóng" - doAssert a.strip(trailing = false) == "áñyóng " - strip(toOa(s), leading, trailing, runes) + block repeatTests: + doAssert repeat('c'.Rune, 5) == "ccccc" + doAssert repeat("×".asRune, 5) == "×××××" + block alignTests: + doAssert align("abc", 4) == " abc" + doAssert align("a", 0) == "a" + doAssert align("1232", 6) == " 1232" + doAssert align("1232", 6, '#'.Rune) == "##1232" + doAssert align("1232", 6, "×".asRune) == "××1232" + doAssert alignLeft("abc", 4) == "abc " + doAssert alignLeft("a", 0) == "a" + doAssert alignLeft("1232", 6) == "1232 " + doAssert alignLeft("1232", 6, '#'.Rune) == "1232##" + doAssert alignLeft("1232", 6, "×".asRune) == "1232××" -proc align*(s: string, count: Natural, padding = ' '.Rune): string {.noSideEffect, inline.} = - ## Aligns a unicode string ``s`` with ``padding``, so that it has a rune-length - ## of ``count``. - ## - ## ``padding`` characters (by default spaces) are added before ``s`` resulting in - ## right alignment. If ``s.runelen >= count``, no spaces are added and ``s`` is - ## returned unchanged. If you need to left align a string use the `alignLeft - ## proc <#alignLeft,string,Natural>`_. - runnableExamples: - assert align("abc", 4) == " abc" - assert align("a", 0) == "a" - assert align("1232", 6) == " 1232" - assert align("1232", 6, '#'.Rune) == "##1232" - assert align("Åge", 5) == " Åge" - assert align("×", 4, '_'.Rune) == "___×" - align(toOa(s), count, padding) - -proc alignLeft*(s: string, count: Natural, padding = ' '.Rune): string {.noSideEffect, inline.} = - ## Left-aligns a unicode string ``s`` with ``padding``, so that it has a - ## rune-length of ``count``. - ## - ## ``padding`` characters (by default spaces) are added after ``s`` resulting in - ## left alignment. If ``s.runelen >= count``, no spaces are added and ``s`` is - ## returned unchanged. If you need to right align a string use the `align - ## proc <#align,string,Natural>`_. - runnableExamples: - assert alignLeft("abc", 4) == "abc " - assert alignLeft("a", 0) == "a" - assert alignLeft("1232", 6) == "1232 " - assert alignLeft("1232", 6, '#'.Rune) == "1232##" - assert alignLeft("Åge", 5) == "Åge " - assert alignLeft("×", 4, '_'.Rune) == "×___" - alignLeft(toOa(s), count, padding) + block differentSizes: + # upper and lower variants have different number of bytes + doAssert toLower("AẞC") == "aßc" + doAssert toLower("ȺẞCD") == "ⱥßcd" + doAssert toUpper("ⱥbc") == "ȺBC" + doAssert toUpper("rsⱦuv") == "RSȾUV" + doAssert swapCase("ⱥbCd") == "ȺBcD" + doAssert swapCase("XyꟆaB") == "xYᶎAb" + doAssert swapCase("aᵹcᲈd") == "AꝽCꙊD" diff --git a/lib/pure/unidecode/gen.py b/lib/pure/unidecode/gen.py index 2fb69f7b2..f0647ea6c 100644 --- a/lib/pure/unidecode/gen.py +++ b/lib/pure/unidecode/gen.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python3 +#! usr/bin/env python3 # -*- coding: utf-8 -*- # Generates the unidecode.dat module @@ -11,7 +11,7 @@ try: except ImportError: pass -def main(): +def main2(): f = open("unidecode.dat", "wb+") for x in range(128, 0xffff + 1): u = eval("u'\\u%04x'" % x) @@ -19,12 +19,12 @@ def main(): val = unidecode(u) # f.write("%x | " % x) - if x == 0x2028: # U+2028 = LINE SEPARATOR + if x==0x2028: # U+2028 = LINE SEPARATOR val = "" - elif x == 0x2029: # U+2029 = PARAGRAPH SEPARATOR + elif x==0x2029: # U+2028 = PARAGRAPH SEPARATOR val = "" f.write("%s\n" % val) f.close() -main() +main2() \ No newline at end of file diff --git a/lib/pure/unidecode/unidecode.nim b/lib/pure/unidecode/unidecode.nim index 9affc53f6..30aaa7cd8 100644 --- a/lib/pure/unidecode/unidecode.nim +++ b/lib/pure/unidecode/unidecode.nim @@ -7,31 +7,30 @@ # distribution, for details about the copyright. # -## This module is based on Python's [Unidecode](https://pypi.org/project/Unidecode/) -## module by Tomaz Solc, which in turn is based on the -## [Text::Unidecode](https://metacpan.org/pod/Text::Unidecode) -## Perl module by Sean M. Burke. +## This module is based on Python's Unidecode module by Tomaz Solc, +## which in turn is based on the ``Text::Unidecode`` Perl module by +## Sean M. Burke +## (http://search.cpan.org/~sburke/Text-Unidecode-0.04/lib/Text/Unidecode.pm ). ## -## It provides a `unidecode proc <#unidecode,string>`_ that does -## Unicode to ASCII transliterations: It finds the sequence of ASCII characters -## that is the closest approximation to the Unicode string. +## It provides a single proc that does Unicode to ASCII transliterations: +## It finds the sequence of ASCII characters that is the closest approximation +## to the Unicode string. ## ## For example, the closest to string "Äußerst" in ASCII is "Ausserst". Some ## information is lost in this transformation, of course, since several Unicode -## strings can be transformed to the same ASCII representation. So this is a -## strictly one-way transformation. However, a human reader will probably -## still be able to guess from the context, what the original string was. +## strings can be transformed in the same ASCII representation. So this is a +## strictly one-way transformation. However a human reader will probably +## still be able to guess what original string was meant from the context. ## -## This module needs the data file `unidecode.dat` to work: This file is -## embedded as a resource into your application by default. You can also -## define the symbol `--define:noUnidecodeTable` during compile time and -## use the `loadUnidecodeTable proc <#loadUnidecodeTable>`_ to initialize -## this module. +## This module needs the data file "unidecode.dat" to work: This file is +## embedded as a resource into your application by default. But you an also +## define the symbol ``--define:noUnidecodeTable`` during compile time and +## use the `loadUnidecodeTable` proc to initialize this module. -import std/unicode +import unicode when not defined(noUnidecodeTable): - import std/strutils + import strutils const translationTable = splitLines(slurp"unidecode/unidecode.dat") else: @@ -39,26 +38,36 @@ else: var translationTable: seq[string] proc loadUnidecodeTable*(datafile = "unidecode.dat") = - ## Loads the datafile that `unidecode <#unidecode,string>`_ needs to work. - ## This is only required if the module was compiled with the - ## `--define:noUnidecodeTable` switch. This needs to be called by the - ## main thread before any thread can make a call to `unidecode`. + ## loads the datafile that `unidecode` to work. This is only required if + ## the module was compiled with the ``--define:noUnidecodeTable`` switch. + ## This needs to be called by the main thread before any thread can make a + ## call to `unidecode`. when defined(noUnidecodeTable): newSeq(translationTable, 0xffff) var i = 0 for line in lines(datafile): - translationTable[i] = line + translationTable[i] = line.string inc(i) proc unidecode*(s: string): string = ## Finds the sequence of ASCII characters that is the closest approximation ## to the UTF-8 string `s`. - runnableExamples: - doAssert unidecode("北京") == "Bei Jing " - doAssert unidecode("Äußerst") == "Ausserst" - + ## + ## Example: + ## + ## ..code-block:: nim + ## + ## unidecode("北京") + ## + ## Results in: "Bei Jing" + ## result = "" for r in runes(s): var c = int(r) if c <=% 127: add(result, chr(c)) - elif c <% translationTable.len: add(result, translationTable[c - 128]) + elif c <% translationTable.len: add(result, translationTable[c-128]) + +when isMainModule: + #loadUnidecodeTable("lib/pure/unidecode/unidecode.dat") + doAssert unidecode("Äußerst") == "Ausserst" + doAssert unidecode("北京") == "Bei Jing " diff --git a/lib/pure/unittest.nim b/lib/pure/unittest.nim index 9dafa8f03..ee2c5fe22 100644 --- a/lib/pure/unittest.nim +++ b/lib/pure/unittest.nim @@ -9,6 +9,11 @@ ## :Author: Zahary Karadjov ## +## **Note**: Instead of ``unittest.nim``, please consider to use +## the ``testament`` tool which offers process isolation for your tests. +## Also ``when isMainModule: doAssert conditionHere`` is usually a +## much simpler solution for testing purposes. +## ## This module implements boilerplate to make unit testing easy. ## ## The test status and name is printed after any output or traceback. @@ -17,17 +22,8 @@ ## parent test as failed. Setup and teardown are inherited. Setup can be ## overridden locally. ## -## Compiled test files as well as `nim c -r ` -## exit with 0 for success (no failed tests) or 1 for failure. -## -## Testament -## ========= -## -## Instead of `unittest`, please consider using -## `the Testament tool `_ which offers process isolation for your tests. -## -## Alternatively using `when isMainModule: doAssert conditionHere` is usually a -## much simpler solution for testing purposes. +## Compiled test files return the number of failed test as exit code, while +## ``nim c -r `` exits with 0 or 1 ## ## Running a single test ## ===================== @@ -43,7 +39,7 @@ ## Running a single test suite ## =========================== ## -## Specify the suite name delimited by `"::"`. +## Specify the suite name delimited by ``"::"``. ## ## .. code:: ## @@ -54,7 +50,7 @@ ## ## A single ``"*"`` can be used for globbing. ## -## Delimit the end of a suite name with `"::"`. +## Delimit the end of a suite name with ``"::"``. ## ## Tests matching **any** of the arguments are executed. ## @@ -92,33 +88,20 @@ ## ## test "out of bounds error is thrown on bad access": ## let v = @[1, 2, 3] # you can do initialization here -## expect(IndexDefect): +## expect(IndexError): ## discard v[4] ## ## echo "suite teardown: run once after the tests" -## -## Limitations/Bugs -## ================ -## Since `check` will rewrite some expressions for supporting checkpoints -## (namely assigns expressions to variables), some type conversions are not supported. -## For example `check 4.0 == 2 + 2` won't work. But `doAssert 4.0 == 2 + 2` works. -## Make sure both sides of the operator (such as `==`, `>=` and so on) have the same type. -## -import std/private/since -import std/exitprocs +import + macros, strutils, streams, times, sets, sequtils -when defined(nimPreviewSlimSystem): - import std/assertions - -import macros, strutils, streams, times, sets, sequtils +include "system/inclrtl" when declared(stdout): import os -const useTerminal = not defined(js) - -when useTerminal: +when not defined(ECMAScript): import terminal type @@ -145,19 +128,21 @@ type ConsoleOutputFormatter* = ref object of OutputFormatter colorOutput: bool ## Have test results printed in color. - ## Default is `auto` depending on `isatty(stdout)`, or override it with - ## `-d:nimUnittestColor:auto|on|off`. - ## - ## Deprecated: Setting the environment variable `NIMTEST_COLOR` to `always` - ## or `never` changes the default for the non-js target to true or false respectively. - ## Deprecated: the environment variable `NIMTEST_NO_COLOR`, when set, changes the - ## default to true, if `NIMTEST_COLOR` is undefined. + ## Default is true for the non-js target, + ## for which ``stdout`` is a tty. + ## Setting the environment variable + ## ``NIMTEST_COLOR`` to ``always`` or + ## ``never`` changes the default for the + ## non-js target to true or false respectively. + ## The deprecated environment variable + ## ``NIMTEST_NO_COLOR``, when set, + ## changes the default to true, if + ## ``NIMTEST_COLOR`` is undefined. outputLevel: OutputLevel ## Set the verbosity of test results. - ## Default is `PRINT_ALL`, or override with: - ## `-d:nimUnittestOutputLevel:PRINT_ALL|PRINT_FAILURES|PRINT_NONE`. - ## - ## Deprecated: the `NIMTEST_OUTPUT_LVL` environment variable is set for the non-js target. + ## Default is ``PRINT_ALL``, unless + ## the ``NIMTEST_OUTPUT_LVL`` environment + ## variable is set for the non-js target. isInSuite: bool isInTest: bool @@ -170,31 +155,17 @@ type var abortOnError* {.threadvar.}: bool ## Set to true in order to quit ## immediately on fail. Default is false, - ## or override with `-d:nimUnittestAbortOnError:on|off`. - ## - ## Deprecated: can also override depending on whether - ## `NIMTEST_ABORT_ON_ERROR` environment variable is set. + ## unless the ``NIMTEST_ABORT_ON_ERROR`` + ## environment variable is set for + ## the non-js target. checkpoints {.threadvar.}: seq[string] formatters {.threadvar.}: seq[OutputFormatter] testsFilters {.threadvar.}: HashSet[string] disabledParamFiltering {.threadvar.}: bool -const - outputLevelDefault = PRINT_ALL - nimUnittestOutputLevel {.strdefine.} = $outputLevelDefault - nimUnittestColor {.strdefine.} = "auto" ## auto|on|off - nimUnittestAbortOnError {.booldefine.} = false - -template deprecateEnvVarHere() = - # xxx issue a runtime warning to deprecate this envvar. - discard - -abortOnError = nimUnittestAbortOnError when declared(stdout): - if existsEnv("NIMTEST_ABORT_ON_ERROR"): - deprecateEnvVarHere() - abortOnError = true + abortOnError = existsEnv("NIMTEST_ABORT_ON_ERROR") method suiteStarted*(formatter: OutputFormatter, suiteName: string) {.base, gcsafe.} = discard @@ -219,49 +190,41 @@ proc delOutputFormatter*(formatter: OutputFormatter) = proc resetOutputFormatters* {.since: (1, 1).} = formatters = @[] - -proc newConsoleOutputFormatter*(outputLevel: OutputLevel = outputLevelDefault, - colorOutput = true): ConsoleOutputFormatter = + +proc newConsoleOutputFormatter*(outputLevel: OutputLevel = OutputLevel.PRINT_ALL, + colorOutput = true): ConsoleOutputFormatter = ConsoleOutputFormatter( outputLevel: outputLevel, colorOutput: colorOutput ) -proc colorOutput(): bool = - let color = nimUnittestColor - case color - of "auto": - when declared(stdout): result = isatty(stdout) - else: result = false - of "on": result = true - of "off": result = false - else: doAssert false, $color - +proc defaultConsoleFormatter*(): ConsoleOutputFormatter = when declared(stdout): + # Reading settings + # On a terminal this branch is executed + var envOutLvl = os.getEnv("NIMTEST_OUTPUT_LVL").string + var colorOutput = isatty(stdout) if existsEnv("NIMTEST_COLOR"): - deprecateEnvVarHere() let colorEnv = getEnv("NIMTEST_COLOR") if colorEnv == "never": - result = false + colorOutput = false elif colorEnv == "always": - result = true + colorOutput = true elif existsEnv("NIMTEST_NO_COLOR"): - deprecateEnvVarHere() - result = false - -proc defaultConsoleFormatter*(): ConsoleOutputFormatter = - var colorOutput = colorOutput() - var outputLevel = nimUnittestOutputLevel.parseEnum[:OutputLevel] - when declared(stdout): - const a = "NIMTEST_OUTPUT_LVL" - if existsEnv(a): - # xxx issue a warning to deprecate this envvar. - outputLevel = getEnv(a).parseEnum[:OutputLevel] - result = newConsoleOutputFormatter(outputLevel, colorOutput) + colorOutput = false + var outputLevel = OutputLevel.PRINT_ALL + if envOutLvl.len > 0: + for opt in countup(low(OutputLevel), high(OutputLevel)): + if $opt == envOutLvl: + outputLevel = opt + break + result = newConsoleOutputFormatter(outputLevel, colorOutput) + else: + result = newConsoleOutputFormatter() method suiteStarted*(formatter: ConsoleOutputFormatter, suiteName: string) = template rawPrint() = echo("\n[Suite] ", suiteName) - when useTerminal: + when not defined(ECMAScript): if formatter.colorOutput: styledEcho styleBright, fgBlue, "\n[Suite] ", resetStyle, suiteName else: rawPrint() @@ -287,8 +250,8 @@ method testEnded*(formatter: ConsoleOutputFormatter, testResult: TestResult) = let prefix = if testResult.suiteName.len > 0: " " else: "" template rawPrint() = echo(prefix, "[", $testResult.status, "] ", testResult.testName) - when useTerminal: - if formatter.colorOutput: + when not defined(ECMAScript): + if formatter.colorOutput and not defined(ECMAScript): var color = case testResult.status of TestStatus.OK: fgGreen of TestStatus.FAILED: fgRed @@ -318,7 +281,7 @@ proc xmlEscape(s: string): string = else: result.add(c) -proc newJUnitOutputFormatter*(stream: Stream): JUnitOutputFormatter = +proc newJUnitOutputFormatter*(stream: Stream): JUnitOutputFormatter = ## Creates a formatter that writes report to the specified stream in ## JUnit format. ## The ``stream`` is NOT closed automatically when the test are finished, @@ -433,6 +396,8 @@ proc matchFilter(suiteName, testName, filter: string): bool = return glob(suiteName, suiteAndTestFilters[0]) and glob(testName, suiteAndTestFilters[1]) +when defined(testing): export matchFilter + proc shouldRun(currentSuiteName, testName: string): bool = ## Check if a test should be run by matching suiteName and testName against ## test filters. @@ -449,7 +414,8 @@ proc ensureInitialized() = if formatters.len == 0: formatters = @[OutputFormatter(defaultConsoleFormatter())] - if not disabledParamFiltering: + if not disabledParamFiltering and not testsFilters.isValid: + testsFilters.init() when declared(paramCount): # Read tests to run from the command line. for i in 1 .. paramCount(): @@ -515,9 +481,7 @@ template suite*(name, body) {.dirty.} = finally: suiteEnded() -proc exceptionTypeName(e: ref Exception): string {.inline.} = - if e == nil: "" - else: $e.name +template exceptionTypeName(e: typed): string = $e.name template test*(name, body) {.dirty.} = ## Define a single test case identified by `name`. @@ -533,7 +497,7 @@ template test*(name, body) {.dirty.} = ## .. code-block:: ## ## [OK] roses are red - bind shouldRun, checkpoints, formatters, ensureInitialized, testEnded, exceptionTypeName, setProgramResult + bind shouldRun, checkpoints, formatters, ensureInitialized, testEnded, exceptionTypeName ensureInitialized() @@ -544,28 +508,23 @@ template test*(name, body) {.dirty.} = for formatter in formatters: formatter.testStarted(name) - {.warning[BareExcept]:off.} try: when declared(testSetupIMPLFlag): testSetupIMPL() when declared(testTeardownIMPLFlag): defer: testTeardownIMPL() - {.warning[BareExcept]:on.} body - {.warning[BareExcept]:off.} except: - let e = getCurrentException() - let eTypeDesc = "[" & exceptionTypeName(e) & "]" - checkpoint("Unhandled exception: " & getCurrentExceptionMsg() & " " & eTypeDesc) - if e == nil: # foreign - fail() - else: + when not defined(js): + let e = getCurrentException() + let eTypeDesc = "[" & exceptionTypeName(e) & "]" + checkpoint("Unhandled exception: " & getCurrentExceptionMsg() & " " & eTypeDesc) var stackTrace {.inject.} = e.getStackTrace() - fail() + fail() finally: if testStatusIMPL == TestStatus.FAILED: - setProgramResult 1 + programResult = 1 let testResult = TestResult( suiteName: when declared(testSuiteName): testSuiteName else: "", testName: name, @@ -573,7 +532,6 @@ template test*(name, body) {.dirty.} = ) testEnded(testResult) checkpoints = @[] - {.warning[BareExcept]:on.} proc checkpoint*(msg: string) = ## Set a checkpoint identified by `msg`. Upon test failure all @@ -602,11 +560,12 @@ template fail* = ## fail() ## ## outputs "Checkpoint A" before quitting. - bind ensureInitialized, setProgramResult + bind ensureInitialized + when declared(testStatusIMPL): testStatusIMPL = TestStatus.FAILED else: - setProgramResult 1 + programResult = 1 ensureInitialized() @@ -617,7 +576,8 @@ template fail* = else: formatter.failureOccurred(checkpoints, "") - if abortOnError: quit(1) + when declared(programResult): + if abortOnError: quit(programResult) checkpoints = @[] @@ -641,17 +601,19 @@ macro check*(conditions: untyped): untyped = ## Verify if a statement or a list of statements is true. ## A helpful error message and set checkpoints are printed out on ## failure (if ``outputLevel`` is not ``PRINT_NONE``). - runnableExamples: - import std/strutils - - check("AKB48".toLowerAscii() == "akb48") - - let teams = {'A', 'K', 'B', '4', '8'} - - check: - "AKB48".toLowerAscii() == "akb48" - 'C' notin teams - + ## Example: + ## + ## .. code-block:: nim + ## + ## import strutils + ## + ## check("AKB48".toLowerAscii() == "akb48") + ## + ## let teams = {'A', 'K', 'B', '4', '8'} + ## + ## check: + ## "AKB48".toLowerAscii() == "akb48" + ## 'C' in teams let checked = callsite()[1] template asgn(a: untyped, value: typed) = @@ -680,15 +642,14 @@ macro check*(conditions: untyped): untyped = let paramAst = exp[i] if exp[i].kind == nnkIdent: result.printOuts.add getAst(print(argStr, paramAst)) - if exp[i].kind in nnkCallKinds + {nnkDotExpr, nnkBracketExpr, nnkPar} and - (exp[i].typeKind notin {ntyTypeDesc} or $exp[0] notin ["is", "isnot"]): + if exp[i].kind in nnkCallKinds + {nnkDotExpr, nnkBracketExpr}: let callVar = newIdentNode(":c" & $counter) result.assigns.add getAst(asgn(callVar, paramAst)) result.check[i] = callVar result.printOuts.add getAst(print(argStr, callVar)) if exp[i].kind == nnkExprEqExpr: # ExprEqExpr - # Ident "v" + # Ident !"v" # IntLit 2 result.check[i] = exp[i][1] if exp[i].typeKind notin {ntyTypeDesc}: @@ -709,9 +670,7 @@ macro check*(conditions: untyped): untyped = result = quote do: block: `assigns` - if `check`: - discard - else: + if not `check`: checkpoint(`lineinfo` & ": Check failed: " & `callLit`) `printOuts` fail() @@ -720,16 +679,14 @@ macro check*(conditions: untyped): untyped = result = newNimNode(nnkStmtList) for node in checked: if node.kind != nnkCommentStmt: - result.add(newCall(newIdentNode("check"), node)) + result.add(newCall(!"check", node)) else: let lineinfo = newStrLitNode(checked.lineInfo) let callLit = checked.toStrLit result = quote do: - if `checked`: - discard - else: + if not `checked`: checkpoint(`lineinfo` & ": Check failed: " & `callLit`) fail() @@ -747,19 +704,22 @@ macro expect*(exceptions: varargs[typed], body: untyped): untyped = ## Test if `body` raises an exception found in the passed `exceptions`. ## The test passes if the raised exception is part of the acceptable ## exceptions. Otherwise, it fails. - runnableExamples: - import std/[math, random, strutils] - proc defectiveRobot() = - randomize() - case rand(1..4) - of 1: raise newException(OSError, "CANNOT COMPUTE!") - of 2: discard parseInt("Hello World!") - of 3: raise newException(IOError, "I can't do that Dave.") - else: assert 2 + 2 == 5 - - expect IOError, OSError, ValueError, AssertionDefect: - defectiveRobot() - + ## Example: + ## + ## .. code-block:: nim + ## + ## import math, random + ## proc defectiveRobot() = + ## randomize() + ## case random(1..4) + ## of 1: raise newException(OSError, "CANNOT COMPUTE!") + ## of 2: discard parseInt("Hello World!") + ## of 3: raise newException(IOError, "I can't do that Dave.") + ## else: assert 2 + 2 == 5 + ## + ## expect IOError, OSError, ValueError, AssertionError: + ## defectiveRobot() + let exp = callsite() template expectBody(errorTypes, lineInfoLit, body): NimNode {.dirty.} = try: body @@ -771,11 +731,13 @@ macro expect*(exceptions: varargs[typed], body: untyped): untyped = checkpoint(lineInfoLit & ": Expect Failed, unexpected exception was thrown.") fail() - var errorTypes = newNimNode(nnkBracket) - for exp in exceptions: - errorTypes.add(exp) + var body = exp[exp.len - 1] - result = getAst(expectBody(errorTypes, errorTypes.lineInfo, body)) + var errorTypes = newNimNode(nnkBracket) + for i in countup(1, exp.len - 2): + errorTypes.add(exp[i]) + + result = getAst(expectBody(errorTypes, exp.lineInfo, body)) proc disableParamFiltering* = ## disables filtering tests with the command line params diff --git a/lib/pure/uri.nim b/lib/pure/uri.nim index ebc8b90ef..9112671c7 100644 --- a/lib/pure/uri.nim +++ b/lib/pure/uri.nim @@ -11,38 +11,33 @@ ## ## A Uniform Resource Identifier (URI) provides a simple and extensible ## means for identifying a resource. A URI can be further classified -## as a locator, a name, or both. The term "Uniform Resource Locator" +## as a locator, a name, or both. The term “Uniform Resource Locator” ## (URL) refers to the subset of URIs. ## -## # Basic usage - - -## ## Combine URIs -runnableExamples: - let host = parseUri("https://nim-lang.org") - assert $host == "https://nim-lang.org" - assert $(host / "/blog.html") == "https://nim-lang.org/blog.html" - assert $(host / "blog2.html") == "https://nim-lang.org/blog2.html" - -## ## Access URI item -runnableExamples: - let res = parseUri("sftp://127.0.0.1:4343") - assert isAbsolute(res) - assert res.port == "4343" - -## ## Data URI Base64 -runnableExamples: - assert getDataUri("Hello World", "text/plain") == "data:text/plain;charset=utf-8;base64,SGVsbG8gV29ybGQ=" - assert getDataUri("Nim", "text/plain") == "data:text/plain;charset=utf-8;base64,Tmlt" - - -import std/[strutils, parseutils, base64] -import std/private/[since, decode_helpers] - -when defined(nimPreviewSlimSystem): - import std/assertions - +## Basic usage +## =========== +## +## Combine URIs +## ------------- +## .. code-block:: +## import uri +## let host = parseUri("https://nim-lang.org") +## let blog = "/blog.html" +## let bloguri = host / blog +## assert $host == "https://nim-lang.org" +## assert $bloguri == "https://nim-lang.org/blog.html" +## +## Access URI item +## --------------- +## .. code-block:: +## import uri +## let res = parseUri("sftp://127.0.0.1:4343") +## if isAbsolute(res): +## assert res.port == "4343" +## else: +## echo "Wrong format" +import strutils, parseutils type Url* = distinct string @@ -50,29 +45,21 @@ type scheme*, username*, password*: string hostname*, port*, path*, query*, anchor*: string opaque*: bool - isIpv6*: bool - UriParseError* = object of ValueError - - -proc uriParseError*(msg: string) {.noreturn.} = - ## Raises a `UriParseError` exception with message `msg`. - raise newException(UriParseError, msg) - -func encodeUrl*(s: string, usePlus = true): string = +proc encodeUrl*(s: string, usePlus = true): string = ## Encodes a URL according to RFC3986. ## ## This means that characters in the set - ## `{'a'..'z', 'A'..'Z', '0'..'9', '-', '.', '_', '~'}` are + ## ``{'a'..'z', 'A'..'Z', '0'..'9', '-', '.', '_', '~'}`` are ## carried over to the result. - ## All other characters are encoded as `%xx` where `xx` + ## All other characters are encoded as ``%xx`` where ``xx`` ## denotes its hexadecimal value. ## - ## As a special rule, when the value of `usePlus` is true, - ## spaces are encoded as `+` instead of `%20`. + ## As a special rule, when the value of ``usePlus`` is true, + ## spaces are encoded as ``+`` instead of ``%20``. ## ## **See also:** - ## * `decodeUrl func<#decodeUrl,string>`_ + ## * `decodeUrl proc<#decodeUrl,string>`_ runnableExamples: assert encodeUrl("https://nim-lang.org") == "https%3A%2F%2Fnim-lang.org" assert encodeUrl("https://nim-lang.org/this is a test") == "https%3A%2F%2Fnim-lang.org%2Fthis+is+a+test" @@ -88,25 +75,29 @@ func encodeUrl*(s: string, usePlus = true): string = add(result, '%') add(result, toHex(ord(c), 2)) -func decodeUrl*(s: string, decodePlus = true): string = +proc decodeUrl*(s: string, decodePlus = true): string = ## Decodes a URL according to RFC3986. ## - ## This means that any `%xx` (where `xx` denotes a hexadecimal - ## value) are converted to the character with ordinal number `xx`, + ## This means that any ``%xx`` (where ``xx`` denotes a hexadecimal + ## value) are converted to the character with ordinal number ``xx``, ## and every other character is carried over. - ## If `xx` is not a valid hexadecimal value, it is left intact. ## - ## As a special rule, when the value of `decodePlus` is true, `+` + ## As a special rule, when the value of ``decodePlus`` is true, ``+`` ## characters are converted to a space. ## ## **See also:** - ## * `encodeUrl func<#encodeUrl,string>`_ + ## * `encodeUrl proc<#encodeUrl,string>`_ runnableExamples: assert decodeUrl("https%3A%2F%2Fnim-lang.org") == "https://nim-lang.org" assert decodeUrl("https%3A%2F%2Fnim-lang.org%2Fthis+is+a+test") == "https://nim-lang.org/this is a test" assert decodeUrl("https%3A%2F%2Fnim-lang.org%2Fthis%20is%20a%20test", false) == "https://nim-lang.org/this is a test" - assert decodeUrl("abc%xyz") == "abc%xyz" + proc handleHexChar(c: char, x: var int) {.inline.} = + case c + of '0'..'9': x = (x shl 4) or (ord(c) - ord('0')) + of 'a'..'f': x = (x shl 4) or (ord(c) - ord('a') + 10) + of 'A'..'F': x = (x shl 4) or (ord(c) - ord('A') + 10) + else: assert(false) result = newString(s.len) var i = 0 @@ -114,7 +105,11 @@ func decodeUrl*(s: string, decodePlus = true): string = while i < s.len: case s[i] of '%': - result[j] = decodePercent(s, i) + var x = 0 + handleHexChar(s[i+1], x) + handleHexChar(s[i+2], x) + inc(i, 2) + result[j] = chr(x) of '+': if decodePlus: result[j] = ' ' @@ -125,28 +120,27 @@ func decodeUrl*(s: string, decodePlus = true): string = inc(j) setLen(result, j) -func encodeQuery*(query: openArray[(string, string)], usePlus = true, - omitEq = true, sep = '&'): string = +proc encodeQuery*(query: openArray[(string, string)], usePlus = true, + omitEq = true): string = ## Encodes a set of (key, value) parameters into a URL query string. ## - ## Every (key, value) pair is URL-encoded and written as `key=value`. If the - ## value is an empty string then the `=` is omitted, unless `omitEq` is + ## Every (key, value) pair is URL-encoded and written as ``key=value``. If the + ## value is an empty string then the ``=`` is omitted, unless ``omitEq`` is ## false. - ## The pairs are joined together by the `sep` character. + ## The pairs are joined together by a ``&`` character. ## - ## The `usePlus` parameter is passed down to the `encodeUrl` function that + ## The ``usePlus`` parameter is passed down to the `encodeUrl` function that ## is used for the URL encoding of the string values. ## ## **See also:** - ## * `encodeUrl func<#encodeUrl,string>`_ + ## * `encodeUrl proc<#encodeUrl,string>`_ runnableExamples: assert encodeQuery({: }) == "" assert encodeQuery({"a": "1", "b": "2"}) == "a=1&b=2" assert encodeQuery({"a": "1", "b": ""}) == "a=1&b" - assert encodeQuery({"a": "1", "b": ""}, omitEq = false, sep = ';') == "a=1;b=" for elem in query: - # Encode the `key = value` pairs and separate them with 'sep' - if result.len > 0: result.add(sep) + # Encode the `key = value` pairs and separate them with a '&' + if result.len > 0: result.add('&') let (key, val) = elem result.add(encodeUrl(key, usePlus)) # Omit the '=' if the value string is empty @@ -154,52 +148,7 @@ func encodeQuery*(query: openArray[(string, string)], usePlus = true, result.add('=') result.add(encodeUrl(val, usePlus)) -iterator decodeQuery*(data: string, sep = '&'): tuple[key, value: string] = - ## Reads and decodes the query string `data` and yields the `(key, value)` pairs - ## the data consists of. If compiled with `-d:nimLegacyParseQueryStrict`, - ## a `UriParseError` is raised when there is an unencoded `=` character in a decoded - ## value, which was the behavior in Nim < 1.5.1. - runnableExamples: - import std/sequtils - assert toSeq(decodeQuery("foo=1&bar=2=3")) == @[("foo", "1"), ("bar", "2=3")] - assert toSeq(decodeQuery("foo=1;bar=2=3", ';')) == @[("foo", "1"), ("bar", "2=3")] - assert toSeq(decodeQuery("&a&=b&=&&")) == @[("", ""), ("a", ""), ("", "b"), ("", ""), ("", "")] - - proc parseData(data: string, i: int, field: var string, sep: char): int = - result = i - while result < data.len: - let c = data[result] - case c - of '%': add(field, decodePercent(data, result)) - of '+': add(field, ' ') - of '&': break - else: - if c == sep: break - else: add(field, data[result]) - inc(result) - - var i = 0 - var name = "" - var value = "" - # decode everything in one pass: - while i < data.len: - setLen(name, 0) # reuse memory - i = parseData(data, i, name, '=') - setLen(value, 0) # reuse memory - if i < data.len and data[i] == '=': - inc(i) # skip '=' - when defined(nimLegacyParseQueryStrict): - i = parseData(data, i, value, '=') - else: - i = parseData(data, i, value, sep) - yield (name, value) - if i < data.len: - when defined(nimLegacyParseQueryStrict): - if data[i] != '&': - uriParseError("'&' expected at index '$#' for '$#'" % [$i, data]) - inc(i) - -func parseAuthority(authority: string, result: var Uri) = +proc parseAuthority(authority: string, result: var Uri) = var i = 0 var inPort = false var inIPv6 = false @@ -218,7 +167,6 @@ func parseAuthority(authority: string, result: var Uri) = inPort = true of '[': inIPv6 = true - result.isIpv6 = true of ']': inIPv6 = false else: @@ -228,7 +176,8 @@ func parseAuthority(authority: string, result: var Uri) = result.hostname.add(authority[i]) i.inc -func parsePath(uri: string, i: var int, result: var Uri) = +proc parsePath(uri: string, i: var int, result: var Uri) = + i.inc parseUntil(uri, result.path, {'?', '#'}, i) # The 'mailto' scheme's PATH actually contains the hostname/username @@ -244,34 +193,31 @@ func parsePath(uri: string, i: var int, result: var Uri) = i.inc # Skip '#' i.inc parseUntil(uri, result.anchor, {}, i) -func initUri*(isIpv6 = false): Uri = - ## Initializes a URI with `scheme`, `username`, `password`, - ## `hostname`, `port`, `path`, `query`, `anchor` and `isIpv6`. +proc initUri*(): Uri = + ## Initializes a URI with ``scheme``, ``username``, ``password``, + ## ``hostname``, ``port``, ``path``, ``query`` and ``anchor``. ## ## **See also:** ## * `Uri type <#Uri>`_ for available fields in the URI type runnableExamples: - var uri2 = initUri(isIpv6 = true) - uri2.scheme = "tcp" - uri2.hostname = "2001:0db8:85a3:0000:0000:8a2e:0370:7334" - uri2.port = "8080" - assert $uri2 == "tcp://[2001:0db8:85a3:0000:0000:8a2e:0370:7334]:8080" + var uri2: Uri + assert initUri() == uri2 result = Uri(scheme: "", username: "", password: "", hostname: "", port: "", - path: "", query: "", anchor: "", isIpv6: isIpv6) + path: "", query: "", anchor: "") -func resetUri(uri: var Uri) = +proc resetUri(uri: var Uri) = for f in uri.fields: when f is string: f.setLen(0) else: f = false -func parseUri*(uri: string, result: var Uri) = +proc parseUri*(uri: string, result: var Uri) = ## Parses a URI. The `result` variable will be cleared before. ## ## **See also:** ## * `Uri type <#Uri>`_ for available fields in the URI type - ## * `initUri func <#initUri>`_ for initializing a URI + ## * `initUri proc <#initUri>`_ for initializing a URI runnableExamples: var res = initUri() parseUri("https://nim-lang.org/docs/manual.html", res) @@ -283,9 +229,9 @@ func parseUri*(uri: string, result: var Uri) = var i = 0 # Check if this is a reference URI (relative URI) - let doubleSlash = uri.len > 1 and uri[0] == '/' and uri[1] == '/' + let doubleSlash = uri.len > 1 and uri[1] == '/' if i < uri.len and uri[i] == '/': - # Make sure `uri` doesn't begin with '//'. + # Make sure ``uri`` doesn't begin with '//'. if not doubleSlash: parsePath(uri, i, result) return @@ -314,7 +260,7 @@ func parseUri*(uri: string, result: var Uri) = # Path parsePath(uri, i, result) -func parseUri*(uri: string): Uri = +proc parseUri*(uri: string): Uri = ## Parses a URI and returns it. ## ## **See also:** @@ -327,18 +273,10 @@ func parseUri*(uri: string): Uri = result = initUri() parseUri(uri, result) -func removeDotSegments(path: string): string = - ## Collapses `..` and `.` in `path` in a similar way as done in `os.normalizedPath` - ## Caution: this is buggy. - runnableExamples: - assert removeDotSegments("a1/a2/../a3/a4/a5/./a6/a7/.//./") == "a1/a3/a4/a5/a6/a7/" - assert removeDotSegments("http://www.ai.") == "http://www.ai." - # xxx adapt or reuse `pathnorm.normalizePath(path, '/')` to make this more reliable, but - # taking into account url specificities such as not collapsing leading `//` in scheme - # `https://`. see `turi` for failing tests. +proc removeDotSegments(path: string): string = if path.len == 0: return "" var collection: seq[string] = @[] - let endsWithSlash = path.endsWith '/' + let endsWithSlash = path[path.len-1] == '/' var i = 0 var currentSegment = "" while i < path.len: @@ -352,7 +290,7 @@ func removeDotSegments(path: string): string = discard collection.pop() i.inc 3 continue - elif i + 1 < path.len and path[i+1] == '/': + elif path[i+1] == '/': i.inc 2 continue currentSegment.add path[i] @@ -365,7 +303,7 @@ func removeDotSegments(path: string): string = result = collection.join("/") if endsWithSlash: result.add '/' -func merge(base, reference: Uri): string = +proc merge(base, reference: Uri): string = # http://tools.ietf.org/html/rfc3986#section-5.2.3 if base.hostname != "" and base.path == "": '/' & reference.path @@ -376,7 +314,7 @@ func merge(base, reference: Uri): string = else: base.path[0 .. lastSegment] & reference.path -func combine*(base: Uri, reference: Uri): Uri = +proc combine*(base: Uri, reference: Uri): Uri = ## Combines a base URI with a reference URI. ## ## This uses the algorithm specified in @@ -386,7 +324,7 @@ func combine*(base: Uri, reference: Uri): Uri = ## URIs path affect the resulting URI. ## ## **See also:** - ## * `/ func <#/,Uri,string>`_ for building URIs + ## * `/ proc <#/,Uri,string>`_ for building URIs runnableExamples: let foo = combine(parseUri("https://nim-lang.org/foo/bar"), parseUri("/baz")) assert foo.path == "/baz" @@ -427,11 +365,11 @@ func combine*(base: Uri, reference: Uri): Uri = result.scheme = base.scheme result.anchor = reference.anchor -func combine*(uris: varargs[Uri]): Uri = +proc combine*(uris: varargs[Uri]): Uri = ## Combines multiple URIs together. ## ## **See also:** - ## * `/ func <#/,Uri,string>`_ for building URIs + ## * `/ proc <#/,Uri,string>`_ for building URIs runnableExamples: let foo = combine(parseUri("https://nim-lang.org/"), parseUri("docs/"), parseUri("manual.html")) @@ -441,22 +379,24 @@ func combine*(uris: varargs[Uri]): Uri = for i in 1 ..< uris.len: result = combine(result, uris[i]) -func isAbsolute*(uri: Uri): bool = +proc isAbsolute*(uri: Uri): bool = ## Returns true if URI is absolute, false otherwise. runnableExamples: - assert parseUri("https://nim-lang.org").isAbsolute - assert not parseUri("nim-lang").isAbsolute + let foo = parseUri("https://nim-lang.org") + assert isAbsolute(foo) == true + let bar = parseUri("nim-lang") + assert isAbsolute(bar) == false return uri.scheme != "" and (uri.hostname != "" or uri.path != "") -func `/`*(x: Uri, path: string): Uri = +proc `/`*(x: Uri, path: string): Uri = ## Concatenates the path specified to the specified URIs path. ## - ## Contrary to the `combine func <#combine,Uri,Uri>`_ you do not have to worry about + ## Contrary to the `combine proc <#combine,Uri,Uri>`_ you do not have to worry about ## the slashes at the beginning and end of the path and URIs path ## respectively. ## ## **See also:** - ## * `combine func <#combine,Uri,Uri>`_ + ## * `combine proc <#combine,Uri,Uri>`_ runnableExamples: let foo = parseUri("https://nim-lang.org/foo/bar") / "/baz" assert foo.path == "/foo/bar/baz" @@ -482,7 +422,7 @@ func `/`*(x: Uri, path: string): Uri = result.path.add '/' result.path.add(path) -func `?`*(u: Uri, query: openArray[(string, string)]): Uri = +proc `?`*(u: Uri, query: openArray[(string, string)]): Uri = ## Concatenates the query parameters to the specified URI object. runnableExamples: let foo = parseUri("https://example.com") / "foo" ? {"bar": "qux"} @@ -490,81 +430,309 @@ func `?`*(u: Uri, query: openArray[(string, string)]): Uri = result = u result.query = encodeQuery(query) -func `$`*(u: Uri): string = +proc `$`*(u: Uri): string = ## Returns the string representation of the specified URI object. runnableExamples: - assert $parseUri("https://nim-lang.org") == "https://nim-lang.org" - # Get the len of all the parts. - let schemeLen = u.scheme.len - let usernameLen = u.username.len - let passwordLen = u.password.len - let hostnameLen = u.hostname.len - let portLen = u.port.len - let pathLen = u.path.len - let queryLen = u.query.len - let anchorLen = u.anchor.len - # Prepare a string that fits all the parts and all punctuation chars. - # 12 is the max len required by all possible punctuation chars. - result = newStringOfCap( - schemeLen + usernameLen + passwordLen + hostnameLen + portLen + pathLen + queryLen + anchorLen + 12 - ) - # Insert to result. - if schemeLen > 0: - result.add u.scheme - result.add ':' - if not u.opaque: - result.add '/' - result.add '/' - if usernameLen > 0: - result.add u.username - if passwordLen > 0: - result.add ':' - result.add u.password - result.add '@' + let foo = parseUri("https://nim-lang.org") + assert $foo == "https://nim-lang.org" + result = "" + if u.scheme.len > 0: + result.add(u.scheme) + if u.opaque: + result.add(":") + else: + result.add("://") + if u.username.len > 0: + result.add(u.username) + if u.password.len > 0: + result.add(":") + result.add(u.password) + result.add("@") if u.hostname.endsWith('/'): - if u.isIpv6: - result.add '[' - result.add u.hostname[0 .. ^2] - result.add ']' - else: - result.add u.hostname[0 .. ^2] + result.add(u.hostname[0..^2]) else: - if u.isIpv6: - result.add '[' - result.add u.hostname - result.add ']' - else: - result.add u.hostname - if portLen > 0: - result.add ':' - result.add u.port - if pathLen > 0: - if hostnameLen > 0 and u.path[0] != '/': - result.add '/' - result.add u.path - if queryLen > 0: - result.add '?' - result.add u.query - if anchorLen > 0: - result.add '#' - result.add u.anchor + result.add(u.hostname) + if u.port.len > 0: + result.add(":") + result.add(u.port) + if u.path.len > 0: + if u.hostname.len > 0 and u.path[0] != '/': + result.add('/') + result.add(u.path) + if u.query.len > 0: + result.add("?") + result.add(u.query) + if u.anchor.len > 0: + result.add("#") + result.add(u.anchor) +when isMainModule: + block: + const test1 = "abc\L+def xyz" + doAssert encodeUrl(test1) == "abc%0A%2Bdef+xyz" + doAssert decodeUrl(encodeUrl(test1)) == test1 + doAssert encodeUrl(test1, false) == "abc%0A%2Bdef%20xyz" + doAssert decodeUrl(encodeUrl(test1, false), false) == test1 + doAssert decodeUrl(encodeUrl(test1)) == test1 -proc getDataUri*(data, mime: string, encoding = "utf-8"): string {.since: (1, 3).} = - ## Convenience proc for `base64.encode` returns a standard Base64 Data URI (RFC-2397) - ## - ## **See also:** - ## * `mimetypes `_ for `mime` argument - ## * https://tools.ietf.org/html/rfc2397 - ## * https://en.wikipedia.org/wiki/Data_URI_scheme - runnableExamples: static: assert getDataUri("Nim", "text/plain") == "data:text/plain;charset=utf-8;base64,Tmlt" - assert encoding.len > 0 and mime.len > 0 # Must *not* be URL-Safe, see RFC-2397 - let base64encoded: string = base64.encode(data) - # ("data:".len + ";charset=".len + ";base64,".len) == 22 - result = newStringOfCap(22 + mime.len + encoding.len + base64encoded.len) - result.add "data:" - result.add mime - result.add ";charset=" - result.add encoding - result.add ";base64," - result.add base64encoded + block: + let str = "http://localhost" + let test = parseUri(str) + doAssert test.path == "" + + block: + let str = "http://localhost/" + let test = parseUri(str) + doAssert test.path == "/" + + block: + let str = "http://localhost:8080/test" + let test = parseUri(str) + doAssert test.scheme == "http" + doAssert test.port == "8080" + doAssert test.path == "/test" + doAssert test.hostname == "localhost" + doAssert($test == str) + + block: + let str = "foo://username:password@example.com:8042/over/there" & + "/index.dtb?type=animal&name=narwhal#nose" + let test = parseUri(str) + doAssert test.scheme == "foo" + doAssert test.username == "username" + doAssert test.password == "password" + doAssert test.hostname == "example.com" + doAssert test.port == "8042" + doAssert test.path == "/over/there/index.dtb" + doAssert test.query == "type=animal&name=narwhal" + doAssert test.anchor == "nose" + doAssert($test == str) + + block: + # IPv6 address + let str = "foo://[::1]:1234/bar?baz=true&qux#quux" + let uri = parseUri(str) + doAssert uri.scheme == "foo" + doAssert uri.hostname == "::1" + doAssert uri.port == "1234" + doAssert uri.path == "/bar" + doAssert uri.query == "baz=true&qux" + doAssert uri.anchor == "quux" + + block: + let str = "urn:example:animal:ferret:nose" + let test = parseUri(str) + doAssert test.scheme == "urn" + doAssert test.path == "example:animal:ferret:nose" + doAssert($test == str) + + block: + let str = "mailto:username@example.com?subject=Topic" + let test = parseUri(str) + doAssert test.scheme == "mailto" + doAssert test.username == "username" + doAssert test.hostname == "example.com" + doAssert test.query == "subject=Topic" + doAssert($test == str) + + block: + let str = "magnet:?xt=urn:sha1:72hsga62ba515sbd62&dn=foobar" + let test = parseUri(str) + doAssert test.scheme == "magnet" + doAssert test.query == "xt=urn:sha1:72hsga62ba515sbd62&dn=foobar" + doAssert($test == str) + + block: + let str = "/test/foo/bar?q=2#asdf" + let test = parseUri(str) + doAssert test.scheme == "" + doAssert test.path == "/test/foo/bar" + doAssert test.query == "q=2" + doAssert test.anchor == "asdf" + doAssert($test == str) + + block: + let str = "test/no/slash" + let test = parseUri(str) + doAssert test.path == "test/no/slash" + doAssert($test == str) + + block: + let str = "//git@github.com:dom96/packages" + let test = parseUri(str) + doAssert test.scheme == "" + doAssert test.username == "git" + doAssert test.hostname == "github.com" + doAssert test.port == "dom96" + doAssert test.path == "/packages" + + block: + let str = "file:///foo/bar/baz.txt" + let test = parseUri(str) + doAssert test.scheme == "file" + doAssert test.username == "" + doAssert test.hostname == "" + doAssert test.port == "" + doAssert test.path == "/foo/bar/baz.txt" + + # Remove dot segments tests + block: + doAssert removeDotSegments("/foo/bar/baz") == "/foo/bar/baz" + + # Combine tests + block: + let concat = combine(parseUri("http://google.com/foo/bar/"), parseUri("baz")) + doAssert concat.path == "/foo/bar/baz" + doAssert concat.hostname == "google.com" + doAssert concat.scheme == "http" + + block: + let concat = combine(parseUri("http://google.com/foo"), parseUri("/baz")) + doAssert concat.path == "/baz" + doAssert concat.hostname == "google.com" + doAssert concat.scheme == "http" + + block: + let concat = combine(parseUri("http://google.com/foo/test"), parseUri("bar")) + doAssert concat.path == "/foo/bar" + + block: + let concat = combine(parseUri("http://google.com/foo/test"), parseUri("/bar")) + doAssert concat.path == "/bar" + + block: + let concat = combine(parseUri("http://google.com/foo/test"), parseUri("bar")) + doAssert concat.path == "/foo/bar" + + block: + let concat = combine(parseUri("http://google.com/foo/test/"), parseUri("bar")) + doAssert concat.path == "/foo/test/bar" + + block: + let concat = combine(parseUri("http://google.com/foo/test/"), parseUri("bar/")) + doAssert concat.path == "/foo/test/bar/" + + block: + let concat = combine(parseUri("http://google.com/foo/test/"), parseUri("bar/"), + parseUri("baz")) + doAssert concat.path == "/foo/test/bar/baz" + + # `/` tests + block: + let test = parseUri("http://example.com/foo") / "bar/asd" + doAssert test.path == "/foo/bar/asd" + + block: + let test = parseUri("http://example.com/foo/") / "/bar/asd" + doAssert test.path == "/foo/bar/asd" + + # removeDotSegments tests + block: + # empty test + doAssert removeDotSegments("") == "" + + # bug #3207 + block: + doAssert parseUri("http://qq/1").combine(parseUri("https://qqq")).`$` == "https://qqq" + + # bug #4959 + block: + let foo = parseUri("http://example.com") / "/baz" + doAssert foo.path == "/baz" + + # bug found on stream 13/10/17 + block: + let foo = parseUri("http://localhost:9515") / "status" + doAssert $foo == "http://localhost:9515/status" + + # bug #6649 #6652 + block: + var foo = parseUri("http://example.com") + foo.hostname = "example.com" + foo.path = "baz" + doAssert $foo == "http://example.com/baz" + + foo.hostname = "example.com/" + foo.path = "baz" + doAssert $foo == "http://example.com/baz" + + foo.hostname = "example.com" + foo.path = "/baz" + doAssert $foo == "http://example.com/baz" + + foo.hostname = "example.com/" + foo.path = "/baz" + doAssert $foo == "http://example.com/baz" + + foo.hostname = "example.com/" + foo.port = "8000" + foo.path = "baz" + doAssert $foo == "http://example.com:8000/baz" + + foo = parseUri("file:/dir/file") + foo.path = "relative" + doAssert $foo == "file:relative" + + # isAbsolute tests + block: + doAssert "www.google.com".parseUri().isAbsolute() == false + doAssert "http://www.google.com".parseUri().isAbsolute() == true + doAssert "file:/dir/file".parseUri().isAbsolute() == true + doAssert "file://localhost/dir/file".parseUri().isAbsolute() == true + doAssert "urn:ISSN:1535-3613".parseUri().isAbsolute() == true + + # path-relative URL *relative + doAssert "about".parseUri().isAbsolute == false + doAssert "about/staff.html".parseUri().isAbsolute == false + doAssert "about/staff.html?".parseUri().isAbsolute == false + doAssert "about/staff.html?parameters".parseUri().isAbsolute == false + + # absolute-path-relative URL *relative + doAssert "/".parseUri().isAbsolute == false + doAssert "/about".parseUri().isAbsolute == false + doAssert "/about/staff.html".parseUri().isAbsolute == false + doAssert "/about/staff.html?".parseUri().isAbsolute == false + doAssert "/about/staff.html?parameters".parseUri().isAbsolute == false + + # scheme-relative URL *relative + doAssert "//username:password@example.com:8888".parseUri().isAbsolute == false + doAssert "//username@example.com".parseUri().isAbsolute == false + doAssert "//example.com".parseUri().isAbsolute == false + doAssert "//example.com/".parseUri().isAbsolute == false + doAssert "//example.com/about".parseUri().isAbsolute == false + doAssert "//example.com/about/staff.html".parseUri().isAbsolute == false + doAssert "//example.com/about/staff.html?".parseUri().isAbsolute == false + doAssert "//example.com/about/staff.html?parameters".parseUri().isAbsolute == false + + # absolute URL *absolute + doAssert "https://username:password@example.com:8888".parseUri().isAbsolute == true + doAssert "https://username@example.com".parseUri().isAbsolute == true + doAssert "https://example.com".parseUri().isAbsolute == true + doAssert "https://example.com/".parseUri().isAbsolute == true + doAssert "https://example.com/about".parseUri().isAbsolute == true + doAssert "https://example.com/about/staff.html".parseUri().isAbsolute == true + doAssert "https://example.com/about/staff.html?".parseUri().isAbsolute == true + doAssert "https://example.com/about/staff.html?parameters".parseUri().isAbsolute == true + + # encodeQuery tests + block: + doAssert encodeQuery({:}) == "" + doAssert encodeQuery({"foo": "bar"}) == "foo=bar" + doAssert encodeQuery({"foo": "bar & baz"}) == "foo=bar+%26+baz" + doAssert encodeQuery({"foo": "bar & baz"}, usePlus = false) == "foo=bar%20%26%20baz" + doAssert encodeQuery({"foo": ""}) == "foo" + doAssert encodeQuery({"foo": ""}, omitEq = false) == "foo=" + doAssert encodeQuery({"a": "1", "b": "", "c": "3"}) == "a=1&b&c=3" + doAssert encodeQuery({"a": "1", "b": "", "c": "3"}, omitEq = false) == "a=1&b=&c=3" + + block: + var foo = parseUri("http://example.com") / "foo" ? {"bar": "1", "baz": "qux"} + var foo1 = parseUri("http://example.com/foo?bar=1&baz=qux") + doAssert foo == foo1 + + block: + var foo = parseUri("http://example.com") / "foo" ? {"do": "do", "bar": ""} + var foo1 = parseUri("http://example.com/foo?do=do&bar") + doAssert foo == foo1 + + echo("All good!") diff --git a/lib/pure/volatile.nim b/lib/pure/volatile.nim index f30d899df..b3705a199 100644 --- a/lib/pure/volatile.nim +++ b/lib/pure/volatile.nim @@ -12,25 +12,19 @@ template volatileLoad*[T](src: ptr T): T = ## Generates a volatile load of the value stored in the container `src`. - ## Note that this only effects code generation on `C` like backends. - when nimvm: + ## Note that this only effects code generation on `C` like backends + when defined(js): src[] else: - when defined(js): - src[] - else: - var res: T - {.emit: [res, " = (*(", typeof(src[]), " volatile*)", src, ");"].} - res + var res: T + {.emit: [res, " = (*(", type(src[]), " volatile*)", src, ");"].} + res template volatileStore*[T](dest: ptr T, val: T) = ## Generates a volatile store into the container `dest` of the value ## `val`. Note that this only effects code generation on `C` like - ## backends. - when nimvm: + ## backends + when defined(js): dest[] = val else: - when defined(js): - dest[] = val - else: - {.emit: ["*((", typeof(dest[]), " volatile*)(", dest, ")) = ", val, ";"].} + {.emit: ["*((", type(dest[]), " volatile*)(", dest, ")) = ", val, ";"].} diff --git a/lib/pure/xmlparser.nim b/lib/pure/xmlparser.nim index 6785fa66e..2a2d19dca 100644 --- a/lib/pure/xmlparser.nim +++ b/lib/pure/xmlparser.nim @@ -11,9 +11,6 @@ import streams, parsexml, strtabs, xmltree -when defined(nimPreviewSlimSystem): - import std/syncio - type XmlError* = object of ValueError ## Exception that is raised ## for invalid XML. @@ -102,11 +99,11 @@ proc parse(x: var XmlParser, errors: var seq[string]): XmlNode = of xmlEof: discard proc parseXml*(s: Stream, filename: string, - errors: var seq[string], options: set[XmlParseOption] = {reportComments}): XmlNode = + errors: var seq[string]): XmlNode = ## Parses the XML from stream ``s`` and returns a ``XmlNode``. Every ## occurred parsing error is added to the ``errors`` sequence. var x: XmlParser - open(x, s, filename, options) + open(x, s, filename, {reportComments}) while true: x.next() case x.kind @@ -121,32 +118,32 @@ proc parseXml*(s: Stream, filename: string, break close(x) -proc parseXml*(s: Stream, options: set[XmlParseOption] = {reportComments}): XmlNode = +proc parseXml*(s: Stream): XmlNode = ## Parses the XML from stream ``s`` and returns a ``XmlNode``. All parsing ## errors are turned into an ``XmlError`` exception. var errors: seq[string] = @[] - result = parseXml(s, "unknown_xml_doc", errors, options) + result = parseXml(s, "unknown_xml_doc", errors) if errors.len > 0: raiseInvalidXml(errors) -proc parseXml*(str: string, options: set[XmlParseOption] = {reportComments}): XmlNode = +proc parseXml*(str: string): XmlNode = ## Parses the XML from string ``str`` and returns a ``XmlNode``. All parsing ## errors are turned into an ``XmlError`` exception. - parseXml(newStringStream(str), options) + parseXml(newStringStream(str)) -proc loadXml*(path: string, errors: var seq[string], options: set[XmlParseOption] = {reportComments}): XmlNode = +proc loadXml*(path: string, errors: var seq[string]): XmlNode = ## Loads and parses XML from file specified by ``path``, and returns ## a ``XmlNode``. Every occurred parsing error is added to the ``errors`` ## sequence. var s = newFileStream(path, fmRead) if s == nil: raise newException(IOError, "Unable to read file: " & path) - result = parseXml(s, path, errors, options) + result = parseXml(s, path, errors) -proc loadXml*(path: string, options: set[XmlParseOption] = {reportComments}): XmlNode = +proc loadXml*(path: string): XmlNode = ## Loads and parses XML from file specified by ``path``, and returns ## a ``XmlNode``. All parsing errors are turned into an ``XmlError`` ## exception. var errors: seq[string] = @[] - result = loadXml(path, errors, options) + result = loadXml(path, errors) if errors.len > 0: raiseInvalidXml(errors) when isMainModule: diff --git a/lib/pure/xmltree.nim b/lib/pure/xmltree.nim index 82513bc98..b23e00fdb 100644 --- a/lib/pure/xmltree.nim +++ b/lib/pure/xmltree.nim @@ -9,33 +9,32 @@ ## A simple XML tree generator. ## -runnableExamples: - var g = newElement("myTag") - g.add newText("some text") - g.add newComment("this is comment") - - var h = newElement("secondTag") - h.add newEntity("some entity") - - let att = {"key1": "first value", "key2": "second value"}.toXmlAttributes - let k = newXmlTree("treeTag", [g, h], att) - - doAssert $k == """ - some text - &some entity; -""" - +## .. code-block:: +## import xmltree +## +## var g = newElement("myTag") +## g.add newText("some text") +## g.add newComment("this is comment") +## +## var h = newElement("secondTag") +## h.add newEntity("some entity") +## +## let att = {"key1": "first value", "key2": "second value"}.toXmlAttributes +## let k = newXmlTree("treeTag", [g, h], att) +## +## echo k +## # +## # some text +## # &some entity; +## # +## +## ## **See also:** ## * `xmlparser module `_ for high-level XML parsing ## * `parsexml module `_ for low-level XML parsing ## * `htmlgen module `_ for html code generator -import std/private/since -import macros, strtabs, strutils, sequtils - -when defined(nimPreviewSlimSystem): - import std/assertions - +import macros, strtabs, strutils type XmlNode* = ref XmlNodeObj ## An XML tree consisting of XML nodes. @@ -45,7 +44,6 @@ type XmlNodeKind* = enum ## Different kinds of XML nodes. xnText, ## a text element - xnVerbatimText, ## xnElement, ## an element with 0 or more children xnCData, ## a CDATA node xnEntity, ## an entity (like ``&thing;``) @@ -58,7 +56,7 @@ type XmlNodeObj {.acyclic.} = object case k: XmlNodeKind # private, use the kind() proc to read this field. - of xnText, xnVerbatimText, xnComment, xnCData, xnEntity: + of xnText, xnComment, xnCData, xnEntity: fText: string of xnElement: fTag: string @@ -70,19 +68,11 @@ const xmlHeader* = "\n" ## Header to use for complete XML output. -template expect(node: XmlNode, kind: set[XmlNodeKind]) = - ## Check the node's kind is within a set of values - assert node.k in kind, "Got " & $node.k - -template expect(node: XmlNode, kind: XmlNodeKind) = - ## Check the node's kind equals a value - assert node.k == kind, "Got " & $node.k - proc newXmlNode(kind: XmlNodeKind): XmlNode = ## Creates a new ``XmlNode``. result = XmlNode(k: kind) -proc newElement*(tag: sink string): XmlNode = +proc newElement*(tag: string): XmlNode = ## Creates a new ``XmlNode`` of kind ``xnElement`` with the given `tag`. ## ## See also: @@ -92,16 +82,14 @@ proc newElement*(tag: sink string): XmlNode = var a = newElement("firstTag") a.add newElement("childTag") assert a.kind == xnElement - assert $a == """ - -""" + assert $a == "" result = newXmlNode(xnElement) result.fTag = tag result.s = @[] # init attributes lazily to save memory -proc newText*(text: sink string): XmlNode = +proc newText*(text: string): XmlNode = ## Creates a new ``XmlNode`` of kind ``xnText`` with the text `text`. runnableExamples: var b = newText("my text") @@ -111,13 +99,7 @@ proc newText*(text: sink string): XmlNode = result = newXmlNode(xnText) result.fText = text -proc newVerbatimText*(text: sink string): XmlNode {.since: (1, 3).} = - ## Creates a new ``XmlNode`` of kind ``xnVerbatimText`` with the text `text`. - ## **Since**: Version 1.3. - result = newXmlNode(xnVerbatimText) - result.fText = text - -proc newComment*(comment: sink string): XmlNode = +proc newComment*(comment: string): XmlNode = ## Creates a new ``XmlNode`` of kind ``xnComment`` with the text `comment`. runnableExamples: var c = newComment("my comment") @@ -127,7 +109,7 @@ proc newComment*(comment: sink string): XmlNode = result = newXmlNode(xnComment) result.fText = comment -proc newCData*(cdata: sink string): XmlNode = +proc newCData*(cdata: string): XmlNode = ## Creates a new ``XmlNode`` of kind ``xnCData`` with the text `cdata`. runnableExamples: var d = newCData("my cdata") @@ -147,27 +129,28 @@ proc newEntity*(entity: string): XmlNode = result = newXmlNode(xnEntity) result.fText = entity -proc newXmlTree*(tag: sink string, children: openArray[XmlNode], +proc newXmlTree*(tag: string, children: openArray[XmlNode], attributes: XmlAttributes = nil): XmlNode = ## Creates a new XML tree with `tag`, `children` and `attributes`. ## ## See also: ## * `newElement proc <#newElement,string>`_ ## * [<> macro](#<>.m,untyped) - - runnableExamples: - var g = newElement("myTag") - g.add newText("some text") - g.add newComment("this is comment") - var h = newElement("secondTag") - h.add newEntity("some entity") - let att = {"key1": "first value", "key2": "second value"}.toXmlAttributes - let k = newXmlTree("treeTag", [g, h], att) - - doAssert $k == """ - some text - &some entity; -""" + ## + ## .. code-block:: + ## var g = newElement("myTag") + ## g.add newText("some text") + ## g.add newComment("this is comment") + ## var h = newElement("secondTag") + ## h.add newEntity("some entity") + ## let att = {"key1": "first value", "key2": "second value"}.toXmlAttributes + ## let k = newXmlTree("treeTag", [g, h], att) + ## + ## echo k + ## ## + ## ## some text + ## ## &some entity; + ## ## result = newXmlNode(xnElement) result.fTag = tag @@ -175,7 +158,7 @@ proc newXmlTree*(tag: sink string, children: openArray[XmlNode], for i in 0..children.len-1: result.s[i] = children[i] result.fAttr = attributes -proc text*(n: XmlNode): lent string {.inline.} = +proc text*(n: XmlNode): string {.inline.} = ## Gets the associated text with the node `n`. ## ## `n` can be a CDATA, Text, comment, or entity node. @@ -190,10 +173,10 @@ proc text*(n: XmlNode): lent string {.inline.} = assert $c == "" assert c.text == "my comment" - n.expect {xnText, xnComment, xnCData, xnEntity} + assert n.k in {xnText, xnComment, xnCData, xnEntity} result = n.fText -proc `text=`*(n: XmlNode, text: sink string) {.inline.} = +proc `text=`*(n: XmlNode, text: string){.inline.} = ## Sets the associated text with the node `n`. ## ## `n` can be a CDATA, Text, comment, or entity node. @@ -208,10 +191,10 @@ proc `text=`*(n: XmlNode, text: sink string) {.inline.} = e.text = "a new entity text" assert $e == "&a new entity text;" - n.expect {xnText, xnComment, xnCData, xnEntity} + assert n.k in {xnText, xnComment, xnCData, xnEntity} n.fText = text -proc tag*(n: XmlNode): lent string {.inline.} = +proc tag*(n: XmlNode): string {.inline.} = ## Gets the tag name of `n`. ## ## `n` has to be an ``xnElement`` node. @@ -224,15 +207,13 @@ proc tag*(n: XmlNode): lent string {.inline.} = runnableExamples: var a = newElement("firstTag") a.add newElement("childTag") - assert $a == """ - -""" + assert $a == "" assert a.tag == "firstTag" - n.expect xnElement + assert n.k == xnElement result = n.fTag -proc `tag=`*(n: XmlNode, tag: sink string) {.inline.} = +proc `tag=`*(n: XmlNode, tag: string) {.inline.} = ## Sets the tag name of `n`. ## ## `n` has to be an ``xnElement`` node. @@ -244,15 +225,11 @@ proc `tag=`*(n: XmlNode, tag: sink string) {.inline.} = runnableExamples: var a = newElement("firstTag") a.add newElement("childTag") - assert $a == """ - -""" + assert $a == "" a.tag = "newTag" - assert $a == """ - -""" + assert $a == "" - n.expect xnElement + assert n.k == xnElement n.fTag = tag proc rawText*(n: XmlNode): string {.inline.} = @@ -306,206 +283,55 @@ proc innerText*(n: XmlNode): string = proc add*(father, son: XmlNode) {.inline.} = ## Adds the child `son` to `father`. - ## `father` must be of `xnElement` type ## ## See also: - ## * `add proc <#add,XmlNode,openArray[XmlNode]>`_ ## * `insert proc <#insert,XmlNode,XmlNode,int>`_ - ## * `insert proc <#insert,XmlNode,openArray[XmlNode],int>`_ ## * `delete proc <#delete,XmlNode,Natural>`_ - ## * `delete proc <#delete.XmlNode,Slice[int]>`_ - ## * `replace proc <#replace.XmlNode,int,openArray[XmlNode]>`_ - ## * `replace proc <#replace.XmlNode,Slice[int],openArray[XmlNode]>`_ runnableExamples: var f = newElement("myTag") f.add newText("my text") f.add newElement("sonTag") f.add newEntity("my entity") assert $f == "my text&my entity;" - - father.expect xnElement add(father.s, son) -proc add*(father: XmlNode, sons: openArray[XmlNode]) {.inline.} = - ## Adds the children `sons` to `father`. - ## `father` must be of `xnElement` type - ## - ## See also: - ## * `add proc <#add,XmlNode,XmlNode>`_ - ## * `insert proc <#insert,XmlNode,XmlNode,int>`_ - ## * `insert proc <#insert,XmlNode,openArray[XmlNode],int>`_ - ## * `delete proc <#delete,XmlNode,Natural>`_ - ## * `delete proc <#delete.XmlNode,Slice[int]>`_ - ## * `replace proc <#replace.XmlNode,int,openArray[XmlNode]>`_ - ## * `replace proc <#replace.XmlNode,Slice[int],openArray[XmlNode]>`_ - runnableExamples: - var f = newElement("myTag") - f.add(@[newText("my text"), newElement("sonTag"), newEntity("my entity")]) - assert $f == "my text&my entity;" - - father.expect xnElement - add(father.s, sons) - - proc insert*(father, son: XmlNode, index: int) {.inline.} = - ## Inserts the child `son` to a given position in `father`. + ## Insert the child `son` to a given position in `father`. ## - ## `father` must be of `xnElement` kind. + ## `father` and `son` must be of `xnElement` kind. ## ## See also: - ## * `insert proc <#insert,XmlNode,openArray[XmlNode],int>`_ ## * `add proc <#add,XmlNode,XmlNode>`_ - ## * `add proc <#add,XmlNode,openArray[XmlNode]>`_ ## * `delete proc <#delete,XmlNode,Natural>`_ - ## * `delete proc <#delete.XmlNode,Slice[int]>`_ - ## * `replace proc <#replace.XmlNode,int,openArray[XmlNode]>`_ - ## * `replace proc <#replace.XmlNode,Slice[int],openArray[XmlNode]>`_ runnableExamples: + from strutils import unindent var f = newElement("myTag") f.add newElement("first") f.insert(newElement("second"), 0) - assert $f == """ - - -""" + assert ($f).unindent == "\n\n\n" - father.expect xnElement + assert father.k == xnElement and son.k == xnElement if len(father.s) > index: insert(father.s, son, index) else: insert(father.s, son, len(father.s)) -proc insert*(father: XmlNode, sons: openArray[XmlNode], index: int) {.inline.} = - ## Inserts the children openArray[`sons`] to a given position in `father`. - ## - ## `father` must be of `xnElement` kind. +proc delete*(n: XmlNode, i: Natural) {.noSideEffect.} = + ## Delete the `i`'th child of `n`. ## ## See also: - ## * `insert proc <#insert,XmlNode,XmlNode,int>`_ ## * `add proc <#add,XmlNode,XmlNode>`_ - ## * `add proc <#add,XmlNode,openArray[XmlNode]>`_ - ## * `delete proc <#delete,XmlNode,Natural>`_ - ## * `delete proc <#delete.XmlNode,Slice[int]>`_ - ## * `replace proc <#replace.XmlNode,int,openArray[XmlNode]>`_ - ## * `replace proc <#replace.XmlNode,Slice[int],openArray[XmlNode]>`_ - runnableExamples: - var f = newElement("myTag") - f.add newElement("first") - f.insert([newElement("second"), newElement("third")], 0) - assert $f == """ - - - -""" - - father.expect xnElement - if len(father.s) > index: - insert(father.s, sons, index) - else: - insert(father.s, sons, len(father.s)) - -proc delete*(n: XmlNode, i: Natural) = - ## Deletes the `i`'th child of `n`. - ## - ## See also: - ## * `delete proc <#delete.XmlNode,Slice[int]>`_ - ## * `add proc <#add,XmlNode,XmlNode>`_ - ## * `add proc <#add,XmlNode,openArray[XmlNode]>`_ ## * `insert proc <#insert,XmlNode,XmlNode,int>`_ - ## * `insert proc <#insert,XmlNode,openArray[XmlNode],int>`_ - ## * `replace proc <#replace.XmlNode,int,openArray[XmlNode]>`_ - ## * `replace proc <#replace.XmlNode,Slice[int],openArray[XmlNode]>`_ runnableExamples: var f = newElement("myTag") f.add newElement("first") f.insert(newElement("second"), 0) f.delete(0) - assert $f == """ - -""" + assert $f == "" - n.expect xnElement + assert n.k == xnElement n.s.delete(i) -proc delete*(n: XmlNode, slice: Slice[int]) = - ## Deletes the items `n[slice]` of `n`. - ## - ## See also: - ## * `delete proc <#delete.XmlNode,int>`_ - ## * `add proc <#add,XmlNode,XmlNode>`_ - ## * `add proc <#add,XmlNode,openArray[XmlNode]>`_ - ## * `insert proc <#insert,XmlNode,XmlNode,int>`_ - ## * `insert proc <#insert,XmlNode,openArray[XmlNode],int>`_ - ## * `replace proc <#replace.XmlNode,int,openArray[XmlNode]>`_ - ## * `replace proc <#replace.XmlNode,Slice[int],openArray[XmlNode]>`_ - runnableExamples: - var f = newElement("myTag") - f.add newElement("first") - f.insert([newElement("second"), newElement("third")], 0) - f.delete(0..1) - assert $f == """ - -""" - - n.expect xnElement - n.s.delete(slice) - -proc replace*(n: XmlNode, i: Natural, replacement: openArray[XmlNode]) = - ## Replaces the `i`'th child of `n` with `replacement` openArray. - ## - ## `n` must be of `xnElement` kind. - ## - ## See also: - ## * `replace proc <#replace.XmlNode,Slice[int],openArray[XmlNode]>`_ - ## * `add proc <#add,XmlNode,XmlNode>`_ - ## * `add proc <#add,XmlNode,openArray[XmlNode]>`_ - ## * `delete proc <#delete,XmlNode,Natural>`_ - ## * `delete proc <#delete.XmlNode,Slice[int]>`_ - ## * `insert proc <#insert,XmlNode,XmlNode,int>`_ - ## * `insert proc <#insert,XmlNode,openArray[XmlNode],int>`_ - runnableExamples: - var f = newElement("myTag") - f.add newElement("first") - f.insert(newElement("second"), 0) - f.replace(0, @[newElement("third"), newElement("fourth")]) - assert $f == """ - - - -""" - - n.expect xnElement - n.s.delete(i) - n.s.insert(replacement, i) - -proc replace*(n: XmlNode, slice: Slice[int], replacement: openArray[XmlNode]) = - ## Deletes the items `n[slice]` of `n`. - ## - ## `n` must be of `xnElement` kind. - ## - ## See also: - ## * `replace proc <#replace.XmlNode,int,openArray[XmlNode]>`_ - ## * `add proc <#add,XmlNode,XmlNode>`_ - ## * `add proc <#add,XmlNode,openArray[XmlNode]>`_ - ## * `delete proc <#delete,XmlNode,Natural>`_ - ## * `delete proc <#delete.XmlNode,Slice[int]>`_ - ## * `insert proc <#insert,XmlNode,XmlNode,int>`_ - ## * `insert proc <#insert,XmlNode,openArray[XmlNode],int>`_ - runnableExamples: - var f = newElement("myTag") - f.add newElement("first") - f.insert([newElement("second"), newElement("fifth")], 0) - f.replace(0..1, @[newElement("third"), newElement("fourth")]) - assert $f == """ - - - -""" - - n.expect xnElement - n.s.delete(slice) - n.s.insert(replacement, slice.a) - proc len*(n: XmlNode): int {.inline.} = ## Returns the number of `n`'s children. runnableExamples: @@ -533,35 +359,37 @@ proc `[]`*(n: XmlNode, i: int): XmlNode {.inline.} = assert $f[1] == "" assert $f[0] == "" - n.expect xnElement + assert n.k == xnElement result = n.s[i] proc `[]`*(n: var XmlNode, i: int): var XmlNode {.inline.} = ## Returns the `i`'th child of `n` so that it can be modified. - n.expect xnElement + assert n.k == xnElement result = n.s[i] proc clear*(n: var XmlNode) = - ## Recursively clears all children of an XmlNode. + ## Recursively clear all children of an XmlNode. ## - runnableExamples: - var g = newElement("myTag") - g.add newText("some text") - g.add newComment("this is comment") - - var h = newElement("secondTag") - h.add newEntity("some entity") - - let att = {"key1": "first value", "key2": "second value"}.toXmlAttributes - var k = newXmlTree("treeTag", [g, h], att) - - doAssert $k == """ - some text - &some entity; -""" - - clear(k) - doAssert $k == """""" + ## .. code-block:: + ## var g = newElement("myTag") + ## g.add newText("some text") + ## g.add newComment("this is comment") + ## + ## var h = newElement("secondTag") + ## h.add newEntity("some entity") + ## + ## let att = {"key1": "first value", "key2": "second value"}.toXmlAttributes + ## var k = newXmlTree("treeTag", [g, h], att) + ## + ## echo k + ## ## + ## ## some text + ## ## &some entity; + ## ## + ## + ## clear(k) + ## echo k + ## ## for i in 0 ..< n.len: clear(n[i]) @@ -571,43 +399,45 @@ proc clear*(n: var XmlNode) = iterator items*(n: XmlNode): XmlNode {.inline.} = ## Iterates over all direct children of `n`. + ## + ## **Examples:** + ## + ## .. code-block:: + ## var g = newElement("myTag") + ## g.add newText("some text") + ## g.add newComment("this is comment") + ## + ## var h = newElement("secondTag") + ## h.add newEntity("some entity") + ## g.add h + ## + ## assert $g == "some text&some entity;" + ## for x in g: # the same as `for x in items(g):` + ## echo x + ## + ## # some text + ## # + ## # &some entity; - runnableExamples: - var g = newElement("myTag") - g.add newText("some text") - g.add newComment("this is comment") - - var h = newElement("secondTag") - h.add newEntity("some entity") - g.add h - - assert $g == "some text&some entity;" - - # for x in g: # the same as `for x in items(g):` - # echo x - - # some text - # - # &some entity; - - n.expect xnElement + assert n.k == xnElement for i in 0 .. n.len-1: yield n[i] iterator mitems*(n: var XmlNode): var XmlNode {.inline.} = ## Iterates over all direct children of `n` so that they can be modified. - n.expect xnElement + assert n.k == xnElement for i in 0 .. n.len-1: yield n[i] proc toXmlAttributes*(keyValuePairs: varargs[tuple[key, val: string]]): XmlAttributes = ## Converts `{key: value}` pairs into `XmlAttributes`. ## - runnableExamples: - let att = {"key1": "first value", "key2": "second value"}.toXmlAttributes - var j = newElement("myTag") - j.attrs = att - - doAssert $j == """""" + ## .. code-block:: + ## let att = {"key1": "first value", "key2": "second value"}.toXmlAttributes + ## var j = newElement("myTag") + ## j.attrs = att + ## + ## echo j + ## ## newStringTable(keyValuePairs) @@ -627,7 +457,7 @@ proc attrs*(n: XmlNode): XmlAttributes {.inline.} = j.attrs = att assert j.attrs == att - n.expect xnElement + assert n.k == xnElement result = n.fAttr proc `attrs=`*(n: XmlNode, attr: XmlAttributes) {.inline.} = @@ -644,7 +474,7 @@ proc `attrs=`*(n: XmlNode, attr: XmlAttributes) {.inline.} = j.attrs = att assert j.attrs == att - n.expect xnElement + assert n.k == xnElement n.fAttr = attr proc attrsLen*(n: XmlNode): int {.inline.} = @@ -661,7 +491,7 @@ proc attrsLen*(n: XmlNode): int {.inline.} = j.attrs = att assert j.attrsLen == 2 - n.expect xnElement + assert n.k == xnElement if not isNil(n.fAttr): result = len(n.fAttr) proc attr*(n: XmlNode, name: string): string = @@ -679,7 +509,7 @@ proc attr*(n: XmlNode, name: string): string = assert j.attr("key1") == "first value" assert j.attr("key2") == "second value" - n.expect xnElement + assert n.kind == xnElement if n.attrs == nil: return "" return n.attrs.getOrDefault(name) @@ -711,15 +541,15 @@ proc escape*(s: string): string = ## ## Escapes these characters: ## - ## ============ =================== + ## ------------ ------------------- ## char is converted to - ## ============ =================== + ## ------------ ------------------- ## ``<`` ``<`` ## ``>`` ``>`` ## ``&`` ``&`` ## ``"`` ``"`` ## ``'`` ``'`` - ## ============ =================== + ## ------------ ------------------- ## ## You can also use `addEscaped proc <#addEscaped,string,string>`_. result = newStringOfCap(s.len) @@ -728,14 +558,25 @@ proc escape*(s: string): string = proc addIndent(result: var string, indent: int, addNewLines: bool) = if addNewLines: result.add("\n") - for i in 1 .. indent: - result.add(' ') + for i in 1..indent: result.add(' ') -proc addImpl(result: var string, n: XmlNode, indent = 0, indWidth = 2, - addNewLines = true, lastNodeIsText = false) = - proc noWhitespace(n: XmlNode): bool = - for i in 0 ..< n.len: - if n[i].kind in {xnText, xnEntity}: return true +proc noWhitespace(n: XmlNode): bool = + for i in 0..n.len-1: + if n[i].kind in {xnText, xnEntity}: return true + +proc add*(result: var string, n: XmlNode, indent = 0, indWidth = 2, + addNewLines = true) = + ## Adds the textual representation of `n` to string `result`. + runnableExamples: + var + a = newElement("firstTag") + b = newText("my text") + c = newComment("my comment") + s = "" + s.add(c) + s.add(a) + s.add(b) + assert s == "my text" proc addEscapedAttr(result: var string, s: string) = # `addEscaped` alternative with less escaped characters. @@ -749,18 +590,8 @@ proc addImpl(result: var string, n: XmlNode, indent = 0, indWidth = 2, else: result.add(c) if n == nil: return - case n.k of xnElement: - if indent > 0 and not lastNodeIsText: - result.addIndent(indent, addNewLines) - - let - addNewLines = if n.noWhitespace(): - false - else: - addNewLines - result.add('<') result.add(n.fTag) if not isNil(n.fAttr): @@ -770,32 +601,29 @@ proc addImpl(result: var string, n: XmlNode, indent = 0, indWidth = 2, result.add("=\"") result.addEscapedAttr(val) result.add('"') - - if n.len == 0: + if n.len > 0: + result.add('>') + if n.len > 1: + if noWhitespace(n): + # for mixed leaves, we cannot output whitespace for readability, + # because this would be wrong. For example: ``ab`` is + # different from ``a b``. + for i in 0..n.len-1: + result.add(n[i], indent+indWidth, indWidth, addNewLines) + else: + for i in 0..n.len-1: + result.addIndent(indent+indWidth, addNewLines) + result.add(n[i], indent+indWidth, indWidth, addNewLines) + result.addIndent(indent, addNewLines) + else: + result.add(n[0], indent+indWidth, indWidth, addNewLines) + result.add("") + else: result.add(" />") - return - - let - indentNext = if n.noWhitespace(): - indent - else: - indent+indWidth - result.add('>') - var lastNodeIsText = false - for i in 0 ..< n.len: - result.addImpl(n[i], indentNext, indWidth, addNewLines, lastNodeIsText) - lastNodeIsText = n[i].kind == xnText - - if not n.noWhitespace(): - result.addIndent(indent, addNewLines) - - result.add("") of xnText: result.addEscaped(n.fText) - of xnVerbatimText: - result.add(n.fText) of xnComment: result.add("my text" - result.addImpl(n, indent, indWidth, addNewLines) - proc `$`*(n: XmlNode): string = ## Converts `n` into its string representation. ## @@ -842,7 +655,7 @@ proc child*(n: XmlNode, name: string): XmlNode = f.add newElement("thirdSon") assert $(f.child("secondSon")) == "" - n.expect xnElement + assert n.kind == xnElement for i in items(n): if i.kind == xnElement: if i.tag == name: @@ -878,7 +691,7 @@ proc findAll*(n: XmlNode, tag: string, result: var seq[XmlNode], a.findAll("BAD", s, caseInsensitive = true) assert $s == "@[c text, d text]" - n.expect xnElement + assert n.k == xnElement for child in n.items(): if child.k != xnElement: continue @@ -908,7 +721,7 @@ proc findAll*(n: XmlNode, tag: string, caseInsensitive = false): seq[XmlNode] = newSeq(result, 0) findAll(n, tag, result, caseInsensitive) -proc xmlConstructor(a: NimNode): NimNode = +proc xmlConstructor(a: NimNode): NimNode {.compileTime.} = if a.kind == nnkCall: result = newCall("newXmlTree", toStrLit(a[0])) var attrs = newNimNode(nnkBracket, a) @@ -938,8 +751,13 @@ macro `<>`*(x: untyped): untyped = ## .. code-block:: nim ## <>a(href="http://nim-lang.org", newText("Nim rules.")) ## - ## Produces an XML tree for: + ## Produces an XML tree for:: ## - ## Nim rules. + ## Nim rules. ## result = xmlConstructor(x) + + +when isMainModule: + assert """Nim rules.""" == + $(<>a(href = "http://nim-lang.org", newText("Nim rules."))) diff --git a/lib/std/appdirs.nim b/lib/std/appdirs.nim deleted file mode 100644 index c945ba8ec..000000000 --- a/lib/std/appdirs.nim +++ /dev/null @@ -1,77 +0,0 @@ -## This module implements helpers for determining special directories used by apps. - -## .. importdoc:: paths.nim - -from std/private/osappdirs import nil -import std/paths -import std/envvars - -proc getHomeDir*(): Path {.inline, tags: [ReadEnvEffect, ReadIOEffect].} = - ## Returns the home directory of the current user. - ## - ## This proc is wrapped by the `expandTilde proc`_ - ## for the convenience of processing paths coming from user configuration files. - ## - ## See also: - ## * `getConfigDir proc`_ - ## * `getTempDir proc`_ - result = Path(osappdirs.getHomeDir()) - -proc getConfigDir*(): Path {.inline, tags: [ReadEnvEffect, ReadIOEffect].} = - ## Returns the config directory of the current user for applications. - ## - ## On non-Windows OSs, this proc conforms to the XDG Base Directory - ## spec. Thus, this proc returns the value of the `XDG_CONFIG_HOME` environment - ## variable if it is set, otherwise it returns the default configuration - ## directory ("~/.config/"). - ## - ## An OS-dependent trailing slash is always present at the end of the - ## returned string: `\\` on Windows and `/` on all other OSs. - ## - ## See also: - ## * `getHomeDir proc`_ - ## * `getTempDir proc`_ - result = Path(osappdirs.getConfigDir()) - -proc getCacheDir*(): Path {.inline.} = - ## Returns the cache directory of the current user for applications. - ## - ## This makes use of the following environment variables: - ## - ## * On Windows: `getEnv("LOCALAPPDATA")` - ## - ## * On macOS: `getEnv("XDG_CACHE_HOME", getEnv("HOME") / "Library/Caches")` - ## - ## * On other platforms: `getEnv("XDG_CACHE_HOME", getEnv("HOME") / ".cache")` - ## - ## **See also:** - ## * `getHomeDir proc`_ - ## * `getTempDir proc`_ - ## * `getConfigDir proc`_ - # follows https://crates.io/crates/platform-dirs - result = Path(osappdirs.getCacheDir()) - -proc getCacheDir*(app: Path): Path {.inline.} = - ## Returns the cache directory for an application `app`. - ## - ## * On Windows, this uses: `getCacheDir() / app / "cache"` - ## * On other platforms, this uses: `getCacheDir() / app` - result = Path(osappdirs.getCacheDir(app.string)) - -proc getTempDir*(): Path {.inline, tags: [ReadEnvEffect, ReadIOEffect].} = - ## Returns the temporary directory of the current user for applications to - ## save temporary files in. - ## - ## On Windows, it calls [GetTempPath](https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-gettemppathw). - ## On Posix based platforms, it will check `TMPDIR`, `TEMP`, `TMP` and `TEMPDIR` environment variables in order. - ## On all platforms, `/tmp` will be returned if the procs fails. - ## - ## You can override this implementation - ## by adding `-d:tempDir=mytempname` to your compiler invocation. - ## - ## .. Note:: This proc does not check whether the returned path exists. - ## - ## See also: - ## * `getHomeDir proc`_ - ## * `getConfigDir proc`_ - result = Path(osappdirs.getTempDir()) diff --git a/lib/std/assertions.nim b/lib/std/assertions.nim deleted file mode 100644 index a249d7751..000000000 --- a/lib/std/assertions.nim +++ /dev/null @@ -1,127 +0,0 @@ -# -# -# Nim's Runtime Library -# (c) Copyright 2022 Nim contributors -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# - -when not defined(nimPreviewSlimSystem) and not declared(sysFatal): - include "system/rawquits" - include "system/fatal" - -## This module implements assertion handling. - -import std/private/miscdollars -# --------------------------------------------------------------------------- -# helpers - -type InstantiationInfo = tuple[filename: string, line: int, column: int] - -proc `$`(info: InstantiationInfo): string = - # The +1 is needed here - # instead of overriding `$` (and changing its meaning), consider explicit name. - result = "" - result.toLocation(info.filename, info.line, info.column + 1) - -# --------------------------------------------------------------------------- - - -proc raiseAssert*(msg: string) {.noinline, noreturn, nosinks.} = - ## Raises an `AssertionDefect` with `msg`. - when defined(nimPreviewSlimSystem): - raise newException(AssertionDefect, msg) - else: - sysFatal(AssertionDefect, msg) - -proc failedAssertImpl*(msg: string) {.raises: [], tags: [].} = - ## Raises an `AssertionDefect` with `msg`, but this is hidden - ## from the effect system. Called when an assertion failed. - # trick the compiler to not list `AssertionDefect` when called - # by `assert`. - # xxx simplify this pending bootstrap >= 1.4.0, after which cast not needed - # anymore since `Defect` can't be raised. - type Hide = proc (msg: string) {.noinline, raises: [], noSideEffect, tags: [].} - cast[Hide](raiseAssert)(msg) - -template assertImpl(cond: bool, msg: string, expr: string, enabled: static[bool]) = - when enabled: - const - loc = instantiationInfo(fullPaths = compileOption("excessiveStackTrace")) - ploc = $loc - bind instantiationInfo - mixin failedAssertImpl - {.line: loc.}: - if not cond: - failedAssertImpl(ploc & " `" & expr & "` " & msg) - -template assert*(cond: untyped, msg = "") = - ## Raises `AssertionDefect` with `msg` if `cond` is false. Note - ## that `AssertionDefect` is hidden from the effect system, so it doesn't - ## produce `{.raises: [AssertionDefect].}`. This exception is only supposed - ## to be caught by unit testing frameworks. - ## - ## No code will be generated for `assert` when passing `-d:danger` (implied by `--assertions:off`). - ## See `command line switches `_. - runnableExamples: assert 1 == 1 - runnableExamples("--assertions:off"): - assert 1 == 2 # no code generated, no failure here - runnableExamples("-d:danger"): assert 1 == 2 # ditto - assertImpl(cond, msg, astToStr(cond), compileOption("assertions")) - -template doAssert*(cond: untyped, msg = "") = - ## Similar to `assert <#assert.t,untyped,string>`_ but is always turned on regardless of `--assertions`. - runnableExamples: - doAssert 1 == 1 # generates code even when built with `-d:danger` or `--assertions:off` - assertImpl(cond, msg, astToStr(cond), true) - -template onFailedAssert*(msg, code: untyped): untyped {.dirty.} = - ## Sets an assertion failure handler that will intercept any assert - ## statements following `onFailedAssert` in the current scope. - runnableExamples: - type MyError = object of CatchableError - lineinfo: tuple[filename: string, line: int, column: int] - # block-wide policy to change the failed assert exception type in order to - # include a lineinfo - onFailedAssert(msg): - raise (ref MyError)(msg: msg, lineinfo: instantiationInfo(-2)) - doAssertRaises(MyError): doAssert false - when not defined(nimHasTemplateRedefinitionPragma): - {.pragma: redefine.} - template failedAssertImpl(msgIMPL: string): untyped {.dirty, redefine.} = - let msg = msgIMPL - code - -template doAssertRaises*(exception: typedesc, code: untyped) = - ## Raises `AssertionDefect` if specified `code` does not raise `exception`. - runnableExamples: - doAssertRaises(ValueError): raise newException(ValueError, "Hello World") - doAssertRaises(CatchableError): raise newException(ValueError, "Hello World") - doAssertRaises(AssertionDefect): doAssert false - var wrong = false - const begin = "expected raising '" & astToStr(exception) & "', instead" - const msgEnd = " by: " & astToStr(code) - template raisedForeign {.gensym.} = raiseAssert(begin & " raised foreign exception" & msgEnd) - {.warning[BareExcept]:off.} - when Exception is exception: - try: - if true: - code - wrong = true - except Exception as e: discard - except: raisedForeign() - else: - try: - if true: - code - wrong = true - except exception: - discard - except Exception as e: - mixin `$` # alternatively, we could define $cstring in this module - raiseAssert(begin & " raised '" & $e.name & "'" & msgEnd) - except: raisedForeign() - {.warning[BareExcept]:on.} - if wrong: - raiseAssert(begin & " nothing was raised" & msgEnd) diff --git a/lib/std/cmdline.nim b/lib/std/cmdline.nim deleted file mode 100644 index 6788dacde..000000000 --- a/lib/std/cmdline.nim +++ /dev/null @@ -1,310 +0,0 @@ -# -# -# Nim's Runtime Library -# (c) Copyright 2022 Andreas Rumpf -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# - -## This module contains system facilities for reading command -## line parameters. - -## **See also:** -## * `parseopt module `_ for command-line parser beyond -## `parseCmdLine proc`_ - - -include system/inclrtl - -when defined(nimPreviewSlimSystem): - import std/widestrs - -when defined(nodejs): - from std/private/oscommon import ReadDirEffect - - -const weirdTarget = defined(nimscript) or defined(js) - - -when weirdTarget: - discard -elif defined(windows): - import winlean -elif defined(posix): - import posix -else: - {.error: "The cmdline module has not been implemented for the target platform.".} - - -# Needed by windows in order to obtain the command line for targets -# other than command line targets -when defined(windows) and not weirdTarget: - template getCommandLine*(): untyped = getCommandLineW() - - -proc parseCmdLine*(c: string): seq[string] {. - noSideEffect, rtl, extern: "nos$1".} = - ## Splits a `command line`:idx: into several components. - ## - ## **Note**: This proc is only occasionally useful, better use the - ## `parseopt module `_. - ## - ## On Windows, it uses the `following parsing rules - ## `_: - ## - ## * Arguments are delimited by white space, which is either a space or a tab. - ## * The caret character (^) is not recognized as an escape character or - ## delimiter. The character is handled completely by the command-line parser - ## in the operating system before being passed to the argv array in the - ## program. - ## * A string surrounded by double quotation marks ("string") is interpreted - ## as a single argument, regardless of white space contained within. A - ## quoted string can be embedded in an argument. - ## * A double quotation mark preceded by a backslash (\") is interpreted as a - ## literal double quotation mark character ("). - ## * Backslashes are interpreted literally, unless they immediately precede - ## a double quotation mark. - ## * If an even number of backslashes is followed by a double quotation mark, - ## one backslash is placed in the argv array for every pair of backslashes, - ## and the double quotation mark is interpreted as a string delimiter. - ## * If an odd number of backslashes is followed by a double quotation mark, - ## one backslash is placed in the argv array for every pair of backslashes, - ## and the double quotation mark is "escaped" by the remaining backslash, - ## causing a literal double quotation mark (") to be placed in argv. - ## - ## On Posix systems, it uses the following parsing rules: - ## Components are separated by whitespace unless the whitespace - ## occurs within ``"`` or ``'`` quotes. - ## - ## See also: - ## * `parseopt module `_ - ## * `paramCount proc`_ - ## * `paramStr proc`_ - ## * `commandLineParams proc`_ - - result = @[] - var i = 0 - var a = "" - while true: - setLen(a, 0) - # eat all delimiting whitespace - while i < c.len and c[i] in {' ', '\t', '\l', '\r'}: inc(i) - if i >= c.len: break - when defined(windows): - # parse a single argument according to the above rules: - var inQuote = false - while i < c.len: - case c[i] - of '\\': - var j = i - while j < c.len and c[j] == '\\': inc(j) - if j < c.len and c[j] == '"': - for k in 1..(j-i) div 2: a.add('\\') - if (j-i) mod 2 == 0: - i = j - else: - a.add('"') - i = j+1 - else: - a.add(c[i]) - inc(i) - of '"': - inc(i) - if not inQuote: inQuote = true - elif i < c.len and c[i] == '"': - a.add(c[i]) - inc(i) - else: - inQuote = false - break - of ' ', '\t': - if not inQuote: break - a.add(c[i]) - inc(i) - else: - a.add(c[i]) - inc(i) - else: - case c[i] - of '\'', '\"': - var delim = c[i] - inc(i) # skip ' or " - while i < c.len and c[i] != delim: - add a, c[i] - inc(i) - if i < c.len: inc(i) - else: - while i < c.len and c[i] > ' ': - add(a, c[i]) - inc(i) - add(result, a) - -when defined(nimdoc): - # Common forward declaration docstring block for parameter retrieval procs. - proc paramCount*(): int {.tags: [ReadIOEffect].} = - ## Returns the number of `command line arguments`:idx: given to the - ## application. - ## - ## Unlike `argc`:idx: in C, if your binary was called without parameters this - ## will return zero. - ## You can query each individual parameter with `paramStr proc`_ - ## or retrieve all of them in one go with `commandLineParams proc`_. - ## - ## **Availability**: When generating a dynamic library (see `--app:lib`) on - ## Posix this proc is not defined. - ## Test for availability using `declared() `_. - ## - ## See also: - ## * `parseopt module `_ - ## * `parseCmdLine proc`_ - ## * `paramStr proc`_ - ## * `commandLineParams proc`_ - ## - ## **Examples:** - ## - ## .. code-block:: nim - ## when declared(paramCount): - ## # Use paramCount() here - ## else: - ## # Do something else! - - proc paramStr*(i: int): string {.tags: [ReadIOEffect].} = - ## Returns the `i`-th `command line argument`:idx: given to the application. - ## - ## `i` should be in the range `1..paramCount()`, the `IndexDefect` - ## exception will be raised for invalid values. Instead of iterating - ## over `paramCount()`_ with this proc you can - ## call the convenience `commandLineParams()`_. - ## - ## Similarly to `argv`:idx: in C, - ## it is possible to call `paramStr(0)` but this will return OS specific - ## contents (usually the name of the invoked executable). You should avoid - ## this and call `getAppFilename()`_ instead. - ## - ## **Availability**: When generating a dynamic library (see `--app:lib`) on - ## Posix this proc is not defined. - ## Test for availability using `declared() `_. - ## - ## See also: - ## * `parseopt module `_ - ## * `parseCmdLine proc`_ - ## * `paramCount proc`_ - ## * `commandLineParams proc`_ - ## * `getAppFilename proc`_ - ## - ## **Examples:** - ## - ## .. code-block:: nim - ## when declared(paramStr): - ## # Use paramStr() here - ## else: - ## # Do something else! - -elif defined(nimscript): discard -elif defined(nodejs): - type Argv = object of JsRoot - let argv {.importjs: "process.argv".} : Argv - proc len(argv: Argv): int {.importjs: "#.length".} - proc `[]`(argv: Argv, i: int): cstring {.importjs: "#[#]".} - - proc paramCount*(): int {.tags: [ReadDirEffect].} = - result = argv.len - 2 - - proc paramStr*(i: int): string {.tags: [ReadIOEffect].} = - let i = i + 1 - if i < argv.len and i >= 0: - result = $argv[i] - else: - raise newException(IndexDefect, formatErrorIndexBound(i - 1, argv.len - 2)) -elif defined(windows): - # Since we support GUI applications with Nim, we sometimes generate - # a WinMain entry proc. But a WinMain proc has no access to the parsed - # command line arguments. The way to get them differs. Thus we parse them - # ourselves. This has the additional benefit that the program's behaviour - # is always the same -- independent of the used C compiler. - var - ownArgv {.threadvar.}: seq[string] - ownParsedArgv {.threadvar.}: bool - - proc paramCount*(): int {.rtl, extern: "nos$1", tags: [ReadIOEffect].} = - # Docstring in nimdoc block. - if not ownParsedArgv: - ownArgv = parseCmdLine($getCommandLine()) - ownParsedArgv = true - result = ownArgv.len-1 - - proc paramStr*(i: int): string {.rtl, extern: "nos$1", - tags: [ReadIOEffect].} = - # Docstring in nimdoc block. - if not ownParsedArgv: - ownArgv = parseCmdLine($getCommandLine()) - ownParsedArgv = true - if i < ownArgv.len and i >= 0: - result = ownArgv[i] - else: - raise newException(IndexDefect, formatErrorIndexBound(i, ownArgv.len-1)) - -elif defined(genode): - proc paramStr*(i: int): string = - raise newException(OSError, "paramStr is not implemented on Genode") - - proc paramCount*(): int = - raise newException(OSError, "paramCount is not implemented on Genode") -elif weirdTarget or (defined(posix) and appType == "lib"): - proc paramStr*(i: int): string {.tags: [ReadIOEffect].} = - raise newException(OSError, "paramStr is not implemented on current platform") - - proc paramCount*(): int {.tags: [ReadIOEffect].} = - raise newException(OSError, "paramCount is not implemented on current platform") -elif not defined(createNimRtl) and - not(defined(posix) and appType == "lib"): - # On Posix, there is no portable way to get the command line from a DLL. - var - cmdCount {.importc: "cmdCount".}: cint - cmdLine {.importc: "cmdLine".}: cstringArray - - proc paramStr*(i: int): string {.tags: [ReadIOEffect].} = - # Docstring in nimdoc block. - if i < cmdCount and i >= 0: - result = $cmdLine[i] - else: - raise newException(IndexDefect, formatErrorIndexBound(i, cmdCount-1)) - - proc paramCount*(): int {.tags: [ReadIOEffect].} = - # Docstring in nimdoc block. - result = cmdCount-1 - -when declared(paramCount) or defined(nimdoc): - proc commandLineParams*(): seq[string] = - ## Convenience proc which returns the command line parameters. - ## - ## This returns **only** the parameters. If you want to get the application - ## executable filename, call `getAppFilename()`_. - ## - ## **Availability**: On Posix there is no portable way to get the command - ## line from a DLL and thus the proc isn't defined in this environment. You - ## can test for its availability with `declared() - ## `_. - ## - ## See also: - ## * `parseopt module `_ - ## * `parseCmdLine proc`_ - ## * `paramCount proc`_ - ## * `paramStr proc`_ - ## * `getAppFilename proc`_ - ## - ## **Examples:** - ## - ## .. code-block:: nim - ## when declared(commandLineParams): - ## # Use commandLineParams() here - ## else: - ## # Do something else! - result = @[] - for i in 1..paramCount(): - result.add(paramStr(i)) -else: - proc commandLineParams*(): seq[string] {.error: - "commandLineParams() unsupported by dynamic libraries".} = - discard diff --git a/lib/std/compilesettings.nim b/lib/std/compilesettings.nim deleted file mode 100644 index 6d8bd22f4..000000000 --- a/lib/std/compilesettings.nim +++ /dev/null @@ -1,66 +0,0 @@ -# -# -# Nim's Runtime Library -# (c) Copyright 2020 Nim Contributors -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# - -## This module allows querying the compiler about -## diverse configuration settings. See also `compileOption`. - -# Note: Only add new enum values at the end to ensure binary compatibility with -# other Nim compiler versions! - -type - SingleValueSetting* {.pure.} = enum ## \ - ## settings resulting in a single string value - arguments, ## experimental: the arguments passed after '-r' - outFile, ## experimental: the output file - outDir, ## the output directory - nimcacheDir, ## the location of the 'nimcache' directory - projectName, ## the project's name that is being compiled - projectPath, ## experimental: some path to the project that is being compiled - projectFull, ## the full path to the project that is being compiled - command, ## experimental: the command (e.g. 'c', 'cpp', 'doc') passed to - ## the Nim compiler - commandLine, ## experimental: the command line passed to Nim - linkOptions, ## additional options passed to the linker - compileOptions, ## additional options passed to the C/C++ compiler - ccompilerPath ## the path to the C/C++ compiler - backend ## the backend (eg: c|cpp|objc|js); both `nim doc --backend:js` - ## and `nim js` would imply backend=js - libPath ## the absolute path to the stdlib library, i.e. nim's `--lib`, since 1.5.1 - gc {.deprecated.} ## gc selected - mm ## memory management selected - - MultipleValueSetting* {.pure.} = enum ## \ - ## settings resulting in a seq of string values - nimblePaths, ## the nimble path(s) - searchPaths, ## the search path for modules - lazyPaths, ## experimental: even more paths - commandArgs, ## the arguments passed to the Nim compiler - cincludes, ## the #include paths passed to the C/C++ compiler - clibs ## libraries passed to the C/C++ compiler - -proc querySetting*(setting: SingleValueSetting): string {. - compileTime, noSideEffect.} = - ## Can be used to get a string compile-time option. - ## - ## See also: - ## * `compileOption `_ for `on|off` options - ## * `compileOption `_ for enum options - ## - runnableExamples: - const nimcache = querySetting(SingleValueSetting.nimcacheDir) - -proc querySettingSeq*(setting: MultipleValueSetting): seq[string] {. - compileTime, noSideEffect.} = - ## Can be used to get a multi-string compile-time option. - ## - ## See also: - ## * `compileOption `_ for `on|off` options - ## * `compileOption `_ for enum options - runnableExamples: - const nimblePaths = querySettingSeq(MultipleValueSetting.nimblePaths) diff --git a/lib/std/decls.nim b/lib/std/decls.nim deleted file mode 100644 index 3f774cd08..000000000 --- a/lib/std/decls.nim +++ /dev/null @@ -1,31 +0,0 @@ -## This module implements syntax sugar for some declarations. - -import macros - -macro byaddr*(sect) = - ## Allows a syntax for l-value references, being an exact analog to - ## `auto& a = ex;` in C++. - ## - ## .. warning:: This makes use of 2 experimental features, namely nullary - ## templates instantiated as symbols and variable macro pragmas. - ## For this reason, its behavior is not stable. The current implementation - ## allows redefinition, but this is not an intended consequence. - runnableExamples: - var s = @[10, 11, 12] - var a {.byaddr.} = s[0] - a += 100 - assert s == @[110, 11, 12] - assert a is int - var b {.byaddr.}: int = s[0] - assert a.addr == b.addr - expectLen sect, 1 - let def = sect[0] - let - lhs = def[0] - typ = def[1] - ex = def[2] - addrTyp = if typ.kind == nnkEmpty: typ else: newTree(nnkPtrTy, typ) - result = quote do: - let tmp: `addrTyp` = addr(`ex`) - template `lhs`: untyped = tmp[] - result.copyLineInfo(def) diff --git a/lib/std/dirs.nim b/lib/std/dirs.nim deleted file mode 100644 index df6107c51..000000000 --- a/lib/std/dirs.nim +++ /dev/null @@ -1,135 +0,0 @@ -## This module implements directory handling. - -from paths import Path, ReadDirEffect, WriteDirEffect - -from std/private/osdirs import dirExists, createDir, existsOrCreateDir, removeDir, - moveDir, walkDir, setCurrentDir, - walkDirRec, PathComponent - -export PathComponent - -proc dirExists*(dir: Path): bool {.inline, tags: [ReadDirEffect].} = - ## Returns true if the directory `dir` exists. If `dir` is a file, false - ## is returned. Follows symlinks. - result = dirExists(dir.string) - -proc createDir*(dir: Path) {.inline, tags: [WriteDirEffect, ReadDirEffect].} = - ## Creates the `directory`:idx: `dir`. - ## - ## The directory may contain several subdirectories that do not exist yet. - ## The full path is created. If this fails, `OSError` is raised. - ## - ## It does **not** fail if the directory already exists because for - ## most usages this does not indicate an error. - ## - ## See also: - ## * `removeDir proc`_ - ## * `existsOrCreateDir proc`_ - ## * `moveDir proc`_ - createDir(dir.string) - -proc existsOrCreateDir*(dir: Path): bool {.inline, tags: [WriteDirEffect, ReadDirEffect].} = - ## Checks if a `directory`:idx: `dir` exists, and creates it otherwise. - ## - ## Does not create parent directories (raises `OSError` if parent directories do not exist). - ## Returns `true` if the directory already exists, and `false` otherwise. - ## - ## See also: - ## * `removeDir proc`_ - ## * `createDir proc`_ - ## * `moveDir proc`_ - result = existsOrCreateDir(dir.string) - -proc removeDir*(dir: Path, checkDir = false - ) {.inline, tags: [WriteDirEffect, ReadDirEffect].} = - ## Removes the directory `dir` including all subdirectories and files - ## in `dir` (recursively). - ## - ## If this fails, `OSError` is raised. This does not fail if the directory never - ## existed in the first place, unless `checkDir` = true. - ## - ## See also: - ## * `removeFile proc `_ - ## * `existsOrCreateDir proc`_ - ## * `createDir proc`_ - ## * `moveDir proc`_ - removeDir(dir.string, checkDir) - -proc moveDir*(source, dest: Path) {.inline, tags: [ReadIOEffect, WriteIOEffect].} = - ## Moves a directory from `source` to `dest`. - ## - ## Symlinks are not followed: if `source` contains symlinks, they themself are - ## moved, not their target. - ## - ## If this fails, `OSError` is raised. - ## - ## See also: - ## * `moveFile proc `_ - ## * `removeDir proc`_ - ## * `existsOrCreateDir proc`_ - ## * `createDir proc`_ - moveDir(source.string, dest.string) - -iterator walkDir*(dir: Path; relative = false, checkDir = false, - skipSpecial = false): - tuple[kind: PathComponent, path: Path] {.tags: [ReadDirEffect].} = - ## Walks over the directory `dir` and yields for each directory or file in - ## `dir`. The component type and full path for each item are returned. - ## - ## Walking is not recursive. - ## * If `relative` is true (default: false) - ## the resulting path is shortened to be relative to ``dir``, - ## otherwise the full path is returned. - ## * If `checkDir` is true, `OSError` is raised when `dir` - ## doesn't exist. - ## * If `skipSpecial` is true, then (besides all directories) only *regular* - ## files (**without** special "file" objects like FIFOs, device files, - ## etc) will be yielded on Unix. - for (k, p) in walkDir(dir.string, relative, checkDir, skipSpecial): - yield (k, Path(p)) - -iterator walkDirRec*(dir: Path, - yieldFilter = {pcFile}, followFilter = {pcDir}, - relative = false, checkDir = false, skipSpecial = false): - Path {.tags: [ReadDirEffect].} = - ## Recursively walks over the directory `dir` and yields for each file - ## or directory in `dir`. - ## - ## Options `relative`, `checkdir`, `skipSpecial` are explained in - ## [walkDir iterator] description. - ## - ## .. warning:: Modifying the directory structure while the iterator - ## is traversing may result in undefined behavior! - ## - ## Walking is recursive. `followFilter` controls the behaviour of the iterator: - ## - ## ===================== ============================================= - ## yieldFilter meaning - ## ===================== ============================================= - ## ``pcFile`` yield real files (default) - ## ``pcLinkToFile`` yield symbolic links to files - ## ``pcDir`` yield real directories - ## ``pcLinkToDir`` yield symbolic links to directories - ## ===================== ============================================= - ## - ## ===================== ============================================= - ## followFilter meaning - ## ===================== ============================================= - ## ``pcDir`` follow real directories (default) - ## ``pcLinkToDir`` follow symbolic links to directories - ## ===================== ============================================= - ## - ## - ## See also: - ## * `walkDir iterator`_ - for p in walkDirRec(dir.string, yieldFilter, followFilter, relative, - checkDir, skipSpecial): - yield Path(p) - -proc setCurrentDir*(newDir: Path) {.inline, tags: [].} = - ## Sets the `current working directory`:idx:; `OSError` - ## is raised if `newDir` cannot been set. - ## - ## See also: - ## * `getCurrentDir proc `_ - osdirs.setCurrentDir(newDir.string) diff --git a/lib/std/editdistance.nim b/lib/std/editdistance.nim index 9f29c5c05..0cb5edc9b 100644 --- a/lib/std/editdistance.nim +++ b/lib/std/editdistance.nim @@ -13,24 +13,23 @@ import unicode proc editDistance*(a, b: string): int {.noSideEffect.} = - ## Returns the **unicode-rune** edit distance between `a` and `b`. + ## Returns the unicode-rune edit distance between ``a`` and ``b``. ## ## This uses the `Levenshtein`:idx: distance algorithm with only a linear ## memory overhead. - runnableExamples: static: doAssert editdistance("Kitten", "Bitten") == 1 if len(a) > len(b): - # make `b` the longer string + # make ``b`` the longer string return editDistance(b, a) # strip common prefix var - iStart = 0 ## The character starting index of the first rune in both strings `a` and `b` + iStart = 0 ## The character starting index of the first rune in both strings ``a`` and ``b`` iNextA = 0 iNextB = 0 runeA, runeB: Rune - lenRunesA = 0 ## The number of relevant runes in string `a`. - lenRunesB = 0 ## The number of relevant runes in string `b`. + lenRunesA = 0 ## The number of relevant runes in string ``a``. + lenRunesB = 0 ## The number of relevant runes in string ``b``. block commonPrefix: - # `a` is the shorter string + # ``a`` is the shorter string while iStart < len(a): iNextA = iStart a.fastRuneAt(iNextA, runeA, doInc = true) @@ -44,9 +43,9 @@ proc editDistance*(a, b: string): int {.noSideEffect.} = var # we know that we are either at the start of the strings # or that the current value of runeA is not equal to runeB - # => start search for common suffix after the current rune (`i_next_*`) - iEndA = iNextA ## The exclusive upper index bound of string `a`. - iEndB = iNextB ## The exclusive upper index bound of string `b`. + # => start search for common suffix after the current rune (``i_next_*``) + iEndA = iNextA ## The exclusive upper index bound of string ``a``. + iEndB = iNextB ## The exclusive upper index bound of string ``b``. iCurrentA = iNextA iCurrentB = iNextB block commonSuffix: @@ -69,8 +68,8 @@ proc editDistance*(a, b: string): int {.noSideEffect.} = addRunesB = 0 iCurrentA = iNextA iCurrentB = iNextB - if iCurrentA >= len(a): # `a` exhausted - if iCurrentB < len(b): # `b` not exhausted + if iCurrentA >= len(a): # ``a`` exhausted + if iCurrentB < len(b): # ``b`` not exhausted iEndA = iCurrentA iEndB = iCurrentB inc(lenRunesA, addRunesA) @@ -79,7 +78,7 @@ proc editDistance*(a, b: string): int {.noSideEffect.} = b.fastRuneAt(iEndB, runeB) inc(lenRunesB) if iEndB >= len(b): break - elif iCurrentB >= len(b): # `b` exhausted and `a` not exhausted + elif iCurrentB >= len(b): # ``b`` exhausted and ``a`` not exhausted iEndA = iCurrentA iEndB = iCurrentB inc(lenRunesA, addRunesA) @@ -182,7 +181,6 @@ proc editDistanceAscii*(a, b: string): int {.noSideEffect.} = ## ## This uses the `Levenshtein`:idx: distance algorithm with only a linear ## memory overhead. - runnableExamples: static: doAssert editDistanceAscii("Kitten", "Bitten") == 1 var len1 = a.len var len2 = b.len if len1 > len2: @@ -264,3 +262,44 @@ proc editDistanceAscii*(a, b: string): int {.noSideEffect.} = if x > c3: x = c3 row[p] = x result = row[e] + + +when isMainModule: + doAssert editDistance("", "") == 0 + doAssert editDistance("kitten", "sitting") == 3 # from Wikipedia + doAssert editDistance("flaw", "lawn") == 2 # from Wikipedia + + doAssert editDistance("привет", "превет") == 1 + doAssert editDistance("Åge", "Age") == 1 + # editDistance, one string is longer in bytes, but shorter in rune length + # first string: 4 bytes, second: 6 bytes, but only 3 runes + doAssert editDistance("aaaa", "×××") == 4 + + block veryLongStringEditDistanceTest: + const cap = 256 + var + s1 = newStringOfCap(cap) + s2 = newStringOfCap(cap) + while len(s1) < cap: + s1.add 'a' + while len(s2) < cap: + s2.add 'b' + doAssert editDistance(s1, s2) == cap + + block combiningCodePointsEditDistanceTest: + const s = "A\xCC\x8Age" + doAssert editDistance(s, "Age") == 1 + + doAssert editDistanceAscii("", "") == 0 + doAssert editDistanceAscii("kitten", "sitting") == 3 # from Wikipedia + doAssert editDistanceAscii("flaw", "lawn") == 2 # from Wikipedia + + + assert(editDistance("prefix__hallo_suffix", "prefix__hallo_suffix") == 0) + assert(editDistance("prefix__hallo_suffix", "prefix__hallo_suffi1") == 1) + assert(editDistance("prefix__hallo_suffix", "prefix__HALLO_suffix") == 5) + assert(editDistance("prefix__hallo_suffix", "prefix__ha_suffix") == 3) + assert(editDistance("prefix__hallo_suffix", "prefix") == 14) + assert(editDistance("prefix__hallo_suffix", "suffix") == 14) + assert(editDistance("prefix__hallo_suffix", "prefix__hao_suffix") == 2) + assert(editDistance("main", "malign") == 2) diff --git a/lib/std/effecttraits.nim b/lib/std/effecttraits.nim deleted file mode 100644 index fb057a669..000000000 --- a/lib/std/effecttraits.nim +++ /dev/null @@ -1,63 +0,0 @@ -# -# -# Nim's Runtime Library -# (c) Copyright 2020 Nim contributors -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# - -## This module provides access to the inferred .raises effects -## for Nim's macro system. -## **Since**: Version 1.4. -## -## One can test for the existence of this standard module -## via `defined(nimHasEffectTraitsModule)`. - -import macros - -proc getRaisesListImpl(n: NimNode): NimNode = discard "see compiler/vmops.nim" -proc getTagsListImpl(n: NimNode): NimNode = discard "see compiler/vmops.nim" -proc getForbidsListImpl(n: NimNode): NimNode = discard "see compiler/vmops.nim" -proc isGcSafeImpl(n: NimNode): bool = discard "see compiler/vmops.nim" -proc hasNoSideEffectsImpl(n: NimNode): bool = discard "see compiler/vmops.nim" - -proc getRaisesList*(fn: NimNode): NimNode = - ## Extracts the `.raises` list of the func/proc/etc `fn`. - ## `fn` has to be a resolved symbol of kind `nnkSym`. This - ## implies that the macro that calls this proc should accept `typed` - ## arguments and not `untyped` arguments. - expectKind fn, nnkSym - result = getRaisesListImpl(fn) - -proc getTagsList*(fn: NimNode): NimNode = - ## Extracts the `.tags` list of the func/proc/etc `fn`. - ## `fn` has to be a resolved symbol of kind `nnkSym`. This - ## implies that the macro that calls this proc should accept `typed` - ## arguments and not `untyped` arguments. - expectKind fn, nnkSym - result = getTagsListImpl(fn) - -proc getForbidsList*(fn: NimNode): NimNode = - ## Extracts the `.forbids` list of the func/proc/etc `fn`. - ## `fn` has to be a resolved symbol of kind `nnkSym`. This - ## implies that the macro that calls this proc should accept `typed` - ## arguments and not `untyped` arguments. - expectKind fn, nnkSym - result = getForbidsListImpl(fn) - -proc isGcSafe*(fn: NimNode): bool = - ## Return true if the func/proc/etc `fn` is `gcsafe`. - ## `fn` has to be a resolved symbol of kind `nnkSym`. This - ## implies that the macro that calls this proc should accept `typed` - ## arguments and not `untyped` arguments. - expectKind fn, nnkSym - result = isGcSafeImpl(fn) - -proc hasNoSideEffects*(fn: NimNode): bool = - ## Return true if the func/proc/etc `fn` has `noSideEffect`. - ## `fn` has to be a resolved symbol of kind `nnkSym`. This - ## implies that the macro that calls this proc should accept `typed` - ## arguments and not `untyped` arguments. - expectKind fn, nnkSym - result = hasNoSideEffectsImpl(fn) diff --git a/lib/std/enumerate.nim b/lib/std/enumerate.nim deleted file mode 100644 index 4f0161b7c..000000000 --- a/lib/std/enumerate.nim +++ /dev/null @@ -1,70 +0,0 @@ -# -# -# Nim's Runtime Library -# (c) Copyright 2020 Nim contributors -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# - -## This module implements `enumerate` syntactic sugar based on Nim's -## macro system. - -import std/private/since -import macros - - -macro enumerate*(x: ForLoopStmt): untyped {.since: (1, 3).} = - ## Enumerating iterator for collections. - ## - ## It yields `(count, value)` tuples (which must be immediately unpacked). - ## The default starting count `0` can be manually overridden if needed. - runnableExamples: - let a = [10, 20, 30] - var b: seq[(int, int)] = @[] - for i, x in enumerate(a): - b.add((i, x)) - assert b == @[(0, 10), (1, 20), (2, 30)] - - let c = "abcd" - var d: seq[(int, char)] - for (i, x) in enumerate(97, c): - d.add((i, x)) - assert d == @[(97, 'a'), (98, 'b'), (99, 'c'), (100, 'd')] - - template genCounter(x): untyped = - # We strip off the first for loop variable and use it as an integer counter. - # We must immediately decrement it by one, because it gets incremented before - # the loop body - to be able to use the final expression in other macros. - newVarStmt(x, infix(countStart, "-", newLit(1))) - - template genInc(x): untyped = - newCall(bindSym"inc", x) - - expectKind x, nnkForStmt - # check if the starting count is specified: - var countStart = if x[^2].len == 2: newLit(0) else: x[^2][1] - result = newStmtList() - var body = x[^1] - if body.kind != nnkStmtList: - body = newTree(nnkStmtList, body) - var newFor = newTree(nnkForStmt) - if x.len == 3: # single iteration variable - if x[0].kind == nnkVarTuple: # for (x, y, ...) in iter - result.add genCounter(x[0][0]) - body.insert(0, genInc(x[0][0])) - for i in 1 .. x[0].len-2: - newFor.add x[0][i] - else: - error("Missing second for loop variable") # for x in iter - else: # for x, y, ... in iter - result.add genCounter(x[0]) - body.insert(0, genInc(x[0])) - for i in 1 .. x.len-3: - newFor.add x[i] - # transform enumerate(X) to 'X' - newFor.add x[^2][^1] - newFor.add body - result.add newFor - # now wrap the whole macro in a block to create a new scope - result = newBlockStmt(result) diff --git a/lib/std/enumutils.nim b/lib/std/enumutils.nim deleted file mode 100644 index 59fb112ed..000000000 --- a/lib/std/enumutils.nim +++ /dev/null @@ -1,194 +0,0 @@ -# -# -# Nim's Runtime Library -# (c) Copyright 2020 Nim contributors -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# - -import macros -from typetraits import OrdinalEnum, HoleyEnum - -when defined(nimPreviewSlimSystem): - import std/assertions - - -# xxx `genEnumCaseStmt` needs tests and runnableExamples - -macro genEnumCaseStmt*(typ: typedesc, argSym: typed, default: typed, - userMin, userMax: static[int], normalizer: static[proc(s :string): string]): untyped = - # Generates a case stmt, which assigns the correct enum field given - # a normalized string comparison to the `argSym` input. - # string normalization is done using passed normalizer. - # NOTE: for an enum with fields Foo, Bar, ... we cannot generate - # `of "Foo".nimIdentNormalize: Foo`. - # This will fail, if the enum is not defined at top level (e.g. in a block). - # Thus we check for the field value of the (possible holed enum) and convert - # the integer value to the generic argument `typ`. - let typ = typ.getTypeInst[1] - let impl = typ.getImpl[2] - expectKind impl, nnkEnumTy - let normalizerNode = quote: `normalizer` - expectKind normalizerNode, nnkSym - result = nnkCaseStmt.newTree(newCall(normalizerNode, argSym)) - # stores all processed field strings to give error msg for ambiguous enums - var foundFields: seq[string] = @[] - var fStr = "" # string of current field - var fNum = BiggestInt(0) # int value of current field - for f in impl: - case f.kind - of nnkEmpty: continue # skip first node of `enumTy` - of nnkSym, nnkIdent: fStr = f.strVal - of nnkAccQuoted: - fStr = "" - for ch in f: - fStr.add ch.strVal - of nnkEnumFieldDef: - case f[1].kind - of nnkStrLit: fStr = f[1].strVal - of nnkTupleConstr: - fStr = f[1][1].strVal - fNum = f[1][0].intVal - of nnkIntLit: - fStr = f[0].strVal - fNum = f[1].intVal - else: - let fAst = f[0].getImpl - if fAst.kind == nnkStrLit: - fStr = fAst.strVal - else: - error("Invalid tuple syntax!", f[1]) - else: error("Invalid node for enum type `" & $f.kind & "`!", f) - # add field if string not already added - if fNum >= userMin and fNum <= userMax: - fStr = normalizer(fStr) - if fStr notin foundFields: - result.add nnkOfBranch.newTree(newLit fStr, nnkCall.newTree(typ, newLit fNum)) - foundFields.add fStr - else: - error("Ambiguous enums cannot be parsed, field " & $fStr & - " appears multiple times!", f) - inc fNum - # finally add else branch to raise or use default - if default == nil: - let raiseStmt = quote do: - raise newException(ValueError, "Invalid enum value: " & $`argSym`) - result.add nnkElse.newTree(raiseStmt) - else: - expectKind(default, nnkSym) - result.add nnkElse.newTree(default) - -macro enumFullRange(a: typed): untyped = - newNimNode(nnkCurly).add(a.getType[1][1..^1]) - -macro enumNames(a: typed): untyped = - # this could be exported too; in particular this could be useful for enum with holes. - result = newNimNode(nnkBracket) - for ai in a.getType[1][1..^1]: - assert ai.kind == nnkSym - result.add newLit ai.strVal - -iterator items*[T: HoleyEnum](E: typedesc[T]): T = - ## Iterates over an enum with holes. - runnableExamples: - type - A = enum - a0 = 2 - a1 = 4 - a2 - B[T] = enum - b0 = 2 - b1 = 4 - from std/sequtils import toSeq - assert A.toSeq == [a0, a1, a2] - assert B[float].toSeq == [B[float].b0, B[float].b1] - for a in enumFullRange(E): yield a - -func span(T: typedesc[HoleyEnum]): int = - (T.high.ord - T.low.ord) + 1 - -const invalidSlot = uint8.high - -proc genLookup[T: typedesc[HoleyEnum]](_: T): auto = - const n = span(T) - var i = 0 - assert n <= invalidSlot.int - var ret {.noinit.}: array[n, uint8] - for ai in mitems(ret): ai = invalidSlot - for ai in items(T): - ret[ai.ord - T.low.ord] = uint8(i) - inc(i) - return ret - -func symbolRankImpl[T](a: T): int {.inline.} = - const n = T.span - const thres = 255 # must be <= `invalidSlot`, but this should be tuned. - when n <= thres: - const lookup = genLookup(T) - let lookup2 {.global.} = lookup # xxx improve pending https://github.com/timotheecour/Nim/issues/553 - #[ - This could be optimized using a hash adapted to `T` (possible since it's known at CT) - to get better key distribution before indexing into the lookup table table. - ]# - {.noSideEffect.}: # because it's immutable - let ret = lookup2[ord(a) - T.low.ord] - if ret != invalidSlot: return ret.int - else: - var i = 0 - # we could also generate a case statement as optimization - for ai in items(T): - if ai == a: return i - inc(i) - raise newException(IndexDefect, $ord(a) & " invalid for " & $T) - -template symbolRank*[T: enum](a: T): int = - ## Returns the index in which `a` is listed in `T`. - ## - ## The cost for a `HoleyEnum` is implementation defined, currently optimized - ## for small enums, otherwise is `O(T.enumLen)`. - runnableExamples: - type - A = enum # HoleyEnum - a0 = -3 - a1 = 10 - a2 - a3 = (20, "f3Alt") - B = enum # OrdinalEnum - b0 - b1 - b2 - C = enum # OrdinalEnum - c0 = 10 - c1 - c2 - assert a2.symbolRank == 2 - assert b2.symbolRank == 2 - assert c2.symbolRank == 2 - assert c2.ord == 12 - assert a2.ord == 11 - var invalid = 7.A - doAssertRaises(IndexDefect): discard invalid.symbolRank - when T is Ordinal: ord(a) - T.low.ord.static - else: symbolRankImpl(a) - -func symbolName*[T: enum](a: T): string = - ## Returns the symbol name of an enum. - ## - ## This uses `symbolRank`. - runnableExamples: - type B = enum - b0 = (10, "kb0") - b1 = "kb1" - b2 - let b = B.low - assert b.symbolName == "b0" - assert $b == "kb0" - static: assert B.high.symbolName == "b2" - type C = enum # HoleyEnum - c0 = -3 - c1 = 4 - c2 = 20 - assert c1.symbolName == "c1" - const names = enumNames(T) - names[a.symbolRank] diff --git a/lib/std/envvars.nim b/lib/std/envvars.nim deleted file mode 100644 index ab5c9f06e..000000000 --- a/lib/std/envvars.nim +++ /dev/null @@ -1,221 +0,0 @@ -# -# -# Nim's Runtime Library -# (c) Copyright 2022 Nim contributors -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# - - -## The `std/envvars` module implements environment variable handling. -import std/oserrors - -type - ReadEnvEffect* = object of ReadIOEffect ## Effect that denotes a read - ## from an environment variable. - WriteEnvEffect* = object of WriteIOEffect ## Effect that denotes a write - ## to an environment variable. - - -when not defined(nimscript): - when defined(nodejs): - proc getEnv*(key: string, default = ""): string {.tags: [ReadEnvEffect].} = - var ret = default.cstring - let key2 = key.cstring - {.emit: "const value = process.env[`key2`];".} - {.emit: "if (value !== undefined) { `ret` = value };".} - result = $ret - - proc existsEnv*(key: string): bool {.tags: [ReadEnvEffect].} = - var key2 = key.cstring - var ret: bool - {.emit: "`ret` = `key2` in process.env;".} - result = ret - - proc putEnv*(key, val: string) {.tags: [WriteEnvEffect].} = - var key2 = key.cstring - var val2 = val.cstring - {.emit: "process.env[`key2`] = `val2`;".} - - proc delEnv*(key: string) {.tags: [WriteEnvEffect].} = - var key2 = key.cstring - {.emit: "delete process.env[`key2`];".} - - iterator envPairsImpl(): tuple[key, value: string] {.tags: [ReadEnvEffect].} = - var num: int - var keys: RootObj - {.emit: "`keys` = Object.keys(process.env); `num` = `keys`.length;".} - for i in 0..".} - from std/private/win_setenv import setEnvImpl - import winlean - when defined(nimPreviewSlimSystem): - import std/widestrs - - type wchar_t {.importc: "wchar_t", header: "".} = int16 - proc c_wgetenv(varname: ptr wchar_t): ptr wchar_t {.importc: "_wgetenv", - header: "".} - proc getEnvImpl(env: cstring): WideCString = - let r: WideCString = env.newWideCString - cast[WideCString](c_wgetenv(cast[ptr wchar_t](r))) - else: - proc c_getenv(env: cstring): cstring {. - importc: "getenv", header: "".} - proc c_setenv(envname: cstring, envval: cstring, overwrite: cint): cint {.importc: "setenv", header: "".} - proc c_unsetenv(env: cstring): cint {.importc: "unsetenv", header: "".} - proc getEnvImpl(env: cstring): cstring = c_getenv(env) - - proc getEnv*(key: string, default = ""): string {.tags: [ReadEnvEffect].} = - ## Returns the value of the `environment variable`:idx: named `key`. - ## - ## If the variable does not exist, `""` is returned. To distinguish - ## whether a variable exists or it's value is just `""`, call - ## `existsEnv(key) proc`_. - ## - ## See also: - ## * `existsEnv proc`_ - ## * `putEnv proc`_ - ## * `delEnv proc`_ - ## * `envPairs iterator`_ - runnableExamples: - assert getEnv("unknownEnv") == "" - assert getEnv("unknownEnv", "doesn't exist") == "doesn't exist" - - let env = getEnvImpl(key) - if env == nil: - result = default - else: - result = $env - - proc existsEnv*(key: string): bool {.tags: [ReadEnvEffect].} = - ## Checks whether the environment variable named `key` exists. - ## Returns true if it exists, false otherwise. - ## - ## See also: - ## * `getEnv proc`_ - ## * `putEnv proc`_ - ## * `delEnv proc`_ - ## * `envPairs iterator`_ - runnableExamples: - assert not existsEnv("unknownEnv") - - result = getEnvImpl(key) != nil - - proc putEnv*(key, val: string) {.tags: [WriteEnvEffect].} = - ## Sets the value of the `environment variable`:idx: named `key` to `val`. - ## If an error occurs, `OSError` is raised. - ## - ## See also: - ## * `getEnv proc`_ - ## * `existsEnv proc`_ - ## * `delEnv proc`_ - ## * `envPairs iterator`_ - when defined(windows): - if key.len == 0 or '=' in key: - raise newException(OSError, "invalid key, got: " & $(key, val)) - if setEnvImpl(key, val, 1'i32) != 0'i32: - raiseOSError(osLastError(), $(key, val)) - else: - if c_setenv(key, val, 1'i32) != 0'i32: - raiseOSError(osLastError(), $(key, val)) - - proc delEnv*(key: string) {.tags: [WriteEnvEffect].} = - ## Deletes the `environment variable`:idx: named `key`. - ## If an error occurs, `OSError` is raised. - ## - ## See also:ven - ## * `getEnv proc`_ - ## * `existsEnv proc`_ - ## * `putEnv proc`_ - ## * `envPairs iterator`_ - template bail = raiseOSError(osLastError(), key) - when defined(windows): - #[ - # https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/putenv-s-wputenv-s?view=msvc-160 - > You can remove a variable from the environment by specifying an empty string (that is, "") for value_string - note that nil is not legal - ]# - if key.len == 0 or '=' in key: - raise newException(OSError, "invalid key, got: " & key) - let envToDel = key & "=" - if c_putenv(cstring envToDel) != 0'i32: bail - else: - if c_unsetenv(key) != 0'i32: bail - - when defined(windows): - when defined(cpp): - proc strEnd(cstr: WideCString, c = 0'i32): WideCString {.importcpp: "(NI16*)wcschr((const wchar_t *)#, #)", - header: "".} - else: - proc strEnd(cstr: WideCString, c = 0'i32): WideCString {.importc: "wcschr", - header: "".} - elif defined(macosx) and not defined(ios) and not defined(emscripten): - # From the manual: - # Shared libraries and bundles don't have direct access to environ, - # which is only available to the loader ld(1) when a complete program - # is being linked. - # The environment routines can still be used, but if direct access to - # environ is needed, the _NSGetEnviron() routine, defined in - # , can be used to retrieve the address of environ - # at runtime. - proc NSGetEnviron(): ptr cstringArray {.importc: "_NSGetEnviron", - header: "".} - elif defined(haiku): - var gEnv {.importc: "environ", header: "".}: cstringArray - else: - var gEnv {.importc: "environ".}: cstringArray - - iterator envPairsImpl(): tuple[key, value: string] {.tags: [ReadEnvEffect].} = - when defined(windows): - let env = getEnvironmentStringsW() - var e = env - if e != nil: - while true: - let eend = strEnd(e) - let kv = $e - let p = find(kv, '=') - yield (substr(kv, 0, p-1), substr(kv, p+1)) - e = cast[WideCString](cast[ByteAddress](eend)+2) - if int(eend[1]) == 0: break - discard freeEnvironmentStringsW(env) - else: - var i = 0 - when defined(macosx) and not defined(ios) and not defined(emscripten): - var gEnv = NSGetEnviron()[] - while gEnv[i] != nil: - let kv = $gEnv[i] - inc(i) - let p = find(kv, '=') - yield (substr(kv, 0, p-1), substr(kv, p+1)) - -proc envPairsImplSeq(): seq[tuple[key, value: string]] = discard # vmops - -iterator envPairs*(): tuple[key, value: string] {.tags: [ReadEnvEffect].} = - ## Iterate over all `environments variables`:idx:. - ## - ## In the first component of the tuple is the name of the current variable stored, - ## in the second its value. - ## - ## Works in native backends, nodejs and vm, like the following APIs: - ## * `getEnv proc`_ - ## * `existsEnv proc`_ - ## * `putEnv proc`_ - ## * `delEnv proc`_ - when nimvm: - for ai in envPairsImplSeq(): yield ai - else: - when defined(nimscript): discard - else: - for ai in envPairsImpl(): yield ai diff --git a/lib/std/exitprocs.nim b/lib/std/exitprocs.nim deleted file mode 100644 index 48b4fca7f..000000000 --- a/lib/std/exitprocs.nim +++ /dev/null @@ -1,90 +0,0 @@ -# -# -# Nim's Runtime Library -# (c) Copyright 2020 Andreas Rumpf -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# - -## This module allows adding hooks to program exit. - -import locks - -type - FunKind = enum kClosure, kNoconv # extend as needed - Fun = object - case kind: FunKind - of kClosure: fun1: proc () {.closure.} - of kNoconv: fun2: proc () {.noconv.} - -var - gFunsLock: Lock - gFuns: seq[Fun] - -initLock(gFunsLock) - -when defined(js): - proc addAtExit(quitProc: proc() {.noconv.}) = - when defined(nodejs): - asm """ - process.on('exit', `quitProc`); - """ - elif defined(js): - asm """ - window.onbeforeunload = `quitProc`; - """ -else: - proc addAtExit(quitProc: proc() {.noconv.}) {. - importc: "atexit", header: "".} - -proc callClosures() {.noconv.} = - withLock gFunsLock: - for i in countdown(gFuns.len-1, 0): - let fun = gFuns[i] - case fun.kind - of kClosure: fun.fun1() - of kNoconv: fun.fun2() - gFuns.setLen(0) - -template fun() = - if gFuns.len == 0: - addAtExit(callClosures) - -proc addExitProc*(cl: proc () {.closure.}) = - ## Adds/registers a quit procedure. Each call to `addExitProc` registers - ## another quit procedure. They are executed on a last-in, first-out basis. - # Support for `addExitProc` is done by Ansi C's facilities here. - # In case of an unhandled exception the exit handlers should - # not be called explicitly! The user may decide to do this manually though. - withLock gFunsLock: - fun() - gFuns.add Fun(kind: kClosure, fun1: cl) - -proc addExitProc*(cl: proc() {.noconv.}) = - ## overload for `noconv` procs. - withLock gFunsLock: - fun() - gFuns.add Fun(kind: kNoconv, fun2: cl) - -when not defined(nimscript): - proc getProgramResult*(): int = - when defined(js) and defined(nodejs): - asm """ -`result` = process.exitCode; -""" - elif not defined(js): - result = programResult - else: - doAssert false - - proc setProgramResult*(a: int) = - # pending https://github.com/nim-lang/Nim/issues/14674 - when defined(js) and defined(nodejs): - asm """ -process.exitCode = `a`; -""" - elif not defined(js): - programResult = a - else: - doAssert false diff --git a/lib/std/files.nim b/lib/std/files.nim deleted file mode 100644 index 138bb5234..000000000 --- a/lib/std/files.nim +++ /dev/null @@ -1,43 +0,0 @@ -## This module implements file handling. - -from paths import Path, ReadDirEffect, WriteDirEffect - -from std/private/osfiles import fileExists, removeFile, - moveFile - - -proc fileExists*(filename: Path): bool {.inline, tags: [ReadDirEffect].} = - ## Returns true if `filename` exists and is a regular file or symlink. - ## - ## Directories, device files, named pipes and sockets return false. - result = fileExists(filename.string) - -proc removeFile*(file: Path) {.inline, tags: [WriteDirEffect].} = - ## Removes the `file`. - ## - ## If this fails, `OSError` is raised. This does not fail - ## if the file never existed in the first place. - ## - ## On Windows, ignores the read-only attribute. - ## - ## See also: - ## * `removeDir proc `_ - ## * `moveFile proc`_ - removeFile(file.string) - -proc moveFile*(source, dest: Path) {.inline, - tags: [ReadDirEffect, ReadIOEffect, WriteIOEffect].} = - ## Moves a file from `source` to `dest`. - ## - ## Symlinks are not followed: if `source` is a symlink, it is itself moved, - ## not its target. - ## - ## If this fails, `OSError` is raised. - ## If `dest` already exists, it will be overwritten. - ## - ## Can be used to `rename files`:idx:. - ## - ## See also: - ## * `moveDir proc `_ - ## * `removeFile proc`_ - moveFile(source.string, dest.string) diff --git a/lib/std/formatfloat.nim b/lib/std/formatfloat.nim deleted file mode 100644 index b216d1fd0..000000000 --- a/lib/std/formatfloat.nim +++ /dev/null @@ -1,142 +0,0 @@ -# -# -# Nim's Runtime Library -# (c) Copyright 2022 Nim contributors -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# - -## This module implements formatting floats as strings. - -when defined(nimPreviewSlimSystem): - import std/assertions - -proc c_memcpy(a, b: pointer, size: csize_t): pointer {.importc: "memcpy", header: "", discardable.} - -proc addCstringN(result: var string, buf: cstring; buflen: int) = - # no nimvm support needed, so it doesn't need to be fast here either - let oldLen = result.len - let newLen = oldLen + buflen - result.setLen newLen - c_memcpy(result[oldLen].addr, buf, buflen.csize_t) - -import std/private/[dragonbox, schubfach] - -proc writeFloatToBufferRoundtrip*(buf: var array[65, char]; value: BiggestFloat): int = - ## This is the implementation to format floats. - ## - ## returns the amount of bytes written to `buf` not counting the - ## terminating '\0' character. - result = toChars(buf, value, forceTrailingDotZero=true).int - buf[result] = '\0' - -proc writeFloatToBufferRoundtrip*(buf: var array[65, char]; value: float32): int = - result = float32ToChars(buf, value, forceTrailingDotZero=true).int - buf[result] = '\0' - -proc c_sprintf(buf, frmt: cstring): cint {.header: "", - importc: "sprintf", varargs, noSideEffect.} - -proc writeToBuffer(buf: var array[65, char]; value: cstring) = - var i = 0 - while value[i] != '\0': - buf[i] = value[i] - inc i - -proc writeFloatToBufferSprintf*(buf: var array[65, char]; value: BiggestFloat): int = - ## This is the implementation to format floats. - ## - ## returns the amount of bytes written to `buf` not counting the - ## terminating '\0' character. - var n = c_sprintf(cast[cstring](addr buf), "%.16g", value).int - var hasDot = false - for i in 0..n-1: - if buf[i] == ',': - buf[i] = '.' - hasDot = true - elif buf[i] in {'a'..'z', 'A'..'Z', '.'}: - hasDot = true - if not hasDot: - buf[n] = '.' - buf[n+1] = '0' - buf[n+2] = '\0' - result = n + 2 - else: - result = n - # On Windows nice numbers like '1.#INF', '-1.#INF' or '1.#NAN' or 'nan(ind)' - # of '-1.#IND' are produced. - # We want to get rid of these here: - if buf[n-1] in {'n', 'N', 'D', 'd', ')'}: - writeToBuffer(buf, "nan") - result = 3 - elif buf[n-1] == 'F': - if buf[0] == '-': - writeToBuffer(buf, "-inf") - result = 4 - else: - writeToBuffer(buf, "inf") - result = 3 - -proc writeFloatToBuffer*(buf: var array[65, char]; value: BiggestFloat | float32): int {.inline.} = - when defined(nimPreviewFloatRoundtrip) or defined(nimPreviewSlimSystem): - writeFloatToBufferRoundtrip(buf, value) - else: - writeFloatToBufferSprintf(buf, value) - -proc addFloatRoundtrip*(result: var string; x: float | float32) = - when nimvm: - doAssert false - else: - var buffer {.noinit.}: array[65, char] - let n = writeFloatToBufferRoundtrip(buffer, x) - result.addCstringN(cast[cstring](buffer[0].addr), n) - -proc addFloatSprintf*(result: var string; x: float) = - when nimvm: - doAssert false - else: - var buffer {.noinit.}: array[65, char] - let n = writeFloatToBufferSprintf(buffer, x) - result.addCstringN(cast[cstring](buffer[0].addr), n) - -proc nimFloatToString(a: float): cstring = - ## ensures the result doesn't print like an integer, i.e. return 2.0, not 2 - # print `-0.0` properly - asm """ - function nimOnlyDigitsOrMinus(n) { - return n.toString().match(/^-?\d+$/); - } - if (Number.isSafeInteger(`a`)) - `result` = `a` === 0 && 1 / `a` < 0 ? "-0.0" : `a`+".0" - else { - `result` = `a`+"" - if(nimOnlyDigitsOrMinus(`result`)){ - `result` = `a`+".0" - } - } - """ - -proc addFloat*(result: var string; x: float | float32) {.inline.} = - ## Converts float to its string representation and appends it to `result`. - runnableExamples: - var - s = "foo:" - b = 45.67 - s.addFloat(45.67) - assert s == "foo:45.67" - template impl = - when defined(nimPreviewFloatRoundtrip) or defined(nimPreviewSlimSystem): - addFloatRoundtrip(result, x) - else: - addFloatSprintf(result, x) - when defined(js): - when nimvm: impl() - else: - result.add nimFloatToString(x) - else: impl() - -when defined(nimPreviewSlimSystem): - func `$`*(x: float | float32): string = - ## Outplace version of `addFloat`. - result.addFloat(x) diff --git a/lib/std/genasts.nim b/lib/std/genasts.nim deleted file mode 100644 index 05b2823ef..000000000 --- a/lib/std/genasts.nim +++ /dev/null @@ -1,89 +0,0 @@ -## This module implements AST generation using captured variables for macros. - -import macros - -type GenAstOpt* = enum - kDirtyTemplate, - # When set, uses a dirty template in implementation of `genAst`. This - # is occasionally useful as workaround for issues such as #8220, see - # `strformat limitations `_ for details. - # Default is unset, to avoid hijacking of uncaptured local symbols by - # symbols in caller scope. - kNoNewLit, - # don't call call newLit automatically in `genAst` capture parameters - -macro genAstOpt*(options: static set[GenAstOpt], args: varargs[untyped]): untyped = - ## Accepts a list of captured variables `a=b` or `a` and a block and returns the - ## AST that represents it. Local `{.inject.}` symbols (e.g. procs) are captured - ## unless `kDirtyTemplate in options`. - runnableExamples: - # This example shows how one could write a simplified version of `unittest.check`. - import std/[macros, strutils] - macro check2(cond: bool): untyped = - assert cond.kind == nnkInfix, "$# not implemented" % $cond.kind - result = genAst(cond, s = repr(cond), lhs = cond[1], rhs = cond[2]): - # each local symbol we access must be explicitly captured - if not cond: - doAssert false, "'$#'' failed: lhs: '$#', rhs: '$#'" % [s, $lhs, $rhs] - let a = 3 - check2 a*2 == a+3 - if false: check2 a*2 < a+1 # would error with: 'a * 2 < a + 1'' failed: lhs: '6', rhs: '4' - - runnableExamples: - # This example goes in more details about the capture semantics. - macro fun(a: string, b: static bool): untyped = - let c = 'z' - var d = 11 # implicitly {.gensym.} and needs to be captured for use in `genAst`. - proc localFun(): auto = 12 # implicitly {.inject.}, doesn't need to be captured. - genAst(a, b, c = true): - # `a`, `b` are captured explicitly, `c` is a local definition masking `c = 'z'`. - const b2 = b # macro static param `b` is forwarded here as a static param. - # `echo d` would give: `var not init` because `d` is not captured. - (a & a, b, c, localFun()) # localFun can be called without capture. - assert fun("ab", false) == ("abab", false, true, 12) - - let params = newTree(nnkFormalParams, newEmptyNode()) - let pragmas = - if kDirtyTemplate in options: - nnkPragma.newTree(ident"dirty") - else: - newEmptyNode() - - template newLitMaybe(a): untyped = - when (a is type) or (typeof(a) is (proc | iterator | func | NimNode)): - a # `proc` actually also covers template, macro - else: newLit(a) - - # using `_` as workaround, see https://github.com/nim-lang/Nim/issues/2465#issuecomment-511076669 - let name = genSym(nskTemplate, "_fun") - let call = newCall(name) - for a in args[0..^2]: - var varName: NimNode - var varVal: NimNode - case a.kind - of nnkExprEqExpr: - varName = a[0] - varVal = a[1] - of nnkIdent: - varName = a - varVal = a - else: error("invalid argument kind: " & $a.kind, a) - if kNoNewLit notin options: varVal = newCall(bindSym"newLitMaybe", varVal) - - params.add newTree(nnkIdentDefs, varName, newEmptyNode(), newEmptyNode()) - call.add varVal - - result = newStmtList() - result.add nnkTemplateDef.newTree( - name, - newEmptyNode(), - newEmptyNode(), - params, - pragmas, - newEmptyNode(), - args[^1]) - result.add newCall(bindSym"getAst", call) - -template genAst*(args: varargs[untyped]): untyped = - ## Convenience wrapper around `genAstOpt`. - genAstOpt({}, args) diff --git a/lib/std/importutils.nim b/lib/std/importutils.nim deleted file mode 100644 index d2da76ea8..000000000 --- a/lib/std/importutils.nim +++ /dev/null @@ -1,44 +0,0 @@ -##[ -Utilities related to import and symbol resolution. - -Experimental API, subject to change. -]## - -#[ -Possible future APIs: -* module symbols (https://github.com/nim-lang/Nim/pull/9560) -* whichModule (subsumes canImport / moduleExists) (https://github.com/timotheecour/Nim/issues/376) -* getCurrentPkgDir (https://github.com/nim-lang/Nim/pull/10530) -* import from a computed string + related APIs (https://github.com/nim-lang/Nim/pull/10527) -]# - -when defined(nimImportutilsExample): - type - Foo = object - f0: int # private - Goo*[T] = object - g0: int # private - proc initFoo*(): auto = Foo() - -proc privateAccess*(t: typedesc) {.magic: "PrivateAccess".} = - ## Enables access to private fields of `t` in current scope. - runnableExamples("-d:nimImportutilsExample"): - # here we're importing a module containing: - # type - # Foo = object - # f0: int # private - # Goo*[T] = object - # g0: int # private - # proc initFoo*(): auto = Foo() - var f = initFoo() - block: - assert not compiles(f.f0) - privateAccess(f.type) - f.f0 = 1 # accessible in this scope - block: - assert f.f0 == 1 # still in scope - assert not compiles(f.f0) - - # this also works with generics - privateAccess(Goo) - assert Goo[float](g0: 1).g0 == 1 diff --git a/lib/std/isolation.nim b/lib/std/isolation.nim deleted file mode 100644 index 7d6ac6092..000000000 --- a/lib/std/isolation.nim +++ /dev/null @@ -1,49 +0,0 @@ -# -# -# Nim's Runtime Library -# (c) Copyright 2020 Nim contributors -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# - -## This module implements the `Isolated[T]` type for -## safe construction of isolated subgraphs that can be -## passed efficiently to different channels and threads. -## -## .. warning:: This module is experimental and its interface may change. -## - -type - Isolated*[T] = object ## Isolated data can only be moved, not copied. - value: T - -proc `=copy`*[T](dest: var Isolated[T]; src: Isolated[T]) {.error.} - -proc `=sink`*[T](dest: var Isolated[T]; src: Isolated[T]) {.inline.} = - # delegate to value's sink operation - `=sink`(dest.value, src.value) - -proc `=destroy`*[T](dest: var Isolated[T]) {.inline.} = - # delegate to value's destroy operation - `=destroy`(dest.value) - -func isolate*[T](value: sink T): Isolated[T] {.magic: "Isolate".} = - ## Creates an isolated subgraph from the expression `value`. - ## Isolation is checked at compile time. - ## - ## Please read https://github.com/nim-lang/RFCs/issues/244 - ## for more details. - Isolated[T](value: value) - -func unsafeIsolate*[T](value: sink T): Isolated[T] = - ## Creates an isolated subgraph from the expression `value`. - ## - ## .. warning:: The proc doesn't check whether `value` is isolated. - ## - Isolated[T](value: value) - -func extract*[T](src: var Isolated[T]): T = - ## Returns the internal value of `src`. - ## The value is moved from `src`. - result = move(src.value) diff --git a/lib/std/jsbigints.nim b/lib/std/jsbigints.nim deleted file mode 100644 index 04578fc87..000000000 --- a/lib/std/jsbigints.nim +++ /dev/null @@ -1,230 +0,0 @@ -## Arbitrary precision integers. -## * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt -when not defined(js): - {.fatal: "Module jsbigints is designed to be used with the JavaScript backend.".} - -when defined(nimPreviewSlimSystem): - import std/assertions - -type JsBigIntImpl {.importjs: "bigint".} = int # https://github.com/nim-lang/Nim/pull/16606 -type JsBigInt* = distinct JsBigIntImpl ## Arbitrary precision integer for JavaScript target. - -func big*(integer: SomeInteger): JsBigInt {.importjs: "BigInt(#)".} = - ## Constructor for `JsBigInt`. - runnableExamples: - doAssert big(1234567890) == big"1234567890" - doAssert 0b1111100111.big == 0o1747.big and 0o1747.big == 999.big - when nimvm: doAssert false, "JsBigInt can not be used at compile-time nor static context" else: discard - -func `'big`*(num: cstring): JsBigInt {.importjs: "BigInt(#)".} = - ## Constructor for `JsBigInt`. - runnableExamples: - doAssert -1'big == 1'big - 2'big - # supports decimal, binary, octal, hex: - doAssert -12'big == big"-12" - doAssert 12'big == 12.big - doAssert 0b101'big == 0b101.big - doAssert 0o701'big == 0o701.big - doAssert 0xdeadbeaf'big == 0xdeadbeaf.big - doAssert 0xffffffffffffffff'big == (1'big shl 64'big) - 1'big - doAssert not compiles(static(12'big)) - when nimvm: doAssert false, "JsBigInt can not be used at compile-time nor static context" else: discard - -func big*(integer: cstring): JsBigInt {.importjs: "BigInt(#)".} = - ## Alias for `'big` - when nimvm: doAssert false, "JsBigInt can not be used at compile-time nor static context" else: discard - -func toCstring*(this: JsBigInt; radix: 2..36): cstring {.importjs: "#.toString(#)".} = - ## Converts from `JsBigInt` to `cstring` representation. - ## * `radix` Base to use for representing numeric values. - ## https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt/toString - runnableExamples: - doAssert big"2147483647".toCstring(2) == "1111111111111111111111111111111".cstring - -func toCstring*(this: JsBigInt): cstring {.importjs: "#.toString()".} - ## Converts from `JsBigInt` to `cstring` representation. - ## https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt/toString - -func `$`*(this: JsBigInt): string = - ## Returns a `string` representation of `JsBigInt`. - runnableExamples: doAssert $big"1024" == "1024n" - $toCstring(this) & 'n' - -func wrapToInt*(this: JsBigInt; bits: Natural): JsBigInt {.importjs: - "(() => { const i = #, b = #; return BigInt.asIntN(b, i) })()".} = - ## Wraps `this` to a signed `JsBigInt` of `bits` bits in `-2 ^ (bits - 1)` .. `2 ^ (bits - 1) - 1`. - ## https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt/asIntN - runnableExamples: - doAssert (big("3") + big("2") ** big("66")).wrapToInt(13) == big("3") - -func wrapToUint*(this: JsBigInt; bits: Natural): JsBigInt {.importjs: - "(() => { const i = #, b = #; return BigInt.asUintN(b, i) })()".} = - ## Wraps `this` to an unsigned `JsBigInt` of `bits` bits in 0 .. `2 ^ bits - 1`. - ## https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt/asUintN - runnableExamples: - doAssert (big("3") + big("2") ** big("66")).wrapToUint(66) == big("3") - -func toNumber*(this: JsBigInt): BiggestInt {.importjs: "Number(#)".} = - ## Does not do any bounds check and may or may not return an inexact representation. - runnableExamples: - doAssert toNumber(big"2147483647") == 2147483647.BiggestInt - -func `+`*(x, y: JsBigInt): JsBigInt {.importjs: "(# $1 #)".} = - runnableExamples: - doAssert (big"9" + big"1") == big"10" - -func `-`*(x, y: JsBigInt): JsBigInt {.importjs: "(# $1 #)".} = - runnableExamples: - doAssert (big"9" - big"1") == big"8" - -func `*`*(x, y: JsBigInt): JsBigInt {.importjs: "(# $1 #)".} = - runnableExamples: - doAssert (big"42" * big"9") == big"378" - -func `div`*(x, y: JsBigInt): JsBigInt {.importjs: "(# / #)".} = - ## Same as `div` but for `JsBigInt`(uses JavaScript `BigInt() / BigInt()`). - runnableExamples: - doAssert big"13" div big"3" == big"4" - doAssert big"-13" div big"3" == big"-4" - doAssert big"13" div big"-3" == big"-4" - doAssert big"-13" div big"-3" == big"4" - -func `mod`*(x, y: JsBigInt): JsBigInt {.importjs: "(# % #)".} = - ## Same as `mod` but for `JsBigInt` (uses JavaScript `BigInt() % BigInt()`). - runnableExamples: - doAssert big"13" mod big"3" == big"1" - doAssert big"-13" mod big"3" == big"-1" - doAssert big"13" mod big"-3" == big"1" - doAssert big"-13" mod big"-3" == big"-1" - -func `<`*(x, y: JsBigInt): bool {.importjs: "(# $1 #)".} = - runnableExamples: - doAssert big"2" < big"9" - -func `<=`*(x, y: JsBigInt): bool {.importjs: "(# $1 #)".} = - runnableExamples: - doAssert big"1" <= big"5" - -func `==`*(x, y: JsBigInt): bool {.importjs: "(# == #)".} = - runnableExamples: - doAssert big"42" == big"42" - -func `**`*(x, y: JsBigInt): JsBigInt {.importjs: "((#) $1 #)".} = - # (#) needed, refs https://github.com/nim-lang/Nim/pull/16409#issuecomment-760550812 - runnableExamples: - doAssert big"2" ** big"64" == big"18446744073709551616" - doAssert big"-2" ** big"3" == big"-8" - doAssert -big"2" ** big"2" == big"4" # parsed as: (-2n) ** 2n - doAssert big"0" ** big"0" == big"1" # edge case - var ok = false - try: discard big"2" ** big"-1" # raises foreign `RangeError` - except: ok = true - doAssert ok - # pending https://github.com/nim-lang/Nim/pull/15940, simplify to: - # doAssertRaises: discard big"2" ** big"-1" # raises foreign `RangeError` - -func `and`*(x, y: JsBigInt): JsBigInt {.importjs: "(# & #)".} = - runnableExamples: - doAssert (big"555" and big"2") == big"2" - -func `or`*(x, y: JsBigInt): JsBigInt {.importjs: "(# | #)".} = - runnableExamples: - doAssert (big"555" or big"2") == big"555" - -func `xor`*(x, y: JsBigInt): JsBigInt {.importjs: "(# ^ #)".} = - runnableExamples: - doAssert (big"555" xor big"2") == big"553" - -func `shl`*(a, b: JsBigInt): JsBigInt {.importjs: "(# << #)".} = - runnableExamples: - doAssert (big"999" shl big"2") == big"3996" - -func `shr`*(a, b: JsBigInt): JsBigInt {.importjs: "(# >> #)".} = - runnableExamples: - doAssert (big"999" shr big"2") == big"249" - -func `-`*(this: JsBigInt): JsBigInt {.importjs: "($1#)".} = - runnableExamples: - doAssert -(big"10101010101") == big"-10101010101" - -func inc*(this: var JsBigInt) {.importjs: "(++[#][0][0])".} = - runnableExamples: - var big1: JsBigInt = big"1" - inc big1 - doAssert big1 == big"2" - -func dec*(this: var JsBigInt) {.importjs: "(--[#][0][0])".} = - runnableExamples: - var big1: JsBigInt = big"2" - dec big1 - doAssert big1 == big"1" - -func inc*(this: var JsBigInt; amount: JsBigInt) {.importjs: "([#][0][0] += #)".} = - runnableExamples: - var big1: JsBigInt = big"1" - inc big1, big"2" - doAssert big1 == big"3" - -func dec*(this: var JsBigInt; amount: JsBigInt) {.importjs: "([#][0][0] -= #)".} = - runnableExamples: - var big1: JsBigInt = big"1" - dec big1, big"2" - doAssert big1 == big"-1" - -func `+=`*(x: var JsBigInt; y: JsBigInt) {.importjs: "([#][0][0] $1 #)".} = - runnableExamples: - var big1: JsBigInt = big"1" - big1 += big"2" - doAssert big1 == big"3" - -func `-=`*(x: var JsBigInt; y: JsBigInt) {.importjs: "([#][0][0] $1 #)".} = - runnableExamples: - var big1: JsBigInt = big"1" - big1 -= big"2" - doAssert big1 == big"-1" - -func `*=`*(x: var JsBigInt; y: JsBigInt) {.importjs: "([#][0][0] $1 #)".} = - runnableExamples: - var big1: JsBigInt = big"2" - big1 *= big"4" - doAssert big1 == big"8" - -func `/=`*(x: var JsBigInt; y: JsBigInt) {.importjs: "([#][0][0] $1 #)".} = - ## Same as `x = x div y`. - runnableExamples: - var big1: JsBigInt = big"11" - big1 /= big"2" - doAssert big1 == big"5" - -proc `+`*(_: JsBigInt): JsBigInt {.error: - "See https://github.com/tc39/proposal-bigint/blob/master/ADVANCED.md#dont-break-asmjs".} # Can not be used by design - ## **Do NOT use.** https://github.com/tc39/proposal-bigint/blob/master/ADVANCED.md#dont-break-asmjs - -proc low*(_: typedesc[JsBigInt]): JsBigInt {.error: - "Arbitrary precision integers do not have a known low.".} ## **Do NOT use.** - -proc high*(_: typedesc[JsBigInt]): JsBigInt {.error: - "Arbitrary precision integers do not have a known high.".} ## **Do NOT use.** - - -runnableExamples: - block: - let big1: JsBigInt = big"2147483647" - let big2: JsBigInt = big"666" - doAssert JsBigInt isnot int - doAssert big1 != big2 - doAssert big1 > big2 - doAssert big1 >= big2 - doAssert big2 < big1 - doAssert big2 <= big1 - doAssert not(big1 == big2) - let z = JsBigInt.default - doAssert $z == "0n" - block: - var a: seq[JsBigInt] - a.setLen 2 - doAssert a == @[big"0", big"0"] - doAssert a[^1] == big"0" - var b: JsBigInt - doAssert b == big"0" - doAssert b == JsBigInt.default diff --git a/lib/std/jsfetch.nim b/lib/std/jsfetch.nim deleted file mode 100644 index 219594619..000000000 --- a/lib/std/jsfetch.nim +++ /dev/null @@ -1,202 +0,0 @@ -## - Fetch for the JavaScript target: https://developer.mozilla.org/docs/Web/API/Fetch_API -when not defined(js): - {.fatal: "Module jsfetch is designed to be used with the JavaScript backend.".} - -import std/[asyncjs, jsformdata, jsheaders] -export jsformdata, jsheaders -from std/httpcore import HttpMethod -from std/jsffi import JsObject - -type - FetchOptions* = ref object of JsRoot ## Options for Fetch API. - keepalive*: bool - metod* {.importjs: "method".}: cstring - body*, integrity*, referrer*, mode*, credentials*, cache*, redirect*, referrerPolicy*: cstring - headers*: Headers - - FetchModes* = enum ## Mode options. - fmCors = "cors" - fmNoCors = "no-cors" - fmSameOrigin = "same-origin" - - FetchCredentials* = enum ## Credential options. See https://developer.mozilla.org/en-US/docs/Web/API/Request/credentials - fcInclude = "include" - fcSameOrigin = "same-origin" - fcOmit = "omit" - - FetchCaches* = enum ## https://developer.mozilla.org/docs/Web/API/Request/cache - fchDefault = "default" - fchNoStore = "no-store" - fchReload = "reload" - fchNoCache = "no-cache" - fchForceCache = "force-cache" - - FetchRedirects* = enum ## Redirects options. - frFollow = "follow" - frError = "error" - frManual = "manual" - - FetchReferrerPolicies* = enum ## Referrer Policy options. - frpNoReferrer = "no-referrer" - frpNoReferrerWhenDowngrade = "no-referrer-when-downgrade" - frpOrigin = "origin" - frpOriginWhenCrossOrigin = "origin-when-cross-origin" - frpUnsafeUrl = "unsafe-url" - - Response* = ref object of JsRoot ## https://developer.mozilla.org/en-US/docs/Web/API/Response - bodyUsed*, ok*, redirected*: bool - typ* {.importjs: "type".}: cstring - url*, statusText*: cstring - status*: cint - headers*: Headers - body*: cstring - - Request* = ref object of JsRoot ## https://developer.mozilla.org/en-US/docs/Web/API/Request - bodyUsed*, ok*, redirected*: bool - typ* {.importjs: "type".}: cstring - url*, statusText*: cstring - status*: cint - headers*: Headers - body*: cstring - -func newResponse*(body: cstring | FormData): Response {.importjs: "(new Response(#))".} - ## Constructor for `Response`. This does *not* call `fetch()`. Same as `new Response()`. - -func newRequest*(url: cstring): Request {.importjs: "(new Request(#))".} - ## Constructor for `Request`. This does *not* call `fetch()`. Same as `new Request()`. - -func newRequest*(url: cstring; fetchOptions: FetchOptions): Request {.importjs: "(new Request(#, #))".} - ## Constructor for `Request` with `fetchOptions`. Same as `fetch(url, fetchOptions)`. - -func clone*(self: Response | Request): Response {.importjs: "#.$1()".} - ## https://developer.mozilla.org/en-US/docs/Web/API/Response/clone - -proc text*(self: Response): Future[cstring] {.importjs: "#.$1()".} - ## https://developer.mozilla.org/en-US/docs/Web/API/Response/text - -proc json*(self: Response): Future[JsObject] {.importjs: "#.$1()".} - ## https://developer.mozilla.org/en-US/docs/Web/API/Response/json - -proc formData*(self: Response): Future[FormData] {.importjs: "#.$1()".} - ## https://developer.mozilla.org/en-US/docs/Web/API/Response/formData - -proc unsafeNewFetchOptions*(metod, body, mode, credentials, cache, referrerPolicy: cstring; - keepalive: bool; redirect = "follow".cstring; referrer = "client".cstring; integrity = "".cstring; headers: Headers = newHeaders()): FetchOptions {.importjs: - "{method: #, body: #, mode: #, credentials: #, cache: #, referrerPolicy: #, keepalive: #, redirect: #, referrer: #, integrity: #, headers: #}".} - ## .. warning:: Unsafe `newfetchOptions`. - -func newfetchOptions*(metod = HttpGet; body: cstring = nil; - mode = fmCors; credentials = fcSameOrigin; cache = fchDefault; referrerPolicy = frpNoReferrerWhenDowngrade; - keepalive = false; redirect = frFollow; referrer = "client".cstring; integrity = "".cstring, - headers: Headers = newHeaders()): FetchOptions = - ## Constructor for `FetchOptions`. - result = FetchOptions( - body: if metod notin {HttpHead, HttpGet}: body else: nil, - mode: cstring($mode), credentials: cstring($credentials), cache: cstring($cache), referrerPolicy: cstring($referrerPolicy), - keepalive: keepalive, redirect: cstring($redirect), referrer: referrer, integrity: integrity, headers: headers, - metod: (case metod - of HttpHead: "HEAD".cstring - of HttpGet: "GET".cstring - of HttpPost: "POST".cstring - of HttpPut: "PUT".cstring - of HttpDelete: "DELETE".cstring - of HttpPatch: "PATCH".cstring - else: "GET".cstring - ) - ) - -proc fetch*(url: cstring | Request): Future[Response] {.importjs: "$1(#)".} - ## `fetch()` API, simple `GET` only, returns a `Future[Response]`. - -proc fetch*(url: cstring | Request; options: FetchOptions): Future[Response] {.importjs: "$1(#, #)".} - ## `fetch()` API that takes a `FetchOptions`, returns a `Future[Response]`. - -func toCstring*(self: Request | Response | FetchOptions): cstring {.importjs: "JSON.stringify(#)".} - -func `$`*(self: Request | Response | FetchOptions): string = $toCstring(self) - - -runnableExamples("-r:off"): - import std/[asyncjs, jsconsole, jsformdata, jsheaders] - from std/httpcore import HttpMethod - from std/jsffi import JsObject - from std/sugar import `=>` - - block: - let options0: FetchOptions = unsafeNewFetchOptions( - metod = "POST".cstring, - body = """{"key": "value"}""".cstring, - mode = "no-cors".cstring, - credentials = "omit".cstring, - cache = "no-cache".cstring, - referrerPolicy = "no-referrer".cstring, - keepalive = false, - redirect = "follow".cstring, - referrer = "client".cstring, - integrity = "".cstring, - headers = newHeaders() - ) - assert options0.keepalive == false - assert options0.metod == "POST".cstring - assert options0.body == """{"key": "value"}""".cstring - assert options0.mode == "no-cors".cstring - assert options0.credentials == "omit".cstring - assert options0.cache == "no-cache".cstring - assert options0.referrerPolicy == "no-referrer".cstring - assert options0.redirect == "follow".cstring - assert options0.referrer == "client".cstring - assert options0.integrity == "".cstring - assert options0.headers.len == 0 - - block: - let options1: FetchOptions = newFetchOptions( - metod = HttpPost, - body = """{"key": "value"}""".cstring, - mode = fmNoCors, - credentials = fcOmit, - cache = fchNoCache, - referrerPolicy = frpNoReferrer, - keepalive = false, - redirect = frFollow, - referrer = "client".cstring, - integrity = "".cstring, - headers = newHeaders() - ) - assert options1.keepalive == false - assert options1.metod == $HttpPost - assert options1.body == """{"key": "value"}""".cstring - assert options1.mode == $fmNoCors - assert options1.credentials == $fcOmit - assert options1.cache == $fchNoCache - assert options1.referrerPolicy == $frpNoReferrer - assert options1.redirect == $frFollow - assert options1.referrer == "client".cstring - assert options1.integrity == "".cstring - assert options1.headers.len == 0 - - block: - let response: Response = newResponse(body = "-. .. --".cstring) - let request: Request = newRequest(url = "http://nim-lang.org".cstring) - - if not defined(nodejs): - block: - proc doFetch(): Future[Response] {.async.} = - fetch "https://httpbin.org/get".cstring - - proc example() {.async.} = - let response: Response = await doFetch() - assert response.ok - assert response.status == 200.cint - assert response.headers is Headers - assert response.body is cstring - - discard example() - - block: - proc example2 {.async.} = - await fetch("https://api.github.com/users/torvalds".cstring) - .then((response: Response) => response.json()) - .then((json: JsObject) => console.log(json)) - .catch((err: Error) => console.log("Request Failed", err)) - - discard example2() diff --git a/lib/std/jsformdata.nim b/lib/std/jsformdata.nim deleted file mode 100644 index 61dcc39a3..000000000 --- a/lib/std/jsformdata.nim +++ /dev/null @@ -1,69 +0,0 @@ -## - `FormData` for the JavaScript target: https://developer.mozilla.org/en-US/docs/Web/API/FormData -when not defined(js): - {.fatal: "Module jsformdata is designed to be used with the JavaScript backend.".} - -from std/dom import Blob - -type FormData* = ref object of JsRoot ## FormData API. - -func newFormData*(): FormData {.importjs: "new FormData()".} - -func add*(self: FormData; name: cstring; value: SomeNumber | bool | cstring | Blob) {.importjs: "#.append(#, #)".} - ## https://developer.mozilla.org/en-US/docs/Web/API/FormData/append - ## - ## .. hint:: Duplicate keys are allowed and order is preserved. - -func add*(self: FormData; name: cstring; value: SomeNumber | bool | cstring | Blob; filename: cstring) {.importjs: "#.append(#, #, #)".} - ## https://developer.mozilla.org/en-US/docs/Web/API/FormData/append - ## - ## .. hint:: Duplicate keys are allowed and order is preserved. - -func delete*(self: FormData; name: cstring) {.importjs: "#.$1(#)".} - ## https://developer.mozilla.org/en-US/docs/Web/API/FormData/delete - ## - ## .. warning:: Deletes *all items* with the same key name. - -func getAll*(self: FormData; name: cstring): seq[cstring] {.importjs: "#.$1(#)".} - ## https://developer.mozilla.org/en-US/docs/Web/API/FormData/getAll - -func hasKey*(self: FormData; name: cstring): bool {.importjs: "#.has(#)".} - ## https://developer.mozilla.org/en-US/docs/Web/API/FormData/has - -func keys*(self: FormData): seq[cstring] {.importjs: "Array.from(#.$1())".} - ## https://developer.mozilla.org/en-US/docs/Web/API/FormData/keys - -func values*(self: FormData): seq[cstring] {.importjs: "Array.from(#.$1())".} - ## https://developer.mozilla.org/en-US/docs/Web/API/FormData/values - -func pairs*(self: FormData): seq[tuple[key, val: cstring]] {.importjs: "Array.from(#.entries())".} - ## https://developer.mozilla.org/en-US/docs/Web/API/FormData/entries - -func put*(self: FormData; name: cstring; value: SomeNumber | bool | cstring | Blob; filename: cstring) {.importjs: "#.set(#, #, #)".} - ## https://developer.mozilla.org/en-US/docs/Web/API/FormData/set - -func `[]=`*(self: FormData; name: cstring; value: SomeNumber | bool | cstring | Blob) {.importjs: "#.set(#, #)".} - ## https://developer.mozilla.org/en-US/docs/Web/API/FormData/set - -func `[]`*(self: FormData; name: cstring): cstring {.importjs: "#.get(#)".} - ## https://developer.mozilla.org/en-US/docs/Web/API/FormData/get - -func clear*(self: FormData) {.importjs: - "(() => { const frmdt = #; Array.from(frmdt.keys()).forEach((key) => frmdt.delete(key)) })()".} - ## Convenience func to delete all items from `FormData`. - -func toCstring*(self: FormData): cstring {.importjs: "JSON.stringify(#)".} - -func `$`*(self: FormData): string = $toCstring(self) - -func len*(self: FormData): int {.importjs: "Array.from(#.entries()).length".} - - -runnableExamples("-r:off"): - let data: FormData = newFormData() - data["key0"] = "value0".cstring - data.add("key1".cstring, "value1".cstring) - data.delete("key1") - assert data.hasKey("key0") - assert data["key0"] == "value0".cstring - data.clear() - assert data.len == 0 diff --git a/lib/std/jsheaders.nim b/lib/std/jsheaders.nim deleted file mode 100644 index 6fd3b3468..000000000 --- a/lib/std/jsheaders.nim +++ /dev/null @@ -1,83 +0,0 @@ -## - HTTP Headers for the JavaScript target: https://developer.mozilla.org/en-US/docs/Web/API/Headers -when not defined(js): - {.fatal: "Module jsheaders is designed to be used with the JavaScript backend.".} - -type Headers* = ref object of JsRoot ## HTTP Headers API. - -func newHeaders*(): Headers {.importjs: "new Headers()".} - ## https://developer.mozilla.org/en-US/docs/Web/API/Headers - -func add*(self: Headers; key: cstring; value: cstring) {.importjs: "#.append(#, #)".} - ## Allows duplicated keys. - ## https://developer.mozilla.org/en-US/docs/Web/API/Headers/append - -func delete*(self: Headers; key: cstring) {.importjs: "#.$1(#)".} - ## https://developer.mozilla.org/en-US/docs/Web/API/Headers/delete - ## - ## .. warning:: Delete *all* items with `key` from the headers, including duplicated keys. - -func hasKey*(self: Headers; key: cstring): bool {.importjs: "#.has(#)".} - ## https://developer.mozilla.org/en-US/docs/Web/API/Headers/has - -func keys*(self: Headers): seq[cstring] {.importjs: "Array.from(#.$1())".} - ## https://developer.mozilla.org/en-US/docs/Web/API/Headers/keys - -func values*(self: Headers): seq[cstring] {.importjs: "Array.from(#.$1())".} - ## https://developer.mozilla.org/en-US/docs/Web/API/Headers/values - -func entries*(self: Headers): seq[tuple[key, value: cstring]] {.importjs: "Array.from(#.$1())".} - ## https://developer.mozilla.org/en-US/docs/Web/API/Headers/entries - -func `[]`*(self: Headers; key: cstring): cstring {.importjs: "#.get(#)".} - ## Get *all* items with `key` from the headers, including duplicated values. - ## https://developer.mozilla.org/en-US/docs/Web/API/Headers/get - -func `[]=`*(self: Headers; key: cstring; value: cstring) {.importjs: "#.set(#, #)".} - ## Do *not* allow duplicated keys, overwrites duplicated keys. - ## https://developer.mozilla.org/en-US/docs/Web/API/Headers/set - -func clear*(self: Headers) {.importjs: - "(() => { const header = #; Array.from(header.keys()).forEach((key) => header.delete(key)) })()".} - ## Convenience func to delete all items from `Headers`. - -func toCstring*(self: Headers): cstring {.importjs: "JSON.stringify(Array.from(#.entries()))".} - ## Returns a `cstring` representation of `Headers`. - -func `$`*(self: Headers): string = $toCstring(self) - -func len*(self: Headers): int {.importjs: "Array.from(#.entries()).length".} - - -runnableExamples("-r:off"): - - block: - let header: Headers = newHeaders() - header.add("key", "value") - assert header.hasKey("key") - assert header.keys() == @["key".cstring] - assert header.values() == @["value".cstring] - assert header["key"] == "value".cstring - header["other"] = "another".cstring - assert header["other"] == "another".cstring - assert header.entries() == @[("key".cstring, "value".cstring), ("other".cstring, "another".cstring)] - assert header.toCstring() == """[["key","value"],["other","another"]]""".cstring - header.delete("other") - assert header.entries() == @[("key".cstring, "value".cstring)] - header.clear() - assert header.entries() == @[] - assert header.len == 0 - - block: - let header: Headers = newHeaders() - header.add("key", "a") - header.add("key", "b") ## Duplicated. - header.add("key", "c") ## Duplicated. - assert header["key"] == "a, b, c".cstring - header["key"] = "value".cstring - assert header["key"] == "value".cstring - - block: - let header: Headers = newHeaders() - header["key"] = "a" - header["key"] = "b" ## Overwrites. - assert header["key"] == "b".cstring diff --git a/lib/std/jsonutils.nim b/lib/std/jsonutils.nim deleted file mode 100644 index 17d08e02e..000000000 --- a/lib/std/jsonutils.nim +++ /dev/null @@ -1,494 +0,0 @@ -##[ -This module implements a hookable (de)serialization for arbitrary types using JSON. -Design goal: avoid importing modules where a custom serialization is needed; -see strtabs.fromJsonHook,toJsonHook for an example. -]## - -runnableExamples: - import std/[strtabs,json] - type Foo = ref object - t: bool - z1: int8 - let a = (1.5'f32, (b: "b2", a: "a2"), 'x', @[Foo(t: true, z1: -3), nil], [{"name": "John"}.newStringTable]) - let j = a.toJson - assert j.jsonTo(typeof(a)).toJson == j - assert $[NaN, Inf, -Inf, 0.0, -0.0, 1.0, 1e-2].toJson == """["nan","inf","-inf",0.0,-0.0,1.0,0.01]""" - assert 0.0.toJson.kind == JFloat - assert Inf.toJson.kind == JString - -import json, strutils, tables, sets, strtabs, options, strformat - -#[ -Future directions: -add a way to customize serialization, for e.g.: -* field renaming -* allow serializing `enum` and `char` as `string` instead of `int` - (enum is more compact/efficient, and robust to enum renamings, but string - is more human readable) -* handle cyclic references, using a cache of already visited addresses -* implement support for serialization and de-serialization of nested variant - objects. -]# - -import macros -from enumutils import symbolName -from typetraits import OrdinalEnum, tupleLen - -when defined(nimPreviewSlimSystem): - import std/assertions - - -proc isNamedTuple(T: typedesc): bool {.magic: "TypeTrait".} - -type - Joptions* = object # xxx rename FromJsonOptions - ## Options controlling the behavior of `fromJson`. - allowExtraKeys*: bool - ## If `true` Nim's object to which the JSON is parsed is not required to - ## have a field for every JSON key. - allowMissingKeys*: bool - ## If `true` Nim's object to which JSON is parsed is allowed to have - ## fields without corresponding JSON keys. - # in future work: a key rename could be added - EnumMode* = enum - joptEnumOrd - joptEnumSymbol - joptEnumString - JsonNodeMode* = enum ## controls `toJson` for JsonNode types - joptJsonNodeAsRef ## returns the ref as is - joptJsonNodeAsCopy ## returns a deep copy of the JsonNode - joptJsonNodeAsObject ## treats JsonNode as a regular ref object - ToJsonOptions* = object - enumMode*: EnumMode - jsonNodeMode*: JsonNodeMode - # xxx charMode, etc - -proc initToJsonOptions*(): ToJsonOptions = - ## initializes `ToJsonOptions` with sane options. - ToJsonOptions(enumMode: joptEnumOrd, jsonNodeMode: joptJsonNodeAsRef) - -proc distinctBase(T: typedesc, recursive: static bool = true): typedesc {.magic: "TypeTrait".} -template distinctBase[T](a: T, recursive: static bool = true): untyped = distinctBase(typeof(a), recursive)(a) - -macro getDiscriminants(a: typedesc): seq[string] = - ## return the discriminant keys - # candidate for std/typetraits - var a = a.getTypeImpl - doAssert a.kind == nnkBracketExpr - let sym = a[1] - let t = sym.getTypeImpl - let t2 = t[2] - doAssert t2.kind == nnkRecList - result = newTree(nnkBracket) - for ti in t2: - if ti.kind == nnkRecCase: - let key = ti[0][0] - let typ = ti[0][1] - result.add newLit key.strVal - if result.len > 0: - result = quote do: - @`result` - else: - result = quote do: - seq[string].default - -macro initCaseObject(T: typedesc, fun: untyped): untyped = - ## does the minimum to construct a valid case object, only initializing - ## the discriminant fields; see also `getDiscriminants` - # maybe candidate for std/typetraits - var a = T.getTypeImpl - doAssert a.kind == nnkBracketExpr - let sym = a[1] - let t = sym.getTypeImpl - var t2: NimNode - case t.kind - of nnkObjectTy: t2 = t[2] - of nnkRefTy: t2 = t[0].getTypeImpl[2] - else: doAssert false, $t.kind # xxx `nnkPtrTy` could be handled too - doAssert t2.kind == nnkRecList - result = newTree(nnkObjConstr) - result.add sym - for ti in t2: - if ti.kind == nnkRecCase: - let key = ti[0][0] - let typ = ti[0][1] - let key2 = key.strVal - let val = quote do: - `fun`(`key2`, typedesc[`typ`]) - result.add newTree(nnkExprColonExpr, key, val) - -proc raiseJsonException(condStr: string, msg: string) {.noinline.} = - # just pick 1 exception type for simplicity; other choices would be: - # JsonError, JsonParser, JsonKindError - raise newException(ValueError, condStr & " failed: " & msg) - -template checkJson(cond: untyped, msg = "") = - if not cond: - raiseJsonException(astToStr(cond), msg) - -proc hasField[T](obj: T, field: string): bool = - for k, _ in fieldPairs(obj): - if k == field: - return true - return false - -macro accessField(obj: typed, name: static string): untyped = - newDotExpr(obj, ident(name)) - -template fromJsonFields(newObj, oldObj, json, discKeys, opt) = - type T = typeof(newObj) - # we could customize whether to allow JNull - checkJson json.kind == JObject, $json.kind - var num, numMatched = 0 - for key, val in fieldPairs(newObj): - num.inc - when key notin discKeys: - if json.hasKey key: - numMatched.inc - fromJson(val, json[key], opt) - elif opt.allowMissingKeys: - # if there are no discriminant keys the `oldObj` must always have the - # same keys as the new one. Otherwise we must check, because they could - # be set to different branches. - when typeof(oldObj) isnot typeof(nil): - if discKeys.len == 0 or hasField(oldObj, key): - val = accessField(oldObj, key) - else: - checkJson false, "key '$1' for $2 not in $3" % [key, $T, json.pretty()] - else: - if json.hasKey key: - numMatched.inc - - let ok = - if opt.allowExtraKeys and opt.allowMissingKeys: - true - elif opt.allowExtraKeys: - # This check is redundant because if here missing keys are not allowed, - # and if `num != numMatched` it will fail in the loop above but it is left - # for clarity. - assert num == numMatched - num == numMatched - elif opt.allowMissingKeys: - json.len == numMatched - else: - json.len == num and num == numMatched - - checkJson ok, "There were $1 keys (expecting $2) for $3 with $4" % [$json.len, $num, $T, json.pretty()] - -proc fromJson*[T](a: var T, b: JsonNode, opt = Joptions()) - -proc discKeyMatch[T](obj: T, json: JsonNode, key: static string): bool = - if not json.hasKey key: - return true - let field = accessField(obj, key) - var jsonVal: typeof(field) - fromJson(jsonVal, json[key]) - if jsonVal != field: - return false - return true - -macro discKeysMatchBodyGen(obj: typed, json: JsonNode, - keys: static seq[string]): untyped = - result = newStmtList() - let r = ident("result") - for key in keys: - let keyLit = newLit key - result.add quote do: - `r` = `r` and discKeyMatch(`obj`, `json`, `keyLit`) - -proc discKeysMatch[T](obj: T, json: JsonNode, keys: static seq[string]): bool = - result = true - discKeysMatchBodyGen(obj, json, keys) - -proc fromJson*[T](a: var T, b: JsonNode, opt = Joptions()) = - ## inplace version of `jsonTo` - #[ - adding "json path" leading to `b` can be added in future work. - ]# - checkJson b != nil, $($T, b) - when compiles(fromJsonHook(a, b, opt)): fromJsonHook(a, b, opt) - elif compiles(fromJsonHook(a, b)): fromJsonHook(a, b) - elif T is bool: a = to(b,T) - elif T is enum: - case b.kind - of JInt: a = T(b.getBiggestInt()) - of JString: a = parseEnum[T](b.getStr()) - else: checkJson false, fmt"Expecting int/string for {$T} got {b.pretty()}" - elif T is uint|uint64: a = T(to(b, uint64)) - elif T is Ordinal: a = cast[T](to(b, int)) - elif T is pointer: a = cast[pointer](to(b, int)) - elif T is distinct: - when nimvm: - # bug, potentially related to https://github.com/nim-lang/Nim/issues/12282 - a = T(jsonTo(b, distinctBase(T))) - else: - a.distinctBase.fromJson(b) - elif T is string|SomeNumber: a = to(b,T) - elif T is cstring: - case b.kind - of JNull: a = nil - of JString: a = b.str - else: checkJson false, fmt"Expecting null/string for {$T} got {b.pretty()}" - elif T is JsonNode: a = b - elif T is ref | ptr: - if b.kind == JNull: a = nil - else: - a = T() - fromJson(a[], b, opt) - elif T is array: - checkJson a.len == b.len, fmt"Json array size doesn't match for {$T}" - var i = 0 - for ai in mitems(a): - fromJson(ai, b[i], opt) - i.inc - elif T is set: - type E = typeof(for ai in a: ai) - for val in b.getElems: - incl a, jsonTo(val, E) - elif T is seq: - a.setLen b.len - for i, val in b.getElems: - fromJson(a[i], val, opt) - elif T is object: - template fun(key, typ): untyped {.used.} = - if b.hasKey key: - jsonTo(b[key], typ) - elif hasField(a, key): - accessField(a, key) - else: - default(typ) - const keys = getDiscriminants(T) - when keys.len == 0: - fromJsonFields(a, nil, b, keys, opt) - else: - if discKeysMatch(a, b, keys): - fromJsonFields(a, nil, b, keys, opt) - else: - var newObj = initCaseObject(T, fun) - fromJsonFields(newObj, a, b, keys, opt) - a = newObj - elif T is tuple: - when isNamedTuple(T): - fromJsonFields(a, nil, b, seq[string].default, opt) - else: - checkJson b.kind == JArray, $(b.kind) # we could customize whether to allow JNull - - when compiles(tupleLen(T)): - let tupleSize = tupleLen(T) - else: - # Tuple len isn't in csources_v1 so using tupleLen would fail. - # Else branch basically never runs (tupleLen added in 1.1 and jsonutils in 1.4), but here for consistency - var tupleSize = 0 - for val in fields(a): - tupleSize.inc - - checkJson b.len == tupleSize, fmt"Json doesn't match expected length of {tupleSize}, got {b.pretty()}" - var i = 0 - for val in fields(a): - fromJson(val, b[i], opt) - i.inc - else: - # checkJson not appropriate here - static: doAssert false, "not yet implemented: " & $T - -proc jsonTo*(b: JsonNode, T: typedesc, opt = Joptions()): T = - ## reverse of `toJson` - fromJson(result, b, opt) - -proc toJson*[T](a: T, opt = initToJsonOptions()): JsonNode = - ## serializes `a` to json; uses `toJsonHook(a: T)` if it's in scope to - ## customize serialization, see strtabs.toJsonHook for an example. - ## - ## .. note:: With `-d:nimPreviewJsonutilsHoleyEnum`, `toJson` now can - ## serialize/deserialize holey enums as regular enums (via `ord`) instead of as strings. - ## It is expected that this behavior becomes the new default in upcoming versions. - when compiles(toJsonHook(a, opt)): result = toJsonHook(a, opt) - elif compiles(toJsonHook(a)): result = toJsonHook(a) - elif T is object | tuple: - when T is object or isNamedTuple(T): - result = newJObject() - for k, v in a.fieldPairs: result[k] = toJson(v, opt) - else: - result = newJArray() - for v in a.fields: result.add toJson(v, opt) - elif T is ref | ptr: - template impl = - if system.`==`(a, nil): result = newJNull() - else: result = toJson(a[], opt) - when T is JsonNode: - case opt.jsonNodeMode - of joptJsonNodeAsRef: result = a - of joptJsonNodeAsCopy: result = copy(a) - of joptJsonNodeAsObject: impl() - else: impl() - elif T is array | seq | set: - result = newJArray() - for ai in a: result.add toJson(ai, opt) - elif T is pointer: result = toJson(cast[int](a), opt) - # edge case: `a == nil` could've also led to `newJNull()`, but this results - # in simpler code for `toJson` and `fromJson`. - elif T is distinct: result = toJson(a.distinctBase, opt) - elif T is bool: result = %(a) - elif T is SomeInteger: result = %a - elif T is enum: - case opt.enumMode - of joptEnumOrd: - when T is Ordinal or defined(nimPreviewJsonutilsHoleyEnum): %(a.ord) - else: toJson($a, opt) - of joptEnumSymbol: - when T is OrdinalEnum: - toJson(symbolName(a), opt) - else: - toJson($a, opt) - of joptEnumString: toJson($a, opt) - elif T is Ordinal: result = %(a.ord) - elif T is cstring: (if a == nil: result = newJNull() else: result = % $a) - else: result = %a - -proc fromJsonHook*[K: string|cstring, V](t: var (Table[K, V] | OrderedTable[K, V]), - jsonNode: JsonNode, opt = Joptions()) = - ## Enables `fromJson` for `Table` and `OrderedTable` types. - ## - ## See also: - ## * `toJsonHook proc<#toJsonHook>`_ - runnableExamples: - import std/[tables, json] - var foo: tuple[t: Table[string, int], ot: OrderedTable[string, int]] - fromJson(foo, parseJson(""" - {"t":{"two":2,"one":1},"ot":{"one":1,"three":3}}""")) - assert foo.t == [("one", 1), ("two", 2)].toTable - assert foo.ot == [("one", 1), ("three", 3)].toOrderedTable - - assert jsonNode.kind == JObject, - "The kind of the `jsonNode` must be `JObject`, but its actual " & - "type is `" & $jsonNode.kind & "`." - clear(t) - for k, v in jsonNode: - t[k] = jsonTo(v, V, opt) - -proc toJsonHook*[K: string|cstring, V](t: (Table[K, V] | OrderedTable[K, V]), opt = initToJsonOptions()): JsonNode = - ## Enables `toJson` for `Table` and `OrderedTable` types. - ## - ## See also: - ## * `fromJsonHook proc<#fromJsonHook,,JsonNode>`_ - # pending PR #9217 use: toSeq(a) instead of `collect` in `runnableExamples`. - runnableExamples: - import std/[tables, json, sugar] - let foo = ( - t: [("two", 2)].toTable, - ot: [("one", 1), ("three", 3)].toOrderedTable) - assert $toJson(foo) == """{"t":{"two":2},"ot":{"one":1,"three":3}}""" - # if keys are not string|cstring, you can use this: - let a = {10: "foo", 11: "bar"}.newOrderedTable - let a2 = collect: (for k,v in a: (k,v)) - assert $toJson(a2) == """[[10,"foo"],[11,"bar"]]""" - - result = newJObject() - for k, v in pairs(t): - # not sure if $k has overhead for string - result[(when K is string: k else: $k)] = toJson(v, opt) - -proc fromJsonHook*[A](s: var SomeSet[A], jsonNode: JsonNode, opt = Joptions()) = - ## Enables `fromJson` for `HashSet` and `OrderedSet` types. - ## - ## See also: - ## * `toJsonHook proc<#toJsonHook,SomeSet[A]>`_ - runnableExamples: - import std/[sets, json] - var foo: tuple[hs: HashSet[string], os: OrderedSet[string]] - fromJson(foo, parseJson(""" - {"hs": ["hash", "set"], "os": ["ordered", "set"]}""")) - assert foo.hs == ["hash", "set"].toHashSet - assert foo.os == ["ordered", "set"].toOrderedSet - - assert jsonNode.kind == JArray, - "The kind of the `jsonNode` must be `JArray`, but its actual " & - "type is `" & $jsonNode.kind & "`." - clear(s) - for v in jsonNode: - incl(s, jsonTo(v, A, opt)) - -proc toJsonHook*[A](s: SomeSet[A], opt = initToJsonOptions()): JsonNode = - ## Enables `toJson` for `HashSet` and `OrderedSet` types. - ## - ## See also: - ## * `fromJsonHook proc<#fromJsonHook,SomeSet[A],JsonNode>`_ - runnableExamples: - import std/[sets, json] - let foo = (hs: ["hash"].toHashSet, os: ["ordered", "set"].toOrderedSet) - assert $toJson(foo) == """{"hs":["hash"],"os":["ordered","set"]}""" - - result = newJArray() - for k in s: - add(result, toJson(k, opt)) - -proc fromJsonHook*[T](self: var Option[T], jsonNode: JsonNode, opt = Joptions()) = - ## Enables `fromJson` for `Option` types. - ## - ## See also: - ## * `toJsonHook proc<#toJsonHook,Option[T]>`_ - runnableExamples: - import std/[options, json] - var opt: Option[string] - fromJsonHook(opt, parseJson("\"test\"")) - assert get(opt) == "test" - fromJson(opt, parseJson("null")) - assert isNone(opt) - - if jsonNode.kind != JNull: - self = some(jsonTo(jsonNode, T, opt)) - else: - self = none[T]() - -proc toJsonHook*[T](self: Option[T], opt = initToJsonOptions()): JsonNode = - ## Enables `toJson` for `Option` types. - ## - ## See also: - ## * `fromJsonHook proc<#fromJsonHook,Option[T],JsonNode>`_ - runnableExamples: - import std/[options, json] - let optSome = some("test") - assert $toJson(optSome) == "\"test\"" - let optNone = none[string]() - assert $toJson(optNone) == "null" - - if isSome(self): - toJson(get(self), opt) - else: - newJNull() - -proc fromJsonHook*(a: var StringTableRef, b: JsonNode) = - ## Enables `fromJson` for `StringTableRef` type. - ## - ## See also: - ## * `toJsonHook proc<#toJsonHook,StringTableRef>`_ - runnableExamples: - import std/[strtabs, json] - var t = newStringTable(modeCaseSensitive) - let jsonStr = """{"mode": 0, "table": {"name": "John", "surname": "Doe"}}""" - fromJsonHook(t, parseJson(jsonStr)) - assert t[] == newStringTable("name", "John", "surname", "Doe", - modeCaseSensitive)[] - - var mode = jsonTo(b["mode"], StringTableMode) - a = newStringTable(mode) - let b2 = b["table"] - for k,v in b2: a[k] = jsonTo(v, string) - -proc toJsonHook*(a: StringTableRef): JsonNode = - ## Enables `toJson` for `StringTableRef` type. - ## - ## See also: - ## * `fromJsonHook proc<#fromJsonHook,StringTableRef,JsonNode>`_ - runnableExamples: - import std/[strtabs, json] - let t = newStringTable("name", "John", "surname", "Doe", modeCaseSensitive) - let jsonStr = """{"mode": "modeCaseSensitive", - "table": {"name": "John", "surname": "Doe"}}""" - assert toJson(t) == parseJson(jsonStr) - - result = newJObject() - result["mode"] = toJson($a.mode) - let t = newJObject() - for k,v in a: t[k] = toJson(v) - result["table"] = t diff --git a/lib/std/logic.nim b/lib/std/logic.nim deleted file mode 100644 index 84640d380..000000000 --- a/lib/std/logic.nim +++ /dev/null @@ -1,10 +0,0 @@ -## This module provides further logic operators like 'forall' and 'exists' -## They are only supported in `.ensures` etc pragmas. - -proc `->`*(a, b: bool): bool {.magic: "Implies".} -proc `<->`*(a, b: bool): bool {.magic: "Iff".} - -proc forall*(args: varargs[untyped]): bool {.magic: "Forall".} -proc exists*(args: varargs[untyped]): bool {.magic: "Exists".} - -proc old*[T](x: T): T {.magic: "Old".} diff --git a/lib/std/monotimes.nim b/lib/std/monotimes.nim index 5c67a5d4c..f819cbc8d 100644 --- a/lib/std/monotimes.nim +++ b/lib/std/monotimes.nim @@ -8,32 +8,31 @@ # ##[ -The `std/monotimes` module implements monotonic timestamps. A monotonic -timestamp represents the time that has passed since some system defined -point in time. The monotonic timestamps are guaranteed not to decrease, -meaning that that the following is guaranteed to work: -]## + The ``std/monotimes`` module implements monotonic timestamps. A monotonic + timestamp represents the time that has passed since some system defined + point in time. The monotonic timestamps are guaranteed to always increase, + meaning that that the following is guaranteed to work: -runnableExamples: - let a = getMonoTime() - let b = getMonoTime() - assert a <= b + .. code-block:: nim + let a = getMonoTime() + # ... do some work + let b = getMonoTime() + assert a <= b -##[ -This is not guaranteed for the `times.Time` type! This means that the -`MonoTime` should be used when measuring durations of time with -high precision. + This is not guaranteed for the `times.Time` type! This means that the + `MonoTime` should be used when measuring durations of time with + high precision. -However, since `MonoTime` represents the time that has passed since some -unknown time origin, it cannot be converted to a human readable timestamp. -If this is required, the `times.Time` type should be used instead. + However, since `MonoTime` represents the time that has passed since some + unknown time origin, it cannot be converted to a human readable timestamp. + If this is required, the `times.Time` type should be used instead. -The `MonoTime` type stores the timestamp in nanosecond resolution, but note -that the actual supported time resolution differs for different systems. + The `MonoTime` type stores the timestamp in nanosecond resolution, but note + that the actual supported time resolution differs for different systems. -See also -======== -* `times module `_ + See also + ======== + * `times module `_ ]## import times @@ -54,16 +53,18 @@ when defined(macosx): when defined(js): proc getJsTicks: float = - ## Returns ticks in the unit seconds. - when defined(nodejs): - {.emit: """ - let process = require('process'); - let time = process.hrtime(); - `result` = time[0] + time[1] / 1000000000; - """.} - else: - proc jsNow(): float {.importjs: "window.performance.now()".} - result = jsNow() / 1000 + ## Returns ticks in the unit seconds + {.emit: """ + var isNode = typeof module !== 'undefined' && module.exports + + if (isNode) { + var process = require('process'); + var time = process.hrtime() + return time[0] + time[1] / 1000000000; + } else { + return window.performance.now() / 1000; + } + """.} # Workaround for #6752. {.push overflowChecks: off.} @@ -73,13 +74,9 @@ when defined(js): system.`+`(a, b) {.pop.} -elif defined(posix) and not defined(osx): +elif defined(posix): import posix -when defined(zephyr): - proc k_uptime_ticks(): int64 {.importc: "k_uptime_ticks", header: "".} - proc k_ticks_to_ns_floor64(ticks: int64): int64 {.importc: "k_ticks_to_ns_floor64", header: "".} - elif defined(windows): proc QueryPerformanceCounter(res: var uint64) {. importc: "QueryPerformanceCounter", stdcall, dynlib: "kernel32".} @@ -87,11 +84,11 @@ elif defined(windows): importc: "QueryPerformanceFrequency", stdcall, dynlib: "kernel32".} proc getMonoTime*(): MonoTime {.tags: [TimeEffect].} = - ## Returns the current `MonoTime` timestamp. + ## Get the current `MonoTime` timestamp. ## ## When compiled with the JS backend and executed in a browser, - ## this proc calls `window.performance.now()`. - ## See [MDN](https://developer.mozilla.org/en-US/docs/Web/API/Performance/now) + ## this proc calls `window.performance.now()`, which is not supported by + ## older browsers. See [MDN](https://developer.mozilla.org/en-US/docs/Web/API/Performance/now) ## for more information. when defined(js): let ticks = getJsTicks() @@ -102,9 +99,6 @@ proc getMonoTime*(): MonoTime {.tags: [TimeEffect].} = mach_timebase_info(machAbsoluteTimeFreq) result = MonoTime(ticks: ticks * machAbsoluteTimeFreq.numer div machAbsoluteTimeFreq.denom) - elif defined(zephyr): - let ticks = k_ticks_to_ns_floor64(k_uptime_ticks()) - result = MonoTime(ticks: ticks) elif defined(posix): var ts: Timespec discard clock_gettime(CLOCK_MONOTONIC, ts) @@ -158,3 +152,19 @@ proc high*(typ: typedesc[MonoTime]): MonoTime = proc low*(typ: typedesc[MonoTime]): MonoTime = ## Returns the lowest representable `MonoTime`. MonoTime(ticks: low(int64)) + +when isMainModule: + let d = initDuration(nanoseconds = 10) + let t1 = getMonoTime() + let t2 = t1 + d + + doAssert t2 - t1 == d + doAssert t1 == t1 + doAssert t1 != t2 + doAssert t2 - d == t1 + doAssert t1 < t2 + doAssert t1 <= t2 + doAssert t1 <= t1 + doAssert not(t2 < t1) + doAssert t1 < high(MonoTime) + doAssert low(MonoTime) < t1 diff --git a/lib/std/objectdollar.nim b/lib/std/objectdollar.nim deleted file mode 100644 index 86ce9afc8..000000000 --- a/lib/std/objectdollar.nim +++ /dev/null @@ -1,13 +0,0 @@ -## This module implements a generic `$` operator to convert objects to strings. - -import std/private/miscdollars - -proc `$`*[T: object](x: T): string = - ## Generic `$` operator for objects with similar output to - ## `$` for named tuples. - runnableExamples: - type Foo = object - a, b: int - let x = Foo(a: 23, b: 45) - assert $x == "(a: 23, b: 45)" - tupleObjectDollar(result, x) diff --git a/lib/std/oserrors.nim b/lib/std/oserrors.nim deleted file mode 100644 index a641a7f47..000000000 --- a/lib/std/oserrors.nim +++ /dev/null @@ -1,117 +0,0 @@ -# -# -# Nim's Runtime Library -# (c) Copyright 2022 Nim contributors -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# - - -## The `std/oserrors` module implements OS error reporting. - -type - OSErrorCode* = distinct int32 ## Specifies an OS Error Code. - -when not defined(nimscript): - when defined(windows): - import winlean - when defined(nimPreviewSlimSystem): - import std/widestrs - else: - var errno {.importc, header: "".}: cint - - proc c_strerror(errnum: cint): cstring {. - importc: "strerror", header: "".} - -proc `==`*(err1, err2: OSErrorCode): bool {.borrow.} -proc `$`*(err: OSErrorCode): string {.borrow.} - -proc osErrorMsg*(errorCode: OSErrorCode): string = - ## Converts an OS error code into a human readable string. - ## - ## The error code can be retrieved using the `osLastError proc`_. - ## - ## If conversion fails, or `errorCode` is `0` then `""` will be - ## returned. - ## - ## See also: - ## * `raiseOSError proc`_ - ## * `osLastError proc`_ - runnableExamples: - when defined(linux): - assert osErrorMsg(OSErrorCode(0)) == "" - assert osErrorMsg(OSErrorCode(1)) == "Operation not permitted" - assert osErrorMsg(OSErrorCode(2)) == "No such file or directory" - - result = "" - when defined(nimscript): - discard - elif defined(windows): - if errorCode != OSErrorCode(0'i32): - var msgbuf: WideCString - if formatMessageW(0x00000100 or 0x00001000 or 0x00000200, - nil, errorCode.int32, 0, addr(msgbuf), 0, nil) != 0'i32: - result = $msgbuf - if msgbuf != nil: localFree(cast[pointer](msgbuf)) - else: - if errorCode != OSErrorCode(0'i32): - result = $c_strerror(errorCode.int32) - -proc newOSError*( - errorCode: OSErrorCode, additionalInfo = "" -): owned(ref OSError) {.noinline.} = - ## Creates a new `OSError exception `_. - ## - ## The `errorCode` will determine the - ## message, `osErrorMsg proc`_ will be used - ## to get this message. - ## - ## The error code can be retrieved using the `osLastError proc`_. - ## - ## If the error code is `0` or an error message could not be retrieved, - ## the message `unknown OS error` will be used. - ## - ## See also: - ## * `osErrorMsg proc`_ - ## * `osLastError proc`_ - result = (ref OSError)(errorCode: errorCode.int32, msg: osErrorMsg(errorCode)) - if additionalInfo.len > 0: - if result.msg.len > 0 and result.msg[^1] != '\n': result.msg.add '\n' - result.msg.add "Additional info: " - result.msg.add additionalInfo - # don't add trailing `.` etc, which negatively impacts "jump to file" in IDEs. - if result.msg == "": - result.msg = "unknown OS error" - -proc raiseOSError*(errorCode: OSErrorCode, additionalInfo = "") {.noinline.} = - ## Raises an `OSError exception `_. - ## - ## Read the description of the `newOSError proc`_ to learn - ## how the exception object is created. - raise newOSError(errorCode, additionalInfo) - -{.push stackTrace:off.} -proc osLastError*(): OSErrorCode {.sideEffect.} = - ## Retrieves the last operating system error code. - ## - ## This procedure is useful in the event when an OS call fails. In that case - ## this procedure will return the error code describing the reason why the - ## OS call failed. The `OSErrorMsg` procedure can then be used to convert - ## this code into a string. - ## - ## .. warning:: The behaviour of this procedure varies between Windows and POSIX systems. - ## On Windows some OS calls can reset the error code to `0` causing this - ## procedure to return `0`. It is therefore advised to call this procedure - ## immediately after an OS call fails. On POSIX systems this is not a problem. - ## - ## See also: - ## * `osErrorMsg proc`_ - ## * `raiseOSError proc`_ - when defined(nimscript): - discard - elif defined(windows): - result = cast[OSErrorCode](getLastError()) - else: - result = OSErrorCode(errno) -{.pop.} diff --git a/lib/std/outparams.nim b/lib/std/outparams.nim deleted file mode 100644 index 8a0e5ae67..000000000 --- a/lib/std/outparams.nim +++ /dev/null @@ -1,38 +0,0 @@ -# -# -# Nim's Runtime Library -# (c) Copyright 2022 Nim contributors -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# - -## `outParamsAt` macro for easy writing code that works with both 2.0 and 1.x. - -import macros - -macro outParamsAt*(positions: static openArray[int]; n: untyped): untyped = - ## Use this macro to annotate `out` parameters in a portable way. - runnableExamples: - proc p(x: var int) {.outParamsAt: [1].} = - discard "x is really an 'out int' if the Nim compiler supports 'out' parameters" - - result = n - when defined(nimHasOutParams): - var p = n.params - for po in positions: - p[po][^2].expectKind nnkVarTy - p[po][^2] = newTree(nnkOutTy, p[po][^2][0]) - -when isMainModule: - {.experimental: "strictDefs".} - - proc main(x: var int) {.outParamsAt: [1].} = - x = 3 - - proc us = - var x: int - main x - echo x - - us() diff --git a/lib/std/packedsets.nim b/lib/std/packedsets.nim deleted file mode 100644 index e8e03af9e..000000000 --- a/lib/std/packedsets.nim +++ /dev/null @@ -1,601 +0,0 @@ -# -# -# Nim's Runtime Library -# (c) Copyright 2012 Andreas Rumpf -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# - -## The `packedsets` module implements an efficient `Ordinal` set implemented as a -## `sparse bit set`:idx:. -## -## Supports any Ordinal type. -## -## See also -## ======== -## * `sets module `_ for more general hash sets - -import std/private/since -import hashes - -when defined(nimPreviewSlimSystem): - import std/assertions - -type - BitScalar = uint - -const - InitIntSetSize = 8 # must be a power of two! - TrunkShift = 9 - BitsPerTrunk = 1 shl TrunkShift # needs to be a power of 2 and - # divisible by 64 - TrunkMask = BitsPerTrunk - 1 - IntsPerTrunk = BitsPerTrunk div (sizeof(BitScalar) * 8) - IntShift = 5 + ord(sizeof(BitScalar) == 8) # 5 or 6, depending on int width - IntMask = 1 shl IntShift - 1 - -type - Trunk {.acyclic.} = ref object - next: Trunk # all nodes are connected with this pointer - key: int # start address at bit 0 - bits: array[0..IntsPerTrunk - 1, BitScalar] # a bit vector - - TrunkSeq = seq[Trunk] - - PackedSet*[A: Ordinal] = object - ## An efficient set of `Ordinal` types implemented as a sparse bit set. - elems: int # only valid for small numbers - counter, max: int - head: Trunk - data: TrunkSeq - a: array[0..33, int] # profiling shows that 34 elements are enough - -proc mustRehash[T](t: T): bool {.inline.} = - let length = t.max + 1 - assert length > t.counter - result = (length * 2 < t.counter * 3) or (length - t.counter < 4) - -proc nextTry(h, maxHash: Hash, perturb: var Hash): Hash {.inline.} = - const PERTURB_SHIFT = 5 - var perturb2 = cast[uint](perturb) shr PERTURB_SHIFT - perturb = cast[Hash](perturb2) - result = ((5 * h) + 1 + perturb) and maxHash - -proc packedSetGet[A](t: PackedSet[A], key: int): Trunk = - var h = key and t.max - var perturb = key - while t.data[h] != nil: - if t.data[h].key == key: - return t.data[h] - h = nextTry(h, t.max, perturb) - result = nil - -proc intSetRawInsert[A](t: PackedSet[A], data: var TrunkSeq, desc: Trunk) = - var h = desc.key and t.max - var perturb = desc.key - while data[h] != nil: - assert data[h] != desc - h = nextTry(h, t.max, perturb) - assert data[h] == nil - data[h] = desc - -proc intSetEnlarge[A](t: var PackedSet[A]) = - var n: TrunkSeq - var oldMax = t.max - t.max = ((t.max + 1) * 2) - 1 - newSeq(n, t.max + 1) - for i in countup(0, oldMax): - if t.data[i] != nil: intSetRawInsert(t, n, t.data[i]) - swap(t.data, n) - -proc intSetPut[A](t: var PackedSet[A], key: int): Trunk = - var h = key and t.max - var perturb = key - while t.data[h] != nil: - if t.data[h].key == key: - return t.data[h] - h = nextTry(h, t.max, perturb) - if mustRehash(t): intSetEnlarge(t) - inc(t.counter) - h = key and t.max - perturb = key - while t.data[h] != nil: h = nextTry(h, t.max, perturb) - assert t.data[h] == nil - new(result) - result.next = t.head - result.key = key - t.head = result - t.data[h] = result - -proc bitincl[A](s: var PackedSet[A], key: int) {.inline.} = - var ret: Trunk - var t = intSetPut(s, key shr TrunkShift) - var u = key and TrunkMask - t.bits[u shr IntShift] = t.bits[u shr IntShift] or - (BitScalar(1) shl (u and IntMask)) - -proc exclImpl[A](s: var PackedSet[A], key: int) = - if s.elems <= s.a.len: - for i in 0.. 1: result.add(", ") - result.add $key - result.add("}") - -iterator items*[A](s: PackedSet[A]): A {.inline.} = - ## Iterates over any included element of `s`. - if s.elems <= s.a.len: - for i in 0..`_ - runnableExamples: - let a = initPackedSet[int]() - assert len(a) == 0 - - type Id = distinct int - var ids = initPackedSet[Id]() - ids.incl(3.Id) - - result = PackedSet[A]( - elems: 0, - counter: 0, - max: 0, - head: nil, - data: @[]) - # a: array[0..33, int] # profiling shows that 34 elements are enough - -proc contains*[A](s: PackedSet[A], key: A): bool = - ## Returns true if `key` is in `s`. - ## - ## This allows the usage of the `in` operator. - runnableExamples: - type ABCD = enum A, B, C, D - - let a = [1, 3, 5].toPackedSet - assert a.contains(3) - assert 3 in a - assert not a.contains(8) - assert 8 notin a - - let letters = [A, C].toPackedSet - assert A in letters - assert C in letters - assert B notin letters - - if s.elems <= s.a.len: - for i in 0..`_ for excluding an element - ## * `incl proc <#incl,PackedSet[A],PackedSet[A]>`_ for including a set - ## * `containsOrIncl proc <#containsOrIncl,PackedSet[A],A>`_ - runnableExamples: - var a = initPackedSet[int]() - a.incl(3) - a.incl(3) - assert len(a) == 1 - - if s.elems <= s.a.len: - for i in 0..`_. - ## - ## **See also:** - ## * `excl proc <#excl,PackedSet[A],PackedSet[A]>`_ for excluding a set - ## * `incl proc <#incl,PackedSet[A],A>`_ for including an element - ## * `containsOrIncl proc <#containsOrIncl,PackedSet[A],A>`_ - runnableExamples: - var a = [1].toPackedSet - a.incl([5].toPackedSet) - assert len(a) == 2 - assert 5 in a - - for item in other.items: incl(s, item) - -proc toPackedSet*[A](x: openArray[A]): PackedSet[A] {.since: (1, 3).} = - ## Creates a new `PackedSet[A]` that contains the elements of `x`. - ## - ## Duplicates are removed. - ## - ## **See also:** - ## * `initPackedSet proc <#initPackedSet>`_ - runnableExamples: - let a = [5, 6, 7, 8, 8].toPackedSet - assert len(a) == 4 - assert $a == "{5, 6, 7, 8}" - - result = initPackedSet[A]() - for item in x: - result.incl(item) - -proc containsOrIncl*[A](s: var PackedSet[A], key: A): bool = - ## Includes `key` in the set `s` and tells if `key` was already in `s`. - ## - ## The difference with regards to the `incl proc <#incl,PackedSet[A],A>`_ is - ## that this proc returns true if `s` already contained `key`. The - ## proc will return false if `key` was added as a new value to `s` during - ## this call. - ## - ## **See also:** - ## * `incl proc <#incl,PackedSet[A],A>`_ for including an element - ## * `missingOrExcl proc <#missingOrExcl,PackedSet[A],A>`_ - runnableExamples: - var a = initPackedSet[int]() - assert a.containsOrIncl(3) == false - assert a.containsOrIncl(3) == true - assert a.containsOrIncl(4) == false - - if s.elems <= s.a.len: - for i in 0..`_ for including an element - ## * `excl proc <#excl,PackedSet[A],PackedSet[A]>`_ for excluding a set - ## * `missingOrExcl proc <#missingOrExcl,PackedSet[A],A>`_ - runnableExamples: - var a = [3].toPackedSet - a.excl(3) - a.excl(3) - a.excl(99) - assert len(a) == 0 - - exclImpl[A](s, ord(key)) - -proc excl*[A](s: var PackedSet[A], other: PackedSet[A]) = - ## Excludes all elements from `other` from `s`. - ## - ## This is the in-place version of `s - other <#-,PackedSet[A],PackedSet[A]>`_. - ## - ## **See also:** - ## * `incl proc <#incl,PackedSet[A],PackedSet[A]>`_ for including a set - ## * `excl proc <#excl,PackedSet[A],A>`_ for excluding an element - ## * `missingOrExcl proc <#missingOrExcl,PackedSet[A],A>`_ - runnableExamples: - var a = [1, 5].toPackedSet - a.excl([5].toPackedSet) - assert len(a) == 1 - assert 5 notin a - - for item in other.items: - excl(s, item) - -proc len*[A](s: PackedSet[A]): int {.inline.} = - ## Returns the number of elements in `s`. - runnableExamples: - let a = [1, 3, 5].toPackedSet - assert len(a) == 3 - - if s.elems < s.a.len: - result = s.elems - else: - result = 0 - for _ in s.items: - # pending bug #11167; when fixed, check each explicit `items` to see if it can be removed - inc(result) - -proc missingOrExcl*[A](s: var PackedSet[A], key: A): bool = - ## Excludes `key` from the set `s` and tells if `key` was already missing from `s`. - ## - ## The difference with regards to the `excl proc <#excl,PackedSet[A],A>`_ is - ## that this proc returns true if `key` was missing from `s`. - ## The proc will return false if `key` was in `s` and it was removed - ## during this call. - ## - ## **See also:** - ## * `excl proc <#excl,PackedSet[A],A>`_ for excluding an element - ## * `excl proc <#excl,PackedSet[A],PackedSet[A]>`_ for excluding a set - ## * `containsOrIncl proc <#containsOrIncl,PackedSet[A],A>`_ - runnableExamples: - var a = [5].toPackedSet - assert a.missingOrExcl(5) == false - assert a.missingOrExcl(5) == true - - var count = s.len - exclImpl(s, ord(key)) - result = count == s.len - -proc clear*[A](result: var PackedSet[A]) = - ## Clears the `PackedSet[A]` back to an empty state. - runnableExamples: - var a = [5, 7].toPackedSet - clear(a) - assert len(a) == 0 - - # setLen(result.data, InitIntSetSize) - # for i in 0..InitIntSetSize - 1: result.data[i] = nil - # result.max = InitIntSetSize - 1 - result.data = @[] - result.max = 0 - result.counter = 0 - result.head = nil - result.elems = 0 - -proc isNil*[A](x: PackedSet[A]): bool {.inline.} = - ## Returns true if `x` is empty, false otherwise. - runnableExamples: - var a = initPackedSet[int]() - assert a.isNil - a.incl(2) - assert not a.isNil - a.excl(2) - assert a.isNil - - x.head.isNil and x.elems == 0 - -proc `=copy`*[A](dest: var PackedSet[A], src: PackedSet[A]) = - ## Copies `src` to `dest`. - ## `dest` does not need to be initialized by the `initPackedSet proc <#initPackedSet>`_. - if src.elems <= src.a.len: - dest.data = @[] - dest.max = 0 - dest.counter = src.counter - dest.head = nil - dest.elems = src.elems - dest.a = src.a - else: - dest.counter = src.counter - dest.max = src.max - dest.elems = src.elems - newSeq(dest.data, src.data.len) - - var it = src.head - while it != nil: - var h = it.key and dest.max - var perturb = it.key - while dest.data[h] != nil: h = nextTry(h, dest.max, perturb) - assert dest.data[h] == nil - var n: Trunk - new(n) - n.next = dest.head - n.key = it.key - n.bits = it.bits - dest.head = n - dest.data[h] = n - it = it.next - -proc assign*[A](dest: var PackedSet[A], src: PackedSet[A]) {.inline, deprecated.} = - ## Copies `src` to `dest`. - ## `dest` does not need to be initialized by the `initPackedSet proc <#initPackedSet>`_. - runnableExamples: - var - a = initPackedSet[int]() - b = initPackedSet[int]() - b.incl(5) - b.incl(7) - a.assign(b) - assert len(a) == 2 - `=copy`(dest, src) - -proc union*[A](s1, s2: PackedSet[A]): PackedSet[A] = - ## Returns the union of the sets `s1` and `s2`. - ## - ## The same as `s1 + s2 <#+,PackedSet[A],PackedSet[A]>`_. - runnableExamples: - let - a = [1, 2, 3].toPackedSet - b = [3, 4, 5].toPackedSet - c = union(a, b) - assert c.len == 5 - assert c == [1, 2, 3, 4, 5].toPackedSet - - result.assign(s1) - incl(result, s2) - -proc intersection*[A](s1, s2: PackedSet[A]): PackedSet[A] = - ## Returns the intersection of the sets `s1` and `s2`. - ## - ## The same as `s1 * s2 <#*,PackedSet[A],PackedSet[A]>`_. - runnableExamples: - let - a = [1, 2, 3].toPackedSet - b = [3, 4, 5].toPackedSet - c = intersection(a, b) - assert c.len == 1 - assert c == [3].toPackedSet - - result = initPackedSet[A]() - for item in s1.items: - if contains(s2, item): - incl(result, item) - -proc difference*[A](s1, s2: PackedSet[A]): PackedSet[A] = - ## Returns the difference of the sets `s1` and `s2`. - ## - ## The same as `s1 - s2 <#-,PackedSet[A],PackedSet[A]>`_. - runnableExamples: - let - a = [1, 2, 3].toPackedSet - b = [3, 4, 5].toPackedSet - c = difference(a, b) - assert c.len == 2 - assert c == [1, 2].toPackedSet - - result = initPackedSet[A]() - for item in s1.items: - if not contains(s2, item): - incl(result, item) - -proc symmetricDifference*[A](s1, s2: PackedSet[A]): PackedSet[A] = - ## Returns the symmetric difference of the sets `s1` and `s2`. - runnableExamples: - let - a = [1, 2, 3].toPackedSet - b = [3, 4, 5].toPackedSet - c = symmetricDifference(a, b) - assert c.len == 4 - assert c == [1, 2, 4, 5].toPackedSet - - result.assign(s1) - for item in s2.items: - if containsOrIncl(result, item): - excl(result, item) - -proc `+`*[A](s1, s2: PackedSet[A]): PackedSet[A] {.inline.} = - ## Alias for `union(s1, s2) <#union,PackedSet[A],PackedSet[A]>`_. - result = union(s1, s2) - -proc `*`*[A](s1, s2: PackedSet[A]): PackedSet[A] {.inline.} = - ## Alias for `intersection(s1, s2) <#intersection,PackedSet[A],PackedSet[A]>`_. - result = intersection(s1, s2) - -proc `-`*[A](s1, s2: PackedSet[A]): PackedSet[A] {.inline.} = - ## Alias for `difference(s1, s2) <#difference,PackedSet[A],PackedSet[A]>`_. - result = difference(s1, s2) - -proc disjoint*[A](s1, s2: PackedSet[A]): bool = - ## Returns true if the sets `s1` and `s2` have no items in common. - runnableExamples: - let - a = [1, 2].toPackedSet - b = [2, 3].toPackedSet - c = [3, 4].toPackedSet - assert disjoint(a, b) == false - assert disjoint(a, c) == true - - for item in s1.items: - if contains(s2, item): - return false - return true - -proc card*[A](s: PackedSet[A]): int {.inline.} = - ## Alias for `len() <#len,PackedSet[A]>`_. - ## - ## Card stands for the [cardinality](http://en.wikipedia.org/wiki/Cardinality) - ## of a set. - result = s.len() - -proc `<=`*[A](s1, s2: PackedSet[A]): bool = - ## Returns true if `s1` is a subset of `s2`. - ## - ## A subset `s1` has all of its elements in `s2`, but `s2` doesn't necessarily - ## have more elements than `s1`. That is, `s1` can be equal to `s2`. - runnableExamples: - let - a = [1].toPackedSet - b = [1, 2].toPackedSet - c = [1, 3].toPackedSet - assert a <= b - assert b <= b - assert not (c <= b) - - for item in s1.items: - if not s2.contains(item): - return false - return true - -proc `<`*[A](s1, s2: PackedSet[A]): bool = - ## Returns true if `s1` is a proper subset of `s2`. - ## - ## A strict or proper subset `s1` has all of its elements in `s2`, but `s2` has - ## more elements than `s1`. - runnableExamples: - let - a = [1].toPackedSet - b = [1, 2].toPackedSet - c = [1, 3].toPackedSet - assert a < b - assert not (b < b) - assert not (c < b) - - return s1 <= s2 and not (s2 <= s1) - -proc `==`*[A](s1, s2: PackedSet[A]): bool = - ## Returns true if both `s1` and `s2` have the same elements and set size. - runnableExamples: - assert [1, 2].toPackedSet == [2, 1].toPackedSet - assert [1, 2].toPackedSet == [2, 1, 2].toPackedSet - - return s1 <= s2 and s2 <= s1 - -proc `$`*[A](s: PackedSet[A]): string = - ## Converts `s` to a string. - runnableExamples: - let a = [1, 2, 3].toPackedSet - assert $a == "{1, 2, 3}" - - dollarImpl() diff --git a/lib/std/paths.nim b/lib/std/paths.nim deleted file mode 100644 index c29096982..000000000 --- a/lib/std/paths.nim +++ /dev/null @@ -1,289 +0,0 @@ -## This module implements path handling. - -import std/private/osseps -export osseps - -import std/envvars -import std/private/osappdirs - -import pathnorm - -from std/private/ospaths2 import joinPath, splitPath, - ReadDirEffect, WriteDirEffect, - isAbsolute, relativePath, - normalizePathEnd, isRelativeTo, parentDir, - tailDir, isRootDir, parentDirs, `/../`, - extractFilename, lastPathPart, - changeFileExt, addFileExt, cmpPaths, splitFile, - unixToNativePath, absolutePath, normalizeExe, - normalizePath -export ReadDirEffect, WriteDirEffect - -type - Path* = distinct string - -func `==`*(x, y: Path): bool {.inline.} = - ## Compares two paths. - ## - ## On a case-sensitive filesystem this is done - ## case-sensitively otherwise case-insensitively. - result = cmpPaths(x.string, y.string) == 0 - -template endsWith(a: string, b: set[char]): bool = - a.len > 0 and a[^1] in b - -func add(x: var string, tail: string) = - var state = 0 - let trailingSep = tail.endsWith({DirSep, AltSep}) or tail.len == 0 and x.endsWith({DirSep, AltSep}) - normalizePathEnd(x, trailingSep=false) - addNormalizePath(tail, x, state, DirSep) - normalizePathEnd(x, trailingSep=trailingSep) - -func add*(x: var Path, y: Path) {.borrow.} - -func `/`*(head, tail: Path): Path {.inline.} = - ## Joins two directory names to one. - ## - ## returns normalized path concatenation of `head` and `tail`, preserving - ## whether or not `tail` has a trailing slash (or, if tail if empty, whether - ## head has one). - ## - ## See also: - ## * `splitPath proc`_ - ## * `uri.combine proc `_ - ## * `uri./ proc `_ - Path(joinPath(head.string, tail.string)) - -func splitPath*(path: Path): tuple[head, tail: Path] {.inline.} = - ## Splits a directory into `(head, tail)` tuple, so that - ## ``head / tail == path`` (except for edge cases like "/usr"). - ## - ## See also: - ## * `add proc`_ - ## * `/ proc`_ - ## * `/../ proc`_ - ## * `relativePath proc`_ - let res = splitPath(path.string) - result = (Path(res.head), Path(res.tail)) - -func splitFile*(path: Path): tuple[dir, name: Path, ext: string] {.inline.} = - ## Splits a filename into `(dir, name, extension)` tuple. - ## - ## `dir` does not end in DirSep unless it's `/`. - ## `extension` includes the leading dot. - ## - ## If `path` has no extension, `ext` is the empty string. - ## If `path` has no directory component, `dir` is the empty string. - ## If `path` has no filename component, `name` and `ext` are empty strings. - ## - ## See also: - ## * `extractFilename proc`_ - ## * `lastPathPart proc`_ - ## * `changeFileExt proc`_ - ## * `addFileExt proc`_ - let res = splitFile(path.string) - result = (Path(res.dir), Path(res.name), res.ext) - -func isAbsolute*(path: Path): bool {.inline, raises: [].} = - ## Checks whether a given `path` is absolute. - ## - ## On Windows, network paths are considered absolute too. - result = isAbsolute(path.string) - -proc relativePath*(path, base: Path, sep = DirSep): Path {.inline.} = - ## Converts `path` to a path relative to `base`. - ## - ## The `sep` (default: DirSep) is used for the path normalizations, - ## this can be useful to ensure the relative path only contains `'/'` - ## so that it can be used for URL constructions. - ## - ## On Windows, if a root of `path` and a root of `base` are different, - ## returns `path` as is because it is impossible to make a relative path. - ## That means an absolute path can be returned. - ## - ## See also: - ## * `splitPath proc`_ - ## * `parentDir proc`_ - ## * `tailDir proc`_ - result = Path(relativePath(path.string, base.string, sep)) - -proc isRelativeTo*(path: Path, base: Path): bool {.inline.} = - ## Returns true if `path` is relative to `base`. - result = isRelativeTo(path.string, base.string) - - -func parentDir*(path: Path): Path {.inline.} = - ## Returns the parent directory of `path`. - ## - ## This is similar to ``splitPath(path).head`` when ``path`` doesn't end - ## in a dir separator, but also takes care of path normalizations. - ## The remainder can be obtained with `lastPathPart(path) proc`_. - ## - ## See also: - ## * `relativePath proc`_ - ## * `splitPath proc`_ - ## * `tailDir proc`_ - ## * `parentDirs iterator`_ - result = Path(parentDir(path.string)) - -func tailDir*(path: Path): Path {.inline.} = - ## Returns the tail part of `path`. - ## - ## See also: - ## * `relativePath proc`_ - ## * `splitPath proc`_ - ## * `parentDir proc`_ - result = Path(tailDir(path.string)) - -func isRootDir*(path: Path): bool {.inline.} = - ## Checks whether a given `path` is a root directory. - result = isRootDir(path.string) - -iterator parentDirs*(path: Path, fromRoot=false, inclusive=true): Path = - ## Walks over all parent directories of a given `path`. - ## - ## If `fromRoot` is true (default: false), the traversal will start from - ## the file system root directory. - ## If `inclusive` is true (default), the original argument will be included - ## in the traversal. - ## - ## Relative paths won't be expanded by this iterator. Instead, it will traverse - ## only the directories appearing in the relative path. - ## - ## See also: - ## * `parentDir proc`_ - ## - for p in parentDirs(path.string, fromRoot, inclusive): - yield Path(p) - -func `/../`*(head, tail: Path): Path {.inline.} = - ## The same as ``parentDir(head) / tail``, unless there is no parent - ## directory. Then ``head / tail`` is performed instead. - ## - ## See also: - ## * `/ proc`_ - ## * `parentDir proc`_ - Path(`/../`(head.string, tail.string)) - -func extractFilename*(path: Path): Path {.inline.} = - ## Extracts the filename of a given `path`. - ## - ## This is the same as ``name & ext`` from `splitFile(path) proc`_. - ## - ## See also: - ## * `splitFile proc`_ - ## * `lastPathPart proc`_ - ## * `changeFileExt proc`_ - ## * `addFileExt proc`_ - result = Path(extractFilename(path.string)) - -func lastPathPart*(path: Path): Path {.inline.} = - ## Like `extractFilename proc`_, but ignores - ## trailing dir separator; aka: `baseName`:idx: in some other languages. - ## - ## See also: - ## * `splitFile proc`_ - ## * `extractFilename proc`_ - ## * `changeFileExt proc`_ - ## * `addFileExt proc`_ - result = Path(lastPathPart(path.string)) - -func changeFileExt*(filename: Path, ext: string): Path {.inline.} = - ## Changes the file extension to `ext`. - ## - ## If the `filename` has no extension, `ext` will be added. - ## If `ext` == "" then any extension is removed. - ## - ## `Ext` should be given without the leading `'.'`, because some - ## filesystems may use a different character. (Although I know - ## of none such beast.) - ## - ## See also: - ## * `splitFile proc`_ - ## * `extractFilename proc`_ - ## * `lastPathPart proc`_ - ## * `addFileExt proc`_ - result = Path(changeFileExt(filename.string, ext)) - -func addFileExt*(filename: Path, ext: string): Path {.inline.} = - ## Adds the file extension `ext` to `filename`, unless - ## `filename` already has an extension. - ## - ## `Ext` should be given without the leading `'.'`, because some - ## filesystems may use a different character. - ## (Although I know of none such beast.) - ## - ## See also: - ## * `splitFile proc`_ - ## * `extractFilename proc`_ - ## * `lastPathPart proc`_ - ## * `changeFileExt proc`_ - result = Path(addFileExt(filename.string, ext)) - -func unixToNativePath*(path: Path, drive=Path("")): Path {.inline.} = - ## Converts an UNIX-like path to a native one. - ## - ## On an UNIX system this does nothing. Else it converts - ## `'/'`, `'.'`, `'..'` to the appropriate things. - ## - ## On systems with a concept of "drives", `drive` is used to determine - ## which drive label to use during absolute path conversion. - ## `drive` defaults to the drive of the current working directory, and is - ## ignored on systems that do not have a concept of "drives". - result = Path(unixToNativePath(path.string, drive.string)) - -proc getCurrentDir*(): Path {.inline, tags: [].} = - ## Returns the `current working directory`:idx: i.e. where the built - ## binary is run. - ## - ## So the path returned by this proc is determined at run time. - ## - ## See also: - ## * `getHomeDir proc `_ - ## * `getConfigDir proc `_ - ## * `getTempDir proc `_ - ## * `setCurrentDir proc `_ - ## * `currentSourcePath template `_ - ## * `getProjectPath proc `_ - result = Path(ospaths2.getCurrentDir()) - -proc normalizeExe*(file: var Path) {.borrow.} - -proc normalizePath*(path: var Path) {.borrow.} - -proc normalizePathEnd*(path: var Path, trailingSep = false) {.borrow.} - -proc absolutePath*(path: Path, root = getCurrentDir()): Path = - ## Returns the absolute path of `path`, rooted at `root` (which must be absolute; - ## default: current directory). - ## If `path` is absolute, return it, ignoring `root`. - ## - ## See also: - ## * `normalizePath proc`_ - result = Path(absolutePath(path.string, root.string)) - -proc expandTildeImpl(path: string): string {. - tags: [ReadEnvEffect, ReadIOEffect].} = - if len(path) == 0 or path[0] != '~': - result = path - elif len(path) == 1: - result = getHomeDir() - elif (path[1] in {DirSep, AltSep}): - result = joinPath(getHomeDir(), path.substr(2)) - else: - # TODO: handle `~bob` and `~bob/` which means home of bob - result = path - -proc expandTilde*(path: Path): Path {.inline, - tags: [ReadEnvEffect, ReadIOEffect].} = - ## Expands ``~`` or a path starting with ``~/`` to a full path, replacing - ## ``~`` with `getHomeDir() `_ (otherwise returns ``path`` unmodified). - ## - ## Windows: this is still supported despite the Windows platform not having this - ## convention; also, both ``~/`` and ``~\`` are handled. - runnableExamples: - import std/appdirs - assert expandTilde(Path("~") / Path("appname.cfg")) == getHomeDir() / Path("appname.cfg") - assert expandTilde(Path("~/foo/bar")) == getHomeDir() / Path("foo/bar") - assert expandTilde(Path("/foo/bar")) == Path("/foo/bar") - result = Path(expandTildeImpl(path.string)) diff --git a/lib/std/private/bitops_utils.nim b/lib/std/private/bitops_utils.nim deleted file mode 100644 index 0b9484416..000000000 --- a/lib/std/private/bitops_utils.nim +++ /dev/null @@ -1,22 +0,0 @@ -template forwardImpl*(impl, arg) {.dirty.} = - when sizeof(x) <= 4: - when x is SomeSignedInt: - impl(cast[uint32](x.int32)) - else: - impl(x.uint32) - else: - when x is SomeSignedInt: - impl(cast[uint64](x.int64)) - else: - impl(x.uint64) - -# this could also be implemented via: -# import std/typetraits -# template castToUnsigned*(x: SomeInteger): auto = cast[toUnsigned(typeof(x))](x) - -template castToUnsigned*(x: int8): uint8 = cast[uint8](x) -template castToUnsigned*(x: int16): uint16 = cast[uint16](x) -template castToUnsigned*(x: int32): uint32 = cast[uint32](x) -template castToUnsigned*(x: int64): uint64 = cast[uint64](x) -template castToUnsigned*(x: int): uint = cast[uint](x) -template castToUnsigned*[T: SomeUnsignedInt](x: T): T = x diff --git a/lib/std/private/decode_helpers.nim b/lib/std/private/decode_helpers.nim deleted file mode 100644 index f11e3060a..000000000 --- a/lib/std/private/decode_helpers.nim +++ /dev/null @@ -1,42 +0,0 @@ -proc handleHexChar*(c: char, x: var int): bool {.inline.} = - ## Converts `%xx` hexadecimal to the ordinal number and adds the result to `x`. - ## Returns `true` if `c` is hexadecimal. - ## - ## When `c` is hexadecimal, the proc is equal to `x = x shl 4 + hex2Int(c)`. - runnableExamples: - var x = 0 - assert handleHexChar('a', x) - assert x == 10 - - assert handleHexChar('B', x) - assert x == 171 # 10 shl 4 + 11 - - assert not handleHexChar('?', x) - assert x == 171 # unchanged - result = true - case c - of '0'..'9': x = (x shl 4) or (ord(c) - ord('0')) - of 'a'..'f': x = (x shl 4) or (ord(c) - ord('a') + 10) - of 'A'..'F': x = (x shl 4) or (ord(c) - ord('A') + 10) - else: - result = false - -proc handleHexChar*(c: char): int {.inline.} = - case c - of '0'..'9': result = (ord(c) - ord('0')) - of 'a'..'f': result = (ord(c) - ord('a') + 10) - of 'A'..'F': result = (ord(c) - ord('A') + 10) - else: discard - -proc decodePercent*(s: openArray[char], i: var int): char = - ## Converts `%xx` hexadecimal to the character with ordinal number `xx`. - ## - ## If `xx` is not a valid hexadecimal value, it is left intact: only the - ## leading `%` is returned as-is, and `xx` characters will be processed in the - ## next step (e.g. in `uri.decodeUrl`) as regular characters. - result = '%' - if i+2 < s.len: - var x = 0 - if handleHexChar(s[i+1], x) and handleHexChar(s[i+2], x): - result = chr(x) - inc(i, 2) diff --git a/lib/std/private/digitsutils.nim b/lib/std/private/digitsutils.nim deleted file mode 100644 index e051e5218..000000000 --- a/lib/std/private/digitsutils.nim +++ /dev/null @@ -1,115 +0,0 @@ -const - trailingZeros100: array[100, int8] = [2'i8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, - 0, 0, 0, 0, 0, 0] - - digits100: array[200, char] = ['0', '0', '0', '1', '0', '2', '0', '3', '0', '4', '0', '5', - '0', '6', '0', '7', '0', '8', '0', '9', '1', '0', '1', '1', '1', '2', '1', '3', '1', '4', - '1', '5', '1', '6', '1', '7', '1', '8', '1', '9', '2', '0', '2', '1', '2', '2', '2', '3', - '2', '4', '2', '5', '2', '6', '2', '7', '2', '8', '2', '9', '3', '0', '3', '1', '3', '2', - '3', '3', '3', '4', '3', '5', '3', '6', '3', '7', '3', '8', '3', '9', '4', '0', '4', '1', - '4', '2', '4', '3', '4', '4', '4', '5', '4', '6', '4', '7', '4', '8', '4', '9', '5', '0', - '5', '1', '5', '2', '5', '3', '5', '4', '5', '5', '5', '6', '5', '7', '5', '8', '5', '9', - '6', '0', '6', '1', '6', '2', '6', '3', '6', '4', '6', '5', '6', '6', '6', '7', '6', '8', - '6', '9', '7', '0', '7', '1', '7', '2', '7', '3', '7', '4', '7', '5', '7', '6', '7', '7', - '7', '8', '7', '9', '8', '0', '8', '1', '8', '2', '8', '3', '8', '4', '8', '5', '8', '6', - '8', '7', '8', '8', '8', '9', '9', '0', '9', '1', '9', '2', '9', '3', '9', '4', '9', '5', - '9', '6', '9', '7', '9', '8', '9', '9'] - -# Inspired by https://engineering.fb.com/2013/03/15/developer-tools/three-optimization-tips-for-c -# Generates: -# .. code-block:: nim -# var res = "" -# for i in 0 .. 99: -# if i < 10: -# res.add "0" & $i -# else: -# res.add $i -# doAssert res == digits100 - -proc utoa2Digits*(buf: var openArray[char]; pos: int; digits: uint32) {.inline.} = - buf[pos] = digits100[2 * digits] - buf[pos+1] = digits100[2 * digits + 1] - #copyMem(buf, unsafeAddr(digits100[2 * digits]), 2 * sizeof((char))) - -proc trailingZeros2Digits*(digits: uint32): int32 {.inline.} = - return trailingZeros100[digits.int8] - -when defined(js): - proc numToString(a: SomeInteger): cstring {.importjs: "((#) + \"\")".} - -func addChars[T](result: var string, x: T, start: int, n: int) {.inline.} = - let old = result.len - result.setLen old + n - template impl = - for i in 0..= nbatch: - let originNum = num - num = num div nbatch - let index = int16((originNum - num * nbatch) shl 1) - tmp[next] = digits100[index + 1] - tmp[next - 1] = digits100[index] - dec(next, 2) - - # process last 1-2 digits - if num < 10: - tmp[next] = chr(ord('0') + num.uint8) - else: - let index = num * 2 - tmp[next] = digits100[index + 1] - tmp[next - 1] = digits100[index] - dec next - addChars(result, tmp, next, tmp.len - next) - -when not defined(nimHasEnforceNoRaises): - {.pragma: enforceNoRaises.} - -func addInt*(result: var string, x: uint64) {.enforceNoRaises.} = - when nimvm: addIntImpl(result, x) - else: - when not defined(js): addIntImpl(result, x) - else: - addChars(result, numToString(x)) - -proc addInt*(result: var string; x: int64) {.enforceNoRaises.} = - ## Converts integer to its string representation and appends it to `result`. - runnableExamples: - var s = "foo" - s.addInt(45) - assert s == "foo45" - template impl = - var num: uint64 - if x < 0: - if x == low(int64): - num = cast[uint64](x) - else: - num = uint64(-x) - result.add '-' - else: - num = uint64(x) - addInt(result, num) - when nimvm: impl() - else: - when defined(js): - addChars(result, numToString(x)) - else: impl() - -proc addInt*(result: var string; x: int) {.inline, enforceNoRaises.} = - addInt(result, int64(x)) diff --git a/lib/std/private/dragonbox.nim b/lib/std/private/dragonbox.nim deleted file mode 100644 index 2ba22a751..000000000 --- a/lib/std/private/dragonbox.nim +++ /dev/null @@ -1,1325 +0,0 @@ -## Copyright 2020 Junekey Jeon -## Copyright 2020 Alexander Bolz -## -## Distributed under the Boost Software License, Version 1.0. -## (See accompanying file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt) - -## char* output_end = Dtoa(buffer, value); -## -## Converts the given double-precision number into decimal form and stores the result in the given -## buffer. -## -## The buffer must be large enough, i.e. >= DtoaMinBufferLength. -## The output format is similar to printf("%g"). -## The output is _not_ null-terminted. -## -## The output is optimal, i.e. the output string -## 1. rounds back to the input number when read in (using round-to-nearest-even) -## 2. is as short as possible, -## 3. is as close to the input number as possible. -## -## Note: -## This function may temporarily write up to DtoaMinBufferLength characters into the buffer. - - -import std/private/digitsutils - -when defined(nimPreviewSlimSystem): - import std/assertions - -const - dtoaMinBufferLength*: cint = 64 - -## This file contains an implementation of Junekey Jeon's Dragonbox algorithm. -## -## It is a simplified version of the reference implementation found here: -## https://github.com/jk-jeon/dragonbox -## -## The reference implementation also works with single-precision floating-point numbers and -## has options to configure the rounding mode. - -template dragonbox_Assert*(x: untyped): untyped = - assert(x) - -# ================================================================================================== -# -# ================================================================================================== - -type - ValueType* = float - BitsType* = uint64 - -type - Double* = object - bits*: BitsType - -const ## = p (includes the hidden bit) - significandSize*: int32 = 53 - -const ## static constexpr int32_t MaxExponent = 1024 - 1 - (SignificandSize - 1); - ## static constexpr int32_t MinExponent = std::numeric_limits::min_exponent - 1 - (SignificandSize - 1); - exponentBias*: int32 = 1024 - 1 + (significandSize - 1) - -const - maxIeeeExponent*: BitsType = BitsType(2 * 1024 - 1) - -const ## = 2^(p-1) - hiddenBit*: BitsType = BitsType(1) shl (significandSize - 1) - -const ## = 2^(p-1) - 1 - significandMask*: BitsType = hiddenBit - 1 - -const - exponentMask*: BitsType = maxIeeeExponent shl (significandSize - 1) - -const - signMask*: BitsType = not (not BitsType(0) shr 1) - -proc constructDouble*(bits: BitsType): Double {.constructor.} = - result.bits = bits - -proc constructDouble*(value: ValueType): Double {.constructor.} = - result.bits = cast[typeof(result.bits)](value) - -proc physicalSignificand*(this: Double): BitsType {.noSideEffect.} = - return this.bits and significandMask - -proc physicalExponent*(this: Double): BitsType {.noSideEffect.} = - return (this.bits and exponentMask) shr (significandSize - 1) - -proc isFinite*(this: Double): bool {.noSideEffect.} = - return (this.bits and exponentMask) != exponentMask - -proc isInf*(this: Double): bool {.noSideEffect.} = - return (this.bits and exponentMask) == exponentMask and - (this.bits and significandMask) == 0 - -proc isNaN*(this: Double): bool {.noSideEffect.} = - return (this.bits and exponentMask) == exponentMask and - (this.bits and significandMask) != 0 - -proc isZero*(this: Double): bool {.noSideEffect.} = - return (this.bits and not signMask) == 0 - -proc signBit*(this: Double): int {.noSideEffect.} = - return ord((this.bits and signMask) != 0) - - -# ================================================================================================== -# -# ================================================================================================== -## namespace -## Returns floor(x / 2^n). -## -## Technically, right-shift of negative integers is implementation defined... -## Should easily be optimized into SAR (or equivalent) instruction. - -proc floorDivPow2*(x: int32; n: int32): int32 {.inline.} = - return x shr n - -proc floorLog2Pow10*(e: int32): int32 {.inline.} = - dragonbox_Assert(e >= -1233) - dragonbox_Assert(e <= 1233) - return floorDivPow2(e * 1741647, 19) - -proc floorLog10Pow2*(e: int32): int32 {.inline.} = - dragonbox_Assert(e >= -1500) - dragonbox_Assert(e <= 1500) - return floorDivPow2(e * 1262611, 22) - -proc floorLog10ThreeQuartersPow2*(e: int32): int32 {.inline.} = - dragonbox_Assert(e >= -1500) - dragonbox_Assert(e <= 1500) - return floorDivPow2(e * 1262611 - 524031, 22) - -# ================================================================================================== -# -# ================================================================================================== - -type - uint64x2* {.bycopy.} = object - hi*: uint64 - lo*: uint64 - - -proc computePow10*(k: int32): uint64x2 {.inline.} = - const - kMin: int32 = -292 - const - kMax: int32 = 326 - const - pow10: array[kMax - kMin + 1, uint64x2] = [ - uint64x2(hi: 0xFF77B1FCBEBCDC4F'u, lo: 0x25E8E89C13BB0F7B'u), - uint64x2(hi: 0x9FAACF3DF73609B1'u, lo: 0x77B191618C54E9AD'u), - uint64x2(hi: 0xC795830D75038C1D'u, lo: 0xD59DF5B9EF6A2418'u), - uint64x2(hi: 0xF97AE3D0D2446F25'u, lo: 0x4B0573286B44AD1E'u), - uint64x2(hi: 0x9BECCE62836AC577'u, lo: 0x4EE367F9430AEC33'u), - uint64x2(hi: 0xC2E801FB244576D5'u, lo: 0x229C41F793CDA740'u), - uint64x2(hi: 0xF3A20279ED56D48A'u, lo: 0x6B43527578C11110'u), - uint64x2(hi: 0x9845418C345644D6'u, lo: 0x830A13896B78AAAA'u), - uint64x2(hi: 0xBE5691EF416BD60C'u, lo: 0x23CC986BC656D554'u), - uint64x2(hi: 0xEDEC366B11C6CB8F'u, lo: 0x2CBFBE86B7EC8AA9'u), - uint64x2(hi: 0x94B3A202EB1C3F39'u, lo: 0x7BF7D71432F3D6AA'u), - uint64x2(hi: 0xB9E08A83A5E34F07'u, lo: 0xDAF5CCD93FB0CC54'u), - uint64x2(hi: 0xE858AD248F5C22C9'u, lo: 0xD1B3400F8F9CFF69'u), - uint64x2(hi: 0x91376C36D99995BE'u, lo: 0x23100809B9C21FA2'u), - uint64x2(hi: 0xB58547448FFFFB2D'u, lo: 0xABD40A0C2832A78B'u), - uint64x2(hi: 0xE2E69915B3FFF9F9'u, lo: 0x16C90C8F323F516D'u), - uint64x2(hi: 0x8DD01FAD907FFC3B'u, lo: 0xAE3DA7D97F6792E4'u), - uint64x2(hi: 0xB1442798F49FFB4A'u, lo: 0x99CD11CFDF41779D'u), - uint64x2(hi: 0xDD95317F31C7FA1D'u, lo: 0x40405643D711D584'u), - uint64x2(hi: 0x8A7D3EEF7F1CFC52'u, lo: 0x482835EA666B2573'u), - uint64x2(hi: 0xAD1C8EAB5EE43B66'u, lo: 0xDA3243650005EED0'u), - uint64x2(hi: 0xD863B256369D4A40'u, lo: 0x90BED43E40076A83'u), - uint64x2(hi: 0x873E4F75E2224E68'u, lo: 0x5A7744A6E804A292'u), - uint64x2(hi: 0xA90DE3535AAAE202'u, lo: 0x711515D0A205CB37'u), - uint64x2(hi: 0xD3515C2831559A83'u, lo: 0x0D5A5B44CA873E04'u), - uint64x2(hi: 0x8412D9991ED58091'u, lo: 0xE858790AFE9486C3'u), - uint64x2(hi: 0xA5178FFF668AE0B6'u, lo: 0x626E974DBE39A873'u), - uint64x2(hi: 0xCE5D73FF402D98E3'u, lo: 0xFB0A3D212DC81290'u), - uint64x2(hi: 0x80FA687F881C7F8E'u, lo: 0x7CE66634BC9D0B9A'u), - uint64x2(hi: 0xA139029F6A239F72'u, lo: 0x1C1FFFC1EBC44E81'u), - uint64x2(hi: 0xC987434744AC874E'u, lo: 0xA327FFB266B56221'u), - uint64x2(hi: 0xFBE9141915D7A922'u, lo: 0x4BF1FF9F0062BAA9'u), - uint64x2(hi: 0x9D71AC8FADA6C9B5'u, lo: 0x6F773FC3603DB4AA'u), - uint64x2(hi: 0xC4CE17B399107C22'u, lo: 0xCB550FB4384D21D4'u), - uint64x2(hi: 0xF6019DA07F549B2B'u, lo: 0x7E2A53A146606A49'u), - uint64x2(hi: 0x99C102844F94E0FB'u, lo: 0x2EDA7444CBFC426E'u), - uint64x2(hi: 0xC0314325637A1939'u, lo: 0xFA911155FEFB5309'u), - uint64x2(hi: 0xF03D93EEBC589F88'u, lo: 0x793555AB7EBA27CB'u), - uint64x2(hi: 0x96267C7535B763B5'u, lo: 0x4BC1558B2F3458DF'u), - uint64x2(hi: 0xBBB01B9283253CA2'u, lo: 0x9EB1AAEDFB016F17'u), - uint64x2(hi: 0xEA9C227723EE8BCB'u, lo: 0x465E15A979C1CADD'u), - uint64x2(hi: 0x92A1958A7675175F'u, lo: 0x0BFACD89EC191ECA'u), - uint64x2(hi: 0xB749FAED14125D36'u, lo: 0xCEF980EC671F667C'u), - uint64x2(hi: 0xE51C79A85916F484'u, lo: 0x82B7E12780E7401B'u), - uint64x2(hi: 0x8F31CC0937AE58D2'u, lo: 0xD1B2ECB8B0908811'u), - uint64x2(hi: 0xB2FE3F0B8599EF07'u, lo: 0x861FA7E6DCB4AA16'u), - uint64x2(hi: 0xDFBDCECE67006AC9'u, lo: 0x67A791E093E1D49B'u), - uint64x2(hi: 0x8BD6A141006042BD'u, lo: 0xE0C8BB2C5C6D24E1'u), - uint64x2(hi: 0xAECC49914078536D'u, lo: 0x58FAE9F773886E19'u), - uint64x2(hi: 0xDA7F5BF590966848'u, lo: 0xAF39A475506A899F'u), - uint64x2(hi: 0x888F99797A5E012D'u, lo: 0x6D8406C952429604'u), - uint64x2(hi: 0xAAB37FD7D8F58178'u, lo: 0xC8E5087BA6D33B84'u), - uint64x2(hi: 0xD5605FCDCF32E1D6'u, lo: 0xFB1E4A9A90880A65'u), - uint64x2(hi: 0x855C3BE0A17FCD26'u, lo: 0x5CF2EEA09A550680'u), - uint64x2(hi: 0xA6B34AD8C9DFC06F'u, lo: 0xF42FAA48C0EA481F'u), - uint64x2(hi: 0xD0601D8EFC57B08B'u, lo: 0xF13B94DAF124DA27'u), - uint64x2(hi: 0x823C12795DB6CE57'u, lo: 0x76C53D08D6B70859'u), - uint64x2(hi: 0xA2CB1717B52481ED'u, lo: 0x54768C4B0C64CA6F'u), - uint64x2(hi: 0xCB7DDCDDA26DA268'u, lo: 0xA9942F5DCF7DFD0A'u), - uint64x2(hi: 0xFE5D54150B090B02'u, lo: 0xD3F93B35435D7C4D'u), - uint64x2(hi: 0x9EFA548D26E5A6E1'u, lo: 0xC47BC5014A1A6DB0'u), - uint64x2(hi: 0xC6B8E9B0709F109A'u, lo: 0x359AB6419CA1091C'u), - uint64x2(hi: 0xF867241C8CC6D4C0'u, lo: 0xC30163D203C94B63'u), - uint64x2(hi: 0x9B407691D7FC44F8'u, lo: 0x79E0DE63425DCF1E'u), - uint64x2(hi: 0xC21094364DFB5636'u, lo: 0x985915FC12F542E5'u), - uint64x2(hi: 0xF294B943E17A2BC4'u, lo: 0x3E6F5B7B17B2939E'u), - uint64x2(hi: 0x979CF3CA6CEC5B5A'u, lo: 0xA705992CEECF9C43'u), - uint64x2(hi: 0xBD8430BD08277231'u, lo: 0x50C6FF782A838354'u), - uint64x2(hi: 0xECE53CEC4A314EBD'u, lo: 0xA4F8BF5635246429'u), - uint64x2(hi: 0x940F4613AE5ED136'u, lo: 0x871B7795E136BE9A'u), - uint64x2(hi: 0xB913179899F68584'u, lo: 0x28E2557B59846E40'u), - uint64x2(hi: 0xE757DD7EC07426E5'u, lo: 0x331AEADA2FE589D0'u), - uint64x2(hi: 0x9096EA6F3848984F'u, lo: 0x3FF0D2C85DEF7622'u), - uint64x2(hi: 0xB4BCA50B065ABE63'u, lo: 0x0FED077A756B53AA'u), - uint64x2(hi: 0xE1EBCE4DC7F16DFB'u, lo: 0xD3E8495912C62895'u), - uint64x2(hi: 0x8D3360F09CF6E4BD'u, lo: 0x64712DD7ABBBD95D'u), - uint64x2(hi: 0xB080392CC4349DEC'u, lo: 0xBD8D794D96AACFB4'u), - uint64x2(hi: 0xDCA04777F541C567'u, lo: 0xECF0D7A0FC5583A1'u), - uint64x2(hi: 0x89E42CAAF9491B60'u, lo: 0xF41686C49DB57245'u), - uint64x2(hi: 0xAC5D37D5B79B6239'u, lo: 0x311C2875C522CED6'u), - uint64x2(hi: 0xD77485CB25823AC7'u, lo: 0x7D633293366B828C'u), - uint64x2(hi: 0x86A8D39EF77164BC'u, lo: 0xAE5DFF9C02033198'u), - uint64x2(hi: 0xA8530886B54DBDEB'u, lo: 0xD9F57F830283FDFD'u), - uint64x2(hi: 0xD267CAA862A12D66'u, lo: 0xD072DF63C324FD7C'u), - uint64x2(hi: 0x8380DEA93DA4BC60'u, lo: 0x4247CB9E59F71E6E'u), - uint64x2(hi: 0xA46116538D0DEB78'u, lo: 0x52D9BE85F074E609'u), - uint64x2(hi: 0xCD795BE870516656'u, lo: 0x67902E276C921F8C'u), - uint64x2(hi: 0x806BD9714632DFF6'u, lo: 0x00BA1CD8A3DB53B7'u), - uint64x2(hi: 0xA086CFCD97BF97F3'u, lo: 0x80E8A40ECCD228A5'u), - uint64x2(hi: 0xC8A883C0FDAF7DF0'u, lo: 0x6122CD128006B2CE'u), - uint64x2(hi: 0xFAD2A4B13D1B5D6C'u, lo: 0x796B805720085F82'u), - uint64x2(hi: 0x9CC3A6EEC6311A63'u, lo: 0xCBE3303674053BB1'u), - uint64x2(hi: 0xC3F490AA77BD60FC'u, lo: 0xBEDBFC4411068A9D'u), - uint64x2(hi: 0xF4F1B4D515ACB93B'u, lo: 0xEE92FB5515482D45'u), - uint64x2(hi: 0x991711052D8BF3C5'u, lo: 0x751BDD152D4D1C4B'u), - uint64x2(hi: 0xBF5CD54678EEF0B6'u, lo: 0xD262D45A78A0635E'u), - uint64x2(hi: 0xEF340A98172AACE4'u, lo: 0x86FB897116C87C35'u), - uint64x2(hi: 0x9580869F0E7AAC0E'u, lo: 0xD45D35E6AE3D4DA1'u), - uint64x2(hi: 0xBAE0A846D2195712'u, lo: 0x8974836059CCA10A'u), - uint64x2(hi: 0xE998D258869FACD7'u, lo: 0x2BD1A438703FC94C'u), - uint64x2(hi: 0x91FF83775423CC06'u, lo: 0x7B6306A34627DDD0'u), - uint64x2(hi: 0xB67F6455292CBF08'u, lo: 0x1A3BC84C17B1D543'u), - uint64x2(hi: 0xE41F3D6A7377EECA'u, lo: 0x20CABA5F1D9E4A94'u), - uint64x2(hi: 0x8E938662882AF53E'u, lo: 0x547EB47B7282EE9D'u), - uint64x2(hi: 0xB23867FB2A35B28D'u, lo: 0xE99E619A4F23AA44'u), - uint64x2(hi: 0xDEC681F9F4C31F31'u, lo: 0x6405FA00E2EC94D5'u), - uint64x2(hi: 0x8B3C113C38F9F37E'u, lo: 0xDE83BC408DD3DD05'u), - uint64x2(hi: 0xAE0B158B4738705E'u, lo: 0x9624AB50B148D446'u), - uint64x2(hi: 0xD98DDAEE19068C76'u, lo: 0x3BADD624DD9B0958'u), - uint64x2(hi: 0x87F8A8D4CFA417C9'u, lo: 0xE54CA5D70A80E5D7'u), - uint64x2(hi: 0xA9F6D30A038D1DBC'u, lo: 0x5E9FCF4CCD211F4D'u), - uint64x2(hi: 0xD47487CC8470652B'u, lo: 0x7647C32000696720'u), - uint64x2(hi: 0x84C8D4DFD2C63F3B'u, lo: 0x29ECD9F40041E074'u), - uint64x2(hi: 0xA5FB0A17C777CF09'u, lo: 0xF468107100525891'u), - uint64x2(hi: 0xCF79CC9DB955C2CC'u, lo: 0x7182148D4066EEB5'u), - uint64x2(hi: 0x81AC1FE293D599BF'u, lo: 0xC6F14CD848405531'u), - uint64x2(hi: 0xA21727DB38CB002F'u, lo: 0xB8ADA00E5A506A7D'u), - uint64x2(hi: 0xCA9CF1D206FDC03B'u, lo: 0xA6D90811F0E4851D'u), - uint64x2(hi: 0xFD442E4688BD304A'u, lo: 0x908F4A166D1DA664'u), - uint64x2(hi: 0x9E4A9CEC15763E2E'u, lo: 0x9A598E4E043287FF'u), - uint64x2(hi: 0xC5DD44271AD3CDBA'u, lo: 0x40EFF1E1853F29FE'u), - uint64x2(hi: 0xF7549530E188C128'u, lo: 0xD12BEE59E68EF47D'u), - uint64x2(hi: 0x9A94DD3E8CF578B9'u, lo: 0x82BB74F8301958CF'u), - uint64x2(hi: 0xC13A148E3032D6E7'u, lo: 0xE36A52363C1FAF02'u), - uint64x2(hi: 0xF18899B1BC3F8CA1'u, lo: 0xDC44E6C3CB279AC2'u), - uint64x2(hi: 0x96F5600F15A7B7E5'u, lo: 0x29AB103A5EF8C0BA'u), - uint64x2(hi: 0xBCB2B812DB11A5DE'u, lo: 0x7415D448F6B6F0E8'u), - uint64x2(hi: 0xEBDF661791D60F56'u, lo: 0x111B495B3464AD22'u), - uint64x2(hi: 0x936B9FCEBB25C995'u, lo: 0xCAB10DD900BEEC35'u), - uint64x2(hi: 0xB84687C269EF3BFB'u, lo: 0x3D5D514F40EEA743'u), - uint64x2(hi: 0xE65829B3046B0AFA'u, lo: 0x0CB4A5A3112A5113'u), - uint64x2(hi: 0x8FF71A0FE2C2E6DC'u, lo: 0x47F0E785EABA72AC'u), - uint64x2(hi: 0xB3F4E093DB73A093'u, lo: 0x59ED216765690F57'u), - uint64x2(hi: 0xE0F218B8D25088B8'u, lo: 0x306869C13EC3532D'u), - uint64x2(hi: 0x8C974F7383725573'u, lo: 0x1E414218C73A13FC'u), - uint64x2(hi: 0xAFBD2350644EEACF'u, lo: 0xE5D1929EF90898FB'u), - uint64x2(hi: 0xDBAC6C247D62A583'u, lo: 0xDF45F746B74ABF3A'u), - uint64x2(hi: 0x894BC396CE5DA772'u, lo: 0x6B8BBA8C328EB784'u), - uint64x2(hi: 0xAB9EB47C81F5114F'u, lo: 0x066EA92F3F326565'u), - uint64x2(hi: 0xD686619BA27255A2'u, lo: 0xC80A537B0EFEFEBE'u), - uint64x2(hi: 0x8613FD0145877585'u, lo: 0xBD06742CE95F5F37'u), - uint64x2(hi: 0xA798FC4196E952E7'u, lo: 0x2C48113823B73705'u), - uint64x2(hi: 0xD17F3B51FCA3A7A0'u, lo: 0xF75A15862CA504C6'u), - uint64x2(hi: 0x82EF85133DE648C4'u, lo: 0x9A984D73DBE722FC'u), - uint64x2(hi: 0xA3AB66580D5FDAF5'u, lo: 0xC13E60D0D2E0EBBB'u), - uint64x2(hi: 0xCC963FEE10B7D1B3'u, lo: 0x318DF905079926A9'u), - uint64x2(hi: 0xFFBBCFE994E5C61F'u, lo: 0xFDF17746497F7053'u), - uint64x2(hi: 0x9FD561F1FD0F9BD3'u, lo: 0xFEB6EA8BEDEFA634'u), - uint64x2(hi: 0xC7CABA6E7C5382C8'u, lo: 0xFE64A52EE96B8FC1'u), - uint64x2(hi: 0xF9BD690A1B68637B'u, lo: 0x3DFDCE7AA3C673B1'u), - uint64x2(hi: 0x9C1661A651213E2D'u, lo: 0x06BEA10CA65C084F'u), - uint64x2(hi: 0xC31BFA0FE5698DB8'u, lo: 0x486E494FCFF30A63'u), - uint64x2(hi: 0xF3E2F893DEC3F126'u, lo: 0x5A89DBA3C3EFCCFB'u), - uint64x2(hi: 0x986DDB5C6B3A76B7'u, lo: 0xF89629465A75E01D'u), - uint64x2(hi: 0xBE89523386091465'u, lo: 0xF6BBB397F1135824'u), - uint64x2(hi: 0xEE2BA6C0678B597F'u, lo: 0x746AA07DED582E2D'u), - uint64x2(hi: 0x94DB483840B717EF'u, lo: 0xA8C2A44EB4571CDD'u), - uint64x2(hi: 0xBA121A4650E4DDEB'u, lo: 0x92F34D62616CE414'u), - uint64x2(hi: 0xE896A0D7E51E1566'u, lo: 0x77B020BAF9C81D18'u), - uint64x2(hi: 0x915E2486EF32CD60'u, lo: 0x0ACE1474DC1D122F'u), - uint64x2(hi: 0xB5B5ADA8AAFF80B8'u, lo: 0x0D819992132456BB'u), - uint64x2(hi: 0xE3231912D5BF60E6'u, lo: 0x10E1FFF697ED6C6A'u), - uint64x2(hi: 0x8DF5EFABC5979C8F'u, lo: 0xCA8D3FFA1EF463C2'u), - uint64x2(hi: 0xB1736B96B6FD83B3'u, lo: 0xBD308FF8A6B17CB3'u), - uint64x2(hi: 0xDDD0467C64BCE4A0'u, lo: 0xAC7CB3F6D05DDBDF'u), - uint64x2(hi: 0x8AA22C0DBEF60EE4'u, lo: 0x6BCDF07A423AA96C'u), - uint64x2(hi: 0xAD4AB7112EB3929D'u, lo: 0x86C16C98D2C953C7'u), - uint64x2(hi: 0xD89D64D57A607744'u, lo: 0xE871C7BF077BA8B8'u), - uint64x2(hi: 0x87625F056C7C4A8B'u, lo: 0x11471CD764AD4973'u), - uint64x2(hi: 0xA93AF6C6C79B5D2D'u, lo: 0xD598E40D3DD89BD0'u), - uint64x2(hi: 0xD389B47879823479'u, lo: 0x4AFF1D108D4EC2C4'u), - uint64x2(hi: 0x843610CB4BF160CB'u, lo: 0xCEDF722A585139BB'u), - uint64x2(hi: 0xA54394FE1EEDB8FE'u, lo: 0xC2974EB4EE658829'u), - uint64x2(hi: 0xCE947A3DA6A9273E'u, lo: 0x733D226229FEEA33'u), - uint64x2(hi: 0x811CCC668829B887'u, lo: 0x0806357D5A3F5260'u), - uint64x2(hi: 0xA163FF802A3426A8'u, lo: 0xCA07C2DCB0CF26F8'u), - uint64x2(hi: 0xC9BCFF6034C13052'u, lo: 0xFC89B393DD02F0B6'u), - uint64x2(hi: 0xFC2C3F3841F17C67'u, lo: 0xBBAC2078D443ACE3'u), - uint64x2(hi: 0x9D9BA7832936EDC0'u, lo: 0xD54B944B84AA4C0E'u), - uint64x2(hi: 0xC5029163F384A931'u, lo: 0x0A9E795E65D4DF12'u), - uint64x2(hi: 0xF64335BCF065D37D'u, lo: 0x4D4617B5FF4A16D6'u), - uint64x2(hi: 0x99EA0196163FA42E'u, lo: 0x504BCED1BF8E4E46'u), - uint64x2(hi: 0xC06481FB9BCF8D39'u, lo: 0xE45EC2862F71E1D7'u), - uint64x2(hi: 0xF07DA27A82C37088'u, lo: 0x5D767327BB4E5A4D'u), - uint64x2(hi: 0x964E858C91BA2655'u, lo: 0x3A6A07F8D510F870'u), - uint64x2(hi: 0xBBE226EFB628AFEA'u, lo: 0x890489F70A55368C'u), - uint64x2(hi: 0xEADAB0ABA3B2DBE5'u, lo: 0x2B45AC74CCEA842F'u), - uint64x2(hi: 0x92C8AE6B464FC96F'u, lo: 0x3B0B8BC90012929E'u), - uint64x2(hi: 0xB77ADA0617E3BBCB'u, lo: 0x09CE6EBB40173745'u), - uint64x2(hi: 0xE55990879DDCAABD'u, lo: 0xCC420A6A101D0516'u), - uint64x2(hi: 0x8F57FA54C2A9EAB6'u, lo: 0x9FA946824A12232E'u), - uint64x2(hi: 0xB32DF8E9F3546564'u, lo: 0x47939822DC96ABFA'u), - uint64x2(hi: 0xDFF9772470297EBD'u, lo: 0x59787E2B93BC56F8'u), - uint64x2(hi: 0x8BFBEA76C619EF36'u, lo: 0x57EB4EDB3C55B65B'u), - uint64x2(hi: 0xAEFAE51477A06B03'u, lo: 0xEDE622920B6B23F2'u), - uint64x2(hi: 0xDAB99E59958885C4'u, lo: 0xE95FAB368E45ECEE'u), - uint64x2(hi: 0x88B402F7FD75539B'u, lo: 0x11DBCB0218EBB415'u), - uint64x2(hi: 0xAAE103B5FCD2A881'u, lo: 0xD652BDC29F26A11A'u), - uint64x2(hi: 0xD59944A37C0752A2'u, lo: 0x4BE76D3346F04960'u), - uint64x2(hi: 0x857FCAE62D8493A5'u, lo: 0x6F70A4400C562DDC'u), - uint64x2(hi: 0xA6DFBD9FB8E5B88E'u, lo: 0xCB4CCD500F6BB953'u), - uint64x2(hi: 0xD097AD07A71F26B2'u, lo: 0x7E2000A41346A7A8'u), - uint64x2(hi: 0x825ECC24C873782F'u, lo: 0x8ED400668C0C28C9'u), - uint64x2(hi: 0xA2F67F2DFA90563B'u, lo: 0x728900802F0F32FB'u), - uint64x2(hi: 0xCBB41EF979346BCA'u, lo: 0x4F2B40A03AD2FFBA'u), - uint64x2(hi: 0xFEA126B7D78186BC'u, lo: 0xE2F610C84987BFA9'u), - uint64x2(hi: 0x9F24B832E6B0F436'u, lo: 0x0DD9CA7D2DF4D7CA'u), - uint64x2(hi: 0xC6EDE63FA05D3143'u, lo: 0x91503D1C79720DBC'u), - uint64x2(hi: 0xF8A95FCF88747D94'u, lo: 0x75A44C6397CE912B'u), - uint64x2(hi: 0x9B69DBE1B548CE7C'u, lo: 0xC986AFBE3EE11ABB'u), - uint64x2(hi: 0xC24452DA229B021B'u, lo: 0xFBE85BADCE996169'u), - uint64x2(hi: 0xF2D56790AB41C2A2'u, lo: 0xFAE27299423FB9C4'u), - uint64x2(hi: 0x97C560BA6B0919A5'u, lo: 0xDCCD879FC967D41B'u), - uint64x2(hi: 0xBDB6B8E905CB600F'u, lo: 0x5400E987BBC1C921'u), - uint64x2(hi: 0xED246723473E3813'u, lo: 0x290123E9AAB23B69'u), - uint64x2(hi: 0x9436C0760C86E30B'u, lo: 0xF9A0B6720AAF6522'u), - uint64x2(hi: 0xB94470938FA89BCE'u, lo: 0xF808E40E8D5B3E6A'u), - uint64x2(hi: 0xE7958CB87392C2C2'u, lo: 0xB60B1D1230B20E05'u), - uint64x2(hi: 0x90BD77F3483BB9B9'u, lo: 0xB1C6F22B5E6F48C3'u), - uint64x2(hi: 0xB4ECD5F01A4AA828'u, lo: 0x1E38AEB6360B1AF4'u), - uint64x2(hi: 0xE2280B6C20DD5232'u, lo: 0x25C6DA63C38DE1B1'u), - uint64x2(hi: 0x8D590723948A535F'u, lo: 0x579C487E5A38AD0F'u), - uint64x2(hi: 0xB0AF48EC79ACE837'u, lo: 0x2D835A9DF0C6D852'u), - uint64x2(hi: 0xDCDB1B2798182244'u, lo: 0xF8E431456CF88E66'u), - uint64x2(hi: 0x8A08F0F8BF0F156B'u, lo: 0x1B8E9ECB641B5900'u), - uint64x2(hi: 0xAC8B2D36EED2DAC5'u, lo: 0xE272467E3D222F40'u), - uint64x2(hi: 0xD7ADF884AA879177'u, lo: 0x5B0ED81DCC6ABB10'u), - uint64x2(hi: 0x86CCBB52EA94BAEA'u, lo: 0x98E947129FC2B4EA'u), - uint64x2(hi: 0xA87FEA27A539E9A5'u, lo: 0x3F2398D747B36225'u), - uint64x2(hi: 0xD29FE4B18E88640E'u, lo: 0x8EEC7F0D19A03AAE'u), - uint64x2(hi: 0x83A3EEEEF9153E89'u, lo: 0x1953CF68300424AD'u), - uint64x2(hi: 0xA48CEAAAB75A8E2B'u, lo: 0x5FA8C3423C052DD8'u), - uint64x2(hi: 0xCDB02555653131B6'u, lo: 0x3792F412CB06794E'u), - uint64x2(hi: 0x808E17555F3EBF11'u, lo: 0xE2BBD88BBEE40BD1'u), - uint64x2(hi: 0xA0B19D2AB70E6ED6'u, lo: 0x5B6ACEAEAE9D0EC5'u), - uint64x2(hi: 0xC8DE047564D20A8B'u, lo: 0xF245825A5A445276'u), - uint64x2(hi: 0xFB158592BE068D2E'u, lo: 0xEED6E2F0F0D56713'u), - uint64x2(hi: 0x9CED737BB6C4183D'u, lo: 0x55464DD69685606C'u), - uint64x2(hi: 0xC428D05AA4751E4C'u, lo: 0xAA97E14C3C26B887'u), - uint64x2(hi: 0xF53304714D9265DF'u, lo: 0xD53DD99F4B3066A9'u), - uint64x2(hi: 0x993FE2C6D07B7FAB'u, lo: 0xE546A8038EFE402A'u), - uint64x2(hi: 0xBF8FDB78849A5F96'u, lo: 0xDE98520472BDD034'u), - uint64x2(hi: 0xEF73D256A5C0F77C'u, lo: 0x963E66858F6D4441'u), - uint64x2(hi: 0x95A8637627989AAD'u, lo: 0xDDE7001379A44AA9'u), - uint64x2(hi: 0xBB127C53B17EC159'u, lo: 0x5560C018580D5D53'u), - uint64x2(hi: 0xE9D71B689DDE71AF'u, lo: 0xAAB8F01E6E10B4A7'u), - uint64x2(hi: 0x9226712162AB070D'u, lo: 0xCAB3961304CA70E9'u), - uint64x2(hi: 0xB6B00D69BB55C8D1'u, lo: 0x3D607B97C5FD0D23'u), - uint64x2(hi: 0xE45C10C42A2B3B05'u, lo: 0x8CB89A7DB77C506B'u), - uint64x2(hi: 0x8EB98A7A9A5B04E3'u, lo: 0x77F3608E92ADB243'u), - uint64x2(hi: 0xB267ED1940F1C61C'u, lo: 0x55F038B237591ED4'u), - uint64x2(hi: 0xDF01E85F912E37A3'u, lo: 0x6B6C46DEC52F6689'u), - uint64x2(hi: 0x8B61313BBABCE2C6'u, lo: 0x2323AC4B3B3DA016'u), - uint64x2(hi: 0xAE397D8AA96C1B77'u, lo: 0xABEC975E0A0D081B'u), - uint64x2(hi: 0xD9C7DCED53C72255'u, lo: 0x96E7BD358C904A22'u), - uint64x2(hi: 0x881CEA14545C7575'u, lo: 0x7E50D64177DA2E55'u), - uint64x2(hi: 0xAA242499697392D2'u, lo: 0xDDE50BD1D5D0B9EA'u), - uint64x2(hi: 0xD4AD2DBFC3D07787'u, lo: 0x955E4EC64B44E865'u), - uint64x2(hi: 0x84EC3C97DA624AB4'u, lo: 0xBD5AF13BEF0B113F'u), - uint64x2(hi: 0xA6274BBDD0FADD61'u, lo: 0xECB1AD8AEACDD58F'u), - uint64x2(hi: 0xCFB11EAD453994BA'u, lo: 0x67DE18EDA5814AF3'u), - uint64x2(hi: 0x81CEB32C4B43FCF4'u, lo: 0x80EACF948770CED8'u), - uint64x2(hi: 0xA2425FF75E14FC31'u, lo: 0xA1258379A94D028E'u), - uint64x2(hi: 0xCAD2F7F5359A3B3E'u, lo: 0x096EE45813A04331'u), - uint64x2(hi: 0xFD87B5F28300CA0D'u, lo: 0x8BCA9D6E188853FD'u), - uint64x2(hi: 0x9E74D1B791E07E48'u, lo: 0x775EA264CF55347E'u), - uint64x2(hi: 0xC612062576589DDA'u, lo: 0x95364AFE032A819E'u), - uint64x2(hi: 0xF79687AED3EEC551'u, lo: 0x3A83DDBD83F52205'u), - uint64x2(hi: 0x9ABE14CD44753B52'u, lo: 0xC4926A9672793543'u), - uint64x2(hi: 0xC16D9A0095928A27'u, lo: 0x75B7053C0F178294'u), - uint64x2(hi: 0xF1C90080BAF72CB1'u, lo: 0x5324C68B12DD6339'u), - uint64x2(hi: 0x971DA05074DA7BEE'u, lo: 0xD3F6FC16EBCA5E04'u), - uint64x2(hi: 0xBCE5086492111AEA'u, lo: 0x88F4BB1CA6BCF585'u), - uint64x2(hi: 0xEC1E4A7DB69561A5'u, lo: 0x2B31E9E3D06C32E6'u), - uint64x2(hi: 0x9392EE8E921D5D07'u, lo: 0x3AFF322E62439FD0'u), - uint64x2(hi: 0xB877AA3236A4B449'u, lo: 0x09BEFEB9FAD487C3'u), - uint64x2(hi: 0xE69594BEC44DE15B'u, lo: 0x4C2EBE687989A9B4'u), - uint64x2(hi: 0x901D7CF73AB0ACD9'u, lo: 0x0F9D37014BF60A11'u), - uint64x2(hi: 0xB424DC35095CD80F'u, lo: 0x538484C19EF38C95'u), - uint64x2(hi: 0xE12E13424BB40E13'u, lo: 0x2865A5F206B06FBA'u), - uint64x2(hi: 0x8CBCCC096F5088CB'u, lo: 0xF93F87B7442E45D4'u), - uint64x2(hi: 0xAFEBFF0BCB24AAFE'u, lo: 0xF78F69A51539D749'u), - uint64x2(hi: 0xDBE6FECEBDEDD5BE'u, lo: 0xB573440E5A884D1C'u), - uint64x2(hi: 0x89705F4136B4A597'u, lo: 0x31680A88F8953031'u), - uint64x2(hi: 0xABCC77118461CEFC'u, lo: 0xFDC20D2B36BA7C3E'u), - uint64x2(hi: 0xD6BF94D5E57A42BC'u, lo: 0x3D32907604691B4D'u), - uint64x2(hi: 0x8637BD05AF6C69B5'u, lo: 0xA63F9A49C2C1B110'u), - uint64x2(hi: 0xA7C5AC471B478423'u, lo: 0x0FCF80DC33721D54'u), - uint64x2(hi: 0xD1B71758E219652B'u, lo: 0xD3C36113404EA4A9'u), - uint64x2(hi: 0x83126E978D4FDF3B'u, lo: 0x645A1CAC083126EA'u), - uint64x2(hi: 0xA3D70A3D70A3D70A'u, lo: 0x3D70A3D70A3D70A4'u), - uint64x2(hi: 0xCCCCCCCCCCCCCCCC'u, lo: 0xCCCCCCCCCCCCCCCD'u), - uint64x2(hi: 0x8000000000000000'u, lo: 0x0000000000000000'u), - uint64x2(hi: 0xA000000000000000'u, lo: 0x0000000000000000'u), - uint64x2(hi: 0xC800000000000000'u, lo: 0x0000000000000000'u), - uint64x2(hi: 0xFA00000000000000'u, lo: 0x0000000000000000'u), - uint64x2(hi: 0x9C40000000000000'u, lo: 0x0000000000000000'u), - uint64x2(hi: 0xC350000000000000'u, lo: 0x0000000000000000'u), - uint64x2(hi: 0xF424000000000000'u, lo: 0x0000000000000000'u), - uint64x2(hi: 0x9896800000000000'u, lo: 0x0000000000000000'u), - uint64x2(hi: 0xBEBC200000000000'u, lo: 0x0000000000000000'u), - uint64x2(hi: 0xEE6B280000000000'u, lo: 0x0000000000000000'u), - uint64x2(hi: 0x9502F90000000000'u, lo: 0x0000000000000000'u), - uint64x2(hi: 0xBA43B74000000000'u, lo: 0x0000000000000000'u), - uint64x2(hi: 0xE8D4A51000000000'u, lo: 0x0000000000000000'u), - uint64x2(hi: 0x9184E72A00000000'u, lo: 0x0000000000000000'u), - uint64x2(hi: 0xB5E620F480000000'u, lo: 0x0000000000000000'u), - uint64x2(hi: 0xE35FA931A0000000'u, lo: 0x0000000000000000'u), - uint64x2(hi: 0x8E1BC9BF04000000'u, lo: 0x0000000000000000'u), - uint64x2(hi: 0xB1A2BC2EC5000000'u, lo: 0x0000000000000000'u), - uint64x2(hi: 0xDE0B6B3A76400000'u, lo: 0x0000000000000000'u), - uint64x2(hi: 0x8AC7230489E80000'u, lo: 0x0000000000000000'u), - uint64x2(hi: 0xAD78EBC5AC620000'u, lo: 0x0000000000000000'u), - uint64x2(hi: 0xD8D726B7177A8000'u, lo: 0x0000000000000000'u), - uint64x2(hi: 0x878678326EAC9000'u, lo: 0x0000000000000000'u), - uint64x2(hi: 0xA968163F0A57B400'u, lo: 0x0000000000000000'u), - uint64x2(hi: 0xD3C21BCECCEDA100'u, lo: 0x0000000000000000'u), - uint64x2(hi: 0x84595161401484A0'u, lo: 0x0000000000000000'u), - uint64x2(hi: 0xA56FA5B99019A5C8'u, lo: 0x0000000000000000'u), - uint64x2(hi: 0xCECB8F27F4200F3A'u, lo: 0x0000000000000000'u), - uint64x2(hi: 0x813F3978F8940984'u, lo: 0x4000000000000000'u), - uint64x2(hi: 0xA18F07D736B90BE5'u, lo: 0x5000000000000000'u), - uint64x2(hi: 0xC9F2C9CD04674EDE'u, lo: 0xA400000000000000'u), - uint64x2(hi: 0xFC6F7C4045812296'u, lo: 0x4D00000000000000'u), - uint64x2(hi: 0x9DC5ADA82B70B59D'u, lo: 0xF020000000000000'u), - uint64x2(hi: 0xC5371912364CE305'u, lo: 0x6C28000000000000'u), - uint64x2(hi: 0xF684DF56C3E01BC6'u, lo: 0xC732000000000000'u), - uint64x2(hi: 0x9A130B963A6C115C'u, lo: 0x3C7F400000000000'u), - uint64x2(hi: 0xC097CE7BC90715B3'u, lo: 0x4B9F100000000000'u), - uint64x2(hi: 0xF0BDC21ABB48DB20'u, lo: 0x1E86D40000000000'u), - uint64x2(hi: 0x96769950B50D88F4'u, lo: 0x1314448000000000'u), - uint64x2(hi: 0xBC143FA4E250EB31'u, lo: 0x17D955A000000000'u), - uint64x2(hi: 0xEB194F8E1AE525FD'u, lo: 0x5DCFAB0800000000'u), - uint64x2(hi: 0x92EFD1B8D0CF37BE'u, lo: 0x5AA1CAE500000000'u), - uint64x2(hi: 0xB7ABC627050305AD'u, lo: 0xF14A3D9E40000000'u), - uint64x2(hi: 0xE596B7B0C643C719'u, lo: 0x6D9CCD05D0000000'u), - uint64x2(hi: 0x8F7E32CE7BEA5C6F'u, lo: 0xE4820023A2000000'u), - uint64x2(hi: 0xB35DBF821AE4F38B'u, lo: 0xDDA2802C8A800000'u), - uint64x2(hi: 0xE0352F62A19E306E'u, lo: 0xD50B2037AD200000'u), - uint64x2(hi: 0x8C213D9DA502DE45'u, lo: 0x4526F422CC340000'u), - uint64x2(hi: 0xAF298D050E4395D6'u, lo: 0x9670B12B7F410000'u), - uint64x2(hi: 0xDAF3F04651D47B4C'u, lo: 0x3C0CDD765F114000'u), - uint64x2(hi: 0x88D8762BF324CD0F'u, lo: 0xA5880A69FB6AC800'u), - uint64x2(hi: 0xAB0E93B6EFEE0053'u, lo: 0x8EEA0D047A457A00'u), - uint64x2(hi: 0xD5D238A4ABE98068'u, lo: 0x72A4904598D6D880'u), - uint64x2(hi: 0x85A36366EB71F041'u, lo: 0x47A6DA2B7F864750'u), - uint64x2(hi: 0xA70C3C40A64E6C51'u, lo: 0x999090B65F67D924'u), - uint64x2(hi: 0xD0CF4B50CFE20765'u, lo: 0xFFF4B4E3F741CF6D'u), - uint64x2(hi: 0x82818F1281ED449F'u, lo: 0xBFF8F10E7A8921A4'u), - uint64x2(hi: 0xA321F2D7226895C7'u, lo: 0xAFF72D52192B6A0D'u), - uint64x2(hi: 0xCBEA6F8CEB02BB39'u, lo: 0x9BF4F8A69F764490'u), - uint64x2(hi: 0xFEE50B7025C36A08'u, lo: 0x02F236D04753D5B4'u), - uint64x2(hi: 0x9F4F2726179A2245'u, lo: 0x01D762422C946590'u), - uint64x2(hi: 0xC722F0EF9D80AAD6'u, lo: 0x424D3AD2B7B97EF5'u), - uint64x2(hi: 0xF8EBAD2B84E0D58B'u, lo: 0xD2E0898765A7DEB2'u), - uint64x2(hi: 0x9B934C3B330C8577'u, lo: 0x63CC55F49F88EB2F'u), - uint64x2(hi: 0xC2781F49FFCFA6D5'u, lo: 0x3CBF6B71C76B25FB'u), - uint64x2(hi: 0xF316271C7FC3908A'u, lo: 0x8BEF464E3945EF7A'u), - uint64x2(hi: 0x97EDD871CFDA3A56'u, lo: 0x97758BF0E3CBB5AC'u), - uint64x2(hi: 0xBDE94E8E43D0C8EC'u, lo: 0x3D52EEED1CBEA317'u), - uint64x2(hi: 0xED63A231D4C4FB27'u, lo: 0x4CA7AAA863EE4BDD'u), - uint64x2(hi: 0x945E455F24FB1CF8'u, lo: 0x8FE8CAA93E74EF6A'u), - uint64x2(hi: 0xB975D6B6EE39E436'u, lo: 0xB3E2FD538E122B44'u), - uint64x2(hi: 0xE7D34C64A9C85D44'u, lo: 0x60DBBCA87196B616'u), - uint64x2(hi: 0x90E40FBEEA1D3A4A'u, lo: 0xBC8955E946FE31CD'u), - uint64x2(hi: 0xB51D13AEA4A488DD'u, lo: 0x6BABAB6398BDBE41'u), - uint64x2(hi: 0xE264589A4DCDAB14'u, lo: 0xC696963C7EED2DD1'u), - uint64x2(hi: 0x8D7EB76070A08AEC'u, lo: 0xFC1E1DE5CF543CA2'u), - uint64x2(hi: 0xB0DE65388CC8ADA8'u, lo: 0x3B25A55F43294BCB'u), - uint64x2(hi: 0xDD15FE86AFFAD912'u, lo: 0x49EF0EB713F39EBE'u), - uint64x2(hi: 0x8A2DBF142DFCC7AB'u, lo: 0x6E3569326C784337'u), - uint64x2(hi: 0xACB92ED9397BF996'u, lo: 0x49C2C37F07965404'u), - uint64x2(hi: 0xD7E77A8F87DAF7FB'u, lo: 0xDC33745EC97BE906'u), - uint64x2(hi: 0x86F0AC99B4E8DAFD'u, lo: 0x69A028BB3DED71A3'u), - uint64x2(hi: 0xA8ACD7C0222311BC'u, lo: 0xC40832EA0D68CE0C'u), - uint64x2(hi: 0xD2D80DB02AABD62B'u, lo: 0xF50A3FA490C30190'u), - uint64x2(hi: 0x83C7088E1AAB65DB'u, lo: 0x792667C6DA79E0FA'u), - uint64x2(hi: 0xA4B8CAB1A1563F52'u, lo: 0x577001B891185938'u), - uint64x2(hi: 0xCDE6FD5E09ABCF26'u, lo: 0xED4C0226B55E6F86'u), - uint64x2(hi: 0x80B05E5AC60B6178'u, lo: 0x544F8158315B05B4'u), - uint64x2(hi: 0xA0DC75F1778E39D6'u, lo: 0x696361AE3DB1C721'u), - uint64x2(hi: 0xC913936DD571C84C'u, lo: 0x03BC3A19CD1E38E9'u), - uint64x2(hi: 0xFB5878494ACE3A5F'u, lo: 0x04AB48A04065C723'u), - uint64x2(hi: 0x9D174B2DCEC0E47B'u, lo: 0x62EB0D64283F9C76'u), - uint64x2(hi: 0xC45D1DF942711D9A'u, lo: 0x3BA5D0BD324F8394'u), - uint64x2(hi: 0xF5746577930D6500'u, lo: 0xCA8F44EC7EE36479'u), - uint64x2(hi: 0x9968BF6ABBE85F20'u, lo: 0x7E998B13CF4E1ECB'u), - uint64x2(hi: 0xBFC2EF456AE276E8'u, lo: 0x9E3FEDD8C321A67E'u), - uint64x2(hi: 0xEFB3AB16C59B14A2'u, lo: 0xC5CFE94EF3EA101E'u), - uint64x2(hi: 0x95D04AEE3B80ECE5'u, lo: 0xBBA1F1D158724A12'u), - uint64x2(hi: 0xBB445DA9CA61281F'u, lo: 0x2A8A6E45AE8EDC97'u), - uint64x2(hi: 0xEA1575143CF97226'u, lo: 0xF52D09D71A3293BD'u), - uint64x2(hi: 0x924D692CA61BE758'u, lo: 0x593C2626705F9C56'u), - uint64x2(hi: 0xB6E0C377CFA2E12E'u, lo: 0x6F8B2FB00C77836C'u), - uint64x2(hi: 0xE498F455C38B997A'u, lo: 0x0B6DFB9C0F956447'u), - uint64x2(hi: 0x8EDF98B59A373FEC'u, lo: 0x4724BD4189BD5EAC'u), - uint64x2(hi: 0xB2977EE300C50FE7'u, lo: 0x58EDEC91EC2CB657'u), - uint64x2(hi: 0xDF3D5E9BC0F653E1'u, lo: 0x2F2967B66737E3ED'u), - uint64x2(hi: 0x8B865B215899F46C'u, lo: 0xBD79E0D20082EE74'u), - uint64x2(hi: 0xAE67F1E9AEC07187'u, lo: 0xECD8590680A3AA11'u), - uint64x2(hi: 0xDA01EE641A708DE9'u, lo: 0xE80E6F4820CC9495'u), - uint64x2(hi: 0x884134FE908658B2'u, lo: 0x3109058D147FDCDD'u), - uint64x2(hi: 0xAA51823E34A7EEDE'u, lo: 0xBD4B46F0599FD415'u), - uint64x2(hi: 0xD4E5E2CDC1D1EA96'u, lo: 0x6C9E18AC7007C91A'u), - uint64x2(hi: 0x850FADC09923329E'u, lo: 0x03E2CF6BC604DDB0'u), - uint64x2(hi: 0xA6539930BF6BFF45'u, lo: 0x84DB8346B786151C'u), - uint64x2(hi: 0xCFE87F7CEF46FF16'u, lo: 0xE612641865679A63'u), - uint64x2(hi: 0x81F14FAE158C5F6E'u, lo: 0x4FCB7E8F3F60C07E'u), - uint64x2(hi: 0xA26DA3999AEF7749'u, lo: 0xE3BE5E330F38F09D'u), - uint64x2(hi: 0xCB090C8001AB551C'u, lo: 0x5CADF5BFD3072CC5'u), - uint64x2(hi: 0xFDCB4FA002162A63'u, lo: 0x73D9732FC7C8F7F6'u), - uint64x2(hi: 0x9E9F11C4014DDA7E'u, lo: 0x2867E7FDDCDD9AFA'u), - uint64x2(hi: 0xC646D63501A1511D'u, lo: 0xB281E1FD541501B8'u), - uint64x2(hi: 0xF7D88BC24209A565'u, lo: 0x1F225A7CA91A4226'u), - uint64x2(hi: 0x9AE757596946075F'u, lo: 0x3375788DE9B06958'u), - uint64x2(hi: 0xC1A12D2FC3978937'u, lo: 0x0052D6B1641C83AE'u), - uint64x2(hi: 0xF209787BB47D6B84'u, lo: 0xC0678C5DBD23A49A'u), - uint64x2(hi: 0x9745EB4D50CE6332'u, lo: 0xF840B7BA963646E0'u), - uint64x2(hi: 0xBD176620A501FBFF'u, lo: 0xB650E5A93BC3D898'u), - uint64x2(hi: 0xEC5D3FA8CE427AFF'u, lo: 0xA3E51F138AB4CEBE'u), - uint64x2(hi: 0x93BA47C980E98CDF'u, lo: 0xC66F336C36B10137'u), - uint64x2(hi: 0xB8A8D9BBE123F017'u, lo: 0xB80B0047445D4184'u), - uint64x2(hi: 0xE6D3102AD96CEC1D'u, lo: 0xA60DC059157491E5'u), - uint64x2(hi: 0x9043EA1AC7E41392'u, lo: 0x87C89837AD68DB2F'u), - uint64x2(hi: 0xB454E4A179DD1877'u, lo: 0x29BABE4598C311FB'u), - uint64x2(hi: 0xE16A1DC9D8545E94'u, lo: 0xF4296DD6FEF3D67A'u), - uint64x2(hi: 0x8CE2529E2734BB1D'u, lo: 0x1899E4A65F58660C'u), - uint64x2(hi: 0xB01AE745B101E9E4'u, lo: 0x5EC05DCFF72E7F8F'u), - uint64x2(hi: 0xDC21A1171D42645D'u, lo: 0x76707543F4FA1F73'u), - uint64x2(hi: 0x899504AE72497EBA'u, lo: 0x6A06494A791C53A8'u), - uint64x2(hi: 0xABFA45DA0EDBDE69'u, lo: 0x0487DB9D17636892'u), - uint64x2(hi: 0xD6F8D7509292D603'u, lo: 0x45A9D2845D3C42B6'u), - uint64x2(hi: 0x865B86925B9BC5C2'u, lo: 0x0B8A2392BA45A9B2'u), - uint64x2(hi: 0xA7F26836F282B732'u, lo: 0x8E6CAC7768D7141E'u), - uint64x2(hi: 0xD1EF0244AF2364FF'u, lo: 0x3207D795430CD926'u), - uint64x2(hi: 0x8335616AED761F1F'u, lo: 0x7F44E6BD49E807B8'u), - uint64x2(hi: 0xA402B9C5A8D3A6E7'u, lo: 0x5F16206C9C6209A6'u), - uint64x2(hi: 0xCD036837130890A1'u, lo: 0x36DBA887C37A8C0F'u), - uint64x2(hi: 0x802221226BE55A64'u, lo: 0xC2494954DA2C9789'u), - uint64x2(hi: 0xA02AA96B06DEB0FD'u, lo: 0xF2DB9BAA10B7BD6C'u), - uint64x2(hi: 0xC83553C5C8965D3D'u, lo: 0x6F92829494E5ACC7'u), - uint64x2(hi: 0xFA42A8B73ABBF48C'u, lo: 0xCB772339BA1F17F9'u), - uint64x2(hi: 0x9C69A97284B578D7'u, lo: 0xFF2A760414536EFB'u), - uint64x2(hi: 0xC38413CF25E2D70D'u, lo: 0xFEF5138519684ABA'u), - uint64x2(hi: 0xF46518C2EF5B8CD1'u, lo: 0x7EB258665FC25D69'u), - uint64x2(hi: 0x98BF2F79D5993802'u, lo: 0xEF2F773FFBD97A61'u), - uint64x2(hi: 0xBEEEFB584AFF8603'u, lo: 0xAAFB550FFACFD8FA'u), - uint64x2(hi: 0xEEAABA2E5DBF6784'u, lo: 0x95BA2A53F983CF38'u), - uint64x2(hi: 0x952AB45CFA97A0B2'u, lo: 0xDD945A747BF26183'u), - uint64x2(hi: 0xBA756174393D88DF'u, lo: 0x94F971119AEEF9E4'u), - uint64x2(hi: 0xE912B9D1478CEB17'u, lo: 0x7A37CD5601AAB85D'u), - uint64x2(hi: 0x91ABB422CCB812EE'u, lo: 0xAC62E055C10AB33A'u), - uint64x2(hi: 0xB616A12B7FE617AA'u, lo: 0x577B986B314D6009'u), - uint64x2(hi: 0xE39C49765FDF9D94'u, lo: 0xED5A7E85FDA0B80B'u), - uint64x2(hi: 0x8E41ADE9FBEBC27D'u, lo: 0x14588F13BE847307'u), - uint64x2(hi: 0xB1D219647AE6B31C'u, lo: 0x596EB2D8AE258FC8'u), - uint64x2(hi: 0xDE469FBD99A05FE3'u, lo: 0x6FCA5F8ED9AEF3BB'u), - uint64x2(hi: 0x8AEC23D680043BEE'u, lo: 0x25DE7BB9480D5854'u), - uint64x2(hi: 0xADA72CCC20054AE9'u, lo: 0xAF561AA79A10AE6A'u), - uint64x2(hi: 0xD910F7FF28069DA4'u, lo: 0x1B2BA1518094DA04'u), - uint64x2(hi: 0x87AA9AFF79042286'u, lo: 0x90FB44D2F05D0842'u), - uint64x2(hi: 0xA99541BF57452B28'u, lo: 0x353A1607AC744A53'u), - uint64x2(hi: 0xD3FA922F2D1675F2'u, lo: 0x42889B8997915CE8'u), - uint64x2(hi: 0x847C9B5D7C2E09B7'u, lo: 0x69956135FEBADA11'u), - uint64x2(hi: 0xA59BC234DB398C25'u, lo: 0x43FAB9837E699095'u), - uint64x2(hi: 0xCF02B2C21207EF2E'u, lo: 0x94F967E45E03F4BB'u), - uint64x2(hi: 0x8161AFB94B44F57D'u, lo: 0x1D1BE0EEBAC278F5'u), - uint64x2(hi: 0xA1BA1BA79E1632DC'u, lo: 0x6462D92A69731732'u), - uint64x2(hi: 0xCA28A291859BBF93'u, lo: 0x7D7B8F7503CFDCFE'u), - uint64x2(hi: 0xFCB2CB35E702AF78'u, lo: 0x5CDA735244C3D43E'u), - uint64x2(hi: 0x9DEFBF01B061ADAB'u, lo: 0x3A0888136AFA64A7'u), - uint64x2(hi: 0xC56BAEC21C7A1916'u, lo: 0x088AAA1845B8FDD0'u), - uint64x2(hi: 0xF6C69A72A3989F5B'u, lo: 0x8AAD549E57273D45'u), - uint64x2(hi: 0x9A3C2087A63F6399'u, lo: 0x36AC54E2F678864B'u), - uint64x2(hi: 0xC0CB28A98FCF3C7F'u, lo: 0x84576A1BB416A7DD'u), - uint64x2(hi: 0xF0FDF2D3F3C30B9F'u, lo: 0x656D44A2A11C51D5'u), - uint64x2(hi: 0x969EB7C47859E743'u, lo: 0x9F644AE5A4B1B325'u), - uint64x2(hi: 0xBC4665B596706114'u, lo: 0x873D5D9F0DDE1FEE'u), - uint64x2(hi: 0xEB57FF22FC0C7959'u, lo: 0xA90CB506D155A7EA'u), - uint64x2(hi: 0x9316FF75DD87CBD8'u, lo: 0x09A7F12442D588F2'u), - uint64x2(hi: 0xB7DCBF5354E9BECE'u, lo: 0x0C11ED6D538AEB2F'u), - uint64x2(hi: 0xE5D3EF282A242E81'u, lo: 0x8F1668C8A86DA5FA'u), - uint64x2(hi: 0x8FA475791A569D10'u, lo: 0xF96E017D694487BC'u), - uint64x2(hi: 0xB38D92D760EC4455'u, lo: 0x37C981DCC395A9AC'u), - uint64x2(hi: 0xE070F78D3927556A'u, lo: 0x85BBE253F47B1417'u), - uint64x2(hi: 0x8C469AB843B89562'u, lo: 0x93956D7478CCEC8E'u), - uint64x2(hi: 0xAF58416654A6BABB'u, lo: 0x387AC8D1970027B2'u), - uint64x2(hi: 0xDB2E51BFE9D0696A'u, lo: 0x06997B05FCC0319E'u), - uint64x2(hi: 0x88FCF317F22241E2'u, lo: 0x441FECE3BDF81F03'u), - uint64x2(hi: 0xAB3C2FDDEEAAD25A'u, lo: 0xD527E81CAD7626C3'u), - uint64x2(hi: 0xD60B3BD56A5586F1'u, lo: 0x8A71E223D8D3B074'u), - uint64x2(hi: 0x85C7056562757456'u, lo: 0xF6872D5667844E49'u), - uint64x2(hi: 0xA738C6BEBB12D16C'u, lo: 0xB428F8AC016561DB'u), - uint64x2(hi: 0xD106F86E69D785C7'u, lo: 0xE13336D701BEBA52'u), - uint64x2(hi: 0x82A45B450226B39C'u, lo: 0xECC0024661173473'u), - uint64x2(hi: 0xA34D721642B06084'u, lo: 0x27F002D7F95D0190'u), - uint64x2(hi: 0xCC20CE9BD35C78A5'u, lo: 0x31EC038DF7B441F4'u), - uint64x2(hi: 0xFF290242C83396CE'u, lo: 0x7E67047175A15271'u), - uint64x2(hi: 0x9F79A169BD203E41'u, lo: 0x0F0062C6E984D386'u), - uint64x2(hi: 0xC75809C42C684DD1'u, lo: 0x52C07B78A3E60868'u), - uint64x2(hi: 0xF92E0C3537826145'u, lo: 0xA7709A56CCDF8A82'u), - uint64x2(hi: 0x9BBCC7A142B17CCB'u, lo: 0x88A66076400BB691'u), - uint64x2(hi: 0xC2ABF989935DDBFE'u, lo: 0x6ACFF893D00EA435'u), - uint64x2(hi: 0xF356F7EBF83552FE'u, lo: 0x0583F6B8C4124D43'u), - uint64x2(hi: 0x98165AF37B2153DE'u, lo: 0xC3727A337A8B704A'u), - uint64x2(hi: 0xBE1BF1B059E9A8D6'u, lo: 0x744F18C0592E4C5C'u), - uint64x2(hi: 0xEDA2EE1C7064130C'u, lo: 0x1162DEF06F79DF73'u), - uint64x2(hi: 0x9485D4D1C63E8BE7'u, lo: 0x8ADDCB5645AC2BA8'u), - uint64x2(hi: 0xB9A74A0637CE2EE1'u, lo: 0x6D953E2BD7173692'u), - uint64x2(hi: 0xE8111C87C5C1BA99'u, lo: 0xC8FA8DB6CCDD0437'u), - uint64x2(hi: 0x910AB1D4DB9914A0'u, lo: 0x1D9C9892400A22A2'u), - uint64x2(hi: 0xB54D5E4A127F59C8'u, lo: 0x2503BEB6D00CAB4B'u), - uint64x2(hi: 0xE2A0B5DC971F303A'u, lo: 0x2E44AE64840FD61D'u), - uint64x2(hi: 0x8DA471A9DE737E24'u, lo: 0x5CEAECFED289E5D2'u), - uint64x2(hi: 0xB10D8E1456105DAD'u, lo: 0x7425A83E872C5F47'u), - uint64x2(hi: 0xDD50F1996B947518'u, lo: 0xD12F124E28F77719'u), - uint64x2(hi: 0x8A5296FFE33CC92F'u, lo: 0x82BD6B70D99AAA6F'u), - uint64x2(hi: 0xACE73CBFDC0BFB7B'u, lo: 0x636CC64D1001550B'u), - uint64x2(hi: 0xD8210BEFD30EFA5A'u, lo: 0x3C47F7E05401AA4E'u), - uint64x2(hi: 0x8714A775E3E95C78'u, lo: 0x65ACFAEC34810A71'u), - uint64x2(hi: 0xA8D9D1535CE3B396'u, lo: 0x7F1839A741A14D0D'u), - uint64x2(hi: 0xD31045A8341CA07C'u, lo: 0x1EDE48111209A050'u), - uint64x2(hi: 0x83EA2B892091E44D'u, lo: 0x934AED0AAB460432'u), - uint64x2(hi: 0xA4E4B66B68B65D60'u, lo: 0xF81DA84D5617853F'u), - uint64x2(hi: 0xCE1DE40642E3F4B9'u, lo: 0x36251260AB9D668E'u), - uint64x2(hi: 0x80D2AE83E9CE78F3'u, lo: 0xC1D72B7C6B426019'u), - uint64x2(hi: 0xA1075A24E4421730'u, lo: 0xB24CF65B8612F81F'u), - uint64x2(hi: 0xC94930AE1D529CFC'u, lo: 0xDEE033F26797B627'u), - uint64x2(hi: 0xFB9B7CD9A4A7443C'u, lo: 0x169840EF017DA3B1'u), - uint64x2(hi: 0x9D412E0806E88AA5'u, lo: 0x8E1F289560EE864E'u), - uint64x2(hi: 0xC491798A08A2AD4E'u, lo: 0xF1A6F2BAB92A27E2'u), - uint64x2(hi: 0xF5B5D7EC8ACB58A2'u, lo: 0xAE10AF696774B1DB'u), - uint64x2(hi: 0x9991A6F3D6BF1765'u, lo: 0xACCA6DA1E0A8EF29'u), - uint64x2(hi: 0xBFF610B0CC6EDD3F'u, lo: 0x17FD090A58D32AF3'u), - uint64x2(hi: 0xEFF394DCFF8A948E'u, lo: 0xDDFC4B4CEF07F5B0'u), - uint64x2(hi: 0x95F83D0A1FB69CD9'u, lo: 0x4ABDAF101564F98E'u), - uint64x2(hi: 0xBB764C4CA7A4440F'u, lo: 0x9D6D1AD41ABE37F1'u), - uint64x2(hi: 0xEA53DF5FD18D5513'u, lo: 0x84C86189216DC5ED'u), - uint64x2(hi: 0x92746B9BE2F8552C'u, lo: 0x32FD3CF5B4E49BB4'u), - uint64x2(hi: 0xB7118682DBB66A77'u, lo: 0x3FBC8C33221DC2A1'u), - uint64x2(hi: 0xE4D5E82392A40515'u, lo: 0x0FABAF3FEAA5334A'u), - uint64x2(hi: 0x8F05B1163BA6832D'u, lo: 0x29CB4D87F2A7400E'u), - uint64x2(hi: 0xB2C71D5BCA9023F8'u, lo: 0x743E20E9EF511012'u), - uint64x2(hi: 0xDF78E4B2BD342CF6'u, lo: 0x914DA9246B255416'u), - uint64x2(hi: 0x8BAB8EEFB6409C1A'u, lo: 0x1AD089B6C2F7548E'u), - uint64x2(hi: 0xAE9672ABA3D0C320'u, lo: 0xA184AC2473B529B1'u), - uint64x2(hi: 0xDA3C0F568CC4F3E8'u, lo: 0xC9E5D72D90A2741E'u), - uint64x2(hi: 0x8865899617FB1871'u, lo: 0x7E2FA67C7A658892'u), - uint64x2(hi: 0xAA7EEBFB9DF9DE8D'u, lo: 0xDDBB901B98FEEAB7'u), - uint64x2(hi: 0xD51EA6FA85785631'u, lo: 0x552A74227F3EA565'u), - uint64x2(hi: 0x8533285C936B35DE'u, lo: 0xD53A88958F87275F'u), - uint64x2(hi: 0xA67FF273B8460356'u, lo: 0x8A892ABAF368F137'u), - uint64x2(hi: 0xD01FEF10A657842C'u, lo: 0x2D2B7569B0432D85'u), - uint64x2(hi: 0x8213F56A67F6B29B'u, lo: 0x9C3B29620E29FC73'u), - uint64x2(hi: 0xA298F2C501F45F42'u, lo: 0x8349F3BA91B47B8F'u), - uint64x2(hi: 0xCB3F2F7642717713'u, lo: 0x241C70A936219A73'u), - uint64x2(hi: 0xFE0EFB53D30DD4D7'u, lo: 0xED238CD383AA0110'u), - uint64x2(hi: 0x9EC95D1463E8A506'u, lo: 0xF4363804324A40AA'u), - uint64x2(hi: 0xC67BB4597CE2CE48'u, lo: 0xB143C6053EDCD0D5'u), - uint64x2(hi: 0xF81AA16FDC1B81DA'u, lo: 0xDD94B7868E94050A'u), - uint64x2(hi: 0x9B10A4E5E9913128'u, lo: 0xCA7CF2B4191C8326'u), - uint64x2(hi: 0xC1D4CE1F63F57D72'u, lo: 0xFD1C2F611F63A3F0'u), - uint64x2(hi: 0xF24A01A73CF2DCCF'u, lo: 0xBC633B39673C8CEC'u), - uint64x2(hi: 0x976E41088617CA01'u, lo: 0xD5BE0503E085D813'u), - uint64x2(hi: 0xBD49D14AA79DBC82'u, lo: 0x4B2D8644D8A74E18'u), - uint64x2(hi: 0xEC9C459D51852BA2'u, lo: 0xDDF8E7D60ED1219E'u), - uint64x2(hi: 0x93E1AB8252F33B45'u, lo: 0xCABB90E5C942B503'u), - uint64x2(hi: 0xB8DA1662E7B00A17'u, lo: 0x3D6A751F3B936243'u), - uint64x2(hi: 0xE7109BFBA19C0C9D'u, lo: 0x0CC512670A783AD4'u), - uint64x2(hi: 0x906A617D450187E2'u, lo: 0x27FB2B80668B24C5'u), - uint64x2(hi: 0xB484F9DC9641E9DA'u, lo: 0xB1F9F660802DEDF6'u), - uint64x2(hi: 0xE1A63853BBD26451'u, lo: 0x5E7873F8A0396973'u), - uint64x2(hi: 0x8D07E33455637EB2'u, lo: 0xDB0B487B6423E1E8'u), - uint64x2(hi: 0xB049DC016ABC5E5F'u, lo: 0x91CE1A9A3D2CDA62'u), - uint64x2(hi: 0xDC5C5301C56B75F7'u, lo: 0x7641A140CC7810FB'u), - uint64x2(hi: 0x89B9B3E11B6329BA'u, lo: 0xA9E904C87FCB0A9D'u), - uint64x2(hi: 0xAC2820D9623BF429'u, lo: 0x546345FA9FBDCD44'u), - uint64x2(hi: 0xD732290FBACAF133'u, lo: 0xA97C177947AD4095'u), - uint64x2(hi: 0x867F59A9D4BED6C0'u, lo: 0x49ED8EABCCCC485D'u), - uint64x2(hi: 0xA81F301449EE8C70'u, lo: 0x5C68F256BFFF5A74'u), - uint64x2(hi: 0xD226FC195C6A2F8C'u, lo: 0x73832EEC6FFF3111'u), - uint64x2(hi: 0x83585D8FD9C25DB7'u, lo: 0xC831FD53C5FF7EAB'u), - uint64x2(hi: 0xA42E74F3D032F525'u, lo: 0xBA3E7CA8B77F5E55'u), - uint64x2(hi: 0xCD3A1230C43FB26F'u, lo: 0x28CE1BD2E55F35EB'u), - uint64x2(hi: 0x80444B5E7AA7CF85'u, lo: 0x7980D163CF5B81B3'u), - uint64x2(hi: 0xA0555E361951C366'u, lo: 0xD7E105BCC332621F'u), - uint64x2(hi: 0xC86AB5C39FA63440'u, lo: 0x8DD9472BF3FEFAA7'u), - uint64x2(hi: 0xFA856334878FC150'u, lo: 0xB14F98F6F0FEB951'u), - uint64x2(hi: 0x9C935E00D4B9D8D2'u, lo: 0x6ED1BF9A569F33D3'u), - uint64x2(hi: 0xC3B8358109E84F07'u, lo: 0x0A862F80EC4700C8'u), - uint64x2(hi: 0xF4A642E14C6262C8'u, lo: 0xCD27BB612758C0FA'u), - uint64x2(hi: 0x98E7E9CCCFBD7DBD'u, lo: 0x8038D51CB897789C'u), - uint64x2(hi: 0xBF21E44003ACDD2C'u, lo: 0xE0470A63E6BD56C3'u), - uint64x2(hi: 0xEEEA5D5004981478'u, lo: 0x1858CCFCE06CAC74'u), - uint64x2(hi: 0x95527A5202DF0CCB'u, lo: 0x0F37801E0C43EBC8'u), - uint64x2(hi: 0xBAA718E68396CFFD'u, lo: 0xD30560258F54E6BA'u), - uint64x2(hi: 0xE950DF20247C83FD'u, lo: 0x47C6B82EF32A2069'u), - uint64x2(hi: 0x91D28B7416CDD27E'u, lo: 0x4CDC331D57FA5441'u), - uint64x2(hi: 0xB6472E511C81471D'u, lo: 0xE0133FE4ADF8E952'u), - uint64x2(hi: 0xE3D8F9E563A198E5'u, lo: 0x58180FDDD97723A6'u), - uint64x2(hi: 0x8E679C2F5E44FF8F'u, lo: 0x570F09EAA7EA7648'u), - uint64x2(hi: 0xB201833B35D63F73'u, lo: 0x2CD2CC6551E513DA'u), - uint64x2(hi: 0xDE81E40A034BCF4F'u, lo: 0xF8077F7EA65E58D1'u), - uint64x2(hi: 0x8B112E86420F6191'u, lo: 0xFB04AFAF27FAF782'u), - uint64x2(hi: 0xADD57A27D29339F6'u, lo: 0x79C5DB9AF1F9B563'u), - uint64x2(hi: 0xD94AD8B1C7380874'u, lo: 0x18375281AE7822BC'u), - uint64x2(hi: 0x87CEC76F1C830548'u, lo: 0x8F2293910D0B15B5'u), - uint64x2(hi: 0xA9C2794AE3A3C69A'u, lo: 0xB2EB3875504DDB22'u), - uint64x2(hi: 0xD433179D9C8CB841'u, lo: 0x5FA60692A46151EB'u), - uint64x2(hi: 0x849FEEC281D7F328'u, lo: 0xDBC7C41BA6BCD333'u), - uint64x2(hi: 0xA5C7EA73224DEFF3'u, lo: 0x12B9B522906C0800'u), - uint64x2(hi: 0xCF39E50FEAE16BEF'u, lo: 0xD768226B34870A00'u), - uint64x2(hi: 0x81842F29F2CCE375'u, lo: 0xE6A1158300D46640'u), - uint64x2(hi: 0xA1E53AF46F801C53'u, lo: 0x60495AE3C1097FD0'u), - uint64x2(hi: 0xCA5E89B18B602368'u, lo: 0x385BB19CB14BDFC4'u), - uint64x2(hi: 0xFCF62C1DEE382C42'u, lo: 0x46729E03DD9ED7B5'u), - uint64x2(hi: 0x9E19DB92B4E31BA9'u, lo: 0x6C07A2C26A8346D1'u), - uint64x2(hi: 0xC5A05277621BE293'u, lo: 0xC7098B7305241885'u), - uint64x2(hi: 0xF70867153AA2DB38'u, lo: 0xB8CBEE4FC66D1EA7'u)] - dragonbox_Assert(k >= kMin) - dragonbox_Assert(k <= kMax) - return pow10[k - kMin] - -## Returns whether value is divisible by 2^e2 - -proc multipleOfPow2*(value: uint64; e2: int32): bool {.inline.} = - dragonbox_Assert(e2 >= 0) - return e2 < 64 and (value and ((uint64(1) shl e2) - 1)) == 0 - -## Returns whether value is divisible by 5^e5 - -proc multipleOfPow5*(value: uint64; e5: int32): bool {.inline.} = - type - MulCmp {.bycopy.} = object - mul: uint64 - cmp: uint64 - - const - mod5 = [MulCmp(mul: 0x0000000000000001'u, cmp: 0xFFFFFFFFFFFFFFFF'u), - MulCmp(mul: 0xCCCCCCCCCCCCCCCD'u, cmp: 0x3333333333333333'u), - MulCmp(mul: 0x8F5C28F5C28F5C29'u, cmp: 0x0A3D70A3D70A3D70'u), - MulCmp(mul: 0x1CAC083126E978D5'u, cmp: 0x020C49BA5E353F7C'u), - MulCmp(mul: 0xD288CE703AFB7E91'u, cmp: 0x0068DB8BAC710CB2'u), - MulCmp(mul: 0x5D4E8FB00BCBE61D'u, cmp: 0x0014F8B588E368F0'u), - MulCmp(mul: 0x790FB65668C26139'u, cmp: 0x000431BDE82D7B63'u), - MulCmp(mul: 0xE5032477AE8D46A5'u, cmp: 0x0000D6BF94D5E57A'u), - MulCmp(mul: 0xC767074B22E90E21'u, cmp: 0x00002AF31DC46118'u), - MulCmp(mul: 0x8E47CE423A2E9C6D'u, cmp: 0x0000089705F4136B'u), - MulCmp(mul: 0x4FA7F60D3ED61F49'u, cmp: 0x000001B7CDFD9D7B'u), - MulCmp(mul: 0x0FEE64690C913975'u, cmp: 0x00000057F5FF85E5'u), - MulCmp(mul: 0x3662E0E1CF503EB1'u, cmp: 0x000000119799812D'u), - MulCmp(mul: 0xA47A2CF9F6433FBD'u, cmp: 0x0000000384B84D09'u), - MulCmp(mul: 0x54186F653140A659'u, cmp: 0x00000000B424DC35'u), - MulCmp(mul: 0x7738164770402145'u, cmp: 0x0000000024075F3D'u), - MulCmp(mul: 0xE4A4D1417CD9A041'u, cmp: 0x000000000734ACA5'u), - MulCmp(mul: 0xC75429D9E5C5200D'u, cmp: 0x000000000170EF54'u), - MulCmp(mul: 0xC1773B91FAC10669'u, cmp: 0x000000000049C977'u), - MulCmp(mul: 0x26B172506559CE15'u, cmp: 0x00000000000EC1E4'u), - MulCmp(mul: 0xD489E3A9ADDEC2D1'u, cmp: 0x000000000002F394'u), - MulCmp(mul: 0x90E860BB892C8D5D'u, cmp: 0x000000000000971D'u), - MulCmp(mul: 0x502E79BF1B6F4F79'u, cmp: 0x0000000000001E39'u), - MulCmp(mul: 0xDCD618596BE30FE5'u, cmp: 0x000000000000060B'u), - MulCmp(mul: 0x2C2AD1AB7BFA3661'u, cmp: 0x0000000000000135'u)] - dragonbox_Assert(e5 >= 0) - dragonbox_Assert(e5 <= 24) - let m5: MulCmp = mod5[e5] - return value * m5.mul <= m5.cmp - -type - FloatingDecimal64* {.bycopy.} = object - significand*: uint64 - exponent*: int32 - - -proc toDecimal64AsymmetricInterval*(e2: int32): FloatingDecimal64 {.inline.} = - ## NB: - ## accept_lower_endpoint = true - ## accept_upper_endpoint = true - const - P: int32 = significandSize - ## Compute k and beta - let minusK: int32 = floorLog10ThreeQuartersPow2(e2) - let betaMinus1: int32 = e2 + floorLog2Pow10(-minusK) - ## Compute xi and zi - let pow10: uint64x2 = computePow10(-minusK) - let lowerEndpoint: uint64 = (pow10.hi - (pow10.hi shr (P + 1))) shr - (64 - P - betaMinus1) - let upperEndpoint: uint64 = (pow10.hi + (pow10.hi shr (P + 0))) shr - (64 - P - betaMinus1) - ## If we don't accept the left endpoint (but we do!) or - ## if the left endpoint is not an integer, increase it - let lowerEndpointIsInteger: bool = (2 <= e2 and e2 <= 3) - let xi: uint64 = lowerEndpoint + uint64(not lowerEndpointIsInteger) - let zi: uint64 = upperEndpoint - ## Try bigger divisor - var q: uint64 = zi div 10 - if q * 10 >= xi: - return FloatingDecimal64(significand: q, exponent: minusK + 1) - q = ((pow10.hi shr (64 - (P + 1) - betaMinus1)) + 1) div 2 - ## When tie occurs, choose one of them according to the rule - if e2 == -77: - dec(q, ord(q mod 2 != 0)) - ## Round to even. - else: - inc(q, ord(q < xi)) - return FloatingDecimal64(significand: q, exponent: minusK) - -proc computeDelta*(pow10: uint64x2; betaMinus1: int32): uint32 {.inline.} = - dragonbox_Assert(betaMinus1 >= 0) - dragonbox_Assert(betaMinus1 <= 63) - return cast[uint32](pow10.hi shr (64 - 1 - betaMinus1)) - -when defined(sizeof_Int128): - proc mul128*(x: uint64; y: uint64): uint64x2 {.inline.} = - ## 1 mulx - type - uint128T = uint128 - let p: uint128T = uint128T(x) * y - let hi: uint64 = cast[uint64](p shr 64) - let lo: uint64 = cast[uint64](p) - return (hi, lo) - -elif defined(vcc) and defined(cpu64): - proc umul128(x, y: uint64, z: ptr uint64): uint64 {.importc: "_umul128", header: "".} - proc mul128*(x: uint64; y: uint64): uint64x2 {.inline.} = - var hi: uint64 = 0 - var lo: uint64 = umul128(x, y, addr(hi)) - return uint64x2(hi: hi, lo: lo) - -else: - proc lo32*(x: uint64): uint32 {.inline.} = - return cast[uint32](x) - - proc hi32*(x: uint64): uint32 {.inline.} = - return cast[uint32](x shr 32) - - proc mul128*(a: uint64; b: uint64): uint64x2 {.inline.} = - let b00: uint64 = uint64(lo32(a)) * lo32(b) - let b01: uint64 = uint64(lo32(a)) * hi32(b) - let b10: uint64 = uint64(hi32(a)) * lo32(b) - let b11: uint64 = uint64(hi32(a)) * hi32(b) - let mid1: uint64 = b10 + hi32(b00) - let mid2: uint64 = b01 + lo32(mid1) - let hi: uint64 = b11 + hi32(mid1) + hi32(mid2) - let lo: uint64 = lo32(b00) or uint64(lo32(mid2)) shl 32 - return uint64x2(hi: hi, lo: lo) - -## Returns (x * y) / 2^128 - -proc mulShift*(x: uint64; y: uint64x2): uint64 {.inline.} = - ## 2 mulx - var p1: uint64x2 = mul128(x, y.hi) - var p0: uint64x2 = mul128(x, y.lo) - p1.lo += p0.hi - inc(p1.hi, ord(p1.lo < p0.hi)) - return p1.hi - -proc mulParity*(twoF: uint64; pow10: uint64x2; betaMinus1: int32): bool {.inline.} = - ## 1 mulx, 1 mul - dragonbox_Assert(betaMinus1 >= 1) - dragonbox_Assert(betaMinus1 <= 63) - let p01: uint64 = twoF * pow10.hi - let p10: uint64 = mul128(twoF, pow10.lo).hi - let mid: uint64 = p01 + p10 - return (mid and (uint64(1) shl (64 - betaMinus1))) != 0 - -proc isIntegralEndpoint*(twoF: uint64; e2: int32; minusK: int32): bool {.inline.} = - if e2 < -2: - return false - if e2 <= 9: - return true - if e2 <= 86: - return multipleOfPow5(twoF, minusK) - return false - -proc isIntegralMidpoint*(twoF: uint64; e2: int32; minusK: int32): bool {.inline.} = - if e2 < -4: - return multipleOfPow2(twoF, minusK - e2 + 1) - if e2 <= 9: - return true - if e2 <= 86: - return multipleOfPow5(twoF, minusK) - return false - -proc toDecimal64*(ieeeSignificand: uint64; ieeeExponent: uint64): FloatingDecimal64 {. - inline.} = - const - kappa: int32 = 2 - const - bigDivisor: uint32 = 1000 - ## 10^(kappa + 1) - const - smallDivisor: uint32 = 100 - ## 10^(kappa) - ## - ## Step 1: - ## integer promotion & Schubfach multiplier calculation. - ## - var m2: uint64 - var e2: int32 - if ieeeExponent != 0: - m2 = hiddenBit or ieeeSignificand - e2 = cast[int32](ieeeExponent) - exponentBias - if 0 <= -e2 and -e2 < significandSize and multipleOfPow2(m2, -e2): - ## Small integer. - return FloatingDecimal64(significand: m2 shr -e2, exponent: 0) - if ieeeSignificand == 0 and ieeeExponent > 1: - ## Shorter interval case; proceed like Schubfach. - return toDecimal64AsymmetricInterval(e2) - else: - ## Subnormal case; interval is always regular. - m2 = ieeeSignificand - e2 = 1 - exponentBias - let isEven: bool = (m2 mod 2 == 0) - let acceptLower: bool = isEven - let acceptUpper: bool = isEven - ## Compute k and beta. - let minusK: int32 = floorLog10Pow2(e2) - kappa - let betaMinus1: int32 = e2 + floorLog2Pow10(-minusK) - dragonbox_Assert(betaMinus1 >= 6) - dragonbox_Assert(betaMinus1 <= 9) - let pow10: uint64x2 = computePow10(-minusK) - ## Compute delta - ## 10^kappa <= delta < 10^(kappa + 1) - ## 100 <= delta < 1000 - let delta: uint32 = computeDelta(pow10, betaMinus1) - dragonbox_Assert(delta >= smallDivisor) - dragonbox_Assert(delta < bigDivisor) - let twoFl: uint64 = 2 * m2 - 1 - let twoFc: uint64 = 2 * m2 - let twoFr: uint64 = 2 * m2 + 1 - ## (54 bits) - ## Compute zi - ## (54 + 9 = 63 bits) - let zi: uint64 = mulShift(twoFr shl betaMinus1, pow10) - ## 2 mulx - ## - ## Step 2: - ## Try larger divisor. - ## - var q: uint64 = zi div bigDivisor - ## uint64_t q = Mul128(zi, 0x83126E978D4FDF3Cu).hi >> 9; // 1 mulx - var r: uint32 = cast[uint32](zi) - bigDivisor * cast[uint32](q) - ## r = zi % BigDivisor - ## 0 <= r < 1000 - if r < delta: ## likely ~50% ?! - ## (r > deltai) - ## Exclude the right endpoint if necessary - if r != 0 or acceptUpper or not isIntegralEndpoint(twoFr, e2, minusK): - return FloatingDecimal64(significand: q, exponent: minusK + kappa + 1) - dragonbox_Assert(q != 0) - dec(q) - r = bigDivisor - elif r == delta: ## unlikely - ## Compare fractional parts. - ## Check conditions in the order different from the paper - ## to take advantage of short-circuiting - if (acceptLower and isIntegralEndpoint(twoFl, e2, minusK)) or - mulParity(twoFl, pow10, betaMinus1): - return FloatingDecimal64(significand: q, exponent: minusK + kappa + 1) - else: - discard - ## - ## Step 3: - ## Find the significand with the smaller divisor - ## - q = q * 10 - ## 1 hmul - ## 0 <= r <= 1000 - let dist: uint32 = r - (delta div 2) + (smallDivisor div 2) - let distQ: uint32 = dist div 100 - ## 1 mul - ## const uint32_t dist_r = dist % 100; - q += distQ - ## if /*likely*/ (dist_r == 0) - if dist == distQ * 100: - ## const bool approx_y_parity = ((dist ^ (SmallDivisor / 2)) & 1) != 0; - let approxYParity: bool = (dist and 1) != 0 - ## Check z^(f) >= epsilon^(f) - ## We have either yi == zi - epsiloni or yi == (zi - epsiloni) - 1, - ## where yi == zi - epsiloni if and only if z^(f) >= epsilon^(f) - ## Since there are only 2 possibilities, we only need to care about the - ## parity. Also, zi and r should have the same parity since the divisor - ## is an even number - if mulParity(twoFc, pow10, betaMinus1) != approxYParity: - dec(q) - elif q mod 2 != 0 and isIntegralMidpoint(twoFc, e2, minusK): - dec(q) - return FloatingDecimal64(significand: q, exponent: minusK + kappa) - -# ================================================================================================== -# ToChars -# ================================================================================================== - -when false: - template `+!`(x: cstring; offset: int): cstring = cast[cstring](cast[uint](x) + uint(offset)) - - template dec(x: cstring; offset=1) = x = cast[cstring](cast[uint](x) - uint(offset)) - template inc(x: cstring; offset=1) = x = cast[cstring](cast[uint](x) + uint(offset)) - - proc memset(x: cstring; ch: char; L: int) {.importc, nodecl.} - proc memmove(a, b: cstring; L: int) {.importc, nodecl.} - -proc utoa8DigitsSkipTrailingZeros*(buf: var openArray[char]; pos: int; digits: uint32): int32 {.inline.} = - dragonbox_Assert(digits >= 1) - dragonbox_Assert(digits <= 99999999'u32) - let q: uint32 = digits div 10000 - let r: uint32 = digits mod 10000 - let qH: uint32 = q div 100 - let qL: uint32 = q mod 100 - utoa2Digits(buf, pos, qH) - utoa2Digits(buf, pos + 2, qL) - if r == 0: - return trailingZeros2Digits(if qL == 0: qH else: qL) + (if qL == 0: 6 else: 4) - else: - let rH: uint32 = r div 100 - let rL: uint32 = r mod 100 - utoa2Digits(buf, pos + 4, rH) - utoa2Digits(buf, pos + 6, rL) - return trailingZeros2Digits(if rL == 0: rH else: rL) + (if rL == 0: 2 else: 0) - -proc printDecimalDigitsBackwards*(buf: var openArray[char]; pos: int; output64: uint64): int32 {.inline.} = - var pos = pos - var output64 = output64 - var tz: int32 = 0 - ## number of trailing zeros removed. - var nd: int32 = 0 - ## number of decimal digits processed. - ## At most 17 digits remaining - if output64 >= 100000000'u64: - let q: uint64 = output64 div 100000000'u64 - let r: uint32 = cast[uint32](output64 mod 100000000'u64) - output64 = q - dec(pos, 8) - if r != 0: - tz = utoa8DigitsSkipTrailingZeros(buf, pos, r) - dragonbox_Assert(tz >= 0) - dragonbox_Assert(tz <= 7) - else: - tz = 8 - nd = 8 - dragonbox_Assert(output64 <= high(uint32)) - var output = cast[uint32](output64) - if output >= 10000: - let q: uint32 = output div 10000 - let r: uint32 = output mod 10000 - output = q - dec(pos, 4) - if r != 0: - let rH: uint32 = r div 100 - let rL: uint32 = r mod 100 - utoa2Digits(buf, pos, rH) - utoa2Digits(buf, pos + 2, rL) - if tz == nd: - inc(tz, trailingZeros2Digits(if rL == 0: rH else: rL) + - (if rL == 0: 2 else: 0)) - else: - if tz == nd: - inc(tz, 4) - else: - for i in 0..3: buf[pos+i] = '0' - ## (actually not required...) - inc(nd, 4) - if output >= 100: - let q: uint32 = output div 100 - let r: uint32 = output mod 100 - output = q - dec(pos, 2) - utoa2Digits(buf, pos, r) - if tz == nd: - inc(tz, trailingZeros2Digits(r)) - inc(nd, 2) - if output >= 100: - let q2: uint32 = output div 100 - let r2: uint32 = output mod 100 - output = q2 - dec(pos, 2) - utoa2Digits(buf, pos, r2) - if tz == nd: - inc(tz, trailingZeros2Digits(r2)) - inc(nd, 2) - dragonbox_Assert(output >= 1) - dragonbox_Assert(output <= 99) - if output >= 10: - let q: uint32 = output - dec(pos, 2) - utoa2Digits(buf, pos, q) - if tz == nd: - inc(tz, trailingZeros2Digits(q)) - else: - let q: uint32 = output - dragonbox_Assert(q >= 1) - dragonbox_Assert(q <= 9) - dec(pos) - buf[pos] = chr(ord('0') + q) - return tz - -proc decimalLength*(v: uint64): int {.inline.} = - dragonbox_Assert(v >= 1) - dragonbox_Assert(v <= 99999999999999999'u64) - if cast[uint32](v shr 32) != 0: - if v >= 10000000000000000'u64: - return 17 - if v >= 1000000000000000'u64: - return 16 - if v >= 100000000000000'u64: - return 15 - if v >= 10000000000000'u64: - return 14 - if v >= 1000000000000'u64: - return 13 - if v >= 100000000000'u64: - return 12 - if v >= 10000000000'u64: - return 11 - return 10 - let v32: uint32 = cast[uint32](v) - if v32 >= 1000000000'u32: - return 10 - if v32 >= 100000000'u32: - return 9 - if v32 >= 10000000'u32: - return 8 - if v32 >= 1000000'u32: - return 7 - if v32 >= 100000'u32: - return 6 - if v32 >= 10000'u32: - return 5 - if v32 >= 1000'u32: - return 4 - if v32 >= 100'u32: - return 3 - if v32 >= 10'u32: - return 2 - return 1 - -proc formatDigits*[T: Ordinal](buffer: var openArray[char]; pos: T; digits: uint64; decimalExponent: int; - forceTrailingDotZero = false): int {.inline.} = - const - minFixedDecimalPoint = -6 - const - maxFixedDecimalPoint = 17 - var pos:int = pos.int - assert(minFixedDecimalPoint <= -1, "internal error") - assert(maxFixedDecimalPoint >= 17, "internal error") - dragonbox_Assert(digits >= 1) - dragonbox_Assert(digits <= 99999999999999999'u64) - dragonbox_Assert(decimalExponent >= -999) - dragonbox_Assert(decimalExponent <= 999) - var numDigits = decimalLength(digits) - let decimalPoint = numDigits + decimalExponent - let useFixed: bool = minFixedDecimalPoint <= decimalPoint and - decimalPoint <= maxFixedDecimalPoint - ## Prepare the buffer. - for i in 0..<32: buffer[pos+i] = '0' - assert(minFixedDecimalPoint >= -30, "internal error") - assert(maxFixedDecimalPoint <= 32, "internal error") - var decimalDigitsPosition: int - if useFixed: - if decimalPoint <= 0: - ## 0.[000]digits - decimalDigitsPosition = 2 - decimalPoint - else: - ## dig.its - ## digits[000] - decimalDigitsPosition = 0 - else: - ## dE+123 or d.igitsE+123 - decimalDigitsPosition = 1 - var digitsEnd = pos + int(decimalDigitsPosition + numDigits) - let tz: int32 = printDecimalDigitsBackwards(buffer, digitsEnd, digits) - dec(digitsEnd, tz) - dec(numDigits, tz) - ## decimal_exponent += tz; // => decimal_point unchanged. - if useFixed: - if decimalPoint <= 0: - ## 0.[000]digits - buffer[pos+1] = '.' - pos = digitsEnd - elif decimalPoint < numDigits: - ## dig.its - when true: #defined(vcc) and not defined(clang): - ## VC does not inline the memmove call below. (Even if compiled with /arch:AVX2.) - ## However, memcpy will be inlined. - var tmp: array[16, char] - for i in 0..<16: tmp[i] = buffer[i+pos+decimalPoint] - for i in 0..<16: buffer[i+pos+decimalPoint+1] = tmp[i] - else: - memmove(buffer +! (decimalPoint + 1), buffer +! decimalPoint, 16) - buffer[pos+decimalPoint] = '.' - pos = digitsEnd + 1 - else: - ## digits[000] - inc(pos, decimalPoint) - if forceTrailingDotZero: - buffer[pos] = '.' - buffer[pos+1] = '0' - inc(pos, 2) - else: - ## Copy the first digit one place to the left. - buffer[pos] = buffer[pos+1] - if numDigits == 1: - ## dE+123 - inc(pos) - else: - ## d.igitsE+123 - buffer[pos+1] = '.' - pos = digitsEnd - let scientificExponent: int = decimalPoint - 1 - ## SF_ASSERT(scientific_exponent != 0); - buffer[pos] = 'e' - buffer[pos+1] = if scientificExponent < 0: '-' else: '+' - inc(pos, 2) - let k: uint32 = cast[uint32](if scientificExponent < 0: -scientificExponent else: scientificExponent) - if k < 10: - buffer[pos] = chr(ord('0') + k) - inc(pos) - elif k < 100: - utoa2Digits(buffer, pos, k) - inc(pos, 2) - else: - let q: uint32 = k div 100 - let r: uint32 = k mod 100 - buffer[pos] = chr(ord('0') + q) - inc(pos) - utoa2Digits(buffer, pos, r) - inc(pos, 2) - return pos - -proc toChars*(buffer: var openArray[char]; v: float; forceTrailingDotZero = false): int {. - inline.} = - var pos = 0 - let significand: uint64 = physicalSignificand(constructDouble(v)) - let exponent: uint64 = physicalExponent(constructDouble(v)) - if exponent != maxIeeeExponent: - ## Finite - buffer[pos] = '-' - inc(pos, signBit(constructDouble(v))) - if exponent != 0 or significand != 0: - ## != 0 - let dec = toDecimal64(significand, exponent) - return formatDigits(buffer, pos, dec.significand, dec.exponent.int, - forceTrailingDotZero) - else: - buffer[pos] = '0' - buffer[pos+1] = '.' - buffer[pos+2] = '0' - buffer[pos+3] = ' ' - inc(pos, if forceTrailingDotZero: 3 else: 1) - return pos - if significand == 0: - buffer[pos] = '-' - inc(pos, signBit(constructDouble(v))) - buffer[pos] = 'i' - buffer[pos+1] = 'n' - buffer[pos+2] = 'f' - buffer[pos+3] = ' ' - return pos + 3 - else: - buffer[pos] = 'n' - buffer[pos+1] = 'a' - buffer[pos+2] = 'n' - buffer[pos+3] = ' ' - return pos + 3 - -when false: - proc toString*(value: float): string = - var buffer: array[dtoaMinBufferLength, char] - let last = toChars(addr buffer, value) - let L = cast[int](last) - cast[int](addr(buffer)) - result = newString(L) - copyMem(addr result[0], addr buffer[0], L) - diff --git a/lib/std/private/gitutils.nim b/lib/std/private/gitutils.nim deleted file mode 100644 index db323bee1..000000000 --- a/lib/std/private/gitutils.nim +++ /dev/null @@ -1,81 +0,0 @@ -##[ -internal API for now, API subject to change -]## - -# xxx move other git utilities here; candidate for stdlib. - -import std/[os, osproc, strutils, tempfiles] - -when defined(nimPreviewSlimSystem): - import std/[assertions, syncio] - -const commitHead* = "HEAD" - -template retryCall*(maxRetry = 3, backoffDuration = 1.0, call: untyped): bool = - ## Retry `call` up to `maxRetry` times with exponential backoff and initial - ## duraton of `backoffDuration` seconds. - ## This is in particular useful for network commands that can fail. - runnableExamples: - doAssert not retryCall(maxRetry = 2, backoffDuration = 0.1, false) - var i = 0 - doAssert: retryCall(maxRetry = 3, backoffDuration = 0.1, (i.inc; i >= 3)) - doAssert retryCall(call = true) - var result = false - var t = backoffDuration - for i in 0.. 0: - let d = stack.pop() - for k, p in walkDir(dir / d, relative = true, checkDir = checkDir): - let rel = d / p - entry.kind = k - if relative: entry.path = rel - else: entry.path = dir / rel - if k in {pcDir, pcLinkToDir}: - if follow == nil or follow(entry): stack.add rel - yield entry - checkDir = false - # We only check top-level dir, otherwise if a subdir is invalid (eg. wrong - # permissions), it'll abort iteration and there would be no way to - # continue iteration. - -proc nativeToUnixPath*(path: string): string = - # pending https://github.com/nim-lang/Nim/pull/13265 - result = path - when defined(windows): - if path.len >= 2 and path[0] in {'a'..'z', 'A'..'Z'} and path[1] == ':': - result[0] = '/' - result[1] = path[0] - if path.len > 2 and path[2] != '\\': - doAssert false, "paths like `C:foo` are currently unsupported, path: " & path - when DirSep == '\\': - result = replace(result, '\\', '/') - -when isMainModule: - import sugar - for a in walkDirRecFilter(".", follow = a=>a.path.lastPathPart notin ["nimcache", ".git", "csources_v1", "csources", "bin"]): - echo a diff --git a/lib/std/private/jsutils.nim b/lib/std/private/jsutils.nim deleted file mode 100644 index 836b3512a..000000000 --- a/lib/std/private/jsutils.nim +++ /dev/null @@ -1,83 +0,0 @@ -when defined(js): - import std/jsbigints - - type - ArrayBuffer* = ref object of JsRoot - Float64Array* = ref object of JsRoot - Uint32Array* = ref object of JsRoot - Uint8Array* = ref object of JsRoot - BigUint64Array* = ref object of JsRoot - - - func newArrayBuffer*(n: int): ArrayBuffer {.importjs: "new ArrayBuffer(#)".} - func newFloat64Array*(buffer: ArrayBuffer): Float64Array {.importjs: "new Float64Array(#)".} - func newUint32Array*(buffer: ArrayBuffer): Uint32Array {.importjs: "new Uint32Array(#)".} - func newBigUint64Array*(buffer: ArrayBuffer): BigUint64Array {.importjs: "new BigUint64Array(#)".} - - func newUint8Array*(n: int): Uint8Array {.importjs: "new Uint8Array(#)".} - - func `[]`*(arr: Uint32Array, i: int): uint32 {.importjs: "#[#]".} - func `[]`*(arr: Uint8Array, i: int): uint8 {.importjs: "#[#]".} - func `[]`*(arr: BigUint64Array, i: int): JsBigInt {.importjs: "#[#]".} - func `[]=`*(arr: Float64Array, i: int, v: float) {.importjs: "#[#] = #".} - - proc jsTypeOf*[T](x: T): cstring {.importjs: "typeof(#)".} = - ## Returns the name of the JsObject's JavaScript type as a cstring. - # xxx replace jsffi.jsTypeOf with this definition and add tests - runnableExamples: - import std/[jsffi, jsbigints] - assert jsTypeOf(1.toJs) == "number" - assert jsTypeOf(false.toJs) == "boolean" - assert [1].toJs.jsTypeOf == "object" # note the difference with `getProtoName` - assert big"1".toJs.jsTypeOf == "bigint" - - proc jsConstructorName*[T](a: T): cstring = - runnableExamples: - import std/jsffi - let a = array[2, float64].default - assert jsConstructorName(a) == "Float64Array" - assert jsConstructorName(a.toJs) == "Float64Array" - asm """`result` = `a`.constructor.name""" - - proc hasJsBigInt*(): bool = - asm """`result` = typeof BigInt != 'undefined'""" - - proc hasBigUint64Array*(): bool = - asm """`result` = typeof BigUint64Array != 'undefined'""" - - proc getProtoName*[T](a: T): cstring {.importjs: "Object.prototype.toString.call(#)".} = - runnableExamples: - import std/[jsffi, jsbigints] - type A = ref object - assert 1.toJs.getProtoName == "[object Number]" - assert "a".toJs.getProtoName == "[object String]" - assert big"1".toJs.getProtoName == "[object BigInt]" - assert false.toJs.getProtoName == "[object Boolean]" - assert (a: 1).toJs.getProtoName == "[object Object]" - assert A.default.toJs.getProtoName == "[object Null]" - assert [1].toJs.getProtoName == "[object Int32Array]" # implementation defined - assert @[1].toJs.getProtoName == "[object Array]" # ditto - - const maxSafeInteger* = 9007199254740991 - ## The same as `Number.MAX_SAFE_INTEGER` or `2^53 - 1`. - ## See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/MAX_SAFE_INTEGER - runnableExamples: - let a {.importjs: "Number.MAX_SAFE_INTEGER".}: int64 - assert a == maxSafeInteger - - proc isInteger*[T](x: T): bool {.importjs: "Number.isInteger(#)".} = - runnableExamples: - import std/jsffi - assert 1.isInteger - assert not 1.5.isInteger - assert 1.toJs.isInteger - assert not 1.5.toJs.isInteger - - proc isSafeInteger*[T](x: T): bool {.importjs: "Number.isSafeInteger(#)".} = - runnableExamples: - import std/jsffi - assert not "123".toJs.isSafeInteger - assert 123.isSafeInteger - assert 123.toJs.isSafeInteger - assert 9007199254740991.toJs.isSafeInteger - assert not 9007199254740992.toJs.isSafeInteger diff --git a/lib/std/private/miscdollars.nim b/lib/std/private/miscdollars.nim deleted file mode 100644 index 06fda6fa1..000000000 --- a/lib/std/private/miscdollars.nim +++ /dev/null @@ -1,39 +0,0 @@ -from std/private/digitsutils import addInt - -template toLocation*(result: var string, file: string | cstring, line: int, col: int) = - ## avoids spurious allocations - # Hopefully this can be re-used everywhere so that if a user needs to customize, - # it can be done in a single place. - result.add file - if line > 0: - result.add "(" - addInt(result, line) - if col > 0: - result.add ", " - addInt(result, col) - result.add ")" - -proc isNamedTuple(T: typedesc): bool {.magic: "TypeTrait".} - -template tupleObjectDollar*[T: tuple | object](result: var string, x: T) = - result = "(" - const isNamed = T is object or isNamedTuple(typeof(T)) - var count {.used.} = 0 - for name, value in fieldPairs(x): - if count > 0: result.add(", ") - when isNamed: - result.add(name) - result.add(": ") - count.inc - when compiles($value): - when value isnot string and value isnot seq and compiles(value.isNil): - if value.isNil: result.add "nil" - else: result.addQuoted(value) - else: - result.addQuoted(value) - else: - result.add("...") - when not isNamed: - if count == 1: - result.add(",") # $(1,) should print as the semantically legal (1,) - result.add(")") diff --git a/lib/std/private/ntpath.nim b/lib/std/private/ntpath.nim deleted file mode 100644 index 7c8661bb7..000000000 --- a/lib/std/private/ntpath.nim +++ /dev/null @@ -1,61 +0,0 @@ -# This module is inspired by Python's `ntpath.py` module. - -import std/[ - strutils, -] - -# Adapted `splitdrive` function from the following commits in Python source -# code: -# 5a607a3ee5e81bdcef3f886f9d20c1376a533df4 (2009): Initial UNC handling (by Mark Hammond) -# 2ba0fd5767577954f331ecbd53596cd8035d7186 (2022): Support for "UNC"-device paths (by Barney Gale) -# -# FAQ: Why use `strip` below? `\\?\UNC` is the start of a "UNC symbolic link", -# which is a special UNC form. Running `strip` differentiates `\\?\UNC\` (a UNC -# symbolic link) from e.g. `\\?\UNCD` (UNCD is the server in the UNC path). -func splitDrive*(p: string): tuple[drive, path: string] = - ## Splits a Windows path into a drive and path part. The drive can be e.g. - ## `C:`. It can also be a UNC path (`\\server\drive\path`). - ## - ## The equivalent `splitDrive` for POSIX systems always returns empty drive. - ## Therefore this proc is only necessary on DOS-like file systems (together - ## with Nim's `doslikeFileSystem` conditional variable). - ## - ## This proc's use case is to extract `path` such that it can be manipulated - ## like a POSIX path. - runnableExamples: - doAssert splitDrive("C:") == ("C:", "") - doAssert splitDrive(r"C:\") == (r"C:", r"\") - doAssert splitDrive(r"\\server\drive\foo\bar") == (r"\\server\drive", r"\foo\bar") - doAssert splitDrive(r"\\?\UNC\server\share\dir") == (r"\\?\UNC\server\share", r"\dir") - - result = ("", p) - if p.len < 2: - return - const sep = '\\' - let normp = p.replace('/', sep) - if p.len > 2 and normp[0] == sep and normp[1] == sep and normp[2] != sep: - - # is a UNC path: - # vvvvvvvvvvvvvvvvvvvv drive letter or UNC path - # \\machine\mountpoint\directory\etc\... - # directory ^^^^^^^^^^^^^^^ - let start = block: - const unc = "\\\\?\\UNC" # Length is 7 - let idx = min(8, normp.len) - if unc == normp[0.. 0: - let buffer = newWideCString(size.int) - if getTempPath(size, buffer) > 0: - result = $buffer - elif defined(android): result = "/data/local/tmp" - else: - getTempDirImpl(result) - if result.len == 0: - result = tempDirDefault - normalizePathEnd(result, trailingSep=true) diff --git a/lib/std/private/oscommon.nim b/lib/std/private/oscommon.nim deleted file mode 100644 index b747e33f1..000000000 --- a/lib/std/private/oscommon.nim +++ /dev/null @@ -1,186 +0,0 @@ -include system/inclrtl - -import std/[oserrors] - -when defined(nimPreviewSlimSystem): - import std/[syncio, assertions, widestrs] - -## .. importdoc:: osdirs.nim, os.nim - -const weirdTarget* = defined(nimscript) or defined(js) - - -type - ReadDirEffect* = object of ReadIOEffect ## Effect that denotes a read - ## operation from the directory - ## structure. - WriteDirEffect* = object of WriteIOEffect ## Effect that denotes a write - ## operation to - ## the directory structure. - - -when weirdTarget: - discard -elif defined(windows): - import winlean, times -elif defined(posix): - import posix - proc c_rename(oldname, newname: cstring): cint {. - importc: "rename", header: "".} -else: - {.error: "OS module not ported to your operating system!".} - - -when weirdTarget: - {.pragma: noWeirdTarget, error: "this proc is not available on the NimScript/js target".} -else: - {.pragma: noWeirdTarget.} - - -when defined(nimscript): - # for procs already defined in scriptconfig.nim - template noNimJs(body): untyped = discard -elif defined(js): - {.pragma: noNimJs, error: "this proc is not available on the js target".} -else: - {.pragma: noNimJs.} - - -when defined(windows) and not weirdTarget: - template wrapUnary*(varname, winApiProc, arg: untyped) = - var varname = winApiProc(newWideCString(arg)) - - template wrapBinary*(varname, winApiProc, arg, arg2: untyped) = - var varname = winApiProc(newWideCString(arg), arg2) - proc findFirstFile*(a: string, b: var WIN32_FIND_DATA): Handle = - result = findFirstFileW(newWideCString(a), b) - template findNextFile*(a, b: untyped): untyped = findNextFileW(a, b) - - template getFilename*(f: untyped): untyped = - $cast[WideCString](addr(f.cFileName[0])) - - proc skipFindData*(f: WIN32_FIND_DATA): bool {.inline.} = - # Note - takes advantage of null delimiter in the cstring - const dot = ord('.') - result = f.cFileName[0].int == dot and (f.cFileName[1].int == 0 or - f.cFileName[1].int == dot and f.cFileName[2].int == 0) - - -type - PathComponent* = enum ## Enumeration specifying a path component. - ## - ## See also: - ## * `walkDirRec iterator`_ - ## * `FileInfo object`_ - pcFile, ## path refers to a file - pcLinkToFile, ## path refers to a symbolic link to a file - pcDir, ## path refers to a directory - pcLinkToDir ## path refers to a symbolic link to a directory - - -when defined(posix) and not weirdTarget: - proc getSymlinkFileKind*(path: string): - tuple[pc: PathComponent, isSpecial: bool] = - # Helper function. - var s: Stat - assert(path != "") - result = (pcLinkToFile, false) - if stat(path, s) == 0'i32: - if S_ISDIR(s.st_mode): - result = (pcLinkToDir, false) - elif not S_ISREG(s.st_mode): - result = (pcLinkToFile, true) - -proc tryMoveFSObject*(source, dest: string, isDir: bool): bool {.noWeirdTarget.} = - ## Moves a file (or directory if `isDir` is true) from `source` to `dest`. - ## - ## Returns false in case of `EXDEV` error or `AccessDeniedError` on Windows (if `isDir` is true). - ## In case of other errors `OSError` is raised. - ## Returns true in case of success. - when defined(windows): - let s = newWideCString(source) - let d = newWideCString(dest) - result = moveFileExW(s, d, MOVEFILE_COPY_ALLOWED or MOVEFILE_REPLACE_EXISTING) != 0'i32 - else: - result = c_rename(source, dest) == 0'i32 - - if not result: - let err = osLastError() - let isAccessDeniedError = - when defined(windows): - const AccessDeniedError = OSErrorCode(5) - isDir and err == AccessDeniedError - else: - err == EXDEV.OSErrorCode - if not isAccessDeniedError: - raiseOSError(err, $(source, dest)) - -when not defined(windows): - const maxSymlinkLen* = 1024 - -proc fileExists*(filename: string): bool {.rtl, extern: "nos$1", - tags: [ReadDirEffect], noNimJs.} = - ## Returns true if `filename` exists and is a regular file or symlink. - ## - ## Directories, device files, named pipes and sockets return false. - ## - ## See also: - ## * `dirExists proc`_ - ## * `symlinkExists proc`_ - when defined(windows): - wrapUnary(a, getFileAttributesW, filename) - if a != -1'i32: - result = (a and FILE_ATTRIBUTE_DIRECTORY) == 0'i32 - else: - var res: Stat - return stat(filename, res) >= 0'i32 and S_ISREG(res.st_mode) - - -proc dirExists*(dir: string): bool {.rtl, extern: "nos$1", tags: [ReadDirEffect], - noNimJs.} = - ## Returns true if the directory `dir` exists. If `dir` is a file, false - ## is returned. Follows symlinks. - ## - ## See also: - ## * `fileExists proc`_ - ## * `symlinkExists proc`_ - when defined(windows): - wrapUnary(a, getFileAttributesW, dir) - if a != -1'i32: - result = (a and FILE_ATTRIBUTE_DIRECTORY) != 0'i32 - else: - var res: Stat - result = stat(dir, res) >= 0'i32 and S_ISDIR(res.st_mode) - - -proc symlinkExists*(link: string): bool {.rtl, extern: "nos$1", - tags: [ReadDirEffect], - noWeirdTarget.} = - ## Returns true if the symlink `link` exists. Will return true - ## regardless of whether the link points to a directory or file. - ## - ## See also: - ## * `fileExists proc`_ - ## * `dirExists proc`_ - when defined(windows): - wrapUnary(a, getFileAttributesW, link) - if a != -1'i32: - # xxx see: bug #16784 (bug9); checking `IO_REPARSE_TAG_SYMLINK` - # may also be needed. - result = (a and FILE_ATTRIBUTE_REPARSE_POINT) != 0'i32 - else: - var res: Stat - result = lstat(link, res) >= 0'i32 and S_ISLNK(res.st_mode) - -when defined(windows) and not weirdTarget: - proc openHandle*(path: string, followSymlink=true, writeAccess=false): Handle = - var flags = FILE_FLAG_BACKUP_SEMANTICS or FILE_ATTRIBUTE_NORMAL - if not followSymlink: - flags = flags or FILE_FLAG_OPEN_REPARSE_POINT - let access = if writeAccess: GENERIC_WRITE else: 0'i32 - - result = createFileW( - newWideCString(path), access, - FILE_SHARE_DELETE or FILE_SHARE_READ or FILE_SHARE_WRITE, - nil, OPEN_EXISTING, flags, 0 - ) diff --git a/lib/std/private/osdirs.nim b/lib/std/private/osdirs.nim deleted file mode 100644 index a4318367d..000000000 --- a/lib/std/private/osdirs.nim +++ /dev/null @@ -1,561 +0,0 @@ -## .. importdoc:: osfiles.nim, appdirs.nim, paths.nim - -include system/inclrtl -import std/oserrors - - -import ospaths2, osfiles -import oscommon -export dirExists, PathComponent - - -when defined(nimPreviewSlimSystem): - import std/[syncio, assertions, widestrs] - - -when weirdTarget: - discard -elif defined(windows): - import winlean, times -elif defined(posix): - import posix, times - -else: - {.error: "OS module not ported to your operating system!".} - - -when weirdTarget: - {.pragma: noWeirdTarget, error: "this proc is not available on the NimScript/js target".} -else: - {.pragma: noWeirdTarget.} - - -when defined(nimscript): - # for procs already defined in scriptconfig.nim - template noNimJs(body): untyped = discard -elif defined(js): - {.pragma: noNimJs, error: "this proc is not available on the js target".} -else: - {.pragma: noNimJs.} - -# Templates for filtering directories and files -when defined(windows) and not weirdTarget: - template isDir(f: WIN32_FIND_DATA): bool = - (f.dwFileAttributes and FILE_ATTRIBUTE_DIRECTORY) != 0'i32 - template isFile(f: WIN32_FIND_DATA): bool = - not isDir(f) -else: - template isDir(f: string): bool {.dirty.} = - dirExists(f) - template isFile(f: string): bool {.dirty.} = - fileExists(f) - -template defaultWalkFilter(item): bool = - ## Walk filter used to return true on both - ## files and directories - true - -template walkCommon(pattern: string, filter) = - ## Common code for getting the files and directories with the - ## specified `pattern` - when defined(windows): - var - f: WIN32_FIND_DATA - res: int - res = findFirstFile(pattern, f) - if res != -1: - defer: findClose(res) - let dotPos = searchExtPos(pattern) - while true: - if not skipFindData(f) and filter(f): - # Windows bug/gotcha: 't*.nim' matches 'tfoo.nims' -.- so we check - # that the file extensions have the same length ... - let ff = getFilename(f) - let idx = ff.len - pattern.len + dotPos - if dotPos < 0 or idx >= ff.len or (idx >= 0 and ff[idx] == '.') or - (dotPos >= 0 and dotPos+1 < pattern.len and pattern[dotPos+1] == '*'): - yield splitFile(pattern).dir / extractFilename(ff) - if findNextFile(res, f) == 0'i32: - let errCode = getLastError() - if errCode == ERROR_NO_MORE_FILES: break - else: raiseOSError(errCode.OSErrorCode) - else: # here we use glob - var - f: Glob - res: int - f.gl_offs = 0 - f.gl_pathc = 0 - f.gl_pathv = nil - res = glob(pattern, 0, nil, addr(f)) - defer: globfree(addr(f)) - if res == 0: - for i in 0.. f.gl_pathc - 1: - assert(f.gl_pathv[i] != nil) - let path = $f.gl_pathv[i] - if filter(path): - yield path - -iterator walkPattern*(pattern: string): string {.tags: [ReadDirEffect], noWeirdTarget.} = - ## Iterate over all the files and directories that match the `pattern`. - ## - ## On POSIX this uses the `glob`:idx: call. - ## `pattern` is OS dependent, but at least the `"*.ext"` - ## notation is supported. - ## - ## See also: - ## * `walkFiles iterator`_ - ## * `walkDirs iterator`_ - ## * `walkDir iterator`_ - ## * `walkDirRec iterator`_ - runnableExamples: - import std/os - import std/sequtils - let paths = toSeq(walkPattern("lib/pure/*")) # works on Windows too - assert "lib/pure/concurrency".unixToNativePath in paths - assert "lib/pure/os.nim".unixToNativePath in paths - walkCommon(pattern, defaultWalkFilter) - -iterator walkFiles*(pattern: string): string {.tags: [ReadDirEffect], noWeirdTarget.} = - ## Iterate over all the files that match the `pattern`. - ## - ## On POSIX this uses the `glob`:idx: call. - ## `pattern` is OS dependent, but at least the `"*.ext"` - ## notation is supported. - ## - ## See also: - ## * `walkPattern iterator`_ - ## * `walkDirs iterator`_ - ## * `walkDir iterator`_ - ## * `walkDirRec iterator`_ - runnableExamples: - import std/os - import std/sequtils - assert "lib/pure/os.nim".unixToNativePath in toSeq(walkFiles("lib/pure/*.nim")) # works on Windows too - walkCommon(pattern, isFile) - -iterator walkDirs*(pattern: string): string {.tags: [ReadDirEffect], noWeirdTarget.} = - ## Iterate over all the directories that match the `pattern`. - ## - ## On POSIX this uses the `glob`:idx: call. - ## `pattern` is OS dependent, but at least the `"*.ext"` - ## notation is supported. - ## - ## See also: - ## * `walkPattern iterator`_ - ## * `walkFiles iterator`_ - ## * `walkDir iterator`_ - ## * `walkDirRec iterator`_ - runnableExamples: - import std/os - import std/sequtils - let paths = toSeq(walkDirs("lib/pure/*")) # works on Windows too - assert "lib/pure/concurrency".unixToNativePath in paths - walkCommon(pattern, isDir) - -proc staticWalkDir(dir: string; relative: bool): seq[ - tuple[kind: PathComponent, path: string]] = - discard - -iterator walkDir*(dir: string; relative = false, checkDir = false, - skipSpecial = false): - tuple[kind: PathComponent, path: string] {.tags: [ReadDirEffect].} = - ## Walks over the directory `dir` and yields for each directory or file in - ## `dir`. The component type and full path for each item are returned. - ## - ## Walking is not recursive. - ## * If `relative` is true (default: false) - ## the resulting path is shortened to be relative to ``dir``, - ## otherwise the full path is returned. - ## * If `checkDir` is true, `OSError` is raised when `dir` - ## doesn't exist. - ## * If `skipSpecial` is true, then (besides all directories) only *regular* - ## files (**without** special "file" objects like FIFOs, device files, - ## etc) will be yielded on Unix. - ## - ## **Example:** - ## - ## This directory structure: - ## - ## dirA / dirB / fileB1.txt - ## / dirC - ## / fileA1.txt - ## / fileA2.txt - ## - ## and this code: - runnableExamples("-r:off"): - import std/[strutils, sugar] - # note: order is not guaranteed - # this also works at compile time - assert collect(for k in walkDir("dirA"): k.path).join(" ") == - "dirA/dirB dirA/dirC dirA/fileA2.txt dirA/fileA1.txt" - ## See also: - ## * `walkPattern iterator`_ - ## * `walkFiles iterator`_ - ## * `walkDirs iterator`_ - ## * `walkDirRec iterator`_ - - when nimvm: - for k, v in items(staticWalkDir(dir, relative)): - yield (k, v) - else: - when weirdTarget: - for k, v in items(staticWalkDir(dir, relative)): - yield (k, v) - elif defined(windows): - var f: WIN32_FIND_DATA - var h = findFirstFile(dir / "*", f) - if h == -1: - if checkDir: - raiseOSError(osLastError(), dir) - else: - defer: findClose(h) - while true: - var k = pcFile - if not skipFindData(f): - if (f.dwFileAttributes and FILE_ATTRIBUTE_DIRECTORY) != 0'i32: - k = pcDir - if (f.dwFileAttributes and FILE_ATTRIBUTE_REPARSE_POINT) != 0'i32: - k = succ(k) - let xx = if relative: extractFilename(getFilename(f)) - else: dir / extractFilename(getFilename(f)) - yield (k, xx) - if findNextFile(h, f) == 0'i32: - let errCode = getLastError() - if errCode == ERROR_NO_MORE_FILES: break - else: raiseOSError(errCode.OSErrorCode) - else: - var d = opendir(dir) - if d == nil: - if checkDir: - raiseOSError(osLastError(), dir) - else: - defer: discard closedir(d) - while true: - var x = readdir(d) - if x == nil: break - var y = $cast[cstring](addr x.d_name) - if y != "." and y != "..": - var s: Stat - let path = dir / y - if not relative: - y = path - var k = pcFile - - template resolveSymlink() = - var isSpecial: bool - (k, isSpecial) = getSymlinkFileKind(path) - if skipSpecial and isSpecial: continue - - template kSetGeneric() = # pure Posix component `k` resolution - if lstat(path.cstring, s) < 0'i32: continue # don't yield - elif S_ISDIR(s.st_mode): - k = pcDir - elif S_ISLNK(s.st_mode): - resolveSymlink() - elif skipSpecial and not S_ISREG(s.st_mode): continue - - when defined(linux) or defined(macosx) or - defined(bsd) or defined(genode) or defined(nintendoswitch): - case x.d_type - of DT_DIR: k = pcDir - of DT_LNK: - resolveSymlink() - of DT_UNKNOWN: - kSetGeneric() - else: # DT_REG or special "files" like FIFOs - if skipSpecial and x.d_type != DT_REG: continue - else: discard # leave it as pcFile - else: # assuming that field `d_type` is not present - kSetGeneric() - - yield (k, y) - -iterator walkDirRec*(dir: string, - yieldFilter = {pcFile}, followFilter = {pcDir}, - relative = false, checkDir = false, skipSpecial = false): - string {.tags: [ReadDirEffect].} = - ## Recursively walks over the directory `dir` and yields for each file - ## or directory in `dir`. - ## - ## Options `relative`, `checkdir`, `skipSpecial` are explained in - ## [walkDir iterator] description. - ## - ## .. warning:: Modifying the directory structure while the iterator - ## is traversing may result in undefined behavior! - ## - ## Walking is recursive. `followFilter` controls the behaviour of the iterator: - ## - ## ===================== ============================================= - ## yieldFilter meaning - ## ===================== ============================================= - ## ``pcFile`` yield real files (default) - ## ``pcLinkToFile`` yield symbolic links to files - ## ``pcDir`` yield real directories - ## ``pcLinkToDir`` yield symbolic links to directories - ## ===================== ============================================= - ## - ## ===================== ============================================= - ## followFilter meaning - ## ===================== ============================================= - ## ``pcDir`` follow real directories (default) - ## ``pcLinkToDir`` follow symbolic links to directories - ## ===================== ============================================= - ## - ## - ## See also: - ## * `walkPattern iterator`_ - ## * `walkFiles iterator`_ - ## * `walkDirs iterator`_ - ## * `walkDir iterator`_ - - var stack = @[""] - var checkDir = checkDir - while stack.len > 0: - let d = stack.pop() - for k, p in walkDir(dir / d, relative = true, checkDir = checkDir, - skipSpecial = skipSpecial): - let rel = d / p - if k in {pcDir, pcLinkToDir} and k in followFilter: - stack.add rel - if k in yieldFilter: - yield if relative: rel else: dir / rel - checkDir = false - # We only check top-level dir, otherwise if a subdir is invalid (eg. wrong - # permissions), it'll abort iteration and there would be no way to - # continue iteration. - # Future work can provide a way to customize this and do error reporting. - - -proc rawRemoveDir(dir: string) {.noWeirdTarget.} = - when defined(windows): - wrapUnary(res, removeDirectoryW, dir) - let lastError = osLastError() - if res == 0'i32 and lastError.int32 != 3'i32 and - lastError.int32 != 18'i32 and lastError.int32 != 2'i32: - raiseOSError(lastError, dir) - else: - if rmdir(dir) != 0'i32 and errno != ENOENT: raiseOSError(osLastError(), dir) - -proc removeDir*(dir: string, checkDir = false) {.rtl, extern: "nos$1", tags: [ - WriteDirEffect, ReadDirEffect], benign, noWeirdTarget.} = - ## Removes the directory `dir` including all subdirectories and files - ## in `dir` (recursively). - ## - ## If this fails, `OSError` is raised. This does not fail if the directory never - ## existed in the first place, unless `checkDir` = true. - ## - ## See also: - ## * `tryRemoveFile proc`_ - ## * `removeFile proc`_ - ## * `existsOrCreateDir proc`_ - ## * `createDir proc`_ - ## * `copyDir proc`_ - ## * `copyDirWithPermissions proc`_ - ## * `moveDir proc`_ - for kind, path in walkDir(dir, checkDir = checkDir): - case kind - of pcFile, pcLinkToFile, pcLinkToDir: removeFile(path) - of pcDir: removeDir(path, true) - # for subdirectories there is no benefit in `checkDir = false` - # (unless perhaps for edge case of concurrent processes also deleting - # the same files) - rawRemoveDir(dir) - -proc rawCreateDir(dir: string): bool {.noWeirdTarget.} = - # Try to create one directory (not the whole path). - # returns `true` for success, `false` if the path has previously existed - # - # This is a thin wrapper over mkDir (or alternatives on other systems), - # so in case of a pre-existing path we don't check that it is a directory. - when defined(solaris): - let res = mkdir(dir, 0o777) - if res == 0'i32: - result = true - elif errno in {EEXIST, ENOSYS}: - result = false - else: - raiseOSError(osLastError(), dir) - elif defined(haiku): - let res = mkdir(dir, 0o777) - if res == 0'i32: - result = true - elif errno == EEXIST or errno == EROFS: - result = false - else: - raiseOSError(osLastError(), dir) - elif defined(posix): - let res = mkdir(dir, 0o777) - if res == 0'i32: - result = true - elif errno == EEXIST: - result = false - else: - #echo res - raiseOSError(osLastError(), dir) - else: - wrapUnary(res, createDirectoryW, dir) - - if res != 0'i32: - result = true - elif getLastError() == 183'i32: - result = false - else: - raiseOSError(osLastError(), dir) - -proc existsOrCreateDir*(dir: string): bool {.rtl, extern: "nos$1", - tags: [WriteDirEffect, ReadDirEffect], noWeirdTarget.} = - ## Checks if a `directory`:idx: `dir` exists, and creates it otherwise. - ## - ## Does not create parent directories (raises `OSError` if parent directories do not exist). - ## Returns `true` if the directory already exists, and `false` otherwise. - ## - ## See also: - ## * `removeDir proc`_ - ## * `createDir proc`_ - ## * `copyDir proc`_ - ## * `copyDirWithPermissions proc`_ - ## * `moveDir proc`_ - result = not rawCreateDir(dir) - if result: - # path already exists - need to check that it is indeed a directory - if not dirExists(dir): - raise newException(IOError, "Failed to create '" & dir & "'") - -proc createDir*(dir: string) {.rtl, extern: "nos$1", - tags: [WriteDirEffect, ReadDirEffect], noWeirdTarget.} = - ## Creates the `directory`:idx: `dir`. - ## - ## The directory may contain several subdirectories that do not exist yet. - ## The full path is created. If this fails, `OSError` is raised. - ## - ## It does **not** fail if the directory already exists because for - ## most usages this does not indicate an error. - ## - ## See also: - ## * `removeDir proc`_ - ## * `existsOrCreateDir proc`_ - ## * `copyDir proc`_ - ## * `copyDirWithPermissions proc`_ - ## * `moveDir proc`_ - if dir == "": - return - var omitNext = isAbsolute(dir) - for p in parentDirs(dir, fromRoot=true): - if omitNext: - omitNext = false - else: - discard existsOrCreateDir(p) - -proc copyDir*(source, dest: string) {.rtl, extern: "nos$1", - tags: [ReadDirEffect, WriteIOEffect, ReadIOEffect], benign, noWeirdTarget.} = - ## Copies a directory from `source` to `dest`. - ## - ## On non-Windows OSes, symlinks are copied as symlinks. On Windows, symlinks - ## are skipped. - ## - ## If this fails, `OSError` is raised. - ## - ## On the Windows platform this proc will copy the attributes from - ## `source` into `dest`. - ## - ## On other platforms created files and directories will inherit the - ## default permissions of a newly created file/directory for the user. - ## Use `copyDirWithPermissions proc`_ - ## to preserve attributes recursively on these platforms. - ## - ## See also: - ## * `copyDirWithPermissions proc`_ - ## * `copyFile proc`_ - ## * `copyFileWithPermissions proc`_ - ## * `removeDir proc`_ - ## * `existsOrCreateDir proc`_ - ## * `createDir proc`_ - ## * `moveDir proc`_ - createDir(dest) - for kind, path in walkDir(source): - var noSource = splitPath(path).tail - if kind == pcDir: - copyDir(path, dest / noSource) - else: - copyFile(path, dest / noSource, {cfSymlinkAsIs}) - - -proc copyDirWithPermissions*(source, dest: string, - ignorePermissionErrors = true) - {.rtl, extern: "nos$1", tags: [ReadDirEffect, WriteIOEffect, ReadIOEffect], - benign, noWeirdTarget.} = - ## Copies a directory from `source` to `dest` preserving file permissions. - ## - ## On non-Windows OSes, symlinks are copied as symlinks. On Windows, symlinks - ## are skipped. - ## - ## If this fails, `OSError` is raised. This is a wrapper proc around - ## `copyDir`_ and `copyFileWithPermissions`_ procs - ## on non-Windows platforms. - ## - ## On Windows this proc is just a wrapper for `copyDir proc`_ since - ## that proc already copies attributes. - ## - ## On non-Windows systems permissions are copied after the file or directory - ## itself has been copied, which won't happen atomically and could lead to a - ## race condition. If `ignorePermissionErrors` is true (default), errors while - ## reading/setting file attributes will be ignored, otherwise will raise - ## `OSError`. - ## - ## See also: - ## * `copyDir proc`_ - ## * `copyFile proc`_ - ## * `copyFileWithPermissions proc`_ - ## * `removeDir proc`_ - ## * `moveDir proc`_ - ## * `existsOrCreateDir proc`_ - ## * `createDir proc`_ - createDir(dest) - when not defined(windows): - try: - setFilePermissions(dest, getFilePermissions(source), followSymlinks = - false) - except: - if not ignorePermissionErrors: - raise - for kind, path in walkDir(source): - var noSource = splitPath(path).tail - if kind == pcDir: - copyDirWithPermissions(path, dest / noSource, ignorePermissionErrors) - else: - copyFileWithPermissions(path, dest / noSource, ignorePermissionErrors, {cfSymlinkAsIs}) - -proc moveDir*(source, dest: string) {.tags: [ReadIOEffect, WriteIOEffect], noWeirdTarget.} = - ## Moves a directory from `source` to `dest`. - ## - ## Symlinks are not followed: if `source` contains symlinks, they themself are - ## moved, not their target. - ## - ## If this fails, `OSError` is raised. - ## - ## See also: - ## * `moveFile proc`_ - ## * `copyDir proc`_ - ## * `copyDirWithPermissions proc`_ - ## * `removeDir proc`_ - ## * `existsOrCreateDir proc`_ - ## * `createDir proc`_ - if not tryMoveFSObject(source, dest, isDir = true): - # Fallback to copy & del - copyDir(source, dest) - removeDir(source) - -proc setCurrentDir*(newDir: string) {.inline, tags: [], noWeirdTarget.} = - ## Sets the `current working directory`:idx:; `OSError` - ## is raised if `newDir` cannot been set. - ## - ## See also: - ## * `getHomeDir proc`_ - ## * `getConfigDir proc`_ - ## * `getTempDir proc`_ - ## * `getCurrentDir proc`_ - when defined(windows): - if setCurrentDirectoryW(newWideCString(newDir)) == 0'i32: - raiseOSError(osLastError(), newDir) - else: - if chdir(newDir) != 0'i32: raiseOSError(osLastError(), newDir) diff --git a/lib/std/private/osfiles.nim b/lib/std/private/osfiles.nim deleted file mode 100644 index 7f822ffcc..000000000 --- a/lib/std/private/osfiles.nim +++ /dev/null @@ -1,403 +0,0 @@ -include system/inclrtl -import std/private/since -import std/oserrors - -import oscommon -export fileExists - -import ospaths2, ossymlinks - -## .. importdoc:: osdirs.nim, os.nim - -when defined(nimPreviewSlimSystem): - import std/[syncio, assertions, widestrs] - -when weirdTarget: - discard -elif defined(windows): - import winlean -elif defined(posix): - import posix, times - - proc toTime(ts: Timespec): times.Time {.inline.} = - result = initTime(ts.tv_sec.int64, ts.tv_nsec.int) -else: - {.error: "OS module not ported to your operating system!".} - - -when weirdTarget: - {.pragma: noWeirdTarget, error: "this proc is not available on the NimScript/js target".} -else: - {.pragma: noWeirdTarget.} - - -when defined(nimscript): - # for procs already defined in scriptconfig.nim - template noNimJs(body): untyped = discard -elif defined(js): - {.pragma: noNimJs, error: "this proc is not available on the js target".} -else: - {.pragma: noNimJs.} - - -type - FilePermission* = enum ## File access permission, modelled after UNIX. - ## - ## See also: - ## * `getFilePermissions`_ - ## * `setFilePermissions`_ - ## * `FileInfo object`_ - fpUserExec, ## execute access for the file owner - fpUserWrite, ## write access for the file owner - fpUserRead, ## read access for the file owner - fpGroupExec, ## execute access for the group - fpGroupWrite, ## write access for the group - fpGroupRead, ## read access for the group - fpOthersExec, ## execute access for others - fpOthersWrite, ## write access for others - fpOthersRead ## read access for others - -proc getFilePermissions*(filename: string): set[FilePermission] {. - rtl, extern: "nos$1", tags: [ReadDirEffect], noWeirdTarget.} = - ## Retrieves file permissions for `filename`. - ## - ## `OSError` is raised in case of an error. - ## On Windows, only the ``readonly`` flag is checked, every other - ## permission is available in any case. - ## - ## See also: - ## * `setFilePermissions proc`_ - ## * `FilePermission enum`_ - when defined(posix): - var a: Stat - if stat(filename, a) < 0'i32: raiseOSError(osLastError(), filename) - result = {} - if (a.st_mode and S_IRUSR.Mode) != 0.Mode: result.incl(fpUserRead) - if (a.st_mode and S_IWUSR.Mode) != 0.Mode: result.incl(fpUserWrite) - if (a.st_mode and S_IXUSR.Mode) != 0.Mode: result.incl(fpUserExec) - - if (a.st_mode and S_IRGRP.Mode) != 0.Mode: result.incl(fpGroupRead) - if (a.st_mode and S_IWGRP.Mode) != 0.Mode: result.incl(fpGroupWrite) - if (a.st_mode and S_IXGRP.Mode) != 0.Mode: result.incl(fpGroupExec) - - if (a.st_mode and S_IROTH.Mode) != 0.Mode: result.incl(fpOthersRead) - if (a.st_mode and S_IWOTH.Mode) != 0.Mode: result.incl(fpOthersWrite) - if (a.st_mode and S_IXOTH.Mode) != 0.Mode: result.incl(fpOthersExec) - else: - wrapUnary(res, getFileAttributesW, filename) - if res == -1'i32: raiseOSError(osLastError(), filename) - if (res and FILE_ATTRIBUTE_READONLY) != 0'i32: - result = {fpUserExec, fpUserRead, fpGroupExec, fpGroupRead, - fpOthersExec, fpOthersRead} - else: - result = {fpUserExec..fpOthersRead} - -proc setFilePermissions*(filename: string, permissions: set[FilePermission], - followSymlinks = true) - {.rtl, extern: "nos$1", tags: [ReadDirEffect, WriteDirEffect], - noWeirdTarget.} = - ## Sets the file permissions for `filename`. - ## - ## If `followSymlinks` set to true (default) and ``filename`` points to a - ## symlink, permissions are set to the file symlink points to. - ## `followSymlinks` set to false is a noop on Windows and some POSIX - ## systems (including Linux) on which `lchmod` is either unavailable or always - ## fails, given that symlinks permissions there are not observed. - ## - ## `OSError` is raised in case of an error. - ## On Windows, only the ``readonly`` flag is changed, depending on - ## ``fpUserWrite`` permission. - ## - ## See also: - ## * `getFilePermissions proc`_ - ## * `FilePermission enum`_ - when defined(posix): - var p = 0.Mode - if fpUserRead in permissions: p = p or S_IRUSR.Mode - if fpUserWrite in permissions: p = p or S_IWUSR.Mode - if fpUserExec in permissions: p = p or S_IXUSR.Mode - - if fpGroupRead in permissions: p = p or S_IRGRP.Mode - if fpGroupWrite in permissions: p = p or S_IWGRP.Mode - if fpGroupExec in permissions: p = p or S_IXGRP.Mode - - if fpOthersRead in permissions: p = p or S_IROTH.Mode - if fpOthersWrite in permissions: p = p or S_IWOTH.Mode - if fpOthersExec in permissions: p = p or S_IXOTH.Mode - - if not followSymlinks and filename.symlinkExists: - when declared(lchmod): - if lchmod(filename, cast[Mode](p)) != 0: - raiseOSError(osLastError(), $(filename, permissions)) - else: - if chmod(filename, cast[Mode](p)) != 0: - raiseOSError(osLastError(), $(filename, permissions)) - else: - wrapUnary(res, getFileAttributesW, filename) - if res == -1'i32: raiseOSError(osLastError(), filename) - if fpUserWrite in permissions: - res = res and not FILE_ATTRIBUTE_READONLY - else: - res = res or FILE_ATTRIBUTE_READONLY - wrapBinary(res2, setFileAttributesW, filename, res) - if res2 == - 1'i32: raiseOSError(osLastError(), $(filename, permissions)) - - -const hasCCopyfile = defined(osx) and not defined(nimLegacyCopyFile) - # xxx instead of `nimLegacyCopyFile`, support something like: `when osxVersion >= (10, 5)` - -when hasCCopyfile: - # `copyfile` API available since osx 10.5. - {.push nodecl, header: "".} - type - copyfile_state_t {.nodecl.} = pointer - copyfile_flags_t = cint - proc copyfile_state_alloc(): copyfile_state_t - proc copyfile_state_free(state: copyfile_state_t): cint - proc c_copyfile(src, dst: cstring, state: copyfile_state_t, flags: copyfile_flags_t): cint {.importc: "copyfile".} - # replace with `let` pending bootstrap >= 1.4.0 - var - COPYFILE_DATA {.nodecl.}: copyfile_flags_t - COPYFILE_XATTR {.nodecl.}: copyfile_flags_t - {.pop.} - -type - CopyFlag* = enum ## Copy options. - cfSymlinkAsIs, ## Copy symlinks as symlinks - cfSymlinkFollow, ## Copy the files symlinks point to - cfSymlinkIgnore ## Ignore symlinks - -const copyFlagSymlink = {cfSymlinkAsIs, cfSymlinkFollow, cfSymlinkIgnore} - -proc copyFile*(source, dest: string, options = {cfSymlinkFollow}) {.rtl, - extern: "nos$1", tags: [ReadDirEffect, ReadIOEffect, WriteIOEffect], - noWeirdTarget.} = - ## Copies a file from `source` to `dest`, where `dest.parentDir` must exist. - ## - ## On non-Windows OSes, `options` specify the way file is copied; by default, - ## if `source` is a symlink, copies the file symlink points to. `options` is - ## ignored on Windows: symlinks are skipped. - ## - ## If this fails, `OSError` is raised. - ## - ## On the Windows platform this proc will - ## copy the source file's attributes into dest. - ## - ## On other platforms you need - ## to use `getFilePermissions`_ and - ## `setFilePermissions`_ - ## procs - ## to copy them by hand (or use the convenience `copyFileWithPermissions - ## proc`_), - ## otherwise `dest` will inherit the default permissions of a newly - ## created file for the user. - ## - ## If `dest` already exists, the file attributes - ## will be preserved and the content overwritten. - ## - ## On OSX, `copyfile` C api will be used (available since OSX 10.5) unless - ## `-d:nimLegacyCopyFile` is used. - ## - ## See also: - ## * `CopyFlag enum`_ - ## * `copyDir proc`_ - ## * `copyFileWithPermissions proc`_ - ## * `tryRemoveFile proc`_ - ## * `removeFile proc`_ - ## * `moveFile proc`_ - - doAssert card(copyFlagSymlink * options) == 1, "There should be exactly " & - "one cfSymlink* in options" - let isSymlink = source.symlinkExists - if isSymlink and (cfSymlinkIgnore in options or defined(windows)): - return - when defined(windows): - let s = newWideCString(source) - let d = newWideCString(dest) - if copyFileW(s, d, 0'i32) == 0'i32: - raiseOSError(osLastError(), $(source, dest)) - else: - if isSymlink and cfSymlinkAsIs in options: - createSymlink(expandSymlink(source), dest) - else: - when hasCCopyfile: - let state = copyfile_state_alloc() - # xxx `COPYFILE_STAT` could be used for one-shot - # `copyFileWithPermissions`. - let status = c_copyfile(source.cstring, dest.cstring, state, - COPYFILE_DATA) - if status != 0: - let err = osLastError() - discard copyfile_state_free(state) - raiseOSError(err, $(source, dest)) - let status2 = copyfile_state_free(state) - if status2 != 0: raiseOSError(osLastError(), $(source, dest)) - else: - # generic version of copyFile which works for any platform: - const bufSize = 8000 # better for memory manager - var d, s: File - if not open(s, source):raiseOSError(osLastError(), source) - if not open(d, dest, fmWrite): - close(s) - raiseOSError(osLastError(), dest) - var buf = alloc(bufSize) - while true: - var bytesread = readBuffer(s, buf, bufSize) - if bytesread > 0: - var byteswritten = writeBuffer(d, buf, bytesread) - if bytesread != byteswritten: - dealloc(buf) - close(s) - close(d) - raiseOSError(osLastError(), dest) - if bytesread != bufSize: break - dealloc(buf) - close(s) - flushFile(d) - close(d) - -proc copyFileToDir*(source, dir: string, options = {cfSymlinkFollow}) - {.noWeirdTarget, since: (1,3,7).} = - ## Copies a file `source` into directory `dir`, which must exist. - ## - ## On non-Windows OSes, `options` specify the way file is copied; by default, - ## if `source` is a symlink, copies the file symlink points to. `options` is - ## ignored on Windows: symlinks are skipped. - ## - ## See also: - ## * `CopyFlag enum`_ - ## * `copyFile proc`_ - if dir.len == 0: # treating "" as "." is error prone - raise newException(ValueError, "dest is empty") - copyFile(source, dir / source.lastPathPart, options) - - -proc copyFileWithPermissions*(source, dest: string, - ignorePermissionErrors = true, - options = {cfSymlinkFollow}) {.noWeirdTarget.} = - ## Copies a file from `source` to `dest` preserving file permissions. - ## - ## On non-Windows OSes, `options` specify the way file is copied; by default, - ## if `source` is a symlink, copies the file symlink points to. `options` is - ## ignored on Windows: symlinks are skipped. - ## - ## This is a wrapper proc around `copyFile`_, - ## `getFilePermissions`_ and `setFilePermissions`_ - ## procs on non-Windows platforms. - ## - ## On Windows this proc is just a wrapper for `copyFile proc`_ since - ## that proc already copies attributes. - ## - ## On non-Windows systems permissions are copied after the file itself has - ## been copied, which won't happen atomically and could lead to a race - ## condition. If `ignorePermissionErrors` is true (default), errors while - ## reading/setting file attributes will be ignored, otherwise will raise - ## `OSError`. - ## - ## See also: - ## * `CopyFlag enum`_ - ## * `copyFile proc`_ - ## * `copyDir proc`_ - ## * `tryRemoveFile proc`_ - ## * `removeFile proc`_ - ## * `moveFile proc`_ - ## * `copyDirWithPermissions proc`_ - copyFile(source, dest, options) - when not defined(windows): - try: - setFilePermissions(dest, getFilePermissions(source), followSymlinks = - (cfSymlinkFollow in options)) - except: - if not ignorePermissionErrors: - raise - -when not declared(ENOENT) and not defined(windows): - when defined(nimscript): - when not defined(haiku): - const ENOENT = cint(2) # 2 on most systems including Solaris - else: - const ENOENT = cint(-2147459069) - else: - var ENOENT {.importc, header: "".}: cint - -when defined(windows) and not weirdTarget: - template deleteFile(file: untyped): untyped = deleteFileW(file) - template setFileAttributes(file, attrs: untyped): untyped = - setFileAttributesW(file, attrs) - -proc tryRemoveFile*(file: string): bool {.rtl, extern: "nos$1", tags: [WriteDirEffect], noWeirdTarget.} = - ## Removes the `file`. - ## - ## If this fails, returns `false`. This does not fail - ## if the file never existed in the first place. - ## - ## On Windows, ignores the read-only attribute. - ## - ## See also: - ## * `copyFile proc`_ - ## * `copyFileWithPermissions proc`_ - ## * `removeFile proc`_ - ## * `moveFile proc`_ - result = true - when defined(windows): - let f = newWideCString(file) - if deleteFile(f) == 0: - result = false - let err = getLastError() - if err == ERROR_FILE_NOT_FOUND or err == ERROR_PATH_NOT_FOUND: - result = true - elif err == ERROR_ACCESS_DENIED and - setFileAttributes(f, FILE_ATTRIBUTE_NORMAL) != 0 and - deleteFile(f) != 0: - result = true - else: - if unlink(file) != 0'i32 and errno != ENOENT: - result = false - -proc removeFile*(file: string) {.rtl, extern: "nos$1", tags: [WriteDirEffect], noWeirdTarget.} = - ## Removes the `file`. - ## - ## If this fails, `OSError` is raised. This does not fail - ## if the file never existed in the first place. - ## - ## On Windows, ignores the read-only attribute. - ## - ## See also: - ## * `removeDir proc`_ - ## * `copyFile proc`_ - ## * `copyFileWithPermissions proc`_ - ## * `tryRemoveFile proc`_ - ## * `moveFile proc`_ - if not tryRemoveFile(file): - raiseOSError(osLastError(), file) - -proc moveFile*(source, dest: string) {.rtl, extern: "nos$1", - tags: [ReadDirEffect, ReadIOEffect, WriteIOEffect], noWeirdTarget.} = - ## Moves a file from `source` to `dest`. - ## - ## Symlinks are not followed: if `source` is a symlink, it is itself moved, - ## not its target. - ## - ## If this fails, `OSError` is raised. - ## If `dest` already exists, it will be overwritten. - ## - ## Can be used to `rename files`:idx:. - ## - ## See also: - ## * `moveDir proc`_ - ## * `copyFile proc`_ - ## * `copyFileWithPermissions proc`_ - ## * `removeFile proc`_ - ## * `tryRemoveFile proc`_ - - if not tryMoveFSObject(source, dest, isDir = false): - when defined(windows): - doAssert false - else: - # Fallback to copy & del - copyFile(source, dest, {cfSymlinkAsIs}) - try: - removeFile(source) - except: - discard tryRemoveFile(dest) - raise diff --git a/lib/std/private/ospaths2.nim b/lib/std/private/ospaths2.nim deleted file mode 100644 index 612003023..000000000 --- a/lib/std/private/ospaths2.nim +++ /dev/null @@ -1,1017 +0,0 @@ -include system/inclrtl -import std/private/since - -import strutils, pathnorm -import std/oserrors - -import oscommon -export ReadDirEffect, WriteDirEffect - -when defined(nimPreviewSlimSystem): - import std/[syncio, assertions, widestrs] - -## .. importdoc:: osappdirs.nim, osdirs.nim, osseps.nim, os.nim - -const weirdTarget = defined(nimscript) or defined(js) - -when weirdTarget: - discard -elif defined(windows): - import winlean -elif defined(posix): - import posix, system/ansi_c -else: - {.error: "OS module not ported to your operating system!".} - -when weirdTarget: - {.pragma: noWeirdTarget, error: "this proc is not available on the NimScript/js target".} -else: - {.pragma: noWeirdTarget.} - -when defined(nimscript): - # for procs already defined in scriptconfig.nim - template noNimJs(body): untyped = discard -elif defined(js): - {.pragma: noNimJs, error: "this proc is not available on the js target".} -else: - {.pragma: noNimJs.} - - -proc normalizePathAux(path: var string){.inline, raises: [], noSideEffect.} - - -import std/private/osseps -export osseps - -proc absolutePathInternal(path: string): string {.gcsafe.} - -proc normalizePathEnd*(path: var string, trailingSep = false) = - ## Ensures ``path`` has exactly 0 or 1 trailing `DirSep`, depending on - ## ``trailingSep``, and taking care of edge cases: it preservers whether - ## a path is absolute or relative, and makes sure trailing sep is `DirSep`, - ## not `AltSep`. Trailing `/.` are compressed, see examples. - if path.len == 0: return - var i = path.len - while i >= 1: - if path[i-1] in {DirSep, AltSep}: dec(i) - elif path[i-1] == '.' and i >= 2 and path[i-2] in {DirSep, AltSep}: dec(i) - else: break - if trailingSep: - # foo// => foo - path.setLen(i) - # foo => foo/ - path.add DirSep - elif i > 0: - # foo// => foo - path.setLen(i) - else: - # // => / (empty case was already taken care of) - path = $DirSep - -proc normalizePathEnd*(path: string, trailingSep = false): string = - ## outplace overload - runnableExamples: - when defined(posix): - assert normalizePathEnd("/lib//.//", trailingSep = true) == "/lib/" - assert normalizePathEnd("lib/./.", trailingSep = false) == "lib" - assert normalizePathEnd(".//./.", trailingSep = false) == "." - assert normalizePathEnd("", trailingSep = true) == "" # not / ! - assert normalizePathEnd("/", trailingSep = false) == "/" # not "" ! - result = path - result.normalizePathEnd(trailingSep) - -template endsWith(a: string, b: set[char]): bool = - a.len > 0 and a[^1] in b - -proc joinPathImpl(result: var string, state: var int, tail: string) = - let trailingSep = tail.endsWith({DirSep, AltSep}) or tail.len == 0 and result.endsWith({DirSep, AltSep}) - normalizePathEnd(result, trailingSep=false) - addNormalizePath(tail, result, state, DirSep) - normalizePathEnd(result, trailingSep=trailingSep) - -proc joinPath*(head, tail: string): string {. - noSideEffect, rtl, extern: "nos$1".} = - ## Joins two directory names to one. - ## - ## returns normalized path concatenation of `head` and `tail`, preserving - ## whether or not `tail` has a trailing slash (or, if tail if empty, whether - ## head has one). - ## - ## See also: - ## * `joinPath(parts: varargs[string]) proc`_ - ## * `/ proc`_ - ## * `splitPath proc`_ - ## * `uri.combine proc `_ - ## * `uri./ proc `_ - runnableExamples: - when defined(posix): - assert joinPath("usr", "lib") == "usr/lib" - assert joinPath("usr", "lib/") == "usr/lib/" - assert joinPath("usr", "") == "usr" - assert joinPath("usr/", "") == "usr/" - assert joinPath("", "") == "" - assert joinPath("", "lib") == "lib" - assert joinPath("", "/lib") == "/lib" - assert joinPath("usr/", "/lib") == "usr/lib" - assert joinPath("usr/lib", "../bin") == "usr/bin" - - result = newStringOfCap(head.len + tail.len) - var state = 0 - joinPathImpl(result, state, head) - joinPathImpl(result, state, tail) - when false: - if len(head) == 0: - result = tail - elif head[len(head)-1] in {DirSep, AltSep}: - if tail.len > 0 and tail[0] in {DirSep, AltSep}: - result = head & substr(tail, 1) - else: - result = head & tail - else: - if tail.len > 0 and tail[0] in {DirSep, AltSep}: - result = head & tail - else: - result = head & DirSep & tail - -proc joinPath*(parts: varargs[string]): string {.noSideEffect, - rtl, extern: "nos$1OpenArray".} = - ## The same as `joinPath(head, tail) proc`_, - ## but works with any number of directory parts. - ## - ## You need to pass at least one element or the proc - ## will assert in debug builds and crash on release builds. - ## - ## See also: - ## * `joinPath(head, tail) proc`_ - ## * `/ proc`_ - ## * `/../ proc`_ - ## * `splitPath proc`_ - runnableExamples: - when defined(posix): - assert joinPath("a") == "a" - assert joinPath("a", "b", "c") == "a/b/c" - assert joinPath("usr/lib", "../../var", "log") == "var/log" - - var estimatedLen = 0 - for p in parts: estimatedLen += p.len - result = newStringOfCap(estimatedLen) - var state = 0 - for i in 0..high(parts): - joinPathImpl(result, state, parts[i]) - -proc `/`*(head, tail: string): string {.noSideEffect, inline.} = - ## The same as `joinPath(head, tail) proc`_. - ## - ## See also: - ## * `/../ proc`_ - ## * `joinPath(head, tail) proc`_ - ## * `joinPath(parts: varargs[string]) proc`_ - ## * `splitPath proc`_ - ## * `uri.combine proc `_ - ## * `uri./ proc `_ - runnableExamples: - when defined(posix): - assert "usr" / "" == "usr" - assert "" / "lib" == "lib" - assert "" / "/lib" == "/lib" - assert "usr/" / "/lib/" == "usr/lib/" - assert "usr" / "lib" / "../bin" == "usr/bin" - - result = joinPath(head, tail) - -when doslikeFileSystem: - import std/private/ntpath - -proc splitPath*(path: string): tuple[head, tail: string] {. - noSideEffect, rtl, extern: "nos$1".} = - ## Splits a directory into `(head, tail)` tuple, so that - ## ``head / tail == path`` (except for edge cases like "/usr"). - ## - ## See also: - ## * `joinPath(head, tail) proc`_ - ## * `joinPath(parts: varargs[string]) proc`_ - ## * `/ proc`_ - ## * `/../ proc`_ - ## * `relativePath proc`_ - runnableExamples: - assert splitPath("usr/local/bin") == ("usr/local", "bin") - assert splitPath("usr/local/bin/") == ("usr/local/bin", "") - assert splitPath("/bin/") == ("/bin", "") - when (NimMajor, NimMinor) <= (1, 0): - assert splitPath("/bin") == ("", "bin") - else: - assert splitPath("/bin") == ("/", "bin") - assert splitPath("bin") == ("", "bin") - assert splitPath("") == ("", "") - - when doslikeFileSystem: - let (drive, splitpath) = splitDrive(path) - let stop = drive.len - else: - const stop = 0 - - var sepPos = -1 - for i in countdown(len(path)-1, stop): - if path[i] in {DirSep, AltSep}: - sepPos = i - break - if sepPos >= 0: - result.head = substr(path, 0, - when (NimMajor, NimMinor) <= (1, 0): - sepPos-1 - else: - if likely(sepPos >= 1): sepPos-1 else: 0 - ) - result.tail = substr(path, sepPos+1) - else: - when doslikeFileSystem: - result.head = drive - result.tail = splitpath - else: - result.head = "" - result.tail = path - -proc isAbsolute*(path: string): bool {.rtl, noSideEffect, extern: "nos$1", raises: [].} = - ## Checks whether a given `path` is absolute. - ## - ## On Windows, network paths are considered absolute too. - runnableExamples: - assert not "".isAbsolute - assert not ".".isAbsolute - when defined(posix): - assert "/".isAbsolute - assert not "a/".isAbsolute - assert "/a/".isAbsolute - - if len(path) == 0: return false - - when doslikeFileSystem: - var len = len(path) - result = (path[0] in {'/', '\\'}) or - (len > 1 and path[0] in {'a'..'z', 'A'..'Z'} and path[1] == ':') - elif defined(macos): - # according to https://perldoc.perl.org/File/Spec/Mac.html `:a` is a relative path - result = path[0] != ':' - elif defined(RISCOS): - result = path[0] == '$' - elif defined(posix) or defined(js): - # `or defined(js)` wouldn't be needed pending https://github.com/nim-lang/Nim/issues/13469 - # This works around the problem for posix, but Windows is still broken with nim js -d:nodejs - result = path[0] == '/' - else: - doAssert false # if ever hits here, adapt as needed - -when FileSystemCaseSensitive: - template `!=?`(a, b: char): bool = a != b -else: - template `!=?`(a, b: char): bool = toLowerAscii(a) != toLowerAscii(b) - -when doslikeFileSystem: - proc isAbsFromCurrentDrive(path: string): bool {.noSideEffect, raises: [].} = - ## An absolute path from the root of the current drive (e.g. "\foo") - path.len > 0 and - (path[0] == AltSep or - (path[0] == DirSep and - (path.len == 1 or path[1] notin {DirSep, AltSep, ':'}))) - - proc sameRoot(path1, path2: string): bool {.noSideEffect, raises: [].} = - ## Return true if path1 and path2 have a same root. - ## - ## Detail of Windows path formats: - ## https://docs.microsoft.com/en-us/dotnet/standard/io/file-path-formats - - assert(isAbsolute(path1)) - assert(isAbsolute(path2)) - - if isAbsFromCurrentDrive(path1) and isAbsFromCurrentDrive(path2): - result = true - elif cmpIgnoreCase(splitDrive(path1).drive, splitDrive(path2).drive) == 0: - result = true - else: - result = false - -proc relativePath*(path, base: string, sep = DirSep): string {. - rtl, extern: "nos$1".} = - ## Converts `path` to a path relative to `base`. - ## - ## The `sep` (default: DirSep_) is used for the path normalizations, - ## this can be useful to ensure the relative path only contains `'/'` - ## so that it can be used for URL constructions. - ## - ## On Windows, if a root of `path` and a root of `base` are different, - ## returns `path` as is because it is impossible to make a relative path. - ## That means an absolute path can be returned. - ## - ## See also: - ## * `splitPath proc`_ - ## * `parentDir proc`_ - ## * `tailDir proc`_ - runnableExamples: - assert relativePath("/Users/me/bar/z.nim", "/Users/other/bad", '/') == "../../me/bar/z.nim" - assert relativePath("/Users/me/bar/z.nim", "/Users/other", '/') == "../me/bar/z.nim" - when not doslikeFileSystem: # On Windows, UNC-paths start with `//` - assert relativePath("/Users///me/bar//z.nim", "//Users/", '/') == "me/bar/z.nim" - assert relativePath("/Users/me/bar/z.nim", "/Users/me", '/') == "bar/z.nim" - assert relativePath("", "/users/moo", '/') == "" - assert relativePath("foo", ".", '/') == "foo" - assert relativePath("foo", "foo", '/') == "." - - if path.len == 0: return "" - var base = if base == ".": "" else: base - var path = path - path.normalizePathAux - base.normalizePathAux - let a1 = isAbsolute(path) - let a2 = isAbsolute(base) - if a1 and not a2: - base = absolutePathInternal(base) - elif a2 and not a1: - path = absolutePathInternal(path) - - when doslikeFileSystem: - if isAbsolute(path) and isAbsolute(base): - if not sameRoot(path, base): - return path - - var f = default PathIter - var b = default PathIter - var ff = (0, -1) - var bb = (0, -1) # (int, int) - result = newStringOfCap(path.len) - # skip the common prefix: - while f.hasNext(path) and b.hasNext(base): - ff = next(f, path) - bb = next(b, base) - let diff = ff[1] - ff[0] - if diff != bb[1] - bb[0]: break - var same = true - for i in 0..diff: - if path[i + ff[0]] !=? base[i + bb[0]]: - same = false - break - if not same: break - ff = (0, -1) - bb = (0, -1) - # for i in 0..diff: - # result.add base[i + bb[0]] - - # /foo/bar/xxx/ -- base - # /foo/bar/baz -- path path - # ../baz - # every directory that is in 'base', needs to add '..' - while true: - if bb[1] >= bb[0]: - if result.len > 0 and result[^1] != sep: - result.add sep - result.add ".." - if not b.hasNext(base): break - bb = b.next(base) - - # add the rest of 'path': - while true: - if ff[1] >= ff[0]: - if result.len > 0 and result[^1] != sep: - result.add sep - for i in 0..ff[1] - ff[0]: - result.add path[i + ff[0]] - if not f.hasNext(path): break - ff = f.next(path) - - when not defined(nimOldRelativePathBehavior): - if result.len == 0: result.add "." - -proc isRelativeTo*(path: string, base: string): bool {.since: (1, 1).} = - ## Returns true if `path` is relative to `base`. - runnableExamples: - doAssert isRelativeTo("./foo//bar", "foo") - doAssert isRelativeTo("foo/bar", ".") - doAssert isRelativeTo("/foo/bar.nim", "/foo/bar.nim") - doAssert not isRelativeTo("foo/bar.nims", "foo/bar.nim") - let path = path.normalizePath - let base = base.normalizePath - let ret = relativePath(path, base) - result = path.len > 0 and not ret.startsWith ".." - -proc parentDirPos(path: string): int = - var q = 1 - if len(path) >= 1 and path[len(path)-1] in {DirSep, AltSep}: q = 2 - for i in countdown(len(path)-q, 0): - if path[i] in {DirSep, AltSep}: return i - result = -1 - -proc parentDir*(path: string): string {. - noSideEffect, rtl, extern: "nos$1".} = - ## Returns the parent directory of `path`. - ## - ## This is similar to ``splitPath(path).head`` when ``path`` doesn't end - ## in a dir separator, but also takes care of path normalizations. - ## The remainder can be obtained with `lastPathPart(path) proc`_. - ## - ## See also: - ## * `relativePath proc`_ - ## * `splitPath proc`_ - ## * `tailDir proc`_ - ## * `parentDirs iterator`_ - runnableExamples: - assert parentDir("") == "" - when defined(posix): - assert parentDir("/usr/local/bin") == "/usr/local" - assert parentDir("foo/bar//") == "foo" - assert parentDir("//foo//bar//.") == "/foo" - assert parentDir("./foo") == "." - assert parentDir("/./foo//./") == "/" - assert parentDir("a//./") == "." - assert parentDir("a/b/c/..") == "a" - result = pathnorm.normalizePath(path) - when doslikeFileSystem: - let (drive, splitpath) = splitDrive(result) - result = splitpath - var sepPos = parentDirPos(result) - if sepPos >= 0: - result = substr(result, 0, sepPos) - normalizePathEnd(result) - elif result == ".." or result == "." or result.len == 0 or result[^1] in {DirSep, AltSep}: - # `.` => `..` and .. => `../..`(etc) would be a sensible alternative - # `/` => `/` (as done with splitFile) would be a sensible alternative - result = "" - else: - result = "." - when doslikeFileSystem: - if result.len == 0: - discard - elif drive.len > 0 and result.len == 1 and result[0] in {DirSep, AltSep}: - result = drive - else: - result = drive & result - -proc tailDir*(path: string): string {. - noSideEffect, rtl, extern: "nos$1".} = - ## Returns the tail part of `path`. - ## - ## See also: - ## * `relativePath proc`_ - ## * `splitPath proc`_ - ## * `parentDir proc`_ - runnableExamples: - assert tailDir("/bin") == "bin" - assert tailDir("bin") == "" - assert tailDir("bin/") == "" - assert tailDir("/usr/local/bin") == "usr/local/bin" - assert tailDir("//usr//local//bin//") == "usr//local//bin//" - assert tailDir("./usr/local/bin") == "usr/local/bin" - assert tailDir("usr/local/bin") == "local/bin" - - var i = 0 - when doslikeFileSystem: - let (drive, splitpath) = path.splitDrive - if drive != "": - return splitpath.strip(chars = {DirSep, AltSep}, trailing = false) - while i < len(path): - if path[i] in {DirSep, AltSep}: - while i < len(path) and path[i] in {DirSep, AltSep}: inc i - return substr(path, i) - inc i - result = "" - -proc isRootDir*(path: string): bool {. - noSideEffect, rtl, extern: "nos$1".} = - ## Checks whether a given `path` is a root directory. - runnableExamples: - assert isRootDir("") - assert isRootDir(".") - assert isRootDir("/") - assert isRootDir("a") - assert not isRootDir("/a") - assert not isRootDir("a/b/c") - - when doslikeFileSystem: - if splitDrive(path).path == "": - return true - result = parentDirPos(path) < 0 - -iterator parentDirs*(path: string, fromRoot=false, inclusive=true): string = - ## Walks over all parent directories of a given `path`. - ## - ## If `fromRoot` is true (default: false), the traversal will start from - ## the file system root directory. - ## If `inclusive` is true (default), the original argument will be included - ## in the traversal. - ## - ## Relative paths won't be expanded by this iterator. Instead, it will traverse - ## only the directories appearing in the relative path. - ## - ## See also: - ## * `parentDir proc`_ - ## - runnableExamples: - let g = "a/b/c" - - for p in g.parentDirs: - echo p - # a/b/c - # a/b - # a - - for p in g.parentDirs(fromRoot=true): - echo p - # a/ - # a/b/ - # a/b/c - - for p in g.parentDirs(inclusive=false): - echo p - # a/b - # a - - if not fromRoot: - var current = path - if inclusive: yield path - while true: - if current.isRootDir: break - current = current.parentDir - yield current - else: - when doslikeFileSystem: - let start = path.splitDrive.drive.len - else: - const start = 0 - for i in countup(start, path.len - 2): # ignore the last / - # deal with non-normalized paths such as /foo//bar//baz - if path[i] in {DirSep, AltSep} and - (i == 0 or path[i-1] notin {DirSep, AltSep}): - yield path.substr(0, i) - - if inclusive: yield path - -proc `/../`*(head, tail: string): string {.noSideEffect.} = - ## The same as ``parentDir(head) / tail``, unless there is no parent - ## directory. Then ``head / tail`` is performed instead. - ## - ## See also: - ## * `/ proc`_ - ## * `parentDir proc`_ - runnableExamples: - when defined(posix): - assert "a/b/c" /../ "d/e" == "a/b/d/e" - assert "a" /../ "d/e" == "a/d/e" - - when doslikeFileSystem: - let (drive, head) = splitDrive(head) - let sepPos = parentDirPos(head) - if sepPos >= 0: - result = substr(head, 0, sepPos-1) / tail - else: - result = head / tail - when doslikeFileSystem: - result = drive / result - -proc normExt(ext: string): string = - if ext == "" or ext[0] == ExtSep: result = ext # no copy needed here - else: result = ExtSep & ext - -proc searchExtPos*(path: string): int = - ## Returns index of the `'.'` char in `path` if it signifies the beginning - ## of the file extension. Returns -1 otherwise. - ## - ## See also: - ## * `splitFile proc`_ - ## * `extractFilename proc`_ - ## * `lastPathPart proc`_ - ## * `changeFileExt proc`_ - ## * `addFileExt proc`_ - runnableExamples: - assert searchExtPos("a/b/c") == -1 - assert searchExtPos("c.nim") == 1 - assert searchExtPos("a/b/c.nim") == 5 - assert searchExtPos("a.b.c.nim") == 5 - - # BUGFIX: do not search until 0! .DS_Store is no file extension! - result = -1 - for i in countdown(len(path)-1, 1): - if path[i] == ExtSep: - result = i - break - elif path[i] in {DirSep, AltSep}: - break # do not skip over path - -proc splitFile*(path: string): tuple[dir, name, ext: string] {. - noSideEffect, rtl, extern: "nos$1".} = - ## Splits a filename into `(dir, name, extension)` tuple. - ## - ## `dir` does not end in DirSep_ unless it's `/`. - ## `extension` includes the leading dot. - ## - ## If `path` has no extension, `ext` is the empty string. - ## If `path` has no directory component, `dir` is the empty string. - ## If `path` has no filename component, `name` and `ext` are empty strings. - ## - ## See also: - ## * `searchExtPos proc`_ - ## * `extractFilename proc`_ - ## * `lastPathPart proc`_ - ## * `changeFileExt proc`_ - ## * `addFileExt proc`_ - runnableExamples: - var (dir, name, ext) = splitFile("usr/local/nimc.html") - assert dir == "usr/local" - assert name == "nimc" - assert ext == ".html" - (dir, name, ext) = splitFile("/usr/local/os") - assert dir == "/usr/local" - assert name == "os" - assert ext == "" - (dir, name, ext) = splitFile("/usr/local/") - assert dir == "/usr/local" - assert name == "" - assert ext == "" - (dir, name, ext) = splitFile("/tmp.txt") - assert dir == "/" - assert name == "tmp" - assert ext == ".txt" - - var namePos = 0 - var dotPos = 0 - when doslikeFileSystem: - let (drive, _) = splitDrive(path) - let stop = len(drive) - result.dir = drive - else: - const stop = 0 - for i in countdown(len(path) - 1, stop): - if path[i] in {DirSep, AltSep} or i == 0: - if path[i] in {DirSep, AltSep}: - result.dir = substr(path, 0, if likely(i >= 1): i - 1 else: 0) - namePos = i + 1 - if dotPos > i: - result.name = substr(path, namePos, dotPos - 1) - result.ext = substr(path, dotPos) - else: - result.name = substr(path, namePos) - break - elif path[i] == ExtSep and i > 0 and i < len(path) - 1 and - path[i - 1] notin {DirSep, AltSep} and - path[i + 1] != ExtSep and dotPos == 0: - dotPos = i - -proc extractFilename*(path: string): string {. - noSideEffect, rtl, extern: "nos$1".} = - ## Extracts the filename of a given `path`. - ## - ## This is the same as ``name & ext`` from `splitFile(path) proc`_. - ## - ## See also: - ## * `searchExtPos proc`_ - ## * `splitFile proc`_ - ## * `lastPathPart proc`_ - ## * `changeFileExt proc`_ - ## * `addFileExt proc`_ - runnableExamples: - assert extractFilename("foo/bar/") == "" - assert extractFilename("foo/bar") == "bar" - assert extractFilename("foo/bar.baz") == "bar.baz" - - if path.len == 0 or path[path.len-1] in {DirSep, AltSep}: - result = "" - else: - result = splitPath(path).tail - -proc lastPathPart*(path: string): string {. - noSideEffect, rtl, extern: "nos$1".} = - ## Like `extractFilename proc`_, but ignores - ## trailing dir separator; aka: `baseName`:idx: in some other languages. - ## - ## See also: - ## * `searchExtPos proc`_ - ## * `splitFile proc`_ - ## * `extractFilename proc`_ - ## * `changeFileExt proc`_ - ## * `addFileExt proc`_ - runnableExamples: - assert lastPathPart("foo/bar/") == "bar" - assert lastPathPart("foo/bar") == "bar" - - let path = path.normalizePathEnd(trailingSep = false) - result = extractFilename(path) - -proc changeFileExt*(filename, ext: string): string {. - noSideEffect, rtl, extern: "nos$1".} = - ## Changes the file extension to `ext`. - ## - ## If the `filename` has no extension, `ext` will be added. - ## If `ext` == "" then any extension is removed. - ## - ## `Ext` should be given without the leading `'.'`, because some - ## filesystems may use a different character. (Although I know - ## of none such beast.) - ## - ## See also: - ## * `searchExtPos proc`_ - ## * `splitFile proc`_ - ## * `extractFilename proc`_ - ## * `lastPathPart proc`_ - ## * `addFileExt proc`_ - runnableExamples: - assert changeFileExt("foo.bar", "baz") == "foo.baz" - assert changeFileExt("foo.bar", "") == "foo" - assert changeFileExt("foo", "baz") == "foo.baz" - - var extPos = searchExtPos(filename) - if extPos < 0: result = filename & normExt(ext) - else: result = substr(filename, 0, extPos-1) & normExt(ext) - -proc addFileExt*(filename, ext: string): string {. - noSideEffect, rtl, extern: "nos$1".} = - ## Adds the file extension `ext` to `filename`, unless - ## `filename` already has an extension. - ## - ## `Ext` should be given without the leading `'.'`, because some - ## filesystems may use a different character. - ## (Although I know of none such beast.) - ## - ## See also: - ## * `searchExtPos proc`_ - ## * `splitFile proc`_ - ## * `extractFilename proc`_ - ## * `lastPathPart proc`_ - ## * `changeFileExt proc`_ - runnableExamples: - assert addFileExt("foo.bar", "baz") == "foo.bar" - assert addFileExt("foo.bar", "") == "foo.bar" - assert addFileExt("foo", "baz") == "foo.baz" - - var extPos = searchExtPos(filename) - if extPos < 0: result = filename & normExt(ext) - else: result = filename - -proc cmpPaths*(pathA, pathB: string): int {. - noSideEffect, rtl, extern: "nos$1".} = - ## Compares two paths. - ## - ## On a case-sensitive filesystem this is done - ## case-sensitively otherwise case-insensitively. Returns: - ## - ## | 0 if pathA == pathB - ## | < 0 if pathA < pathB - ## | > 0 if pathA > pathB - runnableExamples: - when defined(macosx): - assert cmpPaths("foo", "Foo") == 0 - elif defined(posix): - assert cmpPaths("foo", "Foo") > 0 - - let a = normalizePath(pathA) - let b = normalizePath(pathB) - if FileSystemCaseSensitive: - result = cmp(a, b) - else: - when defined(nimscript): - result = cmpic(a, b) - elif defined(nimdoc): discard - else: - result = cmpIgnoreCase(a, b) - -proc unixToNativePath*(path: string, drive=""): string {. - noSideEffect, rtl, extern: "nos$1".} = - ## Converts an UNIX-like path to a native one. - ## - ## On an UNIX system this does nothing. Else it converts - ## `'/'`, `'.'`, `'..'` to the appropriate things. - ## - ## On systems with a concept of "drives", `drive` is used to determine - ## which drive label to use during absolute path conversion. - ## `drive` defaults to the drive of the current working directory, and is - ## ignored on systems that do not have a concept of "drives". - when defined(unix): - result = path - else: - if path.len == 0: return "" - - var start: int - if path[0] == '/': - # an absolute path - when doslikeFileSystem: - if drive != "": - result = drive & ":" & DirSep - else: - result = $DirSep - elif defined(macos): - result = "" # must not start with ':' - else: - result = $DirSep - start = 1 - elif path[0] == '.' and (path.len == 1 or path[1] == '/'): - # current directory - result = $CurDir - start = when doslikeFileSystem: 1 else: 2 - else: - result = "" - start = 0 - - var i = start - while i < len(path): # ../../../ --> :::: - if i+2 < path.len and path[i] == '.' and path[i+1] == '.' and path[i+2] == '/': - # parent directory - when defined(macos): - if result[high(result)] == ':': - add result, ':' - else: - add result, ParDir - else: - add result, ParDir & DirSep - inc(i, 3) - elif path[i] == '/': - add result, DirSep - inc(i) - else: - add result, path[i] - inc(i) - - -when not defined(nimscript): - proc getCurrentDir*(): string {.rtl, extern: "nos$1", tags: [].} = - ## Returns the `current working directory`:idx: i.e. where the built - ## binary is run. - ## - ## So the path returned by this proc is determined at run time. - ## - ## See also: - ## * `getHomeDir proc`_ - ## * `getConfigDir proc`_ - ## * `getTempDir proc`_ - ## * `setCurrentDir proc`_ - ## * `currentSourcePath template `_ - ## * `getProjectPath proc `_ - when defined(nodejs): - var ret: cstring - {.emit: "`ret` = process.cwd();".} - return $ret - elif defined(js): - doAssert false, "use -d:nodejs to have `getCurrentDir` defined" - elif defined(windows): - var bufsize = MAX_PATH.int32 - var res = newWideCString("", bufsize) - while true: - var L = getCurrentDirectoryW(bufsize, res) - if L == 0'i32: - raiseOSError(osLastError()) - elif L > bufsize: - res = newWideCString("", L) - bufsize = L - else: - result = res$L - break - else: - var bufsize = 1024 # should be enough - result = newString(bufsize) - while true: - if getcwd(result.cstring, bufsize) != nil: - setLen(result, c_strlen(result.cstring)) - break - else: - let err = osLastError() - if err.int32 == ERANGE: - bufsize = bufsize shl 1 - doAssert(bufsize >= 0) - result = newString(bufsize) - else: - raiseOSError(osLastError()) - -proc absolutePath*(path: string, root = getCurrentDir()): string = - ## Returns the absolute path of `path`, rooted at `root` (which must be absolute; - ## default: current directory). - ## If `path` is absolute, return it, ignoring `root`. - ## - ## See also: - ## * `normalizedPath proc`_ - ## * `normalizePath proc`_ - runnableExamples: - assert absolutePath("a") == getCurrentDir() / "a" - - if isAbsolute(path): path - else: - if not root.isAbsolute: - raise newException(ValueError, "The specified root is not absolute: " & root) - joinPath(root, path) - -proc absolutePathInternal(path: string): string = - absolutePath(path, getCurrentDir()) - - -proc normalizePath*(path: var string) {.rtl, extern: "nos$1", tags: [].} = - ## Normalize a path. - ## - ## Consecutive directory separators are collapsed, including an initial double slash. - ## - ## On relative paths, double dot (`..`) sequences are collapsed if possible. - ## On absolute paths they are always collapsed. - ## - ## .. warning:: URL-encoded and Unicode attempts at directory traversal are not detected. - ## Triple dot is not handled. - ## - ## See also: - ## * `absolutePath proc`_ - ## * `normalizedPath proc`_ for outplace version - ## * `normalizeExe proc`_ - runnableExamples: - when defined(posix): - var a = "a///b//..//c///d" - a.normalizePath() - assert a == "a/c/d" - - path = pathnorm.normalizePath(path) - when false: - let isAbs = isAbsolute(path) - var stack: seq[string] = @[] - for p in split(path, {DirSep}): - case p - of "", ".": - continue - of "..": - if stack.len == 0: - if isAbs: - discard # collapse all double dots on absoluta paths - else: - stack.add(p) - elif stack[^1] == "..": - stack.add(p) - else: - discard stack.pop() - else: - stack.add(p) - - if isAbs: - path = DirSep & join(stack, $DirSep) - elif stack.len > 0: - path = join(stack, $DirSep) - else: - path = "." - -proc normalizePathAux(path: var string) = normalizePath(path) - -proc normalizedPath*(path: string): string {.rtl, extern: "nos$1", tags: [].} = - ## Returns a normalized path for the current OS. - ## - ## See also: - ## * `absolutePath proc`_ - ## * `normalizePath proc`_ for the in-place version - runnableExamples: - when defined(posix): - assert normalizedPath("a///b//..//c///d") == "a/c/d" - result = pathnorm.normalizePath(path) - -proc normalizeExe*(file: var string) {.since: (1, 3, 5).} = - ## on posix, prepends `./` if `file` doesn't contain `/` and is not `"", ".", ".."`. - runnableExamples: - import std/sugar - when defined(posix): - doAssert "foo".dup(normalizeExe) == "./foo" - doAssert "foo/../bar".dup(normalizeExe) == "foo/../bar" - doAssert "".dup(normalizeExe) == "" - when defined(posix): - if file.len > 0 and DirSep notin file and file != "." and file != "..": - file = "./" & file - -proc sameFile*(path1, path2: string): bool {.rtl, extern: "nos$1", - tags: [ReadDirEffect], noWeirdTarget.} = - ## Returns true if both pathname arguments refer to the same physical - ## file or directory. - ## - ## Raises `OSError` if any of the files does not - ## exist or information about it can not be obtained. - ## - ## This proc will return true if given two alternative hard-linked or - ## sym-linked paths to the same file or directory. - ## - ## See also: - ## * `sameFileContent proc`_ - when defined(windows): - var success = true - var f1 = openHandle(path1) - var f2 = openHandle(path2) - - var lastErr: OSErrorCode - if f1 != INVALID_HANDLE_VALUE and f2 != INVALID_HANDLE_VALUE: - var fi1, fi2: BY_HANDLE_FILE_INFORMATION - - if getFileInformationByHandle(f1, addr(fi1)) != 0 and - getFileInformationByHandle(f2, addr(fi2)) != 0: - result = fi1.dwVolumeSerialNumber == fi2.dwVolumeSerialNumber and - fi1.nFileIndexHigh == fi2.nFileIndexHigh and - fi1.nFileIndexLow == fi2.nFileIndexLow - else: - lastErr = osLastError() - success = false - else: - lastErr = osLastError() - success = false - - discard closeHandle(f1) - discard closeHandle(f2) - - if not success: raiseOSError(lastErr, $(path1, path2)) - else: - var a, b: Stat - if stat(path1, a) < 0'i32 or stat(path2, b) < 0'i32: - raiseOSError(osLastError(), $(path1, path2)) - else: - result = a.st_dev == b.st_dev and a.st_ino == b.st_ino diff --git a/lib/std/private/ossymlinks.nim b/lib/std/private/ossymlinks.nim deleted file mode 100644 index 18737b8b5..000000000 --- a/lib/std/private/ossymlinks.nim +++ /dev/null @@ -1,76 +0,0 @@ -include system/inclrtl -import std/oserrors - -import oscommon -export symlinkExists - -when defined(nimPreviewSlimSystem): - import std/[syncio, assertions, widestrs] - -when weirdTarget: - discard -elif defined(windows): - import winlean, times -elif defined(posix): - import posix -else: - {.error: "OS module not ported to your operating system!".} - - -when weirdTarget: - {.pragma: noWeirdTarget, error: "this proc is not available on the NimScript/js target".} -else: - {.pragma: noWeirdTarget.} - - -when defined(nimscript): - # for procs already defined in scriptconfig.nim - template noNimJs(body): untyped = discard -elif defined(js): - {.pragma: noNimJs, error: "this proc is not available on the js target".} -else: - {.pragma: noNimJs.} - -## .. importdoc:: os.nim - -proc createSymlink*(src, dest: string) {.noWeirdTarget.} = - ## Create a symbolic link at `dest` which points to the item specified - ## by `src`. On most operating systems, will fail if a link already exists. - ## - ## .. warning:: Some OS's (such as Microsoft Windows) restrict the creation - ## of symlinks to root users (administrators) or users with developer mode enabled. - ## - ## See also: - ## * `createHardlink proc`_ - ## * `expandSymlink proc`_ - - when defined(windows): - const SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE = 2 - # allows anyone with developer mode on to create a link - let flag = dirExists(src).int32 or SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE - var wSrc = newWideCString(src) - var wDst = newWideCString(dest) - if createSymbolicLinkW(wDst, wSrc, flag) == 0 or getLastError() != 0: - raiseOSError(osLastError(), $(src, dest)) - else: - if symlink(src, dest) != 0: - raiseOSError(osLastError(), $(src, dest)) - -proc expandSymlink*(symlinkPath: string): string {.noWeirdTarget.} = - ## Returns a string representing the path to which the symbolic link points. - ## - ## On Windows this is a noop, `symlinkPath` is simply returned. - ## - ## See also: - ## * `createSymlink proc`_ - when defined(windows) or defined(nintendoswitch): - result = symlinkPath - else: - result = newString(maxSymlinkLen) - var len = readlink(symlinkPath, result.cstring, maxSymlinkLen) - if len < 0: - raiseOSError(osLastError(), symlinkPath) - if len > maxSymlinkLen: - result = newString(len+1) - len = readlink(symlinkPath, result.cstring, len) - setLen(result, len) diff --git a/lib/std/private/schubfach.nim b/lib/std/private/schubfach.nim deleted file mode 100644 index dad8363ba..000000000 --- a/lib/std/private/schubfach.nim +++ /dev/null @@ -1,436 +0,0 @@ -## Copyright 2020 Alexander Bolz -## -## Distributed under the Boost Software License, Version 1.0. -## (See accompanying file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt) - -# -------------------------------------------------------------------------------------------------- -## This file contains an implementation of the Schubfach algorithm as described in -## -## \[1] Raffaello Giulietti, "The Schubfach way to render doubles", -## https://drive.google.com/open?id=1luHhyQF9zKlM8yJ1nebU0OgVYhfC6CBN -# -------------------------------------------------------------------------------------------------- - -import std/private/digitsutils - -when defined(nimPreviewSlimSystem): - import std/assertions - - -template sf_Assert(x: untyped): untyped = - assert(x) - -# ================================================================================================== -# -# ================================================================================================== - -type - ValueType = float32 - BitsType = uint32 - Single {.bycopy.} = object - bits: BitsType - -const - significandSize: int32 = 24 - MaxExponent = 128 - exponentBias: int32 = MaxExponent - 1 + (significandSize - 1) - maxIeeeExponent: BitsType = BitsType(2 * MaxExponent - 1) - hiddenBit: BitsType = BitsType(1) shl (significandSize - 1) - significandMask: BitsType = hiddenBit - 1 - exponentMask: BitsType = maxIeeeExponent shl (significandSize - 1) - signMask: BitsType = not (not BitsType(0) shr 1) - -proc constructSingle(bits: BitsType): Single {.constructor.} = - result.bits = bits - -proc constructSingle(value: ValueType): Single {.constructor.} = - result.bits = cast[typeof(result.bits)](value) - -proc physicalSignificand(this: Single): BitsType {.noSideEffect.} = - return this.bits and significandMask - -proc physicalExponent(this: Single): BitsType {.noSideEffect.} = - return (this.bits and exponentMask) shr (significandSize - 1) - -proc isFinite(this: Single): bool {.noSideEffect.} = - return (this.bits and exponentMask) != exponentMask - -proc isInf(this: Single): bool {.noSideEffect.} = - return (this.bits and exponentMask) == exponentMask and - (this.bits and significandMask) == 0 - -proc isNaN(this: Single): bool {.noSideEffect.} = - return (this.bits and exponentMask) == exponentMask and - (this.bits and significandMask) != 0 - -proc isZero(this: Single): bool {.noSideEffect.} = - return (this.bits and not signMask) == 0 - -proc signBit(this: Single): int {.noSideEffect.} = - return int((this.bits and signMask) != 0) - -# ================================================================================================== -## Returns floor(x / 2^n). -## -## Technically, right-shift of negative integers is implementation defined... -## Should easily be optimized into SAR (or equivalent) instruction. - -proc floorDivPow2(x: int32; n: int32): int32 {.inline.} = - return x shr n - -## Returns floor(log_10(2^e)) -## ```c -## static inline int32_t FloorLog10Pow2(int32_t e) -## { -## SF_ASSERT(e >= -1500); -## SF_ASSERT(e <= 1500); -## return FloorDivPow2(e * 1262611, 22); -## } -## ``` -## Returns floor(log_10(3/4 2^e)) -## ```c -## static inline int32_t FloorLog10ThreeQuartersPow2(int32_t e) -## { -## SF_ASSERT(e >= -1500); -## SF_ASSERT(e <= 1500); -## return FloorDivPow2(e * 1262611 - 524031, 22); -## } -## ``` -## Returns floor(log_2(10^e)) - -proc floorLog2Pow10(e: int32): int32 {.inline.} = - sf_Assert(e >= -1233) - sf_Assert(e <= 1233) - return floorDivPow2(e * 1741647, 19) - -const - kMin: int32 = -31 - kMax: int32 = 45 - g: array[kMax - kMin + 1, uint64] = [0x81CEB32C4B43FCF5'u64, 0xA2425FF75E14FC32'u64, - 0xCAD2F7F5359A3B3F'u64, 0xFD87B5F28300CA0E'u64, 0x9E74D1B791E07E49'u64, - 0xC612062576589DDB'u64, 0xF79687AED3EEC552'u64, 0x9ABE14CD44753B53'u64, - 0xC16D9A0095928A28'u64, 0xF1C90080BAF72CB2'u64, 0x971DA05074DA7BEF'u64, - 0xBCE5086492111AEB'u64, 0xEC1E4A7DB69561A6'u64, 0x9392EE8E921D5D08'u64, - 0xB877AA3236A4B44A'u64, 0xE69594BEC44DE15C'u64, 0x901D7CF73AB0ACDA'u64, - 0xB424DC35095CD810'u64, 0xE12E13424BB40E14'u64, 0x8CBCCC096F5088CC'u64, - 0xAFEBFF0BCB24AAFF'u64, 0xDBE6FECEBDEDD5BF'u64, 0x89705F4136B4A598'u64, - 0xABCC77118461CEFD'u64, 0xD6BF94D5E57A42BD'u64, 0x8637BD05AF6C69B6'u64, - 0xA7C5AC471B478424'u64, 0xD1B71758E219652C'u64, 0x83126E978D4FDF3C'u64, - 0xA3D70A3D70A3D70B'u64, 0xCCCCCCCCCCCCCCCD'u64, 0x8000000000000000'u64, - 0xA000000000000000'u64, 0xC800000000000000'u64, 0xFA00000000000000'u64, - 0x9C40000000000000'u64, 0xC350000000000000'u64, 0xF424000000000000'u64, - 0x9896800000000000'u64, 0xBEBC200000000000'u64, 0xEE6B280000000000'u64, - 0x9502F90000000000'u64, 0xBA43B74000000000'u64, 0xE8D4A51000000000'u64, - 0x9184E72A00000000'u64, 0xB5E620F480000000'u64, 0xE35FA931A0000000'u64, - 0x8E1BC9BF04000000'u64, 0xB1A2BC2EC5000000'u64, 0xDE0B6B3A76400000'u64, - 0x8AC7230489E80000'u64, 0xAD78EBC5AC620000'u64, 0xD8D726B7177A8000'u64, - 0x878678326EAC9000'u64, 0xA968163F0A57B400'u64, 0xD3C21BCECCEDA100'u64, - 0x84595161401484A0'u64, 0xA56FA5B99019A5C8'u64, 0xCECB8F27F4200F3A'u64, - 0x813F3978F8940985'u64, 0xA18F07D736B90BE6'u64, 0xC9F2C9CD04674EDF'u64, - 0xFC6F7C4045812297'u64, 0x9DC5ADA82B70B59E'u64, 0xC5371912364CE306'u64, - 0xF684DF56C3E01BC7'u64, 0x9A130B963A6C115D'u64, 0xC097CE7BC90715B4'u64, - 0xF0BDC21ABB48DB21'u64, 0x96769950B50D88F5'u64, 0xBC143FA4E250EB32'u64, - 0xEB194F8E1AE525FE'u64, 0x92EFD1B8D0CF37BF'u64, 0xB7ABC627050305AE'u64, - 0xE596B7B0C643C71A'u64, 0x8F7E32CE7BEA5C70'u64, 0xB35DBF821AE4F38C'u64] - -proc computePow10Single(k: int32): uint64 {.inline.} = - ## There are unique beta and r such that 10^k = beta 2^r and - ## 2^63 <= beta < 2^64, namely r = floor(log_2 10^k) - 63 and - ## beta = 2^-r 10^k. - ## Let g = ceil(beta), so (g-1) 2^r < 10^k <= g 2^r, with the latter - ## value being a pretty good overestimate for 10^k. - ## NB: Since for all the required exponents k, we have g < 2^64, - ## all constants can be stored in 128-bit integers. - sf_Assert(k >= kMin) - sf_Assert(k <= kMax) - return g[k - kMin] - -proc lo32(x: uint64): uint32 {.inline.} = - return cast[uint32](x) - -proc hi32(x: uint64): uint32 {.inline.} = - return cast[uint32](x shr 32) - -when defined(sizeof_Int128): - proc roundToOdd(g: uint64; cp: uint32): uint32 {.inline.} = - let p: uint128 = uint128(g) * cp - let y1: uint32 = lo32(cast[uint64](p shr 64)) - let y0: uint32 = hi32(cast[uint64](p)) - return y1 or uint32(y0 > 1) - -elif defined(vcc) and defined(cpu64): - proc umul128(x, y: uint64, z: ptr uint64): uint64 {.importc: "_umul128", header: "".} - proc roundToOdd(g: uint64; cpHi: uint32): uint32 {.inline.} = - var p1: uint64 = 0 - var p0: uint64 = umul128(g, cpHi, addr(p1)) - let y1: uint32 = lo32(p1) - let y0: uint32 = hi32(p0) - return y1 or uint32(y0 > 1) - -else: - proc roundToOdd(g: uint64; cp: uint32): uint32 {.inline.} = - let b01: uint64 = uint64(lo32(g)) * cp - let b11: uint64 = uint64(hi32(g)) * cp - let hi: uint64 = b11 + hi32(b01) - let y1: uint32 = hi32(hi) - let y0: uint32 = lo32(hi) - return y1 or uint32(y0 > 1) - -## Returns whether value is divisible by 2^e2 - -proc multipleOfPow2(value: uint32; e2: int32): bool {.inline.} = - sf_Assert(e2 >= 0) - sf_Assert(e2 <= 31) - return (value and ((uint32(1) shl e2) - 1)) == 0 - -type - FloatingDecimal32 {.bycopy.} = object - digits: uint32 ## num_digits <= 9 - exponent: int32 - -proc toDecimal32(ieeeSignificand: uint32; ieeeExponent: uint32): FloatingDecimal32 {. - inline.} = - var c: uint32 - var q: int32 - if ieeeExponent != 0: - c = hiddenBit or ieeeSignificand - q = cast[int32](ieeeExponent) - exponentBias - if 0 <= -q and -q < significandSize and multipleOfPow2(c, -q): - return FloatingDecimal32(digits: c shr -q, exponent: 0'i32) - else: - c = ieeeSignificand - q = 1 - exponentBias - let isEven: bool = (c mod 2 == 0) - let lowerBoundaryIsCloser: bool = (ieeeSignificand == 0 and ieeeExponent > 1) - ## const int32_t qb = q - 2; - let cbl: uint32 = 4 * c - 2 + uint32(lowerBoundaryIsCloser) - let cb: uint32 = 4 * c - let cbr: uint32 = 4 * c + 2 - ## (q * 1262611 ) >> 22 == floor(log_10( 2^q)) - ## (q * 1262611 - 524031) >> 22 == floor(log_10(3/4 2^q)) - sf_Assert(q >= -1500) - sf_Assert(q <= 1500) - let k: int32 = floorDivPow2(q * 1262611 - (if lowerBoundaryIsCloser: 524031 else: 0), 22) - let h: int32 = q + floorLog2Pow10(-k) + 1 - sf_Assert(h >= 1) - sf_Assert(h <= 4) - let pow10: uint64 = computePow10Single(-k) - let vbl: uint32 = roundToOdd(pow10, cbl shl h) - let vb: uint32 = roundToOdd(pow10, cb shl h) - let vbr: uint32 = roundToOdd(pow10, cbr shl h) - let lower: uint32 = vbl + uint32(not isEven) - let upper: uint32 = vbr - uint32(not isEven) - ## See Figure 4 in [1]. - ## And the modifications in Figure 6. - let s: uint32 = vb div 4 - ## NB: 4 * s == vb & ~3 == vb & -4 - if s >= 10: - let sp: uint32 = s div 10 - ## = vb / 40 - let upInside: bool = lower <= 40 * sp - let wpInside: bool = 40 * sp + 40 <= upper - ## if (up_inside || wp_inside) // NB: At most one of u' and w' is in R_v. - if upInside != wpInside: - return FloatingDecimal32(digits: sp + uint32(wpInside), exponent: k + 1) - let uInside: bool = lower <= 4 * s - let wInside: bool = 4 * s + 4 <= upper - if uInside != wInside: - return FloatingDecimal32(digits: s + uint32(wInside), exponent: k) - let mid: uint32 = 4 * s + 2 - ## = 2(s + t) - let roundUp: bool = vb > mid or (vb == mid and (s and 1) != 0) - return FloatingDecimal32(digits: s + uint32(roundUp), exponent: k) - -## ================================================================================================== -## ToChars -## ================================================================================================== - -proc printDecimalDigitsBackwards[T: Ordinal](buf: var openArray[char]; pos: T; output: uint32): int32 {.inline.} = - var output = output - var pos = pos - var tz: int32 = 0 - ## number of trailing zeros removed. - var nd: int32 = 0 - ## number of decimal digits processed. - ## At most 9 digits remaining - if output >= 10000: - let q: uint32 = output div 10000 - let r: uint32 = output mod 10000 - output = q - dec(pos, 4) - if r != 0: - let rH: uint32 = r div 100 - let rL: uint32 = r mod 100 - utoa2Digits(buf, pos, rH) - utoa2Digits(buf, pos + 2, rL) - tz = trailingZeros2Digits(if rL == 0: rH else: rL) + (if rL == 0: 2 else: 0) - else: - tz = 4 - nd = 4 - if output >= 100: - let q: uint32 = output div 100 - let r: uint32 = output mod 100 - output = q - dec(pos, 2) - utoa2Digits(buf, pos, r) - if tz == nd: - inc(tz, trailingZeros2Digits(r)) - inc(nd, 2) - if output >= 100: - let q2: uint32 = output div 100 - let r2: uint32 = output mod 100 - output = q2 - dec(pos, 2) - utoa2Digits(buf, pos, r2) - if tz == nd: - inc(tz, trailingZeros2Digits(r2)) - inc(nd, 2) - sf_Assert(output >= 1) - sf_Assert(output <= 99) - if output >= 10: - let q: uint32 = output - dec(pos, 2) - utoa2Digits(buf, pos, q) - if tz == nd: - inc(tz, trailingZeros2Digits(q)) - else: - let q: uint32 = output - sf_Assert(q >= 1) - sf_Assert(q <= 9) - dec(pos) - buf[pos] = chr(uint32('0') + q) - return tz - -proc decimalLength(v: uint32): int {.inline.} = - sf_Assert(v >= 1) - sf_Assert(v <= 999999999'u) - if v >= 100000000'u: - return 9 - if v >= 10000000'u: - return 8 - if v >= 1000000'u: - return 7 - if v >= 100000'u: - return 6 - if v >= 10000'u: - return 5 - if v >= 1000'u: - return 4 - if v >= 100'u: - return 3 - if v >= 10'u: - return 2 - return 1 - -proc formatDigits[T: Ordinal](buffer: var openArray[char]; pos: T; digits: uint32; decimalExponent: int; - forceTrailingDotZero: bool = false): int {.inline.} = - const - minFixedDecimalPoint: int32 = -4 - maxFixedDecimalPoint: int32 = 9 - var pos = pos - assert(minFixedDecimalPoint <= -1, "internal error") - assert(maxFixedDecimalPoint >= 1, "internal error") - sf_Assert(digits >= 1) - sf_Assert(digits <= 999999999'u) - sf_Assert(decimalExponent >= -99) - sf_Assert(decimalExponent <= 99) - var numDigits = decimalLength(digits) - let decimalPoint = numDigits + decimalExponent - let useFixed: bool = minFixedDecimalPoint <= decimalPoint and - decimalPoint <= maxFixedDecimalPoint - ## Prepare the buffer. - ## Avoid calling memset/memcpy with variable arguments below... - for i in 0..<32: buffer[pos+i] = '0' - assert(minFixedDecimalPoint >= -30, "internal error") - assert(maxFixedDecimalPoint <= 32, "internal error") - var decimalDigitsPosition: int - if useFixed: - if decimalPoint <= 0: - ## 0.[000]digits - decimalDigitsPosition = 2 - decimalPoint - else: - ## dig.its - ## digits[000] - decimalDigitsPosition = 0 - else: - ## dE+123 or d.igitsE+123 - decimalDigitsPosition = 1 - var digitsEnd = pos + decimalDigitsPosition + numDigits - let tz: int32 = printDecimalDigitsBackwards(buffer, digitsEnd, digits) - dec(digitsEnd, tz) - dec(numDigits, tz) - ## decimal_exponent += tz; // => decimal_point unchanged. - if useFixed: - if decimalPoint <= 0: - ## 0.[000]digits - buffer[pos+1] = '.' - pos = digitsEnd - elif decimalPoint < numDigits: - ## dig.its - for i in countdown(7, 0): - buffer[i + decimalPoint + 1] = buffer[i + decimalPoint] - buffer[pos+decimalPoint] = '.' - pos = digitsEnd + 1 - else: - ## digits[000] - inc(pos, decimalPoint) - if forceTrailingDotZero: - buffer[pos] = '.' - buffer[pos+1] = '0' - inc(pos, 2) - else: - buffer[pos] = buffer[pos+1] - if numDigits == 1: - ## dE+123 - inc(pos) - else: - ## d.igitsE+123 - buffer[pos+1] = '.' - pos = digitsEnd - let scientificExponent = decimalPoint - 1 - ## SF_ASSERT(scientific_exponent != 0); - buffer[pos] = 'e' - buffer[pos+1] = if scientificExponent < 0: '-' else: '+' - inc(pos, 2) - let k: uint32 = cast[uint32](if scientificExponent < 0: -scientificExponent else: scientificExponent) - if k < 10: - buffer[pos] = chr(uint32('0') + k) - inc pos - else: - utoa2Digits(buffer, pos, k) - inc(pos, 2) - return pos - -proc float32ToChars*(buffer: var openArray[char]; v: float32; forceTrailingDotZero = false): int {. - inline.} = - let significand: uint32 = physicalSignificand(constructSingle(v)) - let exponent: uint32 = physicalExponent(constructSingle(v)) - var pos = 0 - if exponent != maxIeeeExponent: - ## Finite - buffer[pos] = '-' - inc(pos, signBit(constructSingle(v))) - if exponent != 0 or significand != 0: - ## != 0 - let dec: auto = toDecimal32(significand, exponent) - return formatDigits(buffer, pos, dec.digits, dec.exponent.int, forceTrailingDotZero) - else: - buffer[pos] = '0' - buffer[pos+1] = '.' - buffer[pos+2] = '0' - buffer[pos+3] = ' ' - inc(pos, if forceTrailingDotZero: 3 else: 1) - return pos - if significand == 0: - buffer[pos] = '-' - inc(pos, signBit(constructSingle(v))) - buffer[pos] = 'i' - buffer[pos+1] = 'n' - buffer[pos+2] = 'f' - buffer[pos+3] = ' ' - return pos + 3 - else: - buffer[pos] = 'n' - buffer[pos+1] = 'a' - buffer[pos+2] = 'n' - buffer[pos+3] = ' ' - return pos + 3 diff --git a/lib/std/private/since.nim b/lib/std/private/since.nim deleted file mode 100644 index 5b22b6391..000000000 --- a/lib/std/private/since.nim +++ /dev/null @@ -1,33 +0,0 @@ -##[ -`since` is used to emulate older versions of nim stdlib with `--useVersion`, -see `tuse_version.nim`. - -If a symbol `foo` is added in version `(1,3,5)`, use `{.since: (1.3.5).}`, not -`{.since: (1.4).}`, so that it works in devel in between releases. - -The emulation cannot be 100% faithful and to avoid adding too much complexity, -`since` is not needed in those cases: -* if a new module is added -* if an overload is added -* if an extra parameter to an existing routine is added -]## - -template since*(version: (int, int), body: untyped) {.dirty.} = - ## Evaluates `body` if the ``(NimMajor, NimMinor)`` is greater than - ## or equal to `version`. Usage: - ## - ## .. code-block:: Nim - ## proc fun*() {.since: (1, 3).} - ## since (1, 3): fun() - when (NimMajor, NimMinor) >= version: - body - -template since*(version: (int, int, int), body: untyped) {.dirty.} = - ## Evaluates `body` if ``(NimMajor, NimMinor, NimPatch)`` is greater than - ## or equal to `version`. Usage: - ## - ## .. code-block:: Nim - ## proc fun*() {.since: (1, 3, 1).} - ## since (1, 3, 1): fun() - when (NimMajor, NimMinor, NimPatch) >= version: - body diff --git a/lib/std/private/strimpl.nim b/lib/std/private/strimpl.nim deleted file mode 100644 index f8c9236a5..000000000 --- a/lib/std/private/strimpl.nim +++ /dev/null @@ -1,113 +0,0 @@ -func toLowerAscii*(c: char): char {.inline.} = - if c in {'A'..'Z'}: - result = chr(ord(c) + (ord('a') - ord('A'))) - else: - result = c - -template firstCharCaseSensitiveImpl[T: string | cstring](a, b: T, aLen, bLen: int) = - if aLen == 0 or bLen == 0: - return aLen - bLen - if a[0] != b[0]: return ord(a[0]) - ord(b[0]) - -template cmpIgnoreStyleImpl*[T: string | cstring](a, b: T, - firstCharCaseSensitive: static bool = false) = - let aLen = a.len - let bLen = b.len - var i = 0 - var j = 0 - when firstCharCaseSensitive: - firstCharCaseSensitiveImpl(a, b, aLen, bLen) - inc i - inc j - while true: - while i < aLen and a[i] == '_': inc i - while j < bLen and b[j] == '_': inc j - let aa = if i < aLen: toLowerAscii(a[i]) else: '\0' - let bb = if j < bLen: toLowerAscii(b[j]) else: '\0' - result = ord(aa) - ord(bb) - if result != 0: return result - # the characters are identical: - if i >= aLen: - # both cursors at the end: - if j >= bLen: return 0 - # not yet at the end of 'b': - return -1 - elif j >= bLen: - return 1 - inc i - inc j - -template cmpIgnoreCaseImpl*[T: string | cstring](a, b: T, - firstCharCaseSensitive: static bool = false) = - let aLen = a.len - let bLen = b.len - var i = 0 - when firstCharCaseSensitive: - firstCharCaseSensitiveImpl(a, b, aLen, bLen) - inc i - var m = min(aLen, bLen) - while i < m: - result = ord(toLowerAscii(a[i])) - ord(toLowerAscii(b[i])) - if result != 0: return - inc i - result = aLen - bLen - -template startsWithImpl*[T: string | cstring](s, prefix: T) = - let prefixLen = prefix.len - let sLen = s.len - var i = 0 - while true: - if i >= prefixLen: return true - if i >= sLen or s[i] != prefix[i]: return false - inc(i) - -template endsWithImpl*[T: string | cstring](s, suffix: T) = - let suffixLen = suffix.len - let sLen = s.len - var i = 0 - var j = sLen - suffixLen - while i+j >= 0 and i+j < sLen: - if s[i+j] != suffix[i]: return false - inc(i) - if i >= suffixLen: return true - - -func cmpNimIdentifier*[T: string | cstring](a, b: T): int = - cmpIgnoreStyleImpl(a, b, true) - -func c_memchr(cstr: pointer, c: char, n: csize_t): pointer {. - importc: "memchr", header: "".} -func c_strstr(haystack, needle: cstring): cstring {. - importc: "strstr", header: "".} - - -func find*(s: cstring, sub: char, start: Natural = 0, last = 0): int = - ## Searches for `sub` in `s` inside the range `start..last` (both ends included). - ## If `last` is unspecified, it defaults to `s.high` (the last element). - ## - ## Searching is case-sensitive. If `sub` is not in `s`, -1 is returned. - ## Otherwise the index returned is relative to `s[0]`, not `start`. - ## Use `s[start..last].rfind` for a `start`-origin index. - let last = if last == 0: s.high else: last - let L = last-start+1 - if L > 0: - let found = c_memchr(s[start].unsafeAddr, sub, cast[csize_t](L)) - if not found.isNil: - return cast[int](found) -% cast[int](s) - return -1 - -func find*(s, sub: cstring, start: Natural = 0, last = 0): int = - ## Searches for `sub` in `s` inside the range `start..last` (both ends included). - ## If `last` is unspecified, it defaults to `s.high` (the last element). - ## - ## Searching is case-sensitive. If `sub` is not in `s`, -1 is returned. - ## Otherwise the index returned is relative to `s[0]`, not `start`. - ## Use `s[start..last].find` for a `start`-origin index. - if sub.len > s.len - start: return -1 - if sub.len == 1: return find(s, sub[0], start, last) - if last == 0 and s.len > start: - let found = c_strstr(cast[cstring](s[start].unsafeAddr), sub) - if not found.isNil: - result = cast[int](found) -% cast[int](s) - else: - result = -1 diff --git a/lib/std/private/syslocks.nim b/lib/std/private/syslocks.nim deleted file mode 100644 index ca8897dc2..000000000 --- a/lib/std/private/syslocks.nim +++ /dev/null @@ -1,234 +0,0 @@ -# -# -# Nim's Runtime Library -# (c) Copyright 2012 Andreas Rumpf -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# - -# Low level system locks and condition vars. - -{.push stackTrace: off.} - -when defined(windows): - type - Handle = int - - SysLock* {.importc: "CRITICAL_SECTION", - header: "", final, pure.} = object # CRITICAL_SECTION in WinApi - DebugInfo: pointer - LockCount: int32 - RecursionCount: int32 - OwningThread: int - LockSemaphore: int - SpinCount: int - - SysCond* {.importc: "RTL_CONDITION_VARIABLE", header: "".} = object - thePtr {.importc: "Ptr".} : Handle - - proc initSysLock*(L: var SysLock) {.importc: "InitializeCriticalSection", - header: "".} - ## Initializes the lock `L`. - - proc tryAcquireSysAux(L: var SysLock): int32 {.importc: "TryEnterCriticalSection", - header: "".} - ## Tries to acquire the lock `L`. - - proc tryAcquireSys*(L: var SysLock): bool {.inline.} = - result = tryAcquireSysAux(L) != 0'i32 - - proc acquireSys*(L: var SysLock) {.importc: "EnterCriticalSection", - header: "".} - ## Acquires the lock `L`. - - proc releaseSys*(L: var SysLock) {.importc: "LeaveCriticalSection", - header: "".} - ## Releases the lock `L`. - - proc deinitSys*(L: var SysLock) {.importc: "DeleteCriticalSection", - header: "".} - - proc initializeConditionVariable( - conditionVariable: var SysCond - ) {.stdcall, noSideEffect, dynlib: "kernel32", importc: "InitializeConditionVariable".} - - proc sleepConditionVariableCS( - conditionVariable: var SysCond, - PCRITICAL_SECTION: var SysLock, - dwMilliseconds: int - ): int32 {.stdcall, noSideEffect, dynlib: "kernel32", importc: "SleepConditionVariableCS".} - - - proc signalSysCond*(hEvent: var SysCond) {.stdcall, noSideEffect, - dynlib: "kernel32", importc: "WakeConditionVariable".} - - proc broadcastSysCond*(hEvent: var SysCond) {.stdcall, noSideEffect, - dynlib: "kernel32", importc: "WakeAllConditionVariable".} - - proc initSysCond*(cond: var SysCond) {.inline.} = - initializeConditionVariable(cond) - proc deinitSysCond*(cond: var SysCond) {.inline.} = - discard - proc waitSysCond*(cond: var SysCond, lock: var SysLock) = - discard sleepConditionVariableCS(cond, lock, -1'i32) - -elif defined(genode): - const - Header = "genode_cpp/syslocks.h" - type - SysLock* {.importcpp: "Nim::SysLock", pure, final, - header: Header.} = object - SysCond* {.importcpp: "Nim::SysCond", pure, final, - header: Header.} = object - - proc initSysLock*(L: var SysLock) = discard - proc deinitSys*(L: var SysLock) = discard - proc acquireSys*(L: var SysLock) {.noSideEffect, importcpp.} - proc tryAcquireSys*(L: var SysLock): bool {.noSideEffect, importcpp.} - proc releaseSys*(L: var SysLock) {.noSideEffect, importcpp.} - - proc initSysCond*(L: var SysCond) = discard - proc deinitSysCond*(L: var SysCond) = discard - proc waitSysCond*(cond: var SysCond, lock: var SysLock) {. - noSideEffect, importcpp.} - proc signalSysCond*(cond: var SysCond) {. - noSideEffect, importcpp.} - proc broadcastSysCond*(cond: var SysCond) {. - noSideEffect, importcpp.} - -else: - type - SysLockObj {.importc: "pthread_mutex_t", pure, final, - header: """#include - #include """.} = object - when defined(linux) and defined(amd64): - abi: array[40 div sizeof(clong), clong] - - SysLockAttr* {.importc: "pthread_mutexattr_t", pure, final - header: """#include - #include """.} = object - when defined(linux) and defined(amd64): - abi: array[4 div sizeof(cint), cint] # actually a cint - - SysCondObj {.importc: "pthread_cond_t", pure, final, - header: """#include - #include """.} = object - when defined(linux) and defined(amd64): - abi: array[48 div sizeof(clonglong), clonglong] - - SysCondAttr {.importc: "pthread_condattr_t", pure, final - header: """#include - #include """.} = object - when defined(linux) and defined(amd64): - abi: array[4 div sizeof(cint), cint] # actually a cint - - SysLockType = distinct cint - - proc initSysLockAux(L: var SysLockObj, attr: ptr SysLockAttr) {. - importc: "pthread_mutex_init", header: "", noSideEffect.} - proc deinitSysAux(L: var SysLockObj) {.noSideEffect, - importc: "pthread_mutex_destroy", header: "".} - - proc acquireSysAux(L: var SysLockObj) {.noSideEffect, - importc: "pthread_mutex_lock", header: "".} - proc tryAcquireSysAux(L: var SysLockObj): cint {.noSideEffect, - importc: "pthread_mutex_trylock", header: "".} - - proc releaseSysAux(L: var SysLockObj) {.noSideEffect, - importc: "pthread_mutex_unlock", header: "".} - - when defined(ios): - # iOS will behave badly if sync primitives are moved in memory. In order - # to prevent this once and for all, we're doing an extra malloc when - # initializing the primitive. - type - SysLock* = ptr SysLockObj - SysCond* = ptr SysCondObj - - when not declared(c_malloc): - proc c_malloc(size: csize_t): pointer {. - importc: "malloc", header: "".} - proc c_free(p: pointer) {. - importc: "free", header: "".} - - proc initSysLock*(L: var SysLock, attr: ptr SysLockAttr = nil) = - L = cast[SysLock](c_malloc(csize_t(sizeof(SysLockObj)))) - initSysLockAux(L[], attr) - - proc deinitSys*(L: var SysLock) = - deinitSysAux(L[]) - c_free(L) - - template acquireSys*(L: var SysLock) = - acquireSysAux(L[]) - template tryAcquireSys*(L: var SysLock): bool = - tryAcquireSysAux(L[]) == 0'i32 - template releaseSys*(L: var SysLock) = - releaseSysAux(L[]) - else: - type - SysLock* = SysLockObj - SysCond* = SysCondObj - - template initSysLock*(L: var SysLock, attr: ptr SysLockAttr = nil) = - initSysLockAux(L, attr) - template deinitSys*(L: var SysLock) = - deinitSysAux(L) - template acquireSys*(L: var SysLock) = - acquireSysAux(L) - template tryAcquireSys*(L: var SysLock): bool = - tryAcquireSysAux(L) == 0'i32 - template releaseSys*(L: var SysLock) = - releaseSysAux(L) - - # rlocks - var SysLockType_Reentrant* {.importc: "PTHREAD_MUTEX_RECURSIVE", - header: "".}: SysLockType - proc initSysLockAttr*(a: var SysLockAttr) {. - importc: "pthread_mutexattr_init", header: "", noSideEffect.} - proc setSysLockType*(a: var SysLockAttr, t: SysLockType) {. - importc: "pthread_mutexattr_settype", header: "", noSideEffect.} - - # locks - proc initSysCondAux(cond: var SysCondObj, cond_attr: ptr SysCondAttr = nil) {. - importc: "pthread_cond_init", header: "", noSideEffect.} - proc deinitSysCondAux(cond: var SysCondObj) {.noSideEffect, - importc: "pthread_cond_destroy", header: "".} - - proc waitSysCondAux(cond: var SysCondObj, lock: var SysLockObj): cint {. - importc: "pthread_cond_wait", header: "", noSideEffect.} - proc signalSysCondAux(cond: var SysCondObj) {. - importc: "pthread_cond_signal", header: "", noSideEffect.} - proc broadcastSysCondAux(cond: var SysCondObj) {. - importc: "pthread_cond_broadcast", header: "", noSideEffect.} - - when defined(ios): - proc initSysCond*(cond: var SysCond, cond_attr: ptr SysCondAttr = nil) = - cond = cast[SysCond](c_malloc(csize_t(sizeof(SysCondObj)))) - initSysCondAux(cond[], cond_attr) - - proc deinitSysCond*(cond: var SysCond) = - deinitSysCondAux(cond[]) - c_free(cond) - - template waitSysCond*(cond: var SysCond, lock: var SysLock) = - discard waitSysCondAux(cond[], lock[]) - template signalSysCond*(cond: var SysCond) = - signalSysCondAux(cond[]) - template broadcastSysCond*(cond: var SysCond) = - broadcastSysCondAux(cond[]) - else: - template initSysCond*(cond: var SysCond, cond_attr: ptr SysCondAttr = nil) = - initSysCondAux(cond, cond_attr) - template deinitSysCond*(cond: var SysCond) = - deinitSysCondAux(cond) - - template waitSysCond*(cond: var SysCond, lock: var SysLock) = - discard waitSysCondAux(cond, lock) - template signalSysCond*(cond: var SysCond) = - signalSysCondAux(cond) - template broadcastSysCond*(cond: var SysCond) = - broadcastSysCondAux(cond) - -{.pop.} diff --git a/lib/std/private/threadtypes.nim b/lib/std/private/threadtypes.nim deleted file mode 100644 index a1cdf21dc..000000000 --- a/lib/std/private/threadtypes.nim +++ /dev/null @@ -1,176 +0,0 @@ -include system/inclrtl - -const hasSharedHeap* = defined(boehmgc) or defined(gogc) # don't share heaps; every thread has its own - -when defined(windows): - type - Handle* = int - SysThread* = Handle - WinThreadProc* = proc (x: pointer): int32 {.stdcall.} - - proc createThread*(lpThreadAttributes: pointer, dwStackSize: int32, - lpStartAddress: WinThreadProc, - lpParameter: pointer, - dwCreationFlags: int32, - lpThreadId: var int32): SysThread {. - stdcall, dynlib: "kernel32", importc: "CreateThread".} - - proc winSuspendThread*(hThread: SysThread): int32 {. - stdcall, dynlib: "kernel32", importc: "SuspendThread".} - - proc winResumeThread*(hThread: SysThread): int32 {. - stdcall, dynlib: "kernel32", importc: "ResumeThread".} - - proc waitForSingleObject*(hHandle: SysThread, dwMilliseconds: int32): int32 {. - stdcall, dynlib: "kernel32", importc: "WaitForSingleObject".} - - proc waitForMultipleObjects*(nCount: int32, - lpHandles: ptr SysThread, - bWaitAll: int32, - dwMilliseconds: int32): int32 {. - stdcall, dynlib: "kernel32", importc: "WaitForMultipleObjects".} - - proc terminateThread*(hThread: SysThread, dwExitCode: int32): int32 {. - stdcall, dynlib: "kernel32", importc: "TerminateThread".} - - proc setThreadAffinityMask*(hThread: SysThread, dwThreadAffinityMask: uint) {. - importc: "SetThreadAffinityMask", stdcall, header: "".} - -elif defined(genode): - const - GenodeHeader* = "genode_cpp/threads.h" - type - SysThread* {.importcpp: "Nim::SysThread", - header: GenodeHeader, final, pure.} = object - GenodeThreadProc* = proc (x: pointer) {.noconv.} - - proc initThread*(s: var SysThread, - env: GenodeEnv, - stackSize: culonglong, - entry: GenodeThreadProc, - arg: pointer, - affinity: cuint) {. - importcpp: "#.initThread(@)".} - - -else: - when not (defined(macosx) or defined(haiku)): - {.passl: "-pthread".} - - when not defined(haiku): - {.passc: "-pthread".} - - const - schedh = "#define _GNU_SOURCE\n#include " - pthreadh* = "#define _GNU_SOURCE\n#include " - - when not declared(Time): - when defined(linux): - type Time = clong - else: - type Time = int - - when (defined(linux) or defined(nintendoswitch)) and defined(amd64): - type - SysThread* {.importc: "pthread_t", - header: "" .} = distinct culong - Pthread_attr* {.importc: "pthread_attr_t", - header: "".} = object - abi: array[56 div sizeof(clong), clong] - elif defined(openbsd) and defined(amd64): - type - SysThread* {.importc: "pthread_t", header: "".} = object - Pthread_attr* {.importc: "pthread_attr_t", - header: "".} = object - else: - type - SysThread* {.importc: "pthread_t", header: "".} = int - Pthread_attr* {.importc: "pthread_attr_t", - header: "".} = object - type - Timespec* {.importc: "struct timespec", header: "".} = object - tv_sec*: Time - tv_nsec*: clong - - proc pthread_attr_init*(a1: var Pthread_attr): cint {. - importc, header: pthreadh.} - proc pthread_attr_setstack*(a1: ptr Pthread_attr, a2: pointer, a3: int): cint {. - importc, header: pthreadh.} - proc pthread_attr_setstacksize*(a1: var Pthread_attr, a2: int): cint {. - importc, header: pthreadh.} - proc pthread_attr_destroy*(a1: var Pthread_attr): cint {. - importc, header: pthreadh.} - - proc pthread_create*(a1: var SysThread, a2: var Pthread_attr, - a3: proc (x: pointer): pointer {.noconv.}, - a4: pointer): cint {.importc: "pthread_create", - header: pthreadh.} - proc pthread_join*(a1: SysThread, a2: ptr pointer): cint {. - importc, header: pthreadh.} - - proc pthread_cancel*(a1: SysThread): cint {. - importc: "pthread_cancel", header: pthreadh.} - - type CpuSet* {.importc: "cpu_set_t", header: schedh.} = object - when defined(linux) and defined(amd64): - abi: array[1024 div (8 * sizeof(culong)), culong] - - proc cpusetZero*(s: var CpuSet) {.importc: "CPU_ZERO", header: schedh.} - proc cpusetIncl*(cpu: cint; s: var CpuSet) {. - importc: "CPU_SET", header: schedh.} - - when defined(android): - # libc of android doesn't implement pthread_setaffinity_np, - # it exposes pthread_gettid_np though, so we can use that in combination - # with sched_setaffinity to set the thread affinity. - type Pid* {.importc: "pid_t", header: "".} = int32 # From posix_other.nim - - proc setAffinityTID*(tid: Pid; setsize: csize_t; s: var CpuSet) {. - importc: "sched_setaffinity", header: schedh.} - - proc pthread_gettid_np*(thread: SysThread): Pid {. - importc: "pthread_gettid_np", header: pthreadh.} - - proc setAffinity*(thread: SysThread; setsize: csize_t; s: var CpuSet) = - setAffinityTID(pthread_gettid_np(thread), setsize, s) - else: - proc setAffinity*(thread: SysThread; setsize: csize_t; s: var CpuSet) {. - importc: "pthread_setaffinity_np", header: pthreadh.} - - -const - emulatedThreadVars* = compileOption("tlsEmulation") -# we preallocate a fixed size for thread local storage, so that no heap -# allocations are needed. Currently less than 16K are used on a 64bit machine. -# We use `float` for proper alignment: -const nimTlsSize {.intdefine.} = 16000 -type - ThreadLocalStorage* = array[0..(nimTlsSize div sizeof(float)), float] - PGcThread* = ptr GcThread - GcThread* {.pure, inheritable.} = object - when emulatedThreadVars: - tls*: ThreadLocalStorage - else: - nil - when hasSharedHeap: - next*, prev*: PGcThread - stackBottom*, stackTop*: pointer - stackSize*: int - else: - nil - -const hasAllocStack* = defined(zephyr) # maybe freertos too? - -type - Thread*[TArg] = object - core*: PGcThread - sys*: SysThread - when TArg is void: - dataFn*: proc () {.nimcall, gcsafe.} - else: - dataFn*: proc (m: TArg) {.nimcall, gcsafe.} - data*: TArg - when hasAllocStack: - rawStack*: pointer - -proc `=copy`*[TArg](x: var Thread[TArg], y: Thread[TArg]) {.error.} diff --git a/lib/std/private/underscored_calls.nim b/lib/std/private/underscored_calls.nim deleted file mode 100644 index f0bcbcc74..000000000 --- a/lib/std/private/underscored_calls.nim +++ /dev/null @@ -1,48 +0,0 @@ - -# -# -# Nim's Runtime Library -# (c) Copyright 2020 Andreas Rumpf -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# - -## This is an internal helper module. Do not use. - -import macros - -proc underscoredCall(n, arg0: NimNode): NimNode = - proc underscorePos(n: NimNode): int = - for i in 1 ..< n.len: - if n[i].eqIdent("_"): return i - return 0 - - if n.kind in nnkCallKinds: - result = copyNimNode(n) - result.add n[0] - - let u = underscorePos(n) - for i in 1..u-1: result.add n[i] - result.add arg0 - for i in u+1..n.len-1: result.add n[i] - elif n.kind in {nnkAsgn, nnkExprEqExpr}: - var field = n[0] - if n[0].kind == nnkDotExpr and n[0][0].eqIdent("_"): - # handle _.field = ... - field = n[0][1] - result = newDotExpr(arg0, field).newAssignment n[1] - else: - # handle e.g. 'x.dup(sort)' - result = newNimNode(nnkCall, n) - result.add n - result.add arg0 - -proc underscoredCalls*(result, calls, arg0: NimNode) = - expectKind calls, {nnkArgList, nnkStmtList, nnkStmtListExpr} - - for call in calls: - if call.kind in {nnkStmtList, nnkStmtListExpr}: - underscoredCalls(result, call, arg0) - else: - result.add underscoredCall(call, arg0) diff --git a/lib/std/private/win_getsysteminfo.nim b/lib/std/private/win_getsysteminfo.nim deleted file mode 100644 index b98478231..000000000 --- a/lib/std/private/win_getsysteminfo.nim +++ /dev/null @@ -1,15 +0,0 @@ -type - SystemInfo* = object - u1: uint32 - dwPageSize: uint32 - lpMinimumApplicationAddress: pointer - lpMaximumApplicationAddress: pointer - dwActiveProcessorMask: ptr uint32 - dwNumberOfProcessors*: uint32 - dwProcessorType: uint32 - dwAllocationGranularity*: uint32 - wProcessorLevel: uint16 - wProcessorRevision: uint16 - -proc getSystemInfo*(lpSystemInfo: ptr SystemInfo) {.stdcall, - dynlib: "kernel32", importc: "GetSystemInfo".} diff --git a/lib/std/private/win_setenv.nim b/lib/std/private/win_setenv.nim deleted file mode 100644 index 66e199dfe..000000000 --- a/lib/std/private/win_setenv.nim +++ /dev/null @@ -1,106 +0,0 @@ -#[ -Copyright (c) Facebook, Inc. and its affiliates. -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. - -Adapted `setenv` from https://github.com/facebook/folly/blob/master/folly/portability/Stdlib.cpp -translated from C to nim. -]# - -#[ -Introduced in https://github.com/facebook/folly/commit/5d8ca09a3f96afefb44e35808f03651a096ab9c7 - -TODO: -check errno_t vs cint -]# - -when not defined(windows): discard -else: - when defined(nimPreviewSlimSystem): - import std/widestrs - - type wchar_t {.importc: "wchar_t".} = int16 - - proc setEnvironmentVariableW*(lpName, lpValue: WideCString): int32 {. - stdcall, dynlib: "kernel32", importc: "SetEnvironmentVariableW", sideEffect.} - # same as winlean.setEnvironmentVariableA - - proc c_getenv(varname: cstring): cstring {.importc: "getenv", header: "".} - proc c_wputenv(envstring: ptr wchar_t): cint {.importc: "_wputenv", header: "".} - proc c_wgetenv(varname: ptr wchar_t): ptr wchar_t {.importc: "_wgetenv", header: "".} - - var errno {.importc, header: "".}: cint - var genviron {.importc: "_environ".}: ptr ptr char - # xxx `ptr UncheckedArray[WideCString]` did not work - - proc wcstombs(wcstr: ptr char, mbstr: ptr wchar_t, count: csize_t): csize_t {.importc, header: "".} - # xxx cint vs errno_t? - - proc setEnvImpl*(name: string, value: string, overwrite: cint): cint = - const EINVAL = cint(22) - let wideName: WideCString = newWideCString(name) - if overwrite == 0 and c_wgetenv(cast[ptr wchar_t](wideName)) != nil: - return 0 - - if value != "": - let envstring: WideCString = newWideCString(name & "=" & value) - let e = c_wputenv(cast[ptr wchar_t](envstring)) - if e != 0: - errno = EINVAL - return -1 - return 0 - #[ - We are trying to set the value to an empty string, but `_putenv` deletes - entries if the value is an empty string, and just calling - SetEnvironmentVariableA doesn't update `_environ`, - so we have to do these terrible things. - ]# - let envstring: WideCString = newWideCString(name & "= ") - if c_wputenv(cast[ptr wchar_t](envstring)) != 0: - errno = EINVAL - return -1 - # Here lies the documentation we blatently ignore to make this work. - var s = cast[WideCString](c_wgetenv(cast[ptr wchar_t](wideName))) - s[0] = Utf16Char('\0') - #[ - This would result in a double null termination, which normally signifies the - end of the environment variable list, so we stick a completely empty - environment variable into the list instead. - ]# - s = cast[WideCString](c_wgetenv(cast[ptr wchar_t](wideName))) - s[1] = Utf16Char('=') - #[ - If genviron is null, the MBCS environment has not been initialized - yet, and we don't need to try to update it. We have to do this otherwise - we'd be forcing the initialization and maintenance of the MBCS environment - even though it's never actually used in most programs. - ]# - if genviron != nil: - - # wcstombs returns `high(csize_t)` if any characters cannot be represented - # in the current codepage. Skip updating MBCS environment in this case. - # For some reason, second `wcstombs` can find non-convertible characters - # that the first `wcstombs` cannot. - let requiredSizeS = wcstombs(nil, cast[ptr wchar_t](wideName), 0) - if requiredSizeS != high(csize_t): - let requiredSize = requiredSizeS.int - var buf = newSeq[char](requiredSize + 1) - let buf2 = buf[0].addr - if wcstombs(buf2, cast[ptr wchar_t](wideName), csize_t(requiredSize + 1)) != high(csize_t): - var ptrToEnv = c_getenv(cast[cstring](buf2)) - ptrToEnv[0] = '\0' - ptrToEnv = c_getenv(cast[cstring](buf2)) - ptrToEnv[1] = '=' - - # And now, we have to update the outer environment to have a proper empty value. - if setEnvironmentVariableW(wideName, value.newWideCString) == 0: - errno = EINVAL - return -1 - return 0 diff --git a/lib/std/setutils.nim b/lib/std/setutils.nim deleted file mode 100644 index 4664d6dcc..000000000 --- a/lib/std/setutils.nim +++ /dev/null @@ -1,77 +0,0 @@ -# -# -# Nim's Runtime Library -# (c) Copyright 2020 Nim Contributors -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# - -## This module adds functionality for the built-in `set` type. -## -## See also -## ======== -## * `std/packedsets `_ -## * `std/sets `_ - -import typetraits, macros - -#[ - type SetElement* = char|byte|bool|int16|uint16|enum|uint8|int8 - ## The allowed types of a built-in set. -]# - -template toSet*(iter: untyped): untyped = - ## Returns a built-in set from the elements of the iterable `iter`. - runnableExamples: - assert "helloWorld".toSet == {'W', 'd', 'e', 'h', 'l', 'o', 'r'} - assert toSet([10u16, 20, 30]) == {10u16, 20, 30} - assert [30u8, 100, 10].toSet == {10u8, 30, 100} - assert toSet(@[1321i16, 321, 90]) == {90i16, 321, 1321} - assert toSet([false]) == {false} - assert toSet(0u8..10) == {0u8..10} - - var result: set[elementType(iter)] - for x in iter: - incl(result, x) - result - -macro enumElementsAsSet(enm: typed): untyped = result = newNimNode(nnkCurly).add(enm.getType[1][1..^1]) - -# func fullSet*(T: typedesc): set[T] {.inline.} = # xxx would give: Error: ordinal type expected -func fullSet*[T](U: typedesc[T]): set[T] {.inline.} = - ## Returns a set containing all elements in `U`. - runnableExamples: - assert bool.fullSet == {true, false} - type A = range[1..3] - assert A.fullSet == {1.A, 2, 3} - assert int8.fullSet.len == 256 - when T is Ordinal: - {T.low..T.high} - else: # Hole filled enum - enumElementsAsSet(T) - -func complement*[T](s: set[T]): set[T] {.inline.} = - ## Returns the set complement of `a`. - runnableExamples: - type Colors = enum - red, green = 3, blue - assert complement({red, blue}) == {green} - assert complement({red, green, blue}).card == 0 - assert complement({range[0..10](0), 1, 2, 3}) == {range[0..10](4), 5, 6, 7, 8, 9, 10} - assert complement({'0'..'9'}) == {0.char..255.char} - {'0'..'9'} - fullSet(T) - s - -func `[]=`*[T](t: var set[T], key: T, val: bool) {.inline.} = - ## Syntax sugar for `if val: t.incl key else: t.excl key` - runnableExamples: - type A = enum - a0, a1, a2, a3 - var s = {a0, a3} - s[a0] = false - s[a1] = false - assert s == {a3} - s[a2] = true - s[a3] = true - assert s == {a2, a3} - if val: t.incl key else: t.excl key diff --git a/lib/std/sha1.nim b/lib/std/sha1.nim index 50175024c..8f35a44ff 100644 --- a/lib/std/sha1.nim +++ b/lib/std/sha1.nim @@ -1,41 +1,46 @@ # # -# Nim's Runtime Library +# The Nim Compiler # (c) Copyright 2015 Nim Contributors # # See the file "copying.txt", included in this # distribution, for details about the copyright. # -## [SHA-1 (Secure Hash Algorithm 1)](https://en.wikipedia.org/wiki/SHA-1) -## is a cryptographic hash function which takes an input and produces -## a 160-bit (20-byte) hash value known as a message digest. + +## **Note:** Import ``std/sha1`` to use this module ## -## See also -## ======== -## * `base64 module`_ for a Base64 encoder and decoder +## SHA-1 (Secure Hash Algorithm 1) is a cryptographic hash function which +## takes an input and produces a 160-bit (20-byte) hash value known as a +## message digest. +## +## .. code-block:: +## import std/sha1 +## +## let accessName = secureHash("John Doe") +## assert $accessName == "AE6E4D1209F17B460503904FAD297B31E9CF6362" +## +## .. code-block:: +## import std/sha1 +## +## let +## a = secureHashFile("myFile.nim") +## b = parseSecureHash("10DFAEBF6BFDBC7939957068E2EFACEC4972933C") +## +## if a == b: +## echo "Files match" +## +## **See also:** +## * `base64 module`_ implements a base64 encoder and decoder ## * `hashes module`_ for efficient computations of hash values for diverse Nim types -## * `md5 module`_ for the MD5 checksum algorithm - -runnableExamples: - let accessName = secureHash("John Doe") - assert $accessName == "AE6E4D1209F17B460503904FAD297B31E9CF6362" - -runnableExamples("-r:off"): - let - a = secureHashFile("myFile.nim") - b = parseSecureHash("10DFAEBF6BFDBC7939957068E2EFACEC4972933C") - assert a == b, "files don't match" +## * `md5 module`_ implements the MD5 checksum algorithm import strutils from endians import bigEndian32, bigEndian64 -when defined(nimPreviewSlimSystem): - import std/syncio - const Sha1DigestSize = 20 type - Sha1Digest* = array[0 .. Sha1DigestSize - 1, uint8] + Sha1Digest* = array[0 .. Sha1DigestSize-1, uint8] SecureHash* = distinct Sha1Digest type @@ -44,14 +49,10 @@ type state: array[5, uint32] buf: array[64, byte] -# This implementation of the SHA-1 algorithm was ported from the Chromium OS one +# This implementation of the SHA1 algorithm was ported from the Chromium OS one # with minor modifications that should not affect its functionality. proc newSha1State*(): Sha1State = - ## Creates a `Sha1State`. - ## - ## If you use the `secureHash proc <#secureHash,openArray[char]>`_, - ## there's no need to call this function explicitly. result.count = 0 result.state[0] = 0x67452301'u32 result.state[1] = 0xEFCDAB89'u32 @@ -145,10 +146,6 @@ proc transform(ctx: var Sha1State) = ctx.state[4] += e proc update*(ctx: var Sha1State, data: openArray[char]) = - ## Updates the `Sha1State` with `data`. - ## - ## If you use the `secureHash proc <#secureHash,openArray[char]>`_, - ## there's no need to call this function explicitly. var i = ctx.count mod 64 var j = 0 var len = data.len @@ -180,10 +177,6 @@ proc update*(ctx: var Sha1State, data: openArray[char]) = ctx.count += data.len proc finalize*(ctx: var Sha1State): Sha1Digest = - ## Finalizes the `Sha1State` and returns a `Sha1Digest`. - ## - ## If you use the `secureHash proc <#secureHash,openArray[char]>`_, - ## there's no need to call this function explicitly. var cnt = uint64(ctx.count * 8) # a 1 bit update(ctx, "\x80") @@ -202,72 +195,54 @@ proc finalize*(ctx: var Sha1State): Sha1Digest = # Public API proc secureHash*(str: openArray[char]): SecureHash = - ## Generates a `SecureHash` from `str`. + ## Generates a ``SecureHash`` from a ``str``. ## ## **See also:** - ## * `secureHashFile proc <#secureHashFile,string>`_ for generating a `SecureHash` from a file - ## * `parseSecureHash proc <#parseSecureHash,string>`_ for converting a string `hash` to `SecureHash` + ## * `secureHashFile proc <#secureHashFile,string>`_ for generating a ``SecureHash`` from a file + ## * `parseSecureHash proc <#parseSecureHash,string>`_ for converting a string ``hash`` to ``SecureHash`` runnableExamples: let hash = secureHash("Hello World") assert hash == parseSecureHash("0A4D55A8D778E5022FAB701977C5D840BBC486D0") - var state = newSha1State() state.update(str) SecureHash(state.finalize()) proc secureHashFile*(filename: string): SecureHash = - ## Generates a `SecureHash` from a file. + ## Generates a ``SecureHash`` from a file. ## ## **See also:** - ## * `secureHash proc <#secureHash,openArray[char]>`_ for generating a `SecureHash` from a string - ## * `parseSecureHash proc <#parseSecureHash,string>`_ for converting a string `hash` to `SecureHash` - const BufferLength = 8192 - - let f = open(filename) - var state = newSha1State() - var buffer = newString(BufferLength) - while true: - let length = readChars(f, buffer) - if length == 0: - break - buffer.setLen(length) - state.update(buffer) - if length != BufferLength: - break - close(f) - - SecureHash(state.finalize()) + ## * `secureHash proc <#secureHash,openArray[char]>`_ for generating a ``SecureHash`` from a string + ## * `parseSecureHash proc <#parseSecureHash,string>`_ for converting a string ``hash`` to ``SecureHash`` + secureHash(readFile(filename)) proc `$`*(self: SecureHash): string = - ## Returns the string representation of a `SecureHash`. + ## Returns the string representation of a ``SecureHash``. ## ## **See also:** - ## * `secureHash proc <#secureHash,openArray[char]>`_ for generating a `SecureHash` from a string + ## * `secureHash proc <#secureHash,openArray[char]>`_ for generating a ``SecureHash`` from a string runnableExamples: let hash = secureHash("Hello World") assert $hash == "0A4D55A8D778E5022FAB701977C5D840BBC486D0" - result = "" for v in Sha1Digest(self): result.add(toHex(int(v), 2)) proc parseSecureHash*(hash: string): SecureHash = - ## Converts a string `hash` to a `SecureHash`. + ## Converts a string ``hash`` to ``SecureHash``. ## ## **See also:** - ## * `secureHash proc <#secureHash,openArray[char]>`_ for generating a `SecureHash` from a string - ## * `secureHashFile proc <#secureHashFile,string>`_ for generating a `SecureHash` from a file + ## * `secureHash proc <#secureHash,openArray[char]>`_ for generating a ``SecureHash`` from a string + ## * `secureHashFile proc <#secureHashFile,string>`_ for generating a ``SecureHash`` from a file runnableExamples: let hashStr = "0A4D55A8D778E5022FAB701977C5D840BBC486D0" secureHash = secureHash("Hello World") assert secureHash == parseSecureHash(hashStr) - for i in 0 ..< Sha1DigestSize: Sha1Digest(result)[i] = uint8(parseHexInt(hash[i*2] & hash[i*2 + 1])) proc `==`*(a, b: SecureHash): bool = - ## Checks if two `SecureHash` values are identical. + ## Checks if two ``SecureHash`` values are identical. runnableExamples: let a = secureHash("Hello World") @@ -275,10 +250,18 @@ proc `==`*(a, b: SecureHash): bool = c = parseSecureHash("0A4D55A8D778E5022FAB701977C5D840BBC486D0") assert a != b assert a == c - # Not a constant-time comparison, but that's acceptable in this context Sha1Digest(a) == Sha1Digest(b) -proc isValidSha1Hash*(s: string): bool = - ## Checks if a string is a valid sha1 hash sum. - s.len == 40 and allCharsInSet(s, HexDigits) +when isMainModule: + let hash1 = secureHash("a93tgj0p34jagp9[agjp98ajrhp9aej]") + doAssert hash1 == hash1 + doAssert parseSecureHash($hash1) == hash1 + + template checkVector(s, exp: string) = + doAssert secureHash(s) == parseSecureHash(exp) + + checkVector("", "da39a3ee5e6b4b0d3255bfef95601890afd80709") + checkVector("abc", "a9993e364706816aba3e25717850c26c9cd0d89d") + checkVector("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", + "84983e441c3bd26ebaae4aa1f95129e5e54670f1") diff --git a/lib/std/socketstreams.nim b/lib/std/socketstreams.nim deleted file mode 100644 index b53d6a5d3..000000000 --- a/lib/std/socketstreams.nim +++ /dev/null @@ -1,181 +0,0 @@ -# -# -# Nim's Runtime Library -# (c) Copyright 2021 Nim contributors -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# - -## This module provides an implementation of the streams interface for sockets. -## It contains two separate implementations, a -## `ReadSocketStream <#ReadSocketStream>`_ and a -## `WriteSocketStream <#WriteSocketStream>`_. -## -## The `ReadSocketStream` only supports reading, peeking, and seeking. -## It reads into a buffer, so even by -## seeking backwards it will only read the same position a single time from the -## underlying socket. To clear the buffer and free the data read into it you -## can call `resetStream`, this will also reset the position back to 0 but -## won't do anything to the underlying socket. -## -## The `WriteSocketStream` allows both reading and writing, but it performs the -## reads on the internal buffer. So by writing to the buffer you can then read -## back what was written but without receiving anything from the socket. You -## can also set the position and overwrite parts of the buffer, and to send -## anything over the socket you need to call `flush` at which point you can't -## write anything to the buffer before the point of the flush (but it can still -## be read). Again to empty the underlying buffer you need to call -## `resetStream`. -## -## Examples -## ======== -## -## .. code-block:: Nim -## import std/socketstreams -## -## var -## socket = newSocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP) -## stream = newReadSocketStream(socket) -## socket.sendTo("127.0.0.1", Port(12345), "SOME REQUEST") -## echo stream.readLine() # Will call `recv` -## stream.setPosition(0) -## echo stream.readLine() # Will return the read line from the buffer -## stream.resetStream() # Buffer is now empty, position is 0 -## echo stream.readLine() # Will call `recv` again -## stream.close() # Closes the socket -## -## .. code-block:: Nim -## -## import std/socketstreams -## -## var socket = newSocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP) -## socket.connect("127.0.0.1", Port(12345)) -## var sendStream = newWriteSocketStream(socket) -## sendStream.write "NOM" -## sendStream.setPosition(1) -## echo sendStream.peekStr(2) # OM -## sendStream.write "I" -## sendStream.setPosition(0) -## echo sendStream.readStr(3) # NIM -## echo sendStream.getPosition() # 3 -## sendStream.flush() # This actually performs the writing to the socket -## sendStream.setPosition(1) -## sendStream.write "I" # Throws an error as we can't write into an already sent buffer - -import net, streams - -type - ReadSocketStream* = ref ReadSocketStreamObj - ReadSocketStreamObj* = object of StreamObj - data: Socket - pos: int - buf: seq[byte] - WriteSocketStream* = ref WriteSocketStreamObj - WriteSocketStreamObj* = object of ReadSocketStreamObj - lastFlush: int - -proc rsAtEnd(s: Stream): bool = - return false - -proc rsSetPosition(s: Stream, pos: int) = - var s = ReadSocketStream(s) - s.pos = pos - -proc rsGetPosition(s: Stream): int = - var s = ReadSocketStream(s) - return s.pos - -proc rsPeekData(s: Stream, buffer: pointer, bufLen: int): int = - let s = ReadSocketStream(s) - if bufLen > 0: - let oldLen = s.buf.len - s.buf.setLen(max(s.pos + bufLen, s.buf.len)) - if s.pos + bufLen > oldLen: - result = s.data.recv(s.buf[oldLen].addr, s.buf.len - oldLen) - if result > 0: - result += oldLen - s.pos - else: - result = bufLen - copyMem(buffer, s.buf[s.pos].addr, result) - -proc rsReadData(s: Stream, buffer: pointer, bufLen: int): int = - result = s.rsPeekData(buffer, bufLen) - var s = ReadSocketStream(s) - s.pos += bufLen - -proc rsReadDataStr(s: Stream, buffer: var string, slice: Slice[int]): int = - var s = ReadSocketStream(s) - result = slice.b + 1 - slice.a - if result > 0: - result = s.rsReadData(buffer[slice.a].addr, result) - inc(s.pos, result) - else: - result = 0 - -proc wsWriteData(s: Stream, buffer: pointer, bufLen: int) = - var s = WriteSocketStream(s) - if s.pos < s.lastFlush: - raise newException(IOError, "Unable to write into buffer that has already been sent") - if s.buf.len < s.pos + bufLen: - s.buf.setLen(s.pos + bufLen) - copyMem(s.buf[s.pos].addr, buffer, bufLen) - s.pos += bufLen - -proc wsPeekData(s: Stream, buffer: pointer, bufLen: int): int = - var s = WriteSocketStream(s) - result = bufLen - if result > 0: - if s.pos > s.buf.len or s.pos == s.buf.len or s.pos + bufLen > s.buf.len: - raise newException(IOError, "Unable to read past end of write buffer") - else: - copyMem(buffer, s.buf[s.pos].addr, bufLen) - -proc wsReadData(s: Stream, buffer: pointer, bufLen: int): int = - result = s.wsPeekData(buffer, bufLen) - var s = ReadSocketStream(s) - s.pos += bufLen - -proc wsAtEnd(s: Stream): bool = - var s = WriteSocketStream(s) - return s.pos == s.buf.len - -proc wsFlush(s: Stream) = - var s = WriteSocketStream(s) - discard s.data.send(s.buf[s.lastFlush].addr, s.buf.len - s.lastFlush) - s.lastFlush = s.buf.len - -proc rsClose(s: Stream) = - {.cast(raises: [IOError, OSError]), cast(tags: []).}: # todo fixme maybe do something? - var s = ReadSocketStream(s) - s.data.close() - -proc newReadSocketStream*(s: Socket): owned ReadSocketStream = - result = ReadSocketStream(data: s, pos: 0, - closeImpl: rsClose, - atEndImpl: rsAtEnd, - setPositionImpl: rsSetPosition, - getPositionImpl: rsGetPosition, - readDataImpl: rsReadData, - peekDataImpl: rsPeekData, - readDataStrImpl: rsReadDataStr) - -proc resetStream*(s: ReadSocketStream) = - s.buf = @[] - s.pos = 0 - -proc newWriteSocketStream*(s: Socket): owned WriteSocketStream = - result = WriteSocketStream(data: s, pos: 0, - closeImpl: rsClose, - atEndImpl: wsAtEnd, - setPositionImpl: rsSetPosition, - getPositionImpl: rsGetPosition, - writeDataImpl: wsWriteData, - readDataImpl: wsReadData, - peekDataImpl: wsPeekData, - flushImpl: wsFlush) - -proc resetStream*(s: WriteSocketStream) = - s.buf = @[] - s.pos = 0 - s.lastFlush = 0 diff --git a/lib/std/stackframes.nim b/lib/std/stackframes.nim deleted file mode 100644 index 28be7ce11..000000000 --- a/lib/std/stackframes.nim +++ /dev/null @@ -1,30 +0,0 @@ -const NimStackTrace = compileOption("stacktrace") -const NimStackTraceMsgs = compileOption("stacktraceMsgs") - -template procName*(): string = - ## returns current C/C++ function name - when defined(c) or defined(cpp): - var name {.inject, noinit.}: cstring - {.emit: "`name` = __func__;".} - $name - -template getPFrame*(): PFrame = - ## avoids a function call (unlike `getFrame()`) - block: - when NimStackTrace: - var framePtr {.inject, noinit.}: PFrame - {.emit: "`framePtr` = &FR_;".} - framePtr - -template setFrameMsg*(msg: string, prefix = " ") = - ## attach a msg to current `PFrame`. This can be called multiple times - ## in a given PFrame. Noop unless passing --stacktraceMsgs and --stacktrace - when NimStackTrace and NimStackTraceMsgs: - block: - var fr {.inject, noinit.}: PFrame - {.emit: "`fr` = &FR_;".} - # consider setting a custom upper limit on size (analog to stack overflow) - frameMsgBuf.setLen fr.frameMsgLen - frameMsgBuf.add prefix - frameMsgBuf.add msg - fr.frameMsgLen += prefix.len + msg.len diff --git a/lib/std/strbasics.nim b/lib/std/strbasics.nim deleted file mode 100644 index be1dd7a58..000000000 --- a/lib/std/strbasics.nim +++ /dev/null @@ -1,119 +0,0 @@ -# -# -# Nim's Runtime Library -# (c) Copyright 2021 Nim Contributors -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# - -## This module provides some high performance string operations. -## -## Experimental API, subject to change. - -when defined(nimPreviewSlimSystem): - import std/assertions - - -const whitespaces = {' ', '\t', '\v', '\r', '\l', '\f'} - -proc add*(x: var string, y: openArray[char]) = - ## Concatenates `x` and `y` in place. `y` must not overlap with `x` to - ## allow future `memcpy` optimizations. - # Use `{.noalias.}` ? - let n = x.len - x.setLen n + y.len - # pending https://github.com/nim-lang/Nim/issues/14655#issuecomment-643671397 - # use x.setLen(n + y.len, isInit = false) - var i = 0 - while i < y.len: - x[n + i] = y[i] - i.inc - # xxx use `nimCopyMem(x[n].addr, y[0].addr, y.len)` after some refactoring - -func stripSlice(s: openArray[char], leading = true, trailing = true, chars: set[char] = whitespaces): Slice[int] = - ## Returns the slice range of `s` which is stripped `chars`. - runnableExamples: - assert stripSlice(" abc ") == 1 .. 3 - var - first = 0 - last = high(s) - if leading: - while first <= last and s[first] in chars: inc(first) - if trailing: - while last >= first and s[last] in chars: dec(last) - result = first .. last - -func setSlice*(s: var string, slice: Slice[int]) = - ## Inplace version of `substr`. - runnableExamples: - import std/sugar - - var a = "Hello, Nim!" - doAssert a.dup(setSlice(7 .. 9)) == "Nim" - doAssert a.dup(setSlice(0 .. 0)) == "H" - doAssert a.dup(setSlice(0 .. 1)) == "He" - doAssert a.dup(setSlice(0 .. 10)) == a - doAssert a.dup(setSlice(1 .. 0)).len == 0 - doAssert a.dup(setSlice(20 .. -1)).len == 0 - - - doAssertRaises(AssertionDefect): - discard a.dup(setSlice(-1 .. 1)) - - doAssertRaises(AssertionDefect): - discard a.dup(setSlice(1 .. 11)) - - - let first = slice.a - let last = slice.b - - assert first >= 0 - assert last <= s.high - - if first > last: - s.setLen(0) - return - template impl = - for index in first .. last: - s[index - first] = s[index] - if first > 0: - when nimvm: impl() - else: - # not JS and not Nimscript - when not declared(moveMem): - impl() - else: - when defined(nimSeqsV2): - prepareMutation(s) - moveMem(addr s[0], addr s[first], last - first + 1) - s.setLen(last - first + 1) - -func strip*(a: var string, leading = true, trailing = true, chars: set[char] = whitespaces) {.inline.} = - ## Inplace version of `strip`. Strips leading or - ## trailing `chars` (default: whitespace characters). - ## - ## If `leading` is true (default), leading `chars` are stripped. - ## If `trailing` is true (default), trailing `chars` are stripped. - ## If both are false, the string is unchanged. - runnableExamples: - var a = " vhellov " - strip(a) - assert a == "vhellov" - - a = " vhellov " - a.strip(leading = false) - assert a == " vhellov" - - a = " vhellov " - a.strip(trailing = false) - assert a == "vhellov " - - var c = "blaXbla" - c.strip(chars = {'b', 'a'}) - assert c == "laXbl" - c = "blaXbla" - c.strip(chars = {'b', 'a', 'l'}) - assert c == "X" - - setSlice(a, stripSlice(a, leading, trailing, chars)) diff --git a/lib/deprecated/pure/sums.nim b/lib/std/sums.nim similarity index 57% rename from lib/deprecated/pure/sums.nim rename to lib/std/sums.nim index a6ce1b85d..dc9d8d507 100644 --- a/lib/deprecated/pure/sums.nim +++ b/lib/std/sums.nim @@ -6,39 +6,12 @@ # See the file "copying.txt", included in this # distribution, for details about the copyright. -## Accurate summation functions. +## Fast sumation functions. -{.deprecated: "use the nimble package `sums` instead.".} - -runnableExamples: - import std/math - - template `~=`(x, y: float): bool = abs(x - y) < 1e-4 - - let - n = 1_000_000 - first = 1e10 - small = 0.1 - var data = @[first] - for _ in 1 .. n: - data.add(small) - - let result = first + small * n.float - - doAssert abs(sum(data) - result) > 0.3 - doAssert sumKbn(data) ~= result - doAssert sumPairs(data) ~= result - -## See also -## ======== -## * `math module `_ for a standard `sum proc `_ func sumKbn*[T](x: openArray[T]): T = - ## Kahan-Babuška-Neumaier summation: O(1) error growth, at the expense - ## of a considerable increase in computational cost. - ## - ## See: - ## * https://en.wikipedia.org/wiki/Kahan_summation_algorithm#Further_enhancements + ## Kahan (compensated) summation: O(1) error growth, at the expense + ## of a considerable increase in computational expense. if len(x) == 0: return var sum = x[0] var c = T(0) @@ -62,13 +35,13 @@ func sumPairwise[T](x: openArray[T], i0, n: int): T = result = sumPairwise(x, i0, n2) + sumPairwise(x, i0 + n2, n - n2) func sumPairs*[T](x: openArray[T]): T = - ## Pairwise (cascade) summation of `x[i0:i0+n-1]`, with O(log n) error growth + ## Pairwise (cascade) summation of ``x[i0:i0+n-1]``, with O(log n) error growth ## (vs O(n) for a simple loop) with negligible performance cost if ## the base case is large enough. ## ## See, e.g.: - ## * https://en.wikipedia.org/wiki/Pairwise_summation - ## * Higham, Nicholas J. (1993), "The accuracy of floating point + ## * http://en.wikipedia.org/wiki/Pairwise_summation + ## Higham, Nicholas J. (1993), "The accuracy of floating point ## summation", SIAM Journal on Scientific Computing 14 (4): 783–799. ## ## In fact, the root-mean-square error growth, assuming random roundoff @@ -76,5 +49,30 @@ func sumPairs*[T](x: openArray[T]): T = ## in practice. See: ## * Manfred Tasche and Hansmartin Zeuner, Handbook of ## Analytic-Computational Methods in Applied Mathematics (2000). + ## let n = len(x) if n == 0: T(0) else: sumPairwise(x, 0, n) + + +when isMainModule: + from math import pow + + var epsilon = 1.0 + while 1.0 + epsilon != 1.0: + epsilon /= 2.0 + let data = @[1.0, epsilon, -epsilon] + assert sumKbn(data) == 1.0 + assert sumPairs(data) != 1.0 # known to fail + assert (1.0 + epsilon) - epsilon != 1.0 + + var tc1: seq[float] + for n in 1 .. 1000: + tc1.add 1.0 / n.float + assert sumKbn(tc1) == 7.485470860550345 + assert sumPairs(tc1) == 7.485470860550345 + + var tc2: seq[float] + for n in 1 .. 1000: + tc2.add pow(-1.0, n.float) / n.float + assert sumKbn(tc2) == -0.6926474305598203 + assert sumPairs(tc2) == -0.6926474305598204 diff --git a/lib/std/symlinks.nim b/lib/std/symlinks.nim deleted file mode 100644 index 54ab7b677..000000000 --- a/lib/std/symlinks.nim +++ /dev/null @@ -1,33 +0,0 @@ -## This module implements symlink (symbolic link) handling. - -## .. importdoc:: os.nim - -from paths import Path, ReadDirEffect - -from std/private/ossymlinks import symlinkExists, createSymlink, expandSymlink - -proc symlinkExists*(link: Path): bool {.inline, tags: [ReadDirEffect].} = - ## Returns true if the symlink `link` exists. Will return true - ## regardless of whether the link points to a directory or file. - result = symlinkExists(link.string) - -proc createSymlink*(src, dest: Path) {.inline.} = - ## Create a symbolic link at `dest` which points to the item specified - ## by `src`. On most operating systems, will fail if a link already exists. - ## - ## .. warning:: Some OS's (such as Microsoft Windows) restrict the creation - ## of symlinks to root users (administrators) or users with developer mode enabled. - ## - ## See also: - ## * `createHardlink proc`_ - ## * `expandSymlink proc`_ - createSymlink(src.string, dest.string) - -proc expandSymlink*(symlinkPath: Path): Path {.inline.} = - ## Returns a string representing the path to which the symbolic link points. - ## - ## On Windows this is a noop, `symlinkPath` is simply returned. - ## - ## See also: - ## * `createSymlink proc`_ - result = Path(expandSymlink(symlinkPath.string)) diff --git a/lib/std/sysrand.nim b/lib/std/sysrand.nim deleted file mode 100644 index eeaa23d72..000000000 --- a/lib/std/sysrand.nim +++ /dev/null @@ -1,325 +0,0 @@ -# -# -# Nim's Runtime Library -# (c) Copyright 2021 Nim contributors -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# - -## .. warning:: This module was added in Nim 1.6. If you are using it for cryptographic purposes, -## keep in mind that so far this has not been audited by any security professionals, -## therefore may not be secure. -## -## `std/sysrand` generates random numbers from a secure source provided by the operating system. -## It is a cryptographically secure pseudorandom number generator -## and should be unpredictable enough for cryptographic applications, -## though its exact quality depends on the OS implementation. -## -## | Targets | Implementation | -## | :--- | ----: | -## | Windows | `BCryptGenRandom`_ | -## | Linux | `getrandom`_ | -## | MacOSX | `SecRandomCopyBytes`_ | -## | iOS | `SecRandomCopyBytes`_ | -## | OpenBSD | `getentropy openbsd`_ | -## | FreeBSD | `getrandom freebsd`_ | -## | JS (Web Browser) | `getRandomValues`_ | -## | Node.js | `randomFillSync`_ | -## | Other Unix platforms | `/dev/urandom`_ | -## -## .. _BCryptGenRandom: https://docs.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptgenrandom -## .. _getrandom: https://man7.org/linux/man-pages/man2/getrandom.2.html -## .. _getentropy: https://www.unix.com/man-page/mojave/2/getentropy -## .. _SecRandomCopyBytes: https://developer.apple.com/documentation/security/1399291-secrandomcopybytes?language=objc -## .. _getentropy openbsd: https://man.openbsd.org/getentropy.2 -## .. _getrandom freebsd: https://www.freebsd.org/cgi/man.cgi?query=getrandom&manpath=FreeBSD+12.0-stable -## .. _getRandomValues: https://www.w3.org/TR/WebCryptoAPI/#Crypto-method-getRandomValues -## .. _randomFillSync: https://nodejs.org/api/crypto.html#crypto_crypto_randomfillsync_buffer_offset_size -## .. _/dev/urandom: https://en.wikipedia.org/wiki//dev/random -## -## On a Linux target, a call to the `getrandom` syscall can be avoided (e.g. -## for targets running kernel version < 3.17) by passing a compile flag of -## `-d:nimNoGetRandom`. If this flag is passed, sysrand will use `/dev/urandom` -## as with any other POSIX compliant OS. -## - -runnableExamples: - doAssert urandom(0).len == 0 - doAssert urandom(113).len == 113 - doAssert urandom(1234) != urandom(1234) # unlikely to fail in practice - -## -## See also -## ======== -## * `random module `_ -## - - -when not defined(js): - import std/oserrors - -when defined(posix): - import posix - -when defined(nimPreviewSlimSystem): - import std/assertions - -const - batchImplOS = defined(freebsd) or defined(openbsd) or defined(zephyr) - batchSize {.used.} = 256 - -when batchImplOS: - template batchImpl(result: var int, dest: var openArray[byte], getRandomImpl) = - let size = dest.len - if size == 0: - return - - let - chunks = (size - 1) div batchSize - left = size - chunks * batchSize - - for i in 0 ..< chunks: - let readBytes = getRandomImpl(addr dest[result], batchSize) - if readBytes < 0: - return readBytes - inc(result, batchSize) - - result = getRandomImpl(addr dest[result], left) - -when defined(js): - import std/private/jsutils - - when defined(nodejs): - {.emit: "const _nim_nodejs_crypto = require('crypto');".} - - proc randomFillSync(p: Uint8Array) {.importjs: "_nim_nodejs_crypto.randomFillSync(#)".} - - template urandomImpl(result: var int, dest: var openArray[byte]) = - let size = dest.len - if size == 0: - return - - var src = newUint8Array(size) - randomFillSync(src) - for i in 0 ..< size: - dest[i] = src[i] - - else: - proc getRandomValues(p: Uint8Array) {.importjs: "window.crypto.getRandomValues(#)".} - # The requested length of `p` must not be more than 65536. - - proc assign(dest: var openArray[byte], src: Uint8Array, base: int, size: int) = - getRandomValues(src) - for j in 0 ..< size: - dest[base + j] = src[j] - - template urandomImpl(result: var int, dest: var openArray[byte]) = - let size = dest.len - if size == 0: - return - - if size <= batchSize: - var src = newUint8Array(size) - assign(dest, src, 0, size) - return - - let - chunks = (size - 1) div batchSize - left = size - chunks * batchSize - - var srcArray = newUint8Array(batchSize) - for i in 0 ..< chunks: - assign(dest, srcArray, result, batchSize) - inc(result, batchSize) - - var leftArray = newUint8Array(left) - assign(dest, leftArray, result, left) - -elif defined(windows): - type - PVOID = pointer - BCRYPT_ALG_HANDLE = PVOID - PUCHAR = ptr uint8 - NTSTATUS = clong - ULONG = culong - - const - STATUS_SUCCESS = 0x00000000 - BCRYPT_USE_SYSTEM_PREFERRED_RNG = 0x00000002 - - proc bCryptGenRandom( - hAlgorithm: BCRYPT_ALG_HANDLE, - pbBuffer: PUCHAR, - cbBuffer: ULONG, - dwFlags: ULONG - ): NTSTATUS {.stdcall, importc: "BCryptGenRandom", dynlib: "Bcrypt.dll".} - - - proc randomBytes(pbBuffer: pointer, cbBuffer: Natural): int {.inline.} = - bCryptGenRandom(nil, cast[PUCHAR](pbBuffer), ULONG(cbBuffer), - BCRYPT_USE_SYSTEM_PREFERRED_RNG) - - template urandomImpl(result: var int, dest: var openArray[byte]) = - let size = dest.len - if size == 0: - return - - result = randomBytes(addr dest[0], size) - -elif defined(linux) and not defined(nimNoGetRandom) and not defined(emscripten): - # TODO using let, pending bootstrap >= 1.4.0 - var SYS_getrandom {.importc: "SYS_getrandom", header: "".}: clong - const syscallHeader = """#include -#include """ - - proc syscall(n: clong): clong {. - importc: "syscall", varargs, header: syscallHeader.} - # When reading from the urandom source (GRND_RANDOM is not set), - # getrandom() will block until the entropy pool has been - # initialized (unless the GRND_NONBLOCK flag was specified). If a - # request is made to read a large number of bytes (more than 256), - # getrandom() will block until those bytes have been generated and - # transferred from kernel memory to buf. - - template urandomImpl(result: var int, dest: var openArray[byte]) = - let size = dest.len - if size == 0: - return - - while result < size: - let readBytes = syscall(SYS_getrandom, addr dest[result], cint(size - result), 0).int - if readBytes == 0: - doAssert false - elif readBytes > 0: - inc(result, readBytes) - else: - if osLastError().int in {EINTR, EAGAIN}: - discard - else: - result = -1 - break - -elif defined(openbsd): - proc getentropy(p: pointer, size: cint): cint {.importc: "getentropy", header: "".} - # Fills a buffer with high-quality entropy, - # which can be used as input for process-context pseudorandom generators like `arc4random`. - # The maximum buffer size permitted is 256 bytes. - - proc getRandomImpl(p: pointer, size: int): int {.inline.} = - result = getentropy(p, cint(size)).int - -elif defined(zephyr): - proc sys_csrand_get(dst: pointer, length: csize_t): cint {.importc: "sys_csrand_get", header: "".} - # Fill the destination buffer with cryptographically secure - # random data values - # - - proc getRandomImpl(p: pointer, size: int): int {.inline.} = - # 0 if success, -EIO if entropy reseed error - result = sys_csrand_get(p, csize_t(size)).int - -elif defined(freebsd): - type cssize_t {.importc: "ssize_t", header: "".} = int - - proc getrandom(p: pointer, size: csize_t, flags: cuint): cssize_t {.importc: "getrandom", header: "".} - # Upon successful completion, the number of bytes which were actually read - # is returned. For requests larger than 256 bytes, this can be fewer bytes - # than were requested. Otherwise, -1 is returned and the global variable - # errno is set to indicate the error. - - proc getRandomImpl(p: pointer, size: int): int {.inline.} = - result = getrandom(p, csize_t(size), 0) - -elif defined(ios) or defined(macosx): - {.passl: "-framework Security".} - - const errSecSuccess = 0 ## No error. - - type - SecRandom {.importc: "struct __SecRandom".} = object - - SecRandomRef = ptr SecRandom - ## An abstract Core Foundation-type object containing information about a random number generator. - - proc secRandomCopyBytes( - rnd: SecRandomRef, count: csize_t, bytes: pointer - ): cint {.importc: "SecRandomCopyBytes", header: "".} - ## https://developer.apple.com/documentation/security/1399291-secrandomcopybytes - - template urandomImpl(result: var int, dest: var openArray[byte]) = - let size = dest.len - if size == 0: - return - - result = secRandomCopyBytes(nil, csize_t(size), addr dest[0]) - -else: - template urandomImpl(result: var int, dest: var openArray[byte]) = - let size = dest.len - if size == 0: - return - - # see: https://www.2uo.de/myths-about-urandom/ which justifies using urandom instead of random - let fd = posix.open("/dev/urandom", O_RDONLY) - - if fd < 0: - result = -1 - else: - try: - var stat: Stat - if fstat(fd, stat) != -1 and S_ISCHR(stat.st_mode): - let - chunks = (size - 1) div batchSize - left = size - chunks * batchSize - - for i in 0 ..< chunks: - let readBytes = posix.read(fd, addr dest[result], batchSize) - if readBytes < 0: - return readBytes - inc(result, batchSize) - - result = posix.read(fd, addr dest[result], left) - else: - result = -1 - finally: - discard posix.close(fd) - -proc urandomInternalImpl(dest: var openArray[byte]): int {.inline.} = - when batchImplOS: - batchImpl(result, dest, getRandomImpl) - else: - urandomImpl(result, dest) - -proc urandom*(dest: var openArray[byte]): bool = - ## Fills `dest` with random bytes suitable for cryptographic use. - ## If the call succeeds, returns `true`. - ## - ## If `dest` is empty, `urandom` immediately returns success, - ## without calling the underlying operating system API. - ## - ## .. warning:: The code hasn't been audited by cryptography experts and - ## is provided as-is without guarantees. Use at your own risks. For production - ## systems we advise you to request an external audit. - result = true - when defined(js): discard urandomInternalImpl(dest) - else: - let ret = urandomInternalImpl(dest) - when defined(windows): - if ret != STATUS_SUCCESS: - result = false - else: - if ret < 0: - result = false - -proc urandom*(size: Natural): seq[byte] {.inline.} = - ## Returns random bytes suitable for cryptographic use. - ## - ## .. warning:: The code hasn't been audited by cryptography experts and - ## is provided as-is without guarantees. Use at your own risks. For production - ## systems we advise you to request an external audit. - result = newSeq[byte](size) - when defined(js): discard urandomInternalImpl(result) - else: - if not urandom(result): - raiseOSError(osLastError()) diff --git a/lib/std/tasks.nim b/lib/std/tasks.nim deleted file mode 100644 index 055ddf144..000000000 --- a/lib/std/tasks.nim +++ /dev/null @@ -1,277 +0,0 @@ -# -# -# Nim's Runtime Library -# (c) Copyright 2021 Nim contributors -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# - -## This module provides basic primitives for creating parallel programs. -## A `Task` should be only owned by a single Thread, it cannot be shared by threads. - -import std/[macros, isolation, typetraits] -import system/ansi_c - -when defined(nimPreviewSlimSystem): - import std/assertions - -export isolation - - -when compileOption("threads"): - from std/effecttraits import isGcSafe - - -# -# proc hello(a: int, b: string) = -# echo $a & b -# -# let literal = "Nim" -# let t = toTask(hello(521, literal)) -# -# -# is roughly converted to -# -# type -# ScratchObj_369098780 = object -# a: int -# b: string -# -# let scratch_369098762 = cast[ptr ScratchObj_369098780](c_calloc(csize_t 1, -# csize_t sizeof(ScratchObj_369098780))) -# if scratch_369098762.isNil: -# raise newException(OutOfMemDefect, "Could not allocate memory") -# block: -# var isolate_369098776 = isolate(521) -# scratch_369098762.a = extract(isolate_369098776) -# var isolate_369098778 = isolate(literal) -# scratch_369098762.b = extract(isolate_369098778) -# proc hello_369098781(args`gensym3: pointer) {.nimcall.} = -# let objTemp_369098775 = cast[ptr ScratchObj_369098780](args`gensym3) -# let :tmp_369098777 = objTemp_369098775.a -# let :tmp_369098779 = objTemp_369098775.b -# hello(a = :tmp_369098777, b = :tmp_369098779) -# -# proc destroyScratch_369098782(args`gensym3: pointer) {.nimcall.} = -# let obj_369098783 = cast[ptr ScratchObj_369098780](args`gensym3) -# =destroy(obj_369098783[]) -# let t = Task(callback: hello_369098781, args: scratch_369098762, destroy: destroyScratch_369098782) -# - - -type - Task* = object ## `Task` contains the callback and its arguments. - callback: proc (args: pointer) {.nimcall, gcsafe.} - args: pointer - destroy: proc (args: pointer) {.nimcall, gcsafe.} - - -proc `=copy`*(x: var Task, y: Task) {.error.} - -proc `=destroy`*(t: var Task) {.inline, gcsafe.} = - ## Frees the resources allocated for a `Task`. - if t.args != nil: - if t.destroy != nil: - t.destroy(t.args) - c_free(t.args) - -proc invoke*(task: Task) {.inline, gcsafe.} = - ## Invokes the `task`. - assert task.callback != nil - task.callback(task.args) - -template checkIsolate(scratchAssignList: seq[NimNode], procParam, scratchDotExpr: NimNode) = - # block: - # var isoTempA = isolate(521) - # scratch.a = extract(isolateA) - # var isoTempB = isolate(literal) - # scratch.b = extract(isolateB) - let isolatedTemp = genSym(nskTemp, "isoTemp") - scratchAssignList.add newVarStmt(isolatedTemp, newCall(newIdentNode("isolate"), procParam)) - scratchAssignList.add newAssignment(scratchDotExpr, - newCall(newIdentNode("extract"), isolatedTemp)) - -template addAllNode(assignParam: NimNode, procParam: NimNode) = - let scratchDotExpr = newDotExpr(scratchIdent, formalParams[i][0]) - - checkIsolate(scratchAssignList, procParam, scratchDotExpr) - - let tempNode = genSym(kind = nskTemp, ident = formalParams[i][0].strVal) - callNode.add nnkExprEqExpr.newTree(formalParams[i][0], tempNode) - tempAssignList.add newLetStmt(tempNode, newDotExpr(objTemp, formalParams[i][0])) - scratchRecList.add newIdentDefs(newIdentNode(formalParams[i][0].strVal), assignParam) - -macro toTask*(e: typed{nkCall | nkInfix | nkPrefix | nkPostfix | nkCommand | nkCallStrLit}): Task = - ## Converts the call and its arguments to `Task`. - runnableExamples("--gc:orc"): - proc hello(a: int) = echo a - - let b = toTask hello(13) - assert b is Task - - if getTypeInst(e).typeKind != ntyVoid: - error("'toTask' cannot accept a call with a return value", e) - - when compileOption("threads"): - if not isGcSafe(e[0]): - error("'toTask' takes a GC safe call expression", e) - - if hasClosure(e[0]): - error("closure call is not allowed", e) - - if e.len > 1: - let scratchIdent = genSym(kind = nskTemp, ident = "scratch") - let impl = e[0].getTypeInst - - when defined(nimTasksDebug): - echo impl.treeRepr - echo e.treeRepr - let formalParams = impl[0] - - var - scratchRecList = newNimNode(nnkRecList) - scratchAssignList: seq[NimNode] - tempAssignList: seq[NimNode] - callNode: seq[NimNode] - - let - objTemp = genSym(nskTemp, ident = "objTemp") - - for i in 1 ..< formalParams.len: - var param = formalParams[i][1] - - if param.kind == nnkBracketExpr and param[0].eqIdent("sink"): - param = param[0] - - if param.typeKind in {ntyExpr, ntyStmt}: - error("'toTask'ed function cannot have a 'typed' or 'untyped' parameter", e) - - case param.kind - of nnkVarTy: - error("'toTask'ed function cannot have a 'var' parameter", e) - of nnkBracketExpr: - if param[0].typeKind == ntyTypeDesc: - callNode.add nnkExprEqExpr.newTree(formalParams[i][0], e[i]) - elif param[0].typeKind in {ntyVarargs, ntyOpenArray}: - if param[1].typeKind in {ntyExpr, ntyStmt}: - error("'toTask'ed function cannot have a 'typed' or 'untyped' parameter", e) - let - seqType = nnkBracketExpr.newTree(newIdentNode("seq"), param[1]) - seqCallNode = newCall("@", e[i]) - addAllNode(seqType, seqCallNode) - else: - addAllNode(param, e[i]) - of nnkBracket, nnkObjConstr: - # passing by static parameters - # so we pass them directly instead of passing by scratchObj - callNode.add nnkExprEqExpr.newTree(formalParams[i][0], e[i]) - of nnkSym, nnkPtrTy: - addAllNode(param, e[i]) - of nnkCharLit..nnkNilLit: - callNode.add nnkExprEqExpr.newTree(formalParams[i][0], e[i]) - else: - error("'toTask'ed function cannot have a parameter of " & $param.kind & " kind", e) - - let scratchObjType = genSym(kind = nskType, ident = "ScratchObj") - let scratchObj = nnkTypeSection.newTree( - nnkTypeDef.newTree( - scratchObjType, - newEmptyNode(), - nnkObjectTy.newTree( - newEmptyNode(), - newEmptyNode(), - scratchRecList - ) - ) - ) - - - let scratchObjPtrType = quote do: - cast[ptr `scratchObjType`](c_calloc(csize_t 1, csize_t sizeof(`scratchObjType`))) - - let scratchLetSection = newLetStmt( - scratchIdent, - scratchObjPtrType - ) - - let scratchCheck = quote do: - if `scratchIdent`.isNil: - raise newException(OutOfMemDefect, "Could not allocate memory") - - var stmtList = newStmtList() - stmtList.add(scratchObj) - stmtList.add(scratchLetSection) - stmtList.add(scratchCheck) - stmtList.add(nnkBlockStmt.newTree(newEmptyNode(), newStmtList(scratchAssignList))) - - var functionStmtList = newStmtList() - let funcCall = newCall(e[0], callNode) - functionStmtList.add tempAssignList - functionStmtList.add funcCall - - let funcName = genSym(nskProc, e[0].strVal) - let destroyName = genSym(nskProc, "destroyScratch") - let objTemp2 = genSym(ident = "obj") - let tempNode = quote("@") do: - `=destroy`(@objTemp2[]) - - result = quote do: - `stmtList` - - proc `funcName`(args: pointer) {.gcsafe, nimcall.} = - let `objTemp` = cast[ptr `scratchObjType`](args) - `functionStmtList` - - proc `destroyName`(args: pointer) {.gcsafe, nimcall.} = - let `objTemp2` = cast[ptr `scratchObjType`](args) - `tempNode` - - Task(callback: `funcName`, args: `scratchIdent`, destroy: `destroyName`) - else: - let funcCall = newCall(e[0]) - let funcName = genSym(nskProc, e[0].strVal) - - result = quote do: - proc `funcName`(args: pointer) {.gcsafe, nimcall.} = - `funcCall` - - Task(callback: `funcName`, args: nil) - - when defined(nimTasksDebug): - echo result.repr - -runnableExamples("--gc:orc"): - block: - var num = 0 - proc hello(a: int) = inc num, a - - let b = toTask hello(13) - b.invoke() - assert num == 13 - # A task can be invoked multiple times - b.invoke() - assert num == 26 - - block: - type - Runnable = ref object - data: int - - var data: int - proc hello(a: Runnable) {.nimcall.} = - a.data += 2 - data = a.data - - - when false: - # the parameters of call must be isolated. - let x = Runnable(data: 12) - let b = toTask hello(x) # error ----> expression cannot be isolated: x - b.invoke() - - let b = toTask(hello(Runnable(data: 12))) - b.invoke() - assert data == 14 - b.invoke() - assert data == 16 diff --git a/lib/std/tempfiles.nim b/lib/std/tempfiles.nim deleted file mode 100644 index 1160aaaad..000000000 --- a/lib/std/tempfiles.nim +++ /dev/null @@ -1,192 +0,0 @@ -# -# -# Nim's Runtime Library -# (c) Copyright 2021 Nim contributors -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# - -## This module creates temporary files and directories. -## -## Experimental API, subject to change. - -#[ -See also: -* `GetTempFileName` (on windows), refs https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-gettempfilenamea -* `mkstemp` (posix), refs https://man7.org/linux/man-pages/man3/mkstemp.3.html -]# - -import os, random - -when defined(nimPreviewSlimSystem): - import std/syncio - -const - maxRetry = 10000 - letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" - nimTempPathLength {.intdefine.} = 8 - - -when defined(windows): - import winlean - when defined(nimPreviewSlimSystem): - import std/widestrs - - var O_RDWR {.importc: "_O_RDWR", header: "".}: cint - - proc c_fdopen( - filehandle: cint, - mode: cstring - ): File {.importc: "_fdopen",header: "".} - - proc open_osfhandle(osh: Handle, mode: cint): cint {. - importc: "_open_osfhandle", header: "".} - - proc close_osfandle(fd: cint): cint {. - importc: "_close", header: "".} -else: - import posix - - proc c_fdopen( - filehandle: cint, - mode: cstring - ): File {.importc: "fdopen",header: "".} - - -proc safeOpen(filename: string): File = - ## Open files exclusively; returns `nil` if the file already exists. - # xxx this should be clarified; it doesn't in particular prevent other processes - # from opening the file, at least currently. - when defined(windows): - let dwShareMode = FILE_SHARE_DELETE or FILE_SHARE_READ or FILE_SHARE_WRITE - let dwCreation = CREATE_NEW - let dwFlags = FILE_FLAG_BACKUP_SEMANTICS or FILE_ATTRIBUTE_NORMAL - let handle = createFileW(newWideCString(filename), GENERIC_READ or GENERIC_WRITE, dwShareMode, - nil, dwCreation, dwFlags, Handle(0)) - - if handle == INVALID_HANDLE_VALUE: - if getLastError() == ERROR_FILE_EXISTS: - return nil - else: - raiseOSError(osLastError(), filename) - - let fileHandle = open_osfhandle(handle, O_RDWR) - if fileHandle == -1: - discard closeHandle(handle) - raiseOSError(osLastError(), filename) - - result = c_fdopen(fileHandle, "w+") - if result == nil: - discard close_osfandle(fileHandle) - raiseOSError(osLastError(), filename) - else: - # xxx we need a `proc toMode(a: FilePermission): Mode`, possibly by - # exposing fusion/filepermissions.fromFilePermissions to stdlib; then we need - # to expose a `perm` param so users can customize this (e.g. the temp file may - # need execute permissions), and figure out how to make the API cross platform. - let mode = Mode(S_IRUSR or S_IWUSR) - let flags = posix.O_RDWR or posix.O_CREAT or posix.O_EXCL - let fileHandle = posix.open(filename, flags, mode) - if fileHandle == -1: - if errno == EEXIST: - # xxx `getLastError()` should be defined on posix too and resolve to `errno`? - return nil - else: - raiseOSError(osLastError(), filename) - - result = c_fdopen(fileHandle, "w+") - if result == nil: - discard posix.close(fileHandle) # TODO handles failure when closing file - raiseOSError(osLastError(), filename) - - -type - NimTempPathState = object - state: Rand - isInit: bool - -var nimTempPathState {.threadvar.}: NimTempPathState - -template randomPathName(length: Natural): string = - var res = newString(length) - if not nimTempPathState.isInit: - nimTempPathState.isInit = true - nimTempPathState.state = initRand() - - for i in 0 ..< length: - res[i] = nimTempPathState.state.sample(letters) - res - -proc getTempDirImpl(dir: string): string {.inline.} = - result = dir - if result.len == 0: - result = getTempDir() - -proc genTempPath*(prefix, suffix: string, dir = ""): string = - ## Generates a path name in `dir`. - ## - ## The path begins with `prefix` and ends with `suffix`. - ## - ## .. note:: `dir` must exist (empty `dir` will resolve to `getTempDir `_). - let dir = getTempDirImpl(dir) - result = dir / (prefix & randomPathName(nimTempPathLength) & suffix) - -proc createTempFile*(prefix, suffix: string, dir = ""): tuple[cfile: File, path: string] = - ## Creates a new temporary file in the directory `dir`. - ## - ## This generates a path name using `genTempPath(prefix, suffix, dir)` and - ## returns a file handle to an open file and the path of that file, possibly after - ## retrying to ensure it doesn't already exist. - ## - ## If failing to create a temporary file, `OSError` will be raised. - ## - ## .. note:: It is the caller's responsibility to close `result.cfile` and - ## remove `result.file` when no longer needed. - ## .. note:: `dir` must exist (empty `dir` will resolve to `getTempDir `_). - runnableExamples: - import std/os - doAssertRaises(OSError): discard createTempFile("", "", "nonexistent") - let (cfile, path) = createTempFile("tmpprefix_", "_end.tmp") - # path looks like: getTempDir() / "tmpprefix_FDCIRZA0_end.tmp" - cfile.write "foo" - cfile.setFilePos 0 - assert readAll(cfile) == "foo" - close cfile - assert readFile(path) == "foo" - removeFile(path) - # xxx why does above work without `cfile.flushFile` ? - let dir = getTempDirImpl(dir) - for i in 0 ..< maxRetry: - result.path = genTempPath(prefix, suffix, dir) - result.cfile = safeOpen(result.path) - if result.cfile != nil: - return - - raise newException(OSError, "Failed to create a temporary file under directory " & dir) - -proc createTempDir*(prefix, suffix: string, dir = ""): string = - ## Creates a new temporary directory in the directory `dir`. - ## - ## This generates a dir name using `genTempPath(prefix, suffix, dir)`, creates - ## the directory and returns it, possibly after retrying to ensure it doesn't - ## already exist. - ## - ## If failing to create a temporary directory, `OSError` will be raised. - ## - ## .. note:: It is the caller's responsibility to remove the directory when no longer needed. - ## .. note:: `dir` must exist (empty `dir` will resolve to `getTempDir `_). - runnableExamples: - import std/os - doAssertRaises(OSError): discard createTempDir("", "", "nonexistent") - let dir = createTempDir("tmpprefix_", "_end") - # dir looks like: getTempDir() / "tmpprefix_YEl9VuVj_end" - assert dirExists(dir) - removeDir(dir) - let dir = getTempDirImpl(dir) - for i in 0 ..< maxRetry: - result = genTempPath(prefix, suffix, dir) - if not existsOrCreateDir(result): - return - - raise newException(OSError, "Failed to create a temporary directory under directory " & dir) diff --git a/lib/std/time_t.nim b/lib/std/time_t.nim index 7fb6e6d46..37918ee6c 100644 --- a/lib/std/time_t.nim +++ b/lib/std/time_t.nim @@ -9,9 +9,9 @@ when defined(nimdoc): type - Impl = distinct int64 - Time* = Impl ## \ - ## Wrapper for `time_t`. On posix, this is an alias to `posix.Time`. + impl = distinct int64 + Time* = impl ## \ + ## Wrapper for ``time_t``. On posix, this is an alias to ``posix.Time``. elif defined(windows): when defined(i386) and defined(gcc): type Time* {.importc: "time_t", header: "".} = distinct int32 diff --git a/lib/std/typedthreads.nim b/lib/std/typedthreads.nim deleted file mode 100644 index 8359ca353..000000000 --- a/lib/std/typedthreads.nim +++ /dev/null @@ -1,263 +0,0 @@ -# -# -# Nim's Runtime Library -# (c) Copyright 2012 Andreas Rumpf -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# - -## Thread support for Nim. -## -## Examples -## ======== -## -## .. code-block:: Nim -## -## import std/locks -## -## var -## thr: array[0..4, Thread[tuple[a,b: int]]] -## L: Lock -## -## proc threadFunc(interval: tuple[a,b: int]) {.thread.} = -## for i in interval.a..interval.b: -## acquire(L) # lock stdout -## echo i -## release(L) -## -## initLock(L) -## -## for i in 0..high(thr): -## createThread(thr[i], threadFunc, (i*10, i*10+5)) -## joinThreads(thr) -## -## deinitLock(L) - -import std/private/[threadtypes] -export Thread - -import system/ansi_c - -when defined(nimPreviewSlimSystem): - import std/assertions - -when defined(genode): - import genode/env - -when hostOS == "any": - {.error: "Threads not implemented for os:any. Please compile with --threads:off.".} - -when hasAllocStack or defined(zephyr) or defined(freertos) or defined(nuttx) or - defined(cpu16) or defined(cpu8): - const - nimThreadStackSize {.intdefine.} = 8192 - nimThreadStackGuard {.intdefine.} = 128 - - StackGuardSize = nimThreadStackGuard - ThreadStackSize = nimThreadStackSize - nimThreadStackGuard -else: - const - StackGuardSize = 4096 - ThreadStackMask = - when defined(genode): - 1024*64*sizeof(int)-1 - else: - 1024*256*sizeof(int)-1 - - ThreadStackSize = ThreadStackMask+1 - StackGuardSize - - -when defined(gcDestructors): - proc allocThreadStorage(size: int): pointer = - result = c_malloc(csize_t size) - zeroMem(result, size) -else: - template allocThreadStorage(size: untyped): untyped = allocShared0(size) - -#const globalsSlot = ThreadVarSlot(0) -#sysAssert checkSlot.int == globalsSlot.int - -# Zephyr doesn't include this properly without some help -when defined(zephyr): - {.emit: """/*INCLUDESECTION*/ - #include - """.} - - -# We jump through some hops here to ensure that Nim thread procs can have -# the Nim calling convention. This is needed because thread procs are -# ``stdcall`` on Windows and ``noconv`` on UNIX. Alternative would be to just -# use ``stdcall`` since it is mapped to ``noconv`` on UNIX anyway. - - - -{.push stack_trace:off.} -when defined(windows): - proc threadProcWrapper[TArg](closure: pointer): int32 {.stdcall.} = - nimThreadProcWrapperBody(closure) - # implicitly return 0 -elif defined(genode): - proc threadProcWrapper[TArg](closure: pointer) {.noconv.} = - nimThreadProcWrapperBody(closure) -else: - proc threadProcWrapper[TArg](closure: pointer): pointer {.noconv.} = - nimThreadProcWrapperBody(closure) -{.pop.} - -proc running*[TArg](t: Thread[TArg]): bool {.inline.} = - ## Returns true if `t` is running. - result = t.dataFn != nil - -proc handle*[TArg](t: Thread[TArg]): SysThread {.inline.} = - ## Returns the thread handle of `t`. - result = t.sys - -when hostOS == "windows": - const MAXIMUM_WAIT_OBJECTS = 64 - - proc joinThread*[TArg](t: Thread[TArg]) {.inline.} = - ## Waits for the thread `t` to finish. - discard waitForSingleObject(t.sys, -1'i32) - - proc joinThreads*[TArg](t: varargs[Thread[TArg]]) = - ## Waits for every thread in `t` to finish. - var a: array[MAXIMUM_WAIT_OBJECTS, SysThread] - var k = 0 - while k < len(t): - var count = min(len(t) - k, MAXIMUM_WAIT_OBJECTS) - for i in 0..(count - 1): a[i] = t[i + k].sys - discard waitForMultipleObjects(int32(count), - cast[ptr SysThread](addr(a)), 1, -1) - inc(k, MAXIMUM_WAIT_OBJECTS) - -elif defined(genode): - proc joinThread*[TArg](t: Thread[TArg]) {.importcpp.} - ## Waits for the thread `t` to finish. - - proc joinThreads*[TArg](t: varargs[Thread[TArg]]) = - ## Waits for every thread in `t` to finish. - for i in 0..t.high: joinThread(t[i]) - -else: - proc joinThread*[TArg](t: Thread[TArg]) {.inline.} = - ## Waits for the thread `t` to finish. - discard pthread_join(t.sys, nil) - - proc joinThreads*[TArg](t: varargs[Thread[TArg]]) = - ## Waits for every thread in `t` to finish. - for i in 0..t.high: joinThread(t[i]) - -when false: - # XXX a thread should really release its heap here somehow: - proc destroyThread*[TArg](t: var Thread[TArg]) = - ## Forces the thread `t` to terminate. This is potentially dangerous if - ## you don't have full control over `t` and its acquired resources. - when hostOS == "windows": - discard TerminateThread(t.sys, 1'i32) - else: - discard pthread_cancel(t.sys) - when declared(registerThread): unregisterThread(addr(t)) - t.dataFn = nil - ## if thread `t` already exited, `t.core` will be `null`. - if not isNil(t.core): - deallocThreadStorage(t.core) - t.core = nil - -when hostOS == "windows": - proc createThread*[TArg](t: var Thread[TArg], - tp: proc (arg: TArg) {.thread, nimcall.}, - param: TArg) = - ## Creates a new thread `t` and starts its execution. - ## - ## Entry point is the proc `tp`. - ## `param` is passed to `tp`. `TArg` can be `void` if you - ## don't need to pass any data to the thread. - t.core = cast[PGcThread](allocThreadStorage(sizeof(GcThread))) - - when TArg isnot void: t.data = param - t.dataFn = tp - when hasSharedHeap: t.core.stackSize = ThreadStackSize - var dummyThreadId: int32 - t.sys = createThread(nil, ThreadStackSize, threadProcWrapper[TArg], - addr(t), 0'i32, dummyThreadId) - if t.sys <= 0: - raise newException(ResourceExhaustedError, "cannot create thread") - - proc pinToCpu*[Arg](t: var Thread[Arg]; cpu: Natural) = - ## Pins a thread to a `CPU`:idx:. - ## - ## In other words sets a thread's `affinity`:idx:. - ## If you don't know what this means, you shouldn't use this proc. - setThreadAffinityMask(t.sys, uint(1 shl cpu)) - -elif defined(genode): - var affinityOffset: cuint = 1 - ## CPU affinity offset for next thread, safe to roll-over. - - proc createThread*[TArg](t: var Thread[TArg], - tp: proc (arg: TArg) {.thread, nimcall.}, - param: TArg) = - t.core = cast[PGcThread](allocThreadStorage(sizeof(GcThread))) - - when TArg isnot void: t.data = param - t.dataFn = tp - when hasSharedHeap: t.stackSize = ThreadStackSize - t.sys.initThread( - runtimeEnv, - ThreadStackSize.culonglong, - threadProcWrapper[TArg], addr(t), affinityOffset) - inc affinityOffset - - proc pinToCpu*[Arg](t: var Thread[Arg]; cpu: Natural) = - {.hint: "cannot change Genode thread CPU affinity after initialization".} - discard - -else: - proc createThread*[TArg](t: var Thread[TArg], - tp: proc (arg: TArg) {.thread, nimcall.}, - param: TArg) = - ## Creates a new thread `t` and starts its execution. - ## - ## Entry point is the proc `tp`. `param` is passed to `tp`. - ## `TArg` can be `void` if you - ## don't need to pass any data to the thread. - t.core = cast[PGcThread](allocThreadStorage(sizeof(GcThread))) - - when TArg isnot void: t.data = param - t.dataFn = tp - when hasSharedHeap: t.core.stackSize = ThreadStackSize - var a {.noinit.}: Pthread_attr - doAssert pthread_attr_init(a) == 0 - when hasAllocStack: - var - rawstk = allocThreadStorage(ThreadStackSize + StackGuardSize) - stk = cast[pointer](cast[uint](rawstk) + StackGuardSize) - let setstacksizeResult = pthread_attr_setstack(addr a, stk, ThreadStackSize) - t.rawStack = rawstk - else: - let setstacksizeResult = pthread_attr_setstacksize(a, ThreadStackSize) - - when not defined(ios): - # This fails on iOS - doAssert(setstacksizeResult == 0) - if pthread_create(t.sys, a, threadProcWrapper[TArg], addr(t)) != 0: - raise newException(ResourceExhaustedError, "cannot create thread") - doAssert pthread_attr_destroy(a) == 0 - - proc pinToCpu*[Arg](t: var Thread[Arg]; cpu: Natural) = - ## Pins a thread to a `CPU`:idx:. - ## - ## In other words sets a thread's `affinity`:idx:. - ## If you don't know what this means, you shouldn't use this proc. - when not defined(macosx): - var s {.noinit.}: CpuSet - cpusetZero(s) - cpusetIncl(cpu.cint, s) - setAffinity(t.sys, csize_t(sizeof(s)), s) - -proc createThread*(t: var Thread[void], tp: proc () {.thread, nimcall.}) = - createThread[void](t, tp) - -when not defined(gcOrc): - include system/threadids diff --git a/lib/std/varints.nim b/lib/std/varints.nim index 0d18b9069..fe06b478a 100644 --- a/lib/std/varints.nim +++ b/lib/std/varints.nim @@ -119,3 +119,36 @@ proc encodeZigzag*(x: int64): uint64 {.inline.} = proc decodeZigzag*(x: uint64): int64 {.inline.} = let casted = cast[int64](x) result = (`shr`(casted, 1)) xor (-(casted and 1)) + +when isMainModule: + #import random + + var dest: array[50, byte] + var got: uint64 + + for test in [0xFFFF_FFFF_FFFFF_FFFFu64, 77u64, 0u64, 10_000_000u64, uint64(high(int64)), + uint64(high(int32)),uint64(low(int32)),uint64(low(int64))]: + let wrLen = writeVu64(dest, test) + let rdLen = readVu64(dest, got) + assert wrLen == rdLen + echo(if got == test: "YES" else: "NO") + echo "number is ", got + + if encodeZigzag(decodeZigzag(test)) != test: + echo "Failure for ", test, " ", encodeZigzag(decodeZigzag(test)), " ", decodeZigzag(test) + + for test in 0u64..300u64: + let wrLen = writeVu64(dest, test) + let rdLen = readVu64(dest, got) + assert wrLen == rdLen + if got != test: + echo "BUG! expected: ", test, " got: ", got, " z0: ", dest[0] + + # check this also works for floats: + for test in [0.0, 0.1, 2.0, +Inf, Nan, NegInf]: + let t = cast[uint64](test) + let wrLenB = writeVu64(dest, t) + let rdLenB = readVu64(dest, got) + assert wrLenB == rdLenB + echo rdLenB + echo(if cast[float64](got) == test: "YES" else: "NO") diff --git a/lib/std/vmutils.nim b/lib/std/vmutils.nim deleted file mode 100644 index e16912a3c..000000000 --- a/lib/std/vmutils.nim +++ /dev/null @@ -1,11 +0,0 @@ -##[ -Experimental API, subject to change. -]## - -proc vmTrace*(on: bool) {.compileTime.} = - runnableExamples: - static: vmTrace(true) - proc fn = - var a = 1 - vmTrace(false) - static: fn() diff --git a/lib/std/widestrs.nim b/lib/std/widestrs.nim deleted file mode 100644 index 8973579e1..000000000 --- a/lib/std/widestrs.nim +++ /dev/null @@ -1,229 +0,0 @@ -# -# -# Nim's Runtime Library -# (c) Copyright 2012 Andreas Rumpf -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# - -## Nim support for C/C++'s `wide strings`:idx:. - -#when not declared(ThisIsSystem): -# {.error: "You must not import this module explicitly".} - -type - Utf16Char* = distinct int16 - -when not (defined(cpu16) or defined(cpu8)): - when defined(nimv2): - - type - WideCString* = ptr UncheckedArray[Utf16Char] - - WideCStringObj* = object - bytes: int - data: WideCString - - proc `=destroy`(a: var WideCStringObj) = - if a.data != nil: - when compileOption("threads"): - deallocShared(a.data) - else: - dealloc(a.data) - - proc `=copy`(a: var WideCStringObj; b: WideCStringObj) {.error.} - - proc `=sink`(a: var WideCStringObj; b: WideCStringObj) = - a.bytes = b.bytes - a.data = b.data - - proc createWide(a: var WideCStringObj; bytes: int) = - a.bytes = bytes - when compileOption("threads"): - a.data = cast[typeof(a.data)](allocShared0(bytes)) - else: - a.data = cast[typeof(a.data)](alloc0(bytes)) - - template `[]`*(a: WideCStringObj; idx: int): Utf16Char = a.data[idx] - template `[]=`*(a: WideCStringObj; idx: int; val: Utf16Char) = a.data[idx] = val - - template nullWide(): untyped = WideCStringObj(bytes: 0, data: nil) - - converter toWideCString*(x: WideCStringObj): WideCString {.inline.} = - result = x.data - - else: - template nullWide(): untyped = nil - - type - WideCString* = ref UncheckedArray[Utf16Char] - WideCStringObj* = WideCString - - template createWide(a; L) = - unsafeNew(a, L) - - proc ord(arg: Utf16Char): int = int(cast[uint16](arg)) - - proc len*(w: WideCString): int = - ## returns the length of a widestring. This traverses the whole string to - ## find the binary zero end marker! - result = 0 - while int16(w[result]) != 0'i16: inc result - - const - UNI_REPLACEMENT_CHAR = Utf16Char(0xFFFD'i16) - UNI_MAX_BMP = 0x0000FFFF - UNI_MAX_UTF16 = 0x0010FFFF - # UNI_MAX_UTF32 = 0x7FFFFFFF - # UNI_MAX_LEGAL_UTF32 = 0x0010FFFF - - halfShift = 10 - halfBase = 0x0010000 - halfMask = 0x3FF - - UNI_SUR_HIGH_START = 0xD800 - UNI_SUR_HIGH_END = 0xDBFF - UNI_SUR_LOW_START = 0xDC00 - UNI_SUR_LOW_END = 0xDFFF - UNI_REPL = 0xFFFD - - template ones(n: untyped): untyped = ((1 shl n)-1) - - template fastRuneAt(s: cstring, i, L: int, result: untyped, doInc = true) = - ## Returns the unicode character `s[i]` in `result`. If `doInc == true` - ## `i` is incremented by the number of bytes that have been processed. - bind ones - - if ord(s[i]) <= 127: - result = ord(s[i]) - when doInc: inc(i) - elif ord(s[i]) shr 5 == 0b110: - #assert(ord(s[i+1]) shr 6 == 0b10) - if i <= L - 2: - result = (ord(s[i]) and (ones(5))) shl 6 or (ord(s[i+1]) and ones(6)) - when doInc: inc(i, 2) - else: - result = UNI_REPL - when doInc: inc(i) - elif ord(s[i]) shr 4 == 0b1110: - if i <= L - 3: - #assert(ord(s[i+1]) shr 6 == 0b10) - #assert(ord(s[i+2]) shr 6 == 0b10) - result = (ord(s[i]) and ones(4)) shl 12 or - (ord(s[i+1]) and ones(6)) shl 6 or - (ord(s[i+2]) and ones(6)) - when doInc: inc(i, 3) - else: - result = UNI_REPL - when doInc: inc(i) - elif ord(s[i]) shr 3 == 0b11110: - if i <= L - 4: - #assert(ord(s[i+1]) shr 6 == 0b10) - #assert(ord(s[i+2]) shr 6 == 0b10) - #assert(ord(s[i+3]) shr 6 == 0b10) - result = (ord(s[i]) and ones(3)) shl 18 or - (ord(s[i+1]) and ones(6)) shl 12 or - (ord(s[i+2]) and ones(6)) shl 6 or - (ord(s[i+3]) and ones(6)) - when doInc: inc(i, 4) - else: - result = UNI_REPL - when doInc: inc(i) - else: - result = 0xFFFD - when doInc: inc(i) - - iterator runes(s: cstring, L: int): int = - var - i = 0 - result: int - while i < L: - fastRuneAt(s, i, L, result, true) - yield result - - proc newWideCString*(size: int): WideCStringObj = - createWide(result, size * 2 + 2) - - proc newWideCString*(source: cstring, L: int): WideCStringObj = - createWide(result, L * 2 + 2) - var d = 0 - for ch in runes(source, L): - - if ch <= UNI_MAX_BMP: - if ch >= UNI_SUR_HIGH_START and ch <= UNI_SUR_LOW_END: - result[d] = UNI_REPLACEMENT_CHAR - else: - result[d] = cast[Utf16Char](uint16(ch)) - elif ch > UNI_MAX_UTF16: - result[d] = UNI_REPLACEMENT_CHAR - else: - let ch = ch - halfBase - result[d] = cast[Utf16Char](uint16((ch shr halfShift) + UNI_SUR_HIGH_START)) - inc d - result[d] = cast[Utf16Char](uint16((ch and halfMask) + UNI_SUR_LOW_START)) - inc d - result[d] = Utf16Char(0) - - proc newWideCString*(s: cstring): WideCStringObj = - if s.isNil: return nullWide - - result = newWideCString(s, s.len) - - proc newWideCString*(s: string): WideCStringObj = - result = newWideCString(cstring s, s.len) - - proc `$`*(w: WideCString, estimate: int, replacement: int = 0xFFFD): string = - result = newStringOfCap(estimate + estimate shr 2) - - var i = 0 - while w[i].int16 != 0'i16: - var ch = ord(w[i]) - inc i - if ch >= UNI_SUR_HIGH_START and ch <= UNI_SUR_HIGH_END: - # If the 16 bits following the high surrogate are in the source buffer... - let ch2 = ord(w[i]) - - # If it's a low surrogate, convert to UTF32: - if ch2 >= UNI_SUR_LOW_START and ch2 <= UNI_SUR_LOW_END: - ch = (((ch and halfMask) shl halfShift) + (ch2 and halfMask)) + halfBase - inc i - else: - #invalid UTF-16 - ch = replacement - elif ch >= UNI_SUR_LOW_START and ch <= UNI_SUR_LOW_END: - #invalid UTF-16 - ch = replacement - - if ch < 0x80: - result.add chr(ch) - elif ch < 0x800: - result.add chr((ch shr 6) or 0xc0) - result.add chr((ch and 0x3f) or 0x80) - elif ch < 0x10000: - result.add chr((ch shr 12) or 0xe0) - result.add chr(((ch shr 6) and 0x3f) or 0x80) - result.add chr((ch and 0x3f) or 0x80) - elif ch <= 0x10FFFF: - result.add chr((ch shr 18) or 0xf0) - result.add chr(((ch shr 12) and 0x3f) or 0x80) - result.add chr(((ch shr 6) and 0x3f) or 0x80) - result.add chr((ch and 0x3f) or 0x80) - else: - # replacement char(in case user give very large number): - result.add chr(0xFFFD shr 12 or 0b1110_0000) - result.add chr(0xFFFD shr 6 and ones(6) or 0b10_0000_00) - result.add chr(0xFFFD and ones(6) or 0b10_0000_00) - - proc `$`*(s: WideCString): string = - result = s $ 80 - - when defined(nimv2): - proc `$`*(s: WideCStringObj, estimate: int, replacement: int = 0xFFFD): string = - `$`(s.data, estimate, replacement) - - proc `$`*(s: WideCStringObj): string = - $(s.data) - - proc len*(w: WideCStringObj): int {.inline.} = - len(w.data) diff --git a/lib/std/with.nim b/lib/std/with.nim deleted file mode 100644 index c7338b4e4..000000000 --- a/lib/std/with.nim +++ /dev/null @@ -1,39 +0,0 @@ -# -# -# Nim's Runtime Library -# (c) Copyright 2020 Andreas Rumpf -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# - -## This module implements the `with` macro for easy -## function chaining. See https://github.com/nim-lang/RFCs/issues/193 -## and https://github.com/nim-lang/RFCs/issues/192 for details leading to this -## particular design. -## -## **Since:** version 1.2. - -import macros, private / underscored_calls - -macro with*(arg: typed; calls: varargs[untyped]): untyped = - ## This macro provides `chaining`:idx: of function calls. - ## It does so by patching every call in `calls` to - ## use `arg` as the first argument. - ## - ## .. caution:: This evaluates `arg` multiple times! - runnableExamples: - var x = "yay" - with x: - add "abc" - add "efg" - doAssert x == "yayabcefg" - - var a = 44 - with a: - += 4 - -= 5 - doAssert a == 43 - - result = newNimNode(nnkStmtList, arg) - underscoredCalls(result, calls, arg) diff --git a/lib/std/wordwrap.nim b/lib/std/wordwrap.nim index 7dcfc7f59..4b0dc4417 100644 --- a/lib/std/wordwrap.nim +++ b/lib/std/wordwrap.nim @@ -11,10 +11,10 @@ import strutils, unicode -proc olen(s: string; start, lastExclusive: int): int = - var i = start +proc olen(s: string): int = + var i = 0 result = 0 - while i < lastExclusive: + while i < s.len: inc result let L = graphemeLen(s, i) inc i, L @@ -32,43 +32,64 @@ proc wrapWords*(s: string, maxLineWidth = 80, result = newStringOfCap(s.len + s.len shr 6) var spaceLeft = maxLineWidth var lastSep = "" - - var i = 0 - while true: - var j = i - let isSep = j < s.len and s[j] in seps - while j < s.len and (s[j] in seps) == isSep: inc(j) - if j <= i: break - #yield (substr(s, i, j-1), isSep) + for word, isSep in tokenize(s, seps): + let wlen = olen(word) if isSep: - lastSep.setLen 0 - for k in i.. spaceLeft: + if splitLongWords and wlen > maxLineWidth: + var i = 0 + while i < word.len: + if spaceLeft <= 0: + spaceLeft = maxLineWidth + result.add newLine + dec spaceLeft + let L = graphemeLen(word, i) + for j in 0 ..< L: result.add word[i+j] + inc i, L else: - spaceLeft = spaceLeft - olen(lastSep, 0, lastSep.len) + spaceLeft = maxLineWidth - wlen + result.add(newLine) + result.add(word) else: - let wlen = olen(s, i, j) - if wlen > spaceLeft: - if splitLongWords and wlen > maxLineWidth: - var k = 0 - while k < j - i: - if spaceLeft <= 0: - spaceLeft = maxLineWidth - result.add newLine - dec spaceLeft - let L = graphemeLen(s, k+i) - for m in 0 ..< L: result.add s[i+k+m] - inc k, L - else: - spaceLeft = maxLineWidth - wlen - result.add(newLine) - for k in i..`_ to enable + ## build time conditionals: + ## + ## .. code-block:: Nim + ## when not defined(release): + ## # Do here programmer friendly expensive sanity checks. + ## # Put here the normal code + +when defined(nimHasRunnableExamples): + proc runnableExamples*(body: untyped) {.magic: "RunnableExamples".} + ## A section you should use to mark `runnable example`:idx: code with. + ## + ## - In normal debug and release builds code within + ## a ``runnableExamples`` section is ignored. + ## - The documentation generator is aware of these examples and considers them + ## part of the ``##`` doc comment. As the last step of documentation + ## generation each runnableExample is put in its own file ``$file_examples$i.nim``, + ## compiled and tested. The collected examples are + ## put into their own module to ensure the examples do not refer to + ## non-exported symbols. + ## + ## Usage: + ## + ## .. code-block:: Nim + ## proc double*(x: int): int = + ## ## This proc doubles a number. + ## runnableExamples: + ## ## at module scope + ## assert double(5) == 10 + ## block: ## at block scope + ## defer: echo "done" + ## + ## result = 2 * x +else: + template runnableExamples*(body: untyped) = + discard + +proc declared*(x: untyped): bool {.magic: "Defined", noSideEffect, compileTime.} + ## Special compile-time procedure that checks whether `x` is + ## declared. `x` has to be an identifier or a qualified identifier. + ## + ## See also: + ## * `declaredInScope <#declaredInScope,untyped>`_ + ## + ## This can be used to check whether a library provides a certain + ## feature or not: + ## + ## .. code-block:: Nim + ## when not declared(strutils.toUpper): + ## # provide our own toUpper proc here, because strutils is + ## # missing it. + +proc declaredInScope*(x: untyped): bool {. + magic: "DefinedInScope", noSideEffect, compileTime.} + ## Special compile-time procedure that checks whether `x` is + ## declared in the current scope. `x` has to be an identifier. + +proc `addr`*[T](x: var T): ptr T {.magic: "Addr", noSideEffect.} = ## Builtin `addr` operator for taking the address of a memory location. - ## - ## .. note:: This works for `let` variables or parameters - ## for better interop with C. When you use it to write a wrapper - ## for a C library and take the address of `let` variables or parameters, - ## you should always check that the original library - ## does never write to data behind the pointer that is returned from - ## this procedure. - ## ## Cannot be overloaded. ## - ## ``` - ## var - ## buf: seq[char] = @['a','b','c'] - ## p = buf[1].addr - ## echo p.repr # ref 0x7faa35c40059 --> 'b' - ## echo p[] # b - ## ``` + ## See also: + ## * `unsafeAddr <#unsafeAddr,T>`_ + ## + ## .. code-block:: Nim + ## var + ## buf: seq[char] = @['a','b','c'] + ## p = buf[1].addr + ## echo p.repr # ref 0x7faa35c40059 --> 'b' + ## echo p[] # b discard proc unsafeAddr*[T](x: T): ptr T {.magic: "Addr", noSideEffect.} = - ## .. warning:: `unsafeAddr` is a deprecated alias for `addr`, - ## use `addr` instead. + ## Builtin `addr` operator for taking the address of a memory + ## location. This works even for ``let`` variables or parameters + ## for better interop with C and so it is considered even more + ## unsafe than the ordinary `addr <#addr,T>`_. + ## + ## **Note**: When you use it to write a wrapper for a C library, you should + ## always check that the original library does never write to data behind the + ## pointer that is returned from this procedure. + ## + ## Cannot be overloaded. discard +when defined(nimNewTypedesc): + type + `static`*[T] {.magic: "Static".} + ## Meta type representing all values that can be evaluated at compile-time. + ## + ## The type coercion ``static(x)`` can be used to force the compile-time + ## evaluation of the given expression ``x``. + + `type`*[T] {.magic: "Type".} + ## Meta type representing the type of all type values. + ## + ## The coercion ``type(x)`` can be used to obtain the type of the given + ## expression ``x``. +else: + proc `type`*(x: untyped): typedesc {.magic: "TypeOf", noSideEffect, compileTime.} = + ## Builtin `type` operator for accessing the type of an expression. + ## Cannot be overloaded. + discard + +when defined(nimHasTypeof): + type + TypeOfMode* = enum ## Possible modes of `typeof`. + typeOfProc, ## Prefer the interpretation that means `x` is a proc call. + typeOfIter ## Prefer the interpretation that means `x` is an iterator call. + + proc typeof*(x: untyped; mode = typeOfIter): typedesc {. + magic: "TypeOf", noSideEffect, compileTime.} = + ## Builtin `typeof` operation for accessing the type of an expression. + ## Since version 0.20.0. + discard + const ThisIsSystem = true proc internalNew*[T](a: var ref T) {.magic: "New", noSideEffect.} ## Leaked implementation detail. Do not use. -proc new*[T](a: var ref T, finalizer: proc (x: ref T) {.nimcall.}) {. - magic: "NewFinalize", noSideEffect.} - ## Creates a new object of type `T` and returns a safe (traced) - ## reference to it in `a`. - ## - ## When the garbage collector frees the object, `finalizer` is called. - ## The `finalizer` may not keep a reference to the - ## object pointed to by `x`. The `finalizer` cannot prevent the GC from - ## freeing the object. - ## - ## **Note**: The `finalizer` refers to the type `T`, not to the object! - ## This means that for each object of type `T` the finalizer will be called! +when true: + proc new*[T](a: var ref T, finalizer: proc (x: ref T) {.nimcall.}) {. + magic: "NewFinalize", noSideEffect.} + ## Creates a new object of type ``T`` and returns a safe (traced) + ## reference to it in ``a``. + ## + ## When the garbage collector frees the object, `finalizer` is called. + ## The `finalizer` may not keep a reference to the + ## object pointed to by `x`. The `finalizer` cannot prevent the GC from + ## freeing the object. + ## + ## **Note**: The `finalizer` refers to the type `T`, not to the object! + ## This means that for each object of type `T` the finalizer will be called! proc wasMoved*[T](obj: var T) {.magic: "WasMoved", noSideEffect.} = ## Resets an object `obj` to its initial (binary zero) value to signify @@ -159,73 +237,72 @@ type seq*[T]{.magic: "Seq".} ## Generic type to construct sequences. set*[T]{.magic: "Set".} ## Generic type to construct bit sets. -type - UncheckedArray*[T]{.magic: "UncheckedArray".} - ## Array with no bounds checking. +when defined(nimUncheckedArrayTyp): + type + UncheckedArray*[T]{.magic: "UncheckedArray".} + ## Array with no bounds checking. +else: + type + UncheckedArray*[T]{.unchecked.} = array[0,T] + ## Array with no bounds checking. type sink*[T]{.magic: "BuiltinType".} type lent*[T]{.magic: "BuiltinType".} -proc high*[T: Ordinal|enum|range](x: T): T {.magic: "High", noSideEffect, - deprecated: "Deprecated since v1.4; there should not be `high(value)`. Use `high(type)`.".} +proc high*[T: Ordinal|enum|range](x: T): T {.magic: "High", noSideEffect.} ## Returns the highest possible value of an ordinal value `x`. ## ## As a special semantic rule, `x` may also be a type identifier. ## - ## **This proc is deprecated**, use this one instead: - ## * `high(typedesc) <#high,typedesc[T]>`_ + ## See also: + ## * `low(T) <#low,T>`_ ## - ## ``` - ## high(2) # => 9223372036854775807 - ## ``` + ## .. code-block:: Nim + ## high(2) # => 9223372036854775807 proc high*[T: Ordinal|enum|range](x: typedesc[T]): T {.magic: "High", noSideEffect.} ## Returns the highest possible value of an ordinal or enum type. ## - ## `high(int)` is Nim's way of writing `INT_MAX`:idx: or `MAX_INT`:idx:. - ## ``` - ## high(int) # => 9223372036854775807 - ## ``` + ## ``high(int)`` is Nim's way of writing `INT_MAX`:idx: or `MAX_INT`:idx:. ## ## See also: ## * `low(typedesc) <#low,typedesc[T]>`_ + ## + ## .. code-block:: Nim + ## high(int) # => 9223372036854775807 proc high*[T](x: openArray[T]): int {.magic: "High", noSideEffect.} ## Returns the highest possible index of a sequence `x`. - ## ``` - ## var s = @[1, 2, 3, 4, 5, 6, 7] - ## high(s) # => 6 - ## for i in low(s)..high(s): - ## echo s[i] - ## ``` ## ## See also: ## * `low(openArray) <#low,openArray[T]>`_ + ## + ## .. code-block:: Nim + ## var s = @[1, 2, 3, 4, 5, 6, 7] + ## high(s) # => 6 + ## for i in low(s)..high(s): + ## echo s[i] proc high*[I, T](x: array[I, T]): I {.magic: "High", noSideEffect.} ## Returns the highest possible index of an array `x`. ## - ## For empty arrays, the return type is `int`. - ## ``` - ## var arr = [1, 2, 3, 4, 5, 6, 7] - ## high(arr) # => 6 - ## for i in low(arr)..high(arr): - ## echo arr[i] - ## ``` - ## ## See also: ## * `low(array) <#low,array[I,T]>`_ + ## + ## .. code-block:: Nim + ## var arr = [1, 2, 3, 4, 5, 6, 7] + ## high(arr) # => 6 + ## for i in low(arr)..high(arr): + ## echo arr[i] proc high*[I, T](x: typedesc[array[I, T]]): I {.magic: "High", noSideEffect.} ## Returns the highest possible index of an array type. ## - ## For empty arrays, the return type is `int`. - ## ``` - ## high(array[7, int]) # => 6 - ## ``` - ## ## See also: ## * `low(typedesc[array]) <#low,typedesc[array[I,T]]>`_ + ## + ## .. code-block:: Nim + ## high(array[7, int]) # => 6 proc high*(x: cstring): int {.magic: "High", noSideEffect.} ## Returns the highest possible index of a compatible string `x`. @@ -236,73 +313,67 @@ proc high*(x: cstring): int {.magic: "High", noSideEffect.} proc high*(x: string): int {.magic: "High", noSideEffect.} ## Returns the highest possible index of a string `x`. - ## ``` - ## var str = "Hello world!" - ## high(str) # => 11 - ## ``` ## ## See also: ## * `low(string) <#low,string>`_ + ## + ## .. code-block:: Nim + ## var str = "Hello world!" + ## high(str) # => 11 -proc low*[T: Ordinal|enum|range](x: T): T {.magic: "Low", noSideEffect, - deprecated: "Deprecated since v1.4; there should not be `low(value)`. Use `low(type)`.".} +proc low*[T: Ordinal|enum|range](x: T): T {.magic: "Low", noSideEffect.} ## Returns the lowest possible value of an ordinal value `x`. As a special ## semantic rule, `x` may also be a type identifier. ## - ## **This proc is deprecated**, use this one instead: - ## * `low(typedesc) <#low,typedesc[T]>`_ + ## See also: + ## * `high(T) <#high,T>`_ ## - ## ``` - ## low(2) # => -9223372036854775808 - ## ``` + ## .. code-block:: Nim + ## low(2) # => -9223372036854775808 proc low*[T: Ordinal|enum|range](x: typedesc[T]): T {.magic: "Low", noSideEffect.} ## Returns the lowest possible value of an ordinal or enum type. ## - ## `low(int)` is Nim's way of writing `INT_MIN`:idx: or `MIN_INT`:idx:. - ## ``` - ## low(int) # => -9223372036854775808 - ## ``` + ## ``low(int)`` is Nim's way of writing `INT_MIN`:idx: or `MIN_INT`:idx:. ## ## See also: ## * `high(typedesc) <#high,typedesc[T]>`_ + ## + ## .. code-block:: Nim + ## low(int) # => -9223372036854775808 proc low*[T](x: openArray[T]): int {.magic: "Low", noSideEffect.} ## Returns the lowest possible index of a sequence `x`. - ## ``` - ## var s = @[1, 2, 3, 4, 5, 6, 7] - ## low(s) # => 0 - ## for i in low(s)..high(s): - ## echo s[i] - ## ``` ## ## See also: ## * `high(openArray) <#high,openArray[T]>`_ + ## + ## .. code-block:: Nim + ## var s = @[1, 2, 3, 4, 5, 6, 7] + ## low(s) # => 0 + ## for i in low(s)..high(s): + ## echo s[i] proc low*[I, T](x: array[I, T]): I {.magic: "Low", noSideEffect.} ## Returns the lowest possible index of an array `x`. ## - ## For empty arrays, the return type is `int`. - ## ``` - ## var arr = [1, 2, 3, 4, 5, 6, 7] - ## low(arr) # => 0 - ## for i in low(arr)..high(arr): - ## echo arr[i] - ## ``` - ## ## See also: ## * `high(array) <#high,array[I,T]>`_ + ## + ## .. code-block:: Nim + ## var arr = [1, 2, 3, 4, 5, 6, 7] + ## low(arr) # => 0 + ## for i in low(arr)..high(arr): + ## echo arr[i] proc low*[I, T](x: typedesc[array[I, T]]): I {.magic: "Low", noSideEffect.} ## Returns the lowest possible index of an array type. ## - ## For empty arrays, the return type is `int`. - ## ``` - ## low(array[7, int]) # => 0 - ## ``` - ## ## See also: ## * `high(typedesc[array]) <#high,typedesc[array[I,T]]>`_ + ## + ## .. code-block:: Nim + ## low(array[7, int]) # => 0 proc low*(x: cstring): int {.magic: "Low", noSideEffect.} ## Returns the lowest possible index of a compatible string `x`. @@ -312,96 +383,98 @@ proc low*(x: cstring): int {.magic: "Low", noSideEffect.} proc low*(x: string): int {.magic: "Low", noSideEffect.} ## Returns the lowest possible index of a string `x`. - ## ``` - ## var str = "Hello world!" - ## low(str) # => 0 - ## ``` ## ## See also: ## * `high(string) <#high,string>`_ + ## + ## .. code-block:: Nim + ## var str = "Hello world!" + ## low(str) # => 0 -when not defined(gcArc) and not defined(gcOrc): - proc shallowCopy*[T](x: var T, y: T) {.noSideEffect, magic: "ShallowCopy".} - ## Use this instead of `=` for a `shallow copy`:idx:. - ## - ## The shallow copy only changes the semantics for sequences and strings - ## (and types which contain those). - ## - ## Be careful with the changed semantics though! - ## There is a reason why the default assignment does a deep copy of sequences - ## and strings. +proc shallowCopy*[T](x: var T, y: T) {.noSideEffect, magic: "ShallowCopy".} + ## Use this instead of `=` for a `shallow copy`:idx:. + ## + ## The shallow copy only changes the semantics for sequences and strings + ## (and types which contain those). + ## + ## Be careful with the changed semantics though! + ## There is a reason why the default assignment does a deep copy of sequences + ## and strings. -# :array|openArray|string|seq|cstring|tuple -proc `[]`*[I: Ordinal;T](a: T; i: I): T {. - noSideEffect, magic: "ArrGet".} -proc `[]=`*[I: Ordinal;T,S](a: T; i: I; - x: sink S) {.noSideEffect, magic: "ArrPut".} -proc `=`*[T](dest: var T; src: T) {.noSideEffect, magic: "Asgn".} -proc `=copy`*[T](dest: var T; src: T) {.noSideEffect, magic: "Asgn".} +when defined(nimArrIdx): + # :array|openArray|string|seq|cstring|tuple + proc `[]`*[I: Ordinal;T](a: T; i: I): T {. + noSideEffect, magic: "ArrGet".} + proc `[]=`*[I: Ordinal;T,S](a: T; i: I; + x: S) {.noSideEffect, magic: "ArrPut".} + proc `=`*[T](dest: var T; src: T) {.noSideEffect, magic: "Asgn".} -proc arrGet[I: Ordinal;T](a: T; i: I): T {. - noSideEffect, magic: "ArrGet".} -proc arrPut[I: Ordinal;T,S](a: T; i: I; - x: S) {.noSideEffect, magic: "ArrPut".} + proc arrGet[I: Ordinal;T](a: T; i: I): T {. + noSideEffect, magic: "ArrGet".} + proc arrPut[I: Ordinal;T,S](a: T; i: I; + x: S) {.noSideEffect, magic: "ArrPut".} -proc `=destroy`*[T](x: var T) {.inline, magic: "Destroy".} = - ## Generic `destructor`:idx: implementation that can be overridden. - discard -proc `=sink`*[T](x: var T; y: T) {.inline, nodestroy, magic: "Asgn".} = - ## Generic `sink`:idx: implementation that can be overridden. - when defined(gcArc) or defined(gcOrc): - x = y - else: - shallowCopy(x, y) - -when defined(nimHasTrace): - proc `=trace`*[T](x: var T; env: pointer) {.inline, magic: "Trace".} = - ## Generic `trace`:idx: implementation that can be overridden. + proc `=destroy`*[T](x: var T) {.inline, magic: "Destroy".} = + ## Generic `destructor`:idx: implementation that can be overridden. discard + proc `=sink`*[T](x: var T; y: T) {.inline, magic: "Asgn".} = + ## Generic `sink`:idx: implementation that can be overridden. + shallowCopy(x, y) type HSlice*[T, U] = object ## "Heterogeneous" slice type. a*: T ## The lower bound (inclusive). b*: U ## The upper bound (inclusive). - Slice*[T] = HSlice[T, T] ## An alias for `HSlice[T, T]`. + Slice*[T] = HSlice[T, T] ## An alias for ``HSlice[T, T]``. -proc `..`*[T, U](a: sink T, b: sink U): HSlice[T, U] {.noSideEffect, inline, magic: "DotDot".} = - ## Binary `slice`:idx: operator that constructs an interval `[a, b]`, both `a` +proc `..`*[T, U](a: T, b: U): HSlice[T, U] {.noSideEffect, inline, magic: "DotDot".} = + ## Binary `slice`:idx: operator that constructs an interval ``[a, b]``, both `a` ## and `b` are inclusive. ## ## Slices can also be used in the set constructor and in ordinal case ## statements, but then they are special-cased by the compiler. - ## ``` + ## + ## .. code-block:: Nim ## let a = [10, 20, 30, 40, 50] ## echo a[2 .. 3] # @[30, 40] - ## ``` result = HSlice[T, U](a: a, b: b) -proc `..`*[T](b: sink T): HSlice[int, T] - {.noSideEffect, inline, magic: "DotDot", deprecated: "replace `..b` with `0..b`".} = - ## Unary `slice`:idx: operator that constructs an interval `[default(int), b]`. - ## ``` +proc `..`*[T](b: T): HSlice[int, T] {.noSideEffect, inline, magic: "DotDot".} = + ## Unary `slice`:idx: operator that constructs an interval ``[default(int), b]``. + ## + ## .. code-block:: Nim ## let a = [10, 20, 30, 40, 50] ## echo a[.. 2] # @[10, 20, 30] - ## ``` result = HSlice[int, T](a: 0, b: b) +when not defined(niminheritable): + {.pragma: inheritable.} +when not defined(nimunion): + {.pragma: unchecked.} +when not defined(nimHasHotCodeReloading): + {.pragma: nonReloadable.} when defined(hotCodeReloading): {.pragma: hcrInline, inline.} else: {.pragma: hcrInline.} +{.push profiler: off.} +let nimvm* {.magic: "Nimvm", compileTime.}: bool = false + ## May be used only in `when` expression. + ## It is true in Nim VM context and false otherwise. +{.pop.} + include "system/arithmetics" include "system/comparisons" const - appType* {.magic: "AppType".}: string = "" + appType* {.magic: "AppType"}: string = "" ## A string that describes the application type. Possible values: ## `"console"`, `"gui"`, `"lib"`. include "system/inclrtl" -const NoFakeVars = defined(nimscript) ## `true` if the backend doesn't support \ +const NoFakeVars* = defined(nimscript) ## `true` if the backend doesn't support \ ## "fake variables" like `var EBADF {.importc.}: cint`. const notJSnotNims = not defined(js) and not defined(nimscript) @@ -412,7 +485,6 @@ when not defined(js) and not defined(nimSeqsV2): len, reserved: int when defined(gogc): elemSize: int - elemAlign: int PGenericSeq {.exportc.} = ptr TGenericSeq # len and space without counting the terminating zero: NimStringDesc {.compilerproc, final.} = object of TGenericSeq @@ -423,11 +495,11 @@ when notJSnotNims and not defined(nimSeqsV2): template space(s: PGenericSeq): int {.dirty.} = s.reserved and not (seqShallowFlag or strlitFlag) -when notJSnotNims: +when notJSnotNims and not defined(nimV2): include "system/hti" type - byte* = uint8 ## This is an alias for `uint8`, that is an unsigned + byte* = uint8 ## This is an alias for ``uint8``, that is an unsigned ## integer, 8 bits wide. Natural* = range[0..high(int)] @@ -438,7 +510,6 @@ type ## is an `int` type ranging from one to the maximum value ## of an `int`. This type is often useful for documentation and debugging. -type RootObj* {.compilerproc, inheritable.} = object ## The root of Nim's object hierarchy. ## @@ -446,64 +517,8 @@ type ## However, objects that have no ancestor are also allowed. RootRef* = ref RootObj ## Reference to `RootObj`. -const NimStackTraceMsgs = compileOption("stacktraceMsgs") -type - RootEffect* {.compilerproc.} = object of RootObj ## \ - ## Base effect class. - ## - ## Each effect should inherit from `RootEffect` unless you know what - ## you're doing. - -type - StackTraceEntry* = object ## In debug mode exceptions store the stack trace that led - ## to them. A `StackTraceEntry` is a single entry of the - ## stack trace. - procname*: cstring ## Name of the proc that is currently executing. - line*: int ## Line number of the proc that is currently executing. - filename*: cstring ## Filename of the proc that is currently executing. - when NimStackTraceMsgs: - frameMsg*: string ## When a stacktrace is generated in a given frame and - ## rendered at a later time, we should ensure the stacktrace - ## data isn't invalidated; any pointer into PFrame is - ## subject to being invalidated so shouldn't be stored. - when defined(nimStackTraceOverride): - programCounter*: uint ## Program counter - will be used to get the rest of the info, - ## when `$` is called on this type. We can't use - ## "cuintptr_t" in here. - procnameStr*, filenameStr*: string ## GC-ed alternatives to "procname" and "filename" - - Exception* {.compilerproc, magic: "Exception".} = object of RootObj ## \ - ## Base exception class. - ## - ## Each exception has to inherit from `Exception`. See the full `exception - ## hierarchy `_. - parent*: ref Exception ## Parent exception (can be used as a stack). - name*: cstring ## The exception's name is its Nim identifier. - ## This field is filled automatically in the - ## `raise` statement. - msg* {.exportc: "message".}: string ## The exception's message. Not - ## providing an exception message - ## is bad style. - when defined(js): - trace*: string - else: - trace*: seq[StackTraceEntry] - up: ref Exception # used for stacking exceptions. Not exported! - - Defect* = object of Exception ## \ - ## Abstract base class for all exceptions that Nim's runtime raises - ## but that are strictly uncatchable as they can also be mapped to - ## a `quit` / `trap` / `exit` operation. - - CatchableError* = object of Exception ## \ - ## Abstract class for all exceptions that are catchable. - -when defined(nimIcIntegrityChecks): - include "system/exceptions" -else: - import system/exceptions - export exceptions +include "system/exceptions" when defined(js) or defined(nimdoc): type @@ -511,10 +526,10 @@ when defined(js) or defined(nimdoc): ## Root type of the JavaScript object hierarchy proc unsafeNew*[T](a: var ref T, size: Natural) {.magic: "New", noSideEffect.} - ## Creates a new object of type `T` and returns a safe (traced) - ## reference to it in `a`. + ## Creates a new object of type ``T`` and returns a safe (traced) + ## reference to it in ``a``. ## - ## This is **unsafe** as it allocates an object of the passed `size`. + ## This is **unsafe** as it allocates an object of the passed ``size``. ## This should only be used for optimization purposes when you know ## what you're doing! ## @@ -522,105 +537,106 @@ proc unsafeNew*[T](a: var ref T, size: Natural) {.magic: "New", noSideEffect.} ## * `new <#new,ref.T,proc(ref.T)>`_ proc sizeof*[T](x: T): int {.magic: "SizeOf", noSideEffect.} - ## Returns the size of `x` in bytes. + ## Returns the size of ``x`` in bytes. ## ## Since this is a low-level proc, ## its usage is discouraged - using `new <#new,ref.T,proc(ref.T)>`_ for - ## the most cases suffices that one never needs to know `x`'s size. + ## the most cases suffices that one never needs to know ``x``'s size. ## - ## As a special semantic rule, `x` may also be a type identifier - ## (`sizeof(int)` is valid). + ## As a special semantic rule, ``x`` may also be a type identifier + ## (``sizeof(int)`` is valid). ## ## Limitations: If used for types that are imported from C or C++, - ## sizeof should fallback to the `sizeof` in the C compiler. The + ## sizeof should fallback to the ``sizeof`` in the C compiler. The ## result isn't available for the Nim compiler and therefore can't ## be used inside of macros. - ## ``` - ## sizeof('A') # => 1 - ## sizeof(2) # => 8 - ## ``` + ## + ## .. code-block:: Nim + ## sizeof('A') # => 1 + ## sizeof(2) # => 8 -proc alignof*[T](x: T): int {.magic: "AlignOf", noSideEffect.} -proc alignof*(x: typedesc): int {.magic: "AlignOf", noSideEffect.} +when defined(nimHasalignOf): + proc alignof*[T](x: T): int {.magic: "AlignOf", noSideEffect.} + proc alignof*(x: typedesc): int {.magic: "AlignOf", noSideEffect.} -proc offsetOfDotExpr(typeAccess: typed): int {.magic: "OffsetOf", noSideEffect, compileTime.} + proc offsetOfDotExpr(typeAccess: typed): int {.magic: "OffsetOf", noSideEffect, compileTime.} -template offsetOf*[T](t: typedesc[T]; member: untyped): int = - var tmp {.noinit.}: ptr T - offsetOfDotExpr(tmp[].member) + template offsetOf*[T](t: typedesc[T]; member: untyped): int = + var tmp {.noinit.}: ptr T + offsetOfDotExpr(tmp[].member) -template offsetOf*[T](value: T; member: untyped): int = - offsetOfDotExpr(value.member) + template offsetOf*[T](value: T; member: untyped): int = + offsetOfDotExpr(value.member) -#proc offsetOf*(memberaccess: typed): int {.magic: "OffsetOf", noSideEffect.} + #proc offsetOf*(memberaccess: typed): int {.magic: "OffsetOf", noSideEffect.} -proc sizeof*(x: typedesc): int {.magic: "SizeOf", noSideEffect.} +when defined(nimtypedescfixed): + proc sizeof*(x: typedesc): int {.magic: "SizeOf", noSideEffect.} proc newSeq*[T](s: var seq[T], len: Natural) {.magic: "NewSeq", noSideEffect.} - ## Creates a new sequence of type `seq[T]` with length `len`. + ## Creates a new sequence of type ``seq[T]`` with length ``len``. ## - ## This is equivalent to `s = @[]; setlen(s, len)`, but more + ## This is equivalent to ``s = @[]; setlen(s, len)``, but more ## efficient since no reallocation is needed. ## ## Note that the sequence will be filled with zeroed entries. ## After the creation of the sequence you should assign entries to ## the sequence instead of adding them. Example: - ## ``` - ## var inputStrings: seq[string] + ## + ## .. code-block:: Nim + ## var inputStrings : seq[string] ## newSeq(inputStrings, 3) ## assert len(inputStrings) == 3 ## inputStrings[0] = "The fourth" ## inputStrings[1] = "assignment" ## inputStrings[2] = "would crash" ## #inputStrings[3] = "out of bounds" - ## ``` proc newSeq*[T](len = 0.Natural): seq[T] = - ## Creates a new sequence of type `seq[T]` with length `len`. + ## Creates a new sequence of type ``seq[T]`` with length ``len``. ## ## Note that the sequence will be filled with zeroed entries. ## After the creation of the sequence you should assign entries to ## the sequence instead of adding them. - ## ``` + ## + ## See also: + ## * `newSeqOfCap <#newSeqOfCap,Natural>`_ + ## * `newSeqUninitialized <#newSeqUninitialized,Natural>`_ + ## + ## .. code-block:: Nim ## var inputStrings = newSeq[string](3) ## assert len(inputStrings) == 3 ## inputStrings[0] = "The fourth" ## inputStrings[1] = "assignment" ## inputStrings[2] = "would crash" ## #inputStrings[3] = "out of bounds" - ## ``` - ## - ## See also: - ## * `newSeqOfCap <#newSeqOfCap,Natural>`_ - ## * `newSeqUninitialized <#newSeqUninitialized,Natural>`_ newSeq(result, len) proc newSeqOfCap*[T](cap: Natural): seq[T] {. magic: "NewSeqOfCap", noSideEffect.} = - ## Creates a new sequence of type `seq[T]` with length zero and capacity - ## `cap`. Example: - ## ``` + ## Creates a new sequence of type ``seq[T]`` with length zero and capacity + ## ``cap``. + ## + ## .. code-block:: Nim ## var x = newSeqOfCap[int](5) ## assert len(x) == 0 ## x.add(10) ## assert len(x) == 1 - ## ``` discard when not defined(js): proc newSeqUninitialized*[T: SomeNumber](len: Natural): seq[T] = - ## Creates a new sequence of type `seq[T]` with length `len`. + ## Creates a new sequence of type ``seq[T]`` with length ``len``. ## ## Only available for numbers types. Note that the sequence will be ## uninitialized. After the creation of the sequence you should assign ## entries to the sequence instead of adding them. - ## Example: - ## ``` + ## + ## .. code-block:: Nim ## var x = newSeqUninitialized[int](3) ## assert len(x) == 3 ## x[0] = 10 - ## ``` result = newSeqOfCap[T](len) when defined(nimSeqsV2): cast[ptr int](addr result)[] = len @@ -628,80 +644,83 @@ when not defined(js): var s = cast[PGenericSeq](result) s.len = len -func len*[TOpenArray: openArray|varargs](x: TOpenArray): int {.magic: "LengthOpenArray".} = +proc len*[TOpenArray: openArray|varargs](x: TOpenArray): int {. + magic: "LengthOpenArray", noSideEffect.} ## Returns the length of an openArray. - runnableExamples: - proc bar[T](a: openArray[T]): int = len(a) - assert bar([1,2]) == 2 - assert [1,2].len == 2 - -func len*(x: string): int {.magic: "LengthStr".} = - ## Returns the length of a string. - runnableExamples: - assert "abc".len == 3 - assert "".len == 0 - assert string.default.len == 0 - -proc len*(x: cstring): int {.magic: "LengthStr", noSideEffect.} = - ## Returns the length of a compatible string. This is an O(n) operation except - ## in js at runtime. ## - ## **Note:** On the JS backend this currently counts UTF-16 code points - ## instead of bytes at runtime (not at compile time). For now, if you - ## need the byte length of the UTF-8 encoding, convert to string with - ## `$` first then call `len`. - runnableExamples: - doAssert len(cstring"abc") == 3 - doAssert len(cstring r"ab\0c") == 5 # \0 is escaped - doAssert len(cstring"ab\0c") == 5 # ditto - var a: cstring = "ab\0c" - when defined(js): doAssert a.len == 4 # len ignores \0 for js - else: doAssert a.len == 2 # \0 is a null terminator - static: - var a2: cstring = "ab\0c" - doAssert a2.len == 2 # \0 is a null terminator, even in js vm + ## .. code-block:: Nim + ## var s = [1, 1, 1, 1, 1] + ## echo len(s) # => 5 -func len*(x: (type array)|array): int {.magic: "LengthArray".} = +proc len*(x: string): int {.magic: "LengthStr", noSideEffect.} + ## Returns the length of a string. + ## + ## .. code-block:: Nim + ## var str = "Hello world!" + ## echo len(str) # => 12 + +proc len*(x: cstring): int {.magic: "LengthStr", noSideEffect.} + ## Returns the length of a compatible string. This is sometimes + ## an O(n) operation. + ## + ## .. code-block:: Nim + ## var str: cstring = "Hello world!" + ## len(str) # => 12 + +proc len*(x: (type array)|array): int {.magic: "LengthArray", noSideEffect.} ## Returns the length of an array or an array type. - ## This is roughly the same as `high(T)-low(T)+1`. - runnableExamples: - var a = [1, 1, 1] - assert a.len == 3 - assert array[0, float].len == 0 - static: assert array[-2..2, float].len == 5 + ## This is roughly the same as ``high(T)-low(T)+1``. + ## + ## .. code-block:: Nim + ## var arr = [1, 1, 1, 1, 1] + ## echo len(arr) # => 5 + ## echo len(array[3..8, int]) # => 6 -func len*[T](x: seq[T]): int {.magic: "LengthSeq".} = - ## Returns the length of `x`. - runnableExamples: - assert @[0, 1].len == 2 - assert seq[int].default.len == 0 - assert newSeq[int](3).len == 3 - let s = newSeqOfCap[int](3) - assert s.len == 0 - # xxx this gives cgen error: assert newSeqOfCap[int](3).len == 0 +proc len*[T](x: seq[T]): int {.magic: "LengthSeq", noSideEffect.} + ## Returns the length of a sequence. + ## + ## .. code-block:: Nim + ## var s = @[1, 1, 1, 1, 1] + ## echo len(s) # => 5 -func ord*[T: Ordinal|enum](x: T): int {.magic: "Ord".} = - ## Returns the internal `int` value of `x`, including for enum with holes - ## and distinct ordinal types. - runnableExamples: - assert ord('A') == 65 - type Foo = enum - f0 = 0, f1 = 3 - assert f1.ord == 3 - type Bar = distinct int - assert 3.Bar.ord == 3 -func chr*(u: range[0..255]): char {.magic: "Chr".} = - ## Converts `u` to a `char`, same as `char(u)`. - runnableExamples: - doAssert chr(65) == 'A' - doAssert chr(255) == '\255' - doAssert chr(255) == char(255) - doAssert not compiles chr(256) - doAssert not compiles char(256) - var x = 256 - doAssertRaises(RangeDefect): discard chr(x) - doAssertRaises(RangeDefect): discard char(x) +proc ord*[T: Ordinal|enum](x: T): int {.magic: "Ord", noSideEffect.} + ## Returns the internal `int` value of an ordinal value ``x``. + ## + ## .. code-block:: Nim + ## echo ord('A') # => 65 + ## echo ord('a') # => 97 + +proc chr*(u: range[0..255]): char {.magic: "Chr", noSideEffect.} + ## Converts an `int` in the range `0..255` to a character. + ## + ## .. code-block:: Nim + ## echo chr(65) # => A + ## echo chr(97) # => a + + +# floating point operations: +proc `+`*(x: float32): float32 {.magic: "UnaryPlusF64", noSideEffect.} +proc `-`*(x: float32): float32 {.magic: "UnaryMinusF64", noSideEffect.} +proc `+`*(x, y: float32): float32 {.magic: "AddF64", noSideEffect.} +proc `-`*(x, y: float32): float32 {.magic: "SubF64", noSideEffect.} +proc `*`*(x, y: float32): float32 {.magic: "MulF64", noSideEffect.} +proc `/`*(x, y: float32): float32 {.magic: "DivF64", noSideEffect.} + +proc `+`*(x: float): float {.magic: "UnaryPlusF64", noSideEffect.} +proc `-`*(x: float): float {.magic: "UnaryMinusF64", noSideEffect.} +proc `+`*(x, y: float): float {.magic: "AddF64", noSideEffect.} +proc `-`*(x, y: float): float {.magic: "SubF64", noSideEffect.} +proc `*`*(x, y: float): float {.magic: "MulF64", noSideEffect.} +proc `/`*(x, y: float): float {.magic: "DivF64", noSideEffect.} + +proc `==`*(x, y: float32): bool {.magic: "EqF64", noSideEffect.} +proc `<=`*(x, y: float32): bool {.magic: "LeF64", noSideEffect.} +proc `<` *(x, y: float32): bool {.magic: "LtF64", noSideEffect.} + +proc `==`*(x, y: float): bool {.magic: "EqF64", noSideEffect.} +proc `<=`*(x, y: float): bool {.magic: "LeF64", noSideEffect.} +proc `<`*(x, y: float): bool {.magic: "LtF64", noSideEffect.} include "system/setops" @@ -709,36 +728,33 @@ include "system/setops" proc contains*[U, V, W](s: HSlice[U, V], value: W): bool {.noSideEffect, inline.} = ## Checks if `value` is within the range of `s`; returns true if - ## `value >= s.a and value <= s.b`. - ## ``` + ## `value >= s.a and value <= s.b` + ## + ## .. code-block:: Nim ## assert((1..3).contains(1) == true) ## assert((1..3).contains(2) == true) ## assert((1..3).contains(4) == false) - ## ``` result = s.a <= value and value <= s.b -when not defined(nimHasCallsitePragma): - {.pragma: callsite.} - -template `in`*(x, y: untyped): untyped {.dirty, callsite.} = contains(y, x) +template `in`*(x, y: untyped): untyped {.dirty.} = contains(y, x) ## Sugar for `contains`. - ## ``` + ## + ## .. code-block:: Nim ## assert(1 in (1..3) == true) ## assert(5 in (1..3) == false) - ## ``` -template `notin`*(x, y: untyped): untyped {.dirty, callsite.} = not contains(y, x) +template `notin`*(x, y: untyped): untyped {.dirty.} = not contains(y, x) ## Sugar for `not contains`. - ## ``` + ## + ## .. code-block:: Nim ## assert(1 notin (1..3) == false) ## assert(5 notin (1..3) == true) - ## ``` proc `is`*[T, S](x: T, y: S): bool {.magic: "Is", noSideEffect.} ## Checks if `T` is of the same type as `S`. ## ## For a negated version, use `isnot <#isnot.t,untyped,untyped>`_. ## - ## ``` + ## .. code-block:: Nim ## assert 42 is int ## assert @[1, 2] is seq ## @@ -750,13 +766,12 @@ proc `is`*[T, S](x: T, y: S): bool {.magic: "Is", noSideEffect.} ## ## assert(test[int](3) == 3) ## assert(test[string]("xyz") == 0) - ## ``` -template `isnot`*(x, y: untyped): untyped {.callsite.} = not (x is y) - ## Negated version of `is <#is,T,S>`_. Equivalent to `not(x is y)`. - ## ``` +template `isnot`*(x, y: untyped): untyped = not (x is y) + ## Negated version of `is <#is,T,S>`_. Equivalent to ``not(x is y)``. + ## + ## .. code-block:: Nim ## assert 42 isnot float ## assert @[1, 2] isnot enum - ## ``` when (defined(nimOwnedEnabled) and not defined(nimscript)) or defined(nimFixedOwned): type owned*[T]{.magic: "BuiltinType".} ## type constructor to mark a ref/ptr or a closure as `owned`. @@ -765,15 +780,15 @@ else: when defined(nimOwnedEnabled) and not defined(nimscript): proc new*[T](a: var owned(ref T)) {.magic: "New", noSideEffect.} - ## Creates a new object of type `T` and returns a safe (traced) - ## reference to it in `a`. + ## Creates a new object of type ``T`` and returns a safe (traced) + ## reference to it in ``a``. proc new*(t: typedesc): auto = - ## Creates a new object of type `T` and returns a safe (traced) + ## Creates a new object of type ``T`` and returns a safe (traced) ## reference to it as result value. ## - ## When `T` is a ref type then the resulting type will be `T`, - ## otherwise it will be `ref T`. + ## When ``T`` is a ref type then the resulting type will be ``T``, + ## otherwise it will be ``ref T``. when (t is ref): var r: owned t else: @@ -782,22 +797,24 @@ when defined(nimOwnedEnabled) and not defined(nimscript): return r proc unown*[T](x: T): T {.magic: "Unown", noSideEffect.} - ## Use the expression `x` ignoring its ownership attribute. + ## Use the expression ``x`` ignoring its ownership attribute. + # This is only required to make 0.20 compile with the 0.19 line. + template ``*(t: untyped): untyped = owned(t) else: template unown*(x: typed): untyped = x proc new*[T](a: var ref T) {.magic: "New", noSideEffect.} - ## Creates a new object of type `T` and returns a safe (traced) - ## reference to it in `a`. + ## Creates a new object of type ``T`` and returns a safe (traced) + ## reference to it in ``a``. proc new*(t: typedesc): auto = - ## Creates a new object of type `T` and returns a safe (traced) + ## Creates a new object of type ``T`` and returns a safe (traced) ## reference to it as result value. ## - ## When `T` is a ref type then the resulting type will be `T`, - ## otherwise it will be `ref T`. + ## When ``T`` is a ref type then the resulting type will be ``T``, + ## otherwise it will be ``ref T``. when (t is ref): var r: t else: @@ -805,41 +822,26 @@ else: new(r) return r + # This is only required to make 0.20 compile with the 0.19 line. + template ``*(t: untyped): untyped = t template disarm*(x: typed) = - ## Useful for `disarming` dangling pointers explicitly for `--newruntime`. - ## Regardless of whether `--newruntime` is used or not - ## this sets the pointer or callback `x` to `nil`. This is an + ## Useful for ``disarming`` dangling pointers explicitly for the + ## --newruntime. Regardless of whether --newruntime is used or not + ## this sets the pointer or callback ``x`` to ``nil``. This is an ## experimental API! x = nil -proc `of`*[T, S](x: T, y: typedesc[S]): bool {.magic: "Of", noSideEffect.} = - ## Checks if `x` is an instance of `y`. - runnableExamples: - type - Base = ref object of RootObj - Sub1 = ref object of Base - Sub2 = ref object of Base - Unrelated = ref object +proc `of`*[T, S](x: typedesc[T], y: typedesc[S]): bool {.magic: "Of", noSideEffect.} +proc `of`*[T, S](x: T, y: typedesc[S]): bool {.magic: "Of", noSideEffect.} +proc `of`*[T, S](x: T, y: S): bool {.magic: "Of", noSideEffect.} + ## Checks if `x` has a type of `y`. + ## + ## .. code-block:: Nim + ## assert(FloatingPointError of Exception) + ## assert(DivByZeroError of Exception) - var base: Base = Sub1() # downcast - doAssert base of Base # generates `CondTrue` (statically true) - doAssert base of Sub1 - doAssert base isnot Sub1 - doAssert not (base of Sub2) - - base = Sub2() # re-assign - doAssert base of Sub2 - doAssert Sub2(base) != nil # upcast - doAssertRaises(ObjectConversionDefect): discard Sub1(base) - - var sub1 = Sub1() - doAssert sub1 of Base - doAssert sub1.Base of Sub1 - - doAssert not compiles(base of Unrelated) - -proc cmp*[T](x, y: T): int = +proc cmp*[T](x, y: T): int {.procvar.} = ## Generic compare proc. ## ## Returns: @@ -849,155 +851,159 @@ proc cmp*[T](x, y: T): int = ## ## This is useful for writing generic algorithms without performance loss. ## This generic implementation uses the `==` and `<` operators. - ## ``` - ## import std/algorithm - ## echo sorted(@[4, 2, 6, 5, 8, 7], cmp[int]) - ## ``` + ## + ## .. code-block:: Nim + ## import algorithm + ## echo sorted(@[4, 2, 6, 5, 8, 7], cmp[int]) if x == y: return 0 if x < y: return -1 return 1 -proc cmp*(x, y: string): int {.noSideEffect.} +proc cmp*(x, y: string): int {.noSideEffect, procvar.} ## Compare proc for strings. More efficient than the generic version. ## ## **Note**: The precise result values depend on the used C runtime library and ## can differ between operating systems! -proc `@`* [IDX, T](a: sink array[IDX, T]): seq[T] {.magic: "ArrToSeq", noSideEffect.} - ## Turns an array into a sequence. - ## - ## This most often useful for constructing - ## sequences with the array constructor: `@[1, 2, 3]` has the type - ## `seq[int]`, while `[1, 2, 3]` has the type `array[0..2, int]`. - ## - ## ``` - ## let - ## a = [1, 3, 5] - ## b = "foo" - ## - ## echo @a # => @[1, 3, 5] - ## echo @b # => @['f', 'o', 'o'] - ## ``` +when defined(nimHasDefault): + proc `@`* [IDX, T](a: sink array[IDX, T]): seq[T] {. + magic: "ArrToSeq", noSideEffect.} + ## Turns an array into a sequence. + ## + ## This most often useful for constructing + ## sequences with the array constructor: ``@[1, 2, 3]`` has the type + ## ``seq[int]``, while ``[1, 2, 3]`` has the type ``array[0..2, int]``. + ## + ## .. code-block:: Nim + ## let + ## a = [1, 3, 5] + ## b = "foo" + ## + ## echo @a # => @[1, 3, 5] + ## echo @b # => @['f', 'o', 'o'] -proc default*[T](_: typedesc[T]): T {.magic: "Default", noSideEffect.} = - ## returns the default value of the type `T`. - runnableExamples: - assert (int, float).default == (0, 0.0) - # note: `var a = default(T)` is usually the same as `var a: T` and (currently) generates - # a value whose binary representation is all 0, regardless of whether this - # would violate type constraints such as `range`, `not nil`, etc. This - # property is required to implement certain algorithms efficiently which - # may require intermediate invalid states. - type Foo = object - a: range[2..6] - var a1: range[2..6] # currently, this compiles - # var a2: Foo # currently, this errors: Error: The Foo type doesn't have a default value. - # var a3 = Foo() # ditto - var a3 = Foo.default # this works, but generates a `UnsafeDefault` warning. - # note: the doc comment also explains why `default` can't be implemented - # via: `template default*[T](t: typedesc[T]): T = (var v: T; v)` + proc default*(T: typedesc): T {.magic: "Default", noSideEffect.} + ## returns the default value of the type ``T``. + proc reset*[T](obj: var T) {.noSideEffect.} = + ## Resets an object `obj` to its default value. + obj = default(typeof(obj)) -proc reset*[T](obj: var T) {.noSideEffect.} = - ## Resets an object `obj` to its default value. - obj = default(typeof(obj)) +else: + proc `@`* [IDX, T](a: array[IDX, T]): seq[T] {. + magic: "ArrToSeq", noSideEffect.} + when defined(nimV2): + proc reset*[T](obj: var T) {.magic: "Destroy", noSideEffect.} + else: + proc reset*[T](obj: var T) {.magic: "Reset", noSideEffect.} proc setLen*[T](s: var seq[T], newlen: Natural) {. magic: "SetLengthSeq", noSideEffect.} - ## Sets the length of seq `s` to `newlen`. `T` may be any sequence type. + ## Sets the length of seq `s` to `newlen`. ``T`` may be any sequence type. ## ## If the current length is greater than the new length, - ## `s` will be truncated. - ## ``` + ## ``s`` will be truncated. + ## + ## .. code-block:: Nim ## var x = @[10, 20] ## x.setLen(5) ## x[4] = 50 ## assert x == @[10, 20, 0, 0, 50] ## x.setLen(1) ## assert x == @[10] - ## ``` proc setLen*(s: var string, newlen: Natural) {. magic: "SetLengthStr", noSideEffect.} ## Sets the length of string `s` to `newlen`. ## ## If the current length is greater than the new length, - ## `s` will be truncated. - ## ``` - ## var myS = "Nim is great!!" - ## myS.setLen(3) # myS <- "Nim" - ## echo myS, " is fantastic!!" - ## ``` + ## ``s`` will be truncated. + ## + ## .. code-block:: Nim + ## var myS = "Nim is great!!" + ## myS.setLen(3) # myS <- "Nim" + ## echo myS, " is fantastic!!" proc newString*(len: Natural): string {. magic: "NewString", importc: "mnewString", noSideEffect.} - ## Returns a new string of length `len` but with uninitialized + ## Returns a new string of length ``len`` but with uninitialized ## content. One needs to fill the string character after character - ## with the index operator `s[i]`. + ## with the index operator ``s[i]``. ## ## This procedure exists only for optimization purposes; - ## the same effect can be achieved with the `&` operator or with `add`. + ## the same effect can be achieved with the ``&`` operator or with ``add``. proc newStringOfCap*(cap: Natural): string {. magic: "NewStringOfCap", importc: "rawNewString", noSideEffect.} - ## Returns a new string of length `0` but with capacity `cap`. + ## Returns a new string of length ``0`` but with capacity `cap`. ## ## This procedure exists only for optimization purposes; the same effect can - ## be achieved with the `&` operator or with `add`. + ## be achieved with the ``&`` operator or with ``add``. proc `&`*(x: string, y: char): string {. - magic: "ConStrStr", noSideEffect.} + magic: "ConStrStr", noSideEffect, merge.} ## Concatenates `x` with `y`. - ## ``` + ## + ## .. code-block:: Nim ## assert("ab" & 'c' == "abc") - ## ``` proc `&`*(x, y: char): string {. - magic: "ConStrStr", noSideEffect.} + magic: "ConStrStr", noSideEffect, merge.} ## Concatenates characters `x` and `y` into a string. - ## ``` + ## + ## .. code-block:: Nim ## assert('a' & 'b' == "ab") - ## ``` proc `&`*(x, y: string): string {. - magic: "ConStrStr", noSideEffect.} + magic: "ConStrStr", noSideEffect, merge.} ## Concatenates strings `x` and `y`. - ## ``` + ## + ## .. code-block:: Nim ## assert("ab" & "cd" == "abcd") - ## ``` proc `&`*(x: char, y: string): string {. - magic: "ConStrStr", noSideEffect.} + magic: "ConStrStr", noSideEffect, merge.} ## Concatenates `x` with `y`. - ## ``` + ## + ## .. code-block:: Nim ## assert('a' & "bc" == "abc") - ## ``` # implementation note: These must all have the same magic value "ConStrStr" so # that the merge optimization works properly. proc add*(x: var string, y: char) {.magic: "AppendStrCh", noSideEffect.} ## Appends `y` to `x` in place. - ## ``` + ## + ## .. code-block:: Nim ## var tmp = "" ## tmp.add('a') ## tmp.add('b') ## assert(tmp == "ab") - ## ``` - -proc add*(x: var string, y: string) {.magic: "AppendStrStr", noSideEffect.} = +proc add*(x: var string, y: string) {.magic: "AppendStrStr", noSideEffect.} ## Concatenates `x` and `y` in place. ## - ## See also `strbasics.add`. - runnableExamples: - var tmp = "" - tmp.add("ab") - tmp.add("cd") - assert tmp == "abcd" + ## .. code-block:: Nim + ## var tmp = "" + ## tmp.add("ab") + ## tmp.add("cd") + ## assert(tmp == "abcd") + type Endianness* = enum ## Type describing the endianness of a processor. littleEndian, bigEndian const - cpuEndian* {.magic: "CpuEndian".}: Endianness = littleEndian + isMainModule* {.magic: "IsMainModule".}: bool = false + ## True only when accessed in the main module. This works thanks to + ## compiler magic. It is useful to embed testing code in a module. + + CompileDate* {.magic: "CompileDate"}: string = "0000-00-00" + ## The date (in UTC) of compilation as a string of the form + ## ``YYYY-MM-DD``. This works thanks to compiler magic. + + CompileTime* {.magic: "CompileTime"}: string = "00:00:00" + ## The time (in UTC) of compilation as a string of the form + ## ``HH:MM:SS``. This works thanks to compiler magic. + + cpuEndian* {.magic: "CpuEndian"}: Endianness = littleEndian ## The endianness of the target CPU. This is a valuable piece of ## information for low-level code only. This works thanks to compiler ## magic. @@ -1015,20 +1021,38 @@ const ## Possible values: ## `"i386"`, `"alpha"`, `"powerpc"`, `"powerpc64"`, `"powerpc64el"`, ## `"sparc"`, `"amd64"`, `"mips"`, `"mipsel"`, `"arm"`, `"arm64"`, - ## `"mips64"`, `"mips64el"`, `"riscv32"`, `"riscv64"`, '"loongarch64"'. + ## `"mips64"`, `"mips64el"`, `"riscv64"`. seqShallowFlag = low(int) strlitFlag = 1 shl (sizeof(int)*8 - 2) # later versions of the codegen \ # emit this flag # for string literals, it allows for some optimizations. +proc compileOption*(option: string): bool {. + magic: "CompileOption", noSideEffect.} + ## Can be used to determine an `on|off` compile-time option. Example: + ## + ## .. code-block:: Nim + ## when compileOption("floatchecks"): + ## echo "compiled with floating point NaN and Inf checks" + +proc compileOption*(option, arg: string): bool {. + magic: "CompileOptionArg", noSideEffect.} + ## Can be used to determine an enum compile-time option. Example: + ## + ## .. code-block:: Nim + ## when compileOption("opt", "size") and compileOption("gc", "boehm"): + ## echo "compiled with optimization for size and uses Boehm's GC" + const hasThreadSupport = compileOption("threads") and not defined(nimscript) hasSharedHeap = defined(boehmgc) or defined(gogc) # don't share heaps; every thread has its own + taintMode = compileOption("taintmode") + nimEnableCovariance* = defined(nimEnableCovariance) # or true when hasThreadSupport and defined(tcc) and not compileOption("tlsEmulation"): # tcc doesn't support TLS - {.error: "`--tlsEmulation:on` must be used when using threads with tcc backend".} + {.error: "``--tlsEmulation:on`` must be used when using threads with tcc backend".} when defined(boehmgc): when defined(windows): @@ -1039,16 +1063,29 @@ when defined(boehmgc): elif defined(macosx): const boehmLib = "libgc.dylib" elif defined(openbsd): - const boehmLib = "libgc.so.(4|5).0" + const boehmLib = "libgc.so.4.0" elif defined(freebsd): const boehmLib = "libgc-threaded.so.1" else: const boehmLib = "libgc.so.1" {.pragma: boehmGC, noconv, dynlib: boehmLib.} -when not defined(nimPreviewSlimSystem): - type TaintedString* {.deprecated: "Deprecated since 1.5".} = string +when taintMode: + type TaintedString* = distinct string ## A distinct string type that + ## is `tainted`:idx:, see `taint mode + ## `_ + ## for details. It is an alias for + ## ``string`` if the taint mode is not + ## turned on. + proc len*(s: TaintedString): int {.borrow.} +else: + type TaintedString* = string ## A distinct string type that + ## is `tainted`:idx:, see `taint mode + ## `_ + ## for details. It is an alias for + ## ``string`` if the taint mode is not + ## turned on. when defined(profiler) and not defined(nimscript): proc nimProfile() {.compilerproc, noinline.} @@ -1066,24 +1103,56 @@ const ## is the value that should be passed to `quit <#quit,int>`_ to indicate ## failure. -when not defined(js) and hostOS != "standalone": +when defined(js) and defined(nodejs) and not defined(nimscript): + var programResult* {.importc: "process.exitCode".}: int + programResult = 0 +elif hostOS != "standalone": var programResult* {.compilerproc, exportc: "nim_program_result".}: int - ## deprecated, prefer `quit` or `exitprocs.getProgramResult`, `exitprocs.setProgramResult`. + ## deprecated, prefer ``quit`` -import std/private/since -import system/ctypes -export ctypes +when defined(nimdoc): + proc quit*(errorcode: int = QuitSuccess) {.magic: "Exit", noreturn.} + ## Stops the program immediately with an exit code. + ## + ## Before stopping the program the "quit procedures" are called in the + ## opposite order they were added with `addQuitProc <#addQuitProc,proc>`_. + ## ``quit`` never returns and ignores any exception that may have been raised + ## by the quit procedures. It does *not* call the garbage collector to free + ## all the memory, unless a quit procedure calls `GC_fullCollect + ## <#GC_fullCollect>`_. + ## + ## The proc ``quit(QuitSuccess)`` is called implicitly when your nim + ## program finishes without incident for platforms where this is the + ## expected behavior. A raised unhandled exception is + ## equivalent to calling ``quit(QuitFailure)``. + ## + ## Note that this is a *runtime* call and using ``quit`` inside a macro won't + ## have any compile time effect. If you need to stop the compiler inside a + ## macro, use the `error `_ or `fatal + ## `_ pragmas. -proc align(address, alignment: int): int = - if alignment == 0: # Actually, this is illegal. This branch exists to actively - # hide problems. - result = address - else: - result = (address + (alignment - 1)) and not (alignment - 1) +elif defined(genode): + include genode/env + + var systemEnv {.exportc: runtimeEnvSym.}: GenodeEnvPtr + + type GenodeEnv* = GenodeEnvPtr + ## Opaque type representing Genode environment. + + proc quit*(env: GenodeEnv; errorcode: int) {.magic: "Exit", noreturn, + importcpp: "#->parent().exit(@); Genode::sleep_forever()", header: "".} + + proc quit*(errorcode: int = QuitSuccess) = + systemEnv.quit(errorcode) + +elif defined(js) and defined(nodejs) and not defined(nimscript): + proc quit*(errorcode: int = QuitSuccess) {.magic: "Exit", + importc: "process.exit", noreturn.} + +else: + proc quit*(errorcode: int = QuitSuccess) {. + magic: "Exit", importc: "exit", header: "", noreturn.} -include system/rawquits -when defined(genode): - export GenodeEnv template sysAssert(cond: bool, msg: string) = when defined(useSysAssert): @@ -1091,7 +1160,7 @@ template sysAssert(cond: bool, msg: string) = cstderr.rawWrite "[SYSASSERT] " cstderr.rawWrite msg cstderr.rawWrite "\n" - rawQuit 1 + quit 1 const hasAlloc = (hostOS != "standalone" or not defined(nogc)) and not defined(nimscript) @@ -1101,7 +1170,7 @@ when notJSnotNims and hasAlloc and not defined(nimSeqsV2): proc addChar(s: NimString, c: char): NimString {.compilerproc, benign.} when defined(nimscript) or not defined(nimSeqsV2): - proc add*[T](x: var seq[T], y: sink T) {.magic: "AppendSeqElem", noSideEffect.} + proc add*[T](x: var seq[T], y: T) {.magic: "AppendSeqElem", noSideEffect.} ## Generic proc for adding a data item `y` to a container `x`. ## ## For containers that have an order, `add` means *append*. New generic @@ -1109,118 +1178,258 @@ when defined(nimscript) or not defined(nimSeqsV2): ## Generic code becomes much easier to write if the Nim naming scheme is ## respected. -when false: # defined(gcDestructors): - proc add*[T](x: var seq[T], y: sink openArray[T]) {.noSideEffect.} = - ## Generic proc for adding a container `y` to a container `x`. - ## - ## For containers that have an order, `add` means *append*. New generic - ## containers should also call their adding proc `add` for consistency. - ## Generic code becomes much easier to write if the Nim naming scheme is - ## respected. - ## ``` - ## var s: seq[string] = @["test2","test2"] - ## s.add("test") # s <- @[test2, test2, test] - ## ``` - ## - ## See also: - ## * `& proc <#&,seq[T],seq[T]>`_ - {.noSideEffect.}: - let xl = x.len - setLen(x, xl + y.len) - for i in 0..high(y): - when nimvm: - # workaround the fact that the VM does not yet - # handle sink parameters properly: - x[xl+i] = y[i] - else: - x[xl+i] = move y[i] -else: - proc add*[T](x: var seq[T], y: openArray[T]) {.noSideEffect.} = - ## Generic proc for adding a container `y` to a container `x`. - ## - ## For containers that have an order, `add` means *append*. New generic - ## containers should also call their adding proc `add` for consistency. - ## Generic code becomes much easier to write if the Nim naming scheme is - ## respected. - ## ``` - ## var s: seq[string] = @["test2","test2"] - ## s.add("test") # s <- @[test2, test2, test] - ## ``` - ## - ## See also: - ## * `& proc <#&,seq[T],seq[T]>`_ - {.noSideEffect.}: - let xl = x.len - setLen(x, xl + y.len) - for i in 0..high(y): x[xl+i] = y[i] - +proc add*[T](x: var seq[T], y: openArray[T]) {.noSideEffect.} = + ## Generic proc for adding a container `y` to a container `x`. + ## + ## For containers that have an order, `add` means *append*. New generic + ## containers should also call their adding proc `add` for consistency. + ## Generic code becomes much easier to write if the Nim naming scheme is + ## respected. + ## + ## See also: + ## * `& proc <#&,seq[T][T],seq[T][T]>`_ + ## + ## .. code-block:: Nim + ## var s: seq[string] = @["test2","test2"] + ## s.add("test") # s <- @[test2, test2, test] + let xl = x.len + setLen(x, xl + y.len) + for i in 0..high(y): x[xl+i] = y[i] when defined(nimSeqsV2): - template movingCopy(a, b: typed) = + template movingCopy(a, b) = a = move(b) else: - template movingCopy(a, b: typed) = + template movingCopy(a, b) = shallowCopy(a, b) proc del*[T](x: var seq[T], i: Natural) {.noSideEffect.} = - ## Deletes the item at index `i` by putting `x[high(x)]` into position `i`. + ## Deletes the item at index `i` by putting ``x[high(x)]`` into position `i`. ## ## This is an `O(1)` operation. ## ## See also: - ## * `delete <#delete,seq[T],Natural>`_ for preserving the order - runnableExamples: - var a = @[10, 11, 12, 13, 14] - a.del(2) - assert a == @[10, 11, 14, 13] + ## * `delete <#delete,seq[T][T],Natural>`_ for preserving the order + ## + ## .. code-block:: Nim + ## var i = @[1, 2, 3, 4, 5] + ## i.del(2) # => @[1, 2, 5, 4] let xl = x.len - 1 movingCopy(x[i], x[xl]) setLen(x, xl) -proc insert*[T](x: var seq[T], item: sink T, i = 0.Natural) {.noSideEffect.} = - ## Inserts `item` into `x` at position `i`. - ## ``` - ## var i = @[1, 3, 5] - ## i.insert(99, 0) # i <- @[99, 1, 3, 5] - ## ``` - {.noSideEffect.}: - template defaultImpl = - let xl = x.len - setLen(x, xl+1) - var j = xl-1 - while j >= i: - movingCopy(x[j+1], x[j]) - dec(j) - when nimvm: - defaultImpl() +proc delete*[T](x: var seq[T], i: Natural) {.noSideEffect.} = + ## Deletes the item at index `i` by moving all ``x[i+1..]`` items by one position. + ## + ## This is an `O(n)` operation. + ## + ## See also: + ## * `del <#delete,seq[T][T],Natural>`_ for O(1) operation + ## + ## .. code-block:: Nim + ## var i = @[1, 2, 3, 4, 5] + ## i.delete(2) # => @[1, 2, 4, 5] + template defaultImpl = + let xl = x.len + for j in i.int..xl-2: movingCopy(x[j], x[j+1]) + setLen(x, xl-1) + + when nimvm: + defaultImpl() + else: + when defined(js): + {.emit: "`x`.splice(`i`, 1);".} else: - when defined(js): - var it : T - {.emit: "`x` = `x` || []; `x`.splice(`i`, 0, `it`);".} - else: - defaultImpl() - x[i] = item + defaultImpl() + +proc insert*[T](x: var seq[T], item: T, i = 0.Natural) {.noSideEffect.} = + ## Inserts `item` into `x` at position `i`. + ## + ## .. code-block:: Nim + ## var i = @[1, 3, 5] + ## i.insert(99, 0) # i <- @[99, 1, 3, 5] + template defaultImpl = + let xl = x.len + setLen(x, xl+1) + var j = xl-1 + while j >= i: + movingCopy(x[j+1], x[j]) + dec(j) + when nimvm: + defaultImpl() + else: + when defined(js): + var it : T + {.emit: "`x` = `x` || []; `x`.splice(`i`, 0, `it`);".} + else: + defaultImpl() + x[i] = item when not defined(nimV2): proc repr*[T](x: T): string {.magic: "Repr", noSideEffect.} ## Takes any Nim variable and returns its string representation. - ## No trailing newline is inserted (so `echo` won't add an empty newline). - ## Use `-d:nimLegacyReprWithNewline` to revert to old behavior where newlines - ## were added in some cases. ## ## It works even for complex data graphs with cycles. This is a great ## debugging tool. - ## ``` - ## var s: seq[string] = @["test2", "test2"] - ## var i = @[1, 2, 3, 4, 5] - ## echo repr(s) # => 0x1055eb050[0x1055ec050"test2", 0x1055ec078"test2"] - ## echo repr(i) # => 0x1055ed050[1, 2, 3, 4, 5] - ## ``` + ## + ## .. code-block:: Nim + ## var s: seq[string] = @["test2", "test2"] + ## var i = @[1, 2, 3, 4, 5] + ## echo repr(s) # => 0x1055eb050[0x1055ec050"test2", 0x1055ec078"test2"] + ## echo repr(i) # => 0x1055ed050[1, 2, 3, 4, 5] -when not defined(nimPreviewSlimSystem): +type + ByteAddress* = int + ## is the signed integer type that should be used for converting + ## pointers to integer addresses for readability. + + BiggestFloat* = float64 + ## is an alias for the biggest floating point type the Nim + ## compiler supports. Currently this is ``float64``, but it is + ## platform-dependent in general. + +when defined(js): + type BiggestUInt* = uint32 + ## is an alias for the biggest unsigned integer type the Nim compiler + ## supports. Currently this is ``uint32`` for JS and ``uint64`` for other + ## targets. +else: + type BiggestUInt* = uint64 + ## is an alias for the biggest unsigned integer type the Nim compiler + ## supports. Currently this is ``uint32`` for JS and ``uint64`` for other + ## targets. + +when defined(windows): type - csize* {.importc: "size_t", nodecl, deprecated: "use `csize_t` instead".} = int - ## This isn't the same as `size_t` in *C*. Don't use it. + clong* {.importc: "long", nodecl.} = int32 + ## This is the same as the type ``long`` in *C*. + culong* {.importc: "unsigned long", nodecl.} = uint32 + ## This is the same as the type ``unsigned long`` in *C*. +else: + type + clong* {.importc: "long", nodecl.} = int + ## This is the same as the type ``long`` in *C*. + culong* {.importc: "unsigned long", nodecl.} = uint + ## This is the same as the type ``unsigned long`` in *C*. + +type # these work for most platforms: + cchar* {.importc: "char", nodecl.} = char + ## This is the same as the type ``char`` in *C*. + cschar* {.importc: "signed char", nodecl.} = int8 + ## This is the same as the type ``signed char`` in *C*. + cshort* {.importc: "short", nodecl.} = int16 + ## This is the same as the type ``short`` in *C*. + cint* {.importc: "int", nodecl.} = int32 + ## This is the same as the type ``int`` in *C*. + csize* {.importc: "size_t", nodecl, deprecated: "use `csize_t` instead".} = int + ## This isn't the same as ``size_t`` in *C*. Don't use it. + csize_t* {.importc: "size_t", nodecl.} = uint + ## This is the same as the type ``size_t`` in *C*. + clonglong* {.importc: "long long", nodecl.} = int64 + ## This is the same as the type ``long long`` in *C*. + cfloat* {.importc: "float", nodecl.} = float32 + ## This is the same as the type ``float`` in *C*. + cdouble* {.importc: "double", nodecl.} = float64 + ## This is the same as the type ``double`` in *C*. + clongdouble* {.importc: "long double", nodecl.} = BiggestFloat + ## This is the same as the type ``long double`` in *C*. + ## This C type is not supported by Nim's code generator. + + cuchar* {.importc: "unsigned char", nodecl.} = char + ## This is the same as the type ``unsigned char`` in *C*. + cushort* {.importc: "unsigned short", nodecl.} = uint16 + ## This is the same as the type ``unsigned short`` in *C*. + cuint* {.importc: "unsigned int", nodecl.} = uint32 + ## This is the same as the type ``unsigned int`` in *C*. + culonglong* {.importc: "unsigned long long", nodecl.} = uint64 + ## This is the same as the type ``unsigned long long`` in *C*. + + cstringArray* {.importc: "char**", nodecl.} = ptr UncheckedArray[cstring] + ## This is binary compatible to the type ``char**`` in *C*. The array's + ## high value is large enough to disable bounds checking in practice. + ## Use `cstringArrayToSeq proc <#cstringArrayToSeq,cstringArray,Natural>`_ + ## to convert it into a ``seq[string]``. + + PFloat32* = ptr float32 ## An alias for ``ptr float32``. + PFloat64* = ptr float64 ## An alias for ``ptr float64``. + PInt64* = ptr int64 ## An alias for ``ptr int64``. + PInt32* = ptr int32 ## An alias for ``ptr int32``. + +proc toFloat*(i: int): float {.noSideEffect, inline.} = + ## Converts an integer `i` into a ``float``. + ## + ## If the conversion fails, `ValueError` is raised. + ## However, on most platforms the conversion cannot fail. + ## + ## .. code-block:: Nim + ## let + ## a = 2 + ## b = 3.7 + ## + ## echo a.toFloat + b # => 5.7 + float(i) + +proc toBiggestFloat*(i: BiggestInt): BiggestFloat {.noSideEffect, inline.} = + ## Same as `toFloat <#toFloat,int>`_ but for ``BiggestInt`` to ``BiggestFloat``. + BiggestFloat(i) + +proc toInt*(f: float): int {.noSideEffect.} = + ## Converts a floating point number `f` into an ``int``. + ## + ## Conversion rounds `f` half away from 0, see + ## `Round half away from zero + ## `_. + ## + ## Note that some floating point numbers (e.g. infinity or even 1e19) + ## cannot be accurately converted. + ## + ## .. code-block:: Nim + ## doAssert toInt(0.49) == 0 + ## doAssert toInt(0.5) == 1 + ## doAssert toInt(-0.5) == -1 # rounding is symmetrical + if f >= 0: int(f+0.5) else: int(f-0.5) + +proc toBiggestInt*(f: BiggestFloat): BiggestInt {.noSideEffect.} = + ## Same as `toInt <#toInt,float>`_ but for ``BiggestFloat`` to ``BiggestInt``. + if f >= 0: BiggestInt(f+0.5) else: BiggestInt(f-0.5) + +proc addQuitProc*(quitProc: proc() {.noconv.}) {. + importc: "atexit", header: "".} + ## Adds/registers a quit procedure. + ## + ## Each call to ``addQuitProc`` registers another quit procedure. Up to 30 + ## procedures can be registered. They are executed on a last-in, first-out + ## basis (that is, the last function registered is the first to be executed). + ## ``addQuitProc`` raises an EOutOfIndex exception if ``quitProc`` cannot be + ## registered. + +# Support for addQuitProc() is done by Ansi C's facilities here. +# In case of an unhandled exception the exit handlers should +# not be called explicitly! The user may decide to do this manually though. + + +proc swap*[T](a, b: var T) {.magic: "Swap", noSideEffect.} + ## Swaps the values `a` and `b`. + ## + ## This is often more efficient than ``tmp = a; a = b; b = tmp``. + ## Particularly useful for sorting algorithms. + ## + ## .. code-block:: Nim + ## var + ## a = 5 + ## b = 9 + ## + ## swap(a, b) + ## + ## assert a == 9 + ## assert b == 5 + +when not defined(js) and not defined(booting) and defined(nimTrMacros): + template swapRefsInArray*{swap(arr[a], arr[b])}(arr: openArray[ref], a, b: int) = + # Optimize swapping of array elements if they are refs. Default swap + # implementation will cause unsureAsgnRef to be emitted which causes + # unnecessary slow down in this case. + swap(cast[ptr pointer](addr arr[a])[], cast[ptr pointer](addr arr[b])[]) const Inf* = 0x7FF0000000000000'f64 @@ -1231,149 +1440,9 @@ const ## Contains an IEEE floating point value of *Not A Number*. ## ## Note that you cannot compare a floating point value to this value - ## and expect a reasonable result - use the `isNaN` or `classify` procedure + ## and expect a reasonable result - use the `classify` procedure ## in the `math module `_ for checking for NaN. -proc high*(T: typedesc[SomeFloat]): T = Inf -proc low*(T: typedesc[SomeFloat]): T = NegInf - -proc toFloat*(i: int): float {.noSideEffect, inline.} = - ## Converts an integer `i` into a `float`. Same as `float(i)`. - ## - ## If the conversion fails, `ValueError` is raised. - ## However, on most platforms the conversion cannot fail. - ## - ## ``` - ## let - ## a = 2 - ## b = 3.7 - ## - ## echo a.toFloat + b # => 5.7 - ## ``` - float(i) - -proc toBiggestFloat*(i: BiggestInt): BiggestFloat {.noSideEffect, inline.} = - ## Same as `toFloat <#toFloat,int>`_ but for `BiggestInt` to `BiggestFloat`. - BiggestFloat(i) - -proc toInt*(f: float): int {.noSideEffect.} = - ## Converts a floating point number `f` into an `int`. - ## - ## Conversion rounds `f` half away from 0, see - ## `Round half away from zero - ## `_, - ## as opposed to a type conversion which rounds towards zero. - ## - ## Note that some floating point numbers (e.g. infinity or even 1e19) - ## cannot be accurately converted. - ## ``` - ## doAssert toInt(0.49) == 0 - ## doAssert toInt(0.5) == 1 - ## doAssert toInt(-0.5) == -1 # rounding is symmetrical - ## ``` - if f >= 0: int(f+0.5) else: int(f-0.5) - -proc toBiggestInt*(f: BiggestFloat): BiggestInt {.noSideEffect.} = - ## Same as `toInt <#toInt,float>`_ but for `BiggestFloat` to `BiggestInt`. - if f >= 0: BiggestInt(f+0.5) else: BiggestInt(f-0.5) - -proc `/`*(x, y: int): float {.inline, noSideEffect.} = - ## Division of integers that results in a float. - ## ``` - ## echo 7 / 5 # => 1.4 - ## ``` - ## - ## See also: - ## * `div `_ - ## * `mod `_ - result = toFloat(x) / toFloat(y) - -{.push stackTrace: off.} - -when defined(js): - proc js_abs[T: SomeNumber](x: T): T {.importc: "Math.abs".} -else: - proc c_fabs(x: cdouble): cdouble {.importc: "fabs", header: "".} - proc c_fabsf(x: cfloat): cfloat {.importc: "fabsf", header: "".} - -proc abs*[T: float64 | float32](x: T): T {.noSideEffect, inline.} = - when nimvm: - if x < 0.0: result = -x - elif x == 0.0: result = 0.0 # handle 0.0, -0.0 - else: result = x # handle NaN, > 0 - else: - when defined(js): result = js_abs(x) - else: - when T is float64: - result = c_fabs(x) - else: - result = c_fabsf(x) - -func abs*(x: int): int {.magic: "AbsI", inline.} = - if x < 0: -x else: x -func abs*(x: int8): int8 {.magic: "AbsI", inline.} = - if x < 0: -x else: x -func abs*(x: int16): int16 {.magic: "AbsI", inline.} = - if x < 0: -x else: x -func abs*(x: int32): int32 {.magic: "AbsI", inline.} = - if x < 0: -x else: x -func abs*(x: int64): int64 {.magic: "AbsI", inline.} = - ## Returns the absolute value of `x`. - ## - ## If `x` is `low(x)` (that is -MININT for its type), - ## an overflow exception is thrown (if overflow checking is turned on). - result = if x < 0: -x else: x - -{.pop.} # stackTrace: off - -when not defined(nimPreviewSlimSystem): - proc addQuitProc*(quitProc: proc() {.noconv.}) {. - importc: "atexit", header: "", deprecated: "use exitprocs.addExitProc".} - ## Adds/registers a quit procedure. - ## - ## Each call to `addQuitProc` registers another quit procedure. Up to 30 - ## procedures can be registered. They are executed on a last-in, first-out - ## basis (that is, the last function registered is the first to be executed). - ## `addQuitProc` raises an EOutOfIndex exception if `quitProc` cannot be - ## registered. - # Support for addQuitProc() is done by Ansi C's facilities here. - # In case of an unhandled exception the exit handlers should - # not be called explicitly! The user may decide to do this manually though. - -proc swap*[T](a, b: var T) {.magic: "Swap", noSideEffect.} - ## Swaps the values `a` and `b`. - ## - ## This is often more efficient than `tmp = a; a = b; b = tmp`. - ## Particularly useful for sorting algorithms. - ## - ## ``` - ## var - ## a = 5 - ## b = 9 - ## - ## swap(a, b) - ## - ## assert a == 9 - ## assert b == 5 - ## ``` - -when not defined(js) and not defined(booting) and defined(nimTrMacros): - template swapRefsInArray*{swap(arr[a], arr[b])}(arr: openArray[ref], a, b: int) = - # Optimize swapping of array elements if they are refs. Default swap - # implementation will cause unsureAsgnRef to be emitted which causes - # unnecessary slow down in this case. - swap(cast[ptr pointer](addr arr[a])[], cast[ptr pointer](addr arr[b])[]) - -when not defined(nimscript): - {.push stackTrace: off, profiler: off.} - - when not defined(nimPreviewSlimSystem): - import std/sysatomics - export sysatomics - else: - import std/sysatomics - - {.pop.} include "system/memalloc" @@ -1383,133 +1452,126 @@ proc `|`*(a, b: typedesc): typedesc = discard include "system/iterators_1" +{.push stackTrace: off.} + +proc abs*(x: float64): float64 {.noSideEffect, inline.} = + if x < 0.0: -x else: x +proc abs*(x: float32): float32 {.noSideEffect, inline.} = + if x < 0.0: -x else: x +proc min*(x, y: float32): float32 {.noSideEffect, inline.} = + if x <= y or y != y: x else: y +proc min*(x, y: float64): float64 {.noSideEffect, inline.} = + if x <= y or y != y: x else: y +proc max*(x, y: float32): float32 {.noSideEffect, inline.} = + if y <= x or y != y: x else: y +proc max*(x, y: float64): float64 {.noSideEffect, inline.} = + if y <= x or y != y: x else: y +proc min*[T: not SomeFloat](x, y: T): T {.inline.} = + if x <= y: x else: y +proc max*[T: not SomeFloat](x, y: T): T {.inline.} = + if y <= x: x else: y + +{.pop.} # stackTrace: off + + +proc high*(T: typedesc[SomeFloat]): T = Inf +proc low*(T: typedesc[SomeFloat]): T = NegInf + proc len*[U: Ordinal; V: Ordinal](x: HSlice[U, V]): int {.noSideEffect, inline.} = ## Length of ordinal slice. When x.b < x.a returns zero length. - ## ``` + ## + ## .. code-block:: Nim ## assert((0..5).len == 6) ## assert((5..2).len == 0) - ## ``` result = max(0, ord(x.b) - ord(x.a) + 1) +when defined(nimNoNilSeqs2): + when not compileOption("nilseqs"): + {.pragma: nilError, error.} + else: + {.pragma: nilError.} +else: + {.pragma: nilError.} + +proc isNil*[T](x: seq[T]): bool {.noSideEffect, magic: "IsNil", nilError.} + ## Requires `--nilseqs:on` since 0.19. + ## + ## Seqs are no longer nil by default, but set and empty. + ## Check for zero length instead. + ## + ## See also: + ## * `isNil(string) <#isNil,string>`_ + proc isNil*[T](x: ref T): bool {.noSideEffect, magic: "IsNil".} +proc isNil*(x: string): bool {.noSideEffect, magic: "IsNil", nilError.} + ## Requires `--nilseqs:on`. + ## + ## See also: + ## * `isNil(seq[T]) <#isNil,seq[T][T]>`_ proc isNil*[T](x: ptr T): bool {.noSideEffect, magic: "IsNil".} proc isNil*(x: pointer): bool {.noSideEffect, magic: "IsNil".} proc isNil*(x: cstring): bool {.noSideEffect, magic: "IsNil".} proc isNil*[T: proc](x: T): bool {.noSideEffect, magic: "IsNil".} ## Fast check whether `x` is nil. This is sometimes more efficient than - ## `== nil`. + ## ``== nil``. -when defined(nimHasTopDownInference): - # magic used for seq type inference - proc `@`*[T](a: openArray[T]): seq[T] {.magic: "OpenArrayToSeq".} = - ## Turns an *openArray* into a sequence. - ## - ## This is not as efficient as turning a fixed length array into a sequence - ## as it always copies every element of `a`. - newSeq(result, a.len) - for i in 0..a.len-1: result[i] = a[i] -else: - proc `@`*[T](a: openArray[T]): seq[T] = - ## Turns an *openArray* into a sequence. - ## - ## This is not as efficient as turning a fixed length array into a sequence - ## as it always copies every element of `a`. - newSeq(result, a.len) - for i in 0..a.len-1: result[i] = a[i] +proc `@`*[T](a: openArray[T]): seq[T] = + ## Turns an *openArray* into a sequence. + ## + ## This is not as efficient as turning a fixed length array into a sequence + ## as it always copies every element of `a`. + newSeq(result, a.len) + for i in 0..a.len-1: result[i] = a[i] + +proc `&`*[T](x, y: seq[T]): seq[T] {.noSideEffect.} = + ## Concatenates two sequences. + ## + ## Requires copying of the sequences. + ## + ## See also: + ## * `add(var seq[T], openArray[T]) <#add,seq[T][T],openArray[T]>`_ + ## + ## .. code-block:: Nim + ## assert(@[1, 2, 3, 4] & @[5, 6] == @[1, 2, 3, 4, 5, 6]) + newSeq(result, x.len + y.len) + for i in 0..x.len-1: + result[i] = x[i] + for i in 0..y.len-1: + result[i+x.len] = y[i] + +proc `&`*[T](x: seq[T], y: T): seq[T] {.noSideEffect.} = + ## Appends element y to the end of the sequence. + ## + ## Requires copying of the sequence. + ## + ## See also: + ## * `add(var seq[T], T) <#add,seq[T][T],T>`_ + ## + ## .. code-block:: Nim + ## assert(@[1, 2, 3] & 4 == @[1, 2, 3, 4]) + newSeq(result, x.len + 1) + for i in 0..x.len-1: + result[i] = x[i] + result[x.len] = y + +proc `&`*[T](x: T, y: seq[T]): seq[T] {.noSideEffect.} = + ## Prepends the element x to the beginning of the sequence. + ## + ## Requires copying of the sequence. + ## + ## .. code-block:: Nim + ## assert(1 & @[2, 3, 4] == @[1, 2, 3, 4]) + newSeq(result, y.len + 1) + result[0] = x + for i in 0..y.len-1: + result[i+1] = y[i] -when defined(nimSeqsV2): - - proc `&`*[T](x, y: sink seq[T]): seq[T] {.noSideEffect.} = - ## Concatenates two sequences. - ## - ## Requires copying of the sequences. - ## ``` - ## assert(@[1, 2, 3, 4] & @[5, 6] == @[1, 2, 3, 4, 5, 6]) - ## ``` - ## - ## See also: - ## * `add(var seq[T], openArray[T]) <#add,seq[T],openArray[T]>`_ - newSeq(result, x.len + y.len) - for i in 0..x.len-1: - result[i] = move(x[i]) - for i in 0..y.len-1: - result[i+x.len] = move(y[i]) - - proc `&`*[T](x: sink seq[T], y: sink T): seq[T] {.noSideEffect.} = - ## Appends element y to the end of the sequence. - ## - ## Requires copying of the sequence. - ## ``` - ## assert(@[1, 2, 3] & 4 == @[1, 2, 3, 4]) - ## ``` - ## - ## See also: - ## * `add(var seq[T], T) <#add,seq[T],sinkT>`_ - newSeq(result, x.len + 1) - for i in 0..x.len-1: - result[i] = move(x[i]) - result[x.len] = move(y) - - proc `&`*[T](x: sink T, y: sink seq[T]): seq[T] {.noSideEffect.} = - ## Prepends the element x to the beginning of the sequence. - ## - ## Requires copying of the sequence. - ## ``` - ## assert(1 & @[2, 3, 4] == @[1, 2, 3, 4]) - ## ``` - newSeq(result, y.len + 1) - result[0] = move(x) - for i in 0..y.len-1: - result[i+1] = move(y[i]) - -else: - - proc `&`*[T](x, y: seq[T]): seq[T] {.noSideEffect.} = - ## Concatenates two sequences. - ## - ## Requires copying of the sequences. - ## ``` - ## assert(@[1, 2, 3, 4] & @[5, 6] == @[1, 2, 3, 4, 5, 6]) - ## ``` - ## - ## See also: - ## * `add(var seq[T], openArray[T]) <#add,seq[T],openArray[T]>`_ - newSeq(result, x.len + y.len) - for i in 0..x.len-1: - result[i] = x[i] - for i in 0..y.len-1: - result[i+x.len] = y[i] - - proc `&`*[T](x: seq[T], y: T): seq[T] {.noSideEffect.} = - ## Appends element y to the end of the sequence. - ## - ## Requires copying of the sequence. - ## ``` - ## assert(@[1, 2, 3] & 4 == @[1, 2, 3, 4]) - ## ``` - ## - ## See also: - ## * `add(var seq[T], T) <#add,seq[T],sinkT>`_ - newSeq(result, x.len + 1) - for i in 0..x.len-1: - result[i] = x[i] - result[x.len] = y - - proc `&`*[T](x: T, y: seq[T]): seq[T] {.noSideEffect.} = - ## Prepends the element x to the beginning of the sequence. - ## - ## Requires copying of the sequence. - ## ``` - ## assert(1 & @[2, 3, 4] == @[1, 2, 3, 4]) - ## ``` - newSeq(result, y.len + 1) - result[0] = x - for i in 0..y.len-1: - result[i+1] = y[i] - +proc astToStr*[T](x: T): string {.magic: "AstToStr", noSideEffect.} + ## Converts the AST of `x` into a string representation. This is very useful + ## for debugging. proc instantiationInfo*(index = -1, fullPaths = false): tuple[ filename: string, line: int, column: int] {.magic: "InstantiationInfo", noSideEffect.} @@ -1519,12 +1581,12 @@ proc instantiationInfo*(index = -1, fullPaths = false): tuple[ ## While similar to the `caller info`:idx: of other languages, it is determined ## at compile time. ## - ## This proc is mostly useful for meta programming (eg. `assert` template) + ## This proc is mostly useful for meta programming (eg. ``assert`` template) ## to retrieve information about the current filename and line number. ## Example: ## - ## ``` - ## import std/strutils + ## .. code-block:: nim + ## import strutils ## ## template testException(exception, code: untyped): typed = ## try: @@ -1542,38 +1604,43 @@ proc instantiationInfo*(index = -1, fullPaths = false): tuple[ ## result = a[pos] ## ## when isMainModule: - ## testException(IndexDefect, tester(30)) - ## testException(IndexDefect, tester(1)) + ## testException(IndexError, tester(30)) + ## testException(IndexError, tester(1)) ## # --> Test failure at example.nim:20 with 'tester(1)' - ## ``` +proc compiles*(x: untyped): bool {.magic: "Compiles", noSideEffect, compileTime.} = + ## Special compile-time procedure that checks whether `x` can be compiled + ## without any semantic error. + ## This can be used to check whether a type supports some operation: + ## + ## .. code-block:: Nim + ## when compiles(3 + 4): + ## echo "'+' for integers is available" + discard when notJSnotNims: - import system/ansi_c - import system/memory + import "system/ansi_c" + import "system/memory" {.push stackTrace: off.} when not defined(js) and hasThreadSupport and hostOS != "standalone": - import std/private/syslocks + const insideRLocksModule = false + include "system/syslocks" include "system/threadlocalstorage" when not defined(js) and defined(nimV2): type + TNimNode {.compilerproc.} = object # to keep the code generator simple DestructorProc = proc (p: pointer) {.nimcall, benign, raises: [].} - TNimTypeV2 {.compilerproc.} = object + TNimType {.compilerproc.} = object destructor: pointer size: int - align: int16 - depth: int16 - display: ptr UncheckedArray[uint32] # classToken - when defined(nimTypeNames): - name: cstring + name: cstring traceImpl: pointer - typeInfoV1: pointer # for backwards compat, usually nil - flags: int - PNimTypeV2 = ptr TNimTypeV2 + disposeImpl: pointer + PNimType = ptr TNimType when notJSnotNims and defined(nimSeqsV2): include "system/strs_v2" @@ -1581,28 +1648,37 @@ when notJSnotNims and defined(nimSeqsV2): {.pop.} -when not defined(nimscript): + +when notJSnotNims: proc writeStackTrace*() {.tags: [], gcsafe, raises: [].} - ## Writes the current stack trace to `stderr`. This is only works + ## Writes the current stack trace to ``stderr``. This is only works ## for debug builds. Since it's usually used for debugging, this ## is proclaimed to have no IO effect! when not declared(sysFatal): include "system/fatal" +when notJSnotNims: + {.push stackTrace: off, profiler: off.} + + proc atomicInc*(memLoc: var int, x: int = 1): int {.inline, + discardable, benign.} + ## Atomic increment of `memLoc`. Returns the value after the operation. + + proc atomicDec*(memLoc: var int, x: int = 1): int {.inline, + discardable, benign.} + ## Atomic decrement of `memLoc`. Returns the value after the operation. + + include "system/atomics" + + {.pop.} + when defined(nimV2): - include system/arc + include system/refs_v2 -template newException*(exceptn: typedesc, message: string; - parentException: ref Exception = nil): untyped = - ## Creates an exception object of type `exceptn` and sets its `msg` field - ## to `message`. Returns the new exception object. - (ref exceptn)(msg: message, parent: parentException) - -when not defined(nimPreviewSlimSystem): - import std/assertions - export assertions +import system/assertions +export assertions import system/iterators export iterators @@ -1611,7 +1687,6 @@ export iterators proc find*[T, S](a: T, item: S): int {.inline.}= ## Returns the first index of `item` in `a` or -1 if not found. This requires ## appropriate `items` and `==` operations to work. - result = 0 for i in items(a): if i == item: return inc(result) @@ -1619,23 +1694,21 @@ proc find*[T, S](a: T, item: S): int {.inline.}= proc contains*[T](a: openArray[T], item: T): bool {.inline.}= ## Returns true if `item` is in `a` or false if not found. This is a shortcut - ## for `find(a, item) >= 0`. + ## for ``find(a, item) >= 0``. ## ## This allows the `in` operator: `a.contains(item)` is the same as ## `item in a`. - ## ``` + ## + ## .. code-block:: Nim ## var a = @[1, 3, 5] ## assert a.contains(5) ## assert 3 in a ## assert 99 notin a - ## ``` return find(a, item) >= 0 proc pop*[T](s: var seq[T]): T {.inline, noSideEffect.} = - ## Returns the last item of `s` and decreases `s.len` by one. This treats + ## Returns the last item of `s` and decreases ``s.len`` by one. This treats ## `s` as a stack and implements the common *pop* operation. - ## - ## Raises `IndexDefect` if `s` is empty. runnableExamples: var a = @[1, 3, 5, 7] let b = pop(a) @@ -1651,14 +1724,14 @@ proc pop*[T](s: var seq[T]): T {.inline, noSideEffect.} = setLen(s, L) proc `==`*[T: tuple|object](x, y: T): bool = - ## Generic `==` operator for tuples that is lifted from the components. + ## Generic ``==`` operator for tuples that is lifted from the components. ## of `x` and `y`. for a, b in fields(x, y): if a != b: return false return true proc `<=`*[T: tuple](x, y: T): bool = - ## Generic lexicographic `<=` operator for tuples that is lifted from the + ## Generic lexicographic ``<=`` operator for tuples that is lifted from the ## components of `x` and `y`. This implementation uses `cmp`. for a, b in fields(x, y): var c = cmp(a, b) @@ -1667,7 +1740,7 @@ proc `<=`*[T: tuple](x, y: T): bool = return true proc `<`*[T: tuple](x, y: T): bool = - ## Generic lexicographic `<` operator for tuples that is lifted from the + ## Generic lexicographic ``<`` operator for tuples that is lifted from the ## components of `x` and `y`. This implementation uses `cmp`. for a, b in fields(x, y): var c = cmp(a, b) @@ -1681,7 +1754,25 @@ include "system/gc_interface" # we have to compute this here before turning it off in except.nim anyway ... const NimStackTrace = compileOption("stacktrace") -import system/coro_detection +template coroutinesSupportedPlatform(): bool = + when defined(sparc) or defined(ELATE) or compileOption("gc", "v2") or + defined(boehmgc) or defined(gogc) or defined(nogc) or defined(gcRegions) or + defined(gcMarkAndSweep): + false + else: + true + +when defined(nimCoroutines): + # Explicit opt-in. + when not coroutinesSupportedPlatform(): + {.error: "Coroutines are not supported on this architecture and/or garbage collector.".} + const nimCoroutines* = true +elif defined(noNimCoroutines): + # Explicit opt-out. + const nimCoroutines* = false +else: + # Autodetect coroutine support. + const nimCoroutines* = false {.push checks: off.} # obviously we cannot generate checking operations here :-) @@ -1689,57 +1780,57 @@ import system/coro_detection # however, stack-traces are available for most parts # of the code -when notJSnotNims: - var - globalRaiseHook*: proc (e: ref Exception): bool {.nimcall, benign.} - ## With this hook you can influence exception handling on a global level. - ## If not nil, every 'raise' statement ends up calling this hook. - ## - ## .. warning:: Ordinary application code should never set this hook! You better know what you do when setting this. - ## - ## If `globalRaiseHook` returns false, the exception is caught and does - ## not propagate further through the call stack. +var + globalRaiseHook*: proc (e: ref Exception): bool {.nimcall, benign.} + ## With this hook you can influence exception handling on a global level. + ## If not nil, every 'raise' statement ends up calling this hook. + ## + ## **Warning**: Ordinary application code should never set this hook! + ## You better know what you do when setting this. + ## + ## If ``globalRaiseHook`` returns false, the exception is caught and does + ## not propagate further through the call stack. - localRaiseHook* {.threadvar.}: proc (e: ref Exception): bool {.nimcall, benign.} - ## With this hook you can influence exception handling on a - ## thread local level. - ## If not nil, every 'raise' statement ends up calling this hook. - ## - ## .. warning:: Ordinary application code should never set this hook! You better know what you do when setting this. - ## - ## If `localRaiseHook` returns false, the exception - ## is caught and does not propagate further through the call stack. + localRaiseHook* {.threadvar.}: proc (e: ref Exception): bool {.nimcall, benign.} + ## With this hook you can influence exception handling on a + ## thread local level. + ## If not nil, every 'raise' statement ends up calling this hook. + ## + ## **Warning**: Ordinary application code should never set this hook! + ## You better know what you do when setting this. + ## + ## If ``localRaiseHook`` returns false, the exception + ## is caught and does not propagate further through the call stack. - outOfMemHook*: proc () {.nimcall, tags: [], benign, raises: [].} - ## Set this variable to provide a procedure that should be called - ## in case of an `out of memory`:idx: event. The standard handler - ## writes an error message and terminates the program. - ## - ## `outOfMemHook` can be used to raise an exception in case of OOM like so: - ## - ## ``` - ## var gOutOfMem: ref EOutOfMemory - ## new(gOutOfMem) # need to be allocated *before* OOM really happened! - ## gOutOfMem.msg = "out of memory" - ## - ## proc handleOOM() = - ## raise gOutOfMem - ## - ## system.outOfMemHook = handleOOM - ## ``` - ## - ## If the handler does not raise an exception, ordinary control flow - ## continues and the program is terminated. - unhandledExceptionHook*: proc (e: ref Exception) {.nimcall, tags: [], benign, raises: [].} - ## Set this variable to provide a procedure that should be called - ## in case of an `unhandle exception` event. The standard handler - ## writes an error message and terminates the program, except when - ## using `--os:any` + outOfMemHook*: proc () {.nimcall, tags: [], benign, raises: [].} + ## Set this variable to provide a procedure that should be called + ## in case of an `out of memory`:idx: event. The standard handler + ## writes an error message and terminates the program. + ## + ## `outOfMemHook` can be used to raise an exception in case of OOM like so: + ## + ## .. code-block:: Nim + ## + ## var gOutOfMem: ref EOutOfMemory + ## new(gOutOfMem) # need to be allocated *before* OOM really happened! + ## gOutOfMem.msg = "out of memory" + ## + ## proc handleOOM() = + ## raise gOutOfMem + ## + ## system.outOfMemHook = handleOOM + ## + ## If the handler does not raise an exception, ordinary control flow + ## continues and the program is terminated. + unhandledExceptionHook*: proc (e: ref Exception) {.nimcall, tags: [], benign, raises: [].} + ## Set this variable to provide a procedure that should be called + ## in case of an `unhandle exception` event. The standard handler + ## writes an error message and terminates the program, except when + ## using `--os:any` type PFrame* = ptr TFrame ## Represents a runtime frame of the call stack; ## part of the debugger API. - # keep in sync with nimbase.h `struct TFrame_` TFrame* {.importc, nodecl, final.} = object ## The frame itself. prev*: PFrame ## Previous frame; used for chaining the call stack. procname*: cstring ## Name of the proc that is currently executing. @@ -1747,17 +1838,9 @@ type filename*: cstring ## Filename of the proc that is currently executing. len*: int16 ## Length of the inspectable slots. calldepth*: int16 ## Used for max call depth checking. - when NimStackTraceMsgs: - frameMsgLen*: int ## end position in frameMsgBuf for this frame. -when defined(js) or defined(nimdoc): +when defined(js): proc add*(x: var string, y: cstring) {.asmNoStackFrame.} = - ## Appends `y` to `x` in place. - runnableExamples: - var tmp = "" - tmp.add(cstring("ab")) - tmp.add(cstring("cd")) - doAssert tmp == "abcd" asm """ if (`x` === null) { `x` = []; } var off = `x`.length; @@ -1766,15 +1849,7 @@ when defined(js) or defined(nimdoc): `x`[off+i] = `y`.charCodeAt(i); } """ - proc add*(x: var cstring, y: cstring) {.magic: "AppendStrStr".} = - ## Appends `y` to `x` in place. - ## Only implemented for JS backend. - runnableExamples: - when defined(js): - var tmp: cstring = "" - tmp.add(cstring("ab")) - tmp.add(cstring("cd")) - doAssert tmp == cstring("abcd") + proc add*(x: var cstring, y: cstring) {.magic: "AppendStrStr".} elif hasAlloc: {.push stackTrace: off, profiler: off.} @@ -1786,32 +1861,52 @@ elif hasAlloc: inc(i) {.pop.} -proc echo*(x: varargs[typed, `$`]) {.magic: "Echo", benign, sideEffect.} - ## Writes and flushes the parameters to the standard output. - ## - ## Special built-in that takes a variable number of arguments. Each argument - ## is converted to a string via `$`, so it works for user-defined - ## types that have an overloaded `$` operator. - ## It is roughly equivalent to `writeLine(stdout, x); flushFile(stdout)`, but - ## available for the JavaScript target too. - ## - ## Unlike other IO operations this is guaranteed to be thread-safe as - ## `echo` is very often used for debugging convenience. If you want to use - ## `echo` inside a `proc without side effects - ## `_ you can use `debugEcho - ## <#debugEcho,varargs[typed,]>`_ instead. +when defined(nimvarargstyped): + proc echo*(x: varargs[typed, `$`]) {.magic: "Echo", tags: [WriteIOEffect], + benign, sideEffect.} + ## Writes and flushes the parameters to the standard output. + ## + ## Special built-in that takes a variable number of arguments. Each argument + ## is converted to a string via ``$``, so it works for user-defined + ## types that have an overloaded ``$`` operator. + ## It is roughly equivalent to ``writeLine(stdout, x); flushFile(stdout)``, but + ## available for the JavaScript target too. + ## + ## Unlike other IO operations this is guaranteed to be thread-safe as + ## ``echo`` is very often used for debugging convenience. If you want to use + ## ``echo`` inside a `proc without side effects + ## `_ you can use `debugEcho + ## <#debugEcho,varargs[typed,]>`_ instead. -proc debugEcho*(x: varargs[typed, `$`]) {.magic: "Echo", noSideEffect, - tags: [], raises: [].} - ## Same as `echo <#echo,varargs[typed,]>`_, but as a special semantic rule, - ## `debugEcho` pretends to be free of side effects, so that it can be used - ## for debugging routines marked as `noSideEffect - ## `_. + proc debugEcho*(x: varargs[typed, `$`]) {.magic: "Echo", noSideEffect, + tags: [], raises: [].} + ## Same as `echo <#echo,varargs[typed,]>`_, but as a special semantic rule, + ## ``debugEcho`` pretends to be free of side effects, so that it can be used + ## for debugging routines marked as `noSideEffect + ## `_. +else: + proc echo*(x: varargs[untyped, `$`]) {.magic: "Echo", tags: [WriteIOEffect], + benign, sideEffect.} + proc debugEcho*(x: varargs[untyped, `$`]) {.magic: "Echo", noSideEffect, + tags: [], raises: [].} + +template newException*(exceptn: typedesc, message: string; + parentException: ref Exception = nil): untyped = + ## Creates an exception object of type ``exceptn`` and sets its ``msg`` field + ## to `message`. Returns the new exception object. + when declared(owned): + var e: owned(ref exceptn) + else: + var e: ref exceptn + new(e) + e.msg = message + e.parent = parentException + e when hostOS == "standalone" and defined(nogc): proc nimToCStringConv(s: NimString): cstring {.compilerproc, inline.} = if s == nil or s.len == 0: result = cstring"" - else: result = cast[cstring](addr s.data) + else: result = cstring(addr s.data) proc getTypeInfo*[T](x: T): pointer {.magic: "GetTypeInfo", benign.} ## Get type information for `x`. @@ -1819,9 +1914,25 @@ proc getTypeInfo*[T](x: T): pointer {.magic: "GetTypeInfo", benign.} ## Ordinary code should not use this, but the `typeinfo module ## `_ instead. +{.push stackTrace: off.} +proc abs*(x: int): int {.magic: "AbsI", noSideEffect.} = + if x < 0: -x else: x +proc abs*(x: int8): int8 {.magic: "AbsI", noSideEffect.} = + if x < 0: -x else: x +proc abs*(x: int16): int16 {.magic: "AbsI", noSideEffect.} = + if x < 0: -x else: x +proc abs*(x: int32): int32 {.magic: "AbsI", noSideEffect.} = + if x < 0: -x else: x +proc abs*(x: int64): int64 {.magic: "AbsI", noSideEffect.} = + ## Returns the absolute value of `x`. + ## + ## If `x` is ``low(x)`` (that is -MININT for its type), + ## an overflow exception is thrown (if overflow checking is turned on). + result = if x < 0: -x else: x +{.pop.} + when not defined(js): - proc likelyProc(val: bool): bool {.importc: "NIM_LIKELY", nodecl, noSideEffect.} proc unlikelyProc(val: bool): bool {.importc: "NIM_UNLIKELY", nodecl, noSideEffect.} @@ -1831,13 +1942,13 @@ template likely*(val: bool): bool = ## You can use this template to decorate a branch condition. On certain ## platforms this can help the processor predict better which branch is ## going to be run. Example: - ## ``` + ## + ## .. code-block:: Nim ## for value in inputValues: ## if likely(value <= 100): ## process(value) ## else: ## echo "Value too big!" - ## ``` ## ## On backends without branch prediction (JS and the nimscript VM), this ## template will not affect code execution. @@ -1855,13 +1966,13 @@ template unlikely*(val: bool): bool = ## You can use this proc to decorate a branch condition. On certain ## platforms this can help the processor predict better which branch is ## going to be run. Example: - ## ``` + ## + ## .. code-block:: Nim ## for value in inputValues: ## if unlikely(value > 100): ## echo "Value too big!" ## else: ## process(value) - ## ``` ## ## On backends without branch prediction (JS and the nimscript VM), this ## template will not affect code execution. @@ -1873,67 +1984,46 @@ template unlikely*(val: bool): bool = else: unlikelyProc(val) + import system/dollars export dollars -when defined(nimAuditDelete): - {.pragma: auditDelete, deprecated: "review this call for out of bounds behavior".} -else: - {.pragma: auditDelete.} - -proc delete*[T](x: var seq[T], i: Natural) {.noSideEffect, auditDelete.} = - ## Deletes the item at index `i` by moving all `x[i+1..^1]` items by one position. - ## - ## This is an `O(n)` operation. - ## - ## .. note:: With `-d:nimStrictDelete`, an index error is produced when the index passed - ## to it was out of bounds. `-d:nimStrictDelete` will become the default - ## in upcoming versions. - ## - ## See also: - ## * `del <#del,seq[T],Natural>`_ for O(1) operation - ## - runnableExamples: - var s = @[1, 2, 3, 4, 5] - s.delete(2) - doAssert s == @[1, 2, 4, 5] - - when defined(nimStrictDelete): - if i > high(x): - # xxx this should call `raiseIndexError2(i, high(x))` after some refactoring - raise (ref IndexDefect)(msg: "index out of bounds: '" & $i & "' < '" & $x.len & "' failed") - - template defaultImpl = - let xl = x.len - for j in i.int..xl-2: movingCopy(x[j], x[j+1]) - setLen(x, xl-1) - - when nimvm: - defaultImpl() - else: - when defined(js): - {.emit: "`x`.splice(`i`, 1);".} - else: - defaultImpl() - - const + NimMajor* {.intdefine.}: int = 1 + ## is the major number of Nim's version. + + NimMinor* {.intdefine.}: int = 1 + ## is the minor number of Nim's version. + + NimPatch* {.intdefine.}: int = 1 + ## is the patch number of Nim's version. + NimVersion*: string = $NimMajor & "." & $NimMinor & "." & $NimPatch ## is the version of Nim as a string. + +type + FileSeekPos* = enum ## Position relative to which seek should happen. + # The values are ordered so that they match with stdio + # SEEK_SET, SEEK_CUR and SEEK_END respectively. + fspSet ## Seek to absolute value + fspCur ## Seek relative to current position + fspEnd ## Seek relative to end + + when not defined(js): {.push stackTrace: off, profiler: off.} when hasAlloc: when not defined(gcRegions) and not usesDestructors: - proc initGC() {.gcsafe, raises: [].} + proc initGC() {.gcsafe.} proc initStackBottom() {.inline, compilerproc.} = # WARNING: This is very fragile! An array size of 8 does not work on my # Linux 64bit system. -- That's because the stack direction is the other # way around. when declared(nimGC_setStackBottom): - var locals {.volatile, noinit.}: pointer + var locals {.volatile.}: pointer locals = addr(locals) nimGC_setStackBottom(locals) @@ -1972,17 +2062,19 @@ when notJSnotNims: memTrackerOp("moveMem", dest, size) proc equalMem(a, b: pointer, size: Natural): bool = nimCmpMem(a, b, size) == 0 - proc cmpMem(a, b: pointer, size: Natural): int = - nimCmpMem(a, b, size).int when not defined(js): proc cmp(x, y: string): int = - when nimvm: + when defined(nimscript): if x < y: result = -1 elif x > y: result = 1 else: result = 0 else: - when not defined(nimscript): # avoid semantic checking + when nimvm: + if x < y: result = -1 + elif x > y: result = 1 + else: result = 0 + else: let minlen = min(x.len, y.len) result = int(nimCmpMem(x.cstring, y.cstring, cast[csize_t](minlen))) if result == 0: @@ -1990,14 +2082,14 @@ when not defined(js): when declared(newSeq): proc cstringArrayToSeq*(a: cstringArray, len: Natural): seq[string] = - ## Converts a `cstringArray` to a `seq[string]`. `a` is supposed to be - ## of length `len`. + ## Converts a ``cstringArray`` to a ``seq[string]``. `a` is supposed to be + ## of length ``len``. newSeq(result, len) for i in 0..len-1: result[i] = $a[i] proc cstringArrayToSeq*(a: cstringArray): seq[string] = - ## Converts a `cstringArray` to a `seq[string]`. `a` is supposed to be - ## terminated by `nil`. + ## Converts a ``cstringArray`` to a ``seq[string]``. `a` is supposed to be + ## terminated by ``nil``. var L = 0 while a[L] != nil: inc(L) result = cstringArrayToSeq(a, L) @@ -2035,12 +2127,7 @@ when not defined(js): when declared(initAllocator): initAllocator() when hasThreadSupport: - when hostOS != "standalone": - include system/threadimpl - when not defined(nimPreviewSlimSystem): - import std/typedthreads - export typedthreads - + when hostOS != "standalone": include "system/threads" elif not defined(nogc) and not defined(nimscript): when not defined(useNimRtl) and not defined(createNimRtl): initStackBottom() when declared(initGC): initGC() @@ -2049,16 +2136,6 @@ when notJSnotNims: proc setControlCHook*(hook: proc () {.noconv.}) ## Allows you to override the behaviour of your application when CTRL+C ## is pressed. Only one such hook is supported. - ## Example: - ## - ## ``` - ## proc ctrlc() {.noconv.} = - ## echo "Ctrl+C fired!" - ## # do clean up stuff - ## quit() - ## - ## setControlCHook(ctrlc) - ## ``` when not defined(noSignalHandler) and not defined(useNimRtl): proc unsetControlCHook*() @@ -2070,7 +2147,7 @@ when notJSnotNims: proc getStackTrace*(e: ref Exception): string {.gcsafe.} ## Gets the stack trace associated with `e`, which is the stack that - ## lead to the `raise` statement. This only works for debug builds. + ## lead to the ``raise`` statement. This only works for debug builds. {.push stackTrace: off, profiler: off.} when defined(memtracker): @@ -2084,7 +2161,7 @@ when notJSnotNims: # we cannot compile this with stack tracing on # as it would recurse endlessly! - include "system/integerops" + include "system/arithm" {.pop.} @@ -2099,7 +2176,6 @@ when notJSnotNims: when hostOS != "standalone" and hostOS != "any": include "system/dyncalls" - import system/countbits_impl include "system/sets" when defined(gogc): @@ -2107,28 +2183,27 @@ when notJSnotNims: else: const GenericSeqSize = (2 * sizeof(int)) - proc getDiscriminant(aa: pointer, n: ptr TNimNode): uint = - sysAssert(n.kind == nkCase, "getDiscriminant: node != nkCase") - var d: uint - var a = cast[uint](aa) - case n.typ.size - of 1: d = uint(cast[ptr uint8](a + uint(n.offset))[]) - of 2: d = uint(cast[ptr uint16](a + uint(n.offset))[]) - of 4: d = uint(cast[ptr uint32](a + uint(n.offset))[]) - of 8: d = uint(cast[ptr uint64](a + uint(n.offset))[]) - else: - d = 0'u - sysAssert(false, "getDiscriminant: invalid n.typ.size") - return d + when not defined(nimV2): + proc getDiscriminant(aa: pointer, n: ptr TNimNode): uint = + sysAssert(n.kind == nkCase, "getDiscriminant: node != nkCase") + var d: uint + var a = cast[uint](aa) + case n.typ.size + of 1: d = uint(cast[ptr uint8](a + uint(n.offset))[]) + of 2: d = uint(cast[ptr uint16](a + uint(n.offset))[]) + of 4: d = uint(cast[ptr uint32](a + uint(n.offset))[]) + of 8: d = uint(cast[ptr uint64](a + uint(n.offset))[]) + else: sysAssert(false, "getDiscriminant: invalid n.typ.size") + return d - proc selectBranch(aa: pointer, n: ptr TNimNode): ptr TNimNode = - var discr = getDiscriminant(aa, n) - if discr < cast[uint](n.len): - result = n.sons[discr] - if result == nil: result = n.sons[n.len] - # n.sons[n.len] contains the `else` part (but may be nil) - else: - result = n.sons[n.len] + proc selectBranch(aa: pointer, n: ptr TNimNode): ptr TNimNode = + var discr = getDiscriminant(aa, n) + if discr < cast[uint](n.len): + result = n.sons[discr] + if result == nil: result = n.sons[n.len] + # n.sons[n.len] contains the ``else`` part (but may be nil) + else: + result = n.sons[n.len] when notJSnotNims and hasAlloc: {.push profiler: off.} @@ -2140,14 +2215,13 @@ when notJSnotNims and hasAlloc: {.pop.} include "system/strmantle" - include "system/assign" - + when not usesDestructors: + include "system/assign" when not defined(nimV2): include "system/repr" when notJSnotNims and hasThreadSupport and hostOS != "standalone": - when not defined(nimPreviewSlimSystem): - include "system/channels_builtin" + include "system/channels" when notJSnotNims and hostOS != "standalone": @@ -2168,10 +2242,9 @@ when notJSnotNims and hostOS != "standalone": proc setCurrentException*(exc: ref Exception) {.inline, benign.} = ## Sets the current exception. ## - ## .. warning:: Only use this if you know what you are doing. + ## **Warning**: Only use this if you know what you are doing. currException = exc -elif defined(nimscript): - proc getCurrentException*(): ref Exception {.compilerRtl.} = discard + when notJSnotNims: {.push stackTrace: off, profiler: off.} @@ -2181,105 +2254,43 @@ when notJSnotNims: proc rawProc*[T: proc](x: T): pointer {.noSideEffect, inline.} = ## Retrieves the raw proc pointer of the closure `x`. This is - ## useful for interfacing closures with C/C++, hash compuations, etc. - when T is "closure": - #[ - The conversion from function pointer to `void*` is a tricky topic, but this - should work at least for c++ >= c++11, e.g. for `dlsym` support. - refs: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=57869, - https://stackoverflow.com/questions/14125474/casts-between-pointer-to-function-and-pointer-to-object-in-c-and-c - ]# - {.emit: """ - `result` = (void*)`x`.ClP_0; - """.} - else: - {.error: "Only closure function and iterator are allowed!".} + ## useful for interfacing closures with C. + {.emit: """ + `result` = `x`.ClP_0; + """.} proc rawEnv*[T: proc](x: T): pointer {.noSideEffect, inline.} = - ## Retrieves the raw environment pointer of the closure `x`. See also `rawProc`. - when T is "closure": - {.emit: """ - `result` = `x`.ClE_0; - """.} - else: - {.error: "Only closure function and iterator are allowed!".} + ## Retrieves the raw environment pointer of the closure `x`. This is + ## useful for interfacing closures with C. + {.emit: """ + `result` = `x`.ClE_0; + """.} - proc finished*[T: proc](x: T): bool {.noSideEffect, inline, magic: "Finished".} = - ## It can be used to determine if a first class iterator has finished. - when T is "iterator": - {.emit: """ - `result` = ((NI*) `x`.ClE_0)[1] < 0; - """.} - else: - {.error: "Only closure iterator is allowed!".} - -from std/private/digitsutils import addInt -export addInt + proc finished*[T: proc](x: T): bool {.noSideEffect, inline.} = + ## can be used to determine if a first class iterator has finished. + {.emit: """ + `result` = ((NI*) `x`.ClE_0)[1] < 0; + """.} when defined(js): - include "system/jssys" - include "system/reprjs" + when not defined(nimscript): + include "system/jssys" + include "system/reprjs" + else: + proc cmp(x, y: string): int = + if x == y: return 0 + if x < y: return -1 + return 1 +when defined(js) or defined(nimscript): + proc addInt*(result: var string; x: int64) = + result.add $x -when defined(nimNoQuit): - proc quit*(errorcode: int = QuitSuccess) = discard "ignoring quit" - -elif defined(nimdoc): - proc quit*(errorcode: int = QuitSuccess) {.magic: "Exit", noreturn.} - ## Stops the program immediately with an exit code. - ## - ## Before stopping the program the "exit procedures" are called in the - ## opposite order they were added with `addExitProc `_. - ## - ## The proc `quit(QuitSuccess)` is called implicitly when your nim - ## program finishes without incident for platforms where this is the - ## expected behavior. A raised unhandled exception is - ## equivalent to calling `quit(QuitFailure)`. - ## - ## Note that this is a *runtime* call and using `quit` inside a macro won't - ## have any compile time effect. If you need to stop the compiler inside a - ## macro, use the `error `_ or `fatal - ## `_ pragmas. - ## - ## .. warning:: `errorcode` gets saturated when it exceeds the valid range - ## on the specific platform. On Posix, the valid range is `low(int8)..high(int8)`. - ## On Windows, the valid range is `low(int32)..high(int32)`. For instance, - ## `quit(int(0x100000000))` is equal to `quit(127)` on Linux. - ## - ## .. danger:: In almost all cases, in particular in library code, prefer - ## alternatives, e.g. `doAssert false` or raise a `Defect`. - ## `quit` bypasses regular control flow in particular `defer`, - ## `try`, `catch`, `finally` and `destructors`, and exceptions that may have been - ## raised by an `addExitProc` proc, as well as cleanup code in other threads. - ## It does *not* call the garbage collector to free all the memory, - ## unless an `addExitProc` proc calls `GC_fullCollect <#GC_fullCollect>`_. - -elif defined(genode): - proc quit*(errorcode: int = QuitSuccess) {.inline, noreturn.} = - rawQuit(errorcode) - -elif defined(js) and defined(nodejs) and not defined(nimscript): - proc quit*(errorcode: int = QuitSuccess) {.magic: "Exit", - importc: "process.exit", noreturn.} - -else: - proc quit*(errorcode: int = QuitSuccess) {.inline, noreturn.} = - when defined(posix): # posix uses low 8 bits - type ExitCodeRange = int8 - else: # win32 uses low 32 bits - type ExitCodeRange = cint - when sizeof(errorcode) > sizeof(ExitCodeRange): - if errorcode < low(ExitCodeRange): - rawQuit(low(ExitCodeRange).cint) - elif errorcode > high(ExitCodeRange): - rawQuit(high(ExitCodeRange).cint) - else: - rawQuit(errorcode.cint) - else: - rawQuit(errorcode.cint) + proc addFloat*(result: var string; x: float) = + result.add $x proc quit*(errormsg: string, errorcode = QuitFailure) {.noreturn.} = - ## A shorthand for `echo(errormsg); quit(errorcode)`. + ## A shorthand for ``echo(errormsg); quit(errorcode)``. when defined(nimscript) or defined(js) or (hostOS == "standalone"): echo errormsg else: @@ -2291,57 +2302,312 @@ proc quit*(errormsg: string, errorcode = QuitFailure) {.noreturn.} = quit(errorcode) {.pop.} # checks: off -# {.pop.} # hints: off +{.pop.} # hints: off -include "system/indices" +proc `/`*(x, y: int): float {.inline, noSideEffect.} = + ## Division of integers that results in a float. + ## + ## See also: + ## * `div <#div,int,int>`_ + ## * `mod <#mod,int,int>`_ + ## + ## .. code-block:: Nim + ## echo 7 / 5 # => 1.4 + result = toFloat(x) / toFloat(y) + +type + BackwardsIndex* = distinct int ## Type that is constructed by ``^`` for + ## reversed array accesses. + ## (See `^ template <#^.t,int>`_) + +template `^`*(x: int): BackwardsIndex = BackwardsIndex(x) + ## Builtin `roof`:idx: operator that can be used for convenient array access. + ## ``a[^x]`` is a shortcut for ``a[a.len-x]``. + ## + ## .. code-block:: Nim + ## let + ## a = [1, 3, 5, 7, 9] + ## b = "abcdefgh" + ## + ## echo a[^1] # => 9 + ## echo b[^2] # => g + +template `..^`*(a, b: untyped): untyped = + ## A shortcut for `.. ^` to avoid the common gotcha that a space between + ## '..' and '^' is required. + a .. ^b + +template `..<`*(a, b: untyped): untyped = + ## A shortcut for `a .. pred(b)`. + ## + ## .. code-block:: Nim + ## for i in 5 ..< 9: + ## echo i # => 5; 6; 7; 8 + a .. (when b is BackwardsIndex: succ(b) else: pred(b)) + +template spliceImpl(s, a, L, b: untyped): untyped = + # make room for additional elements or cut: + var shift = b.len - max(0,L) # ignore negative slice size + var newLen = s.len + shift + if shift > 0: + # enlarge: + setLen(s, newLen) + for i in countdown(newLen-1, a+b.len): movingCopy(s[i], s[i-shift]) + else: + for i in countup(a+b.len, newLen-1): movingCopy(s[i], s[i-shift]) + # cut down: + setLen(s, newLen) + # fill the hole: + for i in 0 ..< b.len: s[a+i] = b[i] + +template `^^`(s, i: untyped): untyped = + (when i is BackwardsIndex: s.len - int(i) else: int(i)) + +template `[]`*(s: string; i: int): char = arrGet(s, i) +template `[]=`*(s: string; i: int; val: char) = arrPut(s, i, val) + +proc `[]`*[T, U](s: string, x: HSlice[T, U]): string {.inline.} = + ## Slice operation for strings. + ## Returns the inclusive range `[s[x.a], s[x.b]]`: + ## + ## .. code-block:: Nim + ## var s = "abcdef" + ## assert s[1..3] == "bcd" + let a = s ^^ x.a + let L = (s ^^ x.b) - a + 1 + result = newString(L) + for i in 0 ..< L: result[i] = s[i + a] + +proc `[]=`*[T, U](s: var string, x: HSlice[T, U], b: string) = + ## Slice assignment for strings. + ## + ## If ``b.len`` is not exactly the number of elements that are referred to + ## by `x`, a `splice`:idx: is performed: + ## + runnableExamples: + var s = "abcdefgh" + s[1 .. ^2] = "xyz" + assert s == "axyzh" + + var a = s ^^ x.a + var L = (s ^^ x.b) - a + 1 + if L == b.len: + for i in 0..`_. + +proc staticRead*(filename: string): string {.magic: "Slurp".} + ## Compile-time `readFile `_ proc for easy + ## `resource`:idx: embedding: + ## + ## .. code-block:: Nim + ## const myResource = staticRead"mydatafile.bin" + ## + ## `slurp <#slurp,string>`_ is an alias for ``staticRead``. + +proc gorge*(command: string, input = "", cache = ""): string {. + magic: "StaticExec".} = discard + ## This is an alias for `staticExec <#staticExec,string,string,string>`_. + +proc staticExec*(command: string, input = "", cache = ""): string {. + magic: "StaticExec".} = discard + ## Executes an external process at compile-time and returns its text output + ## (stdout + stderr). + ## + ## If `input` is not an empty string, it will be passed as a standard input + ## to the executed program. + ## + ## .. code-block:: Nim + ## const buildInfo = "Revision " & staticExec("git rev-parse HEAD") & + ## "\nCompiled on " & staticExec("uname -v") + ## + ## `gorge <#gorge,string,string,string>`_ is an alias for ``staticExec``. + ## + ## Note that you can use this proc inside a pragma like + ## `passc `_ or + ## `passl `_. + ## + ## If ``cache`` is not empty, the results of ``staticExec`` are cached within + ## the ``nimcache`` directory. Use ``--forceBuild`` to get rid of this caching + ## behaviour then. ``command & input & cache`` (the concatenated string) is + ## used to determine whether the entry in the cache is still valid. You can + ## use versioning information for ``cache``: + ## + ## .. code-block:: Nim + ## const stateMachine = staticExec("dfaoptimizer", "input", "0.8.0") + +proc gorgeEx*(command: string, input = "", cache = ""): tuple[output: string, + exitCode: int] = + ## Similar to `gorge <#gorge,string,string,string>`_ but also returns the + ## precious exit code. + discard + + +proc `+=`*[T: float|float32|float64] (x: var T, y: T) {. + inline, noSideEffect.} = + ## Increments in place a floating point number. + x = x + y + +proc `-=`*[T: float|float32|float64] (x: var T, y: T) {. + inline, noSideEffect.} = + ## Decrements in place a floating point number. + x = x - y + +proc `*=`*[T: float|float32|float64] (x: var T, y: T) {. + inline, noSideEffect.} = + ## Multiplies in place a floating point number. + x = x * y + +proc `/=`*(x: var float64, y: float64) {.inline, noSideEffect.} = + ## Divides in place a floating point number. + x = x / y + +proc `/=`*[T: float|float32](x: var T, y: T) {.inline, noSideEffect.} = + ## Divides in place a floating point number. + x = x / y proc `&=`*(x: var string, y: string) {.magic: "AppendStrStr", noSideEffect.} ## Appends in place to a string. - ## ``` + ## + ## .. code-block:: Nim ## var a = "abc" ## a &= "de" # a <- "abcde" - ## ``` template `&=`*(x, y: typed) = ## Generic 'sink' operator for Nim. ## - ## If not specialized further, an alias for `add`. + ## For files an alias for ``write``. + ## If not specialized further, an alias for ``add``. add(x, y) +when declared(File): + template `&=`*(f: File, x: typed) = write(f, x) + +template currentSourcePath*: string = instantiationInfo(-1, true).filename + ## Returns the full file-system path of the current source. + ## + ## To get the directory containing the current source, use it with + ## `os.parentDir() `_ as ``currentSourcePath.parentDir()``. + ## + ## The path returned by this template is set at compile time. + ## + ## See the docstring of `macros.getProjectPath() `_ + ## for an example to see the distinction between the ``currentSourcePath`` + ## and ``getProjectPath``. + ## + ## See also: + ## * `getCurrentDir proc `_ when compileOption("rangechecks"): template rangeCheck*(cond) = ## Helper for performing user-defined range checks. - ## Such checks will be performed only when the `rangechecks` + ## Such checks will be performed only when the ``rangechecks`` ## compile-time option is enabled. - if not cond: sysFatal(RangeDefect, "range check failed") + if not cond: sysFatal(RangeError, "range check failed") else: template rangeCheck*(cond) = discard -when not defined(gcArc) and not defined(gcOrc): - proc shallow*[T](s: var seq[T]) {.noSideEffect, inline.} = - ## Marks a sequence `s` as `shallow`:idx:. Subsequent assignments will not - ## perform deep copies of `s`. - ## - ## This is only useful for optimization purposes. - if s.len == 0: return - when not defined(js) and not defined(nimscript) and not defined(nimSeqsV2): - var s = cast[PGenericSeq](s) - {.noSideEffect.}: - s.reserved = s.reserved or seqShallowFlag +when not defined(nimhygiene): + {.pragma: inject.} - proc shallow*(s: var string) {.noSideEffect, inline.} = - ## Marks a string `s` as `shallow`:idx:. Subsequent assignments will not - ## perform deep copies of `s`. - ## - ## This is only useful for optimization purposes. - when not defined(js) and not defined(nimscript) and not defined(nimSeqsV2): - var s = cast[PGenericSeq](s) - if s == nil: - s = cast[PGenericSeq](newString(0)) - # string literals cannot become 'shallow': - if (s.reserved and strlitFlag) == 0: - {.noSideEffect.}: - s.reserved = s.reserved or seqShallowFlag +proc shallow*[T](s: var seq[T]) {.noSideEffect, inline.} = + ## Marks a sequence `s` as `shallow`:idx:. Subsequent assignments will not + ## perform deep copies of `s`. + ## + ## This is only useful for optimization purposes. + if s.len == 0: return + when not defined(js) and not defined(nimscript) and not defined(nimSeqsV2): + var s = cast[PGenericSeq](s) + s.reserved = s.reserved or seqShallowFlag + +proc shallow*(s: var string) {.noSideEffect, inline.} = + ## Marks a string `s` as `shallow`:idx:. Subsequent assignments will not + ## perform deep copies of `s`. + ## + ## This is only useful for optimization purposes. + when not defined(js) and not defined(nimscript) and not defined(nimSeqsV2): + var s = cast[PGenericSeq](s) + if s == nil: + s = cast[PGenericSeq](newString(0)) + # string literals cannot become 'shallow': + if (s.reserved and strlitFlag) == 0: + s.reserved = s.reserved or seqShallowFlag type NimNodeObj = object @@ -2349,35 +2615,36 @@ type NimNode* {.magic: "PNimrodNode".} = ref NimNodeObj ## Represents a Nim AST node. Macros operate on this type. -type - ForLoopStmt* {.compilerproc.} = object ## \ - ## A special type that marks a macro as a `for-loop macro`:idx:. - ## See `"For Loop Macro" `_. - -macro varargsLen*(x: varargs[untyped]): int {.since: (1, 1).} = - ## returns number of variadic arguments in `x` - proc varargsLenImpl(x: NimNode): NimNode {.magic: "LengthOpenArray", noSideEffect.} - varargsLenImpl(x) - when defined(nimV2): import system/repr_v2 export repr_v2 +macro lenVarargs*(x: varargs[untyped]): int {.since: (1, 1).} = + ## returns number of variadic arguments in `x` + proc lenVarargsImpl(x: NimNode): NimNode {.magic: "LengthOpenArray", noSideEffect.} + lenVarargsImpl(x) + +when false: + template eval*(blk: typed): typed = + ## Executes a block of code at compile time just as if it was a macro. + ## + ## Optionally, the block can return an AST tree that will replace the + ## eval expression. + macro payload: typed {.gensym.} = blk + payload() + when hasAlloc or defined(nimscript): proc insert*(x: var string, item: string, i = 0.Natural) {.noSideEffect.} = ## Inserts `item` into `x` at position `i`. - ## ``` + ## + ## .. code-block:: Nim ## var a = "abc" ## a.insert("zz", 0) # a <- "zzabc" - ## ``` var xl = x.len setLen(x, xl+item.len) var j = xl-1 while j >= i: - when defined(gcArc) or defined(gcOrc): - x[j+item.len] = move x[j] - else: - shallowCopy(x[j+item.len], x[j]) + shallowCopy(x[j+item.len], x[j]) dec(j) j = 0 while j < item.len: @@ -2390,33 +2657,32 @@ when declared(initDebugger): proc addEscapedChar*(s: var string, c: char) {.noSideEffect, inline.} = ## Adds a char to string `s` and applies the following escaping: ## - ## * replaces any ``\`` by `\\` - ## * replaces any `'` by `\'` - ## * replaces any `"` by `\"` - ## * replaces any `\a` by `\\a` - ## * replaces any `\b` by `\\b` - ## * replaces any `\t` by `\\t` - ## * replaces any `\n` by `\\n` - ## * replaces any `\v` by `\\v` - ## * replaces any `\f` by `\\f` - ## * replaces any `\r` by `\\r` - ## * replaces any `\e` by `\\e` - ## * replaces any other character not in the set `{\21..\126}` - ## by `\xHH` where `HH` is its hexadecimal value + ## * replaces any ``\`` by ``\\`` + ## * replaces any ``'`` by ``\'`` + ## * replaces any ``"`` by ``\"`` + ## * replaces any ``\a`` by ``\\a`` + ## * replaces any ``\b`` by ``\\b`` + ## * replaces any ``\t`` by ``\\t`` + ## * replaces any ``\n`` by ``\\n`` + ## * replaces any ``\v`` by ``\\v`` + ## * replaces any ``\f`` by ``\\f`` + ## * replaces any ``\c`` by ``\\c`` + ## * replaces any ``\e`` by ``\\e`` + ## * replaces any other character not in the set ``{'\21..'\126'} + ## by ``\xHH`` where ``HH`` is its hexadecimal value. ## ## The procedure has been designed so that its output is usable for many ## different common syntaxes. ## - ## .. warning:: This is **not correct** for producing ANSI C code! - ## + ## **Note**: This is **not correct** for producing Ansi C code! case c of '\a': s.add "\\a" # \x07 of '\b': s.add "\\b" # \x08 of '\t': s.add "\\t" # \x09 - of '\n': s.add "\\n" # \x0A + of '\L': s.add "\\n" # \x0A of '\v': s.add "\\v" # \x0B of '\f': s.add "\\f" # \x0C - of '\r': (when defined(nimLegacyAddEscapedCharx0D): s.add "\\c" else: s.add "\\r") # \x0D + of '\c': s.add "\\c" # \x0D of '\e': s.add "\\e" # \x1B of '\\': s.add("\\\\") of '\'': s.add("\\'") @@ -2435,9 +2701,9 @@ proc addQuoted*[T](s: var string, x: T) = ## ## See `addEscapedChar <#addEscapedChar,string,char>`_ ## for the escaping scheme. When `x` is a string, characters in the - ## range `{\128..\255}` are never escaped so that multibyte UTF-8 + ## range ``{\128..\255}`` are never escaped so that multibyte UTF-8 ## characters are untouched (note that this behavior is different from - ## `addEscapedChar`). + ## ``addEscapedChar``). ## ## The Nim standard library uses this function on the elements of ## collections when producing a string representation of a collection. @@ -2445,7 +2711,7 @@ proc addQuoted*[T](s: var string, x: T) = ## Users may overload `addQuoted` for custom (string-like) types if ## they want to implement a customized element representation. ## - ## ``` + ## .. code-block:: Nim ## var tmp = "" ## tmp.addQuoted(1) ## tmp.add(", ") @@ -2453,7 +2719,6 @@ proc addQuoted*[T](s: var string, x: T) = ## tmp.add(", ") ## tmp.addQuoted('c') ## assert(tmp == """1, "string", 'c'""") - ## ``` when T is string or T is cstring: s.add("\"") for c in x: @@ -2469,7 +2734,7 @@ proc addQuoted*[T](s: var string, x: T) = s.addEscapedChar(x) s.add("'") # prevent temporary string allocation - elif T is SomeInteger: + elif T is SomeSignedInt: s.addInt(x) elif T is SomeFloat: s.addFloat(x) @@ -2484,10 +2749,10 @@ proc locals*(): RootObj {.magic: "Plugin", noSideEffect.} = ## ## This is quite fast as it does not rely ## on any debug or runtime information. Note that in contrast to what - ## the official signature says, the return type is *not* `RootObj` but a + ## the official signature says, the return type is *not* ``RootObj`` but a ## tuple of a structure that depends on the current scope. Example: ## - ## ``` + ## .. code-block:: Nim ## proc testLocals() = ## var ## a = "something" @@ -2502,19 +2767,15 @@ proc locals*(): RootObj {.magic: "Plugin", noSideEffect.} = ## # -> name a with value something ## # -> name b with value 4 ## # -> B is 1 - ## ``` discard -when hasAlloc and notJSnotNims: +when hasAlloc and notJSnotNims and not usesDestructors: # XXX how to implement 'deepCopy' is an open problem. proc deepCopy*[T](x: var T, y: T) {.noSideEffect, magic: "DeepCopy".} = ## Performs a deep copy of `y` and copies it into `x`. ## ## This is also used by the code generator - ## for the implementation of `spawn`. - ## - ## For `--gc:arc` or `--gc:orc` deepcopy support has to be enabled - ## via `--deepcopy:on`. + ## for the implementation of ``spawn``. discard proc deepCopy*[T](y: T): T = @@ -2526,10 +2787,10 @@ when hasAlloc and notJSnotNims: proc procCall*(x: untyped) {.magic: "ProcCall", compileTime.} = ## Special magic to prohibit dynamic binding for `method`:idx: calls. ## This is similar to `super`:idx: in ordinary OO languages. - ## ``` + ## + ## .. code-block:: Nim ## # 'someMethod' will be resolved fully statically: ## procCall someMethod(a, b) - ## ``` discard @@ -2542,16 +2803,30 @@ proc `==`*(x, y: cstring): bool {.magic: "EqCString", noSideEffect, elif x.isNil or y.isNil: result = false else: result = strcmp(x, y) == 0 +when defined(nimNoNilSeqs2) and not compileOption("nilseqs"): + when defined(nimHasUserErrors): + # bug #9149; ensure that 'type(nil)' does not match *too* well by using 'type(nil) | type(nil)'. + # Eventually (in 0.20?) we will be able to remove this hack completely. + proc `==`*(x: string; y: type(nil) | type(nil)): bool {. + error: "'nil' is now invalid for 'string'; compile with --nilseqs:on for a migration period".} = + discard + proc `==`*(x: type(nil) | type(nil); y: string): bool {. + error: "'nil' is now invalid for 'string'; compile with --nilseqs:on for a migration period".} = + discard + else: + proc `==`*(x: string; y: type(nil) | type(nil)): bool {.error.} = discard + proc `==`*(x: type(nil) | type(nil); y: string): bool {.error.} = discard + template closureScope*(body: untyped): untyped = ## Useful when creating a closure in a loop to capture local loop variables by ## their current iteration values. ## ## Note: This template may not work in some cases, use - ## `capture `_ instead. + ## `capture `_ instead. ## ## Example: ## - ## ``` + ## .. code-block:: Nim ## var myClosure : proc() ## # without closureScope: ## for i in 0 .. 5: @@ -2566,19 +2841,20 @@ template closureScope*(body: untyped): untyped = ## if j == 3: ## myClosure = proc() = echo j ## myClosure() # outputs 3 - ## ``` (proc() = body)() template once*(body: untyped): untyped = ## Executes a block of code only once (the first time the block is reached). - ## ``` - ## proc draw(t: Triangle) = - ## once: - ## graphicsInit() - ## line(t.p1, t.p2) - ## line(t.p2, t.p3) - ## line(t.p3, t.p1) - ## ``` + ## + ## .. code-block:: Nim + ## + ## proc draw(t: Triangle) = + ## once: + ## graphicsInit() + ## line(t.p1, t.p2) + ## line(t.p2, t.p3) + ## line(t.p3, t.p1) + ## var alreadyExecuted {.global.} = false if not alreadyExecuted: alreadyExecuted = true @@ -2586,26 +2862,14 @@ template once*(body: untyped): untyped = {.pop.} # warning[GcMem]: off, warning[Uninit]: off -proc substr*(s: openArray[char]): string = - ## Copies a slice of `s` into a new string and returns this new - ## string. - runnableExamples: - let a = "abcdefgh" - assert a.substr(2, 5) == "cdef" - assert a.substr(2) == "cdefgh" - assert a.substr(5, 99) == "fgh" - result = newString(s.len) - for i, ch in s: - result[i] = ch - -proc substr*(s: string, first, last: int): string = # A bug with `magic: Slice` requires this to exist this way +proc substr*(s: string, first, last: int): string = ## Copies a slice of `s` into a new string and returns this new ## string. ## ## The bounds `first` and `last` denote the indices of - ## the first and last characters that shall be copied. If `last` - ## is omitted, it is treated as `high(s)`. If `last >= s.len`, `s.len` - ## is used instead: This means `substr` can also be used to `cut`:idx: + ## the first and last characters that shall be copied. If ``last`` + ## is omitted, it is treated as ``high(s)``. If ``last >= s.len``, ``s.len`` + ## is used instead: This means ``substr`` can also be used to `cut`:idx: ## or `limit`:idx: a string's length. runnableExamples: let a = "abcdefgh" @@ -2628,10 +2892,11 @@ when defined(nimconfig): when not defined(js): proc toOpenArray*[T](x: ptr UncheckedArray[T]; first, last: int): openArray[T] {. magic: "Slice".} - proc toOpenArray*(x: cstring; first, last: int): openArray[char] {. - magic: "Slice".} - proc toOpenArrayByte*(x: cstring; first, last: int): openArray[byte] {. - magic: "Slice".} + when defined(nimToOpenArrayCString): + proc toOpenArray*(x: cstring; first, last: int): openArray[char] {. + magic: "Slice".} + proc toOpenArrayByte*(x: cstring; first, last: int): openArray[byte] {. + magic: "Slice".} proc toOpenArray*[T](x: seq[T]; first, last: int): openArray[T] {. magic: "Slice".} @@ -2649,19 +2914,24 @@ proc toOpenArrayByte*(x: openArray[char]; first, last: int): openArray[byte] {. proc toOpenArrayByte*(x: seq[char]; first, last: int): openArray[byte] {. magic: "Slice".} +type + ForLoopStmt* {.compilerproc.} = object ## \ + ## A special type that marks a macro as a `for-loop macro`:idx:. + ## See `"For Loop Macro" `_. + when defined(genode): var componentConstructHook*: proc (env: GenodeEnv) {.nimcall.} ## Hook into the Genode component bootstrap process. ## ## This hook is called after all globals are initialized. ## When this hook is set the component will not automatically exit, - ## call `quit` explicitly to do so. This is the only available method + ## call ``quit`` explicitly to do so. This is the only available method ## of accessing the initial Genode environment. proc nim_component_construct(env: GenodeEnv) {.exportc.} = - ## Procedure called during `Component::construct` by the loader. + ## Procedure called during ``Component::construct`` by the loader. if componentConstructHook.isNil: - env.rawQuit(programResult) + env.quit(programResult) # No native Genode application initialization, # exit as would POSIX. else: @@ -2670,104 +2940,11 @@ when defined(genode): # and return to thread entrypoint. -when not defined(nimPreviewSlimSystem): - import std/widestrs - export widestrs +import system/widestrs +export widestrs -when notJSnotNims: - when defined(windows) and compileOption("threads"): - when not declared(addSysExitProc): - proc addSysExitProc(quitProc: proc() {.noconv.}) {.importc: "atexit", header: "".} - var echoLock: SysLock - initSysLock echoLock - addSysExitProc(proc() {.noconv.} = deinitSys(echoLock)) +import system/io +export io - const stdOutLock = compileOption("threads") and - not defined(windows) and - not defined(android) and - not defined(nintendoswitch) and - not defined(freertos) and - not defined(zephyr) and - not defined(nuttx) and - hostOS != "any" - - proc raiseEIO(msg: string) {.noinline, noreturn.} = - sysFatal(IOError, msg) - - proc echoBinSafe(args: openArray[string]) {.compilerproc.} = - when defined(androidNDK): - # When running nim in android app, stdout goes nowhere, so echo gets ignored - # To redirect echo to the android logcat, use -d:androidNDK - const ANDROID_LOG_VERBOSE = 2.cint - proc android_log_print(prio: cint, tag: cstring, fmt: cstring): cint - {.importc: "__android_log_print", header: "", varargs, discardable.} - var s = "" - for arg in args: - s.add arg - android_log_print(ANDROID_LOG_VERBOSE, "nim", s) - else: - # flockfile deadlocks some versions of Android 5.x.x - when stdOutLock: - proc flockfile(f: CFilePtr) {.importc, nodecl.} - proc funlockfile(f: CFilePtr) {.importc, nodecl.} - flockfile(cstdout) - when defined(windows) and compileOption("threads"): - acquireSys echoLock - for s in args: - when defined(windows): - # equivalent to syncio.writeWindows - proc writeWindows(f: CFilePtr; s: string; doRaise = false) = - # Don't ask why but the 'printf' family of function is the only thing - # that writes utf-8 strings reliably on Windows. At least on my Win 10 - # machine. We also enable `setConsoleOutputCP(65001)` now by default. - # But we cannot call printf directly as the string might contain \0. - # So we have to loop over all the sections separated by potential \0s. - var i = c_fprintf(f, "%s", s) - while i < s.len: - if s[i] == '\0': - let w = c_fputc('\0', f) - if w != 0: - if doRaise: raiseEIO("cannot write string to file") - break - inc i - else: - let w = c_fprintf(f, "%s", unsafeAddr s[i]) - if w <= 0: - if doRaise: raiseEIO("cannot write string to file") - break - inc i, w - writeWindows(cstdout, s) - else: - discard c_fwrite(s.cstring, cast[csize_t](s.len), 1, cstdout) - const linefeed = "\n" - discard c_fwrite(linefeed.cstring, linefeed.len, 1, cstdout) - discard c_fflush(cstdout) - when stdOutLock: - funlockfile(cstdout) - when defined(windows) and compileOption("threads"): - releaseSys echoLock - -when not defined(nimPreviewSlimSystem): - import std/syncio - export syncio - -when not defined(createNimHcr) and not defined(nimscript): +when not defined(createNimHcr): include nimhcr - -when notJSnotNims and not defined(nimSeqsV2): - proc prepareMutation*(s: var string) {.inline.} = - ## String literals (e.g. "abc", etc) in the ARC/ORC mode are "copy on write", - ## therefore you should call `prepareMutation` before modifying the strings - ## via `addr`. - runnableExamples("--gc:arc"): - var x = "abc" - var y = "defgh" - prepareMutation(y) # without this, you may get a `SIGBUS` or `SIGSEGV` - moveMem(addr y[0], addr x[0], x.len) - assert y == "abcgh" - discard - -proc nimArrayWith[T](y: T, size: static int): array[size, T] {.compilerRtl, raises: [].} = - ## Creates a new array filled with `y`. - for i in 0..size-1: - result[i] = y diff --git a/lib/system/alloc.nim b/lib/system/alloc.nim index cee70f677..95d5ae7ee 100644 --- a/lib/system/alloc.nim +++ b/lib/system/alloc.nim @@ -11,8 +11,6 @@ {.push profiler:off.} include osalloc -import std/private/syslocks -import std/sysatomics template track(op, address, size) = when defined(memTracker): @@ -24,7 +22,7 @@ template track(op, address, size) = const nimMinHeapPages {.intdefine.} = 128 # 0.5 MB SmallChunkSize = PageSize - MaxFli = when sizeof(int) > 2: 30 else: 14 + MaxFli = 30 MaxLog2Sli = 5 # 32, this cannot be increased without changing 'uint32' # everywhere! MaxSli = 1 shl MaxLog2Sli @@ -32,7 +30,7 @@ const RealFli = MaxFli - FliOffset # size of chunks in last matrix bin - MaxBigChunkSize = int(1'i32 shl MaxFli - 1'i32 shl (MaxFli-MaxLog2Sli-1)) + MaxBigChunkSize = 1 shl MaxFli - 1 shl (MaxFli-MaxLog2Sli-1) HugeChunkSize = MaxBigChunkSize + 1 type @@ -46,6 +44,41 @@ type IntSet = object data: TrunkBuckets +type + AlignType = BiggestFloat + FreeCell {.final, pure.} = object + next: ptr FreeCell # next free cell in chunk (overlaid with refcount) + when not defined(gcDestructors): + zeroField: int # 0 means cell is not used (overlaid with typ field) + # 1 means cell is manually managed pointer + # otherwise a PNimType is stored in there + else: + alignment: int + + PChunk = ptr BaseChunk + PBigChunk = ptr BigChunk + PSmallChunk = ptr SmallChunk + BaseChunk {.pure, inheritable.} = object + prevSize: int # size of previous chunk; for coalescing + # 0th bit == 1 if 'used + size: int # if < PageSize it is a small chunk + + SmallChunk = object of BaseChunk + next, prev: PSmallChunk # chunks of the same size + freeList: ptr FreeCell + free: int # how many bytes remain + acc: int # accumulator for small object allocation + when defined(cpu32): + align: int + data: AlignType # start of usable memory + + BigChunk = object of BaseChunk # not necessarily > PageSize! + next, prev: PBigChunk # chunks of the same (or bigger) size + data: AlignType # start of usable memory + +template smallChunkOverhead(): untyped = sizeof(SmallChunk)-sizeof(AlignType) +template bigChunkOverhead(): untyped = sizeof(BigChunk)-sizeof(AlignType) + # ------------- chunk table --------------------------------------------------- # We use a PtrSet of chunk starts and a table[Page, chunksize] for chunk # endings of big chunks. This is needed by the merging operation. The only @@ -66,90 +99,29 @@ type key, upperBound: int level: int -const - RegionHasLock = false # hasThreadSupport and defined(gcDestructors) - -type - FreeCell {.final, pure.} = object - next: ptr FreeCell # next free cell in chunk (overlaid with refcount) - when not defined(gcDestructors): - zeroField: int # 0 means cell is not used (overlaid with typ field) - # 1 means cell is manually managed pointer - # otherwise a PNimType is stored in there - else: - alignment: int - - PChunk = ptr BaseChunk - PBigChunk = ptr BigChunk - PSmallChunk = ptr SmallChunk - BaseChunk {.pure, inheritable.} = object - prevSize: int # size of previous chunk; for coalescing - # 0th bit == 1 if 'used - size: int # if < PageSize it is a small chunk - owner: ptr MemRegion - - SmallChunk = object of BaseChunk - next, prev: PSmallChunk # chunks of the same size - freeList: ptr FreeCell - free: int # how many bytes remain - acc: int # accumulator for small object allocation - when defined(gcDestructors): - sharedFreeList: ptr FreeCell # make no attempt at avoiding false sharing for now for this object field - data {.align: MemAlign.}: UncheckedArray[byte] # start of usable memory - - BigChunk = object of BaseChunk # not necessarily > PageSize! - next, prev: PBigChunk # chunks of the same (or bigger) size - data {.align: MemAlign.}: UncheckedArray[byte] # start of usable memory - HeapLinks = object len: int chunks: array[30, (PBigChunk, int)] next: ptr HeapLinks MemRegion = object - when not defined(gcDestructors): - minLargeObj, maxLargeObj: int - freeSmallChunks: array[0..max(1,SmallChunkSize div MemAlign-1), PSmallChunk] + minLargeObj, maxLargeObj: int + freeSmallChunks: array[0..SmallChunkSize div MemAlign-1, PSmallChunk] flBitmap: uint32 slBitmap: array[RealFli, uint32] matrix: array[RealFli, array[MaxSli, PBigChunk]] llmem: PLLChunk currMem, maxMem, freeMem, occ: int # memory sizes (allocated from OS) lastSize: int # needed for the case that OS gives us pages linearly - when RegionHasLock: - lock: SysLock - when defined(gcDestructors): - sharedFreeListBigChunks: PBigChunk # make no attempt at avoiding false sharing for now for this object field - chunkStarts: IntSet - when not defined(gcDestructors): - root, deleted, last, freeAvlNodes: PAvlNode - lockActive, locked, blockChunkSizeIncrease: bool # if locked, we cannot free pages. + root, deleted, last, freeAvlNodes: PAvlNode + locked, blockChunkSizeIncrease: bool # if locked, we cannot free pages. nextChunkSize: int - when not defined(gcDestructors): - bottomData: AvlNode + bottomData: AvlNode heapLinks: HeapLinks when defined(nimTypeNames): allocCounter, deallocCounter: int -template smallChunkOverhead(): untyped = sizeof(SmallChunk) -template bigChunkOverhead(): untyped = sizeof(BigChunk) - -when hasThreadSupport: - template loada(x: untyped): untyped = atomicLoadN(unsafeAddr x, ATOMIC_RELAXED) - template storea(x, y: untyped) = atomicStoreN(unsafeAddr x, y, ATOMIC_RELAXED) - - when false: - # not yet required - template atomicStatDec(x, diff: untyped) = discard atomicSubFetch(unsafeAddr x, diff, ATOMIC_RELAXED) - template atomicStatInc(x, diff: untyped) = discard atomicAddFetch(unsafeAddr x, diff, ATOMIC_RELAXED) -else: - template loada(x: untyped): untyped = x - template storea(x, y: untyped) = x = y - -template atomicStatDec(x, diff: untyped) = dec x, diff -template atomicStatInc(x, diff: untyped) = inc x, diff - const fsLookupTable: array[byte, int8] = [ -1'i8, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, @@ -190,7 +162,7 @@ proc mappingSearch(r, fl, sl: var int) {.inline.} = let t = roundup((1 shl (msbit(uint32 r) - MaxLog2Sli)), PageSize) - 1 r = r + t r = r and not t - r = min(r, MaxBigChunkSize).int + r = min(r, MaxBigChunkSize) fl = msbit(uint32 r) sl = (r shr (fl - MaxLog2Sli)) - MaxSli dec fl, FliOffset @@ -256,11 +228,11 @@ proc addChunkToMatrix(a: var MemRegion; b: PBigChunk) = setBit(fl, a.flBitmap) proc incCurrMem(a: var MemRegion, bytes: int) {.inline.} = - atomicStatInc(a.currMem, bytes) + inc(a.currMem, bytes) proc decCurrMem(a: var MemRegion, bytes: int) {.inline.} = a.maxMem = max(a.maxMem, a.currMem) - atomicStatDec(a.currMem, bytes) + dec(a.currMem, bytes) proc getMaxMem(a: var MemRegion): int = # Since we update maxPagesCount only when freeing pages, @@ -278,47 +250,46 @@ proc llAlloc(a: var MemRegion, size: int): pointer = sysAssert roundup(size+sizeof(LLChunk), PageSize) == PageSize, "roundup 6" var old = a.llmem # can be nil and is correct with nil a.llmem = cast[PLLChunk](osAllocPages(PageSize)) - when defined(nimAvlcorruption): + when defined(avlcorruption): trackLocation(a.llmem, PageSize) incCurrMem(a, PageSize) a.llmem.size = PageSize - sizeof(LLChunk) a.llmem.acc = sizeof(LLChunk) a.llmem.next = old - result = cast[pointer](cast[int](a.llmem) + a.llmem.acc) + result = cast[pointer](cast[ByteAddress](a.llmem) + a.llmem.acc) dec(a.llmem.size, size) inc(a.llmem.acc, size) zeroMem(result, size) -when not defined(gcDestructors): - proc getBottom(a: var MemRegion): PAvlNode = - result = addr(a.bottomData) - if result.link[0] == nil: - result.link[0] = result - result.link[1] = result +proc getBottom(a: var MemRegion): PAvlNode = + result = addr(a.bottomData) + if result.link[0] == nil: + result.link[0] = result + result.link[1] = result - proc allocAvlNode(a: var MemRegion, key, upperBound: int): PAvlNode = - if a.freeAvlNodes != nil: - result = a.freeAvlNodes - a.freeAvlNodes = a.freeAvlNodes.link[0] - else: - result = cast[PAvlNode](llAlloc(a, sizeof(AvlNode))) - when defined(nimAvlcorruption): - cprintf("tracking location: %p\n", result) - result.key = key - result.upperBound = upperBound - let bottom = getBottom(a) - result.link[0] = bottom - result.link[1] = bottom - result.level = 1 - #when defined(nimAvlcorruption): - # track("allocAvlNode", result, sizeof(AvlNode)) - sysAssert(bottom == addr(a.bottomData), "bottom data") - sysAssert(bottom.link[0] == bottom, "bottom link[0]") - sysAssert(bottom.link[1] == bottom, "bottom link[1]") +proc allocAvlNode(a: var MemRegion, key, upperBound: int): PAvlNode = + if a.freeAvlNodes != nil: + result = a.freeAvlNodes + a.freeAvlNodes = a.freeAvlNodes.link[0] + else: + result = cast[PAvlNode](llAlloc(a, sizeof(AvlNode))) + when defined(avlcorruption): + cprintf("tracking location: %p\n", result) + result.key = key + result.upperBound = upperBound + let bottom = getBottom(a) + result.link[0] = bottom + result.link[1] = bottom + result.level = 1 + #when defined(avlcorruption): + # track("allocAvlNode", result, sizeof(AvlNode)) + sysAssert(bottom == addr(a.bottomData), "bottom data") + sysAssert(bottom.link[0] == bottom, "bottom link[0]") + sysAssert(bottom.link[1] == bottom, "bottom link[1]") - proc deallocAvlNode(a: var MemRegion, n: PAvlNode) {.inline.} = - n.link[0] = a.freeAvlNodes - a.freeAvlNodes = n +proc deallocAvlNode(a: var MemRegion, n: PAvlNode) {.inline.} = + n.link[0] = a.freeAvlNodes + a.freeAvlNodes = n proc addHeapLink(a: var MemRegion; p: PBigChunk, size: int) = var it = addr(a.heapLinks) @@ -334,8 +305,7 @@ proc addHeapLink(a: var MemRegion; p: PBigChunk, size: int) = it.chunks[L] = (p, size) inc it.len -when not defined(gcDestructors): - include "system/avltree" +include "system/avltree" proc llDeallocAll(a: var MemRegion) = var it = a.llmem @@ -400,7 +370,7 @@ iterator elements(t: IntSet): int {.inline.} = r = r.next proc isSmallChunk(c: PChunk): bool {.inline.} = - result = c.size <= SmallChunkSize-smallChunkOverhead() + return c.size <= SmallChunkSize-smallChunkOverhead() proc chunkUnused(c: PChunk): bool {.inline.} = result = (c.prevSize and 1) == 0 @@ -416,7 +386,7 @@ iterator allObjects(m: var MemRegion): pointer {.inline.} = var c = cast[PSmallChunk](c) let size = c.size - var a = cast[int](addr(c.data)) + var a = cast[ByteAddress](addr(c.data)) let limit = a + c.acc while a <% limit: yield cast[pointer](a) @@ -435,13 +405,13 @@ when not defined(gcDestructors): # ------------- chunk management ---------------------------------------------- proc pageIndex(c: PChunk): int {.inline.} = - result = cast[int](c) shr PageShift + result = cast[ByteAddress](c) shr PageShift proc pageIndex(p: pointer): int {.inline.} = - result = cast[int](p) shr PageShift + result = cast[ByteAddress](p) shr PageShift proc pageAddr(p: pointer): PChunk {.inline.} = - result = cast[PChunk](cast[int](p) and not PageMask) + result = cast[PChunk](cast[ByteAddress](p) and not PageMask) #sysAssert(Contains(allocator.chunkStarts, pageIndex(result))) when false: @@ -466,7 +436,7 @@ proc requestOsChunks(a: var MemRegion, size: int): PBigChunk = a.nextChunkSize = PageSize*4 else: a.nextChunkSize = min(roundup(usedMem shr 2, PageSize), a.nextChunkSize * 2) - a.nextChunkSize = min(a.nextChunkSize, MaxBigChunkSize).int + a.nextChunkSize = min(a.nextChunkSize, MaxBigChunkSize) var size = size if size > a.nextChunkSize: @@ -489,13 +459,13 @@ proc requestOsChunks(a: var MemRegion, size: int): PBigChunk = when defined(memtracker): trackLocation(addr result.size, sizeof(int)) - sysAssert((cast[int](result) and PageMask) == 0, "requestOsChunks 1") + sysAssert((cast[ByteAddress](result) and PageMask) == 0, "requestOsChunks 1") #zeroMem(result, size) result.next = nil result.prev = nil result.size = size # update next.prevSize: - var nxt = cast[int](result) +% size + var nxt = cast[ByteAddress](result) +% size sysAssert((nxt and PageMask) == 0, "requestOsChunks 2") var next = cast[PChunk](nxt) if pageIndex(next) in a.chunkStarts: @@ -503,7 +473,7 @@ proc requestOsChunks(a: var MemRegion, size: int): PBigChunk = next.prevSize = size or (next.prevSize and 1) # set result.prevSize: var lastSize = if a.lastSize != 0: a.lastSize else: PageSize - var prv = cast[int](result) -% lastSize + var prv = cast[ByteAddress](result) -% lastSize sysAssert((nxt and PageMask) == 0, "requestOsChunks 3") var prev = cast[PChunk](prv) if pageIndex(prev) in a.chunkStarts and prev.size == lastSize: @@ -549,22 +519,21 @@ proc listRemove[T](head: var T, c: T) {.inline.} = proc updatePrevSize(a: var MemRegion, c: PBigChunk, prevSize: int) {.inline.} = - var ri = cast[PChunk](cast[int](c) +% c.size) - sysAssert((cast[int](ri) and PageMask) == 0, "updatePrevSize") + var ri = cast[PChunk](cast[ByteAddress](c) +% c.size) + sysAssert((cast[ByteAddress](ri) and PageMask) == 0, "updatePrevSize") if isAccessible(a, ri): ri.prevSize = prevSize or (ri.prevSize and 1) proc splitChunk2(a: var MemRegion, c: PBigChunk, size: int): PBigChunk = - result = cast[PBigChunk](cast[int](c) +% size) + result = cast[PBigChunk](cast[ByteAddress](c) +% size) result.size = c.size - size track("result.size", addr result.size, sizeof(int)) - when not defined(nimOptimizedSplitChunk): - # still active because of weird codegen issue on some of our CIs: - result.next = nil - result.prev = nil + # XXX check if these two nil assignments are dead code given + # addChunkToMatrix's implementation: + result.next = nil + result.prev = nil # size and not used: result.prevSize = size - result.owner = addr a sysAssert((size and 1) == 0, "splitChunk 2") sysAssert((size and PageMask) == 0, "splitChunk: size is not a multiple of the PageSize") @@ -584,8 +553,8 @@ proc freeBigChunk(a: var MemRegion, c: PBigChunk) = when coalescLeft: let prevSize = c.prevSize if prevSize != 0: - var le = cast[PChunk](cast[int](c) -% prevSize) - sysAssert((cast[int](le) and PageMask) == 0, "freeBigChunk 4") + var le = cast[PChunk](cast[ByteAddress](c) -% prevSize) + sysAssert((cast[ByteAddress](le) and PageMask) == 0, "freeBigChunk 4") if isAccessible(a, le) and chunkUnused(le): sysAssert(not isSmallChunk(le), "freeBigChunk 5") if not isSmallChunk(le) and le.size < MaxBigChunkSize: @@ -595,14 +564,11 @@ proc freeBigChunk(a: var MemRegion, c: PBigChunk) = c = cast[PBigChunk](le) if c.size > MaxBigChunkSize: let rest = splitChunk2(a, c, MaxBigChunkSize) - when defined(nimOptimizedSplitChunk): - rest.next = nil - rest.prev = nil addChunkToMatrix(a, c) c = rest when coalescRight: - var ri = cast[PChunk](cast[int](c) +% c.size) - sysAssert((cast[int](ri) and PageMask) == 0, "freeBigChunk 2") + var ri = cast[PChunk](cast[ByteAddress](c) +% c.size) + sysAssert((cast[ByteAddress](ri) and PageMask) == 0, "freeBigChunk 2") if isAccessible(a, ri) and chunkUnused(ri): sysAssert(not isSmallChunk(ri), "freeBigChunk 3") if not isSmallChunk(ri) and c.size < MaxBigChunkSize: @@ -617,18 +583,10 @@ proc freeBigChunk(a: var MemRegion, c: PBigChunk) = proc getBigChunk(a: var MemRegion, size: int): PBigChunk = sysAssert(size > 0, "getBigChunk 2") var size = size # roundup(size, PageSize) - var fl = 0 - var sl = 0 + var fl, sl: int mappingSearch(size, fl, sl) sysAssert((size and PageMask) == 0, "getBigChunk: unaligned chunk") result = findSuitableBlock(a, fl, sl) - - when RegionHasLock: - if not a.lockActive: - a.lockActive = true - initSysLock(a.lock) - acquireSys a.lock - if result == nil: if size < nimMinHeapPages * PageSize: result = requestOsChunks(a, nimMinHeapPages * PageSize) @@ -638,7 +596,6 @@ proc getBigChunk(a: var MemRegion, size: int): PBigChunk = # if we over allocated split the chunk: if result.size > size: splitChunk(a, result, size) - result.owner = addr a else: removeChunkFromMatrix2(a, result, fl, sl) if result.size >= size + PageSize: @@ -646,33 +603,22 @@ proc getBigChunk(a: var MemRegion, size: int): PBigChunk = # set 'used' to to true: result.prevSize = 1 track("setUsedToFalse", addr result.size, sizeof(int)) - sysAssert result.owner == addr a, "getBigChunk: No owner set!" incl(a, a.chunkStarts, pageIndex(result)) dec(a.freeMem, size) - when RegionHasLock: - releaseSys a.lock proc getHugeChunk(a: var MemRegion; size: int): PBigChunk = result = cast[PBigChunk](osAllocPages(size)) - when RegionHasLock: - if not a.lockActive: - a.lockActive = true - initSysLock(a.lock) - acquireSys a.lock incCurrMem(a, size) # XXX add this to the heap links. But also remove it from it later. when false: a.addHeapLink(result, size) - sysAssert((cast[int](result) and PageMask) == 0, "getHugeChunk") + sysAssert((cast[ByteAddress](result) and PageMask) == 0, "getHugeChunk") result.next = nil result.prev = nil result.size = size # set 'used' to to true: result.prevSize = 1 - result.owner = addr a incl(a, a.chunkStarts, pageIndex(result)) - when RegionHasLock: - releaseSys a.lock proc freeHugeChunk(a: var MemRegion; c: PBigChunk) = let size = c.size @@ -736,87 +682,76 @@ else: template trackSize(x) = discard template untrackSize(x) = discard -proc deallocBigChunk(a: var MemRegion, c: PBigChunk) = - when RegionHasLock: - acquireSys a.lock - dec a.occ, c.size - untrackSize(c.size) - sysAssert a.occ >= 0, "rawDealloc: negative occupied memory (case B)" - when not defined(gcDestructors): - a.deleted = getBottom(a) - del(a, a.root, cast[int](addr(c.data))) - if c.size >= HugeChunkSize: freeHugeChunk(a, c) - else: freeBigChunk(a, c) - when RegionHasLock: - releaseSys a.lock - -when defined(gcDestructors): - template atomicPrepend(head, elem: untyped) = - # see also https://en.cppreference.com/w/cpp/atomic/atomic_compare_exchange - when hasThreadSupport: - while true: - elem.next.storea head.loada - if atomicCompareExchangeN(addr head, addr elem.next, elem, weak = true, ATOMIC_RELEASE, ATOMIC_RELAXED): - break +when false: + # not yet used by the GCs + proc rawTryAlloc(a: var MemRegion; requestedSize: int): pointer = + sysAssert(allocInv(a), "rawAlloc: begin") + sysAssert(roundup(65, 8) == 72, "rawAlloc: roundup broken") + sysAssert(requestedSize >= sizeof(FreeCell), "rawAlloc: requested size too small") + var size = roundup(requestedSize, MemAlign) + inc a.occ, size + trackSize(size) + sysAssert(size >= requestedSize, "insufficient allocated size!") + #c_fprintf(stdout, "alloc; size: %ld; %ld\n", requestedSize, size) + if size <= SmallChunkSize-smallChunkOverhead(): + # allocate a small block: for small chunks, we use only its next pointer + var s = size div MemAlign + var c = a.freeSmallChunks[s] + if c == nil: + result = nil + else: + sysAssert c.size == size, "rawAlloc 6" + if c.freeList == nil: + sysAssert(c.acc + smallChunkOverhead() + size <= SmallChunkSize, + "rawAlloc 7") + result = cast[pointer](cast[ByteAddress](addr(c.data)) +% c.acc) + inc(c.acc, size) + else: + result = c.freeList + sysAssert(c.freeList.zeroField == 0, "rawAlloc 8") + c.freeList = c.freeList.next + dec(c.free, size) + sysAssert((cast[ByteAddress](result) and (MemAlign-1)) == 0, "rawAlloc 9") + if c.free < size: + listRemove(a.freeSmallChunks[s], c) + sysAssert(allocInv(a), "rawAlloc: end listRemove test") + sysAssert(((cast[ByteAddress](result) and PageMask) - smallChunkOverhead()) %% + size == 0, "rawAlloc 21") + sysAssert(allocInv(a), "rawAlloc: end small size") else: - elem.next.storea head.loada - head.storea elem - - proc addToSharedFreeListBigChunks(a: var MemRegion; c: PBigChunk) {.inline.} = - sysAssert c.next == nil, "c.next pointer must be nil" - atomicPrepend a.sharedFreeListBigChunks, c - - proc addToSharedFreeList(c: PSmallChunk; f: ptr FreeCell) {.inline.} = - atomicPrepend c.sharedFreeList, f - - proc compensateCounters(a: var MemRegion; c: PSmallChunk; size: int) = - # rawDealloc did NOT do the usual: - # `inc(c.free, size); dec(a.occ, size)` because it wasn't the owner of these - # memory locations. We have to compensate here for these for the entire list. - # Well, not for the entire list, but for `max` elements of the list because - # we split the list in order to achieve bounded response times. - var it = c.freeList - var x = 0 - var maxIters = 20 # make it time-bounded - while it != nil: - if maxIters == 0: - let rest = it.next.loada - if rest != nil: - it.next.storea nil - addToSharedFreeList(c, rest) - break - inc x, size - it = it.next.loada - dec maxIters - inc(c.free, x) - dec(a.occ, x) - - proc freeDeferredObjects(a: var MemRegion; root: PBigChunk) = - var it = root - var maxIters = 20 # make it time-bounded - while true: - if maxIters == 0: - let rest = it.next.loada - it.next.storea nil - addToSharedFreeListBigChunks(a, rest) - break - it = it.next.loada - dec maxIters - if it == nil: break + inc size, bigChunkOverhead() + var fl, sl: int + mappingSearch(size, fl, sl) + sysAssert((size and PageMask) == 0, "getBigChunk: unaligned chunk") + let c = findSuitableBlock(a, fl, sl) + if c != nil: + removeChunkFromMatrix2(a, c, fl, sl) + if c.size >= size + PageSize: + splitChunk(a, c, size) + # set 'used' to to true: + c.prevSize = 1 + incl(a, a.chunkStarts, pageIndex(c)) + dec(a.freeMem, size) + result = addr(c.data) + sysAssert((cast[ByteAddress](c) and (MemAlign-1)) == 0, "rawAlloc 13") + sysAssert((cast[ByteAddress](c) and PageMask) == 0, "rawAlloc: Not aligned on a page boundary") + if a.root == nil: a.root = getBottom(a) + add(a, a.root, cast[ByteAddress](result), cast[ByteAddress](result)+%size) + else: + result = nil proc rawAlloc(a: var MemRegion, requestedSize: int): pointer = when defined(nimTypeNames): inc(a.allocCounter) sysAssert(allocInv(a), "rawAlloc: begin") sysAssert(roundup(65, 8) == 72, "rawAlloc: roundup broken") + sysAssert(requestedSize >= sizeof(FreeCell), "rawAlloc: requested size too small") var size = roundup(requestedSize, MemAlign) - sysAssert(size >= sizeof(FreeCell), "rawAlloc: requested size too small") - sysAssert(size >= requestedSize, "insufficient allocated size!") #c_fprintf(stdout, "alloc; size: %ld; %ld\n", requestedSize, size) if size <= SmallChunkSize-smallChunkOverhead(): # allocate a small block: for small chunks, we use only its next pointer - let s = size div MemAlign + var s = size div MemAlign var c = a.freeSmallChunks[s] if c == nil: c = getSmallChunk(a) @@ -824,33 +759,22 @@ proc rawAlloc(a: var MemRegion, requestedSize: int): pointer = sysAssert c.size == PageSize, "rawAlloc 3" c.size = size c.acc = size - when defined(gcDestructors): - c.sharedFreeList = nil c.free = SmallChunkSize - smallChunkOverhead() - size - sysAssert c.owner == addr(a), "rawAlloc: No owner set!" c.next = nil c.prev = nil listAdd(a.freeSmallChunks[s], c) result = addr(c.data) - sysAssert((cast[int](result) and (MemAlign-1)) == 0, "rawAlloc 4") + sysAssert((cast[ByteAddress](result) and (MemAlign-1)) == 0, "rawAlloc 4") else: sysAssert(allocInv(a), "rawAlloc: begin c != nil") sysAssert c.next != c, "rawAlloc 5" #if c.size != size: # c_fprintf(stdout, "csize: %lld; size %lld\n", c.size, size) sysAssert c.size == size, "rawAlloc 6" - when defined(gcDestructors): - if c.freeList == nil: - when hasThreadSupport: - c.freeList = atomicExchangeN(addr c.sharedFreeList, nil, ATOMIC_RELAXED) - else: - c.freeList = c.sharedFreeList - c.sharedFreeList = nil - compensateCounters(a, c, size) if c.freeList == nil: sysAssert(c.acc + smallChunkOverhead() + size <= SmallChunkSize, "rawAlloc 7") - result = cast[pointer](cast[int](addr(c.data)) +% c.acc) + result = cast[pointer](cast[ByteAddress](addr(c.data)) +% c.acc) inc(c.acc, size) else: result = c.freeList @@ -858,28 +782,19 @@ proc rawAlloc(a: var MemRegion, requestedSize: int): pointer = sysAssert(c.freeList.zeroField == 0, "rawAlloc 8") c.freeList = c.freeList.next dec(c.free, size) - sysAssert((cast[int](result) and (MemAlign-1)) == 0, "rawAlloc 9") + sysAssert((cast[ByteAddress](result) and (MemAlign-1)) == 0, "rawAlloc 9") sysAssert(allocInv(a), "rawAlloc: end c != nil") sysAssert(allocInv(a), "rawAlloc: before c.free < size") if c.free < size: sysAssert(allocInv(a), "rawAlloc: before listRemove test") listRemove(a.freeSmallChunks[s], c) sysAssert(allocInv(a), "rawAlloc: end listRemove test") - sysAssert(((cast[int](result) and PageMask) - smallChunkOverhead()) %% + sysAssert(((cast[ByteAddress](result) and PageMask) - smallChunkOverhead()) %% size == 0, "rawAlloc 21") sysAssert(allocInv(a), "rawAlloc: end small size") inc a.occ, size trackSize(c.size) else: - when defined(gcDestructors): - when hasThreadSupport: - let deferredFrees = atomicExchangeN(addr a.sharedFreeListBigChunks, nil, ATOMIC_RELAXED) - else: - let deferredFrees = a.sharedFreeListBigChunks - a.sharedFreeListBigChunks = nil - if deferredFrees != nil: - freeDeferredObjects(a, deferredFrees) - size = requestedSize + bigChunkOverhead() # roundup(requestedSize+bigChunkOverhead(), PageSize) # allocate a large block var c = if size >= HugeChunkSize: getHugeChunk(a, size) @@ -887,11 +802,10 @@ proc rawAlloc(a: var MemRegion, requestedSize: int): pointer = sysAssert c.prev == nil, "rawAlloc 10" sysAssert c.next == nil, "rawAlloc 11" result = addr(c.data) - sysAssert((cast[int](c) and (MemAlign-1)) == 0, "rawAlloc 13") - sysAssert((cast[int](c) and PageMask) == 0, "rawAlloc: Not aligned on a page boundary") - when not defined(gcDestructors): - if a.root == nil: a.root = getBottom(a) - add(a, a.root, cast[int](result), cast[int](result)+%size) + sysAssert((cast[ByteAddress](c) and (MemAlign-1)) == 0, "rawAlloc 13") + sysAssert((cast[ByteAddress](c) and PageMask) == 0, "rawAlloc: Not aligned on a page boundary") + if a.root == nil: a.root = getBottom(a) + add(a, a.root, cast[ByteAddress](result), cast[ByteAddress](result)+%size) inc a.occ, c.size trackSize(c.size) sysAssert(isAccessible(a, result), "rawAlloc 14") @@ -908,57 +822,51 @@ proc rawDealloc(a: var MemRegion, p: pointer) = #sysAssert(isAllocatedPtr(a, p), "rawDealloc: no allocated pointer") sysAssert(allocInv(a), "rawDealloc: begin") var c = pageAddr(p) - sysAssert(c != nil, "rawDealloc: begin") if isSmallChunk(c): # `p` is within a small chunk: var c = cast[PSmallChunk](c) var s = c.size - # ^ We might access thread foreign storage here. - # The other thread cannot possibly free this block as it's still alive. + dec a.occ, s + untrackSize(s) + sysAssert a.occ >= 0, "rawDealloc: negative occupied memory (case A)" + sysAssert(((cast[ByteAddress](p) and PageMask) - smallChunkOverhead()) %% + s == 0, "rawDealloc 3") var f = cast[ptr FreeCell](p) - if c.owner == addr(a): - # We own the block, there is no foreign thread involved. - dec a.occ, s - untrackSize(s) - sysAssert a.occ >= 0, "rawDealloc: negative occupied memory (case A)" - sysAssert(((cast[int](p) and PageMask) - smallChunkOverhead()) %% - s == 0, "rawDealloc 3") - when not defined(gcDestructors): - #echo("setting to nil: ", $cast[int](addr(f.zeroField))) - sysAssert(f.zeroField != 0, "rawDealloc 1") - f.zeroField = 0 - f.next = c.freeList - c.freeList = f - when overwriteFree: - # set to 0xff to check for usage after free bugs: - nimSetMem(cast[pointer](cast[int](p) +% sizeof(FreeCell)), -1'i32, - s -% sizeof(FreeCell)) - # check if it is not in the freeSmallChunks[s] list: - if c.free < s: - # add it to the freeSmallChunks[s] array: - listAdd(a.freeSmallChunks[s div MemAlign], c) - inc(c.free, s) - else: - inc(c.free, s) - if c.free == SmallChunkSize-smallChunkOverhead(): - listRemove(a.freeSmallChunks[s div MemAlign], c) - c.size = SmallChunkSize - freeBigChunk(a, cast[PBigChunk](c)) + when not defined(gcDestructors): + #echo("setting to nil: ", $cast[ByteAddress](addr(f.zeroField))) + sysAssert(f.zeroField != 0, "rawDealloc 1") + f.zeroField = 0 + f.next = c.freeList + c.freeList = f + when overwriteFree: + # set to 0xff to check for usage after free bugs: + nimSetMem(cast[pointer](cast[int](p) +% sizeof(FreeCell)), -1'i32, + s -% sizeof(FreeCell)) + # check if it is not in the freeSmallChunks[s] list: + if c.free < s: + # add it to the freeSmallChunks[s] array: + listAdd(a.freeSmallChunks[s div MemAlign], c) + inc(c.free, s) else: - when defined(gcDestructors): - addToSharedFreeList(c, f) - sysAssert(((cast[int](p) and PageMask) - smallChunkOverhead()) %% + inc(c.free, s) + if c.free == SmallChunkSize-smallChunkOverhead(): + listRemove(a.freeSmallChunks[s div MemAlign], c) + c.size = SmallChunkSize + freeBigChunk(a, cast[PBigChunk](c)) + sysAssert(((cast[ByteAddress](p) and PageMask) - smallChunkOverhead()) %% s == 0, "rawDealloc 2") else: # set to 0xff to check for usage after free bugs: when overwriteFree: nimSetMem(p, -1'i32, c.size -% bigChunkOverhead()) - when defined(gcDestructors): - if c.owner == addr(a): - deallocBigChunk(a, cast[PBigChunk](c)) - else: - addToSharedFreeListBigChunks(c.owner[], cast[PBigChunk](c)) - else: - deallocBigChunk(a, cast[PBigChunk](c)) + # free big chunk + var c = cast[PBigChunk](c) + dec a.occ, c.size + untrackSize(c.size) + sysAssert a.occ >= 0, "rawDealloc: negative occupied memory (case B)" + a.deleted = getBottom(a) + del(a, a.root, cast[int](addr(c.data))) + if c.size >= HugeChunkSize: freeHugeChunk(a, c) + else: freeBigChunk(a, c) sysAssert(allocInv(a), "rawDealloc: end") when logAlloc: cprintf("dealloc(pointer_%p)\n", p) @@ -969,7 +877,7 @@ when not defined(gcDestructors): if not chunkUnused(c): if isSmallChunk(c): var c = cast[PSmallChunk](c) - var offset = (cast[int](p) and (PageSize-1)) -% + var offset = (cast[ByteAddress](p) and (PageSize-1)) -% smallChunkOverhead() result = (c.acc >% offset) and (offset %% c.size == 0) and (cast[ptr FreeCell](p).zeroField >% 1) @@ -987,12 +895,12 @@ when not defined(gcDestructors): if not chunkUnused(c): if isSmallChunk(c): var c = cast[PSmallChunk](c) - var offset = (cast[int](p) and (PageSize-1)) -% + var offset = (cast[ByteAddress](p) and (PageSize-1)) -% smallChunkOverhead() if c.acc >% offset: - sysAssert(cast[int](addr(c.data)) +% offset == - cast[int](p), "offset is not what you think it is") - var d = cast[ptr FreeCell](cast[int](addr(c.data)) +% + sysAssert(cast[ByteAddress](addr(c.data)) +% offset == + cast[ByteAddress](p), "offset is not what you think it is") + var d = cast[ptr FreeCell](cast[ByteAddress](addr(c.data)) +% offset -% (offset %% c.size)) if d.zeroField >% 1: result = d @@ -1019,7 +927,7 @@ when not defined(gcDestructors): proc ptrSize(p: pointer): int = when not defined(gcDestructors): - var x = cast[pointer](cast[int](p) -% sizeof(FreeCell)) + var x = cast[pointer](cast[ByteAddress](p) -% sizeof(FreeCell)) var c = pageAddr(p) sysAssert(not chunkUnused(c), "ptrSize") result = c.size -% sizeof(FreeCell) @@ -1037,7 +945,7 @@ proc alloc(allocator: var MemRegion, size: Natural): pointer {.gcsafe.} = result = rawAlloc(allocator, size+sizeof(FreeCell)) cast[ptr FreeCell](result).zeroField = 1 # mark it as used sysAssert(not isAllocatedPtr(allocator, result), "alloc") - result = cast[pointer](cast[int](result) +% sizeof(FreeCell)) + result = cast[pointer](cast[ByteAddress](result) +% sizeof(FreeCell)) track("alloc", result, size) else: result = rawAlloc(allocator, size) @@ -1049,7 +957,7 @@ proc alloc0(allocator: var MemRegion, size: Natural): pointer = proc dealloc(allocator: var MemRegion, p: pointer) = when not defined(gcDestructors): sysAssert(p != nil, "dealloc: p is nil") - var x = cast[pointer](cast[int](p) -% sizeof(FreeCell)) + var x = cast[pointer](cast[ByteAddress](p) -% sizeof(FreeCell)) sysAssert(x != nil, "dealloc: x is nil") sysAssert(isAccessible(allocator, x), "is not accessible") sysAssert(cast[ptr FreeCell](x).zeroField == 1, "dealloc: object header corrupted") @@ -1105,12 +1013,12 @@ when defined(nimTypeNames): template instantiateForRegion(allocator: untyped) {.dirty.} = {.push stackTrace: off.} - when defined(nimFulldebug): + when defined(fulldebug): proc interiorAllocatedPtr*(p: pointer): pointer = result = interiorAllocatedPtr(allocator, p) proc isAllocatedPtr*(p: pointer): bool = - let p = cast[pointer](cast[int](p)-%ByteAddress(sizeof(Cell))) + let p = cast[pointer](cast[ByteAddress](p)-%ByteAddress(sizeof(Cell))) result = isAllocatedPtr(allocator, p) proc deallocOsPages = deallocOsPages(allocator) @@ -1140,34 +1048,25 @@ template instantiateForRegion(allocator: untyped) {.dirty.} = inc(result, it.size) it = it.next - when hasThreadSupport and not defined(gcDestructors): - proc addSysExitProc(quitProc: proc() {.noconv.}) {.importc: "atexit", header: "".} - - var sharedHeap: MemRegion - var heapLock: SysLock - initSysLock(heapLock) - addSysExitProc(proc() {.noconv.} = deinitSys(heapLock)) - proc getFreeMem(): int = - #sysAssert(result == countFreeMem()) result = allocator.freeMem + #sysAssert(result == countFreeMem()) - proc getTotalMem(): int = - result = allocator.currMem - - proc getOccupiedMem(): int = - result = allocator.occ #getTotalMem() - getFreeMem() - - proc getMaxMem*(): int = - result = getMaxMem(allocator) + proc getTotalMem(): int = return allocator.currMem + proc getOccupiedMem(): int = return allocator.occ #getTotalMem() - getFreeMem() + proc getMaxMem*(): int = return getMaxMem(allocator) when defined(nimTypeNames): proc getMemCounters*(): (int, int) = getMemCounters(allocator) # -------------------- shared heap region ---------------------------------- + when hasThreadSupport: + var sharedHeap: MemRegion + var heapLock: SysLock + initSysLock(heapLock) proc allocSharedImpl(size: Natural): pointer = - when hasThreadSupport and not defined(gcDestructors): + when hasThreadSupport: acquireSys(heapLock) result = alloc(sharedHeap, size) releaseSys(heapLock) @@ -1179,7 +1078,7 @@ template instantiateForRegion(allocator: untyped) {.dirty.} = zeroMem(result, size) proc deallocSharedImpl(p: pointer) = - when hasThreadSupport and not defined(gcDestructors): + when hasThreadSupport: acquireSys(heapLock) dealloc(sharedHeap, p) releaseSys(heapLock) @@ -1187,7 +1086,7 @@ template instantiateForRegion(allocator: untyped) {.dirty.} = deallocImpl(p) proc reallocSharedImpl(p: pointer, newSize: Natural): pointer = - when hasThreadSupport and not defined(gcDestructors): + when hasThreadSupport: acquireSys(heapLock) result = realloc(sharedHeap, p, newSize) releaseSys(heapLock) @@ -1195,7 +1094,7 @@ template instantiateForRegion(allocator: untyped) {.dirty.} = result = reallocImpl(p, newSize) proc reallocShared0Impl(p: pointer, oldSize, newSize: Natural): pointer = - when hasThreadSupport and not defined(gcDestructors): + when hasThreadSupport: acquireSys(heapLock) result = realloc0(sharedHeap, p, oldSize, newSize) releaseSys(heapLock) @@ -1203,31 +1102,20 @@ template instantiateForRegion(allocator: untyped) {.dirty.} = result = realloc0Impl(p, oldSize, newSize) when hasThreadSupport: - when defined(gcDestructors): - proc getFreeSharedMem(): int = - allocator.freeMem + template sharedMemStatsShared(v: int) = + acquireSys(heapLock) + result = v + releaseSys(heapLock) - proc getTotalSharedMem(): int = - allocator.currMem + proc getFreeSharedMem(): int = + sharedMemStatsShared(sharedHeap.freeMem) - proc getOccupiedSharedMem(): int = - allocator.occ + proc getTotalSharedMem(): int = + sharedMemStatsShared(sharedHeap.currMem) - else: - template sharedMemStatsShared(v: int) = - acquireSys(heapLock) - result = v - releaseSys(heapLock) - - proc getFreeSharedMem(): int = - sharedMemStatsShared(sharedHeap.freeMem) - - proc getTotalSharedMem(): int = - sharedMemStatsShared(sharedHeap.currMem) - - proc getOccupiedSharedMem(): int = - sharedMemStatsShared(sharedHeap.occ) - #sharedMemStatsShared(sharedHeap.currMem - sharedHeap.freeMem) + proc getOccupiedSharedMem(): int = + sharedMemStatsShared(sharedHeap.occ) + #sharedMemStatsShared(sharedHeap.currMem - sharedHeap.freeMem) {.pop.} {.pop.} diff --git a/lib/system/ansi_c.nim b/lib/system/ansi_c.nim index a8a4bd767..1ff15611c 100644 --- a/lib/system/ansi_c.nim +++ b/lib/system/ansi_c.nim @@ -12,6 +12,8 @@ # All symbols are prefixed with 'c_' to avoid ambiguities {.push hints:off, stack_trace: off, profiler: off.} +when not defined(nimHasHotCodeReloading): + {.pragma: nonReloadable.} proc c_memchr*(s: pointer, c: cint, n: csize_t): pointer {. importc: "memchr", header: "".} @@ -31,10 +33,7 @@ proc c_abort*() {. importc: "abort", header: "", noSideEffect, noreturn.} -when defined(nimBuiltinSetjmp): - type - C_JmpBuf* = array[5, pointer] -elif defined(linux) and defined(amd64): +when defined(linux) and defined(amd64): type C_JmpBuf* {.importc: "jmp_buf", header: "", bycopy.} = object abi: array[200 div sizeof(clong), clong] @@ -43,7 +42,6 @@ else: C_JmpBuf* {.importc: "jmp_buf", header: "".} = object -type CSighandlerT = proc (a: cint) {.noconv.} when defined(windows): const SIGABRT* = cint(22) @@ -52,7 +50,6 @@ when defined(windows): SIGINT* = cint(2) SIGSEGV* = cint(11) SIGTERM = cint(15) - SIG_DFL* = cast[CSighandlerT](0) elif defined(macosx) or defined(linux) or defined(freebsd) or defined(openbsd) or defined(netbsd) or defined(solaris) or defined(dragonfly) or defined(nintendoswitch) or defined(genode) or @@ -65,7 +62,6 @@ elif defined(macosx) or defined(linux) or defined(freebsd) or SIGSEGV* = cint(11) SIGTERM* = cint(15) SIGPIPE* = cint(13) - SIG_DFL* = cast[CSighandlerT](0) elif defined(haiku): const SIGABRT* = cint(6) @@ -75,9 +71,8 @@ elif defined(haiku): SIGSEGV* = cint(11) SIGTERM* = cint(15) SIGPIPE* = cint(7) - SIG_DFL* = cast[CSighandlerT](0) else: - when defined(nimscript): + when NoFakeVars: {.error: "SIGABRT not ported to your platform".} else: var @@ -86,7 +81,6 @@ else: SIGABRT* {.importc: "SIGABRT", nodecl.}: cint SIGFPE* {.importc: "SIGFPE", nodecl.}: cint SIGILL* {.importc: "SIGILL", nodecl.}: cint - SIG_DFL* {.importc: "SIG_DFL", nodecl.}: CSighandlerT when defined(macosx) or defined(linux): var SIGPIPE* {.importc: "SIGPIPE", nodecl.}: cint @@ -95,67 +89,27 @@ when defined(macosx): elif defined(haiku): const SIGBUS* = cint(30) -# "nimRawSetjmp" is defined by default for certain platforms, so we need the -# "nimStdSetjmp" escape hatch with it. -when defined(nimSigSetjmp): +when defined(nimSigSetjmp) and not defined(nimStdSetjmp): proc c_longjmp*(jmpb: C_JmpBuf, retval: cint) {. header: "", importc: "siglongjmp".} - proc c_setjmp*(jmpb: C_JmpBuf): cint = + template c_setjmp*(jmpb: C_JmpBuf): cint = proc c_sigsetjmp(jmpb: C_JmpBuf, savemask: cint): cint {. header: "", importc: "sigsetjmp".} c_sigsetjmp(jmpb, 0) -elif defined(nimBuiltinSetjmp): - proc c_longjmp*(jmpb: C_JmpBuf, retval: cint) = - # Apple's Clang++ has trouble converting array names to pointers, so we need - # to be very explicit here. - proc c_builtin_longjmp(jmpb: ptr pointer, retval: cint) {. - importc: "__builtin_longjmp", nodecl.} - # The second parameter needs to be 1 and sometimes the C/C++ compiler checks it. - c_builtin_longjmp(unsafeAddr jmpb[0], 1) - proc c_setjmp*(jmpb: C_JmpBuf): cint = - proc c_builtin_setjmp(jmpb: ptr pointer): cint {. - importc: "__builtin_setjmp", nodecl.} - c_builtin_setjmp(unsafeAddr jmpb[0]) - elif defined(nimRawSetjmp) and not defined(nimStdSetjmp): - when defined(windows): - # No `_longjmp()` on Windows. - proc c_longjmp*(jmpb: C_JmpBuf, retval: cint) {. - header: "", importc: "longjmp".} - when defined(vcc) or defined(clangcl): - proc c_setjmp*(jmpb: C_JmpBuf): cint {. - header: "", importc: "setjmp".} - else: - # The Windows `_setjmp()` takes two arguments, with the second being an - # undocumented buffer used by the SEH mechanism for stack unwinding. - # Mingw-w64 has been trying to get it right for years, but it's still - # prone to stack corruption during unwinding, so we disable that by setting - # it to NULL. - # More details: https://github.com/status-im/nimbus-eth2/issues/3121 - when defined(nimHasStyleChecks): - {.push styleChecks: off.} - - proc c_setjmp*(jmpb: C_JmpBuf): cint = - proc c_setjmp_win(jmpb: C_JmpBuf, ctx: pointer): cint {. - header: "", importc: "_setjmp".} - c_setjmp_win(jmpb, nil) - - when defined(nimHasStyleChecks): - {.pop.} - else: - proc c_longjmp*(jmpb: C_JmpBuf, retval: cint) {. - header: "", importc: "_longjmp".} - proc c_setjmp*(jmpb: C_JmpBuf): cint {. - header: "", importc: "_setjmp".} + proc c_longjmp*(jmpb: C_JmpBuf, retval: cint) {. + header: "", importc: "_longjmp".} + proc c_setjmp*(jmpb: C_JmpBuf): cint {. + header: "", importc: "_setjmp".} else: proc c_longjmp*(jmpb: C_JmpBuf, retval: cint) {. header: "", importc: "longjmp".} proc c_setjmp*(jmpb: C_JmpBuf): cint {. header: "", importc: "setjmp".} -proc c_signal*(sign: cint, handler: CSighandlerT): CSighandlerT {. +type CSighandlerT = proc (a: cint) {.noconv.} +proc c_signal*(sign: cint, handler: proc (a: cint) {.noconv.}): CSighandlerT {. importc: "signal", header: "", discardable.} -proc c_raise*(sign: cint): cint {.importc: "raise", header: "".} type CFile {.importc: "FILE", header: "", @@ -163,7 +117,7 @@ type CFilePtr* = ptr CFile ## The type representing a file handle. # duplicated between io and ansi_c -const stdioUsesMacros = (defined(osx) or defined(freebsd) or defined(dragonfly)) and not defined(emscripten) +const stdioUsesMacros = (defined(osx) or defined(bsd)) and not defined(emscripten) const stderrName = when stdioUsesMacros: "__stderrp" else: "stderr" const stdoutName = when stdioUsesMacros: "__stdoutp" else: "stdout" const stdinName = when stdioUsesMacros: "__stdinp" else: "stdin" @@ -180,48 +134,26 @@ proc c_printf*(frmt: cstring): cint {. proc c_fputs*(c: cstring, f: CFilePtr): cint {. importc: "fputs", header: "", discardable.} -proc c_fputc*(c: char, f: CFilePtr): cint {. - importc: "fputc", header: "", discardable.} proc c_sprintf*(buf, frmt: cstring): cint {. importc: "sprintf", header: "", varargs, noSideEffect.} # we use it only in a way that cannot lead to security issues -when defined(zephyr) and not defined(zephyrUseLibcMalloc): - proc c_malloc*(size: csize_t): pointer {. - importc: "k_malloc", header: "".} - proc c_calloc*(nmemb, size: csize_t): pointer {. - importc: "k_calloc", header: "".} - proc c_free*(p: pointer) {. - importc: "k_free", header: "".} - proc c_realloc*(p: pointer, newsize: csize_t): pointer = - # Zephyr's kernel malloc doesn't support realloc - result = c_malloc(newSize) - # match the ansi c behavior - if not result.isNil(): - copyMem(result, p, newSize) - c_free(p) -else: - proc c_malloc*(size: csize_t): pointer {. - importc: "malloc", header: "".} - proc c_calloc*(nmemb, size: csize_t): pointer {. - importc: "calloc", header: "".} - proc c_free*(p: pointer) {. - importc: "free", header: "".} - proc c_realloc*(p: pointer, newsize: csize_t): pointer {. - importc: "realloc", header: "".} +proc c_malloc*(size: csize_t): pointer {. + importc: "malloc", header: "".} +proc c_calloc*(nmemb, size: csize_t): pointer {. + importc: "calloc", header: "".} +proc c_free*(p: pointer) {. + importc: "free", header: "".} +proc c_realloc*(p: pointer, newsize: csize_t): pointer {. + importc: "realloc", header: "".} -proc c_fwrite*(buf: pointer, size, n: csize_t, f: CFilePtr): csize_t {. +proc c_fwrite*(buf: pointer, size, n: csize_t, f: CFilePtr): cint {. importc: "fwrite", header: "".} -proc c_fflush*(f: CFilePtr): cint {. +proc c_fflush(f: CFilePtr): cint {. importc: "fflush", header: "".} -proc rawWriteString*(f: CFilePtr, s: cstring, length: int) {.compilerproc, nonReloadable, inline.} = - # we cannot throw an exception here! - discard c_fwrite(s, 1, cast[csize_t](length), f) - discard c_fflush(f) - proc rawWrite*(f: CFilePtr, s: cstring) {.compilerproc, nonReloadable, inline.} = # we cannot throw an exception here! discard c_fwrite(s, 1, cast[csize_t](s.len), f) diff --git a/lib/system/arc.nim b/lib/system/arc.nim deleted file mode 100644 index d8527e1e4..000000000 --- a/lib/system/arc.nim +++ /dev/null @@ -1,211 +0,0 @@ -# -# -# Nim's Runtime Library -# (c) Copyright 2019 Andreas Rumpf -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# - -#[ -In this new runtime we simplify the object layouts a bit: The runtime type -information is only accessed for the objects that have it and it's always -at offset 0 then. The ``ref`` object header is independent from the -runtime type and only contains a reference count. -]# - -when defined(gcOrc): - const - rcIncrement = 0b10000 # so that lowest 4 bits are not touched - rcMask = 0b1111 - rcShift = 4 # shift by rcShift to get the reference counter - -else: - const - rcIncrement = 0b1000 # so that lowest 3 bits are not touched - rcMask = 0b111 - rcShift = 3 # shift by rcShift to get the reference counter - -type - RefHeader = object - rc: int # the object header is now a single RC field. - # we could remove it in non-debug builds for the 'owned ref' - # design but this seems unwise. - when defined(gcOrc): - rootIdx: int # thanks to this we can delete potential cycle roots - # in O(1) without doubly linked lists - when defined(nimArcDebug) or defined(nimArcIds): - refId: int - - Cell = ptr RefHeader - -template head(p: pointer): Cell = - cast[Cell](cast[int](p) -% sizeof(RefHeader)) - -const - traceCollector = defined(traceArc) - -when defined(nimArcDebug): - include cellsets - - const traceId = 20 # 1037 - - var gRefId: int - var freedCells: CellSet -elif defined(nimArcIds): - var gRefId: int - - const traceId = -1 - -proc nimNewObj(size, alignment: int): pointer {.compilerRtl.} = - let hdrSize = align(sizeof(RefHeader), alignment) - let s = size + hdrSize - when defined(nimscript): - discard - else: - result = alignedAlloc0(s, alignment) +! hdrSize - when defined(nimArcDebug) or defined(nimArcIds): - head(result).refId = gRefId - atomicInc gRefId - if head(result).refId == traceId: - writeStackTrace() - cfprintf(cstderr, "[nimNewObj] %p %ld\n", result, head(result).rc shr rcShift) - when traceCollector: - cprintf("[Allocated] %p result: %p\n", result -! sizeof(RefHeader), result) - -proc nimNewObjUninit(size, alignment: int): pointer {.compilerRtl.} = - # Same as 'newNewObj' but do not initialize the memory to zero. - # The codegen proved for us that this is not necessary. - let hdrSize = align(sizeof(RefHeader), alignment) - let s = size + hdrSize - when defined(nimscript): - discard - else: - result = cast[ptr RefHeader](alignedAlloc(s, alignment) +! hdrSize) - head(result).rc = 0 - when defined(gcOrc): - head(result).rootIdx = 0 - when defined(nimArcDebug): - head(result).refId = gRefId - atomicInc gRefId - if head(result).refId == traceId: - writeStackTrace() - cfprintf(cstderr, "[nimNewObjUninit] %p %ld\n", result, head(result).rc shr rcShift) - - when traceCollector: - cprintf("[Allocated] %p result: %p\n", result -! sizeof(RefHeader), result) - -proc nimDecWeakRef(p: pointer) {.compilerRtl, inl.} = - dec head(p).rc, rcIncrement - -proc nimIncRef(p: pointer) {.compilerRtl, inl.} = - when defined(nimArcDebug): - if head(p).refId == traceId: - writeStackTrace() - cfprintf(cstderr, "[IncRef] %p %ld\n", p, head(p).rc shr rcShift) - - inc head(p).rc, rcIncrement - when traceCollector: - cprintf("[INCREF] %p\n", head(p)) - -when not defined(gcOrc) or defined(nimThinout): - proc unsureAsgnRef(dest: ptr pointer, src: pointer) {.inline.} = - # This is only used by the old RTTI mechanism and we know - # that 'dest[]' is nil and needs no destruction. Which is really handy - # as we cannot destroy the object reliably if it's an object of unknown - # compile-time type. - dest[] = src - if src != nil: nimIncRef src - -when not defined(nimscript) and defined(nimArcDebug): - proc deallocatedRefId*(p: pointer): int = - ## Returns the ref's ID if the ref was already deallocated. This - ## is a memory corruption check. Returns 0 if there is no error. - let c = head(p) - if freedCells.data != nil and freedCells.contains(c): - result = c.refId - else: - result = 0 - -proc nimRawDispose(p: pointer, alignment: int) {.compilerRtl.} = - when not defined(nimscript): - when traceCollector: - cprintf("[Freed] %p\n", p -! sizeof(RefHeader)) - when defined(nimOwnedEnabled): - if head(p).rc >= rcIncrement: - cstderr.rawWrite "[FATAL] dangling references exist\n" - rawQuit 1 - when defined(nimArcDebug): - # we do NOT really free the memory here in order to reliably detect use-after-frees - if freedCells.data == nil: init(freedCells) - freedCells.incl head(p) - else: - let hdrSize = align(sizeof(RefHeader), alignment) - alignedDealloc(p -! hdrSize, alignment) - -template `=dispose`*[T](x: owned(ref T)) = nimRawDispose(cast[pointer](x), T.alignOf) -#proc dispose*(x: pointer) = nimRawDispose(x) - -proc nimDestroyAndDispose(p: pointer) {.compilerRtl, raises: [].} = - let rti = cast[ptr PNimTypeV2](p) - if rti.destructor != nil: - cast[DestructorProc](rti.destructor)(p) - when false: - cstderr.rawWrite cast[ptr PNimTypeV2](p)[].name - cstderr.rawWrite "\n" - if d == nil: - cstderr.rawWrite "bah, nil\n" - else: - cstderr.rawWrite "has destructor!\n" - nimRawDispose(p, rti.align) - -when defined(gcOrc): - when defined(nimThinout): - include cyclebreaker - else: - include orc - #include cyclecollector - -proc nimDecRefIsLast(p: pointer): bool {.compilerRtl, inl.} = - if p != nil: - var cell = head(p) - - when defined(nimArcDebug): - if cell.refId == traceId: - writeStackTrace() - cfprintf(cstderr, "[DecRef] %p %ld\n", p, cell.rc shr rcShift) - - if (cell.rc and not rcMask) == 0: - result = true - when traceCollector: - cprintf("[ABOUT TO DESTROY] %p\n", cell) - else: - dec cell.rc, rcIncrement - # According to Lins it's correct to do nothing else here. - when traceCollector: - cprintf("[DeCREF] %p\n", cell) - -proc GC_unref*[T](x: ref T) = - ## New runtime only supports this operation for 'ref T'. - var y {.cursor.} = x - `=destroy`(y) - -proc GC_ref*[T](x: ref T) = - ## New runtime only supports this operation for 'ref T'. - if x != nil: nimIncRef(cast[pointer](x)) - -when not defined(gcOrc): - template GC_fullCollect* = - ## Forces a full garbage collection pass. With `--gc:arc` a nop. - discard - -template setupForeignThreadGc* = - ## With `--gc:arc` a nop. - discard - -template tearDownForeignThreadGc* = - ## With `--gc:arc` a nop. - discard - -proc isObjDisplayCheck(source: PNimTypeV2, targetDepth: int16, token: uint32): bool {.compilerRtl, inline.} = - result = targetDepth <= source.depth and source.display[targetDepth] == token diff --git a/lib/system/arithm.nim b/lib/system/arithm.nim new file mode 100644 index 000000000..16ac8affe --- /dev/null +++ b/lib/system/arithm.nim @@ -0,0 +1,425 @@ +# +# +# Nim's Runtime Library +# (c) Copyright 2012 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + + +# simple integer arithmetic with overflow checking + +proc raiseOverflow {.compilerproc, noinline.} = + # a single proc to reduce code size to a minimum + sysFatal(OverflowError, "over- or underflow") + +proc raiseDivByZero {.compilerproc, noinline.} = + sysFatal(DivByZeroError, "division by zero") + +when defined(builtinOverflow): + # Builtin compiler functions for improved performance + when sizeof(clong) == 8: + proc addInt64Overflow[T: int64|int](a, b: T, c: var T): bool {. + importc: "__builtin_saddl_overflow", nodecl, nosideeffect.} + + proc subInt64Overflow[T: int64|int](a, b: T, c: var T): bool {. + importc: "__builtin_ssubl_overflow", nodecl, nosideeffect.} + + proc mulInt64Overflow[T: int64|int](a, b: T, c: var T): bool {. + importc: "__builtin_smull_overflow", nodecl, nosideeffect.} + + elif sizeof(clonglong) == 8: + proc addInt64Overflow[T: int64|int](a, b: T, c: var T): bool {. + importc: "__builtin_saddll_overflow", nodecl, nosideeffect.} + + proc subInt64Overflow[T: int64|int](a, b: T, c: var T): bool {. + importc: "__builtin_ssubll_overflow", nodecl, nosideeffect.} + + proc mulInt64Overflow[T: int64|int](a, b: T, c: var T): bool {. + importc: "__builtin_smulll_overflow", nodecl, nosideeffect.} + + when sizeof(int) == 8: + proc addIntOverflow(a, b: int, c: var int): bool {.inline.} = + addInt64Overflow(a, b, c) + + proc subIntOverflow(a, b: int, c: var int): bool {.inline.} = + subInt64Overflow(a, b, c) + + proc mulIntOverflow(a, b: int, c: var int): bool {.inline.} = + mulInt64Overflow(a, b, c) + + elif sizeof(int) == 4 and sizeof(cint) == 4: + proc addIntOverflow(a, b: int, c: var int): bool {. + importc: "__builtin_sadd_overflow", nodecl, nosideeffect.} + + proc subIntOverflow(a, b: int, c: var int): bool {. + importc: "__builtin_ssub_overflow", nodecl, nosideeffect.} + + proc mulIntOverflow(a, b: int, c: var int): bool {. + importc: "__builtin_smul_overflow", nodecl, nosideeffect.} + + proc addInt64(a, b: int64): int64 {.compilerproc, inline.} = + if addInt64Overflow(a, b, result): + raiseOverflow() + + proc subInt64(a, b: int64): int64 {.compilerproc, inline.} = + if subInt64Overflow(a, b, result): + raiseOverflow() + + proc mulInt64(a, b: int64): int64 {.compilerproc, inline.} = + if mulInt64Overflow(a, b, result): + raiseOverflow() +else: + proc addInt64(a, b: int64): int64 {.compilerproc, inline.} = + result = a +% b + if (result xor a) >= int64(0) or (result xor b) >= int64(0): + return result + raiseOverflow() + + proc subInt64(a, b: int64): int64 {.compilerproc, inline.} = + result = a -% b + if (result xor a) >= int64(0) or (result xor not b) >= int64(0): + return result + raiseOverflow() + + # + # This code has been inspired by Python's source code. + # The native int product x*y is either exactly right or *way* off, being + # just the last n bits of the true product, where n is the number of bits + # in an int (the delivered product is the true product plus i*2**n for + # some integer i). + # + # The native float64 product x*y is subject to three + # rounding errors: on a sizeof(int)==8 box, each cast to double can lose + # info, and even on a sizeof(int)==4 box, the multiplication can lose info. + # But, unlike the native int product, it's not in *range* trouble: even + # if sizeof(int)==32 (256-bit ints), the product easily fits in the + # dynamic range of a float64. So the leading 50 (or so) bits of the float64 + # product are correct. + # + # We check these two ways against each other, and declare victory if they're + # approximately the same. Else, because the native int product is the only + # one that can lose catastrophic amounts of information, it's the native int + # product that must have overflowed. + # + proc mulInt64(a, b: int64): int64 {.compilerproc.} = + var + resAsFloat, floatProd: float64 + result = a *% b + floatProd = toBiggestFloat(a) # conversion + floatProd = floatProd * toBiggestFloat(b) + resAsFloat = toBiggestFloat(result) + + # Fast path for normal case: small multiplicands, and no info + # is lost in either method. + if resAsFloat == floatProd: return result + + # Somebody somewhere lost info. Close enough, or way off? Note + # that a != 0 and b != 0 (else resAsFloat == floatProd == 0). + # The difference either is or isn't significant compared to the + # true value (of which floatProd is a good approximation). + + # abs(diff)/abs(prod) <= 1/32 iff + # 32 * abs(diff) <= abs(prod) -- 5 good bits is "close enough" + if 32.0 * abs(resAsFloat - floatProd) <= abs(floatProd): + return result + raiseOverflow() + +proc negInt64(a: int64): int64 {.compilerproc, inline.} = + if a != low(int64): return -a + raiseOverflow() + +proc absInt64(a: int64): int64 {.compilerproc, inline.} = + if a != low(int64): + if a >= 0: return a + else: return -a + raiseOverflow() + +proc divInt64(a, b: int64): int64 {.compilerproc, inline.} = + if b == int64(0): + raiseDivByZero() + if a == low(int64) and b == int64(-1): + raiseOverflow() + return a div b + +proc modInt64(a, b: int64): int64 {.compilerproc, inline.} = + if b == int64(0): + raiseDivByZero() + return a mod b + +proc absInt(a: int): int {.compilerproc, inline.} = + if a != low(int): + if a >= 0: return a + else: return -a + raiseOverflow() + +const + asmVersion = defined(I386) and (defined(vcc) or defined(wcc) or + defined(dmc) or defined(gcc) or defined(llvm_gcc)) + # my Version of Borland C++Builder does not have + # tasm32, which is needed for assembler blocks + # this is why Borland is not included in the 'when' + +when asmVersion and not defined(gcc) and not defined(llvm_gcc): + # assembler optimized versions for compilers that + # have an intel syntax assembler: + proc addInt(a, b: int): int {.compilerproc, asmNoStackFrame.} = + # a in eax, and b in edx + asm """ + mov eax, ecx + add eax, edx + jno theEnd + call `raiseOverflow` + theEnd: + ret + """ + + proc subInt(a, b: int): int {.compilerproc, asmNoStackFrame.} = + asm """ + mov eax, ecx + sub eax, edx + jno theEnd + call `raiseOverflow` + theEnd: + ret + """ + + proc negInt(a: int): int {.compilerproc, asmNoStackFrame.} = + asm """ + mov eax, ecx + neg eax + jno theEnd + call `raiseOverflow` + theEnd: + ret + """ + + proc divInt(a, b: int): int {.compilerproc, asmNoStackFrame.} = + asm """ + test edx, edx + jne L_NOT_ZERO + call `raiseDivByZero` + L_NOT_ZERO: + cmp ecx, 0x80000000 + jne L_DO_DIV + cmp edx, -1 + jne L_DO_DIV + call `raiseOverflow` + L_DO_DIV: + mov eax, ecx + mov ecx, edx + cdq + idiv ecx + ret + """ + + proc modInt(a, b: int): int {.compilerproc, asmNoStackFrame.} = + asm """ + test edx, edx + jne L_NOT_ZERO + call `raiseDivByZero` + L_NOT_ZERO: + cmp ecx, 0x80000000 + jne L_DO_DIV + cmp edx, -1 + jne L_DO_DIV + call `raiseOverflow` + L_DO_DIV: + mov eax, ecx + mov ecx, edx + cdq + idiv ecx + mov eax, edx + ret + """ + + proc mulInt(a, b: int): int {.compilerproc, asmNoStackFrame.} = + asm """ + mov eax, ecx + mov ecx, edx + xor edx, edx + imul ecx + jno theEnd + call `raiseOverflow` + theEnd: + ret + """ + +elif false: # asmVersion and (defined(gcc) or defined(llvm_gcc)): + proc addInt(a, b: int): int {.compilerproc, inline.} = + # don't use a pure proc here! + asm """ + "addl %%ecx, %%eax\n" + "jno 1\n" + "call _raiseOverflow\n" + "1: \n" + :"=a"(`result`) + :"a"(`a`), "c"(`b`) + """ + #".intel_syntax noprefix" + #/* Intel syntax here */ + #".att_syntax" + + proc subInt(a, b: int): int {.compilerproc, inline.} = + asm """ "subl %%ecx,%%eax\n" + "jno 1\n" + "call _raiseOverflow\n" + "1: \n" + :"=a"(`result`) + :"a"(`a`), "c"(`b`) + """ + + proc mulInt(a, b: int): int {.compilerproc, inline.} = + asm """ "xorl %%edx, %%edx\n" + "imull %%ecx\n" + "jno 1\n" + "call _raiseOverflow\n" + "1: \n" + :"=a"(`result`) + :"a"(`a`), "c"(`b`) + :"%edx" + """ + + proc negInt(a: int): int {.compilerproc, inline.} = + asm """ "negl %%eax\n" + "jno 1\n" + "call _raiseOverflow\n" + "1: \n" + :"=a"(`result`) + :"a"(`a`) + """ + + proc divInt(a, b: int): int {.compilerproc, inline.} = + asm """ "xorl %%edx, %%edx\n" + "idivl %%ecx\n" + "jno 1\n" + "call _raiseOverflow\n" + "1: \n" + :"=a"(`result`) + :"a"(`a`), "c"(`b`) + :"%edx" + """ + + proc modInt(a, b: int): int {.compilerproc, inline.} = + asm """ "xorl %%edx, %%edx\n" + "idivl %%ecx\n" + "jno 1\n" + "call _raiseOverflow\n" + "1: \n" + "movl %%edx, %%eax" + :"=a"(`result`) + :"a"(`a`), "c"(`b`) + :"%edx" + """ + +when not declared(addInt) and defined(builtinOverflow): + proc addInt(a, b: int): int {.compilerproc, inline.} = + if addIntOverflow(a, b, result): + raiseOverflow() + +when not declared(subInt) and defined(builtinOverflow): + proc subInt(a, b: int): int {.compilerproc, inline.} = + if subIntOverflow(a, b, result): + raiseOverflow() + +when not declared(mulInt) and defined(builtinOverflow): + proc mulInt(a, b: int): int {.compilerproc, inline.} = + if mulIntOverflow(a, b, result): + raiseOverflow() + +# Platform independent versions of the above (slower!) +when not declared(addInt): + proc addInt(a, b: int): int {.compilerproc, inline.} = + result = a +% b + if (result xor a) >= 0 or (result xor b) >= 0: + return result + raiseOverflow() + +when not declared(subInt): + proc subInt(a, b: int): int {.compilerproc, inline.} = + result = a -% b + if (result xor a) >= 0 or (result xor not b) >= 0: + return result + raiseOverflow() + +when not declared(negInt): + proc negInt(a: int): int {.compilerproc, inline.} = + if a != low(int): return -a + raiseOverflow() + +when not declared(divInt): + proc divInt(a, b: int): int {.compilerproc, inline.} = + if b == 0: + raiseDivByZero() + if a == low(int) and b == -1: + raiseOverflow() + return a div b + +when not declared(modInt): + proc modInt(a, b: int): int {.compilerproc, inline.} = + if b == 0: + raiseDivByZero() + return a mod b + +when not declared(mulInt): + # + # This code has been inspired by Python's source code. + # The native int product x*y is either exactly right or *way* off, being + # just the last n bits of the true product, where n is the number of bits + # in an int (the delivered product is the true product plus i*2**n for + # some integer i). + # + # The native float64 product x*y is subject to three + # rounding errors: on a sizeof(int)==8 box, each cast to double can lose + # info, and even on a sizeof(int)==4 box, the multiplication can lose info. + # But, unlike the native int product, it's not in *range* trouble: even + # if sizeof(int)==32 (256-bit ints), the product easily fits in the + # dynamic range of a float64. So the leading 50 (or so) bits of the float64 + # product are correct. + # + # We check these two ways against each other, and declare victory if + # they're approximately the same. Else, because the native int product is + # the only one that can lose catastrophic amounts of information, it's the + # native int product that must have overflowed. + # + proc mulInt(a, b: int): int {.compilerproc.} = + var + resAsFloat, floatProd: float + + result = a *% b + floatProd = toFloat(a) * toFloat(b) + resAsFloat = toFloat(result) + + # Fast path for normal case: small multiplicands, and no info + # is lost in either method. + if resAsFloat == floatProd: return result + + # Somebody somewhere lost info. Close enough, or way off? Note + # that a != 0 and b != 0 (else resAsFloat == floatProd == 0). + # The difference either is or isn't significant compared to the + # true value (of which floatProd is a good approximation). + + # abs(diff)/abs(prod) <= 1/32 iff + # 32 * abs(diff) <= abs(prod) -- 5 good bits is "close enough" + if 32.0 * abs(resAsFloat - floatProd) <= abs(floatProd): + return result + raiseOverflow() + +# We avoid setting the FPU control word here for compatibility with libraries +# written in other languages. + +proc raiseFloatInvalidOp {.noinline.} = + sysFatal(FloatInvalidOpError, "FPU operation caused a NaN result") + +proc nanCheck(x: float64) {.compilerproc, inline.} = + if x != x: raiseFloatInvalidOp() + +proc raiseFloatOverflow(x: float64) {.noinline.} = + if x > 0.0: + sysFatal(FloatOverflowError, "FPU operation caused an overflow") + else: + sysFatal(FloatUnderflowError, "FPU operations caused an underflow") + +proc infCheck(x: float64) {.compilerproc, inline.} = + if x != 0.0 and x*0.5 == x: raiseFloatOverflow(x) diff --git a/lib/system/arithmetics.nim b/lib/system/arithmetics.nim index 5c21e56ef..ba9ade192 100644 --- a/lib/system/arithmetics.nim +++ b/lib/system/arithmetics.nim @@ -1,50 +1,157 @@ -proc succ*[T, V: Ordinal](x: T, y: V = 1): T {.magic: "Succ", noSideEffect.} = - ## Returns the `y`-th successor (default: 1) of the value `x`. +proc succ*[T: Ordinal](x: T, y = 1): T {.magic: "Succ", noSideEffect.} + ## Returns the ``y``-th successor (default: 1) of the value ``x``. + ## ``T`` has to be an `ordinal type <#Ordinal>`_. ## - ## If such a value does not exist, `OverflowDefect` is raised + ## If such a value does not exist, ``OverflowError`` is raised ## or a compile time error occurs. - runnableExamples: - assert succ(5) == 6 - assert succ(5, 3) == 8 - -proc pred*[T, V: Ordinal](x: T, y: V = 1): T {.magic: "Pred", noSideEffect.} = - ## Returns the `y`-th predecessor (default: 1) of the value `x`. ## - ## If such a value does not exist, `OverflowDefect` is raised + ## .. code-block:: Nim + ## let x = 5 + ## echo succ(5) # => 6 + ## echo succ(5, 3) # => 8 + +proc pred*[T: Ordinal](x: T, y = 1): T {.magic: "Pred", noSideEffect.} + ## Returns the ``y``-th predecessor (default: 1) of the value ``x``. + ## ``T`` has to be an `ordinal type <#Ordinal>`_. + ## + ## If such a value does not exist, ``OverflowError`` is raised ## or a compile time error occurs. - runnableExamples: - assert pred(5) == 4 - assert pred(5, 3) == 2 - -proc inc*[T, V: Ordinal](x: var T, y: V = 1) {.magic: "Inc", noSideEffect.} = - ## Increments the ordinal `x` by `y`. ## - ## If such a value does not exist, `OverflowDefect` is raised or a compile - ## time error occurs. This is a short notation for: `x = succ(x, y)`. - runnableExamples: - var i = 2 - inc(i) - assert i == 3 - inc(i, 3) - assert i == 6 + ## .. code-block:: Nim + ## let x = 5 + ## echo pred(5) # => 4 + ## echo pred(5, 3) # => 2 -proc dec*[T, V: Ordinal](x: var T, y: V = 1) {.magic: "Dec", noSideEffect.} = - ## Decrements the ordinal `x` by `y`. +proc inc*[T: Ordinal|uint|uint64](x: var T, y = 1) {.magic: "Inc", noSideEffect.} + ## Increments the ordinal ``x`` by ``y``. ## - ## If such a value does not exist, `OverflowDefect` is raised or a compile - ## time error occurs. This is a short notation for: `x = pred(x, y)`. - runnableExamples: - var i = 2 - dec(i) - assert i == 1 - dec(i, 3) - assert i == -2 + ## If such a value does not exist, ``OverflowError`` is raised or a compile + ## time error occurs. This is a short notation for: ``x = succ(x, y)``. + ## + ## .. code-block:: Nim + ## var i = 2 + ## inc(i) # i <- 3 + ## inc(i, 3) # i <- 6 + +proc dec*[T: Ordinal|uint|uint64](x: var T, y = 1) {.magic: "Dec", noSideEffect.} + ## Decrements the ordinal ``x`` by ``y``. + ## + ## If such a value does not exist, ``OverflowError`` is raised or a compile + ## time error occurs. This is a short notation for: ``x = pred(x, y)``. + ## + ## .. code-block:: Nim + ## var i = 2 + ## dec(i) # i <- 1 + ## dec(i, 3) # i <- -2 # -------------------------------------------------------------------------- # built-in operators +when defined(nimNoZeroExtendMagic): + proc ze*(x: int8): int {.deprecated.} = + ## zero extends a smaller integer type to ``int``. This treats `x` as + ## unsigned. + ## **Deprecated since version 0.19.9**: Use unsigned integers instead. + cast[int](uint(cast[uint8](x))) + + proc ze*(x: int16): int {.deprecated.} = + ## zero extends a smaller integer type to ``int``. This treats `x` as + ## unsigned. + ## **Deprecated since version 0.19.9**: Use unsigned integers instead. + cast[int](uint(cast[uint16](x))) + + proc ze64*(x: int8): int64 {.deprecated.} = + ## zero extends a smaller integer type to ``int64``. This treats `x` as + ## unsigned. + ## **Deprecated since version 0.19.9**: Use unsigned integers instead. + cast[int64](uint64(cast[uint8](x))) + + proc ze64*(x: int16): int64 {.deprecated.} = + ## zero extends a smaller integer type to ``int64``. This treats `x` as + ## unsigned. + ## **Deprecated since version 0.19.9**: Use unsigned integers instead. + cast[int64](uint64(cast[uint16](x))) + + proc ze64*(x: int32): int64 {.deprecated.} = + ## zero extends a smaller integer type to ``int64``. This treats `x` as + ## unsigned. + ## **Deprecated since version 0.19.9**: Use unsigned integers instead. + cast[int64](uint64(cast[uint32](x))) + + proc ze64*(x: int): int64 {.deprecated.} = + ## zero extends a smaller integer type to ``int64``. This treats `x` as + ## unsigned. Does nothing if the size of an ``int`` is the same as ``int64``. + ## (This is the case on 64 bit processors.) + ## **Deprecated since version 0.19.9**: Use unsigned integers instead. + cast[int64](uint64(cast[uint](x))) + + proc toU8*(x: int): int8 {.deprecated.} = + ## treats `x` as unsigned and converts it to a byte by taking the last 8 bits + ## from `x`. + ## **Deprecated since version 0.19.9**: Use unsigned integers instead. + cast[int8](x) + + proc toU16*(x: int): int16 {.deprecated.} = + ## treats `x` as unsigned and converts it to an ``int16`` by taking the last + ## 16 bits from `x`. + ## **Deprecated since version 0.19.9**: Use unsigned integers instead. + cast[int16](x) + + proc toU32*(x: int64): int32 {.deprecated.} = + ## treats `x` as unsigned and converts it to an ``int32`` by taking the + ## last 32 bits from `x`. + ## **Deprecated since version 0.19.9**: Use unsigned integers instead. + cast[int32](x) + +elif not defined(js): + proc ze*(x: int8): int {.magic: "Ze8ToI", noSideEffect, deprecated.} + ## zero extends a smaller integer type to ``int``. This treats `x` as + ## unsigned. + ## **Deprecated since version 0.19.9**: Use unsigned integers instead. + + proc ze*(x: int16): int {.magic: "Ze16ToI", noSideEffect, deprecated.} + ## zero extends a smaller integer type to ``int``. This treats `x` as + ## unsigned. + ## **Deprecated since version 0.19.9**: Use unsigned integers instead. + + proc ze64*(x: int8): int64 {.magic: "Ze8ToI64", noSideEffect, deprecated.} + ## zero extends a smaller integer type to ``int64``. This treats `x` as + ## unsigned. + ## **Deprecated since version 0.19.9**: Use unsigned integers instead. + + proc ze64*(x: int16): int64 {.magic: "Ze16ToI64", noSideEffect, deprecated.} + ## zero extends a smaller integer type to ``int64``. This treats `x` as + ## unsigned. + ## **Deprecated since version 0.19.9**: Use unsigned integers instead. + + proc ze64*(x: int32): int64 {.magic: "Ze32ToI64", noSideEffect, deprecated.} + ## zero extends a smaller integer type to ``int64``. This treats `x` as + ## unsigned. + ## **Deprecated since version 0.19.9**: Use unsigned integers instead. + + proc ze64*(x: int): int64 {.magic: "ZeIToI64", noSideEffect, deprecated.} + ## zero extends a smaller integer type to ``int64``. This treats `x` as + ## unsigned. Does nothing if the size of an ``int`` is the same as ``int64``. + ## (This is the case on 64 bit processors.) + ## **Deprecated since version 0.19.9**: Use unsigned integers instead. + + proc toU8*(x: int): int8 {.magic: "ToU8", noSideEffect, deprecated.} + ## treats `x` as unsigned and converts it to a byte by taking the last 8 bits + ## from `x`. + ## **Deprecated since version 0.19.9**: Use unsigned integers instead. + + proc toU16*(x: int): int16 {.magic: "ToU16", noSideEffect, deprecated.} + ## treats `x` as unsigned and converts it to an ``int16`` by taking the last + ## 16 bits from `x`. + ## **Deprecated since version 0.19.9**: Use unsigned integers instead. + + proc toU32*(x: int64): int32 {.magic: "ToU32", noSideEffect, deprecated.} + ## treats `x` as unsigned and converts it to an ``int32`` by taking the + ## last 32 bits from `x`. + ## **Deprecated since version 0.19.9**: Use unsigned integers instead. + # integer calculations: proc `+`*(x: int): int {.magic: "UnaryPlusI", noSideEffect.} ## Unary `+` operator for an integer. Has no effect. @@ -60,13 +167,20 @@ proc `-`*(x: int16): int16 {.magic: "UnaryMinusI", noSideEffect.} proc `-`*(x: int32): int32 {.magic: "UnaryMinusI", noSideEffect.} proc `-`*(x: int64): int64 {.magic: "UnaryMinusI64", noSideEffect.} -proc `not`*(x: int): int {.magic: "BitnotI", noSideEffect.} = +proc `not`*(x: int): int {.magic: "BitnotI", noSideEffect.} ## Computes the `bitwise complement` of the integer `x`. - runnableExamples: - assert not 0'u8 == 255 - assert not 0'i8 == -1 - assert not 1000'u16 == 64535 - assert not 1000'i16 == -1001 + ## + ## .. code-block:: Nim + ## var + ## a = 0'u8 + ## b = 0'i8 + ## c = 1000'u16 + ## d = 1000'i16 + ## + ## echo not a # => 255 + ## echo not b # => -1 + ## echo not c # => 64535 + ## echo not d # => -1001 proc `not`*(x: int8): int8 {.magic: "BitnotI", noSideEffect.} proc `not`*(x: int16): int16 {.magic: "BitnotI", noSideEffect.} proc `not`*(x: int32): int32 {.magic: "BitnotI", noSideEffect.} @@ -93,38 +207,40 @@ proc `*`*(x, y: int16): int16 {.magic: "MulI", noSideEffect.} proc `*`*(x, y: int32): int32 {.magic: "MulI", noSideEffect.} proc `*`*(x, y: int64): int64 {.magic: "MulI", noSideEffect.} -proc `div`*(x, y: int): int {.magic: "DivI", noSideEffect.} = +proc `div`*(x, y: int): int {.magic: "DivI", noSideEffect.} ## Computes the integer division. ## - ## This is roughly the same as `math.trunc(x/y).int`. - runnableExamples: - assert (1 div 2) == 0 - assert (2 div 2) == 1 - assert (3 div 2) == 1 - assert (7 div 3) == 2 - assert (-7 div 3) == -2 - assert (7 div -3) == -2 - assert (-7 div -3) == 2 + ## This is roughly the same as ``trunc(x/y)``. + ## + ## .. code-block:: Nim + ## ( 1 div 2) == 0 + ## ( 2 div 2) == 1 + ## ( 3 div 2) == 1 + ## ( 7 div 3) == 2 + ## (-7 div 3) == -2 + ## ( 7 div -3) == -2 + ## (-7 div -3) == 2 proc `div`*(x, y: int8): int8 {.magic: "DivI", noSideEffect.} proc `div`*(x, y: int16): int16 {.magic: "DivI", noSideEffect.} proc `div`*(x, y: int32): int32 {.magic: "DivI", noSideEffect.} proc `div`*(x, y: int64): int64 {.magic: "DivI", noSideEffect.} -proc `mod`*(x, y: int): int {.magic: "ModI", noSideEffect.} = +proc `mod`*(x, y: int): int {.magic: "ModI", noSideEffect.} ## Computes the integer modulo operation (remainder). ## - ## This is the same as `x - (x div y) * y`. - runnableExamples: - assert (7 mod 5) == 2 - assert (-7 mod 5) == -2 - assert (7 mod -5) == 2 - assert (-7 mod -5) == -2 + ## This is the same as ``x - (x div y) * y``. + ## + ## .. code-block:: Nim + ## ( 7 mod 5) == 2 + ## (-7 mod 5) == -2 + ## ( 7 mod -5) == 2 + ## (-7 mod -5) == -2 proc `mod`*(x, y: int8): int8 {.magic: "ModI", noSideEffect.} proc `mod`*(x, y: int16): int16 {.magic: "ModI", noSideEffect.} proc `mod`*(x, y: int32): int32 {.magic: "ModI", noSideEffect.} proc `mod`*(x, y: int64): int64 {.magic: "ModI", noSideEffect.} -when defined(nimOldShiftRight): +when defined(nimOldShiftRight) or not defined(nimAshr): const shrDepMessage = "`shr` will become sign preserving." proc `shr`*(x: int, y: SomeInteger): int {.magic: "ShrI", noSideEffect, deprecated: shrDepMessage.} proc `shr`*(x: int8, y: SomeInteger): int8 {.magic: "ShrI", noSideEffect, deprecated: shrDepMessage.} @@ -132,7 +248,7 @@ when defined(nimOldShiftRight): proc `shr`*(x: int32, y: SomeInteger): int32 {.magic: "ShrI", noSideEffect, deprecated: shrDepMessage.} proc `shr`*(x: int64, y: SomeInteger): int64 {.magic: "ShrI", noSideEffect, deprecated: shrDepMessage.} else: - proc `shr`*(x: int, y: SomeInteger): int {.magic: "AshrI", noSideEffect.} = + proc `shr`*(x: int, y: SomeInteger): int {.magic: "AshrI", noSideEffect.} ## Computes the `shift right` operation of `x` and `y`, filling ## vacant bit positions with the sign bit. ## @@ -140,82 +256,131 @@ else: ## is different than in *C*. ## ## See also: - ## * `ashr func<#ashr,int,SomeInteger>`_ for arithmetic shift right - runnableExamples: - assert 0b0001_0000'i8 shr 2 == 0b0000_0100'i8 - assert 0b0000_0001'i8 shr 1 == 0b0000_0000'i8 - assert 0b1000_0000'i8 shr 4 == 0b1111_1000'i8 - assert -1 shr 5 == -1 - assert 1 shr 5 == 0 - assert 16 shr 2 == 4 - assert -16 shr 2 == -4 + ## * `ashr proc <#ashr,int,SomeInteger>`_ for arithmetic shift right + ## + ## .. code-block:: Nim + ## 0b0001_0000'i8 shr 2 == 0b0000_0100'i8 + ## 0b0000_0001'i8 shr 1 == 0b0000_0000'i8 + ## 0b1000_0000'i8 shr 4 == 0b1111_1000'i8 + ## -1 shr 5 == -1 + ## 1 shr 5 == 0 + ## 16 shr 2 == 4 + ## -16 shr 2 == -4 proc `shr`*(x: int8, y: SomeInteger): int8 {.magic: "AshrI", noSideEffect.} proc `shr`*(x: int16, y: SomeInteger): int16 {.magic: "AshrI", noSideEffect.} proc `shr`*(x: int32, y: SomeInteger): int32 {.magic: "AshrI", noSideEffect.} proc `shr`*(x: int64, y: SomeInteger): int64 {.magic: "AshrI", noSideEffect.} -proc `shl`*(x: int, y: SomeInteger): int {.magic: "ShlI", noSideEffect.} = +proc `shl`*(x: int, y: SomeInteger): int {.magic: "ShlI", noSideEffect.} ## Computes the `shift left` operation of `x` and `y`. ## ## **Note**: `Operator precedence `_ ## is different than in *C*. - runnableExamples: - assert 1'i32 shl 4 == 0x0000_0010 - assert 1'i64 shl 4 == 0x0000_0000_0000_0010 + ## + ## .. code-block:: Nim + ## 1'i32 shl 4 == 0x0000_0010 + ## 1'i64 shl 4 == 0x0000_0000_0000_0010 proc `shl`*(x: int8, y: SomeInteger): int8 {.magic: "ShlI", noSideEffect.} proc `shl`*(x: int16, y: SomeInteger): int16 {.magic: "ShlI", noSideEffect.} proc `shl`*(x: int32, y: SomeInteger): int32 {.magic: "ShlI", noSideEffect.} proc `shl`*(x: int64, y: SomeInteger): int64 {.magic: "ShlI", noSideEffect.} -proc ashr*(x: int, y: SomeInteger): int {.magic: "AshrI", noSideEffect.} = - ## Shifts right by pushing copies of the leftmost bit in from the left, - ## and let the rightmost bits fall off. - ## - ## Note that `ashr` is not an operator so use the normal function - ## call syntax for it. - ## - ## See also: - ## * `shr func<#shr,int,SomeInteger>`_ - runnableExamples: - assert ashr(0b0001_0000'i8, 2) == 0b0000_0100'i8 - assert ashr(0b1000_0000'i8, 8) == 0b1111_1111'i8 - assert ashr(0b1000_0000'i8, 1) == 0b1100_0000'i8 -proc ashr*(x: int8, y: SomeInteger): int8 {.magic: "AshrI", noSideEffect.} -proc ashr*(x: int16, y: SomeInteger): int16 {.magic: "AshrI", noSideEffect.} -proc ashr*(x: int32, y: SomeInteger): int32 {.magic: "AshrI", noSideEffect.} -proc ashr*(x: int64, y: SomeInteger): int64 {.magic: "AshrI", noSideEffect.} +when defined(nimAshr): + proc ashr*(x: int, y: SomeInteger): int {.magic: "AshrI", noSideEffect.} + ## Shifts right by pushing copies of the leftmost bit in from the left, + ## and let the rightmost bits fall off. + ## + ## Note that `ashr` is not an operator so use the normal function + ## call syntax for it. + ## + ## See also: + ## * `shr proc <#shr,int,SomeInteger>`_ + ## + ## .. code-block:: Nim + ## ashr(0b0001_0000'i8, 2) == 0b0000_0100'i8 + ## ashr(0b1000_0000'i8, 8) == 0b1111_1111'i8 + ## ashr(0b1000_0000'i8, 1) == 0b1100_0000'i8 + proc ashr*(x: int8, y: SomeInteger): int8 {.magic: "AshrI", noSideEffect.} + proc ashr*(x: int16, y: SomeInteger): int16 {.magic: "AshrI", noSideEffect.} + proc ashr*(x: int32, y: SomeInteger): int32 {.magic: "AshrI", noSideEffect.} + proc ashr*(x: int64, y: SomeInteger): int64 {.magic: "AshrI", noSideEffect.} +else: + # used for bootstrapping the compiler + proc ashr*[T](x: T, y: SomeInteger): T = discard -proc `and`*(x, y: int): int {.magic: "BitandI", noSideEffect.} = +proc `and`*(x, y: int): int {.magic: "BitandI", noSideEffect.} ## Computes the `bitwise and` of numbers `x` and `y`. - runnableExamples: - assert (0b0011 and 0b0101) == 0b0001 - assert (0b0111 and 0b1100) == 0b0100 + ## + ## .. code-block:: Nim + ## (0b0011 and 0b0101) == 0b0001 + ## (0b0111 and 0b1100) == 0b0100 proc `and`*(x, y: int8): int8 {.magic: "BitandI", noSideEffect.} proc `and`*(x, y: int16): int16 {.magic: "BitandI", noSideEffect.} proc `and`*(x, y: int32): int32 {.magic: "BitandI", noSideEffect.} proc `and`*(x, y: int64): int64 {.magic: "BitandI", noSideEffect.} -proc `or`*(x, y: int): int {.magic: "BitorI", noSideEffect.} = +proc `or`*(x, y: int): int {.magic: "BitorI", noSideEffect.} ## Computes the `bitwise or` of numbers `x` and `y`. - runnableExamples: - assert (0b0011 or 0b0101) == 0b0111 - assert (0b0111 or 0b1100) == 0b1111 + ## + ## .. code-block:: Nim + ## (0b0011 or 0b0101) == 0b0111 + ## (0b0111 or 0b1100) == 0b1111 proc `or`*(x, y: int8): int8 {.magic: "BitorI", noSideEffect.} proc `or`*(x, y: int16): int16 {.magic: "BitorI", noSideEffect.} proc `or`*(x, y: int32): int32 {.magic: "BitorI", noSideEffect.} proc `or`*(x, y: int64): int64 {.magic: "BitorI", noSideEffect.} -proc `xor`*(x, y: int): int {.magic: "BitxorI", noSideEffect.} = +proc `xor`*(x, y: int): int {.magic: "BitxorI", noSideEffect.} ## Computes the `bitwise xor` of numbers `x` and `y`. - runnableExamples: - assert (0b0011 xor 0b0101) == 0b0110 - assert (0b0111 xor 0b1100) == 0b1011 + ## + ## .. code-block:: Nim + ## (0b0011 xor 0b0101) == 0b0110 + ## (0b0111 xor 0b1100) == 0b1011 proc `xor`*(x, y: int8): int8 {.magic: "BitxorI", noSideEffect.} proc `xor`*(x, y: int16): int16 {.magic: "BitxorI", noSideEffect.} proc `xor`*(x, y: int32): int32 {.magic: "BitxorI", noSideEffect.} proc `xor`*(x, y: int64): int64 {.magic: "BitxorI", noSideEffect.} +type + IntMax32 = int|int8|int16|int32 + +proc `+%`*(x, y: IntMax32): IntMax32 {.magic: "AddU", noSideEffect.} +proc `+%`*(x, y: int64): int64 {.magic: "AddU", noSideEffect.} + ## Treats `x` and `y` as unsigned and adds them. + ## + ## The result is truncated to fit into the result. + ## This implements modulo arithmetic. No overflow errors are possible. + +proc `-%`*(x, y: IntMax32): IntMax32 {.magic: "SubU", noSideEffect.} +proc `-%`*(x, y: int64): int64 {.magic: "SubU", noSideEffect.} + ## Treats `x` and `y` as unsigned and subtracts them. + ## + ## The result is truncated to fit into the result. + ## This implements modulo arithmetic. No overflow errors are possible. + +proc `*%`*(x, y: IntMax32): IntMax32 {.magic: "MulU", noSideEffect.} +proc `*%`*(x, y: int64): int64 {.magic: "MulU", noSideEffect.} + ## Treats `x` and `y` as unsigned and multiplies them. + ## + ## The result is truncated to fit into the result. + ## This implements modulo arithmetic. No overflow errors are possible. + +proc `/%`*(x, y: IntMax32): IntMax32 {.magic: "DivU", noSideEffect.} +proc `/%`*(x, y: int64): int64 {.magic: "DivU", noSideEffect.} + ## Treats `x` and `y` as unsigned and divides them. + ## + ## The result is truncated to fit into the result. + ## This implements modulo arithmetic. No overflow errors are possible. + +proc `%%`*(x, y: IntMax32): IntMax32 {.magic: "ModU", noSideEffect.} +proc `%%`*(x, y: int64): int64 {.magic: "ModU", noSideEffect.} + ## Treats `x` and `y` as unsigned and compute the modulo of `x` and `y`. + ## + ## The result is truncated to fit into the result. + ## This implements modulo arithmetic. No overflow errors are possible. + + # unsigned integer operations: proc `not`*(x: uint): uint {.magic: "BitnotI", noSideEffect.} ## Computes the `bitwise complement` of the integer `x`. @@ -282,7 +447,7 @@ proc `*`*(x, y: uint64): uint64 {.magic: "MulU", noSideEffect.} proc `div`*(x, y: uint): uint {.magic: "DivU", noSideEffect.} ## Computes the integer division for unsigned integers. - ## This is roughly the same as `trunc(x/y)`. + ## This is roughly the same as ``trunc(x/y)``. proc `div`*(x, y: uint8): uint8 {.magic: "DivU", noSideEffect.} proc `div`*(x, y: uint16): uint16 {.magic: "DivU", noSideEffect.} proc `div`*(x, y: uint32): uint32 {.magic: "DivU", noSideEffect.} @@ -290,172 +455,32 @@ proc `div`*(x, y: uint64): uint64 {.magic: "DivU", noSideEffect.} proc `mod`*(x, y: uint): uint {.magic: "ModU", noSideEffect.} ## Computes the integer modulo operation (remainder) for unsigned integers. - ## This is the same as `x - (x div y) * y`. + ## This is the same as ``x - (x div y) * y``. proc `mod`*(x, y: uint8): uint8 {.magic: "ModU", noSideEffect.} proc `mod`*(x, y: uint16): uint16 {.magic: "ModU", noSideEffect.} proc `mod`*(x, y: uint32): uint32 {.magic: "ModU", noSideEffect.} proc `mod`*(x, y: uint64): uint64 {.magic: "ModU", noSideEffect.} + + + proc `+=`*[T: SomeInteger](x: var T, y: T) {. magic: "Inc", noSideEffect.} ## Increments an integer. +proc `+=`*[T: enum|bool](x: var T, y: T) {. + magic: "Inc", noSideEffect, deprecated: "use `inc` instead".} + ## **Deprecated since v0.20**: use `inc` instead. + proc `-=`*[T: SomeInteger](x: var T, y: T) {. magic: "Dec", noSideEffect.} ## Decrements an integer. +proc `-=`*[T: enum|bool](x: var T, y: T) {. + magic: "Dec", noSideEffect, deprecated: "0.20.0, use `dec` instead".} + ## **Deprecated since v0.20**: use `dec` instead. + proc `*=`*[T: SomeInteger](x: var T, y: T) {. inline, noSideEffect.} = ## Binary `*=` operator for integers. x = x * y - -# floating point operations: -proc `+`*(x: float32): float32 {.magic: "UnaryPlusF64", noSideEffect.} -proc `-`*(x: float32): float32 {.magic: "UnaryMinusF64", noSideEffect.} -proc `+`*(x, y: float32): float32 {.magic: "AddF64", noSideEffect.} -proc `-`*(x, y: float32): float32 {.magic: "SubF64", noSideEffect.} -proc `*`*(x, y: float32): float32 {.magic: "MulF64", noSideEffect.} -proc `/`*(x, y: float32): float32 {.magic: "DivF64", noSideEffect.} - -proc `+`*(x: float): float {.magic: "UnaryPlusF64", noSideEffect.} -proc `-`*(x: float): float {.magic: "UnaryMinusF64", noSideEffect.} -proc `+`*(x, y: float): float {.magic: "AddF64", noSideEffect.} -proc `-`*(x, y: float): float {.magic: "SubF64", noSideEffect.} -proc `*`*(x, y: float): float {.magic: "MulF64", noSideEffect.} -proc `/`*(x, y: float): float {.magic: "DivF64", noSideEffect.} - -proc `+=`*[T: float|float32|float64] (x: var T, y: T) {. - inline, noSideEffect.} = - ## Increments in place a floating point number. - x = x + y - -proc `-=`*[T: float|float32|float64] (x: var T, y: T) {. - inline, noSideEffect.} = - ## Decrements in place a floating point number. - x = x - y - -proc `*=`*[T: float|float32|float64] (x: var T, y: T) {. - inline, noSideEffect.} = - ## Multiplies in place a floating point number. - x = x * y - -proc `/=`*(x: var float64, y: float64) {.inline, noSideEffect.} = - ## Divides in place a floating point number. - x = x / y - -proc `/=`*[T: float|float32](x: var T, y: T) {.inline, noSideEffect.} = - ## Divides in place a floating point number. - x = x / y - -# the following have to be included in system, not imported for some reason: - -proc `+%`*(x, y: int): int {.inline.} = - ## Treats `x` and `y` as unsigned and adds them. - ## - ## The result is truncated to fit into the result. - ## This implements modulo arithmetic. No overflow errors are possible. - cast[int](cast[uint](x) + cast[uint](y)) -proc `+%`*(x, y: int8): int8 {.inline.} = cast[int8](cast[uint8](x) + cast[uint8](y)) -proc `+%`*(x, y: int16): int16 {.inline.} = cast[int16](cast[uint16](x) + cast[uint16](y)) -proc `+%`*(x, y: int32): int32 {.inline.} = cast[int32](cast[uint32](x) + cast[uint32](y)) -proc `+%`*(x, y: int64): int64 {.inline.} = cast[int64](cast[uint64](x) + cast[uint64](y)) - -proc `-%`*(x, y: int): int {.inline.} = - ## Treats `x` and `y` as unsigned and subtracts them. - ## - ## The result is truncated to fit into the result. - ## This implements modulo arithmetic. No overflow errors are possible. - cast[int](cast[uint](x) - cast[uint](y)) -proc `-%`*(x, y: int8): int8 {.inline.} = cast[int8](cast[uint8](x) - cast[uint8](y)) -proc `-%`*(x, y: int16): int16 {.inline.} = cast[int16](cast[uint16](x) - cast[uint16](y)) -proc `-%`*(x, y: int32): int32 {.inline.} = cast[int32](cast[uint32](x) - cast[uint32](y)) -proc `-%`*(x, y: int64): int64 {.inline.} = cast[int64](cast[uint64](x) - cast[uint64](y)) - -proc `*%`*(x, y: int): int {.inline.} = - ## Treats `x` and `y` as unsigned and multiplies them. - ## - ## The result is truncated to fit into the result. - ## This implements modulo arithmetic. No overflow errors are possible. - cast[int](cast[uint](x) * cast[uint](y)) -proc `*%`*(x, y: int8): int8 {.inline.} = cast[int8](cast[uint8](x) * cast[uint8](y)) -proc `*%`*(x, y: int16): int16 {.inline.} = cast[int16](cast[uint16](x) * cast[uint16](y)) -proc `*%`*(x, y: int32): int32 {.inline.} = cast[int32](cast[uint32](x) * cast[uint32](y)) -proc `*%`*(x, y: int64): int64 {.inline.} = cast[int64](cast[uint64](x) * cast[uint64](y)) - -proc `/%`*(x, y: int): int {.inline.} = - ## Treats `x` and `y` as unsigned and divides them. - ## - ## The result is truncated to fit into the result. - ## This implements modulo arithmetic. No overflow errors are possible. - cast[int](cast[uint](x) div cast[uint](y)) -proc `/%`*(x, y: int8): int8 {.inline.} = cast[int8](cast[uint8](x) div cast[uint8](y)) -proc `/%`*(x, y: int16): int16 {.inline.} = cast[int16](cast[uint16](x) div cast[uint16](y)) -proc `/%`*(x, y: int32): int32 {.inline.} = cast[int32](cast[uint32](x) div cast[uint32](y)) -proc `/%`*(x, y: int64): int64 {.inline.} = cast[int64](cast[uint64](x) div cast[uint64](y)) - -proc `%%`*(x, y: int): int {.inline.} = - ## Treats `x` and `y` as unsigned and compute the modulo of `x` and `y`. - ## - ## The result is truncated to fit into the result. - ## This implements modulo arithmetic. No overflow errors are possible. - cast[int](cast[uint](x) mod cast[uint](y)) -proc `%%`*(x, y: int8): int8 {.inline.} = cast[int8](cast[uint8](x) mod cast[uint8](y)) -proc `%%`*(x, y: int16): int16 {.inline.} = cast[int16](cast[uint16](x) mod cast[uint16](y)) -proc `%%`*(x, y: int32): int32 {.inline.} = cast[int32](cast[uint32](x) mod cast[uint32](y)) -proc `%%`*(x, y: int64): int64 {.inline.} = cast[int64](cast[uint64](x) mod cast[uint64](y)) - -when not defined(nimPreviewSlimSystem): - proc ze*(x: int8): int {.deprecated.} = - ## zero extends a smaller integer type to `int`. This treats `x` as - ## unsigned. - ## **Deprecated since version 0.19.9**: Use unsigned integers instead. - cast[int](uint(cast[uint8](x))) - - proc ze*(x: int16): int {.deprecated.} = - ## zero extends a smaller integer type to `int`. This treats `x` as - ## unsigned. - ## **Deprecated since version 0.19.9**: Use unsigned integers instead. - cast[int](uint(cast[uint16](x))) - - proc ze64*(x: int8): int64 {.deprecated.} = - ## zero extends a smaller integer type to `int64`. This treats `x` as - ## unsigned. - ## **Deprecated since version 0.19.9**: Use unsigned integers instead. - cast[int64](uint64(cast[uint8](x))) - - proc ze64*(x: int16): int64 {.deprecated.} = - ## zero extends a smaller integer type to `int64`. This treats `x` as - ## unsigned. - ## **Deprecated since version 0.19.9**: Use unsigned integers instead. - cast[int64](uint64(cast[uint16](x))) - - proc ze64*(x: int32): int64 {.deprecated.} = - ## zero extends a smaller integer type to `int64`. This treats `x` as - ## unsigned. - ## **Deprecated since version 0.19.9**: Use unsigned integers instead. - cast[int64](uint64(cast[uint32](x))) - - proc ze64*(x: int): int64 {.deprecated.} = - ## zero extends a smaller integer type to `int64`. This treats `x` as - ## unsigned. Does nothing if the size of an `int` is the same as `int64`. - ## (This is the case on 64 bit processors.) - ## **Deprecated since version 0.19.9**: Use unsigned integers instead. - cast[int64](uint64(cast[uint](x))) - - proc toU8*(x: int): int8 {.deprecated.} = - ## treats `x` as unsigned and converts it to a byte by taking the last 8 bits - ## from `x`. - ## **Deprecated since version 0.19.9**: Use unsigned integers instead. - cast[int8](x) - - proc toU16*(x: int): int16 {.deprecated.} = - ## treats `x` as unsigned and converts it to an `int16` by taking the last - ## 16 bits from `x`. - ## **Deprecated since version 0.19.9**: Use unsigned integers instead. - cast[int16](x) - - proc toU32*(x: int64): int32 {.deprecated.} = - ## treats `x` as unsigned and converts it to an `int32` by taking the - ## last 32 bits from `x`. - ## **Deprecated since version 0.19.9**: Use unsigned integers instead. - cast[int32](x) diff --git a/lib/system/assertions.nim b/lib/system/assertions.nim new file mode 100644 index 000000000..cb1f3fd40 --- /dev/null +++ b/lib/system/assertions.nim @@ -0,0 +1,101 @@ +when not declared(sysFatal): + include "system/fatal" + +# --------------------------------------------------------------------------- +# helpers + +type InstantiationInfo = tuple[filename: string, line: int, column: int] + +proc `$`(x: int): string {.magic: "IntToStr", noSideEffect.} + +proc `$`(info: InstantiationInfo): string = + # The +1 is needed here + # instead of overriding `$` (and changing its meaning), consider explicit name. + info.filename & "(" & $info.line & ", " & $(info.column+1) & ")" + +# --------------------------------------------------------------------------- + + +proc raiseAssert*(msg: string) {.noinline, noreturn.} = + sysFatal(AssertionError, msg) + +proc failedAssertImpl*(msg: string) {.raises: [], tags: [].} = + # trick the compiler to not list ``AssertionError`` when called + # by ``assert``. + type Hide = proc (msg: string) {.noinline, raises: [], noSideEffect, + tags: [].} + Hide(raiseAssert)(msg) + +template assertImpl(cond: bool, msg: string, expr: string, enabled: static[bool]) = + when enabled: + const + loc = instantiationInfo(fullPaths = compileOption("excessiveStackTrace")) + ploc = $loc + bind instantiationInfo + mixin failedAssertImpl + {.line: loc.}: + if not cond: + failedAssertImpl(ploc & " `" & expr & "` " & msg) + +template assert*(cond: untyped, msg = "") = + ## Raises ``AssertionError`` with `msg` if `cond` is false. Note + ## that ``AssertionError`` is hidden from the effect system, so it doesn't + ## produce ``{.raises: [AssertionError].}``. This exception is only supposed + ## to be caught by unit testing frameworks. + ## + ## The compiler may not generate any code at all for ``assert`` if it is + ## advised to do so through the ``-d:danger`` or ``--assertions:off`` + ## `command line switches `_. + const expr = astToStr(cond) + assertImpl(cond, msg, expr, compileOption("assertions")) + +template doAssert*(cond: untyped, msg = "") = + ## Similar to ``assert`` but is always turned on regardless of ``--assertions``. + const expr = astToStr(cond) + assertImpl(cond, msg, expr, true) + +template onFailedAssert*(msg, code: untyped): untyped {.dirty.} = + ## Sets an assertion failure handler that will intercept any assert + ## statements following `onFailedAssert` in the current module scope. + ## + ## .. code-block:: nim + ## # module-wide policy to change the failed assert + ## # exception type in order to include a lineinfo + ## onFailedAssert(msg): + ## var e = new(TMyError) + ## e.msg = msg + ## e.lineinfo = instantiationInfo(-2) + ## raise e + ## + template failedAssertImpl(msgIMPL: string): untyped {.dirty.} = + let msg = msgIMPL + code + +template doAssertRaises*(exception: typedesc, code: untyped) = + ## Raises ``AssertionError`` if specified ``code`` does not raise the + ## specified exception. Example: + ## + ## .. code-block:: nim + ## doAssertRaises(ValueError): + ## raise newException(ValueError, "Hello World") + var wrong = false + when Exception is exception: + try: + if true: + code + wrong = true + except Exception: + discard + else: + try: + if true: + code + wrong = true + except exception: + discard + except Exception: + raiseAssert(astToStr(exception) & + " wasn't raised, another error was raised instead by:\n"& + astToStr(code)) + if wrong: + raiseAssert(astToStr(exception) & " wasn't raised by:\n" & astToStr(code)) diff --git a/lib/system/assign.nim b/lib/system/assign.nim index 42587929c..39ff9d743 100644 --- a/lib/system/assign.nim +++ b/lib/system/assign.nim @@ -7,16 +7,14 @@ # distribution, for details about the copyright. # -include seqs_v2_reimpl - proc genericResetAux(dest: pointer, n: ptr TNimNode) {.benign.} proc genericAssignAux(dest, src: pointer, mt: PNimType, shallow: bool) {.benign.} proc genericAssignAux(dest, src: pointer, n: ptr TNimNode, shallow: bool) {.benign.} = var - d = cast[int](dest) - s = cast[int](src) + d = cast[ByteAddress](dest) + s = cast[ByteAddress](src) case n.kind of nkSlot: genericAssignAux(cast[pointer](d +% n.offset), @@ -40,67 +38,46 @@ proc genericAssignAux(dest, src: pointer, n: ptr TNimNode, # echo "ugh memory corruption! ", n.kind # quit 1 -template deepSeqAssignImpl(operation, additionalArg) {.dirty.} = - var d = cast[ptr NimSeqV2Reimpl](dest) - var s = cast[ptr NimSeqV2Reimpl](src) - d.len = s.len - let elem = mt.base - d.p = cast[ptr NimSeqPayloadReimpl](newSeqPayload(s.len, elem.size, elem.align)) - - let bs = elem.size - let ba = elem.align - let headerSize = align(sizeof(NimSeqPayloadBase), ba) - - for i in 0..d.len-1: - operation(d.p +! (headerSize+i*bs), s.p +! (headerSize+i*bs), mt.base, additionalArg) - proc genericAssignAux(dest, src: pointer, mt: PNimType, shallow: bool) = var - d = cast[int](dest) - s = cast[int](src) + d = cast[ByteAddress](dest) + s = cast[ByteAddress](src) sysAssert(mt != nil, "genericAssignAux 2") case mt.kind of tyString: - when defined(nimSeqsV2): - var x = cast[ptr NimStringV2](dest) - var s2 = cast[ptr NimStringV2](s)[] - nimAsgnStrV2(x[], s2) + var x = cast[PPointer](dest) + var s2 = cast[PPointer](s)[] + if s2 == nil or shallow or ( + cast[PGenericSeq](s2).reserved and seqShallowFlag) != 0: + unsureAsgnRef(x, s2) else: - var x = cast[PPointer](dest) - var s2 = cast[PPointer](s)[] - if s2 == nil or shallow or ( - cast[PGenericSeq](s2).reserved and seqShallowFlag) != 0: - unsureAsgnRef(x, s2) - else: - unsureAsgnRef(x, copyString(cast[NimString](s2))) + unsureAsgnRef(x, copyString(cast[NimString](s2))) of tySequence: - when defined(nimSeqsV2): - deepSeqAssignImpl(genericAssignAux, shallow) + var s2 = cast[PPointer](src)[] + var seq = cast[PGenericSeq](s2) + var x = cast[PPointer](dest) + if s2 == nil or shallow or (seq.reserved and seqShallowFlag) != 0: + # this can happen! nil sequences are allowed + unsureAsgnRef(x, s2) + return + sysAssert(dest != nil, "genericAssignAux 3") + if ntfNoRefs in mt.base.flags: + var ss = nimNewSeqOfCap(mt, seq.len) + cast[PGenericSeq](ss).len = seq.len + unsureAsgnRef(x, ss) + var dst = cast[ByteAddress](cast[PPointer](dest)[]) + copyMem(cast[pointer](dst +% GenericSeqSize), + cast[pointer](cast[ByteAddress](s2) +% GenericSeqSize), + seq.len * mt.base.size) else: - var s2 = cast[PPointer](src)[] - var seq = cast[PGenericSeq](s2) - var x = cast[PPointer](dest) - if s2 == nil or shallow or (seq.reserved and seqShallowFlag) != 0: - # this can happen! nil sequences are allowed - unsureAsgnRef(x, s2) - return - sysAssert(dest != nil, "genericAssignAux 3") - if ntfNoRefs in mt.base.flags: - var ss = nimNewSeqOfCap(mt, seq.len) - cast[PGenericSeq](ss).len = seq.len - unsureAsgnRef(x, ss) - var dst = cast[int](cast[PPointer](dest)[]) - copyMem(cast[pointer](dst +% align(GenericSeqSize, mt.base.align)), - cast[pointer](cast[int](s2) +% align(GenericSeqSize, mt.base.align)), - seq.len *% mt.base.size) - else: - unsureAsgnRef(x, newSeq(mt, seq.len)) - var dst = cast[int](cast[PPointer](dest)[]) - for i in 0..seq.len-1: - genericAssignAux( - cast[pointer](dst +% align(GenericSeqSize, mt.base.align) +% i *% mt.base.size ), - cast[pointer](cast[int](s2) +% align(GenericSeqSize, mt.base.align) +% i *% mt.base.size ), - mt.base, shallow) + unsureAsgnRef(x, newSeq(mt, seq.len)) + var dst = cast[ByteAddress](cast[PPointer](dest)[]) + for i in 0..seq.len-1: + genericAssignAux( + cast[pointer](dst +% i *% mt.base.size +% GenericSeqSize), + cast[pointer](cast[ByteAddress](s2) +% i *% mt.base.size +% + GenericSeqSize), + mt.base, shallow) of tyObject: var it = mt.base # don't use recursion here on the PNimType because the subtype @@ -111,23 +88,14 @@ proc genericAssignAux(dest, src: pointer, mt: PNimType, shallow: bool) = genericAssignAux(dest, src, mt.node, shallow) # we need to copy m_type field for tyObject, as it could be empty for # sequence reallocations: - when defined(nimSeqsV2): - var pint = cast[ptr PNimTypeV2](dest) - #chckObjAsgn(cast[ptr PNimTypeV2](src)[].typeInfoV2, mt) - pint[] = cast[PNimTypeV2](mt.typeInfoV2) - else: - var pint = cast[ptr PNimType](dest) - # We need to copy the *static* type not the dynamic type: - # if p of TB: - # var tbObj = TB(p) - # tbObj of TC # needs to be false! - #c_fprintf(stdout, "%s %s\n", pint[].name, mt.name) - let srcType = cast[ptr PNimType](src)[] - if srcType != nil: - # `!= nil` needed because of cases where object is not initialized properly (see bug #16706) - # note that you can have `srcType == nil` yet `src != nil` - chckObjAsgn(srcType, mt) - pint[] = mt # cast[ptr PNimType](src)[] + var pint = cast[ptr PNimType](dest) + # We need to copy the *static* type not the dynamic type: + # if p of TB: + # var tbObj = TB(p) + # tbObj of TC # needs to be false! + #c_fprintf(stdout, "%s %s\n", pint[].name, mt.name) + chckObjAsgn(cast[ptr PNimType](src)[], mt) + pint[] = mt # cast[ptr PNimType](src)[] of tyTuple: genericAssignAux(dest, src, mt.node, shallow) of tyArray, tyArrayConstr: @@ -167,7 +135,7 @@ when false: of tyPointer: k = "range" of tyOpenArray: k = "openarray" of tyString: k = "string" - of tyCstring: k = "cstring" + of tyCString: k = "cstring" of tyInt: k = "int" of tyInt32: k = "int32" else: k = "other" @@ -181,15 +149,15 @@ proc genericSeqAssign(dest, src: pointer, mt: PNimType) {.compilerproc.} = proc genericAssignOpenArray(dest, src: pointer, len: int, mt: PNimType) {.compilerproc.} = var - d = cast[int](dest) - s = cast[int](src) + d = cast[ByteAddress](dest) + s = cast[ByteAddress](src) for i in 0..len-1: genericAssign(cast[pointer](d +% i *% mt.base.size), cast[pointer](s +% i *% mt.base.size), mt.base) proc objectInit(dest: pointer, typ: PNimType) {.compilerproc, benign.} proc objectInitAux(dest: pointer, n: ptr TNimNode) {.benign.} = - var d = cast[int](dest) + var d = cast[ByteAddress](dest) case n.kind of nkNone: sysAssert(false, "objectInitAux") of nkSlot: objectInit(cast[pointer](d +% n.offset), n.typ) @@ -203,17 +171,13 @@ proc objectInitAux(dest: pointer, n: ptr TNimNode) {.benign.} = proc objectInit(dest: pointer, typ: PNimType) = # the generic init proc that takes care of initialization of complex # objects on the stack or heap - var d = cast[int](dest) + var d = cast[ByteAddress](dest) case typ.kind of tyObject: # iterate over any structural type # here we have to init the type field: - when defined(nimSeqsV2): - var pint = cast[ptr PNimTypeV2](dest) - pint[] = cast[PNimTypeV2](typ.typeInfoV2) - else: - var pint = cast[ptr PNimType](dest) - pint[] = typ + var pint = cast[ptr PNimType](dest) + pint[] = typ objectInitAux(dest, typ.node) of tyTuple: objectInitAux(dest, typ.node) @@ -226,7 +190,7 @@ proc objectInit(dest: pointer, typ: PNimType) = proc genericReset(dest: pointer, mt: PNimType) {.compilerproc, benign.} proc genericResetAux(dest: pointer, n: ptr TNimNode) = - var d = cast[int](dest) + var d = cast[ByteAddress](dest) case n.kind of nkNone: sysAssert(false, "genericResetAux") of nkSlot: genericReset(cast[pointer](d +% n.offset), n.typ) @@ -238,35 +202,18 @@ proc genericResetAux(dest: pointer, n: ptr TNimNode) = zeroMem(cast[pointer](d +% n.offset), n.typ.size) proc genericReset(dest: pointer, mt: PNimType) = - var d = cast[int](dest) + var d = cast[ByteAddress](dest) sysAssert(mt != nil, "genericReset 2") case mt.kind - of tyRef: + of tyString, tyRef, tySequence: unsureAsgnRef(cast[PPointer](dest), nil) - of tyString: - when defined(nimSeqsV2): - var s = cast[ptr NimStringV2](dest) - frees(s[]) - zeroMem(dest, mt.size) - else: - unsureAsgnRef(cast[PPointer](dest), nil) - of tySequence: - when defined(nimSeqsV2): - frees(cast[ptr NimSeqV2Reimpl](dest)[]) - zeroMem(dest, mt.size) - else: - unsureAsgnRef(cast[PPointer](dest), nil) of tyTuple: genericResetAux(dest, mt.node) of tyObject: genericResetAux(dest, mt.node) # also reset the type field for tyObject, for correct branch switching! - when defined(nimSeqsV2): - var pint = cast[ptr PNimTypeV2](dest) - pint[] = nil - else: - var pint = cast[ptr PNimType](dest) - pint[] = nil + var pint = cast[ptr PNimType](dest) + pint[] = nil of tyArray, tyArrayConstr: for i in 0..(mt.size div mt.base.size)-1: genericReset(cast[pointer](d +% i *% mt.base.size), mt.base) @@ -287,10 +234,10 @@ proc FieldDiscriminantCheck(oldDiscVal, newDiscVal: int, let newBranch = selectBranch(newDiscVal, L, a) when defined(nimOldCaseObjects): if newBranch != oldBranch and oldDiscVal != 0: - sysFatal(FieldDefect, "assignment to discriminant changes object branch") + sysFatal(FieldError, "assignment to discriminant changes object branch") else: if newBranch != oldBranch: if oldDiscVal != 0: - sysFatal(FieldDefect, "assignment to discriminant changes object branch") + sysFatal(FieldError, "assignment to discriminant changes object branch") else: - sysFatal(FieldDefect, "assignment to discriminant changes object branch; compile with -d:nimOldCaseObjects for a transition period") + sysFatal(FieldError, "assignment to discriminant changes object branch; compile with -d:nimOldCaseObjects for a transition period") diff --git a/lib/std/sysatomics.nim b/lib/system/atomics.nim similarity index 80% rename from lib/std/sysatomics.nim rename to lib/system/atomics.nim index 36a4e5537..146bb859f 100644 --- a/lib/std/sysatomics.nim +++ b/lib/system/atomics.nim @@ -7,22 +7,17 @@ # distribution, for details about the copyright. # -when defined(nimPreviewSlimSystem): - {.deprecated: "use `std/atomics` instead".} - # Atomic operations for Nim. {.push stackTrace:off, profiler:off.} -const - hasThreadSupport = compileOption("threads") and not defined(nimscript) -const someGcc = defined(gcc) or defined(llvm_gcc) or defined(clang) or defined(nintendoswitch) +const someGcc = defined(gcc) or defined(llvm_gcc) or defined(clang) const someVcc = defined(vcc) or defined(clang_cl) type AtomType* = SomeNumber|pointer|ptr|char|bool ## Type Class representing valid types for use with atomic procs -when someGcc: +when someGcc and hasThreadSupport: type AtomMemModel* = distinct cint var ATOMIC_RELAXED* {.importc: "__ATOMIC_RELAXED", nodecl.}: AtomMemModel @@ -78,7 +73,7 @@ when someGcc: proc atomicCompareExchangeN*[T: AtomType](p, expected: ptr T, desired: T, weak: bool, success_memmodel: AtomMemModel, failure_memmodel: AtomMemModel): bool {. - importc: "__atomic_compare_exchange_n", nodecl.} + importc: "__atomic_compare_exchange_n ", nodecl.} ## This proc implements an atomic compare and exchange operation. This compares the ## contents at p with the contents at expected and if equal, writes desired at p. ## If they are not equal, the current contents at p is written into expected. @@ -105,13 +100,13 @@ when someGcc: proc atomicSubFetch*[T: AtomType](p: ptr T, val: T, mem: AtomMemModel): T {. importc: "__atomic_sub_fetch", nodecl.} proc atomicOrFetch*[T: AtomType](p: ptr T, val: T, mem: AtomMemModel): T {. - importc: "__atomic_or_fetch", nodecl.} + importc: "__atomic_or_fetch ", nodecl.} proc atomicAndFetch*[T: AtomType](p: ptr T, val: T, mem: AtomMemModel): T {. importc: "__atomic_and_fetch", nodecl.} proc atomicXorFetch*[T: AtomType](p: ptr T, val: T, mem: AtomMemModel): T {. importc: "__atomic_xor_fetch", nodecl.} proc atomicNandFetch*[T: AtomType](p: ptr T, val: T, mem: AtomMemModel): T {. - importc: "__atomic_nand_fetch", nodecl.} + importc: "__atomic_nand_fetch ", nodecl.} ## Perform the operation return the old value, all memory models are valid proc atomicFetchAdd*[T: AtomType](p: ptr T, val: T, mem: AtomMemModel): T {. @@ -130,8 +125,8 @@ when someGcc: proc atomicTestAndSet*(p: pointer, mem: AtomMemModel): bool {. importc: "__atomic_test_and_set", nodecl.} ## This built-in function performs an atomic test-and-set operation on the byte at p. - ## The byte is set to some implementation defined nonzero "set" value and the return - ## value is true if and only if the previous contents were "set". + ## The byte is set to some implementation defined nonzero “set” value and the return + ## value is true if and only if the previous contents were “set”. ## All memory models are valid. proc atomicClear*(p: pointer, mem: AtomMemModel) {. @@ -169,48 +164,23 @@ when someGcc: ## ignore this parameter. template fence*() = atomicThreadFence(ATOMIC_SEQ_CST) -elif someVcc: +elif someVcc and hasThreadSupport: type AtomMemModel* = distinct cint const - ATOMIC_RELAXED* = 0.AtomMemModel - ATOMIC_CONSUME* = 1.AtomMemModel - ATOMIC_ACQUIRE* = 2.AtomMemModel - ATOMIC_RELEASE* = 3.AtomMemModel - ATOMIC_ACQ_REL* = 4.AtomMemModel - ATOMIC_SEQ_CST* = 5.AtomMemModel + ATOMIC_RELAXED = 0.AtomMemModel + ATOMIC_CONSUME = 1.AtomMemModel + ATOMIC_ACQUIRE = 2.AtomMemModel + ATOMIC_RELEASE = 3.AtomMemModel + ATOMIC_ACQ_REL = 4.AtomMemModel + ATOMIC_SEQ_CST = 5.AtomMemModel proc `==`(x1, x2: AtomMemModel): bool {.borrow.} - proc readBarrier() {.importc: "_ReadBarrier", header: "".} - proc writeBarrier() {.importc: "_WriteBarrier", header: "".} + proc readBarrier() {.importc: "_ReadBarrier", header: "".} + proc writeBarrier() {.importc: "_WriteBarrier", header: "".} proc fence*() {.importc: "_ReadWriteBarrier", header: "".} - when defined(cpp): - proc interlockedCompareExchange64(p: pointer; exchange, comparand: int64): int64 - {.importcpp: "_InterlockedCompareExchange64(static_cast(#), #, #)", header: "".} - proc interlockedCompareExchange32(p: pointer; exchange, comparand: int32): int32 - {.importcpp: "_InterlockedCompareExchange(static_cast(#), #, #)", header: "".} - proc interlockedCompareExchange8(p: pointer; exchange, comparand: byte): byte - {.importcpp: "_InterlockedCompareExchange8(static_cast(#), #, #)", header: "".} - proc interlockedExchange8(location: pointer; desired: int8): int8 {.importcpp: "_InterlockedExchange8(static_cast(#), #)", header: "".} - proc interlockedExchange16(location: pointer; desired: int16): int16 {.importcpp: "_InterlockedExchange16(static_cast(#), #)", header: "".} - proc interlockedExchange32(location: pointer; desired: int32): int32 {.importcpp: "_InterlockedExchange(static_cast(#), #)", header: "".} - proc interlockedExchange64(location: pointer; desired: int64): int64 {.importcpp: "_InterlockedExchange64(static_cast(#), #)", header: "".} - else: - proc interlockedCompareExchange64(p: pointer; exchange, comparand: int64): int64 - {.importc: "_InterlockedCompareExchange64", header: "".} - proc interlockedCompareExchange32(p: pointer; exchange, comparand: int32): int32 - {.importc: "_InterlockedCompareExchange", header: "".} - proc interlockedCompareExchange8(p: pointer; exchange, comparand: byte): byte - {.importc: "_InterlockedCompareExchange8", header: "".} - - proc interlockedExchange8(location: pointer; desired: int8): int8 {.importc: "_InterlockedExchange8", header: "".} - proc interlockedExchange16(location: pointer; desired: int16): int16 {.importc: "_InterlockedExchange16", header: "".} - proc interlockedExchange32(location: pointer; desired: int32): int32 {.importc: "_InterlockedExchange", header: "".} - proc interlockedExchange64(location: pointer; desired: int64): int64 {.importc: "_InterlockedExchange64", header: "".} - - template barrier(mem: AtomMemModel) = when mem == ATOMIC_RELAXED: discard elif mem == ATOMIC_CONSUME: readBarrier() @@ -219,28 +189,10 @@ elif someVcc: elif mem == ATOMIC_ACQ_REL: fence() elif mem == ATOMIC_SEQ_CST: fence() - proc atomicStoreN*[T: AtomType](p: ptr T, val: T, mem: static[AtomMemModel]) = - barrier(mem) - p[] = val - proc atomicLoadN*[T: AtomType](p: ptr T, mem: static[AtomMemModel]): T = result = p[] barrier(mem) - proc atomicCompareExchangeN*[T: ptr](p, expected: ptr T, desired: T, - weak: bool, success_memmodel: AtomMemModel, failure_memmodel: AtomMemModel): bool = - when sizeof(T) == 8: - interlockedCompareExchange64(p, cast[int64](desired), cast[int64](expected)) == - cast[int64](expected) - elif sizeof(T) == 4: - interlockedCompareExchange32(p, cast[int32](desired), cast[int32](expected)) == - cast[int32](expected) - - proc atomicExchangeN*[T: ptr](p: ptr T, val: T, mem: AtomMemModel): T = - when sizeof(T) == 8: - cast[T](interlockedExchange64(p, cast[int64](val))) - elif sizeof(T) == 4: - cast[T](interlockedExchange32(p, cast[int32](val))) when defined(cpp): when sizeof(int) == 8: proc addAndFetch*(p: ptr int, val: int): int {. @@ -263,10 +215,9 @@ else: inc(p[], val) result = p[] - -proc atomicInc*(memLoc: var int, x: int = 1): int {.inline, discardable, raises: [], tags: [].} = +proc atomicInc*(memLoc: var int, x: int = 1): int = when someGcc and hasThreadSupport: - result = atomicAddFetch(memLoc.addr, x, ATOMIC_SEQ_CST) + result = atomicAddFetch(memLoc.addr, x, ATOMIC_RELAXED) elif someVcc and hasThreadSupport: result = addAndFetch(memLoc.addr, x) inc(result, x) @@ -274,12 +225,12 @@ proc atomicInc*(memLoc: var int, x: int = 1): int {.inline, discardable, raises: inc(memLoc, x) result = memLoc -proc atomicDec*(memLoc: var int, x: int = 1): int {.inline, discardable, raises: [], tags: [].} = +proc atomicDec*(memLoc: var int, x: int = 1): int = when someGcc and hasThreadSupport: when declared(atomicSubFetch): - result = atomicSubFetch(memLoc.addr, x, ATOMIC_SEQ_CST) + result = atomicSubFetch(memLoc.addr, x, ATOMIC_RELAXED) else: - result = atomicAddFetch(memLoc.addr, -x, ATOMIC_SEQ_CST) + result = atomicAddFetch(memLoc.addr, -x, ATOMIC_RELAXED) elif someVcc and hasThreadSupport: result = addAndFetch(memLoc.addr, -x) dec(result, x) @@ -288,6 +239,21 @@ proc atomicDec*(memLoc: var int, x: int = 1): int {.inline, discardable, raises: result = memLoc when someVcc: + when defined(cpp): + proc interlockedCompareExchange64(p: pointer; exchange, comparand: int64): int64 + {.importcpp: "_InterlockedCompareExchange64(static_cast(#), #, #)", header: "".} + proc interlockedCompareExchange32(p: pointer; exchange, comparand: int32): int32 + {.importcpp: "_InterlockedCompareExchange(static_cast(#), #, #)", header: "".} + proc interlockedCompareExchange8(p: pointer; exchange, comparand: byte): byte + {.importcpp: "_InterlockedCompareExchange8(static_cast(#), #, #)", header: "".} + else: + proc interlockedCompareExchange64(p: pointer; exchange, comparand: int64): int64 + {.importc: "_InterlockedCompareExchange64", header: "".} + proc interlockedCompareExchange32(p: pointer; exchange, comparand: int32): int32 + {.importc: "_InterlockedCompareExchange", header: "".} + proc interlockedCompareExchange8(p: pointer; exchange, comparand: byte): byte + {.importc: "_InterlockedCompareExchange8", header: "".} + proc cas*[T: bool|int|ptr](p: ptr T; oldValue, newValue: T): bool = when sizeof(T) == 8: interlockedCompareExchange64(p, cast[int64](newValue), cast[int64](oldValue)) == @@ -315,7 +281,10 @@ static int __tcc_cas(int *ptr, int oldVal, int newVal) : "r" (newVal), "m" (*ptr), "a" (oldVal) : "memory"); - return ret; + if (ret) + return 0; + else + return 1; } """.} else: @@ -332,7 +301,10 @@ static int __tcc_cas(int *ptr, int oldVal, int newVal) : "r" (newVal), "m" (*ptr), "a" (oldVal) : "memory"); - return ret; + if (ret) + return 0; + else + return 1; } """.} diff --git a/lib/system/basic_types.nim b/lib/system/basic_types.nim index bf81b9b6a..39ad0a76c 100644 --- a/lib/system/basic_types.nim +++ b/lib/system/basic_types.nim @@ -11,45 +11,19 @@ type uint32* {.magic: UInt32.} ## Unsigned 32 bit integer type. uint64* {.magic: UInt64.} ## Unsigned 64 bit integer type. -type - float* {.magic: Float.} ## Default floating point type. - float32* {.magic: Float32.} ## 32 bit floating point type. - float64* {.magic: Float.} ## 64 bit floating point type. - -# 'float64' is now an alias to 'float'; this solves many problems - -type - char* {.magic: Char.} ## Built-in 8 bit character type (unsigned). - string* {.magic: String.} ## Built-in string type. - cstring* {.magic: Cstring.} ## Built-in cstring (*compatible string*) type. - pointer* {.magic: Pointer.} ## Built-in pointer type, use the `addr` - ## operator to get a pointer to a variable. - - typedesc* {.magic: TypeDesc.} ## Meta type to denote a type description. - -type - `ptr`*[T] {.magic: Pointer.} ## Built-in generic untraced pointer type. - `ref`*[T] {.magic: Pointer.} ## Built-in generic traced pointer type. - - `nil` {.magic: "Nil".} - - void* {.magic: "VoidType".} ## Meta type to denote the absence of any type. - auto* {.magic: Expr.} ## Meta type for automatic type determination. - any* {.deprecated: "Deprecated since v1.5; Use auto instead.".} = distinct auto ## Deprecated; Use `auto` instead. See https://github.com/nim-lang/RFCs/issues/281 - untyped* {.magic: Expr.} ## Meta type to denote an expression that - ## is not resolved (for templates). - typed* {.magic: Stmt.} ## Meta type to denote an expression that - ## is resolved (for templates). - type # we need to start a new type section here, so that ``0`` can have a type - bool* {.magic: "Bool".} = enum ## Built-in boolean type. + bool* {.magic: Bool.} = enum ## Built-in boolean type. false = 0, true = 1 const - on* = true ## Alias for `true`. - off* = false ## Alias for `false`. + on* = true ## Alias for ``true``. + off* = false ## Alias for ``false``. type + Ordinal*[T] {.magic: Ordinal.} ## Generic ordinal type. Includes integer, + ## bool, character, and enumeration types + ## as well as their subtypes. + SomeSignedInt* = int|int8|int16|int32|int64 ## Type class matching all signed integer types. @@ -59,35 +33,34 @@ type SomeInteger* = SomeSignedInt|SomeUnsignedInt ## Type class matching all integer types. - SomeFloat* = float|float32|float64 - ## Type class matching all floating point number types. - - SomeNumber* = SomeInteger|SomeFloat - ## Type class matching all number types. - SomeOrdinal* = int|int8|int16|int32|int64|bool|enum|uint|uint8|uint16|uint32|uint64 ## Type class matching all ordinal types; however this includes enums with - ## holes. See also `Ordinal` + ## holes. + + BiggestInt* = int64 + ## is an alias for the biggest signed integer type the Nim compiler + ## supports. Currently this is ``int64``, but it is platform-dependent + ## in general. {.push warning[GcMem]: off, warning[Uninit]: off.} {.push hints: off.} proc `not`*(x: bool): bool {.magic: "Not", noSideEffect.} - ## Boolean not; returns true if `x == false`. + ## Boolean not; returns true if ``x == false``. proc `and`*(x, y: bool): bool {.magic: "And", noSideEffect.} - ## Boolean `and`; returns true if `x == y == true` (if both arguments + ## Boolean ``and``; returns true if ``x == y == true`` (if both arguments ## are true). ## - ## Evaluation is lazy: if `x` is false, `y` will not even be evaluated. + ## Evaluation is lazy: if ``x`` is false, ``y`` will not even be evaluated. proc `or`*(x, y: bool): bool {.magic: "Or", noSideEffect.} - ## Boolean `or`; returns true if `not (not x and not y)` (if any of + ## Boolean ``or``; returns true if ``not (not x and not y)`` (if any of ## the arguments is true). ## - ## Evaluation is lazy: if `x` is true, `y` will not even be evaluated. + ## Evaluation is lazy: if ``x`` is true, ``y`` will not even be evaluated. proc `xor`*(x, y: bool): bool {.magic: "Xor", noSideEffect.} - ## Boolean `exclusive or`; returns true if `x != y` (if either argument + ## Boolean `exclusive or`; returns true if ``x != y`` (if either argument ## is true while the other is false). {.pop.} diff --git a/lib/system/bitmasks.nim b/lib/system/bitmasks.nim deleted file mode 100644 index 0663247c2..000000000 --- a/lib/system/bitmasks.nim +++ /dev/null @@ -1,39 +0,0 @@ -# -# -# Nim's Runtime Library -# (c) Copyright 2015 Andreas Rumpf -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# - -# Page size of the system; in most cases 4096 bytes. For exotic OS or -# CPU this needs to be changed: -const - PageShift = when defined(nimPage256) or defined(cpu16): 3 - elif defined(nimPage512): 9 - elif defined(nimPage1k): 10 - else: 12 # \ # my tests showed no improvements for using larger page sizes. - - PageSize = 1 shl PageShift - PageMask = PageSize-1 - - - MemAlign = # also minimal allocatable memory block - when defined(nimMemAlignTiny): 4 - elif defined(useMalloc): - when defined(amd64): 16 - else: 8 - else: 16 - - BitsPerPage = PageSize div MemAlign - UnitsPerPage = BitsPerPage div (sizeof(int)*8) - # how many ints do we need to describe a page: - # on 32 bit systems this is only 16 (!) - - TrunkShift = 9 - BitsPerTrunk = 1 shl TrunkShift # needs to be power of 2 and divisible by 64 - TrunkMask = BitsPerTrunk - 1 - IntsPerTrunk = BitsPerTrunk div (sizeof(int)*8) - IntShift = 5 + ord(sizeof(int) == 8) # 5 or 6, depending on int width - IntMask = 1 shl IntShift - 1 diff --git a/lib/system/cellseqs_v1.nim b/lib/system/cellseqs_v1.nim deleted file mode 100644 index 1952491b3..000000000 --- a/lib/system/cellseqs_v1.nim +++ /dev/null @@ -1,43 +0,0 @@ -# -# -# Nim's Runtime Library -# (c) Copyright 2019 Andreas Rumpf -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# - -# ------------------- cell seq handling --------------------------------------- - -type - PCellArray = ptr UncheckedArray[PCell] - CellSeq {.final, pure.} = object - len, cap: int - d: PCellArray - -proc contains(s: CellSeq, c: PCell): bool {.inline.} = - for i in 0 .. s.len-1: - if s.d[i] == c: return true - return false - -proc add(s: var CellSeq, c: PCell) {.inline.} = - if s.len >= s.cap: - s.cap = s.cap * 3 div 2 - var d = cast[PCellArray](alloc(s.cap * sizeof(PCell))) - copyMem(d, s.d, s.len * sizeof(PCell)) - dealloc(s.d) - s.d = d - # XXX: realloc? - s.d[s.len] = c - inc(s.len) - -proc init(s: var CellSeq, cap: int = 1024) = - s.len = 0 - s.cap = cap - s.d = cast[PCellArray](alloc0(cap * sizeof(PCell))) - -proc deinit(s: var CellSeq) = - dealloc(s.d) - s.d = nil - s.len = 0 - s.cap = 0 diff --git a/lib/system/cellseqs_v2.nim b/lib/system/cellseqs_v2.nim deleted file mode 100644 index 27be48d78..000000000 --- a/lib/system/cellseqs_v2.nim +++ /dev/null @@ -1,56 +0,0 @@ -# -# -# Nim's Runtime Library -# (c) Copyright 2019 Andreas Rumpf -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# - -# Cell seqs for cyclebreaker and cyclicrefs_v2. - -type - CellTuple[T] = (T, PNimTypeV2) - CellArray[T] = ptr UncheckedArray[CellTuple[T]] - CellSeq[T] = object - len, cap: int - d: CellArray[T] - -proc add[T](s: var CellSeq[T], c: T; t: PNimTypeV2) {.inline.} = - if s.len >= s.cap: - s.cap = s.cap * 3 div 2 - when compileOption("threads"): - var d = cast[CellArray[T]](allocShared(uint(s.cap * sizeof(CellTuple[T])))) - else: - var d = cast[CellArray[T]](alloc(s.cap * sizeof(CellTuple[T]))) - copyMem(d, s.d, s.len * sizeof(CellTuple[T])) - when compileOption("threads"): - deallocShared(s.d) - else: - dealloc(s.d) - s.d = d - # XXX: realloc? - s.d[s.len] = (c, t) - inc(s.len) - -proc init[T](s: var CellSeq[T], cap: int = 1024) = - s.len = 0 - s.cap = cap - when compileOption("threads"): - s.d = cast[CellArray[T]](allocShared(uint(s.cap * sizeof(CellTuple[T])))) - else: - s.d = cast[CellArray[T]](alloc(s.cap * sizeof(CellTuple[T]))) - -proc deinit[T](s: var CellSeq[T]) = - if s.d != nil: - when compileOption("threads"): - deallocShared(s.d) - else: - dealloc(s.d) - s.d = nil - s.len = 0 - s.cap = 0 - -proc pop[T](s: var CellSeq[T]): (T, PNimTypeV2) = - result = s.d[s.len-1] - dec s.len diff --git a/lib/system/cellsets.nim b/lib/system/cellsets.nim index a0f1fabf9..c73c84f52 100644 --- a/lib/system/cellsets.nim +++ b/lib/system/cellsets.nim @@ -7,64 +7,22 @@ # distribution, for details about the copyright. # - -#[ - -Efficient set of pointers for the GC (and repr) ------------------------------------------------ - -The GC depends on an extremely efficient datastructure for storing a -set of pointers - this is called a `CellSet` in the source code. -Inserting, deleting and searching are done in constant time. However, -modifying a `CellSet` during traversal leads to undefined behaviour. - -All operations on a CellSet have to perform efficiently. Because a Cellset can -become huge a hash table alone is not suitable for this. - -We use a mixture of bitset and hash table for this. The hash table maps *pages* -to a page descriptor. The page descriptor contains a bit for any possible cell -address within this page. So including a cell is done as follows: - -- Find the page descriptor for the page the cell belongs to. -- Set the appropriate bit in the page descriptor indicating that the - cell points to the start of a memory block. - -Removing a cell is analogous - the bit has to be set to zero. -Single page descriptors are never deleted from the hash table. This is not -needed as the data structures needs to be rebuilt periodically anyway. - -Complete traversal is done in this way:: - - for each page descriptor d: - for each bit in d: - if bit == 1: - traverse the pointer belonging to this bit - -]# - -when defined(gcOrc) or defined(gcArc): - type - PCell = Cell - - when not declaredInScope(PageShift): - include bitmasks - -else: - type - RefCount = int - - Cell {.pure.} = object - refcount: RefCount # the refcount and some flags - typ: PNimType - when trackAllocationSource: - filename: cstring - line: int - when useCellIds: - id: int - - PCell = ptr Cell +# Efficient set of pointers for the GC (and repr) type + RefCount = int + + Cell {.pure.} = object + refcount: RefCount # the refcount and some flags + typ: PNimType + when trackAllocationSource: + filename: cstring + line: int + when useCellIds: + id: int + + PCell = ptr Cell + PPageDesc = ptr PageDesc BitIndex = range[0..UnitsPerPage-1] PageDesc {.final, pure.} = object @@ -77,11 +35,39 @@ type counter, max: int head: PPageDesc data: PPageDescArray + PCellArray = ptr UncheckedArray[PCell] + CellSeq {.final, pure.} = object + len, cap: int + d: PCellArray -when defined(gcOrc) or defined(gcArc): - discard -else: - include cellseqs_v1 +# ------------------- cell seq handling --------------------------------------- + +proc contains(s: CellSeq, c: PCell): bool {.inline.} = + for i in 0 .. s.len-1: + if s.d[i] == c: return true + return false + +proc add(s: var CellSeq, c: PCell) {.inline.} = + if s.len >= s.cap: + s.cap = s.cap * 3 div 2 + var d = cast[PCellArray](alloc(s.cap * sizeof(PCell))) + copyMem(d, s.d, s.len * sizeof(PCell)) + dealloc(s.d) + s.d = d + # XXX: realloc? + s.d[s.len] = c + inc(s.len) + +proc init(s: var CellSeq, cap: int = 1024) = + s.len = 0 + s.cap = cap + s.d = cast[PCellArray](alloc0(cap * sizeof(PCell))) + +proc deinit(s: var CellSeq) = + dealloc(s.d) + s.d = nil + s.len = 0 + s.cap = 0 # ------------------- cell set handling --------------------------------------- diff --git a/lib/system/channels_builtin.nim b/lib/system/channels.nim similarity index 89% rename from lib/system/channels_builtin.nim rename to lib/system/channels.nim index e04f2a0db..65398d65c 100644 --- a/lib/system/channels_builtin.nim +++ b/lib/system/channels.nim @@ -10,10 +10,10 @@ ## Channel support for threads. ## ## **Note**: This is part of the system module. Do not import it directly. -## To activate thread support compile with the `--threads:on` command line switch. +## To activate thread support compile with the ``--threads:on`` command line switch. ## -## **Note:** Channels are designed for the `Thread` type. They are unstable when -## used with `spawn` +## **Note:** Channels are designed for the ``Thread`` type. They are unstable when +## used with ``spawn`` ## ## **Note:** The current implementation of message passing does ## not work with cyclic data structures. @@ -26,11 +26,11 @@ ## The following is a simple example of two different ways to use channels: ## blocking and non-blocking. ## -## .. code-block:: Nim +## .. code-block :: Nim ## # Be sure to compile with --threads:on. ## # The channels and threads modules are part of system and should not be ## # imported. -## import std/os +## import os ## ## # Channels can either be: ## # - declared at the module level, or @@ -91,18 +91,17 @@ ## Sample output ## ------------- ## The program should output something similar to this, but keep in mind that -## exact results may vary in the real world: -## -## Hello World! -## Pretend I'm doing useful work... -## Pretend I'm doing useful work... -## Pretend I'm doing useful work... -## Pretend I'm doing useful work... -## Pretend I'm doing useful work... -## Another message +## exact results may vary in the real world:: +## Hello World! +## Pretend I'm doing useful work... +## Pretend I'm doing useful work... +## Pretend I'm doing useful work... +## Pretend I'm doing useful work... +## Pretend I'm doing useful work... +## Another message ## ## Passing Channels Safely -## ----------------------- +## ---------------------- ## Note that when passing objects to procedures on another thread by pointer ## (for example through a thread's argument), objects created using the default ## allocator will use thread-local, GC-managed memory. Thus it is generally @@ -110,10 +109,10 @@ ## in which case they will use a process-wide (thread-safe) shared heap. ## ## However, it is possible to manually allocate shared memory for channels -## using e.g. `system.allocShared0` and pass these pointers through thread +## using e.g. ``system.allocShared0`` and pass these pointers through thread ## arguments: ## -## .. code-block:: Nim +## .. code-block :: Nim ## proc worker(channel: ptr Channel[string]) = ## let greeting = channel[].recv() ## echo greeting @@ -139,8 +138,6 @@ when not declared(ThisIsSystem): {.error: "You must not import this module explicitly".} -import std/private/syslocks - type pbytes = ptr UncheckedArray[byte] RawChannel {.pure, final.} = object ## msg queue for a thread @@ -154,7 +151,7 @@ type region: MemRegion PRawChannel = ptr RawChannel LoadStoreMode = enum mStore, mLoad - Channel*[TMsg] {.gcsafe.} = RawChannel ## a channel for thread communication + Channel* {.gcsafe.}[TMsg] = RawChannel ## a channel for thread communication const ChannelDeadMask = -2 @@ -185,8 +182,8 @@ when not usesDestructors: proc storeAux(dest, src: pointer, n: ptr TNimNode, t: PRawChannel, mode: LoadStoreMode) {.benign.} = var - d = cast[int](dest) - s = cast[int](src) + d = cast[ByteAddress](dest) + s = cast[ByteAddress](src) case n.kind of nkSlot: storeAux(cast[pointer](d +% n.offset), cast[pointer](s +% n.offset), n.typ, t, mode) @@ -205,8 +202,8 @@ when not usesDestructors: cast[pointer](cast[int](p) +% x) var - d = cast[int](dest) - s = cast[int](src) + d = cast[ByteAddress](dest) + s = cast[ByteAddress](src) sysAssert(mt != nil, "mt == nil") case mt.kind of tyString: @@ -217,7 +214,7 @@ when not usesDestructors: x[] = nil else: var ss = cast[NimString](s2) - var ns = cast[NimString](alloc(t.region, GenericSeqSize + ss.len+1)) + var ns = cast[NimString](alloc(t.region, ss.len+1 + GenericSeqSize)) copyMem(ns, ss, ss.len+1 + GenericSeqSize) x[] = ns else: @@ -242,18 +239,18 @@ when not usesDestructors: else: sysAssert(dest != nil, "dest == nil") if mode == mStore: - x[] = alloc0(t.region, align(GenericSeqSize, mt.base.align) +% seq.len *% mt.base.size) + x[] = alloc0(t.region, seq.len *% mt.base.size +% GenericSeqSize) else: unsureAsgnRef(x, newSeq(mt, seq.len)) - var dst = cast[int](cast[PPointer](dest)[]) + var dst = cast[ByteAddress](cast[PPointer](dest)[]) var dstseq = cast[PGenericSeq](dst) dstseq.len = seq.len dstseq.reserved = seq.len for i in 0..seq.len-1: storeAux( - cast[pointer](dst +% align(GenericSeqSize, mt.base.align) +% i *% mt.base.size), - cast[pointer](cast[int](s2) +% align(GenericSeqSize, mt.base.align) +% - i *% mt.base.size), + cast[pointer](dst +% i*% mt.base.size +% GenericSeqSize), + cast[pointer](cast[ByteAddress](s2) +% i *% mt.base.size +% + GenericSeqSize), mt.base, t, mode) if mode != mStore: dealloc(t.region, s2) of tyObject: @@ -268,8 +265,8 @@ when not usesDestructors: storeAux(dest, src, mt.node, t, mode) of tyArray, tyArrayConstr: for i in 0..(mt.size div mt.base.size)-1: - storeAux(cast[pointer](d +% i *% mt.base.size), - cast[pointer](s +% i *% mt.base.size), mt.base, t, mode) + storeAux(cast[pointer](d +% i*% mt.base.size), + cast[pointer](s +% i*% mt.base.size), mt.base, t, mode) of tyRef: var s = cast[PPointer](src)[] var x = cast[PPointer](dest) @@ -350,7 +347,7 @@ template lockChannel(q, action): untyped = proc sendImpl(q: PRawChannel, typ: PNimType, msg: pointer, noBlock: bool): bool = if q.mask == ChannelDeadMask: - sysFatal(DeadThreadDefect, "cannot send message; thread died") + sysFatal(DeadThreadError, "cannot send message; thread died") acquireSys(q.lock) if q.maxItems > 0: # Wait until count is less than maxItems @@ -363,8 +360,8 @@ proc sendImpl(q: PRawChannel, typ: PNimType, msg: pointer, noBlock: bool): bool rawSend(q, msg, typ) q.elemType = typ - signalSysCond(q.cond) releaseSys(q.lock) + signalSysCond(q.cond) result = true proc send*[TMsg](c: var Channel[TMsg], msg: sink TMsg) {.inline.} = @@ -413,8 +410,8 @@ proc tryRecv*[TMsg](c: var Channel[TMsg]): tuple[dataAvailable: bool, ## Tries to receive a message from the channel `c`, but this can fail ## for all sort of reasons, including contention. ## - ## If it fails, it returns `(false, default(msg))` otherwise it - ## returns `(true, msg)`. + ## If it fails, it returns ``(false, default(msg))`` otherwise it + ## returns ``(true, msg)``. var q = cast[PRawChannel](addr(c)) if q.mask != ChannelDeadMask: if tryAcquireSys(q.lock): @@ -451,7 +448,8 @@ proc close*[TMsg](c: var Channel[TMsg]) = deinitRawChannel(addr(c)) proc ready*[TMsg](c: var Channel[TMsg]): bool = - ## Returns true if some thread is waiting on the channel `c` for + ## Returns true iff some thread is waiting on the channel `c` for ## new messages. var q = cast[PRawChannel](addr(c)) result = q.ready + diff --git a/lib/system/chcks.nim b/lib/system/chcks.nim index dd26d140d..52642bbf9 100644 --- a/lib/system/chcks.nim +++ b/lib/system/chcks.nim @@ -9,61 +9,24 @@ # Implementation of some runtime checks. include system/indexerrors -when defined(nimPreviewSlimSystem): - import std/formatfloat proc raiseRangeError(val: BiggestInt) {.compilerproc, noinline.} = when hostOS == "standalone": - sysFatal(RangeDefect, "value out of range") + sysFatal(RangeError, "value out of range") else: - sysFatal(RangeDefect, "value out of range: ", $val) - -proc raiseIndexError4(l1, h1, h2: int) {.compilerproc, noinline.} = - sysFatal(IndexDefect, "index out of bounds: " & $l1 & ".." & $h1 & " notin 0.." & $(h2 - 1)) + sysFatal(RangeError, "value out of range: ", $val) proc raiseIndexError3(i, a, b: int) {.compilerproc, noinline.} = - sysFatal(IndexDefect, formatErrorIndexBound(i, a, b)) + sysFatal(IndexError, formatErrorIndexBound(i, a, b)) proc raiseIndexError2(i, n: int) {.compilerproc, noinline.} = - sysFatal(IndexDefect, formatErrorIndexBound(i, n)) + sysFatal(IndexError, formatErrorIndexBound(i, n)) proc raiseIndexError() {.compilerproc, noinline.} = - sysFatal(IndexDefect, "index out of bounds") + sysFatal(IndexError, "index out of bounds") proc raiseFieldError(f: string) {.compilerproc, noinline.} = - ## remove after bootstrap > 1.5.1 - sysFatal(FieldDefect, f) - -when defined(nimV2): - proc raiseFieldError2(f: string, discVal: int) {.compilerproc, noinline.} = - ## raised when field is inaccessible given runtime value of discriminant - sysFatal(FieldDefect, f & $discVal & "'") -else: - proc raiseFieldError2(f: string, discVal: string) {.compilerproc, noinline.} = - ## raised when field is inaccessible given runtime value of discriminant - sysFatal(FieldDefect, formatFieldDefect(f, discVal)) - -proc raiseRangeErrorI(i, a, b: BiggestInt) {.compilerproc, noinline.} = - when defined(standalone): - sysFatal(RangeDefect, "value out of range") - else: - sysFatal(RangeDefect, "value out of range: " & $i & " notin " & $a & " .. " & $b) - -proc raiseRangeErrorF(i, a, b: float) {.compilerproc, noinline.} = - when defined(standalone): - sysFatal(RangeDefect, "value out of range") - else: - sysFatal(RangeDefect, "value out of range: " & $i & " notin " & $a & " .. " & $b) - -proc raiseRangeErrorU(i, a, b: uint64) {.compilerproc, noinline.} = - # todo: better error reporting - sysFatal(RangeDefect, "value out of range") - -proc raiseRangeErrorNoArgs() {.compilerproc, noinline.} = - sysFatal(RangeDefect, "value out of range") - -proc raiseObjectConversionError() {.compilerproc, noinline.} = - sysFatal(ObjectConversionDefect, "invalid object conversion") + sysFatal(FieldError, f) proc chckIndx(i, a, b: int): int = if i >= a and i <= b: @@ -87,24 +50,24 @@ proc chckRangeU(i, a, b: uint64): uint64 {.compilerproc.} = if i >= a and i <= b: return i else: - sysFatal(RangeDefect, "value out of range") + sysFatal(RangeError, "value out of range") proc chckRangeF(x, a, b: float): float = if x >= a and x <= b: return x else: when hostOS == "standalone": - sysFatal(RangeDefect, "value out of range") + sysFatal(RangeError, "value out of range") else: - sysFatal(RangeDefect, "value out of range: ", $x) + sysFatal(RangeError, "value out of range: ", $x) proc chckNil(p: pointer) = if p == nil: - sysFatal(NilAccessDefect, "attempt to write to a nil address") + sysFatal(NilAccessError, "attempt to write to a nil address") proc chckNilDisp(p: pointer) {.compilerproc.} = if p == nil: - sysFatal(NilAccessDefect, "cannot dispatch; dispatcher is nil") + sysFatal(NilAccessError, "cannot dispatch; dispatcher is nil") when not defined(nimV2): @@ -114,12 +77,12 @@ when not defined(nimV2): if x == subclass: return # optimized fast path while x != subclass: if x == nil: - sysFatal(ObjectConversionDefect, "invalid object conversion") + sysFatal(ObjectConversionError, "invalid object conversion") x = x.base proc chckObjAsgn(a, b: PNimType) {.compilerproc, inline.} = if a != b: - sysFatal(ObjectAssignmentDefect, "invalid object assignment") + sysFatal(ObjectAssignmentError, "invalid object assignment") type ObjCheckCache = array[0..1, PNimType] @@ -153,5 +116,6 @@ when not defined(nimV2): return true when defined(nimV2): - proc raiseObjectCaseTransition() {.compilerproc.} = - sysFatal(FieldDefect, "assignment to discriminant changes object branch") + proc nimFieldDiscriminantCheckV2(oldDiscVal, newDiscVal: uint8) {.compilerproc.} = + if oldDiscVal != newDiscVal: + sysFatal(FieldError, "assignment to discriminant changes object branch") diff --git a/lib/system/comparisons.nim b/lib/system/comparisons.nim index 36d4d06a8..787820989 100644 --- a/lib/system/comparisons.nim +++ b/lib/system/comparisons.nim @@ -1,24 +1,24 @@ # comparison operators: -proc `==`*[Enum: enum](x, y: Enum): bool {.magic: "EqEnum", noSideEffect.} = +proc `==`*[Enum: enum](x, y: Enum): bool {.magic: "EqEnum", noSideEffect.} ## Checks whether values within the *same enum* have the same underlying value. - runnableExamples: - type - Enum1 = enum - field1 = 3, field2 - Enum2 = enum - place1, place2 = 3 - var - e1 = field1 - e2 = place2.ord.Enum1 - assert e1 == e2 - assert not compiles(e1 == place2) # raises error -proc `==`*(x, y: pointer): bool {.magic: "EqRef", noSideEffect.} = - ## Checks for equality between two `pointer` variables. - runnableExamples: - var # this is a wildly dangerous example - a = cast[pointer](0) - b = cast[pointer](nil) - assert a == b # true due to the special meaning of `nil`/0 as a pointer + ## + ## .. code-block:: Nim + ## type + ## Enum1 = enum + ## Field1 = 3, Field2 + ## Enum2 = enum + ## Place1, Place2 = 3 + ## var + ## e1 = Field1 + ## e2 = Enum1(Place2) + ## echo (e1 == e2) # true + ## echo (e1 == Place2) # raises error +proc `==`*(x, y: pointer): bool {.magic: "EqRef", noSideEffect.} + ## .. code-block:: Nim + ## var # this is a wildly dangerous example + ## a = cast[pointer](0) + ## b = cast[pointer](nil) + ## echo (a == b) # true due to the special meaning of `nil`/0 as a pointer proc `==`*(x, y: string): bool {.magic: "EqStr", noSideEffect.} ## Checks for equality between two `string` variables. @@ -26,11 +26,13 @@ proc `==`*(x, y: char): bool {.magic: "EqCh", noSideEffect.} ## Checks for equality between two `char` variables. proc `==`*(x, y: bool): bool {.magic: "EqB", noSideEffect.} ## Checks for equality between two `bool` variables. -proc `==`*[T](x, y: set[T]): bool {.magic: "EqSet", noSideEffect.} = +proc `==`*[T](x, y: set[T]): bool {.magic: "EqSet", noSideEffect.} ## Checks for equality between two variables of type `set`. - runnableExamples: - assert {1, 2, 2, 3} == {1, 2, 3} # duplication in sets is ignored - + ## + ## .. code-block:: Nim + ## var a = {1, 2, 2, 3} # duplication in sets is ignored + ## var b = {1, 2, 3} + ## echo (a == b) # true proc `==`*[T](x, y: ref T): bool {.magic: "EqRef", noSideEffect.} ## Checks that two `ref` variables refer to the same item. proc `==`*[T](x, y: ptr T): bool {.magic: "EqRef", noSideEffect.} @@ -39,105 +41,102 @@ proc `==`*[T: proc](x, y: T): bool {.magic: "EqProc", noSideEffect.} ## Checks that two `proc` variables refer to the same procedure. proc `<=`*[Enum: enum](x, y: Enum): bool {.magic: "LeEnum", noSideEffect.} -proc `<=`*(x, y: string): bool {.magic: "LeStr", noSideEffect.} = +proc `<=`*(x, y: string): bool {.magic: "LeStr", noSideEffect.} ## Compares two strings and returns true if `x` is lexicographically ## before `y` (uppercase letters come before lowercase letters). - runnableExamples: - let - a = "abc" - b = "abd" - c = "ZZZ" - assert a <= b - assert a <= a - assert not (a <= c) - -proc `<=`*(x, y: char): bool {.magic: "LeCh", noSideEffect.} = + ## + ## .. code-block:: Nim + ## let + ## a = "abc" + ## b = "abd" + ## c = "ZZZ" + ## assert a <= b + ## assert a <= a + ## assert (a <= c) == false +proc `<=`*(x, y: char): bool {.magic: "LeCh", noSideEffect.} ## Compares two chars and returns true if `x` is lexicographically ## before `y` (uppercase letters come before lowercase letters). - runnableExamples: - let - a = 'a' - b = 'b' - c = 'Z' - assert a <= b - assert a <= a - assert not (a <= c) - -proc `<=`*[T](x, y: set[T]): bool {.magic: "LeSet", noSideEffect.} = + ## + ## .. code-block:: Nim + ## let + ## a = 'a' + ## b = 'b' + ## c = 'Z' + ## assert a <= b + ## assert a <= a + ## assert (a <= c) == false +proc `<=`*[T](x, y: set[T]): bool {.magic: "LeSet", noSideEffect.} ## Returns true if `x` is a subset of `y`. ## ## A subset `x` has all of its members in `y` and `y` doesn't necessarily ## have more members than `x`. That is, `x` can be equal to `y`. - runnableExamples: - let - a = {3, 5} - b = {1, 3, 5, 7} - c = {2} - assert a <= b - assert a <= a - assert not (a <= c) - + ## + ## .. code-block:: Nim + ## let + ## a = {3, 5} + ## b = {1, 3, 5, 7} + ## c = {2} + ## assert a <= b + ## assert a <= a + ## assert (a <= c) == false proc `<=`*(x, y: bool): bool {.magic: "LeB", noSideEffect.} proc `<=`*[T](x, y: ref T): bool {.magic: "LePtr", noSideEffect.} proc `<=`*(x, y: pointer): bool {.magic: "LePtr", noSideEffect.} proc `<`*[Enum: enum](x, y: Enum): bool {.magic: "LtEnum", noSideEffect.} -proc `<`*(x, y: string): bool {.magic: "LtStr", noSideEffect.} = +proc `<`*(x, y: string): bool {.magic: "LtStr", noSideEffect.} ## Compares two strings and returns true if `x` is lexicographically ## before `y` (uppercase letters come before lowercase letters). - runnableExamples: - let - a = "abc" - b = "abd" - c = "ZZZ" - assert a < b - assert not (a < a) - assert not (a < c) - -proc `<`*(x, y: char): bool {.magic: "LtCh", noSideEffect.} = + ## + ## .. code-block:: Nim + ## let + ## a = "abc" + ## b = "abd" + ## c = "ZZZ" + ## assert a < b + ## assert (a < a) == false + ## assert (a < c) == false +proc `<`*(x, y: char): bool {.magic: "LtCh", noSideEffect.} ## Compares two chars and returns true if `x` is lexicographically ## before `y` (uppercase letters come before lowercase letters). - runnableExamples: - let - a = 'a' - b = 'b' - c = 'Z' - assert a < b - assert not (a < a) - assert not (a < c) - -proc `<`*[T](x, y: set[T]): bool {.magic: "LtSet", noSideEffect.} = + ## + ## .. code-block:: Nim + ## let + ## a = 'a' + ## b = 'b' + ## c = 'Z' + ## assert a < b + ## assert (a < a) == false + ## assert (a < c) == false +proc `<`*[T](x, y: set[T]): bool {.magic: "LtSet", noSideEffect.} ## Returns true if `x` is a strict or proper subset of `y`. ## ## A strict or proper subset `x` has all of its members in `y` but `y` has ## more elements than `y`. - runnableExamples: - let - a = {3, 5} - b = {1, 3, 5, 7} - c = {2} - assert a < b - assert not (a < a) - assert not (a < c) - + ## + ## .. code-block:: Nim + ## let + ## a = {3, 5} + ## b = {1, 3, 5, 7} + ## c = {2} + ## assert a < b + ## assert (a < a) == false + ## assert (a < c) == false proc `<`*(x, y: bool): bool {.magic: "LtB", noSideEffect.} proc `<`*[T](x, y: ref T): bool {.magic: "LtPtr", noSideEffect.} proc `<`*[T](x, y: ptr T): bool {.magic: "LtPtr", noSideEffect.} proc `<`*(x, y: pointer): bool {.magic: "LtPtr", noSideEffect.} -when not defined(nimHasCallsitePragma): - {.pragma: callsite.} - -template `!=`*(x, y: untyped): untyped {.callsite.} = - ## Unequals operator. This is a shorthand for `not (x == y)`. +template `!=`*(x, y: untyped): untyped = + ## Unequals operator. This is a shorthand for ``not (x == y)``. not (x == y) -template `>=`*(x, y: untyped): untyped {.callsite.} = - ## "is greater or equals" operator. This is the same as `y <= x`. +template `>=`*(x, y: untyped): untyped = + ## "is greater or equals" operator. This is the same as ``y <= x``. y <= x -template `>`*(x, y: untyped): untyped {.callsite.} = - ## "is greater" operator. This is the same as `y < x`. +template `>`*(x, y: untyped): untyped = + ## "is greater" operator. This is the same as ``y < x``. y < x @@ -162,45 +161,25 @@ proc `<`*(x, y: int16): bool {.magic: "LtI", noSideEffect.} proc `<`*(x, y: int32): bool {.magic: "LtI", noSideEffect.} proc `<`*(x, y: int64): bool {.magic: "LtI", noSideEffect.} -proc `<=`*(x, y: uint): bool {.magic: "LeU", noSideEffect.} - ## Returns true if `x <= y`. -proc `<=`*(x, y: uint8): bool {.magic: "LeU", noSideEffect.} -proc `<=`*(x, y: uint16): bool {.magic: "LeU", noSideEffect.} -proc `<=`*(x, y: uint32): bool {.magic: "LeU", noSideEffect.} -proc `<=`*(x, y: uint64): bool {.magic: "LeU", noSideEffect.} -proc `<`*(x, y: uint): bool {.magic: "LtU", noSideEffect.} - ## Returns true if `x < y`. -proc `<`*(x, y: uint8): bool {.magic: "LtU", noSideEffect.} -proc `<`*(x, y: uint16): bool {.magic: "LtU", noSideEffect.} -proc `<`*(x, y: uint32): bool {.magic: "LtU", noSideEffect.} -proc `<`*(x, y: uint64): bool {.magic: "LtU", noSideEffect.} - -proc `<=%`*(x, y: int): bool {.inline.} = +proc `<=%`*(x, y: IntMax32): bool {.magic: "LeU", noSideEffect.} +proc `<=%`*(x, y: int64): bool {.magic: "LeU64", noSideEffect.} ## Treats `x` and `y` as unsigned and compares them. - ## Returns true if `unsigned(x) <= unsigned(y)`. - cast[uint](x) <= cast[uint](y) -proc `<=%`*(x, y: int8): bool {.inline.} = cast[uint8](x) <= cast[uint8](y) -proc `<=%`*(x, y: int16): bool {.inline.} = cast[uint16](x) <= cast[uint16](y) -proc `<=%`*(x, y: int32): bool {.inline.} = cast[uint32](x) <= cast[uint32](y) -proc `<=%`*(x, y: int64): bool {.inline.} = cast[uint64](x) <= cast[uint64](y) + ## Returns true if ``unsigned(x) <= unsigned(y)``. -proc `<%`*(x, y: int): bool {.inline.} = +proc `<%`*(x, y: IntMax32): bool {.magic: "LtU", noSideEffect.} +proc `<%`*(x, y: int64): bool {.magic: "LtU64", noSideEffect.} ## Treats `x` and `y` as unsigned and compares them. - ## Returns true if `unsigned(x) < unsigned(y)`. - cast[uint](x) < cast[uint](y) -proc `<%`*(x, y: int8): bool {.inline.} = cast[uint8](x) < cast[uint8](y) -proc `<%`*(x, y: int16): bool {.inline.} = cast[uint16](x) < cast[uint16](y) -proc `<%`*(x, y: int32): bool {.inline.} = cast[uint32](x) < cast[uint32](y) -proc `<%`*(x, y: int64): bool {.inline.} = cast[uint64](x) < cast[uint64](y) + ## Returns true if ``unsigned(x) < unsigned(y)``. template `>=%`*(x, y: untyped): untyped = y <=% x ## Treats `x` and `y` as unsigned and compares them. - ## Returns true if `unsigned(x) >= unsigned(y)`. + ## Returns true if ``unsigned(x) >= unsigned(y)``. template `>%`*(x, y: untyped): untyped = y <% x ## Treats `x` and `y` as unsigned and compares them. - ## Returns true if `unsigned(x) > unsigned(y)`. + ## Returns true if ``unsigned(x) > unsigned(y)``. + proc `==`*(x, y: uint): bool {.magic: "EqI", noSideEffect.} ## Compares two unsigned integers for equality. @@ -209,14 +188,21 @@ proc `==`*(x, y: uint16): bool {.magic: "EqI", noSideEffect.} proc `==`*(x, y: uint32): bool {.magic: "EqI", noSideEffect.} proc `==`*(x, y: uint64): bool {.magic: "EqI", noSideEffect.} -proc `<=`*(x, y: float32): bool {.magic: "LeF64", noSideEffect.} -proc `<=`*(x, y: float): bool {.magic: "LeF64", noSideEffect.} -proc `<`*(x, y: float32): bool {.magic: "LtF64", noSideEffect.} -proc `<`*(x, y: float): bool {.magic: "LtF64", noSideEffect.} +proc `<=`*(x, y: uint): bool {.magic: "LeU", noSideEffect.} + ## Returns true if ``x <= y``. +proc `<=`*(x, y: uint8): bool {.magic: "LeU", noSideEffect.} +proc `<=`*(x, y: uint16): bool {.magic: "LeU", noSideEffect.} +proc `<=`*(x, y: uint32): bool {.magic: "LeU", noSideEffect.} +proc `<=`*(x, y: uint64): bool {.magic: "LeU", noSideEffect.} + +proc `<`*(x, y: uint): bool {.magic: "LtU", noSideEffect.} + ## Returns true if ``unsigned(x) < unsigned(y)``. +proc `<`*(x, y: uint8): bool {.magic: "LtU", noSideEffect.} +proc `<`*(x, y: uint16): bool {.magic: "LtU", noSideEffect.} +proc `<`*(x, y: uint32): bool {.magic: "LtU", noSideEffect.} +proc `<`*(x, y: uint64): bool {.magic: "LtU", noSideEffect.} -proc `==`*(x, y: float32): bool {.magic: "EqF64", noSideEffect.} -proc `==`*(x, y: float): bool {.magic: "EqF64", noSideEffect.} {.push stackTrace: off.} @@ -231,13 +217,6 @@ proc min*(x, y: int32): int32 {.magic: "MinI", noSideEffect.} = proc min*(x, y: int64): int64 {.magic: "MinI", noSideEffect.} = ## The minimum value of two integers. if x <= y: x else: y -proc min*(x, y: float32): float32 {.noSideEffect, inline.} = - if x <= y or y != y: x else: y -proc min*(x, y: float64): float64 {.noSideEffect, inline.} = - if x <= y or y != y: x else: y -proc min*[T: not SomeFloat](x, y: T): T {.inline.} = - ## Generic minimum operator of 2 values based on `<=`. - if x <= y: x else: y proc max*(x, y: int): int {.magic: "MaxI", noSideEffect.} = if y <= x: x else: y @@ -250,23 +229,16 @@ proc max*(x, y: int32): int32 {.magic: "MaxI", noSideEffect.} = proc max*(x, y: int64): int64 {.magic: "MaxI", noSideEffect.} = ## The maximum value of two integers. if y <= x: x else: y -proc max*(x, y: float32): float32 {.noSideEffect, inline.} = - if y <= x or y != y: x else: y -proc max*(x, y: float64): float64 {.noSideEffect, inline.} = - if y <= x or y != y: x else: y -proc max*[T: not SomeFloat](x, y: T): T {.inline.} = - ## Generic maximum operator of 2 values based on `<=`. - if y <= x: x else: y proc min*[T](x: openArray[T]): T = - ## The minimum value of `x`. `T` needs to have a `<` operator. + ## The minimum value of `x`. ``T`` needs to have a ``<`` operator. result = x[0] for i in 1..high(x): if x[i] < result: result = x[i] proc max*[T](x: openArray[T]): T = - ## The maximum value of `x`. `T` needs to have a `<` operator. + ## The maximum value of `x`. ``T`` needs to have a ``<`` operator. result = x[0] for i in 1..high(x): if result < x[i]: result = x[i] @@ -275,17 +247,11 @@ proc max*[T](x: openArray[T]): T = proc clamp*[T](x, a, b: T): T = - ## Limits the value `x` within the interval \[a, b]. - ## This proc is equivalent to but faster than `max(a, min(b, x))`. - ## - ## .. warning:: `a <= b` is assumed and will not be checked (currently). + ## Limits the value ``x`` within the interval [a, b]. ## - ## **See also:** - ## `math.clamp` for a version that takes a `Slice[T]` instead. - runnableExamples: - assert (1.4).clamp(0.0, 1.0) == 1.0 - assert (0.5).clamp(0.0, 1.0) == 0.5 - assert 4.clamp(1, 3) == max(1, min(3, 4)) + ## .. code-block:: Nim + ## assert((1.4).clamp(0.0, 1.0) == 1.0) + ## assert((0.5).clamp(0.0, 1.0) == 0.5) if x < a: return a if x > b: return b return x @@ -310,8 +276,12 @@ proc `==`*[T](x, y: seq[T]): bool {.noSideEffect.} = ## Generic equals operator for sequences: relies on a equals operator for ## the element type `T`. when nimvm: - if x.len == 0 and y.len == 0: - return true + when not defined(nimNoNil): + if x.isNil and y.isNil: + return true + else: + if x.len == 0 and y.len == 0: + return true else: when not defined(js): proc seqToPtr[T](x: seq[T]): pointer {.inline, noSideEffect.} = @@ -327,6 +297,10 @@ proc `==`*[T](x, y: seq[T]): bool {.noSideEffect.} = asm """`sameObject` = `x` === `y`""" if sameObject: return true + when not defined(nimNoNil): + if x.isNil or y.isNil: + return false + if x.len != y.len: return false diff --git a/lib/system/compilation.nim b/lib/system/compilation.nim deleted file mode 100644 index c04990277..000000000 --- a/lib/system/compilation.nim +++ /dev/null @@ -1,208 +0,0 @@ -const - NimMajor* {.intdefine.}: int = 1 - ## is the major number of Nim's version. Example: - ## ``` - ## when (NimMajor, NimMinor, NimPatch) >= (1, 3, 1): discard - ## ``` - # see also std/private/since - - NimMinor* {.intdefine.}: int = 9 - ## is the minor number of Nim's version. - ## Odd for devel, even for releases. - - NimPatch* {.intdefine.}: int = 1 - ## is the patch number of Nim's version. - ## Odd for devel, even for releases. - -{.push profiler: off.} -let nimvm* {.magic: "Nimvm", compileTime.}: bool = false - ## May be used only in `when` expression. - ## It is true in Nim VM context and false otherwise. -{.pop.} - -const - isMainModule* {.magic: "IsMainModule".}: bool = false - ## True only when accessed in the main module. This works thanks to - ## compiler magic. It is useful to embed testing code in a module. - - CompileDate* {.magic: "CompileDate".}: string = "0000-00-00" - ## The date (in UTC) of compilation as a string of the form - ## `YYYY-MM-DD`. This works thanks to compiler magic. - - CompileTime* {.magic: "CompileTime".}: string = "00:00:00" - ## The time (in UTC) of compilation as a string of the form - ## `HH:MM:SS`. This works thanks to compiler magic. - -proc defined*(x: untyped): bool {.magic: "Defined", noSideEffect, compileTime.} - ## Special compile-time procedure that checks whether `x` is - ## defined. - ## - ## `x` is an external symbol introduced through the compiler's - ## `-d:x switch `_ to enable - ## build time conditionals: - ## ``` - ## when not defined(release): - ## # Do here programmer friendly expensive sanity checks. - ## # Put here the normal code - ## ``` - ## - ## See also: - ## * `compileOption <#compileOption,string>`_ for `on|off` options - ## * `compileOption <#compileOption,string,string>`_ for enum options - ## * `define pragmas `_ - -proc declared*(x: untyped): bool {.magic: "Declared", noSideEffect, compileTime.} - ## Special compile-time procedure that checks whether `x` is - ## declared. `x` has to be an identifier or a qualified identifier. - ## - ## This can be used to check whether a library provides a certain - ## feature or not: - ## ``` - ## when not declared(strutils.toUpper): - ## # provide our own toUpper proc here, because strutils is - ## # missing it. - ## ``` - ## - ## See also: - ## * `declaredInScope <#declaredInScope,untyped>`_ - -proc declaredInScope*(x: untyped): bool {.magic: "DeclaredInScope", noSideEffect, compileTime.} - ## Special compile-time procedure that checks whether `x` is - ## declared in the current scope. `x` has to be an identifier. - -proc compiles*(x: untyped): bool {.magic: "Compiles", noSideEffect, compileTime.} = - ## Special compile-time procedure that checks whether `x` can be compiled - ## without any semantic error. - ## This can be used to check whether a type supports some operation: - ## ``` - ## when compiles(3 + 4): - ## echo "'+' for integers is available" - ## ``` - discard - -proc astToStr*[T](x: T): string {.magic: "AstToStr", noSideEffect.} - ## Converts the AST of `x` into a string representation. This is very useful - ## for debugging. - -proc runnableExamples*(rdoccmd = "", body: untyped) {.magic: "RunnableExamples".} = - ## A section you should use to mark `runnable example`:idx: code with. - ## - ## - In normal debug and release builds code within - ## a `runnableExamples` section is ignored. - ## - The documentation generator is aware of these examples and considers them - ## part of the `##` doc comment. As the last step of documentation - ## generation each runnableExample is put in its own file `$file_examples$i.nim`, - ## compiled and tested. The collected examples are - ## put into their own module to ensure the examples do not refer to - ## non-exported symbols. - runnableExamples: - proc timesTwo*(x: int): int = - ## This proc doubles a number. - runnableExamples: - # at module scope - const exported* = 123 - assert timesTwo(5) == 10 - block: # at block scope - defer: echo "done" - runnableExamples "-d:foo -b:cpp": - import std/compilesettings - assert querySetting(backend) == "cpp" - assert defined(foo) - runnableExamples "-r:off": ## this one is only compiled - import std/browsers - openDefaultBrowser "https://forum.nim-lang.org/" - 2 * x - -proc compileOption*(option: string): bool {. - magic: "CompileOption", noSideEffect.} = - ## Can be used to determine an `on|off` compile-time option. - ## - ## See also: - ## * `compileOption <#compileOption,string,string>`_ for enum options - ## * `defined <#defined,untyped>`_ - ## * `std/compilesettings module `_ - runnableExamples("--floatChecks:off"): - static: doAssert not compileOption("floatchecks") - {.push floatChecks: on.} - static: doAssert compileOption("floatchecks") - # floating point NaN and Inf checks enabled in this scope - {.pop.} - -proc compileOption*(option, arg: string): bool {. - magic: "CompileOptionArg", noSideEffect.} = - ## Can be used to determine an enum compile-time option. - ## - ## See also: - ## * `compileOption <#compileOption,string>`_ for `on|off` options - ## * `defined <#defined,untyped>`_ - ## * `std/compilesettings module `_ - runnableExamples: - when compileOption("opt", "size") and compileOption("gc", "boehm"): - discard "compiled with optimization for size and uses Boehm's GC" - -template currentSourcePath*: string = instantiationInfo(-1, true).filename - ## Returns the full file-system path of the current source. - ## - ## To get the directory containing the current source, use it with - ## `os.parentDir() `_ as `currentSourcePath.parentDir()`. - ## - ## The path returned by this template is set at compile time. - ## - ## See the docstring of `macros.getProjectPath() `_ - ## for an example to see the distinction between the `currentSourcePath` - ## and `getProjectPath`. - ## - ## See also: - ## * `getCurrentDir proc `_ - -proc slurp*(filename: string): string {.magic: "Slurp".} - ## This is an alias for `staticRead <#staticRead,string>`_. - -proc staticRead*(filename: string): string {.magic: "Slurp".} - ## Compile-time `readFile `_ proc for easy - ## `resource`:idx: embedding: - ## - ## The maximum file size limit that `staticRead` and `slurp` can read is - ## near or equal to the *free* memory of the device you are using to compile. - ## ``` - ## const myResource = staticRead"mydatafile.bin" - ## ``` - ## - ## `slurp <#slurp,string>`_ is an alias for `staticRead`. - -proc gorge*(command: string, input = "", cache = ""): string {. - magic: "StaticExec".} = discard - ## This is an alias for `staticExec <#staticExec,string,string,string>`_. - -proc staticExec*(command: string, input = "", cache = ""): string {. - magic: "StaticExec".} = discard - ## Executes an external process at compile-time and returns its text output - ## (stdout + stderr). - ## - ## If `input` is not an empty string, it will be passed as a standard input - ## to the executed program. - ## ``` - ## const buildInfo = "Revision " & staticExec("git rev-parse HEAD") & - ## "\nCompiled on " & staticExec("uname -v") - ## ``` - ## - ## `gorge <#gorge,string,string,string>`_ is an alias for `staticExec`. - ## - ## Note that you can use this proc inside a pragma like - ## `passc `_ or - ## `passl `_. - ## - ## If `cache` is not empty, the results of `staticExec` are cached within - ## the `nimcache` directory. Use `--forceBuild` to get rid of this caching - ## behaviour then. `command & input & cache` (the concatenated string) is - ## used to determine whether the entry in the cache is still valid. You can - ## use versioning information for `cache`: - ## ``` - ## const stateMachine = staticExec("dfaoptimizer", "input", "0.8.0") - ## ``` - -proc gorgeEx*(command: string, input = "", cache = ""): tuple[output: string, - exitCode: int] = - ## Similar to `gorge <#gorge,string,string,string>`_ but also returns the - ## precious exit code. - discard diff --git a/lib/system/coro_detection.nim b/lib/system/coro_detection.nim deleted file mode 100644 index f6c1b5c15..000000000 --- a/lib/system/coro_detection.nim +++ /dev/null @@ -1,20 +0,0 @@ -## Coroutine detection logic - -template coroutinesSupportedPlatform(): bool = - when defined(sparc) or defined(ELATE) or defined(boehmgc) or defined(gogc) or - defined(nogc) or defined(gcRegions) or defined(gcMarkAndSweep): - false - else: - true - -when defined(nimCoroutines): - # Explicit opt-in. - when not coroutinesSupportedPlatform(): - {.error: "Coroutines are not supported on this architecture and/or garbage collector.".} - const nimCoroutines* = true -elif defined(noNimCoroutines): - # Explicit opt-out. - const nimCoroutines* = false -else: - # Autodetect coroutine support. - const nimCoroutines* = false diff --git a/lib/system/countbits_impl.nim b/lib/system/countbits_impl.nim deleted file mode 100644 index 34969cb32..000000000 --- a/lib/system/countbits_impl.nim +++ /dev/null @@ -1,93 +0,0 @@ -# -# -# Nim's Runtime Library -# (c) Copyright 2012 Andreas Rumpf -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# - -## Contains the used algorithms for counting bits. - -from std/private/bitops_utils import forwardImpl, castToUnsigned - -const useBuiltins* = not defined(noIntrinsicsBitOpts) -const noUndefined* = defined(noUndefinedBitOpts) -const useGCC_builtins* = (defined(gcc) or defined(llvm_gcc) or - defined(clang)) and useBuiltins -const useICC_builtins* = defined(icc) and useBuiltins -const useVCC_builtins* = defined(vcc) and useBuiltins -const arch64* = sizeof(int) == 8 - -template countBitsImpl(n: uint32): int = - # generic formula is from: https://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetParallel - var v = uint32(n) - v = v - ((v shr 1'u32) and 0x55555555'u32) - v = (v and 0x33333333'u32) + ((v shr 2'u32) and 0x33333333'u32) - (((v + (v shr 4'u32) and 0xF0F0F0F'u32) * 0x1010101'u32) shr 24'u32).int - -template countBitsImpl(n: uint64): int = - # generic formula is from: https://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetParallel - var v = uint64(n) - v = v - ((v shr 1'u64) and 0x5555555555555555'u64) - v = (v and 0x3333333333333333'u64) + ((v shr 2'u64) and 0x3333333333333333'u64) - v = (v + (v shr 4'u64) and 0x0F0F0F0F0F0F0F0F'u64) - ((v * 0x0101010101010101'u64) shr 56'u64).int - - -when useGCC_builtins: - # Returns the number of set 1-bits in value. - proc builtin_popcount(x: cuint): cint {.importc: "__builtin_popcount", cdecl.} - proc builtin_popcountll(x: culonglong): cint {. - importc: "__builtin_popcountll", cdecl.} - -elif useVCC_builtins: - # Counts the number of one bits (population count) in a 16-, 32-, or 64-byte unsigned integer. - func builtin_popcnt16(a2: uint16): uint16 {. - importc: "__popcnt16", header: "".} - func builtin_popcnt32(a2: uint32): uint32 {. - importc: "__popcnt", header: "".} - func builtin_popcnt64(a2: uint64): uint64 {. - importc: "__popcnt64", header: "".} - -elif useICC_builtins: - # Intel compiler intrinsics: http://fulla.fnal.gov/intel/compiler_c/main_cls/intref_cls/common/intref_allia_misc.htm - # see also: https://software.intel.com/en-us/node/523362 - # Count the number of bits set to 1 in an integer a, and return that count in dst. - func builtin_popcnt32(a: cint): cint {. - importc: "_popcnt", header: "".} - func builtin_popcnt64(a: uint64): cint {. - importc: "_popcnt64", header: "".} - - -func countSetBitsImpl*(x: SomeInteger): int {.inline.} = - ## Counts the set bits in an integer (also called `Hamming weight`:idx:). - # TODO: figure out if ICC support _popcnt32/_popcnt64 on platform without POPCNT. - # like GCC and MSVC - let x = x.castToUnsigned - when nimvm: - result = forwardImpl(countBitsImpl, x) - else: - when useGCC_builtins: - when sizeof(x) <= 4: result = builtin_popcount(x.cuint).int - else: result = builtin_popcountll(x.culonglong).int - elif useVCC_builtins: - when sizeof(x) <= 2: result = builtin_popcnt16(x.uint16).int - elif sizeof(x) <= 4: result = builtin_popcnt32(x.uint32).int - elif arch64: result = builtin_popcnt64(x.uint64).int - else: result = builtin_popcnt32((x.uint64 and 0xFFFFFFFF'u64).uint32).int + - builtin_popcnt32((x.uint64 shr 32'u64).uint32).int - elif useICC_builtins: - when sizeof(x) <= 4: result = builtin_popcnt32(x.cint).int - elif arch64: result = builtin_popcnt64(x.uint64).int - else: result = builtin_popcnt32((x.uint64 and 0xFFFFFFFF'u64).cint).int + - builtin_popcnt32((x.uint64 shr 32'u64).cint).int - else: - when sizeof(x) <= 4: result = countBitsImpl(x.uint32) - else: result = countBitsImpl(x.uint64) - -proc countBits32*(n: uint32): int {.compilerproc, inline.} = - result = countSetBitsImpl(n) - -proc countBits64*(n: uint64): int {.compilerproc, inline.} = - result = countSetBitsImpl(n) diff --git a/lib/system/ctypes.nim b/lib/system/ctypes.nim deleted file mode 100644 index f6a341477..000000000 --- a/lib/system/ctypes.nim +++ /dev/null @@ -1,90 +0,0 @@ -## Some type definitions for compatibility between different -## backends and platforms. - -type - BiggestInt* = int64 - ## is an alias for the biggest signed integer type the Nim compiler - ## supports. Currently this is `int64`, but it is platform-dependent - ## in general. - - BiggestFloat* = float64 - ## is an alias for the biggest floating point type the Nim - ## compiler supports. Currently this is `float64`, but it is - ## platform-dependent in general. - -when defined(js): - type BiggestUInt* = uint32 - ## is an alias for the biggest unsigned integer type the Nim compiler - ## supports. Currently this is `uint32` for JS and `uint64` for other - ## targets. -else: - type BiggestUInt* = uint64 - ## is an alias for the biggest unsigned integer type the Nim compiler - ## supports. Currently this is `uint32` for JS and `uint64` for other - ## targets. - -when defined(windows): - type - clong* {.importc: "long", nodecl.} = int32 - ## This is the same as the type `long` in *C*. - culong* {.importc: "unsigned long", nodecl.} = uint32 - ## This is the same as the type `unsigned long` in *C*. -else: - type - clong* {.importc: "long", nodecl.} = int - ## This is the same as the type `long` in *C*. - culong* {.importc: "unsigned long", nodecl.} = uint - ## This is the same as the type `unsigned long` in *C*. - -type # these work for most platforms: - cchar* {.importc: "char", nodecl.} = char - ## This is the same as the type `char` in *C*. - cschar* {.importc: "signed char", nodecl.} = int8 - ## This is the same as the type `signed char` in *C*. - cshort* {.importc: "short", nodecl.} = int16 - ## This is the same as the type `short` in *C*. - cint* {.importc: "int", nodecl.} = int32 - ## This is the same as the type `int` in *C*. - csize_t* {.importc: "size_t", nodecl.} = uint - ## This is the same as the type `size_t` in *C*. - clonglong* {.importc: "long long", nodecl.} = int64 - ## This is the same as the type `long long` in *C*. - cfloat* {.importc: "float", nodecl.} = float32 - ## This is the same as the type `float` in *C*. - cdouble* {.importc: "double", nodecl.} = float64 - ## This is the same as the type `double` in *C*. - clongdouble* {.importc: "long double", nodecl.} = BiggestFloat - ## This is the same as the type `long double` in *C*. - ## This C type is not supported by Nim's code generator. - - cuchar* {.importc: "unsigned char", nodecl, deprecated: "use `char` or `uint8` instead".} = char - ## Deprecated: Use `uint8` instead. - cushort* {.importc: "unsigned short", nodecl.} = uint16 - ## This is the same as the type `unsigned short` in *C*. - cuint* {.importc: "unsigned int", nodecl.} = uint32 - ## This is the same as the type `unsigned int` in *C*. - culonglong* {.importc: "unsigned long long", nodecl.} = uint64 - ## This is the same as the type `unsigned long long` in *C*. - -type - ByteAddress* {.deprecated: "use `uint`".} = int - ## is the signed integer type that should be used for converting - ## pointers to integer addresses for readability. - - cstringArray* {.importc: "char**", nodecl.} = ptr UncheckedArray[cstring] - ## This is binary compatible to the type `char**` in *C*. The array's - ## high value is large enough to disable bounds checking in practice. - ## Use `cstringArrayToSeq proc <#cstringArrayToSeq,cstringArray,Natural>`_ - ## to convert it into a `seq[string]`. - -when not defined(nimPreviewSlimSystem): - # pollutes namespace - type - PFloat32* {.deprecated: "use `ptr float32`".} = ptr float32 - ## An alias for `ptr float32`. - PFloat64* {.deprecated: "use `ptr float64`".} = ptr float64 - ## An alias for `ptr float64`. - PInt64* {.deprecated: "use `ptr int64`".} = ptr int64 - ## An alias for `ptr int64`. - PInt32* {.deprecated: "use `ptr int32`".} = ptr int32 - ## An alias for `ptr int32`. diff --git a/lib/system/cyclebreaker.nim b/lib/system/cyclebreaker.nim deleted file mode 100644 index 45b0a5a65..000000000 --- a/lib/system/cyclebreaker.nim +++ /dev/null @@ -1,184 +0,0 @@ -# -# -# Nim's Runtime Library -# (c) Copyright 2020 Andreas Rumpf -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# - -#[ -A Cycle breaker for Nim ------------------------ - -Instead of "collecting" cycles with all of its pitfalls we will break cycles. -We exploit that every 'ref' can be 'nil' for this and so get away without -a distinction between weak and strong pointers. The required runtime -mechanisms are the same though: We need to be able to traverse the graph. -This design has the tremendous benefit that it doesn't require a dedicated -'rawDispose' operation and that it plays well with Nim's cost model. -The cost of freeing a subgraph with cycles is 2 * N rather than N, that's all. - -Cycles do not have to be prepared via .acyclic, there are not multiple -pointless traversals, only a single proc, `breakCycles` is exposed as a -separate module. - -Algorithm ---------- - -We traverse the graph and notice the nodes we've already traversed. If we -marked the node already, we set the pointer that leads to this node to 'nil' -and decrement the reference count of the cell we pointed at. - -We notice that multiple paths to the same object do not mean -we found a cycle, it only means the node is shared. - - - a -------> b <----- c - | ^ ^ - +----------+ | - | | - +-------------------+ - -If we simply remove all links to already processed nodes we end up with: - - a -------> b c - | ^ - + | - | | - +-------------------+ - -That seems acceptable, no leak is produced. This implies that the standard -depth-first traversal suffices. - -]# - -include cellseqs_v2 - -const - colGreen = 0b000 - colYellow = 0b001 - colRed = 0b010 - colorMask = 0b011 - -type - TraceProc = proc (p, env: pointer) {.nimcall, benign.} - DisposeProc = proc (p: pointer) {.nimcall, benign.} - -template color(c): untyped = c.rc and colorMask -template setColor(c, col) = - c.rc = c.rc and not colorMask or col - -proc nimIncRefCyclic(p: pointer; cyclic: bool) {.compilerRtl, inl.} = - let h = head(p) - inc h.rc, rcIncrement - -proc nimMarkCyclic(p: pointer) {.compilerRtl, inl.} = discard - -type - GcEnv = object - traceStack: CellSeq[ptr pointer] - -proc trace(p: pointer; desc: PNimTypeV2; j: var GcEnv) {.inline.} = - when false: - cprintf("[Trace] desc: %p %p\n", desc, p) - cprintf("[Trace] trace: %p\n", desc.traceImpl) - if desc.traceImpl != nil: - cast[TraceProc](desc.traceImpl)(p, addr(j)) - -proc nimTraceRef(q: pointer; desc: PNimTypeV2; env: pointer) {.compilerRtl.} = - let p = cast[ptr pointer](q) - when traceCollector: - cprintf("[Trace] raw: %p\n", p) - cprintf("[Trace] deref: %p\n", p[]) - if p[] != nil: - var j = cast[ptr GcEnv](env) - j.traceStack.add(p, desc) - -proc nimTraceRefDyn(q: pointer; env: pointer) {.compilerRtl.} = - let p = cast[ptr pointer](q) - when traceCollector: - cprintf("[TraceDyn] raw: %p\n", p) - cprintf("[TraceDyn] deref: %p\n", p[]) - if p[] != nil: - var j = cast[ptr GcEnv](env) - j.traceStack.add(p, cast[ptr PNimTypeV2](p[])[]) - -var markerGeneration: int - -proc breakCycles(s: Cell; desc: PNimTypeV2) = - let markerColor = if (markerGeneration and 1) == 0: colRed - else: colYellow - atomicInc markerGeneration - when traceCollector: - cprintf("[BreakCycles] starting: %p %s RC %ld trace proc %p\n", - s, desc.name, s.rc shr rcShift, desc.traceImpl) - - var j: GcEnv - init j.traceStack - s.setColor markerColor - trace(s +! sizeof(RefHeader), desc, j) - - while j.traceStack.len > 0: - let (u, desc) = j.traceStack.pop() - let p = u[] - let t = head(p) - if t.color != markerColor: - t.setColor markerColor - trace(p, desc, j) - when traceCollector: - cprintf("[BreakCycles] followed: %p RC %ld\n", t, t.rc shr rcShift) - else: - if (t.rc shr rcShift) > 0: - dec t.rc, rcIncrement - # mark as a link that the produced destructor does not have to follow: - u[] = nil - when traceCollector: - cprintf("[BreakCycles] niled out: %p RC %ld\n", t, t.rc shr rcShift) - else: - # anyhow as a link that the produced destructor does not have to follow: - u[] = nil - when traceCollector: - cprintf("[Bug] %p %s RC %ld\n", t, desc.name, t.rc shr rcShift) - deinit j.traceStack - -proc thinout*[T](x: ref T) {.inline.} = - ## turn the subgraph starting with `x` into its spanning tree by - ## `nil`'ing out any pointers that would harm the spanning tree - ## structure. Any back pointers that introduced cycles - ## and thus would keep the graph from being freed are `nil`'ed. - ## This is a form of cycle collection that works well with Nim's ARC - ## and its associated cost model. - proc getDynamicTypeInfo[T](x: T): PNimTypeV2 {.magic: "GetTypeInfoV2", noSideEffect.} - - breakCycles(head(cast[pointer](x)), getDynamicTypeInfo(x[])) - -proc thinout*[T: proc](x: T) {.inline.} = - proc rawEnv[T: proc](x: T): pointer {.noSideEffect, inline.} = - {.emit: """ - `result` = `x`.ClE_0; - """.} - - let p = rawEnv(x) - breakCycles(head(p), cast[ptr PNimTypeV2](p)[]) - -proc nimDecRefIsLastCyclicDyn(p: pointer): bool {.compilerRtl, inl.} = - if p != nil: - var cell = head(p) - if (cell.rc and not rcMask) == 0: - result = true - #cprintf("[DESTROY] %p\n", p) - else: - dec cell.rc, rcIncrement - # According to Lins it's correct to do nothing else here. - #cprintf("[DeCREF] %p\n", p) - -proc nimDecRefIsLastCyclicStatic(p: pointer; desc: PNimTypeV2): bool {.compilerRtl, inl.} = - if p != nil: - var cell = head(p) - if (cell.rc and not rcMask) == 0: - result = true - #cprintf("[DESTROY] %p %s\n", p, desc.name) - else: - dec cell.rc, rcIncrement - #cprintf("[DeCREF] %p %s %ld\n", p, desc.name, cell.rc) diff --git a/lib/system/cyclicrefs_v2.nim b/lib/system/cyclicrefs_v2.nim new file mode 100644 index 000000000..4fbb4fc94 --- /dev/null +++ b/lib/system/cyclicrefs_v2.nim @@ -0,0 +1,232 @@ +# +# +# Nim's Runtime Library +# (c) Copyright 2019 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +# Cycle collector based on Lins' Jump Stack and other ideas, +# see for example: +# https://pdfs.semanticscholar.org/f2b2/0d168acf38ff86305809a55ef2c5d6ebc787.pdf +# Further refinement in 2008 by the notion of "critical links", see +# "Cyclic reference counting" by Rafael Dueire Lins +# R.D. Lins / Information Processing Letters 109 (2008) 71–78 + +const + colGreen = 0b000 + colYellow = 0b001 + colRed = 0b010 + jumpStackFlag = 0b100 # stored in jumpstack + rcShift = 3 # shift by rcShift to get the reference counter + colorMask = 0b011 + +type + TraceProc = proc (p, env: pointer) {.nimcall, benign.} + DisposeProc = proc (p: pointer) {.nimcall, benign.} + +template color(c): untyped = c.rc and colorMask +template setColor(c, col) = + when col == colGreen: + c.rc = c.rc and not colorMask + else: + c.rc = c.rc and not colorMask or col + +proc nimIncRefCyclic(p: pointer) {.compilerRtl, inl.} = + let h = head(p) + inc h.rc, rcIncrement + h.setColor colYellow # mark as potential cycle! + +proc markCyclic*[T](x: ref T) {.inline.} = + ## Mark the underlying object as a candidate for cycle collections. + ## Experimental API. Do not use! + let h = head(cast[pointer](x)) + h.setColor colYellow +type + CellTuple = (Cell, PNimType) + CellArray = ptr UncheckedArray[CellTuple] + CellSeq = object + len, cap: int + d: CellArray + + GcEnv = object + traceStack: CellSeq + jumpStack: CellSeq + +# ------------------- cell seq handling -------------------------------------- + +proc add(s: var CellSeq, c: Cell; t: PNimType) {.inline.} = + if s.len >= s.cap: + s.cap = s.cap * 3 div 2 + when defined(useMalloc): + var d = cast[CellArray](c_malloc(uint(s.cap * sizeof(CellTuple)))) + else: + var d = cast[CellArray](alloc(s.cap * sizeof(CellTuple))) + copyMem(d, s.d, s.len * sizeof(CellTuple)) + when defined(useMalloc): + c_free(s.d) + else: + dealloc(s.d) + s.d = d + # XXX: realloc? + s.d[s.len] = (c, t) + inc(s.len) + +proc init(s: var CellSeq, cap: int = 1024) = + s.len = 0 + s.cap = cap + when defined(useMalloc): + s.d = cast[CellArray](c_malloc(uint(s.cap * sizeof(CellTuple)))) + else: + s.d = cast[CellArray](alloc(s.cap * sizeof(CellTuple))) + +proc deinit(s: var CellSeq) = + when defined(useMalloc): + c_free(s.d) + else: + dealloc(s.d) + s.d = nil + s.len = 0 + s.cap = 0 + +proc pop(s: var CellSeq): (Cell, PNimType) = + result = s.d[s.len-1] + dec s.len + +# ---------------------------------------------------------------------------- + +proc trace(s: Cell; desc: PNimType; j: var GcEnv) {.inline.} = + if desc.traceImpl != nil: + var p = s +! sizeof(RefHeader) + cast[TraceProc](desc.traceImpl)(p, addr(j)) + +proc free(s: Cell; desc: PNimType) {.inline.} = + when traceCollector: + cprintf("[From ] %p rc %ld color %ld in jumpstack %ld\n", s, s.rc shr rcShift, + s.color, s.rc and jumpStackFlag) + var p = s +! sizeof(RefHeader) + if desc.disposeImpl != nil: + cast[DisposeProc](desc.disposeImpl)(p) + nimRawDispose(p) + +proc collect(s: Cell; desc: PNimType; j: var GcEnv) = + if s.color == colRed: + s.setColor colGreen + trace(s, desc, j) + while j.traceStack.len > 0: + let (t, desc) = j.traceStack.pop() + if t.color == colRed: + t.setColor colGreen + trace(t, desc, j) + free(t, desc) + free(s, desc) + #cprintf("[Cycle free] %p %ld\n", s, s.rc shr rcShift) + +proc markRed(s: Cell; desc: PNimType; j: var GcEnv) = + if s.color != colRed: + s.setColor colRed + trace(s, desc, j) + while j.traceStack.len > 0: + let (t, desc) = j.traceStack.pop() + when traceCollector: + cprintf("[Cycle dec] %p %ld color %ld in jumpstack %ld\n", t, t.rc shr rcShift, t.color, t.rc and jumpStackFlag) + dec t.rc, rcIncrement + if (t.rc and not rcMask) >= 0 and (t.rc and jumpStackFlag) == 0: + t.rc = t.rc or jumpStackFlag + when traceCollector: + cprintf("[Now in jumpstack] %p %ld color %ld in jumpstack %ld\n", t, t.rc shr rcShift, t.color, t.rc and jumpStackFlag) + j.jumpStack.add(t, desc) + if t.color != colRed: + t.setColor colRed + trace(t, desc, j) + +proc scanGreen(s: Cell; desc: PNimType; j: var GcEnv) = + s.setColor colGreen + trace(s, desc, j) + while j.traceStack.len > 0: + let (t, desc) = j.traceStack.pop() + if t.color != colGreen: + t.setColor colGreen + trace(t, desc, j) + inc t.rc, rcIncrement + when traceCollector: + cprintf("[Cycle inc] %p %ld color %ld\n", t, t.rc shr rcShift, t.color) + +proc nimTraceRef(p: pointer; desc: PNimType; env: pointer) {.compilerRtl.} = + if p != nil: + var t = head(p) + var j = cast[ptr GcEnv](env) + j.traceStack.add(t, desc) + +proc nimTraceRefDyn(p: pointer; env: pointer) {.compilerRtl.} = + if p != nil: + let desc = cast[ptr PNimType](p)[] + var t = head(p) + var j = cast[ptr GcEnv](env) + j.traceStack.add(t, desc) + +proc scan(s: Cell; desc: PNimType; j: var GcEnv) = + when traceCollector: + cprintf("[doScanGreen] %p %ld\n", s, s.rc shr rcShift) + # even after trial deletion, `s` is still alive, so undo + # the decrefs by calling `scanGreen`: + if (s.rc and not rcMask) >= 0: + scanGreen(s, desc, j) + s.setColor colYellow + else: + # first we have to repair all the nodes we have seen + # that are still alive; we also need to mark what they + # refer to as alive: + while j.jumpStack.len > 0: + let (t, desc) = j.jumpStack.pop + # not in jump stack anymore! + t.rc = t.rc and not jumpStackFlag + if t.color == colRed and (t.rc and not rcMask) >= 0: + scanGreen(t, desc, j) + t.setColor colYellow + when traceCollector: + cprintf("[jump stack] %p %ld\n", t, t.rc shr rcShift) + # we have proven that `s` and its subgraph are dead, so we can + # collect these nodes: + collect(s, desc, j) + +proc traceCycle(s: Cell; desc: PNimType) {.noinline.} = + when traceCollector: + cprintf("[traceCycle] %p %ld\n", s, s.rc shr rcShift) + var j: GcEnv + init j.jumpStack + init j.traceStack + markRed(s, desc, j) + scan(s, desc, j) + while j.jumpStack.len > 0: + let (t, desc) = j.jumpStack.pop + # not in jump stack anymore! + t.rc = t.rc and not jumpStackFlag + deinit j.jumpStack + deinit j.traceStack + +proc nimDecRefIsLastCyclicDyn(p: pointer): bool {.compilerRtl, inl.} = + if p != nil: + var cell = head(p) + if (cell.rc and not rcMask) == 0: + result = true + #cprintf("[DESTROY] %p\n", p) + else: + dec cell.rc, rcIncrement + if cell.color == colYellow: + let desc = cast[ptr PNimType](p)[] + traceCycle(cell, desc) + # According to Lins it's correct to do nothing else here. + #cprintf("[DeCREF] %p\n", p) + +proc nimDecRefIsLastCyclicStatic(p: pointer; desc: PNimType): bool {.compilerRtl, inl.} = + if p != nil: + var cell = head(p) + if (cell.rc and not rcMask) == 0: + result = true + #cprintf("[DESTROY] %p %s\n", p, desc.name) + else: + dec cell.rc, rcIncrement + if cell.color == colYellow: traceCycle(cell, desc) + #cprintf("[DeCREF] %p %s %ld\n", p, desc.name, cell.rc) diff --git a/lib/system/deepcopy.nim b/lib/system/deepcopy.nim index 72d35f518..66a65cd34 100644 --- a/lib/system/deepcopy.nim +++ b/lib/system/deepcopy.nim @@ -61,8 +61,8 @@ proc genericDeepCopyAux(dest, src: pointer, mt: PNimType; proc genericDeepCopyAux(dest, src: pointer, n: ptr TNimNode; tab: var PtrTable) {.benign.} = var - d = cast[int](dest) - s = cast[int](src) + d = cast[ByteAddress](dest) + s = cast[ByteAddress](src) case n.kind of nkSlot: genericDeepCopyAux(cast[pointer](d +% n.offset), @@ -85,40 +85,33 @@ proc genericDeepCopyAux(dest, src: pointer, n: ptr TNimNode; proc genericDeepCopyAux(dest, src: pointer, mt: PNimType; tab: var PtrTable) = var - d = cast[int](dest) - s = cast[int](src) + d = cast[ByteAddress](dest) + s = cast[ByteAddress](src) sysAssert(mt != nil, "genericDeepCopyAux 2") case mt.kind of tyString: - when defined(nimSeqsV2): - var x = cast[ptr NimStringV2](dest) - var s2 = cast[ptr NimStringV2](s)[] - nimAsgnStrV2(x[], s2) + var x = cast[PPointer](dest) + var s2 = cast[PPointer](s)[] + if s2 == nil: + unsureAsgnRef(x, s2) else: - var x = cast[PPointer](dest) - var s2 = cast[PPointer](s)[] - if s2 == nil: - unsureAsgnRef(x, s2) - else: - unsureAsgnRef(x, copyDeepString(cast[NimString](s2))) + unsureAsgnRef(x, copyDeepString(cast[NimString](s2))) of tySequence: - when defined(nimSeqsV2): - deepSeqAssignImpl(genericDeepCopyAux, tab) - else: - var s2 = cast[PPointer](src)[] - var seq = cast[PGenericSeq](s2) - var x = cast[PPointer](dest) - if s2 == nil: - unsureAsgnRef(x, s2) - return - sysAssert(dest != nil, "genericDeepCopyAux 3") - unsureAsgnRef(x, newSeq(mt, seq.len)) - var dst = cast[int](cast[PPointer](dest)[]) - for i in 0..seq.len-1: - genericDeepCopyAux( - cast[pointer](dst +% align(GenericSeqSize, mt.base.align) +% i *% mt.base.size), - cast[pointer](cast[int](s2) +% align(GenericSeqSize, mt.base.align) +% i *% mt.base.size), - mt.base, tab) + var s2 = cast[PPointer](src)[] + var seq = cast[PGenericSeq](s2) + var x = cast[PPointer](dest) + if s2 == nil: + unsureAsgnRef(x, s2) + return + sysAssert(dest != nil, "genericDeepCopyAux 3") + unsureAsgnRef(x, newSeq(mt, seq.len)) + var dst = cast[ByteAddress](cast[PPointer](dest)[]) + for i in 0..seq.len-1: + genericDeepCopyAux( + cast[pointer](dst +% i *% mt.base.size +% GenericSeqSize), + cast[pointer](cast[ByteAddress](s2) +% i *% mt.base.size +% + GenericSeqSize), + mt.base, tab) of tyObject: # we need to copy m_type field for tyObject, as it could be empty for # sequence reallocations: @@ -140,10 +133,7 @@ proc genericDeepCopyAux(dest, src: pointer, mt: PNimType; tab: var PtrTable) = unsureAsgnRef(cast[PPointer](dest), s2) elif mt.base.deepcopy != nil: let z = mt.base.deepcopy(s2) - when defined(nimSeqsV2): - cast[PPointer](dest)[] = z - else: - unsureAsgnRef(cast[PPointer](dest), z) + unsureAsgnRef(cast[PPointer](dest), z) else: let z = tab.get(s2) if z == nil: @@ -160,16 +150,10 @@ proc genericDeepCopyAux(dest, src: pointer, mt: PNimType; tab: var PtrTable) = let x = usrToCell(s2) let realType = x.typ sysAssert realType == mt, " types do differ" - when defined(nimSeqsV2): - let typ = if mt.base.kind == tyObject: cast[PNimType](cast[ptr PNimTypeV2](s2)[].typeInfoV1) - else: mt.base - let z = nimNewObj(typ.size, typ.align) - cast[PPointer](dest)[] = z - else: - # this version should work for any other GC: - let typ = if mt.base.kind == tyObject: cast[ptr PNimType](s2)[] else: mt.base - let z = newObj(mt, typ.size) - unsureAsgnRef(cast[PPointer](dest), z) + # this version should work for any possible GC: + let typ = if mt.base.kind == tyObject: cast[ptr PNimType](s2)[] else: mt.base + let z = newObj(mt, typ.size) + unsureAsgnRef(cast[PPointer](dest), z) tab.put(s2, z) genericDeepCopyAux(z, s2, typ, tab) else: @@ -185,11 +169,11 @@ proc genericDeepCopyAux(dest, src: pointer, mt: PNimType; tab: var PtrTable) = copyMem(dest, src, mt.size) proc genericDeepCopy(dest, src: pointer, mt: PNimType) {.compilerproc.} = - when not defined(nimSeqsV2): GC_disable() + GC_disable() var tab = initPtrTable() genericDeepCopyAux(dest, src, mt, tab) deinit tab - when not defined(nimSeqsV2): GC_enable() + GC_enable() proc genericSeqDeepCopy(dest, src: pointer, mt: PNimType) {.compilerproc.} = # also invoked for 'string' @@ -199,8 +183,8 @@ proc genericSeqDeepCopy(dest, src: pointer, mt: PNimType) {.compilerproc.} = proc genericDeepCopyOpenArray(dest, src: pointer, len: int, mt: PNimType) {.compilerproc.} = var - d = cast[int](dest) - s = cast[int](src) + d = cast[ByteAddress](dest) + s = cast[ByteAddress](src) for i in 0..len-1: genericDeepCopy(cast[pointer](d +% i *% mt.base.size), cast[pointer](s +% i *% mt.base.size), mt.base) diff --git a/lib/system/dollars.nim b/lib/system/dollars.nim index 4ff3d0ae6..664f1c30d 100644 --- a/lib/system/dollars.nim +++ b/lib/system/dollars.nim @@ -1,38 +1,15 @@ -## `$` is Nim's general way of spelling `toString`:idx:. -runnableExamples: - assert $0.1 == "0.1" - assert $(-2*3) == "-6" +proc `$`*(x: int): string {.magic: "IntToStr", noSideEffect.} + ## The stringify operator for an integer argument. Returns `x` + ## converted to a decimal string. ``$`` is Nim's general way of + ## spelling `toString`:idx:. -import std/private/[digitsutils, miscdollars] - -when not defined(nimPreviewSlimSystem): - import std/formatfloat - export addFloat - - func `$`*(x: float | float32): string = - ## Outplace version of `addFloat`. - result.addFloat(x) - -proc `$`*(x: int): string {.raises: [].} = - ## Outplace version of `addInt`. - result.addInt(x) - -proc `$`*(x: int64): string {.raises: [].} = - ## Outplace version of `addInt`. - result.addInt(x) - -proc `$`*(x: uint64): string {.raises: [].} = - ## Outplace version of `addInt`. - addInt(result, x) - -# same as old `ctfeWhitelist` behavior, whether or not this is a good idea. -template gen(T) = - # xxx simplify this by supporting this in compiler: int{lit} | uint64{lit} | int64{lit} - func `$`*(x: T{lit}): string {.compileTime.} = result.addInt(x) -gen(int) -gen(uint64) -gen(int64) +proc `$`*(x: int64): string {.magic: "Int64ToStr", noSideEffect.} + ## The stringify operator for an integer argument. Returns `x` + ## converted to a decimal string. +proc `$`*(x: float): string {.magic: "FloatToStr", noSideEffect.} + ## The stringify operator for a float argument. Returns `x` + ## converted to a decimal string. proc `$`*(x: bool): string {.magic: "BoolToStr", noSideEffect.} ## The stringify operator for a boolean argument. Returns `x` @@ -52,39 +29,78 @@ proc `$`*(x: cstring): string {.magic: "CStrToStr", noSideEffect.} proc `$`*(x: string): string {.magic: "StrToStr", noSideEffect.} ## The stringify operator for a string argument. Returns `x` ## as it is. This operator is useful for generic code, so - ## that `$expr` also works if `expr` is already a string. + ## that ``$expr`` also works if ``expr`` is already a string. proc `$`*[Enum: enum](x: Enum): string {.magic: "EnumToStr", noSideEffect.} ## The stringify operator for an enumeration argument. This works for ## any enumeration type thanks to compiler magic. ## - ## If a `$` operator for a concrete enumeration is provided, this is + ## If a ``$`` operator for a concrete enumeration is provided, this is ## used instead. (In other words: *Overwriting* is possible.) proc `$`*(t: typedesc): string {.magic: "TypeTrait".} ## Returns the name of the given type. ## - ## For more procedures dealing with `typedesc`, see + ## For more procedures dealing with ``typedesc``, see ## `typetraits module `_. ## ## .. code-block:: Nim - ## doAssert $(typeof(42)) == "int" - ## doAssert $(typeof("Foo")) == "string" - ## static: doAssert $(typeof(@['A', 'B'])) == "seq[char]" + ## doAssert $(type(42)) == "int" + ## doAssert $(type("Foo")) == "string" + ## static: doAssert $(type(@['A', 'B'])) == "seq[char]" -proc `$`*[T: tuple](x: T): string = - ## Generic `$` operator for tuples that is lifted from the components +when defined(nimHasIsNamedTuple): + proc isNamedTuple(T: typedesc): bool {.magic: "TypeTrait".} +else: + # for bootstrap; remove after release 1.2 + proc isNamedTuple(T: typedesc): bool = + # Taken from typetraits. + when T isnot tuple: result = false + else: + var t: T + for name, _ in t.fieldPairs: + when name == "Field0": + return compiles(t.Field0) + else: + return true + return false + + +proc `$`*[T: tuple|object](x: T): string = + ## Generic ``$`` operator for tuples that is lifted from the components ## of `x`. Example: ## ## .. code-block:: Nim ## $(23, 45) == "(23, 45)" ## $(a: 23, b: 45) == "(a: 23, b: 45)" ## $() == "()" - tupleObjectDollar(result, x) + result = "(" + var firstElement = true + const isNamed = T is object or isNamedTuple(T) + when not isNamed: + var count = 0 + for name, value in fieldPairs(x): + if not firstElement: result.add(", ") + when isNamed: + result.add(name) + result.add(": ") + else: + count.inc + when compiles($value): + when value isnot string and value isnot seq and compiles(value.isNil): + if value.isNil: result.add "nil" + else: result.addQuoted(value) + else: + result.addQuoted(value) + firstElement = false + else: + result.add("...") + firstElement = false + when not isNamed: + if count == 1: + result.add(",") # $(1,) should print as the semantically legal (1,) + result.add(")") -when not defined(nimPreviewSlimSystem): - import std/objectdollar - export objectdollar proc collectionToString[T](x: T, prefix, separator, suffix: string): string = result = prefix @@ -106,7 +122,7 @@ proc collectionToString[T](x: T, prefix, separator, suffix: string): string = result.add(suffix) proc `$`*[T](x: set[T]): string = - ## Generic `$` operator for sets that is lifted from the components + ## Generic ``$`` operator for sets that is lifted from the components ## of `x`. Example: ## ## .. code-block:: Nim @@ -114,7 +130,7 @@ proc `$`*[T](x: set[T]): string = collectionToString(x, "{", ", ", "}") proc `$`*[T](x: seq[T]): string = - ## Generic `$` operator for seqs that is lifted from the components + ## Generic ``$`` operator for seqs that is lifted from the components ## of `x`. Example: ## ## .. code-block:: Nim @@ -122,7 +138,7 @@ proc `$`*[T](x: seq[T]): string = collectionToString(x, "@[", ", ", "]") proc `$`*[T, U](x: HSlice[T, U]): string = - ## Generic `$` operator for slices that is lifted from the components + ## Generic ``$`` operator for slices that is lifted from the components ## of `x`. Example: ## ## .. code-block:: Nim @@ -134,11 +150,11 @@ proc `$`*[T, U](x: HSlice[T, U]): string = when not defined(nimNoArrayToString): proc `$`*[T, IDX](x: array[IDX, T]): string = - ## Generic `$` operator for arrays that is lifted from the components. + ## Generic ``$`` operator for arrays that is lifted from the components. collectionToString(x, "[", ", ", "]") proc `$`*[T](x: openArray[T]): string = - ## Generic `$` operator for openarrays that is lifted from the components + ## Generic ``$`` operator for openarrays that is lifted from the components ## of `x`. Example: ## ## .. code-block:: Nim diff --git a/lib/system/dyncalls.nim b/lib/system/dyncalls.nim index 2162b234f..d16dbdf92 100644 --- a/lib/system/dyncalls.nim +++ b/lib/system/dyncalls.nim @@ -19,42 +19,26 @@ const proc nimLoadLibraryError(path: string) = # carefully written to avoid memory allocation: - const prefix = "could not load: " - cstderr.rawWrite(prefix) + cstderr.rawWrite("could not load: ") cstderr.rawWrite(path) - when not defined(nimDebugDlOpen) and not defined(windows): - cstderr.rawWrite("\n(compile with -d:nimDebugDlOpen for more information)") - when defined(windows): - const badExe = "\n(bad format; library may be wrong architecture)" - let loadError = GetLastError() - if loadError == ERROR_BAD_EXE_FORMAT: - cstderr.rawWrite(badExe) - when defined(guiapp): - # Because console output is not shown in GUI apps, display the error as a - # message box instead: - var - msg: array[1000, char] - msgLeft = msg.len - 1 # leave (at least) one for nullchar - msgIdx = 0 - copyMem(msg[msgIdx].addr, prefix.cstring, prefix.len) - msgLeft -= prefix.len - msgIdx += prefix.len - let pathLen = min(path.len, msgLeft) - copyMem(msg[msgIdx].addr, path.cstring, pathLen) - msgLeft -= pathLen - msgIdx += pathLen - if loadError == ERROR_BAD_EXE_FORMAT and msgLeft >= badExe.len: - copyMem(msg[msgIdx].addr, badExe.cstring, badExe.len) - discard MessageBoxA(nil, msg[0].addr, nil, 0) cstderr.rawWrite("\n") - rawQuit(1) + when not defined(nimDebugDlOpen) and not defined(windows): + cstderr.rawWrite("compile with -d:nimDebugDlOpen for more information\n") + when defined(windows) and defined(guiapp): + # Because console output is not shown in GUI apps, display error as message box: + const prefix = "could not load: " + var msg: array[1000, char] + copyMem(msg[0].addr, prefix.cstring, prefix.len) + copyMem(msg[prefix.len].addr, path.cstring, min(path.len + 1, 1000 - prefix.len)) + discard MessageBoxA(nil, msg[0].addr, nil, 0) + quit(1) proc procAddrError(name: cstring) {.compilerproc, nonReloadable, hcrInline.} = # carefully written to avoid memory allocation: cstderr.rawWrite("could not import: ") cstderr.rawWrite(name) cstderr.rawWrite("\n") - rawQuit(1) + quit(1) # this code was inspired from Lua's source code: # Lua - An Extensible Extension Language @@ -91,10 +75,7 @@ when defined(posix): dlclose(lib) proc nimLoadLibrary(path: string): LibHandle = - let flags = - when defined(globalSymbols): RTLD_NOW or RTLD_GLOBAL - else: RTLD_NOW - result = dlopen(path, flags) + result = dlopen(path, RTLD_NOW) when defined(nimDebugDlOpen): let error = dlerror() if error != nil: @@ -161,38 +142,41 @@ elif defined(windows) or defined(dos): dec(m) k = k div 10 if k == 0: break - result = getProcAddress(cast[THINSTANCE](lib), cast[cstring](addr decorated)) + when defined(nimNoArrayToCstringConversion): + result = getProcAddress(cast[THINSTANCE](lib), addr decorated) + else: + result = getProcAddress(cast[THINSTANCE](lib), decorated) if result != nil: return procAddrError(name) elif defined(genode): - proc nimUnloadLibrary(lib: LibHandle) = - raiseAssert("nimUnloadLibrary not implemented") + proc nimUnloadLibrary(lib: LibHandle) {. + error: "nimUnloadLibrary not implemented".} - proc nimLoadLibrary(path: string): LibHandle = - raiseAssert("nimLoadLibrary not implemented") + proc nimLoadLibrary(path: string): LibHandle {. + error: "nimLoadLibrary not implemented".} - proc nimGetProcAddr(lib: LibHandle, name: cstring): ProcAddr = - raiseAssert("nimGetProcAddr not implemented") + proc nimGetProcAddr(lib: LibHandle, name: cstring): ProcAddr {. + error: "nimGetProcAddr not implemented".} -elif defined(nintendoswitch) or defined(freertos) or defined(zephyr) or defined(nuttx): +elif defined(nintendoswitch): proc nimUnloadLibrary(lib: LibHandle) = cstderr.rawWrite("nimUnLoadLibrary not implemented") cstderr.rawWrite("\n") - rawQuit(1) + quit(1) proc nimLoadLibrary(path: string): LibHandle = cstderr.rawWrite("nimLoadLibrary not implemented") cstderr.rawWrite("\n") - rawQuit(1) + quit(1) proc nimGetProcAddr(lib: LibHandle, name: cstring): ProcAddr = cstderr.rawWrite("nimGetProAddr not implemented") cstderr.rawWrite(name) cstderr.rawWrite("\n") - rawQuit(1) + quit(1) else: {.error: "no implementation for dyncalls".} diff --git a/lib/system/embedded.nim b/lib/system/embedded.nim index e0b053c7b..d1e05dad5 100644 --- a/lib/system/embedded.nim +++ b/lib/system/embedded.nim @@ -32,14 +32,10 @@ const proc quitOrDebug() {.noreturn, importc: "abort", header: "", nodecl.} proc raiseException(e: ref Exception, ename: cstring) {.compilerRtl.} = - sysFatal(ReraiseDefect, "exception handling is not available") - -proc raiseExceptionEx(e: sink(ref Exception), ename, procname, filename: cstring, - line: int) {.compilerRtl.} = - sysFatal(ReraiseDefect, "exception handling is not available") + sysFatal(ReraiseError, "exception handling is not available") proc reraiseException() {.compilerRtl.} = - sysFatal(ReraiseDefect, "no exception to reraise") + sysFatal(ReraiseError, "no exception to reraise") proc writeStackTrace() = discard @@ -47,14 +43,4 @@ proc unsetControlCHook() = discard proc setControlCHook(hook: proc () {.noconv.}) = discard proc closureIterSetupExc(e: ref Exception) {.compilerproc, inline.} = - sysFatal(ReraiseDefect, "exception handling is not available") - -when gotoBasedExceptions: - var nimInErrorMode {.threadvar.}: bool - - proc nimErrorFlag(): ptr bool {.compilerRtl, inl.} = - result = addr(nimInErrorMode) - - proc nimTestErrorFlag() {.compilerRtl.} = - if nimInErrorMode: - sysFatal(ReraiseDefect, "exception handling is not available") + sysFatal(ReraiseError, "exception handling is not available") diff --git a/lib/system/exceptions.nim b/lib/system/exceptions.nim index 63588f858..f575f9b9f 100644 --- a/lib/system/exceptions.nim +++ b/lib/system/exceptions.nim @@ -1,13 +1,53 @@ -## Exception and effect types used in Nim code. - type + RootEffect* {.compilerproc.} = object of RootObj ## \ + ## Base effect class. + ## + ## Each effect should inherit from `RootEffect` unless you know what + ## you're doing. TimeEffect* = object of RootEffect ## Time effect. IOEffect* = object of RootEffect ## IO effect. ReadIOEffect* = object of IOEffect ## Effect describing a read IO operation. WriteIOEffect* = object of IOEffect ## Effect describing a write IO operation. ExecIOEffect* = object of IOEffect ## Effect describing an executing IO operation. -type + StackTraceEntry* = object ## In debug mode exceptions store the stack trace that led + ## to them. A `StackTraceEntry` is a single entry of the + ## stack trace. + procname*: cstring ## Name of the proc that is currently executing. + line*: int ## Line number of the proc that is currently executing. + filename*: cstring ## Filename of the proc that is currently executing. + + Exception* {.compilerproc, magic: "Exception".} = object of RootObj ## \ + ## Base exception class. + ## + ## Each exception has to inherit from `Exception`. See the full `exception + ## hierarchy `_. + parent*: ref Exception ## Parent exception (can be used as a stack). + name*: cstring ## The exception's name is its Nim identifier. + ## This field is filled automatically in the + ## ``raise`` statement. + msg* {.exportc: "message".}: string ## The exception's message. Not + ## providing an exception message + ## is bad style. + when defined(js): + trace: string + else: + trace: seq[StackTraceEntry] + when defined(nimBoostrapCsources0_19_0): + # see #10315, bootstrap with `nim cpp` from csources gave error: + # error: no member named 'raise_id' in 'Exception' + raise_id: uint # set when exception is raised + else: + raiseId: uint # set when exception is raised + up: ref Exception # used for stacking exceptions. Not exported! + + Defect* = object of Exception ## \ + ## Abstract base class for all exceptions that Nim's runtime raises + ## but that are strictly uncatchable as they can also be mapped to + ## a ``quit`` / ``trap`` / ``exit`` operation. + + CatchableError* = object of Exception ## \ + ## Abstract class for all exceptions that are catchable. IOError* = object of CatchableError ## \ ## Raised if an IO error occurred. EOFError* = object of IOError ## \ @@ -19,19 +59,19 @@ type ## Raised if a dynamic library could not be loaded. ResourceExhaustedError* = object of CatchableError ## \ ## Raised if a resource request could not be fulfilled. - ArithmeticDefect* = object of Defect ## \ + ArithmeticError* = object of Defect ## \ ## Raised if any kind of arithmetic error occurred. - DivByZeroDefect* = object of ArithmeticDefect ## \ + DivByZeroError* = object of ArithmeticError ## \ ## Raised for runtime integer divide-by-zero errors. - OverflowDefect* = object of ArithmeticDefect ## \ + OverflowError* = object of ArithmeticError ## \ ## Raised for runtime integer overflows. ## ## This happens for calculations whose results are too large to fit in the ## provided bits. - AccessViolationDefect* = object of Defect ## \ + AccessViolationError* = object of Defect ## \ ## Raised for invalid memory access errors - AssertionDefect* = object of Defect ## \ + AssertionError* = object of Defect ## \ ## Raised when assertion is proved wrong. ## ## Usually the result of using the `assert() template @@ -44,79 +84,54 @@ type ## Mostly used by the `tables `_ module, it can also be raised ## by other collection modules like `sets `_ or `strtabs ## `_. - OutOfMemDefect* = object of Defect ## \ + OutOfMemError* = object of Defect ## \ ## Raised for unsuccessful attempts to allocate memory. - IndexDefect* = object of Defect ## \ + IndexError* = object of Defect ## \ ## Raised if an array index is out of bounds. - FieldDefect* = object of Defect ## \ + FieldError* = object of Defect ## \ ## Raised if a record field is not accessible because its discriminant's ## value does not fit. - RangeDefect* = object of Defect ## \ + RangeError* = object of Defect ## \ ## Raised if a range check error occurred. - StackOverflowDefect* = object of Defect ## \ + StackOverflowError* = object of Defect ## \ ## Raised if the hardware stack used for subroutine calls overflowed. - ReraiseDefect* = object of Defect ## \ + ReraiseError* = object of Defect ## \ ## Raised if there is no exception to reraise. - ObjectAssignmentDefect* = object of Defect ## \ + ObjectAssignmentError* = object of Defect ## \ ## Raised if an object gets assigned to its parent's object. - ObjectConversionDefect* = object of Defect ## \ + ObjectConversionError* = object of Defect ## \ ## Raised if an object is converted to an incompatible object type. - ## You can use `of` operator to check if conversion will succeed. - FloatingPointDefect* = object of Defect ## \ + ## You can use ``of`` operator to check if conversion will succeed. + FloatingPointError* = object of Defect ## \ ## Base class for floating point exceptions. - FloatInvalidOpDefect* = object of FloatingPointDefect ## \ + FloatInvalidOpError* = object of FloatingPointError ## \ ## Raised by invalid operations according to IEEE. ## - ## Raised by `0.0/0.0`, for example. - FloatDivByZeroDefect* = object of FloatingPointDefect ## \ + ## Raised by ``0.0/0.0``, for example. + FloatDivByZeroError* = object of FloatingPointError ## \ ## Raised by division by zero. ## ## Divisor is zero and dividend is a finite nonzero number. - FloatOverflowDefect* = object of FloatingPointDefect ## \ + FloatOverflowError* = object of FloatingPointError ## \ ## Raised for overflows. ## ## The operation produced a result that exceeds the range of the exponent. - FloatUnderflowDefect* = object of FloatingPointDefect ## \ + FloatUnderflowError* = object of FloatingPointError ## \ ## Raised for underflows. ## ## The operation produced a result that is too small to be represented as a ## normal number. - FloatInexactDefect* = object of FloatingPointDefect ## \ + FloatInexactError* = object of FloatingPointError ## \ ## Raised for inexact results. ## ## The operation produced a result that cannot be represented with infinite - ## precision -- for example: `2.0 / 3.0, log(1.1)` + ## precision -- for example: ``2.0 / 3.0, log(1.1)`` ## ## **Note**: Nim currently does not detect these! - DeadThreadDefect* = object of Defect ## \ + DeadThreadError* = object of Defect ## \ ## Raised if it is attempted to send a message to a dead thread. - NilAccessDefect* = object of Defect ## \ - ## Raised on dereferences of `nil` pointers. + NilAccessError* = object of Defect ## \ + ## Raised on dereferences of ``nil`` pointers. ## ## This is only raised if the `segfaults module `_ was imported! - -when not defined(nimPreviewSlimSystem): - type - ArithmeticError* {.deprecated: "See corresponding Defect".} = ArithmeticDefect - DivByZeroError* {.deprecated: "See corresponding Defect".} = DivByZeroDefect - OverflowError* {.deprecated: "See corresponding Defect".} = OverflowDefect - AccessViolationError* {.deprecated: "See corresponding Defect".} = AccessViolationDefect - AssertionError* {.deprecated: "See corresponding Defect".} = AssertionDefect - OutOfMemError* {.deprecated: "See corresponding Defect".} = OutOfMemDefect - IndexError* {.deprecated: "See corresponding Defect".} = IndexDefect - - FieldError* {.deprecated: "See corresponding Defect".} = FieldDefect - RangeError* {.deprecated: "See corresponding Defect".} = RangeDefect - StackOverflowError* {.deprecated: "See corresponding Defect".} = StackOverflowDefect - ReraiseError* {.deprecated: "See corresponding Defect".} = ReraiseDefect - ObjectAssignmentError* {.deprecated: "See corresponding Defect".} = ObjectAssignmentDefect - ObjectConversionError* {.deprecated: "See corresponding Defect".} = ObjectConversionDefect - FloatingPointError* {.deprecated: "See corresponding Defect".} = FloatingPointDefect - FloatInvalidOpError* {.deprecated: "See corresponding Defect".} = FloatInvalidOpDefect - FloatDivByZeroError* {.deprecated: "See corresponding Defect".} = FloatDivByZeroDefect - FloatOverflowError* {.deprecated: "See corresponding Defect".} = FloatOverflowDefect - FloatUnderflowError* {.deprecated: "See corresponding Defect".} = FloatUnderflowDefect - FloatInexactError* {.deprecated: "See corresponding Defect".} = FloatInexactDefect - DeadThreadError* {.deprecated: "See corresponding Defect".} = DeadThreadDefect - NilAccessError* {.deprecated: "See corresponding Defect".} = NilAccessDefect diff --git a/lib/system/excpt.nim b/lib/system/excpt.nim index 86cfff9cd..a9c7ba02a 100644 --- a/lib/system/excpt.nim +++ b/lib/system/excpt.nim @@ -10,11 +10,6 @@ # Exception handling code. Carefully coded so that tiny programs which do not # use the heap (and nor exceptions) do not include the GC or memory allocator. -import std/private/miscdollars -import stacktraces - -const noStacktraceAvailable = "No stack traceback available\n" - var errorMessageWriter*: (proc(msg: string) {.tags: [WriteIOEffect], benign, nimcall.}) @@ -22,27 +17,17 @@ var ## instead of `stdmsg.write` when printing stacktrace. ## Unstable API. -when defined(windows): - proc GetLastError(): int32 {.header: "", nodecl.} - const ERROR_BAD_EXE_FORMAT = 193 - when not defined(windows) or not defined(guiapp): proc writeToStdErr(msg: cstring) = rawWrite(cstderr, msg) - proc writeToStdErr(msg: cstring, length: int) = - rawWriteString(cstderr, msg, length) + else: proc MessageBoxA(hWnd: pointer, lpText, lpCaption: cstring, uType: int): int32 {. header: "", nodecl.} + proc writeToStdErr(msg: cstring) = discard MessageBoxA(nil, msg, nil, 0) - proc writeToStdErr(msg: cstring, length: int) = - discard MessageBoxA(nil, msg, nil, 0) -proc writeToStdErr(msg: string) {.inline.} = - # fix bug #13115: handles correctly '\0' unlike default implicit conversion to cstring - writeToStdErr(msg.cstring, msg.len) - -proc showErrorMessage(data: cstring, length: int) {.gcsafe, raises: [].} = +proc showErrorMessage(data: cstring) {.gcsafe, raises: [].} = var toWrite = true if errorMessageWriter != nil: try: @@ -55,10 +40,7 @@ proc showErrorMessage(data: cstring, length: int) {.gcsafe, raises: [].} = # stderr not available by default, use the LOG session echo data else: - writeToStdErr(data, length) - -proc showErrorMessage2(data: string) {.inline.} = - showErrorMessage(data.cstring, data.len) + writeToStdErr(data) proc chckIndx(i, a, b: int): int {.inline, compilerproc, benign.} proc chckRange(i, a, b: int): int {.inline, compilerproc, benign.} @@ -71,8 +53,6 @@ type len: int prev: ptr GcFrameHeader -when NimStackTraceMsgs: - var frameMsgBuf* {.threadvar.}: string var framePtr {.threadvar.}: PFrame excHandler {.threadvar.}: PSafePoint @@ -81,6 +61,10 @@ var currException {.threadvar.}: ref Exception gcFramePtr {.threadvar.}: GcFrame +when defined(cpp) and not defined(noCppExceptions) and not gotoBasedExceptions: + var + raiseCounter {.threadvar.}: uint + type FrameState = tuple[gcFramePtr: GcFrame, framePtr: PFrame, excHandler: PSafePoint, currException: ref Exception] @@ -132,25 +116,51 @@ proc popSafePoint {.compilerRtl, inl.} = proc pushCurrentException(e: sink(ref Exception)) {.compilerRtl, inl.} = e.up = currException currException = e - #showErrorMessage2 "A" + #showErrorMessage "A" proc popCurrentException {.compilerRtl, inl.} = currException = currException.up - #showErrorMessage2 "B" + #showErrorMessage "B" proc popCurrentExceptionEx(id: uint) {.compilerRtl.} = - discard "only for bootstrapping compatbility" + # in cpp backend exceptions can pop-up in the different order they were raised, example #5628 + if currException.raiseId == id: + currException = currException.up + else: + var cur = currException.up + var prev = currException + while cur != nil and cur.raiseId != id: + prev = cur + cur = cur.up + if cur == nil: + showErrorMessage("popCurrentExceptionEx() exception was not found in the exception stack. Aborting...") + quit(1) + prev.up = cur.up proc closureIterSetupExc(e: ref Exception) {.compilerproc, inline.} = currException = e # some platforms have native support for stack traces: const - nativeStackTraceSupported = (defined(macosx) or defined(linux)) and + nativeStackTraceSupported* = (defined(macosx) or defined(linux)) and not NimStackTrace hasSomeStackTrace = NimStackTrace or defined(nimStackTraceOverride) or (defined(nativeStackTrace) and nativeStackTraceSupported) +when defined(nimStackTraceOverride): + type StackTraceOverrideProc* = proc (): string {.nimcall, noinline, benign, raises: [], tags: [].} + ## Procedure type for overriding the default stack trace. + + var stackTraceOverrideGetTraceback: StackTraceOverrideProc = proc(): string {.noinline.} = + result = "Stack trace override procedure not registered.\n" + + proc registerStackTraceOverride*(overrideProc: StackTraceOverrideProc) = + ## Override the default stack trace inside rawWriteStackTrace() with your + ## own procedure. + stackTraceOverrideGetTraceback = overrideProc + + proc auxWriteStackTraceWithOverride(s: var string) = + add(s, stackTraceOverrideGetTraceback()) when defined(nativeStacktrace) and nativeStackTraceSupported: type @@ -168,13 +178,13 @@ when defined(nativeStacktrace) and nativeStackTraceSupported: when not hasThreadSupport: var - tempAddresses: array[maxStackTraceLines, pointer] # should not be alloc'd on stack + tempAddresses: array[0..127, pointer] # should not be alloc'd on stack tempDlInfo: TDl_info proc auxWriteStackTraceWithBacktrace(s: var string) = when hasThreadSupport: var - tempAddresses: array[maxStackTraceLines, pointer] # but better than a threadvar + tempAddresses: array[0..127, pointer] # but better than a threadvar tempDlInfo: TDl_info # This is allowed to be expensive since it only happens during crashes # (but this way you don't need manual stack tracing) @@ -202,7 +212,11 @@ when defined(nativeStacktrace) and nativeStackTraceSupported: when hasSomeStackTrace and not hasThreadSupport: var - tempFrames: array[maxStackTraceLines, PFrame] # should not be alloc'd on stack + tempFrames: array[0..127, PFrame] # should not be alloc'd on stack + +const + reraisedFromBegin = -10 + reraisedFromEnd = -100 template reraisedFrom(z): untyped = StackTraceEntry(procname: nil, line: z, filename: nil) @@ -226,35 +240,21 @@ proc auxWriteStackTrace(f: PFrame; s: var seq[StackTraceEntry]) = s[last] = StackTraceEntry(procname: it.procname, line: it.line, filename: it.filename) - when NimStackTraceMsgs: - let first = if it.prev == nil: 0 else: it.prev.frameMsgLen - if it.frameMsgLen > first: - s[last].frameMsg.setLen(it.frameMsgLen - first) - # somehow string slicing not available here - for i in first .. it.frameMsgLen-1: - s[last].frameMsg[i-first] = frameMsgBuf[i] it = it.prev dec last -template addFrameEntry(s: var string, f: StackTraceEntry|PFrame) = +template addFrameEntry(s, f: untyped) = var oldLen = s.len - s.toLocation(f.filename, f.line, 0) + add(s, f.filename) + if f.line > 0: + add(s, '(') + add(s, $f.line) + add(s, ')') for k in 1..max(1, 25-(s.len-oldLen)): add(s, ' ') add(s, f.procname) - when NimStackTraceMsgs: - when typeof(f) is StackTraceEntry: - add(s, f.frameMsg) - else: - var first = if f.prev == nil: 0 else: f.prev.frameMsgLen - for i in first..raise();".} elif defined(nimQuirky) or gotoBasedExceptions: - pushCurrentException(e) + # XXX This check should likely also be done in the setjmp case below. + if e != currException: + pushCurrentException(e) when gotoBasedExceptions: inc nimInErrorMode else: @@ -458,19 +461,14 @@ proc raiseExceptionAux(e: sink(ref Exception)) {.nodestroy.} = c_longjmp(excHandler.context, 1) else: reportUnhandledError(e) - rawQuit(1) + quit(1) proc raiseExceptionEx(e: sink(ref Exception), ename, procname, filename: cstring, line: int) {.compilerRtl, nodestroy.} = if e.name.isNil: e.name = ename when hasSomeStackTrace: when defined(nimStackTraceOverride): - if e.trace.len == 0: - rawWriteStackTrace(e.trace) - else: - e.trace.add reraisedFrom(reraisedFromBegin) - auxWriteStackTraceWithOverride(e.trace) - e.trace.add reraisedFrom(reraisedFromEnd) + e.trace = @[] elif NimStackTrace: if e.trace.len == 0: rawWriteStackTrace(e.trace) @@ -488,35 +486,27 @@ proc raiseException(e: sink(ref Exception), ename: cstring) {.compilerRtl.} = proc reraiseException() {.compilerRtl.} = if currException == nil: - sysFatal(ReraiseDefect, "no exception to reraise") + sysFatal(ReraiseError, "no exception to reraise") else: when gotoBasedExceptions: inc nimInErrorMode else: raiseExceptionAux(currException) -proc threadTrouble() = - # also forward declared, it is 'raises: []' hence the try-except. - try: - if currException != nil: reportUnhandledError(currException) - except: - discard - rawQuit 1 - proc writeStackTrace() = when hasSomeStackTrace: var s = "" rawWriteStackTrace(s) + cast[proc (s: cstring) {.noSideEffect, tags: [], nimcall, raises: [].}](showErrorMessage)(s) else: - let s = noStacktraceAvailable - cast[proc (s: string) {.noSideEffect, tags: [], nimcall, raises: [].}](showErrorMessage2)(s) + cast[proc (s: cstring) {.noSideEffect, tags: [], nimcall, raises: [].}](showErrorMessage)("No stack traceback available\n") proc getStackTrace(): string = when hasSomeStackTrace: result = "" rawWriteStackTrace(result) else: - result = noStacktraceAvailable + result = "No stack traceback available\n" proc getStackTrace(e: ref Exception): string = if not isNil(e): @@ -524,10 +514,13 @@ proc getStackTrace(e: ref Exception): string = else: result = "" -proc getStackTraceEntries*(e: ref Exception): lent seq[StackTraceEntry] = - ## Returns the attached stack trace to the exception `e` as - ## a `seq`. This is not yet available for the JS backend. - e.trace +proc getStackTraceEntries*(e: ref Exception): seq[StackTraceEntry] = + ## Returns the attached stack trace to the exception ``e`` as + ## a ``seq``. This is not yet available for the JS backend. + when not defined(nimSeqsV2): + shallowCopy(result, e.trace) + else: + result = move(e.trace) proc getStackTraceEntries*(): seq[StackTraceEntry] = ## Returns the stack trace entries for the current stack trace. @@ -539,33 +532,26 @@ const nimCallDepthLimit {.intdefine.} = 2000 proc callDepthLimitReached() {.noinline.} = writeStackTrace() - let msg = "Error: call depth limit reached in a debug build (" & + showErrorMessage("Error: call depth limit reached in a debug build (" & $nimCallDepthLimit & " function calls). You can change it with " & "-d:nimCallDepthLimit= but really try to avoid deep " & - "recursions instead.\n" - showErrorMessage2(msg) - rawQuit(1) + "recursions instead.\n") + quit(1) proc nimFrame(s: PFrame) {.compilerRtl, inl, raises: [].} = - if framePtr == nil: - s.calldepth = 0 - when NimStackTraceMsgs: s.frameMsgLen = 0 - else: - s.calldepth = framePtr.calldepth+1 - when NimStackTraceMsgs: s.frameMsgLen = framePtr.frameMsgLen + s.calldepth = if framePtr == nil: 0 else: framePtr.calldepth+1 s.prev = framePtr framePtr = s if s.calldepth == nimCallDepthLimit: callDepthLimitReached() when defined(cpp) and appType != "lib" and not gotoBasedExceptions and not defined(js) and not defined(nimscript) and - hostOS != "standalone" and hostOS != "any" and not defined(noCppExceptions) and - not defined(nimQuirky): + hostOS != "standalone" and not defined(noCppExceptions): type StdException {.importcpp: "std::exception", header: "".} = object - proc what(ex: StdException): cstring {.importcpp: "((char *)#.what())", nodecl.} + proc what(ex: StdException): cstring {.importcpp: "((char *)#.what())".} proc setTerminate(handler: proc() {.noconv.}) {.importc: "std::set_terminate", header: "".} @@ -576,9 +562,9 @@ when defined(cpp) and appType != "lib" and not gotoBasedExceptions and var msg = "Unknown error in unexpected exception handler" try: - {.emit: "#if !defined(_MSC_VER) || (_MSC_VER >= 1923)".} + {.emit"#if !defined(_MSC_VER) || (_MSC_VER >= 1923)".} raise - {.emit: "#endif".} + {.emit"#endif".} except Exception: msg = currException.getStackTrace() & "Error: unhandled exception: " & currException.msg & " [" & $currException.name & "]" @@ -587,9 +573,9 @@ when defined(cpp) and appType != "lib" and not gotoBasedExceptions and except: msg = "Error: unhandled unknown cpp exception" - {.emit: "#if defined(_MSC_VER) && (_MSC_VER < 1923)".} + {.emit"#if defined(_MSC_VER) && (_MSC_VER < 1923)".} msg = "Error: unhandled unknown cpp exception" - {.emit: "#endif".} + {.emit"#endif".} when defined(genode): # stderr not available by default, use the LOG session @@ -597,12 +583,9 @@ when defined(cpp) and appType != "lib" and not gotoBasedExceptions and else: writeToStdErr msg & "\n" - rawQuit 1 + quit 1 when not defined(noSignalHandler) and not defined(useNimRtl): - type Sighandler = proc (a: cint) {.noconv, benign.} - # xxx factor with ansi_c.CSighandlerT, posix.Sighandler - proc signalHandler(sign: cint) {.exportc: "signalHandler", noconv.} = template processSignal(s, action: untyped) {.dirty.} = if s == SIGINT: action("SIGINT: Interrupted by Ctrl-C.\n") @@ -630,34 +613,17 @@ when not defined(noSignalHandler) and not defined(useNimRtl): var buf = newStringOfCap(2000) rawWriteStackTrace(buf) processSignal(sign, buf.add) # nice hu? currying a la Nim :-) - showErrorMessage2(buf) + showErrorMessage(buf) when not usesDestructors: GC_enable() else: var msg: cstring template asgn(y) = msg = y processSignal(sign, asgn) - # xxx use string for msg instead of cstring, and here use showErrorMessage2(msg) - # unless there's a good reason to use cstring in signal handler to avoid - # using gc? - showErrorMessage(msg, msg.len) - - when defined(posix): - # reset the signal handler to OS default - c_signal(sign, SIG_DFL) - - # re-raise the signal, which will arrive once this handler exit. - # this lets the OS perform actions like core dumping and will - # also return the correct exit code to the shell. - discard c_raise(sign) - else: - rawQuit(1) - - var SIG_IGN {.importc: "SIG_IGN", header: "".}: Sighandler + showErrorMessage(msg) + quit(1) # always quit when SIGABRT proc registerSignalHandler() = - # xxx `signal` is deprecated and has many caveats, we should use `sigaction` instead, e.g. - # https://stackoverflow.com/questions/231912/what-is-the-difference-between-sigaction-and-signal c_signal(SIGINT, signalHandler) c_signal(SIGSEGV, signalHandler) c_signal(SIGABRT, signalHandler) @@ -666,17 +632,14 @@ when not defined(noSignalHandler) and not defined(useNimRtl): when declared(SIGBUS): c_signal(SIGBUS, signalHandler) when declared(SIGPIPE): - when defined(nimLegacySigpipeHandler): - c_signal(SIGPIPE, signalHandler) - else: - c_signal(SIGPIPE, SIG_IGN) + c_signal(SIGPIPE, signalHandler) registerSignalHandler() # call it in initialization section proc setControlCHook(hook: proc () {.noconv.}) = # ugly cast, but should work on all architectures: - when declared(Sighandler): - c_signal(SIGINT, cast[Sighandler](hook)) + type SignalHandler = proc (sign: cint) {.noconv, benign.} + c_signal(SIGINT, cast[SignalHandler](hook)) when not defined(noSignalHandler) and not defined(useNimRtl): proc unsetControlCHook() = diff --git a/lib/system/fatal.nim b/lib/system/fatal.nim index 6073ee779..d68d06712 100644 --- a/lib/system/fatal.nim +++ b/lib/system/fatal.nim @@ -9,48 +9,57 @@ {.push profiler: off.} -const gotoBasedExceptions = compileOption("exceptions", "goto") +when defined(nimHasExceptionsQuery): + const gotoBasedExceptions = compileOption("exceptions", "goto") +else: + const gotoBasedExceptions = false when hostOS == "standalone": include "$projectpath/panicoverride" - func sysFatal(exceptn: typedesc, message: string) {.inline.} = + proc sysFatal(exceptn: typedesc, message: string) {.inline.} = panic(message) - func sysFatal(exceptn: typedesc, message, arg: string) {.inline.} = + proc sysFatal(exceptn: typedesc, message, arg: string) {.inline.} = rawoutput(message) panic(arg) -elif (defined(nimQuirky) or defined(nimPanics)) and not defined(nimscript): +elif (defined(nimQuirky) or gotoBasedExceptions) and not defined(nimscript): import ansi_c - func name(t: typedesc): string {.magic: "TypeTrait".} + proc name(t: typedesc): string {.magic: "TypeTrait".} - func sysFatal(exceptn: typedesc, message, arg: string) {.inline, noreturn.} = - when nimvm: - # TODO when doAssertRaises works in CT, add a test for it - raise (ref exceptn)(msg: message & arg) - else: - {.noSideEffect.}: - writeStackTrace() - var buf = newStringOfCap(200) - add(buf, "Error: unhandled exception: ") - add(buf, message) - add(buf, arg) - add(buf, " [") - add(buf, name exceptn) - add(buf, "]\n") - cstderr.rawWrite buf - rawQuit 1 + proc sysFatal(exceptn: typedesc, message, arg: string) {.inline, noreturn.} = + writeStackTrace() + var buf = newStringOfCap(200) + add(buf, "Error: unhandled exception: ") + add(buf, message) + add(buf, arg) + add(buf, " [") + add(buf, name exceptn) + add(buf, "]\n") + cstderr.rawWrite buf + quit 1 - func sysFatal(exceptn: typedesc, message: string) {.inline, noreturn.} = + proc sysFatal(exceptn: typedesc, message: string) {.inline, noreturn.} = sysFatal(exceptn, message, "") else: - func sysFatal(exceptn: typedesc, message: string) {.inline, noreturn.} = - raise (ref exceptn)(msg: message) - - func sysFatal(exceptn: typedesc, message, arg: string) {.inline, noreturn.} = - raise (ref exceptn)(msg: message & arg) + proc sysFatal(exceptn: typedesc, message: string) {.inline, noreturn.} = + when declared(owned): + var e: owned(ref exceptn) + else: + var e: ref exceptn + new(e) + e.msg = message + raise e + proc sysFatal(exceptn: typedesc, message, arg: string) {.inline, noreturn.} = + when declared(owned): + var e: owned(ref exceptn) + else: + var e: ref exceptn + new(e) + e.msg = message & arg + raise e {.pop.} diff --git a/lib/system/formatfloat.nim b/lib/system/formatfloat.nim index 70dd857d5..cb46c8c36 100644 --- a/lib/system/formatfloat.nim +++ b/lib/system/formatfloat.nim @@ -1,6 +1,59 @@ -when not defined(nimPreviewSlimSystem): - import std/formatfloat - export formatfloat - {.deprecated: "use `std/formatfloat`".} -else: - {.error: "use `std/formatfloat`".} +# +# +# Nim's Runtime Library +# (c) Copyright 2019 Nim contributors +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +proc c_sprintf(buf, frmt: cstring): cint {.header: "", + importc: "sprintf", varargs, noSideEffect.} + +proc writeToBuffer(buf: var array[65, char]; value: cstring) = + var i = 0 + while value[i] != '\0': + buf[i] = value[i] + inc i + +proc writeFloatToBuffer*(buf: var array[65, char]; value: BiggestFloat): int = + ## This is the implementation to format floats in the Nim + ## programming language. The specific format for floating point + ## numbers is not specified in the Nim programming language and + ## might change slightly in the future, but at least wherever you + ## format a float, it should be consistent. + ## + ## returns the amount of bytes written to `buf` not counting the + ## terminating '\0' character. + ## + ## * `buf` - A buffer to write into. The buffer does not need to be + ## initialized and it will be overridden. + ## + var n: int = c_sprintf(addr buf, "%.16g", value) + var hasDot = false + for i in 0..n-1: + if buf[i] == ',': + buf[i] = '.' + hasDot = true + elif buf[i] in {'a'..'z', 'A'..'Z', '.'}: + hasDot = true + if not hasDot: + buf[n] = '.' + buf[n+1] = '0' + buf[n+2] = '\0' + result = n + 2 + else: + result = n + # On Windows nice numbers like '1.#INF', '-1.#INF' or '1.#NAN' or 'nan(ind)' + # of '-1.#IND' are produced. + # We want to get rid of these here: + if buf[n-1] in {'n', 'N', 'D', 'd', ')'}: + writeToBuffer(buf, "nan") + result = 3 + elif buf[n-1] == 'F': + if buf[0] == '-': + writeToBuffer(buf, "-inf") + result = 4 + else: + writeToBuffer(buf, "inf") + result = 3 diff --git a/lib/system/gc.nim b/lib/system/gc.nim index 7db2b6567..7be9f4b1f 100644 --- a/lib/system/gc.nim +++ b/lib/system/gc.nim @@ -12,53 +12,6 @@ # Refcounting + Mark&Sweep. Complex algorithms avoided. # Been there, done that, didn't work. -#[ - -A *cell* is anything that is traced by the GC -(sequences, refs, strings, closures). - -The basic algorithm is *Deferrent Reference Counting* with cycle detection. -References on the stack are not counted for better performance and easier C -code generation. - -Each cell has a header consisting of a RC and a pointer to its type -descriptor. However the program does not know about these, so they are placed at -negative offsets. In the GC code the type `PCell` denotes a pointer -decremented by the right offset, so that the header can be accessed easily. It -is extremely important that `pointer` is not confused with a `PCell`. - -In Nim the compiler cannot always know if a reference -is stored on the stack or not. This is caused by var parameters. -Consider this example: - -.. code-block:: Nim - proc setRef(r: var ref TNode) = - new(r) - - proc usage = - var - r: ref TNode - setRef(r) # here we should not update the reference counts, because - # r is on the stack - setRef(r.left) # here we should update the refcounts! - -We have to decide at runtime whether the reference is on the stack or not. -The generated code looks roughly like this: - -.. code-block:: C - void setref(TNode** ref) { - unsureAsgnRef(ref, newObj(TNode_TI, sizeof(TNode))) - } - void usage(void) { - setRef(&r) - setRef(&r->left) - } - -Note that for systems with a continuous stack (which most systems have) -the check whether the ref is on the stack is very cheap (only two -comparisons). -]# - {.push profiler:off.} const @@ -94,7 +47,7 @@ type waZctDecRef, waPush #, waDebug - Finalizer {.compilerproc.} = proc (self: pointer) {.nimcall, benign, raises: [].} + Finalizer {.compilerproc.} = proc (self: pointer) {.nimcall, benign.} # A ref type can have a finalizer that is called before the object's # storage is freed. @@ -161,7 +114,7 @@ template gcAssert(cond: bool, msg: string) = writeStackTrace() #var x: ptr int #echo x[] - rawQuit 1 + quit 1 proc addZCT(s: var CellSeq, c: PCell) {.noinline.} = if (c.refcount and ZctFlag) == 0: @@ -170,11 +123,11 @@ proc addZCT(s: var CellSeq, c: PCell) {.noinline.} = proc cellToUsr(cell: PCell): pointer {.inline.} = # convert object (=pointer to refcount) to pointer to userdata - result = cast[pointer](cast[int](cell)+%ByteAddress(sizeof(Cell))) + result = cast[pointer](cast[ByteAddress](cell)+%ByteAddress(sizeof(Cell))) proc usrToCell(usr: pointer): PCell {.inline.} = # convert pointer to userdata to object (=pointer to refcount) - result = cast[PCell](cast[int](usr)-%ByteAddress(sizeof(Cell))) + result = cast[PCell](cast[ByteAddress](usr)-%ByteAddress(sizeof(Cell))) proc extGetCellType(c: pointer): PNimType {.compilerproc.} = # used for code generation concerning debugging @@ -219,11 +172,11 @@ template gcTrace(cell, state: untyped) = when traceGC: traceCell(cell, state) # forward declarations: -proc collectCT(gch: var GcHeap) {.benign, raises: [].} -proc isOnStack(p: pointer): bool {.noinline, benign, raises: [].} -proc forAllChildren(cell: PCell, op: WalkOp) {.benign, raises: [].} -proc doOperation(p: pointer, op: WalkOp) {.benign, raises: [].} -proc forAllChildrenAux(dest: pointer, mt: PNimType, op: WalkOp) {.benign, raises: [].} +proc collectCT(gch: var GcHeap) {.benign.} +proc isOnStack(p: pointer): bool {.noinline, benign.} +proc forAllChildren(cell: PCell, op: WalkOp) {.benign.} +proc doOperation(p: pointer, op: WalkOp) {.benign.} +proc forAllChildrenAux(dest: pointer, mt: PNimType, op: WalkOp) {.benign.} # we need the prototype here for debugging purposes proc incRef(c: PCell) {.inline.} = @@ -336,7 +289,7 @@ proc cellsetReset(s: var CellSet) = {.push stacktrace:off.} proc forAllSlotsAux(dest: pointer, n: ptr TNimNode, op: WalkOp) {.benign.} = - var d = cast[int](dest) + var d = cast[ByteAddress](dest) case n.kind of nkSlot: forAllChildrenAux(cast[pointer](d +% n.offset), n.typ, op) of nkList: @@ -356,7 +309,7 @@ proc forAllSlotsAux(dest: pointer, n: ptr TNimNode, op: WalkOp) {.benign.} = of nkNone: sysAssert(false, "forAllSlotsAux") proc forAllChildrenAux(dest: pointer, mt: PNimType, op: WalkOp) = - var d = cast[int](dest) + var d = cast[ByteAddress](dest) if dest == nil: return # nothing to do if ntfNoRefs notin mt.flags: case mt.kind @@ -382,11 +335,12 @@ proc forAllChildren(cell: PCell, op: WalkOp) = of tyRef: # common case forAllChildrenAux(cellToUsr(cell), cell.typ.base, op) of tySequence: - var d = cast[int](cellToUsr(cell)) + var d = cast[ByteAddress](cellToUsr(cell)) var s = cast[PGenericSeq](d) if s != nil: for i in 0..s.len-1: - forAllChildrenAux(cast[pointer](d +% align(GenericSeqSize, cell.typ.base.align) +% i *% cell.typ.base.size), cell.typ.base, op) + forAllChildrenAux(cast[pointer](d +% i *% cell.typ.base.size +% + GenericSeqSize), cell.typ.base, op) else: discard proc addNewObjToZCT(res: PCell, gch: var GcHeap) {.inline.} = @@ -457,7 +411,7 @@ proc rawNewObj(typ: PNimType, size: int, gch: var GcHeap): pointer = collectCT(gch) var res = cast[PCell](rawAlloc(gch.region, size + sizeof(Cell))) #gcAssert typ.kind in {tyString, tySequence} or size >= typ.base.size, "size too small" - gcAssert((cast[int](res) and (MemAlign-1)) == 0, "newObj: 2") + gcAssert((cast[ByteAddress](res) and (MemAlign-1)) == 0, "newObj: 2") # now it is buffered in the ZCT res.typ = typ setFrameInfo(res) @@ -482,22 +436,20 @@ proc newObjNoInit(typ: PNimType, size: int): pointer {.compilerRtl.} = result = rawNewObj(typ, size, gch) when defined(memProfiler): nimProfile(size) -proc newObj(typ: PNimType, size: int): pointer {.compilerRtl, noinline.} = +proc newObj(typ: PNimType, size: int): pointer {.compilerRtl.} = result = rawNewObj(typ, size, gch) zeroMem(result, size) when defined(memProfiler): nimProfile(size) -{.push overflowChecks: on.} proc newSeq(typ: PNimType, len: int): pointer {.compilerRtl.} = # `newObj` already uses locks, so no need for them here. - let size = align(GenericSeqSize, typ.base.align) + len * typ.base.size + let size = addInt(mulInt(len, typ.base.size), GenericSeqSize) result = newObj(typ, size) cast[PGenericSeq](result).len = len cast[PGenericSeq](result).reserved = len when defined(memProfiler): nimProfile(size) -{.pop.} -proc newObjRC1(typ: PNimType, size: int): pointer {.compilerRtl, noinline.} = +proc newObjRC1(typ: PNimType, size: int): pointer {.compilerRtl.} = # generates a new object and sets its reference counter to 1 incTypeSize typ, size sysAssert(allocInv(gch.region), "newObjRC1 begin") @@ -507,7 +459,7 @@ proc newObjRC1(typ: PNimType, size: int): pointer {.compilerRtl, noinline.} = var res = cast[PCell](rawAlloc(gch.region, size + sizeof(Cell))) sysAssert(allocInv(gch.region), "newObjRC1 after rawAlloc") - sysAssert((cast[int](res) and (MemAlign-1)) == 0, "newObj: 2") + sysAssert((cast[ByteAddress](res) and (MemAlign-1)) == 0, "newObj: 2") # now it is buffered in the ZCT res.typ = typ setFrameInfo(res) @@ -524,14 +476,12 @@ proc newObjRC1(typ: PNimType, size: int): pointer {.compilerRtl, noinline.} = sysAssert(allocInv(gch.region), "newObjRC1 end") when defined(memProfiler): nimProfile(size) -{.push overflowChecks: on.} proc newSeqRC1(typ: PNimType, len: int): pointer {.compilerRtl.} = - let size = align(GenericSeqSize, typ.base.align) + len * typ.base.size + let size = addInt(mulInt(len, typ.base.size), GenericSeqSize) result = newObjRC1(typ, size) cast[PGenericSeq](result).len = len cast[PGenericSeq](result).reserved = len when defined(memProfiler): nimProfile(size) -{.pop.} proc growObj(old: pointer, newsize: int, gch: var GcHeap): pointer = collectCT(gch) @@ -541,17 +491,15 @@ proc growObj(old: pointer, newsize: int, gch: var GcHeap): pointer = sysAssert(allocInv(gch.region), "growObj begin") var res = cast[PCell](rawAlloc(gch.region, newsize + sizeof(Cell))) - var elemSize,elemAlign = 1 - if ol.typ.kind != tyString: - elemSize = ol.typ.base.size - elemAlign = ol.typ.base.align + var elemSize = 1 + if ol.typ.kind != tyString: elemSize = ol.typ.base.size incTypeSize ol.typ, newsize - var oldsize = align(GenericSeqSize, elemAlign) + cast[PGenericSeq](old).len * elemSize + var oldsize = cast[PGenericSeq](old).len*elemSize + GenericSeqSize copyMem(res, ol, oldsize + sizeof(Cell)) - zeroMem(cast[pointer](cast[int](res) +% oldsize +% sizeof(Cell)), + zeroMem(cast[pointer](cast[ByteAddress](res) +% oldsize +% sizeof(Cell)), newsize-oldsize) - sysAssert((cast[int](res) and (MemAlign-1)) == 0, "growObj: 3") + sysAssert((cast[ByteAddress](res) and (MemAlign-1)) == 0, "growObj: 3") # This can be wrong for intermediate temps that are nevertheless on the # heap because of lambda lifting: #gcAssert(res.refcount shr rcShift <=% 1, "growObj: 4") @@ -561,8 +509,35 @@ proc growObj(old: pointer, newsize: int, gch: var GcHeap): pointer = gcTrace(res, csAllocated) track("growObj old", ol, 0) track("growObj new", res, newsize) - # since we steal the old seq's contents, we set the old length to 0. - cast[PGenericSeq](old).len = 0 + when defined(nimIncrSeqV3): + # since we steal the old seq's contents, we set the old length to 0. + cast[PGenericSeq](old).len = 0 + elif reallyDealloc: + sysAssert(allocInv(gch.region), "growObj before dealloc") + if ol.refcount shr rcShift <=% 1: + # free immediately to save space: + if (ol.refcount and ZctFlag) != 0: + var j = gch.zct.len-1 + var d = gch.zct.d + while j >= 0: + if d[j] == ol: + d[j] = res + break + dec(j) + beforeDealloc(gch, ol, "growObj stack trash") + decTypeSize(ol, ol.typ) + rawDealloc(gch.region, ol) + else: + # we split the old refcount in 2 parts. XXX This is still not entirely + # correct if the pointer that receives growObj's result is on the stack. + # A better fix would be to emit the location specific write barrier for + # 'growObj', but this is lots of more work and who knows what new problems + # this would create. + res.refcount = rcIncrement + decRef(ol) + else: + sysAssert(ol.typ != nil, "growObj: 5") + zeroMem(ol, sizeof(Cell)) when useCellIds: inc gch.idGenerator res.id = gch.idGenerator * 1000_000 + gch.gcThreadId @@ -609,7 +584,7 @@ proc markS(gch: var GcHeap, c: PCell) = if not containsOrIncl(gch.marked, d): forAllChildren(d, waMarkPrecise) -proc markGlobals(gch: var GcHeap) {.raises: [].} = +proc markGlobals(gch: var GcHeap) = if gch.gcThreadId == 0: for i in 0 .. globalMarkersLen-1: globalMarkers[i]() for i in 0 .. threadLocalMarkersLen-1: threadLocalMarkers[i]() @@ -626,7 +601,7 @@ when logGC: if cycleCheckA[i] == c: return true if cycleCheckALen == len(cycleCheckA): gcAssert(false, "cycle detection overflow") - rawQuit 1 + quit 1 cycleCheckA[cycleCheckALen] = c inc cycleCheckALen @@ -664,9 +639,9 @@ proc doOperation(p: pointer, op: WalkOp) = proc nimGCvisit(d: pointer, op: int) {.compilerRtl.} = doOperation(d, WalkOp(op)) -proc collectZCT(gch: var GcHeap): bool {.benign, raises: [].} +proc collectZCT(gch: var GcHeap): bool {.benign.} -proc collectCycles(gch: var GcHeap) {.raises: [].} = +proc collectCycles(gch: var GcHeap) = when hasThreadSupport: for c in gch.toDispose: nimGCunref(c) @@ -683,16 +658,16 @@ proc collectCycles(gch: var GcHeap) {.raises: [].} = proc gcMark(gch: var GcHeap, p: pointer) {.inline.} = # the addresses are not as cells on the stack, so turn them to cells: sysAssert(allocInv(gch.region), "gcMark begin") - var c = cast[int](p) + var cell = usrToCell(p) + var c = cast[ByteAddress](cell) if c >% PageSize: # fast check: does it look like a cell? - var objStart = cast[PCell](interiorAllocatedPtr(gch.region, p)) + var objStart = cast[PCell](interiorAllocatedPtr(gch.region, cell)) if objStart != nil: # mark the cell: incRef(objStart) add(gch.decStack, objStart) when false: - let cell = usrToCell(p) if isAllocatedPtr(gch.region, cell): sysAssert false, "allocated pointer but not interior?" # mark the cell: @@ -773,7 +748,7 @@ proc unmarkStackAndRegisters(gch: var GcHeap) = decRef(d[i]) gch.decStack.len = 0 -proc collectCTBody(gch: var GcHeap) {.raises: [].} = +proc collectCTBody(gch: var GcHeap) = when withRealTime: let t0 = getticks() sysAssert(allocInv(gch.region), "collectCT: begin") @@ -848,10 +823,10 @@ when withRealTime: stack.bottomSaved = stack.bottom when stackIncreases: stack.bottom = cast[pointer]( - cast[int](stack.pos) - sizeof(pointer) * 6 - stackSize) + cast[ByteAddress](stack.pos) - sizeof(pointer) * 6 - stackSize) else: stack.bottom = cast[pointer]( - cast[int](stack.pos) + sizeof(pointer) * 6 + stackSize) + cast[ByteAddress](stack.pos) + sizeof(pointer) * 6 + stackSize) GC_step(gch, us, strongAdvice) @@ -863,10 +838,9 @@ when not defined(useNimRtl): proc GC_disable() = inc(gch.recGcLock) proc GC_enable() = - when defined(nimDoesntTrackDefects): - if gch.recGcLock <= 0: - raise newException(AssertionDefect, - "API usage error: GC_enable called but GC is already enabled") + if gch.recGcLock <= 0: + raise newException(AssertionError, + "API usage error: GC_enable called but GC is already enabled") dec(gch.recGcLock) proc GC_setStrategy(strategy: GC_Strategy) = @@ -876,7 +850,7 @@ when not defined(useNimRtl): gch.cycleThreshold = InitialCycleThreshold proc GC_disableMarkAndSweep() = - gch.cycleThreshold = high(typeof(gch.cycleThreshold))-1 + gch.cycleThreshold = high(gch.cycleThreshold)-1 # set to the max value to suppress the cycle detector proc GC_fullCollect() = diff --git a/lib/system/gc2.nim b/lib/system/gc2.nim index ed046b5fd..4da9b4f94 100644 --- a/lib/system/gc2.nim +++ b/lib/system/gc2.nim @@ -7,9 +7,6 @@ # distribution, for details about the copyright. # -# xxx deadcode, consider removing unless something could be reused. - - # Garbage Collector # # The basic algorithm is an incremental mark @@ -129,15 +126,15 @@ template gcAssert(cond: bool, msg: string) = echo "[GCASSERT] ", msg GC_disable() writeStackTrace() - rawQuit 1 + quit 1 proc cellToUsr(cell: PCell): pointer {.inline.} = # convert object (=pointer to refcount) to pointer to userdata - result = cast[pointer](cast[int](cell)+%ByteAddress(sizeof(Cell))) + result = cast[pointer](cast[ByteAddress](cell)+%ByteAddress(sizeof(Cell))) proc usrToCell(usr: pointer): PCell {.inline.} = # convert pointer to userdata to object (=pointer to refcount) - result = cast[PCell](cast[int](usr)-%ByteAddress(sizeof(Cell))) + result = cast[PCell](cast[ByteAddress](usr)-%ByteAddress(sizeof(Cell))) proc extGetCellType(c: pointer): PNimType {.compilerproc.} = # used for code generation concerning debugging @@ -252,7 +249,7 @@ proc unsureAsgnRef(dest: PPointer, src: pointer) {.compilerproc.} = dest[] = src proc forAllSlotsAux(dest: pointer, n: ptr TNimNode, op: WalkOp) {.benign.} = - var d = cast[int](dest) + var d = cast[ByteAddress](dest) case n.kind of nkSlot: forAllChildrenAux(cast[pointer](d +% n.offset), n.typ, op) of nkList: @@ -264,7 +261,7 @@ proc forAllSlotsAux(dest: pointer, n: ptr TNimNode, op: WalkOp) {.benign.} = of nkNone: sysAssert(false, "forAllSlotsAux") proc forAllChildrenAux(dest: pointer, mt: PNimType, op: WalkOp) = - var d = cast[int](dest) + var d = cast[ByteAddress](dest) if dest == nil: return # nothing to do if ntfNoRefs notin mt.flags: case mt.kind @@ -290,11 +287,12 @@ proc forAllChildren(cell: PCell, op: WalkOp) = of tyRef: # common case forAllChildrenAux(cellToUsr(cell), cell.typ.base, op) of tySequence: - var d = cast[int](cellToUsr(cell)) + var d = cast[ByteAddress](cellToUsr(cell)) var s = cast[PGenericSeq](d) if s != nil: for i in 0..s.len-1: - forAllChildrenAux(cast[pointer](d +% align(GenericSeqSize, cell.typ.base.align) +% i *% cell.typ.base.size), cell.typ.base, op) + forAllChildrenAux(cast[pointer](d +% i *% cell.typ.base.size +% + GenericSeqSize), cell.typ.base, op) else: discard {.push stackTrace: off, profiler:off.} @@ -330,7 +328,7 @@ proc rawNewObj(typ: PNimType, size: int, gch: var GcHeap): pointer = gcAssert(typ.kind in {tyRef, tyString, tySequence}, "newObj: 1") collectCT(gch) var res = cast[PCell](rawAlloc(gch.region, size + sizeof(Cell))) - gcAssert((cast[int](res) and (MemAlign-1)) == 0, "newObj: 2") + gcAssert((cast[ByteAddress](res) and (MemAlign-1)) == 0, "newObj: 2") # now it is buffered in the ZCT res.typ = typ when leakDetector and not hasThreadSupport: @@ -361,7 +359,7 @@ proc newObj(typ: PNimType, size: int): pointer {.compilerRtl.} = proc newSeq(typ: PNimType, len: int): pointer {.compilerRtl.} = # `newObj` already uses locks, so no need for them here. - let size = addInt(align(GenericSeqSize, typ.base.align), mulInt(len, typ.base.size)) + let size = addInt(mulInt(len, typ.base.size), GenericSeqSize) result = newObj(typ, size) cast[PGenericSeq](result).len = len cast[PGenericSeq](result).reserved = len @@ -380,17 +378,15 @@ proc growObj(old: pointer, newsize: int, gch: var GcHeap): pointer = gcAssert(ol.typ.kind in {tyString, tySequence}, "growObj: 2") var res = cast[PCell](rawAlloc(gch.region, newsize + sizeof(Cell))) - var elemSize, elemAlign = 1 - if ol.typ.kind != tyString: - elemSize = ol.typ.base.size - elemAlign = ol.typ.base.align + var elemSize = 1 + if ol.typ.kind != tyString: elemSize = ol.typ.base.size incTypeSize ol.typ, newsize - var oldsize = align(GenericSeqSize, elemAlign) + cast[PGenericSeq](old).len*elemSize + var oldsize = cast[PGenericSeq](old).len*elemSize + GenericSeqSize copyMem(res, ol, oldsize + sizeof(Cell)) - zeroMem(cast[pointer](cast[int](res)+% oldsize +% sizeof(Cell)), + zeroMem(cast[pointer](cast[ByteAddress](res)+% oldsize +% sizeof(Cell)), newsize-oldsize) - sysAssert((cast[int](res) and (MemAlign-1)) == 0, "growObj: 3") + sysAssert((cast[ByteAddress](res) and (MemAlign-1)) == 0, "growObj: 3") when false: # this is wrong since seqs can be shared via 'shallow': when reallyDealloc: rawDealloc(gch.region, ol) @@ -593,7 +589,7 @@ proc gcMark(gch: var GcHeap, p: pointer) {.inline.} = # the addresses are not as cells on the stack, so turn them to cells: sysAssert(allocInv(gch.region), "gcMark begin") var cell = usrToCell(p) - var c = cast[int](cell) + var c = cast[ByteAddress](cell) if c >% PageSize: # fast check: does it look like a cell? var objStart = cast[PCell](interiorAllocatedPtr(gch.region, cell)) @@ -697,10 +693,10 @@ when withRealTime: stack.bottomSaved = stack.bottom when stackIncreases: stack.bottom = cast[pointer]( - cast[int](stack.pos) - sizeof(pointer) * 6 - stackSize) + cast[ByteAddress](stack.pos) - sizeof(pointer) * 6 - stackSize) else: stack.bottom = cast[pointer]( - cast[int](stack.pos) + sizeof(pointer) * 6 + stackSize) + cast[ByteAddress](stack.pos) + sizeof(pointer) * 6 + stackSize) GC_step(gch, us, strongAdvice) diff --git a/lib/system/gc_common.nim b/lib/system/gc_common.nim index 54c51e783..fe07766d9 100644 --- a/lib/system/gc_common.nim +++ b/lib/system/gc_common.nim @@ -78,11 +78,8 @@ template decTypeSize(cell, t) = when defined(nimTypeNames): if t.kind in {tyString, tySequence}: let cap = cast[PGenericSeq](cellToUsr(cell)).space - let size = - if t.kind == tyString: - cap + 1 + GenericSeqSize - else: - align(GenericSeqSize, t.base.align) + cap * t.base.size + let size = if t.kind == tyString: cap+1+GenericSeqSize + else: addInt(mulInt(cap, t.base.size), GenericSeqSize) atomicDec t.sizes, size+sizeof(Cell) else: atomicDec t.sizes, t.base.size+sizeof(Cell) @@ -166,16 +163,16 @@ when defined(nimdoc): ## this thread will only be initialized once per thread, no matter how often ## it is called. ## - ## This function is available only when `--threads:on` and `--tlsEmulation:off` + ## This function is available only when ``--threads:on`` and ``--tlsEmulation:off`` ## switches are used discard proc tearDownForeignThreadGc*() {.gcsafe.} = - ## Call this to tear down the GC, previously initialized by `setupForeignThreadGc`. + ## Call this to tear down the GC, previously initialized by ``setupForeignThreadGc``. ## If GC has not been previously initialized, or has already been torn down, the ## call does nothing. ## - ## This function is available only when `--threads:on` and `--tlsEmulation:off` + ## This function is available only when ``--threads:on`` and ``--tlsEmulation:off`` ## switches are used discard elif declared(threadType): @@ -217,19 +214,18 @@ proc stackSize(stack: ptr GcStack): int {.noinline.} = when nimCoroutines: var pos = stack.pos else: - var pos {.volatile, noinit.}: pointer + var pos {.volatile.}: pointer pos = addr(pos) if pos != nil: when stackIncreases: - result = cast[int](pos) -% cast[int](stack.bottom) + result = cast[ByteAddress](pos) -% cast[ByteAddress](stack.bottom) else: - result = cast[int](stack.bottom) -% cast[int](pos) + result = cast[ByteAddress](stack.bottom) -% cast[ByteAddress](pos) else: result = 0 proc stackSize(): int {.noinline.} = - result = 0 for stack in gch.stack.items(): result = result + stack.stackSize() @@ -273,9 +269,6 @@ when nimCoroutines: gch.activeStack = gch.stack.find(bottom) gch.activeStack.setPosition(addr(sp)) - proc GC_getActiveStack() : pointer {.cdecl, exportc.} = - return gch.activeStack.bottom - when not defined(useNimRtl): proc nimGC_setStackBottom(theStackBottom: pointer) = # Initializes main stack of the thread. @@ -295,28 +288,25 @@ when not defined(useNimRtl): # the first init must be the one that defines the stack bottom: gch.stack.bottom = theStackBottom elif theStackBottom != gch.stack.bottom: - var a = cast[int](theStackBottom) # and not PageMask - PageSize*2 - var b = cast[int](gch.stack.bottom) + var a = cast[ByteAddress](theStackBottom) # and not PageMask - PageSize*2 + var b = cast[ByteAddress](gch.stack.bottom) #c_fprintf(stdout, "old: %p new: %p;\n",gch.stack.bottom,theStackBottom) when stackIncreases: gch.stack.bottom = cast[pointer](min(a, b)) else: gch.stack.bottom = cast[pointer](max(a, b)) - when nimCoroutines: - if theStackBottom != nil: gch.stack.bottom = theStackBottom - gch.stack.setPosition(theStackBottom) {.pop.} proc isOnStack(p: pointer): bool = - var stackTop {.volatile, noinit.}: pointer + var stackTop {.volatile.}: pointer stackTop = addr(stackTop) - var a = cast[int](gch.getActiveStack().bottom) - var b = cast[int](stackTop) + var a = cast[ByteAddress](gch.getActiveStack().bottom) + var b = cast[ByteAddress](stackTop) when not stackIncreases: swap(a, b) - var x = cast[int](p) + var x = cast[ByteAddress](p) result = a <=% x and x <=% b when defined(sparc): # For SPARC architecture. @@ -337,7 +327,7 @@ when defined(sparc): # For SPARC architecture. # Addresses decrease as the stack grows. while sp <= max: gcMark(gch, sp[]) - sp = cast[PPointer](cast[int](sp) +% sizeof(pointer)) + sp = cast[PPointer](cast[ByteAddress](sp) +% sizeof(pointer)) elif defined(ELATE): {.error: "stack marking code is to be written for this architecture".} @@ -354,8 +344,8 @@ elif stackIncreases: template forEachStackSlotAux(gch, gcMark: untyped) {.dirty.} = for stack in gch.stack.items(): - var max = cast[int](gch.stack.bottom) - var sp = cast[int](addr(registers)) -% sizeof(pointer) + var max = cast[ByteAddress](gch.stack.bottom) + var sp = cast[ByteAddress](addr(registers)) -% sizeof(pointer) while sp >=% max: gcMark(gch, cast[PPointer](sp)[]) sp = sp -% sizeof(pointer) @@ -383,8 +373,8 @@ else: gch.getActiveStack().setPosition(addr(registers)) if c_setjmp(registers) == 0'i32: # To fill the C stack with registers. for stack in gch.stack.items(): - var max = cast[int](stack.bottom) - var sp = cast[int](addr(registers)) + var max = cast[ByteAddress](stack.bottom) + var sp = cast[ByteAddress](addr(registers)) when defined(amd64): if stack.isActiveStack(): # words within the jmp_buf structure may not be properly aligned. @@ -415,7 +405,7 @@ else: # end of non-portable code # ---------------------------------------------------------------------------- -proc prepareDealloc(cell: PCell) {.raises: [].} = +proc prepareDealloc(cell: PCell) = when declared(useMarkForDebug): when useMarkForDebug: gcAssert(cell notin gch.marked, "Cell still alive!") @@ -432,10 +422,10 @@ proc prepareDealloc(cell: PCell) {.raises: [].} = decTypeSize(cell, t) proc deallocHeap*(runFinalizers = true; allowGcAfterwards = true) = - ## Frees the thread local heap. Runs every finalizer if `runFinalizers` - ## is true. If `allowGcAfterwards` is true, a minimal amount of allocation + ## Frees the thread local heap. Runs every finalizer if ``runFinalizers`` + ## is true. If ``allowGcAfterwards`` is true, a minimal amount of allocation ## happens to ensure the GC can continue to work after the call - ## to `deallocHeap`. + ## to ``deallocHeap``. template deallocCell(x) = if isCell(x): # cast to PCell is correct here: @@ -458,7 +448,7 @@ proc deallocHeap*(runFinalizers = true; allowGcAfterwards = true) = initGC() type - GlobalMarkerProc = proc () {.nimcall, benign, raises: [].} + GlobalMarkerProc = proc () {.nimcall, benign.} var globalMarkersLen {.exportc.}: int globalMarkers {.exportc.}: array[0..3499, GlobalMarkerProc] @@ -472,7 +462,7 @@ proc nimRegisterGlobalMarker(markerProc: GlobalMarkerProc) {.compilerproc.} = inc globalMarkersLen else: cstderr.rawWrite("[GC] cannot register global variable; too many global variables") - rawQuit 1 + quit 1 proc nimRegisterThreadLocalMarker(markerProc: GlobalMarkerProc) {.compilerproc.} = if threadLocalMarkersLen <= high(threadLocalMarkers): @@ -480,4 +470,4 @@ proc nimRegisterThreadLocalMarker(markerProc: GlobalMarkerProc) {.compilerproc.} inc threadLocalMarkersLen else: cstderr.rawWrite("[GC] cannot register thread local variable; too many thread local variables") - rawQuit 1 + quit 1 diff --git a/lib/system/gc_hooks.nim b/lib/system/gc_hooks.nim index ace62eea0..70f02e657 100644 --- a/lib/system/gc_hooks.nim +++ b/lib/system/gc_hooks.nim @@ -24,7 +24,7 @@ proc nimRegisterGlobalMarker(markerProc: GlobalMarkerProc) {.compilerproc.} = inc globalMarkersLen else: cstderr.rawWrite("[GC] cannot register global variable; too many global variables") - rawQuit 1 + quit 1 proc nimRegisterThreadLocalMarker(markerProc: GlobalMarkerProc) {.compilerproc.} = if threadLocalMarkersLen <= high(threadLocalMarkers): @@ -32,7 +32,7 @@ proc nimRegisterThreadLocalMarker(markerProc: GlobalMarkerProc) {.compilerproc.} inc threadLocalMarkersLen else: cstderr.rawWrite("[GC] cannot register thread local variable; too many thread local variables") - rawQuit 1 + quit 1 proc traverseGlobals*() = for i in 0..globalMarkersLen-1: diff --git a/lib/system/gc_interface.nim b/lib/system/gc_interface.nim index 84145f33a..9183e6d48 100644 --- a/lib/system/gc_interface.nim +++ b/lib/system/gc_interface.nim @@ -14,7 +14,7 @@ when hasAlloc: gcOptimizeSpace ## optimize for memory footprint when hasAlloc and not defined(js) and not usesDestructors: - proc GC_disable*() {.rtl, inl, benign, raises: [].} + proc GC_disable*() {.rtl, inl, benign.} ## Disables the GC. If called `n` times, `n` calls to `GC_enable` ## are needed to reactivate the GC. ## @@ -22,7 +22,7 @@ when hasAlloc and not defined(js) and not usesDestructors: ## the mark and sweep phase with ## `GC_disableMarkAndSweep <#GC_disableMarkAndSweep>`_. - proc GC_enable*() {.rtl, inl, benign, raises: [].} + proc GC_enable*() {.rtl, inl, benign.} ## Enables the GC again. proc GC_fullCollect*() {.rtl, benign.} @@ -54,7 +54,7 @@ when hasAlloc and not defined(js) and not usesDestructors: proc GC_unref*(x: string) {.magic: "GCunref", benign.} ## See the documentation of `GC_ref <#GC_ref,string>`_. - proc nimGC_setStackBottom*(theStackBottom: pointer) {.compilerRtl, noinline, benign, raises: [].} + proc nimGC_setStackBottom*(theStackBottom: pointer) {.compilerRtl, noinline, benign.} ## Expands operating GC stack range to `theStackBottom`. Does nothing ## if current stack bottom is already lower than `theStackBottom`. diff --git a/lib/system/gc_ms.nim b/lib/system/gc_ms.nim index 72d22f08b..271543445 100644 --- a/lib/system/gc_ms.nim +++ b/lib/system/gc_ms.nim @@ -36,7 +36,7 @@ type # local waMarkPrecise # fast precise marking - Finalizer {.compilerproc.} = proc (self: pointer) {.nimcall, benign, raises: [].} + Finalizer {.compilerproc.} = proc (self: pointer) {.nimcall, benign.} # A ref type can have a finalizer that is called before the object's # storage is freed. @@ -90,21 +90,21 @@ template gcAssert(cond: bool, msg: string) = if not cond: cstderr.rawWrite "[GCASSERT] " cstderr.rawWrite msg - rawQuit 1 + quit 1 proc cellToUsr(cell: PCell): pointer {.inline.} = # convert object (=pointer to refcount) to pointer to userdata - result = cast[pointer](cast[int](cell)+%ByteAddress(sizeof(Cell))) + result = cast[pointer](cast[ByteAddress](cell)+%ByteAddress(sizeof(Cell))) proc usrToCell(usr: pointer): PCell {.inline.} = # convert pointer to userdata to object (=pointer to refcount) - result = cast[PCell](cast[int](usr)-%ByteAddress(sizeof(Cell))) + result = cast[PCell](cast[ByteAddress](usr)-%ByteAddress(sizeof(Cell))) proc extGetCellType(c: pointer): PNimType {.compilerproc.} = # used for code generation concerning debugging result = usrToCell(c).typ -proc unsureAsgnRef(dest: PPointer, src: pointer) {.inline, compilerproc.} = +proc unsureAsgnRef(dest: PPointer, src: pointer) {.inline.} = dest[] = src proc internRefcount(p: pointer): int {.exportc: "getRefcount".} = @@ -115,10 +115,10 @@ when BitsPerPage mod (sizeof(int)*8) != 0: {.error: "(BitsPerPage mod BitsPerUnit) should be zero!".} # forward declarations: -proc collectCT(gch: var GcHeap; size: int) {.benign, raises: [].} -proc forAllChildren(cell: PCell, op: WalkOp) {.benign, raises: [].} -proc doOperation(p: pointer, op: WalkOp) {.benign, raises: [].} -proc forAllChildrenAux(dest: pointer, mt: PNimType, op: WalkOp) {.benign, raises: [].} +proc collectCT(gch: var GcHeap; size: int) {.benign.} +proc forAllChildren(cell: PCell, op: WalkOp) {.benign.} +proc doOperation(p: pointer, op: WalkOp) {.benign.} +proc forAllChildrenAux(dest: pointer, mt: PNimType, op: WalkOp) {.benign.} # we need the prototype here for debugging purposes when defined(nimGcRefLeak): @@ -217,7 +217,7 @@ proc initGC() = gcAssert(gch.gcThreadId >= 0, "invalid computed thread ID") proc forAllSlotsAux(dest: pointer, n: ptr TNimNode, op: WalkOp) {.benign.} = - var d = cast[int](dest) + var d = cast[ByteAddress](dest) case n.kind of nkSlot: forAllChildrenAux(cast[pointer](d +% n.offset), n.typ, op) of nkList: @@ -229,7 +229,7 @@ proc forAllSlotsAux(dest: pointer, n: ptr TNimNode, op: WalkOp) {.benign.} = of nkNone: sysAssert(false, "forAllSlotsAux") proc forAllChildrenAux(dest: pointer, mt: PNimType, op: WalkOp) = - var d = cast[int](dest) + var d = cast[ByteAddress](dest) if dest == nil: return # nothing to do if ntfNoRefs notin mt.flags: case mt.kind @@ -255,11 +255,12 @@ proc forAllChildren(cell: PCell, op: WalkOp) = forAllChildrenAux(cellToUsr(cell), cell.typ.base, op) of tySequence: when not defined(nimSeqsV2): - var d = cast[int](cellToUsr(cell)) + var d = cast[ByteAddress](cellToUsr(cell)) var s = cast[PGenericSeq](d) if s != nil: for i in 0..s.len-1: - forAllChildrenAux(cast[pointer](d +% align(GenericSeqSize, cell.typ.base.align) +% i *% cell.typ.base.size), cell.typ.base, op) + forAllChildrenAux(cast[pointer](d +% i *% cell.typ.base.size +% + GenericSeqSize), cell.typ.base, op) else: discard proc rawNewObj(typ: PNimType, size: int, gch: var GcHeap): pointer = @@ -268,7 +269,7 @@ proc rawNewObj(typ: PNimType, size: int, gch: var GcHeap): pointer = gcAssert(typ.kind in {tyRef, tyString, tySequence}, "newObj: 1") collectCT(gch, size + sizeof(Cell)) var res = cast[PCell](rawAlloc(gch.region, size + sizeof(Cell))) - gcAssert((cast[int](res) and (MemAlign-1)) == 0, "newObj: 2") + gcAssert((cast[ByteAddress](res) and (MemAlign-1)) == 0, "newObj: 2") # now it is buffered in the ZCT res.typ = typ when leakDetector and not hasThreadSupport: @@ -304,22 +305,20 @@ proc newObjRC1(typ: PNimType, size: int): pointer {.compilerRtl.} = when defined(memProfiler): nimProfile(size) when not defined(nimSeqsV2): - {.push overflowChecks: on.} proc newSeq(typ: PNimType, len: int): pointer {.compilerRtl.} = # `newObj` already uses locks, so no need for them here. - let size = align(GenericSeqSize, typ.base.align) + len * typ.base.size + let size = addInt(mulInt(len, typ.base.size), GenericSeqSize) result = newObj(typ, size) cast[PGenericSeq](result).len = len cast[PGenericSeq](result).reserved = len when defined(memProfiler): nimProfile(size) proc newSeqRC1(typ: PNimType, len: int): pointer {.compilerRtl.} = - let size = align(GenericSeqSize, typ.base.align) + len * typ.base.size + let size = addInt(mulInt(len, typ.base.size), GenericSeqSize) result = newObj(typ, size) cast[PGenericSeq](result).len = len cast[PGenericSeq](result).reserved = len when defined(memProfiler): nimProfile(size) - {.pop.} proc growObj(old: pointer, newsize: int, gch: var GcHeap): pointer = collectCT(gch, newsize + sizeof(Cell)) @@ -328,17 +327,15 @@ when not defined(nimSeqsV2): gcAssert(ol.typ.kind in {tyString, tySequence}, "growObj: 2") var res = cast[PCell](rawAlloc(gch.region, newsize + sizeof(Cell))) - var elemSize, elemAlign = 1 - if ol.typ.kind != tyString: - elemSize = ol.typ.base.size - elemAlign = ol.typ.base.align + var elemSize = 1 + if ol.typ.kind != tyString: elemSize = ol.typ.base.size incTypeSize ol.typ, newsize - var oldsize = align(GenericSeqSize, elemAlign) + cast[PGenericSeq](old).len*elemSize + var oldsize = cast[PGenericSeq](old).len*elemSize + GenericSeqSize copyMem(res, ol, oldsize + sizeof(Cell)) - zeroMem(cast[pointer](cast[int](res)+% oldsize +% sizeof(Cell)), + zeroMem(cast[pointer](cast[ByteAddress](res)+% oldsize +% sizeof(Cell)), newsize-oldsize) - sysAssert((cast[int](res) and (MemAlign-1)) == 0, "growObj: 3") + sysAssert((cast[ByteAddress](res) and (MemAlign-1)) == 0, "growObj: 3") when withBitvectors: incl(gch.allocated, res) when useCellIds: inc gch.idGenerator @@ -428,6 +425,15 @@ proc sweep(gch: var GcHeap) = if c.refcount == rcBlack: c.refcount = rcWhite else: freeCyclicCell(gch, c) +when false: + proc newGcInvariant*() = + for x in allObjects(gch.region): + if isCell(x): + var c = cast[PCell](x) + if c.typ == nil: + writeStackTrace() + quit 1 + proc markGlobals(gch: var GcHeap) = if gch.gcThreadId == 0: when defined(nimTracing): @@ -446,10 +452,11 @@ proc markGlobals(gch: var GcHeap) = proc gcMark(gch: var GcHeap, p: pointer) {.inline.} = # the addresses are not as cells on the stack, so turn them to cells: - var c = cast[int](p) + var cell = usrToCell(p) + var c = cast[ByteAddress](cell) if c >% PageSize: # fast check: does it look like a cell? - var objStart = cast[PCell](interiorAllocatedPtr(gch.region, p)) + var objStart = cast[PCell](interiorAllocatedPtr(gch.region, cell)) if objStart != nil: mark(gch, objStart) @@ -485,10 +492,9 @@ when not defined(useNimRtl): proc GC_disable() = inc(gch.recGcLock) proc GC_enable() = - when defined(nimDoesntTrackDefects): - if gch.recGcLock <= 0: - raise newException(AssertionDefect, - "API usage error: GC_enable called but GC is already enabled") + if gch.recGcLock <= 0: + raise newException(AssertionError, + "API usage error: GC_enable called but GC is already enabled") dec(gch.recGcLock) proc GC_setStrategy(strategy: GC_Strategy) = discard @@ -497,7 +503,7 @@ when not defined(useNimRtl): gch.cycleThreshold = InitialThreshold proc GC_disableMarkAndSweep() = - gch.cycleThreshold = high(typeof(gch.cycleThreshold))-1 + gch.cycleThreshold = high(gch.cycleThreshold)-1 # set to the max value to suppress the cycle detector when defined(nimTracing): diff --git a/lib/system/gc_regions.nim b/lib/system/gc_regions.nim index d96de7eac..6b1640ab1 100644 --- a/lib/system/gc_regions.nim +++ b/lib/system/gc_regions.nim @@ -7,12 +7,23 @@ # # "Stack GC" for embedded devices or ultra performance requirements. -import std/private/syslocks -when defined(memProfiler): - proc nimProfile(requestedSize: int) {.benign.} +when defined(nimphpext): + proc roundup(x, v: int): int {.inline.} = + result = (x + (v-1)) and not (v-1) + proc emalloc(size: int): pointer {.importc: "_emalloc".} + proc efree(mem: pointer) {.importc: "_efree".} -when defined(useMalloc): + proc osAllocPages(size: int): pointer {.inline.} = + emalloc(size) + + proc osTryAllocPages(size: int): pointer {.inline.} = + emalloc(size) + + proc osDeallocPages(p: pointer, size: int) {.inline.} = + efree(p) + +elif defined(useMalloc): proc roundup(x, v: int): int {.inline.} = result = (x + (v-1)) and not (v-1) proc emalloc(size: int): pointer {.importc: "malloc", header: "".} @@ -88,16 +99,16 @@ type region: ptr MemRegion var - tlRegion {.threadvar.}: MemRegion -# tempStrRegion {.threadvar.}: MemRegion # not yet used + tlRegion {.threadVar.}: MemRegion +# tempStrRegion {.threadVar.}: MemRegion # not yet used -template withRegion*(r: var MemRegion; body: untyped) = +template withRegion*(r: MemRegion; body: untyped) = let oldRegion = tlRegion tlRegion = r try: body finally: - r = tlRegion + #r = tlRegion tlRegion = oldRegion template inc(p: pointer, s: int) = @@ -266,13 +277,14 @@ when false: setObstackPtr(obs) template withScratchRegion*(body: untyped) = + var scratch: MemRegion let oldRegion = tlRegion - tlRegion = MemRegion() + tlRegion = scratch try: body finally: - deallocAll() tlRegion = oldRegion + deallocAll(scratch) when false: proc joinRegion*(dest: var MemRegion; src: MemRegion) = @@ -322,21 +334,20 @@ proc newObjNoInit(typ: PNimType, size: int): pointer {.compilerRtl.} = result = rawNewObj(tlRegion, typ, size) when defined(memProfiler): nimProfile(size) -{.push overflowChecks: on.} proc newSeq(typ: PNimType, len: int): pointer {.compilerRtl.} = - let size = roundup(align(GenericSeqSize, typ.base.align) + len * typ.base.size, MemAlign) + let size = roundup(addInt(mulInt(len, typ.base.size), GenericSeqSize), + MemAlign) result = rawNewSeq(tlRegion, typ, size) zeroMem(result, size) cast[PGenericSeq](result).len = len cast[PGenericSeq](result).reserved = len proc newStr(typ: PNimType, len: int; init: bool): pointer {.compilerRtl.} = - let size = roundup(len + GenericSeqSize, MemAlign) + let size = roundup(addInt(len, GenericSeqSize), MemAlign) result = rawNewSeq(tlRegion, typ, size) if init: zeroMem(result, size) cast[PGenericSeq](result).len = 0 cast[PGenericSeq](result).reserved = len -{.pop.} proc newObjRC1(typ: PNimType, size: int): pointer {.compilerRtl.} = result = rawNewObj(tlRegion, typ, size) @@ -351,8 +362,7 @@ proc growObj(regionUnused: var MemRegion; old: pointer, newsize: int): pointer = result = rawNewSeq(sh.region[], typ, roundup(newsize, MemAlign)) let elemSize = if typ.kind == tyString: 1 else: typ.base.size - let elemAlign = if typ.kind == tyString: 1 else: typ.base.align - let oldsize = align(GenericSeqSize, elemAlign) + cast[PGenericSeq](old).len*elemSize + let oldsize = cast[PGenericSeq](old).len*elemSize + GenericSeqSize zeroMem(result +! oldsize, newsize-oldsize) copyMem(result, old, oldsize) dealloc(sh.region[], old, roundup(oldsize, MemAlign)) @@ -438,5 +448,5 @@ proc getTotalMem*(r: MemRegion): int = proc nimGC_setStackBottom(theStackBottom: pointer) = discard -proc nimGCref(x: pointer) {.compilerproc.} = discard -proc nimGCunref(x: pointer) {.compilerproc.} = discard +proc nimGCref(x: pointer) {.compilerProc.} = discard +proc nimGCunref(x: pointer) {.compilerProc.} = discard diff --git a/lib/system/hti.nim b/lib/system/hti.nim index 9acaae88b..c20f132fb 100644 --- a/lib/system/hti.nim +++ b/lib/system/hti.nim @@ -40,7 +40,7 @@ type tyPointer, tyOpenArray, tyString, - tyCstring, + tyCString, tyForward, tyInt, tyInt8, @@ -69,7 +69,7 @@ type tyAnythingHidden, tyStaticHidden, tyFromExprHidden, - tyOptDeprecated, + tyOpt, tyVoidHidden TNimNodeKind = enum nkNone, nkSlot, nkList, nkCase @@ -90,7 +90,6 @@ type when defined(gcHooks): head*: pointer size*: int - align*: int kind: TNimKind flags: set[TNimTypeFlag] base*: ptr TNimType @@ -98,8 +97,6 @@ type finalizer*: pointer # the finalizer for the type marker*: proc (p: pointer, op: int) {.nimcall, benign, tags: [], raises: [].} # marker proc for GC deepcopy: proc (p: pointer): pointer {.nimcall, benign, tags: [], raises: [].} - when defined(nimSeqsV2): - typeInfoV2*: pointer when defined(nimTypeNames): name: cstring nextType: ptr TNimType diff --git a/lib/system/inclrtl.nim b/lib/system/inclrtl.nim index 3bf0b9893..adbda9fd6 100644 --- a/lib/system/inclrtl.nim +++ b/lib/system/inclrtl.nim @@ -30,13 +30,12 @@ when defined(createNimRtl): {.pragma: inl.} {.pragma: compilerRtl, compilerproc, exportc: "nimrtl_$1", dynlib.} elif defined(useNimRtl): - #[ - `{.rtl.}` should only be used for non-generic procs. - ]# - const nimrtl* = - when defined(windows): "nimrtl.dll" - elif defined(macosx): "libnimrtl.dylib" - else: "libnimrtl.so" + when defined(windows): + const nimrtl* = "nimrtl.dll" + elif defined(macosx): + const nimrtl* = "libnimrtl.dylib" + else: + const nimrtl* = "libnimrtl.so" {.pragma: rtl, importc: "nimrtl_$1", dynlib: nimrtl, gcsafe.} {.pragma: inl.} {.pragma: compilerRtl, compilerproc, importc: "nimrtl_$1", dynlib: nimrtl.} @@ -45,6 +44,13 @@ else: {.pragma: inl, inline.} {.pragma: compilerRtl, compilerproc.} -{.pragma: benign, gcsafe.} +when defined(nimlocks): + {.pragma: benign, gcsafe, locks: 0.} +else: + {.pragma: benign, gcsafe.} -{.push sinkInference: on.} +template since(version, body: untyped) {.dirty.} = + ## limitation: can't be used to annotate a template (eg typetraits.get), would + ## error: cannot attach a custom pragma. + when (NimMajor, NimMinor) >= version: + body diff --git a/lib/system/indexerrors.nim b/lib/system/indexerrors.nim index 6a8cb8a0a..1b91789bd 100644 --- a/lib/system/indexerrors.nim +++ b/lib/system/indexerrors.nim @@ -1,5 +1,4 @@ # imported by other modules, unlike helpers.nim which is included -# xxx this is now included instead of imported, we should import instead template formatErrorIndexBound*[T](i, a, b: T): string = when defined(standalone): @@ -10,6 +9,3 @@ template formatErrorIndexBound*[T](i, a, b: T): string = template formatErrorIndexBound*[T](i, n: T): string = formatErrorIndexBound(i, 0, n) - -template formatFieldDefect*(f, discVal): string = - f & discVal & "'" diff --git a/lib/system/indices.nim b/lib/system/indices.nim deleted file mode 100644 index fd6770e23..000000000 --- a/lib/system/indices.nim +++ /dev/null @@ -1,158 +0,0 @@ -when not defined(nimHasSystemRaisesDefect): - {.pragma: systemRaisesDefect.} - -type - BackwardsIndex* = distinct int ## Type that is constructed by `^` for - ## reversed array accesses. - ## (See `^ template <#^.t,int>`_) - -template `^`*(x: int): BackwardsIndex = BackwardsIndex(x) - ## Builtin `roof`:idx: operator that can be used for convenient array access. - ## `a[^x]` is a shortcut for `a[a.len-x]`. - ## - ## ``` - ## let - ## a = [1, 3, 5, 7, 9] - ## b = "abcdefgh" - ## - ## echo a[^1] # => 9 - ## echo b[^2] # => g - ## ``` - -proc `[]`*[T](s: openArray[T]; i: BackwardsIndex): T {.inline, systemRaisesDefect.} = - system.`[]`(s, s.len - int(i)) - -proc `[]`*[Idx, T](a: array[Idx, T]; i: BackwardsIndex): T {.inline, systemRaisesDefect.} = - a[Idx(a.len - int(i) + int low(a))] -proc `[]`*(s: string; i: BackwardsIndex): char {.inline, systemRaisesDefect.} = s[s.len - int(i)] - -proc `[]`*[T](s: var openArray[T]; i: BackwardsIndex): var T {.inline, systemRaisesDefect.} = - system.`[]`(s, s.len - int(i)) -proc `[]`*[Idx, T](a: var array[Idx, T]; i: BackwardsIndex): var T {.inline, systemRaisesDefect.} = - a[Idx(a.len - int(i) + int low(a))] -proc `[]`*(s: var string; i: BackwardsIndex): var char {.inline, systemRaisesDefect.} = s[s.len - int(i)] - -proc `[]=`*[T](s: var openArray[T]; i: BackwardsIndex; x: T) {.inline, systemRaisesDefect.} = - system.`[]=`(s, s.len - int(i), x) -proc `[]=`*[Idx, T](a: var array[Idx, T]; i: BackwardsIndex; x: T) {.inline, systemRaisesDefect.} = - a[Idx(a.len - int(i) + int low(a))] = x -proc `[]=`*(s: var string; i: BackwardsIndex; x: char) {.inline, systemRaisesDefect.} = - s[s.len - int(i)] = x - -template `..^`*(a, b: untyped): untyped = - ## A shortcut for `.. ^` to avoid the common gotcha that a space between - ## '..' and '^' is required. - a .. ^b - -template `..<`*(a, b: untyped): untyped = - ## A shortcut for `a .. pred(b)`. - ## ``` - ## for i in 5 ..< 9: - ## echo i # => 5; 6; 7; 8 - ## ``` - a .. (when b is BackwardsIndex: succ(b) else: pred(b)) - -template `[]`*(s: string; i: int): char = arrGet(s, i) -template `[]=`*(s: string; i: int; val: char) = arrPut(s, i, val) - -template `^^`(s, i: untyped): untyped = - (when i is BackwardsIndex: s.len - int(i) else: int(i)) - -template spliceImpl(s, a, L, b: typed): untyped = - # make room for additional elements or cut: - var shift = b.len - max(0,L) # ignore negative slice size - var newLen = s.len + shift - if shift > 0: - # enlarge: - setLen(s, newLen) - for i in countdown(newLen-1, a+b.len): movingCopy(s[i], s[i-shift]) - else: - for i in countup(a+b.len, newLen-1): movingCopy(s[i], s[i-shift]) - # cut down: - setLen(s, newLen) - # fill the hole: - for i in 0 ..< b.len: s[a+i] = b[i] - -proc `[]`*[T, U: Ordinal](s: string, x: HSlice[T, U]): string {.inline, systemRaisesDefect.} = - ## Slice operation for strings. - ## Returns the inclusive range `[s[x.a], s[x.b]]`: - ## ``` - ## var s = "abcdef" - ## assert s[1..3] == "bcd" - ## ``` - let a = s ^^ x.a - let L = (s ^^ x.b) - a + 1 - result = newString(L) - for i in 0 ..< L: result[i] = s[i + a] - -proc `[]=`*[T, U: Ordinal](s: var string, x: HSlice[T, U], b: string) {.systemRaisesDefect.} = - ## Slice assignment for strings. - ## - ## If `b.len` is not exactly the number of elements that are referred to - ## by `x`, a `splice`:idx: is performed: - ## - runnableExamples: - var s = "abcdefgh" - s[1 .. ^2] = "xyz" - assert s == "axyzh" - - var a = s ^^ x.a - var L = (s ^^ x.b) - a + 1 - if L == b.len: - for i in 0..= T(0) or (r xor b) >= T(0): - res[] = r - else: - result = true - -addImplFallback(nimAddInt, int, uint) -addImplFallback(nimAddInt64, int64, uint64) - -template subImplFallback(name, T, U) {.dirty.} = - when not declared(name): - proc name(a, b: T; res: ptr T): bool {.compilerproc, inline.} = - let r = cast[T](cast[U](a) - cast[U](b)) - if (r xor a) >= 0 or (r xor not b) >= 0: - res[] = r - else: - result = true - -subImplFallback(nimSubInt, int, uint) -subImplFallback(nimSubInt64, int64, uint64) - -template mulImplFallback(name, T, U, conv) {.dirty.} = - # - # This code has been inspired by Python's source code. - # The native int product x*y is either exactly right or *way* off, being - # just the last n bits of the true product, where n is the number of bits - # in an int (the delivered product is the true product plus i*2**n for - # some integer i). - # - # The native float64 product x*y is subject to three - # rounding errors: on a sizeof(int)==8 box, each cast to double can lose - # info, and even on a sizeof(int)==4 box, the multiplication can lose info. - # But, unlike the native int product, it's not in *range* trouble: even - # if sizeof(int)==32 (256-bit ints), the product easily fits in the - # dynamic range of a float64. So the leading 50 (or so) bits of the float64 - # product are correct. - # - # We check these two ways against each other, and declare victory if - # they're approximately the same. Else, because the native int product is - # the only one that can lose catastrophic amounts of information, it's the - # native int product that must have overflowed. - # - when not declared(name): - proc name(a, b: T; res: ptr T): bool {.compilerproc, inline.} = - let r = cast[T](cast[U](a) * cast[U](b)) - let floatProd = conv(a) * conv(b) - let resAsFloat = conv(r) - # Fast path for normal case: small multiplicands, and no info - # is lost in either method. - if resAsFloat == floatProd: - res[] = r - else: - # Somebody somewhere lost info. Close enough, or way off? Note - # that a != 0 and b != 0 (else resAsFloat == floatProd == 0). - # The difference either is or isn't significant compared to the - # true value (of which floatProd is a good approximation). - - # abs(diff)/abs(prod) <= 1/32 iff - # 32 * abs(diff) <= abs(prod) -- 5 good bits is "close enough" - if 32.0 * abs(resAsFloat - floatProd) <= abs(floatProd): - res[] = r - else: - result = true - -mulImplFallback(nimMulInt, int, uint, toFloat) -mulImplFallback(nimMulInt64, int64, uint64, toBiggestFloat) - - -template divImplFallback(name, T) {.dirty.} = - proc name(a, b: T; res: ptr T): bool {.compilerproc, inline.} = - # we moved the b == 0 case out into the codegen. - if a == low(T) and b == T(-1): - result = true - else: - res[] = a div b - -divImplFallback(nimDivInt, int) -divImplFallback(nimDivInt64, int64) - -proc raiseFloatInvalidOp {.compilerproc, noinline.} = - sysFatal(FloatInvalidOpDefect, "FPU operation caused a NaN result") - -proc raiseFloatOverflow(x: float64) {.compilerproc, noinline.} = - if x > 0.0: - sysFatal(FloatOverflowDefect, "FPU operation caused an overflow") - else: - sysFatal(FloatUnderflowDefect, "FPU operations caused an underflow") diff --git a/lib/std/syncio.nim b/lib/system/io.nim similarity index 57% rename from lib/std/syncio.nim rename to lib/system/io.nim index 77d4fa04c..985d51a67 100644 --- a/lib/std/syncio.nim +++ b/lib/system/io.nim @@ -1,19 +1,17 @@ # # # Nim's Runtime Library -# (c) Copyright 2022 Nim contributors +# (c) Copyright 2019 Nim contributors # # See the file "copying.txt", included in this # distribution, for details about the copyright. # -## This module implements various synchronized I/O operations. +## This is a part of ``system.nim``, you should not manually import it. -include system/inclrtl -import std/private/since -import std/formatfloat -when defined(windows): - import std/widestrs + +include inclrtl +import formatfloat # ----------------- IO Part ------------------------------------------------ type @@ -21,38 +19,27 @@ type incompleteStruct.} = object File* = ptr CFile ## The type representing a file handle. - FileMode* = enum ## The file mode when opening a file. - fmRead, ## Open the file for read access only. - ## If the file does not exist, it will not - ## be created. - fmWrite, ## Open the file for write access only. - ## If the file does not exist, it will be - ## created. Existing files will be cleared! - fmReadWrite, ## Open the file for read and write access. - ## If the file does not exist, it will be - ## created. Existing files will be cleared! - fmReadWriteExisting, ## Open the file for read and write access. - ## If the file does not exist, it will not be - ## created. The existing file will not be cleared. - fmAppend ## Open the file for writing only; append data - ## at the end. If the file does not exist, it - ## will be created. + FileMode* = enum ## The file mode when opening a file. + fmRead, ## Open the file for read access only. + fmWrite, ## Open the file for write access only. + ## If the file does not exist, it will be + ## created. Existing files will be cleared! + fmReadWrite, ## Open the file for read and write access. + ## If the file does not exist, it will be + ## created. Existing files will be cleared! + fmReadWriteExisting, ## Open the file for read and write access. + ## If the file does not exist, it will not be + ## created. The existing file will not be cleared. + fmAppend ## Open the file for writing only; append data + ## at the end. FileHandle* = cint ## type that represents an OS file handle; this is ## useful for low-level file access - FileSeekPos* = enum ## Position relative to which seek should happen. - # The values are ordered so that they match with stdio - # SEEK_SET, SEEK_CUR and SEEK_END respectively. - fspSet ## Seek to absolute value - fspCur ## Seek relative to current position - fspEnd ## Seek relative to end - # text file handling: when not defined(nimscript) and not defined(js): # duplicated between io and ansi_c - const stdioUsesMacros = (defined(osx) or defined(freebsd) or defined( - dragonfly)) and not defined(emscripten) + const stdioUsesMacros = (defined(osx) or defined(bsd)) and not defined(emscripten) const stderrName = when stdioUsesMacros: "__stderrp" else: "stderr" const stdoutName = when stdioUsesMacros: "__stdoutp" else: "stdout" const stdinName = when stdioUsesMacros: "__stdinp" else: "stdin" @@ -90,7 +77,7 @@ proc c_fputs(c: cstring, f: File): cint {. proc c_fgets(c: cstring, n: cint, f: File): cstring {. importc: "fgets", header: "", tags: [ReadIOEffect].} proc c_fgetc(stream: File): cint {. - importc: "fgetc", header: "", tags: [].} + importc: "fgetc", header: "", tags: [ReadIOEffect].} proc c_ungetc(c: cint, f: File): cint {. importc: "ungetc", header: "", tags: [].} proc c_putc(c: cint, stream: File): cint {. @@ -105,7 +92,7 @@ proc c_feof(f: File): cint {. importc: "feof", header: "".} when not declared(c_fwrite): - proc c_fwrite(buf: pointer, size, n: csize_t, f: File): csize_t {. + proc c_fwrite(buf: pointer, size, n: csize_t, f: File): cint {. importc: "fwrite", header: "".} # C routine that is used here: @@ -120,22 +107,8 @@ when defined(windows): else: proc c_fseek(f: File, offset: int64, whence: cint): cint {. importc: "_fseeki64", header: "", tags: [].} - when defined(tcc): - proc c_fsetpos(f: File, pos: var int64): int32 {. - importc: "fsetpos", header: "", tags: [].} - proc c_fgetpos(f: File, pos: var int64): int32 {. - importc: "fgetpos", header: "", tags: [].} - proc c_telli64(f: cint): int64 {. - importc: "_telli64", header: "", tags: [].} - proc c_ftell(f: File): int64 = - # Taken from https://pt.osdn.net/projects/mingw/scm/git/mingw-org-wsl/blobs/5.4-trunk/mingwrt/mingwex/stdio/ftelli64.c - result = -1'i64 - var pos: int64 - if c_fgetpos(f, pos) == 0 and c_fsetpos(f, pos) == 0: - result = c_telli64(c_fileno(f)) - else: - proc c_ftell(f: File): int64 {. - importc: "_ftelli64", header: "", tags: [].} + proc c_ftell(f: File): int64 {. + importc: "_ftelli64", header: "", tags: [].} else: proc c_fseek(f: File, offset: int64, whence: cint): cint {. importc: "fseeko", header: "", tags: [].} @@ -151,6 +124,13 @@ proc c_fprintf(f: File, frmt: cstring): cint {. proc c_fputc(c: char, f: File): cint {. importc: "fputc", header: "".} +# When running nim in android app, stdout goes nowhere, so echo gets ignored +# To redirect echo to the android logcat, use -d:androidNDK +when defined(androidNDK): + const ANDROID_LOG_VERBOSE = 2.cint + proc android_log_print(prio: cint, tag: cstring, fmt: cstring): cint + {.importc: "__android_log_print", header: "", varargs, discardable.} + template sysFatal(exc, msg) = raise newException(exc, msg) @@ -162,13 +142,13 @@ proc raiseEOF() {.noinline, noreturn.} = proc strerror(errnum: cint): cstring {.importc, header: "".} -when not defined(nimscript): +when not defined(NimScript): var errno {.importc, header: "".}: cint ## error variable EINTR {.importc: "EINTR", header: "".}: cint proc checkErr(f: File) = - when not defined(nimscript): + when not defined(NimScript): if c_ferror(f) != 0: let msg = "errno: " & $errno & " `" & $strerror(errno) & "`" c_clearerr(f) @@ -177,35 +157,30 @@ proc checkErr(f: File) = # shouldn't happen quit(1) -{.push stackTrace: off, profiler: off.} +{.push stackTrace:off, profiler:off.} proc readBuffer*(f: File, buffer: pointer, len: Natural): int {. tags: [ReadIOEffect], benign.} = - ## Reads `len` bytes into the buffer pointed to by `buffer`. Returns + ## reads `len` bytes into the buffer pointed to by `buffer`. Returns ## the actual number of bytes that have been read which may be less than ## `len` (if not as many bytes are remaining), but not greater. result = cast[int](c_fread(buffer, 1, cast[csize_t](len), f)) if result != len: checkErr(f) -proc readBytes*(f: File, a: var openArray[int8|uint8], start, - len: Natural): int {. +proc readBytes*(f: File, a: var openArray[int8|uint8], start, len: Natural): int {. tags: [ReadIOEffect], benign.} = - ## Reads `len` bytes into the buffer `a` starting at `a[start]`. Returns + ## reads `len` bytes into the buffer `a` starting at ``a[start]``. Returns ## the actual number of bytes that have been read which may be less than ## `len` (if not as many bytes are remaining), but not greater. result = readBuffer(f, addr(a[start]), len) -proc readChars*(f: File, a: var openArray[char]): int {.tags: [ReadIOEffect], benign.} = - ## Reads up to `a.len` bytes into the buffer `a`. Returns - ## the actual number of bytes that have been read which may be less than - ## `a.len` (if not as many bytes are remaining), but not greater. - result = readBuffer(f, addr(a[0]), a.len) - proc readChars*(f: File, a: var openArray[char], start, len: Natural): int {. - tags: [ReadIOEffect], benign, deprecated: - "use other `readChars` overload, possibly via: readChars(toOpenArray(buf, start, len-1))".} = - ## Reads `len` bytes into the buffer `a` starting at `a[start]`. Returns + tags: [ReadIOEffect], benign.} = + ## reads `len` bytes into the buffer `a` starting at ``a[start]``. Returns ## the actual number of bytes that have been read which may be less than ## `len` (if not as many bytes are remaining), but not greater. + ## + ## **Warning:** The buffer `a` must be pre-allocated. This can be done + ## using, for example, ``newString``. if (start + len) > len(a): raiseEIO("buffer overflow: (start+len) > length of openarray buffer") result = readBuffer(f, addr(a[start]), len) @@ -217,7 +192,7 @@ proc write*(f: File, c: cstring) {.tags: [WriteIOEffect], benign.} = proc writeBuffer*(f: File, buffer: pointer, len: Natural): int {. tags: [WriteIOEffect], benign.} = - ## Writes the bytes of buffer pointed to by the parameter `buffer` to the + ## writes the bytes of buffer pointed to by the parameter `buffer` to the ## file `f`. Returns the number of actual written bytes, which may be less ## than `len` in case of an error. result = cast[int](c_fwrite(buffer, 1, cast[csize_t](len), f)) @@ -225,7 +200,7 @@ proc writeBuffer*(f: File, buffer: pointer, len: Natural): int {. proc writeBytes*(f: File, a: openArray[int8|uint8], start, len: Natural): int {. tags: [WriteIOEffect], benign.} = - ## Writes the bytes of `a[start..start+len-1]` to the file `f`. Returns + ## writes the bytes of ``a[start..start+len-1]`` to the file `f`. Returns ## the number of actual written bytes, which may be less than `len` in case ## of an error. var x = cast[ptr UncheckedArray[int8]](a) @@ -233,7 +208,7 @@ proc writeBytes*(f: File, a: openArray[int8|uint8], start, len: Natural): int {. proc writeChars*(f: File, a: openArray[char], start, len: Natural): int {. tags: [WriteIOEffect], benign.} = - ## Writes the bytes of `a[start..start+len-1]` to the file `f`. Returns + ## writes the bytes of ``a[start..start+len-1]`` to the file `f`. Returns ## the number of actual written bytes, which may be less than `len` in case ## of an error. var x = cast[ptr UncheckedArray[int8]](a) @@ -269,56 +244,15 @@ proc write*(f: File, s: string) {.tags: [WriteIOEffect], benign.} = raiseEIO("cannot write string to file") {.pop.} -when defined(nimscript): - when defined(windows): - const - IOFBF = cint(0) - IONBF = cint(4) - else: - # On all systems I could find, including Linux, Mac OS X, and the BSDs - const - IOFBF = cint(0) - IONBF = cint(2) +when defined(windows): + const + IOFBF = cint(0) + IONBF = cint(4) else: - var - IOFBF {.importc: "_IOFBF", nodecl.}: cint - IONBF {.importc: "_IONBF", nodecl.}: cint - -const SupportIoctlInheritCtl = (defined(linux) or defined(bsd)) and - not defined(nimscript) -when SupportIoctlInheritCtl: - var - FIOCLEX {.importc, header: "".}: cint - FIONCLEX {.importc, header: "".}: cint - - proc c_ioctl(fd: cint, request: cint): cint {. - importc: "ioctl", header: "", varargs.} -elif defined(posix) and not defined(lwip) and not defined(nimscript): - var - F_GETFD {.importc, header: "".}: cint - F_SETFD {.importc, header: "".}: cint - FD_CLOEXEC {.importc, header: "".}: cint - - proc c_fcntl(fd: cint, cmd: cint): cint {. - importc: "fcntl", header: "", varargs.} -elif defined(windows): - type - WinDWORD = culong - WinBOOL = cint - - const HANDLE_FLAG_INHERIT = 1.WinDWORD - - proc getOsfhandle(fd: cint): int {. - importc: "_get_osfhandle", header: "".} - - type - IoHandle = distinct pointer - ## Windows' HANDLE type. Defined as an untyped pointer but is **not** - ## one. Named like this to avoid collision with other `system` modules. - - proc setHandleInformation(hObject: IoHandle, dwMask, dwFlags: WinDWORD): - WinBOOL {.stdcall, dynlib: "kernel32", - importc: "SetHandleInformation".} + # On all systems I could find, including Linux, Mac OS X, and the BSDs + const + IOFBF = cint(0) + IONBF = cint(2) const BufSize = 4000 @@ -342,7 +276,7 @@ proc flushFile*(f: File) {.tags: [WriteIOEffect].} = discard c_fflush(f) proc getFileHandle*(f: File): FileHandle = - ## Returns the file handle of the file `f`. This is only useful for + ## returns the file handle of the file ``f``. This is only useful for ## platform specific programming. ## Note that on Windows this doesn't return the Windows-specific handle, ## but the C library's notion of a handle, whatever that means. @@ -350,126 +284,44 @@ proc getFileHandle*(f: File): FileHandle = c_fileno(f) proc getOsFileHandle*(f: File): FileHandle = - ## Returns the OS file handle of the file `f`. This is only useful for + ## returns the OS file handle of the file ``f``. This is only useful for ## platform specific programming. when defined(windows): - result = FileHandle getOsfhandle(cint getFileHandle(f)) + proc getOsfhandle(fd: cint): FileHandle {. + importc: "_get_osfhandle", header: "".} + result = getOsfhandle(getFileHandle(f)) else: result = c_fileno(f) -when defined(nimdoc) or (defined(posix) and not defined(nimscript)) or defined(windows): - proc setInheritable*(f: FileHandle, inheritable: bool): bool = - ## control whether a file handle can be inherited by child processes. Returns - ## `true` on success. This requires the OS file handle, which can be - ## retrieved via `getOsFileHandle <#getOsFileHandle,File>`_. - ## - ## This procedure is not guaranteed to be available for all platforms. Test for - ## availability with `declared() `. - when SupportIoctlInheritCtl: - result = c_ioctl(f, if inheritable: FIONCLEX else: FIOCLEX) != -1 - elif defined(freertos) or defined(zephyr): - result = true - elif defined(posix): - var flags = c_fcntl(f, F_GETFD) - if flags == -1: - return false - flags = if inheritable: flags and not FD_CLOEXEC else: flags or FD_CLOEXEC - result = c_fcntl(f, F_SETFD, flags) != -1 - else: - result = setHandleInformation(cast[IoHandle](f), HANDLE_FLAG_INHERIT, - inheritable.WinDWORD) != 0 - -proc readLine*(f: File, line: var string): bool {.tags: [ReadIOEffect], +proc readLine*(f: File, line: var TaintedString): bool {.tags: [ReadIOEffect], benign.} = - ## Reads a line of text from the file `f` into `line`. May throw an IO + ## reads a line of text from the file `f` into `line`. May throw an IO ## exception. - ## A line of text may be delimited by `LF` or `CRLF`. The newline - ## character(s) are not part of the returned string. Returns `false` - ## if the end of the file has been reached, `true` otherwise. If - ## `false` is returned `line` contains no new data. + ## A line of text may be delimited by ``LF`` or ``CRLF``. The newline + ## character(s) are not part of the returned string. Returns ``false`` + ## if the end of the file has been reached, ``true`` otherwise. If + ## ``false`` is returned `line` contains no new data. proc c_memchr(s: pointer, c: cint, n: csize_t): pointer {. importc: "memchr", header: "".} - when defined(windows): - proc readConsole(hConsoleInput: FileHandle, lpBuffer: pointer, - nNumberOfCharsToRead: int32, - lpNumberOfCharsRead: ptr int32, - pInputControl: pointer): int32 {. - importc: "ReadConsoleW", stdcall, dynlib: "kernel32".} - - proc getLastError(): int32 {. - importc: "GetLastError", stdcall, dynlib: "kernel32", sideEffect.} - - proc formatMessageW(dwFlags: int32, lpSource: pointer, - dwMessageId, dwLanguageId: int32, - lpBuffer: pointer, nSize: int32, - arguments: pointer): int32 {. - importc: "FormatMessageW", stdcall, dynlib: "kernel32".} - - proc localFree(p: pointer) {. - importc: "LocalFree", stdcall, dynlib: "kernel32".} - - proc isatty(f: File): bool = - when defined(posix): - proc isatty(fildes: FileHandle): cint {. - importc: "isatty", header: "".} - else: - proc isatty(fildes: FileHandle): cint {. - importc: "_isatty", header: "".} - result = isatty(getFileHandle(f)) != 0'i32 - - # this implies the file is open - if f.isatty: - const numberOfCharsToRead = 2048 - var numberOfCharsRead = 0'i32 - var buffer = newWideCString("", numberOfCharsToRead) - if readConsole(getOsFileHandle(f), addr(buffer[0]), - numberOfCharsToRead, addr(numberOfCharsRead), nil) == 0: - var error = getLastError() - var errorMsg: string - var msgbuf: WideCString - if formatMessageW(0x00000100 or 0x00001000 or 0x00000200, - nil, error, 0, addr(msgbuf), 0, nil) != 0'i32: - errorMsg = $msgbuf - if msgbuf != nil: - localFree(cast[pointer](msgbuf)) - raiseEIO("error: " & $error & " `" & errorMsg & "`") - # input always ends with "\r\n" - numberOfCharsRead -= 2 - # handle Ctrl+Z as EOF - for i in 0.. 0 and line[last-1] == '\c': - line.setLen(last-1) + var last = cast[ByteAddress](m) - cast[ByteAddress](addr line.string[0]) + if last > 0 and line.string[last-1] == '\c': + line.string.setLen(last-1) return last > 1 or fgetsSuccess - elif last > 0 and line[last-1] == '\0': - # We have to distinguish among three possible cases: + # We have to distinguish between two possible cases: # \0\l\0 => line ending in a null character. # \0\l\l => last line without newline, null was put there by fgets. - # \0\l => last line without newline, null was put there by fgets. - if last >= pos + sp - 1 or line[last+1] != '\0': # bug #21273 + elif last > 0 and line.string[last-1] == '\0': + if last < pos + sp - 1 and line.string[last+1] != '\0': dec last - line.setLen(last) + line.string.setLen(last) return last > 0 or fgetsSuccess else: # fgets will have inserted a null byte at the end of the string. @@ -499,13 +350,13 @@ proc readLine*(f: File, line: var string): bool {.tags: [ReadIOEffect], # No \l found: Increase buffer and read more inc pos, sp sp = 128 # read in 128 bytes at a time - line.setLen(pos+sp) + line.string.setLen(pos+sp) -proc readLine*(f: File): string {.tags: [ReadIOEffect], benign.} = - ## Reads a line of text from the file `f`. May throw an IO exception. - ## A line of text may be delimited by `LF` or `CRLF`. The newline +proc readLine*(f: File): TaintedString {.tags: [ReadIOEffect], benign.} = + ## reads a line of text from the file `f`. May throw an IO exception. + ## A line of text may be delimited by ``LF`` or ``CRLF``. The newline ## character(s) are not part of the returned string. - result = newStringOfCap(80) + result = TaintedString(newStringOfCap(80)) if not readLine(f, result): raiseEOF() proc write*(f: File, i: int) {.tags: [WriteIOEffect], benign.} = @@ -525,12 +376,12 @@ proc write*(f: File, b: bool) {.tags: [WriteIOEffect], benign.} = else: write(f, "false") proc write*(f: File, r: float32) {.tags: [WriteIOEffect], benign.} = - var buffer {.noinit.}: array[65, char] + var buffer: array[65, char] discard writeFloatToBuffer(buffer, r) if c_fprintf(f, "%s", buffer[0].addr) < 0: checkErr(f) proc write*(f: File, r: BiggestFloat) {.tags: [WriteIOEffect], benign.} = - var buffer {.noinit.}: array[65, char] + var buffer: array[65, char] discard writeFloatToBuffer(buffer, r) if c_fprintf(f, "%s", buffer[0].addr) < 0: checkErr(f) @@ -562,7 +413,7 @@ proc rawFileSize(file: File): int64 = discard c_fseek(file, oldPos, 0) proc endOfFile*(f: File): bool {.tags: [], benign.} = - ## Returns true if `f` is at the end. + ## Returns true iff `f` is at the end. var c = c_fgetc(f) discard c_ungetc(c, f) return c < 0'i32 @@ -574,7 +425,7 @@ proc readAllFile(file: File, len: int64): string = result = newString(len) let bytes = readBuffer(file, addr(result[0]), len) if endOfFile(file): - if bytes.int64 < len: + if bytes < len: result.setLen(bytes) else: # We read all the bytes but did not reach the EOF @@ -585,7 +436,7 @@ proc readAllFile(file: File): string = var len = rawFileSize(file) result = readAllFile(file, len) -proc readAll*(file: File): string {.tags: [ReadIOEffect], benign.} = +proc readAll*(file: File): TaintedString {.tags: [ReadIOEffect], benign.} = ## Reads all data from the stream `file`. ## ## Raises an IO exception in case of an error. It is an error if the @@ -598,13 +449,18 @@ proc readAll*(file: File): string {.tags: [ReadIOEffect], benign.} = else: let len = rawFileSize(file) if len > 0: - result = readAllFile(file, len) + result = readAllFile(file, len).TaintedString else: - result = readAllBuffer(file) + result = readAllBuffer(file).TaintedString + +proc writeLn[Ty](f: File, x: varargs[Ty, `$`]) = + for i in items(x): + write(f, i) + write(f, "\n") proc writeLine*[Ty](f: File, x: varargs[Ty, `$`]) {.inline, tags: [WriteIOEffect], benign.} = - ## Writes the values `x` to `f` and then writes "\\n". + ## writes the values `x` to `f` and then writes "\\n". ## May throw an IO exception. for i in items(x): write(f, i) @@ -612,7 +468,7 @@ proc writeLine*[Ty](f: File, x: varargs[Ty, `$`]) {.inline, # interface to the C procs: -when defined(windows): +when defined(windows) and not defined(useWinAnsi): when defined(cpp): proc wfopen(filename, mode: WideCString): pointer {. importcpp: "_wfopen((const wchar_t*)#, (const wchar_t*)#)", nodecl.} @@ -640,27 +496,13 @@ else: importc: "freopen", nodecl.} const - NoInheritFlag = - # Platform specific flag for creating a File without inheritance. - when not defined(nimInheritHandles): - when defined(windows): - "N" - elif defined(linux) or defined(bsd): - "e" - else: - "" - else: - "" - FormatOpen: array[FileMode, cstring] = [ - cstring("rb" & NoInheritFlag), "wb" & NoInheritFlag, "w+b" & NoInheritFlag, - "r+b" & NoInheritFlag, "ab" & NoInheritFlag - ] + FormatOpen: array[FileMode, string] = ["rb", "wb", "w+b", "r+b", "ab"] #"rt", "wt", "w+t", "r+t", "at" # we always use binary here as for Nim the OS line ending # should not be translated. when defined(posix) and not defined(nimscript): - when defined(linux) and defined(amd64): + when (defined(linux) or defined(macosx)) and defined(amd64): type Mode {.importc: "mode_t", header: "".} = cint @@ -668,7 +510,7 @@ when defined(posix) and not defined(nimscript): Stat {.importc: "struct stat", header: "", final, pure.} = object ## struct stat filler_1: array[24, char] - st_mode: Mode ## Mode of file + st_mode: Mode ## Mode of file filler_2: array[144 - 24 - 4, char] proc modeIsDir(m: Mode): bool = @@ -681,7 +523,7 @@ when defined(posix) and not defined(nimscript): Stat {.importc: "struct stat", header: "", final, pure.} = object ## struct stat - st_mode: Mode ## Mode of file + st_mode: Mode ## Mode of file proc modeIsDir(m: Mode): bool {.importc: "S_ISDIR", header: "".} ## Test for a directory. @@ -692,66 +534,43 @@ when defined(posix) and not defined(nimscript): proc open*(f: var File, filename: string, mode: FileMode = fmRead, - bufSize: int = -1): bool {.tags: [], raises: [], benign.} = + bufSize: int = -1): bool {.tags: [], raises: [], benign.} = ## Opens a file named `filename` with given `mode`. ## - ## Default mode is readonly. Returns true if the file could be opened. + ## Default mode is readonly. Returns true iff the file could be opened. ## This throws no exception if the file could not be opened. - ## - ## The file handle associated with the resulting `File` is not inheritable. - var p = fopen(filename.cstring, FormatOpen[mode]) + var p = fopen(filename, FormatOpen[mode]) if p != nil: - var f2 = cast[File](p) when defined(posix) and not defined(nimscript): # How `fopen` handles opening a directory is not specified in ISO C and # POSIX. We do not want to handle directories as regular files that can # be opened. - var res {.noinit.}: Stat + var f2 = cast[File](p) + var res: Stat if c_fstat(getFileHandle(f2), res) >= 0'i32 and modeIsDir(res.st_mode): close(f2) return false - when not defined(nimInheritHandles) and declared(setInheritable) and - NoInheritFlag.len == 0: - if not setInheritable(getOsFileHandle(f2), false): - close(f2) - return false - result = true f = cast[File](p) - if bufSize > 0 and bufSize.uint <= high(uint): + if bufSize > 0 and bufSize <= high(cint).int: discard c_setvbuf(f, nil, IOFBF, cast[csize_t](bufSize)) elif bufSize == 0: discard c_setvbuf(f, nil, IONBF, 0) proc reopen*(f: File, filename: string, mode: FileMode = fmRead): bool {. tags: [], benign.} = - ## Reopens the file `f` with given `filename` and `mode`. This + ## reopens the file `f` with given `filename` and `mode`. This ## is often used to redirect the `stdin`, `stdout` or `stderr` ## file variables. ## - ## Default mode is readonly. Returns true if the file could be reopened. - ## - ## The file handle associated with `f` won't be inheritable. - if freopen(filename.cstring, FormatOpen[mode], f) != nil: - when not defined(nimInheritHandles) and declared(setInheritable) and - NoInheritFlag.len == 0: - if not setInheritable(getOsFileHandle(f), false): - close(f) - return false - result = true + ## Default mode is readonly. Returns true iff the file could be reopened. + result = freopen(filename, FormatOpen[mode], f) != nil proc open*(f: var File, filehandle: FileHandle, mode: FileMode = fmRead): bool {.tags: [], raises: [], benign.} = - ## Creates a `File` from a `filehandle` with given `mode`. + ## Creates a ``File`` from a `filehandle` with given `mode`. ## - ## Default mode is readonly. Returns true if the file could be opened. - ## - ## The passed file handle will no longer be inheritable. - when not defined(nimInheritHandles) and declared(setInheritable): - let oshandle = when defined(windows): FileHandle getOsfhandle( - filehandle) else: filehandle - if not setInheritable(oshandle, false): - return false + ## Default mode is readonly. Returns true iff the file could be opened. f = c_fdopen(filehandle, FormatOpen[mode]) result = f != nil @@ -759,27 +578,25 @@ proc open*(filename: string, mode: FileMode = fmRead, bufSize: int = -1): File = ## Opens a file named `filename` with given `mode`. ## - ## Default mode is readonly. Raises an `IOError` if the file + ## Default mode is readonly. Raises an ``IOError`` if the file ## could not be opened. - ## - ## The file handle associated with the resulting `File` is not inheritable. if not open(result, filename, mode, bufSize): sysFatal(IOError, "cannot open: " & filename) proc setFilePos*(f: File, pos: int64, relativeTo: FileSeekPos = fspSet) {.benign.} = - ## Sets the position of the file pointer that is used for read/write + ## sets the position of the file pointer that is used for read/write ## operations. The file's first byte has the index zero. if c_fseek(f, pos, cint(relativeTo)) != 0: raiseEIO("cannot set file position") proc getFilePos*(f: File): int64 {.benign.} = - ## Retrieves the current position of the file pointer that is used to + ## retrieves the current position of the file pointer that is used to ## read from the file `f`. The file's first byte has the index zero. result = c_ftell(f) if result < 0: raiseEIO("cannot retrieve file position") proc getFileSize*(f: File): int64 {.tags: [ReadIOEffect], benign.} = - ## Retrieves the file size (in bytes) of `f`. + ## retrieves the file size (in bytes) of `f`. let oldPos = getFilePos(f) discard c_fseek(f, 0, 2) # seek the end of the file result = getFilePos(f) @@ -794,8 +611,43 @@ proc setStdIoUnbuffered*() {.tags: [], benign.} = when declared(stdin): discard c_setvbuf(stdin, nil, IONBF, 0) +when declared(stdout): + when defined(windows) and compileOption("threads"): + const insideRLocksModule = false + include "system/syslocks" -when defined(windows) and not defined(nimscript) and not defined(js): + var echoLock: SysLock + initSysLock echoLock + + proc echoBinSafe(args: openArray[string]) {.compilerproc.} = + when defined(androidNDK): + var s = "" + for arg in args: + s.add arg + android_log_print(ANDROID_LOG_VERBOSE, "nim", s) + else: + # flockfile deadlocks some versions of Android 5.x.x + when not defined(windows) and not defined(android) and not defined(nintendoswitch) and hostOS != "any": + proc flockfile(f: File) {.importc, nodecl.} + proc funlockfile(f: File) {.importc, nodecl.} + flockfile(stdout) + when defined(windows) and compileOption("threads"): + acquireSys echoLock + for s in args: + when defined(windows): + writeWindows(stdout, s) + else: + discard c_fwrite(s.cstring, cast[csize_t](s.len), 1, stdout) + const linefeed = "\n" + discard c_fwrite(linefeed.cstring, linefeed.len, 1, stdout) + discard c_fflush(stdout) + when not defined(windows) and not defined(android) and not defined(nintendoswitch) and hostOS != "any": + funlockfile(stdout) + when defined(windows) and compileOption("threads"): + releaseSys echoLock + + +when defined(windows) and not defined(nimscript): # work-around C's sucking abstraction: # BUGFIX: stdin and stdout should be binary files! proc c_setmode(handle, mode: cint) {. @@ -811,41 +663,22 @@ when defined(windows) and not defined(nimscript) and not defined(js): when defined(windows) and appType == "console" and not defined(nimDontSetUtf8CodePage) and not defined(nimscript): - import std/exitprocs - proc setConsoleOutputCP(codepage: cuint): int32 {.stdcall, dynlib: "kernel32", importc: "SetConsoleOutputCP".} proc setConsoleCP(wCodePageID: cuint): int32 {.stdcall, dynlib: "kernel32", importc: "SetConsoleCP".} - proc getConsoleOutputCP(): cuint {.stdcall, dynlib: "kernel32", - importc: "GetConsoleOutputCP".} - proc getConsoleCP(): cuint {.stdcall, dynlib: "kernel32", - importc: "GetConsoleCP".} - const Utf8codepage = 65001'u32 + const Utf8codepage = 65001 + discard setConsoleOutputCP(Utf8codepage) + discard setConsoleCP(Utf8codepage) - let - consoleOutputCP = getConsoleOutputCP() - consoleCP = getConsoleCP() - - proc restoreConsoleOutputCP() = discard setConsoleOutputCP(consoleOutputCP) - proc restoreConsoleCP() = discard setConsoleCP(consoleCP) - - if consoleOutputCP != Utf8codepage: - discard setConsoleOutputCP(Utf8codepage) - addExitProc(restoreConsoleOutputCP) - - if consoleCP != Utf8codepage: - discard setConsoleCP(Utf8codepage) - addExitProc(restoreConsoleCP) - -proc readFile*(filename: string): string {.tags: [ReadIOEffect], benign.} = +proc readFile*(filename: string): TaintedString {.tags: [ReadIOEffect], benign.} = ## Opens a file named `filename` for reading, calls `readAll ## <#readAll,File>`_ and closes the file afterwards. Returns the string. ## Raises an IO exception in case of an error. If you need to call ## this inside a compile time macro you can use `staticRead ## `_. - var f: File = nil + var f: File if open(f, filename): try: result = readAll(f) @@ -858,7 +691,7 @@ proc writeFile*(filename, content: string) {.tags: [WriteIOEffect], benign.} = ## Opens a file named `filename` for writing. Then writes the ## `content` completely to the file and closes the file afterwards. ## Raises an IO exception in case of an error. - var f: File = nil + var f: File if open(f, filename, fmWrite): try: f.write(content) @@ -871,7 +704,7 @@ proc writeFile*(filename: string, content: openArray[byte]) {.since: (1, 1).} = ## Opens a file named `filename` for writing. Then writes the ## `content` completely to the file and closes the file afterwards. ## Raises an IO exception in case of an error. - var f: File = nil + var f: File if open(f, filename, fmWrite): try: f.writeBuffer(unsafeAddr content[0], content.len) @@ -880,15 +713,15 @@ proc writeFile*(filename: string, content: openArray[byte]) {.since: (1, 1).} = else: raise newException(IOError, "cannot open: " & filename) -proc readLines*(filename: string, n: Natural): seq[string] = - ## Reads `n` lines from the file named `filename`. Raises an IO exception +proc readLines*(filename: string, n: Natural): seq[TaintedString] = + ## read `n` lines from the file named `filename`. Raises an IO exception ## in case of an error. Raises EOF if file does not contain at least `n` lines. - ## Available at compile time. A line of text may be delimited by `LF` or `CRLF`. + ## Available at compile time. A line of text may be delimited by ``LF`` or ``CRLF``. ## The newline character(s) are not part of the returned strings. - var f: File = nil + var f: File if open(f, filename): try: - result = newSeq[string](n) + result = newSeq[TaintedString](n) for i in 0 .. n - 1: if not readLine(f, result[i]): raiseEOF() @@ -897,46 +730,42 @@ proc readLines*(filename: string, n: Natural): seq[string] = else: sysFatal(IOError, "cannot open: " & filename) -template readLines*(filename: string): seq[ - string] {.deprecated: "use readLines with two arguments".} = +proc readLines*(filename: string): seq[TaintedString] {.deprecated: "use readLines with two arguments".} = readLines(filename, 1) -iterator lines*(filename: string): string {.tags: [ReadIOEffect].} = +iterator lines*(filename: string): TaintedString {.tags: [ReadIOEffect].} = ## Iterates over any line in the file named `filename`. ## ## If the file does not exist `IOError` is raised. The trailing newline ## character(s) are removed from the iterated lines. Example: ## - runnableExamples: - import std/strutils - - proc transformLetters(filename: string) = - var buffer = "" - for line in filename.lines: - buffer.add(line.replace("a", "0") & '\n') - writeFile(filename, buffer) - var f = open(filename, bufSize = 8000) + ## .. code-block:: nim + ## import strutils + ## + ## proc transformLetters(filename: string) = + ## var buffer = "" + ## for line in filename.lines: + ## buffer.add(line.replace("a", "0") & '\x0A') + ## writeFile(filename, buffer) + var f = open(filename, bufSize=8000) try: - var res = newStringOfCap(80) + var res = TaintedString(newStringOfCap(80)) while f.readLine(res): yield res finally: close(f) -iterator lines*(f: File): string {.tags: [ReadIOEffect].} = - ## Iterates over any line in the file `f`. +iterator lines*(f: File): TaintedString {.tags: [ReadIOEffect].} = + ## Iterate over any line in the file `f`. ## ## The trailing newline character(s) are removed from the iterated lines. + ## Example: ## - runnableExamples: - proc countZeros(filename: File): tuple[lines, zeros: int] = - for line in filename.lines: - for letter in line: - if letter == '0': - result.zeros += 1 - result.lines += 1 - var res = newStringOfCap(80) + ## .. code-block:: nim + ## proc countZeros(filename: File): tuple[lines, zeros: int] = + ## for line in filename.lines: + ## for letter in line: + ## if letter == '0': + ## result.zeros += 1 + ## result.lines += 1 + var res = TaintedString(newStringOfCap(80)) while f.readLine(res): yield res - -template `&=`*(f: File, x: typed) = - ## An alias for `write`. - write(f, x) diff --git a/lib/system/iterators.nim b/lib/system/iterators.nim index 4bd12680f..53b287db0 100644 --- a/lib/system/iterators.nim +++ b/lib/system/iterators.nim @@ -1,30 +1,10 @@ -## Default iterators for some Nim types. - -when defined(nimPreviewSlimSystem): - import std/assertions - -when not defined(nimNoLentIterators): - template lent2(T): untyped = lent T -else: - template lent2(T): untyped = T - -iterator items*[T: not char](a: openArray[T]): lent2 T {.inline.} = +iterator items*[T](a: openArray[T]): T {.inline.} = ## Iterates over each item of `a`. var i = 0 while i < len(a): yield a[i] inc(i) -iterator items*[T: char](a: openArray[T]): T {.inline.} = - ## Iterates over each item of `a`. - # a VM bug currently prevents taking address of openArray[char] - # elements converted from a string (would fail in `tests/misc/thallo.nim`) - # in any case there's no performance advantage of returning char by address. - var i = 0 - while i < len(a): - yield a[i] - inc(i) - iterator mitems*[T](a: var openArray[T]): var T {.inline.} = ## Iterates over each item of `a` so that you can modify the yielded value. var i = 0 @@ -34,8 +14,8 @@ iterator mitems*[T](a: var openArray[T]): var T {.inline.} = iterator items*[IX, T](a: array[IX, T]): T {.inline.} = ## Iterates over each item of `a`. - when a.len > 0: - var i = low(IX) + var i = low(IX) + if i <= high(IX): while true: yield a[i] if i >= high(IX): break @@ -43,8 +23,8 @@ iterator items*[IX, T](a: array[IX, T]): T {.inline.} = iterator mitems*[IX, T](a: var array[IX, T]): var T {.inline.} = ## Iterates over each item of `a` so that you can modify the yielded value. - when a.len > 0: - var i = low(IX) + var i = low(IX) + if i <= high(IX): while true: yield a[i] if i >= high(IX): break @@ -61,116 +41,79 @@ iterator items*[T](a: set[T]): T {.inline.} = iterator items*(a: cstring): char {.inline.} = ## Iterates over each item of `a`. - runnableExamples: - from std/sequtils import toSeq - assert toSeq("abc\0def".cstring) == @['a', 'b', 'c'] - assert toSeq("abc".cstring) == @['a', 'b', 'c'] - #[ - assert toSeq(nil.cstring) == @[] # xxx fails with SIGSEGV - this fails with SIGSEGV; unclear whether we want to instead yield nothing - or pay a small price to check for `nil`, a benchmark is needed. Note that - other procs support `nil`. - ]# - template impl() = + when defined(js): var i = 0 - let n = len(a) - while i < n: + var L = len(a) + while i < L: yield a[i] inc(i) - when defined(js): impl() else: - when nimvm: - # xxx `cstring` should behave like c backend instead. - impl() - else: - var i = 0 - while a[i] != '\0': - yield a[i] - inc(i) + var i = 0 + while a[i] != '\0': + yield a[i] + inc(i) iterator mitems*(a: var cstring): var char {.inline.} = ## Iterates over each item of `a` so that you can modify the yielded value. - # xxx this should give CT error in js RT. - runnableExamples: - from std/sugar import collect - var a = "abc\0def" - prepareMutation(a) - var b = a.cstring - let s = collect: - for bi in mitems(b): - if bi == 'b': bi = 'B' - bi - assert s == @['a', 'B', 'c'] - assert b == "aBc" - assert a == "aBc\0def" - - template impl() = + when defined(js): var i = 0 - let n = len(a) - while i < n: + var L = len(a) + while i < L: yield a[i] inc(i) - when defined(js): impl() else: - when nimvm: impl() - else: - var i = 0 - while a[i] != '\0': - yield a[i] - inc(i) + var i = 0 + while a[i] != '\0': + yield a[i] + inc(i) -iterator items*[T: enum and Ordinal](E: typedesc[T]): T = - ## Iterates over the values of `E`. - ## See also `enumutils.items` for enums with holes. - runnableExamples: - type Goo = enum g0 = 2, g1, g2 - from std/sequtils import toSeq - assert Goo.toSeq == [g0, g1, g2] +iterator items*(E: typedesc[enum]): E = + ## Iterates over the values of the enum ``E``. for v in low(E) .. high(E): yield v -iterator items*[T: Ordinal](s: Slice[T]): T = +iterator items*[T](s: HSlice[T, T]): T = ## Iterates over the slice `s`, yielding each value between `s.a` and `s.b` ## (inclusively). for x in s.a .. s.b: yield x iterator pairs*[T](a: openArray[T]): tuple[key: int, val: T] {.inline.} = - ## Iterates over each item of `a`. Yields `(index, a[index])` pairs. + ## Iterates over each item of `a`. Yields ``(index, a[index])`` pairs. var i = 0 while i < len(a): yield (i, a[i]) inc(i) iterator mpairs*[T](a: var openArray[T]): tuple[key: int, val: var T]{.inline.} = - ## Iterates over each item of `a`. Yields `(index, a[index])` pairs. - ## `a[index]` can be modified. + ## Iterates over each item of `a`. Yields ``(index, a[index])`` pairs. + ## ``a[index]`` can be modified. var i = 0 while i < len(a): yield (i, a[i]) inc(i) iterator pairs*[IX, T](a: array[IX, T]): tuple[key: IX, val: T] {.inline.} = - ## Iterates over each item of `a`. Yields `(index, a[index])` pairs. - when a.len > 0: - var i = low(IX) + ## Iterates over each item of `a`. Yields ``(index, a[index])`` pairs. + var i = low(IX) + if i <= high(IX): while true: yield (i, a[i]) if i >= high(IX): break inc(i) iterator mpairs*[IX, T](a: var array[IX, T]): tuple[key: IX, val: var T] {.inline.} = - ## Iterates over each item of `a`. Yields `(index, a[index])` pairs. - ## `a[index]` can be modified. - when a.len > 0: - var i = low(IX) + ## Iterates over each item of `a`. Yields ``(index, a[index])`` pairs. + ## ``a[index]`` can be modified. + var i = low(IX) + if i <= high(IX): while true: yield (i, a[i]) if i >= high(IX): break inc(i) iterator pairs*[T](a: seq[T]): tuple[key: int, val: T] {.inline.} = - ## Iterates over each item of `a`. Yields `(index, a[index])` pairs. + ## Iterates over each item of `a`. Yields ``(index, a[index])`` pairs. var i = 0 let L = len(a) while i < L: @@ -179,8 +122,8 @@ iterator pairs*[T](a: seq[T]): tuple[key: int, val: T] {.inline.} = assert(len(a) == L, "the length of the seq changed while iterating over it") iterator mpairs*[T](a: var seq[T]): tuple[key: int, val: var T] {.inline.} = - ## Iterates over each item of `a`. Yields `(index, a[index])` pairs. - ## `a[index]` can be modified. + ## Iterates over each item of `a`. Yields ``(index, a[index])`` pairs. + ## ``a[index]`` can be modified. var i = 0 let L = len(a) while i < L: @@ -189,7 +132,7 @@ iterator mpairs*[T](a: var seq[T]): tuple[key: int, val: var T] {.inline.} = assert(len(a) == L, "the length of the seq changed while iterating over it") iterator pairs*(a: string): tuple[key: int, val: char] {.inline.} = - ## Iterates over each item of `a`. Yields `(index, a[index])` pairs. + ## Iterates over each item of `a`. Yields ``(index, a[index])`` pairs. var i = 0 let L = len(a) while i < L: @@ -198,8 +141,8 @@ iterator pairs*(a: string): tuple[key: int, val: char] {.inline.} = assert(len(a) == L, "the length of the string changed while iterating over it") iterator mpairs*(a: var string): tuple[key: int, val: var char] {.inline.} = - ## Iterates over each item of `a`. Yields `(index, a[index])` pairs. - ## `a[index]` can be modified. + ## Iterates over each item of `a`. Yields ``(index, a[index])`` pairs. + ## ``a[index]`` can be modified. var i = 0 let L = len(a) while i < L: @@ -208,7 +151,7 @@ iterator mpairs*(a: var string): tuple[key: int, val: var char] {.inline.} = assert(len(a) == L, "the length of the string changed while iterating over it") iterator pairs*(a: cstring): tuple[key: int, val: char] {.inline.} = - ## Iterates over each item of `a`. Yields `(index, a[index])` pairs. + ## Iterates over each item of `a`. Yields ``(index, a[index])`` pairs. when defined(js): var i = 0 var L = len(a) @@ -222,8 +165,8 @@ iterator pairs*(a: cstring): tuple[key: int, val: char] {.inline.} = inc(i) iterator mpairs*(a: var cstring): tuple[key: int, val: var char] {.inline.} = - ## Iterates over each item of `a`. Yields `(index, a[index])` pairs. - ## `a[index]` can be modified. + ## Iterates over each item of `a`. Yields ``(index, a[index])`` pairs. + ## ``a[index]`` can be modified. when defined(js): var i = 0 var L = len(a) @@ -236,7 +179,7 @@ iterator mpairs*(a: var cstring): tuple[key: int, val: var char] {.inline.} = yield (i, a[i]) inc(i) -iterator items*[T](a: seq[T]): lent2 T {.inline.} = +iterator items*[T](a: seq[T]): T {.inline.} = ## Iterates over each item of `a`. var i = 0 let L = len(a) @@ -277,24 +220,24 @@ iterator fields*[T: tuple|object](x: T): RootObj {. magic: "Fields", noSideEffect.} = ## Iterates over every field of `x`. ## - ## .. warning:: This really transforms the 'for' and unrolls the loop. - ## The current implementation also has a bug - ## that affects symbol binding in the loop body. + ## **Warning**: This really transforms the 'for' and unrolls the loop. + ## The current implementation also has a bug + ## that affects symbol binding in the loop body. runnableExamples: var t = (1, "foo") - for v in fields(t): v = default(typeof(v)) + for v in fields(t): v = default(type(v)) doAssert t == (0, "") iterator fields*[S:tuple|object, T:tuple|object](x: S, y: T): tuple[key: string, val: RootObj] {. magic: "Fields", noSideEffect.} = ## Iterates over every field of `x` and `y`. ## - ## .. warning:: This really transforms the 'for' and unrolls the loop. - ## The current implementation also has a bug that affects symbol binding - ## in the loop body. + ## **Warning**: This really transforms the 'for' and unrolls the loop. + ## The current implementation also has a bug that affects symbol binding + ## in the loop body. runnableExamples: var t1 = (1, "foo") - var t2 = default(typeof(t1)) + var t2 = default(type(t1)) for v1, v2 in fields(t1, t2): v2 = v1 doAssert t1 == t2 @@ -303,16 +246,16 @@ iterator fieldPairs*[T: tuple|object](x: T): tuple[key: string, val: RootObj] {. ## Iterates over every field of `x` returning their name and value. ## ## When you iterate over objects with different field types you have to use - ## the compile time `when` instead of a runtime `if` to select the code + ## the compile time ``when`` instead of a runtime ``if`` to select the code ## you want to run for each type. To perform the comparison use the `is ## operator `_. - ## Another way to do the same without `when` is to leave the task of + ## Another way to do the same without ``when`` is to leave the task of ## picking the appropriate code to a secondary proc which you overload for ## each field type and pass the `value` to. ## - ## .. warning:: This really transforms the 'for' and unrolls the loop. The - ## current implementation also has a bug that affects symbol binding in the - ## loop body. + ## **Warning**: This really transforms the 'for' and unrolls the loop. The + ## current implementation also has a bug that affects symbol binding in the + ## loop body. runnableExamples: type Custom = object @@ -331,9 +274,9 @@ iterator fieldPairs*[S: tuple|object, T: tuple|object](x: S, y: T): tuple[ magic: "FieldPairs", noSideEffect.} = ## Iterates over every field of `x` and `y`. ## - ## .. warning:: This really transforms the 'for' and unrolls the loop. - ## The current implementation also has a bug that affects symbol binding - ## in the loop body. + ## **Warning**: This really transforms the 'for' and unrolls the loop. + ## The current implementation also has a bug that affects symbol binding + ## in the loop body. runnableExamples: type Foo = object x1: int diff --git a/lib/system/iterators_1.nim b/lib/system/iterators_1.nim index be61fd62c..07c731c3b 100644 --- a/lib/system/iterators_1.nim +++ b/lib/system/iterators_1.nim @@ -9,27 +9,22 @@ iterator countdown*[T](a, b: T, step: Positive = 1): T {.inline.} = ## ## `T` may be any ordinal type, `step` may only be positive. ## - ## **Note**: This fails to count to `low(int)` if T = int for + ## **Note**: This fails to count to ``low(int)`` if T = int for ## efficiency reasons. - runnableExamples: - import std/sugar - let x = collect(newSeq): - for i in countdown(7, 3): - i - - assert x == @[7, 6, 5, 4, 3] - - let y = collect(newseq): - for i in countdown(9, 2, 3): - i - assert y == @[9, 6, 3] + ## + ## .. code-block:: Nim + ## for i in countdown(7, 3): + ## echo i # => 7; 6; 5; 4; 3 + ## + ## for i in countdown(9, 2, 3): + ## echo i # => 9; 6; 3 when T is (uint|uint64): var res = a while res >= b: yield res if res == b: break dec(res, step) - elif T is IntLikeForCount and T is Ordinal: + elif T is IntLikeForCount: var res = int(a) while res >= int(b): yield T(res) @@ -40,100 +35,148 @@ iterator countdown*[T](a, b: T, step: Positive = 1): T {.inline.} = yield res dec(res, step) -iterator countup*[T](a, b: T, step: Positive = 1): T {.inline.} = - ## Counts from ordinal value `a` to `b` (inclusive) with the given - ## step count. - ## - ## `T` may be any ordinal type, `step` may only be positive. - ## - ## **Note**: This fails to count to `high(int)` if T = int for - ## efficiency reasons. - runnableExamples: - import std/sugar - let x = collect(newSeq): - for i in countup(3, 7): - i - - assert x == @[3, 4, 5, 6, 7] +when defined(nimNewRoof): + iterator countup*[T](a, b: T, step: Positive = 1): T {.inline.} = + ## Counts from ordinal value `a` to `b` (inclusive) with the given + ## step count. + ## + ## `T` may be any ordinal type, `step` may only be positive. + ## + ## **Note**: This fails to count to ``high(int)`` if T = int for + ## efficiency reasons. + ## + ## .. code-block:: Nim + ## for i in countup(3, 7): + ## echo i # => 3; 4; 5; 6; 7 + ## + ## for i in countup(2, 9, 3): + ## echo i # => 2; 5; 8 + mixin inc + when T is IntLikeForCount: + var res = int(a) + while res <= int(b): + yield T(res) + inc(res, step) + else: + var res = a + while res <= b: + yield res + inc(res, step) - let y = collect(newseq): - for i in countup(2, 9, 3): - i - assert y == @[2, 5, 8] - mixin inc - when T is IntLikeForCount and T is Ordinal: - var res = int(a) - while res <= int(b): - yield T(res) - inc(res, step) - else: - var res = a - while res <= b: - yield res - inc(res, step) - -iterator `..`*[T](a, b: T): T {.inline.} = - ## An alias for `countup(a, b, 1)`. - ## - ## See also: - ## * [..<](#..<.i,T,T) - runnableExamples: - import std/sugar - - let x = collect(newSeq): - for i in 3 .. 7: - i - - assert x == @[3, 4, 5, 6, 7] - mixin inc - when T is IntLikeForCount and T is Ordinal: - var res = int(a) - while res <= int(b): - yield T(res) - inc(res) - else: - var res = a - while res <= b: - yield res - inc(res) - -template dotdotImpl(t) {.dirty.} = - iterator `..`*(a, b: t): t {.inline.} = - ## A type specialized version of `..` for convenience so that - ## mixing integer types works better. + iterator `..`*[T](a, b: T): T {.inline.} = + ## An alias for `countup(a, b, 1)`. ## ## See also: ## * [..<](#..<.i,T,T) - var res = a - while res <= b: - yield res - inc(res) + ## + ## .. code-block:: Nim + ## for i in 3 .. 7: + ## echo i # => 3; 4; 5; 6; 7 + mixin inc + when T is IntLikeForCount: + var res = int(a) + while res <= int(b): + yield T(res) + inc(res) + else: + var res = a + while res <= b: + yield res + inc(res) -dotdotImpl(int64) -dotdotImpl(int32) -dotdotImpl(uint64) -dotdotImpl(uint32) + template dotdotImpl(t) {.dirty.} = + iterator `..`*(a, b: t): t {.inline.} = + ## A type specialized version of ``..`` for convenience so that + ## mixing integer types works better. + ## + ## See also: + ## * [..<](#..<.i,T,T) + var res = a + while res <= b: + yield res + inc(res) -iterator `..<`*[T](a, b: T): T {.inline.} = - mixin inc - var i = a - while i < b: - yield i - inc i + dotdotImpl(int64) + dotdotImpl(int32) + dotdotImpl(uint64) + dotdotImpl(uint32) -template dotdotLessImpl(t) {.dirty.} = - iterator `..<`*(a, b: t): t {.inline.} = - ## A type specialized version of `..<` for convenience so that - ## mixing integer types works better. - var res = a - while res < b: - yield res - inc(res) + iterator `..<`*[T](a, b: T): T {.inline.} = + mixin inc + var i = a + while i < b: + yield i + inc i + + template dotdotLessImpl(t) {.dirty.} = + iterator `..<`*(a, b: t): t {.inline.} = + ## A type specialized version of ``..<`` for convenience so that + ## mixing integer types works better. + var res = a + while res < b: + yield res + inc(res) + + dotdotLessImpl(int64) + dotdotLessImpl(int32) + dotdotLessImpl(uint64) + dotdotLessImpl(uint32) + +else: # not defined(nimNewRoof) + iterator countup*[S, T](a: S, b: T, step = 1): T {.inline.} = + ## Counts from ordinal value `a` up to `b` (inclusive) with the given + ## step count. + ## + ## `S`, `T` may be any ordinal type, `step` may only be positive. + ## + ## **Note**: This fails to count to ``high(int)`` if T = int for + ## efficiency reasons. + ## + ## .. code-block:: Nim + ## for i in countup(3, 7): + ## echo i # => 3; 4; 5; 6; 7 + ## + ## for i in countup(2, 9, 3): + ## echo i # => 2; 5; 8 + when T is IntLikeForCount: + var res = int(a) + while res <= int(b): + yield T(res) + inc(res, step) + else: + var res = T(a) + while res <= b: + yield res + inc(res, step) + + iterator `..`*[S, T](a: S, b: T): T {.inline.} = + ## An alias for `countup(a, b, 1)`. + ## + ## See also: + ## * [..<](#..<.i,T,T) + ## + ## .. code-block:: Nim + ## for i in 3 .. 7: + ## echo i # => 3; 4; 5; 6; 7 + mixin inc + when T is IntLikeForCount: + var res = int(a) + while res <= int(b): + yield T(res) + inc(res) + else: + var res = T(a) + while res <= b: + yield res + inc(res) + + iterator `..<`*[S, T](a: S, b: T): T {.inline.} = + mixin inc + var i = T(a) + while i < b: + yield i + inc i -dotdotLessImpl(int64) -dotdotLessImpl(int32) -dotdotLessImpl(uint64) -dotdotLessImpl(uint32) iterator `||`*[S, T](a: S, b: T, annotation: static string = "parallel for"): T {. inline, magic: "OmpParFor", sideEffect.} = @@ -146,9 +189,9 @@ iterator `||`*[S, T](a: S, b: T, annotation: static string = "parallel for"): T ## for further information. ## ## Note that the compiler maps that to - ## the `#pragma omp parallel for` construct of `OpenMP`:idx: and as + ## the ``#pragma omp parallel for`` construct of `OpenMP`:idx: and as ## such isn't aware of the parallelism in your code! Be careful! Later - ## versions of `||` will get proper support by Nim's code generator + ## versions of ``||`` will get proper support by Nim's code generator ## and GC. discard @@ -164,8 +207,8 @@ iterator `||`*[S, T](a: S, b: T, step: Positive, annotation: static string = "pa ## for further information. ## ## Note that the compiler maps that to - ## the `#pragma omp parallel for` construct of `OpenMP`:idx: and as + ## the ``#pragma omp parallel for`` construct of `OpenMP`:idx: and as ## such isn't aware of the parallelism in your code! Be careful! Later - ## versions of `||` will get proper support by Nim's code generator + ## versions of ``||`` will get proper support by Nim's code generator ## and GC. discard diff --git a/lib/system/jssys.nim b/lib/system/jssys.nim index 4f64403fe..2f3512cfc 100644 --- a/lib/system/jssys.nim +++ b/lib/system/jssys.nim @@ -7,8 +7,7 @@ # distribution, for details about the copyright. # -include system/indexerrors -import std/private/miscdollars +import system/indexerrors proc log*(s: cstring) {.importc: "console.log", varargs, nodecl.} @@ -69,12 +68,9 @@ proc getCurrentExceptionMsg*(): string = return $msg return "" -proc setCurrentException*(exc: ref Exception) = - lastJSError = cast[PJSError](exc) - proc auxWriteStackTrace(f: PCallFrame): string = type - TempFrame = tuple[procname: cstring, line: int, filename: cstring] + TempFrame = tuple[procname: cstring, line: int] var it = f i = 0 @@ -83,7 +79,6 @@ proc auxWriteStackTrace(f: PCallFrame): string = while it != nil and i <= high(tempFrames): tempFrames[i].procname = it.procname tempFrames[i].line = it.line - tempFrames[i].filename = it.filename inc(i) inc(total) it = it.prev @@ -97,9 +92,10 @@ proc auxWriteStackTrace(f: PCallFrame): string = add(result, $(total-i)) add(result, " calls omitted) ...\n") for j in countdown(i-1, 0): - result.toLocation($tempFrames[j].filename, tempFrames[j].line, 0) - add(result, " at ") add(result, tempFrames[j].procname) + if tempFrames[j].line > 0: + add(result, ", line: ") + add(result, $tempFrames[j].line) add(result, "\n") proc rawWriteStackTrace(): string = @@ -108,11 +104,6 @@ proc rawWriteStackTrace(): string = else: result = "No stack traceback available\n" -proc writeStackTrace() = - var trace = rawWriteStackTrace() - trace.setLen(trace.len - 1) - echo trace - proc getStackTrace*(): string = rawWriteStackTrace() proc getStackTrace*(e: ref Exception): string = e.trace @@ -130,8 +121,7 @@ proc unhandledException(e: ref Exception) {. when NimStackTrace: add(buf, rawWriteStackTrace()) let cbuf = cstring(buf) - when NimStackTrace: - framePtr = nil + framePtr = nil {.emit: """ if (typeof(Error) !== "undefined") { throw new Error(`cbuf`); @@ -152,7 +142,7 @@ proc raiseException(e: ref Exception, ename: cstring) {. proc reraiseException() {.compilerproc, asmNoStackFrame.} = if lastJSError == nil: - raise newException(ReraiseDefect, "no exception to reraise") + raise newException(ReraiseError, "no exception to reraise") else: if excHandler == 0: if isNimException(): @@ -161,19 +151,19 @@ proc reraiseException() {.compilerproc, asmNoStackFrame.} = asm "throw lastJSError;" proc raiseOverflow {.exportc: "raiseOverflow", noreturn, compilerproc.} = - raise newException(OverflowDefect, "over- or underflow") + raise newException(OverflowError, "over- or underflow") proc raiseDivByZero {.exportc: "raiseDivByZero", noreturn, compilerproc.} = - raise newException(DivByZeroDefect, "division by zero") + raise newException(DivByZeroError, "division by zero") proc raiseRangeError() {.compilerproc, noreturn.} = - raise newException(RangeDefect, "value out of range") + raise newException(RangeError, "value out of range") proc raiseIndexError(i, a, b: int) {.compilerproc, noreturn.} = - raise newException(IndexDefect, formatErrorIndexBound(int(i), int(a), int(b))) + raise newException(IndexError, formatErrorIndexBound(int(i), int(a), int(b))) -proc raiseFieldError2(f: string, discVal: string) {.compilerproc, noreturn.} = - raise newException(FieldDefect, formatFieldDefect(f, discVal)) +proc raiseFieldError(f: string) {.compilerproc, noreturn.} = + raise newException(FieldError, f) proc setConstr() {.varargs, asmNoStackFrame, compilerproc.} = asm """ @@ -193,8 +183,9 @@ proc setConstr() {.varargs, asmNoStackFrame, compilerproc.} = proc makeNimstrLit(c: cstring): string {.asmNoStackFrame, compilerproc.} = {.emit: """ - var result = []; - for (var i = 0; i < `c`.length; ++i) { + var ln = `c`.length; + var result = new Array(ln); + for (var i = 0; i < ln; ++i) { result[i] = `c`.charCodeAt(i); } return result; @@ -344,12 +335,7 @@ proc cmpStrings(a, b: string): int {.asmNoStackFrame, compilerproc.} = """ proc cmp(x, y: string): int = - when nimvm: - if x == y: result = 0 - elif x < y: result = -1 - else: result = 1 - else: - result = cmpStrings(x, y) + return cmpStrings(x, y) proc eqStrings(a, b: string): bool {.asmNoStackFrame, compilerproc.} = asm """ @@ -411,29 +397,24 @@ else: """.} # Arithmetic: -proc checkOverflowInt(a: int) {.asmNoStackFrame, compilerproc.} = - asm """ - if (`a` > 2147483647 || `a` < -2147483648) `raiseOverflow`(); - """ - proc addInt(a, b: int): int {.asmNoStackFrame, compilerproc.} = asm """ var result = `a` + `b`; - `checkOverflowInt`(result); + if (result > 2147483647 || result < -2147483648) `raiseOverflow`(); return result; """ proc subInt(a, b: int): int {.asmNoStackFrame, compilerproc.} = asm """ var result = `a` - `b`; - `checkOverflowInt`(result); + if (result > 2147483647 || result < -2147483648) `raiseOverflow`(); return result; """ proc mulInt(a, b: int): int {.asmNoStackFrame, compilerproc.} = asm """ var result = `a` * `b`; - `checkOverflowInt`(result); + if (result > 2147483647 || result < -2147483648) `raiseOverflow`(); return result; """ @@ -451,29 +432,27 @@ proc modInt(a, b: int): int {.asmNoStackFrame, compilerproc.} = return Math.trunc(`a` % `b`); """ -proc checkOverflowInt64(a: int) {.asmNoStackFrame, compilerproc.} = - asm """ - if (`a` > 9223372036854775807 || `a` < -9223372036854775808) `raiseOverflow`(); - """ - proc addInt64(a, b: int): int {.asmNoStackFrame, compilerproc.} = asm """ var result = `a` + `b`; - `checkOverflowInt64`(result); + if (result > 9223372036854775807 + || result < -9223372036854775808) `raiseOverflow`(); return result; """ proc subInt64(a, b: int): int {.asmNoStackFrame, compilerproc.} = asm """ var result = `a` - `b`; - `checkOverflowInt64`(result); + if (result > 9223372036854775807 + || result < -9223372036854775808) `raiseOverflow`(); return result; """ proc mulInt64(a, b: int): int {.asmNoStackFrame, compilerproc.} = asm """ var result = `a` * `b`; - `checkOverflowInt64`(result); + if (result > 9223372036854775807 + || result < -9223372036854775808) `raiseOverflow`(); return result; """ @@ -503,12 +482,34 @@ proc absInt(a: int): int {.compilerproc.} = proc absInt64(a: int64): int64 {.compilerproc.} = result = if a < 0: a*(-1) else: a +when not defined(nimNoZeroExtendMagic): + proc ze*(a: int): int {.compilerproc.} = + result = a + + proc ze64*(a: int64): int64 {.compilerproc.} = + result = a + + proc toU8*(a: int): int8 {.asmNoStackFrame, compilerproc.} = + asm """ + return `a`; + """ + + proc toU16*(a: int): int16 {.asmNoStackFrame, compilerproc.} = + asm """ + return `a`; + """ + + proc toU32*(a: int64): int32 {.asmNoStackFrame, compilerproc.} = + asm """ + return `a`; + """ + proc nimMin(a, b: int): int {.compilerproc.} = return if a <= b: a else: b proc nimMax(a, b: int): int {.compilerproc.} = return if a >= b: a else: b proc chckNilDisp(p: pointer) {.compilerproc.} = if p == nil: - sysFatal(NilAccessDefect, "cannot dispatch; dispatcher is nil") + sysFatal(NilAccessError, "cannot dispatch; dispatcher is nil") include "system/hti" @@ -566,41 +567,18 @@ proc nimCopy(dest, src: JSRef, ti: PNimType): JSRef = else: asm "`result` = (`dest` === null || `dest` === undefined) ? {} : `dest`;" nimCopyAux(result, src, ti.node) - of tyArrayConstr, tyArray: - # In order to prevent a type change (TypedArray -> Array) and to have better copying performance, - # arrays constructors are considered separately - asm """ - if(ArrayBuffer.isView(`src`)) { - if(`dest` === null || `dest` === undefined || `dest`.length != `src`.length) { - `dest` = new `src`.constructor(`src`); - } else { - `dest`.set(`src`, 0); - } - `result` = `dest`; - } else { - if (`src` === null) { - `result` = null; - } - else { - if (`dest` === null || `dest` === undefined || `dest`.length != `src`.length) { - `dest` = new Array(`src`.length); - } - `result` = `dest`; - for (var i = 0; i < `src`.length; ++i) { - `result`[i] = nimCopy(`result`[i], `src`[i], `ti`.base); - } - } - } - """ - of tySequence, tyOpenArray: + of tySequence, tyArrayConstr, tyOpenArray, tyArray: asm """ if (`src` === null) { `result` = null; } else { - if (`dest` === null || `dest` === undefined || `dest`.length != `src`.length) { + if (`dest` === null || `dest` === undefined) { `dest` = new Array(`src`.length); } + else { + `dest`.length = `src`.length; + } `result` = `dest`; for (var i = 0; i < `src`.length; ++i) { `result`[i] = nimCopy(`result`[i], `src`[i], `ti`.base); @@ -633,7 +611,7 @@ proc genericReset(x: JSRef, ti: PNimType): JSRef {.compilerproc.} = asm "`result` = {m_type: `ti`};" else: asm "`result` = {};" - of tySequence, tyOpenArray, tyString: + of tySequence, tyOpenArray: asm """ `result` = []; """ @@ -670,7 +648,7 @@ proc chckObj(obj, subclass: PNimType) {.compilerproc.} = if x == subclass: return # optimized fast path while x != subclass: if x == nil: - raise newException(ObjectConversionDefect, "invalid object conversion") + raise newException(ObjectConversionError, "invalid object conversion") x = x.base proc isObj(obj, subclass: PNimType): bool {.compilerproc.} = @@ -688,7 +666,6 @@ proc addChar(x: string, c: char) {.compilerproc, asmNoStackFrame.} = {.pop.} proc tenToThePowerOf(b: int): BiggestFloat = - # xxx deadcode var b = b var a = 10.0 result = 1.0 @@ -702,75 +679,86 @@ proc tenToThePowerOf(b: int): BiggestFloat = const IdentChars = {'a'..'z', 'A'..'Z', '0'..'9', '_'} - -proc parseFloatNative(a: openarray[char]): float = - var str = "" - for x in a: - str.add x - - let cstr = cstring str - - asm """ - `result` = Number(`cstr`); - """ - -proc nimParseBiggestFloat(s: openarray[char], number: var BiggestFloat): int {.compilerproc.} = - var sign: bool - var i = 0 +# XXX use JS's native way here +proc nimParseBiggestFloat(s: string, number: var BiggestFloat, start = 0): int {. + compilerproc.} = + var + esign = 1.0 + sign = 1.0 + i = start + exponent: int + flags: int + number = 0.0 if s[i] == '+': inc(i) elif s[i] == '-': - sign = true + sign = -1.0 inc(i) if s[i] == 'N' or s[i] == 'n': if s[i+1] == 'A' or s[i+1] == 'a': if s[i+2] == 'N' or s[i+2] == 'n': if s[i+3] notin IdentChars: number = NaN - return i+3 + return i+3 - start return 0 if s[i] == 'I' or s[i] == 'i': if s[i+1] == 'N' or s[i+1] == 'n': if s[i+2] == 'F' or s[i+2] == 'f': if s[i+3] notin IdentChars: - number = if sign: -Inf else: Inf - return i+3 + number = Inf*sign + return i+3 - start return 0 - - var buf: string - # we could also use an `array[char, N]` buffer to avoid reallocs, or - # use a 2-pass algorithm that first computes the length. - if sign: buf.add '-' - template addInc = - buf.add s[i] + while s[i] in {'0'..'9'}: + # Read integer part + flags = flags or 1 + number = number * 10.0 + toFloat(ord(s[i]) - ord('0')) inc(i) - template eatUnderscores = while s[i] == '_': inc(i) - while s[i] in {'0'..'9'}: # Read integer part - buf.add s[i] + # Decimal? + if s[i] == '.': + var hd = 1.0 inc(i) - eatUnderscores() - if s[i] == '.': # Decimal? - addInc() - while s[i] in {'0'..'9'}: # Read fractional part - addInc() - eatUnderscores() - # Again, read integer and fractional part - if buf.len == ord(sign): return 0 - if s[i] in {'e', 'E'}: # Exponent? - addInc() - if s[i] == '+': inc(i) - elif s[i] == '-': addInc() - if s[i] notin {'0'..'9'}: return 0 while s[i] in {'0'..'9'}: - addInc() - eatUnderscores() - number = parseFloatNative(buf) - result = i + # Read fractional part + flags = flags or 2 + number = number * 10.0 + toFloat(ord(s[i]) - ord('0')) + hd = hd * 10.0 + inc(i) + while s[i] == '_': inc(i) + number = number / hd # this complicated way preserves precision + # Again, read integer and fractional part + if flags == 0: return 0 + # Exponent? + if s[i] in {'e', 'E'}: + inc(i) + if s[i] == '+': + inc(i) + elif s[i] == '-': + esign = -1.0 + inc(i) + if s[i] notin {'0'..'9'}: + return 0 + while s[i] in {'0'..'9'}: + exponent = exponent * 10 + ord(s[i]) - ord('0') + inc(i) + while s[i] == '_': inc(i) + # Calculate Exponent + let hd = tenToThePowerOf(exponent) + if esign > 0.0: number = number * hd + else: number = number / hd + # evaluate sign + number = number * sign + result = i - start + +when defined(nodejs): + # Deprecated. Use `alert` defined in dom.nim + proc alert*(s: cstring) {.importc: "console.log", nodecl, deprecated.} +else: + # Deprecated. Use `alert` defined in dom.nim + proc alert*(s: cstring) {.importc, nodecl, deprecated.} # Workaround for IE, IE up to version 11 lacks 'Math.trunc'. We produce # 'Math.trunc' for Nim's ``div`` and ``mod`` operators: -when defined(nimJsMathTruncPolyfill): - {.emit: """ +const jsMathTrunc = """ if (!Math.trunc) { Math.trunc = function(v) { v = +v; @@ -778,4 +766,5 @@ if (!Math.trunc) { return (v - v % 1) || (v < 0 ? -0 : v === 0 ? v : 0); }; } -""".} +""" +when not defined(nodejs): {.emit: jsMathTrunc .} diff --git a/lib/system/memalloc.nim b/lib/system/memalloc.nim index a94d0995c..df4df2c15 100644 --- a/lib/system/memalloc.nim +++ b/lib/system/memalloc.nim @@ -1,51 +1,38 @@ when notJSnotNims: proc zeroMem*(p: pointer, size: Natural) {.inline, noSideEffect, - tags: [], raises: [].} - ## Overwrites the contents of the memory at `p` with the value 0. + tags: [], locks: 0, raises: [].} + ## Overwrites the contents of the memory at ``p`` with the value 0. ## - ## Exactly `size` bytes will be overwritten. Like any procedure + ## Exactly ``size`` bytes will be overwritten. Like any procedure ## dealing with raw memory this is **unsafe**. proc copyMem*(dest, source: pointer, size: Natural) {.inline, benign, - tags: [], raises: [].} - ## Copies the contents from the memory at `source` to the memory - ## at `dest`. - ## Exactly `size` bytes will be copied. The memory + tags: [], locks: 0, raises: [].} + ## Copies the contents from the memory at ``source`` to the memory + ## at ``dest``. + ## Exactly ``size`` bytes will be copied. The memory ## regions may not overlap. Like any procedure dealing with raw ## memory this is **unsafe**. proc moveMem*(dest, source: pointer, size: Natural) {.inline, benign, - tags: [], raises: [].} - ## Copies the contents from the memory at `source` to the memory - ## at `dest`. + tags: [], locks: 0, raises: [].} + ## Copies the contents from the memory at ``source`` to the memory + ## at ``dest``. ## - ## Exactly `size` bytes will be copied. The memory - ## regions may overlap, `moveMem` handles this case appropriately - ## and is thus somewhat more safe than `copyMem`. Like any procedure + ## Exactly ``size`` bytes will be copied. The memory + ## regions may overlap, ``moveMem`` handles this case appropriately + ## and is thus somewhat more safe than ``copyMem``. Like any procedure ## dealing with raw memory this is still **unsafe**, though. proc equalMem*(a, b: pointer, size: Natural): bool {.inline, noSideEffect, - tags: [], raises: [].} - ## Compares the memory blocks `a` and `b`. `size` bytes will + tags: [], locks: 0, raises: [].} + ## Compares the memory blocks ``a`` and ``b``. ``size`` bytes will ## be compared. ## ## If the blocks are equal, `true` is returned, `false` ## otherwise. Like any procedure dealing with raw memory this is ## **unsafe**. - proc cmpMem*(a, b: pointer, size: Natural): int {.inline, noSideEffect, - tags: [], raises: [].} - ## Compares the memory blocks `a` and `b`. `size` bytes will - ## be compared. - ## - ## Returns: - ## * a value less than zero, if `a < b` - ## * a value greater than zero, if `a > b` - ## * zero, if `a == b` - ## - ## Like any procedure dealing with raw memory this is - ## **unsafe**. - when hasAlloc and not defined(js): proc allocImpl*(size: Natural): pointer {.noconv, rtl, tags: [], benign, raises: [].} @@ -80,7 +67,7 @@ when hasAlloc and not defined(js): when defined(nimAllocStats): var stats: AllocStats - template incStat(what: untyped) = atomicInc stats.what + template incStat(what: untyped) = inc stats.what proc getAllocStats*(): AllocStats = stats else: @@ -88,23 +75,23 @@ when hasAlloc and not defined(js): proc getAllocStats*(): AllocStats = discard template alloc*(size: Natural): pointer = - ## Allocates a new memory block with at least `size` bytes. + ## Allocates a new memory block with at least ``size`` bytes. ## - ## The block has to be freed with `realloc(block, 0) <#realloc.t,pointer,Natural>`_ + ## The block has to be freed with `realloc(block, 0) <#realloc,pointer,Natural>`_ ## or `dealloc(block) <#dealloc,pointer>`_. ## The block is not initialized, so reading ## from it before writing to it is undefined behaviour! ## ## The allocated memory belongs to its allocating thread! - ## Use `allocShared <#allocShared.t,Natural>`_ to allocate from a shared heap. + ## Use `allocShared <#allocShared,Natural>`_ to allocate from a shared heap. ## ## See also: - ## * `alloc0 <#alloc0.t,Natural>`_ + ## * `alloc0 <#alloc0,Natural>`_ incStat(allocCount) allocImpl(size) proc createU*(T: typedesc, size = 1.Positive): ptr T {.inline, benign, raises: [].} = - ## Allocates a new memory block with at least `T.sizeof * size` bytes. + ## Allocates a new memory block with at least ``T.sizeof * size`` bytes. ## ## The block has to be freed with `resize(block, 0) <#resize,ptr.T,Natural>`_ ## or `dealloc(block) <#dealloc,pointer>`_. @@ -119,20 +106,20 @@ when hasAlloc and not defined(js): cast[ptr T](alloc(T.sizeof * size)) template alloc0*(size: Natural): pointer = - ## Allocates a new memory block with at least `size` bytes. + ## Allocates a new memory block with at least ``size`` bytes. ## - ## The block has to be freed with `realloc(block, 0) <#realloc.t,pointer,Natural>`_ + ## The block has to be freed with `realloc(block, 0) <#realloc,pointer,Natural>`_ ## or `dealloc(block) <#dealloc,pointer>`_. ## The block is initialized with all bytes containing zero, so it is - ## somewhat safer than `alloc <#alloc.t,Natural>`_. + ## somewhat safer than `alloc <#alloc,Natural>`_. ## ## The allocated memory belongs to its allocating thread! - ## Use `allocShared0 <#allocShared0.t,Natural>`_ to allocate from a shared heap. + ## Use `allocShared0 <#allocShared0,Natural>`_ to allocate from a shared heap. incStat(allocCount) alloc0Impl(size) proc create*(T: typedesc, size = 1.Positive): ptr T {.inline, benign, raises: [].} = - ## Allocates a new memory block with at least `T.sizeof * size` bytes. + ## Allocates a new memory block with at least ``T.sizeof * size`` bytes. ## ## The block has to be freed with `resize(block, 0) <#resize,ptr.T,Natural>`_ ## or `dealloc(block) <#dealloc,pointer>`_. @@ -147,13 +134,13 @@ when hasAlloc and not defined(js): ## Grows or shrinks a given memory block. ## ## If `p` is **nil** then a new memory block is returned. - ## In either way the block has at least `newSize` bytes. - ## If `newSize == 0` and `p` is not **nil** `realloc` calls `dealloc(p)`. + ## In either way the block has at least ``newSize`` bytes. + ## If ``newSize == 0`` and `p` is not **nil** ``realloc`` calls ``dealloc(p)``. ## In other cases the block has to be freed with ## `dealloc(block) <#dealloc,pointer>`_. ## ## The allocated memory belongs to its allocating thread! - ## Use `reallocShared <#reallocShared.t,pointer,Natural>`_ to reallocate + ## Use `reallocShared <#reallocShared,pointer,Natural>`_ to reallocate ## from a shared heap. reallocImpl(p, newSize) @@ -161,8 +148,8 @@ when hasAlloc and not defined(js): ## Grows or shrinks a given memory block. ## ## If `p` is **nil** then a new memory block is returned. - ## In either way the block has at least `newSize` bytes. - ## If `newSize == 0` and `p` is not **nil** `realloc` calls `dealloc(p)`. + ## In either way the block has at least ``newSize`` bytes. + ## If ``newSize == 0`` and `p` is not **nil** ``realloc`` calls ``dealloc(p)``. ## In other cases the block has to be freed with ## `dealloc(block) <#dealloc,pointer>`_. ## @@ -170,7 +157,7 @@ when hasAlloc and not defined(js): ## somewhat safer then realloc ## ## The allocated memory belongs to its allocating thread! - ## Use `reallocShared <#reallocShared.t,pointer,Natural>`_ to reallocate + ## Use `reallocShared <#reallocShared,pointer,Natural>`_ to reallocate ## from a shared heap. realloc0Impl(p, oldSize, newSize) @@ -178,18 +165,18 @@ when hasAlloc and not defined(js): ## Grows or shrinks a given memory block. ## ## If `p` is **nil** then a new memory block is returned. - ## In either way the block has at least `T.sizeof * newSize` bytes. - ## If `newSize == 0` and `p` is not **nil** `resize` calls `dealloc(p)`. - ## In other cases the block has to be freed with `free`. + ## In either way the block has at least ``T.sizeof * newSize`` bytes. + ## If ``newSize == 0`` and `p` is not **nil** ``resize`` calls ``dealloc(p)``. + ## In other cases the block has to be freed with ``free``. ## ## The allocated memory belongs to its allocating thread! ## Use `resizeShared <#resizeShared,ptr.T,Natural>`_ to reallocate ## from a shared heap. cast[ptr T](realloc(p, T.sizeof * newSize)) - proc dealloc*(p: pointer) {.noconv, compilerproc, rtl, benign, raises: [], tags: [].} = - ## Frees the memory allocated with `alloc`, `alloc0`, - ## `realloc`, `create` or `createU`. + template dealloc*(p: pointer) = + ## Frees the memory allocated with ``alloc``, ``alloc0`` or + ## ``realloc``. ## ## **This procedure is dangerous!** ## If one forgets to free the memory a leak occurs; if one tries to @@ -203,24 +190,24 @@ when hasAlloc and not defined(js): template allocShared*(size: Natural): pointer = ## Allocates a new memory block on the shared heap with at - ## least `size` bytes. + ## least ``size`` bytes. ## ## The block has to be freed with - ## `reallocShared(block, 0) <#reallocShared.t,pointer,Natural>`_ + ## `reallocShared(block, 0) <#reallocShared,pointer,Natural>`_ ## or `deallocShared(block) <#deallocShared,pointer>`_. ## ## The block is not initialized, so reading from it before writing ## to it is undefined behaviour! ## ## See also: - ## * `allocShared0 <#allocShared0.t,Natural>`_. + ## `allocShared0 <#allocShared0,Natural>`_. incStat(allocCount) allocSharedImpl(size) proc createSharedU*(T: typedesc, size = 1.Positive): ptr T {.inline, tags: [], benign, raises: [].} = ## Allocates a new memory block on the shared heap with at - ## least `T.sizeof * size` bytes. + ## least ``T.sizeof * size`` bytes. ## ## The block has to be freed with ## `resizeShared(block, 0) <#resizeShared,ptr.T,Natural>`_ or @@ -235,21 +222,21 @@ when hasAlloc and not defined(js): template allocShared0*(size: Natural): pointer = ## Allocates a new memory block on the shared heap with at - ## least `size` bytes. + ## least ``size`` bytes. ## ## The block has to be freed with - ## `reallocShared(block, 0) <#reallocShared.t,pointer,Natural>`_ + ## `reallocShared(block, 0) <#reallocShared,pointer,Natural>`_ ## or `deallocShared(block) <#deallocShared,pointer>`_. ## ## The block is initialized with all bytes ## containing zero, so it is somewhat safer than - ## `allocShared <#allocShared.t,Natural>`_. + ## `allocShared <#allocShared,Natural>`_. incStat(allocCount) allocShared0Impl(size) proc createShared*(T: typedesc, size = 1.Positive): ptr T {.inline.} = ## Allocates a new memory block on the shared heap with at - ## least `T.sizeof * size` bytes. + ## least ``T.sizeof * size`` bytes. ## ## The block has to be freed with ## `resizeShared(block, 0) <#resizeShared,ptr.T,Natural>`_ or @@ -264,9 +251,9 @@ when hasAlloc and not defined(js): ## Grows or shrinks a given memory block on the heap. ## ## If `p` is **nil** then a new memory block is returned. - ## In either way the block has at least `newSize` bytes. - ## If `newSize == 0` and `p` is not **nil** `reallocShared` calls - ## `deallocShared(p)`. + ## In either way the block has at least ``newSize`` bytes. + ## If ``newSize == 0`` and `p` is not **nil** ``reallocShared`` calls + ## ``deallocShared(p)``. ## In other cases the block has to be freed with ## `deallocShared <#deallocShared,pointer>`_. reallocSharedImpl(p, newSize) @@ -278,9 +265,9 @@ when hasAlloc and not defined(js): ## containing zero, so it is somewhat safer then reallocShared ## ## If `p` is **nil** then a new memory block is returned. - ## In either way the block has at least `newSize` bytes. - ## If `newSize == 0` and `p` is not **nil** `reallocShared` calls - ## `deallocShared(p)`. + ## In either way the block has at least ``newSize`` bytes. + ## If ``newSize == 0`` and `p` is not **nil** ``reallocShared`` calls + ## ``deallocShared(p)``. ## In other cases the block has to be freed with ## `deallocShared <#deallocShared,pointer>`_. reallocShared0Impl(p, oldSize, newSize) @@ -289,16 +276,16 @@ when hasAlloc and not defined(js): ## Grows or shrinks a given memory block on the heap. ## ## If `p` is **nil** then a new memory block is returned. - ## In either way the block has at least `T.sizeof * newSize` bytes. - ## If `newSize == 0` and `p` is not **nil** `resizeShared` calls - ## `freeShared(p)`. + ## In either way the block has at least ``T.sizeof * newSize`` bytes. + ## If ``newSize == 0`` and `p` is not **nil** ``resizeShared`` calls + ## ``freeShared(p)``. ## In other cases the block has to be freed with ## `freeShared <#freeShared,ptr.T>`_. cast[ptr T](reallocShared(p, T.sizeof * newSize)) proc deallocShared*(p: pointer) {.noconv, compilerproc, rtl, benign, raises: [], tags: [].} = - ## Frees the memory allocated with `allocShared`, `allocShared0` or - ## `reallocShared`. + ## Frees the memory allocated with ``allocShared``, ``allocShared0`` or + ## ``reallocShared``. ## ## **This procedure is dangerous!** ## If one forgets to free the memory a leak occurs; if one tries to @@ -308,8 +295,8 @@ when hasAlloc and not defined(js): deallocSharedImpl(p) proc freeShared*[T](p: ptr T) {.inline, benign, raises: [].} = - ## Frees the memory allocated with `createShared`, `createSharedU` or - ## `resizeShared`. + ## Frees the memory allocated with ``createShared``, ``createSharedU`` or + ## ``resizeShared``. ## ## **This procedure is dangerous!** ## If one forgets to free the memory a leak occurs; if one tries to @@ -317,87 +304,6 @@ when hasAlloc and not defined(js): ## or other memory may be corrupted. deallocShared(p) - include bitmasks - - template `+!`(p: pointer, s: SomeInteger): pointer = - cast[pointer](cast[int](p) +% int(s)) - - template `-!`(p: pointer, s: SomeInteger): pointer = - cast[pointer](cast[int](p) -% int(s)) - - proc alignedAlloc(size, align: Natural): pointer = - if align <= MemAlign: - when compileOption("threads"): - result = allocShared(size) - else: - result = alloc(size) - else: - # allocate (size + align - 1) necessary for alignment, - # plus 2 bytes to store offset - when compileOption("threads"): - let base = allocShared(size + align - 1 + sizeof(uint16)) - else: - let base = alloc(size + align - 1 + sizeof(uint16)) - # memory layout: padding + offset (2 bytes) + user_data - # in order to deallocate: read offset at user_data - 2 bytes, - # then deallocate user_data - offset - let offset = align - (cast[int](base) and (align - 1)) - cast[ptr uint16](base +! (offset - sizeof(uint16)))[] = uint16(offset) - result = base +! offset - - proc alignedAlloc0(size, align: Natural): pointer = - if align <= MemAlign: - when compileOption("threads"): - result = allocShared0(size) - else: - result = alloc0(size) - else: - # see comments for alignedAlloc - when compileOption("threads"): - let base = allocShared0(size + align - 1 + sizeof(uint16)) - else: - let base = alloc0(size + align - 1 + sizeof(uint16)) - let offset = align - (cast[int](base) and (align - 1)) - cast[ptr uint16](base +! (offset - sizeof(uint16)))[] = uint16(offset) - result = base +! offset - - proc alignedDealloc(p: pointer, align: int) {.compilerproc.} = - if align <= MemAlign: - when compileOption("threads"): - deallocShared(p) - else: - dealloc(p) - else: - # read offset at p - 2 bytes, then deallocate (p - offset) pointer - let offset = cast[ptr uint16](p -! sizeof(uint16))[] - when compileOption("threads"): - deallocShared(p -! offset) - else: - dealloc(p -! offset) - - proc alignedRealloc(p: pointer, oldSize, newSize, align: Natural): pointer = - if align <= MemAlign: - when compileOption("threads"): - result = reallocShared(p, newSize) - else: - result = realloc(p, newSize) - else: - result = alignedAlloc(newSize, align) - copyMem(result, p, oldSize) - alignedDealloc(p, align) - - proc alignedRealloc0(p: pointer, oldSize, newSize, align: Natural): pointer = - if align <= MemAlign: - when compileOption("threads"): - result = reallocShared0(p, oldSize, newSize) - else: - result = realloc0(p, oldSize, newSize) - else: - result = alignedAlloc(newSize, align) - copyMem(result, p, oldSize) - zeroMem(result +! oldSize, newSize - oldSize) - alignedDealloc(p, align) - {.pop.} # GC interface: @@ -433,7 +339,7 @@ when defined(js): proc reallocShared0(p: pointer, oldsize, newsize: Natural): pointer = discard -when hasAlloc and hasThreadSupport and not defined(useMalloc): +when hasAlloc and hasThreadSupport: proc getOccupiedSharedMem*(): int {.rtl.} ## Returns the number of bytes that are owned by the process ## on the shared heap and hold data. This is only available when diff --git a/lib/system/memory.nim b/lib/system/memory.nim index ebda60d8d..8d190e5f9 100644 --- a/lib/system/memory.nim +++ b/lib/system/memory.nim @@ -2,6 +2,9 @@ const useLibC = not defined(nimNoLibc) +when not defined(nimHasHotCodeReloading): + {.pragma: nonReloadable.} + when useLibC: import ansi_c @@ -42,9 +45,9 @@ proc nimCmpMem*(a, b: pointer, size: Natural): cint {.compilerproc, nonReloadabl if d != 0: return d inc i -proc nimCStrLen*(a: cstring): int {.compilerproc, nonReloadable, inline.} = +proc nimCStrLen*(a: cstring): csize_t {.compilerproc, nonReloadable, inline.} = when useLibC: - cast[int](c_strlen(a)) + c_strlen(a) else: var a = cast[ptr byte](a) while a[] != 0: diff --git a/lib/system/memtracker.nim b/lib/system/memtracker.nim index 289f4e024..115d4a973 100644 --- a/lib/system/memtracker.nim +++ b/lib/system/memtracker.nim @@ -35,7 +35,7 @@ type count*: int disabled: bool data*: array[400, LogEntry] - TrackLogger* = proc (log: TrackLog) {.nimcall, tags: [], gcsafe.} + TrackLogger* = proc (log: TrackLog) {.nimcall, tags: [], locks: 0, gcsafe.} var gLog*: TrackLog @@ -70,9 +70,9 @@ proc addEntry(entry: LogEntry) = if interesting: gLog.disabled = true cprintf("interesting %s:%ld %s\n", entry.file, entry.line, entry.op) - let x = cast[proc() {.nimcall, tags: [], gcsafe, raises: [].}](writeStackTrace) + let x = cast[proc() {.nimcall, tags: [], gcsafe, locks: 0, raises: [].}](writeStackTrace) x() - rawQuit 1 + quit 1 #if gLog.count > high(gLog.data): # gLogger(gLog) # gLog.count = 0 @@ -85,7 +85,7 @@ proc memTrackerWrite(address: pointer; size: int; file: cstring; line: int) {.co size: size, file: file, line: line, thread: myThreadId()) proc memTrackerOp*(op: cstring; address: pointer; size: int) {.tags: [], - gcsafe.} = + locks: 0, gcsafe.} = addEntry LogEntry(op: op, address: address, size: size, file: "", line: 0, thread: myThreadId()) @@ -100,7 +100,6 @@ proc logPendingOps() {.noconv.} = gLogger(gLog) gLog.count = 0 -import std/exitprocs -addExitProc logPendingOps +addQuitProc logPendingOps {.pop.} diff --git a/lib/system/mm/boehm.nim b/lib/system/mm/boehm.nim index 362d2d470..d02d52b52 100644 --- a/lib/system/mm/boehm.nim +++ b/lib/system/mm/boehm.nim @@ -1,6 +1,4 @@ - - proc boehmGCinit {.importc: "GC_init", boehmGC.} proc boehmGC_disable {.importc: "GC_disable", boehmGC.} proc boehmGC_enable {.importc: "GC_enable", boehmGC.} @@ -53,14 +51,14 @@ when not defined(useNimRtl): proc realloc0Impl(p: pointer, oldSize, newSize: Natural): pointer = result = boehmRealloc(p, newSize) if result == nil: raiseOutOfMem() - if newSize > oldSize: - zeroMem(cast[pointer](cast[int](result) + oldSize), newSize - oldSize) + if newsize > oldsize: + zeroMem(cast[pointer](cast[int](result) + oldsize), newsize - oldsize) proc deallocImpl(p: pointer) = boehmDealloc(p) proc allocSharedImpl(size: Natural): pointer = allocImpl(size) proc allocShared0Impl(size: Natural): pointer = alloc0Impl(size) - proc reallocSharedImpl(p: pointer, newSize: Natural): pointer = reallocImpl(p, newSize) - proc reallocShared0Impl(p: pointer, oldSize, newSize: Natural): pointer = realloc0Impl(p, oldSize, newSize) + proc reallocSharedImpl(p: pointer, newsize: Natural): pointer = reallocImpl(p, newsize) + proc reallocShared0Impl(p: pointer, oldsize, newsize: Natural): pointer = realloc0Impl(p, oldsize, newsize) proc deallocSharedImpl(p: pointer) = deallocImpl(p) when hasThreadSupport: @@ -98,18 +96,15 @@ proc initGC() = proc boehmgc_finalizer(obj: pointer, typedFinalizer: (proc(x: pointer) {.cdecl.})) = typedFinalizer(obj) - proc newObj(typ: PNimType, size: int): pointer {.compilerproc.} = if ntfNoRefs in typ.flags: result = allocAtomic(size) else: result = alloc(size) if typ.finalizer != nil: boehmRegisterFinalizer(result, boehmgc_finalizer, typ.finalizer, nil, nil) -{.push overflowChecks: on.} proc newSeq(typ: PNimType, len: int): pointer {.compilerproc.} = - result = newObj(typ, align(GenericSeqSize, typ.base.align) + len * typ.base.size) + result = newObj(typ, addInt(mulInt(len, typ.base.size), GenericSeqSize)) cast[PGenericSeq](result).len = len cast[PGenericSeq](result).reserved = len -{.pop.} proc growObj(old: pointer, newsize: int): pointer = result = realloc(old, newsize) @@ -138,3 +133,4 @@ proc deallocOsPages(r: var MemRegion) {.inline.} = discard proc deallocOsPages() {.inline.} = discard include "system/cellsets" + diff --git a/lib/system/mm/go.nim b/lib/system/mm/go.nim index 9ec25fb65..8e8558bea 100644 --- a/lib/system/mm/go.nim +++ b/lib/system/mm/go.nim @@ -35,6 +35,8 @@ proc goMalloc(size: uint): pointer {.importc: "go_malloc", dynlib: goLib.} proc goSetFinalizer(obj: pointer, f: pointer) {.importc: "set_finalizer", codegenDecl:"$1 $2$3 __asm__ (\"main.Set_finalizer\");\n$1 $2$3", dynlib: goLib.} proc writebarrierptr(dest: PPointer, src: pointer) {.importc: "writebarrierptr", codegenDecl:"$1 $2$3 __asm__ (\"main.Atomic_store_pointer\");\n$1 $2$3", dynlib: goLib.} +proc `$`*(x: uint64): string {.noSideEffect, raises: [].} + proc GC_getStatistics(): string = var mstats = goMemStats() result = "[GC] total allocated memory: " & $(mstats.total_alloc) & "\n" & @@ -99,39 +101,35 @@ proc newObjNoInit(typ: PNimType, size: int): pointer = writebarrierptr(addr(result), newObj(typ, size)) proc newSeq(typ: PNimType, len: int): pointer {.compilerproc.} = - writebarrierptr(addr(result), newObj(typ, align(GenericSeqSize, typ.base.align) + len * typ.base.size)) + writebarrierptr(addr(result), newObj(typ, len * typ.base.size + GenericSeqSize)) cast[PGenericSeq](result).len = len cast[PGenericSeq](result).reserved = len cast[PGenericSeq](result).elemSize = typ.base.size - cast[PGenericSeq](result).elemAlign = typ.base.align proc newSeqRC1(typ: PNimType, len: int): pointer {.compilerRtl.} = writebarrierptr(addr(result), newSeq(typ, len)) proc nimNewSeqOfCap(typ: PNimType, cap: int): pointer {.compilerproc.} = - result = newObj(typ, align(GenericSeqSize, typ.base.align) + cap * typ.base.size) + result = newObj(typ, cap * typ.base.size + GenericSeqSize) cast[PGenericSeq](result).len = 0 cast[PGenericSeq](result).reserved = cap cast[PGenericSeq](result).elemSize = typ.base.size - cast[PGenericSeq](result).elemAlign = typ.base.align proc typedMemMove(dest: pointer, src: pointer, size: uint) {.importc: "typedmemmove", dynlib: goLib.} proc growObj(old: pointer, newsize: int): pointer = # the Go GC doesn't have a realloc - let old = cast[PGenericSeq](old) var metadataOld = cast[PGenericSeq](old) if metadataOld.elemSize == 0: metadataOld.elemSize = 1 - - let oldsize = align(GenericSeqSize, old.elemAlign) + old.len * old.elemSize + let oldsize = cast[PGenericSeq](old).len * cast[PGenericSeq](old).elemSize + GenericSeqSize writebarrierptr(addr(result), goMalloc(newsize.uint)) typedMemMove(result, old, oldsize.uint) proc nimGCref(p: pointer) {.compilerproc, inline.} = discard proc nimGCunref(p: pointer) {.compilerproc, inline.} = discard -proc nimGCunrefNoCycle(p: pointer) {.compilerproc, inline.} = discard -proc nimGCunrefRC1(p: pointer) {.compilerproc, inline.} = discard +proc nimGCunrefNoCycle(p: pointer) {.compilerProc, inline.} = discard +proc nimGCunrefRC1(p: pointer) {.compilerProc, inline.} = discard proc nimGCvisit(d: pointer, op: int) {.compilerRtl.} = discard proc unsureAsgnRef(dest: PPointer, src: pointer) {.compilerproc, inline.} = @@ -151,3 +149,4 @@ proc alloc0(r: var MemRegion, size: int): pointer = proc dealloc(r: var MemRegion, p: pointer) = dealloc(p) proc deallocOsPages(r: var MemRegion) {.inline.} = discard proc deallocOsPages() {.inline.} = discard + diff --git a/lib/system/mm/malloc.nim b/lib/system/mm/malloc.nim index d41dce705..27e32f87d 100644 --- a/lib/system/mm/malloc.nim +++ b/lib/system/mm/malloc.nim @@ -1,28 +1,17 @@ -{.push stackTrace: off.} - proc allocImpl(size: Natural): pointer = - result = c_malloc(size.csize_t) - when defined(zephyr): - if result == nil: - raiseOutOfMem() + c_malloc(size.csize_t) proc alloc0Impl(size: Natural): pointer = - result = c_calloc(size.csize_t, 1) - when defined(zephyr): - if result == nil: - raiseOutOfMem() + c_calloc(size.csize_t, 1) -proc reallocImpl(p: pointer, newSize: Natural): pointer = - result = c_realloc(p, newSize.csize_t) - when defined(zephyr): - if result == nil: - raiseOutOfMem() +proc reallocImpl(p: pointer, newsize: Natural): pointer = + c_realloc(p, newSize.csize_t) -proc realloc0Impl(p: pointer, oldsize, newSize: Natural): pointer = - result = realloc(p, newSize.csize_t) - if newSize > oldSize: - zeroMem(cast[pointer](cast[int](result) + oldSize), newSize - oldSize) +proc realloc0Impl(p: pointer, oldsize, newsize: Natural): pointer = + result = realloc(p, newsize.csize_t) + if newsize > oldsize: + zeroMem(cast[pointer](cast[int](result) + oldsize), newsize - oldsize) proc deallocImpl(p: pointer) = c_free(p) @@ -36,11 +25,11 @@ proc allocSharedImpl(size: Natural): pointer = proc allocShared0Impl(size: Natural): pointer = alloc0Impl(size) -proc reallocSharedImpl(p: pointer, newSize: Natural): pointer = - reallocImpl(p, newSize) +proc reallocSharedImpl(p: pointer, newsize: Natural): pointer = + reallocImpl(p, newsize) -proc reallocShared0Impl(p: pointer, oldsize, newSize: Natural): pointer = - realloc0Impl(p, oldSize, newSize) +proc reallocShared0Impl(p: pointer, oldsize, newsize: Natural): pointer = + realloc0Impl(p, oldsize, newsize) proc deallocSharedImpl(p: pointer) = deallocImpl(p) @@ -49,13 +38,10 @@ proc deallocSharedImpl(p: pointer) = deallocImpl(p) proc GC_disable() = discard proc GC_enable() = discard - -when not defined(gcOrc): - proc GC_fullCollect() = discard - proc GC_enableMarkAndSweep() = discard - proc GC_disableMarkAndSweep() = discard - +proc GC_fullCollect() = discard proc GC_setStrategy(strategy: GC_Strategy) = discard +proc GC_enableMarkAndSweep() = discard +proc GC_disableMarkAndSweep() = discard proc getOccupiedMem(): int = discard proc getFreeMem(): int = discard @@ -74,10 +60,8 @@ proc growObj(old: pointer, newsize: int): pointer = proc nimGCref(p: pointer) {.compilerproc, inline.} = discard proc nimGCunref(p: pointer) {.compilerproc, inline.} = discard -when not defined(gcDestructors): - proc unsureAsgnRef(dest: PPointer, src: pointer) {.compilerproc, inline.} = - dest[] = src - +proc unsureAsgnRef(dest: PPointer, src: pointer) {.compilerproc, inline.} = + dest[] = src proc asgnRef(dest: PPointer, src: pointer) {.compilerproc, inline.} = dest[] = src proc asgnRefNoCycle(dest: PPointer, src: pointer) {.compilerproc, inline, @@ -91,7 +75,6 @@ proc alloc(r: var MemRegion, size: int): pointer = proc alloc0Impl(r: var MemRegion, size: int): pointer = result = alloc0Impl(size) proc dealloc(r: var MemRegion, p: pointer) = dealloc(p) -proc deallocOsPages(r: var MemRegion) = discard -proc deallocOsPages() = discard +proc deallocOsPages(r: var MemRegion) {.inline.} = discard +proc deallocOsPages() {.inline.} = discard -{.pop.} diff --git a/lib/system/mm/none.nim b/lib/system/mm/none.nim index 7818a0805..3572b062c 100644 --- a/lib/system/mm/none.nim +++ b/lib/system/mm/none.nim @@ -19,12 +19,10 @@ proc newObj(typ: PNimType, size: int): pointer {.compilerproc.} = proc newObjNoInit(typ: PNimType, size: int): pointer = result = alloc(size) -{.push overflowChecks: on.} proc newSeq(typ: PNimType, len: int): pointer {.compilerproc.} = - result = newObj(typ, align(GenericSeqSize, typ.align) + len * typ.base.size) + result = newObj(typ, addInt(mulInt(len, typ.base.size), GenericSeqSize)) cast[PGenericSeq](result).len = len cast[PGenericSeq](result).reserved = len -{.pop.} proc growObj(old: pointer, newsize: int): pointer = result = realloc(old, newsize) diff --git a/lib/system/mmdisp.nim b/lib/system/mmdisp.nim index 26f2f0bbf..d2d0d576f 100644 --- a/lib/system/mmdisp.nim +++ b/lib/system/mmdisp.nim @@ -17,10 +17,10 @@ const debugGC = false # we wish to debug the GC... logGC = false traceGC = false # extensive debugging - alwaysCycleGC = defined(nimSmokeCycles) - alwaysGC = defined(nimFulldebug) # collect after every memory + alwaysCycleGC = defined(smokeCycles) + alwaysGC = defined(fulldebug) # collect after every memory # allocation (for debugging) - leakDetector = defined(nimLeakDetector) + leakDetector = defined(leakDetector) overwriteFree = defined(nimBurnFree) # overwrite memory with 0xFF before free trackAllocationSource = leakDetector @@ -30,7 +30,7 @@ const coalescRight = true coalescLeft = true logAlloc = false - useCellIds = defined(nimCorruption) + useCellIds = defined(corruption) type PPointer = ptr pointer @@ -38,15 +38,32 @@ type PByte = ptr ByteArray PString = ptr string -when declared(IntsPerTrunk): - discard -else: - include bitmasks +# Page size of the system; in most cases 4096 bytes. For exotic OS or +# CPU this needs to be changed: +const + PageShift = when defined(cpu16): 8 else: 12 # \ + # my tests showed no improvements for using larger page sizes. + PageSize = 1 shl PageShift + PageMask = PageSize-1 + + MemAlign = 8 # also minimal allocatable memory block + + BitsPerPage = PageSize div MemAlign + UnitsPerPage = BitsPerPage div (sizeof(int)*8) + # how many ints do we need to describe a page: + # on 32 bit systems this is only 16 (!) + + TrunkShift = 9 + BitsPerTrunk = 1 shl TrunkShift # needs to be power of 2 and divisible by 64 + TrunkMask = BitsPerTrunk - 1 + IntsPerTrunk = BitsPerTrunk div (sizeof(int)*8) + IntShift = 5 + ord(sizeof(int) == 8) # 5 or 6, depending on int width + IntMask = 1 shl IntShift - 1 proc raiseOutOfMem() {.noinline.} = if outOfMemHook != nil: outOfMemHook() cstderr.rawWrite("out of memory\n") - rawQuit(1) + quit(1) when defined(boehmgc): include system / mm / boehm @@ -57,16 +74,6 @@ elif defined(gogc): elif (defined(nogc) or defined(gcDestructors)) and defined(useMalloc): include system / mm / malloc - when defined(nogc): - proc GC_getStatistics(): string = "" - proc newObj(typ: PNimType, size: int): pointer {.compilerproc.} = - result = alloc0(size) - - proc newSeq(typ: PNimType, len: int): pointer {.compilerproc.} = - result = newObj(typ, align(GenericSeqSize, typ.align) + len * typ.base.size) - cast[PGenericSeq](result).len = len - cast[PGenericSeq](result).reserved = len - elif defined(nogc): include system / mm / none @@ -76,15 +83,16 @@ else: when not usesDestructors: include "system/cellsets" - when not leakDetector and not useCellIds and not defined(nimV2): + when not leakDetector and not useCellIds: sysAssert(sizeof(Cell) == sizeof(FreeCell), "sizeof FreeCell") - when defined(gcRegions): + when compileOption("gc", "v2"): + include "system/gc2" + elif defined(gcRegions): # XXX due to bootstrapping reasons, we cannot use compileOption("gc", "stack") here include "system/gc_regions" elif defined(nimV2) or usesDestructors: - when not defined(useNimRtl): - var allocator {.rtlThreadVar.}: MemRegion - instantiateForRegion(allocator) + var allocator {.rtlThreadVar.}: MemRegion + instantiateForRegion(allocator) when defined(gcHooks): include "system/gc_hooks" elif defined(gcMarkAndSweep): @@ -94,20 +102,18 @@ else: include "system/gc" when not declared(nimNewSeqOfCap) and not defined(nimSeqsV2): - {.push overflowChecks: on.} proc nimNewSeqOfCap(typ: PNimType, cap: int): pointer {.compilerproc.} = when defined(gcRegions): - let s = cap * typ.base.size # newStr already adds GenericSeqSize + let s = mulInt(cap, typ.base.size) # newStr already adds GenericSeqSize result = newStr(typ, s, ntfNoRefs notin typ.base.flags) else: - let s = align(GenericSeqSize, typ.base.align) + cap * typ.base.size + let s = addInt(mulInt(cap, typ.base.size), GenericSeqSize) when declared(newObjNoInit): result = if ntfNoRefs in typ.base.flags: newObjNoInit(typ, s) else: newObj(typ, s) else: result = newObj(typ, s) cast[PGenericSeq](result).len = 0 cast[PGenericSeq](result).reserved = cap - {.pop.} {.pop.} diff --git a/lib/system/nimscript.nim b/lib/system/nimscript.nim index 0b49ea2e7..719e92c4a 100644 --- a/lib/system/nimscript.nim +++ b/lib/system/nimscript.nim @@ -14,11 +14,11 @@ const buildOS* {.magic: "BuildOS".}: string = "" - ## The OS this build is running on. Can be different from `system.hostOS` + ## The OS this build is running on. Can be different from ``system.hostOS`` ## for cross compilations. buildCPU* {.magic: "BuildCPU".}: string = "" - ## The CPU this build is running on. Can be different from `system.hostCPU` + ## The CPU this build is running on. Can be different from ``system.hostCPU`` ## for cross compilations. template builtin = discard @@ -26,11 +26,14 @@ template builtin = discard # We know the effects better than the compiler: {.push hint[XDeclaredButNotUsed]: off.} -proc listDirsImpl(dir: string): seq[string] {. - tags: [ReadIOEffect], raises: [OSError].} = builtin -proc listFilesImpl(dir: string): seq[string] {. - tags: [ReadIOEffect], raises: [OSError].} = builtin -proc removeDir(dir: string, checkDir = true) {. +proc listDirs*(dir: string): seq[string] = + ## Lists all the subdirectories (non-recursively) in the directory `dir`. + builtin +proc listFiles*(dir: string): seq[string] = + ## Lists all the files (non-recursively) in the directory `dir`. + builtin + +proc removeDir(dir: string) {. tags: [ReadIOEffect, WriteIOEffect], raises: [OSError].} = builtin proc removeFile(dir: string) {. tags: [ReadIOEffect, WriteIOEffect], raises: [OSError].} = builtin @@ -44,7 +47,6 @@ proc copyDir(src, dest: string) {. tags: [ReadIOEffect, WriteIOEffect], raises: [OSError].} = builtin proc createDir(dir: string) {.tags: [WriteIOEffect], raises: [OSError].} = builtin - proc getError: string = builtin proc setCurrentDir(dir: string) = builtin proc getCurrentDir*(): string = @@ -57,7 +59,7 @@ proc warningImpl(arg, orig: string) = discard proc hintImpl(arg, orig: string) = discard proc paramStr*(i: int): string = - ## Retrieves the `i`'th command line parameter. + ## Retrieves the ``i``'th command line parameter. builtin proc paramCount*(): int = @@ -66,7 +68,7 @@ proc paramCount*(): int = proc switch*(key: string, val="") = ## Sets a Nim compiler command line switch, for - ## example `switch("checks", "on")`. + ## example ``switch("checks", "on")``. builtin proc warning*(name: string; val: bool) = @@ -82,9 +84,9 @@ proc hint*(name: string; val: bool) = proc patchFile*(package, filename, replacement: string) = ## Overrides the location of a given file belonging to the ## passed package. - ## If the `replacement` is not an absolute path, the path + ## If the ``replacement`` is not an absolute path, the path ## is interpreted to be local to the Nimscript file that contains - ## the call to `patchFile`, Nim's `--path` is not used at all + ## the call to ``patchFile``, Nim's ``--path`` is not used at all ## to resolve the filename! ## ## Example: @@ -112,19 +114,19 @@ proc cmpic*(a, b: string): int = cmpIgnoreCase(a, b) proc getEnv*(key: string; default = ""): string {.tags: [ReadIOEffect].} = - ## Retrieves the environment variable of name `key`. + ## Retrieves the environment variable of name ``key``. builtin proc existsEnv*(key: string): bool {.tags: [ReadIOEffect].} = - ## Checks for the existence of an environment variable named `key`. + ## Checks for the existence of an environment variable named ``key``. builtin proc putEnv*(key, val: string) {.tags: [WriteIOEffect].} = - ## Sets the value of the environment variable named `key` to `val`. + ## Sets the value of the environment variable named ``key`` to ``val``. builtin proc delEnv*(key: string) {.tags: [WriteIOEffect].} = - ## Deletes the environment variable named `key`. + ## Deletes the environment variable named ``key``. builtin proc fileExists*(filename: string): bool {.tags: [ReadIOEffect].} = @@ -136,8 +138,17 @@ proc dirExists*(dir: string): bool {. ## Checks if the directory `dir` exists. builtin -proc selfExe*(): string {.deprecated: "Deprecated since v1.7; Use getCurrentCompilerExe".} = +proc existsFile*(filename: string): bool = + ## An alias for ``fileExists``. + fileExists(filename) + +proc existsDir*(dir: string): bool = + ## An alias for ``dirExists``. + dirExists(dir) + +proc selfExe*(): string = ## Returns the currently running nim or nimble executable. + # TODO: consider making this as deprecated alias of `getCurrentCompilerExe` builtin proc toExe*(filename: string): string = @@ -150,29 +161,16 @@ proc toDll*(filename: string): string = proc strip(s: string): string = var i = 0 - while s[i] in {' ', '\c', '\n'}: inc i + while s[i] in {' ', '\c', '\L'}: inc i result = s.substr(i) - if result[0] == '"' and result[^1] == '"': - result = result[1..^2] template `--`*(key, val: untyped) = - ## A shortcut for `switch <#switch,string,string>`_ - ## Example: - ## - ## .. code-block:: nim - ## - ## --path:somePath # same as switch("path", "somePath") - ## --path:"someOtherPath" # same as switch("path", "someOtherPath") - switch(strip(astToStr(key)), strip(astToStr(val))) + ## A shortcut for ``switch(astToStr(key), astToStr(val))``. + switch(astToStr(key), strip astToStr(val)) template `--`*(key: untyped) = - ## A shortcut for `switch <#switch,string,string>`_ - ## Example: - ## - ## .. code-block:: nim - ## - ## --listCmd # same as switch("listCmd") - switch(strip(astToStr(key))) + ## A shortcut for ``switch(astToStr(key)``. + switch(astToStr(key), "") type ScriptMode* {.pure.} = enum ## Controls the behaviour of the script. @@ -195,23 +193,13 @@ template checkOsError = template log(msg: string, body: untyped) = if mode in {ScriptMode.Verbose, ScriptMode.Whatif}: echo "[NimScript] ", msg - if mode != ScriptMode.Whatif: + if mode != ScriptMode.WhatIf: body -proc listDirs*(dir: string): seq[string] = - ## Lists all the subdirectories (non-recursively) in the directory `dir`. - result = listDirsImpl(dir) - checkOsError() - -proc listFiles*(dir: string): seq[string] = - ## Lists all the files (non-recursively) in the directory `dir`. - result = listFilesImpl(dir) - checkOsError() - -proc rmDir*(dir: string, checkDir = false) {.raises: [OSError].} = +proc rmDir*(dir: string) {.raises: [OSError].} = ## Removes the directory `dir`. log "rmDir: " & dir: - removeDir(dir, checkDir = checkDir) + removeDir dir checkOsError() proc rmFile*(file: string) {.raises: [OSError].} = @@ -252,11 +240,11 @@ proc cpDir*(`from`, to: string) {.raises: [OSError].} = checkOsError() proc exec*(command: string) {. - raises: [OSError], tags: [ExecIOEffect, WriteIOEffect].} = + raises: [OSError], tags: [ExecIOEffect].} = ## Executes an external process. If the external process terminates with ## a non-zero exit code, an OSError exception is raised. ## - ## **Note:** If you need a version of `exec` that returns the exit code + ## **Note:** If you need a version of ``exec`` that returns the exit code ## and text output of the command, you can use `system.gorgeEx ## `_. log "exec: " & command: @@ -265,7 +253,7 @@ proc exec*(command: string) {. checkOsError() proc exec*(command: string, input: string, cache = "") {. - raises: [OSError], tags: [ExecIOEffect, WriteIOEffect].} = + raises: [OSError], tags: [ExecIOEffect].} = ## Executes an external process. If the external process terminates with ## a non-zero exit code, an OSError exception is raised. log "exec: " & command: @@ -275,9 +263,9 @@ proc exec*(command: string, input: string, cache = "") {. echo output proc selfExec*(command: string) {. - raises: [OSError], tags: [ExecIOEffect, WriteIOEffect].} = + raises: [OSError], tags: [ExecIOEffect].} = ## Executes an external command with the current nim/nimble executable. - ## `Command` must not contain the "nim " part. + ## ``Command`` must not contain the "nim " part. let c = selfExe() & " " & command log "exec: " & c: if rawExec(c) != 0: @@ -314,9 +302,9 @@ proc projectPath*(): string = builtin proc thisDir*(): string = - ## Retrieves the directory of the current `nims` script file. Its path is - ## obtained via `currentSourcePath` (although, currently, - ## `currentSourcePath` resolves symlinks, unlike `thisDir`). + ## Retrieves the directory of the current ``nims`` script file. Its path is + ## obtained via ``currentSourcePath`` (although, currently, + ## ``currentSourcePath`` resolves symlinks, unlike ``thisDir``). builtin proc cd*(dir: string) {.raises: [OSError].} = @@ -342,17 +330,17 @@ template withDir*(dir: string; body: untyped): untyped = ## Usage example: ## ## .. code-block:: nim - ## # inside /some/path/ ## withDir "foo": - ## # move to /some/path/foo/ - ## # back in /some/path/ - let curDir = getCurrentDir() + ## # inside foo + ## #back to last dir + var curDir = getCurrentDir() try: cd(dir) body finally: cd(curDir) + proc writeTask(name, desc: string) = if desc.len > 0: var spaces = " " @@ -360,25 +348,25 @@ proc writeTask(name, desc: string) = echo name, spaces, desc proc cppDefine*(define: string) = - ## tell Nim that `define` is a C preprocessor `#define` and so always + ## tell Nim that ``define`` is a C preprocessor ``#define`` and so always ## needs to be mangled. builtin -proc stdinReadLine(): string {. +proc stdinReadLine(): TaintedString {. tags: [ReadIOEffect], raises: [IOError].} = builtin -proc stdinReadAll(): string {. +proc stdinReadAll(): TaintedString {. tags: [ReadIOEffect], raises: [IOError].} = builtin -proc readLineFromStdin*(): string {.raises: [IOError].} = +proc readLineFromStdin*(): TaintedString {.raises: [IOError].} = ## Reads a line of data from stdin - blocks until \n or EOF which happens when stdin is closed log "readLineFromStdin": result = stdinReadLine() checkError(EOFError) -proc readAllFromStdin*(): string {.raises: [IOError].} = +proc readAllFromStdin*(): TaintedString {.raises: [IOError].} = ## Reads all data from stdin - blocks until EOF which happens when stdin is closed log "readAllFromStdin": result = stdinReadAll() @@ -388,26 +376,11 @@ when not defined(nimble): template `==?`(a, b: string): bool = cmpIgnoreStyle(a, b) == 0 template task*(name: untyped; description: string; body: untyped): untyped = ## Defines a task. Hidden tasks are supported via an empty description. - ## ## Example: ## ## .. code-block:: nim ## task build, "default build is via the C backend": ## setCommand "c" - ## - ## For a task named `foo`, this template generates a `proc` named - ## `fooTask`. This is useful if you need to call one task in - ## another in your Nimscript. - ## - ## Example: - ## - ## .. code-block:: nim - ## task foo, "foo": # > nim foo - ## echo "Running foo" # Running foo - ## - ## task bar, "bar": # > nim bar - ## echo "Running bar" # Running bar - ## fooTask() # Running foo proc `name Task`*() = setCommand "nop" body diff --git a/lib/system/orc.nim b/lib/system/orc.nim deleted file mode 100644 index a56a0c057..000000000 --- a/lib/system/orc.nim +++ /dev/null @@ -1,510 +0,0 @@ -# -# -# Nim's Runtime Library -# (c) Copyright 2020 Andreas Rumpf -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# - -# Cycle collector based on -# https://www.cs.purdue.edu/homes/hosking/690M/Bacon01Concurrent.pdf -# And ideas from Lins' in 2008 by the notion of "critical links", see -# "Cyclic reference counting" by Rafael Dueire Lins -# R.D. Lins / Information Processing Letters 109 (2008) 71–78 -# - -include cellseqs_v2 - -const - colBlack = 0b000 - colGray = 0b001 - colWhite = 0b010 - maybeCycle = 0b100 # possibly part of a cycle; this has to be a "sticky" bit - jumpStackFlag = 0b1000 - colorMask = 0b011 - - logOrc = defined(nimArcIds) - -type - TraceProc = proc (p, env: pointer) {.nimcall, benign.} - DisposeProc = proc (p: pointer) {.nimcall, benign.} - -template color(c): untyped = c.rc and colorMask -template setColor(c, col) = - when col == colBlack: - c.rc = c.rc and not colorMask - else: - c.rc = c.rc and not colorMask or col - -const - optimizedOrc = false # not defined(nimOldOrc) -# XXX Still incorrect, see tests/arc/tdestroy_in_loopcond - -proc nimIncRefCyclic(p: pointer; cyclic: bool) {.compilerRtl, inl.} = - let h = head(p) - inc h.rc, rcIncrement - when optimizedOrc: - if cyclic: - h.rc = h.rc or maybeCycle - -proc nimMarkCyclic(p: pointer) {.compilerRtl, inl.} = - when optimizedOrc: - if p != nil: - let h = head(p) - h.rc = h.rc or maybeCycle - -proc unsureAsgnRef(dest: ptr pointer, src: pointer) {.inline.} = - # This is only used by the old RTTI mechanism and we know - # that 'dest[]' is nil and needs no destruction. Which is really handy - # as we cannot destroy the object reliably if it's an object of unknown - # compile-time type. - dest[] = src - if src != nil: nimIncRefCyclic(src, true) - -const - useJumpStack = false # for thavlak the jump stack doesn't improve the performance at all - -type - GcEnv = object - traceStack: CellSeq[ptr pointer] - when useJumpStack: - jumpStack: CellSeq[ptr pointer] # Lins' jump stack in order to speed up traversals - toFree: CellSeq[Cell] - freed, touched, edges, rcSum: int - keepThreshold: bool - -proc trace(s: Cell; desc: PNimTypeV2; j: var GcEnv) {.inline.} = - if desc.traceImpl != nil: - var p = s +! sizeof(RefHeader) - cast[TraceProc](desc.traceImpl)(p, addr(j)) - -include threadids - -when logOrc: - proc writeCell(msg: cstring; s: Cell; desc: PNimTypeV2) = - cfprintf(cstderr, "%s %s %ld root index: %ld; RC: %ld; color: %ld; thread: %ld\n", - msg, desc.name, s.refId, s.rootIdx, s.rc shr rcShift, s.color, getThreadId()) - -proc free(s: Cell; desc: PNimTypeV2) {.inline.} = - when traceCollector: - cprintf("[From ] %p rc %ld color %ld\n", s, s.rc shr rcShift, s.color) - let p = s +! sizeof(RefHeader) - - when logOrc: writeCell("free", s, desc) - - if desc.destructor != nil: - cast[DestructorProc](desc.destructor)(p) - - when false: - cstderr.rawWrite desc.name - cstderr.rawWrite " " - if desc.destructor == nil: - cstderr.rawWrite "lacks dispose" - if desc.traceImpl != nil: - cstderr.rawWrite ", but has trace\n" - else: - cstderr.rawWrite ", and lacks trace\n" - else: - cstderr.rawWrite "has dispose!\n" - - nimRawDispose(p, desc.align) - -template orcAssert(cond, msg) = - when logOrc: - if not cond: - cfprintf(cstderr, "[Bug!] %s\n", msg) - rawQuit 1 - -when logOrc: - proc strstr(s, sub: cstring): cstring {.header: "", importc.} - -proc nimTraceRef(q: pointer; desc: PNimTypeV2; env: pointer) {.compilerRtl, inl.} = - let p = cast[ptr pointer](q) - if p[] != nil: - - orcAssert strstr(desc.name, "TType") == nil, "following a TType but it's acyclic!" - - var j = cast[ptr GcEnv](env) - j.traceStack.add(p, desc) - -proc nimTraceRefDyn(q: pointer; env: pointer) {.compilerRtl, inl.} = - let p = cast[ptr pointer](q) - if p[] != nil: - var j = cast[ptr GcEnv](env) - j.traceStack.add(p, cast[ptr PNimTypeV2](p[])[]) - -var - roots {.threadvar.}: CellSeq[Cell] - -proc unregisterCycle(s: Cell) = - # swap with the last element. O(1) - let idx = s.rootIdx-1 - when false: - if idx >= roots.len or idx < 0: - cprintf("[Bug!] %ld\n", idx) - rawQuit 1 - roots.d[idx] = roots.d[roots.len-1] - roots.d[idx][0].rootIdx = idx+1 - dec roots.len - s.rootIdx = 0 - -proc scanBlack(s: Cell; desc: PNimTypeV2; j: var GcEnv) = - #[ - proc scanBlack(s: Cell) = - setColor(s, colBlack) - for t in sons(s): - t.rc = t.rc + rcIncrement - if t.color != colBlack: - scanBlack(t) - ]# - s.setColor colBlack - let until = j.traceStack.len - trace(s, desc, j) - when logOrc: writeCell("root still alive", s, desc) - while j.traceStack.len > until: - let (entry, desc) = j.traceStack.pop() - let t = head entry[] - inc t.rc, rcIncrement - if t.color != colBlack: - t.setColor colBlack - trace(t, desc, j) - when logOrc: writeCell("child still alive", t, desc) - -proc markGray(s: Cell; desc: PNimTypeV2; j: var GcEnv) = - #[ - proc markGray(s: Cell) = - if s.color != colGray: - setColor(s, colGray) - for t in sons(s): - t.rc = t.rc - rcIncrement - if t.color != colGray: - markGray(t) - ]# - if s.color != colGray: - s.setColor colGray - inc j.touched - # keep in mind that refcounts are zero based so add 1 here: - inc j.rcSum, (s.rc shr rcShift) + 1 - orcAssert(j.traceStack.len == 0, "markGray: trace stack not empty") - trace(s, desc, j) - while j.traceStack.len > 0: - let (entry, desc) = j.traceStack.pop() - let t = head entry[] - dec t.rc, rcIncrement - inc j.edges - when useJumpStack: - if (t.rc shr rcShift) >= 0 and (t.rc and jumpStackFlag) == 0: - t.rc = t.rc or jumpStackFlag - when traceCollector: - cprintf("[Now in jumpstack] %p %ld color %ld in jumpstack %ld\n", t, t.rc shr rcShift, t.color, t.rc and jumpStackFlag) - j.jumpStack.add(entry, desc) - if t.color != colGray: - t.setColor colGray - inc j.touched - # we already decremented its refcount so account for that: - inc j.rcSum, (t.rc shr rcShift) + 2 - trace(t, desc, j) - -proc scan(s: Cell; desc: PNimTypeV2; j: var GcEnv) = - #[ - proc scan(s: Cell) = - if s.color == colGray: - if s.rc > 0: - scanBlack(s) - else: - s.setColor(colWhite) - for t in sons(s): scan(t) - ]# - if s.color == colGray: - if (s.rc shr rcShift) >= 0: - scanBlack(s, desc, j) - # XXX this should be done according to Lins' paper but currently breaks - #when useJumpStack: - # s.setColor colPurple - else: - when useJumpStack: - # first we have to repair all the nodes we have seen - # that are still alive; we also need to mark what they - # refer to as alive: - while j.jumpStack.len > 0: - let (entry, desc) = j.jumpStack.pop - let t = head entry[] - # not in jump stack anymore! - t.rc = t.rc and not jumpStackFlag - if t.color == colGray and (t.rc shr rcShift) >= 0: - scanBlack(t, desc, j) - # XXX this should be done according to Lins' paper but currently breaks - #t.setColor colPurple - when traceCollector: - cprintf("[jump stack] %p %ld\n", t, t.rc shr rcShift) - - orcAssert(j.traceStack.len == 0, "scan: trace stack not empty") - s.setColor(colWhite) - trace(s, desc, j) - while j.traceStack.len > 0: - let (entry, desc) = j.traceStack.pop() - let t = head entry[] - if t.color == colGray: - if (t.rc shr rcShift) >= 0: - scanBlack(t, desc, j) - else: - when useJumpStack: - # first we have to repair all the nodes we have seen - # that are still alive; we also need to mark what they - # refer to as alive: - while j.jumpStack.len > 0: - let (entry, desc) = j.jumpStack.pop - let t = head entry[] - # not in jump stack anymore! - t.rc = t.rc and not jumpStackFlag - if t.color == colGray and (t.rc shr rcShift) >= 0: - scanBlack(t, desc, j) - # XXX this should be done according to Lins' paper but currently breaks - #t.setColor colPurple - when traceCollector: - cprintf("[jump stack] %p %ld\n", t, t.rc shr rcShift) - - t.setColor(colWhite) - trace(t, desc, j) - -when false: - proc writeCell(msg: cstring; s: Cell) = - cfprintf(cstderr, "%s %p root index: %ld; RC: %ld; color: %ld\n", - msg, s, s.rootIdx, s.rc shr rcShift, s.color) - -proc collectColor(s: Cell; desc: PNimTypeV2; col: int; j: var GcEnv) = - #[ - was: 'collectWhite'. - - proc collectWhite(s: Cell) = - if s.color == colWhite and not buffered(s): - s.setColor(colBlack) - for t in sons(s): - collectWhite(t) - free(s) # watch out, a bug here! - ]# - if s.color == col and s.rootIdx == 0: - orcAssert(j.traceStack.len == 0, "collectWhite: trace stack not empty") - - s.setColor(colBlack) - j.toFree.add(s, desc) - trace(s, desc, j) - while j.traceStack.len > 0: - let (entry, desc) = j.traceStack.pop() - let t = head entry[] - entry[] = nil # ensure that the destructor does touch moribund objects! - if t.color == col and t.rootIdx == 0: - j.toFree.add(t, desc) - t.setColor(colBlack) - trace(t, desc, j) - -proc collectCyclesBacon(j: var GcEnv; lowMark: int) = - # pretty direct translation from - # https://researcher.watson.ibm.com/researcher/files/us-bacon/Bacon01Concurrent.pdf - # Fig. 2. Synchronous Cycle Collection - #[ - for s in roots: - markGray(s) - for s in roots: - scan(s) - for s in roots: - remove s from roots - s.buffered = false - collectWhite(s) - ]# - let last = roots.len - 1 - when logOrc: - for i in countdown(last, lowMark): - writeCell("root", roots.d[i][0], roots.d[i][1]) - - for i in countdown(last, lowMark): - markGray(roots.d[i][0], roots.d[i][1], j) - - var colToCollect = colWhite - if j.rcSum == j.edges: - # short-cut: we know everything is garbage: - colToCollect = colGray - # remember the fact that we got so lucky: - j.keepThreshold = true - else: - for i in countdown(last, lowMark): - scan(roots.d[i][0], roots.d[i][1], j) - - init j.toFree - for i in 0 ..< roots.len: - let s = roots.d[i][0] - s.rootIdx = 0 - collectColor(s, roots.d[i][1], colToCollect, j) - - for i in 0 ..< j.toFree.len: - free(j.toFree.d[i][0], j.toFree.d[i][1]) - - inc j.freed, j.toFree.len - deinit j.toFree - #roots.len = 0 - -const - defaultThreshold = when defined(nimFixedOrc): 10_000 else: 128 - -when defined(nimStressOrc): - const rootsThreshold = 10 # broken with -d:nimStressOrc: 10 and for havlak iterations 1..8 -else: - var rootsThreshold = defaultThreshold - -proc partialCollect(lowMark: int) = - when false: - if roots.len < 10 + lowMark: return - when logOrc: - cfprintf(cstderr, "[partialCollect] begin\n") - var j: GcEnv - init j.traceStack - collectCyclesBacon(j, lowMark) - when logOrc: - cfprintf(cstderr, "[partialCollect] end; freed %ld touched: %ld work: %ld\n", j.freed, j.touched, - roots.len - lowMark) - roots.len = lowMark - deinit j.traceStack - -proc collectCycles() = - ## Collect cycles. - when logOrc: - cfprintf(cstderr, "[collectCycles] begin\n") - - var j: GcEnv - init j.traceStack - when useJumpStack: - init j.jumpStack - collectCyclesBacon(j, 0) - while j.jumpStack.len > 0: - let (t, desc) = j.jumpStack.pop - # not in jump stack anymore! - t.rc = t.rc and not jumpStackFlag - deinit j.jumpStack - else: - collectCyclesBacon(j, 0) - - deinit j.traceStack - deinit roots - - when not defined(nimStressOrc): - # compute the threshold based on the previous history - # of the cycle collector's effectiveness: - # we're effective when we collected 50% or more of the nodes - # we touched. If we're effective, we can reset the threshold: - if j.keepThreshold and rootsThreshold <= defaultThreshold: - discard - elif j.freed * 2 >= j.touched: - when not defined(nimFixedOrc): - rootsThreshold = max(rootsThreshold div 3 * 2, 16) - else: - rootsThreshold = defaultThreshold - #cfprintf(cstderr, "[collectCycles] freed %ld, touched %ld new threshold %ld\n", j.freed, j.touched, rootsThreshold) - elif rootsThreshold < high(int) div 4: - rootsThreshold = rootsThreshold * 3 div 2 - when logOrc: - cfprintf(cstderr, "[collectCycles] end; freed %ld new threshold %ld touched: %ld mem: %ld rcSum: %ld edges: %ld\n", j.freed, rootsThreshold, j.touched, - getOccupiedMem(), j.rcSum, j.edges) - -proc registerCycle(s: Cell; desc: PNimTypeV2) = - s.rootIdx = roots.len+1 - if roots.d == nil: init(roots) - add(roots, s, desc) - - if roots.len >= rootsThreshold: - collectCycles() - when logOrc: - writeCell("[added root]", s, desc) - - orcAssert strstr(desc.name, "TType") == nil, "added a TType as a root!" - -proc GC_runOrc* = - ## Forces a cycle collection pass. - collectCycles() - orcAssert roots.len == 0, "roots not empty!" - -proc GC_enableOrc*() = - ## Enables the cycle collector subsystem of `--gc:orc`. This is a `--gc:orc` - ## specific API. Check with `when defined(gcOrc)` for its existence. - when not defined(nimStressOrc): - rootsThreshold = defaultThreshold - -proc GC_disableOrc*() = - ## Disables the cycle collector subsystem of `--gc:orc`. This is a `--gc:orc` - ## specific API. Check with `when defined(gcOrc)` for its existence. - when not defined(nimStressOrc): - rootsThreshold = high(int) - -proc GC_prepareOrc*(): int {.inline.} = roots.len - -proc GC_partialCollect*(limit: int) = - partialCollect(limit) - -proc GC_fullCollect* = - ## Forces a full garbage collection pass. With `--gc:orc` triggers the cycle - ## collector. This is an alias for `GC_runOrc`. - collectCycles() - -proc GC_enableMarkAndSweep*() = - ## For `--gc:orc` an alias for `GC_enableOrc`. - GC_enableOrc() - -proc GC_disableMarkAndSweep*() = - ## For `--gc:orc` an alias for `GC_disableOrc`. - GC_disableOrc() - -const - acyclicFlag = 1 # see also cggtypes.nim, proc genTypeInfoV2Impl - -when optimizedOrc: - template markedAsCyclic(s: Cell; desc: PNimTypeV2): bool = - (desc.flags and acyclicFlag) == 0 and (s.rc and maybeCycle) != 0 -else: - template markedAsCyclic(s: Cell; desc: PNimTypeV2): bool = - (desc.flags and acyclicFlag) == 0 - -proc rememberCycle(isDestroyAction: bool; s: Cell; desc: PNimTypeV2) {.noinline.} = - if isDestroyAction: - if s.rootIdx > 0: - unregisterCycle(s) - else: - # do not call 'rememberCycle' again unless this cell - # got an 'incRef' event: - if s.rootIdx == 0 and markedAsCyclic(s, desc): - s.setColor colBlack - registerCycle(s, desc) - -proc nimDecRefIsLastCyclicDyn(p: pointer): bool {.compilerRtl, inl.} = - if p != nil: - var cell = head(p) - if (cell.rc and not rcMask) == 0: - result = true - #cprintf("[DESTROY] %p\n", p) - else: - dec cell.rc, rcIncrement - #if cell.color == colPurple: - rememberCycle(result, cell, cast[ptr PNimTypeV2](p)[]) - -proc nimDecRefIsLastDyn(p: pointer): bool {.compilerRtl, inl.} = - if p != nil: - var cell = head(p) - if (cell.rc and not rcMask) == 0: - result = true - #cprintf("[DESTROY] %p\n", p) - else: - dec cell.rc, rcIncrement - #if cell.color == colPurple: - if result: - if cell.rootIdx > 0: - unregisterCycle(cell) - -proc nimDecRefIsLastCyclicStatic(p: pointer; desc: PNimTypeV2): bool {.compilerRtl, inl.} = - if p != nil: - var cell = head(p) - if (cell.rc and not rcMask) == 0: - result = true - #cprintf("[DESTROY] %p %s\n", p, desc.name) - else: - dec cell.rc, rcIncrement - #if cell.color == colPurple: - rememberCycle(result, cell, desc) diff --git a/lib/system/osalloc.nim b/lib/system/osalloc.nim index 925e98ed3..aa86ee379 100644 --- a/lib/system/osalloc.nim +++ b/lib/system/osalloc.nim @@ -28,30 +28,7 @@ const doNotUnmap = not (defined(amd64) or defined(i386)) or defined(windows) or defined(nimAllocNoUnmap) -when defined(nimAllocPagesViaMalloc): - when not defined(gcArc) and not defined(gcOrc): - {.error: "-d:nimAllocPagesViaMalloc is only supported with --gc:arc or --gc:orc".} - - proc osTryAllocPages(size: int): pointer {.inline.} = - let base = c_malloc(csize_t size + PageSize - 1 + sizeof(uint32)) - if base == nil: raiseOutOfMem() - # memory layout: padding + offset (4 bytes) + user_data - # in order to deallocate: read offset at user_data - 4 bytes, - # then deallocate user_data - offset - let offset = PageSize - (cast[int](base) and (PageSize - 1)) - cast[ptr uint32](base +! (offset - sizeof(uint32)))[] = uint32(offset) - result = base +! offset - - proc osAllocPages(size: int): pointer {.inline.} = - result = osTryAllocPages(size) - if result == nil: raiseOutOfMem() - - proc osDeallocPages(p: pointer, size: int) {.inline.} = - # read offset at p - 4 bytes, then deallocate (p - offset) pointer - let offset = cast[ptr uint32](p -! sizeof(uint32))[] - c_free(p -! offset) - -elif defined(emscripten) and not defined(StandaloneHeapSize): +when defined(emscripten) and not defined(StandaloneHeapSize): const PROT_READ = 1 # page can be read PROT_WRITE = 2 # page can be written @@ -80,12 +57,12 @@ elif defined(emscripten) and not defined(StandaloneHeapSize): let pos = cast[int](result) # Convert pointer to PageSize correct one. - var new_pos = cast[int](pos) +% (PageSize - (pos %% PageSize)) + var new_pos = cast[ByteAddress](pos) +% (PageSize - (pos %% PageSize)) if (new_pos-pos) < sizeof(EmscriptenMMapBlock): new_pos = new_pos +% PageSize result = cast[pointer](new_pos) - var mmapDescrPos = cast[int](result) -% sizeof(EmscriptenMMapBlock) + var mmapDescrPos = cast[ByteAddress](result) -% sizeof(EmscriptenMMapBlock) var mmapDescr = cast[EmscriptenMMapBlock](mmapDescrPos) mmapDescr.realSize = realSize @@ -96,25 +73,130 @@ elif defined(emscripten) and not defined(StandaloneHeapSize): proc osTryAllocPages(size: int): pointer = osAllocPages(size) proc osDeallocPages(p: pointer, size: int) {.inline.} = - var mmapDescrPos = cast[int](p) -% sizeof(EmscriptenMMapBlock) + var mmapDescrPos = cast[ByteAddress](p) -% sizeof(EmscriptenMMapBlock) var mmapDescr = cast[EmscriptenMMapBlock](mmapDescrPos) munmap(mmapDescr.realPointer, mmapDescr.realSize) elif defined(genode) and not defined(StandaloneHeapSize): include genode/alloc # osAllocPages, osTryAllocPages, osDeallocPages +elif defined(nintendoswitch) and not defined(StandaloneHeapSize): + + import nintendoswitch/switch_memory + + type + PSwitchBlock = ptr NSwitchBlock + ## This will hold the heap pointer data in a separate + ## block of memory that is PageSize bytes above + ## the requested memory. It's the only good way + ## to pass around data with heap allocations + NSwitchBlock {.pure, inheritable.} = object + realSize: int + heap: pointer # pointer to main heap alloc + heapMirror: pointer # pointer to virtmem mapped heap + + proc alignSize(size: int): int {.inline.} = + ## Align a size integer to be in multiples of PageSize + ## The nintendo switch will not allocate memory that is not + ## aligned to 0x1000 bytes and will just crash. + (size + (PageSize - 1)) and not (PageSize - 1) + + proc deallocate(heapMirror: pointer, heap: pointer, size: int) = + # Unmap the allocated memory + discard svcUnmapMemory(heapMirror, heap, size.uint64) + # These should be called (theoretically), but referencing them crashes the switch. + # The above call seems to free all heap memory, so these are not needed. + # virtmemFreeMap(nswitchBlock.heapMirror, nswitchBlock.realSize.csize) + # free(nswitchBlock.heap) + + proc freeMem(p: pointer) = + # Retrieve the switch block data from the pointer we set before + # The data is located just sizeof(NSwitchBlock) bytes below + # the top of the pointer to the heap + let + nswitchDescrPos = cast[ByteAddress](p) -% sizeof(NSwitchBlock) + nswitchBlock = cast[PSwitchBlock](nswitchDescrPos) + + deallocate( + nswitchBlock.heapMirror, nswitchBlock.heap, nswitchBlock.realSize + ) + + proc storeHeapData(address, heapMirror, heap: pointer, size: int) {.inline.} = + ## Store data in the heap for deallocation purposes later + + # the position of our heap pointer data. Since we allocated PageSize extra + # bytes, we should have a buffer on top of the requested size of at least + # PageSize bytes, which is much larger than sizeof(NSwitchBlock). So we + # decrement the address by sizeof(NSwitchBlock) and use that address + # to store our pointer data + let nswitchBlockPos = cast[ByteAddress](address) -% sizeof(NSwitchBlock) + + # We need to store this in a pointer obj (PSwitchBlock) so that the data sticks + # at the address we've chosen. If NSwitchBlock is used here, the data will + # be all 0 when we try to retrieve it later. + var nswitchBlock = cast[PSwitchBlock](nswitchBlockPos) + nswitchBlock.realSize = size + nswitchBlock.heap = heap + nswitchBlock.heapMirror = heapMirror + + proc getOriginalHeapPosition(address: pointer, difference: int): pointer {.inline.} = + ## This function sets the heap back to the originally requested + ## size + let + pos = cast[int](address) + newPos = cast[ByteAddress](pos) +% difference + + return cast[pointer](newPos) + + template allocPages(size: int, outOfMemoryStmt: untyped): untyped = + # This is to ensure we get a block of memory the requested + # size, as well as space to store our structure + let realSize = alignSize(size + sizeof(NSwitchBlock)) + + let heap = memalign(PageSize, realSize) + + if heap.isNil: + outOfMemoryStmt + + let heapMirror = virtmemReserveMap(realSize.csize) + result = heapMirror + + let rc = svcMapMemory(heapMirror, heap, realSize.uint64) + # Any return code not equal 0 means an error in libnx + if rc.uint32 != 0: + deallocate(heapMirror, heap, realSize) + outOfMemoryStmt + + # set result to be the original size requirement + result = getOriginalHeapPosition(result, realSize - size) + + storeHeapData(result, heapMirror, heap, realSize) + + proc osAllocPages(size: int): pointer {.inline.} = + allocPages(size): + raiseOutOfMem() + + proc osTryAllocPages(size: int): pointer = + allocPages(size): + return nil + + proc osDeallocPages(p: pointer, size: int) = + # Note that in order for the Switch not to crash, a call to + # deallocHeap(runFinalizers = true, allowGcAfterwards = false) + # must be run before gfxExit(). The Switch requires all memory + # to be deallocated before the graphics application has exited. + # + # gfxExit() can be found in in the github + # repo https://github.com/switchbrew/libnx + when reallyOsDealloc: + freeMem(p) + elif defined(posix) and not defined(StandaloneHeapSize): const PROT_READ = 1 # page can be read PROT_WRITE = 2 # page can be written - when defined(netbsd) or defined(openbsd): - # OpenBSD security for setjmp/longjmp coroutines - var MAP_STACK {.importc: "MAP_STACK", header: "".}: cint - else: - const MAP_STACK = 0 # avoid sideeffects - - when defined(macosx) or defined(freebsd): + when defined(macosx) or defined(bsd): const MAP_ANONYMOUS = 0x1000 const MAP_PRIVATE = 0x02 # Changes are private elif defined(solaris): @@ -128,7 +210,7 @@ elif defined(posix) and not defined(StandaloneHeapSize): elif defined(haiku): const MAP_ANONYMOUS = 0x08 const MAP_PRIVATE = 0x02 - else: # posix including netbsd or openbsd + else: var MAP_ANONYMOUS {.importc: "MAP_ANONYMOUS", header: "".}: cint MAP_PRIVATE {.importc: "MAP_PRIVATE", header: "".}: cint @@ -140,13 +222,13 @@ elif defined(posix) and not defined(StandaloneHeapSize): proc osAllocPages(size: int): pointer {.inline.} = result = mmap(nil, cast[csize_t](size), PROT_READ or PROT_WRITE, - MAP_ANONYMOUS or MAP_PRIVATE or MAP_STACK, -1, 0) + MAP_PRIVATE or MAP_ANONYMOUS, -1, 0) if result == nil or result == cast[pointer](-1): raiseOutOfMem() proc osTryAllocPages(size: int): pointer {.inline.} = result = mmap(nil, cast[csize_t](size), PROT_READ or PROT_WRITE, - MAP_ANONYMOUS or MAP_PRIVATE or MAP_STACK, -1, 0) + MAP_PRIVATE or MAP_ANONYMOUS, -1, 0) if result == cast[pointer](-1): result = nil proc osDeallocPages(p: pointer, size: int) {.inline.} = @@ -189,7 +271,7 @@ elif defined(windows) and not defined(StandaloneHeapSize): when reallyOsDealloc: if virtualFree(p, 0, MEM_RELEASE) == 0: cprintf "virtualFree failing!" - rawQuit 1 + quit 1 #VirtualFree(p, size, MEM_DECOMMIT) elif hostOS == "standalone" or defined(StandaloneHeapSize): diff --git a/lib/system/platforms.nim b/lib/system/platforms.nim index 0619f3fca..6e39dc7f2 100644 --- a/lib/system/platforms.nim +++ b/lib/system/platforms.nim @@ -10,8 +10,6 @@ ## Platform detection for NimScript. This module is included by the system module! ## Do not import it directly! -# CPU architectures have alias names mapped in tools/niminst/makefile.nimf - type CpuPlatform* {.pure.} = enum ## the CPU this program will run on. none, ## unknown CPU @@ -35,17 +33,14 @@ type vm, ## Some Virtual machine: Nim's VM or JavaScript avr, ## AVR based processor msp430, ## TI MSP430 microcontroller - riscv32, ## RISC-V 32-bit processor - riscv64, ## RISC-V 64-bit processor - wasm32, ## WASM, 32-bit - e2k, ## MCST Elbrus 2000 - loongarch64, ## LoongArch 64-bit processor - s390x ## IBM Z + riscv64 ## RISC-V 64-bit processor + wasm32 ## WASM, 32-bit OsPlatform* {.pure.} = enum ## the OS this program will run on. none, dos, windows, os2, linux, morphos, skyos, solaris, irix, netbsd, freebsd, openbsd, aix, palmos, qnx, amiga, - atari, netware, macos, macosx, haiku, android, js, standalone, nintendoswitch + atari, netware, macos, macosx, haiku, android, js, nimVM, + standalone, nintendoswitch const targetOS* = when defined(windows): OsPlatform.windows @@ -70,6 +65,7 @@ const elif defined(haiku): OsPlatform.haiku elif defined(android): OsPlatform.android elif defined(js): OsPlatform.js + elif defined(nimVM): OsPlatform.nimVM elif defined(standalone): OsPlatform.standalone elif defined(nintendoswitch): OsPlatform.nintendoswitch else: OsPlatform.none @@ -95,11 +91,7 @@ const elif defined(vm): CpuPlatform.vm elif defined(avr): CpuPlatform.avr elif defined(msp430): CpuPlatform.msp430 - elif defined(riscv32): CpuPlatform.riscv32 elif defined(riscv64): CpuPlatform.riscv64 elif defined(wasm32): CpuPlatform.wasm32 - elif defined(e2k): CpuPlatform.e2k - elif defined(loongarch64): CpuPlatform.loongarch64 - elif defined(s390x): CpuPlatform.s390x else: CpuPlatform.none ## the CPU this program will run on. diff --git a/lib/system/profiler.nim b/lib/system/profiler.nim index e7eb6ac82..0649f1176 100644 --- a/lib/system/profiler.nim +++ b/lib/system/profiler.nim @@ -60,13 +60,13 @@ proc captureStackTrace(f: PFrame, st: var StackTrace) = b = b.prev var - profilingRequestedHook*: proc (): bool {.nimcall, gcsafe.} + profilingRequestedHook*: proc (): bool {.nimcall, locks: 0, gcsafe.} ## set this variable to provide a procedure that implements a profiler in ## user space. See the `nimprof` module for a reference implementation. when defined(memProfiler): type - MemProfilerHook* = proc (st: StackTrace, requestedSize: int) {.nimcall, gcsafe.} + MemProfilerHook* = proc (st: StackTrace, requestedSize: int) {.nimcall, locks: 0, gcsafe.} var profilerHook*: MemProfilerHook diff --git a/lib/system/rawquits.nim b/lib/system/rawquits.nim deleted file mode 100644 index f0ead10c6..000000000 --- a/lib/system/rawquits.nim +++ /dev/null @@ -1,27 +0,0 @@ -import system/ctypes - -when defined(nimNoQuit): - proc rawQuit(errorcode: int = QuitSuccess) = discard "ignoring quit" - -elif defined(genode): - import genode/env - - var systemEnv {.exportc: runtimeEnvSym.}: GenodeEnvPtr - - type GenodeEnv = GenodeEnvPtr - ## Opaque type representing Genode environment. - - proc rawQuit(env: GenodeEnv; errorcode: int) {.magic: "Exit", noreturn, - importcpp: "#->parent().exit(@); Genode::sleep_forever()", header: "".} - - proc rawQuit(errorcode: int = QuitSuccess) {.inline, noreturn.} = - systemEnv.rawQuit(errorcode) - - -elif defined(js) and defined(nodejs) and not defined(nimscript): - proc rawQuit(errorcode: int = QuitSuccess) {.magic: "Exit", - importc: "process.exit", noreturn.} - -else: - proc rawQuit(errorcode: cint) {. - magic: "Exit", importc: "exit", header: "", noreturn.} \ No newline at end of file diff --git a/lib/system/refs_v2.nim b/lib/system/refs_v2.nim new file mode 100644 index 000000000..f6f3ba01c --- /dev/null +++ b/lib/system/refs_v2.nim @@ -0,0 +1,176 @@ +# +# +# Nim's Runtime Library +# (c) Copyright 2019 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +#[ +In this new runtime we simplify the object layouts a bit: The runtime type +information is only accessed for the objects that have it and it's always +at offset 0 then. The ``ref`` object header is independent from the +runtime type and only contains a reference count. + +Object subtyping is checked via the generated 'name'. This should have +comparable overhead to the old pointer chasing approach but has the benefit +that it works across DLL boundaries. + +The generated name is a concatenation of the object names in the hierarchy +so that a subtype check becomes a substring check. For example:: + + type + ObjectA = object of RootObj + ObjectB = object of ObjectA + +ObjectA's ``name`` is "|ObjectA|RootObj|". +ObjectB's ``name`` is "|ObjectB|ObjectA|RootObj|". + +Now to check for ``x of ObjectB`` we need to check +for ``x.typ.name.hasSubstring("|ObjectB|")``. In the actual implementation, +however, we could also use a +hash of ``package & "." & module & "." & name`` to save space. + +]# + +const + rcIncrement = 0b1000 # so that lowest 3 bits are not touched + rcMask = 0b111 + +type + RefHeader = object + rc: int # the object header is now a single RC field. + # we could remove it in non-debug builds for the 'owned ref' + # design but this seems unwise. + Cell = ptr RefHeader + +template `+!`(p: pointer, s: int): pointer = + cast[pointer](cast[int](p) +% s) + +template `-!`(p: pointer, s: int): pointer = + cast[pointer](cast[int](p) -% s) + +template head(p: pointer): Cell = + cast[Cell](cast[int](p) -% sizeof(RefHeader)) + +const + traceCollector = defined(traceArc) + +proc nimNewObj(size: int): pointer {.compilerRtl.} = + let s = size + sizeof(RefHeader) + when defined(nimscript): + discard + elif defined(useMalloc): + var orig = c_malloc(cuint s) + nimZeroMem(orig, s) + result = orig +! sizeof(RefHeader) + elif compileOption("threads"): + result = allocShared0(s) +! sizeof(RefHeader) + else: + result = alloc0(s) +! sizeof(RefHeader) + when traceCollector: + cprintf("[Allocated] %p\n", result -! sizeof(RefHeader)) + +proc nimNewObjUninit(size: int): pointer {.compilerRtl.} = + # Same as 'newNewObj' but do not initialize the memory to zero. + # The codegen proved for us that this is not necessary. + let s = size + sizeof(RefHeader) + when defined(nimscript): + discard + elif defined(useMalloc): + var orig = cast[ptr RefHeader](c_malloc(cuint s)) + elif compileOption("threads"): + var orig = cast[ptr RefHeader](allocShared(s)) + else: + var orig = cast[ptr RefHeader](alloc(s)) + orig.rc = 0 + result = orig +! sizeof(RefHeader) + when traceCollector: + cprintf("[Allocated] %p\n", result -! sizeof(RefHeader)) + +proc nimDecWeakRef(p: pointer) {.compilerRtl, inl.} = + dec head(p).rc, rcIncrement + +proc nimIncRef(p: pointer) {.compilerRtl, inl.} = + inc head(p).rc, rcIncrement + when traceCollector: + cprintf("[INCREF] %p\n", head(p)) + +proc nimRawDispose(p: pointer) {.compilerRtl.} = + when not defined(nimscript): + when traceCollector: + cprintf("[Freed] %p\n", p -! sizeof(RefHeader)) + when defined(nimOwnedEnabled): + if head(p).rc >= rcIncrement: + cstderr.rawWrite "[FATAL] dangling references exist\n" + quit 1 + when defined(useMalloc): + c_free(p -! sizeof(RefHeader)) + elif compileOption("threads"): + deallocShared(p -! sizeof(RefHeader)) + else: + dealloc(p -! sizeof(RefHeader)) + +template dispose*[T](x: owned(ref T)) = nimRawDispose(cast[pointer](x)) +#proc dispose*(x: pointer) = nimRawDispose(x) + +proc nimDestroyAndDispose(p: pointer) {.compilerRtl, raises: [].} = + let d = cast[ptr PNimType](p)[].destructor + if d != nil: cast[DestructorProc](d)(p) + when false: + cstderr.rawWrite cast[ptr PNimType](p)[].name + cstderr.rawWrite "\n" + if d == nil: + cstderr.rawWrite "bah, nil\n" + else: + cstderr.rawWrite "has destructor!\n" + nimRawDispose(p) + +when defined(gcOrc): + include cyclicrefs_v2 + +proc nimDecRefIsLast(p: pointer): bool {.compilerRtl, inl.} = + if p != nil: + var cell = head(p) + if (cell.rc and not rcMask) == 0: + result = true + when traceCollector: + cprintf("[ABOUT TO DESTROY] %p\n", cell) + else: + dec cell.rc, rcIncrement + # According to Lins it's correct to do nothing else here. + when traceCollector: + cprintf("[DeCREF] %p\n", cell) + +proc GC_unref*[T](x: ref T) = + ## New runtime only supports this operation for 'ref T'. + if nimDecRefIsLast(cast[pointer](x)): + # XXX this does NOT work for virtual destructors! + `=destroy`(x[]) + nimRawDispose(cast[pointer](x)) + +proc GC_ref*[T](x: ref T) = + ## New runtime only supports this operation for 'ref T'. + if x != nil: nimIncRef(cast[pointer](x)) + +template GC_fullCollect* = + ## Forces a full garbage collection pass. With ``--gc:arc`` a nop. + discard + +template setupForeignThreadGc* = + ## With ``--gc:arc`` a nop. + discard + +template tearDownForeignThreadGc* = + ## With ``--gc:arc`` a nop. + discard + +proc isObj(obj: PNimType, subclass: cstring): bool {.compilerRtl, inl.} = + proc strstr(s, sub: cstring): cstring {.header: "", importc.} + + result = strstr(obj.name, subclass) != nil + +proc chckObj(obj: PNimType, subclass: cstring) {.compilerRtl.} = + # checks if obj is of type subclass: + if not isObj(obj, subclass): sysFatal(ObjectConversionError, "invalid object conversion") diff --git a/lib/system/repr.nim b/lib/system/repr.nim index 6b6f7e340..cc5ba2fee 100644 --- a/lib/system/repr.nim +++ b/lib/system/repr.nim @@ -16,9 +16,14 @@ proc reprInt(x: int64): string {.compilerproc.} = return $x proc reprFloat(x: float): string {.compilerproc.} = return $x proc reprPointer(x: pointer): string {.compilerproc.} = - result = newString(60) - let n = c_sprintf(cast[cstring](addr result[0]), "%p", x) - setLen(result, n) + when defined(nimNoArrayToCstringConversion): + result = newString(60) + let n = c_sprintf(addr result[0], "%p", x) + setLen(result, n) + else: + var buf: array[0..59, char] + discard c_sprintf(buf, "%p", x) + return $buf proc reprStrAux(result: var string, s: cstring; len: int) = if cast[pointer](s) == nil: @@ -72,8 +77,6 @@ proc reprEnum(e: int, typ: PNimType): string {.compilerRtl.} = result = $e & " (invalid data!)" -include system/repr_impl - type PByteArray = ptr UncheckedArray[byte] # array[0xffff, byte] @@ -99,7 +102,6 @@ proc reprSetAux(result: var string, p: pointer, typ: PNimType) = of 4: u = cast[ptr uint32](p)[] of 8: u = cast[ptr uint64](p)[] else: - u = uint64(0) var a = cast[PByteArray](p) for i in 0 .. typ.size*8-1: if (uint(a[i shr 3]) and (1'u shl (i and 7))) != 0: @@ -155,7 +157,7 @@ when not defined(useNimRtl): var bs = typ.base.size for i in 0..typ.size div bs - 1: if i > 0: add result, ", " - reprAux(result, cast[pointer](cast[int](p) + i*bs), typ.base, cl) + reprAux(result, cast[pointer](cast[ByteAddress](p) + i*bs), typ.base, cl) add result, "]" when defined(nimSeqsV2): @@ -170,7 +172,7 @@ when not defined(useNimRtl): template payloadPtr(x: untyped): untyped = cast[PGenericSeq](x).p else: - const payloadOffset = GenericSeqSize ## the payload offset always depends on the alignment of the member type. + const payloadOffset = GenericSeqSize template payloadPtr(x: untyped): untyped = x proc reprSequence(result: var string, p: pointer, typ: PNimType, @@ -183,7 +185,7 @@ when not defined(useNimRtl): var bs = typ.base.size for i in 0..cast[PGenericSeq](p).len-1: if i > 0: add result, ", " - reprAux(result, cast[pointer](cast[int](payloadPtr(p)) + align(payloadOffset, typ.align) + i*bs), + reprAux(result, cast[pointer](cast[ByteAddress](payloadPtr(p)) + payloadOffset + i*bs), typ.base, cl) add result, "]" @@ -194,14 +196,14 @@ when not defined(useNimRtl): of nkSlot: add result, $n.name add result, " = " - reprAux(result, cast[pointer](cast[int](p) + n.offset), n.typ, cl) + reprAux(result, cast[pointer](cast[ByteAddress](p) + n.offset), n.typ, cl) of nkList: for i in 0..n.len-1: if i > 0: add result, ",\n" reprRecordAux(result, p, n.sons[i], cl) of nkCase: var m = selectBranch(p, n) - reprAux(result, cast[pointer](cast[int](p) + n.offset), n.typ, cl) + reprAux(result, cast[pointer](cast[ByteAddress](p) + n.offset), n.typ, cl) if m != nil: reprRecordAux(result, p, m, cl) proc reprRecord(result: var string, p: pointer, typ: PNimType, @@ -283,7 +285,7 @@ when not defined(useNimRtl): of tyString: let sp = cast[ptr string](p) reprStrAux(result, sp[].cstring, sp[].len) - of tyCstring: + of tyCString: let cs = cast[ptr cstring](p)[] if cs.isNil: add result, "nil" else: reprStrAux(result, cs, cs.len) @@ -307,7 +309,7 @@ when not defined(useNimRtl): var bs = elemtyp.size for i in 0..length - 1: if i > 0: add result, ", " - reprAux(result, cast[pointer](cast[int](p) + i*bs), elemtyp, cl) + reprAux(result, cast[pointer](cast[ByteAddress](p) + i*bs), elemtyp, cl) add result, "]" deinitReprClosure(cl) @@ -322,6 +324,5 @@ when not defined(useNimRtl): else: var p = p reprAux(result, addr(p), typ, cl) - when defined(nimLegacyReprWithNewline): # see PR #16034 - add result, "\n" + add result, "\n" deinitReprClosure(cl) diff --git a/lib/system/repr_impl.nim b/lib/system/repr_impl.nim deleted file mode 100644 index b9ec1890f..000000000 --- a/lib/system/repr_impl.nim +++ /dev/null @@ -1,15 +0,0 @@ -#[ -other APIs common to system/repr and system/reprjs could be refactored here, eg: -* reprChar -* reprBool -* reprStr - -Another possibility in future work would be to have a single include file instead -of system/repr and system/reprjs, and use `when defined(js)` inside it. -]# - -proc reprDiscriminant*(e: int, typ: PNimType): string {.compilerRtl.} = - case typ.kind - of tyEnum: reprEnum(e, typ) - of tyBool: $(e != 0) - else: $e diff --git a/lib/system/repr_v2.nim b/lib/system/repr_v2.nim index f6c720e2c..beca1d842 100644 --- a/lib/system/repr_v2.nim +++ b/lib/system/repr_v2.nim @@ -1,83 +1,53 @@ -include system/inclrtl - -when defined(nimPreviewSlimSystem): - import std/formatfloat - proc isNamedTuple(T: typedesc): bool {.magic: "TypeTrait".} ## imported from typetraits -proc distinctBase(T: typedesc, recursive: static bool = true): typedesc {.magic: "TypeTrait".} +proc distinctBase(T: typedesc): typedesc {.magic: "TypeTrait".} ## imported from typetraits proc repr*(x: NimNode): string {.magic: "Repr", noSideEffect.} -proc repr*(x: int): string = - ## Same as $x - $x +proc repr*(x: int): string {.magic: "IntToStr", noSideEffect.} + ## repr for an integer argument. Returns `x` + ## converted to a decimal string. -proc repr*(x: int64): string = - ## Same as $x - $x +proc repr*(x: int64): string {.magic: "Int64ToStr", noSideEffect.} + ## repr for an integer argument. Returns `x` + ## converted to a decimal string. -proc repr*(x: uint64): string {.noSideEffect.} = - ## Same as $x - $x - -proc repr*(x: float): string = - ## Same as $x - $x +proc repr*(x: float): string {.magic: "FloatToStr", noSideEffect.} + ## repr for a float argument. Returns `x` + ## converted to a decimal string. proc repr*(x: bool): string {.magic: "BoolToStr", noSideEffect.} ## repr for a boolean argument. Returns `x` ## converted to the string "false" or "true". -proc repr*(x: char): string {.noSideEffect, raises: [].} = +proc repr*(x: char): string {.magic: "CharToStr", noSideEffect.} ## repr for a character argument. Returns `x` - ## converted to an escaped string. + ## converted to a string. ## ## .. code-block:: Nim - ## assert repr('c') == "'c'" - result.add '\'' - # Elides string creations if not needed - if x in {'\\', '\0'..'\31', '\127'..'\255'}: - result.add '\\' - if x in {'\0'..'\31', '\127'..'\255'}: - result.add $x.uint8 - else: - result.add x - result.add '\'' + ## assert $'c' == "c" -proc repr*(x: string | cstring): string {.noSideEffect, raises: [].} = +proc repr*(x: cstring): string {.magic: "CStrToStr", noSideEffect.} + ## repr for a CString argument. Returns `x` + ## converted to a string. + +proc repr*(x: string): string {.magic: "StrToStr", noSideEffect.} ## repr for a string argument. Returns `x` - ## converted to a quoted and escaped string. - result.add '\"' - for i in 0.."", but repr of an + # array of string that is not initialized is [nil, nil, ...] ?? + add(result, "nil") + else: + reprStrAux(result, s, s.len) proc addSetElem(result: var string, elem: int, typ: PNimType) = # Dispatch each set element to the correct repr proc @@ -100,6 +114,7 @@ proc reprSetAux(result: var string, s: int, typ: PNimType) = add(result, "}") proc reprSet(e: int, typ: PNimType): string {.compilerRtl.} = + result = "" reprSetAux(result, e, typ) type @@ -115,9 +130,24 @@ proc reprAux(result: var string, p: pointer, typ: PNimType, cl: var ReprClosure) proc reprArray(a: pointer, typ: PNimType, cl: var ReprClosure): string {.compilerRtl.} = + var isNilArrayOrSeq: bool + # isnil is not enough here as it would try to deref `a` without knowing what's inside + {. emit: """ + if (`a` == null) { + `isNilArrayOrSeq` = true; + } else if (`a`[0] == null) { + `isNilArrayOrSeq` = true; + } else { + `isNilArrayOrSeq` = false; + }; + """ .} + if typ.kind == tySequence and isNilArrayOrSeq: + return "nil" + # We prepend @ to seq, the C backend prepends the pointer to the seq. result = if typ.kind == tySequence: "@[" else: "[" var len: int = 0 + var i: int = 0 {. emit: "`len` = `a`.length;\n" .} var dereffed: pointer = a @@ -133,7 +163,7 @@ proc reprArray(a: pointer, typ: PNimType, add(result, "]") -proc isPointedToNil(p: pointer): bool = +proc isPointedToNil(p: pointer): bool {.inline.}= {. emit: "if (`p` === null) {`result` = true};\n" .} proc reprRef(result: var string, p: pointer, typ: PNimType, @@ -175,6 +205,7 @@ proc reprRecordAux(result: var string, o: pointer, typ: PNimType, cl: var ReprCl add(result, "]") proc reprRecord(o: pointer, typ: PNimType, cl: var ReprClosure): string {.compilerRtl.} = + result = "" reprRecordAux(result, o, typ, cl) @@ -204,7 +235,7 @@ proc reprAux(result: var string, p: pointer, typ: PNimType, var fp: int {. emit: "`fp` = `p`;\n" .} add(result, reprStr(cast[string](p))) - of tyCstring: + of tyCString: var fp: cstring {. emit: "`fp` = `p`;\n" .} if fp.isNil: @@ -240,6 +271,6 @@ proc reprAux(result: var string, p: pointer, typ: PNimType, proc reprAny(p: pointer, typ: PNimType): string {.compilerRtl.} = var cl: ReprClosure initReprClosure(cl) + result = "" reprAux(result, p, typ, cl) - when defined(nimLegacyReprWithNewline): # see PR #16034 - add result, "\n" + add(result, "\n") \ No newline at end of file diff --git a/lib/system/seqs_v2.nim b/lib/system/seqs_v2.nim index d7ace446d..3bd5e291b 100644 --- a/lib/system/seqs_v2.nim +++ b/lib/system/seqs_v2.nim @@ -15,6 +15,7 @@ proc supportsCopyMem(t: typedesc): bool {.magic: "TypeTrait".} ## Default seq implementation used by Nim's core. type + NimSeqPayloadBase = object cap: int @@ -22,8 +23,7 @@ type cap: int data: UncheckedArray[T] - NimSeqV2*[T] = object # \ - # if you change this implementation, also change seqs_v2_reimpl.nim! + NimSeqV2*[T] = object len: int p: ptr NimSeqPayload[T] @@ -31,30 +31,27 @@ const nimSeqVersion {.core.} = 2 # XXX make code memory safe for overflows in '*' -proc newSeqPayload(cap, elemSize, elemAlign: int): pointer {.compilerRtl, raises: [].} = +proc newSeqPayload(cap, elemSize: int): pointer {.compilerRtl, raises: [].} = # we have to use type erasure here as Nim does not support generic # compilerProcs. Oh well, this will all be inlined anyway. if cap > 0: - var p = cast[ptr NimSeqPayloadBase](alignedAlloc0(align(sizeof(NimSeqPayloadBase), elemAlign) + cap * elemSize, elemAlign)) + var p = cast[ptr NimSeqPayloadBase](allocShared0(cap * elemSize + sizeof(NimSeqPayloadBase))) p.cap = cap result = p else: result = nil -template `+!`(p: pointer, s: int): pointer = - cast[pointer](cast[int](p) +% s) - -template `-!`(p: pointer, s: int): pointer = - cast[pointer](cast[int](p) -% s) - -proc prepareSeqAdd(len: int; p: pointer; addlen, elemSize, elemAlign: int): pointer {. - noSideEffect, raises: [], compilerRtl.} = +proc prepareSeqAdd(len: int; p: pointer; addlen, elemSize: int): pointer {. + noSideEffect, raises: [].} = {.noSideEffect.}: - let headerSize = align(sizeof(NimSeqPayloadBase), elemAlign) + template `+!`(p: pointer, s: int): pointer = + cast[pointer](cast[int](p) +% s) + + const headerSize = sizeof(NimSeqPayloadBase) if addlen <= 0: result = p elif p == nil: - result = newSeqPayload(len+addlen, elemSize, elemAlign) + result = newSeqPayload(len+addlen, elemSize) else: # Note: this means we cannot support things that have internal pointers as # they get reallocated here. This needs to be documented clearly. @@ -62,37 +59,35 @@ proc prepareSeqAdd(len: int; p: pointer; addlen, elemSize, elemAlign: int): poin let oldCap = p.cap and not strlitFlag let newCap = max(resize(oldCap), len+addlen) if (p.cap and strlitFlag) == strlitFlag: - var q = cast[ptr NimSeqPayloadBase](alignedAlloc0(headerSize + elemSize * newCap, elemAlign)) + var q = cast[ptr NimSeqPayloadBase](allocShared0(headerSize + elemSize * newCap)) copyMem(q +! headerSize, p +! headerSize, len * elemSize) q.cap = newCap result = q else: let oldSize = headerSize + elemSize * oldCap let newSize = headerSize + elemSize * newCap - var q = cast[ptr NimSeqPayloadBase](alignedRealloc0(p, oldSize, newSize, elemAlign)) + var q = cast[ptr NimSeqPayloadBase](reallocShared0(p, oldSize, newSize)) q.cap = newCap result = q -proc shrink*[T](x: var seq[T]; newLen: Natural) {.tags: [], raises: [].} = +proc shrink*[T](x: var seq[T]; newLen: Natural) = when nimvm: - {.cast(tags: []).}: - setLen(x, newLen) + setLen(x, newLen) else: - #sysAssert newLen <= x.len, "invalid newLen parameter for 'shrink'" + mixin `=destroy` + sysAssert newLen <= x.len, "invalid newLen parameter for 'shrink'" when not supportsCopyMem(T): for i in countdown(x.len - 1, newLen): - reset x[i] + `=destroy`(x[i]) # XXX This is wrong for const seqs that were moved into 'x'! - {.noSideEffect.}: - cast[ptr NimSeqV2[T]](addr x).len = newLen + cast[ptr NimSeqV2[T]](addr x).len = newLen proc grow*[T](x: var seq[T]; newLen: Natural; value: T) = let oldLen = x.len - #sysAssert newLen >= x.len, "invalid newLen parameter for 'grow'" if newLen <= oldLen: return var xu = cast[ptr NimSeqV2[T]](addr x) if xu.p == nil or xu.p.cap < newLen: - xu.p = cast[typeof(xu.p)](prepareSeqAdd(oldLen, xu.p, newLen - oldLen, sizeof(T), alignof(T))) + xu.p = cast[typeof(xu.p)](prepareSeqAdd(oldLen, xu.p, newLen - oldLen, sizeof(T))) xu.len = newLen for i in oldLen .. newLen-1: xu.p.data[i] = value @@ -104,17 +99,16 @@ proc add*[T](x: var seq[T]; value: sink T) {.magic: "AppendSeqElem", noSideEffec ## containers should also call their adding proc `add` for consistency. ## Generic code becomes much easier to write if the Nim naming scheme is ## respected. - {.cast(noSideEffect).}: - let oldLen = x.len - var xu = cast[ptr NimSeqV2[T]](addr x) - if xu.p == nil or xu.p.cap < oldLen+1: - xu.p = cast[typeof(xu.p)](prepareSeqAdd(oldLen, xu.p, 1, sizeof(T), alignof(T))) - xu.len = oldLen+1 - # .nodestroy means `xu.p.data[oldLen] = value` is compiled into a - # copyMem(). This is fine as know by construction that - # in `xu.p.data[oldLen]` there is nothing to destroy. - # We also save the `wasMoved + destroy` pair for the sink parameter. - xu.p.data[oldLen] = value + let oldLen = x.len + var xu = cast[ptr NimSeqV2[T]](addr x) + if xu.p == nil or xu.p.cap < oldLen+1: + xu.p = cast[typeof(xu.p)](prepareSeqAdd(oldLen, xu.p, 1, sizeof(T))) + xu.len = oldLen+1 + # .nodestroy means `xu.p.data[oldLen] = value` is compiled into a + # copyMem(). This is fine as know by construction that + # in `xu.p.data[oldLen]` there is nothing to destroy. + # We also save the `wasMoved + destroy` pair for the sink parameter. + xu.p.data[oldLen] = value proc setLen[T](s: var seq[T], newlen: Natural) = {.noSideEffect.}: @@ -125,27 +119,5 @@ proc setLen[T](s: var seq[T], newlen: Natural) = if newlen <= oldLen: return var xu = cast[ptr NimSeqV2[T]](addr s) if xu.p == nil or xu.p.cap < newlen: - xu.p = cast[typeof(xu.p)](prepareSeqAdd(oldLen, xu.p, newlen - oldLen, sizeof(T), alignof(T))) + xu.p = cast[typeof(xu.p)](prepareSeqAdd(oldLen, xu.p, newlen - oldLen, sizeof(T))) xu.len = newlen - for i in oldLen.. 4 -func len*[T](x: set[T]): int {.magic: "Card".} +proc len*[T](x: set[T]): int {.magic: "Card", noSideEffect.} ## An alias for `card(x)`. -func `*`*[T](x, y: set[T]): set[T] {.magic: "MulSet".} = +proc `*`*[T](x, y: set[T]): set[T] {.magic: "MulSet", noSideEffect.} ## This operator computes the intersection of two sets. - runnableExamples: - assert {1, 2, 3} * {2, 3, 4} == {2, 3} - -func `+`*[T](x, y: set[T]): set[T] {.magic: "PlusSet".} = - ## This operator computes the union of two sets. - runnableExamples: - assert {1, 2, 3} + {2, 3, 4} == {1, 2, 3, 4} - -func `-`*[T](x, y: set[T]): set[T] {.magic: "MinusSet".} = - ## This operator computes the difference of two sets. - runnableExamples: - assert {1, 2, 3} - {2, 3, 4} == {1} - -func contains*[T](x: set[T], y: T): bool {.magic: "InSet".} = - ## One should overload this proc if one wants to overload the `in` operator. ## - ## The parameters are in reverse order! `a in b` is a template for - ## `contains(b, a)`. + ## .. code-block:: Nim + ## let + ## a = {1, 2, 3} + ## b = {2, 3, 4} + ## echo a * b # => {2, 3} +proc `+`*[T](x, y: set[T]): set[T] {.magic: "PlusSet", noSideEffect.} + ## This operator computes the union of two sets. + ## + ## .. code-block:: Nim + ## let + ## a = {1, 2, 3} + ## b = {2, 3, 4} + ## echo a + b # => {1, 2, 3, 4} +proc `-`*[T](x, y: set[T]): set[T] {.magic: "MinusSet", noSideEffect.} + ## This operator computes the difference of two sets. + ## + ## .. code-block:: Nim + ## let + ## a = {1, 2, 3} + ## b = {2, 3, 4} + ## echo a - b # => {1} + +proc contains*[T](x: set[T], y: T): bool {.magic: "InSet", noSideEffect.} + ## One should overload this proc if one wants to overload the ``in`` operator. + ## + ## The parameters are in reverse order! ``a in b`` is a template for + ## ``contains(b, a)``. ## This is because the unification algorithm that Nim uses for overload ## resolution works from left to right. - ## But for the `in` operator that would be the wrong direction for this + ## But for the ``in`` operator that would be the wrong direction for this ## piece of code: - runnableExamples: - var s: set[range['a'..'z']] = {'a'..'c'} - assert s.contains('c') - assert 'b' in s - assert 'd' notin s - assert set['a'..'z'] is set[range['a'..'z']] - ## If `in` had been declared as `[T](elem: T, s: set[T])` then `T` would - ## have been bound to `char`. But `s` is not compatible to type - ## `set[char]`! The solution is to bind `T` to `range['a'..'z']`. This - ## is achieved by reversing the parameters for `contains`; `in` then + ## + ## .. code-block:: Nim + ## var s: set[range['a'..'z']] = {'a'..'c'} + ## assert s.contains('c') + ## assert 'b' in s + ## + ## If ``in`` had been declared as ``[T](elem: T, s: set[T])`` then ``T`` would + ## have been bound to ``char``. But ``s`` is not compatible to type + ## ``set[char]``! The solution is to bind ``T`` to ``range['a'..'z']``. This + ## is achieved by reversing the parameters for ``contains``; ``in`` then ## passes its arguments in reverse order. diff --git a/lib/system/sets.nim b/lib/system/sets.nim index e230985e0..0df50957d 100644 --- a/lib/system/sets.nim +++ b/lib/system/sets.nim @@ -10,11 +10,27 @@ # set handling type - NimSet = array[0..8192-1, uint8] + NimSet = array[0..4*2048-1, uint8] -proc cardSetImpl(s: openArray[uint8], len: int): int {.inline.} = +# bitops can't be imported here, therefore the code duplication. + +proc countBits32(n: uint32): int {.compilerproc.} = + # generic formula is from: https://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetParallel + var v = uint32(n) + v = v - ((v shr 1'u32) and 0x55555555'u32) + v = (v and 0x33333333'u32) + ((v shr 2'u32) and 0x33333333'u32) + result = (((v + (v shr 4'u32) and 0xF0F0F0F'u32) * 0x1010101'u32) shr 24'u32).int + +proc countBits64(n: uint64): int {.compilerproc, inline.} = + # generic formula is from: https://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetParallel + var v = uint64(n) + v = v - ((v shr 1'u64) and 0x5555555555555555'u64) + v = (v and 0x3333333333333333'u64) + ((v shr 2'u64) and 0x3333333333333333'u64) + v = (v + (v shr 4'u64) and 0x0F0F0F0F0F0F0F0F'u64) + result = ((v * 0x0101010101010101'u64) shr 56'u64).int + +proc cardSet(s: NimSet, len: int): int {.compilerproc, inline.} = var i = 0 - result = 0 when defined(x86) or defined(amd64): while i < len - 8: inc(result, countBits64((cast[ptr uint64](s[i].unsafeAddr))[])) @@ -23,6 +39,3 @@ proc cardSetImpl(s: openArray[uint8], len: int): int {.inline.} = while i < len: inc(result, countBits32(uint32(s[i]))) inc(i, 1) - -proc cardSet(s: NimSet, len: int): int {.compilerproc, inline.} = - result = cardSetImpl(s, len) diff --git a/lib/system/stacktraces.nim b/lib/system/stacktraces.nim deleted file mode 100644 index 42be9d94f..000000000 --- a/lib/system/stacktraces.nim +++ /dev/null @@ -1,83 +0,0 @@ -# -# -# Nim's Runtime Library -# (c) Copyright 2015 Andreas Rumpf -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# - -# Additional code for customizable stack traces. Unstable API, for internal -# usage only. - -const - reraisedFromBegin* = -10 - reraisedFromEnd* = -100 - maxStackTraceLines* = 128 - -when defined(nimStackTraceOverride): - ## Procedure types for overriding the default stack trace. - type - cuintptr_t* {.importc: "uintptr_t", nodecl.} = uint - ## This is the same as the type `uintptr_t` in C. - - StackTraceOverrideGetTracebackProc* = proc (): string {. - nimcall, gcsafe, raises: [], tags: [], noinline.} - StackTraceOverrideGetProgramCountersProc* = proc (maxLength: cint): seq[cuintptr_t] {. - nimcall, gcsafe, raises: [], tags: [], noinline.} - StackTraceOverrideGetDebuggingInfoProc* = - proc (programCounters: seq[cuintptr_t], maxLength: cint): seq[StackTraceEntry] {. - nimcall, gcsafe, raises: [], tags: [], noinline.} - - # Default procedures (not normally used, because people opting in on this - # override are supposed to register their own versions). - var - stackTraceOverrideGetTraceback: StackTraceOverrideGetTracebackProc = - proc (): string {.nimcall, gcsafe, raises: [], tags: [], noinline.} = - discard - #result = "Stack trace override procedure not registered.\n" - stackTraceOverrideGetProgramCounters: StackTraceOverrideGetProgramCountersProc = - proc (maxLength: cint): seq[cuintptr_t] {.nimcall, gcsafe, raises: [], tags: [], noinline.} = - discard - stackTraceOverrideGetDebuggingInfo: StackTraceOverrideGetDebuggingInfoProc = - proc (programCounters: seq[cuintptr_t], maxLength: cint): seq[StackTraceEntry] {. - nimcall, gcsafe, raises: [], tags: [], noinline.} = - discard - - # Custom procedure registration. - proc registerStackTraceOverride*(overrideProc: StackTraceOverrideGetTracebackProc) = - ## Override the default stack trace inside rawWriteStackTrace() with your - ## own procedure. - stackTraceOverrideGetTraceback = overrideProc - proc registerStackTraceOverrideGetProgramCounters*(overrideProc: StackTraceOverrideGetProgramCountersProc) = - stackTraceOverrideGetProgramCounters = overrideProc - proc registerStackTraceOverrideGetDebuggingInfo*(overrideProc: StackTraceOverrideGetDebuggingInfoProc) = - stackTraceOverrideGetDebuggingInfo = overrideProc - - # Custom stack trace manipulation. - proc auxWriteStackTraceWithOverride*(s: var string) = - add(s, stackTraceOverrideGetTraceback()) - - proc auxWriteStackTraceWithOverride*(s: var seq[StackTraceEntry]) = - let programCounters = stackTraceOverrideGetProgramCounters(maxStackTraceLines) - if s.len == 0: - s = newSeqOfCap[StackTraceEntry](programCounters.len) - for programCounter in programCounters: - s.add(StackTraceEntry(programCounter: cast[uint](programCounter))) - - # We may have more stack trace lines in the output, due to inlined procedures. - proc addDebuggingInfo*(s: seq[StackTraceEntry]): seq[StackTraceEntry] = - var programCounters: seq[cuintptr_t] - # We process program counters in groups from complete stack traces, because - # we have logic that keeps track of certain functions being inlined or not. - for entry in s: - if entry.procname.isNil and entry.programCounter != 0: - programCounters.add(cast[cuintptr_t](entry.programCounter)) - elif entry.procname.isNil and (entry.line == reraisedFromBegin or entry.line == reraisedFromEnd): - result.add(stackTraceOverrideGetDebuggingInfo(programCounters, maxStackTraceLines)) - programCounters = @[] - result.add(entry) - else: - result.add(entry) - if programCounters.len > 0: - result.add(stackTraceOverrideGetDebuggingInfo(programCounters, maxStackTraceLines)) diff --git a/lib/system/strmantle.nim b/lib/system/strmantle.nim index ab158d6b7..a111ec563 100644 --- a/lib/system/strmantle.nim +++ b/lib/system/strmantle.nim @@ -9,15 +9,12 @@ # Compilerprocs for strings that do not depend on the string implementation. -import std/private/digitsutils - - proc cmpStrings(a, b: string): int {.inline, compilerproc.} = let alen = a.len let blen = b.len let minlen = min(alen, blen) if minlen > 0: - result = c_memcmp(unsafeAddr a[0], unsafeAddr b[0], cast[csize_t](minlen)).int + result = c_memcmp(unsafeAddr a[0], unsafeAddr b[0], cast[csize_t](minlen)) if result == 0: result = alen - blen else: @@ -33,7 +30,7 @@ proc eqStrings(a, b: string): bool {.inline, compilerproc.} = proc hashString(s: string): int {.compilerproc.} = # the compiler needs exactly the same hash function! # this used to be used for efficient generation of string case statements - var h = 0'u + var h : uint = 0 for i in 0..len(s)-1: h = h + uint(s[i]) h = h + h shl 10 @@ -43,28 +40,71 @@ proc hashString(s: string): int {.compilerproc.} = h = h + h shl 15 result = cast[int](h) -proc eqCstrings(a, b: cstring): bool {.inline, compilerproc.} = - if pointer(a) == pointer(b): result = true - elif a.isNil or b.isNil: result = false - else: result = c_strcmp(a, b) == 0 - -proc hashCstring(s: cstring): int {.compilerproc.} = - # the compiler needs exactly the same hash function! - # this used to be used for efficient generation of cstring case statements - if s.isNil: return 0 - var h : uint = 0 +proc addInt*(result: var string; x: int64) = + ## Converts integer to its string representation and appends it to `result`. + ## + ## .. code-block:: Nim + ## var + ## a = "123" + ## b = 45 + ## a.addInt(b) # a <- "12345" + let base = result.len + setLen(result, base + sizeof(x)*4) var i = 0 + var y = x while true: - let c = s[i] - if c == '\0': break - h = h + uint(c) - h = h + h shl 10 - h = h xor (h shr 6) - inc i - h = h + h shl 3 - h = h xor (h shr 11) - h = h + h shl 15 - result = cast[int](h) + var d = y div 10 + result[base+i] = chr(abs(int(y - d*10)) + ord('0')) + inc(i) + y = d + if y == 0: break + if x < 0: + result[base+i] = '-' + inc(i) + setLen(result, base+i) + # mirror the string: + for j in 0..i div 2 - 1: + swap(result[base+j], result[base+i-j-1]) + +proc add*(result: var string; x: int64) {.deprecated: + "Deprecated since v0.20, use 'addInt'".} = + addInt(result, x) + +proc nimIntToStr(x: int): string {.compilerRtl.} = + result = newStringOfCap(sizeof(x)*4) + result.addInt x + +proc addCstringN(result: var string, buf: cstring; buflen: int) = + # no nimvm support needed, so it doesn't need to be fast here either + let oldLen = result.len + let newLen = oldLen + buflen + result.setLen newLen + copyMem(result[oldLen].addr, buf, buflen) + +import formatfloat + +proc addFloat*(result: var string; x: float) = + ## Converts float to its string representation and appends it to `result`. + ## + ## .. code-block:: Nim + ## var + ## a = "123" + ## b = 45.67 + ## a.addFloat(b) # a <- "12345.67" + when nimvm: + result.add $x + else: + var buffer: array[65, char] + let n = writeFloatToBuffer(buffer, x) + result.addCstringN(cstring(buffer[0].addr), n) + +proc add*(result: var string; x: float) {.deprecated: + "Deprecated since v0.20, use 'addFloat'".} = + addFloat(result, x) + +proc nimFloatToStr(f: float): string {.compilerproc.} = + result = newStringOfCap(8) + result.addFloat f proc c_strtod(buf: cstring, endptr: ptr cstring): float64 {. importc: "strtod", header: "", noSideEffect.} @@ -75,24 +115,21 @@ const 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, 1e20, 1e21, 1e22] - -{.push staticBoundChecks: off.} - -proc nimParseBiggestFloat(s: openArray[char], number: var BiggestFloat, - ): int {.compilerproc.} = +proc nimParseBiggestFloat(s: string, number: var BiggestFloat, + start = 0): int {.compilerproc.} = # This routine attempt to parse float that can parsed quickly. - # i.e. whose integer part can fit inside a 53bits integer. + # ie whose integer part can fit inside a 53bits integer. # their real exponent must also be <= 22. If the float doesn't follow # these restrictions, transform the float into this form: # INTEGER * 10 ^ exponent and leave the work to standard `strtod()`. # This avoid the problems of decimal character portability. # see: http://www.exploringbinary.com/fast-path-decimal-to-floating-point-conversion/ var - i = 0 + i = start sign = 1.0 kdigits, fdigits = 0 - exponent = 0 - integer = uint64(0) + exponent: int + integer: uint64 fracExponent = 0 expSign = 1 firstDigit = -1 @@ -111,7 +148,7 @@ proc nimParseBiggestFloat(s: openArray[char], number: var BiggestFloat, if s[i+2] == 'N' or s[i+2] == 'n': if i+3 >= s.len or s[i+3] notin IdentChars: number = NaN - return i+3 + return i+3 - start return 0 # Inf? @@ -120,7 +157,7 @@ proc nimParseBiggestFloat(s: openArray[char], number: var BiggestFloat, if s[i+2] == 'F' or s[i+2] == 'f': if i+3 >= s.len or s[i+3] notin IdentChars: number = Inf*sign - return i+3 + return i+3 - start return 0 if i < s.len and s[i] in {'0'..'9'}: @@ -154,8 +191,8 @@ proc nimParseBiggestFloat(s: openArray[char], number: var BiggestFloat, # if has no digits: return error if kdigits + fdigits <= 0 and - (i == 0 or # no char consumed (empty string). - (i == 1 and hasSign)): # or only '+' or '- + (i == start or # no char consumed (empty string). + (i == start + 1 and hasSign)): # or only '+' or '- return 0 if i+1 < s.len and s[i] in {'e', 'E'}: @@ -182,7 +219,7 @@ proc nimParseBiggestFloat(s: openArray[char], number: var BiggestFloat, number = 0.0*sign else: number = Inf*sign - return i + return i - start # if integer is representable in 53 bits: fast path # max fast path integer is 1<<53 - 1 or 8999999999999999 (16 digits) @@ -194,30 +231,29 @@ proc nimParseBiggestFloat(s: openArray[char], number: var BiggestFloat, number = sign * integer.float / powtens[absExponent] else: number = sign * integer.float * powtens[absExponent] - return i + return i - start # if exponent is greater try to fit extra exponent above 22 by multiplying # integer part is there is space left. let slop = 15 - kdigits - fdigits - if absExponent <= 22 + slop and not expNegative: + if absExponent <= 22 + slop and not expNegative: number = sign * integer.float * powtens[slop] * powtens[absExponent-slop] - return i + return i - start # if failed: slow path with strtod. var t: array[500, char] # flaviu says: 325 is the longest reasonable literal var ti = 0 let maxlen = t.high - "e+000".len # reserve enough space for exponent - let endPos = i - result = endPos - i = 0 + result = i - start + i = start # re-parse without error checking, any error should be handled by the code above. - if i < endPos and s[i] == '.': i.inc - while i < endPos and s[i] in {'0'..'9','+','-'}: + if i < s.len and s[i] == '.': i.inc + while i < s.len and s[i] in {'0'..'9','+','-'}: if ti < maxlen: t[ti] = s[i]; inc(ti) inc(i) - while i < endPos and s[i] in {'.', '_'}: # skip underscore and decimal point + while i < s.len and s[i] in {'.', '_'}: # skip underscore and decimal point inc(i) # insert exponent @@ -232,9 +268,15 @@ proc nimParseBiggestFloat(s: openArray[char], number: var BiggestFloat, t[ti-2] = ('0'.ord + absExponent mod 10).char absExponent = absExponent div 10 t[ti-3] = ('0'.ord + absExponent mod 10).char - number = c_strtod(cast[cstring](addr t), nil) -{.pop.} # staticBoundChecks + when defined(nimNoArrayToCstringConversion): + number = c_strtod(addr t, nil) + else: + number = c_strtod(t, nil) + +proc nimInt64ToStr(x: int64): string {.compilerRtl.} = + result = newStringOfCap(sizeof(x)*4) + result.addInt x proc nimBoolToStr(x: bool): string {.compilerRtl.} = return if x: "true" else: "false" @@ -243,6 +285,26 @@ proc nimCharToStr(x: char): string {.compilerRtl.} = result = newString(1) result[0] = x +proc `$`*(x: uint64): string {.noSideEffect, raises: [].} = + ## The stringify operator for an unsigned integer argument. Returns `x` + ## converted to a decimal string. + if x == 0: + result = "0" + else: + result = newString(60) + var i = 0 + var n = x + while n != 0: + let nn = n div 10'u64 + result[i] = char(n - 10'u64 * nn + ord('0')) + inc i + n = nn + result.setLen i + + let half = i div 2 + # Reverse + for t in 0 .. half-1: swap(result[t], result[i-t-1]) + when defined(gcDestructors): proc GC_getStatistics*(): string = result = "[GC] total memory: " diff --git a/lib/system/strs_v2.nim b/lib/system/strs_v2.nim index 429724dab..6f28ad237 100644 --- a/lib/system/strs_v2.nim +++ b/lib/system/strs_v2.nim @@ -29,41 +29,31 @@ template contentSize(cap): int = cap + 1 + sizeof(NimStrPayloadBase) template frees(s) = if not isLiteral(s): - when compileOption("threads"): - deallocShared(s.p) - else: - dealloc(s.p) + deallocShared(s.p) proc resize(old: int): int {.inline.} = if old <= 0: result = 4 - elif old <= high(int16): result = old * 2 + elif old < 65536: result = old * 2 else: result = old * 3 div 2 # for large arrays * 3/2 is better proc prepareAdd(s: var NimStringV2; addlen: int) {.compilerRtl.} = - let newLen = s.len + addlen if isLiteral(s): - let oldP = s.p - # can't mutate a literal, so we need a fresh copy here: - when compileOption("threads"): - s.p = cast[ptr NimStrPayload](allocShared0(contentSize(newLen))) - else: - s.p = cast[ptr NimStrPayload](alloc0(contentSize(newLen))) - s.p.cap = newLen - if s.len > 0: - # we are about to append, so there is no need to copy the \0 terminator: - copyMem(unsafeAddr s.p.data[0], unsafeAddr oldP.data[0], min(s.len, newLen)) + if addlen > 0: + let oldP = s.p + # can't mutate a literal, so we need a fresh copy here: + s.p = cast[ptr NimStrPayload](allocShared0(contentSize(s.len + addlen))) + s.p.cap = s.len + addlen + if s.len > 0: + # we are about to append, so there is no need to copy the \0 terminator: + copyMem(unsafeAddr s.p.data[0], unsafeAddr oldP.data[0], s.len) else: let oldCap = s.p.cap and not strlitFlag - if newLen > oldCap: - let newCap = max(newLen, resize(oldCap)) - when compileOption("threads"): - s.p = cast[ptr NimStrPayload](reallocShared0(s.p, contentSize(oldCap), contentSize(newCap))) - else: - s.p = cast[ptr NimStrPayload](realloc0(s.p, contentSize(oldCap), contentSize(newCap))) + if s.len + addlen > oldCap: + let newCap = max(s.len + addlen, resize(oldCap)) + s.p = cast[ptr NimStrPayload](reallocShared0(s.p, contentSize(oldCap), contentSize(newCap))) s.p.cap = newCap -proc nimAddCharV1(s: var NimStringV2; c: char) {.compilerRtl, inline.} = - #if (s.p == nil) or (s.len+1 > s.p.cap and not strlitFlag): +proc nimAddCharV1(s: var NimStringV2; c: char) {.compilerRtl.} = prepareAdd(s, 1) s.p.data[s.len] = c s.p.data[s.len+1] = '\0' @@ -73,10 +63,7 @@ proc toNimStr(str: cstring, len: int): NimStringV2 {.compilerproc.} = if len <= 0: result = NimStringV2(len: 0, p: nil) else: - when compileOption("threads"): - var p = cast[ptr NimStrPayload](allocShared0(contentSize(len))) - else: - var p = cast[ptr NimStrPayload](alloc0(contentSize(len))) + var p = cast[ptr NimStrPayload](allocShared0(contentSize(len))) p.cap = len if len > 0: # we are about to append, so there is no need to copy the \0 terminator: @@ -89,7 +76,7 @@ proc cstrToNimstr(str: cstring): NimStringV2 {.compilerRtl.} = proc nimToCStringConv(s: NimStringV2): cstring {.compilerproc, nonReloadable, inline.} = if s.len == 0: result = cstring"" - else: result = cast[cstring](unsafeAddr s.p.data) + else: result = cstring(unsafeAddr s.p.data) proc appendString(dest: var NimStringV2; src: NimStringV2) {.compilerproc, inline.} = if src.len > 0: @@ -107,10 +94,7 @@ proc rawNewString(space: int): NimStringV2 {.compilerproc.} = if space <= 0: result = NimStringV2(len: 0, p: nil) else: - when compileOption("threads"): - var p = cast[ptr NimStrPayload](allocShared0(contentSize(space))) - else: - var p = cast[ptr NimStrPayload](alloc0(contentSize(space))) + var p = cast[ptr NimStrPayload](allocShared0(contentSize(space))) p.cap = space result = NimStringV2(len: 0, p: p) @@ -118,20 +102,16 @@ proc mnewString(len: int): NimStringV2 {.compilerproc.} = if len <= 0: result = NimStringV2(len: 0, p: nil) else: - when compileOption("threads"): - var p = cast[ptr NimStrPayload](allocShared0(contentSize(len))) - else: - var p = cast[ptr NimStrPayload](alloc0(contentSize(len))) + var p = cast[ptr NimStrPayload](allocShared0(contentSize(len))) p.cap = len result = NimStringV2(len: len, p: p) proc setLengthStrV2(s: var NimStringV2, newLen: int) {.compilerRtl.} = if newLen == 0: - discard "do not free the buffer here, pattern 's.setLen 0' is common for avoiding allocations" - else: - if newLen > s.len or isLiteral(s): - prepareAdd(s, newLen - s.len) - s.p.data[newLen] = '\0' + frees(s) + s.p = nil + elif newLen > s.len or isLiteral(s): + prepareAdd(s, newLen - s.len) s.len = newLen proc nimAsgnStrV2(a: var NimStringV2, b: NimStringV2) {.compilerRtl.} = @@ -147,47 +127,15 @@ proc nimAsgnStrV2(a: var NimStringV2, b: NimStringV2) {.compilerRtl.} = # 'let y = newStringOfCap(); var x = y' # on the other hand... These get turned into moves now. frees(a) - when compileOption("threads"): - a.p = cast[ptr NimStrPayload](allocShared0(contentSize(b.len))) - else: - a.p = cast[ptr NimStrPayload](alloc0(contentSize(b.len))) + a.p = cast[ptr NimStrPayload](allocShared0(contentSize(b.len))) a.p.cap = b.len a.len = b.len copyMem(unsafeAddr a.p.data[0], unsafeAddr b.p.data[0], b.len+1) -proc nimPrepareStrMutationImpl(s: var NimStringV2) = - let oldP = s.p - # can't mutate a literal, so we need a fresh copy here: - when compileOption("threads"): - s.p = cast[ptr NimStrPayload](allocShared0(contentSize(s.len))) - else: - s.p = cast[ptr NimStrPayload](alloc0(contentSize(s.len))) - s.p.cap = s.len - copyMem(unsafeAddr s.p.data[0], unsafeAddr oldP.data[0], s.len+1) - -proc nimPrepareStrMutationV2(s: var NimStringV2) {.compilerRtl, inline.} = +proc nimPrepareStrMutationV2(s: var NimStringV2) {.compilerRtl.} = if s.p != nil and (s.p.cap and strlitFlag) == strlitFlag: - nimPrepareStrMutationImpl(s) - -proc prepareMutation*(s: var string) {.inline.} = - # string literals are "copy on write", so you need to call - # `prepareMutation` before modifying the strings via `addr`. - {.cast(noSideEffect).}: - let s = unsafeAddr s - nimPrepareStrMutationV2(cast[ptr NimStringV2](s)[]) - - -template capacityImpl(str: NimStringV2): int = - if str.p != nil: str.p.cap else: 0 - -func capacity*(self: string): int {.inline.} = - ## Returns the current capacity of the string. - # See https://github.com/nim-lang/RFCs/issues/460 - runnableExamples: - var str = newStringOfCap(cap = 42) - str.add "Nim" - assert str.capacity == 42 - - {.cast(noSideEffect).}: - let str = unsafeAddr self - result = capacityImpl(cast[ptr NimStringV2](str)[]) + let oldP = s.p + # can't mutate a literal, so we need a fresh copy here: + s.p = cast[ptr NimStrPayload](allocShared0(contentSize(s.len))) + s.p.cap = s.len + copyMem(unsafeAddr s.p.data[0], unsafeAddr oldP.data[0], s.len+1) diff --git a/lib/system/syslocks.nim b/lib/system/syslocks.nim new file mode 100644 index 000000000..fa4164b95 --- /dev/null +++ b/lib/system/syslocks.nim @@ -0,0 +1,226 @@ +# +# +# Nim's Runtime Library +# (c) Copyright 2012 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +# Low level system locks and condition vars. + +{.push stackTrace: off.} + +when defined(Windows): + type + Handle = int + + SysLock {.importc: "CRITICAL_SECTION", + header: "", final, pure.} = object # CRITICAL_SECTION in WinApi + DebugInfo: pointer + LockCount: int32 + RecursionCount: int32 + OwningThread: int + LockSemaphore: int + SpinCount: int + + SysCond = Handle + + proc initSysLock(L: var SysLock) {.importc: "InitializeCriticalSection", + header: "".} + ## Initializes the lock `L`. + + proc tryAcquireSysAux(L: var SysLock): int32 {.importc: "TryEnterCriticalSection", + header: "".} + ## Tries to acquire the lock `L`. + + proc tryAcquireSys(L: var SysLock): bool {.inline.} = + result = tryAcquireSysAux(L) != 0'i32 + + proc acquireSys(L: var SysLock) {.importc: "EnterCriticalSection", + header: "".} + ## Acquires the lock `L`. + + proc releaseSys(L: var SysLock) {.importc: "LeaveCriticalSection", + header: "".} + ## Releases the lock `L`. + + proc deinitSys(L: var SysLock) {.importc: "DeleteCriticalSection", + header: "".} + + proc createEvent(lpEventAttributes: pointer, + bManualReset, bInitialState: int32, + lpName: cstring): SysCond {.stdcall, noSideEffect, + dynlib: "kernel32", importc: "CreateEventA".} + + proc closeHandle(hObject: Handle) {.stdcall, noSideEffect, + dynlib: "kernel32", importc: "CloseHandle".} + proc waitForSingleObject(hHandle: Handle, dwMilliseconds: int32): int32 {. + stdcall, dynlib: "kernel32", importc: "WaitForSingleObject", noSideEffect.} + + proc signalSysCond(hEvent: SysCond) {.stdcall, noSideEffect, + dynlib: "kernel32", importc: "SetEvent".} + + proc initSysCond(cond: var SysCond) {.inline.} = + cond = createEvent(nil, 0'i32, 0'i32, nil) + proc deinitSysCond(cond: var SysCond) {.inline.} = + closeHandle(cond) + proc waitSysCond(cond: var SysCond, lock: var SysLock) = + releaseSys(lock) + discard waitForSingleObject(cond, -1'i32) + acquireSys(lock) + + proc waitSysCondWindows(cond: var SysCond) = + discard waitForSingleObject(cond, -1'i32) + +elif defined(genode): + const + Header = "genode_cpp/syslocks.h" + type + SysLock {.importcpp: "Nim::SysLock", pure, final, + header: Header.} = object + SysCond {.importcpp: "Nim::SysCond", pure, final, + header: Header.} = object + + proc initSysLock(L: var SysLock) = discard + proc deinitSys(L: var SysLock) = discard + proc acquireSys(L: var SysLock) {.noSideEffect, importcpp.} + proc tryAcquireSys(L: var SysLock): bool {.noSideEffect, importcpp.} + proc releaseSys(L: var SysLock) {.noSideEffect, importcpp.} + + proc initSysCond(L: var SysCond) = discard + proc deinitSysCond(L: var SysCond) = discard + proc waitSysCond(cond: var SysCond, lock: var SysLock) {. + noSideEffect, importcpp.} + proc signalSysCond(cond: var SysCond) {. + noSideEffect, importcpp.} + +else: + type + SysLockObj {.importc: "pthread_mutex_t", pure, final, + header: """#include + #include """.} = object + when defined(linux) and defined(amd64): + abi: array[40 div sizeof(clong), clong] + + SysLockAttr {.importc: "pthread_mutexattr_t", pure, final + header: """#include + #include """.} = object + when defined(linux) and defined(amd64): + abi: array[4 div sizeof(cint), cint] # actually a cint + + SysCondObj {.importc: "pthread_cond_t", pure, final, + header: """#include + #include """.} = object + when defined(linux) and defined(amd64): + abi: array[48 div sizeof(clonglong), clonglong] + + SysCondAttr {.importc: "pthread_condattr_t", pure, final + header: """#include + #include """.} = object + when defined(linux) and defined(amd64): + abi: array[4 div sizeof(cint), cint] # actually a cint + + SysLockType = distinct cint + + proc initSysLockAux(L: var SysLockObj, attr: ptr SysLockAttr) {. + importc: "pthread_mutex_init", header: "", noSideEffect.} + proc deinitSysAux(L: var SysLockObj) {.noSideEffect, + importc: "pthread_mutex_destroy", header: "".} + + proc acquireSysAux(L: var SysLockObj) {.noSideEffect, + importc: "pthread_mutex_lock", header: "".} + proc tryAcquireSysAux(L: var SysLockObj): cint {.noSideEffect, + importc: "pthread_mutex_trylock", header: "".} + + proc releaseSysAux(L: var SysLockObj) {.noSideEffect, + importc: "pthread_mutex_unlock", header: "".} + + when defined(ios): + # iOS will behave badly if sync primitives are moved in memory. In order + # to prevent this once and for all, we're doing an extra malloc when + # initializing the primitive. + type + SysLock = ptr SysLockObj + SysCond = ptr SysCondObj + + when not declared(c_malloc): + proc c_malloc(size: csize): pointer {. + importc: "malloc", header: "".} + proc c_free(p: pointer) {. + importc: "free", header: "".} + + proc initSysLock(L: var SysLock, attr: ptr SysLockAttr = nil) = + L = cast[SysLock](c_malloc(sizeof(SysLockObj))) + initSysLockAux(L[], attr) + + proc deinitSys(L: var SysLock) = + deinitSysAux(L[]) + c_free(L) + + template acquireSys(L: var SysLock) = + acquireSysAux(L[]) + template tryAcquireSys(L: var SysLock): bool = + tryAcquireSysAux(L[]) == 0'i32 + template releaseSys(L: var SysLock) = + releaseSysAux(L[]) + else: + type + SysLock = SysLockObj + SysCond = SysCondObj + + template initSysLock(L: var SysLock, attr: ptr SysLockAttr = nil) = + initSysLockAux(L, attr) + template deinitSys(L: var SysLock) = + deinitSysAux(L) + template acquireSys(L: var SysLock) = + acquireSysAux(L) + template tryAcquireSys(L: var SysLock): bool = + tryAcquireSysAux(L) == 0'i32 + template releaseSys(L: var SysLock) = + releaseSysAux(L) + + when insideRLocksModule: + proc SysLockType_Reentrant: SysLockType = + {.emit: "`result` = PTHREAD_MUTEX_RECURSIVE;".} + proc initSysLockAttr(a: var SysLockAttr) {. + importc: "pthread_mutexattr_init", header: "", noSideEffect.} + proc setSysLockType(a: var SysLockAttr, t: SysLockType) {. + importc: "pthread_mutexattr_settype", header: "", noSideEffect.} + + else: + proc initSysCondAux(cond: var SysCondObj, cond_attr: ptr SysCondAttr = nil) {. + importc: "pthread_cond_init", header: "", noSideEffect.} + proc deinitSysCondAux(cond: var SysCondObj) {.noSideEffect, + importc: "pthread_cond_destroy", header: "".} + + proc waitSysCondAux(cond: var SysCondObj, lock: var SysLockObj) {. + importc: "pthread_cond_wait", header: "", noSideEffect.} + proc signalSysCondAux(cond: var SysCondObj) {. + importc: "pthread_cond_signal", header: "", noSideEffect.} + + when defined(ios): + proc initSysCond(cond: var SysCond, cond_attr: ptr SysCondAttr = nil) = + cond = cast[SysCond](c_malloc(sizeof(SysCondObj))) + initSysCondAux(cond[], cond_attr) + + proc deinitSysCond(cond: var SysCond) = + deinitSysCondAux(cond[]) + c_free(cond) + + template waitSysCond(cond: var SysCond, lock: var SysLock) = + waitSysCondAux(cond[], lock[]) + template signalSysCond(cond: var SysCond) = + signalSysCondAux(cond[]) + else: + template initSysCond(cond: var SysCond, cond_attr: ptr SysCondAttr = nil) = + initSysCondAux(cond, cond_attr) + template deinitSysCond(cond: var SysCond) = + deinitSysCondAux(cond) + + template waitSysCond(cond: var SysCond, lock: var SysLock) = + waitSysCondAux(cond, lock) + template signalSysCond(cond: var SysCond) = + signalSysCondAux(cond) + +{.pop.} diff --git a/lib/system/sysspawn.nim b/lib/system/sysspawn.nim new file mode 100644 index 000000000..dc2d13578 --- /dev/null +++ b/lib/system/sysspawn.nim @@ -0,0 +1,194 @@ +# +# +# Nim's Runtime Library +# (c) Copyright 2015 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +## Implements Nim's 'spawn'. + +when not declared(NimString): + {.error: "You must not import this module explicitly".} + +{.push stackTrace:off.} + +# We declare our own condition variables here to get rid of the dummy lock +# on Windows: + +type + CondVar = object + c: SysCond + when defined(posix): + stupidLock: SysLock + counter: int + +proc createCondVar(): CondVar = + initSysCond(result.c) + when defined(posix): + initSysLock(result.stupidLock) + #acquireSys(result.stupidLock) + +proc destroyCondVar(c: var CondVar) {.inline.} = + deinitSysCond(c.c) + +proc await(cv: var CondVar) = + when defined(posix): + acquireSys(cv.stupidLock) + while cv.counter <= 0: + waitSysCond(cv.c, cv.stupidLock) + dec cv.counter + releaseSys(cv.stupidLock) + else: + waitSysCondWindows(cv.c) + +proc signal(cv: var CondVar) = + when defined(posix): + acquireSys(cv.stupidLock) + inc cv.counter + releaseSys(cv.stupidLock) + signalSysCond(cv.c) + +type + FastCondVar = object + event, slowPath: bool + slow: CondVar + +proc createFastCondVar(): FastCondVar = + initSysCond(result.slow.c) + when defined(posix): + initSysLock(result.slow.stupidLock) + #acquireSys(result.slow.stupidLock) + result.event = false + result.slowPath = false + +proc await(cv: var FastCondVar) = + #for i in 0 .. 50: + # if cas(addr cv.event, true, false): + # # this is a HIT: Triggers > 95% in my tests. + # return + # cpuRelax() + #cv.slowPath = true + # XXX For some reason this crashes some test programs + await(cv.slow) + cv.event = false + +proc signal(cv: var FastCondVar) = + cv.event = true + #if cas(addr cv.slowPath, true, false): + signal(cv.slow) + +type + Barrier* {.compilerProc.} = object + counter: int + cv: CondVar + +proc barrierEnter*(b: ptr Barrier) {.compilerProc.} = + atomicInc b.counter + +proc barrierLeave*(b: ptr Barrier) {.compilerProc.} = + atomicDec b.counter + if b.counter <= 0: signal(b.cv) + +proc openBarrier*(b: ptr Barrier) {.compilerProc.} = + b.counter = 0 + b.cv = createCondVar() + +proc closeBarrier*(b: ptr Barrier) {.compilerProc.} = + await(b.cv) + destroyCondVar(b.cv) + +{.pop.} + +# ---------------------------------------------------------------------------- + +type + WorkerProc = proc (thread, args: pointer) {.nimcall, gcsafe.} + Worker = object + taskArrived: CondVar + taskStarted: FastCondVar #\ + # task data: + f: WorkerProc + data: pointer + ready: bool # put it here for correct alignment! + +proc nimArgsPassingDone(p: pointer) {.compilerProc.} = + let w = cast[ptr Worker](p) + signal(w.taskStarted) + +var gSomeReady = createFastCondVar() + +proc slave(w: ptr Worker) {.thread.} = + while true: + w.ready = true # If we instead signal "workerReady" we need the scheduler + # to notice this. The scheduler could then optimize the + # layout of the worker threads (e.g. keep the list sorted) + # so that no search for a "ready" thread is necessary. + # This might be implemented later, but is more tricky than + # it looks because 'spawn' itself can run concurrently. + signal(gSomeReady) + await(w.taskArrived) + assert(not w.ready) + # shield against spurious wakeups: + if w.data != nil: + w.f(w, w.data) + w.data = nil + +const NumThreads = 4 + +var + workers: array[NumThreads, Thread[ptr Worker]] + workersData: array[NumThreads, Worker] + +proc setup() = + for i in 0 ..< NumThreads: + workersData[i].taskArrived = createCondVar() + workersData[i].taskStarted = createFastCondVar() + createThread(workers[i], slave, addr(workersData[i])) + +proc preferSpawn*(): bool = + ## Use this proc to determine quickly if a 'spawn' or a direct call is + ## preferable. If it returns 'true' a 'spawn' may make sense. In general + ## it is not necessary to call this directly; use 'spawnX' instead. + result = gSomeReady.event + +proc spawn*(call: typed) {.magic: "Spawn".} + ## always spawns a new task, so that the 'call' is never executed on + ## the calling thread. 'call' has to be proc call 'p(...)' where 'p' + ## is gcsafe and has 'void' as the return type. + +template spawnX*(call: typed) = + ## spawns a new task if a CPU core is ready, otherwise executes the + ## call in the calling thread. Usually it is advised to + ## use 'spawn' in order to not block the producer for an unknown + ## amount of time. 'call' has to be proc call 'p(...)' where 'p' + ## is gcsafe and has 'void' as the return type. + if preferSpawn(): spawn call + else: call + +proc nimSpawn(fn: WorkerProc; data: pointer) {.compilerProc.} = + # implementation of 'spawn' that is used by the code generator. + while true: + for i in 0.. high(workers): + let w = addr(workersData[i]) + if cas(addr w.ready, true, false): + w.data = data + w.f = fn + signal(w.taskArrived) + await(w.taskStarted) + return + await(gSomeReady) + +proc sync*() = + ## a simple barrier to wait for all spawn'ed tasks. If you need more elaborate + ## waiting, you have to use an explicit barrier. + while true: + var allReady = true + for i in 0 .. high(workers): + if not allReady: break + allReady = allReady and workersData[i].ready + if allReady: break + await(gSomeReady) + +setup() diff --git a/lib/system/sysstr.nim b/lib/system/sysstr.nim index b8dc7101d..853397e0a 100644 --- a/lib/system/sysstr.nim +++ b/lib/system/sysstr.nim @@ -15,13 +15,6 @@ # we don't use refcounts because that's a behaviour # the programmer may not want - -proc dataPointer(a: PGenericSeq, elemAlign: int): pointer = - cast[pointer](cast[int](a) +% align(GenericSeqSize, elemAlign)) - -proc dataPointer(a: PGenericSeq, elemAlign, elemSize, index: int): pointer = - cast[pointer](cast[int](a) +% align(GenericSeqSize, elemAlign) +% (index*%elemSize)) - proc resize(old: int): int {.inline.} = if old <= 0: result = 4 elif old < 65536: result = old * 2 @@ -91,7 +84,7 @@ proc copyStr(s: NimString, start: int): NimString {.compilerproc.} = proc nimToCStringConv(s: NimString): cstring {.compilerproc, nonReloadable, inline.} = if s == nil or s.len == 0: result = cstring"" - else: result = cast[cstring](addr s.data) + else: result = cstring(addr s.data) proc toNimStr(str: cstring, len: int): NimString {.compilerproc.} = result = rawNewStringNoInit(len) @@ -160,9 +153,13 @@ proc addChar(s: NimString, c: char): NimString = result = s if result.len >= result.space: let r = resize(result.space) - result = rawNewStringNoInit(r) - result.len = s.len - copyMem(addr result.data[0], unsafeAddr(s.data[0]), s.len+1) + when defined(nimIncrSeqV3): + result = rawNewStringNoInit(r) + result.len = s.len + copyMem(addr result.data[0], unsafeAddr(s.data[0]), s.len+1) + else: + result = cast[NimString](growObj(result, + sizeof(TGenericSeq) + r + 1)) result.reserved = r result.data[result.len] = c result.data[result.len+1] = '\0' @@ -206,9 +203,12 @@ proc resizeString(dest: NimString, addlen: int): NimString {.compilerRtl.} = result = dest else: # slow path: let sp = max(resize(dest.space), dest.len + addlen) - result = rawNewStringNoInit(sp) - result.len = dest.len - copyMem(addr result.data[0], unsafeAddr(dest.data[0]), dest.len+1) + when defined(nimIncrSeqV3): + result = rawNewStringNoInit(sp) + result.len = dest.len + copyMem(addr result.data[0], unsafeAddr(dest.data[0]), dest.len+1) + else: + result = cast[NimString](growObj(dest, sizeof(TGenericSeq) + sp + 1)) result.reserved = sp #result = rawNewString(sp) #copyMem(result, dest, dest.len + sizeof(TGenericSeq)) @@ -232,17 +232,20 @@ proc setLengthStr(s: NimString, newLen: int): NimString {.compilerRtl.} = result = s else: let sp = max(resize(s.space), newLen) - result = rawNewStringNoInit(sp) - result.len = s.len - copyMem(addr result.data[0], unsafeAddr(s.data[0]), s.len+1) - zeroMem(addr result.data[s.len], newLen - s.len) - result.reserved = sp + when defined(nimIncrSeqV3): + result = rawNewStringNoInit(sp) + result.len = s.len + copyMem(addr result.data[0], unsafeAddr(s.data[0]), s.len+1) + zeroMem(addr result.data[s.len], newLen - s.len) + result.reserved = sp + else: + result = resizeString(s, n) result.len = n result.data[n] = '\0' # ----------------- sequences ---------------------------------------------- -proc incrSeq(seq: PGenericSeq, elemSize, elemAlign: int): PGenericSeq {.compilerproc.} = +proc incrSeq(seq: PGenericSeq, elemSize: int): PGenericSeq {.compilerproc.} = # increments the length by one: # this is needed for supporting ``add``; # @@ -252,18 +255,23 @@ proc incrSeq(seq: PGenericSeq, elemSize, elemAlign: int): PGenericSeq {.compiler result = seq if result.len >= result.space: let r = resize(result.space) - result = cast[PGenericSeq](growObj(result, align(GenericSeqSize, elemAlign) + elemSize * r)) + result = cast[PGenericSeq](growObj(result, elemSize * r + + GenericSeqSize)) result.reserved = r inc(result.len) -proc incrSeqV2(seq: PGenericSeq, elemSize, elemAlign: int): PGenericSeq {.compilerproc.} = +proc incrSeqV2(seq: PGenericSeq, elemSize: int): PGenericSeq {.compilerproc.} = # incrSeq version 2 result = seq if result.len >= result.space: let r = resize(result.space) - result = cast[PGenericSeq](growObj(result, align(GenericSeqSize, elemAlign) + elemSize * r)) + result = cast[PGenericSeq](growObj(result, elemSize * r + + GenericSeqSize)) result.reserved = r +template `+!`(p: pointer, s: int): pointer = + cast[pointer](cast[int](p) +% s) + proc incrSeqV3(s: PGenericSeq, typ: PNimType): PGenericSeq {.compilerproc.} = if s == nil: result = cast[PGenericSeq](newSeq(typ, 1)) @@ -272,28 +280,46 @@ proc incrSeqV3(s: PGenericSeq, typ: PNimType): PGenericSeq {.compilerproc.} = result = s if result.len >= result.space: let r = resize(result.space) - result = cast[PGenericSeq](newSeq(typ, r)) - result.len = s.len - copyMem(dataPointer(result, typ.base.align), dataPointer(s, typ.base.align), s.len * typ.base.size) - # since we steal the content from 's', it's crucial to set s's len to 0. - s.len = 0 + when defined(nimIncrSeqV3): + result = cast[PGenericSeq](newSeq(typ, r)) + result.len = s.len + copyMem(result +! GenericSeqSize, s +! GenericSeqSize, s.len * typ.base.size) + # since we steal the content from 's', it's crucial to set s's len to 0. + s.len = 0 + else: + result = cast[PGenericSeq](growObj(result, typ.base.size * r + + GenericSeqSize)) + result.reserved = r -proc setLengthSeq(seq: PGenericSeq, elemSize, elemAlign, newLen: int): PGenericSeq {. +proc setLengthSeq(seq: PGenericSeq, elemSize, newLen: int): PGenericSeq {. compilerRtl, inl.} = result = seq if result.space < newLen: let r = max(resize(result.space), newLen) - result = cast[PGenericSeq](growObj(result, align(GenericSeqSize, elemAlign) + elemSize * r)) + result = cast[PGenericSeq](growObj(result, elemSize * r + + GenericSeqSize)) result.reserved = r elif newLen < result.len: # we need to decref here, otherwise the GC leaks! when not defined(boehmGC) and not defined(nogc) and not defined(gcMarkAndSweep) and not defined(gogc) and not defined(gcRegions): - if ntfNoRefs notin extGetCellType(result).base.flags: + when false: # compileOption("gc", "v2"): for i in newLen..result.len-1: - forAllChildrenAux(dataPointer(result, elemAlign, elemSize, i), - extGetCellType(result).base, waZctDecRef) + let len0 = gch.tempStack.len + forAllChildrenAux(cast[pointer](cast[ByteAddress](result) +% + GenericSeqSize +% (i*%elemSize)), + extGetCellType(result).base, waPush) + let len1 = gch.tempStack.len + for i in len0 ..< len1: + doDecRef(gch.tempStack.d[i], LocalHeap, MaybeCyclic) + gch.tempStack.len = len0 + else: + if ntfNoRefs notin extGetCellType(result).base.flags: + for i in newLen..result.len-1: + forAllChildrenAux(cast[pointer](cast[ByteAddress](result) +% + GenericSeqSize +% (i*%elemSize)), + extGetCellType(result).base, waZctDecRef) # XXX: zeroing out the memory can still result in crashes if a wiped-out # cell is aliased by another pointer (ie proc parameter or a let variable). @@ -301,7 +327,8 @@ proc setLengthSeq(seq: PGenericSeq, elemSize, elemAlign, newLen: int): PGenericS # presence of user defined destructors, the user will expect the cell to be # "destroyed" thus creating the same problem. We can destroy the cell in the # finalizer of the sequence, but this makes destruction non-deterministic. - zeroMem(dataPointer(result, elemAlign, elemSize, newLen), (result.len-%newLen) *% elemSize) + zeroMem(cast[pointer](cast[ByteAddress](result) +% GenericSeqSize +% + (newLen*%elemSize)), (result.len-%newLen) *% elemSize) result.len = newLen proc setLengthSeqV2(s: PGenericSeq, typ: PNimType, newLen: int): PGenericSeq {. @@ -310,33 +337,36 @@ proc setLengthSeqV2(s: PGenericSeq, typ: PNimType, newLen: int): PGenericSeq {. if s == nil: result = cast[PGenericSeq](newSeq(typ, newLen)) else: - let elemSize = typ.base.size - let elemAlign = typ.base.align - if s.space < newLen: - let r = max(resize(s.space), newLen) - result = cast[PGenericSeq](newSeq(typ, r)) - copyMem(dataPointer(result, elemAlign), dataPointer(s, elemAlign), s.len * elemSize) - # since we steal the content from 's', it's crucial to set s's len to 0. - s.len = 0 - elif newLen < s.len: - result = s - # we need to decref here, otherwise the GC leaks! - when not defined(boehmGC) and not defined(nogc) and - not defined(gcMarkAndSweep) and not defined(gogc) and - not defined(gcRegions): - if ntfNoRefs notin typ.base.flags: - for i in newLen..result.len-1: - forAllChildrenAux(dataPointer(result, elemAlign, elemSize, i), - extGetCellType(result).base, waZctDecRef) + when defined(nimIncrSeqV3): + let elemSize = typ.base.size + if s.space < newLen: + let r = max(resize(s.space), newLen) + result = cast[PGenericSeq](newSeq(typ, r)) + copyMem(result +! GenericSeqSize, s +! GenericSeqSize, s.len * elemSize) + # since we steal the content from 's', it's crucial to set s's len to 0. + s.len = 0 + elif newLen < s.len: + result = s + # we need to decref here, otherwise the GC leaks! + when not defined(boehmGC) and not defined(nogc) and + not defined(gcMarkAndSweep) and not defined(gogc) and + not defined(gcRegions): + if ntfNoRefs notin typ.base.flags: + for i in newLen..result.len-1: + forAllChildrenAux(cast[pointer](cast[ByteAddress](result) +% + GenericSeqSize +% (i*%elemSize)), + extGetCellType(result).base, waZctDecRef) - # XXX: zeroing out the memory can still result in crashes if a wiped-out - # cell is aliased by another pointer (ie proc parameter or a let variable). - # This is a tough problem, because even if we don't zeroMem here, in the - # presence of user defined destructors, the user will expect the cell to be - # "destroyed" thus creating the same problem. We can destroy the cell in the - # finalizer of the sequence, but this makes destruction non-deterministic. - zeroMem(dataPointer(result, elemAlign, elemSize, newLen), (result.len-%newLen) *% elemSize) + # XXX: zeroing out the memory can still result in crashes if a wiped-out + # cell is aliased by another pointer (ie proc parameter or a let variable). + # This is a tough problem, because even if we don't zeroMem here, in the + # presence of user defined destructors, the user will expect the cell to be + # "destroyed" thus creating the same problem. We can destroy the cell in the + # finalizer of the sequence, but this makes destruction non-deterministic. + zeroMem(cast[pointer](cast[ByteAddress](result) +% GenericSeqSize +% + (newLen*%elemSize)), (result.len-%newLen) *% elemSize) + else: + result = s + result.len = newLen else: - result = s - zeroMem(dataPointer(result, elemAlign, elemSize, result.len), (newLen-%result.len) *% elemSize) - result.len = newLen + result = setLengthSeq(s, typ.base.size, newLen) diff --git a/lib/system/threadids.nim b/lib/system/threadids.nim deleted file mode 100644 index 3a6eadcbb..000000000 --- a/lib/system/threadids.nim +++ /dev/null @@ -1,103 +0,0 @@ -# -# -# Nim's Runtime Library -# (c) Copyright 2020 Andreas Rumpf -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# - -# we need to cache current threadId to not perform syscall all the time -var threadId {.threadvar.}: int - -when defined(windows): - proc getCurrentThreadId(): int32 {. - stdcall, dynlib: "kernel32", importc: "GetCurrentThreadId".} - - proc getThreadId*(): int = - ## Gets the ID of the currently running thread. - if threadId == 0: - threadId = int(getCurrentThreadId()) - result = threadId - -elif defined(linux): - proc syscall(arg: clong): clong {.varargs, importc: "syscall", header: "".} - when defined(amd64): - const NR_gettid = clong(186) - else: - var NR_gettid {.importc: "__NR_gettid", header: "".}: clong - - proc getThreadId*(): int = - ## Gets the ID of the currently running thread. - if threadId == 0: - threadId = int(syscall(NR_gettid)) - result = threadId - -elif defined(dragonfly): - proc lwp_gettid(): int32 {.importc, header: "unistd.h".} - - proc getThreadId*(): int = - ## Gets the ID of the currently running thread. - if threadId == 0: - threadId = int(lwp_gettid()) - result = threadId - -elif defined(openbsd): - proc getthrid(): int32 {.importc: "getthrid", header: "".} - - proc getThreadId*(): int = - ## Gets the ID of the currently running thread. - if threadId == 0: - threadId = int(getthrid()) - result = threadId - -elif defined(netbsd): - proc lwp_self(): int32 {.importc: "_lwp_self", header: "".} - - proc getThreadId*(): int = - ## Gets the ID of the currently running thread. - if threadId == 0: - threadId = int(lwp_self()) - result = threadId - -elif defined(freebsd): - proc syscall(arg: cint, arg0: ptr cint): cint {.varargs, importc: "syscall", header: "".} - var SYS_thr_self {.importc:"SYS_thr_self", header:"".}: cint - - proc getThreadId*(): int = - ## Gets the ID of the currently running thread. - var tid = 0.cint - if threadId == 0: - discard syscall(SYS_thr_self, addr tid) - threadId = tid - result = threadId - -elif defined(macosx): - proc syscall(arg: cint): cint {.varargs, importc: "syscall", header: "".} - var SYS_thread_selfid {.importc:"SYS_thread_selfid", header:"".}: cint - - proc getThreadId*(): int = - ## Gets the ID of the currently running thread. - if threadId == 0: - threadId = int(syscall(SYS_thread_selfid)) - result = threadId - -elif defined(solaris): - type thread_t {.importc: "thread_t", header: "".} = distinct int - proc thr_self(): thread_t {.importc, header: "".} - - proc getThreadId*(): int = - ## Gets the ID of the currently running thread. - if threadId == 0: - threadId = int(thr_self()) - result = threadId - -elif defined(haiku): - type thr_id {.importc: "thread_id", header: "".} = distinct int32 - proc find_thread(name: cstring): thr_id {.importc, header: "".} - - proc getThreadId*(): int = - ## Gets the ID of the currently running thread. - if threadId == 0: - threadId = int(find_thread(nil)) - result = threadId diff --git a/lib/system/threadimpl.nim b/lib/system/threadimpl.nim deleted file mode 100644 index 94db23336..000000000 --- a/lib/system/threadimpl.nim +++ /dev/null @@ -1,116 +0,0 @@ -var - nimThreadDestructionHandlers* {.rtlThreadVar.}: seq[proc () {.closure, gcsafe, raises: [].}] -when not defined(boehmgc) and not hasSharedHeap and not defined(gogc) and not defined(gcRegions): - proc deallocOsPages() {.rtl, raises: [].} -proc threadTrouble() {.raises: [], gcsafe.} -# create for the main thread. Note: do not insert this data into the list -# of all threads; it's not to be stopped etc. -when not defined(useNimRtl): - #when not defined(createNimRtl): initStackBottom() - when declared(initGC): - initGC() - when not emulatedThreadVars: - type ThreadType {.pure.} = enum - None = 0, - NimThread = 1, - ForeignThread = 2 - var - threadType {.rtlThreadVar.}: ThreadType - - threadType = ThreadType.NimThread - -when defined(gcDestructors): - proc allocThreadStorage(size: int): pointer = - result = c_malloc(csize_t size) - zeroMem(result, size) - - proc deallocThreadStorage(p: pointer) = c_free(p) -else: - template allocThreadStorage(size: untyped): untyped = allocShared0(size) - template deallocThreadStorage(p: pointer) = deallocShared(p) - -template afterThreadRuns() = - for i in countdown(nimThreadDestructionHandlers.len-1, 0): - nimThreadDestructionHandlers[i]() - -proc onThreadDestruction*(handler: proc () {.closure, gcsafe, raises: [].}) = - ## Registers a *thread local* handler that is called at the thread's - ## destruction. - ## - ## A thread is destructed when the `.thread` proc returns - ## normally or when it raises an exception. Note that unhandled exceptions - ## in a thread nevertheless cause the whole process to die. - nimThreadDestructionHandlers.add handler - -when defined(boehmgc): - type GCStackBaseProc = proc(sb: pointer, t: pointer) {.noconv.} - proc boehmGC_call_with_stack_base(sbp: GCStackBaseProc, p: pointer) - {.importc: "GC_call_with_stack_base", boehmGC.} - proc boehmGC_register_my_thread(sb: pointer) - {.importc: "GC_register_my_thread", boehmGC.} - proc boehmGC_unregister_my_thread() - {.importc: "GC_unregister_my_thread", boehmGC.} - - proc threadProcWrapDispatch[TArg](sb: pointer, thrd: pointer) {.noconv, raises: [].} = - boehmGC_register_my_thread(sb) - try: - let thrd = cast[ptr Thread[TArg]](thrd) - when TArg is void: - thrd.dataFn() - else: - thrd.dataFn(thrd.data) - except: - threadTrouble() - finally: - afterThreadRuns() - boehmGC_unregister_my_thread() -else: - proc threadProcWrapDispatch[TArg](thrd: ptr Thread[TArg]) {.raises: [].} = - try: - when TArg is void: - thrd.dataFn() - else: - when defined(nimV2): - thrd.dataFn(thrd.data) - else: - var x: TArg - deepCopy(x, thrd.data) - thrd.dataFn(x) - except: - threadTrouble() - finally: - afterThreadRuns() - when hasAllocStack: - deallocThreadStorage(thrd.rawStack) - -proc threadProcWrapStackFrame[TArg](thrd: ptr Thread[TArg]) {.raises: [].} = - when defined(boehmgc): - boehmGC_call_with_stack_base(threadProcWrapDispatch[TArg], thrd) - elif not defined(nogc) and not defined(gogc) and not defined(gcRegions) and not usesDestructors: - var p {.volatile.}: pointer - # init the GC for refc/markandsweep - nimGC_setStackBottom(addr(p)) - when declared(initGC): - initGC() - when declared(threadType): - threadType = ThreadType.NimThread - threadProcWrapDispatch[TArg](thrd) - when declared(deallocOsPages): deallocOsPages() - else: - threadProcWrapDispatch(thrd) - -template nimThreadProcWrapperBody*(closure: untyped): untyped = - var thrd = cast[ptr Thread[TArg]](closure) - var core = thrd.core - when declared(globalsSlot): threadVarSetValue(globalsSlot, thrd.core) - threadProcWrapStackFrame(thrd) - # Since an unhandled exception terminates the whole process (!), there is - # no need for a ``try finally`` here, nor would it be correct: The current - # exception is tried to be re-raised by the code-gen after the ``finally``! - # However this is doomed to fail, because we already unmapped every heap - # page! - - # mark as not running anymore: - thrd.core = nil - thrd.dataFn = nil - deallocThreadStorage(cast[pointer](core)) diff --git a/lib/system/threadlocalstorage.nim b/lib/system/threadlocalstorage.nim index e6ad9dca5..117af4c25 100644 --- a/lib/system/threadlocalstorage.nim +++ b/lib/system/threadlocalstorage.nim @@ -1,33 +1,83 @@ -import std/private/threadtypes when defined(windows): type - ThreadVarSlot = distinct int32 + SysThread* = Handle + WinThreadProc = proc (x: pointer): int32 {.stdcall.} - proc threadVarAlloc(): ThreadVarSlot {. - importc: "TlsAlloc", stdcall, header: "".} - proc threadVarSetValue(dwTlsIndex: ThreadVarSlot, lpTlsValue: pointer) {. - importc: "TlsSetValue", stdcall, header: "".} - proc tlsGetValue(dwTlsIndex: ThreadVarSlot): pointer {. - importc: "TlsGetValue", stdcall, header: "".} + proc createThread(lpThreadAttributes: pointer, dwStackSize: int32, + lpStartAddress: WinThreadProc, + lpParameter: pointer, + dwCreationFlags: int32, + lpThreadId: var int32): SysThread {. + stdcall, dynlib: "kernel32", importc: "CreateThread".} - proc getLastError(): uint32 {. - importc: "GetLastError", stdcall, header: "".} - proc setLastError(x: uint32) {. - importc: "SetLastError", stdcall, header: "".} + proc winSuspendThread(hThread: SysThread): int32 {. + stdcall, dynlib: "kernel32", importc: "SuspendThread".} - proc threadVarGetValue(dwTlsIndex: ThreadVarSlot): pointer = - let realLastError = getLastError() - result = tlsGetValue(dwTlsIndex) - setLastError(realLastError) + proc winResumeThread(hThread: SysThread): int32 {. + stdcall, dynlib: "kernel32", importc: "ResumeThread".} -elif defined(genode): - const - GenodeHeader = "genode_cpp/threads.h" + proc waitForMultipleObjects(nCount: int32, + lpHandles: ptr SysThread, + bWaitAll: int32, + dwMilliseconds: int32): int32 {. + stdcall, dynlib: "kernel32", importc: "WaitForMultipleObjects".} + + proc terminateThread(hThread: SysThread, dwExitCode: int32): int32 {. + stdcall, dynlib: "kernel32", importc: "TerminateThread".} + + proc getCurrentThreadId(): int32 {. + stdcall, dynlib: "kernel32", importc: "GetCurrentThreadId".} type + ThreadVarSlot = distinct int32 + + when true: + proc threadVarAlloc(): ThreadVarSlot {. + importc: "TlsAlloc", stdcall, header: "".} + proc threadVarSetValue(dwTlsIndex: ThreadVarSlot, lpTlsValue: pointer) {. + importc: "TlsSetValue", stdcall, header: "".} + proc tlsGetValue(dwTlsIndex: ThreadVarSlot): pointer {. + importc: "TlsGetValue", stdcall, header: "".} + + proc getLastError(): uint32 {. + importc: "GetLastError", stdcall, header: "".} + proc setLastError(x: uint32) {. + importc: "SetLastError", stdcall, header: "".} + + proc threadVarGetValue(dwTlsIndex: ThreadVarSlot): pointer = + let realLastError = getLastError() + result = tlsGetValue(dwTlsIndex) + setLastError(realLastError) + else: + proc threadVarAlloc(): ThreadVarSlot {. + importc: "TlsAlloc", stdcall, dynlib: "kernel32".} + proc threadVarSetValue(dwTlsIndex: ThreadVarSlot, lpTlsValue: pointer) {. + importc: "TlsSetValue", stdcall, dynlib: "kernel32".} + proc threadVarGetValue(dwTlsIndex: ThreadVarSlot): pointer {. + importc: "TlsGetValue", stdcall, dynlib: "kernel32".} + + proc setThreadAffinityMask(hThread: SysThread, dwThreadAffinityMask: uint) {. + importc: "SetThreadAffinityMask", stdcall, header: "".} + +elif defined(genode): + import genode/env + const + GenodeHeader = "genode_cpp/threads.h" + type + SysThread* {.importcpp: "Nim::SysThread", + header: GenodeHeader, final, pure.} = object + GenodeThreadProc = proc (x: pointer) {.noconv.} ThreadVarSlot = int + proc initThread(s: var SysThread, + env: GenodeEnv, + stackSize: culonglong, + entry: GenodeThreadProc, + arg: pointer, + affinity: cuint) {. + importcpp: "#.initThread(@)".} + proc threadVarAlloc(): ThreadVarSlot = 0 proc offMainThread(): bool {. @@ -63,18 +113,60 @@ else: when not defined(haiku): {.passc: "-pthread".} + const + schedh = "#define _GNU_SOURCE\n#include " + pthreadh = "#define _GNU_SOURCE\n#include " + + when not declared(Time): + when defined(linux): + type Time = clong + else: + type Time = int + when (defined(linux) or defined(nintendoswitch)) and defined(amd64): type + SysThread* {.importc: "pthread_t", + header: "" .} = distinct culong + Pthread_attr {.importc: "pthread_attr_t", + header: "".} = object + abi: array[56 div sizeof(clong), clong] ThreadVarSlot {.importc: "pthread_key_t", header: "".} = distinct cuint elif defined(openbsd) and defined(amd64): type + SysThread* {.importc: "pthread_t", header: "".} = object + Pthread_attr {.importc: "pthread_attr_t", + header: "".} = object ThreadVarSlot {.importc: "pthread_key_t", header: "".} = cint else: type + SysThread* {.importc: "pthread_t", header: "".} = object + Pthread_attr {.importc: "pthread_attr_t", + header: "".} = object ThreadVarSlot {.importc: "pthread_key_t", header: "".} = object + type + Timespec {.importc: "struct timespec", header: "".} = object + tv_sec: Time + tv_nsec: clong + + proc pthread_attr_init(a1: var Pthread_attr): cint {. + importc, header: pthreadh.} + proc pthread_attr_setstacksize(a1: var Pthread_attr, a2: int): cint {. + importc, header: pthreadh.} + proc pthread_attr_destroy(a1: var Pthread_attr): cint {. + importc, header: pthreadh.} + + proc pthread_create(a1: var SysThread, a2: var Pthread_attr, + a3: proc (x: pointer): pointer {.noconv.}, + a4: pointer): cint {.importc: "pthread_create", + header: pthreadh.} + proc pthread_join(a1: SysThread, a2: ptr pointer): cint {. + importc, header: pthreadh.} + + proc pthread_cancel(a1: SysThread): cint {. + importc: "pthread_cancel", header: pthreadh.} proc pthread_getspecific(a1: ThreadVarSlot): pointer {. importc: "pthread_getspecific", header: pthreadh.} @@ -94,13 +186,44 @@ else: proc threadVarGetValue(s: ThreadVarSlot): pointer {.inline.} = result = pthread_getspecific(s) + type CpuSet {.importc: "cpu_set_t", header: schedh.} = object + when defined(linux) and defined(amd64): + abi: array[1024 div (8 * sizeof(culong)), culong] + + proc cpusetZero(s: var CpuSet) {.importc: "CPU_ZERO", header: schedh.} + proc cpusetIncl(cpu: cint; s: var CpuSet) {. + importc: "CPU_SET", header: schedh.} + + proc setAffinity(thread: SysThread; setsize: csize_t; s: var CpuSet) {. + importc: "pthread_setaffinity_np", header: pthreadh.} + + +const + emulatedThreadVars = compileOption("tlsEmulation") when emulatedThreadVars: # the compiler generates this proc for us, so that we can get the size of # the thread local var block; we use this only for sanity checking though proc nimThreadVarsSize(): int {.noconv, importc: "NimThreadVarsSize".} - +# we preallocate a fixed size for thread local storage, so that no heap +# allocations are needed. Currently less than 16K are used on a 64bit machine. +# We use ``float`` for proper alignment: +const nimTlsSize {.intdefine.} = 16000 +type + ThreadLocalStorage = array[0..(nimTlsSize div sizeof(float)), float] + PGcThread = ptr GcThread + GcThread {.pure, inheritable.} = object + when emulatedThreadVars: + tls: ThreadLocalStorage + else: + nil + when hasSharedHeap: + next, prev: PGcThread + stackBottom, stackTop: pointer + stackSize: int + else: + nil when emulatedThreadVars: var globalsSlot: ThreadVarSlot @@ -122,4 +245,4 @@ when not defined(useNimRtl): if nimThreadVarsSize() > sizeof(ThreadLocalStorage): c_fprintf(cstderr, """too large thread local storage size requested, use -d:\"nimTlsSize=X\" to setup even more or stop using unittest.nim""") - rawQuit 1 + quit 1 diff --git a/lib/system/threads.nim b/lib/system/threads.nim new file mode 100644 index 000000000..54b07e467 --- /dev/null +++ b/lib/system/threads.nim @@ -0,0 +1,426 @@ +# +# +# Nim's Runtime Library +# (c) Copyright 2012 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +## Thread support for Nim. +## +## **Note**: This is part of the system module. Do not import it directly. +## To activate thread support you need to compile +## with the ``--threads:on`` command line switch. +## +## Nim's memory model for threads is quite different from other common +## programming languages (C, Pascal): Each thread has its own +## (garbage collected) heap and sharing of memory is restricted. This helps +## to prevent race conditions and improves efficiency. See `the manual for +## details of this memory model `_. +## +## Examples +## ======== +## +## .. code-block:: Nim +## +## import locks +## +## var +## thr: array[0..4, Thread[tuple[a,b: int]]] +## L: Lock +## +## proc threadFunc(interval: tuple[a,b: int]) {.thread.} = +## for i in interval.a..interval.b: +## acquire(L) # lock stdout +## echo i +## release(L) +## +## initLock(L) +## +## for i in 0..high(thr): +## createThread(thr[i], threadFunc, (i*10, i*10+5)) +## joinThreads(thr) + +when not declared(ThisIsSystem): + {.error: "You must not import this module explicitly".} + +const + StackGuardSize = 4096 + ThreadStackMask = + when defined(genode): + 1024*64*sizeof(int)-1 + else: + 1024*256*sizeof(int)-1 + ThreadStackSize = ThreadStackMask+1 - StackGuardSize + +#const globalsSlot = ThreadVarSlot(0) +#sysAssert checkSlot.int == globalsSlot.int + +# create for the main thread. Note: do not insert this data into the list +# of all threads; it's not to be stopped etc. +when not defined(useNimRtl): + #when not defined(createNimRtl): initStackBottom() + when declared(initGC): + initGC() + when not emulatedThreadVars: + type ThreadType {.pure.} = enum + None = 0, + NimThread = 1, + ForeignThread = 2 + var + threadType {.rtlThreadVar.}: ThreadType + + threadType = ThreadType.NimThread + +# We jump through some hops here to ensure that Nim thread procs can have +# the Nim calling convention. This is needed because thread procs are +# ``stdcall`` on Windows and ``noconv`` on UNIX. Alternative would be to just +# use ``stdcall`` since it is mapped to ``noconv`` on UNIX anyway. + +type + Thread* {.pure, final.}[TArg] = object + core: PGcThread + sys: SysThread + when TArg is void: + dataFn: proc () {.nimcall, gcsafe.} + else: + dataFn: proc (m: TArg) {.nimcall, gcsafe.} + data: TArg + +var + threadDestructionHandlers {.rtlThreadVar.}: seq[proc () {.closure, gcsafe.}] + +proc onThreadDestruction*(handler: proc () {.closure, gcsafe.}) = + ## Registers a *thread local* handler that is called at the thread's + ## destruction. + ## + ## A thread is destructed when the ``.thread`` proc returns + ## normally or when it raises an exception. Note that unhandled exceptions + ## in a thread nevertheless cause the whole process to die. + when not defined(nimNoNilSeqs): + if threadDestructionHandlers.isNil: + threadDestructionHandlers = @[] + threadDestructionHandlers.add handler + +template afterThreadRuns() = + for i in countdown(threadDestructionHandlers.len-1, 0): + threadDestructionHandlers[i]() + +when not defined(boehmgc) and not hasSharedHeap and not defined(gogc) and not defined(gcRegions): + proc deallocOsPages() {.rtl.} + +when defined(boehmgc): + type GCStackBaseProc = proc(sb: pointer, t: pointer) {.noconv.} + proc boehmGC_call_with_stack_base(sbp: GCStackBaseProc, p: pointer) + {.importc: "GC_call_with_stack_base", boehmGC.} + proc boehmGC_register_my_thread(sb: pointer) + {.importc: "GC_register_my_thread", boehmGC.} + proc boehmGC_unregister_my_thread() + {.importc: "GC_unregister_my_thread", boehmGC.} + + proc threadProcWrapDispatch[TArg](sb: pointer, thrd: pointer) {.noconv.} = + boehmGC_register_my_thread(sb) + try: + let thrd = cast[ptr Thread[TArg]](thrd) + when TArg is void: + thrd.dataFn() + else: + thrd.dataFn(thrd.data) + finally: + afterThreadRuns() + boehmGC_unregister_my_thread() +else: + proc threadProcWrapDispatch[TArg](thrd: ptr Thread[TArg]) = + try: + when TArg is void: + thrd.dataFn() + else: + when defined(nimV2): + thrd.dataFn(thrd.data) + else: + var x: TArg + deepCopy(x, thrd.data) + thrd.dataFn(x) + finally: + afterThreadRuns() + +proc threadProcWrapStackFrame[TArg](thrd: ptr Thread[TArg]) = + when defined(boehmgc): + boehmGC_call_with_stack_base(threadProcWrapDispatch[TArg], thrd) + elif not defined(nogc) and not defined(gogc) and not defined(gcRegions) and not usesDestructors: + var p {.volatile.}: proc(a: ptr Thread[TArg]) {.nimcall, gcsafe.} = + threadProcWrapDispatch[TArg] + # init the GC for refc/markandsweep + nimGC_setStackBottom(addr(p)) + initGC() + when declared(threadType): + threadType = ThreadType.NimThread + p(thrd) + when declared(deallocOsPages): deallocOsPages() + else: + threadProcWrapDispatch(thrd) + +template threadProcWrapperBody(closure: untyped): untyped = + var thrd = cast[ptr Thread[TArg]](closure) + var core = thrd.core + when declared(globalsSlot): threadVarSetValue(globalsSlot, thrd.core) + threadProcWrapStackFrame(thrd) + # Since an unhandled exception terminates the whole process (!), there is + # no need for a ``try finally`` here, nor would it be correct: The current + # exception is tried to be re-raised by the code-gen after the ``finally``! + # However this is doomed to fail, because we already unmapped every heap + # page! + + # mark as not running anymore: + thrd.core = nil + thrd.dataFn = nil + deallocShared(cast[pointer](core)) + +{.push stack_trace:off.} +when defined(windows): + proc threadProcWrapper[TArg](closure: pointer): int32 {.stdcall.} = + threadProcWrapperBody(closure) + # implicitly return 0 +elif defined(genode): + proc threadProcWrapper[TArg](closure: pointer) {.noconv.} = + threadProcWrapperBody(closure) +else: + proc threadProcWrapper[TArg](closure: pointer): pointer {.noconv.} = + threadProcWrapperBody(closure) +{.pop.} + +proc running*[TArg](t: Thread[TArg]): bool {.inline.} = + ## Returns true if `t` is running. + result = t.dataFn != nil + +proc handle*[TArg](t: Thread[TArg]): SysThread {.inline.} = + ## Returns the thread handle of `t`. + result = t.sys + +when hostOS == "windows": + const MAXIMUM_WAIT_OBJECTS = 64 + + proc joinThread*[TArg](t: Thread[TArg]) {.inline.} = + ## Waits for the thread `t` to finish. + discard waitForSingleObject(t.sys, -1'i32) + + proc joinThreads*[TArg](t: varargs[Thread[TArg]]) = + ## Waits for every thread in `t` to finish. + var a: array[MAXIMUM_WAIT_OBJECTS, SysThread] + var k = 0 + while k < len(t): + var count = min(len(t) - k, MAXIMUM_WAIT_OBJECTS) + for i in 0..(count - 1): a[i] = t[i + k].sys + discard waitForMultipleObjects(int32(count), + cast[ptr SysThread](addr(a)), 1, -1) + inc(k, MAXIMUM_WAIT_OBJECTS) + +elif defined(genode): + proc joinThread*[TArg](t: Thread[TArg]) {.importcpp.} + ## Waits for the thread `t` to finish. + + proc joinThreads*[TArg](t: varargs[Thread[TArg]]) = + ## Waits for every thread in `t` to finish. + for i in 0..t.high: joinThread(t[i]) + +else: + proc joinThread*[TArg](t: Thread[TArg]) {.inline.} = + ## Waits for the thread `t` to finish. + discard pthread_join(t.sys, nil) + + proc joinThreads*[TArg](t: varargs[Thread[TArg]]) = + ## Waits for every thread in `t` to finish. + for i in 0..t.high: joinThread(t[i]) + +when false: + # XXX a thread should really release its heap here somehow: + proc destroyThread*[TArg](t: var Thread[TArg]) = + ## Forces the thread `t` to terminate. This is potentially dangerous if + ## you don't have full control over `t` and its acquired resources. + when hostOS == "windows": + discard TerminateThread(t.sys, 1'i32) + else: + discard pthread_cancel(t.sys) + when declared(registerThread): unregisterThread(addr(t)) + t.dataFn = nil + ## if thread `t` already exited, `t.core` will be `null`. + if not isNil(t.core): + deallocShared(t.core) + t.core = nil + +when hostOS == "windows": + proc createThread*[TArg](t: var Thread[TArg], + tp: proc (arg: TArg) {.thread, nimcall.}, + param: TArg) = + ## Creates a new thread `t` and starts its execution. + ## + ## Entry point is the proc `tp`. + ## `param` is passed to `tp`. `TArg` can be ``void`` if you + ## don't need to pass any data to the thread. + t.core = cast[PGcThread](allocShared0(sizeof(GcThread))) + + when TArg isnot void: t.data = param + t.dataFn = tp + when hasSharedHeap: t.core.stackSize = ThreadStackSize + var dummyThreadId: int32 + t.sys = createThread(nil, ThreadStackSize, threadProcWrapper[TArg], + addr(t), 0'i32, dummyThreadId) + if t.sys <= 0: + raise newException(ResourceExhaustedError, "cannot create thread") + + proc pinToCpu*[Arg](t: var Thread[Arg]; cpu: Natural) = + ## Pins a thread to a `CPU`:idx:. + ## + ## In other words sets a thread's `affinity`:idx:. + ## If you don't know what this means, you shouldn't use this proc. + setThreadAffinityMask(t.sys, uint(1 shl cpu)) + +elif defined(genode): + var affinityOffset: cuint = 1 + ## CPU affinity offset for next thread, safe to roll-over. + + proc createThread*[TArg](t: var Thread[TArg], + tp: proc (arg: TArg) {.thread, nimcall.}, + param: TArg) = + t.core = cast[PGcThread](allocShared0(sizeof(GcThread))) + + when TArg isnot void: t.data = param + t.dataFn = tp + when hasSharedHeap: t.stackSize = ThreadStackSize + t.sys.initThread( + runtimeEnv, + ThreadStackSize.culonglong, + threadProcWrapper[TArg], addr(t), affinityOffset) + inc affinityOffset + + proc pinToCpu*[Arg](t: var Thread[Arg]; cpu: Natural) = + {.hint: "cannot change Genode thread CPU affinity after initialization".} + discard + +else: + proc createThread*[TArg](t: var Thread[TArg], + tp: proc (arg: TArg) {.thread, nimcall.}, + param: TArg) = + ## Creates a new thread `t` and starts its execution. + ## + ## Entry point is the proc `tp`. `param` is passed to `tp`. + ## `TArg` can be ``void`` if you + ## don't need to pass any data to the thread. + t.core = cast[PGcThread](allocShared0(sizeof(GcThread))) + + when TArg isnot void: t.data = param + t.dataFn = tp + when hasSharedHeap: t.core.stackSize = ThreadStackSize + var a {.noinit.}: Pthread_attr + doAssert pthread_attr_init(a) == 0 + doAssert pthread_attr_setstacksize(a, ThreadStackSize) == 0 + if pthread_create(t.sys, a, threadProcWrapper[TArg], addr(t)) != 0: + raise newException(ResourceExhaustedError, "cannot create thread") + doAssert pthread_attr_destroy(a) == 0 + + proc pinToCpu*[Arg](t: var Thread[Arg]; cpu: Natural) = + ## Pins a thread to a `CPU`:idx:. + ## + ## In other words sets a thread's `affinity`:idx:. + ## If you don't know what this means, you shouldn't use this proc. + when not defined(macosx): + var s {.noinit.}: CpuSet + cpusetZero(s) + cpusetIncl(cpu.cint, s) + setAffinity(t.sys, csize_t(sizeof(s)), s) + +proc createThread*(t: var Thread[void], tp: proc () {.thread, nimcall.}) = + createThread[void](t, tp) + +# we need to cache current threadId to not perform syscall all the time +var threadId {.threadvar.}: int + +when defined(windows): + proc getThreadId*(): int = + ## Gets the ID of the currently running thread. + if threadId == 0: + threadId = int(getCurrentThreadId()) + result = threadId + +elif defined(linux): + proc syscall(arg: clong): clong {.varargs, importc: "syscall", header: "".} + when defined(amd64): + const NR_gettid = clong(186) + else: + var NR_gettid {.importc: "__NR_gettid", header: "".}: clong + + proc getThreadId*(): int = + ## Gets the ID of the currently running thread. + if threadId == 0: + threadId = int(syscall(NR_gettid)) + result = threadId + +elif defined(dragonfly): + proc lwp_gettid(): int32 {.importc, header: "unistd.h".} + + proc getThreadId*(): int = + ## Gets the ID of the currently running thread. + if threadId == 0: + threadId = int(lwp_gettid()) + result = threadId + +elif defined(openbsd): + proc getthrid(): int32 {.importc: "getthrid", header: "".} + + proc getThreadId*(): int = + ## get the ID of the currently running thread. + if threadId == 0: + threadId = int(getthrid()) + result = threadId + +elif defined(netbsd): + proc lwp_self(): int32 {.importc: "_lwp_self", header: "".} + + proc getThreadId*(): int = + ## Gets the ID of the currently running thread. + if threadId == 0: + threadId = int(lwp_self()) + result = threadId + +elif defined(freebsd): + proc syscall(arg: cint, arg0: ptr cint): cint {.varargs, importc: "syscall", header: "".} + var SYS_thr_self {.importc:"SYS_thr_self", header:""}: cint + + proc getThreadId*(): int = + ## Gets the ID of the currently running thread. + var tid = 0.cint + if threadId == 0: + discard syscall(SYS_thr_self, addr tid) + threadId = tid + result = threadId + +elif defined(macosx): + proc syscall(arg: cint): cint {.varargs, importc: "syscall", header: "".} + var SYS_thread_selfid {.importc:"SYS_thread_selfid", header:"".}: cint + + proc getThreadId*(): int = + ## Gets the ID of the currently running thread. + if threadId == 0: + threadId = int(syscall(SYS_thread_selfid)) + result = threadId + +elif defined(solaris): + type thread_t {.importc: "thread_t", header: "".} = distinct int + proc thr_self(): thread_t {.importc, header: "".} + + proc getThreadId*(): int = + ## Gets the ID of the currently running thread. + if threadId == 0: + threadId = int(thr_self()) + result = threadId + +elif defined(haiku): + type thr_id {.importc: "thread_id", header: "".} = distinct int32 + proc find_thread(name: cstring): thr_id {.importc, header: "".} + + proc getThreadId*(): int = + ## Gets the ID of the currently running thread. + if threadId == 0: + threadId = int(find_thread(nil)) + result = threadId diff --git a/lib/system/widestrs.nim b/lib/system/widestrs.nim new file mode 100644 index 000000000..3048de82a --- /dev/null +++ b/lib/system/widestrs.nim @@ -0,0 +1,211 @@ +# +# +# Nim's Runtime Library +# (c) Copyright 2012 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +# Nim support for C/C++'s `wide strings`:idx:. This is part of the system +# module! Do not import it directly! + +#when not declared(ThisIsSystem): +# {.error: "You must not import this module explicitly".} + +type + Utf16Char* = distinct int16 + +when defined(nimv2): + + type + WideCString* = ptr UncheckedArray[Utf16Char] + + WideCStringObj* = object + bytes: int + data: WideCString + + proc `=destroy`(a: var WideCStringObj) = + if a.data != nil: + deallocShared(a.data) + a.data = nil + + proc `=`(a: var WideCStringObj; b: WideCStringObj) {.error.} + + proc `=sink`(a: var WideCStringObj; b: WideCStringObj) = + a.bytes = b.bytes + a.data = b.data + + proc createWide(a: var WideCStringObj; bytes: int) = + a.bytes = bytes + a.data = cast[typeof(a.data)](allocShared0(bytes)) + + template `[]`*(a: WideCStringObj; idx: int): Utf16Char = a.data[idx] + template `[]=`*(a: WideCStringObj; idx: int; val: Utf16Char) = a.data[idx] = val + + template nullWide(): untyped = WideCStringObj(bytes: 0, data: nil) + + converter toWideCString*(x: WideCStringObj): WideCString {.inline.} = + result = x.data + +else: + template nullWide(): untyped = nil + + type + WideCString* = ref UncheckedArray[Utf16Char] + WideCStringObj* = WideCString + + template createWide(a; L) = + unsafeNew(a, L * 4 + 2) + +proc ord(arg: Utf16Char): int = int(cast[uint16](arg)) + +proc len*(w: WideCString): int = + ## returns the length of a widestring. This traverses the whole string to + ## find the binary zero end marker! + while int16(w[result]) != 0'i16: inc result + +const + UNI_REPLACEMENT_CHAR = Utf16Char(0xFFFD'i16) + UNI_MAX_BMP = 0x0000FFFF + UNI_MAX_UTF16 = 0x0010FFFF + UNI_MAX_UTF32 = 0x7FFFFFFF + UNI_MAX_LEGAL_UTF32 = 0x0010FFFF + + halfShift = 10 + halfBase = 0x0010000 + halfMask = 0x3FF + + UNI_SUR_HIGH_START = 0xD800 + UNI_SUR_HIGH_END = 0xDBFF + UNI_SUR_LOW_START = 0xDC00 + UNI_SUR_LOW_END = 0xDFFF + UNI_REPL = 0xFFFD + +template ones(n: untyped): untyped = ((1 shl n)-1) + +template fastRuneAt(s: cstring, i, L: int, result: untyped, doInc = true) = + ## Returns the unicode character ``s[i]`` in `result`. If ``doInc == true`` + ## `i` is incremented by the number of bytes that have been processed. + bind ones + + if ord(s[i]) <= 127: + result = ord(s[i]) + when doInc: inc(i) + elif ord(s[i]) shr 5 == 0b110: + #assert(ord(s[i+1]) shr 6 == 0b10) + if i <= L - 2: + result = (ord(s[i]) and (ones(5))) shl 6 or (ord(s[i+1]) and ones(6)) + when doInc: inc(i, 2) + else: + result = UNI_REPL + when doInc: inc(i) + elif ord(s[i]) shr 4 == 0b1110: + if i <= L - 3: + #assert(ord(s[i+1]) shr 6 == 0b10) + #assert(ord(s[i+2]) shr 6 == 0b10) + result = (ord(s[i]) and ones(4)) shl 12 or + (ord(s[i+1]) and ones(6)) shl 6 or + (ord(s[i+2]) and ones(6)) + when doInc: inc(i, 3) + else: + result = UNI_REPL + when doInc: inc(i) + elif ord(s[i]) shr 3 == 0b11110: + if i <= L - 4: + #assert(ord(s[i+1]) shr 6 == 0b10) + #assert(ord(s[i+2]) shr 6 == 0b10) + #assert(ord(s[i+3]) shr 6 == 0b10) + result = (ord(s[i]) and ones(3)) shl 18 or + (ord(s[i+1]) and ones(6)) shl 12 or + (ord(s[i+2]) and ones(6)) shl 6 or + (ord(s[i+3]) and ones(6)) + when doInc: inc(i, 4) + else: + result = UNI_REPL + when doInc: inc(i) + else: + result = 0xFFFD + when doInc: inc(i) + +iterator runes(s: cstring, L: int): int = + var + i = 0 + result: int + while i < L: + fastRuneAt(s, i, L, result, true) + yield result + +proc newWideCString*(source: cstring, L: int): WideCStringObj = + createWide(result, L * 4 + 2) + #result = cast[wideCString](alloc(L * 4 + 2)) + var d = 0 + for ch in runes(source, L): + + if ch <= UNI_MAX_BMP: + if ch >= UNI_SUR_HIGH_START and ch <= UNI_SUR_LOW_END: + result[d] = UNI_REPLACEMENT_CHAR + else: + result[d] = cast[Utf16Char](uint16(ch)) + elif ch > UNI_MAX_UTF16: + result[d] = UNI_REPLACEMENT_CHAR + else: + let ch = ch - halfBase + result[d] = cast[Utf16Char](uint16((ch shr halfShift) + UNI_SUR_HIGH_START)) + inc d + result[d] = cast[Utf16Char](uint16((ch and halfMask) + UNI_SUR_LOW_START)) + inc d + result[d] = Utf16Char(0) + +proc newWideCString*(s: cstring): WideCStringObj = + if s.isNil: return nullWide + + result = newWideCString(s, s.len) + +proc newWideCString*(s: string): WideCStringObj = + result = newWideCString(s, s.len) + +proc `$`*(w: WideCString, estimate: int, replacement: int = 0xFFFD): string = + result = newStringOfCap(estimate + estimate shr 2) + + var i = 0 + while w[i].int16 != 0'i16: + var ch = ord(w[i]) + inc i + if ch >= UNI_SUR_HIGH_START and ch <= UNI_SUR_HIGH_END: + # If the 16 bits following the high surrogate are in the source buffer... + let ch2 = ord(w[i]) + + # If it's a low surrogate, convert to UTF32: + if ch2 >= UNI_SUR_LOW_START and ch2 <= UNI_SUR_LOW_END: + ch = (((ch and halfMask) shl halfShift) + (ch2 and halfMask)) + halfBase + inc i + else: + #invalid UTF-16 + ch = replacement + elif ch >= UNI_SUR_LOW_START and ch <= UNI_SUR_LOW_END: + #invalid UTF-16 + ch = replacement + + if ch < 0x80: + result.add chr(ch) + elif ch < 0x800: + result.add chr((ch shr 6) or 0xc0) + result.add chr((ch and 0x3f) or 0x80) + elif ch < 0x10000: + result.add chr((ch shr 12) or 0xe0) + result.add chr(((ch shr 6) and 0x3f) or 0x80) + result.add chr((ch and 0x3f) or 0x80) + elif ch <= 0x10FFFF: + result.add chr((ch shr 18) or 0xf0) + result.add chr(((ch shr 12) and 0x3f) or 0x80) + result.add chr(((ch shr 6) and 0x3f) or 0x80) + result.add chr((ch and 0x3f) or 0x80) + else: + # replacement char(in case user give very large number): + result.add chr(0xFFFD shr 12 or 0b1110_0000) + result.add chr(0xFFFD shr 6 and ones(6) or 0b10_0000_00) + result.add chr(0xFFFD and ones(6) or 0b10_0000_00) + +proc `$`*(s: WideCString): string = + result = s $ 80 diff --git a/lib/system_overview.rst b/lib/system_overview.rst index cc0643bf1..23284dabf 100644 --- a/lib/system_overview.rst +++ b/lib/system_overview.rst @@ -1,23 +1,19 @@ -.. default-role:: code -.. include:: ../doc/rstcommon.rst - The System module imports several separate modules, and their documentation is in separate files: * `iterators `_ -* `exceptions `_ * `assertions `_ * `dollars `_ -* `ctypes `_ +* `io `_ +* `widestrs `_ Here is a short overview of the most commonly used functions from the `system` module. Function names in the tables below are clickable and will take you to the full documentation of the function. -There are many more functions available than the ones listed in this overview. -Use the table of contents on the left-hand side and/or `Ctrl+F` to navigate -through this module. +The amount of available functions is much larger. Use the table of contents +on the left-hand side and/or `Ctrl+F` to navigate through this module. Strings and characters @@ -39,7 +35,7 @@ Proc Usage * `strutils module `_ for common string functions * `strformat module `_ for string interpolation and formatting * `unicode module `_ for Unicode UTF-8 handling -* `strscans `_ for `scanf` and `scanp` macros, which offer +* `strscans `_ for ``scanf`` and ``scanp`` macros, which offer easier substring extraction than regular expressions * `strtabs module `_ for efficient hash tables (dictionaries, in some programming languages) mapping from strings to strings @@ -49,27 +45,24 @@ Proc Usage Seqs ---- -============================================================= ========================================== -Proc Usage -============================================================= ========================================== -`newSeq<#newSeq>`_ Create a new sequence of a given length -`newSeqOfCap<#newSeqOfCap,Natural>`_ Create a new sequence with zero length - and a given capacity -`setLen<#setLen,seq[T],Natural>`_ Set the length of a sequence -`len<#len,seq[T]>`_ Return the length of a sequence -`@<#@,openArray[T]>`_ Turn an array into a sequence -`add<#add,seq[T],sinkT>`_ Add an item to the sequence -`insert<#insert,seq[T],sinkT>`_ Insert an item at a specific position -`delete<#delete,seq[T],Natural>`_ Delete an item while preserving the - order of elements (`O(n)` operation) -`del<#del,seq[T],Natural>`_ `O(1)` removal, doesn't preserve the order -`pop<#pop,seq[T]>`_ Remove and return last item of a sequence -`x & y<#&,seq[T],seq[T]>`_ Concatenate two sequences -`x[a .. b]<#[],openArray[T],HSlice[U: Ordinal,V: Ordinal]>`_ Slice of a sequence (both ends included) -`x[a .. ^b]<#[],openArray[T],HSlice[U: Ordinal,V: Ordinal]>`_ Slice of a sequence but `b` is a - reversed index (both ends included) -`x[a ..< b]<#[],openArray[T],HSlice[U: Ordinal,V: Ordinal]>`_ Slice of a sequence (excluded upper bound) -============================================================= ========================================== +======================================== ========================================== +Proc Usage +======================================== ========================================== +`newSeq<#newSeq>`_ Create a new sequence of a given length +`newSeqOfCap<#newSeqOfCap,Natural>`_ Create a new sequence with zero length + and a given capacity +`setLen<#setLen,seq[T][T],Natural>`_ Set the length of a sequence +`len<#len,seq[T][T]>`_ Return the length of a sequence +`@<#@,array[IDX,T]>`_ Turn an array into a sequence +`add<#add,seq[T][T],T>`_ Add an item to the sequence +`insert<#insert,seq[T][T],T>`_ Insert an item at a specific position +`delete<#delete,seq[T][T],Natural>`_ Delete an item while preserving the + order of elements (`O(n)` operation) +`del<#del,seq[T][T],Natural>`_ `O(1)` removal, doesn't preserve the order +`pop<#pop,seq[T][T]>`_ Remove and return last item of a sequence +`x & y<#&,seq[T][T],seq[T][T]>`_ Concatenate two sequences +`x[a..b]<#[],openArray[T],HSlice[U,V]>`_ Slice of a sequence (both ends included) +======================================== ========================================== **See also:** * `sequtils module `_ for operations on container @@ -99,7 +92,6 @@ Proc Usage =============================== ====================================== **See also:** -* `setutils module `_ for bit set convenience functions * `sets module `_ for hash sets * `intsets module `_ for efficient int sets @@ -157,21 +149,19 @@ Proc Usage Misc ---- -==================================================== ============================================ -Proc Usage -==================================================== ============================================ -`is<#is,T,S>`_ Check if two arguments are of the same type -`isnot<#isnot.t,untyped,untyped>`_ Negated version of `is` -`!=<#!%3D.t,untyped,untyped>`_ Not equals -`addr<#addr,T>`_ Take the address of a memory location -`T and F<#and,bool,bool>`_ Boolean `and` -`T or F<#or,bool,bool>`_ Boolean `or` -`T xor F<#xor,bool,bool>`_ Boolean `xor` (exclusive or) -`not T<#not,bool>`_ Boolean `not` -`a[^x]<#^.t,int>`_ Take the element at the reversed index `x` -`a .. b<#..,sinkT,sinkU>`_ Binary slice that constructs an interval - `[a, b]` -`a ..^ b<#..^.t,untyped,untyped>`_ Interval `[a, b]` but `b` as reversed index -[a ..< b](#..<.t,untyped,untyped) Interval `[a, b)` (excluded upper bound) -[runnableExamples](#runnableExamples,string,untyped) Create testable documentation -==================================================== ============================================ +============================================= ============================================ +Proc Usage +============================================= ============================================ +`is<#is,T,S>`_ Check if two arguments are of the same type +`isnot<#isnot.t,untyped,untyped>`_ Negated version of `is` +`!=<#!%3D.t,untyped,untyped>`_ Not equals +`addr<#addr,T>`_ Take the address of a memory location +`T and F<#and,bool,bool>`_ Boolean `and` +`T or F<#or,bool,bool>`_ Boolean `or` +`T xor F<#xor,bool,bool>`_ Boolean `xor` (exclusive or) +`not T<#not,bool>`_ Boolean `not` +`a .. b<#..,T,U>`_ Binary slice that constructs an interval + `[a, b]` +[a ..< b](#..<.t,untyped,untyped) Interval `[a, b)` (excluded upper bound) +[runnableExamples](#runnableExamples,untyped) Create testable documentation +============================================= ============================================ diff --git a/lib/windows/registry.nim b/lib/windows/registry.nim index 207172f8c..c17f2f455 100644 --- a/lib/windows/registry.nim +++ b/lib/windows/registry.nim @@ -9,10 +9,7 @@ ## This module is experimental and its interface may change. -import std/oserrors - -when defined(nimPreviewSlimSystem): - import std/widestrs +import winlean, os type HKEY* = uint @@ -49,26 +46,24 @@ template call(f) = proc getUnicodeValue*(path, key: string; handle: HKEY): string = let hh = newWideCString path let kk = newWideCString key - var bufSize: int32 + var bufsize: int32 # try a couple of different flag settings: var flags: int32 = RRF_RT_ANY - let err = regGetValue(handle, hh, kk, flags, nil, nil, addr bufSize) + let err = regGetValue(handle, hh, kk, flags, nil, nil, addr bufsize) if err != 0: var newHandle: HKEY call regOpenKeyEx(handle, hh, 0, KEY_READ or KEY_WOW64_64KEY, newHandle) - call regGetValue(newHandle, nil, kk, flags, nil, nil, addr bufSize) - if bufSize > 0: - var res = newWideCString(bufSize) - call regGetValue(newHandle, nil, kk, flags, nil, addr res[0], - addr bufSize) - result = res $ bufSize + call regGetValue(newHandle, nil, kk, flags, nil, nil, addr bufsize) + var res = newWideCString("", bufsize) + call regGetValue(newHandle, nil, kk, flags, nil, cast[pointer](res), + addr bufsize) + result = res $ bufsize call regCloseKey(newHandle) else: - if bufSize > 0: - var res = newWideCString(bufSize) - call regGetValue(handle, hh, kk, flags, nil, addr res[0], - addr bufSize) - result = res $ bufSize + var res = newWideCString("", bufsize) + call regGetValue(handle, hh, kk, flags, nil, cast[pointer](res), + addr bufsize) + result = res $ bufsize proc regSetValue(key: HKEY, lpSubKey, lpValueName: WideCString, dwType: int32; lpData: WideCString; cbData: int32): int32 {. diff --git a/lib/windows/winlean.nim b/lib/windows/winlean.nim index f8c6ce021..649358cb6 100644 --- a/lib/windows/winlean.nim +++ b/lib/windows/winlean.nim @@ -10,6 +10,8 @@ ## This module implements a small wrapper for some needed Win API procedures, ## so that the Nim compiler does not depend on the huge Windows module. +{.deadCodeElim: on.} # dce option deprecated + import dynlib when defined(nimHasStyleChecks): @@ -17,22 +19,20 @@ when defined(nimHasStyleChecks): {.passc: "-DWIN32_LEAN_AND_MEAN".} -when defined(nimPreviewSlimSystem): - from std/syncio import FileHandle - import std/widestrs +const + useWinUnicode* = not defined(useWinAnsi) -type WinChar* = Utf16Char +when useWinUnicode: + type WinChar* = Utf16Char +else: + type WinChar* = char -# See https://docs.microsoft.com/en-us/windows/win32/winprog/windows-data-types type Handle* = int LONG* = int32 ULONG* = int32 PULONG* = ptr int WINBOOL* = int32 - ## `WINBOOL` uses opposite convention as posix, !=0 meaning success. - # xxx this should be distinct int32, distinct would make code less error prone - PBOOL* = ptr WINBOOL DWORD* = int32 PDWORD* = ptr DWORD LPINT* = ptr int32 @@ -40,14 +40,13 @@ type PULONG_PTR* = ptr uint HDC* = Handle HGLRC* = Handle - BYTE* = uint8 - SECURITY_ATTRIBUTES* = object + SECURITY_ATTRIBUTES* {.final, pure.} = object nLength*: int32 lpSecurityDescriptor*: pointer bInheritHandle*: WINBOOL - STARTUPINFO* = object + STARTUPINFO* {.final, pure.} = object cb*: int32 lpReserved*: cstring lpDesktop*: cstring @@ -67,17 +66,17 @@ type hStdOutput*: Handle hStdError*: Handle - PROCESS_INFORMATION* = object + PROCESS_INFORMATION* {.final, pure.} = object hProcess*: Handle hThread*: Handle dwProcessId*: int32 dwThreadId*: int32 - FILETIME* = object ## CANNOT BE int64 BECAUSE OF ALIGNMENT + FILETIME* {.final, pure.} = object ## CANNOT BE int64 BECAUSE OF ALIGNMENT dwLowDateTime*: DWORD dwHighDateTime*: DWORD - BY_HANDLE_FILE_INFORMATION* = object + BY_HANDLE_FILE_INFORMATION* {.final, pure.} = object dwFileAttributes*: DWORD ftCreationTime*: FILETIME ftLastAccessTime*: FILETIME @@ -89,7 +88,7 @@ type nFileIndexHigh*: DWORD nFileIndexLow*: DWORD - OSVERSIONINFO* = object + OSVERSIONINFO* {.final, pure.} = object dwOSVersionInfoSize*: DWORD dwMajorVersion*: DWORD dwMinorVersion*: DWORD @@ -97,12 +96,6 @@ type dwPlatformId*: DWORD szCSDVersion*: array[0..127, WinChar] - Protoent* = object - p_name*: cstring - p_aliases*: cstringArray - p_proto*: cshort - - const STARTF_USESHOWWINDOW* = 1'i32 STARTF_USESTDHANDLES* = 256'i32 @@ -135,16 +128,12 @@ const CREATE_NO_WINDOW* = 0x08000000'i32 - HANDLE_FLAG_INHERIT* = 0x00000001'i32 - -proc isSuccess*(a: WINBOOL): bool {.inline.} = - ## Returns true if `a != 0`. Windows uses a different convention than POSIX, - ## where `a == 0` is commonly used on success. - a != 0 -proc getVersionExW*(lpVersionInfo: ptr OSVERSIONINFO): WINBOOL {. - stdcall, dynlib: "kernel32", importc: "GetVersionExW", sideEffect.} -proc getVersionExA*(lpVersionInfo: ptr OSVERSIONINFO): WINBOOL {. - stdcall, dynlib: "kernel32", importc: "GetVersionExA", sideEffect.} +when useWinUnicode: + proc getVersionExW*(lpVersionInfo: ptr OSVERSIONINFO): WINBOOL {. + stdcall, dynlib: "kernel32", importc: "GetVersionExW", sideEffect.} +else: + proc getVersionExA*(lpVersionInfo: ptr OSVERSIONINFO): WINBOOL {. + stdcall, dynlib: "kernel32", importc: "GetVersionExA", sideEffect.} proc getVersion*(): DWORD {.stdcall, dynlib: "kernel32", importc: "GetVersion", sideEffect.} @@ -178,14 +167,26 @@ proc peekNamedPipe*(hNamedPipe: Handle, lpBuffer: pointer=nil, lpBytesLeftThisMessage: ptr int32 = nil): bool {. stdcall, dynlib: "kernel32", importc: "PeekNamedPipe".} -proc createProcessW*(lpApplicationName, lpCommandLine: WideCString, - lpProcessAttributes: ptr SECURITY_ATTRIBUTES, - lpThreadAttributes: ptr SECURITY_ATTRIBUTES, - bInheritHandles: WINBOOL, dwCreationFlags: int32, - lpEnvironment, lpCurrentDirectory: WideCString, - lpStartupInfo: var STARTUPINFO, - lpProcessInformation: var PROCESS_INFORMATION): WINBOOL{. - stdcall, dynlib: "kernel32", importc: "CreateProcessW", sideEffect.} +when useWinUnicode: + proc createProcessW*(lpApplicationName, lpCommandLine: WideCString, + lpProcessAttributes: ptr SECURITY_ATTRIBUTES, + lpThreadAttributes: ptr SECURITY_ATTRIBUTES, + bInheritHandles: WINBOOL, dwCreationFlags: int32, + lpEnvironment, lpCurrentDirectory: WideCString, + lpStartupInfo: var STARTUPINFO, + lpProcessInformation: var PROCESS_INFORMATION): WINBOOL{. + stdcall, dynlib: "kernel32", importc: "CreateProcessW", sideEffect.} + +else: + proc createProcessA*(lpApplicationName, lpCommandLine: cstring, + lpProcessAttributes: ptr SECURITY_ATTRIBUTES, + lpThreadAttributes: ptr SECURITY_ATTRIBUTES, + bInheritHandles: WINBOOL, dwCreationFlags: int32, + lpEnvironment: pointer, lpCurrentDirectory: cstring, + lpStartupInfo: var STARTUPINFO, + lpProcessInformation: var PROCESS_INFORMATION): WINBOOL{. + stdcall, dynlib: "kernel32", importc: "CreateProcessA", sideEffect.} + proc suspendThread*(hThread: Handle): int32 {.stdcall, dynlib: "kernel32", importc: "SuspendThread", sideEffect.} @@ -214,37 +215,67 @@ proc getLastError*(): int32 {.importc: "GetLastError", proc setLastError*(error: int32) {.importc: "SetLastError", stdcall, dynlib: "kernel32", sideEffect.} -proc formatMessageW*(dwFlags: int32, lpSource: pointer, +when useWinUnicode: + proc formatMessageW*(dwFlags: int32, lpSource: pointer, + dwMessageId, dwLanguageId: int32, + lpBuffer: pointer, nSize: int32, + arguments: pointer): int32 {. + importc: "FormatMessageW", stdcall, dynlib: "kernel32".} +else: + proc formatMessageA*(dwFlags: int32, lpSource: pointer, dwMessageId, dwLanguageId: int32, lpBuffer: pointer, nSize: int32, arguments: pointer): int32 {. - importc: "FormatMessageW", stdcall, dynlib: "kernel32".} + importc: "FormatMessageA", stdcall, dynlib: "kernel32".} proc localFree*(p: pointer) {. importc: "LocalFree", stdcall, dynlib: "kernel32".} -proc getCurrentDirectoryW*(nBufferLength: int32, - lpBuffer: WideCString): int32 {. - importc: "GetCurrentDirectoryW", dynlib: "kernel32", stdcall, sideEffect.} -proc setCurrentDirectoryW*(lpPathName: WideCString): int32 {. - importc: "SetCurrentDirectoryW", dynlib: "kernel32", stdcall, sideEffect.} -proc createDirectoryW*(pathName: WideCString, security: pointer=nil): int32 {. - importc: "CreateDirectoryW", dynlib: "kernel32", stdcall, sideEffect.} -proc removeDirectoryW*(lpPathName: WideCString): int32 {. - importc: "RemoveDirectoryW", dynlib: "kernel32", stdcall, sideEffect.} -proc setEnvironmentVariableW*(lpName, lpValue: WideCString): int32 {. - stdcall, dynlib: "kernel32", importc: "SetEnvironmentVariableW", sideEffect.} +when useWinUnicode: + proc getCurrentDirectoryW*(nBufferLength: int32, + lpBuffer: WideCString): int32 {. + importc: "GetCurrentDirectoryW", dynlib: "kernel32", stdcall, sideEffect.} + proc setCurrentDirectoryW*(lpPathName: WideCString): int32 {. + importc: "SetCurrentDirectoryW", dynlib: "kernel32", stdcall, sideEffect.} + proc createDirectoryW*(pathName: WideCString, security: pointer=nil): int32 {. + importc: "CreateDirectoryW", dynlib: "kernel32", stdcall, sideEffect.} + proc removeDirectoryW*(lpPathName: WideCString): int32 {. + importc: "RemoveDirectoryW", dynlib: "kernel32", stdcall, sideEffect.} + proc setEnvironmentVariableW*(lpName, lpValue: WideCString): int32 {. + stdcall, dynlib: "kernel32", importc: "SetEnvironmentVariableW", sideEffect.} -proc getModuleFileNameW*(handle: Handle, buf: WideCString, - size: int32): int32 {.importc: "GetModuleFileNameW", - dynlib: "kernel32", stdcall.} + proc getModuleFileNameW*(handle: Handle, buf: WideCString, + size: int32): int32 {.importc: "GetModuleFileNameW", + dynlib: "kernel32", stdcall.} +else: + proc getCurrentDirectoryA*(nBufferLength: int32, lpBuffer: cstring): int32 {. + importc: "GetCurrentDirectoryA", dynlib: "kernel32", stdcall, sideEffect.} + proc setCurrentDirectoryA*(lpPathName: cstring): int32 {. + importc: "SetCurrentDirectoryA", dynlib: "kernel32", stdcall, sideEffect.} + proc createDirectoryA*(pathName: cstring, security: pointer=nil): int32 {. + importc: "CreateDirectoryA", dynlib: "kernel32", stdcall, sideEffect.} + proc removeDirectoryA*(lpPathName: cstring): int32 {. + importc: "RemoveDirectoryA", dynlib: "kernel32", stdcall, sideEffect.} + proc setEnvironmentVariableA*(lpName, lpValue: cstring): int32 {. + stdcall, dynlib: "kernel32", importc: "SetEnvironmentVariableA", sideEffect.} -proc createSymbolicLinkW*(lpSymlinkFileName, lpTargetFileName: WideCString, - flags: DWORD): int32 {. - importc:"CreateSymbolicLinkW", dynlib: "kernel32", stdcall, sideEffect.} -proc createHardLinkW*(lpFileName, lpExistingFileName: WideCString, - security: pointer=nil): int32 {. - importc:"CreateHardLinkW", dynlib: "kernel32", stdcall, sideEffect.} + proc getModuleFileNameA*(handle: Handle, buf: cstring, size: int32): int32 {. + importc: "GetModuleFileNameA", dynlib: "kernel32", stdcall.} + +when useWinUnicode: + proc createSymbolicLinkW*(lpSymlinkFileName, lpTargetFileName: WideCString, + flags: DWORD): int32 {. + importc:"CreateSymbolicLinkW", dynlib: "kernel32", stdcall, sideEffect.} + proc createHardLinkW*(lpFileName, lpExistingFileName: WideCString, + security: pointer=nil): int32 {. + importc:"CreateHardLinkW", dynlib: "kernel32", stdcall, sideEffect.} +else: + proc createSymbolicLinkA*(lpSymlinkFileName, lpTargetFileName: cstring, + flags: DWORD): int32 {. + importc:"CreateSymbolicLinkA", dynlib: "kernel32", stdcall, sideEffect.} + proc createHardLinkA*(lpFileName, lpExistingFileName: cstring, + security: pointer=nil): int32 {. + importc:"CreateHardLinkA", dynlib: "kernel32", stdcall, sideEffect.} const FILE_ATTRIBUTE_READONLY* = 0x00000001'i32 @@ -295,51 +326,90 @@ type cFileName*: array[0..(MAX_PATH) - 1, WinChar] cAlternateFileName*: array[0..13, WinChar] -proc findFirstFileW*(lpFileName: WideCString, - lpFindFileData: var WIN32_FIND_DATA): Handle {. - stdcall, dynlib: "kernel32", importc: "FindFirstFileW", sideEffect.} -proc findNextFileW*(hFindFile: Handle, - lpFindFileData: var WIN32_FIND_DATA): int32 {. - stdcall, dynlib: "kernel32", importc: "FindNextFileW", sideEffect.} +when useWinUnicode: + proc findFirstFileW*(lpFileName: WideCString, + lpFindFileData: var WIN32_FIND_DATA): Handle {. + stdcall, dynlib: "kernel32", importc: "FindFirstFileW", sideEffect.} + proc findNextFileW*(hFindFile: Handle, + lpFindFileData: var WIN32_FIND_DATA): int32 {. + stdcall, dynlib: "kernel32", importc: "FindNextFileW", sideEffect.} +else: + proc findFirstFileA*(lpFileName: cstring, + lpFindFileData: var WIN32_FIND_DATA): Handle {. + stdcall, dynlib: "kernel32", importc: "FindFirstFileA", sideEffect.} + proc findNextFileA*(hFindFile: Handle, + lpFindFileData: var WIN32_FIND_DATA): int32 {. + stdcall, dynlib: "kernel32", importc: "FindNextFileA", sideEffect.} proc findClose*(hFindFile: Handle) {.stdcall, dynlib: "kernel32", importc: "FindClose".} -proc getFullPathNameW*(lpFileName: WideCString, nBufferLength: int32, - lpBuffer: WideCString, - lpFilePart: var WideCString): int32 {. - stdcall, dynlib: "kernel32", - importc: "GetFullPathNameW", sideEffect.} -proc getFileAttributesW*(lpFileName: WideCString): int32 {. +when useWinUnicode: + proc getFullPathNameW*(lpFileName: WideCString, nBufferLength: int32, + lpBuffer: WideCString, + lpFilePart: var WideCString): int32 {. stdcall, dynlib: "kernel32", - importc: "GetFileAttributesW", sideEffect.} -proc setFileAttributesW*(lpFileName: WideCString, - dwFileAttributes: int32): WINBOOL {. - stdcall, dynlib: "kernel32", importc: "SetFileAttributesW", sideEffect.} + importc: "GetFullPathNameW", sideEffect.} + proc getFileAttributesW*(lpFileName: WideCString): int32 {. + stdcall, dynlib: "kernel32", + importc: "GetFileAttributesW", sideEffect.} + proc setFileAttributesW*(lpFileName: WideCString, + dwFileAttributes: int32): WINBOOL {. + stdcall, dynlib: "kernel32", importc: "SetFileAttributesW", sideEffect.} -proc copyFileW*(lpExistingFileName, lpNewFileName: WideCString, - bFailIfExists: WINBOOL): WINBOOL {. - importc: "CopyFileW", stdcall, dynlib: "kernel32", sideEffect.} + proc copyFileW*(lpExistingFileName, lpNewFileName: WideCString, + bFailIfExists: WINBOOL): WINBOOL {. + importc: "CopyFileW", stdcall, dynlib: "kernel32", sideEffect.} -proc moveFileW*(lpExistingFileName, lpNewFileName: WideCString): WINBOOL {. - importc: "MoveFileW", stdcall, dynlib: "kernel32", sideEffect.} -proc moveFileExW*(lpExistingFileName, lpNewFileName: WideCString, - flags: DWORD): WINBOOL {. - importc: "MoveFileExW", stdcall, dynlib: "kernel32", sideEffect.} + proc moveFileW*(lpExistingFileName, lpNewFileName: WideCString): WINBOOL {. + importc: "MoveFileW", stdcall, dynlib: "kernel32", sideEffect.} + proc moveFileExW*(lpExistingFileName, lpNewFileName: WideCString, + flags: DWORD): WINBOOL {. + importc: "MoveFileExW", stdcall, dynlib: "kernel32", sideEffect.} -proc getEnvironmentStringsW*(): WideCString {. - stdcall, dynlib: "kernel32", importc: "GetEnvironmentStringsW", sideEffect.} -proc freeEnvironmentStringsW*(para1: WideCString): int32 {. - stdcall, dynlib: "kernel32", importc: "FreeEnvironmentStringsW", sideEffect.} + proc getEnvironmentStringsW*(): WideCString {. + stdcall, dynlib: "kernel32", importc: "GetEnvironmentStringsW", sideEffect.} + proc freeEnvironmentStringsW*(para1: WideCString): int32 {. + stdcall, dynlib: "kernel32", importc: "FreeEnvironmentStringsW", sideEffect.} -proc getCommandLineW*(): WideCString {.importc: "GetCommandLineW", - stdcall, dynlib: "kernel32", sideEffect.} + proc getCommandLineW*(): WideCString {.importc: "GetCommandLineW", + stdcall, dynlib: "kernel32", sideEffect.} + +else: + proc getFullPathNameA*(lpFileName: cstring, nBufferLength: int32, + lpBuffer: cstring, lpFilePart: var cstring): int32 {. + stdcall, dynlib: "kernel32", + importc: "GetFullPathNameA", sideEffect.} + proc getFileAttributesA*(lpFileName: cstring): int32 {. + stdcall, dynlib: "kernel32", + importc: "GetFileAttributesA", sideEffect.} + proc setFileAttributesA*(lpFileName: cstring, + dwFileAttributes: int32): WINBOOL {. + stdcall, dynlib: "kernel32", importc: "SetFileAttributesA", sideEffect.} + + proc copyFileA*(lpExistingFileName, lpNewFileName: cstring, + bFailIfExists: cint): cint {. + importc: "CopyFileA", stdcall, dynlib: "kernel32", sideEffect.} + + proc moveFileA*(lpExistingFileName, lpNewFileName: cstring): WINBOOL {. + importc: "MoveFileA", stdcall, dynlib: "kernel32", sideEffect.} + proc moveFileExA*(lpExistingFileName, lpNewFileName: cstring, + flags: DWORD): WINBOOL {. + importc: "MoveFileExA", stdcall, dynlib: "kernel32", sideEffect.} + + proc getEnvironmentStringsA*(): cstring {. + stdcall, dynlib: "kernel32", importc: "GetEnvironmentStringsA", sideEffect.} + proc freeEnvironmentStringsA*(para1: cstring): int32 {. + stdcall, dynlib: "kernel32", importc: "FreeEnvironmentStringsA", sideEffect.} + + proc getCommandLineA*(): cstring {. + importc: "GetCommandLineA", stdcall, dynlib: "kernel32", sideEffect.} proc rdFileTime*(f: FILETIME): int64 = - result = int64(cast[uint32](f.dwLowDateTime)) or (int64(cast[uint32](f.dwHighDateTime)) shl 32) + result = ze64(f.dwLowDateTime) or (ze64(f.dwHighDateTime) shl 32) proc rdFileSize*(f: WIN32_FIND_DATA): int64 = - result = int64(cast[uint32](f.nFileSizeLow)) or (int64(cast[uint32](f.nFileSizeHigh)) shl 32) + result = ze64(f.nFileSizeLow) or (ze64(f.nFileSizeHigh) shl 32) proc getSystemTimeAsFileTime*(lpSystemTimeAsFileTime: var FILETIME) {. importc: "GetSystemTimeAsFileTime", dynlib: "kernel32", stdcall, sideEffect.} @@ -347,10 +417,17 @@ proc getSystemTimeAsFileTime*(lpSystemTimeAsFileTime: var FILETIME) {. proc sleep*(dwMilliseconds: int32){.stdcall, dynlib: "kernel32", importc: "Sleep", sideEffect.} -proc shellExecuteW*(hwnd: Handle, lpOperation, lpFile, - lpParameters, lpDirectory: WideCString, - nShowCmd: int32): Handle{. - stdcall, dynlib: "shell32.dll", importc: "ShellExecuteW", sideEffect.} +when useWinUnicode: + proc shellExecuteW*(hwnd: Handle, lpOperation, lpFile, + lpParameters, lpDirectory: WideCString, + nShowCmd: int32): Handle{. + stdcall, dynlib: "shell32.dll", importc: "ShellExecuteW", sideEffect.} + +else: + proc shellExecuteA*(hwnd: Handle, lpOperation, lpFile, + lpParameters, lpDirectory: cstring, + nShowCmd: int32): Handle{. + stdcall, dynlib: "shell32.dll", importc: "ShellExecuteA", sideEffect.} proc getFileInformationByHandle*(hFile: Handle, lpFileInformation: ptr BY_HANDLE_FILE_INFORMATION): WINBOOL{. @@ -388,7 +465,7 @@ type PSockAddr = ptr SockAddr - InAddr* {.importc: "IN_ADDR", header: "winsock2.h", union.} = object + InAddr* {.importc: "IN_ADDR", header: "winsock2.h".} = object s_addr*: uint32 # IP address Sockaddr_in* {.importc: "SOCKADDR_IN", @@ -412,9 +489,9 @@ type Sockaddr_storage* {.importc: "SOCKADDR_STORAGE", header: "winsock2.h".} = object ss_family*: uint16 - ss_pad1 {.importc: "__ss_pad1".}: array[6, byte] - ss_align {.importc: "__ss_align".}: int64 - ss_pad2 {.importc: "__ss_pad2".}: array[112, byte] + ss_pad1: array[6, byte] + ss_align: int64 + ss_pad2: array[112, byte] Servent* = object s_name*: cstring @@ -496,14 +573,6 @@ proc gethostbyname*(name: cstring): ptr Hostent {. proc gethostname*(hostname: cstring, len: cint): cint {. stdcall, importc: "gethostname", dynlib: ws2dll, sideEffect.} -proc getprotobyname*( - name: cstring -): ptr Protoent {.stdcall, importc: "getprotobyname", dynlib: ws2dll, sideEffect.} - -proc getprotobynumber*( - proto: cint -): ptr Protoent {.stdcall, importc: "getprotobynumber", dynlib: ws2dll, sideEffect.} - proc socket*(af, typ, protocol: cint): SocketHandle {. stdcall, importc: "socket", dynlib: ws2dll.} @@ -577,7 +646,7 @@ proc getaddrinfo*(nodename, servname: cstring, hints: ptr AddrInfo, res: var ptr AddrInfo): cint {. stdcall, importc: "getaddrinfo", dynlib: ws2dll.} -proc freeAddrInfo*(ai: ptr AddrInfo) {. +proc freeaddrinfo*(ai: ptr AddrInfo) {. stdcall, importc: "freeaddrinfo", dynlib: ws2dll.} proc inet_ntoa*(i: InAddr): cstring {. @@ -628,13 +697,12 @@ const # Error Constants const - ERROR_FILE_NOT_FOUND* = 2 ## https://docs.microsoft.com/en-us/windows/win32/debug/system-error-codes--0-499- + ERROR_FILE_NOT_FOUND* = 2 ERROR_PATH_NOT_FOUND* = 3 ERROR_ACCESS_DENIED* = 5 ERROR_NO_MORE_FILES* = 18 ERROR_LOCK_VIOLATION* = 33 ERROR_HANDLE_EOF* = 38 - ERROR_FILE_EXISTS* = 80 ERROR_BAD_ARGUMENTS* = 165 proc duplicateHandle*(hSourceProcessHandle: Handle, hSourceHandle: Handle, @@ -644,9 +712,6 @@ proc duplicateHandle*(hSourceProcessHandle: Handle, hSourceHandle: Handle, dwOptions: DWORD): WINBOOL{.stdcall, dynlib: "kernel32", importc: "DuplicateHandle".} -proc getHandleInformation*(hObject: Handle, lpdwFlags: ptr DWORD): WINBOOL {. - stdcall, dynlib: "kernel32", importc: "GetHandleInformation".} - proc setHandleInformation*(hObject: Handle, dwMask: DWORD, dwFlags: DWORD): WINBOOL {.stdcall, dynlib: "kernel32", importc: "SetHandleInformation".} @@ -654,20 +719,22 @@ proc setHandleInformation*(hObject: Handle, dwMask: DWORD, proc getCurrentProcess*(): Handle{.stdcall, dynlib: "kernel32", importc: "GetCurrentProcess".} -proc createFileW*(lpFileName: WideCString, dwDesiredAccess, dwShareMode: DWORD, - lpSecurityAttributes: pointer, - dwCreationDisposition, dwFlagsAndAttributes: DWORD, - hTemplateFile: Handle): Handle {. - stdcall, dynlib: "kernel32", importc: "CreateFileW".} -proc deleteFileW*(pathName: WideCString): int32 {. - importc: "DeleteFileW", dynlib: "kernel32", stdcall.} -proc createFileA*(lpFileName: cstring, dwDesiredAccess, dwShareMode: DWORD, - lpSecurityAttributes: pointer, - dwCreationDisposition, dwFlagsAndAttributes: DWORD, - hTemplateFile: Handle): Handle {. - stdcall, dynlib: "kernel32", importc: "CreateFileA".} -proc deleteFileA*(pathName: cstring): int32 {. - importc: "DeleteFileA", dynlib: "kernel32", stdcall.} +when useWinUnicode: + proc createFileW*(lpFileName: WideCString, dwDesiredAccess, dwShareMode: DWORD, + lpSecurityAttributes: pointer, + dwCreationDisposition, dwFlagsAndAttributes: DWORD, + hTemplateFile: Handle): Handle {. + stdcall, dynlib: "kernel32", importc: "CreateFileW".} + proc deleteFileW*(pathName: WideCString): int32 {. + importc: "DeleteFileW", dynlib: "kernel32", stdcall.} +else: + proc createFileA*(lpFileName: cstring, dwDesiredAccess, dwShareMode: DWORD, + lpSecurityAttributes: pointer, + dwCreationDisposition, dwFlagsAndAttributes: DWORD, + hTemplateFile: Handle): Handle {. + stdcall, dynlib: "kernel32", importc: "CreateFileA".} + proc deleteFileA*(pathName: cstring): int32 {. + importc: "DeleteFileA", dynlib: "kernel32", stdcall.} proc setEndOfFile*(hFile: Handle): WINBOOL {.stdcall, dynlib: "kernel32", importc: "SetEndOfFile".} @@ -700,6 +767,13 @@ proc createFileMappingW*(hFile: Handle, lpName: pointer): Handle {. stdcall, dynlib: "kernel32", importc: "CreateFileMappingW".} +when not useWinUnicode: + proc createFileMappingA*(hFile: Handle, + lpFileMappingAttributes: pointer, + flProtect, dwMaximumSizeHigh: DWORD, + dwMaximumSizeLow: DWORD, lpName: cstring): Handle {. + stdcall, dynlib: "kernel32", importc: "CreateFileMappingA".} + proc unmapViewOfFile*(lpBaseAddress: pointer): WINBOOL {.stdcall, dynlib: "kernel32", importc: "UnmapViewOfFile".} @@ -719,7 +793,7 @@ type POVERLAPPED_COMPLETION_ROUTINE* = proc (para1: DWORD, para2: DWORD, para3: POVERLAPPED){.stdcall.} - GUID* = object + GUID* {.final, pure.} = object D1*: int32 D2*: int16 D3*: int16 @@ -738,7 +812,6 @@ const WSAEINPROGRESS* = 10036 WSAEINTR* = 10004 WSAEWOULDBLOCK* = 10035 - WSAESHUTDOWN* = 10058 ERROR_NETNAME_DELETED* = 64 STATUS_PENDING* = 0x103 @@ -831,9 +904,6 @@ proc getProcessTimes*(hProcess: Handle; lpCreationTime, lpExitTime, lpKernelTime, lpUserTime: var FILETIME): WINBOOL {.stdcall, dynlib: "kernel32", importc: "GetProcessTimes".} -proc getSystemTimePreciseAsFileTime*(lpSystemTimeAsFileTime: var FILETIME) {. - importc: "GetSystemTimePreciseAsFileTime", dynlib: "kernel32", stdcall, sideEffect.} - type inet_ntop_proc = proc(family: cint, paddr: pointer, pStringBuffer: cstring, stringBufSize: int32): cstring {.gcsafe, stdcall, tags: [].} @@ -875,7 +945,7 @@ proc inet_ntop*(family: cint, paddr: pointer, pStringBuffer: cstring, stringBufSize: int32): cstring {.stdcall.} = var ver: OSVERSIONINFO ver.dwOSVersionInfoSize = sizeof(ver).DWORD - let res = getVersionExW(ver.addr) + let res = when useWinUnicode: getVersionExW(ver.addr) else: getVersionExA(ver.addr) if res == 0: result = nil elif ver.dwMajorVersion >= 6: @@ -893,13 +963,13 @@ type dwRemoteAddressLength: DWORD, lpdwBytesReceived: ptr DWORD, lpOverlapped: POVERLAPPED): bool {. - stdcall, gcsafe, raises: [].} + stdcall,gcsafe.} WSAPROC_CONNECTEX* = proc (s: SocketHandle, name: ptr SockAddr, namelen: cint, lpSendBuffer: pointer, dwSendDataLength: DWORD, lpdwBytesSent: ptr DWORD, lpOverlapped: POVERLAPPED): bool {. - stdcall, gcsafe, raises: [].} + stdcall,gcsafe.} WSAPROC_GETACCEPTEXSOCKADDRS* = proc(lpOutputBuffer: pointer, dwReceiveDataLength: DWORD, @@ -909,7 +979,7 @@ type LocalSockaddrLength: ptr cint, RemoteSockaddr: ptr PSockAddr, RemoteSockaddrLength: ptr cint) {. - stdcall, gcsafe, raises: [].} + stdcall,gcsafe.} const WT_EXECUTEDEFAULT* = 0x00000000'i32 @@ -937,7 +1007,7 @@ const PROCESS_QUERY_LIMITED_INFORMATION* = 0x00001000'i32 PROCESS_SET_LIMITED_INFORMATION* = 0x00002000'i32 type - WAITORTIMERCALLBACK* = proc(para1: pointer, para2: int32) {.stdcall.} + WAITORTIMERCALLBACK* = proc(para1: pointer, para2: int32): void {.stdcall.} proc postQueuedCompletionStatus*(CompletionPort: Handle, dwNumberOfBytesTransferred: DWORD, @@ -959,10 +1029,16 @@ proc openProcess*(dwDesiredAccess: DWORD, bInheritHandle: WINBOOL, dwProcessId: DWORD): Handle {.stdcall, dynlib: "kernel32", importc: "OpenProcess".} -proc createEvent*(lpEventAttributes: ptr SECURITY_ATTRIBUTES, - bManualReset: DWORD, bInitialState: DWORD, - lpName: ptr Utf16Char): Handle - {.stdcall, dynlib: "kernel32", importc: "CreateEventW".} +when defined(useWinAnsi): + proc createEvent*(lpEventAttributes: ptr SECURITY_ATTRIBUTES, + bManualReset: DWORD, bInitialState: DWORD, + lpName: cstring): Handle + {.stdcall, dynlib: "kernel32", importc: "CreateEventA".} +else: + proc createEvent*(lpEventAttributes: ptr SECURITY_ATTRIBUTES, + bManualReset: DWORD, bInitialState: DWORD, + lpName: ptr Utf16Char): Handle + {.stdcall, dynlib: "kernel32", importc: "CreateEventW".} proc setEvent*(hEvent: Handle): cint {.stdcall, dynlib: "kernel32", importc: "SetEvent".} @@ -994,7 +1070,7 @@ proc wsaResetEvent*(hEvent: Handle): bool {.stdcall, importc: "WSAResetEvent", dynlib: "ws2_32.dll".} type - KEY_EVENT_RECORD* = object + KEY_EVENT_RECORD* {.final, pure.} = object eventType*: int16 bKeyDown*: WINBOOL wRepeatCount*: int16 @@ -1003,12 +1079,17 @@ type uChar*: int16 dwControlKeyState*: DWORD -proc readConsoleInput*(hConsoleInput: Handle, lpBuffer: pointer, nLength: cint, - lpNumberOfEventsRead: ptr cint): cint - {.stdcall, dynlib: "kernel32", importc: "ReadConsoleInputW".} +when defined(useWinAnsi): + proc readConsoleInput*(hConsoleInput: Handle, lpBuffer: pointer, nLength: cint, + lpNumberOfEventsRead: ptr cint): cint + {.stdcall, dynlib: "kernel32", importc: "ReadConsoleInputA".} +else: + proc readConsoleInput*(hConsoleInput: Handle, lpBuffer: pointer, nLength: cint, + lpNumberOfEventsRead: ptr cint): cint + {.stdcall, dynlib: "kernel32", importc: "ReadConsoleInputW".} type - LPFIBER_START_ROUTINE* = proc (param: pointer) {.stdcall.} + LPFIBER_START_ROUTINE* = proc (param: pointer): void {.stdcall.} const FIBER_FLAG_FLOAT_SWITCH* = 0x01 @@ -1017,12 +1098,12 @@ proc CreateFiber*(stackSize: int, fn: LPFIBER_START_ROUTINE, param: pointer): po proc CreateFiberEx*(stkCommit: int, stkReserve: int, flags: int32, fn: LPFIBER_START_ROUTINE, param: pointer): pointer {.stdcall, discardable, dynlib: "kernel32", importc.} proc ConvertThreadToFiber*(param: pointer): pointer {.stdcall, discardable, dynlib: "kernel32", importc.} proc ConvertThreadToFiberEx*(param: pointer, flags: int32): pointer {.stdcall, discardable, dynlib: "kernel32", importc.} -proc DeleteFiber*(fiber: pointer) {.stdcall, discardable, dynlib: "kernel32", importc.} -proc SwitchToFiber*(fiber: pointer) {.stdcall, discardable, dynlib: "kernel32", importc.} +proc DeleteFiber*(fiber: pointer): void {.stdcall, discardable, dynlib: "kernel32", importc.} +proc SwitchToFiber*(fiber: pointer): void {.stdcall, discardable, dynlib: "kernel32", importc.} proc GetCurrentFiber*(): pointer {.stdcall, importc, header: "windows.h".} proc toFILETIME*(t: int64): FILETIME = - ## Convert the Windows file time timestamp `t` to `FILETIME`. + ## Convert the Windows file time timestamp ``t`` to ``FILETIME``. result = FILETIME(dwLowDateTime: cast[DWORD](t), dwHighDateTime: DWORD(t shr 32)) type @@ -1032,42 +1113,5 @@ proc setFileTime*(hFile: Handle, lpCreationTime: LPFILETIME, lpLastAccessTime: LPFILETIME, lpLastWriteTime: LPFILETIME): WINBOOL {.stdcall, dynlib: "kernel32", importc: "SetFileTime".} -type - # https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-sid_identifier_authority - SID_IDENTIFIER_AUTHORITY* {.importc, header: "".} = object - value* {.importc: "Value".}: array[6, BYTE] - # https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-sid - SID* {.importc, header: "".} = object - Revision: BYTE - SubAuthorityCount: BYTE - IdentifierAuthority: SID_IDENTIFIER_AUTHORITY - SubAuthority: ptr ptr DWORD - PSID* = ptr SID - -const - # https://docs.microsoft.com/en-us/windows/win32/secauthz/sid-components - # https://github.com/mirror/mingw-w64/blob/84c950bdab7c999ace49fe8383856be77f88c4a8/mingw-w64-headers/include/winnt.h#L2994 - SECURITY_NT_AUTHORITY* = [BYTE(0), BYTE(0), BYTE(0), BYTE(0), BYTE(0), BYTE(5)] - SECURITY_BUILTIN_DOMAIN_RID* = 32 - DOMAIN_ALIAS_RID_ADMINS* = 544 - -proc allocateAndInitializeSid*(pIdentifierAuthority: ptr SID_IDENTIFIER_AUTHORITY, - nSubAuthorityCount: BYTE, - nSubAuthority0: DWORD, - nSubAuthority1: DWORD, - nSubAuthority2: DWORD, - nSubAuthority3: DWORD, - nSubAuthority4: DWORD, - nSubAuthority5: DWORD, - nSubAuthority6: DWORD, - nSubAuthority7: DWORD, - pSid: ptr PSID): WINBOOL - {.stdcall, dynlib: "Advapi32", importc: "AllocateAndInitializeSid".} -proc checkTokenMembership*(tokenHandle: Handle, sidToCheck: PSID, - isMember: PBOOL): WINBOOL - {.stdcall, dynlib: "Advapi32", importc: "CheckTokenMembership".} -proc freeSid*(pSid: PSID): PSID - {.stdcall, dynlib: "Advapi32", importc: "FreeSid".} - when defined(nimHasStyleChecks): {.pop.} # {.push styleChecks: off.} diff --git a/lib/wrappers/iup.nim b/lib/wrappers/iup.nim new file mode 100644 index 000000000..1a9e6ab3e --- /dev/null +++ b/lib/wrappers/iup.nim @@ -0,0 +1,957 @@ +# +# +# Nim's Runtime Library +# (c) Copyright 2012 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +# C header files translated by hand +# Licence of IUP follows: + + +# **************************************************************************** +# Copyright (C) 1994-2009 Tecgraf, PUC-Rio. +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# **************************************************************************** + +{.deadCodeElim: on.} # dce option deprecated + +when defined(windows): + const dllname = "iup(|30|27|26|25|24).dll" +elif defined(macosx): + const dllname = "libiup(|3.0|2.7|2.6|2.5|2.4).dylib" +else: + const dllname = "libiup(|3.0|2.7|2.6|2.5|2.4).so(|.1)" + +const + IUP_NAME* = "IUP - Portable User Interface" + IUP_COPYRIGHT* = "Copyright (C) 1994-2009 Tecgraf, PUC-Rio." + IUP_DESCRIPTION* = "Portable toolkit for building graphical user interfaces." + constIUP_VERSION* = "3.0" + constIUP_VERSION_NUMBER* = 300000 + constIUP_VERSION_DATE* = "2009/07/18" + +type + Ihandle = object + PIhandle* = ptr Ihandle + + Icallback* = proc (arg: PIhandle): cint {.cdecl.} + +# pre-defined dialogs +proc fileDlg*: PIhandle {.importc: "IupFileDlg", dynlib: dllname, cdecl.} +proc messageDlg*: PIhandle {.importc: "IupMessageDlg", dynlib: dllname, cdecl.} +proc colorDlg*: PIhandle {.importc: "IupColorDlg", dynlib: dllname, cdecl.} +proc fontDlg*: PIhandle {.importc: "IupFontDlg", dynlib: dllname, cdecl.} + +proc getFile*(arq: cstring): cint {. + importc: "IupGetFile", dynlib: dllname, cdecl.} +proc message*(title, msg: cstring) {. + importc: "IupMessage", dynlib: dllname, cdecl.} +proc messagef*(title, format: cstring) {. + importc: "IupMessagef", dynlib: dllname, cdecl, varargs.} +proc alarm*(title, msg, b1, b2, b3: cstring): cint {. + importc: "IupAlarm", dynlib: dllname, cdecl.} +proc scanf*(format: cstring): cint {. + importc: "IupScanf", dynlib: dllname, cdecl, varargs.} +proc listDialog*(theType: cint, title: cstring, size: cint, + list: cstringArray, op, maxCol, maxLin: cint, + marks: ptr cint): cint {. + importc: "IupListDialog", dynlib: dllname, cdecl.} +proc getText*(title, text: cstring): cint {. + importc: "IupGetText", dynlib: dllname, cdecl.} +proc getColor*(x, y: cint, r, g, b: var byte): cint {. + importc: "IupGetColor", dynlib: dllname, cdecl.} + +type + Iparamcb* = proc (dialog: PIhandle, paramIndex: cint, + userData: pointer): cint {.cdecl.} + +proc getParam*(title: cstring, action: Iparamcb, userData: pointer, + format: cstring): cint {. + importc: "IupGetParam", cdecl, varargs, dynlib: dllname.} +proc getParamv*(title: cstring, action: Iparamcb, userData: pointer, + format: cstring, paramCount, paramExtra: cint, + paramData: pointer): cint {. + importc: "IupGetParamv", cdecl, dynlib: dllname.} + + +# Functions + +proc open*(argc: ptr cint, argv: ptr cstringArray): cint {. + importc: "IupOpen", cdecl, dynlib: dllname.} +proc close*() {.importc: "IupClose", cdecl, dynlib: dllname.} +proc imageLibOpen*() {.importc: "IupImageLibOpen", cdecl, dynlib: dllname.} + +proc mainLoop*(): cint {.importc: "IupMainLoop", cdecl, dynlib: dllname, + discardable.} +proc loopStep*(): cint {.importc: "IupLoopStep", cdecl, dynlib: dllname, + discardable.} +proc mainLoopLevel*(): cint {.importc: "IupMainLoopLevel", cdecl, + dynlib: dllname, discardable.} +proc flush*() {.importc: "IupFlush", cdecl, dynlib: dllname.} +proc exitLoop*() {.importc: "IupExitLoop", cdecl, dynlib: dllname.} + +proc update*(ih: PIhandle) {.importc: "IupUpdate", cdecl, dynlib: dllname.} +proc updateChildren*(ih: PIhandle) {.importc: "IupUpdateChildren", cdecl, dynlib: dllname.} +proc redraw*(ih: PIhandle, children: cint) {.importc: "IupRedraw", cdecl, dynlib: dllname.} +proc refresh*(ih: PIhandle) {.importc: "IupRefresh", cdecl, dynlib: dllname.} + +proc mapFont*(iupfont: cstring): cstring {.importc: "IupMapFont", cdecl, dynlib: dllname.} +proc unMapFont*(driverfont: cstring): cstring {.importc: "IupUnMapFont", cdecl, dynlib: dllname.} +proc help*(url: cstring): cint {.importc: "IupHelp", cdecl, dynlib: dllname.} +proc load*(filename: cstring): cstring {.importc: "IupLoad", cdecl, dynlib: dllname.} + +proc iupVersion*(): cstring {.importc: "IupVersion", cdecl, dynlib: dllname.} +proc iupVersionDate*(): cstring {.importc: "IupVersionDate", cdecl, dynlib: dllname.} +proc iupVersionNumber*(): cint {.importc: "IupVersionNumber", cdecl, dynlib: dllname.} +proc setLanguage*(lng: cstring) {.importc: "IupSetLanguage", cdecl, dynlib: dllname.} +proc getLanguage*(): cstring {.importc: "IupGetLanguage", cdecl, dynlib: dllname.} + +proc destroy*(ih: PIhandle) {.importc: "IupDestroy", cdecl, dynlib: dllname.} +proc detach*(child: PIhandle) {.importc: "IupDetach", cdecl, dynlib: dllname.} +proc append*(ih, child: PIhandle): PIhandle {. + importc: "IupAppend", cdecl, dynlib: dllname, discardable.} +proc insert*(ih, refChild, child: PIhandle): PIhandle {. + importc: "IupInsert", cdecl, dynlib: dllname, discardable.} +proc getChild*(ih: PIhandle, pos: cint): PIhandle {. + importc: "IupGetChild", cdecl, dynlib: dllname.} +proc getChildPos*(ih, child: PIhandle): cint {. + importc: "IupGetChildPos", cdecl, dynlib: dllname.} +proc getChildCount*(ih: PIhandle): cint {. + importc: "IupGetChildCount", cdecl, dynlib: dllname.} +proc getNextChild*(ih, child: PIhandle): PIhandle {. + importc: "IupGetNextChild", cdecl, dynlib: dllname.} +proc getBrother*(ih: PIhandle): PIhandle {. + importc: "IupGetBrother", cdecl, dynlib: dllname.} +proc getParent*(ih: PIhandle): PIhandle {. + importc: "IupGetParent", cdecl, dynlib: dllname.} +proc getDialog*(ih: PIhandle): PIhandle {. + importc: "IupGetDialog", cdecl, dynlib: dllname.} +proc getDialogChild*(ih: PIhandle, name: cstring): PIhandle {. + importc: "IupGetDialogChild", cdecl, dynlib: dllname.} +proc reparent*(ih, newParent: PIhandle): cint {. + importc: "IupReparent", cdecl, dynlib: dllname.} + +proc popup*(ih: PIhandle, x, y: cint): cint {. + importc: "IupPopup", cdecl, dynlib: dllname, discardable.} +proc show*(ih: PIhandle): cint {. + importc: "IupShow", cdecl, dynlib: dllname, discardable.} +proc showXY*(ih: PIhandle, x, y: cint): cint {. + importc: "IupShowXY", cdecl, dynlib: dllname, discardable.} +proc hide*(ih: PIhandle): cint {. + importc: "IupHide", cdecl, dynlib: dllname, discardable.} +proc map*(ih: PIhandle): cint {. + importc: "IupMap", cdecl, dynlib: dllname, discardable.} +proc unmap*(ih: PIhandle) {. + importc: "IupUnmap", cdecl, dynlib: dllname, discardable.} + +proc setAttribute*(ih: PIhandle, name, value: cstring) {. + importc: "IupSetAttribute", cdecl, dynlib: dllname.} +proc storeAttribute*(ih: PIhandle, name, value: cstring) {. + importc: "IupStoreAttribute", cdecl, dynlib: dllname.} +proc setAttributes*(ih: PIhandle, str: cstring): PIhandle {. + importc: "IupSetAttributes", cdecl, dynlib: dllname.} +proc getAttribute*(ih: PIhandle, name: cstring): cstring {. + importc: "IupGetAttribute", cdecl, dynlib: dllname.} +proc getAttributes*(ih: PIhandle): cstring {. + importc: "IupGetAttributes", cdecl, dynlib: dllname.} +proc getInt*(ih: PIhandle, name: cstring): cint {. + importc: "IupGetInt", cdecl, dynlib: dllname.} +proc getInt2*(ih: PIhandle, name: cstring): cint {. + importc: "IupGetInt2", cdecl, dynlib: dllname.} +proc getIntInt*(ih: PIhandle, name: cstring, i1, i2: var cint): cint {. + importc: "IupGetIntInt", cdecl, dynlib: dllname.} +proc getFloat*(ih: PIhandle, name: cstring): cfloat {. + importc: "IupGetFloat", cdecl, dynlib: dllname.} +proc setfAttribute*(ih: PIhandle, name, format: cstring) {. + importc: "IupSetfAttribute", cdecl, dynlib: dllname, varargs.} +proc getAllAttributes*(ih: PIhandle, names: cstringArray, n: cint): cint {. + importc: "IupGetAllAttributes", cdecl, dynlib: dllname.} +proc setAtt*(handleName: cstring, ih: PIhandle, name: cstring): PIhandle {. + importc: "IupSetAtt", cdecl, dynlib: dllname, varargs, discardable.} + +proc setGlobal*(name, value: cstring) {. + importc: "IupSetGlobal", cdecl, dynlib: dllname.} +proc storeGlobal*(name, value: cstring) {. + importc: "IupStoreGlobal", cdecl, dynlib: dllname.} +proc getGlobal*(name: cstring): cstring {. + importc: "IupGetGlobal", cdecl, dynlib: dllname.} + +proc setFocus*(ih: PIhandle): PIhandle {. + importc: "IupSetFocus", cdecl, dynlib: dllname.} +proc getFocus*(): PIhandle {. + importc: "IupGetFocus", cdecl, dynlib: dllname.} +proc previousField*(ih: PIhandle): PIhandle {. + importc: "IupPreviousField", cdecl, dynlib: dllname.} +proc nextField*(ih: PIhandle): PIhandle {. + importc: "IupNextField", cdecl, dynlib: dllname.} + +proc getCallback*(ih: PIhandle, name: cstring): Icallback {. + importc: "IupGetCallback", cdecl, dynlib: dllname.} +proc setCallback*(ih: PIhandle, name: cstring, fn: Icallback): Icallback {. + importc: "IupSetCallback", cdecl, dynlib: dllname, discardable.} + +proc setCallbacks*(ih: PIhandle, name: cstring, fn: Icallback): PIhandle {. + importc: "IupSetCallbacks", cdecl, dynlib: dllname, varargs, discardable.} + +proc getFunction*(name: cstring): Icallback {. + importc: "IupGetFunction", cdecl, dynlib: dllname.} +proc setFunction*(name: cstring, fn: Icallback): Icallback {. + importc: "IupSetFunction", cdecl, dynlib: dllname, discardable.} +proc getActionName*(): cstring {. + importc: "IupGetActionName", cdecl, dynlib: dllname.} + +proc getHandle*(name: cstring): PIhandle {. + importc: "IupGetHandle", cdecl, dynlib: dllname.} +proc setHandle*(name: cstring, ih: PIhandle): PIhandle {. + importc: "IupSetHandle", cdecl, dynlib: dllname.} +proc getAllNames*(names: cstringArray, n: cint): cint {. + importc: "IupGetAllNames", cdecl, dynlib: dllname.} +proc getAllDialogs*(names: cstringArray, n: cint): cint {. + importc: "IupGetAllDialogs", cdecl, dynlib: dllname.} +proc getName*(ih: PIhandle): cstring {. + importc: "IupGetName", cdecl, dynlib: dllname.} + +proc setAttributeHandle*(ih: PIhandle, name: cstring, ihNamed: PIhandle) {. + importc: "IupSetAttributeHandle", cdecl, dynlib: dllname.} +proc getAttributeHandle*(ih: PIhandle, name: cstring): PIhandle {. + importc: "IupGetAttributeHandle", cdecl, dynlib: dllname.} + +proc getClassName*(ih: PIhandle): cstring {. + importc: "IupGetClassName", cdecl, dynlib: dllname.} +proc getClassType*(ih: PIhandle): cstring {. + importc: "IupGetClassType", cdecl, dynlib: dllname.} +proc getClassAttributes*(classname: cstring, names: cstringArray, + n: cint): cint {. + importc: "IupGetClassAttributes", cdecl, dynlib: dllname.} +proc saveClassAttributes*(ih: PIhandle) {. + importc: "IupSaveClassAttributes", cdecl, dynlib: dllname.} +proc setClassDefaultAttribute*(classname, name, value: cstring) {. + importc: "IupSetClassDefaultAttribute", cdecl, dynlib: dllname.} + +proc create*(classname: cstring): PIhandle {. + importc: "IupCreate", cdecl, dynlib: dllname.} +proc createv*(classname: cstring, params: pointer): PIhandle {. + importc: "IupCreatev", cdecl, dynlib: dllname.} +proc createp*(classname: cstring, first: pointer): PIhandle {. + importc: "IupCreatep", cdecl, dynlib: dllname, varargs.} + +proc fill*(): PIhandle {.importc: "IupFill", cdecl, dynlib: dllname.} +proc radio*(child: PIhandle): PIhandle {. + importc: "IupRadio", cdecl, dynlib: dllname.} +proc vbox*(child: PIhandle): PIhandle {. + importc: "IupVbox", cdecl, dynlib: dllname, varargs.} +proc vboxv*(children: ptr PIhandle): PIhandle {. + importc: "IupVboxv", cdecl, dynlib: dllname.} +proc zbox*(child: PIhandle): PIhandle {. + importc: "IupZbox", cdecl, dynlib: dllname, varargs.} +proc zboxv*(children: ptr PIhandle): PIhandle {. + importc: "IupZboxv", cdecl, dynlib: dllname.} +proc hbox*(child: PIhandle): PIhandle {. + importc: "IupHbox", cdecl, dynlib: dllname, varargs.} +proc hboxv*(children: ptr PIhandle): PIhandle {. + importc: "IupHboxv", cdecl, dynlib: dllname.} + +proc normalizer*(ihFirst: PIhandle): PIhandle {. + importc: "IupNormalizer", cdecl, dynlib: dllname, varargs.} +proc normalizerv*(ihList: ptr PIhandle): PIhandle {. + importc: "IupNormalizerv", cdecl, dynlib: dllname.} + +proc cbox*(child: PIhandle): PIhandle {. + importc: "IupCbox", cdecl, dynlib: dllname, varargs.} +proc cboxv*(children: ptr PIhandle): PIhandle {. + importc: "IupCboxv", cdecl, dynlib: dllname.} +proc sbox*(child: PIhandle): PIhandle {. + importc: "IupSbox", cdecl, dynlib: dllname.} + +proc frame*(child: PIhandle): PIhandle {. + importc: "IupFrame", cdecl, dynlib: dllname.} + +proc image*(width, height: cint, pixmap: pointer): PIhandle {. + importc: "IupImage", cdecl, dynlib: dllname.} +proc imageRGB*(width, height: cint, pixmap: pointer): PIhandle {. + importc: "IupImageRGB", cdecl, dynlib: dllname.} +proc imageRGBA*(width, height: cint, pixmap: pointer): PIhandle {. + importc: "IupImageRGBA", cdecl, dynlib: dllname.} + +proc item*(title, action: cstring): PIhandle {. + importc: "IupItem", cdecl, dynlib: dllname.} +proc submenu*(title: cstring, child: PIhandle): PIhandle {. + importc: "IupSubmenu", cdecl, dynlib: dllname.} +proc separator*(): PIhandle {. + importc: "IupSeparator", cdecl, dynlib: dllname.} +proc menu*(child: PIhandle): PIhandle {. + importc: "IupMenu", cdecl, dynlib: dllname, varargs.} +proc menuv*(children: ptr PIhandle): PIhandle {. + importc: "IupMenuv", cdecl, dynlib: dllname.} + +proc button*(title, action: cstring): PIhandle {. + importc: "IupButton", cdecl, dynlib: dllname.} +proc link*(url, title: cstring): PIhandle {. + importc: "IupLink", cdecl, dynlib: dllname.} +proc canvas*(action: cstring): PIhandle {. + importc: "IupCanvas", cdecl, dynlib: dllname.} +proc dialog*(child: PIhandle): PIhandle {. + importc: "IupDialog", cdecl, dynlib: dllname.} +proc user*(): PIhandle {. + importc: "IupUser", cdecl, dynlib: dllname.} +proc label*(title: cstring): PIhandle {. + importc: "IupLabel", cdecl, dynlib: dllname.} +proc list*(action: cstring): PIhandle {. + importc: "IupList", cdecl, dynlib: dllname.} +proc text*(action: cstring): PIhandle {. + importc: "IupText", cdecl, dynlib: dllname.} +proc multiLine*(action: cstring): PIhandle {. + importc: "IupMultiLine", cdecl, dynlib: dllname.} +proc toggle*(title, action: cstring): PIhandle {. + importc: "IupToggle", cdecl, dynlib: dllname.} +proc timer*(): PIhandle {. + importc: "IupTimer", cdecl, dynlib: dllname.} +proc progressBar*(): PIhandle {. + importc: "IupProgressBar", cdecl, dynlib: dllname.} +proc val*(theType: cstring): PIhandle {. + importc: "IupVal", cdecl, dynlib: dllname.} +proc tabs*(child: PIhandle): PIhandle {. + importc: "IupTabs", cdecl, dynlib: dllname, varargs.} +proc tabsv*(children: ptr PIhandle): PIhandle {. + importc: "IupTabsv", cdecl, dynlib: dllname.} +proc tree*(): PIhandle {.importc: "IupTree", cdecl, dynlib: dllname.} + +proc spin*(): PIhandle {.importc: "IupSpin", cdecl, dynlib: dllname.} +proc spinbox*(child: PIhandle): PIhandle {. + importc: "IupSpinbox", cdecl, dynlib: dllname.} + +# IupText utilities +proc textConvertLinColToPos*(ih: PIhandle, lin, col: cint, pos: var cint) {. + importc: "IupTextConvertLinColToPos", cdecl, dynlib: dllname.} +proc textConvertPosToLinCol*(ih: PIhandle, pos: cint, lin, col: var cint) {. + importc: "IupTextConvertPosToLinCol", cdecl, dynlib: dllname.} + +proc convertXYToPos*(ih: PIhandle, x, y: cint): cint {. + importc: "IupConvertXYToPos", cdecl, dynlib: dllname.} + +# IupTree utilities +proc treeSetUserId*(ih: PIhandle, id: cint, userid: pointer): cint {. + importc: "IupTreeSetUserId", cdecl, dynlib: dllname, discardable.} +proc treeGetUserId*(ih: PIhandle, id: cint): pointer {. + importc: "IupTreeGetUserId", cdecl, dynlib: dllname.} +proc treeGetId*(ih: PIhandle, userid: pointer): cint {. + importc: "IupTreeGetId", cdecl, dynlib: dllname.} + +proc treeSetAttribute*(ih: PIhandle, name: cstring, id: cint, value: cstring) {. + importc: "IupTreeSetAttribute", cdecl, dynlib: dllname.} +proc treeStoreAttribute*(ih: PIhandle, name: cstring, id: cint, value: cstring) {. + importc: "IupTreeStoreAttribute", cdecl, dynlib: dllname.} +proc treeGetAttribute*(ih: PIhandle, name: cstring, id: cint): cstring {. + importc: "IupTreeGetAttribute", cdecl, dynlib: dllname.} +proc treeGetInt*(ih: PIhandle, name: cstring, id: cint): cint {. + importc: "IupTreeGetInt", cdecl, dynlib: dllname.} +proc treeGetFloat*(ih: PIhandle, name: cstring, id: cint): cfloat {. + importc: "IupTreeGetFloat", cdecl, dynlib: dllname.} +proc treeSetfAttribute*(ih: PIhandle, name: cstring, id: cint, format: cstring) {. + importc: "IupTreeSetfAttribute", cdecl, dynlib: dllname, varargs.} + + +# Common Return Values +const + IUP_ERROR* = cint(1) + IUP_NOERROR* = cint(0) + IUP_OPENED* = cint(-1) + IUP_INVALID* = cint(-1) + + # Callback Return Values + IUP_IGNORE* = cint(-1) + IUP_DEFAULT* = cint(-2) + IUP_CLOSE* = cint(-3) + IUP_CONTINUE* = cint(-4) + + # IupPopup and IupShowXY Parameter Values + IUP_CENTER* = cint(0xFFFF) + IUP_LEFT* = cint(0xFFFE) + IUP_RIGHT* = cint(0xFFFD) + IUP_MOUSEPOS* = cint(0xFFFC) + IUP_CURRENT* = cint(0xFFFB) + IUP_CENTERPARENT* = cint(0xFFFA) + IUP_TOP* = IUP_LEFT + IUP_BOTTOM* = IUP_RIGHT + + # SHOW_CB Callback Values + IUP_SHOW* = cint(0) + IUP_RESTORE* = cint(1) + IUP_MINIMIZE* = cint(2) + IUP_MAXIMIZE* = cint(3) + IUP_HIDE* = cint(4) + + # SCROLL_CB Callback Values + IUP_SBUP* = cint(0) + IUP_SBDN* = cint(1) + IUP_SBPGUP* = cint(2) + IUP_SBPGDN* = cint(3) + IUP_SBPOSV* = cint(4) + IUP_SBDRAGV* = cint(5) + IUP_SBLEFT* = cint(6) + IUP_SBRIGHT* = cint(7) + IUP_SBPGLEFT* = cint(8) + IUP_SBPGRIGHT* = cint(9) + IUP_SBPOSH* = cint(10) + IUP_SBDRAGH* = cint(11) + + # Mouse Button Values and Macros + IUP_BUTTON1* = cint(ord('1')) + IUP_BUTTON2* = cint(ord('2')) + IUP_BUTTON3* = cint(ord('3')) + IUP_BUTTON4* = cint(ord('4')) + IUP_BUTTON5* = cint(ord('5')) + +proc isShift*(s: cstring): bool = return s[0] == 'S' +proc isControl*(s: cstring): bool = return s[1] == 'C' +proc isButton1*(s: cstring): bool = return s[2] == '1' +proc isButton2*(s: cstring): bool = return s[3] == '2' +proc isbutton3*(s: cstring): bool = return s[4] == '3' +proc isDouble*(s: cstring): bool = return s[5] == 'D' +proc isAlt*(s: cstring): bool = return s[6] == 'A' +proc isSys*(s: cstring): bool = return s[7] == 'Y' +proc isButton4*(s: cstring): bool = return s[8] == '4' +proc isButton5*(s: cstring): bool = return s[9] == '5' + +# Pre-Defined Masks +const + IUP_MASK_FLOAT* = "[+/-]?(/d+/.?/d*|/./d+)" + IUP_MASK_UFLOAT* = "(/d+/.?/d*|/./d+)" + IUP_MASK_EFLOAT* = "[+/-]?(/d+/.?/d*|/./d+)([eE][+/-]?/d+)?" + IUP_MASK_INT* = "[+/-]?/d+" + IUP_MASK_UINT* = "/d+" + +# from 32 to 126, all character sets are equal, +# the key code i the same as the character code. +const + K_SP* = cint(ord(' ')) + K_exclam* = cint(ord('!')) + K_quotedbl* = cint(ord('\"')) + K_numbersign* = cint(ord('#')) + K_dollar* = cint(ord('$')) + K_percent* = cint(ord('%')) + K_ampersand* = cint(ord('&')) + K_apostrophe* = cint(ord('\'')) + K_parentleft* = cint(ord('(')) + K_parentright* = cint(ord(')')) + K_asterisk* = cint(ord('*')) + K_plus* = cint(ord('+')) + K_comma* = cint(ord(',')) + K_minus* = cint(ord('-')) + K_period* = cint(ord('.')) + K_slash* = cint(ord('/')) + K_0* = cint(ord('0')) + K_1* = cint(ord('1')) + K_2* = cint(ord('2')) + K_3* = cint(ord('3')) + K_4* = cint(ord('4')) + K_5* = cint(ord('5')) + K_6* = cint(ord('6')) + K_7* = cint(ord('7')) + K_8* = cint(ord('8')) + K_9* = cint(ord('9')) + K_colon* = cint(ord(':')) + K_semicolon* = cint(ord(';')) + K_less* = cint(ord('<')) + K_equal* = cint(ord('=')) + K_greater* = cint(ord('>')) + K_question* = cint(ord('?')) + K_at* = cint(ord('@')) + K_upperA* = cint(ord('A')) + K_upperB* = cint(ord('B')) + K_upperC* = cint(ord('C')) + K_upperD* = cint(ord('D')) + K_upperE* = cint(ord('E')) + K_upperF* = cint(ord('F')) + K_upperG* = cint(ord('G')) + K_upperH* = cint(ord('H')) + K_upperI* = cint(ord('I')) + K_upperJ* = cint(ord('J')) + K_upperK* = cint(ord('K')) + K_upperL* = cint(ord('L')) + K_upperM* = cint(ord('M')) + K_upperN* = cint(ord('N')) + K_upperO* = cint(ord('O')) + K_upperP* = cint(ord('P')) + K_upperQ* = cint(ord('Q')) + K_upperR* = cint(ord('R')) + K_upperS* = cint(ord('S')) + K_upperT* = cint(ord('T')) + K_upperU* = cint(ord('U')) + K_upperV* = cint(ord('V')) + K_upperW* = cint(ord('W')) + K_upperX* = cint(ord('X')) + K_upperY* = cint(ord('Y')) + K_upperZ* = cint(ord('Z')) + K_bracketleft* = cint(ord('[')) + K_backslash* = cint(ord('\\')) + K_bracketright* = cint(ord(']')) + K_circum* = cint(ord('^')) + K_underscore* = cint(ord('_')) + K_grave* = cint(ord('`')) + K_lowera* = cint(ord('a')) + K_lowerb* = cint(ord('b')) + K_lowerc* = cint(ord('c')) + K_lowerd* = cint(ord('d')) + K_lowere* = cint(ord('e')) + K_lowerf* = cint(ord('f')) + K_lowerg* = cint(ord('g')) + K_lowerh* = cint(ord('h')) + K_loweri* = cint(ord('i')) + K_lowerj* = cint(ord('j')) + K_lowerk* = cint(ord('k')) + K_lowerl* = cint(ord('l')) + K_lowerm* = cint(ord('m')) + K_lowern* = cint(ord('n')) + K_lowero* = cint(ord('o')) + K_lowerp* = cint(ord('p')) + K_lowerq* = cint(ord('q')) + K_lowerr* = cint(ord('r')) + K_lowers* = cint(ord('s')) + K_lowert* = cint(ord('t')) + K_loweru* = cint(ord('u')) + K_lowerv* = cint(ord('v')) + K_lowerw* = cint(ord('w')) + K_lowerx* = cint(ord('x')) + K_lowery* = cint(ord('y')) + K_lowerz* = cint(ord('z')) + K_braceleft* = cint(ord('{')) + K_bar* = cint(ord('|')) + K_braceright* = cint(ord('}')) + K_tilde* = cint(ord('~')) + +proc isPrint*(c: cint): bool = return c > 31 and c < 127 + +# also define the escape sequences that have keys associated +const + K_BS* = cint(ord('\b')) + K_TAB* = cint(ord('\t')) + K_LF* = cint(10) + K_CR* = cint(13) + +# IUP Extended Key Codes, range start at 128 +# Modifiers use 256 interval +# These key code definitions are specific to IUP + +proc isXkey*(c: cint): bool = return c > 128 +proc isShiftXkey*(c: cint): bool = return c > 256 and c < 512 +proc isCtrlXkey*(c: cint): bool = return c > 512 and c < 768 +proc isAltXkey*(c: cint): bool = return c > 768 and c < 1024 +proc isSysXkey*(c: cint): bool = return c > 1024 and c < 1280 + +proc iUPxCODE*(c: cint): cint = return c + cint(128) # Normal (must be above 128) +proc iUPsxCODE*(c: cint): cint = + return c + cint(256) + # Shift (must have range to include the standard keys and the normal + # extended keys, so must be above 256 + +proc iUPcxCODE*(c: cint): cint = return c + cint(512) # Ctrl +proc iUPmxCODE*(c: cint): cint = return c + cint(768) # Alt +proc iUPyxCODE*(c: cint): cint = return c + cint(1024) # Sys (Win or Apple) + +const + IUP_NUMMAXCODES* = 1280 ## 5*256=1280 Normal+Shift+Ctrl+Alt+Sys + + K_HOME* = iUPxCODE(1) + K_UP* = iUPxCODE(2) + K_PGUP* = iUPxCODE(3) + K_LEFT* = iUPxCODE(4) + K_MIDDLE* = iUPxCODE(5) + K_RIGHT* = iUPxCODE(6) + K_END* = iUPxCODE(7) + K_DOWN* = iUPxCODE(8) + K_PGDN* = iUPxCODE(9) + K_INS* = iUPxCODE(10) + K_DEL* = iUPxCODE(11) + K_PAUSE* = iUPxCODE(12) + K_ESC* = iUPxCODE(13) + K_ccedilla* = iUPxCODE(14) + K_F1* = iUPxCODE(15) + K_F2* = iUPxCODE(16) + K_F3* = iUPxCODE(17) + K_F4* = iUPxCODE(18) + K_F5* = iUPxCODE(19) + K_F6* = iUPxCODE(20) + K_F7* = iUPxCODE(21) + K_F8* = iUPxCODE(22) + K_F9* = iUPxCODE(23) + K_F10* = iUPxCODE(24) + K_F11* = iUPxCODE(25) + K_F12* = iUPxCODE(26) + K_Print* = iUPxCODE(27) + K_Menu* = iUPxCODE(28) + + K_acute* = iUPxCODE(29) # no Shift/Ctrl/Alt + + K_sHOME* = iUPsxCODE(K_HOME) + K_sUP* = iUPsxCODE(K_UP) + K_sPGUP* = iUPsxCODE(K_PGUP) + K_sLEFT* = iUPsxCODE(K_LEFT) + K_sMIDDLE* = iUPsxCODE(K_MIDDLE) + K_sRIGHT* = iUPsxCODE(K_RIGHT) + K_sEND* = iUPsxCODE(K_END) + K_sDOWN* = iUPsxCODE(K_DOWN) + K_sPGDN* = iUPsxCODE(K_PGDN) + K_sINS* = iUPsxCODE(K_INS) + K_sDEL* = iUPsxCODE(K_DEL) + K_sSP* = iUPsxCODE(K_SP) + K_sTAB* = iUPsxCODE(K_TAB) + K_sCR* = iUPsxCODE(K_CR) + K_sBS* = iUPsxCODE(K_BS) + K_sPAUSE* = iUPsxCODE(K_PAUSE) + K_sESC* = iUPsxCODE(K_ESC) + K_sCcedilla* = iUPsxCODE(K_ccedilla) + K_sF1* = iUPsxCODE(K_F1) + K_sF2* = iUPsxCODE(K_F2) + K_sF3* = iUPsxCODE(K_F3) + K_sF4* = iUPsxCODE(K_F4) + K_sF5* = iUPsxCODE(K_F5) + K_sF6* = iUPsxCODE(K_F6) + K_sF7* = iUPsxCODE(K_F7) + K_sF8* = iUPsxCODE(K_F8) + K_sF9* = iUPsxCODE(K_F9) + K_sF10* = iUPsxCODE(K_F10) + K_sF11* = iUPsxCODE(K_F11) + K_sF12* = iUPsxCODE(K_F12) + K_sPrint* = iUPsxCODE(K_Print) + K_sMenu* = iUPsxCODE(K_Menu) + + K_cHOME* = iUPcxCODE(K_HOME) + K_cUP* = iUPcxCODE(K_UP) + K_cPGUP* = iUPcxCODE(K_PGUP) + K_cLEFT* = iUPcxCODE(K_LEFT) + K_cMIDDLE* = iUPcxCODE(K_MIDDLE) + K_cRIGHT* = iUPcxCODE(K_RIGHT) + K_cEND* = iUPcxCODE(K_END) + K_cDOWN* = iUPcxCODE(K_DOWN) + K_cPGDN* = iUPcxCODE(K_PGDN) + K_cINS* = iUPcxCODE(K_INS) + K_cDEL* = iUPcxCODE(K_DEL) + K_cSP* = iUPcxCODE(K_SP) + K_cTAB* = iUPcxCODE(K_TAB) + K_cCR* = iUPcxCODE(K_CR) + K_cBS* = iUPcxCODE(K_BS) + K_cPAUSE* = iUPcxCODE(K_PAUSE) + K_cESC* = iUPcxCODE(K_ESC) + K_cCcedilla* = iUPcxCODE(K_ccedilla) + K_cF1* = iUPcxCODE(K_F1) + K_cF2* = iUPcxCODE(K_F2) + K_cF3* = iUPcxCODE(K_F3) + K_cF4* = iUPcxCODE(K_F4) + K_cF5* = iUPcxCODE(K_F5) + K_cF6* = iUPcxCODE(K_F6) + K_cF7* = iUPcxCODE(K_F7) + K_cF8* = iUPcxCODE(K_F8) + K_cF9* = iUPcxCODE(K_F9) + K_cF10* = iUPcxCODE(K_F10) + K_cF11* = iUPcxCODE(K_F11) + K_cF12* = iUPcxCODE(K_F12) + K_cPrint* = iUPcxCODE(K_Print) + K_cMenu* = iUPcxCODE(K_Menu) + + K_mHOME* = iUPmxCODE(K_HOME) + K_mUP* = iUPmxCODE(K_UP) + K_mPGUP* = iUPmxCODE(K_PGUP) + K_mLEFT* = iUPmxCODE(K_LEFT) + K_mMIDDLE* = iUPmxCODE(K_MIDDLE) + K_mRIGHT* = iUPmxCODE(K_RIGHT) + K_mEND* = iUPmxCODE(K_END) + K_mDOWN* = iUPmxCODE(K_DOWN) + K_mPGDN* = iUPmxCODE(K_PGDN) + K_mINS* = iUPmxCODE(K_INS) + K_mDEL* = iUPmxCODE(K_DEL) + K_mSP* = iUPmxCODE(K_SP) + K_mTAB* = iUPmxCODE(K_TAB) + K_mCR* = iUPmxCODE(K_CR) + K_mBS* = iUPmxCODE(K_BS) + K_mPAUSE* = iUPmxCODE(K_PAUSE) + K_mESC* = iUPmxCODE(K_ESC) + K_mCcedilla* = iUPmxCODE(K_ccedilla) + K_mF1* = iUPmxCODE(K_F1) + K_mF2* = iUPmxCODE(K_F2) + K_mF3* = iUPmxCODE(K_F3) + K_mF4* = iUPmxCODE(K_F4) + K_mF5* = iUPmxCODE(K_F5) + K_mF6* = iUPmxCODE(K_F6) + K_mF7* = iUPmxCODE(K_F7) + K_mF8* = iUPmxCODE(K_F8) + K_mF9* = iUPmxCODE(K_F9) + K_mF10* = iUPmxCODE(K_F10) + K_mF11* = iUPmxCODE(K_F11) + K_mF12* = iUPmxCODE(K_F12) + K_mPrint* = iUPmxCODE(K_Print) + K_mMenu* = iUPmxCODE(K_Menu) + + K_yHOME* = iUPyxCODE(K_HOME) + K_yUP* = iUPyxCODE(K_UP) + K_yPGUP* = iUPyxCODE(K_PGUP) + K_yLEFT* = iUPyxCODE(K_LEFT) + K_yMIDDLE* = iUPyxCODE(K_MIDDLE) + K_yRIGHT* = iUPyxCODE(K_RIGHT) + K_yEND* = iUPyxCODE(K_END) + K_yDOWN* = iUPyxCODE(K_DOWN) + K_yPGDN* = iUPyxCODE(K_PGDN) + K_yINS* = iUPyxCODE(K_INS) + K_yDEL* = iUPyxCODE(K_DEL) + K_ySP* = iUPyxCODE(K_SP) + K_yTAB* = iUPyxCODE(K_TAB) + K_yCR* = iUPyxCODE(K_CR) + K_yBS* = iUPyxCODE(K_BS) + K_yPAUSE* = iUPyxCODE(K_PAUSE) + K_yESC* = iUPyxCODE(K_ESC) + K_yCcedilla* = iUPyxCODE(K_ccedilla) + K_yF1* = iUPyxCODE(K_F1) + K_yF2* = iUPyxCODE(K_F2) + K_yF3* = iUPyxCODE(K_F3) + K_yF4* = iUPyxCODE(K_F4) + K_yF5* = iUPyxCODE(K_F5) + K_yF6* = iUPyxCODE(K_F6) + K_yF7* = iUPyxCODE(K_F7) + K_yF8* = iUPyxCODE(K_F8) + K_yF9* = iUPyxCODE(K_F9) + K_yF10* = iUPyxCODE(K_F10) + K_yF11* = iUPyxCODE(K_F11) + K_yF12* = iUPyxCODE(K_F12) + K_yPrint* = iUPyxCODE(K_Print) + K_yMenu* = iUPyxCODE(K_Menu) + + K_sPlus* = iUPsxCODE(K_plus) + K_sComma* = iUPsxCODE(K_comma) + K_sMinus* = iUPsxCODE(K_minus) + K_sPeriod* = iUPsxCODE(K_period) + K_sSlash* = iUPsxCODE(K_slash) + K_sAsterisk* = iUPsxCODE(K_asterisk) + + K_cupperA* = iUPcxCODE(K_upperA) + K_cupperB* = iUPcxCODE(K_upperB) + K_cupperC* = iUPcxCODE(K_upperC) + K_cupperD* = iUPcxCODE(K_upperD) + K_cupperE* = iUPcxCODE(K_upperE) + K_cupperF* = iUPcxCODE(K_upperF) + K_cupperG* = iUPcxCODE(K_upperG) + K_cupperH* = iUPcxCODE(K_upperH) + K_cupperI* = iUPcxCODE(K_upperI) + K_cupperJ* = iUPcxCODE(K_upperJ) + K_cupperK* = iUPcxCODE(K_upperK) + K_cupperL* = iUPcxCODE(K_upperL) + K_cupperM* = iUPcxCODE(K_upperM) + K_cupperN* = iUPcxCODE(K_upperN) + K_cupperO* = iUPcxCODE(K_upperO) + K_cupperP* = iUPcxCODE(K_upperP) + K_cupperQ* = iUPcxCODE(K_upperQ) + K_cupperR* = iUPcxCODE(K_upperR) + K_cupperS* = iUPcxCODE(K_upperS) + K_cupperT* = iUPcxCODE(K_upperT) + K_cupperU* = iUPcxCODE(K_upperU) + K_cupperV* = iUPcxCODE(K_upperV) + K_cupperW* = iUPcxCODE(K_upperW) + K_cupperX* = iUPcxCODE(K_upperX) + K_cupperY* = iUPcxCODE(K_upperY) + K_cupperZ* = iUPcxCODE(K_upperZ) + K_c1* = iUPcxCODE(K_1) + K_c2* = iUPcxCODE(K_2) + K_c3* = iUPcxCODE(K_3) + K_c4* = iUPcxCODE(K_4) + K_c5* = iUPcxCODE(K_5) + K_c6* = iUPcxCODE(K_6) + K_c7* = iUPcxCODE(K_7) + K_c8* = iUPcxCODE(K_8) + K_c9* = iUPcxCODE(K_9) + K_c0* = iUPcxCODE(K_0) + K_cPlus* = iUPcxCODE(K_plus) + K_cComma* = iUPcxCODE(K_comma) + K_cMinus* = iUPcxCODE(K_minus) + K_cPeriod* = iUPcxCODE(K_period) + K_cSlash* = iUPcxCODE(K_slash) + K_cSemicolon* = iUPcxCODE(K_semicolon) + K_cEqual* = iUPcxCODE(K_equal) + K_cBracketleft* = iUPcxCODE(K_bracketleft) + K_cBracketright* = iUPcxCODE(K_bracketright) + K_cBackslash* = iUPcxCODE(K_backslash) + K_cAsterisk* = iUPcxCODE(K_asterisk) + + K_mupperA* = iUPmxCODE(K_upperA) + K_mupperB* = iUPmxCODE(K_upperB) + K_mupperC* = iUPmxCODE(K_upperC) + K_mupperD* = iUPmxCODE(K_upperD) + K_mupperE* = iUPmxCODE(K_upperE) + K_mupperF* = iUPmxCODE(K_upperF) + K_mupperG* = iUPmxCODE(K_upperG) + K_mupperH* = iUPmxCODE(K_upperH) + K_mupperI* = iUPmxCODE(K_upperI) + K_mupperJ* = iUPmxCODE(K_upperJ) + K_mupperK* = iUPmxCODE(K_upperK) + K_mupperL* = iUPmxCODE(K_upperL) + K_mupperM* = iUPmxCODE(K_upperM) + K_mupperN* = iUPmxCODE(K_upperN) + K_mupperO* = iUPmxCODE(K_upperO) + K_mupperP* = iUPmxCODE(K_upperP) + K_mupperQ* = iUPmxCODE(K_upperQ) + K_mupperR* = iUPmxCODE(K_upperR) + K_mupperS* = iUPmxCODE(K_upperS) + K_mupperT* = iUPmxCODE(K_upperT) + K_mupperU* = iUPmxCODE(K_upperU) + K_mupperV* = iUPmxCODE(K_upperV) + K_mupperW* = iUPmxCODE(K_upperW) + K_mupperX* = iUPmxCODE(K_upperX) + K_mupperY* = iUPmxCODE(K_upperY) + K_mupperZ* = iUPmxCODE(K_upperZ) + K_m1* = iUPmxCODE(K_1) + K_m2* = iUPmxCODE(K_2) + K_m3* = iUPmxCODE(K_3) + K_m4* = iUPmxCODE(K_4) + K_m5* = iUPmxCODE(K_5) + K_m6* = iUPmxCODE(K_6) + K_m7* = iUPmxCODE(K_7) + K_m8* = iUPmxCODE(K_8) + K_m9* = iUPmxCODE(K_9) + K_m0* = iUPmxCODE(K_0) + K_mPlus* = iUPmxCODE(K_plus) + K_mComma* = iUPmxCODE(K_comma) + K_mMinus* = iUPmxCODE(K_minus) + K_mPeriod* = iUPmxCODE(K_period) + K_mSlash* = iUPmxCODE(K_slash) + K_mSemicolon* = iUPmxCODE(K_semicolon) + K_mEqual* = iUPmxCODE(K_equal) + K_mBracketleft* = iUPmxCODE(K_bracketleft) + K_mBracketright* = iUPmxCODE(K_bracketright) + K_mBackslash* = iUPmxCODE(K_backslash) + K_mAsterisk* = iUPmxCODE(K_asterisk) + + K_yA* = iUPyxCODE(K_upperA) + K_yB* = iUPyxCODE(K_upperB) + K_yC* = iUPyxCODE(K_upperC) + K_yD* = iUPyxCODE(K_upperD) + K_yE* = iUPyxCODE(K_upperE) + K_yF* = iUPyxCODE(K_upperF) + K_yG* = iUPyxCODE(K_upperG) + K_yH* = iUPyxCODE(K_upperH) + K_yI* = iUPyxCODE(K_upperI) + K_yJ* = iUPyxCODE(K_upperJ) + K_yK* = iUPyxCODE(K_upperK) + K_yL* = iUPyxCODE(K_upperL) + K_yM* = iUPyxCODE(K_upperM) + K_yN* = iUPyxCODE(K_upperN) + K_yO* = iUPyxCODE(K_upperO) + K_yP* = iUPyxCODE(K_upperP) + K_yQ* = iUPyxCODE(K_upperQ) + K_yR* = iUPyxCODE(K_upperR) + K_yS* = iUPyxCODE(K_upperS) + K_yT* = iUPyxCODE(K_upperT) + K_yU* = iUPyxCODE(K_upperU) + K_yV* = iUPyxCODE(K_upperV) + K_yW* = iUPyxCODE(K_upperW) + K_yX* = iUPyxCODE(K_upperX) + K_yY* = iUPyxCODE(K_upperY) + K_yZ* = iUPyxCODE(K_upperZ) + K_y1* = iUPyxCODE(K_1) + K_y2* = iUPyxCODE(K_2) + K_y3* = iUPyxCODE(K_3) + K_y4* = iUPyxCODE(K_4) + K_y5* = iUPyxCODE(K_5) + K_y6* = iUPyxCODE(K_6) + K_y7* = iUPyxCODE(K_7) + K_y8* = iUPyxCODE(K_8) + K_y9* = iUPyxCODE(K_9) + K_y0* = iUPyxCODE(K_0) + K_yPlus* = iUPyxCODE(K_plus) + K_yComma* = iUPyxCODE(K_comma) + K_yMinus* = iUPyxCODE(K_minus) + K_yPeriod* = iUPyxCODE(K_period) + K_ySlash* = iUPyxCODE(K_slash) + K_ySemicolon* = iUPyxCODE(K_semicolon) + K_yEqual* = iUPyxCODE(K_equal) + K_yBracketleft* = iUPyxCODE(K_bracketleft) + K_yBracketright* = iUPyxCODE(K_bracketright) + K_yBackslash* = iUPyxCODE(K_backslash) + K_yAsterisk* = iUPyxCODE(K_asterisk) + +proc controlsOpen*(): cint {.cdecl, importc: "IupControlsOpen", dynlib: dllname.} +proc controlsClose*() {.cdecl, importc: "IupControlsClose", dynlib: dllname.} + +proc oldValOpen*() {.cdecl, importc: "IupOldValOpen", dynlib: dllname.} +proc oldTabsOpen*() {.cdecl, importc: "IupOldTabsOpen", dynlib: dllname.} + +proc colorbar*(): PIhandle {.cdecl, importc: "IupColorbar", dynlib: dllname.} +proc cells*(): PIhandle {.cdecl, importc: "IupCells", dynlib: dllname.} +proc colorBrowser*(): PIhandle {.cdecl, importc: "IupColorBrowser", dynlib: dllname.} +proc gauge*(): PIhandle {.cdecl, importc: "IupGauge", dynlib: dllname.} +proc dial*(theType: cstring): PIhandle {.cdecl, importc: "IupDial", dynlib: dllname.} +proc matrix*(action: cstring): PIhandle {.cdecl, importc: "IupMatrix", dynlib: dllname.} + +# IupMatrix utilities +proc matSetAttribute*(ih: PIhandle, name: cstring, lin, col: cint, + value: cstring) {. + cdecl, importc: "IupMatSetAttribute", dynlib: dllname.} +proc matStoreAttribute*(ih: PIhandle, name: cstring, lin, col: cint, + value: cstring) {.cdecl, + importc: "IupMatStoreAttribute", dynlib: dllname.} +proc matGetAttribute*(ih: PIhandle, name: cstring, lin, col: cint): cstring {. + cdecl, importc: "IupMatGetAttribute", dynlib: dllname.} +proc matGetInt*(ih: PIhandle, name: cstring, lin, col: cint): cint {. + cdecl, importc: "IupMatGetInt", dynlib: dllname.} +proc matGetFloat*(ih: PIhandle, name: cstring, lin, col: cint): cfloat {. + cdecl, importc: "IupMatGetFloat", dynlib: dllname.} +proc matSetfAttribute*(ih: PIhandle, name: cstring, lin, col: cint, + format: cstring) {.cdecl, + importc: "IupMatSetfAttribute", + dynlib: dllname, varargs.} + +# Used by IupColorbar +const + IUP_PRIMARY* = -1 + IUP_SECONDARY* = -2 + +# Initialize PPlot widget class +proc pPlotOpen*() {.cdecl, importc: "IupPPlotOpen", dynlib: dllname.} + +# Create an PPlot widget instance +proc pPlot*: PIhandle {.cdecl, importc: "IupPPlot", dynlib: dllname.} + +# Add dataset to plot +proc pPlotBegin*(ih: PIhandle, strXdata: cint) {. + cdecl, importc: "IupPPlotBegin", dynlib: dllname.} +proc pPlotAdd*(ih: PIhandle, x, y: cfloat) {. + cdecl, importc: "IupPPlotAdd", dynlib: dllname.} +proc pPlotAddStr*(ih: PIhandle, x: cstring, y: cfloat) {. + cdecl, importc: "IupPPlotAddStr", dynlib: dllname.} +proc pPlotEnd*(ih: PIhandle): cint {. + cdecl, importc: "IupPPlotEnd", dynlib: dllname.} + +proc pPlotInsertStr*(ih: PIhandle, index, sampleIndex: cint, x: cstring, + y: cfloat) {.cdecl, importc: "IupPPlotInsertStr", + dynlib: dllname.} +proc pPlotInsert*(ih: PIhandle, index, sampleIndex: cint, + x, y: cfloat) {. + cdecl, importc: "IupPPlotInsert", dynlib: dllname.} + +# convert from plot coordinates to pixels +proc pPlotTransform*(ih: PIhandle, x, y: cfloat, ix, iy: var cint) {. + cdecl, importc: "IupPPlotTransform", dynlib: dllname.} + +# Plot on the given device. Uses a "cdCanvas*". +proc pPlotPaintTo*(ih: PIhandle, cnv: pointer) {. + cdecl, importc: "IupPPlotPaintTo", dynlib: dllname.} + + diff --git a/lib/wrappers/linenoise/linenoise.c b/lib/wrappers/linenoise/linenoise.c index be792b96b..ae185fece 100644 --- a/lib/wrappers/linenoise/linenoise.c +++ b/lib/wrappers/linenoise/linenoise.c @@ -765,7 +765,7 @@ void linenoiseEditDeletePrevWord(struct linenoiseState *l) { * when ctrl+d is typed. * * The function returns the length of the current buffer. */ -static int linenoiseEdit(int stdin_fd, int stdout_fd, char *buf, size_t buflen, const char *prompt, linenoiseData* data) +static int linenoiseEdit(int stdin_fd, int stdout_fd, char *buf, size_t buflen, const char *prompt) { struct linenoiseState l; @@ -827,7 +827,6 @@ static int linenoiseEdit(int stdin_fd, int stdout_fd, char *buf, size_t buflen, return (int)l.len; case CTRL_C: /* ctrl-c */ errno = EAGAIN; - data->status = linenoiseStatus_ctrl_C; return -1; case BACKSPACE: /* backspace */ case 8: /* ctrl-h */ @@ -840,7 +839,6 @@ static int linenoiseEdit(int stdin_fd, int stdout_fd, char *buf, size_t buflen, } else { history_len--; free(history[history_len]); - data->status = linenoiseStatus_ctrl_D; return -1; } break; @@ -981,7 +979,7 @@ void linenoisePrintKeyCodes(void) { /* This function calls the line editing function linenoiseEdit() using * the STDIN file descriptor set in raw mode. */ -static int linenoiseRaw(char *buf, size_t buflen, const char *prompt, linenoiseData* data) { +static int linenoiseRaw(char *buf, size_t buflen, const char *prompt) { int count; if (buflen == 0) { @@ -990,7 +988,7 @@ static int linenoiseRaw(char *buf, size_t buflen, const char *prompt, linenoiseD } if (enableRawMode(STDIN_FILENO) == -1) return -1; - count = linenoiseEdit(STDIN_FILENO, STDOUT_FILENO, buf, buflen, prompt, data); + count = linenoiseEdit(STDIN_FILENO, STDOUT_FILENO, buf, buflen, prompt); disableRawMode(STDIN_FILENO); printf("\n"); return count; @@ -1037,7 +1035,7 @@ static char *linenoiseNoTTY(void) { * for a blacklist of stupid terminals, and later either calls the line * editing function or uses dummy fgets() so that you will be able to type * something even in the most desperate of the conditions. */ -char *linenoiseExtra(const char *prompt, linenoiseData* data) { +char *linenoise(const char *prompt) { char buf[LINENOISE_MAX_LINE]; int count; @@ -1058,18 +1056,12 @@ char *linenoiseExtra(const char *prompt, linenoiseData* data) { } return strdup(buf); } else { - count = linenoiseRaw(buf,LINENOISE_MAX_LINE,prompt, data); + count = linenoiseRaw(buf,LINENOISE_MAX_LINE,prompt); if (count == -1) return NULL; return strdup(buf); } } -char *linenoise(const char *prompt) { - linenoiseData data; - data.status = linenoiseStatus_ctrl_unknown; - return linenoiseExtra(prompt, &data); -} - /* This is just a wrapper the user may want to call in order to make sure * the linenoise returned buffer is freed with the same allocator it was * created with. Useful when the main program is using an alternative diff --git a/lib/wrappers/linenoise/linenoise.h b/lib/wrappers/linenoise/linenoise.h index aa86ccb78..ed20232c5 100644 --- a/lib/wrappers/linenoise/linenoise.h +++ b/lib/wrappers/linenoise/linenoise.h @@ -48,16 +48,6 @@ typedef struct linenoiseCompletions { char **cvec; } linenoiseCompletions; -typedef enum linenoiseStatus { - linenoiseStatus_ctrl_unknown, - linenoiseStatus_ctrl_C, - linenoiseStatus_ctrl_D -} linenoiseStatus; - -typedef struct linenoiseData { - linenoiseStatus status; -} linenoiseData; - typedef void(linenoiseCompletionCallback)(const char *, linenoiseCompletions *); typedef char*(linenoiseHintsCallback)(const char *, int *color, int *bold); typedef void(linenoiseFreeHintsCallback)(void *); @@ -67,7 +57,6 @@ void linenoiseSetFreeHintsCallback(linenoiseFreeHintsCallback *); void linenoiseAddCompletion(linenoiseCompletions *, const char *); char *linenoise(const char *prompt); -char *linenoiseExtra(const char *prompt, linenoiseData* data); void linenoiseFree(void *ptr); int linenoiseHistoryAdd(const char *line); int linenoiseHistorySetMaxLen(int len); diff --git a/lib/wrappers/linenoise/linenoise.nim b/lib/wrappers/linenoise/linenoise.nim index 186b3b252..a6260eb12 100644 --- a/lib/wrappers/linenoise/linenoise.nim +++ b/lib/wrappers/linenoise/linenoise.nim @@ -9,14 +9,14 @@ type Completions* = object - len*: csize_t + len*: csize cvec*: cstringArray CompletionCallback* = proc (a2: cstring; a3: ptr Completions) {.cdecl.} {.compile: "linenoise.c".} -proc setCompletionCallback*(a2: CompletionCallback) {. +proc setCompletionCallback*(a2: ptr CompletionCallback) {. importc: "linenoiseSetCompletionCallback".} proc addCompletion*(a2: ptr Completions; a3: cstring) {. importc: "linenoiseAddCompletion".} @@ -32,41 +32,3 @@ proc printKeyCodes*() {.importc: "linenoisePrintKeyCodes".} proc free*(s: cstring) {.importc: "free", header: "".} -when defined(nimExperimentalLinenoiseExtra) and not defined(windows): - # C interface - type LinenoiseStatus = enum - linenoiseStatus_ctrl_unknown - linenoiseStatus_ctrl_C - linenoiseStatus_ctrl_D - - type LinenoiseData* = object - status: LinenoiseStatus - - proc linenoiseExtra(prompt: cstring, data: ptr LinenoiseData): cstring {.importc.} - - # stable nim interface - type Status* = enum - lnCtrlUnkown - lnCtrlC - lnCtrlD - - type ReadLineResult* = object - line*: string - status*: Status - - proc readLineStatus*(prompt: string, result: var ReadLineResult) = - ## line editing API that allows returning the line entered and an indicator - ## of which control key was entered, allowing user to distinguish between - ## for example ctrl-C vs ctrl-D. - runnableExamples("-d:nimExperimentalLinenoiseExtra -r:off"): - var ret: ReadLineResult - while true: - readLineStatus("name: ", ret) # ctrl-D will exit, ctrl-C will go to next prompt - if ret.line.len > 0: echo ret.line - if ret.status == lnCtrlD: break - echo "exiting" - var data: LinenoiseData - let buf = linenoiseExtra(prompt, data.addr) - result.line = $buf - free(buf) - result.status = data.status.ord.Status diff --git a/lib/wrappers/mysql.nim b/lib/wrappers/mysql.nim new file mode 100644 index 000000000..f8d4739ae --- /dev/null +++ b/lib/wrappers/mysql.nim @@ -0,0 +1,1116 @@ +# +# +# Nim's Runtime Library +# (c) Copyright 2010 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +{.deadCodeElim: on.} # dce option deprecated +{.push, callconv: cdecl.} +when defined(nimHasStyleChecks): + {.push styleChecks: off.} + +when defined(Unix): + when defined(macosx): + const + lib = "(libmysqlclient|libmariadbclient)(|.20|.19|.18|.17|.16|.15).dylib" + else: + const + lib = "(libmysqlclient|libmariadbclient).so(|.20|.19|.18|.17|.16|.15)" +when defined(Windows): + const + lib = "(libmysql.dll|libmariadb.dll)" +type + my_bool* = bool + Pmy_bool* = ptr my_bool + PVIO* = pointer + Pgptr* = ptr gptr + gptr* = cstring + Pmy_socket* = ptr my_socket + my_socket* = cint + PPByte* = pointer + cuint* = cint + +# ------------ Start of declaration in "mysql_com.h" --------------------- +# +# ** Common definition between mysql server & client +# +# Field/table name length + +const + NAME_LEN* = 64 + HOSTNAME_LENGTH* = 60 + USERNAME_LENGTH* = 16 + SERVER_VERSION_LENGTH* = 60 + SQLSTATE_LENGTH* = 5 + LOCAL_HOST* = "localhost" + LOCAL_HOST_NAMEDPIPE* = '.' + +const + NAMEDPIPE* = "MySQL" + SERVICENAME* = "MySQL" + +type + Enum_server_command* = enum + COM_SLEEP, COM_QUIT, COM_INIT_DB, COM_QUERY, COM_FIELD_LIST, COM_CREATE_DB, + COM_DROP_DB, COM_REFRESH, COM_SHUTDOWN, COM_STATISTICS, COM_PROCESS_INFO, + COM_CONNECT, COM_PROCESS_KILL, COM_DEBUG, COM_PING, COM_TIME, + COM_DELAYED_INSERT, COM_CHANGE_USER, COM_BINLOG_DUMP, COM_TABLE_DUMP, + COM_CONNECT_OUT, COM_REGISTER_SLAVE, COM_STMT_PREPARE, COM_STMT_EXECUTE, + COM_STMT_SEND_LONG_DATA, COM_STMT_CLOSE, COM_STMT_RESET, COM_SET_OPTION, + COM_STMT_FETCH, COM_END +{.deprecated: [Tenum_server_command: Enum_server_command].} + +const + SCRAMBLE_LENGTH* = 20 # Length of random string sent by server on handshake; + # this is also length of obfuscated password, + # received from client + SCRAMBLE_LENGTH_323* = 8 # length of password stored in the db: + # new passwords are preceded with '*' + SCRAMBLED_PASSWORD_CHAR_LENGTH* = SCRAMBLE_LENGTH * 2 + 1 + SCRAMBLED_PASSWORD_CHAR_LENGTH_323* = SCRAMBLE_LENGTH_323 * 2 + NOT_NULL_FLAG* = 1 # Field can't be NULL + PRI_KEY_FLAG* = 2 # Field is part of a primary key + UNIQUE_KEY_FLAG* = 4 # Field is part of a unique key + MULTIPLE_KEY_FLAG* = 8 # Field is part of a key + BLOB_FLAG* = 16 # Field is a blob + UNSIGNED_FLAG* = 32 # Field is unsigned + ZEROFILL_FLAG* = 64 # Field is zerofill + BINARY_FLAG* = 128 # Field is binary + # The following are only sent to new clients + ENUM_FLAG* = 256 # field is an enum + AUTO_INCREMENT_FLAG* = 512 # field is a autoincrement field + TIMESTAMP_FLAG* = 1024 # Field is a timestamp + SET_FLAG* = 2048 # field is a set + NO_DEFAULT_VALUE_FLAG* = 4096 # Field doesn't have default value + NUM_FLAG* = 32768 # Field is num (for clients) + PART_KEY_FLAG* = 16384 # Intern; Part of some key + GROUP_FLAG* = 32768 # Intern: Group field + UNIQUE_FLAG* = 65536 # Intern: Used by sql_yacc + BINCMP_FLAG* = 131072 # Intern: Used by sql_yacc + REFRESH_GRANT* = 1 # Refresh grant tables + REFRESH_LOG* = 2 # Start on new log file + REFRESH_TABLES* = 4 # close all tables + REFRESH_HOSTS* = 8 # Flush host cache + REFRESH_STATUS* = 16 # Flush status variables + REFRESH_THREADS* = 32 # Flush thread cache + REFRESH_SLAVE* = 64 # Reset master info and restart slave thread + REFRESH_MASTER* = 128 # Remove all bin logs in the index and truncate the index + # The following can't be set with mysql_refresh() + REFRESH_READ_LOCK* = 16384 # Lock tables for read + REFRESH_FAST* = 32768 # Intern flag + REFRESH_QUERY_CACHE* = 65536 # RESET (remove all queries) from query cache + REFRESH_QUERY_CACHE_FREE* = 0x00020000 # pack query cache + REFRESH_DES_KEY_FILE* = 0x00040000 + REFRESH_USER_RESOURCES* = 0x00080000 + CLIENT_LONG_PASSWORD* = 1 # new more secure passwords + CLIENT_FOUND_ROWS* = 2 # Found instead of affected rows + CLIENT_LONG_FLAG* = 4 # Get all column flags + CLIENT_CONNECT_WITH_DB* = 8 # One can specify db on connect + CLIENT_NO_SCHEMA* = 16 # Don't allow database.table.column + CLIENT_COMPRESS* = 32 # Can use compression protocol + CLIENT_ODBC* = 64 # Odbc client + CLIENT_LOCAL_FILES* = 128 # Can use LOAD DATA LOCAL + CLIENT_IGNORE_SPACE* = 256 # Ignore spaces before '(' + CLIENT_PROTOCOL_41* = 512 # New 4.1 protocol + CLIENT_INTERACTIVE* = 1024 # This is an interactive client + CLIENT_SSL* = 2048 # Switch to SSL after handshake + CLIENT_IGNORE_SIGPIPE* = 4096 # IGNORE sigpipes + CLIENT_TRANSACTIONS* = 8192 # Client knows about transactions + CLIENT_RESERVED* = 16384 # Old flag for 4.1 protocol + CLIENT_SECURE_CONNECTION* = 32768 # New 4.1 authentication + CLIENT_MULTI_STATEMENTS* = 65536 # Enable/disable multi-stmt support + CLIENT_MULTI_RESULTS* = 131072 # Enable/disable multi-results + CLIENT_REMEMBER_OPTIONS*: int = 1 shl 31 + SERVER_STATUS_IN_TRANS* = 1 # Transaction has started + SERVER_STATUS_AUTOCOMMIT* = 2 # Server in auto_commit mode + SERVER_STATUS_MORE_RESULTS* = 4 # More results on server + SERVER_MORE_RESULTS_EXISTS* = 8 # Multi query - next query exists + SERVER_QUERY_NO_GOOD_INDEX_USED* = 16 + SERVER_QUERY_NO_INDEX_USED* = 32 # The server was able to fulfill the clients request and opened a + # read-only non-scrollable cursor for a query. This flag comes + # in reply to COM_STMT_EXECUTE and COM_STMT_FETCH commands. + SERVER_STATUS_CURSOR_EXISTS* = 64 # This flag is sent when a read-only cursor is exhausted, in reply to + # COM_STMT_FETCH command. + SERVER_STATUS_LAST_ROW_SENT* = 128 + SERVER_STATUS_DB_DROPPED* = 256 # A database was dropped + SERVER_STATUS_NO_BACKSLASH_ESCAPES* = 512 + ERRMSG_SIZE* = 200 + NET_READ_TIMEOUT* = 30 # Timeout on read + NET_WRITE_TIMEOUT* = 60 # Timeout on write + NET_WAIT_TIMEOUT* = 8 * 60 * 60 # Wait for new query + ONLY_KILL_QUERY* = 1 + +const + MAX_TINYINT_WIDTH* = 3 # Max width for a TINY w.o. sign + MAX_SMALLINT_WIDTH* = 5 # Max width for a SHORT w.o. sign + MAX_MEDIUMINT_WIDTH* = 8 # Max width for a INT24 w.o. sign + MAX_INT_WIDTH* = 10 # Max width for a LONG w.o. sign + MAX_BIGINT_WIDTH* = 20 # Max width for a LONGLONG + MAX_CHAR_WIDTH* = 255 # Max length for a CHAR column + MAX_BLOB_WIDTH* = 8192 # Default width for blob + +type + Pst_net* = ptr St_net + St_net*{.final.} = object + vio*: PVIO + buff*: cstring + buff_end*: cstring + write_pos*: cstring + read_pos*: cstring + fd*: my_socket # For Perl DBI/dbd + max_packet*: int + max_packet_size*: int + pkt_nr*: cuint + compress_pkt_nr*: cuint + write_timeout*: cuint + read_timeout*: cuint + retry_count*: cuint + fcntl*: cint + compress*: my_bool # The following variable is set if we are doing several queries in one + # command ( as in LOAD TABLE ... FROM MASTER ), + # and do not want to confuse the client with OK at the wrong time + remain_in_buf*: int + len*: int + buf_length*: int + where_b*: int + return_status*: ptr cint + reading_or_writing*: char + save_char*: cchar + no_send_ok*: my_bool # For SPs and other things that do multiple stmts + no_send_eof*: my_bool # For SPs' first version read-only cursors + no_send_error*: my_bool # Set if OK packet is already sent, and + # we do not need to send error messages + # Pointer to query object in query cache, do not equal NULL (0) for + # queries in cache that have not stored its results yet + # $endif + last_error*: array[0..(ERRMSG_SIZE) - 1, char] + sqlstate*: array[0..(SQLSTATE_LENGTH + 1) - 1, char] + last_errno*: cuint + error*: char + query_cache_query*: gptr + report_error*: my_bool # We should report error (we have unreported error) + return_errno*: my_bool + + NET* = St_net + PNET* = ptr NET +{.deprecated: [Tst_net: St_net, TNET: NET].} + +const + packet_error* = - 1 + +type + Enum_field_types* = enum # For backward compatibility + TYPE_DECIMAL, TYPE_TINY, TYPE_SHORT, TYPE_LONG, TYPE_FLOAT, TYPE_DOUBLE, + TYPE_NULL, TYPE_TIMESTAMP, TYPE_LONGLONG, TYPE_INT24, TYPE_DATE, TYPE_TIME, + TYPE_DATETIME, TYPE_YEAR, TYPE_NEWDATE, TYPE_VARCHAR, TYPE_BIT, + TYPE_NEWDECIMAL = 246, TYPE_ENUM = 247, TYPE_SET = 248, + TYPE_TINY_BLOB = 249, TYPE_MEDIUM_BLOB = 250, TYPE_LONG_BLOB = 251, + TYPE_BLOB = 252, TYPE_VAR_STRING = 253, TYPE_STRING = 254, + TYPE_GEOMETRY = 255 +{.deprecated: [Tenum_field_types: Enum_field_types].} + +const + CLIENT_MULTI_QUERIES* = CLIENT_MULTI_STATEMENTS + FIELD_TYPE_DECIMAL* = TYPE_DECIMAL + FIELD_TYPE_NEWDECIMAL* = TYPE_NEWDECIMAL + FIELD_TYPE_TINY* = TYPE_TINY + FIELD_TYPE_SHORT* = TYPE_SHORT + FIELD_TYPE_LONG* = TYPE_LONG + FIELD_TYPE_FLOAT* = TYPE_FLOAT + FIELD_TYPE_DOUBLE* = TYPE_DOUBLE + FIELD_TYPE_NULL* = TYPE_NULL + FIELD_TYPE_TIMESTAMP* = TYPE_TIMESTAMP + FIELD_TYPE_LONGLONG* = TYPE_LONGLONG + FIELD_TYPE_INT24* = TYPE_INT24 + FIELD_TYPE_DATE* = TYPE_DATE + FIELD_TYPE_TIME* = TYPE_TIME + FIELD_TYPE_DATETIME* = TYPE_DATETIME + FIELD_TYPE_YEAR* = TYPE_YEAR + FIELD_TYPE_NEWDATE* = TYPE_NEWDATE + FIELD_TYPE_ENUM* = TYPE_ENUM + FIELD_TYPE_SET* = TYPE_SET + FIELD_TYPE_TINY_BLOB* = TYPE_TINY_BLOB + FIELD_TYPE_MEDIUM_BLOB* = TYPE_MEDIUM_BLOB + FIELD_TYPE_LONG_BLOB* = TYPE_LONG_BLOB + FIELD_TYPE_BLOB* = TYPE_BLOB + FIELD_TYPE_VAR_STRING* = TYPE_VAR_STRING + FIELD_TYPE_STRING* = TYPE_STRING + FIELD_TYPE_CHAR* = TYPE_TINY + FIELD_TYPE_INTERVAL* = TYPE_ENUM + FIELD_TYPE_GEOMETRY* = TYPE_GEOMETRY + FIELD_TYPE_BIT* = TYPE_BIT # Shutdown/kill enums and constants + # Bits for THD::killable. + SHUTDOWN_KILLABLE_CONNECT* = chr(1 shl 0) + SHUTDOWN_KILLABLE_TRANS* = chr(1 shl 1) + SHUTDOWN_KILLABLE_LOCK_TABLE* = chr(1 shl 2) + SHUTDOWN_KILLABLE_UPDATE* = chr(1 shl 3) + +type + Enum_shutdown_level* = enum + SHUTDOWN_DEFAULT = 0, SHUTDOWN_WAIT_CONNECTIONS = 1, + SHUTDOWN_WAIT_TRANSACTIONS = 2, SHUTDOWN_WAIT_UPDATES = 8, + SHUTDOWN_WAIT_ALL_BUFFERS = 16, SHUTDOWN_WAIT_CRITICAL_BUFFERS = 17, + KILL_QUERY = 254, KILL_CONNECTION = 255 + Enum_cursor_type* = enum # options for mysql_set_option + CURSOR_TYPE_NO_CURSOR = 0, CURSOR_TYPE_READ_ONLY = 1, + CURSOR_TYPE_FOR_UPDATE = 2, CURSOR_TYPE_SCROLLABLE = 4 + Enum_mysql_set_option* = enum + OPTION_MULTI_STATEMENTS_ON, OPTION_MULTI_STATEMENTS_OFF +{.deprecated: [Tenum_shutdown_level: Enum_shutdown_level, + Tenum_cursor_type: Enum_cursor_type, + Tenum_mysql_set_option: Enum_mysql_set_option].} + +proc my_net_init*(net: PNET, vio: PVIO): my_bool{.cdecl, dynlib: lib, + importc: "my_net_init".} +proc my_net_local_init*(net: PNET){.cdecl, dynlib: lib, + importc: "my_net_local_init".} +proc net_end*(net: PNET){.cdecl, dynlib: lib, importc: "net_end".} +proc net_clear*(net: PNET){.cdecl, dynlib: lib, importc: "net_clear".} +proc net_realloc*(net: PNET, len: int): my_bool{.cdecl, dynlib: lib, + importc: "net_realloc".} +proc net_flush*(net: PNET): my_bool{.cdecl, dynlib: lib, importc: "net_flush".} +proc my_net_write*(net: PNET, packet: cstring, length: int): my_bool{.cdecl, + dynlib: lib, importc: "my_net_write".} +proc net_write_command*(net: PNET, command: char, header: cstring, + head_len: int, packet: cstring, length: int): my_bool{. + cdecl, dynlib: lib, importc: "net_write_command".} +proc net_real_write*(net: PNET, packet: cstring, length: int): cint{.cdecl, + dynlib: lib, importc: "net_real_write".} +proc my_net_read*(net: PNET): int{.cdecl, dynlib: lib, importc: "my_net_read".} + # The following function is not meant for normal usage + # Currently it's used internally by manager.c +type + Psockaddr* = ptr Sockaddr + Sockaddr*{.final.} = object # undefined structure +{.deprecated: [Tsockaddr: Sockaddr].} + +proc my_connect*(s: my_socket, name: Psockaddr, namelen: cuint, timeout: cuint): cint{. + cdecl, dynlib: lib, importc: "my_connect".} +type + Prand_struct* = ptr Rand_struct + Rand_struct*{.final.} = object # The following is for user defined functions + seed1*: int + seed2*: int + max_value*: int + max_value_dbl*: cdouble + + Item_result* = enum + STRING_RESULT, REAL_RESULT, INT_RESULT, ROW_RESULT, DECIMAL_RESULT + PItem_result* = ptr Item_result + Pst_udf_args* = ptr St_udf_args + St_udf_args*{.final.} = object + arg_count*: cuint # Number of arguments + arg_type*: PItem_result # Pointer to item_results + args*: cstringArray # Pointer to item_results + lengths*: ptr int # Length of string arguments + maybe_null*: cstring # Length of string arguments + attributes*: cstringArray # Pointer to attribute name + attribute_lengths*: ptr int # Length of attribute arguments + + UDF_ARGS* = St_udf_args + PUDF_ARGS* = ptr UDF_ARGS # This holds information about the result + Pst_udf_init* = ptr St_udf_init + St_udf_init*{.final.} = object + maybe_null*: my_bool # 1 if function can return NULL + decimals*: cuint # for real functions + max_length*: int # For string functions + theptr*: cstring # free pointer for function data + const_item*: my_bool # free pointer for function data + + UDF_INIT* = St_udf_init + PUDF_INIT* = ptr UDF_INIT # Constants when using compression +{.deprecated: [Trand_stuct: Rand_struct, TItem_result: Item_result, + Tst_udf_args: St_udf_args, TUDF_ARGS: UDF_ARGS, + Tst_udf_init: St_udf_init, TUDF_INIT: UDF_INIT].} + +const + NET_HEADER_SIZE* = 4 # standard header size + COMP_HEADER_SIZE* = 3 # compression header extra size + # Prototypes to password functions + # These functions are used for authentication by client and server and + # implemented in sql/password.c + +proc randominit*(para1: Prand_struct, seed1: int, seed2: int){.cdecl, + dynlib: lib, importc: "randominit".} +proc my_rnd*(para1: Prand_struct): cdouble{.cdecl, dynlib: lib, + importc: "my_rnd".} +proc create_random_string*(fto: cstring, len: cuint, rand_st: Prand_struct){. + cdecl, dynlib: lib, importc: "create_random_string".} +proc hash_password*(fto: int, password: cstring, password_len: cuint){.cdecl, + dynlib: lib, importc: "hash_password".} +proc make_scrambled_password_323*(fto: cstring, password: cstring){.cdecl, + dynlib: lib, importc: "make_scrambled_password_323".} +proc scramble_323*(fto: cstring, message: cstring, password: cstring){.cdecl, + dynlib: lib, importc: "scramble_323".} +proc check_scramble_323*(para1: cstring, message: cstring, salt: int): my_bool{. + cdecl, dynlib: lib, importc: "check_scramble_323".} +proc get_salt_from_password_323*(res: ptr int, password: cstring){.cdecl, + dynlib: lib, importc: "get_salt_from_password_323".} +proc make_password_from_salt_323*(fto: cstring, salt: ptr int){.cdecl, + dynlib: lib, importc: "make_password_from_salt_323".} +proc octet2hex*(fto: cstring, str: cstring, length: cuint): cstring{.cdecl, + dynlib: lib, importc: "octet2hex".} +proc make_scrambled_password*(fto: cstring, password: cstring){.cdecl, + dynlib: lib, importc: "make_scrambled_password".} +proc scramble*(fto: cstring, message: cstring, password: cstring){.cdecl, + dynlib: lib, importc: "scramble".} +proc check_scramble*(reply: cstring, message: cstring, hash_stage2: pointer): my_bool{. + cdecl, dynlib: lib, importc: "check_scramble".} +proc get_salt_from_password*(res: pointer, password: cstring){.cdecl, + dynlib: lib, importc: "get_salt_from_password".} +proc make_password_from_salt*(fto: cstring, hash_stage2: pointer){.cdecl, + dynlib: lib, importc: "make_password_from_salt".} + # end of password.c +proc get_tty_password*(opt_message: cstring): cstring{.cdecl, dynlib: lib, + importc: "get_tty_password".} +proc errno_to_sqlstate*(errno: cuint): cstring{.cdecl, dynlib: lib, + importc: "mysql_errno_to_sqlstate".} + # Some other useful functions +proc modify_defaults_file*(file_location: cstring, option: cstring, + option_value: cstring, section_name: cstring, + remove_option: cint): cint{.cdecl, dynlib: lib, + importc: "load_defaults".} +proc load_defaults*(conf_file: cstring, groups: cstringArray, argc: ptr cint, + argv: ptr cstringArray): cint{.cdecl, dynlib: lib, + importc: "load_defaults".} +proc my_init*(): my_bool{.cdecl, dynlib: lib, importc: "my_init".} +proc my_thread_init*(): my_bool{.cdecl, dynlib: lib, importc: "my_thread_init".} +proc my_thread_end*(){.cdecl, dynlib: lib, importc: "my_thread_end".} +const + NULL_LENGTH*: int = int(not (0)) # For net_store_length + +const + STMT_HEADER* = 4 + LONG_DATA_HEADER* = 6 # ------------ Stop of declaration in "mysql_com.h" ----------------------- + # $include "mysql_time.h" + # $include "mysql_version.h" + # $include "typelib.h" + # $include "my_list.h" /* for LISTs used in 'MYSQL' and 'MYSQL_STMT' */ + # var + # mysql_port : cuint;cvar;external; + # mysql_unix_port : Pchar;cvar;external; + +const + CLIENT_NET_READ_TIMEOUT* = 365 * 24 * 3600 # Timeout on read + CLIENT_NET_WRITE_TIMEOUT* = 365 * 24 * 3600 # Timeout on write + +type + Pst_mysql_field* = ptr St_mysql_field + St_mysql_field*{.final.} = object + name*: cstring # Name of column + org_name*: cstring # Original column name, if an alias + table*: cstring # Table of column if column was a field + org_table*: cstring # Org table name, if table was an alias + db*: cstring # Database for table + catalog*: cstring # Catalog for table + def*: cstring # Default value (set by mysql_list_fields) + len*: int # Width of column (create length) + max_length*: int # Max width for selected set + name_length*: cuint + org_name_length*: cuint + table_length*: cuint + org_table_length*: cuint + db_length*: cuint + catalog_length*: cuint + def_length*: cuint + flags*: cuint # Div flags + decimals*: cuint # Number of decimals in field + charsetnr*: cuint # Character set + ftype*: Enum_field_types # Type of field. See mysql_com.h for types + extension*: pointer + + FIELD* = St_mysql_field + PFIELD* = ptr FIELD + PROW* = ptr ROW # return data as array of strings + ROW* = cstringArray + PFIELD_OFFSET* = ptr FIELD_OFFSET # offset to current field + FIELD_OFFSET* = cuint +{.deprecated: [Tst_mysql_field: St_mysql_field, TFIELD: FIELD, TROW: ROW, + TFIELD_OFFSET: FIELD_OFFSET].} + +proc IS_PRI_KEY*(n: int32): bool +proc IS_NOT_NULL*(n: int32): bool +proc IS_BLOB*(n: int32): bool +proc IS_NUM*(t: Enum_field_types): bool +proc INTERNAL_NUM_FIELD*(f: Pst_mysql_field): bool +proc IS_NUM_FIELD*(f: Pst_mysql_field): bool +type + my_ulonglong* = int64 + Pmy_ulonglong* = ptr my_ulonglong + +const + COUNT_ERROR* = not (my_ulonglong(0)) + +type + Pst_mysql_rows* = ptr St_mysql_rows + St_mysql_rows*{.final.} = object + next*: Pst_mysql_rows # list of rows + data*: ROW + len*: int + + ROWS* = St_mysql_rows + PROWS* = ptr ROWS + PROW_OFFSET* = ptr ROW_OFFSET # offset to current row + ROW_OFFSET* = ROWS +{.deprecated: [Tst_mysql_rows: St_mysql_rows, TROWS: ROWS, + TROW_OFFSET: ROW_OFFSET].} + +const + ALLOC_MAX_BLOCK_TO_DROP* = 4096 + ALLOC_MAX_BLOCK_USAGE_BEFORE_DROP* = 10 # struct for once_alloc (block) + +type + Pst_used_mem* = ptr St_used_mem + St_used_mem*{.final.} = object + next*: Pst_used_mem # Next block in use + left*: cuint # memory left in block + size*: cuint # size of block + + USED_MEM* = St_used_mem + PUSED_MEM* = ptr USED_MEM + Pst_mem_root* = ptr St_mem_root + St_mem_root*{.final.} = object + free*: PUSED_MEM # blocks with free memory in it + used*: PUSED_MEM # blocks almost without free memory + pre_alloc*: PUSED_MEM # preallocated block + min_malloc*: cuint # if block have less memory it will be put in 'used' list + block_size*: cuint # initial block size + block_num*: cuint # allocated blocks counter + # first free block in queue test counter (if it exceed + # MAX_BLOCK_USAGE_BEFORE_DROP block will be dropped in 'used' list) + first_block_usage*: cuint + error_handler*: proc (){.cdecl.} + + MEM_ROOT* = St_mem_root + PMEM_ROOT* = ptr MEM_ROOT # ------------ Stop of declaration in "my_alloc.h" ---------------------- +{.deprecated: [Tst_used_mem: St_used_mem, TUSED_MEM: USED_MEM, + Tst_mem_root: St_mem_root, TMEM_ROOT: MEM_ROOT].} + +type + Pst_mysql_data* = ptr St_mysql_data + St_mysql_data*{.final.} = object + rows*: my_ulonglong + fields*: cuint + data*: PROWS + alloc*: MEM_ROOT + prev_ptr*: ptr PROWS + + DATA* = St_mysql_data + PDATA* = ptr DATA + Option* = enum + OPT_CONNECT_TIMEOUT, OPT_COMPRESS, OPT_NAMED_PIPE, INIT_COMMAND, + READ_DEFAULT_FILE, READ_DEFAULT_GROUP, SET_CHARSET_DIR, SET_CHARSET_NAME, + OPT_LOCAL_INFILE, OPT_PROTOCOL, SHARED_MEMORY_BASE_NAME, OPT_READ_TIMEOUT, + OPT_WRITE_TIMEOUT, OPT_USE_RESULT, OPT_USE_REMOTE_CONNECTION, + OPT_USE_EMBEDDED_CONNECTION, OPT_GUESS_CONNECTION, SET_CLIENT_IP, + SECURE_AUTH, REPORT_DATA_TRUNCATION, OPT_RECONNECT +{.deprecated: [Tst_mysql_data: St_mysql_data, TDATA: DATA, Toption: Option].} + +const + MAX_MYSQL_MANAGER_ERR* = 256 + MAX_MYSQL_MANAGER_MSG* = 256 + MANAGER_OK* = 200 + MANAGER_INFO* = 250 + MANAGER_ACCESS* = 401 + MANAGER_CLIENT_ERR* = 450 + MANAGER_INTERNAL_ERR* = 500 + +type + St_dynamic_array*{.final.} = object + buffer*: cstring + elements*: cuint + max_element*: cuint + alloc_increment*: cuint + size_of_element*: cuint + + DYNAMIC_ARRAY* = St_dynamic_array + Pst_dynamic_array* = ptr St_dynamic_array + Pst_mysql_options* = ptr St_mysql_options + St_mysql_options*{.final.} = object + connect_timeout*: cuint + read_timeout*: cuint + write_timeout*: cuint + port*: cuint + protocol*: cuint + client_flag*: int + host*: cstring + user*: cstring + password*: cstring + unix_socket*: cstring + db*: cstring + init_commands*: Pst_dynamic_array + my_cnf_file*: cstring + my_cnf_group*: cstring + charset_dir*: cstring + charset_name*: cstring + ssl_key*: cstring # PEM key file + ssl_cert*: cstring # PEM cert file + ssl_ca*: cstring # PEM CA file + ssl_capath*: cstring # PEM directory of CA-s? + ssl_cipher*: cstring # cipher to use + shared_memory_base_name*: cstring + max_allowed_packet*: int + use_ssl*: my_bool # if to use SSL or not + compress*: my_bool + named_pipe*: my_bool # On connect, find out the replication role of the server, and + # establish connections to all the peers + rpl_probe*: my_bool # Each call to mysql_real_query() will parse it to tell if it is a read + # or a write, and direct it to the slave or the master + rpl_parse*: my_bool # If set, never read from a master, only from slave, when doing + # a read that is replication-aware + no_master_reads*: my_bool + separate_thread*: my_bool + methods_to_use*: Option + client_ip*: cstring + secure_auth*: my_bool # Refuse client connecting to server if it uses old (pre-4.1.1) protocol + report_data_truncation*: my_bool # 0 - never report, 1 - always report (default) + # function pointers for local infile support + local_infile_init*: proc (para1: var pointer, para2: cstring, para3: pointer): cint{. + cdecl.} + local_infile_read*: proc (para1: pointer, para2: cstring, para3: cuint): cint + local_infile_end*: proc (para1: pointer) + local_infile_error*: proc (para1: pointer, para2: cstring, para3: cuint): cint + local_infile_userdata*: pointer + + Status* = enum + STATUS_READY, STATUS_GET_RESULT, STATUS_USE_RESULT + Protocol_type* = enum # There are three types of queries - the ones that have to go to + # the master, the ones that go to a slave, and the administrative + # type which must happen on the pivot connection + PROTOCOL_DEFAULT, PROTOCOL_TCP, PROTOCOL_SOCKET, PROTOCOL_PIPE, + PROTOCOL_MEMORY + Rpl_type* = enum + RPL_MASTER, RPL_SLAVE, RPL_ADMIN + Charset_info_st*{.final.} = object + number*: cuint + primary_number*: cuint + binary_number*: cuint + state*: cuint + csname*: cstring + name*: cstring + comment*: cstring + tailoring*: cstring + ftype*: cstring + to_lower*: cstring + to_upper*: cstring + sort_order*: cstring + contractions*: ptr int16 + sort_order_big*: ptr ptr int16 + tab_to_uni*: ptr int16 + tab_from_uni*: pointer # was ^MY_UNI_IDX + state_map*: cstring + ident_map*: cstring + strxfrm_multiply*: cuint + mbminlen*: cuint + mbmaxlen*: cuint + min_sort_char*: int16 + max_sort_char*: int16 + escape_with_backslash_is_dangerous*: my_bool + cset*: pointer # was ^MY_CHARSET_HANDLER + coll*: pointer # was ^MY_COLLATION_HANDLER; + + CHARSET_INFO* = Charset_info_st + Pcharset_info_st* = ptr Charset_info_st + Pcharacter_set* = ptr Character_set + Character_set*{.final.} = object + number*: cuint + state*: cuint + csname*: cstring + name*: cstring + comment*: cstring + dir*: cstring + mbminlen*: cuint + mbmaxlen*: cuint + + MY_CHARSET_INFO* = Character_set + PMY_CHARSET_INFO* = ptr MY_CHARSET_INFO + Pst_mysql_methods* = ptr St_mysql_methods + Pst_mysql* = ptr St_mysql + St_mysql*{.final.} = object + net*: NET # Communication parameters + connector_fd*: gptr # ConnectorFd for SSL + host*: cstring + user*: cstring + passwd*: cstring + unix_socket*: cstring + server_version*: cstring + host_info*: cstring + info*: cstring + db*: cstring + charset*: Pcharset_info_st + fields*: PFIELD + field_alloc*: MEM_ROOT + affected_rows*: my_ulonglong + insert_id*: my_ulonglong # id if insert on table with NEXTNR + extra_info*: my_ulonglong # Used by mysqlshow, not used by mysql 5.0 and up + thread_id*: int # Id for connection in server + packet_length*: int + port*: cuint + client_flag*: int + server_capabilities*: int + protocol_version*: cuint + field_count*: cuint + server_status*: cuint + server_language*: cuint + warning_count*: cuint + options*: St_mysql_options + status*: Status + free_me*: my_bool # If free in mysql_close + reconnect*: my_bool # set to 1 if automatic reconnect + scramble*: array[0..(SCRAMBLE_LENGTH + 1) - 1, char] # session-wide random string + # Set if this is the original connection, not a master or a slave we have + # added though mysql_rpl_probe() or mysql_set_master()/ mysql_add_slave() + rpl_pivot*: my_bool # Pointers to the master, and the next slave connections, points to + # itself if lone connection. + master*: Pst_mysql + next_slave*: Pst_mysql + last_used_slave*: Pst_mysql # needed for round-robin slave pick + last_used_con*: Pst_mysql # needed for send/read/store/use result to work correctly with replication + stmts*: pointer # was PList, list of all statements + methods*: Pst_mysql_methods + thd*: pointer # Points to boolean flag in MYSQL_RES or MYSQL_STMT. We set this flag + # from mysql_stmt_close if close had to cancel result set of this object. + unbuffered_fetch_owner*: Pmy_bool + + MySQL* = St_mysql + PMySQL* = ptr MySQL + Pst_mysql_res* = ptr St_mysql_res + St_mysql_res*{.final.} = object + row_count*: my_ulonglong + fields*: PFIELD + data*: PDATA + data_cursor*: PROWS + lengths*: ptr int # column lengths of current row + handle*: PMySQL # for unbuffered reads + field_alloc*: MEM_ROOT + field_count*: cuint + current_field*: cuint + row*: ROW # If unbuffered read + current_row*: ROW # buffer to current row + eof*: my_bool # Used by mysql_fetch_row + unbuffered_fetch_cancelled*: my_bool # mysql_stmt_close() had to cancel this result + methods*: Pst_mysql_methods + + RES* = St_mysql_res + PRES* = ptr RES + Pst_mysql_stmt* = ptr St_mysql_stmt + PSTMT* = ptr STMT + St_mysql_methods*{.final.} = object + read_query_result*: proc (MySQL: PMySQL): my_bool{.cdecl.} + advanced_command*: proc (MySQL: PMySQL, command: Enum_server_command, header: cstring, + header_length: int, arg: cstring, arg_length: int, + skip_check: my_bool): my_bool + read_rows*: proc (MySQL: PMySQL, fields: PFIELD, fields_count: cuint): PDATA + use_result*: proc (MySQL: PMySQL): PRES + fetch_lengths*: proc (fto: ptr int, column: ROW, field_count: cuint) + flush_use_result*: proc (MySQL: PMySQL) + list_fields*: proc (MySQL: PMySQL): PFIELD + read_prepare_result*: proc (MySQL: PMySQL, stmt: PSTMT): my_bool + stmt_execute*: proc (stmt: PSTMT): cint + read_binary_rows*: proc (stmt: PSTMT): cint + unbuffered_fetch*: proc (MySQL: PMySQL, row: cstringArray): cint + free_embedded_thd*: proc (MySQL: PMySQL) + read_statistics*: proc (MySQL: PMySQL): cstring + next_result*: proc (MySQL: PMySQL): my_bool + read_change_user_result*: proc (MySQL: PMySQL, buff: cstring, passwd: cstring): cint + read_rowsfrom_cursor*: proc (stmt: PSTMT): cint + + METHODS* = St_mysql_methods + PMETHODS* = ptr METHODS + Pst_mysql_manager* = ptr St_mysql_manager + St_mysql_manager*{.final.} = object + net*: NET + host*: cstring + user*: cstring + passwd*: cstring + port*: cuint + free_me*: my_bool + eof*: my_bool + cmd_status*: cint + last_errno*: cint + net_buf*: cstring + net_buf_pos*: cstring + net_data_end*: cstring + net_buf_size*: cint + last_error*: array[0..(MAX_MYSQL_MANAGER_ERR) - 1, char] + + MANAGER* = St_mysql_manager + PMANAGER* = ptr MANAGER + Pst_mysql_parameters* = ptr St_mysql_parameters + St_mysql_parameters*{.final.} = object + p_max_allowed_packet*: ptr int + p_net_buffer_length*: ptr int + + PARAMETERS* = St_mysql_parameters + PPARAMETERS* = ptr PARAMETERS + Enum_mysql_stmt_state* = enum + STMT_INIT_DONE = 1, STMT_PREPARE_DONE, STMT_EXECUTE_DONE, STMT_FETCH_DONE + Pst_mysql_bind* = ptr St_mysql_bind + St_mysql_bind*{.final.} = object + len*: int # output length pointer + is_null*: Pmy_bool # Pointer to null indicator + buffer*: pointer # buffer to get/put data + error*: Pmy_bool # set this if you want to track data truncations happened during fetch + buffer_type*: Enum_field_types # buffer type + buffer_length*: int # buffer length, must be set for str/binary + # Following are for internal use. Set by mysql_stmt_bind_param + row_ptr*: ptr byte # for the current data position + offset*: int # offset position for char/binary fetch + length_value*: int # Used if length is 0 + param_number*: cuint # For null count and error messages + pack_length*: cuint # Internal length for packed data + error_value*: my_bool # used if error is 0 + is_unsigned*: my_bool # set if integer type is unsigned + long_data_used*: my_bool # If used with mysql_send_long_data + is_null_value*: my_bool # Used if is_null is 0 + store_param_func*: proc (net: PNET, param: Pst_mysql_bind){.cdecl.} + fetch_result*: proc (para1: Pst_mysql_bind, para2: PFIELD, row: PPByte) + skip_result*: proc (para1: Pst_mysql_bind, para2: PFIELD, row: PPByte) + + BIND* = St_mysql_bind + PBIND* = ptr BIND # statement handler + St_mysql_stmt*{.final.} = object + mem_root*: MEM_ROOT # root allocations + mysql*: PMySQL # connection handle + params*: PBIND # input parameters + `bind`*: PBIND # input parameters + fields*: PFIELD # result set metadata + result*: DATA # cached result set + data_cursor*: PROWS # current row in cached result + affected_rows*: my_ulonglong # copy of mysql->affected_rows after statement execution + insert_id*: my_ulonglong + read_row_func*: proc (stmt: Pst_mysql_stmt, row: PPByte): cint{.cdecl.} + stmt_id*: int # Id for prepared statement + flags*: int # i.e. type of cursor to open + prefetch_rows*: int # number of rows per one COM_FETCH + server_status*: cuint # Copied from mysql->server_status after execute/fetch to know + # server-side cursor status for this statement. + last_errno*: cuint # error code + param_count*: cuint # input parameter count + field_count*: cuint # number of columns in result set + state*: Enum_mysql_stmt_state # statement state + last_error*: array[0..(ERRMSG_SIZE) - 1, char] # error message + sqlstate*: array[0..(SQLSTATE_LENGTH + 1) - 1, char] + send_types_to_server*: my_bool # Types of input parameters should be sent to server + bind_param_done*: my_bool # input buffers were supplied + bind_result_done*: char # output buffers were supplied + unbuffered_fetch_cancelled*: my_bool + update_max_length*: my_bool + + STMT* = St_mysql_stmt + + Enum_stmt_attr_type* = enum + STMT_ATTR_UPDATE_MAX_LENGTH, STMT_ATTR_CURSOR_TYPE, STMT_ATTR_PREFETCH_ROWS +{.deprecated: [Tst_dynamic_array: St_dynamic_array, Tst_mysql_options: St_mysql_options, + TDYNAMIC_ARRAY: DYNAMIC_ARRAY, Tprotocol_type: Protocol_type, + Trpl_type: Rpl_type, Tcharset_info_st: Charset_info_st, + TCHARSET_INFO: CHARSET_INFO, Tcharacter_set: Character_set, + TMY_CHARSET_INFO: MY_CHARSET_INFO, Tst_mysql: St_mysql, + Tst_mysql_methods: St_mysql_methods, TMySql: MySql, + Tst_mysql_res: St_mysql_res, TMETHODS: METHODS, TRES: RES, + Tst_mysql_manager: St_mysql_manager, TMANAGER: MANAGER, + Tst_mysql_parameters: St_mysql_parameters, TPARAMETERS: PARAMETERS, + Tenum_mysql_stmt_state: Enum_mysql_stmt_state, + Tst_mysql_bind: St_mysql_bind, TBIND: BIND, Tst_mysql_stmt: St_mysql_stmt, + TSTMT: STMT, Tenum_stmt_attr_type: Enum_stmt_attr_type, + Tstatus: Status].} + +proc server_init*(argc: cint, argv: cstringArray, groups: cstringArray): cint{. + cdecl, dynlib: lib, importc: "mysql_server_init".} +proc server_end*(){.cdecl, dynlib: lib, importc: "mysql_server_end".} + # mysql_server_init/end need to be called when using libmysqld or + # libmysqlclient (exactly, mysql_server_init() is called by mysql_init() so + # you don't need to call it explicitly; but you need to call + # mysql_server_end() to free memory). The names are a bit misleading + # (mysql_SERVER* to be used when using libmysqlCLIENT). So we add more general + # names which suit well whether you're using libmysqld or libmysqlclient. We + # intend to promote these aliases over the mysql_server* ones. +proc library_init*(argc: cint, argv: cstringArray, groups: cstringArray): cint{. + cdecl, dynlib: lib, importc: "mysql_server_init".} +proc library_end*(){.cdecl, dynlib: lib, importc: "mysql_server_end".} +proc get_parameters*(): PPARAMETERS{.stdcall, dynlib: lib, + importc: "mysql_get_parameters".} + # Set up and bring down a thread; these function should be called + # for each thread in an application which opens at least one MySQL + # connection. All uses of the connection(s) should be between these + # function calls. +proc thread_init*(): my_bool{.stdcall, dynlib: lib, importc: "mysql_thread_init".} +proc thread_end*(){.stdcall, dynlib: lib, importc: "mysql_thread_end".} + # Functions to get information from the MYSQL and MYSQL_RES structures + # Should definitely be used if one uses shared libraries. +proc num_rows*(res: PRES): my_ulonglong{.stdcall, dynlib: lib, + importc: "mysql_num_rows".} +proc num_fields*(res: PRES): cuint{.stdcall, dynlib: lib, + importc: "mysql_num_fields".} +proc eof*(res: PRES): my_bool{.stdcall, dynlib: lib, importc: "mysql_eof".} +proc fetch_field_direct*(res: PRES, fieldnr: cuint): PFIELD{.stdcall, + dynlib: lib, importc: "mysql_fetch_field_direct".} +proc fetch_fields*(res: PRES): PFIELD{.stdcall, dynlib: lib, + importc: "mysql_fetch_fields".} +proc row_tell*(res: PRES): ROW_OFFSET{.stdcall, dynlib: lib, + importc: "mysql_row_tell".} +proc field_tell*(res: PRES): FIELD_OFFSET{.stdcall, dynlib: lib, + importc: "mysql_field_tell".} +proc field_count*(MySQL: PMySQL): cuint{.stdcall, dynlib: lib, + importc: "mysql_field_count".} +proc affected_rows*(MySQL: PMySQL): my_ulonglong{.stdcall, dynlib: lib, + importc: "mysql_affected_rows".} +proc insert_id*(MySQL: PMySQL): my_ulonglong{.stdcall, dynlib: lib, + importc: "mysql_insert_id".} +proc errno*(MySQL: PMySQL): cuint{.stdcall, dynlib: lib, importc: "mysql_errno".} +proc error*(MySQL: PMySQL): cstring{.stdcall, dynlib: lib, importc: "mysql_error".} +proc sqlstate*(MySQL: PMySQL): cstring{.stdcall, dynlib: lib, importc: "mysql_sqlstate".} +proc warning_count*(MySQL: PMySQL): cuint{.stdcall, dynlib: lib, + importc: "mysql_warning_count".} +proc info*(MySQL: PMySQL): cstring{.stdcall, dynlib: lib, importc: "mysql_info".} +proc thread_id*(MySQL: PMySQL): int{.stdcall, dynlib: lib, importc: "mysql_thread_id".} +proc character_set_name*(MySQL: PMySQL): cstring{.stdcall, dynlib: lib, + importc: "mysql_character_set_name".} +proc set_character_set*(MySQL: PMySQL, csname: cstring): int32{.stdcall, dynlib: lib, + importc: "mysql_set_character_set".} +proc init*(MySQL: PMySQL): PMySQL{.stdcall, dynlib: lib, importc: "mysql_init".} +proc ssl_set*(MySQL: PMySQL, key: cstring, cert: cstring, ca: cstring, capath: cstring, + cipher: cstring): my_bool{.stdcall, dynlib: lib, + importc: "mysql_ssl_set".} +proc change_user*(MySQL: PMySQL, user: cstring, passwd: cstring, db: cstring): my_bool{. + stdcall, dynlib: lib, importc: "mysql_change_user".} +proc real_connect*(MySQL: PMySQL, host: cstring, user: cstring, passwd: cstring, + db: cstring, port: cuint, unix_socket: cstring, + clientflag: int): PMySQL{.stdcall, dynlib: lib, + importc: "mysql_real_connect".} +proc select_db*(MySQL: PMySQL, db: cstring): cint{.stdcall, dynlib: lib, + importc: "mysql_select_db".} +proc query*(MySQL: PMySQL, q: cstring): cint{.stdcall, dynlib: lib, importc: "mysql_query".} +proc send_query*(MySQL: PMySQL, q: cstring, len: int): cint{.stdcall, dynlib: lib, + importc: "mysql_send_query".} +proc real_query*(MySQL: PMySQL, q: cstring, len: int): cint{.stdcall, dynlib: lib, + importc: "mysql_real_query".} +proc store_result*(MySQL: PMySQL): PRES{.stdcall, dynlib: lib, + importc: "mysql_store_result".} +proc use_result*(MySQL: PMySQL): PRES{.stdcall, dynlib: lib, importc: "mysql_use_result".} + # perform query on master +proc master_query*(MySQL: PMySQL, q: cstring, len: int): my_bool{.stdcall, dynlib: lib, + importc: "mysql_master_query".} +proc master_send_query*(MySQL: PMySQL, q: cstring, len: int): my_bool{.stdcall, + dynlib: lib, importc: "mysql_master_send_query".} + # perform query on slave +proc slave_query*(MySQL: PMySQL, q: cstring, len: int): my_bool{.stdcall, dynlib: lib, + importc: "mysql_slave_query".} +proc slave_send_query*(MySQL: PMySQL, q: cstring, len: int): my_bool{.stdcall, + dynlib: lib, importc: "mysql_slave_send_query".} +proc get_character_set_info*(MySQL: PMySQL, charset: PMY_CHARSET_INFO){.stdcall, + dynlib: lib, importc: "mysql_get_character_set_info".} + # local infile support +const + LOCAL_INFILE_ERROR_LEN* = 512 + +# procedure mysql_set_local_infile_handler(mysql:PMYSQL; local_infile_init:function (para1:Ppointer; para2:Pchar; para3:pointer):longint; local_infile_read:function (para1:pointer; para2:Pchar; para3:dword):longint; local_infile_end:procedure (_pa +# para6:pointer);cdecl;external mysqllib name 'mysql_set_local_infile_handler'; + +proc set_local_infile_default*(MySQL: PMySQL){.cdecl, dynlib: lib, + importc: "mysql_set_local_infile_default".} + # enable/disable parsing of all queries to decide if they go on master or + # slave +proc enable_rpl_parse*(MySQL: PMySQL){.stdcall, dynlib: lib, + importc: "mysql_enable_rpl_parse".} +proc disable_rpl_parse*(MySQL: PMySQL){.stdcall, dynlib: lib, + importc: "mysql_disable_rpl_parse".} + # get the value of the parse flag +proc rpl_parse_enabled*(MySQL: PMySQL): cint{.stdcall, dynlib: lib, + importc: "mysql_rpl_parse_enabled".} + # enable/disable reads from master +proc enable_reads_from_master*(MySQL: PMySQL){.stdcall, dynlib: lib, + importc: "mysql_enable_reads_from_master".} +proc disable_reads_from_master*(MySQL: PMySQL){.stdcall, dynlib: lib, importc: "mysql_disable_reads_from_master".} + # get the value of the master read flag +proc reads_from_master_enabled*(MySQL: PMySQL): my_bool{.stdcall, dynlib: lib, + importc: "mysql_reads_from_master_enabled".} +proc rpl_query_type*(q: cstring, length: cint): Rpl_type{.stdcall, dynlib: lib, + importc: "mysql_rpl_query_type".} + # discover the master and its slaves +proc rpl_probe*(MySQL: PMySQL): my_bool{.stdcall, dynlib: lib, importc: "mysql_rpl_probe".} + # set the master, close/free the old one, if it is not a pivot +proc set_master*(MySQL: PMySQL, host: cstring, port: cuint, user: cstring, passwd: cstring): cint{. + stdcall, dynlib: lib, importc: "mysql_set_master".} +proc add_slave*(MySQL: PMySQL, host: cstring, port: cuint, user: cstring, passwd: cstring): cint{. + stdcall, dynlib: lib, importc: "mysql_add_slave".} +proc shutdown*(MySQL: PMySQL, shutdown_level: Enum_shutdown_level): cint{.stdcall, + dynlib: lib, importc: "mysql_shutdown".} +proc dump_debug_info*(MySQL: PMySQL): cint{.stdcall, dynlib: lib, + importc: "mysql_dump_debug_info".} +proc refresh*(sql: PMySQL, refresh_options: cuint): cint{.stdcall, dynlib: lib, + importc: "mysql_refresh".} +proc kill*(MySQL: PMySQL, pid: int): cint{.stdcall, dynlib: lib, importc: "mysql_kill".} +proc set_server_option*(MySQL: PMySQL, option: Enum_mysql_set_option): cint{.stdcall, + dynlib: lib, importc: "mysql_set_server_option".} +proc ping*(MySQL: PMySQL): cint{.stdcall, dynlib: lib, importc: "mysql_ping".} +proc stat*(MySQL: PMySQL): cstring{.stdcall, dynlib: lib, importc: "mysql_stat".} +proc get_server_info*(MySQL: PMySQL): cstring{.stdcall, dynlib: lib, + importc: "mysql_get_server_info".} +proc get_client_info*(): cstring{.stdcall, dynlib: lib, + importc: "mysql_get_client_info".} +proc get_client_version*(): int{.stdcall, dynlib: lib, + importc: "mysql_get_client_version".} +proc get_host_info*(MySQL: PMySQL): cstring{.stdcall, dynlib: lib, + importc: "mysql_get_host_info".} +proc get_server_version*(MySQL: PMySQL): int{.stdcall, dynlib: lib, + importc: "mysql_get_server_version".} +proc get_proto_info*(MySQL: PMySQL): cuint{.stdcall, dynlib: lib, + importc: "mysql_get_proto_info".} +proc list_dbs*(MySQL: PMySQL, wild: cstring): PRES{.stdcall, dynlib: lib, + importc: "mysql_list_dbs".} +proc list_tables*(MySQL: PMySQL, wild: cstring): PRES{.stdcall, dynlib: lib, + importc: "mysql_list_tables".} +proc list_processes*(MySQL: PMySQL): PRES{.stdcall, dynlib: lib, + importc: "mysql_list_processes".} +proc options*(MySQL: PMySQL, option: Option, arg: cstring): cint{.stdcall, dynlib: lib, + importc: "mysql_options".} +proc free_result*(result: PRES){.stdcall, dynlib: lib, + importc: "mysql_free_result".} +proc data_seek*(result: PRES, offset: my_ulonglong){.stdcall, dynlib: lib, + importc: "mysql_data_seek".} +proc row_seek*(result: PRES, offset: ROW_OFFSET): ROW_OFFSET{.stdcall, + dynlib: lib, importc: "mysql_row_seek".} +proc field_seek*(result: PRES, offset: FIELD_OFFSET): FIELD_OFFSET{.stdcall, + dynlib: lib, importc: "mysql_field_seek".} +proc fetch_row*(result: PRES): ROW{.stdcall, dynlib: lib, + importc: "mysql_fetch_row".} +proc fetch_lengths*(result: PRES): ptr int{.stdcall, dynlib: lib, + importc: "mysql_fetch_lengths".} +proc fetch_field*(result: PRES): PFIELD{.stdcall, dynlib: lib, + importc: "mysql_fetch_field".} +proc list_fields*(MySQL: PMySQL, table: cstring, wild: cstring): PRES{.stdcall, + dynlib: lib, importc: "mysql_list_fields".} +proc escape_string*(fto: cstring, `from`: cstring, from_length: int): int{. + stdcall, dynlib: lib, importc: "mysql_escape_string".} +proc hex_string*(fto: cstring, `from`: cstring, from_length: int): int{.stdcall, + dynlib: lib, importc: "mysql_hex_string".} +proc real_escape_string*(MySQL: PMySQL, fto: cstring, `from`: cstring, len: int): int{. + stdcall, dynlib: lib, importc: "mysql_real_escape_string".} +proc debug*(debug: cstring){.stdcall, dynlib: lib, importc: "mysql_debug".} + # function mysql_odbc_escape_string(mysql:PMYSQL; fto:Pchar; to_length:dword; from:Pchar; from_length:dword; + # param:pointer; extend_buffer:function (para1:pointer; to:Pchar; length:Pdword):Pchar):Pchar;stdcall;external mysqllib name 'mysql_odbc_escape_string'; +proc myodbc_remove_escape*(MySQL: PMySQL, name: cstring){.stdcall, dynlib: lib, + importc: "myodbc_remove_escape".} +proc thread_safe*(): cuint{.stdcall, dynlib: lib, importc: "mysql_thread_safe".} +proc embedded*(): my_bool{.stdcall, dynlib: lib, importc: "mysql_embedded".} +proc manager_init*(con: PMANAGER): PMANAGER{.stdcall, dynlib: lib, + importc: "mysql_manager_init".} +proc manager_connect*(con: PMANAGER, host: cstring, user: cstring, + passwd: cstring, port: cuint): PMANAGER{.stdcall, + dynlib: lib, importc: "mysql_manager_connect".} +proc manager_close*(con: PMANAGER){.stdcall, dynlib: lib, + importc: "mysql_manager_close".} +proc manager_command*(con: PMANAGER, cmd: cstring, cmd_len: cint): cint{. + stdcall, dynlib: lib, importc: "mysql_manager_command".} +proc manager_fetch_line*(con: PMANAGER, res_buf: cstring, res_buf_size: cint): cint{. + stdcall, dynlib: lib, importc: "mysql_manager_fetch_line".} +proc read_query_result*(MySQL: PMySQL): my_bool{.stdcall, dynlib: lib, + importc: "mysql_read_query_result".} +proc stmt_init*(MySQL: PMySQL): PSTMT{.stdcall, dynlib: lib, importc: "mysql_stmt_init".} +proc stmt_prepare*(stmt: PSTMT, query: cstring, len: int): cint{.stdcall, + dynlib: lib, importc: "mysql_stmt_prepare".} +proc stmt_execute*(stmt: PSTMT): cint{.stdcall, dynlib: lib, + importc: "mysql_stmt_execute".} +proc stmt_fetch*(stmt: PSTMT): cint{.stdcall, dynlib: lib, + importc: "mysql_stmt_fetch".} +proc stmt_fetch_column*(stmt: PSTMT, `bind`: PBIND, column: cuint, offset: int): cint{. + stdcall, dynlib: lib, importc: "mysql_stmt_fetch_column".} +proc stmt_store_result*(stmt: PSTMT): cint{.stdcall, dynlib: lib, + importc: "mysql_stmt_store_result".} +proc stmt_param_count*(stmt: PSTMT): int{.stdcall, dynlib: lib, + importc: "mysql_stmt_param_count".} +proc stmt_attr_set*(stmt: PSTMT, attr_type: Enum_stmt_attr_type, attr: pointer): my_bool{. + stdcall, dynlib: lib, importc: "mysql_stmt_attr_set".} +proc stmt_attr_get*(stmt: PSTMT, attr_type: Enum_stmt_attr_type, attr: pointer): my_bool{. + stdcall, dynlib: lib, importc: "mysql_stmt_attr_get".} +proc stmt_bind_param*(stmt: PSTMT, bnd: PBIND): my_bool{.stdcall, dynlib: lib, + importc: "mysql_stmt_bind_param".} +proc stmt_bind_result*(stmt: PSTMT, bnd: PBIND): my_bool{.stdcall, dynlib: lib, + importc: "mysql_stmt_bind_result".} +proc stmt_close*(stmt: PSTMT): my_bool{.stdcall, dynlib: lib, + importc: "mysql_stmt_close".} +proc stmt_reset*(stmt: PSTMT): my_bool{.stdcall, dynlib: lib, + importc: "mysql_stmt_reset".} +proc stmt_free_result*(stmt: PSTMT): my_bool{.stdcall, dynlib: lib, + importc: "mysql_stmt_free_result".} +proc stmt_send_long_data*(stmt: PSTMT, param_number: cuint, data: cstring, + len: int): my_bool{.stdcall, dynlib: lib, + importc: "mysql_stmt_send_long_data".} +proc stmt_result_metadata*(stmt: PSTMT): PRES{.stdcall, dynlib: lib, + importc: "mysql_stmt_result_metadata".} +proc stmt_param_metadata*(stmt: PSTMT): PRES{.stdcall, dynlib: lib, + importc: "mysql_stmt_param_metadata".} +proc stmt_errno*(stmt: PSTMT): cuint{.stdcall, dynlib: lib, + importc: "mysql_stmt_errno".} +proc stmt_error*(stmt: PSTMT): cstring{.stdcall, dynlib: lib, + importc: "mysql_stmt_error".} +proc stmt_sqlstate*(stmt: PSTMT): cstring{.stdcall, dynlib: lib, + importc: "mysql_stmt_sqlstate".} +proc stmt_row_seek*(stmt: PSTMT, offset: ROW_OFFSET): ROW_OFFSET{.stdcall, + dynlib: lib, importc: "mysql_stmt_row_seek".} +proc stmt_row_tell*(stmt: PSTMT): ROW_OFFSET{.stdcall, dynlib: lib, + importc: "mysql_stmt_row_tell".} +proc stmt_data_seek*(stmt: PSTMT, offset: my_ulonglong){.stdcall, dynlib: lib, + importc: "mysql_stmt_data_seek".} +proc stmt_num_rows*(stmt: PSTMT): my_ulonglong{.stdcall, dynlib: lib, + importc: "mysql_stmt_num_rows".} +proc stmt_affected_rows*(stmt: PSTMT): my_ulonglong{.stdcall, dynlib: lib, + importc: "mysql_stmt_affected_rows".} +proc stmt_insert_id*(stmt: PSTMT): my_ulonglong{.stdcall, dynlib: lib, + importc: "mysql_stmt_insert_id".} +proc stmt_field_count*(stmt: PSTMT): cuint{.stdcall, dynlib: lib, + importc: "mysql_stmt_field_count".} +proc commit*(MySQL: PMySQL): my_bool{.stdcall, dynlib: lib, importc: "mysql_commit".} +proc rollback*(MySQL: PMySQL): my_bool{.stdcall, dynlib: lib, importc: "mysql_rollback".} +proc autocommit*(MySQL: PMySQL, auto_mode: my_bool): my_bool{.stdcall, dynlib: lib, + importc: "mysql_autocommit".} +proc more_results*(MySQL: PMySQL): my_bool{.stdcall, dynlib: lib, + importc: "mysql_more_results".} +proc next_result*(MySQL: PMySQL): cint{.stdcall, dynlib: lib, importc: "mysql_next_result".} +proc close*(sock: PMySQL){.stdcall, dynlib: lib, importc: "mysql_close".} + # status return codes +const + NO_DATA* = 100 + DATA_TRUNCATED* = 101 + +proc reload*(x: PMySQL): cint +when defined(USE_OLD_FUNCTIONS): + proc connect*(MySQL: PMySQL, host: cstring, user: cstring, passwd: cstring): PMySQL{.stdcall, + dynlib: lib, importc: "mysql_connect".} + proc create_db*(MySQL: PMySQL, DB: cstring): cint{.stdcall, dynlib: lib, + importc: "mysql_create_db".} + proc drop_db*(MySQL: PMySQL, DB: cstring): cint{.stdcall, dynlib: lib, + importc: "mysql_drop_db".} +proc net_safe_read*(MySQL: PMySQL): cuint{.cdecl, dynlib: lib, importc: "net_safe_read".} + +proc IS_PRI_KEY(n: int32): bool = + result = (n and PRI_KEY_FLAG) != 0 + +proc IS_NOT_NULL(n: int32): bool = + result = (n and NOT_NULL_FLAG) != 0 + +proc IS_BLOB(n: int32): bool = + result = (n and BLOB_FLAG) != 0 + +proc IS_NUM_FIELD(f: Pst_mysql_field): bool = + result = (f.flags and NUM_FLAG) != 0 + +proc IS_NUM(t: Enum_field_types): bool = + result = (t <= FIELD_TYPE_INT24) or (t == FIELD_TYPE_YEAR) or + (t == FIELD_TYPE_NEWDECIMAL) + +proc INTERNAL_NUM_FIELD(f: Pst_mysql_field): bool = + result = (f.ftype <= FIELD_TYPE_INT24) and + ((f.ftype != FIELD_TYPE_TIMESTAMP) or (f.len == 14) or (f.len == 8)) or + (f.ftype == FIELD_TYPE_YEAR) + +proc reload(x: PMySQL): cint = + result = refresh(x, REFRESH_GRANT) + +{.pop.} +when defined(nimHasStyleChecks): + {.pop.} diff --git a/lib/wrappers/odbcsql.nim b/lib/wrappers/odbcsql.nim new file mode 100644 index 000000000..14dd10ae3 --- /dev/null +++ b/lib/wrappers/odbcsql.nim @@ -0,0 +1,841 @@ +# +# +# Nim's Runtime Library +# (c) Copyright 2015 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +{.deadCodeElim: on.} # dce option deprecated + +when not defined(ODBCVER): + const + ODBCVER = 0x0351 ## define ODBC version 3.51 by default + +when defined(windows): + {.push callconv: stdcall.} + const odbclib = "odbc32.dll" +else: + {.push callconv: cdecl.} + const odbclib = "libodbc.so" + +when defined(nimHasStyleChecks): + {.push styleChecks: off.} + +# DATA TYPES CORRESPONDENCE +# BDE fields ODBC types +# ---------- ------------------ +# ftBlob SQL_BINARY +# ftBoolean SQL_BIT +# ftDate SQL_TYPE_DATE +# ftTime SQL_TYPE_TIME +# ftDateTime SQL_TYPE_TIMESTAMP +# ftInteger SQL_INTEGER +# ftSmallint SQL_SMALLINT +# ftFloat SQL_DOUBLE +# ftString SQL_CHAR +# ftMemo SQL_BINARY // SQL_VARCHAR +# + +type + TSqlChar* = char + TSqlSmallInt* = int16 + SqlUSmallInt* = int16 + SqlHandle* = pointer + SqlHEnv* = SqlHandle + SqlHDBC* = SqlHandle + SqlHStmt* = SqlHandle + SqlHDesc* = SqlHandle + TSqlInteger* = int + SqlUInteger* = int + SqlPointer* = pointer + TSqlReal* = cfloat + TSqlDouble* = cdouble + TSqlFloat* = cdouble + SqlHWND* = pointer + PSQLCHAR* = cstring + PSQLINTEGER* = ptr TSqlInteger + PSQLUINTEGER* = ptr SqlUInteger + PSQLSMALLINT* = ptr TSqlSmallInt + PSQLUSMALLINT* = ptr SqlUSmallInt + PSQLREAL* = ptr TSqlReal + PSQLDOUBLE* = ptr TSqlDouble + PSQLFLOAT* = ptr TSqlFloat + PSQLHANDLE* = ptr SqlHandle + +const # SQL data type codes + SQL_UNKNOWN_TYPE* = 0 + SQL_LONGVARCHAR* = (- 1) + SQL_BINARY* = (- 2) + SQL_VARBINARY* = (- 3) + SQL_LONGVARBINARY* = (- 4) + SQL_BIGINT* = (- 5) + SQL_TINYINT* = (- 6) + SQL_BIT* = (- 7) + SQL_WCHAR* = (- 8) + SQL_WVARCHAR* = (- 9) + SQL_WLONGVARCHAR* = (- 10) + SQL_CHAR* = 1 + SQL_NUMERIC* = 2 + SQL_DECIMAL* = 3 + SQL_INTEGER* = 4 + SQL_SMALLINT* = 5 + SQL_FLOAT* = 6 + SQL_REAL* = 7 + SQL_DOUBLE* = 8 + SQL_DATETIME* = 9 + SQL_VARCHAR* = 12 + SQL_TYPE_DATE* = 91 + SQL_TYPE_TIME* = 92 + SQL_TYPE_TIMESTAMP* = 93 + SQL_DATE* = 9 + SQL_TIME* = 10 + SQL_TIMESTAMP* = 11 + SQL_INTERVAL* = 10 + SQL_GUID* = - 11 # interval codes + +when ODBCVER >= 0x0300: + const + SQL_CODE_YEAR* = 1 + SQL_CODE_MONTH* = 2 + SQL_CODE_DAY* = 3 + SQL_CODE_HOUR* = 4 + SQL_CODE_MINUTE* = 5 + SQL_CODE_SECOND* = 6 + SQL_CODE_YEAR_TO_MONTH* = 7 + SQL_CODE_DAY_TO_HOUR* = 8 + SQL_CODE_DAY_TO_MINUTE* = 9 + SQL_CODE_DAY_TO_SECOND* = 10 + SQL_CODE_HOUR_TO_MINUTE* = 11 + SQL_CODE_HOUR_TO_SECOND* = 12 + SQL_CODE_MINUTE_TO_SECOND* = 13 + SQL_INTERVAL_YEAR* = 100 + SQL_CODE_YEAR + SQL_INTERVAL_MONTH* = 100 + SQL_CODE_MONTH + SQL_INTERVAL_DAY* = 100 + SQL_CODE_DAY + SQL_INTERVAL_HOUR* = 100 + SQL_CODE_HOUR + SQL_INTERVAL_MINUTE* = 100 + SQL_CODE_MINUTE + SQL_INTERVAL_SECOND* = 100 + SQL_CODE_SECOND + SQL_INTERVAL_YEAR_TO_MONTH* = 100 + SQL_CODE_YEAR_TO_MONTH + SQL_INTERVAL_DAY_TO_HOUR* = 100 + SQL_CODE_DAY_TO_HOUR + SQL_INTERVAL_DAY_TO_MINUTE* = 100 + SQL_CODE_DAY_TO_MINUTE + SQL_INTERVAL_DAY_TO_SECOND* = 100 + SQL_CODE_DAY_TO_SECOND + SQL_INTERVAL_HOUR_TO_MINUTE* = 100 + SQL_CODE_HOUR_TO_MINUTE + SQL_INTERVAL_HOUR_TO_SECOND* = 100 + SQL_CODE_HOUR_TO_SECOND + SQL_INTERVAL_MINUTE_TO_SECOND* = 100 + SQL_CODE_MINUTE_TO_SECOND +else: + const + SQL_INTERVAL_YEAR* = - 80 + SQL_INTERVAL_MONTH* = - 81 + SQL_INTERVAL_YEAR_TO_MONTH* = - 82 + SQL_INTERVAL_DAY* = - 83 + SQL_INTERVAL_HOUR* = - 84 + SQL_INTERVAL_MINUTE* = - 85 + SQL_INTERVAL_SECOND* = - 86 + SQL_INTERVAL_DAY_TO_HOUR* = - 87 + SQL_INTERVAL_DAY_TO_MINUTE* = - 88 + SQL_INTERVAL_DAY_TO_SECOND* = - 89 + SQL_INTERVAL_HOUR_TO_MINUTE* = - 90 + SQL_INTERVAL_HOUR_TO_SECOND* = - 91 + SQL_INTERVAL_MINUTE_TO_SECOND* = - 92 + + +when ODBCVER < 0x0300: + const + SQL_UNICODE* = - 95 + SQL_UNICODE_VARCHAR* = - 96 + SQL_UNICODE_LONGVARCHAR* = - 97 + SQL_UNICODE_CHAR* = SQL_UNICODE +else: + # The previous definitions for SQL_UNICODE_ are historical and obsolete + const + SQL_UNICODE* = SQL_WCHAR + SQL_UNICODE_VARCHAR* = SQL_WVARCHAR + SQL_UNICODE_LONGVARCHAR* = SQL_WLONGVARCHAR + SQL_UNICODE_CHAR* = SQL_WCHAR +const # C datatype to SQL datatype mapping + SQL_C_CHAR* = SQL_CHAR + SQL_C_LONG* = SQL_INTEGER + SQL_C_SHORT* = SQL_SMALLINT + SQL_C_FLOAT* = SQL_REAL + SQL_C_DOUBLE* = SQL_DOUBLE + SQL_C_NUMERIC* = SQL_NUMERIC + SQL_C_DEFAULT* = 99 + SQL_SIGNED_OFFSET* = - 20 + SQL_UNSIGNED_OFFSET* = - 22 + SQL_C_DATE* = SQL_DATE + SQL_C_TIME* = SQL_TIME + SQL_C_TIMESTAMP* = SQL_TIMESTAMP + SQL_C_TYPE_DATE* = SQL_TYPE_DATE + SQL_C_TYPE_TIME* = SQL_TYPE_TIME + SQL_C_TYPE_TIMESTAMP* = SQL_TYPE_TIMESTAMP + SQL_C_INTERVAL_YEAR* = SQL_INTERVAL_YEAR + SQL_C_INTERVAL_MONTH* = SQL_INTERVAL_MONTH + SQL_C_INTERVAL_DAY* = SQL_INTERVAL_DAY + SQL_C_INTERVAL_HOUR* = SQL_INTERVAL_HOUR + SQL_C_INTERVAL_MINUTE* = SQL_INTERVAL_MINUTE + SQL_C_INTERVAL_SECOND* = SQL_INTERVAL_SECOND + SQL_C_INTERVAL_YEAR_TO_MONTH* = SQL_INTERVAL_YEAR_TO_MONTH + SQL_C_INTERVAL_DAY_TO_HOUR* = SQL_INTERVAL_DAY_TO_HOUR + SQL_C_INTERVAL_DAY_TO_MINUTE* = SQL_INTERVAL_DAY_TO_MINUTE + SQL_C_INTERVAL_DAY_TO_SECOND* = SQL_INTERVAL_DAY_TO_SECOND + SQL_C_INTERVAL_HOUR_TO_MINUTE* = SQL_INTERVAL_HOUR_TO_MINUTE + SQL_C_INTERVAL_HOUR_TO_SECOND* = SQL_INTERVAL_HOUR_TO_SECOND + SQL_C_INTERVAL_MINUTE_TO_SECOND* = SQL_INTERVAL_MINUTE_TO_SECOND + SQL_C_BINARY* = SQL_BINARY + SQL_C_BIT* = SQL_BIT + SQL_C_SBIGINT* = SQL_BIGINT + SQL_SIGNED_OFFSET # SIGNED BIGINT + SQL_C_UBIGINT* = SQL_BIGINT + SQL_UNSIGNED_OFFSET # UNSIGNED BIGINT + SQL_C_TINYINT* = SQL_TINYINT + SQL_C_SLONG* = SQL_C_LONG + SQL_SIGNED_OFFSET # SIGNED INTEGER + SQL_C_SSHORT* = SQL_C_SHORT + SQL_SIGNED_OFFSET # SIGNED SMALLINT + SQL_C_STINYINT* = SQL_TINYINT + SQL_SIGNED_OFFSET # SIGNED TINYINT + SQL_C_ULONG* = SQL_C_LONG + SQL_UNSIGNED_OFFSET # UNSIGNED INTEGER + SQL_C_USHORT* = SQL_C_SHORT + SQL_UNSIGNED_OFFSET # UNSIGNED SMALLINT + SQL_C_UTINYINT* = SQL_TINYINT + SQL_UNSIGNED_OFFSET # UNSIGNED TINYINT + SQL_C_BOOKMARK* = SQL_C_ULONG # BOOKMARK + SQL_C_GUID* = SQL_GUID + SQL_TYPE_NULL* = 0 + +when ODBCVER < 0x0300: + const + SQL_TYPE_MIN* = SQL_BIT + SQL_TYPE_MAX* = SQL_VARCHAR + +const + SQL_C_VARBOOKMARK* = SQL_C_BINARY + SQL_API_SQLDESCRIBEPARAM* = 58 + SQL_NO_TOTAL* = - 4 + +type + SQL_DATE_STRUCT* {.final, pure.} = object + Year*: TSqlSmallInt + Month*: SqlUSmallInt + Day*: SqlUSmallInt + + PSQL_DATE_STRUCT* = ptr SQL_DATE_STRUCT + SQL_TIME_STRUCT* {.final, pure.} = object + Hour*: SqlUSmallInt + Minute*: SqlUSmallInt + Second*: SqlUSmallInt + + PSQL_TIME_STRUCT* = ptr SQL_TIME_STRUCT + SQL_TIMESTAMP_STRUCT* {.final, pure.} = object + Year*: SqlUSmallInt + Month*: SqlUSmallInt + Day*: SqlUSmallInt + Hour*: SqlUSmallInt + Minute*: SqlUSmallInt + Second*: SqlUSmallInt + Fraction*: SqlUInteger + + PSQL_TIMESTAMP_STRUCT* = ptr SQL_TIMESTAMP_STRUCT + +const + SQL_NAME_LEN* = 128 + SQL_OV_ODBC3* = 3 + SQL_OV_ODBC2* = 2 + SQL_ATTR_ODBC_VERSION* = 200 # Options for SQLDriverConnect + SQL_DRIVER_NOPROMPT* = 0 + SQL_DRIVER_COMPLETE* = 1 + SQL_DRIVER_PROMPT* = 2 + SQL_DRIVER_COMPLETE_REQUIRED* = 3 + SQL_IS_POINTER* = (- 4) # whether an attribute is a pointer or not + SQL_IS_UINTEGER* = (- 5) + SQL_IS_INTEGER* = (- 6) + SQL_IS_USMALLINT* = (- 7) + SQL_IS_SMALLINT* = (- 8) # SQLExtendedFetch "fFetchType" values + SQL_FETCH_BOOKMARK* = 8 + SQL_SCROLL_OPTIONS* = 44 # SQL_USE_BOOKMARKS options + SQL_UB_OFF* = 0 + SQL_UB_ON* = 1 + SQL_UB_DEFAULT* = SQL_UB_OFF + SQL_UB_FIXED* = SQL_UB_ON + SQL_UB_VARIABLE* = 2 # SQL_SCROLL_OPTIONS masks + SQL_SO_FORWARD_ONLY* = 0x00000001 + SQL_SO_KEYSET_DRIVEN* = 0x00000002 + SQL_SO_DYNAMIC* = 0x00000004 + SQL_SO_MIXED* = 0x00000008 + SQL_SO_STATIC* = 0x00000010 + SQL_BOOKMARK_PERSISTENCE* = 82 + SQL_STATIC_SENSITIVITY* = 83 # SQL_BOOKMARK_PERSISTENCE values + SQL_BP_CLOSE* = 0x00000001 + SQL_BP_DELETE* = 0x00000002 + SQL_BP_DROP* = 0x00000004 + SQL_BP_TRANSACTION* = 0x00000008 + SQL_BP_UPDATE* = 0x00000010 + SQL_BP_OTHER_HSTMT* = 0x00000020 + SQL_BP_SCROLL* = 0x00000040 + SQL_DYNAMIC_CURSOR_ATTRIBUTES1* = 144 + SQL_DYNAMIC_CURSOR_ATTRIBUTES2* = 145 + SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES1* = 146 + SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES2* = 147 + SQL_INDEX_KEYWORDS* = 148 + SQL_INFO_SCHEMA_VIEWS* = 149 + SQL_KEYSET_CURSOR_ATTRIBUTES1* = 150 + SQL_KEYSET_CURSOR_ATTRIBUTES2* = 151 + SQL_STATIC_CURSOR_ATTRIBUTES1* = 167 + SQL_STATIC_CURSOR_ATTRIBUTES2* = 168 # supported SQLFetchScroll FetchOrientation's + SQL_CA1_NEXT* = 1 + SQL_CA1_ABSOLUTE* = 2 + SQL_CA1_RELATIVE* = 4 + SQL_CA1_BOOKMARK* = 8 # supported SQLSetPos LockType's + SQL_CA1_LOCK_NO_CHANGE* = 0x00000040 + SQL_CA1_LOCK_EXCLUSIVE* = 0x00000080 + SQL_CA1_LOCK_UNLOCK* = 0x00000100 # supported SQLSetPos Operations + SQL_CA1_POS_POSITION* = 0x00000200 + SQL_CA1_POS_UPDATE* = 0x00000400 + SQL_CA1_POS_DELETE* = 0x00000800 + SQL_CA1_POS_REFRESH* = 0x00001000 # positioned updates and deletes + SQL_CA1_POSITIONED_UPDATE* = 0x00002000 + SQL_CA1_POSITIONED_DELETE* = 0x00004000 + SQL_CA1_SELECT_FOR_UPDATE* = 0x00008000 # supported SQLBulkOperations operations + SQL_CA1_BULK_ADD* = 0x00010000 + SQL_CA1_BULK_UPDATE_BY_BOOKMARK* = 0x00020000 + SQL_CA1_BULK_DELETE_BY_BOOKMARK* = 0x00040000 + SQL_CA1_BULK_FETCH_BY_BOOKMARK* = 0x00080000 # supported values for SQL_ATTR_SCROLL_CONCURRENCY + SQL_CA2_READ_ONLY_CONCURRENCY* = 1 + SQL_CA2_LOCK_CONCURRENCY* = 2 + SQL_CA2_OPT_ROWVER_CONCURRENCY* = 4 + SQL_CA2_OPT_VALUES_CONCURRENCY* = 8 # sensitivity of the cursor to its own inserts, deletes, and updates + SQL_CA2_SENSITIVITY_ADDITIONS* = 0x00000010 + SQL_CA2_SENSITIVITY_DELETIONS* = 0x00000020 + SQL_CA2_SENSITIVITY_UPDATES* = 0x00000040 # semantics of SQL_ATTR_MAX_ROWS + SQL_CA2_MAX_ROWS_SELECT* = 0x00000080 + SQL_CA2_MAX_ROWS_INSERT* = 0x00000100 + SQL_CA2_MAX_ROWS_DELETE* = 0x00000200 + SQL_CA2_MAX_ROWS_UPDATE* = 0x00000400 + SQL_CA2_MAX_ROWS_CATALOG* = 0x00000800 + SQL_CA2_MAX_ROWS_AFFECTS_ALL* = (SQL_CA2_MAX_ROWS_SELECT or + SQL_CA2_MAX_ROWS_INSERT or SQL_CA2_MAX_ROWS_DELETE or + SQL_CA2_MAX_ROWS_UPDATE or SQL_CA2_MAX_ROWS_CATALOG) # semantics of + # SQL_DIAG_CURSOR_ROW_COUNT + SQL_CA2_CRC_EXACT* = 0x00001000 + SQL_CA2_CRC_APPROXIMATE* = 0x00002000 # the kinds of positioned statements that can be simulated + SQL_CA2_SIMULATE_NON_UNIQUE* = 0x00004000 + SQL_CA2_SIMULATE_TRY_UNIQUE* = 0x00008000 + SQL_CA2_SIMULATE_UNIQUE* = 0x00010000 # Operations in SQLBulkOperations + SQL_ADD* = 4 + SQL_SETPOS_MAX_OPTION_VALUE* = SQL_ADD + SQL_UPDATE_BY_BOOKMARK* = 5 + SQL_DELETE_BY_BOOKMARK* = 6 + SQL_FETCH_BY_BOOKMARK* = 7 # Operations in SQLSetPos + SQL_POSITION* = 0 + SQL_REFRESH* = 1 + SQL_UPDATE* = 2 + SQL_DELETE* = 3 # Lock options in SQLSetPos + SQL_LOCK_NO_CHANGE* = 0 + SQL_LOCK_EXCLUSIVE* = 1 + SQL_LOCK_UNLOCK* = 2 # SQLExtendedFetch "rgfRowStatus" element values + SQL_ROW_SUCCESS* = 0 + SQL_ROW_DELETED* = 1 + SQL_ROW_UPDATED* = 2 + SQL_ROW_NOROW* = 3 + SQL_ROW_ADDED* = 4 + SQL_ROW_ERROR* = 5 + SQL_ROW_SUCCESS_WITH_INFO* = 6 + SQL_ROW_PROCEED* = 0 + SQL_ROW_IGNORE* = 1 + SQL_MAX_DSN_LENGTH* = 32 # maximum data source name size + SQL_MAX_OPTION_STRING_LENGTH* = 256 + SQL_ODBC_CURSORS* = 110 + SQL_ATTR_ODBC_CURSORS* = SQL_ODBC_CURSORS # SQL_ODBC_CURSORS options + SQL_CUR_USE_IF_NEEDED* = 0 + SQL_CUR_USE_ODBC* = 1 + SQL_CUR_USE_DRIVER* = 2 + SQL_CUR_DEFAULT* = SQL_CUR_USE_DRIVER + SQL_PARAM_TYPE_UNKNOWN* = 0 + SQL_PARAM_INPUT* = 1 + SQL_PARAM_INPUT_OUTPUT* = 2 + SQL_RESULT_COL* = 3 + SQL_PARAM_OUTPUT* = 4 + SQL_RETURN_VALUE* = 5 # special length/indicator values + SQL_NULL_DATA* = (- 1) + SQL_DATA_AT_EXEC* = (- 2) + SQL_SUCCESS* = 0 + SQL_SUCCESS_WITH_INFO* = 1 + SQL_NO_DATA* = 100 + SQL_ERROR* = (- 1) + SQL_INVALID_HANDLE* = (- 2) + SQL_STILL_EXECUTING* = 2 + SQL_NEED_DATA* = 99 # flags for null-terminated string + SQL_NTS* = (- 3) # maximum message length + SQL_MAX_MESSAGE_LENGTH* = 512 # date/time length constants + SQL_DATE_LEN* = 10 + SQL_TIME_LEN* = 8 # add P+1 if precision is nonzero + SQL_TIMESTAMP_LEN* = 19 # add P+1 if precision is nonzero + # handle type identifiers + SQL_HANDLE_ENV* = 1 + SQL_HANDLE_DBC* = 2 + SQL_HANDLE_STMT* = 3 + SQL_HANDLE_DESC* = 4 # environment attribute + SQL_ATTR_OUTPUT_NTS* = 10001 # connection attributes + SQL_ATTR_AUTO_IPD* = 10001 + SQL_ATTR_METADATA_ID* = 10014 # statement attributes + SQL_ATTR_APP_ROW_DESC* = 10010 + SQL_ATTR_APP_PARAM_DESC* = 10011 + SQL_ATTR_IMP_ROW_DESC* = 10012 + SQL_ATTR_IMP_PARAM_DESC* = 10013 + SQL_ATTR_CURSOR_SCROLLABLE* = (- 1) + SQL_ATTR_CURSOR_SENSITIVITY* = (- 2) + SQL_QUERY_TIMEOUT* = 0 + SQL_MAX_ROWS* = 1 + SQL_NOSCAN* = 2 + SQL_MAX_LENGTH* = 3 + SQL_ASYNC_ENABLE* = 4 # same as SQL_ATTR_ASYNC_ENABLE */ + SQL_BIND_TYPE* = 5 + SQL_CURSOR_TYPE* = 6 + SQL_CONCURRENCY* = 7 + SQL_KEYSET_SIZE* = 8 + SQL_ROWSET_SIZE* = 9 + SQL_SIMULATE_CURSOR* = 10 + SQL_RETRIEVE_DATA* = 11 + SQL_USE_BOOKMARKS* = 12 + SQL_GET_BOOKMARK* = 13 # GetStmtOption Only */ + SQL_ROW_NUMBER* = 14 # GetStmtOption Only */ + SQL_ATTR_CURSOR_TYPE* = SQL_CURSOR_TYPE + SQL_ATTR_CONCURRENCY* = SQL_CONCURRENCY + SQL_ATTR_FETCH_BOOKMARK_PTR* = 16 + SQL_ATTR_ROW_STATUS_PTR* = 25 + SQL_ATTR_ROWS_FETCHED_PTR* = 26 + SQL_AUTOCOMMIT* = 102 + SQL_ATTR_AUTOCOMMIT* = SQL_AUTOCOMMIT + SQL_ATTR_ROW_NUMBER* = SQL_ROW_NUMBER + SQL_TXN_ISOLATION* = 108 + SQL_ATTR_TXN_ISOLATION* = SQL_TXN_ISOLATION + SQL_ATTR_MAX_ROWS* = SQL_MAX_ROWS + SQL_ATTR_USE_BOOKMARKS* = SQL_USE_BOOKMARKS #* connection attributes */ + SQL_ACCESS_MODE* = 101 # SQL_AUTOCOMMIT =102; + SQL_LOGIN_TIMEOUT* = 103 + SQL_OPT_TRACE* = 104 + SQL_OPT_TRACEFILE* = 105 + SQL_TRANSLATE_DLL* = 106 + SQL_TRANSLATE_OPTION* = 107 # SQL_TXN_ISOLATION =108; + SQL_CURRENT_QUALIFIER* = 109 # SQL_ODBC_CURSORS =110; + SQL_QUIET_MODE* = 111 + SQL_PACKET_SIZE* = 112 #* connection attributes with new names */ + SQL_ATTR_ACCESS_MODE* = SQL_ACCESS_MODE # SQL_ATTR_AUTOCOMMIT =SQL_AUTOCOMMIT; + SQL_ATTR_CONNECTION_DEAD* = 1209 #* GetConnectAttr only */ + SQL_ATTR_CONNECTION_TIMEOUT* = 113 + SQL_ATTR_CURRENT_CATALOG* = SQL_CURRENT_QUALIFIER + SQL_ATTR_DISCONNECT_BEHAVIOR* = 114 + SQL_ATTR_ENLIST_IN_DTC* = 1207 + SQL_ATTR_ENLIST_IN_XA* = 1208 + SQL_ATTR_LOGIN_TIMEOUT* = SQL_LOGIN_TIMEOUT # SQL_ATTR_ODBC_CURSORS =SQL_ODBC_CURSORS; + SQL_ATTR_PACKET_SIZE* = SQL_PACKET_SIZE + SQL_ATTR_QUIET_MODE* = SQL_QUIET_MODE + SQL_ATTR_TRACE* = SQL_OPT_TRACE + SQL_ATTR_TRACEFILE* = SQL_OPT_TRACEFILE + SQL_ATTR_TRANSLATE_LIB* = SQL_TRANSLATE_DLL + SQL_ATTR_TRANSLATE_OPTION* = SQL_TRANSLATE_OPTION # SQL_ATTR_TXN_ISOLATION =SQL_TXN_ISOLATION; + #* SQL_ACCESS_MODE options */ + SQL_MODE_READ_WRITE* = 0 + SQL_MODE_READ_ONLY* = 1 + SQL_MODE_DEFAULT* = SQL_MODE_READ_WRITE #* SQL_AUTOCOMMIT options */ + SQL_AUTOCOMMIT_OFF* = 0 + SQL_AUTOCOMMIT_ON* = 1 + SQL_AUTOCOMMIT_DEFAULT* = SQL_AUTOCOMMIT_ON # SQL_ATTR_CURSOR_SCROLLABLE values + SQL_NONSCROLLABLE* = 0 + SQL_SCROLLABLE* = 1 # SQL_CURSOR_TYPE options + SQL_CURSOR_FORWARD_ONLY* = 0 + SQL_CURSOR_KEYSET_DRIVEN* = 1 + SQL_CURSOR_DYNAMIC* = 2 + SQL_CURSOR_STATIC* = 3 + SQL_CURSOR_TYPE_DEFAULT* = SQL_CURSOR_FORWARD_ONLY # Default value + # SQL_CONCURRENCY options + SQL_CONCUR_READ_ONLY* = 1 + SQL_CONCUR_LOCK* = 2 + SQL_CONCUR_ROWVER* = 3 + SQL_CONCUR_VALUES* = 4 + SQL_CONCUR_DEFAULT* = SQL_CONCUR_READ_ONLY # Default value + # identifiers of fields in the SQL descriptor + SQL_DESC_COUNT* = 1001 + SQL_DESC_TYPE* = 1002 + SQL_DESC_LENGTH* = 1003 + SQL_DESC_OCTET_LENGTH_PTR* = 1004 + SQL_DESC_PRECISION* = 1005 + SQL_DESC_SCALE* = 1006 + SQL_DESC_DATETIME_INTERVAL_CODE* = 1007 + SQL_DESC_NULLABLE* = 1008 + SQL_DESC_INDICATOR_PTR* = 1009 + SQL_DESC_DATA_PTR* = 1010 + SQL_DESC_NAME* = 1011 + SQL_DESC_UNNAMED* = 1012 + SQL_DESC_OCTET_LENGTH* = 1013 + SQL_DESC_ALLOC_TYPE* = 1099 # identifiers of fields in the diagnostics area + SQL_DIAG_RETURNCODE* = 1 + SQL_DIAG_NUMBER* = 2 + SQL_DIAG_ROW_COUNT* = 3 + SQL_DIAG_SQLSTATE* = 4 + SQL_DIAG_NATIVE* = 5 + SQL_DIAG_MESSAGE_TEXT* = 6 + SQL_DIAG_DYNAMIC_FUNCTION* = 7 + SQL_DIAG_CLASS_ORIGIN* = 8 + SQL_DIAG_SUBCLASS_ORIGIN* = 9 + SQL_DIAG_CONNECTION_NAME* = 10 + SQL_DIAG_SERVER_NAME* = 11 + SQL_DIAG_DYNAMIC_FUNCTION_CODE* = 12 # dynamic function codes + SQL_DIAG_ALTER_TABLE* = 4 + SQL_DIAG_CREATE_INDEX* = (- 1) + SQL_DIAG_CREATE_TABLE* = 77 + SQL_DIAG_CREATE_VIEW* = 84 + SQL_DIAG_DELETE_WHERE* = 19 + SQL_DIAG_DROP_INDEX* = (- 2) + SQL_DIAG_DROP_TABLE* = 32 + SQL_DIAG_DROP_VIEW* = 36 + SQL_DIAG_DYNAMIC_DELETE_CURSOR* = 38 + SQL_DIAG_DYNAMIC_UPDATE_CURSOR* = 81 + SQL_DIAG_GRANT* = 48 + SQL_DIAG_INSERT* = 50 + SQL_DIAG_REVOKE* = 59 + SQL_DIAG_SELECT_CURSOR* = 85 + SQL_DIAG_UNKNOWN_STATEMENT* = 0 + SQL_DIAG_UPDATE_WHERE* = 82 # Statement attribute values for cursor sensitivity + SQL_UNSPECIFIED* = 0 + SQL_INSENSITIVE* = 1 + SQL_SENSITIVE* = 2 # GetTypeInfo() request for all data types + SQL_ALL_TYPES* = 0 # Default conversion code for SQLBindCol(), SQLBindParam() and SQLGetData() + SQL_DEFAULT* = 99 # SQLGetData() code indicating that the application row descriptor + # specifies the data type + SQL_ARD_TYPE* = (- 99) # SQL date/time type subcodes + SQL_CODE_DATE* = 1 + SQL_CODE_TIME* = 2 + SQL_CODE_TIMESTAMP* = 3 # CLI option values + SQL_FALSE* = 0 + SQL_TRUE* = 1 # values of NULLABLE field in descriptor + SQL_NO_NULLS* = 0 + SQL_NULLABLE* = 1 # Value returned by SQLGetTypeInfo() to denote that it is + # not known whether or not a data type supports null values. + SQL_NULLABLE_UNKNOWN* = 2 + SQL_CLOSE* = 0 + SQL_DROP* = 1 + SQL_UNBIND* = 2 + SQL_RESET_PARAMS* = 3 # Codes used for FetchOrientation in SQLFetchScroll(), + # and in SQLDataSources() + SQL_FETCH_NEXT* = 1 + SQL_FETCH_FIRST* = 2 + SQL_FETCH_FIRST_USER* = 31 + SQL_FETCH_FIRST_SYSTEM* = 32 # Other codes used for FetchOrientation in SQLFetchScroll() + SQL_FETCH_LAST* = 3 + SQL_FETCH_PRIOR* = 4 + SQL_FETCH_ABSOLUTE* = 5 + SQL_FETCH_RELATIVE* = 6 + SQL_NULL_HENV* = SqlHEnv(nil) + SQL_NULL_HDBC* = SqlHDBC(nil) + SQL_NULL_HSTMT* = SqlHStmt(nil) + SQL_NULL_HDESC* = SqlHDesc(nil) #* null handle used in place of parent handle when allocating HENV */ + SQL_NULL_HANDLE* = SqlHandle(nil) #* Values that may appear in the result set of SQLSpecialColumns() */ + SQL_SCOPE_CURROW* = 0 + SQL_SCOPE_TRANSACTION* = 1 + SQL_SCOPE_SESSION* = 2 #* Column types and scopes in SQLSpecialColumns. */ + SQL_BEST_ROWID* = 1 + SQL_ROWVER* = 2 + SQL_ROW_IDENTIFIER* = 1 #* Reserved values for UNIQUE argument of SQLStatistics() */ + SQL_INDEX_UNIQUE* = 0 + SQL_INDEX_ALL* = 1 #* Reserved values for RESERVED argument of SQLStatistics() */ + SQL_QUICK* = 0 + SQL_ENSURE* = 1 #* Values that may appear in the result set of SQLStatistics() */ + SQL_TABLE_STAT* = 0 + SQL_INDEX_CLUSTERED* = 1 + SQL_INDEX_HASHED* = 2 + SQL_INDEX_OTHER* = 3 + SQL_SCROLL_CONCURRENCY* = 43 + SQL_TXN_CAPABLE* = 46 + SQL_TRANSACTION_CAPABLE* = SQL_TXN_CAPABLE + SQL_USER_NAME* = 47 + SQL_TXN_ISOLATION_OPTION* = 72 + SQL_TRANSACTION_ISOLATION_OPTION* = SQL_TXN_ISOLATION_OPTION + SQL_OJ_CAPABILITIES* = 115 + SQL_OUTER_JOIN_CAPABILITIES* = SQL_OJ_CAPABILITIES + SQL_XOPEN_CLI_YEAR* = 10000 + SQL_CURSOR_SENSITIVITY* = 10001 + SQL_DESCRIBE_PARAMETER* = 10002 + SQL_CATALOG_NAME* = 10003 + SQL_COLLATION_SEQ* = 10004 + SQL_MAX_IDENTIFIER_LEN* = 10005 + SQL_MAXIMUM_IDENTIFIER_LENGTH* = SQL_MAX_IDENTIFIER_LEN + SQL_SCCO_READ_ONLY* = 1 + SQL_SCCO_LOCK* = 2 + SQL_SCCO_OPT_ROWVER* = 4 + SQL_SCCO_OPT_VALUES* = 8 #* SQL_TXN_CAPABLE values */ + SQL_TC_NONE* = 0 + SQL_TC_DML* = 1 + SQL_TC_ALL* = 2 + SQL_TC_DDL_COMMIT* = 3 + SQL_TC_DDL_IGNORE* = 4 #* SQL_TXN_ISOLATION_OPTION bitmasks */ + SQL_TXN_READ_UNCOMMITTED* = 1 + SQL_TRANSACTION_READ_UNCOMMITTED* = SQL_TXN_READ_UNCOMMITTED + SQL_TXN_READ_COMMITTED* = 2 + SQL_TRANSACTION_READ_COMMITTED* = SQL_TXN_READ_COMMITTED + SQL_TXN_REPEATABLE_READ* = 4 + SQL_TRANSACTION_REPEATABLE_READ* = SQL_TXN_REPEATABLE_READ + SQL_TXN_SERIALIZABLE* = 8 + SQL_TRANSACTION_SERIALIZABLE* = SQL_TXN_SERIALIZABLE + SQL_SS_ADDITIONS* = 1 + SQL_SS_DELETIONS* = 2 + SQL_SS_UPDATES* = 4 # SQLColAttributes defines + SQL_COLUMN_COUNT* = 0 + SQL_COLUMN_NAME* = 1 + SQL_COLUMN_TYPE* = 2 + SQL_COLUMN_LENGTH* = 3 + SQL_COLUMN_PRECISION* = 4 + SQL_COLUMN_SCALE* = 5 + SQL_COLUMN_DISPLAY_SIZE* = 6 + SQL_COLUMN_NULLABLE* = 7 + SQL_COLUMN_UNSIGNED* = 8 + SQL_COLUMN_MONEY* = 9 + SQL_COLUMN_UPDATABLE* = 10 + SQL_COLUMN_AUTO_INCREMENT* = 11 + SQL_COLUMN_CASE_SENSITIVE* = 12 + SQL_COLUMN_SEARCHABLE* = 13 + SQL_COLUMN_TYPE_NAME* = 14 + SQL_COLUMN_TABLE_NAME* = 15 + SQL_COLUMN_OWNER_NAME* = 16 + SQL_COLUMN_QUALIFIER_NAME* = 17 + SQL_COLUMN_LABEL* = 18 + SQL_COLATT_OPT_MAX* = SQL_COLUMN_LABEL + SQL_COLUMN_DRIVER_START* = 1000 + SQL_DESC_ARRAY_SIZE* = 20 + SQL_DESC_ARRAY_STATUS_PTR* = 21 + SQL_DESC_AUTO_UNIQUE_VALUE* = SQL_COLUMN_AUTO_INCREMENT + SQL_DESC_BASE_COLUMN_NAME* = 22 + SQL_DESC_BASE_TABLE_NAME* = 23 + SQL_DESC_BIND_OFFSET_PTR* = 24 + SQL_DESC_BIND_TYPE* = 25 + SQL_DESC_CASE_SENSITIVE* = SQL_COLUMN_CASE_SENSITIVE + SQL_DESC_CATALOG_NAME* = SQL_COLUMN_QUALIFIER_NAME + SQL_DESC_CONCISE_TYPE* = SQL_COLUMN_TYPE + SQL_DESC_DATETIME_INTERVAL_PRECISION* = 26 + SQL_DESC_DISPLAY_SIZE* = SQL_COLUMN_DISPLAY_SIZE + SQL_DESC_FIXED_PREC_SCALE* = SQL_COLUMN_MONEY + SQL_DESC_LABEL* = SQL_COLUMN_LABEL + SQL_DESC_LITERAL_PREFIX* = 27 + SQL_DESC_LITERAL_SUFFIX* = 28 + SQL_DESC_LOCAL_TYPE_NAME* = 29 + SQL_DESC_MAXIMUM_SCALE* = 30 + SQL_DESC_MINIMUM_SCALE* = 31 + SQL_DESC_NUM_PREC_RADIX* = 32 + SQL_DESC_PARAMETER_TYPE* = 33 + SQL_DESC_ROWS_PROCESSED_PTR* = 34 + SQL_DESC_SCHEMA_NAME* = SQL_COLUMN_OWNER_NAME + SQL_DESC_SEARCHABLE* = SQL_COLUMN_SEARCHABLE + SQL_DESC_TYPE_NAME* = SQL_COLUMN_TYPE_NAME + SQL_DESC_TABLE_NAME* = SQL_COLUMN_TABLE_NAME + SQL_DESC_UNSIGNED* = SQL_COLUMN_UNSIGNED + SQL_DESC_UPDATABLE* = SQL_COLUMN_UPDATABLE #* SQLEndTran() options */ + SQL_COMMIT* = 0 + SQL_ROLLBACK* = 1 + SQL_ATTR_ROW_ARRAY_SIZE* = 27 #* SQLConfigDataSource() options */ + ODBC_ADD_DSN* = 1 + ODBC_CONFIG_DSN* = 2 + ODBC_REMOVE_DSN* = 3 + ODBC_ADD_SYS_DSN* = 4 + ODBC_CONFIG_SYS_DSN* = 5 + ODBC_REMOVE_SYS_DSN* = 6 + + SQL_ACTIVE_CONNECTIONS* = 0 # SQLGetInfo + SQL_DATA_SOURCE_NAME* = 2 + SQL_DATA_SOURCE_READ_ONLY* = 25 + SQL_DATABASE_NAME* = 2 + SQL_DBMS_NAME* = 17 + SQL_DBMS_VERSION* = 18 + SQL_DRIVER_HDBC* = 3 + SQL_DRIVER_HENV* = 4 + SQL_DRIVER_HSTMT* = 5 + SQL_DRIVER_NAME* = 6 + SQL_DRIVER_VER* = 7 + SQL_FETCH_DIRECTION* = 8 + SQL_ODBC_VER* = 10 + SQL_DRIVER_ODBC_VER* = 77 + SQL_SERVER_NAME* = 13 + SQL_ACTIVE_ENVIRONMENTS* = 116 + SQL_ACTIVE_STATEMENTS* = 1 + SQL_SQL_CONFORMANCE* = 118 + SQL_DATETIME_LITERALS* = 119 + SQL_ASYNC_MODE* = 10021 + SQL_BATCH_ROW_COUNT* = 120 + SQL_BATCH_SUPPORT* = 121 + SQL_CATALOG_LOCATION* = 114 + #SQL_CATALOG_NAME* = 10003 + SQL_CATALOG_NAME_SEPARATOR* = 41 + SQL_CATALOG_TERM* = 42 + SQL_CATALOG_USAGE* = 92 + #SQL_COLLATION_SEQ* = 10004 + SQL_COLUMN_ALIAS* = 87 + #SQL_USER_NAME* = 47 + +proc SQLAllocHandle*(HandleType: TSqlSmallInt, InputHandle: SqlHandle, + OutputHandlePtr: var SqlHandle): TSqlSmallInt{. + dynlib: odbclib, importc.} +proc SQLSetEnvAttr*(EnvironmentHandle: SqlHEnv, Attribute: TSqlInteger, + Value: TSqlInteger, StringLength: TSqlInteger): TSqlSmallInt{. + dynlib: odbclib, importc.} +proc SQLGetEnvAttr*(EnvironmentHandle: SqlHEnv, Attribute: TSqlInteger, + Value: SqlPointer, BufferLength: TSqlInteger, + StringLength: PSQLINTEGER): TSqlSmallInt{.dynlib: odbclib, + importc.} +proc SQLFreeHandle*(HandleType: TSqlSmallInt, Handle: SqlHandle): TSqlSmallInt{. + dynlib: odbclib, importc.} +proc SQLGetDiagRec*(HandleType: TSqlSmallInt, Handle: SqlHandle, + RecNumber: TSqlSmallInt, Sqlstate: PSQLCHAR, + NativeError: var TSqlInteger, MessageText: PSQLCHAR, + BufferLength: TSqlSmallInt, TextLength: var TSqlSmallInt): TSqlSmallInt{. + dynlib: odbclib, importc.} +proc SQLGetDiagField*(HandleType: TSqlSmallInt, Handle: SqlHandle, + RecNumber: TSqlSmallInt, DiagIdentifier: TSqlSmallInt, + DiagInfoPtr: SqlPointer, BufferLength: TSqlSmallInt, + StringLengthPtr: var TSqlSmallInt): TSqlSmallInt{. + dynlib: odbclib, importc.} +proc SQLConnect*(ConnectionHandle: SqlHDBC, ServerName: PSQLCHAR, + NameLength1: TSqlSmallInt, UserName: PSQLCHAR, + NameLength2: TSqlSmallInt, Authentication: PSQLCHAR, + NameLength3: TSqlSmallInt): TSqlSmallInt{.dynlib: odbclib, importc.} +proc SQLDisconnect*(ConnectionHandle: SqlHDBC): TSqlSmallInt{.dynlib: odbclib, + importc.} +proc SQLDriverConnect*(hdbc: SqlHDBC, hwnd: SqlHWND, szCsin: cstring, + szCLen: TSqlSmallInt, szCsout: cstring, + cbCSMax: TSqlSmallInt, cbCsOut: var TSqlSmallInt, + f: SqlUSmallInt): TSqlSmallInt{.dynlib: odbclib, importc.} +proc SQLBrowseConnect*(hdbc: SqlHDBC, szConnStrIn: PSQLCHAR, + cbConnStrIn: TSqlSmallInt, szConnStrOut: PSQLCHAR, + cbConnStrOutMax: TSqlSmallInt, + cbConnStrOut: var TSqlSmallInt): TSqlSmallInt{. + dynlib: odbclib, importc.} +proc SQLExecDirect*(StatementHandle: SqlHStmt, StatementText: PSQLCHAR, + TextLength: TSqlInteger): TSqlSmallInt{.dynlib: odbclib, importc.} +proc SQLExecDirectW*(StatementHandle: SqlHStmt, StatementText: WideCString, + TextLength: TSqlInteger): TSqlSmallInt{.dynlib: odbclib, importc.} +proc SQLPrepare*(StatementHandle: SqlHStmt, StatementText: PSQLCHAR, + TextLength: TSqlInteger): TSqlSmallInt{.dynlib: odbclib, importc.} +proc SQLPrepareW*(StatementHandle: SqlHStmt, StatementText: WideCString, + TextLength: TSqlInteger): TSqlSmallInt{.dynlib: odbclib, importc.} +proc SQLCloseCursor*(StatementHandle: SqlHStmt): TSqlSmallInt{.dynlib: odbclib, + importc.} +proc SQLExecute*(StatementHandle: SqlHStmt): TSqlSmallInt{.dynlib: odbclib, importc.} +proc SQLFetch*(StatementHandle: SqlHStmt): TSqlSmallInt{.dynlib: odbclib, importc.} +proc SQLNumResultCols*(StatementHandle: SqlHStmt, ColumnCount: var TSqlSmallInt): TSqlSmallInt{. + dynlib: odbclib, importc.} +proc SQLDescribeCol*(StatementHandle: SqlHStmt, ColumnNumber: SqlUSmallInt, + ColumnName: PSQLCHAR, BufferLength: TSqlSmallInt, + NameLength: var TSqlSmallInt, DataType: var TSqlSmallInt, + ColumnSize: var SqlUInteger, + DecimalDigits: var TSqlSmallInt, Nullable: var TSqlSmallInt): TSqlSmallInt{. + dynlib: odbclib, importc.} +proc SQLFetchScroll*(StatementHandle: SqlHStmt, FetchOrientation: TSqlSmallInt, + FetchOffset: TSqlInteger): TSqlSmallInt{.dynlib: odbclib, + importc.} +proc SQLExtendedFetch*(hstmt: SqlHStmt, fFetchType: SqlUSmallInt, + irow: TSqlInteger, pcrow: PSQLUINTEGER, + rgfRowStatus: PSQLUSMALLINT): TSqlSmallInt{.dynlib: odbclib, + importc.} +proc SQLGetData*(StatementHandle: SqlHStmt, ColumnNumber: SqlUSmallInt, + TargetType: TSqlSmallInt, TargetValue: SqlPointer, + BufferLength: TSqlInteger, StrLen_or_Ind: PSQLINTEGER): TSqlSmallInt{. + dynlib: odbclib, importc.} +proc SQLSetStmtAttr*(StatementHandle: SqlHStmt, Attribute: TSqlInteger, + Value: SqlPointer, StringLength: TSqlInteger): TSqlSmallInt{. + dynlib: odbclib, importc.} +proc SQLGetStmtAttr*(StatementHandle: SqlHStmt, Attribute: TSqlInteger, + Value: SqlPointer, BufferLength: TSqlInteger, + StringLength: PSQLINTEGER): TSqlSmallInt{.dynlib: odbclib, + importc.} +proc SQLGetInfo*(ConnectionHandle: SqlHDBC, InfoType: SqlUSmallInt, + InfoValue: SqlPointer, BufferLength: TSqlSmallInt, + StringLength: PSQLSMALLINT): TSqlSmallInt{.dynlib: odbclib, + importc.} +proc SQLBulkOperations*(StatementHandle: SqlHStmt, Operation: TSqlSmallInt): TSqlSmallInt{. + dynlib: odbclib, importc.} +proc SQLPutData*(StatementHandle: SqlHStmt, Data: SqlPointer, + StrLen_or_Ind: TSqlInteger): TSqlSmallInt{.dynlib: odbclib, importc.} +proc SQLBindCol*(StatementHandle: SqlHStmt, ColumnNumber: SqlUSmallInt, + TargetType: TSqlSmallInt, TargetValue: SqlPointer, + BufferLength: TSqlInteger, StrLen_or_Ind: PSQLINTEGER): TSqlSmallInt{. + dynlib: odbclib, importc.} +proc SQLSetPos*(hstmt: SqlHStmt, irow: SqlUSmallInt, fOption: SqlUSmallInt, + fLock: SqlUSmallInt): TSqlSmallInt{.dynlib: odbclib, importc.} +proc SQLDataSources*(EnvironmentHandle: SqlHEnv, Direction: SqlUSmallInt, + ServerName: PSQLCHAR, BufferLength1: TSqlSmallInt, + NameLength1: PSQLSMALLINT, Description: PSQLCHAR, + BufferLength2: TSqlSmallInt, NameLength2: PSQLSMALLINT): TSqlSmallInt{. + dynlib: odbclib, importc.} +proc SQLDrivers*(EnvironmentHandle: SqlHEnv, Direction: SqlUSmallInt, + DriverDescription: PSQLCHAR, BufferLength1: TSqlSmallInt, + DescriptionLength1: PSQLSMALLINT, DriverAttributes: PSQLCHAR, + BufferLength2: TSqlSmallInt, AttributesLength2: PSQLSMALLINT): TSqlSmallInt{. + dynlib: odbclib, importc.} +proc SQLSetConnectAttr*(ConnectionHandle: SqlHDBC, Attribute: TSqlInteger, + Value: SqlPointer, StringLength: TSqlInteger): TSqlSmallInt{. + dynlib: odbclib, importc.} +proc SQLGetCursorName*(StatementHandle: SqlHStmt, CursorName: PSQLCHAR, + BufferLength: TSqlSmallInt, NameLength: PSQLSMALLINT): TSqlSmallInt{. + dynlib: odbclib, importc.} +proc SQLSetCursorName*(StatementHandle: SqlHStmt, CursorName: PSQLCHAR, + NameLength: TSqlSmallInt): TSqlSmallInt{.dynlib: odbclib, + importc.} +proc SQLRowCount*(StatementHandle: SqlHStmt, RowCount: var TSqlInteger): TSqlSmallInt{. + dynlib: odbclib, importc.} +proc SQLBindParameter*(hstmt: SqlHStmt, ipar: SqlUSmallInt, + fParamType: TSqlSmallInt, fCType: TSqlSmallInt, + fSqlType: TSqlSmallInt, cbColDef: SqlUInteger, + ibScale: TSqlSmallInt, rgbValue: SqlPointer, + cbValueMax: TSqlInteger, pcbValue: PSQLINTEGER): TSqlSmallInt{. + dynlib: odbclib, importc.} +proc SQLFreeStmt*(StatementHandle: SqlHStmt, Option: SqlUSmallInt): TSqlSmallInt{. + dynlib: odbclib, importc.} +proc SQLColAttribute*(StatementHandle: SqlHStmt, ColumnNumber: SqlUSmallInt, + FieldIdentifier: SqlUSmallInt, + CharacterAttribute: PSQLCHAR, BufferLength: TSqlSmallInt, + StringLength: PSQLSMALLINT, + NumericAttribute: SqlPointer): TSqlSmallInt{. + dynlib: odbclib, importc.} +proc SQLEndTran*(HandleType: TSqlSmallInt, Handle: SqlHandle, + CompletionType: TSqlSmallInt): TSqlSmallInt{.dynlib: odbclib, + importc.} +proc SQLTables*(hstmt: SqlHStmt, szTableQualifier: PSQLCHAR, + cbTableQualifier: TSqlSmallInt, szTableOwner: PSQLCHAR, + cbTableOwner: TSqlSmallInt, szTableName: PSQLCHAR, + cbTableName: TSqlSmallInt, szTableType: PSQLCHAR, + cbTableType: TSqlSmallInt): TSqlSmallInt{.dynlib: odbclib, importc.} +proc SQLColumns*(hstmt: SqlHStmt, szTableQualifier: PSQLCHAR, + cbTableQualifier: TSqlSmallInt, szTableOwner: PSQLCHAR, + cbTableOwner: TSqlSmallInt, szTableName: PSQLCHAR, + cbTableName: TSqlSmallInt, szColumnName: PSQLCHAR, + cbColumnName: TSqlSmallInt): TSqlSmallInt{.dynlib: odbclib, importc.} +proc SQLSpecialColumns*(StatementHandle: SqlHStmt, IdentifierType: SqlUSmallInt, + CatalogName: PSQLCHAR, NameLength1: TSqlSmallInt, + SchemaName: PSQLCHAR, NameLength2: TSqlSmallInt, + TableName: PSQLCHAR, NameLength3: TSqlSmallInt, + Scope: SqlUSmallInt, + Nullable: SqlUSmallInt): TSqlSmallInt{. + dynlib: odbclib, importc.} +proc SQLProcedures*(hstmt: SqlHStmt, szTableQualifier: PSQLCHAR, + cbTableQualifier: TSqlSmallInt, szTableOwner: PSQLCHAR, + cbTableOwner: TSqlSmallInt, szTableName: PSQLCHAR, + cbTableName: TSqlSmallInt): TSqlSmallInt{.dynlib: odbclib, + importc.} +proc SQLPrimaryKeys*(hstmt: SqlHStmt, CatalogName: PSQLCHAR, + NameLength1: TSqlSmallInt, SchemaName: PSQLCHAR, + NameLength2: TSqlSmallInt, TableName: PSQLCHAR, + NameLength3: TSqlSmallInt): TSqlSmallInt{.dynlib: odbclib, + importc.} +proc SQLProcedureColumns*(hstmt: SqlHStmt, CatalogName: PSQLCHAR, + NameLength1: TSqlSmallInt, SchemaName: PSQLCHAR, + NameLength2: TSqlSmallInt, ProcName: PSQLCHAR, + NameLength3: TSqlSmallInt, ColumnName: PSQLCHAR, + NameLength4: TSqlSmallInt): TSqlSmallInt{.dynlib: odbclib, + importc.} +proc SQLStatistics*(hstmt: SqlHStmt, CatalogName: PSQLCHAR, + NameLength1: TSqlSmallInt, SchemaName: PSQLCHAR, + NameLength2: TSqlSmallInt, TableName: PSQLCHAR, + NameLength3: TSqlSmallInt, Unique: SqlUSmallInt, + Reserved: SqlUSmallInt): TSqlSmallInt {. + dynlib: odbclib, importc.} +proc SQLErr*(henv: SqlHEnv, hdbc: SqlHDBC, hstmt: SqlHStmt, + szSqlState, pfNativeError, szErrorMsg: PSQLCHAR, + cbErrorMsgMax: TSqlSmallInt, + pcbErrorMsg: PSQLSMALLINT): TSqlSmallInt {. + dynlib: odbclib, importc: "SQLError".} + +{.pop.} +when defined(nimHasStyleChecks): + {.pop.} diff --git a/lib/wrappers/openssl.nim b/lib/wrappers/openssl.nim index fcf52a8d9..4a53fba80 100644 --- a/lib/wrappers/openssl.nim +++ b/lib/wrappers/openssl.nim @@ -7,44 +7,34 @@ # distribution, for details about the copyright. # -## OpenSSL wrapper. Supports OpenSSL >= 1.1.0 dynamically (as default) or statically linked -## using `--dynlibOverride:ssl`. +## OpenSSL support ## -## `-d:sslVersion=1.2.3` can be used to force an SSL version. -## This version must be included in the library name. -## `-d:useOpenssl3` may be set for OpenSSL 3 instead. -## -## There is also limited support for OpenSSL 1.0.x which may require `-d:openssl10`. +## When OpenSSL is dynamically linked, the wrapper provides partial forward and backward +## compatibility for OpenSSL versions above and below 1.1.0 +## +## OpenSSL can also be statically linked using ``--dynlibOverride:ssl`` for OpenSSL >= 1.1.0. +## If you want to statically link against OpenSSL 1.0.x, you now have to +## define the ``openssl10`` symbol via ``-d:openssl10``. ## ## Build and test examples: ## ## .. code-block:: -## ./bin/nim c -d:ssl -p:. -r tests/stdlib/tssl.nim -## ./bin/nim c -d:ssl --threads:on -p:. -r tests/stdlib/thttpclient_ssl.nim ## ./bin/nim c -d:ssl -p:. -r tests/untestable/tssl.nim ## ./bin/nim c -d:ssl -p:. --dynlibOverride:ssl --passl:-lcrypto --passl:-lssl -r tests/untestable/tssl.nim -## ./bin/nim r --putenv:NIM_TESTAMENT_REMOTE_NETWORKING:1 -d:ssl -p:testament/lib --threads:on tests/untestable/thttpclient_ssl_remotenetwork.nim - -# https://www.feistyduck.com/library/openssl-cookbook/online/ch-testing-with-openssl.html -# -from strutils import startsWith - -when defined(nimPreviewSlimSystem): - import std/syncio +{.deadCodeElim: on.} # dce option deprecated when defined(nimHasStyleChecks): {.push styleChecks: off.} -const useWinVersion = defined(windows) or defined(nimdoc) +const useWinVersion = defined(Windows) or defined(nimdoc) -# To force openSSL version use -d:sslVersion=1.2.3 +# To force openSSL version use -d:sslVersion=1.0.0 # See: #10281, #10230 # General issue: # Other dynamic libraries (like libpg) load different openSSL version then what nim loads. # Having two different openSSL loaded version causes a crash. # Use this compile time define to force the openSSL version that your other dynamic libraries want. const sslVersion {.strdefine.}: string = "" -const useOpenssl3* {.booldefine.} = sslVersion.startsWith('3') when sslVersion != "": when defined(macosx): const @@ -63,31 +53,21 @@ when sslVersion != "": from posix import SocketHandle elif useWinVersion: - when defined(openssl10) or defined(nimOldDlls): - when defined(cpu64): - const - DLLSSLName* = "(ssleay32|ssleay64).dll" - DLLUtilName* = "(libeay32|libeay64).dll" - else: - const - DLLSSLName* = "ssleay32.dll" - DLLUtilName* = "libeay32.dll" - elif defined(cpu64): + when not defined(nimOldDlls) and defined(cpu64): const DLLSSLName* = "(libssl-1_1-x64|ssleay64|libssl64).dll" DLLUtilName* = "(libcrypto-1_1-x64|libeay64).dll" else: const DLLSSLName* = "(libssl-1_1|ssleay32|libssl32).dll" - DLLUtilName* = "(libcrypto-1_1|libeay32).dll" + DLLUtilName* = "(libcrypto-1_1|libeay32).dll" from winlean import SocketHandle else: - # same list of versions but ordered differently? when defined(osx): - const versions = "(.3|.1.1|.38|.39|.41|.43|.44|.45|.46|.47|.48|.10|.1.0.2|.1.0.1|.1.0.0|.0.9.9|.0.9.8|)" + const versions = "(.1.1|.38|.39|.41|.43|.44|.45|.46|.47|.10|.1.0.2|.1.0.1|.1.0.0|.0.9.9|.0.9.8|)" else: - const versions = "(.3|.1.1|.1.0.2|.1.0.1|.1.0.0|.0.9.9|.0.9.8|.48|.47|.46|.45|.44|.43|.41|.39|.38|.10|)" + const versions = "(.1.1|.1.0.2|.1.0.1|.1.0.0|.0.9.9|.0.9.8|.47|.46|.45|.44|.43|.41|.39|.38|.10|)" when defined(macosx): const @@ -105,18 +85,15 @@ else: import dynlib -{.pragma: lcrypto, cdecl, dynlib: DLLUtilName, importc.} -{.pragma: lssl, cdecl, dynlib: DLLSSLName, importc.} - type SslStruct {.final, pure.} = object SslPtr* = ptr SslStruct PSslPtr* = ptr SslPtr SslCtx* = SslPtr PSSL_METHOD* = SslPtr - PSTACK* = SslPtr PX509* = SslPtr PX509_NAME* = SslPtr + PEVP_MD* = SslPtr PBIO_METHOD* = SslPtr BIO* = SslPtr EVP_PKEY* = SslPtr @@ -139,15 +116,6 @@ type pem_password_cb* = proc(buf: cstring, size, rwflag: cint, userdata: pointer): cint {.cdecl.} - PaddingType* = enum - RSA_PKCS1_PADDING = 1.cint, - RSA_SSLV23_PADDING = 2.cint, - RSA_NO_PADDING = 3.cint, - RSA_PKCS1_OAEP_PADDING = 4.cint, - RSA_X931_PADDING = 5.cint, - RSA_PKCS1_PSS_PADDING = 6.cint - - const SSL_SENT_SHUTDOWN* = 1 SSL_RECEIVED_SHUTDOWN* = 2 @@ -204,7 +172,6 @@ const SSL_CTRL_SET_TLSEXT_SERVERNAME_CB = 53 SSL_CTRL_SET_TLSEXT_SERVERNAME_ARG = 54 SSL_CTRL_SET_TLSEXT_HOSTNAME = 55 - SSL_CTRL_SET_ECDH_AUTO* = 94 TLSEXT_NAMETYPE_host_name* = 0 SSL_TLSEXT_ERR_OK* = 0 SSL_TLSEXT_ERR_ALERT_WARNING* = 1 @@ -225,9 +192,6 @@ const SSL_OP_ALL* = 0x000FFFFF SSL_VERIFY_NONE* = 0x00000000 SSL_VERIFY_PEER* = 0x00000001 - SSL_ST_CONNECT* = 0x1000 - SSL_ST_ACCEPT* = 0x2000 - SSL_ST_INIT* = SSL_ST_CONNECT or SSL_ST_ACCEPT OPENSSL_DES_DECRYPT* = 0 OPENSSL_DES_ENCRYPT* = 1 X509_V_OK* = 0 @@ -280,21 +244,13 @@ proc TLSv1_method*(): PSSL_METHOD{.cdecl, dynlib: DLLSSLName, importc.} # and support SSLv3, TLSv1, TLSv1.1 and TLSv1.2 # SSLv23_method(), SSLv23_server_method(), SSLv23_client_method() are removed in 1.1.0 -const useStaticLink = compileOption("dynlibOverride", "ssl") or defined(noOpenSSLHacks) - -when useStaticLink: +when compileOption("dynlibOverride", "ssl"): # Static linking when defined(openssl10): proc SSL_library_init*(): cint {.cdecl, dynlib: DLLSSLName, importc, discardable.} proc SSL_load_error_strings*() {.cdecl, dynlib: DLLSSLName, importc.} proc SSLv23_method*(): PSSL_METHOD {.cdecl, dynlib: DLLSSLName, importc.} - proc SSLeay(): culong {.cdecl, dynlib: DLLUtilName, importc.} - - proc getOpenSSLVersion*(): culong = - SSLeay() - - proc ERR_load_BIO_strings*() {.cdecl, dynlib: DLLUtilName, importc.} else: proc OPENSSL_init_ssl*(opts: uint64, settings: uint8): cint {.cdecl, dynlib: DLLSSLName, importc, discardable.} proc SSL_library_init*(): cint {.discardable.} = @@ -305,7 +261,7 @@ when useStaticLink: proc SSLv23_method*(): PSSL_METHOD = TLS_method() - proc OpenSSL_version_num(): culong {.cdecl, dynlib: DLLUtilName, importc.} + proc OpenSSL_version_num(): culong {.cdecl, dynlib: DLLSSLName, importc.} proc getOpenSSLVersion*(): culong = ## Return OpenSSL version as unsigned long @@ -317,105 +273,52 @@ when useStaticLink: # Static linking against OpenSSL < 1.1.0 is not supported discard - proc ERR_load_BIO_strings*() = - discard - - when defined(libressl) or defined(openssl10): - proc SSL_state(ssl: SslPtr): cint {.cdecl, dynlib: DLLSSLName, importc.} - proc SSL_in_init*(ssl: SslPtr): cint {.inline.} = - SSL_state(ssl) and SSL_ST_INIT - else: - proc SSL_in_init*(ssl: SslPtr): cint {.cdecl, dynlib: DLLSSLName, importc.} - proc SSL_CTX_set_ciphersuites*(ctx: SslCtx, str: cstring): cint {.cdecl, dynlib: DLLSSLName, importc.} - template OpenSSL_add_all_algorithms*() = discard proc SSLv23_client_method*(): PSSL_METHOD {.cdecl, dynlib: DLLSSLName, importc.} proc SSLv2_method*(): PSSL_METHOD {.cdecl, dynlib: DLLSSLName, importc.} proc SSLv3_method*(): PSSL_METHOD {.cdecl, dynlib: DLLSSLName, importc.} - proc CRYPTO_set_mem_functions(a,b,c: pointer){.cdecl, dynlib: DLLUtilName, importc.} else: - # Here we're trying to stay compatible between openssl versions. Some + # Here we're trying to stay compatible with openssl 1.0.* and 1.1.*. Some # symbols are loaded dynamically and we don't use them if not found. proc thisModule(): LibHandle {.inline.} = var thisMod {.global.}: LibHandle if thisMod.isNil: thisMod = loadLib() - result = thisMod - proc sslModule(): LibHandle {.inline, raises: [LibraryError], tags:[RootEffect].} = + proc sslModule(): LibHandle {.inline.} = var sslMod {.global.}: LibHandle - try: - if sslMod.isNil: sslMod = loadLibPattern(DLLSSLName) - except: - raise newException(LibraryError, "Could not load SSL using " & DLLSSLName) - + if sslMod.isNil: sslMod = loadLibPattern(DLLSSLName) result = sslMod - proc utilModule(): LibHandle {.inline.} = - var utilMod {.global.}: LibHandle - if utilMod.isNil: utilMod = loadLibPattern(DLLUtilName) - - result = utilMod - - proc symNullable(dll: LibHandle, name: string, alternativeName = ""): pointer = - # Load from DLL. - if not dll.isNil: - result = symAddr(dll, name) - if result.isNil and alternativeName.len > 0: - result = symAddr(dll, alternativeName) - - # Attempt to load from current exe. + proc sslSym(name: string): pointer = + var dl = thisModule() + if not dl.isNil: + result = symAddr(dl, name) if result.isNil: - let thisDynlib = thisModule() - if thisDynlib.isNil: return nil - result = symAddr(thisDynlib, name) - if result.isNil and alternativeName.len > 0: - result = symAddr(thisDynlib, alternativeName) + dl = sslModule() + if not dl.isNil: + result = symAddr(dl, name) - proc sslSymNullable(name: string, alternativeName = ""): pointer {.raises: [LibraryError], tags:[RootEffect].} = - sslModule().symNullable(name, alternativeName) - - proc sslSymThrows(name: string, alternativeName = ""): pointer {.raises: [LibraryError].} = - result = sslSymNullable(name, alternativeName) - if result.isNil: raiseInvalidLibrary(name) - - proc utilSymNullable(name: string, alternativeName = ""): pointer = - utilModule().symNullable(name, alternativeName) - - proc loadPSSLMethod(method1, method2: string): PSSL_METHOD {.raises: [LibraryError], tags:[RootEffect].} = + proc loadPSSLMethod(method1, method2: string): PSSL_METHOD = ## Load from OpenSSL if available, otherwise - ## - let methodSym = sslSymNullable(method1, method2) - if methodSym.isNil: - raise newException(LibraryError, "Could not load " & method1 & " nor " & method2) - - let method2Proc = cast[proc(): PSSL_METHOD {.cdecl, gcsafe, raises: [].}](methodSym) - return method2Proc() - - proc CRYPTO_set_mem_functions(a,b,c: pointer) = - let theProc = cast[proc(a,b,c: pointer) {.cdecl.}](utilModule().symNullable("CRYPTO_set_mem_functions")) - if not theProc.isNil: theProc(a, b, c) + let m1 = cast[proc(): PSSL_METHOD {.cdecl, gcsafe.}](sslSym(method1)) + if not m1.isNil: + return m1() + cast[proc(): PSSL_METHOD {.cdecl, gcsafe.}](sslSym(method2))() proc SSL_library_init*(): cint {.discardable.} = ## Initialize SSL using OPENSSL_init_ssl for OpenSSL >= 1.1.0 otherwise ## SSL_library_init - let newInitSym = sslSymNullable("OPENSSL_init_ssl") - if not newInitSym.isNil: - let newInitProc = - cast[proc(opts: uint64, settings: uint8): cint {.cdecl.}](newInitSym) - return newInitProc(0, 0) - let olderProc = cast[proc(): cint {.cdecl.}](sslSymThrows("SSL_library_init")) + let theProc = cast[proc(opts: uint64, settings: uint8): cint {.cdecl.}](sslSym("OPENSSL_init_ssl")) + if not theProc.isNil: + return theProc(0, 0) + let olderProc = cast[proc(): cint {.cdecl.}](sslSym("SSL_library_init")) if not olderProc.isNil: result = olderProc() proc SSL_load_error_strings*() = - # TODO: Are we ignoring this on purpose? SSL GitHub CI fails otherwise. - let theProc = cast[proc() {.cdecl.}](sslSymNullable("SSL_load_error_strings")) - if not theProc.isNil: theProc() - - proc ERR_load_BIO_strings*() = - let theProc = cast[proc() {.cdecl.}](utilModule().symNullable("ERR_load_BIO_strings")) + let theProc = cast[proc() {.cdecl.}](sslSym("SSL_load_error_strings")) if not theProc.isNil: theProc() proc SSLv23_client_method*(): PSSL_METHOD = @@ -440,45 +343,22 @@ else: loadPSSLMethod("TLS_server_method", "SSLv23_server_method") proc OpenSSL_add_all_algorithms*() = - # TODO: Are we ignoring this on purpose? SSL GitHub CI fails otherwise. - let theProc = cast[proc() {.cdecl.}](sslSymNullable("OPENSSL_add_all_algorithms_conf")) + let theProc = cast[proc() {.cdecl.}](sslSym("OPENSSL_add_all_algorithms_conf")) if not theProc.isNil: theProc() proc getOpenSSLVersion*(): culong = ## Return OpenSSL version as unsigned long or 0 if not available - let theProc = cast[proc(): culong {.cdecl, gcsafe.}](utilSymNullable("OpenSSL_version_num", "SSLeay")) + let theProc = cast[proc(): culong {.cdecl.}](sslSym("OpenSSL_version_num")) result = if theProc.isNil: 0.culong else: theProc() - proc SSL_in_init*(ssl: SslPtr): cint = - # A compatibility wrapper for `SSL_in_init()` for OpenSSL 1.0, 1.1 and LibreSSL - const MainProc = "SSL_in_init" - let - theProc {.global.} = cast[proc(ssl: SslPtr): cint {.cdecl, gcsafe.}](sslSymNullable(MainProc)) - # Fallback - sslState {.global.} = cast[proc(ssl: SslPtr): cint {.cdecl, gcsafe.}](sslSymNullable("SSL_state")) - - if not theProc.isNil: - result = theProc(ssl) - elif not sslState.isNil: - result = sslState(ssl) and SSL_ST_INIT - else: - raiseInvalidLibrary MainProc - - proc SSL_CTX_set_ciphersuites*(ctx: SslCtx, str: cstring): cint = - var theProc {.global.}: proc(ctx: SslCtx, str: cstring): cint {.cdecl, gcsafe.} - if theProc.isNil: - theProc = cast[typeof(theProc)](sslSymThrows("SSL_CTX_set_ciphersuites")) - result = theProc(ctx, str) +proc ERR_load_BIO_strings*(){.cdecl, dynlib: DLLUtilName, importc.} proc SSL_new*(context: SslCtx): SslPtr{.cdecl, dynlib: DLLSSLName, importc.} proc SSL_free*(ssl: SslPtr){.cdecl, dynlib: DLLSSLName, importc.} proc SSL_get_SSL_CTX*(ssl: SslPtr): SslCtx {.cdecl, dynlib: DLLSSLName, importc.} proc SSL_set_SSL_CTX*(ssl: SslPtr, ctx: SslCtx): SslCtx {.cdecl, dynlib: DLLSSLName, importc.} -proc SSL_CTX_set_session_id_context*(context: SslCtx, sid_ctx: string, sid_ctx_len: int){.cdecl, dynlib: DLLSSLName, importc.} -proc SSL_get0_verified_chain*(ssl: SslPtr): PSTACK {.cdecl, dynlib: DLLSSLName, - importc.} proc SSL_CTX_new*(meth: PSSL_METHOD): SslCtx{.cdecl, dynlib: DLLSSLName, importc.} proc SSL_CTX_load_verify_locations*(ctx: SslCtx, CAfile: cstring, @@ -515,11 +395,11 @@ proc SSL_accept*(ssl: SslPtr): cint{.cdecl, dynlib: DLLSSLName, importc.} proc SSL_pending*(ssl: SslPtr): cint{.cdecl, dynlib: DLLSSLName, importc.} proc BIO_new_mem_buf*(data: pointer, len: cint): BIO{.cdecl, - dynlib: DLLUtilName, importc.} + dynlib: DLLSSLName, importc.} proc BIO_new_ssl_connect*(ctx: SslCtx): BIO{.cdecl, dynlib: DLLSSLName, importc.} proc BIO_ctrl*(bio: BIO, cmd: cint, larg: int, arg: cstring): int{.cdecl, - dynlib: DLLUtilName, importc.} + dynlib: DLLSSLName, importc.} proc BIO_get_ssl*(bio: BIO, ssl: ptr SslPtr): int = return BIO_ctrl(bio, BIO_C_GET_SSL, 0, cast[cstring](ssl)) proc BIO_set_conn_hostname*(bio: BIO, name: cstring): int = @@ -537,48 +417,19 @@ when not defined(nimfix): proc BIO_free*(b: BIO): cint{.cdecl, dynlib: DLLUtilName, importc.} -proc ERR_print_errors_fp*(fp: File){.cdecl, dynlib: DLLUtilName, importc.} +proc ERR_print_errors_fp*(fp: File){.cdecl, dynlib: DLLSSLName, importc.} -proc ERR_error_string*(e: culong, buf: cstring): cstring{.cdecl, +proc ERR_error_string*(e: cint, buf: cstring): cstring{.cdecl, dynlib: DLLUtilName, importc.} -proc ERR_get_error*(): culong{.cdecl, dynlib: DLLUtilName, importc.} -proc ERR_peek_last_error*(): culong{.cdecl, dynlib: DLLUtilName, importc.} +proc ERR_get_error*(): cint{.cdecl, dynlib: DLLUtilName, importc.} +proc ERR_peek_last_error*(): cint{.cdecl, dynlib: DLLUtilName, importc.} -proc OPENSSL_config*(configName: cstring){.cdecl, dynlib: DLLUtilName, importc.} +proc OPENSSL_config*(configName: cstring){.cdecl, dynlib: DLLSSLName, importc.} -proc OPENSSL_sk_num*(stack: PSTACK): int {.cdecl, dynlib: DLLSSLName, importc.} - -proc OPENSSL_sk_value*(stack: PSTACK, index: int): pointer {.cdecl, - dynlib: DLLSSLName, importc.} - -proc d2i_X509*(px: ptr PX509, i: ptr ptr uint8, len: cint): PX509 {.cdecl, +when not useWinVersion and not defined(macosx) and not defined(android) and not defined(nimNoAllocForSSL): + proc CRYPTO_set_mem_functions(a,b,c: pointer){.cdecl, dynlib: DLLUtilName, importc.} -proc i2d_X509*(cert: PX509; o: ptr ptr uint8): cint {.cdecl, - dynlib: DLLUtilName, importc.} - -proc d2i_X509*(b: string): PX509 = - ## decode DER/BER bytestring into X.509 certificate struct - var bb = b.cstring - let i = cast[ptr ptr uint8](addr bb) - let ret = d2i_X509(addr result, i, b.len.cint) - if ret.isNil: - raise newException(Exception, "X.509 certificate decoding failed") - -proc i2d_X509*(cert: PX509): string = - ## encode `cert` to DER string - let encoded_length = i2d_X509(cert, nil) - result = newString(encoded_length) - var q = result.cstring - let o = cast[ptr ptr uint8](addr q) - let length = i2d_X509(cert, o) - if length.int <= 0: - raise newException(Exception, "X.509 certificate encoding failed") - -const - useNimsAlloc = not defined(nimNoAllocForSSL) and not defined(gcDestructors) - -when not useWinVersion and not defined(macosx) and not defined(android) and useNimsAlloc: proc allocWrapper(size: int): pointer {.cdecl.} = allocShared(size) proc reallocWrapper(p: pointer; newSize: int): pointer {.cdecl.} = if p == nil: @@ -588,28 +439,27 @@ when not useWinVersion and not defined(macosx) and not defined(android) and useN proc deallocWrapper(p: pointer) {.cdecl.} = if p != nil: deallocShared(p) - proc CRYPTO_malloc_init*() = +proc CRYPTO_malloc_init*() = + when not useWinVersion and not defined(macosx) and not defined(android) and not defined(nimNoAllocForSSL): CRYPTO_set_mem_functions(allocWrapper, reallocWrapper, deallocWrapper) -else: - proc CRYPTO_malloc_init*() = - discard -proc SSL_CTX_ctrl*(ctx: SslCtx, cmd: cint, larg: clong, parg: pointer): clong{. +proc SSL_CTX_ctrl*(ctx: SslCtx, cmd: cint, larg: int, parg: pointer): int{. cdecl, dynlib: DLLSSLName, importc.} proc SSL_CTX_callback_ctrl(ctx: SslCtx, typ: cint, fp: PFunction): int{. cdecl, dynlib: DLLSSLName, importc.} proc SSLCTXSetMode*(ctx: SslCtx, mode: int): int = - result = SSL_CTX_ctrl(ctx, SSL_CTRL_MODE, clong mode, nil) + result = SSL_CTX_ctrl(ctx, SSL_CTRL_MODE, mode, nil) proc SSL_ctrl*(ssl: SslPtr, cmd: cint, larg: int, parg: pointer): int{. cdecl, dynlib: DLLSSLName, importc.} proc SSL_set_tlsext_host_name*(ssl: SslPtr, name: cstring): int = + result = SSL_ctrl(ssl, SSL_CTRL_SET_TLSEXT_HOSTNAME, TLSEXT_NAMETYPE_host_name, name) ## Set the SNI server name extension to be used in a client hello. ## Returns 1 if SNI was set, 0 if current SSL configuration doesn't support SNI. - result = SSL_ctrl(ssl, SSL_CTRL_SET_TLSEXT_HOSTNAME, TLSEXT_NAMETYPE_host_name, name) + proc SSL_get_servername*(ssl: SslPtr, typ: cint = TLSEXT_NAMETYPE_host_name): cstring {.cdecl, dynlib: DLLSSLName, importc.} ## Retrieve the server name requested in the client hello. This can be used @@ -627,16 +477,16 @@ proc SSL_CTX_set_tlsext_servername_callback*(ctx: SslCtx, cb: proc(ssl: SslPtr, result = SSL_CTX_callback_ctrl(ctx, SSL_CTRL_SET_TLSEXT_SERVERNAME_CB, cast[PFunction](cb)) proc SSL_CTX_set_tlsext_servername_arg*(ctx: SslCtx, arg: pointer): int = - ## Set the pointer to be used in the callback registered to `SSL_CTX_set_tlsext_servername_callback`. + ## Set the pointer to be used in the callback registered to ``SSL_CTX_set_tlsext_servername_callback``. result = SSL_CTX_ctrl(ctx, SSL_CTRL_SET_TLSEXT_SERVERNAME_ARG, 0, arg) type PskClientCallback* = proc (ssl: SslPtr; - hint: cstring; identity: cstring; max_identity_len: cuint; psk: ptr uint8; + hint: cstring; identity: cstring; max_identity_len: cuint; psk: ptr cuchar; max_psk_len: cuint): cuint {.cdecl.} PskServerCallback* = proc (ssl: SslPtr; - identity: cstring; psk: ptr uint8; max_psk_len: cint): cuint {.cdecl.} + identity: cstring; psk: ptr cuchar; max_psk_len: cint): cuint {.cdecl.} proc SSL_CTX_set_psk_client_callback*(ctx: SslCtx; callback: PskClientCallback) {.cdecl, dynlib: DLLSSLName, importc.} ## Set callback called when OpenSSL needs PSK (for client). @@ -650,15 +500,6 @@ proc SSL_CTX_use_psk_identity_hint*(ctx: SslCtx; hint: cstring): cint {.cdecl, d proc SSL_get_psk_identity*(ssl: SslPtr): cstring {.cdecl, dynlib: DLLSSLName, importc.} ## Get PSK identity. -proc SSL_CTX_set_ecdh_auto*(ctx: SslCtx, onoff: cint): cint {.inline.} = - ## Set automatic curve selection. - ## - ## On OpenSSL >= 1.1.0 this is on by default and cannot be disabled. - if getOpenSSLVersion() < 0x010100000 or getOpenSSLVersion() == 0x020000000: - result = cint SSL_CTX_ctrl(ctx, SSL_CTRL_SET_ECDH_AUTO, onoff, nil) - else: - result = 1 - proc bioNew*(b: PBIO_METHOD): BIO{.cdecl, dynlib: DLLUtilName, importc: "BIO_new".} proc bioFreeAll*(b: BIO){.cdecl, dynlib: DLLUtilName, importc: "BIO_free_all".} proc bioSMem*(): PBIO_METHOD{.cdecl, dynlib: DLLUtilName, importc: "BIO_s_mem".} @@ -687,78 +528,55 @@ proc sslDoHandshake*(ssl: SslPtr): cint {.cdecl, dynlib: DLLSSLName, importc: "SSL_do_handshake".} + proc ErrClearError*(){.cdecl, dynlib: DLLUtilName, importc: "ERR_clear_error".} proc ErrFreeStrings*(){.cdecl, dynlib: DLLUtilName, importc: "ERR_free_strings".} proc ErrRemoveState*(pid: cint){.cdecl, dynlib: DLLUtilName, importc: "ERR_remove_state".} proc PEM_read_bio_RSA_PUBKEY*(bp: BIO, x: ptr PRSA, pw: pem_password_cb, u: pointer): PRSA {.cdecl, - dynlib: DLLUtilName, importc.} -proc PEM_read_RSA_PUBKEY*(fp: pointer; x: ptr PRSA; cb: pem_password_cb, u: pointer): PRSA {.cdecl, - dynlib: DLLUtilName, importc.} + dynlib: DLLSSLName, importc.} + proc RSA_verify*(kind: cint, origMsg: pointer, origMsgLen: cuint, signature: pointer, - signatureLen: cuint, rsa: PRSA): cint {.cdecl, dynlib: DLLUtilName, importc.} -proc PEM_read_RSAPrivateKey*(fp: pointer; x: ptr PRSA; cb: pem_password_cb, u: pointer): PRSA {.cdecl, - dynlib: DLLUtilName, importc.} -proc PEM_read_RSAPublicKey*(fp: pointer; x: ptr PRSA; cb: pem_password_cb, u: pointer): PRSA {.cdecl, - dynlib: DLLUtilName, importc.} -proc PEM_read_bio_RSAPublicKey*(bp: BIO, x: ptr PRSA, cb: pem_password_cb, u: pointer): PRSA {.cdecl, - dynlib: DLLUtilName, importc.} -proc PEM_read_bio_RSAPrivateKey*(bp: BIO, x: ptr PRSA, cb: pem_password_cb, u: pointer): PRSA {.cdecl, - dynlib: DLLUtilName, importc.} -proc RSA_private_encrypt*(flen: cint, fr: ptr uint8, to: ptr uint8, rsa: PRSA, padding: PaddingType): cint {.cdecl, - dynlib: DLLUtilName, importc.} -proc RSA_public_encrypt*(flen: cint, fr: ptr uint8, to: ptr uint8, rsa: PRSA, padding: PaddingType): cint {.cdecl, - dynlib: DLLUtilName, importc.} -proc RSA_private_decrypt*(flen: cint, fr: ptr uint8, to: ptr uint8, rsa: PRSA, padding: PaddingType): cint {.cdecl, - dynlib: DLLUtilName, importc.} -proc RSA_public_decrypt*(flen: cint, fr: ptr uint8, to: ptr uint8, rsa: PRSA, padding: PaddingType): cint {.cdecl, - dynlib: DLLUtilName, importc.} -proc RSA_free*(rsa: PRSA) {.cdecl, dynlib: DLLUtilName, importc.} -proc RSA_size*(rsa: PRSA): cint {.cdecl, dynlib: DLLUtilName, importc.} + signatureLen: cuint, rsa: PRSA): cint {.cdecl, dynlib: DLLSSLName, importc.} # sha types -proc EVP_md_null*(): EVP_MD {.lcrypto.} -proc EVP_md2*(): EVP_MD {.lcrypto.} -proc EVP_md4*(): EVP_MD {.lcrypto.} -proc EVP_md5*(): EVP_MD {.lcrypto.} -proc EVP_sha*(): EVP_MD {.lcrypto.} -proc EVP_sha1*(): EVP_MD {.lcrypto.} -proc EVP_dss*(): EVP_MD {.lcrypto.} -proc EVP_dss1*(): EVP_MD {.lcrypto.} -proc EVP_ecdsa*(): EVP_MD {.lcrypto.} -proc EVP_sha224*(): EVP_MD {.lcrypto.} -proc EVP_sha256*(): EVP_MD {.lcrypto.} -proc EVP_sha384*(): EVP_MD {.lcrypto.} -proc EVP_sha512*(): EVP_MD {.lcrypto.} -proc EVP_mdc2*(): EVP_MD {.lcrypto.} -proc EVP_ripemd160*(): EVP_MD {.lcrypto.} -proc EVP_whirlpool*(): EVP_MD {.lcrypto.} -proc EVP_MD_size*(md: EVP_MD): cint {.lcrypto.} +proc EVP_md_null*(): EVP_MD {.cdecl, importc.} +proc EVP_md2*(): EVP_MD {.cdecl, importc.} +proc EVP_md4*(): EVP_MD {.cdecl, importc.} +proc EVP_md5*(): EVP_MD {.cdecl, importc.} +proc EVP_sha*(): EVP_MD {.cdecl, importc.} +proc EVP_sha1*(): EVP_MD {.cdecl, importc.} +proc EVP_dss*(): EVP_MD {.cdecl, importc.} +proc EVP_dss1*(): EVP_MD {.cdecl, importc.} +proc EVP_ecdsa*(): EVP_MD {.cdecl, importc.} +proc EVP_sha224*(): EVP_MD {.cdecl, importc.} +proc EVP_sha256*(): EVP_MD {.cdecl, importc.} +proc EVP_sha384*(): EVP_MD {.cdecl, importc.} +proc EVP_sha512*(): EVP_MD {.cdecl, importc.} +proc EVP_mdc2*(): EVP_MD {.cdecl, importc.} +proc EVP_ripemd160*(): EVP_MD {.cdecl, importc.} +proc EVP_whirlpool*(): EVP_MD {.cdecl, importc.} # hmac functions -proc HMAC*(evp_md: EVP_MD; key: pointer; key_len: cint; d: cstring; n: csize_t; md: cstring; md_len: ptr cuint): cstring {.lcrypto.} +proc HMAC*(evp_md: EVP_MD; key: pointer; key_len: cint; d: cstring; n: csize_t; md: cstring; md_len: ptr cuint): cstring {.cdecl, importc.} # RSA key functions -proc PEM_read_bio_PrivateKey*(bp: BIO, x: ptr EVP_PKEY, cb: pointer, u: pointer): EVP_PKEY {.lcrypto.} -proc EVP_PKEY_free*(p: EVP_PKEY) {.lcrypto.} -proc EVP_DigestSignInit*(ctx: EVP_MD_CTX, pctx: ptr EVP_PKEY_CTX, typ: EVP_MD, e: ENGINE, pkey: EVP_PKEY): cint {.lcrypto.} -proc EVP_DigestInit_ex*(ctx: EVP_MD_CTX, typ: EVP_MD, engine: SslPtr = nil): cint {.lcrypto.} -proc EVP_DigestUpdate*(ctx: EVP_MD_CTX, data: pointer, len: cuint): cint {.lcrypto.} -proc EVP_DigestFinal_ex*(ctx: EVP_MD_CTX, buffer: pointer, size: ptr cuint): cint {.lcrypto.} -proc EVP_DigestSignFinal*(ctx: EVP_MD_CTX, data: pointer, len: ptr csize_t): cint {.lcrypto.} -proc EVP_PKEY_CTX_new*(pkey: EVP_PKEY, e: ENGINE): EVP_PKEY_CTX {.lcrypto.} -proc EVP_PKEY_CTX_free*(pkeyCtx: EVP_PKEY_CTX) {.lcrypto.} -proc EVP_PKEY_sign_init*(c: EVP_PKEY_CTX): cint {.lcrypto.} +proc PEM_read_bio_PrivateKey*(bp: BIO, x: ptr EVP_PKEY, cb: pointer, u: pointer): EVP_PKEY {.cdecl, importc.} +proc EVP_PKEY_free*(p: EVP_PKEY) {.cdecl, importc.} +proc EVP_DigestSignInit*(ctx: EVP_MD_CTX, pctx: ptr EVP_PKEY_CTX, typ: EVP_MD, e: ENGINE, pkey: EVP_PKEY): cint {.cdecl, importc.} +proc EVP_DigestUpdate*(ctx: EVP_MD_CTX, data: pointer, len: cuint): cint {.cdecl, importc.} +proc EVP_DigestSignFinal*(ctx: EVP_MD_CTX, data: pointer, len: ptr csize_t): cint {.cdecl, importc.} +proc EVP_PKEY_CTX_new*(pkey: EVP_PKEY, e: ENGINE): EVP_PKEY_CTX {.cdecl, importc.} +proc EVP_PKEY_CTX_free*(pkeyCtx: EVP_PKEY_CTX) {.cdecl, importc.} +proc EVP_PKEY_sign_init*(c: EVP_PKEY_CTX): cint {.cdecl, importc.} when defined(macosx) or defined(windows): - proc EVP_MD_CTX_create*(): EVP_MD_CTX {.lcrypto.} - proc EVP_MD_CTX_destroy*(ctx: EVP_MD_CTX) {.lcrypto.} - proc EVP_MD_CTX_cleanup*(ctx: EVP_MD_CTX): cint {.lcrypto.} + proc EVP_MD_CTX_create*(): EVP_MD_CTX {.cdecl, importc.} + proc EVP_MD_CTX_destroy*(ctx: EVP_MD_CTX) {.cdecl, importc.} else: # some times you will need this instead: - proc EVP_MD_CTX_create*(): EVP_MD_CTX {.cdecl, importc: "EVP_MD_CTX_new", dynlib: DLLUtilName.} - proc EVP_MD_CTX_destroy*(ctx: EVP_MD_CTX) {.cdecl, importc: "EVP_MD_CTX_free", dynlib: DLLUtilName.} - proc EVP_MD_CTX_cleanup*(ctx: EVP_MD_CTX): cint {.cdecl, importc: "EVP_MD_CTX_cleanup", dynlib: DLLUtilName.} + proc EVP_MD_CTX_create*(): EVP_MD_CTX {.cdecl, importc: "EVP_MD_CTX_new".} + proc EVP_MD_CTX_destroy*(ctx: EVP_MD_CTX) {.cdecl, importc: "EVP_MD_CTX_free".} # type @@ -777,8 +595,8 @@ type proc md5_Init*(c: var MD5_CTX): cint{.importc: "MD5_Init".} proc md5_Update*(c: var MD5_CTX; data: pointer; len: csize_t): cint{.importc: "MD5_Update".} proc md5_Final*(md: cstring; c: var MD5_CTX): cint{.importc: "MD5_Final".} -proc md5*(d: ptr uint8; n: csize_t; md: ptr uint8): ptr uint8{.importc: "MD5".} -proc md5_Transform*(c: var MD5_CTX; b: ptr uint8){.importc: "MD5_Transform".} +proc md5*(d: ptr cuchar; n: csize_t; md: ptr cuchar): ptr cuchar{.importc: "MD5".} +proc md5_Transform*(c: var MD5_CTX; b: ptr cuchar){.importc: "MD5_Transform".} {.pop.} from strutils import toHex, toLowerAscii @@ -801,13 +619,13 @@ proc md5_File*(file: string): string {.raises: [IOError,Exception].} = ctx: MD5_CTX discard md5_Init(ctx) - while (let bytes = f.readChars(buf); bytes > 0): + while(let bytes = f.readChars(buf, 0, sz); bytes > 0): discard md5_Update(ctx, buf[0].addr, cast[csize_t](bytes)) - discard md5_Final(cast[cstring](buf[0].addr), ctx) + discard md5_Final(buf[0].addr, ctx) f.close - result = hexStr(cast[cstring](addr buf)) + result = hexStr(addr buf) proc md5_Str*(str: string): string = ## Generate MD5 hash for a string. Result is a 32 character @@ -824,88 +642,8 @@ proc md5_Str*(str: string): string = discard md5_Update(ctx, input[i].addr, cast[csize_t](L)) i += L - discard md5_Final(cast[cstring](addr res), ctx) - result = hexStr(cast[cstring](addr res)) + discard md5_Final(addr res, ctx) + result = hexStr(addr res) when defined(nimHasStyleChecks): {.pop.} - - -# Certificate validation -# On old openSSL version some of these symbols are not available -when not defined(nimDisableCertificateValidation) and not defined(windows): - - # SSL_get_peer_certificate removed in 3.0 - # SSL_get1_peer_certificate added in 3.0 - when useOpenssl3: - proc SSL_get1_peer_certificate*(ssl: SslCtx): PX509 {.cdecl, dynlib: DLLSSLName, importc.} - proc SSL_get_peer_certificate*(ssl: SslCtx): PX509 = - SSL_get1_peer_certificate(ssl) - elif useStaticLink: - proc SSL_get_peer_certificate*(ssl: SslCtx): PX509 {.cdecl, dynlib: DLLSSLName, importc.} - else: - proc SSL_get_peer_certificate*(ssl: SslCtx): PX509 = - let methodSym = sslSymNullable("SSL_get_peer_certificate", "SSL_get1_peer_certificate") - if methodSym.isNil: - raise newException(LibraryError, "Could not load SSL_get_peer_certificate or SSL_get1_peer_certificate") - let method2Proc = cast[proc(ssl: SslCtx): PX509 {.cdecl, gcsafe, raises: [].}](methodSym) - return method2Proc(ssl) - - proc X509_get_subject_name*(a: PX509): PX509_NAME{.cdecl, dynlib: DLLSSLName, importc.} - - proc X509_get_issuer_name*(a: PX509): PX509_NAME{.cdecl, dynlib: DLLUtilName, importc.} - - proc X509_NAME_oneline*(a: PX509_NAME, buf: cstring, size: cint): cstring {. - cdecl, dynlib:DLLSSLName, importc.} - - proc X509_NAME_get_text_by_NID*(subject:cstring, NID: cint, buf: cstring, size: cint): cint{. - cdecl, dynlib:DLLSSLName, importc.} - - proc X509_check_host*(cert: PX509, name: cstring, namelen: cint, flags:cuint, peername: cstring): cint {.cdecl, dynlib: DLLSSLName, importc.} - - proc X509_free*(cert: PX509) {.cdecl, dynlib: DLLSSLName, importc.} - - # Certificates store - - type PX509_STORE* = SslPtr - type PX509_OBJECT* = SslPtr - - {.push callconv:cdecl, dynlib:DLLUtilName, importc.} - - proc X509_OBJECT_new*(): PX509_OBJECT - proc X509_OBJECT_free*(a: PX509_OBJECT) - - proc X509_STORE_new*(): PX509_STORE - proc X509_STORE_free*(v: PX509_STORE) - proc X509_STORE_lock*(ctx: PX509_STORE): cint - proc X509_STORE_unlock*(ctx: PX509_STORE): cint - proc X509_STORE_up_ref*(v: PX509_STORE): cint - proc X509_STORE_set_flags*(ctx: PX509_STORE; flags: culong): cint - proc X509_STORE_set_purpose*(ctx: PX509_STORE; purpose: cint): cint - proc X509_STORE_set_trust*(ctx: PX509_STORE; trust: cint): cint - proc X509_STORE_add_cert*(ctx: PX509_STORE; x: PX509): cint - - {.pop.} - - when isMainModule: - when defined(nimPreviewSlimSystem): - import std/assertions - # A simple certificate test - let certbytes = readFile("certificate.der") - let cert = d2i_X509(certbytes) - let encoded = cert.i2d_X509() - assert encoded == certbytes - -# Application Layer Protocol Negociation extension (TLS-ALPN, RFC7301) -# Available in at least OpenSSL 1.1.1 and later, not sure if earlier -# --Iced Quinn - -proc SSL_CTX_set_alpn_protos*(ctx: SslCtx; protos: cstring; protos_len: cuint): cint {.cdecl, dynlib: DLLSSLName, importc.} -proc SSL_set_alpn_protos*(ssl: SslPtr; protos: cstring; protos_len: cuint): cint {.cdecl, dynlib: DLLSSLName, importc.} -proc SSL_CTX_set_alpn_select_cb*(ctx: SslCtx; cb: proc(ssl: SslPtr; out_proto: ptr cstring; outlen: cstring; in_proto: cstring; inlen: cuint; arg: pointer): cint {.cdecl.}; arg: pointer): cint {.cdecl, dynlib: DLLSSLName, importc.} -proc SSL_get0_alpn_selected*(ssl: SslPtr; data: ptr cstring; len: ptr cuint) {.cdecl, dynlib: DLLSSLName, importc.} -proc SSL_CTX_set_next_protos_advertised_cb*(ctx: SslCtx; cb: proc(ssl: SslPtr; out_proto: ptr cstring; outlen: ptr cuint; arg: pointer): cint {.cdecl.}; arg: pointer) {.cdecl, dynlib: DLLSSLName, importc.} -proc SSL_CTX_set_next_proto_select_cb*(ctx: SslCtx; cb: proc(s: SslPtr; out_proto: cstring; outlen: cstring; in_proto: cstring; inlen: cuint; arg: pointer): cint {.cdecl.}; arg: pointer) {.cdecl, dynlib: DLLSSLName, importc.} -proc SSL_select_next_proto*(out_proto: ptr cstring; outlen: cstring; server: cstring; server_len: cuint; client: cstring; client_len: cuint): cint {.cdecl, dynlib: DLLSSLName, importc.} -proc SSL_get0_next_proto_negotiated*(s: SslPtr; data: ptr cstring; len: ptr cuint) {.cdecl, dynlib: DLLSSLName, importc.} - diff --git a/lib/wrappers/pcre.nim b/lib/wrappers/pcre.nim index 9144f6784..7012053b7 100644 --- a/lib/wrappers/pcre.nim +++ b/lib/wrappers/pcre.nim @@ -7,6 +7,8 @@ # distribution, for details about the copyright. # +{.deadCodeElim: on.} # dce option deprecated + # The current PCRE version information. const diff --git a/lib/wrappers/postgres.nim b/lib/wrappers/postgres.nim new file mode 100644 index 000000000..c90116ea2 --- /dev/null +++ b/lib/wrappers/postgres.nim @@ -0,0 +1,373 @@ +# +# +# Nim's Runtime Library +# (c) Copyright 2015 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +# This module contains the definitions for structures and externs for +# functions used by frontend postgres applications. It is based on +# Postgresql's libpq-fe.h. +# +# It is for postgreSQL version 7.4 and higher with support for the v3.0 +# connection-protocol. +# + +{.deadCodeElim: on.} # dce option deprecated +when defined(nimHasStyleChecks): + {.push styleChecks: off.} + +when defined(windows): + const + dllName = "libpq.dll" +elif defined(macosx): + const + dllName = "libpq.dylib" +else: + const + dllName = "libpq.so(.5|)" +type + POid* = ptr Oid + Oid* = int32 + +const + ERROR_MSG_LENGTH* = 4096 + CMDSTATUS_LEN* = 40 + +type + SockAddr* = array[1..112, int8] + PGresAttDesc*{.pure, final.} = object + name*: cstring + adtid*: Oid + adtsize*: int + + PPGresAttDesc* = ptr PGresAttDesc + PPPGresAttDesc* = ptr PPGresAttDesc + PGresAttValue*{.pure, final.} = object + length*: int32 + value*: cstring + + PPGresAttValue* = ptr PGresAttValue + PPPGresAttValue* = ptr PPGresAttValue + PExecStatusType* = ptr ExecStatusType + ExecStatusType* = enum + PGRES_EMPTY_QUERY = 0, PGRES_COMMAND_OK, PGRES_TUPLES_OK, PGRES_COPY_OUT, + PGRES_COPY_IN, PGRES_BAD_RESPONSE, PGRES_NONFATAL_ERROR, PGRES_FATAL_ERROR + PGlobjfuncs*{.pure, final.} = object + fn_lo_open*: Oid + fn_lo_close*: Oid + fn_lo_creat*: Oid + fn_lo_unlink*: Oid + fn_lo_lseek*: Oid + fn_lo_tell*: Oid + fn_lo_read*: Oid + fn_lo_write*: Oid + + PPGlobjfuncs* = ptr PGlobjfuncs + PConnStatusType* = ptr ConnStatusType + ConnStatusType* = enum + CONNECTION_OK, CONNECTION_BAD, CONNECTION_STARTED, CONNECTION_MADE, + CONNECTION_AWAITING_RESPONSE, CONNECTION_AUTH_OK, CONNECTION_SETENV, + CONNECTION_SSL_STARTUP, CONNECTION_NEEDED + PGconn*{.pure, final.} = object + pghost*: cstring + pgtty*: cstring + pgport*: cstring + pgoptions*: cstring + dbName*: cstring + status*: ConnStatusType + errorMessage*: array[0..(ERROR_MSG_LENGTH) - 1, char] + Pfin*: File + Pfout*: File + Pfdebug*: File + sock*: int32 + laddr*: SockAddr + raddr*: SockAddr + salt*: array[0..(2) - 1, char] + asyncNotifyWaiting*: int32 + notifyList*: pointer + pguser*: cstring + pgpass*: cstring + lobjfuncs*: PPGlobjfuncs + + PPGconn* = ptr PGconn + PGresult*{.pure, final.} = object + ntups*: int32 + numAttributes*: int32 + attDescs*: PPGresAttDesc + tuples*: PPPGresAttValue + tupArrSize*: int32 + resultStatus*: ExecStatusType + cmdStatus*: array[0..(CMDSTATUS_LEN) - 1, char] + binary*: int32 + conn*: PPGconn + + PPGresult* = ptr PGresult + PPostgresPollingStatusType* = ptr PostgresPollingStatusType + PostgresPollingStatusType* = enum + PGRES_POLLING_FAILED = 0, PGRES_POLLING_READING, PGRES_POLLING_WRITING, + PGRES_POLLING_OK, PGRES_POLLING_ACTIVE + PPGTransactionStatusType* = ptr PGTransactionStatusType + PGTransactionStatusType* = enum + PQTRANS_IDLE, PQTRANS_ACTIVE, PQTRANS_INTRANS, PQTRANS_INERROR, + PQTRANS_UNKNOWN + PPGVerbosity* = ptr PGVerbosity + PGVerbosity* = enum + PQERRORS_TERSE, PQERRORS_DEFAULT, PQERRORS_VERBOSE + PPGNotify* = ptr pgNotify + pgNotify*{.pure, final.} = object + relname*: cstring + be_pid*: int32 + extra*: cstring + + PQnoticeReceiver* = proc (arg: pointer, res: PPGresult){.cdecl.} + PQnoticeProcessor* = proc (arg: pointer, message: cstring){.cdecl.} + Ppqbool* = ptr pqbool + pqbool* = char + PPQprintOpt* = ptr PQprintOpt + PQprintOpt*{.pure, final.} = object + header*: pqbool + align*: pqbool + standard*: pqbool + html3*: pqbool + expanded*: pqbool + pager*: pqbool + fieldSep*: cstring + tableOpt*: cstring + caption*: cstring + fieldName*: ptr cstring + + PPQconninfoOption* = ptr PQconninfoOption + PQconninfoOption*{.pure, final.} = object + keyword*: cstring + envvar*: cstring + compiled*: cstring + val*: cstring + label*: cstring + dispchar*: cstring + dispsize*: int32 + + PPQArgBlock* = ptr PQArgBlock + PQArgBlock*{.pure, final.} = object + length*: int32 + isint*: int32 + p*: pointer + +proc pqinitOpenSSL*(do_ssl: int32, do_crypto: int32) {.cdecl, dynlib: dllName, + importc: "PQinitOpenSSL".} +proc pqconnectStart*(conninfo: cstring): PPGconn{.cdecl, dynlib: dllName, + importc: "PQconnectStart".} +proc pqconnectPoll*(conn: PPGconn): PostgresPollingStatusType{.cdecl, + dynlib: dllName, importc: "PQconnectPoll".} +proc pqconnectdb*(conninfo: cstring): PPGconn{.cdecl, dynlib: dllName, + importc: "PQconnectdb".} +proc pqsetdbLogin*(pghost: cstring, pgport: cstring, pgoptions: cstring, + pgtty: cstring, dbName: cstring, login: cstring, pwd: cstring): PPGconn{. + cdecl, dynlib: dllName, importc: "PQsetdbLogin".} +proc pqsetdb*(M_PGHOST, M_PGPORT, M_PGOPT, M_PGTTY, M_DBNAME: cstring): PPGconn +proc pqfinish*(conn: PPGconn){.cdecl, dynlib: dllName, importc: "PQfinish".} +proc pqconndefaults*(): PPQconninfoOption{.cdecl, dynlib: dllName, + importc: "PQconndefaults".} +proc pqconninfoFree*(connOptions: PPQconninfoOption){.cdecl, dynlib: dllName, + importc: "PQconninfoFree".} +proc pqresetStart*(conn: PPGconn): int32{.cdecl, dynlib: dllName, + importc: "PQresetStart".} +proc pqresetPoll*(conn: PPGconn): PostgresPollingStatusType{.cdecl, + dynlib: dllName, importc: "PQresetPoll".} +proc pqreset*(conn: PPGconn){.cdecl, dynlib: dllName, importc: "PQreset".} +proc pqrequestCancel*(conn: PPGconn): int32{.cdecl, dynlib: dllName, + importc: "PQrequestCancel".} +proc pqdb*(conn: PPGconn): cstring{.cdecl, dynlib: dllName, importc: "PQdb".} +proc pquser*(conn: PPGconn): cstring{.cdecl, dynlib: dllName, importc: "PQuser".} +proc pqpass*(conn: PPGconn): cstring{.cdecl, dynlib: dllName, importc: "PQpass".} +proc pqhost*(conn: PPGconn): cstring{.cdecl, dynlib: dllName, importc: "PQhost".} +proc pqport*(conn: PPGconn): cstring{.cdecl, dynlib: dllName, importc: "PQport".} +proc pqtty*(conn: PPGconn): cstring{.cdecl, dynlib: dllName, importc: "PQtty".} +proc pqoptions*(conn: PPGconn): cstring{.cdecl, dynlib: dllName, + importc: "PQoptions".} +proc pqstatus*(conn: PPGconn): ConnStatusType{.cdecl, dynlib: dllName, + importc: "PQstatus".} +proc pqtransactionStatus*(conn: PPGconn): PGTransactionStatusType{.cdecl, + dynlib: dllName, importc: "PQtransactionStatus".} +proc pqparameterStatus*(conn: PPGconn, paramName: cstring): cstring{.cdecl, + dynlib: dllName, importc: "PQparameterStatus".} +proc pqserverVersion*(conn: PPGconn): int32{.cdecl, + dynlib: dllName, importc: "PQserverVersion".} +proc pqprotocolVersion*(conn: PPGconn): int32{.cdecl, dynlib: dllName, + importc: "PQprotocolVersion".} +proc pqerrorMessage*(conn: PPGconn): cstring{.cdecl, dynlib: dllName, + importc: "PQerrorMessage".} +proc pqsocket*(conn: PPGconn): int32{.cdecl, dynlib: dllName, + importc: "PQsocket".} +proc pqbackendPID*(conn: PPGconn): int32{.cdecl, dynlib: dllName, + importc: "PQbackendPID".} +proc pqconnectionNeedsPassword*(conn: PPGconn): int32{.cdecl, dynlib: dllName, + importc: "PQconnectionNeedsPassword".} +proc pqconnectionUsedPassword*(conn: PPGconn): int32{.cdecl, dynlib: dllName, + importc: "PQconnectionUsedPassword".} +proc pqclientEncoding*(conn: PPGconn): int32{.cdecl, dynlib: dllName, + importc: "PQclientEncoding".} +proc pqsetClientEncoding*(conn: PPGconn, encoding: cstring): int32{.cdecl, + dynlib: dllName, importc: "PQsetClientEncoding".} +when defined(USE_SSL): + # Get the SSL structure associated with a connection + proc pqgetssl*(conn: PPGconn): PSSL{.cdecl, dynlib: dllName, + importc: "PQgetssl".} +proc pqsetErrorVerbosity*(conn: PPGconn, verbosity: PGVerbosity): PGVerbosity{. + cdecl, dynlib: dllName, importc: "PQsetErrorVerbosity".} +proc pqtrace*(conn: PPGconn, debug_port: File){.cdecl, dynlib: dllName, + importc: "PQtrace".} +proc pquntrace*(conn: PPGconn){.cdecl, dynlib: dllName, importc: "PQuntrace".} +proc pqsetNoticeReceiver*(conn: PPGconn, theProc: PQnoticeReceiver, arg: pointer): PQnoticeReceiver{. + cdecl, dynlib: dllName, importc: "PQsetNoticeReceiver".} +proc pqsetNoticeProcessor*(conn: PPGconn, theProc: PQnoticeProcessor, + arg: pointer): PQnoticeProcessor{.cdecl, + dynlib: dllName, importc: "PQsetNoticeProcessor".} +proc pqexec*(conn: PPGconn, query: cstring): PPGresult{.cdecl, dynlib: dllName, + importc: "PQexec".} +proc pqexecParams*(conn: PPGconn, command: cstring, nParams: int32, + paramTypes: POid, paramValues: cstringArray, + paramLengths, paramFormats: ptr int32, resultFormat: int32): PPGresult{. + cdecl, dynlib: dllName, importc: "PQexecParams".} +proc pqprepare*(conn: PPGconn, stmtName, query: cstring, nParams: int32, + paramTypes: POid): PPGresult{.cdecl, dynlib: dllName, importc: "PQprepare".} +proc pqexecPrepared*(conn: PPGconn, stmtName: cstring, nParams: int32, + paramValues: cstringArray, + paramLengths, paramFormats: ptr int32, resultFormat: int32): PPGresult{. + cdecl, dynlib: dllName, importc: "PQexecPrepared".} +proc pqsendQuery*(conn: PPGconn, query: cstring): int32{.cdecl, dynlib: dllName, + importc: "PQsendQuery".} +proc pqsendQueryParams*(conn: PPGconn, command: cstring, nParams: int32, + paramTypes: POid, paramValues: cstringArray, + paramLengths, paramFormats: ptr int32, + resultFormat: int32): int32{.cdecl, dynlib: dllName, + importc: "PQsendQueryParams".} +proc pqsendQueryPrepared*(conn: PPGconn, stmtName: cstring, nParams: int32, + paramValues: cstringArray, + paramLengths, paramFormats: ptr int32, + resultFormat: int32): int32{.cdecl, dynlib: dllName, + importc: "PQsendQueryPrepared".} +proc pqgetResult*(conn: PPGconn): PPGresult{.cdecl, dynlib: dllName, + importc: "PQgetResult".} +proc pqisBusy*(conn: PPGconn): int32{.cdecl, dynlib: dllName, + importc: "PQisBusy".} +proc pqconsumeInput*(conn: PPGconn): int32{.cdecl, dynlib: dllName, + importc: "PQconsumeInput".} +proc pqnotifies*(conn: PPGconn): PPGNotify{.cdecl, dynlib: dllName, + importc: "PQnotifies".} +proc pqputCopyData*(conn: PPGconn, buffer: cstring, nbytes: int32): int32{. + cdecl, dynlib: dllName, importc: "PQputCopyData".} +proc pqputCopyEnd*(conn: PPGconn, errormsg: cstring): int32{.cdecl, + dynlib: dllName, importc: "PQputCopyEnd".} +proc pqgetCopyData*(conn: PPGconn, buffer: cstringArray, async: int32): int32{. + cdecl, dynlib: dllName, importc: "PQgetCopyData".} +proc pqgetline*(conn: PPGconn, str: cstring, len: int32): int32{.cdecl, + dynlib: dllName, importc: "PQgetline".} +proc pqputline*(conn: PPGconn, str: cstring): int32{.cdecl, dynlib: dllName, + importc: "PQputline".} +proc pqgetlineAsync*(conn: PPGconn, buffer: cstring, bufsize: int32): int32{. + cdecl, dynlib: dllName, importc: "PQgetlineAsync".} +proc pqputnbytes*(conn: PPGconn, buffer: cstring, nbytes: int32): int32{.cdecl, + dynlib: dllName, importc: "PQputnbytes".} +proc pqendcopy*(conn: PPGconn): int32{.cdecl, dynlib: dllName, + importc: "PQendcopy".} +proc pqsetnonblocking*(conn: PPGconn, arg: int32): int32{.cdecl, + dynlib: dllName, importc: "PQsetnonblocking".} +proc pqisnonblocking*(conn: PPGconn): int32{.cdecl, dynlib: dllName, + importc: "PQisnonblocking".} +proc pqflush*(conn: PPGconn): int32{.cdecl, dynlib: dllName, importc: "PQflush".} +proc pqfn*(conn: PPGconn, fnid: int32, result_buf, result_len: ptr int32, + result_is_int: int32, args: PPQArgBlock, nargs: int32): PPGresult{. + cdecl, dynlib: dllName, importc: "PQfn".} +proc pqresultStatus*(res: PPGresult): ExecStatusType{.cdecl, dynlib: dllName, + importc: "PQresultStatus".} +proc pqresStatus*(status: ExecStatusType): cstring{.cdecl, dynlib: dllName, + importc: "PQresStatus".} +proc pqresultErrorMessage*(res: PPGresult): cstring{.cdecl, dynlib: dllName, + importc: "PQresultErrorMessage".} +proc pqresultErrorField*(res: PPGresult, fieldcode: int32): cstring{.cdecl, + dynlib: dllName, importc: "PQresultErrorField".} +proc pqntuples*(res: PPGresult): int32{.cdecl, dynlib: dllName, + importc: "PQntuples".} +proc pqnfields*(res: PPGresult): int32{.cdecl, dynlib: dllName, + importc: "PQnfields".} +proc pqbinaryTuples*(res: PPGresult): int32{.cdecl, dynlib: dllName, + importc: "PQbinaryTuples".} +proc pqfname*(res: PPGresult, field_num: int32): cstring{.cdecl, + dynlib: dllName, importc: "PQfname".} +proc pqfnumber*(res: PPGresult, field_name: cstring): int32{.cdecl, + dynlib: dllName, importc: "PQfnumber".} +proc pqftable*(res: PPGresult, field_num: int32): Oid{.cdecl, dynlib: dllName, + importc: "PQftable".} +proc pqftablecol*(res: PPGresult, field_num: int32): int32{.cdecl, + dynlib: dllName, importc: "PQftablecol".} +proc pqfformat*(res: PPGresult, field_num: int32): int32{.cdecl, + dynlib: dllName, importc: "PQfformat".} +proc pqftype*(res: PPGresult, field_num: int32): Oid{.cdecl, dynlib: dllName, + importc: "PQftype".} +proc pqfsize*(res: PPGresult, field_num: int32): int32{.cdecl, dynlib: dllName, + importc: "PQfsize".} +proc pqfmod*(res: PPGresult, field_num: int32): int32{.cdecl, dynlib: dllName, + importc: "PQfmod".} +proc pqcmdStatus*(res: PPGresult): cstring{.cdecl, dynlib: dllName, + importc: "PQcmdStatus".} +proc pqoidStatus*(res: PPGresult): cstring{.cdecl, dynlib: dllName, + importc: "PQoidStatus".} +proc pqoidValue*(res: PPGresult): Oid{.cdecl, dynlib: dllName, + importc: "PQoidValue".} +proc pqcmdTuples*(res: PPGresult): cstring{.cdecl, dynlib: dllName, + importc: "PQcmdTuples".} +proc pqgetvalue*(res: PPGresult, tup_num: int32, field_num: int32): cstring{. + cdecl, dynlib: dllName, importc: "PQgetvalue".} +proc pqgetlength*(res: PPGresult, tup_num: int32, field_num: int32): int32{. + cdecl, dynlib: dllName, importc: "PQgetlength".} +proc pqgetisnull*(res: PPGresult, tup_num: int32, field_num: int32): int32{. + cdecl, dynlib: dllName, importc: "PQgetisnull".} +proc pqclear*(res: PPGresult){.cdecl, dynlib: dllName, importc: "PQclear".} +proc pqfreemem*(p: pointer){.cdecl, dynlib: dllName, importc: "PQfreemem".} +proc pqmakeEmptyPGresult*(conn: PPGconn, status: ExecStatusType): PPGresult{. + cdecl, dynlib: dllName, importc: "PQmakeEmptyPGresult".} +proc pqescapeString*(till, `from`: cstring, len: int): int{.cdecl, + dynlib: dllName, importc: "PQescapeString".} +proc pqescapeBytea*(bintext: cstring, binlen: int, bytealen: var int): cstring{. + cdecl, dynlib: dllName, importc: "PQescapeBytea".} +proc pqunescapeBytea*(strtext: cstring, retbuflen: var int): cstring{.cdecl, + dynlib: dllName, importc: "PQunescapeBytea".} +proc pqprint*(fout: File, res: PPGresult, ps: PPQprintOpt){.cdecl, + dynlib: dllName, importc: "PQprint".} +proc pqdisplayTuples*(res: PPGresult, fp: File, fillAlign: int32, + fieldSep: cstring, printHeader: int32, quiet: int32){. + cdecl, dynlib: dllName, importc: "PQdisplayTuples".} +proc pqprintTuples*(res: PPGresult, fout: File, printAttName: int32, + terseOutput: int32, width: int32){.cdecl, dynlib: dllName, + importc: "PQprintTuples".} +proc lo_open*(conn: PPGconn, lobjId: Oid, mode: int32): int32{.cdecl, + dynlib: dllName, importc: "lo_open".} +proc lo_close*(conn: PPGconn, fd: int32): int32{.cdecl, dynlib: dllName, + importc: "lo_close".} +proc lo_read*(conn: PPGconn, fd: int32, buf: cstring, length: int): int32{. + cdecl, dynlib: dllName, importc: "lo_read".} +proc lo_write*(conn: PPGconn, fd: int32, buf: cstring, length: int): int32{. + cdecl, dynlib: dllName, importc: "lo_write".} +proc lo_lseek*(conn: PPGconn, fd: int32, offset: int32, whence: int32): int32{. + cdecl, dynlib: dllName, importc: "lo_lseek".} +proc lo_creat*(conn: PPGconn, mode: int32): Oid{.cdecl, dynlib: dllName, + importc: "lo_creat".} +proc lo_tell*(conn: PPGconn, fd: int32): int32{.cdecl, dynlib: dllName, + importc: "lo_tell".} +proc lo_unlink*(conn: PPGconn, lobjId: Oid): int32{.cdecl, dynlib: dllName, + importc: "lo_unlink".} +proc lo_import*(conn: PPGconn, filename: cstring): Oid{.cdecl, dynlib: dllName, + importc: "lo_import".} +proc lo_export*(conn: PPGconn, lobjId: Oid, filename: cstring): int32{.cdecl, + dynlib: dllName, importc: "lo_export".} +proc pqmblen*(s: cstring, encoding: int32): int32{.cdecl, dynlib: dllName, + importc: "PQmblen".} +proc pqenv2encoding*(): int32{.cdecl, dynlib: dllName, importc: "PQenv2encoding".} +proc pqsetdb(M_PGHOST, M_PGPORT, M_PGOPT, M_PGTTY, M_DBNAME: cstring): PPGconn = + result = pqsetdbLogin(M_PGHOST, M_PGPORT, M_PGOPT, M_PGTTY, M_DBNAME, "", "") + +when defined(nimHasStyleChecks): + {.pop.} diff --git a/lib/wrappers/sqlite3.nim b/lib/wrappers/sqlite3.nim new file mode 100644 index 000000000..f4ec6180f --- /dev/null +++ b/lib/wrappers/sqlite3.nim @@ -0,0 +1,394 @@ +# +# +# Nim's Runtime Library +# (c) Copyright 2012 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +{.deadCodeElim: on.} # dce option deprecated + +when defined(nimHasStyleChecks): + {.push styleChecks: off.} + +when defined(windows): + when defined(nimOldDlls): + const Lib = "sqlite3.dll" + elif defined(cpu64): + const Lib = "sqlite3_64.dll" + else: + const Lib = "sqlite3_32.dll" +elif defined(macosx): + const + Lib = "libsqlite3(|.0).dylib" +else: + const + Lib = "libsqlite3.so(|.0)" + +when defined(staticSqlite): + {.pragma: mylib.} + {.compile: "sqlite3.c".} +else: + {.pragma: mylib, dynlib: Lib.} + +const + SQLITE_INTEGER* = 1 + SQLITE_FLOAT* = 2 + SQLITE_BLOB* = 4 + SQLITE_NULL* = 5 + SQLITE_TEXT* = 3 + SQLITE_UTF8* = 1 + SQLITE_UTF16LE* = 2 + SQLITE_UTF16BE* = 3 # Use native byte order + SQLITE_UTF16* = 4 # sqlite3_create_function only + SQLITE_ANY* = 5 #sqlite_exec return values + SQLITE_OK* = 0 + SQLITE_ERROR* = 1 # SQL error or missing database + SQLITE_INTERNAL* = 2 # An internal logic error in SQLite + SQLITE_PERM* = 3 # Access permission denied + SQLITE_ABORT* = 4 # Callback routine requested an abort + SQLITE_BUSY* = 5 # The database file is locked + SQLITE_LOCKED* = 6 # A table in the database is locked + SQLITE_NOMEM* = 7 # A malloc() failed + SQLITE_READONLY* = 8 # Attempt to write a readonly database + SQLITE_INTERRUPT* = 9 # Operation terminated by sqlite3_interrupt() + SQLITE_IOERR* = 10 # Some kind of disk I/O error occurred + SQLITE_CORRUPT* = 11 # The database disk image is malformed + SQLITE_NOTFOUND* = 12 # (Internal Only) Table or record not found + SQLITE_FULL* = 13 # Insertion failed because database is full + SQLITE_CANTOPEN* = 14 # Unable to open the database file + SQLITE_PROTOCOL* = 15 # Database lock protocol error + SQLITE_EMPTY* = 16 # Database is empty + SQLITE_SCHEMA* = 17 # The database schema changed + SQLITE_TOOBIG* = 18 # Too much data for one row of a table + SQLITE_CONSTRAINT* = 19 # Abort due to constraint violation + SQLITE_MISMATCH* = 20 # Data type mismatch + SQLITE_MISUSE* = 21 # Library used incorrectly + SQLITE_NOLFS* = 22 # Uses OS features not supported on host + SQLITE_AUTH* = 23 # Authorization denied + SQLITE_FORMAT* = 24 # Auxiliary database format error + SQLITE_RANGE* = 25 # 2nd parameter to sqlite3_bind out of range + SQLITE_NOTADB* = 26 # File opened that is not a database file + SQLITE_ROW* = 100 # sqlite3_step() has another row ready + SQLITE_DONE* = 101 # sqlite3_step() has finished executing + SQLITE_COPY* = 0 + SQLITE_CREATE_INDEX* = 1 + SQLITE_CREATE_TABLE* = 2 + SQLITE_CREATE_TEMP_INDEX* = 3 + SQLITE_CREATE_TEMP_TABLE* = 4 + SQLITE_CREATE_TEMP_TRIGGER* = 5 + SQLITE_CREATE_TEMP_VIEW* = 6 + SQLITE_CREATE_TRIGGER* = 7 + SQLITE_CREATE_VIEW* = 8 + SQLITE_DELETE* = 9 + SQLITE_DROP_INDEX* = 10 + SQLITE_DROP_TABLE* = 11 + SQLITE_DROP_TEMP_INDEX* = 12 + SQLITE_DROP_TEMP_TABLE* = 13 + SQLITE_DROP_TEMP_TRIGGER* = 14 + SQLITE_DROP_TEMP_VIEW* = 15 + SQLITE_DROP_TRIGGER* = 16 + SQLITE_DROP_VIEW* = 17 + SQLITE_INSERT* = 18 + SQLITE_PRAGMA* = 19 + SQLITE_READ* = 20 + SQLITE_SELECT* = 21 + SQLITE_TRANSACTION* = 22 + SQLITE_UPDATE* = 23 + SQLITE_ATTACH* = 24 + SQLITE_DETACH* = 25 + SQLITE_ALTER_TABLE* = 26 + SQLITE_REINDEX* = 27 + SQLITE_DENY* = 1 + SQLITE_IGNORE* = 2 # Original from sqlite3.h: + #define SQLITE_STATIC ((void(*)(void *))0) + #define SQLITE_TRANSIENT ((void(*)(void *))-1) + SQLITE_DETERMINISTIC* = 0x800 + +type + Sqlite3 {.pure, final.} = object + PSqlite3* = ptr Sqlite3 + PPSqlite3* = ptr PSqlite3 + Sqlite3_Backup {.pure, final.} = object + PSqlite3_Backup* = ptr Sqlite3_Backup + PPSqlite3_Backup* = ptr PSqlite3_Backup + Context{.pure, final.} = object + Pcontext* = ptr Context + TStmt{.pure, final.} = object + PStmt* = ptr TStmt + Value{.pure, final.} = object + PValue* = ptr Value + PValueArg* = array[0..127, PValue] + + Callback* = proc (para1: pointer, para2: int32, para3, + para4: cstringArray): int32{.cdecl.} + Tbind_destructor_func* = proc (para1: pointer){.cdecl, locks: 0, tags: [], gcsafe.} + Create_function_step_func* = proc (para1: Pcontext, para2: int32, + para3: PValueArg){.cdecl.} + Create_function_func_func* = proc (para1: Pcontext, para2: int32, + para3: PValueArg){.cdecl.} + Create_function_final_func* = proc (para1: Pcontext){.cdecl.} + Result_func* = proc (para1: pointer){.cdecl.} + Create_collation_func* = proc (para1: pointer, para2: int32, para3: pointer, + para4: int32, para5: pointer): int32{.cdecl.} + Collation_needed_func* = proc (para1: pointer, para2: PSqlite3, eTextRep: int32, + para4: cstring){.cdecl.} + +const + SQLITE_STATIC* = nil + SQLITE_TRANSIENT* = cast[Tbind_destructor_func](-1) + +proc close*(para1: PSqlite3): int32{.cdecl, mylib, importc: "sqlite3_close".} +proc exec*(para1: PSqlite3, sql: cstring, para3: Callback, para4: pointer, + errmsg: var cstring): int32{.cdecl, mylib, + importc: "sqlite3_exec".} +proc last_insert_rowid*(para1: PSqlite3): int64{.cdecl, mylib, + importc: "sqlite3_last_insert_rowid".} +proc changes*(para1: PSqlite3): int32{.cdecl, mylib, importc: "sqlite3_changes".} +proc total_changes*(para1: PSqlite3): int32{.cdecl, mylib, + importc: "sqlite3_total_changes".} +proc interrupt*(para1: PSqlite3){.cdecl, mylib, importc: "sqlite3_interrupt".} +proc complete*(sql: cstring): int32{.cdecl, mylib, + importc: "sqlite3_complete".} +proc complete16*(sql: pointer): int32{.cdecl, mylib, + importc: "sqlite3_complete16".} +proc busy_handler*(para1: PSqlite3, + para2: proc (para1: pointer, para2: int32): int32{.cdecl.}, + para3: pointer): int32{.cdecl, mylib, + importc: "sqlite3_busy_handler".} +proc busy_timeout*(para1: PSqlite3, ms: int32): int32{.cdecl, mylib, + importc: "sqlite3_busy_timeout".} +proc get_table*(para1: PSqlite3, sql: cstring, resultp: var cstringArray, + nrow, ncolumn: var cint, errmsg: ptr cstring): int32{.cdecl, + mylib, importc: "sqlite3_get_table".} +proc free_table*(result: cstringArray){.cdecl, mylib, + importc: "sqlite3_free_table".} + # Todo: see how translate sqlite3_mprintf, sqlite3_vmprintf, sqlite3_snprintf + # function sqlite3_mprintf(_para1:Pchar; args:array of const):Pchar;cdecl; external Sqlite3Lib name 'sqlite3_mprintf'; +proc mprintf*(para1: cstring): cstring{.cdecl, varargs, mylib, + importc: "sqlite3_mprintf".} + #function sqlite3_vmprintf(_para1:Pchar; _para2:va_list):Pchar;cdecl; external Sqlite3Lib name 'sqlite3_vmprintf'; +proc free*(z: cstring){.cdecl, mylib, importc: "sqlite3_free".} + #function sqlite3_snprintf(_para1:longint; _para2:Pchar; _para3:Pchar; args:array of const):Pchar;cdecl; external Sqlite3Lib name 'sqlite3_snprintf'; +proc snprintf*(para1: int32, para2: cstring, para3: cstring): cstring{.cdecl, + mylib, varargs, importc: "sqlite3_snprintf".} +proc set_authorizer*(para1: PSqlite3, xAuth: proc (para1: pointer, para2: int32, + para3: cstring, para4: cstring, para5: cstring, para6: cstring): int32{. + cdecl.}, pUserData: pointer): int32{.cdecl, mylib, + importc: "sqlite3_set_authorizer".} +proc trace*(para1: PSqlite3, xTrace: proc (para1: pointer, para2: cstring){.cdecl.}, + para3: pointer): pointer{.cdecl, mylib, + importc: "sqlite3_trace".} +proc progress_handler*(para1: PSqlite3, para2: int32, + para3: proc (para1: pointer): int32{.cdecl.}, + para4: pointer){.cdecl, mylib, + importc: "sqlite3_progress_handler".} +proc commit_hook*(para1: PSqlite3, para2: proc (para1: pointer): int32{.cdecl.}, + para3: pointer): pointer{.cdecl, mylib, + importc: "sqlite3_commit_hook".} +proc open*(filename: cstring, ppDb: var PSqlite3): int32{.cdecl, mylib, + importc: "sqlite3_open".} +proc open16*(filename: pointer, ppDb: var PSqlite3): int32{.cdecl, mylib, + importc: "sqlite3_open16".} +proc errcode*(db: PSqlite3): int32{.cdecl, mylib, importc: "sqlite3_errcode".} +proc errmsg*(para1: PSqlite3): cstring{.cdecl, mylib, importc: "sqlite3_errmsg".} +proc errmsg16*(para1: PSqlite3): pointer{.cdecl, mylib, + importc: "sqlite3_errmsg16".} +proc prepare*(db: PSqlite3, zSql: cstring, nBytes: int32, ppStmt: var PStmt, + pzTail: ptr cstring): int32{.cdecl, mylib, + importc: "sqlite3_prepare".} + +proc prepare_v2*(db: PSqlite3, zSql: cstring, nByte: cint, ppStmt: var PStmt, + pzTail: ptr cstring): cint {. + importc: "sqlite3_prepare_v2", cdecl, mylib.} + +proc prepare16*(db: PSqlite3, zSql: pointer, nBytes: int32, ppStmt: var PStmt, + pzTail: var pointer): int32{.cdecl, mylib, + importc: "sqlite3_prepare16".} +proc bind_blob*(para1: PStmt, para2: int32, para3: pointer, n: int32, + para5: Tbind_destructor_func): int32{.cdecl, mylib, + importc: "sqlite3_bind_blob".} +proc bind_double*(para1: PStmt, para2: int32, para3: float64): int32{.cdecl, + mylib, importc: "sqlite3_bind_double".} +proc bind_int*(para1: PStmt, para2: int32, para3: int32): int32{.cdecl, + mylib, importc: "sqlite3_bind_int".} +proc bind_int64*(para1: PStmt, para2: int32, para3: int64): int32{.cdecl, + mylib, importc: "sqlite3_bind_int64".} +proc bind_null*(para1: PStmt, para2: int32): int32{.cdecl, mylib, + importc: "sqlite3_bind_null".} +proc bind_text*(para1: PStmt, para2: int32, para3: cstring, n: int32, + para5: Tbind_destructor_func): int32{.cdecl, mylib, + importc: "sqlite3_bind_text".} +proc bind_text16*(para1: PStmt, para2: int32, para3: pointer, para4: int32, + para5: Tbind_destructor_func): int32{.cdecl, mylib, + importc: "sqlite3_bind_text16".} + #function sqlite3_bind_value(_para1:Psqlite3_stmt; _para2:longint; _para3:Psqlite3_value):longint;cdecl; external Sqlite3Lib name 'sqlite3_bind_value'; + #These overloaded functions were introduced to allow the use of SQLITE_STATIC and SQLITE_TRANSIENT + #It's the c world man ;-) +proc bind_blob*(para1: PStmt, para2: int32, para3: pointer, n: int32, + para5: int32): int32{.cdecl, mylib, + importc: "sqlite3_bind_blob".} +proc bind_text*(para1: PStmt, para2: int32, para3: cstring, n: int32, + para5: int32): int32{.cdecl, mylib, + importc: "sqlite3_bind_text".} +proc bind_text16*(para1: PStmt, para2: int32, para3: pointer, para4: int32, + para5: int32): int32{.cdecl, mylib, + importc: "sqlite3_bind_text16".} +proc bind_parameter_count*(para1: PStmt): int32{.cdecl, mylib, + importc: "sqlite3_bind_parameter_count".} +proc bind_parameter_name*(para1: PStmt, para2: int32): cstring{.cdecl, + mylib, importc: "sqlite3_bind_parameter_name".} +proc bind_parameter_index*(para1: PStmt, zName: cstring): int32{.cdecl, + mylib, importc: "sqlite3_bind_parameter_index".} +proc clear_bindings*(para1: PStmt): int32 {.cdecl, + mylib, importc: "sqlite3_clear_bindings".} +proc column_count*(PStmt: PStmt): int32{.cdecl, mylib, + importc: "sqlite3_column_count".} +proc column_name*(para1: PStmt, para2: int32): cstring{.cdecl, mylib, + importc: "sqlite3_column_name".} +proc column_table_name*(para1: PStmt; para2: int32): cstring{.cdecl, mylib, + importc: "sqlite3_column_table_name".} +proc column_name16*(para1: PStmt, para2: int32): pointer{.cdecl, mylib, + importc: "sqlite3_column_name16".} +proc column_decltype*(para1: PStmt, i: int32): cstring{.cdecl, mylib, + importc: "sqlite3_column_decltype".} +proc column_decltype16*(para1: PStmt, para2: int32): pointer{.cdecl, + mylib, importc: "sqlite3_column_decltype16".} +proc step*(para1: PStmt): int32{.cdecl, mylib, importc: "sqlite3_step".} +proc data_count*(PStmt: PStmt): int32{.cdecl, mylib, + importc: "sqlite3_data_count".} +proc column_blob*(para1: PStmt, iCol: int32): pointer{.cdecl, mylib, + importc: "sqlite3_column_blob".} +proc column_bytes*(para1: PStmt, iCol: int32): int32{.cdecl, mylib, + importc: "sqlite3_column_bytes".} +proc column_bytes16*(para1: PStmt, iCol: int32): int32{.cdecl, mylib, + importc: "sqlite3_column_bytes16".} +proc column_double*(para1: PStmt, iCol: int32): float64{.cdecl, mylib, + importc: "sqlite3_column_double".} +proc column_int*(para1: PStmt, iCol: int32): int32{.cdecl, mylib, + importc: "sqlite3_column_int".} +proc column_int64*(para1: PStmt, iCol: int32): int64{.cdecl, mylib, + importc: "sqlite3_column_int64".} +proc column_text*(para1: PStmt, iCol: int32): cstring{.cdecl, mylib, + importc: "sqlite3_column_text".} +proc column_text16*(para1: PStmt, iCol: int32): pointer{.cdecl, mylib, + importc: "sqlite3_column_text16".} +proc column_type*(para1: PStmt, iCol: int32): int32{.cdecl, mylib, + importc: "sqlite3_column_type".} +proc finalize*(PStmt: PStmt): int32{.cdecl, mylib, + importc: "sqlite3_finalize".} +proc reset*(PStmt: PStmt): int32{.cdecl, mylib, importc: "sqlite3_reset".} +proc create_function*(para1: PSqlite3, zFunctionName: cstring, nArg: int32, + eTextRep: int32, para5: pointer, + xFunc: Create_function_func_func, + xStep: Create_function_step_func, + xFinal: Create_function_final_func): int32{.cdecl, + mylib, importc: "sqlite3_create_function".} +proc create_function16*(para1: PSqlite3, zFunctionName: pointer, nArg: int32, + eTextRep: int32, para5: pointer, + xFunc: Create_function_func_func, + xStep: Create_function_step_func, + xFinal: Create_function_final_func): int32{.cdecl, + mylib, importc: "sqlite3_create_function16".} +proc aggregate_count*(para1: Pcontext): int32{.cdecl, mylib, + importc: "sqlite3_aggregate_count".} +proc value_blob*(para1: PValue): pointer{.cdecl, mylib, + importc: "sqlite3_value_blob".} +proc value_bytes*(para1: PValue): int32{.cdecl, mylib, + importc: "sqlite3_value_bytes".} +proc value_bytes16*(para1: PValue): int32{.cdecl, mylib, + importc: "sqlite3_value_bytes16".} +proc value_double*(para1: PValue): float64{.cdecl, mylib, + importc: "sqlite3_value_double".} +proc value_int*(para1: PValue): int32{.cdecl, mylib, + importc: "sqlite3_value_int".} +proc value_int64*(para1: PValue): int64{.cdecl, mylib, + importc: "sqlite3_value_int64".} +proc value_text*(para1: PValue): cstring{.cdecl, mylib, + importc: "sqlite3_value_text".} +proc value_text16*(para1: PValue): pointer{.cdecl, mylib, + importc: "sqlite3_value_text16".} +proc value_text16le*(para1: PValue): pointer{.cdecl, mylib, + importc: "sqlite3_value_text16le".} +proc value_text16be*(para1: PValue): pointer{.cdecl, mylib, + importc: "sqlite3_value_text16be".} +proc value_type*(para1: PValue): int32{.cdecl, mylib, + importc: "sqlite3_value_type".} +proc aggregate_context*(para1: Pcontext, nBytes: int32): pointer{.cdecl, + mylib, importc: "sqlite3_aggregate_context".} +proc user_data*(para1: Pcontext): pointer{.cdecl, mylib, + importc: "sqlite3_user_data".} +proc get_auxdata*(para1: Pcontext, para2: int32): pointer{.cdecl, mylib, + importc: "sqlite3_get_auxdata".} +proc set_auxdata*(para1: Pcontext, para2: int32, para3: pointer, + para4: proc (para1: pointer){.cdecl.}){.cdecl, mylib, + importc: "sqlite3_set_auxdata".} +proc result_blob*(para1: Pcontext, para2: pointer, para3: int32, + para4: Result_func){.cdecl, mylib, + importc: "sqlite3_result_blob".} +proc result_double*(para1: Pcontext, para2: float64){.cdecl, mylib, + importc: "sqlite3_result_double".} +proc result_error*(para1: Pcontext, para2: cstring, para3: int32){.cdecl, + mylib, importc: "sqlite3_result_error".} +proc result_error16*(para1: Pcontext, para2: pointer, para3: int32){.cdecl, + mylib, importc: "sqlite3_result_error16".} +proc result_int*(para1: Pcontext, para2: int32){.cdecl, mylib, + importc: "sqlite3_result_int".} +proc result_int64*(para1: Pcontext, para2: int64){.cdecl, mylib, + importc: "sqlite3_result_int64".} +proc result_null*(para1: Pcontext){.cdecl, mylib, + importc: "sqlite3_result_null".} +proc result_text*(para1: Pcontext, para2: cstring, para3: int32, + para4: Result_func){.cdecl, mylib, + importc: "sqlite3_result_text".} +proc result_text16*(para1: Pcontext, para2: pointer, para3: int32, + para4: Result_func){.cdecl, mylib, + importc: "sqlite3_result_text16".} +proc result_text16le*(para1: Pcontext, para2: pointer, para3: int32, + para4: Result_func){.cdecl, mylib, + importc: "sqlite3_result_text16le".} +proc result_text16be*(para1: Pcontext, para2: pointer, para3: int32, + para4: Result_func){.cdecl, mylib, + importc: "sqlite3_result_text16be".} +proc result_value*(para1: Pcontext, para2: PValue){.cdecl, mylib, + importc: "sqlite3_result_value".} +proc create_collation*(para1: PSqlite3, zName: cstring, eTextRep: int32, + para4: pointer, xCompare: Create_collation_func): int32{. + cdecl, mylib, importc: "sqlite3_create_collation".} +proc create_collation16*(para1: PSqlite3, zName: cstring, eTextRep: int32, + para4: pointer, xCompare: Create_collation_func): int32{. + cdecl, mylib, importc: "sqlite3_create_collation16".} +proc collation_needed*(para1: PSqlite3, para2: pointer, para3: Collation_needed_func): int32{. + cdecl, mylib, importc: "sqlite3_collation_needed".} +proc collation_needed16*(para1: PSqlite3, para2: pointer, para3: Collation_needed_func): int32{. + cdecl, mylib, importc: "sqlite3_collation_needed16".} +proc libversion*(): cstring{.cdecl, mylib, importc: "sqlite3_libversion".} + #Alias for allowing better code portability (win32 is not working with external variables) +proc version*(): cstring{.cdecl, mylib, importc: "sqlite3_libversion".} + # Not published functions +proc libversion_number*(): int32{.cdecl, mylib, + importc: "sqlite3_libversion_number".} + +proc backup_init*(pDest: PSqlite3, zDestName: cstring, pSource: PSqlite3, zSourceName: cstring): PSqlite3_Backup {. + cdecl, mylib, importc: "sqlite3_backup_init".} + +proc backup_step*(pBackup: PSqlite3_Backup, nPage: int32): int32 {.cdecl, mylib, importc: "sqlite3_backup_step".} + +proc backup_finish*(pBackup: PSqlite3_Backup): int32 {.cdecl, mylib, importc: "sqlite3_backup_finish".} + +proc backup_pagecount*(pBackup: PSqlite3_Backup): int32 {.cdecl, mylib, importc: "sqlite3_backup_pagecount".} + +proc backup_remaining*(pBackup: PSqlite3_Backup): int32 {.cdecl, mylib, importc: "sqlite3_backup_remaining".} + +proc sqlite3_sleep*(t: int64): int64 {.cdecl, mylib, importc: "sqlite3_sleep".} + + #function sqlite3_key(db:Psqlite3; pKey:pointer; nKey:longint):longint;cdecl; external Sqlite3Lib name 'sqlite3_key'; + #function sqlite3_rekey(db:Psqlite3; pKey:pointer; nKey:longint):longint;cdecl; external Sqlite3Lib name 'sqlite3_rekey'; + #function sqlite3_sleep(_para1:longint):longint;cdecl; external Sqlite3Lib name 'sqlite3_sleep'; + #function sqlite3_expired(_para1:Psqlite3_stmt):longint;cdecl; external Sqlite3Lib name 'sqlite3_expired'; + #function sqlite3_global_recover:longint;cdecl; external Sqlite3Lib name 'sqlite3_global_recover'; +# implementation + +when defined(nimHasStyleChecks): + {.pop.} diff --git a/nim.nimble b/nim.nimble deleted file mode 100644 index 380ffbce8..000000000 --- a/nim.nimble +++ /dev/null @@ -1,15 +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" - -bin = @["compiler/nim", "nimsuggest/nimsuggest"] -skipFiles = @["azure-pipelines.yml" , "build_all.bat" , "build_all.sh" , "build_nimble.bat" , "build_nimble.sh" , "changelog.md" , "koch.nim.cfg" , "nimblemeta.json" , "readme.md" , "security.md" ] -skipDirs = @["build" , "changelogs" , "ci" , "csources_v2" , "drnim" , "nimdoc", "testament"] - -before install: - when defined(windows): - exec "build_all.bat" - else: - exec "./build_all.sh" diff --git a/nimdoc/extlinks/project/doc/manual.md b/nimdoc/extlinks/project/doc/manual.md deleted file mode 100644 index d44b5ca39..000000000 --- a/nimdoc/extlinks/project/doc/manual.md +++ /dev/null @@ -1,17 +0,0 @@ -=================== -Nothing User Manual -=================== - -.. importdoc:: ../main.nim, .. / sub / submodule.nim, ../../util.nim - -First section -============= - -Second *section* & -================== - -Ref. [``] or [submoduleInt] from [module nimdoc/extlinks/project/sub/submodule]. - -Ref. [proc mainfunction*(): int]. - -Ref. [utilfunction(x: int)]. diff --git a/nimdoc/extlinks/project/expected/_._/util.html b/nimdoc/extlinks/project/expected/_._/util.html deleted file mode 100644 index 9b9b29a4f..000000000 --- a/nimdoc/extlinks/project/expected/_._/util.html +++ /dev/null @@ -1,104 +0,0 @@ - - - - - - - -nimdoc/extlinks/util - - - - - - - - - - - - -
    -
    -

    nimdoc/extlinks/util

    -
    -
    -
    - - -
    - -
    - Search: -
    -
    - Group by: - -
    - - -
    -
    - -
    - -

    -
    -

    Procs

    -
    -
    -
    -
    proc utilfunction(x: int): int {....raises: [], tags: [], forbids: [].}
    -
    - - - -
    -
    - -
    - -
    -
    - -
    -
    - - -
    -
    - - - - - - diff --git a/nimdoc/extlinks/project/expected/_._/util.idx b/nimdoc/extlinks/project/expected/_._/util.idx deleted file mode 100644 index d83d8c97d..000000000 --- a/nimdoc/extlinks/project/expected/_._/util.idx +++ /dev/null @@ -1,2 +0,0 @@ -nimTitle util _._/util.html module nimdoc/extlinks/util 0 -nim utilfunction _._/util.html#utilfunction,int proc utilfunction(x: int): int 1 diff --git a/nimdoc/extlinks/project/expected/doc/manual.html b/nimdoc/extlinks/project/expected/doc/manual.html deleted file mode 100644 index 7b964f4ac..000000000 --- a/nimdoc/extlinks/project/expected/doc/manual.html +++ /dev/null @@ -1,44 +0,0 @@ - - - - - - - -Nothing User Manual - - - - - - - - - - - - -
    -
    -

    Nothing User Manual

    - -

    First section

    -

    Second section &

    Ref. submodule: `</a>` or submodule: submoduleInt from module nimdoc/extlinks/project/sub/submodule.

    -

    Ref. main: proc mainfunction*(): int.

    -

    Ref. util: utilfunction(x: int).

    - - - - -
    -
    - - - - - - diff --git a/nimdoc/extlinks/project/expected/doc/manual.idx b/nimdoc/extlinks/project/expected/doc/manual.idx deleted file mode 100644 index 158a758f0..000000000 --- a/nimdoc/extlinks/project/expected/doc/manual.idx +++ /dev/null @@ -1,3 +0,0 @@ -markupTitle Nothing User Manual doc/manual.html Nothing User Manual 0 -heading First section doc/manual.html#first-section First section 0 -heading Second section & doc/manual.html#second-section-amp Second section & 0 diff --git a/nimdoc/extlinks/project/expected/main.html b/nimdoc/extlinks/project/expected/main.html deleted file mode 100644 index cf7982fde..000000000 --- a/nimdoc/extlinks/project/expected/main.html +++ /dev/null @@ -1,142 +0,0 @@ - - - - - - - -nimdoc/extlinks/project/main - - - - - - - - - - - - -
    -
    -

    nimdoc/extlinks/project/main

    -
    -
    -
    - - -
    - -
    - Search: -
    -
    - Group by: - -
    - - -
    -
    - -
    - -

    -

    my heading

    See also module nimdoc/extlinks/util or nimdoc/extlinks/project/sub/submodule module.

    -

    Ref. submodule: `</a>` proc.

    -

    Ref. Nothing User Manual: First section or Nothing User Manual: Second section & from Nothing User Manual.

    -

    - -
    -

    Types

    -
    -
    -
    A = object
    -  
    -
    - - - -
    -
    - -
    -
    -
    -

    Procs

    -
    -
    -
    -
    proc mainfunction(): int {....raises: [], tags: [], forbids: [].}
    -
    - - - -
    -
    - -
    - -
    -
    - -
    -
    - - -
    -
    - - - - - - diff --git a/nimdoc/extlinks/project/expected/main.idx b/nimdoc/extlinks/project/expected/main.idx deleted file mode 100644 index d01f2e4c5..000000000 --- a/nimdoc/extlinks/project/expected/main.idx +++ /dev/null @@ -1,4 +0,0 @@ -nimTitle main main.html module nimdoc/extlinks/project/main 0 -nim A main.html#A object A 17 -nim mainfunction main.html#mainfunction proc mainfunction(): int 20 -heading my heading main.html#my-heading my heading 0 diff --git a/nimdoc/extlinks/project/expected/sub/submodule.html b/nimdoc/extlinks/project/expected/sub/submodule.html deleted file mode 100644 index 913138d6e..000000000 --- a/nimdoc/extlinks/project/expected/sub/submodule.html +++ /dev/null @@ -1,130 +0,0 @@ - - - - - - - -nimdoc/extlinks/project/sub/submodule - - - - - - - - - - - - -
    -
    -

    nimdoc/extlinks/project/sub/submodule

    -
    -
    -
    - - -
    - -
    - Search: -
    -
    - Group by: - -
    - - -
    -
    - -
    - -

    Ref. main: object A from module nimdoc/extlinks/project/main.

    -

    Ref. util: utilfunction(x: int).

    -

    Ref. Nothing User Manual: Second section & from Nothing User Manual.

    -

    -
    -

    Types

    -
    -
    -
    submoduleInt = distinct int
    -
    - - - -
    -
    - -
    -
    -
    -

    Procs

    -
    -
    -
    -
    proc `</a>`(x, y: int): bool {....raises: [], tags: [], forbids: [].}
    -
    - - Attempt to break HTML formatting. - -
    -
    - -
    - -
    -
    - -
    -
    - - -
    -
    - - - - - - diff --git a/nimdoc/extlinks/project/expected/sub/submodule.idx b/nimdoc/extlinks/project/expected/sub/submodule.idx deleted file mode 100644 index 2b02c889e..000000000 --- a/nimdoc/extlinks/project/expected/sub/submodule.idx +++ /dev/null @@ -1,3 +0,0 @@ -nimTitle submodule sub/submodule.html module nimdoc/extlinks/project/sub/submodule 0 -nim `` sub/submodule.html#,int,int proc ``(x, y: int): bool 9 -nim submoduleInt sub/submodule.html#submoduleInt type submoduleInt 13 diff --git a/nimdoc/extlinks/project/expected/theindex.html b/nimdoc/extlinks/project/expected/theindex.html deleted file mode 100644 index 9d2f6723c..000000000 --- a/nimdoc/extlinks/project/expected/theindex.html +++ /dev/null @@ -1,58 +0,0 @@ - - - - - - - -Index - - - - - - - - - - - - - - - - - - - diff --git a/nimdoc/extlinks/project/main.nim b/nimdoc/extlinks/project/main.nim deleted file mode 100644 index 36b778af6..000000000 --- a/nimdoc/extlinks/project/main.nim +++ /dev/null @@ -1,23 +0,0 @@ -## my heading -## ========== -## -## .. importdoc:: sub/submodule.nim, ../util.nim, doc/manual.md -## -## .. See also [Second&&&] and particularly [first section] and [Second section &]. -## -## See also [module nimdoc/extlinks/util] or [nimdoc/extlinks/project/sub/submodule module]. -## -## Ref. [`` proc]. -## -## Ref. [First section] or [Second section &] from [Nothing User Manual]. - - -import ../util, sub/submodule - -type A* = object - x: int - -proc mainfunction*(): int = - # just to suppress "not used" warnings: - if ``(1, 2): - result = utilfunction(0) diff --git a/nimdoc/extlinks/project/sub/submodule.nim b/nimdoc/extlinks/project/sub/submodule.nim deleted file mode 100644 index 876e00684..000000000 --- a/nimdoc/extlinks/project/sub/submodule.nim +++ /dev/null @@ -1,13 +0,0 @@ -## .. importdoc:: ../../util.nim, ../main.nim, ../doc/manual.md -## -## Ref. [object A] from [module nimdoc/extlinks/project/main]. -## -## Ref. [utilfunction(x: int)]. -## -## Ref. [Second section &] from [Nothing User Manual]. - -proc ``*(x, y: int): bool = - ## Attempt to break HTML formatting. - result = x < y - -type submoduleInt* = distinct int diff --git a/nimdoc/extlinks/util.nim b/nimdoc/extlinks/util.nim deleted file mode 100644 index f208f98c1..000000000 --- a/nimdoc/extlinks/util.nim +++ /dev/null @@ -1,2 +0,0 @@ -proc utilfunction*(x: int): int = - x + 42 diff --git a/nimdoc/rst2html/expected/rst_examples.html b/nimdoc/rst2html/expected/rst_examples.html deleted file mode 100644 index 72f6453f2..000000000 --- a/nimdoc/rst2html/expected/rst_examples.html +++ /dev/null @@ -1,273 +0,0 @@ - - - - - - - -Not a Nim Manual - - - - - - - - - - - - -
    -
    -

    Not a Nim Manual

    -
    - -
    - -
    - -

    - -
    Authors:Andreas Rumpf, Zahary Karadjov
    Version:|nimversion|

    "Complexity" seems to be a lot like "energy": you can transfer it from the end-user to one/some of the other players, but the total amount seems to remain pretty much constant for a given task. -- Ran

    - -

    About this document

    Note: This document is a draft! Several of Nim's features may need more precise wording. This manual is constantly evolving into a proper specification.

    -

    Note: The experimental features of Nim are covered here.

    -

    Note: Assignments, moves, and destruction are specified in the destructors document.

    -

    The language constructs are explained using an extended BNF, in which (a)* means 0 or more a's, a+ means 1 or more a's, and (a)? means an optional a. Parentheses may be used to group elements.

    -

    & is the lookahead operator; &a means that an a is expected but not consumed. It will be consumed in the following rule.

    -

    Non-terminals start with a lowercase letter, abstract terminal symbols are in UPPERCASE. Verbatim terminal symbols (including keywords) are quoted with '. An example:

    ifStmt = 'if' expr ':' stmts ('elif' expr ':' stmts)* ('else' stmts)?
    -

    -

    In a typical Nim program, most of the code is compiled into the executable. However, some of the code may be executed at compile-time. This can include constant expressions, macro definitions, and Nim procedures used by macro definitions. Most of the Nim language is supported at compile-time, but there are some restrictions -- see Restrictions on Compile-Time Execution for details. We use the term runtime to cover both compile-time execution and code execution in the executable.

    -
    var a: array[0..1, char]
    -let i = 5
    -try:
    -  a[i] = 'N'
    -except IndexDefect:
    -  echo "invalid index"
    -

    Encoding

    All Nim source files are in the UTF-8 encoding (or its ASCII subset). Other encodings are not supported. Any of the standard platform line termination sequences can be used - the Unix form using ASCII LF (linefeed), the Windows form using the ASCII sequence CR LF (return followed by linefeed), or the old Macintosh form using the ASCII CR (return) character. All of these forms can be used equally, regardless of the platform.

    - -

    Indentation

    Nim's standard grammar describes an indentation sensitive language. This means that all the control structures are recognized by indentation. Indentation consists only of spaces; tabulators are not allowed.

    -

    With this notation we can now easily define the core of the grammar: A block of statements (simplified example):

    ifStmt = 'if' expr ':' stmt
    -         (IND{=} 'elif' expr ':' stmt)*
    -         (IND{=} 'else' ':' stmt)?
    -
    -simpleStmt = ifStmt / ...
    -
    -stmt = IND{>} stmt ^+ IND{=} DED  # list of statements
    -     / simpleStmt                 # or a simple statement
    -

    -

    String literals can be delimited by matching double quotes, and can contain the following escape sequences:

    - - - - - - - - - - - - - - - - - -
    Escape sequenceMeaning
    \pplatform specific newline: CRLF on Windows, LF on Unix
    \r, \ccarriage return
    \n, \lline feed (often called newline)
    \fform feed
    \ttabulator
    \vvertical tabulator
    \\backslash
    \"quotation mark
    \'apostrophe
    \ '0'..'9'+character with decimal value d; all decimal digits directly following are used for the character
    \aalert
    \bbackspace
    \eescape [ESC]
    \x HHcharacter with hex value HH; exactly two hex digits are allowed
    \u HHHHunicode codepoint with hex value HHHH; exactly four hex digits are allowed
    \u {H+}unicode codepoint; all hex digits enclosed in {} are used for the codepoint
    """"long string within quotes""""

    Produces:

    "long string within quotes"
    -

    - -

    Operators

    Nim allows user defined operators. An operator is any combination of the following characters:

    =     +     -     *     /     <     >
    -@     $     ~     &     %     |
    -!     ?     ^     .     :     \
    -

    -

    (The grammar uses the terminal OPR to refer to operator symbols as defined here.)

    -

    The following strings denote other tokens:

    `   (    )     {    }     [    ]    ,  ;   [.    .]  {.   .}  (.  .)  [:
    -

    -

    Otherwise, precedence is determined by the first character.

    - - - - - - - - - - - - -
    Precedence levelOperatorsFirst characterTerminal symbol
    10 (highest)$ ^OP10
    9* / div mod shl shr %* % \ /OP9
    8+ -+ - ~ |OP8
    7&&OP7
    6...OP6
    5== <= < >= > != in notin is isnot not of as from= < > !OP5
    4andOP4
    3or xorOP3
    2@ : ?OP2
    1assignment operator (like +=, *=)OP1
    0 (lowest)arrow like operator (like ->, =>)OP0
    -

    Constants and Constant Expressions

    A constant is a symbol that is bound to the value of a constant expression. Constant expressions are restricted to depend only on the following categories of values and operations, because these are either built into the language or declared and evaluated before semantic analysis of the constant expression:

    -
    • literals
    • -
    • built-in operators
    • -
    • previously declared constants and compile-time variables
    • -
    • previously declared macros and templates
    • -
    • previously declared procedures that have no side effects beyond possibly modifying compile-time variables
    • -
    -

    These integer types are pre-defined:

    -
    int
    -
    the generic signed integer type; its size is platform-dependent and has the same size as a pointer. This type should be used in general. An integer literal that has no type suffix is of this type if it is in the range low(int32)..high(int32) otherwise the literal's type is int64.
    -
    intXX
    -
    additional signed integer types of XX bits use this naming scheme (example: int16 is a 16-bit wide integer). The current implementation supports int8, int16, int32, int64. Literals of these types have the suffix 'iXX.
    -
    uint
    -
    the generic unsigned integer type; its size is platform-dependent and has the same size as a pointer. An integer literal with the type suffix 'u is of this type.
    -
    -

    Let T's be p's return type. NRVO applies for T if sizeof(T) >= N (where N is implementation dependent), in other words, it applies for "big" structures.

    -

    Apart from built-in operations like array indexing, memory allocation, etc. the raise statement is the only way to raise an exception.

    -

    typedesc used as a parameter type also introduces an implicit generic. typedesc has its own set of rules:

    -

    The !=, >, >=, in, notin, isnot operators are in fact templates:

    -

    a > b is transformed into b < a.
    a in b is transformed into contains(b, a).
    notin and isnot have the obvious meanings.

    A template where every parameter is untyped is called an immediate template. For historical reasons templates can be explicitly annotated with an immediate pragma and then these templates do not take part in overloading resolution and the parameters' types are ignored by the compiler. Explicit immediate templates are now deprecated.

    - -

    Symbol lookup in generics

    -

    Open and Closed symbols

    The symbol binding rules in generics are slightly subtle: There are "open" and "closed" symbols. A "closed" symbol cannot be re-bound in the instantiation context, an "open" symbol can. Per default overloaded symbols are open and every other symbol is closed.

    -

    In templates identifiers can be constructed with the backticks notation:

    -
    template typedef(name: untyped, typ: typedesc) =
    -  type
    -    `T name`* {.inject.} = typ
    -    `P name`* {.inject.} = ref `T name`
    -
    -typedef(myint, int)
    -var x: PMyInt

    In the example name is instantiated with myint, so `T name` becomes Tmyint.

    -

    Only top-level symbols that are marked with an asterisk (*) are exported.

    -

    The algorithm for compiling modules is:

    -
    • compile the whole module as usual, following import statements recursively
    • -
    • if there is a cycle only import the already parsed symbols (that are exported); if an unknown identifier occurs then abort
    • -
    - -

    Collective imports from a directory

    The syntax import dir / [moduleA, moduleB] can be used to import multiple modules from the same directory.

    - -

    Pragmas

    Pragmas are Nim's method to give the compiler additional information / commands without introducing a massive number of new keywords. Pragmas are processed on the fly during semantic checking. Pragmas are enclosed in the special {. and .} curly brackets. Pragmas are also often used as a first implementation to play with a language feature before a nicer syntax to access the feature becomes available.

    - -

    deprecated pragma

    The deprecated pragma is used to mark a symbol as deprecated:

    -

    Note: c2nim can parse a large subset of C++ and knows about the importcpp pragma pattern language. It is not necessary to know all the details described here.

    -

    Pure libraries do not depend on any external *.dll or lib*.so binary while impure libraries do. A wrapper is an impure library that is a very low-level interface to a C library.

    - -

    Pure libraries

    -

    Automatic imports

    • system Basic procs and operators that every program needs. It also provides IO facilities for reading and writing text and binary files. It is imported implicitly by the compiler. Do not import it directly. It relies on compiler magic to work.
    • -
    • threads Basic Nim thread support. Note: This is part of the system module. Do not import it explicitly. Enabled with --threads:on.
    • -
    - -

    Code reordering

    The code reordering feature can implicitly rearrange procedure, template, and macro definitions along with variable declarations and initializations at the top level scope so that, to a large extent, a programmer should not have to worry about ordering definitions correctly or be forced to use forward declarations to preface definitions inside a module.

    -

    Example:

    -
    {.experimental: "codeReordering".}
    -
    -proc foo(x: int) =
    -  bar(x)
    -
    -proc bar(x: int) =
    -  echo(x)
    -
    -foo(10)

    It is important to note that reordering only works for symbols at top level scope. Therefore, the following will fail to compile:

    - -

    Parameter constraints

    The parameter constraint expression can use the operators | (or), & (and) and ~ (not) and the following predicates:

    - -

    The ~ operator

    The ~ operator is the not operator in patterns:

    - -

    The ** operator

    The ** is much like the * operator, except that it gathers not only all the arguments, but also the matched operators in reverse polish notation:

    -

    Nim significantly improves on the safety of these features via additional pragmas:

    -
    1. A guard annotation is introduced to prevent data races.
    2. -
    3. Every access of a guarded memory location needs to happen in an appropriate locks statement.
    4. -
    5. Locks and routines can be annotated with lock levels to allow potential deadlocks to be detected during semantic analysis.
    6. -
    -
    1. Two output parameters should never be aliased.
    2. -
    3. An input and an output parameter should not be aliased.
    4. -
    5. An output parameter should never be aliased with a global or thread local variable referenced by the called proc.
    6. -
    7. An input parameter should not be aliased with a global or thread local variable updated by the called proc.
    8. -
    -

    One problem with rules 3 and 4 is that they affect specific global or thread local variables, but Nim's effect tracking only tracks "uses no global variable" via .noSideEffect. The rules 3 and 4 can also be approximated by a different rule:

    -
    1. A global or thread local variable (or a location derived from such a location) can only passed to a parameter of a .noSideEffect proc.
    2. -
    -

    These two procs are the two modus operandi of the real-time garbage collector:

    -
    1. GC_SetMaxPause Mode

      -

      You can call GC_SetMaxPause at program startup and then each triggered garbage collector run tries to not take longer than maxPause time. However, it is possible (and common) that the work is nevertheless not evenly distributed as each call to new can trigger the garbage collector and thus take maxPause time.

      -
    2. -
    3. GC_step Mode

      -

      This allows the garbage collector to perform some work for up to us time. This is useful to call in the main loop to ensure the garbage collector can do its work. To bind all garbage collector activity to a GC_step call, deactivate the garbage collector with GC_disable at program startup. If strongAdvice is set to true, then the garbage collector will be forced to perform the collection cycle. Otherwise, the garbage collector may decide not to do anything, if there is not much garbage to collect. You may also specify the current stack size via stackSize parameter. It can improve performance when you know that there are no unique Nim references below a certain point on the stack. Make sure the size you specify is greater than the potential worst-case size.

      -

      It can improve performance when you know that there are no unique Nim references below a certain point on the stack. Make sure the size you specify is greater than the potential worst-case size.

      -
    4. -
    -

    These procs provide a "best effort" real-time guarantee; in particular the cycle collector is not aware of deadlines. Deactivate it to get more predictable real-time behaviour. Tests show that a 1ms max pause time will be met in almost all cases on modern CPUs (with the cycle collector disabled).

    - -

    Time measurement with garbage collectors

    The garbage collectors' way of measuring time uses (see lib/system/timers.nim for the implementation):

    -
    1. QueryPerformanceCounter and QueryPerformanceFrequency on Windows.
    2. -
    3. mach_absolute_time on Mac OS X.
    4. -
    5. gettimeofday on Posix systems.
    6. -
    -

    As such it supports a resolution of nanoseconds internally; however, the API uses microseconds for convenience.

    - -

    Introduction

    -"Der Mensch ist doch ein Augentier -- schöne Dinge wünsch ich mir." -

    This document is a tutorial for the programming language Nim. This tutorial assumes that you are familiar with basic programming concepts like variables, types, or statements but is kept very basic. The manual contains many more examples of the advanced language features. All code examples in this tutorial, as well as the ones found in the rest of Nim's documentation, follow the Nim style guide.

    -

    However, this does not work. The problem is that the procedure should not only return, but return and continue after an iteration has finished. This return and continue is called a yield statement. Now the only thing left to do is to replace the proc keyword by iterator and here it is - our first iterator:

    - - - - - -
    A1 headerA2 | not fooled
    C1C2 bold
    D1 code \|D2
    E1 | text
    F2 without pipe

    not in table

    -

    - -
    -
    - - -
    -
    - - - - - - diff --git a/nimdoc/rst2html/source/rst_examples.rst b/nimdoc/rst2html/source/rst_examples.rst deleted file mode 100644 index 7fa20de6c..000000000 --- a/nimdoc/rst2html/source/rst_examples.rst +++ /dev/null @@ -1,514 +0,0 @@ -================ -Not a Nim Manual -================ - -:Authors: Andreas Rumpf, Zahary Karadjov -:Version: |nimversion| - -.. role:: nim(code) - :language: nim -.. default-role:: nim - -.. contents:: - - - "Complexity" seems to be a lot like "energy": you can transfer it from the - end-user to one/some of the other players, but the total amount seems to remain - pretty much constant for a given task. -- Ran - - -About this document -=================== - -**Note**: This document is a draft! Several of Nim's features may need more -precise wording. This manual is constantly evolving into a proper specification. - -**Note**: The experimental features of Nim are -covered `here `_. - -**Note**: Assignments, moves, and destruction are specified in -the `destructors `_ document. - -The language constructs are explained using an extended BNF, in which ``(a)*`` -means 0 or more ``a``'s, ``a+`` means 1 or more ``a``'s, and ``(a)?`` means an -optional *a*. Parentheses may be used to group elements. - -``&`` is the lookahead operator; ``&a`` means that an ``a`` is expected but -not consumed. It will be consumed in the following rule. - -Non-terminals start with a lowercase letter, abstract terminal symbols are in -UPPERCASE. Verbatim terminal symbols (including keywords) are quoted -with ``'``. An example:: - - ifStmt = 'if' expr ':' stmts ('elif' expr ':' stmts)* ('else' stmts)? - -In a typical Nim program, most of the code is compiled into the executable. -However, some of the code may be executed at -`compile-time`:idx:. This can include constant expressions, macro definitions, -and Nim procedures used by macro definitions. Most of the Nim language is -supported at compile-time, but there are some restrictions -- see `Restrictions -on Compile-Time Execution <#restrictions-on-compileminustime-execution>`_ for -details. We use the term `runtime`:idx: to cover both compile-time execution -and code execution in the executable. - -.. code-block:: nim - var a: array[0..1, char] - let i = 5 - try: - a[i] = 'N' - except IndexDefect: - echo "invalid index" - -Encoding --------- - -All Nim source files are in the UTF-8 encoding (or its ASCII subset). Other -encodings are not supported. Any of the standard platform line termination -sequences can be used - the Unix form using ASCII LF (linefeed), the Windows -form using the ASCII sequence CR LF (return followed by linefeed), or the old -Macintosh form using the ASCII CR (return) character. All of these forms can be -used equally, regardless of the platform. - - -Indentation ------------ - -Nim's standard grammar describes an `indentation sensitive`:idx: language. -This means that all the control structures are recognized by indentation. -Indentation consists only of spaces; tabulators are not allowed. - -With this notation we can now easily define the core of the grammar: A block of -statements (simplified example):: - - ifStmt = 'if' expr ':' stmt - (IND{=} 'elif' expr ':' stmt)* - (IND{=} 'else' ':' stmt)? - - simpleStmt = ifStmt / ... - - stmt = IND{>} stmt ^+ IND{=} DED # list of statements - / simpleStmt # or a simple statement - - -String literals can be delimited by matching double quotes, and can -contain the following `escape sequences`:idx:\ : - -================== =================================================== - Escape sequence Meaning -================== =================================================== - ``\p`` platform specific newline: CRLF on Windows, - LF on Unix - ``\r``, ``\c`` `carriage return`:idx: - ``\n``, ``\l`` `line feed`:idx: (often called `newline`:idx:) - ``\f`` `form feed`:idx: - ``\t`` `tabulator`:idx: - ``\v`` `vertical tabulator`:idx: - ``\\`` `backslash`:idx: - ``\"`` `quotation mark`:idx: - ``\'`` `apostrophe`:idx: - ``\`` '0'..'9'+ `character with decimal value d`:idx:; - all decimal digits directly - following are used for the character - ``\a`` `alert`:idx: - ``\b`` `backspace`:idx: - ``\e`` `escape`:idx: `[ESC]`:idx: - ``\x`` HH `character with hex value HH`:idx:; - exactly two hex digits are allowed - ``\u`` HHHH `unicode codepoint with hex value HHHH`:idx:; - exactly four hex digits are allowed - ``\u`` {H+} `unicode codepoint`:idx:; - all hex digits enclosed in ``{}`` are used for - the codepoint -================== =================================================== - -.. code-block:: nim - """"long string within quotes"""" - -Produces:: - - "long string within quotes" - -Operators ---------- - -Nim allows user defined operators. An operator is any combination of the -following characters:: - - = + - * / < > - @ $ ~ & % | - ! ? ^ . : \ - -(The grammar uses the terminal OPR to refer to operator symbols as -defined here.) - -The following strings denote other tokens:: - - ` ( ) { } [ ] , ; [. .] {. .} (. .) [: - - -Otherwise, precedence is determined by the first character. - -================ ======================================================= ================== =============== -Precedence level Operators First character Terminal symbol -================ ======================================================= ================== =============== - 10 (highest) ``$ ^`` OP10 - 9 ``* / div mod shl shr %`` ``* % \ /`` OP9 - 8 ``+ -`` ``+ - ~ |`` OP8 - 7 ``&`` ``&`` OP7 - 6 ``..`` ``.`` OP6 - 5 ``== <= < >= > != in notin is isnot not of as from`` ``= < > !`` OP5 - 4 ``and`` OP4 - 3 ``or xor`` OP3 - 2 ``@ : ?`` OP2 - 1 *assignment operator* (like ``+=``, ``*=``) OP1 - 0 (lowest) *arrow like operator* (like ``->``, ``=>``) OP0 -================ ======================================================= ================== =============== - - -Constants and Constant Expressions -================================== - -A `constant`:idx: is a symbol that is bound to the value of a constant -expression. Constant expressions are restricted to depend only on the following -categories of values and operations, because these are either built into the -language or declared and evaluated before semantic analysis of the constant -expression: - -* literals -* built-in operators -* previously declared constants and compile-time variables -* previously declared macros and templates -* previously declared procedures that have no side effects beyond - possibly modifying compile-time variables - -These integer types are pre-defined: - -``int`` - the generic signed integer type; its size is platform-dependent and has the - same size as a pointer. This type should be used in general. An integer - literal that has no type suffix is of this type if it is in the range - ``low(int32)..high(int32)`` otherwise the literal's type is ``int64``. - -intXX - additional signed integer types of XX bits use this naming scheme - (example: int16 is a 16-bit wide integer). - The current implementation supports ``int8``, ``int16``, ``int32``, ``int64``. - Literals of these types have the suffix 'iXX. - -``uint`` - the generic `unsigned integer`:idx: type; its size is platform-dependent and has the same size as a pointer. An integer literal with the type suffix ``'u`` is of this type. - -Let ``T``'s be ``p``'s return type. NRVO applies for ``T`` -if ``sizeof(T) >= N`` (where ``N`` is implementation dependent), -in other words, it applies for "big" structures. - -Apart from built-in operations like array indexing, memory allocation, etc. -the ``raise`` statement is the only way to raise an exception. - -.. XXX document this better! - -`typedesc` used as a parameter type also introduces an implicit -generic. `typedesc` has its own set of rules: - -The ``!=``, ``>``, ``>=``, ``in``, ``notin``, ``isnot`` operators are in fact -templates: - -| ``a > b`` is transformed into ``b < a``. -| ``a in b`` is transformed into ``contains(b, a)``. -| ``notin`` and ``isnot`` have the obvious meanings. - -A template where every parameter is ``untyped`` is called an `immediate`:idx: -template. For historical reasons templates can be explicitly annotated with -an ``immediate`` pragma and then these templates do not take part in -overloading resolution and the parameters' types are *ignored* by the -compiler. Explicit immediate templates are now deprecated. - - - -Symbol lookup in generics -------------------------- - -Open and Closed symbols -~~~~~~~~~~~~~~~~~~~~~~~ - -The symbol binding rules in generics are slightly subtle: There are "open" and -"closed" symbols. A "closed" symbol cannot be re-bound in the instantiation -context, an "open" symbol can. Per default overloaded symbols are open -and every other symbol is closed. - -In templates identifiers can be constructed with the backticks notation: - -.. code-block:: nim - :test: "nim c $1" - - template typedef(name: untyped, typ: typedesc) = - type - `T name`* {.inject.} = typ - `P name`* {.inject.} = ref `T name` - - typedef(myint, int) - var x: PMyInt - -In the example ``name`` is instantiated with ``myint``, so \`T name\` becomes -``Tmyint``. - -Only top-level symbols that are marked with an asterisk (``*``) are -exported. - -The algorithm for compiling modules is: - -- compile the whole module as usual, following import statements recursively - -- if there is a cycle only import the already parsed symbols (that are - exported); if an unknown identifier occurs then abort - - -Collective imports from a directory -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The syntax ``import dir / [moduleA, moduleB]`` can be used to import multiple modules -from the same directory. - - -Pragmas -======= - -Pragmas are Nim's method to give the compiler additional information / -commands without introducing a massive number of new keywords. Pragmas are -processed on the fly during semantic checking. Pragmas are enclosed in the -special ``{.`` and ``.}`` curly brackets. Pragmas are also often used as a -first implementation to play with a language feature before a nicer syntax -to access the feature becomes available. - - -deprecated pragma ------------------ - -The deprecated pragma is used to mark a symbol as deprecated: - -**Note**: `c2nim `_ can parse a large subset of C++ and knows -about the ``importcpp`` pragma pattern language. It is not necessary -to know all the details described here. - - - -Pure libraries do not depend on any external ``*.dll`` or ``lib*.so`` binary -while impure libraries do. A wrapper is an impure library that is a very -low-level interface to a C library. - - -Pure libraries -============== - -Automatic imports ------------------ - -* `system `_ - Basic procs and operators that every program needs. It also provides IO - facilities for reading and writing text and binary files. It is imported - implicitly by the compiler. Do not import it directly. It relies on compiler - magic to work. - -* `threads `_ - Basic Nim thread support. **Note**: This is part of the system module. Do not - import it explicitly. Enabled with ``--threads:on``. - -Code reordering -=============== - -The code reordering feature can implicitly rearrange procedure, template, and -macro definitions along with variable declarations and initializations at the top -level scope so that, to a large extent, a programmer should not have to worry -about ordering definitions correctly or be forced to use forward declarations to -preface definitions inside a module. - -.. - NOTE: The following was documentation for the code reordering precursor, - which was {.noForward.}. - - In this mode, procedure definitions may appear out of order and the compiler - will postpone their semantic analysis and compilation until it actually needs - to generate code using the definitions. In this regard, this mode is similar - to the modus operandi of dynamic scripting languages, where the function - calls are not resolved until the code is executed. Here is the detailed - algorithm taken by the compiler: - - 1. When a callable symbol is first encountered, the compiler will only note - the symbol callable name and it will add it to the appropriate overload set - in the current scope. At this step, it won't try to resolve any of the type - expressions used in the signature of the symbol (so they can refer to other - not yet defined symbols). - - 2. When a top level call is encountered (usually at the very end of the - module), the compiler will try to determine the actual types of all of the - symbols in the matching overload set. This is a potentially recursive process - as the signatures of the symbols may include other call expressions, whose - types will be resolved at this point too. - - 3. Finally, after the best overload is picked, the compiler will start - compiling the body of the respective symbol. This in turn will lead the - compiler to discover more call expressions that need to be resolved and steps - 2 and 3 will be repeated as necessary. - - Please note that if a callable symbol is never used in this scenario, its - body will never be compiled. This is the default behavior leading to best - compilation times, but if exhaustive compilation of all definitions is - required, using ``nim check`` provides this option as well. - -Example: - -.. code-block:: nim - - {.experimental: "codeReordering".} - - proc foo(x: int) = - bar(x) - - proc bar(x: int) = - echo(x) - - foo(10) - - -.. - TODO: Let's table this for now. This is an *experimental feature* and so the - specific manner in which ``declared`` operates with it can be decided in - eventuality, because right now it works a bit weirdly. - - The values of expressions involving ``declared`` are decided *before* the - code reordering process, and not after. As an example, the output of this - code is the same as it would be with code reordering disabled. - - .. code-block:: nim - {.experimental: "codeReordering".} - - proc x() = - echo(declared(foo)) - - var foo = 4 - - x() # "false" - -It is important to note that reordering *only* works for symbols at top level -scope. Therefore, the following will *fail to compile:* - - -Parameter constraints ---------------------- - -The `parameter constraint`:idx: expression can use the operators ``|`` (or), -``&`` (and) and ``~`` (not) and the following predicates: - - -The ``~`` operator -~~~~~~~~~~~~~~~~~~ - -The ``~`` operator is the **not** operator in patterns: - - -The ``**`` operator -~~~~~~~~~~~~~~~~~~~ - -The ``**`` is much like the ``*`` operator, except that it gathers not only -all the arguments, but also the matched operators in reverse polish notation: - -Nim significantly improves on the safety of these features via additional -pragmas: - -1) A `guard`:idx: annotation is introduced to prevent data races. -2) Every access of a guarded memory location needs to happen in an - appropriate `locks`:idx: statement. -3) Locks and routines can be annotated with `lock levels`:idx: to allow - potential deadlocks to be detected during semantic analysis. - -1. Two output parameters should never be aliased. -2. An input and an output parameter should not be aliased. -3. An output parameter should never be aliased with a global or thread local - variable referenced by the called proc. -4. An input parameter should not be aliased with a global or thread local - variable updated by the called proc. - -One problem with rules 3 and 4 is that they affect specific global or thread -local variables, but Nim's effect tracking only tracks "uses no global variable" -via ``.noSideEffect``. The rules 3 and 4 can also be approximated by a different rule: - -5. A global or thread local variable (or a location derived from such a location) - can only passed to a parameter of a ``.noSideEffect`` proc. - -These two procs are the two modus operandi of the real-time garbage collector: - -(1) GC_SetMaxPause Mode - - You can call ``GC_SetMaxPause`` at program startup and then each triggered - garbage collector run tries to not take longer than ``maxPause`` time. However, it is - possible (and common) that the work is nevertheless not evenly distributed - as each call to ``new`` can trigger the garbage collector and thus take ``maxPause`` - time. - -(2) GC_step Mode - - This allows the garbage collector to perform some work for up to ``us`` time. - This is useful to call in the main loop to ensure the garbage collector can do its work. - To bind all garbage collector activity to a ``GC_step`` call, - deactivate the garbage collector with ``GC_disable`` at program startup. - If ``strongAdvice`` is set to ``true``, - then the garbage collector will be forced to perform the collection cycle. - Otherwise, the garbage collector may decide not to do anything, - if there is not much garbage to collect. - You may also specify the current stack size via ``stackSize`` parameter. - It can improve performance when you know that there are no unique Nim references - below a certain point on the stack. Make sure the size you specify is greater - than the potential worst-case size. - - It can improve performance when you know that there are no unique Nim - references below a certain point on the stack. Make sure the size you specify - is greater than the potential worst-case size. - -These procs provide a "best effort" real-time guarantee; in particular the -cycle collector is not aware of deadlines. Deactivate it to get more -predictable real-time behaviour. Tests show that a 1ms max pause -time will be met in almost all cases on modern CPUs (with the cycle collector -disabled). - -Time measurement with garbage collectors ----------------------------------------- - -The garbage collectors' way of measuring time uses -(see ``lib/system/timers.nim`` for the implementation): - -1) ``QueryPerformanceCounter`` and ``QueryPerformanceFrequency`` on Windows. -2) ``mach_absolute_time`` on Mac OS X. -3) ``gettimeofday`` on Posix systems. - -As such it supports a resolution of nanoseconds internally; however, the API -uses microseconds for convenience. - -Introduction -============ - -.. raw:: html -

    - "Der Mensch ist doch ein Augentier -- schöne Dinge wünsch ich mir." -

    - - -This document is a tutorial for the programming language *Nim*. -This tutorial assumes that you are familiar with basic programming concepts -like variables, types, or statements but is kept very basic. The `manual -`_ contains many more examples of the advanced language features. -All code examples in this tutorial, as well as the ones found in the rest of -Nim's documentation, follow the `Nim style guide `_. - -However, this does not work. The problem is that the procedure should not -only ``return``, but return and **continue** after an iteration has -finished. This *return and continue* is called a `yield` statement. Now -the only thing left to do is to replace the ``proc`` keyword by ``iterator`` -and here it is - our first iterator: - -| A1 header | A2 \| not fooled -| :--- | ----: | -| C1 | C2 **bold** | ignored | -| D1 `code \|` | D2 | also ignored -| E1 \| text | -| | F2 without pipe -not in table diff --git a/nimdoc/rsttester.nim b/nimdoc/rsttester.nim deleted file mode 100644 index a0bdfca1e..000000000 --- a/nimdoc/rsttester.nim +++ /dev/null @@ -1,40 +0,0 @@ -# To run this, cd to the git repo root, and run "nim r nimdoc/rsttester.nim". -# to change expected results (after carefully verifying everything), use -d:nimTestsNimdocFixup - -import os, strutils -from std/private/gitutils import diffFiles - -const - baseDir = "nimdoc/rst2html" - -const fixup = defined(nimTestsNimdocFixup) - -var failures = 0 - -proc exec(cmd: string) = - if execShellCmd(cmd) != 0: - quit("FAILURE: " & cmd) - -proc testRst2Html(fixup = false) = - putEnv("SOURCE_DATE_EPOCH", "100000") - const nimExe = getCurrentCompilerExe() # so that `bin/nim_temp r nimdoc/tester.nim` works - - for expectedHtml in walkDir(baseDir / "expected"): - let expectedHtml = expectedHtml.path - let sourceFile = expectedHtml.replace('\\', '/').replace("/expected/", "/source/").replace(".html", ".rst") - exec("$1 rst2html $2" % [nimExe, sourceFile]) - let producedHtml = expectedHtml.replace('\\', '/').replace("/expected/", "/source/htmldocs/") - if readFile(expectedHtml) != readFile(producedHtml): - echo diffFiles(expectedHtml, producedHtml).output - inc failures - if fixup: - copyFile(producedHtml, expectedHtml) - else: - echo "SUCCESS: files identical: ", producedHtml - if failures == 0: - removeDir(baseDir / "source/htmldocs") - -testRst2Html(fixup) - -# Check for failures -if failures > 0: quit($failures & " failures occurred.") diff --git a/nimdoc/test_doctype/expected/test_doctype.html b/nimdoc/test_doctype/expected/test_doctype.html deleted file mode 100644 index 01ad6e5a0..000000000 --- a/nimdoc/test_doctype/expected/test_doctype.html +++ /dev/null @@ -1,82 +0,0 @@ - - - - - - - -nimdoc/test_doctype/test_doctype - - - - - - - - - - - - -
    -
    -

    nimdoc/test_doctype/test_doctype

    -
    -
    -
    - - -
    - -
    - Search: -
    -
    - Group by: - -
    - - -
    -
    - -
    - -

    Check

    -

    -text

    - -

    Check

    -

    text

    - -
    -
    - - -
    -
    - - - - - - diff --git a/nimdoc/test_doctype/test_doctype.nim b/nimdoc/test_doctype/test_doctype.nim deleted file mode 100644 index 28d35fc1e..000000000 --- a/nimdoc/test_doctype/test_doctype.nim +++ /dev/null @@ -1,15 +0,0 @@ -# Markdown (default) interpretes this as text + a Markdown code block: - -## Check -## ~~~~~ -## text -## ~~~~~ - -{.doctype: RST.} - -# Now RST interpretes this as 2 headings: - -## Check -## ~~~~~ -## text -## ~~~~~ diff --git a/nimdoc/test_out_index_dot_html/expected/foo.idx b/nimdoc/test_out_index_dot_html/expected/foo.idx index ac76aa532..a8dabb67e 100644 --- a/nimdoc/test_out_index_dot_html/expected/foo.idx +++ b/nimdoc/test_out_index_dot_html/expected/foo.idx @@ -1,2 +1 @@ -nimTitle foo index.html module nimdoc/test_out_index_dot_html/foo 0 -nim foo index.html#foo proc foo() 1 +foo index.html#foo foo: foo() diff --git a/nimdoc/test_out_index_dot_html/expected/index.html b/nimdoc/test_out_index_dot_html/expected/index.html index 22d5daa35..f47c5f89c 100644 --- a/nimdoc/test_out_index_dot_html/expected/index.html +++ b/nimdoc/test_out_index_dot_html/expected/index.html @@ -1,104 +1,143 @@ - + - + + -nimdoc/test_out_index_dot_html/foo + + + + +foo - + + + - -
    -
    -

    nimdoc/test_out_index_dot_html/foo

    -
    + +
    +
    +

    foo

    +
    -
    - - -
    - -
    - Search: -
    -
    - Group by: - -
    -
      -
    • -
      - Procs -
        - - +
        + +     Dark Mode +
        +
      +
    +
    + Search: +
    +
    + Group by: + +
    +
    - -
    - -

    -
    -

    Procs

    -
    -
    -
    -
    proc foo() {....raises: [], tags: [], forbids: [].}
    -
    - - I do foo - -
    -
    +
    + +

    +
    +

    Procs

    +
    + +
    proc foo() {...}{.raises: [], tags: [].}
    +
    -
    +I do foo -
    -
    + + +
    +
    - - - - +
    + diff --git a/nimdoc/test_out_index_dot_html/expected/theindex.html b/nimdoc/test_out_index_dot_html/expected/theindex.html index ea3486d4b..095dd7471 100644 --- a/nimdoc/test_out_index_dot_html/expected/theindex.html +++ b/nimdoc/test_out_index_dot_html/expected/theindex.html @@ -1,42 +1,92 @@ - + - + + -Index + + + + +Index - + + + - -
    -
    -

    Index

    - Modules: index.

    API symbols

    + +
    +
    +

    Index

    + Modules: index.

    API symbols

    foo:
    • foo: proc foo()
    • + data-doc-search-tag="foo: foo()" href="index.html#foo">foo: foo()
    +
    - - - - +
    + diff --git a/nimdoc/tester.nim b/nimdoc/tester.nim index e94caae7c..a1500455e 100644 --- a/nimdoc/tester.nim +++ b/nimdoc/tester.nim @@ -1,27 +1,18 @@ # Small program that runs the test cases for 'nim doc'. -# To run this, cd to the git repo root, and run "nim r nimdoc/tester.nim". -# to change expected results (after carefully verifying everything), use -d:nimTestsNimdocFixup +# To run this, cd to the git repo root, and run "nim c -r nimdoc/tester.nim". import strutils, os -from std/private/gitutils import diffFiles - -const fixup = defined(nimTestsNimdocFixup) var failures = 0 const baseDir = "nimdoc" -let - baseDirAbs = getCurrentDir() / baseDir type NimSwitches = object doc: seq[string] - docStage2: seq[string] buildIndex: seq[string] - md2html: seq[string] - md2htmlStage2: seq[string] proc exec(cmd: string) = if execShellCmd(cmd) != 0: @@ -30,42 +21,24 @@ proc exec(cmd: string) = proc testNimDoc(prjDir, docsDir: string; switches: NimSwitches; fixup = false) = let nimDocSwitches = switches.doc.join(" ") - nimDocStage2Switches = switches.docStage2.join(" ") - nimMd2HtmlSwitches = switches.md2html.join(" ") - nimMd2HtmlStage2Switches = switches.md2htmlStage2.join(" ") nimBuildIndexSwitches = switches.buildIndex.join(" ") putEnv("SOURCE_DATE_EPOCH", "100000") - const nimExe = getCurrentCompilerExe() # so that `bin/nim_temp r nimdoc/tester.nim` works if nimDocSwitches != "": - exec("$1 doc $2" % [nimExe, nimDocSwitches]) - echo("$1 doc $2" % [nimExe, nimDocSwitches]) - - if nimMd2HtmlSwitches != "": - exec("$1 md2html $2" % [nimExe, nimMd2HtmlSwitches]) - echo("$1 md2html $2" % [nimExe, nimMd2HtmlSwitches]) - - if nimDocStage2Switches != "": - exec("$1 doc $2" % [nimExe, nimDocStage2Switches]) - echo("$1 doc $2" % [nimExe, nimDocStage2Switches]) - - if nimMd2HtmlStage2Switches != "": - exec("$1 md2html $2" % [nimExe, nimMd2HtmlStage2Switches]) - echo("$1 md2html $2" % [nimExe, nimMd2HtmlStage2Switches]) + exec("nim doc $1" % [nimDocSwitches]) if nimBuildIndexSwitches != "": - exec("$1 buildIndex $2" % [nimExe, nimBuildIndexSwitches]) - echo("$1 buildIndex $2" % [nimExe, nimBuildIndexSwitches]) + exec("nim buildIndex $1" % [nimBuildIndexSwitches]) - for expected in walkDirRec(prjDir / "expected/", checkDir=true): + for expected in walkDirRec(prjDir / "expected/"): let produced = expected.replace('\\', '/').replace("/expected/", "/$1/" % [docsDir]) if not fileExists(produced): echo "FAILURE: files not found: ", produced inc failures elif readFile(expected) != readFile(produced): echo "FAILURE: files differ: ", produced - echo diffFiles(expected, produced).output + discard execShellCmd("diff -uNdr " & expected & " " & produced) inc failures if fixup: copyFile(produced, expected) @@ -86,7 +59,7 @@ let "$1/$2.nim" % [test1Dir, test1PrjName]], buildIndex: @["--out:$1/$2/theindex.html" % [test1Dir, test1DocsDir], "$1/$2" % [test1Dir, test1DocsDir]]) -testNimDoc(test1Dir, test1DocsDir, test1Switches, fixup) +testNimDoc(test1Dir, test1DocsDir, test1Switches, defined(fixup)) # Test "nim doc --out:.. --index:on .." let @@ -99,57 +72,7 @@ let "$1/$2.nim" % [test2Dir, test2PrjName]], buildIndex: @["--out:$1/$2/theindex.html" % [test2Dir, test2DocsDir], "$1/$2" % [test2Dir, test2DocsDir]]) -testNimDoc(test2Dir, test2DocsDir, test2Switches, fixup) +testNimDoc(test2Dir, test2DocsDir, test2Switches, defined(fixup)) -# Test `nim doc` on file with `{.doctype.}` pragma -let - test3PrjDir = "test_doctype" - test3PrjName = "test_doctype" - test3Dir = baseDir / test3PrjDir - test3DocsDir = "htmldocs" - test3Switches = NimSwitches(doc: @["$1/$2.nim" % [test3Dir, test3PrjName]]) -testNimDoc(test3Dir, test3DocsDir, test3Switches, fixup) - - -# Test concise external links (RFC#125) that work with `.idx` files. -# extlinks -# ├── project -# │   ├── main.nim -# │   ├── manual.md -# │   └── sub -# │   └── submodule.nim -# └── util.nim -# -# `main.nim` imports `submodule.nim` and `../utils.nim`. -# `main.nim`, `submodule.nim`, `manual.md` do importdoc and reference each other. -let - test4PrjName = "extlinks/project" - test4Dir = baseDir / test4PrjName - test4DirAbs = baseDirAbs / test4PrjName - test4MainModule = "main" - test4MarkupDoc = "doc" / "manual.md" - test4DocsDir = "htmldocs" - # 1st stage is with --index:only, 2nd is final - test4Switches = NimSwitches( - doc: @["--project", - "--outdir:$1/$2" % [test4Dir, test4DocsDir], - "--index:only", - "$1/$2.nim" % [test4Dir, test4MainModule]], - md2html: - @["--outdir:$1/$2" % [test4Dir, test4DocsDir], - "--docroot:$1" % [test4DirAbs], - "--index:only", - "$1/$2" % [test4Dir, test4MarkupDoc]], - docStage2: - @["--project", - "--outdir:$1/$2" % [test4Dir, test4DocsDir], - "$1/$2.nim" % [test4Dir, test4MainModule]], - md2htmlStage2: - @["--outdir:$1/$2" % [test4Dir, test4DocsDir], - "--docroot:$1" % [test4DirAbs], - "$1/$2" % [test4Dir, test4MarkupDoc]], - ) -testNimDoc(test4Dir, test4DocsDir, test4Switches, fixup) - -if failures > 0: - quit "$# failures occurred; see note in nimdoc/tester.nim regarding -d:nimTestsNimdocFixup" % $failures +# Check for failures +if failures > 0: quit($failures & " failures occurred.") diff --git a/nimdoc/testproject/expected/nimdoc.out.css b/nimdoc/testproject/expected/nimdoc.out.css deleted file mode 100644 index 1417d9eff..000000000 --- a/nimdoc/testproject/expected/nimdoc.out.css +++ /dev/null @@ -1,1026 +0,0 @@ -/* -Stylesheet for use with Docutils/rst2html. - -See http://docutils.sf.net/docs/howto/html-stylesheets.html for how to -customize this style sheet. - -Modified from Chad Skeeters' rst2html-style -https://bitbucket.org/cskeeters/rst2html-style/ - -Modified by Boyd Greenfield and narimiran -*/ - -:root { - --primary-background: #fff; - --secondary-background: ghostwhite; - --third-background: #e8e8e8; - --info-background: #50c050; - --warning-background: #c0a000; - --error-background: #e04040; - --border: #dde; - --text: #222; - --anchor: #07b; - --anchor-focus: #607c9f; - --input-focus: #1fa0eb; - --strong: #3c3c3c; - --hint: #9A9A9A; - --nim-sprite-base64: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAN4AAAA9CAYAAADCt9ebAAAACXBIWXMAAAsTAAALEwEAmpwYAAAFFmlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgNS42LWMxNDggNzkuMTY0MDM2LCAyMDE5LzA4LzEzLTAxOjA2OjU3ICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgeG1sbnM6cGhvdG9zaG9wPSJodHRwOi8vbnMuYWRvYmUuY29tL3Bob3Rvc2hvcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgMjEuMCAoV2luZG93cykiIHhtcDpDcmVhdGVEYXRlPSIyMDE5LTEyLTAzVDAxOjAzOjQ4KzAxOjAwIiB4bXA6TW9kaWZ5RGF0ZT0iMjAxOS0xMi0wM1QwMjoyODo0MSswMTowMCIgeG1wOk1ldGFkYXRhRGF0ZT0iMjAxOS0xMi0wM1QwMjoyODo0MSswMTowMCIgZGM6Zm9ybWF0PSJpbWFnZS9wbmciIHBob3Rvc2hvcDpDb2xvck1vZGU9IjMiIHBob3Rvc2hvcDpJQ0NQcm9maWxlPSJzUkdCIElFQzYxOTY2LTIuMSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDozMzM0ZjAxYS0yMDExLWE1NGQtOTVjNy1iOTgxMDFlMDFhMmEiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6MzMzNGYwMWEtMjAxMS1hNTRkLTk1YzctYjk4MTAxZTAxYTJhIiB4bXBNTTpPcmlnaW5hbERvY3VtZW50SUQ9InhtcC5kaWQ6MzMzNGYwMWEtMjAxMS1hNTRkLTk1YzctYjk4MTAxZTAxYTJhIj4gPHhtcE1NOkhpc3Rvcnk+IDxyZGY6U2VxPiA8cmRmOmxpIHN0RXZ0OmFjdGlvbj0iY3JlYXRlZCIgc3RFdnQ6aW5zdGFuY2VJRD0ieG1wLmlpZDozMzM0ZjAxYS0yMDExLWE1NGQtOTVjNy1iOTgxMDFlMDFhMmEiIHN0RXZ0OndoZW49IjIwMTktMTItMDNUMDE6MDM6NDgrMDE6MDAiIHN0RXZ0OnNvZnR3YXJlQWdlbnQ9IkFkb2JlIFBob3Rvc2hvcCAyMS4wIChXaW5kb3dzKSIvPiA8L3JkZjpTZXE+IDwveG1wTU06SGlzdG9yeT4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz4PsixkAAAJ5klEQVR4nO2dfbBUZR3HP3vvxVD0zo0ACXxBuQMoQjJ1DfMl0NIhNcuSZqQhfGt6UWtK06xJexkrmywVRTQlHCIdtclC0zBJvYIvvEUgZpc3XyC7RVbKlQu1/fHdbc+uu2fPOfs85+y55/nMnBl2z+5zfnc5v/M8z+8119XVRYroAG4HfgvMT1YUR4MMAa4HLkhakCRoSVqAELwLeBY4C7gF+D6QS1QiR1ROAJ4Dzk9akKQwoXhtwL4GxvHjU8AKoNPz3leAu4HBFq+bAyZZHD9rDAK+BywDDklYlkQxoXhfAtYAEw2MVckQYBHwU6or99nA08BBFq49GngUeBIYaWH8rNEJdAOXA60Jy5I4jSreSOBKYDzwBPCJhiUqcSjwe2BWnc9NLnxuvMFrnwqsAqYBBwBfNzh2FpmNfs9jkhakWcg1aFxZiH5UL3cDnwf+Xue7BwFjgFHAOwuv24tyob3cO0LIshP4EbCn8Pq/wKvA9sLxMvCvOmPsA1yDZnHv/nEv2mM+F0IeR4m8z7lM7tMbUbzj0CxX7YfbAXwaWFJ4PRrNIu9FS9KJyEIZN68CG4DnkRJtLBw7gHHAYuDdNb77EDAjBhkHIk7xKoiqeK3IwjilzuceQJvoZjdQ/AMZaeoZiWYgBXSEwyleBW0Rv3cR9ZUO4LSI48fN2wN+bi5wJNBvUZaBSCaVy48oxpVhwDdMC5ISxpJRh6/DLGEUrxXt29YBQ+2IkwquR76ofZIWxJFegireNLSnm48skFmmDfmiVgJHJyuKI620ADOpbWEcDPwYOZKD7OmyxCTkXL+wzueOiEEWR8poQb60V4A7kLm/yFjgKeALuM1xLfYDbkX+zEGe98cAX0Oui6viF8vR7OS6urragW2UZr21wK+Aiwlu7XPoN3sYOAd4H6WH1SnA0qSEcjQnRT/e1bgnsw16kGPez4/lyCBF48oNwL+TFGSAsgCndI4qFBVvJ0owdZhjL3CnxfHzBo8+YBMyol0CHBijrKbHS/LoA7Yio9sPgJNr/QHekLGR6MffL+KP4SjnHmQxtoXNmbQP+CHyV75hYDzTIWNpWkU8iR5mq71vVsZqXgtcFqNQ/wG2IOtfD8oi6AX+Ujj+isKz8sBrnu+1okyGdmD/wnEgcDClTIdRyJRvI1cvCMciq7At4rj5eoCPAusbHCfLigda/VyKgi+AtyreMGAzykGzQQ/wO+BxSlkCuy1dq8hw5OieUjimYT+x9bHCdWwS1823Ez1EXmhgjKwrXpHzkduuanbCtzGX+NkPPAj8GincNkPjNkIO5dadUjiOB95m+BonopQpm8R58/0JJbHWy2eshVM8sRvdbyurKV4Hmoka2WA/iwwLP6d+QmzSdKC92GzK/W9R+Q3woQbHCELcN991wJcjftcpXolngKm18vFmoVonYcgDv0Qz5pqGREuOTuA8lPYUZbndh0LJNpkUqgZx33xvomim7RG+6xSvnOm1gqQXoyiMoKxFs8VZpFfpQHvQK4HDUPnAsBa9bxGP0tUjF+IYCkxFew+/G3owdq20pgjzt3uPRscs/o43IaOhH2f4ZaAPRyZQP6vgbuCbyGext87F0sgIZFI/N8BnlwBnolovcWAjq/uzwM0+55cBJ0UYN84ZL+rfbnLMM4FfUDv7Z1XlCe8FetETbleNL7+CZrnvMjCVDuTOOA84Hf+96ga0PC8qXY50FQsuMg+41+d8p885R4n7gdt8zo+qvDkmUF4fZQXwEbS+99KDMhlWkw0eALqQglXyDDCdcovf+4lv5jPNXJ9zWc/FDMMdPudGVCreRlTWwVtWbynwYVQQCFSp61Q042WJLUjB1nneuw8tvXo97x1Lugvg+j1Mo9boySLVHtJFWqsthx5GlbSGeN5bigrHdqPl52Zj4qWLXvTQWY4KOX2ccgPMBLRcuy9+0YzhguXN4GuYq2Zc2R/NZg+hfYt3/9ZCepdQthmB4vIWIYOTbWyWzGt2Y0izG1fqjlltxnsdpbPMRMmd3lqTTumqMw7FZY5G5mSHw5dalreiRWYGWjbZ7gYUlFa0xOtIWA4vk1E6zWEoI+FvyYrjSAO1FG8DCmQGKd+DJFsGogWVVFiP/GWbga9Svg9NgtPQvnd04fUNCcriSBF+vqZ5nn9PQ+Xs4q401oI6EP0R+BkyXoAeAtcgBfwidnvkVaMVFTO6n1JoWTfqiONw1MVP8e6l3GVwOPJZXW5VItGGiuduAu5CZdOrMQJ1CHqpIFccS+LxaD/3Hcr7vF0Xw7UdAwQ/xduLGkJ6aUMhVAuwU006B3wM+ZLmozJ5QRhWkGs9yjKw1fhwDsq8eE/F+y+i1CeHIxD1wppupXrA5xyUOjQHMzU3cyjTeS2aaaN2Fzoc1bhch3xspuqBTkDulQVUz1q4mYEbNuewQD3FexGFS1VjOLoRHwOOinj9HAooXY2CSidHHKeSI5GFcRWNdSxqR7VH1iHHeTV24R+X53C8hSCBvPPqnD8B+AOygn6OYAm0ORSGthLl8B0d4DtRmIKsoMsJF1U/Hi1dt6DusIN8PrsIlUdwOAITpDFlC6q3MTbgmHm011qGepOvQSXPipyOCujW6rxqk0dRWYsVFe8PRSn5JxWOoEvdfOGzfnF5tnCRK+bGi33MoB1hL0U5d1H5J5oVD6A5mp8sQS6KSWh5e0jEcR4BPmhKqJA4xTM3XuxjBlW8DuRacDU3y0myNbNTPHPjxT5m0GTN15A/zVFiI+HKYzgc/ydMlrRfgmQWuYn0F91xJEQYxVuDnMcOrQAWJi2EI72ErQviwqLEQpQ+5XBEIqzi3YWLwF+BMiMcjshEqYR1Gdk1KmxBsaR9SQviSDdRFK8fxVU+YliWZmcbcq7vSFoQR/qJWvuxD0WgLDYoSzPzAqowtjVhORwDhEaKru4GPoliGgcyy4Hj0DLT4TBCo9WO88jQ8Bns97lLghvRTOfqqDiMYqrM+HyUYdBtaLykeRmlK12C9rQOh1FM1vd/HqUIzaT5e+LVoh/VxByHShs6HFaw0VjjHhTxP5d0LT+fRnu5q3HuAodlbHW02Q5cDByM+sw1642cRylCx6PeZiuTFScUFxK+f19QovaRS+t4tsasxhvABbZbSfUCV6CM7qtQl6Fm4E1U22UqcAYqvZ42fgJMxH6vdYc5nkBlSW6Pq4fbS6hb6jg0u9yGug7FyS5U1+UcVBbwbFSuMM1sQ1bXK4A9CcviqM0e9H80HdUxCpwIa4McygA/GfgAcCJqmGKKXUixupEv7nHsLc2agWNQ0d9OzC+PHNHIo1XeLCoe8kkqXiUtwKFoWXoEKqk3BpWLaC8cXsV8HT1J+tFTZKvn+DMqFZi1knvtyKg1O2lBHADcCVxEedNSAP4HJcsr0NNWHVUAAAAASUVORK5CYII="); - - --keyword: #5e8f60; - --identifier: #222; - --comment: #484a86; - --operator: #155da4; - --punctuation: black; - --other: black; - --escapeSequence: #c4891b; - --number: #252dbe; - --literal: #a4255b; - --program: #6060c0; - --option: #508000; - --raw-data: #a4255b; - - --clipboard-image-normal: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' style='color: black' fill='none' viewBox='0 0 24 24' stroke='currentColor'%3E %3Cpath stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2' /%3E %3C/svg%3E"); - --clipboard-image-selected: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' style='color: black' viewBox='0 0 20 20' fill='currentColor'%3E %3Cpath d='M8 3a1 1 0 011-1h2a1 1 0 110 2H9a1 1 0 01-1-1z' /%3E %3Cpath d='M6 3a2 2 0 00-2 2v11a2 2 0 002 2h8a2 2 0 002-2V5a2 2 0 00-2-2 3 3 0 01-3 3H9a3 3 0 01-3-3z' /%3E %3C/svg%3E"); - --clipboard-image: var(--clipboard-image-normal) -} - -[data-theme="dark"] { - --primary-background: #171921; - --secondary-background: #1e202a; - --third-background: #2b2e3b; - --info-background: #008000; - --warning-background: #807000; - --error-background: #c03000; - --border: #0e1014; - --text: #fff; - --anchor: #8be9fd; - --anchor-focus: #8be9fd; - --input-focus: #8be9fd; - --strong: #bd93f9; - --hint: #7A7C85; - --nim-sprite-base64: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAARMAAABMCAYAAABOBlMuAAAACXBIWXMAAAsTAAALEwEAmpwYAAAFFmlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgNS42LWMxNDggNzkuMTY0MDM2LCAyMDE5LzA4LzEzLTAxOjA2OjU3ICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgeG1sbnM6cGhvdG9zaG9wPSJodHRwOi8vbnMuYWRvYmUuY29tL3Bob3Rvc2hvcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgMjEuMCAoV2luZG93cykiIHhtcDpDcmVhdGVEYXRlPSIyMDE5LTEyLTAzVDAxOjE4OjIyKzAxOjAwIiB4bXA6TW9kaWZ5RGF0ZT0iMjAxOS0xMi0wM1QwMToyMDoxMCswMTowMCIgeG1wOk1ldGFkYXRhRGF0ZT0iMjAxOS0xMi0wM1QwMToyMDoxMCswMTowMCIgZGM6Zm9ybWF0PSJpbWFnZS9wbmciIHBob3Rvc2hvcDpDb2xvck1vZGU9IjMiIHBob3Rvc2hvcDpJQ0NQcm9maWxlPSJzUkdCIElFQzYxOTY2LTIuMSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDplZGViMzU3MC1iNmZjLWQyNDQtYTExZi0yMjc5YmY4NDNhYTAiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6ZWRlYjM1NzAtYjZmYy1kMjQ0LWExMWYtMjI3OWJmODQzYWEwIiB4bXBNTTpPcmlnaW5hbERvY3VtZW50SUQ9InhtcC5kaWQ6ZWRlYjM1NzAtYjZmYy1kMjQ0LWExMWYtMjI3OWJmODQzYWEwIj4gPHhtcE1NOkhpc3Rvcnk+IDxyZGY6U2VxPiA8cmRmOmxpIHN0RXZ0OmFjdGlvbj0iY3JlYXRlZCIgc3RFdnQ6aW5zdGFuY2VJRD0ieG1wLmlpZDplZGViMzU3MC1iNmZjLWQyNDQtYTExZi0yMjc5YmY4NDNhYTAiIHN0RXZ0OndoZW49IjIwMTktMTItMDNUMDE6MTg6MjIrMDE6MDAiIHN0RXZ0OnNvZnR3YXJlQWdlbnQ9IkFkb2JlIFBob3Rvc2hvcCAyMS4wIChXaW5kb3dzKSIvPiA8L3JkZjpTZXE+IDwveG1wTU06SGlzdG9yeT4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz4JZNR8AAAfG0lEQVR4nO2deViTZ7r/7yxkJaxJ2MK+GCBAMCwS1kgUFQSKK4XWWqsz1jpjp3b0tDP1V+eqU391fqfT/mpPPd20drTFDS0KFEVWJSGAEgLIZpAICBJACIRs549Rj1WILAkBfD/XlevySp68z/0S3+/7vPdzLyidTgcLkU2bd+z39/f/q1gshsrKSoJELFCa2iaEuU9K6kb+8uXxv54/fzE8L/eswNT2zCfQpjbAGKS8lPFKSEjIXiaTCSEhIeDj4xNnapsQ5j6rktZGp6UlfxIdzQVzCplmanvmG1hTG2BIAtlc26CgoDfT0tL2e3l5AQCAjY0NkMnk/a9s2k6rrKw8UV8n1JjYTIQ5RlAw14KzmL3xze1vfJyUuMJaq9UCFovFm9qu+YbBxcSPFUYkk8l2Q0NDsvo6ocrQx5+I8Ih4bz6f/0l8fHyKlZXV4/dRKBQwmcwwMpn8A4FAoPgHhH9bV1sxa488wZxoaycnJ/a9e/duCa5fkc3WvAiTI4Ib77p+XdqHG9anbfLy8gAAgLGxMdBpF+bjvzExqJj4scKI0dHRnwQHB++orq7+AgDeMuTxJ2Jl4rqU9PT0EwEBAUQCgTDuGAaDAampqYepVKpHUHDk325Ulw0a266YuFW+Gzdu/MDPz29jfn7+XgA4aOw5ESZP6kvpCXv3vnM8NiaSamVl+fj9BepGNDoGFRN7e/slcXFxO1xcXMDJyWnH7j//H/fi4uJdgutXmgw5z5O8smn7X9euXbvf29sbMBjMhONQKBRYWVlBbGzsbjMzM3JoOG+/sKKwy1h2rd/4elpGRsYuLy+vaDweD2w2Oy1h5ZrCvEunEaeeiVnMiabyl/F2/+X9P+8JDPQHHA5napMWBAYTk6DgSNuEhIS9DAYDAP7tq1i6dOkqOp3OWbNu0wens44emeoxA9lcWwKBYEMkEm2JRKIdHo+3QKFQWJ1Op8ZgMER3d/dVq1evTnFycpr0MSkUCsTExGzH4/Gk1LTME/39/TI0Go1FoVCg1WrVY2NjipGRkcGRkRH5dPwrEZHLXMPCwjJSUlIy3dzcfB+97+rqGhYSEpIOAIiYmBguN3zL77dt3uPh4W5qUxYUBhMTb2/vjeHh4cvR6P/dILK0tITIyEg7BweHr363/Z3Ampqaf1Zcu/zMKiVsyVJvMplsRyKR7IhEor2FhYUbhUJhJCYm2pFIJB6JRAIymQx4PB7QaDRoNBowMzMDJycnwOOn7icjEokQGxu7icFgbLp///7jFY1WqwWlUgkjIyOgUCgO7Ni5Rz48PCwfHh7uGRkZeaBQKOSjo6ODCoVCXlNVKn/6uCsT13FXrVr1emho6BYKhfLMnP7+/omrU9LPX8g+UThloxEMxqJFXjxESAyPQcSEExrLWLNmzW57e/txP/fw8ABHR8cdDAaDt3xF2ru9vb03sVgs0cbGxs/FxWVZUlISj0aj+dna2oKtrS1M5PcwJCgUCry8vODRrs84vPfoH6OjoyCXy6Gvr+/R6+CWrX9s7evrk/b19bWr1Wqli4sLZ8OGDe95eXmxUSjUuAd0cHDwjoqK2sYKXFIhvnldYYTTQpgU4/8+jyASCYDGoCd+ZkYYF8OICYezl8PhuOkbQyAQIDo62s/NzS2np6cHbGxsgEajAYFAAAwGA1gsFia6CE0NgUAABwcHsLe3B61WC2q1eo9WqwWNRgNKpRLUajUQiUSgUCh6zwGHwwGTydzo5+eXBQBnZu8MEJ5keHhYPqyYWMtHR0ZBpVIhYj9FUDONgOUvT12+du3avMDAQJjssdRqNWCxCyrEZdLodDoQi8Ulx44de628NL/V1Pa8iERE8l2dHB2CJvpcq9Nqbt1qKURWj1Njxld0ZGTkAW9v70kLCQC8sEIC8O/HKx8fn2gmk8kHgCk7pRFmzrWyAikASE1tx0Jj2uH0EZHL/N7YtuvT4OBgzmz4OBYSeDweIiMjt2S++vtMP1YYEmmJsCCY8mNOIJtr6+zsHBcZGXmIw+G4mZubG8m0hU9HRwcUFxe/KxQKTyDRsQjznSmJCS9+dVRERMTfQ0NDo2xtbfUGiSFMjtHRUaitrc3Jzc09kHvxVLmp7UFAmC6oZQkvrZLL5RJhReHtiQb5scKIXC7371FRUX90dnYGIpE4JR8Jgn40Gg20t7fXFxYWfnr9+vWjz8sdYi+Osh4vzgUBwZSgtu94V+fs7Hx7YGCgra6u7khLS0u2RCwYeTQgKmYFh8fj/f/g4OAldnZ2prR1wdPd3Q1CofBQSUnJkdLi3N8E93FCY6k+Pj48FxcXjlar1ZSWlh65VvYr4kREmDNg79+/D3FxcW5OTk5uXl5evNbW1tL0jK3ZXV1d1ykUintycvInoaGhdkj+gvGxs7MDPp+/m0AgWMQvS/lyeHhYTqPRPJycnIJSU1NZ3t7eW2g0Gly/fv2oWq1Gij0hzClQ/gHhpLS0tEM8Hm/7I8Ho7++HlpYWsLa2Bg8PDxOb+OKhUCigqakJ7t+/D25ubuDu7g4oFAp0Oh08ePAAvv7666TTWUdzTG0nAsKTYMU3ryuSU18+4+bmFrZo0SIOAICVlRUsXrx4zkakLnRIJBI8CgJ8MtdJp9NBZ2enqL29XWRC8xAQxgUNAHD+3L8KGhoaCp78ABES04JCoX4jJAAAAwMDUFtbe96YpRMQEKbL41DU5ubmko6Ojj2PSgggzD36+/vrb9y4cX425zzw93/8EBjon2is44+NjSkePBjqGRwc7G5v7xBV19w8U5B/3qgrr9+/uWtXUuKKD/TZ9MXh/066/OuFmunO8dGBQ98HBbGSp/t9U6LRaDXK0dHBoeFhuVzeL22/0yFqamopufjLqRJ933ssJi0tLSXV1dWHGAzGbuObOzs8ubqa71vZKpUKOjo6blwpOF8zm/Mu5cVkLlkSaswprAHAaVihgK7O7oSGxltvfXLon3nXK4RHT2cdN4pfKDCAlZyUuMJan02nTmczAaBmunPw4qI3cbnh0/36XICq0+lgcPABp7OrK629vUP5z8++LLh2XXD05L++yxrvC4/F5EZ12WBS8saLS5Ys2U2lUufUY45SqQSlUgkqlQrUavXj19jYGGg0GtBoNKDT6UCn05VotVq1TqfToFAojFar1eh0Og0Wi8XhcDgeGo1+/PhgZmYGOBwOsFgsmJmZ/eY1F+nt7YXa2trs2Z73wdCQBgCMHp1IJpHA09MdPD3dLRIS+OtKisvWvbP7vf2lZdePVFwzbHTwyMiI3hidkZFRUKvUYzOZ48HQkBIA5nWqBAqFAktLC7C0tADmIh88Pz4uMSyUk7hn776DV4tKPn/6d/lNxp1MJqsRCASf8vn8XdMpOjRTVCoVjI2NgUqlAq1WCyMjI9DX1wf379+Hvr6+/Q8ePOgdGRmRKxSKx0WLFAqFXKlUKnQ6nUar1arHq47mxwrD4/F4Eg6HI2GxWDwej7cgkUjWFAqFam5uTjU3N6eRyeQPLSwswNraGqysrIBAIDwWFywW+zja11Qi29LSclIikeSZZPJZBovBAI8XA8HBQR9kZZ3lR8cmvFZSlGe00p8IkwONRkNERBj4+i7a4+XpHv307/IbMakWlciXJbx0nMPh7Jqo0JGh0el0MDo6Cl1dXSCVSkEmk7177969W319fe1DQ0M9KpVKoVarlWq1WjndNhUPG3ApAWDcOxLTLwSDwWAOotFoDBaLxRMIBAsrKysne3t7Xzqd7k2n0/c4OzsDlUoFHA4364IyMDAATU1NxdWikhcq6tXKyhJezljPJZKI2eERS5cZeoWCMD2srCwhPX0tVzk2djiCG//GtfLLUoBxShB0dHTU3Lx580sLC4vtJBLJKMZoNBqQSqUglUqPdnR01PT09DT19/fLHjx40DM0NNQ72933GiSVGgB4JFQK+LfoSAGgnL04yppEIh2xtLS0t7GxcaFSqR7Ozs4fMRgMcHR0nJX8pJs3b54Ui8UXjT7RHIRMIkFK8irfwcEHPwQELUmqvYHUGJkLmJubw8YNa/i9vfffY/px3myQiDTPiEl9nVDDX576jaenZ7SnpyfLUJNrNBqQyWRw+/bt4x0dHTdkMlltV1dXw/XygjkdEv4wB0YOAK0AUM70C8HQ6fSzdDrdm0qlejg6OrLc3Ny2MBiMadWjfR4PHjyAmzdvZs/1v5MxoVAokJK8iicWS95k+nH+s0EiQhqpzQGoVFtYk5a87ba0XQAA34xbpagg/5zoT7s/OGNnZ8eaaYkBuVwOnZ2d5VKpVNTS0lLS2NhYWFVZ3Dujg5qQh6uY+ocvCAiKIPn4+Jz19PSMdnV15VCpVL6Dg4NBViw6nQ5EItHRpqamqzM+2DzHzo4O69amftLQeKsAZrDLgmBY/PyYsCIhfs+SiKUFE5Y8EwqFx11cXDihoaFTjjFAoVAwPDwMHR0dourq6jNCofDHhZqUVnvjmgIAcgAgJyg40mLRokX8kJCQjT4+PussLS1n1JPl7t27UFxcfHguB6mNjY2B7G4naNRTWyygUCjAYDGAx+PB0sICSCSi3vFYLBbCwjjA8vddBQtATKb7d3saBwc7IJPJBpsHjUGDGRYLJBIJLK0sAfucmyIGg4FFi3y8AwNZtycUk5KiS02vvf7WWQaDkejg4DApQwAeh3xDaWnpPoFAcPxFqnP6sEvgGf+A8Bx3d/cvIyIiNi1evHjT8wpNj8fAwACUlZW9P9dD5+/ckcFbf9gd2dcnn9LNAovF4inmZHtXNxdOdBR3+/JlS33pdP29wolEInA4weuiYxOy5vvuTkeHDHb+8c8xvb33Z3R9/N+Df+uIjYk02DwkEsna2trS1d/fNyGeF7uTyw1/7g3R3t4O2OxA/TVghULhcQqFQk1JSfmYSNR/5wD4d6EfgUBwvLS09IhUKhW9qAV5H9YjKQwJi6uvrKw8ERoamhkSEpKp7w7yJEqlEiQSyZmysrJv53qjdaVSCZdyTk+3qFMrAJRHRPLPN95qeifj5fU7mYt8JhyMRqMhMJDFdnF25gDAvBYTpXIMWlpay2fq/8m5mDcIABYGnEcGAGI/VlhBZWX1yZdSkz55OX0dV5+7w9bGGvz8mPrFpK62QskJjf2GTqd7x8bGbpnID4BCoUAmk0lLSkqOiESik2UleS/MakQflYKrXQDQxY1a3tTe3i6KiIjY5OXlxX7e9+rr6wsuXbr0t4ffn9OgMWjghMZQRcLp+8GulRVI/QPC37Wxtnal0ajJtjY2E451ZjiBra31vE9lR2PQQKFQaAAwo98Yi8Xq9fpPd56HO6rlvKWJv/PwcK+JilyCmajWMw6HAzs7+rMFpQOCIn6zHywSFvXm5eUdFAqFZ9Rq9bgHa2trq79w4cK+zz49cAARkmcpL81v/a/Dhz49d+7c3qqqqjyVSjXuOJ1OBxKJpDw3N/fA5V+zax6978cKw/sHhM/raMrnUVdboSy4fPWQSFSjd5yFBQWIRNKEd2IEw1J4JUd88WL+R51d3XrHWVDMnxUTa2tr1zXrNiUGsrmPf7DS4tymCxcu7Kuurs55+kKQSqVN586d23vs+8NHDXUCC5Wzp3/Iy8rKeruysvLM2Nhvo7VVKhXU1tYWnj17du/T7UOdnZ2D7OzsfGGB09raVi4S1RzXl0eFw+EAj8chYjKLVFffyOrq1C8mJBLpWTFRKBRyDofzC4vFWvXk+1ev/CLOzs7eKxAIslQqFeh0Oujp6enKzs7em/XTd7OayTqfKb56sT4rK+sPAoHg5KO/o0KhAKFQmHXy5MkdF3/5+TeZmctXpIXZ29v7zqVcKWNRX1epuXu3U/y8pEw0GmndOZt0dnXVDw0P6/W5oNHoZ30mQ0NDPb29vfvj4+Pf3rR5B/7od188XnEUXr4gDgmL+0NfX5/U19d3d3l5+YGfTnyDtLmcIhXXLsu4UcvfR6PRGGtra9eysrIjYrE45+kt4Fheou/69es/unnz5vm7d+/Wmsre2WRkZGTQ1DYg/JYGiUiTm1ugBAC9IfHPiEmDpFITE7fqJI/H27lmzZpDq5LWtz55t6wUXO3ihMYerK+vz2tpaUFaM0yT8tL81ujYle+TSCTrvEunBU9/voTLd92wYcPHVCqV39XVdXCu7+oYCp1O90Kc50Jk3I5+xVcv1jc3N5d4enpSMzIyvkpK3sh78nORsKg3++yPBS/q1q+hKCm61DSekERGJ3ikp6d/ERsbm1xVVXWwtbX1hRFtFAqFPMLMUyZsDyoQCI7LZDKIiIjwzczM/GpV0vro2TTsRSUqZoX3+vXrP1u9enXi0NAQiESirIdRtggIc5oJ40zq6uryGhoa8ry8vBJCQ0O9USjU94mrN7yWc+EnvaXb5gJMvxCMp6cnl0Kh2Le1tZVXXLs8L1LXefGrWRkZGZ/x+XyeUqkEkUh0vqenZ14HZyG8OEwoJjdrygd37NxTEBkZmWBtbQ3BwcEeKBTq+/UbX3/355Pfzlmn66qk9dGbN29+k8PhbCSRSNDZ2Snb9ae/HCkpKTksEhbN2QTD5NSX+Vu3bj0cHBzsjcFg4O7du1BWVvbNwxB9BIQ5j94I2Fu3bhXW19cDl8sFLBYLHA7Hg0wmf/e77e84ffXlPz6fLSMnQ2paZkJ4eHjmtm3b+B4eHvZkMhlQKBTY29s72dvbfxgUFJT8x7ffP1NRUfHjXErnZ/qFYKKjo7dt3rz5g8DAQPtH/XHa2tpqGhsbC55/BASEuYFeMblz505NTU3NgfDw8PcwGAygUCjw9fW1IJPJn/1130Hv0tLSI4WXL4hny9inYS+Osvbz80tgMpn8jIwMPovFch2vpoiDgwM4ODhwfH19OYsWLeJv3/Hu+cbGxquzXZz5aZYlvMRJT0/fFhkZue3JZmfd3d0gEolOIr4ShPmEXjFpkFRqXlrzSnFnZ+d7Tk5OjzNfXVxcICMjY6ezszNnVdL6vU8HWhmbgKAIkrOzMyc1NTXz0YU4maAuOp0OK1as4EVFRfGEQqHg1dfePHzr1q2rs71S8WOF4f38/BLS09M/iIyM5DxdxLq5uVlcVVU1bgVwBIS5il4xAQCQyWRigUBwJikpKe3JVGQcDgdLly7l2tranti0ecf7IpEoy9hbxX6sMDydTvdevXr1ltjY2F3u7u6AxT73FJ7B3Nwc4uLiwthsdphQKCzZkL7l0/r6+oKbNeVG90+EhMXZL1++fFtycvKHrq6uz4igUqmE5ubmEiTHCWG+8dwrUXD9imz9xtd/jIuLS7N5KpsTjUZDUFCQE4PB+F4oFGYmJW888Mv5k4UTHGpGxC9LYaenp78VEhKyxdHRESgUyoyOh0KhwNraGuLi4qIDAgKi6+rqyjekb/mHMSN6N6RvSdu+ffseNpsdZm09ftuW+vp6EIvFSB9hhHnHpG7rUqm0orW1tdXS0tLj6TIEaDQaaDQaxMfH811dXTl/3Xfw+JUrVz411J01cfWG6IiIiC07d+5McHNzs7ewMGyOFw6HAwcHB6BSqVx3d/fwz7/4rkAgEBwXCoUnHpZonDGrU9J5MTEx27du3Zrm4uKC0beaqq6u/ry+vj7XEPMiIMwmkxKTimuXZe/u+fCkp6fnexPdUfF4PPj7+1szGIydLi4unF1/+kvenTt3RG1tbRXTqfma8lIG39/fP/HVV19NZrFYHpMpzjQTzMzMwNPTE+Pp6Zng6emZ4Ofnl5CesfV8bW1tznQe3/wDwvFeXl7Rvr6+Ca+88kpaUFCQh74GXzqdDrq7u6GpqankRQmdR1hYTNrhUFVVlcXj8d6ysrKy0OfstLS0hPj4eC6Xy+U2NzeDRCI5/sa2XeX37t1rGhwc7BoYGJBN1P+FFbiE5OzszGaxWImvvvrqpoCAAKfp+ERmCpPJBCaTmcnhcDJLS0u/TE59+YxUKhXoi/lg+oVgrKysGJaWlna2trYeaWlpXDabvTMgIGDSfp2KiorzbW1tL0zoPMLCYtJX6uVfs2u++PKowMPDgz+ZIslEIhECAgKAxWJlajSazJ6eHmhra4PW1tZvtmz9o6Czs7O+r6+vfWxsbFir1WosLCzsV6xYkcnj8d7z9vaelmPV0Hh5eYGnp+f2mJiY7UVFRZ/HL0v5tru7+5ZGo1FisVg8Docj4fF4CxsbG1c+nx/m7e39sYeHB7i4uIC5ufmU6r4ODQ1BZWXlifkSrYuA8DRTumIrKytPent78728vCb9HRQKBVgsFhwcHIBOpwObzd4yNja2RaVSwdDQEHR1dcHo6CjQaDRwdXWdsWPV0KBQKPDw8AA7O7udERERO2tra2FgYACoVCo4OTkBjUYDMpkMeDz+8WuqaLVaaGxsbL19+/YzSX8ICPOFqYrJidDQ0AwvLy/e80c/CwaDARKJBI86BdJoNHB3dwe1Wj0nViL6IJPJwGQywdnZGZRKJRAIBDBUx8OBgQEoLS39BtkORpjPTJg1PB61N64pmpqarvb39xvUiLkuJE9CJpPBxsbGYEICANDZ2SlHgtQQ5jtTEhMAgLq6ulyJRFJvDGNeREZGRkAikRSUFuci2cEI85opi0l+7hmBWCzOeV6dToTJcfv27cHr168jxbgR5j1TFhMAgObm5hKZDNl0MAQtLS3Xzpw6hkS8Isx7piUmUqlUIBAIJuyjgzA5Ojs7QSKRINGuCAuCaYmJsKKw68qVK59KJJIu5HFneiiVSigqKjouEolOmtoWBARDMC0xAQC4+MvPJadOnXq3ra1N8yL0dDEkOp0OSktLy/Pz8w8+3d4CAWG+Mm0xAQA4fuy/jl+8ePGju3fvGsqeBY9Wq4XKysrWU6dOvX31yi8mKyyFgGBoZiQmAAD/79D+fadPn96PCMrz0el0UFVV1frtt9+mj9fiAgFhPjNjMQEAyMvLO3Ds2LE/tLS0INmuerh27Vr9999//xoiJAgLEYOEntbVVigB4PNNm3cMpqSkfMRms50McdyFgkqlgqKiovJTp069nZ97BhEShAWJQePYj373xdF1GzbLFQrFx6Ghob766ne8KNy7dw+KiopO5ubmfmTK4tsICMbG4EkxWT99d35l4rre/v7+D0NCQvh0Ot3QU8wL1Go1SKVSTX5+/sH8/PyDSP8bhIWOUTLsLuVklQcFR65pbGzcvnLlyvfc3NwsCASCMaaac+h0OhgaGoLq6uqaCxcu/OV01tGcTw7uM7VZCAhGx2jpug/vxAd58atzoqKitq1cuXKnvb29saabE+h0Oqiurpbm5eUdrK6uPlspuDrvY0hmO4YIhUIBGq1/X2CmNqFQKL3/79HomZ/z82xEowyy9zFr80zGDqPn/hdeviBmL47ad+fOnRsRERGbQkNDo62srIw97azT2dkJxcXFx0tKSo7Mdh8hY4LD4TDPH2U4MFjMc6tLmZmZzaj+Aw6H0/t9PB4PGCxmRudNJBL0ngeZTAI0Gj3jv+1szfM88Hic8cUEAKCmqlQOAN/ELU2qkEgkySwWK3HRokVcBoMxG9MbDZ1OB83NzdDU1FRQW1t7XiAQHJ+ovu18pbr6Rg6L5ZtoM0EhcUPT0tJW8tWRb0vQqIkvgKqqmhnVfrl2TfANXo+gjKlUio4OWc1M5sjOzjnQUH8rbqLPu3t6moaGhmfc+3q25tGHUqmECoEIUKbIrVkcEkONiIh4jcvlvu7s7OxLo9GmVe7QVCgUCujq6oKGhoaCioqKo9XV1WeM3YDMVPDik1gpyas+XrVyeaKXl8czjyANjbcgI/MNmkg49Q4ECPOH3NyC4RUr+M8IcHt7B1y9WlKRl3/5kElKnD1sfXEoJCzueEBAQGJYWFgGk8nk2djYAIFAgLm4pTw6Ogqjo6Mgl8vhxo0b50tLS4/U19fnLvS2FIWXfxEDQNLmLW9ueW1TxtchHDaQyWRTm4VgYkZHR6G+vhF+/NfP+y5e+vVjiVgwZpKVydOwF0dZW1lZOTGZTD6bzU4LCAiIptPp8HTDL1MwOjoKLS0tUFdXd1IsFudIpdKKgYGB7tloJTrX4MUnsVJTEj9etzY10dHRAQAAGm81wcsZW5CVyQInL69gNCGBjwcAGBx8ANnncypOnTr3H9nn/reD55wovvrQpyIHAHFUzIocGo3mQaPRfBwdHVlubm7bXF1dgcFgABqNNvruglwuh7t374JMJoOOjo7P79y5I+ru7m7q7e1tXQi7MzOh8PIv4pCw2DdaWtte37Au7aPIyCWAxWABjUbPif9HCMbjURtKiaQBfvr5zH9evlJ0uLQ4r/nJMXNiZTIRrMAlJAcHB18HBweWo6Mjy8rKajeJRAJLS0uwtLQECwsLoFAogMfjAYvFgpmZ2XNXMyqVCoaHh2FoaAiGh4cfvwYGBqCvrw+6u7vfvnfvXlNvb29rT09Pq0QsUM7S6c4rNqS/lrZ5U+YPRBKR9M7u9xwqBUUvtNAudH766XSLE8PR49ixE78/8tVnX403Zk7fUR46NUUAIPIPCMdTKJTdNjY2QKPRgE6nA51OB1tbWyCRSIDD4YBAIAAejwcCgfDYUajVakGlUoFarQadTvfY79HX1wf9/f0gl8tBLpfDvXv3HvXw+dxQPYYXMj+d+P7Mmzv+5OHr6/OJWq1GBHeB09TcUiKuq/coKS3/eqIx/wPkiIXC3w6YjAAAAABJRU5ErkJggg=="); - - --keyword: #ff79c6; - --identifier: #f8f8f2; - --comment: #6272a4; - --operator: #ff79c6; - --punctuation: #f8f8f2; - --other: #f8f8f2; - --escapeSequence: #bd93f9; - --number: #bd93f9; - --literal: #f1fa8c; - --program: #9090c0; - --option: #90b010; - --raw-data: #8be9fd; - - --clipboard-image-normal: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' style='color: lightgray' fill='none' viewBox='0 0 24 24' stroke='currentColor'%3E %3Cpath stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2' /%3E %3C/svg%3E"); - --clipboard-image-selected: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' style='color: lightgray' viewBox='0 0 20 20' fill='currentColor'%3E %3Cpath d='M8 3a1 1 0 011-1h2a1 1 0 110 2H9a1 1 0 01-1-1z' /%3E %3Cpath d='M6 3a2 2 0 00-2 2v11a2 2 0 002 2h8a2 2 0 002-2V5a2 2 0 00-2-2 3 3 0 01-3 3H9a3 3 0 01-3-3z' /%3E %3C/svg%3E"); - --clipboard-image: var(--clipboard-image-normal); -} - -@media (prefers-color-scheme: dark) { - [data-theme="auto"] { - --primary-background: #171921; - --secondary-background: #1e202a; - --third-background: #2b2e3b; - --info-background: #008000; - --warning-background: #807000; - --error-background: #c03000; - --border: #0e1014; - --text: #fff; - --anchor: #8be9fd; - --anchor-focus: #8be9fd; - --input-focus: #8be9fd; - --strong: #bd93f9; - --hint: #7A7C85; - --nim-sprite-base64: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAARMAAABMCAYAAABOBlMuAAAACXBIWXMAAAsTAAALEwEAmpwYAAAFFmlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgNS42LWMxNDggNzkuMTY0MDM2LCAyMDE5LzA4LzEzLTAxOjA2OjU3ICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgeG1sbnM6cGhvdG9zaG9wPSJodHRwOi8vbnMuYWRvYmUuY29tL3Bob3Rvc2hvcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgMjEuMCAoV2luZG93cykiIHhtcDpDcmVhdGVEYXRlPSIyMDE5LTEyLTAzVDAxOjE4OjIyKzAxOjAwIiB4bXA6TW9kaWZ5RGF0ZT0iMjAxOS0xMi0wM1QwMToyMDoxMCswMTowMCIgeG1wOk1ldGFkYXRhRGF0ZT0iMjAxOS0xMi0wM1QwMToyMDoxMCswMTowMCIgZGM6Zm9ybWF0PSJpbWFnZS9wbmciIHBob3Rvc2hvcDpDb2xvck1vZGU9IjMiIHBob3Rvc2hvcDpJQ0NQcm9maWxlPSJzUkdCIElFQzYxOTY2LTIuMSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDplZGViMzU3MC1iNmZjLWQyNDQtYTExZi0yMjc5YmY4NDNhYTAiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6ZWRlYjM1NzAtYjZmYy1kMjQ0LWExMWYtMjI3OWJmODQzYWEwIiB4bXBNTTpPcmlnaW5hbERvY3VtZW50SUQ9InhtcC5kaWQ6ZWRlYjM1NzAtYjZmYy1kMjQ0LWExMWYtMjI3OWJmODQzYWEwIj4gPHhtcE1NOkhpc3Rvcnk+IDxyZGY6U2VxPiA8cmRmOmxpIHN0RXZ0OmFjdGlvbj0iY3JlYXRlZCIgc3RFdnQ6aW5zdGFuY2VJRD0ieG1wLmlpZDplZGViMzU3MC1iNmZjLWQyNDQtYTExZi0yMjc5YmY4NDNhYTAiIHN0RXZ0OndoZW49IjIwMTktMTItMDNUMDE6MTg6MjIrMDE6MDAiIHN0RXZ0OnNvZnR3YXJlQWdlbnQ9IkFkb2JlIFBob3Rvc2hvcCAyMS4wIChXaW5kb3dzKSIvPiA8L3JkZjpTZXE+IDwveG1wTU06SGlzdG9yeT4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz4JZNR8AAAfG0lEQVR4nO2deViTZ7r/7yxkJaxJ2MK+GCBAMCwS1kgUFQSKK4XWWqsz1jpjp3b0tDP1V+eqU391fqfT/mpPPd20drTFDS0KFEVWJSGAEgLIZpAICBJACIRs549Rj1WILAkBfD/XlevySp68z/0S3+/7vPdzLyidTgcLkU2bd+z39/f/q1gshsrKSoJELFCa2iaEuU9K6kb+8uXxv54/fzE8L/eswNT2zCfQpjbAGKS8lPFKSEjIXiaTCSEhIeDj4xNnapsQ5j6rktZGp6UlfxIdzQVzCplmanvmG1hTG2BIAtlc26CgoDfT0tL2e3l5AQCAjY0NkMnk/a9s2k6rrKw8UV8n1JjYTIQ5RlAw14KzmL3xze1vfJyUuMJaq9UCFovFm9qu+YbBxcSPFUYkk8l2Q0NDsvo6ocrQx5+I8Ih4bz6f/0l8fHyKlZXV4/dRKBQwmcwwMpn8A4FAoPgHhH9bV1sxa488wZxoaycnJ/a9e/duCa5fkc3WvAiTI4Ib77p+XdqHG9anbfLy8gAAgLGxMdBpF+bjvzExqJj4scKI0dHRnwQHB++orq7+AgDeMuTxJ2Jl4rqU9PT0EwEBAUQCgTDuGAaDAampqYepVKpHUHDk325Ulw0a266YuFW+Gzdu/MDPz29jfn7+XgA4aOw5ESZP6kvpCXv3vnM8NiaSamVl+fj9BepGNDoGFRN7e/slcXFxO1xcXMDJyWnH7j//H/fi4uJdgutXmgw5z5O8smn7X9euXbvf29sbMBjMhONQKBRYWVlBbGzsbjMzM3JoOG+/sKKwy1h2rd/4elpGRsYuLy+vaDweD2w2Oy1h5ZrCvEunEaeeiVnMiabyl/F2/+X9P+8JDPQHHA5napMWBAYTk6DgSNuEhIS9DAYDAP7tq1i6dOkqOp3OWbNu0wens44emeoxA9lcWwKBYEMkEm2JRKIdHo+3QKFQWJ1Op8ZgMER3d/dVq1evTnFycpr0MSkUCsTExGzH4/Gk1LTME/39/TI0Go1FoVCg1WrVY2NjipGRkcGRkRH5dPwrEZHLXMPCwjJSUlIy3dzcfB+97+rqGhYSEpIOAIiYmBguN3zL77dt3uPh4W5qUxYUBhMTb2/vjeHh4cvR6P/dILK0tITIyEg7BweHr363/Z3Ampqaf1Zcu/zMKiVsyVJvMplsRyKR7IhEor2FhYUbhUJhJCYm2pFIJB6JRAIymQx4PB7QaDRoNBowMzMDJycnwOOn7icjEokQGxu7icFgbLp///7jFY1WqwWlUgkjIyOgUCgO7Ni5Rz48PCwfHh7uGRkZeaBQKOSjo6ODCoVCXlNVKn/6uCsT13FXrVr1emho6BYKhfLMnP7+/omrU9LPX8g+UThloxEMxqJFXjxESAyPQcSEExrLWLNmzW57e/txP/fw8ABHR8cdDAaDt3xF2ru9vb03sVgs0cbGxs/FxWVZUlISj0aj+dna2oKtrS1M5PcwJCgUCry8vODRrs84vPfoH6OjoyCXy6Gvr+/R6+CWrX9s7evrk/b19bWr1Wqli4sLZ8OGDe95eXmxUSjUuAd0cHDwjoqK2sYKXFIhvnldYYTTQpgU4/8+jyASCYDGoCd+ZkYYF8OICYezl8PhuOkbQyAQIDo62s/NzS2np6cHbGxsgEajAYFAAAwGA1gsFia6CE0NgUAABwcHsLe3B61WC2q1eo9WqwWNRgNKpRLUajUQiUSgUCh6zwGHwwGTydzo5+eXBQBnZu8MEJ5keHhYPqyYWMtHR0ZBpVIhYj9FUDONgOUvT12+du3avMDAQJjssdRqNWCxCyrEZdLodDoQi8Ulx44de628NL/V1Pa8iERE8l2dHB2CJvpcq9Nqbt1qKURWj1Njxld0ZGTkAW9v70kLCQC8sEIC8O/HKx8fn2gmk8kHgCk7pRFmzrWyAikASE1tx0Jj2uH0EZHL/N7YtuvT4OBgzmz4OBYSeDweIiMjt2S++vtMP1YYEmmJsCCY8mNOIJtr6+zsHBcZGXmIw+G4mZubG8m0hU9HRwcUFxe/KxQKTyDRsQjznSmJCS9+dVRERMTfQ0NDo2xtbfUGiSFMjtHRUaitrc3Jzc09kHvxVLmp7UFAmC6oZQkvrZLL5RJhReHtiQb5scKIXC7371FRUX90dnYGIpE4JR8Jgn40Gg20t7fXFxYWfnr9+vWjz8sdYi+Osh4vzgUBwZSgtu94V+fs7Hx7YGCgra6u7khLS0u2RCwYeTQgKmYFh8fj/f/g4OAldnZ2prR1wdPd3Q1CofBQSUnJkdLi3N8E93FCY6k+Pj48FxcXjlar1ZSWlh65VvYr4kREmDNg79+/D3FxcW5OTk5uXl5evNbW1tL0jK3ZXV1d1ykUintycvInoaGhdkj+gvGxs7MDPp+/m0AgWMQvS/lyeHhYTqPRPJycnIJSU1NZ3t7eW2g0Gly/fv2oWq1Gij0hzClQ/gHhpLS0tEM8Hm/7I8Ho7++HlpYWsLa2Bg8PDxOb+OKhUCigqakJ7t+/D25ubuDu7g4oFAp0Oh08ePAAvv7666TTWUdzTG0nAsKTYMU3ryuSU18+4+bmFrZo0SIOAICVlRUsXrx4zkakLnRIJBI8CgJ8MtdJp9NBZ2enqL29XWRC8xAQxgUNAHD+3L8KGhoaCp78ABES04JCoX4jJAAAAwMDUFtbe96YpRMQEKbL41DU5ubmko6Ojj2PSgggzD36+/vrb9y4cX425zzw93/8EBjon2is44+NjSkePBjqGRwc7G5v7xBV19w8U5B/3qgrr9+/uWtXUuKKD/TZ9MXh/066/OuFmunO8dGBQ98HBbGSp/t9U6LRaDXK0dHBoeFhuVzeL22/0yFqamopufjLqRJ933ssJi0tLSXV1dWHGAzGbuObOzs8ubqa71vZKpUKOjo6blwpOF8zm/Mu5cVkLlkSaswprAHAaVihgK7O7oSGxltvfXLon3nXK4RHT2cdN4pfKDCAlZyUuMJan02nTmczAaBmunPw4qI3cbnh0/36XICq0+lgcPABp7OrK629vUP5z8++LLh2XXD05L++yxrvC4/F5EZ12WBS8saLS5Ys2U2lUufUY45SqQSlUgkqlQrUavXj19jYGGg0GtBoNKDT6UCn05VotVq1TqfToFAojFar1eh0Og0Wi8XhcDgeGo1+/PhgZmYGOBwOsFgsmJmZ/eY1F+nt7YXa2trs2Z73wdCQBgCMHp1IJpHA09MdPD3dLRIS+OtKisvWvbP7vf2lZdePVFwzbHTwyMiI3hidkZFRUKvUYzOZ48HQkBIA5nWqBAqFAktLC7C0tADmIh88Pz4uMSyUk7hn776DV4tKPn/6d/lNxp1MJqsRCASf8vn8XdMpOjRTVCoVjI2NgUqlAq1WCyMjI9DX1wf379+Hvr6+/Q8ePOgdGRmRKxSKx0WLFAqFXKlUKnQ6nUar1arHq47mxwrD4/F4Eg6HI2GxWDwej7cgkUjWFAqFam5uTjU3N6eRyeQPLSwswNraGqysrIBAIDwWFywW+zja11Qi29LSclIikeSZZPJZBovBAI8XA8HBQR9kZZ3lR8cmvFZSlGe00p8IkwONRkNERBj4+i7a4+XpHv307/IbMakWlciXJbx0nMPh7Jqo0JGh0el0MDo6Cl1dXSCVSkEmk7177969W319fe1DQ0M9KpVKoVarlWq1WjndNhUPG3ApAWDcOxLTLwSDwWAOotFoDBaLxRMIBAsrKysne3t7Xzqd7k2n0/c4OzsDlUoFHA4364IyMDAATU1NxdWikhcq6tXKyhJezljPJZKI2eERS5cZeoWCMD2srCwhPX0tVzk2djiCG//GtfLLUoBxShB0dHTU3Lx580sLC4vtJBLJKMZoNBqQSqUglUqPdnR01PT09DT19/fLHjx40DM0NNQ72933GiSVGgB4JFQK+LfoSAGgnL04yppEIh2xtLS0t7GxcaFSqR7Ozs4fMRgMcHR0nJX8pJs3b54Ui8UXjT7RHIRMIkFK8irfwcEHPwQELUmqvYHUGJkLmJubw8YNa/i9vfffY/px3myQiDTPiEl9nVDDX576jaenZ7SnpyfLUJNrNBqQyWRw+/bt4x0dHTdkMlltV1dXw/XygjkdEv4wB0YOAK0AUM70C8HQ6fSzdDrdm0qlejg6OrLc3Ny2MBiMadWjfR4PHjyAmzdvZs/1v5MxoVAokJK8iicWS95k+nH+s0EiQhqpzQGoVFtYk5a87ba0XQAA34xbpagg/5zoT7s/OGNnZ8eaaYkBuVwOnZ2d5VKpVNTS0lLS2NhYWFVZ3Dujg5qQh6uY+ocvCAiKIPn4+Jz19PSMdnV15VCpVL6Dg4NBViw6nQ5EItHRpqamqzM+2DzHzo4O69amftLQeKsAZrDLgmBY/PyYsCIhfs+SiKUFE5Y8EwqFx11cXDihoaFTjjFAoVAwPDwMHR0dourq6jNCofDHhZqUVnvjmgIAcgAgJyg40mLRokX8kJCQjT4+PussLS1n1JPl7t27UFxcfHguB6mNjY2B7G4naNRTWyygUCjAYDGAx+PB0sICSCSi3vFYLBbCwjjA8vddBQtATKb7d3saBwc7IJPJBpsHjUGDGRYLJBIJLK0sAfucmyIGg4FFi3y8AwNZtycUk5KiS02vvf7WWQaDkejg4DApQwAeh3xDaWnpPoFAcPxFqnP6sEvgGf+A8Bx3d/cvIyIiNi1evHjT8wpNj8fAwACUlZW9P9dD5+/ckcFbf9gd2dcnn9LNAovF4inmZHtXNxdOdBR3+/JlS33pdP29wolEInA4weuiYxOy5vvuTkeHDHb+8c8xvb33Z3R9/N+Df+uIjYk02DwkEsna2trS1d/fNyGeF7uTyw1/7g3R3t4O2OxA/TVghULhcQqFQk1JSfmYSNR/5wD4d6EfgUBwvLS09IhUKhW9qAV5H9YjKQwJi6uvrKw8ERoamhkSEpKp7w7yJEqlEiQSyZmysrJv53qjdaVSCZdyTk+3qFMrAJRHRPLPN95qeifj5fU7mYt8JhyMRqMhMJDFdnF25gDAvBYTpXIMWlpay2fq/8m5mDcIABYGnEcGAGI/VlhBZWX1yZdSkz55OX0dV5+7w9bGGvz8mPrFpK62QskJjf2GTqd7x8bGbpnID4BCoUAmk0lLSkqOiESik2UleS/MakQflYKrXQDQxY1a3tTe3i6KiIjY5OXlxX7e9+rr6wsuXbr0t4ffn9OgMWjghMZQRcLp+8GulRVI/QPC37Wxtnal0ajJtjY2E451ZjiBra31vE9lR2PQQKFQaAAwo98Yi8Xq9fpPd56HO6rlvKWJv/PwcK+JilyCmajWMw6HAzs7+rMFpQOCIn6zHywSFvXm5eUdFAqFZ9Rq9bgHa2trq79w4cK+zz49cAARkmcpL81v/a/Dhz49d+7c3qqqqjyVSjXuOJ1OBxKJpDw3N/fA5V+zax6978cKw/sHhM/raMrnUVdboSy4fPWQSFSjd5yFBQWIRNKEd2IEw1J4JUd88WL+R51d3XrHWVDMnxUTa2tr1zXrNiUGsrmPf7DS4tymCxcu7Kuurs55+kKQSqVN586d23vs+8NHDXUCC5Wzp3/Iy8rKeruysvLM2Nhvo7VVKhXU1tYWnj17du/T7UOdnZ2D7OzsfGGB09raVi4S1RzXl0eFw+EAj8chYjKLVFffyOrq1C8mJBLpWTFRKBRyDofzC4vFWvXk+1ev/CLOzs7eKxAIslQqFeh0Oujp6enKzs7em/XTd7OayTqfKb56sT4rK+sPAoHg5KO/o0KhAKFQmHXy5MkdF3/5+TeZmctXpIXZ29v7zqVcKWNRX1epuXu3U/y8pEw0GmndOZt0dnXVDw0P6/W5oNHoZ30mQ0NDPb29vfvj4+Pf3rR5B/7od188XnEUXr4gDgmL+0NfX5/U19d3d3l5+YGfTnyDtLmcIhXXLsu4UcvfR6PRGGtra9eysrIjYrE45+kt4Fheou/69es/unnz5vm7d+/Wmsre2WRkZGTQ1DYg/JYGiUiTm1ugBAC9IfHPiEmDpFITE7fqJI/H27lmzZpDq5LWtz55t6wUXO3ihMYerK+vz2tpaUFaM0yT8tL81ujYle+TSCTrvEunBU9/voTLd92wYcPHVCqV39XVdXCu7+oYCp1O90Kc50Jk3I5+xVcv1jc3N5d4enpSMzIyvkpK3sh78nORsKg3++yPBS/q1q+hKCm61DSekERGJ3ikp6d/ERsbm1xVVXWwtbX1hRFtFAqFPMLMUyZsDyoQCI7LZDKIiIjwzczM/GpV0vro2TTsRSUqZoX3+vXrP1u9enXi0NAQiESirIdRtggIc5oJ40zq6uryGhoa8ry8vBJCQ0O9USjU94mrN7yWc+EnvaXb5gJMvxCMp6cnl0Kh2Le1tZVXXLs8L1LXefGrWRkZGZ/x+XyeUqkEkUh0vqenZ14HZyG8OEwoJjdrygd37NxTEBkZmWBtbQ3BwcEeKBTq+/UbX3/355Pfzlmn66qk9dGbN29+k8PhbCSRSNDZ2Snb9ae/HCkpKTksEhbN2QTD5NSX+Vu3bj0cHBzsjcFg4O7du1BWVvbNwxB9BIQ5j94I2Fu3bhXW19cDl8sFLBYLHA7Hg0wmf/e77e84ffXlPz6fLSMnQ2paZkJ4eHjmtm3b+B4eHvZkMhlQKBTY29s72dvbfxgUFJT8x7ffP1NRUfHjXErnZ/qFYKKjo7dt3rz5g8DAQPtH/XHa2tpqGhsbC55/BASEuYFeMblz505NTU3NgfDw8PcwGAygUCjw9fW1IJPJn/1130Hv0tLSI4WXL4hny9inYS+Osvbz80tgMpn8jIwMPovFch2vpoiDgwM4ODhwfH19OYsWLeJv3/Hu+cbGxquzXZz5aZYlvMRJT0/fFhkZue3JZmfd3d0gEolOIr4ShPmEXjFpkFRqXlrzSnFnZ+d7Tk5OjzNfXVxcICMjY6ezszNnVdL6vU8HWhmbgKAIkrOzMyc1NTXz0YU4maAuOp0OK1as4EVFRfGEQqHg1dfePHzr1q2rs71S8WOF4f38/BLS09M/iIyM5DxdxLq5uVlcVVU1bgVwBIS5il4xAQCQyWRigUBwJikpKe3JVGQcDgdLly7l2tranti0ecf7IpEoy9hbxX6sMDydTvdevXr1ltjY2F3u7u6AxT73FJ7B3Nwc4uLiwthsdphQKCzZkL7l0/r6+oKbNeVG90+EhMXZL1++fFtycvKHrq6uz4igUqmE5ubmEiTHCWG+8dwrUXD9imz9xtd/jIuLS7N5KpsTjUZDUFCQE4PB+F4oFGYmJW888Mv5k4UTHGpGxC9LYaenp78VEhKyxdHRESgUyoyOh0KhwNraGuLi4qIDAgKi6+rqyjekb/mHMSN6N6RvSdu+ffseNpsdZm09ftuW+vp6EIvFSB9hhHnHpG7rUqm0orW1tdXS0tLj6TIEaDQaaDQaxMfH811dXTl/3Xfw+JUrVz411J01cfWG6IiIiC07d+5McHNzs7ewMGyOFw6HAwcHB6BSqVx3d/fwz7/4rkAgEBwXCoUnHpZonDGrU9J5MTEx27du3Zrm4uKC0beaqq6u/ry+vj7XEPMiIMwmkxKTimuXZe/u+fCkp6fnexPdUfF4PPj7+1szGIydLi4unF1/+kvenTt3RG1tbRXTqfma8lIG39/fP/HVV19NZrFYHpMpzjQTzMzMwNPTE+Pp6Zng6emZ4Ofnl5CesfV8bW1tznQe3/wDwvFeXl7Rvr6+Ca+88kpaUFCQh74GXzqdDrq7u6GpqankRQmdR1hYTNrhUFVVlcXj8d6ysrKy0OfstLS0hPj4eC6Xy+U2NzeDRCI5/sa2XeX37t1rGhwc7BoYGJBN1P+FFbiE5OzszGaxWImvvvrqpoCAAKfp+ERmCpPJBCaTmcnhcDJLS0u/TE59+YxUKhXoi/lg+oVgrKysGJaWlna2trYeaWlpXDabvTMgIGDSfp2KiorzbW1tL0zoPMLCYtJX6uVfs2u++PKowMPDgz+ZIslEIhECAgKAxWJlajSazJ6eHmhra4PW1tZvtmz9o6Czs7O+r6+vfWxsbFir1WosLCzsV6xYkcnj8d7z9vaelmPV0Hh5eYGnp+f2mJiY7UVFRZ/HL0v5tru7+5ZGo1FisVg8Docj4fF4CxsbG1c+nx/m7e39sYeHB7i4uIC5ufmU6r4ODQ1BZWXlifkSrYuA8DRTumIrKytPent78728vCb9HRQKBVgsFhwcHIBOpwObzd4yNja2RaVSwdDQEHR1dcHo6CjQaDRwdXWdsWPV0KBQKPDw8AA7O7udERERO2tra2FgYACoVCo4OTkBjUYDMpkMeDz+8WuqaLVaaGxsbL19+/YzSX8ICPOFqYrJidDQ0AwvLy/e80c/CwaDARKJBI86BdJoNHB3dwe1Wj0nViL6IJPJwGQywdnZGZRKJRAIBDBUx8OBgQEoLS39BtkORpjPTJg1PB61N64pmpqarvb39xvUiLkuJE9CJpPBxsbGYEICANDZ2SlHgtQQ5jtTEhMAgLq6ulyJRFJvDGNeREZGRkAikRSUFuci2cEI85opi0l+7hmBWCzOeV6dToTJcfv27cHr168jxbgR5j1TFhMAgObm5hKZDNl0MAQtLS3Xzpw6hkS8Isx7piUmUqlUIBAIJuyjgzA5Ojs7QSKRINGuCAuCaYmJsKKw68qVK59KJJIu5HFneiiVSigqKjouEolOmtoWBARDMC0xAQC4+MvPJadOnXq3ra1N8yL0dDEkOp0OSktLy/Pz8w8+3d4CAWG+Mm0xAQA4fuy/jl+8ePGju3fvGsqeBY9Wq4XKysrWU6dOvX31yi8mKyyFgGBoZiQmAAD/79D+fadPn96PCMrz0el0UFVV1frtt9+mj9fiAgFhPjNjMQEAyMvLO3Ds2LE/tLS0INmuerh27Vr9999//xoiJAgLEYOEntbVVigB4PNNm3cMpqSkfMRms50McdyFgkqlgqKiovJTp069nZ97BhEShAWJQePYj373xdF1GzbLFQrFx6Ghob766ne8KNy7dw+KiopO5ubmfmTK4tsICMbG4EkxWT99d35l4rre/v7+D0NCQvh0Ot3QU8wL1Go1SKVSTX5+/sH8/PyDSP8bhIWOUTLsLuVklQcFR65pbGzcvnLlyvfc3NwsCASCMaaac+h0OhgaGoLq6uqaCxcu/OV01tGcTw7uM7VZCAhGx2jpug/vxAd58atzoqKitq1cuXKnvb29saabE+h0Oqiurpbm5eUdrK6uPlspuDrvY0hmO4YIhUIBGq1/X2CmNqFQKL3/79HomZ/z82xEowyy9zFr80zGDqPn/hdeviBmL47ad+fOnRsRERGbQkNDo62srIw97azT2dkJxcXFx0tKSo7Mdh8hY4LD4TDPH2U4MFjMc6tLmZmZzaj+Aw6H0/t9PB4PGCxmRudNJBL0ngeZTAI0Gj3jv+1szfM88Hic8cUEAKCmqlQOAN/ELU2qkEgkySwWK3HRokVcBoMxG9MbDZ1OB83NzdDU1FRQW1t7XiAQHJ+ovu18pbr6Rg6L5ZtoM0EhcUPT0tJW8tWRb0vQqIkvgKqqmhnVfrl2TfANXo+gjKlUio4OWc1M5sjOzjnQUH8rbqLPu3t6moaGhmfc+3q25tGHUqmECoEIUKbIrVkcEkONiIh4jcvlvu7s7OxLo9GmVe7QVCgUCujq6oKGhoaCioqKo9XV1WeM3YDMVPDik1gpyas+XrVyeaKXl8czjyANjbcgI/MNmkg49Q4ECPOH3NyC4RUr+M8IcHt7B1y9WlKRl3/5kElKnD1sfXEoJCzueEBAQGJYWFgGk8nk2djYAIFAgLm4pTw6Ogqjo6Mgl8vhxo0b50tLS4/U19fnLvS2FIWXfxEDQNLmLW9ueW1TxtchHDaQyWRTm4VgYkZHR6G+vhF+/NfP+y5e+vVjiVgwZpKVydOwF0dZW1lZOTGZTD6bzU4LCAiIptPp8HTDL1MwOjoKLS0tUFdXd1IsFudIpdKKgYGB7tloJTrX4MUnsVJTEj9etzY10dHRAQAAGm81wcsZW5CVyQInL69gNCGBjwcAGBx8ANnncypOnTr3H9nn/reD55wovvrQpyIHAHFUzIocGo3mQaPRfBwdHVlubm7bXF1dgcFgABqNNvruglwuh7t374JMJoOOjo7P79y5I+ru7m7q7e1tXQi7MzOh8PIv4pCw2DdaWtte37Au7aPIyCWAxWABjUbPif9HCMbjURtKiaQBfvr5zH9evlJ0uLQ4r/nJMXNiZTIRrMAlJAcHB18HBweWo6Mjy8rKajeJRAJLS0uwtLQECwsLoFAogMfjAYvFgpmZ2XNXMyqVCoaHh2FoaAiGh4cfvwYGBqCvrw+6u7vfvnfvXlNvb29rT09Pq0QsUM7S6c4rNqS/lrZ5U+YPRBKR9M7u9xwqBUUvtNAudH766XSLE8PR49ixE78/8tVnX403Zk7fUR46NUUAIPIPCMdTKJTdNjY2QKPRgE6nA51OB1tbWyCRSIDD4YBAIAAejwcCgfDYUajVakGlUoFarQadTvfY79HX1wf9/f0gl8tBLpfDvXv3HvXw+dxQPYYXMj+d+P7Mmzv+5OHr6/OJWq1GBHeB09TcUiKuq/coKS3/eqIx/wPkiIXC3w6YjAAAAABJRU5ErkJggg=="); - - --keyword: #ff79c6; - --identifier: #f8f8f2; - --comment: #6272a4; - --operator: #ff79c6; - --punctuation: #f8f8f2; - --other: #f8f8f2; - --escapeSequence: #bd93f9; - --number: #bd93f9; - --literal: #f1fa8c; - --program: #9090c0; - --option: #90b010; - --raw-data: #8be9fd; - - --clipboard-image-normal: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' style='color: lightgray' fill='none' viewBox='0 0 24 24' stroke='currentColor'%3E %3Cpath stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2' /%3E %3C/svg%3E"); - --clipboard-image-selected: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' style='color: lightgray' viewBox='0 0 20 20' fill='currentColor'%3E %3Cpath d='M8 3a1 1 0 011-1h2a1 1 0 110 2H9a1 1 0 01-1-1z' /%3E %3Cpath d='M6 3a2 2 0 00-2 2v11a2 2 0 002 2h8a2 2 0 002-2V5a2 2 0 00-2-2 3 3 0 01-3 3H9a3 3 0 01-3-3z' /%3E %3C/svg%3E"); - --clipboard-image: var(--clipboard-image-normal); - } -} - -.theme-select-wrapper { - display: flex; - align-items: center; -} - -html { - font-size: 100%; - -webkit-text-size-adjust: 100%; - -ms-text-size-adjust: 100%; } - -body { - font-family: "Lato", "Helvetica Neue", "HelveticaNeue", Helvetica, Arial, sans-serif; - font-weight: 400; - font-size: 1.125em; - line-height: 1.5; - color: var(--text); - background-color: var(--primary-background); } - -/* Skeleton grid */ -.container { - position: relative; - width: 100%; - max-width: 1050px; - margin: 0 auto; - padding: 0; - box-sizing: border-box; } - -.column, .columns { - width: 100%; - float: left; - box-sizing: border-box; - margin-left: 1%; } - -@media print { - #global-links, .link-seesrc, .theme-switch-wrapper, #searchInputDiv, .search-groupby { - display:none; - } - .columns { - width:100% !important; - } -} - -.column:first-child, .columns:first-child { - margin-left: 0; } - -.container .row { - display: flex; } - -.three.columns { - width: 25.0%; - height: 100vh; - position: sticky; - top: 0px; - overflow-y: auto; - padding: 2px; -} - -.nine.columns { - width: 75.0%; - padding-left: 1.5em; } - -.twelve.columns { - width: 100%; - margin-left: 0; } - -@media screen and (max-width: 860px) { - .three.columns { - display: none; - } - .nine.columns { - width: 98.0%; - } - body { - font-size: 1em; - line-height: 1.35; - } -} - -cite { - font-style: italic !important; } - - -/* Nim search input */ -div#searchInputDiv { - margin-bottom: 1em; -} -input#searchInput { - width: 80%; -} - -/* - * Some custom formatting for input forms. - * This also fixes input form colors on Firefox with a dark system theme on Linux. - */ -input { - -moz-appearance: none; - background-color: var(--secondary-background); - color: var(--text); - border: 1px solid var(--border); - font-family: "Lato", "Helvetica Neue", "HelveticaNeue", Helvetica, Arial, sans-serif; - font-size: 0.9em; - padding: 6px; -} - -input:focus { - border: 1px solid var(--input-focus); - box-shadow: 0 0 3px var(--input-focus); -} - -select { - -moz-appearance: none; - background-color: var(--secondary-background); - color: var(--text); - border: 1px solid var(--border); - font-family: "Lato", "Helvetica Neue", "HelveticaNeue", Helvetica, Arial, sans-serif; - font-size: 0.9em; - padding: 6px; -} - -select:focus { - border: 1px solid var(--input-focus); - box-shadow: 0 0 3px var(--input-focus); -} - -/* Docgen styles */ - -:target { - border: 2px solid #B5651D; - border-style: dotted; -} - -/* Links */ -a { - color: var(--anchor); - text-decoration: none; -} - -a span.Identifier { - text-decoration: underline; - text-decoration-color: #aab; -} - -a.reference-toplevel { - font-weight: bold; -} - -a.nimdoc { - word-spacing: 0.3em; -} - -a.toc-backref { - text-decoration: none; - color: var(--text); -} - -a.link-seesrc { - color: #607c9f; - font-size: 0.9em; - font-style: italic; -} - -a:hover, a:focus { - color: var(--anchor-focus); - text-decoration: underline; -} - -a:hover span.Identifier { - color: var(--anchor); -} - - -sub, sup { - position: relative; - font-size: 75%; - line-height: 0; - vertical-align: baseline; } - -sup { - top: -0.5em; } - -sub { - bottom: -0.25em; } - -img { - width: auto; - height: auto; - max-width: 100%; - vertical-align: middle; - border: 0; - -ms-interpolation-mode: bicubic; } - -@media print { - * { - color: black !important; - text-shadow: none !important; - background: transparent !important; - box-shadow: none !important; } - - a, a:visited { - text-decoration: underline; } - - a[href]:after { - content: " (" attr(href) ")"; } - - abbr[title]:after { - content: " (" attr(title) ")"; } - - .ir a:after, - a[href^="javascript:"]:after, - a[href^="#"]:after { - content: ""; } - - pre, blockquote { - border: 1px solid #999; - page-break-inside: avoid; } - - thead { - display: table-header-group; } - - tr, img { - page-break-inside: avoid; } - - img { - max-width: 100% !important; } - - @page { - margin: 0.5cm; } - - h1 { - page-break-before: always; } - - h1.title { - page-break-before: avoid; } - - p, h2, h3 { - orphans: 3; - widows: 3; } - - h2, h3 { - page-break-after: avoid; } -} - - -p { - margin-top: 0.5em; - margin-bottom: 0.5em; } - -small { - font-size: 85%; } - -strong { - font-weight: 600; - font-size: 0.95em; - color: var(--strong); } - -em { - font-style: italic; } - -h1 { - font-size: 1.8em; - font-weight: 400; - padding-bottom: .25em; - border-bottom: 6px solid var(--third-background); - margin-top: 2.5em; - margin-bottom: 1em; - line-height: 1.2em; } - -h1.title { - padding-bottom: 1em; - border-bottom: 0px; - font-size: 2.5em; - text-align: center; - font-weight: 900; - margin-top: 0.75em; - margin-bottom: 0em; } - -h2 { - font-size: 1.3em; - margin-top: 2em; } - -h2.subtitle { - margin-top: 0em; - text-align: center; } - -h3 { - font-size: 1.125em; - font-style: italic; - margin-top: 1.5em; } - -h4 { - font-size: 1.125em; - margin-top: 1em; } - -h5 { - font-size: 1.125em; - margin-top: 0.75em; } - -h6 { - font-size: 1.1em; } - - -ul, ol { - padding: 0; - margin-top: 0.5em; - margin-left: 0.75em; } - -ul ul, ul ol, ol ol, ol ul { - margin-bottom: 0; - margin-left: 1.25em; } - -ul.simple > li { - list-style-type: circle; } - -ul.simple-boot li { - list-style-type: none; - margin-left: 0em; - margin-bottom: 0.5em; } - -ol.simple > li, ul.simple > li { - margin-bottom: 0.2em; - margin-left: 0.4em } - -ul.simple.simple-toc > li { - margin-top: 1em; } - -ul.simple-toc { - list-style: none; - font-size: 0.9em; - margin-left: -0.3em; - margin-top: 1em; } - -ul.simple-toc > li { - list-style-type: none; } - -ul.simple-toc-section { - list-style-type: circle; - margin-left: 0.8em; - color: #6c9aae; } - -ul.nested-toc-section { - list-style-type: circle; - margin-left: -0.75em; - color: var(--text); } - -ul.nested-toc-section > li { - margin-left: 1.25em; } - - -ol.arabic { - list-style: decimal; } - -ol.loweralpha { - list-style: lower-alpha; } - -ol.upperalpha { - list-style: upper-alpha; } - -ol.lowerroman { - list-style: lower-roman; } - -ol.upperroman { - list-style: upper-roman; } - -ul.auto-toc { - list-style-type: none; } - - -dl { - margin-bottom: 1.5em; } - -dt { - margin-bottom: -0.5em; - margin-left: 0.0em; } - -dd { - margin-left: 2.0em; - margin-bottom: 3.0em; - margin-top: 0.5em; } - - -hr { - margin: 2em 0; - border: 0; - border-top: 1px solid #aaa; } - -hr.footnote { - width: 25%; - border-top: 0.15em solid #999; - margin-bottom: 0.15em; - margin-top: 0.15em; -} -div.footnote-group { - margin-left: 1em; -} -div.footnote-label { - display: inline-block; - min-width: 1.7em; -} - -div.option-list { - border: 0.1em solid var(--border); -} -div.option-list-item { - padding-left: 12em; - padding-right: 0; - padding-bottom: 0.3em; - padding-top: 0.3em; -} -div.odd { - background-color: var(--secondary-background); -} -div.option-list-label { - margin-left: -11.5em; - margin-right: 0em; - min-width: 11.5em; - display: inline-block; - vertical-align: top; -} -div.option-list-description { - width: calc(100% - 1em); - padding-left: 1em; - padding-right: 0; - display: inline-block; -} - -blockquote { - font-size: 0.9em; - font-style: italic; - padding-left: 0.5em; - margin-left: 0; - border-left: 5px solid #bbc; -} - -blockquote.markdown-quote { - font-size: 0.9rem; /* use rem to avoid recursion */ - font-style: normal; -} - -.pre, span.tok { - font-family: "Source Code Pro", Monaco, Menlo, Consolas, "Courier New", monospace; - font-weight: 500; - font-size: 0.85em; - color: var(--text); - background-color: var(--third-background); - padding-left: 3px; - padding-right: 3px; - border-radius: 4px; -} - -span.tok { - border: 1px solid #808080; - padding-bottom: 0.1em; - margin-right: 0.2em; -} - -.copyToClipBoard { - position: relative; -} - -pre { - font-family: "Source Code Pro", Monaco, Menlo, Consolas, "Courier New", monospace; - color: var(--text); - font-weight: 500; - display: inline-block; - box-sizing: border-box; - min-width: 100%; - padding: 0.5em; - margin-top: 0.5em; - margin-bottom: 0.5em; - font-size: 0.85em; - white-space: pre !important; - overflow-y: hidden; - overflow-x: visible; - background-color: var(--secondary-background); - border: 1px solid var(--border); - -webkit-border-radius: 6px; - -moz-border-radius: 6px; - border-radius: 6px; -} - -.copyToClipBoardBtn { - visibility: hidden; - position: absolute; - width: 24px; - border-radius: 4px; - background-image: var(--clipboard-image); - right: 5px; - top: 13px; - background-color: var(--secondary-background); - padding: 11px; - border: 0; -} - -.copyToClipBoard:hover .copyToClipBoardBtn { - visibility: visible; -} - -.pre-scrollable { - max-height: 340px; - overflow-y: scroll; } - - -/* Nim line-numbered tables */ -.line-nums-table { - width: 100%; - table-layout: fixed; } - -table.line-nums-table { - border-radius: 4px; - border: 1px solid #cccccc; - background-color: ghostwhite; - border-collapse: separate; - margin-top: 15px; - margin-bottom: 25px; } - -.line-nums-table tbody { - border: none; } - -.line-nums-table td pre { - border: none; - background-color: transparent; } - -.line-nums-table td.blob-line-nums { - width: 28px; } - -.line-nums-table td.blob-line-nums pre { - color: #b0b0b0; - -webkit-filter: opacity(75%); - filter: opacity(75%); - text-align: right; - border-color: transparent; - background-color: transparent; - padding-left: 0px; - margin-left: 0px; - padding-right: 0px; - margin-right: 0px; } - - -table { - max-width: 100%; - background-color: transparent; - margin-top: 0.5em; - margin-bottom: 1.5em; - border-collapse: collapse; - border-color: var(--third-background); - border-spacing: 0; - font-size: 0.9em; -} - -table th, table td { - padding: 0px 0.5em 0px; - border-color: var(--third-background); -} - -table th { - background-color: var(--third-background); - border-color: var(--third-background); - font-weight: bold; } - -table th.docinfo-name { - background-color: transparent; - text-align: right; -} - -table tr:hover { - background-color: var(--third-background); } - - -/* rst2html default used to remove borders from tables and images */ -.borderless, table.borderless td, table.borderless th { - border: 0; } - -table.borderless td, table.borderless th { - /* Override padding for "table.docutils td" with "! important". - The right padding separates the table cells. */ - padding: 0 0.5em 0 0 !important; } - -.admonition { - padding: 0.3em; - background-color: var(--secondary-background); - border-left: 0.4em solid #7f7f84; - margin-bottom: 0.5em; - -webkit-box-shadow: 0 5px 8px -6px rgba(0,0,0,.2); - -moz-box-shadow: 0 5px 8px -6px rgba(0,0,0,.2); - box-shadow: 0 5px 8px -6px rgba(0,0,0,.2); -} -.admonition-info { - border-color: var(--info-background); -} -.admonition-info-text { - color: var(--info-background); -} -.admonition-warning { - border-color: var(--warning-background); -} -.admonition-warning-text { - color: var(--warning-background); -} -.admonition-error { - border-color: var(--error-background); -} -.admonition-error-text { - color: var(--error-background); -} - -.first { - /* Override more specific margin styles with "! important". */ - margin-top: 0 !important; } - -.last, .with-subtitle { - margin-bottom: 0 !important; } - -.hidden { - display: none; } - -blockquote.epigraph { - margin: 2em 5em; } - -dl.docutils dd { - margin-bottom: 0.5em; } - -object[type="image/svg+xml"], object[type="application/x-shockwave-flash"] { - overflow: hidden; } - - -div.figure { - margin-left: 2em; - margin-right: 2em; } - -div.footer, div.header { - clear: both; - text-align: center; - color: #666; - font-size: smaller; } - -div.footer { - padding-top: 5em; } - -div.line-block { - display: block; - margin-top: 1em; - margin-bottom: 1em; } - -div.line-block div.line-block { - margin-top: 0; - margin-bottom: 0; - margin-left: 1.5em; } - -div.topic { - margin: 2em; } - -div.search_results { - background-color: var(--third-background); - margin: 3em; - padding: 1em; - border: 1px solid #4d4d4d; } - -div#global-links ul { - margin-left: 0; - list-style-type: none; } - -div#global-links > simple-boot { - margin-left: 3em; } - -hr.docutils { - width: 75%; } - -img.align-left, .figure.align-left, object.align-left { - clear: left; - float: left; - margin-right: 1em; } - -img.align-right, .figure.align-right, object.align-right { - clear: right; - float: right; - margin-left: 1em; } - -img.align-center, .figure.align-center, object.align-center { - display: block; - margin-left: auto; - margin-right: auto; } - -.align-left { - text-align: left; } - -.align-center { - clear: both; - text-align: center; } - -.align-right { - text-align: right; } - -/* reset inner alignment in figures */ -div.align-right { - text-align: inherit; } - -p.attribution { - text-align: right; - margin-left: 50%; } - -p.caption { - font-style: italic; } - -p.credits { - font-style: italic; - font-size: smaller; } - -p.label { - white-space: nowrap; } - -p.rubric { - font-weight: bold; - font-size: larger; - color: maroon; - text-align: center; } - -p.topic-title { - font-weight: bold; } - -pre.address { - margin-bottom: 0; - margin-top: 0; - font: inherit; } - -pre.literal-block, pre.doctest-block, pre.math, pre.code { - margin-left: 2em; - margin-right: 2em; } - -pre.code .ln { - color: grey; } - -/* line numbers */ -pre.code, code { - background-color: #eeeeee; } - -pre.code .comment, code .comment { - color: #5c6576; } - -pre.code .keyword, code .keyword { - color: #3B0D06; - font-weight: bold; } - -pre.code .literal.string, code .literal.string { - color: #0c5404; } - -pre.code .name.builtin, code .name.builtin { - color: #352b84; } - -pre.code .deleted, code .deleted { - background-color: #DEB0A1; } - -pre.code .inserted, code .inserted { - background-color: #A3D289; } - -span.classifier { - font-style: oblique; } - -span.classifier-delimiter { - font-weight: bold; } - -span.problematic { - color: #b30000; } - -span.section-subtitle { - /* font-size relative to parent (h1..h6 element) */ - font-size: 80%; } - -span.DecNumber { - color: var(--number); } - -span.BinNumber { - color: var(--number); } - -span.HexNumber { - color: var(--number); } - -span.OctNumber { - color: var(--number); } - -span.FloatNumber { - color: var(--number); } - -span.Identifier { - color: var(--identifier); } - -span.Keyword { - font-weight: 600; - color: var(--keyword); } - -span.StringLit { - color: var(--literal); } - -span.LongStringLit { - color: var(--literal); } - -span.CharLit { - color: var(--literal); } - -span.EscapeSequence { - color: var(--escapeSequence); } - -span.Operator { - color: var(--operator); } - -span.Punctuation { - color: var(--punctuation); } - -span.Comment, span.LongComment { - font-style: italic; - font-weight: 400; - color: var(--comment); } - -span.RegularExpression { - color: darkviolet; } - -span.TagStart { - color: darkviolet; } - -span.TagEnd { - color: darkviolet; } - -span.Key { - color: #252dbe; } - -span.Value { - color: #252dbe; } - -span.RawData { - color: var(--raw-data); } - -span.Assembler { - color: #252dbe; } - -span.Preprocessor { - color: #252dbe; } - -span.Directive { - color: #252dbe; } - -span.option { - font-weight: bold; - font-family: "Source Code Pro", Monaco, Menlo, Consolas, "Courier New", monospace; - color: var(--option); } - -span.Prompt { - font-weight: bold; - color: red; } - -span.ProgramOutput { - font-weight: bold; - color: #808080; } - -span.program { - font-weight: bold; - color: var(--program); - text-decoration: underline; - text-decoration-color: var(--hint); - text-decoration-thickness: 0.05em; - text-underline-offset: 0.15em; } - -span.Command, span.Rule, span.Hyperlink, -span.Label, span.Reference, span.Other { - color: var(--other); } - -/* Pop type, const, proc, and iterator defs in nim def blocks */ -dt pre > span.Identifier, dt pre > span.Operator { - color: var(--identifier); - font-weight: 700; } - -dt pre > span.Keyword ~ span.Identifier, dt pre > span.Identifier ~ span.Identifier, -dt pre > span.Operator ~ span.Identifier, dt pre > span.Other ~ span.Identifier { - color: var(--identifier); - font-weight: inherit; } - -/* Nim sprite for the footer (taken from main page favicon) */ -.nim-sprite { - display: inline-block; - width: 51px; - height: 14px; - background-position: 0 0; - background-size: 51px 14px; - -webkit-filter: opacity(50%); - filter: opacity(50%); - background-repeat: no-repeat; - background-image: var(--nim-sprite-base64); - margin-bottom: 5px; } - -span.pragmadots { - /* Position: relative frees us up to make the dots - look really nice without fucking up the layout and - causing bulging in the parent container */ - position: relative; - /* 1px down looks slightly nicer */ - top: 1px; - padding: 2px; - background-color: var(--third-background); - border-radius: 4px; - margin: 0 2px; - cursor: pointer; - font-size: 0.8em; } - -span.pragmadots:hover { - background-color: var(--hint); } - -span.pragmawrap { - display: none; } - -span.attachedType { - display: none; - visibility: hidden; } diff --git a/nimdoc/testproject/expected/subdir/subdir_b/utils.html b/nimdoc/testproject/expected/subdir/subdir_b/utils.html index ee2618ab3..75cb2508f 100644 --- a/nimdoc/testproject/expected/subdir/subdir_b/utils.html +++ b/nimdoc/testproject/expected/subdir/subdir_b/utils.html @@ -1,209 +1,142 @@ - + - + + -subdir/subdir_b/utils + + + + +subdir/subdir_b/utils - - + + + + - -
    -
    -

    subdir/subdir_b/utils

    -
    + +
    +
    +

    subdir/subdir_b/utils

    +
    -
    - - -
    - -
    - Search: -
    -
    - Group by: - -
    -
  • -
    - Iterators -
    -
  • -
  • -
    - Templates - -
    +
  • - -
    - -

    This is a description of the utils module.

    -

    Links work:

    - - +
    + +

    This is now a header

    Next header

    And so on

    @@ -215,391 +148,64 @@
    1. Other case value
    2. Second case.
    -

    Ref group fn2 or specific function like fn2() or fn2( int ) or fn2(int, float).

    -

    Ref generics like this: binarySearch or binarySearch(openArray[T], K, proc (T, K)) or proc binarySearch(openArray[T], K, proc (T, K)) or in different style: proc binarysearch(openarray[T], K, proc(T, K)). Can be combined with export symbols and type parameters: binarysearch*[T, K](openArray[T], K, proc (T, K)). With spaces binary search.

    -

    Note that proc can be used in postfix form: binarySearch proc.

    -

    Ref. type like G and type G and G[T] and type G*[T].

    -

    Group ref. with capital letters works: fN11 or fn11

    -Ref. [] is the same as proc `[]`(G[T]) because there are no overloads. The full form: proc `[]`*[T](x: G[T]): TRef. []= aka `[]=`(G[T], int, T).Ref. $ aka proc $ or proc `$`.Ref. $(a: ref SomeType).Ref. foo_bar aka iterator foo_bar_.Ref. fn[T; U,V: SomeFloat]().Ref. 'big or func `'big` or `'big`(string). -

    Pandoc Markdown

    Now repeat all the auto links of above in Pandoc Markdown Syntax.

    -

    Ref group fn2 or specific function like fn2() or fn2( int ) or fn2(int, float).

    -

    Ref generics like this: binarySearch or binarySearch(openArray[T], K, proc (T, K)) or proc binarySearch(openArray[T], K, proc (T, K)) or in different style: proc binarysearch(openarray[T], K, proc(T, K)). Can be combined with export symbols and type parameters: binarysearch*[T, K](openArray[T], K, proc (T, K)). With spaces binary search.

    -

    Note that proc can be used in postfix form: binarySearch proc.

    -

    Ref. type like G and type G and G[T] and type G*[T].

    -

    Group ref. with capital letters works: fN11 or fn11

    -

    Ref. `[]` is the same as proc `[]`(G[T]) because there are no overloads. The full form: proc `[]`*[T](x: G[T]): T Ref. `[]=` aka `[]=`(G[T], int, T). Ref. $ aka proc $ or proc `$`. Ref. $(a: ref SomeType). Ref. foo_bar aka iterator foo_bar_. Ref. fn[T; U,V: SomeFloat](). Ref. 'big or func `'big` or `'big`(string).

    - -

    Link name syntax

    Pandoc Markdown has synax for changing text of links: Ref. this proc or another symbol.

    - -

    Symbols documentation

    Let us repeat auto links from symbols section below:

    -

    There is also variant f(G[string]). See also f(G[int]).

    -
    -

    Types

    -
    -
    -
    G[T] = object
    -  
    -
    - - - -
    -
    -
    -
    SomeType = enum
    +  
    +

    Types

    +
    + +
    SomeType = enum
       enumValueA, enumValueB, enumValueC
    -
    - - - -
    -
    +
    -
    -
    + + + + +
    -

    Procs

    -
    -
    -
    -
    proc `$`[T](a: G[T]): string
    -
    - - - -
    -
    -
    -
    proc `$`[T](a: ref SomeType): string
    -
    - - - -
    -
    +

    Procs

    +
    + +
    proc someType(): SomeType {...}{.raises: [], tags: [].}
    +
    -
    -
    -
    -
    func `'big`(a: string): SomeType {....raises: [], tags: [], forbids: [].}
    -
    - - - -
    -
    +constructor. -
    -
    -
    -
    proc `[]`[T](x: G[T]): T
    -
    - - - -
    -
    + -
    -
    -
    -
    proc `[]=`[T](a: var G[T]; index: int; value: T)
    -
    - - - -
    -
    - -
    -
    -
    -
    proc binarySearch[T, K](a: openArray[T]; key: K;
    -                        cmp: proc (x: T; y: K): int {.closure.}): int
    -
    - - - -
    -
    - -
    -
    -
    -
    proc f(x: G[int]) {....raises: [], tags: [], forbids: [].}
    -
    - - There is also variant f(G[string]) - -
    -
    -
    -
    proc f(x: G[string]) {....raises: [], tags: [], forbids: [].}
    -
    - - See also f(G[int]). - -
    -
    - -
    -
    -
    -
    proc fn[T; U, V: SomeFloat]()
    -
    - - - -
    -
    - -
    -
    -
    -
    proc fn2() {....raises: [], tags: [], forbids: [].}
    -
    - - comment - -
    -
    -
    -
    proc fn2(x: int) {....raises: [], tags: [], forbids: [].}
    -
    - - fn2 comment - -
    -
    -
    -
    proc fn2(x: int; y: float) {....raises: [], tags: [], forbids: [].}
    -
    - - - -
    -
    - -
    -
    -
    -
    proc fn3(): auto {....raises: [], tags: [], forbids: [].}
    -
    - - comment - -
    -
    - -
    -
    -
    -
    proc fn4(): auto {....raises: [], tags: [], forbids: [].}
    -
    - - comment - -
    -
    - -
    -
    -
    -
    proc fn5() {....raises: [], tags: [], forbids: [].}
    -
    - - comment - -
    -
    - -
    -
    -
    -
    proc fn6() {....raises: [], tags: [], forbids: [].}
    -
    - - comment - -
    -
    - -
    -
    -
    -
    proc fn7() {....raises: [], tags: [], forbids: [].}
    -
    - - comment - -
    -
    - -
    -
    -
    -
    proc fn8(): auto {....raises: [], tags: [], forbids: [].}
    -
    - - comment - -
    -
    - -
    -
    -
    -
    func fn9(a: int): int {....raises: [], tags: [], forbids: [].}
    -
    - - comment - -
    -
    - -
    -
    -
    -
    func fn10(a: int): int {....raises: [], tags: [], forbids: [].}
    -
    - - comment - -
    -
    - -
    -
    -
    -
    func fN11() {....raises: [], tags: [], forbids: [].}
    -
    - - - -
    -
    -
    -
    func fN11(x: int) {....raises: [], tags: [], forbids: [].}
    -
    - - - -
    -
    - -
    -
    -
    -
    proc funWithGenerics[T, U: SomeFloat](a: T; b: U)
    -
    - - - -
    -
    - -
    -
    -
    -
    proc someType(): SomeType {....raises: [], tags: [], forbids: [].}
    -
    - - constructor. - -
    -
    - -
    - -
    -
    -
    -

    Iterators

    -
    -
    -
    -
    iterator fooBar(a: seq[SomeType]): int {....raises: [], tags: [], forbids: [].}
    -
    - - - -
    -
    - -
    - -
    -
    +
    -

    Templates

    -
    -
    -
    -
    template aEnum(): untyped
    -
    - - - -
    -
    +

    Templates

    +
    + +
    template aEnum(): untyped
    +
    -
    -
    -
    -
    template bEnum(): untyped
    -
    - - - -
    -
    -
    -
    -
    -
    template fromUtilsGen(): untyped
    -
    - - should be shown in utils.html only -

    Example:

    -
    discard "should be in utils.html only, not in module that calls fromUtilsGen"
    ditto - -
    -
    -
    + + +
    template bEnum(): untyped
    +
    -
    -
    + + + + + +
    - - - - + + diff --git a/nimdoc/testproject/expected/subdir/subdir_b/utils.idx b/nimdoc/testproject/expected/subdir/subdir_b/utils.idx deleted file mode 100644 index 81c2103e4..000000000 --- a/nimdoc/testproject/expected/subdir/subdir_b/utils.idx +++ /dev/null @@ -1,46 +0,0 @@ -nimTitle utils subdir/subdir_b/utils.html module subdir/subdir_b/utils 0 -nim funWithGenerics subdir/subdir_b/utils.html#funWithGenerics,T,U proc funWithGenerics[T, U: SomeFloat](a: T; b: U) 1 -nim enumValueA subdir/subdir_b/utils.html#enumValueA SomeType.enumValueA 45 -nim enumValueB subdir/subdir_b/utils.html#enumValueB SomeType.enumValueB 45 -nim enumValueC subdir/subdir_b/utils.html#enumValueC SomeType.enumValueC 45 -nim SomeType subdir/subdir_b/utils.html#SomeType enum SomeType 45 -nim G subdir/subdir_b/utils.html#G object G 49 -nim someType subdir/subdir_b/utils.html#someType_2 proc someType(): SomeType 52 -nim fn2 subdir/subdir_b/utils.html#fn2 proc fn2() 57 -nim fn2 subdir/subdir_b/utils.html#fn2,int proc fn2(x: int) 58 -nim fn2 subdir/subdir_b/utils.html#fn2,int,float proc fn2(x: int; y: float) 61 -nim binarySearch subdir/subdir_b/utils.html#binarySearch,openArray[T],K,proc(T,K) proc binarySearch[T, K](a: openArray[T]; key: K;\n cmp: proc (x: T; y: K): int {.closure.}): int 63 -nim fn3 subdir/subdir_b/utils.html#fn3 proc fn3(): auto 66 -nim fn4 subdir/subdir_b/utils.html#fn4 proc fn4(): auto 67 -nim fn5 subdir/subdir_b/utils.html#fn5 proc fn5() 68 -nim fn6 subdir/subdir_b/utils.html#fn6 proc fn6() 70 -nim fn7 subdir/subdir_b/utils.html#fn7 proc fn7() 72 -nim fn8 subdir/subdir_b/utils.html#fn8 proc fn8(): auto 75 -nim fn9 subdir/subdir_b/utils.html#fn9,int proc fn9(a: int): int 78 -nim fn10 subdir/subdir_b/utils.html#fn10,int proc fn10(a: int): int 79 -nim fN11 subdir/subdir_b/utils.html#fN11 proc fN11() 85 -nim fN11 subdir/subdir_b/utils.html#fN11,int proc fN11(x: int) 86 -nim aEnum subdir/subdir_b/utils.html#aEnum.t template aEnum(): untyped 90 -nim bEnum subdir/subdir_b/utils.html#bEnum.t template bEnum(): untyped 95 -nim fromUtilsGen subdir/subdir_b/utils.html#fromUtilsGen.t template fromUtilsGen(): untyped 106 -nim f subdir/subdir_b/utils.html#f,G[int] proc f(x: G[int]) 130 -nim f subdir/subdir_b/utils.html#f,G[string] proc f(x: G[string]) 133 -nim `[]` subdir/subdir_b/utils.html#[],G[T] proc `[]`[T](x: G[T]): T 140 -nim `[]=` subdir/subdir_b/utils.html#[]=,G[T],int,T proc `[]=`[T](a: var G[T]; index: int; value: T) 144 -nim `$` subdir/subdir_b/utils.html#$,G[T] proc `$`[T](a: G[T]): string 148 -nim `$` subdir/subdir_b/utils.html#$,ref.SomeType proc `$`[T](a: ref SomeType): string 152 -nim fooBar subdir/subdir_b/utils.html#fooBar.i,seq[SomeType] iterator fooBar(a: seq[SomeType]): int 156 -nim fn subdir/subdir_b/utils.html#fn proc fn[T; U, V: SomeFloat]() 160 -nim `'big` subdir/subdir_b/utils.html#'big,string proc `'big`(a: string): SomeType 164 -nimgrp $ subdir/subdir_b/utils.html#$-procs-all proc 148 -nimgrp fn11 subdir/subdir_b/utils.html#fN11-procs-all proc 85 -nimgrp fn2 subdir/subdir_b/utils.html#fn2-procs-all proc 57 -nimgrp f subdir/subdir_b/utils.html#f-procs-all proc 130 -heading This is now a header subdir/subdir_b/utils.html#this-is-now-a-header This is now a header 0 -heading Next header subdir/subdir_b/utils.html#this-is-now-a-header-next-header Next header 0 -heading And so on subdir/subdir_b/utils.html#next-header-and-so-on And so on 0 -heading More headers subdir/subdir_b/utils.html#more-headers More headers 0 -heading Up to level 6 subdir/subdir_b/utils.html#more-headers-up-to-level-6 Up to level 6 0 -heading Pandoc Markdown subdir/subdir_b/utils.html#pandoc-markdown Pandoc Markdown 0 -heading Link name syntax subdir/subdir_b/utils.html#pandoc-markdown-link-name-syntax Link name syntax 0 -heading Symbols documentation subdir/subdir_b/utils.html#pandoc-markdown-symbols-documentation Symbols documentation 0 diff --git a/nimdoc/testproject/expected/testproject.html b/nimdoc/testproject/expected/testproject.html index 45a53bb93..77f178265 100644 --- a/nimdoc/testproject/expected/testproject.html +++ b/nimdoc/testproject/expected/testproject.html @@ -1,1208 +1,355 @@ - + - + + -testproject + + + + +testproject - + + + - -
    -
    -

    testproject

    -
    + +
    +
    +

    testproject

    +
    -
    - - -
    - -
    - Search: -
    -
    - Group by: - -
    -
  • -
    - Consts -
    +
  • -
    - Procs -
    +
  • -
    - Methods -
    +
  • -
    - Iterators -
    +
  • -
    - Macros -
    -
  • -
  • -
    - Templates - -
    +
  • - -
    - -

    This is the top level module. -

    Example:

    -
    import testproject
    -import subdir / subdir_b / utils
    -doAssert bar(3, 4) == 7
    -foo(enumValueA, enumValueB)
    -# bug #11078
    -for x in "xx": discard
    top2 -

    Example:

    -
    import testproject
    -discard "in top2"
    top2 after -

    Example:

    -
    import testproject
    -discard "in top3"
    top3 after

    - +
    + +

    This is the top level module. +

    Examples:

    +
    import
    +  subdir / subdir_b / utils
    +
    +doAssert bar(3, 4) == 7
    +foo(enumValueA, enumValueB)
    +for x in "xx":
    +  discard

    +
    -

    Types

    -
    -
    -
    A {.inject.} = enum
    +

    Types

    +
    + +
    A {...}{.inject.} = enum
       aA
    -
    - - The enum A. - -
    -
    -
    -
    B {.inject.} = enum
    +
    + +The enum A. + +
    + +
    B {...}{.inject.} = enum
       bB
    -
    - - The enum B. - -
    -
    -
    -
    Foo = enum
    -  enumValueA2
    -
    - - - -
    -
    -
    -
    FooBuzz {....deprecated: "FooBuzz msg".} = int
    -
    -
    - Deprecated: FooBuzz msg -
    +
    - - -
    -
    -
    -
    Shapes = enum
    -  Circle,                   ## A circle
    -  Triangle,                 ## A three-sided shape
    -  Rectangle                  ## A four-sided shape
    -
    - - Some shapes. - -
    -
    -
    -
    T19396 = object
    -  a*: int
    -
    -
    - - - -
    -
    +The enum B. -
    -
    + + +
    -

    Vars

    -
    -
    -
    aVariable: array[1, int]
    -
    - - - -
    -
    -
    -
    someVariable: bool
    -
    - - This should be visible. - -
    -
    +

    Vars

    +
    + +
    aVariable: array[1, int]
    +
    -
    -
    + + + + +
    -

    Consts

    -
    -
    -
    C_A = 0x7FF0000000000000'f64
    -
    - - - -
    -
    -
    -
    C_B = 0o377'i8
    -
    - - - -
    -
    -
    -
    C_C = 0o277'i8
    -
    - - - -
    -
    -
    -
    C_D = 0o177777'i16
    -
    - - - -
    -
    +

    Consts

    +
    + +
    C_A = 0x7FF0000000000000'f64
    +
    -
    -
    + + + + +
    C_B = 0o377'i8
    +
    + + + +
    + +
    C_C = 0o277'i8
    +
    + + + +
    + +
    C_D = 0o177777'i16
    +
    + + + +
    + +
    -

    Procs

    -
    -
    -
    -
    proc addfBug14485() {....raises: [], tags: [], forbids: [].}
    -
    - - Some proc -

    Example:

    -
    discard "foo() = " & $[1]
    -#[
    -0: let's also add some broken html to make sure this won't break in future
    -1: </span>
    -2: </span>
    -3: </span
    -4: </script>
    -5: </script
    -6: </script
    -7: end of broken html
    -]#
    - -
    -
    +

    Procs

    +
    + +
    proc bar[T](a, b: T): T
    +
    -
    -
    -
    -
    proc anything() {....raises: [], tags: [], forbids: [].}
    -
    - - There is no block quote after blank lines at the beginning. - -
    -
    -
    -
    -
    -
    proc asyncFun1(): Future[int] {....stackTrace: false,
    -                                raises: [Exception, ValueError],
    -                                tags: [RootEffect], forbids: [].}
    -
    - - ok1 - -
    -
    -
    -
    -
    -
    proc asyncFun2(): owned(Future[void]) {....stackTrace: false, raises: [Exception],
    -                                        tags: [RootEffect], forbids: [].}
    -
    - - - -
    -
    + + +
    proc baz[T](a, b: T): T {...}{.deprecated.}
    +
    +
    + Deprecated +
    -
    -
    -
    -
    proc asyncFun3(): owned(Future[void]) {....stackTrace: false, raises: [Exception],
    -                                        tags: [RootEffect], forbids: [].}
    -
    - - -

    Example:

    -
    discard
    ok1 - -
    -
    +This is deprecated without message. -
    -
    -
    -
    proc bar(f: FooBuzz) {....raises: [], tags: [], forbids: [].}
    -
    - - - -
    -
    -
    -
    proc bar[T](a, b: T): T
    -
    - - - -
    -
    + + +
    proc buzz[T](a, b: T): T {...}{.deprecated: "since v0.20".}
    +
    +
    + Deprecated: since v0.20 +
    -
    -
    -
    -
    proc baz() {....raises: [], tags: [], forbids: [].}
    -
    - - - -
    -
    -
    -
    proc baz[T](a, b: T): T {....deprecated.}
    -
    -
    - Deprecated -
    +This is deprecated with a message. - This is deprecated without message. - -
    -
    + + +
    proc isValid[T](x: T): bool
    +
    -
    -
    -
    -
    proc buzz[T](a, b: T): T {....deprecated: "since v0.20".}
    -
    -
    - Deprecated: since v0.20 -
    - This is deprecated with a message. - -
    -
    -
    -
    -
    -
    proc c_nonexistent(frmt: cstring): cint {.importc: "nonexistent",
    -    header: "<stdio.h>", varargs, discardable, ...raises: [], tags: [], forbids: [].}
    -
    - - - -
    -
    + -
    -
    -
    -
    proc c_printf(frmt: cstring): cint {.importc: "printf", header: "<stdio.h>",
    -                                     varargs, discardable, ...raises: [], tags: [],
    -                                     forbids: [].}
    -
    - - the c printf. etc. - -
    -
    +
    +
    +

    Funcs

    +
    + +
    func someFunc() {...}{.raises: [], tags: [].}
    +
    -
    -
    -
    -
    proc fromUtils3() {....raises: [], tags: [], forbids: [].}
    -
    - - came form utils but should be shown where fromUtilsGen is called -

    Example:

    -
    discard """should be shown as examples for fromUtils3
    -       in module calling fromUtilsGen"""
    - -
    -
    +My someFunc. Stuff in quotes here. Some link -
    -
    -
    -
    proc isValid[T](x: T): bool
    -
    - - - -
    -
    + -
    -
    -
    -
    proc low[T: Ordinal | enum | range](x: T): T {.magic: "Low", noSideEffect,
    -    ...raises: [], tags: [], forbids: [].}
    -
    - -

    Returns the lowest possible value of an ordinal value x. As a special semantic rule, x may also be a type identifier.

    -

    See also:

    - -
    low(2) # => -9223372036854775808
    - -
    -
    - -
    -
    -
    -
    proc low2[T: Ordinal | enum | range](x: T): T {.magic: "Low", noSideEffect,
    -    ...raises: [], tags: [], forbids: [].}
    -
    - -

    Returns the lowest possible value of an ordinal value x. As a special semantic rule, x may also be a type identifier.

    -

    See also:

    - -
    low2(2) # => -9223372036854775808
    -

    Example:

    -
    discard "in low2"
    - -
    -
    - -
    -
    -
    -
    proc p1() {....raises: [], tags: [], forbids: [].}
    -
    - - cp1 -

    Example:

    -
    doAssert 1 == 1 # regular comments work here
    c4 -

    Example:

    -
    # c5 regular comments before 1st token work
    -# regular comment
    -#[
    -nested regular comment
    -]#
    -doAssert 2 == 2 # c8
    -## this is a non-nested doc comment
    -
    -##[
    -this is a nested doc comment
    -]##
    -discard "c9"
    -# also work after
    - -
    -
    - -
    -
    -
    -
    func someFunc() {....raises: [], tags: [], forbids: [].}
    -
    - - My someFunc. Stuff in quotes here. Some link - -
    -
    - -
    -
    -
    -
    proc tripleStrLitTest() {....raises: [], tags: [], forbids: [].}
    -
    - - -

    Example: cmd: --hint:XDeclaredButNotUsed:off

    -
    ## mullitline string litterals are tricky as their indentation can span
    -## below that of the runnableExamples
    -let s1a = """
    -should appear at indent 0
    -  at indent 2
    -at indent 0
    -"""
    -# make sure this works too
    -let s1b = """start at same line
    -  at indent 2
    -at indent 0
    -""" # comment after
    -let s2 = """sandwich """
    -let s3 = """"""
    -when false:
    -  let s5 = """
    -        in s5 """
    -
    -let s3b = ["""
    -%!? #[...] # inside a multiline ...
    -""", "foo"]
    -
    -## make sure handles trailing spaces
    -let s4 = """ 
    -"""
    -
    -let s5 = """ x
    -"""
    -let s6 = """ ""
    -"""
    -let s7 = """"""""""
    -let s8 = ["""""""""", """
    -  """ ]
    -discard
    -# should be in
    - -
    -
    - -
    -
    -
    -
    proc z1(): Foo {....raises: [], tags: [], forbids: [].}
    -
    - - cz1 - -
    -
    - -
    -
    -
    -
    proc z2() {....raises: [], tags: [], forbids: [].}
    -
    - - cz2 -

    Example:

    -
    discard "in cz2"
    - -
    -
    - -
    -
    -
    -
    proc z3() {....raises: [], tags: [], forbids: [].}
    -
    - - cz3 - -
    -
    - -
    -
    -
    -
    proc z4() {....raises: [], tags: [], forbids: [].}
    -
    - - cz4 - -
    -
    - -
    -
    -
    -
    proc z5(): int {....raises: [], tags: [], forbids: [].}
    -
    - - cz5 - -
    -
    - -
    -
    -
    -
    proc z6(): int {....raises: [], tags: [], forbids: [].}
    -
    - - cz6 - -
    -
    - -
    -
    -
    -
    proc z7(): int {....raises: [], tags: [], forbids: [].}
    -
    - - cz7 - -
    -
    - -
    -
    -
    -
    proc z8(): int {....raises: [], tags: [], forbids: [].}
    -
    - - cz8 - -
    -
    - -
    -
    -
    -
    proc z9() {....raises: [], tags: [], forbids: [].}
    -
    - - -

    Example:

    -
    doAssert 1 + 1 == 2
    - -
    -
    - -
    -
    -
    -
    proc z10() {....raises: [], tags: [], forbids: [].}
    -
    - - -

    Example: cmd: -d:foobar

    -
    discard 1
    cz10 - -
    -
    - -
    -
    -
    -
    proc z11() {....raises: [], tags: [], forbids: [].}
    -
    - - -

    Example:

    -
    discard 1
    - -
    -
    - -
    -
    -
    -
    proc z12(): int {....raises: [], tags: [], forbids: [].}
    -
    - - -

    Example:

    -
    discard 1
    - -
    -
    - -
    -
    -
    -
    proc z13() {....raises: [], tags: [], forbids: [].}
    -
    - - cz13 -

    Example:

    -
    discard
    - -
    -
    - -
    -
    -
    -
    proc z17() {....raises: [], tags: [], forbids: [].}
    -
    - - cz17 rest -

    Example:

    -
    discard 1
    rest - -
    -
    - -
    - - - -
    -

    Methods

    -
    -
    -
    -
    method method1(self: Moo) {.base, ...raises: [], tags: [], forbids: [].}
    -
    - - foo1 - -
    -
    - -
    -
    -
    -
    method method2(self: Moo): int {.base, ...raises: [], tags: [], forbids: [].}
    -
    - - foo2 - -
    -
    - -
    -
    -
    -
    method method3(self: Moo): int {.base, ...raises: [], tags: [], forbids: [].}
    -
    - - foo3 - -
    -
    - -
    - -
    -
    -
    -

    Iterators

    -
    -
    -
    -
    iterator fromUtils1(): int {....raises: [], tags: [], forbids: [].}
    -
    - - -

    Example:

    -
    # ok1
    -assert 1 == 1
    -# ok2
    - -
    -
    - -
    -
    -
    -
    iterator iter1(n: int): int {....raises: [], tags: [], forbids: [].}
    -
    - - foo1 - -
    -
    - -
    -
    -
    -
    iterator iter2(n: int): int {....raises: [], tags: [], forbids: [].}
    -
    - - foo2 -

    Example:

    -
    discard # bar
    - -
    -
    - -
    - -
    -
    +
    -

    Macros

    -
    -
    -
    -
    macro bar(): untyped
    -
    - - - -
    -
    +

    Macros

    +
    + +
    macro bar(): untyped
    +
    -
    -
    -
    -
    macro z16()
    -
    - - -

    Example:

    -
    discard 1
    cz16 after -

    Example:

    -
    doAssert 2 == 1 + 1
    - -
    -
    -
    -
    -
    -
    macro z18(): int
    -
    - - cz18 - -
    -
    -
    + -
    -
    +
    -

    Templates

    -
    -
    -
    -
    template foo(a, b: SomeType)
    -
    - - This does nothing - -
    -
    +

    Templates

    +
    + +
    template foo(a, b: SomeType)
    +
    -
    -
    -
    -
    template fromUtils2()
    -
    - - ok3 -

    Example:

    -
    discard """should be shown as examples for fromUtils2
    -       in module calling fromUtilsGen"""
    - -
    -
    +This does nothing -
    -
    -
    -
    template myfn()
    -
    - - -

    Example:

    -
    import std/strutils
    -## issue #8871 preserve formatting
    -## line doc comment
    -# bar
    -doAssert "'foo" == "'foo"
    -##[
    -foo
    -bar
    -]##
    +
    -doAssert: not "foo".startsWith "ba" -block: - discard 0xff # elu par cette crapule -# should be inshould be still in - - -
    - -
    -
    -
    -
    template testNimDocTrailingExample()
    -
    - - -

    Example:

    -
    discard 2
    - -
    -
    - -
    -
    -
    -
    template z6t(): int
    -
    - - cz6t - -
    -
    - -
    -
    -
    -
    template z14()
    -
    - - cz14 -

    Example:

    -
    discard
    - -
    -
    - -
    -
    -
    -
    template z15()
    -
    - - cz15 -

    Example:

    -
    discard
    -

    Example:

    -
    discard 3
    -

    Example:

    -
    discard 4
    ok5 ok5b -

    Example:

    -
    assert true
    -

    Example:

    -
    discard 1
    in or out? - -
    -
    - -
    - -
    -
    + +
    - - - - + + diff --git a/nimdoc/testproject/expected/testproject.idx b/nimdoc/testproject/expected/testproject.idx deleted file mode 100644 index 46ffaee72..000000000 --- a/nimdoc/testproject/expected/testproject.idx +++ /dev/null @@ -1,68 +0,0 @@ -nimTitle testproject testproject.html module testproject 0 -nim someVariable testproject.html#someVariable var someVariable 13 -nim C_A testproject.html#C_A const C_A 26 -nim C_B testproject.html#C_B const C_B 27 -nim C_C testproject.html#C_C const C_C 28 -nim C_D testproject.html#C_D const C_D 29 -nim bar testproject.html#bar,T,T proc bar[T](a, b: T): T 31 -nim baz testproject.html#baz,T,T proc baz[T](a, b: T): T 34 -nim buzz testproject.html#buzz,T,T proc buzz[T](a, b: T): T 38 -nim FooBuzz testproject.html#FooBuzz type FooBuzz 43 -nim bar testproject.html#bar proc bar(f: FooBuzz) 47 -nim aVariable testproject.html#aVariable var aVariable 52 -nim A testproject.html#A enum A 92 -nim B testproject.html#B enum B 97 -nim someFunc testproject.html#someFunc proc someFunc() 56 -nim fromUtils1 testproject.html#fromUtils1.i iterator fromUtils1(): int 112 -nim fromUtils2 testproject.html#fromUtils2.t template fromUtils2() 119 -nim fromUtils3 testproject.html#fromUtils3 proc fromUtils3() 57 -nim isValid testproject.html#isValid,T proc isValid[T](x: T): bool 59 -nim enumValueA2 testproject.html#enumValueA2 Foo.enumValueA2 66 -nim Foo testproject.html#Foo enum Foo 66 -nim z1 testproject.html#z1 proc z1(): Foo 69 -nim z2 testproject.html#z2 proc z2() 73 -nim z3 testproject.html#z3 proc z3() 78 -nim z4 testproject.html#z4 proc z4() 81 -nim z5 testproject.html#z5 proc z5(): int 87 -nim z6 testproject.html#z6 proc z6(): int 91 -nim z6t testproject.html#z6t.t template z6t(): int 95 -nim z7 testproject.html#z7 proc z7(): int 99 -nim z8 testproject.html#z8 proc z8(): int 103 -nim z9 testproject.html#z9 proc z9() 111 -nim z10 testproject.html#z10 proc z10() 114 -nim z11 testproject.html#z11 proc z11() 119 -nim z12 testproject.html#z12 proc z12(): int 124 -nim z13 testproject.html#z13 proc z13() 129 -nim baz testproject.html#baz proc baz() 134 -nim z17 testproject.html#z17 proc z17() 144 -nim p1 testproject.html#p1 proc p1() 156 -nim addfBug14485 testproject.html#addfBug14485 proc addfBug14485() 177 -nim c_printf testproject.html#c_printf,cstring proc c_printf(frmt: cstring): cint 193 -nim c_nonexistent testproject.html#c_nonexistent,cstring proc c_nonexistent(frmt: cstring): cint 197 -nim low testproject.html#low,T proc low[T: Ordinal | enum | range](x: T): T 200 -nim low2 testproject.html#low2,T proc low2[T: Ordinal | enum | range](x: T): T 210 -nim tripleStrLitTest testproject.html#tripleStrLitTest proc tripleStrLitTest() 223 -nim method1 testproject.html#method1.e,Moo method method1(self: Moo) 264 -nim method2 testproject.html#method2.e,Moo method method2(self: Moo): int 266 -nim method3 testproject.html#method3.e,Moo method method3(self: Moo): int 269 -nim iter1 testproject.html#iter1.i,int iterator iter1(n: int): int 274 -nim iter2 testproject.html#iter2.i,int iterator iter2(n: int): int 278 -nim bar testproject.html#bar.m macro bar(): untyped 285 -nim z16 testproject.html#z16.m macro z16() 288 -nim z18 testproject.html#z18.m macro z18(): int 297 -nim foo testproject.html#foo.t,SomeType,SomeType template foo(a, b: SomeType) 302 -nim myfn testproject.html#myfn.t template myfn() 307 -nim z14 testproject.html#z14.t template z14() 328 -nim z15 testproject.html#z15.t template z15() 333 -nim asyncFun1 testproject.html#asyncFun1 proc asyncFun1(): Future[int] 358 -nim asyncFun2 testproject.html#asyncFun2 proc asyncFun2(): owned(Future[void]) 361 -nim asyncFun3 testproject.html#asyncFun3 proc asyncFun3(): owned(Future[void]) 362 -nim testNimDocTrailingExample testproject.html#testNimDocTrailingExample.t template testNimDocTrailingExample() 371 -nim Circle testproject.html#Circle Shapes.Circle 380 -nim Triangle testproject.html#Triangle Shapes.Triangle 380 -nim Rectangle testproject.html#Rectangle Shapes.Rectangle 380 -nim Shapes testproject.html#Shapes enum Shapes 380 -nim anything testproject.html#anything proc anything() 387 -nim T19396 testproject.html#T19396 object T19396 392 -nimgrp bar testproject.html#bar-procs-all proc 31 -nimgrp baz testproject.html#baz-procs-all proc 34 diff --git a/nimdoc/testproject/expected/theindex.html b/nimdoc/testproject/expected/theindex.html index f9488eb2d..a76f5961f 100644 --- a/nimdoc/testproject/expected/theindex.html +++ b/nimdoc/testproject/expected/theindex.html @@ -1,416 +1,170 @@ - + - + + -Index + + + + +Index - + + + - -
    -
    -

    Index

    - Modules: subdir/subdir_b/utils, testproject.

    API symbols

    -
    `$`:
      + +
      +
      +

      Index

      + Modules: testproject, utils.

      API symbols

      +
      A:
      -
      `'big`:
      -
      `[]=`:
      -
      `[]`:
      -
      A:
      -
      addfBug14485:
      aEnum:
      -
      anything:
      -
      asyncFun1:
      -
      asyncFun2:
      -
      asyncFun3:
      aVariable:
      • testproject: var aVariable
      • + data-doc-search-tag="testproject: aVariable" href="testproject.html#aVariable">testproject: aVariable
      B:
      • testproject: enum B
      • + data-doc-search-tag="testproject: B" href="testproject.html#B">testproject: B
      bar:
      baz:
      bEnum:
      -
      binarySearch:
      buzz:
      C_A:
      • testproject: const C_A
      • + data-doc-search-tag="testproject: C_A" href="testproject.html#C_A">testproject: C_A
      C_B:
      • testproject: const C_B
      • + data-doc-search-tag="testproject: C_B" href="testproject.html#C_B">testproject: C_B
      C_C:
      • testproject: const C_C
      • + data-doc-search-tag="testproject: C_C" href="testproject.html#C_C">testproject: C_C
      C_D:
      -
      Circle:
      -
      c_nonexistent:
      -
      c_printf:
      enumValueA:
      -
      enumValueA2:
        -
      • testproject: Foo.enumValueA2
      • + data-doc-search-tag="SomeType.enumValueA" href="subdir/subdir_b/utils.html#enumValueA">SomeType.enumValueA
      enumValueB:
      • utils: SomeType.enumValueB
      • + data-doc-search-tag="SomeType.enumValueB" href="subdir/subdir_b/utils.html#enumValueB">SomeType.enumValueB
      enumValueC:
      -
      f:
      -
      fn:
      -
      fn10:
      -
      fN11:
      -
      fn2:
      -
      fn3:
      -
      fn4:
      -
      fn5:
      -
      fn6:
      -
      fn7:
      -
      fn8:
      -
      fn9:
      -
      Foo:
        -
      • testproject: enum Foo
      • + data-doc-search-tag="SomeType.enumValueC" href="subdir/subdir_b/utils.html#enumValueC">SomeType.enumValueC
      foo:
      -
      fooBar:
      -
      FooBuzz:
      -
      fromUtils1:
      -
      fromUtils2:
      -
      fromUtils3:
      -
      fromUtilsGen:
      -
      funWithGenerics:
      -
      G:
        -
      • utils: object G
      • + data-doc-search-tag="testproject: foo(a, b: SomeType)" href="testproject.html#foo.t%2CSomeType%2CSomeType">testproject: foo(a, b: SomeType)
      isValid:
      -
      iter1:
      -
      iter2:
      -
      low:
      -
      low2:
      -
      method1:
      -
      method2:
      -
      method3:
      -
      myfn:
      -
      p1:
      -
      Rectangle:
      -
      Shapes:
        -
      • testproject: enum Shapes
      • + data-doc-search-tag="testproject: isValid[T](x: T): bool" href="testproject.html#isValid%2CT">testproject: isValid[T](x: T): bool
      someFunc:
      SomeType:
      • utils: enum SomeType
      • + data-doc-search-tag="utils: SomeType" href="subdir/subdir_b/utils.html#SomeType">utils: SomeType
      someType:
      -
      someVariable:
      -
      T19396:
      -
      testNimDocTrailingExample:
      -
      Triangle:
      -
      tripleStrLitTest:
      -
      z1:
      -
      z10:
      -
      z11:
      -
      z12:
      -
      z13:
      -
      z14:
      -
      z15:
      -
      z16:
      -
      z17:
      -
      z18:
      -
      z2:
      -
      z3:
      -
      z4:
      -
      z5:
      -
      z6:
      -
      z6t:
      -
      z7:
      -
      z8:
      -
      z9:
        -
      • testproject: proc z9()
      • + data-doc-search-tag="utils: someType(): SomeType" href="subdir/subdir_b/utils.html#someType_2">utils: someType(): SomeType
      +
      - - - - +
      + diff --git a/nimdoc/testproject/subdir/subdir_b/utils.nim b/nimdoc/testproject/subdir/subdir_b/utils.nim index f535d7f74..0576f194f 100644 --- a/nimdoc/testproject/subdir/subdir_b/utils.nim +++ b/nimdoc/testproject/subdir/subdir_b/utils.nim @@ -1,7 +1,5 @@ ##[ -.. include:: ./utils_overview.rst - # This is now a header ## Next header @@ -21,70 +19,18 @@ More text. 1. Other case value 2. Second case. -Ref group fn2_ or specific function like `fn2()`_ -or `fn2( int )`_ or `fn2(int, -float)`_. - -Ref generics like this: binarySearch_ or `binarySearch(openArray[T], K, -proc (T, K))`_ or `proc binarySearch(openArray[T], K, proc (T, K))`_ or -in different style: `proc binarysearch(openarray[T], K, proc(T, K))`_. -Can be combined with export symbols and type parameters: -`binarysearch*[T, K](openArray[T], K, proc (T, K))`_. -With spaces `binary search`_. - -Note that `proc` can be used in postfix form: `binarySearch proc`_. - -Ref. type like G_ and `type G`_ and `G[T]`_ and `type G*[T]`_. - -Group ref. with capital letters works: fN11_ or fn11_ ]## -include ./utils_helpers - type SomeType* = enum enumValueA, enumValueB, enumValueC - G*[T] = object - val: T proc someType*(): SomeType = ## constructor. SomeType(2) - -proc fn2*() = discard ## comment -proc fn2*(x: int) = - ## fn2 comment - discard -proc fn2*(x: int, y: float) = - discard -proc binarySearch*[T, K](a: openArray[T]; key: K; - cmp: proc (x: T; y: K): int {.closure.}): int = - discard -proc fn3*(): auto = 1 ## comment -proc fn4*(): auto = 2 * 3 + 4 ## comment -proc fn5*() ## comment -proc fn5*() = discard -proc fn6*() = - ## comment -proc fn7*() = - ## comment - discard -proc fn8*(): auto = - ## comment - 1+1 -func fn9*(a: int): int = 42 ## comment -func fn10*(a: int): int = a ## comment - -# Note capital letter N will be handled correctly in -# group references like fN11_ or fn11_ -# (or [fN11] or [fn11] in Markdown Syntax): - -func fN11*() = discard -func fN11*(x: int) = discard - # bug #9235 template aEnum*(): untyped = @@ -102,112 +48,3 @@ template bEnum*(): untyped = ## Stuff in `quotes` here. ## [Some link](https://nim-lang.org) discard - -template fromUtilsGen*(): untyped = - ## should be shown in utils.html only - runnableExamples: - discard "should be in utils.html only, not in module that calls fromUtilsGen" - ## ditto - - iterator fromUtils1*(): int = - runnableExamples: - # ok1 - assert 1 == 1 - # ok2 - yield 15 - - template fromUtils2*() = - ## ok3 - runnableExamples: - discard """should be shown as examples for fromUtils2 - in module calling fromUtilsGen""" - - proc fromUtils3*() = - ## came form utils but should be shown where `fromUtilsGen` is called - runnableExamples: discard """should be shown as examples for fromUtils3 - in module calling fromUtilsGen""" - -proc f*(x: G[int]) = - ## There is also variant `f(G[string])`_ - discard -proc f*(x: G[string]) = - ## See also `f(G[int])`_. - discard - -## Ref. `[]`_ is the same as `proc \`[]\`(G[T])`_ because there are no -## overloads. The full form: `proc \`[]\`*[T](x: G[T]): T`_ - -proc `[]`*[T](x: G[T]): T = x.val - -## Ref. `[]=`_ aka `\`[]=\`(G[T], int, T)`_. - -proc `[]=`*[T](a: var G[T], index: int, value: T) = discard - -## Ref. `$`_ aka `proc $`_ or `proc \`$\``_. - -proc `$`*[T](a: G[T]): string = "" - -## Ref. `$(a: ref SomeType)`_. - -proc `$`*[T](a: ref SomeType): string = "" - -## Ref. foo_bar_ aka `iterator foo_bar_`_. - -iterator fooBar*(a: seq[SomeType]): int = discard - -## Ref. `fn[T; U,V: SomeFloat]()`_. - -proc fn*[T; U, V: SomeFloat]() = discard - -## Ref. `'big`_ or `func \`'big\``_ or `\`'big\`(string)`_. - -func `'big`*(a: string): SomeType = discard - -##[ - -Pandoc Markdown -=============== - -Now repeat all the auto links of above in Pandoc Markdown Syntax. - -Ref group [fn2] or specific function like [fn2()] -or [fn2( int )] or [fn2(int, -float)]. - -Ref generics like this: [binarySearch] or [binarySearch(openArray[T], K, -proc (T, K))] or [proc binarySearch(openArray[T], K, proc (T, K))] or -in different style: [proc binarysearch(openarray[T], K, proc(T, K))]. -Can be combined with export symbols and type parameters: -[binarysearch*[T, K](openArray[T], K, proc (T, K))]. -With spaces [binary search]. - -Note that `proc` can be used in postfix form: [binarySearch proc]. - -Ref. type like [G] and [type G] and [G[T]] and [type G*[T]]. - -Group ref. with capital letters works: [fN11] or [fn11] - -Ref. [`[]`] is the same as [proc `[]`(G[T])] because there are no -overloads. The full form: [proc `[]`*[T](x: G[T]): T] -Ref. [`[]=`] aka [`[]=`(G[T], int, T)]. -Ref. [$] aka [proc $] or [proc `$`]. -Ref. [$(a: ref SomeType)]. -Ref. [foo_bar] aka [iterator foo_bar_]. -Ref. [fn[T; U,V: SomeFloat]()]. -Ref. ['big] or [func `'big`] or [`'big`(string)]. - -Link name syntax ----------------- - -Pandoc Markdown has synax for changing text of links: -Ref. [this proc][`[]`] or [another symbol][G[T]]. - -Symbols documentation ---------------------- - -Let us repeat auto links from symbols section below: - -There is also variant [f(G[string])]. -See also [f(G[int])]. - -]## diff --git a/nimdoc/testproject/subdir/subdir_b/utils_helpers.nim b/nimdoc/testproject/subdir/subdir_b/utils_helpers.nim deleted file mode 100644 index 2c45ffb83..000000000 --- a/nimdoc/testproject/subdir/subdir_b/utils_helpers.nim +++ /dev/null @@ -1 +0,0 @@ -proc funWithGenerics*[T, U: SomeFloat](a: T, b: U) = discard diff --git a/nimdoc/testproject/subdir/subdir_b/utils_overview.rst b/nimdoc/testproject/subdir/subdir_b/utils_overview.rst deleted file mode 100644 index 58ce930bf..000000000 --- a/nimdoc/testproject/subdir/subdir_b/utils_overview.rst +++ /dev/null @@ -1,8 +0,0 @@ -This is a description of the utils module. - -Links work: - -* other module: `iterators `_ (not in this dir, just an example) -* internal: `fn2(x)`_ -* internal included from another module: `funWithGenerics*[T, U: - SomeFloat](a: T, b: U)`_. diff --git a/nimdoc/testproject/testproject.nim b/nimdoc/testproject/testproject.nim index b5fa2ac37..d1fcf58cd 100644 --- a/nimdoc/testproject/testproject.nim +++ b/nimdoc/testproject/testproject.nim @@ -9,25 +9,17 @@ runnableExamples: # bug #11078 for x in "xx": discard - -var someVariable*: bool ## This should be visible. - -when true: - ## top2 - runnableExamples: - discard "in top2" - ## top2 after - -runnableExamples: - discard "in top3" -## top3 after - const C_A* = 0x7FF0000000000000'f64 C_B* = 0o377'i8 C_C* = 0o277'i8 C_D* = 0o177777'i16 +template foo*(a, b: SomeType) = + ## This does nothing + ## + discard + proc bar*[T](a, b: T): T = result = a + b @@ -39,356 +31,15 @@ proc buzz*[T](a, b: T): T {.deprecated: "since v0.20".} = ## This is deprecated with a message. result = a + b -type - FooBuzz* {.deprecated: "FooBuzz msg".} = int - -using f: FooBuzz - -proc bar*(f) = # `f` should be expanded to `f: FooBuzz` - discard - import std/macros +macro bar*(): untyped = + result = newStmtList() + var aVariable*: array[1, int] -# bug #9432 aEnum() bEnum() -fromUtilsGen() +# bug #9432 proc isValid*[T](x: T): bool = x.len > 0 - -when true: - # these cases appear redundant but they're actually (almost) all different at - # AST level and needed to ensure docgen keeps working, e.g. because of issues - # like D20200526T163511 - type - Foo* = enum - enumValueA2 - - proc z1*(): Foo = - ## cz1 - Foo.default - - proc z2*() = - ## cz2 - runnableExamples: - discard "in cz2" - - proc z3*() = - ## cz3 - - proc z4*() = - ## cz4 - discard - -when true: - # tests for D20200526T163511 - proc z5*(): int = - ## cz5 - return 1 - - proc z6*(): int = - ## cz6 - 1 - - template z6t*(): int = - ## cz6t - 1 - - proc z7*(): int = - ## cz7 - result = 1 - - proc z8*(): int = - ## cz8 - block: - discard - 1+1 - -when true: - # interleaving 0 or more runnableExamples and doc comments, issue #9227 - proc z9*() = - runnableExamples: doAssert 1 + 1 == 2 - - proc z10*() = - runnableExamples "-d:foobar": - discard 1 - ## cz10 - - proc z11*() = - runnableExamples: - discard 1 - discard - - proc z12*(): int = - runnableExamples: - discard 1 - 12 - - proc z13*() = - ## cz13 - runnableExamples: - discard - - proc baz*() = discard - - proc bazNonExported() = - ## out (not exported) - runnableExamples: - # BUG: this currently this won't be run since not exported - # but probably should - doAssert false - if false: bazNonExported() # silence XDeclaredButNotUsed - - proc z17*() = - # BUG: a comment before 1st doc comment currently doesn't prevent - # doc comment from being docgen'd; probably should be fixed - ## cz17 - ## rest - runnableExamples: - discard 1 - ## rest - # this comment separates docgen'd doc comments - ## out - -when true: # capture non-doc comments correctly even before 1st token - proc p1*() = - ## cp1 - runnableExamples: doAssert 1 == 1 # regular comments work here - ## c4 - runnableExamples: - # c5 regular comments before 1st token work - # regular comment - #[ - nested regular comment - ]# - doAssert 2 == 2 # c8 - ## this is a non-nested doc comment - - ##[ - this is a nested doc comment - ]## - discard "c9" - # also work after - # this should be out - -when true: # issue #14485 - proc addfBug14485*() = - ## Some proc - runnableExamples: - discard "foo() = " & $[1] - #[ - 0: let's also add some broken html to make sure this won't break in future - 1: - 2: - 3: - 5: ", varargs, discardable.} - ## the c printf. - ## etc. - - proc c_nonexistent*(frmt: cstring): cint {.importc: "nonexistent", header: "", varargs, discardable.} - -when true: # tests RST inside comments - proc low*[T: Ordinal|enum|range](x: T): T {.magic: "Low", noSideEffect.} - ## Returns the lowest possible value of an ordinal value `x`. As a special - ## semantic rule, `x` may also be a type identifier. - ## - ## See also: - ## * `low2(T) <#low2,T>`_ - ## - ## .. code-block:: Nim - ## low(2) # => -9223372036854775808 - - proc low2*[T: Ordinal|enum|range](x: T): T {.magic: "Low", noSideEffect.} = - ## Returns the lowest possible value of an ordinal value `x`. As a special - ## semantic rule, `x` may also be a type identifier. - ## - ## See also: - ## * `low(T) <#low,T>`_ - ## - ## .. code-block:: Nim - ## low2(2) # => -9223372036854775808 - runnableExamples: - discard "in low2" - -when true: # multiline string litterals - proc tripleStrLitTest*() = - runnableExamples("--hint:XDeclaredButNotUsed:off"): - ## mullitline string litterals are tricky as their indentation can span - ## below that of the runnableExamples - let s1a = """ -should appear at indent 0 - at indent 2 -at indent 0 -""" - # make sure this works too - let s1b = """start at same line - at indent 2 -at indent 0 -""" # comment after - let s2 = """sandwich """ - let s3 = """""" - when false: - let s5 = """ - in s5 """ - - let s3b = [""" -%!? #[...] # inside a multiline ... -""", "foo"] - - ## make sure handles trailing spaces - let s4 = """ -""" - - let s5 = """ x -""" - let s6 = """ "" -""" - let s7 = """""""""" - let s8 = ["""""""""", """ - """ ] - discard - # should be in - # should be out - -when true: # methods; issue #14691 - type Moo = object - method method1*(self: Moo) {.base.} = - ## foo1 - method method2*(self: Moo): int {.base.} = - ## foo2 - result = 1 - method method3*(self: Moo): int {.base.} = - ## foo3 - 1 - -when true: # iterators - iterator iter1*(n: int): int = - ## foo1 - for i in 0.. " & infileBackup + os.copyFile(source = infile, dest = infileBackup) + prettyPrint(infile, outfile, opt) - if outfile.len != 0 and outdir.len != 0: - quit "[Error] out and outDir cannot both be specified" - - if outfile.len == 0 and outdir.len == 0: - outfiles = infiles - elif outfile.len != 0 and infiles.len > 1: - # Take the last file to maintain backwards compatibility - let infile = infiles[^1] - infiles = @[infile] - outfiles = @[outfile] - elif outfile.len != 0: - outfiles = @[outfile] - elif outdir.len != 0: - outfiles = infiles.mapIt($(joinPath(outdir, it))) - - for (infile, outfile) in zip(infiles, outfiles): - let (dir, _, _) = splitFile(outfile) - createDir(dir) - if not fileExists(outfile) or not sameFile(infile, outfile): - backup = false # no backup needed since won't be over-written - if backup: - let infileBackup = infile & ".backup" # works with .nim or .nims - echo "writing backup " & infile & " > " & infileBackup - os.copyFile(source = infile, dest = infileBackup) - prettyPrint(infile, outfile, opt) - -when isMainModule: - main() +main() diff --git a/nimpretty/tester.nim b/nimpretty/tester.nim index b1f15aee6..041e7edd8 100644 --- a/nimpretty/tester.nim +++ b/nimpretty/tester.nim @@ -1,11 +1,9 @@ # Small program that runs the test cases -import strutils, os, sequtils -from std/private/gitutils import diffFiles +import strutils, os const - dir = "nimpretty/tests" - outputdir = dir / "outputdir" + dir = "nimpretty/tests/" var failures = 0 @@ -27,30 +25,12 @@ proc test(infile, ext: string) = let produced = dir / nimFile.changeFileExt(ext) if readFile(expected) != readFile(produced): echo "FAILURE: files differ: ", nimFile - echo diffFiles(expected, produced).output + discard execShellCmd("diff -uNdr " & expected & " " & produced) failures += 1 else: echo "SUCCESS: files identical: ", nimFile -proc testTogether(infiles: seq[string]) = - if execShellCmd("$# --outDir:$# --backup:off $#" % [nimp, outputdir, infiles.join(" ")]) != 0: - echo "FAILURE: nimpretty cannot prettify files: ", $infiles - failures += 1 - return - - for infile in infiles: - let nimFile = splitFile(infile).name - let expected = dir / "expected" / nimFile & ".nim" - let produced = dir / "outputdir" / infile - if readFile(expected) != readFile(produced): - echo "FAILURE: files differ: ", nimFile - echo diffFiles(expected, produced).output - failures += 1 - else: - echo "SUCCESS: files identical: ", nimFile - -let allFiles = toSeq(walkFiles(dir / "*.nim")) -for t in allFiles: +for t in walkFiles(dir / "*.nim"): test(t, "pretty") # also test that pretty(pretty(x)) == pretty(x) test(t.changeFileExt("pretty"), "pretty2") @@ -58,7 +38,5 @@ for t in allFiles: removeFile(t.changeFileExt("pretty")) removeFile(t.changeFileExt("pretty2")) -testTogether(allFiles) -removeDir(outputdir) if failures > 0: quit($failures & " failures occurred.") diff --git a/nimpretty/tests/exhaustive.nim b/nimpretty/tests/exhaustive.nim index 53ff0ea4d..91ab530e4 100644 --- a/nimpretty/tests/exhaustive.nim +++ b/nimpretty/tests/exhaustive.nim @@ -1,5 +1,5 @@ discard """ - outputsub: '''ObjectAssignmentDefect''' + outputsub: '''ObjectAssignmentError''' exitcode: "1" """ @@ -267,7 +267,7 @@ proc emitTok*(em: var Emitter; L: TLexer; tok: TToken) = if not em.endsInWhite: wr(" ") wr(tok.ident.s) template isUnary(tok): bool = - tok.strongSpaceB == tsNone and tok.strongSpaceA + tok.strongSpaceB == 0 and tok.strongSpaceA > 0 if not isUnary(tok) or em.lastTok in {tkOpr, tkDotDot}: wr(" ") @@ -418,9 +418,9 @@ proc isValid1*[A](s: HashSet[A]): bool {.deprecated: result = s.data.len > 0 # bug #11468 -assert $typeof(a) == "Option[system.int]" -foo(a, $typeof(b), c) -foo(typeof(b), c) # this is ok +assert $type(a) == "Option[system.int]" +foo(a, $type(b), c) +foo(type(b), c) # this is ok proc `<`*[A](s, t: A): bool = discard proc `==`*[A](s, t: HashSet[A]): bool = discard @@ -822,28 +822,3 @@ proc f = # doesn't break the code, but leaving indentation as is would be nice. let x = if true: callingProcWhatever() else: callingADifferentProc() - - -type - EventKind = enum - Stop, StopSuccess, StopError, - SymbolChange, TextChange, - - SpinnyEvent = tuple - kind: EventKind - payload: string - - -type - EventKind2 = enum - Stop2, StopSuccess2, StopError2, - SymbolChange2, TextChange2, - -type - SpinnyEvent2 = tuple - kind: EventKind - payload: string - - -proc hid_open*(vendor_id: cushort; product_id: cushort; serial_number: cstring): ptr HidDevice {. - importc: "hid_open", dynlib: hidapi.} diff --git a/nimpretty/tests/expected/exhaustive.nim b/nimpretty/tests/expected/exhaustive.nim index 266bcae06..3c2355707 100644 --- a/nimpretty/tests/expected/exhaustive.nim +++ b/nimpretty/tests/expected/exhaustive.nim @@ -1,5 +1,5 @@ discard """ - outputsub: '''ObjectAssignmentDefect''' + outputsub: '''ObjectAssignmentError''' exitcode: "1" """ @@ -272,7 +272,7 @@ proc emitTok*(em: var Emitter; L: TLexer; tok: TToken) = if not em.endsInWhite: wr(" ") wr(tok.ident.s) template isUnary(tok): bool = - tok.strongSpaceB == tsNone and tok.strongSpaceA + tok.strongSpaceB == 0 and tok.strongSpaceA > 0 if not isUnary(tok) or em.lastTok in {tkOpr, tkDotDot}: wr(" ") @@ -423,9 +423,9 @@ proc isValid1*[A](s: HashSet[A]): bool {.deprecated: result = s.data.len > 0 # bug #11468 -assert $typeof(a) == "Option[system.int]" -foo(a, $typeof(b), c) -foo(typeof(b), c) # this is ok +assert $type(a) == "Option[system.int]" +foo(a, $type(b), c) +foo(type(b), c) # this is ok proc `<`*[A](s, t: A): bool = discard proc `==`*[A](s, t: HashSet[A]): bool = discard @@ -812,7 +812,7 @@ let foo = if cond: let a = [[aaadsfas, bbb], - [ccc, ddd]] + [ccc, ddd]] let b = [ [aaa, bbb], @@ -835,29 +835,3 @@ proc f = # doesn't break the code, but leaving indentation as is would be nice. let x = if true: callingProcWhatever() else: callingADifferentProc() - - -type - EventKind = enum - Stop, StopSuccess, StopError, - SymbolChange, TextChange, - - SpinnyEvent = tuple - kind: EventKind - payload: string - - -type - EventKind2 = enum - Stop2, StopSuccess2, StopError2, - SymbolChange2, TextChange2, - -type - SpinnyEvent2 = tuple - kind: EventKind - payload: string - - -proc hid_open*(vendor_id: cushort; product_id: cushort; - serial_number: cstring): ptr HidDevice {. - importc: "hid_open", dynlib: hidapi.} diff --git a/nimpretty/tests/expected/simple.nim b/nimpretty/tests/expected/simple.nim index e711eb3b6..5126658ea 100644 --- a/nimpretty/tests/expected/simple.nim +++ b/nimpretty/tests/expected/simple.nim @@ -11,19 +11,3 @@ proc a() = # comment 2 discard - -# bug #15596 -discard ## comment 3 - -discard # comment 4 - - -# bug #20553 - -let `'hello` = 12 -echo `'hello` - - -proc `'u4`(n: string) = - # The leading ' is required. - discard diff --git a/nimpretty/tests/expected/wrong_ind.nim b/nimpretty/tests/expected/wrong_ind.nim index 3ff9de91c..95a35a8fd 100644 --- a/nimpretty/tests/expected/wrong_ind.nim +++ b/nimpretty/tests/expected/wrong_ind.nim @@ -2,7 +2,7 @@ # bug #9505 import std/[ - strutils, os + strutils, ospaths, os ] import pkg/[ regex diff --git a/nimpretty/tests/simple.nim b/nimpretty/tests/simple.nim index 2a01a176e..5126658ea 100644 --- a/nimpretty/tests/simple.nim +++ b/nimpretty/tests/simple.nim @@ -11,19 +11,3 @@ proc a() = # comment 2 discard - -# bug #15596 -discard## comment 3 - -discard # comment 4 - - -# bug #20553 - -let `'hello` = 12 -echo `'hello` - - -proc `'u4`(n: string) = - # The leading ' is required. - discard diff --git a/nimpretty/tests/wrong_ind.nim b/nimpretty/tests/wrong_ind.nim index a042e8822..3c7544cdb 100644 --- a/nimpretty/tests/wrong_ind.nim +++ b/nimpretty/tests/wrong_ind.nim @@ -2,7 +2,7 @@ # bug #9505 import std/[ - strutils, os + strutils, ospaths, os ] import pkg/[ regex diff --git a/nimsuggest/config.nims b/nimsuggest/config.nims deleted file mode 100644 index ee19f9893..000000000 --- a/nimsuggest/config.nims +++ /dev/null @@ -1,2 +0,0 @@ -# xxx not sure why this flag isn't needed: switch("processing", "filenames") -switch("filenames", "canonical") diff --git a/nimsuggest/crashtester.nim b/nimsuggest/crashtester.nim index ead97adec..10fef2b23 100644 --- a/nimsuggest/crashtester.nim +++ b/nimsuggest/crashtester.nim @@ -32,7 +32,7 @@ proc callNimsuggest() = if a == DummyEof: break var line = 0 - for i in 0 ..< contents.len: + for i in 0..< contents.len: let slic = contents[0..i] writeFile("temp000.nim", slic) let (line, col) = getPosition(slic) diff --git a/nimsuggest/nimsuggest.nim b/nimsuggest/nimsuggest.nim index ce9681975..a48e9443d 100644 --- a/nimsuggest/nimsuggest.nim +++ b/nimsuggest/nimsuggest.nim @@ -7,13 +7,6 @@ # distribution, for details about the copyright. # -import compiler/renderer -import strformat -import algorithm -import tables -import std/sha1 -import times - ## Nimsuggest is a tool that helps to give editors IDE like capabilities. when not defined(nimcore): @@ -23,14 +16,11 @@ import strutils, os, parseopt, parseutils, sequtils, net, rdstdin, sexp # Do NOT import suggest. It will lead to weird bugs with # suggestionResultHook, because suggest.nim is included by sigmatch. # So we import that one instead. -import compiler / [options, commands, modules, +import compiler / [options, commands, modules, sem, passes, passaux, msgs, sigmatch, ast, idents, modulegraphs, prefixmatches, lineinfos, cmdlinehelper, - pathutils, condsyms, syntaxes] - -when defined(nimPreviewSlimSystem): - import std/typedthreads + pathutils] when defined(windows): import winlean @@ -53,8 +43,6 @@ Options: --debug enable debug output --log enable verbose logging to nimsuggest.log file --v1 use version 1 of the protocol; for backwards compatibility - --v2 use version 2(default) of the protocol - --v3 use version 3 of the protocol --refresh perform automatic refreshes to keep the analysis precise --maxresults:N limit the number of suggestions to N --tester implies --stdin and outputs a line @@ -88,9 +76,6 @@ var requests: Channel[string] results: Channel[Suggest] -proc executeNoHooksV3(cmd: IdeCmd, file: AbsoluteFile, dirtyfile: AbsoluteFile, line, col: int; tag: string, - graph: ModuleGraph); - proc writelnToChannel(line: string) = results.send(Suggest(section: ideMsg, doc: line)) @@ -112,6 +97,9 @@ const "type 'debug' to toggle debug mode on/off\n" & "type 'terse' to toggle terse mode on/off" +type + EUnexpectedCommand = object of Exception + proc parseQuoted(cmd: string; outp: var string; start: int): int = var i = start i += skipWhitespace(cmd, i) @@ -140,9 +128,6 @@ proc sexp(s: Suggest): SexpNode = ]) if s.section == ideSug: result.add convertSexp(s.prefix) - if s.section in {ideOutline, ideExpand} and s.version == 3: - result.add convertSexp(s.endLine.int) - result.add convertSexp(s.endCol) proc sexp(s: seq[Suggest]): SexpNode = result = newSList() @@ -155,7 +140,7 @@ proc listEpc(): SexpNode = argspecs = sexp("file line column dirtyfile".split(" ").map(newSSymbol)) docstring = sexp("line starts at 1, column at 0, dirtyfile is optional") result = newSList() - for command in ["sug", "con", "def", "use", "dus", "chk", "mod", "globalSymbols", "recompile", "saved", "chkFile", "declaration"]: + for command in ["sug", "con", "def", "use", "dus", "chk", "mod"]: let cmd = sexp(command) methodDesc = newSList() @@ -178,25 +163,9 @@ proc symFromInfo(graph: ModuleGraph; trackPos: TLineInfo): PSym = if m != nil and m.ast != nil: result = findNode(m.ast, trackPos) -template benchmark(benchmarkName: untyped, code: untyped) = - block: - myLog "Started [" & benchmarkName & "]..." - let t0 = epochTime() - code - let elapsed = epochTime() - t0 - let elapsedStr = elapsed.formatFloat(format = ffDecimal, precision = 3) - myLog "CPU Time [" & benchmarkName & "] " & elapsedStr & "s" - -proc executeNoHooks(cmd: IdeCmd, file, dirtyfile: AbsoluteFile, line, col: int, tag: string, +proc executeNoHooks(cmd: IdeCmd, file, dirtyfile: AbsoluteFile, line, col: int; graph: ModuleGraph) = let conf = graph.config - - if conf.suggestVersion == 3: - let command = fmt "cmd = {cmd} {file}:{line}:{col}" - benchmark command: - executeNoHooksV3(cmd, file, dirtyfile, line, col, tag, graph) - return - myLog("cmd: " & $cmd & ", file: " & file.string & ", dirtyFile: " & dirtyfile.string & "[" & $line & ":" & $col & "]") @@ -229,14 +198,11 @@ proc executeNoHooks(cmd: IdeCmd, file, dirtyfile: AbsoluteFile, line, col: int, if conf.ideCmd in {ideUse, ideDus}: let u = if conf.suggestVersion != 1: graph.symFromInfo(conf.m.trackPos) else: graph.usageSym if u != nil: - listUsages(graph, u) + listUsages(conf, u) else: localError(conf, conf.m.trackPos, "found no symbol at this position " & (conf $ conf.m.trackPos)) -proc executeNoHooks(cmd: IdeCmd, file, dirtyfile: AbsoluteFile, line, col: int, graph: ModuleGraph) = - executeNoHooks(cmd, file, dirtyfile, line, col, graph) - -proc execute(cmd: IdeCmd, file, dirtyfile: AbsoluteFile, line, col: int; tag: string, +proc execute(cmd: IdeCmd, file, dirtyfile: AbsoluteFile, line, col: int; graph: ModuleGraph) = if cmd == ideChk: graph.config.structuredErrorHook = errorHook @@ -244,7 +210,7 @@ proc execute(cmd: IdeCmd, file, dirtyfile: AbsoluteFile, line, col: int; tag: st else: graph.config.structuredErrorHook = nil graph.config.writelnHook = myLog - executeNoHooks(cmd, file, dirtyfile, line, col, tag, graph) + executeNoHooks(cmd, file, dirtyfile, line, col, graph) proc executeEpc(cmd: IdeCmd, args: SexpNode; graph: ModuleGraph) = @@ -255,7 +221,7 @@ proc executeEpc(cmd: IdeCmd, args: SexpNode; var dirtyfile = AbsoluteFile"" if len(args) > 3: dirtyfile = AbsoluteFile args[3].getStr("") - execute(cmd, file, dirtyfile, int(line), int(column), args[3].getStr, graph) + execute(cmd, file, dirtyfile, int(line), int(column), graph) proc returnEpc(socket: Socket, uid: BiggestInt, s: SexpNode|string, returnSymbol = "return") = @@ -356,7 +322,7 @@ proc replTcp(x: ThreadParams) {.thread.} = else: server.bindAddr(x.port, x.address) server.listen() - var inp = "" + var inp = "".TaintedString var stdoutSocket: Socket while true: accept(server, stdoutSocket) @@ -473,13 +439,6 @@ proc execCmd(cmd: string; graph: ModuleGraph; cachedMsgs: CachedMsgs) = of "terse": toggle optIdeTerse of "known": conf.ideCmd = ideKnown of "project": conf.ideCmd = ideProject - of "changed": conf.ideCmd = ideChanged - of "globalsymbols": conf.ideCmd = ideGlobalSymbols - of "declaration": conf.ideCmd = ideDeclaration - of "expand": conf.ideCmd = ideExpand - of "chkfile": conf.ideCmd = ideChkFile - of "recompile": conf.ideCmd = ideRecompile - of "type": conf.ideCmd = ideType else: err() var dirtyfile = "" var orig = "" @@ -496,7 +455,6 @@ proc execCmd(cmd: string; graph: ModuleGraph; cachedMsgs: CachedMsgs) = i += parseInt(cmd, line, i) i += skipWhile(cmd, seps, i) i += parseInt(cmd, col, i) - let tag = substr(cmd, i) if conf.ideCmd == ideKnown: results.send(Suggest(section: ideKnown, quality: ord(fileInfoKnown(conf, AbsoluteFile orig)))) @@ -505,23 +463,23 @@ proc execCmd(cmd: string; graph: ModuleGraph; cachedMsgs: CachedMsgs) = else: if conf.ideCmd == ideChk: for cm in cachedMsgs: errorHook(conf, cm.info, cm.msg, cm.sev) - execute(conf.ideCmd, AbsoluteFile orig, AbsoluteFile dirtyfile, line, col, tag, graph) + execute(conf.ideCmd, AbsoluteFile orig, AbsoluteFile dirtyfile, line, col, graph) sentinel() proc recompileFullProject(graph: ModuleGraph) = - benchmark "Recompilation(clean)": - graph.resetForBackend() - graph.resetSystemArtifacts() - graph.vm = nil - graph.resetAllModules() - GC_fullCollect() - graph.compileProject() + #echo "recompiling full project" + resetSystemArtifacts(graph) + graph.vm = nil + graph.resetAllModules() + GC_fullCollect() + compileProject(graph) + #echo GC_getStatistics() proc mainThread(graph: ModuleGraph) = let conf = graph.config - myLog "searchPaths: " - for it in conf.searchPaths: - myLog(" " & it.string) + if gLogging: + for it in conf.searchPaths: + log(it.string) proc wrHook(line: string) {.closure.} = if gMode == mepc: @@ -544,7 +502,7 @@ proc mainThread(graph: ModuleGraph) = else: os.sleep 250 idle += 1 - if idle == 20 and gRefresh and conf.suggestVersion != 3: + if idle == 20 and gRefresh: # we use some nimsuggest activity to enable a lazy recompile: conf.ideCmd = ideChk conf.writelnHook = proc (s: string) = discard @@ -562,8 +520,7 @@ proc mainCommand(graph: ModuleGraph) = clearPasses(graph) registerPass graph, verbosePass registerPass graph, semPass - conf.setCmd cmdIdeTools - defineSymbol(conf.symbols, $conf.backend) + conf.cmd = cmdIdeTools wantMainModule(conf) if not fileExists(conf.projectFull): @@ -571,20 +528,15 @@ proc mainCommand(graph: ModuleGraph) = add(conf.searchPaths, conf.libpath) - conf.setErrorMaxHighMaybe # honor --errorMax even if it may not make sense here + # do not stop after the first error: + conf.errorMax = high(int) # do not print errors, but log them - conf.writelnHook = proc (msg: string) = discard - - if graph.config.suggestVersion == 3: - graph.config.structuredErrorHook = proc (conf: ConfigRef; info: TLineInfo; msg: string; sev: Severity) = - let suggest = Suggest(section: ideChk, filePath: toFullPath(conf, info), - line: toLinenumber(info), column: toColumn(info), doc: msg, forth: $sev) - graph.suggestErrors.mgetOrPut(info.fileIndex, @[]).add suggest + conf.writelnHook = myLog + conf.structuredErrorHook = nil # compile the project before showing any input so that we already # can answer questions right away: - benchmark "Initial compilation": - compileProject(graph) + compileProject(graph) open(requests) open(results) @@ -636,9 +588,8 @@ proc processCmdLine*(pass: TCmdLinePass, cmd: string; conf: ConfigRef) = gMode = mepc conf.verbosity = 0 # Port number gotta be first. of "debug": incl(conf.globalOptions, optIdeDebug) - of "v1": conf.suggestVersion = 1 of "v2": conf.suggestVersion = 0 - of "v3": conf.suggestVersion = 3 + of "v1": conf.suggestVersion = 1 of "tester": gMode = mstdin gEmitEof = true @@ -672,7 +623,8 @@ proc processCmdLine*(pass: TCmdLinePass, cmd: string; conf: ConfigRef) = proc handleCmdLine(cache: IdentCache; conf: ConfigRef) = let self = NimProg( suggestMode: true, - processCmdLine: processCmdLine + processCmdLine: processCmdLine, + mainCommand: mainCommand ) self.initDefinesProg(conf, "nimsuggest") @@ -696,356 +648,8 @@ proc handleCmdLine(cache: IdentCache; conf: ConfigRef) = #msgs.writelnHook = proc (line: string) = log(line) myLog("START " & conf.projectFull.string) - var graph = newModuleGraph(cache, conf) - if self.loadConfigsAndProcessCmdLine(cache, conf, graph): - mainCommand(graph) + discard self.loadConfigsAndRunMainCommand(cache, conf) -# v3 start - -proc recompilePartially(graph: ModuleGraph, projectFileIdx = InvalidFileIdx) = - if projectFileIdx == InvalidFileIdx: - myLog "Recompiling partially from root" - else: - myLog fmt "Recompiling partially starting from {graph.getModule(projectFileIdx)}" - - # inst caches are breaking incremental compilation when the cache caches stuff - # from dirty buffer - # TODO: investigate more efficient way to achieve the same - # graph.typeInstCache.clear() - # graph.procInstCache.clear() - - GC_fullCollect() - - try: - benchmark "Recompilation": - graph.compileProject(projectFileIdx) - except Exception as e: - myLog fmt "Failed to recompile partially with the following error:\n {e.msg} \n\n {e.getStackTrace()}" - try: - graph.recompileFullProject() - except Exception as e: - myLog fmt "Failed clean recompilation:\n {e.msg} \n\n {e.getStackTrace()}" - -func deduplicateSymInfoPair[SymInfoPair](xs: seq[SymInfoPair]): seq[SymInfoPair] = - # xs contains duplicate items and we want to filter them by range because the - # sym may not match. This can happen when xs contains the same definition but - # with different signature because suggestSym might be called multiple times - # for the same symbol (e. g. including/excluding the pragma) - result = @[] - for itm in xs.reversed: - var found = false - for res in result: - if res.info.exactEquals(itm.info): - found = true - break - if not found: - result.add(itm) - result.reverse() - -proc findSymData(graph: ModuleGraph, trackPos: TLineInfo): - ref SymInfoPair = - for s in graph.fileSymbols(trackPos.fileIndex).deduplicateSymInfoPair: - if isTracked(s.info, trackPos, s.sym.name.s.len): - new(result) - result[] = s - break - -proc findSymData(graph: ModuleGraph, file: AbsoluteFile; line, col: int): - ref SymInfoPair = - let - fileIdx = fileInfoIdx(graph.config, file) - trackPos = newLineInfo(fileIdx, line, col) - result = findSymData(graph, trackPos) - -proc markDirtyIfNeeded(graph: ModuleGraph, file: string, originalFileIdx: FileIndex) = - let sha = $sha1.secureHashFile(file) - if graph.config.m.fileInfos[originalFileIdx.int32].hash != sha or graph.config.ideCmd == ideSug: - myLog fmt "{file} changed compared to last compilation" - graph.markDirty originalFileIdx - graph.markClientsDirty originalFileIdx - else: - myLog fmt "No changes in file {file} compared to last compilation" - -proc suggestResult(graph: ModuleGraph, sym: PSym, info: TLineInfo, - defaultSection = ideNone, endLine: uint16 = 0, endCol = 0) = - let section = if defaultSection != ideNone: - defaultSection - elif sym.info.exactEquals(info): - ideDef - else: - ideUse - let suggest = symToSuggest(graph, sym, isLocal=false, section, - info, 100, PrefixMatch.None, false, 0, - endLine = endLine, endCol = endCol) - suggestResult(graph.config, suggest) - -const - # kinds for ideOutline and ideGlobalSymbols - searchableSymKinds = {skField, skEnumField, skIterator, skMethod, skFunc, skProc, skConverter, skTemplate} - -proc symbolEqual(left, right: PSym): bool = - # More relaxed symbol comparison - return left.info.exactEquals(right.info) and left.name == right.name - -proc findDef(n: PNode, line: uint16, col: int16): PNode = - if n.kind in {nkProcDef, nkIteratorDef, nkTemplateDef, nkMethodDef, nkMacroDef}: - if n.info.line == line: - return n - else: - for i in 0 ..< safeLen(n): - let res = findDef(n[i], line, col) - if res != nil: return res - -proc findByTLineInfo(trackPos: TLineInfo, infoPairs: seq[SymInfoPair]): - ref SymInfoPair = - for s in infoPairs: - if s.info.exactEquals trackPos: - new(result) - result[] = s - break - -proc outlineNode(graph: ModuleGraph, n: PNode, endInfo: TLineInfo, infoPairs: seq[SymInfoPair]): bool = - proc checkSymbol(sym: PSym, info: TLineInfo): bool = - result = (sym.owner.kind in {skModule, skType} or sym.kind in {skProc, skMethod, skIterator, skTemplate, skType}) - - if n.kind == nkSym and n.sym.checkSymbol(n.info): - graph.suggestResult(n.sym, n.sym.info, ideOutline, endInfo.line, endInfo.col) - return true - elif n.kind == nkIdent: - let symData = findByTLineInfo(n.info, infoPairs) - if symData != nil and symData.sym.checkSymbol(symData.info): - let sym = symData.sym - graph.suggestResult(sym, sym.info, ideOutline, endInfo.line, endInfo.col) - return true - -proc handleIdentOrSym(graph: ModuleGraph, n: PNode, endInfo: TLineInfo, infoPairs: seq[SymInfoPair]): bool = - for child in n: - if child.kind in {nkIdent, nkSym}: - if graph.outlineNode(child, endInfo, infoPairs): - return true - elif child.kind == nkPostfix: - if graph.handleIdentOrSym(child, endInfo, infoPairs): - return true - -proc iterateOutlineNodes(graph: ModuleGraph, n: PNode, infoPairs: seq[SymInfoPair]) = - var matched = true - if n.kind == nkIdent: - let symData = findByTLineInfo(n.info, infoPairs) - if symData != nil and symData.sym.kind == skEnumField and symData.info.exactEquals(symData.sym.info): - let sym = symData.sym - graph.suggestResult(sym, sym.info, ideOutline, n.endInfo.line, n.endInfo.col) - elif (n.kind in {nkFuncDef, nkProcDef, nkTypeDef, nkMacroDef, nkTemplateDef, nkConverterDef, nkEnumFieldDef, nkConstDef}): - matched = handleIdentOrSym(graph, n, n.endInfo, infoPairs) - else: - matched = false - - if n.kind != nkFormalParams: - for child in n: - graph.iterateOutlineNodes(child, infoPairs) - -proc calculateExpandRange(n: PNode, info: TLineInfo): TLineInfo = - if ((n.kind in {nkFuncDef, nkProcDef, nkIteratorDef, nkTemplateDef, nkMethodDef, nkConverterDef} and - n.info.exactEquals(info)) or - (n.kind in {nkCall, nkCommand} and n[0].info.exactEquals(info))): - result = n.endInfo - else: - for child in n: - result = child.calculateExpandRange(info) - if result != unknownLineInfo: - return result - result = unknownLineInfo - -proc executeNoHooksV3(cmd: IdeCmd, file: AbsoluteFile, dirtyfile: AbsoluteFile, line, col: int; tag: string, - graph: ModuleGraph) = - let conf = graph.config - conf.writelnHook = proc (s: string) = discard - conf.structuredErrorHook = proc (conf: ConfigRef; info: TLineInfo; - msg: string; sev: Severity) = - let suggest = Suggest(section: ideChk, filePath: toFullPath(conf, info), - line: toLinenumber(info), column: toColumn(info), doc: msg, forth: $sev) - graph.suggestErrors.mgetOrPut(info.fileIndex, @[]).add suggest - - conf.ideCmd = cmd - - myLog fmt "cmd: {cmd}, file: {file}[{line}:{col}], dirtyFile: {dirtyfile}, tag: {tag}" - - var fileIndex: FileIndex - - if not (cmd in {ideRecompile, ideGlobalSymbols}): - if not fileInfoKnown(conf, file): - myLog fmt "{file} is unknown, returning no results" - return - - fileIndex = fileInfoIdx(conf, file) - msgs.setDirtyFile( - conf, - fileIndex, - if dirtyfile.isEmpty: AbsoluteFile"" else: dirtyfile) - - if not dirtyfile.isEmpty: - graph.markDirtyIfNeeded(dirtyFile.string, fileInfoIdx(conf, file)) - - # these commands require fully compiled project - if cmd in {ideUse, ideDus, ideGlobalSymbols, ideChk} and graph.needsCompilation(): - graph.recompilePartially() - # when doing incremental build for the project root we should make sure that - # everything is unmarked as no longer beeing dirty in case there is no - # longer reference to a particular module. E. g. A depends on B, B is marked - # as dirty and A loses B import. - graph.unmarkAllDirty() - - # these commands require partially compiled project - elif cmd in {ideSug, ideOutline, ideHighlight, ideDef, ideChkFile, ideType, ideDeclaration, ideExpand} and - (graph.needsCompilation(fileIndex) or cmd == ideSug): - # for ideSug use v2 implementation - if cmd == ideSug: - conf.m.trackPos = newLineInfo(fileIndex, line, col) - conf.m.trackPosAttached = false - else: - conf.m.trackPos = default(TLineInfo) - - graph.recompilePartially(fileIndex) - - case cmd - of ideDef: - let s = graph.findSymData(file, line, col) - if not s.isNil: - graph.suggestResult(s.sym, s.sym.info) - of ideType: - let s = graph.findSymData(file, line, col) - if not s.isNil: - let typeSym = s.sym.typ.sym - if typeSym != nil: - graph.suggestResult(typeSym, typeSym.info, ideType) - elif s.sym.typ.len != 0: - let genericType = s.sym.typ[0].sym - graph.suggestResult(genericType, genericType.info, ideType) - of ideUse, ideDus: - let symbol = graph.findSymData(file, line, col) - if not symbol.isNil: - var res: seq[SymInfoPair] = @[] - for s in graph.suggestSymbolsIter: - if s.sym.symbolEqual(symbol.sym): - res.add(s) - for s in res.deduplicateSymInfoPair(): - graph.suggestResult(s.sym, s.info) - of ideHighlight: - let sym = graph.findSymData(file, line, col) - if not sym.isNil: - let usages = graph.fileSymbols(fileIndex).filterIt(it.sym == sym.sym) - myLog fmt "Found {usages.len} usages in {file.string}" - for s in usages: - graph.suggestResult(s.sym, s.info) - of ideRecompile: - graph.recompileFullProject() - of ideChanged: - graph.markDirtyIfNeeded(file.string, fileIndex) - of ideSug: - # ideSug performs partial build of the file, thus mark it dirty for the - # future calls. - graph.markDirtyIfNeeded(file.string, fileIndex) - of ideOutline: - let n = parseFile(fileIndex, graph.cache, graph.config) - graph.iterateOutlineNodes(n, graph.fileSymbols(fileIndex).deduplicateSymInfoPair) - of ideChk: - myLog fmt "Reporting errors for {graph.suggestErrors.len} file(s)" - for sug in graph.suggestErrorsIter: - suggestResult(graph.config, sug) - of ideChkFile: - let errors = graph.suggestErrors.getOrDefault(fileIndex, @[]) - myLog fmt "Reporting {errors.len} error(s) for {file.string}" - for error in errors: - suggestResult(graph.config, error) - of ideGlobalSymbols: - var - counter = 0 - res: seq[SymInfoPair] = @[] - - for s in graph.suggestSymbolsIter: - if (sfGlobal in s.sym.flags or s.sym.kind in searchableSymKinds) and - s.sym.info == s.info: - if contains(s.sym.name.s, file.string): - inc counter - res = res.filterIt(not it.info.exactEquals(s.info)) - res.add s - # stop after first 1000 matches... - if counter > 1000: - break - - # ... then sort them by weight ... - res.sort() do (left, right: SymInfoPair) -> int: - let - leftString = left.sym.name.s - rightString = right.sym.name.s - leftIndex = leftString.find(file.string) - rightIndex = rightString.find(file.string) - - if leftIndex == rightIndex: - result = cmp(toLowerAscii(leftString), - toLowerAscii(rightString)) - else: - result = cmp(leftIndex, rightIndex) - - # ... and send first 100 results - if res.len > 0: - for i in 0 .. min(100, res.len - 1): - let s = res[i] - graph.suggestResult(s.sym, s.info) - - of ideDeclaration: - let s = graph.findSymData(file, line, col) - if not s.isNil: - # find first mention of the symbol in the file containing the definition. - # It is either the definition or the declaration. - var first: SymInfoPair - for symbol in graph.fileSymbols(s.sym.info.fileIndex).deduplicateSymInfoPair: - if s.sym.symbolEqual(symbol.sym): - first = symbol - break - - if s.info.exactEquals(first.info): - # we are on declaration, go to definition - graph.suggestResult(first.sym, first.sym.info, ideDeclaration) - else: - # we are on definition or usage, look for declaration - graph.suggestResult(first.sym, first.info, ideDeclaration) - of ideExpand: - var level: int = high(int) - let index = skipWhitespace(tag, 0); - let trimmed = substr(tag, index) - if not (trimmed == "" or trimmed == "all"): - discard parseInt(trimmed, level, 0) - - conf.expandPosition = newLineInfo(fileIndex, line, col) - conf.expandLevels = level - conf.expandProgress = false - conf.expandNodeResult = "" - - graph.markDirty fileIndex - graph.markClientsDirty fileIndex - graph.recompilePartially() - var suggest = Suggest() - suggest.section = ideExpand - suggest.version = 3 - suggest.line = line - suggest.column = col - suggest.doc = graph.config.expandNodeResult - if suggest.doc != "": - let - n = parseFile(fileIndex, graph.cache, graph.config) - endInfo = n.calculateExpandRange(conf.expandPosition) - - suggest.endLine = endInfo.line - suggest.endCol = endInfo.col - - suggestResult(graph.config, suggest) - - graph.markDirty fileIndex - graph.markClientsDirty fileIndex - else: - myLog fmt "Discarding {cmd}" - -# v3 end when isMainModule: handleCmdLine(newIdentCache(), newConfigRef()) else: @@ -1062,12 +666,10 @@ else: proc mockCommand(graph: ModuleGraph) = retval = graph let conf = graph.config - conf.setCmd cmdIdeTools - defineSymbol(conf.symbols, $conf.backend) clearPasses(graph) registerPass graph, verbosePass registerPass graph, semPass - + conf.cmd = cmdIdeTools wantMainModule(conf) if not fileExists(conf.projectFull): @@ -1075,7 +677,8 @@ else: add(conf.searchPaths, conf.libpath) - conf.setErrorMaxHighMaybe + # do not stop after the first error: + conf.errorMax = high(int) # do not print errors, but log them conf.writelnHook = myLog conf.structuredErrorHook = nil @@ -1100,7 +703,8 @@ else: conf = newConfigRef() self = NimProg( suggestMode: true, - processCmdLine: mockCmdLine + processCmdLine: mockCmdLine, + mainCommand: mockCommand ) self.initDefinesProg(conf, "nimsuggest") @@ -1123,13 +727,10 @@ else: #msgs.writelnHook = proc (line: string) = log(line) myLog("START " & conf.projectFull.string) - var graph = newModuleGraph(cache, conf) - if self.loadConfigsAndProcessCmdLine(cache, conf, graph): - mockCommand(graph) + discard self.loadConfigsAndRunMainCommand(cache, conf) if gLogging: - myLog("Search paths:") for it in conf.searchPaths: - myLog(" " & it.string) + log(it.string) retval.doStopCompile = proc (): bool = false return NimSuggest(graph: retval, idle: 0, cachedMsgs: @[]) diff --git a/nimsuggest/nimsuggest.nimble b/nimsuggest/nimsuggest.nimble index 53b5d1d6f..3651e12bd 100644 --- a/nimsuggest/nimsuggest.nimble +++ b/nimsuggest/nimsuggest.nimble @@ -1,8 +1,11 @@ +[Package] +name = "nimsuggest" version = "0.1.0" author = "Andreas Rumpf" description = "Tool for providing auto completion data for Nim source code." license = "MIT" -bin = @["nimsuggest"] +bin = "nimsuggest" -requires "nim >= 1.1.1" +[Deps] +Requires: "nim >= 0.11.2, compiler#head" diff --git a/nimsuggest/sexp.nim b/nimsuggest/sexp.nim index 03369ccb7..654640309 100644 --- a/nimsuggest/sexp.nim +++ b/nimsuggest/sexp.nim @@ -12,11 +12,6 @@ import hashes, strutils, lexbase, streams, unicode, macros -import std/private/decode_helpers - -when defined(nimPreviewSlimSystem): - import std/[assertions, formatfloat] - type SexpEventKind* = enum ## enumeration of all events that may occur when parsing sexpError, ## an error occurred during parsing @@ -118,6 +113,14 @@ proc errorMsgExpected*(my: SexpParser, e: string): string = ## other error messages result = "($1, $2) Error: $3" % [$getLine(my), $getColumn(my), e & " expected"] +proc handleHexChar(c: char, x: var int): bool = + result = true # Success + case c + of '0'..'9': x = (x shl 4) or (ord(c) - ord('0')) + of 'a'..'f': x = (x shl 4) or (ord(c) - ord('a') + 10) + of 'A'..'F': x = (x shl 4) or (ord(c) - ord('A') + 10) + else: result = false # error + proc parseString(my: var SexpParser): TTokKind = result = tkString var pos = my.bufpos + 1 @@ -287,33 +290,41 @@ proc raiseParseErr*(p: SexpParser, msg: string) {.noinline, noreturn.} = ## raises an `ESexpParsingError` exception. raise newException(SexpParsingError, errorMsgExpected(p, msg)) -proc newSString*(s: string): SexpNode = +proc newSString*(s: string): SexpNode {.procvar.}= ## Creates a new `SString SexpNode`. result = SexpNode(kind: SString, str: s) -proc newSInt*(n: BiggestInt): SexpNode = +proc newSStringMove(s: string): SexpNode = + result = SexpNode(kind: SString) + shallowCopy(result.str, s) + +proc newSInt*(n: BiggestInt): SexpNode {.procvar.} = ## Creates a new `SInt SexpNode`. result = SexpNode(kind: SInt, num: n) -proc newSFloat*(n: float): SexpNode = +proc newSFloat*(n: float): SexpNode {.procvar.} = ## Creates a new `SFloat SexpNode`. result = SexpNode(kind: SFloat, fnum: n) -proc newSNil*(): SexpNode = +proc newSNil*(): SexpNode {.procvar.} = ## Creates a new `SNil SexpNode`. result = SexpNode(kind: SNil) -proc newSCons*(car, cdr: SexpNode): SexpNode = +proc newSCons*(car, cdr: SexpNode): SexpNode {.procvar.} = ## Creates a new `SCons SexpNode` result = SexpNode(kind: SCons, car: car, cdr: cdr) -proc newSList*(): SexpNode = +proc newSList*(): SexpNode {.procvar.} = ## Creates a new `SList SexpNode` result = SexpNode(kind: SList, elems: @[]) -proc newSSymbol*(s: string): SexpNode = +proc newSSymbol*(s: string): SexpNode {.procvar.} = result = SexpNode(kind: SSymbol, symbol: s) +proc newSSymbolMove(s: string): SexpNode = + result = SexpNode(kind: SSymbol) + shallowCopy(result.symbol, s) + proc getStr*(n: SexpNode, default: string = ""): string = ## Retrieves the string value of a `SString SexpNode`. ## @@ -404,7 +415,7 @@ macro convertSexp*(x: untyped): untyped = ## `%` for every element. result = toSexp(x) -func `==`* (a, b: SexpNode): bool = +proc `==`* (a,b: SexpNode): bool = ## Check two nodes for equality if a.isNil: if b.isNil: return true @@ -591,7 +602,8 @@ proc parseSexp(p: var SexpParser): SexpNode = case p.tok of tkString: # we capture 'p.a' here, so we need to give it a fresh buffer afterwards: - result = SexpNode(kind: SString, str: move p.a) + result = newSStringMove(p.a) + p.a = "" discard getTok(p) of tkInt: result = newSInt(parseBiggestInt(p.a)) @@ -603,7 +615,8 @@ proc parseSexp(p: var SexpParser): SexpNode = result = newSNil() discard getTok(p) of tkSymbol: - result = SexpNode(kind: SSymbol, symbol: move p.a) + result = newSSymbolMove(p.a) + p.a = "" discard getTok(p) of tkParensLe: result = newSList() diff --git a/nimsuggest/tester.nim b/nimsuggest/tester.nim index 060335959..d0870347e 100644 --- a/nimsuggest/tester.nim +++ b/nimsuggest/tester.nim @@ -2,11 +2,8 @@ # Every test file can have a #[!]# comment that is deleted from the input # before 'nimsuggest' is invoked to ensure this token doesn't make a # crucial difference for Nim's parser. -# When debugging, to run a single test, use for e.g.: -# `nim r nimsuggest/tester.nim nimsuggest/tests/tsug_accquote.nim` import os, osproc, strutils, streams, re, sexp, net -from sequtils import toSeq type Test = object @@ -16,17 +13,15 @@ type disabled: bool const + curDir = when defined(windows): "" else: "" DummyEof = "!EOF!" - tpath = "nimsuggest/tests" - # we could also use `stdtest/specialpaths` -import std/compilesettings +template tpath(): untyped = getAppDir() / "tests" proc parseTest(filename: string; epcMode=false): Test = const cursorMarker = "#[!]#" - let nimsug = "bin" / addFileExt("nimsuggest_testing", ExeExt) - doAssert nimsug.fileExists, nimsug - const libpath = querySetting(libPath) + let nimsug = curDir & addFileExt("nimsuggest", ExeExt) + let libpath = findExe("nim").splitFile().dir /../ "lib" result.filename = filename result.dest = getTempDir() / extractFilename(filename) result.cmd = nimsug & " --tester " & result.dest @@ -66,7 +61,7 @@ proc parseTest(filename: string; epcMode=false): Test = elif x.startsWith(">"): # since 'markers' here are not complete yet, we do the $substitutions # afterwards - result.script.add((x.substr(1).replaceWord("$path", tpath).replaceWord("$file", filename), "")) + result.script.add((x.substr(1).replaceWord("$path", tpath()), "")) elif x.len > 0: # expected output line: let x = x % ["file", filename, "lib", libpath] @@ -107,7 +102,7 @@ proc parseCmd(c: string): seq[string] = proc edit(tmpfile: string; x: seq[string]) = if x.len != 3 and x.len != 4: quit "!edit takes two or three arguments" - let f = if x.len >= 4: tpath / x[3] else: tmpfile + let f = if x.len >= 4: tpath() / x[3] else: tmpfile try: let content = readFile(f) let newcontent = content.replace(x[1], x[2]) @@ -124,12 +119,12 @@ proc exec(x: seq[string]) = proc copy(x: seq[string]) = if x.len != 3: quit "!copy takes two arguments" - let rel = tpath + let rel = tpath() copyFile(rel / x[1], rel / x[2]) proc del(x: seq[string]) = if x.len != 2: quit "!del takes one argument" - removeFile(tpath / x[1]) + removeFile(tpath() / x[1]) proc runCmd(cmd, dest: string): bool = result = cmd[0] == '!' @@ -211,19 +206,14 @@ proc sexpToAnswer(s: SexpNode): string = result.add '\t' result.add file result.add '\t' - result.addInt line + result.add line result.add '\t' - result.addInt col + result.add col result.add '\t' result.add doc result.add '\t' - result.addInt a[8].getNum - if a.len >= 11: - result.add '\t' - result.addInt a[9].getNum - result.add '\t' - result.addInt a[10].getNum - elif a.len >= 10: + result.add a[8].getNum + if a.len >= 10: result.add '\t' result.add a[9].getStr result.add '\L' @@ -234,8 +224,8 @@ proc doReport(filename, answer, resp: string; report: var string) = var hasDiff = false for i in 0..min(resp.len-1, answer.len-1): if resp[i] != answer[i]: - report.add "\n Expected:\n" & resp - report.add "\n But got:\n" & answer + report.add "\n Expected: " & resp.substr(i, i+200) + report.add "\n But got: " & answer.substr(i, i+200) hasDiff = true break if not hasDiff: @@ -257,15 +247,13 @@ proc runEpcTest(filename: string): int = for cmd in s.startup: if not runCmd(cmd, s.dest): quit "invalid command: " & cmd - let epccmd = if s.cmd.contains("--v3"): - s.cmd.replace("--tester", "--epc --log") - else: - s.cmd.replace("--tester", "--epc --v2 --log") + let epccmd = s.cmd.replace("--tester", "--epc --v2 --log") let cl = parseCmdLine(epccmd) var p = startProcess(command=cl[0], args=cl[1 .. ^1], options={poStdErrToStdOut, poUsePath, poInteractive, poDaemon}) let outp = p.outputStream + let inp = p.inputStream var report = "" var socket = newSocket() try: @@ -281,20 +269,15 @@ proc runEpcTest(filename: string): int = let a = outp.readAll().strip() let port = parseInt(a) socket.connect("localhost", Port(port)) - for req, resp in items(s.script): if not runCmd(req, s.dest): socket.sendEpcStr(req) let sx = parseSexp(socket.recvEpc()) if not req.startsWith("mod "): - let answer = if sx[2].kind == SNil: "" else: sexpToAnswer(sx) + let answer = sexpToAnswer(sx) doReport(filename, answer, resp, report) - - socket.sendEpcStr "return arg" - # bugfix: this was in `finally` block, causing the original error to be - # potentially masked by another one in case `socket.sendEpcStr` raises - # (e.g. if socket couldn't connect in the 1st place) finally: + socket.sendEpcStr "return arg" close(p) if report.len > 0: echo "==== EPC ========================================" @@ -330,12 +313,8 @@ proc runTest(filename: string): int = answer.add '\L' doReport(filename, answer, resp, report) finally: - try: - inp.writeLine("quit") - inp.flush() - except IOError, OSError: - # assume it's SIGPIPE, ie, the child already died - discard + inp.writeLine("quit") + inp.flush() close(p) if report.len > 0: echo "==== STDIN ======================================" @@ -347,16 +326,11 @@ proc main() = if os.paramCount() > 0: let x = os.paramStr(1) let xx = expandFilename x - # run only stdio when running single test failures += runTest(xx) + failures += runEpcTest(xx) else: - let files = toSeq(walkFiles(tpath / "t*.nim")) - for i, x in files: - echo "$#/$# test: $#" % [$i, $files.len, x] - when defined(i386): - if x == "nimsuggest/tests/tmacro_highlight.nim": - echo "skipping" # workaround bug #17945 - continue + for x in walkFiles(getAppDir() / "tests/t*.nim"): + echo "Test ", x let xx = expandFilename x when not defined(windows): # XXX Windows IO redirection seems bonkers: diff --git a/nimsuggest/tests/fixtures/mdep_v1.nim b/nimsuggest/tests/dep_v1.nim similarity index 100% rename from nimsuggest/tests/fixtures/mdep_v1.nim rename to nimsuggest/tests/dep_v1.nim diff --git a/nimsuggest/tests/fixtures/mdep_v2.nim b/nimsuggest/tests/dep_v2.nim similarity index 100% rename from nimsuggest/tests/fixtures/mdep_v2.nim rename to nimsuggest/tests/dep_v2.nim diff --git a/nimsuggest/tests/ttemplate_highlight.nim b/nimsuggest/tests/disabled_ttemplate_highlight.nim similarity index 100% rename from nimsuggest/tests/ttemplate_highlight.nim rename to nimsuggest/tests/disabled_ttemplate_highlight.nim diff --git a/nimsuggest/tests/fixtures/mclass_macro.nim b/nimsuggest/tests/fixtures/mclass_macro.nim deleted file mode 100644 index cfca0bf3f..000000000 --- a/nimsuggest/tests/fixtures/mclass_macro.nim +++ /dev/null @@ -1,164 +0,0 @@ - -import macros - -macro class*(head, body: untyped): untyped = - # The macro is immediate, since all its parameters are untyped. - # This means, it doesn't resolve identifiers passed to it. - - var typeName, baseName: NimNode - - # flag if object should be exported - var exported: bool - - if head.kind == nnkInfix and head[0].kind == nnkIdent and $head[0] == "of": - # `head` is expression `typeName of baseClass` - # echo head.treeRepr - # -------------------- - # Infix - # Ident !"of" - # Ident !"Animal" - # Ident !"RootObj" - typeName = head[1] - baseName = head[2] - - elif head.kind == nnkInfix and head[0].kind == nnkIdent and - $head[0] == "*" and head[2].kind == nnkPrefix and - head[2][0].kind == nnkIdent and $head[2][0] == "of": - # `head` is expression `typeName* of baseClass` - # echo head.treeRepr - # -------------------- - # Infix - # Ident !"*" - # Ident !"Animal" - # Prefix - # Ident !"of" - # Ident !"RootObj" - typeName = head[1] - baseName = head[2][1] - exported = true - - else: - quit "Invalid node: " & head.lispRepr - - # The following prints out the AST structure: - # - # import macros - # dumptree: - # type X = ref object of Y - # z: int - # -------------------- - # StmtList - # TypeSection - # TypeDef - # Ident !"X" - # Empty - # RefTy - # ObjectTy - # Empty - # OfInherit - # Ident !"Y" - # RecList - # IdentDefs - # Ident !"z" - # Ident !"int" - # Empty - - # create a type section in the result - result = newNimNode(nnkStmtList) - result.add( - if exported: - # mark `typeName` with an asterisk - quote do: - type `typeName`* = ref object of `baseName` - else: - quote do: - type `typeName` = ref object of `baseName` - ) - - # echo treeRepr(body) - # -------------------- - # StmtList - # VarSection - # IdentDefs - # Ident !"name" - # Ident !"string" - # Empty - # IdentDefs - # Ident !"age" - # Ident !"int" - # Empty - # MethodDef - # Ident !"vocalize" - # Empty - # Empty - # FormalParams - # Ident !"string" - # Empty - # Empty - # StmtList - # StrLit ... - # MethodDef - # Ident !"age_human_yrs" - # Empty - # Empty - # FormalParams - # Ident !"int" - # Empty - # Empty - # StmtList - # DotExpr - # Ident !"this" - # Ident !"age" - - # var declarations will be turned into object fields - var recList = newNimNode(nnkRecList) - - # expected name of constructor - let ctorName = newIdentNode("new" & $typeName) - - # Iterate over the statements, adding `this: T` - # to the parameters of functions, unless the - # function is a constructor - for node in body.children: - case node.kind: - - of nnkMethodDef, nnkProcDef: - # check if it is the ctor proc - if node.name.kind != nnkAccQuoted and node.name.basename == ctorName: - # specify the return type of the ctor proc - node.params[0] = typeName - else: - # inject `self: T` into the arguments - node.params.insert(1, newIdentDefs(ident("self"), typeName)) - result.add(node) - - of nnkVarSection: - # variables get turned into fields of the type. - for n in node.children: - recList.add(n) - - else: - result.add(node) - - # Inspect the tree structure: - # - # echo result.treeRepr - # -------------------- - # StmtList - # TypeSection - # TypeDef - # Ident !"Animal" - # Empty - # RefTy - # ObjectTy - # Empty - # OfInherit - # Ident !"RootObj" - # Empty <= We want to replace this - # MethodDef - # ... - - result[0][0][2][0][2] = recList - - # Lets inspect the human-readable version of the output - #echo repr(result) diff --git a/nimsuggest/tests/fixtures/mfakeassert.nim b/nimsuggest/tests/fixtures/mfakeassert.nim deleted file mode 100644 index 765831ba7..000000000 --- a/nimsuggest/tests/fixtures/mfakeassert.nim +++ /dev/null @@ -1,5 +0,0 @@ -# Template for testing defs - -template fakeAssert*(cond: untyped, msg: string = "") = - ## template to allow def lookup testing - if not cond: quit(1) diff --git a/nimsuggest/tests/fixtures/minclude_import.nim b/nimsuggest/tests/fixtures/minclude_import.nim deleted file mode 100644 index 5fa9e5142..000000000 --- a/nimsuggest/tests/fixtures/minclude_import.nim +++ /dev/null @@ -1,15 +0,0 @@ -# Creates an awkward set of dependencies between this, import, and include. -# This pattern appears in the compiler, compiler/(sem|ast|semexprs).nim. - -import mfakeassert -import minclude_types - -proc say*(g: Greet): string = - fakeAssert(true, "always works") - g.greeting & ", " & g.subject & "!" - -include minclude_include - -proc say*(): string = - fakeAssert(1 + 1 == 2, "math works") - say(create()) diff --git a/nimsuggest/tests/fixtures/minclude_include.nim b/nimsuggest/tests/fixtures/minclude_include.nim deleted file mode 100644 index 23f9892cc..000000000 --- a/nimsuggest/tests/fixtures/minclude_include.nim +++ /dev/null @@ -1,4 +0,0 @@ -# this file is included and relies on imports within the include - -proc create*(greeting: string = "Hello", subject: string = "World"): Greet = - Greet(greeting: greeting, subject: subject) diff --git a/nimsuggest/tests/fixtures/minclude_types.nim b/nimsuggest/tests/fixtures/minclude_types.nim deleted file mode 100644 index 3e85ee540..000000000 --- a/nimsuggest/tests/fixtures/minclude_types.nim +++ /dev/null @@ -1,6 +0,0 @@ -# types used by minclude_* (import or include), to find with def in include - -type - Greet* = object - greeting*: string - subject*: string \ No newline at end of file diff --git a/nimsuggest/tests/fixtures/mstrutils.nim b/nimsuggest/tests/fixtures/mstrutils.nim deleted file mode 100644 index d6f25571b..000000000 --- a/nimsuggest/tests/fixtures/mstrutils.nim +++ /dev/null @@ -1,19 +0,0 @@ -import mfakeassert - -func rereplace*(s, sub: string; by: string = ""): string {.used.} = - ## competes for priority in suggestion, here first, but never used in test - - fakeAssert(true, "always works") - result = by - -func replace*(s, sub: string; by: string = ""): string = - ## this is a test version of strutils.replace, it simply returns `by` - - fakeAssert("".len == 0, "empty string is empty") - result = by - -func rerereplace*(s, sub: string; by: string = ""): string {.used.} = - ## isn't used and appears last, lowest priority - - fakeAssert(false, "never works") - result = by diff --git a/nimsuggest/tests/t20440.nim b/nimsuggest/tests/t20440.nim deleted file mode 100644 index 0456aa074..000000000 --- a/nimsuggest/tests/t20440.nim +++ /dev/null @@ -1,7 +0,0 @@ -when not defined(js): - {.fatal: "Crash".} -echo 4 - -discard """ -$nimsuggest --v3 --tester $file -""" diff --git a/nimsuggest/tests/t20440.nims b/nimsuggest/tests/t20440.nims deleted file mode 100644 index 1336be3d4..000000000 --- a/nimsuggest/tests/t20440.nims +++ /dev/null @@ -1 +0,0 @@ -switch("backend", "js") diff --git a/nimsuggest/tests/t21185.nim b/nimsuggest/tests/t21185.nim deleted file mode 100644 index bf5a0e3cc..000000000 --- a/nimsuggest/tests/t21185.nim +++ /dev/null @@ -1,18 +0,0 @@ - -# Reduced case of 21185. Issue was first parameter being static -proc foo(x: static[int]) = discard - -type - Person = object - name: string - age: int - -let p = Person() -p.#[!]# - -discard """ -$nimsuggest --tester --v3 --maxresults:2 $file ->sug $1 -sug;;skField;;age;;int;;$file;;8;;4;;"";;100;;None -sug;;skField;;name;;string;;$file;;7;;4;;"";;100;;None -""" diff --git a/nimsuggest/tests/tchk1.nim b/nimsuggest/tests/tchk1.nim index be6115c1c..2b60ed094 100644 --- a/nimsuggest/tests/tchk1.nim +++ b/nimsuggest/tests/tchk1.nim @@ -15,13 +15,14 @@ proc main = #[!]# discard """ +disabled:true $nimsuggest --tester $file >chk $1 -chk;;skUnknown;;;;Hint;;???;;0;;-1;;">> (toplevel): import(dirty): tests/tchk1.nim [Processing]";;0 -chk;;skUnknown;;;;Error;;$file;;12;;0;;"identifier expected, but got \'keyword template\'";;0 -chk;;skUnknown;;;;Error;;$file;;14;;0;;"nestable statement requires indentation";;0 -chk;;skUnknown;;;;Error;;$file;;17;;0;;"invalid indentation";;0 +chk;;skUnknown;;;;Hint;;???;;-1;;-1;;"tchk1 [Processing]";;0 +chk;;skUnknown;;;;Error;;$file;;12;;0;;"identifier expected, but found \'keyword template\'";;0 +chk;;skUnknown;;;;Error;;$file;;14;;0;;"complex statement requires indentation";;0 chk;;skUnknown;;;;Error;;$file;;12;;0;;"implementation of \'foo\' expected";;0 +chk;;skUnknown;;;;Error;;$file;;17;;0;;"invalid indentation";;0 chk;;skUnknown;;;;Hint;;$file;;12;;9;;"\'foo\' is declared but not used [XDeclaredButNotUsed]";;0 -chk;;skUnknown;;;;Hint;;$file;;14;;5;;"\'main\' is declared but not used [XDeclaredButNotUsed]";;0 +chk;;skUnknown;;;;Hint;;$file;;14;;5;;"\'tchk1.main()[declared in tchk1.nim(14, 5)]\' is declared but not used [XDeclaredButNotUsed]";;0 """ diff --git a/nimsuggest/tests/tchk_compiles.nim b/nimsuggest/tests/tchk_compiles.nim deleted file mode 100644 index c8a3daac4..000000000 --- a/nimsuggest/tests/tchk_compiles.nim +++ /dev/null @@ -1,8 +0,0 @@ -discard compiles(2 + "hello") - -#[!]# -discard """ -$nimsuggest --tester $file ->chk $1 -chk;;skUnknown;;;;Hint;;???;;0;;-1;;">> (toplevel): import(dirty): tests/tchk_compiles.nim [Processing]";;0 -""" diff --git a/nimsuggest/tests/tcon1.nim b/nimsuggest/tests/tcon1.nim index 627e7f400..262dd5151 100644 --- a/nimsuggest/tests/tcon1.nim +++ b/nimsuggest/tests/tcon1.nim @@ -1,43 +1,13 @@ -## Test Invocation `con`text in various situations - -## various of this proc are used as the basis for these tests proc test(s: string; a: int) = discard - -## This overload should be used to ensure the lower airity `test` doesn't match -proc test(s: string; a: string, b: int) = discard - -## similar signature but different name to ensure `con` doesn't get greedy proc testB(a, b: string) = discard - -# with a param already specified test("hello here", #[!]#) - -# as first param testB(#[!]# -# dot expressions -"from behind".test(#[!]# - -# two params matched, so disqualify the lower airity `test` -# TODO: this doesn't work, because dot exprs, overloads, etc aren't currently -# handled by suggest.suggestCall. sigmatch.partialMatch by way of -# sigmatch.matchesAux. Doesn't use the operand before the dot as part of -# the formal parameters. Changing this is tricky because it's used by -# the proper compilation sem pass and that's a big change all in one go. -"and again".test("more", #[!]# - discard """ $nimsuggest --tester $file >con $1 -con;;skProc;;tcon1.test;;proc (s: string, a: int);;$file;;4;;5;;"";;100 -con;;skProc;;tcon1.test;;proc (s: string, a: string, b: int);;$file;;7;;5;;"";;100 +con;;skProc;;tcon1.test;;proc (s: string, a: int);;$file;;1;;5;;"";;100 >con $2 -con;;skProc;;tcon1.testB;;proc (a: string, b: string);;$file;;10;;5;;"";;100 ->con $3 -con;;skProc;;tcon1.test;;proc (s: string, a: string, b: int);;$file;;7;;5;;"";;100 -con;;skProc;;tcon1.test;;proc (s: string, a: int);;$file;;4;;5;;"";;100 ->con $4 -con;;skProc;;tcon1.test;;proc (s: string, a: int);;$file;;4;;5;;"";;100 -con;;skProc;;tcon1.test;;proc (s: string, a: string, b: int);;$file;;7;;5;;"";;100 +con;;skProc;;tcon1.testB;;proc (a: string, b: string);;$file;;2;;5;;"";;100 """ diff --git a/nimsuggest/tests/tdef1.nim b/nimsuggest/tests/tdef1.nim index 5c86923b6..2cd040ea1 100644 --- a/nimsuggest/tests/tdef1.nim +++ b/nimsuggest/tests/tdef1.nim @@ -1,9 +1,9 @@ discard """ $nimsuggest --tester $file >def $1 -def;;skProc;;tdef1.hello;;proc (): string{.noSideEffect, gcsafe.};;$file;;9;;5;;"Return hello";;100 +def;;skProc;;tdef1.hello;;proc (): string{.noSideEffect, gcsafe, locks: 0.};;$file;;9;;5;;"Return hello";;100 >def $1 -def;;skProc;;tdef1.hello;;proc (): string{.noSideEffect, gcsafe.};;$file;;9;;5;;"Return hello";;100 +def;;skProc;;tdef1.hello;;proc (): string{.noSideEffect, gcsafe, locks: 0.};;$file;;9;;5;;"Return hello";;100 """ proc hello(): string = diff --git a/nimsuggest/tests/tdef2.nim b/nimsuggest/tests/tdef2.nim deleted file mode 100644 index 299b83a3d..000000000 --- a/nimsuggest/tests/tdef2.nim +++ /dev/null @@ -1,13 +0,0 @@ -# Test def with template and boundaries for the cursor - -import fixtures/mstrutils - -discard """ -$nimsuggest --tester $file ->def $path/fixtures/mstrutils.nim:6:4 -def;;skTemplate;;mfakeassert.fakeAssert;;template (cond: untyped, msg: string);;*fixtures/mfakeassert.nim;;3;;9;;"template to allow def lookup testing";;100 ->def $path/fixtures/mstrutils.nim:12:3 -def;;skTemplate;;mfakeassert.fakeAssert;;template (cond: untyped, msg: string);;*fixtures/mfakeassert.nim;;3;;9;;"template to allow def lookup testing";;100 ->def $path/fixtures/mstrutils.nim:18:11 -def;;skTemplate;;mfakeassert.fakeAssert;;template (cond: untyped, msg: string);;*fixtures/mfakeassert.nim;;3;;9;;"template to allow def lookup testing";;100 -""" diff --git a/nimsuggest/tests/tdef_forward.nim b/nimsuggest/tests/tdef_forward.nim deleted file mode 100644 index 9bdd8b21d..000000000 --- a/nimsuggest/tests/tdef_forward.nim +++ /dev/null @@ -1,13 +0,0 @@ -discard """ -$nimsuggest --tester $file ->def $1 -def;;skProc;;tdef_forward.hello;;proc (): string;;$file;;8;;5;;"";;100 -def;;skProc;;tdef_forward.hello;;proc (): string;;$file;;12;;5;;"";;100 -""" - -proc hello(): string - -hel#[!]#lo() - -proc hello(): string = - "Hello" diff --git a/nimsuggest/tests/tdef_let.nim b/nimsuggest/tests/tdef_let.nim deleted file mode 100644 index 3e9456d2f..000000000 --- a/nimsuggest/tests/tdef_let.nim +++ /dev/null @@ -1,7 +0,0 @@ -discard """ -$nimsuggest --tester $file ->def $1 -def;;skLet;;tdef_let.intVar;;int;;$file;;7;;4;;"";;100 -""" - -let int#[!]#Var = 10 diff --git a/nimsuggest/tests/tdot3.nim b/nimsuggest/tests/tdot3.nim index 30dd60591..15fc1cd1c 100644 --- a/nimsuggest/tests/tdot3.nim +++ b/nimsuggest/tests/tdot3.nim @@ -9,14 +9,14 @@ proc main(f: Foo) = # this way, the line numbers more often stay the same discard """ -!copy fixtures/mdep_v1.nim dep.nim +!copy dep_v1.nim dep.nim $nimsuggest --tester $file >sug $1 sug;;skField;;x;;int;;*dep.nim;;8;;4;;"";;100;;None sug;;skField;;y;;int;;*dep.nim;;8;;8;;"";;100;;None sug;;skProc;;tdot3.main;;proc (f: Foo);;$file;;5;;5;;"";;100;;None -!copy fixtures/mdep_v2.nim dep.nim +!copy dep_v2.nim dep.nim >mod $path/dep.nim >sug $1 sug;;skField;;x;;int;;*dep.nim;;8;;4;;"";;100;;None diff --git a/nimsuggest/tests/tdot4.nim b/nimsuggest/tests/tdot4.nim index 8681d045a..762534310 100644 --- a/nimsuggest/tests/tdot4.nim +++ b/nimsuggest/tests/tdot4.nim @@ -1,21 +1,17 @@ -# Test that already used suggestions are prioritized +discard """ +disabled:true +$nimsuggest --tester --maxresults:2 $file +>sug $1 +sug;;skProc;;tdot4.main;;proc (inp: string): string;;$file;;10;;5;;"";;100;;None +sug;;skProc;;strutils.replace;;proc (s: string, sub: string, by: string): string{.noSideEffect, gcsafe, locks: 0.};;$lib/pure/strutils.nim;;1506;;5;;"Replaces `sub` in `s` by the string `by`.";;100;;None +""" -from system import string, echo -import fixtures/mstrutils +import strutils proc main(inp: string): string = # use replace here and see if it occurs in the result, it should gain # priority: result = inp.replace(" ", "a").replace("b", "c") + echo "string literal here".#[!]# - -# priority still tested, but limit results to avoid failures from other output -discard """ -$nimsuggest --tester --maxresults:2 $file ->sug $1 -sug;;skProc;;tdot4.main;;proc (inp: string): string;;$file;;6;;5;;"";;100;;None -sug;;skFunc;;mstrutils.replace;;proc (s: string, sub: string, by: string): string{.noSideEffect, gcsafe.};;*fixtures/mstrutils.nim;;9;;5;;"this is a test version of strutils.replace, it simply returns `by`";;100;;None -""" - -# TODO - determine appropriate behaviour for further suggest output and test it diff --git a/nimsuggest/tests/tgeneric_highlight.nim b/nimsuggest/tests/tgeneric_highlight.nim index f351ab705..334323613 100644 --- a/nimsuggest/tests/tgeneric_highlight.nim +++ b/nimsuggest/tests/tgeneric_highlight.nim @@ -8,10 +8,12 @@ $nimsuggest --tester $file highlight;;skType;;1;;7;;3 highlight;;skProc;;1;;0;;6 highlight;;skProc;;1;;0;;6 +highlight;;skType;;1;;7;;3 highlight;;skProc;;1;;0;;6 highlight;;skType;;2;;14;;3 highlight;;skProc;;2;;7;;6 highlight;;skProc;;2;;7;;6 +highlight;;skType;;2;;14;;3 highlight;;skProc;;2;;7;;6 highlight;;skTemplate;;3;;0;;8 highlight;;skType;;3;;9;;3 diff --git a/nimsuggest/tests/tinclude.nim b/nimsuggest/tests/tinclude.nim index 66726f907..0fda43911 100644 --- a/nimsuggest/tests/tinclude.nim +++ b/nimsuggest/tests/tinclude.nim @@ -1,25 +1,8 @@ -# import that has an include: -# * def calls must work into and out of includes -# * outline calls on the import must show included members -import fixtures/minclude_import - -proc go() = - discard create().say() - -go() - discard """ -$nimsuggest --tester $file ->def $path/tinclude.nim:7:14 -def;;skProc;;minclude_import.create;;proc (greeting: string, subject: string): Greet{.noSideEffect, gcsafe.};;*fixtures/minclude_include.nim;;3;;5;;"";;100 ->def $path/fixtures/minclude_include.nim:3:71 -def;;skType;;minclude_types.Greet;;Greet;;*fixtures/minclude_types.nim;;4;;2;;"";;100 ->def $path/fixtures/minclude_include.nim:3:71 -def;;skType;;minclude_types.Greet;;Greet;;*fixtures/minclude_types.nim;;4;;2;;"";;100 ->outline $path/fixtures/minclude_import.nim -outline;;skProc;;minclude_import.say;;*fixtures/minclude_import.nim;;7;;5;;"";;100 -outline;;skProc;;minclude_import.create;;*fixtures/minclude_include.nim;;3;;5;;"";;100 -outline;;skProc;;minclude_import.say;;*fixtures/minclude_import.nim;;13;;5;;"";;100 +disabled:true +$nimsuggest --tester compiler/nim.nim +>def compiler/semexprs.nim:25:50 +def;;skType;;ast.PSym;;PSym;;*ast.nim;;707;;2;;"";;100 +>def compiler/semexprs.nim:25:50 +def;;skType;;ast.PSym;;PSym;;*ast.nim;;707;;2;;"";;100 """ - -# TODO test/fix if the first `def` is not first or repeated we get no results diff --git a/nimsuggest/tests/top_highlight.nim b/nimsuggest/tests/top_highlight.nim deleted file mode 100644 index c3f6bb61d..000000000 --- a/nimsuggest/tests/top_highlight.nim +++ /dev/null @@ -1,11 +0,0 @@ -import json - -%*{}#[!]# - -discard """ -$nimsuggest --tester $file ->highlight $1 -highlight;;skModule;;1;;7;;4 -highlight;;skMacro;;3;;0;;2 -highlight;;skMacro;;3;;0;;2 -""" diff --git a/nimsuggest/tests/tqualified_highlight.nim b/nimsuggest/tests/tqualified_highlight.nim index b83669e72..3b521ecc1 100644 --- a/nimsuggest/tests/tqualified_highlight.nim +++ b/nimsuggest/tests/tqualified_highlight.nim @@ -10,5 +10,5 @@ highlight;;skProc;;1;;7;;4 highlight;;skTemplate;;2;;7;;4 highlight;;skTemplate;;2;;7;;4 highlight;;skTemplate;;2;;7;;4 -highlight;;skFunc;;3;;8;;1 +highlight;;skProc;;3;;8;;1 """ diff --git a/nimsuggest/tests/tstrutils.nim b/nimsuggest/tests/tstrutils.nim new file mode 100644 index 000000000..9462c3d99 --- /dev/null +++ b/nimsuggest/tests/tstrutils.nim @@ -0,0 +1,10 @@ +discard """ +disabled:true +$nimsuggest --tester lib/pure/strutils.nim +>def lib/pure/strutils.nim:2529:6 +def;;skTemplate;;system.doAssert;;proc (cond: bool, msg: string): typed;;*/lib/system.nim;;*;;9;;"same as `assert` but is always turned on and not affected by the\x0A``--assertions`` command line switch.";;100 +""" + +# Line 2529 in strutils.nim is doAssert and this is unlikely to change +# soon since there are a whole lot of doAsserts there. + diff --git a/nimsuggest/tests/tsug_enum.nim b/nimsuggest/tests/tsug_enum.nim deleted file mode 100644 index 97a225f16..000000000 --- a/nimsuggest/tests/tsug_enum.nim +++ /dev/null @@ -1,18 +0,0 @@ -## suggestions for enums - -type - LogLevel {.pure.} = enum - debug, log, warn, error - - FooBar = enum - fbFoo, fbBar - -echo fbFoo, fbBar - -echo LogLevel.deb#[!]# - -discard """ -$nimsuggest --tester $file ->sug $1 -sug;;skEnumField;;debug;;LogLevel;;*nimsuggest/tests/tsug_enum.nim;;5;;4;;"";;100;;Prefix -""" \ No newline at end of file diff --git a/nimsuggest/tests/tsug_regression.nim b/nimsuggest/tests/tsug_regression.nim index 2aff3fe94..1b23da806 100644 --- a/nimsuggest/tests/tsug_regression.nim +++ b/nimsuggest/tests/tsug_regression.nim @@ -7,28 +7,23 @@ type X = object proc main = # bug #52 var - set0 = initHashSet[int]() - set1 = initHashSet[X]() - set2 = initHashSet[ref int]() + set0 = initSet[int]() + set1 = initSet[X]() + set2 = initSet[ref int]() map0 = initTable[int, int]() map1 = initOrderedTable[string, int]() cfg = loadConfig("file") map0.#[!]# -# the maxresults are limited as it seems there is sort or some other -# instability that causes the suggestions to slightly differ between 32 bit -# and 64 bit versions of nimsuggest - discard """ disabled:true -$nimsuggest --tester --maxresults:4 $file +$nimsuggest --tester $file >sug $1 -sug;;skProc;;tables.hasKey;;proc (t: Table[hasKey.A, hasKey.B], key: A): bool;;*/lib/pure/collections/tables.nim;;374;;5;;"Returns true *";;100;;None -sug;;skProc;;tables.clear;;proc (t: var Table[clear.A, clear.B]);;*/lib/pure/collections/tables.nim;;567;;5;;"Resets the table so that it is empty*";;100;;None -sug;;skProc;;tables.contains;;proc (t: Table[contains.A, contains.B], key: A): bool;;*/lib/pure/collections/tables.nim;;*;;5;;"Alias of *";;100;;None -sug;;skProc;;tables.del;;proc (t: var Table[del.A, del.B], key: A);;*/lib/pure/collections/tables.nim;;*;;5;;"*";;100;;None +sug;;skProc;;tables.getOrDefault;;proc (t: Table[getOrDefault.A, getOrDefault.B], key: A): B;;$lib/pure/collections/tables.nim;;178;;5;;"";;100;;None +sug;;skProc;;tables.hasKey;;proc (t: Table[hasKey.A, hasKey.B], key: A): bool;;$lib/pure/collections/tables.nim;;233;;5;;"returns true iff `key` is in the table `t`.";;100;;None +sug;;skProc;;tables.add;;proc (t: var Table[add.A, add.B], key: A, val: B);;$lib/pure/collections/tables.nim;;309;;5;;"puts a new (key, value)-pair into `t` even if ``t[key]`` already exists.";;100;;None +sug;;skIterator;;tables.allValues;;iterator (t: Table[allValues.A, allValues.B], key: A): B{.inline.};;$lib/pure/collections/tables.nim;;225;;9;;"iterates over any value in the table `t` that belongs to the given `key`.";;100;;None +sug;;skProc;;tables.clear;;proc (t: var Table[clear.A, clear.B]);;$lib/pure/collections/tables.nim;;121;;5;;"Resets the table so that it is empty.";;100;;None +* """ - -# TODO enable the tests -# TODO: test/fix suggestion sorting - deprecated suggestions should rank lower diff --git a/nimsuggest/tests/tsug_template.nim b/nimsuggest/tests/tsug_template.nim index a2558c81c..0f258fcc6 100644 --- a/nimsuggest/tests/tsug_template.nim +++ b/nimsuggest/tests/tsug_template.nim @@ -6,7 +6,7 @@ tmp#[!]# discard """ $nimsuggest --tester $file >sug $1 -sug;;skMacro;;tsug_template.tmpb;;macro (){.noSideEffect, gcsafe.};;$file;;2;;6;;"";;100;;Prefix -sug;;skConverter;;tsug_template.tmpc;;converter ();;$file;;3;;10;;"";;100;;Prefix -sug;;skTemplate;;tsug_template.tmpa;;template ();;$file;;1;;9;;"";;100;;Prefix +sug;;skMacro;;tsug_template.tmpb;;macro (){.noSideEffect, gcsafe, locks: 0.};;$file;;2;;6;;"";;0;;Prefix +sug;;skConverter;;tsug_template.tmpc;;converter ();;$file;;3;;10;;"";;0;;Prefix +sug;;skTemplate;;tsug_template.tmpa;;template ();;$file;;1;;9;;"";;0;;Prefix """ diff --git a/nimsuggest/tests/tsug_typedecl.nim b/nimsuggest/tests/tsug_typedecl.nim deleted file mode 100644 index 2a510929d..000000000 --- a/nimsuggest/tests/tsug_typedecl.nim +++ /dev/null @@ -1,26 +0,0 @@ -# suggestions for type declarations - -from system import string, int, bool - -type - super = int - someType = bool - -let str = "hello" - -proc main() = - let a: s#[!]# - -# This output show seq, even though that's not imported. This is due to the -# entire symbol table, regardless of import visibility is currently being -# scanned. This is hardly ideal, but changing it with the current level of test -# coverage is unwise as it might break more than it fixes. - -discard """ -$nimsuggest --tester $file ->sug $1 -sug;;skType;;tsug_typedecl.someType;;someType;;*nimsuggest/tests/tsug_typedecl.nim;;7;;2;;"";;100;;Prefix -sug;;skType;;tsug_typedecl.super;;super;;*nimsuggest/tests/tsug_typedecl.nim;;6;;2;;"";;100;;Prefix -sug;;skType;;system.string;;string;;*lib/system/basic_types.nim;;*;;*;;*;;100;;Prefix -sug;;skType;;system.seq;;seq;;*lib/system.nim;;*;;*;;*;;100;;Prefix -""" diff --git a/nimsuggest/tests/ttempl_inst.nim b/nimsuggest/tests/ttempl_inst.nim deleted file mode 100644 index 5f5b10fe9..000000000 --- a/nimsuggest/tests/ttempl_inst.nim +++ /dev/null @@ -1,13 +0,0 @@ -template foo() = - {.warning: "foo".} - -foo() - -#[!]# -discard """ -$nimsuggest --tester $file ->chk $1 -chk;;skUnknown;;;;Hint;;???;;0;;-1;;">> (toplevel): import(dirty): tests/ttempl_inst.nim [Processing]";;0 -chk;;skUnknown;;;;Hint;;$file;;4;;3;;"template/generic instantiation from here";;0 -chk;;skUnknown;;;;Warning;;$file;;2;;11;;"foo [User]";;0 -""" diff --git a/nimsuggest/tests/ttype_decl.nim b/nimsuggest/tests/ttype_decl.nim index 61d8c26cd..e66d39a1c 100644 --- a/nimsuggest/tests/ttype_decl.nim +++ b/nimsuggest/tests/ttype_decl.nim @@ -1,16 +1,15 @@ discard """ +disabled:true $nimsuggest --tester --maxresults:3 $file >sug $1 -sug;;skType;;ttype_decl.Other;;Other;;$file;;10;;2;;"";;100;;None -sug;;skType;;system.int;;int;;*lib/system/basic_types.nim;;2;;2;;"";;100;;None -sug;;skType;;system.string;;string;;*lib/system/basic_types.nim;;23;;2;;"";;100;;None +sug;;skType;;ttype_decl.Other;;Other;;$file;;10;;2;;"";;0;;None +sug;;skType;;system.int;;int;;$lib/system.nim;;25;;2;;"";;0;;None +sug;;skType;;system.string;;string;;$lib/system.nim;;48;;2;;"";;0;;None """ import strutils type Other = object ## My other object. Foo = #[!]# - OldOne {.deprecated.} = object - x: int proc main(f: Foo) = diff --git a/nimsuggest/tests/tuse.nim b/nimsuggest/tests/tuse.nim deleted file mode 100644 index deaf81ef2..000000000 --- a/nimsuggest/tests/tuse.nim +++ /dev/null @@ -1,22 +0,0 @@ -# basic tests for use - -# bug #58 -proc someOtherProc() = - discard - -someOtherProc() - -proc #[!]#someProc*() = - discard - -#[!]#someProc() - -discard """ -$nimsuggest --tester $file ->use $1 -def;;skProc;;tuse.someProc;;proc (){.noSideEffect, gcsafe.};;$file;;9;;5;;"";;100 -use;;skProc;;tuse.someProc;;proc (){.noSideEffect, gcsafe.};;$file;;12;;0;;"";;100 ->use $2 -def;;skProc;;tuse.someProc;;proc (){.noSideEffect, gcsafe.};;$file;;9;;5;;"";;100 -use;;skProc;;tuse.someProc;;proc (){.noSideEffect, gcsafe.};;$file;;12;;0;;"";;100 -""" diff --git a/nimsuggest/tests/tuse_structure.nim b/nimsuggest/tests/tuse_structure.nim deleted file mode 100644 index f65ab9060..000000000 --- a/nimsuggest/tests/tuse_structure.nim +++ /dev/null @@ -1,15 +0,0 @@ -# tests for use and structures - -type - Foo* = ref object of RootObj - bar*: string - -proc test(f: Foo) = - echo f.#[!]#bar - -discard """ -$nimsuggest --tester $file ->use $1 -def skField tuse_structure.Foo.bar string $file 5 4 "" 100 -use skField tuse_structure.Foo.bar string $file 8 9 "" 100 -""" diff --git a/nimsuggest/tests/tv3.nim b/nimsuggest/tests/tv3.nim deleted file mode 100644 index fd736a1d8..000000000 --- a/nimsuggest/tests/tv3.nim +++ /dev/null @@ -1,27 +0,0 @@ -# tests v3 - -type - Foo* = ref object of RootObj - bar*: string - -proc test(f: Foo) = - echo f.ba#[!]#r - -#[!]# - -discard """ -$nimsuggest --v3 --tester $file ->use $1 -def skField tv3.Foo.bar string $file 5 4 "" 100 -use skField tv3.Foo.bar string $file 8 9 "" 100 ->def $1 -def skField tv3.Foo.bar string $file 5 4 "" 100 ->sug $1 -sug skField bar string $file 5 4 "" 100 Prefix ->globalSymbols test -def skProc tv3.test proc (f: Foo){.gcsafe.} $file 7 5 "" 100 ->globalSymbols Foo -def skType tv3.Foo Foo $file 4 2 "" 100 ->def $2 ->use $2 -""" diff --git a/nimsuggest/tests/tv3_definition.nim b/nimsuggest/tests/tv3_definition.nim deleted file mode 100644 index 03684b7cd..000000000 --- a/nimsuggest/tests/tv3_definition.nim +++ /dev/null @@ -1,9 +0,0 @@ - -let foo = 30 -let bar = foo + fo#[!]#o + foo - -discard """ -$nimsuggest --v3 --tester $file ->def $1 -def skLet tv3_definition.foo int $file 2 4 "" 100 -""" diff --git a/nimsuggest/tests/tv3_forward_definition.nim b/nimsuggest/tests/tv3_forward_definition.nim deleted file mode 100644 index 392e019ff..000000000 --- a/nimsuggest/tests/tv3_forward_definition.nim +++ /dev/null @@ -1,23 +0,0 @@ -proc de#[!]#mo(): int - -proc de#[!]#mo(): int = 5 - -let a = de#[!]#mo() - -discard """ -$nimsuggest --v3 --tester $file ->use $1 -use skProc tv3_forward_definition.demo proc (): int{.noSideEffect, gcsafe.} $file 1 5 "" 100 -def skProc tv3_forward_definition.demo proc (): int{.noSideEffect, gcsafe.} $file 3 5 "" 100 -use skProc tv3_forward_definition.demo proc (): int{.noSideEffect, gcsafe.} $file 5 8 "" 100 ->use $2 -use skProc tv3_forward_definition.demo proc (): int{.noSideEffect, gcsafe.} $file 1 5 "" 100 -def skProc tv3_forward_definition.demo proc (): int{.noSideEffect, gcsafe.} $file 3 5 "" 100 -use skProc tv3_forward_definition.demo proc (): int{.noSideEffect, gcsafe.} $file 5 8 "" 100 ->declaration $1 -declaration skProc tv3_forward_definition.demo proc (): int{.noSideEffect, gcsafe.} $file 3 5 "" 100 ->declaration $2 -declaration skProc tv3_forward_definition.demo proc (): int{.noSideEffect, gcsafe.} $file 1 5 "" 100 ->declaration $3 -declaration skProc tv3_forward_definition.demo proc (): int{.noSideEffect, gcsafe.} $file 1 5 "" 100 -""" diff --git a/nimsuggest/tests/tv3_globalSymbols.nim b/nimsuggest/tests/tv3_globalSymbols.nim deleted file mode 100644 index f965a07aa..000000000 --- a/nimsuggest/tests/tv3_globalSymbols.nim +++ /dev/null @@ -1,14 +0,0 @@ -# Tests the order of the matches -proc Btoken(): int = 5 -proc tokenA(): int = 5 -proc token(): int = 5 -proc BBtokenA(): int = 5 - -discard """ -$nimsuggest --v3 --tester $file ->globalSymbols token -def skProc tv3_globalSymbols.token proc (): int{.noSideEffect, gcsafe.} $file 4 5 "" 100 -def skProc tv3_globalSymbols.tokenA proc (): int{.noSideEffect, gcsafe.} $file 3 5 "" 100 -def skProc tv3_globalSymbols.Btoken proc (): int{.noSideEffect, gcsafe.} $file 2 5 "" 100 -def skProc tv3_globalSymbols.BBtokenA proc (): int{.noSideEffect, gcsafe.} $file 5 5 "" 100 -""" diff --git a/nimsuggest/tests/tv3_import.nim b/nimsuggest/tests/tv3_import.nim deleted file mode 100644 index 3c128f85b..000000000 --- a/nimsuggest/tests/tv3_import.nim +++ /dev/null @@ -1,7 +0,0 @@ -import tv#[!]#3 - -discard """ -$nimsuggest --v3 --tester $file ->def $1 -def skModule tv3 */tv3.nim 1 0 "" 100 -""" diff --git a/nimsuggest/tests/tv3_outline.nim b/nimsuggest/tests/tv3_outline.nim deleted file mode 100644 index 6370948d9..000000000 --- a/nimsuggest/tests/tv3_outline.nim +++ /dev/null @@ -1,45 +0,0 @@ -# tests v3 outline - -type - Foo* = ref object of RootObj - bar*: string - FooEnum = enum value1, value2 - FooPrivate = ref object of RootObj - barPrivate: string - -macro m(arg: untyped): untyped = discard -template t(arg: untyped): untyped = discard -proc p(): void = discard -iterator i(): int = discard -converter c(s: string): int = discard -method m(f: Foo): void = discard -func f(): void = discard - -let a = 1 -var b = 2 -const con = 2 - -proc outer(): void = - proc inner() = discard - -proc procWithLocal(): void = - let local = 10 - -discard """ -$nimsuggest --v3 --tester $file ->outline $file -outline skType tv3_outline.Foo Foo $file 4 2 "" 100 5 16 -outline skType tv3_outline.FooEnum FooEnum $file 6 2 "" 100 6 31 -outline skEnumField tv3_outline.FooEnum.value1 FooEnum $file 6 17 "" 100 6 23 -outline skEnumField tv3_outline.FooEnum.value2 FooEnum $file 6 25 "" 100 6 31 -outline skType tv3_outline.FooPrivate FooPrivate $file 7 2 "" 100 8 22 -outline skMacro tv3_outline.m macro (arg: untyped): untyped{.noSideEffect, gcsafe.} $file 10 6 "" 100 10 40 -outline skTemplate tv3_outline.t template (arg: untyped): untyped $file 11 9 "" 100 11 43 -outline skProc tv3_outline.p proc (){.noSideEffect, gcsafe.} $file 12 5 "" 100 12 24 -outline skConverter tv3_outline.c converter (s: string): int{.noSideEffect, gcsafe.} $file 14 10 "" 100 14 37 -outline skFunc tv3_outline.f proc (){.noSideEffect, gcsafe.} $file 16 5 "" 100 16 24 -outline skConst tv3_outline.con int literal(2) $file 20 6 "" 100 20 13 -outline skProc tv3_outline.outer proc (){.noSideEffect, gcsafe.} $file 22 5 "" 100 23 24 -outline skProc tv3_outline.outer.inner proc (){.noSideEffect, gcsafe.} $file 23 7 "" 100 23 24 -outline skProc tv3_outline.procWithLocal proc (){.noSideEffect, gcsafe.} $file 25 5 "" 100 26 16 -""" diff --git a/nimsuggest/tests/tv3_typeDefinition.nim b/nimsuggest/tests/tv3_typeDefinition.nim deleted file mode 100644 index f86d12cc6..000000000 --- a/nimsuggest/tests/tv3_typeDefinition.nim +++ /dev/null @@ -1,32 +0,0 @@ -# tests v3 - -type - Foo* = ref object of RootObj - bar*: string - -proc test(ff: Foo) = - echo f#[!]#f.bar - -type - Fo#[!]#o2* = ref object of RootObj - -type - FooGeneric[T] = ref object of RootObj - bar*: T - -let fooGeneric = FooGeneric[string]() -echo fo#[!]#oGeneric.bar - -# bad type -echo unde#[!]#fined - -discard """ -$nimsuggest --v3 --tester $file ->type $1 -type skType tv3_typeDefinition.Foo Foo $file 4 2 "" 100 ->type $2 -type skType tv3_typeDefinition.Foo2 Foo2 $file 11 2 "" 100 ->type $3 -type skType tv3_typeDefinition.FooGeneric FooGeneric $file 14 2 "" 100 ->type $4 -""" diff --git a/nimsuggest/tests/twithin_macro.nim b/nimsuggest/tests/twithin_macro.nim index d79dae1be..9c36ffd0f 100644 --- a/nimsuggest/tests/twithin_macro.nim +++ b/nimsuggest/tests/twithin_macro.nim @@ -1,5 +1,166 @@ -from system import string, int, seq, `&`, `$`, `*`, `@`, echo, add, items, RootObj -import fixtures/mclass_macro + +import macros + +macro class*(head, body: untyped): untyped = + # The macro is immediate, since all its parameters are untyped. + # This means, it doesn't resolve identifiers passed to it. + + var typeName, baseName: NimNode + + # flag if object should be exported + var exported: bool + + if head.kind == nnkInfix and head[0].ident == !"of": + # `head` is expression `typeName of baseClass` + # echo head.treeRepr + # -------------------- + # Infix + # Ident !"of" + # Ident !"Animal" + # Ident !"RootObj" + typeName = head[1] + baseName = head[2] + + elif head.kind == nnkInfix and head[0].ident == !"*" and + head[2].kind == nnkPrefix and head[2][0].ident == !"of": + # `head` is expression `typeName* of baseClass` + # echo head.treeRepr + # -------------------- + # Infix + # Ident !"*" + # Ident !"Animal" + # Prefix + # Ident !"of" + # Ident !"RootObj" + typeName = head[1] + baseName = head[2][1] + exported = true + + else: + quit "Invalid node: " & head.lispRepr + + # The following prints out the AST structure: + # + # import macros + # dumptree: + # type X = ref object of Y + # z: int + # -------------------- + # StmtList + # TypeSection + # TypeDef + # Ident !"X" + # Empty + # RefTy + # ObjectTy + # Empty + # OfInherit + # Ident !"Y" + # RecList + # IdentDefs + # Ident !"z" + # Ident !"int" + # Empty + + # create a type section in the result + result = + if exported: + # mark `typeName` with an asterisk + quote do: + type `typeName`* = ref object of `baseName` + else: + quote do: + type `typeName` = ref object of `baseName` + + # echo treeRepr(body) + # -------------------- + # StmtList + # VarSection + # IdentDefs + # Ident !"name" + # Ident !"string" + # Empty + # IdentDefs + # Ident !"age" + # Ident !"int" + # Empty + # MethodDef + # Ident !"vocalize" + # Empty + # Empty + # FormalParams + # Ident !"string" + # Empty + # Empty + # StmtList + # StrLit ... + # MethodDef + # Ident !"age_human_yrs" + # Empty + # Empty + # FormalParams + # Ident !"int" + # Empty + # Empty + # StmtList + # DotExpr + # Ident !"this" + # Ident !"age" + + # var declarations will be turned into object fields + var recList = newNimNode(nnkRecList) + + # expected name of constructor + let ctorName = newIdentNode("new" & $typeName) + + # Iterate over the statements, adding `this: T` + # to the parameters of functions, unless the + # function is a constructor + for node in body.children: + case node.kind: + + of nnkMethodDef, nnkProcDef: + # check if it is the ctor proc + if node.name.kind != nnkAccQuoted and node.name.basename == ctorName: + # specify the return type of the ctor proc + node.params[0] = typeName + else: + # inject `self: T` into the arguments + node.params.insert(1, newIdentDefs(ident("self"), typeName)) + result.add(node) + + of nnkVarSection: + # variables get turned into fields of the type. + for n in node.children: + recList.add(n) + + else: + result.add(node) + + # Inspect the tree structure: + # + # echo result.treeRepr + # -------------------- + # StmtList + # TypeSection + # TypeDef + # Ident !"Animal" + # Empty + # RefTy + # ObjectTy + # Empty + # OfInherit + # Ident !"RootObj" + # Empty <= We want to replace this + # MethodDef + # ... + + result[0][0][2][0][2] = recList + + # Lets inspect the human-readable version of the output + #echo repr(result) + +# --- class Animal of RootObj: var name: string @@ -41,11 +202,13 @@ echo r.age_human_yrs() echo r discard """ -$nimsuggest --tester --maxresults:5 $file +disabled:true +$nimsuggest --tester $file >sug $1 -sug;;skField;;age;;int;;$file;;6;;6;;"";;100;;None -sug;;skField;;name;;string;;$file;;5;;6;;"";;100;;None -sug;;skMethod;;twithin_macro.age_human_yrs;;proc (self: Animal): int;;$file;;8;;9;;"";;100;;None -sug;;skMethod;;twithin_macro.vocalize;;proc (self: Animal): string;;$file;;7;;9;;"";;100;;None -sug;;skMethod;;twithin_macro.vocalize;;proc (self: Rabbit): string;;$file;;23;;9;;"";;100;;None +sug;;skField;;age;;int;;$file;;167;;6;;"";;100;;None +sug;;skField;;name;;string;;$file;;166;;6;;"";;100;;None +sug;;skMethod;;twithin_macro.age_human_yrs;;proc (self: Animal): int;;$file;;169;;9;;"";;100;;None +sug;;skMethod;;twithin_macro.vocalize;;proc (self: Animal): string;;$file;;168;;9;;"";;100;;None +sug;;skMethod;;twithin_macro.vocalize;;proc (self: Rabbit): string;;$file;;184;;9;;"";;100;;None +sug;;skMacro;;twithin_macro.class;;proc (head: untyped, body: untyped): untyped{.gcsafe, locks: .};;$file;;4;;6;;"";;50;;None* """ diff --git a/nimsuggest/tests/twithin_macro_prefix.nim b/nimsuggest/tests/twithin_macro_prefix.nim index dd3810818..1402b762a 100644 --- a/nimsuggest/tests/twithin_macro_prefix.nim +++ b/nimsuggest/tests/twithin_macro_prefix.nim @@ -1,5 +1,166 @@ -from system import string, int, seq, `&`, `$`, `*`, `@`, echo, add, RootObj -import fixtures/mclass_macro + +import macros + +macro class*(head, body: untyped): untyped = + # The macro is immediate, since all its parameters are untyped. + # This means, it doesn't resolve identifiers passed to it. + + var typeName, baseName: NimNode + + # flag if object should be exported + var exported: bool + + if head.kind == nnkInfix and head[0].ident == !"of": + # `head` is expression `typeName of baseClass` + # echo head.treeRepr + # -------------------- + # Infix + # Ident !"of" + # Ident !"Animal" + # Ident !"RootObj" + typeName = head[1] + baseName = head[2] + + elif head.kind == nnkInfix and head[0].ident == !"*" and + head[2].kind == nnkPrefix and head[2][0].ident == !"of": + # `head` is expression `typeName* of baseClass` + # echo head.treeRepr + # -------------------- + # Infix + # Ident !"*" + # Ident !"Animal" + # Prefix + # Ident !"of" + # Ident !"RootObj" + typeName = head[1] + baseName = head[2][1] + exported = true + + else: + quit "Invalid node: " & head.lispRepr + + # The following prints out the AST structure: + # + # import macros + # dumptree: + # type X = ref object of Y + # z: int + # -------------------- + # StmtList + # TypeSection + # TypeDef + # Ident !"X" + # Empty + # RefTy + # ObjectTy + # Empty + # OfInherit + # Ident !"Y" + # RecList + # IdentDefs + # Ident !"z" + # Ident !"int" + # Empty + + # create a type section in the result + result = + if exported: + # mark `typeName` with an asterisk + quote do: + type `typeName`* = ref object of `baseName` + else: + quote do: + type `typeName` = ref object of `baseName` + + # echo treeRepr(body) + # -------------------- + # StmtList + # VarSection + # IdentDefs + # Ident !"name" + # Ident !"string" + # Empty + # IdentDefs + # Ident !"age" + # Ident !"int" + # Empty + # MethodDef + # Ident !"vocalize" + # Empty + # Empty + # FormalParams + # Ident !"string" + # Empty + # Empty + # StmtList + # StrLit ... + # MethodDef + # Ident !"age_human_yrs" + # Empty + # Empty + # FormalParams + # Ident !"int" + # Empty + # Empty + # StmtList + # DotExpr + # Ident !"this" + # Ident !"age" + + # var declarations will be turned into object fields + var recList = newNimNode(nnkRecList) + + # expected name of constructor + let ctorName = newIdentNode("new" & $typeName) + + # Iterate over the statements, adding `this: T` + # to the parameters of functions, unless the + # function is a constructor + for node in body.children: + case node.kind: + + of nnkMethodDef, nnkProcDef: + # check if it is the ctor proc + if node.name.kind != nnkAccQuoted and node.name.basename == ctorName: + # specify the return type of the ctor proc + node.params[0] = typeName + else: + # inject `self: T` into the arguments + node.params.insert(1, newIdentDefs(ident("self"), typeName)) + result.add(node) + + of nnkVarSection: + # variables get turned into fields of the type. + for n in node.children: + recList.add(n) + + else: + result.add(node) + + # Inspect the tree structure: + # + # echo result.treeRepr + # -------------------- + # StmtList + # TypeSection + # TypeDef + # Ident !"Animal" + # Empty + # RefTy + # ObjectTy + # Empty + # OfInherit + # Ident !"RootObj" + # Empty <= We want to replace this + # MethodDef + # ... + + result[0][0][2][0][2] = recList + + # Lets inspect the human-readable version of the output + #echo repr(result) + +# --- class Animal of RootObj: var name: string @@ -41,8 +202,9 @@ echo r.age_human_yrs() echo r discard """ +disabled:true $nimsuggest --tester $file >sug $1 -sug;;skField;;age;;int;;$file;;6;;6;;"";;100;;Prefix -sug;;skMethod;;twithin_macro_prefix.age_human_yrs;;proc (self: Animal): int;;$file;;8;;9;;"";;100;;Prefix +sug;;skField;;age;;int;;$file;;167;;6;;"";;100;;Prefix +sug;;skMethod;;twithin_macro_prefix.age_human_yrs;;proc (self: Animal): int;;$file;;169;;9;;"";;100;;Prefix """ diff --git a/readme.md b/readme.md index 325e8fff9..2c941af84 100644 --- a/readme.md +++ b/readme.md @@ -1,34 +1,27 @@ -# Nim +# Nim [![Build Status][badge-nim-travisci]][nim-travisci] [![builds.sr.ht freebsd status](https://builds.sr.ht/~araq/nim/freebsd.yml.svg)](https://builds.sr.ht/~araq/nim/freebsd.yml?) -[![Build Status](https://dev.azure.com/nim-lang/Nim/_apis/build/status/nim-lang.Nim?branchName=devel)](https://dev.azure.com/nim-lang/Nim/_build/latest?definitionId=1&branchName=devel) - -This repository contains the Nim compiler, Nim's stdlib, tools, and documentation. +This repository contains the Nim compiler, Nim's stdlib, tools and documentation. For more information about Nim, including downloads and documentation for the latest release, check out [Nim's website][nim-site] or [bleeding edge docs](https://nim-lang.github.io/Nim/). ## Community [![Join the IRC chat][badge-nim-irc]][nim-irc] -[![Join the Discord server][badge-nim-discord]][nim-discord] [![Join the Gitter chat][badge-nim-gitter]][nim-gitter] -[![Join the Matrix room](https://img.shields.io/matrix/nim-lang:matrix.org?color=blue&style=flat&logo=matrix)](https://matrix.to/#/#nim-lang:matrix.org) [![Get help][badge-nim-forum-gethelp]][nim-forum] [![View Nim posts on Stack Overflow][badge-nim-stackoverflow]][nim-stackoverflow-newest] [![Follow @nim_lang on Twitter][badge-nim-twitter]][nim-twitter] * The [forum][nim-forum] - the best place to ask questions and to discuss Nim. -* [#nim IRC Channel (Libera Chat)][nim-irc] - a place to discuss Nim in real-time. +* [#nim IRC Channel (Freenode)][nim-irc] - a place to discuss Nim in real-time. Also where most development decisions get made. -* [Discord][nim-discord] - an additional place to discuss Nim in real-time. Most - channels there are bridged to IRC. * [Gitter][nim-gitter] - an additional place to discuss Nim in real-time. There is a bridge between Gitter and the IRC channel. -* [Matrix][nim-matrix] - the main room to discuss Nim in real-time. [Matrix space][nim-matrix-space] contains a list of rooms, most of them are bridged to IRC. * [Telegram][nim-telegram] - an additional place to discuss Nim in real-time. There - is the official Telegram channel. Not bridged to IRC. + is the official Telegram channel. * [Stack Overflow][nim-stackoverflow] - a popular Q/A site for programming related topics that includes posts about Nim. -* [GitHub Wiki][nim-wiki] - Misc user-contributed content. +* [Github Wiki][nim-wiki] - Misc user-contributed content. ## Compiling @@ -37,9 +30,9 @@ architecture combinations: * Windows (Windows XP or greater) - x86 and x86_64 * Linux (most, if not all, distributions) - x86, x86_64, ppc64 and armv6l - * Mac OS X (10.04 or greater) - x86, x86_64, ppc64 and Apple Silicon (based on the ARM64 architecture) + * Mac OS X (10.04 or greater) - x86, x86_64 and ppc64 -More platforms are supported, however, they are not tested regularly and they +More platforms are supported, however they are not tested regularly and they may not be as stable as the above-listed platforms. Compiling the Nim compiler is quite straightforward if you follow these steps: @@ -47,25 +40,19 @@ Compiling the Nim compiler is quite straightforward if you follow these steps: First, the C source of an older version of the Nim compiler is needed to bootstrap the latest version because the Nim compiler itself is written in the Nim programming language. Those C sources are available within the -[``nim-lang/csources_v2``][csources-v2-repo] repository. +[``nim-lang/csources``][csources-repo] repository. Next, to build from source you will need: - * A C compiler such as ``gcc`` 5.x/later or an alternative such as ``clang``, - ``Visual C++`` or ``Intel C++``. It is recommended to use ``gcc`` 5.x or + * A C compiler such as ``gcc`` 3.x/later or an alternative such as ``clang``, + ``Visual C++`` or ``Intel C++``. It is recommended to use ``gcc`` 3.x or later. * Either ``git`` or ``wget`` to download the needed source repositories. * The ``build-essential`` package when using ``gcc`` on Ubuntu (and likely other distros as well). - * On Windows MinGW 4.3.0 (GCC 8.10) is the minimum recommended compiler. - * Nim hosts a known working MinGW distribution: - * [MinGW32.7z](https://nim-lang.org/download/mingw32.7z) - * [MinGW64.7z](https://nim-lang.org/download/mingw64.7z) - -**Windows Note: Cygwin and similar POSIX runtime environments are not supported.** Then, if you are on a \*nix system or Windows, the following steps should compile -Nim from source using ``gcc``, ``git``, and the ``koch`` build tool. +Nim from source using ``gcc``, ``git`` and the ``koch`` build tool. **Note: The following commands are for the development version of the compiler.** For most users, installing the latest stable version is enough. Check out @@ -73,25 +60,23 @@ the installation instructions on the website to do so: https://nim-lang.org/inst For package maintainers: see [packaging guidelines](https://nim-lang.github.io/Nim/packaging.html). -First, get Nim from GitHub: + +First get Nim from github: ``` git clone https://github.com/nim-lang/Nim.git cd Nim ``` -Next, run the appropriate build shell script for your platform: +Next run the appropriate build shell script for your platform: * `build_all.sh` (Linux, Mac) * `build_all.bat` (Windows) -Finally, once you have finished the build steps (on Windows, Mac, or Linux) you + +Finally, once you have finished the build steps (on Windows, Mac or Linux) you should add the ``bin`` directory to your PATH. -See also [bootstrapping the compiler](https://nim-lang.github.io/Nim/intern.html#bootstrapping-the-compiler). - -See also [reproducible builds](https://nim-lang.github.io/Nim/intern.html#bootstrapping-the-compiler-reproducible-builds). - ## Koch ``koch`` is the build tool used to build various parts of Nim and to generate @@ -104,7 +89,7 @@ can run a subset of tests by specifying a category (for example ``./koch tests cat async``). For more information on the ``koch`` build tool please see the documentation -within the [doc/koch.md](https://nim-lang.github.io/Nim/koch.html) file. +within the [doc/koch.rst](doc/koch.rst) file. ## Nimble @@ -139,25 +124,25 @@ you should familiarize yourself with the following repository structure: * ``pure/`` - modules in the standard library written in pure Nim. * ``impure/`` - modules in the standard library written in pure Nim with dependencies written in other languages. - * ``wrappers/`` - modules that wrap dependencies written in other languages. + * ``wrappers/`` - modules which wrap dependencies written in other languages. * ``tests/`` - contains categorized tests for the compiler and standard library. -* ``tools/`` - the tools including ``niminst`` (mostly invoked via +* ``tools/`` - the tools including ``niminst`` and ``nimweb`` (mostly invoked via ``koch``). -* ``koch.nim`` - the tool used to bootstrap Nim, generate C sources, build the website, +* ``koch.nim`` - tool used to bootstrap Nim, generate C sources, build the website, and generate the documentation. If you are not familiar with making a pull request using GitHub and/or git, please read [this guide][pull-request-instructions]. -Ideally, you should make sure that all tests pass before submitting a pull request. +Ideally you should make sure that all tests pass before submitting a pull request. However, if you are short on time, you can just run the tests specific to your -changes by only running the corresponding categories of tests. CI verifies +changes by only running the corresponding categories of tests. Travis CI verifies that all tests pass before allowing the pull request to be accepted, so only running specific tests should be harmless. Integration tests should go in ``tests/untestable``. If you're looking for ways to contribute, please look at our [issue tracker][nim-issues]. -There are always plenty of issues labeled [``Easy``][nim-issues-easy]; these should +There are always plenty of issues labelled [``Easy``][nim-issues-easy]; these should be a good starting point for an initial contribution to Nim. You can also help with the development of Nim by making donations. Donations can be @@ -197,35 +182,32 @@ You can also see a list of all our sponsors/backers from various payment service ## License The compiler and the standard library are licensed under the MIT license, except -for some modules which explicitly state otherwise. As a result, you may use any +for some modules which explicitly state otherwise. As a result you may use any compatible license (essentially any license) for your own programs developed with Nim. You are explicitly permitted to develop commercial applications using Nim. Please read the [copying.txt](copying.txt) file for more details. -Copyright © 2006-2023 Andreas Rumpf, all rights reserved. +Copyright © 2006-2019 Andreas Rumpf, all rights reserved. [nim-site]: https://nim-lang.org [nim-forum]: https://forum.nim-lang.org [nim-issues]: https://github.com/nim-lang/Nim/issues [nim-issues-easy]: https://github.com/nim-lang/Nim/labels/Easy -[nim-irc]: https://web.libera.chat/#nim +[nim-irc]: https://webchat.freenode.net/?channels=nim +[nim-travisci]: https://travis-ci.org/nim-lang/Nim [nim-twitter]: https://twitter.com/nim_lang [nim-stackoverflow]: https://stackoverflow.com/questions/tagged/nim-lang [nim-stackoverflow-newest]: https://stackoverflow.com/questions/tagged/nim-lang?sort=newest&pageSize=15 -[nim-discord]: https://discord.gg/nim [nim-gitter]: https://gitter.im/nim-lang/Nim -[nim-matrix]: https://matrix.to/#/#nim-lang:matrix.org -[nim-matrix-space]: https://matrix.to/#/#nim:envs.net [nim-telegram]: https://t.me/nim_lang [nim-bountysource]: https://www.bountysource.com/teams/nim [nim-bitcoin]: https://blockchain.info/address/1BXfuKM2uvoD6mbx4g5xM3eQhLzkCK77tJ [nimble-repo]: https://github.com/nim-lang/nimble [nimsuggest-repo]: https://github.com/nim-lang/nimsuggest -[csources-repo-deprecated]: https://github.com/nim-lang/csources -[csources-v2-repo]: https://github.com/nim-lang/csources_v2 +[csources-repo]: https://github.com/nim-lang/csources +[badge-nim-travisci]: https://img.shields.io/travis/nim-lang/Nim/devel.svg?style=flat-square [badge-nim-irc]: https://img.shields.io/badge/chat-on_irc-blue.svg?style=flat-square -[badge-nim-discord]: https://img.shields.io/discord/371759389889003530?color=blue&label=discord&logo=discord&logoColor=gold&style=flat-square [badge-nim-gitter]: https://img.shields.io/badge/chat-on_gitter-blue.svg?style=flat-square [badge-nim-forum-gethelp]: https://img.shields.io/badge/Forum-get%20help-4eb899.svg?style=flat-square [badge-nim-twitter]: https://img.shields.io/twitter/follow/nim_lang.svg?style=social diff --git a/security.md b/security.md deleted file mode 100644 index 72a1a3e3d..000000000 --- a/security.md +++ /dev/null @@ -1,20 +0,0 @@ -# Security Policy - -## Supported Versions - -Security advisories are published at: -https://github.com/nim-lang/security/security/advisories?state=published - -Security fixes are provided in new releases and in bugfix releases. - -We do not backport security fixes to older releases. - -(Yet, Linux distributions might backport security fixes for their packages.) - -## Reporting a Vulnerability - -If you have discovered a vulnerability, please notify us about it via -security@nim-lang.org in order to set up a meeting where we can discuss the next -steps. - -Please do not report vulnerabilities via GitHub issues. diff --git a/testament/backend.nim b/testament/backend.nim index 1770c6657..0a6d7d8b9 100644 --- a/testament/backend.nim +++ b/testament/backend.nim @@ -13,6 +13,7 @@ type CommitId = distinct string proc `$`*(id: MachineId): string {.borrow.} +#proc `$`(id: CommitId): string {.borrow.} # not used var thisMachine: MachineId @@ -20,10 +21,10 @@ var thisBranch: string proc getMachine*(): MachineId = - var name = execProcess("hostname").strip + var name = execProcess("hostname").string.strip if name.len == 0: - name = when defined(posix): getEnv("HOSTNAME") - else: getEnv("COMPUTERNAME") + name = when defined(posix): getEnv("HOSTNAME").string + else: getEnv("COMPUTERNAME").string if name.len == 0: quit "cannot determine the machine name" @@ -31,8 +32,8 @@ proc getMachine*(): MachineId = proc getCommit(): CommitId = const commLen = "commit ".len - let hash = execProcess("git log -n 1").strip[commLen..commLen+10] - thisBranch = execProcess("git symbolic-ref --short HEAD").strip + let hash = execProcess("git log -n 1").string.strip[commLen..commLen+10] + thisBranch = execProcess("git symbolic-ref --short HEAD").string.strip if hash.len == 0 or thisBranch.len == 0: quit "cannot determine git HEAD" result = CommitId(hash) diff --git a/testament/caasdriver.nim b/testament/caasdriver.nim index 01e402e07..30383bddb 100644 --- a/testament/caasdriver.nim +++ b/testament/caasdriver.nim @@ -62,7 +62,7 @@ proc doCaasCommand(session: var NimSession, command: string): string = result = "" while true: - var line = "" + var line = TaintedString("") if session.nim.outputStream.readLine(line): if line.string == "": break result.add(line.string & "\n") @@ -78,7 +78,7 @@ proc doProcCommand(session: var NimSession, command: string): string = var process = startProcess(NimBin, args = session.replaceVars(command).split) stream = outputStream(process) - line = "" + line = TaintedString("") result = "" while stream.readLine(line): @@ -113,12 +113,12 @@ proc doScenario(script: string, output: Stream, mode: TRunMode, verbose: bool): result = true var f = open(script) - var project = "" + var project = TaintedString("") if f.readLine(project): var s = startNimSession(script.parentDir / project.string, script, mode) - tline = "" + tline = TaintedString("") ln = 1 while f.readLine(tline): @@ -175,7 +175,7 @@ when isMainModule: verbose = false for i in 0..paramCount() - 1: - let param = paramStr(i + 1) + let param = string(paramStr(i + 1)) case param of "verbose": verbose = true else: filter = param diff --git a/testament/categories.nim b/testament/categories.nim index c428ffc04..f8cc625c4 100644 --- a/testament/categories.nim +++ b/testament/categories.nim @@ -10,11 +10,9 @@ ## Include for the tester that contains test suites that test special features ## of the compiler. -# included from testament.nim +# included from tester.nim import important_packages -import std/[strformat, strutils] -from std/sequtils import filterIt const specialCategories = [ @@ -23,21 +21,26 @@ const "debugger", "dll", "examples", + "flags", "gc", "io", "js", "ic", "lib", + "longgc", "manyloc", "nimble-packages", "niminaction", + "rodfiles", "threads", - "untestable", # see trunner_special + "untestable", + "stdlib", "testdata", "nimcache", "coroutines", "osproc", "shouldfail", + "dir with space", "destructor" ] @@ -45,63 +48,119 @@ proc isTestFile*(file: string): bool = let (_, name, ext) = splitFile(file) result = ext == ".nim" and name.startsWith("t") +# ---------------- IC tests --------------------------------------------- + +proc icTests(r: var TResults; testsDir: string, cat: Category, options: string) = + const + tooltests = ["compiler/nim.nim", "tools/nimgrep.nim"] + writeOnly = " --incremental:writeonly " + readOnly = " --incremental:readonly " + incrementalOn = " --incremental:on " + + template test(x: untyped) = + testSpecWithNimcache(r, makeRawTest(file, x & options, cat), nimcache) + + template editedTest(x: untyped) = + var test = makeTest(file, x & options, cat) + test.spec.targets = {getTestSpecTarget()} + testSpecWithNimcache(r, test, nimcache) + + const tempExt = "_temp.nim" + for it in walkDirRec(testsDir / "ic"): + if isTestFile(it) and not it.endsWith(tempExt): + let nimcache = nimcacheDir(it, options, getTestSpecTarget()) + removeDir(nimcache) + + let content = readFile(it) + for fragment in content.split("#!EDIT!#"): + let file = it.replace(".nim", tempExt) + writeFile(file, fragment) + let oldPassed = r.passed + editedTest incrementalOn + if r.passed != oldPassed+1: break + + for file in tooltests: + let nimcache = nimcacheDir(file, options, getTestSpecTarget()) + removeDir(nimcache) + + let oldPassed = r.passed + test writeOnly + + if r.passed == oldPassed+1: + test readOnly + if r.passed == oldPassed+2: + test readOnly & "-d:nimBackendAssumesChange " + +# --------------------- flags tests ------------------------------------------- + +proc flagTests(r: var TResults, cat: Category, options: string) = + # --genscript + const filename = testsDir/"flags"/"tgenscript" + const genopts = " --genscript" + let nimcache = nimcacheDir(filename, genopts, targetC) + testSpec r, makeTest(filename, genopts, cat) + + when defined(windows): + testExec r, makeTest(filename, " cmd /c cd " & nimcache & + " && compile_tgenscript.bat", cat) + + elif defined(posix): + testExec r, makeTest(filename, " sh -c \"cd " & nimcache & + " && sh compile_tgenscript.sh\"", cat) + + # Run + testExec r, makeTest(filename, " " & nimcache / "tgenscript", cat) + # --------------------- DLL generation tests ---------------------------------- -proc runBasicDLLTest(c, r: var TResults, cat: Category, options: string, isOrc = false) = +proc runBasicDLLTest(c, r: var TResults, cat: Category, options: string) = const rpath = when defined(macosx): " --passL:-rpath --passL:@loader_path" else: "" - if not defined(windows) or not isOrc: # todo fix me on windows - var test1 = makeTest("lib/nimrtl.nim", options & " --outdir:tests/dll", cat) - test1.spec.action = actionCompile - testSpec c, test1 + var test1 = makeTest("lib/nimrtl.nim", options & " --outdir:tests/dll", cat) + test1.spec.action = actionCompile + testSpec c, test1 var test2 = makeTest("tests/dll/server.nim", options & " --threads:on" & rpath, cat) test2.spec.action = actionCompile testSpec c, test2 - - if not isOrc: - var test3 = makeTest("lib/nimhcr.nim", options & " --threads:off --outdir:tests/dll" & rpath, cat) - test3.spec.action = actionCompile - testSpec c, test3 - var test4 = makeTest("tests/dll/visibility.nim", options & " --threads:off --app:lib" & rpath, cat) + var test3 = makeTest("lib/nimhcr.nim", options & " --outdir:tests/dll" & rpath, cat) + test3.spec.action = actionCompile + testSpec c, test3 + var test4 = makeTest("tests/dll/visibility.nim", options & " --app:lib" & rpath, cat) test4.spec.action = actionCompile testSpec c, test4 # windows looks in the dir of the exe (yay!): - when not defined(windows): + when not defined(Windows): # posix relies on crappy LD_LIBRARY_PATH (ugh!): const libpathenv = when defined(haiku): "LIBRARY_PATH" else: "LD_LIBRARY_PATH" - var libpath = getEnv(libpathenv) + var libpath = getEnv(libpathenv).string # Temporarily add the lib directory to LD_LIBRARY_PATH: putEnv(libpathenv, "tests/dll" & (if libpath.len > 0: ":" & libpath else: "")) defer: putEnv(libpathenv, libpath) - if not isOrc: - testSpec r, makeTest("tests/dll/client.nim", options & " --threads:on" & rpath, cat) - testSpec r, makeTest("tests/dll/nimhcr_unit.nim", options & " --threads:off" & rpath, cat) - testSpec r, makeTest("tests/dll/visibility.nim", options & " --threads:off" & rpath, cat) + testSpec r, makeTest("tests/dll/client.nim", options & " --threads:on" & rpath, cat) + testSpec r, makeTest("tests/dll/nimhcr_unit.nim", options & rpath, cat) + testSpec r, makeTest("tests/dll/visibility.nim", options & rpath, cat) if "boehm" notin options: # force build required - see the comments in the .nim file for more details var hcri = makeTest("tests/dll/nimhcr_integration.nim", - options & " --threads:off --forceBuild --hotCodeReloading:on" & rpath, cat) + options & " --forceBuild --hotCodeReloading:on" & rpath, cat) let nimcache = nimcacheDir(hcri.name, hcri.options, getTestSpecTarget()) - let cmd = prepareTestCmd(hcri.spec.getCmd, hcri.name, + hcri.args = prepareTestArgs(hcri.spec.getCmd, hcri.name, hcri.options, nimcache, getTestSpecTarget()) - hcri.testArgs = cmd.parseCmdLine testSpec r, hcri proc dllTests(r: var TResults, cat: Category, options: string) = # dummy compile result: var c = initResults() - runBasicDLLTest c, r, cat, options & " --mm:refc" - runBasicDLLTest c, r, cat, options & " -d:release --mm:refc" - runBasicDLLTest c, r, cat, options, isOrc = true - runBasicDLLTest c, r, cat, options & " -d:release", isOrc = true + runBasicDLLTest c, r, cat, options + runBasicDLLTest c, r, cat, options & " -d:release" when not defined(windows): # still cannot find a recent Windows version of boehm.dll: runBasicDLLTest c, r, cat, options & " --gc:boehm" @@ -110,10 +169,18 @@ proc dllTests(r: var TResults, cat: Category, options: string) = # ------------------------------ GC tests ------------------------------------- proc gcTests(r: var TResults, cat: Category, options: string) = - template testWithoutMs(filename: untyped) = - testSpec r, makeTest("tests/gc" / filename, options & "--mm:refc", cat) + template testWithNone(filename: untyped) = testSpec r, makeTest("tests/gc" / filename, options & - " -d:release -d:useRealtimeGC --mm:refc", cat) + " --gc:none", cat) + testSpec r, makeTest("tests/gc" / filename, options & + " -d:release --gc:none", cat) + + template testWithoutMs(filename: untyped) = + testSpec r, makeTest("tests/gc" / filename, options, cat) + testSpec r, makeTest("tests/gc" / filename, options & + " -d:release", cat) + testSpec r, makeTest("tests/gc" / filename, options & + " -d:release -d:useRealtimeGC", cat) when filename != "gctest": testSpec r, makeTest("tests/gc" / filename, options & " --gc:orc", cat) @@ -126,7 +193,6 @@ proc gcTests(r: var TResults, cat: Category, options: string) = " --gc:markAndSweep", cat) testSpec r, makeTest("tests/gc" / filename, options & " -d:release --gc:markAndSweep", cat) - template test(filename: untyped) = testWithoutBoehm filename when not defined(windows) and not defined(android): @@ -144,6 +210,7 @@ proc gcTests(r: var TResults, cat: Category, options: string) = test "gcleak" test "gcleak2" testWithoutBoehm "gctest" + testWithNone "gctest" test "gcleak3" test "gcleak4" # Disabled because it works and takes too long to run: @@ -158,7 +225,19 @@ proc gcTests(r: var TResults, cat: Category, options: string) = test "stackrefleak" test "cyclecollector" - testWithoutBoehm "trace_globals" + +proc longGCTests(r: var TResults, cat: Category, options: string) = + when defined(windows): + let cOptions = "-ldl -DWIN" + else: + let cOptions = "-ldl" + + var c = initResults() + # According to ioTests, this should compile the file + testSpec c, makeTest("tests/realtimeGC/shared", options, cat) + # ^- why is this not appended to r? Should this be discarded? + testC r, makeTest("tests/realtimeGC/cmain", cOptions, cat), actionRun + testSpec r, makeTest("tests/realtimeGC/nmain", options & "--threads: on", cat) # ------------------------- threading tests ----------------------------------- @@ -177,11 +256,6 @@ proc ioTests(r: var TResults, cat: Category, options: string) = # dummy compile result: var c = initResults() testSpec c, makeTest("tests/system/helpers/readall_echo", options, cat) - # ^- why is this not appended to r? Should this be discarded? - # EDIT: this should be replaced by something like in D20210524T180826, - # likewise in similar instances where `testSpec c` is used, or more generally - # when a test depends on another test, as it makes tests non-independent, - # creating complications for batching and megatest logic. testSpec r, makeTest("tests/system/tio", options, cat) # ------------------------- async tests --------------------------------------- @@ -194,20 +268,16 @@ proc asyncTests(r: var TResults, cat: Category, options: string) = # ------------------------- debugger tests ------------------------------------ proc debuggerTests(r: var TResults, cat: Category, options: string) = - if fileExists("tools/nimgrep.nim"): - var t = makeTest("tools/nimgrep", options & " --debugger:on", cat) - t.spec.action = actionCompile - # force target to C because of MacOS 10.15 SDK headers bug - # https://github.com/nim-lang/Nim/pull/15612#issuecomment-712471879 - t.spec.targets = {targetC} - testSpec r, t + var t = makeTest("tools/nimgrep", options & " --debugger:on", cat) + t.spec.action = actionCompile + testSpec r, t # ------------------------- JS tests ------------------------------------------ proc jsTests(r: var TResults, cat: Category, options: string) = template test(filename: untyped) = - testSpec r, makeTest(filename, options, cat), {targetJS} - testSpec r, makeTest(filename, options & " -d:release", cat), {targetJS} + testSpec r, makeTest(filename, options & " -d:nodejs", cat), {targetJS} + testSpec r, makeTest(filename, options & " -d:nodejs -d:release", cat), {targetJS} for t in os.walkFiles("tests/js/t*.nim"): test(t) @@ -226,6 +296,8 @@ proc jsTests(r: var TResults, cat: Category, options: string) = # ------------------------- nim in action ----------- proc testNimInAction(r: var TResults, cat: Category, options: string) = + let options = options & " --nilseqs:on" + template test(filename: untyped) = testSpec r, makeTest(filename, options, cat) @@ -316,7 +388,7 @@ proc findMainFile(dir: string): string = var nimFiles = 0 for kind, file in os.walkDir(dir): if kind == pcFile: - if file.endsWith(cfgExt): return file[0..^(cfgExt.len+1)] & ".nim" + if file.endsWith(cfgExt): return file[.. ^(cfgExt.len+1)] & ".nim" elif file.endsWith(".nim"): if result.len == 0: result = file inc nimFiles @@ -346,7 +418,7 @@ proc testStdlib(r: var TResults, pattern, options: string, cat: Category) = proc isValid(file: string): bool = for dir in parentDirs(file, inclusive = false): if dir.lastPathPart in ["includes", "nimcache"]: - # e.g.: lib/pure/includes/osenv.nim gives: Error: This is an include file for os.nim! + # eg: lib/pure/includes/osenv.nim gives: Error: This is an include file for os.nim! return false let name = extractFilename(file) if name.splitFile.ext != ".nim": return false @@ -361,12 +433,12 @@ proc testStdlib(r: var TResults, pattern, options: string, cat: Category) = files.sort # reproducible order for testFile in files: - let contents = readFile(testFile) + let contents = readFile(testFile).string var testObj = makeTest(testFile, options, cat) #[ todo: this logic is fragile: - false positives (if appears in a comment), or false negatives, e.g. + false positives (if appears in a comment), or false negatives, eg `when defined(osx) and isMainModule`. Instead of fixing this, see https://github.com/nim-lang/Nim/issues/10045 for a much better way. @@ -376,183 +448,114 @@ proc testStdlib(r: var TResults, pattern, options: string, cat: Category) = testSpec r, testObj # ----------------------------- nimble ---------------------------------------- -proc listPackagesAll(): seq[NimblePackage] = - var nimbleDir = getEnv("NIMBLE_DIR") - if nimbleDir.len == 0: nimbleDir = getHomeDir() / ".nimble" - let packageIndex = nimbleDir / "packages_official.json" + +var nimbleDir = getEnv("NIMBLE_DIR").string +if nimbleDir.len == 0: nimbleDir = getHomeDir() / ".nimble" +let + nimbleExe = findExe("nimble") + packageIndex = nimbleDir / "packages_official.json" + +iterator listPackages(): tuple[name, url, cmd: string, hasDeps: bool] = + let defaultCmd = "nimble test" let packageList = parseFile(packageIndex) - proc findPackage(name: string): JsonNode = - for a in packageList: - if a["name"].str == name: return a - for pkg in important_packages.packages.items: - var pkg = pkg - if pkg.url.len == 0: - let pkg2 = findPackage(pkg.name) - if pkg2 == nil: - raise newException(ValueError, "Cannot find package '$#'." % pkg.name) - pkg.url = pkg2["url"].str - result.add pkg - -proc listPackages(packageFilter: string): seq[NimblePackage] = - let pkgs = listPackagesAll() - if packageFilter.len != 0: - # xxx document `packageFilter`, seems like a bad API, - # at least should be a regex; a substring match makes no sense. - result = pkgs.filterIt(packageFilter in it.name) - else: - if testamentData0.batchArg == "allowed_failures": - result = pkgs.filterIt(it.allowFailure) - elif testamentData0.testamentNumBatch == 0: - result = pkgs + for n, cmd, hasDeps, url in important_packages.packages.items: + let cmd = if cmd.len == 0: defaultCmd else: cmd + if url.len != 0: + yield (n, url, cmd, hasDeps) else: - let pkgs2 = pkgs.filterIt(not it.allowFailure) - for i in 0.. 0: - outputExpected.add runSpec.output - if not runSpec.output.endsWith "\n": - outputExpected.add '\n' + outputExpected.add marker & runSpec.file & "\n" + outputExpected.add runSpec.output.strip + outputExpected.add '\n' + norm outputExpected - if buf != outputExpected: - writeFile(outputExceptedFile, outputExpected) - echo diffFiles(outputGottenFile, outputExceptedFile).output - echo failString & "megatest output different, see $1 vs $2" % [outputGottenFile, outputExceptedFile] - # outputGottenFile, outputExceptedFile not removed on purpose for debugging. + if buf.string != outputExpected: + writeFile("outputExpected.txt", outputExpected) + discard execShellCmd("diff -uNdr outputExpected.txt outputGotten.txt") + echo "output different!" + # outputGotten.txt, outputExpected.txt not removed on purpose for debugging. quit 1 else: - echo "megatest output OK" - + echo "output OK" + removeFile("outputGotten.txt") + removeFile("megatest.nim") + #testSpec r, makeTest("megatest", options, cat) # --------------------------------------------------------------------------- proc processCategory(r: var TResults, cat: Category, options, testsDir: string, runJoinableTests: bool) = - let cat2 = cat.string.normalize - var handled = false - if isNimRepoTests(): - handled = true - case cat2 - of "js": - # only run the JS tests on Windows or Linux because Travis is bad - # and other OSes like Haiku might lack nodejs: - if not defined(linux) and isTravis: - discard - else: - jsTests(r, cat, options) - of "dll": - dllTests(r, cat, options) - of "gc": - gcTests(r, cat, options) - of "debugger": - debuggerTests(r, cat, options) - of "manyloc": - manyLoc r, cat, options - of "threads": - threadTests r, cat, options & " --threads:on" - of "io": - ioTests r, cat, options - of "async": - asyncTests r, cat, options - of "lib": - testStdlib(r, "lib/pure/", options, cat) - testStdlib(r, "lib/packages/docutils/", options, cat) - of "examples": - compileExample(r, "examples/*.nim", options, cat) - compileExample(r, "examples/gtk/*.nim", options, cat) - compileExample(r, "examples/talk/*.nim", options, cat) - of "nimble-packages": - testNimblePackages(r, cat, options) - of "niminaction": - testNimInAction(r, cat, options) - of "ic": - icTests(r, testsDir / cat2, cat, options, isNavigatorTest=false) - of "navigator": - icTests(r, testsDir / cat2, cat, options, isNavigatorTest=true) - of "untestable": - # These require special treatment e.g. because they depend on a third party - # dependency; see `trunner_special` which runs some of those. + case cat.string.normalize + of "rodfiles": + when false: + compileRodFiles(r, cat, options) + runRodFiles(r, cat, options) + of "ic": + when false: + icTests(r, testsDir, cat, options) + of "js": + # only run the JS tests on Windows or Linux because Travis is bad + # and other OSes like Haiku might lack nodejs: + if not defined(linux) and isTravis: discard else: - handled = false - if not handled: - case cat2 - of "megatest": - runJoinedTest(r, cat, testsDir, options) - if isNimRepoTests(): - runJoinedTest(r, cat, testsDir, options & " --mm:refc") - else: - var testsRun = 0 - var files: seq[string] - for file in walkDirRec(testsDir &.? cat.string): - if isTestFile(file): files.add file - files.sort # give reproducible order - for i, name in files: - var test = makeTest(name, options, cat) - if runJoinableTests or not isJoinableSpec(test.spec) or cat.string in specialCategories: - discard "run the test" - else: - test.spec.err = reJoined - testSpec r, test - inc testsRun - if testsRun == 0: - const whiteListedDirs = ["deps", "htmldocs", "pkgs"] - # `pkgs` because bug #16556 creates `pkgs` dirs and this can affect some users - # that try an old version of choosenim. - doAssert cat.string in whiteListedDirs, - "Invalid category specified: '$#' not in whilelist: $#" % [cat.string, $whiteListedDirs] + jsTests(r, cat, options) + of "dll": + dllTests(r, cat, options) + of "flags": + flagTests(r, cat, options) + of "gc": + gcTests(r, cat, options) + of "longgc": + longGCTests(r, cat, options) + of "debugger": + debuggerTests(r, cat, options) + of "manyloc": + manyLoc r, cat, options + of "threads": + threadTests r, cat, options & " --threads:on" + of "io": + ioTests r, cat, options + of "async": + asyncTests r, cat, options + of "lib": + testStdlib(r, "lib/pure/", options, cat) + testStdlib(r, "lib/packages/docutils/", options, cat) + of "examples": + compileExample(r, "examples/*.nim", options, cat) + compileExample(r, "examples/gtk/*.nim", options, cat) + compileExample(r, "examples/talk/*.nim", options, cat) + of "nimble-packages": + testNimblePackages(r, cat) + of "niminaction": + testNimInAction(r, cat, options) + of "untestable": + # We can't test it because it depends on a third party. + discard # TODO: Move untestable tests to someplace else, i.e. nimble repo. + of "megatest": + runJoinedTest(r, cat, testsDir) + else: + var testsRun = 0 + var files: seq[string] + for file in walkDirRec(testsDir &.? cat.string): + if isTestFile(file): files.add file + files.sort # give reproducible order + + for i, name in files: + var test = makeTest(name, options, cat) + if runJoinableTests or not isJoinableSpec(test.spec) or cat.string in specialCategories: + discard "run the test" + else: + test.spec.err = reJoined + testSpec r, test + inc testsRun + if testsRun == 0: + echo "[Warning] - Invalid category specified \"", cat.string, "\", no tests were run" proc processPattern(r: var TResults, pattern, options: string; simulate: bool) = var testsRun = 0 - if dirExists(pattern): - for k, name in walkDir(pattern): - if k in {pcFile, pcLinkToFile} and name.endsWith(".nim"): - if simulate: - echo "Detected test: ", name - else: - var test = makeTest(name, options, Category"pattern") - testSpec r, test - inc testsRun - else: - for name in walkPattern(pattern): - if simulate: - echo "Detected test: ", name - else: - var test = makeTest(name, options, Category"pattern") - testSpec r, test - inc testsRun + for name in walkPattern(pattern): + if simulate: + echo "Detected test: ", name + else: + var test = makeTest(name, options, Category"pattern") + testSpec r, test + inc testsRun if testsRun == 0: echo "no tests were found for pattern: ", pattern diff --git a/testament/htmlgen.nim b/testament/htmlgen.nim index 174f36d0b..8e58dd95e 100644 --- a/testament/htmlgen.nim +++ b/testament/htmlgen.nim @@ -16,7 +16,7 @@ import "testamenthtml.nimf" proc generateTestResultPanelPartial(outfile: File, testResultRow: JsonNode) = let trId = htmlQuote(testResultRow["category"].str & "_" & testResultRow["name"].str). - multiReplace({".": "_", " ": "_", ":": "_", "/": "_"}) + multiReplace({".": "_", " ": "_", ":": "_"}) name = testResultRow["name"].str.htmlQuote() category = testResultRow["category"].str.htmlQuote() target = testResultRow["target"].str.htmlQuote() diff --git a/testament/important_packages.nim b/testament/important_packages.nim index e59198e67..f2ce8fb25 100644 --- a/testament/important_packages.nim +++ b/testament/important_packages.nim @@ -1,174 +1,95 @@ -##[ -## note 1 -`useHead` should ideally be used as the default but lots of packages (e.g. `chronos`) -don't have release tags (or have really old ones compared to HEAD), making it -impossible to test them reliably here. -packages listed here should ideally have regularly updated release tags, so that: -* we're testing recent versions of the package -* the version that's tested is stable enough even if HEAD may occasionally break +template pkg(name: string; cmd = "nimble test"; hasDeps = false; url = ""): untyped = + packages.add((name, cmd, hasDeps, url)) -## note 2: D20210308T165435:here -nimble packages should be testable as follows: -git clone $url $dir && cd $dir -NIMBLE_DIR=$TMP_NIMBLE_DIR XDG_CONFIG_HOME= nimble install --depsOnly -y -NIMBLE_DIR=$TMP_NIMBLE_DIR XDG_CONFIG_HOME= nimble test +var packages*: seq[tuple[name, cmd: string; hasDeps: bool; url: string]] = @[] -if this fails (e.g. nimcrypto), it could be because a package lacks a `tests/nim.cfg` with `--path:..`, -so the above commands would've worked by accident with `nimble install` but not with `nimble install --depsOnly`. -When this is the case, a workaround is to test this package here by adding `--path:$srcDir` on the test `cmd`. -]## -type NimblePackage* = object - name*, cmd*, url*: string - useHead*: bool - allowFailure*: bool - ## When true, we still run the test but the test is allowed to fail. - ## This is useful for packages that currently fail but that we still want to - ## run in CI, e.g. so that we can monitor when they start working again and - ## are reminded about those failures without making CI fail for unrelated PRs. - -var packages*: seq[NimblePackage] - -proc pkg(name: string; cmd = "nimble test"; url = "", useHead = true, allowFailure = false) = - packages.add NimblePackage(name: name, cmd: cmd, url: url, useHead: useHead, allowFailure: allowFailure) - -pkg "alea" pkg "argparse" -pkg "arraymancer", "nim c tests/tests_cpu.nim" -pkg "ast_pattern_matching", "nim c -r tests/test1.nim" -pkg "asyncftpclient", "nimble compileExample" -pkg "asyncthreadpool", "nimble test --mm:refc" -pkg "awk" +pkg "arraymancer", "nim c tests/tests_cpu.nim", true +pkg "ast_pattern_matching", "nim c -r --oldgensym:on tests/test1.nim" +pkg "asyncmysql", "", true pkg "bigints" pkg "binaryheap", "nim c -r binaryheap.nim" -pkg "BipBuffer" -pkg "blscurve", allowFailure = true # pending https://github.com/status-im/nim-blscurve/issues/39 -pkg "bncurve" -pkg "brainfuck", "nim c -d:release -r tests/compile.nim" -pkg "bump", "nim c --gc:arc --path:. -r tests/tbump.nim", "https://github.com/disruptek/bump", allowFailure = true +pkg "blscurve", "", true +pkg "bncurve", "", true pkg "c2nim", "nim c testsuite/tester.nim" pkg "cascade" -pkg "cello", url = "https://github.com/nim-lang/cello", useHead = true pkg "chroma" -pkg "chronicles", "nim c -o:chr -r chronicles.nim", url = "https://github.com/nim-lang/nim-chronicles" -pkg "chronos", "nim c -r -d:release tests/testall" -pkg "cligen", "nim c --path:. -r cligen.nim" -pkg "combparser", "nimble test --gc:orc" +pkg "chronicles", "nim c -o:chr -r chronicles.nim", true +pkg "chronos", "", true +pkg "cligen", "nim c -o:cligenn -r cligen.nim" +pkg "coco", "", true +pkg "combparser" pkg "compactdict" -pkg "comprehension", "nimble test", "https://github.com/alehander92/comprehension" -pkg "criterion", allowFailure = true # pending https://github.com/disruptek/criterion/issues/3 (wrongly closed) -pkg "datamancer" +pkg "comprehension", "", false, "https://github.com/alehander42/comprehension" +pkg "criterion" pkg "dashing", "nim c tests/functional.nim" -pkg "delaunay" pkg "docopt" -pkg "easygl", "nim c -o:egl -r src/easygl.nim", "https://github.com/jackmott/easygl" +pkg "easygl", "nim c -o:egl -r src/easygl.nim", true, "https://github.com/jackmott/easygl" pkg "elvis" -pkg "fidget" -pkg "fragments", "nim c -r fragments/dsl.nim", allowFailure = true # pending https://github.com/nim-lang/packages/issues/2115 -pkg "fusion" +pkg "fragments", "nim c -r fragments/dsl.nim" pkg "gara" pkg "glob" -pkg "ggplotnim", "nim c -d:noCairo -r tests/tests.nim" -pkg "gittyup", "nimble test", "https://github.com/disruptek/gittyup", allowFailure = true -pkg "gnuplot", "nim c gnuplot.nim" -# pkg "gram", "nim c -r --gc:arc --define:danger tests/test.nim", "https://github.com/disruptek/gram" - # pending https://github.com/nim-lang/Nim/issues/16509 +pkg "gnuplot" +# pkg "godot", "nim c -r godot/godot.nim" # not yet compatible with Nim 0.19 pkg "hts", "nim c -o:htss src/hts.nim" -pkg "httpauth" pkg "illwill", "nimble examples" pkg "inim" pkg "itertools", "nim doc src/itertools.nim" pkg "iterutils" pkg "jstin" pkg "karax", "nim c -r tests/tester.nim" -pkg "kdtree", "nimble test -d:nimLegacyRandomInitRand", "https://github.com/jblindsay/kdtree" -pkg "loopfusion", url = "https://github.com/nim-lang/loop-fusion" -pkg "lockfreequeues" -pkg "macroutils" -pkg "manu" -pkg "markdown" -pkg "measuremancer", "nimble testDeps; nimble -y test" -pkg "memo" -pkg "msgpack4nim", "nim c -r tests/test_spec.nim" +pkg "loopfusion" +pkg "msgpack4nim" pkg "nake", "nim c nakefile.nim" -pkg "neo", "nim c -d:blas=openblas --mm:refc tests/all.nim" -pkg "nesm", "nimble tests", "https://github.com/nim-lang/NESM", useHead = true -pkg "netty" -pkg "nico", allowFailure = true -pkg "nicy", "nim c -r src/nicy.nim" +pkg "neo", "nim c -d:blas=openblas tests/all.nim", true +# pkg "nico", "", true +pkg "nicy", "nim c src/nicy.nim" pkg "nigui", "nim c -o:niguii -r src/nigui.nim" -pkg "nimcrypto", "nim r --path:. tests/testall.nim" # `--path:.` workaround needed, see D20210308T165435 -pkg "NimData", "nim c -o:nimdataa src/nimdata.nim" -pkg "nimes", "nim c src/nimes.nim" -pkg "nimfp", "nim c -o:nfp -r src/fp.nim" -pkg "nimgame2", "nim c --mm:refc nimgame2/nimgame.nim" - # XXX Doesn't work with deprecated 'randomize', will create a PR. -pkg "nimgen", "nim c -o:nimgenn -r src/nimgen/runcfg.nim" -pkg "nimib" -pkg "nimlsp" -pkg "nimly", "nim c -r tests/test_readme_example.nim" -pkg "nimongo", "nimble test_ci", allowFailure = true -pkg "nimph", "nimble test", "https://github.com/disruptek/nimph", allowFailure = true -pkg "nimPNG", useHead = true +pkg "nimcrypto", "nim c -r tests/testall.nim" +pkg "NimData", "nim c -o:nimdataa src/nimdata.nim", true +pkg "nimes", "nim c src/nimes.nim", true +pkg "nimfp", "nim c -o:nfp -r src/fp.nim", true +pkg "nimgame2", "nim c nimgame2/nimgame.nim", true +pkg "nimgen", "nim c -o:nimgenn -r src/nimgen/runcfg.nim", true +# pkg "nimlsp", "", true +pkg "nimly", "", true +# pkg "nimongo", "nimble test_ci", true pkg "nimpy", "nim c -r tests/nimfrompy.nim" pkg "nimquery" -pkg "nimsl" +pkg "nimsl", "", true pkg "nimsvg" -pkg "nimterop", "nimble minitest", url = "https://github.com/nim-lang/nimterop" -pkg "nimwc", "nim c nimwc.nim", allowFailure = true -pkg "nimx", "nim c --threads:on test/main.nim", allowFailure = true -pkg "nitter", "nim c src/nitter.nim", "https://github.com/zedeus/nitter" -pkg "norm", "testament r tests/common/tmodel.nim" -pkg "npeg", "nimble testarc" -pkg "numericalnim", "nimble nimCI" -pkg "optionsutils" -pkg "ormin", "nim c -o:orminn ormin.nim" +# pkg "nimterop", "", true +pkg "nimx", "nim c --threads:on test/main.nim", true +pkg "norm", "nim c -r tests/tsqlite.nim", true +pkg "npeg" +pkg "ormin", "nim c -o:orminn ormin.nim", true pkg "parsetoml" pkg "patty" -pkg "pixie" -pkg "plotly", "nim c examples/all.nim" +pkg "plotly", "nim c --oldgensym:on examples/all.nim", true pkg "pnm" pkg "polypbren" -pkg "prologue", "nimble tcompile" -pkg "protobuf", "nim c -o:protobuff -r src/protobuf.nim" -pkg "pylib" +pkg "protobuf", "nim c -o:protobuff -r src/protobuf.nim", true pkg "rbtree" pkg "react", "nimble example" -pkg "regex", "nim c src/regex", url = "https://github.com/nim-lang/nim-regex" +pkg "regex", "nim c src/regex", true pkg "result", "nim c -r result.nim" -pkg "RollingHash", "nim c -r tests/test_cyclichash.nim" pkg "rosencrantz", "nim c -o:rsncntz -r rosencrantz.nim" pkg "sdl1", "nim c -r src/sdl.nim" pkg "sdl2_nim", "nim c -r sdl2/sdl.nim" -pkg "sigv4", "nim c --gc:arc -r sigv4.nim", "https://github.com/disruptek/sigv4" -pkg "sim" -pkg "smtp", "nimble compileExample" -pkg "snip", "nimble test", "https://github.com/genotrance/snip" -pkg "stew" -pkg "stint", "nim r stint.nim" -pkg "strslice" -pkg "strunicode", "nim c -r --mm:refc src/strunicode.nim" -pkg "supersnappy" -pkg "synthesis" -pkg "taskpools" -pkg "telebot", "nim c -o:tbot -r src/telebot.nim" +pkg "snip", "", false, "https://github.com/genotrance/snip" +pkg "stint", "nim c -o:stintt -r stint.nim" +pkg "strunicode", "nim c -r src/strunicode.nim", true +pkg "telebot", "nim c -o:tbot --oldgensym:on -r telebot.nim", true pkg "tempdir" -pkg "templates" -pkg "tensordsl", "nim c -r --mm:refc tests/tests.nim", "https://krux02@bitbucket.org/krux02/tensordslnim.git" -pkg "terminaltables", "nim c src/terminaltables.nim" -pkg "termstyle", "nim c -r termstyle.nim" -pkg "timeit" -pkg "timezones" +pkg "tensordsl", "nim c -r tests/tests.nim", false, "https://krux02@bitbucket.org/krux02/tensordslnim.git" pkg "tiny_sqlite" -pkg "unicodedb", "nim c -d:release -r tests/tests.nim" -pkg "unicodeplus", "nim c -d:release -r tests/tests.nim" +pkg "unicodedb" +pkg "unicodeplus", "", true pkg "unpack" -pkg "weave", "nimble test_gc_arc", useHead = true -pkg "websocket", "nim c websocket.nim" -pkg "winim", "nim c winim.nim" +# pkg "winim", "", true pkg "with" -pkg "ws", allowFailure = true -pkg "yaml", "nim c -r test/tserialization.nim" -pkg "zero_functional", "nim c -r -d:nimNoLentIterators test.nim" -pkg "zippy" +pkg "ws" +pkg "yaml" +pkg "zero_functional", "nim c -r test.nim" diff --git a/testament/lib/readme.md b/testament/lib/readme.md deleted file mode 100644 index 20e866338..000000000 --- a/testament/lib/readme.md +++ /dev/null @@ -1,4 +0,0 @@ -This directory contains helper files used by several tests, to avoid -code duplication, akin to a std extension tailored for testament. - -Some of these could later migrate to stdlib. diff --git a/testament/lib/stdtest/netutils.nim b/testament/lib/stdtest/netutils.nim deleted file mode 100644 index 5115390e0..000000000 --- a/testament/lib/stdtest/netutils.nim +++ /dev/null @@ -1,13 +0,0 @@ -import std/[nativesockets, asyncdispatch, os] - -proc bindAvailablePort*(handle: SocketHandle, port = Port(0)): Port = - ## See also `asynchttpserver.getPort`. - block: - var name: Sockaddr_in - name.sin_family = typeof(name.sin_family)(toInt(AF_INET)) - name.sin_port = htons(uint16(port)) - name.sin_addr.s_addr = htonl(INADDR_ANY) - if bindAddr(handle, cast[ptr SockAddr](addr(name)), - sizeof(name).Socklen) < 0'i32: - raiseOSError(osLastError(), $port) - result = getLocalAddr(handle, AF_INET)[1] diff --git a/testament/lib/stdtest/specialpaths.nim b/testament/lib/stdtest/specialpaths.nim index 7df63666f..3c8b2338c 100644 --- a/testament/lib/stdtest/specialpaths.nim +++ b/testament/lib/stdtest/specialpaths.nim @@ -1,54 +1,30 @@ #[ todo: move findNimStdLibCompileTime, findNimStdLib here -xxx: factor pending https://github.com/timotheecour/Nim/issues/616 - -## note: $lib vs $nim -note: these can resolve to 3 different paths if running via `nim c --lib:lib foo`, -eg if compiler was installed via nimble (or is in nim path), and nim is external -(ie not in `$lib/../bin/` dir) - -import "$lib/../compiler/nimpaths" # <- most robust if you want to favor --lib:lib -import "$nim/compiler/nimpaths" -import compiler/nimpaths ]# import os -when defined(nimPreviewSlimSystem): - import std/assertions # Note: all the const paths defined here are known at compile time and valid # so long Nim repo isn't relocated after compilation. # This means the binaries they produce will embed hardcoded paths, which # isn't appropriate for some applications that need to be relocatable. -const - sourcePath = currentSourcePath() - # robust way to derive other paths here - # We don't depend on PATH so this is robust to having multiple nim binaries - nimRootDir* = sourcePath.parentDir.parentDir.parentDir.parentDir ## root of Nim repo - testsFname* = "tests" - stdlibDir* = nimRootDir / "lib" - systemPath* = stdlibDir / "system.nim" - testsDir* = nimRootDir / testsFname - buildDir* = nimRootDir / "build" - ## refs #10268: all testament generated files should go here to avoid - ## polluting .gitignore +const sourcePath = currentSourcePath() + # robust way to derive other paths here + # We don't depend on PATH so this is robust to having multiple nim + # binaries -proc splitTestFile*(file: string): tuple[cat: string, path: string] = - ## At least one directory is required in the path, to use as a category name - runnableExamples: - doAssert splitTestFile("tests/fakedir/tfakename.nim") == ("fakedir", "tests/fakedir/tfakename.nim".unixToNativePath) - for p in file.parentDirs(inclusive = false): - let parent = p.parentDir - if parent.lastPathPart == testsFname: - result.cat = p.lastPathPart - let dir = getCurrentDir() - if file.isRelativeTo(dir): - result.path = file.relativePath(dir) - else: - result.path = file - return result - doAssert false, "file must match this pattern: '/pathto/tests/dir/**/tfile.nim', got: '" & file & "'" +const nimRootDir* = sourcePath.parentDir.parentDir.parentDir.parentDir + ## root of Nim repo + +const stdlibDir* = nimRootDir / "lib" + # todo: make nimeval.findNimStdLibCompileTime use this + +const systemPath* = stdlibDir / "system.nim" + +const buildDir* = nimRootDir / "build" + ## refs #10268: all testament generated files should go here to avoid + ## polluting .gitignore static: # sanity check diff --git a/testament/lib/stdtest/testutils.nim b/testament/lib/stdtest/testutils.nim deleted file mode 100644 index 12e6a56ab..000000000 --- a/testament/lib/stdtest/testutils.nim +++ /dev/null @@ -1,121 +0,0 @@ -import std/private/miscdollars -when defined(nimscript): - import std/os # xxx investigate why needed -else: - from std/os import getEnv -import std/[macros, genasts] - -template flakyAssert*(cond: untyped, msg = "", notifySuccess = true) = - ## API to deal with flaky or failing tests. This avoids disabling entire tests - ## altogether so that at least the parts that are working are kept being - ## tested. This also avoids making CI fail periodically for tests known to - ## be flaky. Finally, for known failures, passing `notifySuccess = true` will - ## log that the test succeeded, which may indicate that a bug was fixed - ## "by accident" and should be looked into. - const info = instantiationInfo(-1, true) - const expr = astToStr(cond) - if cond and not notifySuccess: - discard # silent success - else: - var msg2 = "" - toLocation(msg2, info.filename, info.line, info.column) - if cond: - # a flaky test is failing, we still report it but we don't fail CI - msg2.add " FLAKY_SUCCESS " - else: - # a previously failing test is now passing, a pre-existing bug might've been - # fixed by accidend - msg2.add " FLAKY_FAILURE " - msg2.add $expr & " " & msg - echo msg2 - -when not defined(js) and not defined(nimscript): - import std/strutils - - proc greedyOrderedSubsetLines*(lhs, rhs: string, allowPrefixMatch = false): bool = - ## Returns true if each stripped line in `lhs` appears in rhs, using a greedy matching. - # xxx improve error reporting by showing the last matched pair - iterator splitLinesClosure(): string {.closure.} = - for line in splitLines(rhs.strip): - yield line - template isMatch(lhsi, rhsi): bool = - if allowPrefixMatch: - startsWith(rhsi, lhsi): - else: - lhsi == rhsi - - var rhsIter = splitLinesClosure - var currentLine = strip(rhsIter()) - - for line in lhs.strip.splitLines: - let line = line.strip - if line.len != 0: - while not isMatch(line, currentLine): - currentLine = strip(rhsIter()) - if rhsIter.finished: - return false - - if rhsIter.finished: - return false - return true - -template enableRemoteNetworking*: bool = - ## Allows contolling whether to run some test at a statement-level granularity. - ## Using environment variables simplifies propagating this all the way across - ## process calls, e.g. `testament all` calls itself, which in turns invokes - ## a `nim` invocation (possibly via additional intermediate processes). - getEnv("NIM_TESTAMENT_REMOTE_NETWORKING") == "1" - -template whenRuntimeJs*(bodyIf, bodyElse) = - ##[ - Behaves as `when defined(js) and not nimvm` (which isn't legal yet). - pending improvements to `nimvm`, this sugar helps; use as follows: - - whenRuntimeJs: - doAssert defined(js) - when nimvm: doAssert false - else: discard - do: - discard - ]## - when nimvm: bodyElse - else: - when defined(js): bodyIf - else: bodyElse - -template whenVMorJs*(bodyIf, bodyElse) = - ## Behaves as: `when defined(js) or nimvm` - when nimvm: bodyIf - else: - when defined(js): bodyIf - else: bodyElse - -template accept*(a) = - doAssert compiles(a) - -template reject*(a) = - doAssert not compiles(a) - -template disableVm*(body) = - when nimvm: discard - else: body - -macro assertAll*(body) = - ## works in VM, unlike `check`, `require` - runnableExamples: - assertAll: - 1+1 == 2 - var a = @[1, 2] # statements work - a.len == 2 - # remove this once these support VM, pending #10129 (closed but not yet fixed) - result = newStmtList() - for a in body: - result.add genAst(a, a2 = a.repr, info = lineInfo(a)) do: - # D20210421T014713:here - # xxx pending https://github.com/nim-lang/Nim/issues/12030, - # `typeof` should introduce its own scope, so that this - # is sufficient: `typeof(a)` instead of `typeof(block: a)` - when typeof(block: a) is void: a - else: - if not a: - raise newException(AssertionDefect, info & " " & a2) diff --git a/testament/specs.nim b/testament/specs.nim index 9edbde3b7..d0770d03e 100644 --- a/testament/specs.nim +++ b/testament/specs.nim @@ -7,17 +7,7 @@ # distribution, for details about the copyright. # -import sequtils, parseutils, strutils, os, streams, parsecfg, - tables, hashes, sets -import compiler/platform - -type TestamentData* = ref object - # better to group globals under 1 object; could group the other ones here too - batchArg*: string - testamentNumBatch*: int - testamentBatch*: int - -let testamentData0* = TestamentData() +import sequtils, parseutils, strutils, os, streams, parsecfg var compilerPrefix* = findExe("nim") @@ -35,77 +25,61 @@ type TOutputCheck* = enum ocIgnore = "ignore" - ocEqual = "equal" + ocEqual = "equal" ocSubstr = "substr" TResultEnum* = enum - reNimcCrash, # nim compiler seems to have crashed - reMsgsDiffer, # error messages differ - reFilesDiffer, # expected and given filenames differ - reLinesDiffer, # expected and given line numbers differ + reNimcCrash, # nim compiler seems to have crashed + reMsgsDiffer, # error messages differ + reFilesDiffer, # expected and given filenames differ + reLinesDiffer, # expected and given line numbers differ reOutputsDiffer, - reExitcodesDiffer, # exit codes of program or of valgrind differ + reExitcodesDiffer, reTimeout, reInvalidPeg, reCodegenFailure, reCodeNotFound, reExeNotFound, - reInstallFailed # package installation failed - reBuildFailed # package building failed - reDisabled, # test is disabled - reJoined, # test is disabled because it was joined into the megatest - reSuccess # test was successful - reInvalidSpec # test had problems to parse the spec + reInstallFailed # package installation failed + reBuildFailed # package building failed + reDisabled, # test is disabled + reJoined, # test is disabled because it was joined into the megatest + reSuccess # test was successful + reInvalidSpec # test had problems to parse the spec TTarget* = enum - targetC = "c" - targetCpp = "cpp" - targetObjC = "objc" - targetJS = "js" - - InlineError* = object - kind*: string - msg*: string - line*, col*: int - - ValgrindSpec* = enum - disabled, enabled, leaking + targetC = "C" + targetCpp = "C++" + targetObjC = "ObjC" + targetJS = "JS" TSpec* = object - # xxx make sure `isJoinableSpec` takes into account each field here. action*: TTestAction file*, cmd*: string - filename*: string ## Test filename (without path). input*: string outputCheck*: TOutputCheck sortoutput*: bool output*: string line*, column*: int + tfile*: string + tline*, tcolumn*: int exitCode*: int msg*: string - ccodeCheck*: seq[string] + ccodeCheck*: string maxCodeSize*: int err*: TResultEnum - inCurrentBatch*: bool targets*: set[TTarget] matrix*: seq[string] nimout*: string - nimoutFull*: bool # whether nimout is all compiler output or a subset - parseErrors*: string # when the spec definition is invalid, this is not empty. + parseErrors*: string # when the spec definition is invalid, this is not empty. unjoinable*: bool - unbatchable*: bool - # whether this test can be batchable via `NIM_TESTAMENT_BATCH`; only very - # few tests are not batchable; the ones that are not could be turned batchable - # by making the dependencies explicit - useValgrind*: ValgrindSpec + useValgrind*: bool timeout*: float # in seconds, fractions possible, - # but don't rely on much precision - inlineErrors*: seq[InlineError] # line information to error message - debugInfo*: string # debug info to give more context + # but don't rely on much precision proc getCmd*(s: TSpec): string = if s.cmd.len == 0: - result = compilerPrefix & " $target --hints:on -d:testing --nimblePath:build/deps/pkgs2 $options $file" + result = compilerPrefix & " $target --hints:on -d:testing --nimblePath:tests/deps $options $file" else: result = s.cmd @@ -113,13 +87,6 @@ const targetToExt*: array[TTarget, string] = ["nim.c", "nim.cpp", "nim.m", "js"] targetToCmd*: array[TTarget, string] = ["c", "cpp", "objc", "js"] -proc defaultOptions*(a: TTarget): string = - case a - of targetJS: "-d:nodejs" - # once we start testing for `nim js -d:nimbrowser` (eg selenium or similar), - # we can adapt this logic; or a given js test can override with `-u:nodejs`. - else: "" - when not declared(parseCfgBool): # candidate for the stdlib: proc parseCfgBool(s: string): bool = @@ -128,172 +95,21 @@ when not declared(parseCfgBool): of "n", "no", "false", "0", "off": result = false else: raise newException(ValueError, "cannot interpret as a bool: " & s) -proc addLine*(self: var string; pieces: varargs[string]) = - for piece in pieces: - self.add piece - self.add "\n" - - -const - inlineErrorKindMarker = "tt." - inlineErrorMarker = "#[" & inlineErrorKindMarker - -proc extractErrorMsg(s: string; i: int; line: var int; col: var int; spec: var TSpec): int = - ## Extract inline error messages. - ## - ## Can parse a single message for a line: - ## - ## .. code-block:: nim - ## - ## proc generic_proc*[T] {.no_destroy, userPragma.} = #[tt.Error - ## ^ 'generic_proc' should be: 'genericProc' [Name] ]# - ## - ## Can parse multiple messages for a line when they are separated by ';': - ## - ## .. code-block:: nim - ## - ## proc generic_proc*[T] {.no_destroy, userPragma.} = #[tt.Error - ## ^ 'generic_proc' should be: 'genericProc' [Name]; tt.Error - ## ^ 'no_destroy' should be: 'nodestroy' [Name]; tt.Error - ## ^ 'userPragma' should be: 'user_pragma' [template declared in mstyleCheck.nim(10, 9)] [Name] ]# - ## - ## .. code-block:: nim - ## - ## proc generic_proc*[T] {.no_destroy, userPragma.} = #[tt.Error - ## ^ 'generic_proc' should be: 'genericProc' [Name]; - ## tt.Error ^ 'no_destroy' should be: 'nodestroy' [Name]; - ## tt.Error ^ 'userPragma' should be: 'user_pragma' [template declared in mstyleCheck.nim(10, 9)] [Name] ]# - ## - result = i + len(inlineErrorMarker) - inc col, len(inlineErrorMarker) - let msgLine = line - var msgCol = -1 - var msg = "" - var kind = "" - - template parseKind = - while result < s.len and s[result] in IdentChars: - kind.add s[result] - inc result - inc col - if kind notin ["Hint", "Warning", "Error"]: - spec.parseErrors.addLine "expected inline message kind: Hint, Warning, Error" - - template skipWhitespace = - while result < s.len and s[result] in Whitespace: - if s[result] == '\n': - col = 1 - inc line - else: - inc col - inc result - - template parseCaret = - if result < s.len and s[result] == '^': - msgCol = col - inc result - inc col - skipWhitespace() - else: - spec.parseErrors.addLine "expected column marker ('^') for inline message" - - template isMsgDelimiter: bool = - s[result] == ';' and - (block: - let nextTokenIdx = result + 1 + parseutils.skipWhitespace(s, result + 1) - if s.len > nextTokenIdx + len(inlineErrorKindMarker) and - s[nextTokenIdx..(nextTokenIdx + len(inlineErrorKindMarker) - 1)] == inlineErrorKindMarker: - true - else: - false) - - template trimTrailingMsgWhitespace = - while msg.len > 0 and msg[^1] in Whitespace: - setLen msg, msg.len - 1 - - template addInlineError = - doAssert msg[^1] notin Whitespace - if kind == "Error": spec.action = actionReject - spec.inlineErrors.add InlineError(kind: kind, msg: msg, line: msgLine, col: msgCol) - - parseKind() - skipWhitespace() - parseCaret() - - while result < s.len-1: - if s[result] == '\n': - msg.add '\n' - inc result - inc line - col = 1 - elif isMsgDelimiter(): - trimTrailingMsgWhitespace() - inc result - skipWhitespace() - addInlineError() - inc result, len(inlineErrorKindMarker) - inc col, 1 + len(inlineErrorKindMarker) - kind.setLen 0 - msg.setLen 0 - parseKind() - skipWhitespace() - parseCaret() - elif s[result] == ']' and s[result+1] == '#': - trimTrailingMsgWhitespace() - inc result, 2 - inc col, 2 - addInlineError() - break - else: - msg.add s[result] - inc result - inc col - - if spec.inlineErrors.len > 0: - spec.unjoinable = true - -proc extractSpec(filename: string; spec: var TSpec): string = - const - tripleQuote = "\"\"\"" - specStart = "discard " & tripleQuote - var s = readFile(filename) - - var i = 0 - var a = -1 - var b = -1 - var line = 1 - var col = 1 - while i < s.len: - if (i == 0 or s[i-1] != ' ') and s.continuesWith(specStart, i): - # `s[i-1] == '\n'` would not work because of `tests/stdlib/tbase64.nim` which contains BOM (https://en.wikipedia.org/wiki/Byte_order_mark) - const lineMax = 10 - if a != -1: - raise newException(ValueError, "testament spec violation: duplicate `specStart` found: " & $(filename, a, b, line)) - elif line > lineMax: - # not overly restrictive, but prevents mistaking some `specStart` as spec if deeep inside a test file - raise newException(ValueError, "testament spec violation: `specStart` should be before line $1, or be indented; info: $2" % [$lineMax, $(filename, a, b, line)]) - i += specStart.len - a = i - elif a > -1 and b == -1 and s.continuesWith(tripleQuote, i): - b = i - i += tripleQuote.len - elif s[i] == '\n': - inc line - inc i - col = 1 - elif s.continuesWith(inlineErrorMarker, i): - i = extractErrorMsg(s, i, line, col, spec) - else: - inc col - inc i - - if a >= 0 and b > a: - result = s.substr(a, b-1).multiReplace({"'''": tripleQuote, "\\31": "\31"}) - elif a >= 0: - raise newException(ValueError, "testament spec violation: `specStart` found but not trailing `tripleQuote`: $1" % $(filename, a, b, line)) +proc extractSpec(filename: string): string = + const tripleQuote = "\"\"\"" + var x = readFile(filename).string + var a = x.find(tripleQuote) + var b = x.find(tripleQuote, a+3) + # look for """ only in the first section + if a >= 0 and b > a and a < 40: + result = x.substr(a+3, b-1).replace("'''", tripleQuote) else: + #echo "warning: file does not contain spec: " & filename result = "" +when not defined(nimhygiene): + {.pragma: inject.} + proc parseTargets*(value: string): set[TTarget] = for v in value.normalize.splitWhitespace: case v @@ -301,38 +117,31 @@ proc parseTargets*(value: string): set[TTarget] = of "cpp", "c++": result.incl(targetCpp) of "objc": result.incl(targetObjC) of "js": result.incl(targetJS) - else: raise newException(ValueError, "invalid target: '$#'" % v) + else: echo "target ignored: " & v + +proc addLine*(self: var string; a: string) = + self.add a + self.add "\n" + +proc addLine*(self: var string; a,b: string) = + self.add a + self.add b + self.add "\n" proc initSpec*(filename: string): TSpec = result.file = filename -proc isCurrentBatch*(testamentData: TestamentData; filename: string): bool = - if testamentData.testamentNumBatch != 0: - hash(filename) mod testamentData.testamentNumBatch == testamentData.testamentBatch - else: - true - proc parseSpec*(filename: string): TSpec = result.file = filename - result.filename = extractFilename(filename) - let specStr = extractSpec(filename, result) + let specStr = extractSpec(filename) var ss = newStringStream(specStr) var p: CfgParser open(p, ss, filename, 1) - var flags: HashSet[string] - var nimoutFound = false while true: var e = next(p) case e.kind of cfgKeyValuePair: - let key = e.key.normalize - const whiteListMulti = ["disabled", "ccodecheck"] - ## list of flags that are correctly handled when passed multiple times - ## (instead of being overwritten) - if key notin whiteListMulti: - doAssert key notin flags, $(key, filename) - flags.incl key - case key + case normalize(e.key) of "action": case e.value.normalize of "compile": @@ -355,10 +164,16 @@ proc parseSpec*(filename: string): TSpec = if result.msg.len == 0 and result.nimout.len == 0: result.parseErrors.addLine "errormsg or msg needs to be specified before column" discard parseInt(e.value, result.column) + of "tfile": + result.tfile = e.value + of "tline": + discard parseInt(e.value, result.tline) + of "tcolumn": + discard parseInt(e.value, result.tcolumn) of "output": if result.outputCheck != ocSubstr: result.outputCheck = ocEqual - result.output = e.value + result.output = strip(e.value) of "input": result.input = e.value of "outputsub": @@ -366,108 +181,71 @@ proc parseSpec*(filename: string): TSpec = result.output = strip(e.value) of "sortoutput": try: - result.sortoutput = parseCfgBool(e.value) + result.sortoutput = parseCfgBool(e.value) except: result.parseErrors.addLine getCurrentExceptionMsg() of "exitcode": discard parseInt(e.value, result.exitCode) result.action = actionRun - of "errormsg": + of "msg": + result.msg = e.value + if result.action != actionRun: + result.action = actionCompile + of "errormsg", "errmsg": result.msg = e.value result.action = actionReject of "nimout": result.nimout = e.value - nimoutFound = true - of "nimoutfull": - result.nimoutFull = parseCfgBool(e.value) - of "batchable": - result.unbatchable = not parseCfgBool(e.value) of "joinable": result.unjoinable = not parseCfgBool(e.value) of "valgrind": when defined(linux) and sizeof(int) == 8: - result.useValgrind = if e.value.normalize == "leaks": leaking - else: ValgrindSpec(parseCfgBool(e.value)) + result.useValgrind = parseCfgBool(e.value) result.unjoinable = true - if result.useValgrind != disabled: + if result.useValgrind: result.outputCheck = ocSubstr else: # Windows lacks valgrind. Silly OS. # Valgrind only supports OSX <= 17.x - result.useValgrind = disabled + result.useValgrind = false of "disabled": - let value = e.value.normalize - case value + case e.value.normalize of "y", "yes", "true", "1", "on": result.err = reDisabled of "n", "no", "false", "0", "off": discard - # These values are defined in `compiler/options.isDefined` - of "win": + of "win", "windows": when defined(windows): result.err = reDisabled of "linux": when defined(linux): result.err = reDisabled of "bsd": when defined(bsd): result.err = reDisabled - of "osx": - when defined(osx): result.err = reDisabled - of "unix", "posix": + of "macosx": + when defined(macosx): result.err = reDisabled + of "unix": + when defined(unix): result.err = reDisabled + of "posix": when defined(posix): result.err = reDisabled - of "freebsd": - when defined(freebsd): result.err = reDisabled - of "littleendian": - when defined(littleendian): result.err = reDisabled - of "bigendian": - when defined(bigendian): result.err = reDisabled - of "cpu8", "8bit": - when defined(cpu8): result.err = reDisabled - of "cpu16", "16bit": - when defined(cpu16): result.err = reDisabled - of "cpu32", "32bit": - when defined(cpu32): result.err = reDisabled - of "cpu64", "64bit": - when defined(cpu64): result.err = reDisabled - # These values are for CI environments - of "travis": # deprecated + of "travis": if isTravis: result.err = reDisabled - of "appveyor": # deprecated + of "appveyor": if isAppVeyor: result.err = reDisabled of "azure": if isAzure: result.err = reDisabled + of "32bit": + if sizeof(int) == 4: + result.err = reDisabled + of "freebsd": + when defined(freebsd): result.err = reDisabled + of "arm64": + when defined(arm64): result.err = reDisabled else: - # Check whether the value exists as an OS or CPU that is - # defined in `compiler/platform`. - block checkHost: - for os in platform.OS: - # Check if the value exists as OS. - if value == os.name.normalize: - # The value exists; is it the same as the current host? - if value == hostOS.normalize: - # The value exists and is the same as the current host, - # so disable the test. - result.err = reDisabled - # The value was defined, so there is no need to check further - # values or raise an error. - break checkHost - for cpu in platform.CPU: - # Check if the value exists as CPU. - if value == cpu.name.normalize: - # The value exists; is it the same as the current host? - if value == hostCPU.normalize: - # The value exists and is the same as the current host, - # so disable the test. - result.err = reDisabled - # The value was defined, so there is no need to check further - # values or raise an error. - break checkHost - # The value doesn't exist as an OS, CPU, or any previous value - # defined in this case statement, so raise an error. - result.parseErrors.addLine "cannot interpret as a bool: ", e.value + result.parseErrors.addLine "cannot interpret as a bool: ", e.value of "cmd": if e.value.startsWith("nim "): result.cmd = compilerPrefix & e.value[3..^1] else: result.cmd = e.value of "ccodecheck": - result.ccodeCheck.add e.value + result.ccodeCheck = e.value of "maxcodesize": discard parseInt(e.value, result.maxCodeSize) of "timeout": @@ -475,11 +253,19 @@ proc parseSpec*(filename: string): TSpec = result.timeout = parseFloat(e.value) except ValueError: result.parseErrors.addLine "cannot interpret as a float: ", e.value - of "targets", "target": - try: - result.targets.incl parseTargets(e.value) - except ValueError as e: - result.parseErrors.addLine e.msg + of "target", "targets": + for v in e.value.normalize.splitWhitespace: + case v + of "c": + result.targets.incl(targetC) + of "cpp", "c++": + result.targets.incl(targetCpp) + of "objc": + result.targets.incl(targetObjC) + of "js": + result.targets.incl(targetJS) + else: + result.parseErrors.addLine "cannot interpret as a target: ", e.value of "matrix": for v in e.value.split(';'): result.matrix.add(v.strip) @@ -498,22 +284,3 @@ proc parseSpec*(filename: string): TSpec = if skips.anyIt(it in result.file): result.err = reDisabled - - if nimoutFound and result.nimout.len == 0 and not result.nimoutFull: - result.parseErrors.addLine "empty `nimout` is vacuously true, use `nimoutFull:true` if intentional" - - result.inCurrentBatch = isCurrentBatch(testamentData0, filename) or result.unbatchable - if not result.inCurrentBatch: - result.err = reDisabled - - # Interpolate variables in msgs: - template varSub(msg: string): string = - try: - msg % ["/", $DirSep, "file", result.filename] - except ValueError: - result.parseErrors.addLine "invalid variable interpolation (see 'https://nim-lang.github.io/Nim/testament.html#writing-unitests-output-message-variable-interpolation')" - msg - result.nimout = result.nimout.varSub - result.msg = result.msg.varSub - for inlineError in result.inlineErrors.mitems: - inlineError.msg = inlineError.msg.varSub diff --git a/testament/testament.nim b/testament/testament.nim index 296c313aa..a437f18dd 100644 --- a/testament/testament.nim +++ b/testament/testament.nim @@ -10,109 +10,87 @@ ## This program verifies Nim against the testcases. import - strutils, pegs, os, osproc, streams, json, std/exitprocs, + strutils, pegs, os, osproc, streams, json, backend, parseopt, specs, htmlgen, browsers, terminal, - algorithm, times, md5, azure, intsets, macros -from std/sugar import dup -import compiler/nodejs -import lib/stdtest/testutils -from lib/stdtest/specialpaths import splitTestFile -from std/private/gitutils import diffStrings + algorithm, times, md5, sequtils, azure -proc trimUnitSep(x: var string) = - let L = x.len - if L > 0 and x[^1] == '\31': - setLen x, L-1 +include compiler/nodejs var useColors = true var backendLogging = true var simulate = false -var optVerbose = false -var useMegatest = true -var valgrindEnabled = true - -proc verboseCmd(cmd: string) = - if optVerbose: - echo "executing: ", cmd const - failString* = "FAIL: " # ensures all failures can be searched with 1 keyword in CI logs testsDir = "tests" & DirSep resultsFile = "testresults.html" + #jsonFile = "testresults.json" # not used Usage = """Usage: testament [options] command [arguments] Command: p|pat|pattern run all the tests matching the given pattern - all run all tests in category folders + all run all tests c|cat|category run all the tests of a certain category r|run run single test file html generate $1 from the database + stats generate statistics about test cases Arguments: arguments are passed to the compiler Options: - --print print results to the console - --verbose print commands (compiling and running tests) + --print also print results to the console --simulate see what tests would be run but don't run them (for debugging) --failing only show failing/ignored tests - --targets:"c cpp js objc" run tests for specified targets (default: c) + --targets:"c c++ js objc" run tests for specified targets (default: all) --nim:path use a particular nim executable (default: $$PATH/nim) --directory:dir Change to directory dir before reading the tests or doing anything else. --colors:on|off Turn messages coloring on|off. --backendLogging:on|off Disable or enable backend logging. By default turned on. --megatest:on|off Enable or disable megatest. Default is on. - --valgrind:on|off Enable or disable valgrind support. Default is on. --skipFrom:file Read tests to skip from `file` - one test per line, # comments ignored On Azure Pipelines, testament will also publish test results via Azure Pipelines' Test Management API provided that System.AccessToken is made available via the environment variable SYSTEM_ACCESSTOKEN. - -Experimental: using environment variable `NIM_TESTAMENT_REMOTE_NETWORKING=1` enables -tests with remote networking (as in CI). """ % resultsFile -proc isNimRepoTests(): bool = - # this logic could either be specific to cwd, or to some file derived from - # the input file, eg testament r /pathto/tests/foo/tmain.nim; we choose - # the former since it's simpler and also works with `testament all`. - let file = "testament"/"testament.nim.cfg" - result = file.fileExists - type Category = distinct string TResults = object - total, passed, failedButAllowed, skipped: int - ## xxx rename passed to passedOrAllowedFailure + total, passed, skipped: int data: string + TTest = object name: string cat: Category options: string - testArgs: seq[string] + args: seq[string] spec: TSpec startTime: float - debugInfo: string # ---------------------------------------------------------------------------- let pegLineError = peg"{[^(]*} '(' {\d+} ', ' {\d+} ') ' ('Error') ':' \s* {.*}" + pegLineTemplate = + peg""" + {[^(]*} '(' {\d+} ', ' {\d+} ') ' + 'template/generic instantiation' ( ' of `' [^`]+ '`' )? ' from here' .* + """ pegOtherError = peg"'Error:' \s* {.*}" pegOfInterest = pegLineError / pegOtherError var gTargets = {low(TTarget)..high(TTarget)} -var targetsSet = false proc isSuccess(input: string): bool = # not clear how to do the equivalent of pkg/regex's: re"FOO(.*?)BAR" in pegs - # note: this doesn't handle colors, eg: `\e[1m\e[0m\e[32mHint:`; while we - # could handle colors, there would be other issues such as handling other flags - # that may appear in user config (eg: `--filenames`). - # Passing `XDG_CONFIG_HOME= testament args...` can be used to ignore user config - # stored in XDG_CONFIG_HOME, refs https://wiki.archlinux.org/index.php/XDG_Base_Directory input.startsWith("Hint: ") and input.endsWith("[SuccessX]") +proc normalizeMsg(s: string): string = + result = newStringOfCap(s.len+1) + for x in splitLines(s): + if result.len > 0: result.add '\L' + result.add x.strip + proc getFileDir(filename: string): string = result = filename.splitFile().dir if not result.isAbsolute(): @@ -120,7 +98,7 @@ proc getFileDir(filename: string): string = proc execCmdEx2(command: string, args: openArray[string]; workingDir, input: string = ""): tuple[ cmdLine: string, - output: string, + output: TaintedString, exitCode: int] {.tags: [ExecIOEffect, ReadIOEffect, RootEffect], gcsafe.} = @@ -128,9 +106,8 @@ proc execCmdEx2(command: string, args: openArray[string]; workingDir, input: str for arg in args: result.cmdLine.add ' ' result.cmdLine.add quoteShell(arg) - verboseCmd(result.cmdLine) - var p = startProcess(command, workingDir = workingDir, args = args, - options = {poStdErrToStdOut, poUsePath}) + var p = startProcess(command, workingDir=workingDir, args=args, + options={poStdErrToStdOut, poUsePath}) var outp = outputStream(p) # There is no way to provide input for the child process @@ -140,12 +117,12 @@ proc execCmdEx2(command: string, args: openArray[string]; workingDir, input: str instream.write(input) close instream - result.exitCode = -1 - var line = newStringOfCap(120) + result.exitCode = -1 + var line = newStringOfCap(120).TaintedString while true: if outp.readLine(line): - result.output.add line - result.output.add '\n' + result.output.string.add(line.string) + result.output.string.add("\n") else: result.exitCode = peekExitCode(p) if result.exitCode != -1: break @@ -156,39 +133,37 @@ proc nimcacheDir(filename, options: string, target: TTarget): string = let hashInput = options & $target result = "nimcache" / (filename & '_' & hashInput.getMD5) -proc prepareTestCmd(cmdTemplate, filename, options, nimcache: string, - target: TTarget, extraOptions = ""): string = - var options = target.defaultOptions & ' ' & options - if nimcache.len > 0: options.add(" --nimCache:$#" % nimcache.quoteShell) - options.add ' ' & extraOptions - # we avoid using `parseCmdLine` which is buggy, refs bug #14343 - result = cmdTemplate % ["target", targetToCmd[target], +proc prepareTestArgs(cmdTemplate, filename, options, nimcache: string, + target: TTarget, extraOptions = ""): seq[string] = + let options = options & " " & quoteShell("--nimCache:" & nimcache) & " " & extraOptions + result = parseCmdLine(cmdTemplate % ["target", targetToCmd[target], "options", options, "file", filename.quoteShell, - "filedir", filename.getFileDir(), "nim", compilerPrefix] + "filedir", filename.getFileDir()]) -proc callNimCompiler(cmdTemplate, filename, options, nimcache: string, - target: TTarget, extraOptions = ""): TSpec = - result.cmd = prepareTestCmd(cmdTemplate, filename, options, nimcache, target, +proc callCompiler(cmdTemplate, filename, options, nimcache: string, + target: TTarget, extraOptions = ""): TSpec = + let c = prepareTestArgs(cmdTemplate, filename, options, nimcache, target, extraOptions) - verboseCmd(result.cmd) - var p = startProcess(command = result.cmd, - options = {poStdErrToStdOut, poUsePath, poEvalCommand}) + result.cmd = quoteShellCommand(c) + var p = startProcess(command=c[0], args=c[1 .. ^1], + options={poStdErrToStdOut, poUsePath}) let outp = p.outputStream - var foundSuccessMsg = false - var foundErrorMsg = false + var suc = "" var err = "" + var tmpl = "" var x = newStringOfCap(120) result.nimout = "" while true: - if outp.readLine(x): - trimUnitSep x - result.nimout.add(x & '\n') + if outp.readLine(x.TaintedString): + result.nimout.add(x & "\n") if x =~ pegOfInterest: - # `err` should contain the last error message + # `err` should contain the last error/warning message err = x - foundErrorMsg = true + elif x =~ pegLineTemplate and err == "": + # `tmpl` contains the last template expansion before the error + tmpl = x elif x.isSuccess: - foundSuccessMsg = true + suc = x elif not running(p): break close(p) @@ -197,23 +172,14 @@ proc callNimCompiler(cmdTemplate, filename, options, nimcache: string, result.output = "" result.line = 0 result.column = 0 - + result.tfile = "" + result.tline = 0 + result.tcolumn = 0 result.err = reNimcCrash - let exitCode = p.peekExitCode - case exitCode - of 0: - if foundErrorMsg: - result.debugInfo.add " compiler exit code was 0 but some Error's were found." - else: - result.err = reSuccess - of 1: - if not foundErrorMsg: - result.debugInfo.add " compiler exit code was 1 but no Error's were found." - if foundSuccessMsg: - result.debugInfo.add " compiler exit code was 1 but no `isSuccess` was true." - else: - result.debugInfo.add " expected compiler exit code 0 or 1, got $1." % $exitCode - + if tmpl =~ pegLineTemplate: + result.tfile = extractFilename(matches[0]) + result.tline = parseInt(matches[1]) + result.tcolumn = parseInt(matches[2]) if err =~ pegLineError: result.file = extractFilename(matches[0]) result.line = parseInt(matches[1]) @@ -221,15 +187,40 @@ proc callNimCompiler(cmdTemplate, filename, options, nimcache: string, result.msg = matches[3] elif err =~ pegOtherError: result.msg = matches[0] - trimUnitSep result.msg + elif suc.isSuccess: + result.err = reSuccess + +proc callCCompiler(cmdTemplate, filename, options: string, + target: TTarget): TSpec = + let c = parseCmdLine(cmdTemplate % ["target", targetToCmd[target], + "options", options, "file", filename.quoteShell, + "filedir", filename.getFileDir()]) + var p = startProcess(command="gcc", args=c[5 .. ^1], + options={poStdErrToStdOut, poUsePath}) + let outp = p.outputStream + var x = newStringOfCap(120) + result.nimout = "" + result.msg = "" + result.file = "" + result.output = "" + result.line = -1 + while true: + if outp.readLine(x.TaintedString): + result.nimout.add(x & "\n") + elif not running(p): + break + close(p) + if p.peekExitCode == 0: + result.err = reSuccess proc initResults: TResults = result.total = 0 result.passed = 0 - result.failedButAllowed = 0 result.skipped = 0 result.data = "" +import macros + macro ignoreStyleEcho(args: varargs[typed]): untyped = let typForegroundColor = bindSym"ForegroundColor".getType let typBackgroundColor = bindSym"BackgroundColor".getType @@ -254,34 +245,22 @@ template maybeStyledEcho(args: varargs[untyped]): untyped = proc `$`(x: TResults): string = - result = """ -Tests passed or allowed to fail: $2 / $1
      -Tests failed and allowed to fail: $3 / $1
      -Tests skipped: $4 / $1
      -""" % [$x.total, $x.passed, $x.failedButAllowed, $x.skipped] - -proc testName(test: TTest, target: TTarget, extraOptions: string, allowFailure: bool): string = - var name = test.name.replace(DirSep, '/') - name.add ' ' & $target - if allowFailure: - name.add " (allowed to fail) " - if test.options.len > 0: name.add ' ' & test.options - if extraOptions.len > 0: name.add ' ' & extraOptions - name.strip() + result = ("Tests passed: $1 / $3
      \n" & + "Tests skipped: $2 / $3
      \n") % + [$x.passed, $x.skipped, $x.total] proc addResult(r: var TResults, test: TTest, target: TTarget, - extraOptions, expected, given: string, successOrig: TResultEnum, - allowFailure = false, givenSpec: ptr TSpec = nil) = - # instead of `ptr TSpec` we could also use `Option[TSpec]`; passing `givenSpec` makes it easier to get what we need - # instead of having to pass individual fields, or abusing existing ones like expected vs given. + expected, given: string, successOrig: TResultEnum) = # test.name is easier to find than test.name.extractFilename # A bit hacky but simple and works with tests/testament/tshould_not_work.nim - let name = testName(test, target, extraOptions, allowFailure) + var name = test.name.replace(DirSep, '/') + name.add " " & $target & test.options + let duration = epochTime() - test.startTime let success = if test.spec.timeout > 0.0 and duration > test.spec.timeout: reTimeout else: successOrig - let durationStr = duration.formatFloat(ffDecimal, precision = 2).align(5) + let durationStr = duration.formatFloat(ffDecimal, precision = 8).align(11) if backendLogging: backend.writeTestResult(name = name, category = test.cat.string, @@ -291,22 +270,16 @@ proc addResult(r: var TResults, test: TTest, target: TTarget, expected = expected, given = given) r.data.addf("$#\t$#\t$#\t$#", name, expected, given, $success) - template dispNonSkipped(color, outcome) = - maybeStyledEcho color, outcome, fgCyan, test.debugInfo, alignLeft(name, 60), fgBlue, " (", durationStr, " sec)" - template disp(msg) = - maybeStyledEcho styleDim, fgYellow, msg & ' ', styleBright, fgCyan, name if success == reSuccess: - dispNonSkipped(fgGreen, "PASS: ") + maybeStyledEcho fgGreen, "PASS: ", fgCyan, alignLeft(name, 60), fgBlue, " (", durationStr, " secs)" elif success == reDisabled: - if test.spec.inCurrentBatch: disp("SKIP:") - else: disp("NOTINBATCH:") - elif success == reJoined: disp("JOINED:") + maybeStyledEcho styleDim, fgYellow, "SKIP: ", styleBright, fgCyan, name + elif success == reJoined: + maybeStyledEcho styleDim, fgYellow, "JOINED: ", styleBright, fgCyan, name else: - dispNonSkipped(fgRed, failString) + maybeStyledEcho styleBright, fgRed, "FAIL: ", fgCyan, name maybeStyledEcho styleBright, fgCyan, "Test \"", test.name, "\"", " in category \"", test.cat.string, "\"" maybeStyledEcho styleBright, fgRed, "Failure: ", $success - if givenSpec != nil and givenSpec.debugInfo.len > 0: - echo "debugInfo: " & givenSpec.debugInfo if success in {reBuildFailed, reNimcCrash, reInstallFailed}: # expected is empty, no reason to print it. echo given @@ -315,7 +288,7 @@ proc addResult(r: var TResults, test: TTest, target: TTarget, maybeStyledEcho styleBright, expected, "\n" maybeStyledEcho fgYellow, "Gotten:" maybeStyledEcho styleBright, given, "\n" - echo diffStrings(expected, given).output + if backendLogging and (isAppVeyor or isAzure): let (outcome, msg) = @@ -325,66 +298,44 @@ proc addResult(r: var TResults, test: TTest, target: TTarget, of reDisabled, reJoined: ("Skipped", "") of reBuildFailed, reNimcCrash, reInstallFailed: - ("Failed", "Failure: " & $success & '\n' & given) + ("Failed", "Failure: " & $success & "\n" & given) else: ("Failed", "Failure: " & $success & "\nExpected:\n" & expected & "\n\n" & "Gotten:\n" & given) if isAzure: azure.addTestResult(name, test.cat.string, int(duration * 1000), msg, success) else: - var p = startProcess("appveyor", args = ["AddTest", test.name.replace("\\", "/") & test.options, + var p = startProcess("appveyor", args=["AddTest", test.name.replace("\\", "/") & test.options, "-Framework", "nim-testament", "-FileName", test.cat.string, "-Outcome", outcome, "-ErrorMessage", msg, - "-Duration", $(duration * 1000).int], - options = {poStdErrToStdOut, poUsePath, poParentStreams}) + "-Duration", $(duration*1000).int], + options={poStdErrToStdOut, poUsePath, poParentStreams}) discard waitForExit(p) close(p) -proc toString(inlineError: InlineError, filename: string): string = - result.add "$file($line, $col) $kind: $msg" % [ - "file", filename, - "line", $inlineError.line, - "col", $inlineError.col, - "kind", $inlineError.kind, - "msg", $inlineError.msg - ] - -proc inlineErrorsMsgs(expected: TSpec): string = - for inlineError in expected.inlineErrors.items: - result.addLine inlineError.toString(expected.filename) - -proc checkForInlineErrors(expected, given: TSpec): bool = - for inlineError in expected.inlineErrors: - if inlineError.toString(expected.filename) notin given.nimout: - return false - true - -proc nimoutCheck(expected, given: TSpec): bool = - result = true - if expected.nimoutFull: - if expected.nimout != given.nimout: - result = false - elif expected.nimout.len > 0 and not greedyOrderedSubsetLines(expected.nimout, given.nimout): - result = false - -proc cmpMsgs(r: var TResults, expected, given: TSpec, test: TTest, - target: TTarget, extraOptions: string) = - if not checkForInlineErrors(expected, given) or - (not expected.nimoutFull and not nimoutCheck(expected, given)): - r.addResult(test, target, extraOptions, expected.nimout & inlineErrorsMsgs(expected), given.nimout, reMsgsDiffer) - elif strip(expected.msg) notin strip(given.msg): - r.addResult(test, target, extraOptions, expected.msg, given.msg, reMsgsDiffer) - elif not nimoutCheck(expected, given): - r.addResult(test, target, extraOptions, expected.nimout, given.nimout, reMsgsDiffer) - elif extractFilename(expected.file) != extractFilename(given.file) and +proc cmpMsgs(r: var TResults, expected, given: TSpec, test: TTest, target: TTarget) = + if strip(expected.msg) notin strip(given.msg): + r.addResult(test, target, expected.msg, given.msg, reMsgsDiffer) + elif expected.nimout.len > 0 and expected.nimout.normalizeMsg notin given.nimout.normalizeMsg: + r.addResult(test, target, expected.nimout, given.nimout, reMsgsDiffer) + elif expected.tfile == "" and extractFilename(expected.file) != extractFilename(given.file) and "internal error:" notin expected.msg: - r.addResult(test, target, extraOptions, expected.filename, given.file, reFilesDiffer) + r.addResult(test, target, expected.file, given.file, reFilesDiffer) elif expected.line != given.line and expected.line != 0 or expected.column != given.column and expected.column != 0: - r.addResult(test, target, extraOptions, $expected.line & ':' & $expected.column, - $given.line & ':' & $given.column, reLinesDiffer) + r.addResult(test, target, $expected.line & ':' & $expected.column, + $given.line & ':' & $given.column, + reLinesDiffer) + elif expected.tfile != "" and extractFilename(expected.tfile) != extractFilename(given.tfile) and + "internal error:" notin expected.msg: + r.addResult(test, target, expected.tfile, given.tfile, reFilesDiffer) + elif expected.tline != given.tline and expected.tline != 0 or + expected.tcolumn != given.tcolumn and expected.tcolumn != 0: + r.addResult(test, target, $expected.tline & ':' & $expected.tcolumn, + $given.tline & ':' & $given.tcolumn, + reLinesDiffer) else: - r.addResult(test, target, extraOptions, expected.msg, given.msg, reSuccess) + r.addResult(test, target, expected.msg, given.msg, reSuccess) inc(r.passed) proc generatedFile(test: TTest, target: TTarget): string = @@ -402,9 +353,10 @@ proc codegenCheck(test: TTest, target: TTarget, spec: TSpec, expectedMsg: var st given: var TSpec) = try: let genFile = generatedFile(test, target) - let contents = readFile(genFile) - for check in spec.ccodeCheck: - if check.len > 0 and check[0] == '\\': + let contents = readFile(genFile).string + let check = spec.ccodeCheck + if check.len > 0: + if check[0] == '\\': # little hack to get 'match' support: if not contents.match(check.peg): given.err = reCodegenFailure @@ -422,78 +374,90 @@ proc codegenCheck(test: TTest, target: TTarget, spec: TSpec, expectedMsg: var st given.err = reCodeNotFound echo getCurrentExceptionMsg() -proc compilerOutputTests(test: TTest, target: TTarget, extraOptions: string, - given: var TSpec, expected: TSpec; r: var TResults) = +proc nimoutCheck(test: TTest; expectedNimout: string; given: var TSpec) = + let giv = given.nimout.strip + var currentPos = 0 + # Only check that nimout contains all expected lines in that order. + # There may be more output in nimout. It is ignored here. + for line in expectedNimout.strip.splitLines: + currentPos = giv.find(line.strip, currentPos) + if currentPos < 0: + given.err = reMsgsDiffer + break + +proc compilerOutputTests(test: TTest, target: TTarget, given: var TSpec, + expected: TSpec; r: var TResults) = var expectedmsg: string = "" var givenmsg: string = "" if given.err == reSuccess: if expected.needsCodegenCheck: codegenCheck(test, target, expected, expectedmsg, given) givenmsg = given.msg - if not nimoutCheck(expected, given) or - not checkForInlineErrors(expected, given): - given.err = reMsgsDiffer - expectedmsg = expected.nimout & inlineErrorsMsgs(expected) + if expected.nimout.len > 0: + expectedmsg = expected.nimout givenmsg = given.nimout.strip + nimoutCheck(test, expectedmsg, given) else: - givenmsg = "$ " & given.cmd & '\n' & given.nimout + givenmsg = "$ " & given.cmd & "\n" & given.nimout if given.err == reSuccess: inc(r.passed) - r.addResult(test, target, extraOptions, expectedmsg, givenmsg, given.err) + r.addResult(test, target, expectedmsg, givenmsg, given.err) proc getTestSpecTarget(): TTarget = - if getEnv("NIM_COMPILE_TO_CPP", "false") == "true": + if getEnv("NIM_COMPILE_TO_CPP", "false").string == "true": result = targetCpp else: result = targetC +proc checkDisabled(r: var TResults, test: TTest): bool = + if test.spec.err in {reDisabled, reJoined}: + # targetC is a lie, but parameter is required + r.addResult(test, targetC, "", "", test.spec.err) + inc(r.skipped) + inc(r.total) + result = false + else: + result = true + var count = 0 -proc equalModuloLastNewline(a, b: string): bool = - # allow lazy output spec that omits last newline, but really those should be fixed instead - result = a == b or b.endsWith("\n") and a == b[0 ..< ^1] - -proc testSpecHelper(r: var TResults, test: var TTest, expected: TSpec, - target: TTarget, extraOptions: string, nimcache: string) = - test.startTime = epochTime() - if testName(test, target, extraOptions, false) in skips: - test.spec.err = reDisabled - - if test.spec.err in {reDisabled, reJoined}: - r.addResult(test, target, extraOptions, "", "", test.spec.err) - inc(r.skipped) - return - var given = callNimCompiler(expected.getCmd, test.name, test.options, nimcache, target, extraOptions) +proc testSpecHelper(r: var TResults, test: TTest, expected: TSpec, + target: TTarget, nimcache: string, extraOptions = "") = case expected.action of actionCompile: - compilerOutputTests(test, target, extraOptions, given, expected, r) + var given = callCompiler(expected.getCmd, test.name, test.options, nimcache, target, + extraOptions = " --stdout --hint[Path]:off --hint[Processing]:off") + compilerOutputTests(test, target, given, expected, r) of actionRun: + var given = callCompiler(expected.getCmd, test.name, test.options, + nimcache, target, extraOptions) if given.err != reSuccess: - r.addResult(test, target, extraOptions, "", "$ " & given.cmd & '\n' & given.nimout, given.err, givenSpec = given.addr) + r.addResult(test, target, "", "$ " & given.cmd & "\n" & given.nimout, given.err) else: let isJsTarget = target == targetJS var exeFile = changeFileExt(test.name, if isJsTarget: "js" else: ExeExt) - if not fileExists(exeFile): - r.addResult(test, target, extraOptions, expected.output, + if not existsFile(exeFile): + r.addResult(test, target, expected.output, "executable not found: " & exeFile, reExeNotFound) else: let nodejs = if isJsTarget: findNodeJs() else: "" if isJsTarget and nodejs == "": - r.addResult(test, target, extraOptions, expected.output, "nodejs binary not in PATH", + r.addResult(test, target, expected.output, "nodejs binary not in PATH", reExeNotFound) else: var exeCmd: string - var args = test.testArgs + var args = test.args if isJsTarget: exeCmd = nodejs - # see D20210217T215950 - args = @["--unhandled-rejections=strict", exeFile] & args + args = concat(@[exeFile], args) else: - exeCmd = exeFile.dup(normalizeExe) - if valgrindEnabled and expected.useValgrind != disabled: - var valgrindOptions = @["--error-exitcode=1"] - if expected.useValgrind != leaking: - valgrindOptions.add "--leak-check=yes" - args = valgrindOptions & exeCmd & args + if defined(posix) and not exeFile.contains('/'): + # "security" in Posix is actually just a euphemism + # for "unproductive arbitrary shit" + exeCmd = "./" & exeFile + else: + exeCmd = exeFile + if expected.useValgrind: + args = @["--error-exitcode=1"] & exeCmd & args exeCmd = "valgrind" var (_, buf, exitCode) = execCmdEx2(exeCmd, args, input = expected.input) # Treat all failure codes from nodejs as 1. Older versions of nodejs used @@ -501,47 +465,47 @@ proc testSpecHelper(r: var TResults, test: var TTest, expected: TSpec, if exitCode != 0: exitCode = 1 let bufB = if expected.sortoutput: - var buf2 = buf - buf2.stripLineEnd - var x = splitLines(buf2) + var x = splitLines(strip(buf.string)) sort(x, system.cmp) - join(x, "\n") & '\n' + join(x, "\n") else: - buf + strip(buf.string) if exitCode != expected.exitCode: - given.err = reExitcodesDiffer - r.addResult(test, target, extraOptions, "exitcode: " & $expected.exitCode, + r.addResult(test, target, "exitcode: " & $expected.exitCode, "exitcode: " & $exitCode & "\n\nOutput:\n" & bufB, reExitcodesDiffer) - elif (expected.outputCheck == ocEqual and not expected.output.equalModuloLastNewline(bufB)) or + elif (expected.outputCheck == ocEqual and expected.output != bufB) or (expected.outputCheck == ocSubstr and expected.output notin bufB): given.err = reOutputsDiffer - r.addResult(test, target, extraOptions, expected.output, bufB, reOutputsDiffer) - compilerOutputTests(test, target, extraOptions, given, expected, r) + r.addResult(test, target, expected.output, bufB, reOutputsDiffer) + else: + compilerOutputTests(test, target, given, expected, r) of actionReject: - cmpMsgs(r, expected, given, test, target, extraOptions) + var given = callCompiler(expected.getCmd, test.name, test.options, + nimcache, target) + cmpMsgs(r, expected, given, test, target) -proc targetHelper(r: var TResults, test: TTest, expected: TSpec, extraOptions: string) = +proc targetHelper(r: var TResults, test: TTest, expected: TSpec, extraOptions = "") = for target in expected.targets: inc(r.total) if target notin gTargets: - r.addResult(test, target, extraOptions, "", "", reDisabled) + r.addResult(test, target, "", "", reDisabled) inc(r.skipped) elif simulate: inc count echo "testSpec count: ", count, " expected: ", expected else: let nimcache = nimcacheDir(test.name, test.options, target) - var testClone = test - testSpecHelper(r, testClone, expected, target, extraOptions, nimcache) + testSpecHelper(r, test, expected, target, nimcache, extraOptions) proc testSpec(r: var TResults, test: TTest, targets: set[TTarget] = {}) = var expected = test.spec if expected.parseErrors.len > 0: # targetC is a lie, but a parameter is required - r.addResult(test, targetC, "", "", expected.parseErrors, reInvalidSpec) + r.addResult(test, targetC, "", expected.parseErrors, reInvalidSpec) inc(r.total) return + if not checkDisabled(r, test): return expected.targets.incl targets # still no target specified at all @@ -551,13 +515,45 @@ proc testSpec(r: var TResults, test: TTest, targets: set[TTarget] = {}) = for m in test.spec.matrix: targetHelper(r, test, expected, m) else: - targetHelper(r, test, expected, "") + targetHelper(r, test, expected) -proc testSpecWithNimcache(r: var TResults, test: TTest; nimcache: string) {.used.} = +proc testSpecWithNimcache(r: var TResults, test: TTest; nimcache: string) = + if not checkDisabled(r, test): return for target in test.spec.targets: inc(r.total) - var testClone = test - testSpecHelper(r, testClone, test.spec, target, "", nimcache) + testSpecHelper(r, test, test.spec, target, nimcache) + +proc testC(r: var TResults, test: TTest, action: TTestAction) = + # runs C code. Doesn't support any specs, just goes by exit code. + if not checkDisabled(r, test): return + + let tname = test.name.addFileExt(".c") + inc(r.total) + maybeStyledEcho "Processing ", fgCyan, extractFilename(tname) + var given = callCCompiler(getCmd(TSpec()), test.name & ".c", test.options, targetC) + if given.err != reSuccess: + r.addResult(test, targetC, "", given.msg, given.err) + elif action == actionRun: + let exeFile = changeFileExt(test.name, ExeExt) + var (_, exitCode) = execCmdEx(exeFile, options = {poStdErrToStdOut, poUsePath}) + if exitCode != 0: given.err = reExitcodesDiffer + if given.err == reSuccess: inc(r.passed) + +proc testExec(r: var TResults, test: TTest) = + # runs executable or script, just goes by exit code + if not checkDisabled(r, test): return + + inc(r.total) + let (outp, errC) = execCmdEx(test.options.strip()) + var given: TSpec + if errC == 0: + given.err = reSuccess + else: + given.err = reExitcodesDiffer + given.msg = outp.string + + if given.err == reSuccess: inc(r.passed) + r.addResult(test, targetC, "", given.msg, given.err) proc makeTest(test, options: string, cat: Category): TTest = result.cat = cat @@ -566,17 +562,19 @@ proc makeTest(test, options: string, cat: Category): TTest = result.spec = parseSpec(addFileExt(test, ".nim")) result.startTime = epochTime() -proc makeRawTest(test, options: string, cat: Category): TTest {.used.} = +proc makeRawTest(test, options: string, cat: Category): TTest = result.cat = cat result.name = test result.options = options result.spec = initSpec(addFileExt(test, ".nim")) + result.startTime = epochTime() result.spec.action = actionCompile result.spec.targets = {getTestSpecTarget()} - result.startTime = epochTime() # TODO: fix these files const disabledFilesDefault = @[ + "LockFreeHash.nim", + "sharedstrings.nim", "tableimpl.nim", "setimpl.nim", "hashcommon.nim", @@ -611,10 +609,13 @@ proc loadSkipFrom(name: string): seq[string] = # used by `nlvm` (at least) for line in lines(name): let sline = line.strip() - if sline.len > 0 and not sline.startsWith('#'): + if sline.len > 0 and not sline.startsWith("#"): result.add sline proc main() = + os.putEnv "NIMTEST_COLOR", "never" + os.putEnv "NIMTEST_OUTPUT_LVL", "PRINT_FAILURES" + azure.init() backend.open() var optPrintResults = false @@ -622,60 +623,42 @@ proc main() = var targetsStr = "" var isMainProcess = true var skipFrom = "" + var useMegatest = true var p = initOptParser() p.next() while p.kind in {cmdLongOption, cmdShortOption}: - case p.key.normalize - of "print": optPrintResults = true - of "verbose": optVerbose = true + case p.key.string.normalize + of "print", "verbose": optPrintResults = true of "failing": optFailing = true - of "pedantic": discard # deadcode refs https://github.com/nim-lang/Nim/issues/16731 + of "pedantic": discard "now always enabled" of "targets": - targetsStr = p.val + targetsStr = p.val.string gTargets = parseTargets(targetsStr) - targetsSet = true of "nim": - compilerPrefix = addFileExt(p.val.absolutePath, ExeExt) + compilerPrefix = addFileExt(p.val.string, ExeExt) of "directory": - setCurrentDir(p.val) + setCurrentDir(p.val.string) of "colors": - case p.val: + case p.val.string: of "on": useColors = true of "off": useColors = false else: quit Usage - of "batch": - testamentData0.batchArg = p.val - if p.val != "_" and p.val.len > 0 and p.val[0] in {'0'..'9'}: - let s = p.val.split("_") - doAssert s.len == 2, $(p.val, s) - testamentData0.testamentBatch = s[0].parseInt - testamentData0.testamentNumBatch = s[1].parseInt - doAssert testamentData0.testamentNumBatch > 0 - doAssert testamentData0.testamentBatch >= 0 and testamentData0.testamentBatch < testamentData0.testamentNumBatch of "simulate": simulate = true of "megatest": - case p.val: + case p.val.string: of "on": useMegatest = true of "off": useMegatest = false else: quit Usage - of "valgrind": - case p.val: - of "on": - valgrindEnabled = true - of "off": - valgrindEnabled = false - else: - quit Usage of "backendlogging": - case p.val: + case p.val.string: of "on": backendLogging = true of "off": @@ -683,39 +666,36 @@ proc main() = else: quit Usage of "skipfrom": - skipFrom = p.val + skipFrom = p.val.string else: quit Usage p.next() if p.kind != cmdArgument: quit Usage - var action = p.key.normalize + var action = p.key.string.normalize p.next() var r = initResults() case action of "all": - #processCategory(r, Category"megatest", p.cmdLineRest, testsDir, runJoinableTests = false) + #processCategory(r, Category"megatest", p.cmdLineRest.string, testsDir, runJoinableTests = false) - var myself = quoteShell(getAppFilename()) + var myself = quoteShell(findExe("testament" / "testament")) if targetsStr.len > 0: myself &= " " & quoteShell("--targets:" & targetsStr) myself &= " " & quoteShell("--nim:" & compilerPrefix) - if testamentData0.batchArg.len > 0: - myself &= " --batch:" & testamentData0.batchArg if skipFrom.len > 0: myself &= " " & quoteShell("--skipFrom:" & skipFrom) var cats: seq[string] - let rest = if p.cmdLineRest.len > 0: " " & p.cmdLineRest else: "" + let rest = if p.cmdLineRest.string.len > 0: " " & p.cmdLineRest.string else: "" for kind, dir in walkDir(testsDir): assert testsDir.startsWith(testsDir) let cat = dir[testsDir.len .. ^1] if kind == pcDir and cat notin ["testdata", "nimcache"]: cats.add cat - if isNimRepoTests(): - cats.add AdditionalCategories + cats.add AdditionalCategories if useMegatest: cats.add MegaTestCat var cmds: seq[string] @@ -724,20 +704,21 @@ proc main() = cmds.add(myself & runtype & quoteShell(cat) & rest) proc progressStatus(idx: int) = - echo "progress[all]: $1/$2 starting: cat: $3" % [$idx, $cats.len, cats[idx]] + echo "progress[all]: i: " & $idx & " / " & $cats.len & " cat: " & cats[idx] if simulate: skips = loadSkipFrom(skipFrom) for i, cati in cats: progressStatus(i) - processCategory(r, Category(cati), p.cmdLineRest, testsDir, runJoinableTests = false) + processCategory(r, Category(cati), p.cmdLineRest.string, testsDir, runJoinableTests = false) else: - addExitProc azure.finalize + addQuitProc azure.finalize quit osproc.execProcesses(cmds, {poEchoCmd, poStdErrToStdOut, poUsePath, poParentStreams}, beforeRunEvent = progressStatus) of "c", "cat", "category": skips = loadSkipFrom(skipFrom) var cat = Category(p.key) - processCategory(r, cat, p.cmdLineRest, testsDir, runJoinableTests = true) + p.next + processCategory(r, cat, p.cmdLineRest.string, testsDir, runJoinableTests = true) of "pcat": skips = loadSkipFrom(skipFrom) # 'pcat' is used for running a category in parallel. Currently the only @@ -746,15 +727,21 @@ proc main() = isMainProcess = false var cat = Category(p.key) p.next - processCategory(r, cat, p.cmdLineRest, testsDir, runJoinableTests = false) + processCategory(r, cat, p.cmdLineRest.string, testsDir, runJoinableTests = false) of "p", "pat", "pattern": skips = loadSkipFrom(skipFrom) let pattern = p.key p.next - processPattern(r, pattern, p.cmdLineRest, simulate) + processPattern(r, pattern, p.cmdLineRest.string, simulate) of "r", "run": - let (cat, path) = splitTestFile(p.key) - processSingleTest(r, cat.Category, p.cmdLineRest, path, gTargets, targetsSet) + var subPath = p.key.string + if subPath.isAbsolute: subPath = subPath.relativePath(getCurrentDir()) + # at least one directory is required in the path, to use as a category name + let pathParts = split(subPath, {DirSep, AltSep}) + # "stdlib/nre/captures.nim" -> "stdlib" + "nre/captures.nim" + let cat = Category(pathParts[0]) + subPath = joinPath(pathParts[1..^1]) + processSingleTest(r, cat, p.cmdLineRest.string, subPath) of "html": generateHtml(resultsFile, optFailing) else: diff --git a/testament/testament.nim.cfg b/testament/testament.nim.cfg index c97284129..69f044554 100644 --- a/testament/testament.nim.cfg +++ b/testament/testament.nim.cfg @@ -1,6 +1,2 @@ -# don't move this file without updating the logic in `isNimRepoTests` - path = "$nim" # For compiler/nodejs -d:ssl # For azure -# my SSL doesn't have this feature and I don't care: --d:nimDisableCertificateValidation diff --git a/testament/tests/shouldfail/tccodecheck.nim b/testament/tests/shouldfail/tccodecheck.nim index 477da1e23..a8d216a5b 100644 --- a/testament/tests/shouldfail/tccodecheck.nim +++ b/testament/tests/shouldfail/tccodecheck.nim @@ -1,5 +1,5 @@ discard """ - ccodecheck: "baz" +ccodecheck: "baz" """ proc foo(): void {.exportc: "bar".}= diff --git a/testament/tests/shouldfail/tcolumn.nim b/testament/tests/shouldfail/tcolumn.nim index 809ddec74..89482e673 100644 --- a/testament/tests/shouldfail/tcolumn.nim +++ b/testament/tests/shouldfail/tcolumn.nim @@ -1,7 +1,7 @@ discard """ - errormsg: "undeclared identifier: 'undeclared'" - line: 9 - column: 7 +errormsg: "undeclared identifier: 'undeclared'" +line: 8 +column: 7 """ # test should fail because the line directive is wrong diff --git a/testament/tests/shouldfail/terrormsg.nim b/testament/tests/shouldfail/terrormsg.nim index 6c130d107..dbbdf5021 100644 --- a/testament/tests/shouldfail/terrormsg.nim +++ b/testament/tests/shouldfail/terrormsg.nim @@ -1,7 +1,7 @@ discard """ - errormsg: "wrong error message" - line: 9 - column: 6 +errormsg: "wrong error message" +line: 8 +column: 6 """ # test should fail because the line directive is wrong diff --git a/testament/tests/shouldfail/texitcode1.nim b/testament/tests/shouldfail/texitcode1.nim index 605f046db..1b38b4f2e 100644 --- a/testament/tests/shouldfail/texitcode1.nim +++ b/testament/tests/shouldfail/texitcode1.nim @@ -1,3 +1,3 @@ discard """ - exitcode: 1 +exitcode: 1 """ diff --git a/testament/tests/shouldfail/tfile.nim b/testament/tests/shouldfail/tfile.nim index b40a4f44f..a6c2ad359 100644 --- a/testament/tests/shouldfail/tfile.nim +++ b/testament/tests/shouldfail/tfile.nim @@ -1,6 +1,6 @@ discard """ - errormsg: "undeclared identifier: 'undefined'" - file: "notthisfile.nim" +errmsg: "undeclared identifier: 'undefined'" +file: "notthisfile.nim" """ echo undefined diff --git a/testament/tests/shouldfail/tline.nim b/testament/tests/shouldfail/tline.nim index fe782eb03..f7a09875c 100644 --- a/testament/tests/shouldfail/tline.nim +++ b/testament/tests/shouldfail/tline.nim @@ -1,7 +1,7 @@ discard """ - errormsg: "undeclared identifier: 'undeclared'" - line: 10 - column: 6 +errormsg: "undeclared identifier: 'undeclared'" +line: 9 +column: 6 """ # test should fail because the line directive is wrong diff --git a/testament/tests/shouldfail/tmaxcodesize.nim b/testament/tests/shouldfail/tmaxcodesize.nim index 92022ee97..9879e4181 100644 --- a/testament/tests/shouldfail/tmaxcodesize.nim +++ b/testament/tests/shouldfail/tmaxcodesize.nim @@ -1,5 +1,5 @@ discard """ - maxcodesize: 1 +maxcodesize: 1 """ echo "Hello World" diff --git a/testament/tests/shouldfail/tmsg.nim b/testament/tests/shouldfail/tmsg.nim new file mode 100644 index 000000000..4ad17fa95 --- /dev/null +++ b/testament/tests/shouldfail/tmsg.nim @@ -0,0 +1,6 @@ +discard """ +msg: "Hello World" +""" + +static: + echo "something else" diff --git a/testament/tests/shouldfail/tnimout.nim b/testament/tests/shouldfail/tnimout.nim index 0a65bfb70..c0e332053 100644 --- a/testament/tests/shouldfail/tnimout.nim +++ b/testament/tests/shouldfail/tnimout.nim @@ -1,6 +1,6 @@ discard """ - nimout: "Hello World!" - action: compile +nimout: "Hello World!" +action: compile """ static: diff --git a/testament/tests/shouldfail/tnimoutfull.nim b/testament/tests/shouldfail/tnimoutfull.nim deleted file mode 100644 index 4fc93f6d2..000000000 --- a/testament/tests/shouldfail/tnimoutfull.nim +++ /dev/null @@ -1,14 +0,0 @@ -discard """ - nimout: ''' -msg1 -msg2 -''' - action: compile - nimoutFull: true -""" - -# should fail because `msg3` is not in nimout and `nimoutFill: true` was given -static: - echo "msg1" - echo "msg2" - echo "msg3" diff --git a/testament/tests/shouldfail/toutput.nim b/testament/tests/shouldfail/toutput.nim index eaf9e8652..ac0bc7a46 100644 --- a/testament/tests/shouldfail/toutput.nim +++ b/testament/tests/shouldfail/toutput.nim @@ -1,7 +1,7 @@ discard """ - output: ''' - done - ''' +output: ''' +done +''' """ echo "broken" diff --git a/testament/tests/shouldfail/toutputsub.nim b/testament/tests/shouldfail/toutputsub.nim index 47324ecee..7cc51ee8d 100644 --- a/testament/tests/shouldfail/toutputsub.nim +++ b/testament/tests/shouldfail/toutputsub.nim @@ -1,5 +1,5 @@ discard """ - outputsub: "something else" +outputsub: "something else" """ echo "Hello World!" diff --git a/testament/tests/shouldfail/treject.nim b/testament/tests/shouldfail/treject.nim deleted file mode 100644 index 1e7258f70..000000000 --- a/testament/tests/shouldfail/treject.nim +++ /dev/null @@ -1,7 +0,0 @@ -discard """ - action: "reject" -""" - -# Because we set action="reject", we expect this line not to compile. But the -# line does compile, therefore the test fails. -assert true diff --git a/testament/tests/shouldfail/tsortoutput.nim b/testament/tests/shouldfail/tsortoutput.nim index 69dfbc0a0..4ce9ce26d 100644 --- a/testament/tests/shouldfail/tsortoutput.nim +++ b/testament/tests/shouldfail/tsortoutput.nim @@ -1,6 +1,6 @@ discard """ - sortoutput: true - output: ''' +sortoutput: true +output: ''' 2 1 ''' diff --git a/testament/tests/shouldfail/tvalgrind.nim b/testament/tests/shouldfail/tvalgrind.nim deleted file mode 100644 index d551ff12e..000000000 --- a/testament/tests/shouldfail/tvalgrind.nim +++ /dev/null @@ -1,17 +0,0 @@ -discard """ - valgrind: true - cmd: "nim $target --gc:arc -d:useMalloc $options $file" -""" - -# this is the same check used by testament/specs.nim whether or not valgrind -# tests are supported -when defined(linux) and sizeof(int) == 8: - # discarding this allocation will cause valgrind to fail (which is what we - # want), but valgrind only runs on 64-bit Linux machines... - discard alloc(1) -else: - # ...so on all other OS/architectures, simulate any non-zero exit code to - # mimic how valgrind would have failed on this test. We cannot use things like - # `disabled: "freebsd"` in the Testament configs above or else the tests will - # be SKIP-ed rather than FAIL-ed - quit(1) # choose 1 to match valgrind's `--error-exit=1`, but could be anything diff --git a/tests/alias/t19349.nim b/tests/alias/t19349.nim deleted file mode 100644 index 1e1e58264..000000000 --- a/tests/alias/t19349.nim +++ /dev/null @@ -1,19 +0,0 @@ -discard """ - action: "compile" -""" - -type - Vec3[T: SomeNumber] = object - arr: array[3, T] - -var - cfloatArr: array[3, array[3, cfloat]] - cfloatSeq = newSeq[Vec3[cfloat]]() -for row in cfloatArr: - cfloatSeq.add(Vec3[float32](arr: [row[0], row[1], row[2]])) - -var - cuintArr: array[3, array[3, cuint]] - cuintSeq = newSeq[Vec3[cuint]]() -for row in cuintArr: - cuintSeq.add(Vec3[uint32](arr: [row[0], row[1], row[2]])) diff --git a/tests/align/talign.nim b/tests/align/talign.nim index 3b8f6b4df..e0503cc70 100644 --- a/tests/align/talign.nim +++ b/tests/align/talign.nim @@ -1,6 +1,6 @@ discard """ ccodeCheck: "\\i @'NIM_ALIGN(128) NI mylocal1' .*" -targets: "c cpp" +target: "c cpp" output: "align ok" """ diff --git a/tests/ambsym/tambprocvar.nim b/tests/ambsym/tambprocvar.nim deleted file mode 100644 index 2a9921bad..000000000 --- a/tests/ambsym/tambprocvar.nim +++ /dev/null @@ -1,19 +0,0 @@ -discard """ - action: reject - cmd: "nim check $file" - nimout: ''' -tambprocvar.nim(15, 11) Error: ambiguous identifier 'foo' -- use one of the following: - tambprocvar.foo: proc (x: int){.noSideEffect, gcsafe.} - tambprocvar.foo: proc (x: float){.noSideEffect, gcsafe.} -''' -""" - -block: - proc foo(x: int) = discard - proc foo(x: float) = discard - - let x = foo - -block: - let x = `+` #[tt.Error - ^ ambiguous identifier '+' -- use one of the following:]# diff --git a/tests/ambsym/tambsym3.nim b/tests/ambsym/tambsym3.nim index e50f9c461..0558517bd 100644 --- a/tests/ambsym/tambsym3.nim +++ b/tests/ambsym/tambsym3.nim @@ -1,15 +1,12 @@ discard """ - errormsg: "ambiguous enum field" + errormsg: "ambiguous identifier" file: "tambsym3.nim" - line: 14 + line: 11 """ # Test ambiguous symbols import mambsym1, times -{.hint[AmbiguousEnum]: on.} -{.hintAsError[AmbiguousEnum]: on.} - var v = mDec #ERROR_MSG ambiguous identifier diff --git a/tests/arc/amodule.nim b/tests/arc/amodule.nim deleted file mode 100644 index 2b4204a66..000000000 --- a/tests/arc/amodule.nim +++ /dev/null @@ -1,21 +0,0 @@ -# bug #14219 -var vectors = @["a", "b", "c", "d", "e"] - -iterator testVectors(): string = - for vector in vectors: - yield vector - -var r = "" -for item in testVectors(): - r.add item -echo r - -# bug #12990 -iterator test(): int {.closure.} = - yield 0 - -let x = test -while true: - let val = x() - if finished(x): break - echo val diff --git a/tests/arc/bmodule.nim b/tests/arc/bmodule.nim deleted file mode 100644 index 70c2cc645..000000000 --- a/tests/arc/bmodule.nim +++ /dev/null @@ -1,4 +0,0 @@ -import cmodule - -for i in @[1, 2, 3].cycle(): - echo i diff --git a/tests/arc/cmodule.nim b/tests/arc/cmodule.nim deleted file mode 100644 index 6c6e6c0fa..000000000 --- a/tests/arc/cmodule.nim +++ /dev/null @@ -1,4 +0,0 @@ -iterator cycle*[T](s: openArray[T]): T = - let s = @s - for x in s: - yield x diff --git a/tests/arc/dmodule.nim b/tests/arc/dmodule.nim deleted file mode 100644 index 455ec7084..000000000 --- a/tests/arc/dmodule.nim +++ /dev/null @@ -1,23 +0,0 @@ -type - MinKind* = enum - minDictionary - minBool - MinValue* = object - case kind*: MinKind - of minDictionary: - symbols: seq[MinOperator] - else: discard - MinOperator = object - -# remove this inline pragma to make it compile -proc `$`*(a: MinValue): string {.inline.} = - case a.kind - of minDictionary: - result = "hello" - for i in a.symbols: - result = "hello" - else: discard - -proc parseMinValue*(): MinValue = - # or this echo - echo result diff --git a/tests/arc/nim.cfg b/tests/arc/nim.cfg deleted file mode 100644 index 7c148b797..000000000 --- a/tests/arc/nim.cfg +++ /dev/null @@ -1 +0,0 @@ ---sinkInference:on diff --git a/tests/arc/t14383.nim b/tests/arc/t14383.nim deleted file mode 100644 index 96b505166..000000000 --- a/tests/arc/t14383.nim +++ /dev/null @@ -1,217 +0,0 @@ -discard """ - cmd: "nim c --gc:arc $file" - output: ''' -hello -hello -@["a", "b"] ---------------------- -plain: -destroying: ('first', 42) -destroying: ('second', 20) -destroying: ('third', 12) - -Option[T]: -destroying: ('first', 42) -destroying: ('second', 20) -destroying: ('third', 12) - -seq[T]: -destroying: ('first', 42) -destroying: ('second', 20) -destroying: ('third', 12) - -1 1 -''' -""" - -import dmodule - -var val = parseMinValue() -if val.kind == minDictionary: - echo val - -#------------------------------------------------------------------------------ -# Issue #15238 -#------------------------------------------------------------------------------ - -proc sinkArg(x: sink seq[string]) = - discard - -proc varArg(lst: var seq[string]) = - sinkArg(lst) - -var x = @["a", "b"] -varArg(x) -echo x - - -#------------------------------------------------------------------------------ -# Issue #15286 -#------------------------------------------------------------------------------ - -import std/os -discard getFileInfo(".") - - -#------------------------------------------------------------------------------ -# Issue #15707 -#------------------------------------------------------------------------------ - -type - JVMObject = ref object -proc freeJVMObject(o: JVMObject) = - discard -proc fromJObject(T: typedesc[JVMObject]): T = - result.new(cast[proc(r: T) {.nimcall.}](freeJVMObject)) - -discard JVMObject.fromJObject() - - -#------------------------------------------------------------------------------ -# Issue #15910 -#------------------------------------------------------------------------------ - -import options - -type - Thing = object - name: string - age: int - -proc `=destroy`(thing: var Thing) = - if thing.name != "": - echo "destroying: ('", thing.name, "', ", thing.age, ")" - `=destroy`(thing.name) - `=destroy`(thing.age) - -proc plain() = - var t = Thing(name: "first", age: 42) - t = Thing(name: "second", age: 20) - t = Thing() - let u = Thing(name: "third", age: 12) - -proc optionT() = - var t = Thing(name: "first", age: 42).some - t = Thing(name: "second", age: 20).some - t = none(Thing) - let u = Thing(name: "third", age: 12).some - -proc seqT() = - var t = @[Thing(name: "first", age: 42)] - t = @[Thing(name: "second", age: 20)] - t = @[] - let u = @[Thing(name: "third", age: 12)] - -echo "---------------------" -echo "plain:" -plain() -echo() - -echo "Option[T]:" -optionT() -echo() - -echo "seq[T]:" -seqT() -echo() - - -#------------------------------------------------------------------------------ -# Issue #16120, const seq into sink -#------------------------------------------------------------------------------ - -proc main = - let avals = @[@[1.0'f32, 4.0, 7.0, 10.0]] - let rankdef = avals - echo avals.len, " ", rankdef.len - -main() - - -#------------------------------------------------------------------------------ -# Issue #16722, ref on distinct type, wrong destructors called -#------------------------------------------------------------------------------ - -type - Obj = object of RootObj - ObjFinal = object - ObjRef = ref Obj - ObjFinalRef = ref ObjFinal - D = distinct Obj - DFinal = distinct ObjFinal - DRef = ref D - DFinalRef = ref DFinal - -proc `=destroy`(o: var Obj) = - doAssert false, "no Obj is constructed in this sample" - -proc `=destroy`(o: var ObjFinal) = - doAssert false, "no ObjFinal is constructed in this sample" - -var dDestroyed: int -proc `=destroy`(d: var D) = - dDestroyed.inc - -proc `=destroy`(d: var DFinal) = - dDestroyed.inc - -func newD(): DRef = - DRef ObjRef() - -func newDFinal(): DFinalRef = - DFinalRef ObjFinalRef() - -proc testRefs() = - discard newD() - discard newDFinal() - -testRefs() - -doAssert(dDestroyed == 2) - - -#------------------------------------------------------------------------------ -# Issue #16185, complex self-assingment elimination -#------------------------------------------------------------------------------ - -type - CpuStorage*[T] = ref CpuStorageObj[T] - CpuStorageObj[T] = object - size*: int - raw_buffer*: ptr UncheckedArray[T] - Tensor[T] = object - buf*: CpuStorage[T] - TestObject = object - x: Tensor[float] - -proc `=destroy`[T](s: var CpuStorageObj[T]) = - if s.raw_buffer != nil: - s.raw_buffer.deallocShared() - s.size = 0 - s.raw_buffer = nil - -proc `=`[T](a: var CpuStorageObj[T]; b: CpuStorageObj[T]) {.error.} - -proc allocCpuStorage[T](s: var CpuStorage[T], size: int) = - new(s) - s.raw_buffer = cast[ptr UncheckedArray[T]](allocShared0(sizeof(T) * size)) - s.size = size - -proc newTensor[T](size: int): Tensor[T] = - allocCpuStorage(result.buf, size) - -proc `[]`[T](t: Tensor[T], idx: int): T = t.buf.raw_buffer[idx] -proc `[]=`[T](t: Tensor[T], idx: int, val: T) = t.buf.raw_buffer[idx] = val - -proc toTensor[T](s: seq[T]): Tensor[T] = - result = newTensor[T](s.len) - for i, x in s: - result[i] = x - -proc main2() = - var t: TestObject - t.x = toTensor(@[1.0, 2, 3, 4]) - t.x = t.x - doAssert(t.x.buf != nil) # self-assignment above should be eliminated - -main2() diff --git a/tests/arc/t14472.nim b/tests/arc/t14472.nim deleted file mode 100644 index 4ef661161..000000000 --- a/tests/arc/t14472.nim +++ /dev/null @@ -1,43 +0,0 @@ -discard """ - valgrind: true - cmd: "nim cpp --gc:arc -d:useMalloc --deepcopy:on $file" -""" - -type - ImportMaterial* = object - # Adding a field here makes the problem go away. - - Mesh* = object - vertices: seq[float32] - material: ImportMaterial - - ImportedScene* = object - meshes*: seq[Mesh] - -proc bork() : ImportedScene = - var mats: seq[ImportMaterial] - - setLen(mats, 1) - add(result.meshes, Mesh(material: mats[0])) - -var s = bork() - - -#------------------------------------------------------------------------ -# issue #15543 - -import tables - -type - cdbl {.importc: "double".} = object - - MyObject = ref object of RootObj - y: Table[string, cdbl] - - -proc test = - var x = new(MyObject) - -test() - - diff --git a/tests/arc/t14864.nim b/tests/arc/t14864.nim deleted file mode 100644 index f59b14d2c..000000000 --- a/tests/arc/t14864.nim +++ /dev/null @@ -1,5 +0,0 @@ -discard """ - cmd: "nim c --gc:arc $file" -""" - -import bmodule diff --git a/tests/arc/t15909.nim b/tests/arc/t15909.nim deleted file mode 100644 index f25c89daf..000000000 --- a/tests/arc/t15909.nim +++ /dev/null @@ -1,16 +0,0 @@ -discard """ - action: run - cmd: "nim c --gc:arc $file" -""" - -proc f1() {.noreturn.} = raise newException(CatchableError, "") - -proc f2(y: int): int = - if y != 0: - y - else: - f1() - -doAssert f2(5) == 5 -doAssertRaises(CatchableError): - discard f2(0) diff --git a/tests/arc/t16033.nim b/tests/arc/t16033.nim deleted file mode 100644 index 59ed22e4d..000000000 --- a/tests/arc/t16033.nim +++ /dev/null @@ -1,10 +0,0 @@ -discard """ - targets: "c js" - matrix: "--gc:arc" -""" - -# bug #16033 -when defined js: - doAssert not compileOption("gc", "arc") -else: - doAssert compileOption("gc", "arc") diff --git a/tests/arc/t16458.nim b/tests/arc/t16458.nim deleted file mode 100644 index 6ae114287..000000000 --- a/tests/arc/t16458.nim +++ /dev/null @@ -1,6 +0,0 @@ -discard """ - matrix: "--gc:orc --d:useNimRtl" - action: "compile" -""" - -echo 134 \ No newline at end of file diff --git a/tests/arc/t16558.nim b/tests/arc/t16558.nim deleted file mode 100644 index 0dbe02b33..000000000 --- a/tests/arc/t16558.nim +++ /dev/null @@ -1,9 +0,0 @@ -discard """ - matrix: "--gc:arc" - errormsg: "expression cannot be cast to 'int'" -""" - -block: # bug #16558 - var value = "hi there" - var keepInt: int - keepInt = cast[int](value) diff --git a/tests/arc/t17025.nim b/tests/arc/t17025.nim deleted file mode 100644 index a64c59ac1..000000000 --- a/tests/arc/t17025.nim +++ /dev/null @@ -1,56 +0,0 @@ -discard """ - cmd: "nim c --gc:arc $file" - output: ''' -{"Package": {"name": "hello"}, "Author": {"name": "name", "qq": "123456789", "email": "email"}} -hello -name -123456789 -email -hello -name2 -987654321 -liame -''' -""" - -import parsecfg, streams, tables - -const cfg = """[Package] -name=hello -[Author] -name=name -qq=123456789 -email="email"""" - -proc main() = - let stream = newStringStream(cfg) - let dict = loadConfig(stream) - var pname = dict.getSectionValue("Package","name") - var name = dict.getSectionValue("Author","name") - var qq = dict.getSectionValue("Author","qq") - var email = dict.getSectionValue("Author","email") - echo dict[] - echo pname & "\n" & name & "\n" & qq & "\n" & email - stream.close() - -main() - -proc getDict(): OrderedTableRef[string, OrderedTableRef[string, string]] = - result = newOrderedTable[string, OrderedTableRef[string, string]]() - result["Package"] = newOrderedTable[string, string]() - result["Package"]["name"] = "hello" - result["Author"] = newOrderedTable[string, string]() - result["Author"]["name"] = "name2" - result["Author"]["qq"] = "987654321" - result["Author"]["email"] = "liame" - -proc main2() = - let dict = getDict() - var pname = dict.getSectionValue("Package","name") - var name = dict.getSectionValue("Author","name") - var qq = dict.getSectionValue("Author","qq") - var email = dict.getSectionValue("Author","email") - echo pname & "\n" & name & "\n" & qq & "\n" & email - -main2() - diff --git a/tests/arc/t17173.nim b/tests/arc/t17173.nim deleted file mode 100644 index 0acd886a2..000000000 --- a/tests/arc/t17173.nim +++ /dev/null @@ -1,10 +0,0 @@ -discard """ - matrix: "--gc:refc; --gc:arc" -""" - -import std/strbasics - - -var a = " vhellov " -strip(a) -doAssert a == "vhellov" diff --git a/tests/arc/t17812.nim b/tests/arc/t17812.nim deleted file mode 100644 index bcd5f3a93..000000000 --- a/tests/arc/t17812.nim +++ /dev/null @@ -1,29 +0,0 @@ -discard """ - targets: "c js" - matrix: "--gc:refc; --gc:arc" -""" - -import std/times - -block: # bug #17812 - block: - type - Task = object - cb: proc () - - proc hello() = discard - - - let t = Task(cb: hello) - - doAssert t.repr.len > 0 - - - block: - type MyObj = object - field: DateTime - - - proc `$`(o: MyObj): string = o.repr - - doAssert ($MyObj()).len > 0 diff --git a/tests/arc/t18645.nim b/tests/arc/t18645.nim deleted file mode 100644 index c5fddd4bb..000000000 --- a/tests/arc/t18645.nim +++ /dev/null @@ -1,18 +0,0 @@ -discard """ - matrix: "--gc:arc; --gc:refc" - output: ''' -1 -2 -3 -''' -""" - -proc bitTypeIdUnion() = - var bitId {.global.} = block: - 0 - inc bitId - echo bitId - -bitTypeIdUnion() -bitTypeIdUnion() -bitTypeIdUnion() diff --git a/tests/arc/t18971.nim b/tests/arc/t18971.nim deleted file mode 100644 index 9b587d956..000000000 --- a/tests/arc/t18971.nim +++ /dev/null @@ -1,10 +0,0 @@ -discard """ - cmd: "nim c --gc:arc $file" -""" - -type MyObj = ref object - -var o = MyObj() -proc x: var MyObj = o - -var o2 = x() diff --git a/tests/arc/t19231.nim b/tests/arc/t19231.nim deleted file mode 100644 index 40fcf277c..000000000 --- a/tests/arc/t19231.nim +++ /dev/null @@ -1,18 +0,0 @@ -discard """ - matrix: "--mm:orc" - targets: "c cpp" -""" - -type - Game* = ref object - -proc free*(game: Game) = - var mixNumOpened:cint = 0 - for i in 0.. 0: - let c = @[a[0] mod b[0]] - a = b - b = c - return a - -doAssert gcd(@[1], @[2]) == @[1] \ No newline at end of file diff --git a/tests/arc/t19862.nim b/tests/arc/t19862.nim deleted file mode 100644 index 6d3f57692..000000000 --- a/tests/arc/t19862.nim +++ /dev/null @@ -1,15 +0,0 @@ -discard """ - matrix: "--gc:refc; --gc:arc" -""" - -import std/widestrs - -# bug #19862 -type NewString = object - -proc len(s: NewString): int = 10 - -converter toNewString(x: WideCStringObj): NewString = discard - -let w = newWideCString("test") -doAssert len(w) == 4 diff --git a/tests/arc/t20456.nim b/tests/arc/t20456.nim deleted file mode 100644 index ace79255a..000000000 --- a/tests/arc/t20456.nim +++ /dev/null @@ -1,7 +0,0 @@ -discard """ - cmd: "nim check $file" - action: "compile" -""" - -when not defined(gcOrc): - {.error: "orc".} diff --git a/tests/arc/t20588.nim b/tests/arc/t20588.nim deleted file mode 100644 index d747c656d..000000000 --- a/tests/arc/t20588.nim +++ /dev/null @@ -1,22 +0,0 @@ -discard """ - cmd: "nim check --warnings:off --hints:off $file" - errormsg: "" - nimout: ''' -t20588.nim(20, 12) Error: illegal type conversion to 'auto' -t20588.nim(21, 14) Error: illegal type conversion to 'typed' -t20588.nim(22, 16) Error: illegal type conversion to 'untyped' -''' -""" - - - - - - - - - - -discard 0.0.auto -discard typed("abc") -discard untyped(4) diff --git a/tests/arc/t21184.nim b/tests/arc/t21184.nim deleted file mode 100644 index 91d0c42c7..000000000 --- a/tests/arc/t21184.nim +++ /dev/null @@ -1,77 +0,0 @@ -discard """ - matrix: "--mm:orc" -""" - -import std/[with] - -type - Node* {.acyclic.} = ref object of RootObj - name: string - data: pointer - children: seq[Node] - TextNode = ref object of Node - text: string - -proc fakeEcho(s: string) = - if s.len < 0: - echo s - -proc newNode[T: Node](parent: Node): T = - new result - result.data = alloc0(250) - parent.children.add(result) - -proc newRootNode(): Node = - new result - result.data = alloc0(250) - -method printNode(node: Node) {.base.} = - fakeEcho node.name - -method printNode(node: TextNode) = - procCall printNode(Node(node)) - fakeEcho node.text - -proc printChildren(node: Node) = - for child in node.children: - child.printNode() - printChildren(child) - -proc free(node: Node) = - for child in node.children: - free(child) - dealloc(node.data) - -template node(parent: Node, body: untyped): untyped = - var node = newNode[Node](parent) - with node: - body - -proc textNode(parent: Node, text: string) = - var node = newNode[TextNode](parent) - node.text = text - -template withRootNode(body: untyped): untyped = - var root = newRootNode() - root.name = "root" - with root: - body - root.printNode() - printChildren(root) - root.free() - -proc doTest() = - withRootNode: - node: - name = "child1" - node: - name = "child2" - node: - name = "child3" - textNode "Hello, world!" - - -# bug #21171 -if isMainModule: - for i in 0..100000: - doTest() diff --git a/tests/arc/t9650.nim b/tests/arc/t9650.nim deleted file mode 100644 index a8182db68..000000000 --- a/tests/arc/t9650.nim +++ /dev/null @@ -1,87 +0,0 @@ -discard """ - matrix: "--gc:arc" -""" - -import typetraits - -# bug #9650 -type - SharedPtr*[T] = object - val: ptr tuple[atomicCounter: int, value: T] - - Node*[T] = object - value: T - next: SharedPtr[Node[T]] - - ForwardList*[T] = object - first: SharedPtr[Node[T]] - -proc `=destroy`*[T](p: var SharedPtr[T]) = - if p.val != nil: - let c = atomicDec(p.val[].atomicCounter) - if c == 0: - when not supportsCopyMem(T): - `=destroy`(p.val[]) - dealloc(p.val) - p.val = nil - -proc `=`*[T](dest: var SharedPtr[T], src: SharedPtr[T]) = - if dest.val != src.val: - if dest.val != nil: - `=destroy`(dest) - if src.val != nil: - discard atomicInc(src.val[].atomicCounter) - dest.val = src.val - -proc `=sink`*[T](dest: var SharedPtr[T], src: SharedPtr[T]) = - if dest.val != nil and dest.val != src.val: - `=destroy`(dest) - dest.val = src.val - - -proc newSharedPtr*[T](val: sink T): SharedPtr[T] = - result.val = cast[type(result.val)](alloc(sizeof(result.val[]))) - reset(result.val[]) - result.val.atomicCounter = 1 - result.val.value = val - -proc isNil*[T](p: SharedPtr[T]): bool = - p.val == nil - -template `->`*[T](p: SharedPtr[T], name: untyped): untyped = - p.val.value.name - -proc createNode[T](val: T): SharedPtr[ Node[T] ]= - result = newSharedPtr(Node[T](value: val)) - -proc push_front*[T](list: var ForwardList[T], val: T) = - var newElem = createNode(val) - newElem->next = list.first - list.first = newElem - -proc pop_front*[T](list: var ForwardList[T]) = - let head = list.first - list.first = head->next - -proc toString*[T](list: ForwardList[T]): string = - result = "[" - var head = list.first - while not head.isNil: - result &= $(head->value) & ", " - head = head->next - result &= ']' - -block: - var x: ForwardList[int] - x.push_front(1) - x.push_front(2) - x.push_front(3) - - doAssert toString(x) == "[3, 2, 1, ]" - - x.pop_front() - x.pop_front() - doAssert toString(x) == "[1, ]" - - x.pop_front() - doAssert toString(x) == "[]" diff --git a/tests/arc/tamemfiles.nim b/tests/arc/tamemfiles.nim deleted file mode 100644 index 97deb489f..000000000 --- a/tests/arc/tamemfiles.nim +++ /dev/null @@ -1,110 +0,0 @@ -discard """ - output: ''' -loop 1a -loop 1b; cols: @[1, x] -loop 1c -loop 1d -loop 1a -loop 1b; cols: @[2, y] -loop 1c -loop 1d -''' - cmd: "nim c --gc:arc $file" -""" - -# bug #13596 - -import tables, memfiles, strutils, os - -type Splitr* = tuple[ repeat: bool, chrDlm: char, setDlm: set[char], n: int ] - -type csize = uint -proc cmemchr*(s: pointer, c: char, n: csize): pointer {. - importc: "memchr", header: "" .} -proc `-!`*(p, q: pointer): int {.inline.} = - (cast[int](p) -% cast[int](q)).int -proc `+!`*(p: pointer, i: int): pointer {.inline.} = - cast[pointer](cast[int](p) +% i) -proc `+!`*(p: pointer, i: uint64): pointer {.inline.} = - cast[pointer](cast[uint64](p) + i) - -proc charEq(x, c: char): bool {.inline.} = x == c - -proc initSplitr*(delim: string): Splitr = - if delim == "white": #User can use any other permutation if needed - result.repeat = true - result.chrDlm = ' ' - result.setDlm = { ' ', '\t', '\n' } - result.n = result.setDlm.card - return - for c in delim: - if c in result.setDlm: - result.repeat = true - continue - result.setDlm.incl(c) - inc(result.n) - if result.n == 1: #support n==1 test to allow memchr optimization - result.chrDlm = delim[0] - -proc hash(x: MemSlice): int = 55542 - -template defSplit[T](slc: T, fs: var seq[MemSlice], n: int, repeat: bool, - sep: untyped, nextSep: untyped, isSep: untyped) {.dirty.} = - fs.setLen(if n < 1: 16 else: n) - var b = slc.data - var eob = b +! slc.size - while repeat and eob -! b > 0 and isSep((cast[cstring](b))[0], sep): - b = b +! 1 - if b == eob: fs.setLen(0); return - var e = nextSep(b, sep, (eob -! b).csize) - while e != nil: - if n < 1: #Unbounded msplit - if result == fs.len - 1: #Expand capacity - fs.setLen(if fs.len < 512: 2*fs.len else: fs.len + 512) - elif result == n - 1: #Need 1 more slot for final field - break - fs[result].data = b - fs[result].size = e -! b - result += 1 - while repeat and eob -! e > 0 and isSep((cast[cstring](e))[1], sep): - e = e +! 1 - b = e +! 1 - if eob -! b <= 0: - b = eob - break - e = nextSep(b, sep, (eob -! b).csize) - if not repeat or eob -! b > 0: - fs[result].data = b - fs[result].size = eob -! b - result += 1 - fs.setLen(result) - -proc msplit*(s: MemSlice, fs: var seq[MemSlice], sep=' ', n=0, - repeat=false): int = - defSplit(s, fs, n, repeat, sep, cmemchr, charEq) - -proc split*(s: Splitr, line: MemSlice, cols: var seq[MemSlice], - n=0) {.inline.} = - discard msplit(line, cols, s.chrDlm, n, s.repeat) - -######################################################################## -# Using lines instead of memSlices & split instead of splitr.split seems -# to mask the arc problem, as does simplifying `Table` to `seq[char]`. - -proc load(path: string, delim=" "): Table[MemSlice, seq[char]] = - let f = memfiles.open(path) - let splitr = initSplitr(delim) - var cols: seq[MemSlice] = @[ ] # re-used seq buffer - var nwSq = newSeqOfCap[char](1) # re-used seq value - nwSq.setLen 1 - for line in memSlices(f, eat='\0'): - stderr.write "loop 1a\n" - splitr.split(line, cols, 2) - stderr.write "loop 1b; cols: ", cols, "\n" - let cs = cast[cstring](cols[0].data) - stderr.write "loop 1c\n" #..reports exception here, but - nwSq[0] = cs[0] #..actually doing out of bounds here - stderr.write "loop 1d\n" - result[cols[1]] = nwSq - -discard load(getAppDir() / "testfile.txt") diff --git a/tests/arc/tamodule.nim b/tests/arc/tamodule.nim deleted file mode 100644 index 1412e0a7c..000000000 --- a/tests/arc/tamodule.nim +++ /dev/null @@ -1,9 +0,0 @@ -discard """ - output: ''' -abcde -0 -''' - cmd: "nim c --gc:arc $file" -""" - -import amodule diff --git a/tests/arc/tarc_macro.nim b/tests/arc/tarc_macro.nim deleted file mode 100644 index ea7d279fd..000000000 --- a/tests/arc/tarc_macro.nim +++ /dev/null @@ -1,46 +0,0 @@ -import macros - -var destroyCalled = false -macro bar() = - let s = newTree(nnkAccQuoted, ident"=destroy") - # let s = ident"`=destroy`" # this would not work - result = quote do: - type Foo = object - # proc `=destroy`(a: var Foo) = destroyCalled = true # this would not work - proc `s`(a: var Foo) = destroyCalled = true - block: - let a = Foo() -bar() -doAssert destroyCalled - -# custom `op` -var destroyCalled2 = false -macro bar(ident) = - var x = 1.5 - result = quote("@") do: - type Foo = object - let `@ident` = 0 # custom op interpolated symbols need quoted (``) - proc `=destroy`(a: var Foo) = - doAssert @x == 1.5 - doAssert compiles(@x == 1.5) - let b1 = @[1,2] - let b2 = @@[1,2] - doAssert $b1 == "[1, 2]" - doAssert $b2 == "@[1, 2]" - destroyCalled2 = true - block: - let a = Foo() -bar(someident) -doAssert destroyCalled2 - -proc `&%`(x: int): int = 1 -proc `&%`(x, y: int): int = 2 - -macro bar2() = - var x = 3 - result = quote("&%") do: - var y = &%x # quoting operator - doAssert &%&%y == 1 # unary operator => need to escape - doAssert y &% y == 2 # binary operator => no need to escape - doAssert y == 3 -bar2() \ No newline at end of file diff --git a/tests/arc/tarc_orc.nim b/tests/arc/tarc_orc.nim deleted file mode 100644 index 981567350..000000000 --- a/tests/arc/tarc_orc.nim +++ /dev/null @@ -1,47 +0,0 @@ -discard """ - targets: "c cpp" - matrix: "--mm:arc; --mm:orc" -""" - -block: - type - PublicKey = array[32, uint8] - PrivateKey = array[64, uint8] - - proc ed25519_create_keypair(publicKey: ptr PublicKey; privateKey: ptr PrivateKey) = - publicKey[][0] = uint8(88) - - type - KeyPair = object - public: PublicKey - private: PrivateKey - - proc initKeyPair(): KeyPair = - ed25519_create_keypair(result.public.addr, result.private.addr) - - let keys = initKeyPair() - doAssert keys.public[0] == 88 - - -template minIndexByIt: untyped = - var other = 3 - other - -proc bug20303() = - var hlibs = @["hello", "world", "how", "are", "you"] - let res = hlibs[minIndexByIt()] - doAssert res == "are" - -bug20303() - -proc main() = # todo bug with templates - block: # bug #11267 - var a: seq[char] = block: @[] - doAssert a == @[] - # 2 - proc b: seq[string] = - discard - @[] - doAssert b() == @[] -static: main() -main() diff --git a/tests/arc/tarcmisc.nim b/tests/arc/tarcmisc.nim deleted file mode 100644 index a03da6211..000000000 --- a/tests/arc/tarcmisc.nim +++ /dev/null @@ -1,560 +0,0 @@ -discard """ - output: ''' -=destroy called -123xyzabc -destroyed: false -destroyed: false -destroyed2: false -destroyed2: false -destroying variable: 2 -destroying variable: 1 -whiley ends :( -1 -(x: "0") -(x: "1") -(x: "2") -(x: "3") -(x: "4") -(x: "5") -(x: "6") -(x: "7") -(x: "8") -(x: "9") -(x: "10") -0 -new line before - @['a'] -new line after - @['a'] -finalizer -aaaaa -hello -true -copying -123 -42 -ok -destroying variable: 20 -destroying variable: 10 -closed -''' - cmd: "nim c --gc:arc --deepcopy:on -d:nimAllocPagesViaMalloc $file" -""" - -# bug #9401 - -type - MyObj = object - len: int - data: ptr UncheckedArray[float] - -proc `=destroy`*(m: var MyObj) = - - echo "=destroy called" - - if m.data != nil: - deallocShared(m.data) - m.data = nil - -type - MyObjDistinct = distinct MyObj - -proc `=copy`*(m: var MyObj, m2: MyObj) = - if m.data == m2.data: return - if m.data != nil: - `=destroy`(m) - m.len = m2.len - if m.len > 0: - m.data = cast[ptr UncheckedArray[float]](allocShared(sizeof(float) * m.len)) - copyMem(m.data, m2.data, sizeof(float) * m.len) - - -proc `=sink`*(m: var MyObj, m2: MyObj) = - if m.data != m2.data: - if m.data != nil: - `=destroy`(m) - m.len = m2.len - m.data = m2.data - -proc newMyObj(len: int): MyObj = - result.len = len - result.data = cast[ptr UncheckedArray[float]](allocShared(sizeof(float) * len)) - -proc newMyObjDistinct(len: int): MyObjDistinct = - MyObjDistinct(newMyObj(len)) - -proc fooDistinct = - doAssert newMyObjDistinct(2).MyObj.len == 2 - -fooDistinct() - - -proc takeSink(x: sink string): bool = true - -proc b(x: sink string): string = - if takeSink(x): - return x & "abc" - -proc bbb(inp: string) = - let y = inp & "xyz" - echo b(y) - -bbb("123") - - -# bug #13691 -type Variable = ref object - value: int - -proc `=destroy`(self: var typeof(Variable()[])) = - echo "destroying variable: ",self.value - -proc newVariable(value: int): Variable = - result = Variable() - result.value = value - #echo "creating variable: ",result.value - -proc test(count: int) = - var v {.global.} = newVariable(10) - - var count = count - 1 - if count == 0: return - - test(count) - echo "destroyed: ", v.isNil - -test(3) - -proc test2(count: int) = - block: #XXX: Fails with block currently - var v {.global.} = newVariable(20) - - var count = count - 1 - if count == 0: return - - test2(count) - echo "destroyed2: ", v.isNil - -test2(3) - -proc whiley = - var a = newVariable(1) - while true: - var b = newVariable(2) - if true: raise newException(CatchableError, "test") - -try: - whiley() -except CatchableError: - echo "whiley ends :(" - -#------------------------------------------------------------------------------ -# issue #13810 - -import streams - -type - A = ref AObj - AObj = object of RootObj - io: Stream - B = ref object of A - x: int - -proc `=destroy`(x: var AObj) = - close(x.io) - echo "closed" - -var x = B(io: newStringStream("thestream")) - - -#------------------------------------------------------------------------------ -# issue #14003 - -proc cryptCTR*(nonce: var openArray[char]) = - nonce[1] = 'A' - -proc main() = - var nonce1 = "0123456701234567" - cryptCTR(nonce1) - doAssert(nonce1 == "0A23456701234567") - var nonce2 = "01234567" - cryptCTR(nonce2.toOpenArray(0, nonce2.len-1)) - doAssert(nonce2 == "0A234567") - -main() - -# bug #14079 -import std/algorithm - -let - n = @["c", "b"] - q = @[("c", "2"), ("b", "1")] - -doAssert n.sortedByIt(it) == @["b", "c"], "fine" -doAssert q.sortedByIt(it[0]) == @[("b", "1"), ("c", "2")], "fails under arc" - - -#------------------------------------------------------------------------------ -# issue #14236 - -type - MyType = object - a: seq[int] - -proc re(x: static[string]): static MyType = - MyType() - -proc match(inp: string, rg: static MyType) = - doAssert rg.a.len == 0 - -match("ac", re"a(b|c)") - -#------------------------------------------------------------------------------ -# issue #14243 - -type - Game* = ref object - -proc free*(game: Game) = - let a = 5 - -proc newGame*(): Game = - new(result, free) - -var game*: Game - - -#------------------------------------------------------------------------------ -# issue #14333 - -type - SimpleLoop = object - - Lsg = object - loops: seq[ref SimpleLoop] - root: ref SimpleLoop - -var lsg: Lsg -lsg.loops.add lsg.root -echo lsg.loops.len - -# bug #14495 -type - Gah = ref object - x: string - -proc bug14495 = - var owners: seq[Gah] - for i in 0..10: - owners.add Gah(x: $i) - - var x: seq[Gah] - for i in 0..10: - x.add owners[i] - - for i in 0..100: - setLen(x, 0) - setLen(x, 10) - - for i in 0..x.len-1: - if x[i] != nil: - echo x[i][] - - for o in owners: - echo o[] - -bug14495() - -# bug #14396 -type - Spinny = ref object - t: ref int - text: string - -proc newSpinny*(): Spinny = - Spinny(t: new(int), text: "hello") - -proc spinnyLoop(x: ref int, spinny: sink Spinny) = - echo x[] - -proc start*(spinny: sink Spinny) = - spinnyLoop(spinny.t, spinny) - -var spinner1 = newSpinny() -spinner1.start() - -# bug #14345 - -type - SimpleLoopB = ref object - children: seq[SimpleLoopB] - parent: SimpleLoopB - -proc addChildLoop(self: SimpleLoopB, loop: SimpleLoopB) = - self.children.add loop - -proc setParent(self: SimpleLoopB, parent: SimpleLoopB) = - self.parent = parent - self.parent.addChildLoop(self) - -var l = SimpleLoopB() -l.setParent(l) - - -# bug #14968 -import times -let currentTime = now().utc - - -# bug #14994 -import sequtils -var newLine = @['a'] -let indent = newSeq[char]() - -echo "new line before - ", newline - -newline.insert(indent, 0) - -echo "new line after - ", newline - -# bug #15044 - -type - Test = ref object - -proc test: Test = - # broken - new(result, proc(x: Test) = - echo "finalizer" - ) - -proc tdirectFinalizer = - discard test() - -tdirectFinalizer() - - -# bug #14480 -proc hello(): int = - result = 42 - -var leaves {.global.} = hello() -doAssert leaves == 42 - -# bug #15052 - -proc mutstrings = - var data = "hello" - for c in data.mitems(): - c = 'a' - echo data - -mutstrings() - -# bug #15038 - -type - Machine = ref object - hello: string - -var machineTypes: seq[tuple[factory: proc(): Machine]] - -proc registerMachine(factory: proc(): Machine) = - var mCreator = proc(): Machine = - result = factory() - - machineTypes.add((factory: mCreator)) - -proc facproc(): Machine = - result = Machine(hello: "hello") - -registerMachine(facproc) - -proc createMachine = - for machine in machineTypes: - echo machine.factory().hello - -createMachine() - -# bug #15122 - -import tables - -type - BENodeKind = enum - tkBytes, - tkList, - tkDict - - BENode = object - case kind: BENodeKind - of tkBytes: strVal: string - of tkList: listVal: seq[BENode] - of tkDict: dictVal: Table[string, BENode] - -var data = { - "examples": { - "values": BENode( - kind: tkList, - listVal: @[BENode(kind: tkBytes, strVal: "test")] - ) - }.toTable() -}.toTable() - -# For ARC listVal is empty for some reason -doAssert data["examples"]["values"].listVal[0].strVal == "test" - - - - -############################################################################### -# bug #15405 -import parsexml -const test_xml_str = "value" -var stream = newStringStream(test_xml_str) -var xml: XmlParser -open(xml, stream, "test") -var xml2 = deepCopy(xml) - -proc text_parser(xml: var XmlParser) = - var test_passed = false - while true: - xml.next() - case xml.kind - of xmlElementStart: - if xml.elementName == "B": - xml.next() - if xml.kind == xmlCharData and xml.charData == "value": - test_passed = true - - of xmlEof: break - else: discard - xml.close() - doAssert(test_passed) - -text_parser(xml) -text_parser(xml2) - -# bug #15599 -type - PixelBuffer = ref object - -proc newPixelBuffer(): PixelBuffer = - new(result) do (buffer: PixelBuffer): - echo "ok" - -discard newPixelBuffer() - - -# bug #17199 - -proc passSeq(data: seq[string]) = - # used the system.& proc initially - let wat = data & "hello" - -proc test2 = - let name = @["hello", "world"] - passSeq(name) - doAssert name == @["hello", "world"] - -static: test2() # was buggy -test2() - -proc merge(x: sink seq[string], y: sink string): seq[string] = - newSeq(result, x.len + 1) - for i in 0..x.len-1: - result[i] = move(x[i]) - result[x.len] = move(y) - -proc passSeq2(data: seq[string]) = - # used the system.& proc initially - let wat = merge(data, "hello") - -proc test3 = - let name = @["hello", "world"] - passSeq2(name) - doAssert name == @["hello", "world"] - -static: test3() # was buggy -test3() - -# bug #17712 -proc t17712 = - var ppv = new int - discard @[ppv] - var el: ref int - el = [ppv][0] - echo el != nil - -t17712() - -# bug #18030 - -type - Foo = object - n: int - -proc `=copy`(dst: var Foo, src: Foo) = - echo "copying" - dst.n = src.n - -proc `=sink`(dst: var Foo, src: Foo) = - echo "sinking" - dst.n = src.n - -var a: Foo - -proc putValue[T](n: T) - -proc useForward = - putValue(123) - -proc putValue[T](n: T) = - var b = Foo(n:n) - a = b - echo b.n - -useForward() - - -# bug #17319 -type - BrokenObject = ref object - brokenType: seq[int] - -proc use(obj: BrokenObject) = - discard - -method testMethod(self: BrokenObject) {.base.} = - iterator testMethodIter() {.closure.} = - use(self) - - var nameIterVar = testMethodIter - nameIterVar() - -let mikasa = BrokenObject() -mikasa.testMethod() - -# bug #19205 -type - InputSectionBase* = object of RootObj - relocations*: seq[int] # traced reference. string has a similar SIGSEGV. - InputSection* = object of InputSectionBase - -proc fooz(sec: var InputSectionBase) = - if sec of InputSection: # this line SIGSEGV. - echo 42 - -var sec = create(InputSection) -sec[] = InputSection(relocations: newSeq[int]()) -fooz sec[] - -block: - type - Data = ref object - id: int - proc main = - var x = Data(id: 99) - var y = x - x[] = Data(id: 778)[] - doAssert y.id == 778 - doAssert x[].id == 778 - main() diff --git a/tests/arc/tasyncawait.nim b/tests/arc/tasyncawait.nim index 91a7453cd..89e924104 100644 --- a/tests/arc/tasyncawait.nim +++ b/tests/arc/tasyncawait.nim @@ -1,10 +1,9 @@ discard """ - outputsub: "result: 5000" - cmd: "nim c --gc:orc $file" + output: "5000" + cmd: "nim c --gc:arc $file" """ -import asyncdispatch, asyncnet, nativesockets, net, strutils -from stdtest/netutils import bindAvailablePort +import asyncdispatch, asyncnet, nativesockets, net, strutils, os var msgCount = 0 @@ -40,29 +39,31 @@ proc readMessages(client: AsyncFD) {.async.} = clientCount.inc break else: - if line.startsWith("Message "): + if line.startswith("Message "): msgCount.inc else: doAssert false -proc createServer(server: AsyncFD) {.async.} = +proc createServer(port: Port) {.async.} = + var server = createAsyncNativeSocket() + block: + var name: Sockaddr_in + name.sin_family = typeof(name.sin_family)(toInt(AF_INET)) + name.sin_port = htons(uint16(port)) + name.sin_addr.s_addr = htonl(INADDR_ANY) + if bindAddr(server.SocketHandle, cast[ptr SockAddr](addr(name)), + sizeof(name).Socklen) < 0'i32: + raiseOSError(osLastError()) + discard server.SocketHandle.listen() while true: asyncCheck readMessages(await accept(server)) -proc main = - let server = createAsyncNativeSocket() - let port = bindAvailablePort(server.SocketHandle) - asyncCheck createServer(server) - asyncCheck launchSwarm(port) - while true: - poll() - if clientCount == swarmSize: break +asyncCheck createServer(Port(10335)) +asyncCheck launchSwarm(Port(10335)) +while true: + poll() + if clientCount == swarmSize: break -let mem = getOccupiedMem() -main() - -doAssert msgCount == swarmSize * messagesToSend -echo "result: ", msgCount -GC_fullCollect() -echo "memory: ", formatSize(getOccupiedMem() - mem) +assert msgCount == swarmSize * messagesToSend +echo msgCount diff --git a/tests/arc/tasyncleak.nim b/tests/arc/tasyncleak.nim deleted file mode 100644 index eb0c45213..000000000 --- a/tests/arc/tasyncleak.nim +++ /dev/null @@ -1,21 +0,0 @@ -discard """ - outputsub: "(allocCount: 4302, deallocCount: 4300)" - cmd: "nim c --gc:orc -d:nimAllocStats $file" -""" - -import asyncdispatch -# bug #15076 -const - # Just to occupy some RAM - BigData = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" - -proc doNothing(): Future[void] {.async.} = - discard - -proc main(): Future[void] {.async.} = - for x in 0 .. 1_000: - await doNothing() - -waitFor main() -GC_fullCollect() -echo getAllocStats() diff --git a/tests/arc/tasyncleak2.nim b/tests/arc/tasyncleak2.nim deleted file mode 100644 index 87d7e73f9..000000000 --- a/tests/arc/tasyncleak2.nim +++ /dev/null @@ -1,88 +0,0 @@ -discard """ - output: "success" - cmd: "nim c --gc:orc $file" -""" - -# issue #15076 -import deques, strutils, asyncdispatch - -proc doNothing(): Future[void] = - #[ - var - :env - :env_1 - try: - `=destroy`(:env) - internalNew(:env) - `=sink`(:env.retFuture1, newFuture("doNothing")) - - `=destroy_1`(:env_1) - internalNew(:env_1) - `=`(:env_1.:up, :env) - `=sink_1`(:env.nameIterVar2, (doNothingIter, :env_1)) - - (doNothingNimAsyncContinue, :env)() - return `=_1`(result, :env.retFuture1) - finally: - `=destroy`(:env) - ]# - - var retFuture = newFuture[void]("doNothing") - iterator doNothingIter(): FutureBase {.closure.} = - # inspected ARC code: looks correct! - block: - var qqq = initDeque[string]() - for i in 0 .. 1000: - qqq.addLast($i) - complete(retFuture) # env.up.retFuture1 - - var nameIterVar = doNothingIter # iter_Env -> retFuture -> - - proc doNothingNimAsyncContinue() {.closure.} = - # inspected ARC code: looks correct - if not nameIterVar.finished: - var next_gensym0 = nameIterVar() - while (not next_gensym0.isNil) and next_gensym0.finished: - next_gensym0 = nameIterVar() - if nameIterVar.finished: - break - if next_gensym0 != nil: - {.gcsafe.}: - next_gensym0.addCallback cast[proc () {.closure, gcsafe.}](doNothingNimAsyncContinue) - - doNothingNimAsyncContinue() - return retFuture - -proc main(): Future[void] = - template await[T](f_gensym12: Future[T]): auto {.used.} = - var internalTmpFuture_gensym12: FutureBase = f_gensym12 - yield internalTmpFuture_gensym12 - (cast[typeof(f_gensym12)](internalTmpFuture_gensym12)).read() - - var retFuture = newFuture[void]("main") - iterator mainIter(): FutureBase {.closure.} = - block: - for x in 0 .. 1000: - await doNothing() - complete(retFuture) - - var nameIterVar_gensym11 = mainIter - proc mainNimAsyncContinue() {.closure.} = - if not nameIterVar_gensym11.finished: - var next_gensym11 = unown nameIterVar_gensym11() - while (not next_gensym11.isNil) and next_gensym11.finished: - next_gensym11 = unown nameIterVar_gensym11() - if nameIterVar_gensym11.finished: - break - if next_gensym11 != nil: - {.gcsafe.}: - next_gensym11.addCallback cast[proc () {.closure, gcsafe.}](mainNimAsyncContinue) - - mainNimAsyncContinue() - return retFuture - -for i in 0..9: - waitFor main() - GC_fullCollect() - doAssert getOccupiedMem() < 1024 -echo "success" diff --git a/tests/arc/tasyncleak3.nim b/tests/arc/tasyncleak3.nim deleted file mode 100644 index 21e963b7f..000000000 --- a/tests/arc/tasyncleak3.nim +++ /dev/null @@ -1,47 +0,0 @@ -discard """ - cmd: "nim c --gc:orc -d:useMalloc $file" - output: "true" - valgrind: "true" -""" - -import strutils - -type - FutureBase* = ref object of RootObj ## Untyped future. - finished: bool - stackTrace: seq[StackTraceEntry] ## For debugging purposes only. - -proc newFuture*(): FutureBase = - new(result) - result.finished = false - result.stackTrace = getStackTraceEntries() - -type - PDispatcher {.acyclic.} = ref object - -var gDisp: PDispatcher -new gDisp - -proc testCompletion(): FutureBase = - var retFuture = newFuture() - - iterator testCompletionIter(): FutureBase {.closure.} = - retFuture.finished = true - when not defined(nobug): - let disp = gDisp # even worse memory consumption this way... - - var nameIterVar = testCompletionIter - proc testCompletionNimAsyncContinue() {.closure.} = - if not nameIterVar.finished: - discard nameIterVar() - testCompletionNimAsyncContinue() - return retFuture - -proc main = - for i in 0..10_000: - discard testCompletion() - -main() - -GC_fullCollect() -echo getOccupiedMem() < 1024 diff --git a/tests/arc/tasyncleak4.nim b/tests/arc/tasyncleak4.nim deleted file mode 100644 index 58cd7f0b7..000000000 --- a/tests/arc/tasyncleak4.nim +++ /dev/null @@ -1,21 +0,0 @@ -discard """ - cmd: "nim c --gc:orc -d:useMalloc $file" - output: '''ok''' - valgrind: "leaks" -""" - -# bug #15076 -import asyncdispatch - -var futures: seq[Future[void]] - -for i in 1..20: - futures.add sleepAsync 1 - futures.add sleepAsync 1 - - futures.all.waitFor() - futures.setLen 0 - -setGlobalDispatcher nil -GC_fullCollect() -echo "ok" diff --git a/tests/arc/tasyncorc.nim b/tests/arc/tasyncorc.nim deleted file mode 100644 index 63703b559..000000000 --- a/tests/arc/tasyncorc.nim +++ /dev/null @@ -1,26 +0,0 @@ -discard """ - output: '''230000''' - cmd: '''nim c --gc:orc -d:useMalloc $file''' - valgrind: "leaks" -""" - -# bug #14402 - -import asynchttpserver, asyncdispatch, httpclient, strutils - -proc cb(req: Request) {.async, gcsafe.} = - const html = " ".repeat(230000) - await req.respond(Http200, html) - -var server = newAsyncHttpServer() -asyncCheck server.serve(Port(8080), cb) - -proc test {.async.} = - var - client = newAsyncHttpClient() - resp = await client.get("http://localhost:8080") - - let x = (await resp.body).len - echo x # crash - -waitFor test() diff --git a/tests/arc/tcaseobj.nim b/tests/arc/tcaseobj.nim index 26c122384..44daa5979 100644 --- a/tests/arc/tcaseobj.nim +++ b/tests/arc/tcaseobj.nim @@ -8,9 +8,6 @@ A B begin end -prevented -(ok: true, value: "ok") -@[(kind: P, pChildren: @[])] myobj destroyed ''' """ @@ -147,186 +144,3 @@ when true: let x = sequence([charSet({'a'..'z', 'A'..'Z', '_'})]) echo "end" testSubObjAssignment() - - -#------------------------------------------------ - -type - MyObject = object - x1: string - case kind1: bool - of false: y1: string - of true: - y2: seq[string] - case kind2: bool - of true: z1: string - of false: - z2: seq[string] - flag: bool - x2: string - -proc test_myobject = - var x: MyObject - x.x1 = "x1" - x.x2 = "x2" - x.y1 = "ljhkjhkjh" - x.kind1 = true - x.y2 = @["1", "2"] - x.kind2 = true - x.z1 = "yes" - x.kind2 = false - x.z2 = @["1", "2"] - x.kind2 = true - x.z1 = "yes" - x.kind2 = true # should be no effect - doAssert(x.z1 == "yes") - x.kind2 = false - x.kind1 = x.kind2 # support self assignment with effect - - try: - x.kind1 = x.flag # flag is not accesible - except FieldDefect: - echo "prevented" - - doAssert(x.x1 == "x1") - doAssert(x.x2 == "x2") - - -test_myobject() - - -#------------------------------------------------ -# bug #14244 - -type - RocksDBResult*[T] = object - case ok*: bool - of true: - value*: T - else: - error*: string - -proc init(): RocksDBResult[string] = - result.ok = true - result.value = "ok" - -echo init() - - -#------------------------------------------------ -# bug #14312 - -type MyObj = object - case kind: bool - of false: x0: int # would work with a type like seq[int]; value would be reset - of true: x1: string - -var a = MyObj(kind: false, x0: 1234) -a.kind = true -doAssert(a.x1 == "") - -block: - # bug #15532 - type Kind = enum - k0, k1 - - type Foo = object - y: int - case kind: Kind - of k0: x0: int - of k1: x1: int - - const j0 = Foo(y: 1, kind: k0, x0: 2) - const j1 = Foo(y: 1, kind: k1, x1: 2) - - doAssert j0.y == 1 - doAssert j0.kind == k0 - doAssert j1.kind == k1 - - doAssert j1.x1 == 2 - doAssert j0.x0 == 2 - -# ------------------------------------ -# bug #20305 - -type - ContentNodeKind = enum - P, Br, Text - ContentNode = object - case kind: ContentNodeKind - of P: pChildren: seq[ContentNode] - of Br: discard - of Text: textStr: string - -proc bug20305 = - var x = ContentNode(kind: P, pChildren: @[ - ContentNode(kind: P, pChildren: @[ContentNode(kind: Text, textStr: "brrr")]) - ]) - x.pChildren.add ContentNode(kind: Br) - x.pChildren.del(0) - {.cast(uncheckedAssign).}: - x.pChildren[0].kind = P - echo x.pChildren - -bug20305() - -# bug #21023 -block: - block: - type - MGErrorKind = enum - mgeUnexpected, mgeNotFound - - type Foo = object - kind: MGErrorKind - ex: Exception - - type Boo = object - a: seq[int] - - type - Result2 = object - case o: bool - of false: - e: Foo - of true: - v: Boo - - proc startSessionSync(): Result2 = - return Result2(o: true) - - proc mainSync = - let ff = startSessionSync() - doAssert ff.o == true - - mainSync() - - block: - type - MGErrorKind = enum - mgeUnexpected, mgeNotFound - - type Foo = object - kind: MGErrorKind - ex: Exception - - type Boo = object - a: seq[int] - - type - Result2 = object - case o: bool - of false: - e: Foo - of true: - v: Boo - s: int - - proc startSessionSync(): Result2 = - return Result2(o: true, s: 12) - - proc mainSync = - let ff = startSessionSync() - doAssert ff.s == 12 - - mainSync() diff --git a/tests/arc/tcaseobjcopy.nim b/tests/arc/tcaseobjcopy.nim deleted file mode 100644 index ed07b404e..000000000 --- a/tests/arc/tcaseobjcopy.nim +++ /dev/null @@ -1,246 +0,0 @@ -discard """ - valgrind: true - cmd: "nim c --gc:arc -d:useMalloc $file" - output: '''myobj destroyed -myobj destroyed -myobj destroyed -A -B -begin -end -prevented -(ok: true, value: "ok") -myobj destroyed -''' -""" - -# bug #13102 - -type - D = ref object - R = object - case o: bool - of false: - discard - of true: - field: D - -iterator things(): R = - when true: - var - unit = D() - while true: - yield R(o: true, field: unit) - else: - while true: - var - unit = D() - yield R(o: true, field: unit) - -proc main = - var i = 0 - for item in things(): - discard item.field - inc i - if i == 2: break - -main() - -# bug #13149 - -type - TMyObj = object - p: pointer - len: int - -proc `=destroy`(o: var TMyObj) = - if o.p != nil: - dealloc o.p - o.p = nil - echo "myobj destroyed" - -proc `=copy`(dst: var TMyObj, src: TMyObj) = - `=destroy`(dst) - dst.p = alloc(src.len) - dst.len = src.len - -proc `=sink`(dst: var TMyObj, src: TMyObj) = - `=destroy`(dst) - dst.p = src.p - dst.len = src.len - -type - TObjKind = enum Z, A, B - TCaseObj = object - case kind: TObjKind - of Z: discard - of A: - x1: int # this int plays important role - x2: TMyObj - of B: - y: TMyObj - -proc testSinks: TCaseObj = - result = TCaseObj(kind: A, x1: 5000, x2: TMyObj(len: 5, p: alloc(5))) - result = TCaseObj(kind: B, y: TMyObj(len: 3, p: alloc(3))) - -proc use(x: TCaseObj) = discard - -proc testCopies(i: int) = - var a: array[2, TCaseObj] - a[i] = TCaseObj(kind: A, x1: 5000, x2: TMyObj(len: 5, p: alloc(5))) - a[i+1] = a[i] # copy, cannot move - use(a[i]) - -let x1 = testSinks() -testCopies(0) - -# bug #12957 - -type - PegKind* = enum - pkCharChoice, - pkSequence - Peg* = object ## type that represents a PEG - case kind: PegKind - of pkCharChoice: charChoice: ref set[char] - else: discard - sons: seq[Peg] - -proc charSet*(s: set[char]): Peg = - ## constructs a PEG from a character set `s` - result = Peg(kind: pkCharChoice) - new(result.charChoice) - result.charChoice[] = s - -proc len(a: Peg): int {.inline.} = return a.sons.len -proc myadd(d: var Peg, s: Peg) {.inline.} = add(d.sons, s) - -proc sequence*(a: openArray[Peg]): Peg = - result = Peg(kind: pkSequence, sons: @[]) - when false: - #works too: - result.myadd(a[0]) - result.myadd(a[1]) - for x in items(a): - # works: - #result.sons.add(x) - # fails: - result.myadd x - if result.len == 1: - result = result.sons[0] # this must not move! - -when true: - # bug #12957 - - proc p = - echo "A" - let x = sequence([charSet({'a'..'z', 'A'..'Z', '_'}), - charSet({'a'..'z', 'A'..'Z', '0'..'9', '_'})]) - echo "B" - p() - - proc testSubObjAssignment = - echo "begin" - # There must be extactly one element in the array constructor! - let x = sequence([charSet({'a'..'z', 'A'..'Z', '_'})]) - echo "end" - testSubObjAssignment() - - -#------------------------------------------------ - -type - MyObject = object - x1: string - case kind1: bool - of false: y1: string - of true: - y2: seq[string] - case kind2: bool - of true: z1: string - of false: - z2: seq[string] - flag: bool - x2: string - -proc test_myobject = - var x: MyObject - x.x1 = "x1" - x.x2 = "x2" - x.y1 = "ljhkjhkjh" - x.kind1 = true - x.y2 = @["1", "2"] - x.kind2 = true - x.z1 = "yes" - x.kind2 = false - x.z2 = @["1", "2"] - x.kind2 = true - x.z1 = "yes" - x.kind2 = true # should be no effect - doAssert(x.z1 == "yes") - x.kind2 = false - x.kind1 = x.kind2 # support self assignment with effect - - try: - x.kind1 = x.flag # flag is not accesible - except FieldDefect: - echo "prevented" - - doAssert(x.x1 == "x1") - doAssert(x.x2 == "x2") - - -test_myobject() - - -#------------------------------------------------ -# bug #14244 - -type - RocksDBResult*[T] = object - case ok*: bool - of true: - value*: T - else: - error*: string - -proc init(): RocksDBResult[string] = - result.ok = true - result.value = "ok" - -echo init() - - -#------------------------------------------------ -# bug #14312 - -type MyObj = object - case kind: bool - of false: x0: int # would work with a type like seq[int]; value would be reset - of true: x1: string - -var a = MyObj(kind: false, x0: 1234) -a.kind = true -doAssert(a.x1 == "") - -block: - # bug #15532 - type Kind = enum - k0, k1 - - type Foo = object - y: int - case kind: Kind - of k0: x0: int - of k1: x1: int - - const j0 = Foo(y: 1, kind: k0, x0: 2) - const j1 = Foo(y: 1, kind: k1, x1: 2) - - doAssert j0.y == 1 - doAssert j0.kind == k0 - doAssert j1.kind == k1 - - doAssert j1.x1 == 2 - doAssert j0.x0 == 2 diff --git a/tests/arc/tclosureiter.nim b/tests/arc/tclosureiter.nim deleted file mode 100644 index e4a2ceac6..000000000 --- a/tests/arc/tclosureiter.nim +++ /dev/null @@ -1,36 +0,0 @@ -discard """ - cmd: '''nim c -d:nimAllocStats --gc:arc $file''' - output: '''(allocCount: 102, deallocCount: 102)''' -""" - -type - FutureBase = ref object - someData: string - -const - # Just to occupy some RAM - BigData = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" - -iterator mainIter(): FutureBase {.closure.} = - for x in 0 .. 100: - var internalTmpFuture = FutureBase(someData: BigData) - yield internalTmpFuture - -proc main() = - var nameIterVar = mainIter - var next = nameIterVar() - while not isNil(next): - next = nameIterVar() - if not isNil(next): - doAssert next.someData.len == 97 - # GC_unref(next) - # If you uncomment the GC_ref above, - # the program basically uses no memory after the run. - # but crashes with refc, which might indicate - # that arc/orc simply never frees the result of "next"? - if finished(nameIterVar): - break - -main() -GC_fullCollect() -echo getAllocStats() diff --git a/tests/arc/tcomputedgotocopy.nim b/tests/arc/tcomputedgotocopy.nim deleted file mode 100644 index 8337123ba..000000000 --- a/tests/arc/tcomputedgotocopy.nim +++ /dev/null @@ -1,41 +0,0 @@ -discard """ - cmd: '''nim c --gc:arc $file''' - output: '''2 -2''' -""" - -type - ObjWithDestructor = object - a: int -proc `=destroy`(self: var ObjWithDestructor) = - echo "destroyed" - -proc `=copy`(self: var ObjWithDestructor, other: ObjWithDestructor) = - echo "copied" - -proc test(a: range[0..1], arg: ObjWithDestructor) = - var iteration = 0 - while true: - {.computedGoto.} - - let - b = int(a) * 2 - c = a - d = arg - e = arg - - discard c - discard d - discard e - - inc iteration - - case a - of 0: - assert false - of 1: - echo b - if iteration == 2: - break - -test(1, ObjWithDestructor()) diff --git a/tests/arc/tconst_to_sink.nim b/tests/arc/tconst_to_sink.nim deleted file mode 100644 index 25f659341..000000000 --- a/tests/arc/tconst_to_sink.nim +++ /dev/null @@ -1,26 +0,0 @@ -discard """ - output: '''@[(s1: "333", s2: ""), (s1: "abc", s2: "def"), (s1: "3x", s2: ""), (s1: "3x", s2: ""), (s1: "3x", s2: ""), (s1: "3x", s2: ""), (s1: "lastone", s2: "")]''' - matrix: "--gc:arc" - targets: "c cpp" -""" - -# bug #13240 - -type - Thing = object - s1: string - s2: string - -var box: seq[Thing] - -const c = [Thing(s1: "333"), Thing(s1: "abc", s2: "def")] - -for i in 0..high(c): - box.add c[i] - -for i in 0..3: - box.add Thing(s1: "3x") - -box.add Thing(s1: "lastone") - -echo box diff --git a/tests/arc/tcontrolflow.nim b/tests/arc/tcontrolflow.nim deleted file mode 100644 index 80cc2b187..000000000 --- a/tests/arc/tcontrolflow.nim +++ /dev/null @@ -1,118 +0,0 @@ -discard """ - output: '''begin A -elif -end A -destroyed -begin false -if -end false -destroyed -begin true -if -end true -7 -##index 2 not in 0 .. 1## -true -''' - cmd: "nim c --gc:arc -d:danger $file" -""" -# we use the -d:danger switch to detect uninitialized stack -# slots more reliably (there shouldn't be any, of course). - -type - Foo = object - id: int - -proc `=destroy`(x: var Foo) = - if x.id != 0: - echo "destroyed" - x.id = 0 - -proc construct(): Foo = Foo(id: 3) - -proc elifIsEasy(cond: bool) = - echo "begin A" - if cond: - echo "if" - elif construct().id == 3: - echo "elif" - else: - echo "else" - echo "end A" - -elifIsEasy(false) - - -proc orIsHard(cond: bool) = - echo "begin ", cond - if cond or construct().id == 3: - echo "if" - else: - echo "else" - echo "end ", cond - -orIsHard(false) -orIsHard(true) - -type - Control = ref object - x: int - - MouseEvent = ref object - control: Control - button: int - -proc run(data: Control) = - var evt = MouseEvent(button: 1) - evt.control = data - if evt.button == 1: - discard - else: - return - - echo data.x - -var c = Control(x: 7) - -run(c) - -proc sysFatal(exceptn: typedesc, message: string) {.inline, noreturn.} = - var buf = newStringOfCap(200) - add(buf, "##") - add(buf, message) - add(buf, "##") - echo buf - -proc ifexpr(i, a, b: int) {.compilerproc, noinline.} = - sysFatal(IndexDefect, - if b < a: "index out of bounds, the container is empty" - else: "index " & $i & " not in " & $a & " .. " & $b) - -ifexpr(2, 0, 1) - -# bug #14899 -template toSeq(): untyped = - block: - var result = @[1] - result - -proc clItems(s: seq[int]) = - assert s.len == 1 - -proc escapeCheck = - clItems(toSeq()) - -escapeCheck() - -# bug #14900 - -proc seqsEqual(a, b: string): bool = - if false: - false - else: - (var result1 = a; result1) == (var result2 = b; result2) - -# can be const or var too -let expected = "hello" - -echo seqsEqual(expected, expected) diff --git a/tests/arc/tcstring.nim b/tests/arc/tcstring.nim new file mode 100644 index 000000000..79c8a7fcf --- /dev/null +++ b/tests/arc/tcstring.nim @@ -0,0 +1,16 @@ +discard """ + cmd: "nim c --gc:arc -r $file" + nimout: '''hello +h +o +''' +""" + +# Issue #13321: [codegen] --gc:arc does not properly emit cstring, results in SIGSEGV + +let a = "hello".cstring +echo a +echo a[0] +echo a[4] +doAssert a[a.len] == '\0' + diff --git a/tests/arc/tcursor_field_obj_constr.nim b/tests/arc/tcursor_field_obj_constr.nim deleted file mode 100644 index b87f734bd..000000000 --- a/tests/arc/tcursor_field_obj_constr.nim +++ /dev/null @@ -1,44 +0,0 @@ -discard """ - output: '''a -b -c''' - cmd: "nim c --gc:arc $file" -""" - -# bug #18469 - -type - Edge = object - neighbor {.cursor.}: Node - - NodeObj = object - neighbors: seq[Edge] - label: string - visited: bool - Node = ref NodeObj - - Graph = object - nodes: seq[Node] - -proc `=destroy`(x: var NodeObj) = - echo x.label - `=destroy`(x.neighbors) - `=destroy`(x.label) - -proc addNode(self: var Graph; label: string): Node = - self.nodes.add(Node(label: label)) - result = self.nodes[^1] - -proc addEdge(self: Graph; source, neighbor: Node) = - source.neighbors.add(Edge(neighbor: neighbor)) - -proc main = - var graph: Graph - let nodeA = graph.addNode("a") - let nodeB = graph.addNode("b") - let nodeC = graph.addNode("c") - - graph.addEdge(nodeA, neighbor = nodeB) - graph.addEdge(nodeA, neighbor = nodeC) - -main() diff --git a/tests/arc/tcursor_on_localvar.nim b/tests/arc/tcursor_on_localvar.nim deleted file mode 100644 index 0f53c5efa..000000000 --- a/tests/arc/tcursor_on_localvar.nim +++ /dev/null @@ -1,161 +0,0 @@ -discard """ - output: '''Section: common - Param: Floats1 -Section: local - Param: Str - Param: Bool - Param: Floats2 -destroy Foo -destroy Foo -''' - cmd: '''nim c --gc:arc $file''' -""" - -# bug #15325 - -import tables -import strutils - -const defaultSection = "***" - -type - Config* = ref object - table: OrderedTableRef[string, OrderedTable[string, string]] - -# ---------------------------------------------------------------------------------------------------------------------- -proc newConfig*(): Config = - result = new(Config) - result.table = newOrderedTable[string, OrderedTable[string, string]]() - -# ---------------------------------------------------------------------------------------------------------------------- -proc add*(self: Config, param, value, section: string) {.nosinks.} = - let s = if section == "": defaultSection else: section - - if not self.table.contains(s): - self.table[s] = initOrderedTable[string, string]() - - self.table[s][param] = value - -# ---------------------------------------------------------------------------------------------------------------------- -proc sections*(self: Config): seq[string] = - for i in self.table.keys: - let s = if i == defaultSection: "" else: i - result.add(s) - -# ---------------------------------------------------------------------------------------------------------------------- -proc params*(self: Config, section: string): seq[string] = - let s = if section == "": defaultSection else: section - - if self.table.contains(s): - for i in self.table[s].keys: - result.add(i) - -# ---------------------------------------------------------------------------------------------------------------------- -proc extract*(str, start, finish: string): string = - let startPos = str.find(start) - - if startPos < 0: - return "" - - let endPos = str.find(finish, startPos) - - if endPos < 0: - return "" - - return str[startPos + start.len() ..< endPos] - -# ---------------------------------------------------------------------------------------------------------------------- -proc loadString*(self: Config, text: string): tuple[valid: bool, errorInLine: int] {.discardable.} = - self.table.clear() - - var data = "" - - data = text - - var - actualSection = "" - lineCount = 0 - - for i in splitLines(data): - lineCount += 1 - - var line = strip(i) - - if line.len() == 0: - continue - - if line[0] == '#' or line[0] == ';': - continue - - if line[0] == '[': - let section = strip(extract(line, "[", "]")) - - if section.len() != 0: - actualSection = section - else: - self.table.clear() - return (false, lineCount) - else: - let equal = find(line, '=') - - if equal <= 0: - self.table.clear() - return (false, lineCount) - else: - let - param = strip(line[0 .. equal - 1]) - value = strip(line[equal + 1 .. ^1]) - - if param.len() == 0: - self.table.clear() - return (false, lineCount) - else: - self.add(param, value, actualSection) - - return (true, 0) - -# ---------------------------------------------------------------------------------------------------------------------- -when isMainModule: - var cfg = newConfig() - - cfg.loadString("[common]\nFloats1 = 1,2,3\n[local]\nStr = \"String...\"\nBool = true\nFloats2 = 4, 5, 6\n") - - for s in cfg.sections(): - echo "Section: " & s - - for p in cfg.params(s): - echo " Param: " & p - -# bug #16437 - -type - Foo = object - FooRef = ref Foo - - Bar = ref object - f: FooRef - -proc `=destroy`(o: var Foo) = - echo "destroy Foo" - -proc testMe(x: Bar) = - var c = (if x != nil: x.f else: nil) - assert c != nil - -proc main = - var b = Bar(f: FooRef()) - testMe(b) - -main() - -proc testMe2(x: Bar) = - var c: FooRef - c = (if x != nil: x.f else: nil) - assert c != nil - -proc main2 = - var b = Bar(f: FooRef()) - testMe2(b) - -main2() - diff --git a/tests/arc/tcursorloop.nim b/tests/arc/tcursorloop.nim deleted file mode 100644 index a37a6a036..000000000 --- a/tests/arc/tcursorloop.nim +++ /dev/null @@ -1,45 +0,0 @@ -discard """ - cmd: '''nim c --gc:arc --expandArc:traverse --hint:Performance:off $file''' - nimout: ''' ---expandArc: traverse - -var - it - jt_cursor -try: - `=copy`(it, root) - block :tmp: - while ( - not (it == nil)): - if true: - echo [it.s] - `=copy`(it, it.ri) - jt_cursor = root - if ( - not (jt_cursor == nil)): - echo [jt_cursor.s] - jt_cursor = jt_cursor.ri -finally: - `=destroy`(it) --- end of expandArc ------------------------ -''' -""" - -type - Node = ref object - le, ri: Node - s: string - -proc traverse(root: Node) = - var it = root - while it != nil: - if true: - echo it.s - it = it.ri - - var jt = root - if jt != nil: - echo jt.s - jt = jt.ri - -traverse(nil) diff --git a/tests/arc/tcustomtrace.nim b/tests/arc/tcustomtrace.nim deleted file mode 100644 index 5e0ecfb24..000000000 --- a/tests/arc/tcustomtrace.nim +++ /dev/null @@ -1,240 +0,0 @@ -discard """ - outputsub: '''1 -2 -3 -4 -5 -6 -89 -90 -90 -0 0 1 -0 1 2 -0 2 3 -1 0 4 -1 1 5 -1 2 6 -1 3 7 -after 6 6 -MEM 0''' -joinable: false - cmd: "nim c --gc:orc -d:useMalloc $file" - valgrind: "true" -""" - -import typetraits - -type - myseq*[T] = object - len, cap: int - data: ptr UncheckedArray[T] - -# XXX make code memory safe for overflows in '*' -var - allocCount, deallocCount: int - -proc `=destroy`*[T](x: var myseq[T]) = - if x.data != nil: - when not supportsCopyMem(T): - for i in 0..= x.cap: resize(x) - result = addr(x.data[x.len]) - inc x.len - -template add*[T](x: var myseq[T]; y: T) = - reserveSlot(x)[] = y - -proc shrink*[T](x: var myseq[T]; newLen: int) = - assert newLen <= x.len - assert newLen >= 0 - when not supportsCopyMem(T): - for i in countdown(x.len - 1, newLen - 1): - `=destroy`(x.data[i]) - x.len = newLen - -proc grow*[T](x: var myseq[T]; newLen: int; value: T) = - if newLen <= x.len: return - assert newLen >= 0 - let oldCap = x.cap - if oldCap == 0: x.cap = newLen - else: x.cap = max(newLen, (oldCap * 3) shr 1) - if x.data == nil: inc allocCount - x.data = cast[type(x.data)](realloc0(x.data, oldCap * sizeof(T), x.cap * sizeof(T))) - for i in x.len.. 0 and t >= q[0].finishAt: - q.pop().fut.callme() - dec count - -var futures: seq[Future] - -proc main = - for i in 1..200: - futures.add sleep(56020904056300) - futures.add sleep(56020804337500) - #futures.add sleep(2.0) - - #futures.add sleep(4.0) - - processTimers() - #q.pop()[1].callme() - #q.pop()[1].callme() - - futures.setLen 0 - - q.clear() - -main() -GC_fullCollect() -echo called, " ", getOccupiedMem() < 160 diff --git a/tests/arc/testfile.txt b/tests/arc/testfile.txt deleted file mode 100644 index 5169490be..000000000 --- a/tests/arc/testfile.txt +++ /dev/null @@ -1,2 +0,0 @@ -1 x -2 y diff --git a/tests/arc/texceptions.nim b/tests/arc/texceptions.nim deleted file mode 100644 index c55b463fc..000000000 --- a/tests/arc/texceptions.nim +++ /dev/null @@ -1,16 +0,0 @@ -discard """ - cmd: "nim cpp --gc:arc $file" -""" - -block: # issue #13071 - type MyExcept = object of CatchableError - proc gun()= - raise newException(MyExcept, "foo:") - proc fun()= - var a = "" - try: - gun() - except Exception as e: - a = e.msg & $e.name # was segfaulting here for `nim cpp --gc:arc` - doAssert a == "foo:MyExcept" - fun() diff --git a/tests/arc/texplicit_sink.nim b/tests/arc/texplicit_sink.nim deleted file mode 100644 index 4b021ed62..000000000 --- a/tests/arc/texplicit_sink.nim +++ /dev/null @@ -1,29 +0,0 @@ -discard """ - output: '''de''' - cmd: '''nim c --mm:arc --expandArc:main $file''' - nimout: '''--expandArc: main - -var - a - b_cursor -try: - a = f "abc" - b_cursor = "de" - `=sink`(a, b_cursor) - echo [a] -finally: - `=destroy`(a) --- end of expandArc ------------------------''' -""" - -# bug #20572 - -proc f(s: string): string = s - -proc main = - var a = f "abc" - var b = "de" - `=sink`(a, b) - echo a - -main() diff --git a/tests/arc/tfuncobj.nim b/tests/arc/tfuncobj.nim deleted file mode 100644 index 50cd9425e..000000000 --- a/tests/arc/tfuncobj.nim +++ /dev/null @@ -1,38 +0,0 @@ -discard """ - outputsub: '''f1 -f2 -f3''' - cmd: "nim c --gc:orc $file" - valgrind: true -""" - -type - FuncObj = object - fn: proc (env: pointer) {.cdecl.} - env: pointer - -proc `=destroy`(x: var FuncObj) = - GC_unref(cast[RootRef](x.env)) - -proc `=copy`(x: var FuncObj, y: FuncObj) {.error.} - -# bug #18433 - -proc main = - var fs: seq[FuncObj] - - proc wrap(p: proc()) = - proc closeOver() = p() - let env = rawEnv closeOver - GC_ref(cast[RootRef](env)) - fs.add(FuncObj(fn: cast[proc(env: pointer){.cdecl.}](rawProc closeOver), env: env)) - - wrap(proc() {.closure.} = echo "f1") - wrap(proc() {.closure.} = echo "f2") - wrap(proc() {.closure.} = echo "f3") - - for a in fs: - a.fn(a.env) - -main() - diff --git a/tests/arc/thamming_orc.nim b/tests/arc/thamming_orc.nim deleted file mode 100644 index 777efb38e..000000000 --- a/tests/arc/thamming_orc.nim +++ /dev/null @@ -1,155 +0,0 @@ -discard """ - output: '''(allocCount: 1114, deallocCount: 1112) -created 491 destroyed 491''' - cmd: "nim c --gc:orc -d:nimAllocStats $file" -""" - -# bug #18421 - -# test Nim Hamming Number Lazy List algo with reference counts and not... -# compile with "-d:release -d:danger" and test with various -# memory managment GC's, allocators, threading, etc. -# it should be guaranteed to work with zero memory leaks with `--gc:orc`... - -# compile with `-d:trace20` to trace creation and destruction of first 20 values. - -from math import log2 - -# implement our own basic BigInt so the bigints library isn't necessary... -type - BigInt = object - digits: seq[uint32] -let zeroBigInt = BigInt(digits: @[ 0'u32 ]) -let oneBigInt = BigInt(digits: @[ 1'u32 ]) - -proc shladd(bi: var BigInt; n: int; a: BigInt) = - # assume that both `bi` and `a` are sized correctly with - # msuint32 for both not containing a zero - let alen = a.digits.len - let mx = max(bi.digits.len, a.digits.len) - for i in bi.digits.len ..< mx: bi.digits.add 0'u32 - var cry = 0'u64 - for i in 0 ..< alen: - cry += (bi.digits[i].uint64 shl n) + a.digits[i].uint64 - bi.digits[i] = cry.uint32; cry = cry shr 32 - for i in alen ..< mx: - cry += bi.digits[i].uint64 shl n - bi.digits[i] = cry.uint32; cry = cry shr 32 - if cry > 0'u64: - bi.digits.add cry.uint32 - -proc `$`(x: BigInt): string = - if x.digits.len == 0 or (x.digits.len == 1 and x.digits[0] == 0'u32): - return "0" - result = ""; var n = x; var msd = n.digits.high - while msd >= 0: - if n.digits[msd] == 0'u32: msd.dec; continue - var brw = 0.uint64 - for i in countdown(msd, 0): - let dvdnd = n.digits[i].uint64 + (brw shl 32) - let q = dvdnd div 10'u64; brw = dvdnd - q * 10'u64 - n.digits[i] = q.uint32 - result &= $brw - for i in 0 .. result.high shr 1: # reverse result string in place - let tmp = result[^(i + 1)] - result[^(i + 1)] = result[i] - result[i] = tmp - -type TriVal = (uint32, uint32, uint32) -type LogRep = (float64, TriVal) -type LogRepf = proc(x: LogRep): LogRep -const one: LogRep = (0.0'f64, (0'u32, 0'u32, 0'u32)) -proc `<`(me: LogRep, othr: LogRep): bool = me[0] < othr[0] - -proc convertTriVal2BigInt(tpl: TriVal): BigInt = - result = oneBigInt - let (x2, x3, x5) = tpl - for _ in 1 .. x2: result.shladd 1, zeroBigInt - for _ in 1 .. x3: result.shladd 1, result - for _ in 1 .. x5: result.shladd 2, result - -const lb2 = 1.0'f64 -const lb3 = 3.0'f64.log2 -const lb5 = 5.0'f64.log2 - -proc mul2(me: LogRep): LogRep = - let (lr, tpl) = me; let (x2, x3, x5) = tpl - (lr + lb2, (x2 + 1, x3, x5)) - -proc mul3(me: LogRep): LogRep = - let (lr, tpl) = me; let (x2, x3, x5) = tpl - (lr + lb3, (x2, x3 + 1, x5)) - -proc mul5(me: LogRep): LogRep = - let (lr, tpl) = me; let (x2, x3, x5) = tpl - (lr + lb5, (x2, x3, x5 + 1)) - -type - LazyListObj = object - hd: LogRep - tlf: proc(): LazyList {.closure.} - tl: LazyList - LazyList = ref LazyListObj - -var destroyed = 0 - -proc `=destroy`(ll: var LazyListObj) = - destroyed += 1 - if ll.tlf == nil and ll.tl == nil: return - - when defined(trace20): - echo "destroying: ", (destroyed, ll.hd[1].convertTriVal2BigInt) - if ll.tlf != nil: ll.tlf.`=destroy` - if ll.tl != nil: ll.tl.`=destroy` - #wasMoved(ll) - -proc rest(ll: LazyList): LazyList = # not thread-safe; needs lock on thunk - if ll.tlf != nil: ll.tl = ll.tlf(); ll.tlf = nil - ll.tl - -var created = 0 -iterator hammings(until: int): TriVal = - proc merge(x, y: LazyList): LazyList = - let xh = x.hd; let yh = y.hd; created += 1 - when defined(trace20): - echo "merge create: ", (created - 1, (if xh < yh: xh else: yh)[1].convertTriVal2BigInt) - if xh < yh: LazyList(hd: xh, tlf: proc(): auto = merge x.rest, y) - else: LazyList(hd: yh, tlf: proc(): auto = merge x, y.rest) - proc smult(mltf: LogRepf; s: LazyList): LazyList = - proc smults(ss: LazyList): LazyList = - when defined(trace20): - echo "mult create: ", (created, ss.hd.mltf[1].convertTriVal2BigInt) - created += 1; LazyList(hd: ss.hd.mltf, tlf: proc(): auto = ss.rest.smults) - s.smults - proc unnsm(s: LazyList, mltf: LogRepf): LazyList = - var r: LazyList = nil - when defined(trace20): - echo "first create: ", (created, one[1].convertTriVal2BigInt) - let frst = LazyList(hd: one, tlf: proc(): LazyList = r); created += 1 - r = if s == nil: smult(mltf, frst) else: s.merge smult(mltf, frst) - r - yield one[1] - var hmpll: LazyList = ((nil.unnsm mul5).unnsm mul3).unnsm mul2 - for _ in 2 .. until: - yield hmpll.hd[1]; hmpll = hmpll.rest # almost forever - -proc main = - var s = "" - for h in hammings(20): s &= $h.convertTrival2BigInt & " " - doAssert s == "1 2 3 4 5 6 8 9 10 12 15 16 18 20 24 25 27 30 32 36 ", - "Algorithmic error finding first 20 Hamming numbers!!!" - - when not defined(trace20): - var lsth: TriVal - for h in hammings(200): lsth = h - doAssert $lsth.convertTriVal2BigInt == "16200", - "Algorithmic error finding 200th Hamming number!!!" - -let mem = getOccupiedMem() -main() -GC_FullCollect() -let mb = getOccupiedMem() - mem -doAssert mb == 0, "Found memory leak of " & $mb & " bytes!!!" - -echo getAllocStats() -echo "created ", created, " destroyed ", destroyed diff --git a/tests/arc/thamming_thinout.nim b/tests/arc/thamming_thinout.nim deleted file mode 100644 index 65c34ef49..000000000 --- a/tests/arc/thamming_thinout.nim +++ /dev/null @@ -1,183 +0,0 @@ -discard """ - cmd: "nim c --gc:orc -d:nimThinout -r $file" - output: '''The first 20 hammings are: 1 2 3 4 5 MEM IS 0''' -""" - -# test Nim Hamming Number Lazy List algo with reference counts and not... -# compile with "-d:release -d:danger" and test with various -# memory managment GC's, allocators, threading, etc. - -from times import epochTime -from math import log2 - -# implement our own basic BigInt so the bigints library isn't necessary... -type - BigInt = object - digits: seq[uint32] -let zeroBigInt = BigInt(digits: @[ 0'u32 ]) -let oneBigInt = BigInt(digits: @[ 1'u32 ]) - -proc shladd(bi: var BigInt; n: int; a: BigInt) = - var cry = 0'u64 - for i in 0 ..< min(bi.digits.len, a.digits.len): - cry += (bi.digits[i].uint64 shl n) + a.digits[i].uint64 - bi.digits[i] = cry.uint32 - cry = cry shr 32 - if cry > 0'u64: - bi.digits.add cry.uint32 - -proc `$`(x: BigInt): string = - if x.digits.len == 0 or (x.digits.len == 1 and x.digits[0] == 0'u32): - return "0" - var n = x - var msd = n.digits.high - result = "" - while msd >= 0: - if n.digits[msd] == 0'u32: msd.dec; continue - var brw = 0.uint64 - for i in countdown(msd, 0): - let dvdnd = n.digits[i].uint64 + (brw shl 32) - let q = dvdnd div 10'u64; brw = dvdnd - q*10'u64; n.digits[i] = q.uint32 - result &= $brw - for i in 0 .. result.high shr 1: - let tmp = result[^(i + 1)] - result[^(i + 1)] = result[i] - result[i] = tmp - -proc convertTrival2BigInt(tpl: (uint32, uint32, uint32)): BigInt = - result = oneBigInt - let (x2, x3, x5) = tpl - for _ in 1 .. x2: result.shladd 1, zeroBigInt - for _ in 1 .. x3: result.shladd 1, result - for _ in 1 .. x5: result.shladd 2, result - -type LogRep = (float64, (uint32, uint32, uint32)) -type LogRepf = proc(x: LogRep): LogRep -const one: LogRep = (0.0f64, (0u32, 0u32, 0u32)) -proc `<`(me: LogRep, othr: LogRep): bool = me[0] < othr[0] - -const lb2 = 1.0'f64 -const lb3 = 3.0'f64.log2 -const lb5 = 5.0'f64.log2 - -proc mul2(me: LogRep): LogRep = - let (lr, tpl) = me; let (x2, x3, x5) = tpl - (lr + lb2, (x2 + 1, x3, x5)) - -proc mul3(me: LogRep): LogRep = - let (lr, tpl) = me; let (x2, x3, x5) = tpl - (lr + lb3, (x2, x3 + 1, x5)) - -proc mul5(me: LogRep): LogRep = - let (lr, tpl) = me; let (x2, x3, x5) = tpl - (lr + lb5, (x2, x3, x5 + 1)) - -type - LazyList = ref object - hd: LogRep - tlf: proc(): LazyList {.closure.} - tl: LazyList - -proc rest(ll: LazyList): LazyList = # not thread-safe; needs lock on thunk - if ll.tlf != nil: - ll.tl = ll.tlf() - ll.tlf = nil - ll.tl - -iterator hamming(until: int): (uint32, uint32, uint32) = - proc merge(x, y: LazyList): LazyList = - let xh = x.hd - let yh = y.hd - if xh < yh: LazyList(hd: xh, tlf: proc(): auto = merge x.rest, y) - else: LazyList(hd: yh, tlf: proc(): auto = merge x, y.rest) - proc smult(mltf: LogRepf; s: LazyList): LazyList = - proc smults(ss: LazyList): LazyList = - LazyList(hd: ss.hd.mltf, tlf: proc(): auto = ss.rest.smults) - s.smults - proc unnsm(s: LazyList, mltf: LogRepf): LazyList = - var r: LazyList = nil - let frst = LazyList(hd: one, tlf: proc(): LazyList = r) - r = if s == nil: smult mltf, frst else: s.merge smult(mltf, frst) - r - var hmpll: LazyList = ((nil.unnsm mul5).unnsm mul3).unnsm mul2 - # var hmpll: LazyList = nil; for m in [mul5, mul3, mul2]: echo one.m # ; hmpll = unnsm(hmpll, m) - yield one[1] - var cnt = 1 - while hmpll != nil: - yield hmpll.hd[1] - hmpll = hmpll.rest # almost forever - cnt.inc - if cnt > until: break - #when declared(thinout): - thinout(hmpll) - -proc main = - stdout.write "The first 20 hammings are: " - for h in hamming(4): - write stdout, h.convertTrival2BigInt, " " - - for h in hamming(200): - discard h.convertTrival2BigInt - -let mem = getOccupiedMem() -main() -echo "MEM IS ", getOccupiedMem() - mem - -#[ -result = (smults, :envP.:up)(rest(:envP.ss2)) - -proc anon = - var - :tmpD_284230 - :tmpD_284233 - :tmpD_284236 - try: - `=sink_283407`(result_283502, - `=sink_283927`(:tmpD_284236, (smults_283495, - wasMoved_284234(:tmpD_284233) - `=_284014`(:tmpD_284233, :envP_283898.:up_283899) - :tmpD_284233)) - :tmpD_284236( - `=sink_283407`(:tmpD_284230, rest_283366(:envP_283898.ss2_-283497)) - :tmpD_284230)) - finally: - `=destroy_283914`(:tmpD_284236) - `=destroy_283388`(:tmpD_284230) - -proc smuls(ss: LazyList_283350; :envP_283891): LazyList_283350 = - var :env_283913 - try: - `=destroy_283951`(:env_283913) - internalNew_43643(:env_283913) - `=_283401`(:env_283913.ss2_-283497, ss_283497) - :env_283913.:up_283899 = :envP_283891 - `=sink_283407`(result_283498, LazyList_283350(hd_283353: :envP_283891.mltf1_-283492( - :env_283913.ss2_-283497.hd_283353), tlf_283356: (:anonymous_283499, - let blitTmp_284227 = :env_283913 - wasMoved_284228(:env_283913) - blitTmp_284227))) - finally: - `=destroy_283951`(:env_283913) - -proc smul = - var - :env_283969 - :tmpD_284220 - try: - `=destroy_284008`(:env_283969) - internalNew_43643(:env_283969) - `=_283976`(:env_283969.mltf1_-283492, mltf_283492) - proc smults(ss: LazyList_283350; :envP_283891): LazyList_283350 = - result_283498 = LazyList_283350(hd_283353: mltf_283492(ss_283497.hd_283353), tlf_283356: proc ( - :envP_283898): auto_43100 = result_283502 = smults_283495(rest_283366(ss_283497))) - - `=sink_283407`(result_283494, - `=sink_283927`(:tmpD_284220, (smults_283495, - let blitTmp_284218 = :env_283969 - wasMoved_284219(:env_283969) - blitTmp_284218)) - :tmpD_284220(s_283493)) - finally: - `=destroy_283914`(:tmpD_284220) - `=destroy_284008`(:env_283969) -]# diff --git a/tests/arc/thard_alignment.nim b/tests/arc/thard_alignment.nim deleted file mode 100644 index baa964c77..000000000 --- a/tests/arc/thard_alignment.nim +++ /dev/null @@ -1,146 +0,0 @@ -discard """ -disabled: "arm64" -cmd: "nim c --gc:arc $file" -output: "y" -""" - -{.passC: "-march=native".} - -proc isAlignedCheck(p: pointer, alignment: int) = - doAssert (cast[uint](p) and uint(alignment - 1)) == 0 - -proc isAlignedCheck[T](p: ref T, alignment: int) = - isAlignedCheck(cast[pointer](p), alignment) - -type - m256d {.importc: "__m256d", header: "immintrin.h".} = object - -proc set1(x: float): m256d {.importc: "_mm256_set1_pd", header: "immintrin.h".} -func `+`(a,b: m256d): m256d {.importc: "_mm256_add_pd", header: "immintrin.h".} -proc `$`(a: m256d): string = - result = $(cast[ptr float](a.addr)[]) - - -var res: seq[seq[m256d]] - -for _ in 1..1000: - var x = newSeq[m256d](1) - x[0] = set1(1.0) # test if operation causes segfault - isAlignedCheck(x[0].addr, alignof(m256d)) - res.add x - -var res2: seq[m256d] -for i in 1..10000: - res2.setLen(res2.len + 1) # check if realloc works - isAlignedCheck(res2[0].addr, alignof(m256d)) - -proc lambdaGen(a, b: float, z: ref m256d) : auto = - var x1 = new(m256d) - var x2 = new(m256d) - isAlignedCheck(x1, alignof(m256d)) - isAlignedCheck(x2, alignof(m256d)) - x1[] = set1(2.0 + a) - x2[] = set1(-23.0 - b) - let capturingLambda = proc(x: ref m256d): ref m256d = - var cc = new(m256d) - var bb = new(m256d) - isAlignedCheck(x1, alignof(m256d)) - isAlignedCheck(x2, alignof(m256d)) - isAlignedCheck(cc, alignof(m256d)) - isAlignedCheck(bb, alignof(m256d)) - isAlignedCheck(z, alignof(m256d)) - - cc[] = x1[] + x1[] + z[] - bb[] = x2[] + set1(12.5) + z[] - - result = new(m256d) - isAlignedCheck(result, alignof(m256d)) - result[] = cc[] + bb[] + x[] - - return capturingLambda - -var xx = new(m256d) -xx[] = set1(10) -isAlignedCheck(xx, alignOf(m256d)) - -let f1 = lambdaGen(2.0 , 2.221, xx) -let f2 = lambdaGen(-1.226 , 3.5, xx) -isAlignedCheck(f1(xx), alignOf(m256d)) -isAlignedCheck(f2(xx), alignOf(m256d)) - - -#----------------------------------------------------------------------------- - -type - MyAligned = object of RootObj - a{.align: 128.}: float - - -var f: MyAligned -isAlignedCheck(f.addr, MyAligned.alignOf) - -var fref = new(MyAligned) -isAlignedCheck(fref, MyAligned.alignOf) - -var fs: seq[MyAligned] -var fr: seq[RootRef] - -for i in 0..1000: - fs.add MyAligned() - isAlignedCheck(fs[^1].addr, MyAligned.alignOf) - fs[^1].a = i.float - - fr.add new(MyAligned) - isAlignedCheck(fr[^1], MyAligned.alignOf) - ((ref MyAligned)fr[^1])[].a = i.float - -for i in 0..1000: - doAssert(fs[i].a == i.float) - doAssert(((ref MyAligned)fr[i]).a == i.float) - - -proc lambdaTest2(a: MyAligned, z: ref MyAligned): auto = - var x1: MyAligned - x1.a = a.a + z.a - var x2: MyAligned - x2.a = a.a - z.a - let capturingLambda = proc(x: MyAligned): MyAligned = - var cc: MyAligned - var bb: MyAligned - isAlignedCheck(x1.addr, MyAligned.alignOf) - isAlignedCheck(x2.addr, MyAligned.alignOf) - isAlignedCheck(cc.addr, MyAligned.alignOf) - isAlignedCheck(bb.addr, MyAligned.alignOf) - isAlignedCheck(z, MyAligned.alignOf) - - cc.a = x1.a + x1.a + z.a - bb.a = x2.a - z.a - - isAlignedCheck(result.addr, MyAligned.alignOf) - result.a = cc.a + bb.a + x2.a - - return capturingLambda - - -let q1 = lambdaTest2(MyAligned(a: 1.0), (ref MyAligned)(a: 2.0)) -let q2 = lambdaTest2(MyAligned( a: -1.0), (ref MyAligned)(a: -2.0)) - -isAlignedCheck(rawEnv(q1), MyAligned.alignOf) -isAlignedCheck(rawEnv(q2), MyAligned.alignOf) -discard q1(MyAligned(a: 1.0)) -discard q2(MyAligned(a: -1.0)) - - -#----------------------------------------------------------------------------- - -block: - var s: seq[seq[MyAligned]] - for len in 0..128: - s.add newSeq[MyAligned](len) - for i in 0.. 0: - isAlignedCheck(s[^1][0].addr, MyAligned.alignOf) - -echo "y" diff --git a/tests/arc/thavlak_orc_stress.nim b/tests/arc/thavlak_orc_stress.nim deleted file mode 100644 index 862e1a097..000000000 --- a/tests/arc/thavlak_orc_stress.nim +++ /dev/null @@ -1,414 +0,0 @@ -discard """ - cmd: "nim c --gc:orc -d:useMalloc -d:nimStressOrc $file" - valgrind: "leaks" - output: "done" -""" - -import tables -import sets -import net - -type - BasicBlock = object - inEdges: seq[ref BasicBlock] - outEdges: seq[ref BasicBlock] - name: int - -proc newBasicBlock(name: int): ref BasicBlock = - new(result) - result.inEdges = newSeq[ref BasicBlock]() - result.outEdges = newSeq[ref BasicBlock]() - result.name = name - -proc hash(x: ref BasicBlock): int {.inline.} = - result = x.name - -type - BasicBlockEdge = object - fr: ref BasicBlock - to: ref BasicBlock - - Cfg = object - basicBlockMap: Table[int, ref BasicBlock] - edgeList: seq[BasicBlockEdge] - startNode: ref BasicBlock - -proc newCfg(): Cfg = - result.basicBlockMap = initTable[int, ref BasicBlock]() - result.edgeList = newSeq[BasicBlockEdge]() - -proc createNode(self: var Cfg, name: int): ref BasicBlock = - #var node: ref BasicBlock - result = self.basicBlockMap.getOrDefault(name) - if result == nil: - result = newBasicBlock(name) - self.basicBlockMap.add name, result - - if self.startNode == nil: - self.startNode = result - -proc addEdge(self: var Cfg, edge: BasicBlockEdge) = - self.edgeList.add(edge) - -proc getNumNodes(self: Cfg): int = - self.basicBlockMap.len - -proc newBasicBlockEdge(cfg: var Cfg, fromName: int, toName: int) = - var newEdge = BasicBlockEdge() - newEdge.fr = cfg.createNode(fromName) - newEdge.to = cfg.createNode(toName) - newEdge.fr.outEdges.add(newEdge.to) - newEdge.to.inEdges.add(newEdge.fr) - cfg.addEdge(newEdge) - -type - SimpleLoop = object - basicBlocks: seq[ref BasicBlock] # TODO: set here - children: seq[ref SimpleLoop] # TODO: set here - parent: ref SimpleLoop - header: ref BasicBlock - isRoot: bool - isReducible: bool - counter: int - nestingLevel: int - depthLevel: int - -proc newSimpleLoop(): ref SimpleLoop = - new(result) - result.basicBlocks = newSeq[ref BasicBlock]() - result.children = newSeq[ref SimpleLoop]() - result.parent = nil - result.header = nil - result.isRoot = false - result.isReducible = true - result.counter = 0 - result.nestingLevel = 0 - result.depthLevel = 0 - -proc addNode(self: ref SimpleLoop, bb: ref BasicBlock) = - self.basicBlocks.add bb - -proc addChildLoop(self: ref SimpleLoop, loop: ref SimpleLoop) = - self.children.add loop - -proc setParent(self: ref SimpleLoop, parent: ref SimpleLoop) = - self.parent = parent - self.parent.addChildLoop(self) - -proc setHeader(self: ref SimpleLoop, bb: ref BasicBlock) = - self.basicBlocks.add(bb) - self.header = bb - -proc setNestingLevel(self: ref SimpleLoop, level: int) = - self.nestingLevel = level - if level == 0: self.isRoot = true - -var loop_counter: int = 0 - -type - Lsg = object - loops: seq[ref SimpleLoop] - root: ref SimpleLoop - -proc createNewLoop(self: var Lsg): ref SimpleLoop = - var s = newSimpleLoop() - loop_counter += 1 - s.counter = loop_counter - s - -proc addLoop(self: var Lsg, l: ref SimpleLoop) = - self.loops.add l - -proc newLsg(): Lsg = - result.loops = newSeq[ref SimpleLoop]() - result.root = result.createNewLoop() - result.root.setNestingLevel(0) - result.addLoop(result.root) - -proc getNumLoops(self: Lsg): int = - self.loops.len - -type - UnionFindNode = object - parent: ref UnionFindNode - bb: ref BasicBlock - l: ref SimpleLoop - dfsNumber: int - -proc newUnionFindNode(): ref UnionFindNode = - new(result) - result.parent = nil - result.bb = nil - result.l = nil - result.dfsNumber = 0 - -proc initNode(self: ref UnionFindNode, bb: ref BasicBlock, dfsNumber: int) = - self.parent = self - self.bb = bb - self.dfsNumber = dfsNumber - -proc findSet(self: ref UnionFindNode): ref UnionFindNode = - var nodeList = newSeq[ref UnionFindNode]() - var node = self - - while node != node.parent: - var parent = node.parent - if parent != parent.parent: nodeList.add node - node = parent - - for iter in nodeList: iter.parent = node.parent - node - -proc union(self: ref UnionFindNode, unionFindNode: ref UnionFindNode) = - self.parent = unionFindNode - - -const - BB_NONHEADER = 1 # a regular BB - BB_REDUCIBLE = 2 # reducible loop - BB_SELF = 3 # single BB loop - BB_IRREDUCIBLE = 4 # irreducible loop - BB_DEAD = 5 # a dead BB - - # # Marker for uninitialized nodes. - UNVISITED = -1 - - # # Safeguard against pathologic algorithm behavior. - MAXNONBACKPREDS = (32 * 1024) - -type - HavlakLoopFinder = object - cfg: Cfg - lsg: Lsg - -proc newHavlakLoopFinder(cfg: sink Cfg, lsg: sink Lsg): HavlakLoopFinder = - result.cfg = cfg - result.lsg = lsg - -proc isAncestor(w: int, v: int, last: seq[int]): bool = - w <= v and v <= last[w] - -proc dfs(currentNode: ref BasicBlock, nodes: var seq[ref UnionFindNode], number: var Table[ref BasicBlock, int], last: var seq[int], current: int): int = - nodes[current].initNode(currentNode, current) - number[currentNode] = current - - var lastid = current - for target in currentNode.outEdges: - if number[target] == UNVISITED: - lastid = dfs(target, nodes, number, last, lastid + 1) - - last[number[currentNode]] = lastid - return lastid - -proc findLoops(self: var HavlakLoopFinder): int = - var startNode = self.cfg.startNode - if startNode == nil: return 0 - var size = self.cfg.getNumNodes - - var nonBackPreds = newSeq[HashSet[int]]() - var backPreds = newSeq[seq[int]]() - var number = initTable[ref BasicBlock, int]() - var header = newSeq[int](size) - var types = newSeq[int](size) - var last = newSeq[int](size) - var nodes = newSeq[ref UnionFindNode]() - - for i in 1..size: - nonBackPreds.add initHashSet[int](1) - backPreds.add newSeq[int]() - nodes.add newUnionFindNode() - - # Step a: - # - initialize all nodes as unvisited. - # - depth-first traversal and numbering. - # - unreached BB's are marked as dead. - # - for v in self.cfg.basicBlockMap.values: number[v] = UNVISITED - discard dfs(startNode, nodes, number, last, 0) - - # Step b: - # - iterate over all nodes. - # - # A backedge comes from a descendant in the DFS tree, and non-backedges - # from non-descendants (following Tarjan). - # - # - check incoming edges 'v' and add them to either - # - the list of backedges (backPreds) or - # - the list of non-backedges (nonBackPreds) - # - for w in 0 ..< size: - header[w] = 0 - types[w] = BB_NONHEADER - - var nodeW = nodes[w].bb - if nodeW != nil: - for nodeV in nodeW.inEdges: - var v = number[nodeV] - if v != UNVISITED: - if isAncestor(w, v, last): - backPreds[w].add v - else: - nonBackPreds[w].incl v - else: - types[w] = BB_DEAD - - # Start node is root of all other loops. - header[0] = 0 - - # Step c: - # - # The outer loop, unchanged from Tarjan. It does nothing except - # for those nodes which are the destinations of backedges. - # For a header node w, we chase backward from the sources of the - # backedges adding nodes to the set P, representing the body of - # the loop headed by w. - # - # By running through the nodes in reverse of the DFST preorder, - # we ensure that inner loop headers will be processed before the - # headers for surrounding loops. - - for w in countdown(size - 1, 0): - # this is 'P' in Havlak's paper - var nodePool = newSeq[ref UnionFindNode]() - - var nodeW = nodes[w].bb - if nodeW != nil: # dead BB - # Step d: - for v in backPreds[w]: - if v != w: - nodePool.add nodes[v].findSet - else: - types[w] = BB_SELF - - # Copy nodePool to workList. - # - var workList = newSeq[ref UnionFindNode]() - for x in nodePool: workList.add x - - if nodePool.len != 0: types[w] = BB_REDUCIBLE - - # work the list... - # - while workList.len > 0: - var x = workList[0] - workList.del(0) - - # Step e: - # - # Step e represents the main difference from Tarjan's method. - # Chasing upwards from the sources of a node w's backedges. If - # there is a node y' that is not a descendant of w, w is marked - # the header of an irreducible loop, there is another entry - # into this loop that avoids w. - # - - # The algorithm has degenerated. Break and - # return in this case. - # - var nonBackSize = nonBackPreds[x.dfsNumber].len - if nonBackSize > MAXNONBACKPREDS: return 0 - - for iter in nonBackPreds[x.dfsNumber]: - var y = nodes[iter] - var ydash = y.findSet - - if not isAncestor(w, ydash.dfsNumber, last): - types[w] = BB_IRREDUCIBLE - nonBackPreds[w].incl ydash.dfsNumber - else: - if ydash.dfsNumber != w and not nodePool.contains(ydash): - workList.add ydash - nodePool.add ydash - - # Collapse/Unionize nodes in a SCC to a single node - # For every SCC found, create a loop descriptor and link it in. - # - if (nodePool.len > 0) or (types[w] == BB_SELF): - var l = self.lsg.createNewLoop - - l.setHeader(nodeW) - l.isReducible = types[w] != BB_IRREDUCIBLE - - # At this point, one can set attributes to the loop, such as: - # - # the bottom node: - # iter = backPreds(w).begin(); - # loop bottom is: nodes(iter).node; - # - # the number of backedges: - # backPreds(w).size() - # - # whether this loop is reducible: - # types(w) != BB_IRREDUCIBLE - # - nodes[w].l = l - - for node in nodePool: - # Add nodes to loop descriptor. - header[node.dfsNumber] = w - node.union(nodes[w]) - - # Nested loops are not added, but linked together. - var node_l = node.l - if node_l != nil: - node_l.setParent(l) - else: - l.addNode(node.bb) - - self.lsg.addLoop(l) - - result = self.lsg.getNumLoops - - -type - LoopTesterApp = object - cfg: Cfg - lsg: Lsg - -proc newLoopTesterApp(): LoopTesterApp = - result.cfg = newCfg() - result.lsg = newLsg() - -proc buildDiamond(self: var LoopTesterApp, start: int): int = - var bb0 = start - newBasicBlockEdge(self.cfg, bb0, bb0 + 1) - newBasicBlockEdge(self.cfg, bb0, bb0 + 2) - newBasicBlockEdge(self.cfg, bb0 + 1, bb0 + 3) - newBasicBlockEdge(self.cfg, bb0 + 2, bb0 + 3) - result = bb0 + 3 - -proc buildConnect(self: var LoopTesterApp, start1: int, end1: int) = - newBasicBlockEdge(self.cfg, start1, end1) - -proc buildStraight(self: var LoopTesterApp, start: int, n: int): int = - for i in 0..n-1: - self.buildConnect(start + i, start + i + 1) - result = start + n - -proc buildBaseLoop(self: var LoopTesterApp, from1: int): int = - var header = self.buildStraight(from1, 1) - var diamond1 = self.buildDiamond(header) - var d11 = self.buildStraight(diamond1, 1) - var diamond2 = self.buildDiamond(d11) - var footer = self.buildStraight(diamond2, 1) - - self.buildConnect(diamond2, d11) - self.buildConnect(diamond1, header) - self.buildConnect(footer, from1) - result = self.buildStraight(footer, 1) - -proc run(self: var LoopTesterApp) = - discard self.cfg.createNode(0) - discard self.buildBaseLoop(0) - discard self.cfg.createNode(1) - self.buildConnect(0, 2) - - for i in 1..8: - # yes, it's 8 and it's correct. - var h = newHavlakLoopFinder(self.cfg, newLsg()) - discard h.findLoops() - - echo "done" - -var l = newLoopTesterApp() -l.run() diff --git a/tests/arc/theavy_recursion.nim b/tests/arc/theavy_recursion.nim deleted file mode 100644 index 9813331f4..000000000 --- a/tests/arc/theavy_recursion.nim +++ /dev/null @@ -1,43 +0,0 @@ -discard """ - output: "yay" - cmd: "nim c --gc:arc $file" -""" - -# bug #15122 - -import tables - -type - BENodeKind* = enum - tkEof, - tkBytes, - tkList, - tkDict - - BENode* = object - case kind: BENodeKind - of tkBytes: strVal: string - of tkList: listVal: seq[BENode] - of tkDict: dictVal*: Table[string, BENode] - else: - discard - -proc unused(s: string): BENode = - # bad: - result = BENode(kind: tkBytes, strVal: "abc") - -proc main = - var data = { - "examples": { - "values": BENode( - kind: tkList, - listVal: @[BENode(kind: tkBytes, strVal: "test")] - ) - }.toTable() - }.toTable() - - # For ARC listVal is empty for some reason - doAssert data["examples"]["values"].listVal[0].strVal == "test" - -main() -echo "yay" diff --git a/tests/arc/timportedobj.nim b/tests/arc/timportedobj.nim index 9a88a9468..82d7b4740 100644 --- a/tests/arc/timportedobj.nim +++ b/tests/arc/timportedobj.nim @@ -1,14 +1,14 @@ -discard """ - cmd: "nim c --gc:arc $file" - action: "compile" -""" - -# bug #13269 - -import posix -proc foo*() = - var last = newSeq[Stat]() - var next = last - for i in 0..3: - last = next -foo() +discard """ + cmd: "nim c --gc:arc $file" + action: "compile" +""" + +# bug #13269 + +import posix +proc foo*() = + var last = newSeq[Stat]() + var next = last + for i in 0..3: + last = next +foo() diff --git a/tests/arc/tkeys_lent.nim b/tests/arc/tkeys_lent.nim deleted file mode 100644 index 2c92350b1..000000000 --- a/tests/arc/tkeys_lent.nim +++ /dev/null @@ -1,17 +0,0 @@ -discard """ - output: '''{"string": 2}''' - cmd: "nim c --gc:orc $file" -""" - -import tables - -proc use(x: int) = echo x - -proc main = - var tab = {"string": 1}.toTable - for keyAAA in tab.keys(): - template alias(): untyped = tab[keyAAA] - alias() = 2 - echo tab - -main() diff --git a/tests/arc/tmarshal.nim b/tests/arc/tmarshal.nim deleted file mode 100644 index f7ec6e2c5..000000000 --- a/tests/arc/tmarshal.nim +++ /dev/null @@ -1,140 +0,0 @@ -discard """ - cmd: "nim c --gc:orc $file" - output: ''' -{"age": 12, "bio": "Я Cletus", "blob": [65, 66, 67, 128], "name": "Cletus"} -true -true -alpha 100 -omega 200 -0''' -""" - -import marshal - -template testit(x) = discard $$to[typeof(x)]($$x) - -var x: array[0..4, array[0..4, string]] = [ - ["test", "1", "2", "3", "4"], ["test", "1", "2", "3", "4"], - ["test", "1", "2", "3", "4"], ["test", "1", "2", "3", "4"], - ["test", "1", "2", "3", "4"]] - -proc blockA = - testit(x) - var test2: tuple[name: string, s: int] = ("tuple test", 56) - testit(test2) - -blockA() - -type - TE = enum - blah, blah2 - - TestObj = object - test, asd: int - case test2: TE - of blah: - help: string - else: - discard - - PNode = ref TNode - TNode = object - next, prev: PNode - data: string - -proc buildList(): PNode = - new(result) - new(result.next) - new(result.prev) - result.data = "middle" - result.next.data = "next" - result.prev.data = "prev" - result.next.next = result.prev - result.next.prev = result - result.prev.next = result - result.prev.prev = result.next - -proc blockB = - var test3: TestObj - test3.test = 42 - test3.test2 = blah - testit(test3) - - var test4: ref tuple[a, b: string] - new(test4) - test4.a = "ref string test: A" - test4.b = "ref string test: B" - testit(test4) - - var test5 = @[(0,1),(2,3),(4,5)] - testit(test5) - - var test7 = buildList() - testit(test7) - - var test6: set[char] = {'A'..'Z', '_'} - testit(test6) - -blockB() - -# bug #1352 - -type - Entity = object of RootObj - name: string - - Person = object of Entity - age: int - bio: string - blob: string - -proc blockC = - var instance1 = Person(name: "Cletus", age: 12, - bio: "Я Cletus", - blob: "ABC\x80") - echo($$instance1) - echo(to[Person]($$instance1).bio == instance1.bio) # true - echo(to[Person]($$instance1).blob == instance1.blob) # true - -blockC() - -# bug 5757 - -type - Something = object - x: string - y: int - -proc blockD = - var data1 = """{"x": "alpha", "y": 100}""" - var data2 = """{"x": "omega", "y": 200}""" - - var r = to[Something](data1) - - echo r.x, " ", r.y - - r = to[Something](data2) - - echo r.x, " ", r.y - -blockD() - -type - Foo = object - a1: string - a2: string - a3: seq[string] - a4: seq[int] - a5: seq[int] - a6: seq[int] - -proc blockE = - var foo = Foo(a2: "", a4: @[], a6: @[1]) - foo.a6.setLen 0 - doAssert $$foo == """{"a1": "", "a2": "", "a3": [], "a4": [], "a5": [], "a6": []}""" - testit(foo) - -blockE() - -GC_fullCollect() -echo getOccupiedMem() diff --git a/tests/arc/tmovebug.nim b/tests/arc/tmovebug.nim index 8ad7c955c..883543877 100644 --- a/tests/arc/tmovebug.nim +++ b/tests/arc/tmovebug.nim @@ -3,113 +3,6 @@ discard """ output: '''5 (w: 5) (w: -5) -c.text = hello -c.text = hello -p.text = hello -p.toks = @["hello"] -c.text = hello -c[].text = hello -pA.text = hello -pA.toks = @["hello"] -c.text = hello -c.text = hello -pD.text = hello -pD.toks = @["hello"] -c.text = hello -c.text = hello -pOD.text = hello -pOD.toks = @["hello"] -fff -fff -2 -fff -fff -2 -fff -fff -2 -mmm -fff -fff -fff -3 -mmm -sink me (sink) -assign me (not sink) -sink me (not sink) -sinked and not optimized to a bitcopy -sinked and not optimized to a bitcopy -sinked and not optimized to a bitcopy -(data: @[0, 0]) -(data: @[0, 0]) -(data: @[0, 0]) -(data: @[0, 0]) -(data: @[0, 0]) -(data: @[0, 0]) -(data: @[0, 0]) -100 -hey -hey -(a: "a", b: 2) -ho -(a: "b", b: 3) -(b: "b", a: 2) -ho -(b: "a", a: 3) -hey -break -break -hey -ho -hey -ho -ho -king -live long; long live -king -hi -try -bye -() -() -() -1 -destroy -1 -destroy -1 -destroy -copy (self-assign) -1 -destroy -1 -destroy -1 -destroy -destroy -copy -@[(f: 2), (f: 2), (f: 3)] -destroy -destroy -destroy -sink -sink -destroy -copy -(f: 1) -destroy -destroy -part-to-whole assigment: -sink -(children: @[]) -destroy -sink -(children: @[]) -destroy -copy -destroy -(f: 1) -destroy ''' """ @@ -193,649 +86,3 @@ proc tbug13314 = execute() tbug13314() - -#------------------------------------------------------------------------- -# bug #13368 - -import strutils -proc procStat() = - for line in @["a b", "c d", "e f"]: - let cols = line.splitWhitespace(maxSplit=1) - let x = cols[0] - let (nm, rest) = (cols[0], cols[1]) -procStat() - - -# bug #14269 - -import sugar, strutils - -type - Cursor = object - text: string - Parsed = object - text: string - toks: seq[string] - -proc tokenize(c: var Cursor): seq[string] = - dump c.text - return c.text.splitWhitespace() - -proc parse(): Parsed = - var c = Cursor(text: "hello") - dump c.text - return Parsed(text: c.text, toks: c.tokenize) # note: c.tokenized uses c.text - -let p = parse() -dump p.text -dump p.toks - - -proc tokenizeA(c: ptr Cursor): seq[string] = - dump c[].text - return c[].text.splitWhitespace() - -proc parseA(): Parsed = - var c = Cursor(text: "hello") - dump c.text - return Parsed(text: c.text, toks: c.addr.tokenizeA) # note: c.tokenized uses c.text - -let pA = parseA() -dump pA.text -dump pA.toks - - -proc tokenizeD(c: Cursor): seq[string] = - dump c.text - return c.text.splitWhitespace() - -proc parseD(): Parsed = - var c = cast[ptr Cursor](alloc0(sizeof(Cursor))) - c[] = Cursor(text: "hello") - dump c.text - return Parsed(text: c.text, toks: c[].tokenizeD) # note: c.tokenized uses c.text - -let pD = parseD() -dump pD.text -dump pD.toks - -# Bug would only pop up with owned refs -proc tokenizeOD(c: Cursor): seq[string] = - dump c.text - return c.text.splitWhitespace() - -proc parseOD(): Parsed = - var c = new Cursor - c[] = Cursor(text: "hello") - dump c.text - return Parsed(text: c.text, toks: c[].tokenizeOD) # note: c.tokenized uses c.text - -let pOD = parseOD() -dump pOD.text -dump pOD.toks - -when false: - # Bug would only pop up with owned refs and implicit derefs, but since they don't work together.. - {.experimental: "implicitDeref".} - proc tokenizeOHD(c: Cursor): seq[string] = - dump c.text - return c.text.splitWhitespace() - - proc parseOHD(): Parsed = - var c = new Cursor - c[] = Cursor(text: "hello") - dump c.text - return Parsed(text: c.text, toks: c.tokenizeOHD) # note: c.tokenized uses c.text - - let pOHD = parseOHD() - dump pOHD.text - dump pOHD.toks - -# bug #13456 - -iterator combinations[T](s: openArray[T], k: int): seq[T] = - let n = len(s) - assert k >= 0 and k <= n - var pos = newSeq[int](k) - var current = newSeq[T](k) - for i in 0..k-1: - pos[k-i-1] = i - var done = false - while not done: - for i in 0..k-1: - current[i] = s[pos[k-i-1]] - yield current - var i = 0 - while i < k: - pos[i] += 1 - if pos[i] < n-i: - for j in 0..i-1: - pos[j] = pos[i] + i - j - break - i += 1 - if i >= k: - break - -type - UndefEx = object of ValueError - -proc main2 = - var delayedSyms = @[1, 2, 3] - var unp: seq[int] - block myb: - for a in 1 .. 2: - if delayedSyms.len > a: - unp = delayedSyms - for t in unp.combinations(a + 1): - try: - var h = false - for k in t: - echo "fff" - if h: continue - if true: - raise newException(UndefEx, "forward declaration") - break myb - except UndefEx: - echo t.len - echo "mmm" - -main2() - - - -type ME = object - who: string - -proc `=`(x: var ME, y: ME) = - if y.who.len > 0: echo "assign ",y.who - -proc `=sink`(x: var ME, y: ME) = - if y.who.len > 0: echo "sink ",y.who - -var dump: ME -template use(x) = dump = x -template def(x) = x = dump - -var c = true - -proc shouldSink() = - var x = ME(who: "me (sink)") - use(x) # we analyse this - if c: def(x) - else: def(x) - use(x) # ok, with the [else] part. - -shouldSink() - -dump = ME() - -proc shouldNotSink() = - var x = ME(who: "me (not sink)") - use(x) # we analyse this - if c: def(x) - use(x) # Not ok without the '[else]' - -shouldNotSink() - -# bug #14568 -import os - -type O2 = object - s: seq[int] - -proc `=sink`(dest: var O2, src: O2) = - echo "sinked and not optimized to a bitcopy" - -var testSeq: O2 - -proc update() = - # testSeq.add(0) # uncommenting this line fixes the leak - testSeq = O2(s: @[]) - testSeq.s.add(0) - -for i in 1..3: - update() - - -# bug #14961 -type - Foo = object - data: seq[int] - -proc initFoo(len: int): Foo = - result = (let s = newSeq[int](len); Foo(data: s) ) - -var f = initFoo(2) -echo initFoo(2) - -proc initFoo2(len: int) = - echo if true: - let s = newSeq[int](len); Foo(data: s) - else: - let s = newSeq[int](len); Foo(data: s) - -initFoo2(2) - -proc initFoo3(len: int) = - echo (block: - let s = newSeq[int](len); Foo(data: s)) - -initFoo3(2) - -proc initFoo4(len: int) = - echo (let s = newSeq[int](len); Foo(data: s)) - -initFoo4(2) - -proc initFoo5(len: int) = - echo (case true - of true: - let s = newSeq[int](len); Foo(data: s) - of false: - let s = newSeq[int](len); Foo(data: s)) - -initFoo5(2) - -proc initFoo6(len: int) = - echo (block: - try: - let s = newSeq[int](len); Foo(data: s) - finally: discard) - -initFoo6(2) - -proc initFoo7(len: int) = - echo (block: - try: - raise newException(CatchableError, "sup") - let s = newSeq[int](len); Foo(data: s) - except CatchableError: - let s = newSeq[int](len); Foo(data: s) ) - -initFoo7(2) - - -# bug #14902 -iterator zip[T](s: openArray[T]): (T, T) = - var i = 0 - while i < 10: - yield (s[i mod 2], s[i mod 2 + 1]) - inc i - -var lastMem = int.high - -proc leak = - const len = 10 - var x = @[newString(len), newString(len), newString(len)] - - var c = 0 - for (a, b) in zip(x): - let newMem = getOccupiedMem() - assert newMem <= lastMem - lastMem = newMem - c += a.len - echo c - -leak() - - -proc consume(a: sink string) = echo a - -proc weirdScopes = - if (let a = "hey"; a.len > 0): - echo a - - while (let a = "hey"; a.len > 0): - echo a - break - - var a = block: (a: "a", b: 2) - echo a - (discard; a) = (echo "ho"; (a: "b", b: 3)) - echo a - - var b = try: (b: "b", a: 2) - except: raise - echo b - (discard; b) = (echo "ho"; (b: "a", a: 3)) - echo b - - var s = "break" - consume((echo "hey"; s)) - echo s - - echo (block: - var a = "hey" - (echo "hey"; "ho")) - - var b2 = "ho" - echo (block: - var a = "hey" - (echo "hey"; b2)) - echo b2 - - type status = enum - alive - - var king = "king" - echo (block: - var a = "a" - when true: - var b = "b" - case alive - of alive: - try: - var c = "c" - if true: - king - else: - "the abyss" - except: - echo "he ded" - "dead king") - echo "live long; long live" - echo king - -weirdScopes() - - -# bug #14985 -proc getScope(): string = - if true: - return "hi" - else: - "else" - -echo getScope() - -proc getScope3(): string = - try: - "try" - except: - return "except" - -echo getScope3() - -proc getScope2(): string = - case true - of true: - return "bye" - else: - "else" - -echo getScope2() - - -#-------------------------------------------------------------------- -#bug #15609 - -type - Wrapper = object - discard - -proc newWrapper(): ref Wrapper = - new(result) - result - - -proc newWrapper2(a: int): ref Wrapper = - new(result) - if a > 0: - result - else: - new(Wrapper) - - -let w1 = newWrapper() -echo $w1[] - -let w2 = newWrapper2(1) -echo $w2[] - -let w3 = newWrapper2(-1) -echo $w3[] - - -#-------------------------------------------------------------------- -#self-assignments - -# Self-assignments that are not statically determinable will get -# turned into `=copy` calls as caseBracketExprCopy demonstrates. -# (`=copy` handles self-assignments at runtime) - -type - OO = object - f: int - W = object - o: OO - -proc `=destroy`(x: var OO) = - if x.f != 0: - echo "destroy" - x.f = 0 - -proc `=sink`(x: var OO, y: OO) = - `=destroy`(x) - echo "sink" - x.f = y.f - -proc `=copy`(x: var OO, y: OO) = - if x.f != y.f: - `=destroy`(x) - echo "copy" - x.f = y.f - else: - echo "copy (self-assign)" - -proc caseSym = - var o = OO(f: 1) - o = o # NOOP - echo o.f # "1" - # "destroy" - -caseSym() - -proc caseDotExpr = - var w = W(o: OO(f: 1)) - w.o = w.o # NOOP - echo w.o.f # "1" - # "destroy" - -caseDotExpr() - -proc caseBracketExpr = - var w = [0: OO(f: 1)] - w[0] = w[0] # NOOP - echo w[0].f # "1" - # "destroy" - -caseBracketExpr() - -proc caseBracketExprCopy = - var w = [0: OO(f: 1)] - let i = 0 - w[i] = w[0] # "copy (self-assign)" - echo w[0].f # "1" - # "destroy" - -caseBracketExprCopy() - -proc caseDotExprAddr = - var w = W(o: OO(f: 1)) - w.o = addr(w.o)[] # NOOP - echo w.o.f # "1" - # "destroy" - -caseDotExprAddr() - -proc caseBracketExprAddr = - var w = [0: OO(f: 1)] - addr(w[0])[] = addr(addr(w[0])[])[] # NOOP - echo w[0].f # "1" - # "destroy" - -caseBracketExprAddr() - -proc caseNotAConstant = - var i = 0 - proc rand: int = - result = i - inc i - var s = @[OO(f: 1), OO(f: 2), OO(f: 3)] - s[rand()] = s[rand()] # "destroy" "copy" - echo s # @[(f: 2), (f: 2), (f: 3)] - -caseNotAConstant() - -proc potentialSelfAssign(i: var int) = - var a: array[2, OO] - a[i] = OO(f: 1) # turned into a memcopy - a[1] = OO(f: 2) - a[i+1] = a[i] # This must not =sink, but =copy - inc i - echo a[i-1] # (f: 1) - -potentialSelfAssign (var xi = 0; xi) - - -#-------------------------------------------------------------------- -echo "part-to-whole assigment:" - -type - Tree = object - children: seq[Tree] - - TreeDefaultHooks = object - children: seq[TreeDefaultHooks] - -proc `=destroy`(x: var Tree) = echo "destroy" -proc `=sink`(x: var Tree, y: Tree) = echo "sink" -proc `=copy`(x: var Tree, y: Tree) = echo "copy" - -proc partToWholeSeq = - var t = Tree(children: @[Tree()]) - t = t.children[0] # This should be sunk, but with the special transform (tmp = t.children[0]; wasMoved(0); `=sink`(t, tmp)) - - var tc = TreeDefaultHooks(children: @[TreeDefaultHooks()]) - tc = tc.children[0] # Ditto; if this were sunk with the normal transform (`=sink`(t, t.children[0]); wasMoved(t.children[0])) - echo tc # then it would crash because t.children[0] does not exist after the call to `=sink` - -partToWholeSeq() - -proc partToWholeSeqRTIndex = - var i = 0 - var t = Tree(children: @[Tree()]) - t = t.children[i] # See comment in partToWholeSeq - - var tc = TreeDefaultHooks(children: @[TreeDefaultHooks()]) - tc = tc.children[i] # See comment in partToWholeSeq - echo tc - -partToWholeSeqRTIndex() - -type List = object - next: ref List - -proc `=destroy`(x: var List) = echo "destroy" -proc `=sink`(x: var List, y: List) = echo "sink" -proc `=copy`(x: var List, y: List) = echo "copy" - -proc partToWholeUnownedRef = - var t = List(next: new List) - t = t.next[] # Copy because t.next is not an owned ref, and thus t.next[] cannot be moved - -partToWholeUnownedRef() - - -#-------------------------------------------------------------------- -# test that nodes that get copied during the transformation -# (like dot exprs) don't loose their firstWrite/lastRead property - -type - OOO = object - initialized: bool - - C = object - o: OOO - -proc `=destroy`(o: var OOO) = - doAssert o.initialized, "OOO was destroyed before initialization!" - -proc initO(): OOO = - OOO(initialized: true) - -proc initC(): C = - C(o: initO()) - -proc pair(): tuple[a: C, b: C] = - result = (a: initC(), b: initC())# <- when firstWrite tries to find this node to start its analysis it fails, because injectdestructors uses copyTree/shallowCopy - -discard pair() - - -# bug #17450 -proc noConsume(x: OO) {.nosinks.} = echo x - -proc main3 = - var i = 1 - noConsume: - block: - OO(f: i) - -main3() - -# misc -proc smoltest(x: bool): bool = - while true: - if true: return x - -discard smoltest(true) - -# bug #18002 -type - TTypeAttachedOp = enum - attachedAsgn - attachedSink - attachedTrace - - PNode = ref object - discard - -proc genAddrOf(n: PNode) = - assert n != nil, "moved?!" - -proc atomicClosureOp = - let x = PNode() - - genAddrOf: - block: - x - - case attachedTrace - of attachedSink: discard - of attachedAsgn: discard - of attachedTrace: genAddrOf(x) - -atomicClosureOp() - - -template assertEq(a, b: untyped): untyped = - block: - let - aval = a - bval = b - - if aval != bval: - quit "bug!" - -proc convoluted = - let _ = (; - var val1: string; - if true: val1 = "22" - true - ) - - assertEq val1, "22" - assertEq val1, "22" - -convoluted() diff --git a/tests/arc/tmovebugcopy.nim b/tests/arc/tmovebugcopy.nim deleted file mode 100644 index ec4315777..000000000 --- a/tests/arc/tmovebugcopy.nim +++ /dev/null @@ -1,526 +0,0 @@ -discard """ - cmd: "nim c --gc:arc $file" - output: '''5 -(w: 5) -(w: -5) -c.text = hello -c.text = hello -p.text = hello -p.toks = @["hello"] -c.text = hello -c[].text = hello -pA.text = hello -pA.toks = @["hello"] -c.text = hello -c.text = hello -pD.text = hello -pD.toks = @["hello"] -c.text = hello -c.text = hello -pOD.text = hello -pOD.toks = @["hello"] -fff -fff -2 -fff -fff -2 -fff -fff -2 -mmm -fff -fff -fff -3 -mmm -sink me (sink) -assign me (not sink) -sink me (not sink) -sinked and not optimized to a bitcopy -sinked and not optimized to a bitcopy -sinked and not optimized to a bitcopy -(data: @[0, 0]) -(data: @[0, 0]) -(data: @[0, 0]) -(data: @[0, 0]) -(data: @[0, 0]) -(data: @[0, 0]) -(data: @[0, 0]) -100 -hey -hey -(a: "a", b: 2) -ho -(a: "b", b: 3) -(b: "b", a: 2) -ho -(b: "a", a: 3) -hey -break -break -hey -ho -hey -ho -ho -king -live long; long live -king -hi -try -bye -''' -""" - -# move bug -type - TMyObj = object - p: pointer - len: int - -var destroyCounter = 0 - -proc `=destroy`(o: var TMyObj) = - if o.p != nil: - dealloc o.p - o.p = nil - inc destroyCounter - -proc `=copy`(dst: var TMyObj, src: TMyObj) = - `=destroy`(dst) - dst.p = alloc(src.len) - dst.len = src.len - -proc `=sink`(dst: var TMyObj, src: TMyObj) = - `=destroy`(dst) - dst.p = src.p - dst.len = src.len - -type - TObjKind = enum Z, A, B - TCaseObj = object - case kind: TObjKind - of Z: discard - of A: - x1: int # this int plays important role - x2: TMyObj - of B: - y: TMyObj - -proc use(a: TCaseObj) = discard - -proc moveBug(i: var int) = - var a: array[2, TCaseObj] - a[i] = TCaseObj(kind: A, x1: 5000, x2: TMyObj(len: 5, p: alloc(5))) # 1 - a[i+1] = a[i] # 2 - inc i - use(a[i-1]) - -var x = 0 -moveBug(x) - -proc moveBug2(): (TCaseObj, TCaseObj) = - var a: array[2, TCaseObj] - a[0] = TCaseObj(kind: A, x1: 5000, x2: TMyObj(len: 5, p: alloc(5))) - a[1] = a[0] # can move 3 - result[0] = TCaseObj(kind: A, x1: 5000, x2: TMyObj(len: 5, p: alloc(5))) # 4 - result[1] = result[0] # 5 - -proc main = - discard moveBug2() - -main() -echo destroyCounter - -# bug #13314 - -type - O = object - v: int - R = ref object - w: int - -proc `$`(r: R): string = $r[] - -proc tbug13314 = - var t5 = R(w: 5) - var execute = proc () = - echo t5 - - execute() - t5.w = -5 - execute() - -tbug13314() - -#------------------------------------------------------------------------- -# bug #13368 - -import strutils -proc procStat() = - for line in @["a b", "c d", "e f"]: - let cols = line.splitWhitespace(maxSplit=1) - let x = cols[0] - let (nm, rest) = (cols[0], cols[1]) -procStat() - - -# bug #14269 - -import sugar, strutils - -type - Cursor = object - text: string - Parsed = object - text: string - toks: seq[string] - -proc tokenize(c: var Cursor): seq[string] = - dump c.text - return c.text.splitWhitespace() - -proc parse(): Parsed = - var c = Cursor(text: "hello") - dump c.text - return Parsed(text: c.text, toks: c.tokenize) # note: c.tokenized uses c.text - -let p = parse() -dump p.text -dump p.toks - - -proc tokenizeA(c: ptr Cursor): seq[string] = - dump c[].text - return c[].text.splitWhitespace() - -proc parseA(): Parsed = - var c = Cursor(text: "hello") - dump c.text - return Parsed(text: c.text, toks: c.addr.tokenizeA) # note: c.tokenized uses c.text - -let pA = parseA() -dump pA.text -dump pA.toks - - -proc tokenizeD(c: Cursor): seq[string] = - dump c.text - return c.text.splitWhitespace() - -proc parseD(): Parsed = - var c = cast[ptr Cursor](alloc0(sizeof(Cursor))) - c[] = Cursor(text: "hello") - dump c.text - return Parsed(text: c.text, toks: c[].tokenizeD) # note: c.tokenized uses c.text - -let pD = parseD() -dump pD.text -dump pD.toks - -# Bug would only pop up with owned refs -proc tokenizeOD(c: Cursor): seq[string] = - dump c.text - return c.text.splitWhitespace() - -proc parseOD(): Parsed = - var c = new Cursor - c[] = Cursor(text: "hello") - dump c.text - return Parsed(text: c.text, toks: c[].tokenizeOD) # note: c.tokenized uses c.text - -let pOD = parseOD() -dump pOD.text -dump pOD.toks - -when false: - # Bug would only pop up with owned refs and implicit derefs, but since they don't work together.. - {.experimental: "implicitDeref".} - proc tokenizeOHD(c: Cursor): seq[string] = - dump c.text - return c.text.splitWhitespace() - - proc parseOHD(): Parsed = - var c = new Cursor - c[] = Cursor(text: "hello") - dump c.text - return Parsed(text: c.text, toks: c.tokenizeOHD) # note: c.tokenized uses c.text - - let pOHD = parseOHD() - dump pOHD.text - dump pOHD.toks - -# bug #13456 - -iterator combinations[T](s: openArray[T], k: int): seq[T] = - let n = len(s) - assert k >= 0 and k <= n - var pos = newSeq[int](k) - var current = newSeq[T](k) - for i in 0..k-1: - pos[k-i-1] = i - var done = false - while not done: - for i in 0..k-1: - current[i] = s[pos[k-i-1]] - yield current - var i = 0 - while i < k: - pos[i] += 1 - if pos[i] < n-i: - for j in 0..i-1: - pos[j] = pos[i] + i - j - break - i += 1 - if i >= k: - break - -type - UndefEx = object of ValueError - -proc main2 = - var delayedSyms = @[1, 2, 3] - var unp: seq[int] - block myb: - for a in 1 .. 2: - if delayedSyms.len > a: - unp = delayedSyms - for t in unp.combinations(a + 1): - try: - var h = false - for k in t: - echo "fff" - if h: continue - if true: - raise newException(UndefEx, "forward declaration") - break myb - except UndefEx: - echo t.len - echo "mmm" - -main2() - - - -type ME = object - who: string - -proc `=copy`(x: var ME, y: ME) = - if y.who.len > 0: echo "assign ",y.who - -proc `=sink`(x: var ME, y: ME) = - if y.who.len > 0: echo "sink ",y.who - -var dump: ME -template use(x) = dump = x -template def(x) = x = dump - -var c = true - -proc shouldSink() = - var x = ME(who: "me (sink)") - use(x) # we analyse this - if c: def(x) - else: def(x) - use(x) # ok, with the [else] part. - -shouldSink() - -dump = ME() - -proc shouldNotSink() = - var x = ME(who: "me (not sink)") - use(x) # we analyse this - if c: def(x) - use(x) # Not ok without the '[else]' - -shouldNotSink() - -# bug #14568 -import os - -type O2 = object - s: seq[int] - -proc `=sink`(dest: var O2, src: O2) = - echo "sinked and not optimized to a bitcopy" - -var testSeq: O2 - -proc update() = - # testSeq.add(0) # uncommenting this line fixes the leak - testSeq = O2(s: @[]) - testSeq.s.add(0) - -for i in 1..3: - update() - - -# bug #14961 -type - Foo = object - data: seq[int] - -proc initFoo(len: int): Foo = - result = (let s = newSeq[int](len); Foo(data: s) ) - -var f = initFoo(2) -echo initFoo(2) - -proc initFoo2(len: int) = - echo if true: - let s = newSeq[int](len); Foo(data: s) - else: - let s = newSeq[int](len); Foo(data: s) - -initFoo2(2) - -proc initFoo3(len: int) = - echo (block: - let s = newSeq[int](len); Foo(data: s)) - -initFoo3(2) - -proc initFoo4(len: int) = - echo (let s = newSeq[int](len); Foo(data: s)) - -initFoo4(2) - -proc initFoo5(len: int) = - echo (case true - of true: - let s = newSeq[int](len); Foo(data: s) - of false: - let s = newSeq[int](len); Foo(data: s)) - -initFoo5(2) - -proc initFoo6(len: int) = - echo (block: - try: - let s = newSeq[int](len); Foo(data: s) - finally: discard) - -initFoo6(2) - -proc initFoo7(len: int) = - echo (block: - try: - raise newException(CatchableError, "sup") - let s = newSeq[int](len); Foo(data: s) - except CatchableError: - let s = newSeq[int](len); Foo(data: s) ) - -initFoo7(2) - - -# bug #14902 -iterator zip[T](s: openArray[T]): (T, T) = - var i = 0 - while i < 10: - yield (s[i mod 2], s[i mod 2 + 1]) - inc i - -var lastMem = int.high - -proc leak = - const len = 10 - var x = @[newString(len), newString(len), newString(len)] - - var c = 0 - for (a, b) in zip(x): - let newMem = getOccupiedMem() - assert newMem <= lastMem - lastMem = newMem - c += a.len - echo c - -leak() - - -proc consume(a: sink string) = echo a - -proc weirdScopes = - if (let a = "hey"; a.len > 0): - echo a - - while (let a = "hey"; a.len > 0): - echo a - break - - var a = block: (a: "a", b: 2) - echo a - (discard; a) = (echo "ho"; (a: "b", b: 3)) - echo a - - var b = try: (b: "b", a: 2) - except: raise - echo b - (discard; b) = (echo "ho"; (b: "a", a: 3)) - echo b - - var s = "break" - consume((echo "hey"; s)) - echo s - - echo (block: - var a = "hey" - (echo "hey"; "ho")) - - var b2 = "ho" - echo (block: - var a = "hey" - (echo "hey"; b2)) - echo b2 - - type status = enum - alive - - var king = "king" - echo (block: - var a = "a" - when true: - var b = "b" - case alive - of alive: - try: - var c = "c" - if true: - king - else: - "the abyss" - except: - echo "he ded" - "dead king") - echo "live long; long live" - echo king - -weirdScopes() - - -# bug #14985 -proc getScope(): string = - if true: - "hi" - else: - "else" - -echo getScope() - -proc getScope3(): string = - try: - "try" - except: - "except" - -echo getScope3() - -proc getScope2(): string = - case true - of true: - "bye" - else: - "else" - -echo getScope2() diff --git a/tests/arc/tnewseq_legacy.nim b/tests/arc/tnewseq_legacy.nim deleted file mode 100644 index 4730d2c2b..000000000 --- a/tests/arc/tnewseq_legacy.nim +++ /dev/null @@ -1,13 +0,0 @@ -discard """ - output: "(allocCount: 201, deallocCount: 201)" - cmd: "nim c --gc:orc -d:nimAllocStats $file" -""" - -proc main(prefix: string) = - var c: seq[string] - for i in 0..<100: - newSeq(c, 100) - c[i] = prefix & $i - -main("abc") -echo getAllocStats() diff --git a/tests/arc/top_no_cursor2.nim b/tests/arc/top_no_cursor2.nim deleted file mode 100644 index 5dfde57aa..000000000 --- a/tests/arc/top_no_cursor2.nim +++ /dev/null @@ -1,53 +0,0 @@ -discard """ - output: '''true -true -true -true -true''' - cmd: "nim c --gc:arc $file" -""" -# bug #15361 - -type - ErrorNodeKind = enum Branch, Leaf - Error = ref object - case kind: ErrorNodeKind - of Branch: - left: Error - right: Error - of Leaf: - leafError: string - input: string - -proc ret(input: string, lefterr, righterr: Error): Error = - result = Error(kind: Branch, left: lefterr, right: righterr, input: input) - -proc parser() = - var rerrors: Error - let lerrors = Error( - kind: Leaf, - leafError: "first error", - input: "123 ;" - ) - # If you remove "block" - everything works - block: - let rresult = Error( - kind: Leaf, - leafError: "second error", - input: ";" - ) - # this assignment is needed too - rerrors = rresult - - # Returns Error(kind: Branch, left: lerrors, right: rerrors, input: "some val") - # needs to be a proc call for some reason, can't inline the result - var data = ret(input = "some val", lefterr = lerrors, righterr = rerrors) - - echo data.left.leafError == "first error" - echo data.left.input == "123 ;" - # stacktrace shows this line - echo data.right.leafError == "second error" - echo data.right.input == ";" - echo data.input == "some val" - -parser() diff --git a/tests/arc/topenarray.nim b/tests/arc/topenarray.nim deleted file mode 100644 index 0e45f3ec7..000000000 --- a/tests/arc/topenarray.nim +++ /dev/null @@ -1,52 +0,0 @@ -discard """ - input: "hi" - output: ''' -hi -Nim -''' - matrix: "--gc:arc -d:useMalloc; --gc:arc" -""" -{.experimental: "views".} - -block: # bug 18627 - proc setPosition(params: openArray[string]) = - for i in params.toOpenArray(0, params.len - 1): - echo i - - proc uciLoop() = - let params = @[readLine(stdin)] - setPosition(params) - - uciLoop() - - proc uciLoop2() = - let params = @["Nim"] - for i in params.toOpenArray(0, params.len - 1): - echo i - uciLoop2() - -when defined(nimPreviewSlimSystem): - import std/assertions - -block: # bug #20954 - block: - doAssertRaises(IndexDefect): - var v: array[10, int] - - echo len(toOpenArray(v, 20, 30)) - - block: - doAssertRaises(IndexDefect): - var v: seq[int] - - echo len(toOpenArray(v, 20, 30)) - -# bug #20422 - -proc f(a: var string) = - var v = a.toOpenArray(1, 3) - v[0] = 'a' - -var a = "Hello" -f(a) -doAssert a == "Hallo" diff --git a/tests/arc/topt_cursor.nim b/tests/arc/topt_cursor.nim deleted file mode 100644 index 794132921..000000000 --- a/tests/arc/topt_cursor.nim +++ /dev/null @@ -1,57 +0,0 @@ -discard """ - output: '''("string here", 80)''' - cmd: '''nim c --gc:arc --expandArc:main --expandArc:sio --hint:Performance:off $file''' - nimout: '''--expandArc: main - -var - x_cursor - :tmpD -try: - x_cursor = ("hi", 5) - if cond: - x_cursor = ("different", 54) else: - x_cursor = ("string here", 80) - echo [ - :tmpD = `$$`(x_cursor) - :tmpD] -finally: - `=destroy`(:tmpD) --- end of expandArc ------------------------ ---expandArc: sio - -block :tmp: - var x_cursor - var f = open("debug.txt", fmRead, 8000) - try: - var res - try: - res = newStringOfCap(80) - block :tmp_1: - while readLine(f, res): - x_cursor = res - echo [x_cursor] - finally: - `=destroy`(res) - finally: - close(f) --- end of expandArc ------------------------''' -""" - -proc main(cond: bool) = - var x = ("hi", 5) # goal: computed as cursor - - x = if cond: - ("different", 54) - else: - ("string here", 80) - - echo x - -main(false) - -proc sio = - for x in lines("debug.txt"): - echo x - -if false: - sio() diff --git a/tests/arc/topt_cursor2.nim b/tests/arc/topt_cursor2.nim deleted file mode 100644 index 4b566ed24..000000000 --- a/tests/arc/topt_cursor2.nim +++ /dev/null @@ -1,76 +0,0 @@ -discard """ - cmd: '''nim c --gc:arc $file''' - output: '''emptyemptyempty -inner destroy -''' -""" - -# bug #15039 - -import lists - -type - Token = ref object of RootObj - children: DoublyLinkedList[Token] - - Paragraph = ref object of Token - -method `$`(token: Token): string {.base.} = - result = "empty" - -method `$`(token: Paragraph): string = - if token.children.head == nil: - result = "" - else: - for c in token.children: - result.add $c - -proc parseLeafBlockInlines(token: Token) = - token.children.append(Token()) - token.children.append(Token()) # <-- this one AAA - - var emNode = newDoublyLinkedNode(Token()) - var i = 0 - - var it = token.children.head - while it != nil: - var nxt = it.next # this is not a cursor, it takes over ownership. - var childNode = it - if i == 0: - childNode.next = emNode # frees the object allocated in line 29 marked with AAA - elif i == 1: - emNode.next = childNode # - it = nxt # incref on freed data, 'nxt' is freed - inc i - -proc parse() = - var token = Token() - token.children.append Paragraph() - parseLeafBlockInlines(token.children.head.value) - for children in token.children: - echo children - -parse() - - -#------------------------------------------------------------------------------ -# issue #15629 - -type inner = object -type outer = ref inner - -proc `=destroy`(b: var inner) = - echo "inner destroy" - -proc newOuter(): outer = - new(result) - -type holder = object - contents: outer - -proc main() = - var t: holder - t.contents = newOuter() - -main() - diff --git a/tests/arc/topt_no_cursor.nim b/tests/arc/topt_no_cursor.nim deleted file mode 100644 index 50dfa26ac..000000000 --- a/tests/arc/topt_no_cursor.nim +++ /dev/null @@ -1,378 +0,0 @@ -discard """ - nimoutFull: true - cmd: '''nim c -r --warnings:off --hints:off --gc:arc --expandArc:newTarget --expandArc:delete --expandArc:p1 --expandArc:tt --hint:Performance:off --assertions:off --expandArc:extractConfig --expandArc:mergeShadowScope --expandArc:check $file''' - nimout: ''' ---expandArc: newTarget - -var - splat - :tmp - :tmp_1 -splat = splitDrive do: - let blitTmp = path - blitTmp -:tmp = splat.drive -`=wasMoved`(splat.drive) -:tmp_1 = splat.path_1 -`=wasMoved`(splat.path_1) -result = ( - let blitTmp_1 = :tmp - blitTmp_1, - let blitTmp_2 = :tmp_1 - blitTmp_2) -`=destroy`(splat) --- end of expandArc ------------------------ ---expandArc: delete - -var - sibling - saved -`=copy`(sibling, target.parent.left) -`=copy`(saved, sibling.right) -`=copy`(sibling.right, saved.left) -`=sink`(sibling.parent, saved) -`=destroy`(sibling) --- end of expandArc ------------------------ ---expandArc: p1 - -var - lresult - lvalue - lnext - _ -lresult = @[123] -_ = ( - let blitTmp = lresult - blitTmp, ";") -lvalue = _[0] -lnext = _[1] -`=sink`(result.value, move lvalue) -`=destroy`(lnext) -`=destroy_1`(lvalue) --- end of expandArc ------------------------ ---expandArc: tt - -var - it_cursor - a - :tmpD - :tmpD_1 - :tmpD_2 -try: - it_cursor = x - a = ( - `=wasMoved`(:tmpD) - `=copy`(:tmpD, it_cursor.key) - :tmpD, - `=wasMoved`(:tmpD_1) - `=copy`(:tmpD_1, it_cursor.val) - :tmpD_1) - echo [ - :tmpD_2 = `$$`(a) - :tmpD_2] -finally: - `=destroy`(:tmpD_2) - `=destroy_1`(a) --- end of expandArc ------------------------ ---expandArc: extractConfig - -var lan_ip -try: - lan_ip = "" - block :tmp: - var line - var i = 0 - let L = len(txt) - block :tmp_1: - while i < L: - var splitted - try: - line = txt[i] - splitted = split(line, " ", -1) - if splitted[0] == "opt": - `=copy`(lan_ip, splitted[1]) - echo [lan_ip] - echo [splitted[1]] - inc(i, 1) - finally: - `=destroy`(splitted) -finally: - `=destroy_1`(lan_ip) --- end of expandArc ------------------------ ---expandArc: mergeShadowScope - -var shadowScope -`=copy`(shadowScope, c.currentScope) -rawCloseScope(c) -block :tmp: - var sym - var i = 0 - let L = len(shadowScope.symbols) - block :tmp_1: - while i < L: - var :tmpD - sym = shadowScope.symbols[i] - addInterfaceDecl(c): - `=wasMoved`(:tmpD) - `=copy_1`(:tmpD, sym) - :tmpD - inc(i, 1) -`=destroy`(shadowScope) --- end of expandArc ------------------------ ---expandArc: check - -var par -this.isValid = fileExists(this.value) -if dirExists(this.value): - var :tmpD - par = (dir: - `=wasMoved`(:tmpD) - `=copy`(:tmpD, this.value) - :tmpD, front: "") else: - var - :tmpD_1 - :tmpD_2 - :tmpD_3 - par = (dir_1: parentDir(this.value), front_1: - `=wasMoved`(:tmpD_1) - `=copy`(:tmpD_1, - :tmpD_3 = splitDrive do: - `=wasMoved`(:tmpD_2) - `=copy`(:tmpD_2, this.value) - :tmpD_2 - :tmpD_3.path) - :tmpD_1) - `=destroy`(:tmpD_3) -if dirExists(par.dir): - `=sink`(this.matchDirs, getSubDirs(par.dir, par.front)) -else: - `=sink`(this.matchDirs, []) -`=destroy`(par) --- end of expandArc ------------------------ ---expandArc: check - -check(this) --- end of expandArc ------------------------ -(package: "", ext: "meo") -doing shady stuff... -3 -6 -(@[1], @[2]) -192.168.0.1 -192.168.0.1 -192.168.0.1 -192.168.0.1 -''' -""" - -import os, std/private/ntpath - -type Target = tuple[package, ext: string] - -proc newTarget*(path: string): Target = - let splat = path.splitDrive - result = (package: splat.drive, ext: splat.path) - -echo newTarget("meo") - -type - Node = ref object - left, right, parent: Node - value: int - -proc delete(target: var Node) = - var sibling = target.parent.left # b3 - var saved = sibling.right # b3.right -> r4 - - sibling.right = saved.left # b3.right -> r4.left = nil - sibling.parent = saved # b3.parent -> r5 = r4 - - #[after this proc: - b 5 - / \ - b 3 b 6 - ]# - - -#[before: - r 5 - / \ - b 3 b 6 - to delete - / \ -empty r 4 -]# -proc main = - var five = Node(value: 5) - - var six = Node(value: 6) - six.parent = five - five.right = six - - var three = Node(value: 3) - three.parent = five - five.left = three - - var four = Node(value: 4) - four.parent = three - three.right = four - - echo "doing shady stuff..." - delete(six) - # need both of these echos - echo five.left.value - echo five.right.value - -main() - -type - Maybe = object - value: seq[int] - -proc p1(): Maybe = - let lresult = @[123] - var lvalue: seq[int] - var lnext: string - (lvalue, lnext) = (lresult, ";") - - result.value = move lvalue - -proc tissue15130 = - doAssert p1().value == @[123] - -tissue15130() - -type - KeyValue = tuple[key, val: seq[int]] - -proc tt(x: KeyValue) = - var it = x - let a = (it.key, it.val) - echo a - -proc encodedQuery = - var query: seq[KeyValue] - query.add (key: @[1], val: @[2]) - - for elem in query: - elem.tt() - -encodedQuery() - -# bug #15147 - -proc s(input: string): (string, string) = - result = (";", "") - -proc charmatch(input: string): (string, string) = - result = ("123", input[0 .. input.high]) - -proc plus(input: string) = - var - lvalue, rvalue: string # cursors - lnext: string # must be cursor!!! - rnext: string # cursor - let lresult = charmatch(input) - (lvalue, lnext) = lresult - - let rresult = s(lnext) - (rvalue, rnext) = rresult - -plus("123;") - -func substrEq(s: string, pos: int, substr: string): bool = - var i = 0 - var length = substr.len - while i < length and pos+i < s.len and s[pos+i] == substr[i]: - inc i - return i == length - -template stringHasSep(s: string, index: int, sep: string): bool = - s.substrEq(index, sep) - -template splitCommon(s, sep, maxsplit, sepLen) = - var last = 0 - var splits = maxsplit - - while last <= len(s): - var first = last - while last < len(s) and not stringHasSep(s, last, sep): - inc(last) - if splits == 0: last = len(s) - yield substr(s, first, last-1) - if splits == 0: break - dec(splits) - inc(last, sepLen) - -iterator split(s: string, sep: string, maxsplit = -1): string = - splitCommon(s, sep, maxsplit, sep.len) - -template accResult(iter: untyped) = - result = @[] - for x in iter: add(result, x) - -func split*(s: string, sep: string, maxsplit = -1): seq[string] = - accResult(split(s, sep, maxsplit)) - - -let txt = @["opt 192.168.0.1", "static_lease 192.168.0.1"] - -# bug #17033 - -proc extractConfig() = - var lan_ip = "" - - for line in txt: - let splitted = line.split(" ") - if splitted[0] == "opt": - lan_ip = splitted[1] # "borrow" is conditional and inside a loop. - # Not good enough... - # we need a flag that live-ranges are disjoint - echo lan_ip - echo splitted[1] # Without this line everything works - -extractConfig() - - -type - Symbol = ref object - name: string - - Scope = ref object - parent: Scope - symbols: seq[Symbol] - - PContext = ref object - currentScope: Scope - -proc rawCloseScope(c: PContext) = - c.currentScope = c.currentScope.parent - -proc addInterfaceDecl(c: PContext; s: Symbol) = - c.currentScope.symbols.add s - -proc mergeShadowScope*(c: PContext) = - let shadowScope = c.currentScope - c.rawCloseScope - for sym in shadowScope.symbols: - c.addInterfaceDecl(sym) - -mergeShadowScope(PContext(currentScope: Scope(parent: Scope()))) - -type - Foo = ref object - isValid*: bool - value*: string - matchDirs*: seq[string] - -proc getSubDirs(parent, front: string): seq[string] = @[] - -method check(this: Foo) {.base.} = - this.isValid = fileExists(this.value) - let par = if dirExists(this.value): (dir: this.value, front: "") - else: (dir: parentDir(this.value), front: splitDrive(this.value).path) - if dirExists(par.dir): - this.matchDirs = getSubDirs(par.dir, par.front) - else: - this.matchDirs = @[] - -check(Foo()) diff --git a/tests/arc/topt_refcursors.nim b/tests/arc/topt_refcursors.nim deleted file mode 100644 index 8c638a4a1..000000000 --- a/tests/arc/topt_refcursors.nim +++ /dev/null @@ -1,54 +0,0 @@ -discard """ - output: '''''' - cmd: '''nim c --gc:arc --expandArc:traverse --hint:Performance:off $file''' - nimout: ''' ---expandArc: traverse - -var - it_cursor - jt -try: - it_cursor = root - block :tmp: - while ( - not (it_cursor == nil)): - echo [it_cursor.s] - it_cursor = it_cursor.ri - `=copy`(jt, root) - block :tmp_1: - while ( - not (jt == nil)): - var ri_1 - try: - `=copy`(ri_1, jt.ri) - echo [jt.s] - `=sink`(jt, ri_1) - `=wasMoved`(ri_1) - finally: - `=destroy`(ri_1) -finally: - `=destroy`(jt) --- end of expandArc ------------------------ -''' -""" - -type - Node = ref object - le, ri: Node - s: string - -proc traverse(root: Node) = - var it = root - while it != nil: - echo it.s - it = it.ri - - var jt = root - while jt != nil: - let ri = jt.ri - echo jt.s - jt = ri - -traverse(nil) - -# XXX: This optimization is not sound diff --git a/tests/arc/topt_wasmoved_destroy_pairs.nim b/tests/arc/topt_wasmoved_destroy_pairs.nim deleted file mode 100644 index 6577d6787..000000000 --- a/tests/arc/topt_wasmoved_destroy_pairs.nim +++ /dev/null @@ -1,95 +0,0 @@ -discard """ - output: '''''' - cmd: '''nim c --gc:arc --expandArc:main --expandArc:tfor --hint:Performance:off $file''' - nimout: ''' ---expandArc: main - -var - a - b - x -x = f() -if cond: - add(a): - let blitTmp = x - blitTmp -else: - add(b): - let blitTmp_1 = x - blitTmp_1 -`=destroy`(b) -`=destroy`(a) --- end of expandArc ------------------------ ---expandArc: tfor - -var - a - b - x -try: - x = f() - block :tmp: - var i_cursor - mixin inc - var i_1 = 0 - block :tmp_1: - while i_1 < 4: - var :tmpD - i_cursor = i_1 - if i_cursor == 2: - return - add(a): - `=wasMoved`(:tmpD) - `=copy`(:tmpD, x) - :tmpD - inc i_1, 1 - if cond: - add(a): - let blitTmp = x - `=wasMoved`(x) - blitTmp - else: - add(b): - let blitTmp_1 = x - `=wasMoved`(x) - blitTmp_1 -finally: - `=destroy`(x) - `=destroy_1`(b) - `=destroy_1`(a) --- end of expandArc ------------------------ -''' -""" - -proc f(): seq[int] = - @[1, 2, 3] - -proc main(cond: bool) = - var a, b: seq[seq[int]] - var x = f() - if cond: - a.add x - else: - b.add x - -# all paths move 'x' so no wasMoved(x); destroy(x) pair should be left in the -# AST. - -main(false) - - -proc tfor(cond: bool) = - var a, b: seq[seq[int]] - - var x = f() - - for i in 0 ..< 4: - if i == 2: return - a.add x - - if cond: - a.add x - else: - b.add x - -tfor(false) diff --git a/tests/arc/torc_basic_test.nim b/tests/arc/torc_basic_test.nim deleted file mode 100644 index 73039fad7..000000000 --- a/tests/arc/torc_basic_test.nim +++ /dev/null @@ -1,138 +0,0 @@ -discard """ - output: "MEM 0" - cmd: "nim c --gc:orc $file" -""" - -type - Node = ref object - name: char - sccId: int - #a: array[3, Node] - a0, a1, a2: Node - rc: int - -proc edge(a, b: Node) = - inc b.rc - if a.a0 == nil: a.a0 = b - elif a.a1 == nil: a.a1 = b - else: a.a2 = b - when false: - var i = 0 - while a.a[i] != nil: inc i - a.a[i] = b - -proc createNode(name: char): Node = - new result - result.name = name - -#[ - - +--------------------------------+ - v | -+---------+ +------+ | -| | | | | -| A +----->+ | +------+------+ -+--+------+ | | | | - | | | | C ------------> G <--| - | | R | | | -+--v------+ | | +-------------+ -| | | | ^ -| B <------+ | | -| | | +--------+ -+---------+ | | - +------+ - -]# -proc use(x: Node) = discard - -proc main = - let a = createNode('A') - let b = createNode('B') - let r = createNode('R') - let c = createNode('C') - - a.edge b - a.edge r - - r.edge b - r.edge c - - let g = createNode('G') - g.edge g - g.edge g - - c.edge g - c.edge a - - use g - use b - -proc buildComplexGraph: Node = - # see https://en.wikipedia.org/wiki/Strongly_connected_component for the - # graph: - let a = createNode('a') - let b = createNode('b') - let c = createNode('c') - let d = createNode('d') - let e = createNode('e') - - a.edge c - c.edge b - c.edge e - b.edge a - d.edge c - e.edge d - - - let f = createNode('f') - b.edge f - e.edge f - - let g = createNode('g') - let h = createNode('h') - let i = createNode('i') - - f.edge g - f.edge i - g.edge h - h.edge i - i.edge g - - let j = createNode('j') - - h.edge j - i.edge j - - let k = createNode('k') - let l = createNode('l') - - f.edge k - k.edge l - l.edge k - k.edge j - - let m = createNode('m') - let n = createNode('n') - let p = createNode('p') - let q = createNode('q') - - m.edge n - n.edge p - n.edge q - q.edge p - p.edge m - - q.edge k - - d.edge m - e.edge n - - result = a - -proc main2 = - let g = buildComplexGraph() - -main() -main2() -GC_fullCollect() -echo "MEM ", getOccupiedMem() diff --git a/tests/arc/torc_selfcycles.nim b/tests/arc/torc_selfcycles.nim deleted file mode 100644 index ac4fa52ce..000000000 --- a/tests/arc/torc_selfcycles.nim +++ /dev/null @@ -1,33 +0,0 @@ -discard """ - output: '''ok''' - cmd: '''nim c --gc:orc -d:useMalloc -d:nimStressOrc $file''' - valgrind: "leaks" -""" - -# bug #15753 - -type - NodeKind = enum - nkDancing, - nkColumn - - DancingNode = ref object - right: DancingNode - column: DancingNode - kind: NodeKind - -proc newColumnNode(): DancingNode = - result = DancingNode(kind: nkColumn) - result.right = result - result.column = result - -proc createDLXList(): DancingNode = - result = newColumnNode() - - for i in 0 .. 15: - let n = newColumnNode() - n.right = result.right - result = n - echo "ok" - -var dlxlist = createDLXList() diff --git a/tests/arc/torcbench.nim b/tests/arc/torcbench.nim deleted file mode 100644 index 4c9e65fee..000000000 --- a/tests/arc/torcbench.nim +++ /dev/null @@ -1,38 +0,0 @@ -discard """ - output: '''true peak memory: true''' - cmd: "nim c --gc:orc -d:release $file" -""" - -import lists, strutils, times - -type - Base = ref object of RootObj - - Node = ref object of Base - parent: DoublyLinkedList[string] - le, ri: Node - self: Node # in order to create a cycle - -proc buildTree(parent: DoublyLinkedList[string]; depth: int): Node = - if depth == 0: - result = nil - elif depth == 1: - result = Node(parent: parent, le: nil, ri: nil, self: nil) - when not defined(gcArc): - result.self = result - else: - result = Node(parent: parent, le: buildTree(parent, depth - 1), ri: buildTree(parent, depth - 2), self: nil) - result.self = result - -proc main() = - for i in countup(1, 100): - var leakList = initDoublyLinkedList[string]() - for j in countup(1, 5000): - leakList.append(newString(200)) - #GC_fullCollect() - for i in 0..400: - discard buildTree(leakList, 8) - -main() -GC_fullCollect() -echo getOccupiedMem() < 10 * 1024 * 1024, " peak memory: ", getMaxMem() < 10 * 1024 * 1024 diff --git a/tests/arc/torcmisc.nim b/tests/arc/torcmisc.nim deleted file mode 100644 index e41ad7c77..000000000 --- a/tests/arc/torcmisc.nim +++ /dev/null @@ -1,66 +0,0 @@ -discard """ - output: '''success''' - cmd: "nim c --gc:orc -d:release $file" -""" - -# bug #17170 - -when true: - import asyncdispatch - - type - Flags = ref object - returnedEof, reading: bool - - proc dummy(): Future[string] {.async.} = - result = "foobar" - - proc hello(s: Flags) {.async.} = - let buf = - try: - await dummy() - except CatchableError as exc: - # When an exception happens here, the Bufferstream is effectively - # broken and no more reads will be valid - for now, return EOF if it's - # called again, though this is not completely true - EOF represents an - # "orderly" shutdown and that's not what happened here.. - s.returnedEof = true - raise exc - finally: - s.reading = false - - waitFor hello(Flags()) - echo "success" - -# bug #18240 -import tables - -type - TopicHandler* = proc(topic: string, - data: seq[byte]): Future[void] {.gcsafe, raises: [Defect].} - - PeerID* = object - data*: seq[byte] - - PeerInfo* = ref object of RootObj - peerId*: PeerID - - Connection* = ref object of RootObj - peerInfo*: PeerInfo - - PubSubPeer* = ref object of RootObj - codec*: string - - PubSub* = ref object of RootObj - topics*: Table[string, seq[TopicHandler]] - peers*: Table[PeerID, PubSubPeer] - -proc getOrCreatePeer*(myParam: PubSub, peerId: PeerID, protos: seq[string]): PubSubPeer = - myParam.peers.withValue(peerId, peer): - return peer[] - -method handleConn*(myParam: PubSub, - conn: Connection, - proto: string) {.base, async.} = - myParam.peers.withValue(conn.peerInfo.peerId, peer): - let peerB = peer[] diff --git a/tests/arc/tref_cast_error.nim b/tests/arc/tref_cast_error.nim deleted file mode 100644 index 20139c1be..000000000 --- a/tests/arc/tref_cast_error.nim +++ /dev/null @@ -1,15 +0,0 @@ -discard """ - cmd: "nim c --gc:arc $file" - errormsg: "expression cannot be cast to 'ref RootObj'" - joinable: false -""" - -type Variant* = object - refval: ref RootObj - -proc newVariant*[T](val: T): Variant = - let pt = T.new() - pt[] = val - result = Variant(refval: cast[ref RootObj](pt)) - -var v = newVariant(@[1, 2, 3]) diff --git a/tests/arc/trepr.nim b/tests/arc/trepr.nim index abf28330a..7a92112ed 100644 --- a/tests/arc/trepr.nim +++ b/tests/arc/trepr.nim @@ -3,18 +3,8 @@ discard """ nimout: '''(a: true, n: doAssert) Table[system.string, trepr.MyType](data: @[], counter: 0) nil -''' - output: ''' -nil -2 -Obj(member: ref @["hello"]) -ref (member: ref @["hello"]) -ObjUa(v: 0, a: [...]) ''' """ - -# xxx consider merging with `tests/stdlib/trepr.nim` to increase overall test coverage - import tables type @@ -42,56 +32,3 @@ macro dumpSym(a: typed) = dumpSym(doAssert) -# bug 13731 - -import os -var a: File -echo repr a - -# bug 13872 - -echo repr(2'u16) - -# bug 14270 - -type - Obj = ref object - member: ref seq[string] - -var c = Obj(member: new seq[string]) -c.member[] = @["hello"] -echo c.repr - -var c2 = new tuple[member: ref seq[string]] -c2.member = new seq[string] -c2.member[] = @["hello"] -echo c2.repr - -proc p2 = - echo "hey" - -discard repr p2 - - -##################################################################### -# bug #15043 - -import macros - -macro extract(): untyped = - result = newStmtList() - var x: seq[tuple[node: NimNode]] - - proc test(n: NimNode) {.closure.} = - x.add (node: n) - - test(parseExpr("discard")) - -extract() - -type - ObjUa = ref object - v: int - a: UncheckedArray[char] - -echo ObjUa().repr diff --git a/tests/arc/tshared_ptr_crash.nim b/tests/arc/tshared_ptr_crash.nim deleted file mode 100644 index 1794834db..000000000 --- a/tests/arc/tshared_ptr_crash.nim +++ /dev/null @@ -1,67 +0,0 @@ -discard """ - cmd: "nim c --threads:on --gc:arc $file" - action: compile -""" - -# bug #17893 - -type - SharedPtr*[T] = object - val: ptr tuple[value: T, atomicCounter: int] - -proc `=destroy`*[T](p: var SharedPtr[T]) = - mixin `=destroy` - if p.val != nil: - if atomicLoadN(addr p.val[].atomicCounter, AtomicConsume) == 0: - `=destroy`(p.val[]) - deallocShared(p.val) - else: - discard atomicDec(p.val[].atomicCounter) - -proc `=copy`*[T](dest: var SharedPtr[T], src: SharedPtr[T]) = - if src.val != nil: - discard atomicInc(src.val[].atomicCounter) - if dest.val != nil: - `=destroy`(dest) - dest.val = src.val - -proc newSharedPtr*[T](val: sink T): SharedPtr[T] {.nodestroy.} = - result.val = cast[typeof(result.val)](allocShared(sizeof(result.val[]))) - result.val.atomicCounter = 0 - result.val.value = val - -proc isNil*[T](p: SharedPtr[T]): bool {.inline.} = - p.val == nil - -proc `[]`*[T](p: SharedPtr[T]): var T {.inline.} = - when compileOption("boundChecks"): - doAssert(p.val != nil, "deferencing nil shared pointer") - result = p.val.value - -type - Sender*[T] = object - queue: SharedPtr[seq[T]] - -proc newSender*[T](queue: sink SharedPtr[seq[T]]): Sender[T] = - result = Sender[T](queue: queue) - -proc send*[T](self: Sender[T]; t: sink T) = - self.queue[].add t - -proc newChannel*(): Sender[int] = - let queue = newSharedPtr(newSeq[int]()) - result = newSender(queue) - - -var - p: Thread[Sender[int]] - -proc threadFn(tx: Sender[int]) = - send tx, 0 - -proc multiThreadedChannel = - let tx = newChannel() - createThread(p, threadFn, tx) - joinThread(p) - -multiThreadedChannel() diff --git a/tests/arc/tstrformat.nim b/tests/arc/tstrformat.nim deleted file mode 100644 index 641f323da..000000000 --- a/tests/arc/tstrformat.nim +++ /dev/null @@ -1,22 +0,0 @@ -discard """ - output: ''' -verstuff -''' - cmd: "nim c --gc:arc $file" -""" - -# bug #13622 - -import strformat - -template necho*(args: string) {.dirty.} = - if getCurrentException() != nil: - echo args - else: - stdout.writeLine(args) - -proc main(cond: bool; arg: string) = - if cond: - necho &"ver{arg}\n" - -main(true, "stuff") diff --git a/tests/arc/tthread.nim b/tests/arc/tthread.nim deleted file mode 100644 index 8a55a666e..000000000 --- a/tests/arc/tthread.nim +++ /dev/null @@ -1,63 +0,0 @@ -discard """ - cmd: "nim cpp --gc:arc --threads:on $file" - output: '''ok1 -ok2 -destroyed -destroyed -destroyed -''' -""" -import threadpool, os - -type - MyObj = object - p: int - MyObjRef = ref MyObj - -proc `=destroy`(x: var MyObj) = - if x.p != 0: - echo "destroyed" - -proc thread1(): string = - os.sleep(1000) - return "ok1" - -proc thread2(): ref string = - os.sleep(1000) - new(result) - result[] = "ok2" - -proc thread3(): ref MyObj = - os.sleep(1000) - new(result) - result[].p = 2 - -var fv1 = spawn thread1() -var fv2 = spawn thread2() -var fv3 = spawn thread3() -sync() -echo ^fv1 -echo (^fv2)[] - - -proc thread4(x: MyObjRef): MyObjRef {.nosinks.} = - os.sleep(1000) - result = x - -proc thread5(x: sink MyObjRef): MyObjRef = - os.sleep(1000) - result = x - -proc ref_forwarding_test = - var x = new(MyObj) - x[].p = 2 - var y = spawn thread4(x) - -proc ref_sink_forwarding_test = - var x = new(MyObj) - x[].p = 2 - var y = spawn thread5(x) - -ref_forwarding_test() -ref_sink_forwarding_test() -sync() diff --git a/tests/arc/tunref_cycle.nim b/tests/arc/tunref_cycle.nim deleted file mode 100644 index 82551b7f7..000000000 --- a/tests/arc/tunref_cycle.nim +++ /dev/null @@ -1,26 +0,0 @@ -discard """ - outputsub: '''inside closure -hello world''' - cmd: "nim c --gc:orc -d:useMalloc $file" - valgrind: true -""" - -# bug #18579 - -var fp: proc (env: pointer) {.cdecl.} -var env: pointer - -proc store(f: proc (){.closure.}) = - proc closeOver() = - echo "inside closure" - f() - (fp,env) = (cast[proc(env: pointer){.cdecl.}](rawProc closeOver), rawEnv closeOver) - GC_ref(cast[RootRef](env)) - -proc run() = - fp(env) - GC_unref(cast[RootRef](env)) - -store(proc() = echo "hello world") -run() -GC_fullCollect() diff --git a/tests/arc/tweave.nim b/tests/arc/tweave.nim deleted file mode 100644 index 1c60ac403..000000000 --- a/tests/arc/tweave.nim +++ /dev/null @@ -1,157 +0,0 @@ -discard """ - outputsub: '''Success''' - cmd: '''nim c --gc:arc --threads:on $file''' - disabled: "bsd" -""" - -# bug #13936 - -import std/atomics - -when defined(nimPreviewSlimSystem): - import std/[assertions, typedthreads] - -const MemBlockSize = 256 - -type - ChannelSPSCSingle* = object - full{.align: 128.}: Atomic[bool] - itemSize*: uint8 - buffer*{.align: 8.}: UncheckedArray[byte] - -proc `=`( - dest: var ChannelSPSCSingle, - source: ChannelSPSCSingle - ) {.error: "A channel cannot be copied".} - -proc initialize*(chan: var ChannelSPSCSingle, itemsize: SomeInteger) {.inline.} = - ## If ChannelSPSCSingle is used intrusive another data structure - ## be aware that it should be the last part due to ending by UncheckedArray - ## Also due to 128 bytes padding, it automatically takes half - ## of the default MemBlockSize - assert itemsize.int in 0 .. int high(uint8) - assert itemSize.int + - sizeof(chan.itemsize) + - sizeof(chan.full) < MemBlockSize - - chan.itemSize = uint8 itemsize - chan.full.store(false, moRelaxed) - -func isEmpty*(chan: var ChannelSPSCSingle): bool {.inline.} = - not chan.full.load(moAcquire) - -func tryRecv*[T](chan: var ChannelSPSCSingle, dst: var T): bool {.inline.} = - ## Try receiving the item buffered in the channel - ## Returns true if successful (channel was not empty) - ## - ## ⚠ Use only in the consumer thread that reads from the channel. - assert (sizeof(T) == chan.itemsize.int) or - # Support dummy object - (sizeof(T) == 0 and chan.itemsize == 1) - - let full = chan.full.load(moAcquire) - if not full: - return false - dst = cast[ptr T](chan.buffer.addr)[] - chan.full.store(false, moRelease) - return true - -func trySend*[T](chan: var ChannelSPSCSingle, src: sink T): bool {.inline.} = - ## Try sending an item into the channel - ## Reurns true if successful (channel was empty) - ## - ## ⚠ Use only in the producer thread that writes from the channel. - assert (sizeof(T) == chan.itemsize.int) or - # Support dummy object - (sizeof(T) == 0 and chan.itemsize == 1) - - let full = chan.full.load(moAcquire) - if full: - return false - cast[ptr T](chan.buffer.addr)[] = src - chan.full.store(true, moRelease) - return true - -# Sanity checks -# ------------------------------------------------------------------------------ -when isMainModule: - - when not compileOption("threads"): - {.error: "This requires --threads:on compilation flag".} - - template sendLoop[T](chan: var ChannelSPSCSingle, - data: sink T, - body: untyped): untyped = - while not chan.trySend(data): - body - - template recvLoop[T](chan: var ChannelSPSCSingle, - data: var T, - body: untyped): untyped = - while not chan.tryRecv(data): - body - - type - ThreadArgs = object - ID: WorkerKind - chan: ptr ChannelSPSCSingle - - WorkerKind = enum - Sender - Receiver - - template Worker(id: WorkerKind, body: untyped): untyped {.dirty.} = - if args.ID == id: - body - - proc thread_func(args: ThreadArgs) = - - # Worker RECEIVER: - # --------- - # <- chan - # <- chan - # <- chan - # - # Worker SENDER: - # --------- - # chan <- 42 - # chan <- 53 - # chan <- 64 - Worker(Receiver): - var val: int - for j in 0 ..< 10: - args.chan[].recvLoop(val): - # Busy loop, in prod we might want to yield the core/thread timeslice - discard - echo " Receiver got: ", val - doAssert val == 42 + j*11 - - Worker(Sender): - doAssert args.chan.full.load(moRelaxed) == false - for j in 0 ..< 10: - let val = 42 + j*11 - args.chan[].sendLoop(val): - # Busy loop, in prod we might want to yield the core/thread timeslice - discard - echo "Sender sent: ", val - - proc main() = - echo "Testing if 2 threads can send data" - echo "-----------------------------------" - var threads: array[2, Thread[ThreadArgs]] - - var chan = cast[ptr ChannelSPSCSingle](allocShared(MemBlockSize)) - chan[].initialize(itemSize = sizeof(int)) - - createThread(threads[0], thread_func, ThreadArgs(ID: Receiver, chan: chan)) - createThread(threads[1], thread_func, ThreadArgs(ID: Sender, chan: chan)) - - joinThread(threads[0]) - joinThread(threads[1]) - - freeShared(chan) - - echo "-----------------------------------" - echo "Success" - - main() diff --git a/tests/arc/tweavecopy.nim b/tests/arc/tweavecopy.nim deleted file mode 100644 index fc796b352..000000000 --- a/tests/arc/tweavecopy.nim +++ /dev/null @@ -1,154 +0,0 @@ -discard """ - outputsub: '''Success''' - cmd: '''nim c --gc:arc --threads:on $file''' - disabled: "bsd" -""" - -# bug #13936 - -import std/atomics - -const MemBlockSize = 256 - -type - ChannelSPSCSingle* = object - full{.align: 128.}: Atomic[bool] - itemSize*: uint8 - buffer*{.align: 8.}: UncheckedArray[byte] - -proc `=copy`( - dest: var ChannelSPSCSingle, - source: ChannelSPSCSingle - ) {.error: "A channel cannot be copied".} - -proc initialize*(chan: var ChannelSPSCSingle, itemsize: SomeInteger) {.inline.} = - ## If ChannelSPSCSingle is used intrusive another data structure - ## be aware that it should be the last part due to ending by UncheckedArray - ## Also due to 128 bytes padding, it automatically takes half - ## of the default MemBlockSize - assert itemsize.int in 0 .. int high(uint8) - assert itemSize.int + - sizeof(chan.itemsize) + - sizeof(chan.full) < MemBlockSize - - chan.itemSize = uint8 itemsize - chan.full.store(false, moRelaxed) - -func isEmpty*(chan: var ChannelSPSCSingle): bool {.inline.} = - not chan.full.load(moAcquire) - -func tryRecv*[T](chan: var ChannelSPSCSingle, dst: var T): bool {.inline.} = - ## Try receiving the item buffered in the channel - ## Returns true if successful (channel was not empty) - ## - ## ⚠ Use only in the consumer thread that reads from the channel. - assert (sizeof(T) == chan.itemsize.int) or - # Support dummy object - (sizeof(T) == 0 and chan.itemsize == 1) - - let full = chan.full.load(moAcquire) - if not full: - return false - dst = cast[ptr T](chan.buffer.addr)[] - chan.full.store(false, moRelease) - return true - -func trySend*[T](chan: var ChannelSPSCSingle, src: sink T): bool {.inline.} = - ## Try sending an item into the channel - ## Reurns true if successful (channel was empty) - ## - ## ⚠ Use only in the producer thread that writes from the channel. - assert (sizeof(T) == chan.itemsize.int) or - # Support dummy object - (sizeof(T) == 0 and chan.itemsize == 1) - - let full = chan.full.load(moAcquire) - if full: - return false - cast[ptr T](chan.buffer.addr)[] = src - chan.full.store(true, moRelease) - return true - -# Sanity checks -# ------------------------------------------------------------------------------ -when isMainModule: - - when not compileOption("threads"): - {.error: "This requires --threads:on compilation flag".} - - template sendLoop[T](chan: var ChannelSPSCSingle, - data: sink T, - body: untyped): untyped = - while not chan.trySend(data): - body - - template recvLoop[T](chan: var ChannelSPSCSingle, - data: var T, - body: untyped): untyped = - while not chan.tryRecv(data): - body - - type - ThreadArgs = object - ID: WorkerKind - chan: ptr ChannelSPSCSingle - - WorkerKind = enum - Sender - Receiver - - template Worker(id: WorkerKind, body: untyped): untyped {.dirty.} = - if args.ID == id: - body - - proc thread_func(args: ThreadArgs) = - - # Worker RECEIVER: - # --------- - # <- chan - # <- chan - # <- chan - # - # Worker SENDER: - # --------- - # chan <- 42 - # chan <- 53 - # chan <- 64 - Worker(Receiver): - var val: int - for j in 0 ..< 10: - args.chan[].recvLoop(val): - # Busy loop, in prod we might want to yield the core/thread timeslice - discard - echo " Receiver got: ", val - doAssert val == 42 + j*11 - - Worker(Sender): - doAssert args.chan.full.load(moRelaxed) == false - for j in 0 ..< 10: - let val = 42 + j*11 - args.chan[].sendLoop(val): - # Busy loop, in prod we might want to yield the core/thread timeslice - discard - echo "Sender sent: ", val - - proc main() = - echo "Testing if 2 threads can send data" - echo "-----------------------------------" - var threads: array[2, Thread[ThreadArgs]] - - var chan = cast[ptr ChannelSPSCSingle](allocShared(MemBlockSize)) - chan[].initialize(itemSize = sizeof(int)) - - createThread(threads[0], thread_func, ThreadArgs(ID: Receiver, chan: chan)) - createThread(threads[1], thread_func, ThreadArgs(ID: Sender, chan: chan)) - - joinThread(threads[0]) - joinThread(threads[1]) - - freeShared(chan) - - echo "-----------------------------------" - echo "Success" - - main() diff --git a/tests/arc/twrong_sinkinference.nim b/tests/arc/twrong_sinkinference.nim deleted file mode 100644 index ecf09d28a..000000000 --- a/tests/arc/twrong_sinkinference.nim +++ /dev/null @@ -1,18 +0,0 @@ -discard """ - cmd: "nim c --gc:arc $file" - errormsg: "type mismatch: got " - line: 18 -""" - -type - Foo = proc (a, b: string) - -proc take(x: Foo) = - x("a", "b") - -proc willSink(a, b: string) = # {.nosinks.} = - var arr: array[3, string] - var x = a - arr[0] = b - -take willSink diff --git a/tests/arithm/t1.nim b/tests/arithm/t1.nim deleted file mode 100644 index 36402da07..000000000 --- a/tests/arithm/t1.nim +++ /dev/null @@ -1,14 +0,0 @@ -doAssert typeOf(1.int64 + 1.int) is int64 -doAssert typeOf(1.uint64 + 1.uint) is uint64 -doAssert int64 is SomeNumber -doAssert int64 is (SomeNumber and not(uint32|uint64|uint|int)) -doAssert int64 is (not(uint32|uint64|uint|int)) -doAssert int isnot int64 -doAssert int64 isnot int -var myInt16 = 5i16 -var myInt: int -doAssert typeOf(myInt16 + 34) is int16 # of type `int16` -doAssert typeOf(myInt16 + myInt) is int # of type `int` -doAssert typeOf(myInt16 + 2i32) is int32 # of type `int32` -doAssert int32 isnot int64 -doAssert int32 isnot int diff --git a/tests/arithm/tarithm.nim b/tests/arithm/tarithm.nim index d0943d225..fcb78bd7a 100644 --- a/tests/arithm/tarithm.nim +++ b/tests/arithm/tarithm.nim @@ -12,9 +12,7 @@ int32 4294967295 2 0 -tUnsignedOps OK ''' -nimout: "tUnsignedOps OK" """ import typetraits @@ -22,10 +20,10 @@ import typetraits block tand: # bug #5216 - echo(name typeof((0x0A'i8 and 0x7F'i32) shl 7'i32)) + echo(name type((0x0A'i8 and 0x7F'i32) shl 7'i32)) let i8 = 0x0A'i8 - echo(name typeof((i8 and 0x7F'i32) shl 7'i32)) + echo(name type((i8 and 0x7F'i32) shl 7'i32)) echo((0x0A'i8 and 0x7F'i32) shl 7'i32) @@ -169,19 +167,3 @@ block tissue12177: echo(a - b) echo(a * b) echo(a div b) - -block tUnsignedOps: - proc testUnsignedOps() = - let a: int8 = -128 - let b: int8 = 127 - - doAssert b +% 1 == -128 - doAssert b -% -1 == -128 - doAssert b *% 2 == -2 - doAssert a /% 4 == 32 - doAssert a %% 7 == 2 - echo "tUnsignedOps OK" - - testUnsignedOps() - static: - testUnsignedOps() diff --git a/tests/arithm/tdiv.nim b/tests/arithm/tdiv.nim deleted file mode 100644 index 5d8eed84d..000000000 --- a/tests/arithm/tdiv.nim +++ /dev/null @@ -1,19 +0,0 @@ -discard """ - targets: "c js" -""" - - -block divUint64: - proc divTest() = - let x1 = 12'u16 - let y = x1 div 5'u16 - let x2 = 1345567'u32 - let z = x2 div 5'u32 - let a = 1345567'u64 div uint64(x1) - doAssert y == 2 - doAssert z == 269113 - doAssert a == 112130 - - static: divTest() - divTest() - diff --git a/tests/array/t15117.nim b/tests/array/t15117.nim deleted file mode 100644 index 157b04bee..000000000 --- a/tests/array/t15117.nim +++ /dev/null @@ -1,27 +0,0 @@ -discard """ - matrix: "--cc:vcc" - disabled: "linux" - disabled: "bsd" - disabled: "osx" - disabled: "unix" - disabled: "posix" -""" -{.experimental: "views".} - -let a: array[0, byte] = [] -discard a - -type B = object - a:int -let b: array[0, B] = [] -let c: array[0, ptr B] = [] -let d: array[0, ref B] = [] -discard b -discard c -discard d - -discard default(array[0, B]) - -type - View1 = openArray[byte] -discard default(View1) diff --git a/tests/array/t20248.nim b/tests/array/t20248.nim deleted file mode 100644 index 66142548b..000000000 --- a/tests/array/t20248.nim +++ /dev/null @@ -1,14 +0,0 @@ -discard """ -cmd: "nim check --hints:off $file" -errormsg: "ordinal type expected; given: Error Type" -nimout: ''' -t20248.nim(10, 36) Error: ordinal type expected; given: Error Type -t20248.nim(14, 20) Error: ordinal type expected; given: Error Type -''' -""" - -type Vec[N: static[int]] = array[0 ..< N, float] - -var v: Vec[32] - -var stuff: array[0 ..< 16, int] diff --git a/tests/array/t9932.nim b/tests/array/t9932.nim deleted file mode 100644 index e3c8abba3..000000000 --- a/tests/array/t9932.nim +++ /dev/null @@ -1,11 +0,0 @@ -discard """ -cmd: "nim check $file" -errormsg: "invalid type: 'typedesc[int]' in this context: 'array[0..0, typedesc[int]]' for var" -nimout: ''' -t9932.nim(10, 5) Error: invalid type: 'type' in this context: 'array[0..0, type]' for var -t9932.nim(11, 5) Error: invalid type: 'typedesc[int]' in this context: 'array[0..0, typedesc[int]]' for var -''' -""" - -var y: array[1,type] -var x = [int] diff --git a/tests/array/tarray.nim b/tests/array/tarray.nim index e9f330e3b..27288bab3 100644 --- a/tests/array/tarray.nim +++ b/tests/array/tarray.nim @@ -1,8 +1,11 @@ discard """ output: ''' [4, 5, 6] + [16, 25, 36] + [16, 25, 36] + apple banana Fruit @@ -44,7 +47,7 @@ block tarray: arr: TMyarray - proc sum(a: openArray[int]): int = + proc sum(a: openarray[int]): int = result = 0 var i = 0 while i < len(a): @@ -344,11 +347,11 @@ block troofregression: if $a != b: echo "Failure ", a, " != ", b - check typeof(4 ...< 1), "HSlice[system.int, system.int]" - check typeof(4 ...< ^1), "HSlice[system.int, system.BackwardsIndex]" - check typeof(4 ... pred(^1)), "HSlice[system.int, system.BackwardsIndex]" - check typeof(4 ... mypred(8)), "HSlice[system.int, system.int]" - check typeof(4 ... mypred(^1)), "HSlice[system.int, system.BackwardsIndex]" + check type(4 ...< 1), "HSlice[system.int, system.int]" + check type(4 ...< ^1), "HSlice[system.int, system.BackwardsIndex]" + check type(4 ... pred(^1)), "HSlice[system.int, system.BackwardsIndex]" + check type(4 ... mypred(8)), "HSlice[system.int, system.int]" + check type(4 ... mypred(^1)), "HSlice[system.int, system.BackwardsIndex]" var rot = 8 @@ -587,21 +590,3 @@ block t12466: a[0'u16 + i] = i for i in 0'u16 ..< 8'u16: a[0'u16 + i] = i - -block t17705: - # https://github.com/nim-lang/Nim/pull/17705 - var a = array[0, int].low - a = int(a) - var b = array[0, int].high - b = int(b) - -block t18643: - # https://github.com/nim-lang/Nim/issues/18643 - let a: array[0, int] = [] - var caught = false - let b = 9999999 - try: - echo a[b] - except IndexDefect: - caught = true - doAssert caught, "IndexDefect not caught!" diff --git a/tests/assert/panicoverride.nim b/tests/assert/panicoverride.nim deleted file mode 100644 index 53ad64215..000000000 --- a/tests/assert/panicoverride.nim +++ /dev/null @@ -1,15 +0,0 @@ -# panicoverride.nim - -proc printf(fmt: cstring) {.varargs, importc, header:"stdio.h".} -proc exit(code: cint) {.importc, header:"stdlib.h".} - -{.push stack_trace: off, profiler:off.} - -proc rawoutput(s: cstring) = - printf("RAW: %s\n", s) - -proc panic(s: cstring) {.noreturn.} = - printf("PANIC: %s\n", s) - exit(0) - -{.pop.} \ No newline at end of file diff --git a/tests/assert/t21195.nim b/tests/assert/t21195.nim deleted file mode 100644 index b690d22a0..000000000 --- a/tests/assert/t21195.nim +++ /dev/null @@ -1,6 +0,0 @@ -discard """ - matrix: "--verbosity:0 --os:standalone --mm:none" -""" -# bug #21195 -var n = 11 -assert(n == 12) diff --git a/tests/assert/tassert.nim b/tests/assert/tassert.nim index a14fec317..99929f080 100644 --- a/tests/assert/tassert.nim +++ b/tests/assert/tassert.nim @@ -10,7 +10,7 @@ proc callC() = callA() try: callC() -except AssertionDefect: +except AssertionError: write(stdout, "assertion failure!") except: write(stdout, "unknown exception!") diff --git a/tests/assert/tassert2.nim b/tests/assert/tassert2.nim index e32ab72e1..50753ba11 100644 --- a/tests/assert/tassert2.nim +++ b/tests/assert/tassert2.nim @@ -1,44 +1,59 @@ discard """ output: ''' -`false` first assertion from bar -`false` second assertion from bar +test1:ok +test2:ok +test3:ok +test4:ok +test5:ok +test6:ok +test7:ok -1 +tassert2.nim +test8:ok +test9:ok +test10:ok +test11:ok ''' """ -from strutils import endsWith - +import testhelper type TLineInfo = tuple[filename: string, line: int, column: int] TMyError = object of Exception lineinfo: TLineInfo EMyError = ref TMyError +echo("") # NOTE: when entering newlines, adjust `expectedEnd` outputs try: doAssert(false, "msg1") # doAssert test -except AssertionDefect as e: - assert e.msg.endsWith "tassert2.nim(20, 11) `false` msg1" +except AssertionError as e: + checkMsg(e.msg, "tassert2.nim(30, 11) `false` msg1", "test1") + +try: + assert false, "msg2" # assert test +except AssertionError as e: + checkMsg(e.msg, "tassert2.nim(35, 10) `false` msg2", "test2") try: assert false # assert test with no msg -except AssertionDefect as e: - assert e.msg.endsWith "tassert2.nim(25, 3) `false` " +except AssertionError as e: + checkMsg(e.msg, "tassert2.nim(40, 10) `false` ", "test3") try: let a = 1 doAssert(a+a==1) # assert test with Ast expression # BUG: const folding would make "1+1==1" appear as `false` in # assert message -except AssertionDefect as e: - assert e.msg.endsWith "`a + a == 1` " +except AssertionError as e: + checkMsg(e.msg, "`a + a == 1` ", "test4") try: let a = 1 doAssert a+a==1 # ditto with `doAssert` and no parens -except AssertionDefect as e: - assert e.msg.endsWith "`a + a == 1` " +except AssertionError as e: + checkMsg(e.msg, "`a + a == 1` ", "test5") proc fooStatic() = # protect against https://github.com/nim-lang/Nim/issues/8758 @@ -65,12 +80,12 @@ block: proc bar: int = # local overrides that are active only in this proc onFailedAssert(msg): - echo msg[^32..^1] + checkMsg(msg, "tassert2.nim(85, 11) `false` first assertion from bar", "test6") assert(false, "first assertion from bar") onFailedAssert(msg): - echo msg[^33..^1] + checkMsg(msg, "tassert2.nim(91, 11) `false` second assertion from bar", "test7") return -1 assert(false, "second assertion from bar") @@ -82,7 +97,8 @@ block: foo() except: let e = EMyError(getCurrentException()) - assert e.msg.endsWith "tassert2.nim(62, 11) `false` assertion from foo" + echo e.lineinfo.filename + checkMsg(e.msg, "tassert2.nim(77, 11) `false` assertion from foo", "test8") block: ## checks for issue https://github.com/nim-lang/Nim/issues/8518 template fun(a: string): string = @@ -91,21 +107,21 @@ block: ## checks for issue https://github.com/nim-lang/Nim/issues/8518 try: doAssert fun("foo1") == fun("foo2"), "mymsg" - except AssertionDefect as e: + except AssertionError as e: # used to expand out the template instantiaiton, sometimes filling hundreds of lines - assert e.msg.endsWith "" + checkMsg(e.msg, """tassert2.nim(109, 14) `fun("foo1") == fun("foo2")` mymsg""", "test9") block: ## checks for issue https://github.com/nim-lang/Nim/issues/9301 try: doAssert 1 + 1 == 3 - except AssertionDefect as e: + except AssertionError as e: # used to const fold as false - assert e.msg.endsWith "tassert2.nim(100, 5) `1 + 1 == 3` " + checkMsg(e.msg, "tassert2.nim(116, 14) `1 + 1 == 3` ", "test10") block: ## checks AST isn't transformed as it used to let a = 1 try: doAssert a > 1 - except AssertionDefect as e: + except AssertionError as e: # used to rewrite as `1 < a` - assert e.msg.endsWith "tassert2.nim(108, 5) `a > 1` " + checkMsg(e.msg, "tassert2.nim(124, 14) `a > 1` ", "test11") diff --git a/tests/assert/tassert_c.nim b/tests/assert/tassert_c.nim index e3e3b8147..84ccea823 100644 --- a/tests/assert/tassert_c.nim +++ b/tests/assert/tassert_c.nim @@ -1,14 +1,14 @@ discard """ - matrix: "-d:nimPreviewSlimSystem --stackTrace:on --excessiveStackTrace:off" + cmd: "nim $target $options --excessiveStackTrace:off $file" output: '''true''' """ -import std/assertions + const expected = """ tassert_c.nim(35) tassert_c tassert_c.nim(34) foo -assertions.nim(*) failedAssertImpl -assertions.nim(*) raiseAssert -""" +assertions.nim(27) failedAssertImpl +assertions.nim(20) raiseAssert +fatal.nim(55) sysFatal""" proc tmatch(x, p: string): bool = var i = 0 @@ -33,8 +33,7 @@ try: proc foo() = assert(false) foo() -except AssertionDefect: +except AssertionError: let e = getCurrentException() let trace = e.getStackTrace - if tmatch(trace, expected): echo true - else: echo "wrong trace:\n" & trace + echo tmatch(trace, expected) diff --git a/tests/assert/tdoassert.nim b/tests/assert/tdoassert.nim new file mode 100644 index 000000000..fa9893505 --- /dev/null +++ b/tests/assert/tdoassert.nim @@ -0,0 +1,20 @@ +discard """ + cmd: "nim $target -d:release $options $file" + output: ''' +test1:ok +test2:ok +''' +""" + +import testhelper + +onFailedAssert(msg): + checkMsg(msg, "tdoassert.nim(15, 9) `a == 2` foo", "test1") + +var a = 1 +doAssert(a == 2, "foo") + +onFailedAssert(msg): + checkMsg(msg, "tdoassert.nim(20, 10) `a == 3` ", "test2") + +doAssert a == 3 diff --git a/tests/assert/testhelper.nim b/tests/assert/testhelper.nim new file mode 100644 index 000000000..03bdd2468 --- /dev/null +++ b/tests/assert/testhelper.nim @@ -0,0 +1,12 @@ +from strutils import endsWith, split +from os import isAbsolute + +proc checkMsg*(msg, expectedEnd, name: string, absolute = true)= + let filePrefix = msg.split(' ', maxSplit = 1)[0] + if absolute and not filePrefix.isAbsolute: + echo name, ":not absolute: `", msg & "`" + elif not msg.endsWith expectedEnd: + echo name, ":expected suffix:\n`" & expectedEnd & "`\ngot:\n`" & msg & "`" + else: + echo name, ":ok" + diff --git a/tests/assert/trelativeassert.nim b/tests/assert/trelativeassert.nim new file mode 100644 index 000000000..62ab2c421 --- /dev/null +++ b/tests/assert/trelativeassert.nim @@ -0,0 +1,11 @@ +discard """ + cmd: "nim $target $options --excessiveStackTrace:off $file" + output: ''' +test:ok +''' +""" +import testhelper +try: + doAssert(false, "msg") +except AssertionError as e: + checkMsg(e.msg, "trelativeassert.nim(9, 11) `false` msg", "test", false) diff --git a/tests/assign/moverload_asgn2.nim b/tests/assign/moverload_asgn2.nim index cfea48cd1..6620adbeb 100644 --- a/tests/assign/moverload_asgn2.nim +++ b/tests/assign/moverload_asgn2.nim @@ -1,7 +1,3 @@ -discard """ - matrix: "--mm:refc" -""" - type Concrete* = object a*, b*: string diff --git a/tests/assign/tassign.nim b/tests/assign/tassign.nim index fdec04d22..0589b0214 100644 --- a/tests/assign/tassign.nim +++ b/tests/assign/tassign.nim @@ -80,7 +80,7 @@ block tcopy: block tgenericassign: type - TAny {.pure.} = object + TAny = object {.pure.} value: pointer rawType: pointer @@ -93,9 +93,9 @@ block tgenericassign: var ret: seq[tuple[name: string, a: TAny]] = @[] for i in 0 .. 8000: var tup = ($name, newAny(nil, nil)) - doAssert(tup[0] == "example") + assert(tup[0] == "example") ret.add(tup) - doAssert(ret[ret.len()-1][0] == "example") + assert(ret[ret.len()-1][0] == "example") @@ -178,7 +178,7 @@ when false: proc `=`[T](d: var GenericT[T]; src: GenericT[T]) = shallowCopy(d.a, src.a) shallowCopy(d.b, src.b) - echo "GenericT[T] '=' ", typeof(T).name + echo "GenericT[T] '=' ", type(T).name var ag: GenericT[int] var bg: GenericT[int] diff --git a/tests/assign/tobject_assign.nim b/tests/assign/tobject_assign.nim deleted file mode 100644 index 8e39ead53..000000000 --- a/tests/assign/tobject_assign.nim +++ /dev/null @@ -1,49 +0,0 @@ -# bug #16706 - -block: # reduced example - type - A = object of RootObj - a0: string - B = object - b0: seq[A] - var c = newSeq[A](2) - var d = B(b0: c) - -when true: # original example - import std/[options, tables, times] - - type - Data* = object - shifts*: OrderedTable[int64, Shift] - balance*: float - - Shift* = object - quoted*: bool - date*: DateTime - description*: string - start*: Option[DateTime] - finish*: Option[DateTime] - breakTime*: Option[Duration] - rate*: float - qty: Option[float] - id*: int64 - - let shift = Shift( - quoted: true, - date: parse("2000-01-01", "yyyy-MM-dd"), - description: "abcdef", - start: none(DateTime), - finish: none(DateTime), - breakTime: none(Duration), - rate: 462.11, - qty: some(10.0), - id: getTime().toUnix() - ) - - var shifts: OrderedTable[int64, Shift] - shifts[shift.id] = shift - - discard Data( - shifts: shifts, - balance: 0.00 - ) diff --git a/tests/ast_pattern_matching.nim b/tests/ast_pattern_matching.nim index 0ba0aa57a..c08234b9e 100644 --- a/tests/ast_pattern_matching.nim +++ b/tests/ast_pattern_matching.nim @@ -133,8 +133,8 @@ proc matchLengthKind*(arg: NimNode; kind: NimNodeKind; length: int): MatchingErr matchLengthKind(arg, {kind}, length) proc matchValue(arg: NimNode; kind: set[NimNodeKind]; value: SomeInteger): MatchingError {.compileTime.} = - template kindFail: bool = not(kind.card == 0 or arg.kind in kind) - template valueFail: bool = arg.intVal != int(value) + let kindFail = not(kind.card == 0 or arg.kind in kind) + let valueFail = arg.intVal != int(value) if kindFail or valueFail: result.node = arg result.kind = WrongKindValue @@ -561,7 +561,7 @@ when isMainModule: echo "got the ident m" testRecCase: - type Obj[T] {.inheritable.} = object + type Obj[T] = object {.inheritable.} name: string case isFat: bool of true: diff --git a/tests/astspec/tastspec.nim b/tests/astspec/tastspec.nim index c99d8ec79..e2cfed277 100644 --- a/tests/astspec/tastspec.nim +++ b/tests/astspec/tastspec.nim @@ -327,43 +327,19 @@ static: testArrayAccessOperator(x[y]) + + ## Parentheses scope: + let ast = myquote: - (a + b) * c + (1, 2, (3)) ast.matchAst: - of nnkInfix(ident"*", nnkPar(nnkInfix(ident"+", ident"a", ident"b")), ident"c"): - echo "parentheses ok" + of nnkPar(nnkIntLit(intVal = 1), nnkIntLit(intVal = 2), nnkPar(nnkIntLit(intVal = 3))): + echo "ok" - ## Tuple Constructors - - scope: - let ast = myquote: - (1, 2, 3) - (a: 1, b: 2, c: 3) - (1,) - (a: 1) - () - - for it in ast: - echo it.lispRepr - it.matchAst: - of nnkTupleConstr(nnkIntLit(intVal = 1), nnkIntLit(intVal = 2), nnkIntLit(intVal = 3)): - echo "simple tuple ok" - of nnkTupleConstr( - nnkExprColonExpr(ident"a", nnkIntLit(intVal = 1)), - nnkExprColonExpr(ident"b", nnkIntLit(intVal = 2)), - nnkExprColonExpr(ident"c", nnkIntLit(intVal = 3)) - ): - echo "named tuple ok" - of nnkTupleConstr(nnkIntLit(intVal = 1)): - echo "one tuple ok" - of nnkTupleConstr(nnkExprColonExpr(ident"a", nnkIntLit(intVal = 1))): - echo "named one tuple ok" - of nnkTupleConstr(): - echo "empty tuple ok" ## Curly braces @@ -871,20 +847,11 @@ static: scope: macro testRecCase(ast: untyped): untyped = - ast.peelOff({nnkStmtList, nnkTypeSection}).matchAst: - of nnkTypeDef( - nnkPragmaExpr( - ident"Obj", - nnkPragma(ident"inheritable") + ast.peelOff({nnkStmtList, nnkTypeSection})[2].matchAst: + of nnkObjectTy( + nnkPragma( + ident"inheritable" ), - nnkGenericParams( - nnkIdentDefs( - ident"T", - nnkEmpty(), - nnkEmpty()) - ), - nnkObjectTy( - nnkEmpty(), nnkEmpty(), nnkRecList( # list of object parameters nnkIdentDefs( @@ -923,7 +890,6 @@ static: ident"T" ), nnkEmpty() - ) ) ) ) @@ -932,8 +898,10 @@ static: ): echo "ok" + + testRecCase: - type Obj[T] {.inheritable.} = object + type Obj[T] = object {.inheritable.} name: string case isFat: bool of true: diff --git a/tests/async/nim.cfg b/tests/async/nim.cfg deleted file mode 100644 index be50f572c..000000000 --- a/tests/async/nim.cfg +++ /dev/null @@ -1 +0,0 @@ ---experimental:strictEffects diff --git a/tests/async/t11558.nim b/tests/async/t11558.nim deleted file mode 100644 index 99961e7b6..000000000 --- a/tests/async/t11558.nim +++ /dev/null @@ -1,13 +0,0 @@ -discard """ -output: "Hello\n9" -""" -import std/asyncdispatch - -proc foo(): Future[string] {.async.} = - "Hello" - -proc bar(): Future[int] {.async.} = - result = 9 - -echo waitFor foo() -echo waitFor bar() diff --git a/tests/async/t12221.nim b/tests/async/t12221.nim index e8bd9c11a..a6ccfb060 100644 --- a/tests/async/t12221.nim +++ b/tests/async/t12221.nim @@ -1,13 +1,13 @@ import asyncdispatch, os, times proc doubleSleep(hardSleep: int) {.async.} = - await sleepAsync(50) + await sleepAsync(100) sleep(hardSleep) template assertTime(target, timeTook: float): untyped {.dirty.} = - doAssert(timeTook*1000 > target - 1000, "Took too short, should've taken " & + assert(timeTook*1000 > target - 1000, "Took too short, should've taken " & $target & "ms, but took " & $(timeTook*1000) & "ms") - doAssert(timeTook*1000 < target + 1000, "Took too long, should've taken " & + assert(timeTook*1000 < target + 1000, "Took too long, should've taken " & $target & "ms, but took " & $(timeTook*1000) & "ms") var @@ -16,25 +16,37 @@ var # NOTE: this uses poll(3000) to limit timing error potential. start = epochTime() -fut = sleepAsync(40) and sleepAsync(100) and doubleSleep(20) +fut = sleepAsync(50) and sleepAsync(150) and doubleSleep(40) while not fut.finished: - poll(1000) + poll(3000) assertTime(150, epochTime() - start) start = epochTime() -fut = sleepAsync(40) and sleepAsync(100) and doubleSleep(50) +fut = sleepAsync(50) and sleepAsync(150) and doubleSleep(100) while not fut.finished: - poll(1000) + poll(3000) assertTime(200, epochTime() - start) start = epochTime() -fut = sleepAsync(40) and sleepAsync(100) and doubleSleep(20) and sleepAsync(200) +fut = sleepAsync(50) and sleepAsync(150) and doubleSleep(40) and sleepAsync(300) while not fut.finished: - poll(1000) + poll(3000) assertTime(300, epochTime() - start) start = epochTime() -fut = (sleepAsync(40) and sleepAsync(100) and doubleSleep(20)) or sleepAsync(300) +fut = sleepAsync(50) and sleepAsync(150) and doubleSleep(100) and sleepAsync(300) while not fut.finished: - poll(1000) + poll(3000) +assertTime(300, epochTime() - start) + +start = epochTime() +fut = (sleepAsync(50) and sleepAsync(150) and doubleSleep(40)) or sleepAsync(700) +while not fut.finished: + poll(3000) assertTime(150, epochTime() - start) + +start = epochTime() +fut = (sleepAsync(50) and sleepAsync(150) and doubleSleep(100)) or sleepAsync(700) +while not fut.finished: + poll(3000) +assertTime(200, epochTime() - start) diff --git a/tests/async/t13889.nim b/tests/async/t13889.nim deleted file mode 100644 index fe75fe38a..000000000 --- a/tests/async/t13889.nim +++ /dev/null @@ -1,27 +0,0 @@ -discard """ - output: ''' -believer Foo is saved:true -believer Bar is saved:true -believer Baz is saved:true -''' -""" - -import asyncdispatch - -var - promise = newFuture[bool]() - -proc believers(name: string) {.async.} = - let v = await promise - echo "believer " & name & " is saved:" & $v - -asyncCheck believers("Foo") -asyncCheck believers("Bar") -asyncCheck believers("Baz") - -proc savior() {.async.} = - await sleepAsync(50) - complete(promise, true) - await sleepAsync(50) # give enough time to see who was saved - -waitFor(savior()) diff --git a/tests/async/t14820.nim b/tests/async/t14820.nim deleted file mode 100644 index 359884468..000000000 --- a/tests/async/t14820.nim +++ /dev/null @@ -1,25 +0,0 @@ -discard """ -output: ''' -iteration: 1 -iteration: 2 -iteration: 3 -iteration: 4 -async done -iteration: 5 -''' -""" - -import asyncdispatch, times - -var done = false -proc somethingAsync() {.async.} = - yield sleepAsync 5000 - echo "async done" - done = true - -asyncCheck somethingAsync() -var count = 0 -while not done: - count += 1 - drain 1000 - echo "iteration: ", count diff --git a/tests/async/t15148.nim b/tests/async/t15148.nim deleted file mode 100644 index ba14c1157..000000000 --- a/tests/async/t15148.nim +++ /dev/null @@ -1,12 +0,0 @@ -import asyncdispatch, asyncfile, os - -const Filename = "t15148.txt" - -proc saveEmpty() {.async.} = - let - text = "" - file = openAsync(Filename, fmWrite) - await file.write(text) - file.close() - -waitFor saveEmpty() diff --git a/tests/async/t15804.nim b/tests/async/t15804.nim deleted file mode 100644 index 8de012196..000000000 --- a/tests/async/t15804.nim +++ /dev/null @@ -1,15 +0,0 @@ -import asyncdispatch - -type - Foo*[E] = ref object - op: proc(): Future[bool] {.gcsafe.} - -proc newFoo*[E](): Foo[E] = - result = Foo[E]() - result.op = proc(): Future[bool] {.gcsafe,async.} = - await sleepAsync(100) - result = false - -when isMainModule: - let f = newFoo[int]() - echo waitFor f.op() diff --git a/tests/async/t20111.nim b/tests/async/t20111.nim deleted file mode 100644 index 0aaa7d886..000000000 --- a/tests/async/t20111.nim +++ /dev/null @@ -1,19 +0,0 @@ -discard """ - action: "run" -""" -import asyncdispatch -type - Sync = object - Async = object - SyncRes = (Sync, string) - AsyncRes = (Async, string) - -proc foo(val: Sync | Async): Future[(Async, string) | (Sync, string)] {.multisync.} = - return (val, "hello") - -let - myAsync = Async() - mySync = Sync() - -doAssert typeof(waitFor foo(myAsync)) is AsyncRes -doAssert typeof(foo(mySync)) is SyncRes diff --git a/tests/async/t21447.nim b/tests/async/t21447.nim deleted file mode 100644 index e4f7ae31f..000000000 --- a/tests/async/t21447.nim +++ /dev/null @@ -1,6 +0,0 @@ -discard """ - action: "compile" - cmd: "nim c -d:release -d:futureLogging $file" -""" - -import std/asyncdispatch diff --git a/tests/async/t6846.nim b/tests/async/t6846.nim index 7fe38f3b3..687a3f865 100644 --- a/tests/async/t6846.nim +++ b/tests/async/t6846.nim @@ -6,10 +6,11 @@ discard """ import asyncdispatch import asyncfile +import times var asyncStdout = 1.AsyncFD.newAsyncFile() proc doStuff: Future[void] {.async.} = await asyncStdout.write "hello world\n" let fut = doStuff() -doAssert fut.finished, "Poll is needed unnecessarily. See #6846." +doAssert fut.finished, "Poll is needed unnecessarily. See #6846." \ No newline at end of file diff --git a/tests/async/t7758.nim b/tests/async/t7758.nim index fe6d32ad3..ce4df1fc9 100644 --- a/tests/async/t7758.nim +++ b/tests/async/t7758.nim @@ -1,9 +1,7 @@ import asyncdispatch -import std/unittest proc task() {.async.} = - const tSleep = 40 - await sleepAsync(tSleep) + await sleepAsync(40) proc main() = var counter = 0 @@ -12,10 +10,6 @@ proc main() = inc(counter) poll(10) - const slack = 1 - # because there is overhead in `async` + `sleepAsync` - # as can be seen by increasing `tSleep` from 40 to 49, which increases the number - # of failures. - check counter <= 4 + slack + doAssert counter <= 4 for i in 0 .. 10: main() diff --git a/tests/async/tacceptcloserace.nim b/tests/async/tacceptcloserace.nim index fee6537d2..cbb5b5098 100644 --- a/tests/async/tacceptcloserace.nim +++ b/tests/async/tacceptcloserace.nim @@ -8,7 +8,7 @@ import asyncdispatch, net, os, nativesockets # bug: https://github.com/nim-lang/Nim/issues/5279 proc setupServerSocket(hostname: string, port: Port): AsyncFD = - let fd = createNativeSocket() + let fd = newNativeSocket() if fd == osInvalidSocket: raiseOSError(osLastError()) setSockOptInt(fd, SOL_SOCKET, SO_REUSEADDR, 1) @@ -30,7 +30,7 @@ for i in 0..100: if not fut.failed: fut.read().closeSocket() - var fd = createAsyncNativeSocket() + var fd = newAsyncNativeSocket() waitFor fd.connect("localhost", port) serverFd.closeSocket() fd.closeSocket() diff --git a/tests/async/tasync_gcsafe.nim b/tests/async/tasync_gcsafe.nim index bc0eb4271..89df6456a 100644 --- a/tests/async/tasync_gcsafe.nim +++ b/tests/async/tasync_gcsafe.nim @@ -7,7 +7,7 @@ discard """ ''' """ -doAssert compileOption("threads"), "this test will not do anything useful without --threads:on" +assert compileOption("threads"), "this test will not do anything useful without --threads:on" import asyncdispatch diff --git a/tests/async/tasync_gcunsafe.nim b/tests/async/tasync_gcunsafe.nim index f3e6bc691..55b66aaef 100644 --- a/tests/async/tasync_gcunsafe.nim +++ b/tests/async/tasync_gcunsafe.nim @@ -1,10 +1,10 @@ discard """ - errormsg: "'anotherGCSafeAsyncProc (Async)' is not GC-safe as it calls 'asyncGCUnsafeProc'" + errormsg: "'anotherGCSafeAsyncProcIter' is not GC-safe as it calls 'asyncGCUnsafeProc'" cmd: "nim c --threads:on $file" file: "asyncmacro.nim" """ -doAssert compileOption("threads"), "this test will not do anything useful without --threads:on" +assert compileOption("threads"), "this test will not do anything useful without --threads:on" import asyncdispatch diff --git a/tests/async/tasync_misc.nim b/tests/async/tasync_misc.nim index ec1418e8c..1febdedb3 100644 --- a/tests/async/tasync_misc.nim +++ b/tests/async/tasync_misc.nim @@ -1,14 +1,19 @@ +discard """ + exitcode: 0 + output: "ok" +""" + import json, asyncdispatch block: #6100 let done = newFuture[int]() done.complete(1) proc asyncSum: Future[int] {.async.} = - for _ in 1..1_000_000: + for _ in 1..10_000_000: result += await done let res = waitFor asyncSum() - doAssert(res == 1_000_000) + doAssert(res == 10000000) block: #7985 proc getData(): Future[JsonNode] {.async.} = @@ -48,36 +53,4 @@ block: # nkCheckedFieldExpr waitFor foo() -block: # 12743 - - template templ = await sleepAsync 0 - - proc prc {.async.} = templ - - waitFor prc() - -block: # issue #13899 - proc someConnect() {.async.} = - await sleepAsync(1) - proc someClose() {.async.} = - await sleepAsync(2) - proc testFooFails(): Future[bool] {.async.} = - await someConnect() - defer: - await someClose() - result = true - proc testFooSucceed(): Future[bool] {.async.} = - try: - await someConnect() - finally: - await someClose() - result = true - doAssert waitFor testFooSucceed() - doAssert waitFor testFooFails() - -block: # issue #9313 - doAssert compiles(block: - proc a() {.async.} = - echo "Hi" - quit(0) - ) +echo "ok" diff --git a/tests/async/tasync_noasync.nim b/tests/async/tasync_noasync.nim deleted file mode 100644 index 0927148bf..000000000 --- a/tests/async/tasync_noasync.nim +++ /dev/null @@ -1,44 +0,0 @@ -discard """ - cmd: "nim check --hints:off --warnings:off $file" - action: "reject" - nimout: ''' -tasync_noasync.nim(21, 10) Error: Can only 'await' inside a proc marked as 'async'. Use 'waitFor' when calling an 'async' proc in a non-async scope instead -tasync_noasync.nim(25, 12) Error: Can only 'await' inside a proc marked as 'async'. Use 'waitFor' when calling an 'async' proc in a non-async scope instead -tasync_noasync.nim(28, 10) Error: Can only 'await' inside a proc marked as 'async'. Use 'waitFor' when calling an 'async' proc in a non-async scope instead -tasync_noasync.nim(31, 10) Error: Can only 'await' inside a proc marked as 'async'. Use 'waitFor' when calling an 'async' proc in a non-async scope instead -tasync_noasync.nim(35, 10) Error: Can only 'await' inside a proc marked as 'async'. Use 'waitFor' when calling an 'async' proc in a non-async scope instead -tasync_noasync.nim(38, 10) Error: Can only 'await' inside a proc marked as 'async'. Use 'waitFor' when calling an 'async' proc in a non-async scope instead -tasync_noasync.nim(40, 8) Error: Can only 'await' inside a proc marked as 'async'. Use 'waitFor' when calling an 'async' proc in a non-async scope instead -''' -""" -import async - -proc a {.async.} = - discard - -# Bad await usage -proc nonAsyncProc = - await a() - -proc nestedNonAsyncProc {.async.} = - proc nested = - await a() - -iterator customIterator: int = - await a() - -macro awaitInMacro = - await a() - -type DummyRef = ref object of RootObj -method awaitInMethod(_: DummyRef) {.base.} = - await a() - -proc improperMultisync {.multisync.} = - await a() - -await a() - -# if we overload a fallback handler to get -# await only available within {.async.} -# we would need `{.dirty.}` templates for await diff --git a/tests/async/tasync_nofuture.nim b/tests/async/tasync_nofuture.nim deleted file mode 100644 index 16155601a..000000000 --- a/tests/async/tasync_nofuture.nim +++ /dev/null @@ -1,11 +0,0 @@ -discard """ - errormsg: "await expects Future[T], got int" - cmd: "nim c $file" - file: "asyncmacro.nim" -""" -import async - -proc a {.async.} = - await 0 - -waitFor a() diff --git a/tests/async/tasync_traceback.nim b/tests/async/tasync_traceback.nim index 98f71b192..7cfbd563f 100644 --- a/tests/async/tasync_traceback.nim +++ b/tests/async/tasync_traceback.nim @@ -1,5 +1,6 @@ discard """ exitcode: 0 + disabled: "windows" output: "Matched" """ import asyncdispatch, strutils @@ -67,56 +68,80 @@ import re const expected = """ b failure Async traceback: - tasync_traceback\.nim\(\d+?\) tasync_traceback - tasync_traceback\.nim\(\d+?\) a \(Async\) - tasync_traceback\.nim\(\d+?\) b \(Async\) + tasync_traceback\.nim\(\d+?\)\s+?tasync_traceback + asyncmacro\.nim\(\d+?\)\s+?a + asyncmacro\.nim\(\d+?\)\s+?aNimAsyncContinue + ## Resumes an async procedure + tasync_traceback\.nim\(\d+?\)\s+?aIter + asyncmacro\.nim\(\d+?\)\s+?b + asyncmacro\.nim\(\d+?\)\s+?bNimAsyncContinue + ## Resumes an async procedure + tasync_traceback\.nim\(\d+?\)\s+?bIter + #\[ + tasync_traceback\.nim\(\d+?\)\s+?tasync_traceback + asyncmacro\.nim\(\d+?\)\s+?a + asyncmacro\.nim\(\d+?\)\s+?aNimAsyncContinue + ## Resumes an async procedure + tasync_traceback\.nim\(\d+?\)\s+?aIter + asyncfutures\.nim\(\d+?\)\s+?read + \]# Exception message: b failure - +Exception type: bar failure Async traceback: - tasync_traceback\.nim\(\d+?\) tasync_traceback - asyncdispatch\.nim\(\d+?\) waitFor - asyncdispatch\.nim\(\d+?\) poll + tasync_traceback\.nim\(\d+?\)\s+?tasync_traceback + asyncdispatch\.nim\(\d+?\)\s+?waitFor + asyncdispatch\.nim\(\d+?\)\s+?poll ## Processes asynchronous completion events - asyncdispatch\.nim\(\d+?\) runOnce - asyncdispatch\.nim\(\d+?\) processPendingCallbacks + asyncdispatch\.nim\(\d+?\)\s+?runOnce + asyncdispatch\.nim\(\d+?\)\s+?processPendingCallbacks ## Executes pending callbacks - tasync_traceback\.nim\(\d+?\) bar \(Async\) + asyncmacro\.nim\(\d+?\)\s+?barNimAsyncContinue + ## Resumes an async procedure + tasync_traceback\.nim\(\d+?\)\s+?barIter + #\[ + tasync_traceback\.nim\(\d+?\)\s+?tasync_traceback + asyncdispatch\.nim\(\d+?\)\s+?waitFor + asyncdispatch\.nim\(\d+?\)\s+?poll + ## Processes asynchronous completion events + asyncdispatch\.nim\(\d+?\)\s+?runOnce + asyncdispatch\.nim\(\d+?\)\s+?processPendingCallbacks + ## Executes pending callbacks + asyncmacro\.nim\(\d+?\)\s+?fooNimAsyncContinue + ## Resumes an async procedure + tasync_traceback\.nim\(\d+?\)\s+?fooIter + asyncfutures\.nim\(\d+?\)\s+?read + \]# Exception message: bar failure - +Exception type: """ -# TODO: is asyncmacro good enough location for fooIter traceback/debugging? just put the callsite info for all? - let resLines = splitLines(result.strip) let expLines = splitLines(expected.strip) -when not defined(cpp): # todo fixme - if resLines.len != expLines.len: - echo("Not matched! Wrong number of lines!") - echo expLines.len - echo resLines.len - echo("Expected: -----------") - echo expected - echo("Gotten: -------------") - echo result - echo("---------------------") - quit(QuitFailure) +if resLines.len != expLines.len: + echo("Not matched! Wrong number of lines!") + echo expLines.len + echo resLines.len + echo("Expected: -----------") + echo expected + echo("Gotten: -------------") + echo result + echo("---------------------") + quit(QuitFailure) - var ok = true - for i in 0 ..< resLines.len: - if not resLines[i].match(re(expLines[i])): - echo "Not matched! Line ", i + 1 - echo "Expected:" - echo expLines[i] - echo "Actual:" - echo resLines[i] - ok = false +var ok = true +for i in 0 ..< resLines.len: + if not resLines[i].match(re(expLines[i])): + echo "Not matched! Line ", i + 1 + echo "Expected:" + echo expLines[i] + echo "Actual:" + echo resLines[i] + ok = false - if ok: - echo("Matched") - else: - quit(QuitFailure) -else: +if ok: echo("Matched") +else: + quit(QuitFailure) diff --git a/tests/async/tasyncawait.nim b/tests/async/tasyncawait.nim index e86542b2d..b1f893489 100644 --- a/tests/async/tasyncawait.nim +++ b/tests/async/tasyncawait.nim @@ -1,10 +1,13 @@ -import asyncdispatch, asyncnet, nativesockets, net, strutils -from stdtest/netutils import bindAvailablePort +discard """ + output: "5000" +""" +import asyncdispatch, asyncnet, nativesockets, net, strutils, os + var msgCount = 0 const - swarmSize = 40 - messagesToSend = 50 + swarmSize = 50 + messagesToSend = 100 var clientCount = 0 @@ -34,23 +37,31 @@ proc readMessages(client: AsyncFD) {.async.} = clientCount.inc break else: - if line.startsWith("Message "): + if line.startswith("Message "): msgCount.inc else: doAssert false -proc createServer(server: AsyncFD) {.async.} = +proc createServer(port: Port) {.async.} = + var server = createAsyncNativeSocket() + block: + var name: Sockaddr_in + name.sin_family = typeof(name.sin_family)(toInt(AF_INET)) + name.sin_port = htons(uint16(port)) + name.sin_addr.s_addr = htonl(INADDR_ANY) + if bindAddr(server.SocketHandle, cast[ptr SockAddr](addr(name)), + sizeof(name).Socklen) < 0'i32: + raiseOSError(osLastError()) + discard server.SocketHandle.listen() while true: asyncCheck readMessages(await accept(server)) -let server = createAsyncNativeSocket() -let port = bindAvailablePort(server.SocketHandle) -asyncCheck createServer(server) -asyncCheck launchSwarm(port) +asyncCheck createServer(Port(10335)) +asyncCheck launchSwarm(Port(10335)) while true: poll() if clientCount == swarmSize: break -doAssert msgCount == swarmSize * messagesToSend -doAssert msgCount == 2000 +assert msgCount == swarmSize * messagesToSend +echo msgCount diff --git a/tests/async/tasyncawait_cyclebreaker.nim b/tests/async/tasyncawait_cyclebreaker.nim new file mode 100644 index 000000000..1eb2c4676 --- /dev/null +++ b/tests/async/tasyncawait_cyclebreaker.nim @@ -0,0 +1,73 @@ +discard """ + output: "50000" + cmd: "nim c -d:nimTypeNames -d:nimCycleBreaker $file" +""" +import asyncdispatch, asyncnet, nativesockets, net, strutils, os + +var msgCount = 0 + +const + swarmSize = 500 + messagesToSend = 100 + +var clientCount = 0 + +proc sendMessages(client: AsyncFD) {.async.} = + for i in 0 ..< messagesToSend: + await send(client, "Message " & $i & "\c\L") + +proc launchSwarm(port: Port) {.async.} = + for i in 0 ..< swarmSize: + var sock = createAsyncNativeSocket() + + await connect(sock, "localhost", port) + await sendMessages(sock) + closeSocket(sock) + +proc readMessages(client: AsyncFD) {.async.} = + # wrapping the AsyncFd into a AsyncSocket object + var sockObj = newAsyncSocket(client) + var (ipaddr, port) = sockObj.getPeerAddr() + doAssert ipaddr == "127.0.0.1" + (ipaddr, port) = sockObj.getLocalAddr() + doAssert ipaddr == "127.0.0.1" + while true: + var line = await recvLine(sockObj) + if line == "": + closeSocket(client) + clientCount.inc + break + else: + if line.startswith("Message "): + msgCount.inc + else: + doAssert false + +proc createServer(port: Port) {.async.} = + var server = createAsyncNativeSocket() + block: + var name: Sockaddr_in + name.sin_family = typeof(name.sin_family)(toInt(AF_INET)) + name.sin_port = htons(uint16(port)) + name.sin_addr.s_addr = htonl(INADDR_ANY) + if bindAddr(server.SocketHandle, cast[ptr SockAddr](addr(name)), + sizeof(name).Socklen) < 0'i32: + raiseOSError(osLastError()) + + discard server.SocketHandle.listen() + while true: + asyncCheck readMessages(await accept(server)) + +asyncCheck createServer(Port(10335)) +asyncCheck launchSwarm(Port(10335)) +while true: + poll() + GC_collectZct() + + let (allocs, deallocs) = getMemCounters() + doAssert allocs < deallocs + 1000 + + if clientCount == swarmSize: break + +assert msgCount == swarmSize * messagesToSend +echo msgCount diff --git a/tests/async/tasyncclosestall.nim b/tests/async/tasyncclosestall.nim index d1c7a5fba..be8a13b98 100644 --- a/tests/async/tasyncclosestall.nim +++ b/tests/async/tasyncclosestall.nim @@ -99,3 +99,4 @@ proc server() {.async.} = when isMainModule: waitFor server() + diff --git a/tests/async/tasyncconnect.nim b/tests/async/tasyncconnect.nim index 564f6c67c..f63a87990 100644 --- a/tests/async/tasyncconnect.nim +++ b/tests/async/tasyncconnect.nim @@ -18,7 +18,7 @@ when defined(windows) or defined(nimdoc): quit("Error: unhandled exception: Connection refused") else: proc testAsyncConnect() {.async.} = - var s = createAsyncNativeSocket() + var s = newAsyncNativeSocket() await s.connect(testHost, testPort) diff --git a/tests/async/tasyncdial.nim b/tests/async/tasyncdial.nim index f0377dfd5..bbff7028d 100644 --- a/tests/async/tasyncdial.nim +++ b/tests/async/tasyncdial.nim @@ -3,6 +3,7 @@ discard """ OK AF_INET OK AF_INET6 ''' + disabled: "travis" """ import @@ -12,7 +13,7 @@ proc setupServerSocket(hostname: string, port: Port, domain: Domain): AsyncFD = ## Creates a socket, binds it to the specified address, and starts listening for connections. ## Registers the descriptor with the dispatcher of the current thread ## Raises OSError in case of an error. - let fd = createNativeSocket(domain) + let fd = newNativeSocket(domain) setSockOptInt(fd, SOL_SOCKET, SO_REUSEADDR, 1) var aiList = getAddrInfo(hostname, port, domain) if bindAddr(fd, aiList.ai_addr, aiList.ai_addrlen.Socklen) < 0'i32: diff --git a/tests/async/tasynceagain.nim b/tests/async/tasynceagain.nim deleted file mode 100644 index 94c3645dc..000000000 --- a/tests/async/tasynceagain.nim +++ /dev/null @@ -1,67 +0,0 @@ -discard """ - disabled: "windows" - exitcode: 0 -""" -# AsyncSocketBug.nim -# Jens Alfke (@snej) -- 16 July 2020 -# Demonstrates data loss by Nim's AsyncSocket. -# Just run it, and it will raise an assertion failure within a minute. - -import asyncdispatch, asyncnet, strformat, strutils, sugar - -const FrameSize = 9999 # Exact size not important, but larger sizes fail quicker - -proc runServer() {.async.} = - # Server side: - var server = newAsyncSocket() - server.bindAddr(Port(9001)) - server.listen() - let client = await server.accept() - echo "Server got client connection" - var lastN = 0 - while true: - let frame = await client.recv(FrameSize) - doAssert frame.len == FrameSize - let n = frame[0..<6].parseInt() - echo "RCVD #", n, ": ", frame[0..80], "..." - if n != lastN + 1: - echo &"******** ERROR: Server received #{n}, but last was #{lastN}!" - doAssert n == lastN + 1 - lastN = n - await sleepAsync 100 - - -proc main() {.async.} = - asyncCheck runServer() - - # Client side: - let socket = newAsyncSocket(buffered = false) - await socket.connect("localhost", Port(9001)) - echo "Client socket connected" - - var sentCount = 0 - var completedCount = 0 - - while sentCount < 2000: - sentCount += 1 - let n = sentCount - - var message = &"{n:06} This is message #{n} of ∞. Please stay tuned for more. " - #echo ">>> ", message - while message.len < FrameSize: - message = message & message - let frame = message[0.. 0 - else: doAssert cond(), $msgCount + assert msgCount == swarmSize * messagesToSend + echo msgCount diff --git a/tests/async/tasynctry.nim b/tests/async/tasynctry.nim index 25eab87fb..a7cb5223d 100644 --- a/tests/async/tasynctry.nim +++ b/tests/async/tasynctry.nim @@ -5,7 +5,6 @@ Specific except Multiple idents in except Multiple except branches Multiple except branches 2 -success ''' targets: "c" """ @@ -15,7 +14,7 @@ import asyncdispatch, strutils proc foobar() {.async.} = if 5 == 5: - raise newException(IndexDefect, "Test") + raise newException(IndexError, "Test") proc catch() {.async.} = # TODO: Create a test for when exceptions are not caught. @@ -26,26 +25,26 @@ proc catch() {.async.} = try: await foobar() - except IndexDefect: + except IndexError: echo("Specific except") try: await foobar() - except OSError, FieldDefect, IndexDefect: + except OSError, FieldError, IndexError: echo("Multiple idents in except") try: await foobar() - except OSError, FieldDefect: + except OSError, FieldError: assert false - except IndexDefect: + except IndexError: echo("Multiple except branches") try: await foobar() - except IndexDefect: + except IndexError: echo("Multiple except branches 2") - except OSError, FieldDefect: + except OSError, FieldError: assert false waitFor catch() @@ -102,17 +101,3 @@ assert y.waitFor() == 2 y = test4() assert y.waitFor() == 2 - -# bug #14279 - -proc expandValue: Future[int] {.async.} = - return 0 - -proc a(b: int): Future[void] {.async.} = - return - -proc b: Future[void] {.async.} = - await a(await expandValue()) - echo "success" - -waitFor(b()) diff --git a/tests/async/tbreak_must_exec_finally.nim b/tests/async/tbreak_must_exec_finally.nim deleted file mode 100644 index 8780e6149..000000000 --- a/tests/async/tbreak_must_exec_finally.nim +++ /dev/null @@ -1,25 +0,0 @@ -discard """ - output: ''' -finally handler 8 -do not duplicate this one -''' -""" - -# bug #15243 - -import asyncdispatch - -proc f() {.async.} = - try: - while true: - try: - await sleepAsync(400) - break - finally: - var localHere = 8 - echo "finally handler ", localHere - finally: - echo "do not duplicate this one" - -when isMainModule: - waitFor f() diff --git a/tests/async/tdiscardableproc.nim b/tests/async/tdiscardableproc.nim deleted file mode 100644 index 93cd83be9..000000000 --- a/tests/async/tdiscardableproc.nim +++ /dev/null @@ -1,9 +0,0 @@ -discard """ - errormsg: "Cannot make async proc discardable. Futures have to be checked with `asyncCheck` instead of discarded" -""" - -import async - -proc foo {.async, discardable.} = discard - -foo() diff --git a/tests/async/testmanyasyncevents.nim b/tests/async/testmanyasyncevents.nim index 9fdd01b4f..5a103736f 100644 --- a/tests/async/testmanyasyncevents.nim +++ b/tests/async/testmanyasyncevents.nim @@ -1,9 +1,8 @@ discard """ output: ''' hasPendingOperations: false -triggerCount: 100 +triggerCount: 100 ''' -disabled: "windows" """ import asyncDispatch diff --git a/tests/async/tfuturestream.nim b/tests/async/tfuturestream.nim index a019df400..b5772d5ac 100644 --- a/tests/async/tfuturestream.nim +++ b/tests/async/tfuturestream.nim @@ -17,7 +17,7 @@ var fs = newFutureStream[int]() proc alpha() {.async.} = for i in 0 .. 5: await fs.write(i) - await sleepAsync(100) + await sleepAsync(200) echo("Done") fs.complete() diff --git a/tests/async/tfuturevar.nim b/tests/async/tfuturevar.nim index b70f1d166..9e3134261 100644 --- a/tests/async/tfuturevar.nim +++ b/tests/async/tfuturevar.nim @@ -1,3 +1,8 @@ +discard """ +action: compile +""" +# XXX: action should be run! + import asyncdispatch proc completeOnReturn(fut: FutureVar[string], x: bool) {.async.} = diff --git a/tests/async/tioselectors.nim b/tests/async/tioselectors.nim index 77d03f8f6..e172e1452 100644 --- a/tests/async/tioselectors.nim +++ b/tests/async/tioselectors.nim @@ -10,8 +10,10 @@ template processTest(t, x: untyped) = #stdout.flushFile() if not x: echo(t & " FAILED\r\n") -when not defined(windows): - import os, posix, nativesockets +when defined(macosx): + echo "All tests passed!" +elif not defined(windows): + import os, posix, nativesockets, times when ioselSupportedPlatform: import osproc @@ -145,16 +147,15 @@ when not defined(windows): proc timer_notification_test(): bool = var selector = newSelector[int]() var timer = selector.registerTimer(100, false, 0) - var rc1 = selector.select(10000) - var rc2 = selector.select(10000) - # if this flakes, see tests/m14634.nim - assert len(rc1) == 1 and len(rc2) == 1, $(len(rc1), len(rc2)) + var rc1 = selector.select(140) + var rc2 = selector.select(140) + assert(len(rc1) == 1 and len(rc2) == 1) selector.unregister(timer) discard selector.select(0) selector.registerTimer(100, true, 0) - var rc4 = selector.select(10000) - var rc5 = selector.select(1000) # this will be an actual wait, keep it small - assert len(rc4) == 1 and len(rc5) == 0, $(len(rc4), len(rc5)) + var rc4 = selector.select(120) + var rc5 = selector.select(120) + assert(len(rc4) == 1 and len(rc5) == 0) assert(selector.isEmpty()) selector.close() result = true @@ -234,7 +235,7 @@ when not defined(windows): if fd == -1: raiseOsError(osLastError()) let length = len(data).cint - if posix.write(fd, cast[pointer](addr data[0]), + if posix.write(fd, cast[pointer](unsafeAddr data[0]), len(data).cint) != length: raiseOsError(osLastError()) if posix.close(fd) == -1: @@ -288,8 +289,8 @@ when not defined(windows): events: set[Event] proc vnode_test(): bool = - proc validate(test: openArray[ReadyKey], - check: openArray[valType]): bool = + proc validate(test: openarray[ReadyKey], + check: openarray[valType]): bool = result = false if len(test) == len(check): for checkItem in check: @@ -444,7 +445,7 @@ when not defined(windows): var thr: array[0..7, Thread[SelectEvent]] var selector = newSelector[int]() - var sock = createNativeSocket() + var sock = newNativeSocket() var event = newSelectEvent() for i in 0..high(thr): createThread(thr[i], event_wait_thread, event) @@ -474,7 +475,7 @@ else: proc socket_notification_test(): bool = proc create_test_socket(): SocketHandle = - var sock = createNativeSocket() + var sock = newNativeSocket() setBlocking(sock, false) result = sock diff --git a/tests/async/tjsandnativeasync.nim b/tests/async/tjsandnativeasync.nim index c4db3bcfb..45839899f 100644 --- a/tests/async/tjsandnativeasync.nim +++ b/tests/async/tjsandnativeasync.nim @@ -19,7 +19,7 @@ else: proc foo() {.async.} = echo "hi" var s = epochTime() - await sleepAsync(200) + await sleepAsync(500) var e = epochTime() doAssert(e - s > 0.1) echo "bye" diff --git a/tests/async/tnewasyncudp.nim b/tests/async/tnewasyncudp.nim index 68de796a0..feab46319 100644 --- a/tests/async/tnewasyncudp.nim +++ b/tests/async/tnewasyncudp.nim @@ -40,9 +40,9 @@ proc launchSwarm(name: ptr SockAddr) {.async.} = var saddr = Sockaddr_in() while i < swarmSize: var peeraddr = prepareAddress(INADDR_LOOPBACK, 0) - var sock = createAsyncNativeSocket(nativesockets.AF_INET, - nativesockets.SOCK_DGRAM, - Protocol.IPPROTO_UDP) + var sock = newAsyncNativeSocket(nativesockets.AF_INET, + nativesockets.SOCK_DGRAM, + Protocol.IPPROTO_UDP) if bindAddr(sock.SocketHandle, cast[ptr SockAddr](peeraddr), sizeof(Sockaddr_in).Socklen) < 0'i32: raiseOSError(osLastError()) @@ -58,7 +58,7 @@ proc launchSwarm(name: ptr SockAddr) {.async.} = 16384, cast[ptr SockAddr](addr saddr), addr slen) size = 0 - var grammString = $cast[cstring](addr buffer) + var grammString = $cstring(addr buffer) if grammString == message: saveSendingPort(sockport) inc(recvCount) @@ -80,8 +80,8 @@ proc readMessages(server: AsyncFD) {.async.} = 16384, cast[ptr SockAddr](addr(saddr)), addr(slen)) size = 0 - var grammString = $cast[cstring](addr buffer) - if grammString.startsWith("Message ") and + var grammString = $cstring(addr buffer) + if grammString.startswith("Message ") and saddr.sin_addr.s_addr == nativesockets.ntohl(INADDR_LOOPBACK.uint32): await sendTo(server, addr grammString[0], len(grammString), cast[ptr SockAddr](addr saddr), slen) @@ -91,9 +91,9 @@ proc readMessages(server: AsyncFD) {.async.} = proc createServer() {.async.} = var name = prepareAddress(INADDR_LOOPBACK, serverPort) - var server = createAsyncNativeSocket(nativesockets.AF_INET, - nativesockets.SOCK_DGRAM, - Protocol.IPPROTO_UDP) + var server = newAsyncNativeSocket(nativesockets.AF_INET, + nativesockets.SOCK_DGRAM, + Protocol.IPPROTO_UDP) if bindAddr(server.SocketHandle, cast[ptr SockAddr](name), sizeof(Sockaddr_in).Socklen) < 0'i32: raiseOSError(osLastError()) diff --git a/tests/async/tpendingcheck.nim b/tests/async/tpendingcheck.nim index 4eceb0353..a5537d8cb 100644 --- a/tests/async/tpendingcheck.nim +++ b/tests/async/tpendingcheck.nim @@ -7,7 +7,7 @@ import asyncdispatch doAssert(not hasPendingOperations()) proc test() {.async.} = - await sleepAsync(50) + await sleepAsync(100) var f = test() while not f.finished: diff --git a/tests/async/tupcoming_async.nim b/tests/async/tupcoming_async.nim index 0b6e53454..da98fc4d8 100644 --- a/tests/async/tupcoming_async.nim +++ b/tests/async/tupcoming_async.nim @@ -45,7 +45,7 @@ when defined(upcoming): poll() proc eventTest5298() = - # Event must raise `AssertionDefect` if event was unregistered twice. + # Event must raise `AssertionError` if event was unregistered twice. # Issue #5298. let e = newAsyncEvent() var eventReceived = false @@ -57,7 +57,7 @@ when defined(upcoming): poll() try: e.unregister() - except AssertionDefect: + except AssertionError: discard e.close() diff --git a/tests/async/twinasyncrw.nim b/tests/async/twinasyncrw.nim index ad27ca38f..db10fffce 100644 --- a/tests/async/twinasyncrw.nim +++ b/tests/async/twinasyncrw.nim @@ -1,6 +1,9 @@ +discard """ + output: "5000" +""" when defined(windows): import asyncdispatch, nativesockets, net, strutils, os, winlean - from stdtest/netutils import bindAvailablePort + var msgCount = 0 const @@ -205,7 +208,7 @@ when defined(windows): proc launchSwarm(port: Port) {.async.} = for i in 0 ..< swarmSize: - var sock = createNativeSocket() + var sock = newNativeSocket() setBlocking(sock, false) await winConnect(AsyncFD(sock), "localhost", port) @@ -220,24 +223,34 @@ when defined(windows): clientCount.inc break else: - if line.startsWith("Message "): + if line.startswith("Message "): msgCount.inc else: doAssert false - proc createServer(server: SocketHandle) {.async.} = + proc createServer(port: Port) {.async.} = + var server = newNativeSocket() + setBlocking(server, false) + block: + var name = Sockaddr_in() + name.sin_family = toInt(Domain.AF_INET).uint16 + name.sin_port = htons(uint16(port)) + name.sin_addr.s_addr = htonl(INADDR_ANY) + if bindAddr(server, cast[ptr SockAddr](addr(name)), + sizeof(name).Socklen) < 0'i32: + raiseOSError(osLastError()) + discard server.listen() while true: asyncCheck readMessages(await winAccept(AsyncFD(server))) - var server = createNativeSocket() - setBlocking(server, false) - let port = bindAvailablePort(server) - asyncCheck createServer(server) - asyncCheck launchSwarm(port) + asyncCheck createServer(Port(10335)) + asyncCheck launchSwarm(Port(10335)) while true: poll() if clientCount == swarmSize: break assert msgCount == swarmSize * messagesToSend - doAssert msgCount == 5000 + echo msgCount +else: + echo(5000) diff --git a/tests/avr/nim.cfg b/tests/avr/nim.cfg deleted file mode 100644 index d6eba8eda..000000000 --- a/tests/avr/nim.cfg +++ /dev/null @@ -1,12 +0,0 @@ -avr.standalone.gcc.path = "/usr/bin" -avr.standalone.gcc.exe = "avr-gcc" -avr.standalone.gcc.linkerexe = "avr-gcc" -passC = "-Os" -passC = "-DF_CPU=16000000UL" -passC = "-mmcu=atmega328p" -passL = "-mmcu=atmega328p" -passC = "-flto" -passL = "-flto" -cpu = "avr" -deadCodeElim = "on" -gc = "arc" diff --git a/tests/avr/panicoverride.nim b/tests/avr/panicoverride.nim deleted file mode 100644 index 770933ddd..000000000 --- a/tests/avr/panicoverride.nim +++ /dev/null @@ -1,13 +0,0 @@ -proc printf(frmt: cstring) {.varargs, importc, header: "", cdecl.} -proc exit(code: int) {.importc, header: "", cdecl.} - -{.push stack_trace: off, profiler:off.} - -proc rawoutput(s: string) = - printf("%s\n", s) - -proc panic(s: string) = - rawoutput(s) - exit(1) - -{.pop.} diff --git a/tests/avr/thello.nim b/tests/avr/thello.nim deleted file mode 100644 index 7ebaeae5f..000000000 --- a/tests/avr/thello.nim +++ /dev/null @@ -1,6 +0,0 @@ -discard """ - cmd: "nim c --compileOnly --os:standalone --exceptions:quirky -d:noSignalHandler -d:danger --threads:off $file" - action: "compile" -""" - -echo "hi" diff --git a/tests/benchmarks/readme.md b/tests/benchmarks/readme.md deleted file mode 100644 index 1e744fc40..000000000 --- a/tests/benchmarks/readme.md +++ /dev/null @@ -1,5 +0,0 @@ -# Collection of benchmarks - -In future work, benchmarks can be added to CI, but for now we provide benchmarks that can be run locally. - -See RFC: https://github.com/timotheecour/Nim/issues/425 diff --git a/tests/benchmarks/ttls.nim b/tests/benchmarks/ttls.nim deleted file mode 100644 index f5314850f..000000000 --- a/tests/benchmarks/ttls.nim +++ /dev/null @@ -1,30 +0,0 @@ -discard """ - action: compile -""" - -#[ -## on osx -nim r -d:danger --threads --tlsEmulation:off tests/benchmarks/ttls.nim -9.999999999992654e-07 - -ditto with `--tlsEmulation:on`: -0.216999 -]# - -import times - -proc main2(): int = - var g0 {.threadvar.}: int - g0.inc - result = g0 - -proc main = - let n = 100_000_000 - var c = 0 - let t = cpuTime() - for i in 0.." + errormsg: "type mismatch: got " line: 10 """ diff --git a/tests/bind/tnicerrorforsymchoice.nim b/tests/bind/tnicerrorforsymchoice.nim index 6001b6b09..684b83239 100644 --- a/tests/bind/tnicerrorforsymchoice.nim +++ b/tests/bind/tnicerrorforsymchoice.nim @@ -1,5 +1,5 @@ discard """ - errormsg: "type mismatch: got " + errormsg: "type mismatch: got " line: 23 """ diff --git a/tests/borrow/tborrow.nim b/tests/borrow/tborrow.nim index 35652e2e0..ee0d0194d 100644 --- a/tests/borrow/tborrow.nim +++ b/tests/borrow/tborrow.nim @@ -1,6 +1,5 @@ discard """ - output: '''4887 true -0.5''' + output: "4887 true" """ # test the new borrow feature that works with generics: @@ -20,72 +19,3 @@ proc `$`(x: DI): string {.borrow.} proc `$`(x: DF): string {.borrow.} echo 4544.DI ++ 343.DI, " ", (4.5.DF ++ 0.5.DF).float == 5.0 - -# issue #14440 - -type Radians = distinct float64 - -func `-=`(a: var Radians, b: Radians) {.borrow.} - -var a = Radians(1.5) -let b = Radians(1.0) - -a -= b - -echo a.float64 - -block: #14449 - type - Foo[T] = object - foo: T - - Bar[T] {.borrow:`.`.} = distinct Foo[T] - SomeThing {.borrow:`.`.} = distinct Foo[float] - OtherThing {.borrow:`.`.} = distinct SomeThing - - var - a: Bar[int] - b: SomeThing - c: OtherThing - a.foo = 300 - b.foo = 400 - c.foo = 42 - assert a.foo == 300 - assert b.foo == 400d - assert c.foo == 42d - -block: # Borrow from muliple aliasses #16666 - type - AImpl = object - i: int - - A = AImpl - - B {.borrow: `.`.} = distinct A - C = B - D {.borrow: `.`.} = distinct C - E {.borrow: `.`.} = distinct D - - let - b = default(B) - d = default(D) - e = default(E) - - assert b.i == 0 - assert d.i == 0 - assert e.i == 0 - -block: # Borrow from generic alias - type - AImpl[T] = object - i: T - B[T] = AImpl[T] - C {.borrow: `.`.} = distinct B[int] - D = B[float] - E {.borrow: `.`.} = distinct D - - let - c = default(C) - e = default(E) - assert c.i == int(0) - assert e.i == 0d \ No newline at end of file diff --git a/tests/borrow/tinvalidborrow.nim b/tests/borrow/tinvalidborrow.nim index 08148608d..89aa4e2e8 100644 --- a/tests/borrow/tinvalidborrow.nim +++ b/tests/borrow/tinvalidborrow.nim @@ -1,25 +1,16 @@ discard """ - cmd: "nim check --hints:off --warnings:off $file" - action: "reject" - nimout:''' -tinvalidborrow.nim(18, 3) Error: only a 'distinct' type can borrow `.` -tinvalidborrow.nim(19, 3) Error: only a 'distinct' type can borrow `.` -tinvalidborrow.nim(20, 1) Error: no symbol to borrow from found -''' + errormsg: "no symbol to borrow from found" + line: 11 """ # bug #516 type TAtom = culong - Test {.borrow:`.`.} = distinct int - Foo[T] = object - a: int - Bar[T] {.borrow:`.`.} = Foo[T] - OtherFoo {.borrow:`.`.} = Foo[int] + proc `==`*(a, b: TAtom): bool {.borrow.} var d, e: TAtom -discard( $(d == e) ) +echo( $(d == e) ) diff --git a/tests/borrow/typeclassborrow.nim b/tests/borrow/typeclassborrow.nim deleted file mode 100644 index ee0b07829..000000000 --- a/tests/borrow/typeclassborrow.nim +++ /dev/null @@ -1,48 +0,0 @@ -type - Foo = distinct seq[int] - Bar[N: static[int]] = distinct seq[int] - Baz = distinct Bar[10] - -proc newSeq(s: var Foo, n: Natural) {.borrow.} -proc newSeq(s: var Bar, n: Natural) {.borrow.} -proc newSeq(s: var Baz, n: Natural) {.borrow.} - - -proc `$`(s: Foo): string {.borrow.} -proc `$`(s: Bar): string {.borrow.} -proc `$`(s: Baz): string {.borrow.} - -proc doThing(b: Bar) = discard -proc doThing(b: Baz) {.borrow.} - -var - foo: Foo - bar: Bar[10] - baz: Baz - -newSeq(foo, 100) -newSeq(bar, bar.N) -newSeq(baz, 10) - -bar.doThing() -baz.doThing() - -assert $seq[int](foo) == $foo -assert $seq[int](bar) == $bar -assert $seq[int](baz) == $baz - -type - Fine* = distinct string - -proc `==`*(x, y: Fine): bool {.borrow.} = - ## Here is the documentation - runnableExamples: - var x = Fine("1234") - var y = Fine("1234") - doAssert x == y - doAssert false - - -var x = Fine("1234") -var y = Fine("1234") -doAssert x == y diff --git a/tests/arc/tcomputedgoto.nim b/tests/casestmt/t12785.nim similarity index 77% rename from tests/arc/tcomputedgoto.nim rename to tests/casestmt/t12785.nim index 541a748c6..bf0f30d42 100644 --- a/tests/arc/tcomputedgoto.nim +++ b/tests/casestmt/t12785.nim @@ -1,7 +1,13 @@ discard """ - cmd: '''nim c --gc:arc $file''' - output: '''2 -2''' + cmd: '''nim c --newruntime $file''' + output: '''copied +copied +2 +copied +copied +2 +destroyed +destroyed''' """ type @@ -31,9 +37,9 @@ proc test(a: range[0..1], arg: ObjWithDestructor) = inc iteration case a - of 0: - assert false - of 1: + of 0: + assert false + of 1: echo b if iteration == 2: break diff --git a/tests/casestmt/t18964.nim b/tests/casestmt/t18964.nim deleted file mode 100644 index 1d2de2bbc..000000000 --- a/tests/casestmt/t18964.nim +++ /dev/null @@ -1,12 +0,0 @@ -discard """ -errormsg: "invalid order of case branches" -""" - -import macros - -macro genCase(val: string): untyped = - result = nnkCaseStmt.newTree(val, - nnkElse.newTree(quote do: echo "else"), - nnkOfBranch.newTree(newLit("miauz"), quote do: echo "first branch")) - -genCase("miauz") diff --git a/tests/casestmt/tcaseexpr1.nim b/tests/casestmt/tcaseexpr1.nim index 4f5bbf100..3d4b6c087 100644 --- a/tests/casestmt/tcaseexpr1.nim +++ b/tests/casestmt/tcaseexpr1.nim @@ -1,23 +1,17 @@ discard """ - cmd: "nim check $options $file" - action: "reject" - nimout: ''' -tcaseexpr1.nim(33, 10) Error: not all cases are covered; missing: {C} -tcaseexpr1.nim(39, 12) Error: type mismatch: got but expected 'int literal(10)' -''' + errormsg: "type mismatch: got but expected 'int'" + line: 33 + file: "tcaseexpr1.nim" + + errormsg: "not all cases are covered; missing: {C}" + line: 27 + file: "tcaseexpr1.nim" """ +# NOTE: This spec is wrong. Spec doesn't support multiple error +# messages. The first one is simply overridden by the second one. +# This just has never been noticed. - - - - - - - - - -# line 20 type E = enum A, B, C diff --git a/tests/casestmt/tcasestmt.nim b/tests/casestmt/tcasestmt.nim index 3a4907494..b7454ef99 100644 --- a/tests/casestmt/tcasestmt.nim +++ b/tests/casestmt/tcasestmt.nim @@ -184,33 +184,33 @@ block tcasestm: doAssert(bstatic == false) var bb: bool - doAssert(not compiles( + doassert(not compiles( bb = case str2: of "": raise newException(ValueError, "Invalid boolean") elif str.startsWith("Y"): true elif str.startsWith("N"): false )) - doAssert(not compiles( + doassert(not compiles( bb = case str2: of "Y": true of "N": false )) - doAssert(not compiles( + doassert(not compiles( bb = case str2: of "Y": true of "N": raise newException(ValueError, "N not allowed") )) - doAssert(not compiles( + doassert(not compiles( bb = case str2: of "Y": raise newException(ValueError, "Invalid Y") else: raise newException(ValueError, "Invalid N") )) - doAssert(not compiles( + doassert(not compiles( bb = case str2: of "Y": raise newException(ValueError, "Invalid Y") @@ -219,7 +219,7 @@ block tcasestm: )) - doAssert(not compiles( + doassert(not compiles( bb = case str2: of "Y": "invalid Y".quit(3) @@ -250,51 +250,3 @@ proc negativeOrNot(num: int): string = doAssert negativeOrNot(-1) == "negative" doAssert negativeOrNot(10000000) == "zero or positive" doAssert negativeOrNot(0) == "zero or positive" - -######################################################## -# issue #13490 -import strutils -func foo(input: string): int = - try: - parseInt(input) - except: - return - -func foo2(b, input: string): int = - case b: - of "Y": - for c in input: - result = if c in '0'..'9': parseInt($c) - else: break - of "N": - for c in input: - result = if c in '0'..'9': parseInt($c) - else: continue - else: return - - -static: - doAssert(foo("3") == 3) - doAssert(foo("a") == 0) - doAssert(foo2("Y", "a2") == 0) - doAssert(foo2("Y", "2a") == 2) - doAssert(foo2("N", "a3") == 3) - doAssert(foo2("z", "2") == 0) - -doAssert(foo("3") == 3) -doAssert(foo("a") == 0) -doAssert(foo2("Y", "a2") == 0) -doAssert(foo2("Y", "2a") == 2) -doAssert(foo2("N", "a3") == 3) -doAssert(foo2("z", "2") == 0) - - -# bug #20031 -proc main(a: uint64) = - case a - else: - discard - -static: - main(10) -main(10) diff --git a/tests/casestmt/tcstring.nim b/tests/casestmt/tcstring.nim deleted file mode 100644 index 288373402..000000000 --- a/tests/casestmt/tcstring.nim +++ /dev/null @@ -1,52 +0,0 @@ -discard """ - targets: "c cpp js" -""" - -type Result = enum none, a, b, c, d, e, f - -proc foo1(x: cstring): Result = - const y = cstring"hash" - const arr = [cstring"it", cstring"finally"] - result = none - case x - of "Andreas", "Rumpf": result = a - of cstring"aa", "bb": result = b - of "cc", y, "when": result = c - of "will", arr, "be", "generated": result = d - of nil: result = f - -var results = [ - foo1("Rumpf"), foo1("Andreas"), - foo1("aa"), foo1(cstring"bb"), - foo1("cc"), foo1("hash"), - foo1("finally"), foo1("generated"), - foo1("no"), foo1("another no"), - foo1(nil)] -doAssert results == [a, a, b, b, c, c, d, d, none, none, f], $results - -proc foo2(x: cstring): Result = - const y = cstring"hash" - const arr = [cstring"it", cstring"finally"] - doAssert not (compiles do: - result = case x - of "Andreas", "Rumpf": a - of cstring"aa", "bb": b - of "cc", y, "when": c - of "will", arr, "be", "generated": d) - case x - of "Andreas", "Rumpf": a - of cstring"aa", "bb": b - of "cc", y, "when": c - of "will", arr, "be", "generated": d - of nil: f - else: e - -results = [ - foo2("Rumpf"), foo2("Andreas"), - foo2("aa"), foo2(cstring"bb"), - foo2("cc"), foo2("hash"), - foo2("finally"), foo2("generated"), - foo2("no"), foo2("another no"), - foo2(nil)] - -doAssert results == [a, a, b, b, c, c, d, d, e, e, f], $results diff --git a/tests/casestmt/tincompletecaseobject.nim b/tests/casestmt/tincompletecaseobject.nim index aa5deda7a..909ee4e1c 100644 --- a/tests/casestmt/tincompletecaseobject.nim +++ b/tests/casestmt/tincompletecaseobject.nim @@ -1,6 +1,6 @@ discard """ errormsg: ''' -not all cases are covered; missing: {nnkComesFrom, nnkDotCall, nnkHiddenCallConv, nnkVarTuple, nnkCurlyExpr, nnkRange, nnkCheckedFieldExpr, nnkDerefExpr, nnkElifExpr, nnkElseExpr, nnkLambda, nnkDo, nnkBind, nnkClosedSymChoice, nnkHiddenSubConv, nnkConv, nnkStaticExpr, nnkAddr, nnkHiddenAddr, nnkHiddenDeref, nnkObjDownConv, nnkObjUpConv, nnkChckRangeF, nnkChckRange64, nnkChckRange, nnkStringToCString, nnkCStringToString, nnkFastAsgn, nnkGenericParams, nnkFormalParams, nnkOfInherit, nnkImportAs, nnkConverterDef, nnkMacroDef, nnkTemplateDef, nnkIteratorDef, nnkOfBranch, nnkElifBranch, nnkExceptBranch, nnkElse, nnkAsmStmt, nnkTypeDef, nnkFinally, nnkContinueStmt, nnkImportStmt, nnkImportExceptStmt, nnkExportStmt, nnkExportExceptStmt, nnkFromStmt, nnkIncludeStmt, nnkUsingStmt, nnkBlockExpr, nnkStmtListType, nnkBlockType, nnkWith, nnkWithout, nnkTypeOfExpr, nnkObjectTy, nnkTupleTy, nnkTupleClassTy, nnkTypeClassTy, nnkStaticTy, nnkRecList, nnkRecCase, nnkRecWhen, nnkVarTy, nnkConstTy, nnkMutableTy, nnkDistinctTy, nnkProcTy, nnkIteratorTy, nnkSharedTy, nnkEnumTy, nnkEnumFieldDef, nnkArgList, nnkPattern, nnkReturnToken, nnkClosure, nnkGotoState, nnkState, nnkBreakState, nnkFuncDef, nnkTupleConstr} +not all cases are covered; missing: {nnkComesFrom, nnkDotCall, nnkHiddenCallConv, nnkVarTuple, nnkCurlyExpr, nnkRange, nnkCheckedFieldExpr, nnkDerefExpr, nnkElifExpr, nnkElseExpr, nnkLambda, nnkDo, nnkBind, nnkClosedSymChoice, nnkHiddenSubConv, nnkConv, nnkStaticExpr, nnkAddr, nnkHiddenAddr, nnkHiddenDeref, nnkObjDownConv, nnkObjUpConv, nnkChckRangeF, nnkChckRange64, nnkChckRange, nnkStringToCString, nnkCStringToString, nnkFastAsgn, nnkGenericParams, nnkFormalParams, nnkOfInherit, nnkImportAs, nnkConverterDef, nnkMacroDef, nnkTemplateDef, nnkIteratorDef, nnkOfBranch, nnkElifBranch, nnkExceptBranch, nnkElse, nnkAsmStmt, nnkTypeDef, nnkFinally, nnkContinueStmt, nnkImportStmt, nnkImportExceptStmt, nnkExportStmt, nnkExportExceptStmt, nnkFromStmt, nnkIncludeStmt, nnkUsingStmt, nnkBlockExpr, nnkStmtListType, nnkBlockType, nnkWith, nnkWithout, nnkTypeOfExpr, nnkObjectTy, nnkTupleTy, nnkTupleClassTy, nnkTypeClassTy, nnkStaticTy, nnkRecList, nnkRecCase, nnkRecWhen, nnkVarTy, nnkConstTy, nnkMutableTy, nnkDistinctTy, nnkProcTy, nnkIteratorTy, nnkSharedTy, nnkEnumTy, nnkEnumFieldDef, nnkArglist, nnkPattern, nnkReturnToken, nnkClosure, nnkGotoState, nnkState, nnkBreakState, nnkFuncDef, nnkTupleConstr} ''' """ @@ -62,7 +62,7 @@ type nnkSharedTy, # 'shared T' nnkEnumTy, nnkEnumFieldDef, - nnkArgList, nnkPattern + nnkArglist, nnkPattern nnkReturnToken, nnkClosure, nnkGotoState, diff --git a/tests/casestmt/tincompletecaseobject2.nim b/tests/casestmt/tincompletecaseobject2.nim index bbeae1909..c080cfeb1 100644 --- a/tests/casestmt/tincompletecaseobject2.nim +++ b/tests/casestmt/tincompletecaseobject2.nim @@ -1,5 +1,12 @@ discard """ cmd: "nim check $file" +errormsg: "not all cases are covered; missing: {A, B}" +nimout: ''' +tincompletecaseobject2.nim(18, 1) Error: not all cases are covered; missing: {' ', '!', '\"', '#', '$', '%', '&', '\'', '*', '+', ',', '-', '.', '/', ':', ';', '<', '=', '>', '?', '@', '[', '\\', ']', '^', '_', '`', '{', '|', '}', '~'} +tincompletecaseobject2.nim(22, 1) Error: not all cases are covered; missing: {B, C, D} +tincompletecaseobject2.nim(25, 1) Error: not all cases are covered; missing: {A, C} +tincompletecaseobject2.nim(28, 1) Error: not all cases are covered; missing: {A, B} +''' """ type ABCD = enum A, B, C, D @@ -8,19 +15,15 @@ type AliasRangeABC = RangeABC PrintableChars = range[' ' .. '~'] -case PrintableChars 'x': #[tt.Error -^ not all cases are covered; missing: {' ', '!', '\"', '#', '$$', '%', '&', '\'', '*', '+', ',', '-', '.', '/', ':', ';', '<', '=', '>', '?', '@', '[', '\\', ']', '^', '_', '`', '{', '|', '}', '~'}]# +case PrintableChars 'x': of '0'..'9', 'A'..'Z', 'a'..'z': discard of '(', ')': discard -case AliasABCD A: #[tt.Error -^ not all cases are covered; missing: {B, C, D}]# +case AliasABCD A: of A: discard -case RangeABC A: #[tt.Error -^ not all cases are covered; missing: {A, C}]# +case RangeABC A: of B: discard -case AliasRangeABC A: #[tt.Error -^ not all cases are covered; missing: {A, B}]# +case AliasRangeABC A: of C: discard diff --git a/tests/ccgbugs/m1/defs.nim b/tests/ccgbugs/m1/defs.nim deleted file mode 100644 index ed78d8b72..000000000 --- a/tests/ccgbugs/m1/defs.nim +++ /dev/null @@ -1,4 +0,0 @@ -type MyObj* = object - field1*: int - s*: string - ch*: char diff --git a/tests/ccgbugs/m19445.c b/tests/ccgbugs/m19445.c deleted file mode 100644 index 74c23d4b4..000000000 --- a/tests/ccgbugs/m19445.c +++ /dev/null @@ -1,3 +0,0 @@ -#include "m19445.h" - -const Foo f = {10, 20, 30, 40}; \ No newline at end of file diff --git a/tests/ccgbugs/m2/defs.nim b/tests/ccgbugs/m2/defs.nim deleted file mode 100644 index 798d1fea8..000000000 --- a/tests/ccgbugs/m2/defs.nim +++ /dev/null @@ -1,4 +0,0 @@ -type MyObj* = object - s*: string - field1*: int - ch*: char diff --git a/tests/ccgbugs/mstatic_assert.nim b/tests/ccgbugs/mstatic_assert.nim deleted file mode 100644 index dbf9c03d1..000000000 --- a/tests/ccgbugs/mstatic_assert.nim +++ /dev/null @@ -1,6 +0,0 @@ -{.emit:""" -NIM_STATIC_ASSERT(sizeof(bool) == 1, ""); -#warning "foo2" -NIM_STATIC_ASSERT(sizeof(bool) == 2, ""); -#warning "foo3" -""".} diff --git a/tests/ccgbugs/t10128.nim b/tests/ccgbugs/t10128.nim deleted file mode 100644 index 48970916f..000000000 --- a/tests/ccgbugs/t10128.nim +++ /dev/null @@ -1,18 +0,0 @@ -# bug #10128 -let data = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz" -var seq2 = newSeq[char](data.len) -for i in 0.. 0: - BlockSlotId.init(x.bid, x.slot) - else: - BlockSlotId.init(x.bid, x.slot) - doAssert x.bid.root.data[0] == 42 - -bug19613() diff --git a/tests/ccgbugs/tcodegenbug1.nim b/tests/ccgbugs/tcodegenbug1.nim index d2ab97ede..ebdc57144 100644 --- a/tests/ccgbugs/tcodegenbug1.nim +++ b/tests/ccgbugs/tcodegenbug1.nim @@ -1,13 +1,9 @@ discard """ - matrix: "--mm:refc" output: '''obj = (inner: (kind: Just, id: 7)) obj.inner.id = 7 id = 7 obj = (inner: (kind: Just, id: 7)) -2 -(a: "a", b: "b", c: "") -caught -(a: "a", b: "b", c: "")''' +2''' """ # bug #6960 @@ -133,53 +129,12 @@ import macros func myfunc(obj: MyObject): MyResult {.raises: [].} = template index: auto = case obj.kind: - of Float: $obj.index + of Float: $obj.index of Fixed: "Fixed" macro to_str(a: untyped): string = - result = newStrLitNode(a.repr) + result = newStrLitNode(a.repr) result.val[0] = index result.val[1] = to_str(obj.kind + Ola) let x = MyObject(someInt: 10, kind: Fixed) echo myfunc(x).val.len - -# bug #14126 - -type X = object - a, b, c: string - -proc f(): X = - result.a = "a" - result.b = "b" - raise (ref ValueError)() - -proc ohmanNoNRVO = - var x: X - x.a = "1" - x.b = "2" - x.c = "3" - - try: - x = f() - except: - discard - - echo x - # once NVRO is sorted out, x.c == "3" - doAssert x.c == "", "shouldn't modify x if f raises" - -ohmanNoNRVO() - -proc ohmanNoNRVO2(x: var X) = - x.a = "1" - x.c = "3" - x = f() - -var xgg: X -try: - ohmanNoNRVO2(xgg) -except: - echo "caught" -echo xgg -# once NVRO is sorted out, xgg.c == "3" -doAssert xgg.c == "", "this assert will fail" diff --git a/tests/ccgbugs/tcodegenbug_bool.nim b/tests/ccgbugs/tcodegenbug_bool.nim deleted file mode 100644 index a0dbf4eb2..000000000 --- a/tests/ccgbugs/tcodegenbug_bool.nim +++ /dev/null @@ -1,11 +0,0 @@ -discard """ -""" - -# issue #13798 -{.emit:""" -#include -void fun(bool a){} -""".} - -proc fun(a: bool) {.importc.} -fun(true) diff --git a/tests/ccgbugs/tcompile_time_var_at_runtime.nim b/tests/ccgbugs/tcompile_time_var_at_runtime.nim deleted file mode 100644 index c0de0390b..000000000 --- a/tests/ccgbugs/tcompile_time_var_at_runtime.nim +++ /dev/null @@ -1,11 +0,0 @@ -discard """ - output: "1\n2\n2\n3" -""" -var a {.compileTime.} = 1 - -echo a -a = 2 -echo a -echo a -a = 3 -echo a \ No newline at end of file diff --git a/tests/ccgbugs/tctypes.nim b/tests/ccgbugs/tctypes.nim deleted file mode 100644 index be6009115..000000000 --- a/tests/ccgbugs/tctypes.nim +++ /dev/null @@ -1,43 +0,0 @@ -discard """ - targets: "c cpp" - matrix: "--gc:refc; --gc:arc" -""" - -# bug #7308 -proc foo(x: seq[int32]) = - var y = newSeq[cint](1) - -proc bar = - var t = newSeq[int32](1) - foo(t) - -bar() - - -# bug #16246 - -proc testWeirdTypeAliases() = - var values = newSeq[cuint](8) - # var values: seq[cuint] does not produce codegen error - var drawCb = proc(): seq[uint32] = - result = newSeq[uint32](10) - -testWeirdTypeAliases() - -block: # bug #11797 - block: - type cdouble2 = cdouble - type Foo1 = seq[cdouble] - type Foo2 = seq[cdouble2] - static: doAssert Foo1 is Foo2 - var a1: Foo1 - var a2: Foo2 - doAssert a1 == @[] - doAssert a2 == @[] - - block: - proc foo[T: int|cint](fun: proc(): T) = discard - proc foo1(): cint = 1 - proc foo3(): int32 = 2 - foo(proc(): cint = foo1()) - foo(proc(): int32 = foo3()) diff --git a/tests/ccgbugs/tdeepcopy_addr_rval.nim b/tests/ccgbugs/tdeepcopy_addr_rval.nim index 4a0b0deaa..07fb8f8ef 100644 --- a/tests/ccgbugs/tdeepcopy_addr_rval.nim +++ b/tests/ccgbugs/tdeepcopy_addr_rval.nim @@ -1,5 +1,4 @@ discard """ - matrix: "--mm:refc; --mm:orc --deepcopy:on" output: "3" """ diff --git a/tests/ccgbugs/tderefblock.nim b/tests/ccgbugs/tderefblock.nim deleted file mode 100644 index fd21a19b8..000000000 --- a/tests/ccgbugs/tderefblock.nim +++ /dev/null @@ -1,25 +0,0 @@ -discard """ - cmd: "nim c -d:release -d:danger $file" - matrix: ";--gc:orc" - output: "42" -""" - -# bug #20107 - -type Foo = object - a, b, c, d: uint64 - -proc c(i: uint64): Foo = - Foo(a: i, b: i, c: i, d: i) - -func x(f: Foo): lent Foo {.inline.} = - f - -proc m() = - let f = block: - let i = c(42) - x(i) - - echo $f.a - -m() diff --git a/tests/ccgbugs/tforward_decl_only.nim b/tests/ccgbugs/tforward_decl_only.nim index d62c36b18..74fbae303 100644 --- a/tests/ccgbugs/tforward_decl_only.nim +++ b/tests/ccgbugs/tforward_decl_only.nim @@ -1,6 +1,7 @@ discard """ ccodecheck: "\\i !@('struct tyObject_MyRefObject'[0-z]+' {')" ccodecheck: "\\i !@('mymoduleInit')" +ccodecheck: "\\i @('mymoduleDatInit')" output: "hello" """ diff --git a/tests/ccgbugs/thtiobj.nim b/tests/ccgbugs/thtiobj.nim index 6db24dad0..7a656905f 100644 --- a/tests/ccgbugs/thtiobj.nim +++ b/tests/ccgbugs/thtiobj.nim @@ -1,5 +1,4 @@ discard """ - matrix: "--mm:refc" targets: "c cpp" """ diff --git a/tests/ccgbugs2/tinefficient_const_table.nim b/tests/ccgbugs/tinefficient_const_table.nim similarity index 86% rename from tests/ccgbugs2/tinefficient_const_table.nim rename to tests/ccgbugs/tinefficient_const_table.nim index 8ab895cb0..7422d0676 100644 --- a/tests/ccgbugs2/tinefficient_const_table.nim +++ b/tests/ccgbugs/tinefficient_const_table.nim @@ -6,7 +6,7 @@ of words''' cmd: r"nim c --hints:on $options -d:release $file" ccodecheck: "! @'genericSeqAssign'" - targets: "c" + target: "c" """ # bug #4354 @@ -15,7 +15,7 @@ import sets import strutils #const FRUITS = ["banana", "apple", "grapes"] -#let FRUITS = ["banana", "apple", "grapes"].toHashSet +#let FRUITS = ["banana", "apple", "grapes"].toSet const FRUITS = {"banana":0, "apple":0, "grapes":0}.toTable proc main() = diff --git a/tests/ccgbugs/tlvalueconv.nim b/tests/ccgbugs/tlvalueconv.nim deleted file mode 100644 index b2cb11eef..000000000 --- a/tests/ccgbugs/tlvalueconv.nim +++ /dev/null @@ -1,32 +0,0 @@ -discard """ - matrix: "--gc:refc; --gc:arc" -""" - -# bug #14160 - -type - TPassContext = object of RootObj - PPassContext = ref TPassContext - - PCtx = ref object of TPassContext - a: int - - ModuleGraph = object - vm: RootRef - -proc main() = - var g = ModuleGraph(vm: new(Pctx)) - PCtx(g.vm) = nil #This generates invalid C code - doAssert g.vm == nil - -main() - -# bug #14325 - -proc main2() = - var g = ModuleGraph(vm: new(Pctx)) - PPassContext(PCtx(g.vm)) = nil #This compiles, but crashes at runtime with gc:arc - doAssert g.vm == nil - -main2() - diff --git a/tests/ccgbugs/tmangle.nim b/tests/ccgbugs/tmangle.nim deleted file mode 100644 index 0050cef92..000000000 --- a/tests/ccgbugs/tmangle.nim +++ /dev/null @@ -1,16 +0,0 @@ -block: - proc hello() = - let NAN_INFINITY = 12 - doAssert NAN_INFINITY == 12 - let INF = "2.0" - doAssert INF == "2.0" - let NAN = 2.3 - doAssert NAN == 2.3 - - hello() - -block: - proc hello(NAN: float) = - doAssert NAN == 2.0 - - hello(2.0) diff --git a/tests/ccgbugs/tmissingbracket.nim b/tests/ccgbugs/tmissingbracket.nim index 2919efe0e..468e13366 100644 --- a/tests/ccgbugs/tmissingbracket.nim +++ b/tests/ccgbugs/tmissingbracket.nim @@ -11,7 +11,7 @@ type className* : string TClassOfTobj = object of TClassOfTCustomObject nil - TCustomObject {.inheritable.} = ref object + TCustomObject = ref object {.inheritable.} class* : ptr TClassOfTCustomObject TObj = ref object of TCustomObject data: int diff --git a/tests/ccgbugs/tmissingderef.nim b/tests/ccgbugs/tmissingderef.nim index eb7da3023..26418800a 100644 --- a/tests/ccgbugs/tmissingderef.nim +++ b/tests/ccgbugs/tmissingderef.nim @@ -1,5 +1,6 @@ discard """ output: '''[10, 0, 0, 0, 0, 0, 0, 0] + 255 1 1 0.5''' diff --git a/tests/ccgbugs/tmissinginit.nim b/tests/ccgbugs/tmissinginit.nim index 9eb58221c..8806a2f21 100644 --- a/tests/ccgbugs/tmissinginit.nim +++ b/tests/ccgbugs/tmissinginit.nim @@ -1,5 +1,4 @@ discard """ - matrix: "--mm:refc" output: '''0 0 0 diff --git a/tests/ccgbugs/tmissingvolatile.nim b/tests/ccgbugs/tmissingvolatile.nim index b877eff71..60b1771dc 100644 --- a/tests/ccgbugs/tmissingvolatile.nim +++ b/tests/ccgbugs/tmissingvolatile.nim @@ -1,8 +1,8 @@ discard """ output: "1" - cmd: r"nim c --hints:on $options --mm:refc -d:release $file" + cmd: r"nim c --hints:on $options -d:release $file" ccodecheck: "'NI volatile state;'" - targets: "c" + target: "C" """ # bug #1539 diff --git a/tests/ccgbugs/tnoalias.nim b/tests/ccgbugs/tnoalias.nim deleted file mode 100644 index 96c3d390b..000000000 --- a/tests/ccgbugs/tnoalias.nim +++ /dev/null @@ -1,13 +0,0 @@ -discard """ - ccodecheck: "\\i@'NI* NIM_NOALIAS field;' @'NIM_CHAR* NIM_NOALIAS x__0qEngDE9aYoYsF8tWnyPacw,' @'void* NIM_NOALIAS q'" -""" - -type - BigNum = object - field {.noalias.}: ptr UncheckedArray[int] - -proc p(x {.noalias.}: openArray[char]) = - var q {.noalias.}: pointer = addr(x[0]) - -var bn: BigNum -p "abc" diff --git a/tests/ccgbugs/tprogmem.nim b/tests/ccgbugs/tprogmem.nim index 58a20583a..884ca158a 100644 --- a/tests/ccgbugs/tprogmem.nim +++ b/tests/ccgbugs/tprogmem.nim @@ -2,7 +2,7 @@ discard """ output: "5" cmd: r"nim c --hints:on $options -d:release $file" ccodecheck: "'/*PROGMEM*/ myLetVariable = {'" - targets: "c" + target: "C" """ var myLetVariable {.exportc, codegenDecl: "$# /*PROGMEM*/ $#".} = [1, 2, 3] diff --git a/tests/ccgbugs/tissues.nim b/tests/ccgbugs/trecursive_closure.nim similarity index 54% rename from tests/ccgbugs/tissues.nim rename to tests/ccgbugs/trecursive_closure.nim index a0c402cc0..4b6514b90 100644 --- a/tests/ccgbugs/tissues.nim +++ b/tests/ccgbugs/trecursive_closure.nim @@ -16,23 +16,3 @@ f(nil) type A = object #of RootObj <-- Uncomment this to get no errors test: proc(i: A): bool var a: proc(i: A): bool # Or comment this line to get no errors - - -# bug #2703 -type - fooObj[T] = object of RootObj - bazObj[T] = object of fooObj[T] - x: T - -var troz: fooObj[string] -echo bazObj[string](troz).x - - -# bug #14880 -type step = object - exec: proc () - -const pipeline = @[step()] - -let crash = pipeline[0] - diff --git a/tests/ccgbugs/tret_arg_init.nim b/tests/ccgbugs/tret_arg_init.nim index e39e5a0de..5cd67de3e 100644 --- a/tests/ccgbugs/tret_arg_init.nim +++ b/tests/ccgbugs/tret_arg_init.nim @@ -1,8 +1,6 @@ discard """ output: ''' - - ''' """ diff --git a/tests/ccgbugs/tsamename3.nim b/tests/ccgbugs/tsamename3.nim deleted file mode 100644 index a69391e5c..000000000 --- a/tests/ccgbugs/tsamename3.nim +++ /dev/null @@ -1,111 +0,0 @@ -block: # bug #15526 - block: - type Foo = ref object - x1: int - let f1 = Foo(x1: 1) - block: - type Foo = ref object - x2: int - let f2 = Foo(x2: 2) - -block: # ditto - template fn() = - block: - type Foo = ref object - x1: int - let f1 = Foo(x1: 1) - doAssert f1.x1 == 1 - block: - type Foo = ref object - x2: int - let f2 = Foo(x2: 2) - doAssert f2.x2 == 2 - static: fn() - fn() - -block: # bug #17162 - template fn = - var ret: string - block: - type A = enum a0, a1, a2 - for ai in A: - ret.add $ai - block: - type A = enum b0, b1, b2, b3 - for ai in A: - ret.add $ai - doAssert ret == "a0a1a2b0b1b2b3" - - static: fn() # ok - fn() # was bug - -block: # ditto - proc fn = - var ret: string - block: - type A = enum a0, a1, a2 - for ai in A: - ret.add $ai - block: - type A = enum b0, b1, b2, b3 - for ai in A: - ret.add $ai - doAssert ret == "a0a1a2b0b1b2b3" - - static: fn() # ok - fn() # was bug - -block: # bug #5170 - block: - type Foo = object - x1: int - let f1 = Foo(x1: 1) - block: - type Foo = object - x2: int - let f2 = Foo(x2: 2) - -block: # ditto - block: - type Foo = object - bar: bool - var f1: Foo - - block: - type Foo = object - baz: int - var f2: Foo - doAssert f2.baz == 0 - - block: - template fn() = - block: - type Foo = object - x1: int - let f1 = Foo(x1: 1) - doAssert f1.x1 == 1 - block: - type Foo = object - x2: int - let f2 = Foo(x2: 2) - doAssert f2.x2 == 2 - static: fn() - fn() - -when true: # ditto, refs https://github.com/nim-lang/Nim/issues/5170#issuecomment-582712132 - type Foo1 = object # at top level - bar: bool - var f1: Foo1 - - block: - type Foo1 = object - baz: int - var f2: Foo1 - doAssert f2.baz == 0 - -block: # make sure `hashType` doesn't recurse infinitely - type - PFoo = ref object - a, b: PFoo - c: int - var a: PFoo diff --git a/tests/ccgbugs/tuple_canon.nim b/tests/ccgbugs/tuple_canon.nim index fbb971861..aa9605d4b 100644 --- a/tests/ccgbugs/tuple_canon.nim +++ b/tests/ccgbugs/tuple_canon.nim @@ -68,7 +68,7 @@ template odd*(i: int) : untyped = proc vidx(hg: HexGrid; col, row: int; i: HexVtxIndex) : Index = #NOTE: this variation compiles - #var offset : typeof(evenSharingOffsets[i]) + #var offset : type(evenSharingOffsets[i]) # #if odd(col): # offset = oddSharingOffsets[i] diff --git a/tests/ccgbugs/twrong_setconstr.nim b/tests/ccgbugs/twrong_setconstr.nim new file mode 100644 index 000000000..8be0b82b5 --- /dev/null +++ b/tests/ccgbugs/twrong_setconstr.nim @@ -0,0 +1,146 @@ +discard """ + output: "" +""" + +# bug #2880 + +type + TMsgKind* = enum + errUnknown, errIllFormedAstX, errInternal, errCannotOpenFile, errGenerated, + errXCompilerDoesNotSupportCpp, errStringLiteralExpected, + errIntLiteralExpected, errInvalidCharacterConstant, + errClosingTripleQuoteExpected, errClosingQuoteExpected, + errTabulatorsAreNotAllowed, errInvalidToken, errLineTooLong, + errInvalidNumber, errInvalidNumberOctalCode, errNumberOutOfRange, + errNnotAllowedInCharacter, errClosingBracketExpected, errMissingFinalQuote, + errIdentifierExpected, errNewlineExpected, errInvalidModuleName, + errOperatorExpected, errTokenExpected, errStringAfterIncludeExpected, + errRecursiveDependencyX, errOnOrOffExpected, errNoneSpeedOrSizeExpected, + errInvalidPragma, errUnknownPragma, errInvalidDirectiveX, + errAtPopWithoutPush, errEmptyAsm, errInvalidIndentation, + errExceptionExpected, errExceptionAlreadyHandled, + errYieldNotAllowedHere, errYieldNotAllowedInTryStmt, + errInvalidNumberOfYieldExpr, errCannotReturnExpr, errAttemptToRedefine, + errStmtInvalidAfterReturn, errStmtExpected, errInvalidLabel, + errInvalidCmdLineOption, errCmdLineArgExpected, errCmdLineNoArgExpected, + errInvalidVarSubstitution, errUnknownVar, errUnknownCcompiler, + errOnOrOffExpectedButXFound, errOnOffOrListExpectedButXFound, + errNoneBoehmRefcExpectedButXFound, + errNoneSpeedOrSizeExpectedButXFound, errGuiConsoleOrLibExpectedButXFound, + errUnknownOS, errUnknownCPU, errGenOutExpectedButXFound, + errArgsNeedRunOption, errInvalidMultipleAsgn, errColonOrEqualsExpected, + errExprExpected, errUndeclaredIdentifier, errUseQualifier, errTypeExpected, + errSystemNeeds, errExecutionOfProgramFailed, errNotOverloadable, + errInvalidArgForX, errStmtHasNoEffect, errXExpectsTypeOrValue, + errXExpectsArrayType, errIteratorCannotBeInstantiated, errExprXAmbiguous, + errConstantDivisionByZero, errOrdinalTypeExpected, + errOrdinalOrFloatTypeExpected, errOverOrUnderflow, + errCannotEvalXBecauseIncompletelyDefined, errChrExpectsRange0_255, + errDynlibRequiresExportc, errUndeclaredFieldX, errNilAccess, + errIndexOutOfBounds, errIndexTypesDoNotMatch, errBracketsInvalidForType, + errValueOutOfSetBounds, errFieldInitTwice, errFieldNotInit, + errExprXCannotBeCalled, errExprHasNoType, errExprXHasNoType, + errCastNotInSafeMode, errExprCannotBeCastedToX, errCommaOrParRiExpected, + errCurlyLeOrParLeExpected, errSectionExpected, errRangeExpected, + errMagicOnlyInSystem, errPowerOfTwoExpected, + errStringMayNotBeEmpty, errCallConvExpected, errProcOnlyOneCallConv, + errSymbolMustBeImported, errExprMustBeBool, errConstExprExpected, + errDuplicateCaseLabel, errRangeIsEmpty, errSelectorMustBeOfCertainTypes, + errSelectorMustBeOrdinal, errOrdXMustNotBeNegative, errLenXinvalid, + errWrongNumberOfVariables, errExprCannotBeRaised, errBreakOnlyInLoop, + errTypeXhasUnknownSize, errConstNeedsConstExpr, errConstNeedsValue, + errResultCannotBeOpenArray, errSizeTooBig, errSetTooBig, + errBaseTypeMustBeOrdinal, errInheritanceOnlyWithNonFinalObjects, + errInheritanceOnlyWithEnums, errIllegalRecursionInTypeX, + errCannotInstantiateX, errExprHasNoAddress, errXStackEscape, + errVarForOutParamNeeded, + errPureTypeMismatch, errTypeMismatch, errButExpected, errButExpectedX, + errAmbiguousCallXYZ, errWrongNumberOfArguments, + errXCannotBePassedToProcVar, + errXCannotBeInParamDecl, errPragmaOnlyInHeaderOfProc, errImplOfXNotAllowed, + errImplOfXexpected, errNoSymbolToBorrowFromFound, errDiscardValueX, + errInvalidDiscard, errIllegalConvFromXtoY, errCannotBindXTwice, + errInvalidOrderInArrayConstructor, + errInvalidOrderInEnumX, errEnumXHasHoles, errExceptExpected, errInvalidTry, + errOptionExpected, errXisNoLabel, errNotAllCasesCovered, + errUnknownSubstitionVar, errComplexStmtRequiresInd, errXisNotCallable, + errNoPragmasAllowedForX, errNoGenericParamsAllowedForX, + errInvalidParamKindX, errDefaultArgumentInvalid, errNamedParamHasToBeIdent, + errNoReturnTypeForX, errConvNeedsOneArg, errInvalidPragmaX, + errXNotAllowedHere, errInvalidControlFlowX, + errXisNoType, errCircumNeedsPointer, errInvalidExpression, + errInvalidExpressionX, errEnumHasNoValueX, errNamedExprExpected, + errNamedExprNotAllowed, errXExpectsOneTypeParam, + errArrayExpectsTwoTypeParams, errInvalidVisibilityX, errInitHereNotAllowed, + errXCannotBeAssignedTo, errIteratorNotAllowed, errXNeedsReturnType, + errNoReturnTypeDeclared, + errInvalidCommandX, errXOnlyAtModuleScope, + errXNeedsParamObjectType, + errTemplateInstantiationTooNested, errInstantiationFrom, + errInvalidIndexValueForTuple, errCommandExpectsFilename, + errMainModuleMustBeSpecified, + errXExpected, + errTIsNotAConcreteType, + errInvalidSectionStart, errGridTableNotImplemented, errGeneralParseError, + errNewSectionExpected, errWhitespaceExpected, errXisNoValidIndexFile, + errCannotRenderX, errVarVarTypeNotAllowed, errInstantiateXExplicitly, + errOnlyACallOpCanBeDelegator, errUsingNoSymbol, + errMacroBodyDependsOnGenericTypes, + errDestructorNotGenericEnough, + errInlineIteratorsAsProcParams, + errXExpectsTwoArguments, + errXExpectsObjectTypes, errXcanNeverBeOfThisSubtype, errTooManyIterations, + errCannotInterpretNodeX, errFieldXNotFound, errInvalidConversionFromTypeX, + errAssertionFailed, errCannotGenerateCodeForX, errXRequiresOneArgument, + errUnhandledExceptionX, errCyclicTree, errXisNoMacroOrTemplate, + errXhasSideEffects, errIteratorExpected, errLetNeedsInit, + errThreadvarCannotInit, errWrongSymbolX, errIllegalCaptureX, + errXCannotBeClosure, errXMustBeCompileTime, + errCannotInferTypeOfTheLiteral, + errCannotInferReturnType, + errGenericLambdaNotAllowed, + errCompilerDoesntSupportTarget, + errUser, + warnCannotOpenFile, + warnOctalEscape, warnXIsNeverRead, warnXmightNotBeenInit, + warnDeprecated, warnConfigDeprecated, + warnSmallLshouldNotBeUsed, warnUnknownMagic, warnRedefinitionOfLabel, + warnUnknownSubstitutionX, warnLanguageXNotSupported, + warnFieldXNotSupported, warnCommentXIgnored, + warnNilStatement, warnTypelessParam, + warnDifferentHeaps, warnWriteToForeignHeap, warnUnsafeCode, + warnEachIdentIsTuple + warnProveInit, warnProveField, warnProveIndex, warnGcUnsafe, warnGcUnsafe2, + warnUninit, warnGcMem, warnDestructor, warnLockLevel, warnResultShadowed, + warnUser, + hintSuccess, hintSuccessX, + hintLineTooLong, hintXDeclaredButNotUsed, hintConvToBaseNotNeeded, + hintConvFromXtoItselfNotNeeded, hintExprAlwaysX, hintQuitCalled, + hintProcessing, hintCodeBegin, hintCodeEnd, hintConf, hintPath, + hintConditionAlwaysTrue, hintName, hintPattern, + hintExecuting, hintLinking, hintDependency, + hintSource, hintStackTrace, hintGCStats, + hintUser + +const + warnMin = warnCannotOpenFile + hintMax = high(TMsgKind) + +type + TNoteKind = range[warnMin..hintMax] # "notes" are warnings or hints + TNoteKinds = set[TNoteKind] + +const + NotesVerbosityConst: array[0..0, TNoteKinds] = [ + {low(TNoteKind)..high(TNoteKind)} - {hintGCStats}] + fuckyou = NotesVerbosityConst[0] + +var + gNotesFromConst: TNoteKinds = NotesVerbosityConst[0] + gNotesFromConst2: TNoteKinds = fuckyou + +if hintGCStats in gNotesFromConst: + echo "hintGCStats in gNotesFromConst A" + +if hintGCStats in gNotesFromConst2: + echo "hintGCStats in gNotesFromConst B" diff --git a/tests/ccgbugs/twrong_tupleconv.nim b/tests/ccgbugs/twrong_tupleconv.nim index 7a887d183..7b1e58083 100644 --- a/tests/ccgbugs/twrong_tupleconv.nim +++ b/tests/ccgbugs/twrong_tupleconv.nim @@ -6,7 +6,7 @@ iterator myitems*[T](a: var seq[T]): var T {.inline.} = while i < L: yield a[i] inc(i) - doAssert(len(a) == L, "the length of the seq changed while iterating over it") + assert(len(a) == L, "the length of the seq changed while iterating over it") # Works fine var xs = @[1,2,3] diff --git a/tests/ccgbugs2/tcodegen.nim b/tests/ccgbugs2/tcodegen.nim deleted file mode 100644 index 84cd76e2f..000000000 --- a/tests/ccgbugs2/tcodegen.nim +++ /dev/null @@ -1,28 +0,0 @@ -discard """ - targets: "c cpp" -""" - -# bug #19094 -type - X = object - filler: array[2048, int] - innerAddress: uint - -proc initX(): X = - result.innerAddress = cast[uint](result.addr) - -proc initXInPlace(x: var X) = - x.innerAddress = cast[uint](x.addr) - -block: # NRVO1 - var x = initX() - let innerAddress = x.innerAddress - let outerAddress = cast[uint](x.addr) - doAssert(innerAddress == outerAddress) # [OK] - -block: # NRVO2 - var x: X - initXInPlace(x) - let innerAddress = x.innerAddress - let outerAddress = cast[uint](x.addr) - doAssert(innerAddress == outerAddress) # [OK] diff --git a/tests/closure/t11042.nim b/tests/closure/t11042.nim deleted file mode 100644 index 6a3928316..000000000 --- a/tests/closure/t11042.nim +++ /dev/null @@ -1,55 +0,0 @@ -discard """ - output:''' -foo: 1 -foo: 2 -bar: 1 -bar: 2 -foo: 1 -foo: 2 -bar: 1 -bar: 2 -bar: 3 -bar: 4 -bar: 5 -bar: 6 -bar: 7 -bar: 8 -bar: 9 -''' -""" - -# bug #11042 -block: - iterator foo: int = - for x in 1..2: - echo "foo: ", x - for y in 1..2: - discard - - for x in foo(): discard - - let bar = iterator: int = - for x in 1..2: - echo "bar: ", x - for y in 1..2: - discard - - for x in bar(): discard - - -block: - iterator foo: int = - for x in 1..2: - echo "foo: ", x - for y in 1..2: - discard - - for x in foo(): discard - - let bar = iterator: int = - for x in 1..9: - echo "bar: ", x - for y in 1..2: - discard - - for x in bar(): discard \ No newline at end of file diff --git a/tests/closure/t15594.nim b/tests/closure/t15594.nim deleted file mode 100644 index aacd9ed84..000000000 --- a/tests/closure/t15594.nim +++ /dev/null @@ -1,10 +0,0 @@ -discard """ - errormsg: "The variable name cannot be `result`!" -""" - -import sugar - -proc begin(): int = - capture result: - echo 1+1 - result diff --git a/tests/closure/t20152.nim b/tests/closure/t20152.nim deleted file mode 100644 index 484ea0741..000000000 --- a/tests/closure/t20152.nim +++ /dev/null @@ -1,20 +0,0 @@ -discard """ - action: compile -""" - -proc foo() = - iterator it():int {.closure.} = - yield 1 - proc useIter() {.nimcall.} = - var iii = it # <-- illegal capture - doAssert iii() == 1 - useIter() -foo() - -proc foo2() = - proc bar() = # Local function, but not a closure, because no captures - echo "hi" - proc baz() {.nimcall.} = # Calls local function - bar() - baz() -foo2() diff --git a/tests/closure/tcapture.nim b/tests/closure/tcapture.nim index dafc44739..ff3490f07 100644 --- a/tests/closure/tcapture.nim +++ b/tests/closure/tcapture.nim @@ -2,9 +2,7 @@ discard """ output: ''' to be, or not to be (v: 1) -(w: -1) (v: 1) -(w: -1) ''' joinable: false """ @@ -16,19 +14,13 @@ var l = m.mapIt(capture([it], proc (s: string): string = it(s))) let r = l.mapIt(it("be")) echo r[0] & ", or " & r[1] -type - O = object - v: int - U = object - w: int +type O = object + v: int var o = O(v: 1) -var u = U(w: -1) var execute: proc() -capture o, u: +capture [o]: execute = proc() = echo o - echo u execute() o.v = -1 -u.w = 1 execute() diff --git a/tests/closure/tclosure.nim b/tests/closure/tclosure.nim index fa1f79ffe..cfef4193a 100644 --- a/tests/closure/tclosure.nim +++ b/tests/closure/tclosure.nim @@ -1,5 +1,5 @@ discard """ - targets: "c" + target: "c" output: ''' 1 3 6 11 20 foo foo88 @@ -38,10 +38,14 @@ joinable: false block tclosure: - proc map(n: var openArray[int], fn: proc (x: int): int {.closure}) = + proc map(n: var openarray[int], fn: proc (x: int): int {.closure}) = for i in 0..n.len-1: n[i] = fn(n[i]) - proc each(n: openArray[int], fn: proc(x: int) {.closure.}) = + proc foldr(n: openarray[int], fn: proc (x, y: int): int {.closure}): int = + for i in 0..n.len-1: + result = fn(result, n[i]) + + proc each(n: openarray[int], fn: proc(x: int) {.closure.}) = for i in 0..n.len-1: fn(n[i]) @@ -63,9 +67,21 @@ block tclosure: #OUT 2 4 6 8 10 + type + ITest = tuple[ + setter: proc(v: int), + getter: proc(): int] + + proc getInterf(): ITest = + var shared: int + + return (setter: proc (x: int) = shared = x, + getter: proc (): int = return shared) + + # bug #5015 - type Mutator = proc(matched: string): string {.noSideEffect, gcsafe.} + type Mutator = proc(matched: string): string {.noSideEffect, gcsafe, locks: 0.} proc putMutated( MutatorCount: static[int], @@ -164,7 +180,7 @@ block tclosure0: block tclosure3: proc main = const n = 30 - for iterations in 0..10_000: + for iterations in 0..50_000: var s: seq[proc(): string {.closure.}] = @[] for i in 0 .. n-1: (proc () = @@ -187,12 +203,210 @@ block tclosure4: let json_elems = json_params["files"].elems # These fail compilation. var files = map(json_elems, proc (x: JsonNode): string = x.str) + #var files = json_elems.map do (x: JsonNode) -> string: x.str let text = """{"files": ["a", "b", "c"]}""" run((text.parseJson).fields) +import hashes, math +block tclosurebug2: + type + TSlotEnum = enum seEmpty, seFilled, seDeleted + TKeyValuePair[A, B] = tuple[slot: TSlotEnum, key: A, val: B] + TKeyValuePairSeq[A, B] = seq[TKeyValuePair[A, B]] + + TOrderedKeyValuePair[A, B] = tuple[ + slot: TSlotEnum, next: int, key: A, val: B] + TOrderedKeyValuePairSeq[A, B] = seq[TOrderedKeyValuePair[A, B]] + OrderedTable[A, B] = object ## table that remembers insertion order + data: TOrderedKeyValuePairSeq[A, B] + counter, first, last: int + + const + growthFactor = 2 + + proc mustRehash(length, counter: int): bool {.inline.} = + assert(length > counter) + result = (length * 2 < counter * 3) or (length - counter < 4) + + proc nextTry(h, maxHash: Hash): Hash {.inline.} = + result = ((5 * h) + 1) and maxHash + + template rawGetImpl() {.dirty.} = + var h: Hash = hash(key) and high(t.data) # start with real hash value + while t.data[h].slot != seEmpty: + if t.data[h].key == key and t.data[h].slot == seFilled: + return h + h = nextTry(h, high(t.data)) + result = -1 + + template rawInsertImpl() {.dirty.} = + var h: Hash = hash(key) and high(data) + while data[h].slot == seFilled: + h = nextTry(h, high(data)) + data[h].key = key + data[h].val = val + data[h].slot = seFilled + + template addImpl() {.dirty.} = + if mustRehash(len(t.data), t.counter): enlarge(t) + rawInsert(t, t.data, key, val) + inc(t.counter) + + template putImpl() {.dirty.} = + var index = rawGet(t, key) + if index >= 0: + t.data[index].val = val + else: + addImpl() + + proc len[A, B](t: OrderedTable[A, B]): int {.inline.} = + ## returns the number of keys in `t`. + result = t.counter + + template forAllOrderedPairs(yieldStmt: untyped) {.dirty.} = + var h = t.first + while h >= 0: + var nxt = t.data[h].next + if t.data[h].slot == seFilled: yieldStmt + h = nxt + + iterator pairs[A, B](t: OrderedTable[A, B]): tuple[key: A, val: B] = + ## iterates over any (key, value) pair in the table `t` in insertion + ## order. + forAllOrderedPairs: + yield (t.data[h].key, t.data[h].val) + + iterator mpairs[A, B](t: var OrderedTable[A, B]): tuple[key: A, val: var B] = + ## iterates over any (key, value) pair in the table `t` in insertion + ## order. The values can be modified. + forAllOrderedPairs: + yield (t.data[h].key, t.data[h].val) + + iterator keys[A, B](t: OrderedTable[A, B]): A = + ## iterates over any key in the table `t` in insertion order. + forAllOrderedPairs: + yield t.data[h].key + + iterator values[A, B](t: OrderedTable[A, B]): B = + ## iterates over any value in the table `t` in insertion order. + forAllOrderedPairs: + yield t.data[h].val + + iterator mvalues[A, B](t: var OrderedTable[A, B]): var B = + ## iterates over any value in the table `t` in insertion order. The values + ## can be modified. + forAllOrderedPairs: + yield t.data[h].val + + proc rawGet[A, B](t: OrderedTable[A, B], key: A): int = + rawGetImpl() + + proc `[]`[A, B](t: OrderedTable[A, B], key: A): B = + ## retrieves the value at ``t[key]``. If `key` is not in `t`, + ## default empty value for the type `B` is returned + ## and no exception is raised. One can check with ``hasKey`` whether the key + ## exists. + var index = rawGet(t, key) + if index >= 0: result = t.data[index].val + + proc mget[A, B](t: var OrderedTable[A, B], key: A): var B = + ## retrieves the value at ``t[key]``. The value can be modified. + ## If `key` is not in `t`, the ``EInvalidKey`` exception is raised. + var index = rawGet(t, key) + if index >= 0: result = t.data[index].val + else: raise newException(KeyError, "key not found: " & $key) + + proc hasKey[A, B](t: OrderedTable[A, B], key: A): bool = + ## returns true iff `key` is in the table `t`. + result = rawGet(t, key) >= 0 + + proc rawInsert[A, B](t: var OrderedTable[A, B], + data: var TOrderedKeyValuePairSeq[A, B], + key: A, val: B) = + rawInsertImpl() + data[h].next = -1 + if t.first < 0: t.first = h + if t.last >= 0: data[t.last].next = h + t.last = h + + proc enlarge[A, B](t: var OrderedTable[A, B]) = + var n: TOrderedKeyValuePairSeq[A, B] + newSeq(n, len(t.data) * growthFactor) + var h = t.first + t.first = -1 + t.last = -1 + while h >= 0: + var nxt = t.data[h].next + if t.data[h].slot == seFilled: + rawInsert(t, n, t.data[h].key, t.data[h].val) + h = nxt + swap(t.data, n) + + proc `[]=`[A, B](t: var OrderedTable[A, B], key: A, val: B) = + ## puts a (key, value)-pair into `t`. + putImpl() + + proc add[A, B](t: var OrderedTable[A, B], key: A, val: B) = + ## puts a new (key, value)-pair into `t` even if ``t[key]`` already exists. + addImpl() + + proc iniOrderedTable[A, B](initialSize=64): OrderedTable[A, B] = + ## creates a new ordered hash table that is empty. `initialSize` needs to be + ## a power of two. + assert isPowerOfTwo(initialSize) + result.counter = 0 + result.first = -1 + result.last = -1 + newSeq(result.data, initialSize) + + proc toOrderedTable[A, B](pairs: openarray[tuple[key: A, + val: B]]): OrderedTable[A, B] = + ## creates a new ordered hash table that contains the given `pairs`. + result = iniOrderedTable[A, B](nextPowerOfTwo(pairs.len+10)) + for key, val in items(pairs): result[key] = val + + proc sort[A, B](t: var OrderedTable[A,B], + cmp: proc (x, y: tuple[key: A, val: B]): int {.closure.}) = + ## sorts the ordered table so that the entry with the highest counter comes + ## first. This is destructive (with the advantage of being efficient)! + ## You must not modify `t` afterwards! + ## You can use the iterators `pairs`, `keys`, and `values` to iterate over + ## `t` in the sorted order. + + # we use shellsort here; fast enough and simple + var h = 1 + while true: + h = 3 * h + 1 + if h >= high(t.data): break + while true: + h = h div 3 + for i in countup(h, high(t.data)): + var j = i + #echo(t.data.len, " ", j, " - ", h) + #echo(repr(t.data[j-h])) + proc rawCmp(x, y: TOrderedKeyValuePair[A, B]): int = + if x.slot in {seEmpty, seDeleted} and y.slot in {seEmpty, seDeleted}: + return 0 + elif x.slot in {seEmpty, seDeleted}: + return -1 + elif y.slot in {seEmpty, seDeleted}: + return 1 + else: + let item1 = (x.key, x.val) + let item2 = (y.key, y.val) + return cmp(item1, item2) + + while rawCmp(t.data[j-h], t.data[j]) <= 0: + swap(t.data[j], t.data[j-h]) + j = j-h + if j < h: break + if h == 1: break + + + import sugar block inference3304: type @@ -239,19 +453,19 @@ block doNotation: b.onClick do (e: Event): echo "click at ", e.x, ",", e.y - b.onFocusLost do (): + b.onFocusLost: echo "lost focus 1" - b.onFocusLost do (): + b.onFocusLost do: echo "lost focus 2" - b.onUserEvent("UserEvent 1") do (): + b.onUserEvent("UserEvent 1") do: discard - onUserEvent(b, "UserEvent 2") do (): + b.onUserEvent "UserEvent 2": discard - b.onUserEvent("UserEvent 3") do (): + b.onUserEvent("UserEvent 3"): discard b.onUserEvent("UserEvent 4", () => echo "event 4") @@ -299,7 +513,7 @@ block tflatmap: let g: A -> Rand[B] = (a: A) => ((rng: RNG) => (f(a), rng)) flatMap(s, g) - discard nextInt.map(i => i - i mod 2) + let f = nextInt.map(i => i - i mod 2) diff --git a/tests/closure/tclosure_issues.nim b/tests/closure/tclosure_issues.nim index b1a2d7c6b..4688834de 100644 --- a/tests/closure/tclosure_issues.nim +++ b/tests/closure/tclosure_issues.nim @@ -71,12 +71,12 @@ block tissue7104: proc sp(cb: proc())= cb() - sp do (): + sp: var i = 0 echo "ok ", i - sp do (): + sp(): inc i echo "ok ", i - sp do (): + sp do: inc i echo "ok ", i diff --git a/tests/closure/tinvalidclosure.nim b/tests/closure/tinvalidclosure.nim index 37d0f68a2..b2d8bd28d 100644 --- a/tests/closure/tinvalidclosure.nim +++ b/tests/closure/tinvalidclosure.nim @@ -1,5 +1,5 @@ discard """ - errormsg: "type mismatch: got " + errormsg: "type mismatch: got " line: 12 """ diff --git a/tests/closure/tinvalidclosure4.nim b/tests/closure/tinvalidclosure4.nim deleted file mode 100644 index 7985a2488..000000000 --- a/tests/closure/tinvalidclosure4.nim +++ /dev/null @@ -1,9 +0,0 @@ -discard """ - errormsg: "illegal capture 'v'" - line: 7 -""" - -proc outer(v: int) = - proc b {.nimcall.} = echo v - b() -outer(5) diff --git a/tests/closure/tinvalidclosure5.nim b/tests/closure/tinvalidclosure5.nim deleted file mode 100644 index 3b5f46a40..000000000 --- a/tests/closure/tinvalidclosure5.nim +++ /dev/null @@ -1,10 +0,0 @@ -discard """ - errormsg: "type mismatch: got but expected 'A = proc (){.nimcall.}'" - line: 9 -""" - -type A = proc() {.nimcall.} -proc main = - let b = 1 - let a: A = proc() = echo b - diff --git a/tests/closure/tnested.nim b/tests/closure/tnested.nim index 31963ea86..dbbe9ba58 100644 --- a/tests/closure/tnested.nim +++ b/tests/closure/tnested.nim @@ -33,7 +33,6 @@ py py px 6 -proc (){.closure, noSideEffect, gcsafe.} ''' """ @@ -178,19 +177,3 @@ block tclosure2: outer2() - -# bug #5688 - -import typetraits - -proc myDiscard[T](a: T) = discard - -proc foo() = - let a = 5 - let f = (proc() = - myDiscard (proc() = echo a) - ) - echo name(typeof(f)) - -foo() - diff --git a/tests/closure/tstmtlist.nim b/tests/closure/tstmtlist.nim deleted file mode 100644 index 6a1390617..000000000 --- a/tests/closure/tstmtlist.nim +++ /dev/null @@ -1,9 +0,0 @@ -discard """ - action: compile -""" - -proc foo(x: proc()) = x() -foo: echo "a" #[tt.Warning - ^ statement list expression assumed to be anonymous proc; this is deprecated, use `do (): ...` or `proc () = ...` instead [StmtListLambda]]# -foo do: echo "b" #[tt.Warning - ^ statement list expression assumed to be anonymous proc; this is deprecated, use `do (): ...` or `proc () = ...` instead [StmtListLambda]]# diff --git a/tests/closure/ttimeinfo.nim b/tests/closure/ttimeinfo.nim index 24d535cbf..7416c0d31 100644 --- a/tests/closure/ttimeinfo.nim +++ b/tests/closure/ttimeinfo.nim @@ -1,7 +1,7 @@ discard """ output: ''' -@[2000-01-01T00:00:00Z, 2001-01-01T00:00:00Z, 2002-01-01T00:00:00Z, 2003-01-01T00:00:00Z, 2004-01-01T00:00:00Z, 2005-01-01T00:00:00Z, 2006-01-01T00:00:00Z, 2007-01-01T00:00:00Z, 2008-01-01T00:00:00Z, 2009-01-01T00:00:00Z, 2010-01-01T00:00:00Z, 2011-01-01T00:00:00Z, 2012-01-01T00:00:00Z, 2013-01-01T00:00:00Z, 2014-01-01T00:00:00Z, 2015-01-01T00:00:00Z] -@[2000-01-01T00:00:00Z, 2001-01-01T00:00:00Z, 2002-01-01T00:00:00Z, 2003-01-01T00:00:00Z, 2004-01-01T00:00:00Z, 2005-01-01T00:00:00Z, 2006-01-01T00:00:00Z, 2007-01-01T00:00:00Z, 2008-01-01T00:00:00Z, 2009-01-01T00:00:00Z, 2010-01-01T00:00:00Z, 2011-01-01T00:00:00Z, 2012-01-01T00:00:00Z, 2013-01-01T00:00:00Z, 2014-01-01T00:00:00Z, 2015-01-01T00:00:00Z] +@[2000-01-01T00:00:00+00:00, 2001-01-01T00:00:00+00:00, 2002-01-01T00:00:00+00:00, 2003-01-01T00:00:00+00:00, 2004-01-01T00:00:00+00:00, 2005-01-01T00:00:00+00:00, 2006-01-01T00:00:00+00:00, 2007-01-01T00:00:00+00:00, 2008-01-01T00:00:00+00:00, 2009-01-01T00:00:00+00:00, 2010-01-01T00:00:00+00:00, 2011-01-01T00:00:00+00:00, 2012-01-01T00:00:00+00:00, 2013-01-01T00:00:00+00:00, 2014-01-01T00:00:00+00:00, 2015-01-01T00:00:00+00:00] +@[2000-01-01T00:00:00+00:00, 2001-01-01T00:00:00+00:00, 2002-01-01T00:00:00+00:00, 2003-01-01T00:00:00+00:00, 2004-01-01T00:00:00+00:00, 2005-01-01T00:00:00+00:00, 2006-01-01T00:00:00+00:00, 2007-01-01T00:00:00+00:00, 2008-01-01T00:00:00+00:00, 2009-01-01T00:00:00+00:00, 2010-01-01T00:00:00+00:00, 2011-01-01T00:00:00+00:00, 2012-01-01T00:00:00+00:00, 2013-01-01T00:00:00+00:00, 2014-01-01T00:00:00+00:00, 2015-01-01T00:00:00+00:00] ''' """ @@ -12,11 +12,11 @@ import times # 1 proc f(n: int): DateTime = - initDateTime(1, mJan, n, 0, 0, 0, utc()) + DateTime(year: n, month: mJan, monthday: 1) echo toSeq(2000 || 2015).map(f) # 2 echo toSeq(2000 || 2015).map(proc (n: int): DateTime = - initDateTime(1, mJan, n, 0, 0, 0, utc()) + DateTime(year: n, month: mJan, monthday: 1) ) diff --git a/tests/collections/tcollections.nim b/tests/collections/tcollections.nim index 7677f7c1a..2f8cfece7 100644 --- a/tests/collections/tcollections.nim +++ b/tests/collections/tcollections.nim @@ -1,10 +1,9 @@ discard """ - targets: "c js" + output: "" """ -# see also: tdeques, tlists, tcritbits +import deques, sequtils -import sets, tables, sequtils block tapply: var x = @[1, 2, 3] @@ -13,6 +12,19 @@ block tapply: x.applyIt(it+5000) doAssert x == @[5111, 5112, 5113] + +block tdeques: + proc index(self: Deque[int], idx: Natural): int = + self[idx] + + proc main = + var testDeque = initDeque[int]() + testDeque.addFirst(1) + assert testDeque.index(0) == 1 + + main() + + block tmapit: var x = @[1, 2, 3] # This mapIt call will run with preallocation because ``len`` is available. @@ -40,66 +52,3 @@ block tmapit: # since ``len`` is not available var r = st.mapIt($(it+10)) doAssert r == @["10", "11", "12", "13", "14"] - - - -# Collections to string: - -# Tests for tuples -doAssert $(1, 2, 3) == "(1, 2, 3)" -doAssert $("1", "2", "3") == """("1", "2", "3")""" -doAssert $('1', '2', '3') == """('1', '2', '3')""" - -# Tests for seqs -doAssert $(@[1, 2, 3]) == "@[1, 2, 3]" -doAssert $(@["1", "2", "3"]) == """@["1", "2", "3"]""" -doAssert $(@['1', '2', '3']) == """@['1', '2', '3']""" - -# Tests for sets -doAssert $(toHashSet([1])) == "{1}" -doAssert $(toHashSet(["1"])) == """{"1"}""" -doAssert $(toHashSet(['1'])) == """{'1'}""" -doAssert $(toOrderedSet([1, 2, 3])) == "{1, 2, 3}" -doAssert $(toOrderedSet(["1", "2", "3"])) == """{"1", "2", "3"}""" -doAssert $(toOrderedSet(['1', '2', '3'])) == """{'1', '2', '3'}""" - -# see also: tcritbitsToString, tlistsToString - -# Tests for tables -when defined(nimIntHash1): - doAssert $({1: "1", 2: "2"}.toTable) == """{1: "1", 2: "2"}""" -else: - doAssert $({1: "1", 2: "2"}.toTable) == """{2: "2", 1: "1"}""" -let tabStr = $({"1": 1, "2": 2}.toTable) -doAssert (tabStr == """{"2": 2, "1": 1}""" or tabStr == """{"1": 1, "2": 2}""") - -# Test escaping behavior -block: - var s = "" - s.addQuoted('\0') - s.addQuoted('\31') - s.addQuoted('\127') - doAssert s == "'\\x00''\\x1F''\\x7F'" -block: - var s = "" - s.addQuoted('\\') - s.addQuoted('\'') - s.addQuoted('\"') - doAssert s == """'\\''\'''\"'""" -block: - var s = "" - s.addQuoted("å") - s.addQuoted("ä") - s.addQuoted("ö") - s.addEscapedChar('\xFF') - doAssert s == """"å""ä""ö"\xFF""" - -# Test customized element representation -type CustomString = object - -proc addQuoted(s: var string, x: CustomString) = - s.add("") - -block: - let s = @[CustomString()] - doAssert $s == "@[]" diff --git a/tests/collections/tcollections_to_string.nim b/tests/collections/tcollections_to_string.nim index 62ba87334..686b9916b 100644 --- a/tests/collections/tcollections_to_string.nim +++ b/tests/collections/tcollections_to_string.nim @@ -19,18 +19,15 @@ doAssert $(@["1", "2", "3"]) == """@["1", "2", "3"]""" doAssert $(@['1', '2', '3']) == """@['1', '2', '3']""" # Tests for sets -doAssert $(toHashSet([1])) == "{1}" -doAssert $(toHashSet(["1"])) == """{"1"}""" -doAssert $(toHashSet(['1'])) == """{'1'}""" +doAssert $(toSet([1])) == "{1}" +doAssert $(toSet(["1"])) == """{"1"}""" +doAssert $(toSet(['1'])) == """{'1'}""" doAssert $(toOrderedSet([1, 2, 3])) == "{1, 2, 3}" doAssert $(toOrderedSet(["1", "2", "3"])) == """{"1", "2", "3"}""" doAssert $(toOrderedSet(['1', '2', '3'])) == """{'1', '2', '3'}""" # Tests for tables -when defined(nimIntHash1): - doAssert $({1: "1", 2: "2"}.toTable) == """{1: "1", 2: "2"}""" -else: - doAssert $({1: "1", 2: "2"}.toTable) == """{2: "2", 1: "1"}""" +doAssert $({1: "1", 2: "2"}.toTable) == """{1: "1", 2: "2"}""" doAssert $({"1": 1, "2": 2}.toTable) == """{"1": 1, "2": 2}""" # Tests for deques diff --git a/tests/collections/thashsets.nim b/tests/collections/thashsets.nim index 359eaa51e..cd4401511 100644 --- a/tests/collections/thashsets.nim +++ b/tests/collections/thashsets.nim @@ -3,9 +3,9 @@ import sets, hashes, algorithm block setEquality: var - a = initHashSet[int]() - b = initHashSet[int]() - c = initHashSet[string]() + a = initSet[int]() + b = initSet[int]() + c = initSet[string]() for i in 0..5: a.incl(i) for i in 1..6: b.incl(i) @@ -16,27 +16,27 @@ block setEquality: block setsContainingTuples: - var set = initHashSet[tuple[i: int, i64: int64, f: float]]() + var set = initSet[tuple[i: int, i64: int64, f: float]]() set.incl( (i: 123, i64: 123'i64, f: 3.14) ) doAssert set.contains( (i: 123, i64: 123'i64, f: 3.14) ) doAssert( not set.contains( (i: 456, i64: 789'i64, f: 2.78) ) ) block setWithTuplesWithSeqs: - var s = initHashSet[tuple[s: seq[int]]]() + var s = initSet[tuple[s: seq[int]]]() s.incl( (s: @[1, 2, 3]) ) doAssert s.contains( (s: @[1, 2, 3]) ) doAssert( not s.contains((s: @[4, 5, 6])) ) block setWithSequences: - var s = initHashSet[seq[int]]() + var s = initSet[seq[int]]() s.incl( @[1, 2, 3] ) doAssert s.contains(@[1, 2, 3]) doAssert( not s.contains(@[4, 5, 6]) ) block setClearWorked: - var s = initHashSet[char]() + var s = initSet[char]() for c in "this is a test": s.incl(c) @@ -79,8 +79,9 @@ block hashForHashedSet: let seq1 = "This is the test." seq2 = "the test is This." - s1 = seq1.toHashSet() - s2 = seq2.toHashSet() + s1 = seq1.toSet() + s2 = seq2.toSet() + var hashSeq: seq[Hash] = @[] doAssert s1 == s2 doAssert hash(s1) == hash(s2) @@ -119,264 +120,3 @@ block hashForOrderdSet: reversed = !$reversed doAssert hash(r) == reversed doAssert hash(s1) != reversed - - -proc testModule() = - ## Internal micro test to validate docstrings and such. - block lenTest: - var values: HashSet[int] - doAssert values.len == 0 - doAssert values.card == 0 - - block setIterator: - type pair = tuple[a, b: int] - var a, b = initHashSet[pair]() - a.incl((2, 3)) - a.incl((3, 2)) - a.incl((2, 3)) - for x, y in a.items: - b.incl((x - 2, y + 1)) - doAssert a.len == b.card - doAssert a.len == 2 - #echo b - - block setContains: - var values = initHashSet[int]() - doAssert(not values.contains(2)) - values.incl(2) - doAssert values.contains(2) - values.excl(2) - doAssert(not values.contains(2)) - - values.incl(4) - var others = toHashSet([6, 7]) - values.incl(others) - doAssert values.len == 3 - - values.init - doAssert values.containsOrIncl(2) == false - doAssert values.containsOrIncl(2) == true - var - a = toHashSet([1, 2]) - b = toHashSet([1]) - b.incl(2) - doAssert a == b - - block exclusions: - var s = toHashSet([2, 3, 6, 7]) - s.excl(2) - s.excl(2) - doAssert s.len == 3 - - var - numbers = toHashSet([1, 2, 3, 4, 5]) - even = toHashSet([2, 4, 6, 8]) - numbers.excl(even) - #echo numbers - # --> {1, 3, 5} - - block toSeqAndString: - var a = toHashSet([2, 7, 5]) - var b = initHashSet[int](a.len) - for x in [2, 7, 5]: b.incl(x) - doAssert($a == $b) - #echo a - #echo toHashSet(["no", "esc'aping", "is \" provided"]) - - #block orderedToSeqAndString: - # echo toOrderedSet([2, 4, 5]) - # echo toOrderedSet(["no", "esc'aping", "is \" provided"]) - - block setOperations: - var - a = toHashSet(["a", "b"]) - b = toHashSet(["b", "c"]) - c = union(a, b) - doAssert c == toHashSet(["a", "b", "c"]) - var d = intersection(a, b) - doAssert d == toHashSet(["b"]) - var e = difference(a, b) - doAssert e == toHashSet(["a"]) - var f = symmetricDifference(a, b) - doAssert f == toHashSet(["a", "c"]) - doAssert d < a and d < b - doAssert((a < a) == false) - doAssert d <= a and d <= b - doAssert((a <= a)) - # Alias test. - doAssert a + b == toHashSet(["a", "b", "c"]) - doAssert a * b == toHashSet(["b"]) - doAssert a - b == toHashSet(["a"]) - doAssert a -+- b == toHashSet(["a", "c"]) - doAssert disjoint(a, b) == false - doAssert disjoint(a, b - a) == true - - block mapSet: - var a = toHashSet([1, 2, 3]) - var b = a.map(proc (x: int): string = $x) - doAssert b == toHashSet(["1", "2", "3"]) - - block lenTest: - var values: OrderedSet[int] - doAssert values.len == 0 - doAssert values.card == 0 - - block setIterator: - type pair = tuple[a, b: int] - var a, b = initOrderedSet[pair]() - a.incl((2, 3)) - a.incl((3, 2)) - a.incl((2, 3)) - for x, y in a.items: - b.incl((x - 2, y + 1)) - doAssert a.len == b.card - doAssert a.len == 2 - - block setPairsIterator: - var s = toOrderedSet([1, 3, 5, 7]) - var items = newSeq[tuple[a: int, b: int]]() - for idx, item in s: items.add((idx, item)) - doAssert items == @[(0, 1), (1, 3), (2, 5), (3, 7)] - - block exclusions: - var s = toOrderedSet([1, 2, 3, 6, 7, 4]) - - s.excl(3) - s.excl(3) - s.excl(1) - s.excl(4) - - var items = newSeq[int]() - for item in s: items.add item - doAssert items == @[2, 6, 7] - - block: #9005 - var s = initOrderedSet[(int, int)]() - for i in 0 .. 30: incl(s, (i, 0)) - for i in 0 .. 30: excl(s, (i, 0)) - doAssert s.len == 0 - - #block orderedSetIterator: - # var a = initOrderedSet[int]() - # for value in [9, 2, 1, 5, 1, 8, 4, 2]: - # a.incl(value) - # for value in a.items: - # echo "Got ", value - - block setContains: - var values = initOrderedSet[int]() - doAssert(not values.contains(2)) - values.incl(2) - doAssert values.contains(2) - - block toSeqAndString: - var a = toOrderedSet([2, 4, 5]) - var b = initOrderedSet[int]() - for x in [2, 4, 5]: b.incl(x) - doAssert($a == $b) - doAssert(a == b) # https://github.com/Araq/Nim/issues/1413 - - block initBlocks: - var a: OrderedSet[int] - a.init(4) - a.incl(2) - a.init - doAssert a.len == 0 - a = initOrderedSet[int](4) - a.incl(2) - doAssert a.len == 1 - - var b: HashSet[int] - b.init(4) - b.incl(2) - b.init - doAssert b.len == 0 - b = initHashSet[int](4) - b.incl(2) - doAssert b.len == 1 - - block missingOrExcl: - var s = toOrderedSet([2, 3, 6, 7]) - doAssert s.missingOrExcl(4) == true - doAssert s.missingOrExcl(6) == false - - block orderedSetEquality: - type pair = tuple[a, b: int] - - var aa = initOrderedSet[pair]() - var bb = initOrderedSet[pair]() - - var x = (a: 1, b: 2) - var y = (a: 3, b: 4) - - aa.incl(x) - aa.incl(y) - - bb.incl(x) - bb.incl(y) - doAssert aa == bb - - block setsWithoutInit: - var - a: HashSet[int] - b: HashSet[int] - c: HashSet[int] - d: HashSet[int] - e: HashSet[int] - - doAssert a.containsOrIncl(3) == false - doAssert a.contains(3) - doAssert a.len == 1 - doAssert a.containsOrIncl(3) - a.incl(3) - doAssert a.len == 1 - a.incl(6) - doAssert a.len == 2 - - b.incl(5) - doAssert b.len == 1 - b.excl(5) - b.excl(c) - doAssert b.missingOrExcl(5) - doAssert b.disjoint(c) - - d = b + c - doAssert d.len == 0 - d = b * c - doAssert d.len == 0 - d = b - c - doAssert d.len == 0 - d = b -+- c - doAssert d.len == 0 - - doAssert (d < e) == false - doAssert d <= e - doAssert d == e - - block setsWithoutInit: - var - a: OrderedSet[int] - b: OrderedSet[int] - c: OrderedSet[int] - d: HashSet[int] - - - doAssert a.containsOrIncl(3) == false - doAssert a.contains(3) - doAssert a.len == 1 - doAssert a.containsOrIncl(3) - a.incl(3) - doAssert a.len == 1 - a.incl(6) - doAssert a.len == 2 - - b.incl(5) - doAssert b.len == 1 - doAssert b.missingOrExcl(5) == false - doAssert b.missingOrExcl(5) - - doAssert c.missingOrExcl(9) - d.incl(c) - doAssert d.len == 0 - -testModule() diff --git a/tests/collections/ttables.nim b/tests/collections/ttables.nim index 95f9418a0..9eccf345a 100644 --- a/tests/collections/ttables.nim +++ b/tests/collections/ttables.nim @@ -7,27 +7,15 @@ And we get here 3 ''' joinable: false -targets: "c cpp js" """ - -# xxx wrap in a template to test in VM, see https://github.com/timotheecour/Nim/issues/534#issuecomment-769565033 - import hashes, sequtils, tables, algorithm -proc sortedPairs[T](t: T): auto = toSeq(t.pairs).sorted -template sortedItems(t: untyped): untyped = sorted(toSeq(t)) - -block tableDollar: - # other tests should use `sortedPairs` to be robust to future table/hash - # implementation changes - doAssert ${1: 'a', 2: 'b'}.toTable in ["{1: 'a', 2: 'b'}", "{2: 'b', 1: 'a'}"] - # test should not be joined because it takes too long. block tableadds: proc main = var tab = newTable[string, string]() for i in 0..1000: - tab["key"] = "value " & $i + tab.add "key", "value " & $i main() echo "done tableadds" @@ -54,20 +42,20 @@ block thashes: var t = initTable[int,int]() t[0] = 42 t[1] = t[0] + 1 - doAssert(t[0] == 42) - doAssert(t[1] == 43) + assert(t[0] == 42) + assert(t[1] == 43) let t2 = {1: 1, 2: 2}.toTable - doAssert(t2[2] == 2) + assert(t2[2] == 2) # Test with char block: var t = initTable[char,int]() t['0'] = 42 t['1'] = t['0'] + 1 - doAssert(t['0'] == 42) - doAssert(t['1'] == 43) + assert(t['0'] == 42) + assert(t['1'] == 43) let t2 = {'1': 1, '2': 2}.toTable - doAssert(t2['2'] == 2) + assert(t2['2'] == 2) # Test with enum block: @@ -76,22 +64,22 @@ block thashes: var t = initTable[E,int]() t[eA] = 42 t[eB] = t[eA] + 1 - doAssert(t[eA] == 42) - doAssert(t[eB] == 43) + assert(t[eA] == 42) + assert(t[eB] == 43) let t2 = {eA: 1, eB: 2}.toTable - doAssert(t2[eB] == 2) + assert(t2[eB] == 2) # Test with range block: type - R = range[0..9] + R = range[1..10] var t = initTable[R,int]() # causes warning, why? t[1] = 42 # causes warning, why? t[2] = t[1] + 1 - doAssert(t[1] == 42) - doAssert(t[2] == 43) + assert(t[1] == 42) + assert(t[2] == 43) let t2 = {1.R: 1, 2.R: 2}.toTable - doAssert(t2[2.R] == 2) + assert(t2[2.R] == 2) # Test which combines the generics for tuples + ordinals block: @@ -100,10 +88,10 @@ block thashes: var t = initTable[(string, E, int, char), int]() t[("a", eA, 0, '0')] = 42 t[("b", eB, 1, '1')] = t[("a", eA, 0, '0')] + 1 - doAssert(t[("a", eA, 0, '0')] == 42) - doAssert(t[("b", eB, 1, '1')] == 43) + assert(t[("a", eA, 0, '0')] == 42) + assert(t[("b", eB, 1, '1')] == 43) let t2 = {("a", eA, 0, '0'): 1, ("b", eB, 1, '1'): 2}.toTable - doAssert(t2[("b", eB, 1, '1')] == 2) + assert(t2[("b", eB, 1, '1')] == 2) # Test to check if overloading is possible # Unfortunately, this does not seem to work for int @@ -137,8 +125,8 @@ block tindexby: doAssert indexBy(newSeq[int](), proc(x: int):int = x) == initTable[int, int](), "empty int table" var tbl1 = initTable[int, int]() - tbl1[1] = 1 - tbl1[2] = 2 + tbl1.add(1,1) + tbl1.add(2,2) doAssert indexBy(@[1,2], proc(x: int):int = x) == tbl1, "int table" type @@ -151,8 +139,8 @@ block tindexby: elem2 = TElem(foo: 2, bar: "baz") var tbl2 = initTable[string, TElem]() - tbl2["bar"] = elem1 - tbl2["baz"] = elem2 + tbl2.add("bar", elem1) + tbl2.add("baz", elem2) doAssert indexBy(@[elem1,elem2], proc(x: TElem): string = x.bar) == tbl2, "element table" @@ -169,22 +157,23 @@ block tableconstr: ignoreExpr({2: 3, "key": "value"}) # NEW: - doAssert 56 in 50..100 + assert 56 in 50..100 - doAssert 56 in 0..60 + assert 56 in ..60 block ttables2: proc TestHashIntInt() = var tab = initTable[int,int]() - let n = 10 - for i in 1..n: + for i in 1..1_000_000: tab[i] = i - for i in 1..n: + for i in 1..1_000_000: var x = tab[i] if x != i : echo "not found ", i - TestHashIntInt() + proc run1() = # occupied Memory stays constant, but + for i in 1 .. 50: # aborts at run: 44 on win32 with 3.2GB with out of memory + TestHashIntInt() # bug #2107 @@ -196,8 +185,10 @@ block ttables2: delTab[5] = 5 + run1() echo "2" + block tablesref: const data = { @@ -240,9 +231,9 @@ block tablesref: t[(1,1)] = "11" for x in 0..1: for y in 0..1: - doAssert t[(x,y)] == $x & $y - doAssert t.sortedPairs == - @[((x: 0, y: 0), "00"), ((x: 0, y: 1), "01"), ((x: 1, y: 0), "10"), ((x: 1, y: 1), "11")] + assert t[(x,y)] == $x & $y + assert($t == + "{(x: 1, y: 1): \"11\", (x: 0, y: 0): \"00\", (x: 0, y: 1): \"01\", (x: 1, y: 0): \"10\"}") block tableTest2: var t = newTable[string, float]() @@ -254,31 +245,31 @@ block tablesref: t["012"] = 67.9 t["123"] = 1.5 # test overwriting - doAssert t["123"] == 1.5 + assert t["123"] == 1.5 try: echo t["111"] # deleted except KeyError: discard - doAssert(not hasKey(t, "111")) - doAssert "111" notin t + assert(not hasKey(t, "111")) + assert "111" notin t for key, val in items(data): t[key] = val.toFloat - for key, val in items(data): doAssert t[key] == val.toFloat + for key, val in items(data): assert t[key] == val.toFloat block orderedTableTest1: var t = newOrderedTable[string, int](2) for key, val in items(data): t[key] = val - for key, val in items(data): doAssert t[key] == val + for key, val in items(data): assert t[key] == val var i = 0 # `pairs` needs to yield in insertion order: for key, val in pairs(t): - doAssert key == data[i][0] - doAssert val == data[i][1] + assert key == data[i][0] + assert val == data[i][1] inc(i) for key, val in mpairs(t): val = 99 - for val in mvalues(t): doAssert val == 99 + for val in mvalues(t): assert val == 99 block countTableTest1: var s = data.toTable @@ -287,11 +278,11 @@ block tablesref: for x in [t, r]: for k in s.keys: x.inc(k) - doAssert x[k] == 1 + assert x[k] == 1 x.inc("90", 3) x.inc("12", 2) x.inc("34", 1) - doAssert t.largest()[0] == "90" + assert t.largest()[0] == "90" t.sort() r.sort(SortOrder.Ascending) @@ -302,43 +293,29 @@ block tablesref: var i = 0 for (k, v) in ps: case i - of 0: doAssert k == "90" and v == 4 - of 1: doAssert k == "12" and v == 3 - of 2: doAssert k == "34" and v == 2 + of 0: assert k == "90" and v == 4 + of 1: assert k == "12" and v == 3 + of 2: assert k == "34" and v == 2 else: break inc i - block smallestLargestNamedFieldsTest: # bug #14918 - const a = [7, 8, 8] - - proc testNamedFields(t: CountTable | CountTableRef) = - doAssert t.smallest.key == 7 - doAssert t.smallest.val == 1 - doAssert t.largest.key == 8 - doAssert t.largest.val == 2 - - let t1 = toCountTable(a) - testNamedFields(t1) - let t2 = newCountTable(a) - testNamedFields(t2) - block SyntaxTest: var x = newTable[int, string]({:}) discard x block nilTest: var i, j: TableRef[int, int] = nil - doAssert i == j + assert i == j j = newTable[int, int]() - doAssert i != j - doAssert j != i + assert i != j + assert j != i i = newTable[int, int]() - doAssert i == j + assert i == j proc orderedTableSortTest() = var t = newOrderedTable[string, int](2) for key, val in items(data): t[key] = val - for key, val in items(data): doAssert t[key] == val + for key, val in items(data): assert t[key] == val proc cmper(x, y: tuple[key: string, val: int]): int = cmp(x.key, y.key) t.sort(cmper) var i = 0 @@ -363,95 +340,32 @@ block tablesref: block anonZipTest: let keys = @['a','b','c'] let values = @[1, 2, 3] - doAssert zip(keys, values).toTable.sortedPairs == @[('a', 1), ('b', 2), ('c', 3)] + doAssert "{'c': 3, 'a': 1, 'b': 2}" == $ toTable zip(keys, values) block clearTableTest: var t = newTable[string, float]() t["test"] = 1.2345 t["111"] = 1.000043 t["123"] = 1.23 - doAssert t.len() != 0 + assert t.len() != 0 t.clear() - doAssert t.len() == 0 + assert t.len() == 0 block clearOrderedTableTest: var t = newOrderedTable[string, int](2) for key, val in items(data): t[key] = val - doAssert t.len() != 0 + assert t.len() != 0 t.clear() - doAssert t.len() == 0 + assert t.len() == 0 block clearCountTableTest: var t = newCountTable[string]() t.inc("90", 3) t.inc("12", 2) t.inc("34", 1) - doAssert t.len() != 0 + assert t.len() != 0 t.clear() - doAssert t.len() == 0 + assert t.len() == 0 orderedTableSortTest() echo "3" - - -block: # https://github.com/nim-lang/Nim/issues/13496 - template testDel(body) = - block: - body - when t is CountTable|CountTableRef: - t.inc(15, 1) - t.inc(19, 2) - t.inc(17, 3) - t.inc(150, 4) - t.del(150) - else: - t[15] = 1 - t[19] = 2 - t[17] = 3 - t[150] = 4 - t.del(150) - doAssert t.len == 3 - doAssert sortedItems(t.values) == @[1, 2, 3] - doAssert sortedItems(t.keys) == @[15, 17, 19] - doAssert sortedPairs(t) == @[(15, 1), (17, 3), (19, 2)] - var s = newSeq[int]() - for v in t.values: s.add(v) - doAssert s.len == 3 - doAssert sortedItems(s) == @[1, 2, 3] - when t is OrderedTable|OrderedTableRef: - doAssert toSeq(t.keys) == @[15, 19, 17] - doAssert toSeq(t.values) == @[1,2,3] - doAssert toSeq(t.pairs) == @[(15, 1), (19, 2), (17, 3)] - - testDel(): (var t: Table[int, int]) - testDel(): (let t = newTable[int, int]()) - testDel(): (var t: OrderedTable[int, int]) - testDel(): (let t = newOrderedTable[int, int]()) - testDel(): (var t: CountTable[int]) - testDel(): (let t = newCountTable[int]()) - - -block testNonPowerOf2: - var a = initTable[int, int](7) - a[1] = 10 - doAssert a[1] == 10 - - var b = initTable[int, int](9) - b[1] = 10 - doAssert b[1] == 10 - -block emptyOrdered: - var t1: OrderedTable[int, string] - var t2: OrderedTable[int, string] - doAssert t1 == t2 - -block: # Table[ref, int] - type A = ref object - x: int - var t: OrderedTable[A, int] - let a1 = A(x: 3) - let a2 = A(x: 3) - t[a1] = 10 - t[a2] = 11 - doAssert t[a1] == 10 - doAssert t[a2] == 11 diff --git a/tests/collections/ttablesthreads.nim b/tests/collections/ttablesthreads.nim index 2a4e1bf42..5553b31ef 100644 --- a/tests/collections/ttablesthreads.nim +++ b/tests/collections/ttablesthreads.nim @@ -3,9 +3,7 @@ discard """ output: '''true''' """ -import hashes, tables, sharedtables, algorithm, sequtils - -proc sortedPairs[T](t: T): auto = toSeq(t.pairs).sorted +import hashes, tables, sharedtables const data = { @@ -48,8 +46,9 @@ block tableTest1: t[(1,1)] = "11" for x in 0..1: for y in 0..1: - doAssert t[(x,y)] == $x & $y - doAssert t.sortedPairs == @[((x: 0, y: 0), "00"), ((x: 0, y: 1), "01"), ((x: 1, y: 0), "10"), ((x: 1, y: 1), "11")] + assert t[(x,y)] == $x & $y + assert($t == + "{(x: 1, y: 1): \"11\", (x: 0, y: 0): \"00\", (x: 0, y: 1): \"01\", (x: 1, y: 0): \"10\"}") block tableTest2: var t = initTable[string, float]() @@ -61,74 +60,74 @@ block tableTest2: t["012"] = 67.9 t["123"] = 1.5 # test overwriting - doAssert t["123"] == 1.5 + assert t["123"] == 1.5 try: echo t["111"] # deleted except KeyError: discard - doAssert(not hasKey(t, "111")) + assert(not hasKey(t, "111")) - doAssert "123" in t - doAssert("111" notin t) + assert "123" in t + assert("111" notin t) for key, val in items(data): t[key] = val.toFloat - for key, val in items(data): doAssert t[key] == val.toFloat + for key, val in items(data): assert t[key] == val.toFloat - doAssert(not t.hasKeyOrPut("456", 4.0)) # test absent key - doAssert t.hasKeyOrPut("012", 3.0) # test present key + assert(not t.hasKeyOrPut("456", 4.0)) # test absent key + assert t.hasKeyOrPut("012", 3.0) # test present key var x = t.mgetOrPut("111", 1.5) # test absent key x = x * 2 - doAssert x == 3.0 + assert x == 3.0 x = t.mgetOrPut("test", 1.5) # test present key x = x * 2 - doAssert x == 2 * 1.2345 + assert x == 2 * 1.2345 block orderedTableTest1: var t = initOrderedTable[string, int](2) for key, val in items(data): t[key] = val - for key, val in items(data): doAssert t[key] == val + for key, val in items(data): assert t[key] == val var i = 0 # `pairs` needs to yield in insertion order: for key, val in pairs(t): - doAssert key == data[i][0] - doAssert val == data[i][1] + assert key == data[i][0] + assert val == data[i][1] inc(i) for key, val in mpairs(t): val = 99 - for val in mvalues(t): doAssert val == 99 + for val in mvalues(t): assert val == 99 block orderedTableTest2: var s = initOrderedTable[string, int]() t = initOrderedTable[string, int]() - doAssert s == t + assert s == t for key, val in items(data): t[key] = val - doAssert s != t + assert s != t for key, val in items(sorteddata): s[key] = val - doAssert s != t + assert s != t t.clear() - doAssert s != t + assert s != t for key, val in items(sorteddata): t[key] = val - doAssert s == t + assert s == t block countTableTest1: var s = data.toTable var t = initCountTable[string]() for k in s.keys: t.inc(k) - for k in t.keys: doAssert t[k] == 1 + for k in t.keys: assert t[k] == 1 t.inc("90", 3) t.inc("12", 2) t.inc("34", 1) - doAssert t.largest()[0] == "90" + assert t.largest()[0] == "90" t.sort() var i = 0 for k, v in t.pairs: case i - of 0: doAssert k == "90" and v == 4 - of 1: doAssert k == "12" and v == 3 - of 2: doAssert k == "34" and v == 2 + of 0: assert k == "90" and v == 4 + of 1: assert k == "12" and v == 3 + of 2: assert k == "34" and v == 2 else: break inc i @@ -136,19 +135,19 @@ block countTableTest2: var s = initCountTable[int]() t = initCountTable[int]() - doAssert s == t + assert s == t s.inc(1) - doAssert s != t + assert s != t t.inc(2) - doAssert s != t + assert s != t t.inc(1) - doAssert s != t + assert s != t s.inc(2) - doAssert s == t + assert s == t s.inc(1) - doAssert s != t + assert s != t t.inc(1) - doAssert s == t + assert s == t block mpairsTableTest1: var t = initTable[string, int]() @@ -162,9 +161,9 @@ block mpairsTableTest1: for k, v in t.pairs: if k == "a" or k == "c": - doAssert v == 9 + assert v == 9 else: - doAssert v != 1 and v != 3 + assert v != 1 and v != 3 block SyntaxTest: var x = toTable[int, string]({:}) @@ -174,10 +173,10 @@ block zeroHashKeysTest: let initialLen = t.len var testTable = t testTable[nullHashKey] = value - doAssert testTable[nullHashKey] == value - doAssert testTable.len == initialLen + 1 + assert testTable[nullHashKey] == value + assert testTable.len == initialLen + 1 testTable.del(nullHashKey) - doAssert testTable.len == initialLen + assert testTable.len == initialLen # with empty table doZeroHashValueTest(toTable[int,int]({:}), 0, 42) @@ -194,46 +193,46 @@ block zeroHashKeysTest: block clearTableTest: var t = data.toTable - doAssert t.len() != 0 + assert t.len() != 0 t.clear() - doAssert t.len() == 0 + assert t.len() == 0 block clearOrderedTableTest: var t = data.toOrderedTable - doAssert t.len() != 0 + assert t.len() != 0 t.clear() - doAssert t.len() == 0 + assert t.len() == 0 block clearCountTableTest: var t = initCountTable[string]() t.inc("90", 3) t.inc("12", 2) t.inc("34", 1) - doAssert t.len() != 0 + assert t.len() != 0 t.clear() - doAssert t.len() == 0 + assert t.len() == 0 block withKeyTest: var t: SharedTable[int, int] t.init() t.withKey(1) do (k: int, v: var int, pairExists: var bool): - doAssert(v == 0) + assert(v == 0) pairExists = true v = 42 - doAssert(t.mget(1) == 42) + assert(t.mget(1) == 42) t.withKey(1) do (k: int, v: var int, pairExists: var bool): - doAssert(v == 42) + assert(v == 42) pairExists = false try: discard t.mget(1) - doAssert(false, "KeyError expected") + assert(false, "KeyError expected") except KeyError: discard t.withKey(2) do (k: int, v: var int, pairExists: var bool): pairExists = false try: discard t.mget(2) - doAssert(false, "KeyError expected") + assert(false, "KeyError expected") except KeyError: discard @@ -242,20 +241,20 @@ block takeTest: t["key"] = 123 var val = 0 - doAssert(t.take("key", val)) - doAssert(val == 123) + assert(t.take("key", val)) + assert(val == 123) val = -1 - doAssert(not t.take("key", val)) - doAssert(val == -1) + assert(not t.take("key", val)) + assert(val == -1) - doAssert(not t.take("otherkey", val)) - doAssert(val == -1) + assert(not t.take("otherkey", val)) + assert(val == -1) proc orderedTableSortTest() = var t = initOrderedTable[string, int](2) for key, val in items(data): t[key] = val - for key, val in items(data): doAssert t[key] == val + for key, val in items(data): assert t[key] == val t.sort(proc (x, y: tuple[key: string, val: int]): int = cmp(x.key, y.key)) var i = 0 # `pairs` needs to yield in sorted order: diff --git a/tests/compiler/samplelib.nim b/tests/compiler/samplelib.nim deleted file mode 100644 index c70971722..000000000 --- a/tests/compiler/samplelib.nim +++ /dev/null @@ -1,2 +0,0 @@ -# Sample library used by tcmdlineclib.nim -proc test(): int {.cdecl, exportc, dynlib.} = 123 diff --git a/tests/compiler/t12684.nim b/tests/compiler/t12684.nim deleted file mode 100644 index a5f33d2c9..000000000 --- a/tests/compiler/t12684.nim +++ /dev/null @@ -1,7 +0,0 @@ -discard """ - cmd: "nim check --hints:off --warnings:off $file" - errormsg: "undeclared identifier: 'Undeclared'" -""" - -var x: Undeclared -import compiler/nimeval diff --git a/tests/compiler/tasciitables.nim b/tests/compiler/tasciitables.nim index 2f3b7bf2f..0a5ee0f05 100644 --- a/tests/compiler/tasciitables.nim +++ b/tests/compiler/tasciitables.nim @@ -1,5 +1,5 @@ -import stdtest/unittest_light -import std/private/asciitables +import compiler/unittest_light +import compiler/asciitables import strformat diff --git a/tests/compiler/tasm.nim b/tests/compiler/tasm.nim deleted file mode 100644 index 9f60231e0..000000000 --- a/tests/compiler/tasm.nim +++ /dev/null @@ -1,15 +0,0 @@ -proc testAsm() = - let src = 41 - var dst = 0 - - asm """ - mov %1, %0\n\t - add $1, %0 - : "=r" (`dst`) - : "r" (`src`)""" - - doAssert dst == 42 - -when defined(gcc) or defined(clang) and not defined(cpp): - {.passc: "-std=c99".} - testAsm() \ No newline at end of file diff --git a/tests/compiler/tbtrees.nim b/tests/compiler/tbtrees.nim deleted file mode 100644 index 973c26420..000000000 --- a/tests/compiler/tbtrees.nim +++ /dev/null @@ -1,84 +0,0 @@ -discard """ - output: ''' -www.amazon.com: 207.171.182.16 -www.apple.com: 17.112.152.32 -www.cnn.com: 64.236.16.20 -www.cs.princeton.edu: abc -www.dell.com: 143.166.224.230 -www.ebay.com: 66.135.192.87 -www.espn.com: 199.181.135.201 -www.google.com: 216.239.41.99 -www.microsoft.com: 207.126.99.140 -www.nytimes.com: 199.239.136.200 -www.princeton.edu: 128.112.128.15 -www.simpsons.com: 209.052.165.60 -www.slashdot.org: 66.35.250.151 -www.weather.com: 63.111.66.11 -www.yahoo.com: 216.109.118.65 -www.yale.edu: 130.132.143.21 -''' -""" - -import compiler/btrees - -import random, tables - -proc main = - var st = initBTree[string, string]() - st.add("www.cs.princeton.edu", "abc") - st.add("www.princeton.edu", "128.112.128.15") - st.add("www.yale.edu", "130.132.143.21") - st.add("www.simpsons.com", "209.052.165.60") - st.add("www.apple.com", "17.112.152.32") - st.add("www.amazon.com", "207.171.182.16") - st.add("www.ebay.com", "66.135.192.87") - st.add("www.cnn.com", "64.236.16.20") - st.add("www.google.com", "216.239.41.99") - st.add("www.nytimes.com", "199.239.136.200") - st.add("www.microsoft.com", "207.126.99.140") - st.add("www.dell.com", "143.166.224.230") - st.add("www.slashdot.org", "66.35.250.151") - st.add("www.espn.com", "199.181.135.201") - st.add("www.weather.com", "63.111.66.11") - st.add("www.yahoo.com", "216.109.118.65") - - doAssert st.getOrDefault("www.cs.princeton.edu") == "abc" - doAssert st.getOrDefault("www.harvardsucks.com") == "" - - doAssert st.getOrDefault("www.simpsons.com") == "209.052.165.60" - doAssert st.getOrDefault("www.apple.com") == "17.112.152.32" - doAssert st.getOrDefault("www.ebay.com") == "66.135.192.87" - doAssert st.getOrDefault("www.dell.com") == "143.166.224.230" - doAssert(st.len == 16) - - for k, v in st: - echo k, ": ", v - - when false: - var b2 = initBTree[string, string]() - const iters = 10_000 - for i in 1..iters: - b2.add($i, $(iters - i)) - for i in 1..iters: - let x = b2.getOrDefault($i) - if x != $(iters - i): - echo "got ", x, ", but expected ", iters - i - echo b2.len - - when true: - var b2 = initBTree[int, string]() - var t2 = initTable[int, string]() - const iters = 100 - for i in 1..iters: - let x = rand(high(int)) - if not t2.hasKey(x): - doAssert b2.getOrDefault(x).len == 0, " what, tree has this element " & $x - t2[x] = $x - b2.add(x, $x) - - doAssert(b2.len == t2.len, "unique entries " & $b2.len) - for k, v in t2: - doAssert $k == v - doAssert b2.getOrDefault(k) == $k - -main() diff --git a/tests/compiler/tcmdlineclib.nim b/tests/compiler/tcmdlineclib.nim deleted file mode 100644 index c06d6f103..000000000 --- a/tests/compiler/tcmdlineclib.nim +++ /dev/null @@ -1,3 +0,0 @@ -proc test(): int {.importc, cdecl.} - -doAssert test() == 123 diff --git a/tests/compiler/tcmdlineclib.nims b/tests/compiler/tcmdlineclib.nims deleted file mode 100644 index f7899d92e..000000000 --- a/tests/compiler/tcmdlineclib.nims +++ /dev/null @@ -1,10 +0,0 @@ -import os - -selfExec "c --app:lib " & (projectDir() / "samplelib.nim") -switch("clibdir", projectDir()) ---clib:samplelib - -# Make test executable can load sample shared library. -# `-rpath` option doesn't work and ignored on Windows. -# But the dll file in same directory as executable file is loaded. -switch("passL", "-Wl,-rpath," & projectDir()) diff --git a/tests/compiler/tcmdlineoswin.nim b/tests/compiler/tcmdlineoswin.nim index 602671e98..6642c5ac6 100644 --- a/tests/compiler/tcmdlineoswin.nim +++ b/tests/compiler/tcmdlineoswin.nim @@ -2,7 +2,7 @@ discard """ cmd: "nim $target $options --os:windows $file" disabled: "linux" disabled: "bsd" - disabled: "osx" + disabled: "macosx" disabled: "unix" disabled: "posix" """ diff --git a/tests/compiler/tcppCompileToNamespace.nim b/tests/compiler/tcppCompileToNamespace.nim index 4e895c38b..1d0977236 100644 --- a/tests/compiler/tcppCompileToNamespace.nim +++ b/tests/compiler/tcppCompileToNamespace.nim @@ -1,5 +1,6 @@ discard """ cmd: "nim cpp --cppCompileToNamespace:foo $options -r $file" +target: cpp """ # Theoretically nim could just ignore the flag cppCompileToNamespace diff --git a/tests/compiler/tdebugutils.nim b/tests/compiler/tdebugutils.nim deleted file mode 100644 index 50b15cb78..000000000 --- a/tests/compiler/tdebugutils.nim +++ /dev/null @@ -1,38 +0,0 @@ -discard """ - joinable: false - disabled: true -""" - -#[ -This test illustrates some features of `debugutils` to debug the compiler. - -## example -this shows how to enable compiler logging just for a section of user code, -without generating tons of unrelated log messages for code you're not interested -in debugging. - -```sh -# enable some debugging code, e.g. the `when false:` block in `semExpr` -nim c -o:bin/nim_temp --stacktrace -d:debug -d:nimDebugUtils compiler/nim -bin/nim_temp c tests/compiler/tdebugutils.nim -``` - -(use --filenames:abs for abs files) - -## result -("<", "tdebugutils.nim(16, 3)", {.define(nimCompilerDebug).}, nil) -(">", "tdebugutils.nim(17, 3)", let a = 2.5 * 3, {}, nkLetSection) -(">", "tdebugutils.nim(17, 15)", 2.5 * 3, {efAllowDestructor, efWantValue}, nkInfix) -(">", "tdebugutils.nim(17, 11)", 2.5, {efAllowStmt, efDetermineType, efOperand}, nkFloatLit) -("<", "tdebugutils.nim(17, 11)", 2.5, float64) -(">", "tdebugutils.nim(17, 17)", 3, {efAllowStmt, efDetermineType, efOperand}, nkIntLit) -("<", "tdebugutils.nim(17, 17)", 3, int literal(3)) -("<", "tdebugutils.nim(17, 15)", 2.5 * 3, float) -("<", "tdebugutils.nim(17, 3)", let a = 2.5 * 3, nil) -(">", "tdebugutils.nim(18, 3)", {.undef(nimCompilerDebug).}, {}, nkPragma) -]# - -proc main = - {.define(nimCompilerDebug).} - let a = 2.5 * 3 - {.undef(nimCompilerDebug).} diff --git a/tests/compiler/tgrammar.nim b/tests/compiler/tgrammar.nim deleted file mode 100644 index 772d0f0cc..000000000 --- a/tests/compiler/tgrammar.nim +++ /dev/null @@ -1,7 +0,0 @@ -discard """ - matrix: "-d:nimTestGrammar" -""" - -import compiler/parser - -checkSameGrammar() diff --git a/tests/compiler/tint128.nim b/tests/compiler/tint128.nim deleted file mode 100644 index a30b1b1cc..000000000 --- a/tests/compiler/tint128.nim +++ /dev/null @@ -1,184 +0,0 @@ -import compiler/int128 - -let (a,b) = divMod(Ten,Ten) - -doAssert $One == "1" -doAssert $Ten == "10" -doAssert $Zero == "0" -let c = parseDecimalInt128("12345678989876543210123456789") -doAssert $c == "12345678989876543210123456789" - -var d : array[39, Int128] -d[0] = parseDecimalInt128("1") -d[1] = parseDecimalInt128("10") -d[2] = parseDecimalInt128("100") -d[3] = parseDecimalInt128("1000") -d[4] = parseDecimalInt128("10000") -d[5] = parseDecimalInt128("100000") -d[6] = parseDecimalInt128("1000000") -d[7] = parseDecimalInt128("10000000") -d[8] = parseDecimalInt128("100000000") -d[9] = parseDecimalInt128("1000000000") -d[10] = parseDecimalInt128("10000000000") -d[11] = parseDecimalInt128("100000000000") -d[12] = parseDecimalInt128("1000000000000") -d[13] = parseDecimalInt128("10000000000000") -d[14] = parseDecimalInt128("100000000000000") -d[15] = parseDecimalInt128("1000000000000000") -d[16] = parseDecimalInt128("10000000000000000") -d[17] = parseDecimalInt128("100000000000000000") -d[18] = parseDecimalInt128("1000000000000000000") -d[19] = parseDecimalInt128("10000000000000000000") -d[20] = parseDecimalInt128("100000000000000000000") -d[21] = parseDecimalInt128("1000000000000000000000") -d[22] = parseDecimalInt128("10000000000000000000000") -d[23] = parseDecimalInt128("100000000000000000000000") -d[24] = parseDecimalInt128("1000000000000000000000000") -d[25] = parseDecimalInt128("10000000000000000000000000") -d[26] = parseDecimalInt128("100000000000000000000000000") -d[27] = parseDecimalInt128("1000000000000000000000000000") -d[28] = parseDecimalInt128("10000000000000000000000000000") -d[29] = parseDecimalInt128("100000000000000000000000000000") -d[30] = parseDecimalInt128("1000000000000000000000000000000") -d[31] = parseDecimalInt128("10000000000000000000000000000000") -d[32] = parseDecimalInt128("100000000000000000000000000000000") -d[33] = parseDecimalInt128("1000000000000000000000000000000000") -d[34] = parseDecimalInt128("10000000000000000000000000000000000") -d[35] = parseDecimalInt128("100000000000000000000000000000000000") -d[36] = parseDecimalInt128("1000000000000000000000000000000000000") -d[37] = parseDecimalInt128("10000000000000000000000000000000000000") -d[38] = parseDecimalInt128("100000000000000000000000000000000000000") - -for i in 0..= 0: - doAssert d[i] div d[j] == d[i-j] - -var sum: Int128 - -for it in d: - sum += it - -doAssert $sum == "111111111111111111111111111111111111111" - -for it in d.mitems: - it = -it - -for i in 0..= 0: - doAssert d[i] div d[j] == -d[i-j] - -doAssert $high(Int128) == "170141183460469231731687303715884105727" -doAssert $low(Int128) == "-170141183460469231731687303715884105728" - -var ma = 100'i64 -var mb = 13 - -doAssert toInt128(ma) * toInt128(0) == toInt128(0) -doAssert toInt128(-ma) * toInt128(0) == toInt128(0) - -# sign correctness -doAssert divMod(toInt128( ma),toInt128( mb)) == (toInt128( ma div mb), toInt128( ma mod mb)) -doAssert divMod(toInt128(-ma),toInt128( mb)) == (toInt128(-ma div mb), toInt128(-ma mod mb)) -doAssert divMod(toInt128( ma),toInt128(-mb)) == (toInt128( ma div -mb), toInt128( ma mod -mb)) -doAssert divMod(toInt128(-ma),toInt128(-mb)) == (toInt128(-ma div -mb), toInt128(-ma mod -mb)) - -doAssert divMod(toInt128( mb),toInt128( mb)) == (toInt128( mb div mb), toInt128( mb mod mb)) -doAssert divMod(toInt128(-mb),toInt128( mb)) == (toInt128(-mb div mb), toInt128(-mb mod mb)) -doAssert divMod(toInt128( mb),toInt128(-mb)) == (toInt128( mb div -mb), toInt128( mb mod -mb)) -doAssert divMod(toInt128(-mb),toInt128(-mb)) == (toInt128(-mb div -mb), toInt128(-mb mod -mb)) - -doAssert divMod(toInt128( mb),toInt128( ma)) == (toInt128( mb div ma), toInt128( mb mod ma)) -doAssert divMod(toInt128(-mb),toInt128( ma)) == (toInt128(-mb div ma), toInt128(-mb mod ma)) -doAssert divMod(toInt128( mb),toInt128(-ma)) == (toInt128( mb div -ma), toInt128( mb mod -ma)) -doAssert divMod(toInt128(-mb),toInt128(-ma)) == (toInt128(-mb div -ma), toInt128(-mb mod -ma)) - -let e = parseDecimalInt128("70997106675279150998592376708984375") - -let strArray = [ - # toHex(e shr 0), toHex(e shr 1), toHex(e shr 2), toHex(e shr 3) - "000dac6d782d266a37300c32591eee37", "0006d636bc1693351b9806192c8f771b", "00036b1b5e0b499a8dcc030c9647bb8d", "0001b58daf05a4cd46e601864b23ddc6", - "0000dac6d782d266a37300c32591eee3", "00006d636bc1693351b9806192c8f771", "000036b1b5e0b499a8dcc030c9647bb8", "00001b58daf05a4cd46e601864b23ddc", - "00000dac6d782d266a37300c32591eee", "000006d636bc1693351b9806192c8f77", "0000036b1b5e0b499a8dcc030c9647bb", "000001b58daf05a4cd46e601864b23dd", - "000000dac6d782d266a37300c32591ee", "0000006d636bc1693351b9806192c8f7", "00000036b1b5e0b499a8dcc030c9647b", "0000001b58daf05a4cd46e601864b23d", - "0000000dac6d782d266a37300c32591e", "00000006d636bc1693351b9806192c8f", "000000036b1b5e0b499a8dcc030c9647", "00000001b58daf05a4cd46e601864b23", - "00000000dac6d782d266a37300c32591", "000000006d636bc1693351b9806192c8", "0000000036b1b5e0b499a8dcc030c964", "000000001b58daf05a4cd46e601864b2", - "000000000dac6d782d266a37300c3259", "0000000006d636bc1693351b9806192c", "00000000036b1b5e0b499a8dcc030c96", "0000000001b58daf05a4cd46e601864b", - "0000000000dac6d782d266a37300c325", "00000000006d636bc1693351b9806192", "000000000036b1b5e0b499a8dcc030c9", "00000000001b58daf05a4cd46e601864", - "00000000000dac6d782d266a37300c32", "000000000006d636bc1693351b980619", "0000000000036b1b5e0b499a8dcc030c", "000000000001b58daf05a4cd46e60186", - "000000000000dac6d782d266a37300c3", "0000000000006d636bc1693351b98061", "00000000000036b1b5e0b499a8dcc030", "0000000000001b58daf05a4cd46e6018", - "0000000000000dac6d782d266a37300c", "00000000000006d636bc1693351b9806", "000000000000036b1b5e0b499a8dcc03", "00000000000001b58daf05a4cd46e601", - "00000000000000dac6d782d266a37300", "000000000000006d636bc1693351b980", "0000000000000036b1b5e0b499a8dcc0", "000000000000001b58daf05a4cd46e60", - "000000000000000dac6d782d266a3730", "0000000000000006d636bc1693351b98", "00000000000000036b1b5e0b499a8dcc", "0000000000000001b58daf05a4cd46e6", - "0000000000000000dac6d782d266a373", "00000000000000006d636bc1693351b9", "000000000000000036b1b5e0b499a8dc", "00000000000000001b58daf05a4cd46e", - "00000000000000000dac6d782d266a37", "000000000000000006d636bc1693351b", "0000000000000000036b1b5e0b499a8d", "000000000000000001b58daf05a4cd46", - "000000000000000000dac6d782d266a3", "0000000000000000006d636bc1693351", "00000000000000000036b1b5e0b499a8", "0000000000000000001b58daf05a4cd4", - "0000000000000000000dac6d782d266a", "00000000000000000006d636bc169335", "000000000000000000036b1b5e0b499a", "00000000000000000001b58daf05a4cd", - "00000000000000000000dac6d782d266", "000000000000000000006d636bc16933", "0000000000000000000036b1b5e0b499", "000000000000000000001b58daf05a4c", - "000000000000000000000dac6d782d26", "0000000000000000000006d636bc1693", "00000000000000000000036b1b5e0b49", "0000000000000000000001b58daf05a4", - "0000000000000000000000dac6d782d2", "00000000000000000000006d636bc169", "000000000000000000000036b1b5e0b4", "00000000000000000000001b58daf05a", - "00000000000000000000000dac6d782d", "000000000000000000000006d636bc16", "0000000000000000000000036b1b5e0b", "000000000000000000000001b58daf05", - "000000000000000000000000dac6d782", "0000000000000000000000006d636bc1", "00000000000000000000000036b1b5e0", "0000000000000000000000001b58daf0", - "0000000000000000000000000dac6d78", "00000000000000000000000006d636bc", "000000000000000000000000036b1b5e", "00000000000000000000000001b58daf", - "00000000000000000000000000dac6d7", "000000000000000000000000006d636b", "0000000000000000000000000036b1b5", "000000000000000000000000001b58da", - "000000000000000000000000000dac6d", "0000000000000000000000000006d636", "00000000000000000000000000036b1b", "0000000000000000000000000001b58d", - "0000000000000000000000000000dac6", "00000000000000000000000000006d63", "000000000000000000000000000036b1", "00000000000000000000000000001b58", - "00000000000000000000000000000dac", "000000000000000000000000000006d6", "0000000000000000000000000000036b", "000000000000000000000000000001b5", - "000000000000000000000000000000da", "0000000000000000000000000000006d", "00000000000000000000000000000036", "0000000000000000000000000000001b", - "0000000000000000000000000000000d", "00000000000000000000000000000006", "00000000000000000000000000000003", "00000000000000000000000000000001", - "00000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", - "00000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", - "00000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", -] - -for i in 0 ..< 128: - let str1 = toHex(e shr i) - let str2 = strArray[i] - doAssert str1 == str2 - -let strArray2 = [ - "000dac6d782d266a37300c32591eee37", "001b58daf05a4cd46e601864b23ddc6e", "0036b1b5e0b499a8dcc030c9647bb8dc", "006d636bc1693351b9806192c8f771b8", - "00dac6d782d266a37300c32591eee370", "01b58daf05a4cd46e601864b23ddc6e0", "036b1b5e0b499a8dcc030c9647bb8dc0", "06d636bc1693351b9806192c8f771b80", - "0dac6d782d266a37300c32591eee3700", "1b58daf05a4cd46e601864b23ddc6e00", "36b1b5e0b499a8dcc030c9647bb8dc00", "6d636bc1693351b9806192c8f771b800", - "dac6d782d266a37300c32591eee37000", "b58daf05a4cd46e601864b23ddc6e000", "6b1b5e0b499a8dcc030c9647bb8dc000", "d636bc1693351b9806192c8f771b8000", - "ac6d782d266a37300c32591eee370000", "58daf05a4cd46e601864b23ddc6e0000", "b1b5e0b499a8dcc030c9647bb8dc0000", "636bc1693351b9806192c8f771b80000", - "c6d782d266a37300c32591eee3700000", "8daf05a4cd46e601864b23ddc6e00000", "1b5e0b499a8dcc030c9647bb8dc00000", "36bc1693351b9806192c8f771b800000", - "6d782d266a37300c32591eee37000000", "daf05a4cd46e601864b23ddc6e000000", "b5e0b499a8dcc030c9647bb8dc000000", "6bc1693351b9806192c8f771b8000000", - "d782d266a37300c32591eee370000000", "af05a4cd46e601864b23ddc6e0000000", "5e0b499a8dcc030c9647bb8dc0000000", "bc1693351b9806192c8f771b80000000", - "782d266a37300c32591eee3700000000", "f05a4cd46e601864b23ddc6e00000000", "e0b499a8dcc030c9647bb8dc00000000", "c1693351b9806192c8f771b800000000", - "82d266a37300c32591eee37000000000", "05a4cd46e601864b23ddc6e000000000", "0b499a8dcc030c9647bb8dc000000000", "1693351b9806192c8f771b8000000000", - "2d266a37300c32591eee370000000000", "5a4cd46e601864b23ddc6e0000000000", "b499a8dcc030c9647bb8dc0000000000", "693351b9806192c8f771b80000000000", - "d266a37300c32591eee3700000000000", "a4cd46e601864b23ddc6e00000000000", "499a8dcc030c9647bb8dc00000000000", "93351b9806192c8f771b800000000000", - "266a37300c32591eee37000000000000", "4cd46e601864b23ddc6e000000000000", "99a8dcc030c9647bb8dc000000000000", "3351b9806192c8f771b8000000000000", - "66a37300c32591eee370000000000000", "cd46e601864b23ddc6e0000000000000", "9a8dcc030c9647bb8dc0000000000000", "351b9806192c8f771b80000000000000", - "6a37300c32591eee3700000000000000", "d46e601864b23ddc6e00000000000000", "a8dcc030c9647bb8dc00000000000000", "51b9806192c8f771b800000000000000", - "a37300c32591eee37000000000000000", "46e601864b23ddc6e000000000000000", "8dcc030c9647bb8dc000000000000000", "1b9806192c8f771b8000000000000000", - "37300c32591eee370000000000000000", "6e601864b23ddc6e0000000000000000", "dcc030c9647bb8dc0000000000000000", "b9806192c8f771b80000000000000000", - "7300c32591eee3700000000000000000", "e601864b23ddc6e00000000000000000", "cc030c9647bb8dc00000000000000000", "9806192c8f771b800000000000000000", - "300c32591eee37000000000000000000", "601864b23ddc6e000000000000000000", "c030c9647bb8dc000000000000000000", "806192c8f771b8000000000000000000", - "00c32591eee370000000000000000000", "01864b23ddc6e0000000000000000000", "030c9647bb8dc0000000000000000000", "06192c8f771b80000000000000000000", - "0c32591eee3700000000000000000000", "1864b23ddc6e00000000000000000000", "30c9647bb8dc00000000000000000000", "6192c8f771b800000000000000000000", - "c32591eee37000000000000000000000", "864b23ddc6e000000000000000000000", "0c9647bb8dc000000000000000000000", "192c8f771b8000000000000000000000", - "32591eee370000000000000000000000", "64b23ddc6e0000000000000000000000", "c9647bb8dc0000000000000000000000", "92c8f771b80000000000000000000000", - "2591eee3700000000000000000000000", "4b23ddc6e00000000000000000000000", "9647bb8dc00000000000000000000000", "2c8f771b800000000000000000000000", - "591eee37000000000000000000000000", "b23ddc6e000000000000000000000000", "647bb8dc000000000000000000000000", "c8f771b8000000000000000000000000", - "91eee370000000000000000000000000", "23ddc6e0000000000000000000000000", "47bb8dc0000000000000000000000000", "8f771b80000000000000000000000000", - "1eee3700000000000000000000000000", "3ddc6e00000000000000000000000000", "7bb8dc00000000000000000000000000", "f771b800000000000000000000000000", - "eee37000000000000000000000000000", "ddc6e000000000000000000000000000", "bb8dc000000000000000000000000000", "771b8000000000000000000000000000", - "ee370000000000000000000000000000", "dc6e0000000000000000000000000000", "b8dc0000000000000000000000000000", "71b80000000000000000000000000000", - "e3700000000000000000000000000000", "c6e00000000000000000000000000000", "8dc00000000000000000000000000000", "1b800000000000000000000000000000", - "37000000000000000000000000000000", "6e000000000000000000000000000000", "dc000000000000000000000000000000", "b8000000000000000000000000000000", - "70000000000000000000000000000000", "e0000000000000000000000000000000", "c0000000000000000000000000000000", "80000000000000000000000000000000", -] - -for i in 0 ..< 128: - let str1 = toHex(e shl i) - let str2 = strArray2[i] - doAssert str1 == str2 diff --git a/tests/compiler/tnimblecmd.nim b/tests/compiler/tnimblecmd.nim deleted file mode 100644 index 53bce4625..000000000 --- a/tests/compiler/tnimblecmd.nim +++ /dev/null @@ -1,75 +0,0 @@ -include compiler/[nimblecmd], sets - -proc v(s: string): Version = s.newVersion - -proc testVersionsComparison = - # #head is special in the sense that it's assumed to always be newest. - doAssert v"1.0" < v"#head" - doAssert v"1.0" < v"1.1" - doAssert v"1.0.1" < v"1.1" - doAssert v"1" < v"1.1" - doAssert v"#aaaqwe" < v"1.1" # We cannot assume that a branch is newer. - doAssert v"#a111" < v"#head" - -proc testAddPackageWithoutChecksum = - ## For backward compatibility it is not required all packages to have a - ## sha1 checksum at the end of the name of the Nimble cache directory. - ## This way a new compiler will be able to work with an older Nimble. - - let conf = newConfigRef() - var rr: PackageInfo - - addPackage conf, rr, "irc-#a111", unknownLineInfo - addPackage conf, rr, "irc-#head", unknownLineInfo - addPackage conf, rr, "irc-0.1.0", unknownLineInfo - - addPackage conf, rr, "another-0.1", unknownLineInfo - - addPackage conf, rr, "ab-0.1.3", unknownLineInfo - addPackage conf, rr, "ab-0.1", unknownLineInfo - addPackage conf, rr, "justone-1.0", unknownLineInfo - - doAssert toSeq(rr.chosen).toHashSet == - ["irc-#head", "another-0.1", "ab-0.1.3", "justone-1.0"].toHashSet - -proc testAddPackageWithChecksum = - let conf = newConfigRef() - var rr: PackageInfo - - # in the case of packages with the same version, but different checksums for - # now the first one will be chosen - - addPackage conf, rr, "irc-#a111-DBC1F902CB79946E990E38AF51F0BAD36ACFABD9", - unknownLineInfo - addPackage conf, rr, "irc-#head-042D4BE2B90ED0672E717D71850ABDB0A2D19CD1", - unknownLineInfo - addPackage conf, rr, "irc-#head-042D4BE2B90ED0672E717D71850ABDB0A2D19CD2", - unknownLineInfo - addPackage conf, rr, "irc-0.1.0-6EE6DE936B32E82C7DBE526DA3463574F6568FAF", - unknownLineInfo - - addPackage conf, rr, "another-0.1", unknownLineInfo - addPackage conf, rr, "another-0.1-F07EE6040579F0590608A8FD34F5F2D91D859340", - unknownLineInfo - - addPackage conf, rr, "ab-0.1.3-34BC3B72CE46CF5A496D1121CFEA7369385E9EA2", - unknownLineInfo - addPackage conf, rr, "ab-0.1.3-24BC3B72CE46CF5A496D1121CFEA7369385E9EA2", - unknownLineInfo - addPackage conf, rr, "ab-0.1-A3CFFABDC4759F7779D541F5E031AED17169390A", - unknownLineInfo - - # lower case hex digits is also a valid sha1 checksum - addPackage conf, rr, "justone-1.0-f07ee6040579f0590608a8fd34f5f2d91d859340", - unknownLineInfo - - doAssert toSeq(rr.chosen).toHashSet == [ - "irc-#head-042D4BE2B90ED0672E717D71850ABDB0A2D19CD1", - "another-0.1", - "ab-0.1.3-34BC3B72CE46CF5A496D1121CFEA7369385E9EA2", - "justone-1.0-f07ee6040579f0590608a8fd34f5f2d91d859340" - ].toHashSet - -testVersionsComparison() -testAddPackageWithoutChecksum() -testAddPackageWithChecksum() diff --git a/tests/compiler/tpathutils.nim b/tests/compiler/tpathutils.nim deleted file mode 100644 index 47ff0f06a..000000000 --- a/tests/compiler/tpathutils.nim +++ /dev/null @@ -1,18 +0,0 @@ -import compiler/pathutils -import os, strutils - - -doAssert AbsoluteDir"/Users/me///" / RelativeFile"z.nim" == AbsoluteFile"/Users/me/z.nim" -doAssert AbsoluteDir"/Users/me" / RelativeFile"../z.nim" == AbsoluteFile"/Users/z.nim" -doAssert AbsoluteDir"/Users/me/" / RelativeFile"../z.nim" == AbsoluteFile"/Users/z.nim" -doAssert relativePath("/foo/bar.nim", "/foo/", '/') == "bar.nim" -doAssert $RelativeDir"foo/bar" == "foo/bar" -doAssert RelativeDir"foo/bar" == RelativeDir"foo/bar" -doAssert RelativeFile"foo/bar".changeFileExt(".txt") == RelativeFile"foo/bar.txt" -doAssert RelativeFile"foo/bar".addFileExt(".txt") == RelativeFile"foo/bar.txt" -doAssert not RelativeDir"foo/bar".isEmpty -doAssert RelativeDir"".isEmpty - -when defined(windows): - let nasty = string(AbsoluteDir(r"C:\Users\rumpf\projects\nim\tests\nimble\nimbleDir\linkedPkgs\pkgB-#head\../../simplePkgs/pkgB-#head/") / RelativeFile"pkgA/module.nim") - doAssert nasty.replace('/', '\\') == r"C:\Users\rumpf\projects\nim\tests\nimble\nimbleDir\simplePkgs\pkgB-#head\pkgA\module.nim" diff --git a/tests/compiler/tprefixmatches.nim b/tests/compiler/tprefixmatches.nim deleted file mode 100644 index 6a3186729..000000000 --- a/tests/compiler/tprefixmatches.nim +++ /dev/null @@ -1,32 +0,0 @@ -import compiler/prefixmatches -import macros - -macro check(val, body: untyped): untyped = - result = newStmtList() - expectKind body, nnkStmtList - for b in body: - expectKind b, nnkTupleConstr - expectLen b, 2 - let p = b[0] - let s = b[1] - result.add quote do: - doAssert prefixMatch(`p`, `s`) == `val` - -check PrefixMatch.Prefix: - ("abc", "abc") - ("a", "abc") - ("xyz", "X_yzzzZe") - -check PrefixMatch.Substr: - ("b", "abc") - ("abc", "fooabcabc") - ("abC", "foo_AB_c") - -check PrefixMatch.Abbrev: - ("abc", "AxxxBxxxCxxx") - ("xyz", "X_yabcZe") - -check PrefixMatch.None: - ("foobar", "afkslfjd_as") - ("xyz", "X_yuuZuuZe") - ("ru", "remotes") diff --git a/tests/compiler/tunittest_light.nim b/tests/compiler/tunittest_light.nim index 2951cc664..422474002 100644 --- a/tests/compiler/tunittest_light.nim +++ b/tests/compiler/tunittest_light.nim @@ -1,8 +1,8 @@ -import stdtest/unittest_light +import compiler/unittest_light proc testAssertEquals() = assertEquals("foo", "foo") - doAssertRaises(AssertionDefect): + doAssertRaises(AssertionError): assertEquals("foo", "foo ") proc testMismatch() = diff --git a/tests/compilerapi/invalid.nim b/tests/compilerapi/invalid.nim deleted file mode 100644 index 3c9364402..000000000 --- a/tests/compilerapi/invalid.nim +++ /dev/null @@ -1 +0,0 @@ -noSuchProc() diff --git a/tests/compilerapi/tcompilerapi.nim b/tests/compilerapi/tcompilerapi.nim index 828dcd0d9..edeaa2ba5 100644 --- a/tests/compilerapi/tcompilerapi.nim +++ b/tests/compilerapi/tcompilerapi.nim @@ -5,7 +5,6 @@ discard """ my secret 11 12 -raising VMQuit ''' joinable: "false" """ @@ -13,35 +12,33 @@ raising VMQuit ## Example program that demonstrates how to use the ## compiler as an API to embed into your own projects. -import "../../compiler" / [ast, vmdef, vm, nimeval, llstream, lineinfos, options] +import "../../compiler" / [ast, vmdef, vm, nimeval, llstream] import std / [os] -proc initInterpreter(script: string): Interpreter = - let std = findNimStdLibCompileTime() - result = createInterpreter(script, [std, parentDir(currentSourcePath), - std / "pure", std / "core"]) - proc main() = - let i = initInterpreter("myscript.nim") - i.implementRoutine("nim", "exposed", "addFloats", proc (a: VmArgs) = + let std = findNimStdLibCompileTime() + var intr = createInterpreter("myscript.nim",[std, parentDir(currentSourcePath)]) + intr.implementRoutine("*", "exposed", "addFloats", proc (a: VmArgs) = setResult(a, getFloat(a, 0) + getFloat(a, 1) + getFloat(a, 2)) ) - i.evalScript() - let foreignProc = i.selectRoutine("hostProgramRunsThis") + + intr.evalScript() + + let foreignProc = selectRoutine(intr, "hostProgramRunsThis") if foreignProc == nil: quit "script does not export a proc of the name: 'hostProgramRunsThis'" - let res = i.callRoutine(foreignProc, [newFloatNode(nkFloatLit, 0.9), - newFloatNode(nkFloatLit, 0.1)]) + let res = intr.callRoutine(foreignProc, [newFloatNode(nkFloatLit, 0.9), + newFloatNode(nkFloatLit, 0.1)]) doAssert res.kind == nkFloatLit echo res.floatVal - let foreignValue = i.selectUniqueSymbol("hostProgramWantsThis") + let foreignValue = selectUniqueSymbol(intr, "hostProgramWantsThis") if foreignValue == nil: quit "script does not export a global of the name: hostProgramWantsThis" - let val = i.getGlobalValue(foreignValue) + let val = intr.getGlobalValue(foreignValue) doAssert val.kind in {nkStrLit..nkTripleStrLit} echo val.strVal - i.destroyInterpreter() + destroyInterpreter(intr) main() @@ -49,23 +46,10 @@ block issue9180: proc evalString(code: string, moduleName = "script.nim") = let stream = llStreamOpen(code) let std = findNimStdLibCompileTime() - var intr = createInterpreter(moduleName, [std, std / "pure", std / "core"]) + var intr = createInterpreter(moduleName, [std]) intr.evalScript(stream) destroyInterpreter(intr) llStreamClose(stream) evalString("echo 10+1") evalString("echo 10+2") - -block error_hook: - type VMQuit = object of CatchableError - - let i = initInterpreter("invalid.nim") - i.registerErrorHook proc(config: ConfigRef; info: TLineInfo; msg: string; - severity: Severity) {.gcsafe.} = - if severity == Error and config.errorCounter >= config.errorMax: - echo "raising VMQuit" - raise newException(VMQuit, "Script error") - - doAssertRaises(VMQuit): - i.evalScript() diff --git a/tests/compilerfeatures/texpandmacro.nim b/tests/compilerfeatures/texpandmacro.nim index fea8b571f..76b0263ae 100644 --- a/tests/compilerfeatures/texpandmacro.nim +++ b/tests/compilerfeatures/texpandmacro.nim @@ -1,6 +1,6 @@ discard """ cmd: "nim c --expandMacro:foo $file" - nimout: '''texpandmacro.nim(17, 1) Hint: expanded macro: + nimout: '''Hint: expanded macro: echo ["injected echo"] var x = 4 [ExpandMacro] ''' diff --git a/tests/compiles/mstaticlib.nim b/tests/compiles/mstaticlib.nim deleted file mode 100644 index 6ed593691..000000000 --- a/tests/compiles/mstaticlib.nim +++ /dev/null @@ -1 +0,0 @@ -echo 1234 \ No newline at end of file diff --git a/tests/compiles/t8630.nim b/tests/compiles/t8630.nim index 8b447d061..aa2be11cd 100644 --- a/tests/compiles/t8630.nim +++ b/tests/compiles/t8630.nim @@ -7,7 +7,7 @@ bar proc test(strings: seq[string]) = for s in strings: - var p3 = addr(s) + var p3 = unsafeAddr(s) echo p3[] test(@["foo", "bar"]) diff --git a/tests/compiles/trecursive_generic_in_compiles.nim b/tests/compiles/trecursive_generic_in_compiles.nim index ab31ad0f5..88d3faeed 100644 --- a/tests/compiles/trecursive_generic_in_compiles.nim +++ b/tests/compiles/trecursive_generic_in_compiles.nim @@ -50,7 +50,7 @@ proc `==`*[T](xs, ys: List[T]): bool = proc asList*[T](xs: varargs[T]): List[T] = ## Creates list from varargs - proc initListImpl(i: int, xs: openArray[T]): List[T] = + proc initListImpl(i: int, xs: openarray[T]): List[T] = if i > high(xs): Nil[T]() else: diff --git a/tests/compiles/tstaticlib.nim b/tests/compiles/tstaticlib.nim deleted file mode 100644 index a18b59204..000000000 --- a/tests/compiles/tstaticlib.nim +++ /dev/null @@ -1,22 +0,0 @@ -import std/[os, osproc, strformat] - - -const dir = "tests/compiles" -const fileName = dir / "mstaticlib.nim" -const nim = getCurrentCompilerExe() - -block: # bug #18578 - const libName = dir / "tstaticlib1.a" - let (_, status) = execCmdEx(fmt"{nim} c -o:{libName} --app:staticlib {fileName}") - doAssert status == 0 - doAssert fileExists(libName) - removeFile(libName) - -block: # bug #16947 - const libName = dir / "tstaticlib2.a" - writeFile(libName, "echo 124") - doAssert fileExists(libName) - let (_, status) = execCmdEx(fmt"{nim} c -o:{libName} --app:staticlib {fileName}") - doAssert status == 0 - doAssert fileExists(libName) - removeFile(libName) diff --git a/tests/concepts/t18409.nim b/tests/concepts/t18409.nim deleted file mode 100644 index 0edba2d31..000000000 --- a/tests/concepts/t18409.nim +++ /dev/null @@ -1,37 +0,0 @@ -discard """ - action: "compile" -""" - -# A vector space over a field F concept. -type VectorSpace*[F] = concept x, y, type V - vector_add(x, y) is V - scalar_mul(x, F) is V - dimension(V) is Natural - -# Real numbers (here floats) form a vector space. -func vector_add*(v: float, w: float): float = v + w -func scalar_mul*(v: float, s: float): float = v * s -func dimension*(x: typedesc[float]): Natural = 1 - -# 2-tuples of real numbers form a vector space. -func vector_add*(v, w: (float, float)): (float, float) = - (vector_add(v[0], w[0]), vector_add(v[1], w[1])) - -func scalar_mul*(v: (float, float), s: float): (float, float) = - (scalar_mul(v[0], s), scalar_mul(v[1], s)) - -func dimension*(x: typedesc[(float, float)]): Natural = 2 - -# Check concept requirements. -assert float is VectorSpace -assert (float, float) is VectorSpace - -# Commutivity axiom for vector spaces over the same field. -func axiom_commutivity*[F](u, v: VectorSpace[F]): bool = - vector_add(u, v) == vector_add(v, u) - -# This is okay. -assert axiom_commutivity(2.2, 3.3) - -# This is not. -assert axiom_commutivity((2.2, 3.3), (4.4, 5.5)) diff --git a/tests/concepts/t19730.nim b/tests/concepts/t19730.nim deleted file mode 100644 index 575d45dda..000000000 --- a/tests/concepts/t19730.nim +++ /dev/null @@ -1,20 +0,0 @@ -discard """ - output: '''1.01.01.01.0 -1.01.01.01.0 -''' -""" - -type - Color = concept c - c.r is SomeFloat - c.g is SomeFloat - c.b is SomeFloat - c.a is SomeFloat - -proc useColor(color: Color) = - echo(color.r, color.g, color.b, color.a) - -let color = (r: 1.0, g: 1.0, b: 1.0, a: 1.0) -useColor(color) - -useColor((r: 1.0, g: 1.0, b: 1.0, a: 1.0)) diff --git a/tests/concepts/t20237.nim b/tests/concepts/t20237.nim deleted file mode 100644 index db9002421..000000000 --- a/tests/concepts/t20237.nim +++ /dev/null @@ -1,3 +0,0 @@ -type Foo = concept - ## doc comment - proc foo(x: Self) diff --git a/tests/concepts/t3330.nim b/tests/concepts/t3330.nim index 901f8d2f4..067e81133 100644 --- a/tests/concepts/t3330.nim +++ b/tests/concepts/t3330.nim @@ -1,22 +1,14 @@ discard """ -matrix: "--mm:refc" errormsg: "type mismatch: got " +disabled: "32bit" nimout: ''' -t3330.nim(70, 4) Error: type mismatch: got +t3330.nim(78, 4) Error: type mismatch: got but expected one of: proc test(foo: Foo[int]) first type mismatch at position: 1 required type for foo: Foo[int] but expression 'bar' is of type: Bar[system.int] -t3330.nim(55, 8) Hint: Non-matching candidates for add(k, string, T) -proc add(x: var string; y: char) - first type mismatch at position: 1 - required type for x: var string - but expression 'k' is of type: Alias -proc add(x: var string; y: cstring) - first type mismatch at position: 1 - required type for x: var string - but expression 'k' is of type: Alias +t3330.nim(63, 8) Hint: Non-matching candidates for add(k, string, T) proc add(x: var string; y: string) first type mismatch at position: 1 required type for x: var string @@ -25,23 +17,39 @@ proc add[T](x: var seq[T]; y: openArray[T]) first type mismatch at position: 1 required type for x: var seq[T] but expression 'k' is of type: Alias -proc add[T](x: var seq[T]; y: sink T) +proc add(result: var string; x: float) + first type mismatch at position: 1 + required type for result: var string + but expression 'k' is of type: Alias +proc add[T](x: var seq[T]; y: T) first type mismatch at position: 1 required type for x: var seq[T] but expression 'k' is of type: Alias +proc add(x: var string; y: cstring) + first type mismatch at position: 1 + required type for x: var string + but expression 'k' is of type: Alias +proc add(x: var string; y: char) + first type mismatch at position: 1 + required type for x: var string + but expression 'k' is of type: Alias +proc add(result: var string; x: int64) + first type mismatch at position: 1 + required type for result: var string + but expression 'k' is of type: Alias -t3330.nim(55, 8) template/generic instantiation of `add` from here -t3330.nim(62, 6) Foo: 'bar.value' cannot be assigned to -t3330.nim(55, 8) template/generic instantiation of `add` from here -t3330.nim(63, 6) Foo: 'bar.x' cannot be assigned to +t3330.nim(63, 8) template/generic instantiation of `add` from here +t3330.nim(70, 6) Foo: 'bar.value' cannot be assigned to +t3330.nim(63, 8) template/generic instantiation of `add` from here +t3330.nim(71, 6) Foo: 'bar.x' cannot be assigned to expression: test(bar)''' """ - - - - +# Note: currently disabled on 32bit because the candidates are presented in +# different order on travis with `NIM_COMPILE_TO_CPP=false CPU=i386`; +# a possible fix would be to sort the candidates by proc signature or +# declaration location @@ -68,3 +76,4 @@ proc test(foo: Foo[int]) = var bar = Bar[int]() bar.test() + diff --git a/tests/concepts/t8012.nim b/tests/concepts/t8012.nim deleted file mode 100644 index ec2aa6e5c..000000000 --- a/tests/concepts/t8012.nim +++ /dev/null @@ -1,15 +0,0 @@ -type - MyTypeCon = concept c - c.counter is int - MyType = object - counter: int - -proc foo(conc: var MyTypeCon) = - conc.counter.inc - if conc.counter < 5: - foo(conc) - -var x: MyType - -x.foo -discard x.repr diff --git a/tests/concepts/t8558.nim b/tests/concepts/t8558.nim deleted file mode 100644 index acb2de30e..000000000 --- a/tests/concepts/t8558.nim +++ /dev/null @@ -1,26 +0,0 @@ -discard """ - output: '''10 -9 -8 -7 -6 -5 -4 -3 -2 -1 -go! -''' -""" - -type Integral = concept x - x == 0 is bool - x - 1 is type(x) - -proc countToZero(n: Integral) = - if n == 0: echo "go!" - else: - echo n - countToZero(n-1) - -countToZero(10) \ No newline at end of file diff --git a/tests/concepts/tconcepts.nim b/tests/concepts/tconcepts.nim index acdff6f24..d0bc76c20 100644 --- a/tests/concepts/tconcepts.nim +++ b/tests/concepts/tconcepts.nim @@ -98,7 +98,7 @@ block tconceptinclosure: block overload_precedence: type ParameterizedType[T] = object - type CustomTypeClass = concept c + type CustomTypeClass = concept true # 3 competing procs diff --git a/tests/concepts/tconcepts_issues.nim b/tests/concepts/tconcepts_issues.nim index 3efb9964a..65f6d4660 100644 --- a/tests/concepts/tconcepts_issues.nim +++ b/tests/concepts/tconcepts_issues.nim @@ -27,8 +27,6 @@ false true -1 Meow -10 0.0 -1 2.0 ''' joinable: false """ @@ -326,15 +324,15 @@ block t6691: block t6782: type Reader = concept c - c.read(openArray[byte], int, int) is int + c.read(openarray[byte], int, int) is int Rdr = concept c - c.rd(openArray[byte], int, int) is int + c.rd(openarray[byte], int, int) is int type TestFile = object - proc read(r: TestFile, dest: openArray[byte], offset: int, limit: int): int = + proc read(r: TestFile, dest: openarray[byte], offset: int, limit: int): int = result = 0 - proc rd(r: TestFile, dest: openArray[byte], offset: int, limit: int): int = + proc rd(r: TestFile, dest: openarray[byte], offset: int, limit: int): int = result = 0 doAssert TestFile is Reader @@ -399,7 +397,7 @@ block misc_issues: echo p2.x is float and p2.y is float # true # https://github.com/nim-lang/Nim/issues/2018 - type ProtocolFollower = concept c + type ProtocolFollower = concept true # not a particularly involved protocol type ImplementorA = object @@ -469,59 +467,3 @@ block misc_issues: # anyway and will be an error soon. var a: Cat = Cat() a.sayHello() - - -# bug #16897 - -type - Fp[N: static int, T] = object - big: array[N, T] - -type - QuadraticExt* = concept x - ## Quadratic Extension concept (like complex) - type BaseField = auto - x.c0 is BaseField - x.c1 is BaseField -var address = pointer(nil) -proc prod(r: var QuadraticExt, b: QuadraticExt) = - if address == nil: - address = addr b - prod(r, b) - else: - assert address == addr b - -type - Fp2[N: static int, T] {.byref.} = object - c0, c1: Fp[N, T] - -# This should be passed by reference, -# but concepts do not respect the 24 bytes rule -# or `byref` pragma. -var r, b: Fp2[6, uint64] - -prod(r, b) - - -block: # bug #21263 - type - DateDayFraction = concept # no T, an atom - proc date(a: Self): int - proc fraction(b: Self): float - Date = distinct int - DateDayFractionImpl = object - date : int - fraction : float - - proc date(a: Date): int = a.int - proc fraction(a:Date): float = 0.0 - - proc date(a: DateDayFractionImpl): int = a.date - proc fraction(b: DateDayFractionImpl): float = b.fraction - - - proc print(a: DateDayFraction) = - echo a.date, " ", a.fraction - - print(10.Date) # ok - print(DateDayFractionImpl(date: 1, fraction: 2)) # error diff --git a/tests/concepts/tconcepts_overload_precedence.nim b/tests/concepts/tconcepts_overload_precedence.nim index c580d2688..9eed6256a 100644 --- a/tests/concepts/tconcepts_overload_precedence.nim +++ b/tests/concepts/tconcepts_overload_precedence.nim @@ -9,7 +9,7 @@ x as CustomTypeClass''' type ParameterizedType[T] = object -type CustomTypeClass = concept c +type CustomTypeClass = concept true # 3 competing procs diff --git a/tests/concepts/texplain.nim b/tests/concepts/texplain.nim index 8cf04ae82..2b19c8b4d 100644 --- a/tests/concepts/texplain.nim +++ b/tests/concepts/texplain.nim @@ -1,92 +1,106 @@ discard """ cmd: "nim c --verbosity:0 --colors:off $file" nimout: ''' -texplain.nim(162, 10) Hint: Non-matching candidates for e(y) +texplain.nim(158, 10) Hint: Non-matching candidates for e(y) proc e(i: int): int first type mismatch at position: 1 required type for i: int but expression 'y' is of type: MatchingType -texplain.nim(165, 7) Hint: Non-matching candidates for e(10) +texplain.nim(161, 7) Hint: Non-matching candidates for e(10) proc e(o: ExplainedConcept): int first type mismatch at position: 1 required type for o: ExplainedConcept but expression '10' is of type: int literal(10) -texplain.nim(128, 6) ExplainedConcept: undeclared field: 'foo' -texplain.nim(128, 5) ExplainedConcept: concept predicate failed -texplain.nim(129, 6) ExplainedConcept: undeclared field: 'bar' -texplain.nim(128, 5) ExplainedConcept: concept predicate failed +texplain.nim(124, 6) ExplainedConcept: undeclared field: 'foo' +texplain.nim(124, 6) ExplainedConcept: undeclared field: '.' +texplain.nim(124, 6) ExplainedConcept: expression '.' cannot be called +texplain.nim(124, 5) ExplainedConcept: concept predicate failed +texplain.nim(125, 6) ExplainedConcept: undeclared field: 'bar' +texplain.nim(125, 6) ExplainedConcept: undeclared field: '.' +texplain.nim(125, 6) ExplainedConcept: expression '.' cannot be called +texplain.nim(124, 5) ExplainedConcept: concept predicate failed -texplain.nim(168, 10) Hint: Non-matching candidates for e(10) +texplain.nim(164, 10) Hint: Non-matching candidates for e(10) proc e(o: ExplainedConcept): int first type mismatch at position: 1 required type for o: ExplainedConcept but expression '10' is of type: int literal(10) -texplain.nim(128, 6) ExplainedConcept: undeclared field: 'foo' -texplain.nim(128, 5) ExplainedConcept: concept predicate failed -texplain.nim(129, 6) ExplainedConcept: undeclared field: 'bar' -texplain.nim(128, 5) ExplainedConcept: concept predicate failed +texplain.nim(124, 6) ExplainedConcept: undeclared field: 'foo' +texplain.nim(124, 6) ExplainedConcept: undeclared field: '.' +texplain.nim(124, 6) ExplainedConcept: expression '.' cannot be called +texplain.nim(124, 5) ExplainedConcept: concept predicate failed +texplain.nim(125, 6) ExplainedConcept: undeclared field: 'bar' +texplain.nim(125, 6) ExplainedConcept: undeclared field: '.' +texplain.nim(125, 6) ExplainedConcept: expression '.' cannot be called +texplain.nim(124, 5) ExplainedConcept: concept predicate failed -texplain.nim(172, 20) Error: type mismatch: got +texplain.nim(168, 20) Error: type mismatch: got but expected one of: +proc e(o: ExplainedConcept): int + first type mismatch at position: 1 + required type for o: ExplainedConcept + but expression 'n' is of type: NonMatchingType +texplain.nim(168, 9) template/generic instantiation of `assert` from here +texplain.nim(124, 5) ExplainedConcept: concept predicate failed proc e(i: int): int first type mismatch at position: 1 required type for i: int but expression 'n' is of type: NonMatchingType -proc e(o: ExplainedConcept): int - first type mismatch at position: 1 - required type for o: ExplainedConcept - but expression 'n' is of type: NonMatchingType -texplain.nim(172, 9) template/generic instantiation of `assert` from here -texplain.nim(128, 5) ExplainedConcept: concept predicate failed expression: e(n) -texplain.nim(173, 20) Error: type mismatch: got +texplain.nim(169, 20) Error: type mismatch: got but expected one of: -proc r(i: string): int - first type mismatch at position: 1 - required type for i: string - but expression 'n' is of type: NonMatchingType proc r(o: RegularConcept): int first type mismatch at position: 1 required type for o: RegularConcept but expression 'n' is of type: NonMatchingType -texplain.nim(173, 9) template/generic instantiation of `assert` from here -texplain.nim(132, 5) RegularConcept: concept predicate failed +texplain.nim(169, 9) template/generic instantiation of `assert` from here +texplain.nim(128, 5) RegularConcept: concept predicate failed proc r[T](a: SomeNumber; b: T; c: auto) first type mismatch at position: 1 required type for a: SomeNumber but expression 'n' is of type: NonMatchingType - -expression: r(n) -texplain.nim(174, 20) Hint: Non-matching candidates for r(y) proc r(i: string): int first type mismatch at position: 1 required type for i: string - but expression 'y' is of type: MatchingType + but expression 'n' is of type: NonMatchingType + +expression: r(n) +texplain.nim(170, 20) Hint: Non-matching candidates for r(y) proc r[T](a: SomeNumber; b: T; c: auto) first type mismatch at position: 1 required type for a: SomeNumber but expression 'y' is of type: MatchingType +proc r(i: string): int + first type mismatch at position: 1 + required type for i: string + but expression 'y' is of type: MatchingType -texplain.nim(182, 2) Error: type mismatch: got +texplain.nim(178, 2) Error: type mismatch: got but expected one of: proc f(o: NestedConcept) first type mismatch at position: 1 required type for o: NestedConcept but expression 'y' is of type: MatchingType -texplain.nim(132, 6) RegularConcept: undeclared field: 'foo' -texplain.nim(132, 5) RegularConcept: concept predicate failed -texplain.nim(133, 6) RegularConcept: undeclared field: 'bar' -texplain.nim(132, 5) RegularConcept: concept predicate failed -texplain.nim(136, 5) NestedConcept: concept predicate failed +texplain.nim(128, 6) RegularConcept: undeclared field: 'foo' +texplain.nim(128, 6) RegularConcept: undeclared field: '.' +texplain.nim(128, 6) RegularConcept: expression '.' cannot be called +texplain.nim(128, 5) RegularConcept: concept predicate failed +texplain.nim(129, 6) RegularConcept: undeclared field: 'bar' +texplain.nim(129, 6) RegularConcept: undeclared field: '.' +texplain.nim(129, 6) RegularConcept: expression '.' cannot be called +texplain.nim(128, 5) RegularConcept: concept predicate failed +texplain.nim(132, 5) NestedConcept: concept predicate failed expression: f(y)''' errormsg: "type mismatch: got " + line: 178 + + disabled: 32bit """ - - +# disabled on 32 bit, because the order of suggested alternatives ``r`` differs # proc r[T](a: SomeNumber; b: T; c: auto) # proc r(i: string): int # proc r(o: RegularConcept): int @@ -103,25 +117,7 @@ expression: f(y)''' - - - - - - - - - - - - - - - - - - -# line 124 HERE +# line 120 HERE type ExplainedConcept {.explain.} = concept o diff --git a/tests/concepts/tmapconcept.nim b/tests/concepts/tmapconcept.nim index cc99737df..6b959eff2 100644 --- a/tests/concepts/tmapconcept.nim +++ b/tests/concepts/tmapconcept.nim @@ -78,7 +78,7 @@ proc getFirstValue[K,V](m : Map[K,V]): V = for i in m.valuesSeq: return i - raise newException(RangeDefect, "no values") + raise newException(RangeError, "no values") proc useConceptProcInGeneric[K, V](t: Table[K, V]): V = return t.getFirstValue diff --git a/tests/concepts/treversable.nim b/tests/concepts/treversable.nim index d30ba0a3c..6ebc077d9 100644 --- a/tests/concepts/treversable.nim +++ b/tests/concepts/treversable.nim @@ -3,7 +3,7 @@ discard """ output: ''' z e -''' + ''' """ type diff --git a/tests/concepts/tspec.nim b/tests/concepts/tspec.nim deleted file mode 100644 index 52f13a40a..000000000 --- a/tests/concepts/tspec.nim +++ /dev/null @@ -1,105 +0,0 @@ -discard """ - output: '''4 -0 -4 -4 -1 -2 -3 -yes int -string int''' - joinable: false -""" - -import hashes - -type - Comparable = concept # no T, an atom - proc cmp(a, b: Self): int - - ToStringable = concept - proc `$`(a: Self): string - - Hashable = concept ## the most basic of identity assumptions - proc hash(x: Self): int - proc `==`(x, y: Self): bool - - Swapable = concept - proc swap(x, y: var Self) - - -proc h(x: Hashable) = - echo x - -h(4) - -when true: - proc compare(a: Comparable) = - echo cmp(a, a) - - compare(4) - -proc dollar(x: ToStringable) = - echo x - -when true: - dollar 4 - dollar "4" - -#type D = distinct int - -#dollar D(4) - -when true: - type - Iterable[Ix] = concept - iterator items(c: Self): Ix - - proc g[Tu](it: Iterable[Tu]) = - for x in it: - echo x - - g(@[1, 2, 3]) - -proc hs(x: Swapable) = - var y = x - swap y, y - -hs(4) - -type - Indexable[T] = concept # has a T, a collection - proc `[]`(a: Self; index: int): T # we need to describe how to infer 'T' - # and then we can use the 'T' and it must match: - proc `[]=`(a: var Self; index: int; value: T) - proc len(a: Self): int - -proc indexOf[T](a: Indexable[T]; value: T) = - echo "yes ", T - -block: - var x = @[1, 2, 3] - indexOf(x, 4) - -import tables, typetraits - -type - Dict[K, V] = concept - proc `[]`(s: Self; k: K): V - proc `[]=`(s: var Self; k: K; v: V) - -proc d[K2, V2](x: Dict[K2, V2]) = - echo K2, " ", V2 - -var x = initTable[string, int]() -d(x) - - -type Monoid = concept - proc `+`(x, y: Self): Self - proc z(t: typedesc[Self]): Self - -proc z(x: typedesc[int]): int = 0 - -doAssert int is Monoid - diff --git a/tests/concepts/tusertypeclasses.nim b/tests/concepts/tusertypeclasses.nim index 83e2b176e..c7104f2a6 100644 --- a/tests/concepts/tusertypeclasses.nim +++ b/tests/concepts/tusertypeclasses.nim @@ -1,5 +1,4 @@ discard """ - matrix: "--mm:refc" output: '''Sortable Sortable Container @@ -10,8 +9,6 @@ int ''' """ -# todo wait for https://github.com/nim-lang/Nim/pull/20380 - import typetraits template reject(expr) = assert(not compiles(x)) diff --git a/tests/concepts/tusertypeclasses2.nim b/tests/concepts/tusertypeclasses2.nim index c9978f6ef..ae05540cd 100644 --- a/tests/concepts/tusertypeclasses2.nim +++ b/tests/concepts/tusertypeclasses2.nim @@ -1,44 +1,24 @@ -block: - type - hasFieldX = concept z - z.x is int +type + hasFieldX = concept z + z.x is int - obj_x = object - x: int + obj_x = object + x: int - ref_obj_x = ref object - x: int + ref_obj_x = ref object + x: int - ref_to_obj_x = ref obj_x + ref_to_obj_x = ref obj_x - p_o_x = ptr obj_x - v_o_x = var obj_x + p_o_x = ptr obj_x + v_o_x = var obj_x - template check(x) = - static: assert(x) +template check(x) = + static: assert(x) - check obj_x is hasFieldX - check ref_obj_x is hasFieldX - check ref_to_obj_x is hasFieldX - check p_o_x is hasFieldX - check v_o_x is hasFieldX +check obj_x is hasFieldX +check ref_obj_x is hasFieldX +check ref_to_obj_x is hasFieldX +check p_o_x is hasFieldX +check v_o_x is hasFieldX -block: - type - Foo = concept x - x.isFoo - Bar = distinct float - template isFoo(x: Bar): untyped = true - proc foo(x: var Foo) = - float(x) = 1.0 - proc foo2(x: var Bar) = - float(x) = 1.0 - proc foo3(x: var (Bar|SomeNumber)) = - float(x) = 1.0 - proc foo4(x: var any) = - float(x) = 1.0 - var x: Bar - foo(x) - foo2(x) - foo3(x) - foo4(x) diff --git a/tests/concepts/twrapconcept.nim b/tests/concepts/twrapconcept.nim index c3dea2ff9..377b63afe 100644 --- a/tests/concepts/twrapconcept.nim +++ b/tests/concepts/twrapconcept.nim @@ -1,6 +1,7 @@ discard """ errormsg: "type mismatch: got " - nimout: "twrapconcept.nim(10, 5) Foo: concept predicate failed" + line: 21 + nimout: "twrapconcept.nim(11, 5) Foo: concept predicate failed" """ # https://github.com/nim-lang/Nim/issues/5127 diff --git a/tests/config.nims b/tests/config.nims index 4bcd67143..cd4ee4b08 100644 --- a/tests/config.nims +++ b/tests/config.nims @@ -1,47 +1,7 @@ -switch("path", "$lib/../testament/lib") - # so we can `import stdtest/foo` inside tests - # Using $lib/../ instead of $nim/ so you can use a different nim to run tests - # during local testing, e.g. nim --lib:lib. +switch("path", "$nim/testament/lib") # so we can `import stdtest/foo` in this dir ## prevent common user config settings to interfere with testament expectations ## Indifidual tests can override this if needed to test for these options. switch("colors", "off") - +switch("listFullPaths", "off") switch("excessiveStackTrace", "off") - -when (NimMajor, NimMinor, NimPatch) >= (1,5,1): - # to make it easier to test against older nim versions, (best effort only) - switch("filenames", "legacyRelProj") - switch("spellSuggest", "0") - -# for std/unittest -switch("define", "nimUnittestOutputLevel:PRINT_FAILURES") -switch("define", "nimUnittestColor:off") - -switch("define", "nimLegacyTypeMismatch") - -hint("Processing", off) - # dots can cause annoyances; instead, a single test can test `hintProcessing` - -# uncomment to enable all flaky tests disabled by this flag -# (works through process calls, e.g. tests that invoke nim). -# switch("define", "nimTestsEnableFlaky") - -# switch("hint", "ConvFromXtoItselfNotNeeded") -# switch("warningAsError", "InheritFromException") # would require fixing a few tests - -# experimental APIs are enabled in testament, refs https://github.com/timotheecour/Nim/issues/575 -# sync with `kochdocs.docDefines` or refactor. -switch("define", "nimExperimentalLinenoiseExtra") - -# preview APIs are expected to be the new default in upcoming versions -switch("define", "nimPreviewFloatRoundtrip") -switch("define", "nimPreviewDotLikeOps") -switch("define", "nimPreviewJsonutilsHoleyEnum") -switch("define", "nimPreviewHashRef") -switch("define", "nimPreviewRangeDefault") -when defined(windows): - switch("tlsEmulation", "off") - -switch("warningAserror", "UnnamedBreak") -switch("legacy", "verboseTypeMismatch") diff --git a/tests/constr/a.nim b/tests/constr/a.nim deleted file mode 100644 index 03788fc57..000000000 --- a/tests/constr/a.nim +++ /dev/null @@ -1,2 +0,0 @@ -type A* = object - a: uint8 \ No newline at end of file diff --git a/tests/constr/b.nim b/tests/constr/b.nim deleted file mode 100644 index 437dd0550..000000000 --- a/tests/constr/b.nim +++ /dev/null @@ -1,2 +0,0 @@ -type B* = object -proc A*(a, b: float): B = discard \ No newline at end of file diff --git a/tests/constr/t18990.nim b/tests/constr/t18990.nim deleted file mode 100644 index 2f60f3c2c..000000000 --- a/tests/constr/t18990.nim +++ /dev/null @@ -1,3 +0,0 @@ -import a, b -discard A(1f, 1f) # works -proc x(b = A(1f, 1f)) = discard # doesn't work \ No newline at end of file diff --git a/tests/constr/tconexpr.nim b/tests/constr/tconexpr.nim deleted file mode 100644 index cca6dd84f..000000000 --- a/tests/constr/tconexpr.nim +++ /dev/null @@ -1,43 +0,0 @@ -discard """ - nimout: ''' -Fibonacci sequence: 0, 1, 1, 2, 3 -Sequence continues: 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610 -''' -""" - - -import strformat - -var fib_n {.compileTime.}: int -var fib_prev {.compileTime.}: int -var fib_prev_prev {.compileTime.}: int - -proc next_fib(): int {.compileTime.} = - let fib = if fib_n < 2: - fib_n - else: - fib_prev_prev + fib_prev - inc(fib_n) - fib_prev_prev = fib_prev - fib_prev = fib - fib - -const f0 = next_fib() -const f1 = next_fib() -const f2 = next_fib() -const f3 = next_fib() -const f4 = next_fib() - -static: - echo fmt"Fibonacci sequence: {f0}, {f1}, {f2}, {f3}, {f4}" - -const fib_continues = block: - var result = fmt"Sequence continues: " - for i in 0..10: - if i > 0: - add(result, ", ") - add(result, $next_fib()) - result - -static: - echo fib_continues \ No newline at end of file diff --git a/tests/constr/tnocompiletimefunc.nim b/tests/constr/tnocompiletimefunc.nim deleted file mode 100644 index a95648c0f..000000000 --- a/tests/constr/tnocompiletimefunc.nim +++ /dev/null @@ -1,14 +0,0 @@ -discard """ - errormsg: "request to generate code for .compileTime proc: foo" -""" - -# ensure compileTime funcs can't be called from runtime - -func foo(a: int): int {.compileTime.} = - a * a - -proc doAThing(): int = - for i in 0..2: - result += foo(i) - -echo doAThing() diff --git a/tests/constr/tnocompiletimefunclambda.nim b/tests/constr/tnocompiletimefunclambda.nim deleted file mode 100644 index d134eea40..000000000 --- a/tests/constr/tnocompiletimefunclambda.nim +++ /dev/null @@ -1,6 +0,0 @@ -discard """ - errormsg: "request to generate code for .compileTime proc: :anonymous" -""" - -let a = func(a: varargs[int]) {.compileTime, closure.} = - discard a[0] \ No newline at end of file diff --git a/tests/constructors/tinvalid_construction.nim b/tests/constructors/tinvalid_construction.nim index 4b372d68a..b3e56eec6 100644 --- a/tests/constructors/tinvalid_construction.nim +++ b/tests/constructors/tinvalid_construction.nim @@ -3,16 +3,11 @@ template accept(x) = template reject(x) = static: assert(not compiles(x)) - {.experimental: "notnil".} - type TRefObj = ref object x: int - IllegalToConstruct = object - x: cstring not nil - THasNotNils = object of RootObj a: TRefObj not nil b: TRefObj not nil @@ -20,8 +15,6 @@ type THasNotNilsRef = ref THasNotNils - TRefObjNotNil = TRefObj not nil - TChoice = enum A, B, C, D, E, F TBaseHasNotNils = object of THasNotNils @@ -33,22 +26,6 @@ type else: discard - PartialRequiresInit = object - a {.requiresInit.}: int - b: string - - PartialRequiresInitRef = ref PartialRequiresInit - - FullRequiresInit {.requiresInit.} = object - a: int - b: int - - FullRequiresInitRef = ref FullRequiresInit - - FullRequiresInitWithParent {.requiresInit.} = object of THasNotNils - e: int - d: int - TObj = object case choice: TChoice of A: @@ -78,23 +55,11 @@ type var x = D var nilRef: TRefObj -let notNilRef = TRefObjNotNil(x: 20) +var notNilRef = TRefObj(x: 20) proc makeHasNotNils: ref THasNotNils = - (ref THasNotNils)(a: TRefObj(x: 10), - b: TRefObj(x: 20)) - -proc userDefinedDefault(T: typedesc): T = - # We'll use that to make sure the user cannot cheat - # with constructing requiresInit types - discard - -proc genericDefault(T: typedesc): T = - result = default(T) - -reject IllegalToConstruct() -reject: - var x: IllegalToConstruct + result.a = TRefObj(x: 10) + result.b = TRefObj(x: 20) accept TObj() accept TObj(choice: A) @@ -109,22 +74,14 @@ reject TObj(a: 10, f: "") # conflicting fields accept TObj(choice: E, e1: TRefObj(x: 10), e2: 10) accept THasNotNils(a: notNilRef, b: notNilRef, c: nilRef) -reject THasNotNils(a: notNilRef, b: nilRef, c: nilRef) # `b` shouldn't be nil +# XXX: the "not nil" logic in the compiler is not strong enough to catch this one yet: +# reject THasNotNils(a: notNilRef, b: nilRef, c: nilRef) reject THasNotNils(b: notNilRef, c: notNilRef) # there is a missing not nil field reject THasNotNils() # again, missing fields accept THasNotNils(a: notNilRef, b: notNilRef) # it's OK to omit a non-mandatory field -# produces only warning: reject default(THasNotNils) -# produces only warning: reject userDefinedDefault(THasNotNils) - -# produces only warning: reject default(TRefObjNotNil) -# produces only warning: reject userDefinedDefault(TRefObjNotNil) -# produces only warning: reject genericDefault(TRefObjNotNil) # missing not nils in base reject TBaseHasNotNils() -# produces only warning: reject default(TBaseHasNotNils) -# produces only warning: reject userDefinedDefault(TBaseHasNotNils) -# produces only warning: reject genericDefault(TBaseHasNotNils) # once you take care of them, it's ok accept TBaseHasNotNils(a: notNilRef, b: notNilRef, choice: D) @@ -149,118 +106,8 @@ accept TBaseHasNotNils(a: notNilRef, b: notNilRef, choice: B, indirectNotNils: m reject TBaseHasNotNils(a: notNilRef, b: notNilRef, choice: B, indirectNotNils: THasNotNilsRef()) accept TBaseHasNotNils(a: notNilRef, b: notNilRef, choice: B, indirectNotNils: THasNotNilsRef(a: notNilRef, b: notNilRef)) -# Accept only instances where the `a` field is present -accept PartialRequiresInit(a: 10, b: "x") -accept PartialRequiresInit(a: 20) -reject PartialRequiresInit(b: "x") -reject PartialRequiresInit() -accept PartialRequiresInitRef(a: 10, b: "x") -accept PartialRequiresInitRef(a: 20) -reject PartialRequiresInitRef(b: "x") -reject PartialRequiresInitRef() -accept((ref PartialRequiresInit)(a: 10, b: "x")) -accept((ref PartialRequiresInit)(a: 20)) -reject((ref PartialRequiresInit)(b: "x")) -reject((ref PartialRequiresInit)()) - -# produces only warning: reject default(PartialRequiresInit) -# produces only warning: reject userDefinedDefault(PartialRequiresInit) -reject: - var obj: PartialRequiresInit - -accept FullRequiresInit(a: 10, b: 20) -reject FullRequiresInit(a: 10) -reject FullRequiresInit(b: 20) -reject FullRequiresInit() -accept FullRequiresInitRef(a: 10, b: 20) -reject FullRequiresInitRef(a: 10) -reject FullRequiresInitRef(b: 20) -reject FullRequiresInitRef() -accept((ref FullRequiresInit)(a: 10, b: 20)) -reject((ref FullRequiresInit)(a: 10)) -reject((ref FullRequiresInit)(b: 20)) -reject((ref FullRequiresInit)()) - -# produces only warning: reject default(FullRequiresInit) -# produces only warning: reject userDefinedDefault(FullRequiresInit) -reject: - var obj: FullRequiresInit - -accept FullRequiresInitWithParent(a: notNilRef, b: notNilRef, c: notNilRef, e: 10, d: 20) -accept FullRequiresInitWithParent(a: notNilRef, b: notNilRef, c: nil, e: 10, d: 20) -reject FullRequiresInitWithParent(a: notNilRef, b: nil, c: nil, e: 10, d: 20) # b should not be nil -reject FullRequiresInitWithParent(a: notNilRef, b: notNilRef, e: 10, d: 20) # c should not be missing -reject FullRequiresInitWithParent(a: notNilRef, b: notNilRef, c: nil, e: 10) # d should not be missing -reject FullRequiresInitWithParent() -# produces only warning: reject default(FullRequiresInitWithParent) -# produces only warning: reject userDefinedDefault(FullRequiresInitWithParent) -reject: - var obj: FullRequiresInitWithParent - # this will be accepted, because the false outer branch will be taken and the inner A branch accept TNestedChoices() -accept default(TNestedChoices) -accept: - var obj: TNestedChoices - -#[# produces only warning: -reject: - # This proc is illegal, because it tries to produce - # a default object of a type that requires initialization: - proc defaultHasNotNils: THasNotNils = - discard -#]# - -#[# produces only warning: -reject: - # You cannot cheat by using the result variable to specify - # only some of the fields - proc invalidPartialTHasNotNils: THasNotNils = - result.c = nilRef -#]# - -#[# produces only warning: -reject: - # The same applies for requiresInit types - proc invalidPartialRequiersInit: PartialRequiresInit = - result.b = "x" -#]# - -#[# produces only warning: -# All code paths must return a value when the result requires initialization: -reject: - proc ifWithoutAnElse: THasNotNils = - if stdin.readLine == "": - return THasNotNils(a: notNilRef, b: notNilRef, c: nilRef) -#]# - -accept: - # All code paths must return a value when the result requires initialization: - proc wellFormedIf: THasNotNils = - if stdin.readLine == "": - return THasNotNils(a: notNilRef, b: notNilRef, c: nilRef) - else: - return THasNotNIls(a: notNilRef, b: notNilRef) - -#[# produces only warning: -reject: - proc caseWithoutAllCasesCovered: FullRequiresInit = - # Please note that these is no else branch here: - case stdin.readLine - of "x": - return FullRequiresInit(a: 10, b: 20) - of "y": - return FullRequiresInit(a: 30, b: 40) -#]# - -accept: - proc wellFormedCase: FullRequiresInit = - case stdin.readLine - of "x": - result = FullRequiresInit(a: 10, b: 20) - else: - # Mixing result and return is fine: - return FullRequiresInit(a: 30, b: 40) # but if we supply a run-time value for the inner branch, the compiler won't be able to prove # that the notnil field was initialized @@ -273,167 +120,3 @@ reject TNestedChoices(outerChoice: false, innerChoice: C) accept TNestedChoices(outerChoice: false, innerChoice: C, notnil: notNilRef) reject TNestedChoices(outerChoice: false, innerChoice: C, notnil: nil) -# Tests involving generics and sequences: -# -block: - # This test aims to show that it's possible to instantiate and - # use a sequence with a requiresInit type: - - var legalSeq: seq[IllegalToConstruct] - legalSeq.add IllegalToConstruct(x: "one") - var two = IllegalToConstruct(x: "two") - legalSeq.add two - var one = legalSeq[0] - var twoAgain = legalSeq.pop - - #[# produces only warning: - # It's not possible to tell the sequence to create elements - # for us though: - reject: - var illegalSeq = newSeq[IllegalToConstruct](10) - #]# - - #[# produces only warning: - reject: - var illegalSeq: seq[IllegalToConstruct] - newSeq(illegalSeq, 10) - #]# - - #[# produces only warning: - reject: - var illegalSeq: seq[IllegalToConstruct] - illegalSeq.setLen 10 - #]# - - # You can still use newSeqOfCap to write efficient code: - var anotherLegalSequence = newSeqOfCap[IllegalToConstruct](10) - for i in 0..9: - anotherLegalSequence.add IllegalToConstruct(x: "x") - -type DefaultConstructible[yesOrNo: static[bool]] = object - when yesOrNo: - x: string - else: - x: cstring not nil - -block: - # Constructability may also depend on the generic parameters of the type: - accept: - var a: DefaultConstructible[true] - var b = DefaultConstructible[true]() - var c = DefaultConstructible[true](x: "test") - var d = DefaultConstructible[false](x: "test") - - reject: - var y: DefaultConstructible[false] - - reject: - var y = DefaultConstructible[false]() - -block: - type - Hash = int - - HashTableSlotType = enum - Free = Hash(0) - Deleted = Hash(1) - HasKey = Hash(2) - - KeyValuePair[A, B] = object - key: A - case hash: HashTableSlotType - of Free, Deleted: - discard - else: - value: B - - # The above KeyValuePair is an interesting type because it - # may become unconstructible depending on the generic parameters: - accept KeyValuePair[int, string](hash: Deleted) - accept KeyValuePair[int, IllegalToConstruct](hash: Deleted) - - accept KeyValuePair[int, string](hash: HasKey) - reject KeyValuePair[int, IllegalToConstruct](hash: HasKey) - - # Since all the above variations don't have a non-constructible - # field in the default branch of the case object, we can construct - # such values: - accept KeyValuePair[int, string]() - accept KeyValuePair[int, IllegalToConstruct]() - accept KeyValuePair[DefaultConstructible[true], string]() - accept KeyValuePair[DefaultConstructible[true], IllegalToConstruct]() - - var a: KeyValuePair[int, string] - var b: KeyValuePair[int, IllegalToConstruct] - var c: KeyValuePair[DefaultConstructible[true], string] - var d: KeyValuePair[DefaultConstructible[true], IllegalToConstruct] - var s1 = newSeq[KeyValuePair[int, IllegalToConstruct]](10) - var s2 = newSeq[KeyValuePair[DefaultConstructible[true], IllegalToConstruct]](10) - - # But let's put the non-constructible values as keys: - reject KeyValuePair[IllegalToConstruct, int](hash: Deleted) - reject KeyValuePair[IllegalToConstruct, int]() - - type IllegalPair = KeyValuePair[DefaultConstructible[false], string] - - reject: - var x: IllegalPair - - #[# produces only warning: - reject: - var s = newSeq[IllegalPair](10) - #]# - -# Specific issues: -# -block: - # https://github.com/nim-lang/Nim/issues/11428 - type - Enum = enum A, B, C - Thing = object - case kind: Enum - of A: discard - of B: s: string - of C: r: range[1..1] # DateTime - - # Fine to not initialize 'r' because this is implicitly initialized and known to be branch 'A'. - var x = Thing() - discard x - -block: - # https://github.com/nim-lang/Nim/issues/4907 - type - Foo = ref object - Bar = object - - Thing[A, B] = ref object - a: A not nil - b: ref B - c: ref B not nil - - proc allocNotNil(T: typedesc): T not nil = - new result - - proc mutateThing(t: var Thing[Foo, Bar]) = - let fooNotNil = allocNotNil(Foo) - var foo: Foo - - let barNotNil = allocNotNil(ref Bar) - var bar: ref Bar - - t.a = fooNotNil - t.b = bar - t.b = barNotNil - t.c = barNotNil - - reject: - t.a = foo - - reject: - t.c = bar - - var thing = Thing[Foo, Bar](a: allocNotNil(Foo), - b: allocNotNil(ref Bar), - c: allocNotNil(ref Bar)) - mutateThing thing - diff --git a/tests/controlflow/tcontrolflow.nim b/tests/controlflow/tcontrolflow.nim index dd21a2bb6..258f3f50d 100644 --- a/tests/controlflow/tcontrolflow.nim +++ b/tests/controlflow/tcontrolflow.nim @@ -19,7 +19,7 @@ block tbreak: run = false block myblock: if true: - break myblock + break echo "leaving myblock" x = true doAssert(x) @@ -95,22 +95,3 @@ block tnestif: else: writeLine(stdout, "looks like Python") #OUT i == 2 - -# bug https://github.com/nim-lang/RFCs/issues/451 -for i in 1..2: # works - break - -block: # works - for i in 1..2: - break - -block: # works - block: - discard 12 + 3 - for i in 1..2: - break - -block named: # works - if true: - break named - doAssert false, "not reached" diff --git a/tests/controlflow/tstatret.nim b/tests/controlflow/tstatret.nim index a3558e6f4..e0f816c7d 100644 --- a/tests/controlflow/tstatret.nim +++ b/tests/controlflow/tstatret.nim @@ -1,7 +1,7 @@ discard """ - nimout: ''' -tstatret.nim(9, 7) Warning: unreachable code after 'return' statement or '{.noReturn.}' proc [UnreachableCode] -''' + errormsg: "unreachable statement after 'return' statement or '{.noReturn.}' proc" + file: "tstatret.nim" + line: 9 """ # no statement after return proc main() = diff --git a/tests/controlflow/tunamedbreak.nim b/tests/controlflow/tunamedbreak.nim deleted file mode 100644 index 46113cabc..000000000 --- a/tests/controlflow/tunamedbreak.nim +++ /dev/null @@ -1,15 +0,0 @@ - -discard """ - cmd: "nim check $file" - action: "reject" - nimout: ''' -tunamedbreak.nim(12, 5) Error: Using an unnamed break in a block is deprecated; Use a named block with a named break instead [UnnamedBreak] -tunamedbreak.nim(15, 3) Error: Using an unnamed break in a block is deprecated; Use a named block with a named break instead [UnnamedBreak] - ''' -""" -for i in 1..2: # errors - block: - break - -block: # errors - break diff --git a/tests/controlflow/tunreachable.nim b/tests/controlflow/tunreachable.nim deleted file mode 100644 index 11c8595eb..000000000 --- a/tests/controlflow/tunreachable.nim +++ /dev/null @@ -1,32 +0,0 @@ -discard """ - cmd: "nim check --warningAsError:UnreachableCode $file" - action: "reject" - nimout: ''' -tunreachable.nim(23, 3) Error: unreachable code after 'return' statement or '{.noReturn.}' proc [UnreachableCode] -tunreachable.nim(30, 3) Error: unreachable code after 'return' statement or '{.noReturn.}' proc [UnreachableCode] -''' -""" - -# bug #9839 -template myquit1():untyped= - ## foo - quit(1) -template myquit2():untyped= - echo 123 - myquit1() - -proc main1()= - - # BUG: uncommenting this doesn't give `Error: unreachable statement` - myquit2() - - echo "after" - -main1() - -proc main2() = - myquit1() - - echo "after" - -main2() diff --git a/tests/converter/m18986.nim b/tests/converter/m18986.nim deleted file mode 100644 index 0ebf343ae..000000000 --- a/tests/converter/m18986.nim +++ /dev/null @@ -1,3 +0,0 @@ -import std/macros - -converter Lit*(x: uint): NimNode = newLit(x) diff --git a/tests/converter/mdontleak.nim b/tests/converter/mdontleak.nim deleted file mode 100644 index e55c3f87c..000000000 --- a/tests/converter/mdontleak.nim +++ /dev/null @@ -1,3 +0,0 @@ - -converter toBool(x: uint32): bool = x != 0 -# Note: This convertes is not exported! diff --git a/tests/converter/t18986.nim b/tests/converter/t18986.nim deleted file mode 100644 index ef300fa49..000000000 --- a/tests/converter/t18986.nim +++ /dev/null @@ -1,10 +0,0 @@ -discard """ - output: "Found a 0" -""" - -import m18986 except Lit -import std/macros - -# bug #18986 -var x = 0.uint -echo "Found a ", x diff --git a/tests/converter/t7097.nim b/tests/converter/t7097.nim deleted file mode 100644 index d8e953080..000000000 --- a/tests/converter/t7097.nim +++ /dev/null @@ -1,38 +0,0 @@ -type - Byte* = uint8 - Bytes* = seq[Byte] - - BytesRange* = object - bytes: Bytes - ibegin, iend: int - -proc initBytesRange*(s: var Bytes, ibegin = 0, iend = -1): BytesRange = - let e = if iend < 0: s.len + iend + 1 - else: iend - assert ibegin > 0 and e <= s.len - when defined(gcRefc): - shallow(s) - result.bytes = s - result.ibegin = ibegin - result.iend = e - -template `[]=`*(r: var BytesRange, i: int, v: Byte) = - r.bytes[r.ibegin + i] = v - -converter fromSeq*(s: Bytes): BytesRange = - var seqCopy = s - return initBytesRange(seqCopy) - -type - Reader* = object - data: BytesRange - position: int - -proc readerFromHex*(input: string): Reader = - let totalBytes = input.len div 2 - var backingStore = newSeq[Byte](totalBytes) - result.data = initBytesRange(backingStore) - - for i in 0 ..< totalBytes: - var nextByte = 0 - result.data[i] = Byte(nextByte) # <-------- instantiated from here diff --git a/tests/converter/t7098.nim b/tests/converter/t7098.nim index 30c9c1e25..8e7634882 100644 --- a/tests/converter/t7098.nim +++ b/tests/converter/t7098.nim @@ -14,8 +14,8 @@ proc initBytesRange*(s: var Bytes, ibegin = 0, iend = -1): BytesRange = let e = if iend < 0: s.len + iend + 1 else: iend assert ibegin >= 0 and e <= s.len - when defined(gcRefc): - shallow(s) + + shallow(s) result.bytes = s result.ibegin = ibegin result.iend = e diff --git a/tests/converter/t9165.nim b/tests/converter/t9165.nim deleted file mode 100644 index d0225ffbc..000000000 --- a/tests/converter/t9165.nim +++ /dev/null @@ -1,11 +0,0 @@ -type ustring = distinct string - -converter toUString(s: string): ustring = ustring(s) -converter toString(s: ustring): string = string(s) - -proc `[]=`*(s: var ustring, slice: Slice[int], replacement: ustring) {.inline.} = - s = replacement - -var s = ustring("123") -s[1..2] = "3" -doAssert s == "3" \ No newline at end of file diff --git a/tests/converter/tconverter.nim b/tests/converter/tconverter.nim deleted file mode 100644 index 0bf067c55..000000000 --- a/tests/converter/tconverter.nim +++ /dev/null @@ -1,11 +0,0 @@ -discard """ - output: '''fooo fooo''' -""" - -converter intToString[T](i: T): string = "fooo" - -let - foo: string = 1 - bar: string = intToString(2) - -echo foo, " ", bar \ No newline at end of file diff --git a/tests/converter/tconverter_with_varargs.nim b/tests/converter/tconverter_with_varargs.nim index fae83221b..6d7e31e85 100644 --- a/tests/converter/tconverter_with_varargs.nim +++ b/tests/converter/tconverter_with_varargs.nim @@ -8,7 +8,7 @@ type converter to_py*(i: int) : PPyRef = nil when false: - proc to_tuple*(vals: openArray[PPyRef]): PPyRef = + proc to_tuple*(vals: openarray[PPyRef]): PPyRef = discard proc abc(args: varargs[PPyRef]) = diff --git a/tests/converter/tdontleak.nim b/tests/converter/tdontleak.nim deleted file mode 100644 index 4965fa90a..000000000 --- a/tests/converter/tdontleak.nim +++ /dev/null @@ -1,10 +0,0 @@ -discard """ - output: '''5''' -joinable: false -""" - -import mdontleak -# bug #19213 - -let a = 5'u32 -echo a diff --git a/tests/converter/texplicit_conversion.nim b/tests/converter/texplicit_conversion.nim index e36d78ad5..6b2e96faf 100644 --- a/tests/converter/texplicit_conversion.nim +++ b/tests/converter/texplicit_conversion.nim @@ -11,9 +11,3 @@ converter toInt(s: string): int = let x = (int)"234" echo x - -block: # Test for nkconv - proc foo(o: var int) = - assert o == 0 - var a = 0 - foo(int(a)) \ No newline at end of file diff --git a/tests/converter/tgenericconverter.nim b/tests/converter/tgenericconverter.nim index cbbd2e1b0..e1c9f7c4c 100644 --- a/tests/converter/tgenericconverter.nim +++ b/tests/converter/tgenericconverter.nim @@ -28,27 +28,3 @@ aa.x = 666 p aa q aa - - -#------------------------------------------------------------- -# issue #16651 -type - PointTup = tuple - x: float32 - y: float32 - -converter tupleToPoint[T1, T2: SomeFloat](self: tuple[x: T1, y: T2]): PointTup = - result = (self.x.float32, self.y.float32) - -proc tupleToPointX(self: tuple[x: SomeFloat, y: SomeFloat]): PointTup = - result = (self.x.float32, self.y.float32) - -proc tupleToPointX2(self: tuple[x: SomeFloat, y: distinct SomeFloat]): PointTup = - result = (self.x.float32, self.y.float32) - -var t1: PointTup = tupleToPointX((1.0, 0.0)) -var t2: PointTup = tupleToPointX2((1.0, 0.0)) -var t3: PointTup = tupleToPointX2((1.0'f32, 0.0)) -var t4: PointTup = tupleToPointX2((1.0, 0.0'f32)) - -var x2: PointTup = (1.0, 0.0) \ No newline at end of file diff --git a/tests/converter/tor_in_converter.nim b/tests/converter/tor_in_converter.nim index df2334647..5674526a1 100644 --- a/tests/converter/tor_in_converter.nim +++ b/tests/converter/tor_in_converter.nim @@ -4,7 +4,7 @@ test''' """ # bug #4537 -# nim js -d:nodejs +# nim js --d:nodejs type Str = distinct string diff --git a/tests/coroutines/texceptions.nim b/tests/coroutines/texceptions.nim index 31feffdff..7b5d57ec0 100644 --- a/tests/coroutines/texceptions.nim +++ b/tests/coroutines/texceptions.nim @@ -1,5 +1,5 @@ discard """ - targets: "c" + target: "c" disabled: true """ diff --git a/tests/coroutines/tgc.nim b/tests/coroutines/tgc.nim index e2f8b6469..46f4f8e83 100644 --- a/tests/coroutines/tgc.nim +++ b/tests/coroutines/tgc.nim @@ -1,22 +1,19 @@ discard """ - matrix: "--gc:refc; --gc:arc; --gc:orc" target: "c" """ -when compileOption("gc", "refc") or not defined(openbsd): - # xxx openbsd gave: stdlib_coro.nim.c:406:22: error: array type 'jmp_buf' (aka 'long [11]') is not assignable (*dest).execContext = src.execContext; - import coro +import coro - var maxOccupiedMemory = 0 +var maxOccupiedMemory = 0 - proc testGC() = - var numbers = newSeq[int](100) - maxOccupiedMemory = max(maxOccupiedMemory, getOccupiedMem()) - suspend(0) +proc testGC() = + var numbers = newSeq[int](100) + maxOccupiedMemory = max(maxOccupiedMemory, getOccupiedMem()) + suspend(0) - start(testGC) - start(testGC) - run() +start(testGC) +start(testGC) +run() - GC_fullCollect() - doAssert(getOccupiedMem() < maxOccupiedMemory, "GC did not free any memory allocated in coroutines") +GC_fullCollect() +doAssert(getOccupiedMem() < maxOccupiedMemory, "GC did not free any memory allocated in coroutines") diff --git a/tests/coroutines/titerators.nim b/tests/coroutines/titerators.nim index 1ea134811..d12a5debe 100644 --- a/tests/coroutines/titerators.nim +++ b/tests/coroutines/titerators.nim @@ -1,5 +1,5 @@ discard """ - targets: "c" + target: "c" disabled: true """ diff --git a/tests/coroutines/twait.nim b/tests/coroutines/twait.nim index 71782ece1..1769966ab 100644 --- a/tests/coroutines/twait.nim +++ b/tests/coroutines/twait.nim @@ -1,28 +1,21 @@ discard """ output: "Exit 1\nExit 2" - matrix: "--gc:refc; --gc:arc; --gc:orc" + disabled: "macosx" target: "c" """ +import coro -when compileOption("gc", "refc") or not defined(openbsd): - # xxx openbsd failed, see tgc.nim - import coro +var coro1: CoroutineRef - var coro1: CoroutineRef - - proc testCoroutine1() = - for i in 0..<10: - suspend(0) - echo "Exit 1" - - proc testCoroutine2() = - coro1.wait() - echo "Exit 2" - - coro1 = coro.start(testCoroutine1) - coro.start(testCoroutine2) - run() -else: - # workaround +proc testCoroutine1() = + for i in 0..<10: + suspend(0) echo "Exit 1" + +proc testCoroutine2() = + coro1.wait() echo "Exit 2" + +coro1 = coro.start(testCoroutine1) +coro.start(testCoroutine2) +run() diff --git a/tests/cpp/enum.hpp b/tests/cpp/enum.hpp deleted file mode 100644 index 268999d68..000000000 --- a/tests/cpp/enum.hpp +++ /dev/null @@ -1,3 +0,0 @@ -namespace namespaced { -enum Enum { A, B, C }; -} diff --git a/tests/cpp/t12946.nim b/tests/cpp/t12946.nim deleted file mode 100644 index 79cd56251..000000000 --- a/tests/cpp/t12946.nim +++ /dev/null @@ -1,8 +0,0 @@ -discard """ - targets: "c cpp" -""" - -import std/atomics -type Futex = distinct Atomic[int32] - -var x: Futex diff --git a/tests/cpp/t4834.nim b/tests/cpp/t4834.nim deleted file mode 100644 index 0275b1b70..000000000 --- a/tests/cpp/t4834.nim +++ /dev/null @@ -1,17 +0,0 @@ -discard """ - targets: "cpp" -""" - -# issue #4834 -block: - defer: - let x = 0 - - -proc main() = - block: - defer: - raise newException(Exception, "foo") - -doAssertRaises(Exception): - main() diff --git a/tests/cpp/t6986.nim b/tests/cpp/t6986.nim index 16e455c3b..ffd277adb 100644 --- a/tests/cpp/t6986.nim +++ b/tests/cpp/t6986.nim @@ -5,9 +5,6 @@ discard """ import sequtils, strutils -when defined(nimPreviewSlimSystem): - import std/syncio - let rules = toSeq(lines("input")) .mapIt(it.split(" => ").mapIt(it.replace("/", ""))) diff --git a/tests/cpp/tasync_cpp.nim b/tests/cpp/tasync_cpp.nim index 3f4ec6208..a68be6cd5 100644 --- a/tests/cpp/tasync_cpp.nim +++ b/tests/cpp/tasync_cpp.nim @@ -1,7 +1,7 @@ discard """ targets: "cpp" output: "hello" - cmd: "nim cpp --clearNimblePath --nimblePath:build/deps/pkgs2 $file" + cmd: "nim cpp --nilseqs:on --nimblePath:tests/deps $file" """ # bug #3299 diff --git a/tests/cpp/tcovariancerules.nim b/tests/cpp/tcovariancerules.nim index 9d49f2cbd..e1769b0e6 100644 --- a/tests/cpp/tcovariancerules.nim +++ b/tests/cpp/tcovariancerules.nim @@ -28,10 +28,10 @@ template reject(x) = import macros -macro skipElse(n: untyped): untyped = n[0] +macro skipElse(n: untyped): typed = n[0] -template acceptWithCovariance(x, otherwise): untyped = - when defined nimEnableCovariance: +template acceptWithCovariance(x, otherwise): typed = + when nimEnableCovariance: x else: reject(x) @@ -79,16 +79,16 @@ proc wantsCovariantSeq2(s: seq[AnimalRef]) = proc wantsCovariantSeq3(s: seq[RefAlias[Animal]]) = for a in s: echo a.x -proc wantsCovariantOpenArray(s: openArray[ref Animal]) = +proc wantsCovariantOperArray(s: openarray[ref Animal]) = for a in s: echo a.x -proc modifiesCovariantOpenArray(s: var openArray[ref Animal]) = +proc modifiesCovariantOperArray(s: var openarray[ref Animal]) = for a in s: echo a.x -proc modifiesDerivedOpenArray(s: var openArray[ref Dog]) = +proc modifiesDerivedOperArray(s: var openarray[ref Dog]) = for a in s: echo a.x -proc wantsNonCovariantOpenArray(s: openArray[Animal]) = +proc wantsNonCovariantOperArray(s: openarray[Animal]) = for a in s: echo a.x proc wantsCovariantArray(s: array[2, ref Animal]) = @@ -199,15 +199,15 @@ accept: wantsCovariantSeq3(@[AnimalRef(cat), dog]) wantsCovariantSeq3(@[cat, dog]) - wantsCovariantOpenArray([cat, dog]) + wantsCovariantOperArray([cat, dog]) acceptWithCovariance: wantsCovariantSeq1(@[cat, cat]) wantsCovariantSeq2(@[dog, makeDerivedRef("dog X")]) # XXX: wantsCovariantSeq3(@[cat, cat]) - wantsCovariantOpenArray(@[cat, cat]) - wantsCovariantOpenArray([dog, dog]) + wantsCovariantOperArray(@[cat, cat]) + wantsCovariantOperArray([dog, dog]) else: echo "cat" echo "cat" @@ -226,7 +226,7 @@ accept: modifiesDerivedArray(dogRefsArray) modifiesDerivedSeq(dogRefs) -reject modifiesCovariantSeqd(ogRefs) +reject modifiesCovariantSeq(dogRefs) reject modifiesCovariantSeq(addr(dogRefs)) reject modifiesCovariantSeq(dogRefs.addr) @@ -245,19 +245,19 @@ when false: wantsNonCovariantArray animalValuesArray reject wantsNonCovariantSeq(dogRefs) -reject modifiesCovariantOpenArray(dogRefs) +reject modifiesCovariantOperArray(dogRefs) reject wantsNonCovariantArray(dogRefsArray) reject wantsNonCovariantSeq(dogValues) reject wantsNonCovariantArray(dogValuesArray) reject modifiesValueArray() -modifiesDerivedOpenArray dogRefs -reject modifiesDerivedOpenArray(dogValues) -reject modifiesDerivedOpenArray(animalRefs) +modifiesDerivedOperArray dogRefs +reject modifiesDerivedOperArray(dogValues) +reject modifiesDerivedOperArray(animalRefs) -reject wantsNonCovariantOpenArray(animalRefs) -reject wantsNonCovariantOpenArray(dogRefs) -reject wantsNonCovariantOpenArray(dogValues) +reject wantsNonCovariantOperArray(animalRefs) +reject wantsNonCovariantOperArray(dogRefs) +reject wantsNonCovariantOperArray(dogValues) var animalRefSeq: seq[ref Animal] @@ -300,12 +300,12 @@ template struct ARR { typedef T DataType[2]; DataType data; }; """.} type - MyPtr[out T] {.importcpp: "'0 *"} = object + MyPtr {.importcpp: "'0 *"} [out T] = object - MySeq[out T] {.importcpp: "ARR<'0>", nodecl} = object + MySeq {.importcpp: "ARR<'0>", nodecl} [out T] = object data: array[2, T] - MyAction[in T] {.importcpp: "FN<'0>::type"} = object + MyAction {.importcpp: "FN<'0>::type"} [in T] = object var cAnimal: MyPtr[Animal] @@ -415,3 +415,4 @@ reject usesAddressOfAnimalRefSeq(addr cAnimalValues) reject usesAddressOfAnimalRefSeq(addr cDogValues) accept usesAddressOfAnimalRefSeq(addr cAnimals) reject usesAddressOfAnimalRefSeq(addr cDogs) + diff --git a/tests/cpp/tcppraise.nim b/tests/cpp/tcppraise.nim index f03956d4c..8f34cb3e4 100644 --- a/tests/cpp/tcppraise.nim +++ b/tests/cpp/tcppraise.nim @@ -68,4 +68,4 @@ except: echo getCurrentExceptionMsg() discard -doAssert: getCurrentException() == nil +doAssert: getCurrentException() == nil \ No newline at end of file diff --git a/tests/cpp/tdont_init_instantiation.nim b/tests/cpp/tdont_init_instantiation.nim index a13a3f6b4..fe487fba0 100644 --- a/tests/cpp/tdont_init_instantiation.nim +++ b/tests/cpp/tdont_init_instantiation.nim @@ -20,7 +20,7 @@ template class C { }; """.} -type C[X] {.importcpp, header: "", nodecl.} = object +type C{.importcpp, header: "", nodecl.} [X] = object proc mkC[X]: C[X] {.importcpp: "C<'*0>()", constructor, nodecl.} proc foo(): C[int] = diff --git a/tests/cpp/temitlist.nim b/tests/cpp/temitlist.nim index 9170be079..852537518 100644 --- a/tests/cpp/temitlist.nim +++ b/tests/cpp/temitlist.nim @@ -1,14 +1,12 @@ discard """ targets: "cpp" - output: ''' -6.0 + output: '''6.0 0''' -disabled: "windows" # pending bug #18011 """ # bug #4730 -type Vector*[T] {.importcpp: "std::vector", header: "".} = object +type Vector* {.importcpp: "std::vector", header: "".}[T] = object template `[]=`*[T](v: var Vector[T], key: int, val: T) = {.emit: [v, "[", key, "] = ", val, ";"].} diff --git a/tests/cpp/tempty_generic_obj.nim b/tests/cpp/tempty_generic_obj.nim index 6125190b4..913c1ec3c 100644 --- a/tests/cpp/tempty_generic_obj.nim +++ b/tests/cpp/tempty_generic_obj.nim @@ -1,9 +1,7 @@ discard """ targets: "cpp" - output: ''' -int + output: '''int float''' -disabled: "windows" # pending bug #18011 """ import typetraits diff --git a/tests/cpp/tenum_set.nim b/tests/cpp/tenum_set.nim deleted file mode 100644 index 6afed722f..000000000 --- a/tests/cpp/tenum_set.nim +++ /dev/null @@ -1,9 +0,0 @@ -discard """ -targets: "cpp" -output: "{A, B, C}" -""" - -type Enum {.importcpp: "namespaced::Enum", header: "enum.hpp".} = enum A, B, C - -var vals = {low(Enum) .. high(Enum)} -echo vals diff --git a/tests/cpp/tevalorder.nim b/tests/cpp/tevalorder.nim index 4764f3aca..f130cef6c 100644 --- a/tests/cpp/tevalorder.nim +++ b/tests/cpp/tevalorder.nim @@ -2,7 +2,7 @@ discard """ output: '''0 1 2''' -targets: "cpp" +target: "cpp" """ # bug #8202 diff --git a/tests/cpp/torc.nim b/tests/cpp/torc.nim deleted file mode 100644 index 64c6c0e5f..000000000 --- a/tests/cpp/torc.nim +++ /dev/null @@ -1,41 +0,0 @@ -discard """ - targets: "cpp" - matrix: "--gc:orc" -""" - -import std/options - -# bug #18410 -type - O = object of RootObj - val: pointer - -proc p(): Option[O] = none(O) - -doAssert $p() == "none(O)" - -# bug #17351 -type - Foo = object of RootObj - Foo2 = object of Foo - Bar = object - x: Foo2 - -var b = Bar() -discard b - -# bug #4678 -{.emit: """/*TYPESECTION*/ -enum class SomeEnum {A,B,C}; -""".} -type - EnumVector[T: enum] {.importcpp: "std::vector", header: "vector".} = object - SomeEnum {.importcpp, nodecl.} = enum - A,B,C - -proc asVector*[T](t: T): EnumVector[T] = - discard -# Nim generates this signature here: -# N_NIMCALL(std::vector<> , asvector_106028_3197418230)(SomeEnum t0) - -discard asVector(SomeEnum.A) diff --git a/tests/cpp/tretvar.nim b/tests/cpp/tretvar.nim index 0c3765346..83c37721e 100644 --- a/tests/cpp/tretvar.nim +++ b/tests/cpp/tretvar.nim @@ -16,9 +16,9 @@ type proc c_str(a: stdString): cstring {.importcpp: "(char *)(#.c_str())", header: "".} -proc len(a: stdString): csize_t {.importcpp: "(#.length())", header: "".} +proc len(a: stdString): csize {.importcpp: "(#.length())", header: "".} -proc setChar(a: var stdString, i: csize_t, c: char) {.importcpp: "(#[#] = #)", header: "".} +proc setChar(a: var stdString, i: csize, c: char) {.importcpp: "(#[#] = #)", header: "".} proc `*`*[T](this: stdUniquePtr[T]): var T {.noSideEffect, importcpp: "(* #)", header: "".} diff --git a/tests/cpp/ttemplatetype.nim b/tests/cpp/ttemplatetype.nim index bf243ac43..ef24e4cdc 100644 --- a/tests/cpp/ttemplatetype.nim +++ b/tests/cpp/ttemplatetype.nim @@ -3,7 +3,7 @@ discard """ """ type - Map[T,U] {.importcpp: "std::map", header: "".} = object + Map {.importcpp: "std::map", header: "".} [T,U] = object proc cInitMap(T: typedesc, U: typedesc): Map[T,U] {.importcpp: "std::map<'*1,'*2>()", nodecl.} diff --git a/tests/cpp/tterminate_handler.nim b/tests/cpp/tterminate_handler.nim index c5ccef53c..79949f4da 100644 --- a/tests/cpp/tterminate_handler.nim +++ b/tests/cpp/tterminate_handler.nim @@ -2,9 +2,8 @@ discard """ targets: "cpp" outputsub: "Error: unhandled unknown cpp exception" exitcode: 1 - disabled: true """ type Crap {.importcpp: "int".} = object var c: Crap -raise c +raise c \ No newline at end of file diff --git a/tests/cpp/ttypeinfo1.nim b/tests/cpp/ttypeinfo.nim similarity index 100% rename from tests/cpp/ttypeinfo1.nim rename to tests/cpp/ttypeinfo.nim diff --git a/tests/cpp/tvector_iterator.nim b/tests/cpp/tvector_iterator.nim index c3886c547..4d686955f 100644 --- a/tests/cpp/tvector_iterator.nim +++ b/tests/cpp/tvector_iterator.nim @@ -12,8 +12,8 @@ struct Vector { """.} type - Vector[T] {.importcpp: "Vector".} = object - VectorIterator[T] {.importcpp: "Vector<'0>::Iterator".} = object + Vector {.importcpp: "Vector".} [T] = object + VectorIterator {.importcpp: "Vector<'0>::Iterator".} [T] = object var x: VectorIterator[void] diff --git a/tests/defaultprocparam/tdefaultprocparam.nim b/tests/defaultprocparam/tdefaultprocparam.nim index 90edfa8c9..5f8c1adab 100644 --- a/tests/defaultprocparam/tdefaultprocparam.nim +++ b/tests/defaultprocparam/tdefaultprocparam.nim @@ -1,90 +1,8 @@ discard """ output: ''' hi -hi -topLevel|topLevel| -topLevel2|topLevel2| -inProc|inProc| -inProc2|inProc2| -topLevel|9 -topLevel2|10 -inProc|7 -inProc2|8 -must have been the wind.. -I'm there -must have been the wind.. -I'm there -symbol'a'symbol'a' -symbol'b'symbol'b' -symbol'a'symbol'b' -symbol'a'9 -symbol'b'9 -symbol'a'0 ''' """ import mdefaultprocparam p() - -proc testP = - p() - -testP() - -proc p2(s: string, count = s): string = s & count - -proc testP2 = - echo p2 """inProc|""" - echo p2 """inProc2|""" - -echo p2 """topLevel|""" -echo p2 """topLevel2|""" - -testP2() - -import macros -macro dTT(a: typed) = echo a.treeRepr - -proc p3(s: string, count = len(s)): string = s & $count - -proc testP3 = - echo p3 """inProc|""" - echo p3 """inProc2|""" - -echo p3 """topLevel|""" -echo p3 """topLevel2|""" - -testP3() - -proc cut(s: string, c = len(s)): string = - s[0..\n"), + jesterVer + ) + result.code = Http502 + result.matched = true + result.action = TCActionSend + of RouteCode: + result.headers = some(@({ + "Content-Type": "text/html;charset=utf-8" + })) + result.content = error( + $error.data.code, + jesterVer + ) + result.code = error.data.code + result.matched = true + result.action = TCActionSend + +proc initRouteError(exc: ref Exception): RouteError = + RouteError( + kind: RouteException, + exc: exc + ) + +proc initRouteError(data: ResponseData): RouteError = + RouteError( + kind: RouteCode, + data: data + ) + +proc dispatchError( + jes: Jester, + request: Request, + error: RouteError +): Future[ResponseData] {.async.} = + for errorProc in jes.errorHandlers: + let data = await errorProc(request, error) + if data.matched: + return data + + return defaultErrorFilter(error) + +proc dispatch( + self: Jester, + req: Request +): Future[ResponseData] {.async.} = + for matcher in self.matchers: + if matcher.async: + let data = await matcher.asyncProc(req) + if data.matched: + return data + else: + let data = matcher.syncProc(req) + if data.matched: + return data + +proc handleFileRequest( + jes: Jester, req: Request +): Future[ResponseData] {.async.} = + # Find static file. + # TODO: Caching. + let path = normalizedPath( + jes.settings.staticDir / cgi.decodeUrl(req.pathInfo) + ) + + # Verify that this isn't outside our static` dir. + var status = Http400 + if path.splitFile.dir.startsWith(jes.settings.staticDir): + if existsDir(path): + status = await sendStaticIfExists( + req, + @[path / "index.html", path / "index.htm"] + ) + else: + status = await sendStaticIfExists(req, @[path]) + + # Http200 means that the data was sent so there is nothing else to do. + if status == Http200: + result[0] = TCActionRaw + when not defined(release): + logging.debug(" -> $1" % path) + return + + return (TCActionSend, status, none[seq[(string, string)]](), "", true) + +proc handleRequestSlow( + jes: Jester, + req: Request, + respDataFut: Future[ResponseData] | ResponseData, + dispatchedError: bool +): Future[void] {.async.} = + var dispatchedError = dispatchedError + var respData: ResponseData + + # httpReq.send(Http200, "Hello, World!", "") + try: + when respDataFut is Future[ResponseData]: + respData = await respDataFut + else: + respData = respDataFut + except: + # Handle any errors by showing them in the browser. + # TODO: Improve the look of this. + let exc = getCurrentException() + respData = await dispatchError(jes, req, initRouteError(exc)) + dispatchedError = true + + # TODO: Put this in a custom matcher? + if not respData.matched: + respData = await handleFileRequest(jes, req) + + case respData.action + of TCActionSend: + if (respData.code.is4xx or respData.code.is5xx) and + not dispatchedError and respData.content.len == 0: + respData = await dispatchError(jes, req, initRouteError(respData)) + + statusContent( + req, + respData.code, + respData.content, + respData.headers + ) + else: + when not defined(release): + logging.debug(" $1" % [$respData.action]) + + # Cannot close the client socket. AsyncHttpServer may be keeping it alive. + +proc handleRequest(jes: Jester, httpReq: NativeRequest): Future[void] = + var req = initRequest(httpReq, jes.settings) + try: + when not defined(release): + logging.debug("$1 $2" % [$req.reqMethod, req.pathInfo]) + + if likely(jes.matchers.len == 1 and not jes.matchers[0].async): + let respData = jes.matchers[0].syncProc(req) + if likely(respData.matched): + statusContent( + req, + respData.code, + respData.content, + respData.headers + ) + else: + return handleRequestSlow(jes, req, respData, false) + else: + return handleRequestSlow(jes, req, dispatch(jes, req), false) + except: + let exc = getCurrentException() + let respDataFut = dispatchError(jes, req, initRouteError(exc)) + return handleRequestSlow(jes, req, respDataFut, true) + +proc newSettings*( + port = Port(5000), staticDir = getCurrentDir() / "public", + appName = "", bindAddr = "", reusePort = false, + futureErrorHandler: proc (fut: Future[void]) {.closure, gcsafe.} = nil +): Settings = + result = Settings( + staticDir: staticDir, + appName: appName, + port: port, + bindAddr: bindAddr, + reusePort: reusePort, + futureErrorHandler: futureErrorHandler + ) + +proc register*(self: var Jester, matcher: MatchProc) = + ## Adds the specified matcher procedure to the specified Jester instance. + self.matchers.add( + Matcher( + async: true, + asyncProc: matcher + ) + ) + +proc register*(self: var Jester, matcher: MatchProcSync) = + ## Adds the specified matcher procedure to the specified Jester instance. + self.matchers.add( + Matcher( + async: false, + syncProc: matcher + ) + ) + +proc register*(self: var Jester, errorHandler: ErrorProc) = + ## Adds the specified error handler procedure to the specified Jester instance. + self.errorHandlers.add(errorHandler) + +proc initJester*( + settings: Settings = newSettings() +): Jester = + result.settings = settings + result.settings.mimes = newMimetypes() + result.matchers = @[] + result.errorHandlers = @[] + +proc initJester*( + matcher: MatchProc, + settings: Settings = newSettings() +): Jester = + result = initJester(settings) + result.register(matcher) + +proc initJester*( + matcher: MatchProcSync, # TODO: Annoying nim bug: `MatchProc | MatchProcSync` doesn't work. + settings: Settings = newSettings() +): Jester = + result = initJester(settings) + result.register(matcher) + +proc serve*( + self: var Jester +) = + ## Creates a new async http server instance and registers + ## it with the dispatcher. + ## + ## The event loop is executed by this function, so it will block forever. + + # Ensure we have at least one logger enabled, defaulting to console. + if logging.getHandlers().len == 0: + addHandler(logging.newConsoleLogger()) + setLogFilter(when defined(release): lvlInfo else: lvlDebug) + + if self.settings.bindAddr.len > 0: + logging.info("Jester is making jokes at http://$1:$2$3" % + [ + self.settings.bindAddr, $self.settings.port, self.settings.appName + ] + ) + else: + logging.info("Jester is making jokes at http://0.0.0.0:$1$2" % + [$self.settings.port, self.settings.appName]) + + var jes = self + when useHttpBeast: + run( + proc (req: httpbeast.Request): Future[void] = + result = handleRequest(jes, req), + httpbeast.initSettings(self.settings.port, self.settings.bindAddr) + ) + else: + self.httpServer = newAsyncHttpServer(reusePort=self.settings.reusePort) + let serveFut = self.httpServer.serve( + self.settings.port, + proc (req: asynchttpserver.Request): Future[void] {.gcsafe, closure.} = + result = handleRequest(jes, req), + self.settings.bindAddr) + if not self.settings.futureErrorHandler.isNil: + serveFut.callback = self.settings.futureErrorHandler + else: + asyncCheck serveFut + runForever() + +template resp*(code: HttpCode, + headers: openarray[tuple[key, value: string]], + content: string): typed = + ## Sets ``(code, headers, content)`` as the response. + bind TCActionSend, newHttpHeaders + result = (TCActionSend, code, headers.newHttpHeaders.some(), content, true) + break route + +template setHeader(headers: var Option[RawHeaders], key, value: string): typed = + bind isNone + if isNone(headers): + headers = some(@({key: value})) + else: + block outer: + # Overwrite key if it exists. + var h = headers.get() + for i in 0 ..< h.len: + if h[i][0] == key: + h[i][1] = value + headers = some(h) + break outer + + # Add key if it doesn't exist. + headers = some(h & @({key: value})) + +template resp*(content: string, contentType = "text/html;charset=utf-8"): typed = + ## Sets ``content`` as the response; ``Http200`` as the status code + ## and ``contentType`` as the Content-Type. + bind TCActionSend, newHttpHeaders, strtabs.`[]=` + result[0] = TCActionSend + result[1] = Http200 + setHeader(result[2], "Content-Type", contentType) + result[3] = content + # This will be set by our macro, so this is here for those not using it. + result.matched = true + break route + +template resp*(content: JsonNode): typed = + ## Serializes ``content`` as the response, sets ``Http200`` as status code + ## and "application/json" Content-Type. + resp($content, contentType="application/json") + +template resp*(code: HttpCode, content: string, + contentType = "text/html;charset=utf-8"): typed = + ## Sets ``content`` as the response; ``code`` as the status code + ## and ``contentType`` as the Content-Type. + bind TCActionSend, newHttpHeaders + result[0] = TCActionSend + result[1] = code + setHeader(result[2], "Content-Type", contentType) + result[3] = content + result.matched = true + break route + +template resp*(code: HttpCode): typed = + ## Responds with the specified ``HttpCode``. This ensures that error handlers + ## are called. + bind TCActionSend, newHttpHeaders + result[0] = TCActionSend + result[1] = code + result.matched = true + break route + +template redirect*(url: string): typed = + ## Redirects to ``url``. Returns from this request handler immediately. + ## Any set response headers are preserved for this request. + bind TCActionSend, newHttpHeaders + result[0] = TCActionSend + result[1] = Http303 + setHeader(result[2], "Location", url) + result[3] = "" + result.matched = true + break route + +template pass*(): typed = + ## Skips this request handler. + ## + ## If you want to stop this request from going further use ``halt``. + result.action = TCActionPass + break outerRoute + +template cond*(condition: bool): typed = + ## If ``condition`` is ``False`` then ``pass`` will be called, + ## i.e. this request handler will be skipped. + if not condition: break outerRoute + +template halt*(code: HttpCode, + headers: openarray[tuple[key, val: string]], + content: string): typed = + ## Immediately replies with the specified request. This means any further + ## code will not be executed after calling this template in the current + ## route. + bind TCActionSend, newHttpHeaders + result[0] = TCActionSend + result[1] = code + result[2] = some(@headers) + result[3] = content + result.matched = true + break allRoutes + +template halt*(): typed = + ## Halts the execution of this request immediately. Returns a 404. + ## All previously set values are **discarded**. + halt(Http404, {"Content-Type": "text/html;charset=utf-8"}, error($Http404, jesterVer)) + +template halt*(code: HttpCode): typed = + halt(code, {"Content-Type": "text/html;charset=utf-8"}, error($code, jesterVer)) + +template halt*(content: string): typed = + halt(Http404, {"Content-Type": "text/html;charset=utf-8"}, content) + +template halt*(code: HttpCode, content: string): typed = + halt(code, {"Content-Type": "text/html;charset=utf-8"}, content) + +template attachment*(filename = ""): typed = + ## Instructs the browser that the response should be stored on disk + ## rather than displayed in the browser. + var disposition = "attachment" + if filename != "": + disposition.add("; filename=\"" & extractFilename(filename) & "\"") + let ext = splitFile(filename).ext + let contentTypeSet = + isSome(result[2]) and result[2].get().toTable.hasKey("Content-Type") + if not contentTypeSet and ext != "": + setHeader(result[2], "Content-Type", getMimetype(request.settings.mimes, ext)) + setHeader(result[2], "Content-Disposition", disposition) + +template sendFile*(filename: string): typed = + ## Sends the file at the specified filename as the response. + result[0] = TCActionRaw + let sendFut = sendStaticIfExists(request, @[filename]) + yield sendFut + let status = sendFut.read() + if status != Http200: + raise newException(JesterError, "Couldn't send requested file: " & filename) + # This will be set by our macro, so this is here for those not using it. + result.matched = true + break route + +template `@`*(s: string): untyped = + ## Retrieves the parameter ``s`` from ``request.params``. ``""`` will be + ## returned if parameter doesn't exist. + if s in params(request): + # TODO: Why does request.params not work? :( + # TODO: This is some weird bug with macros/templates, I couldn't + # TODO: reproduce it easily. + params(request)[s] + else: + "" + +proc setStaticDir*(request: Request, dir: string) = + ## Sets the directory in which Jester will look for static files. It is + ## ``./public`` by default. + ## + ## The files will be served like so: + ## + ## ./public/css/style.css ``->`` http://example.com/css/style.css + ## + ## (``./public`` is not included in the final URL) + request.settings.staticDir = dir + +proc getStaticDir*(request: Request): string = + ## Gets the directory in which Jester will look for static files. + ## + ## ``./public`` by default. + return request.settings.staticDir + +proc makeUri*(request: Request, address = "", absolute = true, + addScriptName = true): string = + ## Creates a URI based on the current request. If ``absolute`` is true it will + ## add the scheme (Usually 'http://'), `request.host` and `request.port`. + ## If ``addScriptName`` is true `request.appName` will be prepended before + ## ``address``. + + # Check if address already starts with scheme:// + var uri = parseUri(address) + + if uri.scheme != "": return address + uri.path = "/" + uri.query = "" + uri.anchor = "" + if absolute: + uri.hostname = request.host + uri.scheme = (if request.secure: "https" else: "http") + if request.port != (if request.secure: 443 else: 80): + uri.port = $request.port + + if addScriptName: uri = uri / request.appName + if address != "": + uri = uri / address + else: + uri = uri / request.pathInfo + return $uri + +template uri*(address = "", absolute = true, addScriptName = true): untyped = + ## Convenience template which can be used in a route. + request.makeUri(address, absolute, addScriptName) + +proc daysForward*(days: int): DateTime = + ## Returns a DateTime object referring to the current time plus ``days``. + return getTime().utc + initInterval(days = days) + +template setCookie*(name, value: string, expires="", + sameSite: SameSite=Lax): typed = + ## Creates a cookie which stores ``value`` under ``name``. + ## + ## The SameSite argument determines the level of CSRF protection that + ## you wish to adopt for this cookie. It's set to Lax by default which + ## should protect you from most vulnerabilities. Note that this is only + ## supported by some browsers: + ## https://caniuse.com/#feat=same-site-cookie-attribute + let newCookie = makeCookie(name, value, expires) + if isSome(result[2]) and + (let headers = result[2].get(); headers.toTable.hasKey("Set-Cookie")): + result[2] = some(headers & @({"Set-Cookie": newCookie})) + else: + setHeader(result[2], "Set-Cookie", newCookie) + +template setCookie*(name, value: string, expires: DateTime, + sameSite: SameSite=Lax): typed = + ## Creates a cookie which stores ``value`` under ``name``. + setCookie(name, value, format(expires, "ddd',' dd MMM yyyy HH:mm:ss 'GMT'")) + +proc normalizeUri*(uri: string): string = + ## Remove any trailing ``/``. + if uri[uri.len-1] == '/': result = uri[0 .. uri.len-2] + else: result = uri + +# -- Macro + +proc checkAction*(respData: var ResponseData): bool = + case respData.action + of TCActionSend, TCActionRaw: + result = true + of TCActionPass: + result = false + of TCActionNothing: + assert(false) + +proc skipDo(node: NimNode): NimNode {.compiletime.} = + if node.kind == nnkDo: + result = node[6] + else: + result = node + +proc ctParsePattern(pattern, pathPrefix: string): NimNode {.compiletime.} = + result = newNimNode(nnkPrefix) + result.add newIdentNode("@") + result.add newNimNode(nnkBracket) + + proc addPattNode(res: var NimNode, typ, text, + optional: NimNode) {.compiletime.} = + var objConstr = newNimNode(nnkObjConstr) + + objConstr.add bindSym("Node") + objConstr.add newNimNode(nnkExprColonExpr).add( + newIdentNode("typ"), typ) + objConstr.add newNimNode(nnkExprColonExpr).add( + newIdentNode("text"), text) + objConstr.add newNimNode(nnkExprColonExpr).add( + newIdentNode("optional"), optional) + + res[1].add objConstr + + var patt = parsePattern(pattern) + if pathPrefix.len > 0: + result.addPattNode( + bindSym("NodeText"), # Node kind + newStrLitNode(pathPrefix), # Text + newIdentNode("false") # Optional? + ) + + for node in patt: + result.addPattNode( + case node.typ + of NodeText: bindSym("NodeText") + of NodeField: bindSym("NodeField"), + newStrLitNode(node.text), + newIdentNode(if node.optional: "true" else: "false")) + +template setDefaultResp*(): typed = + # TODO: bindSym this in the 'routes' macro and put it in each route + bind TCActionNothing, newHttpHeaders + result.action = TCActionNothing + result.code = Http200 + result.content = "" + +template declareSettings(): typed {.dirty.} = + when not declaredInScope(settings): + var settings = newSettings() + +proc createJesterPattern( + routeNode, patternMatchSym: NimNode, + pathPrefix: string +): NimNode {.compileTime.} = + var ctPattern = ctParsePattern(routeNode[1].strVal, pathPrefix) + # -> let = .match(request.path) + return newLetStmt(patternMatchSym, + newCall(bindSym"match", ctPattern, parseExpr("request.pathInfo"))) + +proc escapeRegex(s: string): string = + result = "" + for i in s: + case i + # https://stackoverflow.com/a/400316/492186 + of '.', '^', '$', '*', '+', '?', '(', ')', '[', '{', '\\', '|': + result.add('\\') + result.add(i) + else: + result.add(i) + +proc createRegexPattern( + routeNode, reMatchesSym, patternMatchSym: NimNode, + pathPrefix: string +): NimNode {.compileTime.} = + # -> let = find(request.pathInfo, , ) + var strNode = routeNode[1].copyNimTree() + strNode[1].strVal = escapeRegex(pathPrefix) & strNode[1].strVal + return newLetStmt( + patternMatchSym, + newCall( + bindSym"find", + parseExpr("request.pathInfo"), + strNode, + reMatchesSym + ) + ) + +proc determinePatternType(pattern: NimNode): MatchType {.compileTime.} = + case pattern.kind + of nnkStrLit: + var patt = parsePattern(pattern.strVal) + if patt.len == 1 and patt[0].typ == NodeText: + return MStatic + else: + return MSpecial + of nnkCallStrLit: + expectKind(pattern[0], nnkIdent) + case ($pattern[0]).normalize + of "re": return MRegex + else: + macros.error("Invalid pattern type: " & $pattern[0]) + else: + macros.error("Unexpected node kind: " & $pattern.kind) + +proc createCheckActionIf(): NimNode = + var checkActionIf = parseExpr( + "if checkAction(result): result.matched = true; break routesList" + ) + checkActionIf[0][0][0] = bindSym"checkAction" + return checkActionIf + +proc createGlobalMetaRoute(routeNode, dest: NimNode) {.compileTime.} = + ## Creates a ``before`` or ``after`` route with no pattern, i.e. one which + ## will be always executed. + + # -> block route: + var innerBlockStmt = newStmtList( + newNimNode(nnkBlockStmt).add(newIdentNode("route"), routeNode[1].skipDo()) + ) + + # -> block outerRoute: + var blockStmt = newNimNode(nnkBlockStmt).add( + newIdentNode("outerRoute"), innerBlockStmt) + dest.add blockStmt + +proc createRoute( + routeNode, dest: NimNode, pathPrefix: string, isMetaRoute: bool = false +) {.compileTime.} = + ## Creates code which checks whether the current request path + ## matches a route. + ## + ## The `isMetaRoute` parameter determines whether the route to be created is + ## one of either a ``before`` or an ``after`` route. + + var patternMatchSym = genSym(nskLet, "patternMatchRet") + + # Only used for Regex patterns. + var reMatchesSym = genSym(nskVar, "reMatches") + var reMatches = parseExpr("var reMatches: array[20, string]") + reMatches[0][0] = reMatchesSym + reMatches[0][1][1] = bindSym("MaxSubpatterns") + + let patternType = determinePatternType(routeNode[1]) + case patternType + of MStatic: + discard + of MSpecial: + dest.add createJesterPattern(routeNode, patternMatchSym, pathPrefix) + of MRegex: + dest.add reMatches + dest.add createRegexPattern( + routeNode, reMatchesSym, patternMatchSym, pathPrefix + ) + + var ifStmtBody = newStmtList() + case patternType + of MStatic: discard + of MSpecial: + # -> setPatternParams(request, ret.params) + ifStmtBody.add newCall(bindSym"setPatternParams", newIdentNode"request", + newDotExpr(patternMatchSym, newIdentNode"params")) + of MRegex: + # -> setReMatches(request, ) + ifStmtBody.add newCall(bindSym"setReMatches", newIdentNode"request", + reMatchesSym) + + ifStmtBody.add routeNode[2].skipDo() + + let checkActionIf = + if isMetaRoute: + parseExpr("break routesList") + else: + createCheckActionIf() + # -> block route: ; + var innerBlockStmt = newStmtList( + newNimNode(nnkBlockStmt).add(newIdentNode("route"), ifStmtBody), + checkActionIf + ) + + let ifCond = + case patternType + of MStatic: + infix( + parseExpr("request.pathInfo"), + "==", + newStrLitNode(pathPrefix & routeNode[1].strVal) + ) + of MSpecial: + newDotExpr(patternMatchSym, newIdentNode("matched")) + of MRegex: + infix(patternMatchSym, "!=", newIntLitNode(-1)) + + # -> if .matched: + var ifStmt = newIfStmt((ifCond, innerBlockStmt)) + + # -> block outerRoute: + var blockStmt = newNimNode(nnkBlockStmt).add( + newIdentNode("outerRoute"), ifStmt) + dest.add blockStmt + +proc createError( + errorNode: NimNode, + httpCodeBranches, + exceptionBranches: var seq[tuple[cond, body: NimNode]] +) = + if errorNode.len != 3: + error("Missing error condition or body.", errorNode) + + let routeIdent = newIdentNode("route") + let outerRouteIdent = newIdentNode("outerRoute") + let checkActionIf = createCheckActionIf() + let exceptionIdent = newIdentNode("exception") + let errorIdent = newIdentNode("error") # TODO: Ugh. I shouldn't need these... + let errorCond = errorNode[1] + let errorBody = errorNode[2] + let body = quote do: + block `outerRouteIdent`: + block `routeIdent`: + `errorBody` + `checkActionIf` + + case errorCond.kind + of nnkIdent: + let name = errorCond.strVal + if name.len == 7 and name.startsWith("Http"): + # HttpCode. + httpCodeBranches.add( + ( + infix(parseExpr("error.data.code"), "==", errorCond), + body + ) + ) + else: + # Exception + exceptionBranches.add( + ( + infix(parseExpr("error.exc"), "of", errorCond), + quote do: + let `exceptionIdent` = (ref `errorCond`)(`errorIdent`.exc) + `body` + ) + ) + of nnkCurly: + expectKind(errorCond[0], nnkInfix) + httpCodeBranches.add( + ( + infix(parseExpr("error.data.code"), "in", errorCond), + body + ) + ) + else: + error("Expected exception type or set[HttpCode].", errorCond) + +const definedRoutes = CacheTable"jester.routes" + +proc processRoutesBody( + body: NimNode, + # For HTTP methods. + caseStmtGetBody, + caseStmtPostBody, + caseStmtPutBody, + caseStmtDeleteBody, + caseStmtHeadBody, + caseStmtOptionsBody, + caseStmtTraceBody, + caseStmtConnectBody, + caseStmtPatchBody: var NimNode, + # For `error`. + httpCodeBranches, + exceptionBranches: var seq[tuple[cond, body: NimNode]], + # For before/after stmts. + beforeStmts, + afterStmts: var NimNode, + # For other statements. + outsideStmts: var NimNode, + pathPrefix: string +) = + for i in 0.. 1: + extend[2].strVal + else: + "" + if prefix.len != 0 and prefix[0] != '/': + error("Path prefix for extended route must start with '/'", extend[2]) + + processRoutesBody( + definedRoutes[extend[1].strVal], + caseStmtGetBody, + caseStmtPostBody, + caseStmtPutBody, + caseStmtDeleteBody, + caseStmtHeadBody, + caseStmtOptionsBody, + caseStmtTraceBody, + caseStmtConnectBody, + caseStmtPatchBody, + httpCodeBranches, + exceptionBranches, + beforeStmts, + afterStmts, + outsideStmts, + pathPrefix & prefix + ) + else: + outsideStmts.add(body[i]) + of nnkCommentStmt: + discard + of nnkPragma: + if body[i][0].strVal.normalize notin ["async", "sync"]: + outsideStmts.add(body[i]) + else: + outsideStmts.add(body[i]) + +type + NeedsAsync = enum + ImplicitTrue, ImplicitFalse, ExplicitTrue, ExplicitFalse +proc needsAsync(node: NimNode): NeedsAsync = + result = ImplicitFalse + case node.kind + of nnkCommand, nnkCall: + if node[0].kind == nnkIdent: + case node[0].strVal.normalize + of "await", "sendfile": + return ImplicitTrue + of "resp", "halt", "attachment", "pass", "redirect", "cond", "get", + "post", "patch", "delete": + # This is just a simple heuristic. It's by no means meant to be + # exhaustive. + discard + else: + return ImplicitTrue + of nnkYieldStmt: + return ImplicitTrue + of nnkPragma: + if node[0].kind == nnkIdent: + case node[0].strVal.normalize + of "sync": + return ExplicitFalse + of "async": + return ExplicitTrue + else: discard + else: discard + + for c in node: + let r = needsAsync(c) + if r in {ImplicitTrue, ExplicitTrue, ExplicitFalse}: return r + +proc routesEx(name: string, body: NimNode): NimNode = + # echo(treeRepr(body)) + # echo(treeRepr(name)) + + # Save this route's body so that it can be incorporated into another route. + definedRoutes[name] = body.copyNimTree + + result = newStmtList() + + # -> declareSettings() + result.add newCall(bindSym"declareSettings") + + var outsideStmts = newStmtList() + + var matchBody = newNimNode(nnkStmtList) + let setDefaultRespIdent = bindSym"setDefaultResp" + matchBody.add newCall(setDefaultRespIdent) + # TODO: This diminishes the performance. Would be nice to only include it + # TODO: when setPatternParams or setReMatches is used. + matchBody.add parseExpr("var request = request") + + # HTTP router case statement nodes: + var caseStmt = newNimNode(nnkCaseStmt) + caseStmt.add parseExpr("request.reqMethod") + + var caseStmtGetBody = newNimNode(nnkStmtList) + var caseStmtPostBody = newNimNode(nnkStmtList) + var caseStmtPutBody = newNimNode(nnkStmtList) + var caseStmtDeleteBody = newNimNode(nnkStmtList) + var caseStmtHeadBody = newNimNode(nnkStmtList) + var caseStmtOptionsBody = newNimNode(nnkStmtList) + var caseStmtTraceBody = newNimNode(nnkStmtList) + var caseStmtConnectBody = newNimNode(nnkStmtList) + var caseStmtPatchBody = newNimNode(nnkStmtList) + + # Error handler nodes: + var httpCodeBranches: seq[tuple[cond, body: NimNode]] = @[] + var exceptionBranches: seq[tuple[cond, body: NimNode]] = @[] + + # Before/After nodes: + var beforeRoutes = newStmtList() + var afterRoutes = newStmtList() + + processRoutesBody( + body, + caseStmtGetBody, + caseStmtPostBody, + caseStmtPutBody, + caseStmtDeleteBody, + caseStmtHeadBody, + caseStmtOptionsBody, + caseStmtTraceBody, + caseStmtConnectBody, + caseStmtPatchBody, + httpCodeBranches, + exceptionBranches, + beforeRoutes, + afterRoutes, + outsideStmts, + "" + ) + + var ofBranchGet = newNimNode(nnkOfBranch) + ofBranchGet.add newIdentNode("HttpGet") + ofBranchGet.add caseStmtGetBody + caseStmt.add ofBranchGet + + var ofBranchPost = newNimNode(nnkOfBranch) + ofBranchPost.add newIdentNode("HttpPost") + ofBranchPost.add caseStmtPostBody + caseStmt.add ofBranchPost + + var ofBranchPut = newNimNode(nnkOfBranch) + ofBranchPut.add newIdentNode("HttpPut") + ofBranchPut.add caseStmtPutBody + caseStmt.add ofBranchPut + + var ofBranchDelete = newNimNode(nnkOfBranch) + ofBranchDelete.add newIdentNode("HttpDelete") + ofBranchDelete.add caseStmtDeleteBody + caseStmt.add ofBranchDelete + + var ofBranchHead = newNimNode(nnkOfBranch) + ofBranchHead.add newIdentNode("HttpHead") + ofBranchHead.add caseStmtHeadBody + caseStmt.add ofBranchHead + + var ofBranchOptions = newNimNode(nnkOfBranch) + ofBranchOptions.add newIdentNode("HttpOptions") + ofBranchOptions.add caseStmtOptionsBody + caseStmt.add ofBranchOptions + + var ofBranchTrace = newNimNode(nnkOfBranch) + ofBranchTrace.add newIdentNode("HttpTrace") + ofBranchTrace.add caseStmtTraceBody + caseStmt.add ofBranchTrace + + var ofBranchConnect = newNimNode(nnkOfBranch) + ofBranchConnect.add newIdentNode("HttpConnect") + ofBranchConnect.add caseStmtConnectBody + caseStmt.add ofBranchConnect + + var ofBranchPatch = newNimNode(nnkOfBranch) + ofBranchPatch.add newIdentNode("HttpPatch") + ofBranchPatch.add caseStmtPatchBody + caseStmt.add ofBranchPatch + + # Wrap the routes inside ``routesList`` blocks accordingly, and add them to + # the `match` procedure body. + let routesListIdent = newIdentNode("routesList") + matchBody.add( + quote do: + block `routesListIdent`: + `beforeRoutes` + ) + + matchBody.add( + quote do: + block `routesListIdent`: + `caseStmt` + ) + + matchBody.add( + quote do: + block `routesListIdent`: + `afterRoutes` + ) + + let matchIdent = newIdentNode(name) + let reqIdent = newIdentNode("request") + let needsAsync = needsAsync(body) + case needsAsync + of ImplicitFalse, ExplicitFalse: + hint(fmt"Synchronous route `{name}` has been optimised. Use `{{.async.}}` to change.") + of ImplicitTrue, ExplicitTrue: + hint(fmt"Asynchronous route: {name}.") + var matchProc = + if needsAsync in {ImplicitTrue, ExplicitTrue}: + quote do: + proc `matchIdent`( + `reqIdent`: Request + ): Future[ResponseData] {.async, gcsafe.} = + discard + else: + quote do: + proc `matchIdent`( + `reqIdent`: Request + ): ResponseData {.gcsafe.} = + discard + + # The following `block` is for `halt`. (`return` didn't work :/) + let allRoutesBlock = newTree( + nnkBlockStmt, + newIdentNode("allRoutes"), + matchBody + ) + matchProc[6] = newTree(nnkStmtList, allRoutesBlock) + result.add(outsideStmts) + result.add(matchProc) + + # Error handler proc + let errorHandlerIdent = newIdentNode(name & "ErrorHandler") + let errorIdent = newIdentNode("error") + let exceptionIdent = newIdentNode("exception") + let resultIdent = newIdentNode("result") + var errorHandlerProc = quote do: + proc `errorHandlerIdent`( + `reqIdent`: Request, `errorIdent`: RouteError + ): Future[ResponseData] {.gcsafe, async.} = + block `routesListIdent`: + `setDefaultRespIdent`() + case `errorIdent`.kind + of RouteException: + discard + of RouteCode: + discard + if exceptionBranches.len != 0: + var stmts = newStmtList() + for branch in exceptionBranches: + stmts.add(newIfStmt(branch)) + errorHandlerProc[6][0][1][^1][1][1][0] = stmts + if httpCodeBranches.len > 1: + var stmts = newStmtList() + for branch in httpCodeBranches: + stmts.add(newIfStmt(branch)) + errorHandlerProc[6][0][1][^1][2][1][0] = stmts + result.add(errorHandlerProc) + + # TODO: Replace `body`, `headers`, `code` in routes with `result[i]` to + # get these shortcuts back without sacrificing usability. + # TODO2: Make sure you replace what `guessAction` used to do for this. + + # echo toStrLit(result) + # echo treeRepr(result) + +macro routes*(body: untyped): typed = + result = routesEx("match", body) + let jesIdent = genSym(nskVar, "jes") + let matchIdent = newIdentNode("match") + let errorHandlerIdent = newIdentNode("matchErrorHandler") + let settingsIdent = newIdentNode("settings") + result.add( + quote do: + var `jesIdent` = initJester(`matchIdent`, `settingsIdent`) + `jesIdent`.register(`errorHandlerIdent`) + ) + result.add( + quote do: + serve(`jesIdent`) + ) + +macro router*(name: untyped, body: untyped): typed = + if name.kind != nnkIdent: + error("Need an ident.", name) + + routesEx($name.ident, body) + +macro settings*(body: untyped): typed = + #echo(treeRepr(body)) + expectKind(body, nnkStmtList) + + result = newStmtList() + + # var settings = newSettings() + let settingsIdent = newIdentNode("settings") + result.add newVarStmt(settingsIdent, newCall("newSettings")) + + for asgn in body.children: + expectKind(asgn, nnkAsgn) + result.add newAssignment(newDotExpr(settingsIdent, asgn[0]), asgn[1]) diff --git a/tests/deps/jester-#head/jester.nimble b/tests/deps/jester-#head/jester.nimble new file mode 100644 index 000000000..08e990bd7 --- /dev/null +++ b/tests/deps/jester-#head/jester.nimble @@ -0,0 +1,22 @@ +# Package + +version = "0.4.0" # Be sure to update jester.jesterVer too! +author = "Dominik Picheta" +description = "A sinatra-like web framework for Nim." +license = "MIT" + +skipFiles = @["todo.markdown"] +skipDirs = @["tests"] + +# Deps + +requires "nim >= 0.18.1" + +when not defined(windows): + requires "httpbeast >= 0.2.0" + +# For tests +requires "asynctools" + +task test, "Runs the test suite.": + exec "nimble c -y -r tests/tester" \ No newline at end of file diff --git a/tests/deps/jester-#head/jester/patterns.nim b/tests/deps/jester-#head/jester/patterns.nim new file mode 100644 index 000000000..c827fbc7f --- /dev/null +++ b/tests/deps/jester-#head/jester/patterns.nim @@ -0,0 +1,141 @@ +# Copyright (C) 2012-2018 Dominik Picheta +# MIT License - Look at license.txt for details. +import parseutils, tables +type + NodeType* = enum + NodeText, NodeField + Node* = object + typ*: NodeType + text*: string + optional*: bool + + Pattern* = seq[Node] + +#/show/@id/? +proc parsePattern*(pattern: string): Pattern = + result = @[] + template addNode(result: var Pattern, theT: NodeType, theText: string, + isOptional: bool): typed = + block: + var newNode: Node + newNode.typ = theT + newNode.text = theText + newNode.optional = isOptional + result.add(newNode) + + template `{}`(s: string, i: int): char = + if i >= len(s): + '\0' + else: + s[i] + + var i = 0 + var text = "" + while i < pattern.len(): + case pattern[i] + of '@': + # Add the stored text. + if text != "": + result.addNode(NodeText, text, false) + text = "" + # Parse named parameter. + inc(i) # Skip @ + var nparam = "" + i += pattern.parseUntil(nparam, {'/', '?'}, i) + var optional = pattern{i} == '?' + result.addNode(NodeField, nparam, optional) + if pattern{i} == '?': inc(i) # Only skip ?. / should not be skipped. + of '?': + var optionalChar = text[^1] + setLen(text, text.len-1) # Truncate ``text``. + # Add the stored text. + if text != "": + result.addNode(NodeText, text, false) + text = "" + # Add optional char. + inc(i) # Skip ? + result.addNode(NodeText, $optionalChar, true) + of '\\': + inc i # Skip \ + if pattern[i] notin {'?', '@', '\\'}: + raise newException(ValueError, + "This character does not require escaping: " & pattern[i]) + text.add(pattern{i}) + inc i # Skip ``pattern[i]`` + else: + text.add(pattern{i}) + inc(i) + + if text != "": + result.addNode(NodeText, text, false) + +proc findNextText(pattern: Pattern, i: int, toNode: var Node): bool = + ## Finds the next NodeText in the pattern, starts looking from ``i``. + result = false + for n in i..pattern.len()-1: + if pattern[n].typ == NodeText: + toNode = pattern[n] + return true + +proc check(n: Node, s: string, i: int): bool = + let cutTo = (n.text.len-1)+i + if cutTo > s.len-1: return false + return s.substr(i, cutTo) == n.text + +proc match*(pattern: Pattern, s: string): + tuple[matched: bool, params: Table[string, string]] = + var i = 0 # Location in ``s``. + + result.matched = true + result.params = initTable[string, string]() + + for ncount, node in pattern: + case node.typ + of NodeText: + if node.optional: + if check(node, s, i): + inc(i, node.text.len) # Skip over this optional character. + else: + # If it's not there, we have nothing to do. It's optional after all. + discard + else: + if check(node, s, i): + inc(i, node.text.len) # Skip over this + else: + # No match. + result.matched = false + return + of NodeField: + var nextTxtNode: Node + var stopChar = '/' + if findNextText(pattern, ncount, nextTxtNode): + stopChar = nextTxtNode.text[0] + var matchNamed = "" + i += s.parseUntil(matchNamed, stopChar, i) + result.params[node.text] = matchNamed + if matchNamed == "" and not node.optional: + result.matched = false + return + + if s.len != i: + result.matched = false + +when true: + let f = parsePattern("/show/@id/test/@show?/?") + doAssert match(f, "/show/12/test/hallo/").matched + doAssert match(f, "/show/2131726/test/jjjuuwąąss").matched + doAssert(not match(f, "/").matched) + doAssert(not match(f, "/show//test//").matched) + doAssert(match(f, "/show/asd/test//").matched) + doAssert(not match(f, "/show/asd/asd/test/jjj/").matched) + doAssert(match(f, "/show/@łę¶ŧ←/test/asd/").params["id"] == "@łę¶ŧ←") + + let f2 = parsePattern("/test42/somefile.?@ext?/?") + doAssert(match(f2, "/test42/somefile/").params["ext"] == "") + doAssert(match(f2, "/test42/somefile.txt").params["ext"] == "txt") + doAssert(match(f2, "/test42/somefile.txt/").params["ext"] == "txt") + + let f3 = parsePattern(r"/test32/\@\\\??") + doAssert(match(f3, r"/test32/@\").matched) + doAssert(not match(f3, r"/test32/@\\").matched) + doAssert(match(f3, r"/test32/@\?").matched) diff --git a/tests/deps/jester-#head/jester/private/errorpages.nim b/tests/deps/jester-#head/jester/private/errorpages.nim new file mode 100644 index 000000000..d1e695040 --- /dev/null +++ b/tests/deps/jester-#head/jester/private/errorpages.nim @@ -0,0 +1,19 @@ +# Copyright (C) 2012 Dominik Picheta +# MIT License - Look at license.txt for details. +import htmlgen +proc error*(err, jesterVer: string): string = + return html(head(title(err)), + body(h1(err), + "
      ", + p("Jester " & jesterVer), + style = "text-align: center;" + ), + xmlns="http://www.w3.org/1999/xhtml") + +proc routeException*(error: string, jesterVer: string): string = + return html(head(title("Jester route exception")), + body( + h1("An error has occured in one of your routes."), + p(b("Detail: "), error) + ), + xmlns="http://www.w3.org/1999/xhtml") diff --git a/tests/deps/jester-#head/jester/private/utils.nim b/tests/deps/jester-#head/jester/private/utils.nim new file mode 100644 index 000000000..16dce61fe --- /dev/null +++ b/tests/deps/jester-#head/jester/private/utils.nim @@ -0,0 +1,195 @@ +# Copyright (C) 2012 Dominik Picheta +# MIT License - Look at license.txt for details. +import parseutils, strtabs, strutils, tables, net, mimetypes, asyncdispatch, os +from cgi import decodeUrl + +const + useHttpBeast* = false # not defined(windows) and not defined(useStdLib) + +type + MultiData* = OrderedTable[string, tuple[fields: StringTableRef, body: string]] + + Settings* = ref object + staticDir*: string # By default ./public + appName*: string + mimes*: MimeDb + port*: Port + bindAddr*: string + reusePort*: bool + futureErrorHandler*: proc (fut: Future[void]) {.closure, gcsafe.} + + JesterError* = object of Exception + +proc parseUrlQuery*(query: string, result: var Table[string, string]) + {.deprecated: "use stdlib".} = + var i = 0 + i = query.skip("?") + while i < query.len()-1: + var key = "" + var val = "" + i += query.parseUntil(key, '=', i) + if query[i] != '=': + raise newException(ValueError, "Expected '=' at " & $i & + " but got: " & $query[i]) + inc(i) # Skip = + i += query.parseUntil(val, '&', i) + inc(i) # Skip & + result[decodeUrl(key)] = decodeUrl(val) + +template parseContentDisposition(): typed = + var hCount = 0 + while hCount < hValue.len()-1: + var key = "" + hCount += hValue.parseUntil(key, {';', '='}, hCount) + if hValue[hCount] == '=': + var value = hvalue.captureBetween('"', start = hCount) + hCount += value.len+2 + inc(hCount) # Skip ; + hCount += hValue.skipWhitespace(hCount) + if key == "name": name = value + newPart[0][key] = value + else: + inc(hCount) + hCount += hValue.skipWhitespace(hCount) + +proc parseMultiPart*(body: string, boundary: string): MultiData = + result = initOrderedTable[string, tuple[fields: StringTableRef, body: string]]() + var mboundary = "--" & boundary + + var i = 0 + var partsLeft = true + while partsLeft: + var firstBoundary = body.skip(mboundary, i) + if firstBoundary == 0: + raise newException(ValueError, "Expected boundary. Got: " & body.substr(i, i+25)) + i += firstBoundary + i += body.skipWhitespace(i) + + # Headers + var newPart: tuple[fields: StringTableRef, body: string] = ({:}.newStringTable, "") + var name = "" + while true: + if body[i] == '\c': + inc(i, 2) # Skip \c\L + break + var hName = "" + i += body.parseUntil(hName, ':', i) + if body[i] != ':': + raise newException(ValueError, "Expected : in headers.") + inc(i) # Skip : + i += body.skipWhitespace(i) + var hValue = "" + i += body.parseUntil(hValue, {'\c', '\L'}, i) + if toLowerAscii(hName) == "content-disposition": + parseContentDisposition() + newPart[0][hName] = hValue + i += body.skip("\c\L", i) # Skip *one* \c\L + + # Parse body. + while true: + if body[i] == '\c' and body[i+1] == '\L' and + body.skip(mboundary, i+2) != 0: + if body.skip("--", i+2+mboundary.len) != 0: + partsLeft = false + break + break + else: + newPart[1].add(body[i]) + inc(i) + i += body.skipWhitespace(i) + + result.add(name, newPart) + +proc parseMPFD*(contentType: string, body: string): MultiData = + var boundaryEqIndex = contentType.find("boundary=")+9 + var boundary = contentType.substr(boundaryEqIndex, contentType.len()-1) + return parseMultiPart(body, boundary) + +proc parseCookies*(s: string): Table[string, string] = + ## parses cookies into a string table. + ## + ## The proc is meant to parse the Cookie header set by a client, not the + ## "Set-Cookie" header set by servers. + + result = initTable[string, string]() + var i = 0 + while true: + i += skipWhile(s, {' ', '\t'}, i) + var keystart = i + i += skipUntil(s, {'='}, i) + var keyend = i-1 + if i >= len(s): break + inc(i) # skip '=' + var valstart = i + i += skipUntil(s, {';'}, i) + result[substr(s, keystart, keyend)] = substr(s, valstart, i-1) + if i >= len(s): break + inc(i) # skip ';' + +type + SameSite* = enum + None, Lax, Strict + +proc makeCookie*(key, value, expires: string, domain = "", path = "", + secure = false, httpOnly = false, + sameSite = Lax): string = + result = "" + result.add key & "=" & value + if domain != "": result.add("; Domain=" & domain) + if path != "": result.add("; Path=" & path) + if expires != "": result.add("; Expires=" & expires) + if secure: result.add("; Secure") + if httpOnly: result.add("; HttpOnly") + if sameSite != None: + result.add("; SameSite=" & $sameSite) + +when not declared(tables.getOrDefault): + template getOrDefault*(tab, key): untyped = tab[key] + +when not declared(normalizePath) and not declared(normalizedPath): + proc normalizePath*(path: var string) = + ## Normalize a path. + ## + ## Consecutive directory separators are collapsed, including an initial double slash. + ## + ## On relative paths, double dot (..) sequences are collapsed if possible. + ## On absolute paths they are always collapsed. + ## + ## Warning: URL-encoded and Unicode attempts at directory traversal are not detected. + ## Triple dot is not handled. + let isAbs = isAbsolute(path) + var stack: seq[string] = @[] + for p in split(path, {DirSep}): + case p + of "", ".": + continue + of "..": + if stack.len == 0: + if isAbs: + discard # collapse all double dots on absoluta paths + else: + stack.add(p) + elif stack[^1] == "..": + stack.add(p) + else: + discard stack.pop() + else: + stack.add(p) + + if isAbs: + path = DirSep & join(stack, $DirSep) + elif stack.len > 0: + path = join(stack, $DirSep) + else: + path = "." + + proc normalizedPath*(path: string): string = + ## Returns a normalized path for the current OS. See `<#normalizePath>`_ + result = path + normalizePath(result) + +when false: + var r = {:}.newStringTable + parseUrlQuery("FirstName=Mickey", r) + echo r + diff --git a/tests/deps/jester-#head/jester/request.nim b/tests/deps/jester-#head/jester/request.nim new file mode 100644 index 000000000..1b837d728 --- /dev/null +++ b/tests/deps/jester-#head/jester/request.nim @@ -0,0 +1,184 @@ +import uri, cgi, tables, logging, strutils, re, options + +import jester/private/utils + +when useHttpBeast: + import httpbeast except Settings + import options, httpcore + + type + NativeRequest* = httpbeast.Request +else: + import asynchttpserver + + type + NativeRequest* = asynchttpserver.Request + +type + Request* = object + req: NativeRequest + patternParams: Option[Table[string, string]] + reMatches: array[MaxSubpatterns, string] + settings*: Settings + +proc body*(req: Request): string = + ## Body of the request, only for POST. + ## + ## You're probably looking for ``formData`` + ## instead. + when useHttpBeast: + req.req.body.get("") + else: + req.req.body + +proc headers*(req: Request): HttpHeaders = + ## Headers received with the request. + ## Retrieving these is case insensitive. + when useHttpBeast: + if req.req.headers.isNone: + newHttpHeaders() + else: + req.req.headers.get() + else: + req.req.headers + +proc path*(req: Request): string = + ## Path of request without the query string. + when useHttpBeast: + let p = req.req.path.get("") + let queryStart = p.find('?') + if unlikely(queryStart != -1): + return p[0 .. queryStart-1] + else: + return p + else: + let u = req.req.url + return u.path + +proc reqMethod*(req: Request): HttpMethod = + ## Request method, eg. HttpGet, HttpPost + when useHttpBeast: + req.req.httpMethod.get() + else: + req.req.reqMethod +proc reqMeth*(req: Request): HttpMethod {.deprecated.} = + req.reqMethod + +proc ip*(req: Request): string = + ## IP address of the requesting client. + when useHttpBeast: + result = req.req.ip + else: + result = req.req.hostname + + let headers = req.headers + if headers.hasKey("REMOTE_ADDR"): + result = headers["REMOTE_ADDR"] + if headers.hasKey("x-forwarded-for"): + result = headers["x-forwarded-for"] + +proc params*(req: Request): Table[string, string] = + ## Parameters from the pattern and the query string. + if req.patternParams.isSome(): + result = req.patternParams.get() + else: + result = initTable[string, string]() + + when useHttpBeast: + let query = req.req.path.get("").parseUri().query + else: + let query = req.req.url.query + + try: + for key, val in cgi.decodeData(query): + result[key] = val + except CgiError: + logging.warn("Incorrect query. Got: $1" % [query]) + + let contentType = req.headers.getOrDefault("Content-Type") + if contentType.startswith("application/x-www-form-urlencoded"): + try: + parseUrlQuery(req.body, result) + except: + logging.warn("Could not parse URL query.") + +proc formData*(req: Request): MultiData = + let contentType = req.headers.getOrDefault("Content-Type") + if contentType.startsWith("multipart/form-data"): + result = parseMPFD(contentType, req.body) + +proc matches*(req: Request): array[MaxSubpatterns, string] = + req.reMatches + +proc secure*(req: Request): bool = + if req.headers.hasKey("x-forwarded-proto"): + let proto = req.headers["x-forwarded-proto"] + case proto.toLowerAscii() + of "https": + result = true + of "http": + result = false + else: + logging.warn("Unknown x-forwarded-proto ", proto) + +proc port*(req: Request): int = + if (let p = req.headers.getOrDefault("SERVER_PORT"); p != ""): + result = p.parseInt + else: + result = if req.secure: 443 else: 80 + +proc host*(req: Request): string = + req.headers.getOrDefault("HOST") + +proc appName*(req: Request): string = + ## This is set by the user in ``run``, it is + ## overriden by the "SCRIPT_NAME" scgi + ## parameter. + req.settings.appName + +proc stripAppName(path, appName: string): string = + result = path + if appname.len > 0: + var slashAppName = appName + if slashAppName[0] != '/' and path[0] == '/': + slashAppName = '/' & slashAppName + + if path.startsWith(slashAppName): + if slashAppName.len() == path.len: + return "/" + else: + return path[slashAppName.len .. path.len-1] + else: + raise newException(ValueError, + "Expected script name at beginning of path. Got path: " & + path & " script name: " & slashAppName) + +proc pathInfo*(req: Request): string = + ## This is ``.path`` without ``.appName``. + req.path.stripAppName(req.appName) + +# TODO: Can cookie keys be duplicated? +proc cookies*(req: Request): Table[string, string] = + ## Cookies from the browser. + if (let cookie = req.headers.getOrDefault("Cookie"); cookie != ""): + result = parseCookies(cookie) + else: + result = initTable[string, string]() + +#[ Protected procs ]# + +proc initRequest*(req: NativeRequest, settings: Settings): Request {.inline.} = + Request( + req: req, + settings: settings + ) + +proc getNativeReq*(req: Request): NativeRequest = + req.req + +#[ Only to be used by our route macro. ]# +proc setPatternParams*(req: var Request, p: Table[string, string]) = + req.patternParams = some(p) + +proc setReMatches*(req: var Request, r: array[MaxSubpatterns, string]) = + req.reMatches = r diff --git a/tests/deps/opengl-1.1.0/glu.nim b/tests/deps/opengl-1.1.0/glu.nim new file mode 100644 index 000000000..5594ef915 --- /dev/null +++ b/tests/deps/opengl-1.1.0/glu.nim @@ -0,0 +1,326 @@ +# +# +# Adaption of the delphi3d.net OpenGL units to FreePascal +# Sebastian Guenther (sg@freepascal.org) in 2002 +# These units are free to use +#****************************************************************************** +# Converted to Delphi by Tom Nuydens (tom@delphi3d.net) +# For the latest updates, visit Delphi3D: http://www.delphi3d.net +#****************************************************************************** + +import opengl + +{.deadCodeElim: on.} + +when defined(windows): + {.push, callconv: stdcall.} +else: + {.push, callconv: cdecl.} + +when defined(windows): + const + dllname = "glu32.dll" +elif defined(macosx): + const + dllname = "/System/Library/Frameworks/OpenGL.framework/Libraries/libGLU.dylib" +else: + const + dllname = "libGLU.so.1" + +type + ViewPortArray* = array[0..3, GLint] + T16dArray* = array[0..15, GLdouble] + CallBack* = proc () {.cdecl.} + T3dArray* = array[0..2, GLdouble] + T4pArray* = array[0..3, pointer] + T4fArray* = array[0..3, GLfloat] + +{.deprecated: [ + TViewPortArray: ViewPortArray, + TCallBack: CallBack, +].} + +type + GLUnurbs*{.final.} = ptr object + GLUquadric*{.final.} = ptr object + GLUtesselator*{.final.} = ptr object + GLUnurbsObj* = GLUnurbs + GLUquadricObj* = GLUquadric + GLUtesselatorObj* = GLUtesselator + GLUtriangulatorObj* = GLUtesselator + +proc gluErrorString*(errCode: GLenum): cstring{.dynlib: dllname, + importc: "gluErrorString".} +when defined(Windows): + proc gluErrorUnicodeStringEXT*(errCode: GLenum): ptr int16{.dynlib: dllname, + importc: "gluErrorUnicodeStringEXT".} +proc gluGetString*(name: GLenum): cstring{.dynlib: dllname, + importc: "gluGetString".} +proc gluOrtho2D*(left, right, bottom, top: GLdouble){.dynlib: dllname, + importc: "gluOrtho2D".} +proc gluPerspective*(fovy, aspect, zNear, zFar: GLdouble){.dynlib: dllname, + importc: "gluPerspective".} +proc gluPickMatrix*(x, y, width, height: GLdouble, viewport: var ViewPortArray){. + dynlib: dllname, importc: "gluPickMatrix".} +proc gluLookAt*(eyex, eyey, eyez, centerx, centery, centerz, upx, upy, upz: GLdouble){. + dynlib: dllname, importc: "gluLookAt".} +proc gluProject*(objx, objy, objz: GLdouble, + modelMatrix, projMatrix: var T16dArray, + viewport: var ViewPortArray, winx, winy, winz: ptr GLdouble): int{. + dynlib: dllname, importc: "gluProject".} +proc gluUnProject*(winx, winy, winz: GLdouble, + modelMatrix, projMatrix: var T16dArray, + viewport: var ViewPortArray, objx, objy, objz: ptr GLdouble): int{. + dynlib: dllname, importc: "gluUnProject".} +proc gluScaleImage*(format: GLenum, widthin, heightin: GLint, typein: GLenum, + datain: pointer, widthout, heightout: GLint, + typeout: GLenum, dataout: pointer): int{.dynlib: dllname, + importc: "gluScaleImage".} +proc gluBuild1DMipmaps*(target: GLenum, components, width: GLint, + format, atype: GLenum, data: pointer): int{. + dynlib: dllname, importc: "gluBuild1DMipmaps".} +proc gluBuild2DMipmaps*(target: GLenum, components, width, height: GLint, + format, atype: GLenum, data: pointer): int{. + dynlib: dllname, importc: "gluBuild2DMipmaps".} +proc gluNewQuadric*(): GLUquadric{.dynlib: dllname, importc: "gluNewQuadric".} +proc gluDeleteQuadric*(state: GLUquadric){.dynlib: dllname, + importc: "gluDeleteQuadric".} +proc gluQuadricNormals*(quadObject: GLUquadric, normals: GLenum){. + dynlib: dllname, importc: "gluQuadricNormals".} +proc gluQuadricTexture*(quadObject: GLUquadric, textureCoords: GLboolean){. + dynlib: dllname, importc: "gluQuadricTexture".} +proc gluQuadricOrientation*(quadObject: GLUquadric, orientation: GLenum){. + dynlib: dllname, importc: "gluQuadricOrientation".} +proc gluQuadricDrawStyle*(quadObject: GLUquadric, drawStyle: GLenum){. + dynlib: dllname, importc: "gluQuadricDrawStyle".} +proc gluCylinder*(qobj: GLUquadric, baseRadius, topRadius, height: GLdouble, + slices, stacks: GLint){.dynlib: dllname, + importc: "gluCylinder".} +proc gluDisk*(qobj: GLUquadric, innerRadius, outerRadius: GLdouble, + slices, loops: GLint){.dynlib: dllname, importc: "gluDisk".} +proc gluPartialDisk*(qobj: GLUquadric, innerRadius, outerRadius: GLdouble, + slices, loops: GLint, startAngle, sweepAngle: GLdouble){. + dynlib: dllname, importc: "gluPartialDisk".} +proc gluSphere*(qobj: GLuquadric, radius: GLdouble, slices, stacks: GLint){. + dynlib: dllname, importc: "gluSphere".} +proc gluQuadricCallback*(qobj: GLUquadric, which: GLenum, fn: CallBack){. + dynlib: dllname, importc: "gluQuadricCallback".} +proc gluNewTess*(): GLUtesselator{.dynlib: dllname, importc: "gluNewTess".} +proc gluDeleteTess*(tess: GLUtesselator){.dynlib: dllname, + importc: "gluDeleteTess".} +proc gluTessBeginPolygon*(tess: GLUtesselator, polygon_data: pointer){. + dynlib: dllname, importc: "gluTessBeginPolygon".} +proc gluTessBeginContour*(tess: GLUtesselator){.dynlib: dllname, + importc: "gluTessBeginContour".} +proc gluTessVertex*(tess: GLUtesselator, coords: var T3dArray, data: pointer){. + dynlib: dllname, importc: "gluTessVertex".} +proc gluTessEndContour*(tess: GLUtesselator){.dynlib: dllname, + importc: "gluTessEndContour".} +proc gluTessEndPolygon*(tess: GLUtesselator){.dynlib: dllname, + importc: "gluTessEndPolygon".} +proc gluTessProperty*(tess: GLUtesselator, which: GLenum, value: GLdouble){. + dynlib: dllname, importc: "gluTessProperty".} +proc gluTessNormal*(tess: GLUtesselator, x, y, z: GLdouble){.dynlib: dllname, + importc: "gluTessNormal".} +proc gluTessCallback*(tess: GLUtesselator, which: GLenum, fn: CallBack){. + dynlib: dllname, importc: "gluTessCallback".} +proc gluGetTessProperty*(tess: GLUtesselator, which: GLenum, value: ptr GLdouble){. + dynlib: dllname, importc: "gluGetTessProperty".} +proc gluNewNurbsRenderer*(): GLUnurbs{.dynlib: dllname, + importc: "gluNewNurbsRenderer".} +proc gluDeleteNurbsRenderer*(nobj: GLUnurbs){.dynlib: dllname, + importc: "gluDeleteNurbsRenderer".} +proc gluBeginSurface*(nobj: GLUnurbs){.dynlib: dllname, + importc: "gluBeginSurface".} +proc gluBeginCurve*(nobj: GLUnurbs){.dynlib: dllname, importc: "gluBeginCurve".} +proc gluEndCurve*(nobj: GLUnurbs){.dynlib: dllname, importc: "gluEndCurve".} +proc gluEndSurface*(nobj: GLUnurbs){.dynlib: dllname, importc: "gluEndSurface".} +proc gluBeginTrim*(nobj: GLUnurbs){.dynlib: dllname, importc: "gluBeginTrim".} +proc gluEndTrim*(nobj: GLUnurbs){.dynlib: dllname, importc: "gluEndTrim".} +proc gluPwlCurve*(nobj: GLUnurbs, count: GLint, aarray: ptr GLfloat, + stride: GLint, atype: GLenum){.dynlib: dllname, + importc: "gluPwlCurve".} +proc gluNurbsCurve*(nobj: GLUnurbs, nknots: GLint, knot: ptr GLfloat, + stride: GLint, ctlarray: ptr GLfloat, order: GLint, + atype: GLenum){.dynlib: dllname, importc: "gluNurbsCurve".} +proc gluNurbsSurface*(nobj: GLUnurbs, sknot_count: GLint, sknot: ptr GLfloat, + tknot_count: GLint, tknot: ptr GLfloat, + s_stride, t_stride: GLint, ctlarray: ptr GLfloat, + sorder, torder: GLint, atype: GLenum){.dynlib: dllname, + importc: "gluNurbsSurface".} +proc gluLoadSamplingMatrices*(nobj: GLUnurbs, + modelMatrix, projMatrix: var T16dArray, + viewport: var ViewPortArray){.dynlib: dllname, + importc: "gluLoadSamplingMatrices".} +proc gluNurbsProperty*(nobj: GLUnurbs, aproperty: GLenum, value: GLfloat){. + dynlib: dllname, importc: "gluNurbsProperty".} +proc gluGetNurbsProperty*(nobj: GLUnurbs, aproperty: GLenum, value: ptr GLfloat){. + dynlib: dllname, importc: "gluGetNurbsProperty".} +proc gluNurbsCallback*(nobj: GLUnurbs, which: GLenum, fn: CallBack){. + dynlib: dllname, importc: "gluNurbsCallback".} + #*** Callback function prototypes *** +type # gluQuadricCallback + GLUquadricErrorProc* = proc (p: GLenum) # gluTessCallback + GLUtessBeginProc* = proc (p: GLenum) + GLUtessEdgeFlagProc* = proc (p: GLboolean) + GLUtessVertexProc* = proc (p: pointer) + GLUtessEndProc* = proc () + GLUtessErrorProc* = proc (p: GLenum) + GLUtessCombineProc* = proc (p1: var T3dArray, p2: T4pArray, p3: T4fArray, + p4: ptr pointer) + GLUtessBeginDataProc* = proc (p1: GLenum, p2: pointer) + GLUtessEdgeFlagDataProc* = proc (p1: GLboolean, p2: pointer) + GLUtessVertexDataProc* = proc (p1, p2: pointer) + GLUtessEndDataProc* = proc (p: pointer) + GLUtessErrorDataProc* = proc (p1: GLenum, p2: pointer) + GLUtessCombineDataProc* = proc (p1: var T3dArray, p2: var T4pArray, + p3: var T4fArray, p4: ptr pointer, p5: pointer) # + GLUnurbsErrorProc* = proc (p: GLenum) #*** Generic constants ****/ + +const # Version + GLU_VERSION_1_1* = 1 + GLU_VERSION_1_2* = 1 # Errors: (return value 0 = no error) + GLU_INVALID_ENUM* = 100900 + GLU_INVALID_VALUE* = 100901 + GLU_OUT_OF_MEMORY* = 100902 + GLU_INCOMPATIBLE_GL_VERSION* = 100903 # StringName + GLU_VERSION* = 100800 + GLU_EXTENSIONS* = 100801 # Boolean + GLU_TRUE* = GL_TRUE + GLU_FALSE* = GL_FALSE #*** Quadric constants ****/ + # QuadricNormal + GLU_SMOOTH* = 100000 + GLU_FLAT* = 100001 + GLU_NONE* = 100002 # QuadricDrawStyle + GLU_POINT* = 100010 + GLU_LINE* = 100011 + GLU_FILL* = 100012 + GLU_SILHOUETTE* = 100013 # QuadricOrientation + GLU_OUTSIDE* = 100020 + GLU_INSIDE* = 100021 # Callback types: + # GLU_ERROR = 100103; + #*** Tesselation constants ****/ + GLU_TESS_MAX_COORD* = 1.00000e+150 # TessProperty + GLU_TESS_WINDING_RULE* = 100140 + GLU_TESS_BOUNDARY_ONLY* = 100141 + GLU_TESS_TOLERANCE* = 100142 # TessWinding + GLU_TESS_WINDING_ODD* = 100130 + GLU_TESS_WINDING_NONZERO* = 100131 + GLU_TESS_WINDING_POSITIVE* = 100132 + GLU_TESS_WINDING_NEGATIVE* = 100133 + GLU_TESS_WINDING_ABS_GEQ_TWO* = 100134 # TessCallback + GLU_TESS_BEGIN* = 100100 # void (CALLBACK*)(GLenum type) + constGLU_TESS_VERTEX* = 100101 # void (CALLBACK*)(void *data) + GLU_TESS_END* = 100102 # void (CALLBACK*)(void) + GLU_TESS_ERROR* = 100103 # void (CALLBACK*)(GLenum errno) + GLU_TESS_EDGE_FLAG* = 100104 # void (CALLBACK*)(GLboolean boundaryEdge) + GLU_TESS_COMBINE* = 100105 # void (CALLBACK*)(GLdouble coords[3], + # void *data[4], + # GLfloat weight[4], + # void **dataOut) + GLU_TESS_BEGIN_DATA* = 100106 # void (CALLBACK*)(GLenum type, + # void *polygon_data) + GLU_TESS_VERTEX_DATA* = 100107 # void (CALLBACK*)(void *data, + # void *polygon_data) + GLU_TESS_END_DATA* = 100108 # void (CALLBACK*)(void *polygon_data) + GLU_TESS_ERROR_DATA* = 100109 # void (CALLBACK*)(GLenum errno, + # void *polygon_data) + GLU_TESS_EDGE_FLAG_DATA* = 100110 # void (CALLBACK*)(GLboolean boundaryEdge, + # void *polygon_data) + GLU_TESS_COMBINE_DATA* = 100111 # void (CALLBACK*)(GLdouble coords[3], + # void *data[4], + # GLfloat weight[4], + # void **dataOut, + # void *polygon_data) + # TessError + GLU_TESS_ERROR1* = 100151 + GLU_TESS_ERROR2* = 100152 + GLU_TESS_ERROR3* = 100153 + GLU_TESS_ERROR4* = 100154 + GLU_TESS_ERROR5* = 100155 + GLU_TESS_ERROR6* = 100156 + GLU_TESS_ERROR7* = 100157 + GLU_TESS_ERROR8* = 100158 + GLU_TESS_MISSING_BEGIN_POLYGON* = GLU_TESS_ERROR1 + GLU_TESS_MISSING_BEGIN_CONTOUR* = GLU_TESS_ERROR2 + GLU_TESS_MISSING_END_POLYGON* = GLU_TESS_ERROR3 + GLU_TESS_MISSING_END_CONTOUR* = GLU_TESS_ERROR4 + GLU_TESS_COORD_TOO_LARGE* = GLU_TESS_ERROR5 + GLU_TESS_NEED_COMBINE_CALLBACK* = GLU_TESS_ERROR6 #*** NURBS constants ****/ + # NurbsProperty + GLU_AUTO_LOAD_MATRIX* = 100200 + GLU_CULLING* = 100201 + GLU_SAMPLING_TOLERANCE* = 100203 + GLU_DISPLAY_MODE* = 100204 + GLU_PARAMETRIC_TOLERANCE* = 100202 + GLU_SAMPLING_METHOD* = 100205 + GLU_U_STEP* = 100206 + GLU_V_STEP* = 100207 # NurbsSampling + GLU_PATH_LENGTH* = 100215 + GLU_PARAMETRIC_ERROR* = 100216 + GLU_DOMAIN_DISTANCE* = 100217 # NurbsTrim + GLU_MAP1_TRIM_2* = 100210 + GLU_MAP1_TRIM_3* = 100211 # NurbsDisplay + # GLU_FILL = 100012; + GLU_OUTLINE_POLYGON* = 100240 + GLU_OUTLINE_PATCH* = 100241 # NurbsCallback + # GLU_ERROR = 100103; + # NurbsErrors + GLU_NURBS_ERROR1* = 100251 + GLU_NURBS_ERROR2* = 100252 + GLU_NURBS_ERROR3* = 100253 + GLU_NURBS_ERROR4* = 100254 + GLU_NURBS_ERROR5* = 100255 + GLU_NURBS_ERROR6* = 100256 + GLU_NURBS_ERROR7* = 100257 + GLU_NURBS_ERROR8* = 100258 + GLU_NURBS_ERROR9* = 100259 + GLU_NURBS_ERROR10* = 100260 + GLU_NURBS_ERROR11* = 100261 + GLU_NURBS_ERROR12* = 100262 + GLU_NURBS_ERROR13* = 100263 + GLU_NURBS_ERROR14* = 100264 + GLU_NURBS_ERROR15* = 100265 + GLU_NURBS_ERROR16* = 100266 + GLU_NURBS_ERROR17* = 100267 + GLU_NURBS_ERROR18* = 100268 + GLU_NURBS_ERROR19* = 100269 + GLU_NURBS_ERROR20* = 100270 + GLU_NURBS_ERROR21* = 100271 + GLU_NURBS_ERROR22* = 100272 + GLU_NURBS_ERROR23* = 100273 + GLU_NURBS_ERROR24* = 100274 + GLU_NURBS_ERROR25* = 100275 + GLU_NURBS_ERROR26* = 100276 + GLU_NURBS_ERROR27* = 100277 + GLU_NURBS_ERROR28* = 100278 + GLU_NURBS_ERROR29* = 100279 + GLU_NURBS_ERROR30* = 100280 + GLU_NURBS_ERROR31* = 100281 + GLU_NURBS_ERROR32* = 100282 + GLU_NURBS_ERROR33* = 100283 + GLU_NURBS_ERROR34* = 100284 + GLU_NURBS_ERROR35* = 100285 + GLU_NURBS_ERROR36* = 100286 + GLU_NURBS_ERROR37* = 100287 #*** Backwards compatibility for old tesselator ****/ + +proc gluBeginPolygon*(tess: GLUtesselator){.dynlib: dllname, + importc: "gluBeginPolygon".} +proc gluNextContour*(tess: GLUtesselator, atype: GLenum){.dynlib: dllname, + importc: "gluNextContour".} +proc gluEndPolygon*(tess: GLUtesselator){.dynlib: dllname, + importc: "gluEndPolygon".} +const # Contours types -- obsolete! + GLU_CW* = 100120 + GLU_CCW* = 100121 + GLU_INTERIOR* = 100122 + GLU_EXTERIOR* = 100123 + GLU_UNKNOWN* = 100124 # Names without "TESS_" prefix + GLU_BEGIN* = GLU_TESS_BEGIN + GLU_VERTEX* = constGLU_TESS_VERTEX + GLU_END* = GLU_TESS_END + GLU_ERROR* = GLU_TESS_ERROR + GLU_EDGE_FLAG* = GLU_TESS_EDGE_FLAG + +{.pop.} +# implementation diff --git a/tests/deps/opengl-1.1.0/glut.nim b/tests/deps/opengl-1.1.0/glut.nim new file mode 100644 index 000000000..55a5da0c7 --- /dev/null +++ b/tests/deps/opengl-1.1.0/glut.nim @@ -0,0 +1,366 @@ +# +# +# Adaption of the delphi3d.net OpenGL units to FreePascal +# Sebastian Guenther (sg@freepascal.org) in 2002 +# These units are free to use +# + +# Copyright (c) Mark J. Kilgard, 1994, 1995, 1996. +# This program is freely distributable without licensing fees and is +# provided without guarantee or warrantee expressed or implied. This +# program is -not- in the public domain. +#****************************************************************************** +# Converted to Delphi by Tom Nuydens (tom@delphi3d.net) +# Contributions by Igor Karpov (glygrik@hotbox.ru) +# For the latest updates, visit Delphi3D: http://www.delphi3d.net +#****************************************************************************** + +import opengl + +{.deadCodeElim: on.} + +when defined(windows): + const + dllname = "glut32.dll" +elif defined(macosx): + const + dllname = "/System/Library/Frameworks/GLUT.framework/GLUT" +else: + const + dllname = "libglut.so.3" +type + TGlutVoidCallback* = proc (){.cdecl.} + TGlut1IntCallback* = proc (value: cint){.cdecl.} + TGlut2IntCallback* = proc (v1, v2: cint){.cdecl.} + TGlut3IntCallback* = proc (v1, v2, v3: cint){.cdecl.} + TGlut4IntCallback* = proc (v1, v2, v3, v4: cint){.cdecl.} + TGlut1Char2IntCallback* = proc (c: int8, v1, v2: cint){.cdecl.} + TGlut1UInt3IntCallback* = proc (u, v1, v2, v3: cint){.cdecl.} + +{.deprecated: [Pointer: pointer].} + +const + GLUT_API_VERSION* = 3 + GLUT_XLIB_IMPLEMENTATION* = 12 # Display mode bit masks. + GLUT_RGB* = 0 + GLUT_RGBA* = GLUT_RGB + GLUT_INDEX* = 1 + GLUT_SINGLE* = 0 + GLUT_DOUBLE* = 2 + GLUT_ACCUM* = 4 + GLUT_ALPHA* = 8 + GLUT_DEPTH* = 16 + GLUT_STENCIL* = 32 + GLUT_MULTISAMPLE* = 128 + GLUT_STEREO* = 256 + GLUT_LUMINANCE* = 512 # Mouse buttons. + GLUT_LEFT_BUTTON* = 0 + GLUT_MIDDLE_BUTTON* = 1 + GLUT_RIGHT_BUTTON* = 2 # Mouse button state. + GLUT_DOWN* = 0 + GLUT_UP* = 1 # function keys + GLUT_KEY_F1* = 1 + GLUT_KEY_F2* = 2 + GLUT_KEY_F3* = 3 + GLUT_KEY_F4* = 4 + GLUT_KEY_F5* = 5 + GLUT_KEY_F6* = 6 + GLUT_KEY_F7* = 7 + GLUT_KEY_F8* = 8 + GLUT_KEY_F9* = 9 + GLUT_KEY_F10* = 10 + GLUT_KEY_F11* = 11 + GLUT_KEY_F12* = 12 # directional keys + GLUT_KEY_LEFT* = 100 + GLUT_KEY_UP* = 101 + GLUT_KEY_RIGHT* = 102 + GLUT_KEY_DOWN* = 103 + GLUT_KEY_PAGE_UP* = 104 + GLUT_KEY_PAGE_DOWN* = 105 + GLUT_KEY_HOME* = 106 + GLUT_KEY_END* = 107 + GLUT_KEY_INSERT* = 108 # Entry/exit state. + GLUT_LEFT* = 0 + GLUT_ENTERED* = 1 # Menu usage state. + GLUT_MENU_NOT_IN_USE* = 0 + GLUT_MENU_IN_USE* = 1 # Visibility state. + GLUT_NOT_VISIBLE* = 0 + GLUT_VISIBLE* = 1 # Window status state. + GLUT_HIDDEN* = 0 + GLUT_FULLY_RETAINED* = 1 + GLUT_PARTIALLY_RETAINED* = 2 + GLUT_FULLY_COVERED* = 3 # Color index component selection values. + GLUT_RED* = 0 + GLUT_GREEN* = 1 + GLUT_BLUE* = 2 # Layers for use. + GLUT_NORMAL* = 0 + GLUT_OVERLAY* = 1 + +when defined(Windows): + const # Stroke font constants (use these in GLUT program). + GLUT_STROKE_ROMAN* = cast[pointer](0) + GLUT_STROKE_MONO_ROMAN* = cast[pointer](1) # Bitmap font constants (use these in GLUT program). + GLUT_BITMAP_9_BY_15* = cast[pointer](2) + GLUT_BITMAP_8_BY_13* = cast[pointer](3) + GLUT_BITMAP_TIMES_ROMAN_10* = cast[pointer](4) + GLUT_BITMAP_TIMES_ROMAN_24* = cast[pointer](5) + GLUT_BITMAP_HELVETICA_10* = cast[pointer](6) + GLUT_BITMAP_HELVETICA_12* = cast[pointer](7) + GLUT_BITMAP_HELVETICA_18* = cast[pointer](8) +else: + var # Stroke font constants (use these in GLUT program). + GLUT_STROKE_ROMAN*: pointer + GLUT_STROKE_MONO_ROMAN*: pointer # Bitmap font constants (use these in GLUT program). + GLUT_BITMAP_9_BY_15*: pointer + GLUT_BITMAP_8_BY_13*: pointer + GLUT_BITMAP_TIMES_ROMAN_10*: pointer + GLUT_BITMAP_TIMES_ROMAN_24*: pointer + GLUT_BITMAP_HELVETICA_10*: pointer + GLUT_BITMAP_HELVETICA_12*: pointer + GLUT_BITMAP_HELVETICA_18*: pointer +const # glutGet parameters. + GLUT_WINDOW_X* = 100 + GLUT_WINDOW_Y* = 101 + GLUT_WINDOW_WIDTH* = 102 + GLUT_WINDOW_HEIGHT* = 103 + GLUT_WINDOW_BUFFER_SIZE* = 104 + GLUT_WINDOW_STENCIL_SIZE* = 105 + GLUT_WINDOW_DEPTH_SIZE* = 106 + GLUT_WINDOW_RED_SIZE* = 107 + GLUT_WINDOW_GREEN_SIZE* = 108 + GLUT_WINDOW_BLUE_SIZE* = 109 + GLUT_WINDOW_ALPHA_SIZE* = 110 + GLUT_WINDOW_ACCUM_RED_SIZE* = 111 + GLUT_WINDOW_ACCUM_GREEN_SIZE* = 112 + GLUT_WINDOW_ACCUM_BLUE_SIZE* = 113 + GLUT_WINDOW_ACCUM_ALPHA_SIZE* = 114 + GLUT_WINDOW_DOUBLEBUFFER* = 115 + GLUT_WINDOW_RGBA* = 116 + GLUT_WINDOW_PARENT* = 117 + GLUT_WINDOW_NUM_CHILDREN* = 118 + GLUT_WINDOW_COLORMAP_SIZE* = 119 + GLUT_WINDOW_NUM_SAMPLES* = 120 + GLUT_WINDOW_STEREO* = 121 + GLUT_WINDOW_CURSOR* = 122 + GLUT_SCREEN_WIDTH* = 200 + GLUT_SCREEN_HEIGHT* = 201 + GLUT_SCREEN_WIDTH_MM* = 202 + GLUT_SCREEN_HEIGHT_MM* = 203 + GLUT_MENU_NUM_ITEMS* = 300 + GLUT_DISPLAY_MODE_POSSIBLE* = 400 + GLUT_INIT_WINDOW_X* = 500 + GLUT_INIT_WINDOW_Y* = 501 + GLUT_INIT_WINDOW_WIDTH* = 502 + GLUT_INIT_WINDOW_HEIGHT* = 503 + constGLUT_INIT_DISPLAY_MODE* = 504 + GLUT_ELAPSED_TIME* = 700 + GLUT_WINDOW_FORMAT_ID* = 123 # glutDeviceGet parameters. + GLUT_HAS_KEYBOARD* = 600 + GLUT_HAS_MOUSE* = 601 + GLUT_HAS_SPACEBALL* = 602 + GLUT_HAS_DIAL_AND_BUTTON_BOX* = 603 + GLUT_HAS_TABLET* = 604 + GLUT_NUM_MOUSE_BUTTONS* = 605 + GLUT_NUM_SPACEBALL_BUTTONS* = 606 + GLUT_NUM_BUTTON_BOX_BUTTONS* = 607 + GLUT_NUM_DIALS* = 608 + GLUT_NUM_TABLET_BUTTONS* = 609 + GLUT_DEVICE_IGNORE_KEY_REPEAT* = 610 + GLUT_DEVICE_KEY_REPEAT* = 611 + GLUT_HAS_JOYSTICK* = 612 + GLUT_OWNS_JOYSTICK* = 613 + GLUT_JOYSTICK_BUTTONS* = 614 + GLUT_JOYSTICK_AXES* = 615 + GLUT_JOYSTICK_POLL_RATE* = 616 # glutLayerGet parameters. + GLUT_OVERLAY_POSSIBLE* = 800 + GLUT_LAYER_IN_USE* = 801 + GLUT_HAS_OVERLAY* = 802 + GLUT_TRANSPARENT_INDEX* = 803 + GLUT_NORMAL_DAMAGED* = 804 + GLUT_OVERLAY_DAMAGED* = 805 # glutVideoResizeGet parameters. + GLUT_VIDEO_RESIZE_POSSIBLE* = 900 + GLUT_VIDEO_RESIZE_IN_USE* = 901 + GLUT_VIDEO_RESIZE_X_DELTA* = 902 + GLUT_VIDEO_RESIZE_Y_DELTA* = 903 + GLUT_VIDEO_RESIZE_WIDTH_DELTA* = 904 + GLUT_VIDEO_RESIZE_HEIGHT_DELTA* = 905 + GLUT_VIDEO_RESIZE_X* = 906 + GLUT_VIDEO_RESIZE_Y* = 907 + GLUT_VIDEO_RESIZE_WIDTH* = 908 + GLUT_VIDEO_RESIZE_HEIGHT* = 909 # glutGetModifiers return mask. + GLUT_ACTIVE_SHIFT* = 1 + GLUT_ACTIVE_CTRL* = 2 + GLUT_ACTIVE_ALT* = 4 # glutSetCursor parameters. + # Basic arrows. + GLUT_CURSOR_RIGHT_ARROW* = 0 + GLUT_CURSOR_LEFT_ARROW* = 1 # Symbolic cursor shapes. + GLUT_CURSOR_INFO* = 2 + GLUT_CURSOR_DESTROY* = 3 + GLUT_CURSOR_HELP* = 4 + GLUT_CURSOR_CYCLE* = 5 + GLUT_CURSOR_SPRAY* = 6 + GLUT_CURSOR_WAIT* = 7 + GLUT_CURSOR_TEXT* = 8 + GLUT_CURSOR_CROSSHAIR* = 9 # Directional cursors. + GLUT_CURSOR_UP_DOWN* = 10 + GLUT_CURSOR_LEFT_RIGHT* = 11 # Sizing cursors. + GLUT_CURSOR_TOP_SIDE* = 12 + GLUT_CURSOR_BOTTOM_SIDE* = 13 + GLUT_CURSOR_LEFT_SIDE* = 14 + GLUT_CURSOR_RIGHT_SIDE* = 15 + GLUT_CURSOR_TOP_LEFT_CORNER* = 16 + GLUT_CURSOR_TOP_RIGHT_CORNER* = 17 + GLUT_CURSOR_BOTTOM_RIGHT_CORNER* = 18 + GLUT_CURSOR_BOTTOM_LEFT_CORNER* = 19 # Inherit from parent window. + GLUT_CURSOR_INHERIT* = 100 # Blank cursor. + GLUT_CURSOR_NONE* = 101 # Fullscreen crosshair (if available). + GLUT_CURSOR_FULL_CROSSHAIR* = 102 # GLUT device control sub-API. + # glutSetKeyRepeat modes. + GLUT_KEY_REPEAT_OFF* = 0 + GLUT_KEY_REPEAT_ON* = 1 + GLUT_KEY_REPEAT_DEFAULT* = 2 # Joystick button masks. + GLUT_JOYSTICK_BUTTON_A* = 1 + GLUT_JOYSTICK_BUTTON_B* = 2 + GLUT_JOYSTICK_BUTTON_C* = 4 + GLUT_JOYSTICK_BUTTON_D* = 8 # GLUT game mode sub-API. + # glutGameModeGet. + GLUT_GAME_MODE_ACTIVE* = 0 + GLUT_GAME_MODE_POSSIBLE* = 1 + GLUT_GAME_MODE_WIDTH* = 2 + GLUT_GAME_MODE_HEIGHT* = 3 + GLUT_GAME_MODE_PIXEL_DEPTH* = 4 + GLUT_GAME_MODE_REFRESH_RATE* = 5 + GLUT_GAME_MODE_DISPLAY_CHANGED* = 6 # GLUT initialization sub-API. + +{.push dynlib: dllname, importc.} +proc glutInit*(argcp: ptr cint, argv: pointer) + +proc glutInit*() = + ## version that passes `argc` and `argc` implicitely. + var + cmdLine {.importc: "cmdLine".}: array[0..255, cstring] + cmdCount {.importc: "cmdCount".}: cint + glutInit(addr(cmdCount), addr(cmdLine)) + +proc glutInitDisplayMode*(mode: int16) +proc glutInitDisplayString*(str: cstring) +proc glutInitWindowPosition*(x, y: int) +proc glutInitWindowSize*(width, height: int) +proc glutMainLoop*() + # GLUT window sub-API. +proc glutCreateWindow*(title: cstring): int +proc glutCreateSubWindow*(win, x, y, width, height: int): int +proc glutDestroyWindow*(win: int) +proc glutPostRedisplay*() +proc glutPostWindowRedisplay*(win: int) +proc glutSwapBuffers*() +proc glutSetWindow*(win: int) +proc glutSetWindowTitle*(title: cstring) +proc glutSetIconTitle*(title: cstring) +proc glutPositionWindow*(x, y: int) +proc glutReshapeWindow*(width, height: int) +proc glutPopWindow*() +proc glutPushWindow*() +proc glutIconifyWindow*() +proc glutShowWindow*() +proc glutHideWindow*() +proc glutFullScreen*() +proc glutSetCursor*(cursor: int) +proc glutWarpPointer*(x, y: int) + # GLUT overlay sub-API. +proc glutEstablishOverlay*() +proc glutRemoveOverlay*() +proc glutUseLayer*(layer: GLenum) +proc glutPostOverlayRedisplay*() +proc glutPostWindowOverlayRedisplay*(win: int) +proc glutShowOverlay*() +proc glutHideOverlay*() + # GLUT menu sub-API. +proc glutCreateMenu*(callback: TGlut1IntCallback): int +proc glutDestroyMenu*(menu: int) +proc glutSetMenu*(menu: int) +proc glutAddMenuEntry*(caption: cstring, value: int) +proc glutAddSubMenu*(caption: cstring, submenu: int) +proc glutChangeToMenuEntry*(item: int, caption: cstring, value: int) +proc glutChangeToSubMenu*(item: int, caption: cstring, submenu: int) +proc glutRemoveMenuItem*(item: int) +proc glutAttachMenu*(button: int) +proc glutDetachMenu*(button: int) + # GLUT window callback sub-API. +proc glutDisplayFunc*(f: TGlutVoidCallback) +proc glutReshapeFunc*(f: TGlut2IntCallback) +proc glutKeyboardFunc*(f: TGlut1Char2IntCallback) +proc glutMouseFunc*(f: TGlut4IntCallback) +proc glutMotionFunc*(f: TGlut2IntCallback) +proc glutPassiveMotionFunc*(f: TGlut2IntCallback) +proc glutEntryFunc*(f: TGlut1IntCallback) +proc glutVisibilityFunc*(f: TGlut1IntCallback) +proc glutIdleFunc*(f: TGlutVoidCallback) +proc glutTimerFunc*(millis: int16, f: TGlut1IntCallback, value: int) +proc glutMenuStateFunc*(f: TGlut1IntCallback) +proc glutSpecialFunc*(f: TGlut3IntCallback) +proc glutSpaceballMotionFunc*(f: TGlut3IntCallback) +proc glutSpaceballRotateFunc*(f: TGlut3IntCallback) +proc glutSpaceballButtonFunc*(f: TGlut2IntCallback) +proc glutButtonBoxFunc*(f: TGlut2IntCallback) +proc glutDialsFunc*(f: TGlut2IntCallback) +proc glutTabletMotionFunc*(f: TGlut2IntCallback) +proc glutTabletButtonFunc*(f: TGlut4IntCallback) +proc glutMenuStatusFunc*(f: TGlut3IntCallback) +proc glutOverlayDisplayFunc*(f: TGlutVoidCallback) +proc glutWindowStatusFunc*(f: TGlut1IntCallback) +proc glutKeyboardUpFunc*(f: TGlut1Char2IntCallback) +proc glutSpecialUpFunc*(f: TGlut3IntCallback) +proc glutJoystickFunc*(f: TGlut1UInt3IntCallback, pollInterval: int) + # GLUT color index sub-API. +proc glutSetColor*(cell: int, red, green, blue: GLfloat) +proc glutGetColor*(ndx, component: int): GLfloat +proc glutCopyColormap*(win: int) + # GLUT state retrieval sub-API. + # GLUT extension support sub-API +proc glutExtensionSupported*(name: cstring): int + # GLUT font sub-API +proc glutBitmapCharacter*(font: pointer, character: int) +proc glutBitmapWidth*(font: pointer, character: int): int +proc glutStrokeCharacter*(font: pointer, character: int) +proc glutStrokeWidth*(font: pointer, character: int): int +proc glutBitmapLength*(font: pointer, str: cstring): int +proc glutStrokeLength*(font: pointer, str: cstring): int + # GLUT pre-built models sub-API +proc glutWireSphere*(radius: GLdouble, slices, stacks: GLint) +proc glutSolidSphere*(radius: GLdouble, slices, stacks: GLint) +proc glutWireCone*(base, height: GLdouble, slices, stacks: GLint) +proc glutSolidCone*(base, height: GLdouble, slices, stacks: GLint) +proc glutWireCube*(size: GLdouble) +proc glutSolidCube*(size: GLdouble) +proc glutWireTorus*(innerRadius, outerRadius: GLdouble, sides, rings: GLint) +proc glutSolidTorus*(innerRadius, outerRadius: GLdouble, sides, rings: GLint) +proc glutWireDodecahedron*() +proc glutSolidDodecahedron*() +proc glutWireTeapot*(size: GLdouble) +proc glutSolidTeapot*(size: GLdouble) +proc glutWireOctahedron*() +proc glutSolidOctahedron*() +proc glutWireTetrahedron*() +proc glutSolidTetrahedron*() +proc glutWireIcosahedron*() +proc glutSolidIcosahedron*() + # GLUT video resize sub-API. +proc glutVideoResizeGet*(param: GLenum): int +proc glutSetupVideoResizing*() +proc glutStopVideoResizing*() +proc glutVideoResize*(x, y, width, height: int) +proc glutVideoPan*(x, y, width, height: int) + # GLUT debugging sub-API. +proc glutReportErrors*() + # GLUT device control sub-API. +proc glutIgnoreKeyRepeat*(ignore: int) +proc glutSetKeyRepeat*(repeatMode: int) +proc glutForceJoystickFunc*() + # GLUT game mode sub-API. + #example glutGameModeString('1280x1024:32@75'); +proc glutGameModeString*(AString: cstring) +proc glutLeaveGameMode*() +proc glutGameModeGet*(mode: GLenum): int +# implementation +{.pop.} # dynlib: dllname, importc diff --git a/tests/deps/opengl-1.1.0/glx.nim b/tests/deps/opengl-1.1.0/glx.nim new file mode 100644 index 000000000..6ad096c7d --- /dev/null +++ b/tests/deps/opengl-1.1.0/glx.nim @@ -0,0 +1,154 @@ +# +# +# Translation of the Mesa GLX headers for FreePascal +# Copyright (C) 1999 Sebastian Guenther +# +# +# Mesa 3-D graphics library +# Version: 3.0 +# Copyright (C) 1995-1998 Brian Paul +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Library General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Library General Public License for more details. +# +# You should have received a copy of the GNU Library General Public +# License along with this library; if not, write to the Free +# Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +# + +import X, XLib, XUtil, opengl + +{.deadCodeElim: on.} + +when defined(windows): + const + dllname = "GL.dll" +elif defined(macosx): + const + dllname = "/usr/X11R6/lib/libGL.dylib" +else: + const + dllname = "libGL.so" +const + GLX_USE_GL* = 1'i32 + GLX_BUFFER_SIZE* = 2'i32 + GLX_LEVEL* = 3'i32 + GLX_RGBA* = 4'i32 + GLX_DOUBLEBUFFER* = 5'i32 + GLX_STEREO* = 6'i32 + GLX_AUX_BUFFERS* = 7'i32 + GLX_RED_SIZE* = 8'i32 + GLX_GREEN_SIZE* = 9'i32 + GLX_BLUE_SIZE* = 10'i32 + GLX_ALPHA_SIZE* = 11'i32 + GLX_DEPTH_SIZE* = 12'i32 + GLX_STENCIL_SIZE* = 13'i32 + GLX_ACCUM_RED_SIZE* = 14'i32 + GLX_ACCUM_GREEN_SIZE* = 15'i32 + GLX_ACCUM_BLUE_SIZE* = 16'i32 + GLX_ACCUM_ALPHA_SIZE* = 17'i32 # GLX_EXT_visual_info extension + GLX_X_VISUAL_TYPE_EXT* = 0x00000022 + GLX_TRANSPARENT_TYPE_EXT* = 0x00000023 + GLX_TRANSPARENT_INDEX_VALUE_EXT* = 0x00000024 + GLX_TRANSPARENT_RED_VALUE_EXT* = 0x00000025 + GLX_TRANSPARENT_GREEN_VALUE_EXT* = 0x00000026 + GLX_TRANSPARENT_BLUE_VALUE_EXT* = 0x00000027 + GLX_TRANSPARENT_ALPHA_VALUE_EXT* = 0x00000028 # Error codes returned by glXGetConfig: + GLX_BAD_SCREEN* = 1 + GLX_BAD_ATTRIBUTE* = 2 + GLX_NO_EXTENSION* = 3 + GLX_BAD_VISUAL* = 4 + GLX_BAD_CONTEXT* = 5 + GLX_BAD_VALUE* = 6 + GLX_BAD_ENUM* = 7 # GLX 1.1 and later: + GLX_VENDOR* = 1 + GLX_VERSION* = 2 + GLX_EXTENSIONS* = 3 # GLX_visual_info extension + GLX_TRUE_COLOR_EXT* = 0x00008002 + GLX_DIRECT_COLOR_EXT* = 0x00008003 + GLX_PSEUDO_COLOR_EXT* = 0x00008004 + GLX_STATIC_COLOR_EXT* = 0x00008005 + GLX_GRAY_SCALE_EXT* = 0x00008006 + GLX_STATIC_GRAY_EXT* = 0x00008007 + GLX_NONE_EXT* = 0x00008000 + GLX_TRANSPARENT_RGB_EXT* = 0x00008008 + GLX_TRANSPARENT_INDEX_EXT* = 0x00008009 + +type # From XLib: + XPixmap* = TXID + XFont* = TXID + XColormap* = TXID + GLXContext* = pointer + GLXPixmap* = TXID + GLXDrawable* = TXID + GLXContextID* = TXID + TXPixmap* = XPixmap + TXFont* = XFont + TXColormap* = XColormap + TGLXContext* = GLXContext + TGLXPixmap* = GLXPixmap + TGLXDrawable* = GLXDrawable + TGLXContextID* = GLXContextID + +proc glXChooseVisual*(dpy: PDisplay, screen: int, attribList: ptr int32): PXVisualInfo{. + cdecl, dynlib: dllname, importc: "glXChooseVisual".} +proc glXCreateContext*(dpy: PDisplay, vis: PXVisualInfo, shareList: GLXContext, + direct: bool): GLXContext{.cdecl, dynlib: dllname, + importc: "glXCreateContext".} +proc glXDestroyContext*(dpy: PDisplay, ctx: GLXContext){.cdecl, dynlib: dllname, + importc: "glXDestroyContext".} +proc glXMakeCurrent*(dpy: PDisplay, drawable: GLXDrawable, ctx: GLXContext): bool{. + cdecl, dynlib: dllname, importc: "glXMakeCurrent".} +proc glXCopyContext*(dpy: PDisplay, src, dst: GLXContext, mask: int32){.cdecl, + dynlib: dllname, importc: "glXCopyContext".} +proc glXSwapBuffers*(dpy: PDisplay, drawable: GLXDrawable){.cdecl, + dynlib: dllname, importc: "glXSwapBuffers".} +proc glXCreateGLXPixmap*(dpy: PDisplay, visual: PXVisualInfo, pixmap: XPixmap): GLXPixmap{. + cdecl, dynlib: dllname, importc: "glXCreateGLXPixmap".} +proc glXDestroyGLXPixmap*(dpy: PDisplay, pixmap: GLXPixmap){.cdecl, + dynlib: dllname, importc: "glXDestroyGLXPixmap".} +proc glXQueryExtension*(dpy: PDisplay, errorb, event: var int): bool{.cdecl, + dynlib: dllname, importc: "glXQueryExtension".} +proc glXQueryVersion*(dpy: PDisplay, maj, min: var int): bool{.cdecl, + dynlib: dllname, importc: "glXQueryVersion".} +proc glXIsDirect*(dpy: PDisplay, ctx: GLXContext): bool{.cdecl, dynlib: dllname, + importc: "glXIsDirect".} +proc glXGetConfig*(dpy: PDisplay, visual: PXVisualInfo, attrib: int, + value: var int): int{.cdecl, dynlib: dllname, + importc: "glXGetConfig".} +proc glXGetCurrentContext*(): GLXContext{.cdecl, dynlib: dllname, + importc: "glXGetCurrentContext".} +proc glXGetCurrentDrawable*(): GLXDrawable{.cdecl, dynlib: dllname, + importc: "glXGetCurrentDrawable".} +proc glXWaitGL*(){.cdecl, dynlib: dllname, importc: "glXWaitGL".} +proc glXWaitX*(){.cdecl, dynlib: dllname, importc: "glXWaitX".} +proc glXUseXFont*(font: XFont, first, count, list: int){.cdecl, dynlib: dllname, + importc: "glXUseXFont".} + # GLX 1.1 and later +proc glXQueryExtensionsString*(dpy: PDisplay, screen: int): cstring{.cdecl, + dynlib: dllname, importc: "glXQueryExtensionsString".} +proc glXQueryServerString*(dpy: PDisplay, screen, name: int): cstring{.cdecl, + dynlib: dllname, importc: "glXQueryServerString".} +proc glXGetClientString*(dpy: PDisplay, name: int): cstring{.cdecl, + dynlib: dllname, importc: "glXGetClientString".} + # Mesa GLX Extensions +proc glXCreateGLXPixmapMESA*(dpy: PDisplay, visual: PXVisualInfo, + pixmap: XPixmap, cmap: XColormap): GLXPixmap{. + cdecl, dynlib: dllname, importc: "glXCreateGLXPixmapMESA".} +proc glXReleaseBufferMESA*(dpy: PDisplay, d: GLXDrawable): bool{.cdecl, + dynlib: dllname, importc: "glXReleaseBufferMESA".} +proc glXCopySubBufferMESA*(dpy: PDisplay, drawbale: GLXDrawable, + x, y, width, height: int){.cdecl, dynlib: dllname, + importc: "glXCopySubBufferMESA".} +proc glXGetVideoSyncSGI*(counter: var int32): int{.cdecl, dynlib: dllname, + importc: "glXGetVideoSyncSGI".} +proc glXWaitVideoSyncSGI*(divisor, remainder: int, count: var int32): int{. + cdecl, dynlib: dllname, importc: "glXWaitVideoSyncSGI".} +# implementation diff --git a/tests/deps/opengl-1.1.0/opengl.nim b/tests/deps/opengl-1.1.0/opengl.nim new file mode 100644 index 000000000..55e009a46 --- /dev/null +++ b/tests/deps/opengl-1.1.0/opengl.nim @@ -0,0 +1,8481 @@ + +# +# +# Nimrod's Runtime Library +# (c) Copyright 2012 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +## This module is a wrapper around `opengl`:idx:. If you define the symbol +## ``useGlew`` this wrapper does not use Nimrod's ``dynlib`` mechanism, +## but `glew`:idx: instead. However, this shouldn't be necessary anymore; even +## extension loading for the different operating systems is handled here. +## +## You need to call ``loadExtensions`` after a rendering context has been +## created to load any extension proc that your code uses. + +{.deadCodeElim: on.} + +import macros, sequtils + +{.push warning[User]: off.} + +when defined(linux) and not defined(android) and not defined(emscripten): + import X, XLib, XUtil +elif defined(windows): + import winlean, os + +when defined(windows): + const + ogldll* = "OpenGL32.dll" + gludll* = "GLU32.dll" +elif defined(macosx): + #macosx has this notion of a framework, thus the path to the openGL dylib files + #is absolute + const + ogldll* = "/System/Library/Frameworks/OpenGL.framework/Versions/Current/Libraries/libGL.dylib" + gludll* = "/System/Library/Frameworks/OpenGL.framework/Versions/Current/Libraries/libGLU.dylib" +else: + const + ogldll* = "libGL.so.1" + gludll* = "libGLU.so.1" + +when defined(useGlew): + {.pragma: ogl, header: "".} + {.pragma: oglx, header: "".} + {.pragma: wgl, header: "".} + {.pragma: glu, dynlib: gludll.} +elif defined(ios): + {.pragma: ogl.} + {.pragma: oglx.} + {.passC: "-framework OpenGLES", passL: "-framework OpenGLES".} +elif defined(android) or defined(js) or defined(emscripten): + {.pragma: ogl.} + {.pragma: oglx.} +else: + # quite complex ... thanks to extension support for various platforms: + import dynlib + + let oglHandle = loadLib(ogldll) + if isNil(oglHandle): quit("could not load: " & ogldll) + + when defined(windows): + var wglGetProcAddress = cast[proc (s: cstring): pointer {.stdcall.}]( + symAddr(oglHandle, "wglGetProcAddress")) + elif defined(linux): + var glxGetProcAddress = cast[proc (s: cstring): pointer {.cdecl.}]( + symAddr(oglHandle, "glxGetProcAddress")) + var glxGetProcAddressArb = cast[proc (s: cstring): pointer {.cdecl.}]( + symAddr(oglHandle, "glxGetProcAddressARB")) + + proc glGetProc(h: LibHandle; procName: cstring): pointer = + when defined(windows): + result = symAddr(h, procname) + if result != nil: return + if not isNil(wglGetProcAddress): result = wglGetProcAddress(procName) + elif defined(linux): + if not isNil(glxGetProcAddress): result = glxGetProcAddress(procName) + if result != nil: return + if not isNil(glxGetProcAddressArb): + result = glxGetProcAddressArb(procName) + if result != nil: return + result = symAddr(h, procname) + else: + result = symAddr(h, procName) + if result == nil: raiseInvalidLibrary(procName) + + var gluHandle: LibHandle + + proc gluGetProc(procname: cstring): pointer = + if gluHandle == nil: + gluHandle = loadLib(gludll) + if gluHandle == nil: quit("could not load: " & gludll) + result = glGetProc(gluHandle, procname) + + # undocumented 'dynlib' feature: the string literal is replaced by + # the imported proc name: + {.pragma: ogl, dynlib: glGetProc(oglHandle, "0").} + {.pragma: oglx, dynlib: glGetProc(oglHandle, "0").} + {.pragma: wgl, dynlib: glGetProc(oglHandle, "0").} + {.pragma: glu, dynlib: gluGetProc("").} + + proc nimLoadProcs0() {.importc.} + + template loadExtensions*() = + ## call this after your rendering context has been setup if you use + ## extensions. + bind nimLoadProcs0 + nimLoadProcs0() + +{.pop.} # warning[User]: off + +type + GLenum* = distinct uint32 + GLboolean* = bool + GLbitfield* = distinct uint32 + GLvoid* = pointer + GLbyte* = int8 + GLshort* = int64 + GLint* = int32 + GLclampx* = int32 + GLubyte* = uint8 + GLushort* = uint16 + GLuint* = uint32 + GLhandle* = GLuint + GLsizei* = int32 + GLfloat* = float32 + GLclampf* = float32 + GLdouble* = float64 + GLclampd* = float64 + GLeglImageOES* = distinct pointer + GLchar* = char + GLcharArb* = char + GLfixed* = int32 + GLhalfNv* = uint16 + GLvdpauSurfaceNv* = uint + GLintptr* = int + GLintptrArb* = int + GLint64EXT* = int64 + GLuint64EXT* = uint64 + GLint64* = int64 + GLsizeiptrArb* = int + GLsizeiptr* = int + GLsync* = distinct pointer + GLuint64* = uint64 + GLvectorub2* = array[0..1, GLubyte] + GLvectori2* = array[0..1, GLint] + GLvectorf2* = array[0..1, GLfloat] + GLvectord2* = array[0..1, GLdouble] + GLvectorp2* = array[0..1, pointer] + GLvectorb3* = array[0..2, GLbyte] + GLvectorub3* = array[0..2, GLubyte] + GLvectori3* = array[0..2, GLint] + GLvectorui3* = array[0..2, GLuint] + GLvectorf3* = array[0..2, GLfloat] + GLvectord3* = array[0..2, GLdouble] + GLvectorp3* = array[0..2, pointer] + GLvectors3* = array[0..2, GLshort] + GLvectorus3* = array[0..2, GLushort] + GLvectorb4* = array[0..3, GLbyte] + GLvectorub4* = array[0..3, GLubyte] + GLvectori4* = array[0..3, GLint] + GLvectorui4* = array[0..3, GLuint] + GLvectorf4* = array[0..3, GLfloat] + GLvectord4* = array[0..3, GLdouble] + GLvectorp4* = array[0..3, pointer] + GLvectors4* = array[0..3, GLshort] + GLvectorus4* = array[0..3, GLshort] + GLarray4f* = GLvectorf4 + GLarrayf3* = GLvectorf3 + GLarrayd3* = GLvectord3 + GLarrayi4* = GLvectori4 + GLarrayp4* = GLvectorp4 + GLmatrixub3* = array[0..2, array[0..2, GLubyte]] + GLmatrixi3* = array[0..2, array[0..2, GLint]] + GLmatrixf3* = array[0..2, array[0..2, GLfloat]] + GLmatrixd3* = array[0..2, array[0..2, GLdouble]] + GLmatrixub4* = array[0..3, array[0..3, GLubyte]] + GLmatrixi4* = array[0..3, array[0..3, GLint]] + GLmatrixf4* = array[0..3, array[0..3, GLfloat]] + GLmatrixd4* = array[0..3, array[0..3, GLdouble]] + ClContext* = distinct pointer + ClEvent* = distinct pointer + GLdebugProc* = proc ( + source: GLenum, + typ: GLenum, + id: GLuint, + severity: GLenum, + length: GLsizei, + message: ptr GLchar, + userParam: pointer) {.stdcall.} + GLdebugProcArb* = proc ( + source: GLenum, + typ: GLenum, + id: GLuint, + severity: GLenum, + len: GLsizei, + message: ptr GLchar, + userParam: pointer) {.stdcall.} + GLdebugProcAmd* = proc ( + id: GLuint, + category: GLenum, + severity: GLenum, + len: GLsizei, + message: ptr GLchar, + userParam: pointer) {.stdcall.} + GLdebugProcKhr* = proc ( + source, typ: GLenum, + id: GLuint, + severity: GLenum, + length: GLsizei, + message: ptr GLchar, + userParam: pointer) {.stdcall.} +type + GLerrorCode* {.size: GLenum.sizeof.} = enum # XXX: can't be evaluated when + # in the same type section as + # GLenum. + glErrNoError = (0, "no error") + glErrInvalidEnum = (0x0500, "invalid enum") + glErrInvalidValue = (0x0501, "invalid value") + glErrInvalidOperation = (0x0502, "invalid operation") + glErrStackOverflow = (0x0503, "stack overflow") + glErrStackUnderflow = (0x0504, "stack underflow") + glErrOutOfMem = (0x0505, "out of memory") + glErrInvalidFramebufferOperation = (0x0506, "invalid framebuffer operation") + glErrTableTooLarge = (0x8031, "table too large") + +const AllErrorCodes = { + glErrNoError, + glErrInvalidEnum, + glErrInvalidValue, + glErrInvalidOperation, + glErrStackOverflow, + glErrStackUnderflow, + glErrOutOfMem, + glErrInvalidFramebufferOperation, + glErrTableTooLarge, +} + +when defined(macosx): + type + GLhandleArb = pointer +else: + type + GLhandleArb = uint32 + +{.deprecated: [ + TGLerror: GLerrorCode, + TGLhandleARB: GLhandleArb, + TGLenum: GLenum, + TGLboolean: GLboolean, + TGLbitfield: GLbitfield, + TGLvoid: GLvoid, + TGLbyte: GLbyte, + TGLshort: GLshort, + TGLint: GLint, + TGLclampx: GLclampx, + TGLubyte: GLubyte, + TGLushort: GLushort, + TGLuint: GLuint, + TGLsizei: GLsizei, + TGLfloat: GLfloat, + TGLclampf: GLclampf, + TGLdouble: GLdouble, + TGLclampd: GLclampd, + TGLeglImageOES: GLeglImageOES, + TGLchar: GLchar, + TGLcharARB: GLcharArb, + TGLfixed: GLfixed, + TGLhalfNV: GLhalfNv, + TGLvdpauSurfaceNv: GLvdpauSurfaceNv, + TGLintptr: GLintptr, + TGLintptrARB: GLintptrArb, + TGLint64EXT: GLint64Ext, + TGLuint64EXT: GLuint64Ext, + TGLint64: GLint64, + TGLsizeiptrARB: GLsizeiptrArb, + TGLsizeiptr: GLsizeiptr, + TGLsync: GLsync, + TGLuint64: GLuint64, + TCL_context: ClContext, + TCL_event: ClEvent, + TGLdebugProc: GLdebugProc, + TGLDebugProcARB: GLdebugProcArb, + TGLDebugProcAMD: GLdebugProcAmd, + TGLDebugProcKHR: GLdebugProcKhr, + TGLVectorub2: GLvectorub2, + TGLVectori2: GLvectori2, + TGLVectorf2: GLvectorf2, + TGLVectord2: GLvectord2, + TGLVectorp2: GLvectorp2, + TGLVectorb3: GLvectorb3, + TGLVectorub3: GLvectorub3, + TGLVectori3: GLvectori3, + TGLVectorui3: GLvectorui3, + TGLVectorf3: GLvectorf3, + TGLVectord3: GLvectord3, + TGLVectorp3: GLvectorp3, + TGLVectors3: GLvectors3, + TGLVectorus3: GLvectorus3, + TGLVectorb4: GLvectorb4, + TGLVectorub4: GLvectorub4, + TGLVectori4: GLvectori4, + TGLVectorui4: GLvectorui4, + TGLVectorf4: GLvectorf4, + TGLVectord4: GLvectord4, + TGLVectorp4: GLvectorp4, + TGLVectors4: GLvectors4, + TGLVectorus4: GLvectorus4, + TGLArrayf4: GLarray4f, + TGLArrayf3: GLarrayf3, + TGLArrayd3: GLarrayd3, + TGLArrayi4: GLarrayi4, + TGLArrayp4: GLarrayp4, + TGLMatrixub3: GLmatrixub3, + TGLMatrixi3: GLmatrixi3, + TGLMatrixf3: GLmatrixf3, + TGLMatrixd3: GLmatrixd3, + TGLMatrixub4: GLmatrixub4, + TGLMatrixi4: GLmatrixi4, + TGLMatrixf4: GLmatrixf4, + TGLMatrixd4: GLmatrixd4, + TGLVector3d: GLvectord3, + TGLVector4i: GLvectori4, + TGLVector4f: GLvectorf4, + TGLVector4p: GLvectorp4, + TGLMatrix4f: GLmatrixf4, + TGLMatrix4d: GLmatrixd4, +].} + +proc `==`*(a, b: GLenum): bool {.borrow.} + +proc `==`*(a, b: GLbitfield): bool {.borrow.} + +proc `or`*(a, b: GLbitfield): GLbitfield {.borrow.} + +proc hash*(x: GLenum): int = + result = x.int + +proc glGetError*: GLenum {.stdcall, importc, ogl.} +proc getGLerrorCode*: GLerrorCode = glGetError().GLerrorCode + ## Like ``glGetError`` but returns an enumerator instead. + +type + GLerror* = object of Exception + ## An exception for OpenGL errors. + code*: GLerrorCode ## The error code. This might be invalid for two reasons: + ## an outdated list of errors or a bad driver. + +proc checkGLerror* = + ## Raise ``GLerror`` if the last call to an OpenGL function generated an error. + ## You might want to call this once every frame for example if automatic + ## error checking has been disabled. + let error = getGLerrorCode() + if error == glErrNoError: + return + + var + exc = new(GLerror) + for e in AllErrorCodes: + if e == error: + exc.msg = "OpenGL error: " & $e + raise exc + + exc.code = error + exc.msg = "OpenGL error: unknown (" & $error & ")" + raise exc + +{.push warning[User]: off.} + +const + NoAutoGLerrorCheck* = defined(noAutoGLerrorCheck) ##\ + ## This determines (at compile time) whether an exception should be raised + ## if an OpenGL call generates an error. No additional code will be generated + ## and ``enableAutoGLerrorCheck(bool)`` will have no effect when + ## ``noAutoGLerrorCheck`` is defined. + +{.pop.} # warning[User]: off + +var + gAutoGLerrorCheck = true + gInsideBeginEnd* = false # do not change manually. + +proc enableAutoGLerrorCheck*(yes: bool) = + ## This determines (at run time) whether an exception should be raised if an + ## OpenGL call generates an error. This has no effect when + ## ``noAutoGLerrorCheck`` is defined. + gAutoGLerrorCheck = yes + +macro wrapErrorChecking(f: stmt): stmt {.immediate.} = + f.expectKind nnkStmtList + result = newStmtList() + + for child in f.children: + if child.kind == nnkCommentStmt: + continue + child.expectKind nnkProcDef + + let params = toSeq(child.params.children) + var glProc = copy child + glProc.pragma = newNimNode(nnkPragma).add( + newNimNode(nnkExprColonExpr).add( + ident"importc" , newLit($child.name)) + ).add(ident"ogl") + + let rawGLprocName = $glProc.name + glProc.name = ident(rawGLprocName & "Impl") + var + body = newStmtList glProc + returnsSomething = child.params[0].kind != nnkEmpty + callParams = newSeq[when defined(nimnode): NimNode else: PNimrodNode]() + for param in params[1 ..< params.len]: + callParams.add param[0] + + let glCall = newCall(glProc.name, callParams) + body.add if returnsSomething: + newAssignment(ident"result", glCall) + else: + glCall + + if rawGLprocName == "glBegin": + body.add newAssignment(ident"gInsideBeginEnd", ident"true") + if rawGLprocName == "glEnd": + body.add newAssignment(ident"gInsideBeginEnd", ident"false") + + template errCheck: stmt = + when not (NoAutoGLerrorCheck): + if gAutoGLerrorCheck and not gInsideBeginEnd: + checkGLerror() + + body.add getAst(errCheck()) + + var procc = newProc(child.name, params, body) + procc.pragma = newNimNode(nnkPragma).add(ident"inline") + procc.name = postfix(procc.name, "*") + result.add procc + +{.push stdcall, hint[XDeclaredButNotUsed]: off, warning[SmallLshouldNotBeUsed]: off.} +wrapErrorChecking: + proc glMultiTexCoord2d(target: GLenum, s: GLdouble, t: GLdouble) {.importc.} + proc glDrawElementsIndirect(mode: GLenum, `type`: GLenum, indirect: pointer) {.importc.} + proc glEnableVertexArrayEXT(vaobj: GLuint, `array`: GLenum) {.importc.} + proc glDeleteFramebuffers(n: GLsizei, framebuffers: ptr GLuint) {.importc.} + proc glMultiTexCoord3dv(target: GLenum, v: ptr GLdouble) {.importc.} + proc glVertexAttrib4d(index: GLuint, x: GLdouble, y: GLdouble, z: GLdouble, w: GLdouble) {.importc.} + proc glLoadPaletteFromModelViewMatrixOES() {.importc.} + proc glVertex3xvOES(coords: ptr GLfixed) {.importc.} + proc glNormalStream3sATI(stream: GLenum, nx: GLshort, ny: GLshort, nz: GLshort) {.importc.} + proc glMatrixFrustumEXT(mode: GLenum, left: GLdouble, right: GLdouble, bottom: GLdouble, top: GLdouble, zNear: GLdouble, zFar: GLdouble) {.importc.} + proc glUniformMatrix2fvARB(location: GLint, count: GLsizei, transpose: GLboolean, value: ptr GLfloat) {.importc.} + proc glColor4dv(v: ptr GLdouble) {.importc.} + proc glColor3fv(v: ptr GLfloat) {.importc.} + proc glVertexAttribI1uiEXT(index: GLuint, x: GLuint) {.importc.} + proc glGetDebugMessageLogKHR(count: GLuint, bufsize: GLsizei, sources: ptr GLenum, types: ptr GLenum, ids: ptr GLuint, severities: ptr GLenum, lengths: ptr GLsizei, messageLog: cstring): GLuint {.importc.} + proc glVertexAttribI2iv(index: GLuint, v: ptr GLint) {.importc.} + proc glTexCoord1xvOES(coords: ptr GLfixed) {.importc.} + proc glVertex3hNV(x: GLhalfNv, y: GLhalfNv, z: GLhalfNv) {.importc.} + proc glIsShader(shader: GLuint): GLboolean {.importc.} + proc glDeleteRenderbuffersEXT(n: GLsizei, renderbuffers: ptr GLuint) {.importc.} + proc glVertex3hvNV(v: ptr GLhalfNv) {.importc.} + proc glGetPointervKHR(pname: GLenum, params: ptr pointer) {.importc.} + proc glProgramUniform3i64vNV(program: GLuint, location: GLint, count: GLsizei, value: ptr GLint64Ext) {.importc.} + proc glNamedFramebufferTexture1DEXT(framebuffer: GLuint, attachment: GLenum, textarget: GLenum, texture: GLuint, level: GLint) {.importc.} + proc glGetNamedProgramLocalParameterfvEXT(program: GLuint, target: GLenum, index: GLuint, params: ptr GLfloat) {.importc.} + proc glGenRenderbuffersOES(n: GLsizei, renderbuffers: ptr GLuint) {.importc.} + proc glVertex4dv(v: ptr GLdouble) {.importc.} + proc glTexCoord2fColor4ubVertex3fvSUN(tc: ptr GLfloat, c: ptr GLubyte, v: ptr GLfloat) {.importc.} + proc glTexStorage2DEXT(target: GLenum, levels: GLsizei, internalformat: GLenum, width: GLsizei, height: GLsizei) {.importc.} + proc glVertexAttrib2d(index: GLuint, x: GLdouble, y: GLdouble) {.importc.} + proc glVertexAttrib1dv(index: GLuint, v: ptr GLdouble) {.importc.} + proc glBindProgramARB(target: GLenum, program: GLuint) {.importc.} + proc glRasterPos2dv(v: ptr GLdouble) {.importc.} + proc glCompressedTextureSubImage2DEXT(texture: GLuint, target: GLenum, level: GLint, xoffset: GLint, yoffset: GLint, width: GLsizei, height: GLsizei, format: GLenum, imageSize: GLsizei, bits: pointer) {.importc.} + proc glNormalPointervINTEL(`type`: GLenum, `pointer`: ptr pointer) {.importc.} + proc glGetInteger64vAPPLE(pname: GLenum, params: ptr GLint64) {.importc.} + proc glPushMatrix() {.importc.} + proc glGetCompressedTexImageARB(target: GLenum, level: GLint, img: pointer) {.importc.} + proc glBindMaterialParameterEXT(face: GLenum, value: GLenum): GLuint {.importc.} + proc glBlendEquationIndexedAMD(buf: GLuint, mode: GLenum) {.importc.} + proc glGetObjectBufferfvATI(buffer: GLuint, pname: GLenum, params: ptr GLfloat) {.importc.} + proc glMakeNamedBufferNonResidentNV(buffer: GLuint) {.importc.} + proc glUniform2ui64NV(location: GLint, x: GLuint64Ext, y: GLuint64Ext) {.importc.} + proc glRasterPos4fv(v: ptr GLfloat) {.importc.} + proc glDeleteTextures(n: GLsizei, textures: ptr GLuint) {.importc.} + proc glSecondaryColorPointer(size: GLint, `type`: GLenum, stride: GLsizei, `pointer`: pointer) {.importc.} + proc glTextureSubImage1DEXT(texture: GLuint, target: GLenum, level: GLint, xoffset: GLint, width: GLsizei, format: GLenum, `type`: GLenum, pixels: pointer) {.importc.} + proc glEndTilingQCOM(preserveMask: GLbitfield) {.importc.} + proc glBindBuffer(target: GLenum, buffer: GLuint) {.importc.} + proc glUniformMatrix3fvARB(location: GLint, count: GLsizei, transpose: GLboolean, value: ptr GLfloat) {.importc.} + proc glSamplerParameterf(sampler: GLuint, pname: GLenum, param: GLfloat) {.importc.} + proc glSecondaryColor3d(red: GLdouble, green: GLdouble, blue: GLdouble) {.importc.} + proc glVertexAttrib4sARB(index: GLuint, x: GLshort, y: GLshort, z: GLshort, w: GLshort) {.importc.} + proc glNamedProgramLocalParameterI4iEXT(program: GLuint, target: GLenum, index: GLuint, x: GLint, y: GLint, z: GLint, w: GLint) {.importc.} + proc glProgramUniform2iEXT(program: GLuint, location: GLint, v0: GLint, v1: GLint) {.importc.} + proc glPopAttrib() {.importc.} + proc glGetnColorTableARB(target: GLenum, format: GLenum, `type`: GLenum, bufSize: GLsizei, table: pointer) {.importc.} + proc glMatrixLoadIdentityEXT(mode: GLenum) {.importc.} + proc glGetNamedProgramivEXT(program: GLuint, target: GLenum, pname: GLenum, params: ptr GLint) {.importc.} + proc glCopyTextureSubImage2DEXT(texture: GLuint, target: GLenum, level: GLint, xoffset: GLint, yoffset: GLint, x: GLint, y: GLint, width: GLsizei, height: GLsizei) {.importc.} + proc glUniform4i64NV(location: GLint, x: GLint64Ext, y: GLint64Ext, z: GLint64Ext, w: GLint64Ext) {.importc.} + proc glDeleteTexturesEXT(n: GLsizei, textures: ptr GLuint) {.importc.} + proc glMultiTexCoord1dv(target: GLenum, v: ptr GLdouble) {.importc.} + proc glMultiTexRenderbufferEXT(texunit: GLenum, target: GLenum, renderbuffer: GLuint) {.importc.} + proc glMultiDrawArraysIndirect(mode: GLenum, indirect: ptr pointer, drawcount: GLsizei, stride: GLsizei) {.importc.} + proc glGetUniformfvARB(programObj: GLhandleArb, location: GLint, params: ptr GLfloat) {.importc.} + proc glBufferDataARB(target: GLenum, size: GLsizeiptrArb, data: pointer, usage: GLenum) {.importc.} + proc glTexCoord2d(s: GLdouble, t: GLdouble) {.importc.} + proc glGetArrayObjectfvATI(`array`: GLenum, pname: GLenum, params: ptr GLfloat) {.importc.} + proc glShaderOp1EXT(op: GLenum, res: GLuint, arg1: GLuint) {.importc.} + proc glColor3s(red: GLshort, green: GLshort, blue: GLshort) {.importc.} + proc glStencilFuncSeparate(face: GLenum, fun: GLenum, `ref`: GLint, mask: GLuint) {.importc.} + proc glTextureImage2DMultisampleCoverageNV(texture: GLuint, target: GLenum, coverageSamples: GLsizei, colorSamples: GLsizei, internalFormat: GLint, width: GLsizei, height: GLsizei, fixedSampleLocations: GLboolean) {.importc.} + proc glMultiTexCoord2xvOES(texture: GLenum, coords: ptr GLfixed) {.importc.} + proc glGetVertexAttribLui64vNV(index: GLuint, pname: GLenum, params: ptr GLuint64Ext) {.importc.} + proc glNormal3xOES(nx: GLfixed, ny: GLfixed, nz: GLfixed) {.importc.} + proc glMapBufferRangeEXT(target: GLenum, offset: GLintptr, length: GLsizeiptr, access: GLbitfield): pointer {.importc.} + proc glCreateShader(`type`: GLenum): GLuint {.importc.} + proc glDrawRangeElementArrayAPPLE(mode: GLenum, start: GLuint, `end`: GLuint, first: GLint, count: GLsizei) {.importc.} + proc glVertex2bOES(x: GLbyte) {.importc.} + proc glGetMapxvOES(target: GLenum, query: GLenum, v: ptr GLfixed) {.importc.} + proc glRasterPos3sv(v: ptr GLshort) {.importc.} + proc glDeleteQueriesARB(n: GLsizei, ids: ptr GLuint) {.importc.} + proc glProgramUniform1iv(program: GLuint, location: GLint, count: GLsizei, value: ptr GLint) {.importc.} + proc glVertexStream2dvATI(stream: GLenum, coords: ptr GLdouble) {.importc.} + proc glBindVertexArrayOES(`array`: GLuint) {.importc.} + proc glLightModelfv(pname: GLenum, params: ptr GLfloat) {.importc.} + proc glEvalCoord2dv(u: ptr GLdouble) {.importc.} + proc glColor3hNV(red: GLhalfNv, green: GLhalfNv, blue: GLhalfNv) {.importc.} + proc glSecondaryColor3iEXT(red: GLint, green: GLint, blue: GLint) {.importc.} + proc glBindTexture(target: GLenum, texture: GLuint) {.importc.} + proc glUniformBufferEXT(program: GLuint, location: GLint, buffer: GLuint) {.importc.} + proc glGetCombinerInputParameterfvNV(stage: GLenum, portion: GLenum, variable: GLenum, pname: GLenum, params: ptr GLfloat) {.importc.} + proc glUniform2ui64vNV(location: GLint, count: GLsizei, value: ptr GLuint64Ext) {.importc.} + proc glMatrixMultTransposefEXT(mode: GLenum, m: ptr GLfloat) {.importc.} + proc glLineWidth(width: GLfloat) {.importc.} + proc glRotatef(angle: GLfloat, x: GLfloat, y: GLfloat, z: GLfloat) {.importc.} + proc glNormalStream3svATI(stream: GLenum, coords: ptr GLshort) {.importc.} + proc glTexCoordP4ui(`type`: GLenum, coords: GLuint) {.importc.} + proc glImageTransformParameterfvHP(target: GLenum, pname: GLenum, params: ptr GLfloat) {.importc.} + proc glUniform3uiEXT(location: GLint, v0: GLuint, v1: GLuint, v2: GLuint) {.importc.} + proc glGetInvariantIntegervEXT(id: GLuint, value: GLenum, data: ptr GLint) {.importc.} + proc glGetTransformFeedbackVaryingEXT(program: GLuint, index: GLuint, bufSize: GLsizei, length: ptr GLsizei, size: ptr GLsizei, `type`: ptr GLenum, name: cstring) {.importc.} + proc glSamplerParameterIuiv(sampler: GLuint, pname: GLenum, param: ptr GLuint) {.importc.} + proc glProgramUniform2fEXT(program: GLuint, location: GLint, v0: GLfloat, v1: GLfloat) {.importc.} + proc glMultiTexCoord2hvNV(target: GLenum, v: ptr GLhalfNv) {.importc.} + proc glDeleteRenderbuffersOES(n: GLsizei, renderbuffers: ptr GLuint) {.importc.} + proc glRenderbufferStorageMultisampleCoverageNV(target: GLenum, coverageSamples: GLsizei, colorSamples: GLsizei, internalformat: GLenum, width: GLsizei, height: GLsizei) {.importc.} + proc glStencilClearTagEXT(stencilTagBits: GLsizei, stencilClearTag: GLuint) {.importc.} + proc glConvolutionParameteriv(target: GLenum, pname: GLenum, params: ptr GLint) {.importc.} + proc glFenceSyncAPPLE(condition: GLenum, flags: GLbitfield): GLsync {.importc.} + proc glGetVariantArrayObjectivATI(id: GLuint, pname: GLenum, params: ptr GLint) {.importc.} + proc glProgramUniform4dvEXT(program: GLuint, location: GLint, count: GLsizei, value: ptr GLdouble) {.importc.} + proc glPushDebugGroupKHR(source: GLenum, id: GLuint, length: GLsizei, message: cstring) {.importc.} + proc glFragmentLightivSGIX(light: GLenum, pname: GLenum, params: ptr GLint) {.importc.} + proc glFramebufferTexture2DEXT(target: GLenum, attachment: GLenum, textarget: GLenum, texture: GLuint, level: GLint) {.importc.} + proc glGetActiveSubroutineUniformiv(program: GLuint, shadertype: GLenum, index: GLuint, pname: GLenum, values: ptr GLint) {.importc.} + proc glFrustumf(l: GLfloat, r: GLfloat, b: GLfloat, t: GLfloat, n: GLfloat, f: GLfloat) {.importc.} + proc glEndQueryIndexed(target: GLenum, index: GLuint) {.importc.} + proc glCompressedTextureSubImage3DEXT(texture: GLuint, target: GLenum, level: GLint, xoffset: GLint, yoffset: GLint, zoffset: GLint, width: GLsizei, height: GLsizei, depth: GLsizei, format: GLenum, imageSize: GLsizei, bits: pointer) {.importc.} + proc glGetProgramPipelineInfoLogEXT(pipeline: GLuint, bufSize: GLsizei, length: ptr GLsizei, infoLog: cstring) {.importc.} + proc glGetVertexAttribfvNV(index: GLuint, pname: GLenum, params: ptr GLfloat) {.importc.} + proc glVertexArrayIndexOffsetEXT(vaobj: GLuint, buffer: GLuint, `type`: GLenum, stride: GLsizei, offset: GLintptr) {.importc.} + proc glDrawTexsvOES(coords: ptr GLshort) {.importc.} + proc glMultiTexCoord1hNV(target: GLenum, s: GLhalfNv) {.importc.} + proc glWindowPos2iv(v: ptr GLint) {.importc.} + proc glMultiTexCoordP1ui(texture: GLenum, `type`: GLenum, coords: GLuint) {.importc.} + proc glTexCoord1i(s: GLint) {.importc.} + proc glVertex4hvNV(v: ptr GLhalfNv) {.importc.} + proc glCallLists(n: GLsizei, `type`: GLenum, lists: pointer) {.importc.} + proc glIndexFormatNV(`type`: GLenum, stride: GLsizei) {.importc.} + proc glPointParameterfARB(pname: GLenum, param: GLfloat) {.importc.} + proc glProgramUniform1dv(program: GLuint, location: GLint, count: GLsizei, value: ptr GLdouble) {.importc.} + proc glGetVertexAttribArrayObjectfvATI(index: GLuint, pname: GLenum, params: ptr GLfloat) {.importc.} + proc glVDPAUUnmapSurfacesNV(numSurface: GLsizei, surfaces: ptr GLvdpauSurfaceNv) {.importc.} + proc glVertexAttribIFormat(attribindex: GLuint, size: GLint, `type`: GLenum, relativeoffset: GLuint) {.importc.} + proc glClearColorx(red: GLfixed, green: GLfixed, blue: GLfixed, alpha: GLfixed) {.importc.} + proc glColor3bv(v: ptr GLbyte) {.importc.} + proc glNamedProgramLocalParameter4dEXT(program: GLuint, target: GLenum, index: GLuint, x: GLdouble, y: GLdouble, z: GLdouble, w: GLdouble) {.importc.} + proc glVertexPointer(size: GLint, `type`: GLenum, stride: GLsizei, `pointer`: pointer) {.importc.} + proc glGetObjectLabelKHR(identifier: GLenum, name: GLuint, bufSize: GLsizei, length: ptr GLsizei, label: cstring) {.importc.} + proc glCombinerStageParameterfvNV(stage: GLenum, pname: GLenum, params: ptr GLfloat) {.importc.} + proc glNormal3hvNV(v: ptr GLhalfNv) {.importc.} + proc glUniform2i64NV(location: GLint, x: GLint64Ext, y: GLint64Ext) {.importc.} + proc glMultiTexCoord2iv(target: GLenum, v: ptr GLint) {.importc.} + proc glProgramUniform3i(program: GLuint, location: GLint, v0: GLint, v1: GLint, v2: GLint) {.importc.} + proc glDeleteAsyncMarkersSGIX(marker: GLuint, range: GLsizei) {.importc.} + proc glStencilOp(fail: GLenum, zfail: GLenum, zpass: GLenum) {.importc.} + proc glColorP4ui(`type`: GLenum, color: GLuint) {.importc.} + proc glFinishAsyncSGIX(markerp: ptr GLuint): GLint {.importc.} + proc glDrawTexsOES(x: GLshort, y: GLshort, z: GLshort, width: GLshort, height: GLshort) {.importc.} + proc glLineStipple(factor: GLint, pattern: GLushort) {.importc.} + proc glAlphaFragmentOp1ATI(op: GLenum, dst: GLuint, dstMod: GLuint, arg1: GLuint, arg1Rep: GLuint, arg1Mod: GLuint) {.importc.} + proc glMapTexture2DINTEL(texture: GLuint, level: GLint, access: GLbitfield, stride: ptr GLint, layout: ptr GLenum): pointer {.importc.} + proc glVertex4f(x: GLfloat, y: GLfloat, z: GLfloat, w: GLfloat) {.importc.} + proc glFramebufferTextureARB(target: GLenum, attachment: GLenum, texture: GLuint, level: GLint) {.importc.} + proc glProgramUniform3ui64NV(program: GLuint, location: GLint, x: GLuint64Ext, y: GLuint64Ext, z: GLuint64Ext) {.importc.} + proc glMultTransposeMatrixxOES(m: ptr GLfixed) {.importc.} + proc glNormal3fv(v: ptr GLfloat) {.importc.} + proc glUniform4fARB(location: GLint, v0: GLfloat, v1: GLfloat, v2: GLfloat, v3: GLfloat) {.importc.} + proc glBinormal3bEXT(bx: GLbyte, by: GLbyte, bz: GLbyte) {.importc.} + proc glGenProgramPipelinesEXT(n: GLsizei, pipelines: ptr GLuint) {.importc.} + proc glDispatchComputeIndirect(indirect: GLintptr) {.importc.} + proc glGetPerfMonitorCounterDataAMD(monitor: GLuint, pname: GLenum, dataSize: GLsizei, data: ptr GLuint, bytesWritten: ptr GLint) {.importc.} + proc glStencilOpValueAMD(face: GLenum, value: GLuint) {.importc.} + proc glTangent3fvEXT(v: ptr GLfloat) {.importc.} + proc glUniform3iARB(location: GLint, v0: GLint, v1: GLint, v2: GLint) {.importc.} + proc glMatrixScalefEXT(mode: GLenum, x: GLfloat, y: GLfloat, z: GLfloat) {.importc.} + proc glVertexAttrib2dARB(index: GLuint, x: GLdouble, y: GLdouble) {.importc.} + proc glIsVertexArray(`array`: GLuint): GLboolean {.importc.} + proc glGetMaterialx(face: GLenum, pname: GLenum, param: GLfixed) {.importc.} + proc glMultiTexCoord1dARB(target: GLenum, s: GLdouble) {.importc.} + proc glColor3usv(v: ptr GLushort) {.importc.} + proc glVertexStream3svATI(stream: GLenum, coords: ptr GLshort) {.importc.} + proc glRasterPos3s(x: GLshort, y: GLshort, z: GLshort) {.importc.} + proc glMultiTexCoord2bOES(texture: GLenum, s: GLbyte, t: GLbyte) {.importc.} + proc glGetClipPlanefOES(plane: GLenum, equation: ptr GLfloat) {.importc.} + proc glFramebufferTextureEXT(target: GLenum, attachment: GLenum, texture: GLuint, level: GLint) {.importc.} + proc glVertexAttrib1dNV(index: GLuint, x: GLdouble) {.importc.} + proc glSampleCoverageOES(value: GLfixed, invert: GLboolean) {.importc.} + proc glCompressedTexSubImage2DARB(target: GLenum, level: GLint, xoffset: GLint, yoffset: GLint, width: GLsizei, height: GLsizei, format: GLenum, imageSize: GLsizei, data: pointer) {.importc.} + proc glUniform1iv(location: GLint, count: GLsizei, value: ptr GLint) {.importc.} + proc glExtGetProgramsQCOM(programs: ptr GLuint, maxPrograms: GLint, numPrograms: ptr GLint) {.importc.} + proc glFogx(pname: GLenum, param: GLfixed) {.importc.} + proc glMultiTexCoord3hNV(target: GLenum, s: GLhalfNv, t: GLhalfNv, r: GLhalfNv) {.importc.} + proc glClipPlane(plane: GLenum, equation: ptr GLdouble) {.importc.} + proc glConvolutionParameterxvOES(target: GLenum, pname: GLenum, params: ptr GLfixed) {.importc.} + proc glInvalidateBufferData(buffer: GLuint) {.importc.} + proc glCheckNamedFramebufferStatusEXT(framebuffer: GLuint, target: GLenum): GLenum {.importc.} + proc glLinkProgram(program: GLuint) {.importc.} + proc glCheckFramebufferStatus(target: GLenum): GLenum {.importc.} + proc glBlendFunci(buf: GLuint, src: GLenum, dst: GLenum) {.importc.} + proc glProgramUniform4uiv(program: GLuint, location: GLint, count: GLsizei, value: ptr GLuint) {.importc.} + proc glConvolutionFilter2D(target: GLenum, internalformat: GLenum, width: GLsizei, height: GLsizei, format: GLenum, `type`: GLenum, image: pointer) {.importc.} + proc glVertex4bvOES(coords: ptr GLbyte) {.importc.} + proc glCopyTextureSubImage1DEXT(texture: GLuint, target: GLenum, level: GLint, xoffset: GLint, x: GLint, y: GLint, width: GLsizei) {.importc.} + proc glColor4uiv(v: ptr GLuint) {.importc.} + proc glGetBufferParameteri64v(target: GLenum, pname: GLenum, params: ptr GLint64) {.importc.} + proc glGetLocalConstantBooleanvEXT(id: GLuint, value: GLenum, data: ptr GLboolean) {.importc.} + proc glCoverStrokePathNV(path: GLuint, coverMode: GLenum) {.importc.} + proc glScaled(x: GLdouble, y: GLdouble, z: GLdouble) {.importc.} + proc glLightfv(light: GLenum, pname: GLenum, params: ptr GLfloat) {.importc.} + proc glTexParameterIiv(target: GLenum, pname: GLenum, params: ptr GLint) {.importc.} + proc glMakeImageHandleResidentNV(handle: GLuint64, access: GLenum) {.importc.} + proc glWindowPos3iARB(x: GLint, y: GLint, z: GLint) {.importc.} + proc glListBase(base: GLuint) {.importc.} + proc glFlushMappedBufferRangeEXT(target: GLenum, offset: GLintptr, length: GLsizeiptr) {.importc.} + proc glNormal3dv(v: ptr GLdouble) {.importc.} + proc glProgramUniform4d(program: GLuint, location: GLint, v0: GLdouble, v1: GLdouble, v2: GLdouble, v3: GLdouble) {.importc.} + proc glCreateShaderProgramEXT(`type`: GLenum, string: cstring): GLuint {.importc.} + proc glGetLightxvOES(light: GLenum, pname: GLenum, params: ptr GLfixed) {.importc.} + proc glGetObjectPtrLabelKHR(`ptr`: ptr pointer, bufSize: GLsizei, length: ptr GLsizei, label: cstring) {.importc.} + proc glTransformPathNV(resultPath: GLuint, srcPath: GLuint, transformType: GLenum, transformValues: ptr GLfloat) {.importc.} + proc glMultTransposeMatrixf(m: ptr GLfloat) {.importc.} + proc glMapVertexAttrib2dAPPLE(index: GLuint, size: GLuint, u1: GLdouble, u2: GLdouble, ustride: GLint, uorder: GLint, v1: GLdouble, v2: GLdouble, vstride: GLint, vorder: GLint, points: ptr GLdouble) {.importc.} + proc glIsSync(sync: GLsync): GLboolean {.importc.} + proc glMultMatrixx(m: ptr GLfixed) {.importc.} + proc glInterpolatePathsNV(resultPath: GLuint, pathA: GLuint, pathB: GLuint, weight: GLfloat) {.importc.} + proc glEnableClientStateIndexedEXT(`array`: GLenum, index: GLuint) {.importc.} + proc glProgramEnvParameter4fARB(target: GLenum, index: GLuint, x: GLfloat, y: GLfloat, z: GLfloat, w: GLfloat) {.importc.} + proc glVertexAttrib2svARB(index: GLuint, v: ptr GLshort) {.importc.} + proc glLighti(light: GLenum, pname: GLenum, param: GLint) {.importc.} + proc glSelectBuffer(size: GLsizei, buffer: ptr GLuint) {.importc.} + proc glReplacementCodeusvSUN(code: ptr GLushort) {.importc.} + proc glMapVertexAttrib1fAPPLE(index: GLuint, size: GLuint, u1: GLfloat, u2: GLfloat, stride: GLint, order: GLint, points: ptr GLfloat) {.importc.} + proc glMaterialx(face: GLenum, pname: GLenum, param: GLfixed) {.importc.} + proc glDrawTransformFeedback(mode: GLenum, id: GLuint) {.importc.} + proc glWindowPos2i(x: GLint, y: GLint) {.importc.} + proc glMultiTexEnviEXT(texunit: GLenum, target: GLenum, pname: GLenum, param: GLint) {.importc.} + proc glProgramUniform1fv(program: GLuint, location: GLint, count: GLsizei, value: ptr GLfloat) {.importc.} + proc glDrawBuffersARB(n: GLsizei, bufs: ptr GLenum) {.importc.} + proc glGetUniformLocationARB(programObj: GLhandleArb, name: cstring): GLint {.importc.} + proc glResumeTransformFeedback() {.importc.} + proc glMap1f(target: GLenum, u1: GLfloat, u2: GLfloat, stride: GLint, order: GLint, points: ptr GLfloat) {.importc.} + proc glVertex3xOES(x: GLfixed, y: GLfixed) {.importc.} + proc glPathCoordsNV(path: GLuint, numCoords: GLsizei, coordType: GLenum, coords: pointer) {.importc.} + proc glListParameterfSGIX(list: GLuint, pname: GLenum, param: GLfloat) {.importc.} + proc glGetUniformivARB(programObj: GLhandleArb, location: GLint, params: ptr GLint) {.importc.} + proc glBinormal3bvEXT(v: ptr GLbyte) {.importc.} + proc glVertexAttribP3ui(index: GLuint, `type`: GLenum, normalized: GLboolean, value: GLuint) {.importc.} + proc glGetVertexArrayPointeri_vEXT(vaobj: GLuint, index: GLuint, pname: GLenum, param: ptr pointer) {.importc.} + proc glProgramParameter4fvNV(target: GLenum, index: GLuint, v: ptr GLfloat) {.importc.} + proc glDiscardFramebufferEXT(target: GLenum, numAttachments: GLsizei, attachments: ptr GLenum) {.importc.} + proc glGetDebugMessageLogARB(count: GLuint, bufsize: GLsizei, sources: ptr GLenum, types: ptr GLenum, ids: ptr GLuint, severities: ptr GLenum, lengths: ptr GLsizei, messageLog: cstring): GLuint {.importc.} + proc glResolveMultisampleFramebufferAPPLE() {.importc.} + proc glGetIntegeri_vEXT(target: GLenum, index: GLuint, data: ptr GLint) {.importc.} + proc glDepthBoundsdNV(zmin: GLdouble, zmax: GLdouble) {.importc.} + proc glEnd() {.importc.} + proc glBindBufferBaseEXT(target: GLenum, index: GLuint, buffer: GLuint) {.importc.} + proc glVertexAttribDivisor(index: GLuint, divisor: GLuint) {.importc.} + proc glFogCoorddEXT(coord: GLdouble) {.importc.} + proc glFrontFace(mode: GLenum) {.importc.} + proc glVertexAttrib1hNV(index: GLuint, x: GLhalfNv) {.importc.} + proc glNamedProgramLocalParametersI4uivEXT(program: GLuint, target: GLenum, index: GLuint, count: GLsizei, params: ptr GLuint) {.importc.} + proc glTexCoord1dv(v: ptr GLdouble) {.importc.} + proc glBindVideoCaptureStreamTextureNV(video_capture_slot: GLuint, stream: GLuint, frame_region: GLenum, target: GLenum, texture: GLuint) {.importc.} + proc glWindowPos2iARB(x: GLint, y: GLint) {.importc.} + proc glVertexAttribFormatNV(index: GLuint, size: GLint, `type`: GLenum, normalized: GLboolean, stride: GLsizei) {.importc.} + proc glUniform1uivEXT(location: GLint, count: GLsizei, value: ptr GLuint) {.importc.} + proc glGetVideoivNV(video_slot: GLuint, pname: GLenum, params: ptr GLint) {.importc.} + proc glVertexAttrib3fvARB(index: GLuint, v: ptr GLfloat) {.importc.} + proc glVertexArraySecondaryColorOffsetEXT(vaobj: GLuint, buffer: GLuint, size: GLint, `type`: GLenum, stride: GLsizei, offset: GLintptr) {.importc.} + proc glSecondaryColor3bv(v: ptr GLbyte) {.importc.} + proc glDispatchComputeGroupSizeARB(num_groups_x: GLuint, num_groups_y: GLuint, num_groups_z: GLuint, group_size_x: GLuint, group_size_y: GLuint, group_size_z: GLuint) {.importc.} + proc glNamedCopyBufferSubDataEXT(readBuffer: GLuint, writeBuffer: GLuint, readOffset: GLintptr, writeOffset: GLintptr, size: GLsizeiptr) {.importc.} + proc glSampleCoverage(value: GLfloat, invert: GLboolean) {.importc.} + proc glGetnMapfvARB(target: GLenum, query: GLenum, bufSize: GLsizei, v: ptr GLfloat) {.importc.} + proc glVertexStream2svATI(stream: GLenum, coords: ptr GLshort) {.importc.} + proc glProgramParameters4fvNV(target: GLenum, index: GLuint, count: GLsizei, v: ptr GLfloat) {.importc.} + proc glVertexAttrib4fARB(index: GLuint, x: GLfloat, y: GLfloat, z: GLfloat, w: GLfloat) {.importc.} + proc glIndexd(c: GLdouble) {.importc.} + proc glGetInteger64v(pname: GLenum, params: ptr GLint64) {.importc.} + proc glGetMultiTexImageEXT(texunit: GLenum, target: GLenum, level: GLint, format: GLenum, `type`: GLenum, pixels: pointer) {.importc.} + proc glLightModelx(pname: GLenum, param: GLfixed) {.importc.} + proc glMap2f(target: GLenum, u1: GLfloat, u2: GLfloat, ustride: GLint, uorder: GLint, v1: GLfloat, v2: GLfloat, vstride: GLint, vorder: GLint, points: ptr GLfloat) {.importc.} + proc glSecondaryColorPointerListIBM(size: GLint, `type`: GLenum, stride: GLint, `pointer`: ptr pointer, ptrstride: GLint) {.importc.} + proc glVertexArrayVertexAttribIOffsetEXT(vaobj: GLuint, buffer: GLuint, index: GLuint, size: GLint, `type`: GLenum, stride: GLsizei, offset: GLintptr) {.importc.} + proc glProgramUniformHandleui64vARB(program: GLuint, location: GLint, count: GLsizei, values: ptr GLuint64) {.importc.} + proc glActiveProgramEXT(program: GLuint) {.importc.} + proc glProgramUniformMatrix4x3fv(program: GLuint, location: GLint, count: GLsizei, transpose: GLboolean, value: ptr GLfloat) {.importc.} + proc glCompressedTexSubImage3DARB(target: GLenum, level: GLint, xoffset: GLint, yoffset: GLint, zoffset: GLint, width: GLsizei, height: GLsizei, depth: GLsizei, format: GLenum, imageSize: GLsizei, data: pointer) {.importc.} + proc glBindProgramPipelineEXT(pipeline: GLuint) {.importc.} + proc glDetailTexFuncSGIS(target: GLenum, n: GLsizei, points: ptr GLfloat) {.importc.} + proc glSecondaryColor3ubEXT(red: GLubyte, green: GLubyte, blue: GLubyte) {.importc.} + proc glDrawArraysInstanced(mode: GLenum, first: GLint, count: GLsizei, instancecount: GLsizei) {.importc.} + proc glWindowPos3fARB(x: GLfloat, y: GLfloat, z: GLfloat) {.importc.} + proc glNamedProgramLocalParameter4fEXT(program: GLuint, target: GLenum, index: GLuint, x: GLfloat, y: GLfloat, z: GLfloat, w: GLfloat) {.importc.} + proc glTextureParameterfvEXT(texture: GLuint, target: GLenum, pname: GLenum, params: ptr GLfloat) {.importc.} + proc glProgramUniformHandleui64ARB(program: GLuint, location: GLint, value: GLuint64) {.importc.} + proc glHistogramEXT(target: GLenum, width: GLsizei, internalformat: GLenum, sink: GLboolean) {.importc.} + proc glResumeTransformFeedbackNV() {.importc.} + proc glGetMaterialxv(face: GLenum, pname: GLenum, params: ptr GLfixed) {.importc.} + proc glMultiTexCoord1sv(target: GLenum, v: ptr GLshort) {.importc.} + proc glReadInstrumentsSGIX(marker: GLint) {.importc.} + proc glTexCoord4hNV(s: GLhalfNv, t: GLhalfNv, r: GLhalfNv, q: GLhalfNv) {.importc.} + proc glVertexAttribL4i64vNV(index: GLuint, v: ptr GLint64Ext) {.importc.} + proc glEnableVariantClientStateEXT(id: GLuint) {.importc.} + proc glSyncTextureINTEL(texture: GLuint) {.importc.} + proc glGetObjectPtrLabel(`ptr`: ptr pointer, bufSize: GLsizei, length: ptr GLsizei, label: cstring) {.importc.} + proc glCopyTexSubImage1D(target: GLenum, level: GLint, xoffset: GLint, x: GLint, y: GLint, width: GLsizei) {.importc.} + proc glOrthofOES(l: GLfloat, r: GLfloat, b: GLfloat, t: GLfloat, n: GLfloat, f: GLfloat) {.importc.} + proc glWindowPos3sARB(x: GLshort, y: GLshort, z: GLshort) {.importc.} + proc glIsBufferARB(buffer: GLuint): GLboolean {.importc.} + proc glColor3sv(v: ptr GLshort) {.importc.} + proc glEvalMesh1(mode: GLenum, i1: GLint, i2: GLint) {.importc.} + proc glMultiDrawArrays(mode: GLenum, first: ptr GLint, count: ptr GLsizei, drawcount: GLsizei) {.importc.} + proc glGetMultiTexEnvfvEXT(texunit: GLenum, target: GLenum, pname: GLenum, params: ptr GLfloat) {.importc.} + proc glWindowPos3fMESA(x: GLfloat, y: GLfloat, z: GLfloat) {.importc.} + proc glExtGetFramebuffersQCOM(framebuffers: ptr GLuint, maxFramebuffers: GLint, numFramebuffers: ptr GLint) {.importc.} + proc glTexSubImage3D(target: GLenum, level: GLint, xoffset: GLint, yoffset: GLint, zoffset: GLint, width: GLsizei, height: GLsizei, depth: GLsizei, format: GLenum, `type`: GLenum, pixels: pointer) {.importc.} + proc glVertexAttrib4uiv(index: GLuint, v: ptr GLuint) {.importc.} + proc glProgramUniformui64NV(program: GLuint, location: GLint, value: GLuint64Ext) {.importc.} + proc glMultiTexCoord2ivARB(target: GLenum, v: ptr GLint) {.importc.} + proc glProgramUniform4i64NV(program: GLuint, location: GLint, x: GLint64Ext, y: GLint64Ext, z: GLint64Ext, w: GLint64Ext) {.importc.} + proc glWindowPos2svMESA(v: ptr GLshort) {.importc.} + proc glVertexAttrib3dv(index: GLuint, v: ptr GLdouble) {.importc.} + proc glColor4i(red: GLint, green: GLint, blue: GLint, alpha: GLint) {.importc.} + proc glClampColor(target: GLenum, clamp: GLenum) {.importc.} + proc glVertexP2ui(`type`: GLenum, value: GLuint) {.importc.} + proc glGenQueries(n: GLsizei, ids: ptr GLuint) {.importc.} + proc glBindBufferOffsetNV(target: GLenum, index: GLuint, buffer: GLuint, offset: GLintptr) {.importc.} + proc glGetFragDataLocation(program: GLuint, name: cstring): GLint {.importc.} + proc glVertexAttribs2svNV(index: GLuint, count: GLsizei, v: ptr GLshort) {.importc.} + proc glGetPathLengthNV(path: GLuint, startSegment: GLsizei, numSegments: GLsizei): GLfloat {.importc.} + proc glVertexAttrib3dARB(index: GLuint, x: GLdouble, y: GLdouble, z: GLdouble) {.importc.} + proc glMultiTexGenfvEXT(texunit: GLenum, coord: GLenum, pname: GLenum, params: ptr GLfloat) {.importc.} + proc glFlushPixelDataRangeNV(target: GLenum) {.importc.} + proc glReplacementCodeuiNormal3fVertex3fSUN(rc: GLuint, nx: GLfloat, ny: GLfloat, nz: GLfloat, x: GLfloat, y: GLfloat, z: GLfloat) {.importc.} + proc glPathParameteriNV(path: GLuint, pname: GLenum, value: GLint) {.importc.} + proc glVertexAttribI2iEXT(index: GLuint, x: GLint, y: GLint) {.importc.} + proc glPixelStorei(pname: GLenum, param: GLint) {.importc.} + proc glGetNamedFramebufferParameterivEXT(framebuffer: GLuint, pname: GLenum, params: ptr GLint) {.importc.} + proc glGetTexEnvxv(target: GLenum, pname: GLenum, params: ptr GLfixed) {.importc.} + proc glPathStringNV(path: GLuint, format: GLenum, length: GLsizei, pathString: pointer) {.importc.} + proc glDepthMask(flag: GLboolean) {.importc.} + proc glCopyTexImage1D(target: GLenum, level: GLint, internalformat: GLenum, x: GLint, y: GLint, width: GLsizei, border: GLint) {.importc.} + proc glDepthRangexOES(n: GLfixed, f: GLfixed) {.importc.} + proc glUniform2i64vNV(location: GLint, count: GLsizei, value: ptr GLint64Ext) {.importc.} + proc glSetFragmentShaderConstantATI(dst: GLuint, value: ptr GLfloat) {.importc.} + proc glAttachShader(program: GLuint, shader: GLuint) {.importc.} + proc glGetFramebufferParameterivEXT(framebuffer: GLuint, pname: GLenum, params: ptr GLint) {.importc.} + proc glPointParameteriNV(pname: GLenum, param: GLint) {.importc.} + proc glWindowPos2dMESA(x: GLdouble, y: GLdouble) {.importc.} + proc glGetTextureParameterfvEXT(texture: GLuint, target: GLenum, pname: GLenum, params: ptr GLfloat) {.importc.} + proc glTexBumpParameterfvATI(pname: GLenum, param: ptr GLfloat) {.importc.} + proc glCompressedTexImage1DARB(target: GLenum, level: GLint, internalformat: GLenum, width: GLsizei, border: GLint, imageSize: GLsizei, data: pointer) {.importc.} + proc glGetTexGendv(coord: GLenum, pname: GLenum, params: ptr GLdouble) {.importc.} + proc glGetFragmentMaterialfvSGIX(face: GLenum, pname: GLenum, params: ptr GLfloat) {.importc.} + proc glBeginConditionalRenderNVX(id: GLuint) {.importc.} + proc glLightModelxOES(pname: GLenum, param: GLfixed) {.importc.} + proc glTexCoord2xOES(s: GLfixed, t: GLfixed) {.importc.} + proc glProgramUniformMatrix2x4fvEXT(program: GLuint, location: GLint, count: GLsizei, transpose: GLboolean, value: ptr GLfloat) {.importc.} + proc glRasterPos2xvOES(coords: ptr GLfixed) {.importc.} + proc glGetMapiv(target: GLenum, query: GLenum, v: ptr GLint) {.importc.} + proc glGetImageHandleARB(texture: GLuint, level: GLint, layered: GLboolean, layer: GLint, format: GLenum): GLuint64 {.importc.} + proc glVDPAURegisterVideoSurfaceNV(vdpSurface: pointer, target: GLenum, numTextureNames: GLsizei, textureNames: ptr GLuint): GLvdpauSurfaceNv {.importc.} + proc glVertexAttribL2dEXT(index: GLuint, x: GLdouble, y: GLdouble) {.importc.} + proc glVertexAttrib1dvNV(index: GLuint, v: ptr GLdouble) {.importc.} + proc glPollAsyncSGIX(markerp: ptr GLuint): GLint {.importc.} + proc glCullParameterfvEXT(pname: GLenum, params: ptr GLfloat) {.importc.} + proc glMakeNamedBufferResidentNV(buffer: GLuint, access: GLenum) {.importc.} + proc glPointParameterfSGIS(pname: GLenum, param: GLfloat) {.importc.} + proc glGenLists(range: GLsizei): GLuint {.importc.} + proc glGetTexBumpParameterfvATI(pname: GLenum, param: ptr GLfloat) {.importc.} + proc glCompressedMultiTexSubImage2DEXT(texunit: GLenum, target: GLenum, level: GLint, xoffset: GLint, yoffset: GLint, width: GLsizei, height: GLsizei, format: GLenum, imageSize: GLsizei, bits: pointer) {.importc.} + proc glFinishFenceNV(fence: GLuint) {.importc.} + proc glPointSize(size: GLfloat) {.importc.} + proc glCompressedTextureImage2DEXT(texture: GLuint, target: GLenum, level: GLint, internalformat: GLenum, width: GLsizei, height: GLsizei, border: GLint, imageSize: GLsizei, bits: pointer) {.importc.} + proc glGetUniformui64vNV(program: GLuint, location: GLint, params: ptr GLuint64Ext) {.importc.} + proc glGetMapControlPointsNV(target: GLenum, index: GLuint, `type`: GLenum, ustride: GLsizei, vstride: GLsizei, packed: GLboolean, points: pointer) {.importc.} + proc glGetPathColorGenfvNV(color: GLenum, pname: GLenum, value: ptr GLfloat) {.importc.} + proc glTexCoord2f(s: GLfloat, t: GLfloat) {.importc.} + proc glSampleMaski(index: GLuint, mask: GLbitfield) {.importc.} + proc glReadBufferIndexedEXT(src: GLenum, index: GLint) {.importc.} + proc glCoverFillPathNV(path: GLuint, coverMode: GLenum) {.importc.} + proc glColorTableParameterfvSGI(target: GLenum, pname: GLenum, params: ptr GLfloat) {.importc.} + proc glDeleteVertexArraysAPPLE(n: GLsizei, arrays: ptr GLuint) {.importc.} + proc glGetVertexAttribIiv(index: GLuint, pname: GLenum, params: ptr GLint) {.importc.} + proc glWeightbvARB(size: GLint, weights: ptr GLbyte) {.importc.} + proc glGetNamedBufferPointervEXT(buffer: GLuint, pname: GLenum, params: ptr pointer) {.importc.} + proc glTexCoordPointer(size: GLint, `type`: GLenum, stride: GLsizei, `pointer`: pointer) {.importc.} + proc glColor4fv(v: ptr GLfloat) {.importc.} + proc glGetnUniformfvARB(program: GLuint, location: GLint, bufSize: GLsizei, params: ptr GLfloat) {.importc.} + proc glMaterialxOES(face: GLenum, pname: GLenum, param: GLfixed) {.importc.} + proc glGetFixedv(pname: GLenum, params: ptr GLfixed) {.importc.} + proc glMaterialf(face: GLenum, pname: GLenum, param: GLfloat) {.importc.} + proc glVideoCaptureStreamParameterfvNV(video_capture_slot: GLuint, stream: GLuint, pname: GLenum, params: ptr GLfloat) {.importc.} + proc glGetDebugMessageLogAMD(count: GLuint, bufsize: GLsizei, categories: ptr GLenum, severities: ptr GLuint, ids: ptr GLuint, lengths: ptr GLsizei, message: cstring): GLuint {.importc.} + proc glProgramUniform2uiv(program: GLuint, location: GLint, count: GLsizei, value: ptr GLuint) {.importc.} + proc glMatrixMultTransposedEXT(mode: GLenum, m: ptr GLdouble) {.importc.} + proc glIsPointInStrokePathNV(path: GLuint, x: GLfloat, y: GLfloat): GLboolean {.importc.} + proc glDisable(cap: GLenum) {.importc.} + proc glCompileShader(shader: GLuint) {.importc.} + proc glLoadTransposeMatrixd(m: ptr GLdouble) {.importc.} + proc glGetMultiTexParameterIuivEXT(texunit: GLenum, target: GLenum, pname: GLenum, params: ptr GLuint) {.importc.} + proc glGetHistogram(target: GLenum, reset: GLboolean, format: GLenum, `type`: GLenum, values: pointer) {.importc.} + proc glMultiTexCoord3fvARB(target: GLenum, v: ptr GLfloat) {.importc.} + proc glColor4xvOES(components: ptr GLfixed) {.importc.} + proc glIsBuffer(buffer: GLuint): GLboolean {.importc.} + proc glVertex2dv(v: ptr GLdouble) {.importc.} + proc glNamedProgramLocalParameterI4uivEXT(program: GLuint, target: GLenum, index: GLuint, params: ptr GLuint) {.importc.} + proc glPixelTexGenParameteriSGIS(pname: GLenum, param: GLint) {.importc.} + proc glBindVertexBuffers(first: GLuint, count: GLsizei, buffers: ptr GLuint, offsets: ptr GLintptr, strides: ptr GLsizei) {.importc.} + proc glUniform1ui64vNV(location: GLint, count: GLsizei, value: ptr GLuint64Ext) {.importc.} + proc glColor4ub(red: GLubyte, green: GLubyte, blue: GLubyte, alpha: GLubyte) {.importc.} + proc glConvolutionParameterfv(target: GLenum, pname: GLenum, params: ptr GLfloat) {.importc.} + proc glReplacementCodeuiColor4fNormal3fVertex3fSUN(rc: GLuint, r: GLfloat, g: GLfloat, b: GLfloat, a: GLfloat, nx: GLfloat, ny: GLfloat, nz: GLfloat, x: GLfloat, y: GLfloat, z: GLfloat) {.importc.} + proc glVertexAttribI2ui(index: GLuint, x: GLuint, y: GLuint) {.importc.} + proc glDeleteNamesAMD(identifier: GLenum, num: GLuint, names: ptr GLuint) {.importc.} + proc glPixelTransferxOES(pname: GLenum, param: GLfixed) {.importc.} + proc glVertexAttrib4ivARB(index: GLuint, v: ptr GLint) {.importc.} + proc glLightModeli(pname: GLenum, param: GLint) {.importc.} + proc glGetHistogramEXT(target: GLenum, reset: GLboolean, format: GLenum, `type`: GLenum, values: pointer) {.importc.} + proc glWindowPos3svMESA(v: ptr GLshort) {.importc.} + proc glRasterPos3iv(v: ptr GLint) {.importc.} + proc glCopyTextureSubImage3DEXT(texture: GLuint, target: GLenum, level: GLint, xoffset: GLint, yoffset: GLint, zoffset: GLint, x: GLint, y: GLint, width: GLsizei, height: GLsizei) {.importc.} + proc glTextureStorage3DMultisampleEXT(texture: GLuint, target: GLenum, samples: GLsizei, internalformat: GLenum, width: GLsizei, height: GLsizei, depth: GLsizei, fixedsamplelocations: GLboolean) {.importc.} + proc glIsNameAMD(identifier: GLenum, name: GLuint): GLboolean {.importc.} + proc glProgramUniformMatrix3fv(program: GLuint, location: GLint, count: GLsizei, transpose: GLboolean, value: ptr GLfloat) {.importc.} + proc glGetProgramParameterfvNV(target: GLenum, index: GLuint, pname: GLenum, params: ptr GLfloat) {.importc.} + proc glTexStorage3D(target: GLenum, levels: GLsizei, internalformat: GLenum, width: GLsizei, height: GLsizei, depth: GLsizei) {.importc.} + proc glMultiTexCoord2xOES(texture: GLenum, s: GLfixed, t: GLfixed) {.importc.} + proc glWindowPos2fARB(x: GLfloat, y: GLfloat) {.importc.} + proc glGetProgramResourceIndex(program: GLuint, programInterface: GLenum, name: cstring): GLuint {.importc.} + proc glProgramUniform2uivEXT(program: GLuint, location: GLint, count: GLsizei, value: ptr GLuint) {.importc.} + proc glMakeImageHandleNonResidentNV(handle: GLuint64) {.importc.} + proc glNamedProgramLocalParameter4fvEXT(program: GLuint, target: GLenum, index: GLuint, params: ptr GLfloat) {.importc.} + proc glInvalidateFramebuffer(target: GLenum, numAttachments: GLsizei, attachments: ptr GLenum) {.importc.} + proc glTexStorage3DMultisample(target: GLenum, samples: GLsizei, internalformat: GLenum, width: GLsizei, height: GLsizei, depth: GLsizei, fixedsamplelocations: GLboolean) {.importc.} + proc glMapVertexAttrib2fAPPLE(index: GLuint, size: GLuint, u1: GLfloat, u2: GLfloat, ustride: GLint, uorder: GLint, v1: GLfloat, v2: GLfloat, vstride: GLint, vorder: GLint, points: ptr GLfloat) {.importc.} + proc glCombinerParameterfNV(pname: GLenum, param: GLfloat) {.importc.} + proc glCopyMultiTexImage2DEXT(texunit: GLenum, target: GLenum, level: GLint, internalformat: GLenum, x: GLint, y: GLint, width: GLsizei, height: GLsizei, border: GLint) {.importc.} + proc glBindVertexShaderEXT(id: GLuint) {.importc.} + proc glPathGlyphsNV(firstPathName: GLuint, fontTarget: GLenum, fontName: pointer, fontStyle: GLbitfield, numGlyphs: GLsizei, `type`: GLenum, charcodes: pointer, handleMissingGlyphs: GLenum, pathParameterTemplate: GLuint, emScale: GLfloat) {.importc.} + proc glProgramLocalParametersI4uivNV(target: GLenum, index: GLuint, count: GLsizei, params: ptr GLuint) {.importc.} + proc glMultiTexCoord3hvNV(target: GLenum, v: ptr GLhalfNv) {.importc.} + proc glMultiTexCoordP2uiv(texture: GLenum, `type`: GLenum, coords: ptr GLuint) {.importc.} + proc glDisableVariantClientStateEXT(id: GLuint) {.importc.} + proc glGetTexLevelParameterxvOES(target: GLenum, level: GLint, pname: GLenum, params: ptr GLfixed) {.importc.} + proc glRasterPos2sv(v: ptr GLshort) {.importc.} + proc glWeightPathsNV(resultPath: GLuint, numPaths: GLsizei, paths: ptr GLuint, weights: ptr GLfloat) {.importc.} + proc glDrawBuffersNV(n: GLsizei, bufs: ptr GLenum) {.importc.} + proc glBindBufferARB(target: GLenum, buffer: GLuint) {.importc.} + proc glVariantbvEXT(id: GLuint, `addr`: ptr GLbyte) {.importc.} + proc glColorP3uiv(`type`: GLenum, color: ptr GLuint) {.importc.} + proc glBlendEquationEXT(mode: GLenum) {.importc.} + proc glProgramLocalParameterI4uivNV(target: GLenum, index: GLuint, params: ptr GLuint) {.importc.} + proc glRenderMode(mode: GLenum): GLint {.importc.} + proc glVertexStream4fATI(stream: GLenum, x: GLfloat, y: GLfloat, z: GLfloat, w: GLfloat) {.importc.} + proc glGetObjectLabelEXT(`type`: GLenum, `object`: GLuint, bufSize: GLsizei, length: ptr GLsizei, label: cstring) {.importc.} + proc glNamedFramebufferTexture3DEXT(framebuffer: GLuint, attachment: GLenum, textarget: GLenum, texture: GLuint, level: GLint, zoffset: GLint) {.importc.} + proc glLoadMatrixf(m: ptr GLfloat) {.importc.} + proc glGetQueryObjectuivEXT(id: GLuint, pname: GLenum, params: ptr GLuint) {.importc.} + proc glBindVideoCaptureStreamBufferNV(video_capture_slot: GLuint, stream: GLuint, frame_region: GLenum, offset: GLintPtrArb) {.importc.} + proc glMatrixOrthoEXT(mode: GLenum, left: GLdouble, right: GLdouble, bottom: GLdouble, top: GLdouble, zNear: GLdouble, zFar: GLdouble) {.importc.} + proc glBlendFunc(sfactor: GLenum, dfactor: GLenum) {.importc.} + proc glTexGenxvOES(coord: GLenum, pname: GLenum, params: ptr GLfixed) {.importc.} + proc glMatrixMode(mode: GLenum) {.importc.} + proc glColorTableParameterivSGI(target: GLenum, pname: GLenum, params: ptr GLint) {.importc.} + proc glGetProgramInfoLog(program: GLuint, bufSize: GLsizei, length: ptr GLsizei, infoLog: cstring) {.importc.} + proc glGetSeparableFilter(target: GLenum, format: GLenum, `type`: GLenum, row: pointer, column: pointer, span: pointer) {.importc.} + proc glFogfv(pname: GLenum, params: ptr GLfloat) {.importc.} + proc glDrawTexfvOES(coords: ptr GLfloat) {.importc.} + proc glClipPlanexIMG(p: GLenum, eqn: ptr GLfixed) {.importc.} + proc glResetHistogramEXT(target: GLenum) {.importc.} + proc glMemoryBarrier(barriers: GLbitfield) {.importc.} + proc glGetPixelMapusv(map: GLenum, values: ptr GLushort) {.importc.} + proc glEvalCoord2f(u: GLfloat, v: GLfloat) {.importc.} + proc glUniform4uiv(location: GLint, count: GLsizei, value: ptr GLuint) {.importc.} + proc glIsProgramARB(program: GLuint): GLboolean {.importc.} + proc glPointParameterfv(pname: GLenum, params: ptr GLfloat) {.importc.} + proc glTexBuffer(target: GLenum, internalformat: GLenum, buffer: GLuint) {.importc.} + proc glVertexAttrib1s(index: GLuint, x: GLshort) {.importc.} + proc glRenderbufferStorageMultisampleEXT(target: GLenum, samples: GLsizei, internalformat: GLenum, width: GLsizei, height: GLsizei) {.importc.} + proc glMapNamedBufferEXT(buffer: GLuint, access: GLenum): pointer {.importc.} + proc glDebugMessageCallbackAMD(callback: GLdebugProcAmd, userParam: ptr pointer) {.importc.} + proc glGetTexEnvfv(target: GLenum, pname: GLenum, params: ptr GLfloat) {.importc.} + proc glVertexAttribI3uivEXT(index: GLuint, v: ptr GLuint) {.importc.} + proc glMultiTexEnvfEXT(texunit: GLenum, target: GLenum, pname: GLenum, param: GLfloat) {.importc.} + proc glGetUniformiv(program: GLuint, location: GLint, params: ptr GLint) {.importc.} + proc glProgramLocalParameters4fvEXT(target: GLenum, index: GLuint, count: GLsizei, params: ptr GLfloat) {.importc.} + proc glStencilStrokePathInstancedNV(numPaths: GLsizei, pathNameType: GLenum, paths: pointer, pathBase: GLuint, reference: GLint, mask: GLuint, transformType: GLenum, transformValues: ptr GLfloat) {.importc.} + proc glBeginConditionalRender(id: GLuint, mode: GLenum) {.importc.} + proc glVertexAttribI3uiEXT(index: GLuint, x: GLuint, y: GLuint, z: GLuint) {.importc.} + proc glVDPAUMapSurfacesNV(numSurfaces: GLsizei, surfaces: ptr GLvdpauSurfaceNv) {.importc.} + proc glGetProgramResourceName(program: GLuint, programInterface: GLenum, index: GLuint, bufSize: GLsizei, length: ptr GLsizei, name: cstring) {.importc.} + proc glMultiTexCoord4f(target: GLenum, s: GLfloat, t: GLfloat, r: GLfloat, q: GLfloat) {.importc.} + proc glVertexAttrib2hNV(index: GLuint, x: GLhalfNv, y: GLhalfNv) {.importc.} + proc glDrawArraysInstancedNV(mode: GLenum, first: GLint, count: GLsizei, primcount: GLsizei) {.importc.} + proc glClearAccum(red: GLfloat, green: GLfloat, blue: GLfloat, alpha: GLfloat) {.importc.} + proc glVertexAttribI4usv(index: GLuint, v: ptr GLushort) {.importc.} + proc glGetProgramNamedParameterfvNV(id: GLuint, len: GLsizei, name: ptr GLubyte, params: ptr GLfloat) {.importc.} + proc glTextureLightEXT(pname: GLenum) {.importc.} + proc glPathSubCoordsNV(path: GLuint, coordStart: GLsizei, numCoords: GLsizei, coordType: GLenum, coords: pointer) {.importc.} + proc glBindImageTexture(unit: GLuint, texture: GLuint, level: GLint, layered: GLboolean, layer: GLint, access: GLenum, format: GLenum) {.importc.} + proc glGenVertexArraysAPPLE(n: GLsizei, arrays: ptr GLuint) {.importc.} + proc glFogCoordf(coord: GLfloat) {.importc.} + proc glFrameTerminatorGREMEDY() {.importc.} + proc glValidateProgramPipelineEXT(pipeline: GLuint) {.importc.} + proc glScalexOES(x: GLfixed, y: GLfixed, z: GLfixed) {.importc.} + proc glReplacementCodeuiColor3fVertex3fvSUN(rc: ptr GLuint, c: ptr GLfloat, v: ptr GLfloat) {.importc.} + proc glProgramNamedParameter4dNV(id: GLuint, len: GLsizei, name: ptr GLubyte, x: GLdouble, y: GLdouble, z: GLdouble, w: GLdouble) {.importc.} + proc glMultiDrawElementsIndirectCountARB(mode: GLenum, `type`: GLenum, indirect: GLintptr, drawcount: GLintptr, maxdrawcount: GLsizei, stride: GLsizei) {.importc.} + proc glReferencePlaneSGIX(equation: ptr GLdouble) {.importc.} + proc glNormalStream3iATI(stream: GLenum, nx: GLint, ny: GLint, nz: GLint) {.importc.} + proc glGetColorTableParameterfvEXT(target: GLenum, pname: GLenum, params: ptr GLfloat) {.importc.} + proc glGetAttribLocation(program: GLuint, name: cstring): GLint {.importc.} + proc glMultiTexParameterfEXT(texunit: GLenum, target: GLenum, pname: GLenum, param: GLfloat) {.importc.} + proc glGenFencesNV(n: GLsizei, fences: ptr GLuint) {.importc.} + proc glUniform4dv(location: GLint, count: GLsizei, value: ptr GLdouble) {.importc.} + proc glGetTexLevelParameterfv(target: GLenum, level: GLint, pname: GLenum, params: ptr GLfloat) {.importc.} + proc glProgramUniform1ivEXT(program: GLuint, location: GLint, count: GLsizei, value: ptr GLint) {.importc.} + proc glProgramUniform1dvEXT(program: GLuint, location: GLint, count: GLsizei, value: ptr GLdouble) {.importc.} + proc glLoadTransposeMatrixdARB(m: ptr GLdouble) {.importc.} + proc glVertexAttrib2fvARB(index: GLuint, v: ptr GLfloat) {.importc.} + proc glMultiTexGendEXT(texunit: GLenum, coord: GLenum, pname: GLenum, param: GLdouble) {.importc.} + proc glProgramUniformMatrix4x3dvEXT(program: GLuint, location: GLint, count: GLsizei, transpose: GLboolean, value: ptr GLdouble) {.importc.} + proc glUniform4ui(location: GLint, v0: GLuint, v1: GLuint, v2: GLuint, v3: GLuint) {.importc.} + proc glTexSubImage2D(target: GLenum, level: GLint, xoffset: GLint, yoffset: GLint, width: GLsizei, height: GLsizei, format: GLenum, `type`: GLenum, pixels: pointer) {.importc.} + proc glVertexAttrib3hNV(index: GLuint, x: GLhalfNv, y: GLhalfNv, z: GLhalfNv) {.importc.} + proc glRotatexOES(angle: GLfixed, x: GLfixed, y: GLfixed, z: GLfixed) {.importc.} + proc glGenTextures(n: GLsizei, textures: ptr GLuint) {.importc.} + proc glCheckFramebufferStatusOES(target: GLenum): GLenum {.importc.} + proc glGetVideoCaptureStreamdvNV(video_capture_slot: GLuint, stream: GLuint, pname: GLenum, params: ptr GLdouble) {.importc.} + proc glCompressedTextureSubImage1DEXT(texture: GLuint, target: GLenum, level: GLint, xoffset: GLint, width: GLsizei, format: GLenum, imageSize: GLsizei, bits: pointer) {.importc.} + proc glCurrentPaletteMatrixOES(matrixpaletteindex: GLuint) {.importc.} + proc glCompressedMultiTexSubImage1DEXT(texunit: GLenum, target: GLenum, level: GLint, xoffset: GLint, width: GLsizei, format: GLenum, imageSize: GLsizei, bits: pointer) {.importc.} + proc glNormal3d(nx: GLdouble, ny: GLdouble, nz: GLdouble) {.importc.} + proc glMultiTexCoord1fv(target: GLenum, v: ptr GLfloat) {.importc.} + proc glProgramUniform2uiEXT(program: GLuint, location: GLint, v0: GLuint, v1: GLuint) {.importc.} + proc glMultiTexCoord3fARB(target: GLenum, s: GLfloat, t: GLfloat, r: GLfloat) {.importc.} + proc glRasterPos3xOES(x: GLfixed, y: GLfixed, z: GLfixed) {.importc.} + proc glEGLImageTargetRenderbufferStorageOES(target: GLenum, image: GLeglImageOes) {.importc.} + proc glGetAttribLocationARB(programObj: GLhandleArb, name: cstring): GLint {.importc.} + proc glProgramNamedParameter4dvNV(id: GLuint, len: GLsizei, name: ptr GLubyte, v: ptr GLdouble) {.importc.} + proc glProgramLocalParameterI4uiNV(target: GLenum, index: GLuint, x: GLuint, y: GLuint, z: GLuint, w: GLuint) {.importc.} + proc glNamedFramebufferTextureFaceEXT(framebuffer: GLuint, attachment: GLenum, texture: GLuint, level: GLint, face: GLenum) {.importc.} + proc glIndexf(c: GLfloat) {.importc.} + proc glExtTexObjectStateOverrideiQCOM(target: GLenum, pname: GLenum, param: GLint) {.importc.} + proc glCoverageOperationNV(operation: GLenum) {.importc.} + proc glColorP4uiv(`type`: GLenum, color: ptr GLuint) {.importc.} + proc glDeleteSync(sync: GLsync) {.importc.} + proc glGetHistogramParameterfvEXT(target: GLenum, pname: GLenum, params: ptr GLfloat) {.importc.} + proc glTexCoord4fColor4fNormal3fVertex4fSUN(s: GLfloat, t: GLfloat, p: GLfloat, q: GLfloat, r: GLfloat, g: GLfloat, b: GLfloat, a: GLfloat, nx: GLfloat, ny: GLfloat, nz: GLfloat, x: GLfloat, y: GLfloat, z: GLfloat, w: GLfloat) {.importc.} + proc glEndPerfMonitorAMD(monitor: GLuint) {.importc.} + proc glGetInternalformati64v(target: GLenum, internalformat: GLenum, pname: GLenum, bufSize: GLsizei, params: ptr GLint64) {.importc.} + proc glGenNamesAMD(identifier: GLenum, num: GLuint, names: ptr GLuint) {.importc.} + proc glDrawElementsInstancedBaseVertexBaseInstance(mode: GLenum, count: GLsizei, `type`: GLenum, indices: ptr pointer, instancecount: GLsizei, basevertex: GLint, baseinstance: GLuint) {.importc.} + proc glMultiTexCoord4i(target: GLenum, s: GLint, t: GLint, r: GLint, q: GLint) {.importc.} + proc glVertexAttribL1dv(index: GLuint, v: ptr GLdouble) {.importc.} + proc glGetProgramNamedParameterdvNV(id: GLuint, len: GLsizei, name: ptr GLubyte, params: ptr GLdouble) {.importc.} + proc glSetLocalConstantEXT(id: GLuint, `type`: GLenum, `addr`: pointer) {.importc.} + proc glProgramBinary(program: GLuint, binaryFormat: GLenum, binary: pointer, length: GLsizei) {.importc.} + proc glVideoCaptureNV(video_capture_slot: GLuint, sequence_num: ptr GLuint, capture_time: ptr GLuint64Ext): GLenum {.importc.} + proc glDebugMessageEnableAMD(category: GLenum, severity: GLenum, count: GLsizei, ids: ptr GLuint, enabled: GLboolean) {.importc.} + proc glVertexAttribI1i(index: GLuint, x: GLint) {.importc.} + proc glVertexWeighthNV(weight: GLhalfNv) {.importc.} + proc glTextureParameterIivEXT(texture: GLuint, target: GLenum, pname: GLenum, params: ptr GLint) {.importc.} + proc glClipPlanefIMG(p: GLenum, eqn: ptr GLfloat) {.importc.} + proc glGetLightxv(light: GLenum, pname: GLenum, params: ptr GLfixed) {.importc.} + proc glGetAttachedObjectsARB(containerObj: GLhandleArb, maxCount: GLsizei, count: ptr GLsizei, obj: ptr GLhandleArb) {.importc.} + proc glVertexAttrib4fv(index: GLuint, v: ptr GLfloat) {.importc.} + proc glDisableVertexAttribArrayARB(index: GLuint) {.importc.} + proc glWindowPos3fvARB(v: ptr GLfloat) {.importc.} + proc glClearDepthdNV(depth: GLdouble) {.importc.} + proc glMapParameterivNV(target: GLenum, pname: GLenum, params: ptr GLint) {.importc.} + proc glEndConditionalRenderNVX() {.importc.} + proc glGetFragmentLightivSGIX(light: GLenum, pname: GLenum, params: ptr GLint) {.importc.} + proc glProgramUniformMatrix4fv(program: GLuint, location: GLint, count: GLsizei, transpose: GLboolean, value: ptr GLfloat) {.importc.} + proc glVertexStream1iATI(stream: GLenum, x: GLint) {.importc.} + proc glColorP3ui(`type`: GLenum, color: GLuint) {.importc.} + proc glGetLightxOES(light: GLenum, pname: GLenum, params: ptr GLfixed) {.importc.} + proc glGetLightiv(light: GLenum, pname: GLenum, params: ptr GLint) {.importc.} + proc glVertexStream3dATI(stream: GLenum, x: GLdouble, y: GLdouble, z: GLdouble) {.importc.} + proc glProgramUniform1iEXT(program: GLuint, location: GLint, v0: GLint) {.importc.} + proc glSecondaryColorFormatNV(size: GLint, `type`: GLenum, stride: GLsizei) {.importc.} + proc glDrawElementsBaseVertex(mode: GLenum, count: GLsizei, `type`: GLenum, indices: pointer, basevertex: GLint) {.importc.} + proc glGenFencesAPPLE(n: GLsizei, fences: ptr GLuint) {.importc.} + proc glBinormal3svEXT(v: ptr GLshort) {.importc.} + proc glUseProgramStagesEXT(pipeline: GLuint, stages: GLbitfield, program: GLuint) {.importc.} + proc glDebugMessageCallbackKHR(callback: GLdebugProcKhr, userParam: ptr pointer) {.importc.} + proc glCopyMultiTexSubImage3DEXT(texunit: GLenum, target: GLenum, level: GLint, xoffset: GLint, yoffset: GLint, zoffset: GLint, x: GLint, y: GLint, width: GLsizei, height: GLsizei) {.importc.} + proc glColor4hvNV(v: ptr GLhalfNv) {.importc.} + proc glFenceSync(condition: GLenum, flags: GLbitfield): GLsync {.importc.} + proc glTexCoordPointerListIBM(size: GLint, `type`: GLenum, stride: GLint, `pointer`: ptr pointer, ptrstride: GLint) {.importc.} + proc glPopName() {.importc.} + proc glColor3fVertex3fvSUN(c: ptr GLfloat, v: ptr GLfloat) {.importc.} + proc glGetUniformfv(program: GLuint, location: GLint, params: ptr GLfloat) {.importc.} + proc glMultiTexCoord2hNV(target: GLenum, s: GLhalfNv, t: GLhalfNv) {.importc.} + proc glLightxv(light: GLenum, pname: GLenum, params: ptr GLfixed) {.importc.} + proc glVideoCaptureStreamParameterivNV(video_capture_slot: GLuint, stream: GLuint, pname: GLenum, params: ptr GLint) {.importc.} + proc glEvalCoord1xvOES(coords: ptr GLfixed) {.importc.} + proc glGetProgramEnvParameterIivNV(target: GLenum, index: GLuint, params: ptr GLint) {.importc.} + proc glObjectPurgeableAPPLE(objectType: GLenum, name: GLuint, option: GLenum): GLenum {.importc.} + proc glRequestResidentProgramsNV(n: GLsizei, programs: ptr GLuint) {.importc.} + proc glIsImageHandleResidentNV(handle: GLuint64): GLboolean {.importc.} + proc glColor3hvNV(v: ptr GLhalfNv) {.importc.} + proc glMultiTexCoord2dARB(target: GLenum, s: GLdouble, t: GLdouble) {.importc.} + proc glDeletePathsNV(path: GLuint, range: GLsizei) {.importc.} + proc glVertexAttrib4Nsv(index: GLuint, v: ptr GLshort) {.importc.} + proc glTexEnvf(target: GLenum, pname: GLenum, param: GLfloat) {.importc.} + proc glGlobalAlphaFactoriSUN(factor: GLint) {.importc.} + proc glBlendColorEXT(red: GLfloat, green: GLfloat, blue: GLfloat, alpha: GLfloat) {.importc.} + proc glSecondaryColor3usvEXT(v: ptr GLushort) {.importc.} + proc glProgramEnvParameterI4uiNV(target: GLenum, index: GLuint, x: GLuint, y: GLuint, z: GLuint, w: GLuint) {.importc.} + proc glTexImage4DSGIS(target: GLenum, level: GLint, internalformat: GLenum, width: GLsizei, height: GLsizei, depth: GLsizei, size4d: GLsizei, border: GLint, format: GLenum, `type`: GLenum, pixels: pointer) {.importc.} + proc glMatrixPushEXT(mode: GLenum) {.importc.} + proc glGetPixelTexGenParameterivSGIS(pname: GLenum, params: ptr GLint) {.importc.} + proc glVariantuivEXT(id: GLuint, `addr`: ptr GLuint) {.importc.} + proc glTexParameterfv(target: GLenum, pname: GLenum, params: ptr GLfloat) {.importc.} + proc glGetSubroutineUniformLocation(program: GLuint, shadertype: GLenum, name: cstring): GLint {.importc.} + proc glProgramUniformMatrix3fvEXT(program: GLuint, location: GLint, count: GLsizei, transpose: GLboolean, value: ptr GLfloat) {.importc.} + proc glDrawBuffersATI(n: GLsizei, bufs: ptr GLenum) {.importc.} + proc glGetVertexAttribivNV(index: GLuint, pname: GLenum, params: ptr GLint) {.importc.} + proc glMultiTexCoord4bvOES(texture: GLenum, coords: ptr GLbyte) {.importc.} + proc glCompressedTexSubImage1DARB(target: GLenum, level: GLint, xoffset: GLint, width: GLsizei, format: GLenum, imageSize: GLsizei, data: pointer) {.importc.} + proc glClientActiveTexture(texture: GLenum) {.importc.} + proc glVertexAttrib2fARB(index: GLuint, x: GLfloat, y: GLfloat) {.importc.} + proc glProgramUniform2fvEXT(program: GLuint, location: GLint, count: GLsizei, value: ptr GLfloat) {.importc.} + proc glGetBufferParameterui64vNV(target: GLenum, pname: GLenum, params: ptr GLuint64Ext) {.importc.} + proc glVertexStream3dvATI(stream: GLenum, coords: ptr GLdouble) {.importc.} + proc glReplacementCodeuiNormal3fVertex3fvSUN(rc: ptr GLuint, n: ptr GLfloat, v: ptr GLfloat) {.importc.} + proc glVertexAttrib4svNV(index: GLuint, v: ptr GLshort) {.importc.} + proc glClearBufferSubData(target: GLenum, internalformat: GLenum, offset: GLintptr, size: GLsizeiptr, format: GLenum, `type`: GLenum, data: ptr pointer) {.importc.} + proc glVertexStream2sATI(stream: GLenum, x: GLshort, y: GLshort) {.importc.} + proc glTextureImage2DEXT(texture: GLuint, target: GLenum, level: GLint, internalformat: GLint, width: GLsizei, height: GLsizei, border: GLint, format: GLenum, `type`: GLenum, pixels: pointer) {.importc.} + proc glGetListParameterfvSGIX(list: GLuint, pname: GLenum, params: ptr GLfloat) {.importc.} + proc glUniform3uiv(location: GLint, count: GLsizei, value: ptr GLuint) {.importc.} + proc glIsTexture(texture: GLuint): GLboolean {.importc.} + proc glObjectUnpurgeableAPPLE(objectType: GLenum, name: GLuint, option: GLenum): GLenum {.importc.} + proc glGetVertexAttribdv(index: GLuint, pname: GLenum, params: ptr GLdouble) {.importc.} + proc glGetPointeri_vEXT(pname: GLenum, index: GLuint, params: ptr pointer) {.importc.} + proc glSampleCoveragex(value: GLclampx, invert: GLboolean) {.importc.} + proc glColor3f(red: GLfloat, green: GLfloat, blue: GLfloat) {.importc.} + proc glGetnMapivARB(target: GLenum, query: GLenum, bufSize: GLsizei, v: ptr GLint) {.importc.} + proc glMakeTextureHandleResidentARB(handle: GLuint64) {.importc.} + proc glSecondaryColorP3ui(`type`: GLenum, color: GLuint) {.importc.} + proc glMultiTexCoord4sARB(target: GLenum, s: GLshort, t: GLshort, r: GLshort, q: GLshort) {.importc.} + proc glUniform3i64NV(location: GLint, x: GLint64Ext, y: GLint64Ext, z: GLint64Ext) {.importc.} + proc glVDPAUGetSurfaceivNV(surface: GLvdpauSurfaceNv, pname: GLenum, bufSize: GLsizei, length: ptr GLsizei, values: ptr GLint) {.importc.} + proc glTexBufferEXT(target: GLenum, internalformat: GLenum, buffer: GLuint) {.importc.} + proc glVertexAttribI4ubvEXT(index: GLuint, v: ptr GLubyte) {.importc.} + proc glDeleteFramebuffersOES(n: GLsizei, framebuffers: ptr GLuint) {.importc.} + proc glColor3fVertex3fSUN(r: GLfloat, g: GLfloat, b: GLfloat, x: GLfloat, y: GLfloat, z: GLfloat) {.importc.} + proc glCombinerInputNV(stage: GLenum, portion: GLenum, variable: GLenum, input: GLenum, mapping: GLenum, componentUsage: GLenum) {.importc.} + proc glPolygonOffsetEXT(factor: GLfloat, bias: GLfloat) {.importc.} + proc glWindowPos4dMESA(x: GLdouble, y: GLdouble, z: GLdouble, w: GLdouble) {.importc.} + proc glVertex3f(x: GLfloat, y: GLfloat, z: GLfloat) {.importc.} + proc glTexCoord3f(s: GLfloat, t: GLfloat, r: GLfloat) {.importc.} + proc glMultiTexCoord1fARB(target: GLenum, s: GLfloat) {.importc.} + proc glVertexAttrib4f(index: GLuint, x: GLfloat, y: GLfloat, z: GLfloat, w: GLfloat) {.importc.} + proc glGetFragDataLocationEXT(program: GLuint, name: cstring): GLint {.importc.} + proc glFlushMappedNamedBufferRangeEXT(buffer: GLuint, offset: GLintptr, length: GLsizeiptr) {.importc.} + proc glVertexAttrib1sARB(index: GLuint, x: GLshort) {.importc.} + proc glBitmapxOES(width: GLsizei, height: GLsizei, xorig: GLfixed, yorig: GLfixed, xmove: GLfixed, ymove: GLfixed, bitmap: ptr GLubyte) {.importc.} + proc glEnableVertexArrayAttribEXT(vaobj: GLuint, index: GLuint) {.importc.} + proc glDeleteRenderbuffers(n: GLsizei, renderbuffers: ptr GLuint) {.importc.} + proc glFramebufferRenderbuffer(target: GLenum, attachment: GLenum, renderbuffertarget: GLenum, renderbuffer: GLuint) {.importc.} + proc glInvalidateTexImage(texture: GLuint, level: GLint) {.importc.} + proc glProgramUniform2i64NV(program: GLuint, location: GLint, x: GLint64Ext, y: GLint64Ext) {.importc.} + proc glTextureImage3DMultisampleNV(texture: GLuint, target: GLenum, samples: GLsizei, internalFormat: GLint, width: GLsizei, height: GLsizei, depth: GLsizei, fixedSampleLocations: GLboolean) {.importc.} + proc glValidateProgram(program: GLuint) {.importc.} + proc glUniform1dv(location: GLint, count: GLsizei, value: ptr GLdouble) {.importc.} + proc glNormalStream3dvATI(stream: GLenum, coords: ptr GLdouble) {.importc.} + proc glMultiDrawElementsIndirect(mode: GLenum, `type`: GLenum, indirect: ptr pointer, drawcount: GLsizei, stride: GLsizei) {.importc.} + proc glVertexBlendARB(count: GLint) {.importc.} + proc glIsSampler(sampler: GLuint): GLboolean {.importc.} + proc glVariantdvEXT(id: GLuint, `addr`: ptr GLdouble) {.importc.} + proc glProgramUniformMatrix3x2fvEXT(program: GLuint, location: GLint, count: GLsizei, transpose: GLboolean, value: ptr GLfloat) {.importc.} + proc glVertexStream4fvATI(stream: GLenum, coords: ptr GLfloat) {.importc.} + proc glOrthoxOES(l: GLfixed, r: GLfixed, b: GLfixed, t: GLfixed, n: GLfixed, f: GLfixed) {.importc.} + proc glColorFormatNV(size: GLint, `type`: GLenum, stride: GLsizei) {.importc.} + proc glFogCoordPointer(`type`: GLenum, stride: GLsizei, `pointer`: pointer) {.importc.} + proc glVertexAttrib3dvARB(index: GLuint, v: ptr GLdouble) {.importc.} + proc glVertex3bOES(x: GLbyte, y: GLbyte) {.importc.} + proc glVertexAttribFormat(attribindex: GLuint, size: GLint, `type`: GLenum, normalized: GLboolean, relativeoffset: GLuint) {.importc.} + proc glTexCoord4fVertex4fSUN(s: GLfloat, t: GLfloat, p: GLfloat, q: GLfloat, x: GLfloat, y: GLfloat, z: GLfloat, w: GLfloat) {.importc.} + proc glEnableDriverControlQCOM(driverControl: GLuint) {.importc.} + proc glPointParameteri(pname: GLenum, param: GLint) {.importc.} + proc glVertexAttribI2i(index: GLuint, x: GLint, y: GLint) {.importc.} + proc glGetDriverControlStringQCOM(driverControl: GLuint, bufSize: GLsizei, length: ptr GLsizei, driverControlString: cstring) {.importc.} + proc glGetTexLevelParameteriv(target: GLenum, level: GLint, pname: GLenum, params: ptr GLint) {.importc.} + proc glGetHandleARB(pname: GLenum): GLhandleArb {.importc.} + proc glIndexubv(c: ptr GLubyte) {.importc.} + proc glBlendFunciARB(buf: GLuint, src: GLenum, dst: GLenum) {.importc.} + proc glColor4usv(v: ptr GLushort) {.importc.} + proc glBlendEquationSeparateOES(modeRgb: GLenum, modeAlpha: GLenum) {.importc.} + proc glVertexAttribI4ui(index: GLuint, x: GLuint, y: GLuint, z: GLuint, w: GLuint) {.importc.} + proc glProgramUniform3f(program: GLuint, location: GLint, v0: GLfloat, v1: GLfloat, v2: GLfloat) {.importc.} + proc glVertexAttribL3i64vNV(index: GLuint, v: ptr GLint64Ext) {.importc.} + proc glWeightdvARB(size: GLint, weights: ptr GLdouble) {.importc.} + proc glVertexArrayRangeAPPLE(length: GLsizei, `pointer`: pointer) {.importc.} + proc glMapGrid2d(un: GLint, u1: GLdouble, u2: GLdouble, vn: GLint, v1: GLdouble, v2: GLdouble) {.importc.} + proc glFogiv(pname: GLenum, params: ptr GLint) {.importc.} + proc glUniform2f(location: GLint, v0: GLfloat, v1: GLfloat) {.importc.} + proc glGetDoublei_v(target: GLenum, index: GLuint, data: ptr GLdouble) {.importc.} + proc glGetVertexAttribfv(index: GLuint, pname: GLenum, params: ptr GLfloat) {.importc.} + proc glVertexAttribI2ivEXT(index: GLuint, v: ptr GLint) {.importc.} + proc glIsProgramNV(id: GLuint): GLboolean {.importc.} + proc glTexCoord1hNV(s: GLhalfNv) {.importc.} + proc glMinSampleShadingARB(value: GLfloat) {.importc.} + proc glMultiDrawElements(mode: GLenum, count: ptr GLsizei, `type`: GLenum, indices: ptr pointer, drawcount: GLsizei) {.importc.} + proc glGetQueryObjectuiv(id: GLuint, pname: GLenum, params: ptr GLuint) {.importc.} + proc glReadBuffer(mode: GLenum) {.importc.} + proc glMultiTexCoordP3uiv(texture: GLenum, `type`: GLenum, coords: ptr GLuint) {.importc.} + proc glUniformMatrix3x2fv(location: GLint, count: GLsizei, transpose: GLboolean, value: ptr GLfloat) {.importc.} + proc glBindRenderbuffer(target: GLenum, renderbuffer: GLuint) {.importc.} + proc glBinormal3sEXT(bx: GLshort, by: GLshort, bz: GLshort) {.importc.} + proc glUniform4iARB(location: GLint, v0: GLint, v1: GLint, v2: GLint, v3: GLint) {.importc.} + proc glGetUniformOffsetEXT(program: GLuint, location: GLint): GLintptr {.importc.} + proc glDeleteLists(list: GLuint, range: GLsizei) {.importc.} + proc glVertexAttribI1iEXT(index: GLuint, x: GLint) {.importc.} + proc glFramebufferTexture1D(target: GLenum, attachment: GLenum, textarget: GLenum, texture: GLuint, level: GLint) {.importc.} + proc glVertexAttribI2uiv(index: GLuint, v: ptr GLuint) {.importc.} + proc glBindFragDataLocation(program: GLuint, color: GLuint, name: cstring) {.importc.} + proc glClearStencil(s: GLint) {.importc.} + proc glVertexAttrib4Nubv(index: GLuint, v: ptr GLubyte) {.importc.} + proc glConvolutionFilter2DEXT(target: GLenum, internalformat: GLenum, width: GLsizei, height: GLsizei, format: GLenum, `type`: GLenum, image: pointer) {.importc.} + proc glGenFramebuffersEXT(n: GLsizei, framebuffers: ptr GLuint) {.importc.} + proc glFogCoordfvEXT(coord: ptr GLfloat) {.importc.} + proc glGetRenderbufferParameterivEXT(target: GLenum, pname: GLenum, params: ptr GLint) {.importc.} + proc glVertexAttribs1fvNV(index: GLuint, count: GLsizei, v: ptr GLfloat) {.importc.} + proc glTexCoord2fColor3fVertex3fSUN(s: GLfloat, t: GLfloat, r: GLfloat, g: GLfloat, b: GLfloat, x: GLfloat, y: GLfloat, z: GLfloat) {.importc.} + proc glRasterPos3i(x: GLint, y: GLint, z: GLint) {.importc.} + proc glMultiTexSubImage2DEXT(texunit: GLenum, target: GLenum, level: GLint, xoffset: GLint, yoffset: GLint, width: GLsizei, height: GLsizei, format: GLenum, `type`: GLenum, pixels: pointer) {.importc.} + proc glConvolutionParameteriEXT(target: GLenum, pname: GLenum, params: GLint) {.importc.} + proc glVertexAttribI4iEXT(index: GLuint, x: GLint, y: GLint, z: GLint, w: GLint) {.importc.} + proc glVertexAttribL2i64vNV(index: GLuint, v: ptr GLint64Ext) {.importc.} + proc glBlendColor(red: GLfloat, green: GLfloat, blue: GLfloat, alpha: GLfloat) {.importc.} + proc glGetPathColorGenivNV(color: GLenum, pname: GLenum, value: ptr GLint) {.importc.} + proc glCompressedTextureImage1DEXT(texture: GLuint, target: GLenum, level: GLint, internalformat: GLenum, width: GLsizei, border: GLint, imageSize: GLsizei, bits: pointer) {.importc.} + proc glDrawElementsInstanced(mode: GLenum, count: GLsizei, `type`: GLenum, indices: pointer, instancecount: GLsizei) {.importc.} + proc glFogCoordd(coord: GLdouble) {.importc.} + proc glTexParameterxvOES(target: GLenum, pname: GLenum, params: ptr GLfixed) {.importc.} + proc glWindowPos3svARB(v: ptr GLshort) {.importc.} + proc glGetVertexArrayPointervEXT(vaobj: GLuint, pname: GLenum, param: ptr pointer) {.importc.} + proc glDrawTextureNV(texture: GLuint, sampler: GLuint, x0: GLfloat, y0: GLfloat, x1: GLfloat, y1: GLfloat, z: GLfloat, s0: GLfloat, t0: GLfloat, s1: GLfloat, t1: GLfloat) {.importc.} + proc glUniformMatrix2dv(location: GLint, count: GLsizei, transpose: GLboolean, value: ptr GLdouble) {.importc.} + proc glTexImage3DOES(target: GLenum, level: GLint, internalformat: GLenum, width: GLsizei, height: GLsizei, depth: GLsizei, border: GLint, format: GLenum, `type`: GLenum, pixels: pointer) {.importc.} + proc glClampColorARB(target: GLenum, clamp: GLenum) {.importc.} + proc glTexParameteri(target: GLenum, pname: GLenum, param: GLint) {.importc.} + proc glWindowPos4svMESA(v: ptr GLshort) {.importc.} + proc glMultiTexCoordP4ui(texture: GLenum, `type`: GLenum, coords: GLuint) {.importc.} + proc glVertexP4uiv(`type`: GLenum, value: ptr GLuint) {.importc.} + proc glProgramUniform4iEXT(program: GLuint, location: GLint, v0: GLint, v1: GLint, v2: GLint, v3: GLint) {.importc.} + proc glTexCoord3xvOES(coords: ptr GLfixed) {.importc.} + proc glCopyTexImage2DEXT(target: GLenum, level: GLint, internalformat: GLenum, x: GLint, y: GLint, width: GLsizei, height: GLsizei, border: GLint) {.importc.} + proc glGenSamplers(count: GLsizei, samplers: ptr GLuint) {.importc.} + proc glRasterPos4iv(v: ptr GLint) {.importc.} + proc glWindowPos4sMESA(x: GLshort, y: GLshort, z: GLshort, w: GLshort) {.importc.} + proc glProgramUniform2dvEXT(program: GLuint, location: GLint, count: GLsizei, value: ptr GLdouble) {.importc.} + proc glPrioritizeTexturesEXT(n: GLsizei, textures: ptr GLuint, priorities: ptr GLclampf) {.importc.} + proc glRects(x1: GLshort, y1: GLshort, x2: GLshort, y2: GLshort) {.importc.} + proc glMultiDrawElementsBaseVertex(mode: GLenum, count: ptr GLsizei, `type`: GLenum, indices: ptr pointer, drawcount: GLsizei, basevertex: ptr GLint) {.importc.} + proc glProgramBinaryOES(program: GLuint, binaryFormat: GLenum, binary: pointer, length: GLint) {.importc.} + proc glReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fvSUN(rc: ptr GLuint, tc: ptr GLfloat, c: ptr GLfloat, n: ptr GLfloat, v: ptr GLfloat) {.importc.} + proc glGetMinmaxParameterfv(target: GLenum, pname: GLenum, params: ptr GLfloat) {.importc.} + proc glColor4fNormal3fVertex3fSUN(r: GLfloat, g: GLfloat, b: GLfloat, a: GLfloat, nx: GLfloat, ny: GLfloat, nz: GLfloat, x: GLfloat, y: GLfloat, z: GLfloat) {.importc.} + proc glWindowPos2d(x: GLdouble, y: GLdouble) {.importc.} + proc glGetPerfMonitorGroupStringAMD(group: GLuint, bufSize: GLsizei, length: ptr GLsizei, groupString: cstring) {.importc.} + proc glUniformHandleui64vNV(location: GLint, count: GLsizei, value: ptr GLuint64) {.importc.} + proc glBlendEquation(mode: GLenum) {.importc.} + proc glMapBufferARB(target: GLenum, access: GLenum): pointer {.importc.} + proc glGetMaterialxvOES(face: GLenum, pname: GLenum, params: ptr GLfixed) {.importc.} + proc glVertexAttribI1ivEXT(index: GLuint, v: ptr GLint) {.importc.} + proc glTexCoord4hvNV(v: ptr GLhalfNv) {.importc.} + proc glVertexArrayVertexAttribLOffsetEXT(vaobj: GLuint, buffer: GLuint, index: GLuint, size: GLint, `type`: GLenum, stride: GLsizei, offset: GLintptr) {.importc.} + proc glExtGetShadersQCOM(shaders: ptr GLuint, maxShaders: GLint, numShaders: ptr GLint) {.importc.} + proc glWindowPos4ivMESA(v: ptr GLint) {.importc.} + proc glVertexAttrib1sNV(index: GLuint, x: GLshort) {.importc.} + proc glNormalStream3ivATI(stream: GLenum, coords: ptr GLint) {.importc.} + proc glSecondaryColor3fEXT(red: GLfloat, green: GLfloat, blue: GLfloat) {.importc.} + proc glVertexArrayFogCoordOffsetEXT(vaobj: GLuint, buffer: GLuint, `type`: GLenum, stride: GLsizei, offset: GLintptr) {.importc.} + proc glGetTextureImageEXT(texture: GLuint, target: GLenum, level: GLint, format: GLenum, `type`: GLenum, pixels: pointer) {.importc.} + proc glVertexAttrib4hNV(index: GLuint, x: GLhalfNv, y: GLhalfNv, z: GLhalfNv, w: GLhalfNv) {.importc.} + proc glReplacementCodeusSUN(code: GLushort) {.importc.} + proc glPixelTexGenSGIX(mode: GLenum) {.importc.} + proc glMultiDrawRangeElementArrayAPPLE(mode: GLenum, start: GLuint, `end`: GLuint, first: ptr GLint, count: ptr GLsizei, primcount: GLsizei) {.importc.} + proc glDrawElements(mode: GLenum, count: GLsizei, `type`: GLenum, indices: pointer) {.importc.} + proc glTexCoord1hvNV(v: ptr GLhalfNv) {.importc.} + proc glGetPixelMapuiv(map: GLenum, values: ptr GLuint) {.importc.} + proc glRasterPos4d(x: GLdouble, y: GLdouble, z: GLdouble, w: GLdouble) {.importc.} + proc glTexImage1D(target: GLenum, level: GLint, internalformat: GLint, width: GLsizei, border: GLint, format: GLenum, `type`: GLenum, pixels: pointer) {.importc.} + proc glConvolutionParameterxOES(target: GLenum, pname: GLenum, param: GLfixed) {.importc.} + proc glSecondaryColor3dEXT(red: GLdouble, green: GLdouble, blue: GLdouble) {.importc.} + proc glGetCombinerOutputParameterivNV(stage: GLenum, portion: GLenum, pname: GLenum, params: ptr GLint) {.importc.} + proc glQueryCounter(id: GLuint, target: GLenum) {.importc.} + proc glGetUniformi64vNV(program: GLuint, location: GLint, params: ptr GLint64Ext) {.importc.} + proc glTexCoord2fv(v: ptr GLfloat) {.importc.} + proc glWindowPos3d(x: GLdouble, y: GLdouble, z: GLdouble) {.importc.} + proc glBlendFuncSeparateINGR(sfactorRgb: GLenum, dfactorRgb: GLenum, sfactorAlpha: GLenum, dfactorAlpha: GLenum) {.importc.} + proc glTextureNormalEXT(mode: GLenum) {.importc.} + proc glVertexStream2fATI(stream: GLenum, x: GLfloat, y: GLfloat) {.importc.} + proc glViewportIndexedf(index: GLuint, x: GLfloat, y: GLfloat, w: GLfloat, h: GLfloat) {.importc.} + proc glMultiTexCoord4ivARB(target: GLenum, v: ptr GLint) {.importc.} + proc glBindBufferOffsetEXT(target: GLenum, index: GLuint, buffer: GLuint, offset: GLintptr) {.importc.} + proc glTexCoord3sv(v: ptr GLshort) {.importc.} + proc glVertexArrayVertexAttribBindingEXT(vaobj: GLuint, attribindex: GLuint, bindingindex: GLuint) {.importc.} + proc glVertexAttrib2f(index: GLuint, x: GLfloat, y: GLfloat) {.importc.} + proc glMultiTexGenivEXT(texunit: GLenum, coord: GLenum, pname: GLenum, params: ptr GLint) {.importc.} + proc glUniformui64vNV(location: GLint, count: GLsizei, value: ptr GLuint64Ext) {.importc.} + proc glGetInfoLogARB(obj: GLhandleArb, maxLength: GLsizei, length: ptr GLsizei, infoLog: cstring) {.importc.} + proc glGetNamedProgramLocalParameterIivEXT(program: GLuint, target: GLenum, index: GLuint, params: ptr GLint) {.importc.} + proc glVertexAttrib4s(index: GLuint, x: GLshort, y: GLshort, z: GLshort, w: GLshort) {.importc.} + proc glUniformMatrix4x2dv(location: GLint, count: GLsizei, transpose: GLboolean, value: ptr GLdouble) {.importc.} + proc glVertexAttribs3dvNV(index: GLuint, count: GLsizei, v: ptr GLdouble) {.importc.} + proc glSecondaryColor3dvEXT(v: ptr GLdouble) {.importc.} + proc glTextureRenderbufferEXT(texture: GLuint, target: GLenum, renderbuffer: GLuint) {.importc.} + proc glVertexAttribL2ui64vNV(index: GLuint, v: ptr GLuint64Ext) {.importc.} + proc glBlendFuncSeparateOES(srcRgb: GLenum, dstRgb: GLenum, srcAlpha: GLenum, dstAlpha: GLenum) {.importc.} + proc glVertexAttribDivisorARB(index: GLuint, divisor: GLuint) {.importc.} + proc glWindowPos2sv(v: ptr GLshort) {.importc.} + proc glMultiTexCoord3svARB(target: GLenum, v: ptr GLshort) {.importc.} + proc glCombinerParameterfvNV(pname: GLenum, params: ptr GLfloat) {.importc.} + proc glGetImageTransformParameterfvHP(target: GLenum, pname: GLenum, params: ptr GLfloat) {.importc.} + proc glTexParameteriv(target: GLenum, pname: GLenum, params: ptr GLint) {.importc.} + proc glGetArrayObjectivATI(`array`: GLenum, pname: GLenum, params: ptr GLint) {.importc.} + proc glGetTexParameterIuiv(target: GLenum, pname: GLenum, params: ptr GLuint) {.importc.} + proc glGetProgramPipelineInfoLog(pipeline: GLuint, bufSize: GLsizei, length: ptr GLsizei, infoLog: cstring) {.importc.} + proc glGetOcclusionQueryuivNV(id: GLuint, pname: GLenum, params: ptr GLuint) {.importc.} + proc glVertexAttrib4bvARB(index: GLuint, v: ptr GLbyte) {.importc.} + proc glListParameterfvSGIX(list: GLuint, pname: GLenum, params: ptr GLfloat) {.importc.} + proc glDeleteSamplers(count: GLsizei, samplers: ptr GLuint) {.importc.} + proc glNormalStream3dATI(stream: GLenum, nx: GLdouble, ny: GLdouble, nz: GLdouble) {.importc.} + proc glProgramUniform4i64vNV(program: GLuint, location: GLint, count: GLsizei, value: ptr GLint64Ext) {.importc.} + proc glBlendFuncSeparateiARB(buf: GLuint, srcRgb: GLenum, dstRgb: GLenum, srcAlpha: GLenum, dstAlpha: GLenum) {.importc.} + proc glEndTransformFeedbackEXT() {.importc.} + proc glMultiTexCoord3i(target: GLenum, s: GLint, t: GLint, r: GLint) {.importc.} + proc glMakeBufferResidentNV(target: GLenum, access: GLenum) {.importc.} + proc glTangent3dvEXT(v: ptr GLdouble) {.importc.} + proc glMatrixPopEXT(mode: GLenum) {.importc.} + proc glVertexAttrib4NivARB(index: GLuint, v: ptr GLint) {.importc.} + proc glProgramUniform2ui64NV(program: GLuint, location: GLint, x: GLuint64Ext, y: GLuint64Ext) {.importc.} + proc glWeightPointerARB(size: GLint, `type`: GLenum, stride: GLsizei, `pointer`: pointer) {.importc.} + proc glCullParameterdvEXT(pname: GLenum, params: ptr GLdouble) {.importc.} + proc glFramebufferTexture2D(target: GLenum, attachment: GLenum, textarget: GLenum, texture: GLuint, level: GLint) {.importc.} + proc glGenVertexArrays(n: GLsizei, arrays: ptr GLuint) {.importc.} + proc glUniformHandleui64NV(location: GLint, value: GLuint64) {.importc.} + proc glIndexPointer(`type`: GLenum, stride: GLsizei, `pointer`: pointer) {.importc.} + proc glGetProgramSubroutineParameteruivNV(target: GLenum, index: GLuint, param: ptr GLuint) {.importc.} + proc glVertexAttrib1svARB(index: GLuint, v: ptr GLshort) {.importc.} + proc glDetachObjectARB(containerObj: GLhandleArb, attachedObj: GLhandleArb) {.importc.} + proc glCompressedTexImage3D(target: GLenum, level: GLint, internalformat: GLenum, width: GLsizei, height: GLsizei, depth: GLsizei, border: GLint, imageSize: GLsizei, data: pointer) {.importc.} + proc glBlendFuncSeparate(sfactorRgb: GLenum, dfactorRgb: GLenum, sfactorAlpha: GLenum, dfactorAlpha: GLenum) {.importc.} + proc glExecuteProgramNV(target: GLenum, id: GLuint, params: ptr GLfloat) {.importc.} + proc glAttachObjectARB(containerObj: GLhandleArb, obj: GLhandleArb) {.importc.} + proc glCompressedTexSubImage1D(target: GLenum, level: GLint, xoffset: GLint, width: GLsizei, format: GLenum, imageSize: GLsizei, data: pointer) {.importc.} + proc glProgramUniform4iv(program: GLuint, location: GLint, count: GLsizei, value: ptr GLint) {.importc.} + proc glVertexAttrib3sv(index: GLuint, v: ptr GLshort) {.importc.} + proc glTexCoord3bvOES(coords: ptr GLbyte) {.importc.} + proc glGenTexturesEXT(n: GLsizei, textures: ptr GLuint) {.importc.} + proc glColor4f(red: GLfloat, green: GLfloat, blue: GLfloat, alpha: GLfloat) {.importc.} + proc glGetFramebufferAttachmentParameterivOES(target: GLenum, attachment: GLenum, pname: GLenum, params: ptr GLint) {.importc.} + proc glClearColor(red: GLfloat, green: GLfloat, blue: GLfloat, alpha: GLfloat) {.importc.} + proc glNamedProgramLocalParametersI4ivEXT(program: GLuint, target: GLenum, index: GLuint, count: GLsizei, params: ptr GLint) {.importc.} + proc glMakeImageHandleNonResidentARB(handle: GLuint64) {.importc.} + proc glGenRenderbuffers(n: GLsizei, renderbuffers: ptr GLuint) {.importc.} + proc glVertexAttribL1ui64vARB(index: GLuint, v: ptr GLuint64Ext) {.importc.} + proc glBindFramebufferEXT(target: GLenum, framebuffer: GLuint) {.importc.} + proc glProgramUniform2dEXT(program: GLuint, location: GLint, x: GLdouble, y: GLdouble) {.importc.} + proc glCompressedMultiTexImage2DEXT(texunit: GLenum, target: GLenum, level: GLint, internalformat: GLenum, width: GLsizei, height: GLsizei, border: GLint, imageSize: GLsizei, bits: pointer) {.importc.} + proc glDeleteSyncAPPLE(sync: GLsync) {.importc.} + proc glDebugMessageInsertAMD(category: GLenum, severity: GLenum, id: GLuint, length: GLsizei, buf: cstring) {.importc.} + proc glSecondaryColorPointerEXT(size: GLint, `type`: GLenum, stride: GLsizei, `pointer`: pointer) {.importc.} + proc glTextureImage2DMultisampleNV(texture: GLuint, target: GLenum, samples: GLsizei, internalFormat: GLint, width: GLsizei, height: GLsizei, fixedSampleLocations: GLboolean) {.importc.} + proc glBeginFragmentShaderATI() {.importc.} + proc glClearDepth(depth: GLdouble) {.importc.} + proc glBindTextures(first: GLuint, count: GLsizei, textures: ptr GLuint) {.importc.} + proc glEvalCoord1d(u: GLdouble) {.importc.} + proc glSecondaryColor3b(red: GLbyte, green: GLbyte, blue: GLbyte) {.importc.} + proc glExtGetTexSubImageQCOM(target: GLenum, level: GLint, xoffset: GLint, yoffset: GLint, zoffset: GLint, width: GLsizei, height: GLsizei, depth: GLsizei, format: GLenum, `type`: GLenum, texels: pointer) {.importc.} + proc glClearColorIiEXT(red: GLint, green: GLint, blue: GLint, alpha: GLint) {.importc.} + proc glVertex2xOES(x: GLfixed) {.importc.} + proc glVertexAttrib2s(index: GLuint, x: GLshort, y: GLshort) {.importc.} + proc glUniformHandleui64vARB(location: GLint, count: GLsizei, value: ptr GLuint64) {.importc.} + proc glAreTexturesResidentEXT(n: GLsizei, textures: ptr GLuint, residences: ptr GLboolean): GLboolean {.importc.} + proc glDrawElementsInstancedBaseInstance(mode: GLenum, count: GLsizei, `type`: GLenum, indices: ptr pointer, instancecount: GLsizei, baseinstance: GLuint) {.importc.} + proc glGetString(name: GLenum): ptr GLubyte {.importc.} + proc glDrawTransformFeedbackStream(mode: GLenum, id: GLuint, stream: GLuint) {.importc.} + proc glSecondaryColor3uiv(v: ptr GLuint) {.importc.} + proc glNamedFramebufferParameteriEXT(framebuffer: GLuint, pname: GLenum, param: GLint) {.importc.} + proc glVertexAttrib4hvNV(index: GLuint, v: ptr GLhalfNv) {.importc.} + proc glGetnUniformuivARB(program: GLuint, location: GLint, bufSize: GLsizei, params: ptr GLuint) {.importc.} + proc glProgramUniform4ui(program: GLuint, location: GLint, v0: GLuint, v1: GLuint, v2: GLuint, v3: GLuint) {.importc.} + proc glPointParameterxvOES(pname: GLenum, params: ptr GLfixed) {.importc.} + proc glIsEnabledi(target: GLenum, index: GLuint): GLboolean {.importc.} + proc glColorPointerEXT(size: GLint, `type`: GLenum, stride: GLsizei, count: GLsizei, `pointer`: pointer) {.importc.} + proc glFragmentLightModelfvSGIX(pname: GLenum, params: ptr GLfloat) {.importc.} + proc glRasterPos3f(x: GLfloat, y: GLfloat, z: GLfloat) {.importc.} + proc glDeleteObjectARB(obj: GLhandleArb) {.importc.} + proc glSetFenceNV(fence: GLuint, condition: GLenum) {.importc.} + proc glTransformFeedbackAttribsNV(count: GLuint, attribs: ptr GLint, bufferMode: GLenum) {.importc.} + proc glProgramUniformMatrix2fvEXT(program: GLuint, location: GLint, count: GLsizei, transpose: GLboolean, value: ptr GLfloat) {.importc.} + proc glGetPointerv(pname: GLenum, params: ptr pointer) {.importc.} + proc glWindowPos2dvMESA(v: ptr GLdouble) {.importc.} + proc glTexImage2DMultisample(target: GLenum, samples: GLsizei, internalformat: GLint, width: GLsizei, height: GLsizei, fixedsamplelocations: GLboolean) {.importc.} + proc glGenFragmentShadersATI(range: GLuint): GLuint {.importc.} + proc glTexCoord4fv(v: ptr GLfloat) {.importc.} + proc glCompressedTexImage1D(target: GLenum, level: GLint, internalformat: GLenum, width: GLsizei, border: GLint, imageSize: GLsizei, data: pointer) {.importc.} + proc glGetNamedBufferSubDataEXT(buffer: GLuint, offset: GLintptr, size: GLsizeiptr, data: pointer) {.importc.} + proc glFinish() {.importc.} + proc glDeleteVertexShaderEXT(id: GLuint) {.importc.} + proc glFinishObjectAPPLE(`object`: GLenum, name: GLint) {.importc.} + proc glGetActiveAttribARB(programObj: GLhandleArb, index: GLuint, maxLength: GLsizei, length: ptr GLsizei, size: ptr GLint, `type`: ptr GLenum, name: cstring) {.importc.} + proc glPointParameterx(pname: GLenum, param: GLfixed) {.importc.} + proc glProgramUniformui64vNV(program: GLuint, location: GLint, count: GLsizei, value: ptr GLuint64Ext) {.importc.} + proc glSecondaryColor3ubv(v: ptr GLubyte) {.importc.} + proc glGetProgramLocalParameterIivNV(target: GLenum, index: GLuint, params: ptr GLint) {.importc.} + proc glDeleteProgramPipelinesEXT(n: GLsizei, pipelines: ptr GLuint) {.importc.} + proc glVertexAttrib4fNV(index: GLuint, x: GLfloat, y: GLfloat, z: GLfloat, w: GLfloat) {.importc.} + proc glGetColorTableParameterfvSGI(target: GLenum, pname: GLenum, params: ptr GLfloat) {.importc.} + proc glGetFloati_v(target: GLenum, index: GLuint, data: ptr GLfloat) {.importc.} + proc glGenBuffers(n: GLsizei, buffers: ptr GLuint) {.importc.} + proc glNormal3b(nx: GLbyte, ny: GLbyte, nz: GLbyte) {.importc.} + proc glDrawArraysInstancedARB(mode: GLenum, first: GLint, count: GLsizei, primcount: GLsizei) {.importc.} + proc glTexStorage2DMultisample(target: GLenum, samples: GLsizei, internalformat: GLenum, width: GLsizei, height: GLsizei, fixedsamplelocations: GLboolean) {.importc.} + proc glGetVariantIntegervEXT(id: GLuint, value: GLenum, data: ptr GLint) {.importc.} + proc glColor3ubv(v: ptr GLubyte) {.importc.} + proc glVertexAttribP4uiv(index: GLuint, `type`: GLenum, normalized: GLboolean, value: ptr GLuint) {.importc.} + proc glProgramUniform2ivEXT(program: GLuint, location: GLint, count: GLsizei, value: ptr GLint) {.importc.} + proc glVertexStream4dATI(stream: GLenum, x: GLdouble, y: GLdouble, z: GLdouble, w: GLdouble) {.importc.} + proc glVertexAttribL2ui64NV(index: GLuint, x: GLuint64Ext, y: GLuint64Ext) {.importc.} + proc glSecondaryColor3bEXT(red: GLbyte, green: GLbyte, blue: GLbyte) {.importc.} + proc glGetBufferPointervOES(target: GLenum, pname: GLenum, params: ptr pointer) {.importc.} + proc glGetMaterialfv(face: GLenum, pname: GLenum, params: ptr GLfloat) {.importc.} + proc glVertexStream3sATI(stream: GLenum, x: GLshort, y: GLshort, z: GLshort) {.importc.} + proc glUniform1i(location: GLint, v0: GLint) {.importc.} + proc glVertexAttribL2d(index: GLuint, x: GLdouble, y: GLdouble) {.importc.} + proc glTestObjectAPPLE(`object`: GLenum, name: GLuint): GLboolean {.importc.} + proc glGetTransformFeedbackVarying(program: GLuint, index: GLuint, bufSize: GLsizei, length: ptr GLsizei, size: ptr GLsizei, `type`: ptr GLenum, name: cstring) {.importc.} + proc glFramebufferRenderbufferOES(target: GLenum, attachment: GLenum, renderbuffertarget: GLenum, renderbuffer: GLuint) {.importc.} + proc glVertexStream3iATI(stream: GLenum, x: GLint, y: GLint, z: GLint) {.importc.} + proc glMakeTextureHandleNonResidentNV(handle: GLuint64) {.importc.} + proc glVertexAttrib4fvNV(index: GLuint, v: ptr GLfloat) {.importc.} + proc glArrayElement(i: GLint) {.importc.} + proc glClearBufferData(target: GLenum, internalformat: GLenum, format: GLenum, `type`: GLenum, data: ptr pointer) {.importc.} + proc glSecondaryColor3usEXT(red: GLushort, green: GLushort, blue: GLushort) {.importc.} + proc glRenderbufferStorageMultisample(target: GLenum, samples: GLsizei, internalformat: GLenum, width: GLsizei, height: GLsizei) {.importc.} + proc glTexCoord2xvOES(coords: ptr GLfixed) {.importc.} + proc glWindowPos3f(x: GLfloat, y: GLfloat, z: GLfloat) {.importc.} + proc glTangent3svEXT(v: ptr GLshort) {.importc.} + proc glPointParameterf(pname: GLenum, param: GLfloat) {.importc.} + proc glVertexAttribI4uivEXT(index: GLuint, v: ptr GLuint) {.importc.} + proc glColorTableParameteriv(target: GLenum, pname: GLenum, params: ptr GLint) {.importc.} + proc glMatrixMultdEXT(mode: GLenum, m: ptr GLdouble) {.importc.} + proc glUseProgramStages(pipeline: GLuint, stages: GLbitfield, program: GLuint) {.importc.} + proc glVertexStream4sATI(stream: GLenum, x: GLshort, y: GLshort, z: GLshort, w: GLshort) {.importc.} + proc glDrawElementsInstancedNV(mode: GLenum, count: GLsizei, `type`: GLenum, indices: pointer, primcount: GLsizei) {.importc.} + proc glUniform3d(location: GLint, x: GLdouble, y: GLdouble, z: GLdouble) {.importc.} + proc glDebugMessageControlARB(source: GLenum, `type`: GLenum, severity: GLenum, count: GLsizei, ids: ptr GLuint, enabled: GLboolean) {.importc.} + proc glVertexAttribs3svNV(index: GLuint, count: GLsizei, v: ptr GLshort) {.importc.} + proc glElementPointerATI(`type`: GLenum, `pointer`: pointer) {.importc.} + proc glColor4fNormal3fVertex3fvSUN(c: ptr GLfloat, n: ptr GLfloat, v: ptr GLfloat) {.importc.} + proc glGetPerfMonitorCountersAMD(group: GLuint, numCounters: ptr GLint, maxActiveCounters: ptr GLint, counterSize: GLsizei, counters: ptr GLuint) {.importc.} + proc glDispatchCompute(num_groups_x: GLuint, num_groups_y: GLuint, num_groups_z: GLuint) {.importc.} + proc glVertexAttribDivisorNV(index: GLuint, divisor: GLuint) {.importc.} + proc glProgramUniform3uiEXT(program: GLuint, location: GLint, v0: GLuint, v1: GLuint, v2: GLuint) {.importc.} + proc glRenderbufferStorageMultisampleNV(target: GLenum, samples: GLsizei, internalformat: GLenum, width: GLsizei, height: GLsizei) {.importc.} + proc glBinormalPointerEXT(`type`: GLenum, stride: GLsizei, `pointer`: pointer) {.importc.} + proc glRectxvOES(v1: ptr GLfixed, v2: ptr GLfixed) {.importc.} + proc glGenVertexArraysOES(n: GLsizei, arrays: ptr GLuint) {.importc.} + proc glDebugMessageControlKHR(source: GLenum, `type`: GLenum, severity: GLenum, count: GLsizei, ids: ptr GLuint, enabled: GLboolean) {.importc.} + proc glProgramUniform1uiEXT(program: GLuint, location: GLint, v0: GLuint) {.importc.} + proc glPixelTransferi(pname: GLenum, param: GLint) {.importc.} + proc glIsPointInFillPathNV(path: GLuint, mask: GLuint, x: GLfloat, y: GLfloat): GLboolean {.importc.} + proc glVertexBindingDivisor(bindingindex: GLuint, divisor: GLuint) {.importc.} + proc glGetVertexAttribLui64vARB(index: GLuint, pname: GLenum, params: ptr GLuint64Ext) {.importc.} + proc glProgramUniformMatrix3dvEXT(program: GLuint, location: GLint, count: GLsizei, transpose: GLboolean, value: ptr GLdouble) {.importc.} + proc glDrawBuffer(mode: GLenum) {.importc.} + proc glMultiTexCoord1sARB(target: GLenum, s: GLshort) {.importc.} + proc glSeparableFilter2DEXT(target: GLenum, internalformat: GLenum, width: GLsizei, height: GLsizei, format: GLenum, `type`: GLenum, row: pointer, column: pointer) {.importc.} + proc glTangent3bvEXT(v: ptr GLbyte) {.importc.} + proc glTexParameterIuiv(target: GLenum, pname: GLenum, params: ptr GLuint) {.importc.} + proc glVertexAttribL4i64NV(index: GLuint, x: GLint64Ext, y: GLint64Ext, z: GLint64Ext, w: GLint64Ext) {.importc.} + proc glDebugMessageCallbackARB(callback: GLdebugProcArb, userParam: ptr pointer) {.importc.} + proc glMultiTexCoordP1uiv(texture: GLenum, `type`: GLenum, coords: ptr GLuint) {.importc.} + proc glLabelObjectEXT(`type`: GLenum, `object`: GLuint, length: GLsizei, label: cstring) {.importc.} + proc glGetnPolygonStippleARB(bufSize: GLsizei, pattern: ptr GLubyte) {.importc.} + proc glTexCoord3xOES(s: GLfixed, t: GLfixed, r: GLfixed) {.importc.} + proc glCopyPixels(x: GLint, y: GLint, width: GLsizei, height: GLsizei, `type`: GLenum) {.importc.} + proc glGetnUniformfvEXT(program: GLuint, location: GLint, bufSize: GLsizei, params: ptr GLfloat) {.importc.} + proc glColorMaski(index: GLuint, r: GLboolean, g: GLboolean, b: GLboolean, a: GLboolean) {.importc.} + proc glRasterPos2fv(v: ptr GLfloat) {.importc.} + proc glBindBuffersBase(target: GLenum, first: GLuint, count: GLsizei, buffers: ptr GLuint) {.importc.} + proc glSpriteParameterfvSGIX(pname: GLenum, params: ptr GLfloat) {.importc.} + proc glGetSyncivAPPLE(sync: GLsync, pname: GLenum, bufSize: GLsizei, length: ptr GLsizei, values: ptr GLint) {.importc.} + proc glVertexAttribI3i(index: GLuint, x: GLint, y: GLint, z: GLint) {.importc.} + proc glPixelTransformParameteriEXT(target: GLenum, pname: GLenum, param: GLint) {.importc.} + proc glMultiDrawArraysEXT(mode: GLenum, first: ptr GLint, count: ptr GLsizei, primcount: GLsizei) {.importc.} + proc glGetTextureHandleNV(texture: GLuint): GLuint64 {.importc.} + proc glTexCoordP2ui(`type`: GLenum, coords: GLuint) {.importc.} + proc glDeleteQueries(n: GLsizei, ids: ptr GLuint) {.importc.} + proc glGetVertexAttribArrayObjectivATI(index: GLuint, pname: GLenum, params: ptr GLint) {.importc.} + proc glVertexArrayVertexBindingDivisorEXT(vaobj: GLuint, bindingindex: GLuint, divisor: GLuint) {.importc.} + proc glVertex3i(x: GLint, y: GLint, z: GLint) {.importc.} + proc glBlendEquationSeparatei(buf: GLuint, modeRgb: GLenum, modeAlpha: GLenum) {.importc.} + proc glGetMapAttribParameterivNV(target: GLenum, index: GLuint, pname: GLenum, params: ptr GLint) {.importc.} + proc glGetVideoCaptureivNV(video_capture_slot: GLuint, pname: GLenum, params: ptr GLint) {.importc.} + proc glFragmentMaterialfvSGIX(face: GLenum, pname: GLenum, params: ptr GLfloat) {.importc.} + proc glEGLImageTargetTexture2DOES(target: GLenum, image: GLeglImageOes) {.importc.} + proc glCopyImageSubDataNV(srcName: GLuint, srcTarget: GLenum, srcLevel: GLint, srcX: GLint, srcY: GLint, srcZ: GLint, dstName: GLuint, dstTarget: GLenum, dstLevel: GLint, dstX: GLint, dstY: GLint, dstZ: GLint, width: GLsizei, height: GLsizei, depth: GLsizei) {.importc.} + proc glUniform2i(location: GLint, v0: GLint, v1: GLint) {.importc.} + proc glVertexAttrib3fvNV(index: GLuint, v: ptr GLfloat) {.importc.} + proc glNamedBufferStorageEXT(buffer: GLuint, size: GLsizeiptr, data: ptr pointer, flags: GLbitfield) {.importc.} + proc glProgramEnvParameterI4uivNV(target: GLenum, index: GLuint, params: ptr GLuint) {.importc.} + proc glGetVertexAttribdvARB(index: GLuint, pname: GLenum, params: ptr GLdouble) {.importc.} + proc glVertexAttribL3ui64vNV(index: GLuint, v: ptr GLuint64Ext) {.importc.} + proc glUniform4fvARB(location: GLint, count: GLsizei, value: ptr GLfloat) {.importc.} + proc glWeightsvARB(size: GLint, weights: ptr GLshort) {.importc.} + proc glMakeTextureHandleNonResidentARB(handle: GLuint64) {.importc.} + proc glEvalCoord1xOES(u: GLfixed) {.importc.} + proc glVertexAttrib2sv(index: GLuint, v: ptr GLshort) {.importc.} + proc glVertexAttrib4dvNV(index: GLuint, v: ptr GLdouble) {.importc.} + proc glProgramNamedParameter4fNV(id: GLuint, len: GLsizei, name: ptr GLubyte, x: GLfloat, y: GLfloat, z: GLfloat, w: GLfloat) {.importc.} + proc glCompileShaderARB(shaderObj: GLhandleArb) {.importc.} + proc glProgramEnvParameter4fvARB(target: GLenum, index: GLuint, params: ptr GLfloat) {.importc.} + proc glGetVertexAttribiv(index: GLuint, pname: GLenum, params: ptr GLint) {.importc.} + proc glEvalPoint1(i: GLint) {.importc.} + proc glEvalMapsNV(target: GLenum, mode: GLenum) {.importc.} + proc glGetTexGenxvOES(coord: GLenum, pname: GLenum, params: ptr GLfixed) {.importc.} + proc glBlendEquationSeparate(modeRgb: GLenum, modeAlpha: GLenum) {.importc.} + proc glGetColorTableParameterfv(target: GLenum, pname: GLenum, params: ptr GLfloat) {.importc.} + proc glQueryCounterEXT(id: GLuint, target: GLenum) {.importc.} + proc glExtGetProgramBinarySourceQCOM(program: GLuint, shadertype: GLenum, source: cstring, length: ptr GLint) {.importc.} + proc glGetConvolutionParameteriv(target: GLenum, pname: GLenum, params: ptr GLint) {.importc.} + proc glIsProgramPipeline(pipeline: GLuint): GLboolean {.importc.} + proc glVertexWeightfvEXT(weight: ptr GLfloat) {.importc.} + proc glDisableDriverControlQCOM(driverControl: GLuint) {.importc.} + proc glVertexStream1fvATI(stream: GLenum, coords: ptr GLfloat) {.importc.} + proc glMakeTextureHandleResidentNV(handle: GLuint64) {.importc.} + proc glSamplerParameteriv(sampler: GLuint, pname: GLenum, param: ptr GLint) {.importc.} + proc glTexEnvxOES(target: GLenum, pname: GLenum, param: GLfixed) {.importc.} + proc glEndOcclusionQueryNV() {.importc.} + proc glFlushMappedBufferRangeAPPLE(target: GLenum, offset: GLintptr, size: GLsizeiptr) {.importc.} + proc glVertex4iv(v: ptr GLint) {.importc.} + proc glVertexArrayVertexAttribIFormatEXT(vaobj: GLuint, attribindex: GLuint, size: GLint, `type`: GLenum, relativeoffset: GLuint) {.importc.} + proc glDisableIndexedEXT(target: GLenum, index: GLuint) {.importc.} + proc glVertexAttribL1dEXT(index: GLuint, x: GLdouble) {.importc.} + proc glBeginPerfMonitorAMD(monitor: GLuint) {.importc.} + proc glConvolutionFilter1DEXT(target: GLenum, internalformat: GLenum, width: GLsizei, format: GLenum, `type`: GLenum, image: pointer) {.importc.} + proc glPrimitiveRestartIndex(index: GLuint) {.importc.} + proc glWindowPos2dv(v: ptr GLdouble) {.importc.} + proc glBindFramebufferOES(target: GLenum, framebuffer: GLuint) {.importc.} + proc glTessellationModeAMD(mode: GLenum) {.importc.} + proc glIsVariantEnabledEXT(id: GLuint, cap: GLenum): GLboolean {.importc.} + proc glColor3iv(v: ptr GLint) {.importc.} + proc glFogCoordFormatNV(`type`: GLenum, stride: GLsizei) {.importc.} + proc glClearNamedBufferDataEXT(buffer: GLuint, internalformat: GLenum, format: GLenum, `type`: GLenum, data: ptr pointer) {.importc.} + proc glTextureRangeAPPLE(target: GLenum, length: GLsizei, `pointer`: pointer) {.importc.} + proc glTexCoord4bvOES(coords: ptr GLbyte) {.importc.} + proc glRotated(angle: GLdouble, x: GLdouble, y: GLdouble, z: GLdouble) {.importc.} + proc glAccum(op: GLenum, value: GLfloat) {.importc.} + proc glVertex3d(x: GLdouble, y: GLdouble, z: GLdouble) {.importc.} + proc glGetPathMetricRangeNV(metricQueryMask: GLbitfield, firstPathName: GLuint, numPaths: GLsizei, stride: GLsizei, metrics: ptr GLfloat) {.importc.} + proc glUniform4d(location: GLint, x: GLdouble, y: GLdouble, z: GLdouble, w: GLdouble) {.importc.} + proc glTextureSubImage2DEXT(texture: GLuint, target: GLenum, level: GLint, xoffset: GLint, yoffset: GLint, width: GLsizei, height: GLsizei, format: GLenum, `type`: GLenum, pixels: pointer) {.importc.} + proc glMultiTexCoord1iv(target: GLenum, v: ptr GLint) {.importc.} + proc glFogFuncSGIS(n: GLsizei, points: ptr GLfloat) {.importc.} + proc glGetMaterialxOES(face: GLenum, pname: GLenum, param: GLfixed) {.importc.} + proc glGlobalAlphaFactorbSUN(factor: GLbyte) {.importc.} + proc glGetProgramLocalParameterdvARB(target: GLenum, index: GLuint, params: ptr GLdouble) {.importc.} + proc glDeleteProgramsARB(n: GLsizei, programs: ptr GLuint) {.importc.} + proc glVertexStream1sATI(stream: GLenum, x: GLshort) {.importc.} + proc glMatrixTranslatedEXT(mode: GLenum, x: GLdouble, y: GLdouble, z: GLdouble) {.importc.} + proc glTexSubImage1D(target: GLenum, level: GLint, xoffset: GLint, width: GLsizei, format: GLenum, `type`: GLenum, pixels: pointer) {.importc.} + proc glGetBufferSubData(target: GLenum, offset: GLintptr, size: GLsizeiptr, data: pointer) {.importc.} + proc glUniform4uiEXT(location: GLint, v0: GLuint, v1: GLuint, v2: GLuint, v3: GLuint) {.importc.} + proc glGetShaderiv(shader: GLuint, pname: GLenum, params: ptr GLint) {.importc.} + proc glGetQueryIndexediv(target: GLenum, index: GLuint, pname: GLenum, params: ptr GLint) {.importc.} + proc glDebugMessageInsert(source: GLenum, `type`: GLenum, id: GLuint, severity: GLenum, length: GLsizei, buf: cstring) {.importc.} + proc glVertexAttribs2dvNV(index: GLuint, count: GLsizei, v: ptr GLdouble) {.importc.} + proc glGetFixedvOES(pname: GLenum, params: ptr GLfixed) {.importc.} + proc glUniform2iv(location: GLint, count: GLsizei, value: ptr GLint) {.importc.} + proc glTextureView(texture: GLuint, target: GLenum, origtexture: GLuint, internalformat: GLenum, minlevel: GLuint, numlevels: GLuint, minlayer: GLuint, numlayers: GLuint) {.importc.} + proc glMultiTexCoord1xvOES(texture: GLenum, coords: ptr GLfixed) {.importc.} + proc glTexBufferRange(target: GLenum, internalformat: GLenum, buffer: GLuint, offset: GLintptr, size: GLsizeiptr) {.importc.} + proc glMultiTexCoordPointerEXT(texunit: GLenum, size: GLint, `type`: GLenum, stride: GLsizei, `pointer`: pointer) {.importc.} + proc glBlendColorxOES(red: GLfixed, green: GLfixed, blue: GLfixed, alpha: GLfixed) {.importc.} + proc glReadPixels(x: GLint, y: GLint, width: GLsizei, height: GLsizei, format: GLenum, `type`: GLenum, pixels: pointer) {.importc.} + proc glWindowPos3dARB(x: GLdouble, y: GLdouble, z: GLdouble) {.importc.} + proc glPixelTexGenParameterivSGIS(pname: GLenum, params: ptr GLint) {.importc.} + proc glSecondaryColor3svEXT(v: ptr GLshort) {.importc.} + proc glPopGroupMarkerEXT() {.importc.} + proc glImportSyncEXT(external_sync_type: GLenum, external_sync: GLintptr, flags: GLbitfield): GLsync {.importc.} + proc glVertexAttribLFormatNV(index: GLuint, size: GLint, `type`: GLenum, stride: GLsizei) {.importc.} + proc glVertexAttrib2sNV(index: GLuint, x: GLshort, y: GLshort) {.importc.} + proc glGetIntegeri_v(target: GLenum, index: GLuint, data: ptr GLint) {.importc.} + proc glProgramUniform3uiv(program: GLuint, location: GLint, count: GLsizei, value: ptr GLuint) {.importc.} + proc glGetActiveUniformBlockiv(program: GLuint, uniformBlockIndex: GLuint, pname: GLenum, params: ptr GLint) {.importc.} + proc glCreateShaderProgramv(`type`: GLenum, count: GLsizei, strings: cstringArray): GLuint {.importc.} + proc glUniform2fARB(location: GLint, v0: GLfloat, v1: GLfloat) {.importc.} + proc glVertexStream4ivATI(stream: GLenum, coords: ptr GLint) {.importc.} + proc glNormalP3uiv(`type`: GLenum, coords: ptr GLuint) {.importc.} + proc glVertexAttribLFormat(attribindex: GLuint, size: GLint, `type`: GLenum, relativeoffset: GLuint) {.importc.} + proc glTexCoord2bvOES(coords: ptr GLbyte) {.importc.} + proc glGetActiveUniformName(program: GLuint, uniformIndex: GLuint, bufSize: GLsizei, length: ptr GLsizei, uniformName: cstring) {.importc.} + proc glTexCoord2sv(v: ptr GLshort) {.importc.} + proc glVertexAttrib2dNV(index: GLuint, x: GLdouble, y: GLdouble) {.importc.} + proc glGetFogFuncSGIS(points: ptr GLfloat) {.importc.} + proc glSetFenceAPPLE(fence: GLuint) {.importc.} + proc glRasterPos2f(x: GLfloat, y: GLfloat) {.importc.} + proc glVertexWeightPointerEXT(size: GLint, `type`: GLenum, stride: GLsizei, `pointer`: pointer) {.importc.} + proc glEndList() {.importc.} + proc glVDPAUFiniNV() {.importc.} + proc glTbufferMask3DFX(mask: GLuint) {.importc.} + proc glVertexP4ui(`type`: GLenum, value: GLuint) {.importc.} + proc glTexEnviv(target: GLenum, pname: GLenum, params: ptr GLint) {.importc.} + proc glColor4xOES(red: GLfixed, green: GLfixed, blue: GLfixed, alpha: GLfixed) {.importc.} + proc glBlendEquationi(buf: GLuint, mode: GLenum) {.importc.} + proc glLoadMatrixxOES(m: ptr GLfixed) {.importc.} + proc glFogxOES(pname: GLenum, param: GLfixed) {.importc.} + proc glTexCoord4dv(v: ptr GLdouble) {.importc.} + proc glFogCoordPointerListIBM(`type`: GLenum, stride: GLint, `pointer`: ptr pointer, ptrstride: GLint) {.importc.} + proc glGetPerfMonitorGroupsAMD(numGroups: ptr GLint, groupsSize: GLsizei, groups: ptr GLuint) {.importc.} + proc glVertex2hNV(x: GLhalfNv, y: GLhalfNv) {.importc.} + proc glDeleteFragmentShaderATI(id: GLuint) {.importc.} + proc glGetSamplerParameterIiv(sampler: GLuint, pname: GLenum, params: ptr GLint) {.importc.} + proc glUniform2fvARB(location: GLint, count: GLsizei, value: ptr GLfloat) {.importc.} + proc glFogf(pname: GLenum, param: GLfloat) {.importc.} + proc glMultiTexCoord1iARB(target: GLenum, s: GLint) {.importc.} + proc glGetActiveUniformARB(programObj: GLhandleArb, index: GLuint, maxLength: GLsizei, length: ptr GLsizei, size: ptr GLint, `type`: ptr GLenum, name: cstring) {.importc.} + proc glMapGrid1xOES(n: GLint, u1: GLfixed, u2: GLfixed) {.importc.} + proc glIndexsv(c: ptr GLshort) {.importc.} + proc glFragmentMaterialfSGIX(face: GLenum, pname: GLenum, param: GLfloat) {.importc.} + proc glBindTextureEXT(target: GLenum, texture: GLuint) {.importc.} + proc glRectiv(v1: ptr GLint, v2: ptr GLint) {.importc.} + proc glTangent3dEXT(tx: GLdouble, ty: GLdouble, tz: GLdouble) {.importc.} + proc glProgramUniformMatrix3x4fvEXT(program: GLuint, location: GLint, count: GLsizei, transpose: GLboolean, value: ptr GLfloat) {.importc.} + proc glNormal3hNV(nx: GLhalfNv, ny: GLhalfNv, nz: GLhalfNv) {.importc.} + proc glPushClientAttribDefaultEXT(mask: GLbitfield) {.importc.} + proc glUnmapBufferARB(target: GLenum): GLboolean {.importc.} + proc glVertexAttribs1dvNV(index: GLuint, count: GLsizei, v: ptr GLdouble) {.importc.} + proc glUniformMatrix2x3dv(location: GLint, count: GLsizei, transpose: GLboolean, value: ptr GLdouble) {.importc.} + proc glUniform3f(location: GLint, v0: GLfloat, v1: GLfloat, v2: GLfloat) {.importc.} + proc glTexEnvxv(target: GLenum, pname: GLenum, params: ptr GLfixed) {.importc.} + proc glMapBufferOES(target: GLenum, access: GLenum): pointer {.importc.} + proc glBufferData(target: GLenum, size: GLsizeiptr, data: pointer, usage: GLenum) {.importc.} + proc glDrawElementsInstancedANGLE(mode: GLenum, count: GLsizei, `type`: GLenum, indices: ptr pointer, primcount: GLsizei) {.importc.} + proc glGetTextureHandleARB(texture: GLuint): GLuint64 {.importc.} + proc glNormal3f(nx: GLfloat, ny: GLfloat, nz: GLfloat) {.importc.} + proc glTexCoordP3uiv(`type`: GLenum, coords: ptr GLuint) {.importc.} + proc glTexParameterx(target: GLenum, pname: GLenum, param: GLfixed) {.importc.} + proc glMapBufferRange(target: GLenum, offset: GLintptr, length: GLsizeiptr, access: GLbitfield): pointer {.importc.} + proc glTexCoord2fVertex3fSUN(s: GLfloat, t: GLfloat, x: GLfloat, y: GLfloat, z: GLfloat) {.importc.} + proc glVariantArrayObjectATI(id: GLuint, `type`: GLenum, stride: GLsizei, buffer: GLuint, offset: GLuint) {.importc.} + proc glGetnHistogramARB(target: GLenum, reset: GLboolean, format: GLenum, `type`: GLenum, bufSize: GLsizei, values: pointer) {.importc.} + proc glWindowPos3sv(v: ptr GLshort) {.importc.} + proc glGetVariantPointervEXT(id: GLuint, value: GLenum, data: ptr pointer) {.importc.} + proc glGetLightfv(light: GLenum, pname: GLenum, params: ptr GLfloat) {.importc.} + proc glGetnTexImageARB(target: GLenum, level: GLint, format: GLenum, `type`: GLenum, bufSize: GLsizei, img: pointer) {.importc.} + proc glGenRenderbuffersEXT(n: GLsizei, renderbuffers: ptr GLuint) {.importc.} + proc glMultiDrawArraysIndirectBindlessNV(mode: GLenum, indirect: pointer, drawCount: GLsizei, stride: GLsizei, vertexBufferCount: GLint) {.importc.} + proc glDisableClientStateIndexedEXT(`array`: GLenum, index: GLuint) {.importc.} + proc glMapGrid1f(un: GLint, u1: GLfloat, u2: GLfloat) {.importc.} + proc glTexStorage2D(target: GLenum, levels: GLsizei, internalformat: GLenum, width: GLsizei, height: GLsizei) {.importc.} + proc glShaderStorageBlockBinding(program: GLuint, storageBlockIndex: GLuint, storageBlockBinding: GLuint) {.importc.} + proc glBlendBarrierNV() {.importc.} + proc glGetVideoui64vNV(video_slot: GLuint, pname: GLenum, params: ptr GLuint64Ext) {.importc.} + proc glUniform3ui64NV(location: GLint, x: GLuint64Ext, y: GLuint64Ext, z: GLuint64Ext) {.importc.} + proc glUniform4ivARB(location: GLint, count: GLsizei, value: ptr GLint) {.importc.} + proc glGetQueryObjectivARB(id: GLuint, pname: GLenum, params: ptr GLint) {.importc.} + proc glCompressedTexSubImage3DOES(target: GLenum, level: GLint, xoffset: GLint, yoffset: GLint, zoffset: GLint, width: GLsizei, height: GLsizei, depth: GLsizei, format: GLenum, imageSize: GLsizei, data: pointer) {.importc.} + proc glEnableIndexedEXT(target: GLenum, index: GLuint) {.importc.} + proc glNamedRenderbufferStorageMultisampleCoverageEXT(renderbuffer: GLuint, coverageSamples: GLsizei, colorSamples: GLsizei, internalformat: GLenum, width: GLsizei, height: GLsizei) {.importc.} + proc glVertexAttribI3iEXT(index: GLuint, x: GLint, y: GLint, z: GLint) {.importc.} + proc glUniform4uivEXT(location: GLint, count: GLsizei, value: ptr GLuint) {.importc.} + proc glGetUniformLocation(program: GLuint, name: cstring): GLint {.importc.} + proc glCurrentPaletteMatrixARB(index: GLint) {.importc.} + proc glVertexAttribLPointerEXT(index: GLuint, size: GLint, `type`: GLenum, stride: GLsizei, `pointer`: pointer) {.importc.} + proc glFogCoorddvEXT(coord: ptr GLdouble) {.importc.} + proc glInitNames() {.importc.} + proc glGetPathSpacingNV(pathListMode: GLenum, numPaths: GLsizei, pathNameType: GLenum, paths: pointer, pathBase: GLuint, advanceScale: GLfloat, kerningScale: GLfloat, transformType: GLenum, returnedSpacing: ptr GLfloat) {.importc.} + proc glNormal3fVertex3fvSUN(n: ptr GLfloat, v: ptr GLfloat) {.importc.} + proc glTexCoord2iv(v: ptr GLint) {.importc.} + proc glWindowPos3s(x: GLshort, y: GLshort, z: GLshort) {.importc.} + proc glProgramUniformMatrix3x4fv(program: GLuint, location: GLint, count: GLsizei, transpose: GLboolean, value: ptr GLfloat) {.importc.} + proc glVertexAttribP4ui(index: GLuint, `type`: GLenum, normalized: GLboolean, value: GLuint) {.importc.} + proc glVertexAttribs4ubvNV(index: GLuint, count: GLsizei, v: ptr GLubyte) {.importc.} + proc glProgramLocalParameterI4iNV(target: GLenum, index: GLuint, x: GLint, y: GLint, z: GLint, w: GLint) {.importc.} + proc glStencilMaskSeparate(face: GLenum, mask: GLuint) {.importc.} + proc glClientWaitSync(sync: GLsync, flags: GLbitfield, timeout: GLuint64): GLenum {.importc.} + proc glPolygonOffsetx(factor: GLfixed, units: GLfixed) {.importc.} + proc glCreateProgramObjectARB(): GLhandleArb {.importc.} + proc glClearColorIuiEXT(red: GLuint, green: GLuint, blue: GLuint, alpha: GLuint) {.importc.} + proc glDeleteTransformFeedbacksNV(n: GLsizei, ids: ptr GLuint) {.importc.} + proc glFramebufferDrawBuffersEXT(framebuffer: GLuint, n: GLsizei, bufs: ptr GLenum) {.importc.} + proc glAreTexturesResident(n: GLsizei, textures: ptr GLuint, residences: ptr GLboolean): GLboolean {.importc.} + proc glNamedBufferDataEXT(buffer: GLuint, size: GLsizeiptr, data: pointer, usage: GLenum) {.importc.} + proc glGetInvariantFloatvEXT(id: GLuint, value: GLenum, data: ptr GLfloat) {.importc.} + proc glMultiTexCoord4d(target: GLenum, s: GLdouble, t: GLdouble, r: GLdouble, q: GLdouble) {.importc.} + proc glGetPixelTransformParameterfvEXT(target: GLenum, pname: GLenum, params: ptr GLfloat) {.importc.} + proc glGetStringi(name: GLenum, index: GLuint): ptr GLubyte {.importc.} + proc glMakeBufferNonResidentNV(target: GLenum) {.importc.} + proc glVertex4bOES(x: GLbyte, y: GLbyte, z: GLbyte) {.importc.} + proc glGetObjectLabel(identifier: GLenum, name: GLuint, bufSize: GLsizei, length: ptr GLsizei, label: cstring) {.importc.} + proc glClipPlanexOES(plane: GLenum, equation: ptr GLfixed) {.importc.} + proc glElementPointerAPPLE(`type`: GLenum, `pointer`: pointer) {.importc.} + proc glIsAsyncMarkerSGIX(marker: GLuint): GLboolean {.importc.} + proc glUseShaderProgramEXT(`type`: GLenum, program: GLuint) {.importc.} + proc glReplacementCodeuiColor4ubVertex3fSUN(rc: GLuint, r: GLubyte, g: GLubyte, b: GLubyte, a: GLubyte, x: GLfloat, y: GLfloat, z: GLfloat) {.importc.} + proc glIsTransformFeedback(id: GLuint): GLboolean {.importc.} + proc glEdgeFlag(flag: GLboolean) {.importc.} + proc glGetTexGeniv(coord: GLenum, pname: GLenum, params: ptr GLint) {.importc.} + proc glBeginQueryEXT(target: GLenum, id: GLuint) {.importc.} + proc glUniform1uiEXT(location: GLint, v0: GLuint) {.importc.} + proc glProgramUniform3fvEXT(program: GLuint, location: GLint, count: GLsizei, value: ptr GLfloat) {.importc.} + proc glGetVideoi64vNV(video_slot: GLuint, pname: GLenum, params: ptr GLint64Ext) {.importc.} + proc glProgramUniform3ui(program: GLuint, location: GLint, v0: GLuint, v1: GLuint, v2: GLuint) {.importc.} + proc glSecondaryColor3uiEXT(red: GLuint, green: GLuint, blue: GLuint) {.importc.} + proc glPathStencilFuncNV(fun: GLenum, `ref`: GLint, mask: GLuint) {.importc.} + proc glVertexAttribP1ui(index: GLuint, `type`: GLenum, normalized: GLboolean, value: GLuint) {.importc.} + proc glStencilFillPathInstancedNV(numPaths: GLsizei, pathNameType: GLenum, paths: pointer, pathBase: GLuint, fillMode: GLenum, mask: GLuint, transformType: GLenum, transformValues: ptr GLfloat) {.importc.} + proc glFogCoordfEXT(coord: GLfloat) {.importc.} + proc glTextureParameterIuivEXT(texture: GLuint, target: GLenum, pname: GLenum, params: ptr GLuint) {.importc.} + proc glProgramUniform4dEXT(program: GLuint, location: GLint, x: GLdouble, y: GLdouble, z: GLdouble, w: GLdouble) {.importc.} + proc glFramebufferTextureFaceARB(target: GLenum, attachment: GLenum, texture: GLuint, level: GLint, face: GLenum) {.importc.} + proc glTexCoord3s(s: GLshort, t: GLshort, r: GLshort) {.importc.} + proc glGetFramebufferAttachmentParameteriv(target: GLenum, attachment: GLenum, pname: GLenum, params: ptr GLint) {.importc.} + proc glEndVideoCaptureNV(video_capture_slot: GLuint) {.importc.} + proc glProgramUniformMatrix2x4dv(program: GLuint, location: GLint, count: GLsizei, transpose: GLboolean, value: ptr GLdouble) {.importc.} + proc glGetFloatIndexedvEXT(target: GLenum, index: GLuint, data: ptr GLfloat) {.importc.} + proc glTexCoord1xOES(s: GLfixed) {.importc.} + proc glTexCoord4f(s: GLfloat, t: GLfloat, r: GLfloat, q: GLfloat) {.importc.} + proc glShaderSource(shader: GLuint, count: GLsizei, string: cstringArray, length: ptr GLint) {.importc.} + proc glGetDetailTexFuncSGIS(target: GLenum, points: ptr GLfloat) {.importc.} + proc glResetHistogram(target: GLenum) {.importc.} + proc glVertexAttribP2ui(index: GLuint, `type`: GLenum, normalized: GLboolean, value: GLuint) {.importc.} + proc glDrawTransformFeedbackNV(mode: GLenum, id: GLuint) {.importc.} + proc glWindowPos2fMESA(x: GLfloat, y: GLfloat) {.importc.} + proc glObjectLabelKHR(identifier: GLenum, name: GLuint, length: GLsizei, label: cstring) {.importc.} + proc glMultiTexCoord2iARB(target: GLenum, s: GLint, t: GLint) {.importc.} + proc glVertexAttrib4usv(index: GLuint, v: ptr GLushort) {.importc.} + proc glGetGraphicsResetStatusARB(): GLenum {.importc.} + proc glProgramUniform3dEXT(program: GLuint, location: GLint, x: GLdouble, y: GLdouble, z: GLdouble) {.importc.} + proc glPathSubCommandsNV(path: GLuint, commandStart: GLsizei, commandsToDelete: GLsizei, numCommands: GLsizei, commands: ptr GLubyte, numCoords: GLsizei, coordType: GLenum, coords: pointer) {.importc.} + proc glEndTransformFeedbackNV() {.importc.} + proc glWindowPos2sMESA(x: GLshort, y: GLshort) {.importc.} + proc glTangent3sEXT(tx: GLshort, ty: GLshort, tz: GLshort) {.importc.} + proc glLineWidthx(width: GLfixed) {.importc.} + proc glGetUniformBufferSizeEXT(program: GLuint, location: GLint): GLint {.importc.} + proc glTexCoord2bOES(s: GLbyte, t: GLbyte) {.importc.} + proc glWindowPos3iMESA(x: GLint, y: GLint, z: GLint) {.importc.} + proc glTexGend(coord: GLenum, pname: GLenum, param: GLdouble) {.importc.} + proc glRenderbufferStorageMultisampleANGLE(target: GLenum, samples: GLsizei, internalformat: GLenum, width: GLsizei, height: GLsizei) {.importc.} + proc glGetProgramiv(program: GLuint, pname: GLenum, params: ptr GLint) {.importc.} + proc glDrawTransformFeedbackStreamInstanced(mode: GLenum, id: GLuint, stream: GLuint, instancecount: GLsizei) {.importc.} + proc glMatrixTranslatefEXT(mode: GLenum, x: GLfloat, y: GLfloat, z: GLfloat) {.importc.} + proc glColor4iv(v: ptr GLint) {.importc.} + proc glSecondaryColor3ivEXT(v: ptr GLint) {.importc.} + proc glIsNamedStringARB(namelen: GLint, name: cstring): GLboolean {.importc.} + proc glVertexAttribL4dv(index: GLuint, v: ptr GLdouble) {.importc.} + proc glEndTransformFeedback() {.importc.} + proc glVertexStream3fvATI(stream: GLenum, coords: ptr GLfloat) {.importc.} + proc glProgramUniformMatrix4x2dv(program: GLuint, location: GLint, count: GLsizei, transpose: GLboolean, value: ptr GLdouble) {.importc.} + proc glTextureBufferRangeEXT(texture: GLuint, target: GLenum, internalformat: GLenum, buffer: GLuint, offset: GLintptr, size: GLsizeiptr) {.importc.} + proc glTexCoord2fNormal3fVertex3fvSUN(tc: ptr GLfloat, n: ptr GLfloat, v: ptr GLfloat) {.importc.} + proc glProgramUniform2f(program: GLuint, location: GLint, v0: GLfloat, v1: GLfloat) {.importc.} + proc glMultiTexCoord2sv(target: GLenum, v: ptr GLshort) {.importc.} + proc glTexCoord3bOES(s: GLbyte, t: GLbyte, r: GLbyte) {.importc.} + proc glGenFramebuffersOES(n: GLsizei, framebuffers: ptr GLuint) {.importc.} + proc glMultiTexCoord3sv(target: GLenum, v: ptr GLshort) {.importc.} + proc glVertexAttrib4Nub(index: GLuint, x: GLubyte, y: GLubyte, z: GLubyte, w: GLubyte) {.importc.} + proc glColor3d(red: GLdouble, green: GLdouble, blue: GLdouble) {.importc.} + proc glGetActiveAttrib(program: GLuint, index: GLuint, bufSize: GLsizei, length: ptr GLsizei, size: ptr GLint, `type`: ptr GLenum, name: cstring) {.importc.} + proc glConvolutionParameterfEXT(target: GLenum, pname: GLenum, params: GLfloat) {.importc.} + proc glTexSubImage2DEXT(target: GLenum, level: GLint, xoffset: GLint, yoffset: GLint, width: GLsizei, height: GLsizei, format: GLenum, `type`: GLenum, pixels: pointer) {.importc.} + proc glBinormal3fvEXT(v: ptr GLfloat) {.importc.} + proc glDebugMessageControl(source: GLenum, `type`: GLenum, severity: GLenum, count: GLsizei, ids: ptr GLuint, enabled: GLboolean) {.importc.} + proc glProgramUniform3uivEXT(program: GLuint, location: GLint, count: GLsizei, value: ptr GLuint) {.importc.} + proc glPNTrianglesiATI(pname: GLenum, param: GLint) {.importc.} + proc glGetPerfMonitorCounterInfoAMD(group: GLuint, counter: GLuint, pname: GLenum, data: pointer) {.importc.} + proc glVertexAttribL3ui64NV(index: GLuint, x: GLuint64Ext, y: GLuint64Ext, z: GLuint64Ext) {.importc.} + proc glIsRenderbufferOES(renderbuffer: GLuint): GLboolean {.importc.} + proc glColorSubTable(target: GLenum, start: GLsizei, count: GLsizei, format: GLenum, `type`: GLenum, data: pointer) {.importc.} + proc glCompressedMultiTexImage1DEXT(texunit: GLenum, target: GLenum, level: GLint, internalformat: GLenum, width: GLsizei, border: GLint, imageSize: GLsizei, bits: pointer) {.importc.} + proc glBindSampler(unit: GLuint, sampler: GLuint) {.importc.} + proc glVariantubvEXT(id: GLuint, `addr`: ptr GLubyte) {.importc.} + proc glDisablei(target: GLenum, index: GLuint) {.importc.} + proc glVertexAttribI2uiEXT(index: GLuint, x: GLuint, y: GLuint) {.importc.} + proc glDrawElementArrayATI(mode: GLenum, count: GLsizei) {.importc.} + proc glTagSampleBufferSGIX() {.importc.} + proc glVertexPointerEXT(size: GLint, `type`: GLenum, stride: GLsizei, count: GLsizei, `pointer`: pointer) {.importc.} + proc glFragmentLightiSGIX(light: GLenum, pname: GLenum, param: GLint) {.importc.} + proc glLoadTransposeMatrixxOES(m: ptr GLfixed) {.importc.} + proc glProgramLocalParameter4fvARB(target: GLenum, index: GLuint, params: ptr GLfloat) {.importc.} + proc glGetVariantFloatvEXT(id: GLuint, value: GLenum, data: ptr GLfloat) {.importc.} + proc glProgramUniform4ui64vNV(program: GLuint, location: GLint, count: GLsizei, value: ptr GLuint64Ext) {.importc.} + proc glFragmentLightfSGIX(light: GLenum, pname: GLenum, param: GLfloat) {.importc.} + proc glIsVertexArrayAPPLE(`array`: GLuint): GLboolean {.importc.} + proc glTexCoord1bvOES(coords: ptr GLbyte) {.importc.} + proc glUniform4fv(location: GLint, count: GLsizei, value: ptr GLfloat) {.importc.} + proc glPixelDataRangeNV(target: GLenum, length: GLsizei, `pointer`: pointer) {.importc.} + proc glUniformMatrix4x2fv(location: GLint, count: GLsizei, transpose: GLboolean, value: ptr GLfloat) {.importc.} + proc glRectf(x1: GLfloat, y1: GLfloat, x2: GLfloat, y2: GLfloat) {.importc.} + proc glCoverageMaskNV(mask: GLboolean) {.importc.} + proc glPointParameterfvSGIS(pname: GLenum, params: ptr GLfloat) {.importc.} + proc glProgramUniformMatrix4x2dvEXT(program: GLuint, location: GLint, count: GLsizei, transpose: GLboolean, value: ptr GLdouble) {.importc.} + proc glFragmentLightModelfSGIX(pname: GLenum, param: GLfloat) {.importc.} + proc glDisableVertexAttribAPPLE(index: GLuint, pname: GLenum) {.importc.} + proc glMultiTexCoord3dvARB(target: GLenum, v: ptr GLdouble) {.importc.} + proc glTexCoord4iv(v: ptr GLint) {.importc.} + proc glUniform1f(location: GLint, v0: GLfloat) {.importc.} + proc glVertexAttribParameteriAMD(index: GLuint, pname: GLenum, param: GLint) {.importc.} + proc glGetConvolutionParameterfv(target: GLenum, pname: GLenum, params: ptr GLfloat) {.importc.} + proc glRecti(x1: GLint, y1: GLint, x2: GLint, y2: GLint) {.importc.} + proc glTexEnvxvOES(target: GLenum, pname: GLenum, params: ptr GLfixed) {.importc.} + proc glGetRenderbufferParameteriv(target: GLenum, pname: GLenum, params: ptr GLint) {.importc.} + proc glBlendFuncIndexedAMD(buf: GLuint, src: GLenum, dst: GLenum) {.importc.} + proc glProgramUniformMatrix3x2fv(program: GLuint, location: GLint, count: GLsizei, transpose: GLboolean, value: ptr GLfloat) {.importc.} + proc glDrawArraysInstancedANGLE(mode: GLenum, first: GLint, count: GLsizei, primcount: GLsizei) {.importc.} + proc glTextureBarrierNV() {.importc.} + proc glDrawBuffersIndexedEXT(n: GLint, location: ptr GLenum, indices: ptr GLint) {.importc.} + proc glUniformMatrix4fvARB(location: GLint, count: GLsizei, transpose: GLboolean, value: ptr GLfloat) {.importc.} + proc glInstrumentsBufferSGIX(size: GLsizei, buffer: ptr GLint) {.importc.} + proc glAlphaFuncQCOM(fun: GLenum, `ref`: GLclampf) {.importc.} + proc glUniformMatrix4fv(location: GLint, count: GLsizei, transpose: GLboolean, value: ptr GLfloat) {.importc.} + proc glGetMinmaxParameteriv(target: GLenum, pname: GLenum, params: ptr GLint) {.importc.} + proc glGetInvariantBooleanvEXT(id: GLuint, value: GLenum, data: ptr GLboolean) {.importc.} + proc glVDPAUIsSurfaceNV(surface: GLvdpauSurfaceNv) {.importc.} + proc glGenProgramsARB(n: GLsizei, programs: ptr GLuint) {.importc.} + proc glDrawRangeElementArrayATI(mode: GLenum, start: GLuint, `end`: GLuint, count: GLsizei) {.importc.} + proc glFramebufferRenderbufferEXT(target: GLenum, attachment: GLenum, renderbuffertarget: GLenum, renderbuffer: GLuint) {.importc.} + proc glClearIndex(c: GLfloat) {.importc.} + proc glDepthRangeIndexed(index: GLuint, n: GLdouble, f: GLdouble) {.importc.} + proc glDrawTexivOES(coords: ptr GLint) {.importc.} + proc glTangent3iEXT(tx: GLint, ty: GLint, tz: GLint) {.importc.} + proc glStringMarkerGREMEDY(len: GLsizei, string: pointer) {.importc.} + proc glTexCoordP1ui(`type`: GLenum, coords: GLuint) {.importc.} + proc glOrthox(l: GLfixed, r: GLfixed, b: GLfixed, t: GLfixed, n: GLfixed, f: GLfixed) {.importc.} + proc glReplacementCodeuiVertex3fvSUN(rc: ptr GLuint, v: ptr GLfloat) {.importc.} + proc glMultiTexCoord1bvOES(texture: GLenum, coords: ptr GLbyte) {.importc.} + proc glDrawArraysInstancedBaseInstance(mode: GLenum, first: GLint, count: GLsizei, instancecount: GLsizei, baseinstance: GLuint) {.importc.} + proc glMultMatrixf(m: ptr GLfloat) {.importc.} + proc glProgramUniform4i(program: GLuint, location: GLint, v0: GLint, v1: GLint, v2: GLint, v3: GLint) {.importc.} + proc glScissorArrayv(first: GLuint, count: GLsizei, v: ptr GLint) {.importc.} + proc glGetnUniformivEXT(program: GLuint, location: GLint, bufSize: GLsizei, params: ptr GLint) {.importc.} + proc glGetTexEnvxvOES(target: GLenum, pname: GLenum, params: ptr GLfixed) {.importc.} + proc glWindowPos3ivARB(v: ptr GLint) {.importc.} + proc glProgramStringARB(target: GLenum, format: GLenum, len: GLsizei, string: pointer) {.importc.} + proc glTextureColorMaskSGIS(red: GLboolean, green: GLboolean, blue: GLboolean, alpha: GLboolean) {.importc.} + proc glMultiTexCoord4fv(target: GLenum, v: ptr GLfloat) {.importc.} + proc glUniformMatrix4x3fv(location: GLint, count: GLsizei, transpose: GLboolean, value: ptr GLfloat) {.importc.} + proc glIsPathNV(path: GLuint): GLboolean {.importc.} + proc glStartTilingQCOM(x: GLuint, y: GLuint, width: GLuint, height: GLuint, preserveMask: GLbitfield) {.importc.} + proc glVariantivEXT(id: GLuint, `addr`: ptr GLint) {.importc.} + proc glGetnMinmaxARB(target: GLenum, reset: GLboolean, format: GLenum, `type`: GLenum, bufSize: GLsizei, values: pointer) {.importc.} + proc glTransformFeedbackVaryings(program: GLuint, count: GLsizei, varyings: cstringArray, bufferMode: GLenum) {.importc.} + proc glShaderOp2EXT(op: GLenum, res: GLuint, arg1: GLuint, arg2: GLuint) {.importc.} + proc glVertexAttribPointer(index: GLuint, size: GLint, `type`: GLenum, normalized: GLboolean, stride: GLsizei, `pointer`: pointer) {.importc.} + proc glMultiTexCoord4dvARB(target: GLenum, v: ptr GLdouble) {.importc.} + proc glProgramUniform1ui64NV(program: GLuint, location: GLint, x: GLuint64Ext) {.importc.} + proc glGetShaderSourceARB(obj: GLhandleArb, maxLength: GLsizei, length: ptr GLsizei, source: cstring) {.importc.} + proc glGetBufferSubDataARB(target: GLenum, offset: GLintPtrArb, size: GLsizeiptrArb, data: pointer) {.importc.} + proc glCopyTexSubImage2D(target: GLenum, level: GLint, xoffset: GLint, yoffset: GLint, x: GLint, y: GLint, width: GLsizei, height: GLsizei) {.importc.} + proc glProgramEnvParameterI4iNV(target: GLenum, index: GLuint, x: GLint, y: GLint, z: GLint, w: GLint) {.importc.} + proc glGetVertexAttribivARB(index: GLuint, pname: GLenum, params: ptr GLint) {.importc.} + proc glGetFinalCombinerInputParameterivNV(variable: GLenum, pname: GLenum, params: ptr GLint) {.importc.} + proc glIndexFuncEXT(fun: GLenum, `ref`: GLclampf) {.importc.} + proc glProgramUniformMatrix3dv(program: GLuint, location: GLint, count: GLsizei, transpose: GLboolean, value: ptr GLdouble) {.importc.} + proc glTexStorage1DEXT(target: GLenum, levels: GLsizei, internalformat: GLenum, width: GLsizei) {.importc.} + proc glUniformMatrix2fv(location: GLint, count: GLsizei, transpose: GLboolean, value: ptr GLfloat) {.importc.} + proc glConvolutionParameterf(target: GLenum, pname: GLenum, params: GLfloat) {.importc.} + proc glGlobalAlphaFactordSUN(factor: GLdouble) {.importc.} + proc glCopyTextureImage2DEXT(texture: GLuint, target: GLenum, level: GLint, internalformat: GLenum, x: GLint, y: GLint, width: GLsizei, height: GLsizei, border: GLint) {.importc.} + proc glVertex4xOES(x: GLfixed, y: GLfixed, z: GLfixed) {.importc.} + proc glClearDepthx(depth: GLfixed) {.importc.} + proc glGetColorTableParameteriv(target: GLenum, pname: GLenum, params: ptr GLint) {.importc.} + proc glGenProgramPipelines(n: GLsizei, pipelines: ptr GLuint) {.importc.} + proc glVertexAttribL4ui64vNV(index: GLuint, v: ptr GLuint64Ext) {.importc.} + proc glUniform1fARB(location: GLint, v0: GLfloat) {.importc.} + proc glUniformMatrix3fv(location: GLint, count: GLsizei, transpose: GLboolean, value: ptr GLfloat) {.importc.} + proc glUniform3dv(location: GLint, count: GLsizei, value: ptr GLdouble) {.importc.} + proc glVertexAttribI4iv(index: GLuint, v: ptr GLint) {.importc.} + proc glPixelZoom(xfactor: GLfloat, yfactor: GLfloat) {.importc.} + proc glShadeModel(mode: GLenum) {.importc.} + proc glFramebufferTexture3DOES(target: GLenum, attachment: GLenum, textarget: GLenum, texture: GLuint, level: GLint, zoffset: GLint) {.importc.} + proc glMultiTexCoord2i(target: GLenum, s: GLint, t: GLint) {.importc.} + proc glBlendEquationSeparateIndexedAMD(buf: GLuint, modeRgb: GLenum, modeAlpha: GLenum) {.importc.} + proc glIsEnabled(cap: GLenum): GLboolean {.importc.} + proc glTexImage2D(target: GLenum, level: GLint, internalformat: GLint, width: GLsizei, height: GLsizei, border: GLint, format: GLenum, `type`: GLenum, pixels: pointer) {.importc.} + proc glPolygonOffsetxOES(factor: GLfixed, units: GLfixed) {.importc.} + proc glDrawBuffersEXT(n: GLsizei, bufs: ptr GLenum) {.importc.} + proc glPixelTexGenParameterfSGIS(pname: GLenum, param: GLfloat) {.importc.} + proc glExtGetRenderbuffersQCOM(renderbuffers: ptr GLuint, maxRenderbuffers: GLint, numRenderbuffers: ptr GLint) {.importc.} + proc glBindImageTextures(first: GLuint, count: GLsizei, textures: ptr GLuint) {.importc.} + proc glVertexAttribP2uiv(index: GLuint, `type`: GLenum, normalized: GLboolean, value: ptr GLuint) {.importc.} + proc glTextureImage3DMultisampleCoverageNV(texture: GLuint, target: GLenum, coverageSamples: GLsizei, colorSamples: GLsizei, internalFormat: GLint, width: GLsizei, height: GLsizei, depth: GLsizei, fixedSampleLocations: GLboolean) {.importc.} + proc glRasterPos2s(x: GLshort, y: GLshort) {.importc.} + proc glVertexAttrib4dvARB(index: GLuint, v: ptr GLdouble) {.importc.} + proc glProgramUniformMatrix2x3fvEXT(program: GLuint, location: GLint, count: GLsizei, transpose: GLboolean, value: ptr GLfloat) {.importc.} + proc glProgramUniformMatrix2x4dvEXT(program: GLuint, location: GLint, count: GLsizei, transpose: GLboolean, value: ptr GLdouble) {.importc.} + proc glMultiTexCoord1d(target: GLenum, s: GLdouble) {.importc.} + proc glGetProgramParameterdvNV(target: GLenum, index: GLuint, pname: GLenum, params: ptr GLdouble) {.importc.} + proc glPNTrianglesfATI(pname: GLenum, param: GLfloat) {.importc.} + proc glUniformMatrix3x4fv(location: GLint, count: GLsizei, transpose: GLboolean, value: ptr GLfloat) {.importc.} + proc glVertexAttrib3sNV(index: GLuint, x: GLshort, y: GLshort, z: GLshort) {.importc.} + proc glGetVideoCaptureStreamfvNV(video_capture_slot: GLuint, stream: GLuint, pname: GLenum, params: ptr GLfloat) {.importc.} + proc glCombinerParameterivNV(pname: GLenum, params: ptr GLint) {.importc.} + proc glGetTexGenfvOES(coord: GLenum, pname: GLenum, params: ptr GLfloat) {.importc.} + proc glCopyTexSubImage2DEXT(target: GLenum, level: GLint, xoffset: GLint, yoffset: GLint, x: GLint, y: GLint, width: GLsizei, height: GLsizei) {.importc.} + proc glGetProgramLocalParameterfvARB(target: GLenum, index: GLuint, params: ptr GLfloat) {.importc.} + proc glTexCoord3iv(v: ptr GLint) {.importc.} + proc glVertexAttribs2hvNV(index: GLuint, n: GLsizei, v: ptr GLhalfNv) {.importc.} + proc glNormal3sv(v: ptr GLshort) {.importc.} + proc glUniform2dv(location: GLint, count: GLsizei, value: ptr GLdouble) {.importc.} + proc glSecondaryColor3hvNV(v: ptr GLhalfNv) {.importc.} + proc glDrawArraysInstancedEXT(mode: GLenum, start: GLint, count: GLsizei, primcount: GLsizei) {.importc.} + proc glBeginTransformFeedback(primitiveMode: GLenum) {.importc.} + proc glTexParameterIuivEXT(target: GLenum, pname: GLenum, params: ptr GLuint) {.importc.} + proc glProgramBufferParametersfvNV(target: GLenum, bindingIndex: GLuint, wordIndex: GLuint, count: GLsizei, params: ptr GLfloat) {.importc.} + proc glVertexArrayBindVertexBufferEXT(vaobj: GLuint, bindingindex: GLuint, buffer: GLuint, offset: GLintptr, stride: GLsizei) {.importc.} + proc glPathParameterfNV(path: GLuint, pname: GLenum, value: GLfloat) {.importc.} + proc glGetClipPlanexOES(plane: GLenum, equation: ptr GLfixed) {.importc.} + proc glSecondaryColor3ubvEXT(v: ptr GLubyte) {.importc.} + proc glGetPixelMapxv(map: GLenum, size: GLint, values: ptr GLfixed) {.importc.} + proc glVertexAttribI1uivEXT(index: GLuint, v: ptr GLuint) {.importc.} + proc glMultiTexImage3DEXT(texunit: GLenum, target: GLenum, level: GLint, internalformat: GLint, width: GLsizei, height: GLsizei, depth: GLsizei, border: GLint, format: GLenum, `type`: GLenum, pixels: pointer) {.importc.} + proc glAlphaFuncxOES(fun: GLenum, `ref`: GLfixed) {.importc.} + proc glMultiTexCoord2dv(target: GLenum, v: ptr GLdouble) {.importc.} + proc glBindRenderbufferOES(target: GLenum, renderbuffer: GLuint) {.importc.} + proc glPathStencilDepthOffsetNV(factor: GLfloat, units: GLfloat) {.importc.} + proc glPointParameterfvEXT(pname: GLenum, params: ptr GLfloat) {.importc.} + proc glSampleCoverageARB(value: GLfloat, invert: GLboolean) {.importc.} + proc glVertexAttrib3dNV(index: GLuint, x: GLdouble, y: GLdouble, z: GLdouble) {.importc.} + proc glNamedProgramLocalParameter4dvEXT(program: GLuint, target: GLenum, index: GLuint, params: ptr GLdouble) {.importc.} + proc glGenFramebuffers(n: GLsizei, framebuffers: ptr GLuint) {.importc.} + proc glMultiDrawElementsEXT(mode: GLenum, count: ptr GLsizei, `type`: GLenum, indices: ptr pointer, primcount: GLsizei) {.importc.} + proc glVertexAttrib2fNV(index: GLuint, x: GLfloat, y: GLfloat) {.importc.} + proc glProgramUniform4ivEXT(program: GLuint, location: GLint, count: GLsizei, value: ptr GLint) {.importc.} + proc glTexGeniOES(coord: GLenum, pname: GLenum, param: GLint) {.importc.} + proc glBindProgramPipeline(pipeline: GLuint) {.importc.} + proc glBindSamplers(first: GLuint, count: GLsizei, samplers: ptr GLuint) {.importc.} + proc glColorTableSGI(target: GLenum, internalformat: GLenum, width: GLsizei, format: GLenum, `type`: GLenum, table: pointer) {.importc.} + proc glMultiTexCoord3xOES(texture: GLenum, s: GLfixed, t: GLfixed, r: GLfixed) {.importc.} + proc glIsQueryEXT(id: GLuint): GLboolean {.importc.} + proc glGenBuffersARB(n: GLsizei, buffers: ptr GLuint) {.importc.} + proc glVertex4xvOES(coords: ptr GLfixed) {.importc.} + proc glPixelMapuiv(map: GLenum, mapsize: GLsizei, values: ptr GLuint) {.importc.} + proc glDrawTexfOES(x: GLfloat, y: GLfloat, z: GLfloat, width: GLfloat, height: GLfloat) {.importc.} + proc glPointParameterfEXT(pname: GLenum, param: GLfloat) {.importc.} + proc glPathDashArrayNV(path: GLuint, dashCount: GLsizei, dashArray: ptr GLfloat) {.importc.} + proc glClearTexImage(texture: GLuint, level: GLint, format: GLenum, `type`: GLenum, data: ptr pointer) {.importc.} + proc glIndexdv(c: ptr GLdouble) {.importc.} + proc glMultTransposeMatrixfARB(m: ptr GLfloat) {.importc.} + proc glVertexAttribL3d(index: GLuint, x: GLdouble, y: GLdouble, z: GLdouble) {.importc.} + proc glUniform3fv(location: GLint, count: GLsizei, value: ptr GLfloat) {.importc.} + proc glGetProgramInterfaceiv(program: GLuint, programInterface: GLenum, pname: GLenum, params: ptr GLint) {.importc.} + proc glFogCoordfv(coord: ptr GLfloat) {.importc.} + proc glTexSubImage3DOES(target: GLenum, level: GLint, xoffset: GLint, yoffset: GLint, zoffset: GLint, width: GLsizei, height: GLsizei, depth: GLsizei, format: GLenum, `type`: GLenum, pixels: pointer) {.importc.} + proc glGetPolygonStipple(mask: ptr GLubyte) {.importc.} + proc glGetQueryObjectivEXT(id: GLuint, pname: GLenum, params: ptr GLint) {.importc.} + proc glColor3xOES(red: GLfixed, green: GLfixed, blue: GLfixed) {.importc.} + proc glMultiTexParameterIivEXT(texunit: GLenum, target: GLenum, pname: GLenum, params: ptr GLint) {.importc.} + proc glGetMaterialiv(face: GLenum, pname: GLenum, params: ptr GLint) {.importc.} + proc glVertex2fv(v: ptr GLfloat) {.importc.} + proc glConvolutionParameterivEXT(target: GLenum, pname: GLenum, params: ptr GLint) {.importc.} + proc glGenOcclusionQueriesNV(n: GLsizei, ids: ptr GLuint) {.importc.} + proc glGetVertexAttribdvNV(index: GLuint, pname: GLenum, params: ptr GLdouble) {.importc.} + proc glVertexAttribs4fvNV(index: GLuint, count: GLsizei, v: ptr GLfloat) {.importc.} + proc glVertexAttribL3dv(index: GLuint, v: ptr GLdouble) {.importc.} + proc glTexEnvi(target: GLenum, pname: GLenum, param: GLint) {.importc.} + proc glObjectPtrLabel(`ptr`: ptr pointer, length: GLsizei, label: cstring) {.importc.} + proc glGetTexGenfv(coord: GLenum, pname: GLenum, params: ptr GLfloat) {.importc.} + proc glMapVertexAttrib1dAPPLE(index: GLuint, size: GLuint, u1: GLdouble, u2: GLdouble, stride: GLint, order: GLint, points: ptr GLdouble) {.importc.} + proc glTexCoord3dv(v: ptr GLdouble) {.importc.} + proc glIsEnabledIndexedEXT(target: GLenum, index: GLuint): GLboolean {.importc.} + proc glGlobalAlphaFactoruiSUN(factor: GLuint) {.importc.} + proc glMatrixIndexPointerARB(size: GLint, `type`: GLenum, stride: GLsizei, `pointer`: pointer) {.importc.} + proc glUniformHandleui64ARB(location: GLint, value: GLuint64) {.importc.} + proc glUniform1fvARB(location: GLint, count: GLsizei, value: ptr GLfloat) {.importc.} + proc glGetActiveSubroutineUniformName(program: GLuint, shadertype: GLenum, index: GLuint, bufsize: GLsizei, length: ptr GLsizei, name: cstring) {.importc.} + proc glProgramUniformMatrix4x2fvEXT(program: GLuint, location: GLint, count: GLsizei, transpose: GLboolean, value: ptr GLfloat) {.importc.} + proc glMultiTexCoord4fARB(target: GLenum, s: GLfloat, t: GLfloat, r: GLfloat, q: GLfloat) {.importc.} + proc glGetDriverControlsQCOM(num: ptr GLint, size: GLsizei, driverControls: ptr GLuint) {.importc.} + proc glBindBufferRange(target: GLenum, index: GLuint, buffer: GLuint, offset: GLintptr, size: GLsizeiptr) {.importc.} + proc glMapGrid2f(un: GLint, u1: GLfloat, u2: GLfloat, vn: GLint, v1: GLfloat, v2: GLfloat) {.importc.} + proc glUniform2fv(location: GLint, count: GLsizei, value: ptr GLfloat) {.importc.} + proc glOrtho(left: GLdouble, right: GLdouble, bottom: GLdouble, top: GLdouble, zNear: GLdouble, zFar: GLdouble) {.importc.} + proc glGetImageHandleNV(texture: GLuint, level: GLint, layered: GLboolean, layer: GLint, format: GLenum): GLuint64 {.importc.} + proc glIsImageHandleResidentARB(handle: GLuint64): GLboolean {.importc.} + proc glGetConvolutionParameterivEXT(target: GLenum, pname: GLenum, params: ptr GLint) {.importc.} + proc glLineWidthxOES(width: GLfixed) {.importc.} + proc glPathCommandsNV(path: GLuint, numCommands: GLsizei, commands: ptr GLubyte, numCoords: GLsizei, coordType: GLenum, coords: pointer) {.importc.} + proc glMaterialxvOES(face: GLenum, pname: GLenum, param: ptr GLfixed) {.importc.} + proc glPauseTransformFeedbackNV() {.importc.} + proc glTexCoord4d(s: GLdouble, t: GLdouble, r: GLdouble, q: GLdouble) {.importc.} + proc glUniform3ui64vNV(location: GLint, count: GLsizei, value: ptr GLuint64Ext) {.importc.} + proc glMultiTexCoord3dARB(target: GLenum, s: GLdouble, t: GLdouble, r: GLdouble) {.importc.} + proc glProgramUniform3fEXT(program: GLuint, location: GLint, v0: GLfloat, v1: GLfloat, v2: GLfloat) {.importc.} + proc glTexImage3DMultisampleCoverageNV(target: GLenum, coverageSamples: GLsizei, colorSamples: GLsizei, internalFormat: GLint, width: GLsizei, height: GLsizei, depth: GLsizei, fixedSampleLocations: GLboolean) {.importc.} + proc glNormalPointerEXT(`type`: GLenum, stride: GLsizei, count: GLsizei, `pointer`: pointer) {.importc.} + proc glPathColorGenNV(color: GLenum, genMode: GLenum, colorFormat: GLenum, coeffs: ptr GLfloat) {.importc.} + proc glGetMultiTexGendvEXT(texunit: GLenum, coord: GLenum, pname: GLenum, params: ptr GLdouble) {.importc.} + proc glColor3i(red: GLint, green: GLint, blue: GLint) {.importc.} + proc glPointSizex(size: GLfixed) {.importc.} + proc glGetConvolutionFilterEXT(target: GLenum, format: GLenum, `type`: GLenum, image: pointer) {.importc.} + proc glBindBufferBaseNV(target: GLenum, index: GLuint, buffer: GLuint) {.importc.} + proc glInsertComponentEXT(res: GLuint, src: GLuint, num: GLuint) {.importc.} + proc glVertex2d(x: GLdouble, y: GLdouble) {.importc.} + proc glGetPathDashArrayNV(path: GLuint, dashArray: ptr GLfloat) {.importc.} + proc glVertexAttrib2sARB(index: GLuint, x: GLshort, y: GLshort) {.importc.} + proc glScissor(x: GLint, y: GLint, width: GLsizei, height: GLsizei) {.importc.} + proc glLoadMatrixd(m: ptr GLdouble) {.importc.} + proc glVertex2bvOES(coords: ptr GLbyte) {.importc.} + proc glTexCoord2i(s: GLint, t: GLint) {.importc.} + proc glWriteMaskEXT(res: GLuint, `in`: GLuint, outX: GLenum, outY: GLenum, outZ: GLenum, outW: GLenum) {.importc.} + proc glClientWaitSyncAPPLE(sync: GLsync, flags: GLbitfield, timeout: GLuint64): GLenum {.importc.} + proc glGetObjectBufferivATI(buffer: GLuint, pname: GLenum, params: ptr GLint) {.importc.} + proc glGetNamedBufferParameterivEXT(buffer: GLuint, pname: GLenum, params: ptr GLint) {.importc.} + proc glTexCoord1bOES(s: GLbyte) {.importc.} + proc glVertexAttrib4dARB(index: GLuint, x: GLdouble, y: GLdouble, z: GLdouble, w: GLdouble) {.importc.} + proc glUniform3fARB(location: GLint, v0: GLfloat, v1: GLfloat, v2: GLfloat) {.importc.} + proc glWindowPos2ivARB(v: ptr GLint) {.importc.} + proc glCreateShaderProgramvEXT(`type`: GLenum, count: GLsizei, strings: cstringArray): GLuint {.importc.} + proc glListParameterivSGIX(list: GLuint, pname: GLenum, params: ptr GLint) {.importc.} + proc glGetGraphicsResetStatusEXT(): GLenum {.importc.} + proc glActiveShaderProgramEXT(pipeline: GLuint, program: GLuint) {.importc.} + proc glTexCoordP1uiv(`type`: GLenum, coords: ptr GLuint) {.importc.} + proc glVideoCaptureStreamParameterdvNV(video_capture_slot: GLuint, stream: GLuint, pname: GLenum, params: ptr GLdouble) {.importc.} + proc glGetVertexAttribPointerv(index: GLuint, pname: GLenum, `pointer`: ptr pointer) {.importc.} + proc glGetCompressedMultiTexImageEXT(texunit: GLenum, target: GLenum, lod: GLint, img: pointer) {.importc.} + proc glWindowPos4fMESA(x: GLfloat, y: GLfloat, z: GLfloat, w: GLfloat) {.importc.} + proc glDrawElementsInstancedARB(mode: GLenum, count: GLsizei, `type`: GLenum, indices: pointer, primcount: GLsizei) {.importc.} + proc glVertexStream1dATI(stream: GLenum, x: GLdouble) {.importc.} + proc glMatrixMultfEXT(mode: GLenum, m: ptr GLfloat) {.importc.} + proc glGetPathParameterivNV(path: GLuint, pname: GLenum, value: ptr GLint) {.importc.} + proc glCombinerParameteriNV(pname: GLenum, param: GLint) {.importc.} + proc glUpdateObjectBufferATI(buffer: GLuint, offset: GLuint, size: GLsizei, `pointer`: pointer, preserve: GLenum) {.importc.} + proc glVertexAttrib4uivARB(index: GLuint, v: ptr GLuint) {.importc.} + proc glVertexAttrib4iv(index: GLuint, v: ptr GLint) {.importc.} + proc glFrustum(left: GLdouble, right: GLdouble, bottom: GLdouble, top: GLdouble, zNear: GLdouble, zFar: GLdouble) {.importc.} + proc glDrawTexxvOES(coords: ptr GLfixed) {.importc.} + proc glTexCoord2fColor4ubVertex3fSUN(s: GLfloat, t: GLfloat, r: GLubyte, g: GLubyte, b: GLubyte, a: GLubyte, x: GLfloat, y: GLfloat, z: GLfloat) {.importc.} + proc glMultiTexCoord2fARB(target: GLenum, s: GLfloat, t: GLfloat) {.importc.} + proc glGenTransformFeedbacksNV(n: GLsizei, ids: ptr GLuint) {.importc.} + proc glMultiTexGenfEXT(texunit: GLenum, coord: GLenum, pname: GLenum, param: GLfloat) {.importc.} + proc glGetMinmax(target: GLenum, reset: GLboolean, format: GLenum, `type`: GLenum, values: pointer) {.importc.} + proc glBindTransformFeedback(target: GLenum, id: GLuint) {.importc.} + proc glEnableVertexAttribArrayARB(index: GLuint) {.importc.} + proc glIsFenceAPPLE(fence: GLuint): GLboolean {.importc.} + proc glMultiTexGendvEXT(texunit: GLenum, coord: GLenum, pname: GLenum, params: ptr GLdouble) {.importc.} + proc glRotatex(angle: GLfixed, x: GLfixed, y: GLfixed, z: GLfixed) {.importc.} + proc glGetFragmentLightfvSGIX(light: GLenum, pname: GLenum, params: ptr GLfloat) {.importc.} + proc glMultiTexCoord4dv(target: GLenum, v: ptr GLdouble) {.importc.} + proc glBlendFuncSeparateEXT(sfactorRgb: GLenum, dfactorRgb: GLenum, sfactorAlpha: GLenum, dfactorAlpha: GLenum) {.importc.} + proc glMultiTexCoord1f(target: GLenum, s: GLfloat) {.importc.} + proc glWindowPos2f(x: GLfloat, y: GLfloat) {.importc.} + proc glGetPathTexGenivNV(texCoordSet: GLenum, pname: GLenum, value: ptr GLint) {.importc.} + proc glIndexxvOES(component: ptr GLfixed) {.importc.} + proc glDisableVertexArrayAttribEXT(vaobj: GLuint, index: GLuint) {.importc.} + proc glGetProgramivARB(target: GLenum, pname: GLenum, params: ptr GLint) {.importc.} + proc glPatchParameteri(pname: GLenum, value: GLint) {.importc.} + proc glMultiTexCoord2fv(target: GLenum, v: ptr GLfloat) {.importc.} + proc glTexSubImage3DEXT(target: GLenum, level: GLint, xoffset: GLint, yoffset: GLint, zoffset: GLint, width: GLsizei, height: GLsizei, depth: GLsizei, format: GLenum, `type`: GLenum, pixels: pointer) {.importc.} + proc glFramebufferTexture1DEXT(target: GLenum, attachment: GLenum, textarget: GLenum, texture: GLuint, level: GLint) {.importc.} + proc glTangent3fEXT(tx: GLfloat, ty: GLfloat, tz: GLfloat) {.importc.} + proc glIsVertexAttribEnabledAPPLE(index: GLuint, pname: GLenum): GLboolean {.importc.} + proc glGetShaderInfoLog(shader: GLuint, bufSize: GLsizei, length: ptr GLsizei, infoLog: cstring) {.importc.} + proc glFrustumx(l: GLfixed, r: GLfixed, b: GLfixed, t: GLfixed, n: GLfixed, f: GLfixed) {.importc.} + proc glTexGenfv(coord: GLenum, pname: GLenum, params: ptr GLfloat) {.importc.} + proc glCompressedTexImage2DARB(target: GLenum, level: GLint, internalformat: GLenum, width: GLsizei, height: GLsizei, border: GLint, imageSize: GLsizei, data: pointer) {.importc.} + proc glMultiTexCoord2bvOES(texture: GLenum, coords: ptr GLbyte) {.importc.} + proc glGetTexBumpParameterivATI(pname: GLenum, param: ptr GLint) {.importc.} + proc glMultiTexCoord2svARB(target: GLenum, v: ptr GLshort) {.importc.} + proc glProgramBufferParametersIivNV(target: GLenum, bindingIndex: GLuint, wordIndex: GLuint, count: GLsizei, params: ptr GLint) {.importc.} + proc glIsQueryARB(id: GLuint): GLboolean {.importc.} + proc glFramebufferTextureLayer(target: GLenum, attachment: GLenum, texture: GLuint, level: GLint, layer: GLint) {.importc.} + proc glUniform4i(location: GLint, v0: GLint, v1: GLint, v2: GLint, v3: GLint) {.importc.} + proc glDrawArrays(mode: GLenum, first: GLint, count: GLsizei) {.importc.} + proc glWeightubvARB(size: GLint, weights: ptr GLubyte) {.importc.} + proc glGetUniformSubroutineuiv(shadertype: GLenum, location: GLint, params: ptr GLuint) {.importc.} + proc glMultTransposeMatrixdARB(m: ptr GLdouble) {.importc.} + proc glReplacementCodeuiTexCoord2fNormal3fVertex3fvSUN(rc: ptr GLuint, tc: ptr GLfloat, n: ptr GLfloat, v: ptr GLfloat) {.importc.} + proc glGetMapdv(target: GLenum, query: GLenum, v: ptr GLdouble) {.importc.} + proc glGetMultisamplefvNV(pname: GLenum, index: GLuint, val: ptr GLfloat) {.importc.} + proc glVertex2hvNV(v: ptr GLhalfNv) {.importc.} + proc glProgramUniformMatrix2x3fv(program: GLuint, location: GLint, count: GLsizei, transpose: GLboolean, value: ptr GLfloat) {.importc.} + proc glProgramUniform3iEXT(program: GLuint, location: GLint, v0: GLint, v1: GLint, v2: GLint) {.importc.} + proc glGetnPixelMapusvARB(map: GLenum, bufSize: GLsizei, values: ptr GLushort) {.importc.} + proc glVertexWeighthvNV(weight: ptr GLhalfNv) {.importc.} + proc glDrawTransformFeedbackInstanced(mode: GLenum, id: GLuint, instancecount: GLsizei) {.importc.} + proc glFlushStaticDataIBM(target: GLenum) {.importc.} + proc glWindowPos2fvARB(v: ptr GLfloat) {.importc.} + proc glMultiTexCoord3sARB(target: GLenum, s: GLshort, t: GLshort, r: GLshort) {.importc.} + proc glWindowPos3fv(v: ptr GLfloat) {.importc.} + proc glFlushVertexArrayRangeNV() {.importc.} + proc glTangent3bEXT(tx: GLbyte, ty: GLbyte, tz: GLbyte) {.importc.} + proc glIglooInterfaceSGIX(pname: GLenum, params: pointer) {.importc.} + proc glProgramUniformMatrix4x2fv(program: GLuint, location: GLint, count: GLsizei, transpose: GLboolean, value: ptr GLfloat) {.importc.} + proc glVertexAttribIFormatNV(index: GLuint, size: GLint, `type`: GLenum, stride: GLsizei) {.importc.} + proc glNamedRenderbufferStorageMultisampleEXT(renderbuffer: GLuint, samples: GLsizei, internalformat: GLenum, width: GLsizei, height: GLsizei) {.importc.} + proc glCopyTexImage1DEXT(target: GLenum, level: GLint, internalformat: GLenum, x: GLint, y: GLint, width: GLsizei, border: GLint) {.importc.} + proc glBindTexGenParameterEXT(unit: GLenum, coord: GLenum, value: GLenum): GLuint {.importc.} + proc glVertex4hNV(x: GLhalfNv, y: GLhalfNv, z: GLhalfNv, w: GLhalfNv) {.importc.} + proc glGetMapfv(target: GLenum, query: GLenum, v: ptr GLfloat) {.importc.} + proc glSamplePatternEXT(pattern: GLenum) {.importc.} + proc glIndexxOES(component: GLfixed) {.importc.} + proc glVertexAttrib4ubv(index: GLuint, v: ptr GLubyte) {.importc.} + proc glGetColorTable(target: GLenum, format: GLenum, `type`: GLenum, table: pointer) {.importc.} + proc glFragmentLightModelivSGIX(pname: GLenum, params: ptr GLint) {.importc.} + proc glPixelTransformParameterfEXT(target: GLenum, pname: GLenum, param: GLfloat) {.importc.} + proc glSamplerParameterfv(sampler: GLuint, pname: GLenum, param: ptr GLfloat) {.importc.} + proc glBindTextureUnitParameterEXT(unit: GLenum, value: GLenum): GLuint {.importc.} + proc glColor3ub(red: GLubyte, green: GLubyte, blue: GLubyte) {.importc.} + proc glGetMultiTexGenivEXT(texunit: GLenum, coord: GLenum, pname: GLenum, params: ptr GLint) {.importc.} + proc glVariantusvEXT(id: GLuint, `addr`: ptr GLushort) {.importc.} + proc glMaterialiv(face: GLenum, pname: GLenum, params: ptr GLint) {.importc.} + proc glPassTexCoordATI(dst: GLuint, coord: GLuint, swizzle: GLenum) {.importc.} + proc glGetIntegerui64vNV(value: GLenum, result: ptr GLuint64Ext) {.importc.} + proc glProgramParameteriEXT(program: GLuint, pname: GLenum, value: GLint) {.importc.} + proc glVertexArrayEdgeFlagOffsetEXT(vaobj: GLuint, buffer: GLuint, stride: GLsizei, offset: GLintptr) {.importc.} + proc glGetCombinerInputParameterivNV(stage: GLenum, portion: GLenum, variable: GLenum, pname: GLenum, params: ptr GLint) {.importc.} + proc glLogicOp(opcode: GLenum) {.importc.} + proc glConvolutionParameterfvEXT(target: GLenum, pname: GLenum, params: ptr GLfloat) {.importc.} + proc glIsBufferResidentNV(target: GLenum): GLboolean {.importc.} + proc glIsProgram(program: GLuint): GLboolean {.importc.} + proc glEndQueryARB(target: GLenum) {.importc.} + proc glRenderbufferStorage(target: GLenum, internalformat: GLenum, width: GLsizei, height: GLsizei) {.importc.} + proc glMaterialfv(face: GLenum, pname: GLenum, params: ptr GLfloat) {.importc.} + proc glTranslatex(x: GLfixed, y: GLfixed, z: GLfixed) {.importc.} + proc glPathParameterivNV(path: GLuint, pname: GLenum, value: ptr GLint) {.importc.} + proc glLightxOES(light: GLenum, pname: GLenum, param: GLfixed) {.importc.} + proc glSampleMaskEXT(value: GLclampf, invert: GLboolean) {.importc.} + proc glReplacementCodeubvSUN(code: ptr GLubyte) {.importc.} + proc glVertexAttribArrayObjectATI(index: GLuint, size: GLint, `type`: GLenum, normalized: GLboolean, stride: GLsizei, buffer: GLuint, offset: GLuint) {.importc.} + proc glBeginTransformFeedbackNV(primitiveMode: GLenum) {.importc.} + proc glEvalCoord1fv(u: ptr GLfloat) {.importc.} + proc glProgramUniformMatrix2x3dvEXT(program: GLuint, location: GLint, count: GLsizei, transpose: GLboolean, value: ptr GLdouble) {.importc.} + proc glMaterialxv(face: GLenum, pname: GLenum, param: ptr GLfixed) {.importc.} + proc glGetIntegerui64i_vNV(value: GLenum, index: GLuint, result: ptr GLuint64Ext) {.importc.} + proc glUniformBlockBinding(program: GLuint, uniformBlockIndex: GLuint, uniformBlockBinding: GLuint) {.importc.} + proc glColor4ui(red: GLuint, green: GLuint, blue: GLuint, alpha: GLuint) {.importc.} + proc glColor4ubVertex2fvSUN(c: ptr GLubyte, v: ptr GLfloat) {.importc.} + proc glRectd(x1: GLdouble, y1: GLdouble, x2: GLdouble, y2: GLdouble) {.importc.} + proc glGenVertexShadersEXT(range: GLuint): GLuint {.importc.} + proc glLinkProgramARB(programObj: GLhandleArb) {.importc.} + proc glVertexAttribL4dEXT(index: GLuint, x: GLdouble, y: GLdouble, z: GLdouble, w: GLdouble) {.importc.} + proc glBlitFramebuffer(srcX0: GLint, srcY0: GLint, srcX1: GLint, srcY1: GLint, dstX0: GLint, dstY0: GLint, dstX1: GLint, dstY1: GLint, mask: GLbitfield, filter: GLenum) {.importc.} + proc glUseProgram(program: GLuint) {.importc.} + proc glNamedProgramLocalParameterI4ivEXT(program: GLuint, target: GLenum, index: GLuint, params: ptr GLint) {.importc.} + proc glMatrixLoadTransposedEXT(mode: GLenum, m: ptr GLdouble) {.importc.} + proc glTranslatef(x: GLfloat, y: GLfloat, z: GLfloat) {.importc.} + proc glGetBooleani_v(target: GLenum, index: GLuint, data: ptr GLboolean) {.importc.} + proc glEndFragmentShaderATI() {.importc.} + proc glVertexAttribI4ivEXT(index: GLuint, v: ptr GLint) {.importc.} + proc glMultiDrawElementsIndirectBindlessNV(mode: GLenum, `type`: GLenum, indirect: pointer, drawCount: GLsizei, stride: GLsizei, vertexBufferCount: GLint) {.importc.} + proc glTexCoord2s(s: GLshort, t: GLshort) {.importc.} + proc glProgramUniform1i64vNV(program: GLuint, location: GLint, count: GLsizei, value: ptr GLint64Ext) {.importc.} + proc glPointSizePointerOES(`type`: GLenum, stride: GLsizei, `pointer`: ptr pointer) {.importc.} + proc glGetTexFilterFuncSGIS(target: GLenum, filter: GLenum, weights: ptr GLfloat) {.importc.} + proc glMapGrid2xOES(n: GLint, u1: GLfixed, u2: GLfixed, v1: GLfixed, v2: GLfixed) {.importc.} + proc glRasterPos4xvOES(coords: ptr GLfixed) {.importc.} + proc glGetProgramBinary(program: GLuint, bufSize: GLsizei, length: ptr GLsizei, binaryFormat: ptr GLenum, binary: pointer) {.importc.} + proc glNamedProgramLocalParameterI4uiEXT(program: GLuint, target: GLenum, index: GLuint, x: GLuint, y: GLuint, z: GLuint, w: GLuint) {.importc.} + proc glGetTexImage(target: GLenum, level: GLint, format: GLenum, `type`: GLenum, pixels: pointer) {.importc.} + proc glColor4d(red: GLdouble, green: GLdouble, blue: GLdouble, alpha: GLdouble) {.importc.} + proc glTexCoord2fColor4fNormal3fVertex3fSUN(s: GLfloat, t: GLfloat, r: GLfloat, g: GLfloat, b: GLfloat, a: GLfloat, nx: GLfloat, ny: GLfloat, nz: GLfloat, x: GLfloat, y: GLfloat, z: GLfloat) {.importc.} + proc glIndexi(c: GLint) {.importc.} + proc glGetSamplerParameterIuiv(sampler: GLuint, pname: GLenum, params: ptr GLuint) {.importc.} + proc glGetnUniformivARB(program: GLuint, location: GLint, bufSize: GLsizei, params: ptr GLint) {.importc.} + proc glCopyTexSubImage3DEXT(target: GLenum, level: GLint, xoffset: GLint, yoffset: GLint, zoffset: GLint, x: GLint, y: GLint, width: GLsizei, height: GLsizei) {.importc.} + proc glVertexAttribI2uivEXT(index: GLuint, v: ptr GLuint) {.importc.} + proc glVertexStream2fvATI(stream: GLenum, coords: ptr GLfloat) {.importc.} + proc glArrayElementEXT(i: GLint) {.importc.} + proc glVertexAttrib2fv(index: GLuint, v: ptr GLfloat) {.importc.} + proc glCopyMultiTexSubImage1DEXT(texunit: GLenum, target: GLenum, level: GLint, xoffset: GLint, x: GLint, y: GLint, width: GLsizei) {.importc.} + proc glTexCoord4sv(v: ptr GLshort) {.importc.} + proc glTexGenfvOES(coord: GLenum, pname: GLenum, params: ptr GLfloat) {.importc.} + proc glPointParameteriv(pname: GLenum, params: ptr GLint) {.importc.} + proc glGetNamedRenderbufferParameterivEXT(renderbuffer: GLuint, pname: GLenum, params: ptr GLint) {.importc.} + proc glProgramVertexLimitNV(target: GLenum, limit: GLint) {.importc.} + proc glSetMultisamplefvAMD(pname: GLenum, index: GLuint, val: ptr GLfloat) {.importc.} + proc glLoadIdentityDeformationMapSGIX(mask: GLbitfield) {.importc.} + proc glIsSyncAPPLE(sync: GLsync): GLboolean {.importc.} + proc glProgramUniform1ui64vNV(program: GLuint, location: GLint, count: GLsizei, value: ptr GLuint64Ext) {.importc.} + proc glEdgeFlagPointerListIBM(stride: GLint, `pointer`: ptr ptr GLboolean, ptrstride: GLint) {.importc.} + proc glBeginVertexShaderEXT() {.importc.} + proc glGetIntegerv(pname: GLenum, params: ptr GLint) {.importc.} + proc glVertexAttrib2dvARB(index: GLuint, v: ptr GLdouble) {.importc.} + proc glBeginConditionalRenderNV(id: GLuint, mode: GLenum) {.importc.} + proc glEdgeFlagv(flag: ptr GLboolean) {.importc.} + proc glReplacementCodeubSUN(code: GLubyte) {.importc.} + proc glObjectLabel(identifier: GLenum, name: GLuint, length: GLsizei, label: cstring) {.importc.} + proc glMultiTexCoord3xvOES(texture: GLenum, coords: ptr GLfixed) {.importc.} + proc glNormal3iv(v: ptr GLint) {.importc.} + proc glSamplerParameteri(sampler: GLuint, pname: GLenum, param: GLint) {.importc.} + proc glTextureStorage1DEXT(texture: GLuint, target: GLenum, levels: GLsizei, internalformat: GLenum, width: GLsizei) {.importc.} + proc glVertexStream4dvATI(stream: GLenum, coords: ptr GLdouble) {.importc.} + proc glWindowPos2fv(v: ptr GLfloat) {.importc.} + proc glTexCoord4i(s: GLint, t: GLint, r: GLint, q: GLint) {.importc.} + proc glVertexAttrib4NusvARB(index: GLuint, v: ptr GLushort) {.importc.} + proc glVertexAttribL4d(index: GLuint, x: GLdouble, y: GLdouble, z: GLdouble, w: GLdouble) {.importc.} + proc glVertexAttribDivisorANGLE(index: GLuint, divisor: GLuint) {.importc.} + proc glMatrixIndexPointerOES(size: GLint, `type`: GLenum, stride: GLsizei, `pointer`: pointer) {.importc.} + proc glMultMatrixxOES(m: ptr GLfixed) {.importc.} + proc glMultiTexCoordP2ui(texture: GLenum, `type`: GLenum, coords: GLuint) {.importc.} + proc glDeformationMap3dSGIX(target: GLenum, u1: GLdouble, u2: GLdouble, ustride: GLint, uorder: GLint, v1: GLdouble, v2: GLdouble, vstride: GLint, vorder: GLint, w1: GLdouble, w2: GLdouble, wstride: GLint, worder: GLint, points: ptr GLdouble) {.importc.} + proc glClearDepthfOES(depth: GLclampf) {.importc.} + proc glVertexStream1ivATI(stream: GLenum, coords: ptr GLint) {.importc.} + proc glHint(target: GLenum, mode: GLenum) {.importc.} + proc glVertex3fv(v: ptr GLfloat) {.importc.} + proc glWaitSyncAPPLE(sync: GLsync, flags: GLbitfield, timeout: GLuint64) {.importc.} + proc glWindowPos3i(x: GLint, y: GLint, z: GLint) {.importc.} + proc glCompressedTexImage3DARB(target: GLenum, level: GLint, internalformat: GLenum, width: GLsizei, height: GLsizei, depth: GLsizei, border: GLint, imageSize: GLsizei, data: pointer) {.importc.} + proc glVertexAttrib1fvARB(index: GLuint, v: ptr GLfloat) {.importc.} + proc glMultiTexCoord4xOES(texture: GLenum, s: GLfixed, t: GLfixed, r: GLfixed, q: GLfixed) {.importc.} + proc glUniform4ui64NV(location: GLint, x: GLuint64Ext, y: GLuint64Ext, z: GLuint64Ext, w: GLuint64Ext) {.importc.} + proc glProgramUniform4uiEXT(program: GLuint, location: GLint, v0: GLuint, v1: GLuint, v2: GLuint, v3: GLuint) {.importc.} + proc glUnmapNamedBufferEXT(buffer: GLuint): GLboolean {.importc.} + proc glBitmap(width: GLsizei, height: GLsizei, xorig: GLfloat, yorig: GLfloat, xmove: GLfloat, ymove: GLfloat, bitmap: ptr GLubyte) {.importc.} + proc glNamedProgramLocalParameters4fvEXT(program: GLuint, target: GLenum, index: GLuint, count: GLsizei, params: ptr GLfloat) {.importc.} + proc glGetPathCommandsNV(path: GLuint, commands: ptr GLubyte) {.importc.} + proc glVertexAttrib3fNV(index: GLuint, x: GLfloat, y: GLfloat, z: GLfloat) {.importc.} + proc glNamedProgramStringEXT(program: GLuint, target: GLenum, format: GLenum, len: GLsizei, string: pointer) {.importc.} + proc glMatrixIndexusvARB(size: GLint, indices: ptr GLushort) {.importc.} + proc glBlitFramebufferNV(srcX0: GLint, srcY0: GLint, srcX1: GLint, srcY1: GLint, dstX0: GLint, dstY0: GLint, dstX1: GLint, dstY1: GLint, mask: GLbitfield, filter: GLenum) {.importc.} + proc glVertexAttribI1uiv(index: GLuint, v: ptr GLuint) {.importc.} + proc glEndConditionalRenderNV() {.importc.} + proc glFeedbackBuffer(size: GLsizei, `type`: GLenum, buffer: ptr GLfloat) {.importc.} + proc glMultiTexCoord3bvOES(texture: GLenum, coords: ptr GLbyte) {.importc.} + proc glCopyColorTableSGI(target: GLenum, internalformat: GLenum, x: GLint, y: GLint, width: GLsizei) {.importc.} + proc glActiveTexture(texture: GLenum) {.importc.} + proc glFogCoordhNV(fog: GLhalfNv) {.importc.} + proc glColorMaskIndexedEXT(index: GLuint, r: GLboolean, g: GLboolean, b: GLboolean, a: GLboolean) {.importc.} + proc glGetCompressedTexImage(target: GLenum, level: GLint, img: pointer) {.importc.} + proc glRasterPos2iv(v: ptr GLint) {.importc.} + proc glGetBufferParameterivARB(target: GLenum, pname: GLenum, params: ptr GLint) {.importc.} + proc glProgramUniform3d(program: GLuint, location: GLint, v0: GLdouble, v1: GLdouble, v2: GLdouble) {.importc.} + proc glRasterPos3xvOES(coords: ptr GLfixed) {.importc.} + proc glGetTextureParameterIuivEXT(texture: GLuint, target: GLenum, pname: GLenum, params: ptr GLuint) {.importc.} + proc glBindImageTextureEXT(index: GLuint, texture: GLuint, level: GLint, layered: GLboolean, layer: GLint, access: GLenum, format: GLint) {.importc.} + proc glWindowPos2iMESA(x: GLint, y: GLint) {.importc.} + proc glVertexPointervINTEL(size: GLint, `type`: GLenum, `pointer`: ptr pointer) {.importc.} + proc glPixelTexGenParameterfvSGIS(pname: GLenum, params: ptr GLfloat) {.importc.} + proc glUniform1iARB(location: GLint, v0: GLint) {.importc.} + proc glTextureSubImage3DEXT(texture: GLuint, target: GLenum, level: GLint, xoffset: GLint, yoffset: GLint, zoffset: GLint, width: GLsizei, height: GLsizei, depth: GLsizei, format: GLenum, `type`: GLenum, pixels: pointer) {.importc.} + proc glStencilOpSeparate(face: GLenum, sfail: GLenum, dpfail: GLenum, dppass: GLenum) {.importc.} + proc glVertexAttrib1dARB(index: GLuint, x: GLdouble) {.importc.} + proc glGetVideoCaptureStreamivNV(video_capture_slot: GLuint, stream: GLuint, pname: GLenum, params: ptr GLint) {.importc.} + proc glIsFramebufferEXT(framebuffer: GLuint): GLboolean {.importc.} + proc glPointParameterxv(pname: GLenum, params: ptr GLfixed) {.importc.} + proc glProgramUniform4dv(program: GLuint, location: GLint, count: GLsizei, value: ptr GLdouble) {.importc.} + proc glPassThrough(token: GLfloat) {.importc.} + proc glGetProgramPipelineiv(pipeline: GLuint, pname: GLenum, params: ptr GLint) {.importc.} + proc glApplyTextureEXT(mode: GLenum) {.importc.} + proc glVertexArrayNormalOffsetEXT(vaobj: GLuint, buffer: GLuint, `type`: GLenum, stride: GLsizei, offset: GLintptr) {.importc.} + proc glTexFilterFuncSGIS(target: GLenum, filter: GLenum, n: GLsizei, weights: ptr GLfloat) {.importc.} + proc glRenderbufferStorageOES(target: GLenum, internalformat: GLenum, width: GLsizei, height: GLsizei) {.importc.} + proc glBindParameterEXT(value: GLenum): GLuint {.importc.} + proc glVertex4s(x: GLshort, y: GLshort, z: GLshort, w: GLshort) {.importc.} + proc glLoadTransposeMatrixf(m: ptr GLfloat) {.importc.} + proc glDepthFunc(fun: GLenum) {.importc.} + proc glGetFramebufferAttachmentParameterivEXT(target: GLenum, attachment: GLenum, pname: GLenum, params: ptr GLint) {.importc.} + proc glSampleMaskSGIS(value: GLclampf, invert: GLboolean) {.importc.} + proc glGetPointerIndexedvEXT(target: GLenum, index: GLuint, data: ptr pointer) {.importc.} + proc glVertexStream4iATI(stream: GLenum, x: GLint, y: GLint, z: GLint, w: GLint) {.importc.} + proc glUnlockArraysEXT() {.importc.} + proc glReplacementCodeuivSUN(code: ptr GLuint) {.importc.} + proc glMatrixScaledEXT(mode: GLenum, x: GLdouble, y: GLdouble, z: GLdouble) {.importc.} + proc glMultiTexImage2DEXT(texunit: GLenum, target: GLenum, level: GLint, internalformat: GLint, width: GLsizei, height: GLsizei, border: GLint, format: GLenum, `type`: GLenum, pixels: pointer) {.importc.} + proc glFeedbackBufferxOES(n: GLsizei, `type`: GLenum, buffer: ptr GLfixed) {.importc.} + proc glLightEnviSGIX(pname: GLenum, param: GLint) {.importc.} + proc glMultiTexCoord4dARB(target: GLenum, s: GLdouble, t: GLdouble, r: GLdouble, q: GLdouble) {.importc.} + proc glExtGetTexLevelParameterivQCOM(texture: GLuint, face: GLenum, level: GLint, pname: GLenum, params: ptr GLint) {.importc.} + proc glVertexAttribI4usvEXT(index: GLuint, v: ptr GLushort) {.importc.} + proc glWindowPos2dvARB(v: ptr GLdouble) {.importc.} + proc glBindFramebuffer(target: GLenum, framebuffer: GLuint) {.importc.} + proc glGetProgramPipelineivEXT(pipeline: GLuint, pname: GLenum, params: ptr GLint) {.importc.} + proc glProgramUniformHandleui64vNV(program: GLuint, location: GLint, count: GLsizei, values: ptr GLuint64) {.importc.} + proc glFogCoordhvNV(fog: ptr GLhalfNv) {.importc.} + proc glTextureImage1DEXT(texture: GLuint, target: GLenum, level: GLint, internalformat: GLint, width: GLsizei, border: GLint, format: GLenum, `type`: GLenum, pixels: pointer) {.importc.} + proc glGetActiveAtomicCounterBufferiv(program: GLuint, bufferIndex: GLuint, pname: GLenum, params: ptr GLint) {.importc.} + proc glBeginQueryARB(target: GLenum, id: GLuint) {.importc.} + proc glGetTexParameterIuivEXT(target: GLenum, pname: GLenum, params: ptr GLuint) {.importc.} + proc glUniform4ui64vNV(location: GLint, count: GLsizei, value: ptr GLuint64Ext) {.importc.} + proc glClearAccumxOES(red: GLfixed, green: GLfixed, blue: GLfixed, alpha: GLfixed) {.importc.} + proc glFreeObjectBufferATI(buffer: GLuint) {.importc.} + proc glGetVideouivNV(video_slot: GLuint, pname: GLenum, params: ptr GLuint) {.importc.} + proc glVertexAttribL4ui64NV(index: GLuint, x: GLuint64Ext, y: GLuint64Ext, z: GLuint64Ext, w: GLuint64Ext) {.importc.} + proc glGetUniformBlockIndex(program: GLuint, uniformBlockName: cstring): GLuint {.importc.} + proc glCopyMultiTexSubImage2DEXT(texunit: GLenum, target: GLenum, level: GLint, xoffset: GLint, yoffset: GLint, x: GLint, y: GLint, width: GLsizei, height: GLsizei) {.importc.} + proc glVertex3bvOES(coords: ptr GLbyte) {.importc.} + proc glMultiDrawElementArrayAPPLE(mode: GLenum, first: ptr GLint, count: ptr GLsizei, primcount: GLsizei) {.importc.} + proc glPrimitiveRestartNV() {.importc.} + proc glMateriali(face: GLenum, pname: GLenum, param: GLint) {.importc.} + proc glBegin(mode: GLenum) {.importc.} + proc glFogCoordPointerEXT(`type`: GLenum, stride: GLsizei, `pointer`: pointer) {.importc.} + proc glTexCoord1sv(v: ptr GLshort) {.importc.} + proc glVertexAttribI4sv(index: GLuint, v: ptr GLshort) {.importc.} + proc glTexEnvx(target: GLenum, pname: GLenum, param: GLfixed) {.importc.} + proc glTexParameterIivEXT(target: GLenum, pname: GLenum, params: ptr GLint) {.importc.} + proc glLoadTransposeMatrixfARB(m: ptr GLfloat) {.importc.} + proc glGetTextureSamplerHandleARB(texture: GLuint, sampler: GLuint): GLuint64 {.importc.} + proc glVertexP3uiv(`type`: GLenum, value: ptr GLuint) {.importc.} + proc glProgramUniform2dv(program: GLuint, location: GLint, count: GLsizei, value: ptr GLdouble) {.importc.} + proc glTexCoord4xvOES(coords: ptr GLfixed) {.importc.} + proc glTexStorage1D(target: GLenum, levels: GLsizei, internalformat: GLenum, width: GLsizei) {.importc.} + proc glTextureParameterfEXT(texture: GLuint, target: GLenum, pname: GLenum, param: GLfloat) {.importc.} + proc glVertexAttrib1d(index: GLuint, x: GLdouble) {.importc.} + proc glGetnPixelMapfvARB(map: GLenum, bufSize: GLsizei, values: ptr GLfloat) {.importc.} + proc glDisableVertexAttribArray(index: GLuint) {.importc.} + proc glUniformMatrix4x3dv(location: GLint, count: GLsizei, transpose: GLboolean, value: ptr GLdouble) {.importc.} + proc glRasterPos4f(x: GLfloat, y: GLfloat, z: GLfloat, w: GLfloat) {.importc.} + proc glProgramUniform1fEXT(program: GLuint, location: GLint, v0: GLfloat) {.importc.} + proc glPathTexGenNV(texCoordSet: GLenum, genMode: GLenum, components: GLint, coeffs: ptr GLfloat) {.importc.} + proc glUniform3ui(location: GLint, v0: GLuint, v1: GLuint, v2: GLuint) {.importc.} + proc glVDPAURegisterOutputSurfaceNV(vdpSurface: pointer, target: GLenum, numTextureNames: GLsizei, textureNames: ptr GLuint): GLvdpauSurfaceNv {.importc.} + proc glGetProgramLocalParameterIuivNV(target: GLenum, index: GLuint, params: ptr GLuint) {.importc.} + proc glIsTextureHandleResidentNV(handle: GLuint64): GLboolean {.importc.} + proc glProgramEnvParameters4fvEXT(target: GLenum, index: GLuint, count: GLsizei, params: ptr GLfloat) {.importc.} + proc glReplacementCodeuiTexCoord2fNormal3fVertex3fSUN(rc: GLuint, s: GLfloat, t: GLfloat, nx: GLfloat, ny: GLfloat, nz: GLfloat, x: GLfloat, y: GLfloat, z: GLfloat) {.importc.} + proc glGetMultiTexEnvivEXT(texunit: GLenum, target: GLenum, pname: GLenum, params: ptr GLint) {.importc.} + proc glGetFloatv(pname: GLenum, params: ptr GLfloat) {.importc.} + proc glInsertEventMarkerEXT(length: GLsizei, marker: cstring) {.importc.} + proc glRasterPos3d(x: GLdouble, y: GLdouble, z: GLdouble) {.importc.} + proc glNamedFramebufferRenderbufferEXT(framebuffer: GLuint, attachment: GLenum, renderbuffertarget: GLenum, renderbuffer: GLuint) {.importc.} + proc glGetConvolutionFilter(target: GLenum, format: GLenum, `type`: GLenum, image: pointer) {.importc.} + proc glIsOcclusionQueryNV(id: GLuint): GLboolean {.importc.} + proc glGetnPixelMapuivARB(map: GLenum, bufSize: GLsizei, values: ptr GLuint) {.importc.} + proc glMapParameterfvNV(target: GLenum, pname: GLenum, params: ptr GLfloat) {.importc.} + proc glPushDebugGroup(source: GLenum, id: GLuint, length: GLsizei, message: cstring) {.importc.} + proc glMakeImageHandleResidentARB(handle: GLuint64, access: GLenum) {.importc.} + proc glProgramUniformMatrix2fv(program: GLuint, location: GLint, count: GLsizei, transpose: GLboolean, value: ptr GLfloat) {.importc.} + proc glUniform3i64vNV(location: GLint, count: GLsizei, value: ptr GLint64Ext) {.importc.} + proc glImageTransformParameteriHP(target: GLenum, pname: GLenum, param: GLint) {.importc.} + proc glMultiTexCoord1s(target: GLenum, s: GLshort) {.importc.} + proc glVertexAttribL4dvEXT(index: GLuint, v: ptr GLdouble) {.importc.} + proc glGetProgramEnvParameterfvARB(target: GLenum, index: GLuint, params: ptr GLfloat) {.importc.} + proc glVertexArrayColorOffsetEXT(vaobj: GLuint, buffer: GLuint, size: GLint, `type`: GLenum, stride: GLsizei, offset: GLintptr) {.importc.} + proc glGetHistogramParameterivEXT(target: GLenum, pname: GLenum, params: ptr GLint) {.importc.} + proc glGetRenderbufferParameterivOES(target: GLenum, pname: GLenum, params: ptr GLint) {.importc.} + proc glGetBufferPointerv(target: GLenum, pname: GLenum, params: ptr pointer) {.importc.} + proc glSecondaryColor3ui(red: GLuint, green: GLuint, blue: GLuint) {.importc.} + proc glGetDebugMessageLog(count: GLuint, bufsize: GLsizei, sources: ptr GLenum, types: ptr GLenum, ids: ptr GLuint, severities: ptr GLenum, lengths: ptr GLsizei, messageLog: cstring): GLuint {.importc.} + proc glNormal3i(nx: GLint, ny: GLint, nz: GLint) {.importc.} + proc glTestFenceNV(fence: GLuint): GLboolean {.importc.} + proc glSecondaryColor3usv(v: ptr GLushort) {.importc.} + proc glGenPathsNV(range: GLsizei): GLuint {.importc.} + proc glDeleteBuffersARB(n: GLsizei, buffers: ptr GLuint) {.importc.} + proc glProgramUniform4fvEXT(program: GLuint, location: GLint, count: GLsizei, value: ptr GLfloat) {.importc.} + proc glGetSharpenTexFuncSGIS(target: GLenum, points: ptr GLfloat) {.importc.} + proc glDrawMeshArraysSUN(mode: GLenum, first: GLint, count: GLsizei, width: GLsizei) {.importc.} + proc glVertexAttribs4hvNV(index: GLuint, n: GLsizei, v: ptr GLhalfNv) {.importc.} + proc glGetClipPlane(plane: GLenum, equation: ptr GLdouble) {.importc.} + proc glEvalCoord2fv(u: ptr GLfloat) {.importc.} + proc glAsyncMarkerSGIX(marker: GLuint) {.importc.} + proc glGetSynciv(sync: GLsync, pname: GLenum, bufSize: GLsizei, length: ptr GLsizei, values: ptr GLint) {.importc.} + proc glGetPathTexGenfvNV(texCoordSet: GLenum, pname: GLenum, value: ptr GLfloat) {.importc.} + proc glTexParameterf(target: GLenum, pname: GLenum, param: GLfloat) {.importc.} + proc glMultiTexCoord1fvARB(target: GLenum, v: ptr GLfloat) {.importc.} + proc glNormalPointerListIBM(`type`: GLenum, stride: GLint, `pointer`: ptr pointer, ptrstride: GLint) {.importc.} + proc glFragmentLightfvSGIX(light: GLenum, pname: GLenum, params: ptr GLfloat) {.importc.} + proc glViewportArrayv(first: GLuint, count: GLsizei, v: ptr GLfloat) {.importc.} + proc glNormal3fVertex3fSUN(nx: GLfloat, ny: GLfloat, nz: GLfloat, x: GLfloat, y: GLfloat, z: GLfloat) {.importc.} + proc glMultiTexCoord2dvARB(target: GLenum, v: ptr GLdouble) {.importc.} + proc glCopyColorSubTable(target: GLenum, start: GLsizei, x: GLint, y: GLint, width: GLsizei) {.importc.} + proc glTexCoord2hvNV(v: ptr GLhalfNv) {.importc.} + proc glGetQueryObjectiv(id: GLuint, pname: GLenum, params: ptr GLint) {.importc.} + proc glColor4hNV(red: GLhalfNv, green: GLhalfNv, blue: GLhalfNv, alpha: GLhalfNv) {.importc.} + proc glProgramUniform2fv(program: GLuint, location: GLint, count: GLsizei, value: ptr GLfloat) {.importc.} + proc glMultiTexCoord4hNV(target: GLenum, s: GLhalfNv, t: GLhalfNv, r: GLhalfNv, q: GLhalfNv) {.importc.} + proc glWindowPos2fvMESA(v: ptr GLfloat) {.importc.} + proc glVertexAttrib3s(index: GLuint, x: GLshort, y: GLshort, z: GLshort) {.importc.} + proc glGetIntegerIndexedvEXT(target: GLenum, index: GLuint, data: ptr GLint) {.importc.} + proc glVertexAttrib4Niv(index: GLuint, v: ptr GLint) {.importc.} + proc glProgramLocalParameter4dvARB(target: GLenum, index: GLuint, params: ptr GLdouble) {.importc.} + proc glFramebufferTextureLayerEXT(target: GLenum, attachment: GLenum, texture: GLuint, level: GLint, layer: GLint) {.importc.} + proc glVertexAttribI1ui(index: GLuint, x: GLuint) {.importc.} + proc glFogCoorddv(coord: ptr GLdouble) {.importc.} + proc glLightModelxv(pname: GLenum, param: ptr GLfixed) {.importc.} + proc glGetCombinerOutputParameterfvNV(stage: GLenum, portion: GLenum, pname: GLenum, params: ptr GLfloat) {.importc.} + proc glFramebufferReadBufferEXT(framebuffer: GLuint, mode: GLenum) {.importc.} + proc glGetActiveUniformsiv(program: GLuint, uniformCount: GLsizei, uniformIndices: ptr GLuint, pname: GLenum, params: ptr GLint) {.importc.} + proc glGetProgramStringNV(id: GLuint, pname: GLenum, program: ptr GLubyte) {.importc.} + proc glCopyConvolutionFilter2D(target: GLenum, internalformat: GLenum, x: GLint, y: GLint, width: GLsizei, height: GLsizei) {.importc.} + proc glMultiTexCoord3iARB(target: GLenum, s: GLint, t: GLint, r: GLint) {.importc.} + proc glPushName(name: GLuint) {.importc.} + proc glProgramParameter4dNV(target: GLenum, index: GLuint, x: GLdouble, y: GLdouble, z: GLdouble, w: GLdouble) {.importc.} + proc glVertexAttrib4svARB(index: GLuint, v: ptr GLshort) {.importc.} + proc glSecondaryColor3iv(v: ptr GLint) {.importc.} + proc glCopyColorSubTableEXT(target: GLenum, start: GLsizei, x: GLint, y: GLint, width: GLsizei) {.importc.} + proc glCallList(list: GLuint) {.importc.} + proc glGetMultiTexLevelParameterivEXT(texunit: GLenum, target: GLenum, level: GLint, pname: GLenum, params: ptr GLint) {.importc.} + proc glProgramUniformMatrix2x4fv(program: GLuint, location: GLint, count: GLsizei, transpose: GLboolean, value: ptr GLfloat) {.importc.} + proc glTexBumpParameterivATI(pname: GLenum, param: ptr GLint) {.importc.} + proc glTexGeni(coord: GLenum, pname: GLenum, param: GLint) {.importc.} + proc glSecondaryColor3dv(v: ptr GLdouble) {.importc.} + proc glGetnUniformdvARB(program: GLuint, location: GLint, bufSize: GLsizei, params: ptr GLdouble) {.importc.} + proc glGetNamedProgramLocalParameterdvEXT(program: GLuint, target: GLenum, index: GLuint, params: ptr GLdouble) {.importc.} + proc glGetVertexAttribPointervARB(index: GLuint, pname: GLenum, `pointer`: ptr pointer) {.importc.} + proc glCopyColorTable(target: GLenum, internalformat: GLenum, x: GLint, y: GLint, width: GLsizei) {.importc.} + proc glNamedFramebufferTextureLayerEXT(framebuffer: GLuint, attachment: GLenum, texture: GLuint, level: GLint, layer: GLint) {.importc.} + proc glLoadProgramNV(target: GLenum, id: GLuint, len: GLsizei, program: ptr GLubyte) {.importc.} + proc glAlphaFragmentOp2ATI(op: GLenum, dst: GLuint, dstMod: GLuint, arg1: GLuint, arg1Rep: GLuint, arg1Mod: GLuint, arg2: GLuint, arg2Rep: GLuint, arg2Mod: GLuint) {.importc.} + proc glBindLightParameterEXT(light: GLenum, value: GLenum): GLuint {.importc.} + proc glVertexAttrib1fv(index: GLuint, v: ptr GLfloat) {.importc.} + proc glLoadIdentity() {.importc.} + proc glFramebufferTexture2DMultisampleEXT(target: GLenum, attachment: GLenum, textarget: GLenum, texture: GLuint, level: GLint, samples: GLsizei) {.importc.} + proc glVertexAttrib1dvARB(index: GLuint, v: ptr GLdouble) {.importc.} + proc glDrawRangeElementsBaseVertex(mode: GLenum, start: GLuint, `end`: GLuint, count: GLsizei, `type`: GLenum, indices: pointer, basevertex: GLint) {.importc.} + proc glPixelMapfv(map: GLenum, mapsize: GLsizei, values: ptr GLfloat) {.importc.} + proc glPointParameterxOES(pname: GLenum, param: GLfixed) {.importc.} + proc glBindBufferRangeNV(target: GLenum, index: GLuint, buffer: GLuint, offset: GLintptr, size: GLsizeiptr) {.importc.} + proc glDepthBoundsEXT(zmin: GLclampd, zmax: GLclampd) {.importc.} + proc glProgramUniformMatrix2dv(program: GLuint, location: GLint, count: GLsizei, transpose: GLboolean, value: ptr GLdouble) {.importc.} + proc glSecondaryColor3s(red: GLshort, green: GLshort, blue: GLshort) {.importc.} + proc glEdgeFlagPointerEXT(stride: GLsizei, count: GLsizei, `pointer`: ptr GLboolean) {.importc.} + proc glVertexStream1fATI(stream: GLenum, x: GLfloat) {.importc.} + proc glUniformui64NV(location: GLint, value: GLuint64Ext) {.importc.} + proc glTexCoordP4uiv(`type`: GLenum, coords: ptr GLuint) {.importc.} + proc glTexCoord3d(s: GLdouble, t: GLdouble, r: GLdouble) {.importc.} + proc glDeleteProgramPipelines(n: GLsizei, pipelines: ptr GLuint) {.importc.} + proc glVertex2iv(v: ptr GLint) {.importc.} + proc glGetMultisamplefv(pname: GLenum, index: GLuint, val: ptr GLfloat) {.importc.} + proc glStartInstrumentsSGIX() {.importc.} + proc glGetOcclusionQueryivNV(id: GLuint, pname: GLenum, params: ptr GLint) {.importc.} + proc glDebugMessageCallback(callback: GLdebugProc, userParam: ptr pointer) {.importc.} + proc glPixelZoomxOES(xfactor: GLfixed, yfactor: GLfixed) {.importc.} + proc glTexCoord3i(s: GLint, t: GLint, r: GLint) {.importc.} + proc glEdgeFlagFormatNV(stride: GLsizei) {.importc.} + proc glProgramUniform2i(program: GLuint, location: GLint, v0: GLint, v1: GLint) {.importc.} + proc glColor3b(red: GLbyte, green: GLbyte, blue: GLbyte) {.importc.} + proc glDepthRangefOES(n: GLclampf, f: GLclampf) {.importc.} + proc glEndVertexShaderEXT() {.importc.} + proc glBindVertexArrayAPPLE(`array`: GLuint) {.importc.} + proc glColor4bv(v: ptr GLbyte) {.importc.} + proc glNamedFramebufferTexture2DEXT(framebuffer: GLuint, attachment: GLenum, textarget: GLenum, texture: GLuint, level: GLint) {.importc.} + proc glTexCoord1f(s: GLfloat) {.importc.} + proc glUniform3fvARB(location: GLint, count: GLsizei, value: ptr GLfloat) {.importc.} + proc glGetQueryObjectuivARB(id: GLuint, pname: GLenum, params: ptr GLuint) {.importc.} + proc glVertexAttrib4bv(index: GLuint, v: ptr GLbyte) {.importc.} + proc glGetPixelTransformParameterivEXT(target: GLenum, pname: GLenum, params: ptr GLint) {.importc.} + proc glVertexAttrib3svNV(index: GLuint, v: ptr GLshort) {.importc.} + proc glDeleteQueriesEXT(n: GLsizei, ids: ptr GLuint) {.importc.} + proc glUniform3ivARB(location: GLint, count: GLsizei, value: ptr GLint) {.importc.} + proc glNormal3xvOES(coords: ptr GLfixed) {.importc.} + proc glMatrixLoadfEXT(mode: GLenum, m: ptr GLfloat) {.importc.} + proc glGetNamedFramebufferAttachmentParameterivEXT(framebuffer: GLuint, attachment: GLenum, pname: GLenum, params: ptr GLint) {.importc.} + proc glSeparableFilter2D(target: GLenum, internalformat: GLenum, width: GLsizei, height: GLsizei, format: GLenum, `type`: GLenum, row: pointer, column: pointer) {.importc.} + proc glVertexAttribI3uiv(index: GLuint, v: ptr GLuint) {.importc.} + proc glTextureStorageSparseAMD(texture: GLuint, target: GLenum, internalFormat: GLenum, width: GLsizei, height: GLsizei, depth: GLsizei, layers: GLsizei, flags: GLbitfield) {.importc.} + proc glMultiDrawArraysIndirectCountARB(mode: GLenum, indirect: GLintptr, drawcount: GLintptr, maxdrawcount: GLsizei, stride: GLsizei) {.importc.} + proc glTranslated(x: GLdouble, y: GLdouble, z: GLdouble) {.importc.} + proc glColorPointer(size: GLint, `type`: GLenum, stride: GLsizei, `pointer`: pointer) {.importc.} + proc glDrawElementsInstancedBaseVertex(mode: GLenum, count: GLsizei, `type`: GLenum, indices: pointer, instancecount: GLsizei, basevertex: GLint) {.importc.} + proc glBindAttribLocationARB(programObj: GLhandleArb, index: GLuint, name: cstring) {.importc.} + proc glTexGendv(coord: GLenum, pname: GLenum, params: ptr GLdouble) {.importc.} + proc glGetPathCoordsNV(path: GLuint, coords: ptr GLfloat) {.importc.} + proc glGetMapParameterivNV(target: GLenum, pname: GLenum, params: ptr GLint) {.importc.} + proc glClientAttribDefaultEXT(mask: GLbitfield) {.importc.} + proc glProgramUniformMatrix4x3fvEXT(program: GLuint, location: GLint, count: GLsizei, transpose: GLboolean, value: ptr GLfloat) {.importc.} + proc glEnable(cap: GLenum) {.importc.} + proc glGetVertexAttribPointervNV(index: GLuint, pname: GLenum, `pointer`: ptr pointer) {.importc.} + proc glBindMultiTextureEXT(texunit: GLenum, target: GLenum, texture: GLuint) {.importc.} + proc glGetConvolutionParameterfvEXT(target: GLenum, pname: GLenum, params: ptr GLfloat) {.importc.} + proc glLightModelxvOES(pname: GLenum, param: ptr GLfixed) {.importc.} + proc glMultiTexCoord4sv(target: GLenum, v: ptr GLshort) {.importc.} + proc glGetColorTableParameterivSGI(target: GLenum, pname: GLenum, params: ptr GLint) {.importc.} + proc glFramebufferTexture2DOES(target: GLenum, attachment: GLenum, textarget: GLenum, texture: GLuint, level: GLint) {.importc.} + proc glClearDepthxOES(depth: GLfixed) {.importc.} + proc glDisableClientStateiEXT(`array`: GLenum, index: GLuint) {.importc.} + proc glWindowPos2dARB(x: GLdouble, y: GLdouble) {.importc.} + proc glVertexAttrib1fvNV(index: GLuint, v: ptr GLfloat) {.importc.} + proc glDepthRangedNV(zNear: GLdouble, zFar: GLdouble) {.importc.} + proc glClear(mask: GLbitfield) {.importc.} + proc glUnmapTexture2DINTEL(texture: GLuint, level: GLint) {.importc.} + proc glSecondaryColor3ub(red: GLubyte, green: GLubyte, blue: GLubyte) {.importc.} + proc glVertexAttribI4bv(index: GLuint, v: ptr GLbyte) {.importc.} + proc glTexRenderbufferNV(target: GLenum, renderbuffer: GLuint) {.importc.} + proc glColor4ubVertex3fvSUN(c: ptr GLubyte, v: ptr GLfloat) {.importc.} + proc glVertexAttrib2svNV(index: GLuint, v: ptr GLshort) {.importc.} + proc glMultiTexCoord1ivARB(target: GLenum, v: ptr GLint) {.importc.} + proc glUniformMatrix3x2dv(location: GLint, count: GLsizei, transpose: GLboolean, value: ptr GLdouble) {.importc.} + proc glVertexAttribL3dvEXT(index: GLuint, v: ptr GLdouble) {.importc.} + proc glMultiTexSubImage1DEXT(texunit: GLenum, target: GLenum, level: GLint, xoffset: GLint, width: GLsizei, format: GLenum, `type`: GLenum, pixels: pointer) {.importc.} + proc glGetBufferPointervARB(target: GLenum, pname: GLenum, params: ptr pointer) {.importc.} + proc glGetMultiTexLevelParameterfvEXT(texunit: GLenum, target: GLenum, level: GLint, pname: GLenum, params: ptr GLfloat) {.importc.} + proc glMultiTexParameterIuivEXT(texunit: GLenum, target: GLenum, pname: GLenum, params: ptr GLuint) {.importc.} + proc glGetShaderSource(shader: GLuint, bufSize: GLsizei, length: ptr GLsizei, source: cstring) {.importc.} + proc glStencilFunc(fun: GLenum, `ref`: GLint, mask: GLuint) {.importc.} + proc glVertexAttribI4bvEXT(index: GLuint, v: ptr GLbyte) {.importc.} + proc glVertexAttrib4NuivARB(index: GLuint, v: ptr GLuint) {.importc.} + proc glIsObjectBufferATI(buffer: GLuint): GLboolean {.importc.} + proc glRasterPos2xOES(x: GLfixed, y: GLfixed) {.importc.} + proc glIsFenceNV(fence: GLuint): GLboolean {.importc.} + proc glGetFramebufferParameteriv(target: GLenum, pname: GLenum, params: ptr GLint) {.importc.} + proc glClearBufferfv(buffer: GLenum, drawbuffer: GLint, value: ptr GLfloat) {.importc.} + proc glClearColorxOES(red: GLfixed, green: GLfixed, blue: GLfixed, alpha: GLfixed) {.importc.} + proc glVertexWeightfEXT(weight: GLfloat) {.importc.} + proc glExtIsProgramBinaryQCOM(program: GLuint): GLboolean {.importc.} + proc glTextureStorage2DMultisampleEXT(texture: GLuint, target: GLenum, samples: GLsizei, internalformat: GLenum, width: GLsizei, height: GLsizei, fixedsamplelocations: GLboolean) {.importc.} + proc glGetHistogramParameterxvOES(target: GLenum, pname: GLenum, params: ptr GLfixed) {.importc.} + proc glVertexAttrib4dNV(index: GLuint, x: GLdouble, y: GLdouble, z: GLdouble, w: GLdouble) {.importc.} + proc glGetPerfMonitorCounterStringAMD(group: GLuint, counter: GLuint, bufSize: GLsizei, length: ptr GLsizei, counterString: cstring) {.importc.} + proc glMultiTexCoord2sARB(target: GLenum, s: GLshort, t: GLshort) {.importc.} + proc glSpriteParameterivSGIX(pname: GLenum, params: ptr GLint) {.importc.} + proc glCompressedTextureImage3DEXT(texture: GLuint, target: GLenum, level: GLint, internalformat: GLenum, width: GLsizei, height: GLsizei, depth: GLsizei, border: GLint, imageSize: GLsizei, bits: pointer) {.importc.} + proc glBufferSubData(target: GLenum, offset: GLintptr, size: GLsizeiptr, data: pointer) {.importc.} + proc glBlendParameteriNV(pname: GLenum, value: GLint) {.importc.} + proc glVertexAttrib2fvNV(index: GLuint, v: ptr GLfloat) {.importc.} + proc glGetVariantBooleanvEXT(id: GLuint, value: GLenum, data: ptr GLboolean) {.importc.} + proc glProgramParameteri(program: GLuint, pname: GLenum, value: GLint) {.importc.} + proc glGetLocalConstantIntegervEXT(id: GLuint, value: GLenum, data: ptr GLint) {.importc.} + proc glFragmentMaterialiSGIX(face: GLenum, pname: GLenum, param: GLint) {.importc.} + proc glGetNamedStringivARB(namelen: GLint, name: cstring, pname: GLenum, params: ptr GLint) {.importc.} + proc glBinormal3ivEXT(v: ptr GLint) {.importc.} + proc glCheckFramebufferStatusEXT(target: GLenum): GLenum {.importc.} + proc glVertexAttrib1fNV(index: GLuint, x: GLfloat) {.importc.} + proc glNamedRenderbufferStorageEXT(renderbuffer: GLuint, internalformat: GLenum, width: GLsizei, height: GLsizei) {.importc.} + proc glPresentFrameKeyedNV(video_slot: GLuint, minPresentTime: GLuint64Ext, beginPresentTimeId: GLuint, presentDurationId: GLuint, `type`: GLenum, target0: GLenum, fill0: GLuint, key0: GLuint, target1: GLenum, fill1: GLuint, key1: GLuint) {.importc.} + proc glGetObjectParameterfvARB(obj: GLhandleArb, pname: GLenum, params: ptr GLfloat) {.importc.} + proc glVertex3sv(v: ptr GLshort) {.importc.} + proc glColor4s(red: GLshort, green: GLshort, blue: GLshort, alpha: GLshort) {.importc.} + proc glGetQueryObjecti64vEXT(id: GLuint, pname: GLenum, params: ptr GLint64) {.importc.} + proc glEvalMesh2(mode: GLenum, i1: GLint, i2: GLint, j1: GLint, j2: GLint) {.importc.} + proc glBeginTransformFeedbackEXT(primitiveMode: GLenum) {.importc.} + proc glBufferAddressRangeNV(pname: GLenum, index: GLuint, address: GLuint64Ext, length: GLsizeiptr) {.importc.} + proc glPointParameterfvARB(pname: GLenum, params: ptr GLfloat) {.importc.} + proc glGetActiveVaryingNV(program: GLuint, index: GLuint, bufSize: GLsizei, length: ptr GLsizei, size: ptr GLsizei, `type`: ptr GLenum, name: cstring) {.importc.} + proc glIndexMask(mask: GLuint) {.importc.} + proc glVertexAttribBinding(attribindex: GLuint, bindingindex: GLuint) {.importc.} + proc glDeleteFencesNV(n: GLsizei, fences: ptr GLuint) {.importc.} + proc glVertexAttribI4ubv(index: GLuint, v: ptr GLubyte) {.importc.} + proc glPathParameterfvNV(path: GLuint, pname: GLenum, value: ptr GLfloat) {.importc.} + proc glVertexStream3fATI(stream: GLenum, x: GLfloat, y: GLfloat, z: GLfloat) {.importc.} + proc glVertexAttribs4svNV(index: GLuint, count: GLsizei, v: ptr GLshort) {.importc.} + proc glVertexAttrib4sNV(index: GLuint, x: GLshort, y: GLshort, z: GLshort, w: GLshort) {.importc.} + proc glAlphaFragmentOp3ATI(op: GLenum, dst: GLuint, dstMod: GLuint, arg1: GLuint, arg1Rep: GLuint, arg1Mod: GLuint, arg2: GLuint, arg2Rep: GLuint, arg2Mod: GLuint, arg3: GLuint, arg3Rep: GLuint, arg3Mod: GLuint) {.importc.} + proc glGetHistogramParameterfv(target: GLenum, pname: GLenum, params: ptr GLfloat) {.importc.} + proc glVertexAttribL1ui64NV(index: GLuint, x: GLuint64Ext) {.importc.} + proc glVertexAttribs3fvNV(index: GLuint, count: GLsizei, v: ptr GLfloat) {.importc.} + proc glMultiTexCoord3ivARB(target: GLenum, v: ptr GLint) {.importc.} + proc glClipPlanefOES(plane: GLenum, equation: ptr GLfloat) {.importc.} + proc glVertex3s(x: GLshort, y: GLshort, z: GLshort) {.importc.} + proc glVertex3dv(v: ptr GLdouble) {.importc.} + proc glWeightPointerOES(size: GLint, `type`: GLenum, stride: GLsizei, `pointer`: pointer) {.importc.} + proc glBindBufferBase(target: GLenum, index: GLuint, buffer: GLuint) {.importc.} + proc glIndexs(c: GLshort) {.importc.} + proc glTessellationFactorAMD(factor: GLfloat) {.importc.} + proc glColor4ubVertex3fSUN(r: GLubyte, g: GLubyte, b: GLubyte, a: GLubyte, x: GLfloat, y: GLfloat, z: GLfloat) {.importc.} + proc glPauseTransformFeedback() {.importc.} + proc glImageTransformParameterivHP(target: GLenum, pname: GLenum, params: ptr GLint) {.importc.} + proc glColor3dv(v: ptr GLdouble) {.importc.} + proc glRasterPos4sv(v: ptr GLshort) {.importc.} + proc glInvalidateTexSubImage(texture: GLuint, level: GLint, xoffset: GLint, yoffset: GLint, zoffset: GLint, width: GLsizei, height: GLsizei, depth: GLsizei) {.importc.} + proc glNormalStream3bvATI(stream: GLenum, coords: ptr GLbyte) {.importc.} + proc glUniformMatrix2x4fv(location: GLint, count: GLsizei, transpose: GLboolean, value: ptr GLfloat) {.importc.} + proc glMinmax(target: GLenum, internalformat: GLenum, sink: GLboolean) {.importc.} + proc glGetProgramStageiv(program: GLuint, shadertype: GLenum, pname: GLenum, values: ptr GLint) {.importc.} + proc glScalex(x: GLfixed, y: GLfixed, z: GLfixed) {.importc.} + proc glTexBufferARB(target: GLenum, internalformat: GLenum, buffer: GLuint) {.importc.} + proc glDrawArraysIndirect(mode: GLenum, indirect: pointer) {.importc.} + proc glMatrixLoadTransposefEXT(mode: GLenum, m: ptr GLfloat) {.importc.} + proc glMultiTexCoord2f(target: GLenum, s: GLfloat, t: GLfloat) {.importc.} + proc glDrawRangeElements(mode: GLenum, start: GLuint, `end`: GLuint, count: GLsizei, `type`: GLenum, indices: pointer) {.importc.} + proc glVertexAttrib4NubARB(index: GLuint, x: GLubyte, y: GLubyte, z: GLubyte, w: GLubyte) {.importc.} + proc glMultiTexCoord4xvOES(texture: GLenum, coords: ptr GLfixed) {.importc.} + proc glVertexArrayVertexAttribOffsetEXT(vaobj: GLuint, buffer: GLuint, index: GLuint, size: GLint, `type`: GLenum, normalized: GLboolean, stride: GLsizei, offset: GLintptr) {.importc.} + proc glVertexAttribL1i64vNV(index: GLuint, v: ptr GLint64Ext) {.importc.} + proc glMapBuffer(target: GLenum, access: GLenum): pointer {.importc.} + proc glUniform1ui(location: GLint, v0: GLuint) {.importc.} + proc glGetPixelMapfv(map: GLenum, values: ptr GLfloat) {.importc.} + proc glTexImage2DMultisampleCoverageNV(target: GLenum, coverageSamples: GLsizei, colorSamples: GLsizei, internalFormat: GLint, width: GLsizei, height: GLsizei, fixedSampleLocations: GLboolean) {.importc.} + proc glUniform2ivARB(location: GLint, count: GLsizei, value: ptr GLint) {.importc.} + proc glVertexAttribI3ui(index: GLuint, x: GLuint, y: GLuint, z: GLuint) {.importc.} + proc glGetProgramResourceiv(program: GLuint, programInterface: GLenum, index: GLuint, propCount: GLsizei, props: ptr GLenum, bufSize: GLsizei, length: ptr GLsizei, params: ptr GLint) {.importc.} + proc glUniform4iv(location: GLint, count: GLsizei, value: ptr GLint) {.importc.} + proc glVertexAttrib3f(index: GLuint, x: GLfloat, y: GLfloat, z: GLfloat) {.importc.} + proc glClientActiveVertexStreamATI(stream: GLenum) {.importc.} + proc glTexCoord4fColor4fNormal3fVertex4fvSUN(tc: ptr GLfloat, c: ptr GLfloat, n: ptr GLfloat, v: ptr GLfloat) {.importc.} + proc glColor3xvOES(components: ptr GLfixed) {.importc.} + proc glVertexPointerListIBM(size: GLint, `type`: GLenum, stride: GLint, `pointer`: ptr pointer, ptrstride: GLint) {.importc.} + proc glProgramEnvParameter4dARB(target: GLenum, index: GLuint, x: GLdouble, y: GLdouble, z: GLdouble, w: GLdouble) {.importc.} + proc glGetLocalConstantFloatvEXT(id: GLuint, value: GLenum, data: ptr GLfloat) {.importc.} + proc glTexCoordPointerEXT(size: GLint, `type`: GLenum, stride: GLsizei, count: GLsizei, `pointer`: pointer) {.importc.} + proc glTexCoordPointervINTEL(size: GLint, `type`: GLenum, `pointer`: ptr pointer) {.importc.} + proc glSelectPerfMonitorCountersAMD(monitor: GLuint, enable: GLboolean, group: GLuint, numCounters: GLint, counterList: ptr GLuint) {.importc.} + proc glVertexStream4svATI(stream: GLenum, coords: ptr GLshort) {.importc.} + proc glColor3ui(red: GLuint, green: GLuint, blue: GLuint) {.importc.} + proc glBindTransformFeedbackNV(target: GLenum, id: GLuint) {.importc.} + proc glDeformSGIX(mask: GLbitfield) {.importc.} + proc glDeformationMap3fSGIX(target: GLenum, u1: GLfloat, u2: GLfloat, ustride: GLint, uorder: GLint, v1: GLfloat, v2: GLfloat, vstride: GLint, vorder: GLint, w1: GLfloat, w2: GLfloat, wstride: GLint, worder: GLint, points: ptr GLfloat) {.importc.} + proc glNamedBufferSubDataEXT(buffer: GLuint, offset: GLintptr, size: GLsizeiptr, data: pointer) {.importc.} + proc glGetNamedProgramStringEXT(program: GLuint, target: GLenum, pname: GLenum, string: pointer) {.importc.} + proc glCopyPathNV(resultPath: GLuint, srcPath: GLuint) {.importc.} + proc glMapControlPointsNV(target: GLenum, index: GLuint, `type`: GLenum, ustride: GLsizei, vstride: GLsizei, uorder: GLint, vorder: GLint, packed: GLboolean, points: pointer) {.importc.} + proc glGetBufferParameteriv(target: GLenum, pname: GLenum, params: ptr GLint) {.importc.} + proc glUnmapObjectBufferATI(buffer: GLuint) {.importc.} + proc glGetProgramResourceLocation(program: GLuint, programInterface: GLenum, name: cstring): GLint {.importc.} + proc glUniform4i64vNV(location: GLint, count: GLsizei, value: ptr GLint64Ext) {.importc.} + proc glImageTransformParameterfHP(target: GLenum, pname: GLenum, param: GLfloat) {.importc.} + proc glArrayObjectATI(`array`: GLenum, size: GLint, `type`: GLenum, stride: GLsizei, buffer: GLuint, offset: GLuint) {.importc.} + proc glBindBufferRangeEXT(target: GLenum, index: GLuint, buffer: GLuint, offset: GLintptr, size: GLsizeiptr) {.importc.} + proc glVertexArrayVertexAttribFormatEXT(vaobj: GLuint, attribindex: GLuint, size: GLint, `type`: GLenum, normalized: GLboolean, relativeoffset: GLuint) {.importc.} + proc glBindRenderbufferEXT(target: GLenum, renderbuffer: GLuint) {.importc.} + proc glListParameteriSGIX(list: GLuint, pname: GLenum, param: GLint) {.importc.} + proc glProgramUniformMatrix2dvEXT(program: GLuint, location: GLint, count: GLsizei, transpose: GLboolean, value: ptr GLdouble) {.importc.} + proc glProgramUniform2i64vNV(program: GLuint, location: GLint, count: GLsizei, value: ptr GLint64Ext) {.importc.} + proc glObjectPtrLabelKHR(`ptr`: ptr pointer, length: GLsizei, label: cstring) {.importc.} + proc glVertexAttribL1i64NV(index: GLuint, x: GLint64Ext) {.importc.} + proc glMultiTexBufferEXT(texunit: GLenum, target: GLenum, internalformat: GLenum, buffer: GLuint) {.importc.} + proc glCoverFillPathInstancedNV(numPaths: GLsizei, pathNameType: GLenum, paths: pointer, pathBase: GLuint, coverMode: GLenum, transformType: GLenum, transformValues: ptr GLfloat) {.importc.} + proc glGetVertexAttribIivEXT(index: GLuint, pname: GLenum, params: ptr GLint) {.importc.} + proc glLightf(light: GLenum, pname: GLenum, param: GLfloat) {.importc.} + proc glGetMinmaxParameterfvEXT(target: GLenum, pname: GLenum, params: ptr GLfloat) {.importc.} + proc glUniform1d(location: GLint, x: GLdouble) {.importc.} + proc glLightiv(light: GLenum, pname: GLenum, params: ptr GLint) {.importc.} + proc glVertexAttrib2dvNV(index: GLuint, v: ptr GLdouble) {.importc.} + proc glNormalP3ui(`type`: GLenum, coords: GLuint) {.importc.} + proc glFinalCombinerInputNV(variable: GLenum, input: GLenum, mapping: GLenum, componentUsage: GLenum) {.importc.} + proc glUniform1uiv(location: GLint, count: GLsizei, value: ptr GLuint) {.importc.} + proc glValidateProgramARB(programObj: GLhandleArb) {.importc.} + proc glNormalPointer(`type`: GLenum, stride: GLsizei, `pointer`: pointer) {.importc.} + proc glProgramNamedParameter4fvNV(id: GLuint, len: GLsizei, name: ptr GLubyte, v: ptr GLfloat) {.importc.} + proc glGetBooleanv(pname: GLenum, params: ptr GLboolean) {.importc.} + proc glTangent3ivEXT(v: ptr GLint) {.importc.} + proc glTexImage3DMultisample(target: GLenum, samples: GLsizei, internalformat: GLint, width: GLsizei, height: GLsizei, depth: GLsizei, fixedsamplelocations: GLboolean) {.importc.} + proc glGetUniformIndices(program: GLuint, uniformCount: GLsizei, uniformNames: cstringArray, uniformIndices: ptr GLuint) {.importc.} + proc glVDPAUInitNV(vdpDevice: pointer, getProcAddress: pointer) {.importc.} + proc glGetMinmaxParameterivEXT(target: GLenum, pname: GLenum, params: ptr GLint) {.importc.} + proc glMultiTexCoord2fvARB(target: GLenum, v: ptr GLfloat) {.importc.} + proc glProgramEnvParametersI4ivNV(target: GLenum, index: GLuint, count: GLsizei, params: ptr GLint) {.importc.} + proc glClearTexSubImage(texture: GLuint, level: GLint, xoffset: GLint, yoffset: GLint, zoffset: GLint, width: GLsizei, height: GLsizei, depth: GLsizei, format: GLenum, `type`: GLenum, data: ptr pointer) {.importc.} + proc glRectxOES(x1: GLfixed, y1: GLfixed, x2: GLfixed, y2: GLfixed) {.importc.} + proc glBlendEquationOES(mode: GLenum) {.importc.} + proc glFramebufferTexture(target: GLenum, attachment: GLenum, texture: GLuint, level: GLint) {.importc.} + proc glGetInstrumentsSGIX(): GLint {.importc.} + proc glFramebufferParameteri(target: GLenum, pname: GLenum, param: GLint) {.importc.} + proc glPathCoverDepthFuncNV(fun: GLenum) {.importc.} + proc glGetTranslatedShaderSourceANGLE(shader: GLuint, bufsize: GLsizei, length: ptr GLsizei, source: cstring) {.importc.} + proc glIndexfv(c: ptr GLfloat) {.importc.} + proc glGetActiveUniformBlockName(program: GLuint, uniformBlockIndex: GLuint, bufSize: GLsizei, length: ptr GLsizei, uniformBlockName: cstring) {.importc.} + proc glNormal3s(nx: GLshort, ny: GLshort, nz: GLshort) {.importc.} + proc glColorFragmentOp3ATI(op: GLenum, dst: GLuint, dstMask: GLuint, dstMod: GLuint, arg1: GLuint, arg1Rep: GLuint, arg1Mod: GLuint, arg2: GLuint, arg2Rep: GLuint, arg2Mod: GLuint, arg3: GLuint, arg3Rep: GLuint, arg3Mod: GLuint) {.importc.} + proc glGetProgramResourceLocationIndex(program: GLuint, programInterface: GLenum, name: cstring): GLint {.importc.} + proc glGetBooleanIndexedvEXT(target: GLenum, index: GLuint, data: ptr GLboolean) {.importc.} + proc glGenPerfMonitorsAMD(n: GLsizei, monitors: ptr GLuint) {.importc.} + proc glDrawRangeElementsEXT(mode: GLenum, start: GLuint, `end`: GLuint, count: GLsizei, `type`: GLenum, indices: pointer) {.importc.} + proc glFramebufferTexture3D(target: GLenum, attachment: GLenum, textarget: GLenum, texture: GLuint, level: GLint, zoffset: GLint) {.importc.} + proc glGetTexParameterxvOES(target: GLenum, pname: GLenum, params: ptr GLfixed) {.importc.} + proc glCompileShaderIncludeARB(shader: GLuint, count: GLsizei, path: cstringArray, length: ptr GLint) {.importc.} + proc glGetMultiTexParameterfvEXT(texunit: GLenum, target: GLenum, pname: GLenum, params: ptr GLfloat) {.importc.} + proc glEvalPoint2(i: GLint, j: GLint) {.importc.} + proc glGetProgramivNV(id: GLuint, pname: GLenum, params: ptr GLint) {.importc.} + proc glProgramParameter4fNV(target: GLenum, index: GLuint, x: GLfloat, y: GLfloat, z: GLfloat, w: GLfloat) {.importc.} + proc glMultiTexParameterfvEXT(texunit: GLenum, target: GLenum, pname: GLenum, params: ptr GLfloat) {.importc.} + proc glVertexAttrib3svARB(index: GLuint, v: ptr GLshort) {.importc.} + proc glDrawElementArrayAPPLE(mode: GLenum, first: GLint, count: GLsizei) {.importc.} + proc glMultiTexCoord4x(texture: GLenum, s: GLfixed, t: GLfixed, r: GLfixed, q: GLfixed) {.importc.} + proc glUniformMatrix3dv(location: GLint, count: GLsizei, transpose: GLboolean, value: ptr GLdouble) {.importc.} + proc glVertexAttribPointerARB(index: GLuint, size: GLint, `type`: GLenum, normalized: GLboolean, stride: GLsizei, `pointer`: pointer) {.importc.} + proc glProgramUniformMatrix3x4dv(program: GLuint, location: GLint, count: GLsizei, transpose: GLboolean, value: ptr GLdouble) {.importc.} + proc glGetFloati_vEXT(pname: GLenum, index: GLuint, params: ptr GLfloat) {.importc.} + proc glGetObjectParameterivAPPLE(objectType: GLenum, name: GLuint, pname: GLenum, params: ptr GLint) {.importc.} + proc glPushGroupMarkerEXT(length: GLsizei, marker: cstring) {.importc.} + proc glProgramUniform4uivEXT(program: GLuint, location: GLint, count: GLsizei, value: ptr GLuint) {.importc.} + proc glReplacementCodeuiVertex3fSUN(rc: GLuint, x: GLfloat, y: GLfloat, z: GLfloat) {.importc.} + proc glTexSubImage1DEXT(target: GLenum, level: GLint, xoffset: GLint, width: GLsizei, format: GLenum, `type`: GLenum, pixels: pointer) {.importc.} + proc glProgramUniform1uivEXT(program: GLuint, location: GLint, count: GLsizei, value: ptr GLuint) {.importc.} + proc glGetFenceivNV(fence: GLuint, pname: GLenum, params: ptr GLint) {.importc.} + proc glGetnCompressedTexImageARB(target: GLenum, lod: GLint, bufSize: GLsizei, img: pointer) {.importc.} + proc glTexGenfOES(coord: GLenum, pname: GLenum, param: GLfloat) {.importc.} + proc glVertexAttrib4dv(index: GLuint, v: ptr GLdouble) {.importc.} + proc glVertexAttribL1ui64vNV(index: GLuint, v: ptr GLuint64Ext) {.importc.} + proc glVertexAttrib4fvARB(index: GLuint, v: ptr GLfloat) {.importc.} + proc glDeleteVertexArraysOES(n: GLsizei, arrays: ptr GLuint) {.importc.} + proc glSamplerParameterIiv(sampler: GLuint, pname: GLenum, param: ptr GLint) {.importc.} + proc glMapGrid1d(un: GLint, u1: GLdouble, u2: GLdouble) {.importc.} + proc glTranslatexOES(x: GLfixed, y: GLfixed, z: GLfixed) {.importc.} + proc glCullFace(mode: GLenum) {.importc.} + proc glPrioritizeTextures(n: GLsizei, textures: ptr GLuint, priorities: ptr GLfloat) {.importc.} + proc glGetSeparableFilterEXT(target: GLenum, format: GLenum, `type`: GLenum, row: pointer, column: pointer, span: pointer) {.importc.} + proc glVertexAttrib4NubvARB(index: GLuint, v: ptr GLubyte) {.importc.} + proc glGetTransformFeedbackVaryingNV(program: GLuint, index: GLuint, location: ptr GLint) {.importc.} + proc glTexCoord4xOES(s: GLfixed, t: GLfixed, r: GLfixed, q: GLfixed) {.importc.} + proc glGetProgramEnvParameterdvARB(target: GLenum, index: GLuint, params: ptr GLdouble) {.importc.} + proc glWindowPos2ivMESA(v: ptr GLint) {.importc.} + proc glGlobalAlphaFactorfSUN(factor: GLfloat) {.importc.} + proc glNormalStream3fvATI(stream: GLenum, coords: ptr GLfloat) {.importc.} + proc glRasterPos4i(x: GLint, y: GLint, z: GLint, w: GLint) {.importc.} + proc glReleaseShaderCompiler() {.importc.} + proc glProgramUniformMatrix4fvEXT(program: GLuint, location: GLint, count: GLsizei, transpose: GLboolean, value: ptr GLfloat) {.importc.} + proc glCopyMultiTexImage1DEXT(texunit: GLenum, target: GLenum, level: GLint, internalformat: GLenum, x: GLint, y: GLint, width: GLsizei, border: GLint) {.importc.} + proc glColorTableParameterfv(target: GLenum, pname: GLenum, params: ptr GLfloat) {.importc.} + proc glSecondaryColor3bvEXT(v: ptr GLbyte) {.importc.} + proc glMap1xOES(target: GLenum, u1: GLfixed, u2: GLfixed, stride: GLint, order: GLint, points: GLfixed) {.importc.} + proc glVertexStream1svATI(stream: GLenum, coords: ptr GLshort) {.importc.} + proc glIsRenderbuffer(renderbuffer: GLuint): GLboolean {.importc.} + proc glPatchParameterfv(pname: GLenum, values: ptr GLfloat) {.importc.} + proc glProgramUniformMatrix4dvEXT(program: GLuint, location: GLint, count: GLsizei, transpose: GLboolean, value: ptr GLdouble) {.importc.} + proc glVertexAttrib4ubNV(index: GLuint, x: GLubyte, y: GLubyte, z: GLubyte, w: GLubyte) {.importc.} + proc glVertex2i(x: GLint, y: GLint) {.importc.} + proc glPushClientAttrib(mask: GLbitfield) {.importc.} + proc glDrawArraysEXT(mode: GLenum, first: GLint, count: GLsizei) {.importc.} + proc glCreateProgram(): GLuint {.importc.} + proc glPolygonStipple(mask: ptr GLubyte) {.importc.} + proc glGetColorTableEXT(target: GLenum, format: GLenum, `type`: GLenum, data: pointer) {.importc.} + proc glSharpenTexFuncSGIS(target: GLenum, n: GLsizei, points: ptr GLfloat) {.importc.} + proc glNamedFramebufferTextureEXT(framebuffer: GLuint, attachment: GLenum, texture: GLuint, level: GLint) {.importc.} + proc glWindowPos3fvMESA(v: ptr GLfloat) {.importc.} + proc glBinormal3iEXT(bx: GLint, by: GLint, bz: GLint) {.importc.} + proc glEnableClientStateiEXT(`array`: GLenum, index: GLuint) {.importc.} + proc glProgramUniform3iv(program: GLuint, location: GLint, count: GLsizei, value: ptr GLint) {.importc.} + proc glProgramUniform1dEXT(program: GLuint, location: GLint, x: GLdouble) {.importc.} + proc glPollInstrumentsSGIX(marker_p: ptr GLint): GLint {.importc.} + proc glSecondaryColor3f(red: GLfloat, green: GLfloat, blue: GLfloat) {.importc.} + proc glDeleteTransformFeedbacks(n: GLsizei, ids: ptr GLuint) {.importc.} + proc glCoverStrokePathInstancedNV(numPaths: GLsizei, pathNameType: GLenum, paths: pointer, pathBase: GLuint, coverMode: GLenum, transformType: GLenum, transformValues: ptr GLfloat) {.importc.} + proc glIsTextureHandleResidentARB(handle: GLuint64): GLboolean {.importc.} + proc glVariantsvEXT(id: GLuint, `addr`: ptr GLshort) {.importc.} + proc glTexCoordFormatNV(size: GLint, `type`: GLenum, stride: GLsizei) {.importc.} + proc glTexStorage3DEXT(target: GLenum, levels: GLsizei, internalformat: GLenum, width: GLsizei, height: GLsizei, depth: GLsizei) {.importc.} + proc glUniform2ui(location: GLint, v0: GLuint, v1: GLuint) {.importc.} + proc glReplacementCodePointerSUN(`type`: GLenum, stride: GLsizei, `pointer`: ptr pointer) {.importc.} + proc glFramebufferTextureLayerARB(target: GLenum, attachment: GLenum, texture: GLuint, level: GLint, layer: GLint) {.importc.} + proc glBinormal3dvEXT(v: ptr GLdouble) {.importc.} + proc glProgramUniform2ui64vNV(program: GLuint, location: GLint, count: GLsizei, value: ptr GLuint64Ext) {.importc.} + proc glGetnConvolutionFilterARB(target: GLenum, format: GLenum, `type`: GLenum, bufSize: GLsizei, image: pointer) {.importc.} + proc glStopInstrumentsSGIX(marker: GLint) {.importc.} + proc glVertexAttrib1svNV(index: GLuint, v: ptr GLshort) {.importc.} + proc glVertexAttribs2fvNV(index: GLuint, count: GLsizei, v: ptr GLfloat) {.importc.} + proc glGetInternalformativ(target: GLenum, internalformat: GLenum, pname: GLenum, bufSize: GLsizei, params: ptr GLint) {.importc.} + proc glIsProgramPipelineEXT(pipeline: GLuint): GLboolean {.importc.} + proc glMatrixIndexubvARB(size: GLint, indices: ptr GLubyte) {.importc.} + proc glTexCoord4bOES(s: GLbyte, t: GLbyte, r: GLbyte, q: GLbyte) {.importc.} + proc glSecondaryColor3us(red: GLushort, green: GLushort, blue: GLushort) {.importc.} + proc glGlobalAlphaFactorubSUN(factor: GLubyte) {.importc.} + proc glNamedStringARB(`type`: GLenum, namelen: GLint, name: cstring, stringlen: GLint, string: cstring) {.importc.} + proc glGetAttachedShaders(program: GLuint, maxCount: GLsizei, count: ptr GLsizei, shaders: ptr GLuint) {.importc.} + proc glMatrixRotatefEXT(mode: GLenum, angle: GLfloat, x: GLfloat, y: GLfloat, z: GLfloat) {.importc.} + proc glVertexStream3ivATI(stream: GLenum, coords: ptr GLint) {.importc.} + proc glMatrixIndexuivARB(size: GLint, indices: ptr GLuint) {.importc.} + proc glMatrixRotatedEXT(mode: GLenum, angle: GLdouble, x: GLdouble, y: GLdouble, z: GLdouble) {.importc.} + proc glPathFogGenNV(genMode: GLenum) {.importc.} + proc glMultiTexCoord4hvNV(target: GLenum, v: ptr GLhalfNv) {.importc.} + proc glVertexAttribIPointer(index: GLuint, size: GLint, `type`: GLenum, stride: GLsizei, `pointer`: pointer) {.importc.} + proc glMultiTexCoord3bOES(texture: GLenum, s: GLbyte, t: GLbyte, r: GLbyte) {.importc.} + proc glResizeBuffersMESA() {.importc.} + proc glPrimitiveRestartIndexNV(index: GLuint) {.importc.} + proc glProgramUniform4f(program: GLuint, location: GLint, v0: GLfloat, v1: GLfloat, v2: GLfloat, v3: GLfloat) {.importc.} + proc glColor4ubVertex2fSUN(r: GLubyte, g: GLubyte, b: GLubyte, a: GLubyte, x: GLfloat, y: GLfloat) {.importc.} + proc glGetColorTableParameterivEXT(target: GLenum, pname: GLenum, params: ptr GLint) {.importc.} + proc glDepthRangef(n: GLfloat, f: GLfloat) {.importc.} + proc glVertexArrayVertexOffsetEXT(vaobj: GLuint, buffer: GLuint, size: GLint, `type`: GLenum, stride: GLsizei, offset: GLintptr) {.importc.} + proc glMatrixLoaddEXT(mode: GLenum, m: ptr GLdouble) {.importc.} + proc glVariantfvEXT(id: GLuint, `addr`: ptr GLfloat) {.importc.} + proc glReplacementCodeuiTexCoord2fVertex3fvSUN(rc: ptr GLuint, tc: ptr GLfloat, v: ptr GLfloat) {.importc.} + proc glSamplePatternSGIS(pattern: GLenum) {.importc.} + proc glProgramUniform3i64NV(program: GLuint, location: GLint, x: GLint64Ext, y: GLint64Ext, z: GLint64Ext) {.importc.} + proc glUniform3uivEXT(location: GLint, count: GLsizei, value: ptr GLuint) {.importc.} + proc glGetImageTransformParameterivHP(target: GLenum, pname: GLenum, params: ptr GLint) {.importc.} + proc glPopMatrix() {.importc.} + proc glVertexAttrib3sARB(index: GLuint, x: GLshort, y: GLshort, z: GLshort) {.importc.} + proc glGenQueriesEXT(n: GLsizei, ids: ptr GLuint) {.importc.} + proc glGetQueryObjectui64v(id: GLuint, pname: GLenum, params: ptr GLuint64) {.importc.} + proc glWeightusvARB(size: GLint, weights: ptr GLushort) {.importc.} + proc glWindowPos2sARB(x: GLshort, y: GLshort) {.importc.} + proc glGetTextureLevelParameterivEXT(texture: GLuint, target: GLenum, level: GLint, pname: GLenum, params: ptr GLint) {.importc.} + proc glBufferParameteriAPPLE(target: GLenum, pname: GLenum, param: GLint) {.importc.} + proc glMultiModeDrawArraysIBM(mode: ptr GLenum, first: ptr GLint, count: ptr GLsizei, primcount: GLsizei, modestride: GLint) {.importc.} + proc glUniformMatrix2x3fv(location: GLint, count: GLsizei, transpose: GLboolean, value: ptr GLfloat) {.importc.} + proc glTangentPointerEXT(`type`: GLenum, stride: GLsizei, `pointer`: pointer) {.importc.} + proc glResetMinmax(target: GLenum) {.importc.} + proc glVertexAttribP1uiv(index: GLuint, `type`: GLenum, normalized: GLboolean, value: ptr GLuint) {.importc.} + proc glPixelMapx(map: GLenum, size: GLint, values: ptr GLfixed) {.importc.} + proc glPixelStoref(pname: GLenum, param: GLfloat) {.importc.} + proc glBinormal3dEXT(bx: GLdouble, by: GLdouble, bz: GLdouble) {.importc.} + proc glVertexAttribs1hvNV(index: GLuint, n: GLsizei, v: ptr GLhalfNv) {.importc.} + proc glVertexAttrib4usvARB(index: GLuint, v: ptr GLushort) {.importc.} + proc glUnmapBuffer(target: GLenum): GLboolean {.importc.} + proc glFlushRasterSGIX() {.importc.} + proc glColor3uiv(v: ptr GLuint) {.importc.} + proc glInvalidateBufferSubData(buffer: GLuint, offset: GLintptr, length: GLsizeiptr) {.importc.} + proc glPassThroughxOES(token: GLfixed) {.importc.} + proc glLockArraysEXT(first: GLint, count: GLsizei) {.importc.} + proc glStencilFuncSeparateATI(frontfunc: GLenum, backfunc: GLenum, `ref`: GLint, mask: GLuint) {.importc.} + proc glProgramUniform3dvEXT(program: GLuint, location: GLint, count: GLsizei, value: ptr GLdouble) {.importc.} + proc glGenTransformFeedbacks(n: GLsizei, ids: ptr GLuint) {.importc.} + proc glCopyTexSubImage3DOES(target: GLenum, level: GLint, xoffset: GLint, yoffset: GLint, zoffset: GLint, x: GLint, y: GLint, width: GLsizei, height: GLsizei) {.importc.} + proc glIsNamedBufferResidentNV(buffer: GLuint): GLboolean {.importc.} + proc glSampleMaskIndexedNV(index: GLuint, mask: GLbitfield) {.importc.} + proc glVDPAUSurfaceAccessNV(surface: GLvdpauSurfaceNv, access: GLenum) {.importc.} + proc glProgramUniform3dv(program: GLuint, location: GLint, count: GLsizei, value: ptr GLdouble) {.importc.} + proc glDeleteProgram(program: GLuint) {.importc.} + proc glConvolutionFilter1D(target: GLenum, internalformat: GLenum, width: GLsizei, format: GLenum, `type`: GLenum, image: pointer) {.importc.} + proc glVertex2f(x: GLfloat, y: GLfloat) {.importc.} + proc glWindowPos4dvMESA(v: ptr GLdouble) {.importc.} + proc glColor4us(red: GLushort, green: GLushort, blue: GLushort, alpha: GLushort) {.importc.} + proc glColorMask(red: GLboolean, green: GLboolean, blue: GLboolean, alpha: GLboolean) {.importc.} + proc glGetTexEnviv(target: GLenum, pname: GLenum, params: ptr GLint) {.importc.} + proc glProgramUniform3ivEXT(program: GLuint, location: GLint, count: GLsizei, value: ptr GLint) {.importc.} + proc glSecondaryColor3i(red: GLint, green: GLint, blue: GLint) {.importc.} + proc glGetSamplerParameteriv(sampler: GLuint, pname: GLenum, params: ptr GLint) {.importc.} + proc glDeleteFramebuffersEXT(n: GLsizei, framebuffers: ptr GLuint) {.importc.} + proc glCompressedTexSubImage3D(target: GLenum, level: GLint, xoffset: GLint, yoffset: GLint, zoffset: GLint, width: GLsizei, height: GLsizei, depth: GLsizei, format: GLenum, imageSize: GLsizei, data: pointer) {.importc.} + proc glVertex2s(x: GLshort, y: GLshort) {.importc.} + proc glIsQuery(id: GLuint): GLboolean {.importc.} + proc glFogxv(pname: GLenum, param: ptr GLfixed) {.importc.} + proc glAreProgramsResidentNV(n: GLsizei, programs: ptr GLuint, residences: ptr GLboolean): GLboolean {.importc.} + proc glShaderSourceARB(shaderObj: GLhandleArb, count: GLsizei, string: cstringArray, length: ptr GLint) {.importc.} + proc glPointSizexOES(size: GLfixed) {.importc.} + proc glPixelTransferf(pname: GLenum, param: GLfloat) {.importc.} + proc glExtractComponentEXT(res: GLuint, src: GLuint, num: GLuint) {.importc.} + proc glUniform1fv(location: GLint, count: GLsizei, value: ptr GLfloat) {.importc.} + proc glGetNamedStringARB(namelen: GLint, name: cstring, bufSize: GLsizei, stringlen: ptr GLint, string: cstring) {.importc.} + proc glGetProgramBinaryOES(program: GLuint, bufSize: GLsizei, length: ptr GLsizei, binaryFormat: ptr GLenum, binary: pointer) {.importc.} + proc glDeleteOcclusionQueriesNV(n: GLsizei, ids: ptr GLuint) {.importc.} + proc glEnableClientState(`array`: GLenum) {.importc.} + proc glProgramBufferParametersIuivNV(target: GLenum, bindingIndex: GLuint, wordIndex: GLuint, count: GLsizei, params: ptr GLuint) {.importc.} + proc glProgramUniform2ui(program: GLuint, location: GLint, v0: GLuint, v1: GLuint) {.importc.} + proc glReplacementCodeuiSUN(code: GLuint) {.importc.} + proc glMultMatrixd(m: ptr GLdouble) {.importc.} + proc glInvalidateSubFramebuffer(target: GLenum, numAttachments: GLsizei, attachments: ptr GLenum, x: GLint, y: GLint, width: GLsizei, height: GLsizei) {.importc.} + proc glGenerateMultiTexMipmapEXT(texunit: GLenum, target: GLenum) {.importc.} + proc glDepthRangex(n: GLfixed, f: GLfixed) {.importc.} + proc glGetInteger64i_v(target: GLenum, index: GLuint, data: ptr GLint64) {.importc.} + proc glDrawBuffers(n: GLsizei, bufs: ptr GLenum) {.importc.} + proc glGetPointervEXT(pname: GLenum, params: ptr pointer) {.importc.} + proc glFogxvOES(pname: GLenum, param: ptr GLfixed) {.importc.} + proc glTexCoordP2uiv(`type`: GLenum, coords: ptr GLuint) {.importc.} + proc glVertexFormatNV(size: GLint, `type`: GLenum, stride: GLsizei) {.importc.} + proc glColorPointervINTEL(size: GLint, `type`: GLenum, `pointer`: ptr pointer) {.importc.} + proc glGetMultiTexParameterivEXT(texunit: GLenum, target: GLenum, pname: GLenum, params: ptr GLint) {.importc.} + proc glMultiTexCoordP4uiv(texture: GLenum, `type`: GLenum, coords: ptr GLuint) {.importc.} + proc glResetMinmaxEXT(target: GLenum) {.importc.} + proc glCopyBufferSubData(readTarget: GLenum, writeTarget: GLenum, readOffset: GLintptr, writeOffset: GLintptr, size: GLsizeiptr) {.importc.} + proc glSecondaryColor3sv(v: ptr GLshort) {.importc.} + proc glPixelStorex(pname: GLenum, param: GLfixed) {.importc.} + proc glWaitSync(sync: GLsync, flags: GLbitfield, timeout: GLuint64) {.importc.} + proc glVertexAttribI1iv(index: GLuint, v: ptr GLint) {.importc.} + proc glColorSubTableEXT(target: GLenum, start: GLsizei, count: GLsizei, format: GLenum, `type`: GLenum, data: pointer) {.importc.} + proc glGetDoublev(pname: GLenum, params: ptr GLdouble) {.importc.} + proc glMultiTexParameterivEXT(texunit: GLenum, target: GLenum, pname: GLenum, params: ptr GLint) {.importc.} + proc glMultiTexCoord4svARB(target: GLenum, v: ptr GLshort) {.importc.} + proc glColorPointerListIBM(size: GLint, `type`: GLenum, stride: GLint, `pointer`: ptr pointer, ptrstride: GLint) {.importc.} + proc glScissorIndexed(index: GLuint, left: GLint, bottom: GLint, width: GLsizei, height: GLsizei) {.importc.} + proc glStencilOpSeparateATI(face: GLenum, sfail: GLenum, dpfail: GLenum, dppass: GLenum) {.importc.} + proc glLoadName(name: GLuint) {.importc.} + proc glIsTransformFeedbackNV(id: GLuint): GLboolean {.importc.} + proc glPopDebugGroup() {.importc.} + proc glClipPlanef(p: GLenum, eqn: ptr GLfloat) {.importc.} + proc glDeleteFencesAPPLE(n: GLsizei, fences: ptr GLuint) {.importc.} + proc glGetQueryObjecti64v(id: GLuint, pname: GLenum, params: ptr GLint64) {.importc.} + proc glAlphaFunc(fun: GLenum, `ref`: GLfloat) {.importc.} + proc glIndexPointerEXT(`type`: GLenum, stride: GLsizei, count: GLsizei, `pointer`: pointer) {.importc.} + proc glVertexAttribI3ivEXT(index: GLuint, v: ptr GLint) {.importc.} + proc glIndexub(c: GLubyte) {.importc.} + proc glVertexP2uiv(`type`: GLenum, value: ptr GLuint) {.importc.} + proc glProgramUniform1uiv(program: GLuint, location: GLint, count: GLsizei, value: ptr GLuint) {.importc.} + proc glDebugMessageInsertKHR(source: GLenum, `type`: GLenum, id: GLuint, severity: GLenum, length: GLsizei, buf: cstring) {.importc.} + proc glColor4b(red: GLbyte, green: GLbyte, blue: GLbyte, alpha: GLbyte) {.importc.} + proc glRenderbufferStorageMultisampleAPPLE(target: GLenum, samples: GLsizei, internalformat: GLenum, width: GLsizei, height: GLsizei) {.importc.} + proc glMinSampleShading(value: GLfloat) {.importc.} + proc glBindProgramNV(target: GLenum, id: GLuint) {.importc.} + proc glWindowPos3dMESA(x: GLdouble, y: GLdouble, z: GLdouble) {.importc.} + proc glEdgeFlagPointer(stride: GLsizei, `pointer`: pointer) {.importc.} + proc glGetFragDataIndex(program: GLuint, name: cstring): GLint {.importc.} + proc glTexCoord3hNV(s: GLhalfNv, t: GLhalfNv, r: GLhalfNv) {.importc.} + proc glMultiDrawArraysIndirectAMD(mode: GLenum, indirect: pointer, primcount: GLsizei, stride: GLsizei) {.importc.} + proc glFragmentColorMaterialSGIX(face: GLenum, mode: GLenum) {.importc.} + proc glTexGenf(coord: GLenum, pname: GLenum, param: GLfloat) {.importc.} + proc glVertexAttrib4ubvARB(index: GLuint, v: ptr GLubyte) {.importc.} + proc glClearBufferiv(buffer: GLenum, drawbuffer: GLint, value: ptr GLint) {.importc.} + proc glGenQueriesARB(n: GLsizei, ids: ptr GLuint) {.importc.} + proc glRectdv(v1: ptr GLdouble, v2: ptr GLdouble) {.importc.} + proc glBlendEquationSeparateEXT(modeRgb: GLenum, modeAlpha: GLenum) {.importc.} + proc glTestFenceAPPLE(fence: GLuint): GLboolean {.importc.} + proc glTexGeniv(coord: GLenum, pname: GLenum, params: ptr GLint) {.importc.} + proc glPolygonMode(face: GLenum, mode: GLenum) {.importc.} + proc glFrameZoomSGIX(factor: GLint) {.importc.} + proc glReplacementCodeuiTexCoord2fVertex3fSUN(rc: GLuint, s: GLfloat, t: GLfloat, x: GLfloat, y: GLfloat, z: GLfloat) {.importc.} + proc glUniformSubroutinesuiv(shadertype: GLenum, count: GLsizei, indices: ptr GLuint) {.importc.} + proc glBeginQueryIndexed(target: GLenum, index: GLuint, id: GLuint) {.importc.} + proc glMultiTexGeniEXT(texunit: GLenum, coord: GLenum, pname: GLenum, param: GLint) {.importc.} + proc glRasterPos3fv(v: ptr GLfloat) {.importc.} + proc glMapObjectBufferATI(buffer: GLuint): pointer {.importc.} + proc glIndexiv(c: ptr GLint) {.importc.} + proc glVertexAttribLPointer(index: GLuint, size: GLint, `type`: GLenum, stride: GLsizei, `pointer`: pointer) {.importc.} + proc glMultiTexCoord4s(target: GLenum, s: GLshort, t: GLshort, r: GLshort, q: GLshort) {.importc.} + proc glSecondaryColorP3uiv(`type`: GLenum, color: ptr GLuint) {.importc.} + proc glNormalFormatNV(`type`: GLenum, stride: GLsizei) {.importc.} + proc glVertex4i(x: GLint, y: GLint, z: GLint, w: GLint) {.importc.} + proc glUniform1ui64NV(location: GLint, x: GLuint64Ext) {.importc.} + proc glScissorIndexedv(index: GLuint, v: ptr GLint) {.importc.} + proc glProgramUniform1i(program: GLuint, location: GLint, v0: GLint) {.importc.} + proc glCompressedMultiTexSubImage3DEXT(texunit: GLenum, target: GLenum, level: GLint, xoffset: GLint, yoffset: GLint, zoffset: GLint, width: GLsizei, height: GLsizei, depth: GLsizei, format: GLenum, imageSize: GLsizei, bits: pointer) {.importc.} + proc glFinishTextureSUNX() {.importc.} + proc glFramebufferTexture3DEXT(target: GLenum, attachment: GLenum, textarget: GLenum, texture: GLuint, level: GLint, zoffset: GLint) {.importc.} + proc glSetInvariantEXT(id: GLuint, `type`: GLenum, `addr`: pointer) {.importc.} + proc glGetTexParameterIivEXT(target: GLenum, pname: GLenum, params: ptr GLint) {.importc.} + proc glMultiTexCoordP3ui(texture: GLenum, `type`: GLenum, coords: GLuint) {.importc.} + proc glMultiTexCoord3f(target: GLenum, s: GLfloat, t: GLfloat, r: GLfloat) {.importc.} + proc glNormalStream3fATI(stream: GLenum, nx: GLfloat, ny: GLfloat, nz: GLfloat) {.importc.} + proc glActiveShaderProgram(pipeline: GLuint, program: GLuint) {.importc.} + proc glDisableVertexArrayEXT(vaobj: GLuint, `array`: GLenum) {.importc.} + proc glVertexAttribI3iv(index: GLuint, v: ptr GLint) {.importc.} + proc glProvokingVertex(mode: GLenum) {.importc.} + proc glTexCoord1fv(v: ptr GLfloat) {.importc.} + proc glVertexAttrib3fv(index: GLuint, v: ptr GLfloat) {.importc.} + proc glWindowPos3iv(v: ptr GLint) {.importc.} + proc glProgramUniform4ui64NV(program: GLuint, location: GLint, x: GLuint64Ext, y: GLuint64Ext, z: GLuint64Ext, w: GLuint64Ext) {.importc.} + proc glProgramUniform2d(program: GLuint, location: GLint, v0: GLdouble, v1: GLdouble) {.importc.} + proc glDebugMessageInsertARB(source: GLenum, `type`: GLenum, id: GLuint, severity: GLenum, length: GLsizei, buf: cstring) {.importc.} + proc glMultiTexSubImage3DEXT(texunit: GLenum, target: GLenum, level: GLint, xoffset: GLint, yoffset: GLint, zoffset: GLint, width: GLsizei, height: GLsizei, depth: GLsizei, format: GLenum, `type`: GLenum, pixels: pointer) {.importc.} + proc glMap1d(target: GLenum, u1: GLdouble, u2: GLdouble, stride: GLint, order: GLint, points: ptr GLdouble) {.importc.} + proc glDeleteShader(shader: GLuint) {.importc.} + proc glTexturePageCommitmentEXT(texture: GLuint, target: GLenum, level: GLint, xoffset: GLint, yoffset: GLint, zoffset: GLint, width: GLsizei, height: GLsizei, depth: GLsizei, resident: GLboolean) {.importc.} + proc glFramebufferDrawBufferEXT(framebuffer: GLuint, mode: GLenum) {.importc.} + proc glTexCoord2fNormal3fVertex3fSUN(s: GLfloat, t: GLfloat, nx: GLfloat, ny: GLfloat, nz: GLfloat, x: GLfloat, y: GLfloat, z: GLfloat) {.importc.} + proc glDeleteProgramsNV(n: GLsizei, programs: ptr GLuint) {.importc.} + proc glPointAlongPathNV(path: GLuint, startSegment: GLsizei, numSegments: GLsizei, distance: GLfloat, x: ptr GLfloat, y: ptr GLfloat, tangentX: ptr GLfloat, tangentY: ptr GLfloat): GLboolean {.importc.} + proc glTexCoord1d(s: GLdouble) {.importc.} + proc glStencilStrokePathNV(path: GLuint, reference: GLint, mask: GLuint) {.importc.} + proc glQueryMatrixxOES(mantissa: ptr GLfixed, exponent: ptr GLint): GLbitfield {.importc.} + proc glGetNamedProgramLocalParameterIuivEXT(program: GLuint, target: GLenum, index: GLuint, params: ptr GLuint) {.importc.} + proc glGenerateMipmapOES(target: GLenum) {.importc.} + proc glRenderbufferStorageMultisampleIMG(target: GLenum, samples: GLsizei, internalformat: GLenum, width: GLsizei, height: GLsizei) {.importc.} + proc glVertexBlendEnviATI(pname: GLenum, param: GLint) {.importc.} + proc glPushAttrib(mask: GLbitfield) {.importc.} + proc glShaderOp3EXT(op: GLenum, res: GLuint, arg1: GLuint, arg2: GLuint, arg3: GLuint) {.importc.} + proc glEnableVertexAttribArray(index: GLuint) {.importc.} + proc glVertexAttrib4Nbv(index: GLuint, v: ptr GLbyte) {.importc.} + proc glExtGetBuffersQCOM(buffers: ptr GLuint, maxBuffers: GLint, numBuffers: ptr GLint) {.importc.} + proc glCopyTexSubImage3D(target: GLenum, level: GLint, xoffset: GLint, yoffset: GLint, zoffset: GLint, x: GLint, y: GLint, width: GLsizei, height: GLsizei) {.importc.} + proc glDeletePerfMonitorsAMD(n: GLsizei, monitors: ptr GLuint) {.importc.} + proc glGetTrackMatrixivNV(target: GLenum, address: GLuint, pname: GLenum, params: ptr GLint) {.importc.} + proc glEndConditionalRender() {.importc.} + proc glVertexAttribL3i64NV(index: GLuint, x: GLint64Ext, y: GLint64Ext, z: GLint64Ext) {.importc.} + proc glProgramLocalParametersI4ivNV(target: GLenum, index: GLuint, count: GLsizei, params: ptr GLint) {.importc.} + proc glFlush() {.importc.} + proc glGetNamedBufferParameterui64vNV(buffer: GLuint, pname: GLenum, params: ptr GLuint64Ext) {.importc.} + proc glGetVertexArrayIntegeri_vEXT(vaobj: GLuint, index: GLuint, pname: GLenum, param: ptr GLint) {.importc.} + proc glReadnPixelsEXT(x: GLint, y: GLint, width: GLsizei, height: GLsizei, format: GLenum, `type`: GLenum, bufSize: GLsizei, data: pointer) {.importc.} + proc glMultiTexImage1DEXT(texunit: GLenum, target: GLenum, level: GLint, internalformat: GLint, width: GLsizei, border: GLint, format: GLenum, `type`: GLenum, pixels: pointer) {.importc.} + proc glGetVaryingLocationNV(program: GLuint, name: cstring): GLint {.importc.} + proc glMultiTexCoord4fvARB(target: GLenum, v: ptr GLfloat) {.importc.} + proc glMultiTexCoord3iv(target: GLenum, v: ptr GLint) {.importc.} + proc glVertexAttribL2dvEXT(index: GLuint, v: ptr GLdouble) {.importc.} + proc glTexParameterxOES(target: GLenum, pname: GLenum, param: GLfixed) {.importc.} + proc glSecondaryColor3uivEXT(v: ptr GLuint) {.importc.} + proc glReadnPixelsARB(x: GLint, y: GLint, width: GLsizei, height: GLsizei, format: GLenum, `type`: GLenum, bufSize: GLsizei, data: pointer) {.importc.} + proc glCopyTexSubImage1DEXT(target: GLenum, level: GLint, xoffset: GLint, x: GLint, y: GLint, width: GLsizei) {.importc.} + proc glGetDoublei_vEXT(pname: GLenum, index: GLuint, params: ptr GLdouble) {.importc.} + proc glVariantPointerEXT(id: GLuint, `type`: GLenum, stride: GLuint, `addr`: pointer) {.importc.} + proc glProgramUniform3ui64vNV(program: GLuint, location: GLint, count: GLsizei, value: ptr GLuint64Ext) {.importc.} + proc glTexCoord2fColor3fVertex3fvSUN(tc: ptr GLfloat, c: ptr GLfloat, v: ptr GLfloat) {.importc.} + proc glProgramUniform3fv(program: GLuint, location: GLint, count: GLsizei, value: ptr GLfloat) {.importc.} + proc glBindFragDataLocationIndexed(program: GLuint, colorNumber: GLuint, index: GLuint, name: cstring) {.importc.} + proc glGetnSeparableFilterARB(target: GLenum, format: GLenum, `type`: GLenum, rowBufSize: GLsizei, row: pointer, columnBufSize: GLsizei, column: pointer, span: pointer) {.importc.} + proc glTextureParameteriEXT(texture: GLuint, target: GLenum, pname: GLenum, param: GLint) {.importc.} + proc glGetUniformuivEXT(program: GLuint, location: GLint, params: ptr GLuint) {.importc.} + proc glFragmentMaterialivSGIX(face: GLenum, pname: GLenum, params: ptr GLint) {.importc.} + proc glMultiTexCoord1svARB(target: GLenum, v: ptr GLshort) {.importc.} + proc glClientActiveTextureARB(texture: GLenum) {.importc.} + proc glVertexAttrib1fARB(index: GLuint, x: GLfloat) {.importc.} + proc glVertexAttrib4NbvARB(index: GLuint, v: ptr GLbyte) {.importc.} + proc glRasterPos2d(x: GLdouble, y: GLdouble) {.importc.} + proc glMultiTexCoord4iARB(target: GLenum, s: GLint, t: GLint, r: GLint, q: GLint) {.importc.} + proc glGetPixelTexGenParameterfvSGIS(pname: GLenum, params: ptr GLfloat) {.importc.} + proc glVertexAttribL2dv(index: GLuint, v: ptr GLdouble) {.importc.} + proc glGetProgramStringARB(target: GLenum, pname: GLenum, string: pointer) {.importc.} + proc glRasterPos2i(x: GLint, y: GLint) {.importc.} + proc glTexCoord2fColor4fNormal3fVertex3fvSUN(tc: ptr GLfloat, c: ptr GLfloat, n: ptr GLfloat, v: ptr GLfloat) {.importc.} + proc glMultiTexCoord3s(target: GLenum, s: GLshort, t: GLshort, r: GLshort) {.importc.} + proc glMultTransposeMatrixd(m: ptr GLdouble) {.importc.} + proc glActiveVaryingNV(program: GLuint, name: cstring) {.importc.} + proc glProgramUniform1f(program: GLuint, location: GLint, v0: GLfloat) {.importc.} + proc glGetActiveSubroutineName(program: GLuint, shadertype: GLenum, index: GLuint, bufsize: GLsizei, length: ptr GLsizei, name: cstring) {.importc.} + proc glClipPlanex(plane: GLenum, equation: ptr GLfixed) {.importc.} + proc glMultiTexCoord4iv(target: GLenum, v: ptr GLint) {.importc.} + proc glTransformFeedbackVaryingsEXT(program: GLuint, count: GLsizei, varyings: cstringArray, bufferMode: GLenum) {.importc.} + proc glBlendEquationSeparateiARB(buf: GLuint, modeRgb: GLenum, modeAlpha: GLenum) {.importc.} + proc glVertex2sv(v: ptr GLshort) {.importc.} + proc glAccumxOES(op: GLenum, value: GLfixed) {.importc.} + proc glProgramLocalParameter4dARB(target: GLenum, index: GLuint, x: GLdouble, y: GLdouble, z: GLdouble, w: GLdouble) {.importc.} + proc glIsRenderbufferEXT(renderbuffer: GLuint): GLboolean {.importc.} + proc glMultiDrawElementsIndirectAMD(mode: GLenum, `type`: GLenum, indirect: pointer, primcount: GLsizei, stride: GLsizei) {.importc.} + proc glVertexAttribI4uiEXT(index: GLuint, x: GLuint, y: GLuint, z: GLuint, w: GLuint) {.importc.} + proc glVertex4fv(v: ptr GLfloat) {.importc.} + proc glGenerateMipmapEXT(target: GLenum) {.importc.} + proc glVertexP3ui(`type`: GLenum, value: GLuint) {.importc.} + proc glTexCoord2dv(v: ptr GLdouble) {.importc.} + proc glFlushMappedBufferRange(target: GLenum, offset: GLintptr, length: GLsizeiptr) {.importc.} + proc glTrackMatrixNV(target: GLenum, address: GLuint, matrix: GLenum, transform: GLenum) {.importc.} + proc glFragmentLightModeliSGIX(pname: GLenum, param: GLint) {.importc.} + proc glVertexAttrib4Nusv(index: GLuint, v: ptr GLushort) {.importc.} + proc glScalef(x: GLfloat, y: GLfloat, z: GLfloat) {.importc.} + proc glLightxvOES(light: GLenum, pname: GLenum, params: ptr GLfixed) {.importc.} + proc glTextureParameterivEXT(texture: GLuint, target: GLenum, pname: GLenum, params: ptr GLint) {.importc.} + proc glCompressedMultiTexImage3DEXT(texunit: GLenum, target: GLenum, level: GLint, internalformat: GLenum, width: GLsizei, height: GLsizei, depth: GLsizei, border: GLint, imageSize: GLsizei, bits: pointer) {.importc.} + proc glVertexAttribL1d(index: GLuint, x: GLdouble) {.importc.} + proc glVertexAttrib3fARB(index: GLuint, x: GLfloat, y: GLfloat, z: GLfloat) {.importc.} + proc glVertexAttrib3hvNV(index: GLuint, v: ptr GLhalfNv) {.importc.} + proc glSpriteParameteriSGIX(pname: GLenum, param: GLint) {.importc.} + proc glFrustumxOES(l: GLfixed, r: GLfixed, b: GLfixed, t: GLfixed, n: GLfixed, f: GLfixed) {.importc.} + proc glGetnMapdvARB(target: GLenum, query: GLenum, bufSize: GLsizei, v: ptr GLdouble) {.importc.} + proc glGetMinmaxEXT(target: GLenum, reset: GLboolean, format: GLenum, `type`: GLenum, values: pointer) {.importc.} + proc glProgramUniformHandleui64NV(program: GLuint, location: GLint, value: GLuint64) {.importc.} + proc glWindowPos4fvMESA(v: ptr GLfloat) {.importc.} + proc glExtGetTexturesQCOM(textures: ptr GLuint, maxTextures: GLint, numTextures: ptr GLint) {.importc.} + proc glProgramSubroutineParametersuivNV(target: GLenum, count: GLsizei, params: ptr GLuint) {.importc.} + proc glSampleCoveragexOES(value: GLclampx, invert: GLboolean) {.importc.} + proc glMultiTexEnvivEXT(texunit: GLenum, target: GLenum, pname: GLenum, params: ptr GLint) {.importc.} + proc glGetFinalCombinerInputParameterfvNV(variable: GLenum, pname: GLenum, params: ptr GLfloat) {.importc.} + proc glLightModeliv(pname: GLenum, params: ptr GLint) {.importc.} + proc glUniform4f(location: GLint, v0: GLfloat, v1: GLfloat, v2: GLfloat, v3: GLfloat) {.importc.} + proc glDepthRange(near: GLdouble, far: GLdouble) {.importc.} + proc glProgramUniformMatrix4x3dv(program: GLuint, location: GLint, count: GLsizei, transpose: GLboolean, value: ptr GLdouble) {.importc.} + proc glProgramUniform4fv(program: GLuint, location: GLint, count: GLsizei, value: ptr GLfloat) {.importc.} + proc glGetTexParameterIiv(target: GLenum, pname: GLenum, params: ptr GLint) {.importc.} + proc glVertexAttribs4dvNV(index: GLuint, count: GLsizei, v: ptr GLdouble) {.importc.} + proc glConvolutionParameteri(target: GLenum, pname: GLenum, params: GLint) {.importc.} + proc glVertexAttribI4uiv(index: GLuint, v: ptr GLuint) {.importc.} + proc glEvalCoord1dv(u: ptr GLdouble) {.importc.} + proc glIsFramebuffer(framebuffer: GLuint): GLboolean {.importc.} + proc glEvalCoord2d(u: GLdouble, v: GLdouble) {.importc.} + proc glClearDepthf(d: GLfloat) {.importc.} + proc glCompressedTexSubImage2D(target: GLenum, level: GLint, xoffset: GLint, yoffset: GLint, width: GLsizei, height: GLsizei, format: GLenum, imageSize: GLsizei, data: pointer) {.importc.} + proc glProgramUniformMatrix3x2dvEXT(program: GLuint, location: GLint, count: GLsizei, transpose: GLboolean, value: ptr GLdouble) {.importc.} + proc glGetTexParameterxv(target: GLenum, pname: GLenum, params: ptr GLfixed) {.importc.} + proc glBinormal3fEXT(bx: GLfloat, by: GLfloat, bz: GLfloat) {.importc.} + proc glProgramParameteriARB(program: GLuint, pname: GLenum, value: GLint) {.importc.} + proc glWindowPos3ivMESA(v: ptr GLint) {.importc.} + proc glReplacementCodeuiColor4fNormal3fVertex3fvSUN(rc: ptr GLuint, c: ptr GLfloat, n: ptr GLfloat, v: ptr GLfloat) {.importc.} + proc glPresentFrameDualFillNV(video_slot: GLuint, minPresentTime: GLuint64Ext, beginPresentTimeId: GLuint, presentDurationId: GLuint, `type`: GLenum, target0: GLenum, fill0: GLuint, target1: GLenum, fill1: GLuint, target2: GLenum, fill2: GLuint, target3: GLenum, fill3: GLuint) {.importc.} + proc glIndexPointerListIBM(`type`: GLenum, stride: GLint, `pointer`: ptr pointer, ptrstride: GLint) {.importc.} + proc glVertexStream2dATI(stream: GLenum, x: GLdouble, y: GLdouble) {.importc.} + proc glUniformMatrix3x4dv(location: GLint, count: GLsizei, transpose: GLboolean, value: ptr GLdouble) {.importc.} + proc glMapNamedBufferRangeEXT(buffer: GLuint, offset: GLintptr, length: GLsizeiptr, access: GLbitfield): pointer {.importc.} + proc glColor4sv(v: ptr GLshort) {.importc.} + proc glStencilFillPathNV(path: GLuint, fillMode: GLenum, mask: GLuint) {.importc.} + proc glGetVertexAttribfvARB(index: GLuint, pname: GLenum, params: ptr GLfloat) {.importc.} + proc glWindowPos3dv(v: ptr GLdouble) {.importc.} + proc glHintPGI(target: GLenum, mode: GLint) {.importc.} + proc glVertexAttribs3hvNV(index: GLuint, n: GLsizei, v: ptr GLhalfNv) {.importc.} + proc glProgramUniform1i64NV(program: GLuint, location: GLint, x: GLint64Ext) {.importc.} + proc glReplacementCodeuiColor3fVertex3fSUN(rc: GLuint, r: GLfloat, g: GLfloat, b: GLfloat, x: GLfloat, y: GLfloat, z: GLfloat) {.importc.} + proc glUniform2iARB(location: GLint, v0: GLint, v1: GLint) {.importc.} + proc glViewport(x: GLint, y: GLint, width: GLsizei, height: GLsizei) {.importc.} + proc glBlendFuncSeparateIndexedAMD(buf: GLuint, srcRgb: GLenum, dstRgb: GLenum, srcAlpha: GLenum, dstAlpha: GLenum) {.importc.} + proc glColor3us(red: GLushort, green: GLushort, blue: GLushort) {.importc.} + proc glVertexAttrib2hvNV(index: GLuint, v: ptr GLhalfNv) {.importc.} + proc glGenerateMipmap(target: GLenum) {.importc.} + proc glGetProgramEnvParameterIuivNV(target: GLenum, index: GLuint, params: ptr GLuint) {.importc.} + proc glBlendEquationiARB(buf: GLuint, mode: GLenum) {.importc.} + proc glReadBufferNV(mode: GLenum) {.importc.} + proc glProvokingVertexEXT(mode: GLenum) {.importc.} + proc glPointParameterivNV(pname: GLenum, params: ptr GLint) {.importc.} + proc glBlitFramebufferANGLE(srcX0: GLint, srcY0: GLint, srcX1: GLint, srcY1: GLint, dstX0: GLint, dstY0: GLint, dstX1: GLint, dstY1: GLint, mask: GLbitfield, filter: GLenum) {.importc.} + proc glGetObjectParameterivARB(obj: GLhandleArb, pname: GLenum, params: ptr GLint) {.importc.} + proc glGetSubroutineIndex(program: GLuint, shadertype: GLenum, name: cstring): GLuint {.importc.} + proc glMap2d(target: GLenum, u1: GLdouble, u2: GLdouble, ustride: GLint, uorder: GLint, v1: GLdouble, v2: GLdouble, vstride: GLint, vorder: GLint, points: ptr GLdouble) {.importc.} + proc glRectfv(v1: ptr GLfloat, v2: ptr GLfloat) {.importc.} + proc glDepthRangeArrayv(first: GLuint, count: GLsizei, v: ptr GLdouble) {.importc.} + proc glMultiTexParameteriEXT(texunit: GLenum, target: GLenum, pname: GLenum, param: GLint) {.importc.} + proc glTexStorageSparseAMD(target: GLenum, internalFormat: GLenum, width: GLsizei, height: GLsizei, depth: GLsizei, layers: GLsizei, flags: GLbitfield) {.importc.} + proc glGenerateTextureMipmapEXT(texture: GLuint, target: GLenum) {.importc.} + proc glCopyConvolutionFilter1D(target: GLenum, internalformat: GLenum, x: GLint, y: GLint, width: GLsizei) {.importc.} + proc glVertex4d(x: GLdouble, y: GLdouble, z: GLdouble, w: GLdouble) {.importc.} + proc glGetPathParameterfvNV(path: GLuint, pname: GLenum, value: ptr GLfloat) {.importc.} + proc glDetachShader(program: GLuint, shader: GLuint) {.importc.} + proc glGetColorTableSGI(target: GLenum, format: GLenum, `type`: GLenum, table: pointer) {.importc.} + proc glPixelTransformParameterfvEXT(target: GLenum, pname: GLenum, params: ptr GLfloat) {.importc.} + proc glBufferSubDataARB(target: GLenum, offset: GLintPtrArb, size: GLsizeiptrArb, data: pointer) {.importc.} + proc glVertexAttrib4ubvNV(index: GLuint, v: ptr GLubyte) {.importc.} + proc glCopyTextureImage1DEXT(texture: GLuint, target: GLenum, level: GLint, internalformat: GLenum, x: GLint, y: GLint, width: GLsizei, border: GLint) {.importc.} + proc glGetQueryivARB(target: GLenum, pname: GLenum, params: ptr GLint) {.importc.} + proc glVertexAttribIPointerEXT(index: GLuint, size: GLint, `type`: GLenum, stride: GLsizei, `pointer`: pointer) {.importc.} + proc glVertexAttribL3dEXT(index: GLuint, x: GLdouble, y: GLdouble, z: GLdouble) {.importc.} + proc glGetQueryObjectui64vEXT(id: GLuint, pname: GLenum, params: ptr GLuint64) {.importc.} + proc glColor4x(red: GLfixed, green: GLfixed, blue: GLfixed, alpha: GLfixed) {.importc.} + proc glProgramUniformMatrix3x2dv(program: GLuint, location: GLint, count: GLsizei, transpose: GLboolean, value: ptr GLdouble) {.importc.} + proc glVertexAttribI4i(index: GLuint, x: GLint, y: GLint, z: GLint, w: GLint) {.importc.} + proc glVertexAttrib1f(index: GLuint, x: GLfloat) {.importc.} + proc glUnmapBufferOES(target: GLenum): GLboolean {.importc.} + proc glVertexStream2ivATI(stream: GLenum, coords: ptr GLint) {.importc.} + proc glBeginOcclusionQueryNV(id: GLuint) {.importc.} + proc glVertex4sv(v: ptr GLshort) {.importc.} + proc glEnablei(target: GLenum, index: GLuint) {.importc.} + proc glUseProgramObjectARB(programObj: GLhandleArb) {.importc.} + proc glGetVertexAttribLdvEXT(index: GLuint, pname: GLenum, params: ptr GLdouble) {.importc.} + proc glUniform2d(location: GLint, x: GLdouble, y: GLdouble) {.importc.} + proc glMinmaxEXT(target: GLenum, internalformat: GLenum, sink: GLboolean) {.importc.} + proc glTexImage3D(target: GLenum, level: GLint, internalformat: GLint, width: GLsizei, height: GLsizei, depth: GLsizei, border: GLint, format: GLenum, `type`: GLenum, pixels: pointer) {.importc.} + proc glGenSymbolsEXT(datatype: GLenum, storagetype: GLenum, range: GLenum, components: GLuint): GLuint {.importc.} + proc glVertexAttribI4svEXT(index: GLuint, v: ptr GLshort) {.importc.} + proc glProgramEnvParameter4dvARB(target: GLenum, index: GLuint, params: ptr GLdouble) {.importc.} + proc glProgramUniformMatrix4dv(program: GLuint, location: GLint, count: GLsizei, transpose: GLboolean, value: ptr GLdouble) {.importc.} + proc glGetSamplerParameterfv(sampler: GLuint, pname: GLenum, params: ptr GLfloat) {.importc.} + proc glPopClientAttrib() {.importc.} + proc glHistogram(target: GLenum, width: GLsizei, internalformat: GLenum, sink: GLboolean) {.importc.} + proc glTexEnvfv(target: GLenum, pname: GLenum, params: ptr GLfloat) {.importc.} + proc glMultiTexCoord1dvARB(target: GLenum, v: ptr GLdouble) {.importc.} + proc glGetTexGenivOES(coord: GLenum, pname: GLenum, params: ptr GLint) {.importc.} + proc glUniform1ivARB(location: GLint, count: GLsizei, value: ptr GLint) {.importc.} + proc glTexCoord3fv(v: ptr GLfloat) {.importc.} + proc glVertex2xvOES(coords: ptr GLfixed) {.importc.} + proc glTexCoord4fVertex4fvSUN(tc: ptr GLfloat, v: ptr GLfloat) {.importc.} + proc glUniform2uiv(location: GLint, count: GLsizei, value: ptr GLuint) {.importc.} + proc glMultiTexEnvfvEXT(texunit: GLenum, target: GLenum, pname: GLenum, params: ptr GLfloat) {.importc.} + proc glGetTextureParameterIivEXT(texture: GLuint, target: GLenum, pname: GLenum, params: ptr GLint) {.importc.} + proc glMemoryBarrierEXT(barriers: GLbitfield) {.importc.} + proc glGetTexParameterPointervAPPLE(target: GLenum, pname: GLenum, params: ptr pointer) {.importc.} + proc glWindowPos2svARB(v: ptr GLshort) {.importc.} + proc glEndQuery(target: GLenum) {.importc.} + proc glBlitFramebufferEXT(srcX0: GLint, srcY0: GLint, srcX1: GLint, srcY1: GLint, dstX0: GLint, dstY0: GLint, dstX1: GLint, dstY1: GLint, mask: GLbitfield, filter: GLenum) {.importc.} + proc glProgramEnvParametersI4uivNV(target: GLenum, index: GLuint, count: GLsizei, params: ptr GLuint) {.importc.} + proc glGetActiveUniform(program: GLuint, index: GLuint, bufSize: GLsizei, length: ptr GLsizei, size: ptr GLint, `type`: ptr GLenum, name: cstring) {.importc.} + proc glGenAsyncMarkersSGIX(range: GLsizei): GLuint {.importc.} + proc glClipControlARB(origin: GLenum, depth: GLenum) {.importc.} + proc glDrawElementsInstancedEXT(mode: GLenum, count: GLsizei, `type`: GLenum, indices: pointer, primcount: GLsizei) {.importc.} + proc glGetFragmentMaterialivSGIX(face: GLenum, pname: GLenum, params: ptr GLint) {.importc.} + proc glSwizzleEXT(res: GLuint, `in`: GLuint, outX: GLenum, outY: GLenum, outZ: GLenum, outW: GLenum) {.importc.} + proc glMultiTexCoord1bOES(texture: GLenum, s: GLbyte) {.importc.} + proc glProgramParameters4dvNV(target: GLenum, index: GLuint, count: GLsizei, v: ptr GLdouble) {.importc.} + proc glWindowPos2s(x: GLshort, y: GLshort) {.importc.} + proc glBlendFuncSeparatei(buf: GLuint, srcRgb: GLenum, dstRgb: GLenum, srcAlpha: GLenum, dstAlpha: GLenum) {.importc.} + proc glMultiModeDrawElementsIBM(mode: ptr GLenum, count: ptr GLsizei, `type`: GLenum, indices: ptr pointer, primcount: GLsizei, modestride: GLint) {.importc.} + proc glNormal3x(nx: GLfixed, ny: GLfixed, nz: GLfixed) {.importc.} + proc glProgramUniform1fvEXT(program: GLuint, location: GLint, count: GLsizei, value: ptr GLfloat) {.importc.} + proc glTexCoord2hNV(s: GLhalfNv, t: GLhalfNv) {.importc.} + proc glViewportIndexedfv(index: GLuint, v: ptr GLfloat) {.importc.} + proc glDrawTexxOES(x: GLfixed, y: GLfixed, z: GLfixed, width: GLfixed, height: GLfixed) {.importc.} + proc glProgramParameter4dvNV(target: GLenum, index: GLuint, v: ptr GLdouble) {.importc.} + proc glDeleteBuffers(n: GLsizei, buffers: ptr GLuint) {.importc.} + proc glGetVertexArrayIntegervEXT(vaobj: GLuint, pname: GLenum, param: ptr GLint) {.importc.} + proc glBindFragDataLocationEXT(program: GLuint, color: GLuint, name: cstring) {.importc.} + proc glGenProgramsNV(n: GLsizei, programs: ptr GLuint) {.importc.} + proc glMultiTexCoord1i(target: GLenum, s: GLint) {.importc.} + proc glCompressedTexImage3DOES(target: GLenum, level: GLint, internalformat: GLenum, width: GLsizei, height: GLsizei, depth: GLsizei, border: GLint, imageSize: GLsizei, data: pointer) {.importc.} + proc glGetQueryivEXT(target: GLenum, pname: GLenum, params: ptr GLint) {.importc.} + proc glExtGetBufferPointervQCOM(target: GLenum, params: ptr pointer) {.importc.} + proc glVertex3iv(v: ptr GLint) {.importc.} + proc glVertexAttribL1dvEXT(index: GLuint, v: ptr GLdouble) {.importc.} + proc glValidateProgramPipeline(pipeline: GLuint) {.importc.} + proc glBindVertexArray(`array`: GLuint) {.importc.} + proc glUniform2uiEXT(location: GLint, v0: GLuint, v1: GLuint) {.importc.} + proc glUniform3i(location: GLint, v0: GLint, v1: GLint, v2: GLint) {.importc.} + proc glGetVertexAttribIuiv(index: GLuint, pname: GLenum, params: ptr GLuint) {.importc.} + proc glVertexArrayParameteriAPPLE(pname: GLenum, param: GLint) {.importc.} + proc glVertexAttribL2i64NV(index: GLuint, x: GLint64Ext, y: GLint64Ext) {.importc.} + proc glTexGenivOES(coord: GLenum, pname: GLenum, params: ptr GLint) {.importc.} + proc glIsFramebufferOES(framebuffer: GLuint): GLboolean {.importc.} + proc glColor4ubv(v: ptr GLubyte) {.importc.} + proc glDeleteNamedStringARB(namelen: GLint, name: cstring) {.importc.} + proc glCopyConvolutionFilter1DEXT(target: GLenum, internalformat: GLenum, x: GLint, y: GLint, width: GLsizei) {.importc.} + proc glBufferStorage(target: GLenum, size: GLsizeiptr, data: ptr pointer, flags: GLbitfield) {.importc.} + proc glDrawTexiOES(x: GLint, y: GLint, z: GLint, width: GLint, height: GLint) {.importc.} + proc glRasterPos3dv(v: ptr GLdouble) {.importc.} + proc glIndexMaterialEXT(face: GLenum, mode: GLenum) {.importc.} + proc glGetClipPlanex(plane: GLenum, equation: ptr GLfixed) {.importc.} + proc glIsVertexArrayOES(`array`: GLuint): GLboolean {.importc.} + proc glColorTableEXT(target: GLenum, internalFormat: GLenum, width: GLsizei, format: GLenum, `type`: GLenum, table: pointer) {.importc.} + proc glCompressedTexImage2D(target: GLenum, level: GLint, internalformat: GLenum, width: GLsizei, height: GLsizei, border: GLint, imageSize: GLsizei, data: pointer) {.importc.} + proc glLightx(light: GLenum, pname: GLenum, param: GLfixed) {.importc.} + proc glGetTexParameterfv(target: GLenum, pname: GLenum, params: ptr GLfloat) {.importc.} + proc glVertexAttrib4NsvARB(index: GLuint, v: ptr GLshort) {.importc.} + proc glInterleavedArrays(format: GLenum, stride: GLsizei, `pointer`: pointer) {.importc.} + proc glProgramLocalParameter4fARB(target: GLenum, index: GLuint, x: GLfloat, y: GLfloat, z: GLfloat, w: GLfloat) {.importc.} + proc glPopDebugGroupKHR() {.importc.} + proc glVDPAUUnregisterSurfaceNV(surface: GLvdpauSurfaceNv) {.importc.} + proc glTexCoord1s(s: GLshort) {.importc.} + proc glFramebufferTexture2DMultisampleIMG(target: GLenum, attachment: GLenum, textarget: GLenum, texture: GLuint, level: GLint, samples: GLsizei) {.importc.} + proc glShaderBinary(count: GLsizei, shaders: ptr GLuint, binaryformat: GLenum, binary: pointer, length: GLsizei) {.importc.} + proc glVertexAttrib2dv(index: GLuint, v: ptr GLdouble) {.importc.} + proc glUniformMatrix4dv(location: GLint, count: GLsizei, transpose: GLboolean, value: ptr GLdouble) {.importc.} + proc glWeightivARB(size: GLint, weights: ptr GLint) {.importc.} + proc glGetMultiTexParameterIivEXT(texunit: GLenum, target: GLenum, pname: GLenum, params: ptr GLint) {.importc.} + proc glCopyConvolutionFilter2DEXT(target: GLenum, internalformat: GLenum, x: GLint, y: GLint, width: GLsizei, height: GLsizei) {.importc.} + proc glSecondaryColor3hNV(red: GLhalfNv, green: GLhalfNv, blue: GLhalfNv) {.importc.} + proc glVertexAttrib1sv(index: GLuint, v: ptr GLshort) {.importc.} + proc glFrustumfOES(l: GLfloat, r: GLfloat, b: GLfloat, t: GLfloat, n: GLfloat, f: GLfloat) {.importc.} + proc glVertexStream2iATI(stream: GLenum, x: GLint, y: GLint) {.importc.} + proc glNormalStream3bATI(stream: GLenum, nx: GLbyte, ny: GLbyte, nz: GLbyte) {.importc.} + proc glVertexArrayTexCoordOffsetEXT(vaobj: GLuint, buffer: GLuint, size: GLint, `type`: GLenum, stride: GLsizei, offset: GLintptr) {.importc.} + proc glGetQueryiv(target: GLenum, pname: GLenum, params: ptr GLint) {.importc.} + proc glTransformFeedbackStreamAttribsNV(count: GLsizei, attribs: ptr GLint, nbuffers: GLsizei, bufstreams: ptr GLint, bufferMode: GLenum) {.importc.} + proc glTextureStorage3DEXT(texture: GLuint, target: GLenum, levels: GLsizei, internalformat: GLenum, width: GLsizei, height: GLsizei, depth: GLsizei) {.importc.} + proc glWindowPos3dvMESA(v: ptr GLdouble) {.importc.} + proc glUniform2uivEXT(location: GLint, count: GLsizei, value: ptr GLuint) {.importc.} + proc glTextureStorage2DEXT(texture: GLuint, target: GLenum, levels: GLsizei, internalformat: GLenum, width: GLsizei, height: GLsizei) {.importc.} + proc glVertexArrayMultiTexCoordOffsetEXT(vaobj: GLuint, buffer: GLuint, texunit: GLenum, size: GLint, `type`: GLenum, stride: GLsizei, offset: GLintptr) {.importc.} + proc glVertexStream1dvATI(stream: GLenum, coords: ptr GLdouble) {.importc.} + proc glCopyImageSubData(srcName: GLuint, srcTarget: GLenum, srcLevel: GLint, srcX: GLint, srcY: GLint, srcZ: GLint, dstName: GLuint, dstTarget: GLenum, dstLevel: GLint, dstX: GLint, dstY: GLint, dstZ: GLint, srcWidth: GLsizei, srcHeight: GLsizei, srcDepth: GLsizei) {.importc.} + proc glClearNamedBufferSubDataEXT(buffer: GLuint, internalformat: GLenum, format: GLenum, `type`: GLenum, offset: GLsizeiptr, size: GLsizeiptr, data: ptr pointer) {.importc.} + proc glBindBuffersRange(target: GLenum, first: GLuint, count: GLsizei, buffers: ptr GLuint, offsets: ptr GLintptr, sizes: ptr GLsizeiptr) {.importc.} + proc glGetVertexAttribIuivEXT(index: GLuint, pname: GLenum, params: ptr GLuint) {.importc.} + proc glLoadMatrixx(m: ptr GLfixed) {.importc.} + proc glTransformFeedbackVaryingsNV(program: GLuint, count: GLsizei, locations: ptr GLint, bufferMode: GLenum) {.importc.} + proc glUniform1i64vNV(location: GLint, count: GLsizei, value: ptr GLint64Ext) {.importc.} + proc glVertexArrayVertexAttribLFormatEXT(vaobj: GLuint, attribindex: GLuint, size: GLint, `type`: GLenum, relativeoffset: GLuint) {.importc.} + proc glClearBufferuiv(buffer: GLenum, drawbuffer: GLint, value: ptr GLuint) {.importc.} + proc glCombinerOutputNV(stage: GLenum, portion: GLenum, abOutput: GLenum, cdOutput: GLenum, sumOutput: GLenum, scale: GLenum, bias: GLenum, abDotProduct: GLboolean, cdDotProduct: GLboolean, muxSum: GLboolean) {.importc.} + proc glTexImage3DEXT(target: GLenum, level: GLint, internalformat: GLenum, width: GLsizei, height: GLsizei, depth: GLsizei, border: GLint, format: GLenum, `type`: GLenum, pixels: pointer) {.importc.} + proc glPixelTransformParameterivEXT(target: GLenum, pname: GLenum, params: ptr GLint) {.importc.} + proc glActiveStencilFaceEXT(face: GLenum) {.importc.} + proc glCreateShaderObjectARB(shaderType: GLenum): GLhandleArb {.importc.} + proc glGetTextureParameterivEXT(texture: GLuint, target: GLenum, pname: GLenum, params: ptr GLint) {.importc.} + proc glCopyTextureLevelsAPPLE(destinationTexture: GLuint, sourceTexture: GLuint, sourceBaseLevel: GLint, sourceLevelCount: GLsizei) {.importc.} + proc glVertexAttrib4Nuiv(index: GLuint, v: ptr GLuint) {.importc.} + proc glDrawPixels(width: GLsizei, height: GLsizei, format: GLenum, `type`: GLenum, pixels: pointer) {.importc.} + proc glWindowPos3dvARB(v: ptr GLdouble) {.importc.} + proc glProgramLocalParameterI4ivNV(target: GLenum, index: GLuint, params: ptr GLint) {.importc.} + proc glRasterPos4s(x: GLshort, y: GLshort, z: GLshort, w: GLshort) {.importc.} + proc glTexCoord2fVertex3fvSUN(tc: ptr GLfloat, v: ptr GLfloat) {.importc.} + proc glGetPathMetricsNV(metricQueryMask: GLbitfield, numPaths: GLsizei, pathNameType: GLenum, paths: pointer, pathBase: GLuint, stride: GLsizei, metrics: ptr GLfloat) {.importc.} + proc glMultiTexCoord4bOES(texture: GLenum, s: GLbyte, t: GLbyte, r: GLbyte, q: GLbyte) {.importc.} + proc glTextureBufferEXT(texture: GLuint, target: GLenum, internalformat: GLenum, buffer: GLuint) {.importc.} + proc glSecondaryColor3fv(v: ptr GLfloat) {.importc.} + proc glMultiTexCoord3fv(target: GLenum, v: ptr GLfloat) {.importc.} + proc glGetTexParameteriv(target: GLenum, pname: GLenum, params: ptr GLint) {.importc.} + proc glMap2xOES(target: GLenum, u1: GLfixed, u2: GLfixed, ustride: GLint, uorder: GLint, v1: GLfixed, v2: GLfixed, vstride: GLint, vorder: GLint, points: GLfixed) {.importc.} + proc glFlushVertexArrayRangeAPPLE(length: GLsizei, `pointer`: pointer) {.importc.} + proc glActiveTextureARB(texture: GLenum) {.importc.} + proc glGetVertexAttribLi64vNV(index: GLuint, pname: GLenum, params: ptr GLint64Ext) {.importc.} + proc glNormal3bv(v: ptr GLbyte) {.importc.} + proc glCreateSyncFromCLeventARB(context: ptr ClContext, event: ptr ClContext, flags: GLbitfield): GLsync {.importc.} + proc glRenderbufferStorageEXT(target: GLenum, internalformat: GLenum, width: GLsizei, height: GLsizei) {.importc.} + proc glGetCompressedTextureImageEXT(texture: GLuint, target: GLenum, lod: GLint, img: pointer) {.importc.} + proc glColorFragmentOp2ATI(op: GLenum, dst: GLuint, dstMask: GLuint, dstMod: GLuint, arg1: GLuint, arg1Rep: GLuint, arg1Mod: GLuint, arg2: GLuint, arg2Rep: GLuint, arg2Mod: GLuint) {.importc.} + proc glPixelMapusv(map: GLenum, mapsize: GLsizei, values: ptr GLushort) {.importc.} + proc glGlobalAlphaFactorsSUN(factor: GLshort) {.importc.} + proc glTexParameterxv(target: GLenum, pname: GLenum, params: ptr GLfixed) {.importc.} + proc glEvalCoord2xOES(u: GLfixed, v: GLfixed) {.importc.} + proc glIsList(list: GLuint): GLboolean {.importc.} + proc glVertexAttrib3d(index: GLuint, x: GLdouble, y: GLdouble, z: GLdouble) {.importc.} + proc glSpriteParameterfSGIX(pname: GLenum, param: GLfloat) {.importc.} + proc glPathGlyphRangeNV(firstPathName: GLuint, fontTarget: GLenum, fontName: pointer, fontStyle: GLbitfield, firstGlyph: GLuint, numGlyphs: GLsizei, handleMissingGlyphs: GLenum, pathParameterTemplate: GLuint, emScale: GLfloat) {.importc.} + proc glUniform3iv(location: GLint, count: GLsizei, value: ptr GLint) {.importc.} + proc glClearBufferfi(buffer: GLenum, drawbuffer: GLint, depth: GLfloat, stencil: GLint) {.importc.} + proc glWindowPos3sMESA(x: GLshort, y: GLshort, z: GLshort) {.importc.} + proc glGetMapParameterfvNV(target: GLenum, pname: GLenum, params: ptr GLfloat) {.importc.} + proc glBindFragmentShaderATI(id: GLuint) {.importc.} + proc glTexCoord4s(s: GLshort, t: GLshort, r: GLshort, q: GLshort) {.importc.} + proc glGetMultiTexGenfvEXT(texunit: GLenum, coord: GLenum, pname: GLenum, params: ptr GLfloat) {.importc.} + proc glColorMaterial(face: GLenum, mode: GLenum) {.importc.} + proc glVertexAttribs1svNV(index: GLuint, count: GLsizei, v: ptr GLshort) {.importc.} + proc glEnableVertexAttribAPPLE(index: GLuint, pname: GLenum) {.importc.} + proc glGetDoubleIndexedvEXT(target: GLenum, index: GLuint, data: ptr GLdouble) {.importc.} + proc glOrthof(l: GLfloat, r: GLfloat, b: GLfloat, t: GLfloat, n: GLfloat, f: GLfloat) {.importc.} + proc glVertexBlendEnvfATI(pname: GLenum, param: GLfloat) {.importc.} + proc glUniformMatrix2x4dv(location: GLint, count: GLsizei, transpose: GLboolean, value: ptr GLdouble) {.importc.} + proc glPrioritizeTexturesxOES(n: GLsizei, textures: ptr GLuint, priorities: ptr GLfixed) {.importc.} + proc glGetTextureSamplerHandleNV(texture: GLuint, sampler: GLuint): GLuint64 {.importc.} + proc glDeleteVertexArrays(n: GLsizei, arrays: ptr GLuint) {.importc.} + proc glMultiTexCoord1xOES(texture: GLenum, s: GLfixed) {.importc.} + proc glGlobalAlphaFactorusSUN(factor: GLushort) {.importc.} + proc glGetConvolutionParameterxvOES(target: GLenum, pname: GLenum, params: ptr GLfixed) {.importc.} + proc glProgramUniform4fEXT(program: GLuint, location: GLint, v0: GLfloat, v1: GLfloat, v2: GLfloat, v3: GLfloat) {.importc.} + proc glProgramUniformMatrix3x4dvEXT(program: GLuint, location: GLint, count: GLsizei, transpose: GLboolean, value: ptr GLdouble) {.importc.} + proc glBindVertexBuffer(bindingindex: GLuint, buffer: GLuint, offset: GLintptr, stride: GLsizei) {.importc.} + proc glGetHistogramParameteriv(target: GLenum, pname: GLenum, params: ptr GLint) {.importc.} + proc glGetShaderPrecisionFormat(shadertype: GLenum, precisiontype: GLenum, range: ptr GLint, precision: ptr GLint) {.importc.} + proc glTextureMaterialEXT(face: GLenum, mode: GLenum) {.importc.} + proc glEvalCoord2xvOES(coords: ptr GLfixed) {.importc.} + proc glWeightuivARB(size: GLint, weights: ptr GLuint) {.importc.} + proc glGetTextureLevelParameterfvEXT(texture: GLuint, target: GLenum, level: GLint, pname: GLenum, params: ptr GLfloat) {.importc.} + proc glVertexAttribP3uiv(index: GLuint, `type`: GLenum, normalized: GLboolean, value: ptr GLuint) {.importc.} + proc glProgramEnvParameterI4ivNV(target: GLenum, index: GLuint, params: ptr GLint) {.importc.} + proc glFogi(pname: GLenum, param: GLint) {.importc.} + proc glTexCoord1iv(v: ptr GLint) {.importc.} + proc glReplacementCodeuiColor4ubVertex3fvSUN(rc: ptr GLuint, c: ptr GLubyte, v: ptr GLfloat) {.importc.} + proc glProgramUniform1ui(program: GLuint, location: GLint, v0: GLuint) {.importc.} + proc glMultiTexCoord3d(target: GLenum, s: GLdouble, t: GLdouble, r: GLdouble) {.importc.} + proc glBeginVideoCaptureNV(video_capture_slot: GLuint) {.importc.} + proc glEvalCoord1f(u: GLfloat) {.importc.} + proc glMultiTexCoord1hvNV(target: GLenum, v: ptr GLhalfNv) {.importc.} + proc glSecondaryColor3sEXT(red: GLshort, green: GLshort, blue: GLshort) {.importc.} + proc glTextureImage3DEXT(texture: GLuint, target: GLenum, level: GLint, internalformat: GLint, width: GLsizei, height: GLsizei, depth: GLsizei, border: GLint, format: GLenum, `type`: GLenum, pixels: pointer) {.importc.} + proc glCopyTexImage2D(target: GLenum, level: GLint, internalformat: GLenum, x: GLint, y: GLint, width: GLsizei, height: GLsizei, border: GLint) {.importc.} + proc glFinishFenceAPPLE(fence: GLuint) {.importc.} + proc glVertexArrayRangeNV(length: GLsizei, `pointer`: pointer) {.importc.} + proc glLightModelf(pname: GLenum, param: GLfloat) {.importc.} + proc glVertexAttribL1ui64ARB(index: GLuint, x: GLuint64Ext) {.importc.} + proc glPolygonOffset(factor: GLfloat, units: GLfloat) {.importc.} + proc glRasterPos4xOES(x: GLfixed, y: GLfixed, z: GLfixed, w: GLfixed) {.importc.} + proc glVertexAttrib3dvNV(index: GLuint, v: ptr GLdouble) {.importc.} + proc glBeginQuery(target: GLenum, id: GLuint) {.importc.} + proc glWeightfvARB(size: GLint, weights: ptr GLfloat) {.importc.} + proc glGetUniformuiv(program: GLuint, location: GLint, params: ptr GLuint) {.importc.} + proc glIsTextureEXT(texture: GLuint): GLboolean {.importc.} + proc glGetClipPlanef(plane: GLenum, equation: ptr GLfloat) {.importc.} + proc glTexGenxOES(coord: GLenum, pname: GLenum, param: GLfixed) {.importc.} + proc glFramebufferTextureFaceEXT(target: GLenum, attachment: GLenum, texture: GLuint, level: GLint, face: GLenum) {.importc.} + proc glDisableClientState(`array`: GLenum) {.importc.} + proc glTexPageCommitmentARB(target: GLenum, level: GLint, xoffset: GLint, yoffset: GLint, zoffset: GLint, width: GLsizei, height: GLsizei, depth: GLsizei, resident: GLboolean) {.importc.} + proc glRasterPos4dv(v: ptr GLdouble) {.importc.} + proc glGetLightx(light: GLenum, pname: GLenum, params: ptr GLfixed) {.importc.} + proc glVertexAttrib1hvNV(index: GLuint, v: ptr GLhalfNv) {.importc.} + proc glMultiTexCoord2s(target: GLenum, s: GLshort, t: GLshort) {.importc.} + proc glProgramUniform2iv(program: GLuint, location: GLint, count: GLsizei, value: ptr GLint) {.importc.} + proc glGetListParameterivSGIX(list: GLuint, pname: GLenum, params: ptr GLint) {.importc.} + proc glColorFragmentOp1ATI(op: GLenum, dst: GLuint, dstMask: GLuint, dstMod: GLuint, arg1: GLuint, arg1Rep: GLuint, arg1Mod: GLuint) {.importc.} + proc glReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fSUN(rc: GLuint, s: GLfloat, t: GLfloat, r: GLfloat, g: GLfloat, b: GLfloat, a: GLfloat, nx: GLfloat, ny: GLfloat, nz: GLfloat, x: GLfloat, y: GLfloat, z: GLfloat) {.importc.} + proc glSampleMapATI(dst: GLuint, interp: GLuint, swizzle: GLenum) {.importc.} + proc glProgramUniform1d(program: GLuint, location: GLint, v0: GLdouble) {.importc.} + proc glBindAttribLocation(program: GLuint, index: GLuint, name: cstring) {.importc.} + proc glGetCombinerStageParameterfvNV(stage: GLenum, pname: GLenum, params: ptr GLfloat) {.importc.} + proc glTexSubImage4DSGIS(target: GLenum, level: GLint, xoffset: GLint, yoffset: GLint, zoffset: GLint, woffset: GLint, width: GLsizei, height: GLsizei, depth: GLsizei, size4d: GLsizei, format: GLenum, `type`: GLenum, pixels: pointer) {.importc.} + proc glGetMapAttribParameterfvNV(target: GLenum, index: GLuint, pname: GLenum, params: ptr GLfloat) {.importc.} + proc glNewObjectBufferATI(size: GLsizei, `pointer`: pointer, usage: GLenum): GLuint {.importc.} + proc glWindowPos4iMESA(x: GLint, y: GLint, z: GLint, w: GLint) {.importc.} + proc glNewList(list: GLuint, mode: GLenum) {.importc.} + proc glUniform1i64NV(location: GLint, x: GLint64Ext) {.importc.} + proc glTexCoordP3ui(`type`: GLenum, coords: GLuint) {.importc.} + proc glEndQueryEXT(target: GLenum) {.importc.} + proc glGetVertexAttribLdv(index: GLuint, pname: GLenum, params: ptr GLdouble) {.importc.} + proc glStencilMask(mask: GLuint) {.importc.} + proc glVertexAttrib4sv(index: GLuint, v: ptr GLshort) {.importc.} + proc glRectsv(v1: ptr GLshort, v2: ptr GLshort) {.importc.} + proc glGetVariantArrayObjectfvATI(id: GLuint, pname: GLenum, params: ptr GLfloat) {.importc.} + proc glTexCoord3hvNV(v: ptr GLhalfNv) {.importc.} + proc glGetUniformdv(program: GLuint, location: GLint, params: ptr GLdouble) {.importc.} + proc glSecondaryColor3fvEXT(v: ptr GLfloat) {.importc.} + proc glAlphaFuncx(fun: GLenum, `ref`: GLfixed) {.importc.} + proc glVertexAttribPointerNV(index: GLuint, fsize: GLint, `type`: GLenum, stride: GLsizei, `pointer`: pointer) {.importc.} + proc glColorTable(target: GLenum, internalformat: GLenum, width: GLsizei, format: GLenum, `type`: GLenum, table: pointer) {.importc.} + proc glProgramUniformMatrix2x3dv(program: GLuint, location: GLint, count: GLsizei, transpose: GLboolean, value: ptr GLdouble) {.importc.} + + ## # GL_ARB_direct_state_access + proc glCreateTransformFeedbacks(n: GLsizei; ids: ptr GLuint) {.importc.} + proc glTransformFeedbackBufferBase(xfb: GLuint; index: GLuint; buffer: GLuint) {.importc.} + proc glTransformFeedbackBufferRange(xfb: GLuint; index: GLuint; buffer: GLuint; offset: GLintptr; size: GLsizeiptr) {.importc.} + proc glGetTransformFeedbackiv(xfb: GLuint; pname: GLenum; param: ptr GLint) {.importc.} + proc glGetTransformFeedbacki_v(xfb: GLuint; pname: GLenum; index: GLuint; param: ptr GLint) {.importc.} + proc glGetTransformFeedbacki64_v(xfb: GLuint; pname: GLenum; index: GLuint; param: ptr GLint64) {.importc.} + ## # Buffer object functions + + proc glCreateBuffers(n: GLsizei; buffers: ptr GLuint) {.importc.} + proc glNamedBufferStorage(buffer: GLuint; size: GLsizeiptr; data: pointer; flags: GLbitfield) {.importc.} + proc glNamedBufferData(buffer: GLuint; size: GLsizeiptr; data: pointer; usage: GLenum) {.importc.} + proc glNamedBufferSubData(buffer: GLuint; offset: GLintptr; size: GLsizeiptr; data: pointer) {.importc.} + proc glCopyNamedBufferSubData(readBuffer: GLuint; writeBuffer: GLuint; readOffset: GLintptr; writeOffset: GLintptr; size: GLsizeiptr) {.importc.} + proc glClearNamedBufferData(buffer: GLuint; internalformat: GLenum; format: GLenum; `type`: GLenum; data: pointer) {.importc.} + proc glClearNamedBufferSubData(buffer: GLuint; internalformat: GLenum; offset: GLintptr; size: GLsizeiptr; format: GLenum; `type`: GLenum; data: pointer) {.importc.} + proc glMapNamedBuffer(buffer: GLuint; access: GLenum): pointer {.importc.} + proc glMapNamedBufferRange(buffer: GLuint; offset: GLintptr; length: GLsizeiptr; access: GLbitfield): pointer {.importc.} + proc glUnmapNamedBuffer(buffer: GLuint): GLboolean {.importc.} + proc glFlushMappedNamedBufferRange(buffer: GLuint; offset: GLintptr; length: GLsizeiptr) {.importc.} + proc glGetNamedBufferParameteriv(buffer: GLuint; pname: GLenum; params: ptr GLint) {.importc.} + proc glGetNamedBufferParameteri64v(buffer: GLuint; pname: GLenum; params: ptr GLint64) {.importc.} + proc glGetNamedBufferPointerv(buffer: GLuint; pname: GLenum; params: ptr pointer) {.importc.} + proc glGetNamedBufferSubData(buffer: GLuint; offset: GLintptr; size: GLsizeiptr; data: pointer) {.importc.} + ## # Framebuffer object functions + + proc glCreateFramebuffers(n: GLsizei; framebuffers: ptr GLuint) {.importc.} + proc glNamedFramebufferRenderbuffer(framebuffer: GLuint; attachment: GLenum; renderbuffertarget: GLenum; renderbuffer: GLuint) {.importc.} + proc glNamedFramebufferParameteri(framebuffer: GLuint; pname: GLenum; param: GLint) {.importc.} + proc glNamedFramebufferTexture(framebuffer: GLuint; attachment: GLenum; texture: GLuint; level: GLint) {.importc.} + proc glNamedFramebufferTextureLayer(framebuffer: GLuint; attachment: GLenum; texture: GLuint; level: GLint; layer: GLint) {.importc.} + proc glNamedFramebufferDrawBuffer(framebuffer: GLuint; mode: GLenum) {.importc.} + proc glNamedFramebufferDrawBuffers(framebuffer: GLuint; n: GLsizei; bufs: ptr GLenum) {.importc.} + proc glNamedFramebufferReadBuffer(framebuffer: GLuint; mode: GLenum) {.importc.} + proc glInvalidateNamedFramebufferData(framebuffer: GLuint; numAttachments: GLsizei; attachments: ptr GLenum) {.importc.} + proc glInvalidateNamedFramebufferSubData(framebuffer: GLuint; numAttachments: GLsizei; attachments: ptr GLenum; x: GLint; y: GLint; width: GLsizei; height: GLsizei) {.importc.} + proc glClearNamedFramebufferiv(framebuffer: GLuint; buffer: GLenum; drawbuffer: GLint; value: ptr GLint) {.importc.} + proc glClearNamedFramebufferuiv(framebuffer: GLuint; buffer: GLenum; drawbuffer: GLint; value: ptr GLuint) {.importc.} + proc glClearNamedFramebufferfv(framebuffer: GLuint; buffer: GLenum; drawbuffer: GLint; value: ptr cfloat) {.importc.} + proc glClearNamedFramebufferfi(framebuffer: GLuint; buffer: GLenum; drawbuffer: GLint; depth: cfloat; stencil: GLint) {.importc.} + proc glBlitNamedFramebuffer(readFramebuffer: GLuint; drawFramebuffer: GLuint; srcX0: GLint; srcY0: GLint; srcX1: GLint; srcY1: GLint; dstX0: GLint; dstY0: GLint; dstX1: GLint; dstY1: GLint; mask: GLbitfield; filter: GLenum) {.importc.} + proc glCheckNamedFramebufferStatus(framebuffer: GLuint; target: GLenum): GLenum {.importc.} + proc glGetNamedFramebufferParameteriv(framebuffer: GLuint; pname: GLenum; param: ptr GLint) {.importc.} + proc glGetNamedFramebufferAttachmentParameteriv(framebuffer: GLuint; attachment: GLenum; pname: GLenum; params: ptr GLint) {.importc.} + ## # Renderbuffer object functions + + proc glCreateRenderbuffers(n: GLsizei; renderbuffers: ptr GLuint) {.importc.} + proc glNamedRenderbufferStorage(renderbuffer: GLuint; internalformat: GLenum; width: GLsizei; height: GLsizei) {.importc.} + proc glNamedRenderbufferStorageMultisample(renderbuffer: GLuint; samples: GLsizei; internalformat: GLenum; width: GLsizei; height: GLsizei) {.importc.} + proc glGetNamedRenderbufferParameteriv(renderbuffer: GLuint; pname: GLenum; params: ptr GLint) {.importc.} + ## # Texture object functions + + proc glCreateTextures(target: GLenum; n: GLsizei; textures: ptr GLuint) {.importc.} + proc glTextureBuffer(texture: GLuint; internalformat: GLenum; buffer: GLuint) {.importc.} + proc glTextureBufferRange(texture: GLuint; internalformat: GLenum; buffer: GLuint; offset: GLintptr; size: GLsizeiptr) {.importc.} + proc glTextureStorage1D(texture: GLuint; levels: GLsizei; internalformat: GLenum; width: GLsizei) {.importc.} + proc glTextureStorage2D(texture: GLuint; levels: GLsizei; internalformat: GLenum; width: GLsizei; height: GLsizei) {.importc.} + proc glTextureStorage3D(texture: GLuint; levels: GLsizei; internalformat: GLenum; width: GLsizei; height: GLsizei; depth: GLsizei) {.importc.} + proc glTextureStorage2DMultisample(texture: GLuint; samples: GLsizei; internalformat: GLenum; width: GLsizei; height: GLsizei; fixedsamplelocations: GLboolean) {.importc.} + proc glTextureStorage3DMultisample(texture: GLuint; samples: GLsizei; internalformat: GLenum; width: GLsizei; height: GLsizei; depth: GLsizei; fixedsamplelocations: GLboolean) {.importc.} + proc glTextureSubImage1D(texture: GLuint; level: GLint; xoffset: GLint; width: GLsizei; format: GLenum; `type`: GLenum; pixels: pointer) {.importc.} + proc glTextureSubImage2D(texture: GLuint; level: GLint; xoffset: GLint; yoffset: GLint; width: GLsizei; height: GLsizei; format: GLenum; `type`: GLenum; pixels: pointer) {.importc.} + proc glTextureSubImage3D(texture: GLuint; level: GLint; xoffset: GLint; yoffset: GLint; zoffset: GLint; width: GLsizei; height: GLsizei; depth: GLsizei; format: GLenum; `type`: GLenum; pixels: pointer) {.importc.} + proc glCompressedTextureSubImage1D(texture: GLuint; level: GLint; xoffset: GLint; width: GLsizei; format: GLenum; imageSize: GLsizei; data: pointer) {.importc.} + proc glCompressedTextureSubImage2D(texture: GLuint; level: GLint; xoffset: GLint; yoffset: GLint; width: GLsizei; height: GLsizei; format: GLenum; imageSize: GLsizei; data: pointer) {.importc.} + proc glCompressedTextureSubImage3D(texture: GLuint; level: GLint; xoffset: GLint; yoffset: GLint; zoffset: GLint; width: GLsizei; height: GLsizei; depth: GLsizei; format: GLenum; imageSize: GLsizei; data: pointer) {.importc.} + proc glCopyTextureSubImage1D(texture: GLuint; level: GLint; xoffset: GLint; x: GLint; y: GLint; width: GLsizei) {.importc.} + proc glCopyTextureSubImage2D(texture: GLuint; level: GLint; xoffset: GLint; yoffset: GLint; x: GLint; y: GLint; width: GLsizei; height: GLsizei) {.importc.} + proc glCopyTextureSubImage3D(texture: GLuint; level: GLint; xoffset: GLint; yoffset: GLint; zoffset: GLint; x: GLint; y: GLint; width: GLsizei; height: GLsizei) {.importc.} + proc glTextureParameterf(texture: GLuint; pname: GLenum; param: cfloat) {.importc.} + proc glTextureParameterfv(texture: GLuint; pname: GLenum; param: ptr cfloat) {.importc.} + proc glTextureParameteri(texture: GLuint; pname: GLenum; param: GLint) {.importc.} + proc glTextureParameterIiv(texture: GLuint; pname: GLenum; params: ptr GLint) {.importc.} + proc glTextureParameterIuiv(texture: GLuint; pname: GLenum; params: ptr GLuint) {.importc.} + proc glTextureParameteriv(texture: GLuint; pname: GLenum; param: ptr GLint) {.importc.} + proc glGenerateTextureMipmap(texture: GLuint) {.importc.} + proc glBindTextureUnit(unit: GLuint; texture: GLuint) {.importc.} + proc glGetTextureImage(texture: GLuint; level: GLint; format: GLenum; `type`: GLenum; bufSize: GLsizei; pixels: pointer) {.importc.} + + proc glGetCompressedTextureImage(texture: GLuint; level: GLint; bufSize: GLsizei; pixels: pointer) {.importc.} + proc glGetTextureLevelParameterfv(texture: GLuint; level: GLint; pname: GLenum; params: ptr cfloat) {.importc.} + proc glGetTextureLevelParameteriv(texture: GLuint; level: GLint; pname: GLenum; params: ptr GLint) {.importc.} + proc glGetTextureParameterfv(texture: GLuint; pname: GLenum; params: ptr cfloat) {.importc.} + proc glGetTextureParameterIiv(texture: GLuint; pname: GLenum; params: ptr GLint) {.importc.} + proc glGetTextureParameterIuiv(texture: GLuint; pname: GLenum; params: ptr GLuint) {.importc.} + proc glGetTextureParameteriv(texture: GLuint; pname: GLenum; params: ptr GLint) {.importc.} + ## # Vertex Array object functions + + proc glCreateVertexArrays(n: GLsizei; arrays: ptr GLuint) {.importc.} + proc glDisableVertexArrayAttrib(vaobj: GLuint; index: GLuint) {.importc.} + proc glEnableVertexArrayAttrib(vaobj: GLuint; index: GLuint) {.importc.} + proc glVertexArrayElementBuffer(vaobj: GLuint; buffer: GLuint) {.importc.} + proc glVertexArrayVertexBuffer(vaobj: GLuint; bindingindex: GLuint; buffer: GLuint; offset: GLintptr; stride: GLsizei) {.importc.} + proc glVertexArrayVertexBuffers(vaobj: GLuint; first: GLuint; count: GLsizei; buffers: ptr GLuint; offsets: ptr GLintptr; strides: ptr GLsizei) {.importc.} + proc glVertexArrayAttribFormat(vaobj: GLuint; attribindex: GLuint; size: GLint; `type`: GLenum; normalized: GLboolean; relativeoffset: GLuint) {.importc.} + proc glVertexArrayAttribIFormat(vaobj: GLuint; attribindex: GLuint; size: GLint; `type`: GLenum; relativeoffset: GLuint) {.importc.} + proc glVertexArrayAttribLFormat(vaobj: GLuint; attribindex: GLuint; size: GLint; `type`: GLenum; relativeoffset: GLuint) {.importc.} + proc glVertexArrayAttribBinding(vaobj: GLuint; attribindex: GLuint; bindingindex: GLuint) {.importc.} + proc glVertexArrayBindingDivisor(vaobj: GLuint; bindingindex: GLuint; divisor: GLuint) {.importc.} + proc glGetVertexArrayiv(vaobj: GLuint; pname: GLenum; param: ptr GLint) {.importc.} + proc glGetVertexArrayIndexediv(vaobj: GLuint; index: GLuint; pname: GLenum; param: ptr GLint) {.importc.} + proc glGetVertexArrayIndexed64iv(vaobj: GLuint; index: GLuint; pname: GLenum; param: ptr GLint64) {.importc.} + ## # Sampler object functions + + proc glCreateSamplers(n: GLsizei; samplers: ptr GLuint) {.importc.} + ## # Program Pipeline object functions + + proc glCreateProgramPipelines(n: GLsizei; pipelines: ptr GLuint) {.importc.} + ## # Query object functions + + proc glCreateQueries(target: GLenum; n: GLsizei; ids: ptr GLuint) {.importc.} + proc glGetQueryBufferObjectiv(id: GLuint; buffer: GLuint; pname: GLenum; offset: GLintptr) {.importc.} + proc glGetQueryBufferObjectuiv(id: GLuint; buffer: GLuint; pname: GLenum; offset: GLintptr) {.importc.} + proc glGetQueryBufferObjecti64v(id: GLuint; buffer: GLuint; pname: GLenum; offset: GLintptr) {.importc.} + proc glGetQueryBufferObjectui64v(id: GLuint; buffer: GLuint; pname: GLenum; offset: GLintptr) {.importc.} + +{.pop.} # stdcall, hint[XDeclaredButNotUsed]: off, warning[SmallLshouldNotBeUsed]: off. + +const + cGL_UNSIGNED_BYTE* = 0x1401.GLenum + cGL_UNSIGNED_SHORT* = 0x1403.GLenum + + GL_2X_BIT_ATI* = 0x00000001.GLbitfield + GL_MODELVIEW6_ARB* = 0x8726.GLenum + GL_CULL_FACE_MODE* = 0x0B45.GLenum + GL_TEXTURE_MAG_FILTER* = 0x2800.GLenum + GL_TRANSFORM_FEEDBACK_VARYINGS_EXT* = 0x8C83.GLenum + GL_PATH_JOIN_STYLE_NV* = 0x9079.GLenum + GL_FEEDBACK_BUFFER_SIZE* = 0x0DF1.GLenum + GL_FRAGMENT_LIGHT0_SGIX* = 0x840C.GLenum + GL_DRAW_BUFFER7_ARB* = 0x882C.GLenum + GL_POINT_SPRITE_OES* = 0x8861.GLenum + GL_INT_SAMPLER_RENDERBUFFER_NV* = 0x8E57.GLenum + GL_POST_CONVOLUTION_COLOR_TABLE_SGI* = 0x80D1.GLenum + GL_ZOOM_X* = 0x0D16.GLenum + GL_DRAW_FRAMEBUFFER_NV* = 0x8CA9.GLenum + GL_RGB_FLOAT16_ATI* = 0x881B.GLenum + GL_NUM_COMPRESSED_TEXTURE_FORMATS* = 0x86A2.GLenum + GL_LINE_STRIP* = 0x0003.GLenum + GL_PROXY_POST_COLOR_MATRIX_COLOR_TABLE_SGI* = 0x80D5.GLenum + GL_CURRENT_TIME_NV* = 0x8E28.GLenum + GL_FRAMEBUFFER_UNSUPPORTED* = 0x8CDD.GLenum + GL_PIXEL_TEX_GEN_Q_CEILING_SGIX* = 0x8184.GLenum + GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH_EXT* = 0x8C76.GLenum + GL_MAP_PERSISTENT_BIT* = 0x0040.GLbitfield + GL_IMAGE_2D_MULTISAMPLE_ARRAY_EXT* = 0x9056.GLenum + GL_CON_16_ATI* = 0x8951.GLenum + GL_DEPTH_BUFFER_BIT1_QCOM* = 0x00000200.GLbitfield + GL_TEXTURE30_ARB* = 0x84DE.GLenum + GL_SAMPLER_BUFFER* = 0x8DC2.GLenum + GL_MAX_COLOR_TEXTURE_SAMPLES* = 0x910E.GLenum + GL_DEPTH_STENCIL* = 0x84F9.GLenum + GL_C4F_N3F_V3F* = 0x2A26.GLenum + GL_ZOOM_Y* = 0x0D17.GLenum + GL_RGB10* = 0x8052.GLenum + GL_PRESERVE_ATI* = 0x8762.GLenum + GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS_ARB* = 0x8B4D.GLenum + GL_COLOR_ATTACHMENT12_NV* = 0x8CEC.GLenum + GL_GREEN_MAX_CLAMP_INGR* = 0x8565.GLenum + GL_CURRENT_VERTEX_ATTRIB* = 0x8626.GLenum + GL_TEXTURE_SHARED_SIZE* = 0x8C3F.GLenum + GL_NORMAL_ARRAY_TYPE* = 0x807E.GLenum + GL_DYNAMIC_READ* = 0x88E9.GLenum + GL_ALPHA4_EXT* = 0x803B.GLenum + GL_REPLACEMENT_CODE_ARRAY_SUN* = 0x85C0.GLenum + GL_OFFSET_PROJECTIVE_TEXTURE_RECTANGLE_NV* = 0x8852.GLenum + GL_MAX_VERTEX_ATTRIBS_ARB* = 0x8869.GLenum + GL_VIDEO_COLOR_CONVERSION_MIN_NV* = 0x902B.GLenum + GL_SOURCE3_RGB_NV* = 0x8583.GLenum + GL_ALPHA* = 0x1906.GLenum + GL_OUTPUT_TEXTURE_COORD16_EXT* = 0x87AD.GLenum + GL_BLEND_EQUATION_EXT* = 0x8009.GLenum + GL_BIAS_BIT_ATI* = 0x00000008.GLbitfield + GL_BLEND_EQUATION_RGB* = 0x8009.GLenum + GL_SHADER_BINARY_DMP* = 0x9250.GLenum + GL_IMAGE_FORMAT_COMPATIBILITY_BY_SIZE* = 0x90C8.GLenum + GL_Z4Y12Z4CB12Z4CR12_444_NV* = 0x9037.GLenum + GL_READ_PIXELS_TYPE* = 0x828E.GLenum + GL_CONVOLUTION_HINT_SGIX* = 0x8316.GLenum + GL_TRANSPOSE_AFFINE_3D_NV* = 0x9098.GLenum + GL_PIXEL_MAP_B_TO_B* = 0x0C78.GLenum + GL_VERTEX_BLEND_ARB* = 0x86A7.GLenum + GL_LIGHT2* = 0x4002.GLenum + cGL_BYTE* = 0x1400.GLenum + GL_MAX_TESS_CONTROL_ATOMIC_COUNTERS* = 0x92D3.GLenum + GL_DOMAIN* = 0x0A02.GLenum + GL_PROGRAM_NATIVE_TEMPORARIES_ARB* = 0x88A6.GLenum + GL_RELATIVE_CUBIC_CURVE_TO_NV* = 0x0D.GLenum + GL_TEXTURE_DEPTH_TYPE_ARB* = 0x8C16.GLenum + GL_STENCIL_BACK_PASS_DEPTH_PASS* = 0x8803.GLenum + GL_MAX_FRAGMENT_PROGRAM_LOCAL_PARAMETERS_NV* = 0x8868.GLenum + GL_ATTRIB_STACK_DEPTH* = 0x0BB0.GLenum + GL_DEPTH_COMPONENT16_ARB* = 0x81A5.GLenum + GL_TESSELLATION_MODE_AMD* = 0x9004.GLenum + GL_UNSIGNED_INT8_VEC3_NV* = 0x8FEE.GLenum + GL_DOUBLE_VEC4* = 0x8FFE.GLenum + GL_MAX_TESS_CONTROL_TOTAL_OUTPUT_COMPONENTS* = 0x8E85.GLenum + GL_TEXTURE_GREEN_TYPE_ARB* = 0x8C11.GLenum + GL_PIXEL_PACK_BUFFER* = 0x88EB.GLenum + GL_VERTEX_WEIGHT_ARRAY_EXT* = 0x850C.GLenum + GL_HALF_FLOAT* = 0x140B.GLenum + GL_REG_0_ATI* = 0x8921.GLenum + GL_DEPTH_BUFFER_BIT4_QCOM* = 0x00001000.GLbitfield + GL_UNSIGNED_INT_5_9_9_9_REV_EXT* = 0x8C3E.GLenum + GL_DEPTH_COMPONENT16_SGIX* = 0x81A5.GLenum + GL_COMPRESSED_RGBA_ASTC_8x5_KHR* = 0x93B5.GLenum + GL_EDGE_FLAG_ARRAY_LENGTH_NV* = 0x8F30.GLenum + GL_CON_17_ATI* = 0x8952.GLenum + GL_PARAMETER_BUFFER_ARB* = 0x80EE.GLenum + GL_COLOR_ATTACHMENT6_EXT* = 0x8CE6.GLenum + GL_INDEX_ARRAY_EXT* = 0x8077.GLenum + GL_ALPHA_SCALE* = 0x0D1C.GLenum + GL_LINE_QUALITY_HINT_SGIX* = 0x835B.GLenum + GL_SLUMINANCE8* = 0x8C47.GLenum + GL_DEBUG_OUTPUT_KHR* = 0x92E0.GLenum + GL_TEXTURE_LIGHTING_MODE_HP* = 0x8167.GLenum + GL_SPOT_DIRECTION* = 0x1204.GLenum + GL_V3F* = 0x2A21.GLenum + GL_ALPHA16_EXT* = 0x803E.GLenum + GL_DRAW_BUFFER15_NV* = 0x8834.GLenum + GL_MIN_PROGRAM_TEXEL_OFFSET_EXT* = 0x8904.GLenum + GL_ACTIVE_VARYING_MAX_LENGTH_NV* = 0x8C82.GLenum + GL_COLOR_ATTACHMENT10* = 0x8CEA.GLenum + GL_COLOR_ARRAY_LIST_STRIDE_IBM* = 103082.GLenum + GL_TEXTURE_TARGET_QCOM* = 0x8BDA.GLenum + GL_DRAW_BUFFER12_ARB* = 0x8831.GLenum + GL_SAMPLE_MASK* = 0x8E51.GLenum + GL_TEXTURE_FORMAT_QCOM* = 0x8BD6.GLenum + GL_TEXTURE_COMPONENTS* = 0x1003.GLenum + GL_PROGRAM_PIPELINE_BINDING* = 0x825A.GLenum + GL_HIGH_INT* = 0x8DF5.GLenum + GL_MAP_INVALIDATE_BUFFER_BIT* = 0x0008.GLbitfield + GL_LAYOUT_LINEAR_CPU_CACHED_INTEL* = 2.GLenum + GL_TEXTURE_DS_SIZE_NV* = 0x871D.GLenum + GL_HALF_FLOAT_NV* = 0x140B.GLenum + GL_PROXY_POST_COLOR_MATRIX_COLOR_TABLE* = 0x80D5.GLenum + GL_UNIFORM_BLOCK_REFERENCED_BY_GEOMETRY_SHADER* = 0x8A45.GLenum + GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR* = 0x93DB.GLenum + GL_REG_18_ATI* = 0x8933.GLenum + GL_MAX_COMBINED_COMPUTE_UNIFORM_COMPONENTS* = 0x8266.GLenum + GL_UNPACK_FLIP_Y_WEBGL* = 0x9240.GLenum + GL_POLYGON_STIPPLE_BIT* = 0x00000010.GLbitfield + GL_MULTISAMPLE_BUFFER_BIT6_QCOM* = 0x40000000.GLbitfield + GL_ONE_MINUS_SRC_ALPHA* = 0x0303.GLenum + GL_RASTERIZER_DISCARD_EXT* = 0x8C89.GLenum + GL_BGRA_INTEGER* = 0x8D9B.GLenum + GL_MAX_TESS_EVALUATION_ATOMIC_COUNTER_BUFFERS* = 0x92CE.GLenum + GL_MODELVIEW1_EXT* = 0x850A.GLenum + GL_VERTEX_ELEMENT_SWIZZLE_AMD* = 0x91A4.GLenum + GL_MAP1_GRID_SEGMENTS* = 0x0DD1.GLenum + GL_PATH_ERROR_POSITION_NV* = 0x90AB.GLenum + GL_FOG_COORDINATE_ARRAY_EXT* = 0x8457.GLenum + GL_NUM_INPUT_INTERPOLATOR_COMPONENTS_ATI* = 0x8973.GLenum + GL_MAX_PROGRAM_TEX_INDIRECTIONS_ARB* = 0x880D.GLenum + GL_PATH_GEN_COLOR_FORMAT_NV* = 0x90B2.GLenum + GL_BUFFER_VARIABLE* = 0x92E5.GLenum + GL_PROXY_TEXTURE_CUBE_MAP_ARB* = 0x851B.GLenum + GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_ARB* = 0x8E8D.GLenum + GL_TEXT_FRAGMENT_SHADER_ATI* = 0x8200.GLenum + GL_ALPHA_MAX_SGIX* = 0x8321.GLenum + GL_UNPACK_ALIGNMENT* = 0x0CF5.GLenum + GL_POST_COLOR_MATRIX_RED_SCALE* = 0x80B4.GLenum + GL_CIRCULAR_CW_ARC_TO_NV* = 0xFA.GLenum + GL_MAX_SAMPLES_APPLE* = 0x8D57.GLenum + GL_4PASS_3_SGIS* = 0x80A7.GLenum + GL_SAMPLER_3D_OES* = 0x8B5F.GLenum + GL_UNSIGNED_INT16_VEC2_NV* = 0x8FF1.GLenum + GL_UNSIGNED_INT_SAMPLER_1D_ARRAY* = 0x8DD6.GLenum + GL_REG_8_ATI* = 0x8929.GLenum + GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT* = 0x8366.GLenum + GL_QUERY_RESULT_AVAILABLE_EXT* = 0x8867.GLenum + GL_INTENSITY8_EXT* = 0x804B.GLenum + GL_OUTPUT_TEXTURE_COORD9_EXT* = 0x87A6.GLenum + GL_TEXTURE_BINDING_RECTANGLE_NV* = 0x84F6.GLenum + GL_OFFSET_PROJECTIVE_TEXTURE_RECTANGLE_SCALE_NV* = 0x8853.GLenum + GL_IMAGE_FORMAT_COMPATIBILITY_TYPE* = 0x90C7.GLenum + GL_WRITE_ONLY* = 0x88B9.GLenum + GL_SAMPLER_1D_SHADOW* = 0x8B61.GLenum + GL_DISPATCH_INDIRECT_BUFFER_BINDING* = 0x90EF.GLenum + GL_VERTEX_PROGRAM_BINDING_NV* = 0x864A.GLenum + GL_RGB8_EXT* = 0x8051.GLenum + GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR* = 0x93D7.GLenum + GL_CON_5_ATI* = 0x8946.GLenum + GL_DUAL_INTENSITY8_SGIS* = 0x8119.GLenum + GL_MAX_SAMPLES_EXT* = 0x8D57.GLenum + GL_VERTEX_ARRAY_POINTER_EXT* = 0x808E.GLenum + GL_COMBINE_EXT* = 0x8570.GLenum + GL_MULTISAMPLE_BUFFER_BIT1_QCOM* = 0x02000000.GLbitfield + GL_MAGNITUDE_SCALE_NV* = 0x8712.GLenum + GL_SYNC_CONDITION_APPLE* = 0x9113.GLenum + GL_RGBA_S3TC* = 0x83A2.GLenum + GL_LINE_STIPPLE_REPEAT* = 0x0B26.GLenum + GL_TEXTURE_COMPRESSION_HINT* = 0x84EF.GLenum + GL_TEXTURE_COMPARE_MODE* = 0x884C.GLenum + GL_RGBA_FLOAT_MODE_ATI* = 0x8820.GLenum + GL_OPERAND0_RGB* = 0x8590.GLenum + GL_SIGNED_RGB8_UNSIGNED_ALPHA8_NV* = 0x870D.GLenum + GL_POST_COLOR_MATRIX_GREEN_SCALE_SGI* = 0x80B5.GLenum + GL_Z6Y10Z6CB10Z6Y10Z6CR10_422_NV* = 0x9033.GLenum + GL_UNPACK_ROW_LENGTH* = 0x0CF2.GLenum + GL_DOUBLE_MAT2_EXT* = 0x8F46.GLenum + GL_TEXTURE_GEQUAL_R_SGIX* = 0x819D.GLenum + GL_UNSIGNED_INT_8_24_REV_MESA* = 0x8752.GLenum + GL_DSDT8_NV* = 0x8709.GLenum + GL_RESAMPLE_DECIMATE_SGIX* = 0x8430.GLenum + GL_DEBUG_SOURCE_OTHER_KHR* = 0x824B.GLenum + GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_ARB* = 0x8DA8.GLenum + GL_MAX_VERTEX_UNITS_OES* = 0x86A4.GLenum + GL_ISOLINES* = 0x8E7A.GLenum + GL_INCR_WRAP* = 0x8507.GLenum + GL_BUFFER_MAP_POINTER* = 0x88BD.GLenum + GL_INT_SAMPLER_CUBE_MAP_ARRAY* = 0x900E.GLenum + GL_UNSIGNED_INT_VEC2* = 0x8DC6.GLenum + GL_RENDERBUFFER_HEIGHT_OES* = 0x8D43.GLenum + GL_COMPRESSED_RGBA_ASTC_10x10_KHR* = 0x93BB.GLenum + GL_PIXEL_TEX_GEN_ALPHA_MS_SGIX* = 0x818A.GLenum + GL_LINEAR_SHARPEN_COLOR_SGIS* = 0x80AF.GLenum + GL_COLOR_ATTACHMENT5_EXT* = 0x8CE5.GLenum + GL_VERTEX_ATTRIB_ARRAY9_NV* = 0x8659.GLenum + GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING* = 0x889D.GLenum + GL_BLEND_DST_RGB* = 0x80C8.GLenum + GL_VERTEX_ARRAY_EXT* = 0x8074.GLenum + GL_VERTEX_ARRAY_RANGE_POINTER_NV* = 0x8521.GLenum + GL_DEBUG_SEVERITY_MEDIUM_ARB* = 0x9147.GLenum + GL_OPERAND0_ALPHA* = 0x8598.GLenum + GL_TEXTURE_BINDING_CUBE_MAP* = 0x8514.GLenum + GL_ADD_ATI* = 0x8963.GLenum + GL_AUX1* = 0x040A.GLenum + GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING_EXT* = 0x8210.GLenum + GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS* = 0x8CD9.GLenum + GL_MINUS_NV* = 0x929F.GLenum + GL_RGB4* = 0x804F.GLenum + GL_COMPRESSED_RGBA_ASTC_12x12_KHR* = 0x93BD.GLenum + GL_MAX_GEOMETRY_OUTPUT_VERTICES* = 0x8DE0.GLenum + GL_SURFACE_STATE_NV* = 0x86EB.GLenum + GL_COLOR_MATERIAL_FACE* = 0x0B55.GLenum + GL_TEXTURE18_ARB* = 0x84D2.GLenum + GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2_OES* = 0x9277.GLenum + GL_LOWER_LEFT* = 0x8CA1.GLenum + GL_DRAW_BUFFER8_ATI* = 0x882D.GLenum + GL_TEXTURE_CONSTANT_DATA_SUNX* = 0x81D6.GLenum + GL_SAMPLER_1D* = 0x8B5D.GLenum + GL_POLYGON_OFFSET_EXT* = 0x8037.GLenum + GL_EQUIV* = 0x1509.GLenum + GL_QUERY_BUFFER_BINDING* = 0x9193.GLenum + GL_COMBINE_ARB* = 0x8570.GLenum + GL_MATRIX0_NV* = 0x8630.GLenum + GL_CLAMP_TO_BORDER_SGIS* = 0x812D.GLint + GL_INTENSITY8UI_EXT* = 0x8D7F.GLenum + GL_TRACK_MATRIX_TRANSFORM_NV* = 0x8649.GLenum + GL_SURFACE_MAPPED_NV* = 0x8700.GLenum + GL_INT_VEC3_ARB* = 0x8B54.GLenum + GL_IMAGE_TRANSFORM_2D_HP* = 0x8161.GLenum + GL_PROGRAM_BINARY_RETRIEVABLE_HINT* = 0x8257.GLenum + GL_DRAW_BUFFER8_EXT* = 0x882D.GLenum + GL_DEPTH_STENCIL_EXT* = 0x84F9.GLenum + GL_CONTEXT_PROFILE_MASK* = 0x9126.GLenum + GL_MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB* = 0x88A3.GLenum + GL_MATRIX5_ARB* = 0x88C5.GLenum + GL_FRAMEBUFFER_UNDEFINED_OES* = 0x8219.GLenum + GL_UNPACK_CMYK_HINT_EXT* = 0x800F.GLenum + GL_UNSIGNED_NORMALIZED_EXT* = 0x8C17.GLenum + GL_ONE* = 1.GLenum + GL_EDGE_FLAG_ARRAY_BUFFER_BINDING_ARB* = 0x889B.GLenum + GL_TRANSPOSE_PROJECTION_MATRIX* = 0x84E4.GLenum + GL_MAX_PROGRAM_TOTAL_OUTPUT_COMPONENTS_NV* = 0x8C28.GLenum + GL_CLIP_DISTANCE3* = 0x3003.GLenum + GL_4PASS_1_SGIS* = 0x80A5.GLenum + GL_MAX_FRAGMENT_LIGHTS_SGIX* = 0x8404.GLenum + GL_TEXTURE_3D_OES* = 0x806F.GLenum + GL_TEXTURE0* = 0x84C0.GLenum + GL_INT_IMAGE_CUBE_EXT* = 0x905B.GLenum + GL_INNOCENT_CONTEXT_RESET_ARB* = 0x8254.GLenum + GL_INDEX_ARRAY_TYPE_EXT* = 0x8085.GLenum + GL_SAMPLER_OBJECT_AMD* = 0x9155.GLenum + GL_INDEX_ARRAY_BUFFER_BINDING_ARB* = 0x8899.GLenum + GL_RENDERBUFFER_DEPTH_SIZE_OES* = 0x8D54.GLenum + GL_MAX_SAMPLE_MASK_WORDS* = 0x8E59.GLenum + GL_COMBINER2_NV* = 0x8552.GLenum + GL_COLOR_ARRAY_BUFFER_BINDING_ARB* = 0x8898.GLenum + GL_VERTEX_ATTRIB_ARRAY_NORMALIZED_ARB* = 0x886A.GLenum + GL_STREAM_DRAW* = 0x88E0.GLenum + GL_RGB8I* = 0x8D8F.GLenum + GL_BLEND_COLOR_EXT* = 0x8005.GLenum + GL_MAX_VARYING_VECTORS* = 0x8DFC.GLenum + GL_COPY_WRITE_BUFFER_BINDING* = 0x8F37.GLenum + GL_FIXED_ONLY_ARB* = 0x891D.GLenum + GL_INT_VEC4* = 0x8B55.GLenum + GL_PROGRAM_PIPELINE_BINDING_EXT* = 0x825A.GLenum + GL_UNSIGNED_NORMALIZED_ARB* = 0x8C17.GLenum + GL_NUM_INSTRUCTIONS_PER_PASS_ATI* = 0x8971.GLenum + GL_PIXEL_MODE_BIT* = 0x00000020.GLbitfield + GL_COMPRESSED_RED_RGTC1* = 0x8DBB.GLenum + GL_SHADER_IMAGE_ACCESS_BARRIER_BIT_EXT* = 0x00000020.GLbitfield + GL_VARIANT_DATATYPE_EXT* = 0x87E5.GLenum + GL_DARKEN_NV* = 0x9297.GLenum + GL_POINT_SIZE_MAX_SGIS* = 0x8127.GLenum + GL_OBJECT_ATTACHED_OBJECTS_ARB* = 0x8B85.GLenum + GL_SLUMINANCE_ALPHA_EXT* = 0x8C44.GLenum + GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY* = 0x906A.GLenum + GL_EDGE_FLAG_ARRAY* = 0x8079.GLenum + GL_LINEAR_CLIPMAP_NEAREST_SGIX* = 0x844F.GLenum + GL_LUMINANCE_ALPHA32F_EXT* = 0x8819.GLenum + GL_NORMAL_BIT_PGI* = 0x08000000.GLbitfield + GL_SECONDARY_COLOR_ARRAY* = 0x845E.GLenum + GL_CLIP_PLANE1_IMG* = 0x3001.GLenum + GL_REG_19_ATI* = 0x8934.GLenum + GL_PIXEL_PACK_BUFFER_BINDING* = 0x88ED.GLenum + GL_PIXEL_GROUP_COLOR_SGIS* = 0x8356.GLenum + GL_SELECTION_BUFFER_SIZE* = 0x0DF4.GLenum + GL_SRC_OUT_NV* = 0x928C.GLenum + GL_TEXTURE7* = 0x84C7.GLenum + GL_COMPARE_R_TO_TEXTURE* = 0x884E.GLenum + GL_DUDV_ATI* = 0x8779.GLenum + GL_TEXTURE_BASE_LEVEL* = 0x813C.GLenum + GL_PN_TRIANGLES_POINT_MODE_LINEAR_ATI* = 0x87F5.GLenum + GL_LAYOUT_LINEAR_INTEL* = 1.GLenum + GL_DEPTH_BUFFER_BIT2_QCOM* = 0x00000400.GLbitfield + GL_MAX_TESS_EVALUATION_UNIFORM_BLOCKS* = 0x8E8A.GLenum + GL_LIGHT3* = 0x4003.GLenum + GL_ALPHA_MAX_CLAMP_INGR* = 0x8567.GLenum + GL_RG_INTEGER* = 0x8228.GLenum + GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL* = 0x8CD2.GLenum + GL_TEXTURE_STACK_DEPTH* = 0x0BA5.GLenum + GL_ALREADY_SIGNALED* = 0x911A.GLenum + GL_TEXTURE_CUBE_MAP_OES* = 0x8513.GLenum + GL_N3F_V3F* = 0x2A25.GLenum + GL_SUBTRACT_ARB* = 0x84E7.GLenum + GL_ELEMENT_ARRAY_LENGTH_NV* = 0x8F33.GLenum + GL_NORMAL_ARRAY_EXT* = 0x8075.GLenum + GL_POLYGON_OFFSET_FACTOR_EXT* = 0x8038.GLenum + GL_EIGHTH_BIT_ATI* = 0x00000020.GLbitfield + GL_UNSIGNED_INT_SAMPLER_2D_RECT* = 0x8DD5.GLenum + GL_OBJECT_ACTIVE_ATTRIBUTES_ARB* = 0x8B89.GLenum + GL_MAX_VERTEX_VARYING_COMPONENTS_ARB* = 0x8DDE.GLenum + GL_TEXTURE_COORD_ARRAY_STRIDE_EXT* = 0x808A.GLenum + GL_4_BYTES* = 0x1409.GLenum + GL_SAMPLE_SHADING* = 0x8C36.GLenum + GL_FOG_MODE* = 0x0B65.GLenum + GL_CON_7_ATI* = 0x8948.GLenum + GL_DRAW_FRAMEBUFFER* = 0x8CA9.GLenum + GL_TEXTURE_MEMORY_LAYOUT_INTEL* = 0x83FF.GLenum + GL_RGB32I_EXT* = 0x8D83.GLenum + GL_VERTEX_ARRAY_STRIDE* = 0x807C.GLenum + GL_COLOR_ATTACHMENT3_NV* = 0x8CE3.GLenum + GL_NORMAL_ARRAY_PARALLEL_POINTERS_INTEL* = 0x83F6.GLenum + GL_CONTRAST_NV* = 0x92A1.GLenum + GL_RGBA32F* = 0x8814.GLenum + GL_YCBAYCR8A_4224_NV* = 0x9032.GLenum + GL_MAX_VERTEX_ATTRIB_RELATIVE_OFFSET* = 0x82D9.GLenum + GL_TEXTURE22* = 0x84D6.GLenum + GL_TEXTURE_3D* = 0x806F.GLenum + GL_STENCIL_PASS_DEPTH_FAIL* = 0x0B95.GLenum + GL_PROXY_HISTOGRAM_EXT* = 0x8025.GLenum + GL_ATOMIC_COUNTER_BUFFER_ACTIVE_ATOMIC_COUNTERS* = 0x92C5.GLenum + GL_MAX_ATOMIC_COUNTER_BUFFER_SIZE* = 0x92D8.GLenum + GL_FOG_COORD_ARRAY_TYPE* = 0x8454.GLenum + GL_MAP2_VERTEX_4* = 0x0DB8.GLenum + GL_PACK_COMPRESSED_SIZE_SGIX* = 0x831C.GLenum + GL_POST_TEXTURE_FILTER_SCALE_RANGE_SGIX* = 0x817C.GLenum + GL_ITALIC_BIT_NV* = 0x02.GLbitfield + GL_COMPRESSED_LUMINANCE_ALPHA* = 0x84EB.GLenum + GL_COLOR_TABLE_SCALE_SGI* = 0x80D6.GLenum + GL_DOUBLE_MAT2x4_EXT* = 0x8F4A.GLenum + GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE* = 0x8215.GLenum + GL_MATRIX11_ARB* = 0x88CB.GLenum + GL_REG_5_ATI* = 0x8926.GLenum + GL_RGBA2_EXT* = 0x8055.GLenum + GL_DISCARD_NV* = 0x8530.GLenum + GL_TEXTURE7_ARB* = 0x84C7.GLenum + GL_LUMINANCE32UI_EXT* = 0x8D74.GLenum + GL_ACTIVE_UNIFORM_BLOCKS* = 0x8A36.GLenum + GL_UNSIGNED_INT16_VEC4_NV* = 0x8FF3.GLenum + GL_VERTEX_ATTRIB_ARRAY5_NV* = 0x8655.GLenum + GL_DOUBLE_MAT3x4* = 0x8F4C.GLenum + GL_BOOL* = 0x8B56.GLenum + GL_NUM_COMPRESSED_TEXTURE_FORMATS_ARB* = 0x86A2.GLenum + GL_COMPRESSED_RGB_ARB* = 0x84ED.GLenum + GL_DEBUG_TYPE_MARKER_KHR* = 0x8268.GLenum + GL_TEXTURE_DEPTH_QCOM* = 0x8BD4.GLenum + GL_VARIABLE_F_NV* = 0x8528.GLenum + GL_MAX_PIXEL_MAP_TABLE* = 0x0D34.GLenum + GL_DST_COLOR* = 0x0306.GLenum + GL_OR_INVERTED* = 0x150D.GLenum + GL_TRANSFORM_FEEDBACK_VARYINGS_NV* = 0x8C83.GLenum + GL_RGB_INTEGER* = 0x8D98.GLenum + GL_COLOR_MATERIAL* = 0x0B57.GLenum + GL_DEBUG_SEVERITY_LOW_AMD* = 0x9148.GLenum + GL_MIRROR_CLAMP_TO_BORDER_EXT* = 0x8912.GLint + GL_TEXTURE1_ARB* = 0x84C1.GLenum + GL_MIN_MAP_BUFFER_ALIGNMENT* = 0x90BC.GLenum + GL_MATRIX16_ARB* = 0x88D0.GLenum + GL_TEXTURE_ALPHA_TYPE_ARB* = 0x8C13.GLenum + GL_PROGRAM_POINT_SIZE* = 0x8642.GLenum + GL_COMBINER_AB_OUTPUT_NV* = 0x854A.GLenum + GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2_OES* = 0x9276.GLenum + GL_RGB4_S3TC* = 0x83A1.GLenum + GL_TEXTURE_EXTERNAL_OES* = 0x8D65.GLenum + GL_MAX_MAP_TESSELLATION_NV* = 0x86D6.GLenum + GL_AUX_DEPTH_STENCIL_APPLE* = 0x8A14.GLenum + GL_MAX_DEBUG_LOGGED_MESSAGES_AMD* = 0x9144.GLenum + GL_CONSTANT_BORDER* = 0x8151.GLenum + GL_RESAMPLE_ZERO_FILL_OML* = 0x8987.GLenum + GL_POST_CONVOLUTION_ALPHA_SCALE_EXT* = 0x801F.GLenum + GL_OBJECT_VALIDATE_STATUS_ARB* = 0x8B83.GLenum + GL_DST_ALPHA* = 0x0304.GLenum + GL_COMBINER5_NV* = 0x8555.GLenum + GL_VERSION_ES_CL_1_1* = 1.GLenum + GL_MOVE_TO_CONTINUES_NV* = 0x90B6.GLenum + GL_IMAGE_MAG_FILTER_HP* = 0x815C.GLenum + GL_TEXTURE_FREE_MEMORY_ATI* = 0x87FC.GLenum + GL_DEBUG_TYPE_PORTABILITY_KHR* = 0x824F.GLenum + GL_BUFFER_UPDATE_BARRIER_BIT* = 0x00000200.GLbitfield + GL_FUNC_ADD* = 0x8006.GLenum + GL_PN_TRIANGLES_POINT_MODE_ATI* = 0x87F2.GLenum + GL_DEBUG_CALLBACK_USER_PARAM_ARB* = 0x8245.GLenum + GL_CURRENT_SECONDARY_COLOR* = 0x8459.GLenum + GL_DEPENDENT_RGB_TEXTURE_CUBE_MAP_NV* = 0x885A.GLenum + GL_FRAGMENT_LIGHT7_SGIX* = 0x8413.GLenum + GL_MAP2_TEXTURE_COORD_4* = 0x0DB6.GLenum + GL_PACK_ALIGNMENT* = 0x0D05.GLenum + GL_VERTEX23_BIT_PGI* = 0x00000004.GLbitfield + GL_MAX_CLIPMAP_DEPTH_SGIX* = 0x8177.GLenum + GL_TEXTURE_3D_BINDING_EXT* = 0x806A.GLenum + GL_COLOR_ATTACHMENT1* = 0x8CE1.GLenum + GL_NEAREST* = 0x2600.GLint + GL_MAX_DEBUG_LOGGED_MESSAGES* = 0x9144.GLenum + GL_COMBINER6_NV* = 0x8556.GLenum + GL_COLOR_SUM_EXT* = 0x8458.GLenum + GL_CONVOLUTION_WIDTH* = 0x8018.GLenum + GL_SAMPLE_ALPHA_TO_COVERAGE_ARB* = 0x809E.GLenum + GL_DRAW_FRAMEBUFFER_EXT* = 0x8CA9.GLenum + GL_PROXY_HISTOGRAM* = 0x8025.GLenum + GL_PIXEL_FRAGMENT_ALPHA_SOURCE_SGIS* = 0x8355.GLenum + GL_COMPRESSED_RGBA_ASTC_10x5_KHR* = 0x93B8.GLenum + GL_SMOOTH_CUBIC_CURVE_TO_NV* = 0x10.GLenum + GL_BGR_EXT* = 0x80E0.GLenum + GL_PROGRAM_UNDER_NATIVE_LIMITS_ARB* = 0x88B6.GLenum + GL_VIBRANCE_BIAS_NV* = 0x8719.GLenum + GL_UNPACK_COLORSPACE_CONVERSION_WEBGL* = 0x9243.GLenum + GL_SLUMINANCE8_NV* = 0x8C47.GLenum + GL_TEXTURE_MAX_LEVEL_SGIS* = 0x813D.GLenum + GL_UNIFORM_ATOMIC_COUNTER_BUFFER_INDEX* = 0x92DA.GLenum + GL_RGB9_E5_EXT* = 0x8C3D.GLenum + GL_CULL_VERTEX_IBM* = 103050.GLenum + GL_PROXY_COLOR_TABLE* = 0x80D3.GLenum + GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE* = 0x8216.GLenum + GL_MAX_FRAGMENT_UNIFORM_COMPONENTS* = 0x8B49.GLenum + GL_CCW* = 0x0901.GLenum + GL_COLOR_WRITEMASK* = 0x0C23.GLenum + GL_TEXTURE19_ARB* = 0x84D3.GLenum + GL_VERTEX_STREAM3_ATI* = 0x876F.GLenum + GL_ONE_EXT* = 0x87DE.GLenum + GL_MAX_SAMPLES* = 0x8D57.GLenum + GL_STENCIL_PASS_DEPTH_PASS* = 0x0B96.GLenum + GL_PERFMON_RESULT_AVAILABLE_AMD* = 0x8BC4.GLenum + GL_RETURN* = 0x0102.GLenum + GL_DETAIL_TEXTURE_LEVEL_SGIS* = 0x809A.GLenum + GL_UNSIGNED_INT_IMAGE_CUBE_EXT* = 0x9066.GLenum + GL_FOG_OFFSET_VALUE_SGIX* = 0x8199.GLenum + GL_TEXTURE_MAX_LOD_SGIS* = 0x813B.GLenum + GL_TRANSPOSE_COLOR_MATRIX_ARB* = 0x84E6.GLenum + GL_DEBUG_SOURCE_APPLICATION_ARB* = 0x824A.GLenum + GL_SIGNED_ALPHA_NV* = 0x8705.GLenum + GL_UNSIGNED_INT_IMAGE_2D_EXT* = 0x9063.GLenum + GL_SHADER_IMAGE_ACCESS_BARRIER_BIT* = 0x00000020.GLbitfield + GL_ATOMIC_COUNTER_BARRIER_BIT* = 0x00001000.GLbitfield + GL_COLOR3_BIT_PGI* = 0x00010000.GLbitfield + GL_MATERIAL_SIDE_HINT_PGI* = 0x1A22C.GLenum + GL_LIGHT_MODEL_SPECULAR_VECTOR_APPLE* = 0x85B0.GLenum + GL_LINEAR_SHARPEN_SGIS* = 0x80AD.GLenum + GL_LUMINANCE_SNORM* = 0x9011.GLenum + GL_TEXTURE_LUMINANCE_SIZE* = 0x8060.GLenum + GL_REPLACE_MIDDLE_SUN* = 0x0002.GLenum + GL_TEXTURE_DEFORMATION_SGIX* = 0x8195.GLenum + GL_MULTISAMPLE_BUFFER_BIT7_QCOM* = 0x80000000.GLbitfield + GL_FONT_HAS_KERNING_BIT_NV* = 0x10000000.GLbitfield + GL_COPY* = 0x1503.GLenum + GL_READ_BUFFER_NV* = 0x0C02.GLenum + GL_TRANSPOSE_CURRENT_MATRIX_ARB* = 0x88B7.GLenum + GL_VERTEX_ARRAY_OBJECT_AMD* = 0x9154.GLenum + GL_TIMEOUT_EXPIRED* = 0x911B.GLenum + GL_DYNAMIC_COPY* = 0x88EA.GLenum + GL_DRAW_BUFFER2_ARB* = 0x8827.GLenum + GL_OUTPUT_TEXTURE_COORD10_EXT* = 0x87A7.GLenum + GL_SIGNED_RGBA8_NV* = 0x86FC.GLenum + GL_MATRIX6_ARB* = 0x88C6.GLenum + GL_OP_SUB_EXT* = 0x8796.GLenum + GL_NO_RESET_NOTIFICATION_EXT* = 0x8261.GLenum + GL_TEXTURE_BASE_LEVEL_SGIS* = 0x813C.GLenum + GL_ALPHA_INTEGER* = 0x8D97.GLenum + GL_TEXTURE13* = 0x84CD.GLenum + GL_EYE_LINEAR* = 0x2400.GLenum + GL_INTENSITY4_EXT* = 0x804A.GLenum + GL_SOURCE1_RGB_EXT* = 0x8581.GLenum + GL_AUX_BUFFERS* = 0x0C00.GLenum + GL_SOURCE0_ALPHA* = 0x8588.GLenum + GL_RGB32I* = 0x8D83.GLenum + GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS* = 0x8C8A.GLenum + GL_VIEW_CLASS_S3TC_DXT1_RGBA* = 0x82CD.GLenum + GL_TRANSFORM_FEEDBACK_BUFFER_SIZE_NV* = 0x8C85.GLenum + GL_SAMPLER_KHR* = 0x82E6.GLenum + GL_WRITEONLY_RENDERING_QCOM* = 0x8823.GLenum + GL_PACK_SKIP_ROWS* = 0x0D03.GLenum + GL_MAP1_VERTEX_ATTRIB0_4_NV* = 0x8660.GLenum + GL_PATH_STENCIL_VALUE_MASK_NV* = 0x90B9.GLenum + GL_REPLACE_EXT* = 0x8062.GLenum + GL_MODELVIEW3_ARB* = 0x8723.GLenum + GL_ONE_MINUS_CONSTANT_ALPHA* = 0x8004.GLenum + GL_DSDT8_MAG8_INTENSITY8_NV* = 0x870B.GLenum + GL_CURRENT_QUERY_ARB* = 0x8865.GLenum + GL_LUMINANCE8_ALPHA8_OES* = 0x8045.GLenum + GL_ARRAY_ELEMENT_LOCK_COUNT_EXT* = 0x81A9.GLenum + GL_MODELVIEW19_ARB* = 0x8733.GLenum + GL_MAX_VERTEX_SHADER_INSTRUCTIONS_EXT* = 0x87C5.GLenum + GL_MAX_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB* = 0x8810.GLenum + GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY_EXT* = 0x906C.GLenum + GL_NORMAL_ARRAY_BUFFER_BINDING* = 0x8897.GLenum + GL_AMBIENT* = 0x1200.GLenum + GL_TEXTURE_MATERIAL_PARAMETER_EXT* = 0x8352.GLenum + GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR* = 0x93DA.GLenum + GL_MAX_TESS_CONTROL_UNIFORM_COMPONENTS* = 0x8E7F.GLenum + GL_COMPRESSED_LUMINANCE_ALPHA_ARB* = 0x84EB.GLenum + GL_MODELVIEW14_ARB* = 0x872E.GLenum + GL_INTERLACE_READ_OML* = 0x8981.GLenum + GL_RENDERBUFFER_FREE_MEMORY_ATI* = 0x87FD.GLenum + GL_EMBOSS_MAP_NV* = 0x855F.GLenum + GL_POINT_SIZE_RANGE* = 0x0B12.GLenum + GL_FOG_COORDINATE* = 0x8451.GLenum + GL_MAJOR_VERSION* = 0x821B.GLenum + GL_FRAME_NV* = 0x8E26.GLenum + GL_CURRENT_TEXTURE_COORDS* = 0x0B03.GLenum + GL_PACK_RESAMPLE_OML* = 0x8984.GLenum + GL_DEPTH24_STENCIL8_OES* = 0x88F0.GLenum + GL_PROGRAM_BINARY_FORMATS_OES* = 0x87FF.GLenum + GL_TRANSLATE_3D_NV* = 0x9091.GLenum + GL_TEXTURE_GEN_Q* = 0x0C63.GLenum + GL_COLOR_ATTACHMENT0_EXT* = 0x8CE0.GLenum + GL_ALPHA12* = 0x803D.GLenum + GL_INCR_WRAP_EXT* = 0x8507.GLenum + GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN* = 0x8C88.GLenum + GL_DUAL_ALPHA12_SGIS* = 0x8112.GLenum + GL_EYE_LINE_SGIS* = 0x81F6.GLenum + GL_TEXTURE_MAX_LEVEL_APPLE* = 0x813D.GLenum + GL_TRIANGLE_FAN* = 0x0006.GLenum + GL_DEBUG_GROUP_STACK_DEPTH* = 0x826D.GLenum + GL_IMAGE_CLASS_1_X_16* = 0x82BE.GLenum + GL_COMPILE* = 0x1300.GLenum + GL_LINE_SMOOTH* = 0x0B20.GLenum + GL_FEEDBACK_BUFFER_POINTER* = 0x0DF0.GLenum + GL_CURRENT_SECONDARY_COLOR_EXT* = 0x8459.GLenum + GL_DRAW_BUFFER2_ATI* = 0x8827.GLenum + GL_PN_TRIANGLES_NORMAL_MODE_ATI* = 0x87F3.GLenum + GL_MODELVIEW0_ARB* = 0x1700.GLenum + GL_SRGB8_ALPHA8* = 0x8C43.GLenum + GL_TEXTURE_BLUE_TYPE* = 0x8C12.GLenum + GL_POST_CONVOLUTION_ALPHA_BIAS* = 0x8023.GLenum + GL_PATH_STROKE_BOUNDING_BOX_NV* = 0x90A2.GLenum + GL_RGBA16UI* = 0x8D76.GLenum + GL_OFFSET_HILO_TEXTURE_2D_NV* = 0x8854.GLenum + GL_PREVIOUS_ARB* = 0x8578.GLenum + GL_BINORMAL_ARRAY_EXT* = 0x843A.GLenum + GL_UNSIGNED_INT_IMAGE_CUBE* = 0x9066.GLenum + GL_REG_30_ATI* = 0x893F.GLenum + GL_VIEWPORT_SUBPIXEL_BITS* = 0x825C.GLenum + GL_VERSION* = 0x1F02.GLenum + GL_COMPUTE_PROGRAM_PARAMETER_BUFFER_NV* = 0x90FC.GLenum + GL_DEBUG_CATEGORY_SHADER_COMPILER_AMD* = 0x914E.GLenum + GL_CONVOLUTION_FILTER_SCALE_EXT* = 0x8014.GLenum + GL_HALF_BIT_ATI* = 0x00000008.GLbitfield + GL_SPRITE_AXIS_SGIX* = 0x814A.GLenum + GL_INDEX_ARRAY_STRIDE* = 0x8086.GLenum + GL_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB* = 0x88B2.GLenum + GL_EVAL_VERTEX_ATTRIB0_NV* = 0x86C6.GLenum + GL_COUNTER_RANGE_AMD* = 0x8BC1.GLenum + GL_VERTEX_WEIGHTING_EXT* = 0x8509.GLenum + GL_POST_CONVOLUTION_GREEN_SCALE* = 0x801D.GLenum + GL_UNSIGNED_INT8_NV* = 0x8FEC.GLenum + GL_CURRENT_MATRIX_STACK_DEPTH_NV* = 0x8640.GLenum + GL_STENCIL_INDEX1_OES* = 0x8D46.GLenum + GL_SLUMINANCE_NV* = 0x8C46.GLenum + GL_UNSIGNED_INT_8_8_8_8_REV_EXT* = 0x8367.GLenum + GL_HISTOGRAM_FORMAT* = 0x8027.GLenum + GL_LUMINANCE12_ALPHA4_EXT* = 0x8046.GLenum + GL_FLOAT_MAT3* = 0x8B5B.GLenum + GL_MAX_PROGRAM_TEXEL_OFFSET_NV* = 0x8905.GLenum + GL_PALETTE8_RGBA4_OES* = 0x8B98.GLenum + GL_UNPACK_SKIP_IMAGES_EXT* = 0x806D.GLenum + GL_TEXTURE_CUBE_MAP_NEGATIVE_Y* = 0x8518.GLenum + GL_UNPACK_SUBSAMPLE_RATE_SGIX* = 0x85A1.GLenum + GL_NORMAL_ARRAY_LENGTH_NV* = 0x8F2C.GLenum + GL_VERTEX_ATTRIB_ARRAY4_NV* = 0x8654.GLenum + GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_OES* = 0x8CD9.GLenum + GL_UNSIGNED_BYTE* = 0x1401.GLenum + GL_RGB2_EXT* = 0x804E.GLenum + GL_TEXTURE_BUFFER_SIZE* = 0x919E.GLenum + GL_MAP_STENCIL* = 0x0D11.GLenum + GL_TIMEOUT_EXPIRED_APPLE* = 0x911B.GLenum + GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS* = 0x8C29.GLenum + GL_CON_14_ATI* = 0x894F.GLenum + GL_RGBA12* = 0x805A.GLenum + GL_MAX_SPARSE_ARRAY_TEXTURE_LAYERS* = 0x919A.GLenum + GL_CON_20_ATI* = 0x8955.GLenum + GL_LOCAL_CONSTANT_DATATYPE_EXT* = 0x87ED.GLenum + GL_DUP_FIRST_CUBIC_CURVE_TO_NV* = 0xF2.GLenum + GL_SECONDARY_COLOR_ARRAY_ADDRESS_NV* = 0x8F27.GLenum + GL_TEXTURE_COORD_ARRAY* = 0x8078.GLenum + GL_LUMINANCE8I_EXT* = 0x8D92.GLenum + GL_REPLACE_OLDEST_SUN* = 0x0003.GLenum + GL_TEXTURE_SHADER_NV* = 0x86DE.GLenum + GL_UNSIGNED_INT_8_8_8_8_EXT* = 0x8035.GLenum + GL_SAMPLE_COVERAGE_INVERT* = 0x80AB.GLenum + GL_FOG_COORD_ARRAY_ADDRESS_NV* = 0x8F28.GLenum + GL_GPU_DISJOINT_EXT* = 0x8FBB.GLenum + GL_STENCIL_BACK_PASS_DEPTH_PASS_ATI* = 0x8803.GLenum + GL_TEXTURE_GREEN_SIZE_EXT* = 0x805D.GLenum + GL_INTERLEAVED_ATTRIBS* = 0x8C8C.GLenum + GL_FOG_FUNC_SGIS* = 0x812A.GLenum + GL_TEXTURE_DEPTH_SIZE_ARB* = 0x884A.GLenum + GL_MAP_COHERENT_BIT* = 0x0080.GLbitfield + GL_COMPRESSED_SLUMINANCE_ALPHA* = 0x8C4B.GLenum + GL_RGB32UI* = 0x8D71.GLenum + GL_SEPARABLE_2D* = 0x8012.GLenum + GL_MATRIX10_ARB* = 0x88CA.GLenum + GL_FLOAT_RGBA32_NV* = 0x888B.GLenum + GL_MAX_SPARSE_3D_TEXTURE_SIZE_ARB* = 0x9199.GLenum + GL_TEXTURE_RENDERBUFFER_DATA_STORE_BINDING_NV* = 0x8E54.GLenum + GL_REG_9_ATI* = 0x892A.GLenum + GL_MAP2_VERTEX_ATTRIB14_4_NV* = 0x867E.GLenum + GL_OP_EXP_BASE_2_EXT* = 0x8791.GLenum + GL_INT_IMAGE_BUFFER_EXT* = 0x905C.GLenum + GL_TEXTURE_WRAP_R_EXT* = 0x8072.GLenum + GL_DOUBLE_VEC3* = 0x8FFD.GLenum + GL_DRAW_BUFFER5_EXT* = 0x882A.GLenum + GL_OUTPUT_TEXTURE_COORD7_EXT* = 0x87A4.GLenum + GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB* = 0x8242.GLenum + GL_MAX_TESS_GEN_LEVEL* = 0x8E7E.GLenum + GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB* = 0x8895.GLenum + GL_RGBA16I_EXT* = 0x8D88.GLenum + GL_REG_10_ATI* = 0x892B.GLenum + GL_MAT_EMISSION_BIT_PGI* = 0x00800000.GLbitfield + GL_TEXTURE_COORD_ARRAY_SIZE_EXT* = 0x8088.GLenum + GL_RED_BIAS* = 0x0D15.GLenum + GL_RGB16F_ARB* = 0x881B.GLenum + GL_ANY_SAMPLES_PASSED_CONSERVATIVE* = 0x8D6A.GLenum + GL_BLUE_MAX_CLAMP_INGR* = 0x8566.GLenum + cGL_FLOAT* = 0x1406.GLenum + GL_STENCIL_INDEX8_EXT* = 0x8D48.GLenum + GL_POINT_SIZE_ARRAY_OES* = 0x8B9C.GLenum + GL_INT16_NV* = 0x8FE4.GLenum + GL_PALETTE4_RGB8_OES* = 0x8B90.GLenum + GL_RENDERBUFFER_GREEN_SIZE_OES* = 0x8D51.GLenum + GL_SEPARATE_ATTRIBS_NV* = 0x8C8D.GLenum + GL_BOOL_VEC3_ARB* = 0x8B58.GLenum + GL_ATOMIC_COUNTER_BUFFER_ACTIVE_ATOMIC_COUNTER_INDICES* = 0x92C6.GLenum + GL_STACK_UNDERFLOW_KHR* = 0x0504.GLenum + GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB* = 0x8519.GLenum + GL_COMPRESSED_INTENSITY_ARB* = 0x84EC.GLenum + GL_MAX_ASYNC_TEX_IMAGE_SGIX* = 0x835F.GLenum + GL_TEXTURE_4D_SGIS* = 0x8134.GLenum + GL_TEXCOORD3_BIT_PGI* = 0x40000000.GLbitfield + GL_PIXEL_MAP_I_TO_R_SIZE* = 0x0CB2.GLenum + GL_NORMAL_MAP_ARB* = 0x8511.GLenum + GL_MAX_CONVOLUTION_HEIGHT* = 0x801B.GLenum + GL_COMPRESSED_INTENSITY* = 0x84EC.GLenum + GL_FONT_Y_MAX_BOUNDS_BIT_NV* = 0x00080000.GLbitfield + GL_FLOAT_MAT2* = 0x8B5A.GLenum + GL_TEXTURE_SRGB_DECODE_EXT* = 0x8A48.GLenum + GL_FRAMEBUFFER_BLEND* = 0x828B.GLenum + GL_TEXTURE_COORD_ARRAY_LIST_IBM* = 103074.GLenum + GL_REG_12_ATI* = 0x892D.GLenum + GL_UNSIGNED_INT_ATOMIC_COUNTER* = 0x92DB.GLenum + GL_DETAIL_TEXTURE_2D_BINDING_SGIS* = 0x8096.GLenum + GL_OCCLUSION_TEST_HP* = 0x8165.GLenum + GL_TEXTURE11_ARB* = 0x84CB.GLenum + GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC* = 0x9279.GLenum + GL_BUFFER_MAPPED* = 0x88BC.GLenum + GL_VARIANT_ARRAY_STRIDE_EXT* = 0x87E6.GLenum + GL_CONVOLUTION_BORDER_COLOR_HP* = 0x8154.GLenum + GL_UNPACK_RESAMPLE_OML* = 0x8985.GLenum + GL_TRANSFORM_FEEDBACK_BUFFER_SIZE* = 0x8C85.GLenum + GL_PROXY_TEXTURE_2D_ARRAY_EXT* = 0x8C1B.GLenum + GL_RGBA4_EXT* = 0x8056.GLenum + GL_ALPHA32I_EXT* = 0x8D84.GLenum + GL_ATOMIC_COUNTER_BUFFER_DATA_SIZE* = 0x92C4.GLenum + GL_FRAGMENT_LIGHT_MODEL_AMBIENT_SGIX* = 0x840A.GLenum + GL_BINORMAL_ARRAY_TYPE_EXT* = 0x8440.GLenum + GL_VIEW_CLASS_S3TC_DXT5_RGBA* = 0x82CF.GLenum + GL_TEXTURE_CLIPMAP_OFFSET_SGIX* = 0x8173.GLenum + GL_RESTART_SUN* = 0x0001.GLenum + GL_PERTURB_EXT* = 0x85AE.GLenum + GL_UNSIGNED_BYTE_3_3_2_EXT* = 0x8032.GLenum + GL_LUMINANCE16I_EXT* = 0x8D8C.GLenum + GL_TEXTURE3_ARB* = 0x84C3.GLenum + GL_POINT_SIZE_MIN_EXT* = 0x8126.GLenum + GL_OUTPUT_TEXTURE_COORD1_EXT* = 0x879E.GLenum + GL_COMPARE_REF_TO_TEXTURE* = 0x884E.GLenum + GL_KEEP* = 0x1E00.GLenum + GL_FLOAT_MAT2x4* = 0x8B66.GLenum + GL_FLOAT_VEC4_ARB* = 0x8B52.GLenum + GL_BIAS_BY_NEGATIVE_ONE_HALF_NV* = 0x8541.GLenum + GL_BGR* = 0x80E0.GLenum + GL_SHADER_BINARY_FORMATS* = 0x8DF8.GLenum + GL_CND0_ATI* = 0x896B.GLenum + GL_MIRRORED_REPEAT_IBM* = 0x8370.GLint + GL_REFLECTION_MAP_OES* = 0x8512.GLenum + GL_MAX_VERTEX_BINDABLE_UNIFORMS_EXT* = 0x8DE2.GLenum + GL_R* = 0x2002.GLenum + GL_MAX_SHADER_STORAGE_BLOCK_SIZE* = 0x90DE.GLenum + GL_ATTRIB_ARRAY_STRIDE_NV* = 0x8624.GLenum + GL_VARIABLE_E_NV* = 0x8527.GLenum + GL_HISTOGRAM_EXT* = 0x8024.GLenum + GL_TEXTURE_BINDING_BUFFER_ARB* = 0x8C2C.GLenum + GL_MAX_SPARSE_TEXTURE_SIZE_ARB* = 0x9198.GLenum + GL_TEXTURE5* = 0x84C5.GLenum + GL_NUM_ACTIVE_VARIABLES* = 0x9304.GLenum + GL_DEPTH_STENCIL_ATTACHMENT* = 0x821A.GLenum + GL_WEIGHT_ARRAY_BUFFER_BINDING_ARB* = 0x889E.GLenum + GL_AMBIENT_AND_DIFFUSE* = 0x1602.GLenum + GL_LAYER_NV* = 0x8DAA.GLenum + GL_GLYPH_HORIZONTAL_BEARING_Y_BIT_NV* = 0x08.GLbitfield + GL_TEXTURE8* = 0x84C8.GLenum + GL_MODELVIEW5_ARB* = 0x8725.GLenum + GL_MAX_COMBINED_ATOMIC_COUNTER_BUFFERS* = 0x92D1.GLenum + GL_MAX_TESS_CONTROL_ATOMIC_COUNTER_BUFFERS* = 0x92CD.GLenum + GL_BLUE_MIN_CLAMP_INGR* = 0x8562.GLenum + GL_MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS* = 0x90D9.GLenum + GL_TEXTURE_CUBE_MAP_POSITIVE_Z_OES* = 0x8519.GLenum + GL_MAX_SAMPLES_IMG* = 0x9135.GLenum + GL_QUERY_BY_REGION_WAIT* = 0x8E15.GLenum + GL_T* = 0x2001.GLenum + GL_VIEW_CLASS_RGTC2_RG* = 0x82D1.GLenum + GL_TEXTURE_ENV_MODE* = 0x2200.GLenum + GL_COMPRESSED_SRGB8_ETC2* = 0x9275.GLenum + GL_MAP_FLUSH_EXPLICIT_BIT* = 0x0010.GLbitfield + GL_COLOR_MATERIAL_PARAMETER* = 0x0B56.GLenum + GL_HALF_FLOAT_ARB* = 0x140B.GLenum + GL_NOTEQUAL* = 0x0205.GLenum + GL_MAP_INVALIDATE_BUFFER_BIT_EXT* = 0x0008.GLbitfield + GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS_EXT* = 0x8C29.GLenum + GL_DUAL_TEXTURE_SELECT_SGIS* = 0x8124.GLenum + GL_TEXTURE31* = 0x84DF.GLenum + GL_EVAL_TRIANGULAR_2D_NV* = 0x86C1.GLenum + GL_VIDEO_COLOR_CONVERSION_OFFSET_NV* = 0x902C.GLenum + GL_COMPRESSED_R11_EAC_OES* = 0x9270.GLenum + GL_RGB8_OES* = 0x8051.GLenum + GL_CLIP_PLANE2* = 0x3002.GLenum + GL_HINT_BIT* = 0x00008000.GLbitfield + GL_TEXTURE6_ARB* = 0x84C6.GLenum + GL_FLOAT_VEC2* = 0x8B50.GLenum + GL_TRANSFORM_FEEDBACK_BUFFER_SIZE_EXT* = 0x8C85.GLenum + GL_MAX_EVAL_ORDER* = 0x0D30.GLenum + GL_DUAL_LUMINANCE8_SGIS* = 0x8115.GLenum + GL_ALPHA16I_EXT* = 0x8D8A.GLenum + GL_IDENTITY_NV* = 0x862A.GLenum + GL_VIEW_CLASS_BPTC_UNORM* = 0x82D2.GLenum + GL_PATH_DASH_CAPS_NV* = 0x907B.GLenum + GL_IGNORE_BORDER_HP* = 0x8150.GLenum + GL_PN_TRIANGLES_POINT_MODE_CUBIC_ATI* = 0x87F6.GLenum + GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS_EXT* = 0x8C8B.GLenum + GL_DRAW_BUFFER1_ATI* = 0x8826.GLenum + GL_TEXTURE_MIN_FILTER* = 0x2801.GLenum + GL_EVAL_VERTEX_ATTRIB12_NV* = 0x86D2.GLenum + GL_INT_IMAGE_2D_ARRAY* = 0x905E.GLenum + GL_SRC0_RGB* = 0x8580.GLenum + GL_MIN_EXT* = 0x8007.GLenum + GL_PROGRAM_PIPELINE_OBJECT_EXT* = 0x8A4F.GLenum + GL_STENCIL_BUFFER_BIT* = 0x00000400.GLbitfield + GL_SCREEN_COORDINATES_REND* = 0x8490.GLenum + GL_DOUBLE_VEC3_EXT* = 0x8FFD.GLenum + GL_SUBSAMPLE_DISTANCE_AMD* = 0x883F.GLenum + GL_VERTEX_SHADER_LOCALS_EXT* = 0x87D3.GLenum + GL_VERTEX_ATTRIB_ARRAY13_NV* = 0x865D.GLenum + GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR* = 0x93D9.GLenum + GL_UNSIGNED_NORMALIZED* = 0x8C17.GLenum + GL_DRAW_BUFFER10_NV* = 0x882F.GLenum + GL_PATH_STROKE_MASK_NV* = 0x9084.GLenum + GL_MAX_PROGRAM_NATIVE_TEMPORARIES_ARB* = 0x88A7.GLenum + GL_SRGB_ALPHA_EXT* = 0x8C42.GLenum + GL_CONST_EYE_NV* = 0x86E5.GLenum + GL_MODELVIEW1_ARB* = 0x850A.GLenum + GL_FORMAT_SUBSAMPLE_244_244_OML* = 0x8983.GLenum + GL_LOGIC_OP_MODE* = 0x0BF0.GLenum + GL_CLIP_DISTANCE4* = 0x3004.GLenum + GL_DEBUG_CATEGORY_WINDOW_SYSTEM_AMD* = 0x914A.GLenum + GL_SAMPLES* = 0x80A9.GLenum + GL_UNSIGNED_SHORT_5_5_5_1_EXT* = 0x8034.GLenum + GL_POINT_DISTANCE_ATTENUATION* = 0x8129.GLenum + GL_3D_COLOR* = 0x0602.GLenum + GL_BGRA* = 0x80E1.GLenum + GL_PARAMETER_BUFFER_BINDING_ARB* = 0x80EF.GLenum + GL_EDGE_FLAG_ARRAY_LIST_STRIDE_IBM* = 103085.GLenum + GL_HSL_LUMINOSITY_NV* = 0x92B0.GLenum + GL_PROJECTION_STACK_DEPTH* = 0x0BA4.GLenum + GL_COMBINER_BIAS_NV* = 0x8549.GLenum + GL_AND* = 0x1501.GLenum + GL_TEXTURE27* = 0x84DB.GLenum + GL_VERTEX_PROGRAM_CALLBACK_DATA_MESA* = 0x8BB7.GLenum + GL_DRAW_BUFFER13_ATI* = 0x8832.GLenum + GL_UNSIGNED_SHORT_5_5_5_1* = 0x8034.GLenum + GL_PERFMON_GLOBAL_MODE_QCOM* = 0x8FA0.GLenum + GL_RED_EXT* = 0x1903.GLenum + GL_INNOCENT_CONTEXT_RESET_EXT* = 0x8254.GLenum + GL_UNIFORM_BUFFER_START* = 0x8A29.GLenum + GL_MAX_UNIFORM_BUFFER_BINDINGS* = 0x8A2F.GLenum + GL_SLICE_ACCUM_SUN* = 0x85CC.GLenum + GL_DRAW_BUFFER9_ATI* = 0x882E.GLenum + GL_VERTEX_PROGRAM_PARAMETER_BUFFER_NV* = 0x8DA2.GLenum + GL_READ_FRAMEBUFFER_BINDING_APPLE* = 0x8CAA.GLenum + GL_INDEX_ARRAY_LENGTH_NV* = 0x8F2E.GLenum + GL_DETAIL_TEXTURE_MODE_SGIS* = 0x809B.GLenum + GL_MATRIX13_ARB* = 0x88CD.GLenum + GL_ADD_SIGNED_ARB* = 0x8574.GLenum + GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE* = 0x910A.GLenum + GL_DEPTH_BITS* = 0x0D56.GLenum + GL_LUMINANCE_ALPHA_SNORM* = 0x9012.GLenum + GL_VIEW_CLASS_RGTC1_RED* = 0x82D0.GLenum + GL_LINE_WIDTH* = 0x0B21.GLenum + GL_DRAW_BUFFER14_ATI* = 0x8833.GLenum + GL_CON_30_ATI* = 0x895F.GLenum + GL_POST_COLOR_MATRIX_BLUE_BIAS* = 0x80BA.GLenum + GL_PIXEL_TRANSFORM_2D_EXT* = 0x8330.GLenum + GL_CONTEXT_LOST_WEBGL* = 0x9242.GLenum + GL_COLOR_TABLE_BLUE_SIZE_SGI* = 0x80DC.GLenum + GL_CONSTANT_EXT* = 0x8576.GLenum + GL_IMPLEMENTATION_COLOR_READ_TYPE* = 0x8B9A.GLenum + GL_HSL_COLOR_NV* = 0x92AF.GLenum + GL_LOAD* = 0x0101.GLenum + GL_TEXTURE_BIT* = 0x00040000.GLbitfield + GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT* = 0x8CD9.GLenum + GL_IMAGE_ROTATE_ORIGIN_X_HP* = 0x815A.GLenum + GL_DEPTH_BUFFER_BIT6_QCOM* = 0x00004000.GLbitfield + GL_QUERY* = 0x82E3.GLenum + GL_INVALID_VALUE* = 0x0501.GLenum + GL_PACK_COMPRESSED_BLOCK_HEIGHT* = 0x912C.GLenum + GL_MAX_PROGRAM_GENERIC_RESULTS_NV* = 0x8DA6.GLenum + GL_BACK_PRIMARY_COLOR_NV* = 0x8C77.GLenum + GL_ALPHA8_OES* = 0x803C.GLenum + GL_INDEX* = 0x8222.GLenum + GL_ATTRIB_ARRAY_SIZE_NV* = 0x8623.GLenum + GL_INT_IMAGE_1D_ARRAY* = 0x905D.GLenum + GL_LOCATION* = 0x930E.GLenum + GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT* = 0x8CD7.GLenum + GL_SIMULTANEOUS_TEXTURE_AND_STENCIL_WRITE* = 0x82AF.GLenum + GL_RESAMPLE_ZERO_FILL_SGIX* = 0x842F.GLenum + GL_VERTEX_ARRAY_BINDING_OES* = 0x85B5.GLenum + GL_MATRIX4_ARB* = 0x88C4.GLenum + GL_NEXT_BUFFER_NV* = -2 + GL_ELEMENT_ARRAY_BARRIER_BIT* = 0x00000002.GLbitfield + GL_RGBA16_EXT* = 0x805B.GLenum + GL_SEPARABLE_2D_EXT* = 0x8012.GLenum + GL_R11F_G11F_B10F_EXT* = 0x8C3A.GLenum + GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER_EXT* = 0x8CD4.GLenum + GL_IMAGE_2D_EXT* = 0x904D.GLenum + GL_DRAW_BUFFER6_NV* = 0x882B.GLenum + GL_TEXTURE_RANGE_LENGTH_APPLE* = 0x85B7.GLenum + GL_TEXTURE_RED_TYPE_ARB* = 0x8C10.GLenum + GL_ALPHA16F_ARB* = 0x881C.GLenum + GL_DEBUG_LOGGED_MESSAGES_ARB* = 0x9145.GLenum + GL_TRANSPOSE_MODELVIEW_MATRIX_ARB* = 0x84E3.GLenum + GL_TRANSFORM_FEEDBACK_BUFFER_BINDING_EXT* = 0x8C8F.GLenum + GL_MAX_CONVOLUTION_WIDTH* = 0x801A.GLenum + GL_MIN_FRAGMENT_INTERPOLATION_OFFSET_NV* = 0x8E5B.GLenum + GL_PIXEL_TILE_CACHE_SIZE_SGIX* = 0x8145.GLenum + GL_4PASS_0_SGIS* = 0x80A4.GLenum + GL_PRIMITIVE_RESTART* = 0x8F9D.GLenum + GL_RG16_SNORM* = 0x8F99.GLenum + GL_SAMPLER_2D_SHADOW_EXT* = 0x8B62.GLenum + GL_FRONT* = 0x0404.GLenum + GL_PROXY_TEXTURE_2D_MULTISAMPLE_ARRAY* = 0x9103.GLenum + GL_SAMPLER_BINDING* = 0x8919.GLenum + GL_TEXTURE_2D_STACK_MESAX* = 0x875A.GLenum + GL_ASYNC_HISTOGRAM_SGIX* = 0x832C.GLenum + GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES* = 0x8B9B.GLenum + GL_OP_SET_LT_EXT* = 0x878D.GLenum + GL_INTERNALFORMAT_RED_TYPE* = 0x8278.GLenum + GL_AUX2* = 0x040B.GLenum + GL_CLAMP_FRAGMENT_COLOR* = 0x891B.GLenum + GL_BROWSER_DEFAULT_WEBGL* = 0x9244.GLenum + GL_IMAGE_CLASS_11_11_10* = 0x82C2.GLenum + GL_BUMP_ENVMAP_ATI* = 0x877B.GLenum + GL_FLOAT_32_UNSIGNED_INT_24_8_REV_NV* = 0x8DAD.GLenum + GL_RG_SNORM* = 0x8F91.GLenum + GL_BUMP_ROT_MATRIX_ATI* = 0x8775.GLenum + GL_UNIFORM_TYPE* = 0x8A37.GLenum + GL_FRAGMENT_COLOR_MATERIAL_PARAMETER_SGIX* = 0x8403.GLenum + GL_TEXTURE_BINDING_CUBE_MAP_ARRAY* = 0x900A.GLenum + GL_LUMINANCE12* = 0x8041.GLenum + GL_QUERY_NO_WAIT_NV* = 0x8E14.GLenum + GL_TEXTURE_CUBE_MAP_ARRAY_ARB* = 0x9009.GLenum + GL_QUERY_BY_REGION_NO_WAIT_NV* = 0x8E16.GLenum + GL_FOG_END* = 0x0B64.GLenum + GL_OBJECT_LINK_STATUS_ARB* = 0x8B82.GLenum + GL_TEXTURE_COORD_ARRAY_SIZE* = 0x8088.GLenum + GL_SOURCE0_ALPHA_ARB* = 0x8588.GLenum + GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB* = 0x8518.GLenum + GL_FRAGMENT_LIGHT_MODEL_NORMAL_INTERPOLATION_SGIX* = 0x840B.GLenum + GL_STATIC_COPY* = 0x88E6.GLenum + GL_LINE_WIDTH_RANGE* = 0x0B22.GLenum + GL_VERTEX_SOURCE_ATI* = 0x8774.GLenum + GL_FLOAT_MAT4x3* = 0x8B6A.GLenum + GL_HALF_APPLE* = 0x140B.GLenum + GL_TEXTURE11* = 0x84CB.GLenum + GL_DECODE_EXT* = 0x8A49.GLenum + GL_VERTEX_ARRAY_STRIDE_EXT* = 0x807C.GLenum + GL_SAMPLER_BUFFER_EXT* = 0x8DC2.GLenum + GL_TEXTURE_LOD_BIAS_EXT* = 0x8501.GLenum + GL_MODULATE_SIGNED_ADD_ATI* = 0x8745.GLenum + GL_DEPTH_CLEAR_VALUE* = 0x0B73.GLenum + GL_COMPRESSED_ALPHA* = 0x84E9.GLenum + GL_TEXTURE_1D_STACK_MESAX* = 0x8759.GLenum + GL_TEXTURE_FIXED_SAMPLE_LOCATIONS* = 0x9107.GLenum + GL_LARGE_CCW_ARC_TO_NV* = 0x16.GLenum + GL_COMBINER1_NV* = 0x8551.GLenum + GL_ARRAY_SIZE* = 0x92FB.GLenum + GL_MAX_COMPUTE_IMAGE_UNIFORMS* = 0x91BD.GLenum + GL_TEXTURE_BINDING_EXTERNAL_OES* = 0x8D67.GLenum + GL_REG_26_ATI* = 0x893B.GLenum + GL_MUL_ATI* = 0x8964.GLenum + GL_STENCIL_BUFFER_BIT6_QCOM* = 0x00400000.GLbitfield + GL_INVALID_OPERATION* = 0x0502.GLenum + GL_COLOR_SUM* = 0x8458.GLenum + GL_OP_CROSS_PRODUCT_EXT* = 0x8797.GLenum + GL_COLOR_ATTACHMENT4_NV* = 0x8CE4.GLenum + GL_MAX_RECTANGLE_TEXTURE_SIZE_NV* = 0x84F8.GLenum + GL_BOOL_ARB* = 0x8B56.GLenum + GL_VERTEX_ATTRIB_ARRAY_TYPE_ARB* = 0x8625.GLenum + GL_MODELVIEW8_ARB* = 0x8728.GLenum + GL_STENCIL_TEST* = 0x0B90.GLenum + GL_SRC_OVER_NV* = 0x9288.GLenum + GL_COMPRESSED_LUMINANCE* = 0x84EA.GLenum + GL_MAX_GEOMETRY_PROGRAM_INVOCATIONS_NV* = 0x8E5A.GLenum + GL_WEIGHT_ARRAY_TYPE_ARB* = 0x86A9.GLenum + GL_WRITE_PIXEL_DATA_RANGE_POINTER_NV* = 0x887C.GLenum + GL_COLOR_ARRAY_STRIDE_EXT* = 0x8083.GLenum + GL_BLEND_SRC_ALPHA_EXT* = 0x80CB.GLenum + GL_MAX_PROGRAM_LOCAL_PARAMETERS_ARB* = 0x88B4.GLenum + GL_SCALAR_EXT* = 0x87BE.GLenum + GL_DEBUG_SEVERITY_MEDIUM_KHR* = 0x9147.GLenum + GL_IMAGE_SCALE_X_HP* = 0x8155.GLenum + GL_LUMINANCE6_ALPHA2_EXT* = 0x8044.GLenum + GL_OUTPUT_TEXTURE_COORD22_EXT* = 0x87B3.GLenum + GL_CURRENT_PROGRAM* = 0x8B8D.GLenum + GL_FRAGMENT_PROGRAM_ARB* = 0x8804.GLenum + GL_INFO_LOG_LENGTH* = 0x8B84.GLenum + GL_TEXTURE_CUBE_MAP_POSITIVE_Z* = 0x8519.GLenum + GL_PROJECTION_MATRIX_FLOAT_AS_INT_BITS_OES* = 0x898E.GLenum + GL_PRIMITIVE_RESTART_FIXED_INDEX* = 0x8D69.GLenum + GL_ARRAY_BUFFER_ARB* = 0x8892.GLenum + GL_DEPTH_STENCIL_MESA* = 0x8750.GLenum + GL_LUMINANCE8_OES* = 0x8040.GLenum + GL_REFLECTION_MAP_EXT* = 0x8512.GLenum + GL_PRIMITIVES_GENERATED* = 0x8C87.GLenum + GL_IMAGE_PIXEL_FORMAT* = 0x82A9.GLenum + GL_VERTEX_ARRAY_LIST_STRIDE_IBM* = 103080.GLenum + GL_MAP2_COLOR_4* = 0x0DB0.GLenum + GL_MULTIPLY_NV* = 0x9294.GLenum + GL_UNIFORM_BARRIER_BIT_EXT* = 0x00000004.GLbitfield + GL_STENCIL_BUFFER_BIT3_QCOM* = 0x00080000.GLbitfield + GL_REG_7_ATI* = 0x8928.GLenum + GL_STATIC_READ_ARB* = 0x88E5.GLenum + GL_MATRIX2_ARB* = 0x88C2.GLenum + GL_STENCIL_BUFFER_BIT5_QCOM* = 0x00200000.GLbitfield + GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS_ARB* = 0x8B4C.GLenum + GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG* = 0x8C03.GLenum + GL_R1UI_T2F_N3F_V3F_SUN* = 0x85CA.GLenum + GL_TEXTURE27_ARB* = 0x84DB.GLenum + GL_FRAMEBUFFER_INCOMPLETE_FORMATS_OES* = 0x8CDA.GLenum + GL_MAX_PROGRAM_TEXEL_OFFSET* = 0x8905.GLenum + GL_INT_SAMPLER_2D_ARRAY_EXT* = 0x8DCF.GLenum + GL_DRAW_BUFFER9_EXT* = 0x882E.GLenum + GL_RGB5_A1_EXT* = 0x8057.GLenum + GL_FIELDS_NV* = 0x8E27.GLenum + GL_MAX_TRACK_MATRIX_STACK_DEPTH_NV* = 0x862E.GLenum + GL_SHADER_COMPILER* = 0x8DFA.GLenum + GL_SRC2_ALPHA* = 0x858A.GLenum + GL_TRACE_NAME_MESA* = 0x8756.GLenum + GL_MIRROR_CLAMP_TO_EDGE* = 0x8743.GLint + GL_OPERAND0_RGB_EXT* = 0x8590.GLenum + GL_UNSIGNED_BYTE_2_3_3_REV_EXT* = 0x8362.GLenum + GL_UNSIGNED_INT_2_10_10_10_REV* = 0x8368.GLenum + GL_MAX_CLIP_DISTANCES* = 0x0D32.GLenum + GL_MAP2_TEXTURE_COORD_3* = 0x0DB5.GLenum + GL_DUAL_LUMINANCE16_SGIS* = 0x8117.GLenum + GL_TEXTURE_UPDATE_BARRIER_BIT_EXT* = 0x00000100.GLbitfield + GL_IMAGE_BUFFER_EXT* = 0x9051.GLenum + GL_REDUCE_EXT* = 0x8016.GLenum + GL_EVAL_VERTEX_ATTRIB9_NV* = 0x86CF.GLenum + GL_IMAGE_CLASS_4_X_32* = 0x82B9.GLenum + GL_MAX_FRAGMENT_BINDABLE_UNIFORMS_EXT* = 0x8DE3.GLenum + GL_FRAGMENTS_INSTRUMENT_MAX_SGIX* = 0x8315.GLenum + GL_REG_28_ATI* = 0x893D.GLenum + GL_VARIABLE_B_NV* = 0x8524.GLenum + GL_GET_TEXTURE_IMAGE_TYPE* = 0x8292.GLenum + GL_PERCENTAGE_AMD* = 0x8BC3.GLenum + GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS_ARB* = 0x8DE1.GLenum + GL_MAX_COMPUTE_UNIFORM_BLOCKS* = 0x91BB.GLenum + GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_APPLE* = 0x8D56.GLenum + GL_PROVOKING_VERTEX* = 0x8E4F.GLenum + GL_FRAMEZOOM_FACTOR_SGIX* = 0x818C.GLenum + GL_COLOR_TABLE_ALPHA_SIZE* = 0x80DD.GLenum + GL_PIXEL_TEXTURE_SGIS* = 0x8353.GLenum + GL_MODELVIEW26_ARB* = 0x873A.GLenum + GL_MAX_DEBUG_MESSAGE_LENGTH_KHR* = 0x9143.GLenum + GL_TEXTURE_CUBE_MAP_POSITIVE_Z_EXT* = 0x8519.GLenum + GL_VERTEX_SHADER_LOCAL_CONSTANTS_EXT* = 0x87D2.GLenum + GL_DRAW_INDIRECT_LENGTH_NV* = 0x8F42.GLenum + GL_OPERAND2_RGB_ARB* = 0x8592.GLenum + GL_TESS_EVALUATION_SHADER* = 0x8E87.GLenum + GL_INTERLACE_SGIX* = 0x8094.GLenum + GL_HARDLIGHT_NV* = 0x929B.GLenum + GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT* = 0x8CD0.GLenum + GL_OUTPUT_TEXTURE_COORD6_EXT* = 0x87A3.GLenum + GL_SIGNED_LUMINANCE_NV* = 0x8701.GLenum + GL_CON_13_ATI* = 0x894E.GLenum + GL_CURRENT_TANGENT_EXT* = 0x843B.GLenum + GL_UNSIGNED_INT_IMAGE_3D* = 0x9064.GLenum + GL_MODELVIEW24_ARB* = 0x8738.GLenum + GL_EVAL_FRACTIONAL_TESSELLATION_NV* = 0x86C5.GLenum + GL_POINT_SPRITE_NV* = 0x8861.GLenum + GL_MULTISAMPLE_EXT* = 0x809D.GLenum + GL_INT64_VEC3_NV* = 0x8FEA.GLenum + GL_ABGR_EXT* = 0x8000.GLenum + GL_MAX_GENERAL_COMBINERS_NV* = 0x854D.GLenum + GL_NUM_PROGRAM_BINARY_FORMATS* = 0x87FE.GLenum + GL_TEXTURE_LO_SIZE_NV* = 0x871C.GLenum + GL_INT_IMAGE_1D_ARRAY_EXT* = 0x905D.GLenum + GL_MULTISAMPLE_BUFFER_BIT3_QCOM* = 0x08000000.GLbitfield + GL_TEXTURE_GEN_MODE_OES* = 0x2500.GLenum + GL_SECONDARY_COLOR_ARRAY_STRIDE* = 0x845C.GLenum + GL_ELEMENT_ARRAY_TYPE_APPLE* = 0x8A0D.GLenum + GL_UNPACK_IMAGE_HEIGHT_EXT* = 0x806E.GLenum + GL_PALETTE4_R5_G6_B5_OES* = 0x8B92.GLenum + GL_TEXTURE_RED_SIZE* = 0x805C.GLenum + GL_COLOR_ATTACHMENT7_EXT* = 0x8CE7.GLenum + GL_MAX_PROGRAM_TEXTURE_GATHER_OFFSET* = 0x8E5F.GLenum + GL_DRAW_BUFFER11* = 0x8830.GLenum + GL_MODELVIEW0_MATRIX_EXT* = 0x0BA6.GLenum + GL_LAYER_PROVOKING_VERTEX* = 0x825E.GLenum + GL_TEXTURE14* = 0x84CE.GLenum + GL_ALPHA8_EXT* = 0x803C.GLenum + GL_GENERIC_ATTRIB_NV* = 0x8C7D.GLenum + GL_FRAGMENT_SHADER_DERIVATIVE_HINT_OES* = 0x8B8B.GLenum + GL_STENCIL_ATTACHMENT_OES* = 0x8D20.GLenum + GL_MAX_VARYING_FLOATS* = 0x8B4B.GLenum + GL_RGB_SNORM* = 0x8F92.GLenum + GL_SECONDARY_COLOR_ARRAY_TYPE_EXT* = 0x845B.GLenum + GL_MAX_PROGRAM_LOOP_DEPTH_NV* = 0x88F7.GLenum + GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER* = 0x8CD4.GLenum + GL_MAX_MODELVIEW_STACK_DEPTH* = 0x0D36.GLenum + GL_CON_23_ATI* = 0x8958.GLenum + GL_VERTEX_ARRAY_RANGE_POINTER_APPLE* = 0x8521.GLenum + GL_VERTEX_ARRAY_BUFFER_BINDING* = 0x8896.GLenum + GL_VERTEX_STREAM2_ATI* = 0x876E.GLenum + GL_STENCIL* = 0x1802.GLenum + GL_IMAGE_2D_ARRAY_EXT* = 0x9053.GLenum + GL_RGBA8* = 0x8058.GLenum + GL_TEXTURE_SPARSE_ARB* = 0x91A6.GLenum + GL_PIXEL_TEX_GEN_ALPHA_NO_REPLACE_SGIX* = 0x8188.GLenum + GL_SECONDARY_INTERPOLATOR_ATI* = 0x896D.GLenum + GL_MAX_COMBINED_DIMENSIONS* = 0x8282.GLenum + GL_DEBUG_TYPE_POP_GROUP* = 0x826A.GLenum + GL_IMAGE_CLASS_4_X_8* = 0x82BF.GLenum + GL_VERTEX_ARRAY_RANGE_VALID_NV* = 0x851F.GLenum + GL_LUMINANCE_ALPHA8UI_EXT* = 0x8D81.GLenum + GL_RGBA32F_ARB* = 0x8814.GLenum + GL_GLYPH_HEIGHT_BIT_NV* = 0x02.GLbitfield + GL_FOG_COORD_ARRAY_BUFFER_BINDING* = 0x889D.GLenum + GL_TRACE_OPERATIONS_BIT_MESA* = 0x0001.GLbitfield + GL_INT8_VEC4_NV* = 0x8FE3.GLenum + GL_VERTEX_BINDING_STRIDE* = 0x82D8.GLenum + GL_LIGHT_ENV_MODE_SGIX* = 0x8407.GLenum + GL_PROXY_TEXTURE_1D_EXT* = 0x8063.GLenum + GL_CON_31_ATI* = 0x8960.GLenum + GL_TEXTURE_BORDER_COLOR* = 0x1004.GLenum + GL_ELEMENT_ARRAY_POINTER_APPLE* = 0x8A0E.GLenum + GL_NAME_LENGTH* = 0x92F9.GLenum + GL_PIXEL_COUNT_AVAILABLE_NV* = 0x8867.GLenum + GL_IUI_V3F_EXT* = 0x81AE.GLenum + GL_OBJECT_LINE_SGIS* = 0x81F7.GLenum + GL_T2F_N3F_V3F* = 0x2A2B.GLenum + GL_TRUE* = true.GLboolean + GL_COMPARE_REF_TO_TEXTURE_EXT* = 0x884E.GLenum + GL_MAX_3D_TEXTURE_SIZE* = 0x8073.GLenum + GL_LUMINANCE16_ALPHA16_EXT* = 0x8048.GLenum + GL_DRAW_INDIRECT_ADDRESS_NV* = 0x8F41.GLenum + GL_TEXTURE_IMAGE_FORMAT* = 0x828F.GLenum + GL_MODELVIEW_MATRIX_FLOAT_AS_INT_BITS_OES* = 0x898D.GLenum + GL_TEXTURE_RECTANGLE_ARB* = 0x84F5.GLenum + GL_TEXTURE_INDEX_SIZE_EXT* = 0x80ED.GLenum + GL_VERTEX_ATTRIB_ARRAY_LENGTH_NV* = 0x8F2A.GLenum + GL_DEBUG_CALLBACK_USER_PARAM* = 0x8245.GLenum + GL_INTENSITY8_SNORM* = 0x9017.GLenum + GL_DISTANCE_ATTENUATION_EXT* = 0x8129.GLenum + GL_MAX_TESS_EVALUATION_IMAGE_UNIFORMS* = 0x90CC.GLenum + GL_ATTRIB_ARRAY_POINTER_NV* = 0x8645.GLenum + GL_OBJECT_TYPE* = 0x9112.GLenum + GL_PROGRAM_KHR* = 0x82E2.GLenum + GL_SOURCE0_ALPHA_EXT* = 0x8588.GLenum + GL_PIXEL_MAP_I_TO_G_SIZE* = 0x0CB3.GLenum + GL_RGBA_MODE* = 0x0C31.GLenum + GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR* = 0x93D6.GLenum + GL_MAX_ELEMENTS_VERTICES_EXT* = 0x80E8.GLenum + GL_DEBUG_SOURCE_SHADER_COMPILER* = 0x8248.GLenum + GL_ARC_TO_NV* = 0xFE.GLenum + GL_CON_6_ATI* = 0x8947.GLenum + GL_MAX_OPTIMIZED_VERTEX_SHADER_LOCALS_EXT* = 0x87CE.GLenum + GL_VERTEX_ATTRIB_MAP1_DOMAIN_APPLE* = 0x8A05.GLenum + GL_R16_SNORM* = 0x8F98.GLenum + GL_DOUBLE_VEC2_EXT* = 0x8FFC.GLenum + GL_UNSIGNED_INT8_VEC4_NV* = 0x8FEF.GLenum + GL_POST_CONVOLUTION_RED_SCALE* = 0x801C.GLenum + GL_FULL_STIPPLE_HINT_PGI* = 0x1A219.GLenum + GL_ACTIVE_ATTRIBUTES* = 0x8B89.GLenum + GL_TEXTURE_MATERIAL_FACE_EXT* = 0x8351.GLenum + GL_INCR_WRAP_OES* = 0x8507.GLenum + GL_UNPACK_COMPRESSED_BLOCK_WIDTH* = 0x9127.GLenum + GL_COMPRESSED_SIGNED_LUMINANCE_ALPHA_LATC2_EXT* = 0x8C73.GLenum + GL_MAX_VERTEX_SHADER_LOCALS_EXT* = 0x87C9.GLenum + GL_NUM_VIDEO_CAPTURE_STREAMS_NV* = 0x9024.GLenum + GL_DRAW_BUFFER3_ARB* = 0x8828.GLenum + GL_COMBINER_COMPONENT_USAGE_NV* = 0x8544.GLenum + GL_ELEMENT_ARRAY_POINTER_ATI* = 0x876A.GLenum + GL_RGB8UI_EXT* = 0x8D7D.GLenum + GL_RGBA8I* = 0x8D8E.GLenum + GL_TEXTURE_WIDTH_QCOM* = 0x8BD2.GLenum + GL_DOT3_RGB* = 0x86AE.GLenum + GL_VIDEO_CAPTURE_FIELD_LOWER_HEIGHT_NV* = 0x903B.GLenum + GL_TEXTURE_CUBE_MAP_NEGATIVE_X* = 0x8516.GLenum + GL_UNIFORM_BUFFER_SIZE* = 0x8A2A.GLenum + GL_OPERAND1_ALPHA* = 0x8599.GLenum + GL_TEXTURE_INTENSITY_SIZE_EXT* = 0x8061.GLenum + GL_DEBUG_TYPE_OTHER* = 0x8251.GLenum + GL_MAX_TESS_PATCH_COMPONENTS* = 0x8E84.GLenum + GL_UNIFORM_BUFFER_BINDING* = 0x8A28.GLenum + GL_INTENSITY_FLOAT16_APPLE* = 0x881D.GLenum + GL_TEXTURE_BLUE_SIZE* = 0x805E.GLenum + GL_TEXTURE_BUFFER_OFFSET_ALIGNMENT* = 0x919F.GLenum + GL_TEXTURE_SWIZZLE_G* = 0x8E43.GLenum + GL_MAX_PROGRAM_TEXEL_OFFSET_EXT* = 0x8905.GLenum + GL_COLOR_BUFFER_BIT* = 0x00004000.GLbitfield + GL_ALPHA_FLOAT32_APPLE* = 0x8816.GLenum + GL_PROXY_TEXTURE_2D_EXT* = 0x8064.GLenum + GL_STENCIL_COMPONENTS* = 0x8285.GLenum + GL_VIDEO_CAPTURE_TO_422_SUPPORTED_NV* = 0x9026.GLenum + GL_TEXTURE_COMPRESSED_ARB* = 0x86A1.GLenum + GL_OBJECT_SUBTYPE_ARB* = 0x8B4F.GLenum + GL_MAX_PROGRAM_PARAMETERS_ARB* = 0x88A9.GLenum + GL_OFFSET_TEXTURE_2D_MATRIX_NV* = 0x86E1.GLenum + GL_PN_TRIANGLES_NORMAL_MODE_LINEAR_ATI* = 0x87F7.GLenum + GL_PATCH_VERTICES* = 0x8E72.GLenum + GL_NEGATIVE_Y_EXT* = 0x87DA.GLenum + GL_INT_2_10_10_10_REV* = 0x8D9F.GLenum + GL_READ_FRAMEBUFFER_BINDING_NV* = 0x8CAA.GLenum + GL_POST_COLOR_MATRIX_COLOR_TABLE_SGI* = 0x80D2.GLenum + GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS* = 0x90DA.GLenum + GL_IMAGE_COMPATIBILITY_CLASS* = 0x82A8.GLenum + GL_FLOAT_MAT4* = 0x8B5C.GLenum + GL_FIELD_LOWER_NV* = 0x9023.GLenum + GL_UNPACK_IMAGE_HEIGHT* = 0x806E.GLenum + GL_PATH_COMMAND_COUNT_NV* = 0x909D.GLenum + GL_UNSIGNED_SHORT_4_4_4_4_EXT* = 0x8033.GLenum + GL_VIEW_CLASS_S3TC_DXT3_RGBA* = 0x82CE.GLenum + GL_STENCIL_BUFFER_BIT1_QCOM* = 0x00020000.GLbitfield + GL_BLOCK_INDEX* = 0x92FD.GLenum + GL_BUMP_TARGET_ATI* = 0x877C.GLenum + GL_PATH_STROKE_COVER_MODE_NV* = 0x9083.GLenum + GL_INT_IMAGE_2D_RECT* = 0x905A.GLenum + GL_VECTOR_EXT* = 0x87BF.GLenum + GL_INDEX_ARRAY_BUFFER_BINDING* = 0x8899.GLenum + GL_SAMPLER_2D_SHADOW* = 0x8B62.GLenum + GL_OBJECT_BUFFER_SIZE_ATI* = 0x8764.GLenum + GL_NORMALIZED_RANGE_EXT* = 0x87E0.GLenum + GL_DEPTH_COMPONENT32_OES* = 0x81A7.GLenum + GL_CON_9_ATI* = 0x894A.GLenum + GL_VIRTUAL_PAGE_SIZE_X_ARB* = 0x9195.GLenum + GL_LESS* = 0x0201.GLenum + GL_FRAMEBUFFER_UNSUPPORTED_OES* = 0x8CDD.GLenum + GL_CON_19_ATI* = 0x8954.GLenum + GL_PROGRAM_NATIVE_INSTRUCTIONS_ARB* = 0x88A2.GLenum + GL_MAX_TEXTURE_COORDS_ARB* = 0x8871.GLenum + GL_TRANSFORM_FEEDBACK_BUFFER_MODE* = 0x8C7F.GLenum + GL_TEXTURE_1D_BINDING_EXT* = 0x8068.GLenum + GL_LINE_TOKEN* = 0x0702.GLenum + GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_OES* = 0x8CD7.GLenum + GL_Z4Y12Z4CB12Z4A12Z4Y12Z4CR12Z4A12_4224_NV* = 0x9036.GLenum + GL_TEXTURE_SWIZZLE_R* = 0x8E42.GLenum + GL_PIXEL_UNPACK_BUFFER_ARB* = 0x88EC.GLenum + GL_UNKNOWN_CONTEXT_RESET_EXT* = 0x8255.GLenum + GL_PROGRAM_ERROR_POSITION_NV* = 0x864B.GLenum + GL_ONE_MINUS_CONSTANT_COLOR* = 0x8002.GLenum + GL_POST_COLOR_MATRIX_GREEN_SCALE* = 0x80B5.GLenum + GL_TEXTURE_CUBE_MAP_SEAMLESS* = 0x884F.GLenum + GL_DRAW_BUFFER2* = 0x8827.GLenum + GL_STENCIL_INDEX* = 0x1901.GLenum + GL_FOG_DENSITY* = 0x0B62.GLenum + GL_MATRIX27_ARB* = 0x88DB.GLenum + GL_CURRENT_NORMAL* = 0x0B02.GLenum + GL_AFFINE_3D_NV* = 0x9094.GLenum + GL_STATIC_COPY_ARB* = 0x88E6.GLenum + GL_4X_BIT_ATI* = 0x00000002.GLbitfield + GL_COLOR_BUFFER_BIT3_QCOM* = 0x00000008.GLbitfield + GL_TEXTURE_MATRIX* = 0x0BA8.GLenum + GL_UNDEFINED_APPLE* = 0x8A1C.GLenum + GL_COLOR_TABLE_LUMINANCE_SIZE_SGI* = 0x80DE.GLenum + GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY* = 0x9061.GLenum + GL_RELATIVE_ARC_TO_NV* = 0xFF.GLenum + GL_UNPACK_PREMULTIPLY_ALPHA_WEBGL* = 0x9241.GLenum + GL_READ_FRAMEBUFFER_BINDING_EXT* = 0x8CAA.GLenum + GL_TEXTURE_WRAP_R_OES* = 0x8072.GLenum + GL_MAX_GEOMETRY_VARYING_COMPONENTS_EXT* = 0x8DDD.GLenum + GL_TEXTURE_CUBE_MAP_EXT* = 0x8513.GLenum + GL_COMMAND_BARRIER_BIT_EXT* = 0x00000040.GLbitfield + GL_DEBUG_SEVERITY_NOTIFICATION* = 0x826B.GLenum + GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR* = 0x93D8.GLenum + GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS* = 0x8C8B.GLenum + GL_MAX_DEEP_3D_TEXTURE_WIDTH_HEIGHT_NV* = 0x90D0.GLenum + GL_INT_IMAGE_2D_EXT* = 0x9058.GLenum + GL_RGB_S3TC* = 0x83A0.GLenum + GL_SUCCESS_NV* = 0x902F.GLenum + GL_MATRIX_INDEX_ARRAY_SIZE_OES* = 0x8846.GLenum + GL_VIEW_CLASS_8_BITS* = 0x82CB.GLenum + GL_DONT_CARE* = 0x1100.GLenum + GL_FOG_COORDINATE_ARRAY* = 0x8457.GLenum + GL_DRAW_BUFFER9* = 0x882E.GLenum + GL_TEXTURE28_ARB* = 0x84DC.GLenum + GL_MAX_PROGRAM_TEXTURE_GATHER_OFFSET_ARB* = 0x8E5F.GLenum + GL_TEXTURE21* = 0x84D5.GLenum + GL_TRANSLATE_Y_NV* = 0x908F.GLenum + GL_MODELVIEW17_ARB* = 0x8731.GLenum + GL_ALPHA_FLOAT16_ATI* = 0x881C.GLenum + GL_DEPTH_STENCIL_OES* = 0x84F9.GLenum + GL_QUAD_MESH_SUN* = 0x8614.GLenum + GL_PROGRAM_ADDRESS_REGISTERS_ARB* = 0x88B0.GLenum + GL_VERTEX_BINDING_OFFSET* = 0x82D7.GLenum + GL_FIRST_TO_REST_NV* = 0x90AF.GLenum + GL_SHADE_MODEL* = 0x0B54.GLenum + GL_INT_IMAGE_2D_ARRAY_EXT* = 0x905E.GLenum + GL_FRONT_FACE* = 0x0B46.GLenum + GL_PRIMITIVE_RESTART_INDEX* = 0x8F9E.GLenum + GL_LUMINANCE8* = 0x8040.GLenum + GL_COVERAGE_ALL_FRAGMENTS_NV* = 0x8ED5.GLenum + GL_FRAGMENT_ALPHA_MODULATE_IMG* = 0x8C08.GLenum + GL_CLIP_PLANE3_IMG* = 0x3003.GLenum + GL_EVAL_VERTEX_ATTRIB15_NV* = 0x86D5.GLenum + GL_SYNC_GPU_COMMANDS_COMPLETE* = 0x9117.GLenum + GL_FALSE* = false.GLboolean + GL_MAX_DEBUG_GROUP_STACK_DEPTH_KHR* = 0x826C.GLenum + GL_STENCIL_ATTACHMENT_EXT* = 0x8D20.GLenum + GL_DST_ATOP_NV* = 0x928F.GLenum + GL_REPLACEMENT_CODE_ARRAY_TYPE_SUN* = 0x85C1.GLenum + GL_COMBINE4_NV* = 0x8503.GLenum + GL_MINMAX_SINK_EXT* = 0x8030.GLenum + GL_RG16I* = 0x8239.GLenum + GL_BGRA_IMG* = 0x80E1.GLenum + GL_REFERENCED_BY_COMPUTE_SHADER* = 0x930B.GLenum + GL_MIN_LOD_WARNING_AMD* = 0x919C.GLenum + GL_READ_BUFFER_EXT* = 0x0C02.GLenum + GL_RGBA8UI_EXT* = 0x8D7C.GLenum + GL_LINE_BIT* = 0x00000004.GLbitfield + GL_CONDITION_SATISFIED* = 0x911C.GLenum + GL_SLUMINANCE_ALPHA* = 0x8C44.GLenum + GL_FOG_COORDINATE_ARRAY_TYPE* = 0x8454.GLenum + GL_EXPAND_NORMAL_NV* = 0x8538.GLenum + GL_TEXTURE_2D_ARRAY_EXT* = 0x8C1A.GLenum + GL_SAMPLER_2D_RECT_ARB* = 0x8B63.GLenum + GL_CLAMP_TO_BORDER_NV* = 0x812D.GLint + GL_MAX_GEOMETRY_OUTPUT_VERTICES_ARB* = 0x8DE0.GLenum + GL_TEXCOORD2_BIT_PGI* = 0x20000000.GLbitfield + GL_MATRIX0_ARB* = 0x88C0.GLenum + GL_STENCIL_BUFFER_BIT2_QCOM* = 0x00040000.GLbitfield + GL_COLOR_MATRIX_SGI* = 0x80B1.GLenum + GL_PN_TRIANGLES_TESSELATION_LEVEL_ATI* = 0x87F4.GLenum + GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT* = 0x8CDC.GLenum + GL_LEFT* = 0x0406.GLenum + GL_LO_SCALE_NV* = 0x870F.GLenum + GL_STRICT_DEPTHFUNC_HINT_PGI* = 0x1A216.GLenum + GL_MAX_COMBINED_TESS_CONTROL_UNIFORM_COMPONENTS* = 0x8E1E.GLenum + GL_REPEAT* = 0x2901.GLint + GL_DEBUG_TYPE_PORTABILITY_ARB* = 0x824F.GLenum + GL_MAX_FRAMEBUFFER_LAYERS* = 0x9317.GLenum + GL_TRIANGLE_STRIP* = 0x0005.GLenum + GL_RECLAIM_MEMORY_HINT_PGI* = 0x1A1FE.GLenum + GL_RELATIVE_LINE_TO_NV* = 0x05.GLenum + GL_MAX_LIGHTS* = 0x0D31.GLenum + GL_MULTISAMPLE_BIT* = 0x20000000.GLbitfield + GL_READ_PIXELS* = 0x828C.GLenum + GL_DISCRETE_AMD* = 0x9006.GLenum + GL_QUAD_TEXTURE_SELECT_SGIS* = 0x8125.GLenum + GL_CON_25_ATI* = 0x895A.GLenum + GL_BUFFER_IMMUTABLE_STORAGE* = 0x821F.GLenum + GL_FLOAT_R16_NV* = 0x8884.GLenum + GL_GREEN_INTEGER_EXT* = 0x8D95.GLenum + cGL_FIXED* = 0x140C.GLenum + GL_LIST_PRIORITY_SGIX* = 0x8182.GLenum + GL_DRAW_BUFFER6_EXT* = 0x882B.GLenum + GL_OFFSET_TEXTURE_BIAS_NV* = 0x86E3.GLenum + GL_VERTEX_ATTRIB_ARRAY_POINTER_ARB* = 0x8645.GLenum + GL_MALI_SHADER_BINARY_ARM* = 0x8F60.GLenum + GL_RGB_422_APPLE* = 0x8A1F.GLenum + GL_R1UI_N3F_V3F_SUN* = 0x85C7.GLenum + GL_VERTEX_ARRAY_OBJECT_EXT* = 0x9154.GLenum + GL_UNSIGNED_INT_10F_11F_11F_REV* = 0x8C3B.GLenum + GL_VERSION_ES_CM_1_1* = 1.GLenum + GL_CLEAR_TEXTURE* = 0x9365.GLenum + GL_FLOAT16_VEC3_NV* = 0x8FFA.GLenum + GL_TEXTURE_LUMINANCE_TYPE* = 0x8C14.GLenum + GL_TRANSFORM_FEEDBACK* = 0x8E22.GLenum + GL_POST_CONVOLUTION_COLOR_TABLE* = 0x80D1.GLenum + GL_DEPTH_TEST* = 0x0B71.GLenum + GL_CON_1_ATI* = 0x8942.GLenum + GL_FRAGMENT_SHADER_ATI* = 0x8920.GLenum + GL_SAMPLER_1D_ARRAY_SHADOW* = 0x8DC3.GLenum + GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT* = 0x90DF.GLenum + GL_MAX_SERVER_WAIT_TIMEOUT* = 0x9111.GLenum + GL_VERTEX_SHADER_BIT_EXT* = 0x00000001.GLbitfield + GL_TEXTURE_BINDING_CUBE_MAP_OES* = 0x8514.GLenum + GL_PIXEL_MAP_S_TO_S_SIZE* = 0x0CB1.GLenum + GL_CURRENT_OCCLUSION_QUERY_ID_NV* = 0x8865.GLenum + GL_TIMEOUT_IGNORED_APPLE* = 0xFFFFFFFFFFFFFFFF.GLenum + GL_MAX_COMPUTE_UNIFORM_COMPONENTS* = 0x8263.GLenum + GL_COPY_PIXEL_TOKEN* = 0x0706.GLenum + GL_SPOT_CUTOFF* = 0x1206.GLenum + GL_FRACTIONAL_EVEN* = 0x8E7C.GLenum + GL_MAP1_VERTEX_ATTRIB6_4_NV* = 0x8666.GLenum + GL_TRIANGLE_LIST_SUN* = 0x81D7.GLenum + GL_ATOMIC_COUNTER_BUFFER_START* = 0x92C2.GLenum + GL_MAX_ELEMENTS_VERTICES* = 0x80E8.GLenum + GL_COLOR_ATTACHMENT9_EXT* = 0x8CE9.GLenum + GL_ACCUM_CLEAR_VALUE* = 0x0B80.GLenum + GL_TEXTURE_COORD_ARRAY_LENGTH_NV* = 0x8F2F.GLenum + GL_DRAW_BUFFER3_EXT* = 0x8828.GLenum + GL_TEXTURE_CUBE_MAP_POSITIVE_Y_EXT* = 0x8517.GLenum + GL_C4UB_V3F* = 0x2A23.GLenum + GL_MAX_PROGRAM_ATTRIBS_ARB* = 0x88AD.GLenum + GL_PIXEL_TILE_CACHE_INCREMENT_SGIX* = 0x813F.GLenum + GL_FRAMEBUFFER_INCOMPLETE_LAYER_COUNT_ARB* = 0x8DA9.GLenum + GL_CON_8_ATI* = 0x8949.GLenum + GL_POST_COLOR_MATRIX_ALPHA_BIAS* = 0x80BB.GLenum + GL_RENDERBUFFER_WIDTH* = 0x8D42.GLenum + GL_VERTEX_ID_NV* = 0x8C7B.GLenum + GL_STRICT_LIGHTING_HINT_PGI* = 0x1A217.GLenum + GL_COMPRESSED_RGBA8_ETC2_EAC_OES* = 0x9278.GLenum + GL_PACK_COMPRESSED_BLOCK_WIDTH* = 0x912B.GLenum + GL_ZERO_EXT* = 0x87DD.GLenum + GL_DEBUG_SOURCE_OTHER* = 0x824B.GLenum + GL_MAP_UNSYNCHRONIZED_BIT* = 0x0020.GLbitfield + GL_VERTEX_ARRAY_POINTER* = 0x808E.GLenum + GL_FLOAT_RGBA_NV* = 0x8883.GLenum + GL_WEIGHT_ARRAY_STRIDE_OES* = 0x86AA.GLenum + GL_UNPACK_ROW_BYTES_APPLE* = 0x8A16.GLenum + GL_CURRENT_COLOR* = 0x0B00.GLenum + GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT* = 0x8CD7.GLenum + GL_MAX_NAME_STACK_DEPTH* = 0x0D37.GLenum + GL_SHADER_STORAGE_BUFFER_START* = 0x90D4.GLenum + GL_TRANSFORM_FEEDBACK_BUFFER_MODE_EXT* = 0x8C7F.GLenum + GL_PATH_GEN_COMPONENTS_NV* = 0x90B3.GLenum + GL_AUTO_GENERATE_MIPMAP* = 0x8295.GLenum + GL_UNSIGNED_INT_5_9_9_9_REV* = 0x8C3E.GLenum + GL_VIEWPORT* = 0x0BA2.GLenum + GL_MAX_VERTEX_STREAMS_ATI* = 0x876B.GLenum + GL_MAX_OPTIMIZED_VERTEX_SHADER_VARIANTS_EXT* = 0x87CB.GLenum + GL_STENCIL_CLEAR_VALUE* = 0x0B91.GLenum + GL_UNSIGNED_INT_IMAGE_2D_ARRAY_EXT* = 0x9069.GLenum + GL_FRAGMENT_LIGHT_MODEL_TWO_SIDE_SGIX* = 0x8409.GLenum + GL_FRAGMENT_SHADER_BIT_EXT* = 0x00000002.GLbitfield + GL_COLOR_SUM_ARB* = 0x8458.GLenum + GL_RGBA4_DXT5_S3TC* = 0x83A5.GLenum + GL_INT_IMAGE_CUBE* = 0x905B.GLenum + GL_ACTIVE_ATOMIC_COUNTER_BUFFERS* = 0x92D9.GLenum + GL_INTERNALFORMAT_GREEN_SIZE* = 0x8272.GLenum + GL_OFFSET_HILO_TEXTURE_RECTANGLE_NV* = 0x8855.GLenum + GL_MAX_PN_TRIANGLES_TESSELATION_LEVEL_ATI* = 0x87F1.GLenum + GL_REG_24_ATI* = 0x8939.GLenum + GL_MULT* = 0x0103.GLenum + GL_RGBA2* = 0x8055.GLenum + GL_CONVOLUTION_WIDTH_EXT* = 0x8018.GLenum + GL_STENCIL_EXT* = 0x1802.GLenum + GL_PATH_STROKE_WIDTH_NV* = 0x9075.GLenum + GL_DEBUG_SOURCE_WINDOW_SYSTEM_ARB* = 0x8247.GLenum + GL_QUERY_COUNTER_BITS* = 0x8864.GLenum + GL_OUTPUT_FOG_EXT* = 0x87BD.GLenum + GL_POST_COLOR_MATRIX_RED_BIAS* = 0x80B8.GLenum + GL_UNSIGNED_INT_10_10_10_2* = 0x8036.GLenum + GL_INT_SAMPLER_1D* = 0x8DC9.GLenum + GL_INT_IMAGE_2D_MULTISAMPLE_EXT* = 0x9060.GLenum + GL_RENDERBUFFER_INTERNAL_FORMAT_OES* = 0x8D44.GLenum + GL_TRACE_PIXELS_BIT_MESA* = 0x0010.GLbitfield + GL_FAILURE_NV* = 0x9030.GLenum + GL_INT_SAMPLER_3D_EXT* = 0x8DCB.GLenum + GL_MAX_PROGRAM_PARAMETER_BUFFER_SIZE_NV* = 0x8DA1.GLenum + GL_OBJECT_DISTANCE_TO_POINT_SGIS* = 0x81F1.GLenum + GL_BLEND_SRC_RGB_OES* = 0x80C9.GLenum + GL_LUMINANCE4_ALPHA4_OES* = 0x8043.GLenum + GL_REG_4_ATI* = 0x8925.GLenum + GL_SHADING_LANGUAGE_VERSION_ARB* = 0x8B8C.GLenum + GL_RGBA16F_ARB* = 0x881A.GLenum + GL_R32F* = 0x822E.GLenum + GL_COMPRESSED_SRGB_S3TC_DXT1_NV* = 0x8C4C.GLenum + GL_TESS_CONTROL_OUTPUT_VERTICES* = 0x8E75.GLenum + GL_ONE_MINUS_DST_COLOR* = 0x0307.GLenum + GL_MATRIX19_ARB* = 0x88D3.GLenum + GL_INT_SAMPLER_2D_RECT* = 0x8DCD.GLenum + GL_POST_CONVOLUTION_GREEN_SCALE_EXT* = 0x801D.GLenum + GL_CLIP_DISTANCE5* = 0x3005.GLenum + GL_HISTOGRAM_RED_SIZE_EXT* = 0x8028.GLenum + GL_INTENSITY_FLOAT32_APPLE* = 0x8817.GLenum + GL_MODULATE_ADD_ATI* = 0x8744.GLenum + GL_NEGATIVE_X_EXT* = 0x87D9.GLenum + GL_REG_21_ATI* = 0x8936.GLenum + GL_STENCIL_RENDERABLE* = 0x8288.GLenum + GL_FOG_COORD_ARRAY_STRIDE* = 0x8455.GLenum + GL_FACTOR_MAX_AMD* = 0x901D.GLenum + GL_LUMINANCE16_EXT* = 0x8042.GLenum + GL_VARIANT_ARRAY_POINTER_EXT* = 0x87E9.GLenum + GL_DECAL* = 0x2101.GLenum + GL_SIGNED_ALPHA8_NV* = 0x8706.GLenum + GL_ALPHA_BITS* = 0x0D55.GLenum + GL_MATRIX29_ARB* = 0x88DD.GLenum + GL_FOG* = 0x0B60.GLenum + GL_INDEX_ARRAY_LIST_STRIDE_IBM* = 103083.GLenum + GL_IMAGE_FORMAT_COMPATIBILITY_BY_CLASS* = 0x90C9.GLenum + GL_RGBA4_S3TC* = 0x83A3.GLenum + GL_LUMINANCE16_ALPHA16* = 0x8048.GLenum + GL_PROXY_TEXTURE_RECTANGLE* = 0x84F7.GLenum + GL_FRAGMENT_PROGRAM_PARAMETER_BUFFER_NV* = 0x8DA4.GLenum + GL_UNIFORM_BLOCK_REFERENCED_BY_TESS_CONTROL_SHADER* = 0x84F0.GLenum + GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE* = 0x8CD3.GLenum + GL_COLOR_TABLE_GREEN_SIZE_SGI* = 0x80DB.GLenum + GL_TEXTURE_PRE_SPECULAR_HP* = 0x8169.GLenum + GL_SHADOW_ATTENUATION_EXT* = 0x834E.GLenum + GL_SIGNED_RGB_NV* = 0x86FE.GLenum + GL_CLIENT_ALL_ATTRIB_BITS* = 0xFFFFFFFF.GLbitfield + GL_DEPTH_ATTACHMENT_EXT* = 0x8D00.GLenum + GL_DEBUG_SOURCE_API_KHR* = 0x8246.GLenum + GL_COLOR_INDEXES* = 0x1603.GLenum + GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH* = 0x8243.GLenum + GL_TEXTURE_BINDING_1D* = 0x8068.GLenum + GL_UNSIGNED_INT_SAMPLER_2D* = 0x8DD2.GLenum + GL_DRAW_BUFFER9_NV* = 0x882E.GLenum + GL_RED* = 0x1903.GLenum + GL_LINE_STRIP_ADJACENCY_EXT* = 0x000B.GLenum + GL_NUM_PASSES_ATI* = 0x8970.GLenum + GL_MAT_DIFFUSE_BIT_PGI* = 0x00400000.GLbitfield + GL_LUMINANCE_INTEGER_EXT* = 0x8D9C.GLenum + GL_PIXEL_MAP_I_TO_I* = 0x0C70.GLenum + GL_SLUMINANCE8_ALPHA8_NV* = 0x8C45.GLenum + GL_RGBA4_OES* = 0x8056.GLenum + GL_COMPRESSED_SIGNED_R11_EAC* = 0x9271.GLenum + GL_FRAGMENT_LIGHT4_SGIX* = 0x8410.GLenum + GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS_NV* = 0x8C80.GLenum + GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT* = 0x8C4D.GLenum + GL_READ_FRAMEBUFFER_APPLE* = 0x8CA8.GLenum + GL_DRAW_BUFFER15_ARB* = 0x8834.GLenum + GL_INSTRUMENT_MEASUREMENTS_SGIX* = 0x8181.GLenum + GL_REG_15_ATI* = 0x8930.GLenum + GL_UNSIGNED_INT_IMAGE_1D_ARRAY* = 0x9068.GLenum + GL_COMPUTE_LOCAL_WORK_SIZE* = 0x8267.GLenum + GL_RGBA32I* = 0x8D82.GLenum + GL_VERTEX_ATTRIB_MAP2_APPLE* = 0x8A01.GLenum + GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR* = 0x824D.GLenum + GL_READ_FRAMEBUFFER_BINDING_ANGLE* = 0x8CAA.GLenum + GL_DEBUG_SOURCE_WINDOW_SYSTEM_KHR* = 0x8247.GLenum + GL_OP_FRAC_EXT* = 0x8789.GLenum + GL_RGB_FLOAT32_APPLE* = 0x8815.GLenum + GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER* = 0x8A44.GLenum + GL_NORMAL_ARRAY* = 0x8075.GLenum + GL_TEXTURE21_ARB* = 0x84D5.GLenum + GL_WRITE_ONLY_OES* = 0x88B9.GLenum + GL_TEXTURE0_ARB* = 0x84C0.GLenum + GL_SPRITE_OBJECT_ALIGNED_SGIX* = 0x814D.GLenum + GL_POSITION* = 0x1203.GLenum + GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR* = 0x824E.GLenum + GL_GEOMETRY_OUTPUT_TYPE_ARB* = 0x8DDC.GLenum + GL_IMAGE_PIXEL_TYPE* = 0x82AA.GLenum + GL_UNSIGNED_INT64_AMD* = 0x8BC2.GLenum + GL_LIST_INDEX* = 0x0B33.GLenum + GL_UNSIGNED_INT_8_8_S8_S8_REV_NV* = 0x86DB.GLenum + GL_MAP_ATTRIB_U_ORDER_NV* = 0x86C3.GLenum + GL_PROXY_TEXTURE_RECTANGLE_ARB* = 0x84F7.GLenum + GL_CLIP_NEAR_HINT_PGI* = 0x1A220.GLenum + GL_POST_TEXTURE_FILTER_BIAS_RANGE_SGIX* = 0x817B.GLenum + GL_MAX_UNIFORM_BLOCK_SIZE* = 0x8A30.GLenum + GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER* = 0x8CDB.GLenum + GL_SAMPLE_MASK_INVERT_EXT* = 0x80AB.GLenum + GL_MAP1_VERTEX_ATTRIB14_4_NV* = 0x866E.GLenum + GL_SYNC_FLAGS* = 0x9115.GLenum + GL_COMPRESSED_RGBA* = 0x84EE.GLenum + GL_TEXTURE_COMPRESSED_BLOCK_HEIGHT* = 0x82B2.GLenum + GL_INDEX_ARRAY_STRIDE_EXT* = 0x8086.GLenum + GL_CLIP_DISTANCE_NV* = 0x8C7A.GLenum + GL_UNSIGNED_INT_VEC4* = 0x8DC8.GLenum + GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_ARB* = 0x8E8E.GLenum + GL_MIRRORED_REPEAT_OES* = 0x8370.GLint + GL_WEIGHT_ARRAY_SIZE_ARB* = 0x86AB.GLenum + GL_MIN_SAMPLE_SHADING_VALUE* = 0x8C37.GLenum + GL_SOURCE0_RGB* = 0x8580.GLenum + GL_RG32I* = 0x823B.GLenum + GL_QUERY_BUFFER_BINDING_AMD* = 0x9193.GLenum + GL_OFFSET_PROJECTIVE_TEXTURE_2D_SCALE_NV* = 0x8851.GLenum + GL_POST_CONVOLUTION_BLUE_SCALE_EXT* = 0x801E.GLenum + GL_DOUBLE_MAT3x4_EXT* = 0x8F4C.GLenum + GL_MAX_VERTEX_HINT_PGI* = 0x1A22D.GLenum + GL_ADD* = 0x0104.GLenum + GL_PATH_FORMAT_SVG_NV* = 0x9070.GLenum + GL_VIDEO_BUFFER_BINDING_NV* = 0x9021.GLenum + GL_NUM_EXTENSIONS* = 0x821D.GLenum + GL_DEPTH_RANGE* = 0x0B70.GLenum + GL_FRAGMENT_SUBROUTINE* = 0x92EC.GLenum + GL_DEPTH24_STENCIL8_EXT* = 0x88F0.GLenum + GL_COMPRESSED_RGBA_S3TC_DXT3_EXT* = 0x83F2.GLenum + GL_COLOR_TABLE_SGI* = 0x80D0.GLenum + GL_OBJECT_ACTIVE_UNIFORMS_ARB* = 0x8B86.GLenum + GL_RGBA16F* = 0x881A.GLenum + GL_COORD_REPLACE_ARB* = 0x8862.GLenum + GL_SAMPLE_POSITION_NV* = 0x8E50.GLenum + GL_SRC_ALPHA* = 0x0302.GLenum + GL_COMBINE_ALPHA* = 0x8572.GLenum + GL_CLEAR* = 0x1500.GLenum + GL_HSL_HUE_NV* = 0x92AD.GLenum + GL_SCISSOR_TEST* = 0x0C11.GLenum + GL_UNSIGNED_INT_SAMPLER_BUFFER_EXT* = 0x8DD8.GLenum + GL_RGB16UI* = 0x8D77.GLenum + GL_MATRIX9_ARB* = 0x88C9.GLenum + GL_COLOR_ATTACHMENT13* = 0x8CED.GLenum + GL_BUMP_ROT_MATRIX_SIZE_ATI* = 0x8776.GLenum + GL_PIXEL_PACK_BUFFER_BINDING_ARB* = 0x88ED.GLenum + GL_FONT_X_MAX_BOUNDS_BIT_NV* = 0x00040000.GLbitfield + GL_MODELVIEW31_ARB* = 0x873F.GLenum + GL_DRAW_BUFFER14_ARB* = 0x8833.GLenum + GL_EDGEFLAG_BIT_PGI* = 0x00040000.GLbitfield + GL_TEXTURE_LOD_BIAS_R_SGIX* = 0x8190.GLenum + GL_FIELD_UPPER_NV* = 0x9022.GLenum + GL_CLIP_PLANE3* = 0x3003.GLenum + GL_FRAGMENT_LIGHT_MODEL_LOCAL_VIEWER_SGIX* = 0x8408.GLenum + GL_BLUE* = 0x1905.GLenum + GL_LUMINANCE_ALPHA_FLOAT32_ATI* = 0x8819.GLenum + GL_MATRIX31_ARB* = 0x88DF.GLenum + GL_OR_REVERSE* = 0x150B.GLenum + GL_INTERPOLATE_EXT* = 0x8575.GLenum + GL_MODELVIEW13_ARB* = 0x872D.GLenum + GL_UTF16_NV* = 0x909B.GLenum + GL_READ_FRAMEBUFFER_ANGLE* = 0x8CA8.GLenum + GL_LUMINANCE16F_EXT* = 0x881E.GLenum + GL_VERTEX_ATTRIB_ARRAY7_NV* = 0x8657.GLenum + GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS_EXT* = 0x8C8A.GLenum + GL_PRIMARY_COLOR_EXT* = 0x8577.GLenum + GL_VERTEX_ATTRIB_RELATIVE_OFFSET* = 0x82D5.GLenum + GL_LARGE_CW_ARC_TO_NV* = 0x18.GLenum + GL_PROGRAM_PARAMETER_NV* = 0x8644.GLenum + GL_ASYNC_MARKER_SGIX* = 0x8329.GLenum + GL_TEXTURE24_ARB* = 0x84D8.GLenum + GL_PIXEL_SUBSAMPLE_4242_SGIX* = 0x85A4.GLenum + GL_RGB10_A2_EXT* = 0x8059.GLenum + GL_IMAGE_CLASS_2_X_32* = 0x82BA.GLenum + GL_TEXTURE_INTENSITY_TYPE* = 0x8C15.GLenum + GL_TEXTURE_LOD_BIAS_S_SGIX* = 0x818E.GLenum + GL_PROGRAM_BINARY_LENGTH* = 0x8741.GLenum + GL_CURRENT_RASTER_NORMAL_SGIX* = 0x8406.GLenum + GL_DETAIL_TEXTURE_2D_SGIS* = 0x8095.GLenum + GL_MAX_FRAGMENT_INTERPOLATION_OFFSET_NV* = 0x8E5C.GLenum + GL_CONVOLUTION_FILTER_BIAS_EXT* = 0x8015.GLenum + GL_DT_BIAS_NV* = 0x8717.GLenum + GL_RESET_NOTIFICATION_STRATEGY_EXT* = 0x8256.GLenum + GL_SHADER_STORAGE_BUFFER* = 0x90D2.GLenum + GL_RESET_NOTIFICATION_STRATEGY_ARB* = 0x8256.GLenum + GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT* = 0x8CD1.GLenum + GL_SRC_NV* = 0x9286.GLenum + GL_POINT_FADE_THRESHOLD_SIZE* = 0x8128.GLenum + GL_DEPENDENT_RGB_TEXTURE_3D_NV* = 0x8859.GLenum + GL_QUERY_RESULT_ARB* = 0x8866.GLenum + GL_GEOMETRY_VERTICES_OUT* = 0x8916.GLenum + GL_MAX_COMPUTE_FIXED_GROUP_INVOCATIONS_ARB* = 0x90EB.GLenum + GL_MODELVIEW27_ARB* = 0x873B.GLenum + GL_DRAW_BUFFER11_NV* = 0x8830.GLenum + GL_COLOR_ATTACHMENT9_NV* = 0x8CE9.GLenum + GL_BLEND_SRC* = 0x0BE1.GLenum + GL_CONVOLUTION_2D_EXT* = 0x8011.GLenum + GL_MAX_ELEMENTS_INDICES* = 0x80E9.GLenum + GL_LUMINANCE_ALPHA_FLOAT32_APPLE* = 0x8819.GLenum + GL_INT_IMAGE_1D* = 0x9057.GLenum + GL_CONSTANT_COLOR* = 0x8001.GLenum + GL_FRAMEBUFFER_BARRIER_BIT* = 0x00000400.GLbitfield + GL_POST_CONVOLUTION_BLUE_SCALE* = 0x801E.GLenum + GL_DEBUG_SOURCE_SHADER_COMPILER_ARB* = 0x8248.GLenum + GL_RGB16I* = 0x8D89.GLenum + GL_MAX_WIDTH* = 0x827E.GLenum + GL_LIGHT_MODEL_AMBIENT* = 0x0B53.GLenum + GL_COVERAGE_ATTACHMENT_NV* = 0x8ED2.GLenum + GL_PROGRAM* = 0x82E2.GLenum + GL_IMAGE_ROTATE_ANGLE_HP* = 0x8159.GLenum + GL_SRC2_RGB* = 0x8582.GLenum + GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_KHR* = 0x824E.GLenum + GL_PASS_THROUGH_NV* = 0x86E6.GLenum + GL_HALF_BIAS_NEGATE_NV* = 0x853B.GLenum + GL_SAMPLER_CUBE_SHADOW_EXT* = 0x8DC5.GLenum + GL_COMPRESSED_RGBA_BPTC_UNORM_ARB* = 0x8E8C.GLenum + GL_MAX_SERVER_WAIT_TIMEOUT_APPLE* = 0x9111.GLenum + GL_STORAGE_PRIVATE_APPLE* = 0x85BD.GLenum + GL_VERTEX_SHADER_BIT* = 0x00000001.GLbitfield + GL_POST_COLOR_MATRIX_BLUE_SCALE_SGI* = 0x80B6.GLenum + GL_VERTEX_SHADER_VARIANTS_EXT* = 0x87D0.GLenum + GL_TRANSFORM_FEEDBACK_ACTIVE* = 0x8E24.GLenum + GL_ACTIVE_UNIFORMS* = 0x8B86.GLenum + GL_MULTISAMPLE_BUFFER_BIT0_QCOM* = 0x01000000.GLbitfield + GL_OFFSET_TEXTURE_SCALE_NV* = 0x86E2.GLenum + GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ARB* = 0x88FE.GLenum + GL_BEVEL_NV* = 0x90A6.GLenum + GL_MAX_DRAW_BUFFERS_NV* = 0x8824.GLenum + GL_MAP1_TANGENT_EXT* = 0x8444.GLenum + GL_ANY_SAMPLES_PASSED* = 0x8C2F.GLenum + GL_MAX_IMAGE_SAMPLES* = 0x906D.GLenum + GL_PIXEL_UNPACK_BUFFER_BINDING* = 0x88EF.GLenum + GL_SRGB8_ALPHA8_EXT* = 0x8C43.GLenum + GL_2PASS_1_SGIS* = 0x80A3.GLenum + GL_PROGRAM_POINT_SIZE_ARB* = 0x8642.GLenum + GL_ALLOW_DRAW_WIN_HINT_PGI* = 0x1A20F.GLenum + GL_INTERNALFORMAT_RED_SIZE* = 0x8271.GLenum + GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_OES* = 0x8CD3.GLenum + GL_4PASS_2_SGIS* = 0x80A6.GLenum + GL_PROGRAM_OBJECT_EXT* = 0x8B40.GLenum + GL_SIMULTANEOUS_TEXTURE_AND_STENCIL_TEST* = 0x82AD.GLenum + GL_LIGHTING_BIT* = 0x00000040.GLbitfield + GL_DRAW_BUFFER13_EXT* = 0x8832.GLenum + GL_STREAM_DRAW_ARB* = 0x88E0.GLenum + GL_INDEX_ARRAY_TYPE* = 0x8085.GLenum + GL_DEBUG_SOURCE_THIRD_PARTY* = 0x8249.GLenum + GL_DYNAMIC_COPY_ARB* = 0x88EA.GLenum + GL_COMPARE_R_TO_TEXTURE_ARB* = 0x884E.GLenum + GL_FRAGMENTS_INSTRUMENT_COUNTERS_SGIX* = 0x8314.GLenum + GL_SPARSE_TEXTURE_FULL_ARRAY_CUBE_MIPMAPS_ARB* = 0x91A9.GLenum + GL_MAX_GEOMETRY_UNIFORM_COMPONENTS* = 0x8DDF.GLenum + GL_READ_PIXEL_DATA_RANGE_POINTER_NV* = 0x887D.GLenum + GL_BUFFER_MAPPED_OES* = 0x88BC.GLenum + GL_COLOR_ARRAY_COUNT_EXT* = 0x8084.GLenum + GL_SET_AMD* = 0x874A.GLenum + GL_BLEND_DST_RGB_OES* = 0x80C8.GLenum + GL_MAX_CONVOLUTION_HEIGHT_EXT* = 0x801B.GLenum + GL_DEBUG_SEVERITY_MEDIUM* = 0x9147.GLenum + GL_TEXTURE_INTENSITY_TYPE_ARB* = 0x8C15.GLenum + GL_IMAGE_CLASS_10_10_10_2* = 0x82C3.GLenum + GL_TEXTURE_BORDER_COLOR_NV* = 0x1004.GLenum + GL_VERTEX_ATTRIB_ARRAY12_NV* = 0x865C.GLenum + GL_MAX_GEOMETRY_SHADER_INVOCATIONS* = 0x8E5A.GLenum + GL_NEAREST_CLIPMAP_NEAREST_SGIX* = 0x844D.GLenum + GL_MAP2_VERTEX_ATTRIB12_4_NV* = 0x867C.GLenum + GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING* = 0x889A.GLenum + GL_SEPARATE_SPECULAR_COLOR_EXT* = 0x81FA.GLenum + GL_MATRIX_INDEX_ARRAY_SIZE_ARB* = 0x8846.GLenum + GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB* = 0x8517.GLenum + GL_DECR* = 0x1E03.GLenum + GL_DEPTH_BUFFER_BIT7_QCOM* = 0x00008000.GLbitfield + GL_LOCAL_EXT* = 0x87C4.GLenum + GL_FUNC_REVERSE_SUBTRACT_OES* = 0x800B.GLenum + GL_FLOAT_VEC3* = 0x8B51.GLenum + GL_POINT_SIZE_GRANULARITY* = 0x0B13.GLenum + GL_COLOR_ATTACHMENT9* = 0x8CE9.GLenum + GL_MAT_SPECULAR_BIT_PGI* = 0x04000000.GLbitfield + GL_VERTEX_ATTRIB_MAP1_APPLE* = 0x8A00.GLenum + GL_DEBUG_SOURCE_WINDOW_SYSTEM* = 0x8247.GLenum + GL_NEAREST_MIPMAP_NEAREST* = 0x2700.GLint + GL_MODELVIEW7_ARB* = 0x8727.GLenum + GL_OUTPUT_VERTEX_EXT* = 0x879A.GLenum + GL_FRAMEBUFFER_EXT* = 0x8D40.GLenum + GL_ATC_RGBA_EXPLICIT_ALPHA_AMD* = 0x8C93.GLenum + GL_RENDERBUFFER_WIDTH_OES* = 0x8D42.GLenum + GL_TEXTURE_VIEW_MIN_LAYER* = 0x82DD.GLenum + GL_TEXTURE25_ARB* = 0x84D9.GLenum + GL_LIGHT7* = 0x4007.GLenum + GL_TESS_EVALUATION_SHADER_BIT* = 0x00000010.GLbitfield + GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_EXT* = 0x8CD2.GLenum + GL_COLOR_ATTACHMENT15_NV* = 0x8CEF.GLenum + GL_RED_SNORM* = 0x8F90.GLenum + GL_VIVIDLIGHT_NV* = 0x92A6.GLenum + GL_OBJECT_COMPILE_STATUS_ARB* = 0x8B81.GLenum + GL_INTERNALFORMAT_PREFERRED* = 0x8270.GLenum + GL_OUT_OF_MEMORY* = 0x0505.GLenum + GL_422_REV_EXT* = 0x80CD.GLenum + GL_DOT_PRODUCT_TEXTURE_CUBE_MAP_NV* = 0x86F0.GLenum + GL_PROXY_TEXTURE_1D* = 0x8063.GLenum + GL_FRAGMENT_PROGRAM_CALLBACK_FUNC_MESA* = 0x8BB2.GLenum + GL_YCBCR_422_APPLE* = 0x85B9.GLenum + GL_DRAW_BUFFER10_ATI* = 0x882F.GLenum + GL_COLOR_TABLE_ALPHA_SIZE_SGI* = 0x80DD.GLenum + GL_MAX_TESS_EVALUATION_OUTPUT_COMPONENTS* = 0x8E86.GLenum + GL_MAX_PROGRAM_OUTPUT_VERTICES_NV* = 0x8C27.GLenum + GL_IMAGE_2D_MULTISAMPLE_EXT* = 0x9055.GLenum + GL_ACTIVE_TEXTURE_ARB* = 0x84E0.GLenum + GL_FONT_MAX_ADVANCE_HEIGHT_BIT_NV* = 0x02000000.GLbitfield + GL_QUERY_WAIT_NV* = 0x8E13.GLenum + GL_MAX_ELEMENT_INDEX* = 0x8D6B.GLenum + GL_OP_LOG_BASE_2_EXT* = 0x8792.GLenum + GL_ADD_SIGNED* = 0x8574.GLenum + GL_CONVOLUTION_FORMAT* = 0x8017.GLenum + GL_RENDERBUFFER_RED_SIZE_EXT* = 0x8D50.GLenum + GL_RENDERBUFFER_INTERNAL_FORMAT* = 0x8D44.GLenum + GL_COLOR_ATTACHMENT11_NV* = 0x8CEB.GLenum + GL_MATRIX14_ARB* = 0x88CE.GLenum + GL_COLOR_TABLE_RED_SIZE_SGI* = 0x80DA.GLenum + GL_CON_22_ATI* = 0x8957.GLenum + GL_TEXTURE_SWIZZLE_B_EXT* = 0x8E44.GLenum + GL_SAMPLES_SGIS* = 0x80A9.GLenum + GL_WRITE_PIXEL_DATA_RANGE_LENGTH_NV* = 0x887A.GLenum + GL_FONT_X_MIN_BOUNDS_BIT_NV* = 0x00010000.GLbitfield + GL_3_BYTES* = 0x1408.GLenum + GL_TEXTURE_MAX_CLAMP_S_SGIX* = 0x8369.GLenum + GL_PROXY_TEXTURE_CUBE_MAP_EXT* = 0x851B.GLenum + GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE* = 0x88FE.GLenum + GL_VERTEX_DATA_HINT_PGI* = 0x1A22A.GLenum + GL_VERTEX_WEIGHT_ARRAY_SIZE_EXT* = 0x850D.GLenum + GL_MAX_INTEGER_SAMPLES* = 0x9110.GLenum + GL_TEXTURE_BUFFER_ARB* = 0x8C2A.GLenum + GL_FOG_COORD_ARRAY_POINTER* = 0x8456.GLenum + GL_UNSIGNED_SHORT_1_15_REV_MESA* = 0x8754.GLenum + GL_IMAGE_CUBIC_WEIGHT_HP* = 0x815E.GLenum + GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_OES* = 0x8CD6.GLenum + GL_RGBA_DXT5_S3TC* = 0x83A4.GLenum + GL_INT_IMAGE_2D_MULTISAMPLE* = 0x9060.GLenum + GL_ACTIVE_RESOURCES* = 0x92F5.GLenum + GL_TEXTURE_BINDING_2D* = 0x8069.GLenum + GL_SAMPLE_COVERAGE* = 0x80A0.GLenum + GL_SMOOTH* = 0x1D01.GLenum + GL_SAMPLER_1D_SHADOW_ARB* = 0x8B61.GLenum + GL_VIRTUAL_PAGE_SIZE_Y_AMD* = 0x9196.GLenum + GL_HORIZONTAL_LINE_TO_NV* = 0x06.GLenum + GL_HISTOGRAM_GREEN_SIZE_EXT* = 0x8029.GLenum + GL_COLOR_FLOAT_APPLE* = 0x8A0F.GLenum + GL_NUM_SHADER_BINARY_FORMATS* = 0x8DF9.GLenum + GL_TIMESTAMP* = 0x8E28.GLenum + GL_SRGB_EXT* = 0x8C40.GLenum + GL_MAX_VERTEX_UNIFORM_BLOCKS* = 0x8A2B.GLenum + GL_COLOR_ATTACHMENT2_EXT* = 0x8CE2.GLenum + GL_DEBUG_CALLBACK_FUNCTION_KHR* = 0x8244.GLenum + GL_DISPLAY_LIST* = 0x82E7.GLenum + GL_MAP1_NORMAL* = 0x0D92.GLenum + GL_COMPUTE_TEXTURE* = 0x82A0.GLenum + GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS* = 0x90DB.GLenum + GL_W_EXT* = 0x87D8.GLenum + GL_SAMPLE_SHADING_ARB* = 0x8C36.GLenum + GL_FRAGMENT_INTERPOLATION_OFFSET_BITS* = 0x8E5D.GLenum + GL_IMAGE_CLASS_4_X_16* = 0x82BC.GLenum + GL_FRAGMENT_DEPTH_EXT* = 0x8452.GLenum + GL_EVAL_BIT* = 0x00010000.GLbitfield + GL_UNSIGNED_INT_8_8_8_8* = 0x8035.GLenum + GL_MAX_TESS_CONTROL_INPUT_COMPONENTS* = 0x886C.GLenum + GL_FRAGMENT_PROGRAM_CALLBACK_DATA_MESA* = 0x8BB3.GLenum + GL_SLUMINANCE8_ALPHA8* = 0x8C45.GLenum + GL_MODULATE_COLOR_IMG* = 0x8C04.GLenum + GL_TEXTURE20* = 0x84D4.GLenum + GL_ALPHA_INTEGER_EXT* = 0x8D97.GLenum + GL_TEXTURE_BINDING_CUBE_MAP_EXT* = 0x8514.GLenum + GL_BACK_LEFT* = 0x0402.GLenum + GL_MAX_COMBINED_IMAGE_UNITS_AND_FRAGMENT_OUTPUTS_EXT* = 0x8F39.GLenum + GL_MAX_TRANSFORM_FEEDBACK_BUFFERS* = 0x8E70.GLenum + GL_TRANSFORM_BIT* = 0x00001000.GLbitfield + GL_RGB4_EXT* = 0x804F.GLenum + GL_FRAGMENT_COLOR_EXT* = 0x834C.GLenum + GL_PIXEL_MAP_S_TO_S* = 0x0C71.GLenum + GL_COMPRESSED_RGBA_S3TC_DXT5_EXT* = 0x83F3.GLenum + GL_PATH_STENCIL_DEPTH_OFFSET_FACTOR_NV* = 0x90BD.GLenum + GL_SOURCE0_RGB_EXT* = 0x8580.GLenum + GL_PIXEL_COUNTER_BITS_NV* = 0x8864.GLenum + GL_ALIASED_LINE_WIDTH_RANGE* = 0x846E.GLenum + GL_DRAW_BUFFER10* = 0x882F.GLenum + GL_T4F_C4F_N3F_V4F* = 0x2A2D.GLenum + GL_BLEND_EQUATION_OES* = 0x8009.GLenum + GL_DEPTH_COMPONENT32* = 0x81A7.GLenum + GL_MAX_OPTIMIZED_VERTEX_SHADER_INSTRUCTIONS_EXT* = 0x87CA.GLenum + GL_DEPTH_BUFFER_BIT5_QCOM* = 0x00002000.GLbitfield + GL_RED_MIN_CLAMP_INGR* = 0x8560.GLenum + GL_RGBA_INTEGER_MODE_EXT* = 0x8D9E.GLenum + GL_DOUBLE_MAT4_EXT* = 0x8F48.GLenum + GL_OBJECT_DELETE_STATUS_ARB* = 0x8B80.GLenum + GL_FOG_COORD_ARRAY_LENGTH_NV* = 0x8F32.GLenum + GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING* = 0x889C.GLenum + GL_MAP1_VERTEX_ATTRIB7_4_NV* = 0x8667.GLenum + GL_BLEND_SRC_RGB_EXT* = 0x80C9.GLenum + GL_VERTEX_PROGRAM_POINT_SIZE_ARB* = 0x8642.GLenum + GL_STENCIL_INDEX1_EXT* = 0x8D46.GLenum + GL_TEXTURE_CUBE_MAP_NEGATIVE_X_EXT* = 0x8516.GLenum + GL_FRAGMENT_SHADER_DISCARDS_SAMPLES_EXT* = 0x8A52.GLenum + GL_FOG_COORD_SRC* = 0x8450.GLenum + GL_ANY_SAMPLES_PASSED_EXT* = 0x8C2F.GLenum + GL_ALPHA4* = 0x803B.GLenum + GL_TEXTURE_GEN_MODE* = 0x2500.GLenum + GL_FLOAT_MAT3_ARB* = 0x8B5B.GLenum + GL_PIXEL_MAP_A_TO_A_SIZE* = 0x0CB9.GLenum + GL_FRAGMENT_SHADER_DERIVATIVE_HINT_ARB* = 0x8B8B.GLenum + GL_STENCIL_BACK_PASS_DEPTH_FAIL_ATI* = 0x8802.GLenum + GL_COPY_READ_BUFFER_BINDING* = 0x8F36.GLenum + GL_YCRCB_444_SGIX* = 0x81BC.GLenum + GL_SLUMINANCE_EXT* = 0x8C46.GLenum + GL_EDGE_FLAG_ARRAY_EXT* = 0x8079.GLenum + GL_STENCIL_INDEX8_OES* = 0x8D48.GLenum + GL_RGBA32UI* = 0x8D70.GLenum + GL_TEXTURE_CUBE_MAP* = 0x8513.GLenum + GL_STREAM_COPY* = 0x88E2.GLenum + GL_VIEWPORT_BOUNDS_RANGE* = 0x825D.GLenum + GL_ASYNC_READ_PIXELS_SGIX* = 0x835E.GLenum + GL_VERTEX_ATTRIB_ARRAY_INTEGER* = 0x88FD.GLenum + GL_INTERNALFORMAT_STENCIL_TYPE* = 0x827D.GLenum + GL_OUTPUT_TEXTURE_COORD28_EXT* = 0x87B9.GLenum + GL_MATRIX_MODE* = 0x0BA0.GLenum + GL_MULTISAMPLE_SGIS* = 0x809D.GLenum + GL_R1UI_V3F_SUN* = 0x85C4.GLenum + GL_FLOAT_R32_NV* = 0x8885.GLenum + GL_MAX_DRAW_BUFFERS* = 0x8824.GLenum + GL_CIRCULAR_CCW_ARC_TO_NV* = 0xF8.GLenum + GL_PROGRAM_OUTPUT* = 0x92E4.GLenum + GL_MAX_CUBE_MAP_TEXTURE_SIZE* = 0x851C.GLenum + GL_TRIANGLE_STRIP_ADJACENCY_ARB* = 0x000D.GLenum + GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT* = 0x8A34.GLenum + GL_SRGB* = 0x8C40.GLenum + GL_BUFFER_ACCESS* = 0x88BB.GLenum + GL_TEXTURE_WRAP_S* = 0x2802.GLenum + GL_TRANSFORM_FEEDBACK_VARYINGS* = 0x8C83.GLenum + GL_RG16UI* = 0x823A.GLenum + GL_DUAL_LUMINANCE4_SGIS* = 0x8114.GLenum + GL_DOT_PRODUCT_DEPTH_REPLACE_NV* = 0x86ED.GLenum + GL_READ_FRAMEBUFFER_BINDING* = 0x8CAA.GLenum + GL_MAX_FOG_FUNC_POINTS_SGIS* = 0x812C.GLenum + GL_QUERY_RESULT_NO_WAIT* = 0x9194.GLenum + GL_FILE_NAME_NV* = 0x9074.GLenum + GL_DRAW_FRAMEBUFFER_BINDING* = 0x8CA6.GLenum + GL_FRAGMENT_SHADER* = 0x8B30.GLenum + GL_VIBRANCE_SCALE_NV* = 0x8713.GLenum + GL_PATH_FILL_COVER_MODE_NV* = 0x9082.GLenum + GL_LINEAR_MIPMAP_LINEAR* = 0x2703.GLint + GL_TEXTURE29* = 0x84DD.GLenum + GL_SCISSOR_BOX* = 0x0C10.GLenum + GL_PACK_SKIP_IMAGES* = 0x806B.GLenum + GL_BUFFER_MAP_OFFSET* = 0x9121.GLenum + GL_SLUMINANCE8_EXT* = 0x8C47.GLenum + GL_CONVOLUTION_1D* = 0x8010.GLenum + GL_MAX_GEOMETRY_IMAGE_UNIFORMS* = 0x90CD.GLenum + GL_MAP1_VERTEX_ATTRIB11_4_NV* = 0x866B.GLenum + GL_COLOR_LOGIC_OP* = 0x0BF2.GLenum + GL_SYNC_FLAGS_APPLE* = 0x9115.GLenum + GL_ACCUM_RED_BITS* = 0x0D58.GLenum + GL_VIEW_CLASS_128_BITS* = 0x82C4.GLenum + GL_INT_VEC3* = 0x8B54.GLenum + GL_INTENSITY12* = 0x804C.GLenum + GL_UNIFORM_BLOCK_REFERENCED_BY_COMPUTE_SHADER* = 0x90EC.GLenum + GL_REQUIRED_TEXTURE_IMAGE_UNITS_OES* = 0x8D68.GLenum + GL_MAX_COLOR_MATRIX_STACK_DEPTH* = 0x80B3.GLenum + GL_GLOBAL_ALPHA_FACTOR_SUN* = 0x81DA.GLenum + GL_PACK_RESAMPLE_SGIX* = 0x842C.GLenum + GL_MAX_COMPUTE_FIXED_GROUP_SIZE_ARB* = 0x91BF.GLenum + GL_DEPTH_BUFFER_FLOAT_MODE_NV* = 0x8DAF.GLenum + GL_SIGNED_LUMINANCE_ALPHA_NV* = 0x8703.GLenum + GL_OP_MIN_EXT* = 0x878B.GLenum + GL_TRANSFORM_FEEDBACK_BUFFER_MODE_NV* = 0x8C7F.GLenum + GL_COLOR_INDEX12_EXT* = 0x80E6.GLenum + GL_AUTO_NORMAL* = 0x0D80.GLenum + GL_ARRAY_BUFFER* = 0x8892.GLenum + GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS_EXT* = 0x8DE1.GLenum + GL_VIDEO_CAPTURE_SURFACE_ORIGIN_NV* = 0x903C.GLenum + GL_ACCUM_BLUE_BITS* = 0x0D5A.GLenum + GL_RENDERBUFFER_SAMPLES_ANGLE* = 0x8CAB.GLenum + GL_MAX_ASYNC_HISTOGRAM_SGIX* = 0x832D.GLenum + GL_GLYPH_HAS_KERNING_BIT_NV* = 0x100.GLbitfield + GL_TESS_CONTROL_SUBROUTINE_UNIFORM* = 0x92EF.GLenum + GL_DRAW_BUFFER1* = 0x8826.GLenum + GL_INT8_NV* = 0x8FE0.GLenum + GL_2PASS_0_EXT* = 0x80A2.GLenum + GL_TRANSFORM_FEEDBACK_BUFFER_INDEX* = 0x934B.GLenum + GL_NUM_VIRTUAL_PAGE_SIZES_ARB* = 0x91A8.GLenum + GL_INT_SAMPLER_3D* = 0x8DCB.GLenum + GL_RASTERIZER_DISCARD* = 0x8C89.GLenum + GL_SOURCE2_RGB_ARB* = 0x8582.GLenum + GL_LOCAL_CONSTANT_EXT* = 0x87C3.GLenum + GL_FRAMEBUFFER_INCOMPLETE_LAYER_COUNT_EXT* = 0x8DA9.GLenum + GL_MODELVIEW12_ARB* = 0x872C.GLenum + GL_VERTEX_SUBROUTINE_UNIFORM* = 0x92EE.GLenum + GL_OPERAND0_ALPHA_ARB* = 0x8598.GLenum + GL_DEPTH24_STENCIL8* = 0x88F0.GLenum + GL_RENDERBUFFER_RED_SIZE* = 0x8D50.GLenum + GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING* = 0x8210.GLenum + GL_DRAW_BUFFER10_ARB* = 0x882F.GLenum + GL_UNSIGNED_INT_SAMPLER_3D* = 0x8DD3.GLenum + GL_SKIP_COMPONENTS2_NV* = -5 + GL_PROGRAM_BINARY_LENGTH_OES* = 0x8741.GLenum + GL_VERTEX_ATTRIB_MAP1_SIZE_APPLE* = 0x8A02.GLenum + GL_QUERY_RESULT_EXT* = 0x8866.GLenum + GL_CONSTANT_COLOR0_NV* = 0x852A.GLenum + GL_MAX_ASYNC_DRAW_PIXELS_SGIX* = 0x8360.GLenum + GL_DOT_PRODUCT_DIFFUSE_CUBE_MAP_NV* = 0x86F1.GLenum + GL_ALPHA_TEST_REF* = 0x0BC2.GLenum + GL_MAX_4D_TEXTURE_SIZE_SGIS* = 0x8138.GLenum + GL_INT_SAMPLER_2D_MULTISAMPLE* = 0x9109.GLenum + GL_DRAW_BUFFER6_ATI* = 0x882B.GLenum + GL_INTENSITY16UI_EXT* = 0x8D79.GLenum + GL_POINT_FADE_THRESHOLD_SIZE_ARB* = 0x8128.GLenum + GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING* = 0x889F.GLenum + GL_RENDERBUFFER_WIDTH_EXT* = 0x8D42.GLenum + GL_FIXED_ONLY* = 0x891D.GLenum + GL_HISTOGRAM_BLUE_SIZE* = 0x802A.GLenum + GL_PROGRAM_TEX_INSTRUCTIONS_ARB* = 0x8806.GLenum + GL_MAX_VERTEX_SHADER_VARIANTS_EXT* = 0x87C6.GLenum + GL_UNSIGNED_INT_10_10_10_2_EXT* = 0x8036.GLenum + GL_SAMPLE_ALPHA_TO_ONE_EXT* = 0x809F.GLenum + GL_INDEX_ARRAY* = 0x8077.GLenum + GL_GEQUAL* = 0x0206.GLenum + GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS* = 0x90D8.GLenum + GL_DITHER* = 0x0BD0.GLenum + GL_ATTACHED_SHADERS* = 0x8B85.GLenum + GL_FUNC_SUBTRACT* = 0x800A.GLenum + GL_ATOMIC_COUNTER_BARRIER_BIT_EXT* = 0x00001000.GLbitfield + GL_LUMINANCE4* = 0x803F.GLenum + GL_BLEND_EQUATION_RGB_EXT* = 0x8009.GLenum + GL_TEXTURE_MULTI_BUFFER_HINT_SGIX* = 0x812E.GLenum + GL_DEBUG_SEVERITY_LOW_KHR* = 0x9148.GLenum + GL_UNPACK_COMPRESSED_BLOCK_HEIGHT* = 0x9128.GLenum + GL_CULL_VERTEX_OBJECT_POSITION_EXT* = 0x81AC.GLenum + GL_POST_COLOR_MATRIX_ALPHA_BIAS_SGI* = 0x80BB.GLenum + GL_ADD_SIGNED_EXT* = 0x8574.GLenum + GL_VERTEX_ARRAY_PARALLEL_POINTERS_INTEL* = 0x83F5.GLenum + GL_CURRENT_RASTER_SECONDARY_COLOR* = 0x845F.GLenum + GL_MAX_PROGRAM_TEXTURE_GATHER_OFFSET_NV* = 0x8E5F.GLenum + GL_CONTINUOUS_AMD* = 0x9007.GLenum + GL_R1UI_T2F_C4F_N3F_V3F_SUN* = 0x85CB.GLenum + GL_COMPUTE_SHADER* = 0x91B9.GLenum + GL_CLIP_DISTANCE6* = 0x3006.GLenum + GL_SRC_ATOP_NV* = 0x928E.GLenum + GL_DEPTH_COMPONENT16_OES* = 0x81A5.GLenum + GL_DOUBLE_MAT4* = 0x8F48.GLenum + GL_MAT_SHININESS_BIT_PGI* = 0x02000000.GLbitfield + GL_SAMPLER_BUFFER_AMD* = 0x9001.GLenum + GL_ARRAY_BUFFER_BINDING_ARB* = 0x8894.GLenum + GL_VOLATILE_APPLE* = 0x8A1A.GLenum + GL_ALPHA32UI_EXT* = 0x8D72.GLenum + GL_COLOR_BUFFER_BIT1_QCOM* = 0x00000002.GLbitfield + GL_VERTEX_PROGRAM_CALLBACK_MESA* = 0x8BB4.GLenum + GL_CULL_VERTEX_EXT* = 0x81AA.GLenum + GL_RENDERBUFFER_STENCIL_SIZE_EXT* = 0x8D55.GLenum + GL_SELECT* = 0x1C02.GLenum + GL_LUMINANCE12_ALPHA4* = 0x8046.GLenum + GL_IMAGE_BINDING_LEVEL_EXT* = 0x8F3B.GLenum + GL_MATRIX_PALETTE_ARB* = 0x8840.GLenum + GL_DUAL_ALPHA4_SGIS* = 0x8110.GLenum + GL_BACK_NORMALS_HINT_PGI* = 0x1A223.GLenum + GL_UNSIGNED_SHORT_15_1_MESA* = 0x8753.GLenum + GL_UNSIGNED_SHORT_4_4_4_4_REV* = 0x8365.GLenum + GL_BUFFER* = 0x82E0.GLenum + GL_RENDERBUFFER_INTERNAL_FORMAT_EXT* = 0x8D44.GLenum + GL_MATRIX5_NV* = 0x8635.GLenum + GL_ATOMIC_COUNTER_BUFFER* = 0x92C0.GLenum + GL_SMOOTH_QUADRATIC_CURVE_TO_NV* = 0x0E.GLenum + GL_VARIABLE_D_NV* = 0x8526.GLenum + GL_PINLIGHT_NV* = 0x92A8.GLenum + GL_VERTEX_ATTRIB_ARRAY_INTEGER_EXT* = 0x88FD.GLenum + GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS* = 0x92CF.GLenum + GL_Z6Y10Z6CB10Z6A10Z6Y10Z6CR10Z6A10_4224_NV* = 0x9034.GLenum + GL_RESAMPLE_REPLICATE_SGIX* = 0x842E.GLenum + GL_UNSIGNED_SHORT_5_6_5_REV* = 0x8364.GLenum + GL_VERTEX_ATTRIB_ARRAY2_NV* = 0x8652.GLenum + GL_3D_COLOR_TEXTURE* = 0x0603.GLenum + GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS* = 0x8B4C.GLenum + GL_DEBUG_TYPE_PERFORMANCE_KHR* = 0x8250.GLenum + GL_MATRIX_INDEX_ARRAY_OES* = 0x8844.GLenum + GL_TEXTURE_TOO_LARGE_EXT* = 0x8065.GLenum + GL_PACK_IMAGE_HEIGHT_EXT* = 0x806C.GLenum + GL_YCBYCR8_422_NV* = 0x9031.GLenum + GL_COLOR_ATTACHMENT8* = 0x8CE8.GLenum + GL_SAMPLE_COVERAGE_ARB* = 0x80A0.GLenum + GL_CURRENT_VERTEX_EXT* = 0x87E2.GLenum + GL_LINEAR* = 0x2601.GLint + GL_STENCIL_TAG_BITS_EXT* = 0x88F2.GLenum + GL_T2F_IUI_V3F_EXT* = 0x81B2.GLenum + GL_TEXTURE_3D_BINDING_OES* = 0x806A.GLenum + GL_PATH_CLIENT_LENGTH_NV* = 0x907F.GLenum + GL_MAT_AMBIENT_BIT_PGI* = 0x00100000.GLbitfield + GL_DOUBLE_MAT4x3* = 0x8F4E.GLenum + GL_QUERY_BY_REGION_WAIT_NV* = 0x8E15.GLenum + GL_LEQUAL* = 0x0203.GLenum + GL_PROGRAM_ATTRIBS_ARB* = 0x88AC.GLenum + GL_BUFFER_MAPPED_ARB* = 0x88BC.GLenum + GL_VERTEX_SHADER_ARB* = 0x8B31.GLenum + GL_SOURCE1_ALPHA_EXT* = 0x8589.GLenum + GL_UNSIGNED_INT16_VEC3_NV* = 0x8FF2.GLenum + GL_MAX_PROGRAM_ADDRESS_REGISTERS_ARB* = 0x88B1.GLenum + GL_RGB16* = 0x8054.GLenum + GL_TEXTURE15_ARB* = 0x84CF.GLenum + GL_TEXTURE_GATHER_SHADOW* = 0x82A3.GLenum + GL_FENCE_APPLE* = 0x8A0B.GLenum + GL_TRIANGLES* = 0x0004.GLenum + GL_DOT4_ATI* = 0x8967.GLenum + GL_CURRENT_FOG_COORD* = 0x8453.GLenum + GL_DEPTH_CLAMP_NEAR_AMD* = 0x901E.GLenum + GL_SYNC_FENCE* = 0x9116.GLenum + GL_UNSIGNED_INT64_VEC3_NV* = 0x8FF6.GLenum + GL_DEPTH* = 0x1801.GLenum + GL_TEXTURE_COORD_NV* = 0x8C79.GLenum + GL_COMBINE* = 0x8570.GLenum + GL_MAX_VERTEX_UNITS_ARB* = 0x86A4.GLenum + GL_COLOR_INDEX2_EXT* = 0x80E3.GLenum + GL_POST_IMAGE_TRANSFORM_COLOR_TABLE_HP* = 0x8162.GLenum + GL_INT_SAMPLER_CUBE_MAP_ARRAY_ARB* = 0x900E.GLenum + GL_MIRROR_CLAMP_EXT* = 0x8742.GLint + GL_STENCIL_VALUE_MASK* = 0x0B93.GLenum + GL_UNSIGNED_INT_SAMPLER_BUFFER* = 0x8DD8.GLenum + GL_TRACK_MATRIX_NV* = 0x8648.GLenum + GL_MAP1_VERTEX_3* = 0x0D97.GLenum + GL_OP_MOV_EXT* = 0x8799.GLenum + GL_MAP_INVALIDATE_RANGE_BIT_EXT* = 0x0004.GLbitfield + GL_MAX_CONVOLUTION_WIDTH_EXT* = 0x801A.GLenum + GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_OES* = 0x8518.GLenum + GL_RGBA_SNORM* = 0x8F93.GLenum + GL_MAX_TRACK_MATRICES_NV* = 0x862F.GLenum + GL_MAX_TESS_EVALUATION_INPUT_COMPONENTS* = 0x886D.GLenum + GL_DOUBLE_VEC4_EXT* = 0x8FFE.GLenum + GL_COLOR_TABLE_BLUE_SIZE* = 0x80DC.GLenum + GL_T2F_C3F_V3F* = 0x2A2A.GLenum + GL_INTENSITY16_SNORM* = 0x901B.GLenum + GL_INT_IMAGE_CUBE_MAP_ARRAY_EXT* = 0x905F.GLenum + GL_DEBUG_CATEGORY_UNDEFINED_BEHAVIOR_AMD* = 0x914C.GLenum + GL_NORMAL_MAP_EXT* = 0x8511.GLenum + GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS_NV* = 0x8C8B.GLenum + GL_DRAW_BUFFER4_EXT* = 0x8829.GLenum + GL_PIXEL_MAP_G_TO_G* = 0x0C77.GLenum + GL_TESS_GEN_POINT_MODE* = 0x8E79.GLenum + GL_MAX_VERTEX_ATOMIC_COUNTER_BUFFERS* = 0x92CC.GLenum + GL_UNSIGNED_INT_SAMPLER_2D_RECT_EXT* = 0x8DD5.GLenum + GL_MULTISAMPLE_BUFFER_BIT2_QCOM* = 0x04000000.GLbitfield + GL_POST_COLOR_MATRIX_GREEN_BIAS_SGI* = 0x80B9.GLenum + GL_POST_COLOR_MATRIX_GREEN_BIAS* = 0x80B9.GLenum + GL_TEXTURE10* = 0x84CA.GLenum + GL_RGB32F* = 0x8815.GLenum + GL_DYNAMIC_READ_ARB* = 0x88E9.GLenum + GL_MODELVIEW22_ARB* = 0x8736.GLenum + GL_VERTEX_STREAM0_ATI* = 0x876C.GLenum + GL_TEXTURE_FETCH_BARRIER_BIT_EXT* = 0x00000008.GLbitfield + GL_COMBINER_INPUT_NV* = 0x8542.GLenum + GL_DRAW_BUFFER0_NV* = 0x8825.GLenum + GL_ALPHA_TEST* = 0x0BC0.GLenum + GL_PIXEL_UNPACK_BUFFER* = 0x88EC.GLenum + GL_SRC_IN_NV* = 0x928A.GLenum + GL_COMPRESSED_SIGNED_RED_RGTC1_EXT* = 0x8DBC.GLenum + GL_PACK_SUBSAMPLE_RATE_SGIX* = 0x85A0.GLenum + GL_FRAMEBUFFER_DEFAULT_SAMPLES* = 0x9313.GLenum + GL_ARRAY_OBJECT_OFFSET_ATI* = 0x8767.GLenum + GL_TEXTURE_CUBE_MAP_POSITIVE_X_OES* = 0x8515.GLenum + GL_STENCIL_BITS* = 0x0D57.GLenum + GL_DEPTH_COMPONENT24_OES* = 0x81A6.GLenum + GL_FRAMEBUFFER* = 0x8D40.GLenum + GL_8X_BIT_ATI* = 0x00000004.GLbitfield + GL_TEXTURE_BINDING_2D_MULTISAMPLE_ARRAY* = 0x9105.GLenum + GL_BOOL_VEC2* = 0x8B57.GLenum + GL_EXP* = 0x0800.GLenum + GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_EXT* = 0x851A.GLenum + GL_STENCIL_INDEX16* = 0x8D49.GLenum + GL_FRAGMENT_LIGHTING_SGIX* = 0x8400.GLenum + GL_PACK_SKIP_PIXELS* = 0x0D04.GLenum + GL_TEXTURE_MIN_LOD* = 0x813A.GLenum + GL_COMPRESSED_RGB* = 0x84ED.GLenum + GL_MAP1_VERTEX_ATTRIB2_4_NV* = 0x8662.GLenum + GL_CONJOINT_NV* = 0x9284.GLenum + GL_MAX_COMPUTE_SHARED_MEMORY_SIZE* = 0x8262.GLenum + GL_INTENSITY8* = 0x804B.GLenum + GL_SAMPLER_2D_MULTISAMPLE* = 0x9108.GLenum + GL_MAX_LIST_NESTING* = 0x0B31.GLenum + GL_DOUBLE_MAT3* = 0x8F47.GLenum + GL_TEXTURE_DEPTH* = 0x8071.GLenum + GL_QUADS_FOLLOW_PROVOKING_VERTEX_CONVENTION* = 0x8E4C.GLenum + GL_TEXTURE12_ARB* = 0x84CC.GLenum + GL_R1UI_T2F_V3F_SUN* = 0x85C9.GLenum + GL_REPLACE* = 0x1E01.GLenum + GL_MAX_NUM_ACTIVE_VARIABLES* = 0x92F7.GLenum + GL_RGBA_INTEGER_EXT* = 0x8D99.GLenum + GL_TEXTURE_COMPRESSED_BLOCK_SIZE* = 0x82B3.GLenum + GL_INDEX_CLEAR_VALUE* = 0x0C20.GLenum + GL_PROGRAM_ERROR_POSITION_ARB* = 0x864B.GLenum + GL_LINEARBURN_NV* = 0x92A5.GLenum + GL_TEXTURE_BINDING_CUBE_MAP_ARB* = 0x8514.GLenum + GL_TESSELLATION_FACTOR_AMD* = 0x9005.GLenum + GL_SHADER_IMAGE_STORE* = 0x82A5.GLenum + GL_COMPRESSED_SLUMINANCE_ALPHA_EXT* = 0x8C4B.GLenum + GL_MAX_PALETTE_MATRICES_ARB* = 0x8842.GLenum + GL_UNPACK_CONSTANT_DATA_SUNX* = 0x81D5.GLenum + GL_FLOAT_MAT3x4* = 0x8B68.GLenum + GL_DRAW_BUFFER8_NV* = 0x882D.GLenum + GL_ATTENUATION_EXT* = 0x834D.GLenum + GL_REG_25_ATI* = 0x893A.GLenum + GL_UNSIGNED_INT_SAMPLER_1D* = 0x8DD1.GLenum + GL_TEXTURE_1D_STACK_BINDING_MESAX* = 0x875D.GLenum + GL_SYNC_STATUS_APPLE* = 0x9114.GLenum + GL_TEXTURE_CUBE_MAP_ARRAY* = 0x9009.GLenum + GL_EXP2* = 0x0801.GLenum + GL_COMPRESSED_SIGNED_LUMINANCE_LATC1_EXT* = 0x8C71.GLenum + GL_BUFFER_ACCESS_ARB* = 0x88BB.GLenum + GL_LO_BIAS_NV* = 0x8715.GLenum + GL_MIRROR_CLAMP_ATI* = 0x8742.GLint + GL_SAMPLE_COVERAGE_VALUE* = 0x80AA.GLenum + GL_UNSIGNED_INT_24_8_EXT* = 0x84FA.GLenum + GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN_EXT* = 0x8C88.GLenum + GL_R16UI* = 0x8234.GLenum + GL_BLEND_PREMULTIPLIED_SRC_NV* = 0x9280.GLenum + GL_COLOR_ATTACHMENT0* = 0x8CE0.GLenum + GL_GEOMETRY_VERTICES_OUT_EXT* = 0x8DDA.GLenum + GL_SAMPLE_MASK_NV* = 0x8E51.GLenum + GL_BGRA_INTEGER_EXT* = 0x8D9B.GLenum + GL_PALETTE8_RGBA8_OES* = 0x8B96.GLenum + GL_MAX_ARRAY_TEXTURE_LAYERS_EXT* = 0x88FF.GLenum + GL_TEXTURE_COLOR_TABLE_SGI* = 0x80BC.GLenum + GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS_EXT* = 0x8C80.GLenum + GL_TEXTURE10_ARB* = 0x84CA.GLenum + GL_TRIANGLES_ADJACENCY* = 0x000C.GLenum + GL_COLOR_ARRAY_EXT* = 0x8076.GLenum + GL_MAX_FRAMEBUFFER_SAMPLES* = 0x9318.GLenum + GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING_ARB* = 0x889F.GLenum + GL_IMAGE_TEXEL_SIZE* = 0x82A7.GLenum + GL_MAGNITUDE_BIAS_NV* = 0x8718.GLenum + GL_SHADOW_AMBIENT_SGIX* = 0x80BF.GLenum + GL_BUFFER_SERIALIZED_MODIFY_APPLE* = 0x8A12.GLenum + GL_TEXTURE_COORD_ARRAY_COUNT_EXT* = 0x808B.GLenum + GL_MAX_DRAW_BUFFERS_ARB* = 0x8824.GLenum + GL_MAX_OPTIMIZED_VERTEX_SHADER_INVARIANTS_EXT* = 0x87CD.GLenum + GL_PASS_THROUGH_TOKEN* = 0x0700.GLenum + GL_BLEND_EQUATION* = 0x8009.GLenum + GL_FOG_HINT* = 0x0C54.GLenum + GL_FLOAT_RGB16_NV* = 0x8888.GLenum + GL_OUTPUT_TEXTURE_COORD18_EXT* = 0x87AF.GLenum + GL_T2F_IUI_N3F_V2F_EXT* = 0x81B3.GLenum + GL_SAMPLER_EXTERNAL_OES* = 0x8D66.GLenum + GL_MAX_SUBROUTINES* = 0x8DE7.GLenum + GL_RED_BIT_ATI* = 0x00000001.GLbitfield + GL_SOURCE2_ALPHA* = 0x858A.GLenum + GL_AUX0* = 0x0409.GLenum + GL_OPERAND1_ALPHA_ARB* = 0x8599.GLenum + GL_TEXTURE_MAX_ANISOTROPY_EXT* = 0x84FE.GLenum + GL_VERTEX_PROGRAM_POINT_SIZE_NV* = 0x8642.GLenum + GL_MULTIVIEW_EXT* = 0x90F1.GLenum + GL_FOG_OFFSET_SGIX* = 0x8198.GLenum + GL_COLOR_ARRAY_PARALLEL_POINTERS_INTEL* = 0x83F7.GLenum + GL_ELEMENT_ARRAY_ATI* = 0x8768.GLenum + GL_ALPHA16_SNORM* = 0x9018.GLenum + GL_COMPRESSED_SLUMINANCE_EXT* = 0x8C4A.GLenum + GL_TEXTURE_OBJECT_VALID_QCOM* = 0x8BDB.GLenum + GL_STENCIL_BACK_FUNC* = 0x8800.GLenum + GL_CULL_FACE* = 0x0B44.GLenum + GL_MAP1_COLOR_4* = 0x0D90.GLenum + GL_SHADER_OBJECT_ARB* = 0x8B48.GLenum + GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG* = 0x8C01.GLenum + GL_TANGENT_ARRAY_EXT* = 0x8439.GLenum + GL_NUM_FRAGMENT_CONSTANTS_ATI* = 0x896F.GLenum + GL_COLOR_RENDERABLE* = 0x8286.GLenum + GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS* = 0x8B4D.GLenum + GL_TRANSFORM_FEEDBACK_RECORD_NV* = 0x8C86.GLenum + GL_COLOR_ATTACHMENT1_NV* = 0x8CE1.GLenum + GL_ALPHA_SNORM* = 0x9010.GLenum + GL_PIXEL_TRANSFORM_2D_MATRIX_EXT* = 0x8338.GLenum + GL_SMOOTH_POINT_SIZE_GRANULARITY* = 0x0B13.GLenum + GL_R8I* = 0x8231.GLenum + GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT* = 0x8D56.GLenum + GL_POLYGON_OFFSET_BIAS_EXT* = 0x8039.GLenum + GL_DEPTH_COMPONENT24* = 0x81A6.GLenum + GL_TEXTURE_SWIZZLE_B* = 0x8E44.GLenum + GL_MAX_TESS_CONTROL_TEXTURE_IMAGE_UNITS* = 0x8E81.GLenum + GL_MAP2_INDEX* = 0x0DB1.GLenum + GL_SAMPLER_CUBE_MAP_ARRAY* = 0x900C.GLenum + GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT* = 0x8CD6.GLenum + GL_UNSIGNED_INT_8_8_8_8_REV* = 0x8367.GLenum + GL_PATH_GEN_COEFF_NV* = 0x90B1.GLenum + GL_OPERAND3_ALPHA_NV* = 0x859B.GLenum + GL_LUMINANCE* = 0x1909.GLenum + GL_MAX_SUBROUTINE_UNIFORM_LOCATIONS* = 0x8DE8.GLenum + GL_MAP_READ_BIT* = 0x0001.GLbitfield + GL_MAX_TEXTURE_STACK_DEPTH* = 0x0D39.GLenum + GL_ORDER* = 0x0A01.GLenum + GL_PATH_FILL_MODE_NV* = 0x9080.GLenum + GL_RENDERBUFFER_BLUE_SIZE* = 0x8D52.GLenum + GL_TEXTURE_INTENSITY_SIZE* = 0x8061.GLenum + GL_DRAW_BUFFER1_NV* = 0x8826.GLenum + GL_SCREEN_NV* = 0x9295.GLenum + GL_RGB8I_EXT* = 0x8D8F.GLenum + GL_MIN_PROGRAM_TEXTURE_GATHER_OFFSET* = 0x8E5E.GLenum + GL_DUAL_INTENSITY12_SGIS* = 0x811A.GLenum + GL_SPARE1_NV* = 0x852F.GLenum + GL_PALETTE8_R5_G6_B5_OES* = 0x8B97.GLenum + GL_COLOR_ATTACHMENT7_NV* = 0x8CE7.GLenum + GL_TEXTURE_HEIGHT* = 0x1001.GLenum + GL_RENDERBUFFER_BINDING* = 0x8CA7.GLenum + GL_DRAW_BUFFER7_EXT* = 0x882C.GLenum + GL_HISTOGRAM* = 0x8024.GLenum + GL_COLOR_ATTACHMENT0_OES* = 0x8CE0.GLenum + GL_BINORMAL_ARRAY_STRIDE_EXT* = 0x8441.GLenum + GL_DEBUG_SEVERITY_HIGH_AMD* = 0x9146.GLenum + GL_MIN_SPARSE_LEVEL_AMD* = 0x919B.GLenum + GL_MAP1_VERTEX_ATTRIB10_4_NV* = 0x866A.GLenum + GL_COEFF* = 0x0A00.GLenum + GL_COMPRESSED_RGBA_ASTC_6x5_KHR* = 0x93B3.GLenum + GL_TEXTURE_4D_BINDING_SGIS* = 0x814F.GLenum + GL_BUFFER_USAGE* = 0x8765.GLenum + GL_YCBCR_MESA* = 0x8757.GLenum + GL_CLAMP_VERTEX_COLOR* = 0x891A.GLenum + GL_RGBA8_EXT* = 0x8058.GLenum + GL_BITMAP_TOKEN* = 0x0704.GLenum + GL_IMAGE_SCALE_Y_HP* = 0x8156.GLenum + GL_OUTPUT_TEXTURE_COORD25_EXT* = 0x87B6.GLenum + GL_DEBUG_SOURCE_API* = 0x8246.GLenum + GL_STACK_UNDERFLOW* = 0x0504.GLenum + GL_COMBINER_CD_DOT_PRODUCT_NV* = 0x8546.GLenum + GL_FRAMEBUFFER_BINDING_EXT* = 0x8CA6.GLenum + GL_REG_20_ATI* = 0x8935.GLenum + GL_MAP1_TEXTURE_COORD_4* = 0x0D96.GLenum + GL_DEBUG_OUTPUT_SYNCHRONOUS* = 0x8242.GLenum + GL_ACCUM_ALPHA_BITS* = 0x0D5B.GLenum + GL_INT_10_10_10_2_OES* = 0x8DF7.GLenum + GL_FLOAT_MAT2_ARB* = 0x8B5A.GLenum + GL_FRONT_RIGHT* = 0x0401.GLenum + GL_COMBINER_AB_DOT_PRODUCT_NV* = 0x8545.GLenum + GL_LUMINANCE_ALPHA* = 0x190A.GLenum + GL_C4UB_V2F* = 0x2A22.GLenum + GL_COMBINER_MUX_SUM_NV* = 0x8547.GLenum + GL_MODELVIEW_STACK_DEPTH* = 0x0BA3.GLenum + GL_SAMPLES_ARB* = 0x80A9.GLenum + GL_ALPHA_TEST_FUNC* = 0x0BC1.GLenum + GL_DEPTH_CLAMP* = 0x864F.GLenum + GL_MAP2_VERTEX_ATTRIB8_4_NV* = 0x8678.GLenum + GL_INVALID_INDEX* = 0xFFFFFFFF.GLenum + GL_COMBINER_SCALE_NV* = 0x8548.GLenum + GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_FRAGMENT_SHADER* = 0x92CB.GLenum + GL_DOT_PRODUCT_TEXTURE_RECTANGLE_NV* = 0x864E.GLenum + GL_RELATIVE_SMALL_CW_ARC_TO_NV* = 0x15.GLenum + GL_UNSIGNED_INT_10_10_10_2_OES* = 0x8DF6.GLenum + GL_DISCARD_ATI* = 0x8763.GLenum + GL_PRIMITIVE_RESTART_INDEX_NV* = 0x8559.GLenum + GL_IMAGE_CLASS_2_X_8* = 0x82C0.GLenum + GL_MANUAL_GENERATE_MIPMAP* = 0x8294.GLenum + GL_FLOAT_R_NV* = 0x8880.GLenum + GL_SATURATE_BIT_ATI* = 0x00000040.GLbitfield + GL_BUFFER_SIZE* = 0x8764.GLenum + GL_FRAMEBUFFER_BARRIER_BIT_EXT* = 0x00000400.GLbitfield + GL_LUMINANCE8UI_EXT* = 0x8D80.GLenum + GL_T2F_IUI_V2F_EXT* = 0x81B1.GLenum + GL_OUTPUT_TEXTURE_COORD15_EXT* = 0x87AC.GLenum + GL_COVERAGE_AUTOMATIC_NV* = 0x8ED7.GLenum + GL_TEXTURE_INTERNAL_FORMAT_QCOM* = 0x8BD5.GLenum + GL_INT_IMAGE_CUBE_MAP_ARRAY* = 0x905F.GLenum + GL_BUFFER_UPDATE_BARRIER_BIT_EXT* = 0x00000200.GLbitfield + GL_GLYPH_WIDTH_BIT_NV* = 0x01.GLbitfield + GL_OP_MAX_EXT* = 0x878A.GLenum + GL_MINMAX_FORMAT_EXT* = 0x802F.GLenum + GL_R16I* = 0x8233.GLenum + GL_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB* = 0x8809.GLenum + GL_TEXTURE_MAX_LEVEL* = 0x813D.GLenum + GL_GEOMETRY_SHADER* = 0x8DD9.GLenum + GL_MAX_RENDERBUFFER_SIZE* = 0x84E8.GLenum + GL_RGB16_EXT* = 0x8054.GLenum + GL_DUAL_INTENSITY16_SGIS* = 0x811B.GLenum + GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT* = 0x8CD6.GLenum + GL_BLUE_SCALE* = 0x0D1A.GLenum + GL_RGBA_FLOAT16_APPLE* = 0x881A.GLenum + GL_RGBA8UI* = 0x8D7C.GLenum + GL_COLOR_ATTACHMENT5* = 0x8CE5.GLenum + GL_UNSIGNED_IDENTITY_NV* = 0x8536.GLenum + GL_COMPRESSED_RGBA_ASTC_10x8_KHR* = 0x93BA.GLenum + GL_FRAGMENT_SHADER_ARB* = 0x8B30.GLenum + GL_R8* = 0x8229.GLenum + GL_IMAGE_BINDING_LAYERED* = 0x8F3C.GLenum + GL_RGBA_FLOAT32_ATI* = 0x8814.GLenum + GL_TEXTURE_RED_SIZE_EXT* = 0x805C.GLenum + GL_INT8_VEC2_NV* = 0x8FE1.GLenum + GL_NEGATE_BIT_ATI* = 0x00000004.GLbitfield + GL_ALL_BARRIER_BITS_EXT* = 0xFFFFFFFF.GLbitfield + GL_LIGHT_MODEL_COLOR_CONTROL_EXT* = 0x81F8.GLenum + GL_LUMINANCE_ALPHA16UI_EXT* = 0x8D7B.GLenum + GL_COUNT_UP_NV* = 0x9088.GLenum + GL_QUERY_RESULT_AVAILABLE_ARB* = 0x8867.GLenum + GL_DRAW_INDIRECT_BUFFER* = 0x8F3F.GLenum + GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_EXT* = 0x8CD3.GLenum + GL_OP_DOT3_EXT* = 0x8784.GLenum + GL_COLOR_ATTACHMENT10_NV* = 0x8CEA.GLenum + GL_STENCIL_INDEX4_OES* = 0x8D47.GLenum + GL_LUMINANCE_FLOAT32_ATI* = 0x8818.GLenum + GL_DRAW_BUFFER9_ARB* = 0x882E.GLenum + GL_RG8_EXT* = 0x822B.GLenum + GL_FONT_DESCENDER_BIT_NV* = 0x00400000.GLbitfield + GL_TEXTURE_ALPHA_SIZE_EXT* = 0x805F.GLenum + GL_Y_EXT* = 0x87D6.GLenum + GL_MAX_GEOMETRY_BINDABLE_UNIFORMS_EXT* = 0x8DE4.GLenum + GL_SAMPLER_3D_ARB* = 0x8B5F.GLenum + GL_INVERT_OVG_NV* = 0x92B4.GLenum + GL_REFERENCED_BY_TESS_EVALUATION_SHADER* = 0x9308.GLenum + GL_TEXTURE_COORD_ARRAY_PARALLEL_POINTERS_INTEL* = 0x83F8.GLenum + GL_LIGHT4* = 0x4004.GLenum + GL_VERTEX_STATE_PROGRAM_NV* = 0x8621.GLenum + GL_ZERO* = 0.GLenum + GL_SAMPLER_CUBE_MAP_ARRAY_ARB* = 0x900C.GLenum + GL_SAMPLE_MASK_EXT* = 0x80A0.GLenum + GL_COMBINER_CD_OUTPUT_NV* = 0x854B.GLenum + GL_SAMPLE_ALPHA_TO_MASK_SGIS* = 0x809E.GLenum + GL_RGBA16* = 0x805B.GLenum + GL_PATH_TERMINAL_DASH_CAP_NV* = 0x907D.GLenum + GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING_ARB* = 0x889C.GLenum + GL_DEBUG_SEVERITY_HIGH_KHR* = 0x9146.GLenum + GL_DRAW_BUFFER14_EXT* = 0x8833.GLenum + GL_READ_FRAMEBUFFER* = 0x8CA8.GLenum + GL_UNSIGNED_SHORT_8_8_APPLE* = 0x85BA.GLenum + GL_OR* = 0x1507.GLenum + GL_ONE_MINUS_DST_ALPHA* = 0x0305.GLenum + GL_RGB12* = 0x8053.GLenum + GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_OES* = 0x8CDB.GLenum + GL_OUTPUT_TEXTURE_COORD26_EXT* = 0x87B7.GLenum + GL_LOCAL_CONSTANT_VALUE_EXT* = 0x87EC.GLenum + GL_SURFACE_REGISTERED_NV* = 0x86FD.GLenum + GL_FRAGMENT_PROGRAM_INTERPOLATION_OFFSET_BITS_NV* = 0x8E5D.GLenum + GL_COMPRESSED_RG_RGTC2* = 0x8DBD.GLenum + GL_MAX_VERTEX_ATTRIB_STRIDE* = 0x82E5.GLenum + GL_COLOR_ARRAY_ADDRESS_NV* = 0x8F23.GLenum + GL_MATRIX_INDEX_ARRAY_POINTER_ARB* = 0x8849.GLenum + GL_DUAL_ALPHA8_SGIS* = 0x8111.GLenum + GL_TEXTURE_MAX_LOD* = 0x813B.GLenum + GL_INTERNALFORMAT_SHARED_SIZE* = 0x8277.GLenum + GL_LINEAR_DETAIL_SGIS* = 0x8097.GLenum + GL_RG16F_EXT* = 0x822F.GLenum + GL_LIST_MODE* = 0x0B30.GLenum + GL_VIEWPORT_INDEX_PROVOKING_VERTEX* = 0x825F.GLenum + GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW* = 0x900D.GLenum + GL_COLOR_TABLE_LUMINANCE_SIZE* = 0x80DE.GLenum + GL_COLOR_ARRAY_POINTER* = 0x8090.GLenum + GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT* = 0x84FF.GLenum + GL_LUMINANCE32F_EXT* = 0x8818.GLenum + GL_FRAMEBUFFER_COMPLETE_OES* = 0x8CD5.GLenum + GL_MAX_PROGRAM_TEXTURE_GATHER_COMPONENTS_ARB* = 0x8F9F.GLenum + GL_FEEDBACK* = 0x1C01.GLenum + GL_UNSIGNED_INT_IMAGE_2D_ARRAY* = 0x9069.GLenum + GL_VERTEX_STREAM1_ATI* = 0x876D.GLenum + GL_SLUMINANCE_ALPHA_NV* = 0x8C44.GLenum + GL_MAX_TEXTURE_UNITS_ARB* = 0x84E2.GLenum + GL_MODELVIEW11_ARB* = 0x872B.GLenum + GL_DRAW_FRAMEBUFFER_BINDING_ANGLE* = 0x8CA6.GLenum + GL_NEGATIVE_W_EXT* = 0x87DC.GLenum + GL_MODELVIEW25_ARB* = 0x8739.GLenum + GL_NORMAL_ARRAY_LIST_STRIDE_IBM* = 103081.GLenum + GL_CON_0_ATI* = 0x8941.GLenum + GL_VERTEX_SHADER_INSTRUCTIONS_EXT* = 0x87CF.GLenum + GL_TRANSPOSE_PROGRAM_MATRIX_EXT* = 0x8E2E.GLenum + GL_TEXTURE_DEPTH_TYPE* = 0x8C16.GLenum + GL_PROGRAM_TARGET_NV* = 0x8646.GLenum + GL_MAX_OPTIMIZED_VERTEX_SHADER_LOCAL_CONSTANTS_EXT* = 0x87CC.GLenum + GL_NORMAL_ARRAY_STRIDE_EXT* = 0x807F.GLenum + GL_INT_SAMPLER_2D* = 0x8DCA.GLenum + GL_MAP2_VERTEX_ATTRIB10_4_NV* = 0x867A.GLenum + GL_STEREO* = 0x0C33.GLenum + GL_UNSIGNED_INT_IMAGE_2D_RECT_EXT* = 0x9065.GLenum + GL_TESS_EVALUATION_PROGRAM_PARAMETER_BUFFER_NV* = 0x8C75.GLenum + GL_TRACE_ERRORS_BIT_MESA* = 0x0020.GLbitfield + GL_MAX_GEOMETRY_UNIFORM_BLOCKS* = 0x8A2C.GLenum + GL_CONVOLUTION_2D* = 0x8011.GLenum + GL_RGB_SCALE_ARB* = 0x8573.GLenum + GL_VIDEO_COLOR_CONVERSION_MAX_NV* = 0x902A.GLenum + GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS* = 0x90DD.GLenum + GL_TABLE_TOO_LARGE_EXT* = 0x8031.GLenum + GL_TRANSFORM_FEEDBACK_BINDING_NV* = 0x8E25.GLenum + GL_TEXTURE16_ARB* = 0x84D0.GLenum + GL_FRAGMENT_SHADER_DERIVATIVE_HINT* = 0x8B8B.GLenum + GL_IUI_N3F_V2F_EXT* = 0x81AF.GLenum + GL_CLIP_PLANE2_IMG* = 0x3002.GLenum + GL_VERTEX_ATTRIB_ARRAY10_NV* = 0x865A.GLenum + GL_TEXTURE_FETCH_BARRIER_BIT* = 0x00000008.GLbitfield + GL_DOT3_RGBA_EXT* = 0x8741.GLenum + GL_RENDERBUFFER_GREEN_SIZE_EXT* = 0x8D51.GLenum + GL_MAX_CLIENT_ATTRIB_STACK_DEPTH* = 0x0D3B.GLenum + GL_UNPACK_COMPRESSED_BLOCK_SIZE* = 0x912A.GLenum + GL_SAMPLE_BUFFERS_SGIS* = 0x80A8.GLenum + GL_MAP1_VERTEX_ATTRIB1_4_NV* = 0x8661.GLenum + GL_BUFFER_OBJECT_EXT* = 0x9151.GLenum + GL_INT_SAMPLER_1D_ARRAY* = 0x8DCE.GLenum + GL_POST_TEXTURE_FILTER_SCALE_SGIX* = 0x817A.GLenum + GL_RED_MAX_CLAMP_INGR* = 0x8564.GLenum + GL_POST_COLOR_MATRIX_RED_SCALE_SGI* = 0x80B4.GLenum + GL_TEXTURE_COORD_ARRAY_TYPE* = 0x8089.GLenum + GL_COMPRESSED_SIGNED_RG11_EAC* = 0x9273.GLenum + GL_MULTISAMPLE_FILTER_HINT_NV* = 0x8534.GLenum + GL_COMPRESSED_RGBA8_ETC2_EAC* = 0x9278.GLenum + GL_FONT_UNDERLINE_THICKNESS_BIT_NV* = 0x08000000.GLbitfield + GL_READ_WRITE_ARB* = 0x88BA.GLenum + GL_RENDER_MODE* = 0x0C40.GLenum + GL_MAX_NUM_COMPATIBLE_SUBROUTINES* = 0x92F8.GLenum + GL_PN_TRIANGLES_NORMAL_MODE_QUADRATIC_ATI* = 0x87F8.GLenum + GL_MODELVIEW0_STACK_DEPTH_EXT* = 0x0BA3.GLenum + GL_CONTEXT_FLAG_DEBUG_BIT* = 0x00000002.GLbitfield + GL_TRANSFORM_FEEDBACK_BUFFER_START_EXT* = 0x8C84.GLenum + GL_POINT_SIZE_MAX_EXT* = 0x8127.GLenum + GL_COLOR_ARRAY_LENGTH_NV* = 0x8F2D.GLenum + GL_COLOR_COMPONENTS* = 0x8283.GLenum + GL_LINEARDODGE_NV* = 0x92A4.GLenum + GL_TEXTURE20_ARB* = 0x84D4.GLenum + GL_UNSIGNED_INT64_VEC4_NV* = 0x8FF7.GLenum + GL_TEXTURE28* = 0x84DC.GLenum + GL_HISTOGRAM_FORMAT_EXT* = 0x8027.GLenum + GL_PROGRAM_MATRIX_EXT* = 0x8E2D.GLenum + GL_PIXEL_PACK_BUFFER_EXT* = 0x88EB.GLenum + GL_TEXTURE_CUBE_MAP_POSITIVE_X_EXT* = 0x8515.GLenum + GL_STANDARD_FONT_NAME_NV* = 0x9072.GLenum + GL_REG_13_ATI* = 0x892E.GLenum + GL_GREEN_SCALE* = 0x0D18.GLenum + GL_COLOR_BUFFER_BIT7_QCOM* = 0x00000080.GLbitfield + GL_MAX_COMPUTE_ATOMIC_COUNTER_BUFFERS* = 0x8264.GLenum + GL_LUMINANCE8_ALPHA8_SNORM* = 0x9016.GLenum + GL_GCCSO_SHADER_BINARY_FJ* = 0x9260.GLenum + GL_COORD_REPLACE_NV* = 0x8862.GLenum + GL_SOURCE2_RGB_EXT* = 0x8582.GLenum + GL_IR_INSTRUMENT1_SGIX* = 0x817F.GLenum + GL_CONTEXT_FLAG_DEBUG_BIT_KHR* = 0x00000002.GLbitfield + GL_SWIZZLE_STR_ATI* = 0x8976.GLenum + GL_OUTPUT_TEXTURE_COORD17_EXT* = 0x87AE.GLenum + GL_MODELVIEW2_ARB* = 0x8722.GLenum + GL_R1UI_C4F_N3F_V3F_SUN* = 0x85C8.GLenum + GL_MAX_TEXTURE_BUFFER_SIZE_ARB* = 0x8C2B.GLenum + GL_OUTPUT_TEXTURE_COORD0_EXT* = 0x879D.GLenum + GL_POINT_FADE_THRESHOLD_SIZE_EXT* = 0x8128.GLenum + GL_OUTPUT_TEXTURE_COORD30_EXT* = 0x87BB.GLenum + GL_EVAL_VERTEX_ATTRIB3_NV* = 0x86C9.GLenum + GL_SPHERE_MAP* = 0x2402.GLenum + GL_SHADER_IMAGE_ATOMIC* = 0x82A6.GLenum + GL_INDEX_BITS* = 0x0D51.GLenum + GL_INTERNALFORMAT_ALPHA_TYPE* = 0x827B.GLenum + GL_CON_15_ATI* = 0x8950.GLenum + GL_TESS_EVALUATION_TEXTURE* = 0x829D.GLenum + GL_EDGE_FLAG_ARRAY_STRIDE* = 0x808C.GLenum + GL_VERTEX_ATTRIB_ARRAY8_NV* = 0x8658.GLenum + GL_POST_COLOR_MATRIX_COLOR_TABLE* = 0x80D2.GLenum + GL_CLOSE_PATH_NV* = 0x00.GLenum + GL_SCALE_BY_TWO_NV* = 0x853E.GLenum + GL_PALETTE8_RGB8_OES* = 0x8B95.GLenum + GL_MAX_COMPUTE_ATOMIC_COUNTERS* = 0x8265.GLenum + GL_VERTEX_ATTRIB_ARRAY_NORMALIZED* = 0x886A.GLenum + GL_MAX_VERTEX_ATTRIBS* = 0x8869.GLenum + GL_PROGRAM_POINT_SIZE_EXT* = 0x8642.GLenum + GL_TRANSLATED_SHADER_SOURCE_LENGTH_ANGLE* = 0x93A0.GLenum + GL_SIGNED_NORMALIZED* = 0x8F9C.GLenum + GL_MAX_CUBE_MAP_TEXTURE_SIZE_OES* = 0x851C.GLenum + GL_OFFSET_TEXTURE_2D_SCALE_NV* = 0x86E2.GLenum + GL_COMPRESSED_SLUMINANCE* = 0x8C4A.GLenum + GL_MAX_TESS_EVALUATION_UNIFORM_COMPONENTS* = 0x8E80.GLenum + GL_RASTER_POSITION_UNCLIPPED_IBM* = 0x19262.GLenum + GL_COMPRESSED_TEXTURE_FORMATS_ARB* = 0x86A3.GLenum + GL_TRANSPOSE_MODELVIEW_MATRIX* = 0x84E3.GLenum + GL_ALPHA_FLOAT16_APPLE* = 0x881C.GLenum + GL_PIXEL_MIN_FILTER_EXT* = 0x8332.GLenum + GL_MAX_SPARSE_TEXTURE_SIZE_AMD* = 0x9198.GLenum + GL_UNSIGNED_SHORT_5_6_5_REV_EXT* = 0x8364.GLenum + GL_DU8DV8_ATI* = 0x877A.GLenum + GL_COLOR_ARRAY_LIST_IBM* = 103072.GLenum + GL_RGBA8I_EXT* = 0x8D8E.GLenum + GL_MULTISAMPLE_BUFFER_BIT4_QCOM* = 0x10000000.GLbitfield + GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB* = 0x824D.GLenum + GL_MODELVIEW20_ARB* = 0x8734.GLenum + GL_COLOR_TABLE_RED_SIZE* = 0x80DA.GLenum + GL_UNIFORM_BARRIER_BIT* = 0x00000004.GLbitfield + GL_TEXTURE* = 0x1702.GLenum + GL_CLIP_PLANE0* = 0x3000.GLenum + GL_FOG_COORDINATE_ARRAY_POINTER* = 0x8456.GLenum + GL_CONSTANT_ALPHA_EXT* = 0x8003.GLenum + GL_NAME_STACK_DEPTH* = 0x0D70.GLenum + GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE* = 0x83F2.GLenum + GL_LINEAR_DETAIL_ALPHA_SGIS* = 0x8098.GLenum + GL_EDGE_FLAG_ARRAY_POINTER_EXT* = 0x8093.GLenum + GL_UNSIGNED_SHORT* = 0x1403.GLenum + GL_MAP2_VERTEX_ATTRIB1_4_NV* = 0x8671.GLenum + GL_DEPTH_CLAMP_FAR_AMD* = 0x901F.GLenum + GL_OPERAND3_RGB_NV* = 0x8593.GLenum + GL_TEXTURE_SWIZZLE_R_EXT* = 0x8E42.GLenum + GL_PATCHES* = 0x000E.GLenum + GL_TEXTURE12* = 0x84CC.GLenum + GL_COLOR_ATTACHMENT12_EXT* = 0x8CEC.GLenum + GL_MAP2_VERTEX_ATTRIB15_4_NV* = 0x867F.GLenum + GL_DRAW_BUFFER15_ATI* = 0x8834.GLenum + GL_GEOMETRY_INPUT_TYPE* = 0x8917.GLenum + GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC_OES* = 0x9279.GLenum + GL_RGBA32UI_EXT* = 0x8D70.GLenum + GL_RGBA_FLOAT32_APPLE* = 0x8814.GLenum + GL_NORMAL_MAP_OES* = 0x8511.GLenum + GL_MAP2_GRID_DOMAIN* = 0x0DD2.GLenum + GL_RELATIVE_HORIZONTAL_LINE_TO_NV* = 0x07.GLenum + GL_TANGENT_ARRAY_STRIDE_EXT* = 0x843F.GLenum + GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT* = 0x8CDB.GLenum + GL_OBJECT_POINT_SGIS* = 0x81F5.GLenum + GL_IMAGE_2D_ARRAY* = 0x9053.GLenum + GL_MAX_GEOMETRY_UNIFORM_COMPONENTS_ARB* = 0x8DDF.GLenum + GL_SPRITE_MODE_SGIX* = 0x8149.GLenum + GL_WEIGHT_ARRAY_OES* = 0x86AD.GLenum + GL_MAX_VERTEX_STREAMS* = 0x8E71.GLenum + GL_R16F_EXT* = 0x822D.GLenum + GL_VERSION_ES_CL_1_0* = 1.GLenum + GL_PROXY_TEXTURE_COLOR_TABLE_SGI* = 0x80BD.GLenum + GL_MAX_PROGRAM_INSTRUCTIONS_ARB* = 0x88A1.GLenum + GL_PURGEABLE_APPLE* = 0x8A1D.GLenum + GL_TEXTURE_SWIZZLE_G_EXT* = 0x8E43.GLenum + GL_FIRST_VERTEX_CONVENTION_EXT* = 0x8E4D.GLenum + GL_DEBUG_SEVERITY_LOW* = 0x9148.GLenum + GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT* = 0x00000001.GLbitfield + GL_OBJECT_ACTIVE_ATTRIBUTE_MAX_LENGTH_ARB* = 0x8B8A.GLenum + GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR* = 0x93D4.GLenum + GL_DOT_PRODUCT_CONST_EYE_REFLECT_CUBE_MAP_NV* = 0x86F3.GLenum + GL_RENDERBUFFER_DEPTH_SIZE* = 0x8D54.GLenum + GL_OPERAND1_RGB_ARB* = 0x8591.GLenum + GL_REFLECTION_MAP_NV* = 0x8512.GLenum + GL_MATRIX17_ARB* = 0x88D1.GLenum + GL_EYE_PLANE_ABSOLUTE_NV* = 0x855C.GLenum + GL_SRC1_ALPHA* = 0x8589.GLenum + GL_UNSIGNED_BYTE_2_3_3_REV* = 0x8362.GLenum + GL_RGB5_EXT* = 0x8050.GLenum + GL_TEXTURE_2D_ARRAY* = 0x8C1A.GLenum + GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB* = 0x8515.GLenum + GL_TEXTURE26* = 0x84DA.GLenum + GL_MAX_3D_TEXTURE_SIZE_OES* = 0x8073.GLenum + GL_PIXEL_TILE_WIDTH_SGIX* = 0x8140.GLenum + GL_PIXEL_UNPACK_BUFFER_BINDING_EXT* = 0x88EF.GLenum + GL_TEXTURE_ALPHA_SIZE* = 0x805F.GLenum + GL_RELATIVE_QUADRATIC_CURVE_TO_NV* = 0x0B.GLenum + GL_POINT_SIZE_ARRAY_BUFFER_BINDING_OES* = 0x8B9F.GLenum + GL_GEOMETRY_DEFORMATION_BIT_SGIX* = 0x00000002.GLbitfield + GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS* = 0x8DA8.GLenum + GL_NAMED_STRING_LENGTH_ARB* = 0x8DE9.GLenum + GL_IMAGE_1D_ARRAY* = 0x9052.GLenum + GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_OES* = 0x8CD4.GLenum + GL_MATRIX28_ARB* = 0x88DC.GLenum + GL_FRAGMENT_LIGHT1_SGIX* = 0x840D.GLenum + GL_HARDMIX_NV* = 0x92A9.GLenum + GL_DEBUG_SOURCE_THIRD_PARTY_KHR* = 0x8249.GLenum + GL_PACK_SWAP_BYTES* = 0x0D00.GLenum + GL_MAX_VERTEX_UNIFORM_COMPONENTS_ARB* = 0x8B4A.GLenum + GL_SOURCE2_ALPHA_EXT* = 0x858A.GLenum + GL_DOUBLE_MAT2x4* = 0x8F4A.GLenum + GL_MEDIUM_FLOAT* = 0x8DF1.GLenum + GL_PIXEL_TILE_BEST_ALIGNMENT_SGIX* = 0x813E.GLenum + GL_UNPACK_SKIP_ROWS* = 0x0CF3.GLenum + GL_PACK_COMPRESSED_BLOCK_SIZE* = 0x912E.GLenum + GL_UNSIGNED_INT_IMAGE_2D* = 0x9063.GLenum + GL_COLOR_ARRAY_TYPE_EXT* = 0x8082.GLenum + GL_BUFFER_MAP_POINTER_ARB* = 0x88BD.GLenum + GL_CALLIGRAPHIC_FRAGMENT_SGIX* = 0x8183.GLenum + GL_ONE_MINUS_CONSTANT_COLOR_EXT* = 0x8002.GLenum + GL_COMPRESSED_RGBA_FXT1_3DFX* = 0x86B1.GLenum + GL_CLIP_PLANE1* = 0x3001.GLenum + GL_COVERAGE_BUFFERS_NV* = 0x8ED3.GLenum + GL_ADD_BLEND_IMG* = 0x8C09.GLenum + GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR* = 0x93D5.GLenum + GL_PIXEL_TILE_HEIGHT_SGIX* = 0x8141.GLenum + GL_SAMPLE_COVERAGE_INVERT_ARB* = 0x80AB.GLenum + GL_MAP1_VERTEX_ATTRIB9_4_NV* = 0x8669.GLenum + GL_COLOR_TABLE_BIAS_SGI* = 0x80D7.GLenum + GL_EDGE_FLAG_ARRAY_COUNT_EXT* = 0x808D.GLenum + GL_SAMPLE_BUFFERS_EXT* = 0x80A8.GLenum + GL_COLOR_INDEX* = 0x1900.GLenum + GL_REPLACEMENT_CODE_SUN* = 0x81D8.GLenum + GL_INT_SAMPLER_CUBE_EXT* = 0x8DCC.GLenum + GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE* = 0x8D56.GLenum + GL_VERTEX_ATTRIB_ARRAY_UNIFIED_NV* = 0x8F1E.GLenum + GL_DUAL_LUMINANCE_ALPHA8_SGIS* = 0x811D.GLenum + GL_PIXEL_TEX_GEN_ALPHA_LS_SGIX* = 0x8189.GLenum + GL_CLIP_DISTANCE7* = 0x3007.GLenum + GL_DOT3_RGB_ARB* = 0x86AE.GLenum + GL_TEXTURE_WRAP_T* = 0x2803.GLenum + GL_LUMINANCE12_EXT* = 0x8041.GLenum + GL_TEXTURE_CLIPMAP_VIRTUAL_DEPTH_SGIX* = 0x8174.GLenum + GL_TEXTURE_COMPRESSED_IMAGE_SIZE_ARB* = 0x86A0.GLenum + GL_EVAL_2D_NV* = 0x86C0.GLenum + GL_FRAMEBUFFER_DEFAULT_FIXED_SAMPLE_LOCATIONS* = 0x9314.GLenum + GL_CURRENT_WEIGHT_ARB* = 0x86A8.GLenum + GL_DEBUG_SOURCE_API_ARB* = 0x8246.GLenum + GL_FOG_SPECULAR_TEXTURE_WIN* = 0x80EC.GLenum + GL_BOOL_VEC4* = 0x8B59.GLenum + GL_FRAGMENTS_INSTRUMENT_SGIX* = 0x8313.GLenum + GL_GEOMETRY_OUTPUT_TYPE_EXT* = 0x8DDC.GLenum + GL_TEXTURE_2D* = 0x0DE1.GLenum + GL_MAT_AMBIENT_AND_DIFFUSE_BIT_PGI* = 0x00200000.GLbitfield + GL_TEXTURE_BINDING_RECTANGLE_ARB* = 0x84F6.GLenum + GL_SAMPLE_BUFFERS_3DFX* = 0x86B3.GLenum + GL_INDEX_OFFSET* = 0x0D13.GLenum + GL_MAX_COLOR_ATTACHMENTS* = 0x8CDF.GLenum + GL_PLUS_CLAMPED_NV* = 0x92B1.GLenum + GL_SIGNED_NEGATE_NV* = 0x853D.GLenum + GL_PROXY_TEXTURE_2D_STACK_MESAX* = 0x875C.GLenum + GL_MAX_VERTEX_UNIFORM_COMPONENTS* = 0x8B4A.GLenum + GL_SAMPLE_MASK_VALUE_SGIS* = 0x80AA.GLenum + GL_QUADRATIC_ATTENUATION* = 0x1209.GLenum + GL_LUMINANCE32F_ARB* = 0x8818.GLenum + GL_COVERAGE_COMPONENT4_NV* = 0x8ED1.GLenum + GL_MINMAX_FORMAT* = 0x802F.GLenum + GL_SRGB_DECODE_ARB* = 0x8299.GLenum + GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT* = 0x8CDA.GLenum + GL_UNSIGNED_INT_SAMPLER_CUBE_EXT* = 0x8DD4.GLenum + GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2* = 0x9277.GLenum + GL_DISJOINT_NV* = 0x9283.GLenum + GL_TEXTURE_ENV_BIAS_SGIX* = 0x80BE.GLenum + GL_PROXY_TEXTURE_3D_EXT* = 0x8070.GLenum + GL_SGX_BINARY_IMG* = 0x8C0A.GLenum + GL_COPY_READ_BUFFER* = 0x8F36.GLenum + GL_POINT_FADE_THRESHOLD_SIZE_SGIS* = 0x8128.GLenum + GL_UNIFORM_MATRIX_STRIDE* = 0x8A3D.GLenum + GL_UNIFORM_BLOCK_NAME_LENGTH* = 0x8A41.GLenum + GL_HISTOGRAM_LUMINANCE_SIZE* = 0x802C.GLenum + GL_UNSIGNED_SHORT_4_4_4_4* = 0x8033.GLenum + GL_MAX_DEPTH* = 0x8280.GLenum + GL_IMAGE_1D* = 0x904C.GLenum + GL_LUMINANCE8_ALPHA8_EXT* = 0x8045.GLenum + GL_MAX_TEXTURE_IMAGE_UNITS* = 0x8872.GLenum + GL_MODELVIEW16_ARB* = 0x8730.GLenum + GL_CURRENT_PALETTE_MATRIX_OES* = 0x8843.GLenum + GL_SIGNED_HILO_NV* = 0x86F9.GLenum + GL_FRAMEBUFFER_DEFAULT_HEIGHT* = 0x9311.GLenum + GL_UNPACK_SKIP_IMAGES* = 0x806D.GLenum + GL_2_BYTES* = 0x1407.GLenum + GL_ALLOW_DRAW_FRG_HINT_PGI* = 0x1A210.GLenum + GL_INTENSITY16I_EXT* = 0x8D8B.GLenum + GL_MAX_SAMPLES_NV* = 0x8D57.GLenum + GL_VERTEX_ARRAY_STORAGE_HINT_APPLE* = 0x851F.GLenum + GL_LINE_STRIP_ADJACENCY_ARB* = 0x000B.GLenum + GL_COORD_REPLACE* = 0x8862.GLenum + GL_INDEX_MATERIAL_FACE_EXT* = 0x81BA.GLenum + GL_MODELVIEW15_ARB* = 0x872F.GLenum + GL_TEXTURE19* = 0x84D3.GLenum + GL_UNSIGNED_INT_IMAGE_1D_ARRAY_EXT* = 0x9068.GLenum + GL_SIGNED_INTENSITY8_NV* = 0x8708.GLenum + GL_TEXTURE_MAG_SIZE_NV* = 0x871F.GLenum + GL_DISPATCH_INDIRECT_BUFFER* = 0x90EE.GLenum + GL_MAP1_INDEX* = 0x0D91.GLenum + GL_TEXTURE_BUFFER_DATA_STORE_BINDING* = 0x8C2D.GLenum + GL_MAX_HEIGHT* = 0x827F.GLenum + GL_BLEND_DST_ALPHA* = 0x80CA.GLenum + GL_R1UI_C3F_V3F_SUN* = 0x85C6.GLenum + GL_TEXTURE_PRIORITY_EXT* = 0x8066.GLenum + GL_INT_IMAGE_2D* = 0x9058.GLenum + GL_MAX_MULTISAMPLE_COVERAGE_MODES_NV* = 0x8E11.GLenum + GL_DRAW_BUFFER4_ATI* = 0x8829.GLenum + GL_MAX_GEOMETRY_VARYING_COMPONENTS_ARB* = 0x8DDD.GLenum + GL_DEPTH_EXT* = 0x1801.GLenum + GL_SAMPLE_POSITION* = 0x8E50.GLenum + GL_INTERNALFORMAT_DEPTH_TYPE* = 0x827C.GLenum + GL_MATRIX23_ARB* = 0x88D7.GLenum + GL_DEBUG_TYPE_PUSH_GROUP* = 0x8269.GLenum + GL_POLYGON_OFFSET_FILL* = 0x8037.GLenum + GL_FRAGMENT_PROGRAM_BINDING_NV* = 0x8873.GLenum + GL_FRAMEBUFFER_SRGB_CAPABLE_EXT* = 0x8DBA.GLenum + GL_VERTEX_ATTRIB_BINDING* = 0x82D4.GLenum + GL_UNSIGNED_INT8_VEC2_NV* = 0x8FED.GLenum + GL_POLYGON_OFFSET_FACTOR* = 0x8038.GLenum + GL_BOLD_BIT_NV* = 0x01.GLbitfield + GL_CLAMP_TO_BORDER_ARB* = 0x812D.GLint + GL_INDEX_MODE* = 0x0C30.GLenum + GL_SAMPLER_CUBE_SHADOW_NV* = 0x8DC5.GLenum + GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT* = 0x8C4F.GLenum + GL_MATRIX21_ARB* = 0x88D5.GLenum + GL_UNPACK_ROW_LENGTH_EXT* = 0x0CF2.GLenum + GL_FRAGMENT_NORMAL_EXT* = 0x834A.GLenum + GL_DOT3_ATI* = 0x8966.GLenum + GL_IMPLEMENTATION_COLOR_READ_TYPE_OES* = 0x8B9A.GLenum + GL_IMAGE_BINDING_ACCESS_EXT* = 0x8F3E.GLenum + GL_SYNC_CL_EVENT_ARB* = 0x8240.GLenum + GL_UNSIGNED_INT_24_8* = 0x84FA.GLenum + GL_2PASS_1_EXT* = 0x80A3.GLenum + GL_POST_TEXTURE_FILTER_BIAS_SGIX* = 0x8179.GLenum + GL_TEXTURE_COMPRESSED_IMAGE_SIZE* = 0x86A0.GLenum + GL_LUMINANCE_ALPHA32UI_EXT* = 0x8D75.GLenum + GL_FORCE_BLUE_TO_ONE_NV* = 0x8860.GLenum + GL_FRAMEBUFFER_DEFAULT* = 0x8218.GLenum + GL_VIRTUAL_PAGE_SIZE_Z_ARB* = 0x9197.GLenum + GL_TEXTURE_LIGHT_EXT* = 0x8350.GLenum + GL_MULTISAMPLE_BUFFER_BIT5_QCOM* = 0x20000000.GLbitfield + GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY* = 0x910D.GLenum + GL_SYNC_CONDITION* = 0x9113.GLenum + GL_PERFMON_RESULT_SIZE_AMD* = 0x8BC5.GLenum + GL_PROGRAM_OBJECT_ARB* = 0x8B40.GLenum + GL_MAX_SHININESS_NV* = 0x8504.GLenum + GL_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB* = 0x880A.GLenum + GL_RENDERBUFFER_COLOR_SAMPLES_NV* = 0x8E10.GLenum + GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS* = 0x8A31.GLenum + GL_ACTIVE_SUBROUTINE_UNIFORM_MAX_LENGTH* = 0x8E49.GLenum + GL_MODELVIEW29_ARB* = 0x873D.GLenum + GL_PROXY_TEXTURE_CUBE_MAP_ARRAY_ARB* = 0x900B.GLenum + GL_SIGNED_HILO16_NV* = 0x86FA.GLenum + GL_TRANSFORM_HINT_APPLE* = 0x85B1.GLenum + GL_STENCIL_INDEX4* = 0x8D47.GLenum + GL_EXTENSIONS* = 0x1F03.GLenum + GL_RG16F* = 0x822F.GLenum + GL_MAP_UNSYNCHRONIZED_BIT_EXT* = 0x0020.GLbitfield + GL_LUMINANCE16F_ARB* = 0x881E.GLenum + GL_UNSIGNED_INT_IMAGE_BUFFER* = 0x9067.GLenum + GL_COMPRESSED_RGBA_ASTC_8x8_KHR* = 0x93B7.GLenum + GL_AVERAGE_HP* = 0x8160.GLenum + GL_INDEX_MATERIAL_EXT* = 0x81B8.GLenum + GL_COLOR_TABLE* = 0x80D0.GLenum + GL_FOG_COORDINATE_ARRAY_LIST_IBM* = 103076.GLenum + GL_DEBUG_CATEGORY_OTHER_AMD* = 0x9150.GLenum + GL_R1UI_C4UB_V3F_SUN* = 0x85C5.GLenum + GL_SYSTEM_FONT_NAME_NV* = 0x9073.GLenum + GL_STATIC_VERTEX_ARRAY_IBM* = 103061.GLenum + GL_VERTEX_ATTRIB_ARRAY_DIVISOR_NV* = 0x88FE.GLenum + GL_SCALE_BY_ONE_HALF_NV* = 0x8540.GLenum + GL_INTENSITY_FLOAT32_ATI* = 0x8817.GLenum + GL_FRAGMENT_LIGHT6_SGIX* = 0x8412.GLenum + GL_DECR_WRAP_OES* = 0x8508.GLenum + GL_MODELVIEW23_ARB* = 0x8737.GLenum + GL_PROXY_TEXTURE_1D_ARRAY* = 0x8C19.GLenum + GL_REFERENCED_BY_VERTEX_SHADER* = 0x9306.GLenum + GL_MAX_NAME_LENGTH* = 0x92F6.GLenum + GL_AFFINE_2D_NV* = 0x9092.GLenum + GL_SYNC_OBJECT_APPLE* = 0x8A53.GLenum + GL_PLUS_DARKER_NV* = 0x9292.GLenum + GL_TESS_CONTROL_PROGRAM_NV* = 0x891E.GLenum + GL_RGB_SCALE* = 0x8573.GLenum + GL_RGBA16UI_EXT* = 0x8D76.GLenum + GL_COMPATIBLE_SUBROUTINES* = 0x8E4B.GLenum + GL_COLOR_TABLE_WIDTH* = 0x80D9.GLenum + GL_MAX_COMBINED_UNIFORM_BLOCKS* = 0x8A2E.GLenum + GL_BACK_SECONDARY_COLOR_NV* = 0x8C78.GLenum + GL_MAX_COMPUTE_VARIABLE_GROUP_INVOCATIONS_ARB* = 0x9344.GLenum + GL_SECONDARY_COLOR_NV* = 0x852D.GLenum + GL_RGB16UI_EXT* = 0x8D77.GLenum + GL_SHADER_STORAGE_BUFFER_SIZE* = 0x90D5.GLenum + GL_VERTEX_SUBROUTINE* = 0x92E8.GLenum + GL_MAP_COLOR* = 0x0D10.GLenum + GL_OBJECT_TYPE_ARB* = 0x8B4E.GLenum + GL_LAST_VIDEO_CAPTURE_STATUS_NV* = 0x9027.GLenum + GL_RGB12_EXT* = 0x8053.GLenum + GL_UNSIGNED_INT_IMAGE_3D_EXT* = 0x9064.GLenum + GL_LUMINANCE8_ALPHA8* = 0x8045.GLenum + GL_FLOAT_RGBA_MODE_NV* = 0x888E.GLenum + GL_CURRENT_RASTER_COLOR* = 0x0B04.GLenum + GL_CURRENT_RASTER_POSITION* = 0x0B07.GLenum + GL_UNIFORM_BLOCK_DATA_SIZE* = 0x8A40.GLenum + GL_MALI_PROGRAM_BINARY_ARM* = 0x8F61.GLenum + GL_QUERY_COUNTER_BITS_ARB* = 0x8864.GLenum + GL_VARIANT_ARRAY_EXT* = 0x87E8.GLenum + GL_VIDEO_CAPTURE_FIELD_UPPER_HEIGHT_NV* = 0x903A.GLenum + GL_DEPTH_COMPONENT24_ARB* = 0x81A6.GLenum + GL_UNSIGNED_INVERT_NV* = 0x8537.GLenum + GL_TEXTURE_IMMUTABLE_LEVELS* = 0x82DF.GLenum + GL_DRAW_BUFFER12_ATI* = 0x8831.GLenum + GL_MAP_FLUSH_EXPLICIT_BIT_EXT* = 0x0010.GLbitfield + GL_INDEX_WRITEMASK* = 0x0C21.GLenum + GL_POLYGON_SMOOTH* = 0x0B41.GLenum + GL_COMPRESSED_SIGNED_R11_EAC_OES* = 0x9271.GLenum + GL_TEXTURE_SWIZZLE_A_EXT* = 0x8E45.GLenum + GL_TEXTURE_COORD_ARRAY_STRIDE* = 0x808A.GLenum + GL_PIXEL_MAP_I_TO_R* = 0x0C72.GLenum + GL_CONVOLUTION_HEIGHT* = 0x8019.GLenum + GL_SIGNALED* = 0x9119.GLenum + GL_UNSIGNED_INT_24_8_OES* = 0x84FA.GLenum + GL_DRAW_BUFFER6_ARB* = 0x882B.GLenum + GL_BUFFER_SIZE_ARB* = 0x8764.GLenum + GL_CLEAR_BUFFER* = 0x82B4.GLenum + GL_LUMINANCE16UI_EXT* = 0x8D7A.GLenum + GL_FRAMEBUFFER_ATTACHMENT_ANGLE* = 0x93A3.GLenum + GL_STENCIL_ATTACHMENT* = 0x8D20.GLenum + GL_ALL_COMPLETED_NV* = 0x84F2.GLenum + GL_MIN* = 0x8007.GLenum + GL_COLOR_ATTACHMENT11* = 0x8CEB.GLenum + GL_PATH_STENCIL_FUNC_NV* = 0x90B7.GLenum + GL_MAX_LABEL_LENGTH* = 0x82E8.GLenum + GL_WEIGHT_ARRAY_TYPE_OES* = 0x86A9.GLenum + GL_ACCUM_BUFFER_BIT* = 0x00000200.GLbitfield + GL_WEIGHT_ARRAY_POINTER_ARB* = 0x86AC.GLenum + GL_WEIGHT_SUM_UNITY_ARB* = 0x86A6.GLenum + GL_COMPRESSED_SRGB_EXT* = 0x8C48.GLenum + GL_ATTRIB_ARRAY_TYPE_NV* = 0x8625.GLenum + GL_RED_INTEGER_EXT* = 0x8D94.GLenum + GL_ALWAYS_SOFT_HINT_PGI* = 0x1A20D.GLenum + GL_COMPRESSED_SRGB8_ETC2_OES* = 0x9275.GLenum + GL_LOW_FLOAT* = 0x8DF0.GLenum + GL_PIXEL_FRAGMENT_RGB_SOURCE_SGIS* = 0x8354.GLenum + GL_TEXTURE_LEQUAL_R_SGIX* = 0x819C.GLenum + GL_CONTEXT_COMPATIBILITY_PROFILE_BIT* = 0x00000002.GLbitfield + GL_INCR* = 0x1E02.GLenum + GL_3D* = 0x0601.GLenum + GL_SHADER_KHR* = 0x82E1.GLenum + GL_SRC_COLOR* = 0x0300.GLenum + GL_DRAW_BUFFER7_NV* = 0x882C.GLenum + GL_VERTEX_ARRAY_SIZE* = 0x807A.GLenum + GL_SAMPLER_2D_RECT* = 0x8B63.GLenum + GL_UNSIGNED_SHORT_4_4_4_4_REV_IMG* = 0x8365.GLenum + GL_READ_PIXEL_DATA_RANGE_NV* = 0x8879.GLenum + GL_EDGE_FLAG* = 0x0B43.GLenum + GL_TEXTURE_3D_EXT* = 0x806F.GLenum + GL_DOT_PRODUCT_TEXTURE_1D_NV* = 0x885C.GLenum + GL_COLOR_SUM_CLAMP_NV* = 0x854F.GLenum + GL_RGB10_A2* = 0x8059.GLenum + GL_BOOL_VEC3* = 0x8B58.GLenum + GL_REG_3_ATI* = 0x8924.GLenum + GL_LINEAR_SHARPEN_ALPHA_SGIS* = 0x80AE.GLenum + GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_EXT* = 0x8DA8.GLenum + GL_MAP1_VERTEX_ATTRIB5_4_NV* = 0x8665.GLenum + GL_MAX_COMBINED_IMAGE_UNITS_AND_FRAGMENT_OUTPUTS* = 0x8F39.GLenum + GL_PIXEL_MAP_I_TO_B_SIZE* = 0x0CB4.GLenum + GL_TRANSFORM_FEEDBACK_BARRIER_BIT_EXT* = 0x00000800.GLbitfield + GL_COLOR_BUFFER_BIT6_QCOM* = 0x00000040.GLbitfield + GL_PROGRAM_TEMPORARIES_ARB* = 0x88A4.GLenum + GL_ELEMENT_ARRAY_BUFFER* = 0x8893.GLenum + GL_ALWAYS_FAST_HINT_PGI* = 0x1A20C.GLenum + GL_INTENSITY_FLOAT16_ATI* = 0x881D.GLenum + GL_ACTIVE_ATTRIBUTE_MAX_LENGTH* = 0x8B8A.GLenum + GL_CON_12_ATI* = 0x894D.GLenum + GL_LINEAR_MIPMAP_NEAREST* = 0x2701.GLint + GL_TEXTURE_COVERAGE_SAMPLES_NV* = 0x9045.GLenum + GL_MAX_PROGRAM_NATIVE_PARAMETERS_ARB* = 0x88AB.GLenum + GL_DEPTH_SCALE* = 0x0D1E.GLenum + GL_SOURCE3_ALPHA_NV* = 0x858B.GLenum + GL_ACTIVE_VERTEX_UNITS_ARB* = 0x86A5.GLenum + GL_SWIZZLE_STR_DR_ATI* = 0x8978.GLenum + GL_RGB16I_EXT* = 0x8D89.GLenum + GL_INT_IMAGE_2D_RECT_EXT* = 0x905A.GLenum + GL_GREEN_BIAS* = 0x0D19.GLenum + GL_FRAMEBUFFER_RENDERABLE_LAYERED* = 0x828A.GLenum + GL_COMPRESSED_RGB8_ETC2* = 0x9274.GLenum + GL_COMPRESSED_RGBA_ARB* = 0x84EE.GLenum + GL_MAX_VERTEX_ATOMIC_COUNTERS* = 0x92D2.GLenum + GL_RGBA32I_EXT* = 0x8D82.GLenum + GL_WAIT_FAILED* = 0x911D.GLenum + GL_FOG_COORDINATE_SOURCE_EXT* = 0x8450.GLenum + GL_SAMPLE_MASK_VALUE_NV* = 0x8E52.GLenum + GL_OP_MUL_EXT* = 0x8786.GLenum + GL_FRAGMENT_TEXTURE* = 0x829F.GLenum + GL_GEOMETRY_PROGRAM_NV* = 0x8C26.GLenum + GL_MATRIX20_ARB* = 0x88D4.GLenum + GL_SECONDARY_COLOR_ARRAY_STRIDE_EXT* = 0x845C.GLenum + GL_UNSIGNED_INT_2_10_10_10_REV_EXT* = 0x8368.GLenum + GL_PHONG_HINT_WIN* = 0x80EB.GLenum + GL_EYE_DISTANCE_TO_LINE_SGIS* = 0x81F2.GLenum + GL_SAMPLES_PASSED* = 0x8914.GLenum + GL_MAX_COLOR_ATTACHMENTS_NV* = 0x8CDF.GLenum + GL_WEIGHT_ARRAY_POINTER_OES* = 0x86AC.GLenum + GL_MAX_DEBUG_GROUP_STACK_DEPTH* = 0x826C.GLenum + GL_TEXTURE_2D_STACK_BINDING_MESAX* = 0x875E.GLenum + GL_VARIANT_VALUE_EXT* = 0x87E4.GLenum + GL_TEXTURE_GEN_R* = 0x0C62.GLenum + GL_COMPRESSED_RG11_EAC* = 0x9272.GLenum + GL_IMAGE_ROTATE_ORIGIN_Y_HP* = 0x815B.GLenum + GL_BLEND_ADVANCED_COHERENT_NV* = 0x9285.GLenum + GL_DEBUG_CALLBACK_FUNCTION* = 0x8244.GLenum + GL_PROXY_TEXTURE_4D_SGIS* = 0x8135.GLenum + GL_OCCLUSION_TEST_RESULT_HP* = 0x8166.GLenum + GL_COLOR_ATTACHMENT13_EXT* = 0x8CED.GLenum + GL_LINE_STRIP_ADJACENCY* = 0x000B.GLenum + GL_DEBUG_CATEGORY_APPLICATION_AMD* = 0x914F.GLenum + GL_CIRCULAR_TANGENT_ARC_TO_NV* = 0xFC.GLenum + GL_MAX_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB* = 0x88B3.GLenum + GL_VERTEX_ATTRIB_ARRAY_STRIDE* = 0x8624.GLenum + GL_COMPRESSED_SRGB_ALPHA_EXT* = 0x8C49.GLenum + GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY* = 0x900F.GLenum + GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY* = 0x906C.GLenum + GL_LIGHT_MODEL_COLOR_CONTROL* = 0x81F8.GLenum + GL_INT_VEC2_ARB* = 0x8B53.GLenum + GL_PARALLEL_ARRAYS_INTEL* = 0x83F4.GLenum + GL_COLOR_ATTACHMENT11_EXT* = 0x8CEB.GLenum + GL_SAMPLE_ALPHA_TO_ONE_SGIS* = 0x809F.GLenum + GL_FUNC_ADD_OES* = 0x8006.GLenum + GL_COMBINER_MAPPING_NV* = 0x8543.GLenum + GL_INT_IMAGE_BUFFER* = 0x905C.GLenum + GL_TEXTURE_SWIZZLE_A* = 0x8E45.GLenum + GL_FRAMEBUFFER_ATTACHMENT_LAYERED_ARB* = 0x8DA7.GLenum + GL_EXPAND_NEGATE_NV* = 0x8539.GLenum + GL_COVERAGE_EDGE_FRAGMENTS_NV* = 0x8ED6.GLenum + GL_PATH_OBJECT_BOUNDING_BOX_NV* = 0x908A.GLenum + GL_MAX_RECTANGLE_TEXTURE_SIZE* = 0x84F8.GLenum + GL_FONT_ASCENDER_BIT_NV* = 0x00200000.GLbitfield + GL_INDEX_SHIFT* = 0x0D12.GLenum + GL_LUMINANCE6_ALPHA2* = 0x8044.GLenum + GL_FLOAT_CLEAR_COLOR_VALUE_NV* = 0x888D.GLenum + GL_V2F* = 0x2A20.GLenum + GL_DRAW_BUFFER12_NV* = 0x8831.GLenum + GL_RIGHT* = 0x0407.GLenum + GL_CON_28_ATI* = 0x895D.GLenum + GL_SAMPLER_CUBE_ARB* = 0x8B60.GLenum + GL_OUTPUT_TEXTURE_COORD27_EXT* = 0x87B8.GLenum + GL_MAX_DEPTH_TEXTURE_SAMPLES* = 0x910F.GLenum + GL_MODULATE* = 0x2100.GLenum + GL_NUM_FILL_STREAMS_NV* = 0x8E29.GLenum + GL_DT_SCALE_NV* = 0x8711.GLenum + GL_ONE_MINUS_SRC_COLOR* = 0x0301.GLenum + GL_OPERAND2_ALPHA* = 0x859A.GLenum + GL_MATRIX15_ARB* = 0x88CF.GLenum + GL_MULTISAMPLE* = 0x809D.GLenum + GL_DEPTH32F_STENCIL8* = 0x8CAD.GLenum + GL_COMPRESSED_RGBA_ASTC_4x4_KHR* = 0x93B0.GLenum + GL_DUAL_ALPHA16_SGIS* = 0x8113.GLenum + GL_COMPRESSED_RGB_FXT1_3DFX* = 0x86B0.GLenum + GL_PROXY_TEXTURE_2D_ARRAY* = 0x8C1B.GLenum + GL_UNIFORM_NAME_LENGTH* = 0x8A39.GLenum + GL_COMPILE_AND_EXECUTE* = 0x1301.GLenum + GL_COMPRESSED_RGBA_PVRTC_4BPPV2_IMG* = 0x9138.GLenum + GL_PIXEL_CUBIC_WEIGHT_EXT* = 0x8333.GLenum + GL_GREEN_MIN_CLAMP_INGR* = 0x8561.GLenum + GL_MAX_TEXTURE_LOD_BIAS* = 0x84FD.GLenum + GL_NORMAL_MAP_NV* = 0x8511.GLenum + GL_PIXEL_UNPACK_BUFFER_BINDING_ARB* = 0x88EF.GLenum + GL_LUMINANCE_ALPHA32F_ARB* = 0x8819.GLenum + GL_LUMINANCE_FLOAT16_APPLE* = 0x881E.GLenum + GL_FACTOR_MIN_AMD* = 0x901C.GLenum + GL_BUFFER_GPU_ADDRESS_NV* = 0x8F1D.GLenum + GL_DEBUG_TYPE_PERFORMANCE_ARB* = 0x8250.GLenum + GL_TEXTURE_RESIDENT* = 0x8067.GLenum + GL_TESS_CONTROL_SHADER_BIT* = 0x00000008.GLbitfield + GL_VERTEX_SHADER* = 0x8B31.GLenum + GL_COLOR_ATTACHMENT15_EXT* = 0x8CEF.GLenum + GL_DRAW_BUFFER2_NV* = 0x8827.GLenum + GL_UNSIGNED_INT* = 0x1405.GLenum + GL_TEXTURE_SHARED_SIZE_EXT* = 0x8C3F.GLenum + GL_LIGHT5* = 0x4005.GLenum + GL_VERTEX_ARRAY_SIZE_EXT* = 0x807A.GLenum + GL_YCRCB_SGIX* = 0x8318.GLenum + GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_TESS_EVALUATION_SHADER* = 0x92C9.GLenum + GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_OES* = 0x8CD1.GLenum + GL_QUADRATIC_CURVE_TO_NV* = 0x0A.GLenum + GL_POINTS* = 0x0000.GLenum + GL_OPERAND1_RGB* = 0x8591.GLenum + GL_POINT_DISTANCE_ATTENUATION_ARB* = 0x8129.GLenum + GL_QUERY_BUFFER_BARRIER_BIT* = 0x00008000.GLbitfield + GL_QUAD_LUMINANCE4_SGIS* = 0x8120.GLenum + GL_GENERATE_MIPMAP_SGIS* = 0x8191.GLenum + GL_FRAMEBUFFER_UNSUPPORTED_EXT* = 0x8CDD.GLenum + GL_PALETTE4_RGB5_A1_OES* = 0x8B94.GLenum + GL_TEXTURE_CROP_RECT_OES* = 0x8B9D.GLenum + GL_COMPUTE_SHADER_BIT* = 0x00000020.GLbitfield + GL_OUTPUT_TEXTURE_COORD2_EXT* = 0x879F.GLenum + GL_PALETTE4_RGBA4_OES* = 0x8B93.GLenum + GL_TEXTURE_CLIPMAP_CENTER_SGIX* = 0x8171.GLenum + GL_BLUE_BITS* = 0x0D54.GLenum + GL_RELATIVE_LARGE_CCW_ARC_TO_NV* = 0x17.GLenum + GL_UNSIGNED_SHORT_5_6_5_EXT* = 0x8363.GLenum + GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS* = 0x8DE1.GLenum + GL_UNCORRELATED_NV* = 0x9282.GLenum + GL_TESS_EVALUATION_SUBROUTINE* = 0x92EA.GLenum + GL_MIN_PROGRAM_TEXTURE_GATHER_OFFSET_ARB* = 0x8E5E.GLenum + GL_CON_11_ATI* = 0x894C.GLenum + GL_ACTIVE_TEXTURE* = 0x84E0.GLenum + GL_ASYNC_TEX_IMAGE_SGIX* = 0x835C.GLenum + GL_COLOR_CLEAR_VALUE* = 0x0C22.GLenum + GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY* = 0x910C.GLenum + GL_TESS_CONTROL_TEXTURE* = 0x829C.GLenum + GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_OES* = 0x851A.GLenum + GL_HISTOGRAM_BLUE_SIZE_EXT* = 0x802A.GLenum + GL_PATCH_DEFAULT_OUTER_LEVEL* = 0x8E74.GLenum + GL_PROGRAM_MATRIX_STACK_DEPTH_EXT* = 0x8E2F.GLenum + GL_RENDERBUFFER_BINDING_ANGLE* = 0x8CA7.GLenum + GL_CONSTANT_ATTENUATION* = 0x1207.GLenum + GL_SHADER_CONSISTENT_NV* = 0x86DD.GLenum + GL_MAX_TESS_EVALUATION_ATOMIC_COUNTERS* = 0x92D4.GLenum + GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD* = 0x9160.GLenum + GL_DETAIL_TEXTURE_FUNC_POINTS_SGIS* = 0x809C.GLenum + GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY_EXT* = 0x9061.GLenum + GL_COUNT_DOWN_NV* = 0x9089.GLenum + GL_MATRIX12_ARB* = 0x88CC.GLenum + GL_MAX_VERTEX_SHADER_INVARIANTS_EXT* = 0x87C7.GLenum + GL_REPLICATE_BORDER_HP* = 0x8153.GLenum + GL_MODELVIEW9_ARB* = 0x8729.GLenum + GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT* = 0x8D6A.GLenum + GL_PROGRAM_PARAMETERS_ARB* = 0x88A8.GLenum + GL_LIST_BIT* = 0x00020000.GLbitfield + GL_MAX_GEOMETRY_ATOMIC_COUNTERS* = 0x92D5.GLenum + GL_CONSTANT_COLOR1_NV* = 0x852B.GLenum + GL_AVERAGE_EXT* = 0x8335.GLenum + GL_SINGLE_COLOR_EXT* = 0x81F9.GLenum + GL_VERTEX_ARRAY* = 0x8074.GLenum + GL_COLOR_INDEX1_EXT* = 0x80E2.GLenum + GL_COMPUTE_PROGRAM_NV* = 0x90FB.GLenum + GL_LINES_ADJACENCY* = 0x000A.GLenum + GL_OP_ROUND_EXT* = 0x8790.GLenum + GL_TRANSFORM_FEEDBACK_BUFFER_STRIDE* = 0x934C.GLenum + GL_MAX_DEEP_3D_TEXTURE_DEPTH_NV* = 0x90D1.GLenum + GL_REG_11_ATI* = 0x892C.GLenum + GL_SAMPLES_EXT* = 0x80A9.GLenum + GL_FUNC_REVERSE_SUBTRACT* = 0x800B.GLenum + GL_POINT_SPRITE_COORD_ORIGIN* = 0x8CA0.GLenum + GL_REG_27_ATI* = 0x893C.GLenum + GL_TEXTURE_VIEW_MIN_LEVEL* = 0x82DB.GLenum + GL_NICEST* = 0x1102.GLenum + GL_CLIP_PLANE4_IMG* = 0x3004.GLenum + GL_ARRAY_BUFFER_BINDING* = 0x8894.GLenum + GL_422_AVERAGE_EXT* = 0x80CE.GLenum + GL_RENDERER* = 0x1F01.GLenum + GL_OVERLAY_NV* = 0x9296.GLenum + GL_TEXTURE_SAMPLES_IMG* = 0x9136.GLenum + GL_DEBUG_SOURCE_SHADER_COMPILER_KHR* = 0x8248.GLenum + GL_EYE_DISTANCE_TO_POINT_SGIS* = 0x81F0.GLenum + GL_MAX_PROGRAM_GENERIC_ATTRIBS_NV* = 0x8DA5.GLenum + GL_FILTER4_SGIS* = 0x8146.GLenum + GL_LIGHT_MODEL_LOCAL_VIEWER* = 0x0B51.GLenum + GL_TRIANGLE_MESH_SUN* = 0x8615.GLenum + GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW_ARB* = 0x900D.GLenum + GL_DEPTH_COMPONENTS* = 0x8284.GLenum + GL_NUM_GENERAL_COMBINERS_NV* = 0x854E.GLenum + GL_CLIENT_ACTIVE_TEXTURE_ARB* = 0x84E1.GLenum + GL_FRAGMENT_DEPTH* = 0x8452.GLenum + GL_SEPARATE_ATTRIBS* = 0x8C8D.GLenum + GL_HALF_FLOAT_OES* = 0x8D61.GLenum + GL_PROXY_TEXTURE_2D* = 0x8064.GLenum + GL_VARIANT_ARRAY_TYPE_EXT* = 0x87E7.GLenum + GL_DRAW_BUFFER11_ATI* = 0x8830.GLenum + GL_MATRIX_INDEX_ARRAY_POINTER_OES* = 0x8849.GLenum + GL_CURRENT_INDEX* = 0x0B01.GLenum + GL_UNSIGNED_INT_24_8_MESA* = 0x8751.GLenum + GL_PROGRAM_SEPARABLE* = 0x8258.GLenum + GL_TEXTURE8_ARB* = 0x84C8.GLenum + GL_OPERAND0_ALPHA_EXT* = 0x8598.GLenum + GL_PER_STAGE_CONSTANTS_NV* = 0x8535.GLenum + GL_LINE_LOOP* = 0x0002.GLenum + GL_DRAW_PIXEL_TOKEN* = 0x0705.GLenum + GL_DRAW_BUFFER3* = 0x8828.GLenum + GL_GEOMETRY_DEFORMATION_SGIX* = 0x8194.GLenum + GL_MAX_CUBE_MAP_TEXTURE_SIZE_EXT* = 0x851C.GLenum + GL_GLYPH_VERTICAL_BEARING_X_BIT_NV* = 0x20.GLbitfield + GL_TEXTURE30* = 0x84DE.GLenum + GL_4PASS_1_EXT* = 0x80A5.GLenum + GL_RGB16F_EXT* = 0x881B.GLenum + GL_2PASS_0_SGIS* = 0x80A2.GLenum + GL_CON_27_ATI* = 0x895C.GLenum + GL_SAMPLE_ALPHA_TO_ONE* = 0x809F.GLenum + GL_POLYGON_SMOOTH_HINT* = 0x0C53.GLenum + GL_COLOR_ATTACHMENT_EXT* = 0x90F0.GLenum + GL_PATCH_DEFAULT_INNER_LEVEL* = 0x8E73.GLenum + GL_TEXTURE_MAX_CLAMP_T_SGIX* = 0x836A.GLenum + GL_WEIGHT_ARRAY_BUFFER_BINDING_OES* = 0x889E.GLenum + GL_TEXTURE1* = 0x84C1.GLenum + GL_LINES* = 0x0001.GLenum + GL_PIXEL_TILE_GRID_DEPTH_SGIX* = 0x8144.GLenum + GL_TEXTURE2* = 0x84C2.GLenum + GL_IMAGE_CUBE_MAP_ARRAY_EXT* = 0x9054.GLenum + GL_DRAW_BUFFER4* = 0x8829.GLenum + GL_DRAW_BUFFER_EXT* = 0x0C01.GLenum + GL_STENCIL_INDEX1* = 0x8D46.GLenum + GL_DEPTH_COMPONENT32F_NV* = 0x8DAB.GLenum + GL_VERTEX_ATTRIB_ARRAY_POINTER* = 0x8645.GLenum + GL_DOUBLE_MAT4x2* = 0x8F4D.GLenum + GL_MOVE_TO_NV* = 0x02.GLenum + GL_OP_RECIP_SQRT_EXT* = 0x8795.GLenum + GL_SAMPLER_1D_ARRAY* = 0x8DC0.GLenum + GL_MIN_FRAGMENT_INTERPOLATION_OFFSET* = 0x8E5B.GLenum + GL_TEXTURE_DEPTH_EXT* = 0x8071.GLenum + GL_STENCIL_INDEX8* = 0x8D48.GLenum + GL_MAX_PROGRAM_TEX_INSTRUCTIONS_ARB* = 0x880C.GLenum + GL_INTERNALFORMAT_DEPTH_SIZE* = 0x8275.GLenum + GL_STATE_RESTORE* = 0x8BDC.GLenum + GL_SMALL_CW_ARC_TO_NV* = 0x14.GLenum + GL_LUMINANCE16* = 0x8042.GLenum + GL_VERTEX_ATTRIB_ARRAY1_NV* = 0x8651.GLenum + GL_TEXTURE_MAX_CLAMP_R_SGIX* = 0x836B.GLenum + GL_LUMINANCE_FLOAT16_ATI* = 0x881E.GLenum + GL_MAX_TEXTURE_UNITS* = 0x84E2.GLenum + GL_DRAW_BUFFER4_ARB* = 0x8829.GLenum + GL_DRAW_BUFFER12* = 0x8831.GLenum + GL_R8UI* = 0x8232.GLenum + GL_STENCIL_REF* = 0x0B97.GLenum + GL_VARIANT_EXT* = 0x87C1.GLenum + GL_VERTEX_ATTRIB_MAP2_DOMAIN_APPLE* = 0x8A09.GLenum + GL_QUERY_OBJECT_AMD* = 0x9153.GLenum + GL_PLUS_NV* = 0x9291.GLenum + GL_UNPACK_SWAP_BYTES* = 0x0CF0.GLenum + GL_MAX_UNIFORM_LOCATIONS* = 0x826E.GLenum + GL_GUILTY_CONTEXT_RESET_EXT* = 0x8253.GLenum + GL_DOT3_RGBA_IMG* = 0x86AF.GLenum + GL_X_EXT* = 0x87D5.GLenum + GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY_ARB* = 0x900F.GLenum + GL_TEXTURE_COMPARE_FAIL_VALUE_ARB* = 0x80BF.GLenum + GL_ETC1_RGB8_OES* = 0x8D64.GLenum + GL_LUMINANCE_ALPHA_INTEGER_EXT* = 0x8D9D.GLenum + GL_MINMAX_SINK* = 0x8030.GLenum + GL_RG32F* = 0x8230.GLenum + GL_PROXY_TEXTURE_2D_MULTISAMPLE* = 0x9101.GLenum + GL_RGBA_UNSIGNED_DOT_PRODUCT_MAPPING_NV* = 0x86D9.GLenum + GL_R16* = 0x822A.GLenum + GL_BOUNDING_BOX_NV* = 0x908D.GLenum + GL_INVALID_ENUM* = 0x0500.GLenum + GL_MOVE_TO_RESETS_NV* = 0x90B5.GLenum + GL_SYNC_GPU_COMMANDS_COMPLETE_APPLE* = 0x9117.GLenum + GL_MAX_RECTANGLE_TEXTURE_SIZE_ARB* = 0x84F8.GLenum + GL_UNSIGNED_INT_10F_11F_11F_REV_EXT* = 0x8C3B.GLenum + GL_VERTEX_PRECLIP_HINT_SGIX* = 0x83EF.GLenum + GL_CLIENT_VERTEX_ARRAY_BIT* = 0x00000002.GLbitfield + GL_MAT_COLOR_INDEXES_BIT_PGI* = 0x01000000.GLbitfield + GL_PERFORMANCE_MONITOR_AMD* = 0x9152.GLenum + GL_QUAD_STRIP* = 0x0008.GLenum + GL_MAX_TEXTURE_COORDS_NV* = 0x8871.GLenum + GL_TESS_EVALUATION_SUBROUTINE_UNIFORM* = 0x92F0.GLenum + GL_DRAW_BUFFER1_EXT* = 0x8826.GLenum + GL_TEXTURE18* = 0x84D2.GLenum + GL_COLOR_ATTACHMENT5_NV* = 0x8CE5.GLenum + GL_MAX_COMPUTE_WORK_GROUP_SIZE* = 0x91BF.GLenum + GL_T2F_C4UB_V3F* = 0x2A29.GLenum + GL_MAP1_GRID_DOMAIN* = 0x0DD0.GLenum + GL_DEBUG_TYPE_PUSH_GROUP_KHR* = 0x8269.GLenum + GL_STATIC_READ* = 0x88E5.GLenum + GL_MAX_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB* = 0x880E.GLenum + GL_DOUBLE_EXT* = 0x140A.GLenum + GL_MAX_FRAGMENT_UNIFORM_VECTORS* = 0x8DFD.GLenum + GL_R32F_EXT* = 0x822E.GLenum + GL_MAX_RENDERBUFFER_SIZE_EXT* = 0x84E8.GLenum + GL_COMPRESSED_TEXTURE_FORMATS* = 0x86A3.GLenum + GL_MAX_EXT* = 0x8008.GLenum + GL_VERTEX_ATTRIB_ARRAY_ENABLED_ARB* = 0x8622.GLenum + GL_INTERPOLATE* = 0x8575.GLenum + GL_QUERY_RESULT_NO_WAIT_AMD* = 0x9194.GLenum + GL_TEXTURE_CUBE_MAP_NEGATIVE_X_OES* = 0x8516.GLenum + GL_LUMINANCE16_ALPHA16_SNORM* = 0x901A.GLenum + GL_SRC_ALPHA_SATURATE* = 0x0308.GLenum + GL_DRAW_INDIRECT_BUFFER_BINDING* = 0x8F43.GLenum + GL_T2F_IUI_N3F_V3F_EXT* = 0x81B4.GLenum + GL_MAX_FRAGMENT_UNIFORM_COMPONENTS_ARB* = 0x8B49.GLenum + GL_MAX_ASYNC_READ_PIXELS_SGIX* = 0x8361.GLenum + GL_VERTEX_ARRAY_RANGE_APPLE* = 0x851D.GLenum + GL_SAMPLER_2D_SHADOW_ARB* = 0x8B62.GLenum + GL_ETC1_SRGB8_NV* = 0x88EE.GLenum + GL_COLORBURN_NV* = 0x929A.GLenum + GL_SAMPLER_2D_ARRAY_SHADOW_EXT* = 0x8DC4.GLenum + GL_ALL_BARRIER_BITS* = 0xFFFFFFFF.GLbitfield + GL_TRIANGLE_STRIP_ADJACENCY_EXT* = 0x000D.GLenum + GL_MAX_TEXTURE_BUFFER_SIZE* = 0x8C2B.GLenum + GL_ALIASED_POINT_SIZE_RANGE* = 0x846D.GLenum + GL_STENCIL_BACK_VALUE_MASK* = 0x8CA4.GLenum + GL_CMYK_EXT* = 0x800C.GLenum + GL_OPERAND1_ALPHA_EXT* = 0x8599.GLenum + GL_TEXTURE_SHADOW* = 0x82A1.GLenum + GL_LINEAR_CLIPMAP_LINEAR_SGIX* = 0x8170.GLenum + GL_MIPMAP* = 0x8293.GLenum + GL_LINE_SMOOTH_HINT* = 0x0C52.GLenum + GL_DEPTH_STENCIL_TEXTURE_MODE* = 0x90EA.GLenum + GL_BUFFER_ACCESS_OES* = 0x88BB.GLenum + GL_PROXY_TEXTURE_1D_ARRAY_EXT* = 0x8C19.GLenum + GL_OBJECT_LINEAR* = 0x2401.GLenum + GL_MAP1_TEXTURE_COORD_3* = 0x0D95.GLenum + GL_TEXTURE_RENDERBUFFER_NV* = 0x8E55.GLenum + GL_FRAMEBUFFER_RENDERABLE* = 0x8289.GLenum + GL_DOT3_RGB_EXT* = 0x8740.GLenum + GL_QUAD_LUMINANCE8_SGIS* = 0x8121.GLenum + GL_UNIFORM_BLOCK_INDEX* = 0x8A3A.GLenum + GL_DS_SCALE_NV* = 0x8710.GLenum + GL_TYPE* = 0x92FA.GLenum + GL_MATRIX_EXT* = 0x87C0.GLenum + GL_VERTEX_STREAM4_ATI* = 0x8770.GLenum + GL_TOP_LEVEL_ARRAY_STRIDE* = 0x930D.GLenum + GL_INT_SAMPLER_2D_EXT* = 0x8DCA.GLenum + GL_PATH_FORMAT_PS_NV* = 0x9071.GLenum + GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR* = 0x93D2.GLenum + GL_MAX_TEXTURE_COORDS* = 0x8871.GLenum + GL_MAX_FRAGMENT_INTERPOLATION_OFFSET* = 0x8E5C.GLenum + GL_REG_17_ATI* = 0x8932.GLenum + GL_WAIT_FAILED_APPLE* = 0x911D.GLenum + GL_TEXTURE_BINDING_3D* = 0x806A.GLenum + GL_TEXTURE_VIEW* = 0x82B5.GLenum + GL_DOT3_RGBA_ARB* = 0x86AF.GLenum + GL_MAX_VARYING_FLOATS_ARB* = 0x8B4B.GLenum + GL_UNIFORM_IS_ROW_MAJOR* = 0x8A3E.GLenum + GL_FRAGMENT_SHADER_BIT* = 0x00000002.GLbitfield + GL_MATRIX_INDEX_ARRAY_ARB* = 0x8844.GLenum + GL_PIXEL_PACK_BUFFER_BINDING_EXT* = 0x88ED.GLenum + GL_MATRIX_PALETTE_OES* = 0x8840.GLenum + GL_INTENSITY_SNORM* = 0x9013.GLenum + GL_COLOR_BUFFER_BIT0_QCOM* = 0x00000001.GLbitfield + GL_BITMAP* = 0x1A00.GLenum + GL_CURRENT_MATRIX_NV* = 0x8641.GLenum + GL_QUERY_BUFFER_AMD* = 0x9192.GLenum + GL_EDGE_FLAG_ARRAY_BUFFER_BINDING* = 0x889B.GLenum + GL_4PASS_3_EXT* = 0x80A7.GLenum + GL_TEXTURE_4DSIZE_SGIS* = 0x8136.GLenum + GL_PATH_COORD_COUNT_NV* = 0x909E.GLenum + GL_SLUMINANCE* = 0x8C46.GLenum + GL_POINT_SMOOTH_HINT* = 0x0C51.GLenum + GL_ADJACENT_PAIRS_NV* = 0x90AE.GLenum + GL_BUFFER_BINDING* = 0x9302.GLenum + GL_ARRAY_OBJECT_BUFFER_ATI* = 0x8766.GLenum + GL_PATH_INITIAL_DASH_CAP_NV* = 0x907C.GLenum + GL_RGBA4* = 0x8056.GLenum + GL_PACK_LSB_FIRST* = 0x0D01.GLenum + GL_IMAGE_BINDING_NAME_EXT* = 0x8F3A.GLenum + GL_UNSIGNED_INT_SAMPLER_2D_EXT* = 0x8DD2.GLenum + GL_RGBA12_EXT* = 0x805A.GLenum + GL_COMBINER0_NV* = 0x8550.GLenum + GL_COLOR_BUFFER_BIT4_QCOM* = 0x00000010.GLbitfield + GL_TIME_ELAPSED* = 0x88BF.GLenum + GL_TRANSFORM_FEEDBACK_BUFFER_START* = 0x8C84.GLenum + GL_COMPRESSED_RGBA_ASTC_5x5_KHR* = 0x93B2.GLenum + GL_MAX_SPARSE_3D_TEXTURE_SIZE_AMD* = 0x9199.GLenum + GL_RENDERBUFFER_HEIGHT_EXT* = 0x8D43.GLenum + GL_QUARTER_BIT_ATI* = 0x00000010.GLbitfield + GL_TEXTURE_COMPRESSION_HINT_ARB* = 0x84EF.GLenum + GL_DRAW_BUFFER13* = 0x8832.GLenum + GL_CURRENT_MATRIX_STACK_DEPTH_ARB* = 0x8640.GLenum + GL_DEPENDENT_HILO_TEXTURE_2D_NV* = 0x8858.GLenum + GL_DST_NV* = 0x9287.GLenum + GL_DEBUG_OBJECT_MESA* = 0x8759.GLenum + GL_NUM_INSTRUCTIONS_TOTAL_ATI* = 0x8972.GLenum + GL_FLAT* = 0x1D00.GLenum + GL_EVAL_VERTEX_ATTRIB8_NV* = 0x86CE.GLenum + GL_VERTEX_PROGRAM_CALLBACK_FUNC_MESA* = 0x8BB6.GLenum + GL_TEXTURE_COORD_ARRAY_EXT* = 0x8078.GLenum + GL_LOCATION_INDEX* = 0x930F.GLenum + GL_SLIM10U_SGIX* = 0x831E.GLenum + GL_PHONG_WIN* = 0x80EA.GLenum + GL_EVAL_VERTEX_ATTRIB1_NV* = 0x86C7.GLenum + GL_SMOOTH_LINE_WIDTH_RANGE* = 0x0B22.GLenum + GL_SAMPLER_RENDERBUFFER_NV* = 0x8E56.GLenum + GL_UNPACK_LSB_FIRST* = 0x0CF1.GLenum + GL_SELECTION_BUFFER_POINTER* = 0x0DF3.GLenum + GL_PIXEL_SUBSAMPLE_4444_SGIX* = 0x85A2.GLenum + GL_COMPRESSED_R11_EAC* = 0x9270.GLenum + GL_MAX_CLIP_PLANES* = 0x0D32.GLenum + GL_POST_CONVOLUTION_GREEN_BIAS* = 0x8021.GLenum + GL_COLOR_EXT* = 0x1800.GLenum + GL_VENDOR* = 0x1F00.GLenum + GL_MAP1_VERTEX_ATTRIB8_4_NV* = 0x8668.GLenum + GL_TEXTURE_ALPHA_TYPE* = 0x8C13.GLenum + GL_CURRENT_VERTEX_ATTRIB_ARB* = 0x8626.GLenum + GL_COLOR_BUFFER_BIT2_QCOM* = 0x00000004.GLbitfield + GL_VERTEX_ATTRIB_ARRAY15_NV* = 0x865F.GLenum + GL_OFFSET_PROJECTIVE_TEXTURE_2D_NV* = 0x8850.GLenum + GL_DRAW_BUFFER5_ARB* = 0x882A.GLenum + GL_SAMPLES_PASSED_ARB* = 0x8914.GLenum + GL_PRIMITIVE_RESTART_NV* = 0x8558.GLenum + GL_FRAGMENT_LIGHT3_SGIX* = 0x840F.GLenum + GL_COLOR_INDEX16_EXT* = 0x80E7.GLenum + GL_RGBA8_OES* = 0x8058.GLenum + GL_PACK_CMYK_HINT_EXT* = 0x800E.GLenum + GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE* = 0x8214.GLenum + GL_MODELVIEW0_EXT* = 0x1700.GLenum + GL_RETAINED_APPLE* = 0x8A1B.GLenum + GL_DRAW_PIXELS_APPLE* = 0x8A0A.GLenum + GL_POINT_BIT* = 0x00000002.GLbitfield + GL_PIXEL_MAP_B_TO_B_SIZE* = 0x0CB8.GLenum + GL_RELATIVE_SMALL_CCW_ARC_TO_NV* = 0x13.GLenum + GL_VERTEX_ATTRIB_ARRAY_STRIDE_ARB* = 0x8624.GLenum + GL_DOT_PRODUCT_AFFINE_DEPTH_REPLACE_NV* = 0x885D.GLenum + GL_CON_2_ATI* = 0x8943.GLenum + GL_SAMPLER_2D_ARRAY* = 0x8DC1.GLenum + GL_LINE_STIPPLE_PATTERN* = 0x0B25.GLenum + GL_IMPLEMENTATION_COLOR_READ_FORMAT* = 0x8B9B.GLenum + GL_TRANSPOSE_AFFINE_2D_NV* = 0x9096.GLenum + GL_COLOR_ATTACHMENT7* = 0x8CE7.GLenum + GL_COLOR_ATTACHMENT14* = 0x8CEE.GLenum + GL_SHADER* = 0x82E1.GLenum + GL_SKIP_MISSING_GLYPH_NV* = 0x90A9.GLenum + GL_VERTEX_ARRAY_TYPE* = 0x807B.GLenum + GL_OP_POWER_EXT* = 0x8793.GLenum + GL_MAX_BINDABLE_UNIFORM_SIZE_EXT* = 0x8DED.GLenum + GL_SRGB8* = 0x8C41.GLenum + GL_INTERNALFORMAT_ALPHA_SIZE* = 0x8274.GLenum + GL_IMAGE_2D_MULTISAMPLE* = 0x9055.GLenum + GL_VIDEO_CAPTURE_FRAME_HEIGHT_NV* = 0x9039.GLenum + GL_NEVER* = 0x0200.GLenum + GL_MAP2_TEXTURE_COORD_2* = 0x0DB4.GLenum + GL_PROGRAM_RESULT_COMPONENTS_NV* = 0x8907.GLenum + GL_SHADER_STORAGE_BARRIER_BIT* = 0x00002000.GLbitfield + GL_SLIM8U_SGIX* = 0x831D.GLenum + GL_DRAW_BUFFER7_ATI* = 0x882C.GLenum + GL_CLAMP_TO_EDGE* = 0x812F.GLint + GL_LUMINANCE32I_EXT* = 0x8D86.GLenum + GL_NORMAL_ARRAY_POINTER* = 0x808F.GLenum + GL_ALPHA_TEST_REF_QCOM* = 0x0BC2.GLenum + GL_MATRIX7_NV* = 0x8637.GLenum + GL_REFERENCED_BY_FRAGMENT_SHADER* = 0x930A.GLenum + GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG* = 0x8C02.GLenum + GL_DEBUG_TYPE_MARKER* = 0x8268.GLenum + GL_DEBUG_OUTPUT_SYNCHRONOUS_KHR* = 0x8242.GLenum + GL_CON_26_ATI* = 0x895B.GLenum + GL_COMBINER7_NV* = 0x8557.GLenum + GL_MAP2_TANGENT_EXT* = 0x8445.GLenum + GL_COMPRESSED_RGBA_ASTC_10x6_KHR* = 0x93B9.GLenum + GL_RG8* = 0x822B.GLenum + GL_INT_SAMPLER_1D_ARRAY_EXT* = 0x8DCE.GLenum + GL_POINT_SPRITE_R_MODE_NV* = 0x8863.GLenum + GL_ATOMIC_COUNTER_BUFFER_BINDING* = 0x92C1.GLenum + GL_INTENSITY16F_ARB* = 0x881D.GLenum + GL_DEFORMATIONS_MASK_SGIX* = 0x8196.GLenum + GL_PATH_TERMINAL_END_CAP_NV* = 0x9078.GLenum + GL_VERTEX_BINDING_DIVISOR* = 0x82D6.GLenum + GL_WIDE_LINE_HINT_PGI* = 0x1A222.GLenum + GL_LIGHTING* = 0x0B50.GLenum + GL_CURRENT_BIT* = 0x00000001.GLbitfield + GL_LOSE_CONTEXT_ON_RESET_ARB* = 0x8252.GLenum + GL_COLOR_ATTACHMENT15* = 0x8CEF.GLenum + GL_REGISTER_COMBINERS_NV* = 0x8522.GLenum + GL_UNSIGNED_INT64_VEC2_NV* = 0x8FF5.GLenum + GL_TEXTURE_CLIPMAP_DEPTH_SGIX* = 0x8176.GLenum + GL_HISTOGRAM_WIDTH* = 0x8026.GLenum + GL_RENDERBUFFER_ALPHA_SIZE* = 0x8D53.GLenum + GL_POST_CONVOLUTION_BLUE_BIAS_EXT* = 0x8022.GLenum + GL_SCALED_RESOLVE_FASTEST_EXT* = 0x90BA.GLenum + GL_DRAW_BUFFER15* = 0x8834.GLenum + GL_LUMINANCE4_ALPHA4* = 0x8043.GLenum + GL_SWIZZLE_STRQ_DQ_ATI* = 0x897B.GLenum + GL_OP_MADD_EXT* = 0x8788.GLenum + GL_MAX_ATTRIB_STACK_DEPTH* = 0x0D35.GLenum + GL_DEBUG_GROUP_STACK_DEPTH_KHR* = 0x826D.GLenum + GL_ACTIVE_VARYINGS_NV* = 0x8C81.GLenum + GL_DEBUG_SEVERITY_HIGH* = 0x9146.GLenum + GL_SRGB8_EXT* = 0x8C41.GLenum + GL_STENCIL_WRITEMASK* = 0x0B98.GLenum + GL_REG_14_ATI* = 0x892F.GLenum + GL_PROGRAM_BINARY_ANGLE* = 0x93A6.GLenum + GL_RENDERBUFFER_DEPTH_SIZE_EXT* = 0x8D54.GLenum + GL_ALPHA_BIAS* = 0x0D1D.GLenum + GL_STATIC_ATI* = 0x8760.GLenum + GL_MATRIX_INDEX_ARRAY_BUFFER_BINDING_OES* = 0x8B9E.GLenum + GL_SOFTLIGHT_NV* = 0x929C.GLenum + GL_INDEX_ARRAY_COUNT_EXT* = 0x8087.GLenum + GL_RENDERBUFFER_BLUE_SIZE_EXT* = 0x8D52.GLenum + GL_SHARED_TEXTURE_PALETTE_EXT* = 0x81FB.GLenum + GL_VERTEX_SHADER_OPTIMIZED_EXT* = 0x87D4.GLenum + GL_MAX_SAMPLE_MASK_WORDS_NV* = 0x8E59.GLenum + GL_MAX_MATRIX_PALETTE_STACK_DEPTH_ARB* = 0x8841.GLenum + GL_MATRIX30_ARB* = 0x88DE.GLenum + GL_NORMAL_ARRAY_POINTER_EXT* = 0x808F.GLenum + GL_PIXEL_MAP_A_TO_A* = 0x0C79.GLenum + GL_MATRIX18_ARB* = 0x88D2.GLenum + GL_UNPACK_SKIP_ROWS_EXT* = 0x0CF3.GLenum + GL_INVARIANT_DATATYPE_EXT* = 0x87EB.GLenum + GL_INT_IMAGE_1D_EXT* = 0x9057.GLenum + GL_OUTPUT_TEXTURE_COORD24_EXT* = 0x87B5.GLenum + GL_MAP_WRITE_BIT_EXT* = 0x0002.GLbitfield + GL_MODELVIEW28_ARB* = 0x873C.GLenum + GL_MAX_VARYING_COMPONENTS_EXT* = 0x8B4B.GLenum + GL_OUTPUT_TEXTURE_COORD4_EXT* = 0x87A1.GLenum + GL_UNSIGNED_INT_VEC2_EXT* = 0x8DC6.GLenum + GL_READ_ONLY* = 0x88B8.GLenum + GL_SECONDARY_COLOR_ARRAY_LIST_STRIDE_IBM* = 103087.GLenum + GL_UNSIGNED_INT64_NV* = 0x140F.GLenum + GL_REPLACEMENT_CODE_ARRAY_STRIDE_SUN* = 0x85C2.GLenum + GL_DEPTH_BUFFER_BIT0_QCOM* = 0x00000100.GLbitfield + GL_VERTEX_ATTRIB_MAP2_SIZE_APPLE* = 0x8A06.GLenum + GL_POST_CONVOLUTION_ALPHA_SCALE* = 0x801F.GLenum + GL_TEXTURE_COLOR_SAMPLES_NV* = 0x9046.GLenum + GL_DEBUG_SEVERITY_HIGH_ARB* = 0x9146.GLenum + GL_MAP_WRITE_BIT* = 0x0002.GLbitfield + GL_SRC1_RGB* = 0x8581.GLenum + GL_LIGHT0* = 0x4000.GLenum + GL_READ_PIXELS_FORMAT* = 0x828D.GLenum + GL_COMBINE_RGB_EXT* = 0x8571.GLenum + GL_MATRIX2_NV* = 0x8632.GLenum + GL_INT16_VEC4_NV* = 0x8FE7.GLenum + GL_INT_SAMPLER_CUBE* = 0x8DCC.GLenum + GL_LUMINANCE_ALPHA8I_EXT* = 0x8D93.GLenum + GL_TRIANGLE_STRIP_ADJACENCY* = 0x000D.GLenum + GL_MAX_TEXTURE_BUFFER_SIZE_EXT* = 0x8C2B.GLenum + GL_COLOR_TABLE_BIAS* = 0x80D7.GLenum + GL_MAX_GEOMETRY_INPUT_COMPONENTS* = 0x9123.GLenum + GL_TEXTURE_RANGE_POINTER_APPLE* = 0x85B8.GLenum + GL_PIXEL_SUBSAMPLE_2424_SGIX* = 0x85A3.GLenum + GL_RESAMPLE_REPLICATE_OML* = 0x8986.GLenum + GL_ALL_STATIC_DATA_IBM* = 103060.GLenum + GL_DEBUG_CATEGORY_PERFORMANCE_AMD* = 0x914D.GLenum + GL_ALPHA_TEST_QCOM* = 0x0BC0.GLenum + GL_PREVIOUS_TEXTURE_INPUT_NV* = 0x86E4.GLenum + GL_SIGNED_RGBA_NV* = 0x86FB.GLenum + GL_GLOBAL_ALPHA_SUN* = 0x81D9.GLenum + GL_RGB_FLOAT16_APPLE* = 0x881B.GLenum + GL_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB* = 0x8808.GLenum + GL_UTF8_NV* = 0x909A.GLenum + GL_ALLOW_DRAW_OBJ_HINT_PGI* = 0x1A20E.GLenum + GL_INT_IMAGE_3D* = 0x9059.GLenum + GL_PACK_ROW_LENGTH* = 0x0D02.GLenum + GL_MAX_TEXTURE_LOD_BIAS_EXT* = 0x84FD.GLenum + GL_SCALED_RESOLVE_NICEST_EXT* = 0x90BB.GLenum + GL_422_EXT* = 0x80CC.GLenum + GL_SAMPLER_1D_ARRAY_SHADOW_EXT* = 0x8DC3.GLenum + GL_PIXEL_TRANSFORM_2D_STACK_DEPTH_EXT* = 0x8336.GLenum + GL_COMPRESSED_RED* = 0x8225.GLenum + GL_MAX_RATIONAL_EVAL_ORDER_NV* = 0x86D7.GLenum + GL_MAX_COMBINED_IMAGE_UNIFORMS* = 0x90CF.GLenum + GL_GLYPH_HORIZONTAL_BEARING_ADVANCE_BIT_NV* = 0x10.GLbitfield + GL_TEXTURE_BINDING_1D_ARRAY* = 0x8C1C.GLenum + GL_FRAMEBUFFER_COMPLETE* = 0x8CD5.GLenum + GL_RG8I* = 0x8237.GLenum + GL_COLOR_ATTACHMENT2_NV* = 0x8CE2.GLenum + GL_INT64_VEC4_NV* = 0x8FEB.GLenum + GL_OP_SET_GE_EXT* = 0x878C.GLenum + GL_READ_WRITE* = 0x88BA.GLenum + GL_OPERAND1_RGB_EXT* = 0x8591.GLenum + GL_SHADER_STORAGE_BLOCK* = 0x92E6.GLenum + GL_TEXTURE_UPDATE_BARRIER_BIT* = 0x00000100.GLbitfield + GL_MAX_FRAGMENT_ATOMIC_COUNTERS* = 0x92D6.GLenum + GL_SHADER_INCLUDE_ARB* = 0x8DAE.GLenum + GL_UNSIGNED_SHORT_1_5_5_5_REV* = 0x8366.GLenum + GL_PROGRAM_PIPELINE* = 0x82E4.GLenum + GL_MAP1_TEXTURE_COORD_2* = 0x0D94.GLenum + GL_FOG_COORDINATE_ARRAY_STRIDE_EXT* = 0x8455.GLenum + GL_WEIGHT_ARRAY_SIZE_OES* = 0x86AB.GLenum + GL_R11F_G11F_B10F* = 0x8C3A.GLenum + GL_WRITE_PIXEL_DATA_RANGE_NV* = 0x8878.GLenum + GL_UNSIGNED_SHORT_8_8_REV_APPLE* = 0x85BB.GLenum + GL_CND_ATI* = 0x896A.GLenum + GL_IMAGE_2D_MULTISAMPLE_ARRAY* = 0x9056.GLenum + GL_MAX_TEXTURE_IMAGE_UNITS_NV* = 0x8872.GLenum + GL_COMPRESSED_SIGNED_RG11_EAC_OES* = 0x9273.GLenum + GL_DOT_PRODUCT_TEXTURE_3D_NV* = 0x86EF.GLenum + GL_IMAGE_TRANSLATE_Y_HP* = 0x8158.GLenum + GL_NORMAL_ARRAY_TYPE_EXT* = 0x807E.GLenum + GL_PIXEL_COUNT_NV* = 0x8866.GLenum + GL_INT_IMAGE_3D_EXT* = 0x9059.GLenum + GL_TEXTURE_TYPE_QCOM* = 0x8BD7.GLenum + GL_COMBINE_ALPHA_EXT* = 0x8572.GLenum + GL_POINT_TOKEN* = 0x0701.GLenum + GL_QUAD_ALPHA4_SGIS* = 0x811E.GLenum + GL_SIGNED_HILO8_NV* = 0x885F.GLenum + GL_MULTISAMPLE_ARB* = 0x809D.GLenum + GL_TEXTURE25* = 0x84D9.GLenum + GL_CURRENT_VERTEX_WEIGHT_EXT* = 0x850B.GLenum + GL_BLEND_DST_ALPHA_OES* = 0x80CA.GLenum + GL_UNSIGNED_SHORT_8_8_REV_MESA* = 0x85BB.GLenum + GL_CLAMP_TO_EDGE_SGIS* = 0x812F.GLint + GL_PATH_STENCIL_REF_NV* = 0x90B8.GLenum + GL_DEBUG_OUTPUT* = 0x92E0.GLenum + GL_OBJECT_TYPE_APPLE* = 0x9112.GLenum + GL_TEXTURE_COMPARE_MODE_ARB* = 0x884C.GLenum + GL_CONSTANT* = 0x8576.GLenum + GL_RGB5_A1_OES* = 0x8057.GLenum + GL_INT16_VEC2_NV* = 0x8FE5.GLenum + GL_CONVOLUTION_BORDER_MODE_EXT* = 0x8013.GLenum + GL_CONTEXT_FLAGS* = 0x821E.GLenum + GL_MAX_PROGRAM_SUBROUTINE_NUM_NV* = 0x8F45.GLenum + GL_SPRITE_SGIX* = 0x8148.GLenum + GL_CURRENT_QUERY* = 0x8865.GLenum + GL_STENCIL_OP_VALUE_AMD* = 0x874C.GLenum + GL_UNIFORM* = 0x92E1.GLenum + GL_TEXTURE_BINDING_RECTANGLE* = 0x84F6.GLenum + GL_TRIANGLES_ADJACENCY_EXT* = 0x000C.GLenum + GL_PROVOKING_VERTEX_EXT* = 0x8E4F.GLenum + GL_INT64_VEC2_NV* = 0x8FE9.GLenum + GL_INVERSE_NV* = 0x862B.GLenum + GL_CON_29_ATI* = 0x895E.GLenum + GL_TRANSFORM_FEEDBACK_BUFFER_ACTIVE_NV* = 0x8E24.GLenum + GL_FRONT_AND_BACK* = 0x0408.GLenum + GL_MAX_LABEL_LENGTH_KHR* = 0x82E8.GLenum + GL_TRANSFORM_FEEDBACK_BUFFER_START_NV* = 0x8C84.GLenum + GL_EQUAL* = 0x0202.GLenum + GL_RGB10_EXT* = 0x8052.GLenum + GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS_ARB* = 0x8C29.GLenum + GL_OP_ADD_EXT* = 0x8787.GLenum + GL_REPLACEMENT_CODE_ARRAY_POINTER_SUN* = 0x85C3.GLenum + GL_NORMAL_ARRAY_LIST_IBM* = 103071.GLenum + GL_RENDERBUFFER_GREEN_SIZE* = 0x8D51.GLenum + GL_TESS_CONTROL_PROGRAM_PARAMETER_BUFFER_NV* = 0x8C74.GLenum + GL_CURRENT_PALETTE_MATRIX_ARB* = 0x8843.GLenum + GL_DEBUG_TYPE_ERROR* = 0x824C.GLenum + GL_UNIFORM_BUFFER* = 0x8A11.GLenum + GL_NEAREST_CLIPMAP_LINEAR_SGIX* = 0x844E.GLenum + GL_LAST_VERTEX_CONVENTION* = 0x8E4E.GLenum + GL_COMPRESSED_RGBA_ASTC_12x10_KHR* = 0x93BC.GLenum + GL_FENCE_STATUS_NV* = 0x84F3.GLenum + GL_POST_CONVOLUTION_BLUE_BIAS* = 0x8022.GLenum + GL_BLEND_OVERLAP_NV* = 0x9281.GLenum + GL_COMBINE_RGB_ARB* = 0x8571.GLenum + GL_TESS_GEN_MODE* = 0x8E76.GLenum + GL_TEXTURE_ENV* = 0x2300.GLenum + GL_VERTEX_ATTRIB_ARRAY11_NV* = 0x865B.GLenum + GL_SHININESS* = 0x1601.GLenum + GL_DYNAMIC_STORAGE_BIT* = 0x0100.GLbitfield + GL_MODELVIEW30_ARB* = 0x873E.GLenum + GL_WRAP_BORDER_SUN* = 0x81D4.GLenum + GL_SKIP_COMPONENTS1_NV* = -6 + GL_DEPTH_CLAMP_NV* = 0x864F.GLenum + GL_PROGRAM_BINARY_FORMATS* = 0x87FF.GLenum + GL_CURRENT_RASTER_POSITION_VALID* = 0x0B08.GLenum + GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_TESS_CONTROL_SHADER* = 0x92C8.GLenum + GL_T2F_C4F_N3F_V3F* = 0x2A2C.GLenum + GL_R16F* = 0x822D.GLenum + GL_SECONDARY_COLOR_ARRAY_LENGTH_NV* = 0x8F31.GLenum + GL_SEPARATE_ATTRIBS_EXT* = 0x8C8D.GLenum + GL_NEGATIVE_Z_EXT* = 0x87DB.GLenum + GL_Z400_BINARY_AMD* = 0x8740.GLenum + GL_DRAW_INDIRECT_UNIFIED_NV* = 0x8F40.GLenum + GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS_NV* = 0x8C8A.GLenum + GL_UNSIGNED_INT_S8_S8_8_8_NV* = 0x86DA.GLenum + GL_SRGB8_NV* = 0x8C41.GLenum + GL_DEBUG_SEVERITY_MEDIUM_AMD* = 0x9147.GLenum + GL_MAX_DRAW_BUFFERS_ATI* = 0x8824.GLenum + GL_TEXTURE_COORD_ARRAY_POINTER_EXT* = 0x8092.GLenum + GL_RESAMPLE_AVERAGE_OML* = 0x8988.GLenum + GL_NO_ERROR* = 0.GLenum + GL_RGB5* = 0x8050.GLenum + GL_OP_CLAMP_EXT* = 0x878E.GLenum + GL_PROGRAM_RESIDENT_NV* = 0x8647.GLenum + GL_PROGRAM_ALU_INSTRUCTIONS_ARB* = 0x8805.GLenum + GL_ELEMENT_ARRAY_UNIFIED_NV* = 0x8F1F.GLenum + GL_SECONDARY_COLOR_ARRAY_LIST_IBM* = 103077.GLenum + GL_INTENSITY12_EXT* = 0x804C.GLenum + GL_STENCIL_BUFFER_BIT7_QCOM* = 0x00800000.GLbitfield + GL_SAMPLER* = 0x82E6.GLenum + GL_MAD_ATI* = 0x8968.GLenum + GL_STENCIL_BACK_FAIL* = 0x8801.GLenum + GL_LIGHT_MODEL_TWO_SIDE* = 0x0B52.GLenum + GL_UNPACK_SKIP_PIXELS* = 0x0CF4.GLenum + GL_PIXEL_TEX_GEN_SGIX* = 0x8139.GLenum + GL_FRACTIONAL_ODD* = 0x8E7B.GLenum + GL_LOW_INT* = 0x8DF3.GLenum + GL_MODELVIEW* = 0x1700.GLenum + GL_POST_CONVOLUTION_RED_SCALE_EXT* = 0x801C.GLenum + GL_DRAW_BUFFER11_EXT* = 0x8830.GLenum + GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH* = 0x8A35.GLenum + GL_CONVOLUTION_BORDER_MODE* = 0x8013.GLenum + GL_COMPRESSED_ALPHA_ARB* = 0x84E9.GLenum + GL_DEPTH_ATTACHMENT* = 0x8D00.GLenum + GL_ALPHA8_SNORM* = 0x9014.GLenum + GL_DOUBLE_MAT4x3_EXT* = 0x8F4E.GLenum + GL_INTERNALFORMAT_STENCIL_SIZE* = 0x8276.GLenum + GL_BOOL_VEC2_ARB* = 0x8B57.GLenum + GL_FASTEST* = 0x1101.GLenum + GL_MAX_FRAGMENT_INPUT_COMPONENTS* = 0x9125.GLenum + GL_STENCIL_BACK_FUNC_ATI* = 0x8800.GLenum + GL_POLYGON* = 0x0009.GLenum + GL_SAMPLER_1D_ARRAY_EXT* = 0x8DC0.GLenum + GL_OUTPUT_COLOR1_EXT* = 0x879C.GLenum + GL_IMAGE_2D_RECT* = 0x904F.GLenum + GL_RECT_NV* = 0xF6.GLenum + GL_OUTPUT_TEXTURE_COORD21_EXT* = 0x87B2.GLenum + GL_NOR* = 0x1508.GLenum + GL_FOG_COORD_ARRAY* = 0x8457.GLenum + GL_TEXTURE_CUBE_MAP_POSITIVE_Y_OES* = 0x8517.GLenum + GL_TANGENT_ARRAY_POINTER_EXT* = 0x8442.GLenum + GL_DST_OUT_NV* = 0x928D.GLenum + GL_RENDERBUFFER_BINDING_OES* = 0x8CA7.GLenum + GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR* = 0x93D3.GLenum + GL_TEXTURE_GEN_S* = 0x0C60.GLenum + GL_SLIM12S_SGIX* = 0x831F.GLenum + GL_VERTEX_ARRAY_BINDING* = 0x85B5.GLenum + GL_TRACE_PRIMITIVES_BIT_MESA* = 0x0002.GLbitfield + GL_MAX_DEBUG_MESSAGE_LENGTH* = 0x9143.GLenum + GL_EVAL_VERTEX_ATTRIB4_NV* = 0x86CA.GLenum + GL_ACTIVE_SUBROUTINE_UNIFORMS* = 0x8DE6.GLenum + GL_ACCUM_ADJACENT_PAIRS_NV* = 0x90AD.GLenum + GL_NEGATIVE_ONE_EXT* = 0x87DF.GLenum + GL_UNPACK_RESAMPLE_SGIX* = 0x842D.GLenum + GL_ACTIVE_SUBROUTINE_MAX_LENGTH* = 0x8E48.GLenum + GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_EXT* = 0x8518.GLenum + GL_DEBUG_CATEGORY_API_ERROR_AMD* = 0x9149.GLenum + GL_INTERNALFORMAT_BLUE_SIZE* = 0x8273.GLenum + GL_DRAW_BUFFER13_NV* = 0x8832.GLenum + GL_DEBUG_SOURCE_THIRD_PARTY_ARB* = 0x8249.GLenum + GL_R8_EXT* = 0x8229.GLenum + GL_GENERATE_MIPMAP* = 0x8191.GLenum + cGL_SHORT* = 0x1402.GLenum + GL_PACK_REVERSE_ROW_ORDER_ANGLE* = 0x93A4.GLenum + GL_PATH_DASH_OFFSET_RESET_NV* = 0x90B4.GLenum + GL_PACK_SKIP_VOLUMES_SGIS* = 0x8130.GLenum + GL_TEXTURE_RED_TYPE* = 0x8C10.GLenum + GL_MAX_COLOR_ATTACHMENTS_EXT* = 0x8CDF.GLenum + GL_MAP2_VERTEX_ATTRIB5_4_NV* = 0x8675.GLenum + GL_CONSTANT_ALPHA* = 0x8003.GLenum + GL_COLOR_INDEX8_EXT* = 0x80E5.GLenum + GL_DOUBLE_MAT3_EXT* = 0x8F47.GLenum + GL_ATOMIC_COUNTER_BUFFER_INDEX* = 0x9301.GLenum + GL_LINES_ADJACENCY_EXT* = 0x000A.GLenum + GL_RENDERBUFFER_SAMPLES_IMG* = 0x9133.GLenum + GL_COLOR_TABLE_FORMAT* = 0x80D8.GLenum + GL_VERTEX_ATTRIB_ARRAY_TYPE* = 0x8625.GLenum + GL_QUERY_OBJECT_EXT* = 0x9153.GLenum + GL_STREAM_READ_ARB* = 0x88E1.GLenum + GL_MIRROR_CLAMP_TO_EDGE_ATI* = 0x8743.GLint + GL_FRAGMENT_SUBROUTINE_UNIFORM* = 0x92F2.GLenum + GL_UNIFORM_BUFFER_EXT* = 0x8DEE.GLenum + GL_SOURCE2_RGB* = 0x8582.GLenum + GL_PROGRAM_NATIVE_ATTRIBS_ARB* = 0x88AE.GLenum + GL_LUMINANCE12_ALPHA12* = 0x8047.GLenum + GL_INT_SAMPLER_1D_EXT* = 0x8DC9.GLenum + GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_SAMPLES_EXT* = 0x8D6C.GLenum + GL_DEPTH_RENDERABLE* = 0x8287.GLenum + GL_INTERNALFORMAT_BLUE_TYPE* = 0x827A.GLenum + GL_SLUMINANCE8_ALPHA8_EXT* = 0x8C45.GLenum + GL_TEXTURE_BINDING_CUBE_MAP_ARRAY_ARB* = 0x900A.GLenum + GL_COLOR_MATRIX* = 0x80B1.GLenum + GL_RGB8_SNORM* = 0x8F96.GLenum + GL_COLOR_ARRAY_SIZE* = 0x8081.GLenum + GL_DRAW_BUFFER4_NV* = 0x8829.GLenum + GL_VIDEO_BUFFER_INTERNAL_FORMAT_NV* = 0x902D.GLenum + GL_PRESENT_TIME_NV* = 0x8E2A.GLenum + GL_COPY_WRITE_BUFFER* = 0x8F37.GLenum + GL_UNPACK_SKIP_PIXELS_EXT* = 0x0CF4.GLenum + GL_PRIMITIVES_GENERATED_NV* = 0x8C87.GLenum + GL_INT_SAMPLER_BUFFER* = 0x8DD0.GLenum + GL_GLYPH_HORIZONTAL_BEARING_X_BIT_NV* = 0x04.GLbitfield + GL_FOG_COORDINATE_EXT* = 0x8451.GLenum + GL_VERTEX_ARRAY_ADDRESS_NV* = 0x8F21.GLenum + GL_RENDERBUFFER_RED_SIZE_OES* = 0x8D50.GLenum + GL_BGR_INTEGER_EXT* = 0x8D9A.GLenum + GL_UNSIGNED_BYTE_3_3_2* = 0x8032.GLenum + GL_VBO_FREE_MEMORY_ATI* = 0x87FB.GLenum + GL_PATH_COMPUTED_LENGTH_NV* = 0x90A0.GLenum + GL_COLOR_MATRIX_STACK_DEPTH_SGI* = 0x80B2.GLenum + GL_STACK_OVERFLOW* = 0x0503.GLenum + GL_MODELVIEW1_MATRIX_EXT* = 0x8506.GLenum + GL_CURRENT_BINORMAL_EXT* = 0x843C.GLenum + GL_OP_MULTIPLY_MATRIX_EXT* = 0x8798.GLenum + GL_CLIENT_ATTRIB_STACK_DEPTH* = 0x0BB1.GLenum + GL_VERTEX_PROGRAM_TWO_SIDE_NV* = 0x8643.GLenum + GL_HISTOGRAM_WIDTH_EXT* = 0x8026.GLenum + GL_OBJECT_INFO_LOG_LENGTH_ARB* = 0x8B84.GLenum + GL_SAMPLER_2D_ARRAY_SHADOW* = 0x8DC4.GLenum + GL_UNSIGNED_INT_IMAGE_1D* = 0x9062.GLenum + GL_MAX_IMAGE_UNITS* = 0x8F38.GLenum + GL_TEXTURE31_ARB* = 0x84DF.GLenum + GL_CUBIC_HP* = 0x815F.GLenum + GL_OFFSET_HILO_PROJECTIVE_TEXTURE_2D_NV* = 0x8856.GLenum + GL_ARRAY_STRIDE* = 0x92FE.GLenum + GL_DEPTH_PASS_INSTRUMENT_SGIX* = 0x8310.GLenum + GL_COMMAND_BARRIER_BIT* = 0x00000040.GLbitfield + GL_STATIC_DRAW_ARB* = 0x88E4.GLenum + GL_RGB16F* = 0x881B.GLenum + GL_INDEX_MATERIAL_PARAMETER_EXT* = 0x81B9.GLenum + GL_UNPACK_SKIP_VOLUMES_SGIS* = 0x8132.GLenum + GL_TEXTURE_1D* = 0x0DE0.GLenum + GL_VERTEX_PROGRAM_NV* = 0x8620.GLenum + GL_COLOR_ATTACHMENT0_NV* = 0x8CE0.GLenum + GL_READ_PIXEL_DATA_RANGE_LENGTH_NV* = 0x887B.GLenum + GL_FLOAT_32_UNSIGNED_INT_24_8_REV* = 0x8DAD.GLenum + GL_LINE_RESET_TOKEN* = 0x0707.GLenum + GL_WEIGHT_ARRAY_ARB* = 0x86AD.GLenum + GL_TEXTURE17* = 0x84D1.GLenum + GL_DEPTH_COMPONENT32_ARB* = 0x81A7.GLenum + GL_REFERENCED_BY_TESS_CONTROL_SHADER* = 0x9307.GLenum + GL_INVERT* = 0x150A.GLenum + GL_FOG_COORDINATE_ARRAY_STRIDE* = 0x8455.GLenum + GL_COMPRESSED_SIGNED_RG_RGTC2* = 0x8DBE.GLenum + GL_UNSIGNED_SHORT_8_8_MESA* = 0x85BA.GLenum + GL_ELEMENT_ARRAY_TYPE_ATI* = 0x8769.GLenum + GL_CLAMP_VERTEX_COLOR_ARB* = 0x891A.GLenum + GL_POINT_SIZE_ARRAY_STRIDE_OES* = 0x898B.GLenum + GL_RGB8* = 0x8051.GLenum + GL_MATRIX1_ARB* = 0x88C1.GLenum + GL_TEXTURE_POST_SPECULAR_HP* = 0x8168.GLenum + GL_TEXTURE_WRAP_Q_SGIS* = 0x8137.GLenum + GL_SAMPLER_2D_MULTISAMPLE_ARRAY* = 0x910B.GLenum + GL_INVALID_FRAMEBUFFER_OPERATION_OES* = 0x0506.GLenum + GL_VERTEX_ID_SWIZZLE_AMD* = 0x91A5.GLenum + GL_USE_MISSING_GLYPH_NV* = 0x90AA.GLenum + GL_LUMINANCE8_EXT* = 0x8040.GLenum + GL_INT_VEC2* = 0x8B53.GLenum + GL_TEXTURE9* = 0x84C9.GLenum + GL_RGB32UI_EXT* = 0x8D71.GLenum + GL_FENCE_CONDITION_NV* = 0x84F4.GLenum + GL_QUADS_FOLLOW_PROVOKING_VERTEX_CONVENTION_EXT* = 0x8E4C.GLenum + GL_HSL_SATURATION_NV* = 0x92AE.GLenum + GL_CMYKA_EXT* = 0x800D.GLenum + GL_TRANSFORM_FEEDBACK_BUFFER_NV* = 0x8C8E.GLenum + GL_BUFFER_MAP_POINTER_OES* = 0x88BD.GLenum + GL_STORAGE_CLIENT_APPLE* = 0x85B4.GLenum + GL_VERTEX_ARRAY_BUFFER_BINDING_ARB* = 0x8896.GLenum + GL_TEXTURE_INTERNAL_FORMAT* = 0x1003.GLenum + GL_TRANSFORM_FEEDBACK_BUFFER_PAUSED* = 0x8E23.GLenum + GL_UNSIGNED_INT_VEC3* = 0x8DC7.GLenum + GL_TRACE_MASK_MESA* = 0x8755.GLenum + GL_MAP_READ_BIT_EXT* = 0x0001.GLbitfield + GL_READ_FRAMEBUFFER_EXT* = 0x8CA8.GLenum + GL_HISTOGRAM_GREEN_SIZE* = 0x8029.GLenum + GL_COLOR_TABLE_INTENSITY_SIZE_SGI* = 0x80DF.GLenum + GL_SMALL_CCW_ARC_TO_NV* = 0x12.GLenum + GL_RELATIVE_LARGE_CW_ARC_TO_NV* = 0x19.GLenum + GL_POST_COLOR_MATRIX_BLUE_BIAS_SGI* = 0x80BA.GLenum + GL_SCISSOR_BIT* = 0x00080000.GLbitfield + GL_DRAW_BUFFER0_ATI* = 0x8825.GLenum + GL_GEOMETRY_SHADER_BIT* = 0x00000004.GLbitfield + GL_CLIP_FAR_HINT_PGI* = 0x1A221.GLenum + GL_TEXTURE_COMPARE_FUNC_EXT* = 0x884D.GLenum + GL_IS_ROW_MAJOR* = 0x9300.GLenum + GL_MAP1_VERTEX_4* = 0x0D98.GLenum + GL_OUTPUT_TEXTURE_COORD8_EXT* = 0x87A5.GLenum + GL_MAX_VERTEX_IMAGE_UNIFORMS* = 0x90CA.GLenum + GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE* = 0x8211.GLenum + GL_SOURCE1_ALPHA_ARB* = 0x8589.GLenum + GL_VIRTUAL_PAGE_SIZE_X_AMD* = 0x9195.GLenum + GL_CULL_FRAGMENT_NV* = 0x86E7.GLenum + GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS* = 0x92DC.GLenum + GL_QUERY_COUNTER_BITS_EXT* = 0x8864.GLenum + GL_RGB565* = 0x8D62.GLenum + GL_OFFSET_TEXTURE_RECTANGLE_NV* = 0x864C.GLenum + GL_CONVOLUTION_FORMAT_EXT* = 0x8017.GLenum + GL_EYE_POINT_SGIS* = 0x81F4.GLenum + GL_ALPHA32F_ARB* = 0x8816.GLenum + GL_TEXTURE_DEPTH_SIZE* = 0x884A.GLenum + GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR* = 0x93D1.GLenum + GL_PRIMARY_COLOR_NV* = 0x852C.GLenum + GL_BLEND_DST_ALPHA_EXT* = 0x80CA.GLenum + GL_NORMALIZE* = 0x0BA1.GLenum + GL_POST_CONVOLUTION_GREEN_BIAS_EXT* = 0x8021.GLenum + GL_HI_SCALE_NV* = 0x870E.GLenum + GL_TESS_EVALUATION_PROGRAM_NV* = 0x891F.GLenum + GL_MAX_DUAL_SOURCE_DRAW_BUFFERS* = 0x88FC.GLenum + GL_SWIZZLE_STRQ_ATI* = 0x897A.GLenum + GL_READ_FRAMEBUFFER_NV* = 0x8CA8.GLenum + GL_MATRIX_INDEX_ARRAY_STRIDE_OES* = 0x8848.GLenum + GL_MIN_SPARSE_LEVEL_ARB* = 0x919B.GLenum + GL_RG32UI* = 0x823C.GLenum + GL_SAMPLER_2D_ARRAY_EXT* = 0x8DC1.GLenum + GL_TEXTURE22_ARB* = 0x84D6.GLenum + GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS* = 0x8A32.GLenum + GL_CULL_VERTEX_EYE_POSITION_EXT* = 0x81AB.GLenum + GL_TEXTURE_BUFFER* = 0x8C2A.GLenum + GL_MAX_CUBE_MAP_TEXTURE_SIZE_ARB* = 0x851C.GLenum + GL_NORMAL_ARRAY_COUNT_EXT* = 0x8080.GLenum + GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_NV* = 0x8D56.GLenum + GL_ELEMENT_ARRAY_BARRIER_BIT_EXT* = 0x00000002.GLbitfield + GL_VERTEX_ARRAY_COUNT_EXT* = 0x807D.GLenum + GL_PROGRAM_ERROR_STRING_NV* = 0x8874.GLenum + GL_INVALID_FRAMEBUFFER_OPERATION* = 0x0506.GLenum + GL_RGB9_E5* = 0x8C3D.GLenum + GL_GREEN_BITS* = 0x0D53.GLenum + GL_CLIP_DISTANCE0* = 0x3000.GLenum + GL_COMBINER_SUM_OUTPUT_NV* = 0x854C.GLenum + GL_COLOR_ARRAY* = 0x8076.GLenum + GL_RGBA8_SNORM* = 0x8F97.GLenum + GL_PROGRAM_BINDING_ARB* = 0x8677.GLenum + GL_4PASS_0_EXT* = 0x80A4.GLenum + GL_STATIC_DRAW* = 0x88E4.GLenum + GL_TEXTURE_COMPRESSED_BLOCK_WIDTH* = 0x82B1.GLenum + GL_TEXTURE_STORAGE_SPARSE_BIT_AMD* = 0x00000001.GLbitfield + GL_MEDIUM_INT* = 0x8DF4.GLenum + GL_TEXTURE13_ARB* = 0x84CD.GLenum + GL_LUMINANCE_ALPHA16F_ARB* = 0x881F.GLenum + GL_CONTEXT_CORE_PROFILE_BIT* = 0x00000001.GLbitfield + GL_LOCATION_COMPONENT* = 0x934A.GLenum + GL_TEXTURE_RECTANGLE* = 0x84F5.GLenum + GL_SAMPLER_2D_ARB* = 0x8B5E.GLenum + GL_FLOAT_RG32_NV* = 0x8887.GLenum + GL_SKIP_DECODE_EXT* = 0x8A4A.GLenum + GL_LIGHT6* = 0x4006.GLenum + GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD* = 0x87EE.GLenum + GL_NOOP* = 0x1505.GLenum + GL_DEPTH_BUFFER_BIT* = 0x00000100.GLbitfield + GL_FRAMEBUFFER_BINDING_ANGLE* = 0x8CA6.GLenum + GL_DEBUG_TYPE_POP_GROUP_KHR* = 0x826A.GLenum + GL_SAMPLER_2D_RECT_SHADOW* = 0x8B64.GLenum + GL_CONSERVE_MEMORY_HINT_PGI* = 0x1A1FD.GLenum + GL_QUERY_BY_REGION_NO_WAIT* = 0x8E16.GLenum + GL_UNSIGNED_INT_SAMPLER_CUBE* = 0x8DD4.GLenum + GL_LUMINANCE4_EXT* = 0x803F.GLenum + GL_COLOR_ARRAY_STRIDE* = 0x8083.GLenum + GL_SAMPLER_2D_ARRAY_SHADOW_NV* = 0x8DC4.GLenum + GL_REFERENCED_BY_GEOMETRY_SHADER* = 0x9309.GLenum + GL_SIGNED_RGB_UNSIGNED_ALPHA_NV* = 0x870C.GLenum + GL_OBJECT_PLANE* = 0x2501.GLenum + GL_Q* = 0x2003.GLenum + GL_MAX_SPOT_EXPONENT_NV* = 0x8505.GLenum + GL_VERTEX_ATTRIB_ARRAY_LONG* = 0x874E.GLenum + GL_COLOR_ATTACHMENT3* = 0x8CE3.GLenum + GL_TEXTURE_BINDING_RENDERBUFFER_NV* = 0x8E53.GLenum + GL_EXCLUSION_NV* = 0x92A0.GLenum + GL_EDGE_FLAG_ARRAY_ADDRESS_NV* = 0x8F26.GLenum + GL_PRIMARY_COLOR_ARB* = 0x8577.GLenum + GL_LUMINANCE_ALPHA_FLOAT16_ATI* = 0x881F.GLenum + GL_TRACE_TEXTURES_BIT_MESA* = 0x0008.GLbitfield + GL_FRAMEBUFFER_OES* = 0x8D40.GLenum + GL_PIXEL_MAG_FILTER_EXT* = 0x8331.GLenum + GL_IMAGE_BINDING_LAYERED_EXT* = 0x8F3C.GLenum + GL_PATH_MITER_LIMIT_NV* = 0x907A.GLenum + GL_PROJECTION_MATRIX* = 0x0BA7.GLenum + GL_TEXTURE23_ARB* = 0x84D7.GLenum + GL_VERTEX_ATTRIB_MAP2_COEFF_APPLE* = 0x8A07.GLenum + GL_RGB32F_ARB* = 0x8815.GLenum + GL_RED_SCALE* = 0x0D14.GLenum + GL_GEOMETRY_INPUT_TYPE_ARB* = 0x8DDB.GLenum + GL_EVAL_VERTEX_ATTRIB13_NV* = 0x86D3.GLenum + GL_INT64_NV* = 0x140E.GLenum + GL_VIEW_CLASS_24_BITS* = 0x82C9.GLenum + GL_FRAGMENT_LIGHT2_SGIX* = 0x840E.GLenum + GL_LUMINANCE12_ALPHA12_EXT* = 0x8047.GLenum + GL_MAP2_VERTEX_ATTRIB2_4_NV* = 0x8672.GLenum + GL_POINT_SIZE_MIN_SGIS* = 0x8126.GLenum + GL_DEBUG_TYPE_OTHER_ARB* = 0x8251.GLenum + GL_MAP2_VERTEX_ATTRIB0_4_NV* = 0x8670.GLenum + GL_DEBUG_PRINT_MESA* = 0x875A.GLenum + GL_TEXTURE_PRIORITY* = 0x8066.GLenum + GL_PIXEL_MAP_I_TO_G* = 0x0C73.GLenum + GL_VERTEX_ATTRIB_ARRAY_DIVISOR* = 0x88FE.GLenum + GL_TEXTURE_CUBE_MAP_ARB* = 0x8513.GLenum + GL_LUMINANCE8_SNORM* = 0x9015.GLenum + GL_CLIENT_MAPPED_BUFFER_BARRIER_BIT* = 0x00004000.GLbitfield + GL_MAX_COMBINED_TESS_EVALUATION_UNIFORM_COMPONENTS* = 0x8E1F.GLenum + GL_BUFFER_STORAGE_FLAGS* = 0x8220.GLenum + GL_DEPTH_COMPONENT24_SGIX* = 0x81A6.GLenum + GL_UNIFORM_OFFSET* = 0x8A3B.GLenum + GL_TEXTURE_DT_SIZE_NV* = 0x871E.GLenum + GL_POST_COLOR_MATRIX_ALPHA_SCALE_SGI* = 0x80B7.GLenum + GL_DEPTH32F_STENCIL8_NV* = 0x8DAC.GLenum + GL_STENCIL_FUNC* = 0x0B92.GLenum + GL_NEAREST_MIPMAP_LINEAR* = 0x2702.GLint + GL_COMPRESSED_LUMINANCE_LATC1_EXT* = 0x8C70.GLenum + GL_TEXTURE_BORDER* = 0x1005.GLenum + GL_COLOR_ATTACHMENT14_NV* = 0x8CEE.GLenum + GL_TEXTURE_STORAGE_HINT_APPLE* = 0x85BC.GLenum + GL_VERTEX_ARRAY_RANGE_NV* = 0x851D.GLenum + GL_COLOR_ARRAY_SIZE_EXT* = 0x8081.GLenum + GL_INTERNALFORMAT_SUPPORTED* = 0x826F.GLenum + GL_MULTISAMPLE_BIT_ARB* = 0x20000000.GLbitfield + GL_RGB* = 0x1907.GLenum + GL_TRANSFORM_FEEDBACK_PAUSED* = 0x8E23.GLenum + GL_ALPHA8* = 0x803C.GLenum + GL_STENCIL_FAIL* = 0x0B94.GLenum + GL_PACK_SKIP_IMAGES_EXT* = 0x806B.GLenum + GL_FOG_COORDINATE_ARRAY_TYPE_EXT* = 0x8454.GLenum + GL_RESCALE_NORMAL_EXT* = 0x803A.GLenum + GL_LERP_ATI* = 0x8969.GLenum + GL_MATRIX_INDEX_ARRAY_STRIDE_ARB* = 0x8848.GLenum + GL_PROGRAM_LENGTH_NV* = 0x8627.GLenum + GL_UNSIGNED_INT_SAMPLER_3D_EXT* = 0x8DD3.GLenum + GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT* = 0x8DBE.GLenum + GL_UNSIGNED_INT_24_8_NV* = 0x84FA.GLenum + GL_POINT_SIZE_MIN_ARB* = 0x8126.GLenum + GL_COMP_BIT_ATI* = 0x00000002.GLbitfield + GL_NORMAL_ARRAY_ADDRESS_NV* = 0x8F22.GLenum + GL_TEXTURE9_ARB* = 0x84C9.GLenum + GL_MAX_GEOMETRY_OUTPUT_COMPONENTS* = 0x9124.GLenum + GL_DOUBLEBUFFER* = 0x0C32.GLenum + GL_OFFSET_TEXTURE_2D_BIAS_NV* = 0x86E3.GLenum + GL_ACTIVE_PROGRAM_EXT* = 0x8B8D.GLenum + GL_PARTIAL_SUCCESS_NV* = 0x902E.GLenum + GL_SUBTRACT* = 0x84E7.GLenum + GL_DUAL_INTENSITY4_SGIS* = 0x8118.GLenum + GL_FILL* = 0x1B02.GLenum + GL_COMPRESSED_SRGB_ALPHA* = 0x8C49.GLenum + GL_RENDERBUFFER_OES* = 0x8D41.GLenum + GL_PIXEL_MAP_R_TO_R_SIZE* = 0x0CB6.GLenum + GL_TEXTURE_LUMINANCE_TYPE_ARB* = 0x8C14.GLenum + GL_TEXTURE_BUFFER_FORMAT_EXT* = 0x8C2E.GLenum + GL_OUTPUT_TEXTURE_COORD13_EXT* = 0x87AA.GLenum + GL_LINES_ADJACENCY_ARB* = 0x000A.GLenum + GL_MAX_PROGRAM_SUBROUTINE_PARAMETERS_NV* = 0x8F44.GLenum + GL_INTENSITY32UI_EXT* = 0x8D73.GLenum + GL_PACK_IMAGE_HEIGHT* = 0x806C.GLenum + GL_HI_BIAS_NV* = 0x8714.GLenum + GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB* = 0x824E.GLenum + GL_LINE_STIPPLE* = 0x0B24.GLenum + GL_INDEX_LOGIC_OP* = 0x0BF1.GLenum + GL_CON_18_ATI* = 0x8953.GLenum + GL_QUERY_RESULT* = 0x8866.GLenum + GL_FRAGMENT_PROGRAM_NV* = 0x8870.GLenum + GL_MATRIX1_NV* = 0x8631.GLenum + GL_FUNC_SUBTRACT_OES* = 0x800A.GLenum + GL_PIXEL_MAP_I_TO_A_SIZE* = 0x0CB5.GLenum + GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT* = 0x8365.GLenum + GL_OUTPUT_TEXTURE_COORD20_EXT* = 0x87B1.GLenum + GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT_EXT* = 0x00000001.GLbitfield + GL_TRIANGULAR_NV* = 0x90A5.GLenum + GL_TEXTURE_COMPARE_MODE_EXT* = 0x884C.GLenum + GL_SECONDARY_COLOR_ARRAY_SIZE_EXT* = 0x845A.GLenum + GL_FRAMEBUFFER_ATTACHMENT_LAYERED_EXT* = 0x8DA7.GLenum + GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE* = 0x83F3.GLenum + GL_MAX_COMPUTE_VARIABLE_GROUP_SIZE_ARB* = 0x9345.GLenum + GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING_ARB* = 0x889A.GLenum + GL_PROGRAM_FORMAT_ARB* = 0x8876.GLenum + GL_QUAD_INTENSITY4_SGIS* = 0x8122.GLenum + GL_REPLICATE_BORDER* = 0x8153.GLenum + GL_PN_TRIANGLES_ATI* = 0x87F0.GLenum + GL_DEPTH_TEXTURE_MODE* = 0x884B.GLenum + GL_VARIABLE_C_NV* = 0x8525.GLenum + GL_CLIP_PLANE0_IMG* = 0x3000.GLenum + GL_FRONT_LEFT* = 0x0400.GLenum + GL_MATRIX3_ARB* = 0x88C3.GLenum + GL_BLEND_EQUATION_ALPHA_EXT* = 0x883D.GLenum + GL_BGRA8_EXT* = 0x93A1.GLenum + GL_INTERLACE_READ_INGR* = 0x8568.GLenum + GL_TRANSFORM_FEEDBACK_BUFFER_ACTIVE* = 0x8E24.GLenum + GL_MAP1_VERTEX_ATTRIB13_4_NV* = 0x866D.GLenum + GL_PIXEL_TEX_GEN_Q_FLOOR_SGIX* = 0x8186.GLenum + GL_UNSIGNED_INT_SAMPLER_2D_ARRAY* = 0x8DD7.GLenum + GL_ALL_SHADER_BITS_EXT* = 0xFFFFFFFF.GLbitfield + GL_ONE_MINUS_SRC1_ALPHA* = 0x88FB.GLenum + GL_VERTEX_ARRAY_RANGE_LENGTH_APPLE* = 0x851E.GLenum + GL_PROXY_COLOR_TABLE_SGI* = 0x80D3.GLenum + GL_MAX_RENDERBUFFER_SIZE_OES* = 0x84E8.GLenum + GL_VERTEX_ATTRIB_ARRAY_ENABLED* = 0x8622.GLenum + GL_TEXTURE_BINDING_2D_MULTISAMPLE* = 0x9104.GLenum + GL_STENCIL_BUFFER_BIT0_QCOM* = 0x00010000.GLbitfield + GL_IMAGE_BINDING_FORMAT_EXT* = 0x906E.GLenum + GL_RENDERBUFFER_SAMPLES_NV* = 0x8CAB.GLenum + GL_ACCUM_GREEN_BITS* = 0x0D59.GLenum + GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_COMPUTE_SHADER* = 0x90ED.GLenum + GL_FRAMEBUFFER_UNDEFINED* = 0x8219.GLenum + GL_OFFSET_TEXTURE_2D_NV* = 0x86E8.GLenum + GL_POST_CONVOLUTION_RED_BIAS* = 0x8020.GLenum + GL_DRAW_BUFFER8* = 0x882D.GLenum + GL_MAP_INVALIDATE_RANGE_BIT* = 0x0004.GLbitfield + GL_ALWAYS* = 0x0207.GLenum + GL_ALPHA_MIN_SGIX* = 0x8320.GLenum + GL_SOURCE0_RGB_ARB* = 0x8580.GLenum + GL_POINT_SIZE_ARRAY_POINTER_OES* = 0x898C.GLenum + GL_CUBIC_EXT* = 0x8334.GLenum + GL_MAP2_NORMAL* = 0x0DB2.GLenum + GL_TEXTURE_RESIDENT_EXT* = 0x8067.GLenum + GL_TEXTURE_BUFFER_DATA_STORE_BINDING_ARB* = 0x8C2D.GLenum + GL_BUMP_NUM_TEX_UNITS_ATI* = 0x8777.GLenum + GL_TEXTURE_LOD_BIAS_T_SGIX* = 0x818F.GLenum + GL_FONT_UNDERLINE_POSITION_BIT_NV* = 0x04000000.GLbitfield + GL_NORMAL_ARRAY_STRIDE* = 0x807F.GLenum + GL_CONDITION_SATISFIED_APPLE* = 0x911C.GLenum + GL_POINT_SIZE_MIN* = 0x8126.GLenum + GL_SPARE0_PLUS_SECONDARY_COLOR_NV* = 0x8532.GLenum + GL_LAYOUT_DEFAULT_INTEL* = 0.GLenum + GL_FRAMEBUFFER_BINDING* = 0x8CA6.GLenum + GL_HIGH_FLOAT* = 0x8DF2.GLenum + GL_NO_RESET_NOTIFICATION_ARB* = 0x8261.GLenum + GL_OFFSET_TEXTURE_RECTANGLE_SCALE_NV* = 0x864D.GLenum + GL_VERTEX_ATTRIB_ARRAY_ADDRESS_NV* = 0x8F20.GLenum + GL_VIEW_CLASS_96_BITS* = 0x82C5.GLenum + GL_BACK_RIGHT* = 0x0403.GLenum + GL_BLEND_EQUATION_ALPHA* = 0x883D.GLenum + GL_DISTANCE_ATTENUATION_SGIS* = 0x8129.GLenum + GL_PROXY_TEXTURE_CUBE_MAP_ARRAY* = 0x900B.GLenum + GL_RG16* = 0x822C.GLenum + GL_UNDEFINED_VERTEX* = 0x8260.GLenum + GL_PATH_DASH_OFFSET_NV* = 0x907E.GLenum + GL_ALL_ATTRIB_BITS* = 0xFFFFFFFF.GLbitfield + GL_VERTEX_ATTRIB_MAP1_ORDER_APPLE* = 0x8A04.GLenum + GL_MAX_COLOR_MATRIX_STACK_DEPTH_SGI* = 0x80B3.GLenum + GL_TIME_ELAPSED_EXT* = 0x88BF.GLenum + GL_MAP2_VERTEX_3* = 0x0DB7.GLenum + GL_MAX_PROGRAM_RESULT_COMPONENTS_NV* = 0x8909.GLenum + GL_SAMPLER_2D_RECT_SHADOW_ARB* = 0x8B64.GLenum + GL_REFERENCE_PLANE_SGIX* = 0x817D.GLenum + GL_LUMINANCE4_ALPHA4_EXT* = 0x8043.GLenum + GL_PATH_FILL_MASK_NV* = 0x9081.GLenum + GL_FILTER* = 0x829A.GLenum + GL_INT_SAMPLER_2D_ARRAY* = 0x8DCF.GLenum + GL_MAX_PROGRAM_ATTRIB_COMPONENTS_NV* = 0x8908.GLenum + GL_EVAL_VERTEX_ATTRIB2_NV* = 0x86C8.GLenum + GL_NAND* = 0x150E.GLenum + GL_BLEND_SRC_RGB* = 0x80C9.GLenum + GL_OPERAND2_ALPHA_EXT* = 0x859A.GLenum + GL_IMAGE_1D_EXT* = 0x904C.GLenum + GL_CONVOLUTION_FILTER_SCALE* = 0x8014.GLenum + GL_IMAGE_CLASS_2_X_16* = 0x82BD.GLenum + GL_VIEW_CLASS_BPTC_FLOAT* = 0x82D3.GLenum + GL_PROGRAM_INPUT* = 0x92E3.GLenum + GL_1PASS_SGIS* = 0x80A1.GLenum + GL_FOG_DISTANCE_MODE_NV* = 0x855A.GLenum + GL_STENCIL_INDEX16_EXT* = 0x8D49.GLenum + GL_POST_CONVOLUTION_RED_BIAS_EXT* = 0x8020.GLenum + GL_PIXEL_MAP_R_TO_R* = 0x0C76.GLenum + GL_3DC_XY_AMD* = 0x87FA.GLenum + GL_POINT_SIZE_MAX* = 0x8127.GLenum + GL_DOUBLE_MAT3x2* = 0x8F4B.GLenum + GL_DOUBLE_MAT4x2_EXT* = 0x8F4D.GLenum + GL_TEXTURE_HI_SIZE_NV* = 0x871B.GLenum + GL_MATRIX4_NV* = 0x8634.GLenum + GL_SPRITE_TRANSLATION_SGIX* = 0x814B.GLenum + GL_TEXTURE_FILTER_CONTROL_EXT* = 0x8500.GLenum + GL_SMOOTH_LINE_WIDTH_GRANULARITY* = 0x0B23.GLenum + GL_TEXTURE_BINDING_BUFFER* = 0x8C2C.GLenum + GL_INTENSITY4* = 0x804A.GLenum + GL_MAX_IMAGE_SAMPLES_EXT* = 0x906D.GLenum + GL_COLOR_ATTACHMENT12* = 0x8CEC.GLenum + GL_CLAMP_READ_COLOR* = 0x891C.GLenum + GL_ELEMENT_ARRAY_BUFFER_ARB* = 0x8893.GLenum + GL_MAP2_VERTEX_ATTRIB6_4_NV* = 0x8676.GLenum + GL_CONVOLUTION_HEIGHT_EXT* = 0x8019.GLenum + GL_SGX_PROGRAM_BINARY_IMG* = 0x9130.GLenum + GL_MAP1_TEXTURE_COORD_1* = 0x0D93.GLenum + GL_COMPRESSED_RGBA_ASTC_6x6_KHR* = 0x93B4.GLenum + GL_TEXTURE_APPLICATION_MODE_EXT* = 0x834F.GLenum + GL_TEXTURE_GATHER* = 0x82A2.GLenum + GL_MAX_COMBINED_SHADER_STORAGE_BLOCKS* = 0x90DC.GLenum + GL_DEBUG_LOGGED_MESSAGES_KHR* = 0x9145.GLenum + GL_TEXTURE_VIEW_NUM_LEVELS* = 0x82DC.GLenum + GL_ENABLE_BIT* = 0x00002000.GLbitfield + GL_VERTEX_PROGRAM_TWO_SIDE_ARB* = 0x8643.GLenum + GL_INDEX_TEST_EXT* = 0x81B5.GLenum + GL_TEXTURE_WRAP_R* = 0x8072.GLenum + GL_MAX* = 0x8008.GLenum + GL_UNPACK_IMAGE_DEPTH_SGIS* = 0x8133.GLenum + GL_COLOR_ATTACHMENT13_NV* = 0x8CED.GLenum + GL_FOG_BIT* = 0x00000080.GLbitfield + GL_GEOMETRY_SHADER_EXT* = 0x8DD9.GLenum + GL_ALPHA_TEST_FUNC_QCOM* = 0x0BC1.GLenum + GL_DRAW_BUFFER10_EXT* = 0x882F.GLenum + GL_MAX_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB* = 0x880F.GLenum + GL_STENCIL_BACK_REF* = 0x8CA3.GLenum + GL_SAMPLER_1D_ARB* = 0x8B5D.GLenum + GL_DRAW_BUFFER* = 0x0C01.GLenum + GL_CLIENT_PIXEL_STORE_BIT* = 0x00000001.GLbitfield + GL_TEXTURE_STENCIL_SIZE* = 0x88F1.GLenum + GL_ELEMENT_ARRAY_APPLE* = 0x8A0C.GLenum + GL_CON_21_ATI* = 0x8956.GLenum + GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_VERTEX_SHADER* = 0x92C7.GLenum + GL_PIXEL_MAP_I_TO_B* = 0x0C74.GLenum + GL_VERTEX_ATTRIB_MAP1_COEFF_APPLE* = 0x8A03.GLenum + GL_FOG_INDEX* = 0x0B61.GLenum + GL_PROXY_POST_CONVOLUTION_COLOR_TABLE_SGI* = 0x80D4.GLenum + GL_OUTPUT_TEXTURE_COORD29_EXT* = 0x87BA.GLenum + GL_TESS_CONTROL_SUBROUTINE* = 0x92E9.GLenum + GL_IMAGE_CUBE_MAP_ARRAY* = 0x9054.GLenum + GL_RGB_FLOAT32_ATI* = 0x8815.GLenum + GL_OBJECT_SHADER_SOURCE_LENGTH_ARB* = 0x8B88.GLenum + GL_COLOR_INDEX4_EXT* = 0x80E4.GLenum + GL_DRAW_BUFFER14* = 0x8833.GLenum + GL_PATH_STENCIL_DEPTH_OFFSET_UNITS_NV* = 0x90BE.GLenum + GL_NATIVE_GRAPHICS_HANDLE_PGI* = 0x1A202.GLenum + GL_UNSIGNED_SHORT_5_6_5* = 0x8363.GLenum + GL_GREATER* = 0x0204.GLenum + GL_DATA_BUFFER_AMD* = 0x9151.GLenum + GL_GLYPH_VERTICAL_BEARING_Y_BIT_NV* = 0x40.GLbitfield + GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2* = 0x9276.GLenum + GL_RELATIVE_MOVE_TO_NV* = 0x03.GLenum + GL_BLUE_INTEGER* = 0x8D96.GLenum + GL_BLUE_BIAS* = 0x0D1B.GLenum + GL_SHADER_TYPE* = 0x8B4F.GLenum + GL_TRANSFORM_FEEDBACK_BINDING* = 0x8E25.GLenum + GL_TEXTURE17_ARB* = 0x84D1.GLenum + GL_GREEN* = 0x1904.GLenum + GL_MAX_TESS_CONTROL_UNIFORM_BLOCKS* = 0x8E89.GLenum + GL_DRAW_BUFFER6* = 0x882B.GLenum + GL_VALIDATE_STATUS* = 0x8B83.GLenum + GL_TEXTURE_COORD_ARRAY_ADDRESS_NV* = 0x8F25.GLenum + GL_MVP_MATRIX_EXT* = 0x87E3.GLenum + GL_PIXEL_BUFFER_BARRIER_BIT_EXT* = 0x00000080.GLbitfield + GL_MAX_VERTEX_VARYING_COMPONENTS_EXT* = 0x8DDE.GLenum + GL_STACK_OVERFLOW_KHR* = 0x0503.GLenum + GL_MAX_PROJECTION_STACK_DEPTH* = 0x0D38.GLenum + GL_SKIP_COMPONENTS3_NV* = -4 + GL_DEBUG_ASSERT_MESA* = 0x875B.GLenum + GL_INSTRUMENT_BUFFER_POINTER_SGIX* = 0x8180.GLenum + GL_SAMPLE_ALPHA_TO_MASK_EXT* = 0x809E.GLenum + GL_REG_29_ATI* = 0x893E.GLenum + GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_NV* = 0x8C4E.GLenum + GL_DEBUG_CATEGORY_DEPRECATION_AMD* = 0x914B.GLenum + GL_DEPTH_STENCIL_TO_BGRA_NV* = 0x886F.GLenum + GL_UNSIGNED_INT_VEC3_EXT* = 0x8DC7.GLenum + GL_VERTEX_SHADER_EXT* = 0x8780.GLenum + GL_LIST_BASE* = 0x0B32.GLenum + GL_TEXTURE_STENCIL_SIZE_EXT* = 0x88F1.GLenum + GL_ACTIVE_PROGRAM* = 0x8259.GLenum + GL_RGBA_SIGNED_COMPONENTS_EXT* = 0x8C3C.GLenum + GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR* = 0x93DC.GLenum + GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE* = 0x8CD0.GLenum + GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE* = 0x8217.GLenum + GL_MATRIX7_ARB* = 0x88C7.GLenum + GL_FLOAT_VEC3_ARB* = 0x8B51.GLenum + GL_PACK_ROW_BYTES_APPLE* = 0x8A15.GLenum + GL_PIXEL_TILE_GRID_HEIGHT_SGIX* = 0x8143.GLenum + GL_UNIFORM_BLOCK* = 0x92E2.GLenum + GL_VIEWPORT_BIT* = 0x00000800.GLbitfield + GL_RENDERBUFFER_COVERAGE_SAMPLES_NV* = 0x8CAB.GLenum + GL_MAP1_BINORMAL_EXT* = 0x8446.GLenum + GL_SAMPLER_3D* = 0x8B5F.GLenum + GL_RENDERBUFFER_SAMPLES_APPLE* = 0x8CAB.GLenum + GL_DEPTH_WRITEMASK* = 0x0B72.GLenum + GL_MAP2_VERTEX_ATTRIB9_4_NV* = 0x8679.GLenum + GL_TEXTURE_COMPARE_FUNC* = 0x884D.GLenum + GL_CONTEXT_FLAG_ROBUST_ACCESS_BIT_ARB* = 0x00000004.GLbitfield + GL_READ_BUFFER* = 0x0C02.GLenum + GL_ONE_MINUS_SRC1_COLOR* = 0x88FA.GLenum + GL_PROGRAM_FORMAT_ASCII_ARB* = 0x8875.GLenum + GL_DRAW_FRAMEBUFFER_APPLE* = 0x8CA9.GLenum + GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_OES* = 0x8CD0.GLenum + GL_BLEND_DST* = 0x0BE0.GLenum + GL_SHADER_OBJECT_EXT* = 0x8B48.GLenum + GL_UNSIGNALED* = 0x9118.GLenum + GL_VERTEX4_BIT_PGI* = 0x00000008.GLbitfield + GL_DRAW_FRAMEBUFFER_BINDING_APPLE* = 0x8CA6.GLenum + GL_IMAGE_CUBE_EXT* = 0x9050.GLenum + GL_CONTEXT_ROBUST_ACCESS_EXT* = 0x90F3.GLenum + GL_TEXTURE14_ARB* = 0x84CE.GLenum + GL_TEXTURE_CUBE_MAP_POSITIVE_Y* = 0x8517.GLenum + GL_OFFSET_HILO_PROJECTIVE_TEXTURE_RECTANGLE_NV* = 0x8857.GLenum + GL_COMPRESSED_RG11_EAC_OES* = 0x9272.GLenum + GL_OP_DOT4_EXT* = 0x8785.GLenum + GL_FRAMEBUFFER_COMPLETE_EXT* = 0x8CD5.GLenum + GL_TEXTURE_COMPARE_FUNC_ARB* = 0x884D.GLenum + GL_TEXTURE_FILTER4_SIZE_SGIS* = 0x8147.GLenum + GL_ELEMENT_ARRAY_BUFFER_BINDING* = 0x8895.GLenum + GL_UNSIGNED_INT_IMAGE_BUFFER_EXT* = 0x9067.GLenum + GL_IMAGE_1D_ARRAY_EXT* = 0x9052.GLenum + GL_CLAMP_READ_COLOR_ARB* = 0x891C.GLenum + GL_COMPUTE_SUBROUTINE* = 0x92ED.GLenum + GL_R3_G3_B2* = 0x2A10.GLenum + GL_PATH_DASH_ARRAY_COUNT_NV* = 0x909F.GLenum + GL_SPOT_EXPONENT* = 0x1205.GLenum + GL_NUM_PROGRAM_BINARY_FORMATS_OES* = 0x87FE.GLenum + GL_SWIZZLE_STQ_ATI* = 0x8977.GLenum + GL_SYNC_FLUSH_COMMANDS_BIT_APPLE* = 0x00000001.GLbitfield + GL_VERTEX_STREAM6_ATI* = 0x8772.GLenum + GL_FRAGMENT_COLOR_MATERIAL_SGIX* = 0x8401.GLenum + GL_DYNAMIC_ATI* = 0x8761.GLenum + GL_SUB_ATI* = 0x8965.GLenum + GL_PREVIOUS_EXT* = 0x8578.GLenum + GL_MAP2_TEXTURE_COORD_1* = 0x0DB3.GLenum + GL_COLOR_SAMPLES_NV* = 0x8E20.GLenum + GL_HILO_NV* = 0x86F4.GLenum + GL_SHADER_STORAGE_BUFFER_BINDING* = 0x90D3.GLenum + GL_DUP_LAST_CUBIC_CURVE_TO_NV* = 0xF4.GLenum + GL_ACTIVE_SUBROUTINES* = 0x8DE5.GLenum + GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_IMG* = 0x9134.GLenum + GL_INTENSITY16* = 0x804D.GLenum + GL_MAX_PROGRAM_NATIVE_ATTRIBS_ARB* = 0x88AF.GLenum + GL_TIMESTAMP_EXT* = 0x8E28.GLenum + GL_CLIENT_ACTIVE_TEXTURE* = 0x84E1.GLenum + GL_TEXTURE_BINDING_2D_ARRAY* = 0x8C1D.GLenum + GL_INT_SAMPLER_2D_RECT_EXT* = 0x8DCD.GLenum + GL_PREFER_DOUBLEBUFFER_HINT_PGI* = 0x1A1F8.GLenum + GL_TEXTURE_WIDTH* = 0x1000.GLenum + GL_CPU_OPTIMIZED_QCOM* = 0x8FB1.GLenum + GL_TEXTURE_IMAGE_TYPE* = 0x8290.GLenum + GL_MAX_VERTEX_UNIFORM_VECTORS* = 0x8DFB.GLenum + GL_MODULATE_SUBTRACT_ATI* = 0x8746.GLenum + GL_SYNC_STATUS* = 0x9114.GLenum + GL_IMAGE_2D_RECT_EXT* = 0x904F.GLenum + GL_MATRIX6_NV* = 0x8636.GLenum + GL_SOURCE1_RGB_ARB* = 0x8581.GLenum + GL_MAX_COMBINED_ATOMIC_COUNTERS* = 0x92D7.GLenum + GL_MAX_COMPUTE_LOCAL_INVOCATIONS* = 0x90EB.GLenum + GL_SAMPLER_CUBE* = 0x8B60.GLenum + GL_ALPHA_FLOAT32_ATI* = 0x8816.GLenum + GL_COMPRESSED_LUMINANCE_ARB* = 0x84EA.GLenum + GL_COMPRESSED_RGB8_ETC2_OES* = 0x9274.GLenum + GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH_KHR* = 0x8243.GLenum + GL_MINUS_CLAMPED_NV* = 0x92B3.GLenum + GL_REG_31_ATI* = 0x8940.GLenum + GL_ELEMENT_ARRAY_ADDRESS_NV* = 0x8F29.GLenum + GL_SRC1_COLOR* = 0x88F9.GLenum + GL_DEBUG_SEVERITY_LOW_ARB* = 0x9148.GLenum + GL_CON_3_ATI* = 0x8944.GLenum + GL_R32I* = 0x8235.GLenum + GL_BLEND_COLOR* = 0x8005.GLenum + GL_CLIP_PLANE4* = 0x3004.GLenum + GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT* = 0x00000001.GLbitfield + GL_FLOAT16_VEC4_NV* = 0x8FFB.GLenum + GL_DST_IN_NV* = 0x928B.GLenum + GL_VIRTUAL_PAGE_SIZE_Y_ARB* = 0x9196.GLenum + GL_COLOR_ATTACHMENT8_NV* = 0x8CE8.GLenum + GL_TESS_GEN_VERTEX_ORDER* = 0x8E78.GLenum + GL_LOSE_CONTEXT_ON_RESET_EXT* = 0x8252.GLenum + GL_PROGRAM_INSTRUCTIONS_ARB* = 0x88A0.GLenum + GL_TEXTURE_IMAGE_VALID_QCOM* = 0x8BD8.GLenum + GL_SAMPLE_MASK_VALUE_EXT* = 0x80AA.GLenum + GL_CURRENT_MATRIX_ARB* = 0x8641.GLenum + GL_DECR_WRAP_EXT* = 0x8508.GLenum + GL_BLUE_INTEGER_EXT* = 0x8D96.GLenum + GL_COMPRESSED_RG* = 0x8226.GLenum + GL_MAX_PROGRAM_EXEC_INSTRUCTIONS_NV* = 0x88F4.GLenum + GL_MINMAX_EXT* = 0x802E.GLenum + GL_FLOAT_MAT4_ARB* = 0x8B5C.GLenum + GL_TEXTURE_CLIPMAP_FRAME_SGIX* = 0x8172.GLenum + GL_PIXEL_UNPACK_BUFFER_EXT* = 0x88EC.GLenum + GL_TEXTURE5_ARB* = 0x84C5.GLenum + GL_UNSIGNED_INT_IMAGE_2D_RECT* = 0x9065.GLenum + GL_MAX_COMPUTE_TEXTURE_IMAGE_UNITS* = 0x91BC.GLenum + GL_DEPTH_COMPONENT* = 0x1902.GLenum + GL_RG32F_EXT* = 0x8230.GLenum + GL_FACTOR_ALPHA_MODULATE_IMG* = 0x8C07.GLenum + GL_VERTEX_ARRAY_TYPE_EXT* = 0x807B.GLenum + GL_DS_BIAS_NV* = 0x8716.GLenum + GL_NATIVE_GRAPHICS_BEGIN_HINT_PGI* = 0x1A203.GLenum + GL_ALPHA16UI_EXT* = 0x8D78.GLenum + GL_DOUBLE_VEC2* = 0x8FFC.GLenum + GL_MAP1_VERTEX_ATTRIB12_4_NV* = 0x866C.GLenum + GL_4D_COLOR_TEXTURE* = 0x0604.GLenum + GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS* = 0x90D6.GLenum + GL_SPECULAR* = 0x1202.GLenum + GL_TOP_LEVEL_ARRAY_SIZE* = 0x930C.GLenum + GL_MAX_SPARSE_ARRAY_TEXTURE_LAYERS_ARB* = 0x919A.GLenum + GL_COVERAGE_SAMPLES_NV* = 0x8ED4.GLenum + GL_SIGNALED_APPLE* = 0x9119.GLenum + GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_KHR* = 0x824D.GLenum + GL_BUFFER_KHR* = 0x82E0.GLenum + GL_GEOMETRY_TEXTURE* = 0x829E.GLenum + GL_MIN_PROGRAM_TEXTURE_GATHER_OFFSET_NV* = 0x8E5E.GLenum + GL_EVAL_VERTEX_ATTRIB7_NV* = 0x86CD.GLenum + GL_GLYPH_VERTICAL_BEARING_ADVANCE_BIT_NV* = 0x80.GLbitfield + GL_BINORMAL_ARRAY_POINTER_EXT* = 0x8443.GLenum + GL_AUX3* = 0x040C.GLenum + GL_MULTISAMPLE_BIT_EXT* = 0x20000000.GLbitfield + GL_COLOR_TABLE_FORMAT_SGI* = 0x80D8.GLenum + GL_VERTEX_PROGRAM_POINT_SIZE* = 0x8642.GLenum + GL_LINE_WIDTH_GRANULARITY* = 0x0B23.GLenum + GL_MAX_VERTEX_ATTRIB_BINDINGS* = 0x82DA.GLenum + GL_TEXTURE_BINDING_2D_ARRAY_EXT* = 0x8C1D.GLenum + GL_SIMULTANEOUS_TEXTURE_AND_DEPTH_TEST* = 0x82AC.GLenum + GL_SCALE_BY_FOUR_NV* = 0x853F.GLenum + GL_VIRTUAL_PAGE_SIZE_Z_AMD* = 0x9197.GLenum + GL_TEXTURE16* = 0x84D0.GLenum + GL_DSDT8_MAG8_NV* = 0x870A.GLenum + GL_OP_FLOOR_EXT* = 0x878F.GLenum + GL_MAX_PROGRAM_IF_DEPTH_NV* = 0x88F6.GLenum + GL_VERTEX_ARRAY_LIST_IBM* = 103070.GLenum + GL_COMPRESSED_SIGNED_RED_RGTC1* = 0x8DBC.GLenum + GL_CUBIC_CURVE_TO_NV* = 0x0C.GLenum + GL_PROXY_POST_CONVOLUTION_COLOR_TABLE* = 0x80D4.GLenum + GL_SIGNED_IDENTITY_NV* = 0x853C.GLenum + GL_EVAL_VERTEX_ATTRIB6_NV* = 0x86CC.GLenum + GL_MODELVIEW10_ARB* = 0x872A.GLenum + GL_MULTISAMPLE_3DFX* = 0x86B2.GLenum + GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG* = 0x8C00.GLenum + GL_DSDT_MAG_VIB_NV* = 0x86F7.GLenum + GL_TEXCOORD4_BIT_PGI* = 0x80000000.GLbitfield + GL_TRANSFORM_FEEDBACK_BARRIER_BIT* = 0x00000800.GLbitfield + GL_EVAL_VERTEX_ATTRIB10_NV* = 0x86D0.GLenum + GL_DRAW_BUFFER13_ARB* = 0x8832.GLenum + GL_RENDERBUFFER_STENCIL_SIZE_OES* = 0x8D55.GLenum + GL_INTENSITY8I_EXT* = 0x8D91.GLenum + GL_STENCIL_BACK_PASS_DEPTH_FAIL* = 0x8802.GLenum + GL_INTENSITY32F_ARB* = 0x8817.GLenum + GL_CURRENT_ATTRIB_NV* = 0x8626.GLenum + GL_POLYGON_BIT* = 0x00000008.GLbitfield + GL_COMBINE_RGB* = 0x8571.GLenum + GL_MAX_FRAMEBUFFER_HEIGHT* = 0x9316.GLenum + GL_FRAMEBUFFER_BINDING_OES* = 0x8CA6.GLenum + GL_TEXTURE_GREEN_TYPE* = 0x8C11.GLenum + GL_LINE_TO_NV* = 0x04.GLenum + GL_FUNC_ADD_EXT* = 0x8006.GLenum + GL_TEXTURE_LOD_BIAS* = 0x8501.GLenum + GL_QUAD_INTENSITY8_SGIS* = 0x8123.GLenum + GL_SECONDARY_COLOR_ARRAY_EXT* = 0x845E.GLenum + GL_UNPACK_COMPRESSED_SIZE_SGIX* = 0x831A.GLenum + GL_RGBA_INTEGER* = 0x8D99.GLenum + GL_ATOMIC_COUNTER_BUFFER_SIZE* = 0x92C3.GLenum + GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE* = 0x8D56.GLenum + GL_OBJECT_DISTANCE_TO_LINE_SGIS* = 0x81F3.GLenum + GL_DEPTH_BUFFER_BIT3_QCOM* = 0x00000800.GLbitfield + GL_RGB16_SNORM* = 0x8F9A.GLenum + GL_MATRIX_INDEX_ARRAY_TYPE_ARB* = 0x8847.GLenum + GL_TRANSLATE_X_NV* = 0x908E.GLenum + GL_BUFFER_ACCESS_FLAGS* = 0x911F.GLenum + GL_IS_PER_PATCH* = 0x92E7.GLenum + GL_PATH_GEN_MODE_NV* = 0x90B0.GLenum + GL_ALPHA_MIN_CLAMP_INGR* = 0x8563.GLenum + GL_LUMINANCE_ALPHA32I_EXT* = 0x8D87.GLenum + GL_BUFFER_USAGE_ARB* = 0x8765.GLenum + GL_POINT_SIZE* = 0x0B11.GLenum + GL_INVARIANT_EXT* = 0x87C2.GLenum + GL_IMAGE_BINDING_NAME* = 0x8F3A.GLenum + GL_BLEND_SRC_ALPHA* = 0x80CB.GLenum + GL_OUTPUT_TEXTURE_COORD23_EXT* = 0x87B4.GLenum + GL_EYE_PLANE* = 0x2502.GLenum + GL_BOOL_VEC4_ARB* = 0x8B59.GLenum + GL_MITER_REVERT_NV* = 0x90A7.GLenum + GL_SYNC_X11_FENCE_EXT* = 0x90E1.GLenum + GL_GEOMETRY_SHADER_INVOCATIONS* = 0x887F.GLenum + GL_DRAW_BUFFER5_ATI* = 0x882A.GLenum + GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING_ARB* = 0x889D.GLenum + GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_EXT* = 0x906B.GLenum + GL_PIXEL_TEX_GEN_Q_ROUND_SGIX* = 0x8185.GLenum + GL_DOUBLE_MAT3x2_EXT* = 0x8F4B.GLenum + GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB* = 0x8516.GLenum + GL_MOV_ATI* = 0x8961.GLenum + GL_COLOR4_BIT_PGI* = 0x00020000.GLbitfield + GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR* = 0x93DD.GLenum + GL_DEPTH_BOUNDS_TEST_EXT* = 0x8890.GLenum + GL_DST_OVER_NV* = 0x9289.GLenum + GL_PIXEL_MAP_I_TO_I_SIZE* = 0x0CB0.GLenum + GL_ALPHA16F_EXT* = 0x881C.GLenum + GL_RENDERBUFFER_BINDING_EXT* = 0x8CA7.GLenum + GL_MATRIX25_ARB* = 0x88D9.GLenum + GL_OUTPUT_TEXTURE_COORD19_EXT* = 0x87B0.GLenum + GL_NORMAL_MAP* = 0x8511.GLenum + GL_GPU_ADDRESS_NV* = 0x8F34.GLenum + GL_STREAM_READ* = 0x88E1.GLenum + GL_MIRRORED_REPEAT* = 0x8370.GLint + GL_TEXTURE_SWIZZLE_RGBA* = 0x8E46.GLenum + GL_HALF_BIAS_NORMAL_NV* = 0x853A.GLenum + GL_STENCIL_BACK_OP_VALUE_AMD* = 0x874D.GLenum + GL_TEXTURE_BLUE_TYPE_ARB* = 0x8C12.GLenum + GL_MODELVIEW_PROJECTION_NV* = 0x8629.GLenum + GL_ACTIVE_UNIFORM_MAX_LENGTH* = 0x8B87.GLenum + GL_TEXTURE_SWIZZLE_RGBA_EXT* = 0x8E46.GLenum + GL_TEXTURE_GEN_T* = 0x0C61.GLenum + GL_HILO16_NV* = 0x86F8.GLenum + GL_CURRENT_QUERY_EXT* = 0x8865.GLenum + GL_FLOAT16_VEC2_NV* = 0x8FF9.GLenum + GL_RGBA_FLOAT_MODE_ARB* = 0x8820.GLenum + GL_POINT_SIZE_ARRAY_TYPE_OES* = 0x898A.GLenum + GL_GENERATE_MIPMAP_HINT* = 0x8192.GLenum + GL_1PASS_EXT* = 0x80A1.GLenum + GL_SWIZZLE_STQ_DQ_ATI* = 0x8979.GLenum + GL_VERTICAL_LINE_TO_NV* = 0x08.GLenum + GL_MINMAX* = 0x802E.GLenum + GL_RENDERBUFFER_ALPHA_SIZE_EXT* = 0x8D53.GLenum + GL_DEPTH_COMPONENT32F* = 0x8CAC.GLenum + GL_NEXT_VIDEO_CAPTURE_BUFFER_STATUS_NV* = 0x9025.GLenum + GL_CLIP_PLANE5_IMG* = 0x3005.GLenum + GL_TEXTURE_2D_MULTISAMPLE* = 0x9100.GLenum + GL_PREVIOUS* = 0x8578.GLenum + GL_CULL_MODES_NV* = 0x86E0.GLenum + GL_TRACE_ARRAYS_BIT_MESA* = 0x0004.GLbitfield + GL_MAX_ACTIVE_LIGHTS_SGIX* = 0x8405.GLenum + GL_PRIMITIVE_ID_NV* = 0x8C7C.GLenum + GL_DEPTH_COMPONENT16* = 0x81A5.GLenum + GL_FRAMEBUFFER_ATTACHMENT_LAYERED* = 0x8DA7.GLenum + GL_MAX_FRAGMENT_UNIFORM_BLOCKS* = 0x8A2D.GLenum + GL_OUTPUT_COLOR0_EXT* = 0x879B.GLenum + GL_RGBA16F_EXT* = 0x881A.GLenum + GL_MAX_PALETTE_MATRICES_OES* = 0x8842.GLenum + GL_VIEW_CLASS_64_BITS* = 0x82C6.GLenum + GL_TRACE_ALL_BITS_MESA* = 0xFFFF.GLbitfield + GL_REPLACE_VALUE_AMD* = 0x874B.GLenum + GL_PROXY_POST_IMAGE_TRANSFORM_COLOR_TABLE_HP* = 0x8163.GLenum + GL_BGR_INTEGER* = 0x8D9A.GLenum + GL_MAX_DEBUG_LOGGED_MESSAGES_ARB* = 0x9144.GLenum + GL_FOG_COLOR* = 0x0B66.GLenum + GL_MAX_MULTIVIEW_BUFFERS_EXT* = 0x90F2.GLenum + GL_TRANSFORM_FEEDBACK_BUFFER* = 0x8C8E.GLenum + GL_E_TIMES_F_NV* = 0x8531.GLenum + GL_COLOR_TABLE_WIDTH_SGI* = 0x80D9.GLenum + GL_VERTEX_ATTRIB_ARRAY_SIZE* = 0x8623.GLenum + GL_422_REV_AVERAGE_EXT* = 0x80CF.GLenum + GL_WRITE_DISCARD_NV* = 0x88BE.GLenum + GL_DRAW_BUFFER0_EXT* = 0x8825.GLenum + GL_FONT_HEIGHT_BIT_NV* = 0x00800000.GLbitfield + GL_INTERLACE_OML* = 0x8980.GLenum + GL_FUNC_REVERSE_SUBTRACT_EXT* = 0x800B.GLenum + GL_MAX_VERTEX_SHADER_LOCAL_CONSTANTS_EXT* = 0x87C8.GLenum + GL_PRIMARY_COLOR* = 0x8577.GLenum + GL_RGBA16I* = 0x8D88.GLenum + GL_TEXTURE6* = 0x84C6.GLenum + GL_PATH_FILL_BOUNDING_BOX_NV* = 0x90A1.GLenum + GL_WEIGHT_ARRAY_BUFFER_BINDING* = 0x889E.GLenum + GL_COLOR_CLEAR_UNCLAMPED_VALUE_ATI* = 0x8835.GLenum + GL_YCRCB_422_SGIX* = 0x81BB.GLenum + GL_RGB5_A1* = 0x8057.GLenum + GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE_EXT* = 0x8211.GLenum + GL_DRAW_FRAMEBUFFER_BINDING_EXT* = 0x8CA6.GLenum + GL_TEXTURE_1D_ARRAY* = 0x8C18.GLenum + GL_CLAMP_FRAGMENT_COLOR_ARB* = 0x891B.GLenum + GL_FULL_RANGE_EXT* = 0x87E1.GLenum + GL_GEOMETRY_PROGRAM_PARAMETER_BUFFER_NV* = 0x8DA3.GLenum + GL_CON_24_ATI* = 0x8959.GLenum + GL_2D* = 0x0600.GLenum + GL_DRAW_BUFFER5_NV* = 0x882A.GLenum + GL_PALETTE4_RGBA8_OES* = 0x8B91.GLenum + GL_READ_ONLY_ARB* = 0x88B8.GLenum + GL_NUM_SAMPLE_COUNTS* = 0x9380.GLenum + GL_MATRIX_STRIDE* = 0x92FF.GLenum + GL_HISTOGRAM_RED_SIZE* = 0x8028.GLenum + GL_COLOR_ATTACHMENT4* = 0x8CE4.GLenum + GL_PATH_INITIAL_END_CAP_NV* = 0x9077.GLenum + GL_TEXTURE_USAGE_ANGLE* = 0x93A2.GLenum + GL_DOUBLE_MAT2* = 0x8F46.GLenum + GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE* = 0x8212.GLenum + GL_SECONDARY_COLOR_ARRAY_POINTER* = 0x845D.GLenum + GL_MAX_VIEWPORTS* = 0x825B.GLenum + GL_TRANSFORM_FEEDBACK_BUFFER_EXT* = 0x8C8E.GLenum + GL_FRAMEBUFFER_SRGB_EXT* = 0x8DB9.GLenum + GL_STORAGE_SHARED_APPLE* = 0x85BF.GLenum + GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH* = 0x8C76.GLenum + GL_TRANSFORM_FEEDBACK_NV* = 0x8E22.GLenum + GL_MIRRORED_REPEAT_ARB* = 0x8370.GLint + GL_MAX_VERTEX_OUTPUT_COMPONENTS* = 0x9122.GLenum + GL_BUFFER_MAP_LENGTH* = 0x9120.GLenum + GL_BUFFER_OBJECT_APPLE* = 0x85B3.GLenum + GL_INT_VEC4_ARB* = 0x8B55.GLenum + GL_COMBINER3_NV* = 0x8553.GLenum + GL_INT16_VEC3_NV* = 0x8FE6.GLenum + GL_MAX_3D_TEXTURE_SIZE_EXT* = 0x8073.GLenum + GL_GENERATE_MIPMAP_HINT_SGIS* = 0x8192.GLenum + GL_SRC0_ALPHA* = 0x8588.GLenum + GL_IMAGE_2D* = 0x904D.GLenum + GL_VIEW_CLASS_S3TC_DXT1_RGB* = 0x82CC.GLenum + GL_DOT3_RGBA* = 0x86AF.GLenum + GL_TEXTURE_GREEN_SIZE* = 0x805D.GLenum + GL_DOUBLE_MAT2x3* = 0x8F49.GLenum + GL_COORD_REPLACE_OES* = 0x8862.GLenum + GL_MAX_DEBUG_MESSAGE_LENGTH_ARB* = 0x9143.GLenum + GL_TEXTURE_IMMUTABLE_FORMAT_EXT* = 0x912F.GLenum + GL_INDEX_ARRAY_POINTER_EXT* = 0x8091.GLenum + GL_NUM_SHADING_LANGUAGE_VERSIONS* = 0x82E9.GLenum + GL_DEBUG_CALLBACK_FUNCTION_ARB* = 0x8244.GLenum + GL_OFFSET_TEXTURE_MATRIX_NV* = 0x86E1.GLenum + GL_INTENSITY32I_EXT* = 0x8D85.GLenum + GL_BUMP_TEX_UNITS_ATI* = 0x8778.GLenum + GL_RENDERBUFFER* = 0x8D41.GLenum + GL_UPPER_LEFT* = 0x8CA2.GLenum + GL_GUILTY_CONTEXT_RESET_ARB* = 0x8253.GLenum + GL_MAP2_GRID_SEGMENTS* = 0x0DD3.GLenum + GL_REG_23_ATI* = 0x8938.GLenum + GL_UNSIGNED_INT16_NV* = 0x8FF0.GLenum + GL_TEXTURE_COORD_ARRAY_LIST_STRIDE_IBM* = 103084.GLenum + GL_INVARIANT_VALUE_EXT* = 0x87EA.GLenum + GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN_NV* = 0x8C88.GLenum + GL_TEXTURE2_ARB* = 0x84C2.GLenum + GL_UNSIGNED_INT_SAMPLER_2D_ARRAY_EXT* = 0x8DD7.GLenum + GL_IMAGE_CUBE* = 0x9050.GLenum + GL_MAX_PROGRAM_MATRICES_ARB* = 0x862F.GLenum + GL_SIGNED_LUMINANCE8_ALPHA8_NV* = 0x8704.GLenum + GL_INDEX_ARRAY_LIST_IBM* = 103073.GLenum + GL_EVAL_VERTEX_ATTRIB5_NV* = 0x86CB.GLenum + GL_SHADER_SOURCE_LENGTH* = 0x8B88.GLenum + GL_TEXTURE4* = 0x84C4.GLenum + GL_VERTEX_ATTRIB_ARRAY6_NV* = 0x8656.GLenum + GL_PROXY_TEXTURE_1D_STACK_MESAX* = 0x875B.GLenum + GL_MAP_ATTRIB_V_ORDER_NV* = 0x86C4.GLenum + GL_DSDT_NV* = 0x86F5.GLenum + GL_DEBUG_SEVERITY_NOTIFICATION_KHR* = 0x826B.GLenum + GL_FOG_COORDINATE_ARRAY_LIST_STRIDE_IBM* = 103086.GLenum + GL_COMPRESSED_RGBA_ASTC_8x6_KHR* = 0x93B6.GLenum + GL_LINEAR_ATTENUATION* = 0x1208.GLenum + GL_Z4Y12Z4CB12Z4Y12Z4CR12_422_NV* = 0x9035.GLenum + GL_CONVOLUTION_FILTER_BIAS* = 0x8015.GLenum + GL_IMAGE_MIN_FILTER_HP* = 0x815D.GLenum + GL_EYE_RADIAL_NV* = 0x855B.GLenum + GL_TEXTURE_MIN_LOD_SGIS* = 0x813A.GLenum + GL_TRANSFORM_FEEDBACK_BUFFER_BINDING_NV* = 0x8C8F.GLenum + GL_TRANSLATE_2D_NV* = 0x9090.GLenum + GL_CONSTANT_ARB* = 0x8576.GLenum + GL_FLOAT_MAT2x3* = 0x8B65.GLenum + GL_MULTISAMPLE_COVERAGE_MODES_NV* = 0x8E12.GLenum + GL_TRANSPOSE_COLOR_MATRIX* = 0x84E6.GLenum + GL_PROGRAM_STRING_NV* = 0x8628.GLenum + GL_UNSIGNED_INT_SAMPLER_1D_EXT* = 0x8DD1.GLenum + GL_BLEND_SRC_ALPHA_OES* = 0x80CB.GLenum + GL_RGB32F_EXT* = 0x8815.GLenum + GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_EXT* = 0x8CD4.GLenum + GL_RESTART_PATH_NV* = 0xF0.GLenum + GL_MAP2_VERTEX_ATTRIB11_4_NV* = 0x867B.GLenum + GL_VIEW_CLASS_16_BITS* = 0x82CA.GLenum + GL_BUFFER_DATA_SIZE* = 0x9303.GLenum + GL_BUFFER_FLUSHING_UNMAP_APPLE* = 0x8A13.GLenum + GL_RELATIVE_VERTICAL_LINE_TO_NV* = 0x09.GLenum + GL_SRGB_WRITE* = 0x8298.GLenum + GL_TEXTURE_LUMINANCE_SIZE_EXT* = 0x8060.GLenum + GL_VERTEX_PRECLIP_SGIX* = 0x83EE.GLenum + GL_LINEAR_DETAIL_COLOR_SGIS* = 0x8099.GLenum + GL_SOURCE2_ALPHA_ARB* = 0x858A.GLenum + GL_PATH_FOG_GEN_MODE_NV* = 0x90AC.GLenum + GL_RGB10_A2UI* = 0x906F.GLenum + GL_MULTISAMPLE_BIT_3DFX* = 0x20000000.GLbitfield + GL_PIXEL_MAP_G_TO_G_SIZE* = 0x0CB7.GLenum + GL_COVERAGE_BUFFER_BIT_NV* = 0x00008000.GLbitfield + GL_TEXTURE_COMPRESSED* = 0x86A1.GLenum + GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_GEOMETRY_SHADER* = 0x92CA.GLenum + GL_NAMED_STRING_TYPE_ARB* = 0x8DEA.GLenum + GL_RESCALE_NORMAL* = 0x803A.GLenum + GL_OUTPUT_TEXTURE_COORD3_EXT* = 0x87A0.GLenum + GL_RENDERBUFFER_EXT* = 0x8D41.GLenum + GL_QUERY_NO_WAIT* = 0x8E14.GLenum + GL_SAMPLE_ALPHA_TO_COVERAGE* = 0x809E.GLenum + GL_RG8UI* = 0x8238.GLenum + GL_MATRIX3_NV* = 0x8633.GLenum + GL_SAMPLE_BUFFERS_ARB* = 0x80A8.GLenum + GL_VERTEX_CONSISTENT_HINT_PGI* = 0x1A22B.GLenum + GL_SPRITE_AXIAL_SGIX* = 0x814C.GLenum + GL_MODELVIEW_MATRIX* = 0x0BA6.GLenum + GL_SAMPLE_PATTERN_SGIS* = 0x80AC.GLenum + GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE* = 0x906B.GLenum + GL_FLOAT_RG16_NV* = 0x8886.GLenum + GL_IMAGE_TRANSLATE_X_HP* = 0x8157.GLenum + GL_FRAMEBUFFER_SRGB* = 0x8DB9.GLenum + GL_DRAW_BUFFER7* = 0x882C.GLenum + GL_CONVOLUTION_BORDER_COLOR* = 0x8154.GLenum + GL_DRAW_BUFFER5* = 0x882A.GLenum + GL_GEOMETRY_INPUT_TYPE_EXT* = 0x8DDB.GLenum + GL_IUI_V2F_EXT* = 0x81AD.GLenum + GL_FLOAT_RG_NV* = 0x8881.GLenum + GL_VERTEX_SHADER_INVARIANTS_EXT* = 0x87D1.GLenum + GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_NV* = 0x8C4D.GLenum + GL_MAX_PROGRAM_MATRIX_STACK_DEPTH_ARB* = 0x862E.GLenum + GL_SAMPLE_PATTERN_EXT* = 0x80AC.GLenum + GL_DIFFERENCE_NV* = 0x929E.GLenum + GL_POST_CONVOLUTION_ALPHA_BIAS_EXT* = 0x8023.GLenum + GL_COLOR_ATTACHMENT1_EXT* = 0x8CE1.GLenum + GL_TEXTURE_ALPHA_MODULATE_IMG* = 0x8C06.GLenum + GL_TRANSFORM_FEEDBACK_BUFFER_PAUSED_NV* = 0x8E23.GLenum + GL_MAX_TEXTURE_IMAGE_UNITS_ARB* = 0x8872.GLenum + GL_FIXED_OES* = 0x140C.GLenum + GL_ALREADY_SIGNALED_APPLE* = 0x911A.GLenum + GL_SET* = 0x150F.GLenum + GL_PERFMON_RESULT_AMD* = 0x8BC6.GLenum + GL_VARIABLE_G_NV* = 0x8529.GLenum + GL_DRAW_FRAMEBUFFER_ANGLE* = 0x8CA9.GLenum + GL_GEOMETRY_SUBROUTINE_UNIFORM* = 0x92F1.GLenum + GL_COMPARE_REF_DEPTH_TO_TEXTURE_EXT* = 0x884E.GLenum + GL_POINT* = 0x1B00.GLenum + GL_FONT_MAX_ADVANCE_WIDTH_BIT_NV* = 0x01000000.GLbitfield + GL_MAX_TESS_CONTROL_IMAGE_UNIFORMS* = 0x90CB.GLenum + GL_PLUS_CLAMPED_ALPHA_NV* = 0x92B2.GLenum + GL_DRAW_BUFFER3_ATI* = 0x8828.GLenum + GL_LUMINANCE_ALPHA16I_EXT* = 0x8D8D.GLenum + GL_SUBPIXEL_BITS* = 0x0D50.GLenum + GL_POINT_SPRITE* = 0x8861.GLenum + GL_DRAW_BUFFER0* = 0x8825.GLenum + GL_DEPTH_BIAS* = 0x0D1F.GLenum + GL_COLOR_ARRAY_TYPE* = 0x8082.GLenum + GL_DEPENDENT_GB_TEXTURE_2D_NV* = 0x86EA.GLenum + GL_MAX_SAMPLES_ANGLE* = 0x8D57.GLenum + GL_ALLOW_DRAW_MEM_HINT_PGI* = 0x1A211.GLenum + GL_GEOMETRY_OUTPUT_TYPE* = 0x8918.GLenum + GL_MAX_DEBUG_LOGGED_MESSAGES_KHR* = 0x9144.GLenum + GL_VERTEX_ATTRIB_ARRAY0_NV* = 0x8650.GLenum + GL_PRIMITIVES_GENERATED_EXT* = 0x8C87.GLenum + GL_TEXTURE_FLOAT_COMPONENTS_NV* = 0x888C.GLenum + GL_CLIP_VOLUME_CLIPPING_HINT_EXT* = 0x80F0.GLenum + GL_FRAGMENT_PROGRAM_POSITION_MESA* = 0x8BB0.GLenum + GL_MAX_FRAGMENT_IMAGE_UNIFORMS* = 0x90CE.GLenum + GL_VERTEX_ARRAY_BINDING_APPLE* = 0x85B5.GLenum + GL_SHADER_GLOBAL_ACCESS_BARRIER_BIT_NV* = 0x00000010.GLbitfield + GL_FIRST_VERTEX_CONVENTION* = 0x8E4D.GLenum + GL_DECR_WRAP* = 0x8508.GLenum + GL_IMAGE_CLASS_1_X_32* = 0x82BB.GLenum + GL_MAX_CLIP_PLANES_IMG* = 0x0D32.GLenum + GL_MAX_VARYING_COMPONENTS* = 0x8B4B.GLenum + GL_POST_COLOR_MATRIX_RED_BIAS_SGI* = 0x80B8.GLenum + GL_DSDT_MAG_NV* = 0x86F6.GLenum + GL_DEBUG_SOURCE_APPLICATION* = 0x824A.GLenum + GL_OPERAND0_RGB_ARB* = 0x8590.GLenum + GL_SIMULTANEOUS_TEXTURE_AND_DEPTH_WRITE* = 0x82AE.GLenum + GL_VIDEO_COLOR_CONVERSION_MATRIX_NV* = 0x9029.GLenum + GL_MAP2_VERTEX_ATTRIB13_4_NV* = 0x867D.GLenum + GL_DOT2_ADD_ATI* = 0x896C.GLenum + GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS* = 0x8A33.GLenum + GL_IMAGE_BINDING_LAYER_EXT* = 0x8F3D.GLenum + GL_FRAGMENT_COLOR_MATERIAL_FACE_SGIX* = 0x8402.GLenum + GL_PACK_IMAGE_DEPTH_SGIS* = 0x8131.GLenum + GL_MAX_GEOMETRY_UNIFORM_COMPONENTS_EXT* = 0x8DDF.GLenum + GL_Z_EXT* = 0x87D7.GLenum + GL_MAP1_VERTEX_ATTRIB15_4_NV* = 0x866F.GLenum + GL_RG8_SNORM* = 0x8F95.GLenum + GL_OUTPUT_TEXTURE_COORD5_EXT* = 0x87A2.GLenum + GL_TEXTURE_BINDING_1D_ARRAY_EXT* = 0x8C1C.GLenum + GL_OBJECT_ACTIVE_UNIFORM_MAX_LENGTH_ARB* = 0x8B87.GLenum + GL_PATH_END_CAPS_NV* = 0x9076.GLenum + GL_COLOR_TABLE_GREEN_SIZE* = 0x80DB.GLenum + GL_MAX_ELEMENTS_INDICES_EXT* = 0x80E9.GLenum + GL_TEXTURE_IMMUTABLE_FORMAT* = 0x912F.GLenum + GL_WRITE_ONLY_ARB* = 0x88B9.GLenum + GL_COLOR_ATTACHMENT10_EXT* = 0x8CEA.GLenum + GL_INVERT_RGB_NV* = 0x92A3.GLenum + GL_CURRENT_RASTER_DISTANCE* = 0x0B09.GLenum + GL_DEPTH_STENCIL_TO_RGBA_NV* = 0x886E.GLenum + GL_INVERTED_SCREEN_W_REND* = 0x8491.GLenum + GL_TABLE_TOO_LARGE* = 0x8031.GLenum + GL_REG_16_ATI* = 0x8931.GLenum + GL_BLEND_EQUATION_ALPHA_OES* = 0x883D.GLenum + GL_DRAW_FRAMEBUFFER_BINDING_NV* = 0x8CA6.GLenum + GL_ACTIVE_SUBROUTINE_UNIFORM_LOCATIONS* = 0x8E47.GLenum + GL_TEXTURE_BLUE_SIZE_EXT* = 0x805E.GLenum + GL_TEXTURE_BORDER_VALUES_NV* = 0x871A.GLenum + GL_PROGRAM_LENGTH_ARB* = 0x8627.GLenum + GL_BOUNDING_BOX_OF_BOUNDING_BOXES_NV* = 0x909C.GLenum + GL_DOT_PRODUCT_NV* = 0x86EC.GLenum + GL_TRANSPOSE_PROJECTION_MATRIX_ARB* = 0x84E4.GLenum + GL_TEXTURE_2D_MULTISAMPLE_ARRAY* = 0x9102.GLenum + GL_MIN_PROGRAM_TEXEL_OFFSET_NV* = 0x8904.GLenum + GL_MAP2_BINORMAL_EXT* = 0x8447.GLenum + GL_COLOR_ARRAY_BUFFER_BINDING* = 0x8898.GLenum + GL_TEXTURE_COORD_ARRAY_POINTER* = 0x8092.GLenum + GL_TEXTURE4_ARB* = 0x84C4.GLenum + GL_VARIABLE_A_NV* = 0x8523.GLenum + GL_CURRENT_FOG_COORDINATE_EXT* = 0x8453.GLenum + GL_TEXTURE_CUBE_MAP_POSITIVE_X* = 0x8515.GLenum + GL_DEPENDENT_AR_TEXTURE_2D_NV* = 0x86E9.GLenum + GL_TEXTURE29_ARB* = 0x84DD.GLenum + GL_INVERSE_TRANSPOSE_NV* = 0x862D.GLenum + GL_TEXTURE_COLOR_WRITEMASK_SGIS* = 0x81EF.GLenum + GL_HISTOGRAM_SINK* = 0x802D.GLenum + GL_ALPHA12_EXT* = 0x803D.GLenum + GL_TEXTURE_CLIPMAP_LOD_OFFSET_SGIX* = 0x8175.GLenum + GL_DSDT_MAG_INTENSITY_NV* = 0x86DC.GLenum + GL_ATC_RGB_AMD* = 0x8C92.GLenum + GL_PROGRAM_ATTRIB_COMPONENTS_NV* = 0x8906.GLenum + GL_UNIFORM_BLOCK_BINDING* = 0x8A3F.GLenum + GL_POLYGON_STIPPLE* = 0x0B42.GLenum + GL_BACK* = 0x0405.GLenum + GL_DEPTH_COMPONENT16_NONLINEAR_NV* = 0x8E2C.GLenum + GL_ALPHA32F_EXT* = 0x8816.GLenum + GL_CLAMP_TO_BORDER* = 0x812D.GLint + GL_FLOAT_RGBA16_NV* = 0x888A.GLenum + GL_VERTEX_ARRAY_RANGE_LENGTH_NV* = 0x851E.GLenum + GL_UNSIGNED_INT_SAMPLER_RENDERBUFFER_NV* = 0x8E58.GLenum + GL_SAMPLER_2D* = 0x8B5E.GLenum + GL_SMOOTH_POINT_SIZE_RANGE* = 0x0B12.GLenum + GL_DEPTH_PASS_INSTRUMENT_MAX_SGIX* = 0x8312.GLenum + GL_INTERPOLATE_ARB* = 0x8575.GLenum + GL_VERTEX_ARRAY_LENGTH_NV* = 0x8F2B.GLenum + GL_FUNC_SUBTRACT_EXT* = 0x800A.GLenum + GL_OUTPUT_TEXTURE_COORD14_EXT* = 0x87AB.GLenum + GL_HISTOGRAM_SINK_EXT* = 0x802D.GLenum + GL_RG_EXT* = 0x8227.GLenum + GL_SHARPEN_TEXTURE_FUNC_POINTS_SGIS* = 0x80B0.GLenum + GL_COLOR_TABLE_SCALE* = 0x80D6.GLenum + GL_CURRENT_RASTER_TEXTURE_COORDS* = 0x0B06.GLenum + GL_PIXEL_BUFFER_BARRIER_BIT* = 0x00000080.GLbitfield + GL_SHADING_LANGUAGE_VERSION* = 0x8B8C.GLenum + GL_TEXTURE_MATRIX_FLOAT_AS_INT_BITS_OES* = 0x898F.GLenum + GL_DUAL_LUMINANCE_ALPHA4_SGIS* = 0x811C.GLenum + GL_CLAMP* = 0x2900.GLint + GL_4PASS_2_EXT* = 0x80A6.GLenum + GL_POLYGON_OFFSET_LINE* = 0x2A02.GLenum + GL_LOGIC_OP* = 0x0BF1.GLenum + GL_RENDERBUFFER_HEIGHT* = 0x8D43.GLenum + GL_COPY_INVERTED* = 0x150C.GLenum + GL_NONE* = 0.GLenum + GL_COLOR_ENCODING* = 0x8296.GLenum + GL_ONE_MINUS_CONSTANT_ALPHA_EXT* = 0x8004.GLenum + GL_DEBUG_TYPE_ERROR_KHR* = 0x824C.GLenum + GL_PIXEL_TILE_GRID_WIDTH_SGIX* = 0x8142.GLenum + GL_UNIFORM_SIZE* = 0x8A38.GLenum + GL_VERTEX_SHADER_BINDING_EXT* = 0x8781.GLenum + GL_BLEND_DST_RGB_EXT* = 0x80C8.GLenum + GL_QUADS* = 0x0007.GLenum + cGL_INT* = 0x1404.GLenum + GL_PIXEL_TEX_GEN_MODE_SGIX* = 0x832B.GLenum + GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_ARB* = 0x8E8F.GLenum + GL_SAMPLE_ALPHA_TO_ONE_ARB* = 0x809F.GLenum + GL_RGBA32F_EXT* = 0x8814.GLenum + GL_VERTEX_PROGRAM_POSITION_MESA* = 0x8BB4.GLenum + GL_GEOMETRY_SUBROUTINE* = 0x92EB.GLenum + GL_UNSIGNED_INT_SAMPLER_1D_ARRAY_EXT* = 0x8DD6.GLenum + GL_IMAGE_BINDING_LAYER* = 0x8F3D.GLenum + GL_PIXEL_PACK_BUFFER_ARB* = 0x88EB.GLenum + GL_UNIFORM_BLOCK_REFERENCED_BY_TESS_EVALUATION_SHADER* = 0x84F1.GLenum + GL_VERTEX_ATTRIB_ARRAY_SIZE_ARB* = 0x8623.GLenum + GL_ALPHA8UI_EXT* = 0x8D7E.GLenum + GL_RELATIVE_SMOOTH_CUBIC_CURVE_TO_NV* = 0x11.GLenum + GL_CAVEAT_SUPPORT* = 0x82B8.GLenum + GL_ACCUM* = 0x0100.GLenum + GL_DRAW_BUFFER3_NV* = 0x8828.GLenum + GL_DEBUG_TYPE_OTHER_KHR* = 0x8251.GLenum + GL_TESS_GEN_SPACING* = 0x8E77.GLenum + GL_FLOAT_MAT4x2* = 0x8B69.GLenum + GL_TEXTURE_GEN_STR_OES* = 0x8D60.GLenum + GL_NUM_COMPATIBLE_SUBROUTINES* = 0x8E4A.GLenum + GL_CLIP_DISTANCE1* = 0x3001.GLenum + GL_DEPTH_COMPONENT32_SGIX* = 0x81A7.GLenum + GL_FRAMEZOOM_SGIX* = 0x818B.GLenum + GL_COLOR_ATTACHMENT14_EXT* = 0x8CEE.GLenum + GL_POLYGON_TOKEN* = 0x0703.GLenum + GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE* = 0x8213.GLenum + GL_DRAW_BUFFER2_EXT* = 0x8827.GLenum + GL_MATRIX_INDEX_ARRAY_TYPE_OES* = 0x8847.GLenum + GL_HISTOGRAM_LUMINANCE_SIZE_EXT* = 0x802C.GLenum + GL_DEPTH_BOUNDS_EXT* = 0x8891.GLenum + GL_TEXTURE24* = 0x84D8.GLenum + GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES* = 0x8A43.GLenum + GL_MAX_PATCH_VERTICES* = 0x8E7D.GLenum + GL_COMPILE_STATUS* = 0x8B81.GLenum + GL_MODELVIEW4_ARB* = 0x8724.GLenum + GL_SHADER_BINARY_VIV* = 0x8FC4.GLenum + GL_CON_10_ATI* = 0x894B.GLenum + GL_FRAGMENT_LIGHT5_SGIX* = 0x8411.GLenum + GL_CONVOLUTION_1D_EXT* = 0x8010.GLenum + GL_CONSTANT_BORDER_HP* = 0x8151.GLenum + GL_SAMPLE_BUFFERS* = 0x80A8.GLenum + GL_RGB8UI* = 0x8D7D.GLenum + GL_FRAGMENT_MATERIAL_EXT* = 0x8349.GLenum + GL_OP_RECIP_EXT* = 0x8794.GLenum + GL_SHADER_OPERATION_NV* = 0x86DF.GLenum + GL_COMPUTE_SUBROUTINE_UNIFORM* = 0x92F3.GLenum + GL_VIDEO_BUFFER_PITCH_NV* = 0x9028.GLenum + GL_UNKNOWN_CONTEXT_RESET_ARB* = 0x8255.GLenum + GL_COLOR_ATTACHMENT3_EXT* = 0x8CE3.GLenum + GL_QUERY_WAIT* = 0x8E13.GLenum + GL_SOURCE1_RGB* = 0x8581.GLenum + GL_DELETE_STATUS* = 0x8B80.GLenum + GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH_ARB* = 0x8243.GLenum + GL_HILO8_NV* = 0x885E.GLenum + GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY_EXT* = 0x906A.GLenum + GL_LUMINANCE_ALPHA_FLOAT16_APPLE* = 0x881F.GLenum + GL_LUMINANCE16_SNORM* = 0x9019.GLenum + GL_MAX_CLIPMAP_VIRTUAL_DEPTH_SGIX* = 0x8178.GLenum + GL_RENDER* = 0x1C00.GLenum + GL_RED_INTEGER* = 0x8D94.GLenum + GL_DEBUG_TYPE_ERROR_ARB* = 0x824C.GLenum + GL_IMAGE_BINDING_ACCESS* = 0x8F3E.GLenum + GL_COVERAGE_COMPONENT_NV* = 0x8ED0.GLenum + GL_TEXTURE_BINDING_BUFFER_EXT* = 0x8C2C.GLenum + GL_MAX_PROGRAM_PATCH_ATTRIBS_NV* = 0x86D8.GLenum + GL_DUAL_LUMINANCE12_SGIS* = 0x8116.GLenum + GL_QUAD_ALPHA8_SGIS* = 0x811F.GLenum + GL_COMPRESSED_RED_GREEN_RGTC2_EXT* = 0x8DBD.GLenum + GL_PACK_INVERT_MESA* = 0x8758.GLenum + GL_OUTPUT_TEXTURE_COORD11_EXT* = 0x87A8.GLenum + GL_DYNAMIC_DRAW_ARB* = 0x88E8.GLenum + GL_RGB565_OES* = 0x8D62.GLenum + GL_LINE* = 0x1B01.GLenum + GL_T2F_V3F* = 0x2A27.GLenum + GL_DIFFUSE* = 0x1201.GLenum + GL_FOG_COORDINATE_SOURCE* = 0x8450.GLenum + GL_TEXTURE_1D_ARRAY_EXT* = 0x8C18.GLenum + GL_TEXTURE_RECTANGLE_NV* = 0x84F5.GLenum + GL_STENCIL_INDEX4_EXT* = 0x8D47.GLenum + GL_VERTEX_PROGRAM_TWO_SIDE* = 0x8643.GLenum + GL_REDUCE* = 0x8016.GLenum + GL_DEBUG_CALLBACK_USER_PARAM_KHR* = 0x8245.GLenum + GL_DEBUG_LOGGED_MESSAGES_AMD* = 0x9145.GLenum + GL_FONT_UNITS_PER_EM_BIT_NV* = 0x00100000.GLbitfield + GL_INVALID_FRAMEBUFFER_OPERATION_EXT* = 0x0506.GLenum + GL_NORMAL_ARRAY_BUFFER_BINDING_ARB* = 0x8897.GLenum + GL_SAMPLE_MASK_INVERT_SGIS* = 0x80AB.GLenum + GL_MAX_SHADER_BUFFER_ADDRESS_NV* = 0x8F35.GLenum + GL_PIXEL_MAP_I_TO_A* = 0x0C75.GLenum + GL_MINOR_VERSION* = 0x821C.GLenum + GL_TEXTURE_BUFFER_EXT* = 0x8C2A.GLenum + GL_SKIP_COMPONENTS4_NV* = -3 + GL_FLOAT16_NV* = 0x8FF8.GLenum + GL_FEEDBACK_BUFFER_TYPE* = 0x0DF2.GLenum + GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT* = 0x8C72.GLenum + GL_REG_6_ATI* = 0x8927.GLenum + GL_EDGE_FLAG_ARRAY_LIST_IBM* = 103075.GLenum + GL_MATRIX26_ARB* = 0x88DA.GLenum + GL_ALPHA16* = 0x803E.GLenum + GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME* = 0x8CD1.GLenum + GL_HISTOGRAM_ALPHA_SIZE* = 0x802B.GLenum + GL_COLOR_MATRIX_STACK_DEPTH* = 0x80B2.GLenum + GL_INTERNALFORMAT_GREEN_TYPE* = 0x8279.GLenum + GL_YCRCBA_SGIX* = 0x8319.GLenum + GL_VIEW_CLASS_48_BITS* = 0x82C7.GLenum + GL_VERTEX_ATTRIB_ARRAY3_NV* = 0x8653.GLenum + GL_CLIENT_STORAGE_BIT* = 0x0200.GLbitfield + GL_MIN_SAMPLE_SHADING_VALUE_ARB* = 0x8C37.GLenum + GL_PROXY_TEXTURE_CUBE_MAP* = 0x851B.GLenum + GL_MAX_COMBINED_SHADER_OUTPUT_RESOURCES* = 0x8F39.GLenum + GL_TEXTURE15* = 0x84CF.GLenum + GL_COLOR* = 0x1800.GLenum + GL_LIGHT1* = 0x4001.GLenum + GL_LUMINANCE_ALPHA16F_EXT* = 0x881F.GLenum + GL_TEXTURE_VIEW_NUM_LAYERS* = 0x82DE.GLenum + GL_MAX_TESS_EVALUATION_TEXTURE_IMAGE_UNITS* = 0x8E82.GLenum + GL_INTERLEAVED_ATTRIBS_NV* = 0x8C8C.GLenum + GL_INT_SAMPLER_BUFFER_EXT* = 0x8DD0.GLenum + GL_EVAL_VERTEX_ATTRIB14_NV* = 0x86D4.GLenum + GL_FRAGMENT_PROGRAM_CALLBACK_MESA* = 0x8BB1.GLenum + GL_EMISSION* = 0x1600.GLenum + GL_WEIGHT_ARRAY_STRIDE_ARB* = 0x86AA.GLenum + GL_ACTIVE_VARIABLES* = 0x9305.GLenum + GL_TIMEOUT_IGNORED* = 0xFFFFFFFFFFFFFFFF.GLenum + GL_VERTEX_STREAM5_ATI* = 0x8771.GLenum + GL_INDEX_ARRAY_POINTER* = 0x8091.GLenum + GL_POST_COLOR_MATRIX_ALPHA_SCALE* = 0x80B7.GLenum + GL_TESS_CONTROL_SHADER* = 0x8E88.GLenum + GL_POLYGON_MODE* = 0x0B40.GLenum + GL_ASYNC_DRAW_PIXELS_SGIX* = 0x835D.GLenum + GL_RGBA16_SNORM* = 0x8F9B.GLenum + GL_TEXTURE_NORMAL_EXT* = 0x85AF.GLenum + GL_REG_22_ATI* = 0x8937.GLenum + GL_FRAMEBUFFER_DEFAULT_WIDTH* = 0x9310.GLenum + GL_TEXCOORD1_BIT_PGI* = 0x10000000.GLbitfield + GL_REFERENCE_PLANE_EQUATION_SGIX* = 0x817E.GLenum + GL_COLOR_ALPHA_PAIRING_ATI* = 0x8975.GLenum + GL_SINGLE_COLOR* = 0x81F9.GLenum + GL_MODELVIEW21_ARB* = 0x8735.GLenum + GL_FORMAT_SUBSAMPLE_24_24_OML* = 0x8982.GLenum + GL_SOURCE1_ALPHA* = 0x8589.GLenum + GL_LINEARLIGHT_NV* = 0x92A7.GLenum + GL_REG_2_ATI* = 0x8923.GLenum + GL_QUERY_RESULT_AVAILABLE* = 0x8867.GLenum + GL_PERSPECTIVE_CORRECTION_HINT* = 0x0C50.GLenum + GL_COMBINE_ALPHA_ARB* = 0x8572.GLenum + GL_HISTOGRAM_ALPHA_SIZE_EXT* = 0x802B.GLenum + GL_SIGNED_RGB8_NV* = 0x86FF.GLenum + GL_DEPTH_TEXTURE_MODE_ARB* = 0x884B.GLenum + GL_PRESENT_DURATION_NV* = 0x8E2B.GLenum + GL_TRIANGLES_ADJACENCY_ARB* = 0x000C.GLenum + GL_TEXTURE_BUFFER_OFFSET* = 0x919D.GLenum + GL_PROGRAM_STRING_ARB* = 0x8628.GLenum + GL_UNSIGNED_INT_IMAGE_1D_EXT* = 0x9062.GLenum + GL_COLOR_ATTACHMENT2* = 0x8CE2.GLenum + GL_DOT_PRODUCT_TEXTURE_2D_NV* = 0x86EE.GLenum + GL_QUERY_BUFFER* = 0x9192.GLenum + GL_TEXTURE_CUBE_MAP_NEGATIVE_Z* = 0x851A.GLenum + GL_PIXEL_TEX_GEN_ALPHA_REPLACE_SGIX* = 0x8187.GLenum + GL_FULL_SUPPORT* = 0x82B7.GLenum + GL_MAX_PROGRAM_ENV_PARAMETERS_ARB* = 0x88B5.GLenum + GL_MAX_COMPUTE_WORK_GROUP_COUNT* = 0x91BE.GLenum + GL_DEBUG_TYPE_PERFORMANCE* = 0x8250.GLenum + GL_DRAW_BUFFER12_EXT* = 0x8831.GLenum + GL_UNSIGNED_INT_SAMPLER_BUFFER_AMD* = 0x9003.GLenum + GL_CURRENT_FOG_COORDINATE* = 0x8453.GLenum + GL_INTENSITY_EXT* = 0x8049.GLenum + GL_TRANSPOSE_NV* = 0x862C.GLenum + GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_NV* = 0x8C4F.GLenum + GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS* = 0x8C80.GLenum + GL_COLOR_ARRAY_POINTER_EXT* = 0x8090.GLenum + GL_TEXTURE_BUFFER_DATA_STORE_BINDING_EXT* = 0x8C2D.GLenum + GL_GEOMETRY_VERTICES_OUT_ARB* = 0x8DDA.GLenum + GL_RELATIVE_SMOOTH_QUADRATIC_CURVE_TO_NV* = 0x0F.GLenum + GL_OP_INDEX_EXT* = 0x8782.GLenum + GL_REG_1_ATI* = 0x8922.GLenum + GL_OFFSET* = 0x92FC.GLenum + GL_PATH_COVER_DEPTH_FUNC_NV* = 0x90BF.GLenum + GL_UNPACK_COMPRESSED_BLOCK_DEPTH* = 0x9129.GLenum + GL_POLYGON_OFFSET_UNITS* = 0x2A00.GLenum + GL_INDEX_TEST_FUNC_EXT* = 0x81B6.GLenum + GL_POINT_SMOOTH* = 0x0B10.GLenum + GL_SCALEBIAS_HINT_SGIX* = 0x8322.GLenum + GL_COMPRESSED_RGBA_ASTC_5x4_KHR* = 0x93B1.GLenum + GL_SEPARATE_SPECULAR_COLOR* = 0x81FA.GLenum + GL_VERTEX_ATTRIB_ARRAY14_NV* = 0x865E.GLenum + GL_INTENSITY16_EXT* = 0x804D.GLenum + GL_R8_SNORM* = 0x8F94.GLenum + GL_DEBUG_LOGGED_MESSAGES* = 0x9145.GLenum + GL_ALPHA8I_EXT* = 0x8D90.GLenum + GL_OPERAND2_RGB* = 0x8592.GLenum + GL_EMBOSS_LIGHT_NV* = 0x855D.GLenum + GL_EDGE_FLAG_ARRAY_STRIDE_EXT* = 0x808C.GLenum + GL_VERTEX_ATTRIB_ARRAY_INTEGER_NV* = 0x88FD.GLenum + GL_NUM_LOOPBACK_COMPONENTS_ATI* = 0x8974.GLenum + GL_DEBUG_SOURCE_APPLICATION_KHR* = 0x824A.GLenum + GL_COMPRESSED_RGB_S3TC_DXT1_EXT* = 0x83F0.GLenum + GL_DEBUG_SOURCE_OTHER_ARB* = 0x824B.GLenum + cGL_DOUBLE* = 0x140A.GLenum + GL_STENCIL_TEST_TWO_SIDE_EXT* = 0x8910.GLenum + GL_MIN_PROGRAM_TEXEL_OFFSET* = 0x8904.GLenum + GL_3DC_X_AMD* = 0x87F9.GLenum + GL_FLOAT_RGB32_NV* = 0x8889.GLenum + GL_SECONDARY_COLOR_ARRAY_POINTER_EXT* = 0x845D.GLenum + GL_OPERAND2_ALPHA_ARB* = 0x859A.GLenum + GL_IMAGE_3D* = 0x904E.GLenum + GL_SECONDARY_COLOR_ARRAY_SIZE* = 0x845A.GLenum + GL_RELEASED_APPLE* = 0x8A19.GLenum + GL_RENDER_DIRECT_TO_FRAMEBUFFER_QCOM* = 0x8FB3.GLenum + GL_FRAMEBUFFER_DEFAULT_LAYERS* = 0x9312.GLenum + GL_INTENSITY* = 0x8049.GLenum + GL_RENDERBUFFER_BLUE_SIZE_OES* = 0x8D52.GLenum + GL_FLOAT_RGB_NV* = 0x8882.GLenum + GL_ARRAY_ELEMENT_LOCK_FIRST_EXT* = 0x81A8.GLenum + GL_CON_4_ATI* = 0x8945.GLenum + GL_ROUND_NV* = 0x90A4.GLenum + GL_CLIP_DISTANCE2* = 0x3002.GLenum + GL_MAX_PROGRAM_ALU_INSTRUCTIONS_ARB* = 0x880B.GLenum + GL_PROGRAM_ERROR_STRING_ARB* = 0x8874.GLenum + GL_STORAGE_CACHED_APPLE* = 0x85BE.GLenum + GL_LIGHTEN_NV* = 0x9298.GLenum + GL_TEXTURE23* = 0x84D7.GLenum + GL_SAMPLER_CUBE_SHADOW* = 0x8DC5.GLenum + GL_VERTEX_PROGRAM_ARB* = 0x8620.GLenum + GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT* = 0x8C4E.GLenum + GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB* = 0x851A.GLenum + GL_RENDERBUFFER_SAMPLES* = 0x8CAB.GLenum + GL_RENDERBUFFER_STENCIL_SIZE* = 0x8D55.GLenum + GL_VIRTUAL_PAGE_SIZE_INDEX_ARB* = 0x91A7.GLenum + GL_CLIP_PLANE5* = 0x3005.GLenum + GL_VERTEX_WEIGHT_ARRAY_POINTER_EXT* = 0x8510.GLenum + GL_COLOR_BUFFER_BIT5_QCOM* = 0x00000020.GLbitfield + GL_DOUBLE_MAT2x3_EXT* = 0x8F49.GLenum + GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS* = 0x8A42.GLenum + GL_COLOR_ATTACHMENT8_EXT* = 0x8CE8.GLenum + GL_UNIFORM_BUFFER_BINDING_EXT* = 0x8DEF.GLenum + GL_MATRIX8_ARB* = 0x88C8.GLenum + GL_COUNTER_TYPE_AMD* = 0x8BC0.GLenum + GL_INT8_VEC3_NV* = 0x8FE2.GLenum + GL_TEXTURE_BINDING_3D_OES* = 0x806A.GLenum + GL_DEPTH_PASS_INSTRUMENT_COUNTERS_SGIX* = 0x8311.GLenum + GL_IMAGE_BINDING_LEVEL* = 0x8F3B.GLenum + GL_STENCIL_BACK_FAIL_ATI* = 0x8801.GLenum + GL_TRANSFORM_FEEDBACK_ATTRIBS_NV* = 0x8C7E.GLenum + GL_COLOR_TABLE_INTENSITY_SIZE* = 0x80DF.GLenum + GL_TEXTURE_2D_BINDING_EXT* = 0x8069.GLenum + GL_CW* = 0x0900.GLenum + GL_COLOR_ATTACHMENT6* = 0x8CE6.GLenum + GL_R32UI* = 0x8236.GLenum + GL_PROXY_TEXTURE_3D* = 0x8070.GLenum + GL_FLOAT_VEC2_ARB* = 0x8B50.GLenum + GL_C3F_V3F* = 0x2A24.GLenum + GL_MAX_PROGRAM_PARAMETER_BUFFER_BINDINGS_NV* = 0x8DA0.GLenum + GL_EVAL_VERTEX_ATTRIB11_NV* = 0x86D1.GLenum + GL_MAX_VERTEX_ARRAY_RANGE_ELEMENT_NV* = 0x8520.GLenum + GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_OES* = 0x8CDC.GLenum + GL_MAX_VIEWPORT_DIMS* = 0x0D3A.GLenum + GL_STENCIL_CLEAR_TAG_VALUE_EXT* = 0x88F3.GLenum + GL_TEXTURE_BUFFER_FORMAT_ARB* = 0x8C2E.GLenum + GL_PROGRAM_NATIVE_PARAMETERS_ARB* = 0x88AA.GLenum + GL_FLOAT_MAT3x2* = 0x8B67.GLenum + GL_BLUE_BIT_ATI* = 0x00000004.GLbitfield + GL_COLOR_ATTACHMENT6_NV* = 0x8CE6.GLenum + GL_AND_INVERTED* = 0x1504.GLenum + GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS* = 0x90D7.GLenum + GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR* = 0x93D0.GLenum + GL_PACK_COMPRESSED_BLOCK_DEPTH* = 0x912D.GLenum + GL_TEXTURE_COMPARE_SGIX* = 0x819A.GLenum + GL_SYNC_CL_EVENT_COMPLETE_ARB* = 0x8241.GLenum + GL_DEBUG_TYPE_PORTABILITY* = 0x824F.GLenum + GL_IMAGE_BINDING_FORMAT* = 0x906E.GLenum + GL_RESAMPLE_DECIMATE_OML* = 0x8989.GLenum + GL_MAX_PROGRAM_TEMPORARIES_ARB* = 0x88A5.GLenum + GL_ALL_SHADER_BITS* = 0xFFFFFFFF.GLbitfield + GL_TRANSFORM_FEEDBACK_VARYING* = 0x92F4.GLenum + GL_TRANSFORM_FEEDBACK_BUFFER_BINDING* = 0x8C8F.GLenum + GL_ACTIVE_STENCIL_FACE_EXT* = 0x8911.GLenum + GL_MAP1_VERTEX_ATTRIB4_4_NV* = 0x8664.GLenum + GL_LINK_STATUS* = 0x8B82.GLenum + GL_SYNC_FLUSH_COMMANDS_BIT* = 0x00000001.GLbitfield + GL_BLEND* = 0x0BE2.GLenum + GL_OUTPUT_TEXTURE_COORD12_EXT* = 0x87A9.GLenum + GL_DRAW_BUFFER11_ARB* = 0x8830.GLenum + GL_OBJECT_BUFFER_USAGE_ATI* = 0x8765.GLenum + GL_COLORDODGE_NV* = 0x9299.GLenum + GL_SHADER_IMAGE_LOAD* = 0x82A4.GLenum + GL_EMBOSS_CONSTANT_NV* = 0x855E.GLenum + GL_MAP_TESSELLATION_NV* = 0x86C2.GLenum + GL_MAX_DRAW_BUFFERS_EXT* = 0x8824.GLenum + GL_VERTEX_WEIGHT_ARRAY_TYPE_EXT* = 0x850E.GLenum + GL_TEXTURE_ENV_COLOR* = 0x2201.GLenum + GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER* = 0x8A46.GLenum + GL_DOT_PRODUCT_REFLECT_CUBE_MAP_NV* = 0x86F2.GLenum + GL_QUERY_KHR* = 0x82E3.GLenum + GL_RG* = 0x8227.GLenum + GL_MAX_TEXTURE_SIZE* = 0x0D33.GLenum + GL_TEXTURE_NUM_LEVELS_QCOM* = 0x8BD9.GLenum + GL_MAP2_VERTEX_ATTRIB3_4_NV* = 0x8673.GLenum + GL_LUMINANCE_FLOAT32_APPLE* = 0x8818.GLenum + GL_MAP2_VERTEX_ATTRIB7_4_NV* = 0x8677.GLenum + GL_GEOMETRY_SHADER_ARB* = 0x8DD9.GLenum + GL_SYNC_FENCE_APPLE* = 0x9116.GLenum + GL_SAMPLE_MASK_VALUE* = 0x8E52.GLenum + GL_PROXY_TEXTURE_RECTANGLE_NV* = 0x84F7.GLenum + GL_DEPTH_FUNC* = 0x0B74.GLenum + GL_S* = 0x2000.GLenum + GL_CONSTANT_COLOR_EXT* = 0x8001.GLenum + GL_MAX_PROGRAM_LOOP_COUNT_NV* = 0x88F8.GLenum + GL_VIEW_COMPATIBILITY_CLASS* = 0x82B6.GLenum + GL_INT_SAMPLER_BUFFER_AMD* = 0x9002.GLenum + GL_COMPRESSED_SRGB* = 0x8C48.GLenum + GL_PROGRAM_SEPARABLE_EXT* = 0x8258.GLenum + GL_FOG_FUNC_POINTS_SGIS* = 0x812B.GLenum + GL_MITER_TRUNCATE_NV* = 0x90A8.GLenum + GL_POLYGON_OFFSET_POINT* = 0x2A01.GLenum + GL_SRGB_READ* = 0x8297.GLenum + GL_INDEX_ARRAY_ADDRESS_NV* = 0x8F24.GLenum + GL_MAX_FRAMEBUFFER_WIDTH* = 0x9315.GLenum + GL_COMPRESSED_RED_RGTC1_EXT* = 0x8DBB.GLenum + GL_RGB_INTEGER_EXT* = 0x8D98.GLenum + GL_OP_NEGATE_EXT* = 0x8783.GLenum + GL_POINT_SIZE_MAX_ARB* = 0x8127.GLenum + GL_TEXTURE_DEFORMATION_BIT_SGIX* = 0x00000001.GLbitfield + GL_SIGNED_LUMINANCE8_NV* = 0x8702.GLenum + GL_OPERAND2_RGB_EXT* = 0x8592.GLenum + GL_MAX_PIXEL_TRANSFORM_2D_STACK_DEPTH_EXT* = 0x8337.GLenum + GL_RECIP_ADD_SIGNED_ALPHA_IMG* = 0x8C05.GLenum + GL_VERTEX_STREAM7_ATI* = 0x8773.GLenum + GL_MODELVIEW1_STACK_DEPTH_EXT* = 0x8502.GLenum + GL_DYNAMIC_DRAW* = 0x88E8.GLenum + GL_DRAW_BUFFER15_EXT* = 0x8834.GLenum + GL_TEXTURE_COMPARE_OPERATOR_SGIX* = 0x819B.GLenum + GL_SQUARE_NV* = 0x90A3.GLenum + GL_COMPRESSED_SRGB_S3TC_DXT1_EXT* = 0x8C4C.GLenum + GL_DRAW_BUFFER0_ARB* = 0x8825.GLenum + GL_GPU_OPTIMIZED_QCOM* = 0x8FB2.GLenum + GL_VERTEX_WEIGHT_ARRAY_STRIDE_EXT* = 0x850F.GLenum + GL_SPRITE_EYE_ALIGNED_SGIX* = 0x814E.GLenum + GL_MAP1_VERTEX_ATTRIB3_4_NV* = 0x8663.GLenum + GL_SAMPLE_MASK_SGIS* = 0x80A0.GLenum + GL_TEXTURE_SAMPLES* = 0x9106.GLenum + GL_AND_REVERSE* = 0x1502.GLenum + GL_COMBINER4_NV* = 0x8554.GLenum + GL_FONT_Y_MIN_BOUNDS_BIT_NV* = 0x00020000.GLbitfield + GL_VIEW_CLASS_32_BITS* = 0x82C8.GLenum + GL_BGRA_EXT* = 0x80E1.GLenum + GL_TANGENT_ARRAY_TYPE_EXT* = 0x843E.GLenum + GL_BLEND_EQUATION_RGB_OES* = 0x8009.GLenum + GL_TRANSPOSE_TEXTURE_MATRIX_ARB* = 0x84E5.GLenum + GL_GET_TEXTURE_IMAGE_FORMAT* = 0x8291.GLenum + GL_PACK_MAX_COMPRESSED_SIZE_SGIX* = 0x831B.GLenum + GL_UNIFORM_ARRAY_STRIDE* = 0x8A3C.GLenum + GL_REFLECTION_MAP_ARB* = 0x8512.GLenum + GL_RGBA_FLOAT16_ATI* = 0x881A.GLenum + GL_MAX_TESS_CONTROL_OUTPUT_COMPONENTS* = 0x8E83.GLenum + GL_RED_BITS* = 0x0D52.GLenum + GL_VERTEX_TEXTURE* = 0x829B.GLenum + GL_UNSIGNALED_APPLE* = 0x9118.GLenum + GL_RENDERBUFFER_ALPHA_SIZE_OES* = 0x8D53.GLenum + GL_DRAW_BUFFER14_NV* = 0x8833.GLenum + GL_STREAM_COPY_ARB* = 0x88E2.GLenum + GL_SECONDARY_COLOR_ARRAY_TYPE* = 0x845B.GLenum + GL_MATRIX22_ARB* = 0x88D6.GLenum + GL_VERTEX_ARRAY_RANGE_WITHOUT_FLUSH_NV* = 0x8533.GLenum + GL_IUI_N3F_V3F_EXT* = 0x81B0.GLenum + GL_SPARE0_NV* = 0x852E.GLenum + GL_FOG_COORD* = 0x8451.GLenum + GL_DRAW_BUFFER8_ARB* = 0x882D.GLenum + GL_MATRIX24_ARB* = 0x88D8.GLenum + GL_MAX_DEBUG_MESSAGE_LENGTH_AMD* = 0x9143.GLenum + GL_POST_COLOR_MATRIX_BLUE_SCALE* = 0x80B6.GLenum + GL_TEXTURE_HEIGHT_QCOM* = 0x8BD3.GLenum + GL_NUM_FRAGMENT_REGISTERS_ATI* = 0x896E.GLenum + GL_IMAGE_3D_EXT* = 0x904E.GLenum + GL_TEXTURE_FILTER_CONTROL* = 0x8500.GLenum + GL_VIDEO_BUFFER_NV* = 0x9020.GLenum + GL_CURRENT_MATRIX_INDEX_ARB* = 0x8845.GLenum + GL_STENCIL_BUFFER_BIT4_QCOM* = 0x00100000.GLbitfield + GL_SIGNED_INTENSITY_NV* = 0x8707.GLenum + GL_RASTERIZER_DISCARD_NV* = 0x8C89.GLenum + GL_MAX_DEFORMATION_ORDER_SGIX* = 0x8197.GLenum + GL_SAMPLES_3DFX* = 0x86B4.GLenum + GL_DOT_PRODUCT_PASS_THROUGH_NV* = 0x885B.GLenum + GL_RGB_SCALE_EXT* = 0x8573.GLenum + GL_TEXTURE_UNSIGNED_REMAP_MODE_NV* = 0x888F.GLenum + GL_MIRROR_CLAMP_TO_EDGE_EXT* = 0x8743.GLint + GL_NATIVE_GRAPHICS_END_HINT_PGI* = 0x1A204.GLenum + GL_UNPACK_CLIENT_STORAGE_APPLE* = 0x85B2.GLenum + GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER* = 0x8CDC.GLenum + GL_FOG_START* = 0x0B63.GLenum + GL_MAX_PROGRAM_CALL_DEPTH_NV* = 0x88F5.GLenum + GL_MODELVIEW18_ARB* = 0x8732.GLenum + GL_MAX_FRAMEZOOM_FACTOR_SGIX* = 0x818D.GLenum + GL_EDGE_FLAG_ARRAY_POINTER* = 0x8093.GLenum + GL_GREEN_INTEGER* = 0x8D95.GLenum + GL_IMAGE_BUFFER* = 0x9051.GLenum + GL_PROJECTION* = 0x1701.GLenum + GL_UNSIGNED_INT_VEC4_EXT* = 0x8DC8.GLenum + GL_PALETTE8_RGB5_A1_OES* = 0x8B99.GLenum + GL_RENDERBUFFER_SAMPLES_EXT* = 0x8CAB.GLenum + GL_TEXTURE3* = 0x84C3.GLenum + GL_CURRENT_RASTER_INDEX* = 0x0B05.GLenum + GL_INTERLEAVED_ATTRIBS_EXT* = 0x8C8C.GLenum + GL_STENCIL_BACK_WRITEMASK* = 0x8CA5.GLenum + GL_POINT_SPRITE_ARB* = 0x8861.GLenum + GL_TRANSPOSE_TEXTURE_MATRIX* = 0x84E5.GLenum + GL_DRAW_BUFFER1_ARB* = 0x8826.GLenum + GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS* = 0x92D0.GLenum + GL_DEPTH_ATTACHMENT_OES* = 0x8D00.GLenum + GL_COMPRESSED_RGBA_PVRTC_2BPPV2_IMG* = 0x9137.GLenum + GL_SRGB_ALPHA* = 0x8C42.GLenum + GL_UNSIGNED_INT64_ARB* = 0x140F.GLenum + GL_LAST_VERTEX_CONVENTION_EXT* = 0x8E4E.GLenum + GL_IMAGE_CLASS_1_X_8* = 0x82C1.GLenum + GL_COMPRESSED_RGBA_S3TC_DXT1_EXT* = 0x83F1.GLenum + GL_REFLECTION_MAP* = 0x8512.GLenum + GL_MAX_IMAGE_UNITS_EXT* = 0x8F38.GLenum + GL_DEPTH_STENCIL_NV* = 0x84F9.GLenum + GL_PROGRAM_TEX_INDIRECTIONS_ARB* = 0x8807.GLenum + GL_BINNING_CONTROL_HINT_QCOM* = 0x8FB0.GLenum + GL_T4F_V4F* = 0x2A28.GLenum + GL_FLOAT_VEC4* = 0x8B52.GLenum + GL_CONVEX_HULL_NV* = 0x908B.GLenum + GL_TEXTURE26_ARB* = 0x84DA.GLenum + GL_INDEX_BIT_PGI* = 0x00080000.GLbitfield + GL_TEXTURE_COORD_ARRAY_TYPE_EXT* = 0x8089.GLenum + GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_OES* = 0x8CD2.GLenum + GL_MAX_ARRAY_TEXTURE_LAYERS* = 0x88FF.GLenum + GL_COLOR_ATTACHMENT4_EXT* = 0x8CE4.GLenum + GL_SAMPLE_COVERAGE_VALUE_ARB* = 0x80AA.GLenum + GL_VERTEX_ATTRIB_MAP2_ORDER_APPLE* = 0x8A08.GLenum + GL_MAX_LAYERS* = 0x8281.GLenum + GL_FOG_COORDINATE_ARRAY_POINTER_EXT* = 0x8456.GLenum + GL_INDEX_TEST_REF_EXT* = 0x81B7.GLenum + GL_GREEN_BIT_ATI* = 0x00000002.GLbitfield + GL_STRICT_SCISSOR_HINT_PGI* = 0x1A218.GLenum + GL_MAP2_VERTEX_ATTRIB4_4_NV* = 0x8674.GLenum + GL_MAX_GEOMETRY_OUTPUT_VERTICES_EXT* = 0x8DE0.GLenum + GL_OUTPUT_TEXTURE_COORD31_EXT* = 0x87BC.GLenum + GL_XOR* = 0x1506.GLenum + GL_VIDEO_CAPTURE_FRAME_WIDTH_NV* = 0x9038.GLenum + GL_RGBA* = 0x1908.GLenum + GL_TEXTURE_TARGET* = 0x1006.GLenum + GL_QUERY_TARGET* = 0x82EA.GLenum + +{.deprecated: [ + cGL_TRANSFORM_FEEDBACK_VARYINGS_EXT: GL_TRANSFORM_FEEDBACK_VARYINGS_EXT, + cGL_BLEND_EQUATION_EXT: GL_BLEND_EQUATION_EXT, + cGL_VERTEX_BLEND_ARB: GL_VERTEX_BLEND_ARB, + cGL_TESSELLATION_MODE_AMD: GL_TESSELLATION_MODE_AMD, + cGL_POLYGON_OFFSET_EXT: GL_POLYGON_OFFSET_EXT, + cGL_BLEND_COLOR_EXT: GL_BLEND_COLOR_EXT, + cGL_TRANSFORM_FEEDBACK_VARYINGS_NV: GL_TRANSFORM_FEEDBACK_VARYINGS_NV, + cGL_COLOR_MATERIAL: GL_COLOR_MATERIAL, + cGL_READ_BUFFER_NV: GL_READ_BUFFER_NV, + cGL_FOG_FUNC_SGIS: GL_FOG_FUNC_SGIS, + cGL_HISTOGRAM_EXT: GL_HISTOGRAM_EXT, + cGL_LINE_WIDTH: GL_LINE_WIDTH, + cGL_PROVOKING_VERTEX: GL_PROVOKING_VERTEX, + cGL_SHADE_MODEL: GL_SHADE_MODEL, + cGL_FRONT_FACE: GL_FRONT_FACE, + cGL_PRIMITIVE_RESTART_INDEX: GL_PRIMITIVE_RESTART_INDEX, + cGL_READ_PIXELS: GL_READ_PIXELS, + cGL_VIEWPORT: GL_VIEWPORT, + cGL_DEPTH_RANGE: GL_DEPTH_RANGE, + cGL_COLOR_TABLE_SGI: GL_COLOR_TABLE_SGI, + cGL_CLEAR: GL_CLEAR, + cGL_ASYNC_MARKER_SGIX: GL_ASYNC_MARKER_SGIX, + cGL_ACTIVE_TEXTURE_ARB: GL_ACTIVE_TEXTURE_ARB, + cGL_SAMPLE_COVERAGE: GL_SAMPLE_COVERAGE, + cGL_BLEND_EQUATION_OES: GL_BLEND_EQUATION_OES, + cGL_MATRIX_MODE: GL_MATRIX_MODE, + cGL_TRANSFORM_FEEDBACK_VARYINGS: GL_TRANSFORM_FEEDBACK_VARYINGS, + cGL_SAMPLE_COVERAGE_ARB: GL_SAMPLE_COVERAGE_ARB, + cGL_TRACK_MATRIX_NV: GL_TRACK_MATRIX_NV, + cGL_COMBINER_INPUT_NV: GL_COMBINER_INPUT_NV, + cGL_TESSELLATION_FACTOR_AMD: GL_TESSELLATION_FACTOR_AMD, + cGL_BLEND_EQUATION: GL_BLEND_EQUATION, + cGL_CULL_FACE: GL_CULL_FACE, + cGL_HISTOGRAM: GL_HISTOGRAM, + cGL_PRIMITIVE_RESTART_INDEX_NV: GL_PRIMITIVE_RESTART_INDEX_NV, + cGL_SAMPLE_MASK_EXT: GL_SAMPLE_MASK_EXT, + cGL_RENDER_MODE: GL_RENDER_MODE, + cGL_CURRENT_PALETTE_MATRIX_OES: GL_CURRENT_PALETTE_MATRIX_OES, + cGL_VERTEX_ATTRIB_BINDING: GL_VERTEX_ATTRIB_BINDING, + cGL_TEXTURE_LIGHT_EXT: GL_TEXTURE_LIGHT_EXT, + cGL_INDEX_MATERIAL_EXT: GL_INDEX_MATERIAL_EXT, + cGL_COLOR_TABLE: GL_COLOR_TABLE, + cGL_PATH_STENCIL_FUNC_NV: GL_PATH_STENCIL_FUNC_NV, + cGL_EDGE_FLAG: GL_EDGE_FLAG, + cGL_ACTIVE_TEXTURE: GL_ACTIVE_TEXTURE, + cGL_CLIENT_ACTIVE_TEXTURE_ARB: GL_CLIENT_ACTIVE_TEXTURE_ARB, + cGL_VERTEX_ARRAY_RANGE_APPLE: GL_VERTEX_ARRAY_RANGE_APPLE, + cGL_TEXTURE_VIEW: GL_TEXTURE_VIEW, + cGL_BITMAP: GL_BITMAP, + cGL_PRIMITIVE_RESTART_NV: GL_PRIMITIVE_RESTART_NV, + cGL_VERTEX_BINDING_DIVISOR: GL_VERTEX_BINDING_DIVISOR, + cGL_STENCIL_OP_VALUE_AMD: GL_STENCIL_OP_VALUE_AMD, + cGL_PROVOKING_VERTEX_EXT: GL_PROVOKING_VERTEX_EXT, + cGL_CURRENT_PALETTE_MATRIX_ARB: GL_CURRENT_PALETTE_MATRIX_ARB, + cGL_PIXEL_TEX_GEN_SGIX: GL_PIXEL_TEX_GEN_SGIX, + cGL_GENERATE_MIPMAP: GL_GENERATE_MIPMAP, + cGL_UNIFORM_BUFFER_EXT: GL_UNIFORM_BUFFER_EXT, + cGL_STENCIL_FUNC: GL_STENCIL_FUNC, + cGL_VERTEX_ARRAY_RANGE_NV: GL_VERTEX_ARRAY_RANGE_NV, + cGL_ACTIVE_PROGRAM_EXT: GL_ACTIVE_PROGRAM_EXT, + cGL_LINE_STIPPLE: GL_LINE_STIPPLE, + cGL_REFERENCE_PLANE_SGIX: GL_REFERENCE_PLANE_SGIX, + cGL_DRAW_BUFFER: GL_DRAW_BUFFER, + cGL_LIST_BASE: GL_LIST_BASE, + cGL_READ_BUFFER: GL_READ_BUFFER, + cGL_FRAGMENT_COLOR_MATERIAL_SGIX: GL_FRAGMENT_COLOR_MATERIAL_SGIX, + cGL_CLIENT_ACTIVE_TEXTURE: GL_CLIENT_ACTIVE_TEXTURE, + cGL_BLEND_COLOR: GL_BLEND_COLOR, + cGL_MINMAX_EXT: GL_MINMAX_EXT, + cGL_POINT_SIZE: GL_POINT_SIZE, + cGL_MINMAX: GL_MINMAX, + cGL_SAMPLE_PATTERN_SGIS: GL_SAMPLE_PATTERN_SGIS, + cGL_SAMPLE_PATTERN_EXT: GL_SAMPLE_PATTERN_EXT, + cGL_UNIFORM_BLOCK_BINDING: GL_UNIFORM_BLOCK_BINDING, + cGL_POLYGON_STIPPLE: GL_POLYGON_STIPPLE, + cGL_LOGIC_OP: GL_LOGIC_OP, + cGL_ACCUM: GL_ACCUM, + cGL_FRAMEZOOM_SGIX: GL_FRAMEZOOM_SGIX, + cGL_DEPTH_BOUNDS_EXT: GL_DEPTH_BOUNDS_EXT, + cGL_TEXTURE_BUFFER_EXT: GL_TEXTURE_BUFFER_EXT, + cGL_POLYGON_MODE: GL_POLYGON_MODE, + cGL_TEXTURE_NORMAL_EXT: GL_TEXTURE_NORMAL_EXT, + cGL_PROGRAM_STRING_ARB: GL_PROGRAM_STRING_ARB, + cGL_PATH_COVER_DEPTH_FUNC_NV: GL_PATH_COVER_DEPTH_FUNC_NV, + cGL_TRANSFORM_FEEDBACK_ATTRIBS_NV: GL_TRANSFORM_FEEDBACK_ATTRIBS_NV, + cGL_ACTIVE_STENCIL_FACE_EXT: GL_ACTIVE_STENCIL_FACE_EXT, + cGL_DEPTH_FUNC: GL_DEPTH_FUNC, + cGL_SAMPLE_MASK_SGIS: GL_SAMPLE_MASK_SGIS +].} diff --git a/tests/deps/opengl-1.1.0/opengl.nimble b/tests/deps/opengl-1.1.0/opengl.nimble new file mode 100644 index 000000000..ac3b8aa32 --- /dev/null +++ b/tests/deps/opengl-1.1.0/opengl.nimble @@ -0,0 +1,12 @@ +# Package + +version = "1.1.0" +author = "Andreas Rumpf" +description = "an OpenGL wrapper" +license = "MIT" + +srcDir = "src" + +# Dependencies" + +requires "nim >= 0.10.3", "x11" diff --git a/tests/deps/opengl-1.1.0/wingl.nim b/tests/deps/opengl-1.1.0/wingl.nim new file mode 100644 index 000000000..9497bffb4 --- /dev/null +++ b/tests/deps/opengl-1.1.0/wingl.nim @@ -0,0 +1,369 @@ +import opengl, windows + +{.deadCodeElim: on.} + +proc wglGetExtensionsStringARB*(hdc: HDC): cstring{.dynlib: dllname, + importc: "wglGetExtensionsStringARB".} +const + WGL_FRONT_COLOR_BUFFER_BIT_ARB* = 0x00000001 + WGL_BACK_COLOR_BUFFER_BIT_ARB* = 0x00000002 + WGL_DEPTH_BUFFER_BIT_ARB* = 0x00000004 + WGL_STENCIL_BUFFER_BIT_ARB* = 0x00000008 + +proc WinChoosePixelFormat*(DC: HDC, p2: PPixelFormatDescriptor): int{. + dynlib: "gdi32", importc: "ChoosePixelFormat".} +proc wglCreateBufferRegionARB*(hDC: HDC, iLayerPlane: TGLint, uType: TGLuint): THandle{. + dynlib: dllname, importc: "wglCreateBufferRegionARB".} +proc wglDeleteBufferRegionARB*(hRegion: THandle){.dynlib: dllname, + importc: "wglDeleteBufferRegionARB".} +proc wglSaveBufferRegionARB*(hRegion: THandle, x: TGLint, y: TGLint, + width: TGLint, height: TGLint): BOOL{. + dynlib: dllname, importc: "wglSaveBufferRegionARB".} +proc wglRestoreBufferRegionARB*(hRegion: THandle, x: TGLint, y: TGLint, + width: TGLint, height: TGLint, xSrc: TGLint, + ySrc: TGLint): BOOL{.dynlib: dllname, + importc: "wglRestoreBufferRegionARB".} +proc wglAllocateMemoryNV*(size: TGLsizei, readFrequency: TGLfloat, + writeFrequency: TGLfloat, priority: TGLfloat): PGLvoid{. + dynlib: dllname, importc: "wglAllocateMemoryNV".} +proc wglFreeMemoryNV*(pointer: PGLvoid){.dynlib: dllname, + importc: "wglFreeMemoryNV".} +const + WGL_IMAGE_BUFFER_MIN_ACCESS_I3D* = 0x00000001 + WGL_IMAGE_BUFFER_LOCK_I3D* = 0x00000002 + +proc wglCreateImageBufferI3D*(hDC: HDC, dwSize: DWORD, uFlags: UINT): PGLvoid{. + dynlib: dllname, importc: "wglCreateImageBufferI3D".} +proc wglDestroyImageBufferI3D*(hDC: HDC, pAddress: PGLvoid): BOOL{. + dynlib: dllname, importc: "wglDestroyImageBufferI3D".} +proc wglAssociateImageBufferEventsI3D*(hdc: HDC, pEvent: PHandle, + pAddress: PGLvoid, pSize: PDWORD, + count: UINT): BOOL{.dynlib: dllname, + importc: "wglAssociateImageBufferEventsI3D".} +proc wglReleaseImageBufferEventsI3D*(hdc: HDC, pAddress: PGLvoid, count: UINT): BOOL{. + dynlib: dllname, importc: "wglReleaseImageBufferEventsI3D".} +proc wglEnableFrameLockI3D*(): BOOL{.dynlib: dllname, + importc: "wglEnableFrameLockI3D".} +proc wglDisableFrameLockI3D*(): BOOL{.dynlib: dllname, + importc: "wglDisableFrameLockI3D".} +proc wglIsEnabledFrameLockI3D*(pFlag: PBOOL): BOOL{.dynlib: dllname, + importc: "wglIsEnabledFrameLockI3D".} +proc wglQueryFrameLockMasterI3D*(pFlag: PBOOL): BOOL{.dynlib: dllname, + importc: "wglQueryFrameLockMasterI3D".} +proc wglGetFrameUsageI3D*(pUsage: PGLfloat): BOOL{.dynlib: dllname, + importc: "wglGetFrameUsageI3D".} +proc wglBeginFrameTrackingI3D*(): BOOL{.dynlib: dllname, + importc: "wglBeginFrameTrackingI3D".} +proc wglEndFrameTrackingI3D*(): BOOL{.dynlib: dllname, + importc: "wglEndFrameTrackingI3D".} +proc wglQueryFrameTrackingI3D*(pFrameCount: PDWORD, pMissedFrames: PDWORD, + pLastMissedUsage: PGLfloat): BOOL{. + dynlib: dllname, importc: "wglQueryFrameTrackingI3D".} +const + WGL_NUMBER_PIXEL_FORMATS_ARB* = 0x00002000 + WGL_DRAW_TO_WINDOW_ARB* = 0x00002001 + WGL_DRAW_TO_BITMAP_ARB* = 0x00002002 + WGL_ACCELERATION_ARB* = 0x00002003 + WGL_NEED_PALETTE_ARB* = 0x00002004 + WGL_NEED_SYSTEM_PALETTE_ARB* = 0x00002005 + WGL_SWAP_LAYER_BUFFERS_ARB* = 0x00002006 + WGL_SWAP_METHOD_ARB* = 0x00002007 + WGL_NUMBER_OVERLAYS_ARB* = 0x00002008 + WGL_NUMBER_UNDERLAYS_ARB* = 0x00002009 + WGL_TRANSPARENT_ARB* = 0x0000200A + WGL_TRANSPARENT_RED_VALUE_ARB* = 0x00002037 + WGL_TRANSPARENT_GREEN_VALUE_ARB* = 0x00002038 + WGL_TRANSPARENT_BLUE_VALUE_ARB* = 0x00002039 + WGL_TRANSPARENT_ALPHA_VALUE_ARB* = 0x0000203A + WGL_TRANSPARENT_INDEX_VALUE_ARB* = 0x0000203B + WGL_SHARE_DEPTH_ARB* = 0x0000200C + WGL_SHARE_STENCIL_ARB* = 0x0000200D + WGL_SHARE_ACCUM_ARB* = 0x0000200E + WGL_SUPPORT_GDI_ARB* = 0x0000200F + WGL_SUPPORT_OPENGL_ARB* = 0x00002010 + WGL_DOUBLE_BUFFER_ARB* = 0x00002011 + WGL_STEREO_ARB* = 0x00002012 + WGL_PIXEL_TYPE_ARB* = 0x00002013 + WGL_COLOR_BITS_ARB* = 0x00002014 + WGL_RED_BITS_ARB* = 0x00002015 + WGL_RED_SHIFT_ARB* = 0x00002016 + WGL_GREEN_BITS_ARB* = 0x00002017 + WGL_GREEN_SHIFT_ARB* = 0x00002018 + WGL_BLUE_BITS_ARB* = 0x00002019 + WGL_BLUE_SHIFT_ARB* = 0x0000201A + WGL_ALPHA_BITS_ARB* = 0x0000201B + WGL_ALPHA_SHIFT_ARB* = 0x0000201C + WGL_ACCUM_BITS_ARB* = 0x0000201D + WGL_ACCUM_RED_BITS_ARB* = 0x0000201E + WGL_ACCUM_GREEN_BITS_ARB* = 0x0000201F + WGL_ACCUM_BLUE_BITS_ARB* = 0x00002020 + WGL_ACCUM_ALPHA_BITS_ARB* = 0x00002021 + WGL_DEPTH_BITS_ARB* = 0x00002022 + WGL_STENCIL_BITS_ARB* = 0x00002023 + WGL_AUX_BUFFERS_ARB* = 0x00002024 + WGL_NO_ACCELERATION_ARB* = 0x00002025 + WGL_GENERIC_ACCELERATION_ARB* = 0x00002026 + WGL_FULL_ACCELERATION_ARB* = 0x00002027 + WGL_SWAP_EXCHANGE_ARB* = 0x00002028 + WGL_SWAP_COPY_ARB* = 0x00002029 + WGL_SWAP_UNDEFINED_ARB* = 0x0000202A + WGL_TYPE_RGBA_ARB* = 0x0000202B + WGL_TYPE_COLORINDEX_ARB* = 0x0000202C + +proc wglGetPixelFormatAttribivARB*(hdc: HDC, iPixelFormat: TGLint, + iLayerPlane: TGLint, nAttributes: TGLuint, + piAttributes: PGLint, piValues: PGLint): BOOL{. + dynlib: dllname, importc: "wglGetPixelFormatAttribivARB".} +proc wglGetPixelFormatAttribfvARB*(hdc: HDC, iPixelFormat: TGLint, + iLayerPlane: TGLint, nAttributes: TGLuint, + piAttributes: PGLint, pfValues: PGLfloat): BOOL{. + dynlib: dllname, importc: "wglGetPixelFormatAttribfvARB".} +proc wglChoosePixelFormatARB*(hdc: HDC, piAttribIList: PGLint, + pfAttribFList: PGLfloat, nMaxFormats: TGLuint, + piFormats: PGLint, nNumFormats: PGLuint): BOOL{. + dynlib: dllname, importc: "wglChoosePixelFormatARB".} +const + WGL_ERROR_INVALID_PIXEL_TYPE_ARB* = 0x00002043 + WGL_ERROR_INCOMPATIBLE_DEVICE_CONTEXTS_ARB* = 0x00002054 + +proc wglMakeContextCurrentARB*(hDrawDC: HDC, hReadDC: HDC, hglrc: HGLRC): BOOL{. + dynlib: dllname, importc: "wglMakeContextCurrentARB".} +proc wglGetCurrentReadDCARB*(): HDC{.dynlib: dllname, + importc: "wglGetCurrentReadDCARB".} +const + WGL_DRAW_TO_PBUFFER_ARB* = 0x0000202D # WGL_DRAW_TO_PBUFFER_ARB { already defined } + WGL_MAX_PBUFFER_PIXELS_ARB* = 0x0000202E + WGL_MAX_PBUFFER_WIDTH_ARB* = 0x0000202F + WGL_MAX_PBUFFER_HEIGHT_ARB* = 0x00002030 + WGL_PBUFFER_LARGEST_ARB* = 0x00002033 + WGL_PBUFFER_WIDTH_ARB* = 0x00002034 + WGL_PBUFFER_HEIGHT_ARB* = 0x00002035 + WGL_PBUFFER_LOST_ARB* = 0x00002036 + +proc wglCreatePbufferARB*(hDC: HDC, iPixelFormat: TGLint, iWidth: TGLint, + iHeight: TGLint, piAttribList: PGLint): THandle{. + dynlib: dllname, importc: "wglCreatePbufferARB".} +proc wglGetPbufferDCARB*(hPbuffer: THandle): HDC{.dynlib: dllname, + importc: "wglGetPbufferDCARB".} +proc wglReleasePbufferDCARB*(hPbuffer: THandle, hDC: HDC): TGLint{. + dynlib: dllname, importc: "wglReleasePbufferDCARB".} +proc wglDestroyPbufferARB*(hPbuffer: THandle): BOOL{.dynlib: dllname, + importc: "wglDestroyPbufferARB".} +proc wglQueryPbufferARB*(hPbuffer: THandle, iAttribute: TGLint, piValue: PGLint): BOOL{. + dynlib: dllname, importc: "wglQueryPbufferARB".} +proc wglSwapIntervalEXT*(interval: TGLint): BOOL{.dynlib: dllname, + importc: "wglSwapIntervalEXT".} +proc wglGetSwapIntervalEXT*(): TGLint{.dynlib: dllname, + importc: "wglGetSwapIntervalEXT".} +const + WGL_BIND_TO_TEXTURE_RGB_ARB* = 0x00002070 + WGL_BIND_TO_TEXTURE_RGBA_ARB* = 0x00002071 + WGL_TEXTURE_FORMAT_ARB* = 0x00002072 + WGL_TEXTURE_TARGET_ARB* = 0x00002073 + WGL_MIPMAP_TEXTURE_ARB* = 0x00002074 + WGL_TEXTURE_RGB_ARB* = 0x00002075 + WGL_TEXTURE_RGBA_ARB* = 0x00002076 + WGL_NO_TEXTURE_ARB* = 0x00002077 + WGL_TEXTURE_CUBE_MAP_ARB* = 0x00002078 + WGL_TEXTURE_1D_ARB* = 0x00002079 + WGL_TEXTURE_2D_ARB* = 0x0000207A # WGL_NO_TEXTURE_ARB { already defined } + WGL_MIPMAP_LEVEL_ARB* = 0x0000207B + WGL_CUBE_MAP_FACE_ARB* = 0x0000207C + WGL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB* = 0x0000207D + WGL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB* = 0x0000207E + WGL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB* = 0x0000207F + WGL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB* = 0x00002080 + WGL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB* = 0x00002081 + WGL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB* = 0x00002082 + WGL_FRONT_LEFT_ARB* = 0x00002083 + WGL_FRONT_RIGHT_ARB* = 0x00002084 + WGL_BACK_LEFT_ARB* = 0x00002085 + WGL_BACK_RIGHT_ARB* = 0x00002086 + WGL_AUX0_ARB* = 0x00002087 + WGL_AUX1_ARB* = 0x00002088 + WGL_AUX2_ARB* = 0x00002089 + WGL_AUX3_ARB* = 0x0000208A + WGL_AUX4_ARB* = 0x0000208B + WGL_AUX5_ARB* = 0x0000208C + WGL_AUX6_ARB* = 0x0000208D + WGL_AUX7_ARB* = 0x0000208E + WGL_AUX8_ARB* = 0x0000208F + WGL_AUX9_ARB* = 0x00002090 + +proc wglBindTexImageARB*(hPbuffer: THandle, iBuffer: TGLint): BOOL{. + dynlib: dllname, importc: "wglBindTexImageARB".} +proc wglReleaseTexImageARB*(hPbuffer: THandle, iBuffer: TGLint): BOOL{. + dynlib: dllname, importc: "wglReleaseTexImageARB".} +proc wglSetPbufferAttribARB*(hPbuffer: THandle, piAttribList: PGLint): BOOL{. + dynlib: dllname, importc: "wglSetPbufferAttribARB".} +proc wglGetExtensionsStringEXT*(): cstring{.dynlib: dllname, + importc: "wglGetExtensionsStringEXT".} +proc wglMakeContextCurrentEXT*(hDrawDC: HDC, hReadDC: HDC, hglrc: HGLRC): BOOL{. + dynlib: dllname, importc: "wglMakeContextCurrentEXT".} +proc wglGetCurrentReadDCEXT*(): HDC{.dynlib: dllname, + importc: "wglGetCurrentReadDCEXT".} +const + WGL_DRAW_TO_PBUFFER_EXT* = 0x0000202D + WGL_MAX_PBUFFER_PIXELS_EXT* = 0x0000202E + WGL_MAX_PBUFFER_WIDTH_EXT* = 0x0000202F + WGL_MAX_PBUFFER_HEIGHT_EXT* = 0x00002030 + WGL_OPTIMAL_PBUFFER_WIDTH_EXT* = 0x00002031 + WGL_OPTIMAL_PBUFFER_HEIGHT_EXT* = 0x00002032 + WGL_PBUFFER_LARGEST_EXT* = 0x00002033 + WGL_PBUFFER_WIDTH_EXT* = 0x00002034 + WGL_PBUFFER_HEIGHT_EXT* = 0x00002035 + +proc wglCreatePbufferEXT*(hDC: HDC, iPixelFormat: TGLint, iWidth: TGLint, + iHeight: TGLint, piAttribList: PGLint): THandle{. + dynlib: dllname, importc: "wglCreatePbufferEXT".} +proc wglGetPbufferDCEXT*(hPbuffer: THandle): HDC{.dynlib: dllname, + importc: "wglGetPbufferDCEXT".} +proc wglReleasePbufferDCEXT*(hPbuffer: THandle, hDC: HDC): TGLint{. + dynlib: dllname, importc: "wglReleasePbufferDCEXT".} +proc wglDestroyPbufferEXT*(hPbuffer: THandle): BOOL{.dynlib: dllname, + importc: "wglDestroyPbufferEXT".} +proc wglQueryPbufferEXT*(hPbuffer: THandle, iAttribute: TGLint, piValue: PGLint): BOOL{. + dynlib: dllname, importc: "wglQueryPbufferEXT".} +const + WGL_NUMBER_PIXEL_FORMATS_EXT* = 0x00002000 + WGL_DRAW_TO_WINDOW_EXT* = 0x00002001 + WGL_DRAW_TO_BITMAP_EXT* = 0x00002002 + WGL_ACCELERATION_EXT* = 0x00002003 + WGL_NEED_PALETTE_EXT* = 0x00002004 + WGL_NEED_SYSTEM_PALETTE_EXT* = 0x00002005 + WGL_SWAP_LAYER_BUFFERS_EXT* = 0x00002006 + WGL_SWAP_METHOD_EXT* = 0x00002007 + WGL_NUMBER_OVERLAYS_EXT* = 0x00002008 + WGL_NUMBER_UNDERLAYS_EXT* = 0x00002009 + WGL_TRANSPARENT_EXT* = 0x0000200A + WGL_TRANSPARENT_VALUE_EXT* = 0x0000200B + WGL_SHARE_DEPTH_EXT* = 0x0000200C + WGL_SHARE_STENCIL_EXT* = 0x0000200D + WGL_SHARE_ACCUM_EXT* = 0x0000200E + WGL_SUPPORT_GDI_EXT* = 0x0000200F + WGL_SUPPORT_OPENGL_EXT* = 0x00002010 + WGL_DOUBLE_BUFFER_EXT* = 0x00002011 + WGL_STEREO_EXT* = 0x00002012 + WGL_PIXEL_TYPE_EXT* = 0x00002013 + WGL_COLOR_BITS_EXT* = 0x00002014 + WGL_RED_BITS_EXT* = 0x00002015 + WGL_RED_SHIFT_EXT* = 0x00002016 + WGL_GREEN_BITS_EXT* = 0x00002017 + WGL_GREEN_SHIFT_EXT* = 0x00002018 + WGL_BLUE_BITS_EXT* = 0x00002019 + WGL_BLUE_SHIFT_EXT* = 0x0000201A + WGL_ALPHA_BITS_EXT* = 0x0000201B + WGL_ALPHA_SHIFT_EXT* = 0x0000201C + WGL_ACCUM_BITS_EXT* = 0x0000201D + WGL_ACCUM_RED_BITS_EXT* = 0x0000201E + WGL_ACCUM_GREEN_BITS_EXT* = 0x0000201F + WGL_ACCUM_BLUE_BITS_EXT* = 0x00002020 + WGL_ACCUM_ALPHA_BITS_EXT* = 0x00002021 + WGL_DEPTH_BITS_EXT* = 0x00002022 + WGL_STENCIL_BITS_EXT* = 0x00002023 + WGL_AUX_BUFFERS_EXT* = 0x00002024 + WGL_NO_ACCELERATION_EXT* = 0x00002025 + WGL_GENERIC_ACCELERATION_EXT* = 0x00002026 + WGL_FULL_ACCELERATION_EXT* = 0x00002027 + WGL_SWAP_EXCHANGE_EXT* = 0x00002028 + WGL_SWAP_COPY_EXT* = 0x00002029 + WGL_SWAP_UNDEFINED_EXT* = 0x0000202A + WGL_TYPE_RGBA_EXT* = 0x0000202B + WGL_TYPE_COLORINDEX_EXT* = 0x0000202C + +proc wglGetPixelFormatAttribivEXT*(hdc: HDC, iPixelFormat: TGLint, + iLayerPlane: TGLint, nAttributes: TGLuint, + piAttributes: PGLint, piValues: PGLint): BOOL{. + dynlib: dllname, importc: "wglGetPixelFormatAttribivEXT".} +proc wglGetPixelFormatAttribfvEXT*(hdc: HDC, iPixelFormat: TGLint, + iLayerPlane: TGLint, nAttributes: TGLuint, + piAttributes: PGLint, pfValues: PGLfloat): BOOL{. + dynlib: dllname, importc: "wglGetPixelFormatAttribfvEXT".} +proc wglChoosePixelFormatEXT*(hdc: HDC, piAttribIList: PGLint, + pfAttribFList: PGLfloat, nMaxFormats: TGLuint, + piFormats: PGLint, nNumFormats: PGLuint): BOOL{. + dynlib: dllname, importc: "wglChoosePixelFormatEXT".} +const + WGL_DIGITAL_VIDEO_CURSOR_ALPHA_FRAMEBUFFER_I3D* = 0x00002050 + WGL_DIGITAL_VIDEO_CURSOR_ALPHA_VALUE_I3D* = 0x00002051 + WGL_DIGITAL_VIDEO_CURSOR_INCLUDED_I3D* = 0x00002052 + WGL_DIGITAL_VIDEO_GAMMA_CORRECTED_I3D* = 0x00002053 + +proc wglGetDigitalVideoParametersI3D*(hDC: HDC, iAttribute: TGLint, + piValue: PGLint): BOOL{.dynlib: dllname, + importc: "wglGetDigitalVideoParametersI3D".} +proc wglSetDigitalVideoParametersI3D*(hDC: HDC, iAttribute: TGLint, + piValue: PGLint): BOOL{.dynlib: dllname, + importc: "wglSetDigitalVideoParametersI3D".} +const + WGL_GAMMA_TABLE_SIZE_I3D* = 0x0000204E + WGL_GAMMA_EXCLUDE_DESKTOP_I3D* = 0x0000204F + +proc wglGetGammaTableParametersI3D*(hDC: HDC, iAttribute: TGLint, + piValue: PGLint): BOOL{.dynlib: dllname, + importc: "wglGetGammaTableParametersI3D".} +proc wglSetGammaTableParametersI3D*(hDC: HDC, iAttribute: TGLint, + piValue: PGLint): BOOL{.dynlib: dllname, + importc: "wglSetGammaTableParametersI3D".} +proc wglGetGammaTableI3D*(hDC: HDC, iEntries: TGLint, puRed: PGLUSHORT, + puGreen: PGLUSHORT, puBlue: PGLUSHORT): BOOL{. + dynlib: dllname, importc: "wglGetGammaTableI3D".} +proc wglSetGammaTableI3D*(hDC: HDC, iEntries: TGLint, puRed: PGLUSHORT, + puGreen: PGLUSHORT, puBlue: PGLUSHORT): BOOL{. + dynlib: dllname, importc: "wglSetGammaTableI3D".} +const + WGL_GENLOCK_SOURCE_MULTIVIEW_I3D* = 0x00002044 + WGL_GENLOCK_SOURCE_EXTERNAL_SYNC_I3D* = 0x00002045 + WGL_GENLOCK_SOURCE_EXTERNAL_FIELD_I3D* = 0x00002046 + WGL_GENLOCK_SOURCE_EXTERNAL_TTL_I3D* = 0x00002047 + WGL_GENLOCK_SOURCE_DIGITAL_SYNC_I3D* = 0x00002048 + WGL_GENLOCK_SOURCE_DIGITAL_FIELD_I3D* = 0x00002049 + WGL_GENLOCK_SOURCE_EDGE_FALLING_I3D* = 0x0000204A + WGL_GENLOCK_SOURCE_EDGE_RISING_I3D* = 0x0000204B + WGL_GENLOCK_SOURCE_EDGE_BOTH_I3D* = 0x0000204C + WGL_FLOAT_COMPONENTS_NV* = 0x000020B0 + WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_R_NV* = 0x000020B1 + WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_RG_NV* = 0x000020B2 + WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_RGB_NV* = 0x000020B3 + WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_RGBA_NV* = 0x000020B4 + WGL_TEXTURE_FLOAT_R_NV* = 0x000020B5 + WGL_TEXTURE_FLOAT_RG_NV* = 0x000020B6 + WGL_TEXTURE_FLOAT_RGB_NV* = 0x000020B7 + WGL_TEXTURE_FLOAT_RGBA_NV* = 0x000020B8 + +proc wglEnableGenlockI3D*(hDC: HDC): BOOL{.dynlib: dllname, + importc: "wglEnableGenlockI3D".} +proc wglDisableGenlockI3D*(hDC: HDC): BOOL{.dynlib: dllname, + importc: "wglDisableGenlockI3D".} +proc wglIsEnabledGenlockI3D*(hDC: HDC, pFlag: PBOOL): BOOL{.dynlib: dllname, + importc: "wglIsEnabledGenlockI3D".} +proc wglGenlockSourceI3D*(hDC: HDC, uSource: TGLuint): BOOL{.dynlib: dllname, + importc: "wglGenlockSourceI3D".} +proc wglGetGenlockSourceI3D*(hDC: HDC, uSource: PGLUINT): BOOL{.dynlib: dllname, + importc: "wglGetGenlockSourceI3D".} +proc wglGenlockSourceEdgeI3D*(hDC: HDC, uEdge: TGLuint): BOOL{.dynlib: dllname, + importc: "wglGenlockSourceEdgeI3D".} +proc wglGetGenlockSourceEdgeI3D*(hDC: HDC, uEdge: PGLUINT): BOOL{. + dynlib: dllname, importc: "wglGetGenlockSourceEdgeI3D".} +proc wglGenlockSampleRateI3D*(hDC: HDC, uRate: TGLuint): BOOL{.dynlib: dllname, + importc: "wglGenlockSampleRateI3D".} +proc wglGetGenlockSampleRateI3D*(hDC: HDC, uRate: PGLUINT): BOOL{. + dynlib: dllname, importc: "wglGetGenlockSampleRateI3D".} +proc wglGenlockSourceDelayI3D*(hDC: HDC, uDelay: TGLuint): BOOL{. + dynlib: dllname, importc: "wglGenlockSourceDelayI3D".} +proc wglGetGenlockSourceDelayI3D*(hDC: HDC, uDelay: PGLUINT): BOOL{. + dynlib: dllname, importc: "wglGetGenlockSourceDelayI3D".} +proc wglQueryGenlockMaxSourceDelayI3D*(hDC: HDC, uMaxLineDelay: PGLUINT, + uMaxPixelDelay: PGLUINT): BOOL{. + dynlib: dllname, importc: "wglQueryGenlockMaxSourceDelayI3D".} +const + WGL_BIND_TO_TEXTURE_RECTANGLE_RGB_NV* = 0x000020A0 + WGL_BIND_TO_TEXTURE_RECTANGLE_RGBA_NV* = 0x000020A1 + WGL_TEXTURE_RECTANGLE_NV* = 0x000020A2 + +const + WGL_RGBA_FLOAT_MODE_ATI* = 0x00008820 + WGL_COLOR_CLEAR_UNCLAMPED_VALUE_ATI* = 0x00008835 + WGL_TYPE_RGBA_FLOAT_ATI* = 0x000021A0 + +# implementation diff --git a/tests/deps/x11-1.0/cursorfont.nim b/tests/deps/x11-1.0/cursorfont.nim new file mode 100644 index 000000000..b262ad7c1 --- /dev/null +++ b/tests/deps/x11-1.0/cursorfont.nim @@ -0,0 +1,110 @@ +# $Xorg: cursorfont.h,v 1.4 2001/02/09 02:03:39 xorgcvs Exp $ +# +# +#Copyright 1987, 1998 The Open Group +# +#Permission to use, copy, modify, distribute, and sell this software and its +#documentation for any purpose is hereby granted without fee, provided that +#the above copyright notice appear in all copies and that both that +#copyright notice and this permission notice appear in supporting +#documentation. +# +#The above copyright notice and this permission notice shall be included +#in all copies or substantial portions of the Software. +# +#THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +#OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +#MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +#IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR +#OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +#ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +#OTHER DEALINGS IN THE SOFTWARE. +# +#Except as contained in this notice, the name of The Open Group shall +#not be used in advertising or otherwise to promote the sale, use or +#other dealings in this Software without prior written authorization +#from The Open Group. +# +# + +const + XC_num_glyphs* = 154 + XC_X_cursor* = 0 + XC_arrow* = 2 + XC_based_arrow_down* = 4 + XC_based_arrow_up* = 6 + XC_boat* = 8 + XC_bogosity* = 10 + XC_bottom_left_corner* = 12 + XC_bottom_right_corner* = 14 + XC_bottom_side* = 16 + XC_bottom_tee* = 18 + XC_box_spiral* = 20 + XC_center_ptr* = 22 + XC_circle* = 24 + XC_clock* = 26 + XC_coffee_mug* = 28 + XC_cross* = 30 + XC_cross_reverse* = 32 + XC_crosshair* = 34 + XC_diamond_cross* = 36 + XC_dot* = 38 + XC_dotbox* = 40 + XC_double_arrow* = 42 + XC_draft_large* = 44 + XC_draft_small* = 46 + XC_draped_box* = 48 + XC_exchange* = 50 + XC_fleur* = 52 + XC_gobbler* = 54 + XC_gumby* = 56 + XC_hand1* = 58 + XC_hand2* = 60 + XC_heart* = 62 + XC_icon* = 64 + XC_iron_cross* = 66 + XC_left_ptr* = 68 + XC_left_side* = 70 + XC_left_tee* = 72 + XC_leftbutton* = 74 + XC_ll_angle* = 76 + XC_lr_angle* = 78 + XC_man* = 80 + XC_middlebutton* = 82 + XC_mouse* = 84 + XC_pencil* = 86 + XC_pirate* = 88 + XC_plus* = 90 + XC_question_arrow* = 92 + XC_right_ptr* = 94 + XC_right_side* = 96 + XC_right_tee* = 98 + XC_rightbutton* = 100 + XC_rtl_logo* = 102 + XC_sailboat* = 104 + XC_sb_down_arrow* = 106 + XC_sb_h_double_arrow* = 108 + XC_sb_left_arrow* = 110 + XC_sb_right_arrow* = 112 + XC_sb_up_arrow* = 114 + XC_sb_v_double_arrow* = 116 + XC_shuttle* = 118 + XC_sizing* = 120 + XC_spider* = 122 + XC_spraycan* = 124 + XC_star* = 126 + XC_target* = 128 + XC_tcross* = 130 + XC_top_left_arrow* = 132 + XC_top_left_corner* = 134 + XC_top_right_corner* = 136 + XC_top_side* = 138 + XC_top_tee* = 140 + XC_trek* = 142 + XC_ul_angle* = 144 + XC_umbrella* = 146 + XC_ur_angle* = 148 + XC_watch* = 150 + XC_xterm* = 152 + +# implementation diff --git a/tests/deps/x11-1.0/keysym.nim b/tests/deps/x11-1.0/keysym.nim new file mode 100644 index 000000000..c001ab622 --- /dev/null +++ b/tests/deps/x11-1.0/keysym.nim @@ -0,0 +1,1926 @@ +# +#Converted from X11/keysym.h and X11/keysymdef.h +# +#Capital letter consts renamed from XK_... to XKc_... +# (since Pascal isn't case-sensitive) +# +#i.e. +#C Pascal +#XK_a XK_a +#XK_A XKc_A +# + +#* default keysyms * +import x + +const + XK_VoidSymbol*: TKeySym = 0x00FFFFFF # void symbol + +when defined(XK_MISCELLANY) or true: + const + #* + # * TTY Functions, cleverly chosen to map to ascii, for convenience of + # * programming, but could have been arbitrary (at the cost of lookup + # * tables in client code. + # * + XK_BackSpace*: TKeySym = 0x0000FF08 # back space, back char + XK_Tab*: TKeySym = 0x0000FF09 + XK_Linefeed*: TKeySym = 0x0000FF0A # Linefeed, LF + XK_Clear*: TKeySym = 0x0000FF0B + XK_Return*: TKeySym = 0x0000FF0D # Return, enter + XK_Pause*: TKeySym = 0x0000FF13 # Pause, hold + XK_Scroll_Lock*: TKeySym = 0x0000FF14 + XK_Sys_Req*: TKeySym = 0x0000FF15 + XK_Escape*: TKeySym = 0x0000FF1B + XK_Delete*: TKeySym = 0x0000FFFF # Delete, rubout \ + # International & multi-key character composition + XK_Multi_key*: TKeySym = 0x0000FF20 # Multi-key character compose + XK_Codeinput*: TKeySym = 0x0000FF37 + XK_SingleCandidate*: TKeySym = 0x0000FF3C + XK_MultipleCandidate*: TKeySym = 0x0000FF3D + XK_PreviousCandidate*: TKeySym = 0x0000FF3E # Japanese keyboard support + XK_Kanji*: TKeySym = 0x0000FF21 # Kanji, Kanji convert + XK_Muhenkan*: TKeySym = 0x0000FF22 # Cancel Conversion + XK_Henkan_Mode*: TKeySym = 0x0000FF23 # Start/Stop Conversion + XK_Henkan*: TKeySym = 0x0000FF23 # Alias for Henkan_Mode + XK_Romaji*: TKeySym = 0x0000FF24 # to Romaji + XK_Hiragana*: TKeySym = 0x0000FF25 # to Hiragana + XK_Katakana*: TKeySym = 0x0000FF26 # to Katakana + XK_Hiragana_Katakana*: TKeySym = 0x0000FF27 # Hiragana/Katakana toggle + XK_Zenkaku*: TKeySym = 0x0000FF28 # to Zenkaku + XK_Hankaku*: TKeySym = 0x0000FF29 # to Hankaku + XK_Zenkaku_Hankaku*: TKeySym = 0x0000FF2A # Zenkaku/Hankaku toggle + XK_Touroku*: TKeySym = 0x0000FF2B # Add to Dictionary + XK_Massyo*: TKeySym = 0x0000FF2C # Delete from Dictionary + XK_Kana_Lock*: TKeySym = 0x0000FF2D # Kana Lock + XK_Kana_Shift*: TKeySym = 0x0000FF2E # Kana Shift + XK_Eisu_Shift*: TKeySym = 0x0000FF2F # Alphanumeric Shift + XK_Eisu_toggle*: TKeySym = 0x0000FF30 # Alphanumeric toggle + XK_Kanji_Bangou*: TKeySym = 0x0000FF37 # Codeinput + XK_Zen_Koho*: TKeySym = 0x0000FF3D # Multiple/All Candidate(s) + XK_Mae_Koho*: TKeySym = 0x0000FF3E # Previous Candidate \ + # = $FF31 thru = $FF3F are under XK_KOREAN + # Cursor control & motion + XK_Home*: TKeySym = 0x0000FF50 + XK_Left*: TKeySym = 0x0000FF51 # Move left, left arrow + XK_Up*: TKeySym = 0x0000FF52 # Move up, up arrow + XK_Right*: TKeySym = 0x0000FF53 # Move right, right arrow + XK_Down*: TKeySym = 0x0000FF54 # Move down, down arrow + XK_Prior*: TKeySym = 0x0000FF55 # Prior, previous + XK_Page_Up*: TKeySym = 0x0000FF55 + XK_Next*: TKeySym = 0x0000FF56 # Next + XK_Page_Down*: TKeySym = 0x0000FF56 + XK_End*: TKeySym = 0x0000FF57 # EOL + XK_Begin*: TKeySym = 0x0000FF58 # BOL \ + # Misc Functions + XK_Select*: TKeySym = 0x0000FF60 # Select, mark + XK_Print*: TKeySym = 0x0000FF61 + XK_Execute*: TKeySym = 0x0000FF62 # Execute, run, do + XK_Insert*: TKeySym = 0x0000FF63 # Insert, insert here + XK_Undo*: TKeySym = 0x0000FF65 # Undo, oops + XK_Redo*: TKeySym = 0x0000FF66 # redo, again + XK_Menu*: TKeySym = 0x0000FF67 + XK_Find*: TKeySym = 0x0000FF68 # Find, search + XK_Cancel*: TKeySym = 0x0000FF69 # Cancel, stop, abort, exit + XK_Help*: TKeySym = 0x0000FF6A # Help + XK_Break*: TKeySym = 0x0000FF6B + XK_Mode_switch*: TKeySym = 0x0000FF7E # Character set switch + XK_script_switch*: TKeySym = 0x0000FF7E # Alias for mode_switch + XK_Num_Lock*: TKeySym = 0x0000FF7F # Keypad Functions, keypad numbers cleverly chosen to map to ascii + XK_KP_Space*: TKeySym = 0x0000FF80 # space + XK_KP_Tab*: TKeySym = 0x0000FF89 + XK_KP_Enter*: TKeySym = 0x0000FF8D # enter + XK_KP_F1*: TKeySym = 0x0000FF91 # PF1, KP_A, ... + XK_KP_F2*: TKeySym = 0x0000FF92 + XK_KP_F3*: TKeySym = 0x0000FF93 + XK_KP_F4*: TKeySym = 0x0000FF94 + XK_KP_Home*: TKeySym = 0x0000FF95 + XK_KP_Left*: TKeySym = 0x0000FF96 + XK_KP_Up*: TKeySym = 0x0000FF97 + XK_KP_Right*: TKeySym = 0x0000FF98 + XK_KP_Down*: TKeySym = 0x0000FF99 + XK_KP_Prior*: TKeySym = 0x0000FF9A + XK_KP_Page_Up*: TKeySym = 0x0000FF9A + XK_KP_Next*: TKeySym = 0x0000FF9B + XK_KP_Page_Down*: TKeySym = 0x0000FF9B + XK_KP_End*: TKeySym = 0x0000FF9C + XK_KP_Begin*: TKeySym = 0x0000FF9D + XK_KP_Insert*: TKeySym = 0x0000FF9E + XK_KP_Delete*: TKeySym = 0x0000FF9F + XK_KP_Equal*: TKeySym = 0x0000FFBD # equals + XK_KP_Multiply*: TKeySym = 0x0000FFAA + XK_KP_Add*: TKeySym = 0x0000FFAB + XK_KP_Separator*: TKeySym = 0x0000FFAC # separator, often comma + XK_KP_Subtract*: TKeySym = 0x0000FFAD + XK_KP_Decimal*: TKeySym = 0x0000FFAE + XK_KP_Divide*: TKeySym = 0x0000FFAF + XK_KP_0*: TKeySym = 0x0000FFB0 + XK_KP_1*: TKeySym = 0x0000FFB1 + XK_KP_2*: TKeySym = 0x0000FFB2 + XK_KP_3*: TKeySym = 0x0000FFB3 + XK_KP_4*: TKeySym = 0x0000FFB4 + XK_KP_5*: TKeySym = 0x0000FFB5 + XK_KP_6*: TKeySym = 0x0000FFB6 + XK_KP_7*: TKeySym = 0x0000FFB7 + XK_KP_8*: TKeySym = 0x0000FFB8 + XK_KP_9*: TKeySym = 0x0000FFB9 #*\ + # * Auxilliary Functions; note the duplicate definitions for left and right + # * function keys; Sun keyboards and a few other manufactures have such + # * function key groups on the left and/or right sides of the keyboard. + # * We've not found a keyboard with more than 35 function keys total. + # * + XK_F1*: TKeySym = 0x0000FFBE + XK_F2*: TKeySym = 0x0000FFBF + XK_F3*: TKeySym = 0x0000FFC0 + XK_F4*: TKeySym = 0x0000FFC1 + XK_F5*: TKeySym = 0x0000FFC2 + XK_F6*: TKeySym = 0x0000FFC3 + XK_F7*: TKeySym = 0x0000FFC4 + XK_F8*: TKeySym = 0x0000FFC5 + XK_F9*: TKeySym = 0x0000FFC6 + XK_F10*: TKeySym = 0x0000FFC7 + XK_F11*: TKeySym = 0x0000FFC8 + XK_L1*: TKeySym = 0x0000FFC8 + XK_F12*: TKeySym = 0x0000FFC9 + XK_L2*: TKeySym = 0x0000FFC9 + XK_F13*: TKeySym = 0x0000FFCA + XK_L3*: TKeySym = 0x0000FFCA + XK_F14*: TKeySym = 0x0000FFCB + XK_L4*: TKeySym = 0x0000FFCB + XK_F15*: TKeySym = 0x0000FFCC + XK_L5*: TKeySym = 0x0000FFCC + XK_F16*: TKeySym = 0x0000FFCD + XK_L6*: TKeySym = 0x0000FFCD + XK_F17*: TKeySym = 0x0000FFCE + XK_L7*: TKeySym = 0x0000FFCE + XK_F18*: TKeySym = 0x0000FFCF + XK_L8*: TKeySym = 0x0000FFCF + XK_F19*: TKeySym = 0x0000FFD0 + XK_L9*: TKeySym = 0x0000FFD0 + XK_F20*: TKeySym = 0x0000FFD1 + XK_L10*: TKeySym = 0x0000FFD1 + XK_F21*: TKeySym = 0x0000FFD2 + XK_R1*: TKeySym = 0x0000FFD2 + XK_F22*: TKeySym = 0x0000FFD3 + XK_R2*: TKeySym = 0x0000FFD3 + XK_F23*: TKeySym = 0x0000FFD4 + XK_R3*: TKeySym = 0x0000FFD4 + XK_F24*: TKeySym = 0x0000FFD5 + XK_R4*: TKeySym = 0x0000FFD5 + XK_F25*: TKeySym = 0x0000FFD6 + XK_R5*: TKeySym = 0x0000FFD6 + XK_F26*: TKeySym = 0x0000FFD7 + XK_R6*: TKeySym = 0x0000FFD7 + XK_F27*: TKeySym = 0x0000FFD8 + XK_R7*: TKeySym = 0x0000FFD8 + XK_F28*: TKeySym = 0x0000FFD9 + XK_R8*: TKeySym = 0x0000FFD9 + XK_F29*: TKeySym = 0x0000FFDA + XK_R9*: TKeySym = 0x0000FFDA + XK_F30*: TKeySym = 0x0000FFDB + XK_R10*: TKeySym = 0x0000FFDB + XK_F31*: TKeySym = 0x0000FFDC + XK_R11*: TKeySym = 0x0000FFDC + XK_F32*: TKeySym = 0x0000FFDD + XK_R12*: TKeySym = 0x0000FFDD + XK_F33*: TKeySym = 0x0000FFDE + XK_R13*: TKeySym = 0x0000FFDE + XK_F34*: TKeySym = 0x0000FFDF + XK_R14*: TKeySym = 0x0000FFDF + XK_F35*: TKeySym = 0x0000FFE0 + XK_R15*: TKeySym = 0x0000FFE0 # Modifiers + XK_Shift_L*: TKeySym = 0x0000FFE1 # Left shift + XK_Shift_R*: TKeySym = 0x0000FFE2 # Right shift + XK_Control_L*: TKeySym = 0x0000FFE3 # Left control + XK_Control_R*: TKeySym = 0x0000FFE4 # Right control + XK_Caps_Lock*: TKeySym = 0x0000FFE5 # Caps lock + XK_Shift_Lock*: TKeySym = 0x0000FFE6 # Shift lock + XK_Meta_L*: TKeySym = 0x0000FFE7 # Left meta + XK_Meta_R*: TKeySym = 0x0000FFE8 # Right meta + XK_Alt_L*: TKeySym = 0x0000FFE9 # Left alt + XK_Alt_R*: TKeySym = 0x0000FFEA # Right alt + XK_Super_L*: TKeySym = 0x0000FFEB # Left super + XK_Super_R*: TKeySym = 0x0000FFEC # Right super + XK_Hyper_L*: TKeySym = 0x0000FFED # Left hyper + XK_Hyper_R*: TKeySym = 0x0000FFEE # Right hyper +# XK_MISCELLANY +#* +# * ISO 9995 Function and Modifier Keys +# * Byte 3 = = $FE +# * + +when defined(XK_XKB_KEYS) or true: + const + XK_ISO_Lock*: TKeySym = 0x0000FE01 + XK_ISO_Level2_Latch*: TKeySym = 0x0000FE02 + XK_ISO_Level3_Shift*: TKeySym = 0x0000FE03 + XK_ISO_Level3_Latch*: TKeySym = 0x0000FE04 + XK_ISO_Level3_Lock*: TKeySym = 0x0000FE05 + XK_ISO_Group_Shift*: TKeySym = 0x0000FF7E # Alias for mode_switch + XK_ISO_Group_Latch*: TKeySym = 0x0000FE06 + XK_ISO_Group_Lock*: TKeySym = 0x0000FE07 + XK_ISO_Next_Group*: TKeySym = 0x0000FE08 + XK_ISO_Next_Group_Lock*: TKeySym = 0x0000FE09 + XK_ISO_Prev_Group*: TKeySym = 0x0000FE0A + XK_ISO_Prev_Group_Lock*: TKeySym = 0x0000FE0B + XK_ISO_First_Group*: TKeySym = 0x0000FE0C + XK_ISO_First_Group_Lock*: TKeySym = 0x0000FE0D + XK_ISO_Last_Group*: TKeySym = 0x0000FE0E + XK_ISO_Last_Group_Lock*: TKeySym = 0x0000FE0F + XK_ISO_Left_Tab*: TKeySym = 0x0000FE20 + XK_ISO_Move_Line_Up*: TKeySym = 0x0000FE21 + XK_ISO_Move_Line_Down*: TKeySym = 0x0000FE22 + XK_ISO_Partial_Line_Up*: TKeySym = 0x0000FE23 + XK_ISO_Partial_Line_Down*: TKeySym = 0x0000FE24 + XK_ISO_Partial_Space_Left*: TKeySym = 0x0000FE25 + XK_ISO_Partial_Space_Right*: TKeySym = 0x0000FE26 + XK_ISO_Set_Margin_Left*: TKeySym = 0x0000FE27 + XK_ISO_Set_Margin_Right*: TKeySym = 0x0000FE28 + XK_ISO_Release_Margin_Left*: TKeySym = 0x0000FE29 + XK_ISO_Release_Margin_Right*: TKeySym = 0x0000FE2A + XK_ISO_Release_Both_Margins*: TKeySym = 0x0000FE2B + XK_ISO_Fast_Cursor_Left*: TKeySym = 0x0000FE2C + XK_ISO_Fast_Cursor_Right*: TKeySym = 0x0000FE2D + XK_ISO_Fast_Cursor_Up*: TKeySym = 0x0000FE2E + XK_ISO_Fast_Cursor_Down*: TKeySym = 0x0000FE2F + XK_ISO_Continuous_Underline*: TKeySym = 0x0000FE30 + XK_ISO_Discontinuous_Underline*: TKeySym = 0x0000FE31 + XK_ISO_Emphasize*: TKeySym = 0x0000FE32 + XK_ISO_Center_Object*: TKeySym = 0x0000FE33 + XK_ISO_Enter*: TKeySym = 0x0000FE34 + XK_dead_grave*: TKeySym = 0x0000FE50 + XK_dead_acute*: TKeySym = 0x0000FE51 + XK_dead_circumflex*: TKeySym = 0x0000FE52 + XK_dead_tilde*: TKeySym = 0x0000FE53 + XK_dead_macron*: TKeySym = 0x0000FE54 + XK_dead_breve*: TKeySym = 0x0000FE55 + XK_dead_abovedot*: TKeySym = 0x0000FE56 + XK_dead_diaeresis*: TKeySym = 0x0000FE57 + XK_dead_abovering*: TKeySym = 0x0000FE58 + XK_dead_doubleacute*: TKeySym = 0x0000FE59 + XK_dead_caron*: TKeySym = 0x0000FE5A + XK_dead_cedilla*: TKeySym = 0x0000FE5B + XK_dead_ogonek*: TKeySym = 0x0000FE5C + XK_dead_iota*: TKeySym = 0x0000FE5D + XK_dead_voiced_sound*: TKeySym = 0x0000FE5E + XK_dead_semivoiced_sound*: TKeySym = 0x0000FE5F + XK_dead_belowdot*: TKeySym = 0x0000FE60 + XK_dead_hook*: TKeySym = 0x0000FE61 + XK_dead_horn*: TKeySym = 0x0000FE62 + XK_First_Virtual_Screen*: TKeySym = 0x0000FED0 + XK_Prev_Virtual_Screen*: TKeySym = 0x0000FED1 + XK_Next_Virtual_Screen*: TKeySym = 0x0000FED2 + XK_Last_Virtual_Screen*: TKeySym = 0x0000FED4 + XK_Terminate_Server*: TKeySym = 0x0000FED5 + XK_AccessX_Enable*: TKeySym = 0x0000FE70 + XK_AccessX_Feedback_Enable*: TKeySym = 0x0000FE71 + XK_RepeatKeys_Enable*: TKeySym = 0x0000FE72 + XK_SlowKeys_Enable*: TKeySym = 0x0000FE73 + XK_BounceKeys_Enable*: TKeySym = 0x0000FE74 + XK_StickyKeys_Enable*: TKeySym = 0x0000FE75 + XK_MouseKeys_Enable*: TKeySym = 0x0000FE76 + XK_MouseKeys_Accel_Enable*: TKeySym = 0x0000FE77 + XK_Overlay1_Enable*: TKeySym = 0x0000FE78 + XK_Overlay2_Enable*: TKeySym = 0x0000FE79 + XK_AudibleBell_Enable*: TKeySym = 0x0000FE7A + XK_Pointer_Left*: TKeySym = 0x0000FEE0 + XK_Pointer_Right*: TKeySym = 0x0000FEE1 + XK_Pointer_Up*: TKeySym = 0x0000FEE2 + XK_Pointer_Down*: TKeySym = 0x0000FEE3 + XK_Pointer_UpLeft*: TKeySym = 0x0000FEE4 + XK_Pointer_UpRight*: TKeySym = 0x0000FEE5 + XK_Pointer_DownLeft*: TKeySym = 0x0000FEE6 + XK_Pointer_DownRight*: TKeySym = 0x0000FEE7 + XK_Pointer_Button_Dflt*: TKeySym = 0x0000FEE8 + XK_Pointer_Button1*: TKeySym = 0x0000FEE9 + XK_Pointer_Button2*: TKeySym = 0x0000FEEA + XK_Pointer_Button3*: TKeySym = 0x0000FEEB + XK_Pointer_Button4*: TKeySym = 0x0000FEEC + XK_Pointer_Button5*: TKeySym = 0x0000FEED + XK_Pointer_DblClick_Dflt*: TKeySym = 0x0000FEEE + XK_Pointer_DblClick1*: TKeySym = 0x0000FEEF + XK_Pointer_DblClick2*: TKeySym = 0x0000FEF0 + XK_Pointer_DblClick3*: TKeySym = 0x0000FEF1 + XK_Pointer_DblClick4*: TKeySym = 0x0000FEF2 + XK_Pointer_DblClick5*: TKeySym = 0x0000FEF3 + XK_Pointer_Drag_Dflt*: TKeySym = 0x0000FEF4 + XK_Pointer_Drag1*: TKeySym = 0x0000FEF5 + XK_Pointer_Drag2*: TKeySym = 0x0000FEF6 + XK_Pointer_Drag3*: TKeySym = 0x0000FEF7 + XK_Pointer_Drag4*: TKeySym = 0x0000FEF8 + XK_Pointer_Drag5*: TKeySym = 0x0000FEFD + XK_Pointer_EnableKeys*: TKeySym = 0x0000FEF9 + XK_Pointer_Accelerate*: TKeySym = 0x0000FEFA + XK_Pointer_DfltBtnNext*: TKeySym = 0x0000FEFB + XK_Pointer_DfltBtnPrev*: TKeySym = 0x0000FEFC + #* + # * 3270 Terminal Keys + # * Byte 3 = = $FD + # * + +when defined(XK_3270) or true: + const + XK_3270_Duplicate*: TKeySym = 0x0000FD01 + XK_3270_FieldMark*: TKeySym = 0x0000FD02 + XK_3270_Right2*: TKeySym = 0x0000FD03 + XK_3270_Left2*: TKeySym = 0x0000FD04 + XK_3270_BackTab*: TKeySym = 0x0000FD05 + XK_3270_EraseEOF*: TKeySym = 0x0000FD06 + XK_3270_EraseInput*: TKeySym = 0x0000FD07 + XK_3270_Reset*: TKeySym = 0x0000FD08 + XK_3270_Quit*: TKeySym = 0x0000FD09 + XK_3270_PA1*: TKeySym = 0x0000FD0A + XK_3270_PA2*: TKeySym = 0x0000FD0B + XK_3270_PA3*: TKeySym = 0x0000FD0C + XK_3270_Test*: TKeySym = 0x0000FD0D + XK_3270_Attn*: TKeySym = 0x0000FD0E + XK_3270_CursorBlink*: TKeySym = 0x0000FD0F + XK_3270_AltCursor*: TKeySym = 0x0000FD10 + XK_3270_KeyClick*: TKeySym = 0x0000FD11 + XK_3270_Jump*: TKeySym = 0x0000FD12 + XK_3270_Ident*: TKeySym = 0x0000FD13 + XK_3270_Rule*: TKeySym = 0x0000FD14 + XK_3270_Copy*: TKeySym = 0x0000FD15 + XK_3270_Play*: TKeySym = 0x0000FD16 + XK_3270_Setup*: TKeySym = 0x0000FD17 + XK_3270_Record*: TKeySym = 0x0000FD18 + XK_3270_ChangeScreen*: TKeySym = 0x0000FD19 + XK_3270_DeleteWord*: TKeySym = 0x0000FD1A + XK_3270_ExSelect*: TKeySym = 0x0000FD1B + XK_3270_CursorSelect*: TKeySym = 0x0000FD1C + XK_3270_PrintScreen*: TKeySym = 0x0000FD1D + XK_3270_Enter*: TKeySym = 0x0000FD1E +#* +# * Latin 1 +# * Byte 3 = 0 +# * + +when defined(XK_LATIN1) or true: + const + XK_space*: TKeySym = 0x00000020 + XK_exclam*: TKeySym = 0x00000021 + XK_quotedbl*: TKeySym = 0x00000022 + XK_numbersign*: TKeySym = 0x00000023 + XK_dollar*: TKeySym = 0x00000024 + XK_percent*: TKeySym = 0x00000025 + XK_ampersand*: TKeySym = 0x00000026 + XK_apostrophe*: TKeySym = 0x00000027 + XK_quoteright*: TKeySym = 0x00000027 # deprecated + XK_parenleft*: TKeySym = 0x00000028 + XK_parenright*: TKeySym = 0x00000029 + XK_asterisk*: TKeySym = 0x0000002A + XK_plus*: TKeySym = 0x0000002B + XK_comma*: TKeySym = 0x0000002C + XK_minus*: TKeySym = 0x0000002D + XK_period*: TKeySym = 0x0000002E + XK_slash*: TKeySym = 0x0000002F + XK_0*: TKeySym = 0x00000030 + XK_1*: TKeySym = 0x00000031 + XK_2*: TKeySym = 0x00000032 + XK_3*: TKeySym = 0x00000033 + XK_4*: TKeySym = 0x00000034 + XK_5*: TKeySym = 0x00000035 + XK_6*: TKeySym = 0x00000036 + XK_7*: TKeySym = 0x00000037 + XK_8*: TKeySym = 0x00000038 + XK_9*: TKeySym = 0x00000039 + XK_colon*: TKeySym = 0x0000003A + XK_semicolon*: TKeySym = 0x0000003B + XK_less*: TKeySym = 0x0000003C + XK_equal*: TKeySym = 0x0000003D + XK_greater*: TKeySym = 0x0000003E + XK_question*: TKeySym = 0x0000003F + XK_at*: TKeySym = 0x00000040 + XKc_A*: TKeySym = 0x00000041 + XKc_B*: TKeySym = 0x00000042 + XKc_C*: TKeySym = 0x00000043 + XKc_D*: TKeySym = 0x00000044 + XKc_E*: TKeySym = 0x00000045 + XKc_F*: TKeySym = 0x00000046 + XKc_G*: TKeySym = 0x00000047 + XKc_H*: TKeySym = 0x00000048 + XKc_I*: TKeySym = 0x00000049 + XKc_J*: TKeySym = 0x0000004A + XKc_K*: TKeySym = 0x0000004B + XKc_L*: TKeySym = 0x0000004C + XKc_M*: TKeySym = 0x0000004D + XKc_N*: TKeySym = 0x0000004E + XKc_O*: TKeySym = 0x0000004F + XKc_P*: TKeySym = 0x00000050 + XKc_Q*: TKeySym = 0x00000051 + XKc_R*: TKeySym = 0x00000052 + XKc_S*: TKeySym = 0x00000053 + XKc_T*: TKeySym = 0x00000054 + XKc_U*: TKeySym = 0x00000055 + XKc_V*: TKeySym = 0x00000056 + XKc_W*: TKeySym = 0x00000057 + XKc_X*: TKeySym = 0x00000058 + XKc_Y*: TKeySym = 0x00000059 + XKc_Z*: TKeySym = 0x0000005A + XK_bracketleft*: TKeySym = 0x0000005B + XK_backslash*: TKeySym = 0x0000005C + XK_bracketright*: TKeySym = 0x0000005D + XK_asciicircum*: TKeySym = 0x0000005E + XK_underscore*: TKeySym = 0x0000005F + XK_grave*: TKeySym = 0x00000060 + XK_quoteleft*: TKeySym = 0x00000060 # deprecated + XK_a*: TKeySym = 0x00000061 + XK_b*: TKeySym = 0x00000062 + XK_c*: TKeySym = 0x00000063 + XK_d*: TKeySym = 0x00000064 + XK_e*: TKeySym = 0x00000065 + XK_f*: TKeySym = 0x00000066 + XK_g*: TKeySym = 0x00000067 + XK_h*: TKeySym = 0x00000068 + XK_i*: TKeySym = 0x00000069 + XK_j*: TKeySym = 0x0000006A + XK_k*: TKeySym = 0x0000006B + XK_l*: TKeySym = 0x0000006C + XK_m*: TKeySym = 0x0000006D + XK_n*: TKeySym = 0x0000006E + XK_o*: TKeySym = 0x0000006F + XK_p*: TKeySym = 0x00000070 + XK_q*: TKeySym = 0x00000071 + XK_r*: TKeySym = 0x00000072 + XK_s*: TKeySym = 0x00000073 + XK_t*: TKeySym = 0x00000074 + XK_u*: TKeySym = 0x00000075 + XK_v*: TKeySym = 0x00000076 + XK_w*: TKeySym = 0x00000077 + XK_x*: TKeySym = 0x00000078 + XK_y*: TKeySym = 0x00000079 + XK_z*: TKeySym = 0x0000007A + XK_braceleft*: TKeySym = 0x0000007B + XK_bar*: TKeySym = 0x0000007C + XK_braceright*: TKeySym = 0x0000007D + XK_asciitilde*: TKeySym = 0x0000007E + XK_nobreakspace*: TKeySym = 0x000000A0 + XK_exclamdown*: TKeySym = 0x000000A1 + XK_cent*: TKeySym = 0x000000A2 + XK_sterling*: TKeySym = 0x000000A3 + XK_currency*: TKeySym = 0x000000A4 + XK_yen*: TKeySym = 0x000000A5 + XK_brokenbar*: TKeySym = 0x000000A6 + XK_section*: TKeySym = 0x000000A7 + XK_diaeresis*: TKeySym = 0x000000A8 + XK_copyright*: TKeySym = 0x000000A9 + XK_ordfeminine*: TKeySym = 0x000000AA + XK_guillemotleft*: TKeySym = 0x000000AB # left angle quotation mark + XK_notsign*: TKeySym = 0x000000AC + XK_hyphen*: TKeySym = 0x000000AD + XK_registered*: TKeySym = 0x000000AE + XK_macron*: TKeySym = 0x000000AF + XK_degree*: TKeySym = 0x000000B0 + XK_plusminus*: TKeySym = 0x000000B1 + XK_twosuperior*: TKeySym = 0x000000B2 + XK_threesuperior*: TKeySym = 0x000000B3 + XK_acute*: TKeySym = 0x000000B4 + XK_mu*: TKeySym = 0x000000B5 + XK_paragraph*: TKeySym = 0x000000B6 + XK_periodcentered*: TKeySym = 0x000000B7 + XK_cedilla*: TKeySym = 0x000000B8 + XK_onesuperior*: TKeySym = 0x000000B9 + XK_masculine*: TKeySym = 0x000000BA + XK_guillemotright*: TKeySym = 0x000000BB # right angle quotation mark + XK_onequarter*: TKeySym = 0x000000BC + XK_onehalf*: TKeySym = 0x000000BD + XK_threequarters*: TKeySym = 0x000000BE + XK_questiondown*: TKeySym = 0x000000BF + XKc_Agrave*: TKeySym = 0x000000C0 + XKc_Aacute*: TKeySym = 0x000000C1 + XKc_Acircumflex*: TKeySym = 0x000000C2 + XKc_Atilde*: TKeySym = 0x000000C3 + XKc_Adiaeresis*: TKeySym = 0x000000C4 + XKc_Aring*: TKeySym = 0x000000C5 + XKc_AE*: TKeySym = 0x000000C6 + XKc_Ccedilla*: TKeySym = 0x000000C7 + XKc_Egrave*: TKeySym = 0x000000C8 + XKc_Eacute*: TKeySym = 0x000000C9 + XKc_Ecircumflex*: TKeySym = 0x000000CA + XKc_Ediaeresis*: TKeySym = 0x000000CB + XKc_Igrave*: TKeySym = 0x000000CC + XKc_Iacute*: TKeySym = 0x000000CD + XKc_Icircumflex*: TKeySym = 0x000000CE + XKc_Idiaeresis*: TKeySym = 0x000000CF + XKc_ETH*: TKeySym = 0x000000D0 + XKc_Ntilde*: TKeySym = 0x000000D1 + XKc_Ograve*: TKeySym = 0x000000D2 + XKc_Oacute*: TKeySym = 0x000000D3 + XKc_Ocircumflex*: TKeySym = 0x000000D4 + XKc_Otilde*: TKeySym = 0x000000D5 + XKc_Odiaeresis*: TKeySym = 0x000000D6 + XK_multiply*: TKeySym = 0x000000D7 + XKc_Ooblique*: TKeySym = 0x000000D8 + XKc_Oslash*: TKeySym = XKc_Ooblique + XKc_Ugrave*: TKeySym = 0x000000D9 + XKc_Uacute*: TKeySym = 0x000000DA + XKc_Ucircumflex*: TKeySym = 0x000000DB + XKc_Udiaeresis*: TKeySym = 0x000000DC + XKc_Yacute*: TKeySym = 0x000000DD + XKc_THORN*: TKeySym = 0x000000DE + XK_ssharp*: TKeySym = 0x000000DF + XK_agrave*: TKeySym = 0x000000E0 + XK_aacute*: TKeySym = 0x000000E1 + XK_acircumflex*: TKeySym = 0x000000E2 + XK_atilde*: TKeySym = 0x000000E3 + XK_adiaeresis*: TKeySym = 0x000000E4 + XK_aring*: TKeySym = 0x000000E5 + XK_ae*: TKeySym = 0x000000E6 + XK_ccedilla*: TKeySym = 0x000000E7 + XK_egrave*: TKeySym = 0x000000E8 + XK_eacute*: TKeySym = 0x000000E9 + XK_ecircumflex*: TKeySym = 0x000000EA + XK_ediaeresis*: TKeySym = 0x000000EB + XK_igrave*: TKeySym = 0x000000EC + XK_iacute*: TKeySym = 0x000000ED + XK_icircumflex*: TKeySym = 0x000000EE + XK_idiaeresis*: TKeySym = 0x000000EF + XK_eth*: TKeySym = 0x000000F0 + XK_ntilde*: TKeySym = 0x000000F1 + XK_ograve*: TKeySym = 0x000000F2 + XK_oacute*: TKeySym = 0x000000F3 + XK_ocircumflex*: TKeySym = 0x000000F4 + XK_otilde*: TKeySym = 0x000000F5 + XK_odiaeresis*: TKeySym = 0x000000F6 + XK_division*: TKeySym = 0x000000F7 + XK_oslash*: TKeySym = 0x000000F8 + XK_ooblique*: TKeySym = XK_oslash + XK_ugrave*: TKeySym = 0x000000F9 + XK_uacute*: TKeySym = 0x000000FA + XK_ucircumflex*: TKeySym = 0x000000FB + XK_udiaeresis*: TKeySym = 0x000000FC + XK_yacute*: TKeySym = 0x000000FD + XK_thorn*: TKeySym = 0x000000FE + XK_ydiaeresis*: TKeySym = 0x000000FF +# XK_LATIN1 +#* +# * Latin 2 +# * Byte 3 = 1 +# * + +when defined(XK_LATIN2) or true: + const + XKc_Aogonek*: TKeySym = 0x000001A1 + XK_breve*: TKeySym = 0x000001A2 + XKc_Lstroke*: TKeySym = 0x000001A3 + XKc_Lcaron*: TKeySym = 0x000001A5 + XKc_Sacute*: TKeySym = 0x000001A6 + XKc_Scaron*: TKeySym = 0x000001A9 + XKc_Scedilla*: TKeySym = 0x000001AA + XKc_Tcaron*: TKeySym = 0x000001AB + XKc_Zacute*: TKeySym = 0x000001AC + XKc_Zcaron*: TKeySym = 0x000001AE + XKc_Zabovedot*: TKeySym = 0x000001AF + XK_aogonek*: TKeySym = 0x000001B1 + XK_ogonek*: TKeySym = 0x000001B2 + XK_lstroke*: TKeySym = 0x000001B3 + XK_lcaron*: TKeySym = 0x000001B5 + XK_sacute*: TKeySym = 0x000001B6 + XK_caron*: TKeySym = 0x000001B7 + XK_scaron*: TKeySym = 0x000001B9 + XK_scedilla*: TKeySym = 0x000001BA + XK_tcaron*: TKeySym = 0x000001BB + XK_zacute*: TKeySym = 0x000001BC + XK_doubleacute*: TKeySym = 0x000001BD + XK_zcaron*: TKeySym = 0x000001BE + XK_zabovedot*: TKeySym = 0x000001BF + XKc_Racute*: TKeySym = 0x000001C0 + XKc_Abreve*: TKeySym = 0x000001C3 + XKc_Lacute*: TKeySym = 0x000001C5 + XKc_Cacute*: TKeySym = 0x000001C6 + XKc_Ccaron*: TKeySym = 0x000001C8 + XKc_Eogonek*: TKeySym = 0x000001CA + XKc_Ecaron*: TKeySym = 0x000001CC + XKc_Dcaron*: TKeySym = 0x000001CF + XKc_Dstroke*: TKeySym = 0x000001D0 + XKc_Nacute*: TKeySym = 0x000001D1 + XKc_Ncaron*: TKeySym = 0x000001D2 + XKc_Odoubleacute*: TKeySym = 0x000001D5 + XKc_Rcaron*: TKeySym = 0x000001D8 + XKc_Uring*: TKeySym = 0x000001D9 + XKc_Udoubleacute*: TKeySym = 0x000001DB + XKc_Tcedilla*: TKeySym = 0x000001DE + XK_racute*: TKeySym = 0x000001E0 + XK_abreve*: TKeySym = 0x000001E3 + XK_lacute*: TKeySym = 0x000001E5 + XK_cacute*: TKeySym = 0x000001E6 + XK_ccaron*: TKeySym = 0x000001E8 + XK_eogonek*: TKeySym = 0x000001EA + XK_ecaron*: TKeySym = 0x000001EC + XK_dcaron*: TKeySym = 0x000001EF + XK_dstroke*: TKeySym = 0x000001F0 + XK_nacute*: TKeySym = 0x000001F1 + XK_ncaron*: TKeySym = 0x000001F2 + XK_odoubleacute*: TKeySym = 0x000001F5 + XK_udoubleacute*: TKeySym = 0x000001FB + XK_rcaron*: TKeySym = 0x000001F8 + XK_uring*: TKeySym = 0x000001F9 + XK_tcedilla*: TKeySym = 0x000001FE + XK_abovedot*: TKeySym = 0x000001FF +# XK_LATIN2 +#* +# * Latin 3 +# * Byte 3 = 2 +# * + +when defined(XK_LATIN3) or true: + const + XKc_Hstroke*: TKeySym = 0x000002A1 + XKc_Hcircumflex*: TKeySym = 0x000002A6 + XKc_Iabovedot*: TKeySym = 0x000002A9 + XKc_Gbreve*: TKeySym = 0x000002AB + XKc_Jcircumflex*: TKeySym = 0x000002AC + XK_hstroke*: TKeySym = 0x000002B1 + XK_hcircumflex*: TKeySym = 0x000002B6 + XK_idotless*: TKeySym = 0x000002B9 + XK_gbreve*: TKeySym = 0x000002BB + XK_jcircumflex*: TKeySym = 0x000002BC + XKc_Cabovedot*: TKeySym = 0x000002C5 + XKc_Ccircumflex*: TKeySym = 0x000002C6 + XKc_Gabovedot*: TKeySym = 0x000002D5 + XKc_Gcircumflex*: TKeySym = 0x000002D8 + XKc_Ubreve*: TKeySym = 0x000002DD + XKc_Scircumflex*: TKeySym = 0x000002DE + XK_cabovedot*: TKeySym = 0x000002E5 + XK_ccircumflex*: TKeySym = 0x000002E6 + XK_gabovedot*: TKeySym = 0x000002F5 + XK_gcircumflex*: TKeySym = 0x000002F8 + XK_ubreve*: TKeySym = 0x000002FD + XK_scircumflex*: TKeySym = 0x000002FE +# XK_LATIN3 +#* +# * Latin 4 +# * Byte 3 = 3 +# * + +when defined(XK_LATIN4) or true: + const + XK_kra*: TKeySym = 0x000003A2 + XK_kappa*: TKeySym = 0x000003A2 # deprecated + XKc_Rcedilla*: TKeySym = 0x000003A3 + XKc_Itilde*: TKeySym = 0x000003A5 + XKc_Lcedilla*: TKeySym = 0x000003A6 + XKc_Emacron*: TKeySym = 0x000003AA + XKc_Gcedilla*: TKeySym = 0x000003AB + XKc_Tslash*: TKeySym = 0x000003AC + XK_rcedilla*: TKeySym = 0x000003B3 + XK_itilde*: TKeySym = 0x000003B5 + XK_lcedilla*: TKeySym = 0x000003B6 + XK_emacron*: TKeySym = 0x000003BA + XK_gcedilla*: TKeySym = 0x000003BB + XK_tslash*: TKeySym = 0x000003BC + XKc_ENG*: TKeySym = 0x000003BD + XK_eng*: TKeySym = 0x000003BF + XKc_Amacron*: TKeySym = 0x000003C0 + XKc_Iogonek*: TKeySym = 0x000003C7 + XKc_Eabovedot*: TKeySym = 0x000003CC + XKc_Imacron*: TKeySym = 0x000003CF + XKc_Ncedilla*: TKeySym = 0x000003D1 + XKc_Omacron*: TKeySym = 0x000003D2 + XKc_Kcedilla*: TKeySym = 0x000003D3 + XKc_Uogonek*: TKeySym = 0x000003D9 + XKc_Utilde*: TKeySym = 0x000003DD + XKc_Umacron*: TKeySym = 0x000003DE + XK_amacron*: TKeySym = 0x000003E0 + XK_iogonek*: TKeySym = 0x000003E7 + XK_eabovedot*: TKeySym = 0x000003EC + XK_imacron*: TKeySym = 0x000003EF + XK_ncedilla*: TKeySym = 0x000003F1 + XK_omacron*: TKeySym = 0x000003F2 + XK_kcedilla*: TKeySym = 0x000003F3 + XK_uogonek*: TKeySym = 0x000003F9 + XK_utilde*: TKeySym = 0x000003FD + XK_umacron*: TKeySym = 0x000003FE +# XK_LATIN4 +#* +# * Latin-8 +# * Byte 3 = 18 +# * + +when defined(XK_LATIN8) or true: + const + XKc_Babovedot*: TKeySym = 0x000012A1 + XK_babovedot*: TKeySym = 0x000012A2 + XKc_Dabovedot*: TKeySym = 0x000012A6 + XKc_Wgrave*: TKeySym = 0x000012A8 + XKc_Wacute*: TKeySym = 0x000012AA + XK_dabovedot*: TKeySym = 0x000012AB + XKc_Ygrave*: TKeySym = 0x000012AC + XKc_Fabovedot*: TKeySym = 0x000012B0 + XK_fabovedot*: TKeySym = 0x000012B1 + XKc_Mabovedot*: TKeySym = 0x000012B4 + XK_mabovedot*: TKeySym = 0x000012B5 + XKc_Pabovedot*: TKeySym = 0x000012B7 + XK_wgrave*: TKeySym = 0x000012B8 + XK_pabovedot*: TKeySym = 0x000012B9 + XK_wacute*: TKeySym = 0x000012BA + XKc_Sabovedot*: TKeySym = 0x000012BB + XK_ygrave*: TKeySym = 0x000012BC + XKc_Wdiaeresis*: TKeySym = 0x000012BD + XK_wdiaeresis*: TKeySym = 0x000012BE + XK_sabovedot*: TKeySym = 0x000012BF + XKc_Wcircumflex*: TKeySym = 0x000012D0 + XKc_Tabovedot*: TKeySym = 0x000012D7 + XKc_Ycircumflex*: TKeySym = 0x000012DE + XK_wcircumflex*: TKeySym = 0x000012F0 + XK_tabovedot*: TKeySym = 0x000012F7 + XK_ycircumflex*: TKeySym = 0x000012FE +# XK_LATIN8 +#* +# * Latin-9 (a.k.a. Latin-0) +# * Byte 3 = 19 +# * + +when defined(XK_LATIN9) or true: + const + XKc_OE*: TKeySym = 0x000013BC + XK_oe*: TKeySym = 0x000013BD + XKc_Ydiaeresis*: TKeySym = 0x000013BE +# XK_LATIN9 +#* +# * Katakana +# * Byte 3 = 4 +# * + +when defined(XK_KATAKANA) or true: + const + XK_overline*: TKeySym = 0x0000047E + XK_kana_fullstop*: TKeySym = 0x000004A1 + XK_kana_openingbracket*: TKeySym = 0x000004A2 + XK_kana_closingbracket*: TKeySym = 0x000004A3 + XK_kana_comma*: TKeySym = 0x000004A4 + XK_kana_conjunctive*: TKeySym = 0x000004A5 + XK_kana_middledot*: TKeySym = 0x000004A5 # deprecated + XKc_kana_WO*: TKeySym = 0x000004A6 + XK_kana_a*: TKeySym = 0x000004A7 + XK_kana_i*: TKeySym = 0x000004A8 + XK_kana_u*: TKeySym = 0x000004A9 + XK_kana_e*: TKeySym = 0x000004AA + XK_kana_o*: TKeySym = 0x000004AB + XK_kana_ya*: TKeySym = 0x000004AC + XK_kana_yu*: TKeySym = 0x000004AD + XK_kana_yo*: TKeySym = 0x000004AE + XK_kana_tsu*: TKeySym = 0x000004AF + XK_kana_tu*: TKeySym = 0x000004AF # deprecated + XK_prolongedsound*: TKeySym = 0x000004B0 + XKc_kana_A*: TKeySym = 0x000004B1 + XKc_kana_I*: TKeySym = 0x000004B2 + XKc_kana_U*: TKeySym = 0x000004B3 + XKc_kana_E*: TKeySym = 0x000004B4 + XKc_kana_O*: TKeySym = 0x000004B5 + XKc_kana_KA*: TKeySym = 0x000004B6 + XKc_kana_KI*: TKeySym = 0x000004B7 + XKc_kana_KU*: TKeySym = 0x000004B8 + XKc_kana_KE*: TKeySym = 0x000004B9 + XKc_kana_KO*: TKeySym = 0x000004BA + XKc_kana_SA*: TKeySym = 0x000004BB + XKc_kana_SHI*: TKeySym = 0x000004BC + XKc_kana_SU*: TKeySym = 0x000004BD + XKc_kana_SE*: TKeySym = 0x000004BE + XKc_kana_SO*: TKeySym = 0x000004BF + XKc_kana_TA*: TKeySym = 0x000004C0 + XKc_kana_CHI*: TKeySym = 0x000004C1 + XKc_kana_TI*: TKeySym = 0x000004C1 # deprecated + XKc_kana_TSU*: TKeySym = 0x000004C2 + XKc_kana_TU*: TKeySym = 0x000004C2 # deprecated + XKc_kana_TE*: TKeySym = 0x000004C3 + XKc_kana_TO*: TKeySym = 0x000004C4 + XKc_kana_NA*: TKeySym = 0x000004C5 + XKc_kana_NI*: TKeySym = 0x000004C6 + XKc_kana_NU*: TKeySym = 0x000004C7 + XKc_kana_NE*: TKeySym = 0x000004C8 + XKc_kana_NO*: TKeySym = 0x000004C9 + XKc_kana_HA*: TKeySym = 0x000004CA + XKc_kana_HI*: TKeySym = 0x000004CB + XKc_kana_FU*: TKeySym = 0x000004CC + XKc_kana_HU*: TKeySym = 0x000004CC # deprecated + XKc_kana_HE*: TKeySym = 0x000004CD + XKc_kana_HO*: TKeySym = 0x000004CE + XKc_kana_MA*: TKeySym = 0x000004CF + XKc_kana_MI*: TKeySym = 0x000004D0 + XKc_kana_MU*: TKeySym = 0x000004D1 + XKc_kana_ME*: TKeySym = 0x000004D2 + XKc_kana_MO*: TKeySym = 0x000004D3 + XKc_kana_YA*: TKeySym = 0x000004D4 + XKc_kana_YU*: TKeySym = 0x000004D5 + XKc_kana_YO*: TKeySym = 0x000004D6 + XKc_kana_RA*: TKeySym = 0x000004D7 + XKc_kana_RI*: TKeySym = 0x000004D8 + XKc_kana_RU*: TKeySym = 0x000004D9 + XKc_kana_RE*: TKeySym = 0x000004DA + XKc_kana_RO*: TKeySym = 0x000004DB + XKc_kana_WA*: TKeySym = 0x000004DC + XKc_kana_N*: TKeySym = 0x000004DD + XK_voicedsound*: TKeySym = 0x000004DE + XK_semivoicedsound*: TKeySym = 0x000004DF + XK_kana_switch*: TKeySym = 0x0000FF7E # Alias for mode_switch +# XK_KATAKANA +#* +# * Arabic +# * Byte 3 = 5 +# * + +when defined(XK_ARABIC) or true: + const + XK_Farsi_0*: TKeySym = 0x00000590 + XK_Farsi_1*: TKeySym = 0x00000591 + XK_Farsi_2*: TKeySym = 0x00000592 + XK_Farsi_3*: TKeySym = 0x00000593 + XK_Farsi_4*: TKeySym = 0x00000594 + XK_Farsi_5*: TKeySym = 0x00000595 + XK_Farsi_6*: TKeySym = 0x00000596 + XK_Farsi_7*: TKeySym = 0x00000597 + XK_Farsi_8*: TKeySym = 0x00000598 + XK_Farsi_9*: TKeySym = 0x00000599 + XK_Arabic_percent*: TKeySym = 0x000005A5 + XK_Arabic_superscript_alef*: TKeySym = 0x000005A6 + XK_Arabic_tteh*: TKeySym = 0x000005A7 + XK_Arabic_peh*: TKeySym = 0x000005A8 + XK_Arabic_tcheh*: TKeySym = 0x000005A9 + XK_Arabic_ddal*: TKeySym = 0x000005AA + XK_Arabic_rreh*: TKeySym = 0x000005AB + XK_Arabic_comma*: TKeySym = 0x000005AC + XK_Arabic_fullstop*: TKeySym = 0x000005AE + XK_Arabic_0*: TKeySym = 0x000005B0 + XK_Arabic_1*: TKeySym = 0x000005B1 + XK_Arabic_2*: TKeySym = 0x000005B2 + XK_Arabic_3*: TKeySym = 0x000005B3 + XK_Arabic_4*: TKeySym = 0x000005B4 + XK_Arabic_5*: TKeySym = 0x000005B5 + XK_Arabic_6*: TKeySym = 0x000005B6 + XK_Arabic_7*: TKeySym = 0x000005B7 + XK_Arabic_8*: TKeySym = 0x000005B8 + XK_Arabic_9*: TKeySym = 0x000005B9 + XK_Arabic_semicolon*: TKeySym = 0x000005BB + XK_Arabic_question_mark*: TKeySym = 0x000005BF + XK_Arabic_hamza*: TKeySym = 0x000005C1 + XK_Arabic_maddaonalef*: TKeySym = 0x000005C2 + XK_Arabic_hamzaonalef*: TKeySym = 0x000005C3 + XK_Arabic_hamzaonwaw*: TKeySym = 0x000005C4 + XK_Arabic_hamzaunderalef*: TKeySym = 0x000005C5 + XK_Arabic_hamzaonyeh*: TKeySym = 0x000005C6 + XK_Arabic_alef*: TKeySym = 0x000005C7 + XK_Arabic_beh*: TKeySym = 0x000005C8 + XK_Arabic_tehmarbuta*: TKeySym = 0x000005C9 + XK_Arabic_teh*: TKeySym = 0x000005CA + XK_Arabic_theh*: TKeySym = 0x000005CB + XK_Arabic_jeem*: TKeySym = 0x000005CC + XK_Arabic_hah*: TKeySym = 0x000005CD + XK_Arabic_khah*: TKeySym = 0x000005CE + XK_Arabic_dal*: TKeySym = 0x000005CF + XK_Arabic_thal*: TKeySym = 0x000005D0 + XK_Arabic_ra*: TKeySym = 0x000005D1 + XK_Arabic_zain*: TKeySym = 0x000005D2 + XK_Arabic_seen*: TKeySym = 0x000005D3 + XK_Arabic_sheen*: TKeySym = 0x000005D4 + XK_Arabic_sad*: TKeySym = 0x000005D5 + XK_Arabic_dad*: TKeySym = 0x000005D6 + XK_Arabic_tah*: TKeySym = 0x000005D7 + XK_Arabic_zah*: TKeySym = 0x000005D8 + XK_Arabic_ain*: TKeySym = 0x000005D9 + XK_Arabic_ghain*: TKeySym = 0x000005DA + XK_Arabic_tatweel*: TKeySym = 0x000005E0 + XK_Arabic_feh*: TKeySym = 0x000005E1 + XK_Arabic_qaf*: TKeySym = 0x000005E2 + XK_Arabic_kaf*: TKeySym = 0x000005E3 + XK_Arabic_lam*: TKeySym = 0x000005E4 + XK_Arabic_meem*: TKeySym = 0x000005E5 + XK_Arabic_noon*: TKeySym = 0x000005E6 + XK_Arabic_ha*: TKeySym = 0x000005E7 + XK_Arabic_heh*: TKeySym = 0x000005E7 # deprecated + XK_Arabic_waw*: TKeySym = 0x000005E8 + XK_Arabic_alefmaksura*: TKeySym = 0x000005E9 + XK_Arabic_yeh*: TKeySym = 0x000005EA + XK_Arabic_fathatan*: TKeySym = 0x000005EB + XK_Arabic_dammatan*: TKeySym = 0x000005EC + XK_Arabic_kasratan*: TKeySym = 0x000005ED + XK_Arabic_fatha*: TKeySym = 0x000005EE + XK_Arabic_damma*: TKeySym = 0x000005EF + XK_Arabic_kasra*: TKeySym = 0x000005F0 + XK_Arabic_shadda*: TKeySym = 0x000005F1 + XK_Arabic_sukun*: TKeySym = 0x000005F2 + XK_Arabic_madda_above*: TKeySym = 0x000005F3 + XK_Arabic_hamza_above*: TKeySym = 0x000005F4 + XK_Arabic_hamza_below*: TKeySym = 0x000005F5 + XK_Arabic_jeh*: TKeySym = 0x000005F6 + XK_Arabic_veh*: TKeySym = 0x000005F7 + XK_Arabic_keheh*: TKeySym = 0x000005F8 + XK_Arabic_gaf*: TKeySym = 0x000005F9 + XK_Arabic_noon_ghunna*: TKeySym = 0x000005FA + XK_Arabic_heh_doachashmee*: TKeySym = 0x000005FB + XK_Farsi_yeh*: TKeySym = 0x000005FC + XK_Arabic_farsi_yeh*: TKeySym = XK_Farsi_yeh + XK_Arabic_yeh_baree*: TKeySym = 0x000005FD + XK_Arabic_heh_goal*: TKeySym = 0x000005FE + XK_Arabic_switch*: TKeySym = 0x0000FF7E # Alias for mode_switch +# XK_ARABIC +#* +# * Cyrillic +# * Byte 3 = 6 +# * + +when defined(XK_CYRILLIC) or true: + const + XKc_Cyrillic_GHE_bar*: TKeySym = 0x00000680 + XK_Cyrillic_ghe_bar*: TKeySym = 0x00000690 + XKc_Cyrillic_ZHE_descender*: TKeySym = 0x00000681 + XK_Cyrillic_zhe_descender*: TKeySym = 0x00000691 + XKc_Cyrillic_KA_descender*: TKeySym = 0x00000682 + XK_Cyrillic_ka_descender*: TKeySym = 0x00000692 + XKc_Cyrillic_KA_vertstroke*: TKeySym = 0x00000683 + XK_Cyrillic_ka_vertstroke*: TKeySym = 0x00000693 + XKc_Cyrillic_EN_descender*: TKeySym = 0x00000684 + XK_Cyrillic_en_descender*: TKeySym = 0x00000694 + XKc_Cyrillic_U_straight*: TKeySym = 0x00000685 + XK_Cyrillic_u_straight*: TKeySym = 0x00000695 + XKc_Cyrillic_U_straight_bar*: TKeySym = 0x00000686 + XK_Cyrillic_u_straight_bar*: TKeySym = 0x00000696 + XKc_Cyrillic_HA_descender*: TKeySym = 0x00000687 + XK_Cyrillic_ha_descender*: TKeySym = 0x00000697 + XKc_Cyrillic_CHE_descender*: TKeySym = 0x00000688 + XK_Cyrillic_che_descender*: TKeySym = 0x00000698 + XKc_Cyrillic_CHE_vertstroke*: TKeySym = 0x00000689 + XK_Cyrillic_che_vertstroke*: TKeySym = 0x00000699 + XKc_Cyrillic_SHHA*: TKeySym = 0x0000068A + XK_Cyrillic_shha*: TKeySym = 0x0000069A + XKc_Cyrillic_SCHWA*: TKeySym = 0x0000068C + XK_Cyrillic_schwa*: TKeySym = 0x0000069C + XKc_Cyrillic_I_macron*: TKeySym = 0x0000068D + XK_Cyrillic_i_macron*: TKeySym = 0x0000069D + XKc_Cyrillic_O_bar*: TKeySym = 0x0000068E + XK_Cyrillic_o_bar*: TKeySym = 0x0000069E + XKc_Cyrillic_U_macron*: TKeySym = 0x0000068F + XK_Cyrillic_u_macron*: TKeySym = 0x0000069F + XK_Serbian_dje*: TKeySym = 0x000006A1 + XK_Macedonia_gje*: TKeySym = 0x000006A2 + XK_Cyrillic_io*: TKeySym = 0x000006A3 + XK_Ukrainian_ie*: TKeySym = 0x000006A4 + XK_Ukranian_je*: TKeySym = 0x000006A4 # deprecated + XK_Macedonia_dse*: TKeySym = 0x000006A5 + XK_Ukrainian_i*: TKeySym = 0x000006A6 + XK_Ukranian_i*: TKeySym = 0x000006A6 # deprecated + XK_Ukrainian_yi*: TKeySym = 0x000006A7 + XK_Ukranian_yi*: TKeySym = 0x000006A7 # deprecated + XK_Cyrillic_je*: TKeySym = 0x000006A8 + XK_Serbian_je*: TKeySym = 0x000006A8 # deprecated + XK_Cyrillic_lje*: TKeySym = 0x000006A9 + XK_Serbian_lje*: TKeySym = 0x000006A9 # deprecated + XK_Cyrillic_nje*: TKeySym = 0x000006AA + XK_Serbian_nje*: TKeySym = 0x000006AA # deprecated + XK_Serbian_tshe*: TKeySym = 0x000006AB + XK_Macedonia_kje*: TKeySym = 0x000006AC + XK_Ukrainian_ghe_with_upturn*: TKeySym = 0x000006AD + XK_Byelorussian_shortu*: TKeySym = 0x000006AE + XK_Cyrillic_dzhe*: TKeySym = 0x000006AF + XK_Serbian_dze*: TKeySym = 0x000006AF # deprecated + XK_numerosign*: TKeySym = 0x000006B0 + XKc_Serbian_DJE*: TKeySym = 0x000006B1 + XKc_Macedonia_GJE*: TKeySym = 0x000006B2 + XKc_Cyrillic_IO*: TKeySym = 0x000006B3 + XKc_Ukrainian_IE*: TKeySym = 0x000006B4 + XKc_Ukranian_JE*: TKeySym = 0x000006B4 # deprecated + XKc_Macedonia_DSE*: TKeySym = 0x000006B5 + XKc_Ukrainian_I*: TKeySym = 0x000006B6 + XKc_Ukranian_I*: TKeySym = 0x000006B6 # deprecated + XKc_Ukrainian_YI*: TKeySym = 0x000006B7 + XKc_Ukranian_YI*: TKeySym = 0x000006B7 # deprecated + XKc_Cyrillic_JE*: TKeySym = 0x000006B8 + XKc_Serbian_JE*: TKeySym = 0x000006B8 # deprecated + XKc_Cyrillic_LJE*: TKeySym = 0x000006B9 + XKc_Serbian_LJE*: TKeySym = 0x000006B9 # deprecated + XKc_Cyrillic_NJE*: TKeySym = 0x000006BA + XKc_Serbian_NJE*: TKeySym = 0x000006BA # deprecated + XKc_Serbian_TSHE*: TKeySym = 0x000006BB + XKc_Macedonia_KJE*: TKeySym = 0x000006BC + XKc_Ukrainian_GHE_WITH_UPTURN*: TKeySym = 0x000006BD + XKc_Byelorussian_SHORTU*: TKeySym = 0x000006BE + XKc_Cyrillic_DZHE*: TKeySym = 0x000006BF + XKc_Serbian_DZE*: TKeySym = 0x000006BF # deprecated + XK_Cyrillic_yu*: TKeySym = 0x000006C0 + XK_Cyrillic_a*: TKeySym = 0x000006C1 + XK_Cyrillic_be*: TKeySym = 0x000006C2 + XK_Cyrillic_tse*: TKeySym = 0x000006C3 + XK_Cyrillic_de*: TKeySym = 0x000006C4 + XK_Cyrillic_ie*: TKeySym = 0x000006C5 + XK_Cyrillic_ef*: TKeySym = 0x000006C6 + XK_Cyrillic_ghe*: TKeySym = 0x000006C7 + XK_Cyrillic_ha*: TKeySym = 0x000006C8 + XK_Cyrillic_i*: TKeySym = 0x000006C9 + XK_Cyrillic_shorti*: TKeySym = 0x000006CA + XK_Cyrillic_ka*: TKeySym = 0x000006CB + XK_Cyrillic_el*: TKeySym = 0x000006CC + XK_Cyrillic_em*: TKeySym = 0x000006CD + XK_Cyrillic_en*: TKeySym = 0x000006CE + XK_Cyrillic_o*: TKeySym = 0x000006CF + XK_Cyrillic_pe*: TKeySym = 0x000006D0 + XK_Cyrillic_ya*: TKeySym = 0x000006D1 + XK_Cyrillic_er*: TKeySym = 0x000006D2 + XK_Cyrillic_es*: TKeySym = 0x000006D3 + XK_Cyrillic_te*: TKeySym = 0x000006D4 + XK_Cyrillic_u*: TKeySym = 0x000006D5 + XK_Cyrillic_zhe*: TKeySym = 0x000006D6 + XK_Cyrillic_ve*: TKeySym = 0x000006D7 + XK_Cyrillic_softsign*: TKeySym = 0x000006D8 + XK_Cyrillic_yeru*: TKeySym = 0x000006D9 + XK_Cyrillic_ze*: TKeySym = 0x000006DA + XK_Cyrillic_sha*: TKeySym = 0x000006DB + XK_Cyrillic_e*: TKeySym = 0x000006DC + XK_Cyrillic_shcha*: TKeySym = 0x000006DD + XK_Cyrillic_che*: TKeySym = 0x000006DE + XK_Cyrillic_hardsign*: TKeySym = 0x000006DF + XKc_Cyrillic_YU*: TKeySym = 0x000006E0 + XKc_Cyrillic_A*: TKeySym = 0x000006E1 + XKc_Cyrillic_BE*: TKeySym = 0x000006E2 + XKc_Cyrillic_TSE*: TKeySym = 0x000006E3 + XKc_Cyrillic_DE*: TKeySym = 0x000006E4 + XKc_Cyrillic_IE*: TKeySym = 0x000006E5 + XKc_Cyrillic_EF*: TKeySym = 0x000006E6 + XKc_Cyrillic_GHE*: TKeySym = 0x000006E7 + XKc_Cyrillic_HA*: TKeySym = 0x000006E8 + XKc_Cyrillic_I*: TKeySym = 0x000006E9 + XKc_Cyrillic_SHORTI*: TKeySym = 0x000006EA + XKc_Cyrillic_KA*: TKeySym = 0x000006EB + XKc_Cyrillic_EL*: TKeySym = 0x000006EC + XKc_Cyrillic_EM*: TKeySym = 0x000006ED + XKc_Cyrillic_EN*: TKeySym = 0x000006EE + XKc_Cyrillic_O*: TKeySym = 0x000006EF + XKc_Cyrillic_PE*: TKeySym = 0x000006F0 + XKc_Cyrillic_YA*: TKeySym = 0x000006F1 + XKc_Cyrillic_ER*: TKeySym = 0x000006F2 + XKc_Cyrillic_ES*: TKeySym = 0x000006F3 + XKc_Cyrillic_TE*: TKeySym = 0x000006F4 + XKc_Cyrillic_U*: TKeySym = 0x000006F5 + XKc_Cyrillic_ZHE*: TKeySym = 0x000006F6 + XKc_Cyrillic_VE*: TKeySym = 0x000006F7 + XKc_Cyrillic_SOFTSIGN*: TKeySym = 0x000006F8 + XKc_Cyrillic_YERU*: TKeySym = 0x000006F9 + XKc_Cyrillic_ZE*: TKeySym = 0x000006FA + XKc_Cyrillic_SHA*: TKeySym = 0x000006FB + XKc_Cyrillic_E*: TKeySym = 0x000006FC + XKc_Cyrillic_SHCHA*: TKeySym = 0x000006FD + XKc_Cyrillic_CHE*: TKeySym = 0x000006FE + XKc_Cyrillic_HARDSIGN*: TKeySym = 0x000006FF +# XK_CYRILLIC +#* +# * Greek +# * Byte 3 = 7 +# * + +when defined(XK_GREEK) or true: + const + XKc_Greek_ALPHAaccent*: TKeySym = 0x000007A1 + XKc_Greek_EPSILONaccent*: TKeySym = 0x000007A2 + XKc_Greek_ETAaccent*: TKeySym = 0x000007A3 + XKc_Greek_IOTAaccent*: TKeySym = 0x000007A4 + XKc_Greek_IOTAdieresis*: TKeySym = 0x000007A5 + XKc_Greek_IOTAdiaeresis*: TKeySym = XKc_Greek_IOTAdieresis # old typo + XKc_Greek_OMICRONaccent*: TKeySym = 0x000007A7 + XKc_Greek_UPSILONaccent*: TKeySym = 0x000007A8 + XKc_Greek_UPSILONdieresis*: TKeySym = 0x000007A9 + XKc_Greek_OMEGAaccent*: TKeySym = 0x000007AB + XK_Greek_accentdieresis*: TKeySym = 0x000007AE + XK_Greek_horizbar*: TKeySym = 0x000007AF + XK_Greek_alphaaccent*: TKeySym = 0x000007B1 + XK_Greek_epsilonaccent*: TKeySym = 0x000007B2 + XK_Greek_etaaccent*: TKeySym = 0x000007B3 + XK_Greek_iotaaccent*: TKeySym = 0x000007B4 + XK_Greek_iotadieresis*: TKeySym = 0x000007B5 + XK_Greek_iotaaccentdieresis*: TKeySym = 0x000007B6 + XK_Greek_omicronaccent*: TKeySym = 0x000007B7 + XK_Greek_upsilonaccent*: TKeySym = 0x000007B8 + XK_Greek_upsilondieresis*: TKeySym = 0x000007B9 + XK_Greek_upsilonaccentdieresis*: TKeySym = 0x000007BA + XK_Greek_omegaaccent*: TKeySym = 0x000007BB + XKc_Greek_ALPHA*: TKeySym = 0x000007C1 + XKc_Greek_BETA*: TKeySym = 0x000007C2 + XKc_Greek_GAMMA*: TKeySym = 0x000007C3 + XKc_Greek_DELTA*: TKeySym = 0x000007C4 + XKc_Greek_EPSILON*: TKeySym = 0x000007C5 + XKc_Greek_ZETA*: TKeySym = 0x000007C6 + XKc_Greek_ETA*: TKeySym = 0x000007C7 + XKc_Greek_THETA*: TKeySym = 0x000007C8 + XKc_Greek_IOTA*: TKeySym = 0x000007C9 + XKc_Greek_KAPPA*: TKeySym = 0x000007CA + XKc_Greek_LAMDA*: TKeySym = 0x000007CB + XKc_Greek_LAMBDA*: TKeySym = 0x000007CB + XKc_Greek_MU*: TKeySym = 0x000007CC + XKc_Greek_NU*: TKeySym = 0x000007CD + XKc_Greek_XI*: TKeySym = 0x000007CE + XKc_Greek_OMICRON*: TKeySym = 0x000007CF + XKc_Greek_PI*: TKeySym = 0x000007D0 + XKc_Greek_RHO*: TKeySym = 0x000007D1 + XKc_Greek_SIGMA*: TKeySym = 0x000007D2 + XKc_Greek_TAU*: TKeySym = 0x000007D4 + XKc_Greek_UPSILON*: TKeySym = 0x000007D5 + XKc_Greek_PHI*: TKeySym = 0x000007D6 + XKc_Greek_CHI*: TKeySym = 0x000007D7 + XKc_Greek_PSI*: TKeySym = 0x000007D8 + XKc_Greek_OMEGA*: TKeySym = 0x000007D9 + XK_Greek_alpha*: TKeySym = 0x000007E1 + XK_Greek_beta*: TKeySym = 0x000007E2 + XK_Greek_gamma*: TKeySym = 0x000007E3 + XK_Greek_delta*: TKeySym = 0x000007E4 + XK_Greek_epsilon*: TKeySym = 0x000007E5 + XK_Greek_zeta*: TKeySym = 0x000007E6 + XK_Greek_eta*: TKeySym = 0x000007E7 + XK_Greek_theta*: TKeySym = 0x000007E8 + XK_Greek_iota*: TKeySym = 0x000007E9 + XK_Greek_kappa*: TKeySym = 0x000007EA + XK_Greek_lamda*: TKeySym = 0x000007EB + XK_Greek_lambda*: TKeySym = 0x000007EB + XK_Greek_mu*: TKeySym = 0x000007EC + XK_Greek_nu*: TKeySym = 0x000007ED + XK_Greek_xi*: TKeySym = 0x000007EE + XK_Greek_omicron*: TKeySym = 0x000007EF + XK_Greek_pi*: TKeySym = 0x000007F0 + XK_Greek_rho*: TKeySym = 0x000007F1 + XK_Greek_sigma*: TKeySym = 0x000007F2 + XK_Greek_finalsmallsigma*: TKeySym = 0x000007F3 + XK_Greek_tau*: TKeySym = 0x000007F4 + XK_Greek_upsilon*: TKeySym = 0x000007F5 + XK_Greek_phi*: TKeySym = 0x000007F6 + XK_Greek_chi*: TKeySym = 0x000007F7 + XK_Greek_psi*: TKeySym = 0x000007F8 + XK_Greek_omega*: TKeySym = 0x000007F9 + XK_Greek_switch*: TKeySym = 0x0000FF7E # Alias for mode_switch +# XK_GREEK +#* +# * Technical +# * Byte 3 = 8 +# * + +when defined(XK_TECHNICAL) or true: + const + XK_leftradical*: TKeySym = 0x000008A1 + XK_topleftradical*: TKeySym = 0x000008A2 + XK_horizconnector*: TKeySym = 0x000008A3 + XK_topintegral*: TKeySym = 0x000008A4 + XK_botintegral*: TKeySym = 0x000008A5 + XK_vertconnector*: TKeySym = 0x000008A6 + XK_topleftsqbracket*: TKeySym = 0x000008A7 + XK_botleftsqbracket*: TKeySym = 0x000008A8 + XK_toprightsqbracket*: TKeySym = 0x000008A9 + XK_botrightsqbracket*: TKeySym = 0x000008AA + XK_topleftparens*: TKeySym = 0x000008AB + XK_botleftparens*: TKeySym = 0x000008AC + XK_toprightparens*: TKeySym = 0x000008AD + XK_botrightparens*: TKeySym = 0x000008AE + XK_leftmiddlecurlybrace*: TKeySym = 0x000008AF + XK_rightmiddlecurlybrace*: TKeySym = 0x000008B0 + XK_topleftsummation*: TKeySym = 0x000008B1 + XK_botleftsummation*: TKeySym = 0x000008B2 + XK_topvertsummationconnector*: TKeySym = 0x000008B3 + XK_botvertsummationconnector*: TKeySym = 0x000008B4 + XK_toprightsummation*: TKeySym = 0x000008B5 + XK_botrightsummation*: TKeySym = 0x000008B6 + XK_rightmiddlesummation*: TKeySym = 0x000008B7 + XK_lessthanequal*: TKeySym = 0x000008BC + XK_notequal*: TKeySym = 0x000008BD + XK_greaterthanequal*: TKeySym = 0x000008BE + XK_integral*: TKeySym = 0x000008BF + XK_therefore*: TKeySym = 0x000008C0 + XK_variation*: TKeySym = 0x000008C1 + XK_infinity*: TKeySym = 0x000008C2 + XK_nabla*: TKeySym = 0x000008C5 + XK_approximate*: TKeySym = 0x000008C8 + XK_similarequal*: TKeySym = 0x000008C9 + XK_ifonlyif*: TKeySym = 0x000008CD + XK_implies*: TKeySym = 0x000008CE + XK_identical*: TKeySym = 0x000008CF + XK_radical*: TKeySym = 0x000008D6 + XK_includedin*: TKeySym = 0x000008DA + XK_includes*: TKeySym = 0x000008DB + XK_intersection*: TKeySym = 0x000008DC + XK_union*: TKeySym = 0x000008DD + XK_logicaland*: TKeySym = 0x000008DE + XK_logicalor*: TKeySym = 0x000008DF + XK_partialderivative*: TKeySym = 0x000008EF + XK_function*: TKeySym = 0x000008F6 + XK_leftarrow*: TKeySym = 0x000008FB + XK_uparrow*: TKeySym = 0x000008FC + XK_rightarrow*: TKeySym = 0x000008FD + XK_downarrow*: TKeySym = 0x000008FE +# XK_TECHNICAL +#* +# * Special +# * Byte 3 = 9 +# * + +when defined(XK_SPECIAL): + const + XK_blank*: TKeySym = 0x000009DF + XK_soliddiamond*: TKeySym = 0x000009E0 + XK_checkerboard*: TKeySym = 0x000009E1 + XK_ht*: TKeySym = 0x000009E2 + XK_ff*: TKeySym = 0x000009E3 + XK_cr*: TKeySym = 0x000009E4 + XK_lf*: TKeySym = 0x000009E5 + XK_nl*: TKeySym = 0x000009E8 + XK_vt*: TKeySym = 0x000009E9 + XK_lowrightcorner*: TKeySym = 0x000009EA + XK_uprightcorner*: TKeySym = 0x000009EB + XK_upleftcorner*: TKeySym = 0x000009EC + XK_lowleftcorner*: TKeySym = 0x000009ED + XK_crossinglines*: TKeySym = 0x000009EE + XK_horizlinescan1*: TKeySym = 0x000009EF + XK_horizlinescan3*: TKeySym = 0x000009F0 + XK_horizlinescan5*: TKeySym = 0x000009F1 + XK_horizlinescan7*: TKeySym = 0x000009F2 + XK_horizlinescan9*: TKeySym = 0x000009F3 + XK_leftt*: TKeySym = 0x000009F4 + XK_rightt*: TKeySym = 0x000009F5 + XK_bott*: TKeySym = 0x000009F6 + XK_topt*: TKeySym = 0x000009F7 + XK_vertbar*: TKeySym = 0x000009F8 +# XK_SPECIAL +#* +# * Publishing +# * Byte 3 = a +# * + +when defined(XK_PUBLISHING) or true: + const + XK_emspace*: TKeySym = 0x00000AA1 + XK_enspace*: TKeySym = 0x00000AA2 + XK_em3space*: TKeySym = 0x00000AA3 + XK_em4space*: TKeySym = 0x00000AA4 + XK_digitspace*: TKeySym = 0x00000AA5 + XK_punctspace*: TKeySym = 0x00000AA6 + XK_thinspace*: TKeySym = 0x00000AA7 + XK_hairspace*: TKeySym = 0x00000AA8 + XK_emdash*: TKeySym = 0x00000AA9 + XK_endash*: TKeySym = 0x00000AAA + XK_signifblank*: TKeySym = 0x00000AAC + XK_ellipsis*: TKeySym = 0x00000AAE + XK_doubbaselinedot*: TKeySym = 0x00000AAF + XK_onethird*: TKeySym = 0x00000AB0 + XK_twothirds*: TKeySym = 0x00000AB1 + XK_onefifth*: TKeySym = 0x00000AB2 + XK_twofifths*: TKeySym = 0x00000AB3 + XK_threefifths*: TKeySym = 0x00000AB4 + XK_fourfifths*: TKeySym = 0x00000AB5 + XK_onesixth*: TKeySym = 0x00000AB6 + XK_fivesixths*: TKeySym = 0x00000AB7 + XK_careof*: TKeySym = 0x00000AB8 + XK_figdash*: TKeySym = 0x00000ABB + XK_leftanglebracket*: TKeySym = 0x00000ABC + XK_decimalpoint*: TKeySym = 0x00000ABD + XK_rightanglebracket*: TKeySym = 0x00000ABE + XK_marker*: TKeySym = 0x00000ABF + XK_oneeighth*: TKeySym = 0x00000AC3 + XK_threeeighths*: TKeySym = 0x00000AC4 + XK_fiveeighths*: TKeySym = 0x00000AC5 + XK_seveneighths*: TKeySym = 0x00000AC6 + XK_trademark*: TKeySym = 0x00000AC9 + XK_signaturemark*: TKeySym = 0x00000ACA + XK_trademarkincircle*: TKeySym = 0x00000ACB + XK_leftopentriangle*: TKeySym = 0x00000ACC + XK_rightopentriangle*: TKeySym = 0x00000ACD + XK_emopencircle*: TKeySym = 0x00000ACE + XK_emopenrectangle*: TKeySym = 0x00000ACF + XK_leftsinglequotemark*: TKeySym = 0x00000AD0 + XK_rightsinglequotemark*: TKeySym = 0x00000AD1 + XK_leftdoublequotemark*: TKeySym = 0x00000AD2 + XK_rightdoublequotemark*: TKeySym = 0x00000AD3 + XK_prescription*: TKeySym = 0x00000AD4 + XK_minutes*: TKeySym = 0x00000AD6 + XK_seconds*: TKeySym = 0x00000AD7 + XK_latincross*: TKeySym = 0x00000AD9 + XK_hexagram*: TKeySym = 0x00000ADA + XK_filledrectbullet*: TKeySym = 0x00000ADB + XK_filledlefttribullet*: TKeySym = 0x00000ADC + XK_filledrighttribullet*: TKeySym = 0x00000ADD + XK_emfilledcircle*: TKeySym = 0x00000ADE + XK_emfilledrect*: TKeySym = 0x00000ADF + XK_enopencircbullet*: TKeySym = 0x00000AE0 + XK_enopensquarebullet*: TKeySym = 0x00000AE1 + XK_openrectbullet*: TKeySym = 0x00000AE2 + XK_opentribulletup*: TKeySym = 0x00000AE3 + XK_opentribulletdown*: TKeySym = 0x00000AE4 + XK_openstar*: TKeySym = 0x00000AE5 + XK_enfilledcircbullet*: TKeySym = 0x00000AE6 + XK_enfilledsqbullet*: TKeySym = 0x00000AE7 + XK_filledtribulletup*: TKeySym = 0x00000AE8 + XK_filledtribulletdown*: TKeySym = 0x00000AE9 + XK_leftpointer*: TKeySym = 0x00000AEA + XK_rightpointer*: TKeySym = 0x00000AEB + XK_club*: TKeySym = 0x00000AEC + XK_diamond*: TKeySym = 0x00000AED + XK_heart*: TKeySym = 0x00000AEE + XK_maltesecross*: TKeySym = 0x00000AF0 + XK_dagger*: TKeySym = 0x00000AF1 + XK_doubledagger*: TKeySym = 0x00000AF2 + XK_checkmark*: TKeySym = 0x00000AF3 + XK_ballotcross*: TKeySym = 0x00000AF4 + XK_musicalsharp*: TKeySym = 0x00000AF5 + XK_musicalflat*: TKeySym = 0x00000AF6 + XK_malesymbol*: TKeySym = 0x00000AF7 + XK_femalesymbol*: TKeySym = 0x00000AF8 + XK_telephone*: TKeySym = 0x00000AF9 + XK_telephonerecorder*: TKeySym = 0x00000AFA + XK_phonographcopyright*: TKeySym = 0x00000AFB + XK_caret*: TKeySym = 0x00000AFC + XK_singlelowquotemark*: TKeySym = 0x00000AFD + XK_doublelowquotemark*: TKeySym = 0x00000AFE + XK_cursor*: TKeySym = 0x00000AFF +# XK_PUBLISHING +#* +# * APL +# * Byte 3 = b +# * + +when defined(XK_APL) or true: + const + XK_leftcaret*: TKeySym = 0x00000BA3 + XK_rightcaret*: TKeySym = 0x00000BA6 + XK_downcaret*: TKeySym = 0x00000BA8 + XK_upcaret*: TKeySym = 0x00000BA9 + XK_overbar*: TKeySym = 0x00000BC0 + XK_downtack*: TKeySym = 0x00000BC2 + XK_upshoe*: TKeySym = 0x00000BC3 + XK_downstile*: TKeySym = 0x00000BC4 + XK_underbar*: TKeySym = 0x00000BC6 + XK_jot*: TKeySym = 0x00000BCA + XK_quad*: TKeySym = 0x00000BCC + XK_uptack*: TKeySym = 0x00000BCE + XK_circle*: TKeySym = 0x00000BCF + XK_upstile*: TKeySym = 0x00000BD3 + XK_downshoe*: TKeySym = 0x00000BD6 + XK_rightshoe*: TKeySym = 0x00000BD8 + XK_leftshoe*: TKeySym = 0x00000BDA + XK_lefttack*: TKeySym = 0x00000BDC + XK_righttack*: TKeySym = 0x00000BFC +# XK_APL +#* +# * Hebrew +# * Byte 3 = c +# * + +when defined(XK_HEBREW) or true: + const + XK_hebrew_doublelowline*: TKeySym = 0x00000CDF + XK_hebrew_aleph*: TKeySym = 0x00000CE0 + XK_hebrew_bet*: TKeySym = 0x00000CE1 + XK_hebrew_beth*: TKeySym = 0x00000CE1 # deprecated + XK_hebrew_gimel*: TKeySym = 0x00000CE2 + XK_hebrew_gimmel*: TKeySym = 0x00000CE2 # deprecated + XK_hebrew_dalet*: TKeySym = 0x00000CE3 + XK_hebrew_daleth*: TKeySym = 0x00000CE3 # deprecated + XK_hebrew_he*: TKeySym = 0x00000CE4 + XK_hebrew_waw*: TKeySym = 0x00000CE5 + XK_hebrew_zain*: TKeySym = 0x00000CE6 + XK_hebrew_zayin*: TKeySym = 0x00000CE6 # deprecated + XK_hebrew_chet*: TKeySym = 0x00000CE7 + XK_hebrew_het*: TKeySym = 0x00000CE7 # deprecated + XK_hebrew_tet*: TKeySym = 0x00000CE8 + XK_hebrew_teth*: TKeySym = 0x00000CE8 # deprecated + XK_hebrew_yod*: TKeySym = 0x00000CE9 + XK_hebrew_finalkaph*: TKeySym = 0x00000CEA + XK_hebrew_kaph*: TKeySym = 0x00000CEB + XK_hebrew_lamed*: TKeySym = 0x00000CEC + XK_hebrew_finalmem*: TKeySym = 0x00000CED + XK_hebrew_mem*: TKeySym = 0x00000CEE + XK_hebrew_finalnun*: TKeySym = 0x00000CEF + XK_hebrew_nun*: TKeySym = 0x00000CF0 + XK_hebrew_samech*: TKeySym = 0x00000CF1 + XK_hebrew_samekh*: TKeySym = 0x00000CF1 # deprecated + XK_hebrew_ayin*: TKeySym = 0x00000CF2 + XK_hebrew_finalpe*: TKeySym = 0x00000CF3 + XK_hebrew_pe*: TKeySym = 0x00000CF4 + XK_hebrew_finalzade*: TKeySym = 0x00000CF5 + XK_hebrew_finalzadi*: TKeySym = 0x00000CF5 # deprecated + XK_hebrew_zade*: TKeySym = 0x00000CF6 + XK_hebrew_zadi*: TKeySym = 0x00000CF6 # deprecated + XK_hebrew_qoph*: TKeySym = 0x00000CF7 + XK_hebrew_kuf*: TKeySym = 0x00000CF7 # deprecated + XK_hebrew_resh*: TKeySym = 0x00000CF8 + XK_hebrew_shin*: TKeySym = 0x00000CF9 + XK_hebrew_taw*: TKeySym = 0x00000CFA + XK_hebrew_taf*: TKeySym = 0x00000CFA # deprecated + XK_Hebrew_switch*: TKeySym = 0x0000FF7E # Alias for mode_switch +# XK_HEBREW +#* +# * Thai +# * Byte 3 = d +# * + +when defined(XK_THAI) or true: + const + XK_Thai_kokai*: TKeySym = 0x00000DA1 + XK_Thai_khokhai*: TKeySym = 0x00000DA2 + XK_Thai_khokhuat*: TKeySym = 0x00000DA3 + XK_Thai_khokhwai*: TKeySym = 0x00000DA4 + XK_Thai_khokhon*: TKeySym = 0x00000DA5 + XK_Thai_khorakhang*: TKeySym = 0x00000DA6 + XK_Thai_ngongu*: TKeySym = 0x00000DA7 + XK_Thai_chochan*: TKeySym = 0x00000DA8 + XK_Thai_choching*: TKeySym = 0x00000DA9 + XK_Thai_chochang*: TKeySym = 0x00000DAA + XK_Thai_soso*: TKeySym = 0x00000DAB + XK_Thai_chochoe*: TKeySym = 0x00000DAC + XK_Thai_yoying*: TKeySym = 0x00000DAD + XK_Thai_dochada*: TKeySym = 0x00000DAE + XK_Thai_topatak*: TKeySym = 0x00000DAF + XK_Thai_thothan*: TKeySym = 0x00000DB0 + XK_Thai_thonangmontho*: TKeySym = 0x00000DB1 + XK_Thai_thophuthao*: TKeySym = 0x00000DB2 + XK_Thai_nonen*: TKeySym = 0x00000DB3 + XK_Thai_dodek*: TKeySym = 0x00000DB4 + XK_Thai_totao*: TKeySym = 0x00000DB5 + XK_Thai_thothung*: TKeySym = 0x00000DB6 + XK_Thai_thothahan*: TKeySym = 0x00000DB7 + XK_Thai_thothong*: TKeySym = 0x00000DB8 + XK_Thai_nonu*: TKeySym = 0x00000DB9 + XK_Thai_bobaimai*: TKeySym = 0x00000DBA + XK_Thai_popla*: TKeySym = 0x00000DBB + XK_Thai_phophung*: TKeySym = 0x00000DBC + XK_Thai_fofa*: TKeySym = 0x00000DBD + XK_Thai_phophan*: TKeySym = 0x00000DBE + XK_Thai_fofan*: TKeySym = 0x00000DBF + XK_Thai_phosamphao*: TKeySym = 0x00000DC0 + XK_Thai_moma*: TKeySym = 0x00000DC1 + XK_Thai_yoyak*: TKeySym = 0x00000DC2 + XK_Thai_rorua*: TKeySym = 0x00000DC3 + XK_Thai_ru*: TKeySym = 0x00000DC4 + XK_Thai_loling*: TKeySym = 0x00000DC5 + XK_Thai_lu*: TKeySym = 0x00000DC6 + XK_Thai_wowaen*: TKeySym = 0x00000DC7 + XK_Thai_sosala*: TKeySym = 0x00000DC8 + XK_Thai_sorusi*: TKeySym = 0x00000DC9 + XK_Thai_sosua*: TKeySym = 0x00000DCA + XK_Thai_hohip*: TKeySym = 0x00000DCB + XK_Thai_lochula*: TKeySym = 0x00000DCC + XK_Thai_oang*: TKeySym = 0x00000DCD + XK_Thai_honokhuk*: TKeySym = 0x00000DCE + XK_Thai_paiyannoi*: TKeySym = 0x00000DCF + XK_Thai_saraa*: TKeySym = 0x00000DD0 + XK_Thai_maihanakat*: TKeySym = 0x00000DD1 + XK_Thai_saraaa*: TKeySym = 0x00000DD2 + XK_Thai_saraam*: TKeySym = 0x00000DD3 + XK_Thai_sarai*: TKeySym = 0x00000DD4 + XK_Thai_saraii*: TKeySym = 0x00000DD5 + XK_Thai_saraue*: TKeySym = 0x00000DD6 + XK_Thai_sarauee*: TKeySym = 0x00000DD7 + XK_Thai_sarau*: TKeySym = 0x00000DD8 + XK_Thai_sarauu*: TKeySym = 0x00000DD9 + XK_Thai_phinthu*: TKeySym = 0x00000DDA + XK_Thai_maihanakat_maitho*: TKeySym = 0x00000DDE + XK_Thai_baht*: TKeySym = 0x00000DDF + XK_Thai_sarae*: TKeySym = 0x00000DE0 + XK_Thai_saraae*: TKeySym = 0x00000DE1 + XK_Thai_sarao*: TKeySym = 0x00000DE2 + XK_Thai_saraaimaimuan*: TKeySym = 0x00000DE3 + XK_Thai_saraaimaimalai*: TKeySym = 0x00000DE4 + XK_Thai_lakkhangyao*: TKeySym = 0x00000DE5 + XK_Thai_maiyamok*: TKeySym = 0x00000DE6 + XK_Thai_maitaikhu*: TKeySym = 0x00000DE7 + XK_Thai_maiek*: TKeySym = 0x00000DE8 + XK_Thai_maitho*: TKeySym = 0x00000DE9 + XK_Thai_maitri*: TKeySym = 0x00000DEA + XK_Thai_maichattawa*: TKeySym = 0x00000DEB + XK_Thai_thanthakhat*: TKeySym = 0x00000DEC + XK_Thai_nikhahit*: TKeySym = 0x00000DED + XK_Thai_leksun*: TKeySym = 0x00000DF0 + XK_Thai_leknung*: TKeySym = 0x00000DF1 + XK_Thai_leksong*: TKeySym = 0x00000DF2 + XK_Thai_leksam*: TKeySym = 0x00000DF3 + XK_Thai_leksi*: TKeySym = 0x00000DF4 + XK_Thai_lekha*: TKeySym = 0x00000DF5 + XK_Thai_lekhok*: TKeySym = 0x00000DF6 + XK_Thai_lekchet*: TKeySym = 0x00000DF7 + XK_Thai_lekpaet*: TKeySym = 0x00000DF8 + XK_Thai_lekkao*: TKeySym = 0x00000DF9 +# XK_THAI +#* +# * Korean +# * Byte 3 = e +# * + +when defined(XK_KOREAN) or true: + const + XK_Hangul*: TKeySym = 0x0000FF31 # Hangul start/stop(toggle) + XK_Hangul_Start*: TKeySym = 0x0000FF32 # Hangul start + XK_Hangul_End*: TKeySym = 0x0000FF33 # Hangul end, English start + XK_Hangul_Hanja*: TKeySym = 0x0000FF34 # Start Hangul->Hanja Conversion + XK_Hangul_Jamo*: TKeySym = 0x0000FF35 # Hangul Jamo mode + XK_Hangul_Romaja*: TKeySym = 0x0000FF36 # Hangul Romaja mode + XK_Hangul_Codeinput*: TKeySym = 0x0000FF37 # Hangul code input mode + XK_Hangul_Jeonja*: TKeySym = 0x0000FF38 # Jeonja mode + XK_Hangul_Banja*: TKeySym = 0x0000FF39 # Banja mode + XK_Hangul_PreHanja*: TKeySym = 0x0000FF3A # Pre Hanja conversion + XK_Hangul_PostHanja*: TKeySym = 0x0000FF3B # Post Hanja conversion + XK_Hangul_SingleCandidate*: TKeySym = 0x0000FF3C # Single candidate + XK_Hangul_MultipleCandidate*: TKeySym = 0x0000FF3D # Multiple candidate + XK_Hangul_PreviousCandidate*: TKeySym = 0x0000FF3E # Previous candidate + XK_Hangul_Special*: TKeySym = 0x0000FF3F # Special symbols + XK_Hangul_switch*: TKeySym = 0x0000FF7E # Alias for mode_switch \ + # Hangul Consonant Characters + XK_Hangul_Kiyeog*: TKeySym = 0x00000EA1 + XK_Hangul_SsangKiyeog*: TKeySym = 0x00000EA2 + XK_Hangul_KiyeogSios*: TKeySym = 0x00000EA3 + XK_Hangul_Nieun*: TKeySym = 0x00000EA4 + XK_Hangul_NieunJieuj*: TKeySym = 0x00000EA5 + XK_Hangul_NieunHieuh*: TKeySym = 0x00000EA6 + XK_Hangul_Dikeud*: TKeySym = 0x00000EA7 + XK_Hangul_SsangDikeud*: TKeySym = 0x00000EA8 + XK_Hangul_Rieul*: TKeySym = 0x00000EA9 + XK_Hangul_RieulKiyeog*: TKeySym = 0x00000EAA + XK_Hangul_RieulMieum*: TKeySym = 0x00000EAB + XK_Hangul_RieulPieub*: TKeySym = 0x00000EAC + XK_Hangul_RieulSios*: TKeySym = 0x00000EAD + XK_Hangul_RieulTieut*: TKeySym = 0x00000EAE + XK_Hangul_RieulPhieuf*: TKeySym = 0x00000EAF + XK_Hangul_RieulHieuh*: TKeySym = 0x00000EB0 + XK_Hangul_Mieum*: TKeySym = 0x00000EB1 + XK_Hangul_Pieub*: TKeySym = 0x00000EB2 + XK_Hangul_SsangPieub*: TKeySym = 0x00000EB3 + XK_Hangul_PieubSios*: TKeySym = 0x00000EB4 + XK_Hangul_Sios*: TKeySym = 0x00000EB5 + XK_Hangul_SsangSios*: TKeySym = 0x00000EB6 + XK_Hangul_Ieung*: TKeySym = 0x00000EB7 + XK_Hangul_Jieuj*: TKeySym = 0x00000EB8 + XK_Hangul_SsangJieuj*: TKeySym = 0x00000EB9 + XK_Hangul_Cieuc*: TKeySym = 0x00000EBA + XK_Hangul_Khieuq*: TKeySym = 0x00000EBB + XK_Hangul_Tieut*: TKeySym = 0x00000EBC + XK_Hangul_Phieuf*: TKeySym = 0x00000EBD + XK_Hangul_Hieuh*: TKeySym = 0x00000EBE # Hangul Vowel Characters + XK_Hangul_A*: TKeySym = 0x00000EBF + XK_Hangul_AE*: TKeySym = 0x00000EC0 + XK_Hangul_YA*: TKeySym = 0x00000EC1 + XK_Hangul_YAE*: TKeySym = 0x00000EC2 + XK_Hangul_EO*: TKeySym = 0x00000EC3 + XK_Hangul_E*: TKeySym = 0x00000EC4 + XK_Hangul_YEO*: TKeySym = 0x00000EC5 + XK_Hangul_YE*: TKeySym = 0x00000EC6 + XK_Hangul_O*: TKeySym = 0x00000EC7 + XK_Hangul_WA*: TKeySym = 0x00000EC8 + XK_Hangul_WAE*: TKeySym = 0x00000EC9 + XK_Hangul_OE*: TKeySym = 0x00000ECA + XK_Hangul_YO*: TKeySym = 0x00000ECB + XK_Hangul_U*: TKeySym = 0x00000ECC + XK_Hangul_WEO*: TKeySym = 0x00000ECD + XK_Hangul_WE*: TKeySym = 0x00000ECE + XK_Hangul_WI*: TKeySym = 0x00000ECF + XK_Hangul_YU*: TKeySym = 0x00000ED0 + XK_Hangul_EU*: TKeySym = 0x00000ED1 + XK_Hangul_YI*: TKeySym = 0x00000ED2 + XK_Hangul_I*: TKeySym = 0x00000ED3 # Hangul syllable-final (JongSeong) Characters + XK_Hangul_J_Kiyeog*: TKeySym = 0x00000ED4 + XK_Hangul_J_SsangKiyeog*: TKeySym = 0x00000ED5 + XK_Hangul_J_KiyeogSios*: TKeySym = 0x00000ED6 + XK_Hangul_J_Nieun*: TKeySym = 0x00000ED7 + XK_Hangul_J_NieunJieuj*: TKeySym = 0x00000ED8 + XK_Hangul_J_NieunHieuh*: TKeySym = 0x00000ED9 + XK_Hangul_J_Dikeud*: TKeySym = 0x00000EDA + XK_Hangul_J_Rieul*: TKeySym = 0x00000EDB + XK_Hangul_J_RieulKiyeog*: TKeySym = 0x00000EDC + XK_Hangul_J_RieulMieum*: TKeySym = 0x00000EDD + XK_Hangul_J_RieulPieub*: TKeySym = 0x00000EDE + XK_Hangul_J_RieulSios*: TKeySym = 0x00000EDF + XK_Hangul_J_RieulTieut*: TKeySym = 0x00000EE0 + XK_Hangul_J_RieulPhieuf*: TKeySym = 0x00000EE1 + XK_Hangul_J_RieulHieuh*: TKeySym = 0x00000EE2 + XK_Hangul_J_Mieum*: TKeySym = 0x00000EE3 + XK_Hangul_J_Pieub*: TKeySym = 0x00000EE4 + XK_Hangul_J_PieubSios*: TKeySym = 0x00000EE5 + XK_Hangul_J_Sios*: TKeySym = 0x00000EE6 + XK_Hangul_J_SsangSios*: TKeySym = 0x00000EE7 + XK_Hangul_J_Ieung*: TKeySym = 0x00000EE8 + XK_Hangul_J_Jieuj*: TKeySym = 0x00000EE9 + XK_Hangul_J_Cieuc*: TKeySym = 0x00000EEA + XK_Hangul_J_Khieuq*: TKeySym = 0x00000EEB + XK_Hangul_J_Tieut*: TKeySym = 0x00000EEC + XK_Hangul_J_Phieuf*: TKeySym = 0x00000EED + XK_Hangul_J_Hieuh*: TKeySym = 0x00000EEE # Ancient Hangul Consonant Characters + XK_Hangul_RieulYeorinHieuh*: TKeySym = 0x00000EEF + XK_Hangul_SunkyeongeumMieum*: TKeySym = 0x00000EF0 + XK_Hangul_SunkyeongeumPieub*: TKeySym = 0x00000EF1 + XK_Hangul_PanSios*: TKeySym = 0x00000EF2 + XK_Hangul_KkogjiDalrinIeung*: TKeySym = 0x00000EF3 + XK_Hangul_SunkyeongeumPhieuf*: TKeySym = 0x00000EF4 + XK_Hangul_YeorinHieuh*: TKeySym = 0x00000EF5 # Ancient Hangul Vowel Characters + XK_Hangul_AraeA*: TKeySym = 0x00000EF6 + XK_Hangul_AraeAE*: TKeySym = 0x00000EF7 # Ancient Hangul syllable-final (JongSeong) Characters + XK_Hangul_J_PanSios*: TKeySym = 0x00000EF8 + XK_Hangul_J_KkogjiDalrinIeung*: TKeySym = 0x00000EF9 + XK_Hangul_J_YeorinHieuh*: TKeySym = 0x00000EFA # Korean currency symbol + XK_Korean_Won*: TKeySym = 0x00000EFF +# XK_KOREAN +#* +# * Armenian +# * Byte 3 = = $14 +# * + +when defined(XK_ARMENIAN) or true: + const + XK_Armenian_eternity*: TKeySym = 0x000014A1 + XK_Armenian_ligature_ew*: TKeySym = 0x000014A2 + XK_Armenian_full_stop*: TKeySym = 0x000014A3 + XK_Armenian_verjaket*: TKeySym = 0x000014A3 + XK_Armenian_parenright*: TKeySym = 0x000014A4 + XK_Armenian_parenleft*: TKeySym = 0x000014A5 + XK_Armenian_guillemotright*: TKeySym = 0x000014A6 + XK_Armenian_guillemotleft*: TKeySym = 0x000014A7 + XK_Armenian_em_dash*: TKeySym = 0x000014A8 + XK_Armenian_dot*: TKeySym = 0x000014A9 + XK_Armenian_mijaket*: TKeySym = 0x000014A9 + XK_Armenian_separation_mark*: TKeySym = 0x000014AA + XK_Armenian_but*: TKeySym = 0x000014AA + XK_Armenian_comma*: TKeySym = 0x000014AB + XK_Armenian_en_dash*: TKeySym = 0x000014AC + XK_Armenian_hyphen*: TKeySym = 0x000014AD + XK_Armenian_yentamna*: TKeySym = 0x000014AD + XK_Armenian_ellipsis*: TKeySym = 0x000014AE + XK_Armenian_exclam*: TKeySym = 0x000014AF + XK_Armenian_amanak*: TKeySym = 0x000014AF + XK_Armenian_accent*: TKeySym = 0x000014B0 + XK_Armenian_shesht*: TKeySym = 0x000014B0 + XK_Armenian_question*: TKeySym = 0x000014B1 + XK_Armenian_paruyk*: TKeySym = 0x000014B1 + XKc_Armenian_AYB*: TKeySym = 0x000014B2 + XK_Armenian_ayb*: TKeySym = 0x000014B3 + XKc_Armenian_BEN*: TKeySym = 0x000014B4 + XK_Armenian_ben*: TKeySym = 0x000014B5 + XKc_Armenian_GIM*: TKeySym = 0x000014B6 + XK_Armenian_gim*: TKeySym = 0x000014B7 + XKc_Armenian_DA*: TKeySym = 0x000014B8 + XK_Armenian_da*: TKeySym = 0x000014B9 + XKc_Armenian_YECH*: TKeySym = 0x000014BA + XK_Armenian_yech*: TKeySym = 0x000014BB + XKc_Armenian_ZA*: TKeySym = 0x000014BC + XK_Armenian_za*: TKeySym = 0x000014BD + XKc_Armenian_E*: TKeySym = 0x000014BE + XK_Armenian_e*: TKeySym = 0x000014BF + XKc_Armenian_AT*: TKeySym = 0x000014C0 + XK_Armenian_at*: TKeySym = 0x000014C1 + XKc_Armenian_TO*: TKeySym = 0x000014C2 + XK_Armenian_to*: TKeySym = 0x000014C3 + XKc_Armenian_ZHE*: TKeySym = 0x000014C4 + XK_Armenian_zhe*: TKeySym = 0x000014C5 + XKc_Armenian_INI*: TKeySym = 0x000014C6 + XK_Armenian_ini*: TKeySym = 0x000014C7 + XKc_Armenian_LYUN*: TKeySym = 0x000014C8 + XK_Armenian_lyun*: TKeySym = 0x000014C9 + XKc_Armenian_KHE*: TKeySym = 0x000014CA + XK_Armenian_khe*: TKeySym = 0x000014CB + XKc_Armenian_TSA*: TKeySym = 0x000014CC + XK_Armenian_tsa*: TKeySym = 0x000014CD + XKc_Armenian_KEN*: TKeySym = 0x000014CE + XK_Armenian_ken*: TKeySym = 0x000014CF + XKc_Armenian_HO*: TKeySym = 0x000014D0 + XK_Armenian_ho*: TKeySym = 0x000014D1 + XKc_Armenian_DZA*: TKeySym = 0x000014D2 + XK_Armenian_dza*: TKeySym = 0x000014D3 + XKc_Armenian_GHAT*: TKeySym = 0x000014D4 + XK_Armenian_ghat*: TKeySym = 0x000014D5 + XKc_Armenian_TCHE*: TKeySym = 0x000014D6 + XK_Armenian_tche*: TKeySym = 0x000014D7 + XKc_Armenian_MEN*: TKeySym = 0x000014D8 + XK_Armenian_men*: TKeySym = 0x000014D9 + XKc_Armenian_HI*: TKeySym = 0x000014DA + XK_Armenian_hi*: TKeySym = 0x000014DB + XKc_Armenian_NU*: TKeySym = 0x000014DC + XK_Armenian_nu*: TKeySym = 0x000014DD + XKc_Armenian_SHA*: TKeySym = 0x000014DE + XK_Armenian_sha*: TKeySym = 0x000014DF + XKc_Armenian_VO*: TKeySym = 0x000014E0 + XK_Armenian_vo*: TKeySym = 0x000014E1 + XKc_Armenian_CHA*: TKeySym = 0x000014E2 + XK_Armenian_cha*: TKeySym = 0x000014E3 + XKc_Armenian_PE*: TKeySym = 0x000014E4 + XK_Armenian_pe*: TKeySym = 0x000014E5 + XKc_Armenian_JE*: TKeySym = 0x000014E6 + XK_Armenian_je*: TKeySym = 0x000014E7 + XKc_Armenian_RA*: TKeySym = 0x000014E8 + XK_Armenian_ra*: TKeySym = 0x000014E9 + XKc_Armenian_SE*: TKeySym = 0x000014EA + XK_Armenian_se*: TKeySym = 0x000014EB + XKc_Armenian_VEV*: TKeySym = 0x000014EC + XK_Armenian_vev*: TKeySym = 0x000014ED + XKc_Armenian_TYUN*: TKeySym = 0x000014EE + XK_Armenian_tyun*: TKeySym = 0x000014EF + XKc_Armenian_RE*: TKeySym = 0x000014F0 + XK_Armenian_re*: TKeySym = 0x000014F1 + XKc_Armenian_TSO*: TKeySym = 0x000014F2 + XK_Armenian_tso*: TKeySym = 0x000014F3 + XKc_Armenian_VYUN*: TKeySym = 0x000014F4 + XK_Armenian_vyun*: TKeySym = 0x000014F5 + XKc_Armenian_PYUR*: TKeySym = 0x000014F6 + XK_Armenian_pyur*: TKeySym = 0x000014F7 + XKc_Armenian_KE*: TKeySym = 0x000014F8 + XK_Armenian_ke*: TKeySym = 0x000014F9 + XKc_Armenian_O*: TKeySym = 0x000014FA + XK_Armenian_o*: TKeySym = 0x000014FB + XKc_Armenian_FE*: TKeySym = 0x000014FC + XK_Armenian_fe*: TKeySym = 0x000014FD + XK_Armenian_apostrophe*: TKeySym = 0x000014FE + XK_Armenian_section_sign*: TKeySym = 0x000014FF +# XK_ARMENIAN +#* +# * Georgian +# * Byte 3 = = $15 +# * + +when defined(XK_GEORGIAN) or true: + const + XK_Georgian_an*: TKeySym = 0x000015D0 + XK_Georgian_ban*: TKeySym = 0x000015D1 + XK_Georgian_gan*: TKeySym = 0x000015D2 + XK_Georgian_don*: TKeySym = 0x000015D3 + XK_Georgian_en*: TKeySym = 0x000015D4 + XK_Georgian_vin*: TKeySym = 0x000015D5 + XK_Georgian_zen*: TKeySym = 0x000015D6 + XK_Georgian_tan*: TKeySym = 0x000015D7 + XK_Georgian_in*: TKeySym = 0x000015D8 + XK_Georgian_kan*: TKeySym = 0x000015D9 + XK_Georgian_las*: TKeySym = 0x000015DA + XK_Georgian_man*: TKeySym = 0x000015DB + XK_Georgian_nar*: TKeySym = 0x000015DC + XK_Georgian_on*: TKeySym = 0x000015DD + XK_Georgian_par*: TKeySym = 0x000015DE + XK_Georgian_zhar*: TKeySym = 0x000015DF + XK_Georgian_rae*: TKeySym = 0x000015E0 + XK_Georgian_san*: TKeySym = 0x000015E1 + XK_Georgian_tar*: TKeySym = 0x000015E2 + XK_Georgian_un*: TKeySym = 0x000015E3 + XK_Georgian_phar*: TKeySym = 0x000015E4 + XK_Georgian_khar*: TKeySym = 0x000015E5 + XK_Georgian_ghan*: TKeySym = 0x000015E6 + XK_Georgian_qar*: TKeySym = 0x000015E7 + XK_Georgian_shin*: TKeySym = 0x000015E8 + XK_Georgian_chin*: TKeySym = 0x000015E9 + XK_Georgian_can*: TKeySym = 0x000015EA + XK_Georgian_jil*: TKeySym = 0x000015EB + XK_Georgian_cil*: TKeySym = 0x000015EC + XK_Georgian_char*: TKeySym = 0x000015ED + XK_Georgian_xan*: TKeySym = 0x000015EE + XK_Georgian_jhan*: TKeySym = 0x000015EF + XK_Georgian_hae*: TKeySym = 0x000015F0 + XK_Georgian_he*: TKeySym = 0x000015F1 + XK_Georgian_hie*: TKeySym = 0x000015F2 + XK_Georgian_we*: TKeySym = 0x000015F3 + XK_Georgian_har*: TKeySym = 0x000015F4 + XK_Georgian_hoe*: TKeySym = 0x000015F5 + XK_Georgian_fi*: TKeySym = 0x000015F6 +# XK_GEORGIAN +#* +# * Azeri (and other Turkic or Caucasian languages of ex-USSR) +# * Byte 3 = = $16 +# * + +when defined(XK_CAUCASUS) or true: + # latin + const + XKc_Ccedillaabovedot*: TKeySym = 0x000016A2 + XKc_Xabovedot*: TKeySym = 0x000016A3 + XKc_Qabovedot*: TKeySym = 0x000016A5 + XKc_Ibreve*: TKeySym = 0x000016A6 + XKc_IE*: TKeySym = 0x000016A7 + XKc_UO*: TKeySym = 0x000016A8 + XKc_Zstroke*: TKeySym = 0x000016A9 + XKc_Gcaron*: TKeySym = 0x000016AA + XKc_Obarred*: TKeySym = 0x000016AF + XK_ccedillaabovedot*: TKeySym = 0x000016B2 + XK_xabovedot*: TKeySym = 0x000016B3 + XKc_Ocaron*: TKeySym = 0x000016B4 + XK_qabovedot*: TKeySym = 0x000016B5 + XK_ibreve*: TKeySym = 0x000016B6 + XK_ie*: TKeySym = 0x000016B7 + XK_uo*: TKeySym = 0x000016B8 + XK_zstroke*: TKeySym = 0x000016B9 + XK_gcaron*: TKeySym = 0x000016BA + XK_ocaron*: TKeySym = 0x000016BD + XK_obarred*: TKeySym = 0x000016BF + XKc_SCHWA*: TKeySym = 0x000016C6 + XK_schwa*: TKeySym = 0x000016F6 # those are not really Caucasus, but I put them here for now\ + # For Inupiak + XKc_Lbelowdot*: TKeySym = 0x000016D1 + XKc_Lstrokebelowdot*: TKeySym = 0x000016D2 + XK_lbelowdot*: TKeySym = 0x000016E1 + XK_lstrokebelowdot*: TKeySym = 0x000016E2 # For Guarani + XKc_Gtilde*: TKeySym = 0x000016D3 + XK_gtilde*: TKeySym = 0x000016E3 +# XK_CAUCASUS +#* +# * Vietnamese +# * Byte 3 = = $1e +# * + +when defined(XK_VIETNAMESE) or true: + const + XKc_Abelowdot*: TKeySym = 0x00001EA0 + XK_abelowdot*: TKeySym = 0x00001EA1 + XKc_Ahook*: TKeySym = 0x00001EA2 + XK_ahook*: TKeySym = 0x00001EA3 + XKc_Acircumflexacute*: TKeySym = 0x00001EA4 + XK_acircumflexacute*: TKeySym = 0x00001EA5 + XKc_Acircumflexgrave*: TKeySym = 0x00001EA6 + XK_acircumflexgrave*: TKeySym = 0x00001EA7 + XKc_Acircumflexhook*: TKeySym = 0x00001EA8 + XK_acircumflexhook*: TKeySym = 0x00001EA9 + XKc_Acircumflextilde*: TKeySym = 0x00001EAA + XK_acircumflextilde*: TKeySym = 0x00001EAB + XKc_Acircumflexbelowdot*: TKeySym = 0x00001EAC + XK_acircumflexbelowdot*: TKeySym = 0x00001EAD + XKc_Abreveacute*: TKeySym = 0x00001EAE + XK_abreveacute*: TKeySym = 0x00001EAF + XKc_Abrevegrave*: TKeySym = 0x00001EB0 + XK_abrevegrave*: TKeySym = 0x00001EB1 + XKc_Abrevehook*: TKeySym = 0x00001EB2 + XK_abrevehook*: TKeySym = 0x00001EB3 + XKc_Abrevetilde*: TKeySym = 0x00001EB4 + XK_abrevetilde*: TKeySym = 0x00001EB5 + XKc_Abrevebelowdot*: TKeySym = 0x00001EB6 + XK_abrevebelowdot*: TKeySym = 0x00001EB7 + XKc_Ebelowdot*: TKeySym = 0x00001EB8 + XK_ebelowdot*: TKeySym = 0x00001EB9 + XKc_Ehook*: TKeySym = 0x00001EBA + XK_ehook*: TKeySym = 0x00001EBB + XKc_Etilde*: TKeySym = 0x00001EBC + XK_etilde*: TKeySym = 0x00001EBD + XKc_Ecircumflexacute*: TKeySym = 0x00001EBE + XK_ecircumflexacute*: TKeySym = 0x00001EBF + XKc_Ecircumflexgrave*: TKeySym = 0x00001EC0 + XK_ecircumflexgrave*: TKeySym = 0x00001EC1 + XKc_Ecircumflexhook*: TKeySym = 0x00001EC2 + XK_ecircumflexhook*: TKeySym = 0x00001EC3 + XKc_Ecircumflextilde*: TKeySym = 0x00001EC4 + XK_ecircumflextilde*: TKeySym = 0x00001EC5 + XKc_Ecircumflexbelowdot*: TKeySym = 0x00001EC6 + XK_ecircumflexbelowdot*: TKeySym = 0x00001EC7 + XKc_Ihook*: TKeySym = 0x00001EC8 + XK_ihook*: TKeySym = 0x00001EC9 + XKc_Ibelowdot*: TKeySym = 0x00001ECA + XK_ibelowdot*: TKeySym = 0x00001ECB + XKc_Obelowdot*: TKeySym = 0x00001ECC + XK_obelowdot*: TKeySym = 0x00001ECD + XKc_Ohook*: TKeySym = 0x00001ECE + XK_ohook*: TKeySym = 0x00001ECF + XKc_Ocircumflexacute*: TKeySym = 0x00001ED0 + XK_ocircumflexacute*: TKeySym = 0x00001ED1 + XKc_Ocircumflexgrave*: TKeySym = 0x00001ED2 + XK_ocircumflexgrave*: TKeySym = 0x00001ED3 + XKc_Ocircumflexhook*: TKeySym = 0x00001ED4 + XK_ocircumflexhook*: TKeySym = 0x00001ED5 + XKc_Ocircumflextilde*: TKeySym = 0x00001ED6 + XK_ocircumflextilde*: TKeySym = 0x00001ED7 + XKc_Ocircumflexbelowdot*: TKeySym = 0x00001ED8 + XK_ocircumflexbelowdot*: TKeySym = 0x00001ED9 + XKc_Ohornacute*: TKeySym = 0x00001EDA + XK_ohornacute*: TKeySym = 0x00001EDB + XKc_Ohorngrave*: TKeySym = 0x00001EDC + XK_ohorngrave*: TKeySym = 0x00001EDD + XKc_Ohornhook*: TKeySym = 0x00001EDE + XK_ohornhook*: TKeySym = 0x00001EDF + XKc_Ohorntilde*: TKeySym = 0x00001EE0 + XK_ohorntilde*: TKeySym = 0x00001EE1 + XKc_Ohornbelowdot*: TKeySym = 0x00001EE2 + XK_ohornbelowdot*: TKeySym = 0x00001EE3 + XKc_Ubelowdot*: TKeySym = 0x00001EE4 + XK_ubelowdot*: TKeySym = 0x00001EE5 + XKc_Uhook*: TKeySym = 0x00001EE6 + XK_uhook*: TKeySym = 0x00001EE7 + XKc_Uhornacute*: TKeySym = 0x00001EE8 + XK_uhornacute*: TKeySym = 0x00001EE9 + XKc_Uhorngrave*: TKeySym = 0x00001EEA + XK_uhorngrave*: TKeySym = 0x00001EEB + XKc_Uhornhook*: TKeySym = 0x00001EEC + XK_uhornhook*: TKeySym = 0x00001EED + XKc_Uhorntilde*: TKeySym = 0x00001EEE + XK_uhorntilde*: TKeySym = 0x00001EEF + XKc_Uhornbelowdot*: TKeySym = 0x00001EF0 + XK_uhornbelowdot*: TKeySym = 0x00001EF1 + XKc_Ybelowdot*: TKeySym = 0x00001EF4 + XK_ybelowdot*: TKeySym = 0x00001EF5 + XKc_Yhook*: TKeySym = 0x00001EF6 + XK_yhook*: TKeySym = 0x00001EF7 + XKc_Ytilde*: TKeySym = 0x00001EF8 + XK_ytilde*: TKeySym = 0x00001EF9 + XKc_Ohorn*: TKeySym = 0x00001EFA # U+01a0 + XK_ohorn*: TKeySym = 0x00001EFB # U+01a1 + XKc_Uhorn*: TKeySym = 0x00001EFC # U+01af + XK_uhorn*: TKeySym = 0x00001EFD # U+01b0 + XK_combining_tilde*: TKeySym = 0x00001E9F # U+0303 + XK_combining_grave*: TKeySym = 0x00001EF2 # U+0300 + XK_combining_acute*: TKeySym = 0x00001EF3 # U+0301 + XK_combining_hook*: TKeySym = 0x00001EFE # U+0309 + XK_combining_belowdot*: TKeySym = 0x00001EFF # U+0323 +# XK_VIETNAMESE + +when defined(XK_CURRENCY) or true: + const + XK_EcuSign*: TKeySym = 0x000020A0 + XK_ColonSign*: TKeySym = 0x000020A1 + XK_CruzeiroSign*: TKeySym = 0x000020A2 + XK_FFrancSign*: TKeySym = 0x000020A3 + XK_LiraSign*: TKeySym = 0x000020A4 + XK_MillSign*: TKeySym = 0x000020A5 + XK_NairaSign*: TKeySym = 0x000020A6 + XK_PesetaSign*: TKeySym = 0x000020A7 + XK_RupeeSign*: TKeySym = 0x000020A8 + XK_WonSign*: TKeySym = 0x000020A9 + XK_NewSheqelSign*: TKeySym = 0x000020AA + XK_DongSign*: TKeySym = 0x000020AB + XK_EuroSign*: TKeySym = 0x000020AC +# implementation diff --git a/tests/deps/x11-1.0/x.nim b/tests/deps/x11-1.0/x.nim new file mode 100644 index 000000000..9d9df48bd --- /dev/null +++ b/tests/deps/x11-1.0/x.nim @@ -0,0 +1,400 @@ + +# +# Automatically converted by H2Pas 0.99.15 from x.h +# The following command line parameters were used: +# -p +# -T +# -S +# -d +# -c +# x.h +# +# Pointers to basic pascal types, inserted by h2pas conversion program. + +const + X_PROTOCOL* = 11 + X_PROTOCOL_REVISION* = 0 + +type + PXID* = ptr TXID + TXID* = culong + PMask* = ptr TMask + TMask* = culong + PPAtom* = ptr PAtom + PAtom* = ptr TAtom + TAtom* = culong + PVisualID* = ptr TVisualID + TVisualID* = culong + PTime* = ptr TTime + TTime* = culong + PPWindow* = ptr PWindow + PWindow* = ptr TWindow + TWindow* = TXID + PDrawable* = ptr TDrawable + TDrawable* = TXID + PFont* = ptr TFont + TFont* = TXID + PPixmap* = ptr TPixmap + TPixmap* = TXID + PCursor* = ptr TCursor + TCursor* = TXID + PColormap* = ptr TColormap + TColormap* = TXID + PGContext* = ptr TGContext + TGContext* = TXID + PKeySym* = ptr TKeySym + TKeySym* = TXID + PKeyCode* = ptr TKeyCode + TKeyCode* = cuchar + +proc `==`*(a, b: TAtom): bool = + return system.`==`(a,b) + +const + None* = 0 + ParentRelative* = 1 + CopyFromParent* = 0 + PointerWindow* = 0 + InputFocus* = 1 + PointerRoot* = 1 + AnyPropertyType* = 0 + AnyKey* = 0 + AnyButton* = 0 + AllTemporary* = 0 + CurrentTime* = 0 + NoSymbol* = 0 + NoEventMask* = 0 + KeyPressMask* = 1 shl 0 + KeyReleaseMask* = 1 shl 1 + ButtonPressMask* = 1 shl 2 + ButtonReleaseMask* = 1 shl 3 + EnterWindowMask* = 1 shl 4 + LeaveWindowMask* = 1 shl 5 + PointerMotionMask* = 1 shl 6 + PointerMotionHintMask* = 1 shl 7 + Button1MotionMask* = 1 shl 8 + Button2MotionMask* = 1 shl 9 + Button3MotionMask* = 1 shl 10 + Button4MotionMask* = 1 shl 11 + Button5MotionMask* = 1 shl 12 + ButtonMotionMask* = 1 shl 13 + KeymapStateMask* = 1 shl 14 + ExposureMask* = 1 shl 15 + VisibilityChangeMask* = 1 shl 16 + StructureNotifyMask* = 1 shl 17 + ResizeRedirectMask* = 1 shl 18 + SubstructureNotifyMask* = 1 shl 19 + SubstructureRedirectMask* = 1 shl 20 + FocusChangeMask* = 1 shl 21 + PropertyChangeMask* = 1 shl 22 + ColormapChangeMask* = 1 shl 23 + OwnerGrabButtonMask* = 1 shl 24 + KeyPress* = 2 + KeyRelease* = 3 + ButtonPress* = 4 + ButtonRelease* = 5 + MotionNotify* = 6 + EnterNotify* = 7 + LeaveNotify* = 8 + FocusIn* = 9 + FocusOut* = 10 + KeymapNotify* = 11 + Expose* = 12 + GraphicsExpose* = 13 + NoExpose* = 14 + VisibilityNotify* = 15 + CreateNotify* = 16 + DestroyNotify* = 17 + UnmapNotify* = 18 + MapNotify* = 19 + MapRequest* = 20 + ReparentNotify* = 21 + ConfigureNotify* = 22 + ConfigureRequest* = 23 + GravityNotify* = 24 + ResizeRequest* = 25 + CirculateNotify* = 26 + CirculateRequest* = 27 + PropertyNotify* = 28 + SelectionClear* = 29 + SelectionRequest* = 30 + SelectionNotify* = 31 + ColormapNotify* = 32 + ClientMessage* = 33 + MappingNotify* = 34 + LASTEvent* = 35 + ShiftMask* = 1 shl 0 + LockMask* = 1 shl 1 + ControlMask* = 1 shl 2 + Mod1Mask* = 1 shl 3 + Mod2Mask* = 1 shl 4 + Mod3Mask* = 1 shl 5 + Mod4Mask* = 1 shl 6 + Mod5Mask* = 1 shl 7 + ShiftMapIndex* = 0 + LockMapIndex* = 1 + ControlMapIndex* = 2 + Mod1MapIndex* = 3 + Mod2MapIndex* = 4 + Mod3MapIndex* = 5 + Mod4MapIndex* = 6 + Mod5MapIndex* = 7 + Button1Mask* = 1 shl 8 + Button2Mask* = 1 shl 9 + Button3Mask* = 1 shl 10 + Button4Mask* = 1 shl 11 + Button5Mask* = 1 shl 12 + AnyModifier* = 1 shl 15 + Button1* = 1 + Button2* = 2 + Button3* = 3 + Button4* = 4 + Button5* = 5 + NotifyNormal* = 0 + NotifyGrab* = 1 + NotifyUngrab* = 2 + NotifyWhileGrabbed* = 3 + NotifyHint* = 1 + NotifyAncestor* = 0 + NotifyVirtual* = 1 + NotifyInferior* = 2 + NotifyNonlinear* = 3 + NotifyNonlinearVirtual* = 4 + NotifyPointer* = 5 + NotifyPointerRoot* = 6 + NotifyDetailNone* = 7 + VisibilityUnobscured* = 0 + VisibilityPartiallyObscured* = 1 + VisibilityFullyObscured* = 2 + PlaceOnTop* = 0 + PlaceOnBottom* = 1 + FamilyInternet* = 0 + FamilyDECnet* = 1 + FamilyChaos* = 2 + FamilyInternet6* = 6 + FamilyServerInterpreted* = 5 + PropertyNewValue* = 0 + PropertyDelete* = 1 + ColormapUninstalled* = 0 + ColormapInstalled* = 1 + GrabModeSync* = 0 + GrabModeAsync* = 1 + GrabSuccess* = 0 + AlreadyGrabbed* = 1 + GrabInvalidTime* = 2 + GrabNotViewable* = 3 + GrabFrozen* = 4 + AsyncPointer* = 0 + SyncPointer* = 1 + ReplayPointer* = 2 + AsyncKeyboard* = 3 + SyncKeyboard* = 4 + ReplayKeyboard* = 5 + AsyncBoth* = 6 + SyncBoth* = 7 + RevertToNone* = None + RevertToPointerRoot* = PointerRoot + RevertToParent* = 2 + Success* = 0 + BadRequest* = 1 + BadValue* = 2 + BadWindow* = 3 + BadPixmap* = 4 + BadAtom* = 5 + BadCursor* = 6 + BadFont* = 7 + BadMatch* = 8 + BadDrawable* = 9 + BadAccess* = 10 + BadAlloc* = 11 + BadColor* = 12 + BadGC* = 13 + BadIDChoice* = 14 + BadName* = 15 + BadLength* = 16 + BadImplementation* = 17 + FirstExtensionError* = 128 + LastExtensionError* = 255 + InputOutput* = 1 + InputOnly* = 2 + CWBackPixmap* = 1 shl 0 + CWBackPixel* = 1 shl 1 + CWBorderPixmap* = 1 shl 2 + CWBorderPixel* = 1 shl 3 + CWBitGravity* = 1 shl 4 + CWWinGravity* = 1 shl 5 + CWBackingStore* = 1 shl 6 + CWBackingPlanes* = 1 shl 7 + CWBackingPixel* = 1 shl 8 + CWOverrideRedirect* = 1 shl 9 + CWSaveUnder* = 1 shl 10 + CWEventMask* = 1 shl 11 + CWDontPropagate* = 1 shl 12 + CWColormap* = 1 shl 13 + CWCursor* = 1 shl 14 + CWX* = 1 shl 0 + CWY* = 1 shl 1 + CWWidth* = 1 shl 2 + CWHeight* = 1 shl 3 + CWBorderWidth* = 1 shl 4 + CWSibling* = 1 shl 5 + CWStackMode* = 1 shl 6 + ForgetGravity* = 0 + NorthWestGravity* = 1 + NorthGravity* = 2 + NorthEastGravity* = 3 + WestGravity* = 4 + CenterGravity* = 5 + EastGravity* = 6 + SouthWestGravity* = 7 + SouthGravity* = 8 + SouthEastGravity* = 9 + StaticGravity* = 10 + UnmapGravity* = 0 + NotUseful* = 0 + WhenMapped* = 1 + Always* = 2 + IsUnmapped* = 0 + IsUnviewable* = 1 + IsViewable* = 2 + SetModeInsert* = 0 + SetModeDelete* = 1 + DestroyAll* = 0 + RetainPermanent* = 1 + RetainTemporary* = 2 + Above* = 0 + Below* = 1 + TopIf* = 2 + BottomIf* = 3 + Opposite* = 4 + RaiseLowest* = 0 + LowerHighest* = 1 + PropModeReplace* = 0 + PropModePrepend* = 1 + PropModeAppend* = 2 + GXclear* = 0x00000000 + GXand* = 0x00000001 + GXandReverse* = 0x00000002 + GXcopy* = 0x00000003 + GXandInverted* = 0x00000004 + GXnoop* = 0x00000005 + GXxor* = 0x00000006 + GXor* = 0x00000007 + GXnor* = 0x00000008 + GXequiv* = 0x00000009 + GXinvert* = 0x0000000A + GXorReverse* = 0x0000000B + GXcopyInverted* = 0x0000000C + GXorInverted* = 0x0000000D + GXnand* = 0x0000000E + GXset* = 0x0000000F + LineSolid* = 0 + LineOnOffDash* = 1 + LineDoubleDash* = 2 + CapNotLast* = 0 + CapButt* = 1 + CapRound* = 2 + CapProjecting* = 3 + JoinMiter* = 0 + JoinRound* = 1 + JoinBevel* = 2 + FillSolid* = 0 + FillTiled* = 1 + FillStippled* = 2 + FillOpaqueStippled* = 3 + EvenOddRule* = 0 + WindingRule* = 1 + ClipByChildren* = 0 + IncludeInferiors* = 1 + Unsorted* = 0 + YSorted* = 1 + YXSorted* = 2 + YXBanded* = 3 + CoordModeOrigin* = 0 + CoordModePrevious* = 1 + Complex* = 0 + Nonconvex* = 1 + Convex* = 2 + ArcChord* = 0 + ArcPieSlice* = 1 + GCFunction* = 1 shl 0 + GCPlaneMask* = 1 shl 1 + GCForeground* = 1 shl 2 + GCBackground* = 1 shl 3 + GCLineWidth* = 1 shl 4 + GCLineStyle* = 1 shl 5 + GCCapStyle* = 1 shl 6 + GCJoinStyle* = 1 shl 7 + GCFillStyle* = 1 shl 8 + GCFillRule* = 1 shl 9 + GCTile* = 1 shl 10 + GCStipple* = 1 shl 11 + GCTileStipXOrigin* = 1 shl 12 + GCTileStipYOrigin* = 1 shl 13 + GCFont* = 1 shl 14 + GCSubwindowMode* = 1 shl 15 + GCGraphicsExposures* = 1 shl 16 + GCClipXOrigin* = 1 shl 17 + GCClipYOrigin* = 1 shl 18 + GCClipMask* = 1 shl 19 + GCDashOffset* = 1 shl 20 + GCDashList* = 1 shl 21 + GCArcMode* = 1 shl 22 + GCLastBit* = 22 + FontLeftToRight* = 0 + FontRightToLeft* = 1 + FontChange* = 255 + XYBitmap* = 0 + XYPixmap* = 1 + ZPixmap* = 2 + AllocNone* = 0 + AllocAll* = 1 + DoRed* = 1 shl 0 + DoGreen* = 1 shl 1 + DoBlue* = 1 shl 2 + CursorShape* = 0 + TileShape* = 1 + StippleShape* = 2 + AutoRepeatModeOff* = 0 + AutoRepeatModeOn* = 1 + AutoRepeatModeDefault* = 2 + LedModeOff* = 0 + LedModeOn* = 1 + KBKeyClickPercent* = 1 shl 0 + KBBellPercent* = 1 shl 1 + KBBellPitch* = 1 shl 2 + KBBellDuration* = 1 shl 3 + KBLed* = 1 shl 4 + KBLedMode* = 1 shl 5 + KBKey* = 1 shl 6 + KBAutoRepeatMode* = 1 shl 7 + MappingSuccess* = 0 + MappingBusy* = 1 + MappingFailed* = 2 + MappingModifier* = 0 + MappingKeyboard* = 1 + MappingPointer* = 2 + DontPreferBlanking* = 0 + PreferBlanking* = 1 + DefaultBlanking* = 2 + DisableScreenSaver* = 0 + DisableScreenInterval* = 0 + DontAllowExposures* = 0 + AllowExposures* = 1 + DefaultExposures* = 2 + ScreenSaverReset* = 0 + ScreenSaverActive* = 1 + HostInsert* = 0 + HostDelete* = 1 + EnableAccess* = 1 + DisableAccess* = 0 + StaticGray* = 0 + GrayScale* = 1 + StaticColor* = 2 + PseudoColor* = 3 + TrueColor* = 4 + DirectColor* = 5 + LSBFirst* = 0 + MSBFirst* = 1 + +# implementation diff --git a/tests/deps/x11-1.0/x11.nimble b/tests/deps/x11-1.0/x11.nimble new file mode 100644 index 000000000..2f4385100 --- /dev/null +++ b/tests/deps/x11-1.0/x11.nimble @@ -0,0 +1,11 @@ +[Package] +name: "x11" +version: "1.0" +author: "Andreas Rumpf" +description: "Wrapper for X11" +license: "MIT" + +srcDir: "src" + +[Deps] +requires: "nimrod > 0.9.2" diff --git a/tests/deps/x11-1.0/x11pragma.nim b/tests/deps/x11-1.0/x11pragma.nim new file mode 100644 index 000000000..b4c876cf0 --- /dev/null +++ b/tests/deps/x11-1.0/x11pragma.nim @@ -0,0 +1,20 @@ +# included from xlib bindings + + +when defined(use_pkg_config) or defined(use_pkg_config_static): + {.pragma: libx11, cdecl, importc.} + {.pragma: libx11c, cdecl.} + when defined(use_pkg_config_static): + {.passl: gorge("pkg-config x11 --static --libs").} + else: + {.passl: gorge("pkg-config x11 --libs").} +else: + when defined(macosx): + const + libX11* = "libX11.dylib" + else: + const + libX11* = "libX11.so(|.6)" + + {.pragma: libx11, cdecl, dynlib: libX11, importc.} + {.pragma: libx11c, cdecl, dynlib: libX11.} diff --git a/tests/deps/x11-1.0/xatom.nim b/tests/deps/x11-1.0/xatom.nim new file mode 100644 index 000000000..b2e1dca91 --- /dev/null +++ b/tests/deps/x11-1.0/xatom.nim @@ -0,0 +1,81 @@ +# +# THIS IS A GENERATED FILE +# +# Do not change! Changing this file implies a protocol change! +# + +import + X + +const + XA_PRIMARY* = TAtom(1) + XA_SECONDARY* = TAtom(2) + XA_ARC* = TAtom(3) + XA_ATOM* = TAtom(4) + XA_BITMAP* = TAtom(5) + XA_CARDINAL* = TAtom(6) + XA_COLORMAP* = TAtom(7) + XA_CURSOR* = TAtom(8) + XA_CUT_BUFFER0* = TAtom(9) + XA_CUT_BUFFER1* = TAtom(10) + XA_CUT_BUFFER2* = TAtom(11) + XA_CUT_BUFFER3* = TAtom(12) + XA_CUT_BUFFER4* = TAtom(13) + XA_CUT_BUFFER5* = TAtom(14) + XA_CUT_BUFFER6* = TAtom(15) + XA_CUT_BUFFER7* = TAtom(16) + XA_DRAWABLE* = TAtom(17) + XA_FONT* = TAtom(18) + XA_INTEGER* = TAtom(19) + XA_PIXMAP* = TAtom(20) + XA_POINT* = TAtom(21) + XA_RECTANGLE* = TAtom(22) + XA_RESOURCE_MANAGER* = TAtom(23) + XA_RGB_COLOR_MAP* = TAtom(24) + XA_RGB_BEST_MAP* = TAtom(25) + XA_RGB_BLUE_MAP* = TAtom(26) + XA_RGB_DEFAULT_MAP* = TAtom(27) + XA_RGB_GRAY_MAP* = TAtom(28) + XA_RGB_GREEN_MAP* = TAtom(29) + XA_RGB_RED_MAP* = TAtom(30) + XA_STRING* = TAtom(31) + XA_VISUALID* = TAtom(32) + XA_WINDOW* = TAtom(33) + XA_WM_COMMAND* = TAtom(34) + XA_WM_HINTS* = TAtom(35) + XA_WM_CLIENT_MACHINE* = TAtom(36) + XA_WM_ICON_NAME* = TAtom(37) + XA_WM_ICON_SIZE* = TAtom(38) + XA_WM_NAME* = TAtom(39) + XA_WM_NORMAL_HINTS* = TAtom(40) + XA_WM_SIZE_HINTS* = TAtom(41) + XA_WM_ZOOM_HINTS* = TAtom(42) + XA_MIN_SPACE* = TAtom(43) + XA_NORM_SPACE* = TAtom(44) + XA_MAX_SPACE* = TAtom(45) + XA_END_SPACE* = TAtom(46) + XA_SUPERSCRIPT_X* = TAtom(47) + XA_SUPERSCRIPT_Y* = TAtom(48) + XA_SUBSCRIPT_X* = TAtom(49) + XA_SUBSCRIPT_Y* = TAtom(50) + XA_UNDERLINE_POSITION* = TAtom(51) + XA_UNDERLINE_THICKNESS* = TAtom(52) + XA_STRIKEOUT_ASCENT* = TAtom(53) + XA_STRIKEOUT_DESCENT* = TAtom(54) + XA_ITALIC_ANGLE* = TAtom(55) + XA_X_HEIGHT* = TAtom(56) + XA_QUAD_WIDTH* = TAtom(57) + XA_WEIGHT* = TAtom(58) + XA_POINT_SIZE* = TAtom(59) + XA_RESOLUTION* = TAtom(60) + XA_COPYRIGHT* = TAtom(61) + XA_NOTICE* = TAtom(62) + XA_FONT_NAME* = TAtom(63) + XA_FAMILY_NAME* = TAtom(64) + XA_FULL_NAME* = TAtom(65) + XA_CAP_HEIGHT* = TAtom(66) + XA_WM_CLASS* = TAtom(67) + XA_WM_TRANSIENT_FOR* = TAtom(68) + XA_LAST_PREDEFINED* = TAtom(68) + +# implementation diff --git a/tests/deps/x11-1.0/xcms.nim b/tests/deps/x11-1.0/xcms.nim new file mode 100644 index 000000000..659676c45 --- /dev/null +++ b/tests/deps/x11-1.0/xcms.nim @@ -0,0 +1,389 @@ + +import + x, xlib + +#const +# libX11* = "X11" + +# +# Automatically converted by H2Pas 0.99.15 from xcms.h +# The following command line parameters were used: +# -p +# -T +# -S +# -d +# -c +# xcms.h +# + +const + XcmsFailure* = 0 + XcmsSuccess* = 1 + XcmsSuccessWithCompression* = 2 + +type + PXcmsColorFormat* = ptr TXcmsColorFormat + TXcmsColorFormat* = int32 + +proc XcmsUndefinedFormat*(): TXcmsColorFormat +proc XcmsCIEXYZFormat*(): TXcmsColorFormat +proc XcmsCIEuvYFormat*(): TXcmsColorFormat +proc XcmsCIExyYFormat*(): TXcmsColorFormat +proc XcmsCIELabFormat*(): TXcmsColorFormat +proc XcmsCIELuvFormat*(): TXcmsColorFormat +proc XcmsTekHVCFormat*(): TXcmsColorFormat +proc XcmsRGBFormat*(): TXcmsColorFormat +proc XcmsRGBiFormat*(): TXcmsColorFormat +const + XcmsInitNone* = 0x00000000 + XcmsInitSuccess* = 0x00000001 + XcmsInitFailure* = 0x000000FF + +type + PXcmsFloat* = ptr TXcmsFloat + TXcmsFloat* = float64 + PXcmsRGB* = ptr TXcmsRGB + TXcmsRGB*{.final.} = object + red*: int16 + green*: int16 + blue*: int16 + + PXcmsRGBi* = ptr TXcmsRGBi + TXcmsRGBi*{.final.} = object + red*: TXcmsFloat + green*: TXcmsFloat + blue*: TXcmsFloat + + PXcmsCIEXYZ* = ptr TXcmsCIEXYZ + TXcmsCIEXYZ*{.final.} = object + X*: TXcmsFloat + Y*: TXcmsFloat + Z*: TXcmsFloat + + PXcmsCIEuvY* = ptr TXcmsCIEuvY + TXcmsCIEuvY*{.final.} = object + u_prime*: TXcmsFloat + v_prime*: TXcmsFloat + Y*: TXcmsFloat + + PXcmsCIExyY* = ptr TXcmsCIExyY + TXcmsCIExyY*{.final.} = object + x*: TXcmsFloat + y*: TXcmsFloat + theY*: TXcmsFloat + + PXcmsCIELab* = ptr TXcmsCIELab + TXcmsCIELab*{.final.} = object + L_star*: TXcmsFloat + a_star*: TXcmsFloat + b_star*: TXcmsFloat + + PXcmsCIELuv* = ptr TXcmsCIELuv + TXcmsCIELuv*{.final.} = object + L_star*: TXcmsFloat + u_star*: TXcmsFloat + v_star*: TXcmsFloat + + PXcmsTekHVC* = ptr TXcmsTekHVC + TXcmsTekHVC*{.final.} = object + H*: TXcmsFloat + V*: TXcmsFloat + C*: TXcmsFloat + + PXcmsPad* = ptr TXcmsPad + TXcmsPad*{.final.} = object + pad0*: TXcmsFloat + pad1*: TXcmsFloat + pad2*: TXcmsFloat + pad3*: TXcmsFloat + + PXcmsColor* = ptr TXcmsColor + TXcmsColor*{.final.} = object # spec : record + # case longint of + # 0 : ( RGB : TXcmsRGB ); + # 1 : ( RGBi : TXcmsRGBi ); + # 2 : ( CIEXYZ : TXcmsCIEXYZ ); + # 3 : ( CIEuvY : TXcmsCIEuvY ); + # 4 : ( CIExyY : TXcmsCIExyY ); + # 5 : ( CIELab : TXcmsCIELab ); + # 6 : ( CIELuv : TXcmsCIELuv ); + # 7 : ( TekHVC : TXcmsTekHVC ); + # 8 : ( Pad : TXcmsPad ); + # end; + pad*: TXcmsPad + pixel*: int32 + format*: TXcmsColorFormat + + PXcmsPerScrnInfo* = ptr TXcmsPerScrnInfo + TXcmsPerScrnInfo*{.final.} = object + screenWhitePt*: TXcmsColor + functionSet*: TXPointer + screenData*: TXPointer + state*: int8 + pad*: array[0..2, char] + + PXcmsCCC* = ptr TXcmsCCC + TXcmsCompressionProc* = proc (para1: PXcmsCCC, para2: PXcmsColor, + para3: int32, para4: int32, para5: PBool): TStatus{. + cdecl.} + TXcmsWhiteAdjustProc* = proc (para1: PXcmsCCC, para2: PXcmsColor, + para3: PXcmsColor, para4: TXcmsColorFormat, + para5: PXcmsColor, para6: int32, para7: PBool): TStatus{. + cdecl.} + TXcmsCCC*{.final.} = object + dpy*: PDisplay + screenNumber*: int32 + visual*: PVisual + clientWhitePt*: TXcmsColor + gamutCompProc*: TXcmsCompressionProc + gamutCompClientData*: TXPointer + whitePtAdjProc*: TXcmsWhiteAdjustProc + whitePtAdjClientData*: TXPointer + pPerScrnInfo*: PXcmsPerScrnInfo + + TXcmsCCCRec* = TXcmsCCC + PXcmsCCCRec* = ptr TXcmsCCCRec + TXcmsScreenInitProc* = proc (para1: PDisplay, para2: int32, + para3: PXcmsPerScrnInfo): TStatus{.cdecl.} + TXcmsScreenFreeProc* = proc (para1: TXPointer){.cdecl.} + TXcmsConversionProc* = proc (){.cdecl.} + PXcmsFuncListPtr* = ptr TXcmsFuncListPtr + TXcmsFuncListPtr* = TXcmsConversionProc + TXcmsParseStringProc* = proc (para1: cstring, para2: PXcmsColor): int32{.cdecl.} + PXcmsColorSpace* = ptr TXcmsColorSpace + TXcmsColorSpace*{.final.} = object + prefix*: cstring + id*: TXcmsColorFormat + parseString*: TXcmsParseStringProc + to_CIEXYZ*: TXcmsFuncListPtr + from_CIEXYZ*: TXcmsFuncListPtr + inverse_flag*: int32 + + PXcmsFunctionSet* = ptr TXcmsFunctionSet + TXcmsFunctionSet*{.final.} = object # error + #extern Status XcmsAddColorSpace ( + #in declaration at line 323 + DDColorSpaces*: ptr PXcmsColorSpace + screenInitProc*: TXcmsScreenInitProc + screenFreeProc*: TXcmsScreenFreeProc + + +proc XcmsAddFunctionSet*(para1: PXcmsFunctionSet): TStatus{.cdecl, + dynlib: libX11, importc.} +proc XcmsAllocColor*(para1: PDisplay, para2: TColormap, para3: PXcmsColor, + para4: TXcmsColorFormat): TStatus{.cdecl, dynlib: libX11, + importc.} +proc XcmsAllocNamedColor*(para1: PDisplay, para2: TColormap, para3: cstring, + para4: PXcmsColor, para5: PXcmsColor, + para6: TXcmsColorFormat): TStatus{.cdecl, + dynlib: libX11, importc.} +proc XcmsCCCOfColormap*(para1: PDisplay, para2: TColormap): TXcmsCCC{.cdecl, + dynlib: libX11, importc.} +proc XcmsCIELabClipab*(para1: TXcmsCCC, para2: PXcmsColor, para3: int32, + para4: int32, para5: PBool): TStatus{.cdecl, + dynlib: libX11, importc.} +proc XcmsCIELabClipL*(para1: TXcmsCCC, para2: PXcmsColor, para3: int32, + para4: int32, para5: PBool): TStatus{.cdecl, + dynlib: libX11, importc.} +proc XcmsCIELabClipLab*(para1: TXcmsCCC, para2: PXcmsColor, para3: int32, + para4: int32, para5: PBool): TStatus{.cdecl, + dynlib: libX11, importc.} +proc XcmsCIELabQueryMaxC*(para1: TXcmsCCC, para2: TXcmsFloat, para3: TXcmsFloat, + para4: PXcmsColor): TStatus{.cdecl, dynlib: libX11, + importc.} +proc XcmsCIELabQueryMaxL*(para1: TXcmsCCC, para2: TXcmsFloat, para3: TXcmsFloat, + para4: PXcmsColor): TStatus{.cdecl, dynlib: libX11, + importc.} +proc XcmsCIELabQueryMaxLC*(para1: TXcmsCCC, para2: TXcmsFloat, para3: PXcmsColor): TStatus{. + cdecl, dynlib: libX11, importc.} +proc XcmsCIELabQueryMinL*(para1: TXcmsCCC, para2: TXcmsFloat, para3: TXcmsFloat, + para4: PXcmsColor): TStatus{.cdecl, dynlib: libX11, + importc.} +proc XcmsCIELabToCIEXYZ*(para1: TXcmsCCC, para2: PXcmsColor, para3: PXcmsColor, + para4: int32): TStatus{.cdecl, dynlib: libX11, importc.} +proc XcmsCIELabWhiteShiftColors*(para1: TXcmsCCC, para2: PXcmsColor, + para3: PXcmsColor, para4: TXcmsColorFormat, + para5: PXcmsColor, para6: int32, para7: PBool): TStatus{. + cdecl, dynlib: libX11, importc.} +proc XcmsCIELuvClipL*(para1: TXcmsCCC, para2: PXcmsColor, para3: int32, + para4: int32, para5: PBool): TStatus{.cdecl, + dynlib: libX11, importc.} +proc XcmsCIELuvClipLuv*(para1: TXcmsCCC, para2: PXcmsColor, para3: int32, + para4: int32, para5: PBool): TStatus{.cdecl, + dynlib: libX11, importc.} +proc XcmsCIELuvClipuv*(para1: TXcmsCCC, para2: PXcmsColor, para3: int32, + para4: int32, para5: PBool): TStatus{.cdecl, + dynlib: libX11, importc.} +proc XcmsCIELuvQueryMaxC*(para1: TXcmsCCC, para2: TXcmsFloat, para3: TXcmsFloat, + para4: PXcmsColor): TStatus{.cdecl, dynlib: libX11, + importc.} +proc XcmsCIELuvQueryMaxL*(para1: TXcmsCCC, para2: TXcmsFloat, para3: TXcmsFloat, + para4: PXcmsColor): TStatus{.cdecl, dynlib: libX11, + importc.} +proc XcmsCIELuvQueryMaxLC*(para1: TXcmsCCC, para2: TXcmsFloat, para3: PXcmsColor): TStatus{. + cdecl, dynlib: libX11, importc.} +proc XcmsCIELuvQueryMinL*(para1: TXcmsCCC, para2: TXcmsFloat, para3: TXcmsFloat, + para4: PXcmsColor): TStatus{.cdecl, dynlib: libX11, + importc.} +proc XcmsCIELuvToCIEuvY*(para1: TXcmsCCC, para2: PXcmsColor, para3: PXcmsColor, + para4: int32): TStatus{.cdecl, dynlib: libX11, importc.} +proc XcmsCIELuvWhiteShiftColors*(para1: TXcmsCCC, para2: PXcmsColor, + para3: PXcmsColor, para4: TXcmsColorFormat, + para5: PXcmsColor, para6: int32, para7: PBool): TStatus{. + cdecl, dynlib: libX11, importc.} +proc XcmsCIEXYZToCIELab*(para1: TXcmsCCC, para2: PXcmsColor, para3: PXcmsColor, + para4: int32): TStatus{.cdecl, dynlib: libX11, importc.} +proc XcmsCIEXYZToCIEuvY*(para1: TXcmsCCC, para2: PXcmsColor, para3: PXcmsColor, + para4: int32): TStatus{.cdecl, dynlib: libX11, importc.} +proc XcmsCIEXYZToCIExyY*(para1: TXcmsCCC, para2: PXcmsColor, para3: PXcmsColor, + para4: int32): TStatus{.cdecl, dynlib: libX11, importc.} +proc XcmsCIEXYZToRGBi*(para1: TXcmsCCC, para2: PXcmsColor, para3: int32, + para4: PBool): TStatus{.cdecl, dynlib: libX11, importc.} +proc XcmsCIEuvYToCIELuv*(para1: TXcmsCCC, para2: PXcmsColor, para3: PXcmsColor, + para4: int32): TStatus{.cdecl, dynlib: libX11, importc.} +proc XcmsCIEuvYToCIEXYZ*(para1: TXcmsCCC, para2: PXcmsColor, para3: PXcmsColor, + para4: int32): TStatus{.cdecl, dynlib: libX11, importc.} +proc XcmsCIEuvYToTekHVC*(para1: TXcmsCCC, para2: PXcmsColor, para3: PXcmsColor, + para4: int32): TStatus{.cdecl, dynlib: libX11, importc.} +proc XcmsCIExyYToCIEXYZ*(para1: TXcmsCCC, para2: PXcmsColor, para3: PXcmsColor, + para4: int32): TStatus{.cdecl, dynlib: libX11, importc.} +proc XcmsClientWhitePointOfCCC*(para1: TXcmsCCC): PXcmsColor{.cdecl, + dynlib: libX11, importc.} +proc XcmsConvertColors*(para1: TXcmsCCC, para2: PXcmsColor, para3: int32, + para4: TXcmsColorFormat, para5: PBool): TStatus{.cdecl, + dynlib: libX11, importc.} +proc XcmsCreateCCC*(para1: PDisplay, para2: int32, para3: PVisual, + para4: PXcmsColor, para5: TXcmsCompressionProc, + para6: TXPointer, para7: TXcmsWhiteAdjustProc, + para8: TXPointer): TXcmsCCC{.cdecl, dynlib: libX11, importc.} +proc XcmsDefaultCCC*(para1: PDisplay, para2: int32): TXcmsCCC{.cdecl, + dynlib: libX11, importc.} +proc XcmsDisplayOfCCC*(para1: TXcmsCCC): PDisplay{.cdecl, dynlib: libX11, + importc.} +proc XcmsFormatOfPrefix*(para1: cstring): TXcmsColorFormat{.cdecl, + dynlib: libX11, importc.} +proc XcmsFreeCCC*(para1: TXcmsCCC){.cdecl, dynlib: libX11, importc.} +proc XcmsLookupColor*(para1: PDisplay, para2: TColormap, para3: cstring, + para4: PXcmsColor, para5: PXcmsColor, + para6: TXcmsColorFormat): TStatus{.cdecl, dynlib: libX11, + importc.} +proc XcmsPrefixOfFormat*(para1: TXcmsColorFormat): cstring{.cdecl, + dynlib: libX11, importc.} +proc XcmsQueryBlack*(para1: TXcmsCCC, para2: TXcmsColorFormat, para3: PXcmsColor): TStatus{. + cdecl, dynlib: libX11, importc.} +proc XcmsQueryBlue*(para1: TXcmsCCC, para2: TXcmsColorFormat, para3: PXcmsColor): TStatus{. + cdecl, dynlib: libX11, importc.} +proc XcmsQueryColor*(para1: PDisplay, para2: TColormap, para3: PXcmsColor, + para4: TXcmsColorFormat): TStatus{.cdecl, dynlib: libX11, + importc.} +proc XcmsQueryColors*(para1: PDisplay, para2: TColormap, para3: PXcmsColor, + para4: int32, para5: TXcmsColorFormat): TStatus{.cdecl, + dynlib: libX11, importc.} +proc XcmsQueryGreen*(para1: TXcmsCCC, para2: TXcmsColorFormat, para3: PXcmsColor): TStatus{. + cdecl, dynlib: libX11, importc.} +proc XcmsQueryRed*(para1: TXcmsCCC, para2: TXcmsColorFormat, para3: PXcmsColor): TStatus{. + cdecl, dynlib: libX11, importc.} +proc XcmsQueryWhite*(para1: TXcmsCCC, para2: TXcmsColorFormat, para3: PXcmsColor): TStatus{. + cdecl, dynlib: libX11, importc.} +proc XcmsRGBiToCIEXYZ*(para1: TXcmsCCC, para2: PXcmsColor, para3: int32, + para4: PBool): TStatus{.cdecl, dynlib: libX11, importc.} +proc XcmsRGBiToRGB*(para1: TXcmsCCC, para2: PXcmsColor, para3: int32, + para4: PBool): TStatus{.cdecl, dynlib: libX11, importc.} +proc XcmsRGBToRGBi*(para1: TXcmsCCC, para2: PXcmsColor, para3: int32, + para4: PBool): TStatus{.cdecl, dynlib: libX11, importc.} +proc XcmsScreenNumberOfCCC*(para1: TXcmsCCC): int32{.cdecl, dynlib: libX11, + importc.} +proc XcmsScreenWhitePointOfCCC*(para1: TXcmsCCC): PXcmsColor{.cdecl, + dynlib: libX11, importc.} +proc XcmsSetCCCOfColormap*(para1: PDisplay, para2: TColormap, para3: TXcmsCCC): TXcmsCCC{. + cdecl, dynlib: libX11, importc.} +proc XcmsSetCompressionProc*(para1: TXcmsCCC, para2: TXcmsCompressionProc, + para3: TXPointer): TXcmsCompressionProc{.cdecl, + dynlib: libX11, importc.} +proc XcmsSetWhiteAdjustProc*(para1: TXcmsCCC, para2: TXcmsWhiteAdjustProc, + para3: TXPointer): TXcmsWhiteAdjustProc{.cdecl, + dynlib: libX11, importc.} +proc XcmsSetWhitePoint*(para1: TXcmsCCC, para2: PXcmsColor): TStatus{.cdecl, + dynlib: libX11, importc.} +proc XcmsStoreColor*(para1: PDisplay, para2: TColormap, para3: PXcmsColor): TStatus{. + cdecl, dynlib: libX11, importc.} +proc XcmsStoreColors*(para1: PDisplay, para2: TColormap, para3: PXcmsColor, + para4: int32, para5: PBool): TStatus{.cdecl, + dynlib: libX11, importc.} +proc XcmsTekHVCClipC*(para1: TXcmsCCC, para2: PXcmsColor, para3: int32, + para4: int32, para5: PBool): TStatus{.cdecl, + dynlib: libX11, importc.} +proc XcmsTekHVCClipV*(para1: TXcmsCCC, para2: PXcmsColor, para3: int32, + para4: int32, para5: PBool): TStatus{.cdecl, + dynlib: libX11, importc.} +proc XcmsTekHVCClipVC*(para1: TXcmsCCC, para2: PXcmsColor, para3: int32, + para4: int32, para5: PBool): TStatus{.cdecl, + dynlib: libX11, importc.} +proc XcmsTekHVCQueryMaxC*(para1: TXcmsCCC, para2: TXcmsFloat, para3: TXcmsFloat, + para4: PXcmsColor): TStatus{.cdecl, dynlib: libX11, + importc.} +proc XcmsTekHVCQueryMaxV*(para1: TXcmsCCC, para2: TXcmsFloat, para3: TXcmsFloat, + para4: PXcmsColor): TStatus{.cdecl, dynlib: libX11, + importc.} +proc XcmsTekHVCQueryMaxVC*(para1: TXcmsCCC, para2: TXcmsFloat, para3: PXcmsColor): TStatus{. + cdecl, dynlib: libX11, importc.} +proc XcmsTekHVCQueryMaxVSamples*(para1: TXcmsCCC, para2: TXcmsFloat, + para3: PXcmsColor, para4: int32): TStatus{. + cdecl, dynlib: libX11, importc.} +proc XcmsTekHVCQueryMinV*(para1: TXcmsCCC, para2: TXcmsFloat, para3: TXcmsFloat, + para4: PXcmsColor): TStatus{.cdecl, dynlib: libX11, + importc.} +proc XcmsTekHVCToCIEuvY*(para1: TXcmsCCC, para2: PXcmsColor, para3: PXcmsColor, + para4: int32): TStatus{.cdecl, dynlib: libX11, importc.} +proc XcmsTekHVCWhiteShiftColors*(para1: TXcmsCCC, para2: PXcmsColor, + para3: PXcmsColor, para4: TXcmsColorFormat, + para5: PXcmsColor, para6: int32, para7: PBool): TStatus{. + cdecl, dynlib: libX11, importc.} +proc XcmsVisualOfCCC*(para1: TXcmsCCC): PVisual{.cdecl, dynlib: libX11, importc.} +# implementation + +proc XcmsUndefinedFormat(): TXcmsColorFormat = + result = 0x00000000'i32 + +proc XcmsCIEXYZFormat(): TXcmsColorFormat = + result = 0x00000001'i32 + +proc XcmsCIEuvYFormat(): TXcmsColorFormat = + result = 0x00000002'i32 + +proc XcmsCIExyYFormat(): TXcmsColorFormat = + result = 0x00000003'i32 + +proc XcmsCIELabFormat(): TXcmsColorFormat = + result = 0x00000004'i32 + +proc XcmsCIELuvFormat(): TXcmsColorFormat = + result = 0x00000005'i32 + +proc XcmsTekHVCFormat(): TXcmsColorFormat = + result = 0x00000006'i32 + +proc XcmsRGBFormat(): TXcmsColorFormat = + result = 0x80000000'i32 + +proc XcmsRGBiFormat(): TXcmsColorFormat = + result = 0x80000001'i32 + +#when defined(MACROS): +proc DisplayOfCCC(ccc: TXcmsCCC): PDisplay = + result = ccc.dpy + +proc ScreenNumberOfCCC(ccc: TXcmsCCC): int32 = + result = ccc.screenNumber + +proc VisualOfCCC(ccc: TXcmsCCC): PVisual = + result = ccc.visual + +proc ClientWhitePointOfCCC(ccc: var TXcmsCCC): ptr TXcmsColor = + result = addr(ccc.clientWhitePt) + +proc ScreenWhitePointOfCCC(ccc: var TXcmsCCC): ptr TXcmsColor = + result = addr(ccc.pPerScrnInfo.screenWhitePt) + +proc FunctionSetOfCCC(ccc: TXcmsCCC): TXpointer = + result = ccc.pPerScrnInfo.functionSet diff --git a/tests/deps/x11-1.0/xf86dga.nim b/tests/deps/x11-1.0/xf86dga.nim new file mode 100644 index 000000000..65e26df22 --- /dev/null +++ b/tests/deps/x11-1.0/xf86dga.nim @@ -0,0 +1,235 @@ +# +# Copyright (c) 1999 XFree86 Inc +# +# $XFree86: xc/include/extensions/xf86dga.h,v 3.20 1999/10/13 04:20:48 dawes Exp $ + +import + x, xlib + +const + libXxf86dga* = "libXxf86dga.so" + +#type +# cfloat* = float32 + +# $XFree86: xc/include/extensions/xf86dga1.h,v 1.2 1999/04/17 07:05:41 dawes Exp $ +# +# +#Copyright (c) 1995 Jon Tombs +#Copyright (c) 1995 XFree86 Inc +# +# +#************************************************************************ +# +# THIS IS THE OLD DGA API AND IS OBSOLETE. PLEASE DO NOT USE IT ANYMORE +# +#************************************************************************ + +type + PPcchar* = ptr ptr cstring + +const + X_XF86DGAQueryVersion* = 0 + X_XF86DGAGetVideoLL* = 1 + X_XF86DGADirectVideo* = 2 + X_XF86DGAGetViewPortSize* = 3 + X_XF86DGASetViewPort* = 4 + X_XF86DGAGetVidPage* = 5 + X_XF86DGASetVidPage* = 6 + X_XF86DGAInstallColormap* = 7 + X_XF86DGAQueryDirectVideo* = 8 + X_XF86DGAViewPortChanged* = 9 + XF86DGADirectPresent* = 0x00000001 + XF86DGADirectGraphics* = 0x00000002 + XF86DGADirectMouse* = 0x00000004 + XF86DGADirectKeyb* = 0x00000008 + XF86DGAHasColormap* = 0x00000100 + XF86DGADirectColormap* = 0x00000200 + +proc XF86DGAQueryVersion*(dpy: PDisplay, majorVersion: Pcint, + minorVersion: Pcint): TBool{.cdecl, + dynlib: libXxf86dga, importc.} +proc XF86DGAQueryExtension*(dpy: PDisplay, event_base: Pcint, error_base: Pcint): TBool{. + cdecl, dynlib: libXxf86dga, importc.} +proc XF86DGAGetVideoLL*(dpy: PDisplay, screen: cint, base_addr: Pcint, + width: Pcint, bank_size: Pcint, ram_size: Pcint): TStatus{. + cdecl, dynlib: libXxf86dga, importc.} +proc XF86DGAGetVideo*(dpy: PDisplay, screen: cint, base_addr: PPcchar, + width: Pcint, bank_size: Pcint, ram_size: Pcint): TStatus{. + cdecl, dynlib: libXxf86dga, importc.} +proc XF86DGADirectVideo*(dpy: PDisplay, screen: cint, enable: cint): TStatus{. + cdecl, dynlib: libXxf86dga, importc.} +proc XF86DGADirectVideoLL*(dpy: PDisplay, screen: cint, enable: cint): TStatus{. + cdecl, dynlib: libXxf86dga, importc.} +proc XF86DGAGetViewPortSize*(dpy: PDisplay, screen: cint, width: Pcint, + height: Pcint): TStatus{.cdecl, + dynlib: libXxf86dga, importc.} +proc XF86DGASetViewPort*(dpy: PDisplay, screen: cint, x: cint, y: cint): TStatus{. + cdecl, dynlib: libXxf86dga, importc.} +proc XF86DGAGetVidPage*(dpy: PDisplay, screen: cint, vid_page: Pcint): TStatus{. + cdecl, dynlib: libXxf86dga, importc.} +proc XF86DGASetVidPage*(dpy: PDisplay, screen: cint, vid_page: cint): TStatus{. + cdecl, dynlib: libXxf86dga, importc.} +proc XF86DGAInstallColormap*(dpy: PDisplay, screen: cint, Colormap: TColormap): TStatus{. + cdecl, dynlib: libXxf86dga, importc.} +proc XF86DGAForkApp*(screen: cint): cint{.cdecl, dynlib: libXxf86dga, importc.} +proc XF86DGAQueryDirectVideo*(dpy: PDisplay, screen: cint, flags: Pcint): TStatus{. + cdecl, dynlib: libXxf86dga, importc.} +proc XF86DGAViewPortChanged*(dpy: PDisplay, screen: cint, n: cint): TBool{. + cdecl, dynlib: libXxf86dga, importc.} +const + X_XDGAQueryVersion* = 0 # 1 through 9 are in xf86dga1.pp + # 10 and 11 are reserved to avoid conflicts with rogue DGA extensions + X_XDGAQueryModes* = 12 + X_XDGASetMode* = 13 + X_XDGASetViewport* = 14 + X_XDGAInstallColormap* = 15 + X_XDGASelectInput* = 16 + X_XDGAFillRectangle* = 17 + X_XDGACopyArea* = 18 + X_XDGACopyTransparentArea* = 19 + X_XDGAGetViewportStatus* = 20 + X_XDGASync* = 21 + X_XDGAOpenFramebuffer* = 22 + X_XDGACloseFramebuffer* = 23 + X_XDGASetClientVersion* = 24 + X_XDGAChangePixmapMode* = 25 + X_XDGACreateColormap* = 26 + XDGAConcurrentAccess* = 0x00000001 + XDGASolidFillRect* = 0x00000002 + XDGABlitRect* = 0x00000004 + XDGABlitTransRect* = 0x00000008 + XDGAPixmap* = 0x00000010 + XDGAInterlaced* = 0x00010000 + XDGADoublescan* = 0x00020000 + XDGAFlipImmediate* = 0x00000001 + XDGAFlipRetrace* = 0x00000002 + XDGANeedRoot* = 0x00000001 + XF86DGANumberEvents* = 7 + XDGAPixmapModeLarge* = 0 + XDGAPixmapModeSmall* = 1 + XF86DGAClientNotLocal* = 0 + XF86DGANoDirectVideoMode* = 1 + XF86DGAScreenNotActive* = 2 + XF86DGADirectNotActivated* = 3 + XF86DGAOperationNotSupported* = 4 + XF86DGANumberErrors* = (XF86DGAOperationNotSupported + 1) + +type + PXDGAMode* = ptr TXDGAMode + TXDGAMode*{.final.} = object + num*: cint # A unique identifier for the mode (num > 0) + name*: cstring # name of mode given in the XF86Config + verticalRefresh*: cfloat + flags*: cint # DGA_CONCURRENT_ACCESS, etc... + imageWidth*: cint # linear accessible portion (pixels) + imageHeight*: cint + pixmapWidth*: cint # Xlib accessible portion (pixels) + pixmapHeight*: cint # both fields ignored if no concurrent access + bytesPerScanline*: cint + byteOrder*: cint # MSBFirst, LSBFirst + depth*: cint + bitsPerPixel*: cint + redMask*: culong + greenMask*: culong + blueMask*: culong + visualClass*: cshort + viewportWidth*: cint + viewportHeight*: cint + xViewportStep*: cint # viewport position granularity + yViewportStep*: cint + maxViewportX*: cint # max viewport origin + maxViewportY*: cint + viewportFlags*: cint # types of page flipping possible + reserved1*: cint + reserved2*: cint + + PXDGADevice* = ptr TXDGADevice + TXDGADevice*{.final.} = object + mode*: TXDGAMode + data*: Pcuchar + pixmap*: TPixmap + + PXDGAButtonEvent* = ptr TXDGAButtonEvent + TXDGAButtonEvent*{.final.} = object + theType*: cint + serial*: culong + display*: PDisplay + screen*: cint + time*: TTime + state*: cuint + button*: cuint + + PXDGAKeyEvent* = ptr TXDGAKeyEvent + TXDGAKeyEvent*{.final.} = object + theType*: cint + serial*: culong + display*: PDisplay + screen*: cint + time*: TTime + state*: cuint + keycode*: cuint + + PXDGAMotionEvent* = ptr TXDGAMotionEvent + TXDGAMotionEvent*{.final.} = object + theType*: cint + serial*: culong + display*: PDisplay + screen*: cint + time*: TTime + state*: cuint + dx*: cint + dy*: cint + + PXDGAEvent* = ptr TXDGAEvent + TXDGAEvent*{.final.} = object + pad*: array[0..23, clong] # sorry you have to cast if you want access + #Case LongInt Of + # 0 : (_type : cint); + # 1 : (xbutton : TXDGAButtonEvent); + # 2 : (xkey : TXDGAKeyEvent); + # 3 : (xmotion : TXDGAMotionEvent); + # 4 : (pad : Array[0..23] Of clong); + + +proc XDGAQueryExtension*(dpy: PDisplay, eventBase: Pcint, erroBase: Pcint): TBool{. + cdecl, dynlib: libXxf86dga, importc.} +proc XDGAQueryVersion*(dpy: PDisplay, majorVersion: Pcint, minorVersion: Pcint): TBool{. + cdecl, dynlib: libXxf86dga, importc.} +proc XDGAQueryModes*(dpy: PDisplay, screen: cint, num: Pcint): PXDGAMode{.cdecl, + dynlib: libXxf86dga, importc.} +proc XDGASetMode*(dpy: PDisplay, screen: cint, mode: cint): PXDGADevice{.cdecl, + dynlib: libXxf86dga, importc.} +proc XDGAOpenFramebuffer*(dpy: PDisplay, screen: cint): TBool{.cdecl, + dynlib: libXxf86dga, importc.} +proc XDGACloseFramebuffer*(dpy: PDisplay, screen: cint){.cdecl, + dynlib: libXxf86dga, importc.} +proc XDGASetViewport*(dpy: PDisplay, screen: cint, x: cint, y: cint, flags: cint){. + cdecl, dynlib: libXxf86dga, importc.} +proc XDGAInstallColormap*(dpy: PDisplay, screen: cint, cmap: TColormap){.cdecl, + dynlib: libXxf86dga, importc.} +proc XDGACreateColormap*(dpy: PDisplay, screen: cint, device: PXDGADevice, + alloc: cint): TColormap{.cdecl, dynlib: libXxf86dga, + importc.} +proc XDGASelectInput*(dpy: PDisplay, screen: cint, event_mask: clong){.cdecl, + dynlib: libXxf86dga, importc.} +proc XDGAFillRectangle*(dpy: PDisplay, screen: cint, x: cint, y: cint, + width: cuint, height: cuint, color: culong){.cdecl, + dynlib: libXxf86dga, importc.} +proc XDGACopyArea*(dpy: PDisplay, screen: cint, srcx: cint, srcy: cint, + width: cuint, height: cuint, dstx: cint, dsty: cint){.cdecl, + dynlib: libXxf86dga, importc.} +proc XDGACopyTransparentArea*(dpy: PDisplay, screen: cint, srcx: cint, + srcy: cint, width: cuint, height: cuint, + dstx: cint, dsty: cint, key: culong){.cdecl, + dynlib: libXxf86dga, importc.} +proc XDGAGetViewportStatus*(dpy: PDisplay, screen: cint): cint{.cdecl, + dynlib: libXxf86dga, importc.} +proc XDGASync*(dpy: PDisplay, screen: cint){.cdecl, dynlib: libXxf86dga, importc.} +proc XDGASetClientVersion*(dpy: PDisplay): TBool{.cdecl, dynlib: libXxf86dga, + importc.} +proc XDGAChangePixmapMode*(dpy: PDisplay, screen: cint, x: Pcint, y: Pcint, + mode: cint){.cdecl, dynlib: libXxf86dga, importc.} +proc XDGAKeyEventToXKeyEvent*(dk: PXDGAKeyEvent, xk: PXKeyEvent){.cdecl, + dynlib: libXxf86dga, importc.} +# implementation diff --git a/tests/deps/x11-1.0/xf86vmode.nim b/tests/deps/x11-1.0/xf86vmode.nim new file mode 100644 index 000000000..547f5cbd2 --- /dev/null +++ b/tests/deps/x11-1.0/xf86vmode.nim @@ -0,0 +1,229 @@ +# $XFree86: xc/include/extensions/xf86vmode.h,v 3.30 2001/05/07 20:09:50 mvojkovi Exp $ +# +# +#Copyright 1995 Kaleb S. KEITHLEY +# +#Permission is hereby granted, free of charge, to any person obtaining +#a copy of this software and associated documentation files (the +#"Software"), to deal in the Software without restriction, including +#without limitation the rights to use, copy, modify, merge, publish, +#distribute, sublicense, and/or sell copies of the Software, and to +#permit persons to whom the Software is furnished to do so, subject to +#the following conditions: +# +#The above copyright notice and this permission notice shall be +#included in all copies or substantial portions of the Software. +# +#THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +#EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +#MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +#IN NO EVENT SHALL Kaleb S. KEITHLEY BE LIABLE FOR ANY CLAIM, DAMAGES +#OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +#ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +#OTHER DEALINGS IN THE SOFTWARE. +# +#Except as contained in this notice, the name of Kaleb S. KEITHLEY +#shall not be used in advertising or otherwise to promote the sale, use +#or other dealings in this Software without prior written authorization +#from Kaleb S. KEITHLEY +# +# +# $Xorg: xf86vmode.h,v 1.3 2000/08/18 04:05:46 coskrey Exp $ +# THIS IS NOT AN X CONSORTIUM STANDARD OR AN X PROJECT TEAM SPECIFICATION + +import + x, xlib + +const + libXxf86vm* = "libXxf86vm.so" + +type + PINT32* = ptr int32 + +const + X_XF86VidModeQueryVersion* = 0 + X_XF86VidModeGetModeLine* = 1 + X_XF86VidModeModModeLine* = 2 + X_XF86VidModeSwitchMode* = 3 + X_XF86VidModeGetMonitor* = 4 + X_XF86VidModeLockModeSwitch* = 5 + X_XF86VidModeGetAllModeLines* = 6 + X_XF86VidModeAddModeLine* = 7 + X_XF86VidModeDeleteModeLine* = 8 + X_XF86VidModeValidateModeLine* = 9 + X_XF86VidModeSwitchToMode* = 10 + X_XF86VidModeGetViewPort* = 11 + X_XF86VidModeSetViewPort* = 12 # new for version 2.x of this extension + X_XF86VidModeGetDotClocks* = 13 + X_XF86VidModeSetClientVersion* = 14 + X_XF86VidModeSetGamma* = 15 + X_XF86VidModeGetGamma* = 16 + X_XF86VidModeGetGammaRamp* = 17 + X_XF86VidModeSetGammaRamp* = 18 + X_XF86VidModeGetGammaRampSize* = 19 + X_XF86VidModeGetPermissions* = 20 + CLKFLAG_PROGRAMABLE* = 1 + +when defined(XF86VIDMODE_EVENTS): + const + XF86VidModeNotify* = 0 + XF86VidModeNumberEvents* = (XF86VidModeNotify + 1) + XF86VidModeNotifyMask* = 0x00000001 + XF86VidModeNonEvent* = 0 + XF86VidModeModeChange* = 1 +else: + const + XF86VidModeNumberEvents* = 0 +const + XF86VidModeBadClock* = 0 + XF86VidModeBadHTimings* = 1 + XF86VidModeBadVTimings* = 2 + XF86VidModeModeUnsuitable* = 3 + XF86VidModeExtensionDisabled* = 4 + XF86VidModeClientNotLocal* = 5 + XF86VidModeZoomLocked* = 6 + XF86VidModeNumberErrors* = (XF86VidModeZoomLocked + 1) + XF86VM_READ_PERMISSION* = 1 + XF86VM_WRITE_PERMISSION* = 2 + +type + PXF86VidModeModeLine* = ptr TXF86VidModeModeLine + TXF86VidModeModeLine*{.final.} = object + hdisplay*: cushort + hsyncstart*: cushort + hsyncend*: cushort + htotal*: cushort + hskew*: cushort + vdisplay*: cushort + vsyncstart*: cushort + vsyncend*: cushort + vtotal*: cushort + flags*: cuint + privsize*: cint + c_private*: PINT32 + + PPPXF86VidModeModeInfo* = ptr PPXF86VidModeModeInfo + PPXF86VidModeModeInfo* = ptr PXF86VidModeModeInfo + PXF86VidModeModeInfo* = ptr TXF86VidModeModeInfo + TXF86VidModeModeInfo*{.final.} = object + dotclock*: cuint + hdisplay*: cushort + hsyncstart*: cushort + hsyncend*: cushort + htotal*: cushort + hskew*: cushort + vdisplay*: cushort + vsyncstart*: cushort + vsyncend*: cushort + vtotal*: cushort + flags*: cuint + privsize*: cint + c_private*: PINT32 + + PXF86VidModeSyncRange* = ptr TXF86VidModeSyncRange + TXF86VidModeSyncRange*{.final.} = object + hi*: cfloat + lo*: cfloat + + PXF86VidModeMonitor* = ptr TXF86VidModeMonitor + TXF86VidModeMonitor*{.final.} = object + vendor*: cstring + model*: cstring + EMPTY*: cfloat + nhsync*: cuchar + hsync*: PXF86VidModeSyncRange + nvsync*: cuchar + vsync*: PXF86VidModeSyncRange + + PXF86VidModeNotifyEvent* = ptr TXF86VidModeNotifyEvent + TXF86VidModeNotifyEvent*{.final.} = object + theType*: cint # of event + serial*: culong # # of last request processed by server + send_event*: TBool # true if this came from a SendEvent req + display*: PDisplay # Display the event was read from + root*: TWindow # root window of event screen + state*: cint # What happened + kind*: cint # What happened + forced*: TBool # extents of new region + time*: TTime # event timestamp + + PXF86VidModeGamma* = ptr TXF86VidModeGamma + TXF86VidModeGamma*{.final.} = object + red*: cfloat # Red Gamma value + green*: cfloat # Green Gamma value + blue*: cfloat # Blue Gamma value + + +when defined(MACROS): + proc XF86VidModeSelectNextMode*(disp: PDisplay, scr: cint): TBool + proc XF86VidModeSelectPrevMode*(disp: PDisplay, scr: cint): TBool +proc XF86VidModeQueryVersion*(dpy: PDisplay, majorVersion: Pcint, + minorVersion: Pcint): TBool{.cdecl, + dynlib: libXxf86vm, importc.} +proc XF86VidModeQueryExtension*(dpy: PDisplay, event_base: Pcint, + error_base: Pcint): TBool{.cdecl, + dynlib: libXxf86vm, importc.} +proc XF86VidModeSetClientVersion*(dpy: PDisplay): TBool{.cdecl, + dynlib: libXxf86vm, importc.} +proc XF86VidModeGetModeLine*(dpy: PDisplay, screen: cint, dotclock: Pcint, + modeline: PXF86VidModeModeLine): TBool{.cdecl, + dynlib: libXxf86vm, importc.} +proc XF86VidModeGetAllModeLines*(dpy: PDisplay, screen: cint, modecount: Pcint, + modelinesPtr: PPPXF86VidModeModeInfo): TBool{. + cdecl, dynlib: libXxf86vm, importc.} +proc XF86VidModeAddModeLine*(dpy: PDisplay, screen: cint, + new_modeline: PXF86VidModeModeInfo, + after_modeline: PXF86VidModeModeInfo): TBool{. + cdecl, dynlib: libXxf86vm, importc.} +proc XF86VidModeDeleteModeLine*(dpy: PDisplay, screen: cint, + modeline: PXF86VidModeModeInfo): TBool{.cdecl, + dynlib: libXxf86vm, importc.} +proc XF86VidModeModModeLine*(dpy: PDisplay, screen: cint, + modeline: PXF86VidModeModeLine): TBool{.cdecl, + dynlib: libXxf86vm, importc.} +proc XF86VidModeValidateModeLine*(dpy: PDisplay, screen: cint, + modeline: PXF86VidModeModeInfo): TStatus{. + cdecl, dynlib: libXxf86vm, importc.} +proc XF86VidModeSwitchMode*(dpy: PDisplay, screen: cint, zoom: cint): TBool{. + cdecl, dynlib: libXxf86vm, importc.} +proc XF86VidModeSwitchToMode*(dpy: PDisplay, screen: cint, + modeline: PXF86VidModeModeInfo): TBool{.cdecl, + dynlib: libXxf86vm, importc.} +proc XF86VidModeLockModeSwitch*(dpy: PDisplay, screen: cint, lock: cint): TBool{. + cdecl, dynlib: libXxf86vm, importc.} +proc XF86VidModeGetMonitor*(dpy: PDisplay, screen: cint, + monitor: PXF86VidModeMonitor): TBool{.cdecl, + dynlib: libXxf86vm, importc.} +proc XF86VidModeGetViewPort*(dpy: PDisplay, screen: cint, x_return: Pcint, + y_return: Pcint): TBool{.cdecl, dynlib: libXxf86vm, + importc.} +proc XF86VidModeSetViewPort*(dpy: PDisplay, screen: cint, x: cint, y: cint): TBool{. + cdecl, dynlib: libXxf86vm, importc.} +proc XF86VidModeGetDotClocks*(dpy: PDisplay, screen: cint, flags_return: Pcint, + number_of_clocks_return: Pcint, + max_dot_clock_return: Pcint, clocks_return: PPcint): TBool{. + cdecl, dynlib: libXxf86vm, importc.} +proc XF86VidModeGetGamma*(dpy: PDisplay, screen: cint, Gamma: PXF86VidModeGamma): TBool{. + cdecl, dynlib: libXxf86vm, importc.} +proc XF86VidModeSetGamma*(dpy: PDisplay, screen: cint, Gamma: PXF86VidModeGamma): TBool{. + cdecl, dynlib: libXxf86vm, importc.} +proc XF86VidModeSetGammaRamp*(dpy: PDisplay, screen: cint, size: cint, + red_array: Pcushort, green_array: Pcushort, + blue_array: Pcushort): TBool{.cdecl, + dynlib: libXxf86vm, importc.} +proc XF86VidModeGetGammaRamp*(dpy: PDisplay, screen: cint, size: cint, + red_array: Pcushort, green_array: Pcushort, + blue_array: Pcushort): TBool{.cdecl, + dynlib: libXxf86vm, importc.} +proc XF86VidModeGetGammaRampSize*(dpy: PDisplay, screen: cint, size: Pcint): TBool{. + cdecl, dynlib: libXxf86vm, importc.} +proc XF86VidModeGetPermissions*(dpy: PDisplay, screen: cint, permissions: Pcint): TBool{. + cdecl, dynlib: libXxf86vm, importc.} +# implementation + +#when defined(MACROS): +proc XF86VidModeSelectNextMode(disp: PDisplay, scr: cint): TBool = + XF86VidModeSwitchMode(disp, scr, 1) + +proc XF86VidModeSelectPrevMode(disp: PDisplay, scr: cint): TBool = + XF86VidModeSwitchMode(disp, scr, - 1) diff --git a/tests/deps/x11-1.0/xi.nim b/tests/deps/x11-1.0/xi.nim new file mode 100644 index 000000000..d1b9f7846 --- /dev/null +++ b/tests/deps/x11-1.0/xi.nim @@ -0,0 +1,307 @@ +# +# $Xorg: XI.h,v 1.4 2001/02/09 02:03:23 xorgcvs Exp $ +# +#************************************************************ +# +#Copyright 1989, 1998 The Open Group +# +#Permission to use, copy, modify, distribute, and sell this software and its +#documentation for any purpose is hereby granted without fee, provided that +#the above copyright notice appear in all copies and that both that +#copyright notice and this permission notice appear in supporting +#documentation. +# +#The above copyright notice and this permission notice shall be included in +#all copies or substantial portions of the Software. +# +#THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +#IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +#FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +#OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +#AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +#CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +#Except as contained in this notice, the name of The Open Group shall not be +#used in advertising or otherwise to promote the sale, use or other dealings +#in this Software without prior written authorization from The Open Group. +# +#Copyright 1989 by Hewlett-Packard Company, Palo Alto, California. +# +# All Rights Reserved +# +#Permission to use, copy, modify, and distribute this software and its +#documentation for any purpose and without fee is hereby granted, +#provided that the above copyright notice appear in all copies and that +#both that copyright notice and this permission notice appear in +#supporting documentation, and that the name of Hewlett-Packard not be +#used in advertising or publicity pertaining to distribution of the +#software without specific, written prior permission. +# +#HEWLETT-PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +#ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +#HEWLETT-PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +#ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +#WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +#ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +#SOFTWARE. +# +#********************************************************/ +# $XFree86: xc/include/extensions/XI.h,v 1.5 2001/12/14 19:53:28 dawes Exp $ +# +# Definitions used by the server, library and client +# +# Pascal Convertion was made by Ido Kannner - kanerido@actcom.net.il +# +#Histroy: +# 2004/10/15 - Fixed a bug of accessing second based records by removing "paced record" and chnaged it to +# "reocrd" only. +# 2004/10/07 - Removed the "uses X;" line. The unit does not need it. +# 2004/10/03 - Conversion from C header to Pascal unit. +# + +const + sz_xGetExtensionVersionReq* = 8 + sz_xGetExtensionVersionReply* = 32 + sz_xListInputDevicesReq* = 4 + sz_xListInputDevicesReply* = 32 + sz_xOpenDeviceReq* = 8 + sz_xOpenDeviceReply* = 32 + sz_xCloseDeviceReq* = 8 + sz_xSetDeviceModeReq* = 8 + sz_xSetDeviceModeReply* = 32 + sz_xSelectExtensionEventReq* = 12 + sz_xGetSelectedExtensionEventsReq* = 8 + sz_xGetSelectedExtensionEventsReply* = 32 + sz_xChangeDeviceDontPropagateListReq* = 12 + sz_xGetDeviceDontPropagateListReq* = 8 + sz_xGetDeviceDontPropagateListReply* = 32 + sz_xGetDeviceMotionEventsReq* = 16 + sz_xGetDeviceMotionEventsReply* = 32 + sz_xChangeKeyboardDeviceReq* = 8 + sz_xChangeKeyboardDeviceReply* = 32 + sz_xChangePointerDeviceReq* = 8 + sz_xChangePointerDeviceReply* = 32 + sz_xGrabDeviceReq* = 20 + sz_xGrabDeviceReply* = 32 + sz_xUngrabDeviceReq* = 12 + sz_xGrabDeviceKeyReq* = 20 + sz_xGrabDeviceKeyReply* = 32 + sz_xUngrabDeviceKeyReq* = 16 + sz_xGrabDeviceButtonReq* = 20 + sz_xGrabDeviceButtonReply* = 32 + sz_xUngrabDeviceButtonReq* = 16 + sz_xAllowDeviceEventsReq* = 12 + sz_xGetDeviceFocusReq* = 8 + sz_xGetDeviceFocusReply* = 32 + sz_xSetDeviceFocusReq* = 16 + sz_xGetFeedbackControlReq* = 8 + sz_xGetFeedbackControlReply* = 32 + sz_xChangeFeedbackControlReq* = 12 + sz_xGetDeviceKeyMappingReq* = 8 + sz_xGetDeviceKeyMappingReply* = 32 + sz_xChangeDeviceKeyMappingReq* = 8 + sz_xGetDeviceModifierMappingReq* = 8 + sz_xSetDeviceModifierMappingReq* = 8 + sz_xSetDeviceModifierMappingReply* = 32 + sz_xGetDeviceButtonMappingReq* = 8 + sz_xGetDeviceButtonMappingReply* = 32 + sz_xSetDeviceButtonMappingReq* = 8 + sz_xSetDeviceButtonMappingReply* = 32 + sz_xQueryDeviceStateReq* = 8 + sz_xQueryDeviceStateReply* = 32 + sz_xSendExtensionEventReq* = 16 + sz_xDeviceBellReq* = 8 + sz_xSetDeviceValuatorsReq* = 8 + sz_xSetDeviceValuatorsReply* = 32 + sz_xGetDeviceControlReq* = 8 + sz_xGetDeviceControlReply* = 32 + sz_xChangeDeviceControlReq* = 8 + sz_xChangeDeviceControlReply* = 32 + +const + INAME* = "XInputExtension" + +const + XI_KEYBOARD* = "KEYBOARD" + XI_MOUSE* = "MOUSE" + XI_TABLET* = "TABLET" + XI_TOUCHSCREEN* = "TOUCHSCREEN" + XI_TOUCHPAD* = "TOUCHPAD" + XI_BARCODE* = "BARCODE" + XI_BUTTONBOX* = "BUTTONBOX" + XI_KNOB_BOX* = "KNOB_BOX" + XI_ONE_KNOB* = "ONE_KNOB" + XI_NINE_KNOB* = "NINE_KNOB" + XI_TRACKBALL* = "TRACKBALL" + XI_QUADRATURE* = "QUADRATURE" + XI_ID_MODULE* = "ID_MODULE" + XI_SPACEBALL* = "SPACEBALL" + XI_DATAGLOVE* = "DATAGLOVE" + XI_EYETRACKER* = "EYETRACKER" + XI_CURSORKEYS* = "CURSORKEYS" + XI_FOOTMOUSE* = "FOOTMOUSE" + +const + Dont_Check* = 0 + XInput_Initial_Release* = 1 + XInput_Add_XDeviceBell* = 2 + XInput_Add_XSetDeviceValuators* = 3 + XInput_Add_XChangeDeviceControl* = 4 + +const + XI_Absent* = 0 + XI_Present* = 1 + +const + XI_Initial_Release_Major* = 1 + XI_Initial_Release_Minor* = 0 + +const + XI_Add_XDeviceBell_Major* = 1 + XI_Add_XDeviceBell_Minor* = 1 + +const + XI_Add_XSetDeviceValuators_Major* = 1 + XI_Add_XSetDeviceValuators_Minor* = 2 + +const + XI_Add_XChangeDeviceControl_Major* = 1 + XI_Add_XChangeDeviceControl_Minor* = 3 + +const + DEVICE_RESOLUTION* = 1 + +const + NoSuchExtension* = 1 + +const + COUNT* = 0 + CREATE* = 1 + +const + NewPointer* = 0 + NewKeyboard* = 1 + +const + XPOINTER* = 0 + XKEYBOARD* = 1 + +const + UseXKeyboard* = 0x000000FF + +const + IsXPointer* = 0 + IsXKeyboard* = 1 + IsXExtensionDevice* = 2 + +const + AsyncThisDevice* = 0 + SyncThisDevice* = 1 + ReplayThisDevice* = 2 + AsyncOtherDevices* = 3 + AsyncAll* = 4 + SyncAll* = 5 + +const + FollowKeyboard* = 3 + RevertToFollowKeyboard* = 3 + +const + DvAccelNum* = int(1) shl 0 + DvAccelDenom* = int(1) shl 1 + DvThreshold* = int(1) shl 2 + +const + DvKeyClickPercent* = int(1) shl 0 + DvPercent* = int(1) shl 1 + DvPitch* = int(1) shl 2 + DvDuration* = int(1) shl 3 + DvLed* = int(1) shl 4 + DvLedMode* = int(1) shl 5 + DvKey* = int(1) shl 6 + DvAutoRepeatMode* = 1 shl 7 + +const + DvString* = int(1) shl 0 + +const + DvInteger* = int(1) shl 0 + +const + DeviceMode* = int(1) shl 0 + Relative* = 0 + Absolute* = 1 # Merged from Metrolink tree for XINPUT stuff + TS_Raw* = 57 + TS_Scaled* = 58 + SendCoreEvents* = 59 + DontSendCoreEvents* = 60 # End of merged section + +const + ProximityState* = int(1) shl 1 + InProximity* = int(0) shl 1 + OutOfProximity* = int(1) shl 1 + +const + AddToList* = 0 + DeleteFromList* = 1 + +const + KeyClass* = 0 + ButtonClass* = 1 + ValuatorClass* = 2 + FeedbackClass* = 3 + ProximityClass* = 4 + FocusClass* = 5 + OtherClass* = 6 + +const + KbdFeedbackClass* = 0 + PtrFeedbackClass* = 1 + StringFeedbackClass* = 2 + IntegerFeedbackClass* = 3 + LedFeedbackClass* = 4 + BellFeedbackClass* = 5 + +const + devicePointerMotionHint* = 0 + deviceButton1Motion* = 1 + deviceButton2Motion* = 2 + deviceButton3Motion* = 3 + deviceButton4Motion* = 4 + deviceButton5Motion* = 5 + deviceButtonMotion* = 6 + deviceButtonGrab* = 7 + deviceOwnerGrabButton* = 8 + noExtensionEvent* = 9 + +const + XI_BadDevice* = 0 + XI_BadEvent* = 1 + XI_BadMode* = 2 + XI_DeviceBusy* = 3 + XI_BadClass* = 4 # Make XEventClass be a CARD32 for 64 bit servers. Don't affect client + # definition of XEventClass since that would be a library interface change. + # See the top of X.h for more _XSERVER64 magic. + # + +when defined(XSERVER64): + type + XEventClass* = CARD32 +else: + type + XEventClass* = int32 +#****************************************************************** +# * +# * Extension version structure. +# * +# + +type + PXExtensionVersion* = ptr TXExtensionVersion + TXExtensionVersion*{.final.} = object + present*: int16 + major_version*: int16 + minor_version*: int16 + + +# implementation diff --git a/tests/deps/x11-1.0/xinerama.nim b/tests/deps/x11-1.0/xinerama.nim new file mode 100644 index 000000000..96f5d7da3 --- /dev/null +++ b/tests/deps/x11-1.0/xinerama.nim @@ -0,0 +1,25 @@ +# Converted from X11/Xinerama.h +import + xlib + +const + xineramaLib = "libXinerama.so" + +type + PXineramaScreenInfo* = ptr TXineramaScreenInfo + TXineramaScreenInfo*{.final.} = object + screen_number*: cint + x_org*: int16 + y_org*: int16 + width*: int16 + height*: int16 + + +proc XineramaQueryExtension*(dpy: PDisplay, event_base: Pcint, error_base: Pcint): TBool{. + cdecl, dynlib: xineramaLib, importc.} +proc XineramaQueryVersion*(dpy: PDisplay, major: Pcint, minor: Pcint): TStatus{. + cdecl, dynlib: xineramaLib, importc.} +proc XineramaIsActive*(dpy: PDisplay): TBool{.cdecl, dynlib: xineramaLib, importc.} +proc XineramaQueryScreens*(dpy: PDisplay, number: Pcint): PXineramaScreenInfo{. + cdecl, dynlib: xineramaLib, importc.} + diff --git a/tests/deps/x11-1.0/xkb.nim b/tests/deps/x11-1.0/xkb.nim new file mode 100644 index 000000000..2ecf17026 --- /dev/null +++ b/tests/deps/x11-1.0/xkb.nim @@ -0,0 +1,2387 @@ +# +# $Xorg: XKB.h,v 1.3 2000/08/18 04:05:45 coskrey Exp $ +#************************************************************ +# $Xorg: XKBstr.h,v 1.3 2000/08/18 04:05:45 coskrey Exp $ +#************************************************************ +# $Xorg: XKBgeom.h,v 1.3 2000/08/18 04:05:45 coskrey Exp $ +#************************************************************ +# +#Copyright (c) 1993 by Silicon Graphics Computer Systems, Inc. +# +#Permission to use, copy, modify, and distribute this +#software and its documentation for any purpose and without +#fee is hereby granted, provided that the above copyright +#notice appear in all copies and that both that copyright +#notice and this permission notice appear in supporting +#documentation, and that the name of Silicon Graphics not be +#used in advertising or publicity pertaining to distribution +#of the software without specific prior written permission. +#Silicon Graphics makes no representation about the suitability +#of this software for any purpose. It is provided "as is" +#without any express or implied warranty. +# +#SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS +#SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +#AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON +#GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL +#DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, +#DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE +#OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH +#THE USE OR PERFORMANCE OF THIS SOFTWARE. +# +#******************************************************** +# $XFree86: xc/include/extensions/XKB.h,v 1.5 2002/11/20 04:49:01 dawes Exp $ +# $XFree86: xc/include/extensions/XKBgeom.h,v 3.9 2002/09/18 17:11:40 tsi Exp $ +# +# Pascal Convertion was made by Ido Kannner - kanerido@actcom.net.il +# +#Thanks: +# I want to thanks to oliebol for putting up with all of the problems that was found +# while translating this code. ;) +# +# I want to thanks #fpc channel in freenode irc, for helping me, and to put up with my +# weird questions ;) +# +# Thanks for mmc in #xlib on freenode irc And so for the channel itself for the helping me to +# understanding some of the problems I had converting this headers and pointing me to resources +# that helped translating this headers. +# +# Ido +# +#History: +# 2004/10/15 - Fixed a bug of accessing second based records by removing "paced record" and +# chnaged it to "reocrd" only. +# 2004/10/04 - 06 - Convertion from the c header of XKBgeom.h. +# 2004/10/03 - Removed the XKBstr_UNIT compiler decleration. Afther the joined files, +# There is no need for it anymore. +# - There is a need to define (for now) XKBgeom (compiler define) in order +# to use the code of it. At this moment, I did not yet converted it to Pascal. +# +# 2004/09/17 - 10/04 - Convertion from the c header of XKBstr. +# +# 2004/10/03 - Joined xkbstr.pas into xkb.pas because of the circular calls problems. +# - Added the history of xkbstr.pas above this addition. +# +# 2004/09/17 - Fixed a wrong convertion number of XkbPerKeyBitArraySize, instead +# of float, it's now converted into integer (as it should have been). +# +# 2004/09/15 - 16 - Convertion from the c header of XKB.h. +# + +import + X, Xlib + +include "x11pragma.nim" + +proc XkbcharToInt*(v: int8): int16 +proc XkbIntTo2chars*(i: int16, h, L: var int8) +proc Xkb2charsToInt*(h, L: int8): int16 + # + # Common data structures and access macros + # +type + PWord* = ptr array[0..64_000, int16] + PByte* = ptr byte + PXkbStatePtr* = ptr TXkbStateRec + TXkbStateRec*{.final.} = object + group*: int8 + locked_group*: int8 + base_group*: int16 + latched_group*: int16 + mods*: int8 + base_mods*: int8 + latched_mods*: int8 + locked_mods*: int8 + compat_state*: int8 + grab_mods*: int8 + compat_grab_mods*: int8 + lookup_mods*: int8 + compat_lookup_mods*: int8 + ptr_buttons*: int16 + + +proc XkbModLocks*(s: PXkbStatePtr): int8 +proc XkbStateMods*(s: PXkbStatePtr): int16 +proc XkbGroupLock*(s: PXkbStatePtr): int8 +proc XkbStateGroup*(s: PXkbStatePtr): int16 +proc XkbStateFieldFromRec*(s: PXkbStatePtr): int +proc XkbGrabStateFromRec*(s: PXkbStatePtr): int +type + PXkbModsPtr* = ptr TXkbModsRec + TXkbModsRec*{.final.} = object + mask*: int8 # effective mods + real_mods*: int8 + vmods*: int16 + + +type + PXkbKTMapEntryPtr* = ptr TXkbKTMapEntryRec + TXkbKTMapEntryRec*{.final.} = object + active*: bool + level*: int8 + mods*: TXkbModsRec + + +type + PXkbKeyTypePtr* = ptr TXkbKeyTypeRec + TXkbKeyTypeRec*{.final.} = object + mods*: TXkbModsRec + num_levels*: int8 + map_count*: int8 + map*: PXkbKTMapEntryPtr + preserve*: PXkbModsPtr + name*: TAtom + level_names*: TAtom + + +proc XkbNumGroups*(g: int16): int16 +proc XkbOutOfRangeGroupInfo*(g: int16): int16 +proc XkbOutOfRangeGroupAction*(g: int16): int16 +proc XkbOutOfRangeGroupNumber*(g: int16): int16 +proc XkbSetGroupInfo*(g, w, n: int16): int16 +proc XkbSetNumGroups*(g, n: int16): int16 + # + # Structures and access macros used primarily by the server + # +type + PXkbBehavior* = ptr TXkbBehavior + TXkbBehavior*{.final.} = object + theType*: int8 + data*: int8 + + +type + PXkbModAction* = ptr TXkbModAction + TXkbModAction*{.final.} = object + theType*: int8 + flags*: int8 + mask*: int8 + real_mods*: int8 + vmods1*: int8 + vmods2*: int8 + + +proc XkbModActionVMods*(a: PXkbModAction): int16 +proc XkbSetModActionVMods*(a: PXkbModAction, v: int8) +type + PXkbGroupAction* = ptr TXkbGroupAction + TXkbGroupAction*{.final.} = object + theType*: int8 + flags*: int8 + group_XXX*: int8 + + +proc XkbSAGroup*(a: PXkbGroupAction): int8 +proc XkbSASetGroupProc*(a: PXkbGroupAction, g: int8) +type + PXkbISOAction* = ptr TXkbISOAction + TXkbISOAction*{.final.} = object + theType*: int8 + flags*: int8 + mask*: int8 + real_mods*: int8 + group_XXX*: int8 + affect*: int8 + vmods1*: int8 + vmods2*: int8 + + +type + PXkbPtrAction* = ptr TXkbPtrAction + TXkbPtrAction*{.final.} = object + theType*: int8 + flags*: int8 + high_XXX*: int8 + low_XXX*: int8 + high_YYY*: int8 + low_YYY*: int8 + + +proc XkbPtrActionX*(a: PXkbPtrAction): int16 +proc XkbPtrActionY*(a: PXkbPtrAction): int16 +proc XkbSetPtrActionX*(a: PXkbPtrAction, x: int8) +proc XkbSetPtrActionY*(a: PXkbPtrAction, y: int8) +type + PXkbPtrBtnAction* = ptr TXkbPtrBtnAction + TXkbPtrBtnAction*{.final.} = object + theType*: int8 + flags*: int8 + count*: int8 + button*: int8 + + +type + PXkbPtrDfltAction* = ptr TXkbPtrDfltAction + TXkbPtrDfltAction*{.final.} = object + theType*: int8 + flags*: int8 + affect*: int8 + valueXXX*: int8 + + +proc XkbSAPtrDfltValue*(a: PXkbPtrDfltAction): int8 +proc XkbSASetPtrDfltValue*(a: PXkbPtrDfltAction, c: pointer) +type + PXkbSwitchScreenAction* = ptr TXkbSwitchScreenAction + TXkbSwitchScreenAction*{.final.} = object + theType*: int8 + flags*: int8 + screenXXX*: int8 + + +proc XkbSAScreen*(a: PXkbSwitchScreenAction): int8 +proc XkbSASetScreen*(a: PXkbSwitchScreenAction, s: pointer) +type + PXkbCtrlsAction* = ptr TXkbCtrlsAction + TXkbCtrlsAction*{.final.} = object + theType*: int8 + flags*: int8 + ctrls3*: int8 + ctrls2*: int8 + ctrls1*: int8 + ctrls0*: int8 + + +proc XkbActionSetCtrls*(a: PXkbCtrlsAction, c: int8) +proc XkbActionCtrls*(a: PXkbCtrlsAction): int16 +type + PXkbMessageAction* = ptr TXkbMessageAction + TXkbMessageAction*{.final.} = object + theType*: int8 + flags*: int8 + message*: array[0..5, char] + + +type + PXkbRedirectKeyAction* = ptr TXkbRedirectKeyAction + TXkbRedirectKeyAction*{.final.} = object + theType*: int8 + new_key*: int8 + mods_mask*: int8 + mods*: int8 + vmods_mask0*: int8 + vmods_mask1*: int8 + vmods0*: int8 + vmods1*: int8 + + +proc XkbSARedirectVMods*(a: PXkbRedirectKeyAction): int16 +proc XkbSARedirectSetVMods*(a: PXkbRedirectKeyAction, m: int8) +proc XkbSARedirectVModsMask*(a: PXkbRedirectKeyAction): int16 +proc XkbSARedirectSetVModsMask*(a: PXkbRedirectKeyAction, m: int8) +type + PXkbDeviceBtnAction* = ptr TXkbDeviceBtnAction + TXkbDeviceBtnAction*{.final.} = object + theType*: int8 + flags*: int8 + count*: int8 + button*: int8 + device*: int8 + + +type + PXkbDeviceValuatorAction* = ptr TXkbDeviceValuatorAction + TXkbDeviceValuatorAction*{.final.} = object # + # Macros to classify key actions + # + theType*: int8 + device*: int8 + v1_what*: int8 + v1_ndx*: int8 + v1_value*: int8 + v2_what*: int8 + v2_ndx*: int8 + v2_value*: int8 + + +const + XkbAnyActionDataSize* = 7 + +type + PXkbAnyAction* = ptr TXkbAnyAction + TXkbAnyAction*{.final.} = object + theType*: int8 + data*: array[0..XkbAnyActionDataSize - 1, int8] + + +proc XkbIsModAction*(a: PXkbAnyAction): bool +proc XkbIsGroupAction*(a: PXkbAnyAction): bool +proc XkbIsPtrAction*(a: PXkbAnyAction): bool +type + PXkbAction* = ptr TXkbAction + TXkbAction*{.final.} = object # + # XKB request codes, used in: + # - xkbReqType field of all requests + # - requestMinor field of some events + # + any*: TXkbAnyAction + mods*: TXkbModAction + group*: TXkbGroupAction + iso*: TXkbISOAction + thePtr*: TXkbPtrAction + btn*: TXkbPtrBtnAction + dflt*: TXkbPtrDfltAction + screen*: TXkbSwitchScreenAction + ctrls*: TXkbCtrlsAction + msg*: TXkbMessageAction + redirect*: TXkbRedirectKeyAction + devbtn*: TXkbDeviceBtnAction + devval*: TXkbDeviceValuatorAction + theType*: int8 + + +const + X_kbUseExtension* = 0 + X_kbSelectEvents* = 1 + X_kbBell* = 3 + X_kbGetState* = 4 + X_kbLatchLockState* = 5 + X_kbGetControls* = 6 + X_kbSetControls* = 7 + X_kbGetMap* = 8 + X_kbSetMap* = 9 + X_kbGetCompatMap* = 10 + X_kbSetCompatMap* = 11 + X_kbGetIndicatorState* = 12 + X_kbGetIndicatorMap* = 13 + X_kbSetIndicatorMap* = 14 + X_kbGetNamedIndicator* = 15 + X_kbSetNamedIndicator* = 16 + X_kbGetNames* = 17 + X_kbSetNames* = 18 + X_kbGetGeometry* = 19 + X_kbSetGeometry* = 20 + X_kbPerClientFlags* = 21 + X_kbListComponents* = 22 + X_kbGetKbdByName* = 23 + X_kbGetDeviceInfo* = 24 + X_kbSetDeviceInfo* = 25 + X_kbSetDebuggingFlags* = 101 # + # In the X sense, XKB reports only one event. + # The type field of all XKB events is XkbEventCode + # + +const + XkbEventCode* = 0 + XkbNumberEvents* = XkbEventCode + 1 # + # XKB has a minor event code so it can use one X event code for + # multiple purposes. + # - reported in the xkbType field of all XKB events. + # - XkbSelectEventDetails: Indicates the event for which event details + # are being changed + # + +const + XkbNewKeyboardNotify* = 0 + XkbMapNotify* = 1 + XkbStateNotify* = 2 + XkbControlsNotify* = 3 + XkbIndicatorStateNotify* = 4 + XkbIndicatorMapNotify* = 5 + XkbNamesNotify* = 6 + XkbCompatMapNotify* = 7 + XkbBellNotify* = 8 + XkbActionMessage* = 9 + XkbAccessXNotify* = 10 + XkbExtensionDeviceNotify* = 11 # + # Event Mask: + # - XkbSelectEvents: Specifies event interest. + # + +const + XkbNewKeyboardNotifyMask* = int(1) shl 0 + XkbMapNotifyMask* = int(1) shl 1 + XkbStateNotifyMask* = int(1) shl 2 + XkbControlsNotifyMask* = int(1) shl 3 + XkbIndicatorStateNotifyMask* = int(1) shl 4 + XkbIndicatorMapNotifyMask* = int(1) shl 5 + XkbNamesNotifyMask* = int(1) shl 6 + XkbCompatMapNotifyMask* = int(1) shl 7 + XkbBellNotifyMask* = int(1) shl 8 + XkbActionMessageMask* = int(1) shl 9 + XkbAccessXNotifyMask* = int(1) shl 10 + XkbExtensionDeviceNotifyMask* = int(1) shl 11 + XkbAllEventsMask* = 0x00000FFF # + # NewKeyboardNotify event details: + # + +const + XkbNKN_KeycodesMask* = int(1) shl 0 + XkbNKN_GeometryMask* = int(1) shl 1 + XkbNKN_DeviceIDMask* = int(1) shl 2 + XkbAllNewKeyboardEventsMask* = 0x00000007 # + # AccessXNotify event types: + # - The 'what' field of AccessXNotify events reports the + # reason that the event was generated. + # + +const + XkbAXN_SKPress* = 0 + XkbAXN_SKAccept* = 1 + XkbAXN_SKReject* = 2 + XkbAXN_SKRelease* = 3 + XkbAXN_BKAccept* = 4 + XkbAXN_BKReject* = 5 + XkbAXN_AXKWarning* = 6 # + # AccessXNotify details: + # - Used as an event detail mask to limit the conditions under which + # AccessXNotify events are reported + # + +const + XkbAXN_SKPressMask* = int(1) shl 0 + XkbAXN_SKAcceptMask* = int(1) shl 1 + XkbAXN_SKRejectMask* = int(1) shl 2 + XkbAXN_SKReleaseMask* = int(1) shl 3 + XkbAXN_BKAcceptMask* = int(1) shl 4 + XkbAXN_BKRejectMask* = int(1) shl 5 + XkbAXN_AXKWarningMask* = int(1) shl 6 + XkbAllAccessXEventsMask* = 0x0000000F # + # State detail mask: + # - The 'changed' field of StateNotify events reports which of + # the keyboard state components have changed. + # - Used as an event detail mask to limit the conditions under + # which StateNotify events are reported. + # + +const + XkbModifierStateMask* = int(1) shl 0 + XkbModifierBaseMask* = int(1) shl 1 + XkbModifierLatchMask* = int(1) shl 2 + XkbModifierLockMask* = int(1) shl 3 + XkbGroupStateMask* = int(1) shl 4 + XkbGroupBaseMask* = int(1) shl 5 + XkbGroupLatchMask* = int(1) shl 6 + XkbGroupLockMask* = int(1) shl 7 + XkbCompatStateMask* = int(1) shl 8 + XkbGrabModsMask* = int(1) shl 9 + XkbCompatGrabModsMask* = int(1) shl 10 + XkbLookupModsMask* = int(1) shl 11 + XkbCompatLookupModsMask* = int(1) shl 12 + XkbPointerButtonMask* = int(1) shl 13 + XkbAllStateComponentsMask* = 0x00003FFF # + # Controls detail masks: + # The controls specified in XkbAllControlsMask: + # - The 'changed' field of ControlsNotify events reports which of + # the keyboard controls have changed. + # - The 'changeControls' field of the SetControls request specifies + # the controls for which values are to be changed. + # - Used as an event detail mask to limit the conditions under + # which ControlsNotify events are reported. + # + # The controls specified in the XkbAllBooleanCtrlsMask: + # - The 'enabledControls' field of ControlsNotify events reports the + # current status of the boolean controls. + # - The 'enabledControlsChanges' field of ControlsNotify events reports + # any boolean controls that have been turned on or off. + # - The 'affectEnabledControls' and 'enabledControls' fields of the + # kbSetControls request change the set of enabled controls. + # - The 'accessXTimeoutMask' and 'accessXTimeoutValues' fields of + # an XkbControlsRec specify the controls to be changed if the keyboard + # times out and the values to which they should be changed. + # - The 'autoCtrls' and 'autoCtrlsValues' fields of the PerClientFlags + # request specifies the specify the controls to be reset when the + # client exits and the values to which they should be reset. + # - The 'ctrls' field of an indicator map specifies the controls + # that drive the indicator. + # - Specifies the boolean controls affected by the SetControls and + # LockControls key actions. + # + +const + XkbRepeatKeysMask* = int(1) shl 0 + XkbSlowKeysMask* = int(1) shl 1 + XkbBounceKeysMask* = int(1) shl 2 + XkbStickyKeysMask* = int(1) shl 3 + XkbMouseKeysMask* = int(1) shl 4 + XkbMouseKeysAccelMask* = int(1) shl 5 + XkbAccessXKeysMask* = int(1) shl 6 + XkbAccessXTimeoutMask* = int(1) shl 7 + XkbAccessXFeedbackMask* = int(1) shl 8 + XkbAudibleBellMask* = int(1) shl 9 + XkbOverlay1Mask* = int(1) shl 10 + XkbOverlay2Mask* = int(1) shl 11 + XkbIgnoreGroupLockMask* = int(1) shl 12 + XkbGroupsWrapMask* = int(1) shl 27 + XkbInternalModsMask* = int(1) shl 28 + XkbIgnoreLockModsMask* = int(1) shl 29 + XkbPerKeyRepeatMask* = int(1) shl 30 + XkbControlsEnabledMask* = int(1) shl 31 + XkbAccessXOptionsMask* = XkbStickyKeysMask or XkbAccessXFeedbackMask + XkbAllBooleanCtrlsMask* = 0x00001FFF + XkbAllControlsMask* = 0xF8001FFF # + # Compatibility Map Compontents: + # - Specifies the components to be allocated in XkbAllocCompatMap. + # + +const + XkbSymInterpMask* = 1 shl 0 + XkbGroupCompatMask* = 1 shl 1 + XkbAllCompatMask* = 0x00000003 # + # Assorted constants and limits. + # + +const + XkbAllIndicatorsMask* = 0xFFFFFFFF # + # Map components masks: + # Those in AllMapComponentsMask: + # - Specifies the individual fields to be loaded or changed for the + # GetMap and SetMap requests. + # Those in ClientInfoMask: + # - Specifies the components to be allocated by XkbAllocClientMap. + # Those in ServerInfoMask: + # - Specifies the components to be allocated by XkbAllocServerMap. + # + +const + XkbKeyTypesMask* = 1 shl 0 + XkbKeySymsMask* = 1 shl 1 + XkbModifierMapMask* = 1 shl 2 + XkbExplicitComponentsMask* = 1 shl 3 + XkbKeyActionsMask* = 1 shl 4 + XkbKeyBehaviorsMask* = 1 shl 5 + XkbVirtualModsMask* = 1 shl 6 + XkbVirtualModMapMask* = 1 shl 7 + XkbAllClientInfoMask* = XkbKeyTypesMask or XkbKeySymsMask or + XkbModifierMapMask + XkbAllServerInfoMask* = XkbExplicitComponentsMask or XkbKeyActionsMask or + XkbKeyBehaviorsMask or XkbVirtualModsMask or XkbVirtualModMapMask + XkbAllMapComponentsMask* = XkbAllClientInfoMask or XkbAllServerInfoMask # + # Names component mask: + # - Specifies the names to be loaded or changed for the GetNames and + # SetNames requests. + # - Specifies the names that have changed in a NamesNotify event. + # - Specifies the names components to be allocated by XkbAllocNames. + # + +const + XkbKeycodesNameMask* = 1 shl 0 + XkbGeometryNameMask* = 1 shl 1 + XkbSymbolsNameMask* = 1 shl 2 + XkbPhysSymbolsNameMask* = 1 shl 3 + XkbTypesNameMask* = 1 shl 4 + XkbCompatNameMask* = 1 shl 5 + XkbKeyTypeNamesMask* = 1 shl 6 + XkbKTLevelNamesMask* = 1 shl 7 + XkbIndicatorNamesMask* = 1 shl 8 + XkbKeyNamesMask* = 1 shl 9 + XkbKeyAliasesMask* = 1 shl 10 + XkbVirtualModNamesMask* = 1 shl 11 + XkbGroupNamesMask* = 1 shl 12 + XkbRGNamesMask* = 1 shl 13 + XkbComponentNamesMask* = 0x0000003F + XkbAllNamesMask* = 0x00003FFF # + # Miscellaneous event details: + # - event detail masks for assorted events that don't reall + # have any details. + # + +const + XkbAllStateEventsMask* = XkbAllStateComponentsMask + XkbAllMapEventsMask* = XkbAllMapComponentsMask + XkbAllControlEventsMask* = XkbAllControlsMask + XkbAllIndicatorEventsMask* = XkbAllIndicatorsMask + XkbAllNameEventsMask* = XkbAllNamesMask + XkbAllCompatMapEventsMask* = XkbAllCompatMask + XkbAllBellEventsMask* = int(1) shl 0 + XkbAllActionMessagesMask* = int(1) shl 0 # + # XKB reports one error: BadKeyboard + # A further reason for the error is encoded into to most significant + # byte of the resourceID for the error: + # XkbErr_BadDevice - the device in question was not found + # XkbErr_BadClass - the device was found but it doesn't belong to + # the appropriate class. + # XkbErr_BadId - the device was found and belongs to the right + # class, but not feedback with a matching id was + # found. + # The low byte of the resourceID for this error contains the device + # id, class specifier or feedback id that failed. + # + +const + XkbKeyboard* = 0 + XkbNumberErrors* = 1 + XkbErr_BadDevice* = 0x000000FF + XkbErr_BadClass* = 0x000000FE + XkbErr_BadId* = 0x000000FD # + # Keyboard Components Mask: + # - Specifies the components that follow a GetKeyboardByNameReply + # + +const + XkbClientMapMask* = int(1) shl 0 + XkbServerMapMask* = int(1) shl 1 + XkbCompatMapMask* = int(1) shl 2 + XkbIndicatorMapMask* = int(1) shl 3 + XkbNamesMask* = int(1) shl 4 + XkbGeometryMask* = int(1) shl 5 + XkbControlsMask* = int(1) shl 6 + XkbAllComponentsMask* = 0x0000007F # + # AccessX Options Mask + # - The 'accessXOptions' field of an XkbControlsRec specifies the + # AccessX options that are currently in effect. + # - The 'accessXTimeoutOptionsMask' and 'accessXTimeoutOptionsValues' + # fields of an XkbControlsRec specify the Access X options to be + # changed if the keyboard times out and the values to which they + # should be changed. + # + +const + XkbAX_SKPressFBMask* = int(1) shl 0 + XkbAX_SKAcceptFBMask* = int(1) shl 1 + XkbAX_FeatureFBMask* = int(1) shl 2 + XkbAX_SlowWarnFBMask* = int(1) shl 3 + XkbAX_IndicatorFBMask* = int(1) shl 4 + XkbAX_StickyKeysFBMask* = int(1) shl 5 + XkbAX_TwoKeysMask* = int(1) shl 6 + XkbAX_LatchToLockMask* = int(1) shl 7 + XkbAX_SKReleaseFBMask* = int(1) shl 8 + XkbAX_SKRejectFBMask* = int(1) shl 9 + XkbAX_BKRejectFBMask* = int(1) shl 10 + XkbAX_DumbBellFBMask* = int(1) shl 11 + XkbAX_FBOptionsMask* = 0x00000F3F + XkbAX_SKOptionsMask* = 0x000000C0 + XkbAX_AllOptionsMask* = 0x00000FFF # + # XkbUseCoreKbd is used to specify the core keyboard without having + # to look up its X input extension identifier. + # XkbUseCorePtr is used to specify the core pointer without having + # to look up its X input extension identifier. + # XkbDfltXIClass is used to specify "don't care" any place that the + # XKB protocol is looking for an X Input Extension + # device class. + # XkbDfltXIId is used to specify "don't care" any place that the + # XKB protocol is looking for an X Input Extension + # feedback identifier. + # XkbAllXIClasses is used to get information about all device indicators, + # whether they're part of the indicator feedback class + # or the keyboard feedback class. + # XkbAllXIIds is used to get information about all device indicator + # feedbacks without having to list them. + # XkbXINone is used to indicate that no class or id has been specified. + # XkbLegalXILedClass(c) True if 'c' specifies a legal class with LEDs + # XkbLegalXIBellClass(c) True if 'c' specifies a legal class with bells + # XkbExplicitXIDevice(d) True if 'd' explicitly specifies a device + # XkbExplicitXIClass(c) True if 'c' explicitly specifies a device class + # XkbExplicitXIId(c) True if 'i' explicitly specifies a device id + # XkbSingleXIClass(c) True if 'c' specifies exactly one device class, + # including the default. + # XkbSingleXIId(i) True if 'i' specifies exactly one device + # identifier, including the default. + # + +const + XkbUseCoreKbd* = 0x00000100 + XkbUseCorePtr* = 0x00000200 + XkbDfltXIClass* = 0x00000300 + XkbDfltXIId* = 0x00000400 + XkbAllXIClasses* = 0x00000500 + XkbAllXIIds* = 0x00000600 + XkbXINone* = 0x0000FF00 + +proc XkbLegalXILedClass*(c: int): bool +proc XkbLegalXIBellClass*(c: int): bool +proc XkbExplicitXIDevice*(c: int): bool +proc XkbExplicitXIClass*(c: int): bool +proc XkbExplicitXIId*(c: int): bool +proc XkbSingleXIClass*(c: int): bool +proc XkbSingleXIId*(c: int): bool +const + XkbNoModifier* = 0x000000FF + XkbNoShiftLevel* = 0x000000FF + XkbNoShape* = 0x000000FF + XkbNoIndicator* = 0x000000FF + XkbNoModifierMask* = 0 + XkbAllModifiersMask* = 0x000000FF + XkbAllVirtualModsMask* = 0x0000FFFF + XkbNumKbdGroups* = 4 + XkbMaxKbdGroup* = XkbNumKbdGroups - 1 + XkbMaxMouseKeysBtn* = 4 # + # Group Index and Mask: + # - Indices into the kt_index array of a key type. + # - Mask specifies types to be changed for XkbChangeTypesOfKey + # + +const + XkbGroup1Index* = 0 + XkbGroup2Index* = 1 + XkbGroup3Index* = 2 + XkbGroup4Index* = 3 + XkbAnyGroup* = 254 + XkbAllGroups* = 255 + XkbGroup1Mask* = 1 shl 0 + XkbGroup2Mask* = 1 shl 1 + XkbGroup3Mask* = 1 shl 2 + XkbGroup4Mask* = 1 shl 3 + XkbAnyGroupMask* = 1 shl 7 + XkbAllGroupsMask* = 0x0000000F # + # BuildCoreState: Given a keyboard group and a modifier state, + # construct the value to be reported an event. + # GroupForCoreState: Given the state reported in an event, + # determine the keyboard group. + # IsLegalGroup: Returns TRUE if 'g' is a valid group index. + # + +proc XkbBuildCoreState*(m, g: int): int +proc XkbGroupForCoreState*(s: int): int +proc XkbIsLegalGroup*(g: int): bool + # + # GroupsWrap values: + # - The 'groupsWrap' field of an XkbControlsRec specifies the + # treatment of out of range groups. + # - Bits 6 and 7 of the group info field of a key symbol map + # specify the interpretation of out of range groups for the + # corresponding key. + # +const + XkbWrapIntoRange* = 0x00000000 + XkbClampIntoRange* = 0x00000040 + XkbRedirectIntoRange* = 0x00000080 # + # Action flags: Reported in the 'flags' field of most key actions. + # Interpretation depends on the type of the action; not all actions + # accept all flags. + # + # Option Used for Actions + # ------ ---------------- + # ClearLocks SetMods, LatchMods, SetGroup, LatchGroup + # LatchToLock SetMods, LatchMods, SetGroup, LatchGroup + # LockNoLock LockMods, ISOLock, LockPtrBtn, LockDeviceBtn + # LockNoUnlock LockMods, ISOLock, LockPtrBtn, LockDeviceBtn + # UseModMapMods SetMods, LatchMods, LockMods, ISOLock + # GroupAbsolute SetGroup, LatchGroup, LockGroup, ISOLock + # UseDfltButton PtrBtn, LockPtrBtn + # NoAcceleration MovePtr + # MoveAbsoluteX MovePtr + # MoveAbsoluteY MovePtr + # ISODfltIsGroup ISOLock + # ISONoAffectMods ISOLock + # ISONoAffectGroup ISOLock + # ISONoAffectPtr ISOLock + # ISONoAffectCtrls ISOLock + # MessageOnPress ActionMessage + # MessageOnRelease ActionMessage + # MessageGenKeyEvent ActionMessage + # AffectDfltBtn SetPtrDflt + # DfltBtnAbsolute SetPtrDflt + # SwitchApplication SwitchScreen + # SwitchAbsolute SwitchScreen + # + +const + XkbSA_ClearLocks* = int(1) shl 0 + XkbSA_LatchToLock* = int(1) shl 1 + XkbSA_LockNoLock* = int(1) shl 0 + XkbSA_LockNoUnlock* = int(1) shl 1 + XkbSA_UseModMapMods* = int(1) shl 2 + XkbSA_GroupAbsolute* = int(1) shl 2 + XkbSA_UseDfltButton* = 0 + XkbSA_NoAcceleration* = int(1) shl 0 + XkbSA_MoveAbsoluteX* = int(1) shl 1 + XkbSA_MoveAbsoluteY* = int(1) shl 2 + XkbSA_ISODfltIsGroup* = int(1) shl 7 + XkbSA_ISONoAffectMods* = int(1) shl 6 + XkbSA_ISONoAffectGroup* = int(1) shl 5 + XkbSA_ISONoAffectPtr* = int(1) shl 4 + XkbSA_ISONoAffectCtrls* = int(1) shl 3 + XkbSA_ISOAffectMask* = 0x00000078 + XkbSA_MessageOnPress* = int(1) shl 0 + XkbSA_MessageOnRelease* = int(1) shl 1 + XkbSA_MessageGenKeyEvent* = int(1) shl 2 + XkbSA_AffectDfltBtn* = 1 + XkbSA_DfltBtnAbsolute* = int(1) shl 2 + XkbSA_SwitchApplication* = int(1) shl 0 + XkbSA_SwitchAbsolute* = int(1) shl 2 # + # The following values apply to the SA_DeviceValuator + # action only. Valuator operations specify the action + # to be taken. Values specified in the action are + # multiplied by 2^scale before they are applied. + # + +const + XkbSA_IgnoreVal* = 0x00000000 + XkbSA_SetValMin* = 0x00000010 + XkbSA_SetValCenter* = 0x00000020 + XkbSA_SetValMax* = 0x00000030 + XkbSA_SetValRelative* = 0x00000040 + XkbSA_SetValAbsolute* = 0x00000050 + XkbSA_ValOpMask* = 0x00000070 + XkbSA_ValScaleMask* = 0x00000007 + +proc XkbSA_ValOp*(a: int): int +proc XkbSA_ValScale*(a: int): int + # + # Action types: specifies the type of a key action. Reported in the + # type field of all key actions. + # +const + XkbSA_NoAction* = 0x00000000 + XkbSA_SetMods* = 0x00000001 + XkbSA_LatchMods* = 0x00000002 + XkbSA_LockMods* = 0x00000003 + XkbSA_SetGroup* = 0x00000004 + XkbSA_LatchGroup* = 0x00000005 + XkbSA_LockGroup* = 0x00000006 + XkbSA_MovePtr* = 0x00000007 + XkbSA_PtrBtn* = 0x00000008 + XkbSA_LockPtrBtn* = 0x00000009 + XkbSA_SetPtrDflt* = 0x0000000A + XkbSA_ISOLock* = 0x0000000B + XkbSA_Terminate* = 0x0000000C + XkbSA_SwitchScreen* = 0x0000000D + XkbSA_SetControls* = 0x0000000E + XkbSA_LockControls* = 0x0000000F + XkbSA_ActionMessage* = 0x00000010 + XkbSA_RedirectKey* = 0x00000011 + XkbSA_DeviceBtn* = 0x00000012 + XkbSA_LockDeviceBtn* = 0x00000013 + XkbSA_DeviceValuator* = 0x00000014 + XkbSA_LastAction* = XkbSA_DeviceValuator + XkbSA_NumActions* = XkbSA_LastAction + 1 + +const + XkbSA_XFree86Private* = 0x00000086 +# +# Specifies the key actions that clear latched groups or modifiers. +# + +const ##define XkbSA_BreakLatch \ + # ((1<>13)&0x3) + result = (s shr 13) and 0x00000003 + +proc XkbIsLegalGroup(g: int): bool = + ##define XkbIsLegalGroup(g) (((g)>=0)&&((g)= 0) and (g < XkbNumKbdGroups) + +proc XkbSA_ValOp(a: int): int = + ##define XkbSA_ValOp(a) ((a)&XkbSA_ValOpMask) + result = a and XkbSA_ValOpMask + +proc XkbSA_ValScale(a: int): int = + ##define XkbSA_ValScale(a) ((a)&XkbSA_ValScaleMask) + result = a and XkbSA_ValScaleMask + +proc XkbIsModAction(a: PXkbAnyAction): bool = + ##define XkbIsModAction(a) (((a)->type>=Xkb_SASetMods)&&((a)->type<=XkbSA_LockMods)) + result = (ze(a.theType) >= XkbSA_SetMods) and (ze(a.theType) <= XkbSA_LockMods) + +proc XkbIsGroupAction(a: PXkbAnyAction): bool = + ##define XkbIsGroupAction(a) (((a)->type>=XkbSA_SetGroup)&&((a)->type<=XkbSA_LockGroup)) + result = (ze(a.theType) >= XkbSA_SetGroup) or (ze(a.theType) <= XkbSA_LockGroup) + +proc XkbIsPtrAction(a: PXkbAnyAction): bool = + ##define XkbIsPtrAction(a) (((a)->type>=XkbSA_MovePtr)&&((a)->type<=XkbSA_SetPtrDflt)) + result = (ze(a.theType) >= XkbSA_MovePtr) and + (ze(a.theType) <= XkbSA_SetPtrDflt) + +proc XkbIsLegalKeycode(k: int): bool = + ##define XkbIsLegalKeycode(k) (((k)>=XkbMinLegalKeyCode)&&((k)<=XkbMaxLegalKeyCode)) + result = (k >= XkbMinLegalKeyCode) and (k <= XkbMaxLegalKeyCode) + +proc XkbShiftLevel(n: int8): int8 = + ##define XkbShiftLevel(n) ((n)-1) + result = n - 1'i8 + +proc XkbShiftLevelMask(n: int8): int8 = + ##define XkbShiftLevelMask(n) (1<<((n)-1)) + result = 1'i8 shl (n - 1'i8) + +proc XkbcharToInt(v: int8): int16 = + ##define XkbcharToInt(v) ((v)&0x80?(int)((v)|(~0xff)):(int)((v)&0x7f)) + if ((v and 0x80'i8) != 0'i8): result = v or (not 0xFF'i16) + else: result = int16(v and 0x7F'i8) + +proc XkbIntTo2chars(i: int16, h, L: var int8) = + ##define XkbIntTo2chars(i,h,l) (((h)=((i>>8)&0xff)),((l)=((i)&0xff))) + h = toU8((i shr 8'i16) and 0x00FF'i16) + L = toU8(i and 0xFF'i16) + +proc Xkb2charsToInt(h, L: int8): int16 = + when defined(cpu64): + ##define Xkb2charsToInt(h,l) ((h)&0x80?(int)(((h)<<8)|(l)|(~0xffff)): (int)(((h)<<8)|(l)&0x7fff)) + if (h and 0x80'i8) != 0'i8: + result = toU16((ze(h) shl 8) or ze(L) or not 0x0000FFFF) + else: + result = toU16((ze(h) shl 8) or ze(L) and 0x00007FFF) + else: + ##define Xkb2charsToInt(h,l) ((short)(((h)<<8)|(l))) + result = toU16(ze(h) shl 8 or ze(L)) + +proc XkbModLocks(s: PXkbStatePtr): int8 = + ##define XkbModLocks(s) ((s)->locked_mods) + result = s.locked_mods + +proc XkbStateMods(s: PXkbStatePtr): int16 = + ##define XkbStateMods(s) ((s)->base_mods|(s)->latched_mods|XkbModLocks(s)) + result = s.base_mods or s.latched_mods or XkbModLocks(s) + +proc XkbGroupLock(s: PXkbStatePtr): int8 = + ##define XkbGroupLock(s) ((s)->locked_group) + result = s.locked_group + +proc XkbStateGroup(s: PXkbStatePtr): int16 = + ##define XkbStateGroup(s) ((s)->base_group+(s)->latched_group+XkbGroupLock(s)) + result = s.base_group + (s.latched_group) + XkbGroupLock(s) + +proc XkbStateFieldFromRec(s: PXkbStatePtr): int = + ##define XkbStateFieldFromRec(s) XkbBuildCoreState((s)->lookup_mods,(s)->group) + result = XkbBuildCoreState(s.lookup_mods, s.group) + +proc XkbGrabStateFromRec(s: PXkbStatePtr): int = + ##define XkbGrabStateFromRec(s) XkbBuildCoreState((s)->grab_mods,(s)->group) + result = XkbBuildCoreState(s.grab_mods, s.group) + +proc XkbNumGroups(g: int16): int16 = + ##define XkbNumGroups(g) ((g)&0x0f) + result = g and 0x0000000F'i16 + +proc XkbOutOfRangeGroupInfo(g: int16): int16 = + ##define XkbOutOfRangeGroupInfo(g) ((g)&0xf0) + result = g and 0x000000F0'i16 + +proc XkbOutOfRangeGroupAction(g: int16): int16 = + ##define XkbOutOfRangeGroupAction(g) ((g)&0xc0) + result = g and 0x000000C0'i16 + +proc XkbOutOfRangeGroupNumber(g: int16): int16 = + ##define XkbOutOfRangeGroupNumber(g) (((g)&0x30)>>4) + result = (g and 0x00000030'i16) shr 4'i16 + +proc XkbSetGroupInfo(g, w, n: int16): int16 = + ##define XkbSetGroupInfo(g,w,n) (((w)&0xc0)|(((n)&3)<<4)|((g)&0x0f)) + result = (w and 0x000000C0'i16) or + ((n and 3'i16) shl 4'i16) or (g and 0x0000000F'i16) + +proc XkbSetNumGroups(g, n: int16): int16 = + ##define XkbSetNumGroups(g,n) (((g)&0xf0)|((n)&0x0f)) + result = (g and 0x000000F0'i16) or (n and 0x0000000F'i16) + +proc XkbModActionVMods(a: PXkbModAction): int16 = + ##define XkbModActionVMods(a) ((short)(((a)->vmods1<<8)|((a)->vmods2))) + result = toU16((ze(a.vmods1) shl 8) or ze(a.vmods2)) + +proc XkbSetModActionVMods(a: PXkbModAction, v: int8) = + ##define XkbSetModActionVMods(a,v) (((a)->vmods1=(((v)>>8)&0xff)),(a)->vmods2=((v)&0xff)) + a.vmods1 = toU8((ze(v) shr 8) and 0x000000FF) + a.vmods2 = toU8(ze(v) and 0x000000FF) + +proc XkbSAGroup(a: PXkbGroupAction): int8 = + ##define XkbSAGroup(a) (XkbcharToInt((a)->group_XXX)) + result = int8(XkbcharToInt(a.group_XXX)) + +proc XkbSASetGroupProc(a: PXkbGroupAction, g: int8) = + ##define XkbSASetGroup(a,g) ((a)->group_XXX=(g)) + a.group_XXX = g + +proc XkbPtrActionX(a: PXkbPtrAction): int16 = + ##define XkbPtrActionX(a) (Xkb2charsToInt((a)->high_XXX,(a)->low_XXX)) + result = int16(Xkb2charsToInt(a.high_XXX, a.low_XXX)) + +proc XkbPtrActionY(a: PXkbPtrAction): int16 = + ##define XkbPtrActionY(a) (Xkb2charsToInt((a)->high_YYY,(a)->low_YYY)) + result = int16(Xkb2charsToInt(a.high_YYY, a.low_YYY)) + +proc XkbSetPtrActionX(a: PXkbPtrAction, x: int8) = + ##define XkbSetPtrActionX(a,x) (XkbIntTo2chars(x,(a)->high_XXX,(a)->low_XXX)) + XkbIntTo2chars(x, a.high_XXX, a.low_XXX) + +proc XkbSetPtrActionY(a: PXkbPtrAction, y: int8) = + ##define XkbSetPtrActionY(a,y) (XkbIntTo2chars(y,(a)->high_YYY,(a)->low_YYY)) + XkbIntTo2chars(y, a.high_YYY, a.low_YYY) + +proc XkbSAPtrDfltValue(a: PXkbPtrDfltAction): int8 = + ##define XkbSAPtrDfltValue(a) (XkbcharToInt((a)->valueXXX)) + result = int8(XkbcharToInt(a.valueXXX)) + +proc XkbSASetPtrDfltValue(a: PXkbPtrDfltAction, c: pointer) = + ##define XkbSASetPtrDfltValue(a,c) ((a)->valueXXX= ((c)&0xff)) + a.valueXXX = toU8(cast[int](c)) + +proc XkbSAScreen(a: PXkbSwitchScreenAction): int8 = + ##define XkbSAScreen(a) (XkbcharToInt((a)->screenXXX)) + result = toU8(XkbcharToInt(a.screenXXX)) + +proc XkbSASetScreen(a: PXkbSwitchScreenAction, s: pointer) = + ##define XkbSASetScreen(a,s) ((a)->screenXXX= ((s)&0xff)) + a.screenXXX = toU8(cast[int](s)) + +proc XkbActionSetCtrls(a: PXkbCtrlsAction, c: int8) = + ##define XkbActionSetCtrls(a,c) (((a)->ctrls3=(((c)>>24)&0xff)),((a)->ctrls2=(((c)>>16)&0xff)), + # ((a)->ctrls1=(((c)>>8)&0xff)),((a)->ctrls0=((c)&0xff))) + a.ctrls3 = toU8((ze(c) shr 24) and 0x000000FF) + a.ctrls2 = toU8((ze(c) shr 16) and 0x000000FF) + a.ctrls1 = toU8((ze(c) shr 8) and 0x000000FF) + a.ctrls0 = toU8(ze(c) and 0x000000FF) + +proc XkbActionCtrls(a: PXkbCtrlsAction): int16 = + ##define XkbActionCtrls(a) ((((unsigned int)(a)->ctrls3)<<24)|(((unsigned int)(a)->ctrls2)<<16)| + # (((unsigned int)(a)->ctrls1)<<8)|((unsigned int)((a)->ctrls0))) + result = toU16((ze(a.ctrls3) shl 24) or (ze(a.ctrls2) shl 16) or + (ze(a.ctrls1) shl 8) or ze(a.ctrls0)) + +proc XkbSARedirectVMods(a: PXkbRedirectKeyAction): int16 = + ##define XkbSARedirectVMods(a) ((((unsigned int)(a)->vmods1)<<8)|((unsigned int)(a)->vmods0)) + result = toU16((ze(a.vmods1) shl 8) or ze(a.vmods0)) + +proc XkbSARedirectSetVMods(a: PXkbRedirectKeyAction, m: int8) = + ##define XkbSARedirectSetVMods(a,m) (((a)->vmods_mask1=(((m)>>8)&0xff)),((a)->vmods_mask0=((m)&0xff))) + a.vmods_mask1 = toU8((ze(m) shr 8) and 0x000000FF) + a.vmods_mask0 = toU8(ze(m) or 0x000000FF) + +proc XkbSARedirectVModsMask(a: PXkbRedirectKeyAction): int16 = + ##define XkbSARedirectVModsMask(a) ((((unsigned int)(a)->vmods_mask1)<<8)| + # ((unsigned int)(a)->vmods_mask0)) + result = toU16((ze(a.vmods_mask1) shl 8) or ze(a.vmods_mask0)) + +proc XkbSARedirectSetVModsMask(a: PXkbRedirectKeyAction, m: int8) = + ##define XkbSARedirectSetVModsMask(a,m) (((a)->vmods_mask1=(((m)>>8)&0xff)),((a)->vmods_mask0=((m)&0xff))) + a.vmods_mask1 = toU8(ze(m) shr 8 and 0x000000FF) + a.vmods_mask0 = toU8(ze(m) and 0x000000FF) + +proc XkbAX_AnyFeedback(c: PXkbControlsPtr): int16 = + ##define XkbAX_AnyFeedback(c) ((c)->enabled_ctrls&XkbAccessXFeedbackMask) + result = toU16(ze(c.enabled_ctrls) and XkbAccessXFeedbackMask) + +proc XkbAX_NeedOption(c: PXkbControlsPtr, w: int16): int16 = + ##define XkbAX_NeedOption(c,w) ((c)->ax_options&(w)) + result = toU16(ze(c.ax_options) and ze(w)) + +proc XkbAX_NeedFeedback(c: PXkbControlsPtr, w: int16): bool = + ##define XkbAX_NeedFeedback(c,w) (XkbAX_AnyFeedback(c)&&XkbAX_NeedOption(c,w)) + result = (XkbAX_AnyFeedback(c) > 0'i16) and (XkbAX_NeedOption(c, w) > 0'i16) + +proc XkbSMKeyActionsPtr(m: PXkbServerMapPtr, k: int16): PXkbAction = + ##define XkbSMKeyActionsPtr(m,k) (&(m)->acts[(m)->key_acts[k]]) + result = addr(m.acts[ze(m.key_acts[ze(k)])]) + +proc XkbCMKeyGroupInfo(m: PXkbClientMapPtr, k: int16): int8 = + ##define XkbCMKeyGroupInfo(m,k) ((m)->key_sym_map[k].group_info) + result = m.key_sym_map[ze(k)].group_info + +proc XkbCMKeyNumGroups(m: PXkbClientMapPtr, k: int16): int8 = + ##define XkbCMKeyNumGroups(m,k) (XkbNumGroups((m)->key_sym_map[k].group_info)) + result = toU8(XkbNumGroups(m.key_sym_map[ze(k)].group_info)) + +proc XkbCMKeyGroupWidth(m: PXkbClientMapPtr, k: int16, g: int8): int8 = + ##define XkbCMKeyGroupWidth(m,k,g) (XkbCMKeyType(m,k,g)->num_levels) + result = XkbCMKeyType(m, k, g).num_levels + +proc XkbCMKeyGroupsWidth(m: PXkbClientMapPtr, k: int16): int8 = + ##define XkbCMKeyGroupsWidth(m,k) ((m)->key_sym_map[k].width) + result = m.key_sym_map[ze(k)].width + +proc XkbCMKeyTypeIndex(m: PXkbClientMapPtr, k: int16, g: int8): int8 = + ##define XkbCMKeyTypeIndex(m,k,g) ((m)->key_sym_map[k].kt_index[g&0x3]) + result = m.key_sym_map[ze(k)].kt_index[ze(g) and 0x00000003] + +proc XkbCMKeyType(m: PXkbClientMapPtr, k: int16, g: int8): PXkbKeyTypePtr = + ##define XkbCMKeyType(m,k,g) (&(m)->types[XkbCMKeyTypeIndex(m,k,g)]) + result = addr(m.types[ze(XkbCMKeyTypeIndex(m, k, g))]) + +proc XkbCMKeyNumSyms(m: PXkbClientMapPtr, k: int16): int16 = + ##define XkbCMKeyNumSyms(m,k) (XkbCMKeyGroupsWidth(m,k)*XkbCMKeyNumGroups(m,k)) + result = toU16(ze(XkbCMKeyGroupsWidth(m, k)) or ze(XkbCMKeyNumGroups(m, k))) + +proc XkbCMKeySymsOffset(m: PXkbClientMapPtr, k: int16): int8 = + ##define XkbCMKeySymsOffset(m,k) ((m)->key_sym_map[k].offset) + result = m.key_sym_map[ze(k)].offset + +proc XkbCMKeySymsPtr*(m: PXkbClientMapPtr, k: int16): PKeySym = + ##define XkbCMKeySymsPtr(m,k) (&(m)->syms[XkbCMKeySymsOffset(m,k)]) + result = addr(m.syms[ze(XkbCMKeySymsOffset(m, k))]) + +proc XkbIM_IsAuto(i: PXkbIndicatorMapPtr): bool = + ##define XkbIM_IsAuto(i) ((((i)->flags&XkbIM_NoAutomatic)==0)&&(((i)->which_groups&&(i)->groups)|| + # ((i)->which_mods&&(i)->mods.mask)|| ((i)->ctrls))) + result = ((ze(i.flags) and XkbIM_NoAutomatic) == 0) and + (((i.which_groups > 0'i8) and (i.groups > 0'i8)) or + ((i.which_mods > 0'i8) and (i.mods.mask > 0'i8)) or (i.ctrls > 0'i8)) + +proc XkbIM_InUse(i: PXkbIndicatorMapPtr): bool = + ##define XkbIM_InUse(i) (((i)->flags)||((i)->which_groups)||((i)->which_mods)||((i)->ctrls)) + result = (i.flags > 0'i8) or (i.which_groups > 0'i8) or (i.which_mods > 0'i8) or + (i.ctrls > 0'i8) + +proc XkbKeyKeyTypeIndex(d: PXkbDescPtr, k: int16, g: int8): int8 = + ##define XkbKeyKeyTypeIndex(d,k,g) (XkbCMKeyTypeIndex((d)->map,k,g)) + result = XkbCMKeyTypeIndex(d.map, k, g) + +proc XkbKeyKeyType(d: PXkbDescPtr, k: int16, g: int8): PXkbKeyTypePtr = + ##define XkbKeyKeyType(d,k,g) (XkbCMKeyType((d)->map,k,g)) + result = XkbCMKeyType(d.map, k, g) + +proc XkbKeyGroupWidth(d: PXkbDescPtr, k: int16, g: int8): int8 = + ##define XkbKeyGroupWidth(d,k,g) (XkbCMKeyGroupWidth((d)->map,k,g)) + result = XkbCMKeyGroupWidth(d.map, k, g) + +proc XkbKeyGroupsWidth(d: PXkbDescPtr, k: int16): int8 = + ##define XkbKeyGroupsWidth(d,k) (XkbCMKeyGroupsWidth((d)->map,k)) + result = XkbCMKeyGroupsWidth(d.map, k) + +proc XkbKeyGroupInfo(d: PXkbDescPtr, k: int16): int8 = + ##define XkbKeyGroupInfo(d,k) (XkbCMKeyGroupInfo((d)->map,(k))) + result = XkbCMKeyGroupInfo(d.map, k) + +proc XkbKeyNumGroups(d: PXkbDescPtr, k: int16): int8 = + ##define XkbKeyNumGroups(d,k) (XkbCMKeyNumGroups((d)->map,(k))) + result = XkbCMKeyNumGroups(d.map, k) + +proc XkbKeyNumSyms(d: PXkbDescPtr, k: int16): int16 = + ##define XkbKeyNumSyms(d,k) (XkbCMKeyNumSyms((d)->map,(k))) + result = XkbCMKeyNumSyms(d.map, k) + +proc XkbKeySymsPtr*(d: PXkbDescPtr, k: int16): PKeySym = + ##define XkbKeySymsPtr(d,k) (XkbCMKeySymsPtr((d)->map,(k))) + result = XkbCMKeySymsPtr(d.map, k) + +proc XkbKeySym(d: PXkbDescPtr, k: int16, n: int16): TKeySym = + ##define XkbKeySym(d,k,n) (XkbKeySymsPtr(d,k)[n]) + result = cast[ptr array[0..0xffff, TKeySym]](XkbKeySymsPtr(d, k))[ze(n)] # XXX: this seems strange! + +proc XkbKeySymEntry(d: PXkbDescPtr, k: int16, sl: int16, g: int8): TKeySym = + ##define XkbKeySymEntry(d,k,sl,g) (XkbKeySym(d,k,((XkbKeyGroupsWidth(d,k)*(g))+(sl)))) + result = XkbKeySym(d, k, toU16(ze(XkbKeyGroupsWidth(d, k)) * ze(g) + ze(sl))) + +proc XkbKeyAction(d: PXkbDescPtr, k: int16, n: int16): PXkbAction = + ##define XkbKeyAction(d,k,n) (XkbKeyHasActions(d,k)?&XkbKeyActionsPtr(d,k)[n]:NULL) + #if (XkbKeyHasActions(d, k)): + # result = XkbKeyActionsPtr(d, k)[ze(n)] #Buggy !!! + assert(false) + result = nil + +proc XkbKeyActionEntry(d: PXkbDescPtr, k: int16, sl: int16, g: int8): int8 = + ##define XkbKeyActionEntry(d,k,sl,g) (XkbKeyHasActions(d,k) ? + # XkbKeyAction(d, k, ((XkbKeyGroupsWidth(d, k) * (g))+(sl))):NULL) + if XkbKeyHasActions(d, k): + result = XkbKeyGroupsWidth(d, k) *% g +% toU8(sl) + else: + result = 0'i8 + +proc XkbKeyHasActions(d: PXkbDescPtr, k: int16): bool = + ##define XkbKeyHasActions(d,k) ((d)->server->key_acts[k]!=0) + result = d.server.key_acts[ze(k)] != 0'i16 + +proc XkbKeyNumActions(d: PXkbDescPtr, k: int16): int16 = + ##define XkbKeyNumActions(d,k) (XkbKeyHasActions(d,k)?XkbKeyNumSyms(d,k):1) + if (XkbKeyHasActions(d, k)): result = XkbKeyNumSyms(d, k) + else: result = 1'i16 + +proc XkbKeyActionsPtr(d: PXkbDescPtr, k: int16): PXkbAction = + ##define XkbKeyActionsPtr(d,k) (XkbSMKeyActionsPtr((d)->server,k)) + result = XkbSMKeyActionsPtr(d.server, k) + +proc XkbKeycodeInRange(d: PXkbDescPtr, k: int16): bool = + ##define XkbKeycodeInRange(d,k) (((k)>=(d)->min_key_code)&& ((k)<=(d)->max_key_code)) + result = (char(toU8(k)) >= d.min_key_code) and (char(toU8(k)) <= d.max_key_code) + +proc XkbNumKeys(d: PXkbDescPtr): int8 = + ##define XkbNumKeys(d) ((d)->max_key_code-(d)->min_key_code+1) + result = toU8(ord(d.max_key_code) - ord(d.min_key_code) + 1) + +proc XkbXI_DevHasBtnActs(d: PXkbDeviceInfoPtr): bool = + ##define XkbXI_DevHasBtnActs(d) (((d)->num_btns>0)&&((d)->btn_acts!=NULL)) + result = (d.num_btns > 0'i16) and (not (d.btn_acts == nil)) + +proc XkbXI_LegalDevBtn(d: PXkbDeviceInfoPtr, b: int16): bool = + ##define XkbXI_LegalDevBtn(d,b) (XkbXI_DevHasBtnActs(d)&&((b)<(d)->num_btns)) + result = XkbXI_DevHasBtnActs(d) and (b <% d.num_btns) + +proc XkbXI_DevHasLeds(d: PXkbDeviceInfoPtr): bool = + ##define XkbXI_DevHasLeds(d) (((d)->num_leds>0)&&((d)->leds!=NULL)) + result = (d.num_leds > 0'i16) and (not (d.leds == nil)) + +proc XkbBoundsWidth(b: PXkbBoundsPtr): int16 = + ##define XkbBoundsWidth(b) (((b)->x2)-((b)->x1)) + result = (b.x2) - b.x1 + +proc XkbBoundsHeight(b: PXkbBoundsPtr): int16 = + ##define XkbBoundsHeight(b) (((b)->y2)-((b)->y1)) + result = (b.y2) - b.y1 + +proc XkbOutlineIndex(s: PXkbShapePtr, o: PXkbOutlinePtr): int32 = + ##define XkbOutlineIndex(s,o) ((int)((o)-&(s)->outlines[0])) + result = int32((cast[TAddress](o) - cast[TAddress](addr(s.outlines[0]))) div sizeof(PXkbOutlinePtr)) + +proc XkbShapeDoodadColor(g: PXkbGeometryPtr, d: PXkbShapeDoodadPtr): PXkbColorPtr = + ##define XkbShapeDoodadColor(g,d) (&(g)->colors[(d)->color_ndx]) + result = addr((g.colors[ze(d.color_ndx)])) + +proc XkbShapeDoodadShape(g: PXkbGeometryPtr, d: PXkbShapeDoodadPtr): PXkbShapePtr = + ##define XkbShapeDoodadShape(g,d) (&(g)->shapes[(d)->shape_ndx]) + result = addr(g.shapes[ze(d.shape_ndx)]) + +proc XkbSetShapeDoodadColor(g: PXkbGeometryPtr, d: PXkbShapeDoodadPtr, + c: PXkbColorPtr) = + ##define XkbSetShapeDoodadColor(g,d,c) ((d)->color_ndx= (c)-&(g)->colors[0]) + d.color_ndx = toU16((cast[TAddress](c) - cast[TAddress](addr(g.colors[0]))) div sizeof(TXkbColorRec)) + +proc XkbSetShapeDoodadShape(g: PXkbGeometryPtr, d: PXkbShapeDoodadPtr, + s: PXkbShapePtr) = + ##define XkbSetShapeDoodadShape(g,d,s) ((d)->shape_ndx= (s)-&(g)->shapes[0]) + d.shape_ndx = toU16((cast[TAddress](s) - cast[TAddress](addr(g.shapes[0]))) div sizeof(TXkbShapeRec)) + +proc XkbTextDoodadColor(g: PXkbGeometryPtr, d: PXkbTextDoodadPtr): PXkbColorPtr = + ##define XkbTextDoodadColor(g,d) (&(g)->colors[(d)->color_ndx]) + result = addr(g.colors[ze(d.color_ndx)]) + +proc XkbSetTextDoodadColor(g: PXkbGeometryPtr, d: PXkbTextDoodadPtr, + c: PXkbColorPtr) = + ##define XkbSetTextDoodadColor(g,d,c) ((d)->color_ndx= (c)-&(g)->colors[0]) + d.color_ndx = toU16((cast[TAddress](c) - cast[TAddress](addr(g.colors[0]))) div sizeof(TXkbColorRec)) + +proc XkbIndicatorDoodadShape(g: PXkbGeometryPtr, d: PXkbIndicatorDoodadPtr): PXkbShapeDoodadPtr = + ##define XkbIndicatorDoodadShape(g,d) (&(g)->shapes[(d)->shape_ndx]) + result = cast[PXkbShapeDoodadPtr](addr(g.shapes[ze(d.shape_ndx)])) + +proc XkbIndicatorDoodadOnColor(g: PXkbGeometryPtr, d: PXkbIndicatorDoodadPtr): PXkbColorPtr = + ##define XkbIndicatorDoodadOnColor(g,d) (&(g)->colors[(d)->on_color_ndx]) + result = addr(g.colors[ze(d.on_color_ndx)]) + +proc XkbIndicatorDoodadOffColor(g: PXkbGeometryPtr, d: PXkbIndicatorDoodadPtr): PXkbColorPtr = + ##define XkbIndicatorDoodadOffColor(g,d) (&(g)->colors[(d)->off_color_ndx]) + result = addr(g.colors[ze(d.off_color_ndx)]) + +proc XkbSetIndicatorDoodadOnColor(g: PXkbGeometryPtr, d: PXkbIndicatorDoodadPtr, + c: PXkbColorPtr) = + ##define XkbSetIndicatorDoodadOnColor(g,d,c) ((d)->on_color_ndx= (c)-&(g)->colors[0]) + d.on_color_ndx = toU16((cast[TAddress](c) - cast[TAddress](addr(g.colors[0]))) div sizeof(TXkbColorRec)) + +proc XkbSetIndicatorDoodadOffColor(g: PXkbGeometryPtr, + d: PXkbIndicatorDoodadPtr, c: PXkbColorPtr) = + ##define XkbSetIndicatorDoodadOffColor(g,d,c) ((d)->off_color_ndx= (c)-&(g)->colors[0]) + d.off_color_ndx = toU16((cast[TAddress](c) - cast[TAddress](addr(g.colors[0]))) div sizeof(TxkbColorRec)) + +proc XkbSetIndicatorDoodadShape(g: PXkbGeometryPtr, d: PXkbIndicatorDoodadPtr, + s: PXkbShapeDoodadPtr) = + ##define XkbSetIndicatorDoodadShape(g,d,s) ((d)->shape_ndx= (s)-&(g)->shapes[0]) + d.shape_ndx = toU16((cast[TAddress](s) - (cast[TAddress](addr(g.shapes[0])))) div sizeof(TXkbShapeRec)) + +proc XkbLogoDoodadColor(g: PXkbGeometryPtr, d: PXkbLogoDoodadPtr): PXkbColorPtr = + ##define XkbLogoDoodadColor(g,d) (&(g)->colors[(d)->color_ndx]) + result = addr(g.colors[ze(d.color_ndx)]) + +proc XkbLogoDoodadShape(g: PXkbGeometryPtr, d: PXkbLogoDoodadPtr): PXkbShapeDoodadPtr = + ##define XkbLogoDoodadShape(g,d) (&(g)->shapes[(d)->shape_ndx]) + result = cast[PXkbShapeDoodadPtr](addr(g.shapes[ze(d.shape_ndx)])) + +proc XkbSetLogoDoodadColor(g: PXkbGeometryPtr, d: PXkbLogoDoodadPtr, + c: PXkbColorPtr) = + ##define XkbSetLogoDoodadColor(g,d,c) ((d)->color_ndx= (c)-&(g)->colors[0]) + d.color_ndx = toU16((cast[TAddress](c) - cast[TAddress](addr(g.colors[0]))) div sizeof(TXkbColorRec)) + +proc XkbSetLogoDoodadShape(g: PXkbGeometryPtr, d: PXkbLogoDoodadPtr, + s: PXkbShapeDoodadPtr) = + ##define XkbSetLogoDoodadShape(g,d,s) ((d)->shape_ndx= (s)-&(g)->shapes[0]) + d.shape_ndx = toU16((cast[TAddress](s) - cast[TAddress](addr(g.shapes[0]))) div sizeof(TXkbShapeRec)) + +proc XkbKeyShape(g: PXkbGeometryPtr, k: PXkbKeyPtr): PXkbShapeDoodadPtr = + ##define XkbKeyShape(g,k) (&(g)->shapes[(k)->shape_ndx]) + result = cast[PXkbShapeDoodadPtr](addr(g.shapes[ze(k.shape_ndx)])) + +proc XkbKeyColor(g: PXkbGeometryPtr, k: PXkbKeyPtr): PXkbColorPtr = + ##define XkbKeyColor(g,k) (&(g)->colors[(k)->color_ndx]) + result = addr(g.colors[ze(k.color_ndx)]) + +proc XkbSetKeyShape(g: PXkbGeometryPtr, k: PXkbKeyPtr, s: PXkbShapeDoodadPtr) = + ##define XkbSetKeyShape(g,k,s) ((k)->shape_ndx= (s)-&(g)->shapes[0]) + k.shape_ndx = toU8((cast[TAddress](s) - cast[TAddress](addr(g.shapes[0]))) div sizeof(TXkbShapeRec)) + +proc XkbSetKeyColor(g: PXkbGeometryPtr, k: PXkbKeyPtr, c: PXkbColorPtr) = + ##define XkbSetKeyColor(g,k,c) ((k)->color_ndx= (c)-&(g)->colors[0]) + k.color_ndx = toU8((cast[TAddress](c) - cast[TAddress](addr(g.colors[0]))) div sizeof(TxkbColorRec)) + +proc XkbGeomColorIndex(g: PXkbGeometryPtr, c: PXkbColorPtr): int32 = + ##define XkbGeomColorIndex(g,c) ((int)((c)-&(g)->colors[0])) + result = toU16((cast[TAddress](c) - (cast[TAddress](addr(g.colors[0])))) div sizeof(TxkbColorRec)) diff --git a/tests/deps/x11-1.0/xkblib.nim b/tests/deps/x11-1.0/xkblib.nim new file mode 100644 index 000000000..2366b0971 --- /dev/null +++ b/tests/deps/x11-1.0/xkblib.nim @@ -0,0 +1,661 @@ +# $Xorg: XKBlib.h,v 1.6 2000/08/17 19:45:03 cpqbld Exp $ +#************************************************************ +#Copyright (c) 1993 by Silicon Graphics Computer Systems, Inc. +# +#Permission to use, copy, modify, and distribute this +#software and its documentation for any purpose and without +#fee is hereby granted, provided that the above copyright +#notice appear in all copies and that both that copyright +#notice and this permission notice appear in supporting +#documentation, and that the name of Silicon Graphics not be +#used in advertising or publicity pertaining to distribution +#of the software without specific prior written permission. +#Silicon Graphics makes no representation about the suitability +#of this software for any purpose. It is provided "as is" +#without any express or implied warranty. +# +#SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS +#SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +#AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON +#GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL +#DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING `from` LOSS OF USE, +#DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE +#OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH +#THE USE OR PERFORMANCE OF THIS SOFTWARE. +# +#********************************************************/ +# $XFree86: xc/lib/X11/XKBlib.h,v 3.3 2001/08/01 00:44:38 tsi Exp $ +# +# Pascal Convertion was made by Ido Kannner - kanerido@actcom.net.il +# +#Thanks: +# I want to thanks to oliebol for putting up with all of the problems that was found +# while translating this code. ;) +# +# I want to thanks #fpc channel in freenode irc, for helping me, and to put up with my +# weird questions ;) +# +# Thanks for mmc in #xlib on freenode irc And so for the channel itself for the helping me to +# understanding some of the problems I had converting this headers and pointing me to resources +# that helped translating this headers. +# +# Ido +# +#History: +# 2004/10/15 - Fixed a bug of accessing second based records by removing "paced record" and +# chnaged it to "reocrd" only. +# 2004/10/10 - Added to TXkbGetAtomNameFunc and TXkbInternAtomFunc the cdecl call. +# 2004/10/06 - 09 - Convertion `from` the c header of XKBlib.h +# +# + +import + X, Xlib, XKB + + +include "x11pragma.nim" + + +type + PXkbAnyEvent* = ptr TXkbAnyEvent + TXkbAnyEvent*{.final.} = object + theType*: int16 # XkbAnyEvent + serial*: int32 # # of last req processed by server + send_event*: bool # is this `from` a SendEvent request? + display*: PDisplay # Display the event was read `from` + time*: TTime # milliseconds; + xkb_type*: int16 # XKB event minor code + device*: int16 # device ID + + +type + PXkbNewKeyboardNotifyEvent* = ptr TXkbNewKeyboardNotifyEvent + TXkbNewKeyboardNotifyEvent*{.final.} = object + theType*: int16 # XkbAnyEvent + serial*: int32 # of last req processed by server + send_event*: bool # is this `from` a SendEvent request? + display*: PDisplay # Display the event was read `from` + time*: TTime # milliseconds + xkb_type*: int16 # XkbNewKeyboardNotify + device*: int16 # device ID + old_device*: int16 # device ID of previous keyboard + min_key_code*: int16 # minimum key code + max_key_code*: int16 # maximum key code + old_min_key_code*: int16 # min key code of previous kbd + old_max_key_code*: int16 # max key code of previous kbd + changed*: int16 # changed aspects of the keyboard + req_major*: int8 # major and minor opcode of req + req_minor*: int8 # that caused change, if applicable + + +type + PXkbMapNotifyEvent* = ptr TXkbMapNotifyEvent + TXkbMapNotifyEvent*{.final.} = object + theType*: int16 # XkbAnyEvent + serial*: int32 # of last req processed by server + send_event*: bool # is this `from` a SendEvent request + display*: PDisplay # Display the event was read `from` + time*: TTime # milliseconds + xkb_type*: int16 # XkbMapNotify + device*: int16 # device ID + changed*: int16 # fields which have been changed + flags*: int16 # reserved + first_type*: int16 # first changed key type + num_types*: int16 # number of changed key types + min_key_code*: TKeyCode + max_key_code*: TKeyCode + first_key_sym*: TKeyCode + first_key_act*: TKeyCode + first_key_behavior*: TKeyCode + first_key_explicit*: TKeyCode + first_modmap_key*: TKeyCode + first_vmodmap_key*: TKeyCode + num_key_syms*: int16 + num_key_acts*: int16 + num_key_behaviors*: int16 + num_key_explicit*: int16 + num_modmap_keys*: int16 + num_vmodmap_keys*: int16 + vmods*: int16 # mask of changed virtual mods + + +type + PXkbStateNotifyEvent* = ptr TXkbStateNotifyEvent + TXkbStateNotifyEvent*{.final.} = object + theType*: int16 # XkbAnyEvent + serial*: int32 # # of last req processed by server + send_event*: bool # is this `from` a SendEvent request? + display*: PDisplay # Display the event was read `from` + time*: TTime # milliseconds + xkb_type*: int16 # XkbStateNotify + device*: int16 # device ID + changed*: int16 # mask of changed state components + group*: int16 # keyboard group + base_group*: int16 # base keyboard group + latched_group*: int16 # latched keyboard group + locked_group*: int16 # locked keyboard group + mods*: int16 # modifier state + base_mods*: int16 # base modifier state + latched_mods*: int16 # latched modifiers + locked_mods*: int16 # locked modifiers + compat_state*: int16 # compatibility state + grab_mods*: int8 # mods used for grabs + compat_grab_mods*: int8 # grab mods for non-XKB clients + lookup_mods*: int8 # mods sent to clients + compat_lookup_mods*: int8 # mods sent to non-XKB clients + ptr_buttons*: int16 # pointer button state + keycode*: TKeyCode # keycode that caused the change + event_type*: int8 # KeyPress or KeyRelease + req_major*: int8 # Major opcode of request + req_minor*: int8 # Minor opcode of request + + +type + PXkbControlsNotifyEvent* = ptr TXkbControlsNotifyEvent + TXkbControlsNotifyEvent*{.final.} = object + theType*: int16 # XkbAnyEvent + serial*: int32 # of last req processed by server + send_event*: bool # is this `from` a SendEvent request? + display*: PDisplay # Display the event was read `from` + time*: TTime # milliseconds + xkb_type*: int16 # XkbControlsNotify + device*: int16 # device ID + changed_ctrls*: int16 # controls with changed sub-values + enabled_ctrls*: int16 # controls currently enabled + enabled_ctrl_changes*: int16 # controls just {en,dis}abled + num_groups*: int16 # total groups on keyboard + keycode*: TKeyCode # key that caused change or 0 + event_type*: int8 # type of event that caused change + req_major*: int8 # if keycode==0, major and minor + req_minor*: int8 # opcode of req that caused change + + +type + PXkbIndicatorNotifyEvent* = ptr TXkbIndicatorNotifyEvent + TXkbIndicatorNotifyEvent*{.final.} = object + theType*: int16 # XkbAnyEvent + serial*: int32 # of last req processed by server + send_event*: bool # is this `from` a SendEvent request? + display*: PDisplay # Display the event was read `from` + time*: TTime # milliseconds + xkb_type*: int16 # XkbIndicatorNotify + device*: int16 # device + changed*: int16 # indicators with new state or map + state*: int16 # current state of all indicators + + +type + PXkbNamesNotifyEvent* = ptr TXkbNamesNotifyEvent + TXkbNamesNotifyEvent*{.final.} = object + theType*: int16 # XkbAnyEvent + serial*: int32 # of last req processed by server + send_event*: bool # is this `from` a SendEvent request? + display*: PDisplay # Display the event was read `from` + time*: TTime # milliseconds + xkb_type*: int16 # XkbNamesNotify + device*: int16 # device ID + changed*: int32 # names that have changed + first_type*: int16 # first key type with new name + num_types*: int16 # number of key types with new names + first_lvl*: int16 # first key type new new level names + num_lvls*: int16 # # of key types w/new level names + num_aliases*: int16 # total number of key aliases + num_radio_groups*: int16 # total number of radio groups + changed_vmods*: int16 # virtual modifiers with new names + changed_groups*: int16 # groups with new names + changed_indicators*: int16 # indicators with new names + first_key*: int16 # first key with new name + num_keys*: int16 # number of keys with new names + + +type + PXkbCompatMapNotifyEvent* = ptr TXkbCompatMapNotifyEvent + TXkbCompatMapNotifyEvent*{.final.} = object + theType*: int16 # XkbAnyEvent + serial*: int32 # of last req processed by server + send_event*: bool # is this `from` a SendEvent request? + display*: PDisplay # Display the event was read `from` + time*: TTime # milliseconds + xkb_type*: int16 # XkbCompatMapNotify + device*: int16 # device ID + changed_groups*: int16 # groups with new compat maps + first_si*: int16 # first new symbol interp + num_si*: int16 # number of new symbol interps + num_total_si*: int16 # total # of symbol interps + + +type + PXkbBellNotifyEvent* = ptr TXkbBellNotifyEvent + TXkbBellNotifyEvent*{.final.} = object + theType*: int16 # XkbAnyEvent + serial*: int32 # of last req processed by server + send_event*: bool # is this `from` a SendEvent request? + display*: PDisplay # Display the event was read `from` + time*: TTime # milliseconds + xkb_type*: int16 # XkbBellNotify + device*: int16 # device ID + percent*: int16 # requested volume as a % of maximum + pitch*: int16 # requested pitch in Hz + duration*: int16 # requested duration in useconds + bell_class*: int16 # (input extension) feedback class + bell_id*: int16 # (input extension) ID of feedback + name*: TAtom # "name" of requested bell + window*: TWindow # window associated with event + event_only*: bool # "event only" requested + + +type + PXkbActionMessageEvent* = ptr TXkbActionMessageEvent + TXkbActionMessageEvent*{.final.} = object + theType*: int16 # XkbAnyEvent + serial*: int32 # of last req processed by server + send_event*: bool # is this `from` a SendEvent request? + display*: PDisplay # Display the event was read `from` + time*: TTime # milliseconds + xkb_type*: int16 # XkbActionMessage + device*: int16 # device ID + keycode*: TKeyCode # key that generated the event + press*: bool # true if act caused by key press + key_event_follows*: bool # true if key event also generated + group*: int16 # effective group + mods*: int16 # effective mods + message*: array[0..XkbActionMessageLength, char] # message -- leave space for NUL + + +type + PXkbAccessXNotifyEvent* = ptr TXkbAccessXNotifyEvent + TXkbAccessXNotifyEvent*{.final.} = object + theType*: int16 # XkbAnyEvent + serial*: int32 # of last req processed by server + send_event*: bool # is this `from` a SendEvent request? + display*: PDisplay # Display the event was read `from` + time*: TTime # milliseconds + xkb_type*: int16 # XkbAccessXNotify + device*: int16 # device ID + detail*: int16 # XkbAXN_* + keycode*: int16 # key of event + sk_delay*: int16 # current slow keys delay + debounce_delay*: int16 # current debounce delay + + +type + PXkbExtensionDeviceNotifyEvent* = ptr TXkbExtensionDeviceNotifyEvent + TXkbExtensionDeviceNotifyEvent*{.final.} = object + theType*: int16 # XkbAnyEvent + serial*: int32 # of last req processed by server + send_event*: bool # is this `from` a SendEvent request? + display*: PDisplay # Display the event was read `from` + time*: TTime # milliseconds + xkb_type*: int16 # XkbExtensionDeviceNotify + device*: int16 # device ID + reason*: int16 # reason for the event + supported*: int16 # mask of supported features + unsupported*: int16 # mask of unsupported features + # that some app tried to use + first_btn*: int16 # first button that changed + num_btns*: int16 # range of buttons changed + leds_defined*: int16 # indicators with names or maps + led_state*: int16 # current state of the indicators + led_class*: int16 # feedback class for led changes + led_id*: int16 # feedback id for led changes + + +type + PXkbEvent* = ptr TXkbEvent + TXkbEvent*{.final.} = object + theType*: int16 + any*: TXkbAnyEvent + new_kbd*: TXkbNewKeyboardNotifyEvent + map*: TXkbMapNotifyEvent + state*: TXkbStateNotifyEvent + ctrls*: TXkbControlsNotifyEvent + indicators*: TXkbIndicatorNotifyEvent + names*: TXkbNamesNotifyEvent + compat*: TXkbCompatMapNotifyEvent + bell*: TXkbBellNotifyEvent + message*: TXkbActionMessageEvent + accessx*: TXkbAccessXNotifyEvent + device*: TXkbExtensionDeviceNotifyEvent + core*: TXEvent + + +type + PXkbKbdDpyStatePtr* = ptr TXkbKbdDpyStateRec + TXkbKbdDpyStateRec*{.final.} = object # XkbOpenDisplay error codes + +const + XkbOD_Success* = 0 + XkbOD_BadLibraryVersion* = 1 + XkbOD_ConnectionRefused* = 2 + XkbOD_NonXkbServer* = 3 + XkbOD_BadServerVersion* = 4 # Values for XlibFlags + +const + XkbLC_ForceLatin1Lookup* = 1 shl 0 + XkbLC_ConsumeLookupMods* = 1 shl 1 + XkbLC_AlwaysConsumeShiftAndLock* = 1 shl 2 + XkbLC_IgnoreNewKeyboards* = 1 shl 3 + XkbLC_ControlFallback* = 1 shl 4 + XkbLC_ConsumeKeysOnComposeFail* = 1 shl 29 + XkbLC_ComposeLED* = 1 shl 30 + XkbLC_BeepOnComposeFail* = 1 shl 31 + XkbLC_AllComposeControls* = 0xC0000000 + XkbLC_AllControls* = 0xC000001F + +proc XkbIgnoreExtension*(ignore: bool): bool{.libx11c, + importc: "XkbIgnoreExtension".} +proc XkbOpenDisplay*(name: cstring, ev_rtrn, err_rtrn, major_rtrn, minor_rtrn, + reason: ptr int16): PDisplay{.libx11c, importc: "XkbOpenDisplay".} +proc XkbQueryExtension*(dpy: PDisplay, opcodeReturn, eventBaseReturn, + errorBaseReturn, majorRtrn, minorRtrn: ptr int16): bool{. + libx11c, importc: "XkbQueryExtension".} +proc XkbUseExtension*(dpy: PDisplay, major_rtrn, minor_rtrn: ptr int16): bool{. + libx11c, importc: "XkbUseExtension".} +proc XkbLibraryVersion*(libMajorRtrn, libMinorRtrn: ptr int16): bool{.libx11c, importc: "XkbLibraryVersion".} +proc XkbSetXlibControls*(dpy: PDisplay, affect, values: int16): int16{.libx11c, importc: "XkbSetXlibControls".} +proc XkbGetXlibControls*(dpy: PDisplay): int16{.libx11c, + importc: "XkbGetXlibControls".} +type + TXkbInternAtomFunc* = proc (dpy: PDisplay, name: cstring, only_if_exists: bool): TAtom{. + cdecl.} + +type + TXkbGetAtomNameFunc* = proc (dpy: PDisplay, atom: TAtom): cstring{.cdecl.} + +proc XkbSetAtomFuncs*(getAtom: TXkbInternAtomFunc, getName: TXkbGetAtomNameFunc){. + libx11c, importc: "XkbSetAtomFuncs".} +proc XkbKeycodeToKeysym*(dpy: PDisplay, kc: TKeyCode, group, level: int16): TKeySym{. + libx11c, importc: "XkbKeycodeToKeysym".} +proc XkbKeysymToModifiers*(dpy: PDisplay, ks: TKeySym): int16{.libx11c, importc: "XkbKeysymToModifiers".} +proc XkbLookupKeySym*(dpy: PDisplay, keycode: TKeyCode, + modifiers, modifiers_return: int16, keysym_return: PKeySym): bool{. + libx11c, importc: "XkbLookupKeySym".} +proc XkbLookupKeyBinding*(dpy: PDisplay, sym_rtrn: TKeySym, mods: int16, + buffer: cstring, nbytes: int16, extra_rtrn: ptr int16): int16{. + libx11c, importc: "XkbLookupKeyBinding".} +proc XkbTranslateKeyCode*(xkb: PXkbDescPtr, keycode: TKeyCode, + modifiers, modifiers_return: int16, + keysym_return: PKeySym): bool{.libx11c, + importc: "XkbTranslateKeyCode".} +proc XkbTranslateKeySym*(dpy: PDisplay, sym_return: TKeySym, modifiers: int16, + buffer: cstring, nbytes: int16, extra_rtrn: ptr int16): int16{. + libx11c, importc: "XkbTranslateKeySym".} +proc XkbSetAutoRepeatRate*(dpy: PDisplay, deviceSpec, delay, interval: int16): bool{. + libx11c, importc: "XkbSetAutoRepeatRate".} +proc XkbGetAutoRepeatRate*(dpy: PDisplay, deviceSpec: int16, + delayRtrn, intervalRtrn: PWord): bool{.libx11c, importc: "XkbGetAutoRepeatRate".} +proc XkbChangeEnabledControls*(dpy: PDisplay, deviceSpec, affect, values: int16): bool{. + libx11c, importc: "XkbChangeEnabledControls".} +proc XkbDeviceBell*(dpy: PDisplay, win: TWindow, + deviceSpec, bellClass, bellID, percent: int16, name: TAtom): bool{. + libx11c, importc: "XkbDeviceBell".} +proc XkbForceDeviceBell*(dpy: PDisplay, + deviceSpec, bellClass, bellID, percent: int16): bool{. + libx11c, importc: "XkbForceDeviceBell".} +proc XkbDeviceBellEvent*(dpy: PDisplay, win: TWindow, + deviceSpec, bellClass, bellID, percent: int16, + name: TAtom): bool{.libx11c, + importc: "XkbDeviceBellEvent".} +proc XkbBell*(dpy: PDisplay, win: TWindow, percent: int16, name: TAtom): bool{. + libx11c, importc: "XkbBell".} +proc XkbForceBell*(dpy: PDisplay, percent: int16): bool{.libx11c, + importc: "XkbForceBell".} +proc XkbBellEvent*(dpy: PDisplay, win: TWindow, percent: int16, name: TAtom): bool{. + libx11c, importc: "XkbBellEvent".} +proc XkbSelectEvents*(dpy: PDisplay, deviceID, affect, values: int16): bool{. + libx11c, importc: "XkbSelectEvents".} +proc XkbSelectEventDetails*(dpy: PDisplay, deviceID, eventType: int16, + affect, details: int32): bool{.libx11c, importc: "XkbSelectEventDetails".} +proc XkbNoteMapChanges*(old: PXkbMapChangesPtr, new: PXkbMapNotifyEvent, + wanted: int16){.libx11c, + importc: "XkbNoteMapChanges".} +proc XkbNoteNameChanges*(old: PXkbNameChangesPtr, new: PXkbNamesNotifyEvent, + wanted: int16){.libx11c, + importc: "XkbNoteNameChanges".} +proc XkbGetIndicatorState*(dpy: PDisplay, deviceSpec: int16, pStateRtrn: PWord): TStatus{. + libx11c, importc: "XkbGetIndicatorState".} +proc XkbGetDeviceIndicatorState*(dpy: PDisplay, + deviceSpec, ledClass, ledID: int16, + pStateRtrn: PWord): TStatus{.libx11c, importc: "XkbGetDeviceIndicatorState".} +proc XkbGetIndicatorMap*(dpy: PDisplay, which: int32, desc: PXkbDescPtr): TStatus{. + libx11c, importc: "XkbGetIndicatorMap".} +proc XkbSetIndicatorMap*(dpy: PDisplay, which: int32, desc: PXkbDescPtr): bool{. + libx11c, importc: "XkbSetIndicatorMap".} +proc XkbNoteIndicatorMapChanges*(o, n: PXkbIndicatorChangesPtr, w: int16) +proc XkbNoteIndicatorStateChanges*(o, n: PXkbIndicatorChangesPtr, w: int16) +proc XkbGetIndicatorMapChanges*(d: PDisplay, x: PXkbDescPtr, + c: PXkbIndicatorChangesPtr): TStatus +proc XkbChangeIndicatorMaps*(d: PDisplay, x: PXkbDescPtr, + c: PXkbIndicatorChangesPtr): bool +proc XkbGetNamedIndicator*(dpy: PDisplay, name: TAtom, pNdxRtrn: ptr int16, + pStateRtrn: ptr bool, pMapRtrn: PXkbIndicatorMapPtr, + pRealRtrn: ptr bool): bool{.libx11c, + importc: "XkbGetNamedIndicator".} +proc XkbGetNamedDeviceIndicator*(dpy: PDisplay, + deviceSpec, ledClass, ledID: int16, + name: TAtom, pNdxRtrn: ptr int16, + pStateRtrn: ptr bool, + pMapRtrn: PXkbIndicatorMapPtr, + pRealRtrn: ptr bool): bool{.libx11c, importc: "XkbGetNamedDeviceIndicator".} +proc XkbSetNamedIndicator*(dpy: PDisplay, name: TAtom, + changeState, state, createNewMap: bool, + pMap: PXkbIndicatorMapPtr): bool{.libx11c, importc: "XkbSetNamedIndicator".} +proc XkbSetNamedDeviceIndicator*(dpy: PDisplay, + deviceSpec, ledClass, ledID: int16, + name: TAtom, + changeState, state, createNewMap: bool, + pMap: PXkbIndicatorMapPtr): bool{.libx11c, importc: "XkbSetNamedDeviceIndicator".} +proc XkbLockModifiers*(dpy: PDisplay, deviceSpec, affect, values: int16): bool{. + libx11c, importc: "XkbLockModifiers".} +proc XkbLatchModifiers*(dpy: PDisplay, deviceSpec, affect, values: int16): bool{. + libx11c, importc: "XkbLatchModifiers".} +proc XkbLockGroup*(dpy: PDisplay, deviceSpec, group: int16): bool{.libx11c, importc: "XkbLockGroup".} +proc XkbLatchGroup*(dpy: PDisplay, deviceSpec, group: int16): bool{.libx11c, importc: "XkbLatchGroup".} +proc XkbSetServerInternalMods*(dpy: PDisplay, deviceSpec, affectReal, + realValues, affectVirtual, virtualValues: int16): bool{.libx11c, importc: "XkbSetServerInternalMods".} +proc XkbSetIgnoreLockMods*(dpy: PDisplay, deviceSpec, affectReal, realValues, + affectVirtual, virtualValues: int16): bool{.libx11c, + importc: "XkbSetIgnoreLockMods".} +proc XkbVirtualModsToReal*(dpy: PDisplay, virtual_mask: int16, mask_rtrn: PWord): bool{. + libx11c, importc: "XkbVirtualModsToReal".} +proc XkbComputeEffectiveMap*(xkb: PXkbDescPtr, theType: PXkbKeyTypePtr, + map_rtrn: PByte): bool{.libx11c, + importc: "XkbComputeEffectiveMap".} +proc XkbInitCanonicalKeyTypes*(xkb: PXkbDescPtr, which: int16, keypadVMod: int16): TStatus{. + libx11c, importc: "XkbInitCanonicalKeyTypes".} +proc XkbAllocKeyboard*(): PXkbDescPtr{.libx11c, + importc: "XkbAllocKeyboard".} +proc XkbFreeKeyboard*(xkb: PXkbDescPtr, which: int16, freeDesc: bool){.libx11c, importc: "XkbFreeKeyboard".} +proc XkbAllocClientMap*(xkb: PXkbDescPtr, which, nTypes: int16): TStatus{.libx11c, importc: "XkbAllocClientMap".} +proc XkbAllocServerMap*(xkb: PXkbDescPtr, which, nActions: int16): TStatus{. + libx11c, importc: "XkbAllocServerMap".} +proc XkbFreeClientMap*(xkb: PXkbDescPtr, what: int16, freeMap: bool){.libx11c, importc: "XkbFreeClientMap".} +proc XkbFreeServerMap*(xkb: PXkbDescPtr, what: int16, freeMap: bool){.libx11c, importc: "XkbFreeServerMap".} +proc XkbAddKeyType*(xkb: PXkbDescPtr, name: TAtom, map_count: int16, + want_preserve: bool, num_lvls: int16): PXkbKeyTypePtr{. + libx11c, importc: "XkbAddKeyType".} +proc XkbAllocIndicatorMaps*(xkb: PXkbDescPtr): TStatus{.libx11c, + importc: "XkbAllocIndicatorMaps".} +proc XkbFreeIndicatorMaps*(xkb: PXkbDescPtr){.libx11c, + importc: "XkbFreeIndicatorMaps".} +proc XkbGetMap*(dpy: PDisplay, which, deviceSpec: int16): PXkbDescPtr{.libx11c, importc: "XkbGetMap".} +proc XkbGetUpdatedMap*(dpy: PDisplay, which: int16, desc: PXkbDescPtr): TStatus{. + libx11c, importc: "XkbGetUpdatedMap".} +proc XkbGetMapChanges*(dpy: PDisplay, xkb: PXkbDescPtr, + changes: PXkbMapChangesPtr): TStatus{.libx11c, importc: "XkbGetMapChanges".} +proc XkbRefreshKeyboardMapping*(event: PXkbMapNotifyEvent): TStatus{.libx11c, importc: "XkbRefreshKeyboardMapping".} +proc XkbGetKeyTypes*(dpy: PDisplay, first, num: int16, xkb: PXkbDescPtr): TStatus{. + libx11c, importc: "XkbGetKeyTypes".} +proc XkbGetKeySyms*(dpy: PDisplay, first, num: int16, xkb: PXkbDescPtr): TStatus{. + libx11c, importc: "XkbGetKeySyms".} +proc XkbGetKeyActions*(dpy: PDisplay, first, num: int16, xkb: PXkbDescPtr): TStatus{. + libx11c, importc: "XkbGetKeyActions".} +proc XkbGetKeyBehaviors*(dpy: PDisplay, firstKey, nKeys: int16, + desc: PXkbDescPtr): TStatus{.libx11c, + importc: "XkbGetKeyBehaviors".} +proc XkbGetVirtualMods*(dpy: PDisplay, which: int16, desc: PXkbDescPtr): TStatus{. + libx11c, importc: "XkbGetVirtualMods".} +proc XkbGetKeyExplicitComponents*(dpy: PDisplay, firstKey, nKeys: int16, + desc: PXkbDescPtr): TStatus{.libx11c, importc: "XkbGetKeyExplicitComponents".} +proc XkbGetKeyModifierMap*(dpy: PDisplay, firstKey, nKeys: int16, + desc: PXkbDescPtr): TStatus{.libx11c, + importc: "XkbGetKeyModifierMap".} +proc XkbAllocControls*(xkb: PXkbDescPtr, which: int16): TStatus{.libx11c, importc: "XkbAllocControls".} +proc XkbFreeControls*(xkb: PXkbDescPtr, which: int16, freeMap: bool){.libx11c, importc: "XkbFreeControls".} +proc XkbGetControls*(dpy: PDisplay, which: int32, desc: PXkbDescPtr): TStatus{. + libx11c, importc: "XkbGetControls".} +proc XkbSetControls*(dpy: PDisplay, which: int32, desc: PXkbDescPtr): bool{. + libx11c, importc: "XkbSetControls".} +proc XkbNoteControlsChanges*(old: PXkbControlsChangesPtr, + new: PXkbControlsNotifyEvent, wanted: int16){. + libx11c, importc: "XkbNoteControlsChanges".} +proc XkbGetControlsChanges*(d: PDisplay, x: PXkbDescPtr, + c: PXkbControlsChangesPtr): TStatus +proc XkbChangeControls*(d: PDisplay, x: PXkbDescPtr, c: PXkbControlsChangesPtr): bool +proc XkbAllocCompatMap*(xkb: PXkbDescPtr, which, nInterpret: int16): TStatus{. + libx11c, importc: "XkbAllocCompatMap".} +proc XkbFreeCompatMap*(xkib: PXkbDescPtr, which: int16, freeMap: bool){.libx11c, importc: "XkbFreeCompatMap".} +proc XkbGetCompatMap*(dpy: PDisplay, which: int16, xkb: PXkbDescPtr): TStatus{. + libx11c, importc: "XkbGetCompatMap".} +proc XkbSetCompatMap*(dpy: PDisplay, which: int16, xkb: PXkbDescPtr, + updateActions: bool): bool{.libx11c, + importc: "XkbSetCompatMap".} +proc XkbAddSymInterpret*(xkb: PXkbDescPtr, si: PXkbSymInterpretPtr, + updateMap: bool, changes: PXkbChangesPtr): PXkbSymInterpretPtr{. + libx11c, importc: "XkbAddSymInterpret".} +proc XkbAllocNames*(xkb: PXkbDescPtr, which: int16, + nTotalRG, nTotalAliases: int16): TStatus{.libx11c, importc: "XkbAllocNames".} +proc XkbGetNames*(dpy: PDisplay, which: int16, desc: PXkbDescPtr): TStatus{. + libx11c, importc: "XkbGetNames".} +proc XkbSetNames*(dpy: PDisplay, which, firstType, nTypes: int16, + desc: PXkbDescPtr): bool{.libx11c, + importc: "XkbSetNames".} +proc XkbChangeNames*(dpy: PDisplay, xkb: PXkbDescPtr, + changes: PXkbNameChangesPtr): bool{.libx11c, + importc: "XkbChangeNames".} +proc XkbFreeNames*(xkb: PXkbDescPtr, which: int16, freeMap: bool){.libx11c, importc: "XkbFreeNames".} +proc XkbGetState*(dpy: PDisplay, deviceSpec: int16, rtrnState: PXkbStatePtr): TStatus{. + libx11c, importc: "XkbGetState".} +proc XkbSetMap*(dpy: PDisplay, which: int16, desc: PXkbDescPtr): bool{.libx11c, importc: "XkbSetMap".} +proc XkbChangeMap*(dpy: PDisplay, desc: PXkbDescPtr, changes: PXkbMapChangesPtr): bool{. + libx11c, importc: "XkbChangeMap".} +proc XkbSetDetectableAutoRepeat*(dpy: PDisplay, detectable: bool, + supported: ptr bool): bool{.libx11c, importc: "XkbSetDetectableAutoRepeat".} +proc XkbGetDetectableAutoRepeat*(dpy: PDisplay, supported: ptr bool): bool{. + libx11c, importc: "XkbGetDetectableAutoRepeat".} +proc XkbSetAutoResetControls*(dpy: PDisplay, changes: int16, + auto_ctrls, auto_values: PWord): bool{.libx11c, importc: "XkbSetAutoResetControls".} +proc XkbGetAutoResetControls*(dpy: PDisplay, auto_ctrls, auto_ctrl_values: PWord): bool{. + libx11c, importc: "XkbGetAutoResetControls".} +proc XkbSetPerClientControls*(dpy: PDisplay, change: int16, values: PWord): bool{. + libx11c, importc: "XkbSetPerClientControls".} +proc XkbGetPerClientControls*(dpy: PDisplay, ctrls: PWord): bool{.libx11c, importc: "XkbGetPerClientControls".} +proc XkbCopyKeyType*(`from`, into: PXkbKeyTypePtr): TStatus{.libx11c, importc: "XkbCopyKeyType".} +proc XkbCopyKeyTypes*(`from`, into: PXkbKeyTypePtr, num_types: int16): TStatus{. + libx11c, importc: "XkbCopyKeyTypes".} +proc XkbResizeKeyType*(xkb: PXkbDescPtr, type_ndx, map_count: int16, + want_preserve: bool, new_num_lvls: int16): TStatus{. + libx11c, importc: "XkbResizeKeyType".} +proc XkbResizeKeySyms*(desc: PXkbDescPtr, forKey, symsNeeded: int16): PKeySym{. + libx11c, importc: "XkbResizeKeySyms".} +proc XkbResizeKeyActions*(desc: PXkbDescPtr, forKey, actsNeeded: int16): PXkbAction{. + libx11c, importc: "XkbResizeKeyActions".} +proc XkbChangeTypesOfKey*(xkb: PXkbDescPtr, key, num_groups: int16, + groups: int16, newTypes: ptr int16, + pChanges: PXkbMapChangesPtr): TStatus{.libx11c, importc: "XkbChangeTypesOfKey".} + +proc XkbListComponents*(dpy: PDisplay, deviceSpec: int16, + ptrns: PXkbComponentNamesPtr, max_inout: ptr int16): PXkbComponentListPtr{. + libx11c, importc: "XkbListComponents".} +proc XkbFreeComponentList*(list: PXkbComponentListPtr){.libx11c, + importc: "XkbFreeComponentList".} +proc XkbGetKeyboard*(dpy: PDisplay, which, deviceSpec: int16): PXkbDescPtr{. + libx11c, importc: "XkbGetKeyboard".} +proc XkbGetKeyboardByName*(dpy: PDisplay, deviceSpec: int16, + names: PXkbComponentNamesPtr, want, need: int16, + load: bool): PXkbDescPtr{.libx11c, + importc: "XkbGetKeyboardByName".} + +proc XkbKeyTypesForCoreSymbols*(xkb: PXkbDescPtr, + map_width: int16, # keyboard device + core_syms: PKeySym, # always mapWidth symbols + protected: int16, # explicit key types + types_inout: ptr int16, # always four type indices + xkb_syms_rtrn: PKeySym): int16{.libx11c, importc: "XkbKeyTypesForCoreSymbols".} + # must have enough space +proc XkbApplyCompatMapToKey*(xkb: PXkbDescPtr, + key: TKeyCode, # key to be updated + changes: PXkbChangesPtr): bool{.libx11c, importc: "XkbApplyCompatMapToKey".} + # resulting changes to map +proc XkbUpdateMapFromCore*(xkb: PXkbDescPtr, + first_key: TKeyCode, # first changed key + num_keys, + map_width: int16, + core_keysyms: PKeySym, # symbols `from` core keymap + changes: PXkbChangesPtr): bool{.libx11c, importc: "XkbUpdateMapFromCore".} + +proc XkbAddDeviceLedInfo*(devi: PXkbDeviceInfoPtr, ledClass, ledId: int16): PXkbDeviceLedInfoPtr{. + libx11c, importc: "XkbAddDeviceLedInfo".} +proc XkbResizeDeviceButtonActions*(devi: PXkbDeviceInfoPtr, newTotal: int16): TStatus{. + libx11c, importc: "XkbResizeDeviceButtonActions".} +proc XkbAllocDeviceInfo*(deviceSpec, nButtons, szLeds: int16): PXkbDeviceInfoPtr{. + libx11c, importc: "XkbAllocDeviceInfo".} +proc XkbFreeDeviceInfo*(devi: PXkbDeviceInfoPtr, which: int16, freeDevI: bool){. + libx11c, importc: "XkbFreeDeviceInfo".} +proc XkbNoteDeviceChanges*(old: PXkbDeviceChangesPtr, + new: PXkbExtensionDeviceNotifyEvent, wanted: int16){. + libx11c, importc: "XkbNoteDeviceChanges".} +proc XkbGetDeviceInfo*(dpy: PDisplay, which, deviceSpec, ledClass, ledID: int16): PXkbDeviceInfoPtr{. + libx11c, importc: "XkbGetDeviceInfo".} +proc XkbGetDeviceInfoChanges*(dpy: PDisplay, devi: PXkbDeviceInfoPtr, + changes: PXkbDeviceChangesPtr): TStatus{.libx11c, importc: "XkbGetDeviceInfoChanges".} +proc XkbGetDeviceButtonActions*(dpy: PDisplay, devi: PXkbDeviceInfoPtr, + all: bool, first, nBtns: int16): TStatus{.libx11c, importc: "XkbGetDeviceButtonActions".} +proc XkbGetDeviceLedInfo*(dpy: PDisplay, devi: PXkbDeviceInfoPtr, + ledClass, ledId, which: int16): TStatus{.libx11c, importc: "XkbGetDeviceLedInfo".} +proc XkbSetDeviceInfo*(dpy: PDisplay, which: int16, devi: PXkbDeviceInfoPtr): bool{. + libx11c, importc: "XkbSetDeviceInfo".} +proc XkbChangeDeviceInfo*(dpy: PDisplay, desc: PXkbDeviceInfoPtr, + changes: PXkbDeviceChangesPtr): bool{.libx11c, importc: "XkbChangeDeviceInfo".} +proc XkbSetDeviceLedInfo*(dpy: PDisplay, devi: PXkbDeviceInfoPtr, + ledClass, ledID, which: int16): bool{.libx11c, importc: "XkbSetDeviceLedInfo".} +proc XkbSetDeviceButtonActions*(dpy: PDisplay, devi: PXkbDeviceInfoPtr, + first, nBtns: int16): bool{.libx11c, importc: "XkbSetDeviceButtonActions".} + +proc XkbToControl*(c: int8): int8{.libx11c, + importc: "XkbToControl".} + +proc XkbSetDebuggingFlags*(dpy: PDisplay, mask, flags: int16, msg: cstring, + ctrls_mask, ctrls, rtrn_flags, rtrn_ctrls: int16): bool{. + libx11c, importc: "XkbSetDebuggingFlags".} +proc XkbApplyVirtualModChanges*(xkb: PXkbDescPtr, changed: int16, + changes: PXkbChangesPtr): bool{.libx11c, importc: "XkbApplyVirtualModChanges".} + +# implementation + +proc XkbNoteIndicatorMapChanges(o, n: PXkbIndicatorChangesPtr, w: int16) = + ##define XkbNoteIndicatorMapChanges(o,n,w) ((o)->map_changes|=((n)->map_changes&(w))) + o.map_changes = o.map_changes or (n.map_changes and w) + +proc XkbNoteIndicatorStateChanges(o, n: PXkbIndicatorChangesPtr, w: int16) = + ##define XkbNoteIndicatorStateChanges(o,n,w) ((o)->state_changes|=((n)->state_changes&(w))) + o.state_changes = o.state_changes or (n.state_changes and (w)) + +proc XkbGetIndicatorMapChanges(d: PDisplay, x: PXkbDescPtr, + c: PXkbIndicatorChangesPtr): TStatus = + ##define XkbGetIndicatorMapChanges(d,x,c) (XkbGetIndicatorMap((d),(c)->map_changes,x) + result = XkbGetIndicatorMap(d, c.map_changes, x) + +proc XkbChangeIndicatorMaps(d: PDisplay, x: PXkbDescPtr, + c: PXkbIndicatorChangesPtr): bool = + ##define XkbChangeIndicatorMaps(d,x,c) (XkbSetIndicatorMap((d),(c)->map_changes,x)) + result = XkbSetIndicatorMap(d, c.map_changes, x) + +proc XkbGetControlsChanges(d: PDisplay, x: PXkbDescPtr, + c: PXkbControlsChangesPtr): TStatus = + ##define XkbGetControlsChanges(d,x,c) XkbGetControls(d,(c)->changed_ctrls,x) + result = XkbGetControls(d, c.changed_ctrls, x) + +proc XkbChangeControls(d: PDisplay, x: PXkbDescPtr, c: PXkbControlsChangesPtr): bool = + ##define XkbChangeControls(d,x,c) XkbSetControls(d,(c)->changed_ctrls,x) + result = XkbSetControls(d, c.changed_ctrls, x) diff --git a/tests/deps/x11-1.0/xlib.nim b/tests/deps/x11-1.0/xlib.nim new file mode 100644 index 000000000..e9f211936 --- /dev/null +++ b/tests/deps/x11-1.0/xlib.nim @@ -0,0 +1,2026 @@ + +import + x + +include "x11pragma.nim" + +type + cunsigned* = cint + Pcint* = ptr cint + PPcint* = ptr Pcint + PPcuchar* = ptr ptr cuchar + PWideChar* = ptr int16 + PPChar* = ptr cstring + PPPChar* = ptr ptr cstring + Pculong* = ptr culong + Pcuchar* = cstring + Pcuint* = ptr cuint + Pcushort* = ptr uint16 +# Automatically converted by H2Pas 0.99.15 from xlib.h +# The following command line parameters were used: +# -p +# -T +# -S +# -d +# -c +# xlib.h + +const + XlibSpecificationRelease* = 6 + +type + PXPointer* = ptr TXPointer + TXPointer* = ptr char + PBool* = ptr TBool + TBool* = int #cint? + PStatus* = ptr TStatus + TStatus* = cint + +const + QueuedAlready* = 0 + QueuedAfterReading* = 1 + QueuedAfterFlush* = 2 + +type + PPXExtData* = ptr PXExtData + PXExtData* = ptr TXExtData + TXExtData*{.final.} = object + number*: cint + next*: PXExtData + free_private*: proc (extension: PXExtData): cint{.cdecl.} + private_data*: TXPointer + + PXExtCodes* = ptr TXExtCodes + TXExtCodes*{.final.} = object + extension*: cint + major_opcode*: cint + first_event*: cint + first_error*: cint + + PXPixmapFormatValues* = ptr TXPixmapFormatValues + TXPixmapFormatValues*{.final.} = object + depth*: cint + bits_per_pixel*: cint + scanline_pad*: cint + + PXGCValues* = ptr TXGCValues + TXGCValues*{.final.} = object + function*: cint + plane_mask*: culong + foreground*: culong + background*: culong + line_width*: cint + line_style*: cint + cap_style*: cint + join_style*: cint + fill_style*: cint + fill_rule*: cint + arc_mode*: cint + tile*: TPixmap + stipple*: TPixmap + ts_x_origin*: cint + ts_y_origin*: cint + font*: TFont + subwindow_mode*: cint + graphics_exposures*: TBool + clip_x_origin*: cint + clip_y_origin*: cint + clip_mask*: TPixmap + dash_offset*: cint + dashes*: cchar + + PXGC* = ptr TXGC + TXGC*{.final.} = object + TGC* = PXGC + PGC* = ptr TGC + PVisual* = ptr TVisual + TVisual*{.final.} = object + ext_data*: PXExtData + visualid*: TVisualID + c_class*: cint + red_mask*, green_mask*, blue_mask*: culong + bits_per_rgb*: cint + map_entries*: cint + + PDepth* = ptr TDepth + TDepth*{.final.} = object + depth*: cint + nvisuals*: cint + visuals*: PVisual + + PXDisplay* = ptr TXDisplay + TXDisplay*{.final.} = object + PScreen* = ptr TScreen + TScreen*{.final.} = object + ext_data*: PXExtData + display*: PXDisplay + root*: TWindow + width*, height*: cint + mwidth*, mheight*: cint + ndepths*: cint + depths*: PDepth + root_depth*: cint + root_visual*: PVisual + default_gc*: TGC + cmap*: TColormap + white_pixel*: culong + black_pixel*: culong + max_maps*, min_maps*: cint + backing_store*: cint + save_unders*: TBool + root_input_mask*: clong + + PScreenFormat* = ptr TScreenFormat + TScreenFormat*{.final.} = object + ext_data*: PXExtData + depth*: cint + bits_per_pixel*: cint + scanline_pad*: cint + + PXSetWindowAttributes* = ptr TXSetWindowAttributes + TXSetWindowAttributes*{.final.} = object + background_pixmap*: TPixmap + background_pixel*: culong + border_pixmap*: TPixmap + border_pixel*: culong + bit_gravity*: cint + win_gravity*: cint + backing_store*: cint + backing_planes*: culong + backing_pixel*: culong + save_under*: TBool + event_mask*: clong + do_not_propagate_mask*: clong + override_redirect*: TBool + colormap*: TColormap + cursor*: TCursor + + PXWindowAttributes* = ptr TXWindowAttributes + TXWindowAttributes*{.final.} = object + x*, y*: cint + width*, height*: cint + border_width*: cint + depth*: cint + visual*: PVisual + root*: TWindow + c_class*: cint + bit_gravity*: cint + win_gravity*: cint + backing_store*: cint + backing_planes*: culong + backing_pixel*: culong + save_under*: TBool + colormap*: TColormap + map_installed*: TBool + map_state*: cint + all_event_masks*: clong + your_event_mask*: clong + do_not_propagate_mask*: clong + override_redirect*: TBool + screen*: PScreen + + PXHostAddress* = ptr TXHostAddress + TXHostAddress*{.final.} = object + family*: cint + len*: cint + address*: cstring + + PXServerInterpretedAddress* = ptr TXServerInterpretedAddress + TXServerInterpretedAddress*{.final.} = object + typelength*: cint + valuelength*: cint + theType*: cstring + value*: cstring + + PXImage* = ptr TXImage + TF*{.final.} = object + create_image*: proc (para1: PXDisplay, para2: PVisual, para3: cuint, + para4: cint, para5: cint, para6: cstring, para7: cuint, + para8: cuint, para9: cint, para10: cint): PXImage{. + cdecl.} + destroy_image*: proc (para1: PXImage): cint{.cdecl.} + get_pixel*: proc (para1: PXImage, para2: cint, para3: cint): culong{.cdecl.} + put_pixel*: proc (para1: PXImage, para2: cint, para3: cint, para4: culong): cint{. + cdecl.} + sub_image*: proc (para1: PXImage, para2: cint, para3: cint, para4: cuint, + para5: cuint): PXImage{.cdecl.} + add_pixel*: proc (para1: PXImage, para2: clong): cint{.cdecl.} + + TXImage*{.final.} = object + width*, height*: cint + xoffset*: cint + format*: cint + data*: cstring + byte_order*: cint + bitmap_unit*: cint + bitmap_bit_order*: cint + bitmap_pad*: cint + depth*: cint + bytes_per_line*: cint + bits_per_pixel*: cint + red_mask*: culong + green_mask*: culong + blue_mask*: culong + obdata*: TXPointer + f*: TF + + PXWindowChanges* = ptr TXWindowChanges + TXWindowChanges*{.final.} = object + x*, y*: cint + width*, height*: cint + border_width*: cint + sibling*: TWindow + stack_mode*: cint + + PXColor* = ptr TXColor + TXColor*{.final.} = object + pixel*: culong + red*, green*, blue*: cushort + flags*: cchar + pad*: cchar + + PXSegment* = ptr TXSegment + TXSegment*{.final.} = object + x1*, y1*, x2*, y2*: cshort + + PXPoint* = ptr TXPoint + TXPoint*{.final.} = object + x*, y*: cshort + + PXRectangle* = ptr TXRectangle + TXRectangle*{.final.} = object + x*, y*: cshort + width*, height*: cushort + + PXArc* = ptr TXArc + TXArc*{.final.} = object + x*, y*: cshort + width*, height*: cushort + angle1*, angle2*: cshort + + PXKeyboardControl* = ptr TXKeyboardControl + TXKeyboardControl*{.final.} = object + key_click_percent*: cint + bell_percent*: cint + bell_pitch*: cint + bell_duration*: cint + led*: cint + led_mode*: cint + key*: cint + auto_repeat_mode*: cint + + PXKeyboardState* = ptr TXKeyboardState + TXKeyboardState*{.final.} = object + key_click_percent*: cint + bell_percent*: cint + bell_pitch*, bell_duration*: cuint + led_mask*: culong + global_auto_repeat*: cint + auto_repeats*: array[0..31, cchar] + + PXTimeCoord* = ptr TXTimeCoord + TXTimeCoord*{.final.} = object + time*: TTime + x*, y*: cshort + + PXModifierKeymap* = ptr TXModifierKeymap + TXModifierKeymap*{.final.} = object + max_keypermod*: cint + modifiermap*: PKeyCode + + PDisplay* = ptr TDisplay + TDisplay* = TXDisplay + PXPrivate* = ptr TXPrivate + TXPrivate*{.final.} = object + PXrmHashBucketRec* = ptr TXrmHashBucketRec + TXrmHashBucketRec*{.final.} = object + PXPrivDisplay* = ptr TXPrivDisplay + TXPrivDisplay*{.final.} = object + ext_data*: PXExtData + private1*: PXPrivate + fd*: cint + private2*: cint + proto_major_version*: cint + proto_minor_version*: cint + vendor*: cstring + private3*: TXID + private4*: TXID + private5*: TXID + private6*: cint + resource_alloc*: proc (para1: PXDisplay): TXID{.cdecl.} + byte_order*: cint + bitmap_unit*: cint + bitmap_pad*: cint + bitmap_bit_order*: cint + nformats*: cint + pixmap_format*: PScreenFormat + private8*: cint + release*: cint + private9*, private10*: PXPrivate + qlen*: cint + last_request_read*: culong + request*: culong + private11*: TXPointer + private12*: TXPointer + private13*: TXPointer + private14*: TXPointer + max_request_size*: cunsigned + db*: PXrmHashBucketRec + private15*: proc (para1: PXDisplay): cint{.cdecl.} + display_name*: cstring + default_screen*: cint + nscreens*: cint + screens*: PScreen + motion_buffer*: culong + private16*: culong + min_keycode*: cint + max_keycode*: cint + private17*: TXPointer + private18*: TXPointer + private19*: cint + xdefaults*: cstring + + PXKeyEvent* = ptr TXKeyEvent + TXKeyEvent*{.final.} = object + theType*: cint + serial*: culong + send_event*: TBool + display*: PDisplay + window*: TWindow + root*: TWindow + subwindow*: TWindow + time*: TTime + x*, y*: cint + x_root*, y_root*: cint + state*: cuint + keycode*: cuint + same_screen*: TBool + + PXKeyPressedEvent* = ptr TXKeyPressedEvent + TXKeyPressedEvent* = TXKeyEvent + PXKeyReleasedEvent* = ptr TXKeyReleasedEvent + TXKeyReleasedEvent* = TXKeyEvent + PXButtonEvent* = ptr TXButtonEvent + TXButtonEvent*{.final.} = object + theType*: cint + serial*: culong + send_event*: TBool + display*: PDisplay + window*: TWindow + root*: TWindow + subwindow*: TWindow + time*: TTime + x*, y*: cint + x_root*, y_root*: cint + state*: cuint + button*: cuint + same_screen*: TBool + + PXButtonPressedEvent* = ptr TXButtonPressedEvent + TXButtonPressedEvent* = TXButtonEvent + PXButtonReleasedEvent* = ptr TXButtonReleasedEvent + TXButtonReleasedEvent* = TXButtonEvent + PXMotionEvent* = ptr TXMotionEvent + TXMotionEvent*{.final.} = object + theType*: cint + serial*: culong + send_event*: TBool + display*: PDisplay + window*: TWindow + root*: TWindow + subwindow*: TWindow + time*: TTime + x*, y*: cint + x_root*, y_root*: cint + state*: cuint + is_hint*: cchar + same_screen*: TBool + + PXPointerMovedEvent* = ptr TXPointerMovedEvent + TXPointerMovedEvent* = TXMotionEvent + PXCrossingEvent* = ptr TXCrossingEvent + TXCrossingEvent*{.final.} = object + theType*: cint + serial*: culong + send_event*: TBool + display*: PDisplay + window*: TWindow + root*: TWindow + subwindow*: TWindow + time*: TTime + x*, y*: cint + x_root*, y_root*: cint + mode*: cint + detail*: cint + same_screen*: TBool + focus*: TBool + state*: cuint + + PXEnterWindowEvent* = ptr TXEnterWindowEvent + TXEnterWindowEvent* = TXCrossingEvent + PXLeaveWindowEvent* = ptr TXLeaveWindowEvent + TXLeaveWindowEvent* = TXCrossingEvent + PXFocusChangeEvent* = ptr TXFocusChangeEvent + TXFocusChangeEvent*{.final.} = object + theType*: cint + serial*: culong + send_event*: TBool + display*: PDisplay + window*: TWindow + mode*: cint + detail*: cint + + PXFocusInEvent* = ptr TXFocusInEvent + TXFocusInEvent* = TXFocusChangeEvent + PXFocusOutEvent* = ptr TXFocusOutEvent + TXFocusOutEvent* = TXFocusChangeEvent + PXKeymapEvent* = ptr TXKeymapEvent + TXKeymapEvent*{.final.} = object + theType*: cint + serial*: culong + send_event*: TBool + display*: PDisplay + window*: TWindow + key_vector*: array[0..31, cchar] + + PXExposeEvent* = ptr TXExposeEvent + TXExposeEvent*{.final.} = object + theType*: cint + serial*: culong + send_event*: TBool + display*: PDisplay + window*: TWindow + x*, y*: cint + width*, height*: cint + count*: cint + + PXGraphicsExposeEvent* = ptr TXGraphicsExposeEvent + TXGraphicsExposeEvent*{.final.} = object + theType*: cint + serial*: culong + send_event*: TBool + display*: PDisplay + drawable*: TDrawable + x*, y*: cint + width*, height*: cint + count*: cint + major_code*: cint + minor_code*: cint + + PXNoExposeEvent* = ptr TXNoExposeEvent + TXNoExposeEvent*{.final.} = object + theType*: cint + serial*: culong + send_event*: TBool + display*: PDisplay + drawable*: TDrawable + major_code*: cint + minor_code*: cint + + PXVisibilityEvent* = ptr TXVisibilityEvent + TXVisibilityEvent*{.final.} = object + theType*: cint + serial*: culong + send_event*: TBool + display*: PDisplay + window*: TWindow + state*: cint + + PXCreateWindowEvent* = ptr TXCreateWindowEvent + TXCreateWindowEvent*{.final.} = object + theType*: cint + serial*: culong + send_event*: TBool + display*: PDisplay + parent*: TWindow + window*: TWindow + x*, y*: cint + width*, height*: cint + border_width*: cint + override_redirect*: TBool + + PXDestroyWindowEvent* = ptr TXDestroyWindowEvent + TXDestroyWindowEvent*{.final.} = object + theType*: cint + serial*: culong + send_event*: TBool + display*: PDisplay + event*: TWindow + window*: TWindow + + PXUnmapEvent* = ptr TXUnmapEvent + TXUnmapEvent*{.final.} = object + theType*: cint + serial*: culong + send_event*: TBool + display*: PDisplay + event*: TWindow + window*: TWindow + from_configure*: TBool + + PXMapEvent* = ptr TXMapEvent + TXMapEvent*{.final.} = object + theType*: cint + serial*: culong + send_event*: TBool + display*: PDisplay + event*: TWindow + window*: TWindow + override_redirect*: TBool + + PXMapRequestEvent* = ptr TXMapRequestEvent + TXMapRequestEvent*{.final.} = object + theType*: cint + serial*: culong + send_event*: TBool + display*: PDisplay + parent*: TWindow + window*: TWindow + + PXReparentEvent* = ptr TXReparentEvent + TXReparentEvent*{.final.} = object + theType*: cint + serial*: culong + send_event*: TBool + display*: PDisplay + event*: TWindow + window*: TWindow + parent*: TWindow + x*, y*: cint + override_redirect*: TBool + + PXConfigureEvent* = ptr TXConfigureEvent + TXConfigureEvent*{.final.} = object + theType*: cint + serial*: culong + send_event*: TBool + display*: PDisplay + event*: TWindow + window*: TWindow + x*, y*: cint + width*, height*: cint + border_width*: cint + above*: TWindow + override_redirect*: TBool + + PXGravityEvent* = ptr TXGravityEvent + TXGravityEvent*{.final.} = object + theType*: cint + serial*: culong + send_event*: TBool + display*: PDisplay + event*: TWindow + window*: TWindow + x*, y*: cint + + PXResizeRequestEvent* = ptr TXResizeRequestEvent + TXResizeRequestEvent*{.final.} = object + theType*: cint + serial*: culong + send_event*: TBool + display*: PDisplay + window*: TWindow + width*, height*: cint + + PXConfigureRequestEvent* = ptr TXConfigureRequestEvent + TXConfigureRequestEvent*{.final.} = object + theType*: cint + serial*: culong + send_event*: TBool + display*: PDisplay + parent*: TWindow + window*: TWindow + x*, y*: cint + width*, height*: cint + border_width*: cint + above*: TWindow + detail*: cint + value_mask*: culong + + PXCirculateEvent* = ptr TXCirculateEvent + TXCirculateEvent*{.final.} = object + theType*: cint + serial*: culong + send_event*: TBool + display*: PDisplay + event*: TWindow + window*: TWindow + place*: cint + + PXCirculateRequestEvent* = ptr TXCirculateRequestEvent + TXCirculateRequestEvent*{.final.} = object + theType*: cint + serial*: culong + send_event*: TBool + display*: PDisplay + parent*: TWindow + window*: TWindow + place*: cint + + PXPropertyEvent* = ptr TXPropertyEvent + TXPropertyEvent*{.final.} = object + theType*: cint + serial*: culong + send_event*: TBool + display*: PDisplay + window*: TWindow + atom*: TAtom + time*: TTime + state*: cint + + PXSelectionClearEvent* = ptr TXSelectionClearEvent + TXSelectionClearEvent*{.final.} = object + theType*: cint + serial*: culong + send_event*: TBool + display*: PDisplay + window*: TWindow + selection*: TAtom + time*: TTime + + PXSelectionRequestEvent* = ptr TXSelectionRequestEvent + TXSelectionRequestEvent*{.final.} = object + theType*: cint + serial*: culong + send_event*: TBool + display*: PDisplay + owner*: TWindow + requestor*: TWindow + selection*: TAtom + target*: TAtom + property*: TAtom + time*: TTime + + PXSelectionEvent* = ptr TXSelectionEvent + TXSelectionEvent*{.final.} = object + theType*: cint + serial*: culong + send_event*: TBool + display*: PDisplay + requestor*: TWindow + selection*: TAtom + target*: TAtom + property*: TAtom + time*: TTime + + PXColormapEvent* = ptr TXColormapEvent + TXColormapEvent*{.final.} = object + theType*: cint + serial*: culong + send_event*: TBool + display*: PDisplay + window*: TWindow + colormap*: TColormap + c_new*: TBool + state*: cint + + PXClientMessageEvent* = ptr TXClientMessageEvent + TXClientMessageEvent*{.final.} = object + theType*: cint + serial*: culong + send_event*: TBool + display*: PDisplay + window*: TWindow + message_type*: TAtom + format*: cint + data*: array[0..4, clong] # using clong here to be 32/64-bit dependent + # as the original C union + + PXMappingEvent* = ptr TXMappingEvent + TXMappingEvent*{.final.} = object + theType*: cint + serial*: culong + send_event*: TBool + display*: PDisplay + window*: TWindow + request*: cint + first_keycode*: cint + count*: cint + + PXErrorEvent* = ptr TXErrorEvent + TXErrorEvent*{.final.} = object + theType*: cint + display*: PDisplay + resourceid*: TXID + serial*: culong + error_code*: cuchar + request_code*: cuchar + minor_code*: cuchar + + PXAnyEvent* = ptr TXAnyEvent + TXAnyEvent*{.final.} = object + theType*: cint + serial*: culong + send_event*: TBool + display*: PDisplay + window*: TWindow + + PXEvent* = ptr TXEvent + TXEvent*{.final.} = object + theType*: cint + pad*: array[0..22, clong] # + # case longint of + # 0 : ( theType : cint ); + # 1 : ( xany : TXAnyEvent ); + # 2 : ( xkey : TXKeyEvent ); + # 3 : ( xbutton : TXButtonEvent ); + # 4 : ( xmotion : TXMotionEvent ); + # 5 : ( xcrossing : TXCrossingEvent ); + # 6 : ( xfocus : TXFocusChangeEvent ); + # 7 : ( xexpose : TXExposeEvent ); + # 8 : ( xgraphicsexpose : TXGraphicsExposeEvent ); + # 9 : ( xnoexpose : TXNoExposeEvent ); + # 10 : ( xvisibility : TXVisibilityEvent ); + # 11 : ( xcreatewindow : TXCreateWindowEvent ); + # 12 : ( xdestroywindow : TXDestroyWindowEvent ); + # 13 : ( xunmap : TXUnmapEvent ); + # 14 : ( xmap : TXMapEvent ); + # 15 : ( xmaprequest : TXMapRequestEvent ); + # 16 : ( xreparent : TXReparentEvent ); + # 17 : ( xconfigure : TXConfigureEvent ); + # 18 : ( xgravity : TXGravityEvent ); + # 19 : ( xresizerequest : TXResizeRequestEvent ); + # 20 : ( xconfigurerequest : TXConfigureRequestEvent ); + # 21 : ( xcirculate : TXCirculateEvent ); + # 22 : ( xcirculaterequest : TXCirculateRequestEvent ); + # 23 : ( xproperty : TXPropertyEvent ); + # 24 : ( xselectionclear : TXSelectionClearEvent ); + # 25 : ( xselectionrequest : TXSelectionRequestEvent ); + # 26 : ( xselection : TXSelectionEvent ); + # 27 : ( xcolormap : TXColormapEvent ); + # 28 : ( xclient : TXClientMessageEvent ); + # 29 : ( xmapping : TXMappingEvent ); + # 30 : ( xerror : TXErrorEvent ); + # 31 : ( xkeymap : TXKeymapEvent ); + # 32 : ( pad : array[0..23] of clong ); + # + + +proc xclient*(e: PXEvent): PXClientMessageEvent = + ## Treats XEvent as XClientMessageEvent + return cast[PXClientMessageEvent](e) + +proc xclient*(e: var TXEvent): PXClientMessageEvent = + return xclient(PXEvent(e.addr)) + +type + PXCharStruct* = ptr TXCharStruct + TXCharStruct*{.final.} = object + lbearing*: cshort + rbearing*: cshort + width*: cshort + ascent*: cshort + descent*: cshort + attributes*: cushort + + PXFontProp* = ptr TXFontProp + TXFontProp*{.final.} = object + name*: TAtom + card32*: culong + + PPPXFontStruct* = ptr PPXFontStruct + PPXFontStruct* = ptr PXFontStruct + PXFontStruct* = ptr TXFontStruct + TXFontStruct*{.final.} = object + ext_data*: PXExtData + fid*: TFont + direction*: cunsigned + min_char_or_byte2*: cunsigned + max_char_or_byte2*: cunsigned + min_byte1*: cunsigned + max_byte1*: cunsigned + all_chars_exist*: TBool + default_char*: cunsigned + n_properties*: cint + properties*: PXFontProp + min_bounds*: TXCharStruct + max_bounds*: TXCharStruct + per_char*: PXCharStruct + ascent*: cint + descent*: cint + + PXTextItem* = ptr TXTextItem + TXTextItem*{.final.} = object + chars*: cstring + nchars*: cint + delta*: cint + font*: TFont + + PXChar2b* = ptr TXChar2b + TXChar2b*{.final.} = object + byte1*: cuchar + byte2*: cuchar + + PXTextItem16* = ptr TXTextItem16 + TXTextItem16*{.final.} = object + chars*: PXChar2b + nchars*: cint + delta*: cint + font*: TFont + + PXEDataObject* = ptr TXEDataObject + TXEDataObject*{.final.} = object + display*: PDisplay #case longint of + # 0 : ( display : PDisplay ); + # 1 : ( gc : TGC ); + # 2 : ( visual : PVisual ); + # 3 : ( screen : PScreen ); + # 4 : ( pixmap_format : PScreenFormat ); + # 5 : ( font : PXFontStruct ); + + PXFontSetExtents* = ptr TXFontSetExtents + TXFontSetExtents*{.final.} = object + max_ink_extent*: TXRectangle + max_logical_extent*: TXRectangle + + PXOM* = ptr TXOM + TXOM*{.final.} = object + PXOC* = ptr TXOC + TXOC*{.final.} = object + TXFontSet* = PXOC + PXFontSet* = ptr TXFontSet + PXmbTextItem* = ptr TXmbTextItem + TXmbTextItem*{.final.} = object + chars*: cstring + nchars*: cint + delta*: cint + font_set*: TXFontSet + + PXwcTextItem* = ptr TXwcTextItem + TXwcTextItem*{.final.} = object + chars*: PWideChar #wchar_t* + nchars*: cint + delta*: cint + font_set*: TXFontSet + + +const + XNRequiredCharSet* = "requiredCharSet" + XNQueryOrientation* = "queryOrientation" + XNBaseFontName* = "baseFontName" + XNOMAutomatic* = "omAutomatic" + XNMissingCharSet* = "missingCharSet" + XNDefaultString* = "defaultString" + XNOrientation* = "orientation" + XNDirectionalDependentDrawing* = "directionalDependentDrawing" + XNContextualDrawing* = "contextualDrawing" + XNFontInfo* = "fontInfo" + +type + PXOMCharSetList* = ptr TXOMCharSetList + TXOMCharSetList*{.final.} = object + charset_count*: cint + charset_list*: PPChar + + PXOrientation* = ptr TXOrientation + TXOrientation* = enum + XOMOrientation_LTR_TTB, XOMOrientation_RTL_TTB, XOMOrientation_TTB_LTR, + XOMOrientation_TTB_RTL, XOMOrientation_Context + PXOMOrientation* = ptr TXOMOrientation + TXOMOrientation*{.final.} = object + num_orientation*: cint + orientation*: PXOrientation + + PXOMFontInfo* = ptr TXOMFontInfo + TXOMFontInfo*{.final.} = object + num_font*: cint + font_struct_list*: ptr PXFontStruct + font_name_list*: PPChar + + PXIM* = ptr TXIM + TXIM*{.final.} = object + PXIC* = ptr TXIC + TXIC*{.final.} = object + TXIMProc* = proc (para1: TXIM, para2: TXPointer, para3: TXPointer){.cdecl.} + TXICProc* = proc (para1: TXIC, para2: TXPointer, para3: TXPointer): TBool{. + cdecl.} + TXIDProc* = proc (para1: PDisplay, para2: TXPointer, para3: TXPointer){.cdecl.} + PXIMStyle* = ptr TXIMStyle + TXIMStyle* = culong + PXIMStyles* = ptr TXIMStyles + TXIMStyles*{.final.} = object + count_styles*: cushort + supported_styles*: PXIMStyle + + +const + XIMPreeditArea* = 0x00000001 + XIMPreeditCallbacks* = 0x00000002 + XIMPreeditPosition* = 0x00000004 + XIMPreeditNothing* = 0x00000008 + XIMPreeditNone* = 0x00000010 + XIMStatusArea* = 0x00000100 + XIMStatusCallbacks* = 0x00000200 + XIMStatusNothing* = 0x00000400 + XIMStatusNone* = 0x00000800 + XNVaNestedList* = "XNVaNestedList" + XNQueryInputStyle* = "queryInputStyle" + XNClientWindow* = "clientWindow" + XNInputStyle* = "inputStyle" + XNFocusWindow* = "focusWindow" + XNResourceName* = "resourceName" + XNResourceClass* = "resourceClass" + XNGeometryCallback* = "geometryCallback" + XNDestroyCallback* = "destroyCallback" + XNFilterEvents* = "filterEvents" + XNPreeditStartCallback* = "preeditStartCallback" + XNPreeditDoneCallback* = "preeditDoneCallback" + XNPreeditDrawCallback* = "preeditDrawCallback" + XNPreeditCaretCallback* = "preeditCaretCallback" + XNPreeditStateNotifyCallback* = "preeditStateNotifyCallback" + XNPreeditAttributes* = "preeditAttributes" + XNStatusStartCallback* = "statusStartCallback" + XNStatusDoneCallback* = "statusDoneCallback" + XNStatusDrawCallback* = "statusDrawCallback" + XNStatusAttributes* = "statusAttributes" + XNArea* = "area" + XNAreaNeeded* = "areaNeeded" + XNSpotLocation* = "spotLocation" + XNColormap* = "colorMap" + XNStdColormap* = "stdColorMap" + XNForeground* = "foreground" + XNBackground* = "background" + XNBackgroundPixmap* = "backgroundPixmap" + XNFontSet* = "fontSet" + XNLineSpace* = "lineSpace" + XNCursor* = "cursor" + XNQueryIMValuesList* = "queryIMValuesList" + XNQueryICValuesList* = "queryICValuesList" + XNVisiblePosition* = "visiblePosition" + XNR6PreeditCallback* = "r6PreeditCallback" + XNStringConversionCallback* = "stringConversionCallback" + XNStringConversion* = "stringConversion" + XNResetState* = "resetState" + XNHotKey* = "hotKey" + XNHotKeyState* = "hotKeyState" + XNPreeditState* = "preeditState" + XNSeparatorofNestedList* = "separatorofNestedList" + XBufferOverflow* = - (1) + XLookupNone* = 1 + XLookupChars* = 2 + XLookupKeySymVal* = 3 + XLookupBoth* = 4 + +type + PXVaNestedList* = ptr TXVaNestedList + TXVaNestedList* = pointer + PXIMCallback* = ptr TXIMCallback + TXIMCallback*{.final.} = object + client_data*: TXPointer + callback*: TXIMProc + + PXICCallback* = ptr TXICCallback + TXICCallback*{.final.} = object + client_data*: TXPointer + callback*: TXICProc + + PXIMFeedback* = ptr TXIMFeedback + TXIMFeedback* = culong + +const + XIMReverse* = 1 + XIMUnderline* = 1 shl 1 + XIMHighlight* = 1 shl 2 + XIMPrimary* = 1 shl 5 + XIMSecondary* = 1 shl 6 + XIMTertiary* = 1 shl 7 + XIMVisibleToForward* = 1 shl 8 + XIMVisibleToBackword* = 1 shl 9 + XIMVisibleToCenter* = 1 shl 10 + +type + PXIMText* = ptr TXIMText + TXIMText*{.final.} = object + len*: cushort + feedback*: PXIMFeedback + encoding_is_wchar*: TBool + multi_byte*: cstring + + PXIMPreeditState* = ptr TXIMPreeditState + TXIMPreeditState* = culong + +const + XIMPreeditUnKnown* = 0 + XIMPreeditEnable* = 1 + XIMPreeditDisable* = 1 shl 1 + +type + PXIMPreeditStateNotifyCallbackStruct* = ptr TXIMPreeditStateNotifyCallbackStruct + TXIMPreeditStateNotifyCallbackStruct*{.final.} = object + state*: TXIMPreeditState + + PXIMResetState* = ptr TXIMResetState + TXIMResetState* = culong + +const + XIMInitialState* = 1 + XIMPreserveState* = 1 shl 1 + +type + PXIMStringConversionFeedback* = ptr TXIMStringConversionFeedback + TXIMStringConversionFeedback* = culong + +const + XIMStringConversionLeftEdge* = 0x00000001 + XIMStringConversionRightEdge* = 0x00000002 + XIMStringConversionTopEdge* = 0x00000004 + XIMStringConversionBottomEdge* = 0x00000008 + XIMStringConversionConcealed* = 0x00000010 + XIMStringConversionWrapped* = 0x00000020 + +type + PXIMStringConversionText* = ptr TXIMStringConversionText + TXIMStringConversionText*{.final.} = object + len*: cushort + feedback*: PXIMStringConversionFeedback + encoding_is_wchar*: TBool + mbs*: cstring + + PXIMStringConversionPosition* = ptr TXIMStringConversionPosition + TXIMStringConversionPosition* = cushort + PXIMStringConversionType* = ptr TXIMStringConversionType + TXIMStringConversionType* = cushort + +const + XIMStringConversionBuffer* = 0x00000001 + XIMStringConversionLine* = 0x00000002 + XIMStringConversionWord* = 0x00000003 + XIMStringConversionChar* = 0x00000004 + +type + PXIMStringConversionOperation* = ptr TXIMStringConversionOperation + TXIMStringConversionOperation* = cushort + +const + XIMStringConversionSubstitution* = 0x00000001 + XIMStringConversionRetrieval* = 0x00000002 + +type + PXIMCaretDirection* = ptr TXIMCaretDirection + TXIMCaretDirection* = enum + XIMForwardChar, XIMBackwardChar, XIMForwardWord, XIMBackwardWord, + XIMCaretUp, XIMCaretDown, XIMNextLine, XIMPreviousLine, XIMLineStart, + XIMLineEnd, XIMAbsolutePosition, XIMDontChange + PXIMStringConversionCallbackStruct* = ptr TXIMStringConversionCallbackStruct + TXIMStringConversionCallbackStruct*{.final.} = object + position*: TXIMStringConversionPosition + direction*: TXIMCaretDirection + operation*: TXIMStringConversionOperation + factor*: cushort + text*: PXIMStringConversionText + + PXIMPreeditDrawCallbackStruct* = ptr TXIMPreeditDrawCallbackStruct + TXIMPreeditDrawCallbackStruct*{.final.} = object + caret*: cint + chg_first*: cint + chg_length*: cint + text*: PXIMText + + PXIMCaretStyle* = ptr TXIMCaretStyle + TXIMCaretStyle* = enum + XIMIsInvisible, XIMIsPrimary, XIMIsSecondary + PXIMPreeditCaretCallbackStruct* = ptr TXIMPreeditCaretCallbackStruct + TXIMPreeditCaretCallbackStruct*{.final.} = object + position*: cint + direction*: TXIMCaretDirection + style*: TXIMCaretStyle + + PXIMStatusDataType* = ptr TXIMStatusDataType + TXIMStatusDataType* = enum + XIMTextType, XIMBitmapType + PXIMStatusDrawCallbackStruct* = ptr TXIMStatusDrawCallbackStruct + TXIMStatusDrawCallbackStruct*{.final.} = object + theType*: TXIMStatusDataType + bitmap*: TPixmap + + PXIMHotKeyTrigger* = ptr TXIMHotKeyTrigger + TXIMHotKeyTrigger*{.final.} = object + keysym*: TKeySym + modifier*: cint + modifier_mask*: cint + + PXIMHotKeyTriggers* = ptr TXIMHotKeyTriggers + TXIMHotKeyTriggers*{.final.} = object + num_hot_key*: cint + key*: PXIMHotKeyTrigger + + PXIMHotKeyState* = ptr TXIMHotKeyState + TXIMHotKeyState* = culong + +const + XIMHotKeyStateON* = 0x00000001 + XIMHotKeyStateOFF* = 0x00000002 + +type + PXIMValuesList* = ptr TXIMValuesList + TXIMValuesList*{.final.} = object + count_values*: cushort + supported_values*: PPChar + + +type + funcdisp* = proc (display: PDisplay): cint{.cdecl.} + funcifevent* = proc (display: PDisplay, event: PXEvent, p: TXPointer): TBool{. + cdecl.} + chararr32* = array[0..31, char] + +const + AllPlanes*: culong = culong(not 0) + +proc XLoadQueryFont*(para1: PDisplay, para2: cstring): PXFontStruct{.libx11.} +proc XQueryFont*(para1: PDisplay, para2: TXID): PXFontStruct{.libx11.} +proc XGetMotionEvents*(para1: PDisplay, para2: TWindow, para3: TTime, + para4: TTime, para5: Pcint): PXTimeCoord{.libx11.} +proc XDeleteModifiermapEntry*(para1: PXModifierKeymap, para2: TKeyCode, + para3: cint): PXModifierKeymap{.libx11.} +proc XGetModifierMapping*(para1: PDisplay): PXModifierKeymap{.libx11.} +proc XInsertModifiermapEntry*(para1: PXModifierKeymap, para2: TKeyCode, + para3: cint): PXModifierKeymap{.libx11.} +proc XNewModifiermap*(para1: cint): PXModifierKeymap{.libx11.} +proc XCreateImage*(para1: PDisplay, para2: PVisual, para3: cuint, para4: cint, + para5: cint, para6: cstring, para7: cuint, para8: cuint, + para9: cint, para10: cint): PXImage{.libx11.} +proc XInitImage*(para1: PXImage): TStatus{.libx11.} +proc XGetImage*(para1: PDisplay, para2: TDrawable, para3: cint, para4: cint, + para5: cuint, para6: cuint, para7: culong, para8: cint): PXImage{. + libx11.} +proc XGetSubImage*(para1: PDisplay, para2: TDrawable, para3: cint, para4: cint, + para5: cuint, para6: cuint, para7: culong, para8: cint, + para9: PXImage, para10: cint, para11: cint): PXImage{.libx11.} +proc XOpenDisplay*(para1: cstring): PDisplay{.libx11.} +proc XrmInitialize*(){.libx11.} +proc XFetchBytes*(para1: PDisplay, para2: Pcint): cstring{.libx11.} +proc XFetchBuffer*(para1: PDisplay, para2: Pcint, para3: cint): cstring{.libx11.} +proc XGetAtomName*(para1: PDisplay, para2: TAtom): cstring{.libx11.} +proc XGetAtomNames*(para1: PDisplay, para2: PAtom, para3: cint, para4: PPchar): TStatus{. + libx11.} +proc XGetDefault*(para1: PDisplay, para2: cstring, para3: cstring): cstring{. + libx11.} +proc XDisplayName*(para1: cstring): cstring{.libx11.} +proc XKeysymToString*(para1: TKeySym): cstring{.libx11.} +proc XSynchronize*(para1: PDisplay, para2: TBool): funcdisp{.libx11.} +proc XSetAfterFunction*(para1: PDisplay, para2: funcdisp): funcdisp{.libx11.} +proc XInternAtom*(para1: PDisplay, para2: cstring, para3: TBool): TAtom{.libx11.} +proc XInternAtoms*(para1: PDisplay, para2: PPchar, para3: cint, para4: TBool, + para5: PAtom): TStatus{.libx11.} +proc XCopyColormapAndFree*(para1: PDisplay, para2: TColormap): TColormap{.libx11.} +proc XCreateColormap*(para1: PDisplay, para2: TWindow, para3: PVisual, + para4: cint): TColormap{.libx11.} +proc XCreatePixmapCursor*(para1: PDisplay, para2: TPixmap, para3: TPixmap, + para4: PXColor, para5: PXColor, para6: cuint, + para7: cuint): TCursor{.libx11.} +proc XCreateGlyphCursor*(para1: PDisplay, para2: TFont, para3: TFont, + para4: cuint, para5: cuint, para6: PXColor, + para7: PXColor): TCursor{.libx11.} +proc XCreateFontCursor*(para1: PDisplay, para2: cuint): TCursor{.libx11.} +proc XLoadFont*(para1: PDisplay, para2: cstring): TFont{.libx11.} +proc XCreateGC*(para1: PDisplay, para2: TDrawable, para3: culong, + para4: PXGCValues): TGC{.libx11.} +proc XGContextFromGC*(para1: TGC): TGContext{.libx11.} +proc XFlushGC*(para1: PDisplay, para2: TGC){.libx11.} +proc XCreatePixmap*(para1: PDisplay, para2: TDrawable, para3: cuint, + para4: cuint, para5: cuint): TPixmap{.libx11.} +proc XCreateBitmapFromData*(para1: PDisplay, para2: TDrawable, para3: cstring, + para4: cuint, para5: cuint): TPixmap{.libx11.} +proc XCreatePixmapFromBitmapData*(para1: PDisplay, para2: TDrawable, + para3: cstring, para4: cuint, para5: cuint, + para6: culong, para7: culong, para8: cuint): TPixmap{. + libx11.} +proc XCreateSimpleWindow*(para1: PDisplay, para2: TWindow, para3: cint, + para4: cint, para5: cuint, para6: cuint, para7: cuint, + para8: culong, para9: culong): TWindow{.libx11.} +proc XGetSelectionOwner*(para1: PDisplay, para2: TAtom): TWindow{.libx11.} +proc XCreateWindow*(para1: PDisplay, para2: TWindow, para3: cint, para4: cint, + para5: cuint, para6: cuint, para7: cuint, para8: cint, + para9: cuint, para10: PVisual, para11: culong, + para12: PXSetWindowAttributes): TWindow{.libx11.} +proc XListInstalledColormaps*(para1: PDisplay, para2: TWindow, para3: Pcint): PColormap{. + libx11.} +proc XListFonts*(para1: PDisplay, para2: cstring, para3: cint, para4: Pcint): PPChar{. + libx11.} +proc XListFontsWithInfo*(para1: PDisplay, para2: cstring, para3: cint, + para4: Pcint, para5: PPXFontStruct): PPChar{.libx11.} +proc XGetFontPath*(para1: PDisplay, para2: Pcint): PPChar{.libx11.} +proc XListExtensions*(para1: PDisplay, para2: Pcint): PPChar{.libx11.} +proc XListProperties*(para1: PDisplay, para2: TWindow, para3: Pcint): PAtom{. + libx11.} +proc XListHosts*(para1: PDisplay, para2: Pcint, para3: PBool): PXHostAddress{. + libx11.} +proc XKeycodeToKeysym*(para1: PDisplay, para2: TKeyCode, para3: cint): TKeySym{. + libx11.} +proc XLookupKeysym*(para1: PXKeyEvent, para2: cint): TKeySym{.libx11.} +proc XGetKeyboardMapping*(para1: PDisplay, para2: TKeyCode, para3: cint, + para4: Pcint): PKeySym{.libx11.} +proc XStringToKeysym*(para1: cstring): TKeySym{.libx11.} +proc XMaxRequestSize*(para1: PDisplay): clong{.libx11.} +proc XExtendedMaxRequestSize*(para1: PDisplay): clong{.libx11.} +proc XResourceManagerString*(para1: PDisplay): cstring{.libx11.} +proc XScreenResourceString*(para1: PScreen): cstring{.libx11.} +proc XDisplayMotionBufferSize*(para1: PDisplay): culong{.libx11.} +proc XVisualIDFromVisual*(para1: PVisual): TVisualID{.libx11.} +proc XInitThreads*(): TStatus{.libx11.} +proc XLockDisplay*(para1: PDisplay){.libx11.} +proc XUnlockDisplay*(para1: PDisplay){.libx11.} +proc XInitExtension*(para1: PDisplay, para2: cstring): PXExtCodes{.libx11.} +proc XAddExtension*(para1: PDisplay): PXExtCodes{.libx11.} +proc XFindOnExtensionList*(para1: PPXExtData, para2: cint): PXExtData{.libx11.} +proc XEHeadOfExtensionList*(para1: TXEDataObject): PPXExtData{.libx11.} +proc XRootWindow*(para1: PDisplay, para2: cint): TWindow{.libx11.} +proc XDefaultRootWindow*(para1: PDisplay): TWindow{.libx11.} +proc XRootWindowOfScreen*(para1: PScreen): TWindow{.libx11.} +proc XDefaultVisual*(para1: PDisplay, para2: cint): PVisual{.libx11.} +proc XDefaultVisualOfScreen*(para1: PScreen): PVisual{.libx11.} +proc XDefaultGC*(para1: PDisplay, para2: cint): TGC{.libx11.} +proc XDefaultGCOfScreen*(para1: PScreen): TGC{.libx11.} +proc XBlackPixel*(para1: PDisplay, para2: cint): culong{.libx11.} +proc XWhitePixel*(para1: PDisplay, para2: cint): culong{.libx11.} +proc XAllPlanes*(): culong{.libx11.} +proc XBlackPixelOfScreen*(para1: PScreen): culong{.libx11.} +proc XWhitePixelOfScreen*(para1: PScreen): culong{.libx11.} +proc XNextRequest*(para1: PDisplay): culong{.libx11.} +proc XLastKnownRequestProcessed*(para1: PDisplay): culong{.libx11.} +proc XServerVendor*(para1: PDisplay): cstring{.libx11.} +proc XDisplayString*(para1: PDisplay): cstring{.libx11.} +proc XDefaultColormap*(para1: PDisplay, para2: cint): TColormap{.libx11.} +proc XDefaultColormapOfScreen*(para1: PScreen): TColormap{.libx11.} +proc XDisplayOfScreen*(para1: PScreen): PDisplay{.libx11.} +proc XScreenOfDisplay*(para1: PDisplay, para2: cint): PScreen{.libx11.} +proc XDefaultScreenOfDisplay*(para1: PDisplay): PScreen{.libx11.} +proc XEventMaskOfScreen*(para1: PScreen): clong{.libx11.} +proc XScreenNumberOfScreen*(para1: PScreen): cint{.libx11.} +type + TXErrorHandler* = proc (para1: PDisplay, para2: PXErrorEvent): cint{.cdecl.} + +proc XSetErrorHandler*(para1: TXErrorHandler): TXErrorHandler{.libx11.} +type + TXIOErrorHandler* = proc (para1: PDisplay): cint{.cdecl.} + +proc XSetIOErrorHandler*(para1: TXIOErrorHandler): TXIOErrorHandler{.libx11.} +proc XListPixmapFormats*(para1: PDisplay, para2: Pcint): PXPixmapFormatValues{. + libx11.} +proc XListDepths*(para1: PDisplay, para2: cint, para3: Pcint): Pcint{.libx11.} +proc XReconfigureWMWindow*(para1: PDisplay, para2: TWindow, para3: cint, + para4: cuint, para5: PXWindowChanges): TStatus{. + libx11.} +proc XGetWMProtocols*(para1: PDisplay, para2: TWindow, para3: PPAtom, + para4: Pcint): TStatus{.libx11.} +proc XSetWMProtocols*(para1: PDisplay, para2: TWindow, para3: PAtom, para4: cint): TStatus{. + libx11.} +proc XIconifyWindow*(para1: PDisplay, para2: TWindow, para3: cint): TStatus{. + libx11.} +proc XWithdrawWindow*(para1: PDisplay, para2: TWindow, para3: cint): TStatus{. + libx11.} +proc XGetCommand*(para1: PDisplay, para2: TWindow, para3: PPPchar, para4: Pcint): TStatus{. + libx11.} +proc XGetWMColormapWindows*(para1: PDisplay, para2: TWindow, para3: PPWindow, + para4: Pcint): TStatus{.libx11.} +proc XSetWMColormapWindows*(para1: PDisplay, para2: TWindow, para3: PWindow, + para4: cint): TStatus{.libx11.} +proc XFreeStringList*(para1: PPchar){.libx11.} +proc XSetTransientForHint*(para1: PDisplay, para2: TWindow, para3: TWindow): cint{. + libx11.} +proc XActivateScreenSaver*(para1: PDisplay): cint{.libx11.} +proc XAddHost*(para1: PDisplay, para2: PXHostAddress): cint{.libx11.} +proc XAddHosts*(para1: PDisplay, para2: PXHostAddress, para3: cint): cint{. + libx11.} +proc XAddToExtensionList*(para1: PPXExtData, para2: PXExtData): cint{.libx11.} +proc XAddToSaveSet*(para1: PDisplay, para2: TWindow): cint{.libx11.} +proc XAllocColor*(para1: PDisplay, para2: TColormap, para3: PXColor): TStatus{. + libx11.} +proc XAllocColorCells*(para1: PDisplay, para2: TColormap, para3: TBool, + para4: Pculong, para5: cuint, para6: Pculong, + para7: cuint): TStatus{.libx11.} +proc XAllocColorPlanes*(para1: PDisplay, para2: TColormap, para3: TBool, + para4: Pculong, para5: cint, para6: cint, para7: cint, + para8: cint, para9: Pculong, para10: Pculong, + para11: Pculong): TStatus{.libx11.} +proc XAllocNamedColor*(para1: PDisplay, para2: TColormap, para3: cstring, + para4: PXColor, para5: PXColor): TStatus{.libx11.} +proc XAllowEvents*(para1: PDisplay, para2: cint, para3: TTime): cint{.libx11.} +proc XAutoRepeatOff*(para1: PDisplay): cint{.libx11.} +proc XAutoRepeatOn*(para1: PDisplay): cint{.libx11.} +proc XBell*(para1: PDisplay, para2: cint): cint{.libx11.} +proc XBitmapBitOrder*(para1: PDisplay): cint{.libx11.} +proc XBitmapPad*(para1: PDisplay): cint{.libx11.} +proc XBitmapUnit*(para1: PDisplay): cint{.libx11.} +proc XCellsOfScreen*(para1: PScreen): cint{.libx11.} +proc XChangeActivePointerGrab*(para1: PDisplay, para2: cuint, para3: TCursor, + para4: TTime): cint{.libx11.} +proc XChangeGC*(para1: PDisplay, para2: TGC, para3: culong, para4: PXGCValues): cint{. + libx11.} +proc XChangeKeyboardControl*(para1: PDisplay, para2: culong, + para3: PXKeyboardControl): cint{.libx11.} +proc XChangeKeyboardMapping*(para1: PDisplay, para2: cint, para3: cint, + para4: PKeySym, para5: cint): cint{.libx11.} +proc XChangePointerControl*(para1: PDisplay, para2: TBool, para3: TBool, + para4: cint, para5: cint, para6: cint): cint{.libx11.} +proc XChangeProperty*(para1: PDisplay, para2: TWindow, para3: TAtom, + para4: TAtom, para5: cint, para6: cint, para7: Pcuchar, + para8: cint): cint{.libx11.} +proc XChangeSaveSet*(para1: PDisplay, para2: TWindow, para3: cint): cint{.libx11.} +proc XChangeWindowAttributes*(para1: PDisplay, para2: TWindow, para3: culong, + para4: PXSetWindowAttributes): cint{.libx11.} +proc XCheckIfEvent*(para1: PDisplay, para2: PXEvent, para3: funcifevent, + para4: TXPointer): TBool{.libx11.} +proc XCheckMaskEvent*(para1: PDisplay, para2: clong, para3: PXEvent): TBool{. + libx11.} +proc XCheckTypedEvent*(para1: PDisplay, para2: cint, para3: PXEvent): TBool{. + libx11.} +proc XCheckTypedWindowEvent*(para1: PDisplay, para2: TWindow, para3: cint, + para4: PXEvent): TBool{.libx11.} +proc XCheckWindowEvent*(para1: PDisplay, para2: TWindow, para3: clong, + para4: PXEvent): TBool{.libx11.} +proc XCirculateSubwindows*(para1: PDisplay, para2: TWindow, para3: cint): cint{. + libx11.} +proc XCirculateSubwindowsDown*(para1: PDisplay, para2: TWindow): cint{.libx11.} +proc XCirculateSubwindowsUp*(para1: PDisplay, para2: TWindow): cint{.libx11.} +proc XClearArea*(para1: PDisplay, para2: TWindow, para3: cint, para4: cint, + para5: cuint, para6: cuint, para7: TBool): cint{.libx11.} +proc XClearWindow*(para1: PDisplay, para2: TWindow): cint{.libx11.} +proc XCloseDisplay*(para1: PDisplay): cint{.libx11.} +proc XConfigureWindow*(para1: PDisplay, para2: TWindow, para3: cuint, + para4: PXWindowChanges): cint{.libx11.} +proc XConnectionNumber*(para1: PDisplay): cint{.libx11.} +proc XConvertSelection*(para1: PDisplay, para2: TAtom, para3: TAtom, + para4: TAtom, para5: TWindow, para6: TTime): cint{. + libx11.} +proc XCopyArea*(para1: PDisplay, para2: TDrawable, para3: TDrawable, para4: TGC, + para5: cint, para6: cint, para7: cuint, para8: cuint, + para9: cint, para10: cint): cint{.libx11.} +proc XCopyGC*(para1: PDisplay, para2: TGC, para3: culong, para4: TGC): cint{. + libx11.} +proc XCopyPlane*(para1: PDisplay, para2: TDrawable, para3: TDrawable, + para4: TGC, para5: cint, para6: cint, para7: cuint, + para8: cuint, para9: cint, para10: cint, para11: culong): cint{. + libx11.} +proc XDefaultDepth*(para1: PDisplay, para2: cint): cint{.libx11.} +proc XDefaultDepthOfScreen*(para1: PScreen): cint{.libx11.} +proc XDefaultScreen*(para1: PDisplay): cint{.libx11.} +proc XDefineCursor*(para1: PDisplay, para2: TWindow, para3: TCursor): cint{. + libx11.} +proc XDeleteProperty*(para1: PDisplay, para2: TWindow, para3: TAtom): cint{. + libx11.} +proc XDestroyWindow*(para1: PDisplay, para2: TWindow): cint{.libx11.} +proc XDestroySubwindows*(para1: PDisplay, para2: TWindow): cint{.libx11.} +proc XDoesBackingStore*(para1: PScreen): cint{.libx11.} +proc XDoesSaveUnders*(para1: PScreen): TBool{.libx11.} +proc XDisableAccessControl*(para1: PDisplay): cint{.libx11.} +proc XDisplayCells*(para1: PDisplay, para2: cint): cint{.libx11.} +proc XDisplayHeight*(para1: PDisplay, para2: cint): cint{.libx11.} +proc XDisplayHeightMM*(para1: PDisplay, para2: cint): cint{.libx11.} +proc XDisplayKeycodes*(para1: PDisplay, para2: Pcint, para3: Pcint): cint{. + libx11.} +proc XDisplayPlanes*(para1: PDisplay, para2: cint): cint{.libx11.} +proc XDisplayWidth*(para1: PDisplay, para2: cint): cint{.libx11.} +proc XDisplayWidthMM*(para1: PDisplay, para2: cint): cint{.libx11.} +proc XDrawArc*(para1: PDisplay, para2: TDrawable, para3: TGC, para4: cint, + para5: cint, para6: cuint, para7: cuint, para8: cint, para9: cint): cint{. + libx11.} +proc XDrawArcs*(para1: PDisplay, para2: TDrawable, para3: TGC, para4: PXArc, + para5: cint): cint{.libx11.} +proc XDrawImageString*(para1: PDisplay, para2: TDrawable, para3: TGC, + para4: cint, para5: cint, para6: cstring, para7: cint): cint{. + libx11.} +proc XDrawImageString16*(para1: PDisplay, para2: TDrawable, para3: TGC, + para4: cint, para5: cint, para6: PXChar2b, para7: cint): cint{. + libx11.} +proc XDrawLine*(para1: PDisplay, para2: TDrawable, para3: TGC, para4: cint, + para5: cint, para6: cint, para7: cint): cint{.libx11.} +proc XDrawLines*(para1: PDisplay, para2: TDrawable, para3: TGC, para4: PXPoint, + para5: cint, para6: cint): cint{.libx11.} +proc XDrawPoint*(para1: PDisplay, para2: TDrawable, para3: TGC, para4: cint, + para5: cint): cint{.libx11.} +proc XDrawPoints*(para1: PDisplay, para2: TDrawable, para3: TGC, para4: PXPoint, + para5: cint, para6: cint): cint{.libx11.} +proc XDrawRectangle*(para1: PDisplay, para2: TDrawable, para3: TGC, para4: cint, + para5: cint, para6: cuint, para7: cuint): cint{.libx11.} +proc XDrawRectangles*(para1: PDisplay, para2: TDrawable, para3: TGC, + para4: PXRectangle, para5: cint): cint{.libx11.} +proc XDrawSegments*(para1: PDisplay, para2: TDrawable, para3: TGC, + para4: PXSegment, para5: cint): cint{.libx11.} +proc XDrawString*(para1: PDisplay, para2: TDrawable, para3: TGC, para4: cint, + para5: cint, para6: cstring, para7: cint): cint{.libx11.} +proc XDrawString16*(para1: PDisplay, para2: TDrawable, para3: TGC, para4: cint, + para5: cint, para6: PXChar2b, para7: cint): cint{.libx11.} +proc XDrawText*(para1: PDisplay, para2: TDrawable, para3: TGC, para4: cint, + para5: cint, para6: PXTextItem, para7: cint): cint{.libx11.} +proc XDrawText16*(para1: PDisplay, para2: TDrawable, para3: TGC, para4: cint, + para5: cint, para6: PXTextItem16, para7: cint): cint{.libx11.} +proc XEnableAccessControl*(para1: PDisplay): cint{.libx11.} +proc XEventsQueued*(para1: PDisplay, para2: cint): cint{.libx11.} +proc XFetchName*(para1: PDisplay, para2: TWindow, para3: PPchar): TStatus{. + libx11.} +proc XFillArc*(para1: PDisplay, para2: TDrawable, para3: TGC, para4: cint, + para5: cint, para6: cuint, para7: cuint, para8: cint, para9: cint): cint{. + libx11.} +proc XFillArcs*(para1: PDisplay, para2: TDrawable, para3: TGC, para4: PXArc, + para5: cint): cint{.libx11.} +proc XFillPolygon*(para1: PDisplay, para2: TDrawable, para3: TGC, + para4: PXPoint, para5: cint, para6: cint, para7: cint): cint{. + libx11.} +proc XFillRectangle*(para1: PDisplay, para2: TDrawable, para3: TGC, para4: cint, + para5: cint, para6: cuint, para7: cuint): cint{.libx11.} +proc XFillRectangles*(para1: PDisplay, para2: TDrawable, para3: TGC, + para4: PXRectangle, para5: cint): cint{.libx11.} +proc XFlush*(para1: PDisplay): cint{.libx11.} +proc XForceScreenSaver*(para1: PDisplay, para2: cint): cint{.libx11.} +proc XFree*(para1: pointer): cint{.libx11.} +proc XFreeColormap*(para1: PDisplay, para2: TColormap): cint{.libx11.} +proc XFreeColors*(para1: PDisplay, para2: TColormap, para3: Pculong, + para4: cint, para5: culong): cint{.libx11.} +proc XFreeCursor*(para1: PDisplay, para2: TCursor): cint{.libx11.} +proc XFreeExtensionList*(para1: PPchar): cint{.libx11.} +proc XFreeFont*(para1: PDisplay, para2: PXFontStruct): cint{.libx11.} +proc XFreeFontInfo*(para1: PPchar, para2: PXFontStruct, para3: cint): cint{. + libx11.} +proc XFreeFontNames*(para1: PPchar): cint{.libx11.} +proc XFreeFontPath*(para1: PPchar): cint{.libx11.} +proc XFreeGC*(para1: PDisplay, para2: TGC): cint{.libx11.} +proc XFreeModifiermap*(para1: PXModifierKeymap): cint{.libx11.} +proc XFreePixmap*(para1: PDisplay, para2: TPixmap): cint{.libx11.} +proc XGeometry*(para1: PDisplay, para2: cint, para3: cstring, para4: cstring, + para5: cuint, para6: cuint, para7: cuint, para8: cint, + para9: cint, para10: Pcint, para11: Pcint, para12: Pcint, + para13: Pcint): cint{.libx11.} +proc XGetErrorDatabaseText*(para1: PDisplay, para2: cstring, para3: cstring, + para4: cstring, para5: cstring, para6: cint): cint{. + libx11.} +proc XGetErrorText*(para1: PDisplay, para2: cint, para3: cstring, para4: cint): cint{. + libx11.} +proc XGetFontProperty*(para1: PXFontStruct, para2: TAtom, para3: Pculong): TBool{. + libx11.} +proc XGetGCValues*(para1: PDisplay, para2: TGC, para3: culong, para4: PXGCValues): TStatus{. + libx11.} +proc XGetGeometry*(para1: PDisplay, para2: TDrawable, para3: PWindow, + para4: Pcint, para5: Pcint, para6: Pcuint, para7: Pcuint, + para8: Pcuint, para9: Pcuint): TStatus{.libx11.} +proc XGetIconName*(para1: PDisplay, para2: TWindow, para3: PPchar): TStatus{. + libx11.} +proc XGetInputFocus*(para1: PDisplay, para2: PWindow, para3: Pcint): cint{. + libx11.} +proc XGetKeyboardControl*(para1: PDisplay, para2: PXKeyboardState): cint{.libx11.} +proc XGetPointerControl*(para1: PDisplay, para2: Pcint, para3: Pcint, + para4: Pcint): cint{.libx11.} +proc XGetPointerMapping*(para1: PDisplay, para2: Pcuchar, para3: cint): cint{. + libx11.} +proc XGetScreenSaver*(para1: PDisplay, para2: Pcint, para3: Pcint, para4: Pcint, + para5: Pcint): cint{.libx11.} +proc XGetTransientForHint*(para1: PDisplay, para2: TWindow, para3: PWindow): TStatus{. + libx11.} +proc XGetWindowProperty*(para1: PDisplay, para2: TWindow, para3: TAtom, + para4: clong, para5: clong, para6: TBool, para7: TAtom, + para8: PAtom, para9: Pcint, para10: Pculong, + para11: Pculong, para12: PPcuchar): cint{.libx11.} +proc XGetWindowAttributes*(para1: PDisplay, para2: TWindow, + para3: PXWindowAttributes): TStatus{.libx11.} +proc XGrabButton*(para1: PDisplay, para2: cuint, para3: cuint, para4: TWindow, + para5: TBool, para6: cuint, para7: cint, para8: cint, + para9: TWindow, para10: TCursor): cint{.libx11.} +proc XGrabKey*(para1: PDisplay, para2: cint, para3: cuint, para4: TWindow, + para5: TBool, para6: cint, para7: cint): cint{.libx11.} +proc XGrabKeyboard*(para1: PDisplay, para2: TWindow, para3: TBool, para4: cint, + para5: cint, para6: TTime): cint{.libx11.} +proc XGrabPointer*(para1: PDisplay, para2: TWindow, para3: TBool, para4: cuint, + para5: cint, para6: cint, para7: TWindow, para8: TCursor, + para9: TTime): cint{.libx11.} +proc XGrabServer*(para1: PDisplay): cint{.libx11.} +proc XHeightMMOfScreen*(para1: PScreen): cint{.libx11.} +proc XHeightOfScreen*(para1: PScreen): cint{.libx11.} +proc XIfEvent*(para1: PDisplay, para2: PXEvent, para3: funcifevent, + para4: TXPointer): cint{.libx11.} +proc XImageByteOrder*(para1: PDisplay): cint{.libx11.} +proc XInstallColormap*(para1: PDisplay, para2: TColormap): cint{.libx11.} +proc XKeysymToKeycode*(para1: PDisplay, para2: TKeySym): TKeyCode{.libx11.} +proc XKillClient*(para1: PDisplay, para2: TXID): cint{.libx11.} +proc XLookupColor*(para1: PDisplay, para2: TColormap, para3: cstring, + para4: PXColor, para5: PXColor): TStatus{.libx11.} +proc XLowerWindow*(para1: PDisplay, para2: TWindow): cint{.libx11.} +proc XMapRaised*(para1: PDisplay, para2: TWindow): cint{.libx11.} +proc XMapSubwindows*(para1: PDisplay, para2: TWindow): cint{.libx11.} +proc XMapWindow*(para1: PDisplay, para2: TWindow): cint{.libx11.} +proc XMaskEvent*(para1: PDisplay, para2: clong, para3: PXEvent): cint{.libx11.} +proc XMaxCmapsOfScreen*(para1: PScreen): cint{.libx11.} +proc XMinCmapsOfScreen*(para1: PScreen): cint{.libx11.} +proc XMoveResizeWindow*(para1: PDisplay, para2: TWindow, para3: cint, + para4: cint, para5: cuint, para6: cuint): cint{.libx11.} +proc XMoveWindow*(para1: PDisplay, para2: TWindow, para3: cint, para4: cint): cint{. + libx11.} +proc XNextEvent*(para1: PDisplay, para2: PXEvent): cint{.libx11.} +proc XNoOp*(para1: PDisplay): cint{.libx11.} +proc XParseColor*(para1: PDisplay, para2: TColormap, para3: cstring, + para4: PXColor): TStatus{.libx11.} +proc XParseGeometry*(para1: cstring, para2: Pcint, para3: Pcint, para4: Pcuint, + para5: Pcuint): cint{.libx11.} +proc XPeekEvent*(para1: PDisplay, para2: PXEvent): cint{.libx11.} +proc XPeekIfEvent*(para1: PDisplay, para2: PXEvent, para3: funcifevent, + para4: TXPointer): cint{.libx11.} +proc XPending*(para1: PDisplay): cint{.libx11.} +proc XPlanesOfScreen*(para1: PScreen): cint{.libx11.} +proc XProtocolRevision*(para1: PDisplay): cint{.libx11.} +proc XProtocolVersion*(para1: PDisplay): cint{.libx11.} +proc XPutBackEvent*(para1: PDisplay, para2: PXEvent): cint{.libx11.} +proc XPutImage*(para1: PDisplay, para2: TDrawable, para3: TGC, para4: PXImage, + para5: cint, para6: cint, para7: cint, para8: cint, + para9: cuint, para10: cuint): cint{.libx11.} +proc XQLength*(para1: PDisplay): cint{.libx11.} +proc XQueryBestCursor*(para1: PDisplay, para2: TDrawable, para3: cuint, + para4: cuint, para5: Pcuint, para6: Pcuint): TStatus{. + libx11.} +proc XQueryBestSize*(para1: PDisplay, para2: cint, para3: TDrawable, + para4: cuint, para5: cuint, para6: Pcuint, para7: Pcuint): TStatus{. + libx11.} +proc XQueryBestStipple*(para1: PDisplay, para2: TDrawable, para3: cuint, + para4: cuint, para5: Pcuint, para6: Pcuint): TStatus{. + libx11.} +proc XQueryBestTile*(para1: PDisplay, para2: TDrawable, para3: cuint, + para4: cuint, para5: Pcuint, para6: Pcuint): TStatus{. + libx11.} +proc XQueryColor*(para1: PDisplay, para2: TColormap, para3: PXColor): cint{. + libx11.} +proc XQueryColors*(para1: PDisplay, para2: TColormap, para3: PXColor, + para4: cint): cint{.libx11.} +proc XQueryExtension*(para1: PDisplay, para2: cstring, para3: Pcint, + para4: Pcint, para5: Pcint): TBool{.libx11.} + #? +proc XQueryKeymap*(para1: PDisplay, para2: chararr32): cint{.libx11.} +proc XQueryPointer*(para1: PDisplay, para2: TWindow, para3: PWindow, + para4: PWindow, para5: Pcint, para6: Pcint, para7: Pcint, + para8: Pcint, para9: Pcuint): TBool{.libx11.} +proc XQueryTextExtents*(para1: PDisplay, para2: TXID, para3: cstring, + para4: cint, para5: Pcint, para6: Pcint, para7: Pcint, + para8: PXCharStruct): cint{.libx11.} +proc XQueryTextExtents16*(para1: PDisplay, para2: TXID, para3: PXChar2b, + para4: cint, para5: Pcint, para6: Pcint, para7: Pcint, + para8: PXCharStruct): cint{.libx11.} +proc XQueryTree*(para1: PDisplay, para2: TWindow, para3: PWindow, + para4: PWindow, para5: PPWindow, para6: Pcuint): TStatus{. + libx11.} +proc XRaiseWindow*(para1: PDisplay, para2: TWindow): cint{.libx11.} +proc XReadBitmapFile*(para1: PDisplay, para2: TDrawable, para3: cstring, + para4: Pcuint, para5: Pcuint, para6: PPixmap, + para7: Pcint, para8: Pcint): cint{.libx11.} +proc XReadBitmapFileData*(para1: cstring, para2: Pcuint, para3: Pcuint, + para4: PPcuchar, para5: Pcint, para6: Pcint): cint{. + libx11.} +proc XRebindKeysym*(para1: PDisplay, para2: TKeySym, para3: PKeySym, + para4: cint, para5: Pcuchar, para6: cint): cint{.libx11.} +proc XRecolorCursor*(para1: PDisplay, para2: TCursor, para3: PXColor, + para4: PXColor): cint{.libx11.} +proc XRefreshKeyboardMapping*(para1: PXMappingEvent): cint{.libx11.} +proc XRemoveFromSaveSet*(para1: PDisplay, para2: TWindow): cint{.libx11.} +proc XRemoveHost*(para1: PDisplay, para2: PXHostAddress): cint{.libx11.} +proc XRemoveHosts*(para1: PDisplay, para2: PXHostAddress, para3: cint): cint{. + libx11.} +proc XReparentWindow*(para1: PDisplay, para2: TWindow, para3: TWindow, + para4: cint, para5: cint): cint{.libx11.} +proc XResetScreenSaver*(para1: PDisplay): cint{.libx11.} +proc XResizeWindow*(para1: PDisplay, para2: TWindow, para3: cuint, para4: cuint): cint{. + libx11.} +proc XRestackWindows*(para1: PDisplay, para2: PWindow, para3: cint): cint{. + libx11.} +proc XRotateBuffers*(para1: PDisplay, para2: cint): cint{.libx11.} +proc XRotateWindowProperties*(para1: PDisplay, para2: TWindow, para3: PAtom, + para4: cint, para5: cint): cint{.libx11.} +proc XScreenCount*(para1: PDisplay): cint{.libx11.} +proc XSelectInput*(para1: PDisplay, para2: TWindow, para3: clong): cint{.libx11.} +proc XSendEvent*(para1: PDisplay, para2: TWindow, para3: TBool, para4: clong, + para5: PXEvent): TStatus{.libx11.} +proc XSetAccessControl*(para1: PDisplay, para2: cint): cint{.libx11.} +proc XSetArcMode*(para1: PDisplay, para2: TGC, para3: cint): cint{.libx11.} +proc XSetBackground*(para1: PDisplay, para2: TGC, para3: culong): cint{.libx11.} +proc XSetClipMask*(para1: PDisplay, para2: TGC, para3: TPixmap): cint{.libx11.} +proc XSetClipOrigin*(para1: PDisplay, para2: TGC, para3: cint, para4: cint): cint{. + libx11.} +proc XSetClipRectangles*(para1: PDisplay, para2: TGC, para3: cint, para4: cint, + para5: PXRectangle, para6: cint, para7: cint): cint{. + libx11.} +proc XSetCloseDownMode*(para1: PDisplay, para2: cint): cint{.libx11.} +proc XSetCommand*(para1: PDisplay, para2: TWindow, para3: PPchar, para4: cint): cint{. + libx11.} +proc XSetDashes*(para1: PDisplay, para2: TGC, para3: cint, para4: cstring, + para5: cint): cint{.libx11.} +proc XSetFillRule*(para1: PDisplay, para2: TGC, para3: cint): cint{.libx11.} +proc XSetFillStyle*(para1: PDisplay, para2: TGC, para3: cint): cint{.libx11.} +proc XSetFont*(para1: PDisplay, para2: TGC, para3: TFont): cint{.libx11.} +proc XSetFontPath*(para1: PDisplay, para2: PPchar, para3: cint): cint{.libx11.} +proc XSetForeground*(para1: PDisplay, para2: TGC, para3: culong): cint{.libx11.} +proc XSetFunction*(para1: PDisplay, para2: TGC, para3: cint): cint{.libx11.} +proc XSetGraphicsExposures*(para1: PDisplay, para2: TGC, para3: TBool): cint{. + libx11.} +proc XSetIconName*(para1: PDisplay, para2: TWindow, para3: cstring): cint{. + libx11.} +proc XSetInputFocus*(para1: PDisplay, para2: TWindow, para3: cint, para4: TTime): cint{. + libx11.} +proc XSetLineAttributes*(para1: PDisplay, para2: TGC, para3: cuint, para4: cint, + para5: cint, para6: cint): cint{.libx11.} +proc XSetModifierMapping*(para1: PDisplay, para2: PXModifierKeymap): cint{. + libx11.} +proc XSetPlaneMask*(para1: PDisplay, para2: TGC, para3: culong): cint{.libx11.} +proc XSetPointerMapping*(para1: PDisplay, para2: Pcuchar, para3: cint): cint{. + libx11.} +proc XSetScreenSaver*(para1: PDisplay, para2: cint, para3: cint, para4: cint, + para5: cint): cint{.libx11.} +proc XSetSelectionOwner*(para1: PDisplay, para2: TAtom, para3: TWindow, + para4: TTime): cint{.libx11.} +proc XSetState*(para1: PDisplay, para2: TGC, para3: culong, para4: culong, + para5: cint, para6: culong): cint{.libx11.} +proc XSetStipple*(para1: PDisplay, para2: TGC, para3: TPixmap): cint{.libx11.} +proc XSetSubwindowMode*(para1: PDisplay, para2: TGC, para3: cint): cint{.libx11.} +proc XSetTSOrigin*(para1: PDisplay, para2: TGC, para3: cint, para4: cint): cint{. + libx11.} +proc XSetTile*(para1: PDisplay, para2: TGC, para3: TPixmap): cint{.libx11.} +proc XSetWindowBackground*(para1: PDisplay, para2: TWindow, para3: culong): cint{. + libx11.} +proc XSetWindowBackgroundPixmap*(para1: PDisplay, para2: TWindow, para3: TPixmap): cint{. + libx11.} +proc XSetWindowBorder*(para1: PDisplay, para2: TWindow, para3: culong): cint{. + libx11.} +proc XSetWindowBorderPixmap*(para1: PDisplay, para2: TWindow, para3: TPixmap): cint{. + libx11.} +proc XSetWindowBorderWidth*(para1: PDisplay, para2: TWindow, para3: cuint): cint{. + libx11.} +proc XSetWindowColormap*(para1: PDisplay, para2: TWindow, para3: TColormap): cint{. + libx11.} +proc XStoreBuffer*(para1: PDisplay, para2: cstring, para3: cint, para4: cint): cint{. + libx11.} +proc XStoreBytes*(para1: PDisplay, para2: cstring, para3: cint): cint{.libx11.} +proc XStoreColor*(para1: PDisplay, para2: TColormap, para3: PXColor): cint{. + libx11.} +proc XStoreColors*(para1: PDisplay, para2: TColormap, para3: PXColor, + para4: cint): cint{.libx11.} +proc XStoreName*(para1: PDisplay, para2: TWindow, para3: cstring): cint{.libx11.} +proc XStoreNamedColor*(para1: PDisplay, para2: TColormap, para3: cstring, + para4: culong, para5: cint): cint{.libx11.} +proc XSync*(para1: PDisplay, para2: TBool): cint{.libx11.} +proc XTextExtents*(para1: PXFontStruct, para2: cstring, para3: cint, + para4: Pcint, para5: Pcint, para6: Pcint, para7: PXCharStruct): cint{. + libx11.} +proc XTextExtents16*(para1: PXFontStruct, para2: PXChar2b, para3: cint, + para4: Pcint, para5: Pcint, para6: Pcint, + para7: PXCharStruct): cint{.libx11.} +proc XTextWidth*(para1: PXFontStruct, para2: cstring, para3: cint): cint{.libx11.} +proc XTextWidth16*(para1: PXFontStruct, para2: PXChar2b, para3: cint): cint{. + libx11.} +proc XTranslateCoordinates*(para1: PDisplay, para2: TWindow, para3: TWindow, + para4: cint, para5: cint, para6: Pcint, + para7: Pcint, para8: PWindow): TBool{.libx11.} +proc XUndefineCursor*(para1: PDisplay, para2: TWindow): cint{.libx11.} +proc XUngrabButton*(para1: PDisplay, para2: cuint, para3: cuint, para4: TWindow): cint{. + libx11.} +proc XUngrabKey*(para1: PDisplay, para2: cint, para3: cuint, para4: TWindow): cint{. + libx11.} +proc XUngrabKeyboard*(para1: PDisplay, para2: TTime): cint{.libx11.} +proc XUngrabPointer*(para1: PDisplay, para2: TTime): cint{.libx11.} +proc XUngrabServer*(para1: PDisplay): cint{.libx11.} +proc XUninstallColormap*(para1: PDisplay, para2: TColormap): cint{.libx11.} +proc XUnloadFont*(para1: PDisplay, para2: TFont): cint{.libx11.} +proc XUnmapSubwindows*(para1: PDisplay, para2: TWindow): cint{.libx11.} +proc XUnmapWindow*(para1: PDisplay, para2: TWindow): cint{.libx11.} +proc XVendorRelease*(para1: PDisplay): cint{.libx11.} +proc XWarpPointer*(para1: PDisplay, para2: TWindow, para3: TWindow, para4: cint, + para5: cint, para6: cuint, para7: cuint, para8: cint, + para9: cint): cint{.libx11.} +proc XWidthMMOfScreen*(para1: PScreen): cint{.libx11.} +proc XWidthOfScreen*(para1: PScreen): cint{.libx11.} +proc XWindowEvent*(para1: PDisplay, para2: TWindow, para3: clong, para4: PXEvent): cint{. + libx11.} +proc XWriteBitmapFile*(para1: PDisplay, para2: cstring, para3: TPixmap, + para4: cuint, para5: cuint, para6: cint, para7: cint): cint{. + libx11.} +proc XSupportsLocale*(): TBool{.libx11.} +proc XSetLocaleModifiers*(para1: cstring): cstring{.libx11.} +proc XOpenOM*(para1: PDisplay, para2: PXrmHashBucketRec, para3: cstring, + para4: cstring): TXOM{.libx11.} +proc XCloseOM*(para1: TXOM): TStatus{.libx11.} +proc XSetOMValues*(para1: TXOM): cstring{.varargs, libx11.} +proc XGetOMValues*(para1: TXOM): cstring{.varargs, libx11.} +proc XDisplayOfOM*(para1: TXOM): PDisplay{.libx11.} +proc XLocaleOfOM*(para1: TXOM): cstring{.libx11.} +proc XCreateOC*(para1: TXOM): TXOC{.varargs, libx11.} +proc XDestroyOC*(para1: TXOC){.libx11.} +proc XOMOfOC*(para1: TXOC): TXOM{.libx11.} +proc XSetOCValues*(para1: TXOC): cstring{.varargs, libx11.} +proc XGetOCValues*(para1: TXOC): cstring{.varargs, libx11.} +proc XCreateFontSet*(para1: PDisplay, para2: cstring, para3: PPPchar, + para4: Pcint, para5: PPchar): TXFontSet{.libx11.} +proc XFreeFontSet*(para1: PDisplay, para2: TXFontSet){.libx11.} +proc XFontsOfFontSet*(para1: TXFontSet, para2: PPPXFontStruct, para3: PPPchar): cint{. + libx11.} +proc XBaseFontNameListOfFontSet*(para1: TXFontSet): cstring{.libx11.} +proc XLocaleOfFontSet*(para1: TXFontSet): cstring{.libx11.} +proc XContextDependentDrawing*(para1: TXFontSet): TBool{.libx11.} +proc XDirectionalDependentDrawing*(para1: TXFontSet): TBool{.libx11.} +proc XContextualDrawing*(para1: TXFontSet): TBool{.libx11.} +proc XExtentsOfFontSet*(para1: TXFontSet): PXFontSetExtents{.libx11.} +proc XmbTextEscapement*(para1: TXFontSet, para2: cstring, para3: cint): cint{. + libx11.} +proc XwcTextEscapement*(para1: TXFontSet, para2: PWideChar, para3: cint): cint{. + libx11.} +proc Xutf8TextEscapement*(para1: TXFontSet, para2: cstring, para3: cint): cint{. + libx11.} +proc XmbTextExtents*(para1: TXFontSet, para2: cstring, para3: cint, + para4: PXRectangle, para5: PXRectangle): cint{.libx11.} +proc XwcTextExtents*(para1: TXFontSet, para2: PWideChar, para3: cint, + para4: PXRectangle, para5: PXRectangle): cint{.libx11.} +proc Xutf8TextExtents*(para1: TXFontSet, para2: cstring, para3: cint, + para4: PXRectangle, para5: PXRectangle): cint{.libx11.} +proc XmbTextPerCharExtents*(para1: TXFontSet, para2: cstring, para3: cint, + para4: PXRectangle, para5: PXRectangle, para6: cint, + para7: Pcint, para8: PXRectangle, para9: PXRectangle): TStatus{. + libx11.} +proc XwcTextPerCharExtents*(para1: TXFontSet, para2: PWideChar, para3: cint, + para4: PXRectangle, para5: PXRectangle, para6: cint, + para7: Pcint, para8: PXRectangle, para9: PXRectangle): TStatus{. + libx11.} +proc Xutf8TextPerCharExtents*(para1: TXFontSet, para2: cstring, para3: cint, + para4: PXRectangle, para5: PXRectangle, + para6: cint, para7: Pcint, para8: PXRectangle, + para9: PXRectangle): TStatus{.libx11.} +proc XmbDrawText*(para1: PDisplay, para2: TDrawable, para3: TGC, para4: cint, + para5: cint, para6: PXmbTextItem, para7: cint){.libx11.} +proc XwcDrawText*(para1: PDisplay, para2: TDrawable, para3: TGC, para4: cint, + para5: cint, para6: PXwcTextItem, para7: cint){.libx11.} +proc Xutf8DrawText*(para1: PDisplay, para2: TDrawable, para3: TGC, para4: cint, + para5: cint, para6: PXmbTextItem, para7: cint){.libx11.} +proc XmbDrawString*(para1: PDisplay, para2: TDrawable, para3: TXFontSet, + para4: TGC, para5: cint, para6: cint, para7: cstring, + para8: cint){.libx11.} +proc XwcDrawString*(para1: PDisplay, para2: TDrawable, para3: TXFontSet, + para4: TGC, para5: cint, para6: cint, para7: PWideChar, + para8: cint){.libx11.} +proc Xutf8DrawString*(para1: PDisplay, para2: TDrawable, para3: TXFontSet, + para4: TGC, para5: cint, para6: cint, para7: cstring, + para8: cint){.libx11.} +proc XmbDrawImageString*(para1: PDisplay, para2: TDrawable, para3: TXFontSet, + para4: TGC, para5: cint, para6: cint, para7: cstring, + para8: cint){.libx11.} +proc XwcDrawImageString*(para1: PDisplay, para2: TDrawable, para3: TXFontSet, + para4: TGC, para5: cint, para6: cint, para7: PWideChar, + para8: cint){.libx11.} +proc Xutf8DrawImageString*(para1: PDisplay, para2: TDrawable, para3: TXFontSet, + para4: TGC, para5: cint, para6: cint, para7: cstring, + para8: cint){.libx11.} +proc XOpenIM*(para1: PDisplay, para2: PXrmHashBucketRec, para3: cstring, + para4: cstring): TXIM{.libx11.} +proc XCloseIM*(para1: TXIM): TStatus{.libx11.} +proc XGetIMValues*(para1: TXIM): cstring{.varargs, libx11.} +proc XSetIMValues*(para1: TXIM): cstring{.varargs, libx11.} +proc XDisplayOfIM*(para1: TXIM): PDisplay{.libx11.} +proc XLocaleOfIM*(para1: TXIM): cstring{.libx11.} +proc XCreateIC*(para1: TXIM): TXIC{.varargs, libx11.} +proc XDestroyIC*(para1: TXIC){.libx11.} +proc XSetICFocus*(para1: TXIC){.libx11.} +proc XUnsetICFocus*(para1: TXIC){.libx11.} +proc XwcResetIC*(para1: TXIC): PWideChar{.libx11.} +proc XmbResetIC*(para1: TXIC): cstring{.libx11.} +proc Xutf8ResetIC*(para1: TXIC): cstring{.libx11.} +proc XSetICValues*(para1: TXIC): cstring{.varargs, libx11.} +proc XGetICValues*(para1: TXIC): cstring{.varargs, libx11.} +proc XIMOfIC*(para1: TXIC): TXIM{.libx11.} +proc XFilterEvent*(para1: PXEvent, para2: TWindow): TBool{.libx11.} +proc XmbLookupString*(para1: TXIC, para2: PXKeyPressedEvent, para3: cstring, + para4: cint, para5: PKeySym, para6: PStatus): cint{.libx11.} +proc XwcLookupString*(para1: TXIC, para2: PXKeyPressedEvent, para3: PWideChar, + para4: cint, para5: PKeySym, para6: PStatus): cint{.libx11.} +proc Xutf8LookupString*(para1: TXIC, para2: PXKeyPressedEvent, para3: cstring, + para4: cint, para5: PKeySym, para6: PStatus): cint{. + libx11.} +proc XVaCreateNestedList*(unused: cint): TXVaNestedList{.varargs, libx11.} +proc XRegisterIMInstantiateCallback*(para1: PDisplay, para2: PXrmHashBucketRec, + para3: cstring, para4: cstring, + para5: TXIDProc, para6: TXPointer): TBool{. + libx11.} +proc XUnregisterIMInstantiateCallback*(para1: PDisplay, + para2: PXrmHashBucketRec, para3: cstring, + para4: cstring, para5: TXIDProc, + para6: TXPointer): TBool{.libx11.} +type + TXConnectionWatchProc* = proc (para1: PDisplay, para2: TXPointer, para3: cint, + para4: TBool, para5: PXPointer){.cdecl.} + +proc XInternalConnectionNumbers*(para1: PDisplay, para2: PPcint, para3: Pcint): TStatus{. + libx11.} +proc XProcessInternalConnection*(para1: PDisplay, para2: cint){.libx11.} +proc XAddConnectionWatch*(para1: PDisplay, para2: TXConnectionWatchProc, + para3: TXPointer): TStatus{.libx11.} +proc XRemoveConnectionWatch*(para1: PDisplay, para2: TXConnectionWatchProc, + para3: TXPointer){.libx11.} +proc XSetAuthorization*(para1: cstring, para2: cint, para3: cstring, para4: cint){. + libx11.} + # + # _Xmbtowc? + # _Xwctomb? + # +#when defined(MACROS): +proc ConnectionNumber*(dpy: PDisplay): cint +proc RootWindow*(dpy: PDisplay, scr: cint): TWindow +proc DefaultScreen*(dpy: PDisplay): cint +proc DefaultRootWindow*(dpy: PDisplay): TWindow +proc DefaultVisual*(dpy: PDisplay, scr: cint): PVisual +proc DefaultGC*(dpy: PDisplay, scr: cint): TGC +proc BlackPixel*(dpy: PDisplay, scr: cint): culong +proc WhitePixel*(dpy: PDisplay, scr: cint): culong +proc QLength*(dpy: PDisplay): cint +proc DisplayWidth*(dpy: PDisplay, scr: cint): cint +proc DisplayHeight*(dpy: PDisplay, scr: cint): cint +proc DisplayWidthMM*(dpy: PDisplay, scr: cint): cint +proc DisplayHeightMM*(dpy: PDisplay, scr: cint): cint +proc DisplayPlanes*(dpy: PDisplay, scr: cint): cint +proc DisplayCells*(dpy: PDisplay, scr: cint): cint +proc ScreenCount*(dpy: PDisplay): cint +proc ServerVendor*(dpy: PDisplay): cstring +proc ProtocolVersion*(dpy: PDisplay): cint +proc ProtocolRevision*(dpy: PDisplay): cint +proc VendorRelease*(dpy: PDisplay): cint +proc DisplayString*(dpy: PDisplay): cstring +proc DefaultDepth*(dpy: PDisplay, scr: cint): cint +proc DefaultColormap*(dpy: PDisplay, scr: cint): TColormap +proc BitmapUnit*(dpy: PDisplay): cint +proc BitmapBitOrder*(dpy: PDisplay): cint +proc BitmapPad*(dpy: PDisplay): cint +proc ImageByteOrder*(dpy: PDisplay): cint +proc NextRequest*(dpy: PDisplay): culong +proc LastKnownRequestProcessed*(dpy: PDisplay): culong +proc ScreenOfDisplay*(dpy: PDisplay, scr: cint): PScreen +proc DefaultScreenOfDisplay*(dpy: PDisplay): PScreen +proc DisplayOfScreen*(s: PScreen): PDisplay +proc RootWindowOfScreen*(s: PScreen): TWindow +proc BlackPixelOfScreen*(s: PScreen): culong +proc WhitePixelOfScreen*(s: PScreen): culong +proc DefaultColormapOfScreen*(s: PScreen): TColormap +proc DefaultDepthOfScreen*(s: PScreen): cint +proc DefaultGCOfScreen*(s: PScreen): TGC +proc DefaultVisualOfScreen*(s: PScreen): PVisual +proc WidthOfScreen*(s: PScreen): cint +proc HeightOfScreen*(s: PScreen): cint +proc WidthMMOfScreen*(s: PScreen): cint +proc HeightMMOfScreen*(s: PScreen): cint +proc PlanesOfScreen*(s: PScreen): cint +proc CellsOfScreen*(s: PScreen): cint +proc MinCmapsOfScreen*(s: PScreen): cint +proc MaxCmapsOfScreen*(s: PScreen): cint +proc DoesSaveUnders*(s: PScreen): TBool +proc DoesBackingStore*(s: PScreen): cint +proc EventMaskOfScreen*(s: PScreen): clong +proc XAllocID*(dpy: PDisplay): TXID +# implementation + +#when defined(MACROS): +template privDisp : expr = cast[PXPrivDisplay](dpy) + +proc ConnectionNumber(dpy: PDisplay): cint = + privDisp.fd + +proc RootWindow(dpy: PDisplay, scr: cint): TWindow = + ScreenOfDisplay(dpy, scr).root + +proc DefaultScreen(dpy: PDisplay): cint = + privDisp.default_screen + +proc DefaultRootWindow(dpy: PDisplay): TWindow = + ScreenOfDisplay(dpy, DefaultScreen(dpy)).root + +proc DefaultVisual(dpy: PDisplay, scr: cint): PVisual = + ScreenOfDisplay(dpy, scr).root_visual + +proc DefaultGC(dpy: PDisplay, scr: cint): TGC = + ScreenOfDisplay(dpy, scr).default_gc + +proc BlackPixel(dpy: PDisplay, scr: cint): culong = + ScreenOfDisplay(dpy, scr).black_pixel + +proc WhitePixel(dpy: PDisplay, scr: cint): culong = + ScreenOfDisplay(dpy, scr).white_pixel + +proc QLength(dpy: PDisplay): cint = + privDisp.qlen + +proc DisplayWidth(dpy: PDisplay, scr: cint): cint = + ScreenOfDisplay(dpy, scr).width + +proc DisplayHeight(dpy: PDisplay, scr: cint): cint = + ScreenOfDisplay(dpy, scr).height + +proc DisplayWidthMM(dpy: PDisplay, scr: cint): cint = + ScreenOfDisplay(dpy, scr).mwidth + +proc DisplayHeightMM(dpy: PDisplay, scr: cint): cint = + ScreenOfDisplay(dpy, scr).mheight + +proc DisplayPlanes(dpy: PDisplay, scr: cint): cint = + ScreenOfDisplay(dpy, scr).root_depth + +proc DisplayCells(dpy: PDisplay, scr: cint): cint = + DefaultVisual(dpy, scr).map_entries + +proc ScreenCount(dpy: PDisplay): cint = + privDisp.nscreens + +proc ServerVendor(dpy: PDisplay): cstring = + privDisp.vendor + +proc ProtocolVersion(dpy: PDisplay): cint = + privDisp.proto_major_version + +proc ProtocolRevision(dpy: PDisplay): cint = + privDisp.proto_minor_version + +proc VendorRelease(dpy: PDisplay): cint = + privDisp.release + +proc DisplayString(dpy: PDisplay): cstring = + privDisp.display_name + +proc DefaultDepth(dpy: PDisplay, scr: cint): cint = + ScreenOfDisplay(dpy, scr).root_depth + +proc DefaultColormap(dpy: PDisplay, scr: cint): TColormap = + ScreenOfDisplay(dpy, scr).cmap + +proc BitmapUnit(dpy: PDisplay): cint = + privDisp.bitmap_unit + +proc BitmapBitOrder(dpy: PDisplay): cint = + privDisp.bitmap_bit_order + +proc BitmapPad(dpy: PDisplay): cint = + privDisp.bitmap_pad + +proc ImageByteOrder(dpy: PDisplay): cint = + privDisp.byte_order + +proc NextRequest(dpy: PDisplay): culong = + privDisp.request + 1.culong + +proc LastKnownRequestProcessed(dpy: PDisplay): culong = + privDisp.last_request_read + +# from fowltek/pointer_arithm, required for ScreenOfDisplay() +proc offset[A] (some: ptr A; b: int): ptr A = + cast[ptr A](cast[int](some) + (b * sizeof(A))) +proc ScreenOfDisplay(dpy: PDisplay, scr: cint): PScreen = + #addr(((privDisp.screens)[scr])) + privDisp.screens.offset(scr.int) + +proc DefaultScreenOfDisplay(dpy: PDisplay): PScreen = + ScreenOfDisplay(dpy, DefaultScreen(dpy)) + +proc DisplayOfScreen(s: PScreen): PDisplay = + s.display + +proc RootWindowOfScreen(s: PScreen): TWindow = + s.root + +proc BlackPixelOfScreen(s: PScreen): culong = + s.black_pixel + +proc WhitePixelOfScreen(s: PScreen): culong = + s.white_pixel + +proc DefaultColormapOfScreen(s: PScreen): TColormap = + s.cmap + +proc DefaultDepthOfScreen(s: PScreen): cint = + s.root_depth + +proc DefaultGCOfScreen(s: PScreen): TGC = + s.default_gc + +proc DefaultVisualOfScreen(s: PScreen): PVisual = + s.root_visual + +proc WidthOfScreen(s: PScreen): cint = + s.width + +proc HeightOfScreen(s: PScreen): cint = + s.height + +proc WidthMMOfScreen(s: PScreen): cint = + s.mwidth + +proc HeightMMOfScreen(s: PScreen): cint = + s.mheight + +proc PlanesOfScreen(s: PScreen): cint = + s.root_depth + +proc CellsOfScreen(s: PScreen): cint = + DefaultVisualOfScreen(s).map_entries + +proc MinCmapsOfScreen(s: PScreen): cint = + s.min_maps + +proc MaxCmapsOfScreen(s: PScreen): cint = + s.max_maps + +proc DoesSaveUnders(s: PScreen): TBool = + s.save_unders + +proc DoesBackingStore(s: PScreen): cint = + s.backing_store + +proc EventMaskOfScreen(s: PScreen): clong = + s.root_input_mask + +proc XAllocID(dpy: PDisplay): TXID = + privDisp.resource_alloc(dpy) diff --git a/tests/deps/x11-1.0/xrandr.nim b/tests/deps/x11-1.0/xrandr.nim new file mode 100644 index 000000000..ee6f1705b --- /dev/null +++ b/tests/deps/x11-1.0/xrandr.nim @@ -0,0 +1,194 @@ +# +# $XFree86: xc/lib/Xrandr/Xrandr.h,v 1.9 2002/09/29 23:39:44 keithp Exp $ +# +# Copyright (C) 2000 Compaq Computer Corporation, Inc. +# Copyright (C) 2002 Hewlett-Packard Company, Inc. +# +# Permission to use, copy, modify, distribute, and sell this software and its +# documentation for any purpose is hereby granted without fee, provided that +# the above copyright notice appear in all copies and that both that +# copyright notice and this permission notice appear in supporting +# documentation, and that the name of Compaq not be used in advertising or +# publicity pertaining to distribution of the software without specific, +# written prior permission. HP makes no representations about the +# suitability of this software for any purpose. It is provided "as is" +# without express or implied warranty. +# +# HP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL COMPAQ +# BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION +# OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN +# CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +# +# Author: Jim Gettys, HP Labs, HP. +# + +import + x, xlib + +const + libXrandr* = "libXrandr.so" + +# * $XFree86: xc/include/extensions/randr.h,v 1.4 2001/11/24 07:24:58 keithp Exp $ +# * +# * Copyright (C) 2000, Compaq Computer Corporation, +# * Copyright (C) 2002, Hewlett Packard, Inc. +# * +# * Permission to use, copy, modify, distribute, and sell this software and its +# * documentation for any purpose is hereby granted without fee, provided that +# * the above copyright notice appear in all copies and that both that +# * copyright notice and this permission notice appear in supporting +# * documentation, and that the name of Compaq or HP not be used in advertising +# * or publicity pertaining to distribution of the software without specific, +# * written prior permission. HP makes no representations about the +# * suitability of this software for any purpose. It is provided "as is" +# * without express or implied warranty. +# * +# * HP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL +# * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL HP +# * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION +# * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN +# * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +# * +# * Author: Jim Gettys, HP Labs, Hewlett-Packard, Inc. +# * + +type + PRotation* = ptr TRotation + TRotation* = cushort + PSizeID* = ptr TSizeID + TSizeID* = cushort + PSubpixelOrder* = ptr TSubpixelOrder + TSubpixelOrder* = cushort + +const + RANDR_NAME* = "RANDR" + RANDR_MAJOR* = 1 + RANDR_MINOR* = 1 + RRNumberErrors* = 0 + RRNumberEvents* = 1 + constX_RRQueryVersion* = 0 # we skip 1 to make old clients fail pretty immediately + X_RROldGetScreenInfo* = 1 + X_RR1_0SetScreenConfig* = 2 # V1.0 apps share the same set screen config request id + constX_RRSetScreenConfig* = 2 + X_RROldScreenChangeSelectInput* = 3 # 3 used to be ScreenChangeSelectInput; deprecated + constX_RRSelectInput* = 4 + constX_RRGetScreenInfo* = 5 # used in XRRSelectInput + RRScreenChangeNotifyMask* = 1 shl 0 + RRScreenChangeNotify* = 0 # used in the rotation field; rotation and reflection in 0.1 proto. + RR_Rotate_0* = 1 + RR_Rotate_90* = 2 + RR_Rotate_180* = 4 + RR_Rotate_270* = 8 # new in 1.0 protocol, to allow reflection of screen + RR_Reflect_X* = 16 + RR_Reflect_Y* = 32 + RRSetConfigSuccess* = 0 + RRSetConfigInvalidConfigTime* = 1 + RRSetConfigInvalidTime* = 2 + RRSetConfigFailed* = 3 + +type + PXRRScreenSize* = ptr TXRRScreenSize + TXRRScreenSize*{.final.} = object # + # Events. + # + width*, height*: cint + mwidth*, mheight*: cint + + TXRRScreenChangeNotifyEvent*{.final.} = object # internal representation is private to the library + typ*: cint # event base + serial*: culong # # of last request processed by server + send_event*: TBool # true if this came from a SendEvent request + display*: PDisplay # Display the event was read from + window*: TWindow # window which selected for this event + root*: TWindow # Root window for changed screen + timestamp*: TTime # when the screen change occurred + config_timestamp*: TTime # when the last configuration change + size_index*: TSizeID + subpixel_order*: TSubpixelOrder + rotation*: TRotation + width*: cint + height*: cint + mwidth*: cint + mheight*: cint + + PXRRScreenConfiguration* = ptr TXRRScreenConfiguration + TXRRScreenConfiguration*{.final.} = object + +proc XRRQueryExtension*(dpy: PDisplay, event_basep, error_basep: Pcint): TBool{. + cdecl, dynlib: libXrandr, importc.} +proc XRRQueryVersion*(dpy: PDisplay, major_versionp: Pcint, + minor_versionp: Pcint): TStatus{.cdecl, dynlib: libXrandr, + importc.} +proc XRRGetScreenInfo*(dpy: PDisplay, draw: TDrawable): PXRRScreenConfiguration{. + cdecl, dynlib: libXrandr, importc.} +proc XRRFreeScreenConfigInfo*(config: PXRRScreenConfiguration){.cdecl, + dynlib: libXrandr, importc.} + # + # Note that screen configuration changes are only permitted if the client can + # prove it has up to date configuration information. We are trying to + # insist that it become possible for screens to change dynamically, so + # we want to ensure the client knows what it is talking about when requesting + # changes. + # +proc XRRSetScreenConfig*(dpy: PDisplay, config: PXRRScreenConfiguration, + draw: TDrawable, size_index: cint, rotation: TRotation, + timestamp: TTime): TStatus{.cdecl, dynlib: libXrandr, + importc.} + # added in v1.1, sorry for the lame name +proc XRRSetScreenConfigAndRate*(dpy: PDisplay, config: PXRRScreenConfiguration, + draw: TDrawable, size_index: cint, + rotation: TRotation, rate: cshort, + timestamp: TTime): TStatus{.cdecl, + dynlib: libXrandr, importc.} +proc XRRConfigRotations*(config: PXRRScreenConfiguration, + current_rotation: PRotation): TRotation{.cdecl, + dynlib: libXrandr, importc.} +proc XRRConfigTimes*(config: PXRRScreenConfiguration, config_timestamp: PTime): TTime{. + cdecl, dynlib: libXrandr, importc.} +proc XRRConfigSizes*(config: PXRRScreenConfiguration, nsizes: Pcint): PXRRScreenSize{. + cdecl, dynlib: libXrandr, importc.} +proc XRRConfigRates*(config: PXRRScreenConfiguration, sizeID: cint, + nrates: Pcint): ptr int16{.cdecl, dynlib: libXrandr, importc.} +proc XRRConfigCurrentConfiguration*(config: PXRRScreenConfiguration, + rotation: PRotation): TSizeID{.cdecl, + dynlib: libXrandr, importc.} +proc XRRConfigCurrentRate*(config: PXRRScreenConfiguration): cshort{.cdecl, + dynlib: libXrandr, importc.} +proc XRRRootToScreen*(dpy: PDisplay, root: TWindow): cint{.cdecl, + dynlib: libXrandr, importc.} + # + # returns the screen configuration for the specified screen; does a lazy + # evalution to delay getting the information, and caches the result. + # These routines should be used in preference to XRRGetScreenInfo + # to avoid unneeded round trips to the X server. These are new + # in protocol version 0.1. + # +proc XRRScreenConfig*(dpy: PDisplay, screen: cint): PXRRScreenConfiguration{. + cdecl, dynlib: libXrandr, importc.} +proc XRRConfig*(screen: PScreen): PXRRScreenConfiguration{.cdecl, + dynlib: libXrandr, importc.} +proc XRRSelectInput*(dpy: PDisplay, window: TWindow, mask: cint){.cdecl, + dynlib: libXrandr, importc.} + # + # the following are always safe to call, even if RandR is not implemented + # on a screen + # +proc XRRRotations*(dpy: PDisplay, screen: cint, current_rotation: PRotation): TRotation{. + cdecl, dynlib: libXrandr, importc.} +proc XRRSizes*(dpy: PDisplay, screen: cint, nsizes: Pcint): PXRRScreenSize{. + cdecl, dynlib: libXrandr, importc.} +proc XRRRates*(dpy: PDisplay, screen: cint, sizeID: cint, nrates: Pcint): ptr int16{. + cdecl, dynlib: libXrandr, importc.} +proc XRRTimes*(dpy: PDisplay, screen: cint, config_timestamp: PTime): TTime{. + cdecl, dynlib: libXrandr, importc.} + # + # intended to take RRScreenChangeNotify, or + # ConfigureNotify (on the root window) + # returns 1 if it is an event type it understands, 0 if not + # +proc XRRUpdateConfiguration*(event: PXEvent): cint{.cdecl, dynlib: libXrandr, + importc.} +# implementation diff --git a/tests/deps/x11-1.0/xrender.nim b/tests/deps/x11-1.0/xrender.nim new file mode 100644 index 000000000..c4b2b364d --- /dev/null +++ b/tests/deps/x11-1.0/xrender.nim @@ -0,0 +1,241 @@ + +import + x, xlib + +when defined(use_pkg_config) or defined(use_pkg_config_static): + {.pragma: libxrender, cdecl, importc.} + when defined(use_pkg_config): + {.passl: gorge("pkg-config xrender --libs").} + else: + {.passl: gorge("pkg-config xrender --static --libs").} +else: + when defined(macosx): + const + libXrender* = "libXrender.dylib" + else: + const + libXrender* = "libXrender.so" + + + {.pragma: libxrender, dynlib: libXrender, cdecl, importc.} +#const +# libXrender* = "libXrender.so" + +# +# Automatically converted by H2Pas 0.99.15 from xrender.h +# The following command line parameters were used: +# -p +# -T +# -S +# -d +# -c +# xrender.h +# + +type + PGlyph* = ptr TGlyph + TGlyph* = int32 + PGlyphSet* = ptr TGlyphSet + TGlyphSet* = int32 + PPicture* = ptr TPicture + TPicture* = int32 + PPictFormat* = ptr TPictFormat + TPictFormat* = int32 + +const + RENDER_NAME* = "RENDER" + RENDER_MAJOR* = 0 + RENDER_MINOR* = 0 + constX_RenderQueryVersion* = 0 + X_RenderQueryPictFormats* = 1 + X_RenderQueryPictIndexValues* = 2 + X_RenderQueryDithers* = 3 + constX_RenderCreatePicture* = 4 + constX_RenderChangePicture* = 5 + X_RenderSetPictureClipRectangles* = 6 + constX_RenderFreePicture* = 7 + constX_RenderComposite* = 8 + X_RenderScale* = 9 + X_RenderTrapezoids* = 10 + X_RenderTriangles* = 11 + X_RenderTriStrip* = 12 + X_RenderTriFan* = 13 + X_RenderColorTrapezoids* = 14 + X_RenderColorTriangles* = 15 + X_RenderTransform* = 16 + constX_RenderCreateGlyphSet* = 17 + constX_RenderReferenceGlyphSet* = 18 + constX_RenderFreeGlyphSet* = 19 + constX_RenderAddGlyphs* = 20 + constX_RenderAddGlyphsFromPicture* = 21 + constX_RenderFreeGlyphs* = 22 + constX_RenderCompositeGlyphs8* = 23 + constX_RenderCompositeGlyphs16* = 24 + constX_RenderCompositeGlyphs32* = 25 + BadPictFormat* = 0 + BadPicture* = 1 + BadPictOp* = 2 + BadGlyphSet* = 3 + BadGlyph* = 4 + RenderNumberErrors* = BadGlyph + 1 + PictTypeIndexed* = 0 + PictTypeDirect* = 1 + PictOpClear* = 0 + PictOpSrc* = 1 + PictOpDst* = 2 + PictOpOver* = 3 + PictOpOverReverse* = 4 + PictOpIn* = 5 + PictOpInReverse* = 6 + PictOpOut* = 7 + PictOpOutReverse* = 8 + PictOpAtop* = 9 + PictOpAtopReverse* = 10 + PictOpXor* = 11 + PictOpAdd* = 12 + PictOpSaturate* = 13 + PictOpMaximum* = 13 + PolyEdgeSharp* = 0 + PolyEdgeSmooth* = 1 + PolyModePrecise* = 0 + PolyModeImprecise* = 1 + CPRepeat* = 1 shl 0 + CPAlphaMap* = 1 shl 1 + CPAlphaXOrigin* = 1 shl 2 + CPAlphaYOrigin* = 1 shl 3 + CPClipXOrigin* = 1 shl 4 + CPClipYOrigin* = 1 shl 5 + CPClipMask* = 1 shl 6 + CPGraphicsExposure* = 1 shl 7 + CPSubwindowMode* = 1 shl 8 + CPPolyEdge* = 1 shl 9 + CPPolyMode* = 1 shl 10 + CPDither* = 1 shl 11 + CPLastBit* = 11 + +type + PXRenderDirectFormat* = ptr TXRenderDirectFormat + TXRenderDirectFormat*{.final.} = object + red*: int16 + redMask*: int16 + green*: int16 + greenMask*: int16 + blue*: int16 + blueMask*: int16 + alpha*: int16 + alphaMask*: int16 + + PXRenderPictFormat* = ptr TXRenderPictFormat + TXRenderPictFormat*{.final.} = object + id*: TPictFormat + thetype*: int32 + depth*: int32 + direct*: TXRenderDirectFormat + colormap*: TColormap + + +const + PictFormatID* = 1 shl 0 + PictFormatType* = 1 shl 1 + PictFormatDepth* = 1 shl 2 + PictFormatRed* = 1 shl 3 + PictFormatRedMask* = 1 shl 4 + PictFormatGreen* = 1 shl 5 + PictFormatGreenMask* = 1 shl 6 + PictFormatBlue* = 1 shl 7 + PictFormatBlueMask* = 1 shl 8 + PictFormatAlpha* = 1 shl 9 + PictFormatAlphaMask* = 1 shl 10 + PictFormatColormap* = 1 shl 11 + +type + PXRenderVisual* = ptr TXRenderVisual + TXRenderVisual*{.final.} = object + visual*: PVisual + format*: PXRenderPictFormat + + PXRenderDepth* = ptr TXRenderDepth + TXRenderDepth*{.final.} = object + depth*: int32 + nvisuals*: int32 + visuals*: PXRenderVisual + + PXRenderScreen* = ptr TXRenderScreen + TXRenderScreen*{.final.} = object + depths*: PXRenderDepth + ndepths*: int32 + fallback*: PXRenderPictFormat + + PXRenderInfo* = ptr TXRenderInfo + TXRenderInfo*{.final.} = object + format*: PXRenderPictFormat + nformat*: int32 + screen*: PXRenderScreen + nscreen*: int32 + depth*: PXRenderDepth + ndepth*: int32 + visual*: PXRenderVisual + nvisual*: int32 + + PXRenderPictureAttributes* = ptr TXRenderPictureAttributes + TXRenderPictureAttributes*{.final.} = object + repeat*: TBool + alpha_map*: TPicture + alpha_x_origin*: int32 + alpha_y_origin*: int32 + clip_x_origin*: int32 + clip_y_origin*: int32 + clip_mask*: TPixmap + graphics_exposures*: TBool + subwindow_mode*: int32 + poly_edge*: int32 + poly_mode*: int32 + dither*: TAtom + + PXGlyphInfo* = ptr TXGlyphInfo + TXGlyphInfo*{.final.} = object + width*: int16 + height*: int16 + x*: int16 + y*: int16 + xOff*: int16 + yOff*: int16 + + +proc XRenderQueryExtension*(dpy: PDisplay, event_basep: ptr int32, + error_basep: ptr int32): TBool{.libxrender.} +proc XRenderQueryVersion*(dpy: PDisplay, major_versionp: ptr int32, + minor_versionp: ptr int32): TStatus{.libxrender.} +proc XRenderQueryFormats*(dpy: PDisplay): TStatus{.libxrender.} +proc XRenderFindVisualFormat*(dpy: PDisplay, visual: PVisual): PXRenderPictFormat{. + libxrender.} +proc XRenderFindFormat*(dpy: PDisplay, mask: int32, + `template`: PXRenderPictFormat, count: int32): PXRenderPictFormat{. + libxrender.} +proc XRenderCreatePicture*(dpy: PDisplay, drawable: TDrawable, + format: PXRenderPictFormat, valuemask: int32, + attributes: PXRenderPictureAttributes): TPicture{. + libxrender.} +proc XRenderChangePicture*(dpy: PDisplay, picture: TPicture, valuemask: int32, + attributes: PXRenderPictureAttributes){.libxrender.} +proc XRenderFreePicture*(dpy: PDisplay, picture: TPicture){.libxrender.} +proc XRenderComposite*(dpy: PDisplay, op: int32, src: TPicture, mask: TPicture, + dst: TPicture, src_x: int32, src_y: int32, mask_x: int32, + mask_y: int32, dst_x: int32, dst_y: int32, width: int32, + height: int32){.libxrender.} +proc XRenderCreateGlyphSet*(dpy: PDisplay, format: PXRenderPictFormat): TGlyphSet{. + libxrender.} +proc XRenderReferenceGlyphSet*(dpy: PDisplay, existing: TGlyphSet): TGlyphSet{. + libxrender.} +proc XRenderFreeGlyphSet*(dpy: PDisplay, glyphset: TGlyphSet){.libxrender.} +proc XRenderAddGlyphs*(dpy: PDisplay, glyphset: TGlyphSet, gids: PGlyph, + glyphs: PXGlyphInfo, nglyphs: int32, images: cstring, + nbyte_images: int32){.libxrender.} +proc XRenderFreeGlyphs*(dpy: PDisplay, glyphset: TGlyphSet, gids: PGlyph, + nglyphs: int32){.libxrender.} +proc XRenderCompositeString8*(dpy: PDisplay, op: int32, src: TPicture, + dst: TPicture, maskFormat: PXRenderPictFormat, + glyphset: TGlyphSet, xSrc: int32, ySrc: int32, + xDst: int32, yDst: int32, str: cstring, + nchar: int32){.libxrender.} +# implementation diff --git a/tests/deps/x11-1.0/xresource.nim b/tests/deps/x11-1.0/xresource.nim new file mode 100644 index 000000000..c96fbbb52 --- /dev/null +++ b/tests/deps/x11-1.0/xresource.nim @@ -0,0 +1,201 @@ + +import + x, xlib + +#const +# libX11* = "libX11.so" + +# +# Automatically converted by H2Pas 0.99.15 from xresource.h +# The following command line parameters were used: +# -p +# -T +# -S +# -d +# -c +# xresource.h +# + +proc Xpermalloc*(para1: int32): cstring{.cdecl, dynlib: libX11, importc.} +type + PXrmQuark* = ptr TXrmQuark + TXrmQuark* = int32 + TXrmQuarkList* = PXrmQuark + PXrmQuarkList* = ptr TXrmQuarkList + +proc NULLQUARK*(): TXrmQuark +type + PXrmString* = ptr TXrmString + TXrmString* = ptr char + +proc NULLSTRING*(): TXrmString +proc XrmStringToQuark*(para1: cstring): TXrmQuark{.cdecl, dynlib: libX11, + importc.} +proc XrmPermStringToQuark*(para1: cstring): TXrmQuark{.cdecl, dynlib: libX11, + importc.} +proc XrmQuarkToString*(para1: TXrmQuark): TXrmString{.cdecl, dynlib: libX11, + importc.} +proc XrmUniqueQuark*(): TXrmQuark{.cdecl, dynlib: libX11, importc.} +#when defined(MACROS): +proc XrmStringsEqual*(a1, a2: cstring): bool +type + PXrmBinding* = ptr TXrmBinding + TXrmBinding* = enum + XrmBindTightly, XrmBindLoosely + TXrmBindingList* = PXrmBinding + PXrmBindingList* = ptr TXrmBindingList + +proc XrmStringToQuarkList*(para1: cstring, para2: TXrmQuarkList){.cdecl, + dynlib: libX11, importc.} +proc XrmStringToBindingQuarkList*(para1: cstring, para2: TXrmBindingList, + para3: TXrmQuarkList){.cdecl, dynlib: libX11, + importc.} +type + PXrmName* = ptr TXrmName + TXrmName* = TXrmQuark + PXrmNameList* = ptr TXrmNameList + TXrmNameList* = TXrmQuarkList + +#when defined(MACROS): +proc XrmNameToString*(name: int32): TXrmString +proc XrmStringToName*(str: cstring): int32 +proc XrmStringToNameList*(str: cstring, name: PXrmQuark) +type + PXrmClass* = ptr TXrmClass + TXrmClass* = TXrmQuark + PXrmClassList* = ptr TXrmClassList + TXrmClassList* = TXrmQuarkList + +#when defined(MACROS): +proc XrmClassToString*(c_class: int32): TXrmString +proc XrmStringToClass*(c_class: cstring): int32 +proc XrmStringToClassList*(str: cstring, c_class: PXrmQuark) +type + PXrmRepresentation* = ptr TXrmRepresentation + TXrmRepresentation* = TXrmQuark + +#when defined(MACROS): +proc XrmStringToRepresentation*(str: cstring): int32 +proc XrmRepresentationToString*(thetype: int32): TXrmString +type + PXrmValue* = ptr TXrmValue + TXrmValue*{.final.} = object + size*: int32 + address*: TXPointer + + TXrmValuePtr* = PXrmValue + PXrmValuePtr* = ptr TXrmValuePtr + PXrmHashBucketRec* = ptr TXrmHashBucketRec + TXrmHashBucketRec*{.final.} = object + TXrmHashBucket* = PXrmHashBucketRec + PXrmHashBucket* = ptr TXrmHashBucket + PXrmHashTable* = ptr TXrmHashTable + TXrmHashTable* = ptr TXrmHashBucket + TXrmDatabase* = PXrmHashBucketRec + PXrmDatabase* = ptr TXrmDatabase + +proc XrmDestroyDatabase*(para1: TXrmDatabase){.cdecl, dynlib: libX11, importc.} +proc XrmQPutResource*(para1: PXrmDatabase, para2: TXrmBindingList, + para3: TXrmQuarkList, para4: TXrmRepresentation, + para5: PXrmValue){.cdecl, dynlib: libX11, importc.} +proc XrmPutResource*(para1: PXrmDatabase, para2: cstring, para3: cstring, + para4: PXrmValue){.cdecl, dynlib: libX11, importc.} +proc XrmQPutStringResource*(para1: PXrmDatabase, para2: TXrmBindingList, + para3: TXrmQuarkList, para4: cstring){.cdecl, + dynlib: libX11, importc.} +proc XrmPutStringResource*(para1: PXrmDatabase, para2: cstring, para3: cstring){. + cdecl, dynlib: libX11, importc.} +proc XrmPutLineResource*(para1: PXrmDatabase, para2: cstring){.cdecl, + dynlib: libX11, importc.} +proc XrmQGetResource*(para1: TXrmDatabase, para2: TXrmNameList, + para3: TXrmClassList, para4: PXrmRepresentation, + para5: PXrmValue): TBool{.cdecl, dynlib: libX11, importc.} +proc XrmGetResource*(para1: TXrmDatabase, para2: cstring, para3: cstring, + para4: PPchar, para5: PXrmValue): TBool{.cdecl, + dynlib: libX11, importc.} + # There is no definition of TXrmSearchList + #function XrmQGetSearchList(para1:TXrmDatabase; para2:TXrmNameList; para3:TXrmClassList; para4:TXrmSearchList; para5:longint):TBool;cdecl;external libX11; + #function XrmQGetSearchResource(para1:TXrmSearchList; para2:TXrmName; para3:TXrmClass; para4:PXrmRepresentation; para5:PXrmValue):TBool;cdecl;external libX11; +proc XrmSetDatabase*(para1: PDisplay, para2: TXrmDatabase){.cdecl, + dynlib: libX11, importc.} +proc XrmGetDatabase*(para1: PDisplay): TXrmDatabase{.cdecl, dynlib: libX11, + importc.} +proc XrmGetFileDatabase*(para1: cstring): TXrmDatabase{.cdecl, dynlib: libX11, + importc.} +proc XrmCombineFileDatabase*(para1: cstring, para2: PXrmDatabase, para3: TBool): TStatus{. + cdecl, dynlib: libX11, importc.} +proc XrmGetStringDatabase*(para1: cstring): TXrmDatabase{.cdecl, dynlib: libX11, + importc.} +proc XrmPutFileDatabase*(para1: TXrmDatabase, para2: cstring){.cdecl, + dynlib: libX11, importc.} +proc XrmMergeDatabases*(para1: TXrmDatabase, para2: PXrmDatabase){.cdecl, + dynlib: libX11, importc.} +proc XrmCombineDatabase*(para1: TXrmDatabase, para2: PXrmDatabase, para3: TBool){. + cdecl, dynlib: libX11, importc.} +const + XrmEnumAllLevels* = 0 + XrmEnumOneLevel* = 1 + +type + funcbool* = proc (): TBool {.cdecl.} + +proc XrmEnumerateDatabase*(para1: TXrmDatabase, para2: TXrmNameList, + para3: TXrmClassList, para4: int32, para5: funcbool, + para6: TXPointer): TBool{.cdecl, dynlib: libX11, + importc.} +proc XrmLocaleOfDatabase*(para1: TXrmDatabase): cstring{.cdecl, dynlib: libX11, + importc.} +type + PXrmOptionKind* = ptr TXrmOptionKind + TXrmOptionKind* = enum + XrmoptionNoArg, XrmoptionIsArg, XrmoptionStickyArg, XrmoptionSepArg, + XrmoptionResArg, XrmoptionSkipArg, XrmoptionSkipLine, XrmoptionSkipNArgs + PXrmOptionDescRec* = ptr TXrmOptionDescRec + TXrmOptionDescRec*{.final.} = object + option*: cstring + specifier*: cstring + argKind*: TXrmOptionKind + value*: TXPointer + + TXrmOptionDescList* = PXrmOptionDescRec + PXrmOptionDescList* = ptr TXrmOptionDescList + +proc XrmParseCommand*(para1: PXrmDatabase, para2: TXrmOptionDescList, + para3: int32, para4: cstring, para5: ptr int32, + para6: PPchar){.cdecl, dynlib: libX11, importc.} +# implementation + +proc NULLQUARK(): TXrmQuark = + result = TXrmQuark(0) + +proc NULLSTRING(): TXrmString = + result = nil + +#when defined(MACROS): +proc XrmStringsEqual(a1, a2: cstring): bool = + #result = (strcomp(a1, a2)) == 0 + $a1 == $a2 + +proc XrmNameToString(name: int32): TXrmString = + result = XrmQuarkToString(name) + +proc XrmStringToName(str: cstring): int32 = + result = XrmStringToQuark(str) + +proc XrmStringToNameList(str: cstring, name: PXrmQuark) = + XrmStringToQuarkList(str, name) + +proc XrmClassToString(c_class: int32): TXrmString = + result = XrmQuarkToString(c_class) + +proc XrmStringToClass(c_class: cstring): int32 = + result = XrmStringToQuark(c_class) + +proc XrmStringToClassList(str: cstring, c_class: PXrmQuark) = + XrmStringToQuarkList(str, c_class) + +proc XrmStringToRepresentation(str: cstring): int32 = + result = XrmStringToQuark(str) + +proc XrmRepresentationToString(thetype: int32): TXrmString = + result = XrmQuarkToString(thetype) diff --git a/tests/deps/x11-1.0/xshm.nim b/tests/deps/x11-1.0/xshm.nim new file mode 100644 index 000000000..e56bd87b1 --- /dev/null +++ b/tests/deps/x11-1.0/xshm.nim @@ -0,0 +1,77 @@ + +import + x, xlib + +#const +# libX11* = "libX11.so" + +# +# Automatically converted by H2Pas 0.99.15 from xshm.h +# The following command line parameters were used: +# -p +# -T +# -S +# -d +# -c +# xshm.h +# + +const + constX_ShmQueryVersion* = 0 + constX_ShmAttach* = 1 + constX_ShmDetach* = 2 + constX_ShmPutImage* = 3 + constX_ShmGetImage* = 4 + constX_ShmCreatePixmap* = 5 + ShmCompletion* = 0 + ShmNumberEvents* = ShmCompletion + 1 + BadShmSeg* = 0 + ShmNumberErrors* = BadShmSeg + 1 + +type + PShmSeg* = ptr TShmSeg + TShmSeg* = culong + PXShmCompletionEvent* = ptr TXShmCompletionEvent + TXShmCompletionEvent*{.final.} = object + theType*: cint + serial*: culong + send_event*: TBool + display*: PDisplay + drawable*: TDrawable + major_code*: cint + minor_code*: cint + shmseg*: TShmSeg + offset*: culong + + PXShmSegmentInfo* = ptr TXShmSegmentInfo + TXShmSegmentInfo*{.final.} = object + shmseg*: TShmSeg + shmid*: cint + shmaddr*: cstring + readOnly*: TBool + + +proc XShmQueryExtension*(para1: PDisplay): TBool{.cdecl, dynlib: libX11, importc.} +proc XShmGetEventBase*(para1: PDisplay): cint{.cdecl, dynlib: libX11, importc.} +proc XShmQueryVersion*(para1: PDisplay, para2: Pcint, para3: Pcint, para4: PBool): TBool{. + cdecl, dynlib: libX11, importc.} +proc XShmPixmapFormat*(para1: PDisplay): cint{.cdecl, dynlib: libX11, importc.} +proc XShmAttach*(para1: PDisplay, para2: PXShmSegmentInfo): TStatus{.cdecl, + dynlib: libX11, importc.} +proc XShmDetach*(para1: PDisplay, para2: PXShmSegmentInfo): TStatus{.cdecl, + dynlib: libX11, importc.} +proc XShmPutImage*(para1: PDisplay, para2: TDrawable, para3: TGC, + para4: PXImage, para5: cint, para6: cint, para7: cint, + para8: cint, para9: cuint, para10: cuint, para11: TBool): TStatus{. + cdecl, dynlib: libX11, importc.} +proc XShmGetImage*(para1: PDisplay, para2: TDrawable, para3: PXImage, + para4: cint, para5: cint, para6: culong): TStatus{.cdecl, + dynlib: libX11, importc.} +proc XShmCreateImage*(para1: PDisplay, para2: PVisual, para3: cuint, + para4: cint, para5: cstring, para6: PXShmSegmentInfo, + para7: cuint, para8: cuint): PXImage{.cdecl, + dynlib: libX11, importc.} +proc XShmCreatePixmap*(para1: PDisplay, para2: TDrawable, para3: cstring, + para4: PXShmSegmentInfo, para5: cuint, para6: cuint, + para7: cuint): TPixmap{.cdecl, dynlib: libX11, importc.} +# implementation diff --git a/tests/deps/x11-1.0/xutil.nim b/tests/deps/x11-1.0/xutil.nim new file mode 100644 index 000000000..b7de0ae3e --- /dev/null +++ b/tests/deps/x11-1.0/xutil.nim @@ -0,0 +1,412 @@ + +import + x, xlib, keysym + +#const +# libX11* = "libX11.so" + +# +# Automatically converted by H2Pas 0.99.15 from xutil.h +# The following command line parameters were used: +# -p +# -T +# -S +# -d +# -c +# xutil.h +# + +const + NoValue* = 0x00000000 + XValue* = 0x00000001 + YValue* = 0x00000002 + WidthValue* = 0x00000004 + HeightValue* = 0x00000008 + AllValues* = 0x0000000F + XNegative* = 0x00000010 + YNegative* = 0x00000020 + +type + TCPoint*{.final.} = object + x*: cint + y*: cint + + PXSizeHints* = ptr TXSizeHints + TXSizeHints*{.final.} = object + flags*: clong + x*, y*: cint + width*, height*: cint + min_width*, min_height*: cint + max_width*, max_height*: cint + width_inc*, height_inc*: cint + min_aspect*, max_aspect*: TCPoint + base_width*, base_height*: cint + win_gravity*: cint + + +const + USPosition* = 1 shl 0 + USSize* = 1 shl 1 + PPosition* = 1 shl 2 + PSize* = 1 shl 3 + PMinSize* = 1 shl 4 + PMaxSize* = 1 shl 5 + PResizeInc* = 1 shl 6 + PAspect* = 1 shl 7 + PBaseSize* = 1 shl 8 + PWinGravity* = 1 shl 9 + PAllHints* = PPosition or PSize or PMinSize or PMaxSize or PResizeInc or + PAspect + +type + PXWMHints* = ptr TXWMHints + TXWMHints*{.final.} = object + flags*: clong + input*: TBool + initial_state*: cint + icon_pixmap*: TPixmap + icon_window*: TWindow + icon_x*, icon_y*: cint + icon_mask*: TPixmap + window_group*: TXID + + +const + InputHint* = 1 shl 0 + StateHint* = 1 shl 1 + IconPixmapHint* = 1 shl 2 + IconWindowHint* = 1 shl 3 + IconPositionHint* = 1 shl 4 + IconMaskHint* = 1 shl 5 + WindowGroupHint* = 1 shl 6 + AllHints* = InputHint or StateHint or IconPixmapHint or IconWindowHint or + IconPositionHint or IconMaskHint or WindowGroupHint + XUrgencyHint* = 1 shl 8 + WithdrawnState* = 0 + NormalState* = 1 + IconicState* = 3 + DontCareState* = 0 + ZoomState* = 2 + InactiveState* = 4 + +type + PXTextProperty* = ptr TXTextProperty + TXTextProperty*{.final.} = object + value*: Pcuchar + encoding*: TAtom + format*: cint + nitems*: culong + + +const + XNoMemory* = - 1 + XLocaleNotSupported* = - 2 + XConverterNotFound* = - 3 + +type + PXICCEncodingStyle* = ptr TXICCEncodingStyle + TXICCEncodingStyle* = enum + XStringStyle, XCompoundTextStyle, XTextStyle, XStdICCTextStyle, + XUTF8StringStyle + PPXIconSize* = ptr PXIconSize + PXIconSize* = ptr TXIconSize + TXIconSize*{.final.} = object + min_width*, min_height*: cint + max_width*, max_height*: cint + width_inc*, height_inc*: cint + + PXClassHint* = ptr TXClassHint + TXClassHint*{.final.} = object + res_name*: cstring + res_class*: cstring + + +type + PXComposeStatus* = ptr TXComposeStatus + TXComposeStatus*{.final.} = object + compose_ptr*: TXPointer + chars_matched*: cint + + +type + PXRegion* = ptr TXRegion + TXRegion*{.final.} = object + TRegion* = PXRegion + PRegion* = ptr TRegion + +const + RectangleOut* = 0 + RectangleIn* = 1 + RectanglePart* = 2 + +type + PXVisualInfo* = ptr TXVisualInfo + TXVisualInfo*{.final.} = object + visual*: PVisual + visualid*: TVisualID + screen*: cint + depth*: cint + class*: cint + red_mask*: culong + green_mask*: culong + blue_mask*: culong + colormap_size*: cint + bits_per_rgb*: cint + + +const + VisualNoMask* = 0x00000000 + VisualIDMask* = 0x00000001 + VisualScreenMask* = 0x00000002 + VisualDepthMask* = 0x00000004 + VisualClassMask* = 0x00000008 + VisualRedMaskMask* = 0x00000010 + VisualGreenMaskMask* = 0x00000020 + VisualBlueMaskMask* = 0x00000040 + VisualColormapSizeMask* = 0x00000080 + VisualBitsPerRGBMask* = 0x00000100 + VisualAllMask* = 0x000001FF + +type + PPXStandardColormap* = ptr PXStandardColormap + PXStandardColormap* = ptr TXStandardColormap + TXStandardColormap*{.final.} = object + colormap*: TColormap + red_max*: culong + red_mult*: culong + green_max*: culong + green_mult*: culong + blue_max*: culong + blue_mult*: culong + base_pixel*: culong + visualid*: TVisualID + killid*: TXID + + +const + BitmapSuccess* = 0 + BitmapOpenFailed* = 1 + BitmapFileInvalid* = 2 + BitmapNoMemory* = 3 + XCSUCCESS* = 0 + XCNOMEM* = 1 + XCNOENT* = 2 + ReleaseByFreeingColormap*: TXID = TXID(1) + +type + PXContext* = ptr TXContext + TXContext* = cint + +proc XAllocClassHint*(): PXClassHint{.cdecl, dynlib: libX11, importc.} +proc XAllocIconSize*(): PXIconSize{.cdecl, dynlib: libX11, importc.} +proc XAllocSizeHints*(): PXSizeHints{.cdecl, dynlib: libX11, importc.} +proc XAllocStandardColormap*(): PXStandardColormap{.cdecl, dynlib: libX11, + importc.} +proc XAllocWMHints*(): PXWMHints{.cdecl, dynlib: libX11, importc.} +proc XClipBox*(para1: TRegion, para2: PXRectangle): cint{.cdecl, dynlib: libX11, + importc.} +proc XCreateRegion*(): TRegion{.cdecl, dynlib: libX11, importc.} +proc XDefaultString*(): cstring{.cdecl, dynlib: libX11, importc.} +proc XDeleteContext*(para1: PDisplay, para2: TXID, para3: TXContext): cint{. + cdecl, dynlib: libX11, importc.} +proc XDestroyRegion*(para1: TRegion): cint{.cdecl, dynlib: libX11, importc.} +proc XEmptyRegion*(para1: TRegion): cint{.cdecl, dynlib: libX11, importc.} +proc XEqualRegion*(para1: TRegion, para2: TRegion): cint{.cdecl, dynlib: libX11, + importc.} +proc XFindContext*(para1: PDisplay, para2: TXID, para3: TXContext, + para4: PXPointer): cint{.cdecl, dynlib: libX11, importc.} +proc XGetClassHint*(para1: PDisplay, para2: TWindow, para3: PXClassHint): TStatus{. + cdecl, dynlib: libX11, importc.} +proc XGetIconSizes*(para1: PDisplay, para2: TWindow, para3: PPXIconSize, + para4: Pcint): TStatus{.cdecl, dynlib: libX11, importc.} +proc XGetNormalHints*(para1: PDisplay, para2: TWindow, para3: PXSizeHints): TStatus{. + cdecl, dynlib: libX11, importc.} +proc XGetRGBColormaps*(para1: PDisplay, para2: TWindow, + para3: PPXStandardColormap, para4: Pcint, para5: TAtom): TStatus{. + cdecl, dynlib: libX11, importc.} +proc XGetSizeHints*(para1: PDisplay, para2: TWindow, para3: PXSizeHints, + para4: TAtom): TStatus{.cdecl, dynlib: libX11, importc.} +proc XGetStandardColormap*(para1: PDisplay, para2: TWindow, + para3: PXStandardColormap, para4: TAtom): TStatus{. + cdecl, dynlib: libX11, importc.} +proc XGetTextProperty*(para1: PDisplay, para2: TWindow, para3: PXTextProperty, + para4: TAtom): TStatus{.cdecl, dynlib: libX11, importc.} +proc XGetVisualInfo*(para1: PDisplay, para2: clong, para3: PXVisualInfo, + para4: Pcint): PXVisualInfo{.cdecl, dynlib: libX11, importc.} +proc XGetWMClientMachine*(para1: PDisplay, para2: TWindow, para3: PXTextProperty): TStatus{. + cdecl, dynlib: libX11, importc.} +proc XGetWMHints*(para1: PDisplay, para2: TWindow): PXWMHints{.cdecl, + dynlib: libX11, importc.} +proc XGetWMIconName*(para1: PDisplay, para2: TWindow, para3: PXTextProperty): TStatus{. + cdecl, dynlib: libX11, importc.} +proc XGetWMName*(para1: PDisplay, para2: TWindow, para3: PXTextProperty): TStatus{. + cdecl, dynlib: libX11, importc.} +proc XGetWMNormalHints*(para1: PDisplay, para2: TWindow, para3: PXSizeHints, + para4: ptr int): TStatus{.cdecl, dynlib: libX11, importc.} +proc XGetWMSizeHints*(para1: PDisplay, para2: TWindow, para3: PXSizeHints, + para4: ptr int, para5: TAtom): TStatus{.cdecl, + dynlib: libX11, importc.} +proc XGetZoomHints*(para1: PDisplay, para2: TWindow, para3: PXSizeHints): TStatus{. + cdecl, dynlib: libX11, importc.} +proc XIntersectRegion*(para1: TRegion, para2: TRegion, para3: TRegion): cint{. + cdecl, dynlib: libX11, importc.} +proc XConvertCase*(para1: TKeySym, para2: PKeySym, para3: PKeySym){.cdecl, + dynlib: libX11, importc.} +proc XLookupString*(para1: PXKeyEvent, para2: cstring, para3: cint, + para4: PKeySym, para5: PXComposeStatus): cint{.cdecl, + dynlib: libX11, importc.} +proc XMatchVisualInfo*(para1: PDisplay, para2: cint, para3: cint, para4: cint, + para5: PXVisualInfo): TStatus{.cdecl, dynlib: libX11, + importc.} +proc XOffsetRegion*(para1: TRegion, para2: cint, para3: cint): cint{.cdecl, + dynlib: libX11, importc.} +proc XPointInRegion*(para1: TRegion, para2: cint, para3: cint): TBool{.cdecl, + dynlib: libX11, importc.} +proc XPolygonRegion*(para1: PXPoint, para2: cint, para3: cint): TRegion{.cdecl, + dynlib: libX11, importc.} +proc XRectInRegion*(para1: TRegion, para2: cint, para3: cint, para4: cuint, + para5: cuint): cint{.cdecl, dynlib: libX11, importc.} +proc XSaveContext*(para1: PDisplay, para2: TXID, para3: TXContext, + para4: cstring): cint{.cdecl, dynlib: libX11, importc.} +proc XSetClassHint*(para1: PDisplay, para2: TWindow, para3: PXClassHint): cint{. + cdecl, dynlib: libX11, importc.} +proc XSetIconSizes*(para1: PDisplay, para2: TWindow, para3: PXIconSize, + para4: cint): cint{.cdecl, dynlib: libX11, importc.} +proc XSetNormalHints*(para1: PDisplay, para2: TWindow, para3: PXSizeHints): cint{. + cdecl, dynlib: libX11, importc.} +proc XSetRGBColormaps*(para1: PDisplay, para2: TWindow, + para3: PXStandardColormap, para4: cint, para5: TAtom){. + cdecl, dynlib: libX11, importc.} +proc XSetSizeHints*(para1: PDisplay, para2: TWindow, para3: PXSizeHints, + para4: TAtom): cint{.cdecl, dynlib: libX11, importc.} +proc XSetStandardProperties*(para1: PDisplay, para2: TWindow, para3: cstring, + para4: cstring, para5: TPixmap, para6: PPchar, + para7: cint, para8: PXSizeHints): cint{.cdecl, + dynlib: libX11, importc.} +proc XSetTextProperty*(para1: PDisplay, para2: TWindow, para3: PXTextProperty, + para4: TAtom){.cdecl, dynlib: libX11, importc.} +proc XSetWMClientMachine*(para1: PDisplay, para2: TWindow, para3: PXTextProperty){. + cdecl, dynlib: libX11, importc.} +proc XSetWMHints*(para1: PDisplay, para2: TWindow, para3: PXWMHints): cint{. + cdecl, dynlib: libX11, importc.} +proc XSetWMIconName*(para1: PDisplay, para2: TWindow, para3: PXTextProperty){. + cdecl, dynlib: libX11, importc.} +proc XSetWMName*(para1: PDisplay, para2: TWindow, para3: PXTextProperty){.cdecl, + dynlib: libX11, importc.} +proc XSetWMNormalHints*(para1: PDisplay, para2: TWindow, para3: PXSizeHints){. + cdecl, dynlib: libX11, importc.} +proc XSetWMProperties*(para1: PDisplay, para2: TWindow, para3: PXTextProperty, + para4: PXTextProperty, para5: PPchar, para6: cint, + para7: PXSizeHints, para8: PXWMHints, para9: PXClassHint){. + cdecl, dynlib: libX11, importc.} +proc XmbSetWMProperties*(para1: PDisplay, para2: TWindow, para3: cstring, + para4: cstring, para5: PPchar, para6: cint, + para7: PXSizeHints, para8: PXWMHints, + para9: PXClassHint){.cdecl, dynlib: libX11, importc.} +proc Xutf8SetWMProperties*(para1: PDisplay, para2: TWindow, para3: cstring, + para4: cstring, para5: PPchar, para6: cint, + para7: PXSizeHints, para8: PXWMHints, + para9: PXClassHint){.cdecl, dynlib: libX11, importc.} +proc XSetWMSizeHints*(para1: PDisplay, para2: TWindow, para3: PXSizeHints, + para4: TAtom){.cdecl, dynlib: libX11, importc.} +proc XSetRegion*(para1: PDisplay, para2: TGC, para3: TRegion): cint{.cdecl, + dynlib: libX11, importc.} +proc XSetStandardColormap*(para1: PDisplay, para2: TWindow, + para3: PXStandardColormap, para4: TAtom){.cdecl, + dynlib: libX11, importc.} +proc XSetZoomHints*(para1: PDisplay, para2: TWindow, para3: PXSizeHints): cint{. + cdecl, dynlib: libX11, importc.} +proc XShrinkRegion*(para1: TRegion, para2: cint, para3: cint): cint{.cdecl, + dynlib: libX11, importc.} +proc XStringListToTextProperty*(para1: PPchar, para2: cint, + para3: PXTextProperty): TStatus{.cdecl, + dynlib: libX11, importc.} +proc XSubtractRegion*(para1: TRegion, para2: TRegion, para3: TRegion): cint{. + cdecl, dynlib: libX11, importc.} +proc XmbTextListToTextProperty*(para1: PDisplay, para2: PPchar, para3: cint, + para4: TXICCEncodingStyle, para5: PXTextProperty): cint{. + cdecl, dynlib: libX11, importc.} +proc XwcTextListToTextProperty*(para1: PDisplay, para2: ptr ptr int16, para3: cint, + para4: TXICCEncodingStyle, para5: PXTextProperty): cint{. + cdecl, dynlib: libX11, importc.} +proc Xutf8TextListToTextProperty*(para1: PDisplay, para2: PPchar, para3: cint, + para4: TXICCEncodingStyle, + para5: PXTextProperty): cint{.cdecl, + dynlib: libX11, importc.} +proc XwcFreeStringList*(para1: ptr ptr int16){.cdecl, dynlib: libX11, importc.} +proc XTextPropertyToStringList*(para1: PXTextProperty, para2: PPPchar, + para3: Pcint): TStatus{.cdecl, dynlib: libX11, + importc.} +proc XmbTextPropertyToTextList*(para1: PDisplay, para2: PXTextProperty, + para3: PPPchar, para4: Pcint): cint{.cdecl, + dynlib: libX11, importc.} +proc XwcTextPropertyToTextList*(para1: PDisplay, para2: PXTextProperty, + para3: ptr ptr ptr int16, para4: Pcint): cint{.cdecl, + dynlib: libX11, importc.} +proc Xutf8TextPropertyToTextList*(para1: PDisplay, para2: PXTextProperty, + para3: PPPchar, para4: Pcint): cint{.cdecl, + dynlib: libX11, importc.} +proc XUnionRectWithRegion*(para1: PXRectangle, para2: TRegion, para3: TRegion): cint{. + cdecl, dynlib: libX11, importc.} +proc XUnionRegion*(para1: TRegion, para2: TRegion, para3: TRegion): cint{.cdecl, + dynlib: libX11, importc.} +proc XWMGeometry*(para1: PDisplay, para2: cint, para3: cstring, para4: cstring, + para5: cuint, para6: PXSizeHints, para7: Pcint, para8: Pcint, + para9: Pcint, para10: Pcint, para11: Pcint): cint{.cdecl, + dynlib: libX11, importc.} +proc XXorRegion*(para1: TRegion, para2: TRegion, para3: TRegion): cint{.cdecl, + dynlib: libX11, importc.} +#when defined(MACROS): +proc XDestroyImage*(ximage: PXImage): cint +proc XGetPixel*(ximage: PXImage, x, y: cint): culong +proc XPutPixel*(ximage: PXImage, x, y: cint, pixel: culong): cint +proc XSubImage*(ximage: PXImage, x, y: cint, width, height: cuint): PXImage +proc XAddPixel*(ximage: PXImage, value: clong): cint +proc IsKeypadKey*(keysym: TKeySym): bool +proc IsPrivateKeypadKey*(keysym: TKeySym): bool +proc IsCursorKey*(keysym: TKeySym): bool +proc IsPFKey*(keysym: TKeySym): bool +proc IsFunctionKey*(keysym: TKeySym): bool +proc IsMiscFunctionKey*(keysym: TKeySym): bool +proc IsModifierKey*(keysym: TKeySym): bool + #function XUniqueContext : TXContext; + #function XStringToContext(_string : Pchar) : TXContext; +# implementation + +#when defined(MACROS): +proc XDestroyImage(ximage: PXImage): cint = + ximage.f.destroy_image(ximage) + +proc XGetPixel(ximage: PXImage, x, y: cint): culong = + ximage.f.get_pixel(ximage, x, y) + +proc XPutPixel(ximage: PXImage, x, y: cint, pixel: culong): cint = + ximage.f.put_pixel(ximage, x, y, pixel) + +proc XSubImage(ximage: PXImage, x, y: cint, width, height: cuint): PXImage = + ximage.f.sub_image(ximage, x, y, width, height) + +proc XAddPixel(ximage: PXImage, value: clong): cint = + ximage.f.add_pixel(ximage, value) + +proc IsKeypadKey(keysym: TKeySym): bool = + (keysym >= XK_KP_Space) and (keysym <= XK_KP_Equal) + +proc IsPrivateKeypadKey(keysym: TKeySym): bool = + (keysym >= 0x11000000.TKeySym) and (keysym <= 0x1100FFFF.TKeySym) + +proc IsCursorKey(keysym: TKeySym): bool = + (keysym >= XK_Home) and (keysym < XK_Select) + +proc IsPFKey(keysym: TKeySym): bool = + (keysym >= XK_KP_F1) and (keysym <= XK_KP_F4) + +proc IsFunctionKey(keysym: TKeySym): bool = + (keysym >= XK_F1) and (keysym <= XK_F35) + +proc IsMiscFunctionKey(keysym: TKeySym): bool = + (keysym >= XK_Select) and (keysym <= XK_Break) + +proc IsModifierKey(keysym: TKeySym): bool = + ((keysym >= XK_Shift_L) and (keysym <= XK_Hyper_R)) or + (keysym == XK_Mode_switch) or (keysym == XK_Num_Lock) diff --git a/tests/deps/x11-1.0/xv.nim b/tests/deps/x11-1.0/xv.nim new file mode 100644 index 000000000..45ab61418 --- /dev/null +++ b/tests/deps/x11-1.0/xv.nim @@ -0,0 +1,84 @@ +#*********************************************************** +#Copyright 1991 by Digital Equipment Corporation, Maynard, Massachusetts, +#and the Massachusetts Institute of Technology, Cambridge, Massachusetts. +# +# All Rights Reserved +# +#Permission to use, copy, modify, and distribute this software and its +#documentation for any purpose and without fee is hereby granted, +#provided that the above copyright notice appear in all copies and that +#both that copyright notice and this permission notice appear in +#supporting documentation, and that the names of Digital or MIT not be +#used in advertising or publicity pertaining to distribution of the +#software without specific, written prior permission. +# +#DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +#ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +#DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +#ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +#WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +#ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +#SOFTWARE. +# +#****************************************************************** +# $XFree86: xc/include/extensions/Xv.h,v 1.3 1999/05/23 06:33:22 dawes Exp $ + +import + x + +const + XvName* = "libXVideo.so" + XvVersion* = 2 + XvRevision* = 2 # Symbols + +type + TXvPortID* = TXID + TXvEncodingID* = TXID + +const + XvNone* = 0 + XvInput* = 0 + XvOutput* = 1 + XvInputMask* = 1 shl XvInput + XvOutputMask* = 1 shl XvOutput + XvVideoMask* = 0x00000004 + XvStillMask* = 0x00000008 + XvImageMask* = 0x00000010 # These two are not client viewable + XvPixmapMask* = 0x00010000 + XvWindowMask* = 0x00020000 + XvGettable* = 0x00000001 + XvSettable* = 0x00000002 + XvRGB* = 0 + XvYUV* = 1 + XvPacked* = 0 + XvPlanar* = 1 + XvTopToBottom* = 0 + XvBottomToTop* = 1 # Events + XvVideoNotify* = 0 + XvPortNotify* = 1 + XvNumEvents* = 2 # Video Notify Reasons + XvStarted* = 0 + XvStopped* = 1 + XvBusy* = 2 + XvPreempted* = 3 + XvHardError* = 4 + XvLastReason* = 4 + XvNumReasons* = XvLastReason + 1 + XvStartedMask* = 1 shl XvStarted + XvStoppedMask* = 1 shl XvStopped + XvBusyMask* = 1 shl XvBusy + XvPreemptedMask* = 1 shl XvPreempted + XvHardErrorMask* = 1 shl XvHardError + XvAnyReasonMask* = (1 shl XvNumReasons) - 1 + XvNoReasonMask* = 0 # Errors + XvBadPort* = 0 + XvBadEncoding* = 1 + XvBadControl* = 2 + XvNumErrors* = 3 # Status + XvBadExtension* = 1 + XvAlreadyGrabbed* = 2 + XvInvalidTime* = 3 + XvBadReply* = 4 + XvBadAlloc* = 5 + +# implementation diff --git a/tests/deps/x11-1.0/xvlib.nim b/tests/deps/x11-1.0/xvlib.nim new file mode 100644 index 000000000..e642cb350 --- /dev/null +++ b/tests/deps/x11-1.0/xvlib.nim @@ -0,0 +1,234 @@ +#*********************************************************** +#Copyright 1991 by Digital Equipment Corporation, Maynard, Massachusetts, +#and the Massachusetts Institute of Technology, Cambridge, Massachusetts. +# +# All Rights Reserved +# +#Permission to use, copy, modify, and distribute this software and its +#documentation for any purpose and without fee is hereby granted, +#provided that the above copyright notice appear in all copies and that +#both that copyright notice and this permission notice appear in +#supporting documentation, and that the names of Digital or MIT not be +#used in advertising or publicity pertaining to distribution of the +#software without specific, written prior permission. +# +#DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +#ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +#DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +#ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +#WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +#ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +#SOFTWARE. +# +#****************************************************************** +# $XFree86: xc/include/extensions/Xvlib.h,v 1.3 1999/12/11 19:28:48 mvojkovi Exp $ +#* +#** File: +#** +#** Xvlib.h --- Xv library public header file +#** +#** Author: +#** +#** David Carver (Digital Workstation Engineering/Project Athena) +#** +#** Revisions: +#** +#** 26.06.91 Carver +#** - changed XvFreeAdaptors to XvFreeAdaptorInfo +#** - changed XvFreeEncodings to XvFreeEncodingInfo +#** +#** 11.06.91 Carver +#** - changed SetPortControl to SetPortAttribute +#** - changed GetPortControl to GetPortAttribute +#** - changed QueryBestSize +#** +#** 05.15.91 Carver +#** - version 2.0 upgrade +#** +#** 01.24.91 Carver +#** - version 1.4 upgrade +#** +#* + +import + x, xlib, xshm, xv + +const + libXv* = "libXv.so" + +type + PXvRational* = ptr TXvRational + TXvRational*{.final.} = object + numerator*: cint + denominator*: cint + + PXvAttribute* = ptr TXvAttribute + TXvAttribute*{.final.} = object + flags*: cint # XvGettable, XvSettable + min_value*: cint + max_value*: cint + name*: cstring + + PPXvEncodingInfo* = ptr PXvEncodingInfo + PXvEncodingInfo* = ptr TXvEncodingInfo + TXvEncodingInfo*{.final.} = object + encoding_id*: TXvEncodingID + name*: cstring + width*: culong + height*: culong + rate*: TXvRational + num_encodings*: culong + + PXvFormat* = ptr TXvFormat + TXvFormat*{.final.} = object + depth*: cchar + visual_id*: culong + + PPXvAdaptorInfo* = ptr PXvAdaptorInfo + PXvAdaptorInfo* = ptr TXvAdaptorInfo + TXvAdaptorInfo*{.final.} = object + base_id*: TXvPortID + num_ports*: culong + thetype*: cchar + name*: cstring + num_formats*: culong + formats*: PXvFormat + num_adaptors*: culong + + PXvVideoNotifyEvent* = ptr TXvVideoNotifyEvent + TXvVideoNotifyEvent*{.final.} = object + theType*: cint + serial*: culong # # of last request processed by server + send_event*: TBool # true if this came from a SendEvent request + display*: PDisplay # Display the event was read from + drawable*: TDrawable # drawable + reason*: culong # what generated this event + port_id*: TXvPortID # what port + time*: TTime # milliseconds + + PXvPortNotifyEvent* = ptr TXvPortNotifyEvent + TXvPortNotifyEvent*{.final.} = object + theType*: cint + serial*: culong # # of last request processed by server + send_event*: TBool # true if this came from a SendEvent request + display*: PDisplay # Display the event was read from + port_id*: TXvPortID # what port + time*: TTime # milliseconds + attribute*: TAtom # atom that identifies attribute + value*: clong # value of attribute + + PXvEvent* = ptr TXvEvent + TXvEvent*{.final.} = object + pad*: array[0..23, clong] #case longint of + # 0 : ( + # theType : cint; + # ); + # 1 : ( + # xvvideo : TXvVideoNotifyEvent; + # ); + # 2 : ( + # xvport : TXvPortNotifyEvent; + # ); + # 3 : ( + # + # ); + + PXvImageFormatValues* = ptr TXvImageFormatValues + TXvImageFormatValues*{.final.} = object + id*: cint # Unique descriptor for the format + theType*: cint # XvRGB, XvYUV + byte_order*: cint # LSBFirst, MSBFirst + guid*: array[0..15, cchar] # Globally Unique IDentifier + bits_per_pixel*: cint + format*: cint # XvPacked, XvPlanar + num_planes*: cint # for RGB formats only + depth*: cint + red_mask*: cuint + green_mask*: cuint + blue_mask*: cuint # for YUV formats only + y_sample_bits*: cuint + u_sample_bits*: cuint + v_sample_bits*: cuint + horz_y_period*: cuint + horz_u_period*: cuint + horz_v_period*: cuint + vert_y_period*: cuint + vert_u_period*: cuint + vert_v_period*: cuint + component_order*: array[0..31, char] # eg. UYVY + scanline_order*: cint # XvTopToBottom, XvBottomToTop + + PXvImage* = ptr TXvImage + TXvImage*{.final.} = object + id*: cint + width*, height*: cint + data_size*: cint # bytes + num_planes*: cint + pitches*: cint # bytes + offsets*: cint # bytes + data*: pointer + obdata*: TXPointer + + +proc XvQueryExtension*(display: PDisplay, p_version, p_revision, p_requestBase, + p_eventBase, p_errorBase: cuint): cint{.cdecl, dynlib: libXv, importc.} +proc XvQueryAdaptors*(display: PDisplay, window: TWindow, p_nAdaptors: cuint, + p_pAdaptors: PPXvAdaptorInfo): cint{.cdecl, dynlib: libXv, + importc.} +proc XvQueryEncodings*(display: PDisplay, port: TXvPortID, p_nEncoding: cuint, + p_pEncoding: PPXvEncodingInfo): cint{.cdecl, + dynlib: libXv, importc.} +proc XvPutVideo*(display: PDisplay, port: TXvPortID, d: TDrawable, gc: TGC, + vx, vy: cint, vw, vh: cuint, dx, dy: cint, dw, dh: cuint): cint{. + cdecl, dynlib: libXv, importc.} +proc XvPutStill*(display: PDisplay, port: TXvPortID, d: TDrawable, gc: TGC, + vx, vy: cint, vw, vh: cuint, dx, dy: cint, dw, dh: cuint): cint{. + cdecl, dynlib: libXv, importc.} +proc XvGetVideo*(display: PDisplay, port: TXvPortID, d: TDrawable, gc: TGC, + vx, vy: cint, vw, vh: cuint, dx, dy: cint, dw, dh: cuint): cint{. + cdecl, dynlib: libXv, importc.} +proc XvGetStill*(display: PDisplay, port: TXvPortID, d: TDrawable, gc: TGC, + vx, vy: cint, vw, vh: cuint, dx, dy: cint, dw, dh: cuint): cint{. + cdecl, dynlib: libXv, importc.} +proc XvStopVideo*(display: PDisplay, port: TXvPortID, drawable: TDrawable): cint{. + cdecl, dynlib: libXv, importc.} +proc XvGrabPort*(display: PDisplay, port: TXvPortID, time: TTime): cint{.cdecl, + dynlib: libXv, importc.} +proc XvUngrabPort*(display: PDisplay, port: TXvPortID, time: TTime): cint{. + cdecl, dynlib: libXv, importc.} +proc XvSelectVideoNotify*(display: PDisplay, drawable: TDrawable, onoff: TBool): cint{. + cdecl, dynlib: libXv, importc.} +proc XvSelectPortNotify*(display: PDisplay, port: TXvPortID, onoff: TBool): cint{. + cdecl, dynlib: libXv, importc.} +proc XvSetPortAttribute*(display: PDisplay, port: TXvPortID, attribute: TAtom, + value: cint): cint{.cdecl, dynlib: libXv, importc.} +proc XvGetPortAttribute*(display: PDisplay, port: TXvPortID, attribute: TAtom, + p_value: cint): cint{.cdecl, dynlib: libXv, importc.} +proc XvQueryBestSize*(display: PDisplay, port: TXvPortID, motion: TBool, + vid_w, vid_h, drw_w, drw_h: cuint, + p_actual_width, p_actual_height: cuint): cint{.cdecl, + dynlib: libXv, importc.} +proc XvQueryPortAttributes*(display: PDisplay, port: TXvPortID, number: cint): PXvAttribute{. + cdecl, dynlib: libXv, importc.} +proc XvFreeAdaptorInfo*(adaptors: PXvAdaptorInfo){.cdecl, dynlib: libXv, importc.} +proc XvFreeEncodingInfo*(encodings: PXvEncodingInfo){.cdecl, dynlib: libXv, + importc.} +proc XvListImageFormats*(display: PDisplay, port_id: TXvPortID, + count_return: cint): PXvImageFormatValues{.cdecl, + dynlib: libXv, importc.} +proc XvCreateImage*(display: PDisplay, port: TXvPortID, id: cint, data: pointer, + width, height: cint): PXvImage{.cdecl, dynlib: libXv, + importc.} +proc XvPutImage*(display: PDisplay, id: TXvPortID, d: TDrawable, gc: TGC, + image: PXvImage, src_x, src_y: cint, src_w, src_h: cuint, + dest_x, dest_y: cint, dest_w, dest_h: cuint): cint{.cdecl, + dynlib: libXv, importc.} +proc XvShmPutImage*(display: PDisplay, id: TXvPortID, d: TDrawable, gc: TGC, + image: PXvImage, src_x, src_y: cint, src_w, src_h: cuint, + dest_x, dest_y: cint, dest_w, dest_h: cuint, + send_event: TBool): cint{.cdecl, dynlib: libXv, importc.} +proc XvShmCreateImage*(display: PDisplay, port: TXvPortID, id: cint, + data: pointer, width, height: cint, + shminfo: PXShmSegmentInfo): PXvImage{.cdecl, + dynlib: libXv, importc.} +# implementation diff --git a/tests/deps/zip-0.2.1/zip.nimble b/tests/deps/zip-0.2.1/zip.nimble new file mode 100644 index 000000000..561f1b9c9 --- /dev/null +++ b/tests/deps/zip-0.2.1/zip.nimble @@ -0,0 +1,18 @@ +# Package + +version = "0.2.1" +author = "Anonymous" +description = "Wrapper for the zip library" +license = "MIT" + +skipDirs = @["tests"] + +# Dependencies + +requires "nim >= 0.10.0" + +task tests, "Run lib tests": + withDir "tests": + exec "nim c -r ziptests" + exec "nim c -r zlibtests" + exec "nim c -r gziptests" diff --git a/tests/deps/zip-0.2.1/zip/gzipfiles.nim b/tests/deps/zip-0.2.1/zip/gzipfiles.nim new file mode 100644 index 000000000..82c412bc3 --- /dev/null +++ b/tests/deps/zip-0.2.1/zip/gzipfiles.nim @@ -0,0 +1,97 @@ +import os +import zlib +import streams +export streams + +## This module implements a gzipfile stream for reading, writing, appending. + +type + GzFileStream* = ref object of Stream + mode: FileMode + f: GzFile + +const SEEK_SET = 0.int32 # Seek from beginning of file. + +proc fsClose(s: Stream) = + if not GzFileStream(s).f.isNil: + discard gzclose(GzFileStream(s).f) + GzFileStream(s).f = nil + +proc fsFlush(s: Stream) = + # compiler flushFile also discard c_fflush + discard gzflush(GzFileStream(s).f, Z_FINISH) + +proc fsAtEnd(s: Stream): bool = + result = gzeof(GzFileStream(s).f) == 1 + +proc fsSetPosition(s: Stream, pos: int) = + if gzseek(GzFileStream(s).f, pos.ZOffT, SEEK_SET) == -1: + if GzFileStream(s).mode in {fmWrite, fmAppend}: + raise newException(IOError, "error in gzip stream while seeking! (file is in write/append mode!") + else: + raise newException(IOError, "error in gzip stream while seeking!") + +proc fsGetPosition(s: Stream): int = + result = gztell(GzFileStream(s).f).int + +proc fsReadData(s: Stream, buffer: pointer, bufLen: int): int = + result = gzread(GzFileStream(s).f, buffer, bufLen).int + if result == -1: + if GzFileStream(s).mode in {fmWrite, fmAppend}: + raise newException(IOError, "cannot read data from write-only gzip stream!") + else: + raise newException(IOError, "cannot read from stream!") + +proc fsPeekData(s: Stream, buffer: pointer, bufLen: int): int = + let gz = GzFileStream(s) + if gz.mode in {fmWrite, fmAppend}: + raise newException(IOError, "cannot peek data from write-only gzip stream!") + let pos = int(gztell(gz.f)) + result = fsReadData(s, buffer, bufLen) + fsSetPosition(s, pos) + +proc fsWriteData(s: Stream, buffer: pointer, bufLen: int) = + if gzwrite(GzFileStream(s).f, buffer, bufLen).int != bufLen: + if GzFileStream(s).mode in {fmWrite, fmAppend}: + raise newException(IOError, "cannot write data to gzip stream!") + else: + raise newException(IOError, "cannot write data to read-only gzip stream!") + + +proc newGzFileStream*(filename: string; mode=fmRead; level=Z_DEFAULT_COMPRESSION): GzFileStream = + ## Opens a Gzipfile as a file stream. `mode` can be + ## ``fmRead``, ``fmWrite`` or ``fmAppend``. + ## + ## Compression level can be set with ``level`` argument. Currently + ## ``Z_DEFAULT_COMPRESSION`` is 6. + ## + ## Note: ``level`` is ignored if ``mode`` is `fmRead` + ## + ## Note: There is only partial support for file seeking + ## - in fmRead mode, seeking randomly inside the gzip + ## file will lead to poor performance. + ## - in fmWrite, fmAppend mode, only forward seeking + ## is supported. + new(result) + case mode + of fmRead: result.f = gzopen(filename, "rb") + of fmWrite: result.f = gzopen(filename, "wb") + of fmAppend: result.f = gzopen(filename, "ab") + else: raise newException(IOError, "unsupported file mode '" & $mode & + "' for GzFileStream!") + if result.f.isNil: + let err = osLastError() + if err != OSErrorCode(0'i32): + raiseOSError(err) + if mode in {fmWrite, fmAppend}: + discard gzsetparams(result.f, level.int32, Z_DEFAULT_STRATEGY.int32) + + result.mode = mode + result.closeImpl = fsClose + result.atEndImpl = fsAtEnd + result.setPositionImpl = fsSetPosition + result.getPositionImpl = fsGetPosition + result.readDataImpl = fsReadData + result.peekDataImpl = fsPeekData + result.writeDataImpl = fsWriteData + result.flushImpl = fsFlush diff --git a/tests/deps/zip-0.2.1/zip/libzip.nim b/tests/deps/zip-0.2.1/zip/libzip.nim new file mode 100644 index 000000000..a2904cd2c --- /dev/null +++ b/tests/deps/zip-0.2.1/zip/libzip.nim @@ -0,0 +1,252 @@ +# +# +# Nim's Runtime Library +# (c) Copyright 2013 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +## Interface to the `libzip `_ library by +## Dieter Baron and Thomas Klausner. This version links +## against ``libzip2.so.2`` unless you define the symbol ``useLibzipSrc``; then +## it is compiled against some old ``libizp_all.c`` file. + +# +# zip.h -- exported declarations. +# Copyright (C) 1999-2008 Dieter Baron and Thomas Klausner +# +# This file is part of libzip, a library to manipulate ZIP archives. +# The authors can be contacted at +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. The names of the authors may not be used to endorse or promote +# products derived from this software without specific prior +# written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS +# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +# GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER +# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN +# IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + +import times + +when defined(unix) and not defined(useLibzipSrc): + when defined(macosx): + {.pragma: mydll, dynlib: "libzip(|2|4).dylib".} + else: + {.pragma: mydll, dynlib: "libzip(|2).so(|.4|.2|.1|.0)".} +else: + when defined(unix): + {.passl: "-lz".} + {.compile: "zip/private/libzip_all.c".} + {.pragma: mydll.} + +type + ZipSourceCmd* = int32 + + ZipSourceCallback* = proc (state: pointer, data: pointer, length: int, + cmd: ZipSourceCmd): int {.cdecl.} + PZipStat* = ptr ZipStat + ZipStat* = object ## the 'zip_stat' struct + name*: cstring ## name of the file + index*: int32 ## index within archive + crc*: int32 ## crc of file data + mtime*: Time ## modification time + size*: int ## size of file (uncompressed) + compSize*: int ## size of file (compressed) + compMethod*: int16 ## compression method used + encryptionMethod*: int16 ## encryption method used + + Zip = object + ZipSource = object + ZipFile = object + + PZip* = ptr Zip ## represents a zip archive + PZipFile* = ptr ZipFile ## represents a file within an archive + PZipSource* = ptr ZipSource ## represents a source for an archive +{.deprecated: [TZipSourceCmd: ZipSourceCmd, TZipStat: ZipStat, TZip: Zip, + TZipSourceCallback: ZipSourceCallback, TZipSource: ZipSource, + TZipFile: ZipFile].} + +# flags for zip_name_locate, zip_fopen, zip_stat, ... +const + ZIP_CREATE* = 1'i32 + ZIP_EXCL* = 2'i32 + ZIP_CHECKCONS* = 4'i32 + ZIP_FL_NOCASE* = 1'i32 ## ignore case on name lookup + ZIP_FL_NODIR* = 2'i32 ## ignore directory component + ZIP_FL_COMPRESSED* = 4'i32 ## read compressed data + ZIP_FL_UNCHANGED* = 8'i32 ## use original data, ignoring changes + ZIP_FL_RECOMPRESS* = 16'i32 ## force recompression of data + +const # archive global flags flags + ZIP_AFL_TORRENT* = 1'i32 ## torrent zipped + +const # libzip error codes + ZIP_ER_OK* = 0'i32 ## N No error + ZIP_ER_MULTIDISK* = 1'i32 ## N Multi-disk zip archives not supported + ZIP_ER_RENAME* = 2'i32 ## S Renaming temporary file failed + ZIP_ER_CLOSE* = 3'i32 ## S Closing zip archive failed + ZIP_ER_SEEK* = 4'i32 ## S Seek error + ZIP_ER_READ* = 5'i32 ## S Read error + ZIP_ER_WRITE* = 6'i32 ## S Write error + ZIP_ER_CRC* = 7'i32 ## N CRC error + ZIP_ER_ZIPCLOSED* = 8'i32 ## N Containing zip archive was closed + ZIP_ER_NOENT* = 9'i32 ## N No such file + ZIP_ER_EXISTS* = 10'i32 ## N File already exists + ZIP_ER_OPEN* = 11'i32 ## S Can't open file + ZIP_ER_TMPOPEN* = 12'i32 ## S Failure to create temporary file + ZIP_ER_ZLIB* = 13'i32 ## Z Zlib error + ZIP_ER_MEMORY* = 14'i32 ## N Malloc failure + ZIP_ER_CHANGED* = 15'i32 ## N Entry has been changed + ZIP_ER_COMPNOTSUPP* = 16'i32 ## N Compression method not supported + ZIP_ER_EOF* = 17'i32 ## N Premature EOF + ZIP_ER_INVAL* = 18'i32 ## N Invalid argument + ZIP_ER_NOZIP* = 19'i32 ## N Not a zip archive + ZIP_ER_INTERNAL* = 20'i32 ## N Internal error + ZIP_ER_INCONS* = 21'i32 ## N Zip archive inconsistent + ZIP_ER_REMOVE* = 22'i32 ## S Can't remove file + ZIP_ER_DELETED* = 23'i32 ## N Entry has been deleted + +const # type of system error value + ZIP_ET_NONE* = 0'i32 ## sys_err unused + ZIP_ET_SYS* = 1'i32 ## sys_err is errno + ZIP_ET_ZLIB* = 2'i32 ## sys_err is zlib error code + +const # compression methods + ZIP_CM_DEFAULT* = -1'i32 ## better of deflate or store + ZIP_CM_STORE* = 0'i32 ## stored (uncompressed) + ZIP_CM_SHRINK* = 1'i32 ## shrunk + ZIP_CM_REDUCE_1* = 2'i32 ## reduced with factor 1 + ZIP_CM_REDUCE_2* = 3'i32 ## reduced with factor 2 + ZIP_CM_REDUCE_3* = 4'i32 ## reduced with factor 3 + ZIP_CM_REDUCE_4* = 5'i32 ## reduced with factor 4 + ZIP_CM_IMPLODE* = 6'i32 ## imploded + ## 7 - Reserved for Tokenizing compression algorithm + ZIP_CM_DEFLATE* = 8'i32 ## deflated + ZIP_CM_DEFLATE64* = 9'i32 ## deflate64 + ZIP_CM_PKWARE_IMPLODE* = 10'i32 ## PKWARE imploding + ## 11 - Reserved by PKWARE + ZIP_CM_BZIP2* = 12'i32 ## compressed using BZIP2 algorithm + ## 13 - Reserved by PKWARE + ZIP_CM_LZMA* = 14'i32 ## LZMA (EFS) + ## 15-17 - Reserved by PKWARE + ZIP_CM_TERSE* = 18'i32 ## compressed using IBM TERSE (new) + ZIP_CM_LZ77* = 19'i32 ## IBM LZ77 z Architecture (PFS) + ZIP_CM_WAVPACK* = 97'i32 ## WavPack compressed data + ZIP_CM_PPMD* = 98'i32 ## PPMd version I, Rev 1 + +const # encryption methods + ZIP_EM_NONE* = 0'i32 ## not encrypted + ZIP_EM_TRAD_PKWARE* = 1'i32 ## traditional PKWARE encryption + +const + ZIP_EM_UNKNOWN* = 0x0000FFFF'i32 ## unknown algorithm + +const + ZIP_SOURCE_OPEN* = 0'i32 ## prepare for reading + ZIP_SOURCE_READ* = 1'i32 ## read data + ZIP_SOURCE_CLOSE* = 2'i32 ## reading is done + ZIP_SOURCE_STAT* = 3'i32 ## get meta information + ZIP_SOURCE_ERROR* = 4'i32 ## get error information + constZIP_SOURCE_FREE* = 5'i32 ## cleanup and free resources + ZIP_SOURCE_SUPPORTS* = 14'i32 ## check supported commands + +proc zip_add*(para1: PZip, para2: cstring, para3: PZipSource): int32 {.cdecl, + importc: "zip_add", mydll.} +proc zip_add_dir*(para1: PZip, para2: cstring): int32 {.cdecl, + importc: "zip_add_dir", mydll.} +proc zip_close*(para1: PZip) {.cdecl, importc: "zip_close", mydll.} +proc zip_delete*(para1: PZip, para2: int32): int32 {.cdecl, mydll, + importc: "zip_delete".} +proc zip_error_clear*(para1: PZip) {.cdecl, importc: "zip_error_clear", mydll.} +proc zip_error_get*(para1: PZip, para2: ptr int32, para3: ptr int32) {.cdecl, + importc: "zip_error_get", mydll.} +proc zip_error_get_sys_type*(para1: int32): int32 {.cdecl, mydll, + importc: "zip_error_get_sys_type".} +proc zip_error_to_str*(para1: cstring, para2: int, para3: int32, + para4: int32): int32 {.cdecl, mydll, + importc: "zip_error_to_str".} +proc zip_fclose*(para1: PZipFile) {.cdecl, mydll, + importc: "zip_fclose".} +proc zip_file_error_clear*(para1: PZipFile) {.cdecl, mydll, + importc: "zip_file_error_clear".} +proc zip_file_error_get*(para1: PZipFile, para2: ptr int32, para3: ptr int32) {. + cdecl, mydll, importc: "zip_file_error_get".} +proc zip_file_strerror*(para1: PZipFile): cstring {.cdecl, mydll, + importc: "zip_file_strerror".} +proc zip_fopen*(para1: PZip, para2: cstring, para3: int32): PZipFile {.cdecl, + mydll, importc: "zip_fopen".} +proc zip_fopen_index*(para1: PZip, para2: int32, para3: int32): PZipFile {. + cdecl, mydll, importc: "zip_fopen_index".} +proc zip_fread*(para1: PZipFile, para2: pointer, para3: int): int {. + cdecl, mydll, importc: "zip_fread".} +proc zip_get_archive_comment*(para1: PZip, para2: ptr int32, para3: int32): cstring {. + cdecl, mydll, importc: "zip_get_archive_comment".} +proc zip_get_archive_flag*(para1: PZip, para2: int32, para3: int32): int32 {. + cdecl, mydll, importc: "zip_get_archive_flag".} +proc zip_get_file_comment*(para1: PZip, para2: int32, para3: ptr int32, + para4: int32): cstring {.cdecl, mydll, + importc: "zip_get_file_comment".} +proc zip_get_name*(para1: PZip, para2: int32, para3: int32): cstring {.cdecl, + mydll, importc: "zip_get_name".} +proc zip_get_num_files*(para1: PZip): int32 {.cdecl, + mydll, importc: "zip_get_num_files".} +proc zip_name_locate*(para1: PZip, para2: cstring, para3: int32): int32 {.cdecl, + mydll, importc: "zip_name_locate".} +proc zip_open*(para1: cstring, para2: int32, para3: ptr int32): PZip {.cdecl, + mydll, importc: "zip_open".} +proc zip_rename*(para1: PZip, para2: int32, para3: cstring): int32 {.cdecl, + mydll, importc: "zip_rename".} +proc zip_replace*(para1: PZip, para2: int32, para3: PZipSource): int32 {.cdecl, + mydll, importc: "zip_replace".} +proc zip_set_archive_comment*(para1: PZip, para2: cstring, para3: int32): int32 {. + cdecl, mydll, importc: "zip_set_archive_comment".} +proc zip_set_archive_flag*(para1: PZip, para2: int32, para3: int32): int32 {. + cdecl, mydll, importc: "zip_set_archive_flag".} +proc zip_set_file_comment*(para1: PZip, para2: int32, para3: cstring, + para4: int32): int32 {.cdecl, mydll, + importc: "zip_set_file_comment".} +proc zip_source_buffer*(para1: PZip, para2: pointer, para3: int, para4: int32): PZipSource {. + cdecl, mydll, importc: "zip_source_buffer".} +proc zip_source_file*(para1: PZip, para2: cstring, para3: int, para4: int): PZipSource {. + cdecl, mydll, importc: "zip_source_file".} +proc zip_source_filep*(para1: PZip, para2: File, para3: int, para4: int): PZipSource {. + cdecl, mydll, importc: "zip_source_filep".} +proc zip_source_free*(para1: PZipSource) {.cdecl, mydll, + importc: "zip_source_free".} +proc zip_source_function*(para1: PZip, para2: ZipSourceCallback, + para3: pointer): PZipSource {.cdecl, mydll, + importc: "zip_source_function".} +proc zip_source_zip*(para1: PZip, para2: PZip, para3: int32, para4: int32, + para5: int, para6: int): PZipSource {.cdecl, mydll, + importc: "zip_source_zip".} +proc zip_stat*(para1: PZip, para2: cstring, para3: int32, para4: PZipStat): int32 {. + cdecl, mydll, importc: "zip_stat".} +proc zip_stat_index*(para1: PZip, para2: int32, para3: int32, para4: PZipStat): int32 {. + cdecl, mydll, importc: "zip_stat_index".} +proc zip_stat_init*(para1: PZipStat) {.cdecl, mydll, importc: "zip_stat_init".} +proc zip_strerror*(para1: PZip): cstring {.cdecl, mydll, importc: "zip_strerror".} +proc zip_unchange*(para1: PZip, para2: int32): int32 {.cdecl, mydll, + importc: "zip_unchange".} +proc zip_unchange_all*(para1: PZip): int32 {.cdecl, mydll, + importc: "zip_unchange_all".} +proc zip_unchange_archive*(para1: PZip): int32 {.cdecl, mydll, + importc: "zip_unchange_archive".} diff --git a/tests/deps/zip-0.2.1/zip/private/libzip_all.c b/tests/deps/zip-0.2.1/zip/private/libzip_all.c new file mode 100644 index 000000000..e0627a7eb --- /dev/null +++ b/tests/deps/zip-0.2.1/zip/private/libzip_all.c @@ -0,0 +1,4193 @@ +/* + zipint.h -- internal declarations. + Copyright (C) 1999-2008 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include + +/* +#ifdef _MSC_VER +#define ZIP_EXTERN __declspec(dllimport) +#endif +*/ + +/* + zip.h -- exported declarations. + Copyright (C) 1999-2008 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#ifndef ZIP_EXTERN +#define ZIP_EXTERN +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include + +/* flags for zip_open */ + +#define ZIP_CREATE 1 +#define ZIP_EXCL 2 +#define ZIP_CHECKCONS 4 + + +/* flags for zip_name_locate, zip_fopen, zip_stat, ... */ + +#define ZIP_FL_NOCASE 1 /* ignore case on name lookup */ +#define ZIP_FL_NODIR 2 /* ignore directory component */ +#define ZIP_FL_COMPRESSED 4 /* read compressed data */ +#define ZIP_FL_UNCHANGED 8 /* use original data, ignoring changes */ +#define ZIP_FL_RECOMPRESS 16 /* force recompression of data */ + +/* archive global flags flags */ + +#define ZIP_AFL_TORRENT 1 /* torrent zipped */ + +/* libzip error codes */ + +#define ZIP_ER_OK 0 /* N No error */ +#define ZIP_ER_MULTIDISK 1 /* N Multi-disk zip archives not supported */ +#define ZIP_ER_RENAME 2 /* S Renaming temporary file failed */ +#define ZIP_ER_CLOSE 3 /* S Closing zip archive failed */ +#define ZIP_ER_SEEK 4 /* S Seek error */ +#define ZIP_ER_READ 5 /* S Read error */ +#define ZIP_ER_WRITE 6 /* S Write error */ +#define ZIP_ER_CRC 7 /* N CRC error */ +#define ZIP_ER_ZIPCLOSED 8 /* N Containing zip archive was closed */ +#define ZIP_ER_NOENT 9 /* N No such file */ +#define ZIP_ER_EXISTS 10 /* N File already exists */ +#define ZIP_ER_OPEN 11 /* S Can't open file */ +#define ZIP_ER_TMPOPEN 12 /* S Failure to create temporary file */ +#define ZIP_ER_ZLIB 13 /* Z Zlib error */ +#define ZIP_ER_MEMORY 14 /* N Malloc failure */ +#define ZIP_ER_CHANGED 15 /* N Entry has been changed */ +#define ZIP_ER_COMPNOTSUPP 16 /* N Compression method not supported */ +#define ZIP_ER_EOF 17 /* N Premature EOF */ +#define ZIP_ER_INVAL 18 /* N Invalid argument */ +#define ZIP_ER_NOZIP 19 /* N Not a zip archive */ +#define ZIP_ER_INTERNAL 20 /* N Internal error */ +#define ZIP_ER_INCONS 21 /* N Zip archive inconsistent */ +#define ZIP_ER_REMOVE 22 /* S Can't remove file */ +#define ZIP_ER_DELETED 23 /* N Entry has been deleted */ + + +/* type of system error value */ + +#define ZIP_ET_NONE 0 /* sys_err unused */ +#define ZIP_ET_SYS 1 /* sys_err is errno */ +#define ZIP_ET_ZLIB 2 /* sys_err is zlib error code */ + +/* compression methods */ + +#define ZIP_CM_DEFAULT -1 /* better of deflate or store */ +#define ZIP_CM_STORE 0 /* stored (uncompressed) */ +#define ZIP_CM_SHRINK 1 /* shrunk */ +#define ZIP_CM_REDUCE_1 2 /* reduced with factor 1 */ +#define ZIP_CM_REDUCE_2 3 /* reduced with factor 2 */ +#define ZIP_CM_REDUCE_3 4 /* reduced with factor 3 */ +#define ZIP_CM_REDUCE_4 5 /* reduced with factor 4 */ +#define ZIP_CM_IMPLODE 6 /* imploded */ +/* 7 - Reserved for Tokenizing compression algorithm */ +#define ZIP_CM_DEFLATE 8 /* deflated */ +#define ZIP_CM_DEFLATE64 9 /* deflate64 */ +#define ZIP_CM_PKWARE_IMPLODE 10 /* PKWARE imploding */ +/* 11 - Reserved by PKWARE */ +#define ZIP_CM_BZIP2 12 /* compressed using BZIP2 algorithm */ +/* 13 - Reserved by PKWARE */ +#define ZIP_CM_LZMA 14 /* LZMA (EFS) */ +/* 15-17 - Reserved by PKWARE */ +#define ZIP_CM_TERSE 18 /* compressed using IBM TERSE (new) */ +#define ZIP_CM_LZ77 19 /* IBM LZ77 z Architecture (PFS) */ +#define ZIP_CM_WAVPACK 97 /* WavPack compressed data */ +#define ZIP_CM_PPMD 98 /* PPMd version I, Rev 1 */ + +/* encryption methods */ + +#define ZIP_EM_NONE 0 /* not encrypted */ +#define ZIP_EM_TRAD_PKWARE 1 /* traditional PKWARE encryption */ +#if 0 /* Strong Encryption Header not parsed yet */ +#define ZIP_EM_DES 0x6601 /* strong encryption: DES */ +#define ZIP_EM_RC2_OLD 0x6602 /* strong encryption: RC2, version < 5.2 */ +#define ZIP_EM_3DES_168 0x6603 +#define ZIP_EM_3DES_112 0x6609 +#define ZIP_EM_AES_128 0x660e +#define ZIP_EM_AES_192 0x660f +#define ZIP_EM_AES_256 0x6610 +#define ZIP_EM_RC2 0x6702 /* strong encryption: RC2, version >= 5.2 */ +#define ZIP_EM_RC4 0x6801 +#endif +#define ZIP_EM_UNKNOWN 0xffff /* unknown algorithm */ + +typedef long myoff_t; /* XXX: 64 bit support */ + +enum zip_source_cmd { + ZIP_SOURCE_OPEN, /* prepare for reading */ + ZIP_SOURCE_READ, /* read data */ + ZIP_SOURCE_CLOSE, /* reading is done */ + ZIP_SOURCE_STAT, /* get meta information */ + ZIP_SOURCE_ERROR, /* get error information */ + ZIP_SOURCE_FREE /* cleanup and free resources */ +}; + +typedef ssize_t (*zip_source_callback)(void *state, void *data, + size_t len, enum zip_source_cmd cmd); + +struct zip_stat { + const char *name; /* name of the file */ + int index; /* index within archive */ + unsigned int crc; /* crc of file data */ + time_t mtime; /* modification time */ + myoff_t size; /* size of file (uncompressed) */ + myoff_t comp_size; /* size of file (compressed) */ + unsigned short comp_method; /* compression method used */ + unsigned short encryption_method; /* encryption method used */ +}; + +struct zip; +struct zip_file; +struct zip_source; + + +ZIP_EXTERN int zip_add(struct zip *, const char *, struct zip_source *); +ZIP_EXTERN int zip_add_dir(struct zip *, const char *); +ZIP_EXTERN int zip_close(struct zip *); +ZIP_EXTERN int zip_delete(struct zip *, int); +ZIP_EXTERN void zip_error_clear(struct zip *); +ZIP_EXTERN void zip_error_get(struct zip *, int *, int *); +ZIP_EXTERN int zip_error_get_sys_type(int); +ZIP_EXTERN int zip_error_to_str(char *, size_t, int, int); +ZIP_EXTERN int zip_fclose(struct zip_file *); +ZIP_EXTERN void zip_file_error_clear(struct zip_file *); +ZIP_EXTERN void zip_file_error_get(struct zip_file *, int *, int *); +ZIP_EXTERN const char *zip_file_strerror(struct zip_file *); +ZIP_EXTERN struct zip_file *zip_fopen(struct zip *, const char *, int); +ZIP_EXTERN struct zip_file *zip_fopen_index(struct zip *, int, int); +ZIP_EXTERN ssize_t zip_fread(struct zip_file *, void *, size_t); +ZIP_EXTERN const char *zip_get_archive_comment(struct zip *, int *, int); +ZIP_EXTERN int zip_get_archive_flag(struct zip *, int, int); +ZIP_EXTERN const char *zip_get_file_comment(struct zip *, int, int *, int); +ZIP_EXTERN const char *zip_get_name(struct zip *, int, int); +ZIP_EXTERN int zip_get_num_files(struct zip *); +ZIP_EXTERN int zip_name_locate(struct zip *, const char *, int); +ZIP_EXTERN struct zip *zip_open(const char *, int, int *); +ZIP_EXTERN int zip_rename(struct zip *, int, const char *); +ZIP_EXTERN int zip_replace(struct zip *, int, struct zip_source *); +ZIP_EXTERN int zip_set_archive_comment(struct zip *, const char *, int); +ZIP_EXTERN int zip_set_archive_flag(struct zip *, int, int); +ZIP_EXTERN int zip_set_file_comment(struct zip *, int, const char *, int); +ZIP_EXTERN struct zip_source *zip_source_buffer(struct zip *, const void *, + myoff_t, int); +ZIP_EXTERN struct zip_source *zip_source_file(struct zip *, const char *, + myoff_t, myoff_t); +ZIP_EXTERN struct zip_source *zip_source_filep(struct zip *, FILE *, + myoff_t, myoff_t); +ZIP_EXTERN void zip_source_free(struct zip_source *); +ZIP_EXTERN struct zip_source *zip_source_function(struct zip *, + zip_source_callback, void *); +ZIP_EXTERN struct zip_source *zip_source_zip(struct zip *, struct zip *, + int, int, myoff_t, myoff_t); +ZIP_EXTERN int zip_stat(struct zip *, const char *, int, struct zip_stat *); +ZIP_EXTERN int zip_stat_index(struct zip *, int, int, struct zip_stat *); +ZIP_EXTERN void zip_stat_init(struct zip_stat *); +ZIP_EXTERN const char *zip_strerror(struct zip *); +ZIP_EXTERN int zip_unchange(struct zip *, int); +ZIP_EXTERN int zip_unchange_all(struct zip *); +ZIP_EXTERN int zip_unchange_archive(struct zip *); + +#ifdef __cplusplus +} +#endif + + +/* config.h. Generated from config.h.in by configure. */ +/* config.h.in. Generated from configure.ac by autoheader. */ + +/* Define to 1 if you have the declaration of `tzname', and to 0 if you don't. + */ +/* #undef HAVE_DECL_TZNAME */ + +#define HAVE_CONFIG_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_DLFCN_H 1 + +/* Define to 1 if you have the `fseeko' function. */ +#define HAVE_FSEEKO 1 + +/* Define to 1 if you have the `ftello' function. */ +#define HAVE_FTELLO 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the `z' library (-lz). */ +#define HAVE_LIBZ 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_MEMORY_H 1 + +/* Define to 1 if you have the `mkstemp' function. */ +#define HAVE_MKSTEMP 1 + +/* Define to 1 if you have the `MoveFileExA' function. */ +/* #undef HAVE_MOVEFILEEXA */ + +/* Define to 1 if you have the header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if `tm_zone' is member of `struct tm'. */ +#ifdef WIN32 +#undef HAVE_STRUCT_TM_TM_ZONE +#else +#define HAVE_STRUCT_TM_TM_ZONE 1 +#endif + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if your `struct tm' has `tm_zone'. Deprecated, use + `HAVE_STRUCT_TM_TM_ZONE' instead. */ +#define HAVE_TM_ZONE 1 + +/* Define to 1 if you don't have `tm_zone' but do have the external array + `tzname'. */ +/* #undef HAVE_TZNAME */ + +/* Define to 1 if you have the header file. */ +#define HAVE_UNISTD_H 1 + +/* Define to 1 if your C compiler doesn't accept -c and -o together. */ +/* #undef NO_MINUS_C_MINUS_O */ + +/* Name of package */ +#define PACKAGE "libzip" + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "libzip@nih.at" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "libzip" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "libzip 0.9" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "libzip" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "0.9" + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Define to 1 if your declares `struct tm'. */ +/* #undef TM_IN_SYS_TIME */ + +/* Version number of package */ +#define VERSION "0.9" + + +#ifndef HAVE_MKSTEMP +int _zip_mkstemp(char *); +#define mkstemp _zip_mkstemp +#endif + +#ifdef HAVE_MOVEFILEEXA +#include +#define _zip_rename(s, t) \ + (!MoveFileExA((s), (t), \ + MOVEFILE_COPY_ALLOWED|MOVEFILE_REPLACE_EXISTING)) +#else +#define _zip_rename rename +#endif + +#ifndef HAVE_FSEEKO +#define fseeko(s, o, w) (fseek((s), (long int)(o), (w))) +#endif +#ifndef HAVE_FTELLO +#define ftello(s) ((long)ftell((s))) +#endif + + +#define CENTRAL_MAGIC "PK\1\2" +#define LOCAL_MAGIC "PK\3\4" +#define EOCD_MAGIC "PK\5\6" +#define DATADES_MAGIC "PK\7\8" +#define TORRENT_SIG "TORRENTZIPPED-" +#define TORRENT_SIG_LEN 14 +#define TORRENT_CRC_LEN 8 +#define TORRENT_MEM_LEVEL 8 +#define CDENTRYSIZE 46u +#define LENTRYSIZE 30 +#define MAXCOMLEN 65536 +#define EOCDLEN 22 +#define CDBUFSIZE (MAXCOMLEN+EOCDLEN) +#define BUFSIZE 8192 + + +/* state of change of a file in zip archive */ + +enum zip_state { ZIP_ST_UNCHANGED, ZIP_ST_DELETED, ZIP_ST_REPLACED, + ZIP_ST_ADDED, ZIP_ST_RENAMED }; + +/* constants for struct zip_file's member flags */ + +#define ZIP_ZF_EOF 1 /* EOF reached */ +#define ZIP_ZF_DECOMP 2 /* decompress data */ +#define ZIP_ZF_CRC 4 /* compute and compare CRC */ + +/* directory entry: general purpose bit flags */ + +#define ZIP_GPBF_ENCRYPTED 0x0001 /* is encrypted */ +#define ZIP_GPBF_DATA_DESCRIPTOR 0x0008 /* crc/size after file data */ +#define ZIP_GPBF_STRONG_ENCRYPTION 0x0040 /* uses strong encryption */ + +/* error information */ + +struct zip_error { + int zip_err; /* libzip error code (ZIP_ER_*) */ + int sys_err; /* copy of errno (E*) or zlib error code */ + char *str; /* string representation or NULL */ +}; + +/* zip archive, part of API */ + +struct zip { + char *zn; /* file name */ + FILE *zp; /* file */ + struct zip_error error; /* error information */ + + unsigned int flags; /* archive global flags */ + unsigned int ch_flags; /* changed archive global flags */ + + struct zip_cdir *cdir; /* central directory */ + char *ch_comment; /* changed archive comment */ + int ch_comment_len; /* length of changed zip archive + * comment, -1 if unchanged */ + int nentry; /* number of entries */ + int nentry_alloc; /* number of entries allocated */ + struct zip_entry *entry; /* entries */ + int nfile; /* number of opened files within archive */ + int nfile_alloc; /* number of files allocated */ + struct zip_file **file; /* opened files within archive */ +}; + +/* file in zip archive, part of API */ + +struct zip_file { + struct zip *za; /* zip archive containing this file */ + struct zip_error error; /* error information */ + int flags; /* -1: eof, >0: error */ + + int method; /* compression method */ + myoff_t fpos; /* position within zip file (fread/fwrite) */ + unsigned long bytes_left; /* number of bytes left to read */ + unsigned long cbytes_left; /* number of bytes of compressed data left */ + + unsigned long crc; /* CRC so far */ + unsigned long crc_orig; /* CRC recorded in archive */ + + char *buffer; + z_stream *zstr; +}; + +/* zip archive directory entry (central or local) */ + +struct zip_dirent { + unsigned short version_madeby; /* (c) version of creator */ + unsigned short version_needed; /* (cl) version needed to extract */ + unsigned short bitflags; /* (cl) general purpose bit flag */ + unsigned short comp_method; /* (cl) compression method used */ + time_t last_mod; /* (cl) time of last modification */ + unsigned int crc; /* (cl) CRC-32 of uncompressed data */ + unsigned int comp_size; /* (cl) size of commpressed data */ + unsigned int uncomp_size; /* (cl) size of uncommpressed data */ + char *filename; /* (cl) file name (NUL-terminated) */ + unsigned short filename_len; /* (cl) length of filename (w/o NUL) */ + char *extrafield; /* (cl) extra field */ + unsigned short extrafield_len; /* (cl) length of extra field */ + char *comment; /* (c) file comment */ + unsigned short comment_len; /* (c) length of file comment */ + unsigned short disk_number; /* (c) disk number start */ + unsigned short int_attrib; /* (c) internal file attributes */ + unsigned int ext_attrib; /* (c) external file attributes */ + unsigned int offset; /* (c) offset of local header */ +}; + +/* zip archive central directory */ + +struct zip_cdir { + struct zip_dirent *entry; /* directory entries */ + int nentry; /* number of entries */ + + unsigned int size; /* size of central direcotry */ + unsigned int offset; /* offset of central directory in file */ + char *comment; /* zip archive comment */ + unsigned short comment_len; /* length of zip archive comment */ +}; + + + +struct zip_source { + zip_source_callback f; + void *ud; +}; + +/* entry in zip archive directory */ + +struct zip_entry { + enum zip_state state; + struct zip_source *source; + char *ch_filename; + char *ch_comment; + int ch_comment_len; +}; + + + +extern const char * const _zip_err_str[]; +extern const int _zip_nerr_str; +extern const int _zip_err_type[]; + + + +#define ZIP_ENTRY_DATA_CHANGED(x) \ + ((x)->state == ZIP_ST_REPLACED \ + || (x)->state == ZIP_ST_ADDED) + + + +int _zip_cdir_compute_crc(struct zip *, uLong *); +void _zip_cdir_free(struct zip_cdir *); +struct zip_cdir *_zip_cdir_new(int, struct zip_error *); +int _zip_cdir_write(struct zip_cdir *, FILE *, struct zip_error *); + +void _zip_dirent_finalize(struct zip_dirent *); +void _zip_dirent_init(struct zip_dirent *); +int _zip_dirent_read(struct zip_dirent *, FILE *, + unsigned char **, unsigned int, int, struct zip_error *); +void _zip_dirent_torrent_normalize(struct zip_dirent *); +int _zip_dirent_write(struct zip_dirent *, FILE *, int, struct zip_error *); + +void _zip_entry_free(struct zip_entry *); +void _zip_entry_init(struct zip *, int); +struct zip_entry *_zip_entry_new(struct zip *); + +void _zip_error_clear(struct zip_error *); +void _zip_error_copy(struct zip_error *, struct zip_error *); +void _zip_error_fini(struct zip_error *); +void _zip_error_get(struct zip_error *, int *, int *); +void _zip_error_init(struct zip_error *); +void _zip_error_set(struct zip_error *, int, int); +const char *_zip_error_strerror(struct zip_error *); + +int _zip_file_fillbuf(void *, size_t, struct zip_file *); +unsigned int _zip_file_get_offset(struct zip *, int); + +int _zip_filerange_crc(FILE *, myoff_t, myoff_t, uLong *, struct zip_error *); + +struct zip_source *_zip_source_file_or_p(struct zip *, const char *, FILE *, + myoff_t, myoff_t); + +void _zip_free(struct zip *); +const char *_zip_get_name(struct zip *, int, int, struct zip_error *); +int _zip_local_header_read(struct zip *, int); +void *_zip_memdup(const void *, size_t, struct zip_error *); +int _zip_name_locate(struct zip *, const char *, int, struct zip_error *); +struct zip *_zip_new(struct zip_error *); +unsigned short _zip_read2(unsigned char **); +unsigned int _zip_read4(unsigned char **); +int _zip_replace(struct zip *, int, const char *, struct zip_source *); +int _zip_set_name(struct zip *, int, const char *); +int _zip_unchange(struct zip *, int, int); +void _zip_unchange_data(struct zip_entry *); + + +#include +#include +#include +#include + +const char * +_zip_error_strerror(struct zip_error *err) +{ + const char *zs, *ss; + char buf[128], *s; + + _zip_error_fini(err); + + if (err->zip_err < 0 || err->zip_err >= _zip_nerr_str) { + sprintf(buf, "Unknown error %d", err->zip_err); + zs = NULL; + ss = buf; + } + else { + zs = _zip_err_str[err->zip_err]; + + switch (_zip_err_type[err->zip_err]) { + case ZIP_ET_SYS: + ss = strerror(err->sys_err); + break; + + case ZIP_ET_ZLIB: + ss = zError(err->sys_err); + break; + + default: + ss = NULL; + } + } + + if (ss == NULL) + return zs; + else { + if ((s=(char *)malloc(strlen(ss) + + (zs ? strlen(zs)+2 : 0) + 1)) == NULL) + return _zip_err_str[ZIP_ER_MEMORY]; + + sprintf(s, "%s%s%s", + (zs ? zs : ""), + (zs ? ": " : ""), + ss); + err->str = s; + + return s; + } +} + +#include + + + +void +_zip_error_clear(struct zip_error *err) +{ + err->zip_err = ZIP_ER_OK; + err->sys_err = 0; +} + + + +void +_zip_error_copy(struct zip_error *dst, struct zip_error *src) +{ + dst->zip_err = src->zip_err; + dst->sys_err = src->sys_err; +} + + + +void +_zip_error_fini(struct zip_error *err) +{ + free(err->str); + err->str = NULL; +} + + + +void +_zip_error_get(struct zip_error *err, int *zep, int *sep) +{ + if (zep) + *zep = err->zip_err; + if (sep) { + if (zip_error_get_sys_type(err->zip_err) != ZIP_ET_NONE) + *sep = err->sys_err; + else + *sep = 0; + } +} + + + +void +_zip_error_init(struct zip_error *err) +{ + err->zip_err = ZIP_ER_OK; + err->sys_err = 0; + err->str = NULL; +} + + + +void +_zip_error_set(struct zip_error *err, int ze, int se) +{ + if (err) { + err->zip_err = ze; + err->sys_err = se; + } +} + + +#include +#include + +#include +#include +#include +#include +#include +#include + +#ifndef O_BINARY +#define O_BINARY 0 +#endif + + + +int +_zip_mkstemp(char *path) +{ + int fd; + char *start, *trv; + struct stat sbuf; + pid_t pid; + + /* To guarantee multiple calls generate unique names even if + the file is not created. 676 different possibilities with 7 + or more X's, 26 with 6 or less. */ + static char xtra[2] = "aa"; + int xcnt = 0; + + pid = getpid(); + + /* Move to end of path and count trailing X's. */ + for (trv = path; *trv; ++trv) + if (*trv == 'X') + xcnt++; + else + xcnt = 0; + + /* Use at least one from xtra. Use 2 if more than 6 X's. */ + if (*(trv - 1) == 'X') + *--trv = xtra[0]; + if (xcnt > 6 && *(trv - 1) == 'X') + *--trv = xtra[1]; + + /* Set remaining X's to pid digits with 0's to the left. */ + while (*--trv == 'X') { + *trv = (pid % 10) + '0'; + pid /= 10; + } + + /* update xtra for next call. */ + if (xtra[0] != 'z') + xtra[0]++; + else { + xtra[0] = 'a'; + if (xtra[1] != 'z') + xtra[1]++; + else + xtra[1] = 'a'; + } + + /* + * check the target directory; if you have six X's and it + * doesn't exist this runs for a *very* long time. + */ + for (start = trv + 1;; --trv) { + if (trv <= path) + break; + if (*trv == '/') { + *trv = '\0'; + if (stat(path, &sbuf)) + return (0); + if (!S_ISDIR(sbuf.st_mode)) { + errno = ENOTDIR; + return (0); + } + *trv = '/'; + break; + } + } + + for (;;) { + if ((fd=open(path, O_CREAT|O_EXCL|O_RDWR|O_BINARY, 0600)) >= 0) + return (fd); + if (errno != EEXIST) + return (0); + + /* tricky little algorithm for backward compatibility */ + for (trv = start;;) { + if (!*trv) + return (0); + if (*trv == 'z') + *trv++ = 'a'; + else { + if (isdigit((unsigned char)*trv)) + *trv = 'a'; + else + ++*trv; + break; + } + } + } + /*NOTREACHED*/ +} + + +#include +#include +#include +#include +#include +#include + +static time_t _zip_d2u_time(int, int); +static char *_zip_readfpstr(FILE *, unsigned int, int, struct zip_error *); +static char *_zip_readstr(unsigned char **, int, int, struct zip_error *); +static void _zip_u2d_time(time_t, unsigned short *, unsigned short *); +static void _zip_write2(unsigned short, FILE *); +static void _zip_write4(unsigned int, FILE *); + + + +void +_zip_cdir_free(struct zip_cdir *cd) +{ + int i; + + if (!cd) + return; + + for (i=0; inentry; i++) + _zip_dirent_finalize(cd->entry+i); + free(cd->comment); + free(cd->entry); + free(cd); +} + + + +struct zip_cdir * +_zip_cdir_new(int nentry, struct zip_error *error) +{ + struct zip_cdir *cd; + + if ((cd=(struct zip_cdir *)malloc(sizeof(*cd))) == NULL) { + _zip_error_set(error, ZIP_ER_MEMORY, 0); + return NULL; + } + + if ((cd->entry=(struct zip_dirent *)malloc(sizeof(*(cd->entry))*nentry)) + == NULL) { + _zip_error_set(error, ZIP_ER_MEMORY, 0); + free(cd); + return NULL; + } + + /* entries must be initialized by caller */ + + cd->nentry = nentry; + cd->size = cd->offset = 0; + cd->comment = NULL; + cd->comment_len = 0; + + return cd; +} + + + +int +_zip_cdir_write(struct zip_cdir *cd, FILE *fp, struct zip_error *error) +{ + int i; + + cd->offset = ftello(fp); + + for (i=0; inentry; i++) { + if (_zip_dirent_write(cd->entry+i, fp, 0, error) != 0) + return -1; + } + + cd->size = ftello(fp) - cd->offset; + + /* clearerr(fp); */ + fwrite(EOCD_MAGIC, 1, 4, fp); + _zip_write4(0, fp); + _zip_write2((unsigned short)cd->nentry, fp); + _zip_write2((unsigned short)cd->nentry, fp); + _zip_write4(cd->size, fp); + _zip_write4(cd->offset, fp); + _zip_write2(cd->comment_len, fp); + fwrite(cd->comment, 1, cd->comment_len, fp); + + if (ferror(fp)) { + _zip_error_set(error, ZIP_ER_WRITE, errno); + return -1; + } + + return 0; +} + + + +void +_zip_dirent_finalize(struct zip_dirent *zde) +{ + free(zde->filename); + zde->filename = NULL; + free(zde->extrafield); + zde->extrafield = NULL; + free(zde->comment); + zde->comment = NULL; +} + + + +void +_zip_dirent_init(struct zip_dirent *de) +{ + de->version_madeby = 0; + de->version_needed = 20; /* 2.0 */ + de->bitflags = 0; + de->comp_method = 0; + de->last_mod = 0; + de->crc = 0; + de->comp_size = 0; + de->uncomp_size = 0; + de->filename = NULL; + de->filename_len = 0; + de->extrafield = NULL; + de->extrafield_len = 0; + de->comment = NULL; + de->comment_len = 0; + de->disk_number = 0; + de->int_attrib = 0; + de->ext_attrib = 0; + de->offset = 0; +} + + + +/* _zip_dirent_read(zde, fp, bufp, left, localp, error): + Fills the zip directory entry zde. + + If bufp is non-NULL, data is taken from there and bufp is advanced + by the amount of data used; no more than left bytes are used. + Otherwise data is read from fp as needed. + + If localp != 0, it reads a local header instead of a central + directory entry. + + Returns 0 if successful. On error, error is filled in and -1 is + returned. +*/ + +int +_zip_dirent_read(struct zip_dirent *zde, FILE *fp, + unsigned char **bufp, unsigned int left, int localp, + struct zip_error *error) +{ + unsigned char buf[CDENTRYSIZE]; + unsigned char *cur; + unsigned short dostime, dosdate; + unsigned int size; + + if (localp) + size = LENTRYSIZE; + else + size = CDENTRYSIZE; + + if (bufp) { + /* use data from buffer */ + cur = *bufp; + if (left < size) { + _zip_error_set(error, ZIP_ER_NOZIP, 0); + return -1; + } + } + else { + /* read entry from disk */ + if ((fread(buf, 1, size, fp)version_madeby = _zip_read2(&cur); + else + zde->version_madeby = 0; + zde->version_needed = _zip_read2(&cur); + zde->bitflags = _zip_read2(&cur); + zde->comp_method = _zip_read2(&cur); + + /* convert to time_t */ + dostime = _zip_read2(&cur); + dosdate = _zip_read2(&cur); + zde->last_mod = _zip_d2u_time(dostime, dosdate); + + zde->crc = _zip_read4(&cur); + zde->comp_size = _zip_read4(&cur); + zde->uncomp_size = _zip_read4(&cur); + + zde->filename_len = _zip_read2(&cur); + zde->extrafield_len = _zip_read2(&cur); + + if (localp) { + zde->comment_len = 0; + zde->disk_number = 0; + zde->int_attrib = 0; + zde->ext_attrib = 0; + zde->offset = 0; + } else { + zde->comment_len = _zip_read2(&cur); + zde->disk_number = _zip_read2(&cur); + zde->int_attrib = _zip_read2(&cur); + zde->ext_attrib = _zip_read4(&cur); + zde->offset = _zip_read4(&cur); + } + + zde->filename = NULL; + zde->extrafield = NULL; + zde->comment = NULL; + + if (bufp) { + if (left < CDENTRYSIZE + (zde->filename_len+zde->extrafield_len + +zde->comment_len)) { + _zip_error_set(error, ZIP_ER_NOZIP, 0); + return -1; + } + + if (zde->filename_len) { + zde->filename = _zip_readstr(&cur, zde->filename_len, 1, error); + if (!zde->filename) + return -1; + } + + if (zde->extrafield_len) { + zde->extrafield = _zip_readstr(&cur, zde->extrafield_len, 0, + error); + if (!zde->extrafield) + return -1; + } + + if (zde->comment_len) { + zde->comment = _zip_readstr(&cur, zde->comment_len, 0, error); + if (!zde->comment) + return -1; + } + } + else { + if (zde->filename_len) { + zde->filename = _zip_readfpstr(fp, zde->filename_len, 1, error); + if (!zde->filename) + return -1; + } + + if (zde->extrafield_len) { + zde->extrafield = _zip_readfpstr(fp, zde->extrafield_len, 0, + error); + if (!zde->extrafield) + return -1; + } + + if (zde->comment_len) { + zde->comment = _zip_readfpstr(fp, zde->comment_len, 0, error); + if (!zde->comment) + return -1; + } + } + + if (bufp) + *bufp = cur; + + return 0; +} + + + +/* _zip_dirent_torrent_normalize(de); + Set values suitable for torrentzip. +*/ + +void +_zip_dirent_torrent_normalize(struct zip_dirent *de) +{ + static struct tm torrenttime; + static time_t last_mod = 0; + + if (last_mod == 0) { +#ifdef HAVE_STRUCT_TM_TM_ZONE + time_t now; + struct tm *l; +#endif + + torrenttime.tm_sec = 0; + torrenttime.tm_min = 32; + torrenttime.tm_hour = 23; + torrenttime.tm_mday = 24; + torrenttime.tm_mon = 11; + torrenttime.tm_year = 96; + torrenttime.tm_wday = 0; + torrenttime.tm_yday = 0; + torrenttime.tm_isdst = 0; + +#ifdef HAVE_STRUCT_TM_TM_ZONE + time(&now); + l = localtime(&now); + torrenttime.tm_gmtoff = l->tm_gmtoff; + torrenttime.tm_zone = l->tm_zone; +#endif + + last_mod = mktime(&torrenttime); + } + + de->version_madeby = 0; + de->version_needed = 20; /* 2.0 */ + de->bitflags = 2; /* maximum compression */ + de->comp_method = ZIP_CM_DEFLATE; + de->last_mod = last_mod; + + de->disk_number = 0; + de->int_attrib = 0; + de->ext_attrib = 0; + de->offset = 0; + + free(de->extrafield); + de->extrafield = NULL; + de->extrafield_len = 0; + free(de->comment); + de->comment = NULL; + de->comment_len = 0; +} + + + +/* _zip_dirent_write(zde, fp, localp, error): + Writes zip directory entry zde to file fp. + + If localp != 0, it writes a local header instead of a central + directory entry. + + Returns 0 if successful. On error, error is filled in and -1 is + returned. +*/ + +int +_zip_dirent_write(struct zip_dirent *zde, FILE *fp, int localp, + struct zip_error *error) +{ + unsigned short dostime, dosdate; + + fwrite(localp ? LOCAL_MAGIC : CENTRAL_MAGIC, 1, 4, fp); + + if (!localp) + _zip_write2(zde->version_madeby, fp); + _zip_write2(zde->version_needed, fp); + _zip_write2(zde->bitflags, fp); + _zip_write2(zde->comp_method, fp); + + _zip_u2d_time(zde->last_mod, &dostime, &dosdate); + _zip_write2(dostime, fp); + _zip_write2(dosdate, fp); + + _zip_write4(zde->crc, fp); + _zip_write4(zde->comp_size, fp); + _zip_write4(zde->uncomp_size, fp); + + _zip_write2(zde->filename_len, fp); + _zip_write2(zde->extrafield_len, fp); + + if (!localp) { + _zip_write2(zde->comment_len, fp); + _zip_write2(zde->disk_number, fp); + _zip_write2(zde->int_attrib, fp); + _zip_write4(zde->ext_attrib, fp); + _zip_write4(zde->offset, fp); + } + + if (zde->filename_len) + fwrite(zde->filename, 1, zde->filename_len, fp); + + if (zde->extrafield_len) + fwrite(zde->extrafield, 1, zde->extrafield_len, fp); + + if (!localp) { + if (zde->comment_len) + fwrite(zde->comment, 1, zde->comment_len, fp); + } + + if (ferror(fp)) { + _zip_error_set(error, ZIP_ER_WRITE, errno); + return -1; + } + + return 0; +} + + + +static time_t +_zip_d2u_time(int dtime, int ddate) +{ + struct tm *tm; + time_t now; + + now = time(NULL); + tm = localtime(&now); + /* let mktime decide if DST is in effect */ + tm->tm_isdst = -1; + + tm->tm_year = ((ddate>>9)&127) + 1980 - 1900; + tm->tm_mon = ((ddate>>5)&15) - 1; + tm->tm_mday = ddate&31; + + tm->tm_hour = (dtime>>11)&31; + tm->tm_min = (dtime>>5)&63; + tm->tm_sec = (dtime<<1)&62; + + return mktime(tm); +} + + + +unsigned short +_zip_read2(unsigned char **a) +{ + unsigned short ret; + + ret = (*a)[0]+((*a)[1]<<8); + *a += 2; + + return ret; +} + + + +unsigned int +_zip_read4(unsigned char **a) +{ + unsigned int ret; + + ret = ((((((*a)[3]<<8)+(*a)[2])<<8)+(*a)[1])<<8)+(*a)[0]; + *a += 4; + + return ret; +} + + + +static char * +_zip_readfpstr(FILE *fp, unsigned int len, int nulp, struct zip_error *error) +{ + char *r, *o; + + r = (char *)malloc(nulp ? len+1 : len); + if (!r) { + _zip_error_set(error, ZIP_ER_MEMORY, 0); + return NULL; + } + + if (fread(r, 1, len, fp)>8)&0xff, fp); + + return; +} + + + +static void +_zip_write4(unsigned int i, FILE *fp) +{ + putc(i&0xff, fp); + putc((i>>8)&0xff, fp); + putc((i>>16)&0xff, fp); + putc((i>>24)&0xff, fp); + + return; +} + + + +static void +_zip_u2d_time(time_t time, unsigned short *dtime, unsigned short *ddate) +{ + struct tm *tm; + + tm = localtime(&time); + *ddate = ((tm->tm_year+1900-1980)<<9) + ((tm->tm_mon+1)<<5) + + tm->tm_mday; + *dtime = ((tm->tm_hour)<<11) + ((tm->tm_min)<<5) + + ((tm->tm_sec)>>1); + + return; +} + + + +ZIP_EXTERN int +zip_delete(struct zip *za, int idx) +{ + if (idx < 0 || idx >= za->nentry) { + _zip_error_set(&za->error, ZIP_ER_INVAL, 0); + return -1; + } + + /* allow duplicate file names, because the file will + * be removed directly afterwards */ + if (_zip_unchange(za, idx, 1) != 0) + return -1; + + za->entry[idx].state = ZIP_ST_DELETED; + + return 0; +} + + + +ZIP_EXTERN void +zip_error_clear(struct zip *za) +{ + _zip_error_clear(&za->error); +} + + +ZIP_EXTERN int +zip_add(struct zip *za, const char *name, struct zip_source *source) +{ + if (name == NULL || source == NULL) { + _zip_error_set(&za->error, ZIP_ER_INVAL, 0); + return -1; + } + + return _zip_replace(za, -1, name, source); +} + + +ZIP_EXTERN int +zip_error_get_sys_type(int ze) +{ + if (ze < 0 || ze >= _zip_nerr_str) + return 0; + + return _zip_err_type[ze]; +} + + +ZIP_EXTERN void +zip_error_get(struct zip *za, int *zep, int *sep) +{ + _zip_error_get(&za->error, zep, sep); +} + + +const char * const _zip_err_str[] = { + "No error", + "Multi-disk zip archives not supported", + "Renaming temporary file failed", + "Closing zip archive failed", + "Seek error", + "Read error", + "Write error", + "CRC error", + "Containing zip archive was closed", + "No such file", + "File already exists", + "Can't open file", + "Failure to create temporary file", + "Zlib error", + "Malloc failure", + "Entry has been changed", + "Compression method not supported", + "Premature EOF", + "Invalid argument", + "Not a zip archive", + "Internal error", + "Zip archive inconsistent", + "Can't remove file", + "Entry has been deleted", +}; + +const int _zip_nerr_str = sizeof(_zip_err_str)/sizeof(_zip_err_str[0]); + +#define N ZIP_ET_NONE +#define S ZIP_ET_SYS +#define Z ZIP_ET_ZLIB + +const int _zip_err_type[] = { + N, + N, + S, + S, + S, + S, + S, + N, + N, + N, + N, + S, + S, + Z, + N, + N, + N, + N, + N, + N, + N, + N, + S, + N, +}; + + +struct zip_entry * +_zip_entry_new(struct zip *za) +{ + struct zip_entry *ze; + if (!za) { + ze = (struct zip_entry *)malloc(sizeof(struct zip_entry)); + if (!ze) { + _zip_error_set(&za->error, ZIP_ER_MEMORY, 0); + return NULL; + } + } + else { + if (za->nentry >= za->nentry_alloc-1) { + za->nentry_alloc += 16; + za->entry = (struct zip_entry *)realloc(za->entry, + sizeof(struct zip_entry) + * za->nentry_alloc); + if (!za->entry) { + _zip_error_set(&za->error, ZIP_ER_MEMORY, 0); + return NULL; + } + } + ze = za->entry+za->nentry; + } + + ze->state = ZIP_ST_UNCHANGED; + + ze->ch_filename = NULL; + ze->ch_comment = NULL; + ze->ch_comment_len = -1; + ze->source = NULL; + + if (za) + za->nentry++; + + return ze; +} + + +void +_zip_entry_free(struct zip_entry *ze) +{ + free(ze->ch_filename); + ze->ch_filename = NULL; + free(ze->ch_comment); + ze->ch_comment = NULL; + ze->ch_comment_len = -1; + + _zip_unchange_data(ze); +} + + +static int add_data(struct zip *, struct zip_source *, struct zip_dirent *, + FILE *); +static int add_data_comp(zip_source_callback, void *, struct zip_stat *, + FILE *, struct zip_error *); +static int add_data_uncomp(struct zip *, zip_source_callback, void *, + struct zip_stat *, FILE *); +static void ch_set_error(struct zip_error *, zip_source_callback, void *); +static int copy_data(FILE *, myoff_t, FILE *, struct zip_error *); +static int write_cdir(struct zip *, struct zip_cdir *, FILE *); +static int _zip_cdir_set_comment(struct zip_cdir *, struct zip *); +static int _zip_changed(struct zip *, int *); +static char *_zip_create_temp_output(struct zip *, FILE **); +static int _zip_torrentzip_cmp(const void *, const void *); + + + +struct filelist { + int idx; + const char *name; +}; + + + +ZIP_EXTERN int +zip_close(struct zip *za) +{ + int survivors; + int i, j, error; + char *temp; + FILE *out; + mode_t mask; + struct zip_cdir *cd; + struct zip_dirent de; + struct filelist *filelist; + int reopen_on_error; + int new_torrentzip; + + reopen_on_error = 0; + + if (za == NULL) + return -1; + + if (!_zip_changed(za, &survivors)) { + _zip_free(za); + return 0; + } + + /* don't create zip files with no entries */ + if (survivors == 0) { + if (za->zn && za->zp) { + if (remove(za->zn) != 0) { + _zip_error_set(&za->error, ZIP_ER_REMOVE, errno); + return -1; + } + } + _zip_free(za); + return 0; + } + + if ((filelist=(struct filelist *)malloc(sizeof(filelist[0])*survivors)) + == NULL) + return -1; + + if ((cd=_zip_cdir_new(survivors, &za->error)) == NULL) { + free(filelist); + return -1; + } + + for (i=0; ientry[i]); + + /* archive comment is special for torrentzip */ + if (zip_get_archive_flag(za, ZIP_AFL_TORRENT, 0)) { + cd->comment = _zip_memdup(TORRENT_SIG "XXXXXXXX", + TORRENT_SIG_LEN + TORRENT_CRC_LEN, + &za->error); + if (cd->comment == NULL) { + _zip_cdir_free(cd); + free(filelist); + return -1; + } + cd->comment_len = TORRENT_SIG_LEN + TORRENT_CRC_LEN; + } + else if (zip_get_archive_flag(za, ZIP_AFL_TORRENT, ZIP_FL_UNCHANGED) == 0) { + if (_zip_cdir_set_comment(cd, za) == -1) { + _zip_cdir_free(cd); + free(filelist); + return -1; + } + } + + if ((temp=_zip_create_temp_output(za, &out)) == NULL) { + _zip_cdir_free(cd); + return -1; + } + + + /* create list of files with index into original archive */ + for (i=j=0; inentry; i++) { + if (za->entry[i].state == ZIP_ST_DELETED) + continue; + + filelist[j].idx = i; + filelist[j].name = zip_get_name(za, i, 0); + j++; + } + if (zip_get_archive_flag(za, ZIP_AFL_TORRENT, 0)) + qsort(filelist, survivors, sizeof(filelist[0]), + _zip_torrentzip_cmp); + + new_torrentzip = (zip_get_archive_flag(za, ZIP_AFL_TORRENT, 0) == 1 + && zip_get_archive_flag(za, ZIP_AFL_TORRENT, + ZIP_FL_UNCHANGED) == 0); + error = 0; + for (j=0; jentry+i) || new_torrentzip) { + _zip_dirent_init(&de); + + if (zip_get_archive_flag(za, ZIP_AFL_TORRENT, 0)) + _zip_dirent_torrent_normalize(&de); + + /* use it as central directory entry */ + memcpy(cd->entry+j, &de, sizeof(cd->entry[j])); + + /* set/update file name */ + if (za->entry[i].ch_filename == NULL) { + if (za->entry[i].state == ZIP_ST_ADDED) { + de.filename = strdup("-"); + de.filename_len = 1; + cd->entry[j].filename = "-"; + } + else { + de.filename = strdup(za->cdir->entry[i].filename); + de.filename_len = strlen(de.filename); + cd->entry[j].filename = za->cdir->entry[i].filename; + cd->entry[j].filename_len = de.filename_len; + } + } + } + else { + /* copy existing directory entries */ + if (fseeko(za->zp, za->cdir->entry[i].offset, SEEK_SET) != 0) { + _zip_error_set(&za->error, ZIP_ER_SEEK, errno); + error = 1; + break; + } + if (_zip_dirent_read(&de, za->zp, NULL, 0, 1, &za->error) != 0) { + error = 1; + break; + } + if (de.bitflags & ZIP_GPBF_DATA_DESCRIPTOR) { + de.crc = za->cdir->entry[i].crc; + de.comp_size = za->cdir->entry[i].comp_size; + de.uncomp_size = za->cdir->entry[i].uncomp_size; + de.bitflags &= ~ZIP_GPBF_DATA_DESCRIPTOR; + } + memcpy(cd->entry+j, za->cdir->entry+i, sizeof(cd->entry[j])); + } + + if (za->entry[i].ch_filename) { + free(de.filename); + if ((de.filename=strdup(za->entry[i].ch_filename)) == NULL) { + error = 1; + break; + } + de.filename_len = strlen(de.filename); + cd->entry[j].filename = za->entry[i].ch_filename; + cd->entry[j].filename_len = de.filename_len; + } + + if (zip_get_archive_flag(za, ZIP_AFL_TORRENT, 0) == 0 + && za->entry[i].ch_comment_len != -1) { + /* as the rest of cd entries, its malloc/free is done by za */ + cd->entry[j].comment = za->entry[i].ch_comment; + cd->entry[j].comment_len = za->entry[i].ch_comment_len; + } + + cd->entry[j].offset = ftello(out); + + if (ZIP_ENTRY_DATA_CHANGED(za->entry+i) || new_torrentzip) { + struct zip_source *zs; + + zs = NULL; + if (!ZIP_ENTRY_DATA_CHANGED(za->entry+i)) { + if ((zs=zip_source_zip(za, za, i, ZIP_FL_RECOMPRESS, 0, -1)) + == NULL) { + error = 1; + break; + } + } + + if (add_data(za, zs ? zs : za->entry[i].source, &de, out) < 0) { + error = 1; + break; + } + cd->entry[j].last_mod = de.last_mod; + cd->entry[j].comp_method = de.comp_method; + cd->entry[j].comp_size = de.comp_size; + cd->entry[j].uncomp_size = de.uncomp_size; + cd->entry[j].crc = de.crc; + } + else { + if (_zip_dirent_write(&de, out, 1, &za->error) < 0) { + error = 1; + break; + } + /* we just read the local dirent, file is at correct position */ + if (copy_data(za->zp, cd->entry[j].comp_size, out, + &za->error) < 0) { + error = 1; + break; + } + } + + _zip_dirent_finalize(&de); + } + + if (!error) { + if (write_cdir(za, cd, out) < 0) + error = 1; + } + + /* pointers in cd entries are owned by za */ + cd->nentry = 0; + _zip_cdir_free(cd); + + if (error) { + _zip_dirent_finalize(&de); + fclose(out); + remove(temp); + free(temp); + return -1; + } + + if (fclose(out) != 0) { + _zip_error_set(&za->error, ZIP_ER_CLOSE, errno); + remove(temp); + free(temp); + return -1; + } + + if (za->zp) { + fclose(za->zp); + za->zp = NULL; + reopen_on_error = 1; + } + if (_zip_rename(temp, za->zn) != 0) { + _zip_error_set(&za->error, ZIP_ER_RENAME, errno); + remove(temp); + free(temp); + if (reopen_on_error) { + /* ignore errors, since we're already in an error case */ + za->zp = fopen(za->zn, "rb"); + } + return -1; + } + mask = umask(0); + umask(mask); + chmod(za->zn, 0666&~mask); + + _zip_free(za); + free(temp); + + return 0; +} + + + +static int +add_data(struct zip *za, struct zip_source *zs, struct zip_dirent *de, FILE *ft) +{ + myoff_t offstart, offend; + zip_source_callback cb; + void *ud; + struct zip_stat st; + + cb = zs->f; + ud = zs->ud; + + if (cb(ud, &st, sizeof(st), ZIP_SOURCE_STAT) < (ssize_t)sizeof(st)) { + ch_set_error(&za->error, cb, ud); + return -1; + } + + if (cb(ud, NULL, 0, ZIP_SOURCE_OPEN) < 0) { + ch_set_error(&za->error, cb, ud); + return -1; + } + + offstart = ftello(ft); + + if (_zip_dirent_write(de, ft, 1, &za->error) < 0) + return -1; + + if (st.comp_method != ZIP_CM_STORE) { + if (add_data_comp(cb, ud, &st, ft, &za->error) < 0) + return -1; + } + else { + if (add_data_uncomp(za, cb, ud, &st, ft) < 0) + return -1; + } + + if (cb(ud, NULL, 0, ZIP_SOURCE_CLOSE) < 0) { + ch_set_error(&za->error, cb, ud); + return -1; + } + + offend = ftello(ft); + + if (fseeko(ft, offstart, SEEK_SET) < 0) { + _zip_error_set(&za->error, ZIP_ER_SEEK, errno); + return -1; + } + + + de->last_mod = st.mtime; + de->comp_method = st.comp_method; + de->crc = st.crc; + de->uncomp_size = st.size; + de->comp_size = st.comp_size; + + if (zip_get_archive_flag(za, ZIP_AFL_TORRENT, 0)) + _zip_dirent_torrent_normalize(de); + + if (_zip_dirent_write(de, ft, 1, &za->error) < 0) + return -1; + + if (fseeko(ft, offend, SEEK_SET) < 0) { + _zip_error_set(&za->error, ZIP_ER_SEEK, errno); + return -1; + } + + return 0; +} + + + +static int +add_data_comp(zip_source_callback cb, void *ud, struct zip_stat *st,FILE *ft, + struct zip_error *error) +{ + char buf[BUFSIZE]; + ssize_t n; + + st->comp_size = 0; + while ((n=cb(ud, buf, sizeof(buf), ZIP_SOURCE_READ)) > 0) { + if (fwrite(buf, 1, n, ft) != (size_t)n) { + _zip_error_set(error, ZIP_ER_WRITE, errno); + return -1; + } + + st->comp_size += n; + } + if (n < 0) { + ch_set_error(error, cb, ud); + return -1; + } + + return 0; +} + + + +static int +add_data_uncomp(struct zip *za, zip_source_callback cb, void *ud, + struct zip_stat *st, FILE *ft) +{ + char b1[BUFSIZE], b2[BUFSIZE]; + int end, flush, ret; + ssize_t n; + size_t n2; + z_stream zstr; + int mem_level; + + st->comp_method = ZIP_CM_DEFLATE; + st->comp_size = st->size = 0; + st->crc = crc32(0, NULL, 0); + + zstr.zalloc = Z_NULL; + zstr.zfree = Z_NULL; + zstr.opaque = NULL; + zstr.avail_in = 0; + zstr.avail_out = 0; + + if (zip_get_archive_flag(za, ZIP_AFL_TORRENT, 0)) + mem_level = TORRENT_MEM_LEVEL; + else + mem_level = MAX_MEM_LEVEL; + + /* -MAX_WBITS: undocumented feature of zlib to _not_ write a zlib header */ + deflateInit2(&zstr, Z_BEST_COMPRESSION, Z_DEFLATED, -MAX_WBITS, mem_level, + Z_DEFAULT_STRATEGY); + + zstr.next_out = (Bytef *)b2; + zstr.avail_out = sizeof(b2); + zstr.avail_in = 0; + + flush = 0; + end = 0; + while (!end) { + if (zstr.avail_in == 0 && !flush) { + if ((n=cb(ud, b1, sizeof(b1), ZIP_SOURCE_READ)) < 0) { + ch_set_error(&za->error, cb, ud); + deflateEnd(&zstr); + return -1; + } + if (n > 0) { + zstr.avail_in = n; + zstr.next_in = (Bytef *)b1; + st->size += n; + st->crc = crc32(st->crc, (Bytef *)b1, n); + } + else + flush = Z_FINISH; + } + + ret = deflate(&zstr, flush); + if (ret != Z_OK && ret != Z_STREAM_END) { + _zip_error_set(&za->error, ZIP_ER_ZLIB, ret); + return -1; + } + + if (zstr.avail_out != sizeof(b2)) { + n2 = sizeof(b2) - zstr.avail_out; + + if (fwrite(b2, 1, n2, ft) != n2) { + _zip_error_set(&za->error, ZIP_ER_WRITE, errno); + return -1; + } + + zstr.next_out = (Bytef *)b2; + zstr.avail_out = sizeof(b2); + st->comp_size += n2; + } + + if (ret == Z_STREAM_END) { + deflateEnd(&zstr); + end = 1; + } + } + + return 0; +} + + + +static void +ch_set_error(struct zip_error *error, zip_source_callback cb, void *ud) +{ + int e[2]; + + if ((cb(ud, e, sizeof(e), ZIP_SOURCE_ERROR)) < (ssize_t)sizeof(e)) { + error->zip_err = ZIP_ER_INTERNAL; + error->sys_err = 0; + } + else { + error->zip_err = e[0]; + error->sys_err = e[1]; + } +} + + + +static int +copy_data(FILE *fs, myoff_t len, FILE *ft, struct zip_error *error) +{ + char buf[BUFSIZE]; + int n, nn; + + if (len == 0) + return 0; + + while (len > 0) { + nn = len > sizeof(buf) ? sizeof(buf) : len; + if ((n=fread(buf, 1, nn, fs)) < 0) { + _zip_error_set(error, ZIP_ER_READ, errno); + return -1; + } + else if (n == 0) { + _zip_error_set(error, ZIP_ER_EOF, 0); + return -1; + } + + if (fwrite(buf, 1, n, ft) != (size_t)n) { + _zip_error_set(error, ZIP_ER_WRITE, errno); + return -1; + } + + len -= n; + } + + return 0; +} + + + +static int +write_cdir(struct zip *za, struct zip_cdir *cd, FILE *out) +{ + myoff_t offset; + uLong crc; + char buf[TORRENT_CRC_LEN+1]; + + if (_zip_cdir_write(cd, out, &za->error) < 0) + return -1; + + if (zip_get_archive_flag(za, ZIP_AFL_TORRENT, 0) == 0) + return 0; + + + /* fix up torrentzip comment */ + + offset = ftello(out); + + if (_zip_filerange_crc(out, cd->offset, cd->size, &crc, &za->error) < 0) + return -1; + + snprintf(buf, sizeof(buf), "%08lX", (long)crc); + + if (fseeko(out, offset-TORRENT_CRC_LEN, SEEK_SET) < 0) { + _zip_error_set(&za->error, ZIP_ER_SEEK, errno); + return -1; + } + + if (fwrite(buf, TORRENT_CRC_LEN, 1, out) != 1) { + _zip_error_set(&za->error, ZIP_ER_WRITE, errno); + return -1; + } + + return 0; +} + + + +static int +_zip_cdir_set_comment(struct zip_cdir *dest, struct zip *src) +{ + if (src->ch_comment_len != -1) { + dest->comment = _zip_memdup(src->ch_comment, + src->ch_comment_len, &src->error); + if (dest->comment == NULL) + return -1; + dest->comment_len = src->ch_comment_len; + } else { + if (src->cdir && src->cdir->comment) { + dest->comment = _zip_memdup(src->cdir->comment, + src->cdir->comment_len, &src->error); + if (dest->comment == NULL) + return -1; + dest->comment_len = src->cdir->comment_len; + } + } + + return 0; +} + + + +static int +_zip_changed(struct zip *za, int *survivorsp) +{ + int changed, i, survivors; + + changed = survivors = 0; + + if (za->ch_comment_len != -1 + || za->ch_flags != za->flags) + changed = 1; + + for (i=0; inentry; i++) { + if ((za->entry[i].state != ZIP_ST_UNCHANGED) + || (za->entry[i].ch_comment_len != -1)) + changed = 1; + if (za->entry[i].state != ZIP_ST_DELETED) + survivors++; + } + + *survivorsp = survivors; + + return changed; +} + + + +static char * +_zip_create_temp_output(struct zip *za, FILE **outp) +{ + char *temp; + int tfd; + FILE *tfp; + + if ((temp=(char *)malloc(strlen(za->zn)+8)) == NULL) { + _zip_error_set(&za->error, ZIP_ER_MEMORY, 0); + return NULL; + } + + sprintf(temp, "%s.XXXXXX", za->zn); + + if ((tfd=mkstemp(temp)) == -1) { + _zip_error_set(&za->error, ZIP_ER_TMPOPEN, errno); + free(temp); + return NULL; + } + + if ((tfp=fdopen(tfd, "r+b")) == NULL) { + _zip_error_set(&za->error, ZIP_ER_TMPOPEN, errno); + close(tfd); + remove(temp); + free(temp); + return NULL; + } + + *outp = tfp; + return temp; +} + + + +static int +_zip_torrentzip_cmp(const void *a, const void *b) +{ + return strcasecmp(((const struct filelist *)a)->name, + ((const struct filelist *)b)->name); +} + + + +ZIP_EXTERN int +zip_add_dir(struct zip *za, const char *name) +{ + int len, ret; + char *s; + struct zip_source *source; + + if (name == NULL) { + _zip_error_set(&za->error, ZIP_ER_INVAL, 0); + return -1; + } + + s = NULL; + len = strlen(name); + + if (name[len-1] != '/') { + if ((s=(char *)malloc(len+2)) == NULL) { + _zip_error_set(&za->error, ZIP_ER_MEMORY, 0); + return -1; + } + strcpy(s, name); + s[len] = '/'; + s[len+1] = '\0'; + } + + if ((source=zip_source_buffer(za, NULL, 0, 0)) == NULL) { + free(s); + return -1; + } + + ret = _zip_replace(za, -1, s ? s : name, source); + + free(s); + if (ret < 0) + zip_source_free(source); + + return ret; +} + + +ZIP_EXTERN int +zip_error_to_str(char *buf, size_t len, int ze, int se) +{ + const char *zs, *ss; + + if (ze < 0 || ze >= _zip_nerr_str) + return snprintf(buf, len, "Unknown error %d", ze); + + zs = _zip_err_str[ze]; + + switch (_zip_err_type[ze]) { + case ZIP_ET_SYS: + ss = strerror(se); + break; + + case ZIP_ET_ZLIB: + ss = zError(se); + break; + + default: + ss = NULL; + } + + return snprintf(buf, len, "%s%s%s", + zs, (ss ? ": " : ""), (ss ? ss : "")); +} + + +ZIP_EXTERN void +zip_file_error_clear(struct zip_file *zf) +{ + _zip_error_clear(&zf->error); +} + + +ZIP_EXTERN int +zip_fclose(struct zip_file *zf) +{ + int i, ret; + + if (zf->zstr) + inflateEnd(zf->zstr); + free(zf->buffer); + free(zf->zstr); + + for (i=0; iza->nfile; i++) { + if (zf->za->file[i] == zf) { + zf->za->file[i] = zf->za->file[zf->za->nfile-1]; + zf->za->nfile--; + break; + } + } + + ret = 0; + if (zf->error.zip_err) + ret = zf->error.zip_err; + else if ((zf->flags & ZIP_ZF_CRC) && (zf->flags & ZIP_ZF_EOF)) { + /* if EOF, compare CRC */ + if (zf->crc_orig != zf->crc) + ret = ZIP_ER_CRC; + } + + free(zf); + return ret; +} + + +int +_zip_filerange_crc(FILE *fp, myoff_t start, myoff_t len, uLong *crcp, + struct zip_error *errp) +{ + Bytef buf[BUFSIZE]; + size_t n; + + *crcp = crc32(0L, Z_NULL, 0); + + if (fseeko(fp, start, SEEK_SET) != 0) { + _zip_error_set(errp, ZIP_ER_SEEK, errno); + return -1; + } + + while (len > 0) { + n = len > BUFSIZE ? BUFSIZE : len; + if ((n=fread(buf, 1, n, fp)) <= 0) { + _zip_error_set(errp, ZIP_ER_READ, errno); + return -1; + } + + *crcp = crc32(*crcp, buf, n); + + len-= n; + } + + return 0; +} + + +ZIP_EXTERN const char * +zip_file_strerror(struct zip_file *zf) +{ + return _zip_error_strerror(&zf->error); +} + + +/* _zip_file_get_offset(za, ze): + Returns the offset of the file data for entry ze. + + On error, fills in za->error and returns 0. +*/ + +unsigned int +_zip_file_get_offset(struct zip *za, int idx) +{ + struct zip_dirent de; + unsigned int offset; + + offset = za->cdir->entry[idx].offset; + + if (fseeko(za->zp, offset, SEEK_SET) != 0) { + _zip_error_set(&za->error, ZIP_ER_SEEK, errno); + return 0; + } + + if (_zip_dirent_read(&de, za->zp, NULL, 0, 1, &za->error) != 0) + return 0; + + offset += LENTRYSIZE + de.filename_len + de.extrafield_len; + + _zip_dirent_finalize(&de); + + return offset; +} + + +ZIP_EXTERN void +zip_file_error_get(struct zip_file *zf, int *zep, int *sep) +{ + _zip_error_get(&zf->error, zep, sep); +} + + +static struct zip_file *_zip_file_new(struct zip *za); + + + +ZIP_EXTERN struct zip_file * +zip_fopen_index(struct zip *za, int fileno, int flags) +{ + int len, ret; + int zfflags; + struct zip_file *zf; + + if ((fileno < 0) || (fileno >= za->nentry)) { + _zip_error_set(&za->error, ZIP_ER_INVAL, 0); + return NULL; + } + + if ((flags & ZIP_FL_UNCHANGED) == 0 + && ZIP_ENTRY_DATA_CHANGED(za->entry+fileno)) { + _zip_error_set(&za->error, ZIP_ER_CHANGED, 0); + return NULL; + } + + if (fileno >= za->cdir->nentry) { + _zip_error_set(&za->error, ZIP_ER_INVAL, 0); + return NULL; + } + + zfflags = 0; + switch (za->cdir->entry[fileno].comp_method) { + case ZIP_CM_STORE: + zfflags |= ZIP_ZF_CRC; + break; + + case ZIP_CM_DEFLATE: + if ((flags & ZIP_FL_COMPRESSED) == 0) + zfflags |= ZIP_ZF_CRC | ZIP_ZF_DECOMP; + break; + default: + if ((flags & ZIP_FL_COMPRESSED) == 0) { + _zip_error_set(&za->error, ZIP_ER_COMPNOTSUPP, 0); + return NULL; + } + break; + } + + zf = _zip_file_new(za); + + zf->flags = zfflags; + /* zf->name = za->cdir->entry[fileno].filename; */ + zf->method = za->cdir->entry[fileno].comp_method; + zf->bytes_left = za->cdir->entry[fileno].uncomp_size; + zf->cbytes_left = za->cdir->entry[fileno].comp_size; + zf->crc_orig = za->cdir->entry[fileno].crc; + + if ((zf->fpos=_zip_file_get_offset(za, fileno)) == 0) { + zip_fclose(zf); + return NULL; + } + + if ((zf->flags & ZIP_ZF_DECOMP) == 0) + zf->bytes_left = zf->cbytes_left; + else { + if ((zf->buffer=(char *)malloc(BUFSIZE)) == NULL) { + _zip_error_set(&za->error, ZIP_ER_MEMORY, 0); + zip_fclose(zf); + return NULL; + } + + len = _zip_file_fillbuf(zf->buffer, BUFSIZE, zf); + if (len <= 0) { + _zip_error_copy(&za->error, &zf->error); + zip_fclose(zf); + return NULL; + } + + if ((zf->zstr = (z_stream *)malloc(sizeof(z_stream))) == NULL) { + _zip_error_set(&za->error, ZIP_ER_MEMORY, 0); + zip_fclose(zf); + return NULL; + } + zf->zstr->zalloc = Z_NULL; + zf->zstr->zfree = Z_NULL; + zf->zstr->opaque = NULL; + zf->zstr->next_in = (Bytef *)zf->buffer; + zf->zstr->avail_in = len; + + /* negative value to tell zlib that there is no header */ + if ((ret=inflateInit2(zf->zstr, -MAX_WBITS)) != Z_OK) { + _zip_error_set(&za->error, ZIP_ER_ZLIB, ret); + zip_fclose(zf); + return NULL; + } + } + + return zf; +} + + + +int +_zip_file_fillbuf(void *buf, size_t buflen, struct zip_file *zf) +{ + int i, j; + + if (zf->error.zip_err != ZIP_ER_OK) + return -1; + + if ((zf->flags & ZIP_ZF_EOF) || zf->cbytes_left <= 0 || buflen <= 0) + return 0; + + if (fseeko(zf->za->zp, zf->fpos, SEEK_SET) < 0) { + _zip_error_set(&zf->error, ZIP_ER_SEEK, errno); + return -1; + } + if (buflen < zf->cbytes_left) + i = buflen; + else + i = zf->cbytes_left; + + j = fread(buf, 1, i, zf->za->zp); + if (j == 0) { + _zip_error_set(&zf->error, ZIP_ER_EOF, 0); + j = -1; + } + else if (j < 0) + _zip_error_set(&zf->error, ZIP_ER_READ, errno); + else { + zf->fpos += j; + zf->cbytes_left -= j; + } + + return j; +} + + + +static struct zip_file * +_zip_file_new(struct zip *za) +{ + struct zip_file *zf, **file; + int n; + + if ((zf=(struct zip_file *)malloc(sizeof(struct zip_file))) == NULL) { + _zip_error_set(&za->error, ZIP_ER_MEMORY, 0); + return NULL; + } + + if (za->nfile >= za->nfile_alloc-1) { + n = za->nfile_alloc + 10; + file = (struct zip_file **)realloc(za->file, + n*sizeof(struct zip_file *)); + if (file == NULL) { + _zip_error_set(&za->error, ZIP_ER_MEMORY, 0); + free(zf); + return NULL; + } + za->nfile_alloc = n; + za->file = file; + } + + za->file[za->nfile++] = zf; + + zf->za = za; + _zip_error_init(&zf->error); + zf->flags = 0; + zf->crc = crc32(0L, Z_NULL, 0); + zf->crc_orig = 0; + zf->method = -1; + zf->bytes_left = zf->cbytes_left = 0; + zf->fpos = 0; + zf->buffer = NULL; + zf->zstr = NULL; + + return zf; +} + + +ZIP_EXTERN struct zip_file * +zip_fopen(struct zip *za, const char *fname, int flags) +{ + int idx; + + if ((idx=zip_name_locate(za, fname, flags)) < 0) + return NULL; + + return zip_fopen_index(za, idx, flags); +} + + +ZIP_EXTERN int +zip_set_file_comment(struct zip *za, int idx, const char *comment, int len) +{ + char *tmpcom; + + if (idx < 0 || idx >= za->nentry + || len < 0 || len > MAXCOMLEN + || (len > 0 && comment == NULL)) { + _zip_error_set(&za->error, ZIP_ER_INVAL, 0); + return -1; + } + + if (len > 0) { + if ((tmpcom=(char *)_zip_memdup(comment, len, &za->error)) == NULL) + return -1; + } + else + tmpcom = NULL; + + free(za->entry[idx].ch_comment); + za->entry[idx].ch_comment = tmpcom; + za->entry[idx].ch_comment_len = len; + + return 0; +} + + +ZIP_EXTERN struct zip_source * +zip_source_file(struct zip *za, const char *fname, myoff_t start, myoff_t len) +{ + if (za == NULL) + return NULL; + + if (fname == NULL || start < 0 || len < -1) { + _zip_error_set(&za->error, ZIP_ER_INVAL, 0); + return NULL; + } + + return _zip_source_file_or_p(za, fname, NULL, start, len); +} + + +struct read_data { + const char *buf, *data, *end; + time_t mtime; + int freep; +}; + +static ssize_t read_data(void *state, void *data, size_t len, + enum zip_source_cmd cmd); + + + +ZIP_EXTERN struct zip_source * +zip_source_buffer(struct zip *za, const void *data, myoff_t len, int freep) +{ + struct read_data *f; + struct zip_source *zs; + + if (za == NULL) + return NULL; + + if (len < 0 || (data == NULL && len > 0)) { + _zip_error_set(&za->error, ZIP_ER_INVAL, 0); + return NULL; + } + + if ((f=(struct read_data *)malloc(sizeof(*f))) == NULL) { + _zip_error_set(&za->error, ZIP_ER_MEMORY, 0); + return NULL; + } + + f->data = (const char *)data; + f->end = ((const char *)data)+len; + f->freep = freep; + f->mtime = time(NULL); + + if ((zs=zip_source_function(za, read_data, f)) == NULL) { + free(f); + return NULL; + } + + return zs; +} + + + +static ssize_t +read_data(void *state, void *data, size_t len, enum zip_source_cmd cmd) +{ + struct read_data *z; + char *buf; + size_t n; + + z = (struct read_data *)state; + buf = (char *)data; + + switch (cmd) { + case ZIP_SOURCE_OPEN: + z->buf = z->data; + return 0; + + case ZIP_SOURCE_READ: + n = z->end - z->buf; + if (n > len) + n = len; + + if (n) { + memcpy(buf, z->buf, n); + z->buf += n; + } + + return n; + + case ZIP_SOURCE_CLOSE: + return 0; + + case ZIP_SOURCE_STAT: + { + struct zip_stat *st; + + if (len < sizeof(*st)) + return -1; + + st = (struct zip_stat *)data; + + zip_stat_init(st); + st->mtime = z->mtime; + st->size = z->end - z->data; + + return sizeof(*st); + } + + case ZIP_SOURCE_ERROR: + { + int *e; + + if (len < sizeof(int)*2) + return -1; + + e = (int *)data; + e[0] = e[1] = 0; + } + return sizeof(int)*2; + + case ZIP_SOURCE_FREE: + if (z->freep) { + free((void *)z->data); + z->data = NULL; + } + free(z); + return 0; + + default: + ; + } + + return -1; +} + + +int +_zip_set_name(struct zip *za, int idx, const char *name) +{ + char *s; + int i; + + if (idx < 0 || idx >= za->nentry || name == NULL) { + _zip_error_set(&za->error, ZIP_ER_INVAL, 0); + return -1; + } + + if ((i=_zip_name_locate(za, name, 0, NULL)) != -1 && i != idx) { + _zip_error_set(&za->error, ZIP_ER_EXISTS, 0); + return -1; + } + + /* no effective name change */ + if (i == idx) + return 0; + + if ((s=strdup(name)) == NULL) { + _zip_error_set(&za->error, ZIP_ER_MEMORY, 0); + return -1; + } + + if (za->entry[idx].state == ZIP_ST_UNCHANGED) + za->entry[idx].state = ZIP_ST_RENAMED; + + free(za->entry[idx].ch_filename); + za->entry[idx].ch_filename = s; + + return 0; +} + + +ZIP_EXTERN int +zip_set_archive_flag(struct zip *za, int flag, int value) +{ + if (value) + za->ch_flags |= flag; + else + za->ch_flags &= ~flag; + + return 0; +} + + +void +_zip_unchange_data(struct zip_entry *ze) +{ + if (ze->source) { + (void)ze->source->f(ze->source->ud, NULL, 0, ZIP_SOURCE_FREE); + free(ze->source); + ze->source = NULL; + } + + ze->state = ze->ch_filename ? ZIP_ST_RENAMED : ZIP_ST_UNCHANGED; +} + + +ZIP_EXTERN int +zip_unchange_archive(struct zip *za) +{ + free(za->ch_comment); + za->ch_comment = NULL; + za->ch_comment_len = -1; + + za->ch_flags = za->flags; + + return 0; +} + +ZIP_EXTERN int +zip_unchange(struct zip *za, int idx) +{ + return _zip_unchange(za, idx, 0); +} + + + +int +_zip_unchange(struct zip *za, int idx, int allow_duplicates) +{ + int i; + + if (idx < 0 || idx >= za->nentry) { + _zip_error_set(&za->error, ZIP_ER_INVAL, 0); + return -1; + } + + if (za->entry[idx].ch_filename) { + if (!allow_duplicates) { + i = _zip_name_locate(za, + _zip_get_name(za, idx, ZIP_FL_UNCHANGED, NULL), + 0, NULL); + if (i != -1 && i != idx) { + _zip_error_set(&za->error, ZIP_ER_EXISTS, 0); + return -1; + } + } + + free(za->entry[idx].ch_filename); + za->entry[idx].ch_filename = NULL; + } + + free(za->entry[idx].ch_comment); + za->entry[idx].ch_comment = NULL; + za->entry[idx].ch_comment_len = -1; + + _zip_unchange_data(za->entry+idx); + + return 0; +} + +ZIP_EXTERN int +zip_unchange_all(struct zip *za) +{ + int ret, i; + + ret = 0; + for (i=0; inentry; i++) + ret |= _zip_unchange(za, i, 1); + + ret |= zip_unchange_archive(za); + + return ret; +} + + +ZIP_EXTERN int +zip_set_archive_comment(struct zip *za, const char *comment, int len) +{ + char *tmpcom; + + if (len < 0 || len > MAXCOMLEN + || (len > 0 && comment == NULL)) { + _zip_error_set(&za->error, ZIP_ER_INVAL, 0); + return -1; + } + + if (len > 0) { + if ((tmpcom=(char *)_zip_memdup(comment, len, &za->error)) == NULL) + return -1; + } + else + tmpcom = NULL; + + free(za->ch_comment); + za->ch_comment = tmpcom; + za->ch_comment_len = len; + + return 0; +} + + +ZIP_EXTERN int +zip_replace(struct zip *za, int idx, struct zip_source *source) +{ + if (idx < 0 || idx >= za->nentry || source == NULL) { + _zip_error_set(&za->error, ZIP_ER_INVAL, 0); + return -1; + } + + if (_zip_replace(za, idx, NULL, source) == -1) + return -1; + + return 0; +} + + + + +int +_zip_replace(struct zip *za, int idx, const char *name, + struct zip_source *source) +{ + if (idx == -1) { + if (_zip_entry_new(za) == NULL) + return -1; + + idx = za->nentry - 1; + } + + _zip_unchange_data(za->entry+idx); + + if (name && _zip_set_name(za, idx, name) != 0) + return -1; + + za->entry[idx].state = ((za->cdir == NULL || idx >= za->cdir->nentry) + ? ZIP_ST_ADDED : ZIP_ST_REPLACED); + za->entry[idx].source = source; + + return idx; +} + + +ZIP_EXTERN int +zip_rename(struct zip *za, int idx, const char *name) +{ + const char *old_name; + int old_is_dir, new_is_dir; + + if (idx >= za->nentry || idx < 0 || name[0] == '\0') { + _zip_error_set(&za->error, ZIP_ER_INVAL, 0); + return -1; + } + + if ((old_name=zip_get_name(za, idx, 0)) == NULL) + return -1; + + new_is_dir = (name[strlen(name)-1] == '/'); + old_is_dir = (old_name[strlen(old_name)-1] == '/'); + + if (new_is_dir != old_is_dir) { + _zip_error_set(&za->error, ZIP_ER_INVAL, 0); + return -1; + } + + return _zip_set_name(za, idx, name); +} + +#include +#include +#include +#include +#include +#include + +static void set_error(int *, struct zip_error *, int); +static struct zip *_zip_allocate_new(const char *, int *); +static int _zip_checkcons(FILE *, struct zip_cdir *, struct zip_error *); +static void _zip_check_torrentzip(struct zip *); +static struct zip_cdir *_zip_find_central_dir(FILE *, int, int *, myoff_t); +static int _zip_file_exists(const char *, int, int *); +static int _zip_headercomp(struct zip_dirent *, int, + struct zip_dirent *, int); +static unsigned char *_zip_memmem(const unsigned char *, int, + const unsigned char *, int); +static struct zip_cdir *_zip_readcdir(FILE *, unsigned char *, unsigned char *, + int, int, struct zip_error *); + + + +ZIP_EXTERN struct zip * +zip_open(const char *fn, int flags, int *zep) +{ + FILE *fp; + struct zip *za; + struct zip_cdir *cdir; + int i; + myoff_t len; + + switch (_zip_file_exists(fn, flags, zep)) { + case -1: + return NULL; + case 0: + return _zip_allocate_new(fn, zep); + default: + break; + } + + if ((fp=fopen(fn, "rb")) == NULL) { + set_error(zep, NULL, ZIP_ER_OPEN); + return NULL; + } + + fseeko(fp, 0, SEEK_END); + len = ftello(fp); + + /* treat empty files as empty archives */ + if (len == 0) { + if ((za=_zip_allocate_new(fn, zep)) == NULL) + fclose(fp); + else + za->zp = fp; + return za; + } + + cdir = _zip_find_central_dir(fp, flags, zep, len); + if (cdir == NULL) { + fclose(fp); + return NULL; + } + + if ((za=_zip_allocate_new(fn, zep)) == NULL) { + _zip_cdir_free(cdir); + fclose(fp); + return NULL; + } + + za->cdir = cdir; + za->zp = fp; + + if ((za->entry=(struct zip_entry *)malloc(sizeof(*(za->entry)) + * cdir->nentry)) == NULL) { + set_error(zep, NULL, ZIP_ER_MEMORY); + _zip_free(za); + return NULL; + } + for (i=0; inentry; i++) + _zip_entry_new(za); + + _zip_check_torrentzip(za); + za->ch_flags = za->flags; + + return za; +} + + + +static void +set_error(int *zep, struct zip_error *err, int ze) +{ + int se; + + if (err) { + _zip_error_get(err, &ze, &se); + if (zip_error_get_sys_type(ze) == ZIP_ET_SYS) + errno = se; + } + + if (zep) + *zep = ze; +} + + + +/* _zip_readcdir: + tries to find a valid end-of-central-directory at the beginning of + buf, and then the corresponding central directory entries. + Returns a struct zip_cdir which contains the central directory + entries, or NULL if unsuccessful. */ + +static struct zip_cdir * +_zip_readcdir(FILE *fp, unsigned char *buf, unsigned char *eocd, int buflen, + int flags, struct zip_error *error) +{ + struct zip_cdir *cd; + unsigned char *cdp, **bufp; + int i, comlen, nentry; + + comlen = buf + buflen - eocd - EOCDLEN; + if (comlen < 0) { + /* not enough bytes left for comment */ + _zip_error_set(error, ZIP_ER_NOZIP, 0); + return NULL; + } + + /* check for end-of-central-dir magic */ + if (memcmp(eocd, EOCD_MAGIC, 4) != 0) { + _zip_error_set(error, ZIP_ER_NOZIP, 0); + return NULL; + } + + if (memcmp(eocd+4, "\0\0\0\0", 4) != 0) { + _zip_error_set(error, ZIP_ER_MULTIDISK, 0); + return NULL; + } + + cdp = eocd + 8; + /* number of cdir-entries on this disk */ + i = _zip_read2(&cdp); + /* number of cdir-entries */ + nentry = _zip_read2(&cdp); + + if ((cd=_zip_cdir_new(nentry, error)) == NULL) + return NULL; + + cd->size = _zip_read4(&cdp); + cd->offset = _zip_read4(&cdp); + cd->comment = NULL; + cd->comment_len = _zip_read2(&cdp); + + if ((comlen < cd->comment_len) || (cd->nentry != i)) { + _zip_error_set(error, ZIP_ER_NOZIP, 0); + free(cd); + return NULL; + } + if ((flags & ZIP_CHECKCONS) && comlen != cd->comment_len) { + _zip_error_set(error, ZIP_ER_INCONS, 0); + free(cd); + return NULL; + } + + if (cd->comment_len) { + if ((cd->comment=(char *)_zip_memdup(eocd+EOCDLEN, + cd->comment_len, error)) + == NULL) { + free(cd); + return NULL; + } + } + + cdp = eocd; + if (cd->size < (unsigned int)(eocd-buf)) { + /* if buffer already read in, use it */ + cdp = eocd - cd->size; + bufp = &cdp; + } + else { + /* go to start of cdir and read it entry by entry */ + bufp = NULL; + clearerr(fp); + fseeko(fp, cd->offset, SEEK_SET); + /* possible consistency check: cd->offset = + len-(cd->size+cd->comment_len+EOCDLEN) ? */ + if (ferror(fp) || ((unsigned long)ftello(fp) != cd->offset)) { + /* seek error or offset of cdir wrong */ + if (ferror(fp)) + _zip_error_set(error, ZIP_ER_SEEK, errno); + else + _zip_error_set(error, ZIP_ER_NOZIP, 0); + free(cd); + return NULL; + } + } + + for (i=0; inentry; i++) { + if ((_zip_dirent_read(cd->entry+i, fp, bufp, eocd-cdp, 0, + error)) < 0) { + cd->nentry = i; + _zip_cdir_free(cd); + return NULL; + } + } + + return cd; +} + + + +/* _zip_checkcons: + Checks the consistency of the central directory by comparing central + directory entries with local headers and checking for plausible + file and header offsets. Returns -1 if not plausible, else the + difference between the lowest and the highest fileposition reached */ + +static int +_zip_checkcons(FILE *fp, struct zip_cdir *cd, struct zip_error *error) +{ + int i; + unsigned int min, max, j; + struct zip_dirent temp; + + if (cd->nentry) { + max = cd->entry[0].offset; + min = cd->entry[0].offset; + } + else + min = max = 0; + + for (i=0; inentry; i++) { + if (cd->entry[i].offset < min) + min = cd->entry[i].offset; + if (min > cd->offset) { + _zip_error_set(error, ZIP_ER_NOZIP, 0); + return -1; + } + + j = cd->entry[i].offset + cd->entry[i].comp_size + + cd->entry[i].filename_len + LENTRYSIZE; + if (j > max) + max = j; + if (max > cd->offset) { + _zip_error_set(error, ZIP_ER_NOZIP, 0); + return -1; + } + + if (fseeko(fp, cd->entry[i].offset, SEEK_SET) != 0) { + _zip_error_set(error, ZIP_ER_SEEK, 0); + return -1; + } + + if (_zip_dirent_read(&temp, fp, NULL, 0, 1, error) == -1) + return -1; + + if (_zip_headercomp(cd->entry+i, 0, &temp, 1) != 0) { + _zip_error_set(error, ZIP_ER_INCONS, 0); + _zip_dirent_finalize(&temp); + return -1; + } + _zip_dirent_finalize(&temp); + } + + return max - min; +} + + + +/* _zip_check_torrentzip: + check wether ZA has a valid TORRENTZIP comment, i.e. is torrentzipped */ + +static void +_zip_check_torrentzip(struct zip *za) +{ + uLong crc_got, crc_should; + char buf[8+1]; + char *end; + + if (za->zp == NULL || za->cdir == NULL) + return; + + if (za->cdir->comment_len != TORRENT_SIG_LEN+8 + || strncmp(za->cdir->comment, TORRENT_SIG, TORRENT_SIG_LEN) != 0) + return; + + memcpy(buf, za->cdir->comment+TORRENT_SIG_LEN, 8); + buf[8] = '\0'; + errno = 0; + crc_should = strtoul(buf, &end, 16); + if ((crc_should == UINT_MAX && errno != 0) || (end && *end)) + return; + + if (_zip_filerange_crc(za->zp, za->cdir->offset, za->cdir->size, + &crc_got, NULL) < 0) + return; + + if (crc_got == crc_should) + za->flags |= ZIP_AFL_TORRENT; +} + + + + +/* _zip_headercomp: + compares two headers h1 and h2; if they are local headers, set + local1p or local2p respectively to 1, else 0. Return 0 if they + are identical, -1 if not. */ + +static int +_zip_headercomp(struct zip_dirent *h1, int local1p, struct zip_dirent *h2, + int local2p) +{ + if ((h1->version_needed != h2->version_needed) +#if 0 + /* some zip-files have different values in local + and global headers for the bitflags */ + || (h1->bitflags != h2->bitflags) +#endif + || (h1->comp_method != h2->comp_method) + || (h1->last_mod != h2->last_mod) + || (h1->filename_len != h2->filename_len) + || !h1->filename || !h2->filename + || strcmp(h1->filename, h2->filename)) + return -1; + + /* check that CRC and sizes are zero if data descriptor is used */ + if ((h1->bitflags & ZIP_GPBF_DATA_DESCRIPTOR) && local1p + && (h1->crc != 0 + || h1->comp_size != 0 + || h1->uncomp_size != 0)) + return -1; + if ((h2->bitflags & ZIP_GPBF_DATA_DESCRIPTOR) && local2p + && (h2->crc != 0 + || h2->comp_size != 0 + || h2->uncomp_size != 0)) + return -1; + + /* check that CRC and sizes are equal if no data descriptor is used */ + if (((h1->bitflags & ZIP_GPBF_DATA_DESCRIPTOR) == 0 || local1p == 0) + && ((h2->bitflags & ZIP_GPBF_DATA_DESCRIPTOR) == 0 || local2p == 0)) { + if ((h1->crc != h2->crc) + || (h1->comp_size != h2->comp_size) + || (h1->uncomp_size != h2->uncomp_size)) + return -1; + } + + if ((local1p == local2p) + && ((h1->extrafield_len != h2->extrafield_len) + || (h1->extrafield_len && h2->extrafield + && memcmp(h1->extrafield, h2->extrafield, + h1->extrafield_len)))) + return -1; + + /* if either is local, nothing more to check */ + if (local1p || local2p) + return 0; + + if ((h1->version_madeby != h2->version_madeby) + || (h1->disk_number != h2->disk_number) + || (h1->int_attrib != h2->int_attrib) + || (h1->ext_attrib != h2->ext_attrib) + || (h1->offset != h2->offset) + || (h1->comment_len != h2->comment_len) + || (h1->comment_len && h2->comment + && memcmp(h1->comment, h2->comment, h1->comment_len))) + return -1; + + return 0; +} + + + +static struct zip * +_zip_allocate_new(const char *fn, int *zep) +{ + struct zip *za; + struct zip_error error; + + if ((za=_zip_new(&error)) == NULL) { + set_error(zep, &error, 0); + return NULL; + } + + za->zn = strdup(fn); + if (!za->zn) { + _zip_free(za); + set_error(zep, NULL, ZIP_ER_MEMORY); + return NULL; + } + return za; +} + + + +static int +_zip_file_exists(const char *fn, int flags, int *zep) +{ + struct stat st; + + if (fn == NULL) { + set_error(zep, NULL, ZIP_ER_INVAL); + return -1; + } + + if (stat(fn, &st) != 0) { + if (flags & ZIP_CREATE) + return 0; + else { + set_error(zep, NULL, ZIP_ER_OPEN); + return -1; + } + } + else if ((flags & ZIP_EXCL)) { + set_error(zep, NULL, ZIP_ER_EXISTS); + return -1; + } + /* ZIP_CREATE gets ignored if file exists and not ZIP_EXCL, + just like open() */ + + return 1; +} + + + +static struct zip_cdir * +_zip_find_central_dir(FILE *fp, int flags, int *zep, myoff_t len) +{ + struct zip_cdir *cdir, *cdirnew; + unsigned char *buf, *match; + int a, best, buflen, i; + struct zip_error zerr; + + i = fseeko(fp, -(len < CDBUFSIZE ? len : CDBUFSIZE), SEEK_END); + if (i == -1 && errno != EFBIG) { + /* seek before start of file on my machine */ + set_error(zep, NULL, ZIP_ER_SEEK); + return NULL; + } + + /* 64k is too much for stack */ + if ((buf=(unsigned char *)malloc(CDBUFSIZE)) == NULL) { + set_error(zep, NULL, ZIP_ER_MEMORY); + return NULL; + } + + clearerr(fp); + buflen = fread(buf, 1, CDBUFSIZE, fp); + + if (ferror(fp)) { + set_error(zep, NULL, ZIP_ER_READ); + free(buf); + return NULL; + } + + best = -1; + cdir = NULL; + match = buf; + _zip_error_set(&zerr, ZIP_ER_NOZIP, 0); + + while ((match=_zip_memmem(match, buflen-(match-buf)-18, + (const unsigned char *)EOCD_MAGIC, 4))!=NULL) { + /* found match -- check, if good */ + /* to avoid finding the same match all over again */ + match++; + if ((cdirnew=_zip_readcdir(fp, buf, match-1, buflen, flags, + &zerr)) == NULL) + continue; + + if (cdir) { + if (best <= 0) + best = _zip_checkcons(fp, cdir, &zerr); + a = _zip_checkcons(fp, cdirnew, &zerr); + if (best < a) { + _zip_cdir_free(cdir); + cdir = cdirnew; + best = a; + } + else + _zip_cdir_free(cdirnew); + } + else { + cdir = cdirnew; + if (flags & ZIP_CHECKCONS) + best = _zip_checkcons(fp, cdir, &zerr); + else + best = 0; + } + cdirnew = NULL; + } + + free(buf); + + if (best < 0) { + set_error(zep, &zerr, 0); + _zip_cdir_free(cdir); + return NULL; + } + + return cdir; +} + + + +static unsigned char * +_zip_memmem(const unsigned char *big, int biglen, const unsigned char *little, + int littlelen) +{ + const unsigned char *p; + + if ((biglen < littlelen) || (littlelen == 0)) + return NULL; + p = big-1; + while ((p=(const unsigned char *) + memchr(p+1, little[0], (size_t)(big-(p+1)+biglen-littlelen+1))) + != NULL) { + if (memcmp(p+1, little+1, littlelen-1)==0) + return (unsigned char *)p; + } + + return NULL; +} + + +/* _zip_new: + creates a new zipfile struct, and sets the contents to zero; returns + the new struct. */ + +struct zip * +_zip_new(struct zip_error *error) +{ + struct zip *za; + + za = (struct zip *)malloc(sizeof(struct zip)); + if (!za) { + _zip_error_set(error, ZIP_ER_MEMORY, 0); + return NULL; + } + + za->zn = NULL; + za->zp = NULL; + _zip_error_init(&za->error); + za->cdir = NULL; + za->ch_comment = NULL; + za->ch_comment_len = -1; + za->nentry = za->nentry_alloc = 0; + za->entry = NULL; + za->nfile = za->nfile_alloc = 0; + za->file = NULL; + za->flags = za->ch_flags = 0; + + return za; +} + + +void * +_zip_memdup(const void *mem, size_t len, struct zip_error *error) +{ + void *ret; + + ret = malloc(len); + if (!ret) { + _zip_error_set(error, ZIP_ER_MEMORY, 0); + return NULL; + } + + memcpy(ret, mem, len); + + return ret; +} + + +ZIP_EXTERN int +zip_get_num_files(struct zip *za) +{ + if (za == NULL) + return -1; + + return za->nentry; +} + +ZIP_EXTERN const char * +zip_get_name(struct zip *za, int idx, int flags) +{ + return _zip_get_name(za, idx, flags, &za->error); +} + + + +const char * +_zip_get_name(struct zip *za, int idx, int flags, struct zip_error *error) +{ + if (idx < 0 || idx >= za->nentry) { + _zip_error_set(error, ZIP_ER_INVAL, 0); + return NULL; + } + + if ((flags & ZIP_FL_UNCHANGED) == 0) { + if (za->entry[idx].state == ZIP_ST_DELETED) { + _zip_error_set(error, ZIP_ER_DELETED, 0); + return NULL; + } + if (za->entry[idx].ch_filename) + return za->entry[idx].ch_filename; + } + + if (za->cdir == NULL || idx >= za->cdir->nentry) { + _zip_error_set(error, ZIP_ER_INVAL, 0); + return NULL; + } + + return za->cdir->entry[idx].filename; +} + + +ZIP_EXTERN const char * +zip_get_file_comment(struct zip *za, int idx, int *lenp, int flags) +{ + if (idx < 0 || idx >= za->nentry) { + _zip_error_set(&za->error, ZIP_ER_INVAL, 0); + return NULL; + } + + if ((flags & ZIP_FL_UNCHANGED) + || (za->entry[idx].ch_comment_len == -1)) { + if (lenp != NULL) + *lenp = za->cdir->entry[idx].comment_len; + return za->cdir->entry[idx].comment; + } + + if (lenp != NULL) + *lenp = za->entry[idx].ch_comment_len; + return za->entry[idx].ch_comment; +} + + +ZIP_EXTERN int +zip_get_archive_flag(struct zip *za, int flag, int flags) +{ + int fl; + + fl = (flags & ZIP_FL_UNCHANGED) ? za->flags : za->ch_flags; + + return (fl & flag) ? 1 : 0; +} + + +ZIP_EXTERN const char * +zip_get_archive_comment(struct zip *za, int *lenp, int flags) +{ + if ((flags & ZIP_FL_UNCHANGED) + || (za->ch_comment_len == -1)) { + if (za->cdir) { + if (lenp != NULL) + *lenp = za->cdir->comment_len; + return za->cdir->comment; + } + else { + if (lenp != NULL) + *lenp = -1; + return NULL; + } + } + + if (lenp != NULL) + *lenp = za->ch_comment_len; + return za->ch_comment; +} + + +/* _zip_free: + frees the space allocated to a zipfile struct, and closes the + corresponding file. */ + +void +_zip_free(struct zip *za) +{ + int i; + + if (za == NULL) + return; + + if (za->zn) + free(za->zn); + + if (za->zp) + fclose(za->zp); + + _zip_cdir_free(za->cdir); + + if (za->entry) { + for (i=0; inentry; i++) { + _zip_entry_free(za->entry+i); + } + free(za->entry); + } + + for (i=0; infile; i++) { + if (za->file[i]->error.zip_err == ZIP_ER_OK) { + _zip_error_set(&za->file[i]->error, ZIP_ER_ZIPCLOSED, 0); + za->file[i]->za = NULL; + } + } + + free(za->file); + + free(za); + + return; +} + + +ZIP_EXTERN ssize_t +zip_fread(struct zip_file *zf, void *outbuf, size_t toread) +{ + int ret; + size_t out_before, len; + int i; + + if (!zf) + return -1; + + if (zf->error.zip_err != 0) + return -1; + + if ((zf->flags & ZIP_ZF_EOF) || (toread == 0)) + return 0; + + if (zf->bytes_left == 0) { + zf->flags |= ZIP_ZF_EOF; + if (zf->flags & ZIP_ZF_CRC) { + if (zf->crc != zf->crc_orig) { + _zip_error_set(&zf->error, ZIP_ER_CRC, 0); + return -1; + } + } + return 0; + } + + if ((zf->flags & ZIP_ZF_DECOMP) == 0) { + ret = _zip_file_fillbuf(outbuf, toread, zf); + if (ret > 0) { + if (zf->flags & ZIP_ZF_CRC) + zf->crc = crc32(zf->crc, (Bytef *)outbuf, ret); + zf->bytes_left -= ret; + } + return ret; + } + + zf->zstr->next_out = (Bytef *)outbuf; + zf->zstr->avail_out = toread; + out_before = zf->zstr->total_out; + + /* endless loop until something has been accomplished */ + for (;;) { + ret = inflate(zf->zstr, Z_SYNC_FLUSH); + + switch (ret) { + case Z_OK: + case Z_STREAM_END: + /* all ok */ + /* Z_STREAM_END probably won't happen, since we didn't + have a header */ + len = zf->zstr->total_out - out_before; + if (len >= zf->bytes_left || len >= toread) { + if (zf->flags & ZIP_ZF_CRC) + zf->crc = crc32(zf->crc, (Bytef *)outbuf, len); + zf->bytes_left -= len; + return len; + } + break; + + case Z_BUF_ERROR: + if (zf->zstr->avail_in == 0) { + i = _zip_file_fillbuf(zf->buffer, BUFSIZE, zf); + if (i == 0) { + _zip_error_set(&zf->error, ZIP_ER_INCONS, 0); + return -1; + } + else if (i < 0) + return -1; + zf->zstr->next_in = (Bytef *)zf->buffer; + zf->zstr->avail_in = i; + continue; + } + /* fallthrough */ + case Z_NEED_DICT: + case Z_DATA_ERROR: + case Z_STREAM_ERROR: + case Z_MEM_ERROR: + _zip_error_set(&zf->error, ZIP_ER_ZLIB, ret); + return -1; + } + } +} + + +ZIP_EXTERN const char * +zip_strerror(struct zip *za) +{ + return _zip_error_strerror(&za->error); +} + + +ZIP_EXTERN void +zip_stat_init(struct zip_stat *st) +{ + st->name = NULL; + st->index = -1; + st->crc = 0; + st->mtime = (time_t)-1; + st->size = -1; + st->comp_size = -1; + st->comp_method = ZIP_CM_STORE; + st->encryption_method = ZIP_EM_NONE; +} + + +ZIP_EXTERN int +zip_stat_index(struct zip *za, int index, int flags, struct zip_stat *st) +{ + const char *name; + + if (index < 0 || index >= za->nentry) { + _zip_error_set(&za->error, ZIP_ER_INVAL, 0); + return -1; + } + + if ((name=zip_get_name(za, index, flags)) == NULL) + return -1; + + + if ((flags & ZIP_FL_UNCHANGED) == 0 + && ZIP_ENTRY_DATA_CHANGED(za->entry+index)) { + if (za->entry[index].source->f(za->entry[index].source->ud, + st, sizeof(*st), ZIP_SOURCE_STAT) < 0) { + _zip_error_set(&za->error, ZIP_ER_CHANGED, 0); + return -1; + } + } + else { + if (za->cdir == NULL || index >= za->cdir->nentry) { + _zip_error_set(&za->error, ZIP_ER_INVAL, 0); + return -1; + } + + st->crc = za->cdir->entry[index].crc; + st->size = za->cdir->entry[index].uncomp_size; + st->mtime = za->cdir->entry[index].last_mod; + st->comp_size = za->cdir->entry[index].comp_size; + st->comp_method = za->cdir->entry[index].comp_method; + if (za->cdir->entry[index].bitflags & ZIP_GPBF_ENCRYPTED) { + if (za->cdir->entry[index].bitflags & ZIP_GPBF_STRONG_ENCRYPTION) { + /* XXX */ + st->encryption_method = ZIP_EM_UNKNOWN; + } + else + st->encryption_method = ZIP_EM_TRAD_PKWARE; + } + else + st->encryption_method = ZIP_EM_NONE; + /* st->bitflags = za->cdir->entry[index].bitflags; */ + } + + st->index = index; + st->name = name; + + return 0; +} + + +ZIP_EXTERN int +zip_stat(struct zip *za, const char *fname, int flags, struct zip_stat *st) +{ + int idx; + + if ((idx=zip_name_locate(za, fname, flags)) < 0) + return -1; + + return zip_stat_index(za, idx, flags, st); +} + + +struct read_zip { + struct zip_file *zf; + struct zip_stat st; + myoff_t off, len; +}; + +static ssize_t read_zip(void *st, void *data, size_t len, + enum zip_source_cmd cmd); + + + +ZIP_EXTERN struct zip_source * +zip_source_zip(struct zip *za, struct zip *srcza, int srcidx, int flags, + myoff_t start, myoff_t len) +{ + struct zip_error error; + struct zip_source *zs; + struct read_zip *p; + + /* XXX: ZIP_FL_RECOMPRESS */ + + if (za == NULL) + return NULL; + + if (srcza == NULL || start < 0 || len < -1 || srcidx < 0 || srcidx >= srcza->nentry) { + _zip_error_set(&za->error, ZIP_ER_INVAL, 0); + return NULL; + } + + if ((flags & ZIP_FL_UNCHANGED) == 0 + && ZIP_ENTRY_DATA_CHANGED(srcza->entry+srcidx)) { + _zip_error_set(&za->error, ZIP_ER_CHANGED, 0); + return NULL; + } + + if (len == 0) + len = -1; + + if (start == 0 && len == -1 && (flags & ZIP_FL_RECOMPRESS) == 0) + flags |= ZIP_FL_COMPRESSED; + else + flags &= ~ZIP_FL_COMPRESSED; + + if ((p=(struct read_zip *)malloc(sizeof(*p))) == NULL) { + _zip_error_set(&za->error, ZIP_ER_MEMORY, 0); + return NULL; + } + + _zip_error_copy(&error, &srcza->error); + + if (zip_stat_index(srcza, srcidx, flags, &p->st) < 0 + || (p->zf=zip_fopen_index(srcza, srcidx, flags)) == NULL) { + free(p); + _zip_error_copy(&za->error, &srcza->error); + _zip_error_copy(&srcza->error, &error); + + return NULL; + } + p->off = start; + p->len = len; + + if ((flags & ZIP_FL_COMPRESSED) == 0) { + p->st.size = p->st.comp_size = len; + p->st.comp_method = ZIP_CM_STORE; + p->st.crc = 0; + } + + if ((zs=zip_source_function(za, read_zip, p)) == NULL) { + free(p); + return NULL; + } + + return zs; +} + + + +static ssize_t +read_zip(void *state, void *data, size_t len, enum zip_source_cmd cmd) +{ + struct read_zip *z; + char b[8192], *buf; + int i, n; + + z = (struct read_zip *)state; + buf = (char *)data; + + switch (cmd) { + case ZIP_SOURCE_OPEN: + for (n=0; noff; n+= i) { + i = (z->off-n > sizeof(b) ? sizeof(b) : z->off-n); + if ((i=zip_fread(z->zf, b, i)) < 0) { + zip_fclose(z->zf); + z->zf = NULL; + return -1; + } + } + return 0; + + case ZIP_SOURCE_READ: + if (z->len != -1) + n = len > z->len ? z->len : len; + else + n = len; + + + if ((i=zip_fread(z->zf, buf, n)) < 0) + return -1; + + if (z->len != -1) + z->len -= i; + + return i; + + case ZIP_SOURCE_CLOSE: + return 0; + + case ZIP_SOURCE_STAT: + if (len < sizeof(z->st)) + return -1; + len = sizeof(z->st); + + memcpy(data, &z->st, len); + return len; + + case ZIP_SOURCE_ERROR: + { + int *e; + + if (len < sizeof(int)*2) + return -1; + + e = (int *)data; + zip_file_error_get(z->zf, e, e+1); + } + return sizeof(int)*2; + + case ZIP_SOURCE_FREE: + zip_fclose(z->zf); + free(z); + return 0; + + default: + ; + } + + return -1; +} + + +ZIP_EXTERN struct zip_source * +zip_source_function(struct zip *za, zip_source_callback zcb, void *ud) +{ + struct zip_source *zs; + + if (za == NULL) + return NULL; + + if ((zs=(struct zip_source *)malloc(sizeof(*zs))) == NULL) { + _zip_error_set(&za->error, ZIP_ER_MEMORY, 0); + return NULL; + } + + zs->f = zcb; + zs->ud = ud; + + return zs; +} + + +ZIP_EXTERN void +zip_source_free(struct zip_source *source) +{ + if (source == NULL) + return; + + (void)source->f(source->ud, NULL, 0, ZIP_SOURCE_FREE); + + free(source); +} + + +struct read_file { + char *fname; /* name of file to copy from */ + FILE *f; /* file to copy from */ + myoff_t off; /* start offset of */ + myoff_t len; /* lengt of data to copy */ + myoff_t remain; /* bytes remaining to be copied */ + int e[2]; /* error codes */ +}; + +static ssize_t read_file(void *state, void *data, size_t len, + enum zip_source_cmd cmd); + + + +ZIP_EXTERN struct zip_source * +zip_source_filep(struct zip *za, FILE *file, myoff_t start, myoff_t len) +{ + if (za == NULL) + return NULL; + + if (file == NULL || start < 0 || len < -1) { + _zip_error_set(&za->error, ZIP_ER_INVAL, 0); + return NULL; + } + + return _zip_source_file_or_p(za, NULL, file, start, len); +} + + + +struct zip_source * +_zip_source_file_or_p(struct zip *za, const char *fname, FILE *file, + myoff_t start, myoff_t len) +{ + struct read_file *f; + struct zip_source *zs; + + if (file == NULL && fname == NULL) { + _zip_error_set(&za->error, ZIP_ER_INVAL, 0); + return NULL; + } + + if ((f=(struct read_file *)malloc(sizeof(struct read_file))) == NULL) { + _zip_error_set(&za->error, ZIP_ER_MEMORY, 0); + return NULL; + } + + f->fname = NULL; + if (fname) { + if ((f->fname=strdup(fname)) == NULL) { + _zip_error_set(&za->error, ZIP_ER_MEMORY, 0); + free(f); + return NULL; + } + } + f->f = file; + f->off = start; + f->len = (len ? len : -1); + + if ((zs=zip_source_function(za, read_file, f)) == NULL) { + free(f); + return NULL; + } + + return zs; +} + + + +static ssize_t +read_file(void *state, void *data, size_t len, enum zip_source_cmd cmd) +{ + struct read_file *z; + char *buf; + int i, n; + + z = (struct read_file *)state; + buf = (char *)data; + + switch (cmd) { + case ZIP_SOURCE_OPEN: + if (z->fname) { + if ((z->f=fopen(z->fname, "rb")) == NULL) { + z->e[0] = ZIP_ER_OPEN; + z->e[1] = errno; + return -1; + } + } + + if (fseeko(z->f, z->off, SEEK_SET) < 0) { + z->e[0] = ZIP_ER_SEEK; + z->e[1] = errno; + return -1; + } + z->remain = z->len; + return 0; + + case ZIP_SOURCE_READ: + if (z->remain != -1) + n = len > z->remain ? z->remain : len; + else + n = len; + + if ((i=fread(buf, 1, n, z->f)) < 0) { + z->e[0] = ZIP_ER_READ; + z->e[1] = errno; + return -1; + } + + if (z->remain != -1) + z->remain -= i; + + return i; + + case ZIP_SOURCE_CLOSE: + if (z->fname) { + fclose(z->f); + z->f = NULL; + } + return 0; + + case ZIP_SOURCE_STAT: + { + struct zip_stat *st; + struct stat fst; + int err; + + if (len < sizeof(*st)) + return -1; + + if (z->f) + err = fstat(fileno(z->f), &fst); + else + err = stat(z->fname, &fst); + + if (err != 0) { + z->e[0] = ZIP_ER_READ; /* best match */ + z->e[1] = errno; + return -1; + } + + st = (struct zip_stat *)data; + + zip_stat_init(st); + st->mtime = fst.st_mtime; + if (z->len != -1) + st->size = z->len; + else if ((fst.st_mode&S_IFMT) == S_IFREG) + st->size = fst.st_size; + + return sizeof(*st); + } + + case ZIP_SOURCE_ERROR: + if (len < sizeof(int)*2) + return -1; + + memcpy(data, z->e, sizeof(int)*2); + return sizeof(int)*2; + + case ZIP_SOURCE_FREE: + free(z->fname); + if (z->f) + fclose(z->f); + free(z); + return 0; + + default: + ; + } + + return -1; +} + + +ZIP_EXTERN int +zip_name_locate(struct zip *za, const char *fname, int flags) +{ + return _zip_name_locate(za, fname, flags, &za->error); +} + + + +int +_zip_name_locate(struct zip *za, const char *fname, int flags, + struct zip_error *error) +{ + int (*cmp)(const char *, const char *); + const char *fn, *p; + int i, n; + + if (fname == NULL) { + _zip_error_set(error, ZIP_ER_INVAL, 0); + return -1; + } + + cmp = (flags & ZIP_FL_NOCASE) ? strcasecmp : strcmp; + + n = (flags & ZIP_FL_UNCHANGED) ? za->cdir->nentry : za->nentry; + for (i=0; icdir->entry[i].filename; + else + fn = _zip_get_name(za, i, flags, error); + + /* newly added (partially filled) entry */ + if (fn == NULL) + continue; + + if (flags & ZIP_FL_NODIR) { + p = strrchr(fn, '/'); + if (p) + fn = p+1; + } + + if (cmp(fname, fn) == 0) + return i; + } + + _zip_error_set(error, ZIP_ER_NOENT, 0); + return -1; +} + diff --git a/tests/deps/zip-0.2.1/zip/zipfiles.nim b/tests/deps/zip-0.2.1/zip/zipfiles.nim new file mode 100644 index 000000000..274587df9 --- /dev/null +++ b/tests/deps/zip-0.2.1/zip/zipfiles.nim @@ -0,0 +1,193 @@ +# +# +# Nim's Runtime Library +# (c) Copyright 2012 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +## This module implements a zip archive creator/reader/modifier. + +import + streams, libzip, times, os, strutils + +const BufSize = 8 * 1024 + +type + ZipArchive* = object of RootObj ## represents a zip archive + mode: FileMode + w: PZip +{.deprecated: [TZipArchive: ZipArchive].} + +proc zipError(z: var ZipArchive) = + var e: ref IOError + new(e) + e.msg = $zip_strerror(z.w) + raise e + +proc open*(z: var ZipArchive, filename: string, mode: FileMode = fmRead): bool = + ## Opens a zip file for reading, writing or appending. All file modes are + ## supported. Returns true iff successful, false otherwise. + var err, flags: int32 + case mode + of fmRead, fmReadWriteExisting, fmAppend: flags = 0 + of fmWrite: + if existsFile(filename): removeFile(filename) + flags = ZIP_CREATE or ZIP_EXCL + of fmReadWrite: flags = ZIP_CREATE + z.w = zip_open(filename, flags, addr(err)) + z.mode = mode + result = z.w != nil + +proc close*(z: var ZipArchive) = + ## Closes a zip file. + zip_close(z.w) + +proc createDir*(z: var ZipArchive, dir: string) = + ## Creates a directory within the `z` archive. This does not fail if the + ## directory already exists. Note that for adding a file like + ## ``"path1/path2/filename"`` it is not necessary + ## to create the ``"path/path2"`` subdirectories - it will be done + ## automatically by ``addFile``. + assert(z.mode != fmRead) + discard zip_add_dir(z.w, dir) + zip_error_clear(z.w) + +proc addFile*(z: var ZipArchive, dest, src: string) = + ## Adds the file `src` to the archive `z` with the name `dest`. `dest` + ## may contain a path that will be created. + assert(z.mode != fmRead) + if not fileExists(src): + raise newException(IOError, "File '" & src & "' does not exist") + var zipsrc = zip_source_file(z.w, src, 0, -1) + if zipsrc == nil: + #echo("Dest: " & dest) + #echo("Src: " & src) + zipError(z) + if zip_add(z.w, dest, zipsrc) < 0'i32: + zip_source_free(zipsrc) + zipError(z) + +proc addFile*(z: var ZipArchive, file: string) = + ## A shortcut for ``addFile(z, file, file)``, i.e. the name of the source is + ## the name of the destination. + addFile(z, file, file) + +proc mySourceCallback(state, data: pointer, len: int, + cmd: ZipSourceCmd): int {.cdecl.} = + var src = cast[Stream](state) + case cmd + of ZIP_SOURCE_OPEN: + if src.setPositionImpl != nil: setPosition(src, 0) # reset + of ZIP_SOURCE_READ: + result = readData(src, data, len) + of ZIP_SOURCE_CLOSE: close(src) + of ZIP_SOURCE_STAT: + var stat = cast[PZipStat](data) + zip_stat_init(stat) + stat.size = high(int32)-1 # we don't know the size + stat.mtime = getTime() + result = sizeof(ZipStat) + of ZIP_SOURCE_ERROR: + var err = cast[ptr array[0..1, cint]](data) + err[0] = ZIP_ER_INTERNAL + err[1] = 0 + result = 2*sizeof(cint) + of constZIP_SOURCE_FREE: GC_unref(src) + of ZIP_SOURCE_SUPPORTS: + # By default a read-only source is supported, which suits us. + result = -1 + else: + # An unknown command, failing + result = -1 + +proc addFile*(z: var ZipArchive, dest: string, src: Stream) = + ## Adds a file named with `dest` to the archive `z`. `dest` + ## may contain a path. The file's content is read from the `src` stream. + assert(z.mode != fmRead) + GC_ref(src) + var zipsrc = zip_source_function(z.w, mySourceCallback, cast[pointer](src)) + if zipsrc == nil: zipError(z) + if zip_add(z.w, dest, zipsrc) < 0'i32: + zip_source_free(zipsrc) + zipError(z) + +# -------------- zip file stream --------------------------------------------- + +type + TZipFileStream = object of StreamObj + f: PZipFile + atEnd: bool + + PZipFileStream* = + ref TZipFileStream ## a reader stream of a file within a zip archive + +proc fsClose(s: Stream) = zip_fclose(PZipFileStream(s).f) +proc fsAtEnd(s: Stream): bool = PZipFileStream(s).atEnd +proc fsReadData(s: Stream, buffer: pointer, bufLen: int): int = + result = zip_fread(PZipFileStream(s).f, buffer, bufLen) + if result == 0: + PZipFileStream(s).atEnd = true + +proc newZipFileStream(f: PZipFile): PZipFileStream = + new(result) + result.f = f + result.atEnd = false + result.closeImpl = fsClose + result.readDataImpl = fsReadData + result.atEndImpl = fsAtEnd + # other methods are nil! + +# ---------------------------------------------------------------------------- + +proc getStream*(z: var ZipArchive, filename: string): PZipFileStream = + ## returns a stream that can be used to read the file named `filename` + ## from the archive `z`. Returns nil in case of an error. + ## The returned stream does not support the `setPosition`, `getPosition`, + ## `writeData` or `atEnd` methods. + var x = zip_fopen(z.w, filename, 0'i32) + if x != nil: result = newZipFileStream(x) + +iterator walkFiles*(z: var ZipArchive): string = + ## walks over all files in the archive `z` and returns the filename + ## (including the path). + var i = 0'i32 + var num = zip_get_num_files(z.w) + while i < num: + yield $zip_get_name(z.w, i, 0'i32) + inc(i) + +proc extractFile*(z: var ZipArchive, srcFile: string, dest: Stream) = + ## extracts a file from the zip archive `z` to the destination stream. + var buf: array[BufSize, byte] + var strm = getStream(z, srcFile) + while true: + let bytesRead = strm.readData(addr(buf[0]), buf.len) + if bytesRead <= 0: break + dest.writeData(addr(buf[0]), bytesRead) + + dest.flush() + strm.close() + +proc extractFile*(z: var ZipArchive, srcFile: string, dest: string) = + ## extracts a file from the zip archive `z` to the destination filename. + var file = newFileStream(dest, fmWrite) + if file.isNil: + raise newException(IOError, "Failed to create output file: " & dest) + extractFile(z, srcFile, file) + file.close() + +proc extractAll*(z: var ZipArchive, dest: string) = + ## extracts all files from archive `z` to the destination directory. + createDir(dest) + for file in walkFiles(z): + if file.contains("/"): + createDir(dest / file[0..file.rfind("/")]) + extractFile(z, file, dest / file) + +when not defined(testing) and true: + var zip: ZipArchive + if not zip.open("nim-0.11.0.zip"): + raise newException(IOError, "opening zip failed") + zip.extractAll("test") diff --git a/tests/deps/zip-0.2.1/zip/zlib.nim b/tests/deps/zip-0.2.1/zip/zlib.nim new file mode 100644 index 000000000..f41ed5cfe --- /dev/null +++ b/tests/deps/zip-0.2.1/zip/zlib.nim @@ -0,0 +1,425 @@ +# Converted from Pascal + +## Interface to the zlib http://www.zlib.net/ compression library. + +when defined(windows): + const libz = "zlib1.dll" +elif defined(macosx): + const libz = "libz.dylib" +else: + const libz = "libz.so.1" + +type + Uint* = int32 + Ulong* = int + Ulongf* = int + Pulongf* = ptr Ulongf + ZOffT* = int32 + Pbyte* = cstring + Pbytef* = cstring + Allocfunc* = proc (p: pointer, items: Uint, size: Uint): pointer{.cdecl.} + FreeFunc* = proc (p: pointer, address: pointer){.cdecl.} + InternalState*{.final, pure.} = object + PInternalState* = ptr InternalState + ZStream*{.final, pure.} = object + nextIn*: Pbytef + availIn*: Uint + totalIn*: Ulong + nextOut*: Pbytef + availOut*: Uint + totalOut*: Ulong + msg*: Pbytef + state*: PInternalState + zalloc*: Allocfunc + zfree*: FreeFunc + opaque*: pointer + dataType*: int32 + adler*: Ulong + reserved*: Ulong + + ZStreamRec* = ZStream + PZstream* = ptr ZStream + GzFile* = pointer + ZStreamHeader* = enum + DETECT_STREAM, + RAW_DEFLATE, + ZLIB_STREAM, + GZIP_STREAM + + ZlibStreamError* = object of Exception + +{.deprecated: [TInternalState: InternalState, TAllocfunc: Allocfunc, + TFreeFunc: FreeFunc, TZStream: ZStream, TZStreamRec: ZStreamRec].} + +const + Z_NO_FLUSH* = 0 + Z_PARTIAL_FLUSH* = 1 + Z_SYNC_FLUSH* = 2 + Z_FULL_FLUSH* = 3 + Z_FINISH* = 4 + Z_OK* = 0 + Z_STREAM_END* = 1 + Z_NEED_DICT* = 2 + Z_ERRNO* = -1 + Z_STREAM_ERROR* = -2 + Z_DATA_ERROR* = -3 + Z_MEM_ERROR* = -4 + Z_BUF_ERROR* = -5 + Z_VERSION_ERROR* = -6 + Z_NO_COMPRESSION* = 0 + Z_BEST_SPEED* = 1 + Z_BEST_COMPRESSION* = 9 + Z_DEFAULT_COMPRESSION* = -1 + Z_FILTERED* = 1 + Z_HUFFMAN_ONLY* = 2 + Z_DEFAULT_STRATEGY* = 0 + Z_BINARY* = 0 + Z_ASCII* = 1 + Z_UNKNOWN* = 2 + Z_DEFLATED* = 8 + Z_NULL* = 0 + Z_MEM_LEVEL* = 8 + MAX_WBITS* = 15 + +proc zlibVersion*(): cstring{.cdecl, dynlib: libz, importc: "zlibVersion".} +proc deflate*(strm: var ZStream, flush: int32): int32{.cdecl, dynlib: libz, + importc: "deflate".} +proc deflateEnd*(strm: var ZStream): int32{.cdecl, dynlib: libz, + importc: "deflateEnd".} +proc inflate*(strm: var ZStream, flush: int32): int32{.cdecl, dynlib: libz, + importc: "inflate".} +proc inflateEnd*(strm: var ZStream): int32{.cdecl, dynlib: libz, + importc: "inflateEnd".} +proc deflateSetDictionary*(strm: var ZStream, dictionary: Pbytef, + dictLength: Uint): int32{.cdecl, dynlib: libz, + importc: "deflateSetDictionary".} +proc deflateCopy*(dest, source: var ZStream): int32{.cdecl, dynlib: libz, + importc: "deflateCopy".} +proc deflateReset*(strm: var ZStream): int32{.cdecl, dynlib: libz, + importc: "deflateReset".} +proc deflateParams*(strm: var ZStream, level: int32, strategy: int32): int32{. + cdecl, dynlib: libz, importc: "deflateParams".} +proc inflateSetDictionary*(strm: var ZStream, dictionary: Pbytef, + dictLength: Uint): int32{.cdecl, dynlib: libz, + importc: "inflateSetDictionary".} +proc inflateSync*(strm: var ZStream): int32{.cdecl, dynlib: libz, + importc: "inflateSync".} +proc inflateReset*(strm: var ZStream): int32{.cdecl, dynlib: libz, + importc: "inflateReset".} +proc compress*(dest: Pbytef, destLen: Pulongf, source: Pbytef, sourceLen: Ulong): cint{. + cdecl, dynlib: libz, importc: "compress".} +proc compress2*(dest: Pbytef, destLen: Pulongf, source: Pbytef, + sourceLen: Ulong, level: cint): cint{.cdecl, dynlib: libz, + importc: "compress2".} +proc uncompress*(dest: Pbytef, destLen: Pulongf, source: Pbytef, + sourceLen: Ulong): cint{.cdecl, dynlib: libz, + importc: "uncompress".} +proc compressBound*(sourceLen: Ulong): Ulong {.cdecl, dynlib: libz, importc.} +proc gzopen*(path: cstring, mode: cstring): GzFile{.cdecl, dynlib: libz, + importc: "gzopen".} +proc gzdopen*(fd: int32, mode: cstring): GzFile{.cdecl, dynlib: libz, + importc: "gzdopen".} +proc gzsetparams*(thefile: GzFile, level: int32, strategy: int32): int32{.cdecl, + dynlib: libz, importc: "gzsetparams".} +proc gzread*(thefile: GzFile, buf: pointer, length: int): int32{.cdecl, + dynlib: libz, importc: "gzread".} +proc gzwrite*(thefile: GzFile, buf: pointer, length: int): int32{.cdecl, + dynlib: libz, importc: "gzwrite".} +proc gzprintf*(thefile: GzFile, format: Pbytef): int32{.varargs, cdecl, + dynlib: libz, importc: "gzprintf".} +proc gzputs*(thefile: GzFile, s: Pbytef): int32{.cdecl, dynlib: libz, + importc: "gzputs".} +proc gzgets*(thefile: GzFile, buf: Pbytef, length: int32): Pbytef{.cdecl, + dynlib: libz, importc: "gzgets".} +proc gzputc*(thefile: GzFile, c: char): char{.cdecl, dynlib: libz, + importc: "gzputc".} +proc gzgetc*(thefile: GzFile): char{.cdecl, dynlib: libz, importc: "gzgetc".} +proc gzflush*(thefile: GzFile, flush: int32): int32{.cdecl, dynlib: libz, + importc: "gzflush".} +proc gzseek*(thefile: GzFile, offset: ZOffT, whence: int32): ZOffT{.cdecl, + dynlib: libz, importc: "gzseek".} +proc gzrewind*(thefile: GzFile): int32{.cdecl, dynlib: libz, importc: "gzrewind".} +proc gztell*(thefile: GzFile): ZOffT{.cdecl, dynlib: libz, importc: "gztell".} +proc gzeof*(thefile: GzFile): int {.cdecl, dynlib: libz, importc: "gzeof".} +proc gzclose*(thefile: GzFile): int32{.cdecl, dynlib: libz, importc: "gzclose".} +proc gzerror*(thefile: GzFile, errnum: var int32): Pbytef{.cdecl, dynlib: libz, + importc: "gzerror".} +proc adler32*(adler: Ulong, buf: Pbytef, length: Uint): Ulong{.cdecl, + dynlib: libz, importc: "adler32".} + ## **Warning**: Adler-32 requires at least a few hundred bytes to get rolling. +proc crc32*(crc: Ulong, buf: Pbytef, length: Uint): Ulong{.cdecl, dynlib: libz, + importc: "crc32".} +proc deflateInitu*(strm: var ZStream, level: int32, version: cstring, + streamSize: int32): int32{.cdecl, dynlib: libz, + importc: "deflateInit_".} +proc inflateInitu*(strm: var ZStream, version: cstring, + streamSize: int32): int32 {. + cdecl, dynlib: libz, importc: "inflateInit_".} +proc deflateInit*(strm: var ZStream, level: int32): int32 +proc inflateInit*(strm: var ZStream): int32 +proc deflateInit2u*(strm: var ZStream, level: int32, `method`: int32, + windowBits: int32, memLevel: int32, strategy: int32, + version: cstring, streamSize: int32): int32 {.cdecl, + dynlib: libz, importc: "deflateInit2_".} +proc inflateInit2u*(strm: var ZStream, windowBits: int32, version: cstring, + streamSize: int32): int32{.cdecl, dynlib: libz, + importc: "inflateInit2_".} +proc deflateInit2*(strm: var ZStream, + level, `method`, windowBits, memLevel, + strategy: int32): int32 +proc inflateInit2*(strm: var ZStream, windowBits: int32): int32 +proc zError*(err: int32): cstring{.cdecl, dynlib: libz, importc: "zError".} +proc inflateSyncPoint*(z: PZstream): int32{.cdecl, dynlib: libz, + importc: "inflateSyncPoint".} +proc getCrcTable*(): pointer{.cdecl, dynlib: libz, importc: "get_crc_table".} + +proc deflateBound*(strm: var ZStream, sourceLen: ULong): ULong {.cdecl, + dynlib: libz, importc: "deflateBound".} + +proc deflateInit(strm: var ZStream, level: int32): int32 = + result = deflateInitu(strm, level, zlibVersion(), sizeof(ZStream).cint) + +proc inflateInit(strm: var ZStream): int32 = + result = inflateInitu(strm, zlibVersion(), sizeof(ZStream).cint) + +proc deflateInit2(strm: var ZStream, + level, `method`, windowBits, memLevel, + strategy: int32): int32 = + result = deflateInit2u(strm, level, `method`, windowBits, memLevel, + strategy, zlibVersion(), sizeof(ZStream).cint) + +proc inflateInit2(strm: var ZStream, windowBits: int32): int32 = + result = inflateInit2u(strm, windowBits, zlibVersion(), + sizeof(ZStream).cint) + +proc zlibAllocMem*(appData: pointer, items, size: int): pointer {.cdecl.} = + result = alloc(items * size) + +proc zlibFreeMem*(appData, `block`: pointer) {.cdecl.} = + dealloc(`block`) + + +proc compress*(sourceBuf: cstring; sourceLen: int; level=Z_DEFAULT_COMPRESSION; stream=GZIP_STREAM): string = + ## Given a cstring, returns its deflated version with an optional header. + ## + ## Valid argument for ``stream`` are + ## - ``ZLIB_STREAM`` - add a zlib header and footer. + ## - ``GZIP_STREAM`` - add a basic gzip header and footer. + ## - ``RAW_DEFLATE`` - no header is generated. + ## + ## Passing a nil cstring will crash this proc in release mode and assert in + ## debug mode. + ## + ## Compression level can be set with ``level`` argument. Currently + ## ``Z_DEFAULT_COMPRESSION`` is 6. + ## + ## Returns "" on failure. + assert(not sourceBuf.isNil) + assert(sourceLen >= 0) + + var z: ZStream + var windowBits = MAX_WBITS + case (stream) + of RAW_DEFLATE: windowBits = -MAX_WBITS + of GZIP_STREAM: windowBits = MAX_WBITS + 16 + of ZLIB_STREAM, DETECT_STREAM: + discard # DETECT_STREAM defaults to ZLIB_STREAM + + var status = deflateInit2(z, level.int32, Z_DEFLATED.int32, + windowBits.int32, Z_MEM_LEVEL.int32, + Z_DEFAULT_STRATEGY.int32) + case status + of Z_OK: discard + of Z_MEM_ERROR: raise newException(OutOfMemError, "") + of Z_STREAM_ERROR: raise newException(ZlibStreamError, "invalid zlib stream parameter!") + of Z_VERSION_ERROR: raise newException(ZlibStreamError, "zlib version mismatch!") + else: raise newException(ZlibStreamError, "Unkown error(" & $status & ") : " & $z.msg) + + let space = deflateBound(z, sourceLen) + var compressed = newStringOfCap(space) + z.next_in = sourceBuf + z.avail_in = sourceLen.Uint + z.next_out = addr(compressed[0]) + z.avail_out = space.Uint + + status = deflate(z, Z_FINISH) + if status != Z_STREAM_END: + discard deflateEnd(z) # cleanup allocated ressources + raise newException(ZlibStreamError, "Invalid stream state(" & $status & ") : " & $z.msg) + + status = deflateEnd(z) + if status != Z_OK: # cleanup allocated ressources + raise newException(ZlibStreamError, "Invalid stream state(" & $status & ") : " & $z.msg) + + compressed.setLen(z.total_out) + swap(result, compressed) + +proc compress*(input: string; level=Z_DEFAULT_COMPRESSION; stream=GZIP_STREAM): string = + ## Given a string, returns its deflated version with an optional header. + ## + ## Valid arguments for ``stream`` are + ## - ``ZLIB_STREAM`` - add a zlib header and footer. + ## - ``GZIP_STREAM`` - add a basic gzip header and footer. + ## - ``RAW_DEFLATE`` - no header is generated. + ## + ## Compression level can be set with ``level`` argument. Currently + ## ``Z_DEFAULT_COMPRESSION`` is 6. + ## + ## Returns "" on failure. + result = compress(input, input.len, level, stream) + +proc uncompress*(sourceBuf: cstring, sourceLen: Natural; stream=DETECT_STREAM): string = + ## Given a deflated buffer returns its inflated content as a string. + ## + ## Valid arguments for ``stream`` are + ## - ``DETECT_STREAM`` - detect if zlib or gzip header is present + ## and decompress stream. Fail on raw deflate stream. + ## - ``ZLIB_STREAM`` - decompress a zlib stream. + ## - ``GZIP_STREAM`` - decompress a gzip stream. + ## - ``RAW_DEFLATE`` - decompress a raw deflate stream. + ## + ## Passing a nil cstring will crash this proc in release mode and assert in + ## debug mode. + ## + ## Returns "" on problems. Failure is a very loose concept, it could be you + ## passing a non deflated string, or it could mean not having enough memory + ## for the inflated version. + ## + ## The uncompression algorithm is based on http://zlib.net/zpipe.c. + assert(not sourceBuf.isNil) + assert(sourceLen >= 0) + var z: ZStream + var decompressed: string = "" + var sbytes = 0 + var wbytes = 0 + ## allocate inflate state + + z.availIn = 0 + var wbits = case (stream) + of RAW_DEFLATE: -MAX_WBITS + of ZLIB_STREAM: MAX_WBITS + of GZIP_STREAM: MAX_WBITS + 16 + of DETECT_STREAM: MAX_WBITS + 32 + + var status = inflateInit2(z, wbits.int32) + + case status + of Z_OK: discard + of Z_MEM_ERROR: raise newException(OutOfMemError, "") + of Z_STREAM_ERROR: raise newException(ZlibStreamError, "invalid zlib stream parameter!") + of Z_VERSION_ERROR: raise newException(ZlibStreamError, "zlib version mismatch!") + else: raise newException(ZlibStreamError, "Unkown error(" & $status & ") : " & $z.msg) + + # run loop until all input is consumed. + # handle concatenated deflated stream with header. + while true: + z.availIn = (sourceLen - sbytes).int32 + + # no more input available + if (sourceLen - sbytes) <= 0: break + z.nextIn = sourceBuf[sbytes].unsafeaddr + + # run inflate() on available input until output buffer is full + while true: + # if written bytes >= output size : resize output + if wbytes >= decompressed.len: + let cur_outlen = decompressed.len + let new_outlen = if decompressed.len == 0: sourceLen*2 else: decompressed.len*2 + if new_outlen < cur_outlen: # unsigned integer overflow, buffer too large + discard inflateEnd(z); + raise newException(OverflowError, "zlib stream decompressed size is too large! (size > " & $int.high & ")") + + decompressed.setLen(new_outlen) + + # available space for decompression + let space = decompressed.len - wbytes + z.availOut = space.Uint + z.nextOut = decompressed[wbytes].addr + + status = inflate(z, Z_NO_FLUSH) + if status.int8 notin {Z_OK.int8, Z_STREAM_END.int8, Z_BUF_ERROR.int8}: + discard inflateEnd(z) + case status + of Z_MEM_ERROR: raise newException(OutOfMemError, "") + of Z_DATA_ERROR: raise newException(ZlibStreamError, "invalid zlib stream parameter!") + else: raise newException(ZlibStreamError, "Unkown error(" & $status & ") : " & $z.msg) + + # add written bytes, if any. + wbytes += space - z.availOut.int + + # may need more input + if not (z.availOut == 0): break + + # inflate() says stream is done + if (status == Z_STREAM_END): + # may have another stream concatenated + if z.availIn != 0: + sbytes = sourceLen - z.availIn # add consumed bytes + if inflateReset(z) != Z_OK: # reset zlib struct and try again + raise newException(ZlibStreamError, "Invalid stream state(" & $status & ") : " & $z.msg) + else: + break # end of decompression + + # clean up and don't care about any error + discard inflateEnd(z) + + if status != Z_STREAM_END: + raise newException(ZlibStreamError, "Invalid stream state(" & $status & ") : " & $z.msg) + + decompressed.setLen(wbytes) + swap(result, decompressed) + + +proc uncompress*(sourceBuf: string; stream=DETECT_STREAM): string = + ## Given a GZIP-ed string return its inflated content. + ## + ## Valid arguments for ``stream`` are + ## - ``DETECT_STREAM`` - detect if zlib or gzip header is present + ## and decompress stream. Fail on raw deflate stream. + ## - ``ZLIB_STREAM`` - decompress a zlib stream. + ## - ``GZIP_STREAM`` - decompress a gzip stream. + ## - ``RAW_DEFLATE`` - decompress a raw deflate stream. + ## + ## Returns "" on failure. + result = uncompress(sourceBuf, sourceBuf.len, stream) + + + +proc deflate*(buffer: var string; level=Z_DEFAULT_COMPRESSION; stream=GZIP_STREAM): bool {.discardable.} = + ## Convenience proc which deflates a string and insert an optional header/footer. + ## + ## Valid arguments for ``stream`` are + ## - ``ZLIB_STREAM`` - add a zlib header and footer. + ## - ``GZIP_STREAM`` - add a basic gzip header and footer. + ## - ``RAW_DEFLATE`` - no header is generated. + ## + ## Compression level can be set with ``level`` argument. Currently + ## ``Z_DEFAULT_COMPRESSION`` is 6. + ## + ## Returns true if `buffer` was successfully deflated otherwise the buffer is untouched. + + var temp = compress(addr(buffer[0]), buffer.len, level, stream) + if temp.len != 0: + swap(buffer, temp) + result = true + +proc inflate*(buffer: var string; stream=DETECT_STREAM): bool {.discardable.} = + ## Convenience proc which inflates a string containing compressed data + ## with an optional header. + ## + ## Valid argument for ``stream`` are: + ## - ``DETECT_STREAM`` - detect if zlib or gzip header is present + ## and decompress stream. Fail on raw deflate stream. + ## - ``ZLIB_STREAM`` - decompress a zlib stream. + ## - ``GZIP_STREAM`` - decompress a gzip stream. + ## - ``RAW_DEFLATE`` - decompress a raw deflate stream. + ## + ## It is ok to pass a buffer which doesn't contain deflated data, + ## in this case the proc won't modify the buffer. + ## + ## Returns true if `buffer` was successfully inflated. + + var temp = uncompress(addr(buffer[0]), buffer.len, stream) + if temp.len != 0: + swap(buffer, temp) + result = true diff --git a/tests/deps/zip-0.2.1/zip/zzip.nim b/tests/deps/zip-0.2.1/zip/zzip.nim new file mode 100644 index 000000000..553970e0c --- /dev/null +++ b/tests/deps/zip-0.2.1/zip/zzip.nim @@ -0,0 +1,176 @@ +# +# +# Nim's Runtime Library +# (c) Copyright 2008 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +## This module is an interface to the zzip library. + +# Author: +# Guido Draheim +# Tomi Ollila +# Copyright (c) 1999,2000,2001,2002,2003,2004 Guido Draheim +# All rights reserved, +# usage allowed under the restrictions of the +# Lesser GNU General Public License +# or alternatively the restrictions +# of the Mozilla Public License 1.1 + +when defined(windows): + const + dllname = "zzip.dll" +else: + const + dllname = "libzzip.so" + +type + TZZipError* = int32 # Name conflict if we drop the `T` + +const + ZZIP_ERROR* = -4096'i32 + ZZIP_NO_ERROR* = 0'i32 # no error, may be used if user sets it. + ZZIP_OUTOFMEM* = ZZIP_ERROR - 20'i32 # out of memory + ZZIP_DIR_OPEN* = ZZIP_ERROR - 21'i32 # failed to open zipfile, see errno for details + ZZIP_DIR_STAT* = ZZIP_ERROR - 22'i32 # failed to fstat zipfile, see errno for details + ZZIP_DIR_SEEK* = ZZIP_ERROR - 23'i32 # failed to lseek zipfile, see errno for details + ZZIP_DIR_READ* = ZZIP_ERROR - 24'i32 # failed to read zipfile, see errno for details + ZZIP_DIR_TOO_SHORT* = ZZIP_ERROR - 25'i32 + ZZIP_DIR_EDH_MISSING* = ZZIP_ERROR - 26'i32 + ZZIP_DIRSIZE* = ZZIP_ERROR - 27'i32 + ZZIP_ENOENT* = ZZIP_ERROR - 28'i32 + ZZIP_UNSUPP_COMPR* = ZZIP_ERROR - 29'i32 + ZZIP_CORRUPTED* = ZZIP_ERROR - 31'i32 + ZZIP_UNDEF* = ZZIP_ERROR - 32'i32 + ZZIP_DIR_LARGEFILE* = ZZIP_ERROR - 33'i32 + + ZZIP_CASELESS* = 1'i32 shl 12'i32 + ZZIP_NOPATHS* = 1'i32 shl 13'i32 + ZZIP_PREFERZIP* = 1'i32 shl 14'i32 + ZZIP_ONLYZIP* = 1'i32 shl 16'i32 + ZZIP_FACTORY* = 1'i32 shl 17'i32 + ZZIP_ALLOWREAL* = 1'i32 shl 18'i32 + ZZIP_THREADED* = 1'i32 shl 19'i32 + +type + ZZipDir* {.final, pure.} = object + ZZipFile* {.final, pure.} = object + ZZipPluginIO* {.final, pure.} = object + + ZZipDirent* {.final, pure.} = object + d_compr*: int32 ## compression method + d_csize*: int32 ## compressed size + st_size*: int32 ## file size / decompressed size + d_name*: cstring ## file name / strdupped name + + ZZipStat* = ZZipDirent +{.deprecated: [TZZipDir: ZzipDir, TZZipFile: ZzipFile, + TZZipPluginIO: ZzipPluginIO, TZZipDirent: ZzipDirent, + TZZipStat: ZZipStat].} + +proc zzip_strerror*(errcode: int32): cstring {.cdecl, dynlib: dllname, + importc: "zzip_strerror".} +proc zzip_strerror_of*(dir: ptr ZZipDir): cstring {.cdecl, dynlib: dllname, + importc: "zzip_strerror_of".} +proc zzip_errno*(errcode: int32): int32 {.cdecl, dynlib: dllname, + importc: "zzip_errno".} + +proc zzip_geterror*(dir: ptr ZZipDir): int32 {.cdecl, dynlib: dllname, + importc: "zzip_error".} +proc zzip_seterror*(dir: ptr ZZipDir, errcode: int32) {.cdecl, dynlib: dllname, + importc: "zzip_seterror".} +proc zzip_compr_str*(compr: int32): cstring {.cdecl, dynlib: dllname, + importc: "zzip_compr_str".} +proc zzip_dirhandle*(fp: ptr ZZipFile): ptr ZZipDir {.cdecl, dynlib: dllname, + importc: "zzip_dirhandle".} +proc zzip_dirfd*(dir: ptr ZZipDir): int32 {.cdecl, dynlib: dllname, + importc: "zzip_dirfd".} +proc zzip_dir_real*(dir: ptr ZZipDir): int32 {.cdecl, dynlib: dllname, + importc: "zzip_dir_real".} +proc zzip_file_real*(fp: ptr ZZipFile): int32 {.cdecl, dynlib: dllname, + importc: "zzip_file_real".} +proc zzip_realdir*(dir: ptr ZZipDir): pointer {.cdecl, dynlib: dllname, + importc: "zzip_realdir".} +proc zzip_realfd*(fp: ptr ZZipFile): int32 {.cdecl, dynlib: dllname, + importc: "zzip_realfd".} + +proc zzip_dir_alloc*(fileext: cstringArray): ptr ZZipDir {.cdecl, + dynlib: dllname, importc: "zzip_dir_alloc".} +proc zzip_dir_free*(para1: ptr ZZipDir): int32 {.cdecl, dynlib: dllname, + importc: "zzip_dir_free".} + +proc zzip_dir_fdopen*(fd: int32, errcode_p: ptr TZZipError): ptr ZZipDir {.cdecl, + dynlib: dllname, importc: "zzip_dir_fdopen".} +proc zzip_dir_open*(filename: cstring, errcode_p: ptr TZZipError): ptr ZZipDir {. + cdecl, dynlib: dllname, importc: "zzip_dir_open".} +proc zzip_dir_close*(dir: ptr ZZipDir) {.cdecl, dynlib: dllname, + importc: "zzip_dir_close".} +proc zzip_dir_read*(dir: ptr ZZipDir, dirent: ptr ZZipDirent): int32 {.cdecl, + dynlib: dllname, importc: "zzip_dir_read".} + +proc zzip_opendir*(filename: cstring): ptr ZZipDir {.cdecl, dynlib: dllname, + importc: "zzip_opendir".} +proc zzip_closedir*(dir: ptr ZZipDir) {.cdecl, dynlib: dllname, + importc: "zzip_closedir".} +proc zzip_readdir*(dir: ptr ZZipDir): ptr ZZipDirent {.cdecl, dynlib: dllname, + importc: "zzip_readdir".} +proc zzip_rewinddir*(dir: ptr ZZipDir) {.cdecl, dynlib: dllname, + importc: "zzip_rewinddir".} +proc zzip_telldir*(dir: ptr ZZipDir): int {.cdecl, dynlib: dllname, + importc: "zzip_telldir".} +proc zzip_seekdir*(dir: ptr ZZipDir, offset: int) {.cdecl, dynlib: dllname, + importc: "zzip_seekdir".} + +proc zzip_file_open*(dir: ptr ZZipDir, name: cstring, flags: int32): ptr ZZipFile {. + cdecl, dynlib: dllname, importc: "zzip_file_open".} +proc zzip_file_close*(fp: ptr ZZipFile) {.cdecl, dynlib: dllname, + importc: "zzip_file_close".} +proc zzip_file_read*(fp: ptr ZZipFile, buf: pointer, length: int): int {. + cdecl, dynlib: dllname, importc: "zzip_file_read".} +proc zzip_open*(name: cstring, flags: int32): ptr ZZipFile {.cdecl, + dynlib: dllname, importc: "zzip_open".} +proc zzip_close*(fp: ptr ZZipFile) {.cdecl, dynlib: dllname, + importc: "zzip_close".} +proc zzip_read*(fp: ptr ZZipFile, buf: pointer, length: int): int {. + cdecl, dynlib: dllname, importc: "zzip_read".} + +proc zzip_freopen*(name: cstring, mode: cstring, para3: ptr ZZipFile): ptr ZZipFile {. + cdecl, dynlib: dllname, importc: "zzip_freopen".} +proc zzip_fopen*(name: cstring, mode: cstring): ptr ZZipFile {.cdecl, + dynlib: dllname, importc: "zzip_fopen".} +proc zzip_fread*(p: pointer, size: int, nmemb: int, + file: ptr ZZipFile): int {.cdecl, dynlib: dllname, + importc: "zzip_fread".} +proc zzip_fclose*(fp: ptr ZZipFile) {.cdecl, dynlib: dllname, + importc: "zzip_fclose".} + +proc zzip_rewind*(fp: ptr ZZipFile): int32 {.cdecl, dynlib: dllname, + importc: "zzip_rewind".} +proc zzip_seek*(fp: ptr ZZipFile, offset: int, whence: int32): int {. + cdecl, dynlib: dllname, importc: "zzip_seek".} +proc zzip_tell*(fp: ptr ZZipFile): int {.cdecl, dynlib: dllname, + importc: "zzip_tell".} + +proc zzip_dir_stat*(dir: ptr ZZipDir, name: cstring, zs: ptr ZZipStat, + flags: int32): int32 {.cdecl, dynlib: dllname, + importc: "zzip_dir_stat".} +proc zzip_file_stat*(fp: ptr ZZipFile, zs: ptr ZZipStat): int32 {.cdecl, + dynlib: dllname, importc: "zzip_file_stat".} +proc zzip_fstat*(fp: ptr ZZipFile, zs: ptr ZZipStat): int32 {.cdecl, dynlib: dllname, + importc: "zzip_fstat".} + +proc zzip_open_shared_io*(stream: ptr ZZipFile, name: cstring, + o_flags: int32, o_modes: int32, ext: cstringArray, + io: ptr ZZipPluginIO): ptr ZZipFile {.cdecl, + dynlib: dllname, importc: "zzip_open_shared_io".} +proc zzip_open_ext_io*(name: cstring, o_flags: int32, o_modes: int32, + ext: cstringArray, io: ptr ZZipPluginIO): ptr ZZipFile {. + cdecl, dynlib: dllname, importc: "zzip_open_ext_io".} +proc zzip_opendir_ext_io*(name: cstring, o_modes: int32, + ext: cstringArray, io: ptr ZZipPluginIO): ptr ZZipDir {. + cdecl, dynlib: dllname, importc: "zzip_opendir_ext_io".} +proc zzip_dir_open_ext_io*(filename: cstring, errcode_p: ptr TZZipError, + ext: cstringArray, io: ptr ZZipPluginIO): ptr ZZipDir {. + cdecl, dynlib: dllname, importc: "zzip_dir_open_ext_io".} diff --git a/tests/destructor/nim.cfg b/tests/destructor/nim.cfg deleted file mode 100644 index 7c148b797..000000000 --- a/tests/destructor/nim.cfg +++ /dev/null @@ -1 +0,0 @@ ---sinkInference:on diff --git a/tests/destructor/t12037.nim b/tests/destructor/t12037.nim index 30266690f..1a7d536cc 100644 --- a/tests/destructor/t12037.nim +++ b/tests/destructor/t12037.nim @@ -1,5 +1,5 @@ discard """ - cmd: '''nim c --gc:arc $file''' + cmd: '''nim c --newruntime $file''' output: ''' showing original type, length, and contents seq[int] 1 @[42] copy length and contents 1 @[42] @@ -9,11 +9,11 @@ copy length and contents 1 @[42] proc test() = var sq1 = @[42] echo "showing original type, length, and contents ", sq1.typeof, " ", sq1.len, " ", sq1 - doAssert cast[int](sq1[0].addr) != 0 + doAssert cast[int](sq1[0].unsafeAddr) != 0 var sq2 = sq1 # copy of original echo "copy length and contents ", sq2.len, " ", sq2 - doAssert cast[int](sq2[0].addr) != 0 - doAssert cast[int](sq1[0].addr) != 0 + doAssert cast[int](sq2[0].unsafeAddr) != 0 + doAssert cast[int](sq1[0].unsafeAddr) != 0 test() diff --git a/tests/destructor/t16607.nim b/tests/destructor/t16607.nim deleted file mode 100644 index f98a6d517..000000000 --- a/tests/destructor/t16607.nim +++ /dev/null @@ -1,23 +0,0 @@ -discard """ - matrix: "--gc:refc; --gc:arc" -""" - -# bug #16607 - -type - O {.requiresInit.} = object - initialized: bool - -proc `=destroy`(o: var O) = - doAssert o.initialized, "O was destroyed before initialization!" - -proc initO(): O = - O(initialized: true) - -proc pair(): tuple[a, b: O] = - result = (a: initO(), b: initO()) - -proc main() = - discard pair() - -main() diff --git a/tests/destructor/t17198.nim b/tests/destructor/t17198.nim deleted file mode 100644 index 098db8245..000000000 --- a/tests/destructor/t17198.nim +++ /dev/null @@ -1,32 +0,0 @@ -discard """ - cmd: '''nim c --gc:arc $file''' - output: ''' -other -''' -""" - -import std/macros - -macro bigCaseStmt(arg: untyped): untyped = - result = nnkCaseStmt.newTree(arg) - - # try to change 2000 to a bigger value if it doesn't crash - for x in 0 ..< 2000: - result.add nnkOfBranch.newTree(newStrLitNode($x), newStrLitNode($x)) - - result.add nnkElse.newTree(newStrLitNode("other")) - -macro bigIfElseExpr(): untyped = - result = nnkIfExpr.newTree() - - for x in 0 ..< 1000: - result.add nnkElifExpr.newTree(newLit(false), newStrLitNode($x)) - - result.add nnkElseExpr.newTree(newStrLitNode("other")) - -proc test(arg: string): string = - echo bigIfElseExpr() - - result = bigCaseStmt(arg) - -discard test("test") diff --git a/tests/destructor/t5342.nim b/tests/destructor/t5342.nim deleted file mode 100644 index 0acd5ef9d..000000000 --- a/tests/destructor/t5342.nim +++ /dev/null @@ -1,24 +0,0 @@ -discard """ - matrix: "--mm:refc; --mm:arc" - targets: "c js" - output: ''' -1 -2 -here -2 -1 -''' -""" - - -type - A = object - id: int - B = object - a: A -proc `=destroy`(a: var A) = echo a.id -var x = A(id: 1) -var y = B(a: A(id: 2)) -`=destroy`(x) -`=destroy`(y) -echo "here" \ No newline at end of file diff --git a/tests/destructor/t7346.nim b/tests/destructor/t7346.nim index 3834d39ff..9e5292a61 100644 --- a/tests/destructor/t7346.nim +++ b/tests/destructor/t7346.nim @@ -2,7 +2,8 @@ discard """ joinable: false """ -# This bug could only be reproduced with --newruntime +when not defined(nimNewRuntime): + {.error: "This bug could only be reproduced with --newruntime".} type Obj = object diff --git a/tests/destructor/t9440.nim b/tests/destructor/t9440.nim deleted file mode 100644 index 153bb303d..000000000 --- a/tests/destructor/t9440.nim +++ /dev/null @@ -1,52 +0,0 @@ -discard """ - matrix: "--gc:refc; --gc:orc; --gc:arc" - output: ''' -() -Destroyed -() -Destroyed -() -Destroyed -end -------------------------- -() -Destroyed -end -''' - -""" - -# bug #9440 -block: - type - X = object - - proc `=destroy`(x: var X) = - echo "Destroyed" - - proc main() = - for x in 0 .. 2: - var obj = X() - echo obj - # The destructor call is invoked after "end" is printed - echo "end" - - main() - -echo "-------------------------" - -block: - type - X = object - - proc `=destroy`(x: var X) = - echo "Destroyed" - - proc main() = - block: - var obj = X() - echo obj - # The destructor is not called when obj goes out of scope - echo "end" - - main() diff --git a/tests/destructor/tarc.nim b/tests/destructor/tarc.nim index 54d75a410..1acc95fad 100644 --- a/tests/destructor/tarc.nim +++ b/tests/destructor/tarc.nim @@ -6,11 +6,7 @@ Success Hello 1 2 -0 -List -@["4", "5", "6", "", "", "a", ""] -@["", "", "a", ""] -''' +0''' cmd: '''nim c --gc:arc $file''' """ @@ -149,36 +145,3 @@ proc bug13105 = bug13105() echo getOccupiedMem() - startMem - - -#------------------------------------------------------------------------------ -# issue #14294 - -import tables - -type - TagKind = enum - List = 0, Compound - - Tag = object - case kind: TagKind - of List: - values: seq[Tag] - of Compound: - compound: Table[string, Tag] - -var a = Tag(kind: List) -var b = a -echo a.kind -var c = a - -proc testAdd(i: int; yyy: openArray[string]) = - var x: seq[string] - x.add [$i, $(i+1), $(i+2)] - x.add yyy - echo x - -var y = newSeq[string](4) -y[2] = "a" -testAdd(4, y) -echo y diff --git a/tests/destructor/tarc2.nim b/tests/destructor/tarc2.nim index a7d7b4945..bd6343b2f 100644 --- a/tests/destructor/tarc2.nim +++ b/tests/destructor/tarc2.nim @@ -13,13 +13,9 @@ proc create(): T = T(s: @[], data: "abc") proc addX(x: T; data: string) = x.data = data -{.push sinkInference: off.} - proc addX(x: T; child: T) = x.s.add child -{.pop.} - proc main(rootName: string) = var root = create() root.data = rootName @@ -27,5 +23,4 @@ proc main(rootName: string) = let mem = getOccupiedMem() main("yeah") -GC_fullCollect() echo "leak: ", getOccupiedMem() - mem > 0 diff --git a/tests/destructor/tarray_indexing.nim b/tests/destructor/tarray_indexing.nim index a9dfdf4ed..7efd5a00c 100644 --- a/tests/destructor/tarray_indexing.nim +++ b/tests/destructor/tarray_indexing.nim @@ -1,7 +1,7 @@ discard """ output: '''allocating 1048576 65536 filling page from 1048576 len 65536''' - cmd: '''nim c --gc:arc $file''' + cmd: '''nim c --newruntime $file''' """ # bug #12669 @@ -63,7 +63,7 @@ proc fillPages*(mem: UserProcessMemory, start: uint32, data: seq[byte]) = #echo cast[uint64](addr mem.pageAccess[i]) let page = mem.pageAccess[i] assert page != nil - #copyMem(page, addr data[i * 0x1000 - start], 0x1000) + #copyMem(page, unsafeAddr data[i * 0x1000 - start], 0x1000) const base = 0x00100000 diff --git a/tests/destructor/tasync_prototype.nim b/tests/destructor/tasync_prototype.nim index 81fd824e9..bd80adf0c 100644 --- a/tests/destructor/tasync_prototype.nim +++ b/tests/destructor/tasync_prototype.nim @@ -32,12 +32,7 @@ proc serve(server: PAsyncHttpServer): PFutureBase = yield acceptAddrFut var fut = acceptAddrFut.value - # with the new scope based destruction, this cannot - # possibly work: var f {.cursor.} = processClient() - # It also seems to be the wrong way how to avoid the - # cycle. The cycle is caused by capturing the 'env' - # part from 'env.f'. when true: f.callback = proc () = diff --git a/tests/destructor/tasync_prototype_cyclic.nim b/tests/destructor/tasync_prototype_cyclic.nim index 8ba73a8fc..136e0b676 100644 --- a/tests/destructor/tasync_prototype_cyclic.nim +++ b/tests/destructor/tasync_prototype_cyclic.nim @@ -51,5 +51,4 @@ proc main = discard serve(PAsyncHttpServer(value: "asdas")) main() -GC_fullCollect() echo "MEMORY ", getOccupiedMem() - mem diff --git a/tests/destructor/tatomicptrs.nim b/tests/destructor/tatomicptrs.nim index 88f84d67c..7313afbf5 100644 --- a/tests/destructor/tatomicptrs.nim +++ b/tests/destructor/tatomicptrs.nim @@ -27,7 +27,7 @@ template decRef(x): untyped = atomicDec(x.refcount) proc makeShared*[T](x: sink T): SharedPtr[T] = # XXX could benefit from a macro that generates it. - result = cast[SharedPtr[T]](allocShared0(sizeof(x))) + result = cast[SharedPtr[T]](allocShared(sizeof(x))) result.x[] = x echo "allocating" @@ -72,7 +72,6 @@ template `.=`*[T](s: SharedPtr[T]; field, value: untyped) = from macros import unpackVarargs template `.()`*[T](s: SharedPtr[T]; field: untyped, args: varargs[untyped]): untyped = - # xxx this isn't used, the test should be improved unpackVarargs(s.x.field, args) diff --git a/tests/destructor/tbintree2.nim b/tests/destructor/tbintree2.nim index d56c2850b..e910f430a 100644 --- a/tests/destructor/tbintree2.nim +++ b/tests/destructor/tbintree2.nim @@ -1,7 +1,7 @@ discard """ cmd: '''nim c -d:nimAllocStats --newruntime $file''' output: '''0 -(allocCount: 5, deallocCount: 5)''' +(allocCount: 6, deallocCount: 6)''' """ import system / ansi_c @@ -21,21 +21,21 @@ proc merge(lower, greater: owned Node): owned Node = elif greater.isNil: result = lower elif lower.y < greater.y: - lower.right = merge(move lower.right, greater) + lower.right = merge(lower.right, greater) result = lower else: - greater.left = merge(lower, move greater.left) + greater.left = merge(lower, greater.left) result = greater proc splitBinary(orig: owned Node, value: int32): (owned Node, owned Node) = if orig.isNil: result = (nil, nil) elif orig.x < value: - let splitPair = splitBinary(move orig.right, value) + let splitPair = splitBinary(orig.right, value) orig.right = splitPair[0] result = (orig, splitPair[1]) else: - let splitPair = splitBinary(move orig.left, value) + let splitPair = splitBinary(orig.left, value) orig.left = splitPair[1] result = (splitPair[0], orig) @@ -57,7 +57,7 @@ proc `=destroy`(t: var Tree) {.nodestroy.} = let x = s.pop if x.left != nil: s.add(x.left) if x.right != nil: s.add(x.right) - `=dispose`(x) + dispose(x) `=destroy`(s) proc hasValue(self: var Tree, x: int32): bool = diff --git a/tests/destructor/tcaseobj_transitions.nim b/tests/destructor/tcaseobj_transitions.nim index 61464101f..4e203f4ef 100644 --- a/tests/destructor/tcaseobj_transitions.nim +++ b/tests/destructor/tcaseobj_transitions.nim @@ -1,5 +1,5 @@ discard """ - cmd: '''nim c --gc:arc $file''' + cmd: '''nim c --newruntime $file''' output: '''no crash''' """ diff --git a/tests/destructor/tcomplexobjconstr.nim b/tests/destructor/tcomplexobjconstr.nim index aea0ad1fe..fd112b6e2 100644 --- a/tests/destructor/tcomplexobjconstr.nim +++ b/tests/destructor/tcomplexobjconstr.nim @@ -20,16 +20,16 @@ type of true: y*: float var x = new(MyObject2) -doAssert x of MyObject2 -doAssert x.subobj of MyObject1 -doAssert x.more[2] of MyObject1 -doAssert x.more[2] of RootObj +assert x of MyObject2 +assert x.subobj of MyObject1 +assert x.more[2] of MyObject1 +assert x.more[2] of RootObj var y: MyObject2 -doAssert y of MyObject2 -doAssert y.subobj of MyObject1 -doAssert y.more[2] of MyObject1 -doAssert y.more[2] of RootObj +assert y of MyObject2 +assert y.subobj of MyObject1 +assert y.more[2] of MyObject1 +assert y.more[2] of RootObj echo "true" diff --git a/tests/destructor/tconsume_twice.nim b/tests/destructor/tconsume_twice.nim index b0a039e9b..8687b3ce5 100644 --- a/tests/destructor/tconsume_twice.nim +++ b/tests/destructor/tconsume_twice.nim @@ -1,7 +1,7 @@ discard """ cmd: "nim c --newruntime $file" - errormsg: "'=copy' is not available for type ; requires a copy because it's not the last read of 'a'; another read is done here: tconsume_twice.nim(13, 10); routine: consumeTwice" - line: 11 + errormsg: "sink parameter `a` is already consumed at tconsume_twice.nim(11, 10)" + line: 13 """ type Foo = ref object diff --git a/tests/destructor/tcustomseqs.nim b/tests/destructor/tcustomseqs.nim index 17a19f871..4087dc4a8 100644 --- a/tests/destructor/tcustomseqs.nim +++ b/tests/destructor/tcustomseqs.nim @@ -121,7 +121,7 @@ proc createSeq*[T](elems: varargs[T]): myseq[T] = result.data = cast[type(result.data)](alloc(result.cap * sizeof(T))) inc allocCount when supportsCopyMem(T): - copyMem(result.data, addr(elems[0]), result.cap * sizeof(T)) + copyMem(result.data, unsafeAddr(elems[0]), result.cap * sizeof(T)) else: for i in 0..= self.cap: resize(self) @@ -58,22 +60,22 @@ proc add*(self: var mystring; c: char) = inc self.len proc ensure(self: var mystring; newLen: int) = - if newLen >= self.cap: - self.cap = max((self.cap * 3) shr 1, newLen) - if self.cap > 0: - if self.data == nil: inc allocCount - self.data = cast[type(self.data)](realloc(self.data, self.cap + 1)) + if newLen >= cap: + cap = max((cap * 3) shr 1, newLen) + if cap > 0: + if data == nil: inc allocCount + data = cast[type(data)](realloc(data, cap + 1)) proc add*(self: var mystring; y: mystring) = - let newLen = self.len + y.len + let newLen = len + y.len ensure(self, newLen) - copyMem(addr self.data[self.len], y.data, y.data.len + 1) - self.len = newLen + copyMem(addr data[len], y.data, y.data.len + 1) + len = newLen proc create*(lit: string): mystring = let newLen = lit.len ensure(result, newLen) - copyMem(addr result.data[result.len], addr lit[0], newLen + 1) + copyMem(addr result.data[result.len], unsafeAddr lit[0], newLen + 1) result.len = newLen proc `&`*(a, b: mystring): mystring = diff --git a/tests/destructor/tcycle1.nim b/tests/destructor/tcycle1.nim index 8dc552294..c30977433 100644 --- a/tests/destructor/tcycle1.nim +++ b/tests/destructor/tcycle1.nim @@ -50,5 +50,4 @@ proc main = let mem = getOccupiedMem() main() -GC_fullCollect() echo "MEM ", getOccupiedMem() - mem diff --git a/tests/destructor/tcycle2.nim b/tests/destructor/tcycle2.nim index 7b03101fe..c4b297559 100644 --- a/tests/destructor/tcycle2.nim +++ b/tests/destructor/tcycle2.nim @@ -13,24 +13,6 @@ proc main(x: int) = let m = n n.kids.add m -type - NodeA = ref object - s: char - a: array[3, NodeA] - -proc m: NodeA = - result = NodeA(s: 'a') - result.a[0] = result - result.a[1] = result - result.a[2] = result - -proc mainA = - for i in 0..10: - discard m() - let mem = getOccupiedMem() main(90) -mainA() -GC_fullCollect() - echo "MEM ", getOccupiedMem() - mem diff --git a/tests/destructor/tcycle3.nim b/tests/destructor/tcycle3.nim index 8662136e7..a938ded01 100644 --- a/tests/destructor/tcycle3.nim +++ b/tests/destructor/tcycle3.nim @@ -2,8 +2,6 @@ discard """ output: '''BEGIN END END 2 -cpu.nes false -cpu step nes is nil? - false 0''' cmd: '''nim c --gc:orc $file''' """ @@ -61,38 +59,6 @@ proc main = c.run echo "END 2" -# bug #14159 -type - NES = ref object - cpu: CPU - apu: APU - - CPU = ref object - nes: NES - - APU = object - nes: NES - cpu: CPU - -proc initAPU(nes: sink NES): APU {.nosinks.} = - result.nes = nes - result.cpu = nes.cpu - -proc step(cpu: CPU): int = - echo "cpu.nes ", cpu.isNil - echo "cpu step nes is nil? - ", cpu.nes.isNil() - -proc newNES(): NES = - new result - result.cpu = CPU(nes: result) - result.apu = initAPU(result) - -proc bug14159 = - var nesConsole = newNES() - discard nesConsole.cpu.step() - let mem = getOccupiedMem() main() -bug14159() -GC_fullCollect() echo getOccupiedMem() - mem diff --git a/tests/destructor/tdestructor.nim b/tests/destructor/tdestructor.nim index e081eb251..5cfecea4e 100644 --- a/tests/destructor/tdestructor.nim +++ b/tests/destructor/tdestructor.nim @@ -1,27 +1,27 @@ discard """ - output: '''----1 + output: '''---- myobj constructed myobj destroyed -----2 +---- mygeneric1 constructed mygeneric1 destroyed -----3 +---- mygeneric2 constructed mygeneric2 destroyed myobj destroyed -----4 +---- mygeneric3 constructed mygeneric1 destroyed -----5 +---- mydistinctObj constructed myobj destroyed mygeneric2 destroyed -------------------8 -mygeneric1 destroyed -----6 +------------------ +---- +---- myobj destroyed -----7 ----9 +mygeneric1 destroyed +--- myobj destroyed myobj destroyed ''' @@ -33,7 +33,7 @@ type p: pointer proc `=destroy`(o: var TMyObj) = - if o.p != nil: + if o.p != nil: dealloc o.p o.p = nil echo "myobj destroyed" @@ -114,19 +114,19 @@ proc mydistinctObj = echo "mydistinctObj constructed" -echo "----1" +echo "----" myobj() -echo "----2" +echo "----" mygeneric1() -echo "----3" +echo "----" mygeneric2[int](10) -echo "----4" +echo "----" mygeneric3() -echo "----5" +echo "----" mydistinctObj() proc caseobj = @@ -134,16 +134,16 @@ proc caseobj = var o1 = TCaseObj(kind: A, x: TMyGeneric1[int](x: 10)) block: - echo "----6" + echo "----" var o2 = TCaseObj(kind: B, y: open()) block: - echo "----7" + echo "----" var o3 = TCaseObj(kind: D, innerKind: B, r: "test", p: TMyGeneric3[int, float, string](x: 10, y: 1.0, z: "test")) -echo "------------------8" +echo "------------------" caseobj() proc caseobj_test_sink: TCaseObj = @@ -153,15 +153,5 @@ proc caseobj_test_sink: TCaseObj = result = TCaseObj(kind: B, y: open()) -echo "---9" -discard caseobj_test_sink() - -# issue #14315 - -type Vector*[T] = object - x1: int - # x2: T # uncomment will remove error - -# proc `=destroy`*(x: var Vector[int]) = discard # this will remove error -proc `=destroy`*[T](x: var Vector[T]) = discard -var a: Vector[int] # Error: unresolved generic parameter +echo "---" +discard caseobj_test_sink() \ No newline at end of file diff --git a/tests/destructor/tdestructor3.nim b/tests/destructor/tdestructor3.nim index 3f5eb2cc1..b68aedce9 100644 --- a/tests/destructor/tdestructor3.nim +++ b/tests/destructor/tdestructor3.nim @@ -1,6 +1,5 @@ discard """ - output: ''' -assign + output: '''assign destroy destroy 5 @@ -23,18 +22,17 @@ joinable: false type T = object proc `=`(lhs: var T, rhs: T) = - echo "assign" + echo "assign" proc `=destroy`(v: var T) = - echo "destroy" + echo "destroy" proc use(x: T) = discard proc usedToBeBlock = - var v1 = T() - var v2: T = v1 - discard addr(v2) # prevent cursorfication - use v1 + var v1 : T + var v2 : T = v1 + use v1 usedToBeBlock() @@ -106,12 +104,12 @@ test() #------------------------------------------------------------ # Issue #12883 -type +type TopObject = object internal: UniquePtr[int] proc deleteTop(p: ptr TopObject) = - if p != nil: + if p != nil: `=destroy`(p[]) # !!! this operation used to leak the integer deallocshared(p) @@ -119,67 +117,12 @@ proc createTop(): ptr TopObject = result = cast[ptr TopObject](allocShared0(sizeof(TopObject))) result.internal = newUniquePtr(1) -proc test2() = +proc test2() = let x = createTop() echo $x.internal deleteTop(x) -echo "---------------" +echo "---------------" echo "app begin" test2() -echo "app end" - -# bug #14601 - -when true: # D20200607T202043 - type Foo2 = object - x: int - x2: array[10, int] - - type Vec = object - vals: seq[Foo2] - - proc `=destroy`*(a: var Foo2) {.inline.} = - discard - - proc initFoo2(x: int): Foo2 = Foo2(x: x) - - proc add2(v: var Vec, a: Foo2) = # ditto with `a: sink Foo2` - v.vals.add a - - proc add3(v: var Vec, a: Foo2) = # ditto with `a: sink Foo2` - v.vals = @[a] - - proc add4(v: var Vec, a: sink Foo2) = # ditto with `a: sink Foo2` - v.vals.add a - - proc add5(v: var Vec, a: sink Foo2) = # ditto with `a: sink Foo2` - v.vals = @[a] - - proc main2()= - var a: Vec - var b = Foo2(x: 10) - a.add2 b # ok - a.vals.add Foo2(x: 10) # ok - a.add2 initFoo2(x = 10) # ok - a.add2 Foo2(x: 10) # bug - a.add3 initFoo2(x = 10) # ok - a.add3 Foo2(x: 10) # bug - a.add4 initFoo2(x = 10) # ok - a.add4 Foo2(x: 10) # bug - a.add5 initFoo2(x = 10) # ok - a.add5 Foo2(x: 10) # bug - main2() - - - -#------------------------------------------------------------ -# Issue #15825 - -type - Union = string | int | char - -proc run(a: sink Union) = - discard - -run("123") +echo "app end" \ No newline at end of file diff --git a/tests/destructor/tdestructor_too_late.nim b/tests/destructor/tdestructor_too_late.nim index 76d1dde84..d279280ba 100644 --- a/tests/destructor/tdestructor_too_late.nim +++ b/tests/destructor/tdestructor_too_late.nim @@ -1,5 +1,5 @@ discard """ - errormsg: "cannot bind another '=destroy' to: Obj; previous declaration was constructed here implicitly: tdestructor_too_late.nim(7, 16)" + errmsg: "cannot bind another '=destroy' to: Obj; previous declaration was constructed here implicitly: tdestructor_too_late.nim(7, 16)" """ type Obj* = object v*: int diff --git a/tests/destructor/tdont_return_unowned_from_owned.nim b/tests/destructor/tdont_return_unowned_from_owned.nim index ffe87cd76..a726960c6 100644 --- a/tests/destructor/tdont_return_unowned_from_owned.nim +++ b/tests/destructor/tdont_return_unowned_from_owned.nim @@ -1,12 +1,8 @@ discard """ cmd: "nim check --newruntime --hints:off $file" - nimout: ''' -tdont_return_unowned_from_owned.nim(26, 13) Error: assignment produces a dangling ref: the unowned ref lives longer than the owned ref -tdont_return_unowned_from_owned.nim(27, 13) Error: assignment produces a dangling ref: the unowned ref lives longer than the owned ref -tdont_return_unowned_from_owned.nim(31, 10) Error: cannot return an owned pointer as an unowned pointer; use 'owned(RootRef)' as the return type -tdont_return_unowned_from_owned.nim(43, 10) Error: cannot return an owned pointer as an unowned pointer; use 'owned(Obj)' as the return type -tdont_return_unowned_from_owned.nim(46, 10) Error: cannot return an owned pointer as an unowned pointer; use 'owned(Obj)' as the return type -tdont_return_unowned_from_owned.nim(49, 6) Error: type mismatch: got + nimout: '''tdont_return_unowned_from_owned.nim(36, 10) Error: cannot return an owned pointer as an unowned pointer; use 'owned(Obj)' as the return type +tdont_return_unowned_from_owned.nim(39, 10) Error: cannot return an owned pointer as an unowned pointer; use 'owned(Obj)' as the return type +tdont_return_unowned_from_owned.nim(42, 6) Error: type mismatch: got but expected one of: proc new[T](a: var ref T; finalizer: proc (x: ref T) {.nimcall.}) first type mismatch at position: 2 @@ -14,21 +10,18 @@ proc new[T](a: var ref T; finalizer: proc (x: ref T) {.nimcall.}) 2 other mismatching symbols have been suppressed; compile with --showAllMismatches:on to see them expression: new(result) -tdont_return_unowned_from_owned.nim(49, 6) Error: illformed AST: +tdont_return_unowned_from_owned.nim(42, 6) Error: illformed AST: +tdont_return_unowned_from_owned.nim(50, 13) Error: assignment produces a dangling ref: the unowned ref lives longer than the owned ref +tdont_return_unowned_from_owned.nim(51, 13) Error: assignment produces a dangling ref: the unowned ref lives longer than the owned ref +tdont_return_unowned_from_owned.nim(55, 10) Error: cannot return an owned pointer as an unowned pointer; use 'owned(RootRef)' as the return type ''' - errormsg: "illformed AST:" + errormsg: "cannot return an owned pointer as an unowned pointer; use 'owned(RootRef)' as the return type" + line: 55 """ -proc testA(result: var (RootRef, RootRef)) = - let r: owned RootRef = RootRef() - result[0] = r - result[1] = RootRef() -proc testB(): RootRef = - let r: owned RootRef = RootRef() - result = r @@ -46,11 +39,17 @@ proc newObjB(): Obj = result = Obj() proc newObjC(): Obj = - new(result) # illFormedAst raises GlobalError, - # without pipeline parsing, it needs to placed at the end - # in case that it disturbs other errors + new(result) let a = newObjA() let b = newObjB() let c = newObjC() +proc testA(result: var (RootRef, RootRef)) = + let r: owned RootRef = RootRef() + result[0] = r + result[1] = RootRef() + +proc testB(): RootRef = + let r: owned RootRef = RootRef() + result = r diff --git a/tests/destructor/tfinalizer.nim b/tests/destructor/tfinalizer.nim index eb2cd09af..02a5cef7e 100644 --- a/tests/destructor/tfinalizer.nim +++ b/tests/destructor/tfinalizer.nim @@ -1,6 +1,6 @@ discard """ cmd: "nim c --gc:arc $file" - output: '''Foo(field: "Dick Laurent", k: ka, x: 0.0) + output: '''Foo(field: Dick Laurent, k: ka, x: 0.0) Nobody is dead Dick Laurent is dead''' """ diff --git a/tests/destructor/tgcdestructors.nim b/tests/destructor/tgcdestructors.nim index 07a3731a0..7169daaf1 100644 --- a/tests/destructor/tgcdestructors.nim +++ b/tests/destructor/tgcdestructors.nim @@ -1,5 +1,5 @@ discard """ - cmd: '''nim c -d:nimAllocStats --gc:arc $file''' + cmd: '''nim c -d:nimAllocStats --newruntime $file''' output: '''hi ho ha @@ -10,7 +10,7 @@ a: @[4, 2, 3] 0 30 true -(allocCount: 27, deallocCount: 27)''' +(allocCount: 41, deallocCount: 41)''' """ include system / ansi_c diff --git a/tests/destructor/tglobaldestructor.nim b/tests/destructor/tglobaldestructor.nim index 4d002a092..403f670a0 100644 --- a/tests/destructor/tglobaldestructor.nim +++ b/tests/destructor/tglobaldestructor.nim @@ -1,5 +1,5 @@ discard """ - cmd: '''nim c --gc:arc $file''' + cmd: '''nim c --newruntime $file''' output: '''(v: 42) igotdestroyed''' """ diff --git a/tests/destructor/tgotoexceptions4.nim b/tests/destructor/tgotoexceptions4.nim index b2b481256..918169084 100644 --- a/tests/destructor/tgotoexceptions4.nim +++ b/tests/destructor/tgotoexceptions4.nim @@ -4,9 +4,7 @@ discard """ caught in fun caughtsome msgMyExcept in finally -caught1 -123 -123''' +caught1''' """ when true: @@ -40,21 +38,3 @@ when true: except CatchableError: echo "caught1" funB() - -# bug #13782 - -import strutils -var n = 123 - -try: n = parseInt("xxx") -except: discard - -echo n - -proc sameTestButForLocalVar = - var n = 123 - try: n = parseInt("xxx") - except: discard - echo n - -sameTestButForLocalVar() diff --git a/tests/destructor/tgotoexceptions5.nim b/tests/destructor/tgotoexceptions5.nim deleted file mode 100644 index 695aab0a4..000000000 --- a/tests/destructor/tgotoexceptions5.nim +++ /dev/null @@ -1,45 +0,0 @@ -discard """ - output: ''' -before -swallowed -before -swallowed B -''' - cmd: "nim c --gc:arc --exceptions:goto -d:ssl $file" -""" - -# bug #13599 -proc main() = - try: - echo "before" - raise newException(CatchableError, "foo") - except AssertionDefect: - echo "caught" - echo "after" - -try: - main() -except: - echo "swallowed" - -proc mainB() = - try: - echo "before" - raise newException(CatchableError, "foo") - # except CatchableError: # would work - except AssertionDefect: - echo "caught" - except: - raise - echo "after" - -try: - mainB() -except: - echo "swallowed B" - -# bug #14647 -import httpclient - -newAsyncHttpClient().close() - diff --git a/tests/destructor/tgotoexceptions6.nim b/tests/destructor/tgotoexceptions6.nim deleted file mode 100644 index 7c01f6a52..000000000 --- a/tests/destructor/tgotoexceptions6.nim +++ /dev/null @@ -1,10 +0,0 @@ -discard """ - cmd: "nim c --gc:arc --exceptions:goto $file" - outputsub: "Error: unhandled exception: virus detected [ValueError]" - exitcode: "1" -""" - -# bug #13436 -proc foo = - raise newException(ValueError, "virus detected") -foo() diff --git a/tests/destructor/tgotoexceptions7.nim b/tests/destructor/tgotoexceptions7.nim deleted file mode 100644 index 6e564a044..000000000 --- a/tests/destructor/tgotoexceptions7.nim +++ /dev/null @@ -1,48 +0,0 @@ -discard """ - cmd: "nim c --gc:arc --exceptions:goto --panics:off $file" - output: '''prevented! -caught -AssertionDefect -900''' -""" - -type - E = enum - kindA, kindB - Obj = object - case kind: E - of kindA: s: string - of kindB: i: int - - ObjA = ref object of RootObj - ObjB = ref object of ObjA - -proc takeRange(x: range[0..4]) = discard - -proc bplease(x: ObjB) = discard - -proc helper = doAssert(false) - -proc main(i: int) = - var obj = Obj(kind: kindA, s: "abc") - obj.kind = kindB - obj.i = 2 - try: - var objA = ObjA() - bplease(ObjB(objA)) - except ObjectConversionDefect: - echo "prevented!" - - try: - takeRange(i) - except RangeDefect: - echo "caught" - - try: - helper() - except AssertionDefect: - echo "AssertionDefect" - - echo i * i - -main(30) diff --git a/tests/destructor/tgotoexceptions8.nim b/tests/destructor/tgotoexceptions8.nim deleted file mode 100644 index 8ed2ed0ba..000000000 --- a/tests/destructor/tgotoexceptions8.nim +++ /dev/null @@ -1,76 +0,0 @@ -discard """ - output: '''A -B -X -inner finally -Y -outer finally -msg1 -msg2 -finally2 -finally1 -true''' - cmd: "nim c --gc:arc $file" -""" - -# bug #13668 - -proc main = - try: - try: - raise newException(IOError, "IOError") - - except: - echo "A" - raise newException(CatchableError, "CatchableError") - - except: - echo "B" - #discard - -proc mainB = - try: - try: - raise newException(IOError, "IOError") - - except: - echo "X" - raise newException(CatchableError, "CatchableError") - finally: - echo "inner finally" - - except: - echo "Y" - #discard - finally: - echo "outer finally" - -main() -mainB() - -when true: - #bug 7204 - proc nested_finally = - try: - raise newException(KeyError, "msg1") - except KeyError as ex: - echo ex.msg - try: - # pop exception - raise newException(ValueError, "msg2") # push: exception stack (1 entry) - except: - echo getCurrentExceptionMsg() - # pop exception (except) - finally: - echo "finally2" - # pop exception (except KeyError as ex) - finally: - echo "finally1" - - nested_finally() - -# bug #14925 -proc test(b: bool) = - echo b - -test(try: true except: false) diff --git a/tests/destructor/tmatrix.nim b/tests/destructor/tmatrix.nim index 98ca95c94..a3bd59df3 100644 --- a/tests/destructor/tmatrix.nim +++ b/tests/destructor/tmatrix.nim @@ -96,16 +96,14 @@ proc info = allocCount = 0 deallocCount = 0 -proc copy(a: Matrix): Matrix = a - proc test1 = var a = matrix(5, 5, 1.0) - var b = copy a + var b = a var c = a + b proc test2 = var a = matrix(5, 5, 1.0) - var b = copy a + var b = a var c = -a proc test3 = diff --git a/tests/destructor/tmisc_destructors.nim b/tests/destructor/tmisc_destructors.nim index 082cb0f78..53c67e34b 100644 --- a/tests/destructor/tmisc_destructors.nim +++ b/tests/destructor/tmisc_destructors.nim @@ -21,13 +21,11 @@ proc `=sink`(dest: var Foo, src: Foo) = proc `=`(dest: var Foo, src: Foo) = assign_counter.inc -proc createFoo(): Foo = Foo(boo: 0) - proc test(): auto = - var a, b = createFoo() + var a,b : Foo return (a, b, Foo(boo: 5)) -var (ag, bg, _) = test() +var (a, b, _) = test() doAssert assign_counter == 0 doAssert sink_counter == 0 diff --git a/tests/destructor/tmove_objconstr.nim b/tests/destructor/tmove_objconstr.nim index a583a1704..5b2198e51 100644 --- a/tests/destructor/tmove_objconstr.nim +++ b/tests/destructor/tmove_objconstr.nim @@ -8,7 +8,7 @@ test destroyed 0 4 Pony is dying!''' joinable: false -targets: "c" +target: "C" """ # bug #4214 @@ -50,7 +50,7 @@ proc `=destroy`(o: var Pony) = echo "Pony is dying!" proc getPony: Pony = - result = Pony(name: "Sparkles") + result.name = "Sparkles" iterator items(p: Pony): int = for i in 1..4: @@ -112,7 +112,7 @@ proc myfunc2(x, y: int): tuple[a: MySeqNonCopyable, b:int, c:MySeqNonCopyable] = var cc = newMySeq(y, 5.0) (a: case x: of 1: - let (z1, z2) = myfunc(x, y) + let (z1, z2) = myfunc(x,y) z2 elif x > 5: raise newException(ValueError, "new error") else: newMySeq(x, 1.0), @@ -178,7 +178,7 @@ proc myfuncLoop(x: int): MySeqNonCopyable = discard myfuncLoop(3) #------------------------------------------------------------ -# Move into table via openArray +# Move into table via openarray #------------------------------------------------------------ type diff --git a/tests/destructor/tnewruntime_misc.nim b/tests/destructor/tnewruntime_misc.nim index 21c70557d..263ea1bd4 100644 --- a/tests/destructor/tnewruntime_misc.nim +++ b/tests/destructor/tnewruntime_misc.nim @@ -7,8 +7,7 @@ axc ... destroying GenericObj[T] GenericObj[system.int] test -(allocCount: 12, deallocCount: 10) -3''' +(allocCount: 17, deallocCount: 15)''' """ import system / ansi_c @@ -25,13 +24,8 @@ putEnv("HEAPTRASHING", "Indeed") let s1 = getAllocStats() - -proc newTableOwned[A, B](initialSize = defaultInitialSize): owned(TableRef[A, B]) = - new(result) - result[] = initTable[A, B](initialSize) - proc main = - var w = newTableOwned[string, owned Node]() + var w = newTable[string, owned Node]() w["key"] = Node(field: "value") echo w["key"][] echo getEnv("HEAPTRASHING") @@ -137,19 +131,4 @@ proc xx(xml: string): MyObject = discard xx("test") - -# Windows has 1 extra allocation in `getEnv` - there it allocates parameter to -# `_wgetenv` (WideCString). Therefore subtract by 1 to match other OSes' -# allocation. -when defined(windows): - import std/importutils - privateAccess(AllocStats) - echo getAllocStats() - s1 - AllocStats(allocCount: 1, deallocCount: 1) -else: - echo getAllocStats() - s1 - -# bug #13457 -var s = "abcde" -s.setLen(3) - -echo s.cstring.len +echo getAllocStats() - s1 diff --git a/tests/destructor/tnewruntime_strutils.nim b/tests/destructor/tnewruntime_strutils.nim index 9c8d41973..9afb507f7 100644 --- a/tests/destructor/tnewruntime_strutils.nim +++ b/tests/destructor/tnewruntime_strutils.nim @@ -1,12 +1,8 @@ discard """ valgrind: true - cmd: '''nim c -d:nimAllocStats --gc:arc -d:useMalloc $file''' + cmd: '''nim c -d:nimAllocStats --newruntime -d:useMalloc $file''' output: ''' -@[(input: @["KXSC", "BGMC"]), (input: @["PXFX"]), (input: @["WXRQ", "ZSCZD"])] -14 -First tasks completed. -Second tasks completed. -test1''' +@[(input: @["KXSC", "BGMC"]), (input: @["PXFX"]), (input: @["WXRQ", "ZSCZD"])]''' """ import strutils, os, std / wordwrap @@ -41,7 +37,7 @@ bug12899() proc nonStaticTests = doAssert formatBiggestFloat(1234.567, ffDecimal, -1) == "1234.567000" - doAssert formatBiggestFloat(1234.567, ffDecimal, 0) == "1235." # bugs 8242, 12586 + doAssert formatBiggestFloat(1234.567, ffDecimal, 0) == "1235" # bugs 8242, 12586 doAssert formatBiggestFloat(1234.567, ffDecimal, 1) == "1234.6" doAssert formatBiggestFloat(0.00000000001, ffDecimal, 11) == "0.00000000001" doAssert formatBiggestFloat(0.00000000001, ffScientific, 1, ',') in @@ -215,40 +211,3 @@ staticTests() # bug #12965 let xaa = @[""].join() let xbb = @["", ""].join() - -# bug #16365 - -# Task 1: -when true: - # Task 1_a: - var test_string_a = "name_something" - echo test_string_a.len() - let new_len_a = test_string_a.len - "_something".len() - test_string_a.setLen new_len_a - - echo "First tasks completed." - -# Task 2: -when true: - # Task 2_a - var test_string: string - let some_string = "something" - for i in some_string.items: - test_string.add $i - - # Task 2_b - var test_string_b = "name_something" - let new_len_b = test_string_b.len - "_something".len() - test_string_b.setLen new_len_b - - echo "Second tasks completed." - -# bug #17450 -proc main = - var i = 1 - echo: - block: - "test" & $i - -main() - diff --git a/tests/destructor/topttree.nim b/tests/destructor/topttree.nim index 8cf757e8b..fa5495689 100644 --- a/tests/destructor/topttree.nim +++ b/tests/destructor/topttree.nim @@ -1,5 +1,4 @@ discard """ - disabled: i386 output: '''10.0 60.0 90.0 diff --git a/tests/destructor/towned_binary_tree.nim b/tests/destructor/towned_binary_tree.nim index fb635e7c6..3ec80badf 100644 --- a/tests/destructor/towned_binary_tree.nim +++ b/tests/destructor/towned_binary_tree.nim @@ -1,7 +1,7 @@ discard """ - cmd: '''nim c -d:nimAllocStats --gc:arc $file''' - output: '''31665 -(allocCount: 33334, deallocCount: 33334)''' + cmd: '''nim c -d:nimAllocStats --newruntime $file''' + output: '''331665 +(allocCount: 333335, deallocCount: 333335)''' """ # bug #11053 @@ -72,7 +72,7 @@ proc main() = cur = 5'i32 res = 0 - for i in 1 ..< 100000: + for i in 1 ..< 1000000: let a = i mod 3 cur = (cur * 57 + 43) mod 10007 case a: diff --git a/tests/destructor/tprevent_assign.nim b/tests/destructor/tprevent_assign.nim index 4c484ebc1..108ccc371 100644 --- a/tests/destructor/tprevent_assign.nim +++ b/tests/destructor/tprevent_assign.nim @@ -1,5 +1,5 @@ discard """ - errormsg: "'=copy' is not available for type ; requires a copy because it's not the last read of 'otherTree'" + errormsg: "'=' is not available for type ; requires a copy because it's not the last read of 'otherTree'" line: 29 """ diff --git a/tests/destructor/tprevent_assign2.nim b/tests/destructor/tprevent_assign2.nim index fd1a711db..0e4481710 100644 --- a/tests/destructor/tprevent_assign2.nim +++ b/tests/destructor/tprevent_assign2.nim @@ -1,5 +1,5 @@ discard """ - errormsg: "'=copy' is not available for type ; requires a copy because it's not the last read of 'otherTree'" + errormsg: "'=' is not available for type ; requires a copy because it's not the last read of 'otherTree'" file: "tprevent_assign2.nim" line: 48 """ @@ -18,7 +18,7 @@ proc createTree(x: int): Foo = proc take2(a, b: sink Foo) = echo a.x, " ", b.x -when false: +proc allowThis() = var otherTree: Foo try: for i in 0..3: @@ -51,5 +51,5 @@ proc preventThis() = else: discard -#allowThis() +allowThis() preventThis() diff --git a/tests/destructor/tprevent_assign3.nim b/tests/destructor/tprevent_assign3.nim index b9bd40fa9..a8a35ea5e 100644 --- a/tests/destructor/tprevent_assign3.nim +++ b/tests/destructor/tprevent_assign3.nim @@ -1,5 +1,5 @@ discard """ - errormsg: "'=copy' is not available for type ; requires a copy because it's not the last read of 'otherTree'" + errormsg: "'=' is not available for type ; requires a copy because it's not the last read of 'otherTree'" file: "tprevent_assign3.nim" line: 46 """ @@ -18,7 +18,7 @@ proc createTree(x: int): Foo = proc take2(a, b: sink Foo) = echo a.x, " ", b.x -when false: +proc allowThis() = var otherTree: Foo try: for i in 0..3: @@ -47,7 +47,7 @@ proc preventThis2() = finally: echo otherTree -#allowThis() +allowThis() preventThis2() diff --git a/tests/destructor/trecursive.nim b/tests/destructor/trecursive.nim index e7afa6ba9..55e67f52a 100644 --- a/tests/destructor/trecursive.nim +++ b/tests/destructor/trecursive.nim @@ -32,29 +32,3 @@ proc test1() = echo "test1 OK" test1() - -#------------------------------------------------------------------------------ -# issue #14217 - -type - MyObject = object - p: ptr int - -proc `=destroy`(x: var MyObject) = - if x.p != nil: - deallocShared(x.p) - -proc `=`(x: var MyObject, y: MyObject) {.error.} - -proc newMyObject(i: int): MyObject = - result.p = createShared(int) - result.p[] = i - -proc test: seq[MyObject] = - for i in 0..3: - let x = newMyObject(i) - result.add x - -var x = test() -for i in 0..3: - doAssert(x[i].p[] == i) diff --git a/tests/destructor/tselect.nim b/tests/destructor/tselect.nim index c22bf7203..9262b47d4 100644 --- a/tests/destructor/tselect.nim +++ b/tests/destructor/tselect.nim @@ -1,9 +1,6 @@ discard """ output: '''abcsuffix -xyzsuffix -destroy foo 2 -destroy foo 1 -''' +xyzsuffix''' cmd: '''nim c --gc:arc $file''' """ @@ -27,24 +24,3 @@ proc test(param: string; cond: bool) = test("suffix", true) test("suffix", false) - - - -#-------------------------------------------------------------------- -# issue #13659 - -type - Foo = ref object - data: int - parent: Foo - -proc `=destroy`(self: var type(Foo()[])) = - echo "destroy foo ", self.data - for i in self.fields: i.reset - -proc getParent(self: Foo): Foo = self.parent - -var foo1 = Foo(data: 1) -var foo2 = Foo(data: 2, parent: foo1) - -foo2.getParent.data = 1 \ No newline at end of file diff --git a/tests/destructor/tsetjmp_raise.nim b/tests/destructor/tsetjmp_raise.nim index 3a9803f39..b6078ada2 100644 --- a/tests/destructor/tsetjmp_raise.nim +++ b/tests/destructor/tsetjmp_raise.nim @@ -1,5 +1,5 @@ discard """ - outputsub: "index 2 not in 0 .. 0 [IndexDefect]" + outputsub: "index 2 not in 0 .. 0 [IndexError]" exitcode: 1 cmd: "nim c --gc:arc --exceptions:setjmp $file" """ diff --git a/tests/destructor/tsimpleclosure.nim b/tests/destructor/tsimpleclosure.nim index 9626dd6f8..4916f4bab 100644 --- a/tests/destructor/tsimpleclosure.nim +++ b/tests/destructor/tsimpleclosure.nim @@ -1,11 +1,11 @@ discard """ - cmd: '''nim c -d:nimAllocStats --gc:arc $file''' + cmd: '''nim c -d:nimAllocStats --newruntime $file''' output: '''a b 70 hello hello hello -(allocCount: 3, deallocCount: 3)''' +(allocCount: 4, deallocCount: 4)''' """ import system / ansi_c diff --git a/tests/destructor/ttuple.nim b/tests/destructor/ttuple.nim index d0ea72c60..5a2126105 100644 --- a/tests/destructor/ttuple.nim +++ b/tests/destructor/ttuple.nim @@ -2,7 +2,7 @@ discard """ output: '''5.0 10.0 =destroy -=destroy +=destroy ''' """ diff --git a/tests/destructor/tuse_ownedref_after_move.nim b/tests/destructor/tuse_ownedref_after_move.nim index 69348d530..46540837c 100644 --- a/tests/destructor/tuse_ownedref_after_move.nim +++ b/tests/destructor/tuse_ownedref_after_move.nim @@ -1,6 +1,6 @@ discard """ cmd: '''nim c --newruntime $file''' - errormsg: "'=copy' is not available for type ; requires a copy because it's not the last read of ':envAlt.b1'; routine: main" + errormsg: "'=' is not available for type ; requires a copy because it's not the last read of ':envAlt.b1'; another read is done here: tuse_ownedref_after_move.nim(52, 4)" line: 48 """ diff --git a/tests/destructor/tuse_result_prevents_sinks.nim b/tests/destructor/tuse_result_prevents_sinks.nim index e74c16da3..37b5af9b2 100644 --- a/tests/destructor/tuse_result_prevents_sinks.nim +++ b/tests/destructor/tuse_result_prevents_sinks.nim @@ -1,6 +1,6 @@ discard """ output: "" - targets: "c" + target: "C" """ # bug #9594 @@ -17,20 +17,15 @@ proc `=sink`(self: var Foo; other: Foo) = proc `=destroy`(self: var Foo) = discard -template preventCursorInference(x) = - let p = addr(x) - proc test(): Foo = result = Foo() let temp = result - preventCursorInference temp doAssert temp.i > 0 return result proc testB(): Foo = result = Foo() let temp = result - preventCursorInference temp doAssert temp.i > 0 discard test() diff --git a/tests/destructor/tv2_cast.nim b/tests/destructor/tv2_cast.nim index 6fa419996..9c05b2ae1 100644 --- a/tests/destructor/tv2_cast.nim +++ b/tests/destructor/tv2_cast.nim @@ -1,113 +1,10 @@ discard """ + cmd: '''nim c --newruntime $file''' output: '''@[1] @[116, 101, 115, 116] -@[1953719668, 875770417] -destroying O1''' - cmd: '''nim c --gc:arc --expandArc:main --expandArc:main1 --expandArc:main2 --expandArc:main3 --hints:off --assertions:off $file''' - nimout: ''' ---expandArc: main - -var - data - :tmpD - :tmpD_1 - :tmpD_2 -data = - `=wasMoved`(:tmpD) - `=copy`(:tmpD, cast[string]( - :tmpD_2 = encode(cast[seq[byte]]( - :tmpD_1 = newString(100) - :tmpD_1)) - :tmpD_2)) - :tmpD -`=destroy`(:tmpD_2) -`=destroy_1`(:tmpD_1) -`=destroy_1`(data) --- end of expandArc ------------------------ ---expandArc: main1 - -var - s - data - :tmpD - :tmpD_1 -s = newString(100) -data = - `=wasMoved`(:tmpD) - `=copy`(:tmpD, cast[string]( - :tmpD_1 = encode(toOpenArrayByte(s, 0, len(s) - 1)) - :tmpD_1)) - :tmpD -`=destroy`(:tmpD_1) -`=destroy_1`(data) -`=destroy_1`(s) --- end of expandArc ------------------------ ---expandArc: main2 - -var - s - data - :tmpD - :tmpD_1 -s = newSeq(100) -data = - `=wasMoved`(:tmpD) - `=copy`(:tmpD, cast[string]( - :tmpD_1 = encode(s) - :tmpD_1)) - :tmpD -`=destroy`(:tmpD_1) -`=destroy_1`(data) -`=destroy`(s) --- end of expandArc ------------------------ ---expandArc: main3 - -var - data - :tmpD - :tmpD_1 - :tmpD_2 -data = - `=wasMoved`(:tmpD) - `=copy`(:tmpD, cast[string]( - :tmpD_2 = encode do: - :tmpD_1 = newSeq(100) - :tmpD_1 - :tmpD_2)) - :tmpD -`=destroy`(:tmpD_2) -`=destroy`(:tmpD_1) -`=destroy_1`(data) --- end of expandArc ------------------------ -''' +@[1953719668, 875770417]''' """ -func encode*(src: openArray[byte]): seq[byte] = - result = newSeq[byte](src.len) - -template compress*(src: string): string = - cast[string](encode(cast[seq[byte]](src))) - -proc main = - let data = compress(newString(100)) -main() - -proc main1 = - var - s = newString(100) - let data = cast[string](encode(s.toOpenArrayByte(0, s.len-1))) -main1() - -proc main2 = - var - s = newSeq[byte](100) - let data = cast[string](encode(s)) -main2() - -proc main3 = - let data = cast[string](encode(newSeq[byte](100))) -main3() - # bug #11018 discard cast[seq[uint8]](@[1]) discard cast[seq[uint8]]("test") @@ -123,26 +20,4 @@ echo a #issue 11204 var ac {.compileTime.} = @["a", "b"] -const bc = ac.len - - -type - O = object of RootRef - i: int - - O1 = object of O - O2 = object of O - -proc `=destroy`(o: var O) = - echo "destroying O" - -proc `=destroy`(o: var O1) = - echo "destroying O1" - -proc `=destroy`(o: var O2) = - echo "destroying O2" - -proc test = - let o3 = cast[ref O2]((ref O1)()) - -test() +const bc = ac.len \ No newline at end of file diff --git a/tests/destructor/tv2_raise.nim b/tests/destructor/tv2_raise.nim index 66b0aec30..828d0a396 100644 --- a/tests/destructor/tv2_raise.nim +++ b/tests/destructor/tv2_raise.nim @@ -2,7 +2,7 @@ discard """ valgrind: true cmd: '''nim c -d:nimAllocStats --newruntime $file''' output: '''OK 3 -(allocCount: 7, deallocCount: 4)''' +(allocCount: 8, deallocCount: 3)''' """ import strutils, math diff --git a/tests/destructor/twasmoved_error.nim b/tests/destructor/twasmoved_error.nim deleted file mode 100644 index 1cd57e3df..000000000 --- a/tests/destructor/twasmoved_error.nim +++ /dev/null @@ -1,37 +0,0 @@ -discard """ - cmd: '''nim c --mm:arc $file''' - errormsg: "'=wasMoved' is not available for type ; routine: main" -""" - -# bug #19291 - -const - screenWidth = 800 - screenHeight = 450 - -var - ready = false -type - Game = object - -proc `=destroy`(x: var Game) = - assert ready, "Window is already opened" - ready = false - -proc `=sink`(x: var Game; y: Game) {.error.} -proc `=copy`(x: var Game; y: Game) {.error.} -proc `=wasMoved`(x: var Game) {.error.} - -proc initGame(width, height: int32, title: string): Game = - assert not ready, "Window is already closed" - ready = true - -proc update(x: Game) = discard - -proc main = - var g = initGame(screenWidth, screenHeight, "Tetris raylib") - g.update() - var g2 = g - echo "hello" - -main() diff --git a/tests/destructor/twidgets_unown.nim b/tests/destructor/twidgets_unown.nim index 8653d5c28..1d2f26f2a 100644 --- a/tests/destructor/twidgets_unown.nim +++ b/tests/destructor/twidgets_unown.nim @@ -2,7 +2,7 @@ discard """ cmd: '''nim c -d:nimAllocStats --newruntime $file''' output: '''button clicked! -(allocCount: 6, deallocCount: 6)''' +(allocCount: 9, deallocCount: 9)''' """ import system / ansi_c diff --git a/tests/discard/tdiscardable.nim b/tests/discard/tdiscardable.nim index 69cb9f6a1..032050139 100644 --- a/tests/discard/tdiscardable.nim +++ b/tests/discard/tdiscardable.nim @@ -65,48 +65,3 @@ proc main2() = main1() main2() - -block: # bug #13583 - block: - proc hello(): int {.discardable.} = 12 - - iterator test(): int {.closure.} = - while true: - hello() - - let t = test - - block: - proc hello(): int {.discardable.} = 12 - - iterator test(): int {.closure.} = - while true: - block: - yield 12 - hello() - - let t = test - doAssert t() == 12 - - block: - proc hello(): int {.discardable.} = 12 - - iterator test(): int {.closure.} = - while true: - yield 12 - hello() - - let t = test - doAssert t() == 12 - -block: - proc bar(): string {.discardable.} = - "15" - - proc foo(): int = - while true: - raise newException(ValueError, "check") - 12 - - doAssertRaises(ValueError): - doAssert foo() == 12 diff --git a/tests/discard/tillegaldiscardtypes.nim b/tests/discard/tillegaldiscardtypes.nim deleted file mode 100644 index b7877bcd2..000000000 --- a/tests/discard/tillegaldiscardtypes.nim +++ /dev/null @@ -1,14 +0,0 @@ -discard """ - cmd: "nim check $file" - errormsg: "statement returns no value that can be discarded" - nimout: ''' -tillegaldiscardtypes.nim(11, 3) Error: statement returns no value that can be discarded -tillegaldiscardtypes.nim(12, 3) Error: statement returns no value that can be discarded -''' -""" - -proc b(v: int) = # bug #21360 - discard @[] - discard [] - -b(0) \ No newline at end of file diff --git a/tests/discard/tneedsdiscard.nim b/tests/discard/tneedsdiscard.nim index 75cd9d2df..d9483947f 100644 --- a/tests/discard/tneedsdiscard.nim +++ b/tests/discard/tneedsdiscard.nim @@ -1,5 +1,5 @@ discard """ - errormsg: '''expression 'open(f, "arg.txt", fmRead, -1)' is of type 'bool' and has to be used (or discarded); start of expression here: tneedsdiscard.nim(7, 3)''' + errormsg: '''expression 'open(f, "arg.txt", fmRead, -1)' is of type 'bool' and has to be discarded; start of expression here: tneedsdiscard.nim(7, 3)''' line: 10 """ diff --git a/tests/discard/tneedsdiscard_in_for.nim b/tests/discard/tneedsdiscard_in_for.nim index 7685bd577..499b06009 100644 --- a/tests/discard/tneedsdiscard_in_for.nim +++ b/tests/discard/tneedsdiscard_in_for.nim @@ -1,5 +1,5 @@ discard """ - errormsg: '''expression 'premultiply(app.gradient[i])' is of type 'Rgba8' and has to be used (or discarded)''' + errormsg: '''expression 'premultiply(app.gradient[i])' is of type 'Rgba8' and has to be discarded''' line: 22 """ @@ -8,7 +8,7 @@ type Rgba8 = object proc premultiply*(c: var Rgba8): var Rgba8 = - return c + discard type App = ref object diff --git a/tests/discard/tvoidcontext.nim b/tests/discard/tvoidcontext.nim index 9e2b913ad..25e0d4fdf 100644 --- a/tests/discard/tvoidcontext.nim +++ b/tests/discard/tvoidcontext.nim @@ -1,5 +1,5 @@ discard """ - errormsg: '''expression '"invalid"' is of type 'string' and has to be used (or discarded)''' + errormsg: '''expression '"invalid"' is of type 'string' and has to be discarded''' line: 12 """ diff --git a/tests/distinct/t7165.nim b/tests/distinct/t7165.nim deleted file mode 100644 index b16c29c0e..000000000 --- a/tests/distinct/t7165.nim +++ /dev/null @@ -1,15 +0,0 @@ - -type - Table[K, V] = object - key: K - val: V - - MyTable = distinct Table[string, int] - MyTableRef = ref MyTable - -proc newTable[K, V](): ref Table[K, V] = discard - -proc newMyTable: MyTableRef = - MyTableRef(newTable[string, int]()) # <--- error here - -discard newMyTable() diff --git a/tests/distinct/tdistinct.nim b/tests/distinct/tdistinct.nim index 8ec083020..2c0196745 100644 --- a/tests/distinct/tdistinct.nim +++ b/tests/distinct/tdistinct.nim @@ -1,5 +1,4 @@ discard """ - targets: "c js" output: ''' tdistinct 25 @@ -8,7 +7,6 @@ false false false Foo -foo ''' """ @@ -108,96 +106,3 @@ type FooD = distinct int proc `<=`(a, b: FooD): bool {.borrow.} for f in [FooD(0): "Foo"]: echo f - -block tRequiresInit: - template accept(x) = - static: doAssert compiles(x) - - template reject(x) = - static: doAssert not compiles(x) - - type - Foo = object - x: string - - DistinctFoo {.requiresInit, borrow: `.`.} = distinct Foo - DistinctString {.requiresInit.} = distinct string - - reject: - var foo: DistinctFoo - foo.x = "test" - doAssert foo.x == "test" - - accept: - let foo = DistinctFoo(Foo(x: "test")) - doAssert foo.x == "test" - - reject: - var s: DistinctString - s = "test" - doAssert string(s) == "test" - - accept: - let s = DistinctString("test") - doAssert string(s) == "test" - -block: #17322 - type - A[T] = distinct string - - proc foo(a: var A) = - a.string.add "foo" - - type - B = distinct A[int] - - var b: B - foo(A[int](b)) - echo A[int](b).string - b.string.add "bar" - assert b.string == "foobar" - -type Foo = distinct string - -template main() = - # xxx put everything here to test under RT + VM - block: # bug #12282 - block: - proc test() = - var s: Foo - s.string.add('c') - doAssert s.string == "c" # was failing - test() - - block: - proc add(a: var Foo, b: char) {.borrow.} - proc test() = - var s: Foo - s.add('c') - doAssert s.string == "c" # was ok - test() - - block: - proc add(a: var Foo, b: char) {.borrow.} - proc test() = - var s: string - s.Foo.add('c') - doAssert s.string == "c" # was failing - test() - block: #18061 - type - A = distinct (0..100) - B = A(0) .. A(10) - proc test(b: B) = discard - let - a = A(10) - b = B(a) - test(b) - - proc test(a: A) = discard - discard cast[B](A(1)) - var c: B - - -static: main() -main() diff --git a/tests/distinct/tdistinct_issues.nim b/tests/distinct/tdistinct_issues.nim index 747cf0b8d..ce71344d0 100644 --- a/tests/distinct/tdistinct_issues.nim +++ b/tests/distinct/tdistinct_issues.nim @@ -65,17 +65,3 @@ block t9322: proc mystr(s: string) = echo s mystr($Fix("apr")) - - -block: # bug #13517 - type MyUint64 = distinct uint64 - - proc `==`(a: MyUint64, b: uint64): bool = uint64(a) == b - - block: - doAssert MyUint64.high is MyUint64 - doAssert MyUint64.high == 18446744073709551615'u64 - - static: - doAssert MyUint64.high is MyUint64 - doAssert MyUint64.high == 18446744073709551615'u64 diff --git a/tests/distinct/tnil.nim b/tests/distinct/tnil.nim index b54c07432..5bdb97f37 100644 --- a/tests/distinct/tnil.nim +++ b/tests/distinct/tnil.nim @@ -1,21 +1,29 @@ +discard """ +output: ''' +1 +0 +0 +''' +""" {.experimental: "notnil".} type MyPointer = distinct pointer MyString = distinct string MyInt = distinct int -proc foo(a: MyPointer): int = +proc foo(a: MyPointer) = # workaround a Windows 'repr' difference: - cast[int](a) + echo cast[int](a) -doAssert foo(cast[MyPointer](1)) == 1 -doAssert foo(cast[MyPointer](nil)) == 0 -doAssert foo(MyPointer(nil)) == 0 +foo(cast[MyPointer](1)) +foo(cast[MyPointer](nil)) +foo(nil) var p: MyPointer p = cast[MyPointer](1) p = cast[MyPointer](nil) p = nil.MyPointer +p = nil var i: MyInt i = 1.MyInt diff --git a/tests/distros/tdistros_detect.nim b/tests/distros/tdistros_detect.nim deleted file mode 100644 index 9639cfeb9..000000000 --- a/tests/distros/tdistros_detect.nim +++ /dev/null @@ -1,21 +0,0 @@ -import distros - -discard """ - exitcode: 0 - output: "" -""" - -when defined(windows): - doAssert detectOs(Windows) == true - doAssert detectOs(Linux) == false - doAssert detectOs(MacOSX) == false - -when defined(linux): - doAssert detectOs(Linux) == true - doAssert detectOs(Windows) == false - doAssert detectOs(MacOSX) == false - -when defined(macosx): - doAssert detectOs(MacOSX) == true - doAssert detectOs(Windows) == false - doAssert detectOs(Linux) == false diff --git a/tests/dll/client.nim b/tests/dll/client.nim index 62697569f..90ca05149 100644 --- a/tests/dll/client.nim +++ b/tests/dll/client.nim @@ -1,4 +1,6 @@ discard """ + output: "Done" + disabled: "freebsd" cmd: "nim $target --debuginfo --hints:on --define:useNimRtl $options $file" """ @@ -36,8 +38,5 @@ proc eval(n: PNode): int = for i in 0..100_000: discard eval(buildTree(2)) -# bug https://forum.nim-lang.org/t/8176; Error: ambiguous identifier: 'nimrtl' -import std/strutils -doAssert join(@[1, 2]) == "12" -doAssert join(@[1.5, 2.5]) == "1.52.5" -doAssert join(@["a", "bc"]) == "abc" +echo "Done" + diff --git a/tests/dll/nimhcr_0_3.nim b/tests/dll/nimhcr_0_3.nim index 183424e11..56f66e08c 100644 --- a/tests/dll/nimhcr_0_3.nim +++ b/tests/dll/nimhcr_0_3.nim @@ -14,6 +14,5 @@ let c = makeCounter() afterCodeReload: echo " 0: after - closure iterator: ", c() echo " 0: after - closure iterator: ", c() - echo " 0: after - c_2 = ", c_2 proc getInt*(): int = return g_1 + g_2.len diff --git a/tests/dll/nimhcr_2_1.nim b/tests/dll/nimhcr_2_1.nim index 705ed6d5a..faafb1f76 100644 --- a/tests/dll/nimhcr_2_1.nim +++ b/tests/dll/nimhcr_2_1.nim @@ -7,8 +7,6 @@ type let g_2* = @[Type2(data: 2), Type2(data: 3)][1..^1] # should have a length of 1 -const c_2* = [1, 2, 3] # testing that a complext const object is properly exported - var a: tuple[str: string, i: int] a.str = " 2: random string" echo a.str diff --git a/tests/dll/nimhcr_integration.nim b/tests/dll/nimhcr_integration.nim index ac34f1f85..64f6bb708 100644 --- a/tests/dll/nimhcr_integration.nim +++ b/tests/dll/nimhcr_integration.nim @@ -1,5 +1,5 @@ discard """ - disabled: "true" + disabled: "macosx" output: ''' main: HELLO! main: hasAnyModuleChanged? true @@ -35,7 +35,6 @@ max mutual recursion reached! bar 0: after - closure iterator: 0 0: after - closure iterator: 1 - 0: after - c_2 = [1, 2, 3] main: after The answer is: 9 main: hasAnyModuleChanged? true @@ -54,20 +53,6 @@ done ''' """ -#[ -xxx disabled: "openbsd" because it would otherwise give: -/home/build/Nim/lib/nimhcr.nim(532) hcrInit -/home/build/Nim/lib/nimhcr.nim(503) initModules -/home/build/Nim/lib/nimhcr.nim(463) initPointerData -/home/build/Nim/lib/nimhcr.nim(346) hcrRegisterProc -/home/build/Nim/lib/pure/reservedmem.nim(223) setLen -/home/build/Nim/lib/pure/reservedmem.nim(97) setLen -/home/build/Nim/lib/pure/includes/oserr.nim(94) raiseOSError -Error: unhandled exception: Not supported [OSError] - -After instrumenting code, the stacktrace actually points to the call to `check mprotect` -]# - ## This is perhaps the most complex test in the nim test suite - calling the ## compiler on the file itself with the same set or arguments and reloading ## parts of the program at runtime! In the same folder there are a few modules @@ -112,7 +97,6 @@ proc compileReloadExecute() = # binary triggers rebuilding itself here it shouldn't rebuild the main module - # that would lead to replacing the main binary executable which is running! let cmd = commandLineParams()[0..^1].join(" ").replace(" --forceBuild") - doAssert cmd.len > 0 let (stdout, exitcode) = execCmdEx(cmd) if exitcode != 0: echo "COMPILATION ERROR!" @@ -167,4 +151,4 @@ update 0 update 1 update 2 -echo "done" \ No newline at end of file +echo "done" diff --git a/tests/dll/nimhcr_unit.nim b/tests/dll/nimhcr_unit.nim index 0b924bdf7..f539a53c8 100644 --- a/tests/dll/nimhcr_unit.nim +++ b/tests/dll/nimhcr_unit.nim @@ -1,6 +1,4 @@ discard """ -disabled: "openbsd" -disabled: "netbsd" output: ''' fastcall_proc implementation #1 10 11 diff --git a/tests/dll/server.nim b/tests/dll/server.nim index dd4606298..2b7791d4b 100644 --- a/tests/dll/server.nim +++ b/tests/dll/server.nim @@ -1,7 +1,6 @@ discard """ action: compile cmd: "nim $target --debuginfo --hints:on --define:useNimRtl --app:lib $options $file" -batchable: false """ type diff --git a/tests/effects/tcast_as_pragma.nim b/tests/effects/tcast_as_pragma.nim deleted file mode 100644 index 1de61333e..000000000 --- a/tests/effects/tcast_as_pragma.nim +++ /dev/null @@ -1,18 +0,0 @@ -discard """ - cmd: "nim c $file" - action: "compile" -""" - -proc taggy() {.tags: RootEffect.} = discard - -proc m {.raises: [], tags: [].} = - {.cast(noSideEffect).}: - echo "hi" - - {.cast(raises: []).}: - raise newException(ValueError, "bah") - - {.cast(tags: []).}: - taggy() - -m() diff --git a/tests/effects/tdiagnostic_messages.nim b/tests/effects/tdiagnostic_messages.nim deleted file mode 100644 index b1acf8c5c..000000000 --- a/tests/effects/tdiagnostic_messages.nim +++ /dev/null @@ -1,37 +0,0 @@ -discard """ - nimoutFull: true - action: "reject" - cmd: "nim r --hint:Conf:off $file" - nimout: ''' -tdiagnostic_messages.nim(36, 6) Error: 'a' can have side effects -> tdiagnostic_messages.nim(37, 30) Hint: 'a' calls `.sideEffect` 'callWithSideEffects' ->> tdiagnostic_messages.nim(29, 6) Hint: 'callWithSideEffects' called by 'a' ->>> tdiagnostic_messages.nim(31, 34) Hint: 'callWithSideEffects' calls `.sideEffect` 'indirectCallViaVarParam' ->>>> tdiagnostic_messages.nim(25, 6) Hint: 'indirectCallViaVarParam' called by 'callWithSideEffects' ->>>>> tdiagnostic_messages.nim(26, 7) Hint: 'indirectCallViaVarParam' calls routine via hidden pointer indirection ->>> tdiagnostic_messages.nim(32, 33) Hint: 'callWithSideEffects' calls `.sideEffect` 'indirectCallViaPointer' ->>>> tdiagnostic_messages.nim(27, 6) Hint: 'indirectCallViaPointer' called by 'callWithSideEffects' ->>>>> tdiagnostic_messages.nim(28, 32) Hint: 'indirectCallViaPointer' calls routine via pointer indirection ->>> tdiagnostic_messages.nim(33, 3) Hint: 'callWithSideEffects' calls `.sideEffect` 'myEcho' ->>>> tdiagnostic_messages.nim(24, 6) Hint: 'myEcho' called by 'callWithSideEffects' ->>> tdiagnostic_messages.nim(34, 3) Hint: 'callWithSideEffects' accesses global state 'globalVar' ->>>> tdiagnostic_messages.nim(23, 5) Hint: 'globalVar' accessed by 'callWithSideEffects' - -''' -""" - -var globalVar = 0 -proc myEcho(a: string) {.sideEffect.} = discard -proc indirectCallViaVarParam(call: var proc(): int {.nimcall.}): int = - call() -proc indirectCallViaPointer(call: pointer): int = - cast[ptr proc(): int](call)[]() -proc callWithSideEffects(): int = - var p = proc (): int {.nimcall.} = 0 - discard indirectCallViaVarParam(p) - discard indirectCallViaPointer(addr p) - myEcho "" - globalVar - -func a: int = - discard callWithSideEffects() diff --git a/tests/effects/teffects1.nim b/tests/effects/teffects1.nim index caa8907c3..8f827110c 100644 --- a/tests/effects/teffects1.nim +++ b/tests/effects/teffects1.nim @@ -1,10 +1,8 @@ discard """ - cmd: "nim check --hint:Conf:off --hint:XDeclaredButNotUsed:off $file" - nimout: ''' -teffects1.nim(17, 28) template/generic instantiation from here -''' + errormsg: "can raise an unlisted exception: ref IOError" + file: "io.nim" """ -{.push warningAsError[Effect]: on.} + type TObj {.pure, inheritable.} = object TObjB = object of TObj @@ -14,29 +12,8 @@ type proc forw: int {. .} -proc lier(): int {.raises: [IO2Error].} = #[tt.Hint - ^ 'lier' cannot raise 'IO2Error' [XCannotRaiseY] ]# - writeLine stdout, "arg" #[tt.Error - ^ writeLine stdout, ["arg"] can raise an unlisted exception: ref IOError ]# +proc lier(): int {.raises: [IO2Error].} = + writeLine stdout, "arg" proc forw: int = raise newException(IOError, "arg") - -{.push raises: [Defect].} - -type - MyProcType* = proc(x: int): string #{.raises: [ValueError, Defect].} - -proc foo(x: int): string {.nimcall, raises: [ValueError].} = - if x > 9: - raise newException(ValueError, "Use single digit") - $x - -var p: MyProcType = foo #[tt.Error - ^ -type mismatch: got but expected 'MyProcType = proc (x: int): string{.closure.}' - Calling convention mismatch: got '{.nimcall.}', but expected '{.closure.}'. -.raise effects differ -]# -{.pop.} -{.pop.} diff --git a/tests/effects/teffects10.nim b/tests/effects/teffects10.nim deleted file mode 100644 index 8193b394a..000000000 --- a/tests/effects/teffects10.nim +++ /dev/null @@ -1,12 +0,0 @@ -discard """ -action: compile -""" - -# https://github.com/nim-lang/Nim/issues/15495 - -proc f() {.raises: [].} = - var a: proc () - var b: proc () - swap(a, b) - -f() diff --git a/tests/effects/teffects11.nim b/tests/effects/teffects11.nim deleted file mode 100644 index 20b7026ab..000000000 --- a/tests/effects/teffects11.nim +++ /dev/null @@ -1,21 +0,0 @@ -discard """ -action: compile -errormsg: "type mismatch: got " -line: 21 -""" - -type - Effect1 = object - Effect2 = object - Effect3 = object - -proc test(fnc: proc(x: int): void {.forbids: [Effect2].}) {.tags: [Effect1, Effect3, RootEffect].} = - fnc(1) - -proc t1(x: int): void = echo $x -proc t2(x: int): void {.tags: [Effect2].} = echo $x -proc t3(x: int): void {.tags: [Effect3].} = echo $x - -test(t1) -test(t3) -test(t2) diff --git a/tests/effects/teffects12.nim b/tests/effects/teffects12.nim deleted file mode 100644 index 5f5499c38..000000000 --- a/tests/effects/teffects12.nim +++ /dev/null @@ -1,52 +0,0 @@ -discard """ -action: compile -""" - -import std/locks - -type - Test2Effect* = object - Test2* = object - value2*: int - Test1Effect* = object - Test1* = object - value1*: int - Main* = object - test1Lock: Lock - test1: Test1 - test2Lock: Lock - test2: Test2 - -proc `=copy`(obj1: var Test2, obj2: Test2) {.error.} -proc `=copy`(obj1: var Test1, obj2: Test1) {.error.} -proc `=copy`(obj1: var Main, obj2: Main) {.error.} - -proc withTest1(main: var Main, - fn: proc(test1: var Test1) {.gcsafe, forbids: [Test1Effect].}) {.gcsafe, tags: [Test1Effect, RootEffect].} = - withLock(main.test1Lock): - fn(main.test1) - -proc withTest2(main: var Main, - fn: proc(test1: var Test2) {.gcsafe, forbids: [Test2Effect].}) {.gcsafe, tags: [Test2Effect, RootEffect].} = - withLock(main.test2Lock): - fn(main.test2) - -proc newMain(): Main = - var test1lock: Lock - initLock(test1Lock) - var test2lock: Lock - initLock(test2Lock) - var main = Main(test1Lock: move(test1Lock), test1: Test1(value1: 1), - test2Lock: move(test2Lock), test2: Test2(value2: 2)) - main.withTest1(proc(test1: var Test1) = test1.value1 += 1) - main.withTest2(proc(test2: var Test2) = test2.value2 += 1) - move main - -var main = newMain() -main.withTest1(proc(test1: var Test1) = - test1.value1 += 1 - main.withTest2(proc(test2: var Test2) = test2.value2 += 1) -) - -main.withTest1(proc(test1: var Test1) {.tags: [].} = echo $test1.value1) -main.withTest2(proc(test2: var Test2) {.tags: [].} = echo $test2.value2) diff --git a/tests/effects/teffects13.nim b/tests/effects/teffects13.nim deleted file mode 100644 index 73082f997..000000000 --- a/tests/effects/teffects13.nim +++ /dev/null @@ -1,19 +0,0 @@ -discard """ -action: compile -errormsg: "writeSomething() has an illegal effect: WriteIO" -line: 19 -""" - -type - IO = object of RootEffect ## input/output effect - ReadIO = object of IO ## input effect - WriteIO = object of IO ## output effect - -proc readSomething(): string {.tags: [ReadIO].} = "" -proc writeSomething(): void {.tags: [WriteIO].} = echo "..." - -proc noWritesPlease() {.forbids: [WriteIO].} = - # this is OK: - echo readSomething() - # the compiler prevents this: - writeSomething() diff --git a/tests/effects/teffects14.nim b/tests/effects/teffects14.nim deleted file mode 100644 index 6291d9569..000000000 --- a/tests/effects/teffects14.nim +++ /dev/null @@ -1,15 +0,0 @@ -discard """ -action: compile -errormsg: "func1() has an illegal effect: IO" -line: 15 -""" - -type IO = object ## input/output effect -proc func1(): string {.tags: [IO].} = discard -proc func2(): string = discard - -proc no_IO_please() {.forbids: [IO].} = - # this is OK because it didn't define any tag: - discard func2() - # the compiler prevents this: - let y = func1() diff --git a/tests/effects/teffects15.nim b/tests/effects/teffects15.nim deleted file mode 100644 index c3079cdbc..000000000 --- a/tests/effects/teffects15.nim +++ /dev/null @@ -1,18 +0,0 @@ -discard """ -action: compile -errormsg: "method1(c) has an illegal effect: IO" -line: 18 -""" - -type - IO = object ## input/output effect - CustomObject* = object of RootObj - text: string - -method method1(obj: var CustomObject): string {.tags: [IO].} = obj.text & "." -method method2(obj: var CustomObject): string = obj.text & ":" - -proc noIO() {.forbids: [IO].} = - var c = CustomObject(text: "a") - echo c.method2() - echo c.method1() diff --git a/tests/effects/teffects16.nim b/tests/effects/teffects16.nim deleted file mode 100644 index ee8f782a3..000000000 --- a/tests/effects/teffects16.nim +++ /dev/null @@ -1,20 +0,0 @@ -discard """ -action: compile -errormsg: "writeSomething(\"a\") can have an unlisted effect: WriteIO" -line: 20 -""" - -type - IO = object of RootEffect ## input/output effect - ReadIO = object of IO ## input effect - WriteIO = object of IO ## output effect - LogIO = object of IO ## another output effect - -proc readSomething(): string {.tags: [ReadIO].} = "" -proc writeSomething(msg: string): void {.tags: [WriteIO].} = echo msg -proc logSomething(msg: string): void {.tags: [LogIo].} = echo msg - -proc noWritesPlease() {.forbids: [WriteIO], tags: [LogIO, ReadIO].} = - echo readSomething() - logSomething("a") - writeSomething("a") diff --git a/tests/effects/teffects17.nim b/tests/effects/teffects17.nim deleted file mode 100644 index 5e6b83896..000000000 --- a/tests/effects/teffects17.nim +++ /dev/null @@ -1,17 +0,0 @@ -discard """ -action: compile -errormsg: "writeSomething(\"a\") has an illegal effect: WriteIO" -line: 17 -""" - -type - IO = object of RootEffect ## input/output effect - ReadIO = object of IO ## input effect - WriteIO = object of IO ## output effect - -proc readSomething(): string {.tags: [ReadIO].} = "" -proc writeSomething(msg: string): void {.tags: [WriteIO].} = echo msg - -proc illegalEffectNegation() {.forbids: [WriteIO], tags: [ReadIO, WriteIO].} = - echo readSomething() - writeSomething("a") diff --git a/tests/effects/teffects18.nim b/tests/effects/teffects18.nim deleted file mode 100644 index 576e76635..000000000 --- a/tests/effects/teffects18.nim +++ /dev/null @@ -1,19 +0,0 @@ -discard """ -action: compile -errormsg: "type mismatch: got " -line: 19 -""" - -type MyEffect = object -type ProcType1 = proc (i: int): void {.forbids: [MyEffect].} -type ProcType2 = proc (i: int): void - -proc testFunc(p: ProcType1): void = p(1) - -proc toBeCalled(i: int): void {.tags: [MyEffect].} = echo $i - -let emptyTags = proc(i: int): void {.tags: [].} = echo $i -let noTags: ProcType2 = proc(i: int): void = toBeCalled(i) - -testFunc(emptyTags) -testFunc(noTags) diff --git a/tests/effects/teffects19.nim b/tests/effects/teffects19.nim deleted file mode 100644 index 6b4ab0819..000000000 --- a/tests/effects/teffects19.nim +++ /dev/null @@ -1,23 +0,0 @@ -discard """ -action: compile -errormsg: "type mismatch: got " -line: 23 -""" - -type MyEffect = object -type ProcType1 = proc (i: int): void {.forbids: [MyEffect].} -type ProcType2 = proc (i: int): void - -proc caller1(p: ProcType1): void = p(1) -proc caller2(p: ProcType2): void = p(1) - -proc effectful(i: int): void {.tags: [MyEffect].} = echo $i -proc effectless(i: int): void {.forbids: [MyEffect].} = echo $i - -proc toBeCalled1(i: int): void = effectful(i) -proc toBeCalled2(i: int): void = effectless(i) - -caller1(toBeCalled2) -caller2(toBeCalled1) -caller2(toBeCalled2) -caller1(toBeCalled1) diff --git a/tests/effects/teffects2.nim b/tests/effects/teffects2.nim index 777a4cebc..e4b50aba5 100644 --- a/tests/effects/teffects2.nim +++ b/tests/effects/teffects2.nim @@ -2,9 +2,9 @@ discard """ errormsg: "can raise an unlisted exception: ref IOError" line: 19 """ -{.push warningAsError[Effect]: on.} + type - TObj {.pure, inheritable.} = object + TObj = object {.pure, inheritable.} TObjB = object of TObj a, b, c: string @@ -17,4 +17,3 @@ proc lier(): int {.raises: [IOError].} = proc forw: int = raise newException(IOError, "arg") -{.pop.} diff --git a/tests/effects/teffects3.nim b/tests/effects/teffects3.nim index 4c050510a..ee5470c47 100644 --- a/tests/effects/teffects3.nim +++ b/tests/effects/teffects3.nim @@ -4,7 +4,7 @@ discard """ """ type - TObj {.pure, inheritable.} = object + TObj = object {.pure, inheritable.} TObjB = object of TObj a, b, c: string fn: proc (): int {.tags: [].} diff --git a/tests/effects/teffects4.nim b/tests/effects/teffects4.nim index b875754b6..88cc0efa9 100644 --- a/tests/effects/teffects4.nim +++ b/tests/effects/teffects4.nim @@ -4,7 +4,7 @@ discard """ """ type - TObj {.pure, inheritable.} = object + TObj = object {.pure, inheritable.} TObjB = object of TObj a, b, c: string fn: proc (): int {.tags: [ReadIOEffect].} diff --git a/tests/effects/teffects6.nim b/tests/effects/teffects6.nim index d3af22434..6a4eea155 100644 --- a/tests/effects/teffects6.nim +++ b/tests/effects/teffects6.nim @@ -21,7 +21,7 @@ createMenuItem(s, "Go to definition...", ) -proc noRaise(x: proc()) {.raises: [], effectsOf: x.} = +proc noRaise(x: proc()) {.raises: [].} = # unknown call that might raise anything, but valid: x() @@ -34,23 +34,3 @@ proc use*() = use() - -# bug #12642 -import os - -proc raises() {.raises: Exception.} = discard -proc harmless() {.raises: [].} = discard - -let x = if paramStr(1) == "true": harmless else: raises - -let - choice = 0 - -proc withoutSideEffects(): int = 0 -proc withSideEffects(): int = echo "foo" # the echo causes the side effect - -let procPtr = case choice - of 0: withoutSideEffects - else: withSideEffects - -echo procPtr.repr diff --git a/tests/effects/teffects7.nim b/tests/effects/teffects7.nim index 9b7fbf5f0..1cd144459 100644 --- a/tests/effects/teffects7.nim +++ b/tests/effects/teffects7.nim @@ -1,16 +1,14 @@ discard """ - errormsg: "can raise an unlisted exception: ref ValueError" + errormsg: "can raise an unlisted exception: ref FloatingPointError" line: 10 """ -{.push warningAsError[Effect]: on.} + proc foo() {.raises: [].} = try: discard except KeyError: - raise newException(ValueError, "foo") + raise newException(FloatingPointError, "foo") except Exception: discard foo() - -{.pop.} diff --git a/tests/effects/teffects8.nim b/tests/effects/teffects8.nim index 359b3a1df..fb3c088d6 100644 --- a/tests/effects/teffects8.nim +++ b/tests/effects/teffects8.nim @@ -2,7 +2,7 @@ discard """ errormsg: "can raise an unlisted exception: Exception" line: 10 """ -{.push warningAsError[Effect]: on.} + proc foo() {.raises: [].} = try: discard @@ -10,4 +10,3 @@ proc foo() {.raises: [].} = raise foo() -{.pop.} diff --git a/tests/effects/teffects9.nim b/tests/effects/teffects9.nim deleted file mode 100644 index d92668fe9..000000000 --- a/tests/effects/teffects9.nim +++ /dev/null @@ -1,22 +0,0 @@ -discard """ - errormsg: "can raise an unlisted exception: ref Exception" - line: 16 -""" - -# bug #8481 - -type - ParentObj = ref object of RootObj - DerivedObj = ref object of ParentObj - -method doSome(o: ParentObj) {.base, raises: [].} = - discard - -method doSome(o: DerivedObj) = - raise newException(Exception, "oops, this raised") - -proc thisRaises() {.raises: [].} = - let o = new(DerivedObj) - o.doSome() - -thisRaises() diff --git a/tests/effects/teffectsmisc.nim b/tests/effects/teffectsmisc.nim deleted file mode 100644 index 8fb95b275..000000000 --- a/tests/effects/teffectsmisc.nim +++ /dev/null @@ -1,39 +0,0 @@ -discard """ - output: ''' -printing from adder -''' -""" - -import std/sugar - -block: - proc makeAdder(a: int): (int) -> void = - proc discard_adder(x: int) {.closure.} = - discard a + x - - proc echo_adder(x: int) {.closure.} = - echo("printing from adder") - - if a > 0: - discard_adder - else: - echo_adder - - let newAdder = makeAdder(0) - newAdder(5) - -block: - proc makeAdder(a: int): (int) -> void = - proc discard_adder(x: int) {.closure.} = - discard a + x - - proc echo_adder(x: int) {.closure.} = - echo("printing from adder") - - if a > 0: - echo_adder - else: - discard_adder - - let newAdder = makeAdder(0) - newAdder(5) diff --git a/tests/effects/tfuncs_cannot_mutate.nim b/tests/effects/tfuncs_cannot_mutate.nim deleted file mode 100644 index 9934d27a7..000000000 --- a/tests/effects/tfuncs_cannot_mutate.nim +++ /dev/null @@ -1,35 +0,0 @@ -discard """ - errormsg: "cannot mutate location select(x, z).data within a strict func" - line: 35 -""" - -{.experimental: "strictFuncs".} - -type - Node = ref object - le, ri: Node - data: string - -func insert(x: var seq[Node]; yyy: Node) = - let L = x.len - x.setLen L + 1 - x[L] = yyy - -func len(n: Node): int = - var it = n - while it != nil: - inc result - it = it.ri - -func doNotDistract(n: Node) = - var m = Node(data: "abc") - -func select(a, b: Node): Node = b - -func mutate(n: Node) = - var it = n - let x = it - let y = x - let z = y - - select(x, z).data = "tricky" diff --git a/tests/effects/tfuncs_cannot_mutate2.nim b/tests/effects/tfuncs_cannot_mutate2.nim deleted file mode 100644 index 86f811017..000000000 --- a/tests/effects/tfuncs_cannot_mutate2.nim +++ /dev/null @@ -1,24 +0,0 @@ -discard """ - errormsg: "cannot mutate location x[0].a within a strict func" - line: 12 -""" - -{.experimental: "strictFuncs".} - -func copy[T](x: var openArray[T]; y: openArray[T]) = - for i in 0..high(x): - x[i] = y[i] - - x[0].a = nil - -type - R = ref object - a, b: R - data: string - -proc main = - var a, b: array[3, R] - b = [R(data: "a"), R(data: "b"), R(data: "c")] - copy a, b - -main() diff --git a/tests/effects/tfuncs_cannot_mutate3.nim b/tests/effects/tfuncs_cannot_mutate3.nim deleted file mode 100644 index 029152029..000000000 --- a/tests/effects/tfuncs_cannot_mutate3.nim +++ /dev/null @@ -1,35 +0,0 @@ -discard """ - errormsg: "cannot mutate location kid.parent within a strict func" - line: 16 -""" - -{.experimental: "strictFuncs".} - -type - Node = ref object - name: string - kids: seq[Node] - parent: Node - -func initParents(tree: Node) = - for kid in tree.kids: - kid.parent = tree - initParents(kid) - -proc process(intro: Node): Node = - var tree = Node(name: "root", kids: @[ - intro, - Node(name: "one", kids: @[ - Node(name: "two"), - Node(name: "three"), - ]), - Node(name: "four"), - ]) - initParents(tree) - -proc main() = - var intro = Node(name: "intro") - var tree = process(intro) - echo intro.parent.name - -main() diff --git a/tests/effects/tfuncs_cannot_mutate_simple.nim b/tests/effects/tfuncs_cannot_mutate_simple.nim deleted file mode 100644 index 0ae4a0db9..000000000 --- a/tests/effects/tfuncs_cannot_mutate_simple.nim +++ /dev/null @@ -1,19 +0,0 @@ -discard """ - errormsg: '''cannot mutate location x.data within a strict func''' - line: 15 -""" - -{.experimental: "strictFuncs".} - -# bug #15508 - -type - MyType = ref object - data: string - -func edit(x: MyType) = - x.data = "hello" - -let x = MyType() -x.edit() -echo x.data diff --git a/tests/effects/tgcsafe.nim b/tests/effects/tgcsafe.nim index cfac3ddd8..363624f19 100644 --- a/tests/effects/tgcsafe.nim +++ b/tests/effects/tgcsafe.nim @@ -1,5 +1,5 @@ discard """ - errormsg: "'mainUnsafe' is not GC-safe as it performs an indirect call here" + errormsg: "'mainUnsafe' is not GC-safe" line: 26 cmd: "nim $target --hints:on --threads:on $options $file" """ @@ -13,7 +13,7 @@ proc myproc(i: int) {.gcsafe.} = if isNil(global_proc): return -proc mymap(x: proc ()) {.effectsOf: x.} = +proc mymap(x: proc ()) = x() var diff --git a/tests/effects/tgcsafe2.nim b/tests/effects/tgcsafe2.nim index 6268592a9..07da4e3f8 100644 --- a/tests/effects/tgcsafe2.nim +++ b/tests/effects/tgcsafe2.nim @@ -1,5 +1,5 @@ discard """ - errormsg: '''type mismatch: got ''' + errormsg: '''type mismatch: got ''' line: 11 """ #5620 diff --git a/tests/effects/tgcsafe3.nim b/tests/effects/tgcsafe3.nim index 36ea5112c..5137efe4c 100644 --- a/tests/effects/tgcsafe3.nim +++ b/tests/effects/tgcsafe3.nim @@ -1,5 +1,5 @@ discard """ - errormsg: "'myproc' is not GC-safe as it calls 'global_proc'" + errormsg: "'myproc' is not GC-safe as it accesses 'global_proc' which is a global using GC'ed memory" line: 12 cmd: "nim $target --hints:on --threads:on $options $file" """ diff --git a/tests/effects/tlaxeffects.nim b/tests/effects/tlaxeffects.nim deleted file mode 100644 index 7eedc372a..000000000 --- a/tests/effects/tlaxeffects.nim +++ /dev/null @@ -1,11 +0,0 @@ -discard """ - cmd: "nim $target $options --legacy:laxEffects $file" -""" - - -type - Foo = object - bar: seq[Foo] - -proc `==`(a, b: Foo): bool = - a.bar == b.bar diff --git a/tests/effects/tnestedprocs.nim b/tests/effects/tnestedprocs.nim deleted file mode 100644 index 125896d44..000000000 --- a/tests/effects/tnestedprocs.nim +++ /dev/null @@ -1,63 +0,0 @@ -discard """ - cmd: "nim check --hints:off $file" - nimout: '''tnestedprocs.nim(27, 8) Error: 'inner' can have side effects -> tnestedprocs.nim(29, 13) Hint: 'inner' calls `.sideEffect` 'outer2' ->> tnestedprocs.nim(26, 6) Hint: 'outer2' called by 'inner' - -tnestedprocs.nim(45, 8) Error: 'inner' can have side effects -> tnestedprocs.nim(47, 13) Hint: 'inner' calls `.sideEffect` 'outer6' ->> tnestedprocs.nim(44, 6) Hint: 'outer6' called by 'inner' - -tnestedprocs.nim(58, 41) Error: type mismatch: got but expected 'proc (){.closure, noSideEffect.}' - Pragma mismatch: got '{..}', but expected '{.noSideEffect.}'. -''' - errormsg: "type mismatch: got but expected 'proc (){.closure, noSideEffect.}'" -""" -{.experimental: "strictEffects".} -proc outer {.noSideEffect.} = - proc inner(p: int) = - if p == 0: - outer() - - inner(4) - -outer() - -proc outer2 = - proc inner(p: int) {.noSideEffect.} = - if p == 0: - outer2() - - inner(4) - -outer2() - -proc outer3(p: int) {.noSideEffect.} = - proc inner(p: int) {.noSideEffect.} = - if p == 0: - p.outer3() - - inner(4) - -outer3(5) - -proc outer6 = - proc inner(p: int) {.noSideEffect.} = - if p == 0: - outer6() - - inner(4) - echo "bad" - -outer6() - - -proc outer4 = - proc inner(p: int) {.noSideEffect.} = - if p == 0: - let x: proc () {.noSideEffect.} = outer4 - x() - - inner(4) - -outer4() diff --git a/tests/effects/tnosideeffect.nim b/tests/effects/tnosideeffect.nim deleted file mode 100644 index 9fc2f74d4..000000000 --- a/tests/effects/tnosideeffect.nim +++ /dev/null @@ -1,24 +0,0 @@ -block: # `.noSideEffect` - func foo(bar: proc(): int): int {.effectsOf: bar.} = bar() - var count = 0 - proc fn1(): int = 1 - proc fn2(): int = (count.inc; count) - - template accept(body) = - doAssert compiles(block: - body) - - template reject(body) = - doAssert not compiles(block: - body) - - accept: - func fun1() = discard foo(fn1) - reject: - func fun1() = discard foo(fn2) - - var foo2: type(foo) = foo - accept: - func main() = discard foo(fn1) - reject: - func main() = discard foo2(fn1) diff --git a/tests/effects/toutparam.nim b/tests/effects/toutparam.nim deleted file mode 100644 index 1126aa77e..000000000 --- a/tests/effects/toutparam.nim +++ /dev/null @@ -1,28 +0,0 @@ -discard """ - cmd: '''nim c --warningAsError:Uninit:on --skipCfg --skipParentCfg $file''' - errormsg: "use explicit initialization of 'x' for clarity [Uninit]" - line: 24 - disabled: "true" -""" - -proc gah[T](x: out T) = - x = 3 - -proc main = - var a: array[2, int] - var x: int - gah(x) - a[0] = 3 - a[x] = 3 - echo x - -main() - -proc mainB = - var a: array[2, int] - var x: int - a[0] = 3 - a[x] = 3 - echo x - -mainB() diff --git a/tests/effects/tstrict_caseobjects.nim b/tests/effects/tstrict_caseobjects.nim deleted file mode 100644 index 20bc810e0..000000000 --- a/tests/effects/tstrict_caseobjects.nim +++ /dev/null @@ -1,47 +0,0 @@ -discard """ - errormsg: "field access outside of valid case branch: x.x" - line: 45 -""" - -{.experimental: "strictCaseObjects".} - -type - NodeKind = enum - nkParent, - nkChild - - Node {.acyclic.} = ref object - case kind: NodeKind - of nkParent: - children: seq[Node] - of nkChild: - name: string - -let list = @[Node(kind: nkParent, children: @[]), Node(kind: nkChild, name: "hello")] -for node in list: - case node.kind - of nkChild: - echo $node.name # here this time there is a warning - else: discard - - -type - Foo = object - case b: bool - of false: - s: string - of true: - x: int - -var x = Foo(b: true, x: 4) -case x.b -of true: - echo x.x -of false: - echo "no" - -case x.b -of false: - echo x.x -of true: - echo "no" diff --git a/tests/effects/tstrict_effects.nim b/tests/effects/tstrict_effects.nim deleted file mode 100644 index eee8fb71a..000000000 --- a/tests/effects/tstrict_effects.nim +++ /dev/null @@ -1,27 +0,0 @@ -discard """ - errormsg: "s1 can raise an unlisted exception: CatchableError" - line: 27 -""" - -{.push warningAsError[Effect]: on.} -{.experimental: "strictEffects".} - -# bug #18376 - -{.push raises: [Defect].} -type Call = proc (x: int): int {.gcsafe, raises: [Defect, CatchableError].} - -type Bar* = object - foo*: Call - -proc passOn*(x: Call) = discard - -proc barCal(b: var Bar, s: string, s1: Call) = - #compiler complains that his line can throw CatchableError - passOn s1 - - -proc passOnB*(x: Call) {.effectsOf: x.} = discard - -proc barCal2(b: var Bar, s: string, s1: Call) = - passOnB s1 diff --git a/tests/effects/tstrict_effects2.nim b/tests/effects/tstrict_effects2.nim deleted file mode 100644 index acc0a0540..000000000 --- a/tests/effects/tstrict_effects2.nim +++ /dev/null @@ -1,28 +0,0 @@ -discard """ - errormsg: "can raise an unlisted exception: Exception" - line: 23 -""" - -{.push warningAsError[Effect]: on.} -{.experimental: "strictEffects".} - -# bug #13905 - -proc atoi(v: cstring): cint {.importc: "atoi", cdecl, raises: [].} - -type Conv = proc(v: cstring): cint {.cdecl, raises: [].} - -var x: Conv = atoi - -# bug #17475 - -type - Callback = proc() - -proc f(callback: Callback) {.raises: [].} = - callback() - -proc main = - f(proc () = raise newException(IOError, "IO")) - -main() diff --git a/tests/effects/tstrict_effects3.nim b/tests/effects/tstrict_effects3.nim deleted file mode 100644 index 027b46474..000000000 --- a/tests/effects/tstrict_effects3.nim +++ /dev/null @@ -1,46 +0,0 @@ -discard """ - action: compile -""" - -{.push warningAsError[Effect]: on.} - -{.experimental: "strictEffects".} - -proc fn(a: int, p1, p2: proc()) {.effectsOf: p1.} = - if a == 7: - p1() - if a<0: - raise newException(ValueError, $a) - -proc main() {.raises: [ValueError].} = - fn(1, proc()=discard, proc() = raise newException(IOError, "foo")) -main() - -# bug #19159 - -import macros - -func mkEnter() = - template helper = - discard - when defined pass: - helper() - else: - let ast = getAst(helper()) - - -# bug #6559 -type - SafeFn = proc (): void {. raises: [] } - -proc ok() {. raises: [] .} = discard -proc fail() {. raises: [] .} - -let f1 : SafeFn = ok -let f2 : SafeFn = fail - - -proc fail() = discard -f1() -f2() - diff --git a/tests/effects/tstrict_effects_sort.nim b/tests/effects/tstrict_effects_sort.nim deleted file mode 100644 index 8928ed0d3..000000000 --- a/tests/effects/tstrict_effects_sort.nim +++ /dev/null @@ -1,27 +0,0 @@ -discard """ - errormsg: "cmpE can raise an unlisted exception: Exception" - line: 27 -""" - -{.push warningAsError[Effect]: on.} - -{.experimental: "strictEffects".} - -import algorithm - -type - MyInt = distinct int - -var toSort = @[MyInt 1, MyInt 2, MyInt 3] - -proc cmpN(a, b: MyInt): int = - cmp(a.int, b.int) - -proc harmless {.raises: [].} = - toSort.sort cmpN - -proc cmpE(a, b: MyInt): int {.raises: [Exception].} = - cmp(a.int, b.int) - -proc harmfull {.raises: [].} = - toSort.sort cmpE diff --git a/tests/effects/tstrict_funcs.nim b/tests/effects/tstrict_funcs.nim deleted file mode 100644 index 9d20f5d7e..000000000 --- a/tests/effects/tstrict_funcs.nim +++ /dev/null @@ -1,46 +0,0 @@ -discard """ - cmd: "nim c --experimental:strictFuncs --experimental:views $file" -""" - -import tables, streams, parsecsv - -type - Contig2Reads = TableRef[string, seq[string]] - -proc get_Contig2Reads(sin: Stream, fn: string, contig2len: TableRef[string, int]): Contig2Reads = - result = newTable[string, seq[string]]() - var parser: CsvParser - open(parser, sin, filename = fn, separator = ' ', skipInitialSpace = true) - while readRow(parser, 2): - if contig2len.haskey(parser.row[1]): - mgetOrPut(result, parser.row[1], @[]).add(parser.row[0]) - - - -block: - # issue #15756 - func `&&&`[T](x: var seq[T], y: sink T): seq[T] = - newSeq(result, x.len + 1) - for i in 0..x.len-1: - result[i] = move(x[i]) - result[x.len] = move(y) - - var x = @[0, 1] - let z = x &&& 2 - - -func copy[T](x: var openArray[T]; y: openArray[T]) = - for i in 0..high(x): - x[i] = y[i] - -type - R = ref object - a, b: R - data: string - -proc main = - var a, b: array[3, R] - b = [R(data: "a"), R(data: "b"), R(data: "c")] - copy a, b - -main() diff --git a/tests/effects/tstrict_funcs_imports.nim b/tests/effects/tstrict_funcs_imports.nim deleted file mode 100644 index 53f346236..000000000 --- a/tests/effects/tstrict_funcs_imports.nim +++ /dev/null @@ -1,178 +0,0 @@ -discard """ - cmd: "nim $target $options --hints:on --experimental:strictFuncs --experimental:views --threads:on -d:ssl -d:nimCoroutines $file" - targets: "c" -""" -{.warning[UnusedImport]: off.} - -when defined(linux): - import linenoise - -when defined(nimPreviewSlimSystem): - import std/[ - assertions, - formatfloat, - objectdollar, - syncio, - widestrs, - ] - -import - algorithm, - asyncdispatch, - asyncfile, - asyncfutures, - asynchttpserver, - asyncmacro, - asyncnet, - asyncstreams, - atomics, - base64, - bitops, - browsers, - cgi, - chains, - colors, - complex, - cookies, - coro, - cpuinfo, - cpuload, - critbits, - cstrutils, - deques, - distros, - dynlib, - encodings, - endians, - epoll, - fenv, - hashes, - heapqueue, - hotcodereloading, - htmlgen, - htmlparser, - httpclient, - httpcore, - inotify, - intsets, - json, - kqueue, - lenientops, - lexbase, - lists, - locks, - logging, - macrocache, - macros, - marshal, - math, - md5, - memfiles, - mersenne, - mimetypes, - nativesockets, - net, - nimhcr, - # nimprof, - nre, - oids, - options, - os, - osproc, - parsecfg, - parsecsv, - parsejson, - parseopt, - parsesql, - parseutils, - parsexml, - pathnorm, - pegs, - posix_utils, - prelude, - random, - rationals, - rdstdin, - re, - registry, - reservedmem, - rlocks, - ropes, - rtarrays, - selectors, - sequtils, - sets, - sharedlist, - sharedtables, - ssl_certs, - ssl_config, - stats, - streams, - streamwrapper, - strformat, - strmisc, - strscans, - strtabs, - strutils, - sugar, - tables, - terminal, - threadpool, - times, - typeinfo, - typetraits, - unicode, - unidecode, - unittest, - uri, - volatile, - winlean, - xmlparser, - xmltree - -import experimental/[ - diff, -] - -import packages/docutils/[ - highlite, - rst, - rstast, - rstgen, -] - -import std/[ - compilesettings, - decls, - editdistance, - effecttraits, - enumerate, - enumutils, - exitprocs, - isolation, - jsonutils, - logic, - monotimes, - packedsets, - setutils, - sha1, - socketstreams, - stackframes, - sums, - time_t, - varints, - with, - wordwrap, - wrapnils, -] - -import std/private/[ - asciitables, - decode_helpers, - gitutils, - globs, - miscdollars, - since, - strimpl, - underscored_calls, -] diff --git a/tests/effects/tstrict_funcs_imports_js.nim b/tests/effects/tstrict_funcs_imports_js.nim deleted file mode 100644 index 667887ff0..000000000 --- a/tests/effects/tstrict_funcs_imports_js.nim +++ /dev/null @@ -1,20 +0,0 @@ -discard """ - cmd: "nim $target $options --hints:on --experimental:strictFuncs --experimental:views $file" - targets: "js" -""" -{.warning[UnusedImport]: off.} - -import - asyncjs, - dom, - jsconsole, - jsffi, - jsre - -import std/[ - jsbigints, -] - -import std/private/[ - jsutils, -] diff --git a/tests/effects/tstrictfuncs_misc.nim b/tests/effects/tstrictfuncs_misc.nim deleted file mode 100644 index 8c573bb3a..000000000 --- a/tests/effects/tstrictfuncs_misc.nim +++ /dev/null @@ -1,65 +0,0 @@ -discard """ - action: compile -""" - -{.experimental: "strictFuncs".} - -func sortedFake1[T](a: openArray[T]): seq[T] = - for i in 0 .. a.high: result.add a[i] -func sortedFake2[T](a: openArray[T]): seq[T] = - result = newSeq[T](a.len) - for i in 0 .. a.high: result[i] = a[i] -type Foo1 = object -type Foo2 = ref object -block: - let a1 = sortedFake1([Foo1()]) # ok - let a2 = sortedFake1([Foo2()]) # ok -block: - let a1 = sortedFake2([Foo1()]) # ok - let a2 = sortedFake2([Foo2()]) # error: Error: 'sortedFake2' can have side effects - - -import std/sequtils -type Foob = ref object - x: int -let a1 = zip(@[1,2], @[1,2]) # ok -let a2 = zip(@[Foob(x: 1)], @[Foob(x: 2)]) # error in 1.6.0 RC2, but not 1.4.x - - -# bug #20863 -type - Fooc = ref object - -func twice(foo: Fooc) = - var a = newSeq[Fooc](2) - a[0] = foo # No error. - a[1] = foo # Error: 'twice' can have side effects. - -let foo = Fooc() -twice(foo) - -# bug #17387 -import json - -func parseColumn(columnNode: JsonNode) = - let columnName = columnNode["name"].str - -parseColumn(%*{"a": "b"}) - -type - MyTable = object - data: seq[int] - - JsonNode3 = ref object - fields: MyTable - -proc `[]`(t: MyTable, key: string): int = - result = t.data[0] - -proc `[]`(x: JsonNode3, key: string): int = - result = x.fields[key] - -func parseColumn(columnNode: JsonNode3) = - var columnName = columnNode["test"] - -parseColumn(JsonNode3()) diff --git a/tests/enum/m16462_1.nim b/tests/enum/m16462_1.nim deleted file mode 100644 index 631c63256..000000000 --- a/tests/enum/m16462_1.nim +++ /dev/null @@ -1,3 +0,0 @@ -type - Scancode* {.pure.} = enum - SCANCODE_LEFT = 80 \ No newline at end of file diff --git a/tests/enum/m16462_2.nim b/tests/enum/m16462_2.nim deleted file mode 100644 index 631c63256..000000000 --- a/tests/enum/m16462_2.nim +++ /dev/null @@ -1,3 +0,0 @@ -type - Scancode* {.pure.} = enum - SCANCODE_LEFT = 80 \ No newline at end of file diff --git a/tests/enum/mcrossmodule.nim b/tests/enum/mcrossmodule.nim deleted file mode 100644 index e534a202c..000000000 --- a/tests/enum/mcrossmodule.nim +++ /dev/null @@ -1,6 +0,0 @@ - -type - OtherEnum* = enum - Success, Failed, More - -proc some*(x: OtherEnum): bool = x == Success diff --git a/tests/enum/t16462.nim b/tests/enum/t16462.nim deleted file mode 100644 index 9f38286bb..000000000 --- a/tests/enum/t16462.nim +++ /dev/null @@ -1,5 +0,0 @@ -import m16462_1 except Scancode -import m16462_2 - -# bug #16462 -let a = SCANCODE_LEFT \ No newline at end of file diff --git a/tests/enum/tcrossmodule.nim b/tests/enum/tcrossmodule.nim deleted file mode 100644 index c21072198..000000000 --- a/tests/enum/tcrossmodule.nim +++ /dev/null @@ -1,15 +0,0 @@ -import mcrossmodule - -type - MyEnum = enum - Success - -template t = - doAssert some(Success) - -t() - -block: # legacy support for behavior before overloadableEnums - # warning: ambiguous enum field 'Success' assumed to be of type MyEnum - let x = {Success} - doAssert x is set[MyEnum] diff --git a/tests/enum/tenum.nim b/tests/enum/tenum.nim index 88d85ddcc..8cc578d3c 100644 --- a/tests/enum/tenum.nim +++ b/tests/enum/tenum.nim @@ -6,7 +6,7 @@ ABCDC foo first0second32third64 my value A1my value Bconc2valueCabc4abc -my value A0my value Bconc1valueCabc3abc +my value A0my value Bconc1valueCabc3valueC ''' """ @@ -124,25 +124,25 @@ block tnamedfields: # trick the optimizer with a variable: var x = valueD echo valueA, ord(valueA), valueB, ord(valueB), valueC, valueD, ord(valueD), x - doAssert $x == $valueD, $x - doAssert $x == "abc", $x -block tfakeOptions: + +block toptions: type - TFakeOption = enum - fakeNone, fakeForceFullMake, fakeBoehmGC, fakeRefcGC, fakeRangeCheck, - fakeBoundsCheck, fakeOverflowCheck, fakeNilCheck, fakeAssert, fakeLineDir, - fakeWarns, fakeHints, fakeListCmd, fakeCompileOnly, - fakeSafeCode, # only allow safe code - fakeStyleCheck, fakeOptimizeSpeed, fakeOptimizeSize, fakeGenDynLib, - fakeGenGuiApp, fakeStackTrace + # please make sure we have under 32 options (improves code efficiency!) + TOption = enum + optNone, optForceFullMake, optBoehmGC, optRefcGC, optRangeCheck, + optBoundsCheck, optOverflowCheck, optNilCheck, optAssert, optLineDir, + optWarns, optHints, optListCmd, optCompileOnly, + optSafeCode, # only allow safe code + optStyleCheck, optOptimizeSpeed, optOptimizeSize, optGenDynLib, + optGenGuiApp, optStackTrace - TFakeOptionset = set[TFakeOption] + TOptionset = set[TOption] var - gFakeOptions: TFakeOptionset = {fakeRefcGC, fakeRangeCheck, fakeBoundsCheck, - fakeOverflowCheck, fakeAssert, fakeWarns, fakeHints, fakeLineDir, fakeStackTrace} + gOptions: TOptionset = {optRefcGC, optRangeCheck, optBoundsCheck, + optOverflowCheck, optAssert, optWarns, optHints, optLineDir, optStackTrace} compilerArgs: int gExitcode: int8 @@ -154,25 +154,3 @@ block nonzero: # bug #6959 B C let slice = SomeEnum.low..SomeEnum.high - -block size_one_byte: # bug #15752 - type - Flag = enum - Disabled = 0x00 - Enabled = 0xFF - - static: - assert 1 == sizeof(Flag) - -block: # bug #12589 - when not defined(i386): - type - OGRwkbGeometryType {.size: sizeof(cuint).} = enum - wkbPoint25D = 0x80000001.cuint, wkbLineString25D = 0x80000002, - wkbPolygon25D = 0x80000003 - - proc typ(): OGRwkbGeometryType = - return wkbPoint25D - - when not defined(gcRefc): - doAssert $typ() == "wkbPoint25D" diff --git a/tests/enum/tenum_self.nim b/tests/enum/tenum_self.nim deleted file mode 100644 index 27b1c3204..000000000 --- a/tests/enum/tenum_self.nim +++ /dev/null @@ -1,11 +0,0 @@ -discard """ - errormsg: "1 can't be converted to ErrorFoo" -""" - - -type - Foo = enum - Bar = 0.Foo - - ErrorFoo = enum - eBar = 1.ErrorFoo diff --git a/tests/enum/toverloadable_enums.nim b/tests/enum/toverloadable_enums.nim deleted file mode 100644 index 9bb551467..000000000 --- a/tests/enum/toverloadable_enums.nim +++ /dev/null @@ -1,120 +0,0 @@ -discard """ - output: '''B -0 -E2-B''' -joinable: false -""" - -{.experimental: "overloadableEnums".} - -type - E1 = enum - value1, - value2 - E2 = enum - value1, - value2 = 4 - -const - Lookuptable = [ - E1.value1: "1", - value2: "2" - ] - -when false: - const - Lookuptable: array[E1, string] = [ - value1: "1", - value2: "2" - ] - - -proc p(e: E1): int = - # test that the 'case' statement is smart enough: - case e - of value1: echo "A" - of value2: echo "B" - - -let v = p value2 # ERROR: ambiguous! -# (value2|value2) nkClosedSymChoice -> nkSym - -proc x(p: int) = discard -proc x(p: string) = discard - -proc takeCallback(param: proc(p: int)) = discard - -takeCallback x - -echo ord v - -block: # https://github.com/nim-lang/RFCs/issues/8 - type - Enum1 = enum - A, B, C - Enum2 = enum - A, Z - - proc f(e: Enum1): int = ord(e) - proc g(e: Enum2): int = ord(e) - - proc h(e: Enum1): int = ord(e) - proc h(e: Enum2): int = ord(e) - - let fA = f(A) # Type of A is well defined - let gA = g(A) # Same as above - - let hA1 = h(Enum1.A) # A requires disambiguation - let hA2 = h(Enum2.A) # Similarly - let hA3 = h(B) - let hA4 = h(B) - let x = ord(Enum1.A) # Also - doAssert fA == 0 - doAssert gA == 0 - doAssert hA1 == 0 - doAssert hA2 == 0 - doAssert x == 0 - doAssert hA3 == 1 - doAssert hA4 == 1 - -# bug #18769 -proc g3[T](x: T, e: E2): int = - case e - of value1: echo "E2-A" # Error: type mismatch: got 'E1' for 'value1' but expected 'E2 = enum' - of value2: echo "E2-B" - -let v5 = g3(99, E2.value2) - -block: # only allow enums to overload enums - # mirrors behavior without overloadableEnums - proc foo() = discard - block: - type Foo = enum foo - doAssert foo is Foo - foo() - -import macros -block: # test with macros/templates - type - Enum1 = enum - value01, value02 - Enum2 = enum - value01, value10 - - macro isOneM(a: untyped): bool = - result = newCall(bindSym"==", a, ident"value01") - - macro isOneMS(a: untyped): bool = - result = newCall(bindSym"==", a, bindSym"value01") - - template isOneT(a: untyped): bool = - a == value01 - - let e1 = Enum1.value01 - let e2 = Enum2.value01 - doAssert isOneM(e1) - doAssert isOneM(e2) - doAssert isOneMS(e1) - doAssert isOneMS(e2) - doAssert isOneT(e1) - doAssert isOneT(e2) diff --git a/tests/enum/tredefinition.nim b/tests/enum/tredefinition.nim deleted file mode 100644 index 615ca6b1c..000000000 --- a/tests/enum/tredefinition.nim +++ /dev/null @@ -1,9 +0,0 @@ -discard """ - cmd: '''nim check --hints:off $file''' - action: reject -nimout: ''' -tredefinition.nim(9, 25) Error: redefinition of 'Key_a'; previous declaration here: tredefinition.nim(9, 18) -''' -""" - -type Key* = enum Key_A, Key_a \ No newline at end of file diff --git a/tests/errmsgs/t10251.nim b/tests/errmsgs/t10251.nim deleted file mode 100644 index 19adf02eb..000000000 --- a/tests/errmsgs/t10251.nim +++ /dev/null @@ -1,19 +0,0 @@ -discard """ - action:reject - cmd: "nim check $options $file" - nimout: ''' -t10251.nim(19, 23) Error: redefinition of 'goo1'; previous declaration here: t10251.nim(19, 11) -''' -""" - -# line 10 -type - Enum1 = enum - foo, bar, baz - Enum2 = enum - foo, bar, baz - - -type - Enum3 {.pure.} = enum # fixed (by accident?) in https://github.com/nim-lang/Nim/pull/18263 - goo0, goo1, goo2, goo1 diff --git a/tests/errmsgs/t10376.nim b/tests/errmsgs/t10376.nim index 814c860dc..2ce16d6a2 100644 --- a/tests/errmsgs/t10376.nim +++ b/tests/errmsgs/t10376.nim @@ -1,7 +1,6 @@ discard """ - matrix: "--mm:refc" errormsg: "finalizer must be a direct reference to a proc" - line: 30 + line: 29 """ type diff --git a/tests/errmsgs/t10489_a.nim b/tests/errmsgs/t10489_a.nim index c762ce876..86659f7ac 100644 --- a/tests/errmsgs/t10489_a.nim +++ b/tests/errmsgs/t10489_a.nim @@ -1,5 +1,5 @@ discard """ -errormsg: "invalid type: 'macro (body: untyped): untyped{.noSideEffect, gcsafe.}' for let. Did you mean to call the macro with '()'?" +errormsg: "cannot assign macro 'm' to 'x1'. Did you mean to call the macro with '()'?" line: 9 """ diff --git a/tests/errmsgs/t10489_b.nim b/tests/errmsgs/t10489_b.nim index df05f0e6e..1182b4512 100644 --- a/tests/errmsgs/t10489_b.nim +++ b/tests/errmsgs/t10489_b.nim @@ -1,5 +1,5 @@ discard """ -errormsg: "invalid type: 'macro (body: untyped): untyped{.noSideEffect, gcsafe.}' for const. Did you mean to call the macro with '()'?" +errormsg: "cannot assign macro 'm' to 'x2'. Did you mean to call the macro with '()'?" line: 9 """ diff --git a/tests/errmsgs/t10594.nim b/tests/errmsgs/t10594.nim index d27dd6433..c9506c542 100644 --- a/tests/errmsgs/t10594.nim +++ b/tests/errmsgs/t10594.nim @@ -3,5 +3,5 @@ discard """ line: 7 """ -template foo(v: varargs[int]) = addr v +template foo(v: varargs[int]) = unsafeAddr v foo(1, 2) diff --git a/tests/errmsgs/t10734.nim b/tests/errmsgs/t10734.nim deleted file mode 100644 index 4e73db7cd..000000000 --- a/tests/errmsgs/t10734.nim +++ /dev/null @@ -1,20 +0,0 @@ -discard """ - cmd: "nim check $file" - errormsg: "" - nimout: ''' -t10734.nim(19, 1) Error: invalid indentation -t10734.nim(19, 6) Error: invalid indentation -t10734.nim(20, 7) Error: expression expected, but found '[EOF]' -t10734.nim(18, 5) Error: 'proc' is not a concrete type; for a callback without parameters use 'proc()' -t10734.nim(19, 6) Error: undeclared identifier: 'p' -t10734.nim(19, 6) Error: expression 'p' has no type (or is ambiguous) -t10734.nim(19, 6) Error: 'p' cannot be assigned to -t10734.nim(17, 3) Hint: 'T' is declared but not used [XDeclaredButNotUsed] -''' -""" - -type - T = object - a: -proc p = - case \ No newline at end of file diff --git a/tests/errmsgs/t10735.nim b/tests/errmsgs/t10735.nim deleted file mode 100644 index 307acac2d..000000000 --- a/tests/errmsgs/t10735.nim +++ /dev/null @@ -1,41 +0,0 @@ -discard """ - cmd: "nim check $file" - errormsg: "selector must be of an ordinal type, float or string" - nimout: ''' -t10735.nim(38, 5) Error: 'let' symbol requires an initialization -t10735.nim(39, 10) Error: undeclared identifier: 'pos' -t10735.nim(39, 9) Error: type mismatch: got -but expected one of: -proc `[]`(s: string; i: BackwardsIndex): char - first type mismatch at position: 0 -proc `[]`(s: var string; i: BackwardsIndex): var char - first type mismatch at position: 0 -proc `[]`[I: Ordinal; T](a: T; i: I): T - first type mismatch at position: 0 -proc `[]`[Idx, T; U, V: Ordinal](a: array[Idx, T]; x: HSlice[U, V]): seq[T] - first type mismatch at position: 0 -proc `[]`[Idx, T](a: array[Idx, T]; i: BackwardsIndex): T - first type mismatch at position: 0 -proc `[]`[Idx, T](a: var array[Idx, T]; i: BackwardsIndex): var T - first type mismatch at position: 0 -proc `[]`[T, U: Ordinal](s: string; x: HSlice[T, U]): string - first type mismatch at position: 0 -proc `[]`[T; U, V: Ordinal](s: openArray[T]; x: HSlice[U, V]): seq[T] - first type mismatch at position: 0 -proc `[]`[T](s: openArray[T]; i: BackwardsIndex): T - first type mismatch at position: 0 -proc `[]`[T](s: var openArray[T]; i: BackwardsIndex): var T - first type mismatch at position: 0 -template `[]`(s: string; i: int): char - first type mismatch at position: 0 - -expression: `[]`(buf, pos) -t10735.nim(39, 9) Error: selector must be of an ordinal type, float or string -''' - joinable: false -""" - -let buf: cstring -case buf[pos] -else: - case buf[pos] diff --git a/tests/errmsgs/t12844.nim b/tests/errmsgs/t12844.nim index a274b72b4..999d26255 100644 --- a/tests/errmsgs/t12844.nim +++ b/tests/errmsgs/t12844.nim @@ -1,9 +1,9 @@ discard """ cmd: "nim check $file" -errormsg: "invalid type: 'template (args: varargs[string])' for var. Did you mean to call the template with '()'?" +errormsg: "cannot assign template 'z' to 'y'. Did you mean to call the template with '()'?" nimout: ''' -t12844.nim(11, 7) Error: invalid type: 'template (args: varargs[string])' for const. Did you mean to call the template with '()'? -t12844.nim(12, 5) Error: invalid type: 'template (args: varargs[string])' for var. Did you mean to call the template with '()'?''' +t12844.nim(11, 11) Error: cannot assign template 'z' to 'x'. Did you mean to call the template with '()'? +t12844.nim(12, 9) Error: cannot assign template 'z' to 'y'. Did you mean to call the template with '()'?''' """ template z*(args: varargs[string, `$`]) = diff --git a/tests/errmsgs/t14444.nim b/tests/errmsgs/t14444.nim deleted file mode 100644 index 143b4542e..000000000 --- a/tests/errmsgs/t14444.nim +++ /dev/null @@ -1,14 +0,0 @@ -discard """ - matrix: "--hints:off" - exitcode: "1" - output: ''' -t14444.nim(13) t14444 -fatal.nim(51) sysFatal -Error: unhandled exception: index out of bounds, the container is empty [IndexDefect] -''' -""" - -when true: # bug #14444 - var i: string - i[10] = 'j' - echo i \ No newline at end of file diff --git a/tests/errmsgs/t16654.nim b/tests/errmsgs/t16654.nim deleted file mode 100644 index 749707c06..000000000 --- a/tests/errmsgs/t16654.nim +++ /dev/null @@ -1,12 +0,0 @@ -discard """ - cmd: "nim check $options $file" - errormsg: "type mismatch: got but expected 'float'" -""" - -when true: # bug #16654 - func fn[T](a: T, op: proc(a: T): float) = discard - proc main() = - let v = 1 - proc bar(r: auto): auto = v - fn(1, bar) - main() diff --git a/tests/errmsgs/t17460.nim b/tests/errmsgs/t17460.nim deleted file mode 100644 index e377bc48a..000000000 --- a/tests/errmsgs/t17460.nim +++ /dev/null @@ -1,19 +0,0 @@ -discard """ - cmd: "nim check $options $file" - errormsg: "wrong number of variables" -""" - -iterator xclusters*[T](a: openArray[T]; s: static[int]): array[s, T] {.inline.} = - var result: array[s, T] # iterators have no default result variable - var i = 0 - while i < len(a): - for j, x in mpairs(result): - x = a[(i + j) mod len(a)] - yield result - inc(i) - -proc m = - for (i, j, k) in xclusters([1, 2, 3, 4, 5], 3): - echo i, j, k - -m() \ No newline at end of file diff --git a/tests/errmsgs/t18327.nim b/tests/errmsgs/t18327.nim deleted file mode 100644 index 686a1bd0c..000000000 --- a/tests/errmsgs/t18327.nim +++ /dev/null @@ -1,5 +0,0 @@ -discard """ - errormsg: "parameter 'n' requires a type" -""" - -proc fn3(n) = discard \ No newline at end of file diff --git a/tests/errmsgs/t18886.nim b/tests/errmsgs/t18886.nim deleted file mode 100644 index 8ed160c64..000000000 --- a/tests/errmsgs/t18886.nim +++ /dev/null @@ -1,18 +0,0 @@ -discard """ - cmd: "nim check --hints:off $file" - errormsg: "" - nimout: ''' -t18886.nim(18, 24) Error: ambiguous identifier: 'bar' -- you need a helper proc to disambiguate the following: - t18886.bar: proc (i: ptr int){.noSideEffect, gcsafe.} - t18886.bar: proc (i: ptr char){.noSideEffect, gcsafe.} -''' -""" - -type Foo = (proc(_: pointer): void) - - -proc bar(i: ptr[int]) = discard -proc bar(i: ptr[char]) = discard - - -let fooBar = cast[Foo](bar) \ No newline at end of file diff --git a/tests/errmsgs/t18983.nim b/tests/errmsgs/t18983.nim deleted file mode 100644 index 3451875cb..000000000 --- a/tests/errmsgs/t18983.nim +++ /dev/null @@ -1,7 +0,0 @@ -discard """ - errormsg: "illegal recursion in type 'A'" -""" - -type - A* = A - B = (A,) diff --git a/tests/errmsgs/t19224.nim b/tests/errmsgs/t19224.nim deleted file mode 100644 index 7a9ecb2e7..000000000 --- a/tests/errmsgs/t19224.nim +++ /dev/null @@ -1,12 +0,0 @@ -discard """ -cmd: "nim check --hints:off $file" -errormsg: "" -nimout: ''' -t19224.nim(10, 10) Error: cannot infer element type of items([]) -t19224.nim(12, 10) Error: cannot infer element type of items(@[]) -''' -""" - -for _ in []: discard - -for _ in @[]: discard diff --git a/tests/errmsgs/t19882.nim b/tests/errmsgs/t19882.nim deleted file mode 100644 index 1f2f95ab7..000000000 --- a/tests/errmsgs/t19882.nim +++ /dev/null @@ -1,10 +0,0 @@ - -discard """ - errormsg: "cannot instantiate 'A[T, P]' inside of type definition: 'init'; Maybe generic arguments are missing?" -""" -type A[T,P] = object - b:T - c:P -proc init(): ref A = - new(result) -var a = init() diff --git a/tests/errmsgs/t19882_2.nim b/tests/errmsgs/t19882_2.nim deleted file mode 100644 index 7f3055a5d..000000000 --- a/tests/errmsgs/t19882_2.nim +++ /dev/null @@ -1,5 +0,0 @@ -discard """ - errormsg: "cannot instantiate: 'A[T]'; the object's generic parameters cannot be inferred and must be explicitly given" -""" -type A[T] = object -var a = A() \ No newline at end of file diff --git a/tests/errmsgs/t21257.nim b/tests/errmsgs/t21257.nim deleted file mode 100644 index eecdb1dfe..000000000 --- a/tests/errmsgs/t21257.nim +++ /dev/null @@ -1,20 +0,0 @@ -discard """ - action: compile - cmd: "nim check $file" -""" - -type AC_WINCTRL_Fields* = distinct uint8 - -type AC_STATUSA_WSTATE0* {.pure.} = enum - ABOVE = 0x0, - INSIDE = 0x1, - BELOW = 0x2, - -type AC_WINCTRL_WINTSEL0* {.pure.} = enum - ABOVE = 0x0, - INSIDE = 0x1, - BELOW = 0x2, - OUTSIDE = 0x3, - -proc write*(WINTSEL0: AC_WINCTRL_WINTSEL0 = ABOVE) = - discard diff --git a/tests/errmsgs/t2614.nim b/tests/errmsgs/t2614.nim deleted file mode 100644 index 031ecb9d1..000000000 --- a/tests/errmsgs/t2614.nim +++ /dev/null @@ -1,21 +0,0 @@ -discard """ - cmd: "nim check $options --hints:off $file" - errormsg: "" - nimout: ''' -t2614.nim(19, 27) Error: type mismatch: got but expected 'array[0..1, proc (){.closure.}]' - Calling convention mismatch: got '{.nimcall.}', but expected '{.closure.}'. -t2614.nim(21, 22) Error: type mismatch: got but expected 'seq[proc (){.closure.}]' - Calling convention mismatch: got '{.nimcall.}', but expected '{.closure.}'. -''' -""" - -proc g -proc f = - if false: g() -proc g = - if false: f() - -var a = [f, g] # This works -var b: array[2, proc()] = [f, g] # Error - -var c: seq[proc()] = @[f, g] \ No newline at end of file diff --git a/tests/errmsgs/t5167_4.nim b/tests/errmsgs/t5167_4.nim index dafd7754d..7a263622b 100644 --- a/tests/errmsgs/t5167_4.nim +++ b/tests/errmsgs/t5167_4.nim @@ -1,5 +1,5 @@ discard """ -errormsg: "type mismatch: got " +errormsg: "type mismatch: got " line: 19 """ diff --git a/tests/errmsgs/t5167_5.nim b/tests/errmsgs/t5167_5.nim index ab6f094f3..a9e260845 100644 --- a/tests/errmsgs/t5167_5.nim +++ b/tests/errmsgs/t5167_5.nim @@ -1,5 +1,5 @@ discard """ -cmd: "nim check --mm:refc $file" +cmd: "nim check $file" errormsg: "'t' has unspecified generic parameters" nimout: ''' t5167_5.nim(10, 16) Error: expression 'system' has no type (or is ambiguous) diff --git a/tests/errmsgs/t5282.nim b/tests/errmsgs/t5282.nim deleted file mode 100644 index 4da49d155..000000000 --- a/tests/errmsgs/t5282.nim +++ /dev/null @@ -1,5 +0,0 @@ -discard """ - errormsg: "illegal recursion in type 'x'" -""" - -type x = distinct x diff --git a/tests/errmsgs/t5870.nim b/tests/errmsgs/t5870.nim index 96966bcd7..bcbc9cca9 100644 --- a/tests/errmsgs/t5870.nim +++ b/tests/errmsgs/t5870.nim @@ -1,5 +1,5 @@ discard """ -errormsg: "invalid type: 'SomeRefObj' in this context: 'seq[SomeRefObj]' for const" +errormsg: "invalid type for const: seq[SomeRefObj]" line: 14 """ diff --git a/tests/errmsgs/t6608.nim b/tests/errmsgs/t6608.nim deleted file mode 100644 index 88cbf42fd..000000000 --- a/tests/errmsgs/t6608.nim +++ /dev/null @@ -1,15 +0,0 @@ -discard """ - cmd: "nim c --hints:off $file" - errormsg: "type mismatch: got <>" - nimout: '''t6608.nim(13, 4) Error: type mismatch: got <> -but expected one of: -AcceptCB = proc (s: string){.closure.}''' -""" - -type - AcceptCB = proc (s: string) - -proc x(x: AcceptCB) = - x() - -x() diff --git a/tests/errmsgs/t8064.nim b/tests/errmsgs/t8064.nim deleted file mode 100644 index e7941e36a..000000000 --- a/tests/errmsgs/t8064.nim +++ /dev/null @@ -1,8 +0,0 @@ -import tables - -values - - -discard """ - errormsg: "expression has no type: values" -""" diff --git a/tests/errmsgs/t8434.nim b/tests/errmsgs/t8434.nim index 5d962ee5c..c8bc1193b 100644 --- a/tests/errmsgs/t8434.nim +++ b/tests/errmsgs/t8434.nim @@ -3,7 +3,7 @@ discard """ nimout: '''but expected one of: proc fun0[T1: int | float | object | array | seq](a1: T1; a2: int) first type mismatch at position: 1 - required type for a1: T1: int or float or object or array or seq + required type for a1: T1: int or float or object or array or seq[T] but expression 'byte(1)' is of type: byte expression: fun0(byte(1), 0) diff --git a/tests/errmsgs/t8610.nim b/tests/errmsgs/t8610.nim index ec99beae5..dd1a3ed29 100644 --- a/tests/errmsgs/t8610.nim +++ b/tests/errmsgs/t8610.nim @@ -1,5 +1,5 @@ discard """ - errormsg: "invalid type: 'typedesc[int]' for const" + errmsg: "'typedesc' metatype is not valid here; typed '=' instead of ':'?" """ -## bug #8610 +## issue #8610 const Foo = int diff --git a/tests/errmsgs/t8794.nim b/tests/errmsgs/t8794.nim index 9db54a9c7..22e4014f1 100644 --- a/tests/errmsgs/t8794.nim +++ b/tests/errmsgs/t8794.nim @@ -2,7 +2,7 @@ discard """ cmd: "nim check $options $file" errormsg: "" nimout: ''' -t8794.nim(39, 27) Error: undeclared field: 'a3' for type m8794.Foo3 [type declared in m8794.nim(1, 6)] +t8794.nim(39, 27) Error: undeclared field: 'a3' for type m8794.Foo3 [declared in m8794.nim(1, 6)] ''' """ diff --git a/tests/errmsgs/t9768.nim b/tests/errmsgs/t9768.nim index b5ff58367..d369150a5 100644 --- a/tests/errmsgs/t9768.nim +++ b/tests/errmsgs/t9768.nim @@ -1,14 +1,13 @@ discard """ - errormsg: "unhandled exception: t9768.nim(24, 3) `a < 4` [AssertionDefect]" - file: "std/assertions.nim" - matrix: "-d:nimPreviewSlimSystem" + errmsg: "unhandled exception:" + file: "system/fatal.nim" nimout: ''' stack trace: (most recent call last) -t9768.nim(29, 33) main -t9768.nim(24, 11) foo1 +t9768.nim(28, 33) main +t9768.nim(23, 11) foo1 ''' """ -import std/assertions + diff --git a/tests/errmsgs/t9908_01.nim b/tests/errmsgs/t9908_01.nim index 99bc8237d..b9d37b67b 100644 --- a/tests/errmsgs/t9908_01.nim +++ b/tests/errmsgs/t9908_01.nim @@ -1,5 +1,5 @@ discard """ -errormsg: "ordinal type expected; given: string" +errormsg: "ordinal type expected" line: 10 """ diff --git a/tests/errmsgs/t9908_02.nim b/tests/errmsgs/t9908_02.nim index 4fc60b3df..7ff3d1ff7 100644 --- a/tests/errmsgs/t9908_02.nim +++ b/tests/errmsgs/t9908_02.nim @@ -1,5 +1,5 @@ discard """ -errormsg: "ordinal type expected; given: float" +errormsg: "ordinal type expected" line: 10 """ diff --git a/tests/errmsgs/tcall_with_default_arg.nim b/tests/errmsgs/tcall_with_default_arg.nim index 44752f1ee..1cc86638f 100644 --- a/tests/errmsgs/tcall_with_default_arg.nim +++ b/tests/errmsgs/tcall_with_default_arg.nim @@ -1,5 +1,5 @@ discard """ -outputsub: '''tcall_with_default_arg.nim(8) fail''' +outputsub: '''tcall_with_default_arg.nim(16) anotherFoo''' exitcode: 1 """ # issue: #5604 diff --git a/tests/errmsgs/tcannot_capture_builtin.nim b/tests/errmsgs/tcannot_capture_builtin.nim index 65afa627e..3b8aae241 100644 --- a/tests/errmsgs/tcannot_capture_builtin.nim +++ b/tests/errmsgs/tcannot_capture_builtin.nim @@ -1,5 +1,5 @@ discard """ -errormsg: "'+' is a built-in and cannot be used as a first-class procedure" +errormsg: "'+' cannot be passed to a procvar" line: 8 """ diff --git a/tests/errmsgs/tcase_stmt.nim b/tests/errmsgs/tcase_stmt.nim deleted file mode 100644 index cf63b9c17..000000000 --- a/tests/errmsgs/tcase_stmt.nim +++ /dev/null @@ -1,29 +0,0 @@ -discard """ - cmd: "nim check --hints:off $file" - errormsg: "" - nimout: ''' -tcase_stmt.nim(22, 7) Error: selector must be of an ordinal type, float or string -tcase_stmt.nim(28, 6) Error: selector must be of an ordinal type, float or string - - - - - - - -''' -""" - - - -# bug #19682 -type A = object - -case A() -else: - discard - -# bug #20283 - -case @[] -else: discard diff --git a/tests/errmsgs/tconceptconstraint.nim b/tests/errmsgs/tconceptconstraint.nim index 066ec5bdb..9ab1708c7 100644 --- a/tests/errmsgs/tconceptconstraint.nim +++ b/tests/errmsgs/tconceptconstraint.nim @@ -1,7 +1,8 @@ discard """ errormsg: "cannot instantiate B" + line: 20 nimout: ''' -got: +got: but expected: ''' """ diff --git a/tests/errmsgs/tconcisetypemismatch.nim b/tests/errmsgs/tconcisetypemismatch.nim deleted file mode 100644 index 4227644ce..000000000 --- a/tests/errmsgs/tconcisetypemismatch.nim +++ /dev/null @@ -1,23 +0,0 @@ -discard """ - cmd: "nim c --hints:off --skipParentCfg $file" - errormsg: "type mismatch" - nimout: ''' -tconcisetypemismatch.nim(23, 47) Error: type mismatch -Expression: int(inNanoseconds(t2 - t1)) / 100.5 - [1] int(inNanoseconds(t2 - t1)): int - [2] 100.5: float64 - -Expected one of (first mismatch at position [#]): -[1] proc `/`(x, y: float): float -[1] proc `/`(x, y: float32): float32 -[2] proc `/`(x, y: int): float -''' -""" - -import std/monotimes -from times import inNanoseconds - -let t1 = getMonotime() -let result = 1 + 2 -let t2 = getMonotime() -echo "Elapsed: ", (t2 - t1).inNanoseconds.int / 100.5 \ No newline at end of file diff --git a/tests/errmsgs/tconcisetypemismatch.nims b/tests/errmsgs/tconcisetypemismatch.nims deleted file mode 100644 index e9dce8147..000000000 --- a/tests/errmsgs/tconcisetypemismatch.nims +++ /dev/null @@ -1,21 +0,0 @@ -switch("path", "$lib/../testament/lib") - # so we can `import stdtest/foo` inside tests - # Using $lib/../ instead of $nim/ so you can use a different nim to run tests - # during local testing, e.g. nim --lib:lib. - -## prevent common user config settings to interfere with testament expectations -## Indifidual tests can override this if needed to test for these options. -switch("colors", "off") - -switch("excessiveStackTrace", "off") - -when (NimMajor, NimMinor, NimPatch) >= (1,5,1): - # to make it easier to test against older nim versions, (best effort only) - switch("filenames", "legacyRelProj") - switch("spellSuggest", "0") - -# for std/unittest -switch("define", "nimUnittestOutputLevel:PRINT_FAILURES") -switch("define", "nimUnittestColor:off") - -hint("Processing", off) diff --git a/tests/errmsgs/tconstinfo.nim b/tests/errmsgs/tconstinfo.nim deleted file mode 100644 index 170972b9f..000000000 --- a/tests/errmsgs/tconstinfo.nim +++ /dev/null @@ -1,7 +0,0 @@ -# https://forum.nim-lang.org/t/9762 - -const foo = "abc" -case 'a' -of foo: echo "should error" #[tt.Error - ^ type mismatch: got but expected 'char']# -else: discard diff --git a/tests/errmsgs/tdeclaredlocs.nim b/tests/errmsgs/tdeclaredlocs.nim deleted file mode 100644 index 926ebf217..000000000 --- a/tests/errmsgs/tdeclaredlocs.nim +++ /dev/null @@ -1,92 +0,0 @@ -discard """ - action: reject - matrix: "--declaredLocs --hints:off" - nimoutFull: true - nimout: ''' -tdeclaredlocs.nim(92, 3) Error: type mismatch: got -but expected one of: -proc fn(a: Bam) [proc declared in tdeclaredlocs.nim(86, 6)] - first type mismatch at position: 1 - required type for a: Bam [object declared in tdeclaredlocs.nim(78, 3)] - but expression 'a' is of type: seq[MyInt2{char}] [char declared in tdeclaredlocs.nim(73, 3)] -proc fn(a: Goo[MyInt2]) [proc declared in tdeclaredlocs.nim(89, 6)] - first type mismatch at position: 1 - required type for a: Goo[MyInt2{char}] [object declared in tdeclaredlocs.nim(79, 3)] - but expression 'a' is of type: seq[MyInt2{char}] [char declared in tdeclaredlocs.nim(73, 3)] -proc fn(a: Goo[cint]) [proc declared in tdeclaredlocs.nim(88, 6)] - first type mismatch at position: 1 - required type for a: Goo[cint{int32}] [object declared in tdeclaredlocs.nim(79, 3)] - but expression 'a' is of type: seq[MyInt2{char}] [char declared in tdeclaredlocs.nim(73, 3)] -proc fn(a: array[3, Bar]) [proc declared in tdeclaredlocs.nim(82, 6)] - first type mismatch at position: 1 - required type for a: array[0..2, Bar] [object declared in tdeclaredlocs.nim(74, 3)] - but expression 'a' is of type: seq[MyInt2{char}] [char declared in tdeclaredlocs.nim(73, 3)] -proc fn(a: seq[Bar]) [proc declared in tdeclaredlocs.nim(81, 6)] - first type mismatch at position: 1 - required type for a: seq[Bar] [object declared in tdeclaredlocs.nim(74, 3)] - but expression 'a' is of type: seq[MyInt2{char}] [char declared in tdeclaredlocs.nim(73, 3)] -proc fn(a: seq[MyInt1]) [proc declared in tdeclaredlocs.nim(80, 6)] - first type mismatch at position: 1 - required type for a: seq[MyInt1{int}] [int declared in tdeclaredlocs.nim(72, 3)] - but expression 'a' is of type: seq[MyInt2{char}] [char declared in tdeclaredlocs.nim(73, 3)] -proc fn(a: set[Baz]) [proc declared in tdeclaredlocs.nim(84, 6)] - first type mismatch at position: 1 - required type for a: set[Baz{enum}] [enum declared in tdeclaredlocs.nim(75, 3)] - but expression 'a' is of type: seq[MyInt2{char}] [char declared in tdeclaredlocs.nim(73, 3)] -proc fn(a: set[MyInt2]) [proc declared in tdeclaredlocs.nim(83, 6)] - first type mismatch at position: 1 - required type for a: set[MyInt2{char}] [char declared in tdeclaredlocs.nim(73, 3)] - but expression 'a' is of type: seq[MyInt2{char}] [char declared in tdeclaredlocs.nim(73, 3)] -proc fn(a: var SetBaz) [proc declared in tdeclaredlocs.nim(85, 6)] - first type mismatch at position: 1 - required type for a: var SetBaz [enum declared in tdeclaredlocs.nim(75, 3)] - but expression 'a' is of type: seq[MyInt2{char}] [char declared in tdeclaredlocs.nim(73, 3)] -proc fn(a: var ref ptr Bam) [proc declared in tdeclaredlocs.nim(87, 6)] - first type mismatch at position: 1 - required type for a: var ref ptr Bam [object declared in tdeclaredlocs.nim(78, 3)] - but expression 'a' is of type: seq[MyInt2{char}] [char declared in tdeclaredlocs.nim(73, 3)] - -expression: fn(a) -''' -""" - -#[ -see also: tests/errmsgs/tsigmatch.nim -]# - - - - - - - - - - - - - - -# line 70 -type - MyInt1 = int - MyInt2 = char - Bar = object - Baz = enum k0, k1 - Baz2 = Baz - SetBaz = set[Baz2] - Bam = ref object - Goo[T] = object -proc fn(a: seq[MyInt1]) = discard -proc fn(a: seq[Bar]) = discard -proc fn(a: array[3, Bar]) = discard -proc fn(a: set[MyInt2]) = discard -proc fn(a: set[Baz]) = discard -proc fn(a: var SetBaz) = discard -proc fn(a: Bam) = discard -proc fn(a: var ref ptr Bam) = discard -proc fn(a: Goo[cint]) = discard -proc fn(a: Goo[MyInt2]) = discard - -var a: seq[MyInt2] -fn(a) diff --git a/tests/errmsgs/tdistinct_nil.nim b/tests/errmsgs/tdistinct_nil.nim deleted file mode 100644 index a2b403293..000000000 --- a/tests/errmsgs/tdistinct_nil.nim +++ /dev/null @@ -1,23 +0,0 @@ -discard """ - cmd: "nim check $file" - action: reject - nimout: ''' -tdistinct_nil.nim(23, 4) Error: type mismatch: got -but expected one of: -proc foo(x: DistinctPointer) - first type mismatch at position: 1 - required type for x: DistinctPointer - but expression 'nil' is of type: typeof(nil) - -expression: foo(nil) -''' -""" - -type - DistinctPointer = distinct pointer - -proc foo(x: DistinctPointer) = - discard - -foo(DistinctPointer(nil)) -foo(nil) diff --git a/tests/errmsgs/tdont_show_system.nim b/tests/errmsgs/tdont_show_system.nim index 164fdd801..830113218 100644 --- a/tests/errmsgs/tdont_show_system.nim +++ b/tests/errmsgs/tdont_show_system.nim @@ -1,5 +1,5 @@ discard """ - errormsg: "expression 'true' is of type 'bool' and has to be used (or discarded)" + errormsg: "expression 'true' is of type 'bool' and has to be discarded" line: 13 file: "tdont_show_system.nim" """ diff --git a/tests/errmsgs/tgcsafety.nim b/tests/errmsgs/tgcsafety.nim index 66496d364..e6a62204e 100644 --- a/tests/errmsgs/tgcsafety.nim +++ b/tests/errmsgs/tgcsafety.nim @@ -1,16 +1,15 @@ discard """ cmd: "nim check $file" -errormsg: "type mismatch: got " +errormsg: "type mismatch: got .}>" nimout: ''' -tgcsafety.nim(31, 18) Error: type mismatch: got +type mismatch: got .}> but expected one of: proc serve(server: AsyncHttpServer; port: Port; - callback: proc (request: Request): Future[void] {.closure, gcsafe.}; - address = ""; assumedDescriptorsPerRequest = -1; domain = AF_INET): owned( - Future[void]) + callback: proc (request: Request): Future[void] {.closure, gcsafe.}; + address = ""): owned(Future[void]) first type mismatch at position: 3 required type for callback: proc (request: Request): Future[system.void]{.closure, gcsafe.} - but expression 'cb' is of type: proc (req: Request): Future[system.void] + but expression 'cb' is of type: proc (req: Request): Future[system.void]{.locks: .} This expression is not GC-safe. Annotate the proc with {.gcsafe.} to get extended error information. expression: serve(server, Port(7898), cb) diff --git a/tests/errmsgs/tgenericconstraint.nim b/tests/errmsgs/tgenericconstraint.nim index b51fb3488..e3093fead 100644 --- a/tests/errmsgs/tgenericconstraint.nim +++ b/tests/errmsgs/tgenericconstraint.nim @@ -1,7 +1,8 @@ discard """ errormsg: "cannot instantiate B" + line: 14 nimout: ''' -got: +got: but expected: ''' """ diff --git a/tests/errmsgs/tinteger_literals.nim b/tests/errmsgs/tinteger_literals.nim index f90ab14a1..98c92a227 100644 --- a/tests/errmsgs/tinteger_literals.nim +++ b/tests/errmsgs/tinteger_literals.nim @@ -1,14 +1,15 @@ discard """ - cmd: "nim check $file" +cmd: "nim check $file" +errormsg: "number out of range: '300'u8'" +nimout: ''' +tinteger_literals.nim(12, 9) Error: number out of range: '18446744073709551616'u64' +tinteger_literals.nim(13, 9) Error: number out of range: '9223372036854775808'i64' +tinteger_literals.nim(14, 9) Error: number out of range: '9223372036854775808' +tinteger_literals.nim(15, 9) Error: number out of range: '300'u8' +''' """ -# high(uint64) + 1 -discard 18446744073709551616'u64 #[tt.Error - ^ number out of range: '18446744073709551616'u64' ]# -# high(int64) + 1 -discard 9223372036854775808'i64 #[tt.Error - ^ number out of range: '9223372036854775808'i64' ]# -# high(int64) + 1 -discard 9223372036854775808 #[tt.Error - ^ number out of range: '9223372036854775808' ]# -discard 300'u8 #[tt.Error - ^ number out of range: '300'u8' ]# + +discard 18446744073709551616'u64 # high(uint64) + 1 +discard 9223372036854775808'i64 # high(int64) + 1 +discard 9223372036854775808 # high(int64) + 1 +discard 300'u8 \ No newline at end of file diff --git a/tests/errmsgs/tinvalidinout.nim b/tests/errmsgs/tinvalidinout.nim index 268bcf4d5..1fa3805ee 100644 --- a/tests/errmsgs/tinvalidinout.nim +++ b/tests/errmsgs/tinvalidinout.nim @@ -9,7 +9,7 @@ tinvalidinout.nim(18, 9) Error: the 'in' modifier can be used only with imported """ type - Foo[in T] {.header: "foo.h", importcpp.} = object + Foo {.header: "foo.h", importcpp.} [in T] = object Bar[out X] = object x: int diff --git a/tests/errmsgs/tnested_empty_seq.nim b/tests/errmsgs/tnested_empty_seq.nim index 871b0ee85..ffe8bc3ee 100644 --- a/tests/errmsgs/tnested_empty_seq.nim +++ b/tests/errmsgs/tnested_empty_seq.nim @@ -1,5 +1,5 @@ discard """ - errormsg: "invalid type: 'empty' in this context: 'array[0..0, (string, seq[empty])]' for var" + errormsg: "invalid type: 'empty' in this context: 'array[0..0, tuple of (string, seq[empty])]' for var" line: 8 """ diff --git a/tests/errmsgs/tnon_concrete_cast.nim b/tests/errmsgs/tnon_concrete_cast.nim index 9e05c736c..e4ae890ce 100644 --- a/tests/errmsgs/tnon_concrete_cast.nim +++ b/tests/errmsgs/tnon_concrete_cast.nim @@ -34,7 +34,7 @@ proc write(rw: var MyReadWrite; value: SomeNumber): void = proc write[T](rw: var MyReadWrite; value: seq[T]): void = rw.write value.len let dst = cast[ptr SomeNumber](cast[uint](rw.memfile.mem) + uint(rw.offset)) - let src = cast[pointer](value[0].addr) + let src = cast[pointer](value[0].unsafeAddr) let size = sizeof(T) * value.len copyMem(dst, src, size) rw.offset += size diff --git a/tests/errmsgs/tproc_mismatch.nim b/tests/errmsgs/tproc_mismatch.nim deleted file mode 100644 index 16f319f3b..000000000 --- a/tests/errmsgs/tproc_mismatch.nim +++ /dev/null @@ -1,74 +0,0 @@ -discard """ - action: reject - cmd: '''nim check --hints:off $options $file''' - nimoutFull: true - nimout: ''' -tproc_mismatch.nim(38, 52) Error: type mismatch: got but expected 'proc (a: int, c: float){.closure, noSideEffect.}' - Calling convention mismatch: got '{.cdecl.}', but expected '{.closure.}'. -tproc_mismatch.nim(42, 6) Error: type mismatch: got -but expected one of: -proc bar(a: proc ()) - first type mismatch at position: 1 - required type for a: proc (){.closure.} - but expression 'fn1' is of type: proc (){.inline, noSideEffect, gcsafe.} - Calling convention mismatch: got '{.inline.}', but expected '{.closure.}'. - -expression: bar(fn1) -tproc_mismatch.nim(46, 8) Error: type mismatch: got but expected 'proc (){.closure.}' - Calling convention mismatch: got '{.inline.}', but expected '{.closure.}'. -tproc_mismatch.nim(51, 8) Error: type mismatch: got but expected 'proc (){.closure, noSideEffect.}' - Calling convention mismatch: got '{.nimcall.}', but expected '{.closure.}'. - Pragma mismatch: got '{..}', but expected '{.noSideEffect.}'. -tproc_mismatch.nim(55, 8) Error: type mismatch: got but expected 'proc (a: float){.closure.}' - Calling convention mismatch: got '{.nimcall.}', but expected '{.closure.}'. -tproc_mismatch.nim(64, 9) Error: type mismatch: got but expected 'proc (a: int){.closure, gcsafe.}' - Calling convention mismatch: got '{.nimcall.}', but expected '{.closure.}'. - Pragma mismatch: got '{..}', but expected '{.gcsafe.}'. -tproc_mismatch.nim(72, 9) Error: type mismatch: got but expected 'proc (a: int): int{.cdecl.}' - Calling convention mismatch: got '{.nimcall.}', but expected '{.cdecl.}'. -tproc_mismatch.nim(73, 9) Error: type mismatch: got but expected 'proc (a: int): int{.nimcall.}' - Calling convention mismatch: got '{.cdecl.}', but expected '{.nimcall.}'. -''' -""" - - - -block: # CallConv mismatch - func a(a: int, c: float) {.cdecl.} = discard - var b: proc(a: int, c: float) {.noSideEffect.} = a -block: # Parameter CallConv mismatch - proc fn1() {.inline.} = discard - proc bar(a: proc()) = discard - bar(fn1) -block: # CallConv mismatch - proc fn1() {.inline.} = discard - var fn: proc() - fn = fn1 -block: # Pragma mismatch - var a = "" - proc fn1() = a.add "b" - var fn: proc() {.noSideEffect.} - fn = fn1 -block: # Fail match not do to Pragma or CallConv - proc fn1(a: int) = discard - var fn: proc(a: float) - fn = fn1 -block: # Infered noSideEffect assign - type Foo = ref object - x0: int - var g0 = Foo(x0: 1) - proc fn1(a: int) = g0.x0 = a - var fn2: proc(a: int) - var fn3: proc(a: int) {.gcsafe.} - fn2 = fn1 - fn3 = fn1 -block: # Indrection through pragmas - {.pragma: inl1, inline.} - {.pragma: inl2, inline.} - {.pragma: p1, nimcall.} - {.pragma: p2, cdecl.} - var fn1: proc(a: int): int {.inl1, p1.} - var fn2: proc(a: int): int {.inl2, p2.} - fn2 = fn1 - fn1 = fn2 - diff --git a/tests/errmsgs/tproper_stacktrace.nim b/tests/errmsgs/tproper_stacktrace.nim index b0a008840..c7dfbaf2a 100644 --- a/tests/errmsgs/tproper_stacktrace.nim +++ b/tests/errmsgs/tproper_stacktrace.nim @@ -1,5 +1,4 @@ discard """ - matrix: "--stackTrace:on --hint:all:off --warnings:off" output: '''ok''' """ import strscans, strutils @@ -7,7 +6,7 @@ import strscans, strutils proc raiseTestException*() = raise newException(Exception, "test") -proc matchStackTrace(actualEntries: openArray[StackTraceEntry], expected: string) = +proc matchStackTrace(actualEntries: openarray[StackTraceEntry], expected: string) = var expectedEntries = newSeq[StackTraceEntry]() var i = 0 @@ -77,10 +76,10 @@ when true: bar() const expectedStackTrace = """ - tproper_stacktrace.nim(87) tproper_stacktrace - tproper_stacktrace.nim(77) foo - tproper_stacktrace.nim(74) bar - tproper_stacktrace.nim(8) raiseTestException + tproper_stacktrace.nim(86) tproper_stacktrace + tproper_stacktrace.nim(76) foo + tproper_stacktrace.nim(73) bar + tproper_stacktrace.nim(7) raiseTestException """ verifyStackTrace expectedStackTrace: @@ -94,9 +93,9 @@ when true: bar(x) const expectedStackTrace = """ - tproper_stacktrace.nim(104) tproper_stacktrace - tproper_stacktrace.nim(91) bar - tproper_stacktrace.nim(8) raiseTestException + tproper_stacktrace.nim(103) tproper_stacktrace + tproper_stacktrace.nim(90) bar + tproper_stacktrace.nim(7) raiseTestException """ verifyStackTrace expectedStackTrace: @@ -111,10 +110,10 @@ when true: bar() const expectedStackTrace = """ - tproper_stacktrace.nim(121) tproper_stacktrace - tproper_stacktrace.nim(111) foo - tproper_stacktrace.nim(108) bar - tproper_stacktrace.nim(8) raiseTestException + tproper_stacktrace.nim(120) tproper_stacktrace + tproper_stacktrace.nim(110) foo + tproper_stacktrace.nim(107) bar + tproper_stacktrace.nim(7) raiseTestException """ verifyStackTrace expectedStackTrace: @@ -130,10 +129,10 @@ when true: bar() const expectedStackTrace = """ - tproper_stacktrace.nim(140) tproper_stacktrace - tproper_stacktrace.nim(130) foo - tproper_stacktrace.nim(126) baz - tproper_stacktrace.nim(8) raiseTestException + tproper_stacktrace.nim(139) tproper_stacktrace + tproper_stacktrace.nim(129) foo + tproper_stacktrace.nim(125) baz + tproper_stacktrace.nim(7) raiseTestException """ verifyStackTrace expectedStackTrace: diff --git a/tests/errmsgs/tproper_stacktrace2.nim b/tests/errmsgs/tproper_stacktrace2.nim index 5a6ca3fcb..44b208c87 100644 --- a/tests/errmsgs/tproper_stacktrace2.nim +++ b/tests/errmsgs/tproper_stacktrace2.nim @@ -1,6 +1,5 @@ discard """ - matrix: "--stackTrace:on" - outputsub: '''tproper_stacktrace2.nim(21) main''' + outputsub: '''tproper_stacktrace2.nim(20) main''' exitcode: 1 """ diff --git a/tests/errmsgs/tproper_stacktrace3.nim b/tests/errmsgs/tproper_stacktrace3.nim index 97d63e6ec..c292fa092 100644 --- a/tests/errmsgs/tproper_stacktrace3.nim +++ b/tests/errmsgs/tproper_stacktrace3.nim @@ -1,6 +1,5 @@ discard """ - matrix: "--stackTrace:on" - outputsub: '''tproper_stacktrace3.nim(22) main''' + outputsub: '''tproper_stacktrace3.nim(21) main''' exitcode: 1 """ diff --git a/tests/errmsgs/treportunused.nim b/tests/errmsgs/treportunused.nim index 46afe163d..b339e06bf 100644 --- a/tests/errmsgs/treportunused.nim +++ b/tests/errmsgs/treportunused.nim @@ -1,28 +1,16 @@ discard """ - matrix: "--hint:all:off --hint:XDeclaredButNotUsed" - nimoutFull: true nimout: ''' -treportunused.nim(51, 5) Hint: 'A' is declared but not used [XDeclaredButNotUsed] -treportunused.nim(52, 5) Hint: 'B' is declared but not used [XDeclaredButNotUsed] -treportunused.nim(55, 5) Hint: 'D' is declared but not used [XDeclaredButNotUsed] -treportunused.nim(56, 5) Hint: 'E' is declared but not used [XDeclaredButNotUsed] -treportunused.nim(59, 5) Hint: 'G' is declared but not used [XDeclaredButNotUsed] -treportunused.nim(60, 5) Hint: 'H' is declared but not used [XDeclaredButNotUsed] -treportunused.nim(64, 5) Hint: 'K' is declared but not used [XDeclaredButNotUsed] -treportunused.nim(65, 5) Hint: 'L' is declared but not used [XDeclaredButNotUsed] -treportunused.nim(31, 10) Hint: 's1' is declared but not used [XDeclaredButNotUsed] -treportunused.nim(32, 10) Hint: 's2' is declared but not used [XDeclaredButNotUsed] -treportunused.nim(33, 10) Hint: 's3' is declared but not used [XDeclaredButNotUsed] -treportunused.nim(34, 6) Hint: 's4' is declared but not used [XDeclaredButNotUsed] -treportunused.nim(35, 6) Hint: 's5' is declared but not used [XDeclaredButNotUsed] -treportunused.nim(36, 7) Hint: 's6' is declared but not used [XDeclaredButNotUsed] -treportunused.nim(37, 7) Hint: 's7' is declared but not used [XDeclaredButNotUsed] -treportunused.nim(38, 5) Hint: 's8' is declared but not used [XDeclaredButNotUsed] -treportunused.nim(39, 5) Hint: 's9' is declared but not used [XDeclaredButNotUsed] -treportunused.nim(40, 6) Hint: 's10' is declared but not used [XDeclaredButNotUsed] -treportunused.nim(41, 6) Hint: 's11' is declared but not used [XDeclaredButNotUsed] -treportunused.nim(45, 3) Hint: 'v0.99' is declared but not used [XDeclaredButNotUsed] -treportunused.nim(46, 3) Hint: 'v0.99.99' is declared but not used [XDeclaredButNotUsed] +treportunused.nim(19, 10) Hint: 's1' is declared but not used [XDeclaredButNotUsed] +treportunused.nim(26, 5) Hint: 's8' is declared but not used [XDeclaredButNotUsed] +treportunused.nim(22, 6) Hint: 's4' is declared but not used [XDeclaredButNotUsed] +treportunused.nim(25, 7) Hint: 's7' is declared but not used [XDeclaredButNotUsed] +treportunused.nim(24, 7) Hint: 's6' is declared but not used [XDeclaredButNotUsed] +treportunused.nim(23, 6) Hint: 's5' is declared but not used [XDeclaredButNotUsed] +treportunused.nim(20, 10) Hint: 's2' is declared but not used [XDeclaredButNotUsed] +treportunused.nim(29, 6) Hint: 's11' is declared but not used [XDeclaredButNotUsed] +treportunused.nim(27, 5) Hint: 's9' is declared but not used [XDeclaredButNotUsed] +treportunused.nim(21, 10) Hint: 's3' is declared but not used [XDeclaredButNotUsed] +treportunused.nim(28, 6) Hint: 's10' is declared but not used [XDeclaredButNotUsed] ''' action: compile """ @@ -39,27 +27,3 @@ let s8 = 0 var s9: int type s10 = object type s11 = type(1.2) - -# bug #14407 (requires `compiler/nim.cfg` containing define:nimPreviewFloatRoundtrip) -let - `v0.99` = "0.99" - `v0.99.99` = "0.99.99" - -block: # bug #18201 - # Test that unused type aliases raise hint XDeclaredButNotUsed. - type - A = int - B = distinct int - - C = object - D = C - E = distinct C - - F = string - G = F - H = distinct F - - J = enum - Foo - K = J - L = distinct J diff --git a/tests/errmsgs/tsigmatch.nim b/tests/errmsgs/tsigmatch.nim index 85ed34169..21e2c217d 100644 --- a/tests/errmsgs/tsigmatch.nim +++ b/tests/errmsgs/tsigmatch.nim @@ -1,45 +1,45 @@ discard """ - cmd: "nim check --mm:refc --showAllMismatches:on --hints:off $file" + cmd: "nim check --showAllMismatches:on --hints:off $file" nimout: ''' tsigmatch.nim(111, 4) Error: type mismatch: got but expected one of: -proc f(a: A) - first type mismatch at position: 2 - extra argument given proc f(b: B) first type mismatch at position: 1 required type for b: B but expression 'A()' is of type: A +proc f(a: A) + first type mismatch at position: 2 + extra argument given expression: f(A(), "extra") -tsigmatch.nim(125, 6) Error: type mismatch: got <(string, proc (){.gcsafe.})> +tsigmatch.nim(125, 6) Error: type mismatch: got but expected one of: proc foo(x: (string, proc ())) first type mismatch at position: 1 - required type for x: (string, proc (){.closure.}) - but expression '("foobar", proc () = echo(["Hello!"]))' is of type: (string, proc (){.gcsafe.}) + required type for x: tuple of (string, proc (){.closure.}) + but expression '("foobar", proc () = echo(["Hello!"]))' is of type: tuple of (string, proc (){.gcsafe, locks: 0.}) expression: foo(("foobar", proc () = echo(["Hello!"]))) -tsigmatch.nim(132, 11) Error: type mismatch: got +tsigmatch.nim(132, 11) Error: type mismatch: got but expected one of: proc foo[T, S](op: proc (x: T): S {.cdecl.}): auto first type mismatch at position: 1 required type for op: proc (x: T): S{.cdecl.} - but expression 'fun' is of type: proc (s: string): string{.noSideEffect, gcsafe.} + but expression 'fun' is of type: proc (s: string): string{.noSideEffect, gcsafe, locks: 0.} proc foo[T, S](op: proc (x: T): S {.safecall.}): auto first type mismatch at position: 1 required type for op: proc (x: T): S{.safecall.} - but expression 'fun' is of type: proc (s: string): string{.noSideEffect, gcsafe.} + but expression 'fun' is of type: proc (s: string): string{.noSideEffect, gcsafe, locks: 0.} expression: foo(fun) -tsigmatch.nim(143, 13) Error: type mismatch: got +tsigmatch.nim(143, 13) Error: type mismatch: got but expected one of: -proc takesFuncs(fs: openArray[proc (x: int) {.gcsafe.}]) +proc takesFuncs(fs: openArray[proc (x: int) {.gcsafe, locks: 0.}]) first type mismatch at position: 1 - required type for fs: openArray[proc (x: int){.closure, gcsafe.}] - but expression '[proc (x: int) {.gcsafe.} = echo [x]]' is of type: array[0..0, proc (x: int){.gcsafe.}] + required type for fs: openArray[proc (x: int){.closure, gcsafe, locks: 0.}] + but expression '[proc (x: int) {.gcsafe, locks: 0.} = echo [x]]' is of type: array[0..0, proc (x: int){.gcsafe, locks: 0.}] -expression: takesFuncs([proc (x: int) {.gcsafe.} = echo [x]]) +expression: takesFuncs([proc (x: int) {.gcsafe, locks: 0.} = echo [x]]) tsigmatch.nim(149, 4) Error: type mismatch: got but expected one of: proc f(a0: uint8; b: string) @@ -61,14 +61,14 @@ proc f(a1: string; a2: varargs[string]; a3: float; a4: var string) expression: f("asdf", "1", "2", "3", "4", 2.3, "bad") tsigmatch.nim(164, 4) Error: type mismatch: got but expected one of: -proc f(x: string; a0: string) - first type mismatch at position: 2 - required type for a0: string - but expression 'a0 = 12' is of type: int literal(12) proc f(x: string; a0: var int) first type mismatch at position: 2 required type for a0: var int but expression 'a0 = 12' is immutable, not 'var' +proc f(x: string; a0: string) + first type mismatch at position: 2 + required type for a0: string + but expression 'a0 = 12' is of type: int literal(12) expression: f(foo, a0 = 12) tsigmatch.nim(171, 7) Error: type mismatch: got @@ -89,22 +89,22 @@ expression: fun1(default(Mystring), "asdf") -#[ -see also: tests/errmsgs/tdeclaredlocs.nim -]# + + + ## line 100 -when true: +block: # bug #11061 Type mismatch error "first type mismatch at" points to wrong argument/position # Note: the error msg now gives correct position for mismatched argument type A = object of RootObj B = object of A -block: + proc f(b: B) = discard proc f(a: A) = discard @@ -132,15 +132,15 @@ block: echo foo(fun) block: - # bug #10285 Function signature don't match when inside seq/array/openArray + # bug #10285 Function signature don't match when inside seq/array/openarray # Note: the error message now shows `closure` which helps debugging the issue # out why it doesn't match - proc takesFunc(f: proc (x: int) {.gcsafe.}) = + proc takesFunc(f: proc (x: int) {.gcsafe, locks: 0.}) = echo "takes single Func" - proc takesFuncs(fs: openArray[proc (x: int) {.gcsafe.}]) = + proc takesFuncs(fs: openarray[proc (x: int) {.gcsafe, locks: 0.}]) = echo "takes multiple Func" - takesFunc(proc (x: int) {.gcsafe.} = echo x) # works - takesFuncs([proc (x: int) {.gcsafe.} = echo x]) # fails + takesFunc(proc (x: int) {.gcsafe, locks: 0.} = echo x) # works + takesFuncs([proc (x: int) {.gcsafe, locks: 0.} = echo x]) # fails block: # bug https://github.com/nim-lang/Nim/issues/11061#issuecomment-508970465 @@ -163,7 +163,7 @@ block: var foo = "" f(foo, a0 = 12) -when true: +block: type Mystring = string type MyInt = int proc fun1(a1: MyInt, a2: Mystring) = discard diff --git a/tests/errmsgs/tsigmatch2.nim b/tests/errmsgs/tsigmatch2.nim index 31c966337..c4eb4c197 100644 --- a/tests/errmsgs/tsigmatch2.nim +++ b/tests/errmsgs/tsigmatch2.nim @@ -3,18 +3,17 @@ discard """ nimout: ''' tsigmatch2.nim(40, 14) Error: type mismatch: got but expected one of: -proc foo(args: varargs[string, myproc]): string - first type mismatch at position: 1 - required type for args: varargs[string] - but expression '1.2' is of type: float64 proc foo(i: Foo): string first type mismatch at position: 1 required type for i: Foo but expression '1.2' is of type: float64 +proc foo(args: varargs[string, myproc]): string + first type mismatch at position: 1 + required type for args: varargs[string] + but expression '1.2' is of type: float64 expression: foo(1.2) -tsigmatch2.nim(40, 14) Error: expression '' has no type (or is ambiguous) -tsigmatch2.nim(46, 3) Error: type mismatch: got +tsigmatch2.nim(46, 7) Error: type mismatch: got but expected one of: proc foo(args: varargs[string, myproc]) first type mismatch at position: 1 @@ -27,12 +26,13 @@ expression: foo 1 """ + # line 30 -type Foo = object + block: # issue #13182 proc myproc(a: int): string = $("myproc", a) proc foo(args: varargs[string, myproc]): string = $args - + type Foo = object proc foo(i: Foo): string = "in foo(i)" static: doAssert foo(Foo()) == "in foo(i)" static: doAssert foo(1) == """["(\"myproc\", 1)"]""" @@ -44,4 +44,4 @@ block: let temp = 12.isNil proc foo(args: varargs[string, myproc]) = discard foo 1 -static: echo "done" +static: echo "done" \ No newline at end of file diff --git a/tests/errmsgs/tstaticexprscope.nim b/tests/errmsgs/tstaticexprscope.nim index 6969e389e..7af5bf9b3 100644 --- a/tests/errmsgs/tstaticexprscope.nim +++ b/tests/errmsgs/tstaticexprscope.nim @@ -1,5 +1,5 @@ discard """ - errormsg: "undeclared identifier: 'z'" + errmsg: "undeclared identifier: 'z'" line: 11 """ diff --git a/tests/errmsgs/ttypeAllowed.nim b/tests/errmsgs/ttypeAllowed.nim index fdb4c70b8..a5b335faa 100644 --- a/tests/errmsgs/ttypeAllowed.nim +++ b/tests/errmsgs/ttypeAllowed.nim @@ -1,11 +1,11 @@ discard """ cmd: "nim check $file" -errormsg: "" +errmsg: "" nimout: ''' -ttypeAllowed.nim(13, 5) Error: invalid type: 'iterator (a: int, b: int, step: Positive): int{.inline, noSideEffect, gcsafe.}' for let -ttypeAllowed.nim(17, 7) Error: invalid type: 'iterator (a: int, b: int, step: Positive): int{.inline, noSideEffect, gcsafe.}' for const -ttypeAllowed.nim(21, 5) Error: invalid type: 'iterator (a: int, b: int, step: Positive): int{.inline, noSideEffect, gcsafe.}' for var -ttypeAllowed.nim(26, 10) Error: invalid type: 'iterator (a: int, b: int, step: Positive): int{.inline, noSideEffect, gcsafe.}' for result +ttypeAllowed.nim(13, 5) Error: invalid type: 'iterator (a: int, b: int, step: Positive): int{.inline, noSideEffect, gcsafe, locks: 0.}' for let +ttypeAllowed.nim(17, 7) Error: invalid type for const: iterator (a: int, b: int, step: Positive): int{.inline, noSideEffect, gcsafe, locks: 0.} +ttypeAllowed.nim(21, 5) Error: invalid type: 'iterator (a: int, b: int, step: Positive): int{.inline, noSideEffect, gcsafe, locks: 0.}' for var +ttypeAllowed.nim(26, 10) Error: invalid type: 'iterator (a: int, b: int, step: Positive): int{.inline, noSideEffect, gcsafe, locks: 0.}' for result ''' """ diff --git a/tests/errmsgs/tundeclared_field.nim b/tests/errmsgs/tundeclared_field.nim deleted file mode 100644 index 5668050e0..000000000 --- a/tests/errmsgs/tundeclared_field.nim +++ /dev/null @@ -1,50 +0,0 @@ -discard """ -cmd: '''nim check --hints:off $file''' -action: reject -nimout: ''' -tundeclared_field.nim(25, 12) Error: undeclared field: 'bad1' for type tundeclared_field.A [type declared in tundeclared_field.nim(22, 8)] -tundeclared_field.nim(30, 17) Error: undeclared field: 'bad2' for type tundeclared_field.A [type declared in tundeclared_field.nim(28, 8)] -tundeclared_field.nim(36, 4) Error: undeclared field: 'bad3' for type tundeclared_field.A [type declared in tundeclared_field.nim(33, 8)] -tundeclared_field.nim(42, 12) Error: undeclared field: 'bad4' for type tundeclared_field.B [type declared in tundeclared_field.nim(39, 8)] -tundeclared_field.nim(43, 4) Error: undeclared field: 'bad5' for type tundeclared_field.B [type declared in tundeclared_field.nim(39, 8)] -tundeclared_field.nim(44, 23) Error: undeclared field: 'bad6' for type tundeclared_field.B [type declared in tundeclared_field.nim(39, 8)] -tundeclared_field.nim(46, 19) Error: undeclared field: 'bad7' for type tundeclared_field.B [type declared in tundeclared_field.nim(39, 8)] -tundeclared_field.nim(50, 13) Error: cannot instantiate Foo [type declared in tundeclared_field.nim(49, 8)] -''' -""" - -#[ -xxx in future work, generic instantiations (e.g. `B[int]`) should be shown with their instantiation instead of `tundeclared_field.B`, -maybe using TPreferedDesc.preferResolved or preferMixed -]# -# line 20 -block: - type A = object - a0: int - var a: A - discard a.bad1 - -block: - type A = object - a0: int - var a = A(bad2: 0) - -block: - type A = object - a0: int - var a: A - a.bad3 = 0 - -block: - type B[T] = object - b0: int - var b: B[int] - discard b.bad4 - b.bad5 = 0 - var b2 = B[int](bad6: 0) - type Bi = B[int] - var b3 = Bi(bad7: 0) - -block: - type Foo[T: SomeInteger] = object - var a: Foo[float] diff --git a/tests/errmsgs/tundeclared_routine.nim b/tests/errmsgs/tundeclared_routine.nim deleted file mode 100644 index 2f1320fff..000000000 --- a/tests/errmsgs/tundeclared_routine.nim +++ /dev/null @@ -1,44 +0,0 @@ -discard """ -cmd: '''nim check --hints:off $file''' -action: reject -nimout: ''' -tundeclared_routine.nim(24, 17) Error: attempting to call routine: 'myiter' - found tundeclared_routine.myiter(a: string) [iterator declared in tundeclared_routine.nim(22, 12)] - found tundeclared_routine.myiter() [iterator declared in tundeclared_routine.nim(23, 12)] -tundeclared_routine.nim(29, 28) Error: invalid pragma: myPragma -tundeclared_routine.nim(36, 13) Error: undeclared field: 'bar3' for type tundeclared_routine.Foo [type declared in tundeclared_routine.nim(33, 8)] - found tundeclared_routine.bar3() [iterator declared in tundeclared_routine.nim(35, 12)] -tundeclared_routine.nim(41, 13) Error: undeclared field: 'bar4' for type tundeclared_routine.Foo [type declared in tundeclared_routine.nim(39, 8)] -tundeclared_routine.nim(44, 15) Error: attempting to call routine: 'bad5' -''' -""" - - - - - -# line 20 -block: - iterator myiter(a:string): int = discard - iterator myiter(): int = discard - let a = myiter(1) - -block: - proc myPragma():int=discard - iterator myPragma():int=discard - proc myfun(a:int): int {.myPragma.} = 1 - let a = myfun(1) - -block: - type Foo = object - var a = Foo() - iterator bar3():int=discard - let a2 = a.bar3 - -block: - type Foo = object - var a = Foo() - let a2 = a.bar4 - -block: - let a = bad5(1) diff --git a/tests/errmsgs/tunknown_named_parameter.nim b/tests/errmsgs/tunknown_named_parameter.nim index d3dd6cd2d..e9be23068 100644 --- a/tests/errmsgs/tunknown_named_parameter.nim +++ b/tests/errmsgs/tunknown_named_parameter.nim @@ -2,26 +2,26 @@ discard """ cmd: "nim check $file" errormsg: "type mismatch: got " nimout: ''' -func rsplit(s: string; sep: char; maxsplit: int = -1): seq[string] +proc rsplit(s: string; sep: char; maxsplit: int = -1): seq[string] first type mismatch at position: 2 required type for sep: char but expression '{':'}' is of type: set[char] -func rsplit(s: string; sep: string; maxsplit: int = -1): seq[string] +proc rsplit(s: string; seps: set[char] = Whitespace; maxsplit: int = -1): seq[string] + first type mismatch at position: 3 + unknown named parameter: maxsplits +proc rsplit(s: string; sep: string; maxsplit: int = -1): seq[string] first type mismatch at position: 2 required type for sep: string but expression '{':'}' is of type: set[char] -func rsplit(s: string; seps: set[char] = Whitespace; maxsplit: int = -1): seq[ - string] - first type mismatch at position: 3 - unknown named parameter: maxsplits expression: rsplit("abc:def", {':'}, maxsplits = 1) ''' +disabled: 32bit """ - # bug #8043 +# disabled on 32 bit systems because the order of suggested proc alternatives is different. import strutils "abc:def".rsplit({':'}, maxsplits = 1) diff --git a/tests/errmsgs/twrong_at_operator.nim b/tests/errmsgs/twrong_at_operator.nim index 438186f01..ebf6d966b 100644 --- a/tests/errmsgs/twrong_at_operator.nim +++ b/tests/errmsgs/twrong_at_operator.nim @@ -1,16 +1,17 @@ discard """ -errormsg: "type mismatch: got " +errormsg: "type mismatch: got " +line: 22 nimout: ''' -twrong_at_operator.nim(21, 30) Error: type mismatch: got +twrong_at_operator.nim(22, 30) Error: type mismatch: got but expected one of: proc `@`[IDX, T](a: sink array[IDX, T]): seq[T] first type mismatch at position: 1 required type for a: sink array[IDX, T] - but expression '[int]' is of type: array[0..0, typedesc[int]] + but expression '[int]' is of type: array[0..0, type int] proc `@`[T](a: openArray[T]): seq[T] first type mismatch at position: 1 required type for a: openArray[T] - but expression '[int]' is of type: array[0..0, typedesc[int]] + but expression '[int]' is of type: array[0..0, type int] expression: @[int] ''' diff --git a/tests/errmsgs/twrongcolon.nim b/tests/errmsgs/twrongcolon.nim index 06e802eb7..6f5cc3e5d 100644 --- a/tests/errmsgs/twrongcolon.nim +++ b/tests/errmsgs/twrongcolon.nim @@ -1,10 +1,11 @@ discard """ -errormsg: "in expression ' do:" +errormsg: "in expression '(" nimout: ''' -twrongcolon.nim(10, 12) Error: in expression ' do: - 890': identifier expected, but found '' +Error: in expression '( + 890)': identifier expected, but found '' ''' +line: 11 """ var n: int : 890 diff --git a/tests/errmsgs/undeclared_routime.nim b/tests/errmsgs/undeclared_routime.nim new file mode 100644 index 000000000..426507652 --- /dev/null +++ b/tests/errmsgs/undeclared_routime.nim @@ -0,0 +1,13 @@ +discard """ +cmd: '''nim c --hints:off $file''' +errormsg: "attempting to call routine: 'myiter'" +nimout: '''undeclared_routime.nim(13, 15) Error: attempting to call routine: 'myiter' + found 'undeclared_routime.myiter(a: string)[declared in undeclared_routime.nim(10, 9)]' of kind 'iterator' + found 'undeclared_routime.myiter()[declared in undeclared_routime.nim(11, 9)]' of kind 'iterator' +''' +""" + +iterator myiter(a:string): int = discard +iterator myiter(): int = discard + +let a = myiter(1) diff --git a/tests/errmsgs/undeclared_routime2.nim b/tests/errmsgs/undeclared_routime2.nim new file mode 100644 index 000000000..3e48b48f4 --- /dev/null +++ b/tests/errmsgs/undeclared_routime2.nim @@ -0,0 +1,9 @@ +discard """ +cmd: '''nim c --hints:off $file''' +errormsg: "invalid pragma: myPragma" +""" + +proc myPragma():int=discard +iterator myPragma():int=discard +proc myfun(a:int): int {.myPragma.} = 1 +let a = myfun(1) diff --git a/tests/errmsgs/undeclared_routime3.nim b/tests/errmsgs/undeclared_routime3.nim new file mode 100644 index 000000000..052adfc08 --- /dev/null +++ b/tests/errmsgs/undeclared_routime3.nim @@ -0,0 +1,13 @@ +discard """ +cmd: '''nim c --hints:off $file''' +errormsg: "undeclared field: 'bar'" +nimout: '''undeclared_routime3.nim(13, 10) Error: undeclared field: 'bar' + found 'undeclared_routime3.bar()[declared in undeclared_routime3.nim(12, 9)]' of kind 'iterator' +''' +""" + + +type Foo = object +var a = Foo() +iterator bar():int=discard +let a = a.bar diff --git a/tests/errmsgs/undeclared_routime4.nim b/tests/errmsgs/undeclared_routime4.nim new file mode 100644 index 000000000..674caa421 --- /dev/null +++ b/tests/errmsgs/undeclared_routime4.nim @@ -0,0 +1,10 @@ +discard """ +cmd: '''nim c --hints:off $file''' +errormsg: "undeclared field: 'bar'" +nimout: '''undeclared_routime4.nim(10, 10) Error: undeclared field: 'bar' +''' +""" + +type Foo = object +var a = Foo() +let a = a.bar diff --git a/tests/errmsgs/undeclared_routime5.nim b/tests/errmsgs/undeclared_routime5.nim new file mode 100644 index 000000000..4394134ab --- /dev/null +++ b/tests/errmsgs/undeclared_routime5.nim @@ -0,0 +1,9 @@ +discard """ +cmd: '''nim c --hints:off $file''' +errormsg: "undeclared identifier: 'myfun'" +nimout: '''undeclared_routime5.nim(9, 9) Error: undeclared identifier: 'myfun' +''' +""" + + +let a = myfun(1) diff --git a/tests/errmsgs/tundeclared_routine_compiles.nim b/tests/errmsgs/undeclared_routime_compiles.nim similarity index 100% rename from tests/errmsgs/tundeclared_routine_compiles.nim rename to tests/errmsgs/undeclared_routime_compiles.nim diff --git a/tests/exception/m21261.nim b/tests/exception/m21261.nim deleted file mode 100644 index 11b12fb5b..000000000 --- a/tests/exception/m21261.nim +++ /dev/null @@ -1 +0,0 @@ -raise (ref Exception)(msg: "something") \ No newline at end of file diff --git a/tests/exception/t13115.nim b/tests/exception/t13115.nim deleted file mode 100644 index ee1daed26..000000000 --- a/tests/exception/t13115.nim +++ /dev/null @@ -1,38 +0,0 @@ -const msg = "This char is `" & '\0' & "` and works fine!" - -when defined nim_t13115: - # bug #13115 - template fn = - raise newException(Exception, msg) - when defined nim_t13115_static: - static: fn() - fn() -else: - import std/[osproc,strformat,os,strutils] - proc main = - const nim = getCurrentCompilerExe() - const file = currentSourcePath - for b in "c js cpp".split: - when defined(openbsd): - if b == "js": - # xxx bug: pending #13115 - # remove special case once nodejs updated >= 12.16.2 - # refs https://github.com/nim-lang/Nim/pull/16167#issuecomment-738270751 - continue - - # save CI time by avoiding mostly redundant combinations as far as this bug is concerned - var opts = case b - of "c": @["", "-d:nim_t13115_static", "-d:danger", "-d:debug"] - of "js": @["", "-d:nim_t13115_static"] - else: @[""] - - for opt in opts: - let cmd = fmt"{nim} r -b:{b} -d:nim_t13115 {opt} --hints:off {file}" - let (outp, exitCode) = execCmdEx(cmd) - when defined windows: - # `\0` not preserved on windows - doAssert "` and works fine!" in outp, cmd & "\n" & msg - else: - doAssert msg in outp, cmd & "\n" & msg - doAssert exitCode == 1 - main() diff --git a/tests/exception/t18620.nim b/tests/exception/t18620.nim deleted file mode 100644 index ee23f8bac..000000000 --- a/tests/exception/t18620.nim +++ /dev/null @@ -1,17 +0,0 @@ -discard """ - matrix: "--gc:arc; --gc:refc" -""" - -proc hello() = - raise newException(ValueError, "You are wrong") - -var flag = false - -try: - hello() -except ValueError as e: - flag = true - doAssert len(getStackTraceEntries(e)) > 0 - doAssert len(getStackTraceEntries(e)) > 0 - -doAssert flag diff --git a/tests/exception/t20613.nim b/tests/exception/t20613.nim deleted file mode 100644 index 6edb69415..000000000 --- a/tests/exception/t20613.nim +++ /dev/null @@ -1,8 +0,0 @@ -discard """ - matrix: "; --panics:on" -""" - -func test = - if 0 > 10: - raiseAssert "hey" -test() diff --git a/tests/exception/t21261.nim b/tests/exception/t21261.nim deleted file mode 100644 index 84817d854..000000000 --- a/tests/exception/t21261.nim +++ /dev/null @@ -1,9 +0,0 @@ -discard """ - exitcode: 1 - outputsub: ''' -m21261.nim(1) m21261 -Error: unhandled exception: something [Exception] -''' -""" - -import m21261 \ No newline at end of file diff --git a/tests/exception/t9657.nim b/tests/exception/t9657.nim index 6ac525a70..0b6e128e0 100644 --- a/tests/exception/t9657.nim +++ b/tests/exception/t9657.nim @@ -1,12 +1,9 @@ discard """ action: run exitcode: 1 - targets: "c cpp" - disabled: "openbsd" - disabled: "netbsd" + target: "c" """ - +# todo: remove `target: "c"` workaround once #10343 is properly fixed close stdmsg const m = "exception!" -# see #10343 for details on this test discard writeBuffer(stdmsg, cstring(m), m.len) diff --git a/tests/exception/tcpp_imported_exc.nim b/tests/exception/tcpp_imported_exc.nim index 55a58440f..c8349f7d5 100644 --- a/tests/exception/tcpp_imported_exc.nim +++ b/tests/exception/tcpp_imported_exc.nim @@ -1,8 +1,6 @@ discard """ -matrix: "--mm:refc" targets: "cpp" -output: ''' -caught as std::exception +output: '''caught as std::exception expected finally1 finally2 @@ -14,10 +12,9 @@ finally 2 expected cpp exception caught ''' -disabled: "windows" # pending bug #18011 """ -type +type std_exception* {.importcpp: "std::exception", header: "".} = object std_runtime_error* {.importcpp: "std::runtime_error", header: "".} = object std_string* {.importcpp: "std::string", header: "".} = object @@ -28,7 +25,7 @@ proc constructRuntimeError(s: stdstring): std_runtime_error {.importcpp: "std::r proc what(ex: std_runtime_error): cstring {.importcpp: "((char *)#.what())".} -proc myexception = +proc myexception = raise constructRuntimeError(constructStdString("cpp_exception")) try: @@ -44,17 +41,17 @@ except std_exception: doAssert(getCurrentException() == nil) -proc earlyReturn = +proc earlyReturn = try: try: - myexception() + myexception() finally: echo "finally1" except: return finally: echo "finally2" - + earlyReturn() doAssert(getCurrentException() == nil) @@ -77,7 +74,7 @@ doAssert(getCurrentException() == nil) # raise by pointer and also generic type type - std_vector[T] {.importcpp"std::vector", header"".} = object + std_vector {.importcpp"std::vector", header"".} [T] = object proc newVector[T](len: int): ptr std_vector[T] {.importcpp: "new std::vector<'1>(@)".} proc deleteVector[T](v: ptr std_vector[T]) {.importcpp: "delete @; @ = NIM_NIL;".} @@ -121,15 +118,16 @@ try: echo "finally 2" except: echo "expected" - + + doAssert(getCurrentException() == nil) try: - try: - myexception() - except std_runtime_error as ex: - echo "cpp exception caught" - raise newException(ValueError, "rewritten " & $ex.what()) + try: + myexception() + except std_runtime_error as ex: + echo "cpp exception caught" + raise newException(ValueError, "rewritten " & $ex.what()) except: doAssert(getCurrentExceptionMsg() == "rewritten cpp_exception") diff --git a/tests/exception/tcpp_imported_exc2.nim b/tests/exception/tcpp_imported_exc2.nim deleted file mode 100644 index ff299ea3d..000000000 --- a/tests/exception/tcpp_imported_exc2.nim +++ /dev/null @@ -1,10 +0,0 @@ -discard """ -targets: "cpp" -output: "" -""" -#issue #14369 case 2 -type RuntimeError {.requiresInit, importcpp: "std::runtime_error", header: "".} = object - -proc initRuntimeError(a: cstring): RuntimeError {.importcpp: "std::runtime_error(@)", constructor.} -try: raise initRuntimeError("foo2") -except: discard diff --git a/tests/exception/texcas.nim b/tests/exception/texcas.nim index ad6819f11..7108e334c 100644 --- a/tests/exception/texcas.nim +++ b/tests/exception/texcas.nim @@ -1,9 +1,8 @@ discard """ targets: "c cpp" - output: ''' + output: '''Hello Hello -Hello -''' + ''' """ proc test[T]() = try: diff --git a/tests/exception/texception_inference.nim b/tests/exception/texception_inference.nim deleted file mode 100644 index 7dd01cca1..000000000 --- a/tests/exception/texception_inference.nim +++ /dev/null @@ -1,32 +0,0 @@ -discard """ - output: '''good''' - cmd: "nim c --gc:orc -d:release $file" -""" - -type - Raising[T, E] = object - -proc foo[T, Errors](x: proc (x: Raising[T, Errors])) {.raises: Errors.} = - discard - -proc callback(x: Raising[int, ValueError]) = - echo "callback" - -proc xy() {.raises: [ValueError].} = - foo callback - -proc x[E]() {.raises: [E, IOError].} = - raise newException(E, "text here") - -try: - x[ValueError]() -except ValueError: - echo "good" - -proc callback2(x: Raising[int, IOError]) = - discard - -proc foo2[T, OtherErrors](x: proc(x: Raising[T, OtherErrors])) {.raises: [ValueError, OtherErrors].} = - discard - -foo2 callback2 diff --git a/tests/exception/texceptionbreak.nim b/tests/exception/texceptionbreak.nim index b8ce7eead..6548192c6 100644 --- a/tests/exception/texceptionbreak.nim +++ b/tests/exception/texceptionbreak.nim @@ -29,16 +29,16 @@ echo "2" try: raise newException(OSError, "Problem") except OSError: - block label: - break label + block: + break echo "3" # Fourth Variety -block label: +block: try: raise newException(OSError, "Problem") except OSError: - break label + break echo "4" diff --git a/tests/exception/texceptions.nim b/tests/exception/texceptions.nim index 62d24c934..7bce32837 100644 --- a/tests/exception/texceptions.nim +++ b/tests/exception/texceptions.nim @@ -1,8 +1,5 @@ discard """ - disabled: "windows" # no sigsetjmp() there - matrix: "-d:nimStdSetjmp; -d:nimSigSetjmp; -d:nimRawSetjmp; -d:nimBuiltinSetjmp" output: ''' - BEFORE FINALLY @@ -19,7 +16,7 @@ FINALLY echo "" -proc no_exception = +proc no_expcetion = try: echo "BEFORE" @@ -30,7 +27,7 @@ proc no_exception = finally: echo "FINALLY" -try: no_exception() +try: no_expcetion() except: echo "RECOVER" echo "" @@ -92,10 +89,10 @@ block: result.add(1212) try: try: - raise newException(AssertionDefect, "a") + raise newException(AssertionError, "a") finally: result.add(42) - except AssertionDefect: + except AssertionError: result.add(99) finally: result.add(10) @@ -107,7 +104,7 @@ block: result.add(-1) except ValueError: result.add(-1) - except IndexDefect: + except IndexError: result.add(2) except: result.add(3) diff --git a/tests/exception/texceptions2.nim b/tests/exception/texceptions2.nim deleted file mode 100644 index 97fd856a0..000000000 --- a/tests/exception/texceptions2.nim +++ /dev/null @@ -1,130 +0,0 @@ -discard """ - disabled: "posix" # already covered by texceptions.nim - matrix: "-d:nimStdSetjmp; -d:nimRawSetjmp; -d:nimBuiltinSetjmp" - output: ''' - -BEFORE -FINALLY - -BEFORE -EXCEPT -FINALLY -RECOVER - -BEFORE -EXCEPT: IOError: hi -FINALLY -''' -""" - -echo "" - -proc no_exception = - try: - echo "BEFORE" - - except: - echo "EXCEPT" - raise - - finally: - echo "FINALLY" - -try: no_exception() -except: echo "RECOVER" - -echo "" - -proc reraise_in_except = - try: - echo "BEFORE" - raise newException(IOError, "") - - except IOError: - echo "EXCEPT" - raise - - finally: - echo "FINALLY" - -try: reraise_in_except() -except: echo "RECOVER" - -echo "" - -proc return_in_except = - try: - echo "BEFORE" - raise newException(IOError, "hi") - - except: - echo "EXCEPT: ", getCurrentException().name, ": ", getCurrentExceptionMsg() - return - - finally: - echo "FINALLY" - -try: return_in_except() -except: echo "RECOVER" - -block: #10417 - proc moo() {.noreturn.} = discard - - let bar = - try: - 1 - except: - moo() - - doAssert(bar == 1) - -# Make sure the VM handles the exceptions correctly -block: - proc fun1(): seq[int] = - try: - try: - raise newException(ValueError, "xx") - except: - doAssert("xx" == getCurrentExceptionMsg()) - raise newException(KeyError, "yy") - except: - doAssert("yy" == getCurrentExceptionMsg()) - result.add(1212) - try: - try: - raise newException(AssertionDefect, "a") - finally: - result.add(42) - except AssertionDefect: - result.add(99) - finally: - result.add(10) - result.add(4) - result.add(0) - try: - result.add(1) - except KeyError: - result.add(-1) - except ValueError: - result.add(-1) - except IndexDefect: - result.add(2) - except: - result.add(3) - - try: - try: - result.add(1) - return - except: - result.add(-1) - finally: - result.add(2) - except KeyError: - doAssert(false) - finally: - result.add(3) - - let x1 = fun1() - const x2 = fun1() - doAssert(x1 == x2) diff --git a/tests/exception/tindexerrorformatbounds.nim b/tests/exception/tindexerrorformatbounds.nim new file mode 100644 index 000000000..7563c5ffa --- /dev/null +++ b/tests/exception/tindexerrorformatbounds.nim @@ -0,0 +1,31 @@ +import os, osproc, strutils + +const characters = "abcdefghijklmnopqrstuvwxyz" +var s: string + +# # chcks.nim:23 +# # test formatErrorIndexBound returns correct bounds +block: + s = characters + try: + discard s[0..999] + except IndexError: + let msg = getCurrentExceptionMsg() + let expected = "index $# not in 0 .. $#" % [$len(s), $(len(s)-1)] + doAssert msg.contains expected, $(msg, expected) + +block: + try: + discard paramStr(999) + except IndexError: + let msg = getCurrentExceptionMsg() + let expected = "index 999 not in 0 .. 0" + doAssert msg.contains expected, $(msg, expected) + +block: + const nim = getCurrentCompilerExe() + for i in 1..4: + let (outp, errC) = execCmdEx("$# e tests/exception/testindexerroroutput.nims test$#" % [nim, $i]) + let expected = "index 3 not in 0 .. 2" + doAssert errC != 0 + doAssert outp.contains expected, $(outp, errC, expected, i) diff --git a/tests/exception/tsetexceptions.nim b/tests/exception/tsetexceptions.nim deleted file mode 100644 index 0e353f43e..000000000 --- a/tests/exception/tsetexceptions.nim +++ /dev/null @@ -1,11 +0,0 @@ -discard """ - targets: "c cpp js" - joinable: false -""" - -# refs https://github.com/nim-lang/Nim/pull/18247#issuecomment-860877161 - -let ex = newException(CatchableError, "test") -setCurrentException(ex) -doAssert getCurrentException().msg == ex.msg -doAssert getCurrentExceptionMsg() == ex.msg diff --git a/tests/exception/twrongexc.nim b/tests/exception/twrongexc.nim index d229c5749..9c656f3d9 100644 --- a/tests/exception/twrongexc.nim +++ b/tests/exception/twrongexc.nim @@ -4,5 +4,5 @@ discard """ """ try: raise newException(ValueError, "") -except OverflowDefect: +except OverflowError: echo("Error caught") diff --git a/tests/exprs/texprstmt.nim b/tests/exprs/texprstmt.nim index 3c9704650..742670cc1 100644 --- a/tests/exprs/texprstmt.nim +++ b/tests/exprs/texprstmt.nim @@ -1,5 +1,5 @@ discard """ - errormsg: "expression 'result[1 .. BackwardsIndex(1)]' is of type 'string' and has to be used (or discarded)" + errormsg: "expression 'result[1 .. BackwardsIndex(1)]' is of type 'string' and has to be discarded" line: 10 """ diff --git a/tests/exprs/tresultwarning.nim b/tests/exprs/tresultwarning.nim index 28dabfdb1..32934408e 100644 --- a/tests/exprs/tresultwarning.nim +++ b/tests/exprs/tresultwarning.nim @@ -1,5 +1,5 @@ discard """ - nimout: "tresultwarning.nim(6, 7) Warning: Special variable 'result' is shadowed. [ResultShadowed]" + nimout: "Special variable 'result' is shadowed. [ResultShadowed]" """ proc test(): string = diff --git a/tests/exprs/tstmtexp.nim b/tests/exprs/tstmtexp.nim index 0ae866497..75d8dd081 100644 --- a/tests/exprs/tstmtexp.nim +++ b/tests/exprs/tstmtexp.nim @@ -1,5 +1,5 @@ discard """ - errormsg: "expression '5' is of type 'int literal(5)' and has to be used (or discarded)" + errormsg: "expression '5' is of type 'int literal(5)' and has to be discarded" file: "tstmtexp.nim" line: 8 """ diff --git a/tests/fields/tfielditerator.nim b/tests/fields/tfielditerator.nim index d1fbf02f9..877e4454c 100644 --- a/tests/fields/tfielditerator.nim +++ b/tests/fields/tfielditerator.nim @@ -60,12 +60,12 @@ block titerator1: for key, val in fieldPairs(x): echo key, ": ", val - doAssert x != y - doAssert x == x - doAssert(not (x < x)) - doAssert x <= x - doAssert y < x - doAssert y <= x + assert x != y + assert x == x + assert(not (x < x)) + assert x <= x + assert y < x + assert y <= x block titerator2: diff --git a/tests/tools/compile/tniminst.nim b/tests/flags/tgenscript.nim similarity index 51% rename from tests/tools/compile/tniminst.nim rename to tests/flags/tgenscript.nim index 78c736af0..bf83ab972 100644 --- a/tests/tools/compile/tniminst.nim +++ b/tests/flags/tgenscript.nim @@ -1,5 +1,6 @@ discard """ + target: "c" action: compile """ -include tools/niminst/niminst \ No newline at end of file +echo "--genscript" diff --git a/tests/float/tfloat1.nim b/tests/float/tfloat1.nim index d3497f24c..54d49a7c1 100644 --- a/tests/float/tfloat1.nim +++ b/tests/float/tfloat1.nim @@ -1,5 +1,5 @@ discard """ - outputsub: "Error: unhandled exception: FPU operation caused an overflow [FloatOverflowDefect]" + outputsub: "Error: unhandled exception: FPU operation caused an overflow [FloatOverflowError]" exitcode: "1" """ # Test new floating point exceptions diff --git a/tests/float/tfloat2.nim b/tests/float/tfloat2.nim index 1de63dde3..130c71087 100644 --- a/tests/float/tfloat2.nim +++ b/tests/float/tfloat2.nim @@ -1,5 +1,5 @@ discard """ - outputsub: "Error: unhandled exception: FPU operation caused a NaN result [FloatInvalidOpDefect]" + outputsub: "Error: unhandled exception: FPU operation caused a NaN result [FloatInvalidOpError]" exitcode: "1" """ # Test new floating point exceptions diff --git a/tests/float/tfloat4.nim b/tests/float/tfloat4.nim index f6216c374..6a87cbe66 100644 --- a/tests/float/tfloat4.nim +++ b/tests/float/tfloat4.nim @@ -8,7 +8,7 @@ proc c_sprintf(buf, fmt: cstring) {.importc:"sprintf", header: "", vara proc floatToStr(f: float64): string = var buffer: array[128, char] - c_sprintf(cast[cstring](addr buffer), "%.16e", f) + c_sprintf(addr buffer, "%.16e", f) result = "" for ch in buffer: if ch == '\0': @@ -54,10 +54,4 @@ doAssert 9999999999999999.0 == "9999999999999999.0".parseFloat doAssert 0.999999999999999 == ".999999999999999".parseFloat doAssert 0.9999999999999999 == ".9999999999999999".parseFloat -# bug #18400 -var s = [-13.888888'f32] -assert $s[0] == "-13.888888" -var x = 1.23456789012345'f32 -assert $x == "1.2345679" - echo("passed all tests.") diff --git a/tests/float/tfloat6.nim b/tests/float/tfloat6.nim new file mode 100644 index 000000000..c4cd6e932 --- /dev/null +++ b/tests/float/tfloat6.nim @@ -0,0 +1,23 @@ +discard """ + output: ''' +1e-06 : 1e-06 +1e-06 : 1e-06 +0.001 : 0.001 +1e-06 : 1e-06 +1e-06 : 1e-06 +10.000001 : 10.000001 +100.000001 : 100.000001 +''' + disabled: "windows" +""" + +import strutils + +echo "0.00_0001".parseFloat(), " : ", 1E-6 +echo "0.00__00_01".parseFloat(), " : ", 1E-6 +echo "0.0_01".parseFloat(), " : ", 0.001 +echo "0.00_000_1".parseFloat(), " : ", 1E-6 +echo "0.00000_1".parseFloat(), " : ", 1E-6 + +echo "1_0.00_0001".parseFloat(), " : ", 10.000001 +echo "1__00.00_0001".parseFloat(), " : ", 1_00.000001 diff --git a/tests/float/tfloatmod.nim b/tests/float/tfloatmod.nim index 37546a64c..0b84ec7e0 100644 --- a/tests/float/tfloatmod.nim +++ b/tests/float/tfloatmod.nim @@ -1,5 +1,5 @@ discard """ - targets: "c cpp js" + targets: "c c++ js" output: "ok" exitcode: "0" """ diff --git a/tests/float/tfloatnan.nim b/tests/float/tfloatnan.nim index 9e3dd94f6..8f384c3d9 100644 --- a/tests/float/tfloatnan.nim +++ b/tests/float/tfloatnan.nim @@ -15,7 +15,7 @@ echo "Nim: ", f32, " (float)" let f64: float64 = NaN echo "Nim: ", f64, " (double)" -block: # bug #10305 +block: # issue #10305 # with `-O3 -ffast-math`, generated C/C++ code is not nan compliant # user can pass `--passC:-ffast-math` if he doesn't care. proc fun() = @@ -42,16 +42,3 @@ block: # bug #10305 fun() fun2(0) -template main() = - # xxx move all tests under here - block: # bug #16469 - let a1 = 0.0 - let a2 = -0.0 - let a3 = 1.0 / a1 - let a4 = 1.0 / a2 - doAssert a3 == Inf - doAssert a4 == -Inf - doAssert $(a1, a2, a3, a4) == "(0.0, -0.0, inf, -inf)" - -static: main() -main() diff --git a/tests/float/tfloats.nim b/tests/float/tfloats.nim deleted file mode 100644 index 480396e81..000000000 --- a/tests/float/tfloats.nim +++ /dev/null @@ -1,165 +0,0 @@ -discard """ - matrix: "-d:nimPreviewFloatRoundtrip; -u:nimPreviewFloatRoundtrip" - targets: "c cpp js" -""" - -#[ -xxx merge all or most float tests into this file -]# - -import std/[fenv, math, strutils] -import stdtest/testutils - -proc equalsOrNaNs(a, b: float): bool = - if isNaN(a): isNaN(b) - elif a == 0: - b == 0 and signbit(a) == signbit(b) - else: - a == b - -template reject(a) = - doAssertRaises(ValueError): discard parseFloat(a) - -template main = - block: - proc test(a: string, b: float) = - let a2 = a.parseFloat - doAssert equalsOrNaNs(a2, b), $(a, a2, b) - test "0.00_0001", 1E-6 - test "0.00__00_01", 1E-6 - test "0.0_01", 0.001 - test "0.00_000_1", 1E-6 - test "0.00000_1", 1E-6 - test "1_0.00_0001", 10.000001 - test "1__00.00_0001", 1_00.000001 - test "inf", Inf - test "-inf", -Inf - test "-Inf", -Inf - test "-INF", -Inf - test "NaN", NaN - test "-nan", NaN - test ".1", 0.1 - test "-.1", -0.1 - test "-0", -0.0 - when false: # pending bug #18246 - test "-0", -0.0 - test ".1e-1", 0.1e-1 - test "0_1_2_3.0_1_2_3E+0_1_2", 123.0123e12 - test "0_1_2.e-0", 12e0 - test "0_1_2e-0", 12e0 - test "-0e0", -0.0 - test "-0e-0", -0.0 - - reject "a" - reject "" - reject "e1" - reject "infa" - reject "infe1" - reject "_" - reject "1e" - - when false: # gray area; these numbers should probably be invalid - reject "1_" - reject "1_.0" - reject "1.0_" - - block: # bugs mentioned in https://github.com/nim-lang/Nim/pull/18504#issuecomment-881635317 - block: # example 1 - let a = 0.1+0.2 - doAssert a != 0.3 - when defined(nimPreviewFloatRoundtrip): - doAssert $a == "0.30000000000000004" - else: - whenRuntimeJs: discard - do: doAssert $a == "0.3" - block: # example 2 - const a = 0.1+0.2 - when defined(nimPreviewFloatRoundtrip): - doAssert $($a, a) == """("0.30000000000000004", 0.30000000000000004)""" - else: - whenRuntimeJs: discard - do: doAssert $($a, a) == """("0.3", 0.3)""" - block: # example 3 - const a1 = 0.1+0.2 - let a2 = a1 - doAssert a1 != 0.3 - when defined(nimPreviewFloatRoundtrip): - doAssert $[$a1, $a2] == """["0.30000000000000004", "0.30000000000000004"]""" - else: - whenRuntimeJs: discard - do: doAssert $[$a1, $a2] == """["0.3", "0.3"]""" - - when defined(nimPreviewFloatRoundtrip): - block: # bug #18148 - var a = 1.1'f32 - doAssert $a == "1.1", $a # was failing - - block: # bug #18400 - block: - let a1 = 0.1'f32 - let a2 = 0.2'f32 - let a3 = a1 + a2 - var s = "" - s.addFloat(a3) - whenVMorJs: discard # xxx refs #12884 - do: - doAssert a3 == 0.3'f32 - doAssert $a3 == "0.3" - - block: - let a1 = 0.1 - let a2 = 0.2 - let a3 = a1 + a2 - var s = "" - s.addFloat(a3) - doAssert a3 != 0.3 - doAssert $a3 == "0.30000000000000004" - - block: - var s = [-13.888888'f32] - whenRuntimeJs: discard - do: - doAssert $s == "[-13.888888]" - doAssert $s[0] == "-13.888888" - - block: # bug #7717 - proc test(f: float) = - let f2 = $f - let f3 = parseFloat(f2) - doAssert equalsOrNaNs(f, f3), $(f, f2, f3) - test 1.0 + epsilon(float64) - test 1000000.0000000123 - test log2(100000.0) - test maximumPositiveValue(float32) - test maximumPositiveValue(float64) - test minimumPositiveValue(float32) - test minimumPositiveValue(float64) - - block: # bug #12884 - block: # example 1 - const x0: float32 = 1.32 - let x1 = 1.32 - let x2 = 1.32'f32 - var x3: float32 = 1.32 - doAssert $(x0, x1, x2, x3) == "(1.32, 1.32, 1.32, 1.32)" - block: # example https://github.com/nim-lang/Nim/issues/12884#issuecomment-564967962 - let x = float(1.32'f32) - when nimvm: discard # xxx prints 1.3 - else: - when not defined(js): - doAssert $x == "1.3200000524520874" - doAssert $1.32 == "1.32" - doAssert $1.32'f32 == "1.32" - let x2 = 1.32'f32 - doAssert $x2 == "1.32" - block: - var x = 1.23456789012345'f32 - when nimvm: - discard # xxx, refs #12884 - else: - when not defined(js): - doAssert x == 1.2345679'f32 - doAssert $x == "1.2345679" - -static: main() -main() diff --git a/tests/gc/cyclecollector.nim b/tests/gc/cyclecollector.nim index 2d02a7a3c..7b47758f2 100644 --- a/tests/gc/cyclecollector.nim +++ b/tests/gc/cyclecollector.nim @@ -9,10 +9,7 @@ type proc createCycle(leaf: string): Node = new result result.a = result - when defined(gcArc) or defined(gcOrc): - result.leaf = leaf - else: - shallowCopy result.leaf, leaf + shallowCopy result.leaf, leaf proc main = for i in 0 .. 100_000: diff --git a/tests/gc/gcleak.nim b/tests/gc/gcleak.nim index 0bf993968..0b2e6e14d 100644 --- a/tests/gc/gcleak.nim +++ b/tests/gc/gcleak.nim @@ -12,14 +12,7 @@ type proc makeObj(): TTestObj = result.x = "Hello" -const numIter = - # see tests/gc/gcleak2.nim - when defined(boehmgc): - 1_000 - elif defined(gcMarkAndSweep): 10_000 - else: 100_000 - -for i in 1 .. numIter: +for i in 1 .. 100_000: when defined(gcMarkAndSweep) or defined(boehmgc): GC_fullcollect() var obj = makeObj() diff --git a/tests/gc/gcleak2.nim b/tests/gc/gcleak2.nim index bc943dbe7..fe1718aef 100644 --- a/tests/gc/gcleak2.nim +++ b/tests/gc/gcleak2.nim @@ -14,20 +14,8 @@ proc makeObj(): TTestObj = result.x = "Hello" result.s = @[1,2,3] -const numIter = - when defined(boehmgc): - # super slow because GC_fullcollect() at each iteration; especially - # on OSX 10.15 where it takes ~170s - # `getOccupiedMem` should be constant after each iteration for i >= 3 - 1_000 - elif defined(gcMarkAndSweep): - # likewise, somewhat slow, 1_000_000 would run for 8s - # and same remark as above - 100_000 - else: 1_000_000 - proc inProc() = - for i in 1 .. numIter: + for i in 1 .. 1_000_000: when defined(gcMarkAndSweep) or defined(boehmgc): GC_fullcollect() var obj: TTestObj diff --git a/tests/gc/gcleak3.nim b/tests/gc/gcleak3.nim index 5e146d69f..588e238e9 100644 --- a/tests/gc/gcleak3.nim +++ b/tests/gc/gcleak3.nim @@ -17,10 +17,14 @@ for i in 0..1024: s.add(obj) proc limit*[t](a: var seq[t]) = - while s.len > 0: + var loop = s.len() - 512 + for i in 0..loop: + #echo i + #GC_fullCollect() if getOccupiedMem() > 3000_000: quit("still a leak!") - s.delete(0) + s.delete(i) s.limit() + echo "no leak: ", getOccupiedMem() diff --git a/tests/gc/gcleak4.nim b/tests/gc/gcleak4.nim index a72db67b7..fbe18a386 100644 --- a/tests/gc/gcleak4.nim +++ b/tests/gc/gcleak4.nim @@ -35,7 +35,7 @@ proc newPlus(a, b: sink(ref TExpr)): ref TPlusExpr = const Limit = when compileOption("gc", "markAndSweep") or compileOption("gc", "boehm"): 5*1024*1024 else: 500_000 -for i in 0..50_000: +for i in 0..100_000: var s: array[0..11, ref TExpr] for j in 0..high(s): s[j] = newPlus(newPlus(newLit(j), newLit(2)), newLit(4)) diff --git a/tests/gc/gcleak5.nim b/tests/gc/gcleak5.nim index f1913831b..6ab50e19e 100644 --- a/tests/gc/gcleak5.nim +++ b/tests/gc/gcleak5.nim @@ -9,7 +9,7 @@ proc main = for ii in 0..50_000: #while true: var t = getTime() - var g = t.utc() + var g = t.getGMTime() #echo isOnStack(addr g) if i mod 100 == 0: diff --git a/tests/gc/growobjcrash.nim b/tests/gc/growobjcrash.nim index ff1aa7e98..07f92b8f4 100644 --- a/tests/gc/growobjcrash.nim +++ b/tests/gc/growobjcrash.nim @@ -1,4 +1,8 @@ -import std/[cgi, strtabs] +discard """ + output: "works" +""" + +import cgi, strtabs proc handleRequest(query: string): StringTableRef = iterator foo(): StringTableRef {.closure.} = @@ -14,7 +18,7 @@ const Limit = 5*1024*1024 proc main = var counter = 0 - for i in 0 .. 10_000: + for i in 0 .. 100_000: for k, v in handleRequest("nick=Elina2&type=activate"): inc counter if counter mod 100 == 0: @@ -22,3 +26,4 @@ proc main = quit "but now a leak" main() +echo "works" diff --git a/tests/gc/panicoverride.nim b/tests/gc/panicoverride.nim deleted file mode 100644 index 0f28b0b72..000000000 --- a/tests/gc/panicoverride.nim +++ /dev/null @@ -1,14 +0,0 @@ - -proc printf(frmt: cstring) {.varargs, importc, header: "", cdecl.} -proc exit(code: int) {.importc, header: "", cdecl.} - -{.push stack_trace: off, profiler:off.} - -proc rawoutput(s: string) = - printf("%s\n", s) - -proc panic(s: string) {.noreturn.} = - rawoutput(s) - exit(1) - -{.pop.} \ No newline at end of file diff --git a/tests/gc/thavlak.nim b/tests/gc/thavlak.nim index cfd860e25..b4cdacf7c 100644 --- a/tests/gc/thavlak.nim +++ b/tests/gc/thavlak.nim @@ -1,13 +1,13 @@ discard """ output: '''Welcome to LoopTesterApp, Nim edition Constructing Simple CFG... -5000 dummy loops +15000 dummy loops Constructing CFG... Performing Loop Recognition 1 Iteration -Another 3 iterations... -... -Found 1 loops (including artificial root node) (3)''' +Another 5 iterations... +..... +Found 1 loops (including artificial root node) (5)''' """ # bug #3184 @@ -384,9 +384,9 @@ proc run(self: var LoopTesterApp) = discard self.cfg.createNode(1) self.buildConnect(0, 2) - echo "5000 dummy loops" + echo "15000 dummy loops" - for i in 1..5000: + for i in 1..15000: withScratchRegion: var h = newHavlakLoopFinder(self.cfg, newLsg()) discard h.findLoops @@ -394,7 +394,7 @@ proc run(self: var LoopTesterApp) = echo "Constructing CFG..." var n = 2 - when true: # not defined(gcOrc): + when not defined(gcOrc): # currently cycle detection is so slow that we disable this part for parlooptrees in 1..10: discard self.cfg.createNode(n + 1) @@ -414,10 +414,10 @@ proc run(self: var LoopTesterApp) = var h = newHavlakLoopFinder(self.cfg, newLsg()) var loops = h.findLoops - echo "Another 3 iterations..." + echo "Another 5 iterations..." var sum = 0 - for i in 1..3: + for i in 1..5: withScratchRegion: write stdout, "." flushFile(stdout) @@ -437,5 +437,4 @@ proc main = let mem = getOccupiedMem() main() when defined(gcOrc): - GC_fullCollect() doAssert getOccupiedMem() == mem diff --git a/tests/gc/trace_globals.nim b/tests/gc/trace_globals.nim deleted file mode 100644 index f62a15692..000000000 --- a/tests/gc/trace_globals.nim +++ /dev/null @@ -1,33 +0,0 @@ -discard """ - output: ''' -10000000 -10000000 -10000000''' -""" - -# bug #17085 - -#[ -refs https://github.com/nim-lang/Nim/issues/17085#issuecomment-786466595 -with --gc:boehm, this warning sometimes gets generated: -Warning: Repeated allocation of very large block (appr. size 14880768): -May lead to memory leak and poor performance. -nim CI now runs this test with `testWithoutBoehm` to avoid running it with --gc:boehm. -]# - -proc init(): string = - for a in 0..<10000000: - result.add 'c' - -proc f() = - var a {.global.} = init() - var b {.global.} = init() - var c {.global.} = init() - - echo a.len - # `echo` intentional according to - # https://github.com/nim-lang/Nim/pull/17469/files/0c9e94cb6b9ebca9da7cb19a063fba7aa409748e#r600016573 - echo b.len - echo c.len - -f() diff --git a/tests/gc/tregionleak.nim b/tests/gc/tregionleak.nim deleted file mode 100644 index 277cfc987..000000000 --- a/tests/gc/tregionleak.nim +++ /dev/null @@ -1,23 +0,0 @@ -discard """ - cmd: '''nim c --gc:regions $file''' - output: ''' -finalized -finalized -''' -""" - -proc finish(o: RootRef) = - echo "finalized" - -withScratchRegion: - var test: RootRef - new(test, finish) - -var - mr: MemRegion - test: RootRef - -withRegion(mr): - new(test, finish) - -deallocAll(mr) diff --git a/tests/gc/tstandalone.nim b/tests/gc/tstandalone.nim deleted file mode 100644 index 41dad9ba4..000000000 --- a/tests/gc/tstandalone.nim +++ /dev/null @@ -1,14 +0,0 @@ -discard """ - matrix: "--os:standalone --gc:none" - exitcode: 1 - output: "value out of range" -""" - -type - rangeType = range[0..1] - -var - r: rangeType = 0 - i = 2 - -r = rangeType(i) diff --git a/tests/generics/mdotlookup.nim b/tests/generics/mdotlookup.nim index 3112c133f..2984574c2 100644 --- a/tests/generics/mdotlookup.nim +++ b/tests/generics/mdotlookup.nim @@ -1,15 +1,15 @@ -proc baz(o: auto): int = 5 # if bar is exported, it works +proc baz(o: any): int = 5 # if bar is exported, it works type MyObj = object x: int -proc foo*(b: auto) = +proc foo*(b: any) = var o: MyObj echo b.baz, " ", o.x.baz, " ", b.baz() import sets -var intset = initHashSet[int]() +var intset = initSet[int]() proc fn*[T](a: T) = if a in intset: echo("true") diff --git a/tests/generics/module_with_generics.nim b/tests/generics/module_with_generics.nim index 960a694d7..e801a4790 100644 --- a/tests/generics/module_with_generics.nim +++ b/tests/generics/module_with_generics.nim @@ -1,5 +1,5 @@ type - Base[T] {.inheritable.} = ref object + Base[T] = ref object {.inheritable.} value*: T Derived[T] = ref object of Base[T] diff --git a/tests/generics/t13525.nim b/tests/generics/t13525.nim deleted file mode 100644 index 1fd84852b..000000000 --- a/tests/generics/t13525.nim +++ /dev/null @@ -1,6 +0,0 @@ -# https://github.com/nim-lang/Nim/issues/13524 -template fun(field): untyped = astToStr(field) -proc test1(): string = fun(nonexistent1) -proc test2[T](): string = fun(nonexistent2) # used to cause: Error: undeclared identifier: 'nonexistent2' -doAssert test1() == "nonexistent1" -doAssert test2[int]() == "nonexistent2" diff --git a/tests/generics/t16639.nim b/tests/generics/t16639.nim deleted file mode 100644 index fc00dfc34..000000000 --- a/tests/generics/t16639.nim +++ /dev/null @@ -1,21 +0,0 @@ -discard """ - action: compile -""" - -type Foo[T] = object - when true: - x: float - -type Bar = object - when true: - x: float - -import std/macros -import std/assertions - -macro test() = - let a = getImpl(bindSym"Foo")[^1] - let b = getImpl(bindSym"Bar")[^1] - doAssert treeRepr(a) == treeRepr(b) - -test() diff --git a/tests/generics/t18859.nim b/tests/generics/t18859.nim deleted file mode 100644 index ca6c3d10b..000000000 --- a/tests/generics/t18859.nim +++ /dev/null @@ -1,17 +0,0 @@ -import macros - -macro symFromDesc(T: typedesc): untyped = - let typ = getType(T) - typ[1] - -template produceType(T: typedesc): untyped = - type - XT = object - x: symFromDesc(T) - - XT - -type - X[T] = produceType(T) - -var x: X[int] diff --git a/tests/generics/t20996.nim b/tests/generics/t20996.nim deleted file mode 100644 index 8aa83c4e2..000000000 --- a/tests/generics/t20996.nim +++ /dev/null @@ -1,15 +0,0 @@ -discard """ - action: compile -""" - -import std/macros - -macro matchMe(x: typed): untyped = - discard x.getTypeImpl - -type - ElementRT = object - Element[Z] = ElementRT # this version is needed, even though we don't use it - -let ar = ElementRT() -matchMe(ar) diff --git a/tests/generics/t4668.nim b/tests/generics/t4668.nim deleted file mode 100644 index bd44cc975..000000000 --- a/tests/generics/t4668.nim +++ /dev/null @@ -1,166 +0,0 @@ -discard """ - output: ''' -foo1 -foo2 -''' -""" - -block: - type - FooObj[T] = object - v: T - Foo1[T] = FooObj[T] - Foo2 = FooObj - - proc foo1(x: Foo1) = echo "foo1" - proc foo2(x: Foo2) = echo "foo2" - - var x: FooObj[float] - foo1(x) # works - foo2(x) # works - -block: - type - FooObj[T] = T - Foo1[T] = FooObj[T] - Foo2 = FooObj - Foo3 = Foo1 - Foo4x = FooObj[SomeInteger] - Foo4 = FooObj[SomeFloat] - Foo5x = Foo1[SomeInteger] - Foo5 = Foo1[SomeFloat] - - proc foo0(x: FooObj): int = 0 - proc foo1(x: Foo1): int = 1 - proc foo2(x: Foo2): int = 2 - proc foo3(x: Foo3): int = 3 - proc foo4(x: Foo4x): int = 40 - proc foo4(x: Foo4): int = 4 - proc foo5(x: Foo5x): int = 50 - proc foo5(x: Foo5): int = 5 - - block: - var x: FooObj[float] - doAssert(foo0(x) == 0) - doAssert(foo1(x) == 1) - doAssert(foo2(x) == 2) - doAssert(foo3(x) == 3) - doAssert(foo4(x) == 4) - doAssert(foo5(x) == 5) - - block: - var x: Foo1[float] - doAssert(foo0(x) == 0) - doAssert(foo1(x) == 1) - doAssert(foo2(x) == 2) - doAssert(foo3(x) == 3) - doAssert(foo4(x) == 4) - doAssert(foo5(x) == 5) - - block: - var x: Foo2[float] - doAssert(foo0(x) == 0) - doAssert(foo1(x) == 1) - doAssert(foo2(x) == 2) - doAssert(foo3(x) == 3) - doAssert(foo4(x) == 4) - doAssert(foo5(x) == 5) - -block: - type - FooObj[T,U] = object - x: T - y: U - Foo1[U,T] = FooObj[T,U] - Foo2 = FooObj - Foo3 = Foo1 - Foo4x = FooObj[SomeInteger,SomeInteger] - Foo4y = FooObj[SomeInteger,SomeFloat] - Foo4z = FooObj[SomeFloat,SomeFloat] - Foo4 = FooObj[SomeFloat,SomeInteger] - Foo5x = Foo1[SomeInteger,SomeInteger] - Foo5y = Foo1[SomeFloat,SomeInteger] - Foo5z = Foo1[SomeFloat,SomeFloat] - Foo5 = Foo1[SomeInteger,SomeFloat] - - proc foo0(x: FooObj): int = 0 - proc foo1(x: Foo1): int = 1 - proc foo2(x: Foo2): int = 2 - proc foo3(x: Foo3): int = 3 - proc foo4(x: Foo4x): int = 40 - proc foo4(x: Foo4y): int = 41 - proc foo4(x: Foo4z): int = 42 - proc foo4(x: Foo4): int = 4 - proc foo5(x: Foo5x): int = 50 - proc foo5(x: Foo5y): int = 51 - proc foo5(x: Foo5z): int = 52 - proc foo5(x: Foo5): int = 5 - - block: - var x: FooObj[float,int] - doAssert(foo0(x) == 0) - doAssert(foo1(x) == 1) - doAssert(foo2(x) == 2) - doAssert(foo3(x) == 3) - doAssert(foo4(x) == 4) - doAssert(foo5(x) == 5) - - block: - var x: Foo1[int,float] - doAssert(foo0(x) == 0) - doAssert(foo1(x) == 1) - doAssert(foo2(x) == 2) - doAssert(foo3(x) == 3) - doAssert(foo4(x) == 4) - doAssert(foo5(x) == 5) - -block: - type - FooObj[T] = object of RootObj - v: T - FooObj2[T] = object of FooObj[T] - Foo1[T] = FooObj[T] - Foo2 = FooObj - Foo3 = Foo1 - Foo4x = FooObj[SomeInteger] - Foo4 = FooObj[SomeFloat] - Foo5x = Foo1[SomeInteger] - Foo5 = Foo1[SomeFloat] - - proc foo0(x: FooObj): int = 0 - proc foo1(x: Foo1): int = 1 - proc foo2(x: Foo2): int = 2 - proc foo3(x: Foo3): int = 3 - proc foo4(x: Foo4x): int = 40 - proc foo4(x: Foo4): int = 4 - proc foo5(x: Foo5x): int = 50 - proc foo5(x: Foo5): int = 5 - - block: - var x: FooObj[float] - doAssert(foo0(x) == 0) - doAssert(foo1(x) == 1) - doAssert(foo2(x) == 2) - doAssert(foo3(x) == 3) - doAssert(foo4(x) == 4) - doAssert(foo5(x) == 5) - - block: - var x: Foo1[float] - doAssert(foo0(x) == 0) - doAssert(foo1(x) == 1) - doAssert(foo2(x) == 2) - doAssert(foo3(x) == 3) - doAssert(foo4(x) == 4) - doAssert(foo5(x) == 5) - - #[ XXX These still fail - block: - var x: FooObj2[float] - doAssert(foo0(x) == 0) - doAssert(foo1(x) == 1) - doAssert(foo2(x) == 2) - doAssert(foo3(x) == 3) - doAssert(foo4(x) == 4) - doAssert(foo5(x) == 5) - ]# diff --git a/tests/generics/t500.nim b/tests/generics/t500.nim deleted file mode 100644 index 2486359aa..000000000 --- a/tests/generics/t500.nim +++ /dev/null @@ -1,8 +0,0 @@ -discard """ -action: compile -""" - -type - TTest = tuple[x: range[0..80], y: range[0..25]] - -let x: TTest = (2, 23) diff --git a/tests/generics/t5926.nim b/tests/generics/t5926.nim deleted file mode 100644 index bb14c3af5..000000000 --- a/tests/generics/t5926.nim +++ /dev/null @@ -1,22 +0,0 @@ -discard """ -action: compile -""" - -type - SomeObj[T] = object - -template useSomeObj[T]() = - var retObj: SomeObj[T] - -useSomeObj[void]() -useSomeObj[int]() - - -type - Data*[T] = object - x: T - -template test*[T](xxx: T) = - let data = Data[T](x: xxx) - -test(1) diff --git a/tests/generics/t6060.nim b/tests/generics/t6060.nim deleted file mode 100644 index 6b1856f1c..000000000 --- a/tests/generics/t6060.nim +++ /dev/null @@ -1,11 +0,0 @@ -import tables - -type MyTab[A,B] = distinct TableRef[A,B] - -proc `$`[A,B](t: MyTab[A,B]): string = - "My special table " & $TableRef[A,B](t) - -proc create[A,B](): MyTab[A,B] = MyTab(newTable[A,B]()) - -var a = create[int,int]() -doAssert $a == "My special table {:}" diff --git a/tests/generics/t6137.nim b/tests/generics/t6137.nim index 991f39dd1..abf02a756 100644 --- a/tests/generics/t6137.nim +++ b/tests/generics/t6137.nim @@ -16,7 +16,7 @@ let # define a vector of length 3 x: vector[3] = [1.0, 3.0, 5.0] -proc vectFunc[T](x: vector[T]): vector[T] = +proc vectFunc[T](x: vector[T]): vector[T] {.procvar.} = # Define a vector function result = 2.0*x diff --git a/tests/generics/t6637.nim b/tests/generics/t6637.nim deleted file mode 100644 index dd4f339a2..000000000 --- a/tests/generics/t6637.nim +++ /dev/null @@ -1,9 +0,0 @@ - -type - Grid2D*[I: SomeInteger, w, h: static[I], T] = object - grid: array[w, array[h, T]] - Grid2DIns = Grid2D[int, 2, 3, uint8] - -let a = Grid2DIns() -doAssert a.grid.len == 2 -doAssert a.grid[0].len == 3 diff --git a/tests/generics/t7446.nim b/tests/generics/t7446.nim deleted file mode 100644 index 71aa8f0e8..000000000 --- a/tests/generics/t7446.nim +++ /dev/null @@ -1,10 +0,0 @@ -proc foo(x: Natural or SomeUnsignedInt):int = - when x is int: - result = 1 - else: - result = 2 -let a = 10 -doAssert foo(a) == 1 - -let b = 10'u8 -doAssert foo(b) == 2 \ No newline at end of file diff --git a/tests/generics/tarc_misc.nim b/tests/generics/tarc_misc.nim deleted file mode 100644 index 3e7762556..000000000 --- a/tests/generics/tarc_misc.nim +++ /dev/null @@ -1,21 +0,0 @@ -discard """ - output: '''''' - cmd: "nim c --gc:arc $file" -""" - -# bug #13519 - -var unrelated: seq[proc() {.closure, gcsafe.}] - -unrelated.add proc () = - echo "gcsafe" - -import tables, sequtils -let t = newTable[int, proc()]() - -type - MyProc = proc() {.closure.} - -var result: seq[MyProc] = @[] -for x in t.values: - result.add(x) diff --git a/tests/generics/tbintree.nim b/tests/generics/tbintree.nim index 83f14406b..a1a13c7b5 100644 --- a/tests/generics/tbintree.nim +++ b/tests/generics/tbintree.nim @@ -55,8 +55,8 @@ proc find*[Ty2](b: PBinaryTree[Ty2], data: Ty2): bool = iterator preorder*[T](root: PBinaryTree[T]): T = # Preorder traversal of a binary tree. - # This uses an explicit stack (which is more efficient than - # a recursive iterator factory). + # Since recursive iterators are not yet implemented, + # this uses an explicit stack: var stack: seq[PBinaryTree[T]] = @[root] while stack.len > 0: var n = stack.pop() diff --git a/tests/generics/tcan.nim b/tests/generics/tcan.nim index bbefa7233..eea69cdb7 100644 --- a/tests/generics/tcan.nim +++ b/tests/generics/tcan.nim @@ -31,7 +31,7 @@ block tinherit: block tspecialise: type - TGen[T] {.inheritable.} = object + TGen[T] = object {.inheritable.} TSpef = object of TGen[string] diff --git a/tests/generics/texplicitgeneric2.nim b/tests/generics/texplicitgeneric2.nim index 37b133130..573b10ae8 100644 --- a/tests/generics/texplicitgeneric2.nim +++ b/tests/generics/texplicitgeneric2.nim @@ -1,5 +1,6 @@ discard """ output: "Key: 12 value: 12Key: 13 value: 13 Key: A value: 12 Key: B value: 13" + disabled: true """ # test explicit type instantiation @@ -13,12 +14,12 @@ proc newDict*[TKey, TValue](): PDict[TKey, TValue] = new(result) result.data = @[] -proc add*(d: PDict, k: d.TKey, v: d.TValue) = +proc add*(d: PDict, k: TKey, v: TValue) = d.data.add((k, v)) -iterator items*(d: PDict): tuple[k: d.TKey, v: d.TValue] = - for k, v in items(d.data): yield (k, v) +#iterator items*(d: PDict): tuple[k: TKey, v: TValue] = +# for k, v in items(d.data): yield (k, v) var d = newDict[int, string]() d.add(12, "12") diff --git a/tests/generics/tgeneric0.nim b/tests/generics/tgeneric0.nim index b5e1c4bb4..ae4820f57 100644 --- a/tests/generics/tgeneric0.nim +++ b/tests/generics/tgeneric0.nim @@ -140,29 +140,3 @@ var res = Resource(name: "Resource 1") (proc (r: typeof(res)) = echo r[])(res) - -# bug #4061 - -type List[T] = object - e: T - n: ptr List[T] - -proc zip*[T,U](xs: List[T], ys: List[U]): List[(T,U)] = discard - -proc unzip*[T,U](xs: List[tuple[t: T, u: U]]): (List[T], List[U]) = discard - -proc unzip2*[T,U](xs: List[(T,U)]): (List[T], List[U]) = discard - -type - AtomicType = pointer|ptr|int - - Atomic[T: AtomicType] = distinct T - - Block[T: AtomicType] = object - - AtomicContainer[T: AtomicType] = object - b: Atomic[ptr Block[T]] - -# bug #8295 -var x = AtomicContainer[int]() -doAssert (ptr Block[int])(x.b) == nil diff --git a/tests/generics/tgeneric3.nim b/tests/generics/tgeneric3.nim index 29a73afc6..4cb12f91b 100644 --- a/tests/generics/tgeneric3.nim +++ b/tests/generics/tgeneric3.nim @@ -1,9 +1,9 @@ discard """ output: ''' 312 -1000 -1000 -500 +1000000 +1000000 +500000 0 ''' """ @@ -12,7 +12,7 @@ import strutils type PNode[T,D] = ref TNode[T,D] - TItem[T,D] {.acyclic, pure, final, shallow.} = object + TItem {.acyclic, pure, final, shallow.} [T,D] = object key: T value: D node: PNode[T,D] @@ -20,7 +20,7 @@ type val_set: bool TItems[T,D] = seq[ref TItem[T,D]] - TNode[T,D] {.acyclic, pure, final, shallow.} = object + TNode {.acyclic, pure, final, shallow.} [T,D] = object slots: TItems[T,D] left: PNode[T,D] count: int32 @@ -243,7 +243,7 @@ proc InsertItem[T,D](APath: RPath[T,D], ANode:PNode[T,D], Akey: T, Avalue: D) = of cLenCenter: setLen(APath.Nd.slots, cLen4) of cLen4: setLen(APath.Nd.slots, cLenMax) else: discard - for i in countdown(APath.Nd.count.int - 1, x + 1): APath.Nd.slots[i] = move APath.Nd.slots[i - 1] + for i in countdown(APath.Nd.count.int - 1, x + 1): shallowCopy(APath.Nd.slots[i], APath.Nd.slots[i - 1]) APath.Nd.slots[x] = setItem(Akey, Avalue, ANode) @@ -255,39 +255,31 @@ proc SplitPage[T,D](n, left: PNode[T,D], xi: int, Akey:var T, Avalue:var D): PNo result.slots.newSeq(cLenCenter) result.count = cCenter if x == cCenter: - for i in 0..cCenter-1: - it1[i] = move left.slots[i] - for i in 0..cCenter-1: - result.slots[i] = move left.slots[cCenter + i] + for i in 0..cCenter-1: shallowCopy(it1[i], left.slots[i]) + for i in 0..cCenter-1: shallowCopy(result.slots[i], left.slots[cCenter + i]) result.left = n else : if x < cCenter : - for i in 0..x-1: - it1[i] = move left.slots[i] + for i in 0..x-1: shallowCopy(it1[i], left.slots[i]) it1[x] = setItem(Akey, Avalue, n) - for i in x+1 .. cCenter-1: - it1[i] = move left.slots[i-1] + for i in x+1 .. cCenter-1: shallowCopy(it1[i], left.slots[i-1]) var w = left.slots[cCenter-1] Akey = w.key Avalue = w.value result.left = w.node - for i in 0..cCenter-1: - result.slots[i] = move left.slots[cCenter + i] + for i in 0..cCenter-1: shallowCopy(result.slots[i], left.slots[cCenter + i]) else : - for i in 0..cCenter-1: - it1[i] = move left.slots[i] + for i in 0..cCenter-1: shallowCopy(it1[i], left.slots[i]) x = x - (cCenter + 1) - for i in 0..x-1: - result.slots[i] = move left.slots[cCenter + i + 1] + for i in 0..x-1: shallowCopy(result.slots[i], left.slots[cCenter + i + 1]) result.slots[x] = setItem(Akey, Avalue, n) - for i in x+1 .. cCenter-1: - result.slots[i] = move left.slots[cCenter + i] + for i in x+1 .. cCenter-1: shallowCopy(result.slots[i], left.slots[cCenter + i]) var w = left.slots[cCenter] Akey = w.key Avalue = w.value result.left = w.node left.count = cCenter - left.slots = move it1 + shallowCopy(left.slots, it1) proc internalPut[T,D](ANode: ref TNode[T,D], Akey: T, Avalue: D, Oldvalue: var D): ref TNode[T,D] = @@ -445,7 +437,7 @@ proc test() = var it1 = internalFind(root, 312) echo it1.value - for i in 1..1_000: + for i in 1..1_000_000: root = internalPut(root, i, i, oldvalue) var cnt = 0 diff --git a/tests/generics/tgeneric_recursionlimit.nim b/tests/generics/tgeneric_recursionlimit.nim deleted file mode 100644 index 5fe9b43c6..000000000 --- a/tests/generics/tgeneric_recursionlimit.nim +++ /dev/null @@ -1,123 +0,0 @@ -discard """ - action: "compile" -""" - -# https://github.com/nim-lang/Nim/issues/20348 - -type - Payload[T] = object - payload: T - Carrier[T] = object - val: T - -type - Payload0*[T] = object - payload: Payload[T] - Payload1*[T] = object - payload: Payload[T] - Payload2*[T] = object - payload: Payload[T] - Payload3*[T] = object - payload: Payload[T] - Payload4*[T] = object - payload: Payload[T] - Payload5*[T] = object - payload: Payload[T] - Payload6*[T] = object - payload: Payload[T] - Payload7*[T] = object - payload: Payload[T] - Payload8*[T] = object - payload: Payload[T] - Payload9*[T] = object - payload: Payload[T] - Payload10*[T] = object - payload: Payload[T] - Payload11*[T] = object - payload: Payload[T] - Payload12*[T] = object - payload: Payload[T] - Payload13*[T] = object - payload: Payload[T] - Payload14*[T] = object - payload: Payload[T] - Payload15*[T] = object - payload: Payload[T] - Payload16*[T] = object - payload: Payload[T] - Payload17*[T] = object - payload: Payload[T] - Payload18*[T] = object - payload: Payload[T] - Payload19*[T] = object - payload: Payload[T] - Payload20*[T] = object - payload: Payload[T] - Payload21*[T] = object - payload: Payload[T] - Payload22*[T] = object - payload: Payload[T] - Payload23*[T] = object - payload: Payload[T] - Payload24*[T] = object - payload: Payload[T] - Payload25*[T] = object - payload: Payload[T] - Payload26*[T] = object - payload: Payload[T] - Payload27*[T] = object - payload: Payload[T] - Payload28*[T] = object - payload: Payload[T] - Payload29*[T] = object - payload: Payload[T] - Payload30*[T] = object - payload: Payload[T] - Payload31*[T] = object - payload: Payload[T] - Payload32*[T] = object - payload: Payload[T] - Payload33*[T] = object - payload: Payload[T] - -type - Carriers*[T] = object - c0*: Carrier[Payload0[T]] - c1*: Carrier[Payload1[T]] - c2*: Carrier[Payload2[T]] - c3*: Carrier[Payload3[T]] - c4*: Carrier[Payload4[T]] - c5*: Carrier[Payload5[T]] - c6*: Carrier[Payload6[T]] - c7*: Carrier[Payload7[T]] - c8*: Carrier[Payload8[T]] - c9*: Carrier[Payload9[T]] - c10*: Carrier[Payload10[T]] - c11*: Carrier[Payload11[T]] - c12*: Carrier[Payload12[T]] - c13*: Carrier[Payload13[T]] - c14*: Carrier[Payload14[T]] - c15*: Carrier[Payload15[T]] - c16*: Carrier[Payload16[T]] - c17*: Carrier[Payload17[T]] - c18*: Carrier[Payload18[T]] - c19*: Carrier[Payload19[T]] - c20*: Carrier[Payload20[T]] - c21*: Carrier[Payload21[T]] - c22*: Carrier[Payload22[T]] - c23*: Carrier[Payload23[T]] - c24*: Carrier[Payload24[T]] - c25*: Carrier[Payload25[T]] - c26*: Carrier[Payload26[T]] - c27*: Carrier[Payload27[T]] - c28*: Carrier[Payload28[T]] - c29*: Carrier[Payload29[T]] - c30*: Carrier[Payload30[T]] - c31*: Carrier[Payload31[T]] - c32*: Carrier[Payload32[T]] - c33*: Carrier[Payload33[T]] - -var carriers : Carriers[int] - -static: - assert $(typeof(carriers.c33.val)) == "Payload33[system.int]" diff --git a/tests/generics/tgenerics_issues.nim b/tests/generics/tgenerics_issues.nim index 3068a22f2..af71a8938 100644 --- a/tests/generics/tgenerics_issues.nim +++ b/tests/generics/tgenerics_issues.nim @@ -23,10 +23,6 @@ concrete 88 G:0,1:0.1 G:0,1:0.1 H:1:0.1 -0 -(foo: none(seq[Foo]), s: "") -(foo: some(@[(a: "world", bar: none(Bar))]), s: "hello,") -@[(a: "hey", bar: none(Bar))] ''' joinable: false """ @@ -55,8 +51,8 @@ block t88: let c = ChildClass[string].new("Base", "Child") - doAssert c.baseMethod == "Base" - doAssert c.overriddenMethod == "Child" + assert c.baseMethod == "Base" + assert c.overriddenMethod == "Child" @@ -128,7 +124,7 @@ block t1789: bar: array[N, T] proc `[]`[N, T](f: Bar[N, T], n: range[0..(N - 1)]): T = - doAssert high(n) == N-1 + assert high(n) == N-1 result = f.bar[n] var b: Bar[3, int] @@ -603,7 +599,7 @@ block t7854: block t5864: - proc defaultStatic(s: openArray, N: static[int] = 1): int = N + proc defaultStatic(s: openarray, N: static[int] = 1): int = N proc defaultGeneric[T](a: T = 2): int = a let a = [1, 2, 3, 4].defaultStatic() @@ -734,7 +730,7 @@ block t1684: proc newDerived(idx: int): DerivedType {.inline.} = DerivedType(idx: idx) let d = newDerived(2) - doAssert(d.index == 2) + assert(d.index == 2) @@ -766,129 +762,3 @@ block t3717: var f: Foo[Foo[int]] discard foo(f) - - - -block: # issue #9458 - type - Option[T] = object - val: T - has: bool - - Bar = object - - proc none(T: typedesc): Option[T] = - discard - - proc foo[T](self: T; x: Option[Bar] = Bar.none) = - discard - - foo(1) - - -# bug #8426 -type - MyBool[T: uint] = range[T(0)..T(1)] # Works - -var x: MyBool[uint] -echo x - -# x = 2 # correctly prevented - -type - MyBool2 = range[uint(0)..uint(1)] # Error ordinal or float type expected - - -# bug #10396 -import options, strutils - -type - Foo {.acyclic.} = object - a: string - bar: Option[Bar] - - Bar {.acyclic.} = object - foo: Option[seq[Foo]] # if this was just Option[Foo], everything works fine - s: string - -proc getBar(x: string): Bar - -proc intoFoos(ss: seq[string]): seq[Foo] = - result = @[] - for s in ss: - let spl = s.split(',') - if spl.len > 1: - result.add Foo(a: spl[0], - bar: some(getBar(spl[1]))) - else: - result.add Foo(a: s, - bar: none[Bar]()) - -proc getBar(x: string): Bar = - let spl = x.split(' ') - result = - if spl.len > 1: - Bar(foo: some(spl[1..high(spl)].intoFoos), - s: spl[0]) - else: - Bar(foo: none[seq[Foo]](), - s: "") - -proc fakeReadLine(): string = "hey" - -echo getBar(fakeReadLine()) # causes error - -echo getBar("hello, world") # causes error - -discard $getBar(fakeReadLine()) # causes error - -discard $getBar("hello, world") # causes error - -discard getBar(fakeReadLine()) # no error - -discard getBar("hello, world") # no error - -echo intoFoos(fakeReadLine().split(' ')) # no error, works as expected - - -# bug #14990 -type - Tile3 = Tile2 - Tile2 = Tile - Tile[n] = object - a: n - -var a: Tile3[int] - -block: # Ensure no segfault from constraint - type - Regex[A: SomeOrdinal] = ref object - val: Regex[A] - MyConstraint = (seq or enum or set) - MyOtherType[A: MyConstraint] = ref object - val: MyOtherType[A] - - var - a = Regex[int]() - b = Regex[bool]() - c = MyOtherType[seq[int]]() - -block: # https://github.com/nim-lang/Nim/issues/20416 - type - Item[T] = object - link:ptr Item[T] - data:T - - KVSeq[A,B] = seq[(A,B)] - - MyTable[A,B] = object - data: KVSeq[A,B] - - Container[T] = object - a: MyTable[int,ref Item[T]] - - proc p1(sg:Container) = discard # Make sure that a non parameterized 'Container' argument still compiles - - proc p2[T](sg:Container[T]) = discard - var v : Container[int] - p2(v) diff --git a/tests/generics/tgenerics_various.nim b/tests/generics/tgenerics_various.nim index 4cfa47809..22d3cff7a 100644 --- a/tests/generics/tgenerics_various.nim +++ b/tests/generics/tgenerics_various.nim @@ -58,23 +58,23 @@ block tgenericdefaults: var x1: TFoo[int, float] static: - doAssert type(x1.x) is int - doAssert type(x1.y) is float - doAssert type(x1.z) is int + assert type(x1.x) is int + assert type(x1.y) is float + assert type(x1.z) is int var x2: TFoo[string, R = float, U = seq[int]] static: - doAssert type(x2.x) is string - doAssert type(x2.y) is seq[int] - doAssert type(x2.z) is float + assert type(x2.x) is string + assert type(x2.y) is seq[int] + assert type(x2.z) is float var x3: TBar[float] static: - doAssert type(x3.x) is float - doAssert type(x3.y) is array[4, float] - doAssert type(x3.z) is float + assert type(x3.x) is float + assert type(x3.y) is array[4, float] + assert type(x3.z) is float @@ -150,31 +150,31 @@ block tsharedcases: doAssert high(f2.data2) == 3 # int8.len - 1 == 3 static: - doAssert high(f1.data1) == ord(C) - doAssert high(f1.data2) == 5 # length of MyEnum minus one, because we used T.high + assert high(f1.data1) == ord(C) + assert high(f1.data2) == 5 # length of MyEnum minus one, because we used T.high - doAssert high(f2.data1) == 126 - doAssert high(f2.data2) == 3 + assert high(f2.data1) == 126 + assert high(f2.data2) == 3 - doAssert high(f1.data3) == 6 # length of MyEnum - doAssert high(f2.data3) == 4 # length of int8 + assert high(f1.data3) == 6 # length of MyEnum + assert high(f2.data3) == 4 # length of int8 - doAssert f2.data3[0] is float + assert f2.data3[0] is float block tmap_auto: let x = map(@[1, 2, 3], x => x+10) - doAssert x == @[11, 12, 13] + assert x == @[11, 12, 13] let y = map(@[(1,"a"), (2,"b"), (3,"c")], x => $x[0] & x[1]) - doAssert y == @["1a", "2b", "3c"] + assert y == @["1a", "2b", "3c"] proc eatsTwoArgProc[T,S,U](a: T, b: S, f: proc(t: T, s: S): U): U = f(a,b) let z = eatsTwoArgProc(1, "a", (t,s) => $t & s) - doAssert z == "1a" + assert z == "1a" @@ -230,8 +230,8 @@ block tvarargs_vs_generics: echo "direct" proc withDirectType[T](arg: T) = echo "generic" - proc withOpenArray(args: openArray[string]) = - echo "openArray" + proc withOpenArray(args: openarray[string]) = + echo "openarray" proc withOpenArray[T](arg: T) = echo "generic" proc withVarargs(args: varargs[string]) = @@ -253,17 +253,3 @@ block: var x: Que[int] doAssert(x.x == 0) - - -# bug #4466 -proc identity[T](t: T): T = t - -proc doSomething[A, B](t: tuple[a: A, b: B]) = discard - -discard identity((c: 1, d: 2)) -doSomething(identity((1, 2))) - -# bug #6231 -proc myProc[T, U](x: T or U) = discard - -myProc[int, string](x = 2) diff --git a/tests/generics/timplicit_and_explicit.nim b/tests/generics/timplicit_and_explicit.nim deleted file mode 100644 index ba24b79e9..000000000 --- a/tests/generics/timplicit_and_explicit.nim +++ /dev/null @@ -1,45 +0,0 @@ - -block: # basic test - proc doStuff[T](a: SomeInteger): T = discard - proc doStuff[T;Y](a: SomeInteger, b: Y): Y = discard - assert typeof(doStuff[int](100)) is int - assert typeof(doStuff[int](100, 1.0)) is float - assert typeof(doStuff[int](100, "Hello")) is string - - proc t[T](x: T; z: int | float): seq[T] = result.add(x & $z) - - assert t[string]("Hallo", 2.0) == @["Hallo" & $2.0] - - proc t2[T](z: int | float): seq[T] = result.add($z) - - assert t2[string](2.0) == @[$2.0] - -block: # template test - template someThing[T;Y](a: SomeFloat, b: SomeOrdinal): (T, Y) = (a, b) - assert typeof(someThing[float64, int](1.0, 100)) is (float64, int) - -block: # static test - proc t[T](s: static bool) = discard - proc t2[T](s: static string) = discard - t[string](true) - t2[int]("hello") - t2[string]("world") - t2[float]("test222222") - -block: #11152 - proc f[T](X: typedesc) = discard - f[int](string) - -block: #15622 - proc test1[T](a: T, b: static[string] = "") = discard - test1[int64](123) - proc test2[T](a: T, b: static[string] = "") = discard - test2[int64, static[string]](123) - -block: #4688 - proc convertTo[T](v: int or float): T = (T)(v) - discard convertTo[float](1) - -block: #4164 - proc printStr[T](s: static[string]): T = discard - discard printStr[int]("hello static") \ No newline at end of file diff --git a/tests/generics/tinheritable_importcpp.nim b/tests/generics/tinheritable_importcpp.nim deleted file mode 100644 index 8ee18b70b..000000000 --- a/tests/generics/tinheritable_importcpp.nim +++ /dev/null @@ -1,10 +0,0 @@ -discard """ - targets: "cpp" - action: compile -""" - -# #4651 -type - Vector[T] {.importcpp: "std::vector<'0 >", header: "vector", inheritable.} = object - VectorDerived {.importcpp: "SomeVectorDerived", nodecl.} = object of Vector[int] - # Error: inheritance only works with non-final objects diff --git a/tests/generics/tmetafield.nim b/tests/generics/tmetafield.nim index cf30a936d..7a2375abe 100644 --- a/tests/generics/tmetafield.nim +++ b/tests/generics/tmetafield.nim @@ -1,23 +1,10 @@ discard """ cmd: "nim check $options $file" - action: "reject" - nimout: ''' -tmetafield.nim(26, 5) Error: 'proc' is not a concrete type; for a callback without parameters use 'proc()' -tmetafield.nim(27, 5) Error: 'Foo' is not a concrete type -tmetafield.nim(29, 5) Error: invalid type: 'proc' in this context: 'TBaseMed' for var -''' + errormsg: "'proc' is not a concrete type" + errormsg: "'Foo' is not a concrete type." + errormsg: "invalid type: 'proc' in this context: 'TBaseMed'" """ -# bug #188 - - - - - - - - -# line 20 type Foo[T] = object x: T @@ -28,3 +15,4 @@ type var a: TBaseMed +# issue 188 diff --git a/tests/generics/tnullary_generics.nim b/tests/generics/tnullary_generics.nim deleted file mode 100644 index c79558ee3..000000000 --- a/tests/generics/tnullary_generics.nim +++ /dev/null @@ -1,26 +0,0 @@ -discard """ - nimout: ''' -hah -hey -hey -hah -''' -""" - -# non-generic -proc foo(s: string) = - static: echo "hah" - echo s - -static: echo "hey" - -foo("hoo") - -# nullary generic -proc bar[](s: string) = - static: echo "hah" - echo s - -static: echo "hey" - -bar("hoo") diff --git a/tests/generics/tparam_binding.nim b/tests/generics/tparam_binding.nim index fa7558613..cd0d58e02 100644 --- a/tests/generics/tparam_binding.nim +++ b/tests/generics/tparam_binding.nim @@ -1,7 +1,6 @@ discard """ - matrix: "--mm:arc; --mm:refc" errormsg: "got " - line: 28 + line: 27 """ type diff --git a/tests/generics/tparser_generator.nim b/tests/generics/tparser_generator.nim index ac921c0e5..8f8fea382 100644 --- a/tests/generics/tparser_generator.nim +++ b/tests/generics/tparser_generator.nim @@ -147,7 +147,7 @@ proc literal*[N, T, P](pattern: P, kind: N): Rule[N, T] = let parser = proc (text: T, start: int, nodes: var seq[Node[N]]): int = if start == len(text): return -1 - doAssert(len(text)>start, "Attempting to match at $#, string length is $# " % [$start, $len(text)]) + assert(len(text)>start, "Attempting to match at $#, string length is $# " % [$start, $len(text)]) when P is string or P is seq[N]: debug(debugLex, "Literal[" & $kind & "]: testing " & $pattern & " at " & $start & ": " & $text[start..start+len(pattern)-1]) if text.continuesWith(pattern, start): @@ -177,7 +177,7 @@ proc token[N, T](pattern: T, kind: N): Rule[N, T] = debug(debugLex, "Token[" & $kind & "]: testing " & pattern & " at " & $start) if start == len(text): return -1 - doAssert(len(text)>start, "Attempting to match at $#, string length is $# " % [$start, $len(text)]) + assert(len(text)>start, "Attempting to match at $#, string length is $# " % [$start, $len(text)]) let m = text.match(re(pattern), start) if m.isSome: let node = initNode(start, len(m.get.match), kind) @@ -192,7 +192,7 @@ proc chartest[N, T, S](testfunc: proc(s: S): bool, kind: N): Rule[N, T] = let parser = proc (text: T, start: int, nodes: var seq[Node[N]]): int = if start == len(text): return -1 - doAssert(len(text)>start, "Attempting to match at $#, string length is $# " % [$start, $len(text)]) + assert(len(text)>start, "Attempting to match at $#, string length is $# " % [$start, $len(text)]) if testfunc(text[start]): nodes.add(initNode(start, 1, kind)) result = 1 @@ -252,11 +252,11 @@ proc fail*[N, T](message: string, kind: N): Rule[N, T] = proc `+`*[N, T](left: Rule[N, T], right: Rule[N, T]): Rule[N, T] = let parser = proc (text: T, start: int, nodes: var seq[Node[N]]): int = var mynodes = newSeq[Node[N]]() - doAssert(not isNil(left.parser), "Left hand side parser is nil") + assert(not isNil(left.parser), "Left hand side parser is nil") let leftlength = left.parser(text, start, mynodes) if leftlength == -1: return leftlength - doAssert(not isNil(right.parser), "Right hand side parser is nil") + assert(not isNil(right.parser), "Right hand side parser is nil") let rightlength = right.parser(text, start+leftlength, mynodes) if rightlength == -1: return rightlength @@ -267,13 +267,13 @@ proc `+`*[N, T](left: Rule[N, T], right: Rule[N, T]): Rule[N, T] = proc `/`*[N, T](left: Rule[N, T], right: Rule[N, T]): Rule[N, T] = let parser = proc (text: T, start: int, nodes: var seq[Node[N]]): int = var mynodes = newSeq[Node[N]]() - doAssert(not isNil(left.parser), "Left hand side of / is not fully defined") + assert(not isNil(left.parser), "Left hand side of / is not fully defined") let leftlength = left.parser(text, start, mynodes) if leftlength != -1: nodes.add(mynodes) return leftlength mynodes = newSeq[Node[N]]() - doAssert(not isNil(right.parser), "Right hand side of / is not fully defined") + assert(not isNil(right.parser), "Right hand side of / is not fully defined") let rightlength = right.parser(text, start, mynodes) if rightlength == -1: return rightlength @@ -360,7 +360,7 @@ proc `/`*[N, T](rule: Rule[N, T]): Rule[N, T] = result = newRule[N, T](parser, rule.kind) proc `->`*(rule: Rule, production: Rule) = - doAssert(not isnil(production.parser), "Right hand side of -> is nil - has the rule been defined yet?") + assert(not isnil(production.parser), "Right hand side of -> is nil - has the rule been defined yet?") rule.parser = production.parser template grammar*[K](Kind, Text, Symbol: typedesc; default: K, code: untyped): typed {.hint[XDeclaredButNotUsed]: off.} = diff --git a/tests/generics/tpointerprocs.nim b/tests/generics/tpointerprocs.nim deleted file mode 100644 index 2bcaf15b3..000000000 --- a/tests/generics/tpointerprocs.nim +++ /dev/null @@ -1,28 +0,0 @@ -discard """ -cmd: "nim check $options --hints:off $file" -action: "reject" -nimout:''' -tpointerprocs.nim(15, 11) Error: 'foo' doesn't have a concrete type, due to unspecified generic parameters. -tpointerprocs.nim(27, 11) Error: cannot instantiate: 'foo[int]'; got 1 typeof(s) but expected 2 -tpointerprocs.nim(27, 14) Error: expression 'foo[int]' has no type (or is ambiguous) -tpointerprocs.nim(28, 11) Error: expression 'bar' has no type (or is ambiguous) -''' -""" - -block: - proc foo(x: int | float): float = result = 1.0 - let - bar = foo - baz = bar - -block: - proc foo(x: int | float): float = result = 1.0 - let - bar = foo[int] - baz = bar - -block: - proc foo(x: int | float, y: int or string): float = result = 1.0 - let - bar = foo[int] - baz = bar \ No newline at end of file diff --git a/tests/generics/tprevent_double_bind.nim b/tests/generics/tprevent_double_bind.nim index d8fc6e5d3..86e080ab6 100644 --- a/tests/generics/tprevent_double_bind.nim +++ b/tests/generics/tprevent_double_bind.nim @@ -1,5 +1,5 @@ discard """ - errormsg: "type mismatch: got " + errormsg: "type mismatch: got " line: 20 """ diff --git a/tests/generics/trecursivegenerics.nim b/tests/generics/trecursivegenerics.nim deleted file mode 100644 index 1b152b063..000000000 --- a/tests/generics/trecursivegenerics.nim +++ /dev/null @@ -1,96 +0,0 @@ -block: # Replicates #18728 - type - FlipFlop[A, B] = ref object - val: A - next: FlipFlop[B, A] - - Trinary[A, B, C] = ref object - next: Trinary[B, C, A] - - assert typeof(FlipFlop[int, string]().next) is FlipFlop[string, int] - assert typeof(FlipFlop[string, int]().next) is FlipFlop[int, string] - assert typeof(Trinary[int, float, string]().next) is Trinary[float, string, int] - assert typeof(Trinary[int, float, string]().next.next) is Trinary[string, int, float] - var a = FlipFlop[int, string](val: 100, next: FlipFlop[string, int](val: "Hello")) - assert a.val == 100 - assert a.next.val == "Hello" - -block: # 18838 - type - DoublyLinkedNodeObj[T] = object - value: T - - DoublyLinkedNode[T] = ref DoublyLinkedNodeObj[T] - - Item[T] = ref object - link: DoublyLinkedNode[Item[T]] - - Box = object - - proc newDoublyLinkedNode[T](value: T): DoublyLinkedNode[T] = - new(result) - result.value = value - - let link = newDoublyLinkedNode(Item[Box]()) - -import lists -block: - type - Box = object - Item[T] = ref object - link:DoublyLinkedNode[ Item[T] ] - - ItemSimple = ref object - link:DoublyLinkedNode[ ItemSimple ] - - let link = newDoublyLinkedNode( Item[Box]() ) - -block: #18897 - type - SkipListObj[T] = object - over: SkipList[T] - down: SkipList[T] - value: T - - SkipList[T] = ref SkipListObj[T] - - GraphObj[N, E; F: static[int]] = object - nodes: SkipList[Node[N, E]] - - Graph[N, E; F: static[int]] = ref GraphObj[N, E, F] - - Node[N, E] = ref NodeObj[N, E] - - NodeObj[N, E] = object - value: N - incoming: SkipList[Edge[N, E]] - outgoing: SkipList[Edge[N, E]] - - Edge[N, E] = ref EdgeObj[N, E] - - EdgeObj[N, E] = object - value: E - id: int - source: Node[N, E] - target: Node[N, E] - - EdgeResult[N, E] = tuple - source: Node[N, E] - edge: Edge[N, E] - target: Node[N, E] - - proc newSkipList[T](value: T): SkipList[T] = - static: echo T, " ", typeof(result.value) - result = SkipList[T](value: value) - - proc toSkipList[T](values: openArray[T] = @[]): SkipList[T] = - for item in items(values): - if result.isNil: - result = newSkipList(item) - - proc newContainer[N, E, F](graph: Graph[N, E, F]; form: typedesc): auto = - result = toSkipList[form]([]) - - var - result = Graph[int, string, 0]() - result.nodes = result.newContainer(Node[int, string]) \ No newline at end of file diff --git a/tests/generics/treentranttypes.nim b/tests/generics/treentranttypes.nim index 40ff1647b..31fa25293 100644 --- a/tests/generics/treentranttypes.nim +++ b/tests/generics/treentranttypes.nim @@ -2,13 +2,21 @@ discard """ output: ''' (10, ("test", 1.2)) 3x3 Matrix [[0.0, 2.0, 3.0], [2.0, 0.0, 5.0], [2.0, 0.0, 5.0]] + 2x3 Matrix [[0.0, 2.0, 3.0], [2.0, 0.0, 5.0]] + 2x3 Literal [[0.0, 2.0, 3.0], [2.0, 0.0, 5.0]] + 2x3 Matrix [[0.0, 0.0, 0.0], [0.0, 0.0, 0.0]] + 2x2 ArrayArray[[0.0, 0.0, 0.0], [0.0, 0.0, 0.0]] + 2x3 ArrayVector[[0.0, 0.0, 0.0], [0.0, 0.0, 0.0]] + 2x3 VectorVector [[0.0, 0.0, 0.0], [0.0, 0.0, 0.0]] + 2x3 VectorArray [[0.0, 0.0, 0.0], [0.0, 0.0, 0.0]] + @[1, 2] @[1, 2] @[1, 2]@[3, 4] diff --git a/tests/arc/trtree.nim b/tests/generics/trtree.nim similarity index 89% rename from tests/arc/trtree.nim rename to tests/generics/trtree.nim index 683403a62..4bd7d11f4 100644 --- a/tests/arc/trtree.nim +++ b/tests/generics/trtree.nim @@ -1,7 +1,7 @@ discard """ output: '''1 [2, 3, 4, 7] [0, 0]''' - targets: "c" + target: "c" joinable: false disabled: 32bit cmd: "nim c --gc:arc $file" @@ -71,24 +71,24 @@ proc newRStarTree*[M, D: Dim; RT, LT](minFill: range[30 .. 50] = 40): RStarTree[ result.p = M * 30 div 100 result.root = newLeaf[M, D, RT, LT]() -proc center(r: Box): auto =#BoxCenter[r.len, typeof(r[0].a)] = - var res: BoxCenter[r.len, typeof(r[0].a)] +proc center(r: Box): auto =#BoxCenter[r.len, type(r[0].a)] = + var result: BoxCenter[r.len, type(r[0].a)] for i in 0 .. r.high: when r[0].a is SomeInteger: - res[i] = (r[i].a + r[i].b) div 2 + result[i] = (r[i].a + r[i].b) div 2 elif r[0].a is SomeFloat: - res[i] = (r[i].a + r[i].b) / 2 + result[i] = (r[i].a + r[i].b) / 2 else: assert false - return res + return result proc distance(c1, c2: BoxCenter): auto = - var res: typeof(c1[0]) + var result: type(c1[0]) for i in 0 .. c1.high: - res += (c1[i] - c2[i]) * (c1[i] - c2[i]) - return res + result += (c1[i] - c2[i]) * (c1[i] - c2[i]) + return result proc overlap(r1, r2: Box): auto = - result = typeof(r1[0].a)(1) + result = type(r1[0].a)(1) for i in 0 .. r1.high: result *= (min(r1[i].b, r2[i].b) - max(r1[i].a, r2[i].a)) if result <= 0: return 0 @@ -104,13 +104,13 @@ proc intersect(r1, r2: Box): bool = return false return true -proc area(r: Box): auto = #typeof(r[0].a) = - result = typeof(r[0].a)(1) +proc area(r: Box): auto = #type(r[0].a) = + result = type(r[0].a)(1) for i in 0 .. r.high: result *= r[i].b - r[i].a -proc margin(r: Box): auto = #typeof(r[0].a) = - result = typeof(r[0].a)(0) +proc margin(r: Box): auto = #type(r[0].a) = + result = type(r[0].a)(0) for i in 0 .. r.high: result += r[i].b - r[i].a @@ -138,16 +138,16 @@ proc search*[M, D: Dim; RT, LT](t: RTree[M, D, RT, LT]; b: Box[D, RT]): seq[LT] # a R*TREE proc proc chooseSubtree[M, D: Dim; RT, LT](t: RTree[M, D, RT, LT]; b: Box[D, RT]; level: int): H[M, D, RT, LT] = assert level >= 0 - var it = t.root - while it.level > level: - let nn = Node[M, D, RT, LT](it) + var n = t.root + while n.level > level: + let nn = Node[M, D, RT, LT](n) var i0 = 0 # selected index - var minLoss = typeof(b[0].a).high - if it.level == 1: # childreen are leaves -- determine the minimum overlap costs - for i in 0 ..< it.numEntries: + var minLoss = type(b[0].a).high + if n.level == 1: # childreen are leaves -- determine the minimum overlap costs + for i in 0 ..< n.numEntries: let nx = union(nn.a[i].b, b) var loss = 0 - for j in 0 ..< it.numEntries: + for j in 0 ..< n.numEntries: if i == j: continue loss += (overlap(nx, nn.a[j].b) - overlap(nn.a[i].b, nn.a[j].b)) # overlap (i, j) == (j, i), so maybe cache that? var rep = loss < minLoss @@ -163,7 +163,7 @@ proc chooseSubtree[M, D: Dim; RT, LT](t: RTree[M, D, RT, LT]; b: Box[D, RT]; lev i0 = i minLoss = loss else: - for i in 0 ..< it.numEntries: + for i in 0 ..< n.numEntries: let loss = enlargement(nn.a[i].b, b) var rep = loss < minLoss if loss == minLoss: @@ -174,13 +174,28 @@ proc chooseSubtree[M, D: Dim; RT, LT](t: RTree[M, D, RT, LT]; b: Box[D, RT]; lev if rep: i0 = i minLoss = loss - it = nn.a[i0].n - return it + n = nn.a[i0].n + return n + +proc chooseLeaf[M, D: Dim; RT, LT](t: RTree[M, D, RT, LT]; b: Box[D, RT]; level: int): H[M, D, RT, LT] = + assert level >= 0 + var n = t.root + while n.level > level: + var j = -1 # selected index + var x: type(b[0].a) + let nn = Node[M, D, RT, LT](n) + for i in 0 ..< n.numEntries: + let h = enlargement(nn.a[i].b, b) + if j < 0 or h < x or (x == h and area(nn.a[i].b) < area(nn.a[j].b)): + x = h + j = i + n = nn.a[j].n + return n proc pickSeeds[M, D: Dim; RT, LT](t: RTree[M, D, RT, LT]; n: Node[M, D, RT, LT] | Leaf[M, D, RT, LT]; bx: Box[D, RT]): (int, int) = var i0, j0: int - var bi, bj: typeof(bx) - var largestWaste = typeof(bx[0].a).low + var bi, bj: type(bx) + var largestWaste = type(bx[0].a).low for i in -1 .. n.a.high: for j in 0 .. n.a.high: if unlikely(i == j): continue @@ -200,7 +215,7 @@ proc pickSeeds[M, D: Dim; RT, LT](t: RTree[M, D, RT, LT]; n: Node[M, D, RT, LT] proc pickNext[M, D: Dim; RT, LT](t: RTree[M, D, RT, LT]; n0, n1, n2: Node[M, D, RT, LT] | Leaf[M, D, RT, LT]; b1, b2: Box[D, RT]): int = let a1 = area(b1) let a2 = area(b2) - var d = typeof(a1).low + var d = type(a1).low for i in 0 ..< n0.numEntries: let d1 = area(union(b1, n0.a[i].b)) - a1 let d2 = area(union(b2, n0.a[i].b)) - a2 @@ -220,15 +235,15 @@ proc sortPlus[T](a: var openArray[T], ax: var T, cmp: proc (x, y: T): int {.clos a.sort(cmp, order) # R*TREE procs -proc rstarSplit[M, D: Dim; RT, LT](t: RStarTree[M, D, RT, LT]; n: var Node[M, D, RT, LT] | var Leaf[M, D, RT, LT]; lx: L[D, RT, LT] | N[M, D, RT, LT]): typeof(n) = - type NL = typeof(lx) - var nBest: typeof(n) +proc rstarSplit[M, D: Dim; RT, LT](t: RStarTree[M, D, RT, LT]; n: var Node[M, D, RT, LT] | var Leaf[M, D, RT, LT]; lx: L[D, RT, LT] | N[M, D, RT, LT]): type(n) = + type NL = type(lx) + var nBest: type(n) new nBest var lx = lx when n is Node[M, D, RT, LT]: lx.n.parent = n - var lxbest: typeof(lx) - var m0 = lx.b[0].a.typeof.high + var lxbest: type(lx) + var m0 = lx.b[0].a.high for d2 in 0 ..< 2 * D: let d = d2 div 2 if d2 mod 2 == 0: @@ -251,8 +266,8 @@ proc rstarSplit[M, D: Dim; RT, LT](t: RStarTree[M, D, RT, LT]; n: var Node[M, D, lxbest = lx m0 = m var i0 = -1 - var o0 = lx.b[0].a.typeof.high - for i in t.m - 1 .. n.a.typeof.high - t.m + 1: + var o0 = lx.b[0].a.high + for i in t.m - 1 .. n.a.high - t.m + 1: var b1 = lxbest.b for j in 0 ..< i: b1 = union(nbest.a[j].b, b1) @@ -277,8 +292,8 @@ proc rstarSplit[M, D: Dim; RT, LT](t: RStarTree[M, D, RT, LT]; n: var Node[M, D, for i in 0 ..< result.numEntries: result.a[i].n.parent = result -proc quadraticSplit[M, D: Dim; RT, LT](t: RTree[M, D, RT, LT]; n: var Node[M, D, RT, LT] | var Leaf[M, D, RT, LT]; lx: L[D, RT, LT] | N[M, D, RT, LT]): typeof(n) = - var n1, n2: typeof(n) +proc quadraticSplit[M, D: Dim; RT, LT](t: RTree[M, D, RT, LT]; n: var Node[M, D, RT, LT] | var Leaf[M, D, RT, LT]; lx: L[D, RT, LT] | N[M, D, RT, LT]): type(n) = + var n1, n2: type(n) var s1, s2: int new n1 new n2 @@ -341,7 +356,7 @@ proc quadraticSplit[M, D: Dim; RT, LT](t: RTree[M, D, RT, LT]; n: var Node[M, D, n[] = n1[] return n2 -proc overflowTreatment[M, D: Dim; RT, LT](t: RStarTree[M, D, RT, LT]; n: var Node[M, D, RT, LT] | var Leaf[M, D, RT, LT]; lx: L[D, RT, LT] | N[M, D, RT, LT]): typeof(n) +proc overflowTreatment[M, D: Dim; RT, LT](t: RStarTree[M, D, RT, LT]; n: var Node[M, D, RT, LT] | var Leaf[M, D, RT, LT]; lx: L[D, RT, LT] | N[M, D, RT, LT]): type(n) proc adjustTree[M, D: Dim; RT, LT](t: RTree[M, D, RT, LT]; l, ll: H[M, D, RT, LT]; hb: Box[D, RT]) = var n = l @@ -361,7 +376,7 @@ proc adjustTree[M, D: Dim; RT, LT](t: RTree[M, D, RT, LT]; l, ll: H[M, D, RT, LT var i = 0 while p.a[i].n != n: inc(i) - var b: typeof(p.a[0].b) + var b: type(p.a[0].b) if n of Leaf[M, D, RT, LT]: when false:#if likely(nn.isNil): # no performance gain b = union(p.a[i].b, Leaf[M, D, RT, LT](n).a[n.numEntries - 1].b) @@ -397,7 +412,12 @@ proc adjustTree[M, D: Dim; RT, LT](t: RTree[M, D, RT, LT]; l, ll: H[M, D, RT, LT nn = nil else: let h: N[M, D, RT, LT] = (b, nn) - nn = quadraticSplit(t, p, h) + if t of RStarTree[M, D, RT, LT]: + nn = overflowTreatment(RStarTree[M, D, RT, LT](t), p, h) + elif t of RTree[M, D, RT, LT]: + nn = quadraticSplit(RTree[M, D, RT, LT](t), p, h) + else: + assert false assert n == H[M, D, RT, LT](p) assert n != nil assert t.root != nil @@ -427,9 +447,9 @@ proc insert*[M, D: Dim; RT, LT](t: RTree[M, D, RT, LT]; leaf: N[M, D, RT, LT] | proc rsinsert[M, D: Dim; RT, LT](t: RStarTree[M, D, RT, LT]; leaf: N[M, D, RT, LT] | L[D, RT, LT]; level: int) proc reInsert[M, D: Dim; RT, LT](t: RStarTree[M, D, RT, LT]; n: var Node[M, D, RT, LT] | var Leaf[M, D, RT, LT]; lx: L[D, RT, LT] | N[M, D, RT, LT]) = - type NL = typeof(lx) + type NL = type(lx) var lx = lx - var buf: typeof(n.a) + var buf: type(n.a) let p = Node[M, D, RT, LT](n.parent) var i = 0 while p.a[i].n != n: @@ -449,7 +469,7 @@ proc reInsert[M, D: Dim; RT, LT](t: RStarTree[M, D, RT, LT]; n: var Node[M, D, R for i in M - t.p + 1 .. n.a.high: rsinsert(t, buf[i], n.level) -proc overflowTreatment[M, D: Dim; RT, LT](t: RStarTree[M, D, RT, LT]; n: var Node[M, D, RT, LT] | var Leaf[M, D, RT, LT]; lx: L[D, RT, LT] | N[M, D, RT, LT]): typeof(n) = +proc overflowTreatment[M, D: Dim; RT, LT](t: RStarTree[M, D, RT, LT]; n: var Node[M, D, RT, LT] | var Leaf[M, D, RT, LT]; lx: L[D, RT, LT] | N[M, D, RT, LT]): type(n) = if n.level != t.root.level and t.firstOverflow[n.level]: t.firstOverflow[n.level] = false reInsert(t, n, lx) @@ -547,16 +567,18 @@ proc condenseTree[M, D: Dim; RT, LT](t: RTree[M, D, RT, LT]; leaf: Leaf[M, D, RT rsinsert(RStarTree[M, D, RT, LT](t), Node[M, D, RT, LT](n).a[i], n.level) else: assert false - else: + elif t of RTree[M, D, RT, LT]: for n in q: if n of Leaf[M, D, RT, LT]: for i in 0 ..< n.numEntries: - insert(t, Leaf[M, D, RT, LT](n).a[i]) + insert(RTree[M, D, RT, LT](t), Leaf[M, D, RT, LT](n).a[i]) elif n of Node[M, D, RT, LT]: for i in 0 ..< n.numEntries: - insert(t, Node[M, D, RT, LT](n).a[i], n.level) + insert(RTree[M, D, RT, LT](t), Node[M, D, RT, LT](n).a[i], n.level) else: assert false + else: + assert false proc delete*[M, D: Dim; RT, LT](t: RTree[M, D, RT, LT]; leaf: L[D, RT, LT]): bool {.discardable.} = let l = findLeaf(t, leaf) @@ -637,4 +659,6 @@ proc test(n: int) = assert r.len == r2.len assert r.sorted(system.cmp) == r2.sorted(system.cmp) -test(500) +test(1500) + +# 651 lines diff --git a/tests/generics/tstatic_constrained.nim b/tests/generics/tstatic_constrained.nim deleted file mode 100644 index 3c9201548..000000000 --- a/tests/generics/tstatic_constrained.nim +++ /dev/null @@ -1,79 +0,0 @@ -discard """ - cmd: "nim check --hints:off --warnings:off $file" - action: "reject" - nimout:''' -tstatic_constrained.nim(44, 22) Error: cannot instantiate MyOtherType [type declared in tstatic_constrained.nim(30, 5)] -got: -but expected: -tstatic_constrained.nim(44, 22) Error: cannot instantiate MyOtherType [type declared in tstatic_constrained.nim(30, 5)] -got: -but expected: -tstatic_constrained.nim(44, 31) Error: object constructor needs an object type [proxy] -tstatic_constrained.nim(44, 31) Error: expression '' has no type (or is ambiguous) -tstatic_constrained.nim(45, 22) Error: cannot instantiate MyOtherType [type declared in tstatic_constrained.nim(30, 5)] -got: -but expected: -tstatic_constrained.nim(45, 22) Error: cannot instantiate MyOtherType [type declared in tstatic_constrained.nim(30, 5)] -got: -but expected: -tstatic_constrained.nim(45, 34) Error: object constructor needs an object type [proxy] -tstatic_constrained.nim(45, 34) Error: expression '' has no type (or is ambiguous) -tstatic_constrained.nim(77, 14) Error: cannot instantiate MyType [type declared in tstatic_constrained.nim(71, 5)] -got: -but expected: -''' -""" -block: - type - MyType[T; X: static T] = object - data: T - MyOtherType[T: float or string, Y: static T] = object - - func f[T,X](a: MyType[T,X]): MyType[T,X] = - when T is string: - MyType[T,X](data: a.data & X) - else: - MyType[T,X](data: a.data + X) - - discard MyType[int, 2](data: 1) - discard MyType[string, "Helelello"](data: "Hmmm") - discard MyType[int, 2](data: 1).f() - discard MyType[string, "Helelello"](data: "Hmmm").f() - discard MyOtherType[float, 1.3]() - discard MyOtherType[string, "Hello"]() - discard MyOtherType[int, 10]() - discard MyOtherType[byte, 10u8]() - -block: - type - Moduloable = concept m, type M - m mod m is M - Addable = concept a, type A - a + a is A - Modulo[T: Moduloable; Mod: static T] = distinct T - ModuloAdd[T: Moduloable or Addable; Mod: static T] = distinct T - ModuAddable = Addable or Moduloable - ModdAddClass[T: ModuAddable; Mod: static T] = distinct T - - proc toMod[T](val: T, modVal: static T): Modulo[T, modVal] = - mixin `mod` - Modulo[T, modVal](val mod modVal) - var - a = 3231.toMod(10) - b = 5483.toMod(10) - discard ModuloAdd[int, 3](0) - discard ModdAddClass[int, 3](0) - -block: - type - MyConstraint = int or string - MyOtherConstraint[T] = object - MyType[T: MyConstraint; Y: static T] = object - MyOtherType[T: MyOtherConstraint; Y: static T] = object - - var - a: MyType[int, 10] - b: MyType[string, "hello"] - c: MyType[float, 10d] - d: MyOtherType[MyOtherConstraint[float],MyOtherConstraint[float]()] - e: MyOtherType[MyOtherConstraint[int], MyOtherConstraint[int]()] \ No newline at end of file diff --git a/tests/generics/tthread_generic.nim b/tests/generics/tthread_generic.nim index 300da56a6..2af5a7615 100644 --- a/tests/generics/tthread_generic.nim +++ b/tests/generics/tthread_generic.nim @@ -1,5 +1,5 @@ discard """ - matrix: "--mm:refc; --mm:orc" + cmd: "nim $target --hints:on --threads:on $options $file" action: compile """ diff --git a/tests/gensym/tgensymgeneric.nim b/tests/gensym/tgensymgeneric.nim index 6e1df4842..c17a0715f 100644 --- a/tests/gensym/tgensymgeneric.nim +++ b/tests/gensym/tgensymgeneric.nim @@ -21,7 +21,7 @@ template genImpl() = gensymed.x = "abc" else: gensymed.x = 123 - result = move gensymed + shallowCopy(result, gensymed) proc gen[T](x: T): T = genImpl() diff --git a/tests/global/t3505.nim b/tests/global/t3505.nim deleted file mode 100644 index 437a02ae6..000000000 --- a/tests/global/t3505.nim +++ /dev/null @@ -1,41 +0,0 @@ -discard """ -cmd: "nim check $options --hints:off $file" -action: "reject" -nimout: ''' -t3505.nim(22, 22) Error: cannot assign local to global variable -t3505.nim(31, 28) Error: cannot assign local to global variable -t3505.nim(39, 29) Error: cannot assign local to global variable - - - - -''' -""" - - - - - - -proc foo = - let a = 0 - var b {.global.} = a -foo() - -# issue #5132 -proc initX(it: float): int = 8 -proc initX2(it: int): int = it - -proc main() = - var f: float - var x {.global.} = initX2(initX(f)) - -main() - -# issue #20866 -proc foo2() = - iterator bar() {.closure.} = - discard - var g {.global.} = rawProc(bar) - -foo2() \ No newline at end of file diff --git a/tests/ic/config.nims b/tests/ic/config.nims deleted file mode 100644 index a522efb0d..000000000 --- a/tests/ic/config.nims +++ /dev/null @@ -1,3 +0,0 @@ -when defined(windows): - --tlsEmulation:off ---mm:refc diff --git a/tests/ic/mbaseobj.nim b/tests/ic/mbaseobj.nim deleted file mode 100644 index 0f4e4a90d..000000000 --- a/tests/ic/mbaseobj.nim +++ /dev/null @@ -1,7 +0,0 @@ - -type - Base* = ref object of RootObj - s*: string - -method m*(b: Base) {.base.} = - echo "Base ", b.s diff --git a/tests/ic/mcompiletime_counter.nim b/tests/ic/mcompiletime_counter.nim deleted file mode 100644 index 6fc7b3f2a..000000000 --- a/tests/ic/mcompiletime_counter.nim +++ /dev/null @@ -1,15 +0,0 @@ - -import std/macros -import std/macrocache - -const myCounter = CacheCounter"myCounter" - -proc getUniqueId*(): int {.compileTime.} = - inc myCounter - result = myCounter.value - -static: - myCounter.inc(3) - assert myCounter.value == 3 - - diff --git a/tests/ic/mdefconverter.nim b/tests/ic/mdefconverter.nim deleted file mode 100644 index d0a23f801..000000000 --- a/tests/ic/mdefconverter.nim +++ /dev/null @@ -1,2 +0,0 @@ - -converter toBool*(x: int): bool = x != 0 diff --git a/tests/ic/mimports.nim b/tests/ic/mimports.nim deleted file mode 100644 index 50773e001..000000000 --- a/tests/ic/mimports.nim +++ /dev/null @@ -1,9 +0,0 @@ -from mimportsb {.all.} import fnb1, hfnb3 - -proc fn1*(): int = 1 -proc fn2*(): int = 2 -proc hfn3(): int = 3 -proc hfn4(): int = 4 -proc hfn5(): int = 5 - -export mimportsb.fnb2, hfnb3 diff --git a/tests/ic/mimportsb.nim b/tests/ic/mimportsb.nim deleted file mode 100644 index 3cae925c5..000000000 --- a/tests/ic/mimportsb.nim +++ /dev/null @@ -1,4 +0,0 @@ -proc fnb1*(): int = 1 -proc fnb2*(): int = 2 -proc hfnb3(): int = 3 -proc hfnb4(): int = 4 diff --git a/tests/ic/tcompiletime_counter.nim b/tests/ic/tcompiletime_counter.nim deleted file mode 100644 index 695a6ec27..000000000 --- a/tests/ic/tcompiletime_counter.nim +++ /dev/null @@ -1,24 +0,0 @@ -discard """ - output: '''id 4''' -""" - -import mcompiletime_counter - -const intId = getUniqueId() - -echo "id ", intId - -#!EDIT!# - -discard """ - output: '''id 4 5''' -""" - -import mcompiletime_counter - -const - intId = getUniqueId() - floatId = getUniqueId() - -echo "id ", intId, " ", floatId - diff --git a/tests/ic/tconverter.nim b/tests/ic/tconverter.nim deleted file mode 100644 index aecdf4b48..000000000 --- a/tests/ic/tconverter.nim +++ /dev/null @@ -1,18 +0,0 @@ -discard """ - output: "yes" -""" - -import mdefconverter - -echo "yes" - -#!EDIT!# - -discard """ - output: "converted int to bool" -""" - -import mdefconverter - -if 4: - echo "converted int to bool" diff --git a/tests/ic/tgenerics.nim b/tests/ic/tgenerics.nim index 138799e85..bc5c05f4f 100644 --- a/tests/ic/tgenerics.nim +++ b/tests/ic/tgenerics.nim @@ -1,5 +1,6 @@ discard """ output: "bar" + disabled: "true" """ import tables diff --git a/tests/ic/timports.nim b/tests/ic/timports.nim deleted file mode 100644 index 518a689f5..000000000 --- a/tests/ic/timports.nim +++ /dev/null @@ -1,29 +0,0 @@ -import mimports -doAssert fn1() == 1 -doAssert not declared(hfn3) - -#!EDIT!# - -import mimports {.all.} -doAssert fn1() == 1 -doAssert declared(hfn3) -doAssert hfn3() == 3 -doAssert mimports.hfn4() == 4 - -# reexports -doAssert not declared(fnb1) -doAssert not declared(hfnb4) -doAssert fnb2() == 2 -doAssert hfnb3() == 3 - -#!EDIT!# - -from mimports {.all.} import hfn3 -doAssert not declared(fn1) -from mimports {.all.} as bar import fn1 -doAssert fn1() == 1 -doAssert hfn3() == 3 -doAssert not declared(hfn4) -doAssert declared(mimports.hfn4) -doAssert mimports.hfn4() == 4 -doAssert bar.hfn4() == 4 diff --git a/tests/ic/tmethods.nim b/tests/ic/tmethods.nim deleted file mode 100644 index 251f26889..000000000 --- a/tests/ic/tmethods.nim +++ /dev/null @@ -1,28 +0,0 @@ -discard """ - output: '''Base abc''' -""" - -import mbaseobj - -var c = Base(s: "abc") -m c - -#!EDIT!# - -discard """ - output: '''Base abc -Inherited abc''' -""" - -import mbaseobj - -type - Inherited = ref object of Base - -method m(i: Inherited) = - procCall m(Base i) - echo "Inherited ", i.s - -var c = Inherited(s: "abc") -m c - diff --git a/tests/ic/tstdlib_import_changed.nim b/tests/ic/tstdlib_import_changed.nim deleted file mode 100644 index da69a53b5..000000000 --- a/tests/ic/tstdlib_import_changed.nim +++ /dev/null @@ -1,15 +0,0 @@ -discard """ - output: '''yes''' -""" - -echo "yes" - -#!EDIT!# - -discard """ - output: '''yes2''' -""" - -import std / [monotimes] -#discard getMonoTime() -echo "yes2" diff --git a/tests/implicit/timplicit.nim b/tests/implicit/timplicit.nim new file mode 100644 index 000000000..bb701249c --- /dev/null +++ b/tests/implicit/timplicit.nim @@ -0,0 +1,49 @@ +discard """ + output: ''' +1 +2 +3 +4 +2 +88 +timplicit done +''' +""" + + +for x in [1, 2, 3, 4]: + echo x + + +type + TValue* {.pure, final.} = object of RootObj + a: int + PValue = ref TValue + PPValue = ptr PValue + + +var x: PValue +new x +var sp: PPValue = addr x + +sp.a = 2 +if sp.a == 2: echo 2 # with sp[].a the error is gone + +# Test the new auto-deref a little + +{.experimental.} + +proc p(x: var int; y: int) = x += y + +block: + var x: ref int + new(x) + + x.p(44) + + var indirect = p + x.indirect(44) + + echo x[] + + echo "timplicit done" diff --git a/tests/import/buzz/m21496.nim b/tests/import/buzz/m21496.nim deleted file mode 100644 index 7c87e2c04..000000000 --- a/tests/import/buzz/m21496.nim +++ /dev/null @@ -1 +0,0 @@ -proc fb* = echo "buzz!" \ No newline at end of file diff --git a/tests/import/fizz/m21496.nim b/tests/import/fizz/m21496.nim deleted file mode 100644 index 834c11eae..000000000 --- a/tests/import/fizz/m21496.nim +++ /dev/null @@ -1 +0,0 @@ -proc fb* = echo "fizz!" \ No newline at end of file diff --git a/tests/import/t21496.nim b/tests/import/t21496.nim deleted file mode 100644 index 568f2ac51..000000000 --- a/tests/import/t21496.nim +++ /dev/null @@ -1,9 +0,0 @@ -discard """ - errormsg: "redefinition of 'm21496'; previous declaration here: t21496.nim(5, 12)" -""" - -import fizz/m21496, buzz/m21496 - -# bug #21496 - -m21496.fb() diff --git a/tests/importalls/m1.nim b/tests/importalls/m1.nim deleted file mode 100644 index b6ccbf5da..000000000 --- a/tests/importalls/m1.nim +++ /dev/null @@ -1,70 +0,0 @@ -import ./m2 -import ./m3 {.all.} as m3 -from ./m3 as m3Bis import nil - -doAssert m3h2 == 2 -export m3h2 - -export m3Bis.m3p1 - -const foo0* = 2 -const foo1 = bar1 - -const foo1Aux = 2 -export foo1Aux - -doAssert not declared(bar2) -doAssert not compiles(bar2) - -var foo2 = 2 -let foo3 = 2 - -type Foo4 = enum - kg1, kg2 - -type Foo4b {.pure.} = enum - foo4b1, foo4b2 - -type Foo5 = object - z1: string - z2: Foo4 - z3: int - z4*: int - -proc `z3`*(a: Foo5): auto = - a.z3 * 10 - -proc foo6(): auto = 2 -proc foo6b*(): auto = 2 -template foo7: untyped = 2 -macro foo8(): untyped = discard -template foo9(a: int) = discard - -block: - template foo10: untyped = 2 - type Foo11 = enum - kg1b, kg2b - proc foo12(): auto = 2 - -proc initFoo5*(z3: int): Foo5 = Foo5(z3: z3) - -func foo13(): auto = 2 -iterator foo14a(): int = discard -iterator foo14b*(): int = discard -iterator foo14c(): int {.closure.} = discard -iterator foo14d(): int {.inline.} = discard - -# fwd declare -proc foo15(): int -proc foo15(): int = 2 - -proc foo16*(): int -proc foo16(): int = 2 - -proc foo17*(): int -proc foo17*(): int = 2 - -# other -type A1 = distinct int -type A2 = distinct int -converter foo18(x: A1): A2 = discard diff --git a/tests/importalls/m2.nim b/tests/importalls/m2.nim deleted file mode 100644 index 186650f68..000000000 --- a/tests/importalls/m2.nim +++ /dev/null @@ -1,3 +0,0 @@ -const bar1* = 2 -const bar2 = 2 -const bar3 = 3 diff --git a/tests/importalls/m3.nim b/tests/importalls/m3.nim deleted file mode 100644 index caeae2a01..000000000 --- a/tests/importalls/m3.nim +++ /dev/null @@ -1,5 +0,0 @@ -# xxx use below naming convention in other test files: p: public, h: hidden -const m3p1* = 2 -const m3h2 = 2 -const m3h3 = 3 -const m3h4 = 4 diff --git a/tests/importalls/m4.nim b/tests/importalls/m4.nim deleted file mode 100644 index b682b766a..000000000 --- a/tests/importalls/m4.nim +++ /dev/null @@ -1,10 +0,0 @@ -{.warning[UnusedImport]: off.} # xxx bug: this shouldn't be needed since we have `export m3` -import ./m3 {.all.} -import ./m3 as m3b -export m3b -export m3h3 -export m3.m3h4 - -import ./m2 {.all.} as m2b -export m2b except bar3 - diff --git a/tests/importalls/mt0.nim b/tests/importalls/mt0.nim deleted file mode 100644 index 154d30ef9..000000000 --- a/tests/importalls/mt0.nim +++ /dev/null @@ -1,9 +0,0 @@ -import ./m1 as m -doAssert compiles(foo0) -doAssert not compiles(foo1) -doAssert foo6b() == 2 -doAssert m3h2 == 2 - -var f = initFoo5(z3=3) -doAssert f.z3 == 30 -doAssert z3(f) == 30 diff --git a/tests/importalls/mt1.nim b/tests/importalls/mt1.nim deleted file mode 100644 index b7983945c..000000000 --- a/tests/importalls/mt1.nim +++ /dev/null @@ -1,23 +0,0 @@ -import ./m1 {.all.} as m -doAssert foo1 == 2 -doAssert m.foo1 == 2 - -doAssert m.m3h2 == 2 -doAssert m3h2 == 2 -doAssert m.foo1Aux == 2 -doAssert m.m3p1 == 2 - -## field access -import std/importutils -privateAccess(Foo5) -var x = Foo5(z1: "foo", z2: m.kg1) -doAssert x.z1 == "foo" - -var f0: Foo5 -f0.z3 = 3 -doAssert f0.z3 == 3 -var f = initFoo5(z3=3) -doAssert f.z3 == 3 -doAssert z3(f) == 30 -doAssert m.z3(f) == 30 -doAssert not compiles(mt1.`z3`(f)) # z3 is an imported symbol diff --git a/tests/importalls/mt2.nim b/tests/importalls/mt2.nim deleted file mode 100644 index 52edbb69e..000000000 --- a/tests/importalls/mt2.nim +++ /dev/null @@ -1,104 +0,0 @@ -from ./m1 {.all.} as r1 import foo1 -from ./m1 {.all.} as r2 import foo7 - -block: # different symbol kinds - doAssert foo1 == 2 - doAssert r1.foo1 == 2 - doAssert r1.foo2 == 2 - doAssert compiles(foo1) - doAssert compiles(r1.foo2) - doAssert not compiles(foo2) - doAssert not compiles(m3h2) - doAssert r1.foo3 == 2 - - block: # enum - var a: r1.Foo4 - let a1 = r1.kg1 - doAssert a1 == r1.Foo4.kg1 - type A = r1.Foo4 - doAssert a1 == A.kg1 - doAssert not compiles(kg1) - doAssert compiles(A.kg1) - var witness = false - for ai in r1.Foo4: - doAssert ai == a - doAssert ai == a1 - witness = true - break - doAssert witness - - block: # {.pure.} enum - var a: r1.Foo4b - doAssert not compiles(r1.foo4b1) # because pure - doAssert not compiles(foo4b1) - let a1 = r1.Foo4b.foo4b1 - doAssert a1 == a - type A = r1.Foo4b - doAssert a1 == A.foo4b1 - var witness = false - for ai in A: - doAssert ai == a - doAssert ai == a1 - witness = true - break - doAssert witness - - block: # object - doAssert compiles(r1.Foo5) - var a: r1.Foo5 - doAssert compiles(a.z4) - doAssert not compiles(a.z3) - - block: # remaining symbol kinds - doAssert r1.foo6() == 2 - doAssert r1.foo6b() == 2 - doAssert foo7() == 2 - doAssert r2.foo6b() == 2 - - r1.foo8() - r1.foo9(1) - doAssert r1.foo13() == 2 - for a in r1.foo14a(): discard - for a in r1.foo14b(): discard - for a in r1.foo14c(): discard - for a in r1.foo14d(): discard - doAssert r1.foo15() == 2 - doAssert r1.foo16() == 2 - doAssert r1.foo17() == 2 - doAssert compiles(r1.foo18) - doAssert declared(r1.foo18) - - block: # declarations at block scope should not be visible - doAssert declared(foo7) - doAssert declared(r1.foo6) - doAssert not declared(foo10) - doAssert not declared(foo6) - doAssert not declared(r1.Foo11) - doAssert not declared(r1.kg1b) - doAssert not declared(r1.foo12) - doAssert not compiles(r1.foo12()) - -## field access -import std/importutils -privateAccess(r1.Foo5) -var x = r1.Foo5(z1: "foo", z2: r1.kg1) -doAssert x.z1 == "foo" - -var f0: r1.Foo5 -f0.z3 = 3 -doAssert f0.z3 == 3 -var f = r1.initFoo5(z3=3) -doAssert f.z3 == 3 -doAssert r1.z3(f) == 30 - -import ./m1 as r3 -doAssert not declared(foo2) -doAssert not declared(r3.foo2) - -from ./m1 {.all.} as r4 import nil -doAssert not declared(foo2) -doAssert declared(r4.foo2) - -from ./m1 {.all.} import nil -doAssert not declared(foo2) -doAssert declared(m1.foo2) diff --git a/tests/importalls/mt3.nim b/tests/importalls/mt3.nim deleted file mode 100644 index 2bd7fd79d..000000000 --- a/tests/importalls/mt3.nim +++ /dev/null @@ -1,12 +0,0 @@ -import ./m1 {.all.} - # D20201209T194412:here keep this as is, without `as`, so that mt8.nim test keeps - # checking that the original module symbol for `m1` isn't modified and that - # only the alias in `createModuleAlias` is affected. -doAssert declared(m1.foo1) -doAssert foo1 == 2 - - -doAssert m1.foo1 == 2 - -doAssert not compiles(mt3.foo0) # foo0 is an imported symbol -doAssert not compiles(mt3.foo1) # ditto diff --git a/tests/importalls/mt4.nim b/tests/importalls/mt4.nim deleted file mode 100644 index cd7d32aad..000000000 --- a/tests/importalls/mt4.nim +++ /dev/null @@ -1,4 +0,0 @@ -import ./m1 {.all.} except foo1 -doAssert foo2 == 2 -doAssert declared(foo2) -doAssert not compiles(foo1) diff --git a/tests/importalls/mt4b.nim b/tests/importalls/mt4b.nim deleted file mode 100644 index 4578bc54c..000000000 --- a/tests/importalls/mt4b.nim +++ /dev/null @@ -1,3 +0,0 @@ -from ./m1 {.all.} as m2 import nil -doAssert not compiles(foo1) -doAssert m2.foo1 == 2 diff --git a/tests/importalls/mt5.nim b/tests/importalls/mt5.nim deleted file mode 100644 index 5c5785af6..000000000 --- a/tests/importalls/mt5.nim +++ /dev/null @@ -1,9 +0,0 @@ -import ./m1 {.all.} as m2 except foo1 -doAssert foo2 == 2 -doAssert not compiles(foo1) -doAssert m2.foo1 == 2 -doAssert compiles(m2.foo1) - -from system {.all.} as s import ThisIsSystem -doAssert ThisIsSystem -doAssert s.ThisIsSystem diff --git a/tests/importalls/mt6.nim b/tests/importalls/mt6.nim deleted file mode 100644 index ac6f542b6..000000000 --- a/tests/importalls/mt6.nim +++ /dev/null @@ -1,13 +0,0 @@ -import ./m1 {.all.} as m2 -doAssert compiles(foo1) -doAssert compiles(m2.foo1) -doAssert declared(foo1) -doAssert declared(m2.foo0) # public: works fine - -doAssert m2.foo1 == 2 -doAssert declared(m2.foo1) -doAssert not declared(m2.nonexistent) - -# also tests the quoted `""` import -import "."/"m1" {.all.} as m1b -doAssert compiles(m1b.foo1) diff --git a/tests/importalls/mt7.nim b/tests/importalls/mt7.nim deleted file mode 100644 index 45a664610..000000000 --- a/tests/importalls/mt7.nim +++ /dev/null @@ -1,14 +0,0 @@ -include ./m1 -doAssert compiles(foo1) -doAssert compiles(mt7.foo1) -doAssert declared(foo1) -doAssert declared(mt7.foo1) -doAssert declared(mt7.foo0) - -var f0: Foo5 -f0.z3 = 3 -doAssert f0.z3 == 3 -var f = initFoo5(z3=3) -doAssert f.z3 == 3 -doAssert mt7.z3(f) == 30 -doAssert z3(f) == 30 diff --git a/tests/importalls/mt8.nim b/tests/importalls/mt8.nim deleted file mode 100644 index f484e7b01..000000000 --- a/tests/importalls/mt8.nim +++ /dev/null @@ -1,23 +0,0 @@ -#[ -test multiple imports -]# - -{.warning[UnusedImport]: off.} -import ./m1, m2 {.all.}, ./m3 {.all.} - # make sure this keeps using `import ./m1` without as. - -# m1 is regularly imported -doAssert declared(m1.foo0) -doAssert declared(foo0) - -doAssert not declared(m1.foo1) - # if we didn't call `createModuleAlias` even for `import f1 {.all.}`, - # this would fail, see D20201209T194412. - -# m2 -doAssert declared(m2.bar2) -doAssert declared(bar2) - -# m3 -doAssert declared(m3.m3h2) -doAssert declared(m3h2) diff --git a/tests/importalls/mt9.nim b/tests/importalls/mt9.nim deleted file mode 100644 index 42d48ecbd..000000000 --- a/tests/importalls/mt9.nim +++ /dev/null @@ -1,12 +0,0 @@ -# tests re-export of a module with import {.all.} - -import ./m4 - -doAssert m3p1 == 2 -doAssert not declared(m3h2) -doAssert m3h3 == 3 -doAssert m3h4 == 4 - -doAssert bar1 == 2 -doAssert bar2 == 2 -doAssert not declared(bar3) diff --git a/tests/importalls/tmain2.nim b/tests/importalls/tmain2.nim deleted file mode 100644 index 596f0f135..000000000 --- a/tests/importalls/tmain2.nim +++ /dev/null @@ -1,7 +0,0 @@ -discard """ -joinable: false # for clarity, but not necessary -""" - -{.warning[UnusedImport]: off.} -# only import `mt*.nim` here; these depend on `m*.nim` -import "."/[mt0,mt1,mt2,mt3,mt4,mt4b,mt5,mt6,mt7,mt8,mt9] diff --git a/tests/init/tinitchecks_v2.nim b/tests/init/tinitchecks_v2.nim deleted file mode 100644 index 4a8cda028..000000000 --- a/tests/init/tinitchecks_v2.nim +++ /dev/null @@ -1,59 +0,0 @@ -discard """ -cmd: "nim check $file" -action: "compile" -""" - -{.experimental: "strictDefs".} - -proc myopen(f: out File; s: string): bool = - f = default(File) - result = false - -proc main = - var f: File - if myopen(f, "aarg"): - f.close - -proc invalid = - var s: seq[string] - s.add "abc" #[tt.Warning - ^ use explicit initialization of 's' for clarity [Uninit] ]# - -proc valid = - var s: seq[string] = @[] - s.add "abc" # valid! - -main() -invalid() -valid() - -proc branchy(cond: bool) = - var s: seq[string] - if cond: - s = @["y"] - else: - s = @[] - s.add "abc" # valid! - -branchy true - -proc p(x: out int; y: out string; cond: bool) = #[tt.Warning - ^ Cannot prove that 'y' is initialized. This will become a compile time error in the future. [ProveInit] ]# - x = 4 - if cond: - y = "abc" - # error: not every path initializes 'y' - -var gl: int -var gs: string -p gl, gs, false - -proc canRaise(x: int): int = - result = x - raise newException(ValueError, "wrong") - -proc currentlyValid(x: out int; y: out string; cond: bool) = - x = canRaise(45) - y = "abc" # <-- error: not every path initializes 'y' - -currentlyValid gl, gs, false diff --git a/tests/init/tlet.nim b/tests/init/tlet.nim deleted file mode 100644 index e32bedb18..000000000 --- a/tests/init/tlet.nim +++ /dev/null @@ -1,55 +0,0 @@ -{.experimental: "strictDefs".} - -proc bar(x: out string) = - x = "abc" - -template moe = # bug #21043 - try: - discard - except ValueError as e: - echo(e.msg) - -template moe0 {.dirty.} = # bug #21043 - try: - discard - except ValueError as e: - echo(e.msg) - -proc foo() = - block: - let x: string - if true: - x = "abc" - else: - x = "def" - doAssert x == "abc" - block: - let y: string - bar(y) - doAssert y == "abc" - block: - let x: string - if true: - x = "abc" - discard "abc" - else: - x = "def" - discard "def" - doAssert x == "abc" - block: # - let x {.used.} : int - block: # - let x: float - x = 1.234 - doAssert x == 1.234 - - block: - try: - discard - except ValueError as e: - echo(e.msg) - moe() - moe0() - -static: foo() -foo() diff --git a/tests/init/tlet_uninit2.nim b/tests/init/tlet_uninit2.nim deleted file mode 100644 index 174aa28f7..000000000 --- a/tests/init/tlet_uninit2.nim +++ /dev/null @@ -1,5 +0,0 @@ -discard """ - errormsg: "'let' symbol requires an initialization" -""" - -let x: int \ No newline at end of file diff --git a/tests/init/tlet_uninit3.nim b/tests/init/tlet_uninit3.nim deleted file mode 100644 index cb786f8c8..000000000 --- a/tests/init/tlet_uninit3.nim +++ /dev/null @@ -1,24 +0,0 @@ -discard """ - cmd: "nim check $file" - action: "reject" - nimout: ''' -tlet_uninit3.nim(13, 5) Error: 'let' symbol requires an initialization -tlet_uninit3.nim(19, 5) Error: 'x' cannot be assigned to -tlet_uninit3.nim(23, 11) Error: 'let' symbol requires an initialization -''' -""" - -{.experimental: "strictDefs".} - -let global {.used.}: int - -proc foo() = - block: - let x: int - x = 13 - x = 14 - - block: - let x: int - doAssert x == 0 -foo() diff --git a/tests/init/tlet_uninit4.nim b/tests/init/tlet_uninit4.nim deleted file mode 100644 index c57d15ff8..000000000 --- a/tests/init/tlet_uninit4.nim +++ /dev/null @@ -1,12 +0,0 @@ -discard """ - errormsg: "type mismatch: got " -""" - -{.experimental: "strictDefs".} - -proc foo(x: var string) = - echo x - -proc bar() = - let x: string - foo(x) diff --git a/tests/init/toutparam_subtype.nim b/tests/init/toutparam_subtype.nim deleted file mode 100644 index 3597f1459..000000000 --- a/tests/init/toutparam_subtype.nim +++ /dev/null @@ -1,24 +0,0 @@ -discard """ -cmd: "nim check $file" -action: "compile" -errormsg: "type mismatch: got " -line: 21 -""" - -{.experimental: "strictDefs".} - -type - Superclass[T] = object of RootObj - a: T - Subclass[T] = object of Superclass[T] - s: string - -proc init[T](x: out Superclass[T]) = - x = Superclass(a: 8) - -proc subtypeCheck = - var v: Subclass[int] - init(v) - echo v.s # the 's' field was never initialized! - -subtypeCheck() diff --git a/tests/init/tuninit1.nim b/tests/init/tuninit1.nim index ac3007e8d..67c0c4d8b 100644 --- a/tests/init/tuninit1.nim +++ b/tests/init/tuninit1.nim @@ -1,10 +1,11 @@ discard """ - nimout: "tuninit1.nim(34, 11) Warning: use explicit initialization of 'y' for clarity [Uninit]" + nimout: "Warning: 'y' might not have been initialized [Uninit]" + line:34 action: compile """ import strutils -{.experimental: "strictDefs".} + {.warning[Uninit]:on.} proc p = diff --git a/tests/isolate/tisolate.nim b/tests/isolate/tisolate.nim deleted file mode 100644 index a0e71e321..000000000 --- a/tests/isolate/tisolate.nim +++ /dev/null @@ -1,41 +0,0 @@ -discard """ - errormsg: "expression cannot be isolated: select(a, b)" - line: 39 -""" - -import std / isolation - -import json, streams - -proc myParseJson(s: Stream; filename: string): JsonNode = - {.cast(noSideEffect).}: - result = parseJson(s, filename) - - -proc f(): seq[int] = - @[1, 2, 3] - -type - Node = ref object - x: string - -proc g(): Node = nil - -proc select(a, b: Node): Node = - a - -proc main = - discard isolate f() - - - discard isolate g() - - discard isolate select(Node(x: "a"), nil) - discard isolate select(Node(x: "a"), Node(x: "b")) - - discard isolate myParseJson(newFileStream("my.json"), "my.json") - - var a, b: Node - discard isolate select(a, b) - -main() diff --git a/tests/isolate/tisolate2.nim b/tests/isolate/tisolate2.nim deleted file mode 100644 index 9bf92d82e..000000000 --- a/tests/isolate/tisolate2.nim +++ /dev/null @@ -1,22 +0,0 @@ -discard """ - errormsg: "expression cannot be isolated: a_to_b(a)" - line: 22 -""" - -# bug #19013 -import std/isolation - -type Z = ref object - i: int - -type A = object - z: Z - -type B = object - z: Z - -func a_to_b(a: A): B = - result = B(z: a.z) - -let a = A(z: Z(i: 3)) -let b = isolate(a_to_b(a)) diff --git a/tests/iter/t1550.nim b/tests/iter/t1550.nim deleted file mode 100644 index 8ad96f0da..000000000 --- a/tests/iter/t1550.nim +++ /dev/null @@ -1,20 +0,0 @@ -type - A[T] = iterator(x: T): T {.gcsafe, closure.} - -iterator aimp[T](x: T): T {.gcsafe, closure.} = - var total = 0 - while (total < 100): - yield total - total += x - -iterator bimp(y: A[int], z:int): int {.gcsafe, closure.} = - for i in y(z): - yield i - -for x in aimp[int](3): - discard x - -var y = aimp[int] -var z = bimp -for x in z(y, 1): - discard x \ No newline at end of file diff --git a/tests/iter/t16076.nim b/tests/iter/t16076.nim deleted file mode 100644 index 2eb409068..000000000 --- a/tests/iter/t16076.nim +++ /dev/null @@ -1,45 +0,0 @@ -discard """ - targets: "c js" -""" - -proc main() = - block: # bug #17485 - type - O = ref object - i: int - - iterator t(o: O): int = - if o != nil: - yield o.i - yield 0 - - proc m = - var data = "" - for i in t(nil): - data.addInt i - - doAssert data == "0" - - m() - - - block: # bug #16076 - type - R = ref object - z: int - - var data = "" - - iterator foo(x: int; y: R = nil): int {.inline.} = - if y == nil: - yield x - else: - yield y.z - - for b in foo(10): - data.addInt b - - doAssert data == "10" - -static: main() -main() diff --git a/tests/iter/t21306.nim b/tests/iter/t21306.nim deleted file mode 100644 index 43fea9c80..000000000 --- a/tests/iter/t21306.nim +++ /dev/null @@ -1,114 +0,0 @@ -# bug #21306 -type - FutureState {.pure.} = enum - Pending, Finished, Cancelled, Failed - - FutureBase = ref object of RootObj - state: FutureState - error: ref CatchableError - id: uint - - Future[T] = ref object of FutureBase - closure: iterator(f: Future[T]): FutureBase {.raises: [Defect, CatchableError, Exception], gcsafe.} - value: T - -template setupFutureBase() = - new(result) - result.state = FutureState.Pending - -proc newFutureImpl[T](): Future[T] = - setupFutureBase() - -template newFuture[T](fromProc: static[string] = ""): Future[T] = - newFutureImpl[T]() - -proc internalRead[T](fut: Future[T]): T = - when T isnot void: - return fut.value - -template await[T](f: Future[T]): untyped = - when declared(chronosInternalRetFuture): - when not declaredInScope(chronosInternalTmpFuture): - var chronosInternalTmpFuture {.inject.}: FutureBase = f - else: - chronosInternalTmpFuture = f - - yield chronosInternalTmpFuture - - when T isnot void: - cast[type(f)](chronosInternalTmpFuture).internalRead() - -type - VerifierError {.pure.} = enum - Invalid - MissingParent - UnviableFork - Duplicate - ProcessingCallback = proc() {.gcsafe, raises: [Defect].} - BlockVerifier = - proc(signedBlock: int): - Future[VerifierError] {.gcsafe, raises: [Defect].} - - SyncQueueKind {.pure.} = enum - Forward, Backward - - SyncRequest[T] = object - kind: SyncQueueKind - index: uint64 - slot: uint64 - count: uint64 - item: T - - SyncResult[T] = object - request: SyncRequest[T] - data: seq[ref int] - - SyncQueue[T] = ref object - kind: SyncQueueKind - readyQueue: seq[SyncResult[T]] - blockVerifier: BlockVerifier - -iterator blocks[T](sq: SyncQueue[T], - sr: SyncResult[T]): ref int = - case sq.kind - of SyncQueueKind.Forward: - for i in countup(0, len(sr.data) - 1): - yield sr.data[i] - of SyncQueueKind.Backward: - for i in countdown(len(sr.data) - 1, 0): - yield sr.data[i] - -proc push[T](sq: SyncQueue[T]; sr: SyncRequest[T]; data: seq[ref int]; - processingCb: ProcessingCallback = nil): Future[void] {. - stackTrace: off, gcsafe.} = - iterator push_436208182(chronosInternalRetFuture: Future[void]): FutureBase {. - closure, gcsafe, raises: [Defect, CatchableError, Exception].} = - block: - template result(): auto {.used.} = - {.fatal: "You should not reference the `result` variable inside" & - " a void async proc".} - - let item = default(SyncResult[T]) - for blk in sq.blocks(item): - let res = await sq.blockVerifier(blk[]) - - var resultFuture = newFuture[void]("push") - resultFuture.closure = push_436208182 - return resultFuture - -type - SomeTPeer = ref object - score: int - -proc getSlice(): seq[ref int] = - discard - -template smokeTest(kkind: SyncQueueKind, start, finish: uint64, - chunkSize: uint64) = - var queue: SyncQueue[SomeTPeer] - var request: SyncRequest[SomeTPeer] - discard queue.push(request, getSlice()) - -for k in {SyncQueueKind.Forward}: - for item in [(uint64(1181), uint64(1399), 41'u64)]: - smokeTest(k, item[0], item[1], item[2]) \ No newline at end of file diff --git a/tests/iter/t2771.nim b/tests/iter/t2771.nim deleted file mode 100644 index 49befb0a9..000000000 --- a/tests/iter/t2771.nim +++ /dev/null @@ -1,21 +0,0 @@ -template t1(i: int): int= - i+1 -template t2(i: int): int= - i+1 - -doAssert t1(10).t2() == 12 - - -template it1(i: int): iterator(): int = - iterator result(): int {.closure, gensym.} = - yield i+1 - result - -template it2(iter: iterator(): int): iterator(): int = - iterator result(): int {.closure, gensym.} = - yield iter()+1 - result - -let x2 = it1(10).it2() - -doAssert x2() == 12 diff --git a/tests/iter/tarrayiter.nim b/tests/iter/tarrayiter.nim deleted file mode 100644 index eb7ba591a..000000000 --- a/tests/iter/tarrayiter.nim +++ /dev/null @@ -1,14 +0,0 @@ -block: - iterator `[]`(a: int, r: int): int = - for q in 0 .. r: - yield a - - for val in 10[2]: discard - - type Custom = distinct string - - iterator `[]`(a: Custom, r: int): char = - for q in 0 .. r: - yield a.string[q] - - for val in Custom("test")[2]: discard \ No newline at end of file diff --git a/tests/iter/tclosureiters.nim b/tests/iter/tclosureiters.nim index 85611373c..345a4867a 100644 --- a/tests/iter/tclosureiters.nim +++ b/tests/iter/tclosureiters.nim @@ -19,18 +19,7 @@ discard """ 0 1 2 -70 -0 -(1, 1) -(1, 2) -(1, 3) -(2, 1) -(2, 2) -(2, 3) -(3, 1) -(3, 2) -(3, 3) -''' +70''' """ when true: @@ -107,7 +96,7 @@ proc unused = iterator lineIter2*(filename: string): string {.closure.} = var f = open(filename, bufSize=8000) defer: close(f) # <-- commenting defer "solves" the problem - var res = newStringOfCap(80) + var res = TaintedString(newStringOfCap(80)) while f.readLine(res): yield res proc unusedB = @@ -150,23 +139,3 @@ iterator filesIt(path: string): auto {.closure.} = let prefix = path.splitPath[1] for f in files: yield prefix / f - -# bug #13815 -var love = iterator: int {.closure.} = - yield cast[type( - block: - var a = 0 - yield a - a)](0) - -for i in love(): - echo i - -# bug #18474 -iterator pairs(): (int, int) {.closure.} = - for i in 1..3: - for j in 1..3: - yield (i, j) - -for pair in pairs(): - echo pair diff --git a/tests/iter/titer.nim b/tests/iter/titer.nim index 3a2450ae3..22be1bad5 100644 --- a/tests/iter/titer.nim +++ b/tests/iter/titer.nim @@ -55,60 +55,3 @@ const for i in 0..len(stringArray)-1: echo(stringArray[i]) -# bug #15360 - -type Rule[T] = (int, T) - -var t: seq[Rule[int]] -for (c, t) in t: - discard - - - -import std/sugar - -# bug #14165 -iterator log_nodups_hamming(): int {.inline.} = - let lb3 = 1 - let lb4 = 123 - proc mul3(): int = lb3 + lb4 - yield mul3() - -for h in log_nodups_hamming(): - break -for h in log_nodups_hamming(): - break -for h in log_nodups_hamming(): - break - -# bug #18536 -iterator envPairs*(): int = - var foo: seq[int] - proc fun() = - foo = @[] - fun() - yield 3 - -proc main() = - for a in envPairs(): - discard - for a in envPairs(): - discard -static: main() -main() - -# bug #6269 -iterator makeFn(outer_val: int): proc(a: int): int = - for i in 0..1: - yield proc(a:int): int = - return a + i.int - -let v1 = 42 - -let res = collect: - for fn1 in makeFn(v1): - let v2 = fn1(v1) - for fn2 in makeFn(v2): - fn2(v2) - -doAssert res == @[42, 43, 43, 44] diff --git a/tests/iter/titer11.nim b/tests/iter/titer11.nim index 2b39c74f7..c4c7d4a16 100644 --- a/tests/iter/titer11.nim +++ b/tests/iter/titer11.nim @@ -26,14 +26,3 @@ var output = represent(s) for item in output(): echo item - - -#------------------------------------------------------------------------------ -# Issue #12747 - -type - ABC = ref object - arr: array[0x40000, pointer] -let a = ABC() -for a in a.arr: - assert a == nil \ No newline at end of file diff --git a/tests/iter/titer13.nim b/tests/iter/titer13.nim index 086c40ca4..0d4a399c5 100644 --- a/tests/iter/titer13.nim +++ b/tests/iter/titer13.nim @@ -72,7 +72,7 @@ block: echo a block t5859: - proc flatIterator[T](s: openArray[T]): auto {.noSideEffect.}= + proc flatIterator[T](s: openarray[T]): auto {.noSideEffect.}= result = iterator(): auto = when (T is not seq|array): for item in s: diff --git a/tests/iter/titer2.nim b/tests/iter/titer2.nim index 975cc786c..f60aed73a 100644 --- a/tests/iter/titer2.nim +++ b/tests/iter/titer2.nim @@ -17,7 +17,7 @@ type TSlotEnum = enum seEmpty, seFilled, seDeleted TKeyValuePair[A, B] = tuple[slot: TSlotEnum, key: A, val: B] TKeyValuePairSeq[A, B] = seq[TKeyValuePair[A, B]] - TTable*[A, B] {.final.} = object + TTable* {.final.}[A, B] = object data: TKeyValuePairSeq[A, B] counter: int diff --git a/tests/iter/titer3.nim b/tests/iter/titer3.nim index defd56c98..9dcfd7be5 100644 --- a/tests/iter/titer3.nim +++ b/tests/iter/titer3.nim @@ -26,7 +26,7 @@ var x = [[1, 2, 3], [4, 5, 6]] for y in iter1(x[0]): write(stdout, $y) writeLine(stdout, "") -# ensure closure and inline iterators have the same behaviour regarding +# ensure closure and inline iterators have the same behaviour wrt # parameter passing iterator clo(a: int): int {.closure.} = diff --git a/tests/iter/titer_issues.nim b/tests/iter/titer_issues.nim index adba8a8e3..a7830dfab 100644 --- a/tests/iter/titer_issues.nim +++ b/tests/iter/titer_issues.nim @@ -18,30 +18,6 @@ end 1 2 7 -9002 -9004 -9006 -9008 -9010 -9012 -9014 -9016 -9018 -@[1, 2] -@[1, 2, 3] -1 -nested finally -outer finally -nested finally -outer finally -nested finally -outer finally -nested finally -outer finally -In defer -trying -exception caught -finally block ''' """ @@ -148,7 +124,7 @@ block t3837_chained: block t3221_complex: - iterator permutations[T](ys: openArray[T]): seq[T] = + iterator permutations[T](ys: openarray[T]): seq[T] = var d = 1 c = newSeq[int](ys.len) @@ -206,7 +182,7 @@ block t3499_keepstate: break # bug #3499 last snippet fixed - # bug #705 last snippet fixed + # bug 705 last snippet fixed @@ -237,158 +213,3 @@ block t2023_objiter: var o = init() echo(o.iter()) - - -block: - # bug #13739 - iterator myIter(arg: openArray[int]): int = - var tmp = 0 - let len = arg.len - while tmp < len: - yield arg[tmp] * 2 - inc tmp - - proc someProc() = - var data = [4501,4502,4503,4504,4505,4506,4507,4508,4509] - # StmtListExpr should not get special treatment. - for x in myIter((discard;data)): - echo x - - someProc() - -block: - # bug #12576 - iterator ff(sq: varargs[seq[int]]): int = - for x in sq: - echo x - - for x in ff(@[1, 2], @[1, 2, 3]): - echo x - - -# bug #19575 - -iterator bb() {.closure.} = - while true: - try: discard - except: break - finally: break - -var a = bb - -iterator cc() {.closure.} = - while true: - try: discard - except: - if true: - break - finally: - if true: - break - -var a2 = cc - -# bug #16876 -block: - iterator a(num: int): int {.closure.} = - if num == 1: - yield num - else: - for i in a(num - 1): - yield i - - for i in a(5): - echo i - -block: - # bug #19911 (return in nested try) - - # try yield -> try - iterator p1: int {.closure.} = - try: - yield 0 - try: - return - finally: - echo "nested finally" - echo "shouldn't run" - finally: - echo "outer finally" - echo "shouldn't run" - - for _ in p1(): - discard - - # try -> try yield - iterator p2: int {.closure.} = - try: - try: - yield 0 - return - finally: - echo "nested finally" - echo "shouldn't run" - finally: - echo "outer finally" - echo "shouldn't run" - - for _ in p2(): - discard - - # try yield -> try yield - iterator p3: int {.closure.} = - try: - yield 0 - try: - yield 0 - return - finally: - echo "nested finally" - echo "shouldn't run" - finally: - echo "outer finally" - echo "shouldn't run" - - for _ in p3(): - discard - - # try -> try - iterator p4: int {.closure.} = - try: - try: - return - finally: - echo "nested finally" - echo "shouldn't run" - finally: - echo "outer finally" - echo "shouldn't run" - - for _ in p4(): - discard - -# bug #18824 -iterator poc_iterator: int {.closure.} = - block bug18824: - try: - break bug18824 - finally: - echo "In defer" - -for _ in poc_iterator(): - discard - -# bug #20624 -iterator tryFinally() {.closure.} = - block route: - try: - echo "trying" - raise - except: - echo "exception caught" - break route - finally: - echo "finally block" - -var x = tryFinally -x() diff --git a/tests/iter/titervaropenarray.nim b/tests/iter/titervaropenarray.nim index ad1192bd8..4469fdcf5 100644 --- a/tests/iter/titervaropenarray.nim +++ b/tests/iter/titervaropenarray.nim @@ -1,6 +1,6 @@ discard """ output: "123" - targets: "c" + targets: "C" """ # Try to break the transformation pass: iterator iterAndZero(a: var openArray[int]): int = diff --git a/tests/iter/tmoditer.nim b/tests/iter/tmoditer.nim index 99e5b642d..b92a416fb 100644 --- a/tests/iter/tmoditer.nim +++ b/tests/iter/tmoditer.nim @@ -43,7 +43,7 @@ proc `=copy`(dst: var NonCopyable, src: NonCopyable) {.error.} proc `=sink`(dst: var NonCopyable, src: NonCopyable) = dst.x = src.x -iterator lentItems[T](a: openArray[T]): lent T = +iterator lentItems[T](a: openarray[T]): lent T = for i in 0..a.high: yield a[i] diff --git a/tests/iter/tpermutations.nim b/tests/iter/tpermutations.nim index 30a66460f..c5067ba31 100644 --- a/tests/iter/tpermutations.nim +++ b/tests/iter/tpermutations.nim @@ -12,7 +12,7 @@ perm: 6778800.0 det: 0.0 import sequtils, sugar -iterator permutations*[T](ys: openArray[T]): tuple[perm: seq[T], sign: int] = +iterator permutations*[T](ys: openarray[T]): tuple[perm: seq[T], sign: int] = var d = 1 c = newSeq[int](ys.len) diff --git a/tests/iter/tshallowcopy_closures.nim b/tests/iter/tshallowcopy_closures.nim index 06b04a788..279e7d950 100644 --- a/tests/iter/tshallowcopy_closures.nim +++ b/tests/iter/tshallowcopy_closures.nim @@ -1,5 +1,4 @@ discard """ - matrix: "--mm:refc" ccodecheck: "!@('{' \\s* 'NI HEX3Astate;' \\s* '}')" output: ''' a1 10 diff --git a/tests/iter/tyieldintry.nim b/tests/iter/tyieldintry.nim index 47ba6efa6..62c16c741 100644 --- a/tests/iter/tyieldintry.nim +++ b/tests/iter/tyieldintry.nim @@ -1,16 +1,15 @@ discard """ - matrix: "; --experimental:strictdefs" - targets: "c cpp" +targets: "c cpp" +output: "ok" """ - var closureIterResult = newSeq[int]() proc checkpoint(arg: int) = closureIterResult.add(arg) type - TestError = object of CatchableError - AnotherError = object of CatchableError + TestException = object of Exception + AnotherException = object of Exception proc testClosureIterAux(it: iterator(): int, exceptionExpected: bool, expectedResults: varargs[int]) = closureIterResult.setLen(0) @@ -20,7 +19,7 @@ proc testClosureIterAux(it: iterator(): int, exceptionExpected: bool, expectedRe try: for i in it(): closureIterResult.add(i) - except TestError: + except TestException: exceptionCaught = true if closureIterResult != @expectedResults or exceptionCaught != exceptionExpected: @@ -38,8 +37,8 @@ proc test(it: iterator(): int, expectedResults: varargs[int]) = proc testExc(it: iterator(): int, expectedResults: varargs[int]) = testClosureIterAux(it, true, expectedResults) -proc raiseTestError() = - raise newException(TestError, "Test exception!") +proc raiseException() = + raise newException(TestException, "Test exception!") block: iterator it(): int {.closure.} = @@ -57,8 +56,8 @@ block: yield 0 try: checkpoint(1) - raiseTestError() - except TestError: + raiseException() + except TestException: checkpoint(2) yield 3 checkpoint(4) @@ -88,7 +87,7 @@ block: yield 0 try: yield 1 - raiseTestError() + raiseException() yield 2 finally: checkpoint(3) @@ -102,8 +101,8 @@ block: iterator it(): int {.closure.} = try: try: - raiseTestError() - except AnotherError: + raiseException() + except AnotherException: yield 123 finally: checkpoint(3) @@ -116,8 +115,8 @@ block: iterator it(): int {.closure.} = try: yield 1 - raiseTestError() - except AnotherError: + raiseException() + except AnotherException: checkpoint(123) finally: checkpoint(2) @@ -133,12 +132,12 @@ block: yield 1 try: yield 2 - raiseTestError() - except AnotherError: + raiseException() + except AnotherException: yield 123 finally: yield 3 - except AnotherError: + except AnotherException: yield 124 finally: yield 4 @@ -169,10 +168,10 @@ block: try: try: yield 0 - raiseTestError() + raiseException() finally: checkpoint(1) - except TestError: + except TestException: yield 2 return finally: @@ -187,10 +186,10 @@ block: try: try: yield 0 - raiseTestError() + raiseException() finally: return # Return in finally should stop exception propagation - except AnotherError: + except AnotherException: yield 2 return finally: @@ -227,9 +226,9 @@ block: var foo = 123 let i = try: yield 0 - raiseTestError() + raiseException() 1 - except TestError as e: + except TestException as e: assert(e.msg == "Test exception!") case foo of 1: @@ -261,9 +260,9 @@ block: template tryexcept: int = try: yield 1 - raiseTestError() + raiseException() 123 - except TestError: + except TestException: yield 2 checkpoint(3) 4 @@ -322,11 +321,11 @@ block: for i in 0 .. 1: try: yield 1 - raiseTestError() - except TestError as e: + raiseException() + except TestException as e: doAssert(e.msg == "Test exception!") yield 2 - except AnotherError: + except AnotherException: yield 123 except: yield 1234 @@ -482,25 +481,5 @@ block: # nnkChckRange test(it, 1, 2, 3) -block: #17849 - yield in case subject - template yieldInCase: int = - yield 2 - 3 +echo "ok" - iterator it(): int {.closure.} = - yield 1 - case yieldInCase() - of 1: checkpoint(11) - of 3: checkpoint(13) - else: checkpoint(14) - yield 5 - - test(it, 1, 2, 13, 5) - -block: # void iterator - iterator it() {.closure.} = - try: - yield - except: - discard - var a = it diff --git a/tests/js/readme.md b/tests/js/readme.md deleted file mode 100644 index 7fcc722fa..000000000 --- a/tests/js/readme.md +++ /dev/null @@ -1,5 +0,0 @@ -## notes -Prefer moving tests to a non-js directory so that they get tested across all backends automatically. -Ideally, tests/js should be reserved to code that only makes sense in js. - -Note also that tests for a js specific module (e.g.: `std/jsbigints`) belong to `tests/stdlib`, (e.g.: `tests/stdlib/tjsbigints.nim`) diff --git a/tests/js/t11166.nim b/tests/js/t11166.nim index e98ccda10..8dd77925c 100644 --- a/tests/js/t11166.nim +++ b/tests/js/t11166.nim @@ -1,20 +1,4 @@ -discard """ - output: ''' -test1 -test2 -''' -""" - import jsffi -type - C = object - props: int - -var c: C - when compiles(c.props): - echo "test1" - -when not compiles(d.props): - echo "test2" + echo "test" diff --git a/tests/js/t11354.nim b/tests/js/t11354.nim deleted file mode 100644 index 8dee90de0..000000000 --- a/tests/js/t11354.nim +++ /dev/null @@ -1,20 +0,0 @@ -discard """ - output: ''' -0 -@[@[0, 1]] -''' -""" - -type - TrackySeq[T] = object - s: seq[T] - pos: int - -proc foobar(ls: var TrackySeq[seq[int]], i: int): var seq[int] = - echo ls.pos # removing this, or making the return explicit works - ls.s[i] - -var foo: TrackySeq[seq[int]] -foo.s.add(@[0]) -foo.foobar(0).add(1) -echo foo.s \ No newline at end of file diff --git a/tests/js/t11697.nim b/tests/js/t11697.nim deleted file mode 100644 index 967752586..000000000 --- a/tests/js/t11697.nim +++ /dev/null @@ -1,5 +0,0 @@ -import tables - -var xs: Table[int, Table[int, int]] - -doAssertRaises(KeyError): reset xs[0] diff --git a/tests/js/t12303.nim b/tests/js/t12303.nim deleted file mode 100644 index 270d82ced..000000000 --- a/tests/js/t12303.nim +++ /dev/null @@ -1,16 +0,0 @@ -discard """ - output: "{ b: 2 }" -""" - -import jsconsole, jsffi - -type - A = ref object - b: B - - B = object - b: int - -var a = cast[A](js{}) -a.b = B(b: 2) -console.log a.b diff --git a/tests/js/t12672.nim b/tests/js/t12672.nim deleted file mode 100644 index a658fbcbe..000000000 --- a/tests/js/t12672.nim +++ /dev/null @@ -1,12 +0,0 @@ -discard """ - output: "" -""" - -proc foo = - var x: seq[seq[int]] - for row in x.mitems: - let i = 1 - echo row - inc row[i-1] - -foo() diff --git a/tests/js/t14153.nim b/tests/js/t14153.nim deleted file mode 100644 index 350bbd83b..000000000 --- a/tests/js/t14153.nim +++ /dev/null @@ -1,22 +0,0 @@ -discard """ - output: ''' -index 5 not in 0 .. 2 -index 5 not in 0 .. 2 -''' -""" - -var x = @[1, 2, 3] - -try: - echo x[5] -except IndexError: - echo getCurrentExceptionMsg() -except: - doAssert false - -try: - x[5] = 8 -except IndexError: - echo getCurrentExceptionMsg() -except: - doAssert false diff --git a/tests/js/t14570.nim b/tests/js/t14570.nim deleted file mode 100644 index 100c2651d..000000000 --- a/tests/js/t14570.nim +++ /dev/null @@ -1,11 +0,0 @@ -discard """ - output: ''' -18 -''' -""" - -type A = range[15 .. 30] - -let a: A = 18 - -echo ord(a) diff --git a/tests/js/t17177.nim b/tests/js/t17177.nim deleted file mode 100644 index fc362cec1..000000000 --- a/tests/js/t17177.nim +++ /dev/null @@ -1,10 +0,0 @@ -import std/asyncjs - -proc fn1(n: int): Future[int] {.async.} = return n -proc main2() = - proc fn2(n: int): Future[int] {.async.} = return n -proc main3(a: auto) = - proc fn3(n: int): Future[int] {.async.} = return n -proc main4() {.async.} = - proc fn4(n: int): Future[int] {.async.} = return n - discard diff --git a/tests/js/t20233.nim b/tests/js/t20233.nim deleted file mode 100644 index 401d14122..000000000 --- a/tests/js/t20233.nim +++ /dev/null @@ -1,7 +0,0 @@ -discard """ - output: "yes" -""" -case 1.0 -of 1.0..2.0, 4.0: echo "yes" -of 3.0: discard -else: echo "no" \ No newline at end of file diff --git a/tests/js/t20235.nim b/tests/js/t20235.nim deleted file mode 100644 index 3a69c2bd6..000000000 --- a/tests/js/t20235.nim +++ /dev/null @@ -1,11 +0,0 @@ -discard """ - action: "run" - output: "0 4" -""" - -proc main = - var s = "" - s.setLen(4) - echo s[0].ord, " ", s.len - -main() diff --git a/tests/js/t21209.nim b/tests/js/t21209.nim deleted file mode 100644 index 4de34f035..000000000 --- a/tests/js/t21209.nim +++ /dev/null @@ -1,6 +0,0 @@ -discard """ - action: "compile" - cmd: "nim check --warning[UnusedImport]:off $file" -""" - -import std/times diff --git a/tests/js/t21209.nims b/tests/js/t21209.nims deleted file mode 100644 index 318e28f97..000000000 --- a/tests/js/t21209.nims +++ /dev/null @@ -1 +0,0 @@ ---b:js \ No newline at end of file diff --git a/tests/js/t21247.nim b/tests/js/t21247.nim deleted file mode 100644 index 5b38787b3..000000000 --- a/tests/js/t21247.nim +++ /dev/null @@ -1,15 +0,0 @@ -import std/typetraits - -type - QueryParams* = distinct seq[(string, string)] - -converter toBase*(params: var QueryParams): var seq[(string, string)] = - params.distinctBase - -proc foo(): QueryParams = - # Issue was that the implicit converter call didn't say that it took the - # address of the parameter it was converting. This led to the parameter not being - # passed as a fat pointer which toBase expected - result.add(("hello", "world")) - -assert foo().distinctBase() == @[("hello", "world")] diff --git a/tests/js/t21439.nim b/tests/js/t21439.nim deleted file mode 100644 index 972356cd0..000000000 --- a/tests/js/t21439.nim +++ /dev/null @@ -1,14 +0,0 @@ -discard """ - action: "compile" -""" - -proc test(a: openArray[string]): proc = - result = proc = - for i in a: - discard i - - -const a = ["t1", "t2"] - -discard test(a) - diff --git a/tests/js/t7109.nim b/tests/js/t7109.nim deleted file mode 100644 index 0d071dbbf..000000000 --- a/tests/js/t7109.nim +++ /dev/null @@ -1,8 +0,0 @@ -discard """ - errormsg: "Closure iterators are not supported by JS backend!" -""" - -iterator iter*(): int {.closure.} = - yield 3 - -var x = iter diff --git a/tests/js/t7127.nim b/tests/js/t7127.nim deleted file mode 100644 index 364aedd4a..000000000 --- a/tests/js/t7127.nim +++ /dev/null @@ -1,2 +0,0 @@ -doAssertRaises(DivByZeroDefect): discard 1 mod 0 -doAssertRaises(DivByZeroDefect): discard 1 div 0 \ No newline at end of file diff --git a/tests/js/t7224.nim b/tests/js/t7224.nim index 77fef10a7..be9d0ae9c 100644 --- a/tests/js/t7224.nim +++ b/tests/js/t7224.nim @@ -1,11 +1,10 @@ discard """ cmd: "nim $target $options --stackTrace:on --lineTrace:on $file" outputsub: ''' -t7224.nim(25) at module t7224 -t7224.nim(22) at t7224.aaa -t7224.nim(19) at t7224.bbb -t7224.nim(16) at t7224.ccc -t7224.nim(13) at t7224.ddd +t7224.aaa, line: 21 +t7224.bbb, line: 18 +t7224.ccc, line: 15 +t7224.ddd, line: 12 ''' """ diff --git a/tests/js/t8231.nim b/tests/js/t8231.nim deleted file mode 100644 index b0625a621..000000000 --- a/tests/js/t8231.nim +++ /dev/null @@ -1,3 +0,0 @@ -import strutils - -doAssert formatSize(2462056448, '.', bpIEC, false) == "2.293GiB" \ No newline at end of file diff --git a/tests/js/t8821.nim b/tests/js/t8821.nim deleted file mode 100644 index 38c88efa8..000000000 --- a/tests/js/t8821.nim +++ /dev/null @@ -1,9 +0,0 @@ - -proc isInt32(i: int): bool = - case i - of 1 .. 70000: - return true - else: - return false - -doAssert isInt32(1) == true \ No newline at end of file diff --git a/tests/js/t9410.nim b/tests/js/t9410.nim index 042520dc5..78c329a24 100644 --- a/tests/js/t9410.nim +++ b/tests/js/t9410.nim @@ -447,10 +447,10 @@ template tests = doAssert seqOfSeqs == @[@[10, 2], @[30, 4]] when false: - block: # openArray + block: # openarray # Error: internal error: genAddr: nkStmtListExpr var calls = 0 - proc getvarint(x: var openArray[int]): var int = + proc getvarint(x: var openarray[int]): var int = calls += 1 if true: x[1] diff --git a/tests/js/taddr.nim b/tests/js/taddr.nim new file mode 100644 index 000000000..d8ff4c11b --- /dev/null +++ b/tests/js/taddr.nim @@ -0,0 +1,79 @@ +discard """ + action: run +""" + +type T = object + x: int + s: string + +var obj: T +var fieldAddr = addr(obj.x) +var objAddr = addr(obj) + +# Integer tests +var field = fieldAddr[] +doAssert field == 0 + +var objDeref = objAddr[] +doAssert objDeref.x == 0 + +# Change value +obj.x = 42 + +doAssert field == 0 +doAssert objDeref.x == 0 + +field = fieldAddr[] +objDeref = objAddr[] + +doAssert field == 42 +doAssert objDeref.x == 42 + +# String tests +obj.s = "lorem ipsum dolor sit amet" +var indexAddr = addr(obj.s[2]) + +doAssert indexAddr[] == 'r' + +indexAddr[] = 'd' + +doAssert indexAddr[] == 'd' + +doAssert obj.s == "lodem ipsum dolor sit amet" + +# Bug #2148 +var x: array[2, int] +var y = addr x[1] + +y[] = 12 +doAssert(x[1] == 12) + +type + Foo = object + bar: int + +var foo: array[2, Foo] +var z = addr foo[1] + +z[].bar = 12345 +doAssert(foo[1].bar == 12345) + +var t : tuple[a, b: int] +var pt = addr t[1] +pt[] = 123 +doAssert(t.b == 123) + +#block: # Test "untyped" pointer. +proc testPtr(p: pointer, a: int) = + doAssert(a == 5) + (cast[ptr int](p))[] = 124 +var i = 123 +testPtr(addr i, 5) +doAssert(i == 124) + +var someGlobal = 5 +proc getSomeGlobalPtr(): ptr int = addr someGlobal +let someGlobalPtr = getSomeGlobalPtr() +doAssert(someGlobalPtr[] == 5) +someGlobalPtr[] = 10 +doAssert(someGlobal == 10) diff --git a/tests/js/tarrayboundscheck.nim b/tests/js/tarrayboundscheck.nim index d8bf8de97..f0eaeb89d 100644 --- a/tests/js/tarrayboundscheck.nim +++ b/tests/js/tarrayboundscheck.nim @@ -39,12 +39,6 @@ proc test_arrayboundscheck() = echo "month out of bounds: ", idx except: echo "idx out of bounds: ", i - - # #13966 - var negativeIndexed: array[-2..2, int] = [0, 1, 2, 3, 4] - negativeIndexed[-1] = 2 - negativeIndexed[1] = 2 - doAssert negativeIndexed == [0, 2, 2, 2, 4] test_arrayboundscheck() {.pop.} \ No newline at end of file diff --git a/tests/js/tasync.nim b/tests/js/tasync.nim new file mode 100644 index 000000000..318237651 --- /dev/null +++ b/tests/js/tasync.nim @@ -0,0 +1,33 @@ +discard """ + output: ''' +x +e +''' +""" + +import asyncjs + +# demonstrate forward definition +# for js +proc y(e: int): Future[string] {.async.} + +proc e: int {.discardable.} = + echo "e" + return 2 + +proc x(e: int): Future[void] {.async.} = + var s = await y(e) + if e > 2: + return + echo s + e() + +proc y(e: int): Future[string] {.async.} = + if e > 0: + return await y(0) + else: + return "x" + + +discard x(2) + diff --git a/tests/js/tasyncjs_pragma.nim b/tests/js/tasync_pragma.nim similarity index 93% rename from tests/js/tasyncjs_pragma.nim rename to tests/js/tasync_pragma.nim index 2b6f32e92..916769fad 100644 --- a/tests/js/tasyncjs_pragma.nim +++ b/tests/js/tasync_pragma.nim @@ -5,8 +5,6 @@ t ''' """ -# xxx merge into tasyncjs.nim - import asyncjs, macros macro f*(a: untyped): untyped = diff --git a/tests/js/tasyncjs.nim b/tests/js/tasyncjs.nim deleted file mode 100644 index 3de143643..000000000 --- a/tests/js/tasyncjs.nim +++ /dev/null @@ -1,102 +0,0 @@ -discard """ - output: ''' -x -e -done -''' -""" - -#[ -xxx move this to tests/stdlib/tasyncjs.nim -]# - -import std/asyncjs - -block: - # demonstrate forward definition for js - proc y(e: int): Future[string] {.async.} - - proc e: int {.discardable.} = - echo "e" - return 2 - - proc x(e: int): Future[void] {.async.} = - var s = await y(e) - if e > 2: - return - echo s - e() - - proc y(e: int): Future[string] {.async.} = - if e > 0: - return await y(0) - else: - return "x" - - discard x(2) - -import std/sugar -from std/strutils import contains - -var witness: seq[string] - -proc fn(n: int): Future[int] {.async.} = - if n >= 7: - raise newException(ValueError, "foobar: " & $n) - if n > 0: - var ret = 1 + await fn(n-1) - witness.add $(n, ret) - return ret - else: - return 10 - -proc asyncFact(n: int): Future[int] {.async.} = - if n > 0: result = n * await asyncFact(n-1) - else: result = 1 - -proc asyncIdentity(n: int): Future[int] {.async.} = - if n > 0: result = 1 + await asyncIdentity(n-1) - else: result = 0 - -proc main() {.async.} = - block: # then - let x = await fn(4) - .then((a: int) => a.float) - .then((a: float) => $a) - doAssert x == "14.0" - doAssert witness == @["(1, 11)", "(2, 12)", "(3, 13)", "(4, 14)"] - - doAssert (await fn(2)) == 12 - - let x2 = await fn(4).then((a: int) => (discard)).then(() => 13) - doAssert x2 == 13 - - let x4 = await asyncFact(3).then(asyncIdentity).then(asyncIdentity).then((a:int) => a * 7).then(asyncIdentity) - doAssert x4 == 3 * 2 * 7 - - block: # bug #17177 - proc asyncIdentityNested(n: int): Future[int] {.async.} = return n - let x5 = await asyncFact(3).then(asyncIdentityNested) - doAssert x5 == 3 * 2 - - when false: # xxx pending bug #17254 - let x6 = await asyncFact(3).then((a:int) {.async.} => a * 11) - doAssert x6 == 3 * 2 * 11 - - block: # catch - var reason: Error - await fn(6).then((a: int) => (witness.add $a)).catch((r: Error) => (reason = r)) - doAssert reason == nil - - await fn(7).then((a: int) => (discard)).catch((r: Error) => (reason = r)) - doAssert reason != nil - doAssert reason.name == "Error" - doAssert "foobar: 7" in $reason.message - echo "done" # justified here to make sure we're running this, since it's inside `async` - -block asyncPragmaInType: - type Handler = proc () {.async.} - proc foo() {.async.} = discard - var x: Handler = foo - -discard main() diff --git a/tests/js/tasyncjs_bad.nim b/tests/js/tasyncjs_bad.nim deleted file mode 100644 index b1e5a7bc3..000000000 --- a/tests/js/tasyncjs_bad.nim +++ /dev/null @@ -1,22 +0,0 @@ -discard """ - exitCode: 1 - outputsub: "Error: unhandled exception: foobar: 13" -""" - -# note: this needs `--unhandled-rejections=strict`, see D20210217T215950 - -import std/asyncjs -from std/sugar import `=>` - -proc fn(n: int): Future[int] {.async.} = - if n >= 7: raise newException(ValueError, "foobar: " & $n) - else: result = n - -proc main() {.async.} = - let x1 = await fn(6) - doAssert x1 == 6 - await fn(7).catch((a: Error) => (discard)) - let x3 = await fn(13) - doAssert false # shouldn't go here, should fail before - -discard main() diff --git a/tests/js/tbasics.nim b/tests/js/tbasics.nim index ef84f8bb5..b297bb037 100644 --- a/tests/js/tbasics.nim +++ b/tests/js/tbasics.nim @@ -54,7 +54,7 @@ for x in someGlobal: doAssert(x == 0) proc tdefault = var x = default(int) doAssert(x == 0) - proc inner(v: openArray[string]) = + proc inner(v: openarray[string]) = doAssert(v.len == 0) inner(default(seq[string])) diff --git a/tests/js/tbigint_backend.nim b/tests/js/tbigint_backend.nim deleted file mode 100644 index 8f2f6c4f4..000000000 --- a/tests/js/tbigint_backend.nim +++ /dev/null @@ -1,57 +0,0 @@ -import std/private/jsutils - - -type JsBigIntImpl {.importc: "bigint".} = int -type JsBigInt = distinct JsBigIntImpl - -doAssert JsBigInt isnot int -func big*(integer: SomeInteger): JsBigInt {.importjs: "BigInt(#)".} -func big*(integer: cstring): JsBigInt {.importjs: "BigInt(#)".} -func `<=`*(x, y: JsBigInt): bool {.importjs: "(# $1 #)".} -func `==`*(x, y: JsBigInt): bool {.importjs: "(# === #)".} -func inc*(x: var JsBigInt) {.importjs: "[#][0][0]++".} -func inc2*(x: var JsBigInt) {.importjs: "#++".} -func toCstring*(this: JsBigInt): cstring {.importjs: "#.toString()".} -func `$`*(this: JsBigInt): string = - $toCstring(this) - -block: - doAssert defined(nimHasJsBigIntBackend) - let z1 = big"10" - let z2 = big"15" - doAssert z1 == big"10" - doAssert z1 == z1 - doAssert z1 != z2 - var s: seq[cstring] - for i in z1 .. z2: - s.add $i - doAssert s == @["10".cstring, "11", "12", "13", "14", "15"] - block: - var a=big"3" - a.inc - doAssert a == big"4" - block: - var z: JsBigInt - doAssert $z == "0" - doAssert z.jsTypeOf == "bigint" # would fail without codegen change - doAssert z != big(1) - doAssert z == big"0" # ditto - - # ditto below - block: - let z: JsBigInt = big"1" - doAssert $z == "1" - doAssert z.jsTypeOf == "bigint" - doAssert z == big"1" - - block: - let z = JsBigInt.default - doAssert $z == "0" - doAssert z.jsTypeOf == "bigint" - doAssert z == big"0" - - block: - var a: seq[JsBigInt] - a.setLen 3 - doAssert a[^1].jsTypeOf == "bigint" - doAssert a[^1] == big"0" diff --git a/tests/js/tbyvar.nim b/tests/js/tbyvar.nim index 93724a2f1..705d62574 100644 --- a/tests/js/tbyvar.nim +++ b/tests/js/tbyvar.nim @@ -1,16 +1,15 @@ discard """ - output: ''' -foo 12 + output: '''foo 12 bar 12 2 foo 12 bar 12 2 12.5 -(nums: @[5.0, 5.0, 10.0, 5.0, 5.0, 5.0, 5.0, 5.0, 5.0, 5.0]) -(nums: @[5.0, 5.0, 50.0, 5.0, 5.0, 5.0, 5.0, 5.0, 5.0, 5.0]) -(nums: @[5.0, 5.0, 45.0, 5.0, 5.0, 5.0, 5.0, 5.0, 5.0, 5.0]) -(nums: @[5.0, 5.0, 9.0, 5.0, 5.0, 5.0, 5.0, 5.0, 5.0, 5.0]) +(nums: @[5, 5, 10, 5, 5, 5, 5, 5, 5, 5]) +(nums: @[5, 5, 50, 5, 5, 5, 5, 5, 5, 5]) +(nums: @[5, 5, 45, 5, 5, 5, 5, 5, 5, 5]) +(nums: @[5, 5, 9, 5, 5, 5, 5, 5, 5, 5]) asd ''' """ @@ -39,9 +38,9 @@ proc main = main() -# Test: pass var seq to var openArray +# Test: pass var seq to var openarray var s = @[2, 1] -proc foo(a: var openArray[int]) = a[0] = 123 +proc foo(a: var openarray[int]) = a[0] = 123 proc bar(s: var seq[int], a: int) = doAssert(a == 5) diff --git a/tests/js/tclosures.nim b/tests/js/tclosures.nim index 4f1c28de3..3137123bf 100644 --- a/tests/js/tclosures.nim +++ b/tests/js/tclosures.nim @@ -22,7 +22,7 @@ asm """ function print (text) { console.log (text); } """ -proc consoleprint (str:cstring): void {.importc: "print", nodecl.} +proc consoleprint (str:cstring): void {.importc: "print", noDecl.} proc print* (a: varargs[string, `$`]) = consoleprint "$1: $2" % [consolePrefix, join(a, " ")] type CallbackProc {.importc.} = proc () : cstring diff --git a/tests/js/tconsole.nim b/tests/js/tconsole.nim index 88c71ea18..b2eecc656 100644 --- a/tests/js/tconsole.nim +++ b/tests/js/tconsole.nim @@ -3,6 +3,7 @@ discard """ Hello, console 1 2 3 ''' + disabled: "freebsd" """ # This file tests the JavaScript console diff --git a/tests/js/tcsymbol.nim b/tests/js/tcsymbol.nim deleted file mode 100644 index 07e52b9b6..000000000 --- a/tests/js/tcsymbol.nim +++ /dev/null @@ -1,6 +0,0 @@ -discard """ - matrix: "--cc:gcc; --cc:tcc" -""" - -doAssert not defined(gcc) -doAssert not defined(tcc) \ No newline at end of file diff --git a/tests/js/tdiscard.nim b/tests/js/tdiscard.nim deleted file mode 100644 index 9aa6ea1b1..000000000 --- a/tests/js/tdiscard.nim +++ /dev/null @@ -1,3 +0,0 @@ -import dom - -discard Node() \ No newline at end of file diff --git a/tests/js/tdollar_float.nim b/tests/js/tdollar_float.nim deleted file mode 100644 index 4fd8e3cba..000000000 --- a/tests/js/tdollar_float.nim +++ /dev/null @@ -1,62 +0,0 @@ -#[ -merge into tests/system/tdollars.nim once https://github.com/nim-lang/Nim/pull/14122 -is merged -]# - -import unittest - -block: # https://github.com/timotheecour/Nim/issues/133 - # simple test - var a: float = 2 - check $a == "2.0" - - # systematic tests - template fun(a2: static float) = - const a: float = a2 # needed pending https://github.com/timotheecour/Nim/issues/132 - var b = a - check $b == $a - - fun 2 - fun 2.0 - fun 2.1 - fun 1_000 - fun 1_000.1 - fun 1_000_000_000.1 - fun 1_000_000_000_000.1 - - # negatives - fun -2.0 - fun -2.1 - - # 0 - fun 0 - fun -0 - fun 0.0 - - block: - var a = -0.0 - check $a in ["-0.0", "0.0"] - - # exponents - block: - var a = 5e20 - check $a in ["5e20", "500000000000000000000.0"] - - fun 3.4e1'f32 - fun 3.4e-1'f32 - fun -3.4e-1'f32 - fun 3.4e-1'f32 - fun 3e-1'f32 - - block: - var a = 3.4e38'f32 - check $a in ["3.4e+38", "3.4e+038"] - # on windows, printf (used in VM) prints as 3.4e+038 - # but js prints as 3.4e+38 - # on osx, both print as 3.4e+38 - # see https://github.com/timotheecour/Nim/issues/138 - - when false: # edge cases - fun -0.0 # see https://github.com/timotheecour/Nim/issues/136 - fun 5e20 - fun 3.4e38'f32 diff --git a/tests/js/temptyseq.nim b/tests/js/temptyseq.nim deleted file mode 100644 index 6489cf817..000000000 --- a/tests/js/temptyseq.nim +++ /dev/null @@ -1,8 +0,0 @@ -# #12671 - -proc foo = - var x: seq[int] - doAssertRaises(IndexDefect): - inc x[0] - -foo() diff --git a/tests/js/tfieldchecks.nim b/tests/js/tfieldchecks.nim index a0679a349..77759a75a 100644 --- a/tests/js/tfieldchecks.nim +++ b/tests/js/tfieldchecks.nim @@ -24,15 +24,15 @@ var obj = X(f0: "foo", f1: C, f3: 3.14) block: echo obj.f0 echo obj.f1 - doAssertRaises(FieldDefect): echo obj.f2 + doAssertRaises(FieldError): echo obj.f2 echo obj.f3 block: let a0 = addr(obj.f0) echo a0[] - # let a1 = addr(obj.f1) + # let a1 = unsafeAddr(obj.f1) # echo a1[] - doAssertRaises(FieldDefect): + doAssertRaises(FieldError): let a2 = addr(obj.f2) echo a2[] let a3 = addr(obj.f3) diff --git a/tests/js/tglobal.nim b/tests/js/tglobal.nim deleted file mode 100644 index 38f5eec34..000000000 --- a/tests/js/tglobal.nim +++ /dev/null @@ -1,30 +0,0 @@ -block global: - proc getState(): int = - var state0 {.global.}: int - inc state0 - result = state0 - - for i in 0 ..< 3: - doAssert getState() == i + 1 - - for i in 0 ..< 3: - once: - doAssert i == 0 - - -block threadvar: - proc getThreadState0(): int = - var state0 {.threadvar.}: int - inc state0 - result = state0 - - for i in 0 ..< 3: - doAssert getThreadState0() == i + 1 - - proc getThreadState1(): int = - var state1 {.threadvar.}: int - inc state1 - result = state1 - - for i in 0 ..< 3: - doAssert getThreadState1() == i + 1 diff --git a/tests/js/tindexdefect.nim b/tests/js/tindexdefect.nim deleted file mode 100644 index 37994ec2e..000000000 --- a/tests/js/tindexdefect.nim +++ /dev/null @@ -1,9 +0,0 @@ -discard """ - outputsub: "unhandled exception: index 10000 not in 0 .. 0 [IndexDefect]" - exitcode: 1 - joinable: false -""" - -var s = ['a'] -let z = s[10000] == 'a' -echo z \ No newline at end of file diff --git a/tests/js/tjsffi.nim b/tests/js/tjsffi.nim index 2e57f70c1..af33cee8a 100644 --- a/tests/js/tjsffi.nim +++ b/tests/js/tjsffi.nim @@ -1,196 +1,291 @@ discard """ output: ''' +true +true +true +true +true +true +true +true +true +true +true +true +true +true +true +true 3 2 12 Event { name: 'click: test' } Event { name: 'reloaded: test' } Event { name: 'updates: test' } +true +true +true +true +true +true +true ''' """ import jsffi, jsconsole # Tests for JsObject -block: # Test JsObject []= and [] - let obj = newJsObject() - obj["a"] = 11 - obj["b"] = "test" - obj["c"] = "test".cstring - doAssert obj["a"].to(int) == 11 - doAssert obj["c"].to(cstring) == "test".cstring +# Test JsObject []= and [] +block: + proc test(): bool = + let obj = newJsObject() + var working = true + obj["a"] = 11 + obj["b"] = "test" + obj["c"] = "test".cstring + working = working and obj["a"].to(int) == 11 + working = working and obj["c"].to(cstring) == "test".cstring + working + echo test() -block: # Test JsObject .= and . - let obj = newJsObject() - obj.a = 11 - obj.b = "test" - obj.c = "test".cstring - obj.`$!&` = 42 - obj.`while` = 99 - doAssert obj.a.to(int) == 11 - doAssert obj.b.to(string) == "test" - doAssert obj.c.to(cstring) == "test".cstring - doAssert obj.`$!&`.to(int) == 42 - doAssert obj.`while`.to(int) == 99 +# Test JsObject .= and . +block: + proc test(): bool = + let obj = newJsObject() + var working = true + obj.a = 11 + obj.b = "test" + obj.c = "test".cstring + obj.`$!&` = 42 + obj.`while` = 99 + working = working and obj.a.to(int) == 11 + working = working and obj.b.to(string) == "test" + working = working and obj.c.to(cstring) == "test".cstring + working = working and obj.`$!&`.to(int) == 42 + working = working and obj.`while`.to(int) == 99 + working + echo test() -block: # Test JsObject .() - let obj = newJsObject() - obj.`?!$` = proc(x, y, z: int, t: cstring): cstring = t & $(x + y + z) - doAssert obj.`?!$`(1, 2, 3, "Result is: ").to(cstring) == cstring"Result is: 6" +# Test JsObject .() +block: + proc test(): bool = + let obj = newJsObject() + obj.`?!$` = proc(x, y, z: int, t: cstring): cstring = t & $(x + y + z) + obj.`?!$`(1, 2, 3, "Result is: ").to(cstring) == cstring"Result is: 6" + echo test() -block: # Test JsObject []() - let obj = newJsObject() - obj.a = proc(x, y, z: int, t: string): string = t & $(x + y + z) - let call = obj["a"].to(proc(x, y, z: int, t: string): string) - doAssert call(1, 2, 3, "Result is: ") == "Result is: 6" +# Test JsObject []() +block: + proc test(): bool = + let obj = newJsObject() + obj.a = proc(x, y, z: int, t: string): string = t & $(x + y + z) + let call = obj["a"].to(proc(x, y, z: int, t: string): string) + call(1, 2, 3, "Result is: ") == "Result is: 6" + echo test() # Test JsObject Iterators -block: # testPairs - let obj = newJsObject() - obj.a = 10 - obj.b = 20 - obj.c = 30 - for k, v in obj.pairs: - case $k - of "a": - doAssert v.to(int) == 10 - of "b": - doAssert v.to(int) == 20 - of "c": - doAssert v.to(int) == 30 - else: - doAssert false -block: # testItems - let obj = newJsObject() - obj.a = 10 - obj.b = 20 - obj.c = 30 - for v in obj.items: - doAssert v.to(int) in [10, 20, 30] -block: # testKeys - let obj = newJsObject() - obj.a = 10 - obj.b = 20 - obj.c = 30 - for v in obj.keys: - doAssert $v in ["a", "b", "c"] +block: + proc testPairs(): bool = + let obj = newJsObject() + var working = true + obj.a = 10 + obj.b = 20 + obj.c = 30 + for k, v in obj.pairs: + case $k + of "a": + working = working and v.to(int) == 10 + of "b": + working = working and v.to(int) == 20 + of "c": + working = working and v.to(int) == 30 + else: + return false + working + proc testItems(): bool = + let obj = newJsObject() + var working = true + obj.a = 10 + obj.b = 20 + obj.c = 30 + for v in obj.items: + working = working and v.to(int) in [10, 20, 30] + working + proc testKeys(): bool = + let obj = newJsObject() + var working = true + obj.a = 10 + obj.b = 20 + obj.c = 30 + for v in obj.keys: + working = working and $v in ["a", "b", "c"] + working + proc test(): bool = testPairs() and testItems() and testKeys() + echo test() -block: # Test JsObject equality - {. emit: "var comparison = {a: 22, b: 'test'};" .} - var comparison {. importjs, nodecl .}: JsObject - let obj = newJsObject() - obj.a = 22 - obj.b = "test".cstring - doAssert obj.a == comparison.a and obj.b == comparison.b +# Test JsObject equality +block: + proc test(): bool = + {. emit: "var comparison = {a: 22, b: 'test'};" .} + var comparison {. importjs, nodecl .}: JsObject + let obj = newJsObject() + obj.a = 22 + obj.b = "test".cstring + obj.a == comparison.a and obj.b == comparison.b + echo test() -block: # Test JsObject literal - {. emit: "var comparison = {a: 22, b: 'test'};" .} - var comparison {. importjs, nodecl .}: JsObject - let obj = JsObject{ a: 22, b: "test".cstring } - doAssert obj.a == comparison.a and obj.b == comparison.b +# Test JsObject literal +block: + proc test(): bool = + {. emit: "var comparison = {a: 22, b: 'test'};" .} + var comparison {. importjs, nodecl .}: JsObject + let obj = JsObject{ a: 22, b: "test".cstring } + obj.a == comparison.a and obj.b == comparison.b + echo test() # Tests for JsAssoc -block: # Test JsAssoc []= and [] - let obj = newJsAssoc[int, int]() - obj[1] = 11 - doAssert not compiles(obj["a"] = 11) - doAssert not compiles(obj["a"]) - doAssert not compiles(obj[2] = "test") - doAssert not compiles(obj[3] = "test".cstring) - doAssert obj[1] == 11 +# Test JsAssoc []= and [] +block: + proc test(): bool = + let obj = newJsAssoc[int, int]() + var working = true + obj[1] = 11 + working = working and not compiles(obj["a"] = 11) + working = working and not compiles(obj["a"]) + working = working and not compiles(obj[2] = "test") + working = working and not compiles(obj[3] = "test".cstring) + working = working and obj[1] == 11 + working + echo test() -block: # Test JsAssoc .= and . - let obj = newJsAssoc[cstring, int]() - var working = true - obj.a = 11 - obj.`$!&` = 42 - doAssert not compiles(obj.b = "test") - doAssert not compiles(obj.c = "test".cstring) - doAssert obj.a == 11 - doAssert obj.`$!&` == 42 +# Test JsAssoc .= and . +block: + proc test(): bool = + let obj = newJsAssoc[cstring, int]() + var working = true + obj.a = 11 + obj.`$!&` = 42 + working = working and not compiles(obj.b = "test") + working = working and not compiles(obj.c = "test".cstring) + working = working and obj.a == 11 + working = working and obj.`$!&` == 42 + working + echo test() -block: # Test JsAssoc .() - let obj = newJsAssoc[cstring, proc(e: int): int]() - obj.a = proc(e: int): int = e * e - doAssert obj.a(10) == 100 +# Test JsAssoc .() +block: + proc test(): bool = + let obj = newJsAssoc[cstring, proc(e: int): int]() + obj.a = proc(e: int): int = e * e + obj.a(10) == 100 + echo test() -block: # Test JsAssoc []() - let obj = newJsAssoc[cstring, proc(e: int): int]() - obj.a = proc(e: int): int = e * e - let call = obj["a"] - doAssert call(10) == 100 +# Test JsAssoc []() +block: + proc test(): bool = + let obj = newJsAssoc[cstring, proc(e: int): int]() + obj.a = proc(e: int): int = e * e + let call = obj["a"] + call(10) == 100 + echo test() # Test JsAssoc Iterators -block: # testPairs - let obj = newJsAssoc[cstring, int]() - obj.a = 10 - obj.b = 20 - obj.c = 30 - for k, v in obj.pairs: - case $k - of "a": - doAssert v == 10 - of "b": - doAssert v == 20 - of "c": - doAssert v == 30 - else: - doAssert false -block: # testItems - let obj = newJsAssoc[cstring, int]() - obj.a = 10 - obj.b = 20 - obj.c = 30 - for v in obj.items: - doAssert v in [10, 20, 30] -block: # testKeys - let obj = newJsAssoc[cstring, int]() - obj.a = 10 - obj.b = 20 - obj.c = 30 - for v in obj.keys: - doAssert v in [cstring"a", cstring"b", cstring"c"] +block: + proc testPairs(): bool = + let obj = newJsAssoc[cstring, int]() + var working = true + obj.a = 10 + obj.b = 20 + obj.c = 30 + for k, v in obj.pairs: + case $k + of "a": + working = working and v == 10 + of "b": + working = working and v == 20 + of "c": + working = working and v == 30 + else: + return false + working + proc testItems(): bool = + let obj = newJsAssoc[cstring, int]() + var working = true + obj.a = 10 + obj.b = 20 + obj.c = 30 + for v in obj.items: + working = working and v in [10, 20, 30] + working + proc testKeys(): bool = + let obj = newJsAssoc[cstring, int]() + var working = true + obj.a = 10 + obj.b = 20 + obj.c = 30 + for v in obj.keys: + working = working and v in [cstring"a", cstring"b", cstring"c"] + working + proc test(): bool = testPairs() and testItems() and testKeys() + echo test() -block: # Test JsAssoc equality - {. emit: "var comparison = {a: 22, b: 55};" .} - var comparison {. importjs, nodecl .}: JsAssoc[cstring, int] - let obj = newJsAssoc[cstring, int]() - obj.a = 22 - obj.b = 55 - doAssert obj.a == comparison.a and obj.b == comparison.b +# Test JsAssoc equality +block: + proc test(): bool = + {. emit: "var comparison = {a: 22, b: 55};" .} + var comparison {. importjs, nodecl .}: JsAssoc[cstring, int] + let obj = newJsAssoc[cstring, int]() + obj.a = 22 + obj.b = 55 + obj.a == comparison.a and obj.b == comparison.b + echo test() -block: # Test JsAssoc literal - {. emit: "var comparison = {a: 22, b: 55};" .} - var comparison {. importjs, nodecl .}: JsAssoc[cstring, int] - let obj = JsAssoc[cstring, int]{ a: 22, b: 55 } - doAssert compiles(JsAssoc[int, int]{ 1: 22, 2: 55 }) - doAssert comparison.a == obj.a and comparison.b == obj.b - doAssert not compiles(JsAssoc[cstring, int]{ a: "test" }) +# Test JsAssoc literal +block: + proc test(): bool = + {. emit: "var comparison = {a: 22, b: 55};" .} + var comparison {. importjs, nodecl .}: JsAssoc[cstring, int] + let obj = JsAssoc[cstring, int]{ a: 22, b: 55 } + var working = true + working = working and + compiles(JsAssoc[int, int]{ 1: 22, 2: 55 }) + working = working and + comparison.a == obj.a and comparison.b == obj.b + working = working and + not compiles(JsAssoc[cstring, int]{ a: "test" }) + working + echo test() # Tests for macros on non-JsRoot objects -block: # Test lit +# Test lit +block: type TestObject = object a: int b: cstring - {. emit: "var comparison = {a: 1};" .} - var comparison {. importjs, nodecl .}: TestObject - let obj = TestObject{ a: 1 } - doAssert obj == comparison + proc test(): bool = + {. emit: "var comparison = {a: 1};" .} + var comparison {. importjs, nodecl .}: TestObject + let obj = TestObject{ a: 1 } + obj == comparison + echo test() -block: # Test bindMethod +# Test bindMethod +block: type TestObject = object a: int onWhatever: proc(e: int): int proc handleWhatever(this: TestObject, e: int): int = e + this.a - block: + proc test(): bool = let obj = TestObject(a: 9, onWhatever: bindMethod(handleWhatever)) - doAssert obj.onWhatever(1) == 10 + obj.onWhatever(1) == 10 + echo test() block: {.emit: "function jsProc(n) { return n; }" .} proc jsProc(x: int32): JsObject {.importjs: "jsProc(#)".} - block: + + proc test() = var x = jsProc(1) var y = jsProc(2) console.log x + y @@ -199,6 +294,8 @@ block: x += jsProc(10) console.log x + test() + block: {.emit: """ @@ -217,7 +314,7 @@ block: on("click") do (e: Event): console.log e - jslib.on("reloaded") do (): + jslib.on("reloaded") do: console.log jsarguments[0] # this test case is different from the above, because @@ -226,42 +323,11 @@ block: console.log jsarguments[0] block: - doAssert jsUndefined == jsNull - doAssert jsUndefined == nil - doAssert jsNull == nil - doAssert jsUndefined.isNil - doAssert jsNull.isNil - doAssert jsNull.isNull - doAssert jsUndefined.isUndefined -block: # test ** - var a = toJs(0) - var b = toJs(0) - doAssert to(a ** b, int) == 1 - a = toJs(1) - b = toJs(1) - doAssert to(a ** b, int) == 1 - a = toJs(-1) - b = toJs(-1) - doAssert to(a ** b, int) == -1 - a = toJs(6) - b = toJs(6) - doAssert to(a ** b, int) == 46656 - a = toJs(5.5) - b = toJs(3) - doAssert to(a ** b, float) == 166.375 - a = toJs(5) - b = toJs(3.0) - doAssert to(a ** b, float) == 125.0 - a = toJs(7.0) - b = toJS(6.0) - doAssert to(a ** b, float) == 117649.0 - a = toJs(8) - b = toJS(-2) - doAssert to(a ** b, float) == 0.015625 - - a = toJs(1) - b = toJs(1) - doAssert to(`**`(a + a, b), int) == 2 - - doAssert to(`**`(toJs(1) + toJs(1), toJs(2)), int) == 4 + echo jsUndefined == jsNull + echo jsUndefined == nil + echo jsNull == nil + echo jsUndefined.isNil + echo jsNull.isNil + echo jsNull.isNull + echo jsUndefined.isUndefined diff --git a/tests/js/tjsffi_old.nim b/tests/js/tjsffi_old.nim index 19f30ee2c..1f149694b 100644 --- a/tests/js/tjsffi_old.nim +++ b/tests/js/tjsffi_old.nim @@ -35,9 +35,6 @@ true ## same as tjsffi, but this test uses the old names: importc and ## importcpp. This test is for backwards compatibility. -# xxx instead of maintaining this near-duplicate test file, just have tests -# that check that importc, importcpp, importjs work and remove this file. - import jsffi, jsconsole # Tests for JsObject @@ -321,7 +318,7 @@ block: on("click") do (e: Event): console.log e - jslib.on("reloaded") do (): + jslib.on("reloaded") do: console.log jsarguments[0] # this test case is different from the above, because diff --git a/tests/js/tjshello.nim b/tests/js/tjshello.nim index 8e090b3d2..19e0b90ae 100644 --- a/tests/js/tjshello.nim +++ b/tests/js/tjshello.nim @@ -1,5 +1,4 @@ discard """ - cmd: "nim $target $options --stackTrace:off --lineTrace:off $file" output: "Hello World" maxcodesize: 1000 ccodecheck: "!@'function'" @@ -8,3 +7,4 @@ discard """ import jsconsole console.log "Hello World" + diff --git a/tests/js/tjshello_stacktrace.nim b/tests/js/tjshello_stacktrace.nim deleted file mode 100644 index d5e1c36eb..000000000 --- a/tests/js/tjshello_stacktrace.nim +++ /dev/null @@ -1,9 +0,0 @@ -discard """ - output: "Hello World" - maxcodesize: 4500 - ccodecheck: "!@'function'" -""" - -import jsconsole - -console.log "Hello World" diff --git a/tests/js/tlent.nim b/tests/js/tlent.nim deleted file mode 100644 index 2546e5b1d..000000000 --- a/tests/js/tlent.nim +++ /dev/null @@ -1,33 +0,0 @@ -discard """ - output: ''' -hmm -100 -hmm -100 -''' -""" - -# #16800 - -type A = object - b: int -var t = A(b: 100) -block: - proc getValues: lent int = - echo "hmm" - result = t.b - echo getValues() -block: - proc getValues: lent int = - echo "hmm" - t.b - echo getValues() - -when false: # still an issue, #16908 - template main = - iterator fn[T](a:T): lent T = yield a - let a = @[10] - for b in fn(a): echo b - - static: main() - main() diff --git a/tests/js/tmangle.nim b/tests/js/tmangle.nim index caaa15fa1..c97bf7029 100644 --- a/tests/js/tmangle.nim +++ b/tests/js/tmangle.nim @@ -62,8 +62,8 @@ block: result = result and obj1.`&&`.addr[] == "bar".cstring result = result and obj2.`if` == 0 result = result and obj2.`for` == 0 - result = result and obj2.`==`.isNil - result = result and obj2.`&&`.isNil + result = result and obj2.`==`.isNil() + result = result and obj2.`&&`.isNil() echo test() # Test codegen for fields with uppercase letters: diff --git a/tests/js/tmodify_cstring.nim b/tests/js/tmodify_cstring.nim deleted file mode 100644 index 82f8ccb23..000000000 --- a/tests/js/tmodify_cstring.nim +++ /dev/null @@ -1,6 +0,0 @@ -discard """ - errormsg: "cstring doesn't support `[]=` operator" -""" - -var x = cstring"abcd" -x[0] = 'x' diff --git a/tests/js/tnilstrs.nim b/tests/js/tnilstrs.nim index 6c1e4e401..c0048cb24 100644 --- a/tests/js/tnilstrs.nim +++ b/tests/js/tnilstrs.nim @@ -14,12 +14,4 @@ block: var x = "foo".cstring var y: string add(y, x) - doAssert y == "foo" - -block: - type Foo = object - a: string - var foo = Foo(a: "foo") - var y = move foo.a - doAssert foo.a.len == 0 - doAssert y == "foo" + doAssert y == "foo" \ No newline at end of file diff --git a/tests/js/tos.nim b/tests/js/tos.nim deleted file mode 100644 index bfe3cd9b4..000000000 --- a/tests/js/tos.nim +++ /dev/null @@ -1,23 +0,0 @@ -# xxx consider merging this in tests/stdlib/tos.nim for increased coverage (with selecting disabling) - -static: doAssert defined(nodejs) - -import os - -block: - doAssert "./foo//./bar/".normalizedPath == "foo/bar" - doAssert relativePath(".//foo/bar", "foo") == "bar" - doAssert "/".isAbsolute - doAssert not "".isAbsolute - doAssert not ".".isAbsolute - doAssert not "foo".isAbsolute - doAssert relativePath("", "bar") == "" - doAssert normalizedPath(".///foo//./") == "foo" - let cwd = getCurrentDir() - - let isWindows = '\\' in cwd - # defined(windows) doesn't work with -d:nodejs but should - # these actually break because of that (see https://github.com/nim-lang/Nim/issues/13469) - if not isWindows: - doAssert cwd.isAbsolute - doAssert relativePath(getCurrentDir() / "foo", "bar") == "../foo" diff --git a/tests/js/trepr.nim b/tests/js/trepr.nim index a562ad63b..366d247c5 100644 --- a/tests/js/trepr.nim +++ b/tests/js/trepr.nim @@ -1,4 +1,6 @@ -# xxx consider merging with `tests/stdlib/trepr.nim` to increase overall test coverage +discard """ + action: run +""" block ints: let @@ -135,13 +137,15 @@ block tuples: when defined js: doAssert(repr(ot) == """ [Field0 = true, -Field1 = 120]""") +Field1 = 120] +""") doAssert(repr(t) == """ [Field0 = 42, Field1 = 12.34, Field2 = "tuple", Field3 = [Field0 = true, -Field1 = 120]]""") +Field1 = 120]] +""") block objects: type @@ -158,12 +162,14 @@ block objects: doAssert(repr(oo) == """ [a = true, -b = 120]""") +b = 120] +""") doAssert(repr(o) == """ [a = 42, b = 12.34, c = [a = true, -b = 120]]""") +b = 120]] +""") block arrays: type @@ -177,14 +183,15 @@ block arrays: c = [o, o, o] d = ["hi", "array", "!"] - doAssert(repr(a) == "[0.0, 1.0, 2.0]") - doAssert(repr(b) == "[[0.0, 1.0, 2.0], [0.0, 1.0, 2.0], [0.0, 1.0, 2.0]]") + doAssert(repr(a) == "[0.0, 1.0, 2.0]\n") + doAssert(repr(b) == "[[0.0, 1.0, 2.0], [0.0, 1.0, 2.0], [0.0, 1.0, 2.0]]\n") doAssert(repr(c) == """ [[x = 42, y = [0.0, 1.0, 2.0]], [x = 42, y = [0.0, 1.0, 2.0]], [x = 42, -y = [0.0, 1.0, 2.0]]]""") - doAssert(repr(d) == "[\"hi\", \"array\", \"!\"]") +y = [0.0, 1.0, 2.0]]] +""") + doAssert(repr(d) == "[\"hi\", \"array\", \"!\"]\n") block seqs: type @@ -198,14 +205,15 @@ block seqs: c = @[o, o, o] d = @["hi", "array", "!"] - doAssert(repr(a) == "@[0.0, 1.0, 2.0]") - doAssert(repr(b) == "@[@[0.0, 1.0, 2.0], @[0.0, 1.0, 2.0], @[0.0, 1.0, 2.0]]") + doAssert(repr(a) == "@[0.0, 1.0, 2.0]\n") + doAssert(repr(b) == "@[@[0.0, 1.0, 2.0], @[0.0, 1.0, 2.0], @[0.0, 1.0, 2.0]]\n") doAssert(repr(c) == """ @[[x = 42, y = @[0.0, 1.0, 2.0]], [x = 42, y = @[0.0, 1.0, 2.0]], [x = 42, -y = @[0.0, 1.0, 2.0]]]""") - doAssert(repr(d) == "@[\"hi\", \"array\", \"!\"]") +y = @[0.0, 1.0, 2.0]]] +""") + doAssert(repr(d) == "@[\"hi\", \"array\", \"!\"]\n") block ptrs: type @@ -218,12 +226,13 @@ block ptrs: c = addr a[2] d = AObj() - doAssert(repr(a) == "[12.0, 13.0, 14.0]") - doAssert(repr(b) == "ref 0 --> 12.0") - doAssert(repr(c) == "ref 2 --> 14.0") + doAssert(repr(a) == "[12.0, 13.0, 14.0]\n") + doAssert(repr(b) == "ref 0 --> 12.0\n") + doAssert(repr(c) == "ref 2 --> 14.0\n") doAssert(repr(d) == """ [x = nil, -y = 0]""") +y = 0] +""") block ptrs: type @@ -239,7 +248,8 @@ block ptrs: [x = ref 0 --> [[x = nil, y = 0], [x = nil, y = 0]], -y = 0]""") +y = 0] +""") block procs: proc test(): int = @@ -248,9 +258,9 @@ block procs: ptest = test nilproc: proc(): int - doAssert(repr(test) == "0") - doAssert(repr(ptest) == "0") - doAssert(repr(nilproc) == "nil") + doAssert(repr(test) == "0\n") + doAssert(repr(ptest) == "0\n") + doAssert(repr(nilproc) == "nil\n") block bunch: type @@ -283,7 +293,7 @@ block bunch: result[] = b var - aa = default(A) + aa: A bb: B = B(a: "inner", b: @['o', 'b', 'j']) cc: A = A(a: 12, b: 1, c: 1.2, d: '\0', e: eC, f: "hello", g: {'A'}, h: {2'i16}, @@ -298,21 +308,22 @@ b = 0, c = 0.0, d = '\0', e = eA, -f = "", +f = nil, g = {}, h = {}, -i = ["", "", ""], -j = @[], -k = -12, -l = [a = "", -b = @[]], +i = [nil, nil, nil], +j = nil, +k = 0, +l = [a = nil, +b = nil], m = nil, n = nil, -o = [Field0 = [a = "", -b = @[]], -Field1 = ""], +o = [Field0 = [a = nil, +b = nil], +Field1 = nil], p = nil, -q = nil]""") +q = nil] +""") doAssert(repr(cc) == """ [a = 12, b = 1, @@ -335,7 +346,8 @@ o = [Field0 = [a = "inner", b = @['o', 'b', 'j']], Field1 = "tuple!"], p = 0, -q = "cstringtest"]""") +q = "cstringtest"] +""") block another: type @@ -346,9 +358,9 @@ block another: Size3 = enum s3e=0, s3f=2000000000 - doAssert(repr([s1a, s1b]) == "[s1a, s1b]") - doAssert(repr([s2c, s2d]) == "[s2c, s2d]") - doAssert(repr([s3e, s3f]) == "[s3e, s3f]") + doAssert(repr([s1a, s1b]) == "[s1a, s1b]\n") + doAssert(repr([s2c, s2d]) == "[s2c, s2d]\n") + doAssert(repr([s3e, s3f]) == "[s3e, s3f]\n") block another2: @@ -383,13 +395,15 @@ block another2: y = 13, z = 45, s = ["abc", "xyz"], -e = en6]""") +e = en6] +""") doAssert(repr(q) == """ ref 0 --> [x = 0, y = 13, z = 45, s = ["abc", "xyz"], -e = en6]""") +e = en6] +""") doAssert(repr(s) == """ @[ref 0 --> [x = 0, y = 13, @@ -407,7 +421,8 @@ e = en6], ref 3 --> [x = 0, y = 13, z = 45, s = ["abc", "xyz"], -e = en6]]""") +e = en6]] +""") doAssert(repr(en4) == "en4") doAssert(repr({'a'..'p'}) == "{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p'}") diff --git a/tests/js/treprinifexpr.nim b/tests/js/treprinifexpr.nim deleted file mode 100644 index 09ded18b9..000000000 --- a/tests/js/treprinifexpr.nim +++ /dev/null @@ -1,18 +0,0 @@ -type - Enum = enum A - -let - enumVal = A - tmp = if true: $enumVal else: $enumVal - -let - intVal = 12 - tmp2 = if true: repr(intVal) else: $enumVal - -let - strVal = "123" - tmp3 = if true: repr(strVal) else: $strVal - -let - floatVal = 12.4 - tmp4 = if true: repr(floatVal) else: $floatVal \ No newline at end of file diff --git a/tests/js/tseqops.nim b/tests/js/tseqops.nim index 8cfb50886..af664222c 100644 --- a/tests/js/tseqops.nim +++ b/tests/js/tseqops.nim @@ -1,3 +1,11 @@ +discard """ + output: '''(x: 0, y: 0) +(x: 5, y: 0) +@[(x: "2", y: 4), (x: "4", y: 5), (x: "4", y: 5)] +@[(a: "3", b: 3), (a: "1", b: 1), (a: "2", b: 2)] +''' +""" + # bug #4139 type @@ -9,8 +17,8 @@ proc onLoad() = var foo = TestO(x: 0, y: 0) test.add(foo) foo.x = 5 - doAssert $test[0] == "(x: 0, y: 0)" - doAssert $foo == "(x: 5, y: 0)" + echo(test[0]) + echo foo onLoad() @@ -26,7 +34,7 @@ proc foo(x: var seq[MyObj]) = var s = @[MyObj(x: "2", y: 4), MyObj(x: "4", y: 5)] foo(s) -doAssert $s == """@[(x: "2", y: 4), (x: "4", y: 5), (x: "4", y: 5)]""" +echo s # bug #5933 import sequtils @@ -40,9 +48,4 @@ var test = @[Test(a: "1", b: 1), Test(a: "2", b: 2)] test.insert(@[Test(a: "3", b: 3)], 0) -doAssert $test == """@[(a: "3", b: 3), (a: "1", b: 1), (a: "2", b: 2)]""" - -proc hello(): array[5, int] = discard -var x = @(hello()) -x.add(2) -doAssert x == @[0, 0, 0, 0, 0, 2] +echo test diff --git a/tests/js/tsourcemap.nim b/tests/js/tsourcemap.nim deleted file mode 100644 index ff6f6122f..000000000 --- a/tests/js/tsourcemap.nim +++ /dev/null @@ -1,96 +0,0 @@ -discard """ - action: "run" - target: "js" - cmd: "nim js -r -d:nodejs $options --sourceMap:on $file" -""" -import std/[os, json, strutils, sequtils, algorithm, assertions, paths, compilesettings] - -# Implements a very basic sourcemap parser and then runs it on itself. -# Allows to check for basic problems such as bad counts and lines missing (e.g. issue #21052) - -type - SourceMap = object - version: int - sources: seq[string] - names: seq[string] - mappings: string - file: string - - Line = object - line, column: int - file: string - -const - flag = 1 shl 5 - signBit = 0b1 - fourBits = 0b1111 - fiveBits = 0b11111 - mask = (1 shl 5) - 1 - alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" - -var b64Table: seq[int] = 0.repeat(max(alphabet.mapIt(it.ord)) + 1) -for i, b in alphabet.pairs: - b64Table[b.ord] = i - -# From https://github.com/juancarlospaco/nodejs/blob/main/src/nodejs/jsfs.nim -proc importFs*() {.importjs: "var fs = require(\"fs\");".} -proc readFileSync*(path: cstring): cstring {.importjs: "(fs.$1(#).toString())".} -importFS() -# Read in needed files -let - jsFileName = string(querySetting(outDir).Path / "tsourcemap.js".Path) - mapFileName = jsFileName & ".map" - - data = parseJson($mapFileName.cstring.readFileSync()).to(SourceMap) - jsFile = $readFileSync(jsFileName.cstring) - -proc decodeVLQ(inp: string): seq[int] = - var - shift, value: int - for v in inp.mapIt(b64Table[it.ord]): - value += (v and mask) shl shift - if (v and flag) > 0: - shift += 5 - continue - result &= (value shr 1) * (if (value and 1) > 0: -1 else: 1) - shift = 0 - value = 0 - - -# Keep track of state -var - line = 0 - source = 0 - name = 0 - column = 0 - jsLine = 1 - lines: seq[Line] - -for gline in data.mappings.split(';'): - jsLine += 1 - var jsColumn = 0 - for item in gline.strip().split(','): - let value = item.decodeVLQ() - doAssert value.len in [0, 1, 4, 5] - if value.len == 0: - continue - jsColumn += value[0] - if value.len >= 4: - source += value[1] - line += value[2] - column += value[3] - lines &= Line(line: line, column: column, file: data.sources[source]) - -let jsLines = jsFile.splitLines().len -# There needs to be a mapping for every line in the JS -# If there isn't then the JS lines wont match up with Nim lines. -# Except we don't care about the final line since that doesn't need to line up -doAssert data.mappings.count(';') == jsLines - 1 - -# Check we can find this file somewhere in the source map -var foundSelf = false -for line in lines: - if "tsourcemap.nim" in line.file: - foundSelf = true - doAssert line.line in 0..Nim" - -block txmltree: - var x = <>a(href="nim.de", newText("www.nim-test.de")) - - doAssert($x == "www.nim-test.de") - doAssert(newText("foo").innerText == "foo") - doAssert(newEntity("bar").innerText == "bar") - doAssert(newComment("baz").innerText == "") - - let y = newXmlTree("x", [ - newText("foo"), - newXmlTree("y", [ - newText("bar") - ]) - ]) - doAssert(y.innerText == "foobar") diff --git a/tests/js/tstreams.nim b/tests/js/tstreams.nim deleted file mode 100644 index 43c26e01a..000000000 --- a/tests/js/tstreams.nim +++ /dev/null @@ -1,22 +0,0 @@ -discard """ - output: ''' -I -AM -GROOT -''' -""" - -import streams - -var s = newStringStream("I\nAM\nGROOT") -doAssert s.peekStr(1) == "I" -doAssert s.peekChar() == 'I' -for line in s.lines: - echo line -s.close - -var s2 = newStringStream("abc") -doAssert s2.readAll == "abc" -s2.write("def") -doAssert s2.data == "abcdef" -s2.close diff --git a/tests/js/ttempgen.nim b/tests/js/ttempgen.nim deleted file mode 100644 index badc66c1b..000000000 --- a/tests/js/ttempgen.nim +++ /dev/null @@ -1,79 +0,0 @@ -discard """ - output: ''' -foo -''' -""" - -block: # #12672 - var a = @[1] - let i = 1 - inc a[i-1] - - var b: seq[int] - doAssertRaises(IndexDefect): inc b[0] - doAssertRaises(IndexDefect): inc b[i-1] - - var x: seq[seq[int]] - doAssertRaises(IndexDefect): # not TypeError - inc x[0][i-1] - -block: # #14087 - type Obj = object - str: string - - var s = @[Obj(str: "abc"), Obj(str: "def")] - s[1].str.add("ghi") - s[s.len - 1].str.add("jkl") - s[^1].str.add("mno") - s[s.high].str.add("pqr") - - let slen = s.len - s[slen - 1].str.add("stu") - - let shigh = s.high - s[shigh].str.add("vwx") - - proc foo(): int = - echo "foo" - shigh - s[foo()].str.add("yz") - doAssert s[1].str == "defghijklmnopqrstuvwxyz" - -block: # #14117 - type - A = object - case kind: bool - of true: - sons: seq[int] - else: discard - - var a = A(kind: true) - doAssert a.sons.len == 0 - a.sons.add(1) - doAssert a.sons.len == 1 - -import tables - -block: # #13966 - var t: Table[int8, array[int8, seq[tuple[]]]] - - t[0] = default(array[int8, seq[tuple[]]]) - t[0][0].add () - -block: # #11783 - proc fun(): string = - discard - - var ret: string - ret.add fun() - doAssert ret == "" - -block: # #12256 - var x: bool - - doAssert x == false - - reset x - - doAssert x == false - doAssert x != true diff --git a/tests/js/ttypedarray.nim b/tests/js/ttypedarray.nim deleted file mode 100644 index 222f66569..000000000 --- a/tests/js/ttypedarray.nim +++ /dev/null @@ -1,21 +0,0 @@ -import std/private/jsutils - -proc main()= - template fn(a): untyped = jsConstructorName(a) - doAssert fn(array[2, int8].default) == "Int8Array" - doAssert fn(array[2, uint8].default) == "Uint8Array" - doAssert fn(array[2, byte].default) == "Uint8Array" - # doAssert fn(array[2, char].default) == "Uint8Array" # xxx fails; bug? - doAssert fn(array[2, uint64].default) == "Array" - # pending https://github.com/nim-lang/RFCs/issues/187 maybe use `BigUint64Array` - doAssert fn([1'u8]) == "Uint8Array" - doAssert fn([1'u16]) == "Uint16Array" - doAssert fn([byte(1)]) == "Uint8Array" - doAssert fn([1.0'f32]) == "Float32Array" - doAssert fn(array[2, float32].default) == "Float32Array" - doAssert fn(array[2, float].default) == "Float64Array" - doAssert fn(array[2, float64].default) == "Float64Array" - doAssert fn([1.0]) == "Float64Array" - doAssert fn([1.0'f64]) == "Float64Array" - -main() diff --git a/tests/js/tunion.nim b/tests/js/tunion.nim deleted file mode 100644 index e185495ad..000000000 --- a/tests/js/tunion.nim +++ /dev/null @@ -1,7 +0,0 @@ -discard """ - errormsg: "`{.union.}` is not implemented for js backend." -""" - -type Foo {.union.} = object - as_bytes: array[8, int8] - data: int64 diff --git a/tests/js/tunittest_error.nim b/tests/js/tunittest_error.nim deleted file mode 100644 index 781e34338..000000000 --- a/tests/js/tunittest_error.nim +++ /dev/null @@ -1,24 +0,0 @@ -discard """ - exitcode: 1 - outputsub: "[FAILED] with exception" -""" - -# see also: `tests/stdlib/tunittest_error.nim` - -import unittest - -proc ddd() = - raise newException(IOError, "didn't do stuff") - -proc ccc() = - ddd() - -proc bbb() = - ccc() - -proc aaa() = - bbb() - -test "with exception": - check 3 == 3 - aaa() diff --git a/tests/js/tunittest_error2.nim b/tests/js/tunittest_error2.nim deleted file mode 100644 index 9c5af7529..000000000 --- a/tests/js/tunittest_error2.nim +++ /dev/null @@ -1,16 +0,0 @@ -discard """ - exitcode: 1 - outputsub: ''' -[] -[FAILED] Bad test - ''' - matrix: "-d:nodejs" - targets: "js" - joinable: false -""" - -# bug #16978 -import unittest -test "Bad test": - var x: cstring = nil - let y = x[0] diff --git a/tests/js/tunittests.nim b/tests/js/tunittests.nim new file mode 100644 index 000000000..7c2e70563 --- /dev/null +++ b/tests/js/tunittests.nim @@ -0,0 +1,11 @@ +discard """ + output: ''' +[Suite] Bacon + [OK] >:)''' +""" + +import unittest + +suite "Bacon": + test ">:)": + check(true == true) diff --git a/tests/js/twritestacktrace.nim b/tests/js/twritestacktrace.nim deleted file mode 100644 index 2fe2b1987..000000000 --- a/tests/js/twritestacktrace.nim +++ /dev/null @@ -1,12 +0,0 @@ -discard """ - cmd: "nim js --panics:on $file" - output: '''Traceback (most recent call last) -twritestacktrace.nim(12) at module twritestacktrace -twritestacktrace.nim(10) at twritestacktrace.hello -''' -""" - -proc hello() = - writeStackTrace() - -hello() diff --git a/tests/lent/t16898.nim b/tests/lent/t16898.nim deleted file mode 100644 index a69c6d244..000000000 --- a/tests/lent/t16898.nim +++ /dev/null @@ -1,31 +0,0 @@ -discard """ - errormsg: "invalid type: 'lent QuadraticExt' in this context: 'proc (r: var QuadraticExt, a: lent QuadraticExt, b: lent QuadraticExt){.noSideEffect, gcsafe.}' for proc" -""" - -# bug #16898 -type - Fp[N: static int, T] = object - big: array[N, T] - -type - QuadraticExt* = concept x - ## Quadratic Extension concept (like complex) - type BaseField = auto - x.c0 is BaseField - x.c1 is BaseField - -{.experimental:"views".} - -func prod(r: var QuadraticExt, a, b: lent QuadraticExt) = - discard - -type - Fp2[N: static int, T] = object - c0, c1: Fp[N, T] - -# This should be passed by reference, -# but concepts do not respect the 24 bytes rule -# or `byref` pragma. -var r, a, b: Fp2[6, uint64] - -prod(r, a, b) diff --git a/tests/lent/t17621.nim b/tests/lent/t17621.nim deleted file mode 100644 index e324a963e..000000000 --- a/tests/lent/t17621.nim +++ /dev/null @@ -1,15 +0,0 @@ -discard """ - errormsg: "invalid type: 'lent Test' in this context: 'proc (self: lent Test)' for proc" -""" - -# bug #17621 -{.experimental: "views".} - -type Test = ref object - foo: int - -proc modify(self: lent Test) = - self.foo += 1 - -let test = Test(foo: 12) -modify(test) diff --git a/tests/lent/tbasic_lent_check.nim b/tests/lent/tbasic_lent_check.nim index 92d731451..4389cbc6e 100644 --- a/tests/lent/tbasic_lent_check.nim +++ b/tests/lent/tbasic_lent_check.nim @@ -1,5 +1,4 @@ discard """ - targets: "c cpp js" output: "1" """ @@ -15,48 +14,3 @@ proc main = doAssert(not compiles(passToVar(viewInto(x)))) main() - -template main2 = # bug #15958 - when defined(js): - proc sameAddress[T](a, b: T): bool {.importjs: "(# === #)".} - else: - template sameAddress(a, b): bool = a.unsafeAddr == b.unsafeAddr - proc byLent[T](a: T): lent T = a - let a = [11,12] - let b = @[21,23] - let ss = {1, 2, 3, 5} - doAssert byLent(a) == [11,12] - doAssert sameAddress(byLent(a), a) - doAssert byLent(b) == @[21,23] - # pending bug #16073 - doAssert sameAddress(byLent(b), b) - doAssert byLent(ss) == {1, 2, 3, 5} - doAssert sameAddress(byLent(ss), ss) - - let r = new(float) - r[] = 10.0 - # bug #16073 - doAssert byLent(r)[] == 10.0 - - when not defined(js): # pending bug https://github.com/timotheecour/Nim/issues/372 - let p = create(float) - p[] = 20.0 - doAssert byLent(p)[] == 20.0 - - proc byLent2[T](a: openArray[T]): lent T = a[0] - doAssert byLent2(a) == 11 - doAssert sameAddress(byLent2(a), a[0]) - doAssert byLent2(b) == 21 - doAssert sameAddress(byLent2(b), b[0]) - - proc byLent3[T](a: varargs[T]): lent T = a[1] - let - x = 10 - y = 20 - z = 30 - doAssert byLent3(x, y, z) == 20 - -main2() -when false: - # bug: Error: unhandled exception: 'node' is not accessible using discriminant 'kind' of type 'TFullReg' [FieldDefect] - static: main2() diff --git a/tests/lent/tlent_from_var.nim b/tests/lent/tlent_from_var.nim deleted file mode 100644 index 912390dc1..000000000 --- a/tests/lent/tlent_from_var.nim +++ /dev/null @@ -1,32 +0,0 @@ -discard """ - output: '''x -[10, 11, 12, 13]''' -""" - -# bug #14805 - -type Foo = object - a: string - -proc bar(f: var Foo): lent string = - result = f.a - -var foo = Foo(a: "x") -echo bar(foo) - - -# bug #14878 - -# proc byLentImpl[T](a: T): lent T = a -proc byLentVar[T](a: var T): lent T = - result = a - # result = a.byLentImpl # this doesn't help - -var x = 3 # error: cannot take the address of an rvalue of type 'NI *' - -var xs = [10,11,12,13] # SIGSEGV - -let x2 = x.byLentVar - -let xs2 = xs.byLentVar -echo xs2 diff --git a/tests/lent/tnot_allowed_lent.nim b/tests/lent/tnot_allowed_lent.nim index a1db6d184..b144ce36b 100644 --- a/tests/lent/tnot_allowed_lent.nim +++ b/tests/lent/tnot_allowed_lent.nim @@ -1,5 +1,5 @@ discard """ - errormsg: "expression has no address" + errmsg: "expression has no address" """ type MyObject = object @@ -7,10 +7,10 @@ type proc mytest1(s: MyObject, i: int): lent string = ## works fine - if i < s.x.len - 1 and s.x[i] != "": + if i < s.x.len - 1 and s.x[i] != "": result = s.x[i] else: raise newException(KeyError, "err1") - + proc mytest2(s: MyObject, i: int): lent string = ## reject due to if expr if i < s.x.len - 1 and s.x[i] != "": s.x[i] diff --git a/tests/lent/tnot_allowed_lent2.nim b/tests/lent/tnot_allowed_lent2.nim deleted file mode 100644 index d0c958df3..000000000 --- a/tests/lent/tnot_allowed_lent2.nim +++ /dev/null @@ -1,14 +0,0 @@ -discard """ - errormsg: "'x' cannot be assigned to" - line: 10 -""" - -proc bug14498 = - var a = @['a', 'b', 'c', 'd', 'e', 'f'] - - for x in a: - x = 'c' - - echo a - -bug14498() diff --git a/tests/let/timportc.nim b/tests/let/timportc.nim deleted file mode 100644 index 85244da9f..000000000 --- a/tests/let/timportc.nim +++ /dev/null @@ -1,24 +0,0 @@ -discard """ -targets: "c cpp js" -""" - -when defined(c) or defined(cpp): - {.emit:""" - const int TEST1 = 123; - #define TEST2 321 - """.} - -when defined(js): - {.emit:""" - const TEST1 = 123; - const TEST2 = 321; // JS doesn't have macros, so we just duplicate - """.} - -let - TEST0 = 1 - TEST1 {.importc, nodecl.}: cint - TEST2 {.importc, nodecl.}: cint - -doAssert TEST0 == 1 -doAssert TEST1 == 123 -doAssert TEST2 == 321 diff --git a/tests/let/timportc2.nim b/tests/let/timportc2.nim deleted file mode 100644 index 964305923..000000000 --- a/tests/let/timportc2.nim +++ /dev/null @@ -1,8 +0,0 @@ -discard """ - errormsg: "'let' symbol requires an initialization" - line: "7" -""" - -# Test that this still works when not annotated with importc -let test: cint -echo test diff --git a/tests/lexer/mlexerutils.nim b/tests/lexer/mlexerutils.nim deleted file mode 100644 index eae7a0006..000000000 --- a/tests/lexer/mlexerutils.nim +++ /dev/null @@ -1,9 +0,0 @@ -import macros - -macro lispReprStr*(a: untyped): untyped = newLit(a.lispRepr) - -macro assertAST*(expected: string, struct: untyped): untyped = - var ast = newLit(struct.treeRepr) - result = quote do: - if `ast` != `expected`: - doAssert false, "\nGot:\n" & `ast`.indent(2) & "\nExpected:\n" & `expected`.indent(2) \ No newline at end of file diff --git a/tests/lexer/tcustom_numeric_literals.nim b/tests/lexer/tcustom_numeric_literals.nim deleted file mode 100644 index 9c49d0c08..000000000 --- a/tests/lexer/tcustom_numeric_literals.nim +++ /dev/null @@ -1,185 +0,0 @@ -discard """ - targets: "c cpp js" -""" - -# Test tkStrNumLit - -import std/[macros, strutils] -import mlexerutils - -# AST checks - -assertAST dedent """ - StmtList - ProcDef - AccQuoted - Ident "\'" - Ident "wrap" - Empty - Empty - FormalParams - Ident "string" - IdentDefs - Ident "number" - Ident "string" - Empty - Empty - Empty - StmtList - Asgn - Ident "result" - Infix - Ident "&" - Infix - Ident "&" - StrLit "[[" - Ident "number" - StrLit "]]"""": - proc `'wrap`(number: string): string = - result = "[[" & number & "]]" - -assertAST dedent """ - StmtList - DotExpr - RStrLit "-38383839292839283928392839283928392839283.928493849385935898243e-50000" - Ident "\'wrap"""": - -38383839292839283928392839283928392839283.928493849385935898243e-50000'wrap - -proc `'wrap`(number: string): string = "[[" & number & "]]" -proc wrap2(number: string): string = "[[" & number & "]]" -doAssert lispReprStr(-1'wrap) == """(DotExpr (RStrLit "-1") (Ident "\'wrap"))""" - -template main = - block: # basic suffix usage - template `'twrap`(number: string): untyped = - number.`'wrap` - proc extraContext(): string = - 22.40'wrap - proc `*`(left, right: string): string = - result = left & "times" & right - proc `+`(left, right: string): string = - result = left & "plus" & right - - doAssert 1'wrap == "[[1]]" - doAssert -1'wrap == "[[-1]]": - "unable to resolve a negative integer-suffix pattern" - doAssert 12345.67890'wrap == "[[12345.67890]]" - doAssert 1'wrap*1'wrap == "[[1]]times[[1]]": - "unable to resolve an operator between two suffixed numeric literals" - doAssert 1'wrap+ -1'wrap == "[[1]]plus[[-1]]": # will generate a compiler warning about inconsistent spacing - "unable to resolve a negative suffixed numeric literal following an operator" - doAssert 1'wrap + -1'wrap == "[[1]]plus[[-1]]" - doAssert 1'twrap == "[[1]]" - doAssert extraContext() == "[[22.40]]": - "unable to return a suffixed numeric literal by an implicit return" - doAssert 0x5a3a'wrap == "[[0x5a3a]]" - doAssert 0o5732'wrap == "[[0o5732]]" - doAssert 0b0101111010101'wrap == "[[0b0101111010101]]" - doAssert -38383839292839283928392839283928392839283.928493849385935898243e-50000'wrap == "[[-38383839292839283928392839283928392839283.928493849385935898243e-50000]]" - doAssert 1234.56'wrap == "[[1234.56]]": - "unable to properly account for context with suffixed numeric literals" - - block: # verify that the i64, f32, etc builtin suffixes still parse correctly - const expectedF32: float32 = 123.125 - proc `'f9`(number: string): string = # proc starts with 'f' just like 'f32' - "[[" & number & "]]" - proc `'f32a`(number: string): string = # looks even more like 'f32' - "[[" & number & "]]" - proc `'d9`(number: string): string = # proc starts with 'd' just like the d suffix - "[[" & number & "]]" - proc `'i9`(number: string): string = # proc starts with 'i' just like 'i64' - "[[" & number & "]]" - proc `'u9`(number: string): string = # proc starts with 'u' just like 'u8' - "[[" & number & "]]" - - doAssert 123.125f32 == expectedF32: - "failing to support non-quoted legacy f32 floating point suffix" - doAssert 123.125'f32 == expectedF32 - doAssert 123.125e0'f32 == expectedF32 - doAssert 1234.56'wrap == 1234.56'f9 - doAssert 1234.56'wrap == 1234.56'f32a - doAssert 1234.56'wrap == 1234.56'd9 - doAssert 1234.56'wrap == 1234.56'i9 - doAssert 1234.56'wrap == 1234.56'u9 - doAssert lispReprStr(1234.56'u9) == """(DotExpr (RStrLit "1234.56") (Ident "\'u9"))""": - "failed to properly build AST for suffix that starts with u" - doAssert -128'i8 == (-128).int8 - - block: # case checks - doAssert 1E2 == 100: - "lexer not handling upper-case exponent" - doAssert 1.0E2 == 100.0 - doAssert 1e2 == 100 - doAssert 0xdeadBEEF'wrap == "[[0xdeadBEEF]]": - "lexer not maintaining original case" - doAssert 0.1E12'wrap == "[[0.1E12]]" - doAssert 0.0e12'wrap == "[[0.0e12]]" - doAssert 0.0e+12'wrap == "[[0.0e+12]]" - doAssert 0.0e-12'wrap == "[[0.0e-12]]" - doAssert 0e-12'wrap == "[[0e-12]]" - - block: # macro and template usage - template `'foo`(a: string): untyped = (a, 2) - doAssert -12'foo == ("-12", 2) - template `'fooplus`(a: string, b: int): untyped = (a, b) - doAssert -12'fooplus(2) == ("-12", 2) - template `'fooplusopt`(a: string, b: int = 99): untyped = (a, b) - doAssert -12'fooplusopt(2) == ("-12", 2) - doAssert -12'fooplusopt() == ("-12", 99) - doAssert -12'fooplusopt == ("-12", 99) - macro `'bar`(a: static string): untyped = newLit(a.repr) - doAssert -12'bar == "\"-12\"" - macro deb(a): untyped = newLit(a.repr) - doAssert deb(-12'bar) == "-12'bar" - - block: # bug 1 from https://github.com/nim-lang/Nim/pull/17020#issuecomment-803193947 - macro deb1(a): untyped = newLit a.repr - macro deb2(a): untyped = newLit a.lispRepr - doAssert deb1(-12'wrap) == "-12'wrap" - doAssert deb1(-12'nonexistent) == "-12'nonexistent" - doAssert deb2(-12'nonexistent) == """(DotExpr (RStrLit "-12") (Ident "\'nonexistent"))""" - when false: # xxx bug: - # this holds: - doAssert deb2(-12.wrap2) == """(DotExpr (IntLit -12) (Sym "wrap2"))""" - doAssert deb2(-12'wrap) == """(DotExpr (RStrLit "-12") (Sym "\'wrap"))""" - # but instead this should hold: - doAssert deb2(-12.wrap2) == """(DotExpr (IntLit -12) (Ident "wrap2"))""" - doAssert deb2(-12'wrap) == """(DotExpr (RStrLit "-12") (Ident "\'wrap"))""" - - block: # bug 2 from https://github.com/nim-lang/Nim/pull/17020#issuecomment-803193947 - template toSuf(`'suf`): untyped = - let x = -12'suf - x - doAssert toSuf(`'wrap`) == "[[-12]]" - - block: # bug 10 from https://github.com/nim-lang/Nim/pull/17020#issuecomment-803193947 - proc `myecho`(a: auto): auto = a - template fn1(): untyped = - let a = "abc" - -12'wrap - template fn2(): untyped = - `myecho` -12'wrap - template fn3(): untyped = - -12'wrap - doAssert fn1() == "[[-12]]" - doAssert fn2() == "[[-12]]" - doAssert fn3() == "[[-12]]" - - when false: # xxx this fails; bug 9 from https://github.com/nim-lang/Nim/pull/17020#issuecomment-803193947 - #[ - possible workaround: use `genAst` (https://github.com/nim-lang/Nim/pull/17426) and this: - let a3 = `'wrap3`("-128") - ]# - block: - macro metawrap(): untyped = - func wrap1(a: string): string = "{" & a & "}" - func `'wrap3`(a: string): string = "{" & a & "}" - result = quote do: - let a1 = wrap1"-128" - let a2 = -128'wrap3 - metawrap() - doAssert a1 == "{-128}" - doAssert a2 == "{-128}" - -static: main() -main() diff --git a/tests/lexer/tintegerliterals.nim b/tests/lexer/tintegerliterals.nim index fd401b71b..7420db144 100644 --- a/tests/lexer/tintegerliterals.nim +++ b/tests/lexer/tintegerliterals.nim @@ -1,9 +1,9 @@ # test the valid literals -doAssert 0b10 == 2 -doAssert 0B10 == 2 -doAssert 0x10 == 16 -doAssert 0X10 == 16 -doAssert 0o10 == 8 +assert 0b10 == 2 +assert 0B10 == 2 +assert 0x10 == 16 +assert 0X10 == 16 +assert 0o10 == 8 # the following is deprecated: -doAssert 0c10 == 8 -doAssert 0C10 == 8 +assert 0c10 == 8 +assert 0C10 == 8 diff --git a/tests/lexer/tlexerspaces.nim b/tests/lexer/tlexerspaces.nim deleted file mode 100644 index 14b16111d..000000000 --- a/tests/lexer/tlexerspaces.nim +++ /dev/null @@ -1,2 +0,0 @@ -discard 12 + 5 -discard 12 + 5 diff --git a/tests/lexer/tunary_minus.nim b/tests/lexer/tunary_minus.nim deleted file mode 100644 index 1641e918c..000000000 --- a/tests/lexer/tunary_minus.nim +++ /dev/null @@ -1,81 +0,0 @@ -discard """ - targets: "c cpp js" -""" - -# Test numeric literals and handling of minus symbol - -import std/[macros, strutils] - -import mlexerutils - -const one = 1 -const minusOne = `-`(one) - -# border cases that *should* generate compiler errors: -assertAST dedent """ - StmtList - Asgn - Ident "x" - Command - IntLit 4 - IntLit -1""": - x = 4 -1 -assertAST dedent """ - StmtList - VarSection - IdentDefs - Ident "x" - Ident "uint" - IntLit -1""": - var x: uint = -1 -template bad() = - x = 4 -1 -doAssert not compiles(bad()) - -template main = - block: # check when a minus (-) is a negative sign for a literal - doAssert -1 == minusOne: - "unable to parse a spaced-prefixed negative int" - doAssert lispReprStr(-1) == """(IntLit -1)""" - doAssert -1.0'f64 == minusOne.float64 - doAssert lispReprStr(-1.000'f64) == """(Float64Lit -1.0)""" - doAssert lispReprStr( -1.000'f64) == """(Float64Lit -1.0)""" - doAssert [-1].contains(minusOne): - "unable to handle negatives after square bracket" - doAssert lispReprStr([-1]) == """(Bracket (IntLit -1))""" - doAssert (-1, 2)[0] == minusOne: - "unable to handle negatives after parenthesis" - doAssert lispReprStr((-1, 2)) == """(TupleConstr (IntLit -1) (IntLit 2))""" - proc x(): int = - var a = 1;-1 # the -1 should act as the return value - doAssert x() == minusOne: - "unable to handle negatives after semi-colon" - - block: - doAssert -0b111 == -7 - doAssert -0xff == -255 - doAssert -128'i8 == (-128).int8 - doAssert $(-128'i8) == "-128" - doAssert -32768'i16 == int16.low - doAssert -2147483648'i32 == int32.low - when int.sizeof > 4: - doAssert -9223372036854775808 == int.low - when not defined(js): - doAssert -9223372036854775808 == int64.low - - block: # check when a minus (-) is an unary op - doAssert -one == minusOne: - "unable to a negative prior to identifier" - - block: # check when a minus (-) is a a subtraction op - doAssert 4-1 == 3: - "unable to handle subtraction sans surrounding spaces with a numeric literal" - doAssert 4-one == 3: - "unable to handle subtraction sans surrounding spaces with an identifier" - doAssert 4 - 1 == 3: - "unable to handle subtraction with surrounding spaces with a numeric literal" - doAssert 4 - one == 3: - "unable to handle subtraction with surrounding spaces with an identifier" - -static: main() -main() diff --git a/tests/lexer/tunicode_operators.nim b/tests/lexer/tunicode_operators.nim deleted file mode 100644 index 6ad40beab..000000000 --- a/tests/lexer/tunicode_operators.nim +++ /dev/null @@ -1,16 +0,0 @@ -#{.experimental: "unicodeOperators".} - -proc `⊙`(x, y: int): int = x * y -proc `⊙=`(x: var int, y: int) = x *= y - -proc `⊞++`(x, y: int): int = x + y - -const a = 9 - -var x = 45 -x ⊙= a⊞++4⊙3 - -var y = 45 -y *= 9 + 4 * 3 - -assert x == y diff --git a/tests/lookups/tbind_for_generics.nim b/tests/lookups/tbind_for_generics.nim deleted file mode 100644 index db5fbebbc..000000000 --- a/tests/lookups/tbind_for_generics.nim +++ /dev/null @@ -1,17 +0,0 @@ -discard """ - errormsg: "type mismatch: got " - line: 8 -""" -proc g[T](x: T) = - bind `+` - # because we bind `+` here, we must not find the `+` for 'Foo' below: - echo x + x - -type - Foo = object - a: int - -proc `+`(a, b: Foo): Foo = Foo(a: a.a+b.a) - -g(3) -g(Foo(a: 8)) diff --git a/tests/lookups/test.nim b/tests/lookups/test.nim index dfacaf5b5..97dfa131a 100644 --- a/tests/lookups/test.nim +++ b/tests/lookups/test.nim @@ -1,7 +1,7 @@ discard """ output: ''' - [Suite] memoization + ''' """ diff --git a/tests/lookups/tredef.nim b/tests/lookups/tredef.nim index 7c1df238e..8f1b38bd1 100644 --- a/tests/lookups/tredef.nim +++ b/tests/lookups/tredef.nim @@ -4,7 +4,7 @@ foo(1, "test") proc bar(a: int, b: string) = discard bar(1, "test") -template foo(a: int, b: string) {.redefine.} = bar(a, b) +template foo(a: int, b: string) = bar(a, b) foo(1, "test") block: diff --git a/tests/m14634.nim b/tests/m14634.nim deleted file mode 100644 index f19f02f0c..000000000 --- a/tests/m14634.nim +++ /dev/null @@ -1,48 +0,0 @@ -#[ -Tool to investigate underlying reasons for https://github.com/nim-lang/Nim/pull/14634 -nim r --threads:on -d:threadsafe tests/m14634.nim -]# - -when not defined(windows): - import std/selectors - - type TestData = object - s1, s2, s3: int - - proc timerNotificationTestImpl(data: var TestData) = - var selector = newSelector[int]() - let t0 = 5 - var timer = selector.registerTimer(t0, false, 0) - let t = 2000 - # values too close to `t0` cause the test to be flaky in CI on OSX+freebsd - # When running locally, t0=100, t=98 will succeed some of the time which indicates - # there is some lag involved. Note that the higher `t-t0` is, the less times - # the test fails. - var rc1 = selector.select(t) - var rc2 = selector.select(t) - doAssert len(rc1) <= 1 and len(rc2) <= 1 - data.s1 += ord(len(rc1) == 1) - data.s2 += ord(len(rc2) == 1) - selector.unregister(timer) - discard selector.select(0) - selector.registerTimer(t0, true, 0) - # same comment as above - var rc4 = selector.select(t) - let t2 = 100 - # this can't be too large as it'll actually wait that long: - # timer_notification_test.n * t2 - var rc5 = selector.select(t2) - doAssert len(rc4) + len(rc5) <= 1 - data.s3 += ord(len(rc4) + len(rc5) == 1) - doAssert(selector.isEmpty()) - selector.close() - - proc timerNotificationTest() = - var data: TestData - let n = 10 - for i in 0.. nnkPostfix(*, nnkIdent), forcing re-sem - result[0] = nnkPostfix.newTree(ident"*").add: - n.name.strVal.ident - -macro unexport(n: typed): untyped = - result = copyNimTree(n) - # turn nnkSym -> nnkIdent, forcing re-sem and dropping any exported-ness - # that might be present - result[0] = n.name.strVal.ident - -proc foo*() {.unexport.} = discard -proc bar() {.eexport.} = discard - -proc foooof*() {.unexport, eexport, unexport.} = discard -proc barrab() {.eexport, unexport, eexport.} = discard - -macro eexportMulti(n: typed): untyped = - # use the call version of `eexport` macro for one or more decls - result = copyNimTree(n) - for i in 0.. 2: - for j in i: - j - echo(x) - -block: - let y = @[@[1, 2], @[2, 4, 6]] - let x = collect(newSeq): - for i in y: - for j in i: - if i.len > 2: - j - echo(x) diff --git a/tests/macros/t14511.nim b/tests/macros/t14511.nim deleted file mode 100644 index f3b1e2894..000000000 --- a/tests/macros/t14511.nim +++ /dev/null @@ -1,54 +0,0 @@ -discard """ - output: "true\n(y: XInt, a: 5)\n(y: XString, b: \"abc\")" -""" - -import macros - -block TEST_1: - # https://github.com/nim-lang/Nim/issues/14511 - - template myPragma() {.pragma.} - - type - XType = enum - XInt, - XString, - XUnused - X = object - case y {.myPragma.}: XType - of XInt, XUnused: - a: int - else: # <-- Else case caused the "Error: index 1 not in 0 .. 0" error - b: string - - var x: X = X(y: XInt, a: 5) - echo x.y.hasCustomPragma(myPragma) - echo x - echo X(y: XString, b: "abc") - - -block TEST_2: - template myDevice(val: string) {.pragma.} - template myKey(val: string) {.pragma.} - template myMouse(val: string) {.pragma.} - - type - Device {.pure.} = enum Keyboard, Mouse - Key = enum Key1, Key2 - Mouse = enum Mouse1, Mouse2 - - type - Obj = object of RootObj - case device {.myDevice: "MyDevicePragmaStr".}: Device - of Device.Keyboard: - key {.myKey: "MyKeyPragmaStr".}: Key - else: # <-- Else case caused the "Error: index 1 not in 0 .. 0" error - mouse {.myMouse: "MyMousePragmaStr".}: Mouse - - var obj: Obj - assert obj.device.hasCustomPragma(myDevice) == true - assert obj.key.hasCustomPragma(myKey) == true - assert obj.mouse.hasCustomPragma(myMouse) == true - assert obj.device.getCustomPragmaVal(myDevice) == "MyDevicePragmaStr" - assert obj.key.getCustomPragmaVal(myKey) == "MyKeyPragmaStr" - assert obj.mouse.getCustomPragmaVal(myMouse) == "MyMousePragmaStr" \ No newline at end of file diff --git a/tests/macros/t14847.nim b/tests/macros/t14847.nim deleted file mode 100644 index 0e6d0dd2d..000000000 --- a/tests/macros/t14847.nim +++ /dev/null @@ -1,20 +0,0 @@ -discard """ - output: "98" -""" -import macros - -#bug #14847 -proc hello*(b: string) = - echo b - -macro dispatch(pro: typed, params: untyped): untyped = - var impl = pro.getImpl - let id = ident(pro.strVal & "_coverage") - impl[0] = id - let call = newCall(id, params) - - result = newStmtList() - result.add(impl) - result.add(call) - -dispatch(hello, "98") diff --git a/tests/macros/t16758.nim b/tests/macros/t16758.nim deleted file mode 100644 index 66b6d42c5..000000000 --- a/tests/macros/t16758.nim +++ /dev/null @@ -1,38 +0,0 @@ -discard """ -errormsg: "'blk.p(a)' has nil child at index 1" -action: reject -""" -import macros - -type BlockLiteral[T] = object - p: T - -proc p[T](a:int) = echo 1 -proc p[T](a:string) = echo "a" - -iterator arguments(formalParams: NimNode): NimNode = - var iParam = 0 - for i in 1 ..< formalParams.len: - let pp = formalParams[i] - for j in 0 .. pp.len - 3: - yield pp[j] - inc iParam - -macro implementInvoke(T: typedesc): untyped = - let t = getTypeImpl(T)[1] - - let call = newCall(newDotExpr(ident"blk", ident"p")) - let params = copyNimTree(t[0]) - result = newProc(ident"invoke", body = call) - # result[2] = newTree(nnkGenericParams,T) - for n in arguments(params): - call.add(n) - - params.insert(1, newIdentDefs(ident"blk", newTree(nnkBracketExpr, bindSym"BlockLiteral", T))) - result.params = params - -proc getInvoke(T: typedesc) = - implementInvoke(T) - - -getInvoke(proc(a: int)) diff --git a/tests/macros/t17836.nim b/tests/macros/t17836.nim deleted file mode 100644 index 2453637f5..000000000 --- a/tests/macros/t17836.nim +++ /dev/null @@ -1,15 +0,0 @@ -import macros - -# Ensure that `isNil` works in the typed macro context when pass procs. - -type - O = object - fn: proc(i: int): int - -var o: O - -macro typedBug(expr: typed) = - doAssert expr[1] != nil - doAssert not expr[1].isNil - -typedBug(o.fn) \ No newline at end of file diff --git a/tests/macros/t18203.nim b/tests/macros/t18203.nim deleted file mode 100644 index aae0a2690..000000000 --- a/tests/macros/t18203.nim +++ /dev/null @@ -1,15 +0,0 @@ -discard """ - matrix: "--hint:SuccessX:off --hint:Link:off --hint:Conf:off --hint:CC:off --hint:XDeclaredButNotUsed:on" - nimout: ''' -''' -nimoutFull: true -action: compile -""" - -# bug #18203 -import std/macros - -macro foo(x: typed) = newProc ident"bar" -proc bar() {.foo.} = raise -bar() - diff --git a/tests/macros/t18235.nim b/tests/macros/t18235.nim deleted file mode 100644 index ba5c48a24..000000000 --- a/tests/macros/t18235.nim +++ /dev/null @@ -1,18 +0,0 @@ -import m18235 - -# this must error out because it was never actually exported -doAssert(not declared(foo)) -doAssert not compiles(foo()) - -doAssert(not declared(foooof)) -doAssert not compiles(foooof()) - -doAssert(not declared(oof)) -doAssert not compiles(oof()) - -# this should have been exported just fine - -bar() -barrab() -rab() -baz() \ No newline at end of file diff --git a/tests/macros/t19766_20114.nim b/tests/macros/t19766_20114.nim deleted file mode 100644 index ac336f150..000000000 --- a/tests/macros/t19766_20114.nim +++ /dev/null @@ -1,16 +0,0 @@ -discard """ - action: compile - nimout: ''' -const - foo {.strdefine.} = "abc" -let hey {.tddd.} = 5 -''' -""" - -import macros - -template tddd {.pragma.} - -expandMacros: - const foo {.strdefine.} = "abc" - let hey {.tddd.} = 5 diff --git a/tests/macros/t20067.nim b/tests/macros/t20067.nim deleted file mode 100644 index 0ee3a4712..000000000 --- a/tests/macros/t20067.nim +++ /dev/null @@ -1,28 +0,0 @@ -discard """ - output: ''' -b.defaultVal = foo -$c.defaultVal = bar -''' -""" - -import macros - -# #18976 - -macro getString(identifier): string = - result = newLit($identifier) -doAssert getString(abc) == "abc" -doAssert getString(`a b c`) == "abc" - -# #20067 - -template defaultVal*(value : typed) {.pragma.} - -type A = ref object - b {.defaultVal: "foo".}: string - `$c` {.defaultVal: "bar".}: string - -let a = A(b: "a", `$c`: "b") - -echo "b.defaultVal = " & a.b.getCustomPragmaVal(defaultVal) -echo "$c.defaultVal = " & a.`$c`.getCustomPragmaVal(defaultVal) diff --git a/tests/macros/t7875.nim b/tests/macros/t7875.nim deleted file mode 100644 index 7b6e47b86..000000000 --- a/tests/macros/t7875.nim +++ /dev/null @@ -1,22 +0,0 @@ -discard """ - nimout: "var mysym`gensym0: MyType[float32]" - joinable: false -""" - -import macros - -type - MyType[T] = object - -# this is totally fine -var mysym: MyType[float32] - -macro foobar(): untyped = - let floatSym = bindSym"float32" - - result = quote do: - var mysym: MyType[`floatSym`] - - echo result.repr - -foobar() diff --git a/tests/macros/tastrepr.nim b/tests/macros/tastrepr.nim index 759ca55b5..e4271f019 100644 --- a/tests/macros/tastrepr.nim +++ b/tests/macros/tastrepr.nim @@ -1,6 +1,5 @@ discard """ output: ''' - var data = @[(1, "one"), (2, "two")] for (i, d) in pairs(data): discard diff --git a/tests/macros/tcasestmtmacro.nim b/tests/macros/tcasestmtmacro.nim deleted file mode 100644 index 32019a92a..000000000 --- a/tests/macros/tcasestmtmacro.nim +++ /dev/null @@ -1,33 +0,0 @@ -discard """ - output: ''' -yes -''' -""" - -import macros - -macro `case`(n: tuple): untyped = - result = newTree(nnkIfStmt) - let selector = n[0] - for i in 1 ..< n.len: - let it = n[i] - case it.kind - of nnkElse, nnkElifBranch, nnkElifExpr, nnkElseExpr: - result.add it - of nnkOfBranch: - for j in 0..it.len-2: - let cond = newCall("==", selector, it[j]) - result.add newTree(nnkElifBranch, cond, it[^1]) - else: - error "custom 'case' for tuple cannot handle this node", it - -var correct = false - -case ("foo", 78) -of ("foo", 78): - correct = true - echo "yes" -of ("bar", 88): echo "no" -else: discard - -doAssert correct diff --git a/tests/macros/tclosuremacro.nim b/tests/macros/tclosuremacro.nim index 44c2411a5..9f2137dec 100644 --- a/tests/macros/tclosuremacro.nim +++ b/tests/macros/tclosuremacro.nim @@ -1,6 +1,11 @@ discard """ - output: ''' + output: '''10 +10 +10 +3 +3 noReturn +6 calling mystuff yes calling mystuff @@ -8,7 +13,7 @@ yes ''' """ -import sugar, macros +import future, macros proc twoParams(x: (int, int) -> int): int = result = x(5, 5) @@ -25,23 +30,23 @@ proc noReturn(x: () -> void) = proc doWithOneAndTwo(f: (int, int) -> int): int = f(1,2) -doAssert twoParams(proc (a, b: auto): auto = a + b) == 10 -doAssert twoParams((x, y) => x + y) == 10 -doAssert oneParam(x => x+5) == 10 -doAssert noParams(() => 3) == 3 -doAssert doWithOneAndTwo((x, y) => x + y) == 3 +echo twoParams(proc (a, b: auto): auto = a + b) +echo twoParams((x, y) => x + y) + +echo oneParam(x => x+5) + +echo noParams(() => 3) + +echo doWithOneAndTwo((x, y) => x + y) noReturn((() -> void) => echo("noReturn")) proc pass2(f: (int, int) -> int): (int) -> int = ((x: int) -> int) => f(2, x) -doAssert pass2((x, y) => x + y)(4) == 6 +echo pass2((x, y) => x + y)(4) -const fun = (x, y: int) {.noSideEffect.} => x + y -doAssert typeof(fun) is (proc (x, y: int): int {.nimcall.}) -doAssert fun(3, 4) == 7 proc register(name: string; x: proc()) = echo "calling ", name @@ -67,14 +72,3 @@ macro m(x: untyped): untyped = m: proc mystuff() = echo "yes" - -const typedParamAndPragma = (x, y: int) -> int => x + y -doAssert typedParamAndPragma(1, 2) == 3 - -type - Bot = object - call: proc (): string {.noSideEffect.} - -var myBot = Bot() -myBot.call = () {.noSideEffect.} => "I'm a bot." -doAssert myBot.call() == "I'm a bot." diff --git a/tests/macros/tdumpast.nim b/tests/macros/tdumpast.nim index 484b3c2f3..b9d224ab8 100644 --- a/tests/macros/tdumpast.nim +++ b/tests/macros/tdumpast.nim @@ -2,69 +2,34 @@ import macros -block: - template plus(a, b: untyped): untyped {.dirty} = - a + b +template plus(a, b: untyped): untyped {.dirty} = + a + b - macro call(e: untyped): untyped = - result = newCall("foo", newStrLitNode("bar")) +macro call(e: untyped): untyped = + result = newCall("foo", newStrLitNode("bar")) - macro dumpAST(n: untyped): string = - var msg = "" - msg.add "lispRepr:\n" & n.lispRepr & "\n" - msg.add "treeRepr:\n" & n.treeRepr & "\n" +macro dumpAST(n: untyped): untyped = + # dump AST as a side-effect and return the inner node + let n = callsite() + echo n.lispRepr + echo n.treeRepr - var plusAst = getAst(plus(1, 2)) - msg.add "lispRepr:\n" & n.lispRepr & "\n" + var plusAst = getAst(plus(1, 2)) + echo plusAst.lispRepr - var callAst = getAst(call(4)) - msg.add "callAst.lispRepr:\n" & callAst.lispRepr & "\n" + var callAst = getAst(call(4)) + echo callAst.lispRepr - var e = parseExpr("foo(bar + baz)") - msg.add "e.lispRepr:\n" & e.lispRepr & "\n" - result = msg.newLit + var e = parseExpr("foo(bar + baz)") + echo e.lispRepr - let a = dumpAST: - proc add(x, y: int): int = - return x + y - const foo = 3 + result = n[1] - doAssert a == """ -lispRepr: -(StmtList (ProcDef (Ident "add") (Empty) (Empty) (FormalParams (Ident "int") (IdentDefs (Ident "x") (Ident "y") (Ident "int") (Empty))) (Empty) (Empty) (StmtList (ReturnStmt (Infix (Ident "+") (Ident "x") (Ident "y"))))) (ConstSection (ConstDef (Ident "foo") (Empty) (IntLit 3)))) -treeRepr: -StmtList - ProcDef - Ident "add" - Empty - Empty - FormalParams - Ident "int" - IdentDefs - Ident "x" - Ident "y" - Ident "int" - Empty - Empty - Empty - StmtList - ReturnStmt - Infix - Ident "+" - Ident "x" - Ident "y" - ConstSection - ConstDef - Ident "foo" - Empty - IntLit 3 -lispRepr: -(StmtList (ProcDef (Ident "add") (Empty) (Empty) (FormalParams (Ident "int") (IdentDefs (Ident "x") (Ident "y") (Ident "int") (Empty))) (Empty) (Empty) (StmtList (ReturnStmt (Infix (Ident "+") (Ident "x") (Ident "y"))))) (ConstSection (ConstDef (Ident "foo") (Empty) (IntLit 3)))) -callAst.lispRepr: -(Call (Ident "foo") (StrLit "bar")) -e.lispRepr: -(Call (Ident "foo") (Infix (Ident "+") (Ident "bar") (Ident "baz"))) -""" +dumpAST: + proc add(x, y: int): int = + return x + y + + proc sub(x, y: int): int = return x - y macro fun() = let n = quote do: @@ -83,79 +48,3 @@ macro fun3(): untyped = int | float | array | seq | object | ptr | pointer | float32 doAssert n.repr == "int | float | array | seq | object | ptr | pointer | float32", n.repr fun3() - -macro fun4() = - let n = quote do: - (a: 1) - doAssert n.repr == "(a: 1)", n.repr -fun4() - -# nkTupleConstr vs nkPar tests: -block: # lispRepr - macro lispRepr2(a: untyped): string = newLit a.lispRepr - - doAssert lispRepr2(()) == """(TupleConstr)""" - doAssert lispRepr2((a: 1)) == """(TupleConstr (ExprColonExpr (Ident "a") (IntLit 1)))""" - doAssert lispRepr2((a: 1, b: 2)) == """(TupleConstr (ExprColonExpr (Ident "a") (IntLit 1)) (ExprColonExpr (Ident "b") (IntLit 2)))""" - doAssert lispRepr2((1,)) == """(TupleConstr (IntLit 1))""" - doAssert lispRepr2((1, 2)) == """(TupleConstr (IntLit 1) (IntLit 2))""" - doAssert lispRepr2((1, 2, 3.0)) == """(TupleConstr (IntLit 1) (IntLit 2) (FloatLit 3.0))""" - doAssert lispRepr2((1)) == """(Par (IntLit 1))""" - doAssert lispRepr2((1+2)) == """(Par (Infix (Ident "+") (IntLit 1) (IntLit 2)))""" - -block: # repr - macro repr2(a: untyped): string = newLit a.repr - - doAssert repr2(()) == "()" - doAssert repr2((a: 1)) == "(a: 1)" - doAssert repr2((a: 1, b: 2)) == "(a: 1, b: 2)" - doAssert repr2((1,)) == "(1,)" - doAssert repr2((1, 2)) == "(1, 2)" - doAssert repr2((1, 2, 3.0)) == "(1, 2, 3.0)" - doAssert repr2((1)) == "(1)" - doAssert repr2((1+2)) == "(1 + 2)" - -block: # treeRepr - macro treeRepr2(a: untyped): string = newLit a.treeRepr - macro treeRepr3(a: typed): string = newLit a.treeRepr - - doAssert treeRepr2(1+1 == 2) == """ -Infix - Ident "==" - Infix - Ident "+" - IntLit 1 - IntLit 1 - IntLit 2""" - - proc baz() = discard - proc baz(a: int) = discard - proc baz(a: float) = discard - - doAssert treeRepr3(baz()) == """ -Call - Sym "baz"""" - - let a = treeRepr3(block: - proc bar(a: auto) = baz()) - doAssert a == """ -BlockStmt - Empty - ProcDef - Sym "bar" - Empty - GenericParams - Sym "a:type" - FormalParams - Empty - IdentDefs - Sym "a" - Sym "auto" - Empty - Empty - Bracket - Empty - Empty - StmtList - Call - OpenSymChoice 3 "baz"""" diff --git a/tests/macros/texpectIdent1.nim b/tests/macros/texpectIdent1.nim deleted file mode 100644 index 26e52afb5..000000000 --- a/tests/macros/texpectIdent1.nim +++ /dev/null @@ -1,18 +0,0 @@ -discard """ -errormsg: "Expected identifier to be `foo` here" -line: 18 -""" - -import macros - -macro testUntyped(arg: untyped): void = - arg.expectKind nnkStmtList - arg.expectLen 2 - arg[0].expectKind nnkCall - arg[0][0].expectIdent "foo" # must pass - arg[1].expectKind nnkCall - arg[1][0].expectIdent "foo" # must fail - -testUntyped: - foo(123) - bar(321) diff --git a/tests/macros/texpectIdent2.nim b/tests/macros/texpectIdent2.nim deleted file mode 100644 index 887a6ddc3..000000000 --- a/tests/macros/texpectIdent2.nim +++ /dev/null @@ -1,24 +0,0 @@ -discard """ -errormsg: "Expected identifier to be `foo` here" -line: 24 -""" - -import macros - -macro testTyped(arg: typed): void = - arg.expectKind nnkStmtList - arg.expectLen 2 - arg[0].expectKind nnkCall - arg[0][0].expectIdent "foo" # must pass - arg[1].expectKind nnkCall - arg[1][0].expectIdent "foo" # must fail - -proc foo(arg: int) = - discard - -proc bar(arg: int) = - discard - -testTyped: - foo(123) - bar(321) diff --git a/tests/macros/tforloop_macro1.nim b/tests/macros/tforloop_macro1.nim index a8f45c7ac..49918563d 100644 --- a/tests/macros/tforloop_macro1.nim +++ b/tests/macros/tforloop_macro1.nim @@ -12,7 +12,7 @@ discard """ """ import macros - +{.experimental: "forLoopMacros".} macro mymacro(): untyped = result = newLit([1, 2, 3]) diff --git a/tests/macros/tgetimpl.nim b/tests/macros/tgetimpl.nim index 66722a234..d231a4336 100644 --- a/tests/macros/tgetimpl.nim +++ b/tests/macros/tgetimpl.nim @@ -1,5 +1,5 @@ discard """ - nimout: '''foo = "muhaha" + nimout: '''"muhaha" proc poo(x, y: int) = let y = x echo ["poo"]''' @@ -65,36 +65,3 @@ macro check_gen_proc(ex: typed): (bool, bool) = let a = @[1,2,3] assert: check_gen_proc(len(a)) == (false, true) - -#--------------------------------------------------------------- -# issue #16110 - -macro check(x: type): untyped = - let z = getType(x) - let y = getImpl(z[1]) - let sym = if y[0].kind == nnkSym: y[0] else: y[0][0] - expectKind(z[1], nnkSym) - expectKind(sym, nnkSym) - expectKind(y[2], nnkObjectTy) - doAssert(sym == z[1]) - -type - TirePtr = ptr object - code: int - - TireRef* = ref object - code: int - - TireRef2* {.inheritable.} = ref object - code: int - - TireRef3* {.inheritable.} = object - code: int - -var z1: TirePtr -check(typeof(z1[])) -var z2: TireRef -check(typeof(z2[])) -var z3: TireRef2 -check(typeof(z3[])) -check(TireRef3) diff --git a/tests/macros/tgetraiseslist.nim b/tests/macros/tgetraiseslist.nim deleted file mode 100644 index 79694a66f..000000000 --- a/tests/macros/tgetraiseslist.nim +++ /dev/null @@ -1,29 +0,0 @@ -discard """ - nimout: '''##[ValueError, Gen[string]]## -%%[RootEffect]%% -true true''' -""" - -import macros -import std / effecttraits - -type - Gen[T] = object of CatchableError - x: T - -macro m(call: typed): untyped = - echo "##", repr getRaisesList(call[0]), "##" - echo "%%", repr getTagsList(call[0]), "%%" - echo isGcSafe(call[0]), " ", hasNoSideEffects(call[0]) - result = call - -proc gutenTag() {.tags: RootEffect.} = discard - -proc r(inp: int) = - if inp == 0: - raise newException(ValueError, "bah") - elif inp == 1: - raise newException(Gen[string], "bahB") - gutenTag() - -m r(2) diff --git a/tests/macros/tgettype.nim b/tests/macros/tgettype.nim index d91efe1fe..bd70a1c30 100644 --- a/tests/macros/tgettype.nim +++ b/tests/macros/tgettype.nim @@ -1,85 +1,29 @@ -import std/macros -import stdtest/testutils +discard """ +output: ''' +(ObjectTy (Empty) (Sym "Model") (RecList (Sym "name") (Sym "password"))) +(BracketExpr (Sym "typeDesc") (Sym "User")) +''' +""" +import macros -# getType +type + Model = object of RootObj + User = object of Model + name : string + password : string -block: - type - Model = object of RootObj - User = object of Model - name : string - password : string +macro testUser: string = + result = newLit(User.getType.lispRepr) - macro testUser: string = - result = newLit(User.getType.lispRepr) +macro testGeneric(T: typedesc[Model]): string= + result = newLit(T.getType.lispRepr) - macro testGeneric(T: typedesc[Model]): string= - result = newLit(T.getType.lispRepr) +echo testUser +echo User.testGeneric - doAssert testUser == """(ObjectTy (Empty) (Sym "Model") (RecList (Sym "name") (Sym "password")))""" - doAssert User.testGeneric == """(BracketExpr (Sym "typeDesc") (Sym "User"))""" +macro assertVoid(e: typed): untyped = + assert(getTypeInst(e).typeKind == ntyVoid) - macro assertVoid(e: typed): untyped = - assert(getTypeInst(e).typeKind == ntyVoid) +proc voidProc() = discard - proc voidProc() = discard - - assertVoid voidProc() - -block: - # refs #18220; not an actual solution (yet) but at least shows what's currently - # possible - - type Callable1[R, T, U] = concept fn - fn(default(T)) is R - fn is U - - # note that typetraits.arity doesn't work - macro arity(a: typed): int = - # number of params - # this is not production code! - let a2 = a.getType[1] # this used to crash nim, with: `vmdeps.nim(292, 25) `false`` - newLit a2.len - 1 - - type Callable2[R, T, U] = concept fn - fn(default(T)) is R - fn is U - arity(U) == 2 - - proc map1[T, R, U](a: T, fn: Callable1[R, T, U]): R = - let fn = U(fn) - # `cast[U](fn)` would also work; - # this is currently needed otherwise, sigmatch errors with: - # Error: attempting to call routine: 'fn' - # found 'fn' [param declared in tgettype.nim(53, 28)] - # this can be fixed in future work - fn(a) - - proc map2[T, R, U](a: T, fn: Callable2[R, T, U]): R = - let fn = U(fn) - fn(a) - - proc fn1(a: int, a2 = 'x'): string = $(a, a2, "fn1") - proc fn2(a: int, a2 = "zoo"): string = $(a, a2, "fn2") - proc fn3(a: int, a2 = "zoo2"): string = $(a, a2, "fn3") - proc fn4(a: int): string {.inline.} = $(a, "fn4") - proc fn5(a: int): string = $(a, "fn5") - - assertAll: - # Callable1 - 1.map1(fn1) == """(1, 'x', "fn1")""" - 1.map1(fn2) == """(1, "zoo", "fn2")""" - 1.map1(fn3) == """(1, "zoo", "fn3")""" - # fn3's optional param is not honored, because fn3 and fn2 yield same - # generic instantiation; this is a caveat with this approach - # There are several possible ways to improve things in future work. - 1.map1(fn4) == """(1, "fn4")""" - 1.map1(fn5) == """(1, "fn5")""" - - # Callable2; prevents passing procs with optional params to avoid above - # mentioned caveat, but more restrictive - not compiles(1.map2(fn1)) - not compiles(1.map2(fn2)) - not compiles(1.map2(fn3)) - 1.map2(fn4) == """(1, "fn4")""" - 1.map2(fn5) == """(1, "fn5")""" +assertVoid voidProc() diff --git a/tests/macros/tgettypeinst.nim b/tests/macros/tgettypeinst.nim index e722f14aa..2f9557160 100644 --- a/tests/macros/tgettypeinst.nim +++ b/tests/macros/tgettypeinst.nim @@ -191,14 +191,14 @@ template myAttr3() {.pragma.} template serializationKey(key: string) {.pragma.} type - MyObj {.packed,myAttr,serializationKey: "one".} = object + MyObj = object {.packed,myAttr,serializationKey: "one".} myField {.myAttr2,serializationKey: "two".}: int myField2 {.myAttr3,serializationKey: "three".}: float # field pragmas not currently supported test(MyObj): type - _ {.packed,myAttr,serializationKey: "one".} = object + _ = object {.packed,myAttr,serializationKey: "one".} myField: int myField2: float diff --git a/tests/macros/tmacro2.nim b/tests/macros/tmacro2.nim index 1ad63ec8c..72972c0c1 100644 --- a/tests/macros/tmacro2.nim +++ b/tests/macros/tmacro2.nim @@ -26,11 +26,3 @@ const t = mac("HEllo World") echo s, " ", t -#----------------------------------------------------------------------------- -# issue #15326 -macro m(n:typed):auto = - result = n - -proc f[T](x:T): T {.m.} = x - -discard f(3) \ No newline at end of file diff --git a/tests/macros/tmacro6.nim b/tests/macros/tmacro6.nim index c65d34b6d..0b6423100 100644 --- a/tests/macros/tmacro6.nim +++ b/tests/macros/tmacro6.nim @@ -1,22 +1,22 @@ discard """ -errormsg: "expression '123' is of type 'int literal(123)' and has to be used (or discarded)" +errormsg: "expression '123' is of type 'int literal(123)' and has to be discarded" line: 71 """ import macros -proc foo(a, b, c: int): int = +proc foo(a,b,c: int): int = result += a result += b result += c -macro bar(a, b, c: int): int = +macro bar(a,b,c: int): int = result = newCall(ident"echo") result.add a result.add b result.add c -macro baz(a, b, c: int): int = +macro baz(a,b,c: int): int = let stmt = nnkStmtListExpr.newTree() stmt.add newCall(ident"echo", a) stmt.add newCall(ident"echo", b) @@ -26,7 +26,7 @@ macro baz(a, b, c: int): int = # test no result type with explicit return -macro baz2(a, b, c: int) = +macro baz2(a,b,c: int) = let stmt = nnkStmtListExpr.newTree() stmt.add newCall(ident"echo", a) stmt.add newCall(ident"echo", b) @@ -35,7 +35,7 @@ macro baz2(a, b, c: int) = # test explicit void type with explicit return -macro baz3(a, b, c: int): void = +macro baz3(a,b,c: int): void = let stmt = nnkStmtListExpr.newTree() stmt.add newCall(ident"echo", a) stmt.add newCall(ident"echo", b) @@ -44,7 +44,7 @@ macro baz3(a, b, c: int): void = # test no result type with result variable -macro baz4(a, b, c: int) = +macro baz4(a,b,c: int) = result = nnkStmtListExpr.newTree() result.add newCall(ident"echo", a) result.add newCall(ident"echo", b) @@ -52,7 +52,7 @@ macro baz4(a, b, c: int) = # test explicit void type with result variable -macro baz5(a, b, c: int): void = +macro baz5(a,b,c: int): void = let result = nnkStmtListExpr.newTree() result.add newCall(ident"echo", a) result.add newCall(ident"echo", b) diff --git a/tests/macros/tmacrogensym.nim b/tests/macros/tmacrogensym.nim index 7c0d75f82..15a08c574 100644 --- a/tests/macros/tmacrogensym.nim +++ b/tests/macros/tmacrogensym.nim @@ -1,6 +1,6 @@ import nativesockets, asyncdispatch, macros var p = newDispatcher() -var sock = createAsyncNativeSocket() +var sock = newAsyncNativeSocket() proc convertReturns(node, retFutureSym: NimNode): NimNode {.compileTime.} = case node.kind @@ -27,7 +27,7 @@ macro async2(prc: untyped): untyped = # -> iterator nameIter(): FutureBase {.closure.} = # Changing this line to: newIdentNode($prc[0].ident & "Iter") # will make it work. - var iteratorNameSym = genSym(nskIterator, $prc[0] & "Iter") + var iteratorNameSym = genSym(nskIterator, $prc[0].ident & "Iter") assert iteratorNameSym.symKind == nskIterator #var iteratorNameSym = newIdentNode($prc[0].ident & "Iter") var procBody = prc[6].convertReturns(retFutureSym) @@ -39,7 +39,7 @@ macro async2(prc: untyped): untyped = # -> var nameIterVar = nameIter # -> var first = nameIterVar() - var varNameIterSym = newIdentNode($prc[0] & "IterVar") #genSym(nskVar, $prc[0].ident & "IterVar") + var varNameIterSym = newIdentNode($prc[0].ident & "IterVar") #genSym(nskVar, $prc[0].ident & "IterVar") var varNameIter = newVarStmt(varNameIterSym, iteratorNameSym) outerProcBody.add varNameIter var varFirstSym = genSym(nskVar, "first") @@ -52,7 +52,7 @@ macro async2(prc: untyped): untyped = # Remove the 'closure' pragma. for i in 0 ..< result[4].len: - if result[4][i] == newIdentNode("async"): + if result[4][i].ident == !"async": result[4].del(i) result[6] = outerProcBody diff --git a/tests/macros/tmacrogetimpl.nim b/tests/macros/tmacrogetimpl.nim deleted file mode 100644 index 1d996ff29..000000000 --- a/tests/macros/tmacrogetimpl.nim +++ /dev/null @@ -1,31 +0,0 @@ -import macros - -# bug #5034 - -macro copyImpl(srsProc: typed, toSym: untyped) = - result = copyNimTree(getImplTransformed(srsProc)) - result[0] = ident $toSym.toStrLit() - -proc foo1(x: float, one: bool = true): float = - if one: - return 1'f - result = x - -proc bar1(what: string): string = - ## be a little more adversarial with `skResult` - proc buzz: string = - result = "lightyear" - if what == "buzz": - result = "buzz " & buzz() - else: - result = what - return result - -copyImpl(foo1, foo2) -doAssert foo1(1'f) == 1.0 -doAssert foo2(10.0, false) == 10.0 -doAssert foo2(10.0) == 1.0 - -copyImpl(bar1, bar2) -doAssert bar1("buzz") == "buzz lightyear" -doAssert bar1("macros") == "macros" diff --git a/tests/macros/tmacros1.nim b/tests/macros/tmacros1.nim index c588ff7e6..53af4287c 100644 --- a/tests/macros/tmacros1.nim +++ b/tests/macros/tmacros1.nim @@ -60,22 +60,3 @@ macro foo(t: static Tuple): untyped = doAssert t.b == 12345 foo((a: "foo", b: 12345)) - - -# bug #16307 - -macro bug(x: untyped): string = - newLit repr(x) - -let res = bug: - block: - ## one - ## two - ## three - -doAssert res == """ - -block: - ## one - ## two - ## three""" diff --git a/tests/macros/tmacros_issues.nim b/tests/macros/tmacros_issues.nim index a81c51658..df385c445 100644 --- a/tests/macros/tmacros_issues.nim +++ b/tests/macros/tmacros_issues.nim @@ -19,8 +19,6 @@ nil 42 false true -@[i0, i1, i2, i3, i4] -@[tmp, tmp, tmp, tmp, tmp] ''' output: ''' @@ -29,18 +27,6 @@ array[0 .. 100, int] 10 test 0o377'i8 -0o000000000755'i32 -1 -2 -3 -foo1 -foo2 -foo3 -true -false -true -false -1.0 ''' """ @@ -64,7 +50,7 @@ block t7723: block t8706: macro varargsLen(args:varargs[untyped]): untyped = - doAssert args.kind == nnkArgList + doAssert args.kind == nnkArglist doAssert args.len == 0 result = newLit(args.len) @@ -258,264 +244,3 @@ macro toRendererBug(n): untyped = result = newLit repr(n) echo toRendererBug(0o377'i8) -echo toRendererBug(0o755'i32) - -# bug #12129 -macro foobar() = - var loopVars = newSeq[NimNode](5) - for i, sym in loopVars.mpairs(): - sym = ident("i" & $i) - echo loopVars - for sym in loopVars.mitems(): - sym = ident("tmp") - echo loopVars - -foobar() - - -# bug #13253 -import macros - -type - FooBar = object - a: seq[int] - -macro genFoobar(a: static FooBar): untyped = - result = newStmtList() - for b in a.a: - result.add(newCall(bindSym"echo", newLit b)) - -proc foobar(a: static FooBar) = - genFoobar(a) # removing this make it work - for b in a.a: - echo "foo" & $b - -proc main() = - const a: seq[int] = @[1, 2,3] - # Error: type mismatch: got but expected 'seq[int]' - const fb = Foobar(a: a) - foobar(fb) -main() - -# bug #13484 - -proc defForward(id, nid: NimNode): NimNode = - result = newProc(id, @[newIdentNode("bool"), newIdentDefs(nid, newIdentNode("int"))], body=newEmptyNode()) - -proc defEven(evenid, oddid, nid: NimNode): NimNode = - result = quote do: - proc `evenid`(`nid`: int): bool = - if `nid` == 0: - return true - else: - return `oddid`(`nid` - 1) - -proc defOdd(evenid, oddid, nid: NimNode): NimNode = - result = quote do: - proc `oddid`(`nid`: int): bool = - if `nid` == 0: - return false - else: - return `evenid`(`nid` - 1) - -proc callNode(funid, param: NimNode): NimNode = - result = quote do: - `funid`(`param`) - -macro testEvenOdd3(): untyped = - let - evenid = newIdentNode("even3") - oddid = newIdentNode("odd3") - nid = newIdentNode("n") - oddForward = defForward(oddid, nid) - even = defEven(evenid, oddid, nid) - odd = defOdd(evenid, oddid, nid) - callEven = callNode(evenid, newLit(42)) - callOdd = callNode(oddid, newLit(42)) - result = quote do: - `oddForward` - `even` - `odd` - echo `callEven` - echo `callOdd` - -macro testEvenOdd4(): untyped = - let - evenid = newIdentNode("even4") - oddid = newIdentNode("odd4") - nid = newIdentNode("n") - oddForward = defForward(oddid, nid) - even = defEven(evenid, oddid, nid) - odd = defOdd(evenid, oddid, nid) - callEven = callNode(evenid, newLit(42)) - callOdd = callNode(oddid, newLit(42)) - # rewrite the body of proc node. - oddForward[6] = newStmtList() - result = quote do: - `oddForward` - `even` - `odd` - echo `callEven` - echo `callOdd` - -macro testEvenOdd5(): untyped = - let - evenid = genSym(nskProc, "even5") - oddid = genSym(nskProc, "odd5") - nid = newIdentNode("n") - oddForward = defForward(oddid, nid) - even = defEven(evenid, oddid, nid) - odd = defOdd(evenid, oddid, nid) - callEven = callNode(evenid, newLit(42)) - callOdd = callNode(oddid, newLit(42)) - result = quote do: - `oddForward` - `even` - `odd` - echo `callEven` - echo `callOdd` - -macro testEvenOdd6(): untyped = - let - evenid = genSym(nskProc, "even6") - oddid = genSym(nskProc, "odd6") - nid = newIdentNode("n") - oddForward = defForward(oddid, nid) - even = defEven(evenid, oddid, nid) - odd = defOdd(evenid, oddid, nid) - callEven = callNode(evenid, newLit(42)) - callOdd = callNode(oddid, newLit(42)) - # rewrite the body of proc node. - oddForward[6] = newStmtList() - result = quote do: - `oddForward` - `even` - `odd` - echo `callEven` - echo `callOdd` - -# it works -testEvenOdd3() - -# it causes an error (redefinition of odd4), which is correct -assert not compiles testEvenOdd4() - -# it caused an error (still forwarded: odd5) -testEvenOdd5() - -# it works, because the forward decl and definition share the symbol and the compiler is forgiving here -#testEvenOdd6() #Don't test it though, the compiler may become more strict in the future - -# bug #15385 -var captured_funcs {.compileTime.}: seq[NimNode] = @[] - -macro aad*(fns: varargs[typed]): typed = - result = newStmtList() - for fn in fns: - captured_funcs.add fn[0] - result.add fn - -func exp*(x: float): float ## get different error if you remove forward declaration - -func exp*(x: float): float {.aad.} = - var x1 = min(max(x, -708.4), 709.8) - var result: float ## looks weird because it is taken from template expansion - result = x1 + 1.0 - result - -template check_accuracy(f: untyped, rng: Slice[float], n: int, verbose = false): auto = - - proc check_accuracy: tuple[avg_ulp: float, max_ulp: int] {.gensym.} = - let k = (rng.b - rng.a) / (float) n - var - res, x: float - i, max_ulp = 0 - avg_ulp = 0.0 - - x = rng.a - while (i < n): - res = f(x) - i.inc - x = x + 0.001 - (avg_ulp, max_ulp) - check_accuracy() - -discard check_accuracy(exp, -730.0..709.4, 4) - -# And without forward decl -macro aad2*(fns: varargs[typed]): typed = - result = newStmtList() - for fn in fns: - captured_funcs.add fn[0] - result.add fn - -func exp2*(x: float): float {.aad2.} = - var x1 = min(max(x, -708.4), 709.8) - var result: float ## looks weird because it is taken from template expansion - result = x1 + 1.0 - result - -template check_accuracy2(f: untyped, rng: Slice[float], n: int, verbose = false): auto = - - proc check_accuracy2: tuple[avg_ulp: float, max_ulp: int] {.gensym.} = - let k = (rng.b - rng.a) / (float) n - var - res, x: float - i, max_ulp = 0 - avg_ulp = 0.0 - - x = rng.a - while (i < n): - res = f(x) - i.inc - x = x + 0.001 - (avg_ulp, max_ulp) - check_accuracy2() - -discard check_accuracy2(exp2, -730.0..709.4, 4) - -# And minimized: -macro aadMin(fn: typed): typed = fn - -func expMin: float - -func expMin: float {.aadMin.} = 1 - -echo expMin() - - -# doubly-typed forward decls -macro noop(x: typed) = x -noop: - proc cally() = discard - -cally() - -noop: - proc barry() - -proc barry() = discard - -# some more: -proc barry2() {.noop.} -proc barry2() = discard - -proc barry3() {.noop.} -proc barry3() {.noop.} = discard - - -# issue #15389 -block double_sem_for_procs: - - macro aad(fns: varargs[typed]): typed = - result = newStmtList() - for fn in fns: - result.add fn - - func exp(x: float): float {.aad.} = - var x1 = min(max(x, -708.4), 709.8) - if x1 > 0.0: - return x1 + 1.0 - result = 10.0 - - discard exp(5.0) diff --git a/tests/macros/tmacros_various.nim b/tests/macros/tmacros_various.nim index 2446912ea..3991a5e30 100644 --- a/tests/macros/tmacros_various.nim +++ b/tests/macros/tmacros_various.nim @@ -22,9 +22,6 @@ a[1]: 45 x: some string ([("key", "val"), ("keyB", "2")], [("val", "key"), ("2", "keyB")]) ([("key", "val"), ("keyB", "2")], [("val", "key"), ("2", "keyB")]) -0 -0 -0 ''' """ @@ -91,7 +88,7 @@ block tlexerex: -block tcopylineinfo: +block tlineinfo: # issue #5617, feature request type Test = object @@ -103,27 +100,6 @@ block tcopylineinfo: var z = mixer(Test) doAssert z -block tsetgetlineinfo: - # issue #21098, feature request - type Test = object - - macro mixer1(n: typed): untyped = - let x = newIdentNode("echo") - var lineInfo = n.lineInfoObj - x.setLineInfo lineInfo - result = newLit(x.lineInfo == n.lineInfo) - - macro mixer2(n: typed): untyped = - let x = newIdentNode("echo") - var lineInfo = n.lineInfoObj - lineInfo.line += 1 - x.setLineInfo lineInfo - result = newLit(x.lineInfo != n.lineInfo) - - doAssert mixer1(Test) - - doAssert mixer2(Test) - block tdebugstmt: @@ -218,143 +194,3 @@ static: doAssert(v == a) echo "macrocache ok" - -block tupleNewLitTests: - macro t(): untyped = - result = newLit (1, "foo", (), (1,), (a1: 'x', a2: @["ba"])) - doAssert $t() == """(1, "foo", (), (1,), (a1: 'x', a2: @["ba"]))""" - # this `$` test is needed because tuple equality doesn't distinguish - # between named vs unnamed tuples - doAssert t() == (1, "foo", (), (1, ), (a1: 'x', a2: @["ba"])) - -from strutils import contains -block getImplTransformed: - macro bar(a: typed): string = - # newLit a.getImpl.repr # this would be before code transformation - let b = a.getImplTransformed - newLit b.repr - template toExpand() = - for ai in 0..2: echo ai - proc baz(a=1): int = - defer: discard - toExpand() - 12 - const code = bar(baz) - # sanity check: - doAssert "finally" in code # `defer` is lowered to try/finally - doAssert "while" in code # `for` is lowered to `while` - doAssert "toExpand" notin code - # template is expanded (but that would already be the case with - # `a.getImpl.repr`, unlike the other transformations mentioned above - - -# test macro resemming -macro makeVar(): untyped = - quote: - var tensorY {.inject.}: int - -macro noop(a: typed): untyped = - a - -noop: - makeVar -echo tensorY - -macro xbenchmark(body: typed): untyped = - result = body - -xbenchmark: - proc fastSHA(inputtest: string) = - discard inputtest - fastSHA("hey") - - -block: # bug #13511 - type - Builder = ref object - components: seq[Component] - Component = object - - proc add(builder: var Builder, component: Component) {.compileTime.} = - builder.components.add(component) - - macro debugAst(arg: typed): untyped = - ## just for debugging purpose. - discard arg.treeRepr - return arg - - static: - var component = Component() - var builder = Builder() - - template foo(): untyped = - ## WAS: this doc comment causes compilation failure. - builder - - debugAst: - add(foo(), component) - -block: # bug #15118 - macro flop(name: static string) = - let id = genSym(nskType, "env") - let r = - nnkStmtList.newTree( - nnkTypeSection.newTree( - nnkTypeDef.newTree( - id, - newEmptyNode(), - nnkRefTy.newTree( - nnkObjectTy.newTree( - newEmptyNode(), - newEmptyNode(), - nnkRecList.newTree( - nnkIdentDefs.newTree( - newIdentNode(name), - newIdentNode("int"), - newEmptyNode() - ) - ) - ) - ) - ) - ), - - # var f: T - - nnkVarSection.newTree( - nnkIdentDefs.newTree( - newIdentNode("f"), - id, - newEmptyNode() - ) - ), - - # echo f.a - nnkCommand.newTree( - newIdentNode("new"), - newIdentNode("f") - ), - - nnkCommand.newTree( - newIdentNode("echo"), - nnkDotExpr.newTree( - newIdentNode("f"), - newIdentNode(name) - ) - ) - ) - r - - - block: - flop("a") - - block: - flop("b") - -static: - block: - const containsTable = CacheTable"containsTable" - doAssert "foo" notin containsTable - containsTable["foo"] = newLit 42 - doAssert "foo" in containsTable diff --git a/tests/macros/tmacrostmt.nim b/tests/macros/tmacrostmt.nim index 79be5f764..56a0bf840 100644 --- a/tests/macros/tmacrostmt.nim +++ b/tests/macros/tmacrostmt.nim @@ -100,30 +100,18 @@ proc fn4(x: int): int = proc fn5(a, b: float): float = result = - a * a / (b * b) -proc `{}`(x: seq[float], i: int, j: int): float = - x[i + 0 * j] - -proc `{}=`(x: var seq[float], i: int, val: float) = - x[i] = val - -proc fn6() = - var a = @[1.0, 2.0] - let z = a{0, 1} - a{2} = 5.0 - - #------------------------------------ # bug #10807 proc fn_unsafeaddr(x: int): int = cast[int](unsafeAddr(x)) static: + echo fn_unsafeaddr.repr_to_string let fn1s = "proc fn1(x, y: int): int =\n result = 2 * (x + y)\n" let fn2s = "proc fn2(x, y: float): float =\n result = (y + 2 * x) / (x - y)\n" let fn3s = "proc fn3(x, y: int): bool =\n result = ((x and 3) div 4 or x mod (y xor -1)) == 0 or not contains([1, 2], y)\n" let fn4s = "proc fn4(x: int): int =\n if x mod 2 == 0:\n return x + 2\n else:\n return 0\n" let fn5s = "proc fn5(a, b: float): float =\n result = -a * a / (b * b)\n" - let fn6s = "proc fn6() =\n var a = @[1.0, 2.0]\n let z = a{0, 1}\n a{2} = 5.0\n" let fnAddr = "proc fn_unsafeaddr(x: int): int =\n result = cast[int](unsafeAddr(x))\n" doAssert fn1.repr_to_string == fn1s @@ -131,7 +119,6 @@ static: doAssert fn3.repr_to_string == fn3s doAssert fn4.repr_to_string == fn4s doAssert fn5.repr_to_string == fn5s - doAssert fn6.repr_to_string == fn6s doAssert fn_unsafeaddr.repr_to_string == fnAddr #------------------------------------ diff --git a/tests/macros/tmacrotypes.nim b/tests/macros/tmacrotypes.nim index 43819c81d..8cf93a593 100644 --- a/tests/macros/tmacrotypes.nim +++ b/tests/macros/tmacrotypes.nim @@ -4,50 +4,20 @@ void; ntyVoid; void; void int; ntyInt; int; int proc (); ntyProc; proc[void]; proc () voidProc; ntyProc; proc[void]; proc () -listing fields for ObjType -a: string -b: int -listing fields for ObjRef -skipping ref type -a: string -b: int -listing fields for RefType -skipping ref type -a: int -b: float -listing fields for typeof(a) -skipping ref type -a: string -b: int -listing fields for typeof(b) -skipping ref type -a: string -b: int -listing fields for typeof(c) -skipping ref type -a: int -b: float -listing fields for typeof(x) -a: string -b: int -listing fields for typeof(x) -a: int -b: float typeDesc[range[1 .. 5]]; ntyTypeDesc; typeDesc[range[1, 5]]; typeDesc[range[1 .. 5]] typeDesc[range]; ntyTypeDesc; typeDesc[range[T]]; typeDesc[range]''' """ -import macros, typetraits +import macros macro checkType(ex: typed): untyped = echo ex.getTypeInst.repr, "; ", ex.typeKind, "; ", ex.getType.repr, "; ", ex.getTypeImpl.repr macro checkProcType(fn: typed): untyped = - if fn.kind == nnkProcDef: - result = fn let fn_sym = if fn.kind == nnkProcDef: fn[0] else: fn echo fn_sym, "; ", fn_sym.typeKind, "; ", fn_sym.getType.repr, "; ", fn_sym.getTypeImpl.repr + proc voidProc = echo "hello" proc intProc(a: int, b: float): int {.checkProcType.} = 10 @@ -56,58 +26,6 @@ checkType(intProc(10, 20.0)) checkType(voidProc) checkProcType(voidProc) -macro listFields(T: typed) = - echo "listing fields for ", repr(T) - let inputExprType = getType(T) - - var objType = inputExprType[1] - if objType.kind == nnkBracketExpr and objType.len > 1: - if ((objType[0].kind == nnkRefTy) or - (objType[0].kind == nnkSym and eqIdent(objType[0], "ref"))): - echo "skipping ref type" - objType = objType[1] - - let typeAst = objType.getImpl - - var objectDef = typeAst[2] - if objectDef.kind == nnkRefTy: - objectDef = objectDef[0] - - let recList = objectDef[2] - for rec in recList: - echo $rec[0], ": ", $rec[1] - -type - ObjType* = object of RootObj - a: string - b: int - - ObjRef = ref ObjType - - RefType* = ref object of RootObj - a: int - b: float - -listFields ObjType -listFields ObjRef -listFields RefType - -let - a = new ObjType - b = new ObjRef - c = new RefType - -listFields typeOf(a) -listFields typeOf(b) -listFields typeOf(c) - -proc genericProc(x: object) = - listFields typeOf(x) - -genericProc a[] -genericProc b[] -genericProc c[] - # bug #10548 block: var c {.compileTime.} = 0 diff --git a/tests/macros/tmemit.nim b/tests/macros/tmemit.nim index 6c9f9f935..06ab8a1e2 100644 --- a/tests/macros/tmemit.nim +++ b/tests/macros/tmemit.nim @@ -1,5 +1,6 @@ discard """ output: ''' +HELLO WORLD c_func 12 ''' @@ -7,6 +8,8 @@ c_func import macros, strutils +emit("echo " & '"' & "hello world".toUpperAscii & '"') + # bug #1025 macro foo(icname): untyped = diff --git a/tests/macros/tparsefile.nim b/tests/macros/tparsefile.nim deleted file mode 100644 index a41223f80..000000000 --- a/tests/macros/tparsefile.nim +++ /dev/null @@ -1,11 +0,0 @@ -import macros - -static: - let fn = "mparsefile.nim" - var raised = false - try: - discard parseStmt(staticRead(fn), filename = fn) - except ValueError as e: - raised = true - doAssert e.msg == "mparsefile.nim(4, 1) Error: invalid indentation" - doAssert raised diff --git a/tests/macros/tprochelpers.nim b/tests/macros/tprochelpers.nim deleted file mode 100644 index d95a2ced8..000000000 --- a/tests/macros/tprochelpers.nim +++ /dev/null @@ -1,22 +0,0 @@ -import std/macros -import stdtest/testutils - -macro test1(prc: untyped): untyped = - assertAll: - prc.params.len == 2 - prc.params[1].len == 4 - prc.pragma.len == 2 - - prc.params = nnkFormalParams.newTree( - ident("int") - ) - prc.pragma = newEmptyNode() - - assertAll: - prc.params.len == 1 - prc.pragma.len == 0 - prc - -proc test(a, b: int): int {.gcsafe, raises: [], test1.} = 5 - -type hello = proc(a, b: int): int {.gcsafe, raises: [], test1.} diff --git a/tests/macros/tstaticparamsmacro.nim b/tests/macros/tstaticparamsmacro.nim index 2632ca730..8bd653920 100644 --- a/tests/macros/tstaticparamsmacro.nim +++ b/tests/macros/tstaticparamsmacro.nim @@ -7,9 +7,9 @@ numbers 11 22 AST a -@[(c: 11, d: 22), (c: 33, d: 44)] +[(11, 22), (33, 44)] AST b -(e: @[55, 66], f: @[77, 88]) +([55, 66], [77, 88]) 55 10 20Test diff --git a/tests/macros/tstructuredlogging.nim b/tests/macros/tstructuredlogging.nim index 5e4fdea3f..05bb52a40 100644 --- a/tests/macros/tstructuredlogging.nim +++ b/tests/macros/tstructuredlogging.nim @@ -66,7 +66,7 @@ macro mergeScopes(scopeHolders: typed, newBindings: untyped): untyped = newScopeDefinition.add newAssignment(newIdentNode(k), v) result = quote: - template scopeHolder {.redefine.} = `newScopeDefinition` + template scopeHolder = `newScopeDefinition` template scope(newBindings: untyped) {.dirty.} = mergeScopes(bindSym"scopeHolder", newBindings) diff --git a/tests/macros/ttypenodes.nim b/tests/macros/ttypenodes.nim deleted file mode 100644 index 233ea9780..000000000 --- a/tests/macros/ttypenodes.nim +++ /dev/null @@ -1,16 +0,0 @@ -import macros - -macro makeEnum(): untyped = - newTree(nnkEnumTy, newEmptyNode(), ident"a", ident"b", ident"c") - -macro makeObject(): untyped = - newTree(nnkObjectTy, newEmptyNode(), newEmptyNode(), newTree(nnkRecList, - newTree(nnkIdentDefs, ident"x", ident"y", ident"int", newEmptyNode()))) - -type - Foo = makeEnum() - Bar = makeObject() - -doAssert {a, b, c} is set[Foo] -let bar = Bar(x: 3, y: 4) -doAssert (bar.x, bar.y) == (3, 4) diff --git a/tests/macros/tvtable.nim b/tests/macros/tvtable.nim index 0f322b7d5..dc07a726b 100644 --- a/tests/macros/tvtable.nim +++ b/tests/macros/tvtable.nim @@ -18,7 +18,7 @@ type # it's also possible to use a strongly typed tuple here VTable = array[0..1, pointer] - TBase {.inheritable.} = object + TBase = object {.inheritable.} vtbl: ptr VTable TUserObject1 = object of TBase diff --git a/tests/magics/t10307.nim b/tests/magics/t10307.nim deleted file mode 100644 index b5a93c5c6..000000000 --- a/tests/magics/t10307.nim +++ /dev/null @@ -1,24 +0,0 @@ -discard """ - cmd: "nim c --mm:refc -d:useGcAssert $file" - output: '''running someProc(true) -res: yes -yes -running someProc(false) -res: - -''' -""" - -proc someProc(x:bool):cstring = - var res:string = "" - if x: - res = "yes" - echo "res: ", res - GC_ref(res) - result = res - -echo "running someProc(true)" -echo someProc(true) - -echo "running someProc(false)" -echo someProc(false) diff --git a/tests/magics/t20938.nim b/tests/magics/t20938.nim deleted file mode 100644 index 7341cbb91..000000000 --- a/tests/magics/t20938.nim +++ /dev/null @@ -1,12 +0,0 @@ -discard """ - cmd: "nim c --mm:refc $file" - action: "compile" -""" - -template foo(x: typed) = - discard x - -foo: - var x = "hello" - x.shallowCopy("test") - true diff --git a/tests/magics/tmagics.nim b/tests/magics/tmagics.nim index e52912b74..fa138320c 100644 --- a/tests/magics/tmagics.nim +++ b/tests/magics/tmagics.nim @@ -1,5 +1,4 @@ discard """ - matrix: "--mm:refc" output: ''' true true @@ -19,7 +18,7 @@ block tlowhigh: for i in low(a) .. high(a): a[i] = 0 - proc sum(a: openArray[int]): int = + proc sum(a: openarray[int]): int = result = 0 for i in low(a)..high(a): inc(result, a[i]) @@ -56,11 +55,3 @@ block t9442: GC_unref(v2) GC_ref(v3) GC_unref(v3) - -block: # bug #6499 - let x = (chr, 0) - doAssert x[1] == 0 - -block: # bug #12229 - proc foo(T: typedesc) = discard - foo(ref) diff --git a/tests/magics/trunnableexamples.nim b/tests/magics/trunnableexamples.nim new file mode 100644 index 000000000..e6b2b70f8 --- /dev/null +++ b/tests/magics/trunnableexamples.nim @@ -0,0 +1,60 @@ +discard """ +cmd: "nim doc $file" +action: "compile" +nimout: ''' +foo1 +foo2 +foo3 +foo5 +foo6 +foo7 +foo8 +foo9 +''' +joinable: false +""" + +proc fun*() = + runnableExamples: + block: # `defer` only allowed inside a block + defer: echo "foo1" + + runnableExamples: + # `fun*` only allowed at top level + proc fun*()=echo "foo2" + fun() + block: + defer: echo "foo3" + + runnableExamples: + # ditto + proc fun*()=echo "foo5" + fun() + + runnableExamples: + # `codeReordering` only allowed at top level + {.experimental: "codeReordering".} + proc fun1() = fun2() + proc fun2() = echo "foo6" + fun1() + + runnableExamples: + # only works at top level + import std/macros + macro myImport(a: static string): untyped = + newTree(nnkImportStmt, [newLit a]) + myImport "str" & "utils" + doAssert declared(isAlphaAscii) + echo "foo7" + +# also check for runnableExamples at module scope +runnableExamples: + block: + defer: echo "foo8" + +runnableExamples: + proc fun*()=echo "foo9" + fun() + +# note: there are yet other examples where putting runnableExamples at module +# scope is needed, for example when using an `include` before an `import`, etc. diff --git a/tests/manyloc/argument_parser/argument_parser.nim b/tests/manyloc/argument_parser/argument_parser.nim index e2c1b0a04..9cea59477 100644 --- a/tests/manyloc/argument_parser/argument_parser.nim +++ b/tests/manyloc/argument_parser/argument_parser.nim @@ -102,7 +102,7 @@ type # - Tparam_kind procs -proc `$`*(value: Tparam_kind): string = +proc `$`*(value: Tparam_kind): string {.procvar.} = ## Stringifies the type, used to generate help texts. case value: of PK_EMPTY: result = "" @@ -137,7 +137,7 @@ proc new_parameter_specification*(consumes = PK_EMPTY, # - Tparsed_parameter procs -proc `$`*(data: Tparsed_parameter): string = +proc `$`*(data: Tparsed_parameter): string {.procvar.} = ## Stringifies the value, mostly for debug purposes. ## ## The proc will display the value followed by non string type in brackets. @@ -225,7 +225,7 @@ template raise_or_quit(exception, message: untyped) = template run_custom_proc(parsed_parameter: Tparsed_parameter, custom_validator: Tparameter_callback, - parameter: string) = + parameter: TaintedString) = ## Runs the custom validator if it is not nil. ## ## Pass in the string of the parameter triggering the call. If the @@ -251,8 +251,8 @@ proc parse_parameter(quit_on_failure: bool, param, value: string, case param_kind: of PK_INT: try: result.int_val = value.parseInt - except OverflowDefect: - raise_or_quit(OverflowDefect, ("parameter $1 requires an " & + except OverflowError: + raise_or_quit(OverflowError, ("parameter $1 requires an " & "integer, but $2 is too large to fit into one") % [param, escape(value)]) except ValueError: @@ -301,7 +301,8 @@ template build_specification_lookup(): OrderedTable[string, ptr Tparameter_specification] = ## Returns the table used to keep pointers to all of the specifications. var result {.gensym.}: OrderedTable[string, ptr Tparameter_specification] - result = initOrderedTable[string, ptr Tparameter_specification](expected.len) + result = initOrderedTable[string, ptr Tparameter_specification]( + tables.rightSize(expected.len)) for i in 0..expected.len-1: for param_to_detect in expected[i].names: if result.hasKey(param_to_detect): @@ -318,7 +319,7 @@ proc echo_help*(expected: seq[Tparameter_specification] = @[], proc parse*(expected: seq[Tparameter_specification] = @[], - type_of_positional_parameters = PK_STRING, args: seq[string] = @[], + type_of_positional_parameters = PK_STRING, args: seq[TaintedString] = @[], bad_prefixes = @["-", "--"], end_of_options = "--", quit_on_failure = true): Tcommandline_results = ## Parses parameters and returns results. @@ -446,7 +447,7 @@ proc build_help*(expected: seq[Tparameter_specification] = @[], # First generate the joined version of input parameters in a list. var - seen = initHashSet[string]() + seen = initSet[string]() prefixes: seq[string] = @[] helps: seq[string] = @[] for key in keys: diff --git a/tests/manyloc/keineschweine/dependencies/chipmunk/chipmunk.nim b/tests/manyloc/keineschweine/dependencies/chipmunk/chipmunk.nim index 6eb1b3844..552b3e756 100644 --- a/tests/manyloc/keineschweine/dependencies/chipmunk/chipmunk.nim +++ b/tests/manyloc/keineschweine/dependencies/chipmunk/chipmunk.nim @@ -106,7 +106,7 @@ type #/ Collision begin event function callback type. #/ Returning false from a begin callback causes the collision to be ignored until - #/ the separate callback is called when the objects stop colliding. + #/ the the separate callback is called when the objects stop colliding. TCollisionBeginFunc* = proc (arb: PArbiter; space: PSpace; data: pointer): bool{. cdecl.} #/ Collision pre-solve event function callback type. diff --git a/tests/manyloc/keineschweine/dependencies/enet/enet.nim b/tests/manyloc/keineschweine/dependencies/enet/enet.nim index 5dee6ae9c..02ebef595 100644 --- a/tests/manyloc/keineschweine/dependencies/enet/enet.nim +++ b/tests/manyloc/keineschweine/dependencies/enet/enet.nim @@ -265,7 +265,7 @@ const ENET_PEER_RELIABLE_WINDOW_SIZE = 0x1000 ENET_PEER_FREE_RELIABLE_WINDOWS = 8 -when defined(linux) or true: +when defined(Linux) or true: import posix const ENET_SOCKET_NULL*: cint = -1 @@ -295,7 +295,7 @@ when defined(linux) or true: template ENET_SOCKETSET_CHECK*(sockset, socket: untyped): untyped = FD_ISSET(socket, addr((sockset))) -when defined(windows): +when defined(Windows): ## put the content of win32.h in here diff --git a/tests/manyloc/keineschweine/dependencies/genpacket/streams_enh.nim b/tests/manyloc/keineschweine/dependencies/genpacket/streams_enh.nim index a0c8a7a3c..ad0d20f1c 100644 --- a/tests/manyloc/keineschweine/dependencies/genpacket/streams_enh.nim +++ b/tests/manyloc/keineschweine/dependencies/genpacket/streams_enh.nim @@ -1,7 +1,7 @@ import streams from strutils import repeat -proc readPaddedStr*(s: PStream, length: int, padChar = '\0'): string = +proc readPaddedStr*(s: PStream, length: int, padChar = '\0'): TaintedString = var lastChr = length result = s.readStr(length) while lastChr >= 0 and result[lastChr - 1] == padChar: dec(lastChr) @@ -16,7 +16,7 @@ proc writePaddedStr*(s: PStream, str: string, length: int, padChar = '\0') = else: s.write(str) -proc readLEStr*(s: PStream): string = +proc readLEStr*(s: PStream): TaintedString = var len = s.readInt16() result = s.readStr(len) diff --git a/tests/manyloc/keineschweine/dependencies/nake/nake.nim b/tests/manyloc/keineschweine/dependencies/nake/nake.nim index e466ee5e1..83569e30e 100644 --- a/tests/manyloc/keineschweine/dependencies/nake/nake.nim +++ b/tests/manyloc/keineschweine/dependencies/nake/nake.nim @@ -7,10 +7,6 @@ contents thereof. As said in the Olde Country, `Keepe it Gangster'.""" -#[ -xxx remove this? seems mostly duplicate of: tests/manyloc/nake/nake.nim -]# - import strutils, parseopt, tables, os type @@ -55,7 +51,7 @@ template withDir*(dir: string; body: stmt): stmt = cd(curDir) when true: - if not fileExists("nakefile.nim"): + if not existsFile("nakefile.nim"): echo "No nakefile.nim found. Current working dir is ", getCurrentDir() quit 1 var args = "" @@ -64,8 +60,7 @@ when true: args.add " " quit(shell("nim", "c", "-r", "nakefile.nim", args)) else: - import std/exitprocs - addExitProc(proc() {.noconv.} = + addQuitProc(proc() {.noconv.} = var task: string printTaskList: bool diff --git a/tests/manyloc/keineschweine/enet_server/enet_server.nim b/tests/manyloc/keineschweine/enet_server/enet_server.nim index 794e1c843..336e57755 100644 --- a/tests/manyloc/keineschweine/enet_server/enet_server.nim +++ b/tests/manyloc/keineschweine/enet_server/enet_server.nim @@ -118,7 +118,7 @@ when true: of cmdShortOption, cmdLongOption: case key of "f", "file": - if fileExists(val): + if existsFile(val): zoneCfgFile = val else: echo("File does not exist: ", val) @@ -136,7 +136,7 @@ when true: address.port = port var path = getAppDir()/../"data"/zoneFile - if not fileExists(path): + if not existsFile(path): echo("Zone settings file does not exist: ../data/", zoneFile) echo(path) quit(1) diff --git a/tests/manyloc/keineschweine/keineschweine.nim b/tests/manyloc/keineschweine/keineschweine.nim index cde31bd18..b6fd3cc19 100644 --- a/tests/manyloc/keineschweine/keineschweine.nim +++ b/tests/manyloc/keineschweine/keineschweine.nim @@ -446,7 +446,7 @@ ingameClient.registerHandler(KeyF12, down, proc() = toggleSpec()) ingameClient.registerHandler(KeyF11, down, toggleShipSelect) ingameClient.registerHandler(MouseLeft, down, handleLClick) when defined(recordMode): - if not dirExists("data/snapshots"): + if not existsDir("data/snapshots"): createDir("data/snapshots") ingameClient.registerHandler(keynum9, down, proc() = if not isRecording: startRecording() @@ -486,7 +486,7 @@ when defined(DebugKeys): activeVehicle.body.setPos mouseToSpace()) ingameClient.registerHandler(KeyY, down, proc() = const looloo = ["Asteroid1", "Asteroid2"] - addObject(looloo[rand(looloo.len)])) + addObject(looloo[random(looloo.len)])) ingameClient.registerHandler(KeyO, down, proc() = if objects.len == 0: echo "Objects is empty" diff --git a/tests/manyloc/keineschweine/keineschweine.nim.cfg b/tests/manyloc/keineschweine/keineschweine.nim.cfg index a670e2b77..f335a0e0e 100644 --- a/tests/manyloc/keineschweine/keineschweine.nim.cfg +++ b/tests/manyloc/keineschweine/keineschweine.nim.cfg @@ -7,4 +7,4 @@ path = "dependencies/genpacket" path = "enet_server" debugger = off warning[SmallLshouldNotBeUsed] = off -mm = refc +nilseqs = on diff --git a/tests/manyloc/keineschweine/lib/client_helpers.nim b/tests/manyloc/keineschweine/lib/client_helpers.nim index b535225dc..0ebb4ade1 100644 --- a/tests/manyloc/keineschweine/lib/client_helpers.nim +++ b/tests/manyloc/keineschweine/lib/client_helpers.nim @@ -69,7 +69,7 @@ proc updateFileProgress*() = downloadProgress.setString($currentFileTransfer.pos & '/' & $currentFileTransfer.fullLen) ## HFileTransfer -proc handleFilePartRecv*(serv: PServer; buffer: PBuffer) = +proc handleFilePartRecv*(serv: PServer; buffer: PBuffer) {.procvar.} = var f = readScFileTransfer(buffer) updateFileProgress() @@ -103,14 +103,14 @@ proc saveCurrentFile() = let path = expandPath(currentFileTransfer.assetType, currentFileTransfer.fileName) parent = parentDir(path) - if not dirExists(parent): + if not existsDir(parent): createDir(parent) echo("Created dir") writeFile path, currentFIleTransfer.data echo "Write file" ## HChallengeResult -proc handleFileChallengeResult*(serv: PServer; buffer: PBuffer) = +proc handleFileChallengeResult*(serv: PServer; buffer: PBuffer) {.procvar.} = var res = readScChallengeResult(buffer).status echo "got challnege result: ", res if res and currentFileTransfer.readyToSave: @@ -122,12 +122,12 @@ proc handleFileChallengeResult*(serv: PServer; buffer: PBuffer) = echo "REsetting current file" ## HFileCHallenge -proc handleFileChallenge*(serv: PServer; buffer: PBuffer) = +proc handleFileChallenge*(serv: PServer; buffer: PBuffer) {.procvar.} = var challenge = readScFileChallenge(buffer) path = expandPath(challenge) resp: CsFileChallenge - if not fileExists(path): + if not existsFile(path): resp.needFile = true echo "Got file challenge, need file." else: diff --git a/tests/manyloc/keineschweine/lib/estreams.nim b/tests/manyloc/keineschweine/lib/estreams.nim index c5e45e0e7..5ab029b52 100644 --- a/tests/manyloc/keineschweine/lib/estreams.nim +++ b/tests/manyloc/keineschweine/lib/estreams.nim @@ -78,9 +78,9 @@ proc write*(buffer: PBuffer; val: var string) = setLen buffer.data, buffer.pos + length.int copyMem(addr buffer.data[buffer.pos], addr val[0], length.int) inc buffer.pos, length.int -proc write*[T: SomeNumber|bool|char|byte](buffer: PBuffer; val: sink T) = +proc write*[T: SomeNumber|bool|char|byte](buffer: PBuffer; val: T) = var v: T - v = val + shallowCopy v, val writeBE buffer, v proc readInt8*(buffer: PBuffer): int8 = diff --git a/tests/manyloc/keineschweine/lib/glut.nim b/tests/manyloc/keineschweine/lib/glut.nim index de9a97456..44a290728 100644 --- a/tests/manyloc/keineschweine/lib/glut.nim +++ b/tests/manyloc/keineschweine/lib/glut.nim @@ -93,7 +93,7 @@ const GLUT_NORMAL* = 0 GLUT_OVERLAY* = 1 -when defined(windows): +when defined(Windows): const # Stroke font constants (use these in GLUT program). GLUT_STROKE_ROMAN* = cast[Pointer](0) GLUT_STROKE_MONO_ROMAN* = cast[Pointer](1) # Bitmap font constants (use these in GLUT program). diff --git a/tests/manyloc/keineschweine/lib/sg_assets.nim b/tests/manyloc/keineschweine/lib/sg_assets.nim index 5929add43..7caa9c3fb 100644 --- a/tests/manyloc/keineschweine/lib/sg_assets.nim +++ b/tests/manyloc/keineschweine/lib/sg_assets.nim @@ -221,7 +221,7 @@ template cacheImpl(procName, cacheName, resultType, body: untyped) {.dirty.} = cacheName[filename] = result template checkFile(path: untyped) {.dirty.} = - if not fileExists(path): + if not existsFile(path): errors.add("File missing: " & path) cacheImpl newSprite, SpriteSheets, PSpriteSheet: @@ -322,7 +322,7 @@ proc validateSettings*(settings: JsonNode, errors: var seq[string]): bool = inc id proc loadSettingsFromFile*(filename: string, errors: var seq[string]): bool = - if not fileExists(filename): + if not existsFile(filename): errors.add("File does not exist: "&filename) else: result = loadSettings(readFile(filename), errors) diff --git a/tests/manyloc/keineschweine/lib/sg_gui.nim b/tests/manyloc/keineschweine/lib/sg_gui.nim index bcf415556..83ad0d1bf 100644 --- a/tests/manyloc/keineschweine/lib/sg_gui.nim +++ b/tests/manyloc/keineschweine/lib/sg_gui.nim @@ -193,28 +193,28 @@ proc setActive*(t: PTextEntry) = if not t.isNil and not t.inputClient.isNil: input_helpers.setActive(t.inputClient) -when false: - proc newMessageArea*(container: PGuiContainer; position: TVector2f): PMessageArea = - new(result) - result.messages = @[] - result.pos = position - container.add(result) - proc add*(m: PMessageArea, text: string): PText = - result = messageProto.copy() - result.setString(text) - m.messages.add(result) - let nmsgs = len(m.messages) - var pos = vec2f(m.pos.x, m.pos.y) - for i in countdown(nmsgs - 1, max(nmsgs - 30, 0)): - setPosition(m.messages[i], pos) - pos.y -= 16.0 - proc draw*(window: PRenderWindow; m: PMessageArea) = - let nmsgs = len(m.messages) - if nmsgs == 0: return - for i in countdown(nmsgs - 1, max(nmsgs - 30, 0)): - window.draw(m.messages[i]) +discard """proc newMessageArea*(container: PGuiContainer; position: TVector2f): PMessageArea = + new(result) + result.messages = @[] + result.pos = position + container.add(result) +proc add*(m: PMessageArea, text: string): PText = + result = messageProto.copy() + result.setString(text) + m.messages.add(result) + let nmsgs = len(m.messages) + var pos = vec2f(m.pos.x, m.pos.y) + for i in countdown(nmsgs - 1, max(nmsgs - 30, 0)): + setPosition(m.messages[i], pos) + pos.y -= 16.0 +proc draw*(window: PRenderWindow; m: PMessageArea) = + let nmsgs = len(m.messages) + if nmsgs == 0: return + for i in countdown(nmsgs - 1, max(nmsgs - 30, 0)): + window.draw(m.messages[i]) +""" proc newMessageArea*(container: PGuiContainer; position: TVector2f): PMessageArea = new(result) result.messages = @[] diff --git a/tests/manyloc/keineschweine/lib/zlib_helpers.nim b/tests/manyloc/keineschweine/lib/zlib_helpers.nim index e51c000c8..895f41759 100644 --- a/tests/manyloc/keineschweine/lib/zlib_helpers.nim +++ b/tests/manyloc/keineschweine/lib/zlib_helpers.nim @@ -1,26 +1,21 @@ -# xxx this test is bad (echo instead of error, etc) - import zip/zlib proc compress*(source: string): string = var sourcelen = source.len - destLen = sourcelen + (sourcelen.float * 0.1).int + 16 + destlen = sourcelen + (sourcelen.float * 0.1).int + 16 result = "" result.setLen destLen - # see http://www.zlib.net/zlib-1.2.11.tar.gz for correct definitions - var destLen2 = destLen.Ulongf - var res = zlib.compress(cstring(result), addr destLen2, cstring(source), sourceLen.Ulong) + var res = zlib.compress(cstring(result), addr destLen, cstring(source), sourceLen) if res != Z_OK: echo "Error occurred: ", res - elif destLen2.int < result.len: - result.setLen(destLen2.int) + elif destLen < result.len: + result.setLen(destLen) proc uncompress*(source: string, destLen: var int): string = result = "" result.setLen destLen - var destLen2 = destLen.Ulongf - var res = zlib.uncompress(cstring(result), addr destLen2, cstring(source), source.len.Ulong) + var res = zlib.uncompress(cstring(result), addr destLen, cstring(source), source.len) if res != Z_OK: echo "Error occurred: ", res diff --git a/tests/manyloc/keineschweine/server/old_dirserver.nim b/tests/manyloc/keineschweine/server/old_dirserver.nim index cd2b60b26..390b738aa 100644 --- a/tests/manyloc/keineschweine/server/old_dirserver.nim +++ b/tests/manyloc/keineschweine/server/old_dirserver.nim @@ -164,7 +164,7 @@ when true: of cmdShortOption, cmdLongOption: case key of "f", "file": - if fileExists(val): + if existsFile(val): cfgFile = val else: echo("File does not exist: ", val) diff --git a/tests/manyloc/keineschweine/server/old_sg_server.nim b/tests/manyloc/keineschweine/server/old_sg_server.nim index 8bd44017e..473880e2b 100644 --- a/tests/manyloc/keineschweine/server/old_sg_server.nim +++ b/tests/manyloc/keineschweine/server/old_sg_server.nim @@ -149,7 +149,7 @@ when true: of cmdShortOption, cmdLongOption: case key of "f", "file": - if fileExists(val): + if existsFile(val): zoneCfgFile = val else: echo("File does not exist: ", val) @@ -165,7 +165,7 @@ when true: dirServerInfo = jsonSettings["dirserver"] var path = getAppDir()/../"data"/zoneFile - if not fileExists(path): + if not existsFile(path): echo("Zone settings file does not exist: ../data/", zoneFile) echo(path) quit(1) diff --git a/tests/manyloc/nake/nake.nim b/tests/manyloc/nake/nake.nim index ce7faab5c..ebcf21d19 100644 --- a/tests/manyloc/nake/nake.nim +++ b/tests/manyloc/nake/nake.nim @@ -51,7 +51,7 @@ template withDir*(dir: string; body: untyped) = cd(curDir) when true: - if not fileExists("nakefile.nim"): + if not existsFile("nakefile.nim"): echo "No nakefile.nim found. Current working dir is ", getCurrentDir() quit 1 var args = "" @@ -60,8 +60,7 @@ when true: args.add " " quit(shell("nim", "c", "-r", "nakefile.nim", args)) else: - import std/exitprocs - addExitProc(proc() {.noconv.} = + addQuitProc(proc() {.noconv.} = var task: string printTaskList: bool diff --git a/tests/manyloc/nake/nakefile.nim b/tests/manyloc/nake/nakefile.nim index fc479a5c2..35ed3cbb0 100644 --- a/tests/manyloc/nake/nakefile.nim +++ b/tests/manyloc/nake/nakefile.nim @@ -29,12 +29,11 @@ task "test2", "Build release test build test release build": if shell("nim", ReleaseDefines, ReleaseTestDefines, "compile", ExeName) == 0: shell "."/ExeName -when false: - task "dirserver", "build the directory server": - withDir "server": - if shell("nim", ServerDefines, "compile", "dirserver") != 0: - echo "Failed to build the dirserver" - quit 1 +discard """task "dirserver", "build the directory server": + withDir "server": + if shell("nim", ServerDefines, "compile", "dirserver") != 0: + echo "Failed to build the dirserver" + quit 1""" task "zoneserver", "build the zone server": withDir "enet_server": @@ -64,7 +63,7 @@ task "release", "release build": ## zip up all the files and such or something useful here task "testskel", "create skeleton test dir for testing": - let dirname = "test-" & $rand(5000) + let dirname = "test-"& $random(5000) removeDir dirName createDir dirName/"data/fnt" copyFile "data/fnt/LiberationMono-Regular", dirName/"data/fnt/LiberationMono-Regular.ttf" @@ -78,7 +77,7 @@ task "testskel", "create skeleton test dir for testing": task "clean", "cleanup generated files": var dirs = @["nimcache", "server"/"nimcache"] dirs.apply(proc(x: var string) = - if dirExists(x): removeDir(x)) + if existsDir(x): removeDir(x)) task "download", "download game assets": var @@ -87,7 +86,7 @@ task "download", "download game assets": client = newHttpClient() path.add DirSep path.add(extractFilename(GameAssets)) - if fileExists(path): + if existsFile(path): echo "The file already exists\n", "[R]emove [M]ove [Q]uit [S]kip Source: ", GameAssets case stdin.readLine.toLowerAscii @@ -134,7 +133,7 @@ task "download", "download game assets": else: ## this crashes, dunno why var z: TZipArchive - destDir = getCurrentDir()/("unzip" & $rand(5000)) + destDir = getCurrentDir()/("unzip"& $random(5000)) if not z.open(path, fmRead): echo "Could not open zip, bad download?" return diff --git a/tests/manyloc/named_argument_bug/tri_engine/gfx/gl/gl.nim b/tests/manyloc/named_argument_bug/tri_engine/gfx/gl/gl.nim index 29e23f9d0..7d787c07b 100644 --- a/tests/manyloc/named_argument_bug/tri_engine/gfx/gl/gl.nim +++ b/tests/manyloc/named_argument_bug/tri_engine/gfx/gl/gl.nim @@ -53,7 +53,7 @@ else: const glRealType* = cGLfloat -proc setUniformV4*[T](loc: GLint, vecs: var openArray[TV4[T]]) = +proc setUniformV4*[T](loc: GLint, vecs: var openarray[TV4[T]]) = glUniform4fv(loc, vecs.len.GLsizei, cast[ptr GLfloat](vecs[0].addr)) proc setUniformV4*[T](loc: GLint, vec: TV4[T]) = diff --git a/tests/manyloc/named_argument_bug/tri_engine/gfx/gl/primitive.nim b/tests/manyloc/named_argument_bug/tri_engine/gfx/gl/primitive.nim index accc2d96b..3bfaf1cbc 100644 --- a/tests/manyloc/named_argument_bug/tri_engine/gfx/gl/primitive.nim +++ b/tests/manyloc/named_argument_bug/tri_engine/gfx/gl/primitive.nim @@ -47,7 +47,7 @@ proc newVert*(rect: rect.TRect): seq[TVert] = proc newVertAttrib(i: GLuint, size: GLint, stride: GLsizei, offset: GLvoid): TVertAttrib = TVertAttrib(i: i, size: size, stride: stride, offset: offset) -proc genBuf*[T](vboTarget, objUsage: GLenum, data: var openArray[T]): GLuint = +proc genBuf*[T](vboTarget, objUsage: GLenum, data: var openarray[T]): GLuint = result = 0.GLuint ?glGenBuffers(1, result.addr) ?glBindBuffer(vboTarget, result) diff --git a/tests/manyloc/standalone/panicoverride.nim b/tests/manyloc/standalone/panicoverride.nim index c0b8bb030..d9b3f4388 100644 --- a/tests/manyloc/standalone/panicoverride.nim +++ b/tests/manyloc/standalone/panicoverride.nim @@ -11,4 +11,9 @@ proc panic(s: string) {.noreturn.} = rawoutput(s) exit(1) +# Alternatively we also could implement these 2 here: +# +# proc sysFatal(exceptn: typeDesc, message: string) {.noReturn.} +# proc sysFatal(exceptn: typeDesc, message, arg: string) {.noReturn.} + {.pop.} diff --git a/tests/manyloc/standalone2/panicoverride.nim b/tests/manyloc/standalone2/panicoverride.nim deleted file mode 100644 index c0b8bb030..000000000 --- a/tests/manyloc/standalone2/panicoverride.nim +++ /dev/null @@ -1,14 +0,0 @@ - -proc printf(frmt: cstring) {.varargs, importc, header: "", cdecl.} -proc exit(code: int) {.importc, header: "", cdecl.} - -{.push stack_trace: off, profiler:off.} - -proc rawoutput(s: string) = - printf("%s\n", s) - -proc panic(s: string) {.noreturn.} = - rawoutput(s) - exit(1) - -{.pop.} diff --git a/tests/manyloc/standalone2/tavr.nim b/tests/manyloc/standalone2/tavr.nim deleted file mode 100644 index 6cbc5c699..000000000 --- a/tests/manyloc/standalone2/tavr.nim +++ /dev/null @@ -1,7 +0,0 @@ -# bug #16404 - -proc printf(frmt: cstring) {.varargs, header: "", cdecl.} - -var x = 0 -inc x -printf("hi %ld\n", x+4777) diff --git a/tests/manyloc/standalone2/tavr.nim.cfg b/tests/manyloc/standalone2/tavr.nim.cfg deleted file mode 100644 index 2a31618d0..000000000 --- a/tests/manyloc/standalone2/tavr.nim.cfg +++ /dev/null @@ -1,5 +0,0 @@ ---gc:arc ---cpu:avr ---os:standalone ---compileOnly ---threads:off diff --git a/tests/metatype/tcps.nim b/tests/metatype/tcps.nim deleted file mode 100644 index 042e32bd6..000000000 --- a/tests/metatype/tcps.nim +++ /dev/null @@ -1,35 +0,0 @@ -discard """ - output: '''10 -string''' -""" - -# bug #18059 -type - C = ref object of RootObj - fn: ContProc - ex: ref Exception - - ContProc = proc (c: C): C {.nimcall.} - -proc noop(c: C): C = c - -type - Env[T] = ref object of C - x: T - -proc foo_cont[U](c: C): C = - proc afterCall[V](c: C): C = - echo Env[V](c).x - - c.fn = afterCall[U] - return noop(c) - -proc foo[T](x: T): C = - return Env[T](fn: foo_cont[T], x: x) - -proc tramp(c: sink C) = - while c != nil and c.fn != nil: - c = c.fn(c) - -tramp foo(10) -tramp foo("string") diff --git a/tests/metatype/tmatrix3.nim b/tests/metatype/tmatrix3.nim index 28e85fcee..a143e2bc9 100644 --- a/tests/metatype/tmatrix3.nim +++ b/tests/metatype/tmatrix3.nim @@ -1,5 +1,5 @@ discard """ - output: "\n" + output: "" """ type Matrix[M,N: static[int]] = array[M, array[N, float]] diff --git a/tests/metatype/tmetatype_various.nim b/tests/metatype/tmetatype_various.nim index c17410a06..a56eca018 100644 --- a/tests/metatype/tmetatype_various.nim +++ b/tests/metatype/tmetatype_various.nim @@ -1,7 +1,4 @@ -discard """ - matrix: "--mm:refc" - output: '''[1, 0, 0, 0, 0, 0, 0, 0] CTBool[Ct[system.uint32]]''' -""" + block tconstraints: proc myGenericProc[T: object|tuple|int|ptr|ref|distinct](x: T): string = @@ -40,29 +37,13 @@ block tfieldaccessor: block tprocbothmeta: proc myFun[A](x: A): auto = result = float(x+10) - + proc myMap[T,S](sIn: seq[T], f: proc (q: T): S): seq[S] = result = newSeq[S](sIn.len) for i in 0.. high(T): - raise newException(RangeDefect, "protocol error") + raise newException(RangeError, "protocol error") return T(v) #proc toNumber[T](v: int32): T = diff --git a/tests/metatype/twildtypedesc.nim b/tests/metatype/twildtypedesc.nim index d1c5ffba5..268bff0d8 100644 --- a/tests/metatype/twildtypedesc.nim +++ b/tests/metatype/twildtypedesc.nim @@ -17,8 +17,8 @@ proc unpack[T](v: string): T = var s = "123" -doAssert(unpack[string](s) is string) -doAssert(unpack[int](s) is int) +assert(unpack[string](s) is string) +assert(unpack[int](s) is int) echo unpack[int](s) echo unpack[string](s) @@ -37,7 +37,7 @@ proc unit(t: typedesc[int]): t = 0 proc unit(t: typedesc[string]): t = "" proc unit(t: typedesc[float]): t = 0.0 -doAssert unit(int) == 0 -doAssert unit(string) == "" -doAssert unit(float) == 0.0 +assert unit(int) == 0 +assert unit(string) == "" +assert unit(float) == 0.0 diff --git a/tests/metatype/typeclassinference.nim b/tests/metatype/typeclassinference.nim index b3f197718..c845e04f7 100644 --- a/tests/metatype/typeclassinference.nim +++ b/tests/metatype/typeclassinference.nim @@ -19,25 +19,3 @@ var ptr1: ptr = addr(str1) var str2: string = "hello, world!" var ptr2: ptr = str2 -block: # built in typeclass inference - proc tupleA(): tuple = return (1, 2) - proc tupleB(): tuple = (1f, 2f) - assert typeof(tupleA()) is (int, int) - assert typeof(tupleB()) is (float32, float32) - - proc a(val: int or float): tuple = - when typeof(val) is int: - (10, 10) - else: - (30f, 30f) - - assert typeof(a(10)) is (int, int) - assert typeof(a(10.0)) is (float32, float32) - - proc b(val: int or float): set = - when typeof(val) is int: - {10u8, 3} - else: - {'a', 'b'} - assert typeof(b(10)) is set[uint8] - assert typeof(b(10.0)) is set[char] \ No newline at end of file diff --git a/tests/metatype/typedesc_as_value.nim b/tests/metatype/typedesc_as_value.nim index 463d23724..f6e526987 100644 --- a/tests/metatype/typedesc_as_value.nim +++ b/tests/metatype/typedesc_as_value.nim @@ -1,5 +1,5 @@ discard """ - errormsg: "invalid type: 'typedesc[int]' for var" + errormsg: "'typedesc' metatype is not valid here; typed '=' instead of ':'?" """ diff --git a/tests/metatype/utypeclasses.nim b/tests/metatype/utypeclasses.nim index f94b39742..06bab375e 100644 --- a/tests/metatype/utypeclasses.nim +++ b/tests/metatype/utypeclasses.nim @@ -3,11 +3,11 @@ import unittest proc concat(a, b): string = result = $a & $b -block: # if proc param types are not supplied, the params are assumed to be generic +test "if proc param types are not supplied, the params are assumed to be generic": check concat(1, "test") == "1test" check concat(1, 20) == "120" check concat("foo", "bar") == "foobar" -block: # explicit param types can still be specified +test "explicit param types can still be specified": check concat[cstring, cstring]("x", "y") == "xy" diff --git a/tests/method/t20515.nim b/tests/method/t20515.nim deleted file mode 100644 index 1921f2e46..000000000 --- a/tests/method/t20515.nim +++ /dev/null @@ -1,20 +0,0 @@ -discard """ - errormsg: "Base method 'zzz' requires explicit '{.gcsafe.}' to be GC-safe" - line: 10 -""" - -type - A = ref object of RootObj - B = ref object of A - -method zzz(a: A) {.base.} = - discard - -var s: seq[int] -method zzz(a: B) = - echo s - -proc xxx(someObj: A) {.gcsafe.} = - someObj.zzz() - -xxx(B()) diff --git a/tests/method/tgeneric_methods.nim b/tests/method/tgeneric_methods.nim index ab92c66d8..0e2aeeede 100644 --- a/tests/method/tgeneric_methods.nim +++ b/tests/method/tgeneric_methods.nim @@ -1,5 +1,4 @@ discard """ - matrix: "--mm:arc; --mm:refc" output: '''wow2 X 1 X 3''' diff --git a/tests/method/tmethod_issues.nim b/tests/method/tmethod_issues.nim index daaa46522..80f54caee 100644 --- a/tests/method/tmethod_issues.nim +++ b/tests/method/tmethod_issues.nim @@ -1,16 +1,13 @@ discard """ - matrix: "--mm:arc; --mm:refc" output: ''' wof! wof! -type A -type B ''' """ # bug #1659 -type Animal {.inheritable.} = ref object +type Animal = ref object {.inheritable.} type Dog = ref object of Animal method say(a: Animal): auto {.base.} = "wat!" @@ -129,42 +126,3 @@ var obj2 = Class2() obj1.test(obj2) obj2.test(obj1) - - -# ------------------------------------------------------- -# issue #16516 - -type - A = ref object of RootObj - x: int - - B = ref object of A - -method foo(v: sink A, lst: var seq[A]) {.base,locks:0.} = - echo "type A" - lst.add v - -method foo(v: sink B, lst: var seq[A]) = - echo "type B" - lst.add v - -proc main() = - let - a = A(x: 5) - b: A = B(x: 5) - - var lst: seq[A] - - foo(a, lst) - foo(b, lst) - -main() - -block: # bug #20391 - type Container[T] = ref object of RootRef - item: T - - let a = Container[int]() - - doAssert a of Container[int] - doAssert not (a of Container[string]) diff --git a/tests/method/tmethod_various.nim b/tests/method/tmethod_various.nim index c41d04983..fd022717b 100644 --- a/tests/method/tmethod_various.nim +++ b/tests/method/tmethod_various.nim @@ -1,5 +1,4 @@ discard """ - matrix: "--mm:arc; --mm:refc" output: ''' do nothing HELLO WORLD! @@ -12,7 +11,7 @@ method somethin(obj: RootObj) {.base.} = echo "do nothing" type - TNode* {.inheritable.} = object + TNode* = object {.inheritable.} PNode* = ref TNode PNodeFoo* = ref object of TNode @@ -30,7 +29,7 @@ o.somethin() # tmproto type - Obj1 {.inheritable.} = ref object + Obj1 = ref object {.inheritable.} Obj2 = ref object of Obj1 method beta(x: Obj1): int {.base.} diff --git a/tests/method/tmultim.nim b/tests/method/tmultim.nim index 126eb7526..7023e18bf 100644 --- a/tests/method/tmultim.nim +++ b/tests/method/tmultim.nim @@ -10,13 +10,12 @@ collide: thing, unit | do nothing ''' joinable: false - disabled: true """ # tmultim2 type - TThing {.inheritable.} = object + TThing = object {.inheritable.} TUnit = object of TThing x: int TParticle = object of TThing @@ -49,7 +48,7 @@ staticCollide(a, b) # tmultim6 type - Thing {.inheritable.} = object + Thing = object {.inheritable.} Unit[T] = object of Thing x: T Particle = object of Thing @@ -81,7 +80,7 @@ method somethin(obj: RootObj) {.base.} = echo "do nothing" type - TNode* {.inheritable.} = object + TNode* = object {.inheritable.} PNode* = ref TNode PNodeFoo* = ref object of TNode diff --git a/tests/method/tmultimjs.nim b/tests/method/tmultimjs.nim index 36960f2e1..ce62a2c23 100644 --- a/tests/method/tmultimjs.nim +++ b/tests/method/tmultimjs.nim @@ -4,7 +4,6 @@ discard """ Hi derived! hello ''' - disabled: true """ diff --git a/tests/method/tnildispatcher.nim b/tests/method/tnildispatcher.nim index 219d2b29f..017e8155f 100644 --- a/tests/method/tnildispatcher.nim +++ b/tests/method/tnildispatcher.nim @@ -1,5 +1,5 @@ discard """ - outputsub: '''Error: unhandled exception: cannot dispatch; dispatcher is nil [NilAccessDefect]''' + outputsub: '''Error: unhandled exception: cannot dispatch; dispatcher is nil [NilAccessError]''' exitcode: 1 """ # bug #5599 diff --git a/tests/method/tsingle_methods.nim b/tests/method/tsingle_methods.nim index b564e7d87..40269559a 100644 --- a/tests/method/tsingle_methods.nim +++ b/tests/method/tsingle_methods.nim @@ -1,5 +1,5 @@ discard """ - matrix: "--mm:arc --multimethods:off; --mm:refc --multimethods:off" + cmd: "nim c --multimethods:off $file" output: '''base base base diff --git a/tests/misc/m15316.nim b/tests/misc/m15316.nim deleted file mode 100644 index 188d06946..000000000 --- a/tests/misc/m15316.nim +++ /dev/null @@ -1 +0,0 @@ -proc foo = (if) diff --git a/tests/misc/m15955.nim b/tests/misc/m15955.nim deleted file mode 100644 index 22da345db..000000000 --- a/tests/misc/m15955.nim +++ /dev/null @@ -1,4 +0,0 @@ -proc add*(a, b: int): int {.cdecl, exportc.} = - a + b -proc sub*(a, b: int): int {.cdecl, exportc.} = - a - b \ No newline at end of file diff --git a/tests/misc/m15955_main.nim b/tests/misc/m15955_main.nim deleted file mode 100644 index a71af8121..000000000 --- a/tests/misc/m15955_main.nim +++ /dev/null @@ -1,11 +0,0 @@ -import stdtest/specialpaths -import std/os - -const buildLib = buildDir / "libD20220923T19380" - -{.passL: buildLib.} -proc add*(a, b: int):int {.cdecl, importc.} -proc sub*(a, b: int):int {.cdecl, importc.} - -echo add(10, 5) -echo sub(10, 5) diff --git a/tests/misc/m20149.nim b/tests/misc/m20149.nim deleted file mode 100644 index 942262a6e..000000000 --- a/tests/misc/m20149.nim +++ /dev/null @@ -1,2 +0,0 @@ -let x = 12 -echo x diff --git a/tests/misc/m20456.nims b/tests/misc/m20456.nims deleted file mode 100644 index 8a9313129..000000000 --- a/tests/misc/m20456.nims +++ /dev/null @@ -1 +0,0 @@ -echo 123 \ No newline at end of file diff --git a/tests/misc/mbackend.nim b/tests/misc/mbackend.nim deleted file mode 100644 index b6578a212..000000000 --- a/tests/misc/mbackend.nim +++ /dev/null @@ -1,30 +0,0 @@ -#[ -We can't merge this test inside a `when defined(cpp)` because some bug that was -fixed would not trigger in that case. -]# - -import std/compilesettings - -static: - ## bugfix 1: this used to CT error with: Error: unhandled exception: mimportcpp.nim(6, 18) `defined(cpp)` - doAssert defined(cpp) - doAssert querySetting(backend) == "cpp" - - ## checks that `--backend:c` has no side effect (ie, can be overridden by subsequent commands) - doAssert not defined(c) - doAssert not defined(js) - doAssert not defined(js) - -type - std_exception {.importcpp: "std::exception", header: "".} = object -proc what(s: std_exception): cstring {.importcpp: "((char *)#.what())".} - -var isThrown = false -try: - ## bugfix 2: this used to CT error with: Error: only a 'ref object' can be raised - raise std_exception() -except std_exception as ex: - doAssert ex.what().len > 0 - isThrown = true - -doAssert isThrown diff --git a/tests/misc/mbetterrun.nim b/tests/misc/mbetterrun.nim deleted file mode 100644 index d4f427af0..000000000 --- a/tests/misc/mbetterrun.nim +++ /dev/null @@ -1,3 +0,0 @@ -const mbetterrunVal {.strdefine.} = "" -static: echo "compiling: " & mbetterrunVal -echo "running: " & mbetterrunVal diff --git a/tests/misc/mfield_defect.nim b/tests/misc/mfield_defect.nim deleted file mode 100644 index 53bfba40e..000000000 --- a/tests/misc/mfield_defect.nim +++ /dev/null @@ -1,30 +0,0 @@ -#[ -ran from trunner -]# - - - - - - -# line 10 -type Kind = enum k0, k1, k2, k3, k4 - -type Foo = object - case kind: Kind - of k0: f0: int - of k1: f1: int - of k2: f2: int - of k3: f3: int - of k4: f4: int - -proc main()= - var foo = Foo(kind: k3, f3: 3) - let s1 = foo.f3 - doAssert s1 == 3 - let s2 = foo.f2 - -when defined case1: - static: main() -when defined case2: - main() diff --git a/tests/misc/mimportc.nim b/tests/misc/mimportc.nim deleted file mode 100644 index 602c6372d..000000000 --- a/tests/misc/mimportc.nim +++ /dev/null @@ -1,26 +0,0 @@ -#[ -this test will grow with more importc+importcpp tests; see driver in trunner.nim -]# - -{.emit:""" -struct A { - static int fun0(int a){ - return a; - } - static int& fun1(int& a){ - return a; - } -}; -""".} - -proc fun0*(a: cint): int {.importcpp:"A::$1(@)".} -proc fun1*(a: var cint): var int {.importcpp:"A::$1(@)".} = - ## some comment; this test is for #14314 - runnableExamples: discard - -proc main()= - var a = 10.cint - doAssert fun0(a) == a - doAssert fun1(a).addr == a.addr - echo "witness" -main() diff --git a/tests/misc/mjsondoc.nim b/tests/misc/mjsondoc.nim deleted file mode 100644 index e4642f0b4..000000000 --- a/tests/misc/mjsondoc.nim +++ /dev/null @@ -1,11 +0,0 @@ -proc doSomething*(x, y: int): int = - ## do something - x + y - -const - a* = 1 ## echo 1234 - b* = "test" - -type - MyEnum* = enum - foo, bar diff --git a/tests/misc/msizeof5.nim b/tests/misc/msizeof5.nim deleted file mode 100644 index 63573a705..000000000 --- a/tests/misc/msizeof5.nim +++ /dev/null @@ -1,131 +0,0 @@ -## tests for -d:checkAbi used by addAbiCheck via NIM_STATIC_ASSERT - -{.emit:"""/*TYPESECTION*/ -struct Foo1{ - int a; -}; -struct Foo2{ - int a; -}; -enum Foo3{k1, k2}; -typedef enum Foo3 Foo3b; -typedef enum Foo4{k3, k4} Foo4; - -typedef int Foo5[3]; - -typedef struct Foo6{ - int a1; - bool a2; - double a3; - struct Foo6* a4; -} Foo6; -""".} - -template ensureCgen(T: typedesc) = - ## ensures cgen - var a {.volatile.}: T - -block: - type Foo1Alias{.importc: "struct Foo1", size: sizeof(cint).} = object - a: cint - ensureCgen Foo1Alias - -block: - type Foo3Alias{.importc: "enum Foo3", size: sizeof(cint).} = enum - k1, k2 - ensureCgen Foo3Alias - -block: - type Foo3bAlias{.importc: "Foo3b", size: sizeof(cint).} = enum - k1, k2 - ensureCgen Foo3bAlias - -block: - type Foo3b{.importc, size: sizeof(cint).} = enum - k1, k2 - ensureCgen Foo3b - static: - doAssert Foo3b.sizeof == cint.sizeof - -block: - type Foo4{.importc, size: sizeof(cint).} = enum - k3, k4 - # adding entries should not yield duplicate ABI checks, as enforced by - # `typeABICache`. - # Currently the test doesn't check for this but you can inspect the cgen'd file - ensureCgen Foo4 - ensureCgen Foo4 - ensureCgen Foo4 - -block: - type Foo5{.importc.} = array[3, cint] - ensureCgen Foo5 - -block: - type Foo5{.importc.} = array[3, cint] - ensureCgen Foo5 - -block: # CT sizeof - type Foo6GT = object # grountruth - a1: cint - a2: bool - a3: cfloat - a4: ptr Foo6GT - - type Foo6{.importc, completeStruct.} = object - a1: cint - a2: bool - a3: cfloat - a4: ptr Foo6 - - static: doAssert compiles(static(Foo6.sizeof)) - static: doAssert Foo6.sizeof == Foo6GT.sizeof - static: doAssert (Foo6, int, array[2, Foo6]).sizeof == - (Foo6GT, int, array[2, Foo6GT]).sizeof - -block: - type GoodImportcType {.importc: "signed char", nodecl.} = char - # "good" in sense the sizeof will match - ensureCgen GoodImportcType - -block: - type Foo6{.importc.} = object - a1: cint - doAssert compiles(Foo6.sizeof) - static: doAssert not compiles(static(Foo6.sizeof)) - -when defined caseBad: - # Each case below should give a static cgen assert fail message - - block: - type BadImportcType {.importc: "unsigned char", nodecl.} = uint64 - # "sizeof" check will fail - ensureCgen BadImportcType - - block: - type Foo2AliasBad{.importc: "struct Foo2", size: 1.} = object - a: cint - ensureCgen Foo2AliasBad - - block: - type Foo5{.importc.} = array[4, cint] - ensureCgen Foo5 - - block: - type Foo5{.importc.} = array[3, bool] - ensureCgen Foo5 - - block: - type Foo6{.importc:"struct Foo6", completeStruct.} = object - a1: cint - # a2: bool # missing this should trigger assert fail - a3: cfloat - a4: ptr Foo6 - ensureCgen Foo6 - - when false: - block: - # pre-existing BUG: this should give a CT error in semcheck because `size` - # disagrees with `array[3, cint]` - type Foo5{.importc, size: 1.} = array[3, cint] - ensureCgen Foo5 diff --git a/tests/misc/msizeof5.nim.cfg b/tests/misc/msizeof5.nim.cfg deleted file mode 100644 index dc0712a8c..000000000 --- a/tests/misc/msizeof5.nim.cfg +++ /dev/null @@ -1,5 +0,0 @@ -# Do not limit number of error messages from backend compiler. -gcc.options.always %= "${gcc.options.always} -fmax-errors=100" -clang.options.always %= "${clang.options.always} -ferror-limit=100" -gcc.cpp.options.always %= "${gcc.cpp.options.always} -fmax-errors=100" -clang.cpp.options.always %= "${clang.cpp.options.always} -ferror-limit=100" diff --git a/tests/misc/mspellsuggest.nim b/tests/misc/mspellsuggest.nim deleted file mode 100644 index ad449554f..000000000 --- a/tests/misc/mspellsuggest.nim +++ /dev/null @@ -1,7 +0,0 @@ -proc fooBar4*(a: int) = discard -var fooBar9* = 0 - -var fooCar* = 0 -type FooBar* = int -type FooCar* = int -type GooBa* = int diff --git a/tests/misc/mtlsemulation.h b/tests/misc/mtlsemulation.h deleted file mode 100644 index 992977acd..000000000 --- a/tests/misc/mtlsemulation.h +++ /dev/null @@ -1,37 +0,0 @@ -#include - -struct Foo1 { - /* - uncommenting would give: - error: initializer for thread-local variable must be a constant expression - N_LIB_PRIVATE NIM_THREADVAR Foo1 g1__9brEZhPEldbVrNpdRGmWESA; - */ - // Foo1() noexcept { } - - /* - uncommenting would give: - error: type of thread-local variable has non-trivial destruction - */ - // ~Foo1() { } - int x; -}; - -struct Foo2 { - Foo2() noexcept { } - ~Foo2() { } - int x; -}; - -static int ctorCalls = 0; -static int dtorCalls = 0; - -struct Foo3 { - Foo3() noexcept { - ctorCalls = ctorCalls + 1; - x = 10; - } - ~Foo3() { - dtorCalls = dtorCalls + 1; - } - int x; -}; diff --git a/tests/misc/parsecomb.nim b/tests/misc/parsecomb.nim index 4f149cbf6..4ff2f65d2 100644 --- a/tests/misc/parsecomb.nim +++ b/tests/misc/parsecomb.nim @@ -1,7 +1,3 @@ -discard """ - matrix: "--mm:arc; --mm:refc" -""" - type Input[T] = object toks: seq[T] index: int diff --git a/tests/misc/t11634.nim b/tests/misc/t11634.nim deleted file mode 100644 index 4ecb6a53c..000000000 --- a/tests/misc/t11634.nim +++ /dev/null @@ -1,20 +0,0 @@ -discard """ - action: reject - nimout: ''' -t11634.nim(20, 7) Error: cannot destructure to compile time variable -''' -""" - -type Foo = ref object - val: int - -proc divmod(a, b: Foo): (Foo, Foo) = - ( - Foo(val: a.val div b.val), - Foo(val: a.val mod b.val) - ) - -block: - let a {.compileTime.} = Foo(val: 2) - let b {.compileTime.} = Foo(val: 3) - let (c11634 {.compileTime.}, d11634 {.compileTime.}) = divmod(a, b) diff --git a/tests/misc/t12869.nim b/tests/misc/t12869.nim deleted file mode 100644 index 731a4e95e..000000000 --- a/tests/misc/t12869.nim +++ /dev/null @@ -1,14 +0,0 @@ -discard """ - errormsg: "type mismatch: got but expected 'int'" - line: 12 -""" - -import sugar -from algorithm import sorted, SortOrder - -let a = 5 - -proc sorted*[T](a: openArray[T], key: proc(v: T): int, order = SortOrder.Ascending): seq[T] = - sorted(a, (x, y) => key(x) < key(y), order) - -echo sorted(@[9, 1, 8, 2, 6, 4, 5, 0], (x) => (a - x).abs) diff --git a/tests/misc/t14667.nim b/tests/misc/t14667.nim deleted file mode 100644 index 3034e2841..000000000 --- a/tests/misc/t14667.nim +++ /dev/null @@ -1,12 +0,0 @@ -discard """ - matrix: "--cc:vcc" - disabled: "linux" - disabled: "bsd" - disabled: "osx" - disabled: "unix" - disabled: "posix" -""" - -type A = tuple -discard () -discard default(A) diff --git a/tests/misc/t15955.nim b/tests/misc/t15955.nim deleted file mode 100644 index 7441e5398..000000000 --- a/tests/misc/t15955.nim +++ /dev/null @@ -1,22 +0,0 @@ -discard """ -joinable: false -""" - -import stdtest/specialpaths -import std/[osproc, strformat, os] - -const - nim = getCurrentCompilerExe() - buildLib = buildDir / "libD20220923T19380" - currentDir = splitFile(currentSourcePath).dir - file = currentDir / "m15955.nim" - main = currentDir / "m15955_main.nim" - - -proc runCmd(cmd: string) = - let (msg, code) = execCmdEx(cmd) - doAssert code == 0, msg - - -runCmd fmt"{nim} c -o:{buildLib} --nomain --nimMainPrefix:libA -f --app:staticlib {file}" -runCmd fmt"{nim} c -r {main}" diff --git a/tests/misc/t16244.nim b/tests/misc/t16244.nim deleted file mode 100644 index 5e8128736..000000000 --- a/tests/misc/t16244.nim +++ /dev/null @@ -1,9 +0,0 @@ -discard """ - errormsg: "type mismatch: got " - line: 9 -""" - -proc g(): auto = 1 -proc h(): auto = 1.0 - -var a = g() + h() diff --git a/tests/misc/t16264.nim b/tests/misc/t16264.nim deleted file mode 100644 index afe319e6c..000000000 --- a/tests/misc/t16264.nim +++ /dev/null @@ -1,2 +0,0 @@ -import times -doAssert low(Time) == fromUnix(0) \ No newline at end of file diff --git a/tests/misc/t16541.nim b/tests/misc/t16541.nim deleted file mode 100644 index 452327e8f..000000000 --- a/tests/misc/t16541.nim +++ /dev/null @@ -1,12 +0,0 @@ -discard """ - action: "reject" - -""" - -import strutils, sugar, nre - -proc my_replace*(s: string, r: Regex, by: string | (proc (match: string): string)): string = - nre.replace(s, r, by) - -discard my_replace("abcde", re"[bcd]", match => match.to_upper) == "aBCDe" -discard my_replace("abcde", re"[bcd]", (match: string) => match.to_upper) == "aBCDe" diff --git a/tests/misc/t17286.nim b/tests/misc/t17286.nim deleted file mode 100644 index 3a54e624e..000000000 --- a/tests/misc/t17286.nim +++ /dev/null @@ -1,16 +0,0 @@ -discard """ - cmd: "nim check -b:js $file" - action: "compile" -""" - -# bug #17286 - -import std/compilesettings - -static: - doAssert querySetting(backend) == "js" - doAssert defined(js) - doAssert not defined(c) - -import random -randomize() \ No newline at end of file diff --git a/tests/misc/t18077.nim b/tests/misc/t18077.nim deleted file mode 100644 index 6cd05d575..000000000 --- a/tests/misc/t18077.nim +++ /dev/null @@ -1,21 +0,0 @@ -discard """ - cmd: '''nim doc -d:nimTestsT18077b:4 --doccmd:"-d:nimTestsT18077 -d:nimTestsT18077b:3 --hints:off" $file''' - action: compile -""" - -# bug #18077 - -const nimTestsT18077b {.intdefine.} = 1 - -static: - when defined(nimdoc): - doAssert nimTestsT18077b == 4 - doAssert not defined(nimTestsT18077) - else: - doAssert defined(nimTestsT18077) - doAssert nimTestsT18077b == 3 - -runnableExamples: - const nimTestsT18077b {.intdefine.} = 2 - doAssert nimTestsT18077b == 3 - doAssert defined(nimTestsT18077) diff --git a/tests/misc/t18079.nim b/tests/misc/t18079.nim deleted file mode 100644 index ae64bbff9..000000000 --- a/tests/misc/t18079.nim +++ /dev/null @@ -1,15 +0,0 @@ -discard """ - matrix: "--mm:orc" -""" - -type - Foo = object - y: int - - Bar = object - x: Foo - -proc baz(state: var Bar):int = - state.x.y = 2 - state.x.y -doAssert baz((ref Bar)(x: (new Foo)[])[]) == 2 diff --git a/tests/misc/t19046.nim b/tests/misc/t19046.nim deleted file mode 100644 index b3bfec7ae..000000000 --- a/tests/misc/t19046.nim +++ /dev/null @@ -1,19 +0,0 @@ -discard """ - targets: "c cpp" - matrix: "--threads:on" - disabled: "win" - disabled: "osx" - action: compile -""" - -# bug #19046 - -import std/os - -var t: Thread[void] - -proc test = discard -proc main = - createThread(t, test) - pinToCpu(t, 1) -main() \ No newline at end of file diff --git a/tests/misc/t20253.nim b/tests/misc/t20253.nim deleted file mode 100644 index d47c36c55..000000000 --- a/tests/misc/t20253.nim +++ /dev/null @@ -1,10 +0,0 @@ -discard """ - errormsg: "'result' requires explicit initialization" - line: 10 -""" - -type Meow {.requiresInit.} = object - init: bool - -proc initMeow(): Meow = - discard diff --git a/tests/misc/t20289.nim b/tests/misc/t20289.nim deleted file mode 100644 index 5a0a269f0..000000000 --- a/tests/misc/t20289.nim +++ /dev/null @@ -1,15 +0,0 @@ -discard """ - action: reject -""" - -type E[T] = object - v: T - -template j[T](R: type E[T], x: untyped): R = R(v: x) -template d[T](O: type E, v: T): E[T] = E[T].j(v) - -proc w[T](): E[T] = - template r(k: int): auto = default(T) - E.d r - -discard w[int]() diff --git a/tests/misc/t20456_2.nim b/tests/misc/t20456_2.nim deleted file mode 100644 index 37e52c452..000000000 --- a/tests/misc/t20456_2.nim +++ /dev/null @@ -1,14 +0,0 @@ -discard """ - joinable: false -""" - -import std/[osproc, os, strformat] -from stdtest/specialpaths import testsDir - -when defined(nimPreviewSlimSystem): - import std/assertions - -const - nim = getCurrentCompilerExe() - file = testsDir / "misc" / "m20456.nims" -doAssert execCmd(fmt"{nim} check {file}") == 0 diff --git a/tests/misc/t21109.nim b/tests/misc/t21109.nim deleted file mode 100644 index 0f7980896..000000000 --- a/tests/misc/t21109.nim +++ /dev/null @@ -1,13 +0,0 @@ -discard """ - action: reject - errormsg: "type expected" - file: "iterators.nim" -""" - - -template b(j: untyped) = j -template m() = discard - -b: - for t, f in @[]: - m() diff --git a/tests/misc/t21443.nim b/tests/misc/t21443.nim deleted file mode 100644 index 70413c5b3..000000000 --- a/tests/misc/t21443.nim +++ /dev/null @@ -1,6 +0,0 @@ -import std/envvars - -# bug #19292 -putEnv("NimPutEnvTest", "test") -# bug #21122 -doAssert getEnv("NimPutEnvTest") == "test" diff --git a/tests/misc/t3482.nim b/tests/misc/t3482.nim deleted file mode 100644 index 33b3b8f40..000000000 --- a/tests/misc/t3482.nim +++ /dev/null @@ -1,15 +0,0 @@ -discard """ - action: reject - nimout: "t3482.nim(13, 8) Error: undeclared identifier: 'output'" -""" -# bug #3482 (correct behavior since 1.4.0, cgen error in 1.2.0) -template foo*(body: typed) = - if true: - body - -proc test = - foo: - var output = "" - echo output.len - -test() diff --git a/tests/misc/t5540.nim b/tests/misc/t5540.nim deleted file mode 100644 index 6a19e70e1..000000000 --- a/tests/misc/t5540.nim +++ /dev/null @@ -1,45 +0,0 @@ -# bug #5540; works in 1.2.0 -# fails in 1.0 (Error: cannot generate VM code for) -# fails in 0.18.0 (Error: type mismatch: got ) - -block: - type - Fruit = object - Yellow = object - a: int - template getColor(x: typedesc[Fruit]): typedesc = Yellow - type - Banana[T] = object - b: T - a: getColor(Fruit) - Apple[T] = object - a: T - b: getColor(T) - block: - var x: Banana[int] - doAssert x.b == 0 - doAssert x.a is Yellow - block: - var x: Apple[Fruit] - doAssert x.b is Yellow - -block: - type - Fruit = object - Yellow = object - a: int - - template getColor(x: typedesc[Fruit]): typedesc = Yellow - - type - Banana[T] = object - b: T - a: getColor(Fruit) - - Apple[T] = object - a: T - b: getColor(T) - - var x: Banana[int] - x.b = 13 - x.a.a = 17 diff --git a/tests/misc/t6549.nim b/tests/misc/t6549.nim deleted file mode 100644 index 1d7393318..000000000 --- a/tests/misc/t6549.nim +++ /dev/null @@ -1,4 +0,0 @@ - -const l = $(range[low(uint64) .. high(uint64)]) -const r = "range 0..18446744073709551615(uint64)" -doAssert l == r diff --git a/tests/misc/t8404.nim b/tests/misc/t8404.nim deleted file mode 100644 index 87991071c..000000000 --- a/tests/misc/t8404.nim +++ /dev/null @@ -1,33 +0,0 @@ -discard """ - targets: "c cpp js" -""" -template main() = - block: # bug #8404 - # can conv - template float2int(T) = - var a = -1.0 - let b = T(a) - doAssert b < 0 - let c = b + 1 - doAssert c is T - doAssert c == 0 - - float2int(int8) - float2int(int16) - float2int(int32) - float2int(int64) - - block: - # can handle middle conv - # `/` can trigger int to float - template float2int(T) = - let n = T(1 / 256) - doAssert n == 0 - - float2int(int8) - float2int(int16) - float2int(int32) - # float2int(int64) -main() -static: - main() diff --git a/tests/misc/t8545.nim b/tests/misc/t8545.nim deleted file mode 100644 index 89957e1d3..000000000 --- a/tests/misc/t8545.nim +++ /dev/null @@ -1,23 +0,0 @@ -discard """ - targets: "c cpp js" -""" - -# bug #8545 - -template bar(a: static[bool]): untyped = int - -proc main() = - proc foo1(a: static[bool]): auto = 1 - doAssert foo1(true) == 1 - - proc foo2(a: static[bool]): bar(a) = 1 - doAssert foo2(true) == 1 - - proc foo3(a: static[bool]): bar(cast[static[bool]](a)) = 1 - doAssert foo3(true) == 1 - - proc foo4(a: static[bool]): bar(static(a)) = 1 - doAssert foo4(true) == 1 - -static: main() -main() diff --git a/tests/misc/t9039.nim b/tests/misc/t9039.nim deleted file mode 100644 index 3271cd34e..000000000 --- a/tests/misc/t9039.nim +++ /dev/null @@ -1,24 +0,0 @@ -discard """ - action: reject - nimout: ''' -t9039.nim(22, 22) Error: type mismatch: got -but expression 'nesting + 1' is of type: int -''' -""" - -# bug #9039; this used to hang in 0.19.0 - - - - - -# line 15 -func default(T: typedesc[array]): T = discard -doAssert default(array[3, int]) == [0, 0, 0] -func shapeBad*[T: not char](s: openArray[T], rank: static[int], nesting = 0, parent_shape = default(array[rank, int])): array[rank, int] = - result = parent_shape - result[nesting] = s.len - when (T is seq|array): - result = shapeBad(s[0], nesting + 1, result) -let a1 = [1, 2, 3].shapeBad(rank = 1) -let a2 = [[1, 2, 3], [4, 5, 6]].shapeBad(rank = 2) diff --git a/tests/misc/t9091.nim b/tests/misc/t9091.nim deleted file mode 100644 index 6e7a98ca5..000000000 --- a/tests/misc/t9091.nim +++ /dev/null @@ -1,33 +0,0 @@ -# bug #9091 - -import streams - -block: - type Mine = ref object - a: int - - proc write(io: Stream, t: Mine) = - io.write("sure") - - let str = newStringStream() - let mi = new Mine - - str.write(mi) - str.setPosition 0 - doAssert str.readAll == "sure" - -block: - type - AObj = object - x: int - - proc foo(a: int): string = "" - - proc test(args: varargs[string, foo]) = - doAssert false - - proc test(a: AObj) = - discard - - let x = AObj() - test(x) diff --git a/tests/misc/t9710.nim b/tests/misc/t9710.nim deleted file mode 100644 index c65cb7bf4..000000000 --- a/tests/misc/t9710.nim +++ /dev/null @@ -1,6 +0,0 @@ -discard """ - matrix: "--debugger:native" -""" -# bug #9710 -for i in 1 || 200: - discard i diff --git a/tests/misc/taddr.nim b/tests/misc/taddr.nim deleted file mode 100644 index 48d4928ac..000000000 --- a/tests/misc/taddr.nim +++ /dev/null @@ -1,285 +0,0 @@ -discard """ - targets: "c cpp js" - matrix: "; -d:release" -""" - -type T = object - x: int - s: string - -var obj: T -var fieldAddr = addr(obj.x) -var objAddr = addr(obj) - -# Integer tests -var field = fieldAddr[] -doAssert field == 0 - -var objDeref = objAddr[] -doAssert objDeref.x == 0 - -# Change value -obj.x = 42 - -doAssert field == 0 -doAssert objDeref.x == 0 - -field = fieldAddr[] -objDeref = objAddr[] - -doAssert field == 42 -doAssert objDeref.x == 42 - -# String tests -obj.s = "lorem ipsum dolor sit amet" -when defined(gcArc) or defined(gcOrc): - prepareMutation(obj.s) - - -var indexAddr = addr(obj.s[2]) - -doAssert indexAddr[] == 'r' - -indexAddr[] = 'd' - -doAssert indexAddr[] == 'd' - -doAssert obj.s == "lodem ipsum dolor sit amet" - -# Bug #2148 -var x: array[2, int] -var y = addr x[1] - -y[] = 12 -doAssert(x[1] == 12) - -type - Foo = object - bar: int - -var foo: array[2, Foo] -var z = addr foo[1] - -z[].bar = 12345 -doAssert(foo[1].bar == 12345) - -var t : tuple[a, b: int] -var pt = addr t[1] -pt[] = 123 -doAssert(t.b == 123) - -#block: # Test "untyped" pointer. -proc testPtr(p: pointer, a: int) = - doAssert(a == 5) - (cast[ptr int](p))[] = 124 -var i = 123 -testPtr(addr i, 5) -doAssert(i == 124) - -var someGlobal = 5 -proc getSomeGlobalPtr(): ptr int = addr someGlobal -let someGlobalPtr = getSomeGlobalPtr() -doAssert(someGlobalPtr[] == 5) -someGlobalPtr[] = 10 -doAssert(someGlobal == 10) - -block: - # bug #14576 - # lots of these used to give: Error: internal error: genAddr: 2 - proc byLent[T](a: T): lent T = a - proc byPtr[T](a: T): ptr T = a.addr - - block: - let a = (10,11) - let (x,y) = byLent(a) - doAssert (x,y) == a - - block: # (with -d:release) bug #14578 - let a = 10 - doAssert byLent(a) == 10 - let a2 = byLent(a) - doAssert a2 == 10 - - block: - let a = [11,12] - doAssert byLent(a) == [11,12] # bug #15958 - let a2 = (11,) - doAssert byLent(a2) == (11,) - - block: - proc byLent2[T](a: seq[T]): lent T = a[1] - var a = @[20,21,22] - doAssert byLent2(a) == 21 - - block: # sanity checks - proc bar[T](a: var T): var T = a - var a = (10, 11) - let (k,v) = bar(a) - doAssert (k, v) == a - doAssert k == 10 - bar(a)[0]+=100 - doAssert a == (110, 11) - var a2 = 12 - doAssert bar(a2) == a2 - bar(a2).inc - doAssert a2 == 13 - - block: # pending bug #15959 - when false: - proc byLent2[T](a: T): lent type(a[0]) = a[0] - -proc test14420() = # bug #14420 - # s/proc/template/ would hit bug #16005 - block: - type Foo = object - x: float - - proc fn(a: var Foo): var float = - ## WAS: discard <- turn this into a comment (or a `discard`) and error disappears - # result = a.x # this works - a.x # WAS: Error: limited VM support for 'addr' - - proc fn2(a: var Foo): var float = - result = a.x # this works - a.x # WAS: Error: limited VM support for 'addr' - - var a = Foo() - discard fn(a) - discard fn2(a) - - block: - proc byLent2[T](a: T): lent T = - runnableExamples: discard - a - proc byLent3[T](a: T): lent T = - runnableExamples: discard - result = a - var a = 10 - let x3 = byLent3(a) # works - let x2 = byLent2(a) # WAS: Error: internal error: genAddr: nkStmtListExpr - - block: - type MyOption[T] = object - case has: bool - of true: - value: T - of false: - discard - func some[T](val: T): MyOption[T] = - result = MyOption[T](has: true, value: val) - func get[T](opt: MyOption[T]): lent T = - doAssert opt.has - # result = opt.value # this was ok - opt.value # this had the bug - let x = some(10) - doAssert x.get() == 10 - -template test14339() = # bug #14339 - block: - type - Node = ref object - val: int - proc bar(c: Node): var int = - var n = c # was: Error: limited VM support for 'addr' - c.val - var a = Node() - discard a.bar() - block: - type - Node = ref object - val: int - proc bar(c: Node): var int = - var n = c - doAssert n.val == n[].val - n.val - var a = Node(val: 3) - a.bar() = 5 - when nimvm: - doAssert a.val == 5 - else: - when not defined(js): # pending bug #16003 - doAssert a.val == 5 - -template testStatic15464() = # bug #15464 - proc access(s: var seq[char], i: int): var char = s[i] - proc access(s: var string, i: int): var char = s[i] - static: - var s = @['a', 'b', 'c'] - access(s, 2) = 'C' - doAssert access(s, 2) == 'C' - static: - var s = "abc" - access(s, 2) = 'C' - doAssert access(s, 2) == 'C' - -proc test15464() = # bug #15464 (v2) - proc access(s: var seq[char], i: int): var char = s[i] - proc access(s: var string, i: int): var char = s[i] - block: - var s = @['a', 'b', 'c'] - access(s, 2) = 'C' - doAssert access(s, 2) == 'C' - block: - var s = "abc" - access(s, 2) = 'C' - doAssert access(s, 2) == 'C' - -block: # bug #15939 - block: - const foo = "foo" - proc proc1(s: var string) = - if s[^1] notin {'a'..'z'}: - s = "" - proc proc2(f: string): string = - result = f - proc1(result) - const bar = proc2(foo) - doAssert bar == "foo" - -template prepareMutationForOrc(x: string) = - when defined(gcArc) or defined(gcOrc): - when nimvm: - discard - else: - prepareMutation(x) - -proc test15939() = # bug #15939 (v2) - template fn(a) = - when typeof(a) is string: - prepareMutationForOrc(a) - let pa = a[0].addr - doAssert pa != nil - doAssert pa[] == 'a' - pa[] = 'x' - doAssert pa[] == 'x' - doAssert a == "xbc" - when not defined js: # otherwise overflows - let pa2 = cast[ptr char](cast[int](pa) + 1) - doAssert pa2[] == 'b' - pa2[] = 'B' - doAssert a == "xBc" - - # mystring[ind].addr - var a = "abc" - fn(a) - - # mycstring[ind].addr - template cstringTest = - var a2 = "abc" - prepareMutationForOrc(a2) - var b2 = a2.cstring - fn(b2) - when nimvm: cstringTest() - else: # can't take address of cstring element in js - when not defined(js): cstringTest() - -template main = - # xxx wrap all other tests here like that so they're also tested in VM - test14420() - test14339() - test15464() - test15939() - -testStatic15464() -static: main() -main() diff --git a/tests/misc/tapp_lib_staticlib.nim b/tests/misc/tapp_lib_staticlib.nim deleted file mode 100644 index 92c9acbc3..000000000 --- a/tests/misc/tapp_lib_staticlib.nim +++ /dev/null @@ -1,27 +0,0 @@ -discard """ -joinable: false -""" - -# bug #16949 - -when defined case1: - proc foo(): int {.exportc.} = 10 -elif defined case2: - proc foo(): int {.exportc, dynlib.} = 10 -elif defined caseMain: - proc foo(): int {.importc.} - doAssert foo() == 10 -else: - import stdtest/specialpaths - import std/[os, strformat, strutils, compilesettings] - proc runCmd(cmd: string) = - doAssert execShellCmd(cmd) == 0, $cmd - const - file = currentSourcePath - nim = getCurrentCompilerExe() - mode = querySetting(backend) - proc test(lib, options: string) = - runCmd fmt"{nim} {mode} -o:{lib} --nomain {options} -f {file}" - # runCmd fmt"{nim} r -b:{mode} --passl:{lib} -d:caseMain -f {file}" # pending https://github.com/nim-lang/Nim/pull/16945 - test(buildDir / "libD20210205T172314.a", "--app:staticlib -d:nimLinkerWeakSymbols -d:case1") - test(buildDir / DynlibFormat % "D20210205T172720", "--app:lib -d:case2") diff --git a/tests/misc/tcast.nim b/tests/misc/tcast.nim index 6d67b1c52..a8d1cf306 100644 --- a/tests/misc/tcast.nim +++ b/tests/misc/tcast.nim @@ -10,94 +10,15 @@ type MyProc3 = proc() #{.closure.} is implicit proc testProc() = echo "Hello World" -template reject(x) = doAssert(not compiles(x)) - proc callPointer(p: pointer) = # can cast to proc(){.cdecl.} let ffunc0 = cast[MyProc](p) # can cast to proc(){.nimcall.} let ffunc1 = cast[MyProc2](p) # cannot cast to proc(){.closure.} - reject: cast[MyProc3](p) + doAssert(not compiles(cast[MyProc3](p))) ffunc0() ffunc1() callPointer(cast[pointer](testProc)) - -reject: discard cast[enum](0) -proc a = echo "hi" - -reject: discard cast[ptr](a) - -# bug #15623 -block: - if false: - let x = cast[ptr int](nil) - echo x[] - -block: - if false: - var x: ref int = nil - echo cast[ptr int](x)[] - -block: - doAssert cast[int](cast[ptr int](nil)) == 0 - -block: - var x: ref int = nil - doAssert cast[int](cast[ptr int](x)) == 0 - -block: # cast of nil - block: - static: - let a = cast[pointer](nil) - doAssert a.repr == "nil" - - block: - static: - doAssert cast[ptr int](nil).repr == "nil" - - block: - const str = cast[ptr int](nil) - static: - doAssert str.repr == "nil" - - block: - static: - doAssert cast[ptr int](nil).repr == "nil" - - block: - static: - doAssert cast[RootRef](nil).repr == "nil" - - when false: # xxx bug #15730, not fixed yet - block: - static: - doAssert cast[cstring](nil).repr == "nil" - -template main() = - # xxx move all under here to get tested in VM - block: # cast of enum - type Koo = enum k1, k2 - type Goo = enum g1, g2 - type Boo = enum b1 = -1, b2, b3, b4 - type Coo = enum c1 = -1i8, c2, c3, c4 - when nimvm: - # xxx: Error: VM does not support 'cast' from tyEnum to tyEnum - discard - else: - doAssert cast[Koo](k2) == k2 - doAssert cast[Goo](k2) == g2 - doAssert cast[Goo](k2.ord) == g2 - - doAssert b3.ord == 1 - doAssert cast[Koo](b3) == k2 - doAssert cast[Boo](k2) == b3 - - doAssert c3.ord == 1 - doAssert cast[Koo](c3) == k2 - doAssert cast[Coo](k2) == c3 - -static: main() -main() diff --git a/tests/misc/tconv.nim b/tests/misc/tconv.nim index 5e8eac729..f7d15b0b5 100644 --- a/tests/misc/tconv.nim +++ b/tests/misc/tconv.nim @@ -1,11 +1,5 @@ -discard """ - matrix: "--warningAsError:EnumConv --warningAsError:CStringConv" -""" - template reject(x) = - static: doAssert(not compiles(x)) -template accept(x) = - static: doAssert(compiles(x)) + static: assert(not compiles(x)) reject: const x = int8(300) @@ -61,60 +55,3 @@ block: # issue 3766 proc r(x: static[R]) = echo x r 3.R - - -block: # https://github.com/nim-lang/RFCs/issues/294 - type Koo = enum k1, k2 - type Goo = enum g1, g2 - - accept: Koo(k2) - accept: k2.Koo - accept: k2.int.Goo - - reject: Goo(k2) - reject: k2.Goo - reject: k2.string - - {.push warningAsError[EnumConv]:off.} - discard Goo(k2) - accept: Goo(k2) - accept: k2.Goo - reject: k2.string - {.pop.} - - reject: Goo(k2) - reject: k2.Goo - -reject: - # bug #18550 - proc f(c: char): cstring = - var x = newString(109*1024*1024) - x[0] = c - x - -{.push warning[AnyEnumConv]:on, warningAsError[AnyEnumConv]:on.} - -reject: - type - Foo = enum - one - three - - var va = 2 - var vb = va.Foo - -{.pop.} - -{.push warningAsError[HoleEnumConv]:on.} - -reject: - # bug #12815 - type - Hole = enum - one = 1 - three = 3 - - var va = 2 - var vb = va.Hole - -{.pop.} diff --git a/tests/misc/tdangerisrelease.nim b/tests/misc/tdangerisrelease.nim index e1854dca5..26ce75ac4 100644 --- a/tests/misc/tdangerisrelease.nim +++ b/tests/misc/tdangerisrelease.nim @@ -1,5 +1,6 @@ discard """ - cmd: "nim c $options -r $file" + cmd: "nim $target $options -r $file" + targets: "c cpp" matrix: "-d:danger; -d:release" output: ''' a diff --git a/tests/misc/tdefine.nim b/tests/misc/tdefine.nim index f3fa4711f..1378b8901 100644 --- a/tests/misc/tdefine.nim +++ b/tests/misc/tdefine.nim @@ -1,23 +1,12 @@ discard """ joinable: false -cmd: "nim c $options -d:booldef -d:booldef2=false -d:intdef=2 -d:strdef=foobar -d:namespaced.define=false -d:double.namespaced.define -r $file" -matrix: "; -d:useGenericDefine" +cmd: "nim c -d:booldef -d:booldef2=false -d:intdef=2 -d:strdef=foobar -r $file" """ -when defined(useGenericDefine): - {.pragma: booldefine2, define.} - {.pragma: intdefine2, define.} - {.pragma: strdefine2, define.} -else: - - {.pragma: booldefine2, booldefine.} - {.pragma: intdefine2, intdefine.} - {.pragma: strdefine2, strdefine.} - -const booldef {.booldefine2.} = false -const booldef2 {.booldefine2.} = true -const intdef {.intdefine2.} = 0 -const strdef {.strdefine2.} = "" +const booldef {.booldefine.} = false +const booldef2 {.booldefine.} = true +const intdef {.intdefine.} = 0 +const strdef {.strdefine.} = "" doAssert defined(booldef) doAssert defined(booldef2) @@ -27,51 +16,3 @@ doAssert booldef doAssert not booldef2 doAssert intdef == 2 doAssert strdef == "foobar" - -when defined(useGenericDefine): - block: - const uintdef {.define: "intdef".}: uint = 17 - doAssert intdef == int(uintdef) - const cstrdef {.define: "strdef".}: cstring = "not strdef" - doAssert $cstrdef == strdef - type FooBar = enum foo, bar, foobar - const enumdef {.define: "strdef".} = foo - doAssert $enumdef == strdef - doAssert enumdef == foobar - -# Intentionally not defined from command line -const booldef3 {.booldefine2.} = true -const intdef2 {.intdefine2.} = 1 -const strdef2 {.strdefine2.} = "abc" -type T = object - when booldef3: - field1: int - when intdef2 == 1: - field2: int - when strdef2 == "abc": - field3: int - -doAssert not defined(booldef3) -doAssert not defined(intdef2) -doAssert not defined(strdef2) -discard T(field1: 1, field2: 2, field3: 3) - -doAssert defined(namespaced.define) -const `namespaced.define` {.booldefine2.} = true -doAssert not `namespaced.define` -when defined(useGenericDefine): - const aliasToNamespacedDefine {.define: "namespaced.define".} = not `namespaced.define` -else: - const aliasToNamespacedDefine {.booldefine: "namespaced.define".} = not `namespaced.define` -doAssert aliasToNamespacedDefine == `namespaced.define` - -doAssert defined(double.namespaced.define) -const `double.namespaced.define` {.booldefine2.} = false -doAssert `double.namespaced.define` -when defined(useGenericDefine): - const aliasToDoubleNamespacedDefine {.define: "double.namespaced.define".} = not `double.namespaced.define` -else: - const aliasToDoubleNamespacedDefine {.booldefine: "double.namespaced.define".} = not `double.namespaced.define` -doAssert aliasToDoubleNamespacedDefine == `double.namespaced.define` - -doAssert not defined(namespaced.butnotdefined) diff --git a/tests/misc/temptyecho.nim b/tests/misc/temptyecho.nim index a3c407897..5f1aa6515 100644 --- a/tests/misc/temptyecho.nim +++ b/tests/misc/temptyecho.nim @@ -1,6 +1,2 @@ -discard """ -output: "\n" -""" - echo() diff --git a/tests/misc/tevents.nim b/tests/misc/tevents.nim new file mode 100644 index 000000000..045c9fc5b --- /dev/null +++ b/tests/misc/tevents.nim @@ -0,0 +1,48 @@ +discard """ +output: ''' +HandlePrintEvent: Output -> Handled print event +HandlePrintEvent2: Output -> printing for ME +HandlePrintEvent2: Output -> printing for ME +''' +""" + +import events + +type + PrintEventArgs = object of EventArgs + user*: string + +proc handleprintevent*(e: EventArgs) = + write(stdout, "HandlePrintEvent: Output -> Handled print event\n") + +proc handleprintevent2*(e: EventArgs) = + var args: PrintEventArgs = PrintEventArgs(e) + write(stdout, "HandlePrintEvent2: Output -> printing for " & args.user) + +var ee = initEventEmitter() + +var eventargs: PrintEventArgs +eventargs.user = "ME\n" + +##method one test + +ee.on("print", handleprintevent) +ee.on("print", handleprintevent2) + +ee.emit("print", eventargs) + +##method two test + +type + SomeObject = object of RootObj + printEvent: EventHandler + +var obj: SomeObject +obj.printEvent = initEventHandler("print") +obj.printEvent.addHandler(handleprintevent2) + +ee.emit(obj.printEvent, eventargs) + +obj.printEvent.removeHandler(handleprintevent2) + +ee.emit(obj.printEvent, eventargs) diff --git a/tests/misc/theaproots.nim b/tests/misc/theaproots.nim index 2dd345254..1ea3c86b9 100644 --- a/tests/misc/theaproots.nim +++ b/tests/misc/theaproots.nim @@ -28,7 +28,7 @@ proc acc(x: var Foo): var ref Bar = proc test(maybeFoo: var Foo, maybeSeq: var seq[ref Bar], - bars: var openArray[ref Bar], + bars: var openarray[ref Bar], maybeTup: var Tup) = var bb: ref Bar maybeFoo.rmaybe = bb diff --git a/tests/misc/thints_off.nim b/tests/misc/thints_off.nim deleted file mode 100644 index 5a4cadad6..000000000 --- a/tests/misc/thints_off.nim +++ /dev/null @@ -1,4 +0,0 @@ -discard """ - matrix: "--hints:off" -""" -doAssert true diff --git a/tests/misc/tints.nim b/tests/misc/tints.nim index d24cbd4ac..fa3eb42cb 100644 --- a/tests/misc/tints.nim +++ b/tests/misc/tints.nim @@ -77,9 +77,5 @@ block: # Casts to uint testCast(-5'i32, uint8, 251'u8) -# issue #7174 -let c = 1'u -let val = c > 0 -doAssert val echo("Success") #OUT Success diff --git a/tests/misc/tinvalidnewseq.nim b/tests/misc/tinvalidnewseq.nim index 7a95db020..dec00fd4a 100644 --- a/tests/misc/tinvalidnewseq.nim +++ b/tests/misc/tinvalidnewseq.nim @@ -13,7 +13,7 @@ proc parseURL(url: string): TURL = var pattern: string = r"([a-zA-Z]+://)?(\w+?\.)?(\w+)(\.\w+)(:[0-9]+)?(/.+)?" var m: array[0..6, string] #Array with the matches newSeq(m, 7) #ERROR - discard re.match(url, re(pattern), m) + discard regexprs.match(url, re(pattern), m) result = (protocol: m[1], subdomain: m[2], domain: m[3] & m[4], port: m[5], path: m[6].split('/')) diff --git a/tests/misc/tjoinable.nim b/tests/misc/tjoinable.nim deleted file mode 100644 index f23fca0d4..000000000 --- a/tests/misc/tjoinable.nim +++ /dev/null @@ -1,3 +0,0 @@ -# checks that megatest allows duplicate names, see also `tests/testament/tjoinable.nim` -doAssert defined(testing) -doAssert defined(nimMegatest) diff --git a/tests/misc/tlambdadonotation.nim b/tests/misc/tlambdadonotation.nim index 3160c0972..af51efdbf 100644 --- a/tests/misc/tlambdadonotation.nim +++ b/tests/misc/tlambdadonotation.nim @@ -67,7 +67,7 @@ proc main2() = proc foo() = subscriber.consume() - emitter.on_event() do (): + emitter.on_event() do: subscriber.consume() # this works diff --git a/tests/misc/tlocals.nim b/tests/misc/tlocals.nim index e59976102..ad9e7d032 100644 --- a/tests/misc/tlocals.nim +++ b/tests/misc/tlocals.nim @@ -1,5 +1,4 @@ discard """ - matrix: "--mm:refc; --mm:orc" output: '''(x: "string here", a: 1) b is 5 x is 12''' @@ -63,14 +62,3 @@ proc foo3[T](y: T) = bar2(y) foo3(12) - -block: # bug #12682 - template foo(): untyped = - var c1 = locals() - 1 - - proc testAll()= - doAssert foo() == 1 - let c2=locals() - - testAll() diff --git a/tests/misc/tnew.nim b/tests/misc/tnew.nim index 41ef3fa19..2d9a64461 100644 --- a/tests/misc/tnew.nim +++ b/tests/misc/tnew.nim @@ -1,5 +1,4 @@ discard """ -matrix: "--mm:refc" outputsub: ''' Simple tree node allocation worked! Simple cycle allocation worked! @@ -11,7 +10,6 @@ joinable: false # and the code generation for gc walkers # (and the garbage collector): -## todo fixme it doesn't work for ORC type PNode = ref TNode TNode = object diff --git a/tests/misc/tnoforward.nim b/tests/misc/tnoforward.nim index 0d9b40c83..3e96e3489 100644 --- a/tests/misc/tnoforward.nim +++ b/tests/misc/tnoforward.nim @@ -1,6 +1,5 @@ discard """ - matrix: "--experimental:codeReordering" - output: "10" + disabled: true """ # {. noforward: on .} diff --git a/tests/misc/tnoop.nim b/tests/misc/tnoop.nim index f55f2441a..a1365cfbe 100644 --- a/tests/misc/tnoop.nim +++ b/tests/misc/tnoop.nim @@ -1,8 +1,9 @@ discard """ nimout: ''' - found 'a' [var declared in tnoop.nim(10, 3)] + found 'a' of kind 'var' ''' file: "tnoop.nim" + line: 13 errormsg: "attempting to call routine: 'a'" """ diff --git a/tests/misc/tparseopt.nim b/tests/misc/tparseopt.nim index 47be05bac..25ce77816 100644 --- a/tests/misc/tparseopt.nim +++ b/tests/misc/tparseopt.nim @@ -22,15 +22,6 @@ kind: cmdShortOption key:val -- r:0 kind: cmdShortOption key:val -- l: kind: cmdShortOption key:val -- r:4 kind: cmdLongOption key:val -- debug: -cmdShortOption key: v value: '' -cmdArgument key: ABC value: '' -cmdShortOption key: v value: 'ABC' -cmdShortOption key: v value: '' -cmdArgument key: ABC value: '' -cmdShortOption key: v value: '' -cmdArgument key: ABC value: '' -cmdShortOption key: j value: '4' -cmdArgument key: ok value: '' ''' joinable: false """ @@ -80,7 +71,7 @@ else: import osproc, os, strutils from stdtest/specialpaths import buildDir - import stdtest/unittest_light + import "../.." / compiler/unittest_light block: # fix #9951 template runTest(parseoptCustom) = @@ -130,27 +121,3 @@ arg 3 ai.len:4 :{a4"b} arg 4 ai.len:4 :{a5'b} arg 5 ai.len:4 :{a6\b} arg 6 ai.len:4 :{a7'b}""" - - - - block: - let args = @["-v", "ABC"] - var p = parseopt.initOptParser(args, shortnoVal = {'n'}, longnoVal = @["novalue"]) - for kind, key, val in parseopt.getopt(p): - echo kind," key: ", key, " value: '", val, "'" - - var r = parseopt.initOptParser(@["-v ABC"], shortnoVal = {'n'}, longnoVal = @["novalue"]) - for kind, key, val in parseopt.getopt(r): - echo kind," key: ", key, " value: '", val, "'" - - var s = parseopt.initOptParser("-v ABC", shortnoVal = {'v'}, longnoVal = @["novalue"]) - for kind, key, val in parseopt.getopt(s): - echo kind," key: ", key, " value: '", val, "'" - - var m = parseopt.initOptParser("-v ABC", shortnoVal = {'n'}, longnoVal = @["novalue"]) - for kind, key, val in parseopt.getopt(m): - echo kind," key: ", key, " value: '", val, "'" - - var n = parseopt.initOptParser("-j4 ok", shortnoVal = {'n'}, longnoVal = @["novalue"]) - for kind, key, val in parseopt.getopt(n): - echo kind," key: ", key, " value: '", val, "'" diff --git a/tests/misc/tproveinit.nim b/tests/misc/tproveinit.nim deleted file mode 100644 index c9f688309..000000000 --- a/tests/misc/tproveinit.nim +++ /dev/null @@ -1,18 +0,0 @@ -discard """ - joinable: false -""" - -{.warningAsError[ProveInit]:on.} -template main() = - proc fn(): var int = - discard - discard fn() -doAssert not compiles(main()) - -# bug #9901 -import std/[sequtils, times] -proc parseMyDates(line: string): DateTime = - result = parse(line, "yyyy-MM-dd") -var dateStrings = @["2018-12-01", "2018-12-02", "2018-12-03"] -var parsed = dateStrings.map(parseMyDates) -discard parsed diff --git a/tests/misc/tradix.nim b/tests/misc/tradix.nim index f4fb56849..1773a9609 100644 --- a/tests/misc/tradix.nim +++ b/tests/misc/tradix.nim @@ -40,8 +40,8 @@ type TRadixNode {.pure, inheritable.} = object kind: TRadixNodeKind TRadixNodeLinear = object of TRadixNode - len: uint8 - keys: array[0..31, uint8] + len: int8 + keys: array[0..31, int8] vals: array[0..31, PRadixNode] TRadixNodeFull = object of TRadixNode @@ -49,8 +49,8 @@ type TRadixNodeLeafBits = object of TRadixNode b: array[0..7, int] TRadixNodeLeafLinear = object of TRadixNode - len: uint8 - keys: array[0..31, uint8] + len: int8 + keys: array[0..31, int8] var root: PRadixNode @@ -59,8 +59,8 @@ proc searchInner(r: PRadixNode, a: int): PRadixNode = case r.kind of rnLinear: var x = cast[ptr TRadixNodeLinear](r) - for i in 0..int(x.len)-1: - if int(x.keys[i]) == a: return x.vals[i] + for i in 0..ze(x.len)-1: + if ze(x.keys[i]) == a: return x.vals[i] of rnFull: var x = cast[ptr TRadixNodeFull](r) return x.b[a] @@ -87,8 +87,8 @@ proc searchLeaf(r: PRadixNode, a: int): bool = return testBit(x.b[a /% BitsPerUnit], a) of rnLeafLinear: var x = cast[ptr TRadixNodeLeafLinear](r) - for i in 0..int(x.len)-1: - if int(x.keys[i]) == a: return true + for i in 0..ze(x.len)-1: + if ze(x.keys[i]) == a: return true else: assert(false) proc exclLeaf(r: PRadixNode, a: int) = @@ -98,9 +98,9 @@ proc exclLeaf(r: PRadixNode, a: int) = resetBit(x.b[a /% BitsPerUnit], a) of rnLeafLinear: var x = cast[ptr TRadixNodeLeafLinear](r) - var L = int(x.len) + var L = ze(x.len) for i in 0..L-1: - if int(x.keys[i]) == a: + if ze(x.keys[i]) == a: x.keys[i] = x.keys[L-1] dec(x.len) return @@ -131,8 +131,8 @@ proc addLeaf(r: var PRadixNode, a: int): bool = # a linear node: var x = cast[ptr TRadixNodeLinear](alloc0(sizeof(TRadixNodeLinear))) x.kind = rnLeafLinear - x.len = 1'u8 - x.keys[0] = uint8(a) + x.len = 1'i8 + x.keys[0] = toU8(a) r = x return false # not already in set case r.kind @@ -141,18 +141,18 @@ proc addLeaf(r: var PRadixNode, a: int): bool = return testOrSetBit(x.b[a /% BitsPerUnit], a) of rnLeafLinear: var x = cast[ptr TRadixNodeLeafLinear](r) - var L = int(x.len) + var L = ze(x.len) for i in 0..L-1: - if int(x.keys[i]) == a: return true + if ze(x.keys[i]) == a: return true if L <= high(x.keys): - x.keys[L] = uint8(a) + x.keys[L] = toU8(a) inc(x.len) else: # transform into a full node: var y = cast[ptr TRadixNodeLeafBits](alloc0(sizeof(TRadixNodeLeafBits))) y.kind = rnLeafBits - for i in 0..int(x.len)-1: - var u = int(x.keys[i]) + for i in 0..ze(x.len)-1: + var u = ze(x.keys[i]) setBit(y.b[u /% BitsPerUnit], u) setBit(y.b[a /% BitsPerUnit], a) dealloc(r) @@ -167,26 +167,26 @@ proc addInner(r: var PRadixNode, a: int, d: int): bool = # a linear node: var x = cast[ptr TRadixNodeLinear](alloc0(sizeof(TRadixNodeLinear))) x.kind = rnLinear - x.len = 1'u8 - x.keys[0] = uint8(k) + x.len = 1'i8 + x.keys[0] = toU8(k) r = x return addInner(x.vals[0], a, d-8) case r.kind of rnLinear: var x = cast[ptr TRadixNodeLinear](r) - var L = int(x.len) + var L = ze(x.len) for i in 0..L-1: - if int(x.keys[i]) == k: # already exists + if ze(x.keys[i]) == k: # already exists return addInner(x.vals[i], a, d-8) if L <= high(x.keys): - x.keys[L] = uint8(k) + x.keys[L] = toU8(k) inc(x.len) return addInner(x.vals[L], a, d-8) else: # transform into a full node: var y = cast[ptr TRadixNodeFull](alloc0(sizeof(TRadixNodeFull))) y.kind = rnFull - for i in 0..L-1: y.b[int(x.keys[i])] = x.vals[i] + for i in 0..L-1: y.b[ze(x.keys[i])] = x.vals[i] dealloc(r) r = y return addInner(y.b[k], a, d-8) @@ -211,8 +211,8 @@ iterator innerElements(r: PRadixNode): tuple[prefix: int, n: PRadixNode] = yield (i, r.b[i]) of rnLinear: var r = cast[ptr TRadixNodeLinear](r) - for i in 0..int(r.len)-1: - yield (int(r.keys[i]), r.vals[i]) + for i in 0..ze(r.len)-1: + yield (ze(r.keys[i]), r.vals[i]) else: assert(false) iterator leafElements(r: PRadixNode): int = @@ -228,8 +228,8 @@ iterator leafElements(r: PRadixNode): int = yield i*BitsPerUnit+j of rnLeafLinear: var r = cast[ptr TRadixNodeLeafLinear](r) - for i in 0..int(r.len)-1: - yield int(r.keys[i]) + for i in 0..ze(r.len)-1: + yield ze(r.keys[i]) else: assert(false) iterator elements*(r: PRadixNode): ByteAddress {.inline.} = diff --git a/tests/misc/trangechecks.nim b/tests/misc/trangechecks.nim index e48b1272b..2c6f0f66d 100644 --- a/tests/misc/trangechecks.nim +++ b/tests/misc/trangechecks.nim @@ -14,14 +14,14 @@ var x: range[1..10] = 10 try: x += 1 echo x -except OverflowDefect, RangeDefect: +except OverflowError, RangeError: expected += 1 echo x try: inc x echo x -except OverflowDefect, RangeDefect: +except OverflowError, RangeError: expected += 1 echo x @@ -29,20 +29,15 @@ x = 1 try: x -= 1 echo x -except OverflowDefect, RangeDefect: +except OverflowError, RangeError: expected += 1 echo x try: dec x echo x -except OverflowDefect, RangeDefect: +except OverflowError, RangeError: expected += 1 echo x echo expected == 4 - -# bug #13698 -var - x45 = "hello".cstring - p = x45.len.int32 diff --git a/tests/misc/trfc405.nim b/tests/misc/trfc405.nim deleted file mode 100644 index 8c967eb77..000000000 --- a/tests/misc/trfc405.nim +++ /dev/null @@ -1,84 +0,0 @@ - -{.experimental: "flexibleOptionalParams".} - -# https://github.com/nim-lang/RFCs/issues/405 - -template main = - template fn1(a = 1, b = 2, body): auto = (a, b, astToStr(body)) - let a1 = fn1(10, 20): - foo - doAssert a1 == (10, 20, "\nfoo") - - template fn2(a = 1, b = 2, body): auto = (a, b, astToStr(body)) - let a2 = fn2(a = 10): foo - doAssert a2 == (10, 2, "\nfoo") - let a2b = fn2(b = 20): foo - doAssert a2b == (1, 20, "\nfoo") - - template fn3(x: int, a = 1, b = 2, body): auto = (a, b, astToStr(body)) - let a3 = fn3(3, 10, 20): foo - doAssert a3 == (10, 20, "\nfoo") - let a3b = fn3(3, a = 10): foo - doAssert a3b == (10, 2, "\nfoo") - - template fn4(x: int, y: int, body): auto = (x, y, astToStr(body)) - let a4 = fn4(1, 2): foo - doAssert a4 == (1, 2, "\nfoo") - - template fn5(x = 1, y = 2, body: untyped = 3): auto = (x, y, astToStr(body)) - doAssert compiles(fn5(1, 2, foo)) - doAssert not compiles(fn5(1, foo)) - - block: - # with an overload - var witness = 0 - template fn6() = discard - template fn6(procname: string, body: untyped): untyped = witness.inc - fn6("abc"): discard - assert witness == 1 - - block: - # with overloads - var witness = 0 - template fn6() = discard - template fn6(a: int) = discard - template fn6(procname: string, body: untyped): untyped = witness.inc - fn6("abc"): discard - assert witness == 1 - - template fn6(b = 1.5, body: untyped): untyped = witness.inc - fn6(1.3): discard - assert witness == 2 - - block: - var witness = 0 - template fn6(a: int) = discard - template fn6(a: string) = discard - template fn6(ignore: string, b = 1.5, body: untyped): untyped = witness.inc - fn6(""): - foobar1 - foobar2 - doAssert witness == 1 - fn6(""): discard - doAssert witness == 2 - - block: # multi block args - template fn8(a = 1, b = 2, body1: untyped, body2: untyped): auto = (a, b, astToStr(body1), astToStr(body2)) - let a1 = fn8(): - foobar1 - foobar2 - do: - foobar3 - foobar4 - doAssert a1 == (1, 2, "\nfoobar1\nfoobar2", "\nfoobar3\nfoobar4") - - let a2 = fn8(b = 20): - foobar1 - foobar2 - do: - foobar3 - foobar4 - doAssert a2 == (1, 20, "\nfoobar1\nfoobar2", "\nfoobar3\nfoobar4") - -static: main() -main() diff --git a/tests/misc/trfc_341.nim b/tests/misc/trfc_341.nim deleted file mode 100644 index 37cf675c6..000000000 --- a/tests/misc/trfc_341.nim +++ /dev/null @@ -1,27 +0,0 @@ -# test for https://github.com/nim-lang/RFCs/issues/341 -import std/json -import std/jsonutils -import std/macros - -macro fn1(a: untyped): string = newLit a.lispRepr - -doAssert fn1(a.?b.c) == """(DotExpr (Infix (Ident ".?") (Ident "a") (Ident "b")) (Ident "c"))""" - -template `.?`(a: JsonNode, b: untyped{ident}): JsonNode = - a[astToStr(b)] - -proc identity[T](a: T): T = a -proc timesTwo[T](a: T): T = a * 2 - -template main = - let a = (a1: 1, a2: "abc", a3: (a4: 2.5)) - let j = a.toJson - doAssert j.?a1.getInt == 1 - doAssert j.?a3.?a4.getFloat == 2.5 - doAssert j.?a3.?a4.getFloat.timesTwo == 5.0 - doAssert j.?a3.identity.?a4.getFloat.timesTwo == 5.0 - doAssert j.identity.?a3.identity.?a4.identity.getFloat.timesTwo == 5.0 - doAssert j.identity.?a3.?a4.identity.getFloat.timesTwo == 5.0 - -static: main() -main() diff --git a/tests/misc/trunner.nim b/tests/misc/trunner.nim deleted file mode 100644 index aca19f72d..000000000 --- a/tests/misc/trunner.nim +++ /dev/null @@ -1,440 +0,0 @@ -discard """ - targets: "c cpp" - joinable: false -""" - -## tests that don't quite fit the mold and are easier to handle via `execCmdEx` -## A few others could be added to here to simplify code. -## Note: this test is a bit slow but tests a lot of things; please don't disable. -## Note: if needed, we could use `matrix: "-d:case1; -d:case2"` to split this -## into several independent tests while retaining the common test helpers. - -import std/[strformat,os,osproc,unittest,compilesettings] -from std/sequtils import toSeq,mapIt -from std/algorithm import sorted -import stdtest/[specialpaths, unittest_light] -from std/private/globs import nativeToUnixPath -from strutils import startsWith, strip, removePrefix -from std/sugar import dup -import "$lib/../compiler/nimpaths" - -proc isDots(a: string): bool = - ## test for `hintProcessing` dots - a.startsWith(".") and a.strip(chars = {'.'}) == "" - -const - nim = getCurrentCompilerExe() - mode = querySetting(backend) - nimcache = buildDir / "nimcacheTrunner" - # instead of `querySetting(nimcacheDir)`, avoids stomping on other parallel tests - -proc runNimCmd(file, options = "", rtarg = ""): auto = - let fileabs = testsDir / file.unixToNativePath - # doAssert fileabs.fileExists, fileabs # disabled because this allows passing `nim r --eval:code fakefile` - let cmd = fmt"{nim} {mode} --hint:all:off {options} {fileabs} {rtarg}" - result = execCmdEx(cmd) - when false: # for debugging - echo cmd - echo result[0] & "\n" & $result[1] - -proc runNimCmdChk(file, options = "", rtarg = "", status = 0): string = - let (ret, status2) = runNimCmd(file, options, rtarg = rtarg) - doAssert status2 == status, $(file, options, status, status2) & "\n" & ret - ret - -proc genShellCmd(filename: string): string = - let filename = filename.quoteShell - when defined(windows): "cmd /c " & filename # or "cmd /c " ? - else: "sh " & filename - -when defined(nimTrunnerFfi): - block: # mevalffi - when defined(openbsd): - #[ - openbsd defines `#define stderr (&__sF[2])` which makes it cumbersome - for dlopen'ing inside `importcSymbol`. Instead of adding special rules - inside `importcSymbol` to handle this, we disable just the part that's - not working and will provide a more general, clean fix in future PR. - ]# - var opt = "-d:nimEvalffiStderrWorkaround" - let prefix = "" - else: - var opt = "" - let prefix = """ -hello world stderr -hi stderr -""" - let output = runNimCmdChk("vm/mevalffi.nim", fmt"{opt} --warnings:off --experimental:compiletimeFFI") - doAssert output == fmt""" -{prefix}foo -foo:100 -foo:101 -foo:102:103 -foo:102:103:104 -foo:0.03:asdf:103:105 -ret=[s1:foobar s2:foobar age:25 pi:3.14] -""", output - -elif not defined(nimTestsTrunnerDebugging): - # don't run twice the same test with `nimTrunnerFfi` - # use `-d:nimTestsTrunnerDebugging` for debugging convenience when you want to just run 1 test - import std/strutils - import std/json - template check2(msg) = doAssert msg in output, output - - block: # tests with various options `nim doc --project --index --docroot` - # regression tests for issues and PRS: #14376 #13223 #6583 ##13647 - let file = testsDir / "nimdoc/sub/mmain.nim" - let mainFname = "mmain.html" - let htmldocsDirCustom = nimcache / "htmldocsCustom" - let docroot = testsDir / "nimdoc" - let options = [ - 0: "--project", - 1: "--project --docroot", - 2: "", - 3: fmt"--outDir:{htmldocsDirCustom}", - 4: fmt"--docroot:{docroot}", - 5: "--project --useNimcache", - 6: "--index:off", - ] - - for i in 0..>> ")) == "3" # prompt depends on `nimUseLinenoise` - check3 lines[3] == "ab" - check3 lines[4] == "" - else: - check3 "3" in outp - check3 "ab" in outp - doAssert exitCode == 0 - block: - let (outp, exitCode) = run "echo 1+2; quit(2)" - check3 "3" in outp - doAssert exitCode == 2 - - block: # nimBetterRun - let file = "misc/mbetterrun.nim" - const nimcache2 = buildDir / "D20210423T185116" - removeDir nimcache2 - # related to `-d:nimBetterRun` - let opt = fmt"-r --usenimcache --nimcache:{nimcache2}" - var ret = "" - for a in @["v1", "v2", "v1", "v3"]: - ret.add runNimCmdChk(file, fmt"{opt} -d:mbetterrunVal:{a}") - ret.add runNimCmdChk(file, fmt"{opt} -d:mbetterrunVal:v2", rtarg = "arg1 arg2") - # rt arguments should not cause a recompilation - doAssert ret == """ -compiling: v1 -running: v1 -compiling: v2 -running: v2 -running: v1 -compiling: v3 -running: v3 -running: v2 -""", ret - - block: # nim dump - let cmd = fmt"{nim} dump --dump.format:json -d:D20210428T161003 --hints:off ." - let (ret, status) = execCmdEx(cmd) - doAssert status == 0 - let j = ret.parseJson - # sanity checks - doAssert "D20210428T161003" in j["defined_symbols"].to(seq[string]) - doAssert j["version"].to(string) == NimVersion - doAssert j["nimExe"].to(string) == getCurrentCompilerExe() - - block: # genscript - const nimcache2 = buildDir / "D20210524T212851" - removeDir(nimcache2) - let input = "tgenscript_fakefile" # no need for a real file, --eval is good enough - let output = runNimCmdChk(input, fmt"""--genscript --nimcache:{nimcache2.quoteShell} --eval:"echo(12345)" """) - doAssert output.len == 0, output - let ext = when defined(windows): ".bat" else: ".sh" - let filename = fmt"compile_{input}{ext}" # synchronize with `generateScript` - doAssert fileExists(nimcache2/filename), nimcache2/filename - let (outp, status) = execCmdEx(genShellCmd(filename), options = {poStdErrToStdOut}, workingDir = nimcache2) - doAssert status == 0, outp - let (outp2, status2) = execCmdEx(nimcache2 / input, options = {poStdErrToStdOut}) - doAssert outp2 == "12345\n", outp2 - doAssert status2 == 0 - - block: # UnusedImport - proc fn(opt: string, expected: string) = - let output = runNimCmdChk("pragmas/mused3.nim", fmt"--warning:all:off --warning:UnusedImport --hint:DuplicateModuleImport {opt}") - doAssert output == expected, opt & "\noutput:\n" & output & "expected:\n" & expected - fn("-d:case1"): """ -mused3.nim(13, 8) Warning: imported and not used: 'mused3b' [UnusedImport] -""" - fn("-d:case2"): "" - fn("-d:case3"): "" - fn("-d:case4"): "" - fn("-d:case5"): "" - fn("-d:case6"): "" - fn("-d:case7"): "" - fn("-d:case8"): "" - fn("-d:case9"): "" - fn("-d:case10"): "" - when false: - fn("-d:case11"): """ - Warning: imported and not used: 'm2' [UnusedImport] - """ - fn("-d:case12"): """ -mused3.nim(75, 10) Hint: duplicate import of 'mused3a'; previous import here: mused3.nim(74, 10) [DuplicateModuleImport] -""" - - block: # FieldDefect - proc fn(opt: string, expected: string) = - let output = runNimCmdChk("misc/mfield_defect.nim", fmt"-r --warning:all:off --declaredlocs {opt}", status = 1) - doAssert expected in output, opt & "\noutput:\n" & output & "expected:\n" & expected - fn("-d:case1"): """mfield_defect.nim(25, 15) Error: field 'f2' is not accessible for type 'Foo' [discriminant declared in mfield_defect.nim(14, 8)] using 'kind = k3'""" - fn("-d:case2 --gc:refc"): """mfield_defect.nim(25, 15) field 'f2' is not accessible for type 'Foo' [discriminant declared in mfield_defect.nim(14, 8)] using 'kind = k3'""" - fn("-d:case1 -b:js"): """mfield_defect.nim(25, 15) Error: field 'f2' is not accessible for type 'Foo' [discriminant declared in mfield_defect.nim(14, 8)] using 'kind = k3'""" - fn("-d:case2 -b:js"): """field 'f2' is not accessible for type 'Foo' [discriminant declared in mfield_defect.nim(14, 8)] using 'kind = k3'""" - # 3 instead of k3, because of lack of RTTI - fn("-d:case2 --gc:arc"): """mfield_defect.nim(25, 15) field 'f2' is not accessible for type 'Foo' [discriminant declared in mfield_defect.nim(14, 8)] using 'kind = 3'""" -else: - discard # only during debugging, tests added here will run with `-d:nimTestsTrunnerDebugging` enabled diff --git a/tests/misc/trunner_special.nim b/tests/misc/trunner_special.nim deleted file mode 100644 index 50a2e4d5a..000000000 --- a/tests/misc/trunner_special.nim +++ /dev/null @@ -1,31 +0,0 @@ -discard """ - targets: "c cpp" - joinable: false -""" - -#[ -Runs tests that require special treatment, e.g. because they rely on 3rd party code -or require external networking. - -xxx test all tests/untestable/* here, possibly with adjustments to make running times reasonable -]# - -import std/[strformat,os,unittest,compilesettings] -import stdtest/specialpaths - -const - nim = getCurrentCompilerExe() - mode = querySetting(backend) - -proc runCmd(cmd: string) = - let ret = execShellCmd(cmd) - check ret == 0 # allows more than 1 failure - -proc main = - let options = fmt"-b:{mode} --hints:off" - block: # SSL nimDisableCertificateValidation integration tests - runCmd fmt"{nim} r {options} -d:nimDisableCertificateValidation -d:ssl {testsDir}/untestable/thttpclient_ssl_disabled.nim" - block: # SSL certificate check integration tests - runCmd fmt"{nim} r {options} -d:ssl --threads:on --mm:refc {testsDir}/untestable/thttpclient_ssl_remotenetwork.nim" - -main() diff --git a/tests/misc/tsemfold.nim b/tests/misc/tsemfold.nim index 2ce8d9560..486ddc5a6 100644 --- a/tests/misc/tsemfold.nim +++ b/tests/misc/tsemfold.nim @@ -2,25 +2,25 @@ discard """ action: run """ -doAssertRaises(OverflowDefect): discard low(int8) - 1'i8 -doAssertRaises(OverflowDefect): discard high(int8) + 1'i8 -doAssertRaises(OverflowDefect): discard abs(low(int8)) -doAssertRaises(DivByZeroDefect): discard 1 mod 0 -doAssertRaises(DivByZeroDefect): discard 1 div 0 -doAssertRaises(OverflowDefect): discard low(int8) div -1'i8 +doAssertRaises(OverflowError): discard low(int8) - 1'i8 +doAssertRaises(OverflowError): discard high(int8) + 1'i8 +doAssertRaises(OverflowError): discard abs(low(int8)) +doAssertRaises(DivByZeroError): discard 1 mod 0 +doAssertRaises(DivByZeroError): discard 1 div 0 +doAssertRaises(OverflowError): discard low(int8) div -1'i8 -doAssertRaises(OverflowDefect): discard -low(int64) -doAssertRaises(OverflowDefect): discard low(int64) - 1'i64 -doAssertRaises(OverflowDefect): discard high(int64) + 1'i64 +doAssertRaises(OverflowError): discard -low(int64) +doAssertRaises(OverflowError): discard low(int64) - 1'i64 +doAssertRaises(OverflowError): discard high(int64) + 1'i64 type E = enum eA, eB -doAssertRaises(OverflowDefect): discard eA.pred -doAssertRaises(OverflowDefect): discard eB.succ +doAssertRaises(OverflowError): discard eA.pred +doAssertRaises(OverflowError): discard eB.succ -doAssertRaises(OverflowDefect): discard low(int8) * -1 -doAssertRaises(OverflowDefect): discard low(int64) * -1 -doAssertRaises(OverflowDefect): discard high(int8) * 2 -doAssertRaises(OverflowDefect): discard high(int64) * 2 +doAssertRaises(OverflowError): discard low(int8) * -1 +doAssertRaises(OverflowError): discard low(int64) * -1 +doAssertRaises(OverflowError): discard high(int8) * 2 +doAssertRaises(OverflowError): discard high(int64) * 2 doAssert abs(-1) == 1 doAssert 2 div 2 == 1 diff --git a/tests/misc/tsimplesort.nim b/tests/misc/tsimplesort.nim index 395db55e6..e4a8e0b37 100644 --- a/tests/misc/tsimplesort.nim +++ b/tests/misc/tsimplesort.nim @@ -10,7 +10,7 @@ type TSlotEnum = enum seEmpty, seFilled, seDeleted TKeyValuePair[A, B] = tuple[slot: TSlotEnum, key: A, val: B] TKeyValuePairSeq[A, B] = seq[TKeyValuePair[A, B]] - TTable*[A, B] {.final, myShallow.} = object + TTable* {.final, myShallow.}[A, B] = object data: TKeyValuePairSeq[A, B] counter: int @@ -112,7 +112,7 @@ proc initTable*[A, B](initialSize=64): TTable[A, B] = result.counter = 0 newSeq(result.data, initialSize) -proc toTable*[A, B](pairs: openArray[tuple[key: A, +proc toTable*[A, B](pairs: openarray[tuple[key: A, val: B]]): TTable[A, B] = ## creates a new hash table that contains the given `pairs`. result = initTable[A, B](nextPowerOfTwo(pairs.len+10)) @@ -137,7 +137,8 @@ proc `$`*[A, B](t: TTable[A, B]): string = # ------------------------------ count tables ------------------------------- type - TCountTable*[A] {.final, myShallow.} = object ## table that counts the number of each key + TCountTable* {.final, myShallow.}[ + A] = object ## table that counts the number of each key data: seq[tuple[key: A, val: int]] counter: int diff --git a/tests/misc/tsizeof.nim b/tests/misc/tsizeof.nim index 0d96a5e04..7b92d3639 100644 --- a/tests/misc/tsizeof.nim +++ b/tests/misc/tsizeof.nim @@ -78,7 +78,7 @@ macro c_offsetof(fieldAccess: typed): int32 = ## Bullet proof implementation that works on actual offsetof operator ## in the c backend. Assuming of course this implementation is ## correct. - let s = if fieldAccess.kind == nnkCheckedFieldExpr: fieldAccess[0] + let s = if fieldAccess.kind == nnkCheckedFieldExpr: fieldAccess[0] else: fieldAccess let a = s[0].getTypeInst let b = s[1] @@ -346,31 +346,6 @@ testinstance: c: char d: int32 # unaligned - Kind = enum - K1, K2 - - AnotherEnum = enum - X1, X2, X3 - - MyObject = object - s: string - case k: Kind - of K1: nil - of K2: - x: float - y: int32 - z: AnotherEnum - - Stack[N: static int, T: object] = object - pad: array[128 - sizeof(array[N, ptr T]) - sizeof(int) - sizeof(pointer), byte] - stack: array[N, ptr T] - len*: int - rawMem: ptr array[N, T] - - Stack2[T: object] = object - pad: array[128 - sizeof(array[sizeof(T), ptr T]), byte] - - const trivialSize = sizeof(TrivialType) # needs to be able to evaluate at compile time proc main(): void = @@ -386,9 +361,6 @@ testinstance: var go : GenericObject[int64] var po : PaddingOfSetEnum33 var capo: MyCustomAlignPackedObject - var issue15516: MyObject - var issue12636_1: Stack[5, MyObject] - var issue12636_2: Stack2[MyObject] var e1: Enum1 @@ -407,7 +379,7 @@ testinstance: else: doAssert sizeof(SimpleAlignment) > 10 - testSizeAlignOf(t,a,b,c,d,e,f,g,ro,go,po, e1, e2, e4, e8, eoa, eob, capo, issue15516, issue12636_1, issue12636_2) + testSizeAlignOf(t,a,b,c,d,e,f,g,ro,go,po, e1, e2, e4, e8, eoa, eob, capo) type WithBitsize {.objectconfig.} = object @@ -714,21 +686,3 @@ reject: reject: const off8 = offsetof(MyPackedCaseObject, val5) - - -type - O0 = object - T0 = tuple[] - -doAssert sizeof(O0) == 1 -doAssert sizeof(T0) == 1 - - -type - # this thing may not have padding bytes at the end - PackedUnion* {.union, packed.} = object - a*: array[11, byte] - b*: int64 - -doAssert sizeof(PackedUnion) == 11 -doAssert alignof(PackedUnion) == 1 diff --git a/tests/misc/tsizeof2.nim b/tests/misc/tsizeof2.nim index da28de508..a193cf7c3 100644 --- a/tests/misc/tsizeof2.nim +++ b/tests/misc/tsizeof2.nim @@ -1,5 +1,5 @@ discard """ -errormsg: "'sizeof' requires '.importc' types to be '.completeStruct'" +errormsg: "cannot evaluate 'sizeof' because its type is not defined completely" line: 9 """ diff --git a/tests/misc/tsizeof3.nim b/tests/misc/tsizeof3.nim index f0ba8c4d0..1215b4bcd 100644 --- a/tests/misc/tsizeof3.nim +++ b/tests/misc/tsizeof3.nim @@ -27,32 +27,3 @@ type static: doAssert(compiles(offsetOf(Payload, vals))) - - -type - GoodboySave* {.bycopy.} = object - saveCount: uint8 - savePoint: uint16 - shards: uint32 - friendCount: uint8 - friendCards: set[0..255] - locationsKnown: set[0..127] - locationsUnlocked: set[0..127] - pickupsObtained: set[0..127] - pickupsUsed: set[0..127] - pickupCount: uint8 - -block: # bug #20914 - block: - proc csizeof[T](a: T): int {.importc:"sizeof", nodecl.} - - var s: GoodboySave - doAssert sizeof(s) == 108 - doAssert csizeof(s) == static(sizeof(s)) - - block: - proc calignof[T](a: T): int {.importc:"alignof", header: "".} - - var s: set[0..256] - doAssert alignof(s) == 1 - doAssert calignof(s) == static(alignof(s)) diff --git a/tests/misc/tslices.nim b/tests/misc/tslices.nim index 987b50de1..d063c5ebf 100644 --- a/tests/misc/tslices.nim +++ b/tests/misc/tslices.nim @@ -11,9 +11,10 @@ verichtetd # Test the new slices. +import strutils + var mystr = "Abgrund" -# mystr[..1] = "Zu" # deprecated -mystr[0..1] = "Zu" +mystr[..1] = "Zu" mystr[4..4] = "5" @@ -22,8 +23,7 @@ type var myarr: array[TEnum, int] = [1, 2, 3, 4, 5, 6] myarr[e1..e3] = myarr[e4..e6] -# myarr[..e3] = myarr[e4..e6] # deprecated -myarr[0..e3] = myarr[e4..e6] +myarr[..e3] = myarr[e4..e6] for x in items(myarr): stdout.write(x) echo() @@ -46,8 +46,7 @@ echo mystr mystr[4..4] = "u" # test full replacement -# mystr[.. ^2] = "egerichtet" # deprecated -mystr[0 .. ^2] = "egerichtet" +mystr[.. ^2] = "egerichtet" echo mystr diff --git a/tests/misc/tspellsuggest.nim b/tests/misc/tspellsuggest.nim deleted file mode 100644 index 345458bb1..000000000 --- a/tests/misc/tspellsuggest.nim +++ /dev/null @@ -1,45 +0,0 @@ -discard """ - # pending bug #16521 (bug 12) use `matrix` - cmd: "nim c --spellsuggest:15 --hints:off $file" - action: "reject" - nimout: ''' -tspellsuggest.nim(45, 13) Error: undeclared identifier: 'fooBar' -candidates (edit distance, scope distance); see '--spellSuggest': - (1, 0): 'fooBar8' - (1, 1): 'fooBar7' - (1, 3): 'fooBar1' - (1, 3): 'fooBar2' - (1, 3): 'fooBar3' - (1, 3): 'fooBar4' - (1, 3): 'fooBar5' - (1, 3): 'fooBar6' - (1, 5): 'FooBar' - (1, 5): 'fooBar4' - (1, 5): 'fooBar9' - (1, 5): 'fooCar' - (2, 5): 'FooCar' - (2, 5): 'GooBa' - (3, 0): 'fooBarBaz' -''' -""" - -# tests `--spellsuggest:num` - - - -# line 30 -import ./mspellsuggest - -var fooBar1 = 0 -let fooBar2 = 0 -const fooBar3 = 0 -proc fooBar4() = discard -template fooBar5() = discard -macro fooBar6() = discard - -proc main = - var fooBar7 = 0 - block: - var fooBar8 = 0 - const fooBarBaz = 0 - let x = fooBar diff --git a/tests/misc/tspellsuggest2.nim b/tests/misc/tspellsuggest2.nim deleted file mode 100644 index bf76cc208..000000000 --- a/tests/misc/tspellsuggest2.nim +++ /dev/null @@ -1,45 +0,0 @@ -discard """ - # pending bug #16521 (bug 12) use `matrix` - cmd: "nim c --spellsuggest --hints:off $file" - action: "reject" - nimout: ''' -tspellsuggest2.nim(45, 13) Error: undeclared identifier: 'fooBar' -candidates (edit distance, scope distance); see '--spellSuggest': - (1, 0): 'fooBar8' - (1, 1): 'fooBar7' - (1, 3): 'fooBar1' - (1, 3): 'fooBar2' - (1, 3): 'fooBar3' - (1, 3): 'fooBar4' - (1, 3): 'fooBar5' - (1, 3): 'fooBar6' - (1, 5): 'FooBar' - (1, 5): 'fooBar4' - (1, 5): 'fooBar9' - (1, 5): 'fooCar' -''' -""" - -# tests `--spellsuggest` - - - - - - -# line 30 -import ./mspellsuggest - -var fooBar1 = 0 -let fooBar2 = 0 -const fooBar3 = 0 -proc fooBar4() = discard -template fooBar5() = discard -macro fooBar6() = discard - -proc main = - var fooBar7 = 0 - block: - var fooBar8 = 0 - const fooBarBaz = 0 - let x = fooBar diff --git a/tests/misc/tspellsuggest3.nim b/tests/misc/tspellsuggest3.nim deleted file mode 100644 index 9b0b84602..000000000 --- a/tests/misc/tspellsuggest3.nim +++ /dev/null @@ -1,21 +0,0 @@ -discard """ - # pending bug #16521 (bug 12) use `matrix` - cmd: "nim c --spellsuggest:4 --hints:off $file" - action: "reject" - nimout: ''' -tspellsuggest3.nim(21, 1) Error: undeclared identifier: 'fooBar' -candidates (edit distance, scope distance); see '--spellSuggest': - (1, 2): 'FooBar' - (1, 2): 'fooBar4' - (1, 2): 'fooBar9' - (1, 2): 'fooCar' -''' -""" - -import ./mspellsuggest -import ./mspellsuggest -import ./mspellsuggest -import ./mspellsuggest - - -fooBar diff --git a/tests/misc/tstrtabs.nim b/tests/misc/tstrtabs.nim deleted file mode 100644 index 2f7eda9f7..000000000 --- a/tests/misc/tstrtabs.nim +++ /dev/null @@ -1,20 +0,0 @@ -discard """ - targets: "c cpp js" -""" - -import std/strtabs - -proc fun()= - let ret = newStringTable(modeCaseSensitive) - ret["foo"] = "bar" - - doAssert $ret == "{foo: bar}" - - let b = ret["foo"] - doAssert b == "bar" - -proc main()= - static: fun() - fun() - -main() diff --git a/tests/misc/ttlsemulation.nim b/tests/misc/ttlsemulation.nim deleted file mode 100644 index 767a9bd4e..000000000 --- a/tests/misc/ttlsemulation.nim +++ /dev/null @@ -1,76 +0,0 @@ -discard """ - disabled: i386 - matrix: "-d:nimTtlsemulationCase1 --threads --tlsEmulation:on; -d:nimTtlsemulationCase2 --threads --tlsEmulation:off; -d:nimTtlsemulationCase3 --threads" - targets: "c cpp" -""" - -#[ -tests for: `.cppNonPod`, `--tlsEmulation` -]# - -import std/sugar - -block: - # makes sure the logic in config/nim.cfg or testament doesn't interfere with `--tlsEmulation` so we test the right thing. - when defined(nimTtlsemulationCase1): - doAssert compileOption("tlsEmulation") - elif defined(nimTtlsemulationCase2): - doAssert not compileOption("tlsEmulation") - elif defined(nimTtlsemulationCase3): - when defined(osx): - doAssert not compileOption("tlsEmulation") - else: - doAssert false - -block: - proc main1(): int = - var g0 {.threadvar.}: int - g0.inc - g0 - let s = collect: - for i in 0..<3: main1() - doAssert s == @[1,2,3] - -when defined(cpp): # bug #16752 - when defined(windows) and defined(nimTtlsemulationCase2): - discard # xxx this failed with exitCode 1 - else: - type Foo1 {.importcpp: "Foo1", header: "mtlsemulation.h".} = object - x: cint - type Foo2 {.cppNonPod, importcpp: "Foo2", header: "mtlsemulation.h".} = object - x: cint - - var ctorCalls {.importcpp.}: cint - var dtorCalls {.importcpp.}: cint - type Foo3 {.cppNonPod, importcpp: "Foo3", header: "mtlsemulation.h".} = object - x: cint - - proc sub(i: int) = - var g1 {.threadvar.}: Foo1 - var g2 {.threadvar.}: Foo2 - var g3 {.threadvar.}: Foo3 - discard g1 - discard g2 - - # echo (g3.x, ctorCalls, dtorCalls) - when compileOption("tlsEmulation"): - # xxx bug - discard - else: - doAssert g3.x.int == 10 + i - doAssert ctorCalls == 2 - doAssert dtorCalls == 1 - g3.x.inc - - proc main() = - doAssert ctorCalls == 0 - doAssert dtorCalls == 0 - block: - var f3: Foo3 - doAssert f3.x == 10 - doAssert ctorCalls == 1 - doAssert dtorCalls == 1 - - for i in 0..<3: - sub(i) - main() diff --git a/tests/misc/tunsignedcomp.nim b/tests/misc/tunsignedcomp.nim index 970c4ae9d..19c8876b1 100644 --- a/tests/misc/tunsignedcomp.nim +++ b/tests/misc/tunsignedcomp.nim @@ -10,127 +10,127 @@ discard """ # unsigned < signed -doAssert 10'u8 < 20'i8 -doAssert 10'u8 < 20'i16 -doAssert 10'u8 < 20'i32 -doAssert 10'u8 < 20'i64 +assert 10'u8 < 20'i8 +assert 10'u8 < 20'i16 +assert 10'u8 < 20'i32 +assert 10'u8 < 20'i64 -doAssert 10'u16 < 20'i8 -doAssert 10'u16 < 20'i16 -doAssert 10'u16 < 20'i32 -doAssert 10'u16 < 20'i64 +assert 10'u16 < 20'i8 +assert 10'u16 < 20'i16 +assert 10'u16 < 20'i32 +assert 10'u16 < 20'i64 -doAssert 10'u32 < 20'i8 -doAssert 10'u32 < 20'i16 -doAssert 10'u32 < 20'i32 -doAssert 10'u32 < 20'i64 +assert 10'u32 < 20'i8 +assert 10'u32 < 20'i16 +assert 10'u32 < 20'i32 +assert 10'u32 < 20'i64 -# doAssert 10'u64 < 20'i8 -# doAssert 10'u64 < 20'i16 -# doAssert 10'u64 < 20'i32 -# doAssert 10'u64 < 20'i64 +# assert 10'u64 < 20'i8 +# assert 10'u64 < 20'i16 +# assert 10'u64 < 20'i32 +# assert 10'u64 < 20'i64 # signed < unsigned -doAssert 10'i8 < 20'u8 -doAssert 10'i8 < 20'u16 -doAssert 10'i8 < 20'u32 -# doAssert 10'i8 < 20'u64 +assert 10'i8 < 20'u8 +assert 10'i8 < 20'u16 +assert 10'i8 < 20'u32 +# assert 10'i8 < 20'u64 -doAssert 10'i16 < 20'u8 -doAssert 10'i16 < 20'u16 -doAssert 10'i16 < 20'u32 -# doAssert 10'i16 < 20'u64 +assert 10'i16 < 20'u8 +assert 10'i16 < 20'u16 +assert 10'i16 < 20'u32 +# assert 10'i16 < 20'u64 -doAssert 10'i32 < 20'u8 -doAssert 10'i32 < 20'u16 -doAssert 10'i32 < 20'u32 -# doAssert 10'i32 < 20'u64 +assert 10'i32 < 20'u8 +assert 10'i32 < 20'u16 +assert 10'i32 < 20'u32 +# assert 10'i32 < 20'u64 -doAssert 10'i64 < 20'u8 -doAssert 10'i64 < 20'u16 -doAssert 10'i64 < 20'u32 -# doAssert 10'i64 < 20'u64 +assert 10'i64 < 20'u8 +assert 10'i64 < 20'u16 +assert 10'i64 < 20'u32 +# assert 10'i64 < 20'u64 # unsigned <= signed -doAssert 10'u8 <= 20'i8 -doAssert 10'u8 <= 20'i16 -doAssert 10'u8 <= 20'i32 -doAssert 10'u8 <= 20'i64 +assert 10'u8 <= 20'i8 +assert 10'u8 <= 20'i16 +assert 10'u8 <= 20'i32 +assert 10'u8 <= 20'i64 -doAssert 10'u16 <= 20'i8 -doAssert 10'u16 <= 20'i16 -doAssert 10'u16 <= 20'i32 -doAssert 10'u16 <= 20'i64 +assert 10'u16 <= 20'i8 +assert 10'u16 <= 20'i16 +assert 10'u16 <= 20'i32 +assert 10'u16 <= 20'i64 -doAssert 10'u32 <= 20'i8 -doAssert 10'u32 <= 20'i16 -doAssert 10'u32 <= 20'i32 -doAssert 10'u32 <= 20'i64 +assert 10'u32 <= 20'i8 +assert 10'u32 <= 20'i16 +assert 10'u32 <= 20'i32 +assert 10'u32 <= 20'i64 -# doAssert 10'u64 <= 20'i8 -# doAssert 10'u64 <= 20'i16 -# doAssert 10'u64 <= 20'i32 -# doAssert 10'u64 <= 20'i64 +# assert 10'u64 <= 20'i8 +# assert 10'u64 <= 20'i16 +# assert 10'u64 <= 20'i32 +# assert 10'u64 <= 20'i64 # signed <= unsigned -doAssert 10'i8 <= 20'u8 -doAssert 10'i8 <= 20'u16 -doAssert 10'i8 <= 20'u32 -# doAssert 10'i8 <= 20'u64 +assert 10'i8 <= 20'u8 +assert 10'i8 <= 20'u16 +assert 10'i8 <= 20'u32 +# assert 10'i8 <= 20'u64 -doAssert 10'i16 <= 20'u8 -doAssert 10'i16 <= 20'u16 -doAssert 10'i16 <= 20'u32 -# doAssert 10'i16 <= 20'u64 +assert 10'i16 <= 20'u8 +assert 10'i16 <= 20'u16 +assert 10'i16 <= 20'u32 +# assert 10'i16 <= 20'u64 -doAssert 10'i32 <= 20'u8 -doAssert 10'i32 <= 20'u16 -doAssert 10'i32 <= 20'u32 -# doAssert 10'i32 <= 20'u64 +assert 10'i32 <= 20'u8 +assert 10'i32 <= 20'u16 +assert 10'i32 <= 20'u32 +# assert 10'i32 <= 20'u64 -doAssert 10'i64 <= 20'u8 -doAssert 10'i64 <= 20'u16 -doAssert 10'i64 <= 20'u32 -# doAssert 10'i64 <= 20'u64 +assert 10'i64 <= 20'u8 +assert 10'i64 <= 20'u16 +assert 10'i64 <= 20'u32 +# assert 10'i64 <= 20'u64 # signed == unsigned -doAssert 10'i8 == 10'u8 -doAssert 10'i8 == 10'u16 -doAssert 10'i8 == 10'u32 -# doAssert 10'i8 == 10'u64 +assert 10'i8 == 10'u8 +assert 10'i8 == 10'u16 +assert 10'i8 == 10'u32 +# assert 10'i8 == 10'u64 -doAssert 10'i16 == 10'u8 -doAssert 10'i16 == 10'u16 -doAssert 10'i16 == 10'u32 -# doAssert 10'i16 == 10'u64 +assert 10'i16 == 10'u8 +assert 10'i16 == 10'u16 +assert 10'i16 == 10'u32 +# assert 10'i16 == 10'u64 -doAssert 10'i32 == 10'u8 -doAssert 10'i32 == 10'u16 -doAssert 10'i32 == 10'u32 -# doAssert 10'i32 == 10'u64 +assert 10'i32 == 10'u8 +assert 10'i32 == 10'u16 +assert 10'i32 == 10'u32 +# assert 10'i32 == 10'u64 -doAssert 10'i64 == 10'u8 -doAssert 10'i64 == 10'u16 -doAssert 10'i64 == 10'u32 -# doAssert 10'i64 == 10'u64 +assert 10'i64 == 10'u8 +assert 10'i64 == 10'u16 +assert 10'i64 == 10'u32 +# assert 10'i64 == 10'u64 # unsigned == signed -doAssert 10'u8 == 10'i8 -doAssert 10'u8 == 10'i16 -doAssert 10'u8 == 10'i32 -# doAssert 10'u8 == 10'i64 +assert 10'u8 == 10'i8 +assert 10'u8 == 10'i16 +assert 10'u8 == 10'i32 +# assert 10'u8 == 10'i64 -doAssert 10'u16 == 10'i8 -doAssert 10'u16 == 10'i16 -doAssert 10'u16 == 10'i32 -# doAssert 10'u16 == 10'i64 +assert 10'u16 == 10'i8 +assert 10'u16 == 10'i16 +assert 10'u16 == 10'i32 +# assert 10'u16 == 10'i64 -doAssert 10'u32 == 10'i8 -doAssert 10'u32 == 10'i16 -doAssert 10'u32 == 10'i32 -# doAssert 10'u32 == 10'i64 +assert 10'u32 == 10'i8 +assert 10'u32 == 10'i16 +assert 10'u32 == 10'i32 +# assert 10'u32 == 10'i64 -# doAssert 10'u64 == 10'i8 -# doAssert 10'u64 == 10'i16 -# doAssert 10'u64 == 10'i32 -# doAssert 10'u64 == 10'i64 +# assert 10'u64 == 10'i8 +# assert 10'u64 == 10'i16 +# assert 10'u64 == 10'i32 +# assert 10'u64 == 10'i64 diff --git a/tests/misc/tunsignedconv.nim b/tests/misc/tunsignedconv.nim index c32f85b4d..17d137947 100644 --- a/tests/misc/tunsignedconv.nim +++ b/tests/misc/tunsignedconv.nim @@ -1,4 +1,6 @@ + # Tests unsigned literals and implicit conversion between uints and ints +# Passes if it compiles var h8:uint8 = 128 var h16:uint16 = 32768 @@ -41,57 +43,3 @@ block t4176: var yyy: uint8 = 0 yyy = yyy - 127 doAssert type(yyy) is uint8 - -# bug #13661 - -proc fun(): uint = cast[uint](-1) -const x0 = fun() - -doAssert typeof(x0) is uint - -discard $x0 - -# bug #13671 - -const x1 = cast[uint](-1) -discard $(x1,) - -# bug #13698 -let n2: csize_t = 1 -doAssert $n2.int32 == "1" - -# bug #14616 - -let limit = 1'u64 - -let rangeVar = 0'u64 ..< limit - -when not defined(gcRefc): - doAssert repr(rangeVar) == """0 .. 0""", repr(rangeVar) - -# bug #15210 - -let a3 = not 0'u64 -var success = false -try: - discard a3.int64 -except RangeDefect: - success = true - -doAssert success, "conversion should fail at runtime" - -template main() = - # xxx move all tests under here so it gets tested in CT and RT - block: # bug #17572 - type T = distinct uint64 - func f(x: uint64): auto = - let a = T(x) - (x, a.uint64) - const x = 1'u64 shl 63 or 7 - const b = T(x) - doAssert b.uint64 == 9223372036854775815'u64 - doAssert $b.uint64 == "9223372036854775815" - doAssert f(x) == (9223372036854775815'u64, 9223372036854775815'u64) - -static: main() -main() diff --git a/tests/misc/tunsignedinc.nim b/tests/misc/tunsignedinc.nim index 9d1a4bbb4..6d1b627d6 100644 --- a/tests/misc/tunsignedinc.nim +++ b/tests/misc/tunsignedinc.nim @@ -1,8 +1,8 @@ block: # bug #2427 var x = 0'u8 - dec x # OverflowDefect - x -= 1 # OverflowDefect + dec x # OverflowError + x -= 1 # OverflowError x = x - 1 # No error doAssert(x == 253'u8) diff --git a/tests/misc/tupcomingfeatures.nim b/tests/misc/tupcomingfeatures.nim new file mode 100644 index 000000000..d37ce85cf --- /dev/null +++ b/tests/misc/tupcomingfeatures.nim @@ -0,0 +1,35 @@ +discard """ + output: '''0 -2 0 +0 -2''' +""" + +{.this: self.} + +type + Foo = object + a, b, x: int + +proc yay(self: Foo) = + echo a, " ", b, " ", x + +proc footest[T](self: var Foo, a: T) = + b = 1+a + yay() + +proc nongeneric(self: Foo) = + echo a, " ", b + +var ff: Foo +footest(ff, -3) +ff.nongeneric + +{.experimental.} +using + c: Foo + x, y: int + +proc usesSig(c) = + echo "yummy" + +proc foobar(c, y) = + echo "yay" diff --git a/tests/misc/tvarious1.nim b/tests/misc/tvarious1.nim index 9c912ee8e..9c0b541db 100644 --- a/tests/misc/tvarious1.nim +++ b/tests/misc/tvarious1.nim @@ -46,13 +46,3 @@ echo value var ys = @[4.1, 5.6, 7.2, 1.7, 9.3, 4.4, 3.2] #var x = int(ys.high / 2) #echo ys[x] # Works echo ys[int(ys.high / 2)] # Doesn't work - - -# bug #19680 -var here = "" -when stderr is static: - doAssert false -else: - here = "works" - -doAssert here == "works" diff --git a/tests/misc/tvarnums.nim b/tests/misc/tvarnums.nim index 498099c49..2aef242e1 100644 --- a/tests/misc/tvarnums.nim +++ b/tests/misc/tvarnums.nim @@ -7,7 +7,7 @@ import strutils type - TBuffer = array[0..10, uint8] + TBuffer = array[0..10, int8] proc toVarNum(x: int32, b: var TBuffer) = # encoding: first bit indicates end of number (0 if at end) @@ -21,11 +21,11 @@ proc toVarNum(x: int32, b: var TBuffer) = # anyway a = abs(x) # first 6 bits: - b[0] = uint8(ord(a >% 63'i32) shl 7 or (ord(x < 0'i32) shl 6) or (int(a) and 63)) + b[0] = toU8(ord(a >% 63'i32) shl 7 or (ord(x < 0'i32) shl 6) or (int(a) and 63)) a = (a shr 6'i32) and 0x03ffffff # skip first 6 bits var i = 1 while a != 0'i32: - b[i] = uint8(ord(a >% 127'i32) shl 7 or (int(a) and 127)) + b[i] = toU8(ord(a >% 127'i32) shl 7 or (int(a) and 127)) inc(i) a = a shr 7'i32 @@ -41,40 +41,40 @@ proc toVarNum64(x: int64, b: var TBuffer) = # anyway a = abs(x) # first 6 bits: - b[0] = uint8(ord(a >% 63'i64) shl 7 or (ord(x < 0'i64) shl 6) or int(a and 63)) + b[0] = toU8(ord(a >% 63'i64) shl 7 or (ord(x < 0'i64) shl 6) or int(a and 63)) a = (a shr 6) and 0x03ffffffffffffff # skip first 6 bits var i = 1 while a != 0'i64: - b[i] = uint8(ord(a >% 127'i64) shl 7 or int(a and 127)) + b[i] = toU8(ord(a >% 127'i64) shl 7 or int(a and 127)) inc(i) a = a shr 7 proc toNum64(b: TBuffer): int64 = # treat first byte different: - result = int64(b[0]) and 63 + result = ze64(b[0]) and 63 var i = 0 Shift = 6'i64 - while (int(b[i]) and 128) != 0: + while (ze(b[i]) and 128) != 0: inc(i) - result = result or ((int64(b[i]) and 127) shl Shift) + result = result or ((ze64(b[i]) and 127) shl Shift) inc(Shift, 7) - if (int(b[0]) and 64) != 0: # sign bit set? + if (ze(b[0]) and 64) != 0: # sign bit set? result = not result +% 1 # this is the same as ``- result`` # but gives no overflow error for low(int) proc toNum(b: TBuffer): int32 = # treat first byte different: - result = int32(b[0]) and 63 + result = int32 ze(b[0]) and 63 var i = 0 Shift = 6'i32 - while (int(b[i]) and 128) != 0: + while (ze(b[i]) and 128) != 0: inc(i) - result = result or ((int32(b[i]) and 127'i32) shl Shift) + result = result or ((int32(ze(b[i])) and 127'i32) shl Shift) Shift = Shift + 7'i32 - if (int(b[0]) and (1 shl 6)) != 0: # sign bit set? + if (ze(b[0]) and (1 shl 6)) != 0: # sign bit set? result = (not result) +% 1'i32 # this is the same as ``- result`` # but gives no overflow error for low(int) diff --git a/tests/misc/tvcc.nim b/tests/misc/tvcc.nim deleted file mode 100644 index 10533729c..000000000 --- a/tests/misc/tvcc.nim +++ /dev/null @@ -1,9 +0,0 @@ -discard """ - matrix: "--cc:vcc" - disabled: "linux" - disabled: "bsd" - disabled: "osx" - disabled: "unix" - disabled: "posix" -""" -doAssert true diff --git a/tests/misc/twarningaserror.nim b/tests/misc/twarningaserror.nim deleted file mode 100644 index 6f7b76095..000000000 --- a/tests/misc/twarningaserror.nim +++ /dev/null @@ -1,35 +0,0 @@ -discard """ - joinable: false -""" - -#[ -tests: hintAsError, warningAsError -]# - -template fn1 = - {.hintAsError[ConvFromXtoItselfNotNeeded]:on.} - proc fn(a: string) = discard a.string - {.hintAsError[ConvFromXtoItselfNotNeeded]:off.} - -template fn2 = - {.hintAsError[ConvFromXtoItselfNotNeeded]:on.} - proc fn(a: string) = discard a - {.hintAsError[ConvFromXtoItselfNotNeeded]:off.} - -template gn1 = - {.warningAsError[ProveInit]:on.} - proc fn(): var int = discard - discard fn() - {.warningAsError[ProveInit]:off.} - -template gn2 = - {.warningAsError[ProveInit]:on.} - proc fn(): int = discard - discard fn() - {.warningAsError[ProveInit]:off.} - -doAssert not compiles(fn1()) -doAssert compiles(fn2()) - -doAssert not compiles(gn1()) -doAssert compiles(gn2()) diff --git a/tests/mmaptest.nim b/tests/mmaptest.nim index 33010606f..7a93cdd45 100644 --- a/tests/mmaptest.nim +++ b/tests/mmaptest.nim @@ -19,11 +19,8 @@ proc `+!!`(p: pointer, size: int): pointer {.inline.} = result = cast[pointer](cast[int](p) + size) const - PageShift = when defined(nimPage256) or defined(cpu16): 8 - elif defined(nimPage512): 9 - elif defined(nimPage1k): 10 - else: 12 # \ # my tests showed no improvements for using larger page sizes. - + PageShift = when defined(cpu16): 8 else: 12 # \ + # my tests showed no improvements for using larger page sizes. PageSize = 1 shl PageShift var p = osAllocPages(3 * PageSize) diff --git a/tests/modules/a/module_name_clashes.nim b/tests/modules/a/module_name_clashes.nim deleted file mode 100644 index 209526e22..000000000 --- a/tests/modules/a/module_name_clashes.nim +++ /dev/null @@ -1,8 +0,0 @@ -# See `tmodule_name_clashes` - -import ../b/module_name_clashes -type A* = object - b*: B - -proc print*(a: A) = - echo repr a diff --git a/tests/modules/b/module_name_clashes.nim b/tests/modules/b/module_name_clashes.nim deleted file mode 100644 index 6a10cac33..000000000 --- a/tests/modules/b/module_name_clashes.nim +++ /dev/null @@ -1,3 +0,0 @@ -# See `tmodule_name_clashes` - -type B* = object diff --git a/tests/modules/mforwarded_pure_enum.nim b/tests/modules/mforwarded_pure_enum.nim deleted file mode 100644 index 3f03390a5..000000000 --- a/tests/modules/mforwarded_pure_enum.nim +++ /dev/null @@ -1,3 +0,0 @@ - -import mforwarded_pure_enum2 -export mforwarded_pure_enum2.PureEnum diff --git a/tests/modules/mforwarded_pure_enum2.nim b/tests/modules/mforwarded_pure_enum2.nim deleted file mode 100644 index e5d5d2a71..000000000 --- a/tests/modules/mforwarded_pure_enum2.nim +++ /dev/null @@ -1,4 +0,0 @@ - -type - PureEnum* {.pure.} = enum - x, y, z diff --git a/tests/modules/seq.nim b/tests/modules/seq.nim deleted file mode 100644 index 176e44025..000000000 --- a/tests/modules/seq.nim +++ /dev/null @@ -1,5 +0,0 @@ -var seq: seq[int] -var b: seq[float] - -echo seq -echo b diff --git a/tests/modules/t8665.nim b/tests/modules/t8665.nim index 7cfdbdb00..74d31452f 100644 --- a/tests/modules/t8665.nim +++ b/tests/modules/t8665.nim @@ -1,5 +1,4 @@ discard """ - matrix: "--experimental:codeReordering" action: compile """ diff --git a/tests/modules/texplicit_system_import.nim b/tests/modules/texplicit_system_import.nim index 0a4cedc71..bc4d018bf 100644 --- a/tests/modules/texplicit_system_import.nim +++ b/tests/modules/texplicit_system_import.nim @@ -1,9 +1,9 @@ +##. import system except `+` - discard """ errormsg: "undeclared identifier: '+'" line: 9 """ - - +# Testament requires that the initial """ occurs before the 40th byte +# in the file. No kidding... echo 4+5 diff --git a/tests/modules/tfowarded_pure_enum.nim b/tests/modules/tfowarded_pure_enum.nim deleted file mode 100644 index 1d2c4f342..000000000 --- a/tests/modules/tfowarded_pure_enum.nim +++ /dev/null @@ -1,7 +0,0 @@ -discard """ - output: '''z''' -""" - -import mforwarded_pure_enum as t2 - -echo z diff --git a/tests/modules/tmodule_name_clashes.nim b/tests/modules/tmodule_name_clashes.nim deleted file mode 100644 index 814d5d152..000000000 --- a/tests/modules/tmodule_name_clashes.nim +++ /dev/null @@ -1,17 +0,0 @@ -discard """ -matrix: "--mm:refc" -targets: "c" -ccodecheck: "\\i @('atmaatsmodule_name_clashesdotnim_DatInit000')" -ccodecheck: "\\i @('atmbatsmodule_name_clashesdotnim_DatInit000')" -joinable: false -""" - -# Test module name clashes within same package. -# This was created to test that module symbol mangling functioned correctly -# for the C backend when there are one or more modules with the same name in -# a package, and more than one of them require module initialization procs. -# I'm not sure of the simplest method to cause the init procs to be generated. - -import a/module_name_clashes - -print A() diff --git a/tests/modules/treorder.nim b/tests/modules/treorder.nim index 626d9684b..c81715cd8 100644 --- a/tests/modules/treorder.nim +++ b/tests/modules/treorder.nim @@ -1,5 +1,5 @@ discard """ - matrix: "--experimental:codeReordering -d:testdef" + cmd: "nim -d:testdef $target $file" output: '''works 34 34 defined diff --git a/tests/modules/tselfimport.nim b/tests/modules/tselfimport.nim index ba5d9b4cf..7e50bef7c 100644 --- a/tests/modules/tselfimport.nim +++ b/tests/modules/tselfimport.nim @@ -1,5 +1,5 @@ discard """ - errormsg: "module 'tselfimport' cannot import itself" + errormsg: "A module cannot import itself" file: "tselfimport.nim" line: 7 """ diff --git a/tests/modules/tseq.nim b/tests/modules/tseq.nim deleted file mode 100644 index 22ee48f42..000000000 --- a/tests/modules/tseq.nim +++ /dev/null @@ -1,8 +0,0 @@ -discard """ - joinable: false - output: '''@[] -@[] -''' -""" - -import seq diff --git a/tests/modules/tstrutils_insert_sep.nim b/tests/modules/tstrutils_insert_sep.nim deleted file mode 100644 index 775fe7da1..000000000 --- a/tests/modules/tstrutils_insert_sep.nim +++ /dev/null @@ -1,13 +0,0 @@ -discard """ - output: ''' --100 --100,000 -100,000 -''' -""" -# test https://github.com/nim-lang/Nim/issues/11352 - -import strutils -echo insertSep($(-100), ',') -echo insertSep($(-100_000), ',') -echo insertSep($(100_000), ',') \ No newline at end of file diff --git a/tests/navigator/minclude.nim b/tests/navigator/minclude.nim deleted file mode 100644 index f65ebfab9..000000000 --- a/tests/navigator/minclude.nim +++ /dev/null @@ -1,2 +0,0 @@ -# An include file. -foo(3) diff --git a/tests/navigator/tincludefile.nim b/tests/navigator/tincludefile.nim deleted file mode 100644 index a913d0736..000000000 --- a/tests/navigator/tincludefile.nim +++ /dev/null @@ -1,29 +0,0 @@ -discard """ - disabled: true - cmd: "nim check $options --defusages:$file,12,7 $file" - nimout: '''def tincludefile_temp.nim(11, 10) -usage tincludefile_temp.nim(12, 8) - ''' -""" - - - -proc foo(x: int) = - echo x - -foo(3) -echo "yes", 1 != 3 - -#!EDIT!# -discard """ - cmd: "nim check $options --defusages:$file/../minclude.nim,2,2 $file" - nimout: '''def tincludefile_temp.nim(10, 6) -usage minclude.nim(2, 1) - ''' -""" - - -proc foo(x: int) = - echo x - -include minclude diff --git a/tests/navigator/tnav1.nim b/tests/navigator/tnav1.nim deleted file mode 100644 index e76c921f3..000000000 --- a/tests/navigator/tnav1.nim +++ /dev/null @@ -1,33 +0,0 @@ -discard """ - disabled: true - cmd: "nim check $options --defusages:$file,12,7 $file" - nimout: '''def tnav1_temp.nim(11, 10) -usage tnav1_temp.nim(12, 8) - ''' -""" - -import std / [times] - -proc foo(x: int) = - echo x - -foo(3) -echo "yes", 1 != 3 - -#!EDIT!# -discard """ - cmd: "nim check $options --defusages:$file,15,2 $file" - nimout: '''def tnav1_temp.nim(12, 6) -usage tnav1_temp.nim(15, 1) - ''' -""" - - -import std / [times] - -proc foo(x: int) = - echo x - -foo(3) -echo "yes", 1 != 3 - diff --git a/tests/newconfig/bar/nim.cfg b/tests/newconfig/bar/nim.cfg deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/newconfig/foo2/mfoo2.customext b/tests/newconfig/foo2/mfoo2.customext deleted file mode 100644 index 66c8b1d15..000000000 --- a/tests/newconfig/foo2/mfoo2.customext +++ /dev/null @@ -1,2 +0,0 @@ -doAssert defined(nimscript) -echo "123" diff --git a/tests/newconfig/mconfigcheck.nims b/tests/newconfig/mconfigcheck.nims deleted file mode 100644 index 8df6715f6..000000000 --- a/tests/newconfig/mconfigcheck.nims +++ /dev/null @@ -1,9 +0,0 @@ -mode = ScriptMode.Verbose -proc build() = - echo "building nim... " - exec "sleep 10" - exec "nonexistant command" - echo getCurrentDir() - -echo "hello" -build() diff --git a/tests/newconfig/tfoo.nim b/tests/newconfig/tfoo.nim index 0c6ded470..f332cd6d4 100644 --- a/tests/newconfig/tfoo.nim +++ b/tests/newconfig/tfoo.nim @@ -1,6 +1,6 @@ discard """ - cmd: "nim default --hint:cc:off --hint:cc $file" - output: '''hello world! 0.5 true''' + cmd: "nim default $file" + output: '''hello world! 0.5''' nimout: '''[NimScript] exec: gcc -v''' """ @@ -10,4 +10,4 @@ when not defined(definedefine): import math, mfriends discard gen[int]() -echo "hello world! ", ln 2.0, " ", compileOption("opt", "speed") +echo "hello world! ", ln 2.0 diff --git a/tests/newconfig/tfoo.nims b/tests/newconfig/tfoo.nims index 0cb950227..8dcc7d6f1 100644 --- a/tests/newconfig/tfoo.nims +++ b/tests/newconfig/tfoo.nims @@ -3,32 +3,11 @@ mode = ScriptMode.Whatif exec "gcc -v" ---define:release - --forceBuild --path: "../friends" warning("uninit", off) - -block: # supported syntaxes for hint,warning,switch - --hint:processing - hint("processing", on) - hint("processing", off) - switch("hint", "processing") - switch("hint", "processing:on") - switch("hint", "processing:off") - switch("hint", "[processing]") - switch("hint", "[processing]:on") - switch("hint", "[processing]:off") # leave it off - - --warning:UnusedImport - switch("warning", "UnusedImport:off") - switch("warning", "UnusedImport:on") - switch("warning", "[UnusedImport]:off") - switch("warning", "[UnusedImport]:on") - switch("warning", "[UnusedImport]") - switch("warning", "UnusedImport") # leave it on - +hint("processing", off) #--verbosity:2 patchFile("stdlib", "math", "mymath") @@ -45,64 +24,65 @@ doAssert(existsEnv("dummy") == false) # issue #7283 putEnv("dummy", "myval") -doAssert(existsEnv("dummy")) +doAssert(existsEnv("dummy") == true) doAssert(getEnv("dummy") == "myval") -delEnv("dummy") -doAssert(existsEnv("dummy") == false) # issue #7393 let wd = getCurrentDir() cd("..") -doAssert wd != getCurrentDir() +assert wd != getCurrentDir() cd(wd) -doAssert wd == getCurrentDir() +assert wd == getCurrentDir() when false: # this doesn't work in a 'koch testintall' environment - doAssert findExe("nim") != "" + assert findExe("nim") != "" # general tests mode = ScriptMode.Verbose -doAssert getCommand() == "c" +assert getCommand() == "c" setCommand("cpp") -doAssert getCommand() == "cpp" +assert getCommand() == "cpp" setCommand("c") -doAssert cmpic("HeLLO", "hello") == 0 +assert cmpic("HeLLO", "hello") == 0 -doAssert fileExists("tests/newconfig/tfoo.nims") == true -doAssert dirExists("tests") == true +assert fileExists("tests/newconfig/tfoo.nims") == true +assert dirExists("tests") == true -doAssert fileExists("tests/newconfig/tfoo.nims") == true -doAssert dirExists("tests") == true +assert existsFile("tests/newconfig/tfoo.nims") == true +assert existsDir("tests") == true discard selfExe() when defined(windows): - doAssert toExe("nim") == "nim.exe" - doAssert toDll("nim") == "nim.dll" + assert toExe("nim") == "nim.exe" + assert toDll("nim") == "nim.dll" else: - doAssert toExe("nim") == "nim" - doAssert toDll("nim") == "libnim.so" + assert toExe("nim") == "nim" + assert toDll("nim") == "libnim.so" rmDir("tempXYZ") -doAssertRaises(OSError): - rmDir("tempXYZ", checkDir = true) -doAssert dirExists("tempXYZ") == false +assert dirExists("tempXYZ") == false mkDir("tempXYZ") -doAssert dirExists("tempXYZ") == true -doAssert fileExists("tempXYZ/koch.nim") == false +assert dirExists("tempXYZ") == true +assert fileExists("tempXYZ/koch.nim") == false when false: # this doesn't work in a 'koch testintall' environment cpFile("koch.nim", "tempXYZ/koch.nim") - doAssert fileExists("tempXYZ/koch.nim") == true + assert fileExists("tempXYZ/koch.nim") == true cpDir("nimsuggest", "tempXYZ/.") - doAssert dirExists("tempXYZ/tests") == true - doAssert fileExists("tempXYZ/nimsuggest.nim") == true + assert dirExists("tempXYZ/tests") == true + assert fileExists("tempXYZ/nimsuggest.nim") == true rmFile("tempXYZ/koch.nim") - doAssert fileExists("tempXYZ/koch.nim") == false + assert fileExists("tempXYZ/koch.nim") == false rmDir("tempXYZ") -doAssert dirExists("tempXYZ") == false +assert dirExists("tempXYZ") == false + +putEnv("dummy", "myval") +doAssert(existsEnv("dummy") == true) +delEnv("dummy") +doAssert(existsEnv("dummy") == false) diff --git a/tests/nimble/tnimblepathdollar_fault.nim b/tests/nimble/tnimblepathdollarfail.nim similarity index 70% rename from tests/nimble/tnimblepathdollar_fault.nim rename to tests/nimble/tnimblepathdollarfail.nim index 3f0270123..0b9b04eb4 100644 --- a/tests/nimble/tnimblepathdollar_fault.nim +++ b/tests/nimble/tnimblepathdollarfail.nim @@ -1,9 +1,6 @@ discard """ - errormsg: "cannot open file: pkgA/module" + errmsg: "cannot open file: pkgA/module" """ - -# see nims file; comment out `switch("noNimblePath")` there and there would be no error - import pkgA/module as A import pkgB/module as B import pkgC/module as C diff --git a/tests/nimble/tnimblepathdollar_fault.nims b/tests/nimble/tnimblepathdollarfail.nims similarity index 100% rename from tests/nimble/tnimblepathdollar_fault.nims rename to tests/nimble/tnimblepathdollarfail.nims diff --git a/tests/nimdoc/imp.nim b/tests/nimdoc/imp.nim deleted file mode 100644 index ca08dcb35..000000000 --- a/tests/nimdoc/imp.nim +++ /dev/null @@ -1 +0,0 @@ -proc fn5*() = discard diff --git a/tests/nimdoc/m13129.nim b/tests/nimdoc/m13129.nim deleted file mode 100644 index 145cae39c..000000000 --- a/tests/nimdoc/m13129.nim +++ /dev/null @@ -1,36 +0,0 @@ -# issue #13129 - -when defined(cpp): - {.push header: "".} - type - Vector[T] {.importcpp: "std::vector".} = object -elif defined(js): - proc endsWith*(s, suffix: cstring): bool {.noSideEffect,importjs: "#.endsWith(#)".} -elif defined(c): - proc c_printf*(frmt: cstring): cint {. - importc: "printf", header: "", varargs, discardable.} - -proc main*() = - runnableExamples: - import std/compilesettings - doAssert not defined(m13129Foo1) - doAssert defined(m13129Foo2) - doAssert not defined(nimdoc) - echo "ok2: backend: " & querySetting(backend) - -import std/compilesettings -when defined nimdoc: - static: - doAssert defined(m13129Foo1) - doAssert not defined(m13129Foo2) - echo "ok1:" & querySetting(backend) - -when isMainModule: - when not defined(js): - import std/os - let cache = querySetting(nimcacheDir) - doAssert cache.len > 0 - let app = getAppFilename() - doAssert app.isRelativeTo(cache), $(app, cache) - doAssert querySetting(projectFull) == currentSourcePath - echo "ok3" diff --git a/tests/nimdoc/readme.md b/tests/nimdoc/readme.md deleted file mode 100644 index 40b5841eb..000000000 --- a/tests/nimdoc/readme.md +++ /dev/null @@ -1,3 +0,0 @@ -## links -* $nim/nimdoc/tester.nim: tests html validation -* $nim/tests/nimdoc/: tests `runnableExamples` + `nim doc` logic diff --git a/tests/nimdoc/sub/imp.nim b/tests/nimdoc/sub/imp.nim deleted file mode 100644 index d66542e45..000000000 --- a/tests/nimdoc/sub/imp.nim +++ /dev/null @@ -1 +0,0 @@ -proc fn4*() = discard diff --git a/tests/nimdoc/sub/imp2.nim b/tests/nimdoc/sub/imp2.nim deleted file mode 100644 index 60fa1e72d..000000000 --- a/tests/nimdoc/sub/imp2.nim +++ /dev/null @@ -1 +0,0 @@ -proc fn3*() = discard diff --git a/tests/nimdoc/sub/mmain.nim b/tests/nimdoc/sub/mmain.nim deleted file mode 100644 index 42547b0b8..000000000 --- a/tests/nimdoc/sub/mmain.nim +++ /dev/null @@ -1,8 +0,0 @@ -{.warning[UnusedImport]: off.} - -import ../imp as impa -import imp as impb -import imp2 - -proc fn1*() = discard -proc fn2*() = discard diff --git a/tests/nimdoc/t15916.nim b/tests/nimdoc/t15916.nim deleted file mode 100644 index c6c09d94b..000000000 --- a/tests/nimdoc/t15916.nim +++ /dev/null @@ -1,16 +0,0 @@ -discard """ -cmd: "nim doc --hints:off $file" -action: "compile" -joinable: false -""" - -type - Test* = object - id: int - -proc initTest*(id: int): Test = - result.id = id - -proc hello*() = - runnableExamples: - discard diff --git a/tests/nimdoc/t17615.nim b/tests/nimdoc/t17615.nim deleted file mode 100644 index 77ae35a15..000000000 --- a/tests/nimdoc/t17615.nim +++ /dev/null @@ -1,11 +0,0 @@ -discard """ - cmd: "nim doc -r $file" - errormsg: "runnableExamples must appear before the first non-comment statement" - line: 10 -""" - -func fn*() = - ## foo - discard - runnableExamples: - assert true diff --git a/tests/nimdoc/trunnableexamples.nim b/tests/nimdoc/trunnableexamples.nim deleted file mode 100644 index 1188cdd1b..000000000 --- a/tests/nimdoc/trunnableexamples.nim +++ /dev/null @@ -1,210 +0,0 @@ -discard """ -cmd: "nim doc --doccmd:--hints:off --hints:off $file" -action: "compile" -nimoutFull: true -nimout: ''' -foo1 -foo2 -foo3 -foo5 -foo7 -in examplesInTemplate1 -doc in outer -doc in inner1 -doc in inner2 -foo8 -foo9 -foo6 -''' -joinable: false -""" - -#[ -pending bug #18077, use instead: -cmd: "nim doc --doccmd:'-d:testFooExternal --hints:off' --hints:off $file" -and merge trunnableexamples2 back here -]# -{.define(testFooExternal).} - -proc fun*() = - runnableExamples: - block: # `defer` only allowed inside a block - defer: echo "foo1" - - runnableExamples: - # `fun*` only allowed at top level - proc fun*()=echo "foo2" - fun() - block: - defer: echo "foo3" - - runnableExamples: - # ditto - proc fun*()=echo "foo5" - fun() - - runnableExamples("--experimental:codeReordering --warnings:off"): - # `codeReordering` only allowed at top level - {.experimental: "codeReordering".} - proc fun1() = fun2() - proc fun2() = echo "foo6" - fun1() - - runnableExamples: - # only works at top level - import std/macros - macro myImport(a: static string): untyped = - newTree(nnkImportStmt, [newLit a]) - myImport "str" & "utils" - doAssert declared(isAlphaAscii) - echo "foo7" - -when true: # issue #12746 - # this proc on its own works fine with `nim doc` - proc goodProc*() = - runnableExamples: - try: - discard - except CatchableError: - # just the general except will work - discard - - # FIXED: this proc fails with `nim doc` - proc badProc*() = - runnableExamples: - try: - discard - except IOError: - # specifying Error is culprit - discard - -when true: # runnableExamples with rdoccmd - runnableExamples "-d:testFoo -d:testBar": - doAssert defined(testFoo) and defined(testBar) - doAssert defined(testFooExternal) - runnableExamples "-d:testFoo2": - doAssert defined(testFoo2) - doAssert not defined(testFoo) # doesn't get confused by other examples - - ## all these syntaxes work too - runnableExamples("-d:testFoo2"): discard - runnableExamples(): discard - runnableExamples: discard - runnableExamples "-r:off": # issue #10731 - doAssert false ## we compile only (-r:off), so this won't be run - runnableExamples "-b:js": - import std/compilesettings - proc startsWith*(s, prefix: cstring): bool {.noSideEffect, importjs: "#.startsWith(#)".} - doAssert querySetting(backend) == "js" - runnableExamples "-b:cpp": - static: doAssert defined(cpp) - type std_exception {.importcpp: "std::exception", header: "".} = object - - proc fun2*() = - runnableExamples "-d:foo": discard # checks that it also works inside procs - - template fun3Impl(): untyped = - runnableExamples(rdoccmd="-d:foo"): - nonexistent - # bugfix: this shouldn't be semchecked when `runnableExamples` - # has more than 1 argument - discard - - proc fun3*[T]() = - fun3Impl() - - when false: # future work - # passing non-string-litterals (for reuse) - const a = "-b:cpp" - runnableExamples(a): discard - - # passing seq (to run with multiple compilation options) - runnableExamples(@["-b:cpp", "-b:js"]): discard - -when true: # bug #16993 - template examplesInTemplate1*(cond: untyped) = - ## in examplesInTemplate1 - runnableExamples: - echo "in examplesInTemplate1" - discard - examplesInTemplate1 true - examplesInTemplate1 true - examplesInTemplate1 true - -when true: # bug #18054 - template outer*(body: untyped) = - ## outer template doc string. - runnableExamples: - echo "doc in outer" - ## - template inner1*() = - ## inner1 template doc string. - runnableExamples: - echo "doc in inner1" - ## - - template inner2*() = - ## inner2 template doc string. - runnableExamples: - echo "doc in inner2" - body - outer: - inner1() - inner2() - -when true: # bug #17835 - template anyItFake*(s, pred: untyped): bool = - ## Foo - runnableExamples: discard - true - - proc anyItFakeMain*(n: seq[int]): bool = - result = anyItFake(n, it == 0) - # this was giving: Error: runnableExamples must appear before the first non-comment statement - -runnableExamples: - block: # bug #17279 - when int.sizeof == 8: - let x = 0xffffffffffffffff - doAssert x == -1 - - # bug #13491 - block: - proc fun(): int = doAssert false - doAssertRaises(AssertionDefect, (discard fun())) - - block: - template foo(body) = discard - foo (discard) - - block: - template fn(body: untyped): untyped = true - doAssert(fn do: nonexistent) - import std/macros - macro foo*(x, y) = - result = newLetStmt(x[0][0], x[0][1]) - foo: - a = 1 - do: discard - -# also check for runnableExamples at module scope -runnableExamples: - block: - defer: echo "foo8" - -runnableExamples: - proc fun*()=echo "foo9" - fun() - -# note: there are yet other examples where putting runnableExamples at module -# scope is needed, for example when using an `include` before an `import`, etc. - -##[ -snippet: - -.. code-block:: Nim - :test: - - doAssert defined(testFooExternal) - -]## diff --git a/tests/nimdoc/trunnableexamples2.nim b/tests/nimdoc/trunnableexamples2.nim deleted file mode 100644 index 5a437744e..000000000 --- a/tests/nimdoc/trunnableexamples2.nim +++ /dev/null @@ -1,11 +0,0 @@ -discard """ -cmd: "nim doc --doccmd:-d:testFooExternal --hints:off $file" -action: "compile" -joinable: false -""" - -# pending bug #18077, merge back inside trunnableexamples.nim -when true: # runnableExamples with rdoccmd - runnableExamples "-d:testFoo -d:testBar": - doAssert defined(testFoo) and defined(testBar) - doAssert defined(testFooExternal) diff --git a/tests/niminaction/Chapter1/various1.nim b/tests/niminaction/Chapter1/various1.nim index 21553dc40..4e2cb463d 100644 --- a/tests/niminaction/Chapter1/various1.nim +++ b/tests/niminaction/Chapter1/various1.nim @@ -32,7 +32,7 @@ block: # Block added due to clash. let dog = Dog() dog.bark() #<2> -import sequtils, sugar, strutils +import sequtils, future, strutils let list = @["Dominik Picheta", "Andreas Rumpf", "Desmond Hume"] list.map( (x: string) -> (string, string) => (x.split[0], x.split[1]) diff --git a/tests/niminaction/Chapter2/explicit_discard.nim b/tests/niminaction/Chapter2/explicit_discard.nim index 7f3b3395e..9a3b4407e 100644 --- a/tests/niminaction/Chapter2/explicit_discard.nim +++ b/tests/niminaction/Chapter2/explicit_discard.nim @@ -1,5 +1,5 @@ discard """ - errormsg: "has to be used (or discarded)" + errormsg: "has to be discarded" line: 7 """ diff --git a/tests/niminaction/Chapter2/resultaccept.nim b/tests/niminaction/Chapter2/resultaccept.nim index 390f7b329..7dd976b40 100644 --- a/tests/niminaction/Chapter2/resultaccept.nim +++ b/tests/niminaction/Chapter2/resultaccept.nim @@ -22,7 +22,7 @@ proc resultVar2: string = result.add("returned") doAssert implicit() == "I will be returned" -doAssert discarded().len == 0 +doAssert discarded() == nil doAssert explicit() == "I will be returned" doAssert resultVar() == "I will be returned" doAssert resultVar2() == "I will be returned" \ No newline at end of file diff --git a/tests/niminaction/Chapter2/resultreject.nim b/tests/niminaction/Chapter2/resultreject.nim index 145345072..87c84bf0a 100644 --- a/tests/niminaction/Chapter2/resultreject.nim +++ b/tests/niminaction/Chapter2/resultreject.nim @@ -1,5 +1,5 @@ discard """ - errormsg: "has to be used (or discarded)" + errormsg: "has to be discarded" line: 27 """ diff --git a/tests/niminaction/Chapter2/various2.nim b/tests/niminaction/Chapter2/various2.nim index 921f38c7d..dddbdb472 100644 --- a/tests/niminaction/Chapter2/various2.nim +++ b/tests/niminaction/Chapter2/various2.nim @@ -140,7 +140,7 @@ let numbers = @[1, 2, 3, 4, 5, 6] let odd = filter(numbers, proc (x: int): bool = x mod 2 != 0) doAssert odd == @[1, 3, 5] -import sequtils, sugar +import sequtils, future let numbers1 = @[1, 2, 3, 4, 5, 6] let odd1 = filter(numbers1, (x: int) -> bool => x mod 2 != 0) assert odd1 == @[1, 3, 5] @@ -149,7 +149,7 @@ proc isValid(x: int, validator: proc (x: int): bool) = if validator(x): echo(x, " is valid") else: echo(x, " is NOT valid") -import sugar +import future proc isValid2(x: int, validator: (x: int) -> bool) = if validator(x): echo(x, " is valid") else: echo(x, " is NOT valid") @@ -179,13 +179,13 @@ for i in list4.low .. list4.high: echo(list4[i]) var list5: seq[int] = @[] -doAssertRaises(IndexDefect): +doAssertRaises(IndexError): list5[0] = 1 list5.add(1) assert list5[0] == 1 -doAssertRaises(IndexDefect): +doAssertRaises(IndexError): echo list5[42] # -- Errata: var list: seq[int]; echo(list[0]). This now creates an exception, @@ -193,7 +193,7 @@ doAssertRaises(IndexDefect): block: var list = newSeq[string](3) - assert list[0].len == 0 + assert list[0] == nil list[0] = "Foo" list[1] = "Bar" list[2] = "Baz" diff --git a/tests/niminaction/Chapter3/various3.nim b/tests/niminaction/Chapter3/various3.nim index c7cdf7db4..711740da8 100644 --- a/tests/niminaction/Chapter3/various3.nim +++ b/tests/niminaction/Chapter3/various3.nim @@ -1,5 +1,4 @@ discard """ -matrix: "--mm:refc" output: ''' Future is no longer empty, 42 ''' @@ -8,7 +7,7 @@ Future is no longer empty, 42 import threadpool proc foo: string = "Dog" var x: FlowVar[string] = spawn foo() -doAssert(^x == "Dog") +assert(^x == "Dog") block: type @@ -20,20 +19,20 @@ block: discard var obj = Box(empty: false, contents: "Hello") - doAssert obj.contents == "Hello" + assert obj.contents == "Hello" var obj2 = Box(empty: true) - doAssertRaises(FieldDefect): + doAssertRaises(FieldError): echo(obj2.contents) import json -doAssert parseJson("null").kind == JNull -doAssert parseJson("true").kind == JBool -doAssert parseJson("42").kind == JInt -doAssert parseJson("3.14").kind == JFloat -doAssert parseJson("\"Hi\"").kind == JString -doAssert parseJson("""{ "key": "value" }""").kind == JObject -doAssert parseJson("[1, 2, 3, 4]").kind == JArray +assert parseJson("null").kind == JNull +assert parseJson("true").kind == JBool +assert parseJson("42").kind == JInt +assert parseJson("3.14").kind == JFloat +assert parseJson("\"Hi\"").kind == JString +assert parseJson("""{ "key": "value" }""").kind == JObject +assert parseJson("[1, 2, 3, 4]").kind == JArray import json let data = """ @@ -41,15 +40,15 @@ let data = """ """ let obj = parseJson(data) -doAssert obj.kind == JObject -doAssert obj["username"].kind == JString -doAssert obj["username"].str == "Dominik" +assert obj.kind == JObject +assert obj["username"].kind == JString +assert obj["username"].str == "Dominik" block: proc count10(): int = for i in 0 ..< 10: result.inc - doAssert count10() == 10 + assert count10() == 10 type Point = tuple[x, y: int] diff --git a/tests/niminaction/Chapter7/Tweeter/src/createDatabase.nim b/tests/niminaction/Chapter7/Tweeter/src/createDatabase.nim index 67d9323f2..a7d4ebe00 100644 --- a/tests/niminaction/Chapter7/Tweeter/src/createDatabase.nim +++ b/tests/niminaction/Chapter7/Tweeter/src/createDatabase.nim @@ -1,5 +1,4 @@ discard """ -disabled: true output: "Database created successfully!" """ diff --git a/tests/niminaction/Chapter7/Tweeter/src/database.nim b/tests/niminaction/Chapter7/Tweeter/src/database.nim index bd6667f70..3785ea307 100644 --- a/tests/niminaction/Chapter7/Tweeter/src/database.nim +++ b/tests/niminaction/Chapter7/Tweeter/src/database.nim @@ -50,7 +50,7 @@ proc post*(database: Database, message: Message) = raise newException(ValueError, "Message has to be less than 140 characters.") database.db.exec(sql"INSERT INTO Message VALUES (?, ?, ?);", #<2> - message.username, $message.time.toUnix().int, message.msg) #<3> + message.username, $message.time.toSeconds().int, message.msg) #<3> proc follow*(database: Database, follower: User, user: User) = database.db.exec(sql"INSERT INTO Following VALUES (?, ?);",#<2> @@ -90,4 +90,4 @@ proc findMessages*(database: Database, usernames: seq[string], "ORDER BY time DESC LIMIT " & $limit), usernames) for row in messages: - result.add(Message(username: row[0], time: fromUnix(row[1].parseInt), msg: row[2])) + result.add(Message(username: row[0], time: fromSeconds(row[1].parseInt), msg: row[2])) diff --git a/tests/niminaction/Chapter7/Tweeter/src/tweeter.nim b/tests/niminaction/Chapter7/Tweeter/src/tweeter.nim index 1b521521c..12aaf49b8 100644 --- a/tests/niminaction/Chapter7/Tweeter/src/tweeter.nim +++ b/tests/niminaction/Chapter7/Tweeter/src/tweeter.nim @@ -1,7 +1,5 @@ discard """ -disabled: true action: compile -matrix: "--threads:off" """ import asyncdispatch, times @@ -53,7 +51,7 @@ routes: redirect(uri("/" & @"target")) post "/login": - setCookie("username", @"username", getTime().utc() + 2.hours) + setCookie("username", @"username", getTime().getGMTime() + 2.hours) redirect("/") post "/createMessage": diff --git a/tests/niminaction/Chapter7/Tweeter/src/views/user.nim b/tests/niminaction/Chapter7/Tweeter/src/views/user.nim index 4abcf440d..18f3713b3 100644 --- a/tests/niminaction/Chapter7/Tweeter/src/views/user.nim +++ b/tests/niminaction/Chapter7/Tweeter/src/views/user.nim @@ -33,7 +33,7 @@ #for message in messages:
      ${message.username} - ${message.time.utc().format("HH:mm MMMM d',' yyyy")} + ${message.time.getGMTime().format("HH:mm MMMM d',' yyyy")}

      ${message.msg}

      #end for diff --git a/tests/niminaction/Chapter7/Tweeter/tests/database_test.nim b/tests/niminaction/Chapter7/Tweeter/tests/database_test.nim index c8beb4a30..a3cab4cba 100644 --- a/tests/niminaction/Chapter7/Tweeter/tests/database_test.nim +++ b/tests/niminaction/Chapter7/Tweeter/tests/database_test.nim @@ -1,5 +1,4 @@ discard """ -disabled: true outputsub: "All tests finished successfully!" """ diff --git a/tests/niminaction/Chapter8/sdl/sdl.nim b/tests/niminaction/Chapter8/sdl/sdl.nim index 212f7b022..14fa59c85 100644 --- a/tests/niminaction/Chapter8/sdl/sdl.nim +++ b/tests/niminaction/Chapter8/sdl/sdl.nim @@ -1,8 +1,8 @@ -when defined(windows): +when defined(Windows): const libName* = "SDL2.dll" -elif defined(linux) or defined(freebsd) or defined(netbsd): +elif defined(Linux) or defined(freebsd): const libName* = "libSDL2.so" -elif defined(macosx): +elif defined(MacOsX): const libName* = "libSDL2.dylib" elif defined(openbsd): const libName* = "libSDL2.so.0.6" diff --git a/tests/niminaction/Chapter8/sfml/sfml_test.nim b/tests/niminaction/Chapter8/sfml/sfml_test.nim index e71060cb4..3c158d1de 100644 --- a/tests/niminaction/Chapter8/sfml/sfml_test.nim +++ b/tests/niminaction/Chapter8/sfml/sfml_test.nim @@ -1,6 +1,7 @@ discard """ action: compile disabled: "windows" +disabled: "freebsd" """ import sfml, os diff --git a/tests/notnil/tmust_compile.nim b/tests/notnil/tmust_compile.nim index 3a013e9ed..d09dda057 100644 --- a/tests/notnil/tmust_compile.nim +++ b/tests/notnil/tmust_compile.nim @@ -63,13 +63,3 @@ proc parse(cts: CTS, jn: JsonNode) = proc p(x: proc(){.closure.} not nil) = discard p(proc(){.closure.} = discard) - -# bug #6490 - -proc p2(a: proc()) = - if a.isNil: - raise newException(ValueError, "a is nil") - else: - let b: proc() not nil = a - -p2(writeStackTrace) diff --git a/tests/notnil/tnotnil4.nim b/tests/notnil/tnotnil4.nim index c5178f71b..4fd169827 100644 --- a/tests/notnil/tnotnil4.nim +++ b/tests/notnil/tnotnil4.nim @@ -10,9 +10,8 @@ proc check(a: TObj not nil) = proc doit() = var x : array[0..1, TObj] - let y = x[0] - if y != nil: - check(y) + if x[0] != nil: + check(x[0]) doit() diff --git a/tests/notnil/tnotnil5.nim b/tests/notnil/tnotnil5.nim deleted file mode 100644 index 2dcb7f7c3..000000000 --- a/tests/notnil/tnotnil5.nim +++ /dev/null @@ -1,28 +0,0 @@ -discard """ - matrix: "--threads:on" -""" - -{.experimental: "parallel".} -{.experimental: "notnil".} -import threadpool - -type - AO = object - x: int - - A = ref AO not nil - -proc process(a: A): A = - return A(x: a.x+1) - -proc processMany(ayys: openArray[A]): seq[A] = - var newAs: seq[FlowVar[A]] - - parallel: - for a in ayys: - newAs.add(spawn process(a)) - for newAflow in newAs: - let newA = ^newAflow - if isNil(newA): - return @[] - result.add(newA) diff --git a/tests/notnil/tnotnil_in_objconstr.nim b/tests/notnil/tnotnil_in_objconstr.nim index 471150f44..fb8ac8d6f 100644 --- a/tests/notnil/tnotnil_in_objconstr.nim +++ b/tests/notnil/tnotnil_in_objconstr.nim @@ -1,17 +1,13 @@ discard """ - errormsg: "The Foo type requires the following fields to be initialized: bar, baz" - line: "17" + errormsg: "fields not initialized: bar" + line: "13" """ {.experimental: "notnil".} # bug #2355 type - Base = object of RootObj - baz: ref int not nil - - Foo = object of Base + Foo = object foo: ref int bar: ref int not nil - var x: ref int = new(int) # Create instance without initializing the `bar` field var f = Foo(foo: x) diff --git a/tests/objects/m19342.c b/tests/objects/m19342.c deleted file mode 100644 index 113f65309..000000000 --- a/tests/objects/m19342.c +++ /dev/null @@ -1,12 +0,0 @@ -struct Node -{ - int data[25]; -}; - - -struct Node hello(int name) { - struct Node x = {999, 1, 2, 3, 4, 5, 6, 7, 8, 9, - 0, 1, 2, 3, 4, 5, 6, 7 ,8, 9, - 1, 2, 3, 4, 5}; - return x; -} \ No newline at end of file diff --git a/tests/objects/mobject_default_value.nim b/tests/objects/mobject_default_value.nim deleted file mode 100644 index 224549501..000000000 --- a/tests/objects/mobject_default_value.nim +++ /dev/null @@ -1,15 +0,0 @@ -type - Clean = object - mem: int - Default* = object - poi: int = 12 - clc: Clean - se*: range[0'i32 .. high(int32)] - - NonDefault* = object - poi: int - - PrellDeque*[T] = object - pendingTasks*: range[0'i32 .. high(int32)] - head: T - tail: T diff --git a/tests/objects/t17437.nim b/tests/objects/t17437.nim deleted file mode 100644 index b5c0e0525..000000000 --- a/tests/objects/t17437.nim +++ /dev/null @@ -1,22 +0,0 @@ -discard """ - cmd: "nim check $file" - errormsg: "" - nimout: ''' -t17437.nim(20, 16) Error: undeclared identifier: 'x' -t17437.nim(20, 16) Error: expression 'x' has no type (or is ambiguous) -t17437.nim(20, 19) Error: incorrect object construction syntax -t17437.nim(20, 19) Error: incorrect object construction syntax -t17437.nim(20, 12) Error: expression '' has no type (or is ambiguous) -''' -""" - -# bug #17437 invalid object construction should result in error - -type - V = ref object - x, y: int - -proc m = - var v = V(x: x, y) - -m() diff --git a/tests/objects/t19342.nim b/tests/objects/t19342.nim deleted file mode 100644 index d40d15a4b..000000000 --- a/tests/objects/t19342.nim +++ /dev/null @@ -1,18 +0,0 @@ -discard """ - targets: "c cpp" -""" - -{.compile: "m19342.c".} - -# bug #19342 -type - Node* {.bycopy.} = object - data: array[25, cint] - -proc myproc(name: cint): Node {.importc: "hello", cdecl.} - -proc parse = - let node = myproc(10) - doAssert node.data[0] == 999 - -parse() diff --git a/tests/objects/t19342_2.nim b/tests/objects/t19342_2.nim deleted file mode 100644 index 6f6d0f2b3..000000000 --- a/tests/objects/t19342_2.nim +++ /dev/null @@ -1,18 +0,0 @@ -discard """ - targets: "c cpp" -""" - -{.compile: "m19342.c".} - -# bug #19342 -type - Node* {.byRef.} = object - data: array[25, cint] - -proc myproc(name: cint): Node {.importc: "hello", cdecl.} - -proc parse = - let node = myproc(10) - doAssert node.data[0] == 999 - -parse() \ No newline at end of file diff --git a/tests/objects/t4318.nim b/tests/objects/t4318.nim deleted file mode 100644 index beadd6909..000000000 --- a/tests/objects/t4318.nim +++ /dev/null @@ -1,17 +0,0 @@ -discard """ - matrix: "--mm:refc" -""" - - -type - A = object of RootObj - B = object of A - -method identify(a:A) {.base.} = echo "A" -method identify(b:B) = echo "B" - -var b: B - -doAssertRaises(ObjectAssignmentDefect): - var a: A = b - discard a diff --git a/tests/objects/tdefaultfieldscheck.nim b/tests/objects/tdefaultfieldscheck.nim deleted file mode 100644 index d6feb2988..000000000 --- a/tests/objects/tdefaultfieldscheck.nim +++ /dev/null @@ -1,19 +0,0 @@ -discard """ - cmd: "nim check --hints:off $file" - errormsg: "" - nimout: -''' -tdefaultfieldscheck.nim(14, 17) Error: type mismatch: got but expected 'int' -tdefaultfieldscheck.nim(15, 20) Error: type mismatch: got but expected 'string' -tdefaultfieldscheck.nim(17, 16) Error: type mismatch: got but expected 'int' -''' -""" - -type - Date* = object - name: int = "string" - time: string = 12 - goal: float = 7 - fun: int = 1.4 - -echo default(Date) \ No newline at end of file diff --git a/tests/objects/tdefaultrangetypescheck.nim b/tests/objects/tdefaultrangetypescheck.nim deleted file mode 100644 index 71e7ac59b..000000000 --- a/tests/objects/tdefaultrangetypescheck.nim +++ /dev/null @@ -1,11 +0,0 @@ -discard """ - errormsg: "cannot convert 0 to range 1..5(int)" - line: 9 -""" - -type - Point = object - y: int - x: range[1..5] = 0 - -echo default(Point) diff --git a/tests/objects/tobj_asgn_dont_slice.nim b/tests/objects/tobj_asgn_dont_slice.nim index ce67c4490..866b5aecc 100644 --- a/tests/objects/tobj_asgn_dont_slice.nim +++ b/tests/objects/tobj_asgn_dont_slice.nim @@ -1,6 +1,5 @@ discard """ - matrix: "--mm:refc" - outputsub: '''ObjectAssignmentDefect''' + outputsub: '''ObjectAssignmentError''' exitcode: "1" """ diff --git a/tests/objects/tobjconstr.nim b/tests/objects/tobjconstr.nim index ee5a5b221..1e4d89d68 100644 --- a/tests/objects/tobjconstr.nim +++ b/tests/objects/tobjconstr.nim @@ -50,30 +50,27 @@ type BS = object of B C = object of BS z*: int +# inherited fields are ignored, so no fields are set +when true: + var + o: B + o = B(x: 123) + echo o + o = B(y: 678, x: 123) + echo o -proc main2 = - # inherited fields are ignored, so no fields are set - when true: - var - o: B - o = B(x: 123) - echo o - o = B(y: 678, x: 123) - echo o +# inherited fields are ignored +echo C(x: 128, z: 89) # (y: 0, x: 0) +echo B(y: 678, x: 123) # (y: 678, x: 0) +echo B(x: 123, y: 678) # (y: 678, x: 0) - # inherited fields are ignored - echo C(x: 128, z: 89) # (y: 0, x: 0) - echo B(y: 678, x: 123) # (y: 678, x: 0) - echo B(x: 123, y: 678) # (y: 678, x: 0) +when true: + # correct, both with `var` and `let`; + var b=B(x: 123) + echo b # (y: 0, x: 123) + b=B(y: 678, x: 123) + echo b # (y: 678, x: 123) + b=B(y: b.x, x: b.y) + echo b # (y: 123, x: 678) - when true: - # correct, both with `var` and `let`; - var b=B(x: 123) - echo b # (y: 0, x: 123) - b=B(y: 678, x: 123) - echo b # (y: 678, x: 123) - b=B(y: b.x, x: b.y) - echo b # (y: 123, x: 678) - -main2() GC_fullCollect() diff --git a/tests/objects/tobjconstr2.nim b/tests/objects/tobjconstr2.nim index cf4a694b4..6253edab0 100644 --- a/tests/objects/tobjconstr2.nim +++ b/tests/objects/tobjconstr2.nim @@ -15,8 +15,8 @@ echo s[0].x # bug #563 type - Foo {.inheritable.} = - object + Foo = + object {.inheritable.} x: int Bar = diff --git a/tests/objects/tobjcov.nim b/tests/objects/tobjcov.nim index a12f74702..6c587e04d 100644 --- a/tests/objects/tobjcov.nim +++ b/tests/objects/tobjcov.nim @@ -1,6 +1,6 @@ discard """ action: compile -targets: "c" +target: "c" """ # Covariance is not type safe: diff --git a/tests/objects/tobject.nim b/tests/objects/tobject.nim index a185bebcb..34856eaef 100644 --- a/tests/objects/tobject.nim +++ b/tests/objects/tobject.nim @@ -1,3 +1,8 @@ +discard """ +output: "[Suite] object basic methods" +""" + +import unittest type Obj = object foo: int @@ -5,13 +10,13 @@ type Obj = object proc makeObj(x: int): Obj = result.foo = x -block: # object basic methods - block: # it should convert an object to a string +suite "object basic methods": + test "it should convert an object to a string": var obj = makeObj(1) # Should be "obj: (foo: 1)" or similar. - doAssert($obj == "(foo: 1)") - block: # it should test equality based on fields - doAssert(makeObj(1) == makeObj(1)) + check($obj == "(foo: 1)") + test "it should test equality based on fields": + check(makeObj(1) == makeObj(1)) # bug #10203 @@ -37,38 +42,3 @@ var b: TMyObj = a type InheritableFoo {.inheritable.} = ref object InheritableBar = ref object of InheritableFoo # ERROR. - -block: # bug #14698 - const N = 3 - type Foo[T] = ref object - x1: int - when N == 2: - x2: float - when N == 3: - x3: seq[int] - else: - x4: char - x4b: array[9, char] - - let t = Foo[float](x1: 1) - doAssert $(t[]) == "(x1: 1, x3: @[])" - doAssert t.sizeof == int.sizeof - type Foo1 = object - x1: int - x3: seq[int] - doAssert t[].sizeof == Foo1.sizeof - -# bug #147 -type - TValue* {.pure, final.} = object of RootObj - a: int - PValue = ref TValue - PPValue = ptr PValue - - -var x: PValue -new x -var sp: PPValue = addr x - -sp.a = 2 -doAssert sp.a == 2 diff --git a/tests/objects/tobject3.nim b/tests/objects/tobject3.nim index 9ff1743ce..bec2582fe 100644 --- a/tests/objects/tobject3.nim +++ b/tests/objects/tobject3.nim @@ -82,14 +82,3 @@ proc newArrayAnimationSampler*[T](): ArrayAnimationSampler[T] = discard newArrayAnimationSampler[Foo6]() discard newArrayAnimationSampler[AnotherFoo]() - -type - DefaultIsNone* = pointer | ptr | ref | proc {.nimcall.} | cstring | cstringArray - OptionKind* {.pure.} = enum None, Some - OptionA* [T] = object of RootObj - when T is DefaultIsNone: - value: T - else: - value: T - kind: OptionKind - SomeA* [T] = object of OptionA[T] diff --git a/tests/objects/tobject_default_value.nim b/tests/objects/tobject_default_value.nim deleted file mode 100644 index 59af943e0..000000000 --- a/tests/objects/tobject_default_value.nim +++ /dev/null @@ -1,596 +0,0 @@ -discard """ - matrix: "-d:nimPreviewRangeDefault --mm:refc; -d:nimPreviewRangeDefault --warningAsError:ProveInit --mm:orc" - targets: "c cpp js" -""" - -import std/[times, macros, tables] - -type - Guess = object - poi: DateTime - - GuessDistinct = distinct Guess - -block: - var x: Guess - discard Guess() - - var y: GuessDistinct - - discard y - - discard GuessDistinct(x) - - -import mobject_default_value - -block: - let x = Default() - doAssert x.se == 0'i32 - -block: - let x = default(Default) - doAssert x.se == 0'i32 -# echo Default(poi: 12) -# echo Default(poi: 17) - -# echo NonDefault(poi: 77) - -block: - var x: Default - doAssert x.se == 0'i32 - -type - ObjectBase = object of RootObj - value = 12 - - ObjectBaseDistinct = distinct ObjectBase - - DinstinctInObject = object - data: ObjectBaseDistinct - - Object = object of ObjectBase - time: float = 1.2 - date: int - scale: range[1..10] - - Object2 = object - name: Object - - Object3 = object - obj: Object2 - - ObjectTuple = tuple - base: ObjectBase - typ: int - obj: Object - - TupleInObject = object - size = 777 - data: ObjectTuple - - Ref = ref object of ObjectBase - - RefInt = ref object of Ref - data = 73 - - Ref2 = ref object of ObjectBase - - RefInt2 = ref object of Ref - data = 73 - -var t {.threadvar.}: Default -# var m1, m2 {.threadvar.}: Default - -block: - doAssert t.se == 0'i32 - -block: # ARC/ORC cannot bind destructors twice, so it cannot - # be moved into main - block: - var x: Ref - new(x) - doAssert x.value == 12, "Ref.value = " & $x.value - - var y: RefInt - new(y) - doAssert y.value == 12 - doAssert y.data == 73 - - block: - var x: Ref2 - new(x, proc (x: Ref2) {.nimcall.} = discard "call Ref") - doAssert x.value == 12, "Ref.value = " & $x.value - - proc call(x: RefInt2) = - discard "call RefInt" - - var y: RefInt2 - new(y, call) - doAssert y.value == 12 - doAssert y.data == 73 - -template main {.dirty.} = - block: # bug #16744 - type - R = range[1..10] - Obj = object - r: R - - var - rVal: R = default(R) # Works fine - objVal = default(Obj) - - doAssert rVal == 0 # it should be 1 - doAssert objVal.r == 1 - - block: # bug #16744 - type - R = range[1..10] - Obj = object - r: R - - var - rVal: R = default(R) # Works fine - objVal = Obj() - - doAssert rVal == 0 # it should be 1 - doAssert objVal.r == 1 - - block: # bug #3608 - type - abc = ref object - w: range[2..100] - - proc createABC(): abc = - new(result) - result.w = 20 - - doAssert createABC().w == 20 - - block: - var x = new ObjectBase - doAssert x.value == 12 - - proc hello(): ref ObjectBase = - new result - - let z = hello() - doAssert z.value == 12 - - block: - var base = ObjectBase() - var x: ObjectBaseDistinct = ObjectBaseDistinct(base) - doAssert ObjectBase(x).value == 12 - let y = ObjectBaseDistinct(default(ObjectBase)) - doAssert ObjectBase(y).value == 12 - - let m = ObjectBaseDistinct(ObjectBase()) - doAssert ObjectBase(m).value == 12 - - proc hello(): ObjectBaseDistinct = - result = ObjectBaseDistinct(default(ObjectBase)) - - let z = hello() - doAssert ObjectBase(z).value == 12 - - block: - var x: DinstinctInObject - x.data = ObjectBaseDistinct(default(ObjectBase)) - - doAssert ObjectBase(x.data).value == 12 - - block: - var x = Object() - doAssert x.value == 12 - doAssert x.time == 1.2 - doAssert x.scale == 1 - - let y = default(Object) - doAssert y.value == 12 - doAssert y.time == 1.2 - doAssert y.scale == 1 - - var x1, x2, x3 = default(Object) - doAssert x1.value == 12 - doAssert x1.time == 1.2 - doAssert x1.scale == 1 - doAssert x2.value == 12 - doAssert x2.time == 1.2 - doAssert x2.scale == 1 - doAssert x3.value == 12 - doAssert x3.time == 1.2 - doAssert x3.scale == 1 - - block: - var x = new Object - doAssert x[] == default(Object) - - block: - var x = default(Object2) - doAssert x.name.value == 12 - doAssert x.name.time == 1.2 - doAssert x.name.scale == 1 - - block: - let x = Object2() - doAssert x.name.value == 12 - doAssert x.name.time == 1.2 - doAssert x.name.scale == 1 - - block: - var x: ref Object2 - new x - doAssert x[] == default(Object2) - - block: - var x = default(Object3) - doAssert x.obj.name.value == 12 - doAssert x.obj.name.time == 1.2 - doAssert x.obj.name.scale == 1 - - block: - var x = Object3() - doAssert x.obj.name.value == 12 - doAssert x.obj.name.time == 1.2 - doAssert x.obj.name.scale == 1 - - when nimvm: - # todo - discard "fixme" - else: - when defined(gcArc) or defined(gcOrc): - block: #seq - var x = newSeq[Object](10) - let y = x[0] - doAssert y.value == 12 - doAssert y.time == 1.2 - doAssert y.scale == 1 - - block: - var x: seq[Object] - setLen(x, 5) - let y = x[^1] - doAssert y.value == 12 - doAssert y.time == 1.2 - doAssert y.scale == 1 - - block: - var my = @[1, 2, 3, 4, 5] - my.setLen(0) - my.setLen(5) - doAssert my == @[0, 0, 0, 0, 0] - - block: - var my = "hello" - my.setLen(0) - my.setLen(5) - doAssert $(@my) == """@['\x00', '\x00', '\x00', '\x00', '\x00']""" - - block: # array - var x: array[10, Object] = default(array[10, Object]) - let y = x[0] - doAssert y.value == 12 - doAssert y.time == 1.2 - doAssert y.scale == 1 - - block: # array - var x {.noinit.}: array[10, Object] - discard x - - block: # tuple - var x = default(ObjectTuple) - doAssert x.base.value == 12 - doAssert x.typ == 0 - doAssert x.obj.time == 1.2 - doAssert x.obj.date == 0 - doAssert x.obj.scale == 1 - doAssert x.obj.value == 12 - - block: # tuple in object - var x = default(TupleInObject) - doAssert x.data.base.value == 12 - doAssert x.data.typ == 0 - doAssert x.data.obj.time == 1.2 - doAssert x.data.obj.date == 0 - doAssert x.data.obj.scale == 1 - doAssert x.data.obj.value == 12 - doAssert x.size == 777 - - type - ObjectArray = object - data: array[10, Object] - - block: - var x = default(ObjectArray) - let y = x.data[0] - doAssert y.value == 12 - doAssert y.time == 1.2 - doAssert y.scale == 1 - - block: - var x: PrellDeque[int] - doAssert x.pendingTasks == 0 - - type - Color = enum - Red, Blue, Yellow - - ObjectVarint = object - case kind: Color - of Red: - data: int = 10 - of Blue: - fill = "123" - of Yellow: - time = 1.8'f32 - - ObjectVarint1 = object - case kind: Color = Blue - of Red: - data1: int = 10 - of Blue: - fill2 = "123" - cry: float - of Yellow: - time3 = 1.8'f32 - him: int - - block: - var x = ObjectVarint(kind: Red) - doAssert x.kind == Red - doAssert x.data == 10 - - block: - var x = ObjectVarint(kind: Blue) - doAssert x.kind == Blue - doAssert x.fill == "123" - - block: - var x = ObjectVarint(kind: Yellow) - doAssert x.kind == Yellow - doAssert typeof(x.time) is float32 - - block: - var x = default(ObjectVarint1) - doAssert x.kind == Blue - doAssert x.fill2 == "123" - x.cry = 326 - - type - ObjectVarint2 = object - case kind: Color - of Red: - data: int = 10 - of Blue: - fill = "123" - of Yellow: - time = 1.8'f32 - - block: - var x = ObjectVarint2(kind: Blue) - doAssert x.fill == "123" - - block: - type - Color = enum - Red, Blue, Yellow - - type - ObjectVarint3 = object # fixme it doesn't work with static - case kind: Color = Blue - of Red: - data1: int = 10 - of Blue: - case name: Color = Blue - of Blue: - go = 12 - else: - temp = 66 - fill2 = "123" - cry: float - of Yellow: - time3 = 1.8'f32 - him: int - - block: - var x = default(ObjectVarint3) - doAssert x.kind == Blue - doAssert x.name == Blue - doAssert x.go == 12 - - block: - var x = ObjectVarint3(kind: Blue, name: Red, temp: 99) - doAssert x.kind == Blue - doAssert x.name == Red - doAssert x.temp == 99 - - block: - type - Default = tuple - id: int = 1 - obj: ObjectBase - name: string - - Class = object - def: Default - - Member = object - def: Default = (id: 777, obj: ObjectBase(), name: "fine") - - block: - var x = default(Default) - doAssert x.id == 1 - doAssert x.obj == default(ObjectBase) - doAssert x.name == "" - - block: - var x = default(Class) - doAssert x.def == default(Default) - doAssert x.def.id == 1 - doAssert x.def.obj == default(ObjectBase) - doAssert x.def.name == "" - - block: - var x = default(Member) - doAssert x.def.id == 777 - doAssert x.def.obj == default(ObjectBase) - doAssert x.def.name == "fine" - - block: - var x {.noinit.} = 12 - doAssert x == 12 - - type - Pure = object - id: int = 12 - - var y {.noinit.}: Pure - doAssert y.id == 0 - - var z {.noinit.}: Pure = Pure(id: 77) - doAssert z.id == 77 - - block: # bug #20681 - type A = object - d: DateTime = DateTime() - - let x = default(A) - doAssert $x == "(d: Uninitialized DateTime)" - - block: # bug #20715 - block: - type - Foo = enum - A - B - - Bar = object - case foo: Foo - of A: - t: range[-1..2] - else: discard - - var d = default(Bar) - doAssert d.t == -1 - - block: - type - Foo = enum - A - B - - Bar = object - case foo: Foo - of A: - t: range[0..2] - else: discard - - var d = default(Bar) - doAssert d.t == 0 - - block: # bug #20740 - block: - proc foo(x: static DateTime = Datetime()) = - discard - - foo() - - block: - macro foo(x: static DateTime) = - discard x - - macro foo2: untyped = - var x = DateTime() - - result = quote do: - foo(`x`) - - foo2() - - - block: # issue #20699 - type - Either[A,B] = object - case kind:bool - of false: - b: B - of true: - a: A - O = object of RootRef - - proc oToEither(o:O):Either[O,void] = - Either[O,void](kind:true,a: o) - - discard oToEither(O()) - - block: # bug #20695 - type - Default = object - tabs: Table[string, int] = initTable[string, int]() - - let d = default(Default) - doAssert d.tabs.len == 0 - - block: - type - Default = object - tabs: Table[string, int] = Table[string, int]() - - let d = default(Default) - doAssert d.tabs.len == 0 - - - block: - type DjangoDateTime = distinct DateTime - - type Default = object - data: DjangoDateTime = DjangoDateTime(DateTime()) - - let x = default(Default) - doAssert x.data is DjangoDateTime - - block: - type DjangoDateTime = distinct DateTime - - type Default = object - data = DjangoDateTime(DateTime()) - - let x = default(Default) - doAssert x.data is DjangoDateTime - - block: - type - Result2 = object - case o: bool - of false: - e: float - of true: - v {.requiresInit.} : int = 1 - - proc startSessionSync(): Result2 = - return Result2(o: true) - - proc mainSync = - let ff = startSessionSync() - doAssert ff.v == 1 - - mainSync() - - block: - type - Result2 = object - v {.requiresInit.} : int = 1 - - proc startSessionSync(): Result2 = - return Result2() - - proc mainSync = - let ff = startSessionSync() - doAssert ff.v == 1 - - mainSync() - - -static: main() -main() diff --git a/tests/objects/tobjects_issues.nim b/tests/objects/tobjects_issues.nim index f1a416d04..fddfff7d5 100644 --- a/tests/objects/tobjects_issues.nim +++ b/tests/objects/tobjects_issues.nim @@ -113,5 +113,5 @@ block t3038: Type = ref object of RootObj SubType[T] = ref object of Type data: Data[T] - SubSubType = ref object of SubType[int] + SubSubType = ref object of SubType SubSubSubType = ref object of SubSubType diff --git a/tests/objects/tobjects_various.nim b/tests/objects/tobjects_various.nim index 55db9312e..315193de9 100644 --- a/tests/objects/tobjects_various.nim +++ b/tests/objects/tobjects_various.nim @@ -31,7 +31,7 @@ block tobject2: block tofopr: type - TMyType {.inheritable.} = object + TMyType = object {.inheritable.} len: int data: string @@ -105,16 +105,3 @@ block t7244: proc test(foo: var Foo) = discard proc test(bar: var Bar) = test(Foo(bar)) - - -import std/macros - -#bug #20856 -macro ensureImplWorksOnConstr(t: typed): untyped = - expectKind(t, nnkObjConstr) - doAssert t[0].getTypeInst.getImpl.repr == "A = object" - doAssert t[0].getImpl.repr == "A = object" - -type A = object - -ensureImplWorksOnConstr(A()) diff --git a/tests/objects/tunsafenew.nim b/tests/objects/tunsafenew.nim deleted file mode 100644 index 6c1b33cd9..000000000 --- a/tests/objects/tunsafenew.nim +++ /dev/null @@ -1,10 +0,0 @@ -discard """ - errormsg: "conversion from int literal(-1) to Natural is invalid" -""" - -type - Obj = object - case b: bool - else: discard -var o: ref Obj -unsafeNew(o, -1) \ No newline at end of file diff --git a/tests/objects/tunsafenew2.nim b/tests/objects/tunsafenew2.nim deleted file mode 100644 index 83112bcfc..000000000 --- a/tests/objects/tunsafenew2.nim +++ /dev/null @@ -1,15 +0,0 @@ -discard """ -valgrind: "leaks" -matrix: "-d:useMalloc" -targets: "c cpp" -""" - -type - Obj = object - case b: bool - else: discard - a: UncheckedArray[byte] - -var o: ref Obj -unsafeNew(o, sizeof(Obj) + 512) -zeroMem(addr o.a, 512) diff --git a/tests/objects/twhen1.nim b/tests/objects/twhen1.nim index 5b8eea3f4..2301d255a 100644 --- a/tests/objects/twhen1.nim +++ b/tests/objects/twhen1.nim @@ -49,9 +49,3 @@ block: block: var x: Foo4[0] - -type - MyObject = object - x: int - when (NimMajor, NimMinor) >= (1, 1): - y: int diff --git a/tests/objvariant/t14581.nim b/tests/objvariant/t14581.nim deleted file mode 100644 index 72ba32f18..000000000 --- a/tests/objvariant/t14581.nim +++ /dev/null @@ -1,25 +0,0 @@ -discard """ - matrix: "--gc:refc; --gc:arc" - output: "abc: @[(kind: A, x: 0)]" -""" - -import std/tables - -type E = enum - A, B - -type O = object - case kind: E - of A: - x: int - of B: - y: int - -proc someTable(): Table[string, seq[O]] = - result = initTable[string, seq[O]]() - result["abc"] = @[O(kind: A)] - -const t = someTable() - -for k, v in t: - echo k, ": ", v diff --git a/tests/objvariant/tcheckedfield1.nim b/tests/objvariant/tcheckedfield1.nim index 4a6c49f66..69b099f24 100644 --- a/tests/objvariant/tcheckedfield1.nim +++ b/tests/objvariant/tcheckedfield1.nim @@ -1,5 +1,6 @@ discard """ - nimout: "tcheckedfield1.nim(39, 6) Warning: cannot prove that field 'x.s' is accessible [ProveField]" + nimout: "Warning: cannot prove that field 'x.s' is accessible [ProveField]" + line:51 action: run output: "abc abc" """ diff --git a/tests/objvariant/tconstructionorder.nim b/tests/objvariant/tconstructionorder.nim index 5ca484884..19ddea7a1 100644 --- a/tests/objvariant/tconstructionorder.nim +++ b/tests/objvariant/tconstructionorder.nim @@ -23,22 +23,22 @@ type # This will test that all the values are what we expect. proc assertTree(root: Node) = # check root of tree - doAssert root.kind == Operator - doAssert root.operator == '*' + assert root.kind == Operator + assert root.operator == '*' # check left subtree - doAssert root.left.value == 5 - doAssert root.left.kind == Literal + assert root.left.value == 5 + assert root.left.kind == Literal # check right subtree - doAssert root.right.kind == Operator - doAssert root.right.operator == '+' + assert root.right.kind == Operator + assert root.right.operator == '+' - doAssert root.right.left.value == 5 - doAssert root.right.left.kind == Literal + assert root.right.left.value == 5 + assert root.right.left.kind == Literal - doAssert root.right.right.value == 10 - doAssert root.right.right.kind == Literal + assert root.right.right.value == 10 + assert root.right.right.kind == Literal proc newLiteralNode(value: int): Node = result = Node( diff --git a/tests/objvariant/treassign.nim b/tests/objvariant/treassign.nim index 527204616..2938b30a3 100644 --- a/tests/objvariant/treassign.nim +++ b/tests/objvariant/treassign.nim @@ -25,34 +25,3 @@ t.curr = TokenObject(kind: Token.bar, bar: BasicNumber(value: 12.34)) t.curr = TokenObject(kind: Token.foo, foo: "foo") echo "SUCCESS" - -proc passToVar(x: var Token) = discard - -{.cast(uncheckedAssign).}: - passToVar(t.curr.kind) - - t.curr = TokenObject(kind: t.curr.kind, foo: "abc") - - t.curr.kind = Token.foo - - -block: - type - TokenKind = enum - strLit, intLit - Token = object - case kind*: TokenKind - of strLit: - s*: string - of intLit: - i*: int64 - - var t = Token(kind: strLit, s: "abc") - - {.cast(uncheckedAssign).}: - - # inside the 'cast' section it is allowed to assign to the 't.kind' field directly: - t.kind = intLit - - {.cast(uncheckedAssign).}: - t.kind = strLit \ No newline at end of file diff --git a/tests/openarray/topena1.nim b/tests/openarray/topena1.nim index 380c57f2a..ed3a0cedb 100644 --- a/tests/openarray/topena1.nim +++ b/tests/openarray/topena1.nim @@ -6,4 +6,4 @@ discard """ # Tests a special bug var - x: ref openArray[string] #ERROR_MSG invalid type + x: ref openarray[string] #ERROR_MSG invalid type diff --git a/tests/openarray/topenarray.nim b/tests/openarray/topenarray.nim deleted file mode 100644 index c752becf2..000000000 --- a/tests/openarray/topenarray.nim +++ /dev/null @@ -1,53 +0,0 @@ -discard """ - targets: "c cpp js" -""" - -proc fn1[T](a: openArray[T]): seq[T] = - for ai in a: result.add ai - -proc fn2[T](a: var openArray[T]): seq[T] = - for ai in a: result.add ai - -proc fn3[T](a: var openArray[T]) = - for i, ai in mpairs(a): ai = i * 10 - -proc main = - var a = [1,2,3,4,5] - - doAssert fn1(a.toOpenArray(1,3)) == @[2,3,4] - - doAssert fn2(toOpenArray(a, 1, 3)) == @[2,3,4] - doAssert fn2(a.toOpenArray(1,3)) == @[2,3,4] - - fn3(a.toOpenArray(1,3)) - when defined(js): discard # xxx bug #15952: `a` left unchanged - else: doAssert a == [1, 0, 10, 20, 5] - - block: # bug #12521 - block: - type slice[T] = openArray[T] - - # Proc using that alias - proc testing(sl: slice[int]): seq[int] = - for item in sl: - result.add item - - let mySeq = @[1, 2, 3, 4, 5, 6, 7, 8, 9] - doAssert testing(mySeq) == mySeq - doAssert testing(mySeq[2..^2]) == mySeq[2..^2] - - block: - type slice = openArray[int] - - # Proc using that alias - proc testing(sl: slice): seq[int] = - for item in sl: - result.add item - - let mySeq = @[1, 2, 3, 4, 5, 6, 7, 8, 9] - doAssert testing(mySeq) == mySeq - doAssert testing(mySeq[2..^2]) == mySeq[2..^2] - - -main() -static: main() diff --git a/tests/openarray/topenarrayrepr.nim b/tests/openarray/topenarrayrepr.nim index fc40d88c3..3784d4bbb 100644 --- a/tests/openarray/topenarrayrepr.nim +++ b/tests/openarray/topenarrayrepr.nim @@ -2,12 +2,12 @@ discard """ output: "5 - [1]" """ type - TProc = proc (n: int, m: openArray[int64]) {.nimcall.} + TProc = proc (n: int, m: openarray[int64]) {.nimcall.} proc Foo(x: int, P: TProc) = P(x, [ 1'i64 ]) -proc Bar(n: int, m: openArray[int64]) = +proc Bar(n: int, m: openarray[int64]) = echo($n & " - " & repr(m)) Foo(5, Bar) #OUT 5 - [1] diff --git a/tests/openarray/topenlen.nim b/tests/openarray/topenlen.nim index 164241b85..83d58ac5c 100644 --- a/tests/openarray/topenlen.nim +++ b/tests/openarray/topenlen.nim @@ -5,7 +5,7 @@ discard """ proc choose(b: openArray[string]): string = return b[0] -proc p(a, b: openArray[string]): int = +proc p(a, b: openarray[string]): int = result = a.len + b.len - 1 for j in 0 .. a.len: inc(result) discard choose(a) diff --git a/tests/openarray/tptrarrayderef.nim b/tests/openarray/tptrarrayderef.nim index 1b7ef0df0..5e77430d1 100644 --- a/tests/openarray/tptrarrayderef.nim +++ b/tests/openarray/tptrarrayderef.nim @@ -15,14 +15,14 @@ var raa = [11,12,13] #bug #3586 -proc mutate[T](arr:openArray[T], brr: openArray[T]) = +proc mutate[T](arr:openarray[T], brr: openArray[T]) = for i in 0..arr.len-1: doAssert(arr[i] == brr[i]) mutate(arr, arr) #bug #2240 -proc f(a: openArray[int], b: openArray[int]) = +proc f(a: openarray[int], b: openArray[int]) = for i in 0..a.len-1: doAssert(a[i] == b[i]) @@ -37,7 +37,7 @@ ra[2] = 13 f(ra[], raa) #bug #2240b -proc fillBuffer(buf: var openArray[char]) = +proc fillBuffer(buf: var openarray[char]) = for i in 0..buf.len-1: buf[i] = chr(i) diff --git a/tests/osproc/passenv.nim b/tests/osproc/passenv.nim index 40b1c3f7c..815f7536f 100644 --- a/tests/osproc/passenv.nim +++ b/tests/osproc/passenv.nim @@ -1,7 +1,7 @@ discard """ file: "passenv.nim" output: "123" - targets: "c cpp objc" + targets: "c c++ objc" """ import osproc, os, strtabs diff --git a/tests/osproc/ta_in.nim b/tests/osproc/ta_in.nim new file mode 100644 index 000000000..fb294ec14 --- /dev/null +++ b/tests/osproc/ta_in.nim @@ -0,0 +1,9 @@ +discard """ +action: compile +""" + +# This file is prefixed with an "a", because other tests +# depend on it and it must be compiled first. +import strutils +let x = stdin.readLine() +echo x.parseInt + 5 diff --git a/tests/osproc/ta_out.nim b/tests/osproc/ta_out.nim new file mode 100644 index 000000000..01b78eb11 --- /dev/null +++ b/tests/osproc/ta_out.nim @@ -0,0 +1,33 @@ +discard """ +output: ''' +start ta_out +to stdout +to stdout +to stderr +to stderr +to stdout +to stdout +end ta_out +''' +""" + +echo "start ta_out" + +# This file is prefixed with an "a", because other tests +# depend on it and it must be compiled first. +stdout.writeLine("to stdout") +stdout.flushFile() +stdout.writeLine("to stdout") +stdout.flushFile() + +stderr.writeLine("to stderr") +stderr.flushFile() +stderr.writeLine("to stderr") +stderr.flushFile() + +stdout.writeLine("to stdout") +stdout.flushFile() +stdout.writeLine("to stdout") +stdout.flushFile() + +echo "end ta_out" diff --git a/tests/osproc/tafalse.nim b/tests/osproc/tafalse.nim new file mode 100644 index 000000000..05a0bfce9 --- /dev/null +++ b/tests/osproc/tafalse.nim @@ -0,0 +1,7 @@ +discard """ +exitcode: 1 +""" + +# 'tafalse.nim' to ensure it is compiled before texitcode.nim +import system +quit(QuitFailure) diff --git a/tests/osproc/tclose.nim b/tests/osproc/tclose.nim index 1c99237c7..d466b466a 100644 --- a/tests/osproc/tclose.nim +++ b/tests/osproc/tclose.nim @@ -13,12 +13,12 @@ when defined(linux): let initCount = countFds() let p = osproc.startProcess("echo", options={poUsePath}) - doAssert countFds() == initCount + 3 + assert countFds() == initCount + 3 p.close - doAssert countFds() == initCount + assert countFds() == initCount let p1 = osproc.startProcess("echo", options={poUsePath}) discard p1.inputStream - doAssert countFds() == initCount + 3 + assert countFds() == initCount + 3 p.close - doAssert countFds() == initCount + assert countFds() == initCount diff --git a/tests/osproc/texecps.nim b/tests/osproc/texecps.nim index b818fe8eb..10715fa0f 100644 --- a/tests/osproc/texecps.nim +++ b/tests/osproc/texecps.nim @@ -1,7 +1,3 @@ -discard """ -joinable: false -""" - import osproc, streams, strutils, os const NumberOfProcesses = 13 diff --git a/tests/osproc/texitcode.nim b/tests/osproc/texitcode.nim new file mode 100644 index 000000000..558017716 --- /dev/null +++ b/tests/osproc/texitcode.nim @@ -0,0 +1,23 @@ +discard """ + output: "" +""" + +import osproc, os + +const filename = when defined(Windows): "tafalse.exe" else: "tafalse" +let dir = getCurrentDir() / "tests" / "osproc" +doAssert fileExists(dir / filename) + +var p = startProcess(filename, dir) +doAssert(waitForExit(p) == QuitFailure) + +p = startProcess(filename, dir) +var running = true +while running: + running = running(p) +doAssert(waitForExit(p) == QuitFailure) + +# make sure that first call to running() after process exit returns false +p = startProcess(filename, dir) +os.sleep(500) +doAssert(not running(p)) diff --git a/tests/osproc/treadlines.nim b/tests/osproc/treadlines.nim deleted file mode 100644 index bb6a7f129..000000000 --- a/tests/osproc/treadlines.nim +++ /dev/null @@ -1,23 +0,0 @@ -discard """ - output: ''' -Error: cannot open 'a.nim' -Error: cannot open 'b.nim' -''' - targets: "c" -""" - -import osproc -from std/os import getCurrentCompilerExe - -var ps: seq[Process] # compile & run 2 progs in parallel -const nim = getCurrentCompilerExe() -for prog in ["a", "b"]: - ps.add startProcess(nim, "", - ["r", "--hint:Conf:off", "--hint:Processing:off", prog], - options = {poUsePath, poDaemon, poStdErrToStdOut}) - -for p in ps: - let (lines, exCode) = p.readLines - if exCode != 0: - for line in lines: echo line - p.close diff --git a/tests/osproc/tstderr.nim b/tests/osproc/tstderr.nim new file mode 100644 index 000000000..55b11eba5 --- /dev/null +++ b/tests/osproc/tstderr.nim @@ -0,0 +1,37 @@ +discard """ + output: ''' +start tstderr +-------------------------------------- +to stderr +to stderr +-------------------------------------- +''' +""" + +echo "start tstderr" + +import osproc, os, streams + +const filename = "ta_out".addFileExt(ExeExt) + +doAssert fileExists(getCurrentDir() / "tests" / "osproc" / filename) + +var p = startProcess(filename, getCurrentDir() / "tests" / "osproc", + options={}) + +try: + let stdoutStream = p.outputStream + let stderrStream = p.errorStream + var x = newStringOfCap(120) + var output = "" + while stderrStream.readLine(x.TaintedString): + output.add(x & "\n") + + echo "--------------------------------------" + stdout.flushFile() + stderr.write output + stderr.flushFile() + echo "--------------------------------------" + stdout.flushFile() +finally: + p.close() diff --git a/tests/osproc/tstdin.nim b/tests/osproc/tstdin.nim new file mode 100644 index 000000000..8579680ab --- /dev/null +++ b/tests/osproc/tstdin.nim @@ -0,0 +1,17 @@ +discard """ + output: "10" +""" +import osproc, os, streams + +const filename = when defined(Windows): "ta_in.exe" else: "ta_in" + +doAssert fileExists(getCurrentDir() / "tests" / "osproc" / filename) + +var p = startProcess(filename, getCurrentDir() / "tests" / "osproc") +p.inputStream.write("5\n") +p.inputStream.flush() + +var line = "" + +while p.outputStream.readLine(line.TaintedString): + echo line diff --git a/tests/osproc/tstdout.nim b/tests/osproc/tstdout.nim new file mode 100644 index 000000000..e3ed3986a --- /dev/null +++ b/tests/osproc/tstdout.nim @@ -0,0 +1,31 @@ +discard """ + output: '''-------------------------------------- +start ta_out +to stdout +to stdout +to stderr +to stderr +to stdout +to stdout +end ta_out +-------------------------------------- +''' +""" +import osproc, os, streams + +const filename = when defined(Windows): "ta_out.exe" else: "ta_out" + +doAssert fileExists(getCurrentDir() / "tests" / "osproc" / filename) + +var p = startProcess(filename, getCurrentDir() / "tests" / "osproc", + options={poStdErrToStdOut}) + +let outputStream = p.outputStream +var x = newStringOfCap(120) +var output = "" +while outputStream.readLine(x.TaintedString): + output.add(x & "\n") + +echo "--------------------------------------" +stdout.write output +echo "--------------------------------------" diff --git a/tests/overflow/tdistinct_range.nim b/tests/overflow/tdistinct_range.nim deleted file mode 100644 index f53515d45..000000000 --- a/tests/overflow/tdistinct_range.nim +++ /dev/null @@ -1,6 +0,0 @@ -discard """ - outputsub: "Error: unhandled exception: over- or underflow [OverflowDefect]" - exitcode: "1" -""" -var x: distinct range[0..5] -dec(x) \ No newline at end of file diff --git a/tests/overflow/toverflow.nim b/tests/overflow/toverflow.nim deleted file mode 100644 index 972f929c6..000000000 --- a/tests/overflow/toverflow.nim +++ /dev/null @@ -1,82 +0,0 @@ -discard """ - output: "ok" - matrix: "--overflowChecks:off; --overflowChecks:off --b:js" -""" -# Tests nim's ability to detect overflows - -{.push overflowChecks: on.} - -var - a = high(int) - b = -2 - overflowDetected = false - -try: - echo(b - a) -except OverflowDefect: - overflowDetected = true - -{.pop.} # overflow check - -doAssert(overflowDetected) - -block: # Overflow checks in a proc - var - a = high(int) - b = -2 - overflowDetected = false - - {.push overflowChecks: on.} - proc foo() = - let c = b - a - {.pop.} - - try: - foo() - except OverflowDefect: - overflowDetected = true - - doAssert(overflowDetected) - -block: # Overflow checks in a forward declared proc - var - a = high(int) - b = -2 - overflowDetected = false - - proc foo() - - {.push overflowChecks: on.} - proc foo() = - let c = b - a - {.pop.} - - try: - foo() - except OverflowDefect: - overflowDetected = true - - doAssert(overflowDetected) - -block: # Overflow checks doesn't affect fwd declaration - var - a = high(int) - b = -2 - overflowDetected = false - - {.push overflowChecks: on.} - proc foo() - {.pop.} - - proc foo() = - let c = b - a - - try: - foo() - except OverflowDefect: - overflowDetected = true - - doAssert(not overflowDetected) - - -echo "ok" diff --git a/tests/overflow/toverflow_reorder.nim b/tests/overflw/toverflw.nim similarity index 88% rename from tests/overflow/toverflow_reorder.nim rename to tests/overflw/toverflw.nim index fcf7b0c82..d96231900 100644 --- a/tests/overflow/toverflow_reorder.nim +++ b/tests/overflw/toverflw.nim @@ -1,5 +1,3 @@ -{.experimental: "codeReordering".} - discard """ output: "ok" cmd: "nim $target --overflowChecks:off $options $file" @@ -14,8 +12,8 @@ var overflowDetected = false try: - echo b - a -except OverflowDefect: + writeLine(stdout, b - a) +except OverflowError: overflowDetected = true {.pop.} # overflow check @@ -35,7 +33,7 @@ block: # Overflow checks in a proc try: foo() - except OverflowDefect: + except OverflowError: overflowDetected = true doAssert(overflowDetected) @@ -55,7 +53,7 @@ block: # Overflow checks in a forward declared proc try: foo() - except OverflowDefect: + except OverflowError: overflowDetected = true doAssert(overflowDetected) @@ -75,7 +73,7 @@ block: # Overflow checks doesn't affect fwd declaration try: foo() - except OverflowDefect: + except OverflowError: overflowDetected = true doAssert(not overflowDetected) diff --git a/tests/overflow/toverflow2.nim b/tests/overflw/toverflw2.nim similarity index 91% rename from tests/overflow/toverflow2.nim rename to tests/overflw/toverflw2.nim index c06b35c6d..91b900ca4 100644 --- a/tests/overflow/toverflow2.nim +++ b/tests/overflw/toverflw2.nim @@ -1,5 +1,5 @@ discard """ - outputsub: "Error: unhandled exception: over- or underflow [OverflowDefect]" + outputsub: "Error: unhandled exception: over- or underflow [OverflowError]" exitcode: "1" """ var a : int32 = 2147483647 diff --git a/tests/overflow/tovfint.nim b/tests/overflw/tovfint.nim similarity index 100% rename from tests/overflow/tovfint.nim rename to tests/overflw/tovfint.nim diff --git a/tests/overload/t7416.nim b/tests/overload/t7416.nim deleted file mode 100644 index 4a9b2e7cb..000000000 --- a/tests/overload/t7416.nim +++ /dev/null @@ -1,9 +0,0 @@ -type - Foo[T] = object - IntFoo = Foo[int] - -proc bar(b: object|tuple) = discard -proc bar(b: IntFoo) = discard - -var f: IntFoo -bar(f) \ No newline at end of file diff --git a/tests/overload/t8829.nim b/tests/overload/t8829.nim deleted file mode 100644 index fe0dbf2bf..000000000 --- a/tests/overload/t8829.nim +++ /dev/null @@ -1,18 +0,0 @@ -block: - let txt = "Hello World" - - template `[]`[T](p: ptr T, span: Slice[int]): untyped = - toOpenArray(cast[ptr array[0, T]](p)[], span.a, span.b) - - doAssert $cast[ptr uint8](txt[0].addr)[0 ..< txt.len] == - "[72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100]" - - -block: - let txt = "Hello World" - - template `[]`[T](p: ptr T, span: Slice[int]): untyped = - toOpenArray(cast[ptr array[0, T]](p)[], span.a, span.b) - - doAssert $cast[ptr uint8](txt[0].addr)[0 ..< txt.len] == - "[72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100]" diff --git a/tests/overload/tnamedparamoverloading.nim b/tests/overload/tnamedparamoverloading.nim deleted file mode 100644 index a7c37ba52..000000000 --- a/tests/overload/tnamedparamoverloading.nim +++ /dev/null @@ -1,14 +0,0 @@ -discard """ - output: ''' -Using x: 2 -Using y: 2 -''' -""" - -proc foo(x: int) = - echo "Using x: ", x -proc foo(y: int) = - echo "Using y: ", y - -foo(x = 2) -foo(y = 2) \ No newline at end of file diff --git a/tests/overload/toverl4.nim b/tests/overload/toverl4.nim index 21cedaa96..537925674 100644 --- a/tests/overload/toverl4.nim +++ b/tests/overload/toverl4.nim @@ -1,6 +1,5 @@ discard """ - output: '''true -5.0''' + output: '''true''' """ #bug #592 @@ -76,26 +75,3 @@ proc add*[TKey, TData](root: var PElement[TKey, TData], key: TKey, data: TData) var tree = PElement[int, int](kind: ElementKind.inner, key: 0, left: nil, right: nil) let result = add(tree, 1, 1) echo(result) - -# bug #3748 -type - Foo = object - bar: int - -proc bar(cur: Foo, val: int, s:seq[string]) = - discard cur.bar - -proc does_fail(): Foo = - let a = @["a"] - result.bar(5, a) - -doAssert does_fail().bar == 0 - -# bug #20645 - -type Zzz[Gen] = object - -proc testZ(z: Zzz) = - echo z.Gen(5) - -testZ(Zzz[float]()) diff --git a/tests/overload/toverload_various.nim b/tests/overload/toverload_various.nim index 0741fce60..78497e607 100644 --- a/tests/overload/toverload_various.nim +++ b/tests/overload/toverload_various.nim @@ -264,245 +264,9 @@ proc init*[T](hmctx: HMAC[T], key: ptr byte, ulen: uint) = const sizeBlock = hmctx.sizeBlock echo sizeBlock -proc hmac*[A, B](HashType: typedesc, key: openArray[A], - data: openArray[B]) = +proc hmac*[A, B](HashType: typedesc, key: openarray[A], + data: openarray[B]) = var ctx: HMAC[HashType] ctx.init(nil, 0) sha256.hmac("", "") - - - -# nested generic types -block: - type - Foo[T] = object - f: T - Bar[T] = object - b: T - Baz[T] = object - z: T - FooBar[T] = Foo[Bar[T]] - FooBarBaz[T] = FooBar[Baz[T]] - #Int = int - Int = SomeInteger - FooBarBazInt = FooBarBaz[Int] - FooBarBazX = FooBarBaz[int] - - proc p00(x: Foo): auto = x.f - proc p01[T](x: Foo[T]): auto = x.f - proc p02[T:Foo](x: T): auto = x.f - - proc p10(x: FooBar): auto = x.f - proc p11[T](x: FooBar[T]): auto = x.f - proc p12[T:FooBar](x: T): auto = x.f - proc p13(x: Foo[Bar]): auto = x.f - proc p14[T](x: Foo[Bar[T]]): auto = x.f - proc p15[T:Bar](x: Foo[T]): auto = x.f - proc p16[T:Foo[Bar]](x: T): auto = x.f - - proc p20(x: FooBarBaz): auto = x.f - proc p21[T](x: FooBarBaz[T]): auto = x.f - proc p22[T:FooBarBaz](x: T): auto = x.f - proc p23(x: FooBar[Baz]): auto = x.f - proc p24[T](x: FooBar[Baz[T]]): auto = x.f - proc p25[T:Baz](x: FooBar[T]): auto = x.f - proc p26[T:FooBar[Baz]](x: T): auto = x.f - proc p27(x: Foo[Bar[Baz]]): auto = x.f - proc p28[T](x: Foo[Bar[Baz[T]]]): auto = x.f - proc p29[T:Baz](x: Foo[Bar[T]]): auto = x.f - proc p2A[T:Bar[Baz]](x: Foo[T]): auto = x.f - proc p2B[T:Foo[Bar[Baz]]](x: T): auto = x.f - - proc p30(x: FooBarBazInt): auto = x.f - proc p31[T:FooBarBazInt](x: T): auto = x.f - proc p32(x: FooBarBaz[Int]): auto = x.f - proc p33[T:Int](x: FooBarBaz[T]): auto = x.f - proc p34[T:FooBarBaz[Int]](x: T): auto = x.f - proc p35(x: FooBar[Baz[Int]]): auto = x.f - proc p36[T:Int](x: FooBar[Baz[T]]): auto = x.f - proc p37[T:Baz[Int]](x: FooBar[T]): auto = x.f - proc p38[T:FooBar[Baz[Int]]](x: T): auto = x.f - proc p39(x: Foo[Bar[Baz[Int]]]): auto = x.f - proc p3A[T:Int](x: Foo[Bar[Baz[T]]]): auto = x.f - proc p3B[T:Baz[Int]](x: Foo[Bar[T]]): auto = x.f - proc p3C[T:Bar[Baz[Int]]](x: Foo[T]): auto = x.f - proc p3D[T:Foo[Bar[Baz[Int]]]](x: T): auto = x.f - - template test(x: typed) = - let t00 = p00(x) - let t01 = p01(x) - let t02 = p02(x) - let t10 = p10(x) - let t11 = p11(x) - let t12 = p12(x) - #let t13 = p13(x) - let t14 = p14(x) - #let t15 = p15(x) - #let t16 = p16(x) - let t20 = p20(x) - let t21 = p21(x) - let t22 = p22(x) - #let t23 = p23(x) - let t24 = p24(x) - #let t25 = p25(x) - #let t26 = p26(x) - #let t27 = p27(x) - let t28 = p28(x) - #let t29 = p29(x) - #let t2A = p2A(x) - #let t2B = p2B(x) - let t30 = p30(x) - let t31 = p31(x) - let t32 = p32(x) - let t33 = p33(x) - let t34 = p34(x) - let t35 = p35(x) - let t36 = p36(x) - let t37 = p37(x) - let t38 = p38(x) - let t39 = p39(x) - let t3A = p3A(x) - let t3B = p3B(x) - let t3C = p3C(x) - let t3D = p3D(x) - - var a: Foo[Bar[Baz[int]]] - test(a) - var b: FooBar[Baz[int]] - test(b) - var c: FooBarBaz[int] - test(c) - var d: FooBarBazX - test(d) - - -# overloading on tuples with generic alias -block: - type - Foo[F,T] = object - exArgs: T - FooUn[F,T] = Foo[F,tuple[a:T]] - FooBi[F,T1,T2] = Foo[F,tuple[a:T1,b:T2]] - - proc foo1[F,T](x: Foo[F,tuple[a:T]]): int = 1 - proc foo1[F,T1,T2](x: Foo[F,tuple[a:T1,b:T2]]): int = 2 - proc foo2[F,T](x: FooUn[F,T]): int = 1 - proc foo2[F,T1,T2](x: FooBi[F,T1,T2]):int = 2 - - template bar1[F,T](x: Foo[F,tuple[a:T]]): int = 1 - template bar1[F,T1,T2](x: Foo[F,tuple[a:T1,b:T2]]): int = 2 - template bar2[F,T](x: FooUn[F,T]): int = 1 - template bar2[F,T1,T2](x: FooBi[F,T1,T2]): int = 2 - - proc test(x: auto, n: int) = - doAssert(foo1(x) == n) - doAssert(foo2(x) == n) - doAssert(bar1(x) == n) - doAssert(bar2(x) == n) - - var a: Foo[int, tuple[a:int]] - test(a, 1) - var b: FooUn[int, int] - test(b, 1) - var c: Foo[int, tuple[a:int,b:int]] - test(c, 2) - var d: FooBi[int, int, int] - test(d, 2) - - -# inheritance and generics -block: - type - Foo[T] = object of RootObj - x: T - Bar[T] = object of Foo[T] - y: T - Baz[T] = object of Bar[T] - z: T - - template t0(x: Foo[int]): int = 0 - template t0(x: Bar[int]): int = 1 - template t0(x: Foo[bool or int]): int = 10 - template t0(x: Bar[bool or int]): int = 11 - #template t0[T:bool or int](x: Bar[T]): int = 11 - template t0[T](x: Foo[T]): int = 20 - template t0[T](x: Bar[T]): int = 21 - proc p0(x: Foo[int]): int = 0 - proc p0(x: Bar[int]): int = 1 - #proc p0(x: Foo[bool or int]): int = 10 - #proc p0(x: Bar[bool or int]): int = 11 - proc p0[T](x: Foo[T]): int = 20 - proc p0[T](x: Bar[T]): int = 21 - - var a: Foo[int] - var b: Bar[int] - var c: Baz[int] - var d: Foo[bool] - var e: Bar[bool] - var f: Baz[bool] - var g: Foo[float] - var h: Bar[float] - var i: Baz[float] - doAssert(t0(a) == 0) - doAssert(t0(b) == 1) - doAssert(t0(c) == 1) - doAssert(t0(d) == 10) - doAssert(t0(e) == 11) - doAssert(t0(f) == 11) - doAssert(t0(g) == 20) - doAssert(t0(h) == 21) - #doAssert(t0(i) == 21) - doAssert(p0(a) == 0) - doAssert(p0(b) == 1) - doAssert(p0(c) == 1) - #doAssert(p0(d) == 10) - #doAssert(p0(e) == 11) - #doAssert(p0(f) == 11) - doAssert(p0(g) == 20) - doAssert(p0(h) == 21) - doAssert(p0(i) == 21) - - #type - # f0 = proc(x:Foo) - - -block: - type - TilesetCT[n: static[int]] = distinct int - TilesetRT = int - Tileset = TilesetCT | TilesetRT - - func prepareTileset(tileset: var Tileset) = discard - - func prepareTileset(tileset: Tileset): Tileset = - result = tileset - result.prepareTileset - - var parsedTileset: TilesetRT - prepareTileset(parsedTileset) - - -block: - proc p1[T,U: SomeInteger|SomeFloat](x: T, y: U): int|float = - when T is SomeInteger and U is SomeInteger: - result = int(x) + int(y) - else: - result = float(x) + float(y) - doAssert(p1(1,2) == 3) - doAssert(p1(1.0,2) == 3.0) - doAssert(p1(1,2.0) == 3.0) - doAssert(p1(1.0,2.0) == 3.0) - - type Foo[T,U] = U - template F[T,U](t: typedesc[T], x: U): untyped = Foo[T,U](x) - proc p2[T; U,V:Foo[T,SomeNumber]](x: U, y: V): T = - T(x) + T(y) - #proc p2[T; U:Foo[T,SomeNumber], V:Foo[not T,SomeNumber]](x: U, y: V): T = - # T(x) + T(y) - doAssert(p2(F(int,1),F(int,2)) == 3) - doAssert(p2(F(float,1),F(float,2)) == 3.0) - doAssert(p2(F(float,1),F(float,2.0)) == 3.0) - doAssert(p2(F(float,1.0),F(float,2)) == 3.0) - doAssert(p2(F(float,1.0),F(float,2.0)) == 3.0) - #doAssert(p2(F(float,1),F(int,2.0)) == 3.0) diff --git a/tests/overload/tproc_types_dont_like_subtypes.nim b/tests/overload/tproc_types_dont_like_subtypes.nim deleted file mode 100644 index 6774be156..000000000 --- a/tests/overload/tproc_types_dont_like_subtypes.nim +++ /dev/null @@ -1,20 +0,0 @@ -discard """ - errormsg: "got " - line: 20 -""" - -type - A = ref object of RootObj - B = ref object of A - - P = proc (a: A) - -# bug #16325 - -proc doThings(a: A, p: P) = - p(a) - -var x = proc (b: B) {.closure.} = - echo "B" - -doThings(B(), x) diff --git a/tests/overload/tselfderef.nim b/tests/overload/tselfderef.nim new file mode 100644 index 000000000..96f1da42a --- /dev/null +++ b/tests/overload/tselfderef.nim @@ -0,0 +1,20 @@ +discard """ +action: compile +""" + +# bug #4671 +{.experimental.} +{.this: self.} +type + SomeObj = object + f: int + +proc f(num: int) = + discard + +var intptr: ptr int +intptr.f() # compiles fine + +proc doSomething(self: var SomeObj) = + var pint: ptr int + pint.f() # Error: expression '.(pint, "f")' cannot be called diff --git a/tests/overload/tstatic_with_converter.nim b/tests/overload/tstatic_with_converter.nim index e830e8a22..2871744eb 100644 --- a/tests/overload/tstatic_with_converter.nim +++ b/tests/overload/tstatic_with_converter.nim @@ -1,8 +1,6 @@ discard """ output: ''' -9.0 - -''' +9.0''' """ ### bug #6773 @@ -42,8 +40,7 @@ proc `^`(x: vfloat, exp: static[float]): vfloat = pow(x, exp) proc `$`(x: vfloat): string = - let y = cast[ptr float](addr x) - # xxx not sure if intentional in this issue, but this returns "" + let y = cast[ptr float](unsafeAddr x) echo y[] let x = set1(9.0) diff --git a/tests/package/stdlib/stdlib.nimble b/tests/package/stdlib/stdlib.nimble deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/package/stdlib/system.nim b/tests/package/stdlib/system.nim deleted file mode 100644 index 475f8ec5b..000000000 --- a/tests/package/stdlib/system.nim +++ /dev/null @@ -1,2 +0,0 @@ -# this module is part of tstdlib_name_not_special -doAssert true \ No newline at end of file diff --git a/tests/package/tstdlib_name_not_special.nim b/tests/package/tstdlib_name_not_special.nim deleted file mode 100644 index e8226a82d..000000000 --- a/tests/package/tstdlib_name_not_special.nim +++ /dev/null @@ -1,3 +0,0 @@ -# Test whether a another package named 'stdlib' can be imported and used. -# This caused a crash in the past. -import stdlib/system \ No newline at end of file diff --git a/tests/parallel/t10913.nim b/tests/parallel/t10913.nim deleted file mode 100644 index d8459ecd0..000000000 --- a/tests/parallel/t10913.nim +++ /dev/null @@ -1,20 +0,0 @@ -discard """ - matrix: "--threads:on" - errormsg: "'spawn'ed function cannot have a 'typed' or 'untyped' parameter" -""" - -# bug #10913 - -import threadpool - -proc useParallel*[T](unused: T) = - # use a generic T here to show the problem. - {.push experimental: "parallel".} - parallel: - for i in 0..4: - spawn echo "echo in parallel" - sync() - - {.pop.} - -useParallel(1) diff --git a/tests/parallel/t7535.nim b/tests/parallel/t7535.nim deleted file mode 100644 index 052dcdc3a..000000000 --- a/tests/parallel/t7535.nim +++ /dev/null @@ -1,11 +0,0 @@ -discard """ - matrix: "--threads:on" - errormsg: "'spawn' takes a call expression; got: proc (x: uint32) = echo [x]" -""" - -import threadpool - -# bug #7535 -proc print_parallel_nok(r: uint32) = - for x in 0..r: - spawn (proc (x: uint32) = echo x) diff --git a/tests/parallel/t9691.nim b/tests/parallel/t9691.nim deleted file mode 100644 index bbf2b1bc7..000000000 --- a/tests/parallel/t9691.nim +++ /dev/null @@ -1,9 +0,0 @@ -discard """ - matrix: "--threads:on" - errormsg: "'spawn'ed function cannot have a 'typed' or 'untyped' parameter" -""" - -# bug #9691 - -import threadpool -spawn echo() diff --git a/tests/parallel/tarray_of_channels.nim b/tests/parallel/tarray_of_channels.nim index 9479227aa..5139920ea 100644 --- a/tests/parallel/tarray_of_channels.nim +++ b/tests/parallel/tarray_of_channels.nim @@ -8,7 +8,6 @@ test test test ''' -disabled: "openbsd" """ # bug #2257 diff --git a/tests/parallel/tblocking_channel.nim b/tests/parallel/tblocking_channel.nim index eb5fcb715..8b8b49454 100644 --- a/tests/parallel/tblocking_channel.nim +++ b/tests/parallel/tblocking_channel.nim @@ -1,8 +1,6 @@ discard """ output: "" -disabled: "freebsd" """ -# disabled pending bug #15725 import threadpool, os var chan: Channel[int] @@ -27,11 +25,11 @@ proc emitter() = spawn emitter() # At this point emitter should be stuck in `send` -sleep(50) # Sleep a bit to ensure that it is still stuck +sleep(100) # Sleep a bit to ensure that it is still stuck doAssert(not msgSent) spawn receiver() -sleep(50) # Sleep a bit to let receicer consume the messages +sleep(100) # Sleep a bit to let receicer consume the messages doAssert(msgSent) # Sender should be unblocked doAssert(chan.trySend(4)) diff --git a/tests/parallel/tconvexhull.nim b/tests/parallel/tconvexhull.nim index a89aa910b..184a131a2 100644 --- a/tests/parallel/tconvexhull.nim +++ b/tests/parallel/tconvexhull.nim @@ -1,7 +1,8 @@ discard """ - matrix: "--mm:refc" output: ''' ''' + +ccodeCheck: "\\i ! @'deepCopy(' .*" """ # parallel convex hull for Nim bigbreak @@ -50,11 +51,12 @@ proc convex_hull[T](points: var seq[T], cmp: proc(x, y: T): int {.closure.}) : s ul[k] = spawn half[T](points, k == 0) result = concat(^ul[0], ^ul[1]) -var s = map(toSeq(0..9999), proc(x: int): Point = (float(x div 100), float(x mod 100))) +var s = map(toSeq(0..99999), proc(x: int): Point = (float(x div 1000), float(x mod 1000))) # On some runs, this pool size reduction will set the "shutdown" attribute on the # worker thread that executes our spawned task, before we can read the flowvars. setMaxPoolSize 2 -for i in 0..2: +#echo convex_hull[Point](s, cmpPoint) +for i in 0..5: doAssert convex_hull[Point](s, cmpPoint) == - @[(0.0, 0.0), (99.0, 0.0), (99.0, 99.0), (0.0, 99.0)] + @[(0.0, 0.0), (99.0, 0.0), (99.0, 999.0), (0.0, 999.0)] diff --git a/tests/parallel/tdeepcopy.nim b/tests/parallel/tdeepcopy.nim index 96ca15ca3..84e2edf3f 100644 --- a/tests/parallel/tdeepcopy.nim +++ b/tests/parallel/tdeepcopy.nim @@ -1,55 +1,18 @@ discard """ - matrix: "--mm:refc" - output: ''' -13 abc -called deepCopy for int -called deepCopy for int -done999 999 -''' + output: '''13 abc''' """ -import threadpool - -block one: - type - PBinaryTree = ref object - le, ri: PBinaryTree - value: int - - proc main = - var x: PBinaryTree - deepCopy(x, PBinaryTree(ri: PBinaryTree(le: PBinaryTree(value: 13)))) - var y: string - deepCopy y, "abc" - echo x.ri.le.value, " ", y - - main() +type + PBinaryTree = ref object + le, ri: PBinaryTree + value: int -block two: - type - Bar[T] = object - x: T +proc main = + var x: PBinaryTree + deepCopy(x, PBinaryTree(ri: PBinaryTree(le: PBinaryTree(value: 13)))) + var y: string + deepCopy y, "abc" + echo x.ri.le.value, " ", y - proc `=deepCopy`[T](b: ref Bar[T]): ref Bar[T] = - result.new - result.x = b.x - when T is int: - echo "called deepCopy for int" - else: - echo "called deepCopy for something else" - - proc foo(b: ref Bar[int]): int = 999 - -# test that the disjoint checker deals with 'a = spawn f(); g = spawn f()': - - proc main = - var dummy: ref Bar[int] - new(dummy) - dummy.x = 44 - #parallel: - let f = spawn foo(dummy) - let b = spawn foo(dummy) - echo "done", ^f, " ", ^b - - main() +main() diff --git a/tests/parallel/tdeepcopy2.nim b/tests/parallel/tdeepcopy2.nim index e8305173d..2ad623ed1 100644 --- a/tests/parallel/tdeepcopy2.nim +++ b/tests/parallel/tdeepcopy2.nim @@ -1,10 +1,7 @@ discard """ - matrix: "--mm:refc" - output: ''' + output: '''called deepCopy for int called deepCopy for int -called deepCopy for int -done999 999 -''' +done999 999''' """ import threadpool diff --git a/tests/parallel/tdisjoint_slice1.nim b/tests/parallel/tdisjoint_slice1.nim index 6892e7383..c1d0e52f8 100644 --- a/tests/parallel/tdisjoint_slice1.nim +++ b/tests/parallel/tdisjoint_slice1.nim @@ -1,51 +1,21 @@ discard """ - matrix: "--mm:refc" outputsub: "EVEN 28" """ -import threadpool, locks +import threadpool -block one: - proc odd(a: int) = echo "ODD ", a - proc even(a: int) = echo "EVEN ", a +proc odd(a: int) = echo "ODD ", a +proc even(a: int) = echo "EVEN ", a - proc main() = - var a: array[0..30, int] - for i in low(a)..high(a): a[i] = i - parallel: - var i = 0 - while i <= 29: - spawn even(a[i]) - spawn odd(a[i+1]) - inc i, 2 - # is correct here +proc main() = + var a: array[0..30, int] + for i in low(a)..high(a): a[i] = i + parallel: + var i = 0 + while i <= 29: + spawn even(a[i]) + spawn odd(a[i+1]) + inc i, 2 + # is correct here - main() - - -block two: - var echoLock: Lock - initLock echoLock - - proc f(a: openArray[int]) = - for x in a: - withLock echoLock: - echo x - - proc f(a: int) = - withLock echoLock: - echo a - - proc main() = - var a: array[0..9, int] = [0,1,2,3,4,5,6,7,8,9] - parallel: - spawn f(a[0..2]) - #spawn f(a[16..30]) - var i = 3 - while i <= 8: - spawn f(a[i]) - spawn f(a[i+1]) - inc i, 2 - # is correct here - - main() +main() diff --git a/tests/parallel/tdisjoint_slice2.nim b/tests/parallel/tdisjoint_slice2.nim new file mode 100644 index 000000000..25cb2362f --- /dev/null +++ b/tests/parallel/tdisjoint_slice2.nim @@ -0,0 +1,40 @@ +discard """ + output: '''0 +1 +2 +3 +4 +5 +6 +7 +8''' + sortoutput: true +""" + +import threadpool, locks + +var echoLock: Lock +initLock echoLock + +proc f(a: openArray[int]) = + for x in a: + withLock echoLock: + echo x + +proc f(a: int) = + withLock echoLock: + echo a + +proc main() = + var a: array[0..9, int] = [0,1,2,3,4,5,6,7,8,9] + parallel: + spawn f(a[0..2]) + #spawn f(a[16..30]) + var i = 3 + while i <= 8: + spawn f(a[i]) + spawn f(a[i+1]) + inc i, 2 + # is correct here + +main() diff --git a/tests/parallel/tflowvar.nim b/tests/parallel/tflowvar.nim index e44b29a87..fd3aa326e 100644 --- a/tests/parallel/tflowvar.nim +++ b/tests/parallel/tflowvar.nim @@ -1,11 +1,9 @@ discard """ - matrix: "--mm:refc" output: '''foobarfoobar bazbearbazbear 1''' cmd: "nim $target --threads:on $options $file" - disabled: "openbsd" """ import threadpool diff --git a/tests/parallel/tgc_unsafe2.nim b/tests/parallel/tgc_unsafe2.nim index 7d98dafcb..40af728fb 100644 --- a/tests/parallel/tgc_unsafe2.nim +++ b/tests/parallel/tgc_unsafe2.nim @@ -1,8 +1,9 @@ discard """ errormsg: "'consumer' is not GC-safe as it calls 'track'" - nimout: '''tgc_unsafe2.nim(21, 6) Warning: 'trick' is not GC-safe as it accesses 'global' which is a global using GC'ed memory [GcUnsafe2] -tgc_unsafe2.nim(25, 6) Warning: 'track' is not GC-safe as it calls 'trick' [GcUnsafe2] -tgc_unsafe2.nim(27, 6) Error: 'consumer' is not GC-safe as it calls 'track' + line: 28 + nimout: '''tgc_unsafe2.nim(22, 6) Warning: 'trick' is not GC-safe as it accesses 'global' which is a global using GC'ed memory [GcUnsafe2] +tgc_unsafe2.nim(26, 6) Warning: 'track' is not GC-safe as it calls 'trick' [GcUnsafe2] +tgc_unsafe2.nim(28, 6) Error: 'consumer' is not GC-safe as it calls 'track' ''' """ diff --git a/tests/parallel/tguard1.nim b/tests/parallel/tguard1.nim index f4c92319b..b1eb7e7c5 100644 --- a/tests/parallel/tguard1.nim +++ b/tests/parallel/tguard1.nim @@ -5,7 +5,7 @@ output: "90" when false: template lock(a, b: ptr Lock; body: stmt) = - if cast[int](a) < cast[int](b): + if cast[ByteAddress](a) < cast[ByteAddress](b): pthread_mutex_lock(a) pthread_mutex_lock(b) else: diff --git a/tests/parallel/tinvalid_array_bounds.nim b/tests/parallel/tinvalid_array_bounds.nim index 8dc93c33f..4c6065fd6 100644 --- a/tests/parallel/tinvalid_array_bounds.nim +++ b/tests/parallel/tinvalid_array_bounds.nim @@ -1,6 +1,5 @@ discard """ - matrix: "--mm:refc" - errormsg: "cannot prove (i)..(i) disjoint from (i + 1)..(i + 1)" + errormsg: "can prove: i + 1 > 30" line: 21 """ diff --git a/tests/parallel/tlet_spawn.nim b/tests/parallel/tlet_spawn.nim index 853ffc443..62341d8f0 100644 --- a/tests/parallel/tlet_spawn.nim +++ b/tests/parallel/tlet_spawn.nim @@ -4,7 +4,7 @@ done999 999 ''' """ -import std/[threadpool, os] +import threadpool proc foo(): int = 999 @@ -17,12 +17,3 @@ proc main = echo "done", f, " ", b main() - -# bug #13781 -proc thread(): string = - os.sleep(1000) - return "ok" - -var fv = spawn thread() -sync() -doAssert ^fv == "ok" diff --git a/tests/parallel/tmissing_deepcopy.nim b/tests/parallel/tmissing_deepcopy.nim index ea77936ad..94e027b60 100644 --- a/tests/parallel/tmissing_deepcopy.nim +++ b/tests/parallel/tmissing_deepcopy.nim @@ -1,5 +1,4 @@ discard """ - matrix: "--mm:refc" ccodeCheck: "@'genericDeepCopy(' .*" action: compile """ @@ -27,10 +26,10 @@ proc greet(p:Person) = " friend:", p.friend.name, "(", cast[int](addr p.friend.name),") }" proc setup = - for i in 0 ..< 10: + for i in 0 ..< 20: people.add newPerson("Person" & $(i + 1)) - for i in 0 ..< 10: - people[i].friend = people[9-i] + for i in 0 ..< 20: + people[i].friend = people[19-i] proc update = parallel: diff --git a/tests/parallel/tnon_disjoint_slice1.nim b/tests/parallel/tnon_disjoint_slice1.nim index 51762187d..72d008bbd 100644 --- a/tests/parallel/tnon_disjoint_slice1.nim +++ b/tests/parallel/tnon_disjoint_slice1.nim @@ -1,7 +1,6 @@ discard """ - matrix: "--mm:refc" errormsg: "cannot prove (i)..(i) disjoint from (i + 1)..(i + 1)" - line: 21 + line: 20 """ import threadpool diff --git a/tests/parallel/tparfind.nim b/tests/parallel/tparfind.nim index cf1bc9336..4b3610c67 100644 --- a/tests/parallel/tparfind.nim +++ b/tests/parallel/tparfind.nim @@ -1,5 +1,4 @@ discard """ - matrix: "--mm:refc" output: "500" """ diff --git a/tests/parallel/tpi.nim b/tests/parallel/tpi.nim index cd965d585..1abed6f23 100644 --- a/tests/parallel/tpi.nim +++ b/tests/parallel/tpi.nim @@ -1,5 +1,4 @@ discard """ - matrix: "--mm:refc" output: '''3.141792613595791 3.141792613595791''' """ diff --git a/tests/parallel/tsendtwice.nim b/tests/parallel/tsendtwice.nim index 6bf5e5ebb..0b3ce15a5 100644 --- a/tests/parallel/tsendtwice.nim +++ b/tests/parallel/tsendtwice.nim @@ -7,7 +7,7 @@ ob2 @[] ob @[] ob3 @[] ''' - matrix: "--mm:refc" + cmd: "nim c -r --threads:on $file" """ # bug #4776 @@ -17,9 +17,9 @@ import tables type Base* = ref object of RootObj someSeq: seq[int] - baseData: array[40000, byte] + baseData: array[400000, byte] Derived* = ref object of Base - data: array[40000, byte] + data: array[400000, byte] type ThreadPool = ref object diff --git a/tests/parallel/tsimple_array_checks.nim b/tests/parallel/tsimple_array_checks.nim index ab292f935..650b809e0 100644 --- a/tests/parallel/tsimple_array_checks.nim +++ b/tests/parallel/tsimple_array_checks.nim @@ -61,15 +61,3 @@ maino() # Doesn't work outside a proc when true: main() - -block two: - proc f(a: openArray[int]) = - discard - - proc main() = - var a: array[0..9, int] = [0,1,2,3,4,5,6,7,8,9] - parallel: - spawn f(a[0..2]) - - - main() \ No newline at end of file diff --git a/tests/parallel/tsysspawn.nim b/tests/parallel/tsysspawn.nim index b7ecd1264..7244a5ee6 100644 --- a/tests/parallel/tsysspawn.nim +++ b/tests/parallel/tsysspawn.nim @@ -1,11 +1,7 @@ discard """ output: '''4 -8 -(a: 1) -2 -2 -''' - matrix: "--mm:refc" +8''' + cmd: "nim $target --threads:on $options $file" """ import threadpool @@ -33,32 +29,3 @@ sync() echo x echo y - - -#-------------------------------------------------------- -# issue #14014 - -import threadpool - -type A = object - a: int - -proc f(t: typedesc): t = - t(a:1) - -let r = spawn f(A) -echo ^r - -proc f2(x: static[int]): int = - x - -let r2 = spawn f2(2) -echo ^r2 - -type statint = static[int] - -proc f3(x: statint): int = - x - -let r3 = spawn f3(2) -echo ^r3 diff --git a/tests/parallel/tuseafterdef.nim b/tests/parallel/tuseafterdef.nim index e73f1b794..833c72a0a 100644 --- a/tests/parallel/tuseafterdef.nim +++ b/tests/parallel/tuseafterdef.nim @@ -1,8 +1,6 @@ discard """ - matrix: "--mm:refc" errormsg: "(k)..(k) not disjoint from (k)..(k)" - line: 24 - action: compile + line: 23 """ # bug #1597 diff --git a/tests/parallel/twaitany.nim b/tests/parallel/twaitany.nim index d57c5f40f..2be3d432f 100644 --- a/tests/parallel/twaitany.nim +++ b/tests/parallel/twaitany.nim @@ -1,10 +1,9 @@ discard """ - matrix: "--mm:refc" output: '''true''' """ # bug #7638 -import threadpool, os +import threadpool, os, strformat proc timer(d: int): int = #echo fmt"sleeping {d}" @@ -12,7 +11,7 @@ proc timer(d: int): int = #echo fmt"done {d}" return d -var durations = [1000, 1500, 2000] +var durations = [1000, 1500, 2000, 2500, 3000] var tasks: seq[FlowVarBase] = @[] var results: seq[int] = @[] @@ -26,9 +25,11 @@ while index != -1: #echo repr results index = blockUntilAny(tasks) -doAssert results.len == 3 +doAssert results.len == 5 doAssert 1000 in results doAssert 1500 in results doAssert 2000 in results +doAssert 2500 in results +doAssert 3000 in results sync() echo "true" diff --git a/tests/parser/t12274.nim b/tests/parser/t12274.nim deleted file mode 100644 index 6b7c9f55a..000000000 --- a/tests/parser/t12274.nim +++ /dev/null @@ -1,13 +0,0 @@ -discard """ - joinable: false -""" - -var s: seq[int] -s.add block: - let i = 1 - i -s.add try: - 2 -except: - 3 -doAssert s == @[1, 2] diff --git a/tests/parser/t15667.nim b/tests/parser/t15667.nim deleted file mode 100644 index fcb862825..000000000 --- a/tests/parser/t15667.nim +++ /dev/null @@ -1,61 +0,0 @@ -discard """ - cmd: "nim check $options $file" - action: "reject" - nimout: ''' -t15667.nim(23, 5) Error: invalid indentation, maybe you forgot a '=' at t15667.nim(22, 13) ? -t15667.nim(28, 5) Error: invalid indentation, maybe you forgot a '=' at t15667.nim(26, 13) ? -t15667.nim(33, 5) Error: invalid indentation, maybe you forgot a '=' at t15667.nim(31, 25) ? -t15667.nim(42, 5) Error: invalid indentation, maybe you forgot a '=' at t15667.nim(38, 12) ? -t15667.nim(56, 5) Error: invalid indentation, maybe you forgot a '=' at t15667.nim(55, 13) ? -t15667.nim(61, 48) Error: expression expected, but found ',' -''' -""" - - - - - - - -# line 20 -block: - proc fn1() - discard - -block: - proc fn2() - # - discard - -block: - proc fn3() {.exportc.} - # - discard - -block: # complex example - proc asdfasdfsd() {. exportc, - inline - .} # foo - #[ - bar - ]# - discard - -block: # xxx this doesn't work yet (only a bare `invalid indentation` error) - proc fn5() - ## - discard - -block: # ditto - proc fn6*() - ## foo bar - runnableExamples: discard - -block: - proc fn8() - runnableExamples: - discard - discard - -# semiStmtList loop issue -proc bar(k:static bool):SomeNumber = (when k: 3, else: 3.0) diff --git a/tests/parser/t19662.nim b/tests/parser/t19662.nim deleted file mode 100644 index 7a1864ac6..000000000 --- a/tests/parser/t19662.nim +++ /dev/null @@ -1,6 +0,0 @@ - var i: int # bug #19662 -echo i - -discard """ - errormsg: "invalid indentation" -""" \ No newline at end of file diff --git a/tests/parser/t20922.nim b/tests/parser/t20922.nim deleted file mode 100644 index 110610fb1..000000000 --- a/tests/parser/t20922.nim +++ /dev/null @@ -1,35 +0,0 @@ -discard """ - cmd: "nim check $options --verbosity:0 --hints:off $file" - action: "reject" - nimout: ''' -t20922.nim(26, 5) Error: expression expected, but found ':' -t20922.nim(34, 7) Error: expression expected, but found ':' -t20922.nim(35, 5) Error: ':' or '=' expected, but got 'keyword of' -Error: in expression ' '+'': identifier expected, but found '' -t20922.nim(26, 7) Error: attempting to call undeclared routine: '' -Error: in expression ' '+'': identifier expected, but found '' -t20922.nim(26, 7) Error: attempting to call undeclared routine: '' -t20922.nim(26, 7) Error: expression '' cannot be called -t20922.nim(26, 7) Error: expression '' has no type (or is ambiguous) -t20922.nim(26, 7) Error: VM problem: dest register is not set -''' -""" -# original test case issue #20922 -type Token = enum - incDataPtr, - incDataPtrByte - -proc mapInstrToToken(instr: char): Token = - case instr: - of '>': - incDataPtr - of: '+': - incDataPtrByte - -# same issue with `of` in object branches (different parser procs calling `exprList`) -type - Bar = enum A, B - Foo = object - case kind: Bar - of: x: int - of B: y: float diff --git a/tests/parser/tcommand_as_expr.nim b/tests/parser/tcommand_as_expr.nim index f37c34f63..b25ec4bd8 100644 --- a/tests/parser/tcommand_as_expr.nim +++ b/tests/parser/tcommand_as_expr.nim @@ -36,12 +36,3 @@ echo f -4 echo int -1 # doesn't compile echo int `-` 1 # compiles - -var num = 1 -num += int 2 -doAssert num == 3 - -import options -var opt = some some none int -opt = some some none int -opt = some none Option[int] diff --git a/tests/parser/tcommandequals.nim b/tests/parser/tcommandequals.nim deleted file mode 100644 index f41b318ac..000000000 --- a/tests/parser/tcommandequals.nim +++ /dev/null @@ -1,17 +0,0 @@ -discard """ - output: ''' -5 -''' -""" - -proc foo(a, b: int) = - echo a + b - -foo a = 2, b = 3 - -import macros - -macro bar(args: varargs[untyped]): untyped = - doAssert args[0].kind == nnkExprEqExpr - -bar "a" = 1 diff --git a/tests/parser/tcommandindent.nim b/tests/parser/tcommandindent.nim deleted file mode 100644 index 449c218db..000000000 --- a/tests/parser/tcommandindent.nim +++ /dev/null @@ -1,16 +0,0 @@ -when false: # parse the following - let foo = Obj( - field1: proc (src: pointer, srcLen: Natural) - {.nimcall, gcsafe, raises: [IOError, Defect].} = - var file = FileOutputStream(s).file - - implementWrites s.buffers, src, srcLen, "FILE", - writeStartAddr, writeLen, - file.writeBuffer(writeStartAddr, writeLen) - , - field2: proc {.nimcall, gcsafe, raises: [IOError, Defect].} = - flushFile FileOutputStream(s).file - , - field3: proc () {.nimcall, gcsafe, raises: [IOError, Defect].} = - close FileOutputStream(s).file - ) diff --git a/tests/parser/tdo.nim b/tests/parser/tdo.nim index 382d03398..7bd1f7411 100644 --- a/tests/parser/tdo.nim +++ b/tests/parser/tdo.nim @@ -1,12 +1,8 @@ discard """ - output: ''' + output: '''true true true -true -true inner B -running with pragma -ran with pragma -''' +true inner B''' """ template withValue(a, b, c, d, e: untyped) = @@ -81,14 +77,3 @@ proc main2 = echo "true inner B" main2() - -proc withPragma(foo: int, bar: proc() {.raises: [].}) = - echo "running with pragma" - bar() - -withPragma(3) do {.raises: [].}: - echo "ran with pragma" - -doAssert not (compiles do: - withPragma(3) do {.raises: [].}: - raise newException(Exception)) diff --git a/tests/parser/tdoc_comments.nim b/tests/parser/tdoc_comments.nim index 3c86e69ea..fa1374b45 100644 --- a/tests/parser/tdoc_comments.nim +++ b/tests/parser/tdoc_comments.nim @@ -69,7 +69,3 @@ type MyEnum3* = enum value5 ## only document the enum value - -# bug #18847 -proc close*() = ## asdfasdfsdfa - discard ## adsfasdfads diff --git a/tests/parser/tdoublenotnil.nim b/tests/parser/tdoublenotnil.nim deleted file mode 100644 index c61008c54..000000000 --- a/tests/parser/tdoublenotnil.nim +++ /dev/null @@ -1,3 +0,0 @@ -when false: - type Foo = Bar not nil not nil #[tt.Error - ^ invalid indentation]# diff --git a/tests/parser/tifexprs.nim b/tests/parser/tifexprs.nim deleted file mode 100644 index 3a7e2bddc..000000000 --- a/tests/parser/tifexprs.nim +++ /dev/null @@ -1,12 +0,0 @@ -discard """ - output: ''' -1 -''' -""" - -var a, b: int -let x = if a > b: - 0 - else: 1 - -echo x diff --git a/tests/parser/tinvifstmt.nim b/tests/parser/tinvifstmt.nim deleted file mode 100644 index 0455bce60..000000000 --- a/tests/parser/tinvifstmt.nim +++ /dev/null @@ -1,12 +0,0 @@ -discard """ - errormsg: "invalid indentation" - line: 9 - column: 3 -""" - -if true: - echo "a" - elif: - echo "b" - else: - echo "c" diff --git a/tests/parser/tpostexprblocks.nim b/tests/parser/tpostexprblocks.nim index 6cd4a8350..c27bbf321 100644 --- a/tests/parser/tpostexprblocks.nim +++ b/tests/parser/tpostexprblocks.nim @@ -406,105 +406,6 @@ StmtList DiscardStmt Empty IntLit 0 - Command - Ident "foo390" - Call - Ident "x" - Do - Empty - Empty - Empty - FormalParams - Empty - IdentDefs - Ident "y" - Empty - Empty - Empty - Empty - StmtList - DiscardStmt - Empty - Do - Empty - Empty - Empty - FormalParams - Ident "int" - IdentDefs - Ident "z" - Empty - Empty - Empty - Empty - StmtList - DiscardStmt - Empty - Do - Empty - Empty - Empty - FormalParams - Ident "int" - IdentDefs - Ident "w" - Ident "int" - Empty - Empty - Empty - StmtList - DiscardStmt - Empty - StmtList - DiscardStmt - Empty - OfBranch - Ident "a" - StmtList - DiscardStmt - Empty - OfBranch - TupleConstr - Ident "a" - Ident "b" - StmtList - DiscardStmt - Empty - ElifBranch - Ident "a" - StmtList - DiscardStmt - Empty - ElifBranch - TupleConstr - Ident "a" - Ident "b" - StmtList - DiscardStmt - Empty - ExceptBranch - Ident "a" - StmtList - DiscardStmt - Empty - ExceptBranch - TupleConstr - Ident "a" - Ident "b" - StmtList - DiscardStmt - Empty - Finally - StmtList - DiscardStmt - Empty - - Call - Ident "foo" - Finally - StmtList - DiscardStmt - Empty ''' """ @@ -639,30 +540,3 @@ dumpTree: foo380.add((quote do: discard )[0]) - - foo390 x do (y): - discard - do (z) -> int: - discard - do (w: int) -> int: - discard - do: - discard - of a: - discard - of (a, b): - discard - elif a: - discard - elif (a, b): - discard - except a: - discard - except (a, b): - discard - finally: - discard - - foo: - finally: - discard diff --git a/tests/parser/tprecedence.nim b/tests/parser/tprecedence.nim index 9be79543b..66a2922db 100644 --- a/tests/parser/tprecedence.nim +++ b/tests/parser/tprecedence.nim @@ -54,10 +54,3 @@ let const test = proc(): int = 1 - -# bug #8759 -block: - template `=>`(a, b): untyped = (a, b) - template `+=`(a, b): untyped = a * b - - doAssert ("abc" => 3 += 5) == ("abc", 15) diff --git a/tests/parser/tprocexprasstmt.nim b/tests/parser/tprocexprasstmt.nim deleted file mode 100644 index a02dde6f6..000000000 --- a/tests/parser/tprocexprasstmt.nim +++ /dev/null @@ -1,3 +0,0 @@ -func r(): auto = - func(): int = 2 -discard r()() diff --git a/tests/parser/tstatementoperators.nim b/tests/parser/tstatementoperators.nim deleted file mode 100644 index d2b85bb4b..000000000 --- a/tests/parser/tstatementoperators.nim +++ /dev/null @@ -1,12 +0,0 @@ -discard """ - nimout: ''' -Infix - Ident "from" - Ident "a" - Ident "b" -''' -""" - -from macros import dumpTree - -dumpTree(a from b) \ No newline at end of file diff --git a/tests/parser/tstmtlists.nim b/tests/parser/tstmtlists.nim deleted file mode 100644 index 158c93340..000000000 --- a/tests/parser/tstmtlists.nim +++ /dev/null @@ -1,180 +0,0 @@ -discard """ - output: ''' -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -hello -1 -hello -2 -hello -3 -hello -4 -hello -5 -hello -6 -hello -7 -hello -8 -hello -9 -hello -10 -hello -1 -hello -2 -hello -3 -hello -4 -hello -5 -hello -6 -hello -7 -hello -8 -hello -9 -hello -10 -lucky -lucky -''' -""" - -block: ( - discard; - echo 1 + 1; - ) - -block: ( - discard; #Haha - #haha - echo 1 + 1; -) - -block: ( - discard; - #Hmm - echo 1 + - 1; -) - -block: ( - discard - echo "2" -) - -block: ( - discard; - echo 1 + - 1 -) - -block: ( - discard - echo 1 + - 1 -) - -block: ( - discard; - discard -) - -block: ( - discard - echo 1 + 1; - ) - -block: ( - discard - echo 1 + 1; -) - -block: ( - discard - echo 1 + - 1; -) - -block: ( - discard; - ) - -block: ( discard; echo 1 + #heh - 1; -) - -for i in 1..10: - echo "hello" - echo i - -for i in 1..10: ( - echo "hello"; - echo i; -) - -proc square(inSeq: seq[float]): seq[float] = ( - result = newSeq[float](len(inSeq)); - for i, v in inSeq: ( - result[i] = v * v; - ) -) - -proc square2(inSeq: seq[float]): seq[float] = - result = newSeq[float](len(inSeq)); - for i, v in inSeq: ( - result[i] = v * v; - ) - -proc cstringCheck(tracked: int; n: int) = - if true == false and (let a = high(int); let b = high(int); - a.int8 == 8 and a.int8 notin {3..9}): - echo(tracked, n) - -template dim: int = - (if int.high == 0: - int.high - else: - int.high) - -template dim2: int = - (if int.high == 0: - int.high - else: - int.high) - -template dim3: int = - ( - if int.high == 0: - int.high - else: - int.high) - -# lenient indentation: - -echo (if 0 == 1: - "0 == 1" -else: - "lucky") - -# bug #16426 -echo (when 0 == 1: - "0 == 1" -else: - "lucky") - diff --git a/tests/parser/ttry.nim b/tests/parser/ttry.nim deleted file mode 100644 index 190b0b8dc..000000000 --- a/tests/parser/ttry.nim +++ /dev/null @@ -1,27 +0,0 @@ -# bug #21144 -block: - try: - let c = try: - 10 - except ValueError as exc: - 10 - except ValueError as exc: - discard - -if true: - block: - let c = try: - 10 - except ValueError as exc: - 10 - except OSError: - 99 - - -try: - let c = try: - 10 - except ValueError as exc: - 10 -except ValueError as exc: - discard \ No newline at end of file diff --git a/tests/parser/ttypeclasses.nim b/tests/parser/ttypeclasses.nim index e6e7a48b8..06146dcb6 100644 --- a/tests/parser/ttypeclasses.nim +++ b/tests/parser/ttypeclasses.nim @@ -16,31 +16,31 @@ var z: ptr int const C = @[1, 2, 3] static: - doAssert x is ref - doAssert y is distinct - doAssert z is ptr - doAssert C is static - doAssert C[1] is static[int] - doAssert C[0] is static[SomeInteger] - doAssert C isnot static[string] - doAssert C is SEQ|OBJ - doAssert C isnot OBJ|TPL - doAssert int is int - doAssert int is T - doAssert int is SomeInteger - doAssert seq[int] is type - doAssert seq[int] is type[seq] - doAssert seq[int] isnot type[seq[float]] - doAssert i isnot type[int] - doAssert type(i) is type[int] - doAssert x isnot T - doAssert y isnot S - doAssert z isnot enum - doAssert x isnot object - doAssert y isnot tuple - doAssert z isnot seq + assert x is ref + assert y is distinct + assert z is ptr + assert C is static + assert C[1] is static[int] + assert C[0] is static[SomeInteger] + assert C isnot static[string] + assert C is SEQ|OBJ + assert C isnot OBJ|TPL + assert int is int + assert int is T + assert int is SomeInteger + assert seq[int] is type + assert seq[int] is type[seq] + assert seq[int] isnot type[seq[float]] + assert i isnot type[int] + assert type(i) is type[int] + assert x isnot T + assert y isnot S + assert z isnot enum + assert x isnot object + assert y isnot tuple + assert z isnot seq # XXX: These cases don't work properly at the moment: - # doAssert type[int] isnot int - # doAssert type(int) isnot int + # assert type[int] isnot int + # assert type(int) isnot int diff --git a/tests/parser/ttypecommandcomma.nim b/tests/parser/ttypecommandcomma.nim deleted file mode 100644 index 7ca59a799..000000000 --- a/tests/parser/ttypecommandcomma.nim +++ /dev/null @@ -1,9 +0,0 @@ -discard """ - errormsg: "invalid indentation" - line: 8 - column: 19 -""" - -type - Foo = call(1, 2), 3: - 4 \ No newline at end of file diff --git a/tests/parser/ttypecommandindent1.nim b/tests/parser/ttypecommandindent1.nim deleted file mode 100644 index 9aa274e2a..000000000 --- a/tests/parser/ttypecommandindent1.nim +++ /dev/null @@ -1,9 +0,0 @@ -discard """ - errormsg: "invalid indentation" - line: 9 - column: 3 -""" - -type - Foo = call x, y, z: - abc diff --git a/tests/parser/ttypecommandindent2.nim b/tests/parser/ttypecommandindent2.nim deleted file mode 100644 index 0883df90f..000000000 --- a/tests/parser/ttypecommandindent2.nim +++ /dev/null @@ -1,11 +0,0 @@ -discard """ - errormsg: "invalid indentation" - line: 10 - column: 5 -""" - -type - Foo = call x, y, z: - abc - do: - def diff --git a/tests/parser/ttypecommandindent3.nim b/tests/parser/ttypecommandindent3.nim deleted file mode 100644 index f9fdcc1e4..000000000 --- a/tests/parser/ttypecommandindent3.nim +++ /dev/null @@ -1,11 +0,0 @@ -discard """ - errormsg: "expression expected, but found 'keyword do'" - line: 10 - column: 1 -""" - -type - Foo = call x, y, z: - abc -do: - def diff --git a/tests/parser/ttypeexprobject.nim b/tests/parser/ttypeexprobject.nim deleted file mode 100644 index 6895f1731..000000000 --- a/tests/parser/ttypeexprobject.nim +++ /dev/null @@ -1,10 +0,0 @@ -discard """ - errormsg: "invalid indentation" - line: 10 - column: 14 -""" - -type - A = (object | tuple | int) - B = int | object | tuple - C = object | tuple | int # issue #8846 diff --git a/tests/parser/ttypeexprs.nim b/tests/parser/ttypeexprs.nim deleted file mode 100644 index e40efc7d9..000000000 --- a/tests/parser/ttypeexprs.nim +++ /dev/null @@ -1,25 +0,0 @@ -proc foo[T: ptr int | ptr string](x: T) = discard -var x = "abc" -foo(addr x) - -let n = 3'u32 -type Double = ( - when n.sizeof == 4: uint64 - elif n.sizeof == 2: uint32 - else: uint16 -) - -type - A = (ref | ptr | pointer) - B = pointer | ptr | ref - C = ref | ptr | pointer - -template `+`(a, b): untyped = (b, a) -template `*`(a, b): untyped = (a, b) - -doAssert (ref int + ref float * ref string + ref bool) is - (ref bool, ((ref float, ref string), ref int)) -type X = ref int + ref float * ref string + ref bool -doAssert X is (ref bool, ((ref float, ref string), ref int)) - -type SomePointer = proc | ref | ptr | pointer diff --git a/tests/parser/ttypemodifiers.nim b/tests/parser/ttypemodifiers.nim index 9a1ccb1a5..2c322b44b 100644 --- a/tests/parser/ttypemodifiers.nim +++ b/tests/parser/ttypemodifiers.nim @@ -21,7 +21,7 @@ StmtList Ident "PtrTuple" Empty PtrTy - TupleConstr + Par Ident "int" Ident "string" TypeDef @@ -43,14 +43,14 @@ StmtList Ident "RefTupleType" Empty RefTy - TupleConstr + Par Ident "int" Ident "string" TypeDef Ident "RefTupleVars" Empty RefTy - TupleConstr + Par Ident "a" Ident "b" TypeDef @@ -80,7 +80,7 @@ StmtList Empty Command Ident "static" - TupleConstr + Par Ident "int" Ident "string" TypeDef @@ -155,7 +155,7 @@ StmtList Empty Command Ident "type" - TupleConstr + Par Ident "a" Ident "b" TypeDef @@ -163,7 +163,7 @@ StmtList Empty Command Ident "type" - TupleConstr + Par Ident "int" Ident "string" TypeDef @@ -287,7 +287,7 @@ StmtList IdentDefs Ident "refTuple2" RefTy - TupleConstr + Par Ident "int" Ident "string" Empty @@ -524,3 +524,4 @@ dumpTree: static: staticStmtList1 staticStmtList2 + diff --git a/tests/parser/ttypesectioncalls.nim b/tests/parser/ttypesectioncalls.nim deleted file mode 100644 index 003444fc5..000000000 --- a/tests/parser/ttypesectioncalls.nim +++ /dev/null @@ -1,328 +0,0 @@ -discard """ -nimout: ''' -StmtList - TypeSection - TypeDef - Ident "A" - Empty - Call - Ident "call" - IntLit 1 - TypeSection - TypeDef - Ident "B" - Empty - Command - Ident "call" - IntLit 2 - TypeDef - Ident "C" - Empty - Call - Ident "call" - StmtList - IntLit 3 - TypeDef - Ident "D" - Empty - Call - Ident "call" - StmtList - IntLit 4 - TypeSection - TypeDef - Ident "E" - Empty - Call - Ident "call" - IntLit 5 - IntLit 6 - TypeDef - Ident "F" - Empty - Command - Ident "call" - IntLit 7 - IntLit 8 - TypeDef - Ident "G" - Empty - Call - Ident "call" - IntLit 9 - StmtList - IntLit 10 - TypeDef - Ident "H" - Empty - Call - Ident "call" - IntLit 11 - StmtList - IntLit 12 - TypeDef - Ident "I" - Empty - Command - Ident "call" - IntLit 13 - StmtList - IntLit 14 - TypeDef - Ident "J" - Empty - Command - Ident "call" - IntLit 15 - StmtList - IntLit 16 - TypeSection - TypeDef - Ident "K" - Empty - Call - Ident "call" - IntLit 17 - IntLit 18 - IntLit 19 - TypeDef - Ident "L" - Empty - Command - Ident "call" - IntLit 20 - IntLit 21 - IntLit 22 - TypeDef - Ident "M" - Empty - Call - Ident "call" - IntLit 23 - IntLit 24 - StmtList - IntLit 25 - TypeDef - Ident "N" - Empty - Command - Ident "call" - IntLit 26 - IntLit 27 - StmtList - IntLit 28 - TypeDef - Ident "O" - Empty - Command - Ident "call" - IntLit 29 - IntLit 30 - StmtList - IntLit 31 - TypeSection - TypeDef - Ident "P" - Empty - Command - Ident "call" - TupleConstr - IntLit 32 - IntLit 33 - Infix - Ident "+" - Infix - Ident "*" - IntLit 34 - IntLit 35 - IntLit 36 - StmtList - IntLit 37 - TypeDef - Ident "R" - Empty - Command - Ident "call" - Infix - Ident "@" - TupleConstr - IntLit 38 - IntLit 39 - Infix - Ident "shl" - IntLit 40 - IntLit 41 - Infix - Ident "-" - Infix - Ident "*" - IntLit 42 - IntLit 43 - IntLit 44 - StmtList - IntLit 45 - TypeDef - Ident "S" - Empty - Command - Ident "call" - IntLit 46 - StmtList - IntLit 47 - StmtList - IntLit 48 - TypeDef - Ident "T" - Empty - Call - Ident "call" - StmtList - IntLit 49 - StmtList - IntLit 50 - StmtList - IntLit 51 -a: IntLit 1 -a: IntLit 2 -a: StmtList - IntLit 3 -a: StmtList - IntLit 4 -a: IntLit 5 -b: IntLit 6 -a: IntLit 7 -b: IntLit 8 -a: IntLit 9 -b: StmtList - IntLit 10 -a: IntLit 11 -b: StmtList - IntLit 12 -a: IntLit 13 -b: StmtList - IntLit 14 -a: IntLit 15 -b: StmtList - IntLit 16 -a: IntLit 17 -b: IntLit 18 -c: IntLit 19 -a: IntLit 20 -b: IntLit 21 -c: IntLit 22 -a: IntLit 23 -b: IntLit 24 -c: StmtList - IntLit 25 -a: IntLit 26 -b: IntLit 27 -c: StmtList - IntLit 28 -a: IntLit 29 -b: IntLit 30 -c: StmtList - IntLit 31 -a: TupleConstr - IntLit 32 - IntLit 33 -b: Infix - Ident "+" - Infix - Ident "*" - IntLit 34 - IntLit 35 - IntLit 36 -c: StmtList - IntLit 37 -a: Infix - Ident "@" - TupleConstr - IntLit 38 - IntLit 39 - Infix - Ident "shl" - IntLit 40 - IntLit 41 -b: Infix - Ident "-" - Infix - Ident "*" - IntLit 42 - IntLit 43 - IntLit 44 -c: StmtList - IntLit 45 -a: IntLit 46 -b: StmtList - IntLit 47 -c: StmtList - IntLit 48 -a: StmtList - IntLit 49 -b: StmtList - IntLit 50 -c: StmtList - IntLit 51 -''' -""" -import macros - -macro call(a): untyped = - echo "a: ", a.treeRepr - result = ident"int" -macro call(a, b): untyped = - echo "a: ", a.treeRepr - echo "b: ", b.treeRepr - result = ident"int" -macro call(a, b, c): untyped = - echo "a: ", a.treeRepr - echo "b: ", b.treeRepr - echo "c: ", c.treeRepr - result = ident"int" - -macro sections(x): untyped = - echo x.treeRepr - result = newStmtList(x) - for ts in x: - for td in ts: - let t = td[0] - result.add quote do: - doAssert `t` is int - -sections: - type A = call(1) - type - B = call 2 - C = call: 3 - D = call(): 4 - type - E = call(5, 6) - F = call 7, 8 - G = call(9): 10 - H = call(11): - 12 - I = call 13: 14 - J = call 15: - 16 - type - K = call(17, 18, 19) - L = call 20, 21, 22 - M = call(23, 24): 25 - N = call 26, 27: 28 - O = call 29, 30: - 31 - type - P = call (32, 33), 34 * 35 + 36: - 37 - R = call (38, 39) @ 40 shl 41, 42 * 43 - 44: - 45 - S = call 46: - 47 - do: - 48 - T = call: - 49 - do: - 50 - do: - 51 diff --git a/tests/pragmas/cfunction.c b/tests/pragmas/cfunction.c deleted file mode 100644 index bf49d6a29..000000000 --- a/tests/pragmas/cfunction.c +++ /dev/null @@ -1,4 +0,0 @@ - -int cfunction(void) { - return NUMBER_HERE; -} diff --git a/tests/pragmas/mused2a.nim b/tests/pragmas/mused2a.nim deleted file mode 100644 index d9b2bb9bf..000000000 --- a/tests/pragmas/mused2a.nim +++ /dev/null @@ -1,23 +0,0 @@ -import std/strutils - -from std/os import fileExists - -import std/typetraits as typetraits2 -from std/setutils import complement - - - - - -proc fn1() = discard -proc fn2*() = discard - - -let fn4 = 0 -let fn5* = 0 - - -const fn7 = 0 -const fn8* = 0 - -type T1 = object diff --git a/tests/pragmas/mused2b.nim b/tests/pragmas/mused2b.nim deleted file mode 100644 index 39c92b964..000000000 --- a/tests/pragmas/mused2b.nim +++ /dev/null @@ -1,3 +0,0 @@ -import mused2c -export mused2c - diff --git a/tests/pragmas/mused2c.nim b/tests/pragmas/mused2c.nim deleted file mode 100644 index a374e634e..000000000 --- a/tests/pragmas/mused2c.nim +++ /dev/null @@ -1 +0,0 @@ -proc baz*() = discard \ No newline at end of file diff --git a/tests/pragmas/mused3.nim b/tests/pragmas/mused3.nim deleted file mode 100644 index 0beec1d44..000000000 --- a/tests/pragmas/mused3.nim +++ /dev/null @@ -1,76 +0,0 @@ -#[ -ran from trunner -]# - - - - - - -# line 10 -when defined case1: - from mused3a import nil - from mused3b import nil - mused3a.fn1() - -when defined case2: - from mused3a as m1 import nil - m1.fn1() - -when defined case3: - from mused3a import fn1 - fn1() - -when defined case4: - from mused3a as m1 import fn1 - m1.fn1() - -when defined case5: - import mused3a as m1 - fn1() - -when defined case6: - import mused3a except nonexistent - fn1() - -when defined case7: - import mused3a - mused3a.fn1() - -when defined case8: - # re-export test - import mused3a except nonexistent - gn1() - -when defined case9: - # re-export test - import mused3a - gn1() - -when defined case10: - #[ - edge case which happens a lot in compiler code: - don't report UnusedImport for mused3b here even though it works without `import mused3b`, - because `a.b0.f0` is accessible from both mused3a and mused3b (fields are given implicit access) - ]# - import mused3a - import mused3b - var a: Bar - discard a.b0.f0 - -when false: - when defined case11: - #[ - xxx minor bug: this should give: - Warning: imported and not used: 'm2' [UnusedImport] - but doesn't, because currently implementation in `markOwnerModuleAsUsed` - only looks at `fn1`, not fully qualified call `m1.fn1() - ]# - from mused3a as m1 import nil - from mused3a as m2 import nil - m1.fn1() - -when defined case12: - import mused3a - import mused3a - fn1() diff --git a/tests/pragmas/mused3a.nim b/tests/pragmas/mused3a.nim deleted file mode 100644 index c33d1ecb3..000000000 --- a/tests/pragmas/mused3a.nim +++ /dev/null @@ -1,41 +0,0 @@ -when defined case1: - proc fn1*() = discard - -when defined case2: - proc fn1*() = discard - -when defined case3: - proc fn1*() = discard - proc fn2*() = discard - -when defined case4: - proc fn1*() = discard - proc fn2*() = discard - -when defined case5: - proc fn1*() = discard - -when defined case6: - proc fn1*() = discard - -when defined case7: - proc fn1*() = discard - -when defined case8: - import mused3b - export mused3b - -when defined case9: - import mused3b - export mused3b - -when defined case10: - import mused3b - type Bar* = object - b0*: Foo - -when defined case11: - proc fn1*() = discard - -when defined case12: - proc fn1*() = discard diff --git a/tests/pragmas/mused3b.nim b/tests/pragmas/mused3b.nim deleted file mode 100644 index de288bb08..000000000 --- a/tests/pragmas/mused3b.nim +++ /dev/null @@ -1,12 +0,0 @@ -when defined case1: - proc gn1*()=discard - -when defined case8: - proc gn1*()=discard - -when defined case9: - proc gn1*()=discard - -when defined case10: - type Foo* = object - f0*: int diff --git a/tests/pragmas/t12558.nim b/tests/pragmas/t12558.nim deleted file mode 100644 index 14fc74cee..000000000 --- a/tests/pragmas/t12558.nim +++ /dev/null @@ -1,15 +0,0 @@ -discard """ - nimout: '''@["1", "2", "3"]''' -""" - -import sequtils - -{.push compile_time.} - -proc foo = - echo map_it([1, 2, 3], $it) - -{.pop.} - -static: - foo() diff --git a/tests/pragmas/t12640.nim b/tests/pragmas/t12640.nim deleted file mode 100644 index c85185699..000000000 --- a/tests/pragmas/t12640.nim +++ /dev/null @@ -1,26 +0,0 @@ -discard """ - matrix: "--mm:refc" - nimout: '''1 -2 -3 -[1, 2, 3]''' - - output: '''1 -2 -3 -[1, 2, 3]''' -""" - -# todo fixme it doesn't work with ORC -proc doIt(a: openArray[int]) = - echo a - -proc foo() = - var bug {.global, compiletime.}: seq[int] - bug = @[1, 2 ,3] - for i in 0 .. high(bug): echo bug[i] - doIt(bug) - -static: - foo() -foo() diff --git a/tests/pragmas/t6448.nim b/tests/pragmas/t6448.nim index 6efb56e08..ab2e3811f 100644 --- a/tests/pragmas/t6448.nim +++ b/tests/pragmas/t6448.nim @@ -1,5 +1,5 @@ discard """ - errormsg: '''ambiguous call''' + errormsg: '''ambiguous call; both foobar.async''' line: 10 disabled: "32bit" """ diff --git a/tests/pragmas/t8741.nim b/tests/pragmas/t8741.nim index 221c732b0..61a449c01 100644 --- a/tests/pragmas/t8741.nim +++ b/tests/pragmas/t8741.nim @@ -1,5 +1,5 @@ discard """ - cmd: "nim check --hint:processing:off $file" + cmd: "nim check --hint[processing]:off $file" errormsg: "3 is not two" nimout: '''t8741.nim(13, 9) Error: cannot attach a custom pragma to 'a' t8741.nim(29, 15) template/generic instantiation of `onlyTwo` from here diff --git a/tests/pragmas/tbitsize.nim b/tests/pragmas/tbitsize.nim index 39aee445f..7a44944d2 100644 --- a/tests/pragmas/tbitsize.nim +++ b/tests/pragmas/tbitsize.nim @@ -10,13 +10,13 @@ type var b: bits -doAssert b.flag == 0 +assert b.flag == 0 b.flag = 1 -doAssert b.flag == 1 +assert b.flag == 1 b.flag = 2 -doAssert b.flag == 0 +assert b.flag == 0 b.opts = 7 -doAssert b.opts == 7 +assert b.opts == 7 b.opts = 9 -doAssert b.opts == -7 +assert b.opts == -7 diff --git a/tests/pragmas/tcompile_missing_file.nim b/tests/pragmas/tcompile_missing_file.nim deleted file mode 100644 index fd90bd57d..000000000 --- a/tests/pragmas/tcompile_missing_file.nim +++ /dev/null @@ -1,5 +0,0 @@ -discard """ - joinable: false - errormsg: "cannot find: noexist.c" -""" -{.compile: "noexist.c".} diff --git a/tests/pragmas/tcompile_pragma.nim b/tests/pragmas/tcompile_pragma.nim deleted file mode 100644 index 5b99352dd..000000000 --- a/tests/pragmas/tcompile_pragma.nim +++ /dev/null @@ -1,10 +0,0 @@ -discard """ - output: '''34''' - joinable: false -""" - -{.compile("cfunction.c", "-DNUMBER_HERE=34").} - -proc cfunction(): cint {.importc.} - -echo cfunction() diff --git a/tests/pragmas/tcustom_pragma.nim b/tests/pragmas/tcustom_pragma.nim index ad25cad98..719af4d50 100644 --- a/tests/pragmas/tcustom_pragma.nim +++ b/tests/pragmas/tcustom_pragma.nim @@ -1,6 +1,6 @@ {.experimental: "notnil".} -import macros, asyncmacro, asyncfutures +import macros block: template myAttr() {.pragma.} @@ -8,7 +8,7 @@ block: proc myProc():int {.myAttr.} = 2 const hasMyAttr = myProc.hasCustomPragma(myAttr) static: - doAssert(hasMyAttr) + assert(hasMyAttr) block: template myAttr(a: string) {.pragma.} @@ -17,26 +17,10 @@ block: MyObj = object myField1, myField2 {.myAttr: "hi".}: int - MyGenericObj[T] = object - myField1, myField2 {.myAttr: "hi".}: int - - MyOtherObj = MyObj - - var o: MyObj static: - doAssert o.myField2.hasCustomPragma(myAttr) - doAssert(not o.myField1.hasCustomPragma(myAttr)) - doAssert(not o.myField1.hasCustomPragma(MyObj)) - doAssert(not o.myField1.hasCustomPragma(MyOtherObj)) - - var ogen: MyGenericObj[int] - static: - doAssert ogen.myField2.hasCustomPragma(myAttr) - doAssert(not ogen.myField1.hasCustomPragma(myAttr)) - doAssert(not ogen.myField1.hasCustomPragma(MyGenericObj)) - doAssert(not ogen.myField1.hasCustomPragma(MyGenericObj)) - + assert o.myField2.hasCustomPragma(myAttr) + assert(not o.myField1.hasCustomPragma(myAttr)) import custom_pragma block: # A bit more advanced case @@ -58,31 +42,31 @@ block: # A bit more advanced case var s: MySerializable const aDefVal = s.a.getCustomPragmaVal(defaultValue) - static: doAssert(aDefVal == 5) + static: assert(aDefVal == 5) const aSerKey = s.a.getCustomPragmaVal(serializationKey) - static: doAssert(aSerKey == "asdf") + static: assert(aSerKey == "asdf") const cSerKey = getCustomPragmaVal(s.field.c, serializationKey) - static: doAssert(cSerKey == "cc") + static: assert(cSerKey == "cc") const procSerKey = getCustomPragmaVal(myproc, serializationKey) - static: doAssert(procSerKey == "myprocSS") + static: assert(procSerKey == "myprocSS") - static: doAssert(hasCustomPragma(myproc, alternativeKey)) + static: assert(hasCustomPragma(myproc, alternativeKey)) const hasFieldCustomPragma = s.field.hasCustomPragma(defaultValue) - static: doAssert(hasFieldCustomPragma == false) + static: assert(hasFieldCustomPragma == false) # pragma on an object static: - doAssert Subfield.hasCustomPragma(defaultValue) - doAssert(Subfield.getCustomPragmaVal(defaultValue) == "catman") + assert Subfield.hasCustomPragma(defaultValue) + assert(Subfield.getCustomPragmaVal(defaultValue) == "catman") - doAssert hasCustomPragma(type(s.field), defaultValue) + assert hasCustomPragma(type(s.field), defaultValue) proc foo(s: var MySerializable) = - static: doAssert(s.a.getCustomPragmaVal(defaultValue) == 5) + static: assert(s.a.getCustomPragmaVal(defaultValue) == 5) foo(s) @@ -107,8 +91,8 @@ block: # ref types leftSerKey = getCustomPragmaVal(s.left, serializationKey) rightSerKey = getCustomPragmaVal(s.right, serializationKey) static: - doAssert leftSerKey == "l" - doAssert rightSerKey == "r" + assert leftSerKey == "l" + assert rightSerKey == "r" var specS = SpecialNodeRef() @@ -116,25 +100,25 @@ block: # ref types dataDefVal = hasCustomPragma(specS.data, defaultValue) specLeftSerKey = hasCustomPragma(specS.left, serializationKey) static: - doAssert dataDefVal == true - doAssert specLeftSerKey == true + assert dataDefVal == true + assert specLeftSerKey == true var ptrS = NodePtr(nil) const ptrRightSerKey = getCustomPragmaVal(ptrS.right, serializationKey) static: - doAssert ptrRightSerKey == "r" + assert ptrRightSerKey == "r" var f = MyFile() const fileDefVal = f.getCustomPragmaVal(defaultValue) filePathDefVal = f.path.getCustomPragmaVal(defaultValue) static: - doAssert fileDefVal == "closed" - doAssert filePathDefVal == "invalid" + assert fileDefVal == "closed" + assert filePathDefVal == "invalid" static: - doAssert TypeWithoutPragma.hasCustomPragma(defaultValue) == false + assert TypeWithoutPragma.hasCustomPragma(defaultValue) == false block: type @@ -160,9 +144,9 @@ block: nestedItemDefVal = vari.nestedItem.getCustomPragmaVal(defaultValue) static: - doAssert hasIntSerKey - doAssert strSerKey == "string" - doAssert nestedItemDefVal == "Nimmers of the world, unite!" + assert hasIntSerKey + assert strSerKey == "string" + assert nestedItemDefVal == "Nimmers of the world, unite!" block: template simpleAttr {.pragma.} @@ -170,25 +154,15 @@ block: type Annotated {.simpleAttr.} = object proc generic_proc[T]() = - doAssert Annotated.hasCustomPragma(simpleAttr) + assert Annotated.hasCustomPragma(simpleAttr) + #-------------------------------------------------------------------------- # Pragma on proc type -type - MyAnnotatedProcType {.defaultValue(4).} = proc(x: int) - -let a {.defaultValue(4).}: proc(x: int) = nil -var b: MyAnnotatedProcType = nil -var c: proc(x: int): void {.defaultValue(5).} = nil -var d {.defaultValue(44).}: MyAnnotatedProcType = nil +let a: proc(x: int) {.defaultValue(5).} = nil static: - doAssert hasCustomPragma(a, defaultValue) - doAssert hasCustomPragma(MyAnnotatedProcType, defaultValue) - doAssert hasCustomPragma(b, defaultValue) - doAssert hasCustomPragma(typeof(c), defaultValue) - doAssert getCustomPragmaVal(d, defaultValue) == 44 - doAssert getCustomPragmaVal(typeof(d), defaultValue) == 4 + doAssert hasCustomPragma(a.type, defaultValue) # bug #8371 template thingy {.pragma.} @@ -275,232 +249,3 @@ block: var e {.fooBar("foo", 123, 'u').}: int doAssert(hasCustomPragma(e, fooBar)) doAssert(getCustomPragmaVal(e, fooBar).c == 123) - -block: - macro expectedAst(expectedRepr: static[string], input: untyped): untyped = - doAssert input.treeRepr & "\n" == expectedRepr - return input - - macro expectedAstRepr(expectedRepr: static[string], input: untyped): untyped = - doAssert input.repr == expectedRepr - return input - - const procTypeAst = """ -ProcTy - FormalParams - Empty - IdentDefs - Ident "x" - Ident "int" - Empty - Pragma - Ident "async" -""" - - type - Foo = proc (x: int) {.expectedAst(procTypeAst), async.} - - static: doAssert Foo is proc(x: int): Future[void] - - const asyncProcTypeAst = """ -proc (s: string): Future[void] {..}""" - # using expectedAst would show `OpenSymChoice` for Future[void], which is fragile. - type - Bar = proc (s: string) {.async, expectedAstRepr(asyncProcTypeAst).} - - static: doAssert Bar is proc(x: string): Future[void] - - const typeAst = """ -TypeDef - PragmaExpr - Ident "Baz" - Pragma - Empty - ObjectTy - Empty - Empty - RecList - IdentDefs - Ident "x" - Ident "string" - Empty -""" - - type - Baz {.expectedAst(typeAst).} = object - x: string - - static: doAssert Baz.x is string - - const procAst = """ -ProcDef - Ident "bar" - Empty - Empty - FormalParams - Ident "string" - IdentDefs - Ident "s" - Ident "string" - Empty - Empty - Empty - StmtList - ReturnStmt - Ident "s" -""" - - proc bar(s: string): string {.expectedAst(procAst).} = - return s - - static: doAssert bar("x") == "x" - -#------------------------------------------------------ -# bug #13909 - -template dependency*(id: string, weight = 0.0) {.pragma.} - -type - MyObject* = object - provider*: proc(obj: string): pointer {.dependency("Data/" & obj, 16.1), noSideEffect.} - -proc myproc(obj: string): string {.dependency("Data/" & obj, 16.1).} = - result = obj - -# bug 12523 -template myCustomPragma {.pragma.} - -type - RefType = ref object - field {.myCustomPragma.}: int - - ObjType = object - field {.myCustomPragma.}: int - RefType2 = ref ObjType - -block: - let x = RefType() - for fieldName, fieldSym in fieldPairs(x[]): - doAssert hasCustomPragma(fieldSym, myCustomPragma) - -block: - let x = RefType2() - for fieldName, fieldSym in fieldPairs(x[]): - doAssert hasCustomPragma(fieldSym, myCustomPragma) - -# bug 8457 -block: - template world {.pragma.} - - type - Hello = ref object - a: float32 - b {.world.}: int - - discard Hello(a: 1.0, b: 12) - -# custom pragma on iterators -block: - template prag {.pragma.} - {.push prag.} - proc hello = discard - iterator hello2: int = discard - -# issue #11511 -when false: - template myAttr {.pragma.} - - type TObj = object - a {.myAttr.}: int - - macro hasMyAttr(t: typedesc): untyped = - let objTy = t.getType[1].getType - let recList = objTy[2] - let sym = recList[0] - assert sym.kind == nnkSym and sym.eqIdent("a") - let hasAttr = sym.hasCustomPragma(myAttr) - newLit(hasAttr) - - doAssert hasMyAttr(TObj) - - -# bug #11415 -template noserialize() {.pragma.} - -type - Point[T] = object - x, y: T - - ReplayEventKind = enum - FoodAppeared, FoodEaten, DirectionChanged - - ReplayEvent = object - case kind: ReplayEventKind - of FoodEaten, FoodAppeared: # foodPos is in multiple branches - foodPos {.noserialize.}: Point[float] - of DirectionChanged: - playerPos: float -let ev = ReplayEvent( - kind: FoodEaten, - foodPos: Point[float](x: 5.0, y: 1.0) - ) - -doAssert ev.foodPos.hasCustomPragma(noserialize) - - -when false: - # misc - {.pragma: haha.} - {.pragma: hoho.} - template hehe(key, val: string, haha) {.pragma.} - - type A {.haha, hoho, haha, hehe("hi", "hu", "he").} = int - - assert A.getCustomPragmaVal(hehe) == (key: "hi", val: "hu", haha: "he") - - template hehe(key, val: int) {.pragma.} - - var bb {.haha, hoho, hehe(1, 2), haha, hehe("hi", "hu", "he").} = 3 - - # left-to-right priority/override order for getCustomPragmaVal - assert bb.getCustomPragmaVal(hehe) == (key: "hi", val: "hu", haha: "he") - -{.experimental: "dynamicBindSym".} - -# const -block: - template myAttr() {.pragma.} - template myAttr2(x: int) {.pragma.} - template myAttr3(x: string) {.pragma.} - - type - MyObj2 = ref object - - const a {.myAttr,myAttr2(2),myAttr3:"test".}: int = 0 - const b {.myAttr,myAttr2(2),myAttr3:"test".} = 0 - - macro forceHasCustomPragma(x: untyped, y: typed): untyped = - var x = bindSym(x.repr) - for c in x: - if c.symKind == nskConst: - x = c - break - result = getAst(hasCustomPragma(x, y)) - - macro forceGetCustomPragmaVal(x: untyped, y: typed): untyped = - var x = bindSym(x.repr) - for c in x: - if c.symKind == nskConst: - x = c - break - result = getAst(getCustomPragmaVal(x, y)) - - template check(s: untyped) = - doAssert forceHasCustomPragma(s, myAttr) - doAssert forceHasCustomPragma(s, myAttr2) - doAssert forceGetCustomPragmaVal(s, myAttr2) == 2 - doAssert forceHasCustomPragma(s, myAttr3) - doAssert forceGetCustomPragmaVal(s, myAttr3) == "test" - - check(a) - check(b) diff --git a/tests/pragmas/thintprocessing.nim b/tests/pragmas/thintprocessing.nim deleted file mode 100644 index c608bc6e4..000000000 --- a/tests/pragmas/thintprocessing.nim +++ /dev/null @@ -1,18 +0,0 @@ -discard """ - disabled: windows - matrix: "--hint:processing" - nimout: ''' -compile start -.. -warn_module.nim(6, 6) Hint: 'test' is declared but not used [XDeclaredButNotUsed] -compile end -''' -""" - -static: - echo "compile start" - -import warn_module - -static: - echo "compile end" diff --git a/tests/pragmas/tlocks.nim b/tests/pragmas/tlocks.nim index 5d6fcdd9c..ba66a2dca 100644 --- a/tests/pragmas/tlocks.nim +++ b/tests/pragmas/tlocks.nim @@ -1,3 +1,4 @@ + type SomeBase* = ref object of RootObj type SomeDerived* = ref object of SomeBase memberProc*: proc () diff --git a/tests/pragmas/tnoreturn.nim b/tests/pragmas/tnoreturn.nim index 6a58055fe..6d0466df3 100644 --- a/tests/pragmas/tnoreturn.nim +++ b/tests/pragmas/tnoreturn.nim @@ -1,5 +1,4 @@ discard """ -matrix: "--mm:refc" ccodeCheck: "\\i @'__attribute__((noreturn))' .*" action: compile """ diff --git a/tests/pragmas/tpragmas_misc.nim b/tests/pragmas/tpragmas_misc.nim deleted file mode 100644 index 6dc2e6b80..000000000 --- a/tests/pragmas/tpragmas_misc.nim +++ /dev/null @@ -1,70 +0,0 @@ -##[ -tests for misc pragmas that don't need a separate file -]## - -block: - static: doAssert not defined(tpragmas_misc_def) - {.undef(tpragmas_misc_def).} # works even if not set - static: doAssert not defined(tpragmas_misc_def) - {.define(tpragmas_misc_def).} - static: doAssert defined(tpragmas_misc_def) - {.undef(tpragmas_misc_def).} - static: doAssert not defined(tpragmas_misc_def) - -block: # (partial fix) bug #15920 - block: # var template pragmas don't work in templates - template foo(expr) = - expr - proc fun1()= - let a {.foo.} = 1 - template fun2()= - let a {.foo.} = 1 - fun1() # ok - fun2() # WAS bug - - template foo2() = discard # distractor (template or other symbol kind) - block: - template foo2(expr) = - expr - proc fun1()= - let a {.foo2.} = 1 - template fun2()= - let a {.foo2.} = 1 - fun1() # ok - fun2() # bug: Error: invalid pragma: foo2 - - block: # template pragmas don't work for templates, #18212 - # adapted from $nim/lib/std/private/since.nim - # case without overload - template since3(version: (int, int), body: untyped) {.dirty.} = - when (NimMajor, NimMinor) >= version: - body - when true: # bug - template fun3(): int {.since3: (1, 3).} = 12 - - block: # ditto, w - # case with overload - template since2(version: (int, int), body: untyped) {.dirty.} = - when (NimMajor, NimMinor) >= version: - body - template since2(version: (int, int, int), body: untyped) {.dirty.} = - when (NimMajor, NimMinor, NimPatch) >= version: - body - when true: # bug - template fun3(): int {.since2: (1, 3).} = 12 - -when true: # D20210801T100514:here - from macros import genSym - block: - template fn() = - var ret {.gensym.}: int # must special case template pragmas so it doesn't get confused - discard ret - fn() - static: discard genSym() - -block: # issue #10994 - macro foo(x): untyped = x - template bar {.pragma.} - - proc a {.bar.} = discard # works - proc b {.bar, foo.} = discard # doesn't diff --git a/tests/pragmas/tpragmas_reorder.nim b/tests/pragmas/tpragmas_reorder.nim deleted file mode 100644 index c4b1a6b0a..000000000 --- a/tests/pragmas/tpragmas_reorder.nim +++ /dev/null @@ -1,19 +0,0 @@ -discard """ - matrix: "--experimental:codeReordering" -""" - -runnableExamples: - import strtabs - var t = newStringTable() - t["name"] = "John" - t["city"] = "Monaco" - doAssert t.len == 2 - doAssert t.hasKey "name" - doAssert "name" in t - -include "system/inclrtl" - -{.pragma: rtlFunc, rtl.} - -proc hasKey*(): bool {.rtlFunc.} = - discard \ No newline at end of file diff --git a/tests/pragmas/tpush.nim b/tests/pragmas/tpush.nim index f2779ea70..5ecfe9704 100644 --- a/tests/pragmas/tpush.nim +++ b/tests/pragmas/tpush.nim @@ -13,15 +13,3 @@ proc WarnMe() = x: int echo(x) -# bug #11852 -proc foo(x: string, y: int, res: int) = - {.push checks: off} - var a: ptr char = unsafeAddr(x[y]) - {.pop.} - if x.len > y: - doAssert ord(a[]) == 51 - else: - doAssert x.len + 48 == res - -foo("", 0, 48) -foo("abc", 40, 51) diff --git a/tests/pragmas/treorder.nim b/tests/pragmas/treorder.nim index 72e8808b3..09a98ef6a 100644 --- a/tests/pragmas/treorder.nim +++ b/tests/pragmas/treorder.nim @@ -1,5 +1,4 @@ discard """ -matrix: "--experimental:codeReordering" output:'''0 1 2 diff --git a/tests/pragmas/ttypedef_macro.nim b/tests/pragmas/ttypedef_macro.nim deleted file mode 100644 index dd4c87757..000000000 --- a/tests/pragmas/ttypedef_macro.nim +++ /dev/null @@ -1,66 +0,0 @@ -import macros - -macro makeref(s): untyped = - expectKind s, nnkTypeDef - result = newTree(nnkTypeDef, s[0], s[1], newTree(nnkRefTy, s[2])) - -type - Obj {.makeref.} = object - a: int - -doAssert Obj is ref -doAssert Obj(a: 3)[].a == 3 - -macro multiply(amount: static int, s): 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: 2.} = object - x, y, z: int - Baz = object - -let bar1 = Bar1(x: 1, y: 2, z: 3) -let bar2 = Bar2(x: bar1.x, y: bar1.y, z: bar1.z) -doAssert Bar1 isnot Bar2 -doAssert not declared(Bar) -doAssert not declared(Bar3) - -# https://github.com/nim-lang/RFCs/issues/219 - -macro inferKind(td): untyped = - let name = $td[0].basename - var rhs = td[2] - while rhs.kind in {nnkPtrTy, nnkRefTy}: rhs = rhs[0] - if rhs.kind != nnkObjectTy: - result = td - else: - for n in rhs[^1]: - if n.kind == nnkRecCase and n[0][^2].eqIdent"_": - let kindTypeName = ident(name & "Kind") - let en = newTree(nnkEnumTy, newEmptyNode()) - for i in 1 ..< n.len: - let branch = n[i] - if branch.kind == nnkOfBranch: - for j in 0 ..< branch.len - 1: - en.add(branch[j]) - n[0][^2] = kindTypeName - return newTree(nnkTypeSection, - newTree(nnkTypeDef, kindTypeName, newEmptyNode(), en), - td) - -type Node {.inferKind.} = ref object - case kind: _ - of opValue: value: int - of opAdd, opSub, opMul, opCall: kids: seq[Node] - -doAssert opValue is NodeKind -let node = Node(kind: opMul, kids: @[ - Node(kind: opValue, value: 3), - Node(kind: opValue, value: 5) -]) -doAssert node.kind == opMul -doAssert node.kids[0].value * node.kids[1].value == 15 diff --git a/tests/pragmas/tused2.nim b/tests/pragmas/tused2.nim deleted file mode 100644 index f80c198d8..000000000 --- a/tests/pragmas/tused2.nim +++ /dev/null @@ -1,46 +0,0 @@ -discard """ - matrix: "--hint:all:off --hint:XDeclaredButNotUsed --path:." - joinable: false - nimoutFull: true - nimout: ''' -mused2a.nim(12, 6) Hint: 'fn1' is declared but not used [XDeclaredButNotUsed] -mused2a.nim(16, 5) Hint: 'fn4' is declared but not used [XDeclaredButNotUsed] -mused2a.nim(20, 7) Hint: 'fn7' is declared but not used [XDeclaredButNotUsed] -mused2a.nim(23, 6) Hint: 'T1' is declared but not used [XDeclaredButNotUsed] -mused2a.nim(1, 11) Warning: imported and not used: 'strutils' [UnusedImport] -mused2a.nim(3, 9) Warning: imported and not used: 'os' [UnusedImport] -mused2a.nim(5, 23) Warning: imported and not used: 'typetraits2' [UnusedImport] -mused2a.nim(6, 9) Warning: imported and not used: 'setutils' [UnusedImport] -tused2.nim(42, 8) Warning: imported and not used: 'mused2a' [UnusedImport] -tused2.nim(45, 11) Warning: imported and not used: 'strutils' [UnusedImport] -''' -""" - - - - - - - - - - - - - - - - - - - - - - -# line 40 - -import mused2a -import mused2b - -import std/strutils -baz() diff --git a/tests/pragmas/tuserpragma2.nim b/tests/pragmas/tuserpragma2.nim index c3f31cd5e..ce16c4649 100644 --- a/tests/pragmas/tuserpragma2.nim +++ b/tests/pragmas/tuserpragma2.nim @@ -3,10 +3,9 @@ discard """ file: "tuserpragma2.nim" line: 11 """ -{.push warningAsError[Effect]: on.} + # bug #7216 {.pragma: my_pragma, raises: [].} proc test1 {.my_pragma.} = raise newException(Exception, "msg") -{.pop.} diff --git a/tests/pragmas/tvar_macro.nim b/tests/pragmas/tvar_macro.nim deleted file mode 100644 index 3fb6e3e53..000000000 --- a/tests/pragmas/tvar_macro.nim +++ /dev/null @@ -1,128 +0,0 @@ -import macros - -block: # test usage - macro modify(sec) = - result = copy sec - result[0][0] = ident(repr(result[0][0]) & "Modified") - - block: - let foo {.modify.} = 3 - doAssert fooModified == 3 - - block: # in section - let - a = 1 - b {.modify.} = 2 - c = 3 - doAssert (a, bModified, c) == (1, 2, 3) - -block: # with single argument - macro appendToName(name: static string, sec) = - result = sec - result[0][0] = ident(repr(result[0][0]) & name) - - block: - let foo {.appendToName: "Bar".} = 3 - doAssert fooBar == 3 - - block: - let - a = 1 - b {.appendToName("").} = 2 - c = 3 - doAssert (a, b, c) == (1, 2, 3) - -macro appendToNameAndAdd(name: static string, incr: static int, sec) = - result = sec - result[0][0] = ident(repr(result[0][0]) & name) - result[0][2] = infix(result[0][2], "+", newLit(incr)) - -block: # with multiple arguments - block: - let foo {.appendToNameAndAdd("Bar", 5).} = 3 - doAssert fooBar == 8 - - block: - let - a = 1 - b {.appendToNameAndAdd("", 15).} = 2 - c = 3 - doAssert (a, b, c) == (1, 17, 3) - -block: # in other kinds of sections - block: - const - a = 1 - b {.appendToNameAndAdd("", 15).} = 2 - c = 3 - doAssert (a, b, c) == (1, 17, 3) - doAssert static(b) == b - - block: - var - a = 1 - b {.appendToNameAndAdd("", 15).} = 2 - c = 3 - doAssert (a, b, c) == (1, 17, 3) - b += a - c += b - doAssert (a, b, c) == (1, 18, 21) - -block: # with other pragmas - macro appendToNameAndAdd(name: static string, incr, sec) = - result = sec - result[0][0][0] = ident(repr(result[0][0][0]) & name) - result[0][0][1].add(ident"deprecated") - result[0][2] = infix(result[0][2], "+", incr) - - var - a = 1 - foo {.exportc: "exportedFooBar", appendToNameAndAdd("Bar", {'0'..'9'}), used.} = {'a'..'z', 'A'..'Z'} - b = 2 - - doAssert (a, b) == (1, 2) - - let importedFooBar {.importc: "exportedFooBar", nodecl.}: set[char] - - doAssert importedFooBar == fooBar #[tt.Warning - ^ fooBar is deprecated - ]# - - -block: # with stropping - macro `cast`(def) = - let def = def[0] - let - lhs = def[0] - typ = def[1] - ex = def[2] - addrTyp = if typ.kind == nnkEmpty: typ else: newTree(nnkPtrTy, typ) - result = quote do: - let tmp: `addrTyp` = unsafeAddr(`ex`) - template `lhs`: untyped = tmp[] - - macro assign(def) = - result = getAst(`cast`(def)) - - block: - let s = @["foo", "bar"] - let a {.`assign`.} = s[0] - doAssert a == "foo" - doAssert a[0].addr == s[0][0].addr - - block: - let - s = @["foo", "bar"] - a {.`cast`.} = s[0] - doAssert a == "foo" - doAssert a[0].addr == s[0][0].addr - -block: # bug #15920 - macro foo(def) = - result = def - proc fun1()= - let a {.foo.} = 1 - template fun2()= - let a {.foo.} = 1 - fun1() # ok - fun2() # BUG diff --git a/tests/pragmas/twarning_off.nim b/tests/pragmas/twarning_off.nim index ccf07b9c4..f1de9076f 100644 --- a/tests/pragmas/twarning_off.nim +++ b/tests/pragmas/twarning_off.nim @@ -1,6 +1,8 @@ discard """ nimout: ''' compile start +Hint: warn_module [Processing] +Hint: hashes [Processing] warn_module.nim(6, 6) Hint: 'test' is declared but not used [XDeclaredButNotUsed] compile end ''' diff --git a/tests/proc/t15949.nim b/tests/proc/t15949.nim deleted file mode 100644 index bc3fddc84..000000000 --- a/tests/proc/t15949.nim +++ /dev/null @@ -1,20 +0,0 @@ -# bug #15949 - -discard """ -errormsg: "parameter 'a' requires a type" -nimout: ''' -t15949.nim(20, 14) Error: parameter 'a' requires a type''' -""" - - -# line 10 -proc procGood(a, b = 1): (int, int) = (a, b) - -doAssert procGood() == (1, 1) -doAssert procGood(b = 3) == (1, 3) -doAssert procGood(a = 2) == (2, 1) -doAssert procGood(a = 5, b = 6) == (5, 6) - -# The type (and default value propagation breaks in the below example -# as semicolon is used instead of comma. -proc procBad(a; b = 1): (int, int) = (a, b) diff --git a/tests/proc/t17157.nim b/tests/proc/t17157.nim deleted file mode 100644 index 020e93fce..000000000 --- a/tests/proc/t17157.nim +++ /dev/null @@ -1,6 +0,0 @@ -discard """ - errormsg: "'untyped' is only allowed in templates and macros or magic procs" -""" - -template something(op: proc (v: untyped): void): void = - discard diff --git a/tests/proc/t19795.nim b/tests/proc/t19795.nim deleted file mode 100644 index 677ec0a63..000000000 --- a/tests/proc/t19795.nim +++ /dev/null @@ -1,19 +0,0 @@ -discard """ - matrix: "--mm:arc" -""" - -# bug #19795 -# bug #21085 - -type Vector = seq[int] - -var vect: Vector = newSeq[int](5) -doAssert vect == @[0, 0, 0, 0, 0] - -# Needed to get the problem. Could also use "var". -let vectCopy = vect - -# Then some procedure definition is needed to get the problem. -proc p(): int = 3 - -doAssert vect == @[0, 0, 0, 0, 0] \ No newline at end of file diff --git a/tests/proc/tfunc_type.nim b/tests/proc/tfunc_type.nim index 93697acb1..2a583fcb9 100644 --- a/tests/proc/tfunc_type.nim +++ b/tests/proc/tfunc_type.nim @@ -1,6 +1,6 @@ discard """ - errormsg: "func keyword is not allowed in type descriptions, use proc with {.noSideEffect.} pragma instead" + errmsg: "func keyword is not allowed in type descriptions, use proc with {.noSideEffect.} pragma instead" """ type diff --git a/tests/proc/tillegalreturntype.nim b/tests/proc/tillegalreturntype.nim index 1076f7f75..e26c44bea 100644 --- a/tests/proc/tillegalreturntype.nim +++ b/tests/proc/tillegalreturntype.nim @@ -1,6 +1,6 @@ discard """ - cmd: "nim check --hints:off $file" - errormsg: "" + cmd: "nim check $file" + errmsg: "" nimout: ''' tillegalreturntype.nim(11, 11) Error: return type 'typed' is only valid for macros and templates tillegalreturntype.nim(14, 11) Error: return type 'untyped' is only valid for macros and templates diff --git a/tests/proc/tlambdapragma.nim b/tests/proc/tlambdapragma.nim deleted file mode 100644 index daa952b1e..000000000 --- a/tests/proc/tlambdapragma.nim +++ /dev/null @@ -1,7 +0,0 @@ -discard """ - errormsg: "invalid pragma: exportc" -""" - -let _ = proc () {.exportc.} = - # this would previously cause a codegen error - discard diff --git a/tests/proc/tunderscoreparam.nim b/tests/proc/tunderscoreparam.nim deleted file mode 100644 index c2f6cf8ad..000000000 --- a/tests/proc/tunderscoreparam.nim +++ /dev/null @@ -1,109 +0,0 @@ -discard """ - targets: "c cpp js" -""" - -import std/[assertions, sequtils] - -proc test() = - block: - proc ok(_, _, a: int): int = - doAssert not compiles(_) - a - doassert ok(4, 2, 5) == 5 - - block: - proc ok(_: int, _: int, a: int): int = a - doAssert ok(4, 2, 5) == 5 - - block: - proc ok(_: int, _: float, a: int): int = a - doAssert ok(1, 2.0, 5) == 5 - - block: - proc ok(_: int, _: float, _: string, a: int): int = a - doAssert ok(1, 2.6, "5", 5) == 5 - - block: - proc ok[T](_, _, a: T): T = - doAssert not compiles(_) - a - doAssert ok(4, 2, 5) == 5 - doAssert ok("a", "b", "c") == "c" - doAssert not compiles(ok(1, 2, "a")) - - block: - let ok = proc (_, _, a: int): int = - doAssert not compiles(_) - a - doAssert ok(4, 2, 5) == 5 - - block: - proc foo(lam: proc (_, _, a: int): int): int = - lam(4, 2, 5) - doAssert foo(proc (_, _, a: auto): auto = - doAssert not compiles(_) - a) == 5 - - block: - iterator fn(_, _: int, c: int): int = yield c - doAssert toSeq(fn(1,2,3)) == @[3] - - block: - template ok(_, _, a: int): int = a - doAssert ok(4, 2, 5) == 5 - - block: - doAssert not (compiles do: - template bad(_: int): int = _ - discard bad(3)) - - block: - template ok(_: int, _: int, a: int): int = a - doAssert ok(4, 2, 5) == 5 - - block: - template ok(_: int, _: float, a: int): int = a - doAssert ok(1, 2.0, 5) == 5 - - block: - template ok(_: int, _: float, _: string, a: int): int = a - doAssert ok(1, 2.6, "5", 5) == 5 - - block: - template main2() = - iterator fn(_, _: int, c: int): int = yield c - main2() - - block: - template main = - proc foo(_: int) = - let a = _ - doAssert not compiles(main()) - -proc closureTest() = - var x = 0 - - block: - proc foo(_, _: int) = x += 5 - - foo(1, 2) - doAssert x == 5 - - block: - proc foo(_: int, _: float) = x += 5 - - foo(1, 2) - doAssert x == 10 - - block: - proc foo(_: int, _: float, _: string) = x += 5 - - foo(1, 2, "5") - doAssert x == 15 - -static: test() -test() - -when not defined(js): - static: closureTest() -closureTest() diff --git a/tests/range/t19678.nim b/tests/range/t19678.nim deleted file mode 100644 index 88f7eff89..000000000 --- a/tests/range/t19678.nim +++ /dev/null @@ -1,17 +0,0 @@ -discard """ - cmd: "nim check --hints:off $file" - errormsg: "" - nimout: ''' -t19678.nim(13, 13) Error: range of string is invalid - - - -''' -""" - -case "5": - of "0" .. "9": - discard - else: - discard - diff --git a/tests/range/tcompiletime_range_checks.nim b/tests/range/tcompiletime_range_checks.nim index 29e2c48a8..37095e0b7 100644 --- a/tests/range/tcompiletime_range_checks.nim +++ b/tests/range/tcompiletime_range_checks.nim @@ -1,5 +1,5 @@ discard """ - cmd: "nim check --hint:Processing:off --hint:Conf:off $file" + cmd: "nim check --hint[Processing]:off --hint[Conf]:off $file" errormsg: "18446744073709551615 can't be converted to int8" nimout: '''tcompiletime_range_checks.nim(36, 21) Error: 2147483648 can't be converted to int32 tcompiletime_range_checks.nim(37, 23) Error: -1 can't be converted to uint64 diff --git a/tests/range/trange.nim b/tests/range/trange.nim index abfa7d474..c864387f6 100644 --- a/tests/range/trange.nim +++ b/tests/range/trange.nim @@ -74,37 +74,37 @@ block tn8vsint16: import strutils block tcolors: - type TColor = distinct uint32 + type TColor = distinct int32 proc rgb(r, g, b: range[0..255]): TColor = result = TColor(r or g shl 8 or b shl 16) proc `$`(c: TColor): string = - result = "#" & toHex(uint32(c), 6) + result = "#" & toHex(int32(c), 6) echo rgb(34, 55, 255) - block: + when false: type - TColor = distinct uint32 - TColorComponent = distinct uint8 + TColor = distinct int32 + TColorComponent = distinct int8 proc red(a: TColor): TColorComponent = - result = TColorComponent(uint32(a) and 0xff'u32) + result = TColorComponent(int32(a) and 0xff'i32) proc green(a: TColor): TColorComponent = - result = TColorComponent(uint32(a) shr 8'u32 and 0xff'u32) + result = TColorComponent(int32(a) shr 8'i32 and 0xff'i32) proc blue(a: TColor): TColorComponent = - result = TColorComponent(uint32(a) shr 16'u32 and 0xff'u32) + result = TColorComponent(int32(a) shr 16'i32 and 0xff'i32) proc rgb(r, g, b: range[0..255]): TColor = result = TColor(r or g shl 8 or b shl 8) proc `+!` (a, b: TColorComponent): TColorComponent = ## saturated arithmetic: - result = TColorComponent(min(int(uint8(a)) + int(uint8(b)), 255)) + result = TColorComponent(min(ze(int8(a)) + ze(int8(b)), 255)) proc `+` (a, b: TColor): TColor = ## saturated arithmetic for colors makes sense, I think: - return rgb(int(red(a) +! red(b)), int(green(a) +! green(b)), int(blue(a) +! blue(b))) + return rgb(red(a) +! red(b), green(a) +! green(b), blue(a) +! blue(b)) - discard rgb(34, 55, 255) + rgb(34, 55, 255) block: type @@ -142,15 +142,3 @@ var a: array[4'u, string] for i in 0..` (or `cat` to avoid parallel -testing, which is slower). +tested by running `koch tests cat `. + +The folder ``rodfiles`` contains special tests that test incremental +compilation via symbol files. The folder ``dll`` contains simple DLL tests. The folder ``realtimeGC`` contains a test for validating that the realtime GC -can run properly without linking against the nimrtl.dll/so. +can run properly without linking against the nimrtl.dll/so. It includes a C +client and platform specific build files for manual compilation. diff --git a/tests/realtimeGC/cmain.c b/tests/realtimeGC/cmain.c new file mode 100644 index 000000000..0d4bb096a --- /dev/null +++ b/tests/realtimeGC/cmain.c @@ -0,0 +1,67 @@ +#ifdef WIN +#include +#else +#include +#include /* for sleep(3) */ +#endif +#include +#include +#include +#include +#include + +#define RUNTIME (15*60) + + +typedef void (*pFunc)(void); + +int main(int argc, char* argv[]) +{ + int i; + void* hndl; + pFunc status; + pFunc count; + pFunc checkOccupiedMem; + +#ifdef WIN + hndl = (void*) LoadLibrary((char const*)"./tests/realtimeGC/shared.dll"); + status = (pFunc)GetProcAddress((HMODULE) hndl, (char const*)"status"); + count = (pFunc)GetProcAddress((HMODULE) hndl, (char const*)"count"); + checkOccupiedMem = (pFunc)GetProcAddress((HMODULE) hndl, (char const*)"checkOccupiedMem"); +#else /* OSX || NIX */ + hndl = (void*) dlopen((char const*)"./tests/realtimeGC/libshared.so", RTLD_LAZY); + status = (pFunc) dlsym(hndl, (char const*)"status"); + count = (pFunc) dlsym(hndl, (char const*)"count"); + checkOccupiedMem = (pFunc) dlsym(hndl, (char const*)"checkOccupiedMem"); +#endif + + assert(hndl); + assert(status); + assert(count); + assert(checkOccupiedMem); + + time_t startTime = time((time_t*)0); + time_t runTime = (time_t)(RUNTIME); + time_t accumTime = 0; + while (accumTime < runTime) { + for (i = 0; i < 10; i++) + count(); + /* printf("1. sleeping...\n"); */ + sleep(1); + for (i = 0; i < 10; i++) + status(); + /* printf("2. sleeping...\n"); */ + sleep(1); + checkOccupiedMem(); + accumTime = time((time_t*)0) - startTime; + /* printf("--- Minutes left to run: %d\n", (int)(runTime-accumTime)/60); */ + } + printf("Cleaning up the shared object pointer...\n"); +#ifdef WIN + FreeLibrary((HMODULE)hndl); +#else /* OSX || NIX */ + dlclose(hndl); +#endif + printf("Done\n"); + return 0; +} diff --git a/tests/realtimeGC/main.nim.cfg b/tests/realtimeGC/main.nim.cfg new file mode 100644 index 000000000..fed4fa471 --- /dev/null +++ b/tests/realtimeGC/main.nim.cfg @@ -0,0 +1,6 @@ + +--app:console +--threads:on + +-d:release +-d:useRealtimeGC diff --git a/tests/realtimeGC/nmain.nim b/tests/realtimeGC/nmain.nim new file mode 100644 index 000000000..c9f558dbc --- /dev/null +++ b/tests/realtimeGC/nmain.nim @@ -0,0 +1,46 @@ +discard """ + cmd: "nim $target --debuginfo $options $file" + output: "Done" +""" + +import times, os, threadpool + +const RUNTIME = 15 * 60 # 15 minutes + +when defined(windows): + const dllname = "./tests/realtimeGC/shared.dll" +elif defined(macosx): + const dllname = "./tests/realtimeGC/libshared.dylib" +else: + const dllname = "./tests/realtimeGC/libshared.so" + +proc status() {.importc: "status", dynlib: dllname.} +proc count() {.importc: "count", dynlib: dllname.} +proc checkOccupiedMem() {.importc: "checkOccupiedMem", dynlib: dllname.} + +proc process() = + let startTime = getTime() + let runTime = cast[Time](RUNTIME) # + var accumTime: Time + while accumTime < runTime: + for i in 0..10: + count() + # echo("1. sleeping... ") + sleep(500) + for i in 0..10: + status() + # echo("2. sleeping... ") + sleep(500) + checkOccupiedMem() + accumTime = cast[Time]((getTime() - startTime)) + # echo("--- Minutes left to run: ", int(int(runTime-accumTime)/60)) + +proc main() = + process() + # parallel: + # for i in 0..0: + # spawn process() + # sync() + echo("Done") + +main() diff --git a/tests/realtimeGC/readme.txt b/tests/realtimeGC/readme.txt new file mode 100644 index 000000000..b2e37a1f0 --- /dev/null +++ b/tests/realtimeGC/readme.txt @@ -0,0 +1,21 @@ +Test the realtime GC without linking nimrtl.dll/so. + +Note, this is a long running test, default is 35 minutes. To change the +the run time see RUNTIME in nmain.nim and cmain.c. + +You can build shared.nim, nmain.nim, and cmain.c by running make (nix systems) +or make.bat (Windows systems). They both assume GCC and that it's in your +path. Output: shared.(dll/so), cmain(.exe), nmain(.exe). + +To run the test: execute either nmain or cmain in a shell window. + +To build by hand: + + - build the shared object (shared.nim): + + $ nim c tests/realtimeGC/shared.nim + + - build the client executables: + + $ nim c --threads:on tests/realtimeGC/nmain.nim + $ gcc -o tests/realtimeGC/cmain tests/realtimeGC/cmain.c -ldl diff --git a/tests/realtimeGC/shared.nim b/tests/realtimeGC/shared.nim index 8b5c05e47..1abe42089 100644 --- a/tests/realtimeGC/shared.nim +++ b/tests/realtimeGC/shared.nim @@ -1,3 +1,8 @@ +discard """ +cmd: "nim $target --debuginfo --hints:on --app:lib $options $file" +action: compile +""" + import strutils # Global state, accessing with threads, no locks. Don't do this at diff --git a/tests/realtimeGC/shared.nim.cfg b/tests/realtimeGC/shared.nim.cfg new file mode 100644 index 000000000..e153b26fa --- /dev/null +++ b/tests/realtimeGC/shared.nim.cfg @@ -0,0 +1,5 @@ +--app:lib +--threads:on + +-d:release +-d:useRealtimeGC diff --git a/tests/realtimeGC/tmain.nim b/tests/realtimeGC/tmain.nim deleted file mode 100644 index ca0177e3d..000000000 --- a/tests/realtimeGC/tmain.nim +++ /dev/null @@ -1,62 +0,0 @@ -discard """ - cmd: "nim $target --threads:on -d:release -d:useRealtimeGC $options $file" - joinable:false -""" - -#[ -was: cmd: "nim $target --debuginfo $options $file" -these dont' seem needed --debuginfo -nor these from the previous main.nim.cfg: --app:console -]# - -#[ -Test the realtime GC without linking nimrtl.dll/so. - -To build by hand and run the test for 35 minutes: -`nim r --threads:on -d:runtimeSecs:2100 tests/realtimeGC/tmain.nim` -]# - -import times, os, strformat, strutils -from stdtest/specialpaths import buildDir -# import threadpool - -const runtimeSecs {.intdefine.} = 5 - -const file = "shared.nim" -const dllname = buildDir / (DynlibFormat % "shared_D20210524T180506") - -static: - # D20210524T180826:here we compile the dependency on the fly - let nim = getCurrentCompilerExe() - let (output, exitCode) = gorgeEx(fmt"{nim} c -o:{dllname} --debuginfo --app:lib --threads:on -d:release -d:useRealtimeGC {file}") - doAssert exitCode == 0, output - -proc status() {.importc: "status", dynlib: dllname.} -proc count() {.importc: "count", dynlib: dllname.} -proc checkOccupiedMem() {.importc: "checkOccupiedMem", dynlib: dllname.} - -proc process() = - let startTime = getTime() - let runTime = cast[Time](runtimeSecs) - var accumTime: Time - while accumTime < runTime: - for i in 0..10: - count() - # echo("1. sleeping... ") - sleep(500) - for i in 0..10: - status() - # echo("2. sleeping... ") - sleep(500) - checkOccupiedMem() - accumTime = cast[Time]((getTime() - startTime)) - # echo("--- Minutes left to run: ", int(int(runTime-accumTime)/60)) - -proc main() = - process() - # parallel: - # for i in 0..0: - # spawn process() - # sync() - -main() diff --git a/tests/rodfiles/aconv.nim b/tests/rodfiles/aconv.nim new file mode 100644 index 000000000..ffd8f3648 --- /dev/null +++ b/tests/rodfiles/aconv.nim @@ -0,0 +1,9 @@ +discard """ + output: "ugly conversion successful" +""" + +import int2bool + +if 4: + echo "ugly conversion successful" + diff --git a/tests/rodfiles/amethods.nim b/tests/rodfiles/amethods.nim new file mode 100644 index 000000000..29cf757f7 --- /dev/null +++ b/tests/rodfiles/amethods.nim @@ -0,0 +1,13 @@ + +type + TBaseClass* = object of RootObj + +proc newBaseClass*: ref TBaseClass = + new result + +method echoType*(x: ref TBaseClass) {.base.} = + echo "base class" + +proc echoAlias*(x: ref TBaseClass) = + echoType x + diff --git a/tests/rodfiles/bconv.nim b/tests/rodfiles/bconv.nim new file mode 100644 index 000000000..2289a7f97 --- /dev/null +++ b/tests/rodfiles/bconv.nim @@ -0,0 +1,9 @@ +discard """ + output: "ugly conversion successful 2" +""" + +import int2bool + +if 4: + echo "ugly conversion successful 2" + diff --git a/tests/rodfiles/bmethods.nim b/tests/rodfiles/bmethods.nim new file mode 100644 index 000000000..c77941e4a --- /dev/null +++ b/tests/rodfiles/bmethods.nim @@ -0,0 +1,29 @@ +discard """ + output: '''derived class +base class +''' +""" + +import amethods + + +type + TDerivedClass* = object of TBaseClass + +proc newDerivedClass: ref TDerivedClass = + new result + +method echoType*(x: ref TDerivedClass) = + echo "derived class" + +var b, d: ref TBaseClass + +b = newBaseClass() +d = newDerivedClass() + +#b.echoType() +#d.echoType() + +echoAlias d +echoAlias b + diff --git a/tests/rodfiles/bmethods2.nim b/tests/rodfiles/bmethods2.nim new file mode 100644 index 000000000..c9d25eee4 --- /dev/null +++ b/tests/rodfiles/bmethods2.nim @@ -0,0 +1,29 @@ +discard """ + output: '''derived class 2 +base class +''' +""" + +import amethods + + +type + TDerivedClass* = object of TBaseClass + +proc newDerivedClass: ref TDerivedClass = + new result + +method echoType*(x: ref TDerivedClass) = + echo "derived class 2" + +var b, d: ref TBaseClass + +b = newBaseClass() +d = newDerivedClass() + +#b.echoType() +#d.echoType() + +echoAlias d +echoAlias b + diff --git a/tests/rodfiles/deada.nim b/tests/rodfiles/deada.nim new file mode 100644 index 000000000..3fa4192f8 --- /dev/null +++ b/tests/rodfiles/deada.nim @@ -0,0 +1,8 @@ +discard """ + output: '''246 +''' +""" + +import deadg, deadb + + diff --git a/tests/rodfiles/deada2.nim b/tests/rodfiles/deada2.nim new file mode 100644 index 000000000..2925b4d43 --- /dev/null +++ b/tests/rodfiles/deada2.nim @@ -0,0 +1,12 @@ +discard """ + output: '''246 +xyzabc +''' +""" + +import deadg, deadb + +# now add call to previously unused proc p2: +echo p2("xyz", "abc") + + diff --git a/tests/rodfiles/deadb.nim b/tests/rodfiles/deadb.nim new file mode 100644 index 000000000..776a07ac7 --- /dev/null +++ b/tests/rodfiles/deadb.nim @@ -0,0 +1,7 @@ + +import deadg + + +echo p1(123, 123) + + diff --git a/tests/rodfiles/deadg.nim b/tests/rodfiles/deadg.nim new file mode 100644 index 000000000..0aee59bb8 --- /dev/null +++ b/tests/rodfiles/deadg.nim @@ -0,0 +1,7 @@ +proc p1*(x, y: int): int = + result = x + y + +proc p2*(x, y: string): string = + result = x & y + + diff --git a/tests/rodfiles/gtkex1.nim b/tests/rodfiles/gtkex1.nim new file mode 100644 index 000000000..50779cb9e --- /dev/null +++ b/tests/rodfiles/gtkex1.nim @@ -0,0 +1,14 @@ +import + cairo, glib2, gtk2 + +proc destroy(widget: PWidget, data: Pgpointer) {.cdecl.} = + main_quit() + +var + window: PWidget +nim_init() +window = window_new(WINDOW_TOPLEVEL) +discard signal_connect(window, "destroy", + SIGNAL_FUNC(gtkex1.destroy), nil) +show(window) +main() diff --git a/tests/rodfiles/gtkex2.nim b/tests/rodfiles/gtkex2.nim new file mode 100644 index 000000000..0949e4872 --- /dev/null +++ b/tests/rodfiles/gtkex2.nim @@ -0,0 +1,22 @@ + +import + glib2, gtk2 + +proc destroy(widget: PWidget, data: Pgpointer){.cdecl.} = + main_quit() + +var + window: PWidget + button: PWidget + +nim_init() +window = window_new(WINDOW_TOPLEVEL) +button = button_new("Click me") +set_border_width(PContainer(window), 5) +add(PContainer(window), button) +discard signal_connect(window, "destroy", + SIGNAL_FUNC(gtkex2.destroy), nil) +show(button) +show(window) +main() + diff --git a/tests/rodfiles/hallo.nim b/tests/rodfiles/hallo.nim new file mode 100644 index 000000000..ac45be9fa --- /dev/null +++ b/tests/rodfiles/hallo.nim @@ -0,0 +1,6 @@ +discard """ + output: "Hello World" +""" + +echo "Hello World" + diff --git a/tests/rodfiles/hallo2.nim b/tests/rodfiles/hallo2.nim new file mode 100644 index 000000000..40fe64cfd --- /dev/null +++ b/tests/rodfiles/hallo2.nim @@ -0,0 +1,17 @@ +discard """ + output: "Hello World" +""" + +# Test incremental type information + +type + TNode = object {.pure.} + le, ri: ref TNode + data: string + +proc newNode(data: string): ref TNode = + new(result) + result.data = data + +echo newNode("Hello World").data + diff --git a/tests/rodfiles/int2bool.nim b/tests/rodfiles/int2bool.nim new file mode 100644 index 000000000..bb0682844 --- /dev/null +++ b/tests/rodfiles/int2bool.nim @@ -0,0 +1,7 @@ + +{.overflowchecks: on.} + +converter uglyToBool*(x: int): bool = + result = x != 0 + + diff --git a/tests/rodfiles/nim.cfg b/tests/rodfiles/nim.cfg new file mode 100644 index 000000000..78fc8db64 --- /dev/null +++ b/tests/rodfiles/nim.cfg @@ -0,0 +1,2 @@ +--nimcache:"$projectPath/nimcache" +--symbolFiles:on diff --git a/tests/rodfiles/tgeneric1.nim b/tests/rodfiles/tgeneric1.nim new file mode 100644 index 000000000..a3f7b870b --- /dev/null +++ b/tests/rodfiles/tgeneric1.nim @@ -0,0 +1,13 @@ +discard """ + output: "abcd" +""" + +import tables + +var x = initTable[int, string]() + +x[2] = "ab" +x[5] = "cd" + +echo x[2], x[5] + diff --git a/tests/rodfiles/tgeneric2.nim b/tests/rodfiles/tgeneric2.nim new file mode 100644 index 000000000..552d60267 --- /dev/null +++ b/tests/rodfiles/tgeneric2.nim @@ -0,0 +1,13 @@ +discard """ + output: "abef" +""" + +import tables + +var x = initTable[int, string]() + +x[2] = "ab" +x[5] = "ef" + +echo x[2], x[5] + diff --git a/tests/sandwich/generic_library.nim b/tests/sandwich/generic_library.nim deleted file mode 100644 index 43e7bd65f..000000000 --- a/tests/sandwich/generic_library.nim +++ /dev/null @@ -1,6 +0,0 @@ - -proc libraryFunc*[T](x: T) = - mixin mixedIn, indirectlyMixedIn - echo mixedIn() - echo indirectlyMixedIn() - diff --git a/tests/sandwich/helper_module.nim b/tests/sandwich/helper_module.nim deleted file mode 100644 index d003bf044..000000000 --- a/tests/sandwich/helper_module.nim +++ /dev/null @@ -1,3 +0,0 @@ - -proc indirectlyMixedIn*: int = - 200 diff --git a/tests/sandwich/module_using_generic_library.nim b/tests/sandwich/module_using_generic_library.nim deleted file mode 100644 index bbb0d92a4..000000000 --- a/tests/sandwich/module_using_generic_library.nim +++ /dev/null @@ -1,12 +0,0 @@ - -import - generic_library, helper_module - -proc mixedIn: int = 100 - -proc makeUseOfLibrary*[T](x: T) = - bind mixedIn, indirectlyMixedIn - libraryFunc(x) - -when isMainModule: - makeUseOfLibrary "test" diff --git a/tests/sandwich/tmain.nim b/tests/sandwich/tmain.nim deleted file mode 100644 index aa50bfb04..000000000 --- a/tests/sandwich/tmain.nim +++ /dev/null @@ -1,9 +0,0 @@ -discard """ - output: '''100 -200''' -""" - -import - module_using_generic_library - -makeUseOfLibrary "test" diff --git a/tests/collections/tseq.nim b/tests/seq/tseq.nim similarity index 72% rename from tests/collections/tseq.nim rename to tests/seq/tseq.nim index 39f066f4c..6a28bc8e6 100644 --- a/tests/collections/tseq.nim +++ b/tests/seq/tseq.nim @@ -1,5 +1,4 @@ discard """ - matrix: "--mm:refc; --mm:orc" output: ''' Hithere, what's your name?Hathere, what's your name? fA13msg1falsefB14msg2truefC15msg3false @@ -12,6 +11,8 @@ FilterIt: [1, 3, 7] Concat: [1, 3, 5, 7, 2, 4, 6] Deduplicate: [1, 2, 3, 4, 5, 7] @[()] +@[1, 42, 3] +@[1, 42, 3] 2345623456 ''' """ @@ -23,7 +24,7 @@ block tseq2: # multiply two int sequences: for i in 0..len(a)-1: result[i] = a[i] * b[i] - doAssert(@[1, 2, 3] * @[1, 2, 3] == @[1, 4, 9]) + assert(@[1, 2, 3] * @[1, 2, 3] == @[1, 4, 9]) @@ -157,43 +158,41 @@ block tsequtils: echo someObjSeq -when not defined(nimseqsv2): - block tshallowseq: - proc xxx() = - var x: seq[int] = @[1, 2, 3] - var y: seq[int] - system.shallowCopy(y, x) - y[1] = 42 - doAssert y == @[1, 42, 3] - doAssert x == @[1, 42, 3] - xxx() + +block tshallowseq: + proc xxx() = + var x: seq[int] = @[1, 2, 3] + var y: seq[int] + system.shallowCopy(y, x) + y[1] = 42 + echo y + echo x + xxx() - block tshallowemptyseq: - proc test() = - var nilSeq: seq[int] = @[] - var emptySeq: seq[int] = newSeq[int]() - block: - var t = @[1,2,3] - when defined(gcRefc): - shallow(nilSeq) - t = nilSeq - doAssert t == @[] - block: - var t = @[1,2,3] - when defined(gcRefc): - shallow(emptySeq) - t = emptySeq - doAssert t == @[] - block: - var t = @[1,2,3] - shallowCopy(t, nilSeq) - doAssert t == @[] - block: - var t = @[1,2,3] - shallowCopy(t, emptySeq) - doAssert t == @[] - test() +block tshallowemptyseq: + proc test() = + var nilSeq: seq[int] = @[] + var emptySeq: seq[int] = newSeq[int]() + block: + var t = @[1,2,3] + shallow(nilSeq) + t = nilSeq + doAssert t == @[] + block: + var t = @[1,2,3] + shallow(emptySeq) + t = emptySeq + doAssert t == @[] + block: + var t = @[1,2,3] + shallowCopy(t, nilSeq) + doAssert t == @[] + block: + var t = @[1,2,3] + shallowCopy(t, emptySeq) + doAssert t == @[] + test() import strutils @@ -202,16 +201,6 @@ block ttoseq: stdout.write(x) for x in items(toSeq(countup(2, 6))): stdout.write(x) - var y: typeof("a b c".split) + var y: type("a b c".split) y = "xzy" stdout.write("\n") - -block tseqmapitchain: - doAssert @[101, 102] == [1, 2].mapIt(func (x: int): int = it + x).mapIt(it(100)) - - -for i in 0..100: - # fix #14655 - var test = newSeqOfCap[uint32](1) - test.setLen(1) - doAssert test[0] == 0, $(test[0], i) diff --git a/tests/sets/m17385.nim b/tests/sets/m17385.nim deleted file mode 100644 index 3919e067a..000000000 --- a/tests/sets/m17385.nim +++ /dev/null @@ -1,11 +0,0 @@ -import std/sets - -type - Diff*[T] = object - data: T - -proc test*[T](diff: Diff[T]) = - var bPopular = initHashSet[T]() - for element in bPopular.items(): - echo element - diff --git a/tests/sets/t15435.nim b/tests/sets/t15435.nim deleted file mode 100644 index 5ead7e641..000000000 --- a/tests/sets/t15435.nim +++ /dev/null @@ -1,29 +0,0 @@ -# bug #15435 -discard """ -errormsg: "type mismatch: got " -nimout: '''t15435.nim(28, 13) Error: type mismatch: got -but expected one of: -proc `<`[T](x, y: set[T]): bool - first type mismatch at position: 2 - required type for y: set[T] - but expression 'x' is of type: set[range 1..5(uint8)] -20 other mismatching symbols have been suppressed; compile with --showAllMismatches:on to see them - -expression: {1'u8, 5} < x''' -""" - - - - - - -## line 20 -var - x: set[range[1u8..5u8]] - -x.incl(1) -x.incl(3) -x.incl(5) - -if {1u8, 5} < x: - echo "successful" diff --git a/tests/sets/t17385.nim b/tests/sets/t17385.nim deleted file mode 100644 index cc08b4882..000000000 --- a/tests/sets/t17385.nim +++ /dev/null @@ -1,4 +0,0 @@ -import m17385 - -let a = Diff[int]() -a.test() diff --git a/tests/sets/t20997.nim b/tests/sets/t20997.nim deleted file mode 100644 index b320eee1a..000000000 --- a/tests/sets/t20997.nim +++ /dev/null @@ -1,18 +0,0 @@ -discard """ - joinable: false -""" - -{.passC: "-flto".} -{.passL: "-flto".} - -template f(n: int) = discard card(default(set[range[0 .. (1 shl n) - 1]])) -f( 7) -f( 8) -f( 9) -f(10) -f(11) -f(12) -f(13) -f(14) -f(15) -f(16) diff --git a/tests/sets/t5792.nim b/tests/sets/t5792.nim deleted file mode 100644 index 297a1fc15..000000000 --- a/tests/sets/t5792.nim +++ /dev/null @@ -1,17 +0,0 @@ -discard """ - matrix: "--gc:refc; --gc:arc" -""" - -type - T = enum - a - b - c - U = object - case k: T - of a: - x: int - of {b, c} - {a}: - y: int - -doAssert U(k: b, y: 1).y == 1 diff --git a/tests/sets/tsets.nim b/tests/sets/tsets.nim index 517c0b89c..dbbeed543 100644 --- a/tests/sets/tsets.nim +++ b/tests/sets/tsets.nim @@ -1,57 +1,207 @@ -# Test builtin sets +discard """ +output: ''' +Ha ein F ist in s! +false +''' +""" +# Test the handling of sets -# xxx these tests are not very good, this should be revisited. - -when defined nimTestsTsetsGenerate: - # to generate enums for this test - var ret: string - for i in 0..<276: - ret.add "k" & $i & ", " - echo ret +import + strutils proc testSets(s: var set[char]) = s = {'A', 'B', 'C', 'E'..'G'} + {'Z'} + s # test sets if the first element is different from 0: -block: - type - TAZ = range['a'..'z'] - TAZset = set[TAZ] - FakeTokType = enum - k0, k1, k2, k3, k4, k5, k6, k7, k8, k9, k10, k11, k12, k13, k14, k15, k16, k17, k18, k19, k20, k21, k22, k23, k24, k25, k26, k27, k28, k29, k30, k31, k32, k33, k34, k35, k36, k37, k38, k39, k40, k41, k42, k43, k44, k45, k46, k47, k48, k49, k50, k51, k52, k53, k54, k55, k56, k57, k58, k59, k60, k61, k62, k63, k64, k65, k66, k67, k68, k69, k70, k71, k72, k73, k74, k75, k76, k77, k78, k79, k80, k81, k82, k83, k84, k85, k86, k87, k88, k89, k90, k91, k92, k93, k94, k95, k96, k97, k98, k99, k100, k101, k102, k103, k104, k105, k106, k107, k108, k109, k110, k111, k112, k113, k114, k115, k116, k117, k118, k119, k120, k121, k122, k123, k124, k125, k126, k127, k128, k129, k130, k131, k132, k133, k134, k135, k136, k137, k138, k139, k140, k141, k142, k143, k144, k145, k146, k147, k148, k149, k150, k151, k152, k153, k154, k155, k156, k157, k158, k159, k160, k161, k162, k163, k164, k165, k166, k167, k168, k169, k170, k171, k172, k173, k174, k175, k176, k177, k178, k179, k180, k181, k182, k183, k184, k185, k186, k187, k188, k189, k190, k191, k192, k193, k194, k195, k196, k197, k198, k199, k200, k201, k202, k203, k204, k205, k206, k207, k208, k209, k210, k211, k212, k213, k214, k215, k216, k217, k218, k219, k220, k221, k222, k223, k224, k225, k226, k227, k228, k229, k230, k231, k232, k233, k234, k235, k236, k237, k238, k239, k240, k241, k242, k243, k244, k245, k246, k247, k248, k249 - FakeTokTypeRange = range[k2..k101] - FakeTokTypes = set[FakeTokTypeRange] +type + TAZ = range['a'..'z'] + TAZset = set[TAZ] - const toktypes: FakeTokTypes = {FakeTokTypeRange(k2)..pred(k64), k72..k74} + TTokType* = enum + tkInvalid, tkEof, + tkSymbol, + tkAddr, tkAnd, tkAs, tkAsm, tkBlock, tkBreak, tkCase, tkCast, tkConst, + tkContinue, tkConverter, tkDiscard, tkDiv, tkElif, tkElse, tkEnd, tkEnum, + tkExcept, tkException, tkFinally, tkFor, tkFrom, tkGeneric, tkIf, tkImplies, + tkImport, tkIn, tkInclude, tkIs, tkIsnot, tkIterator, tkLambda, tkMacro, + tkMethod, tkMod, tkNil, tkNot, tkNotin, tkObject, tkOf, tkOr, tkOut, tkProc, + tkPtr, tkRaise, tkRecord, tkRef, tkReturn, tkShl, tkShr, tkTemplate, tkTry, + tkType, tkVar, tkWhen, tkWhere, tkWhile, tkWith, tkWithout, tkXor, tkYield, + tkIntLit, tkInt8Lit, tkInt16Lit, tkInt32Lit, tkInt64Lit, tkFloatLit, + tkFloat32Lit, tkFloat64Lit, tkStrLit, tkRStrLit, tkTripleStrLit, tkCharLit, + tkRCharLit, tkParLe, tkParRi, tkBracketLe, tkBracketRi, tkCurlyLe, + tkCurlyRi, tkBracketDotLe, tkBracketDotRi, + tkCurlyDotLe, tkCurlyDotRi, + tkParDotLe, tkParDotRi, + tkComma, tkSemiColon, tkColon, tkEquals, tkDot, tkDotDot, tkHat, tkOpr, + tkComment, tkAccent, tkInd, tkSad, tkDed, + tkSpaces, tkInfixOpr, tkPrefixOpr, tkPostfixOpr + TTokTypeRange = range[tkSymbol..tkDed] + TTokTypes* = set[TTokTypeRange] - var - s: set[char] - a: TAZset - s = {'0'..'9'} - testSets(s) - doAssert 'F' in s - a = {} #{'a'..'z'} - for x in low(TAZ) .. high(TAZ): - incl(a, x) - doAssert x in a +const + toktypes: TTokTypes = {TTokTypeRange(tkSymbol)..pred(tkIntLit), + tkStrLit..tkTripleStrLit} + +var + s: set[char] + a: TAZset +s = {'0'..'9'} +testSets(s) +if 'F' in s: write(stdout, "Ha ein F ist in s!\n") +else: write(stdout, "BUG: F ist nicht in s!\n") +a = {} #{'a'..'z'} +for x in low(TAZ) .. high(TAZ): + incl(a, x) + if x in a: discard + else: write(stdout, "BUG: something not in a!\n") + +for x in low(TTokTypeRange) .. high(TTokTypeRange): + if x in tokTypes: + discard + #writeLine(stdout, "the token '$1' is in the set" % repr(x)) + +#OUT Ha ein F ist in s! - for x in low(FakeTokTypeRange) .. high(FakeTokTypeRange): - if x in tokTypes: - discard type - FakeMsgKind* = enum - k0, k1, k2, k3, k4, k5, k6, k7, k8, k9, k10, k11, k12, k13, k14, k15, k16, k17, k18, k19, k20, k21, k22, k23, k24, k25, k26, k27, k28, k29, k30, k31, k32, k33, k34, k35, k36, k37, k38, k39, k40, k41, k42, k43, k44, k45, k46, k47, k48, k49, k50, k51, k52, k53, k54, k55, k56, k57, k58, k59, k60, k61, k62, k63, k64, k65, k66, k67, k68, k69, k70, k71, k72, k73, k74, k75, k76, k77, k78, k79, k80, k81, k82, k83, k84, k85, k86, k87, k88, k89, k90, k91, k92, k93, k94, k95, k96, k97, k98, k99, k100, k101, k102, k103, k104, k105, k106, k107, k108, k109, k110, k111, k112, k113, k114, k115, k116, k117, k118, k119, k120, k121, k122, k123, k124, k125, k126, k127, k128, k129, k130, k131, k132, k133, k134, k135, k136, k137, k138, k139, k140, k141, k142, k143, k144, k145, k146, k147, k148, k149, k150, k151, k152, k153, k154, k155, k156, k157, k158, k159, k160, k161, k162, k163, k164, k165, k166, k167, k168, k169, k170, k171, k172, k173, k174, k175, k176, k177, k178, k179, k180, k181, k182, k183, k184, k185, k186, k187, k188, k189, k190, k191, k192, k193, k194, k195, k196, k197, k198, k199, k200, k201, k202, k203, k204, k205, k206, k207, k208, k209, k210, k211, k212, k213, k214, k215, k216, k217, k218, k219, k220, k221, k222, k223, k224, k225, k226, k227, k228, k229, k230, k231, k232, k233, k234, k235, k236, k237, k238, k239, k240, k241, k242, k243, k244, k245, k246, k247, k248, k249, k250, k251, k252, k253, k254, k255, k256, k257, k258, k259, k260, k261, k262, k263, k264, k265, k266, k267, k268, k269, k270, k271, k272, k273, k274, k275, + TMsgKind* = enum + errUnknown, errIllFormedAstX, errInternal, errCannotOpenFile, errGenerated, + errXCompilerDoesNotSupportCpp, errStringLiteralExpected, + errIntLiteralExpected, errInvalidCharacterConstant, + errClosingTripleQuoteExpected, errClosingQuoteExpected, + errTabulatorsAreNotAllowed, errInvalidToken, errLineTooLong, + errInvalidNumber, errNumberOutOfRange, errNnotAllowedInCharacter, + errClosingBracketExpected, errMissingFinalQuote, errIdentifierExpected, + errNewlineExpected, + errInvalidModuleName, + errOperatorExpected, errTokenExpected, errStringAfterIncludeExpected, + errRecursiveDependencyX, errOnOrOffExpected, errNoneSpeedOrSizeExpected, + errInvalidPragma, errUnknownPragma, errInvalidDirectiveX, + errAtPopWithoutPush, errEmptyAsm, errInvalidIndentation, + errExceptionExpected, errExceptionAlreadyHandled, + errYieldNotAllowedHere, errYieldNotAllowedInTryStmt, + errInvalidNumberOfYieldExpr, errCannotReturnExpr, errAttemptToRedefine, + errStmtInvalidAfterReturn, errStmtExpected, errInvalidLabel, + errInvalidCmdLineOption, errCmdLineArgExpected, errCmdLineNoArgExpected, + errInvalidVarSubstitution, errUnknownVar, errUnknownCcompiler, + errOnOrOffExpectedButXFound, errNoneBoehmRefcExpectedButXFound, + errNoneSpeedOrSizeExpectedButXFound, errGuiConsoleOrLibExpectedButXFound, + errUnknownOS, errUnknownCPU, errGenOutExpectedButXFound, + errArgsNeedRunOption, errInvalidMultipleAsgn, errColonOrEqualsExpected, + errExprExpected, errUndeclaredIdentifier, errUseQualifier, errTypeExpected, + errSystemNeeds, errExecutionOfProgramFailed, errNotOverloadable, + errInvalidArgForX, errStmtHasNoEffect, errXExpectsTypeOrValue, + errXExpectsArrayType, errIteratorCannotBeInstantiated, errExprXAmbiguous, + errConstantDivisionByZero, errOrdinalTypeExpected, + errOrdinalOrFloatTypeExpected, errOverOrUnderflow, + errCannotEvalXBecauseIncompletelyDefined, errChrExpectsRange0_255, + errDynlibRequiresExportc, errUndeclaredFieldX, errNilAccess, + errIndexOutOfBounds, errIndexTypesDoNotMatch, errBracketsInvalidForType, + errValueOutOfSetBounds, errFieldInitTwice, errFieldNotInit, + errExprXCannotBeCalled, errExprHasNoType, errExprXHasNoType, + errCastNotInSafeMode, errExprCannotBeCastedToX, errCommaOrParRiExpected, + errCurlyLeOrParLeExpected, errSectionExpected, errRangeExpected, + errMagicOnlyInSystem, errPowerOfTwoExpected, + errStringMayNotBeEmpty, errCallConvExpected, errProcOnlyOneCallConv, + errSymbolMustBeImported, errExprMustBeBool, errConstExprExpected, + errDuplicateCaseLabel, errRangeIsEmpty, errSelectorMustBeOfCertainTypes, + errSelectorMustBeOrdinal, errOrdXMustNotBeNegative, errLenXinvalid, + errWrongNumberOfVariables, errExprCannotBeRaised, errBreakOnlyInLoop, + errTypeXhasUnknownSize, errConstNeedsConstExpr, errConstNeedsValue, + errResultCannotBeOpenArray, errSizeTooBig, errSetTooBig, + errBaseTypeMustBeOrdinal, errInheritanceOnlyWithNonFinalObjects, + errInheritanceOnlyWithEnums, errIllegalRecursionInTypeX, + errCannotInstantiateX, errExprHasNoAddress, errXStackEscape, + errVarForOutParamNeeded, + errPureTypeMismatch, errTypeMismatch, errButExpected, errButExpectedX, + errAmbiguousCallXYZ, errWrongNumberOfArguments, + errXCannotBePassedToProcVar, + errXCannotBeInParamDecl, errPragmaOnlyInHeaderOfProc, errImplOfXNotAllowed, + errImplOfXexpected, errNoSymbolToBorrowFromFound, errDiscardValueX, + errInvalidDiscard, errIllegalConvFromXtoY, errCannotBindXTwice, + errInvalidOrderInArrayConstructor, + errInvalidOrderInEnumX, errEnumXHasHoles, errExceptExpected, errInvalidTry, + errOptionExpected, errXisNoLabel, errNotAllCasesCovered, + errUnknownSubstitionVar, errComplexStmtRequiresInd, errXisNotCallable, + errNoPragmasAllowedForX, errNoGenericParamsAllowedForX, + errInvalidParamKindX, errDefaultArgumentInvalid, errNamedParamHasToBeIdent, + errNoReturnTypeForX, errConvNeedsOneArg, errInvalidPragmaX, + errXNotAllowedHere, errInvalidControlFlowX, + errXisNoType, errCircumNeedsPointer, errInvalidExpression, + errInvalidExpressionX, errEnumHasNoValueX, errNamedExprExpected, + errNamedExprNotAllowed, errXExpectsOneTypeParam, + errArrayExpectsTwoTypeParams, errInvalidVisibilityX, errInitHereNotAllowed, + errXCannotBeAssignedTo, errIteratorNotAllowed, errXNeedsReturnType, + errNoReturnTypeDeclared, + errInvalidCommandX, errXOnlyAtModuleScope, + errXNeedsParamObjectType, + errTemplateInstantiationTooNested, errInstantiationFrom, + errInvalidIndexValueForTuple, errCommandExpectsFilename, + errMainModuleMustBeSpecified, + errXExpected, + errTIsNotAConcreteType, + errInvalidSectionStart, errGridTableNotImplemented, errGeneralParseError, + errNewSectionExpected, errWhitespaceExpected, errXisNoValidIndexFile, + errCannotRenderX, errVarVarTypeNotAllowed, errInstantiateXExplicitly, + errOnlyACallOpCanBeDelegator, errUsingNoSymbol, + errMacroBodyDependsOnGenericTypes, + errDestructorNotGenericEnough, + errInlineIteratorsAsProcParams, + errXExpectsTwoArguments, + errXExpectsObjectTypes, errXcanNeverBeOfThisSubtype, errTooManyIterations, + errCannotInterpretNodeX, errFieldXNotFound, errInvalidConversionFromTypeX, + errAssertionFailed, errCannotGenerateCodeForX, errXRequiresOneArgument, + errUnhandledExceptionX, errCyclicTree, errXisNoMacroOrTemplate, + errXhasSideEffects, errIteratorExpected, errLetNeedsInit, + errThreadvarCannotInit, errWrongSymbolX, errIllegalCaptureX, + errXCannotBeClosure, errXMustBeCompileTime, + errCannotInferTypeOfTheLiteral, + errCannotInferReturnType, + errGenericLambdaNotAllowed, + errCompilerDoesntSupportTarget, + errUser, + warnCannotOpenFile, + warnOctalEscape, warnXIsNeverRead, warnXmightNotBeenInit, + warnDeprecated, warnConfigDeprecated, + warnSmallLshouldNotBeUsed, warnUnknownMagic, warnRedefinitionOfLabel, + warnUnknownSubstitutionX, warnLanguageXNotSupported, + warnFieldXNotSupported, warnCommentXIgnored, + warnNilStatement, warnTypelessParam, + warnDifferentHeaps, warnWriteToForeignHeap, warnUnsafeCode, + warnEachIdentIsTuple, + warnProveInit, warnProveField, warnProveIndex, warnGcUnsafe, warnGcUnsafe2, + warnUninit, warnGcMem, warnDestructor, warnLockLevel, warnResultShadowed, + warnUser, + hintSuccess, hintSuccessX, + hintLineTooLong, hintXDeclaredButNotUsed, hintConvToBaseNotNeeded, + hintConvFromXtoItselfNotNeeded, hintExprAlwaysX, hintQuitCalled, + hintProcessing, hintCodeBegin, hintCodeEnd, hintConf, hintPath, + hintConditionAlwaysTrue, hintName, hintPattern, + hintUser -doAssert pred(k260) == k259 +const + fatalMin* = errUnknown + fatalMax* = errInternal + errMin* = errUnknown + errMax* = errUser + warnMin* = warnCannotOpenFile + warnMax* = pred(hintSuccess) + hintMin* = hintSuccess + hintMax* = high(TMsgKind) type - FakeMsgKind2 = range[k230..high(FakeMsgKind)] - FakeMsgKind3 = set[FakeMsgKind2] + TNoteKind* = range[warnMin..hintMax] # "notes" are warnings or hints + TNoteKinds* = set[TNoteKind] -var gNotes: FakeMsgKind3 = {low(FakeMsgKind2)..high(FakeMsgKind2)} - {k233, k235} +var + gNotes*: TNoteKinds = {low(TNoteKind)..high(TNoteKind)} - + {warnUninit, warnProveField, warnProveIndex, warnGcUnsafe} -doAssert k233 notin gNotes + +#import compiler.msgs + +echo warnUninit in gNotes # 7555 doAssert {-1.int8, -2, -2}.card == 2 @@ -68,24 +218,3 @@ type Foo = enum let x = { Foo1, Foo2 } # bug #8425 - -block: - # bug #2880 - type - FakeMsgKind = enum - k0, k1, k2, k3, k4, k5, k6, k7, k8, k9, k10, k11, k12, k13, k14, k15, k16, k17, k18, k19, k20, k21, k22, k23, k24, k25, k26, k27, k28, k29, k30, k31, k32, k33, k34, k35, k36, k37, k38, k39, k40, k41, k42, k43, k44, k45, k46, k47, k48, k49, k50, k51, k52, k53, k54, k55, k56, k57, k58, k59, k60, k61, k62, k63, k64, k65, k66, k67, k68, k69, k70, k71, k72, k73, k74, k75, k76, k77, k78, k79, k80, k81, k82, k83, k84, k85, k86, k87, k88, k89, k90, k91, k92, k93, k94, k95, k96, k97, k98, k99, k100 - - type - FakeMsgKind2 = range[FakeMsgKind.k50..high(FakeMsgKind)] - FakeMsgKind2s = set[FakeMsgKind2] - - const - a1: array[0..0, FakeMsgKind2s] = [{low(FakeMsgKind2)..high(FakeMsgKind2)} - {FakeMsgKind.k99}] - a2 = a1[0] - - var - s1: FakeMsgKind2s = a1[0] - s2: FakeMsgKind2s = a2 - - doAssert k99 notin s1 - doAssert k99 notin s2 diff --git a/tests/sets/tsets_various.nim b/tests/sets/tsets_various.nim index 419bcfdcc..8a63763b4 100644 --- a/tests/sets/tsets_various.nim +++ b/tests/sets/tsets_various.nim @@ -1,18 +1,15 @@ discard """ - targets: "c cpp js" + output: ''' +set is empty +''' """ -import std/[sets, hashes] -from std/sequtils import toSeq -from std/algorithm import sorted -from stdtest/testutils import whenVMorJs +import sets, hashes -proc sortedPairs[T](t: T): auto = toSeq(t.pairs).sorted -template sortedItems(t: untyped): untyped = sorted(toSeq(t)) block tsetpop: - var a = initHashSet[int]() + var a = initSet[int]() for i in 1..1000: a.incl(i) doAssert len(a) == 1000 @@ -20,12 +17,10 @@ block tsetpop: discard a.pop() doAssert len(a) == 0 - var msg = "" try: echo a.pop() except KeyError as e: - msg = e.msg - doAssert msg == "set is empty" + echo e.msg @@ -55,20 +50,20 @@ block tsets2: "80"] block tableTest1: - var t = initHashSet[tuple[x, y: int]]() + var t = initSet[tuple[x, y: int]]() t.incl((0,0)) t.incl((1,0)) - doAssert(not t.containsOrIncl((0,1))) + assert(not t.containsOrIncl((0,1))) t.incl((1,1)) for x in 0..1: for y in 0..1: - doAssert((x,y) in t) - #doAssert($t == + assert((x,y) in t) + #assert($t == # "{(x: 0, y: 0), (x: 0, y: 1), (x: 1, y: 0), (x: 1, y: 1)}") block setTest2: - var t = initHashSet[string]() + var t = initSet[string]() t.incl("test") t.incl("111") t.incl("123") @@ -76,40 +71,40 @@ block tsets2: t.incl("012") t.incl("123") # test duplicates - doAssert "123" in t - doAssert "111" notin t # deleted + assert "123" in t + assert "111" notin t # deleted - doAssert t.missingOrExcl("000") - doAssert "000" notin t - doAssert t.missingOrExcl("012") == false - doAssert "012" notin t + assert t.missingOrExcl("000") + assert "000" notin t + assert t.missingOrExcl("012") == false + assert "012" notin t - doAssert t.containsOrIncl("012") == false - doAssert t.containsOrIncl("012") - doAssert "012" in t # added back + assert t.containsOrIncl("012") == false + assert t.containsOrIncl("012") + assert "012" in t # added back for key in items(data): t.incl(key) - for key in items(data): doAssert key in t + for key in items(data): assert key in t for key in items(data): t.excl(key) - for key in items(data): doAssert key notin t + for key in items(data): assert key notin t block orderedSetTest1: var t = data.toOrderedSet - for key in items(data): doAssert key in t + for key in items(data): assert key in t var i = 0 # `items` needs to yield in insertion order: for key in items(t): - doAssert key == data[i] + assert key == data[i] inc(i) block tsets3: let - s1: HashSet[int] = toHashSet([1, 2, 4, 8, 16]) - s2: HashSet[int] = toHashSet([1, 2, 3, 5, 8]) - s3: HashSet[int] = toHashSet([3, 5, 7]) + s1: HashSet[int] = toSet([1, 2, 4, 8, 16]) + s2: HashSet[int] = toSet([1, 2, 3, 5, 8]) + s3: HashSet[int] = toSet([3, 5, 7]) block union: let @@ -117,22 +112,22 @@ block tsets3: s1_s3 = s1 + s3 s2_s3 = s2 + s3 - doAssert s1_s2.len == 7 - doAssert s1_s3.len == 8 - doAssert s2_s3.len == 6 + assert s1_s2.len == 7 + assert s1_s3.len == 8 + assert s2_s3.len == 6 for i in s1: - doAssert i in s1_s2 - doAssert i in s1_s3 + assert i in s1_s2 + assert i in s1_s3 for i in s2: - doAssert i in s1_s2 - doAssert i in s2_s3 + assert i in s1_s2 + assert i in s2_s3 for i in s3: - doAssert i in s1_s3 - doAssert i in s2_s3 + assert i in s1_s3 + assert i in s2_s3 - doAssert((s1 + s1) == s1) - doAssert((s2 + s1) == s1_s2) + assert((s1 + s1) == s1) + assert((s2 + s1) == s1_s2) block intersection: let @@ -140,22 +135,22 @@ block tsets3: s1_s3 = intersection(s1, s3) s2_s3 = s2 * s3 - doAssert s1_s2.len == 3 - doAssert s1_s3.len == 0 - doAssert s2_s3.len == 2 + assert s1_s2.len == 3 + assert s1_s3.len == 0 + assert s2_s3.len == 2 for i in s1_s2: - doAssert i in s1 - doAssert i in s2 + assert i in s1 + assert i in s2 for i in s1_s3: - doAssert i in s1 - doAssert i in s3 + assert i in s1 + assert i in s3 for i in s2_s3: - doAssert i in s2 - doAssert i in s3 + assert i in s2 + assert i in s3 - doAssert((s2 * s2) == s2) - doAssert((s3 * s2) == s2_s3) + assert((s2 * s2) == s2) + assert((s3 * s2) == s2_s3) block symmetricDifference: let @@ -163,22 +158,22 @@ block tsets3: s1_s3 = s1 -+- s3 s2_s3 = s2 -+- s3 - doAssert s1_s2.len == 4 - doAssert s1_s3.len == 8 - doAssert s2_s3.len == 4 + assert s1_s2.len == 4 + assert s1_s3.len == 8 + assert s2_s3.len == 4 for i in s1: - doAssert i in s1_s2 xor i in s2 - doAssert i in s1_s3 xor i in s3 + assert i in s1_s2 xor i in s2 + assert i in s1_s3 xor i in s3 for i in s2: - doAssert i in s1_s2 xor i in s1 - doAssert i in s2_s3 xor i in s3 + assert i in s1_s2 xor i in s1 + assert i in s2_s3 xor i in s3 for i in s3: - doAssert i in s1_s3 xor i in s1 - doAssert i in s2_s3 xor i in s2 + assert i in s1_s3 xor i in s1 + assert i in s2_s3 xor i in s2 - doAssert((s3 -+- s3) == initHashSet[int]()) - doAssert((s3 -+- s1) == s1_s3) + assert((s3 -+- s3) == initSet[int]()) + assert((s3 -+- s1) == s1_s3) block difference: let @@ -186,101 +181,20 @@ block tsets3: s1_s3 = difference(s1, s3) s2_s3 = s2 - s3 - doAssert s1_s2.len == 2 - doAssert s1_s3.len == 5 - doAssert s2_s3.len == 3 + assert s1_s2.len == 2 + assert s1_s3.len == 5 + assert s2_s3.len == 3 for i in s1: - doAssert i in s1_s2 xor i in s2 - doAssert i in s1_s3 xor i in s3 + assert i in s1_s2 xor i in s2 + assert i in s1_s3 xor i in s3 for i in s2: - doAssert i in s2_s3 xor i in s3 + assert i in s2_s3 xor i in s3 - doAssert((s2 - s2) == initHashSet[int]()) + assert((s2 - s2) == initSet[int]()) block disjoint: - doAssert(not disjoint(s1, s2)) - doAssert disjoint(s1, s3) - doAssert(not disjoint(s2, s3)) - doAssert(not disjoint(s2, s2)) - -block: # https://github.com/nim-lang/Nim/issues/13496 - template testDel(body) = - block: - body - t.incl(15) - t.incl(19) - t.incl(17) - t.incl(150) - t.excl(150) - doAssert t.len == 3 - doAssert sortedItems(t) == @[15, 17, 19] - var s = newSeq[int]() - for v in t: s.add(v) - doAssert s.len == 3 - doAssert sortedItems(s) == @[15, 17, 19] - when t is OrderedSet: - doAssert sortedPairs(t) == @[(a: 0, b: 15), (a: 1, b: 19), (a: 2, b: 17)] - doAssert toSeq(t) == @[15, 19, 17] - - testDel(): (var t: HashSet[int]) - testDel(): (var t: OrderedSet[int]) - -block: # test correctness after a number of inserts/deletes - template testDel(body) = - block: - body - var expected: seq[int] - let n = 100 - let n2 = n*2 - for i in 0..=n or i mod 3 != 0) and i mod 7 != 0: - expected.add i - - for i in expected: doAssert i in t - doAssert t.len == expected.len - doAssert sortedItems(t) == expected - - testDel(): (var t: HashSet[int]) - testDel(): (var t: OrderedSet[int]) - - -template main() = - # xxx move all tests inside this - block: - let a = {true, false} - doAssert $a == "{false, true}" - doAssert a.len == 2 - - block: - let a = {false .. true} - doAssert $a == "{false, true}" - doAssert a.len == 2 - - block: - let a = {false .. false} - doAssert $a == "{false}" - doAssert a.len == 1 - - block: # bug #16123 - whenVMorJs: discard - do: - type CallType = proc() {.closure.} - var setA = initHashSet[CallType]() - let foo = proc() = discard - setA.incl(foo) - doAssert setA.contains(foo) - -static: main() -main() + assert(not disjoint(s1, s2)) + assert disjoint(s1, s3) + assert(not disjoint(s2, s3)) + assert(not disjoint(s2, s2)) diff --git a/tests/showoff/tdrdobbs_examples.nim b/tests/showoff/tdrdobbs_examples.nim index c61e177dc..0e10c6dd8 100644 --- a/tests/showoff/tdrdobbs_examples.nim +++ b/tests/showoff/tdrdobbs_examples.nim @@ -40,12 +40,12 @@ const msb3999 = mostSignificantBit(3999) echo msb3999, " ", mostSignificantBit(0), " ", square(44) -proc filter[T](a: openArray[T], predicate: proc (x: T): bool): seq[T] = +proc filter[T](a: openarray[T], predicate: proc (x: T): bool): seq[T] = result = @[] # @[] constructs the empty seq for x in a: if predicate(x): result.add(x) -proc map[T, S](a: openArray[T], fn: proc (x: T): S): seq[S] = +proc map[T, S](a: openarray[T], fn: proc (x: T): S): seq[S] = newSeq(result, a.len) for i in 0 ..< a.len: result[i] = fn(a[i]) diff --git a/tests/showoff/tformatopt.nim b/tests/showoff/tformatopt.nim index 420dd026b..6e790c38e 100644 --- a/tests/showoff/tformatopt.nim +++ b/tests/showoff/tformatopt.nim @@ -37,7 +37,7 @@ macro optFormat{`%`(f, a)}(f: string{lit}, a: openArray[string]): untyped = result = newNimNode(nnkBracket) let f = f.strVal formatImpl(newLit) - result = nestList(newIdentNode("&"), result) + result = nestList(!"&", result) template optAdd1{x = y; add(x, z)}(x, y, z: string) = x = y & z diff --git a/tests/slice/tdistinct.nim b/tests/slice/tdistinct.nim deleted file mode 100644 index d99b529a7..000000000 --- a/tests/slice/tdistinct.nim +++ /dev/null @@ -1,2 +0,0 @@ -type Foo = distinct uint64 -const slice = 0 ..< 42.Foo diff --git a/tests/specialops/tcallops.nim b/tests/specialops/tcallops.nim deleted file mode 100644 index c541a0c1d..000000000 --- a/tests/specialops/tcallops.nim +++ /dev/null @@ -1,49 +0,0 @@ -import macros - -{.experimental: "callOperator".} - -type Foo[T: proc] = object - callback: T - -macro `()`(foo: Foo, args: varargs[untyped]): untyped = - result = newCall(newDotExpr(foo, ident"callback")) - for a in args: - result.add(a) - -var f1Calls = 0 -var f = Foo[proc()](callback: proc() = inc f1Calls) -doAssert f1Calls == 0 -f() -doAssert f1Calls == 1 -var f2Calls = 0 -f.callback = proc() = inc f2Calls -doAssert f2Calls == 0 -f() -doAssert f2Calls == 1 - -let g = Foo[proc (x: int): int](callback: proc (x: int): int = x * 2 + 1) -doAssert g(15) == 31 - -proc `()`(args: varargs[string]): string = - result = "(" - for a in args: result.add(a) - result.add(')') - -let a = "1" -let b = "2" -let c = "3" - -doAssert a(b) == "(12)" -doAssert a.b(c) == `()`(b, a, c) -doAssert (a.b)(c) == `()`(a.b, c) -doAssert `()`(a.b, c) == `()`(`()`(b, a), c) - -block: # bug #1072 - var x: int - - proc foo(some:int):int = some - proc `()`(l,r:string): string = discard - - block: - var foo = 42 - doAssert x.foo == 0 diff --git a/tests/specialops/tcallprecedence.nim b/tests/specialops/tcallprecedence.nim deleted file mode 100644 index 6116f83d5..000000000 --- a/tests/specialops/tcallprecedence.nim +++ /dev/null @@ -1,44 +0,0 @@ -import macros - -{.experimental: "dotOperators".} -{.experimental: "callOperator".} - -block: - template `.()`(foo: int, args: varargs[untyped]): untyped {.used.} = - ".()" - - template `()`(foo: int, args: varargs[untyped]): untyped = - "()" - - let a = (b: 1) - let c = 3 - - doAssert a.b(c) == "()" - doAssert not compiles(a(c)) - doAssert (a.b)(c) == "()" - -macro `()`(args: varargs[typed]): untyped = - result = newLit("() " & args.treeRepr) - -macro `.`(args: varargs[typed]): untyped = - result = newLit(". " & args.treeRepr) - -block: - let a = 1 - let b = 2 - doAssert a.b == `()`(b, a) - -block: - let a = 1 - proc b(): int {.used.} = 2 - doAssert a.b == `.`(a, b) - -block: - let a = 1 - proc b(x: int): int = x + 1 - let c = 3 - - doAssert a.b(c) == `.`(a, b, c) - doAssert a(b) == `()`(a, b) - doAssert (a.b)(c) == `()`(a.b, c) - doAssert a.b == b(a) diff --git a/tests/specialops/tdotops.nim b/tests/specialops/tdotops.nim index ca5eee665..227204f51 100644 --- a/tests/specialops/tdotops.nim +++ b/tests/specialops/tdotops.nim @@ -1,6 +1,5 @@ discard """ output: ''' - 10 assigning z = 20 reading field y @@ -13,18 +12,9 @@ no params call to b 100 one param call to c with 10 100 -0 4 -''' +0 4''' """ -block: - type Foo = object - var a: Foo - template `.`(a: Foo, b: untyped): untyped = astToStr(b) - template callme(a, f): untyped = a.f - doAssert callme(a, f2) == "f2" # not `f` - doAssert a.callme(f3) == "f3" - type T1 = object x*: int diff --git a/tests/specialops/terrmsgs.nim b/tests/specialops/terrmsgs.nim deleted file mode 100644 index d1a790e54..000000000 --- a/tests/specialops/terrmsgs.nim +++ /dev/null @@ -1,76 +0,0 @@ -discard """ -action: reject -cmd: '''nim check $options $file''' -matrix: "; -d:testWithout" -""" - -when not defined(testWithout): # test for same errors before and after - {.experimental: "dotOperators".} - {.experimental: "callOperator".} - -# issue #13063 - -block: - type Foo = object - type Bar = object - x1: int - var b: Bar - block: - template `.`(a: Foo, b: untyped): untyped = 123 - echo b.x #[tt.Error - ^ undeclared field: 'x' for type terrmsgs.Bar [type declared in terrmsgs.nim(15, 8)]]# - block: - template `.()`(a: Foo, b: untyped): untyped = 123 - echo b.x() #[tt.Error - ^ attempting to call undeclared routine: 'x']# - block: - template `.=`(a: Foo, b: untyped, c: untyped) = b = c - b.x = 123 #[tt.Error - ^ undeclared field: 'x=' for type terrmsgs.Bar [type declared in terrmsgs.nim(15, 8)]]# - # yeah it says x= but does it matter in practice - block: - template `()`(a: Foo, b: untyped, c: untyped) = echo "something" - - # completely undeclared:: - xyz(123) #[tt.Error - ^ undeclared identifier: 'xyz']# - - # already declared routine: - min(123) #[tt.Error - ^ type mismatch: got ]# - - # non-routine type shows `()` overloads: - b(123) #[tt.Error - ^ attempting to call routine: 'b']# - - echo b.x #[tt.Error - ^ undeclared field: 'x' for type terrmsgs.Bar [type declared in terrmsgs.nim(15, 8)]]# - echo b.x() #[tt.Error - ^ attempting to call undeclared routine: 'x']# - -# issue #7777 - -import macros - -block: - type TestType = object - private_field: string - - when false: - template getField(obj, field: untyped): untyped = obj.field - - macro `.`(obj: TestType, field: untyped): untyped = - let private = newIdentNode("private_" & $field) - result = quote do: - `obj`.getField(`private`) #[tt.Error - ^ attempting to call undeclared routine: 'getField']# - - var tt: TestType - discard tt.field - -block: # related to issue #6981 - proc `()`(a:string, b:string):string = a & b - proc mewSeq[T](a,b:int)=discard - proc mewSeq[T](c:int)= discard - mewSeq[int]() #[tt.Error - ^ type mismatch: got <>]# diff --git a/tests/specialops/tnewseq.nim b/tests/specialops/tnewseq.nim deleted file mode 100644 index 970a5a8c2..000000000 --- a/tests/specialops/tnewseq.nim +++ /dev/null @@ -1,22 +0,0 @@ -# issue #6981 - -import std/assertions - -{.experimental: "callOperator".} - -block: # issue #6981 - proc `()`(a:string, b:string):string = a & b - - var s = newSeq[int](3) - - doAssert s == @[0, 0, 0] - -block: # generalized example from #6981 - proc mewSeq[T](a: int)=discard - proc mewSeq[T]()= discard - mewSeq[int]() - -block: # issue #9831 - type Foo = object - proc `()`(foo: Foo) = discard - let x = newSeq[int]() diff --git a/tests/statictypes/t20148.nim b/tests/statictypes/t20148.nim deleted file mode 100644 index d74a7755e..000000000 --- a/tests/statictypes/t20148.nim +++ /dev/null @@ -1,8 +0,0 @@ -type Percent = range[0.0 .. 1.0] -# type Percent = float # using unlimited `float` works fine - -proc initColor*(alpha: Percent): bool = - echo alpha - -const moduleInstanceStyle = initColor(1) -# let moduleInstanceStyle = initColor(1) # using runtime conversion works fine diff --git a/tests/statictypes/t9255.nim b/tests/statictypes/t9255.nim index aec2fbaf5..86bc8c7f1 100644 --- a/tests/statictypes/t9255.nim +++ b/tests/statictypes/t9255.nim @@ -1,6 +1,6 @@ discard """ errormsg: ''' -type mismatch: got +type mismatch: got ''' line: 13 """ diff --git a/tests/statictypes/tpassthruarith.nim b/tests/statictypes/tpassthruarith.nim index 33e4e0303..857e5b0af 100644 --- a/tests/statictypes/tpassthruarith.nim +++ b/tests/statictypes/tpassthruarith.nim @@ -1,9 +1,13 @@ discard """ output: ''' [[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, 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] + [1, 2, 3, 4] ''' """ diff --git a/tests/statictypes/tstatic.nim b/tests/statictypes/tstatic.nim deleted file mode 100644 index aaa63534b..000000000 --- a/tests/statictypes/tstatic.nim +++ /dev/null @@ -1,56 +0,0 @@ -discard """ - targets: "c cpp js" -""" - -template main() = - block: # bug #17589 - #[ - # all those gave some variation of the same bug: - 'intVal' is not accessible using discriminant 'kind' of type 'TFullReg' - 'floatVal' is not accessible using discriminant 'kind' of type 'TFullReg' - ]# - block: - proc f(a: static uint64): uint64 = - a - const x = 3'u64 - static: doAssert f(x) == 3'u64 - doAssert f(x) == 3'u64 - - block: - proc f(a: static uint64): uint64 = - a - const x = 3'u64 - static: doAssert f(x) == 3'u64 - doAssert f(x) == 3'u64 - - block: - proc foo(x: uint8): uint8 = x - proc f(a: static uint8): auto = foo(a) - const x = 3'u8 - static: doAssert f(x) == 3'u8 - doAssert f(x) == 3'u8 - - block: - template foo2(x: float) = - let b = x == 0 - proc foo(x: float) = foo2(x) - proc f(a: static float) = foo(a) - const x = 1.0 - static: f(x) - - block: - proc foo(x: int32) = - let b = x == 0 - proc f(a: static int32) = foo(a) - static: f(32767) # was working - static: f(32768) # was failing because >= int16.high (see isInt16Lit) - - block: # bug #14585 - const foo_m0ninv = 0x1234'u64 - proc foo(m0ninv: static uint64) = - let b = $m0ninv - static: - foo(foo_m0ninv) - -static: main() -main() diff --git a/tests/statictypes/tstaticimportcpp.nim b/tests/statictypes/tstaticimportcpp.nim index ec4696379..125dcb98d 100644 --- a/tests/statictypes/tstaticimportcpp.nim +++ b/tests/statictypes/tstaticimportcpp.nim @@ -23,12 +23,12 @@ struct SimpleStruct { """ .} type - GenericIntType[N: static[int]; T] {.importcpp: "GenericIntType<'0, '1>".} = object + GenericIntType {.importcpp: "GenericIntType<'0, '1>".} [N: static[int]; T] = object data: array[N, T] - GenericIntTypeAlt[N: static[int]; T] {.importcpp: "GenericIntType".} = object + GenericIntTypeAlt {.importcpp: "GenericIntType".} [N: static[int]; T] = object - GenericTType[T] {.importcpp: "GenericTType<'0>".} = object + GenericTType {.importcpp: "GenericTType<'0>".} [T] = object field: T GenInt4 = GenericIntType[4, int] diff --git a/tests/statictypes/tstatictypes.nim b/tests/statictypes/tstatictypes.nim index 5df3f35fd..c95e499d7 100644 --- a/tests/statictypes/tstatictypes.nim +++ b/tests/statictypes/tstatictypes.nim @@ -1,16 +1,7 @@ discard """ -nimoutFull: true nimout: ''' staticAlialProc instantiated with 358 staticAlialProc instantiated with 368 -0: Foo -1: Bar -0: Foo -1: Bar -0: Foo -1: Bar -0: Foo -1: Bar ''' output: ''' 16 @@ -18,23 +9,19 @@ output: ''' b is 2 times a 17 ['\x00', '\x00', '\x00', '\x00'] -heyho -Val1 -Val1 ''' -matrix: "--hints:off" """ import macros -template ok(x) = doAssert(x) -template no(x) = doAssert(not x) +template ok(x) = assert(x) +template no(x) = assert(not x) template accept(x) = - static: doAssert(compiles(x)) + static: assert(compiles(x)) template reject(x) = - static: doAssert(not compiles(x)) + static: assert(not compiles(x)) proc plus(a, b: int): int = a + b @@ -64,8 +51,8 @@ when true: b: static[int], c: static int) = static: - doAssert a.isStatic and b.isStatic and c.isStatic - doAssert isStatic(a + plus(b, c)) + assert a.isStatic and b.isStatic and c.isStatic + assert isStatic(a + plus(b, c)) echo "staticAlialProc instantiated with ", a, b, c when b mod a == 0: @@ -101,10 +88,6 @@ when true: reject: var x = static(v) -block: # issue #13730 - type Foo[T: static[float]] = object - doAssert Foo[0.0] is Foo[-0.0] - when true: type ArrayWrapper1[S: static int] = object @@ -121,9 +104,9 @@ when true: var aw3: ArrayWrapper3[(10, "str")] static: - doAssert aw1.data.high == 5 - doAssert aw2.data.high == 6 - doAssert aw3.data.high == 9 + assert aw1.data.high == 5 + assert aw2.data.high == 6 + assert aw3.data.high == 9 # #6077 block: @@ -183,211 +166,3 @@ var s: StringValue16 echo s - -block: #13529 - block: - type Foo[T: static type] = object - var foo: Foo["test"] - doAssert $foo == "()" - doAssert foo.T is string - static: doAssert foo.T == "test" - doAssert not compiles( - block: - type Foo2[T: static type] = object - x: T) - - block: - type Foo[T: static[float]] = object - var foo: Foo[1.2] - doAssert $foo == "()" - doAssert foo.T == 1.2 - - block: # routines also work - proc fun(a: static) = (const a2 = a) - fun(1) - fun(1.2) - block: # routines also work - proc fun(a: static type) = (const a2 = a) - fun(1) - fun(1.2) - - block: # this also works - proc fun[T](a: static[T]) = (const a2 = a) - fun(1) - fun(1.2) - -block: # #12713 - block: - type Cell = object - c: int - proc test(c: static string) = discard #Remove this and it compiles - proc test(c: Cell) = discard - test Cell(c: 0) - block: - type Cell = object - c: int - proc test(c: static string) = discard #Remove this and it compiles - proc test(c: Cell) = discard - test Cell() - -block: # issue #14802 - template fn(s: typed): untyped = - proc bar() = discard - 12 - const myConst = static(fn(1)) - doAssert myConst == 12 - - -# bug #12571 -type - T[K: static bool] = object of RootObj - when K == true: - foo: string - else: - bar: string - U[K: static bool] = object of T[K] - -let t = T[true](foo: "hey") -let u = U[false](bar: "ho") -echo t.foo, u.bar - - -#------------------------------------------------------------------------------ -# issue #9679 - -type - Foo*[T] = object - bar*: int - dummy: T - -proc initFoo(T: type, bar: int): Foo[T] = - result.bar = 1 - -proc fails[T](x: static Foo[T]) = # Change to non-static and it compiles - doAssert($x == "(bar: 1, dummy: 0)") - -block: - const foo = initFoo(int, 2) - fails(foo) - - -import tables - -var foo{.compileTime.} = [ - "Foo", - "Bar" -] - -var bar{.compileTime.} = { - 0: "Foo", - 1: "Bar" -}.toTable() - -macro fooM(): untyped = - for i, val in foo: - echo i, ": ", val - -macro barM(): untyped = - for i, val in bar: - echo i, ": ", val - -macro fooParam(x: static array[2, string]): untyped = - for i, val in x: - echo i, ": ", val - -macro barParam(x: static Table[int, string]): untyped = - let barParamInsides = proc(i: int, val: string): NimNode = - echo i, ": ", val - for i, val in x: - discard barParamInsides(i, val) - -fooM() -barM() -fooParam(foo) -barParam(bar) - - -#----------------------------------------------------------------------------------------- -# issue #7546 -type - rangeB[N: static[int16]] = range[0'i16 .. N] - setB[N: static[int16]] = set[rangeB[N]] - -block: - var s : setB[14'i16] - - -#----------------------------------------------------------------------------------------- -# issue #9520 - -type - MyEnum = enum - Val1, Val2 - -proc myproc(a: static[MyEnum], b: int) = - if b < 0: - myproc(a, -b) - - echo $a - -myproc(Val1, -10) - - -#------------------------------------------------------------------------------------------ -# issue #6177 - -type - G[N,M:static[int], T] = object - o: T - -proc newG[N,M:static[int],T](x:var G[N,M,T], y:T) = - x.o = y+10*N+100*M - -proc newG[N,M:static[int],T](x:T):G[N,M,T] = result.newG(x) - -var x:G[2,3,int] -x.newG(4) -var y = newG[2,3,int](4) - - -#------------------------------------------------------------------------------------------ -# issue #12897 - -type - TileCT[n: static int] = object - a: array[n, int] - Tile = TileCT #Commenting this out to make it work - - -#------------------------------------------------------------------------------------------ -# issue #15858 - -proc fn(N1: static int, N2: static int, T: typedesc): array[N1 * N2, T] = - doAssert(len(result) == N1 * N2) - -let yy = fn(5, 10, float) - - -block: - block: - type Foo[N: static int] = array[cint(0) .. cint(N), float] - type T = Foo[3] - block: - type Foo[N: static int] = array[int32(0) .. int32(N), float] - type T = Foo[3] - - -#------------------------------------------------------------------------------------------ -# static proc/lambda param -func isSorted2[T](a: openArray[T], cmp: static proc(x, y: T): bool {.inline.}): bool = - result = true - for i in 0.. 0: - main1(n-1) - -proc main2(n: int) = - count.inc - setFrameMsg $("main2", n, count) - proc bar() = - setFrameMsg $("bar ",) - if n < 3: raise newException(CatchableError, "on purpose") - bar() - main2(n-1) - -proc main() = - var z = 0 - setFrameMsg "\n z: " & $z, prefix = "" - # multiple calls inside a frame are possible - z.inc - setFrameMsg "\n z: " & $z, prefix = "" - try: - main2(5) - except CatchableError: - main1(10) # goes deep and then unwinds; sanity check to ensure `setFrameMsg` from inside - # `main1` won't invalidate the stacktrace; if StackTraceEntry.frameMsg - # were a reference instead of a copy, this would fail. - let e = getCurrentException() - let trace = e.getStackTrace - echo trace - -main() diff --git a/tests/stdlib/nre/captures.nim b/tests/stdlib/nre/captures.nim index acc141baf..bd5e83ecc 100644 --- a/tests/stdlib/nre/captures.nim +++ b/tests/stdlib/nre/captures.nim @@ -1,12 +1,12 @@ import unittest, optional_nonstrict include nre -block: # captures - block: # map capture names to numbers +suite "captures": + test "map capture names to numbers": check(getNameToNumberTable(re("(?1(?2(?3))(?'v4'4))()")) == { "v1" : 0, "v2" : 1, "v3" : 2, "v4" : 3 }.toTable()) - block: # capture bounds are correct + test "capture bounds are correct": let ex1 = re("([0-9])") check("1 23".find(ex1).matchBounds == 0 .. 0) check("1 23".find(ex1).captureBounds[0] == 0 .. 0) @@ -20,7 +20,7 @@ block: # captures let ex3 = re("([0-9]+)") check("824".find(ex3).captureBounds[0] == 0 .. 2) - block: # named captures + test "named captures": let ex1 = "foobar".find(re("(?foo)(?bar)")) check(ex1.captures["foo"] == "foo") check(ex1.captures["bar"] == "bar") @@ -32,7 +32,7 @@ block: # captures expect KeyError: discard ex2.captures["bar"] - block: # named capture bounds + test "named capture bounds": let ex1 = "foo".find(re("(?foo)(?bar)?")) check("foo" in ex1.captureBounds) check(ex1.captureBounds["foo"] == 0..2) @@ -40,12 +40,12 @@ block: # captures expect KeyError: discard ex1.captures["bar"] - block: # capture count + test "capture count": let ex1 = re("(?foo)(?bar)?") check(ex1.captureCount == 2) check(ex1.captureNameId == {"foo" : 0, "bar" : 1}.toTable()) - block: # named capture table + test "named capture table": let ex1 = "foo".find(re("(?foo)(?bar)?")) check(ex1.captures.toTable == {"foo" : "foo"}.toTable()) check(ex1.captureBounds.toTable == {"foo" : 0..2}.toTable()) @@ -53,7 +53,7 @@ block: # captures let ex2 = "foobar".find(re("(?foo)(?bar)?")) check(ex2.captures.toTable == {"foo" : "foo", "bar" : "bar"}.toTable()) - block: # capture sequence + test "capture sequence": let ex1 = "foo".find(re("(?foo)(?bar)?")) check(ex1.captures.toSeq == @[some("foo"), none(string)]) check(ex1.captureBounds.toSeq == @[some(0..2), none(Slice[int])]) diff --git a/tests/stdlib/nre/escape.nim b/tests/stdlib/nre/escape.nim index 5e7dc0c0e..db5e8a001 100644 --- a/tests/stdlib/nre/escape.nim +++ b/tests/stdlib/nre/escape.nim @@ -1,7 +1,7 @@ import nre, unittest -block: # escape strings - block: # escape strings +suite "escape strings": + test "escape strings": check("123".escapeRe() == "123") check("[]".escapeRe() == r"\[\]") check("()".escapeRe() == r"\(\)") diff --git a/tests/stdlib/nre/find.nim b/tests/stdlib/nre/find.nim index 7e7555d73..caa953ff4 100644 --- a/tests/stdlib/nre/find.nim +++ b/tests/stdlib/nre/find.nim @@ -3,23 +3,23 @@ import nre except toSeq import optional_nonstrict import times, strutils -block: # find - block: # find text +suite "find": + test "find text": check("3213a".find(re"[a-z]").match == "a") check(toSeq(findIter("1 2 3 4 5 6 7 8 ", re" ")).map( proc (a: RegexMatch): string = a.match ) == @[" ", " ", " ", " ", " ", " ", " ", " "]) - block: # find bounds + test "find bounds": check(toSeq(findIter("1 2 3 4 5 ", re" ")).map( proc (a: RegexMatch): Slice[int] = a.matchBounds ) == @[1..1, 3..3, 5..5, 7..7, 9..9]) - block: # overlapping find + test "overlapping find": check("222".findAll(re"22") == @["22"]) check("2222".findAll(re"22") == @["22", "22"]) - block: # len 0 find + test "len 0 find": check("".findAll(re"\ ") == newSeq[string]()) check("".findAll(re"") == @[""]) check("abc".findAll(re"") == @["", "", "", ""]) @@ -27,7 +27,7 @@ block: # find check("word\r\lword".findAll(re"(*ANYCRLF)(?m)$") == @["", ""]) check("слово слово".findAll(re"(*U)\b") == @["", "", "", ""]) - block: # bail early + test "bail early": ## we expect nothing to be found and we should be bailing out early which means that ## the timing difference between searching in small and large data should be well ## within a tolerance margin diff --git a/tests/stdlib/nre/init.nim b/tests/stdlib/nre/init.nim index f0c8e0a00..26e668104 100644 --- a/tests/stdlib/nre/init.nim +++ b/tests/stdlib/nre/init.nim @@ -1,12 +1,12 @@ import unittest include nre -block: # Test NRE initialization - block: # correct initialization +suite "Test NRE initialization": + test "correct initialization": check(re("[0-9]+") != nil) check(re("(?i)[0-9]+") != nil) - block: # options + test "options": check(extractOptions("(*NEVER_UTF)") == ("", pcre.NEVER_UTF, true)) check(extractOptions("(*UTF8)(*ANCHORED)(*UCP)z") == @@ -19,14 +19,14 @@ block: # Test NRE initialization check(extractOptions("(*LIMIT_MATCH=6)(*ANCHORED)z") == ("(*LIMIT_MATCH=6)z", pcre.ANCHORED, true)) - block: # incorrect options + test "incorrect options": for s in ["CR", "(CR", "(*CR", "(*abc)", "(*abc)CR", "(?i)", "(*LIMIT_MATCH=5", "(*NO_AUTO_POSSESS=5)"]: let ss = s & "(*NEVER_UTF)" check(extractOptions(ss) == (ss, 0, true)) - block: # invalid regex + test "invalid regex": expect(SyntaxError): discard re("[0-9") try: discard re("[0-9") diff --git a/tests/stdlib/nre/match.nim b/tests/stdlib/nre/match.nim index 7e09a4b2f..06b69fd04 100644 --- a/tests/stdlib/nre/match.nim +++ b/tests/stdlib/nre/match.nim @@ -1,12 +1,12 @@ include nre, unittest, optional_nonstrict -block: # match - block: # upper bound must be inclusive +suite "match": + test "upper bound must be inclusive": check("abc".match(re"abc", endpos = -1) == none(RegexMatch)) check("abc".match(re"abc", endpos = 1) == none(RegexMatch)) check("abc".match(re"abc", endpos = 2) != none(RegexMatch)) - block: # match examples + test "match examples": check("abc".match(re"(\w)").captures[0] == "a") check("abc".match(re"(?\w)").captures["letter"] == "a") check("abc".match(re"(\w)\w").captures[-1] == "ab") @@ -14,5 +14,5 @@ block: # match check("abc".match(re"").captureBounds[-1] == 0 .. -1) check("abc".match(re"abc").captureBounds[-1] == 0 .. 2) - block: # match test cases + test "match test cases": check("123".match(re"").matchBounds == 0 .. -1) diff --git a/tests/stdlib/nre/misc.nim b/tests/stdlib/nre/misc.nim index b7df08ee9..f4a88b639 100644 --- a/tests/stdlib/nre/misc.nim +++ b/tests/stdlib/nre/misc.nim @@ -1,13 +1,13 @@ import unittest, nre, strutils, optional_nonstrict -block: # Misc tests - block: # unicode +suite "Misc tests": + test "unicode": check("".find(re"(*UTF8)").match == "") check("перевірка".replace(re"(*U)\w", "") == "") - block: # empty or non-empty match - check("abc".findAll(re"|.").join(":") == ":a::b::c:") - check("abc".findAll(re".|").join(":") == "a:b:c:") + test "empty or non-empty match": + check("abc".findall(re"|.").join(":") == ":a::b::c:") + check("abc".findall(re".|").join(":") == "a:b:c:") check("abc".replace(re"|.", "x") == "xxxxxxx") check("abc".replace(re".|", "x") == "xxxx") diff --git a/tests/stdlib/nre/replace.nim b/tests/stdlib/nre/replace.nim index 5cf659f21..812a7f384 100644 --- a/tests/stdlib/nre/replace.nim +++ b/tests/stdlib/nre/replace.nim @@ -1,13 +1,13 @@ include nre import unittest -block: # replace - block: # replace with 0-length strings +suite "replace": + test "replace with 0-length strings": check("".replace(re"1", proc (v: RegexMatch): string = "1") == "") check(" ".replace(re"", proc (v: RegexMatch): string = "1") == "1 1") check("".replace(re"", proc (v: RegexMatch): string = "1") == "1") - block: # regular replace + test "regular replace": check("123".replace(re"\d", "foo") == "foofoofoo") check("123".replace(re"(\d)", "$1$1") == "112233") check("123".replace(re"(\d)(\d)", "$1$2") == "123") @@ -15,8 +15,8 @@ block: # replace check("123".replace(re"(?\d)(\d)", "$foo$#$#") == "1123") check("123".replace(re"(?\d)(\d)", "${foo}$#$#") == "1123") - block: # replacing missing captures should throw instead of segfaulting - expect IndexDefect: discard "ab".replace(re"(a)|(b)", "$1$2") - expect IndexDefect: discard "b".replace(re"(a)?(b)", "$1$2") + test "replacing missing captures should throw instead of segfaulting": + expect IndexError: discard "ab".replace(re"(a)|(b)", "$1$2") + expect IndexError: discard "b".replace(re"(a)?(b)", "$1$2") expect KeyError: discard "b".replace(re"(a)?", "${foo}") expect KeyError: discard "b".replace(re"(?a)?", "${foo}") diff --git a/tests/stdlib/nre/split.nim b/tests/stdlib/nre/split.nim index 3cd57bb82..9d57ea7d8 100644 --- a/tests/stdlib/nre/split.nim +++ b/tests/stdlib/nre/split.nim @@ -1,8 +1,8 @@ import unittest, strutils include nre -block: # string splitting - block: # splitting strings +suite "string splitting": + test "splitting strings": check("1 2 3 4 5 6 ".split(re" ") == @["1", "2", "3", "4", "5", "6", ""]) check("1 2 ".split(re(" ")) == @["1", "", "2", "", ""]) check("1 2".split(re(" ")) == @["1", "2"]) @@ -10,22 +10,22 @@ block: # string splitting check("".split(re"foo") == @[""]) check("9".split(re"\son\s") == @["9"]) - block: # captured patterns + test "captured patterns": check("12".split(re"(\d)") == @["", "1", "", "2", ""]) - block: # maxsplit + test "maxsplit": check("123".split(re"", maxsplit = 2) == @["1", "23"]) check("123".split(re"", maxsplit = 1) == @["123"]) check("123".split(re"", maxsplit = -1) == @["1", "2", "3"]) - block: # split with 0-length match + test "split with 0-length match": check("12345".split(re("")) == @["1", "2", "3", "4", "5"]) check("".split(re"") == newSeq[string]()) check("word word".split(re"\b") == @["word", " ", "word"]) check("word\r\lword".split(re"(*ANYCRLF)(?m)$") == @["word", "\r\lword"]) check("слово слово".split(re"(*U)(\b)") == @["", "слово", "", " ", "", "слово", ""]) - block: # perl split tests + test "perl split tests": check("forty-two" .split(re"") .join(",") == "f,o,r,t,y,-,t,w,o") check("forty-two" .split(re"", 3) .join(",") == "f,o,rty-two") check("split this string" .split(re" ") .join(",") == "split,this,string") @@ -47,7 +47,7 @@ block: # string splitting check("" .split(re"") .len == 0) check(":" .split(re"") .len == 1) - block: # start position + test "start position": check("abc".split(re"", start = 1) == @["b", "c"]) check("abc".split(re"", start = 2) == @["c"]) check("abc".split(re"", start = 3) == newSeq[string]()) diff --git a/tests/stdlib/t10231.nim b/tests/stdlib/t10231.nim index 3d09721aa..2bb64b475 100644 --- a/tests/stdlib/t10231.nim +++ b/tests/stdlib/t10231.nim @@ -1,11 +1,10 @@ discard """ - targets: "cpp" + target: cpp action: run exitcode: 0 """ import os -import std/assertions # consider moving this inside tosproc (taking care that it's for cpp mode) diff --git a/tests/stdlib/t14139.nim b/tests/stdlib/t14139.nim deleted file mode 100644 index 866bdb45f..000000000 --- a/tests/stdlib/t14139.nim +++ /dev/null @@ -1,10 +0,0 @@ -import std/heapqueue -import std/assertions - -var test_queue : HeapQueue[int] - -test_queue.push(7) -test_queue.push(3) -test_queue.push(9) -let i = test_queue.pushpop(10) -doAssert i == 3 diff --git a/tests/stdlib/t15663.nim b/tests/stdlib/t15663.nim deleted file mode 100644 index 8e8bfd9a8..000000000 --- a/tests/stdlib/t15663.nim +++ /dev/null @@ -1,9 +0,0 @@ -discard """ - cmd: "nim c --gc:arc $file" - output: "Test" -""" - -import std/widestrs - -let ws = newWideCString("Test") -echo ws diff --git a/tests/stdlib/t21406.nim b/tests/stdlib/t21406.nim deleted file mode 100644 index 5b96227ce..000000000 --- a/tests/stdlib/t21406.nim +++ /dev/null @@ -1,5 +0,0 @@ -import std/[times, strformat] -import std/assertions - -doAssert fmt"{getTime()}" == $getTime() -doAssert fmt"{now()}" == $now() diff --git a/tests/stdlib/t7686.nim b/tests/stdlib/t7686.nim deleted file mode 100644 index 9902cfcb5..000000000 --- a/tests/stdlib/t7686.nim +++ /dev/null @@ -1,10 +0,0 @@ -import std/strutils -import std/assertions - -type - MyEnum = enum - A, - a - -doAssert parseEnum[MyEnum]("A") == A -doAssert parseEnum[MyEnum]("a") == a diff --git a/tests/stdlib/t8925.nim b/tests/stdlib/t8925.nim index c55e93e73..dbf55fd88 100644 --- a/tests/stdlib/t8925.nim +++ b/tests/stdlib/t8925.nim @@ -1,5 +1,5 @@ discard """ - errormsg: "type mismatch between pattern '$$i' (position: 1) and HourRange var 'hour'" + errormsg: "type mismatch between pattern '$i' (position: 1) and HourRange var 'hour'" file: "strscans.nim" """ diff --git a/tests/stdlib/t9754.nim b/tests/stdlib/t9754.nim deleted file mode 100644 index 971b5a8fb..000000000 --- a/tests/stdlib/t9754.nim +++ /dev/null @@ -1,6 +0,0 @@ -discard """ - joinable: false -""" - -import tmarshal -import tparsesql \ No newline at end of file diff --git a/tests/stdlib/talgorithm.nim b/tests/stdlib/talgorithm.nim deleted file mode 100644 index 83a84f956..000000000 --- a/tests/stdlib/talgorithm.nim +++ /dev/null @@ -1,274 +0,0 @@ -discard """ - targets: "c js" - output:'''@["3", "2", "1"] -''' -""" -#12928,10456 - -import std/[sequtils, algorithm, json, sugar] -import std/assertions - -proc test() = - try: - let info = parseJson(""" - {"a": ["1", "2", "3"]} - """) - let prefixes = info["a"].getElems().mapIt(it.getStr()).sortedByIt(it).reversed() - echo prefixes - except: - discard - -test() - -block: - # Tests for lowerBound - var arr = @[1, 2, 3, 5, 6, 7, 8, 9] - doAssert arr.lowerBound(0) == 0 - doAssert arr.lowerBound(4) == 3 - doAssert arr.lowerBound(5) == 3 - doAssert arr.lowerBound(10) == 8 - arr = @[1, 5, 10] - doAssert arr.lowerBound(4) == 1 - doAssert arr.lowerBound(5) == 1 - doAssert arr.lowerBound(6) == 2 - # Tests for isSorted - var srt1 = [1, 2, 3, 4, 4, 4, 4, 5] - var srt2 = ["iello", "hello"] - var srt3 = [1.0, 1.0, 1.0] - var srt4: seq[int] - doAssert srt1.isSorted(cmp) == true - doAssert srt2.isSorted(cmp) == false - doAssert srt3.isSorted(cmp) == true - doAssert srt4.isSorted(cmp) == true - var srtseq = newSeq[int]() - doAssert srtseq.isSorted(cmp) == true - # Tests for reversed - var arr1 = @[0, 1, 2, 3, 4] - doAssert arr1.reversed() == @[4, 3, 2, 1, 0] - for i in 0 .. high(arr1): - doAssert arr1.reversed(0, i) == arr1.reversed()[high(arr1) - i .. high(arr1)] - doAssert arr1.reversed(i, high(arr1)) == arr1.reversed()[0 .. high(arr1) - i] - -block: - var list = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] - let list2 = list.rotatedLeft(1 ..< 9, 3) - let expected = [0, 4, 5, 6, 7, 8, 1, 2, 3, 9, 10] - - doAssert list.rotateLeft(1 ..< 9, 3) == 6 - doAssert list == expected - doAssert list2 == @expected - - var s0, s1, s2, s3, s4, s5 = "xxxabcdefgxxx" - - doAssert s0.rotateLeft(3 ..< 10, 3) == 7 - doAssert s0 == "xxxdefgabcxxx" - doAssert s1.rotateLeft(3 ..< 10, 2) == 8 - doAssert s1 == "xxxcdefgabxxx" - doAssert s2.rotateLeft(3 ..< 10, 4) == 6 - doAssert s2 == "xxxefgabcdxxx" - doAssert s3.rotateLeft(3 ..< 10, -3) == 6 - doAssert s3 == "xxxefgabcdxxx" - doAssert s4.rotateLeft(3 ..< 10, -10) == 6 - doAssert s4 == "xxxefgabcdxxx" - doAssert s5.rotateLeft(3 ..< 10, 11) == 6 - doAssert s5 == "xxxefgabcdxxx" - - block product: - doAssert product(newSeq[seq[int]]()) == newSeq[seq[int]](), "empty input" - doAssert product(@[newSeq[int](), @[], @[]]) == newSeq[seq[int]](), "bit more empty input" - doAssert product(@[@[1, 2]]) == @[@[1, 2]], "a simple case of one element" - doAssert product(@[@[1, 2], @[3, 4]]) == @[@[2, 4], @[1, 4], @[2, 3], @[1, - 3]], "two elements" - doAssert product(@[@[1, 2], @[3, 4], @[5, 6]]) == @[@[2, 4, 6], @[1, 4, 6], - @[2, 3, 6], @[1, 3, 6], @[2, 4, 5], @[1, 4, 5], @[2, 3, 5], @[1, 3, 5]], "three elements" - doAssert product(@[@[1, 2], @[]]) == newSeq[seq[int]](), "two elements, but one empty" - - block lowerBound: - doAssert lowerBound([1, 2, 4], 3, system.cmp[int]) == 2 - doAssert lowerBound([1, 2, 2, 3], 4, system.cmp[int]) == 4 - doAssert lowerBound([1, 2, 3, 10], 11) == 4 - - block upperBound: - doAssert upperBound([1, 2, 4], 3, system.cmp[int]) == 2 - doAssert upperBound([1, 2, 2, 3], 3, system.cmp[int]) == 4 - doAssert upperBound([1, 2, 3, 5], 3) == 3 - - block fillEmptySeq: - var s = newSeq[int]() - s.fill(0) - - block testBinarySearch: - var noData: seq[int] - doAssert binarySearch(noData, 7) == -1 - let oneData = @[1] - doAssert binarySearch(oneData, 1) == 0 - doAssert binarySearch(oneData, 7) == -1 - let someData = @[1, 3, 4, 7] - doAssert binarySearch(someData, 1) == 0 - doAssert binarySearch(someData, 7) == 3 - doAssert binarySearch(someData, -1) == -1 - doAssert binarySearch(someData, 5) == -1 - doAssert binarySearch(someData, 13) == -1 - let moreData = @[1, 3, 5, 7, 4711] - doAssert binarySearch(moreData, -1) == -1 - doAssert binarySearch(moreData, 1) == 0 - doAssert binarySearch(moreData, 5) == 2 - doAssert binarySearch(moreData, 6) == -1 - doAssert binarySearch(moreData, 4711) == 4 - doAssert binarySearch(moreData, 4712) == -1 - -# merge -proc main() = - block: - var x = @[1, 7, 8, 11, 21, 33, 45, 99] - var y = @[6, 7, 9, 12, 57, 66] - - var merged: seq[int] - merged.merge(x, y) - doAssert merged.isSorted - doAssert merged == sorted(x & y) - - block: - var x = @[111, 88, 76, 56, 45, 31, 22, 19, 11, 3] - var y = @[99, 85, 83, 82, 69, 64, 48, 42, 33, 31, 26, 13] - - var merged: seq[int] - merged.merge(x, y, (x, y) => -system.cmp(x, y)) - doAssert merged.isSorted((x, y) => -system.cmp(x, y)) - doAssert merged == sorted(x & y, SortOrder.Descending) - - block: - var x: seq[int] = @[] - var y = @[1] - - var merged: seq[int] - merged.merge(x, y) - doAssert merged.isSorted - doAssert merged.isSorted(SortOrder.Descending) - doAssert merged == @[1] - - block: - var x = [1, 3, 5, 5, 7] - var y: seq[int] = @[] - - var merged: seq[int] - merged.merge(x, y) - doAssert merged.isSorted - doAssert merged == @x - - block: - var x = [1, 3, 5, 5, 7] - var y: seq[int] = @[] - - var merged: seq[int] = @[1, 2, 3, 5, 6, 56, 99, 2, 34] - merged.merge(x, y) - doAssert merged == @[1, 2, 3, 5, 6, 56, 99, 2, 34, 1, 3, 5, 5, 7] - - - block: - var x: array[0, int] - var y = [1, 4, 6, 7, 9] - - var merged: seq[int] - merged.merge(x, y) - doAssert merged.isSorted - doAssert merged == @y - - block: - var x: array[0, int] - var y: array[0, int] - - var merged: seq[int] - merged.merge(x, y) - doAssert merged.isSorted - doAssert merged.len == 0 - - block: - var x: array[0, int] - var y: array[0, int] - - var merged: seq[int] = @[99, 99, 99] - merged.setLen(0) - merged.merge(x, y) - doAssert merged.isSorted - doAssert merged.len == 0 - - block: - var x: seq[int] - var y: seq[int] - - var merged: seq[int] - merged.merge(x, y) - doAssert merged.isSorted - doAssert merged.len == 0 - - block: - type - Record = object - id: int - - proc r(id: int): Record = - Record(id: id) - - proc cmp(x, y: Record): int = - if x.id == y.id: return 0 - if x.id < y.id: return -1 - result = 1 - - var x = @[r(-12), r(1), r(3), r(8), r(13), r(88)] - var y = @[r(4), r(7), r(12), r(13), r(77), r(99)] - - var merged: seq[Record] = @[] - merged.merge(x, y, cmp) - doAssert merged.isSorted(cmp) - doAssert merged.len == 12 - - block: - type - Record = object - id: int - - proc r(id: int): Record = - Record(id: id) - - proc ascendingCmp(x, y: Record): int = - if x.id == y.id: return 0 - if x.id < y.id: return -1 - result = 1 - - proc descendingCmp(x, y: Record): int = - if x.id == y.id: return 0 - if x.id < y.id: return 1 - result = -1 - - var x = @[r(-12), r(1), r(3), r(8), r(13), r(88)] - var y = @[r(4), r(7), r(12), r(13), r(77), r(99)] - - var merged: seq[Record] - merged.setLen(0) - merged.merge(x, y, ascendingCmp) - doAssert merged.isSorted(ascendingCmp) - doAssert merged == sorted(x & y, ascendingCmp) - - reverse(x) - reverse(y) - - merged.setLen(0) - merged.merge(x, y, descendingCmp) - doAssert merged.isSorted(descendingCmp) - doAssert merged == sorted(x & y, ascendingCmp, SortOrder.Descending) - - reverse(x) - reverse(y) - merged.setLen(0) - merged.merge(x, y, proc (x, y: Record): int = -descendingCmp(x, y)) - doAssert merged.isSorted(proc (x, y: Record): int = -descendingCmp(x, y)) - doAssert merged == sorted(x & y, ascendingCmp) - - - var x: seq[(int, int)] - x.merge([(1,1)], [(1,2)], (a,b) => a[0] - b[0]) - doAssert x == @[(1, 1), (1, 2)] - -static: main() -main() diff --git a/tests/stdlib/tarithmetics.nim b/tests/stdlib/tarithmetics.nim deleted file mode 100644 index a69334e71..000000000 --- a/tests/stdlib/tarithmetics.nim +++ /dev/null @@ -1,49 +0,0 @@ -discard """ - targets: "c cpp js" -""" -import std/assertions -# TODO: in future work move existing arithmetic tests (tests/arithm/*) into this file -# FYI https://github.com/nim-lang/Nim/pull/17767 - -template main = - # put all arithmetic tests - - block tshr: - block: # Signed types - let - a1 = -3 - a2 = -2 - b1 = -4'i8 - b2 = 1'i8 - c1 = -5'i16 - c2 = 1'i16 - d1 = -7i32 - d2 = 1'i32 - e1 = -9'i64 - e2 = 1'i64 - doAssert a1 shr a2 == -1 - doAssert b1 shr b2 == -2 - doAssert c1 shr c2 == -3 - doAssert d1 shr d2 == -4 - doAssert e1 shr e2 == -5 - - block: # Unsigned types - let - a1 = 3'u - a2 = 2'u - b1 = 2'u8 - b2 = 1'u8 - c1 = 5'u16 - c2 = 1'u16 - d1 = 6'u32 - d2 = 1'u32 - e1 = 8'u64 - e2 = 1'u64 - doAssert a1 shr a2 == 0 - doAssert b1 shr b2 == 1 - doAssert c1 shr c2 == 2 - doAssert d1 shr d2 == 3 - doAssert e1 shr e2 == 4 - -static: main() -main() diff --git a/tests/stdlib/tasynchttpserver.nim b/tests/stdlib/tasynchttpserver.nim deleted file mode 100644 index 8cf0d0ced..000000000 --- a/tests/stdlib/tasynchttpserver.nim +++ /dev/null @@ -1,120 +0,0 @@ -discard """ - cmd: "nim c --threads:on $file" - exitcode: 0 - output: "OK" - disabled: false -""" - -import strutils -from net import TimeoutError -import std/assertions - -import httpclient, asynchttpserver, asyncdispatch, asyncfutures - -template runTest( - handler: proc (request: Request): Future[void] {.gcsafe.}, - request: proc (server: AsyncHttpServer): Future[AsyncResponse], - test: proc (response: AsyncResponse, body: string): Future[void]) = - - let server = newAsyncHttpServer() - - discard server.serve(Port(64123), handler) - - let - response = waitFor(request(server)) - body = waitFor(response.body) - - discard test(response, body) - -proc test200() {.async.} = - proc handler(request: Request) {.async.} = - await request.respond(Http200, "Hello World, 200") - - proc request(server: AsyncHttpServer): Future[AsyncResponse] {.async.} = - let - client = newAsyncHttpClient() - clientResponse = await client.request("http://localhost:64123/") - - server.close() - - return clientResponse - - proc test(response: AsyncResponse, body: string) {.async.} = - doAssert(response.status == $Http200) - doAssert(body == "Hello World, 200") - doAssert(response.headers.hasKey("Content-Length")) - doAssert(response.headers["Content-Length"] == "16") - - runTest(handler, request, test) - -proc test404() {.async.} = - proc handler(request: Request) {.async.} = - await request.respond(Http404, "Hello World, 404") - - proc request(server: AsyncHttpServer): Future[AsyncResponse] {.async.} = - let - client = newAsyncHttpClient() - clientResponse = await client.request("http://localhost:64123/") - - server.close() - - return clientResponse - - proc test(response: AsyncResponse, body: string) {.async.} = - doAssert(response.status == $Http404) - doAssert(body == "Hello World, 404") - doAssert(response.headers.hasKey("Content-Length")) - doAssert(response.headers["Content-Length"] == "16") - - runTest(handler, request, test) - -proc testCustomEmptyHeaders() {.async.} = - proc handler(request: Request) {.async.} = - await request.respond(Http200, "Hello World, 200", newHttpHeaders()) - - proc request(server: AsyncHttpServer): Future[AsyncResponse] {.async.} = - let - client = newAsyncHttpClient() - clientResponse = await client.request("http://localhost:64123/") - - server.close() - - return clientResponse - - proc test(response: AsyncResponse, body: string) {.async.} = - doAssert(response.status == $Http200) - doAssert(body == "Hello World, 200") - doAssert(response.headers.hasKey("Content-Length")) - doAssert(response.headers["Content-Length"] == "16") - - runTest(handler, request, test) - -proc testCustomContentLength() {.async.} = - proc handler(request: Request) {.async.} = - let headers = newHttpHeaders() - headers["Content-Length"] = "0" - await request.respond(Http200, "Hello World, 200", headers) - - proc request(server: AsyncHttpServer): Future[AsyncResponse] {.async.} = - let - client = newAsyncHttpClient() - clientResponse = await client.request("http://localhost:64123/") - - server.close() - - return clientResponse - - proc test(response: AsyncResponse, body: string) {.async.} = - doAssert(response.status == $Http200) - doAssert(body == "") - doAssert(response.headers.hasKey("Content-Length")) - doAssert(response.headers["Content-Length"] == "0") - - runTest(handler, request, test) - -waitFor(test200()) -waitFor(test404()) -waitFor(testCustomEmptyHeaders()) -waitFor(testCustomContentLength()) - -echo "OK" diff --git a/tests/stdlib/tasynchttpserver_transferencoding.nim b/tests/stdlib/tasynchttpserver_transferencoding.nim deleted file mode 100644 index dae87be82..000000000 --- a/tests/stdlib/tasynchttpserver_transferencoding.nim +++ /dev/null @@ -1,91 +0,0 @@ -discard """ - matrix: "--gc:arc --threads:on; --gc:arc --threads:on -d:danger; --threads:on" - disabled: "freebsd" -""" - -import httpclient, asynchttpserver, asyncdispatch, asyncfutures -import net - -import std/asyncnet -import std/nativesockets -import std/assertions - -const postBegin = """ -POST / HTTP/1.1 -Transfer-Encoding:chunked - -""" - -template genTest(input, expected: string) = - proc handler(request: Request, future: Future[bool]) {.async, gcsafe.} = - doAssert(request.body == expected) - doAssert(request.headers.hasKey("Transfer-Encoding")) - doAssert(not request.headers.hasKey("Content-Length")) - future.complete(true) - await request.respond(Http200, "Good") - - proc sendData(data: string, port: Port) {.async.} = - var socket = newSocket() - defer: socket.close() - - socket.connect("127.0.0.1", port) - socket.send(data) - - proc runTest(): Future[bool] {.async.} = - var handlerFuture = newFuture[bool]("runTest") - let data = postBegin & input - let server = newAsyncHttpServer() - server.listen(Port(0)) - - proc wrapper(request: Request): Future[void] {.gcsafe, closure.} = - handler(request, handlerFuture) - - asyncCheck sendData(data, server.getPort) - asyncCheck server.acceptRequest(wrapper) - doAssert await handlerFuture - - server.close() - return true - - doAssert waitFor runTest() - -block: - const expected = "hello=world" - const input = ("b\r\n" & - "hello=world\r\n" & - "0\r\n" & - "\r\n") - genTest(input, expected) -block: - const expected = "hello encoding" - const input = ("e\r\n" & - "hello encoding\r\n" & - "0\r\n" & - "\r\n") - genTest(input, expected) -block: - # https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Transfer-Encoding - const expected = "MozillaDeveloperNetwork" - const input = ("7\r\n" & - "Mozilla\r\n" & - "9\r\n" & - "Developer\r\n" & - "7\r\n" & - "Network\r\n" & - "0\r\n" & - "\r\n") - genTest(input, expected) -block: - # https://en.wikipedia.org/wiki/Chunked_transfer_encoding#Example - const expected = "Wikipedia in \r\n\r\nchunks." - const input = ("4\r\n" & - "Wiki\r\n" & - "6\r\n" & - "pedia \r\n" & - "E\r\n" & - "in \r\n" & - "\r\n" & - "chunks.\r\n" & - "0\r\n" & - "\r\n") - genTest(input, expected) diff --git a/tests/stdlib/tbase64.nim b/tests/stdlib/tbase64.nim index 60fa3865d..9db6e8802 100644 --- a/tests/stdlib/tbase64.nim +++ b/tests/stdlib/tbase64.nim @@ -1,11 +1,9 @@ discard """ - targets: "c js" + output: "OK" """ -import std/assertions -import std/base64 +import base64 -template main() = - doAssert encode("a") == "YQ==" +proc main() = doAssert encode("Hello World") == "SGVsbG8gV29ybGQ=" doAssert encode("leasure.") == "bGVhc3VyZS4=" doAssert encode("easure.") == "ZWFzdXJlLg==" @@ -27,30 +25,20 @@ template main() = const tests = ["", "abc", "xyz", "man", "leasure.", "sure.", "easure.", "asure.", longText, testInputExpandsTo76, testInputExpands] - doAssert encodeMime("foobarbaz", lineLen=4) == "Zm9v\r\nYmFy\r\nYmF6" + doAssert encodeMIME("foobarbaz", lineLen=4) == "Zm9v\r\nYmFy\r\nYmF6" doAssert decode("Zm9v\r\nYmFy\r\nYmF6") == "foobarbaz" for t in items(tests): doAssert decode(encode(t)) == t - doAssert decode(encodeMime(t, lineLen=40)) == t - doAssert decode(encodeMime(t, lineLen=76)) == t + doAssert decode(encodeMIME(t, lineLen=40)) == t + doAssert decode(encodeMIME(t, lineLen=76)) == t - doAssertRaises(ValueError): discard decode("SGVsbG\x008gV29ybGQ=") + const invalid = "SGVsbG\x008gV29ybGQ=" + try: + doAssert decode(invalid) == "will throw error" + except ValueError: + discard - block base64urlSafe: - doAssert encode("c\xf7>", safe = true) == "Y_c-" - doAssert encode("c\xf7>", safe = false) == "Y/c+" # Not a nice URL :( - doAssert decode("Y/c+") == decode("Y_c-") - # Output must not change with safe=true - doAssert encode("Hello World", safe = true) == "SGVsbG8gV29ybGQ=" - doAssert encode("leasure.", safe = true) == "bGVhc3VyZS4=" - doAssert encode("easure.", safe = true) == "ZWFzdXJlLg==" - doAssert encode("asure.", safe = true) == "YXN1cmUu" - doAssert encode("sure.", safe = true) == "c3VyZS4=" - doAssert encode([1,2,3], safe = true) == "AQID" - doAssert encode(['h','e','y'], safe = true) == "aGV5" - doAssert encode("", safe = true) == "" - doAssert encode("the quick brown dog jumps over the lazy fox", safe = true) == "dGhlIHF1aWNrIGJyb3duIGRvZyBqdW1wcyBvdmVyIHRoZSBsYXp5IGZveA==" + echo "OK" -static: main() main() diff --git a/tests/stdlib/tbitops.nim b/tests/stdlib/tbitops.nim index c90943a93..e4461345e 100644 --- a/tests/stdlib/tbitops.nim +++ b/tests/stdlib/tbitops.nim @@ -1,11 +1,8 @@ discard """ nimout: "OK" - output: ''' -OK -''' + output: "OK" """ import bitops -import std/assertions proc main() = const U8 = 0b0011_0010'u8 @@ -18,123 +15,115 @@ proc main() = const I64A = 0b01000100_00111111_01111100_10001010_10011001_01001000_01111010_00010001'i64 const U64B = 0b00110010_11011101_10001111_00101000_00000000_00000000_00000000_00000000'u64 const I64B = 0b00110010_11011101_10001111_00101000_00000000_00000000_00000000_00000000'i64 - const U64C = 0b00101010_11110101_10001111_00101000_00000100_00000000_00000100_00000000'u64 - const I64C = 0b00101010_11110101_10001111_00101000_00000100_00000000_00000100_00000000'i64 - doAssert (U8 and U8) == bitand(U8,U8) - doAssert (I8 and I8) == bitand(I8,I8) - doAssert (U16 and U16) == bitand(U16,U16) - doAssert (I16 and I16) == bitand(I16,I16) - doAssert (U32 and U32) == bitand(U32,U32) - doAssert (I32 and I32) == bitand(I32,I32) - doAssert (U64A and U64B) == bitand(U64A,U64B) - doAssert (I64A and I64B) == bitand(I64A,I64B) - doAssert (U64A and U64B and U64C) == bitand(U64A,U64B,U64C) - doAssert (I64A and I64B and I64C) == bitand(I64A,I64B,I64C) + doAssert( (U8 and U8) == bitand(U8,U8) ) + doAssert( (I8 and I8) == bitand(I8,I8) ) + doAssert( (U16 and U16) == bitand(U16,U16) ) + doAssert( (I16 and I16) == bitand(I16,I16) ) + doAssert( (U32 and U32) == bitand(U32,U32) ) + doAssert( (I32 and I32) == bitand(I32,I32) ) + doAssert( (U64A and U64B) == bitand(U64A,U64B) ) + doAssert( (I64A and I64B) == bitand(I64A,I64B) ) - doAssert (U8 or U8) == bitor(U8,U8) - doAssert (I8 or I8) == bitor(I8,I8) - doAssert (U16 or U16) == bitor(U16,U16) - doAssert (I16 or I16) == bitor(I16,I16) - doAssert (U32 or U32) == bitor(U32,U32) - doAssert (I32 or I32) == bitor(I32,I32) - doAssert (U64A or U64B) == bitor(U64A,U64B) - doAssert (I64A or I64B) == bitor(I64A,I64B) - doAssert (U64A or U64B or U64C) == bitor(U64A,U64B,U64C) - doAssert (I64A or I64B or I64C) == bitor(I64A,I64B,I64C) + doAssert( (U8 or U8) == bitor(U8,U8) ) + doAssert( (I8 or I8) == bitor(I8,I8) ) + doAssert( (U16 or U16) == bitor(U16,U16) ) + doAssert( (I16 or I16) == bitor(I16,I16) ) + doAssert( (U32 or U32) == bitor(U32,U32) ) + doAssert( (I32 or I32) == bitor(I32,I32) ) + doAssert( (U64A or U64B) == bitor(U64A,U64B) ) + doAssert( (I64A or I64B) == bitor(I64A,I64B) ) - doAssert (U8 xor U8) == bitxor(U8,U8) - doAssert (I8 xor I8) == bitxor(I8,I8) - doAssert (U16 xor U16) == bitxor(U16,U16) - doAssert (I16 xor I16) == bitxor(I16,I16) - doAssert (U32 xor U32) == bitxor(U32,U32) - doAssert (I32 xor I32) == bitxor(I32,I32) - doAssert (U64A xor U64B) == bitxor(U64A,U64B) - doAssert (I64A xor I64B) == bitxor(I64A,I64B) - doAssert (U64A xor U64B xor U64C) == bitxor(U64A,U64B,U64C) - doAssert (I64A xor I64B xor I64C) == bitxor(I64A,I64B,I64C) + doAssert( (U8 xor U8) == bitxor(U8,U8) ) + doAssert( (I8 xor I8) == bitxor(I8,I8) ) + doAssert( (U16 xor U16) == bitxor(U16,U16) ) + doAssert( (I16 xor I16) == bitxor(I16,I16) ) + doAssert( (U32 xor U32) == bitxor(U32,U32) ) + doAssert( (I32 xor I32) == bitxor(I32,I32) ) + doAssert( (U64A xor U64B) == bitxor(U64A,U64B) ) + doAssert( (I64A xor I64B) == bitxor(I64A,I64B) ) - doAssert not(U8) == bitnot(U8) - doAssert not(I8) == bitnot(I8) - doAssert not(U16) == bitnot(U16) - doAssert not(I16) == bitnot(I16) - doAssert not(U32) == bitnot(U32) - doAssert not(I32) == bitnot(I32) - doAssert not(U64A) == bitnot(U64A) - doAssert not(I64A) == bitnot(I64A) + doAssert( not(U8) == bitnot(U8) ) + doAssert( not(I8) == bitnot(I8) ) + doAssert( not(U16) == bitnot(U16) ) + doAssert( not(I16) == bitnot(I16) ) + doAssert( not(U32) == bitnot(U32) ) + doAssert( not(I32) == bitnot(I32) ) + doAssert( not(U64A) == bitnot(U64A) ) + doAssert( not(I64A) == bitnot(I64A) ) - doAssert U64A.fastLog2 == 62 - doAssert I64A.fastLog2 == 62 - doAssert U64A.countLeadingZeroBits == 1 - doAssert I64A.countLeadingZeroBits == 1 - doAssert U64A.countTrailingZeroBits == 0 - doAssert I64A.countTrailingZeroBits == 0 - doAssert U64A.firstSetBit == 1 - doAssert I64A.firstSetBit == 1 - doAssert U64A.parityBits == 1 - doAssert I64A.parityBits == 1 - doAssert U64A.countSetBits == 29 - doAssert I64A.countSetBits == 29 - doAssert U64A.rotateLeftBits(37) == 0b00101001_00001111_01000010_00101000_10000111_11101111_10010001_01010011'u64 - doAssert U64A.rotateRightBits(37) == 0b01010100_11001010_01000011_11010000_10001010_00100001_11111011_11100100'u64 + doAssert( U64A.fastLog2 == 62) + doAssert( I64A.fastLog2 == 62) + doAssert( U64A.countLeadingZeroBits == 1) + doAssert( I64A.countLeadingZeroBits == 1) + doAssert( U64A.countTrailingZeroBits == 0) + doAssert( I64A.countTrailingZeroBits == 0) + doAssert( U64A.firstSetBit == 1) + doAssert( I64A.firstSetBit == 1) + doAssert( U64A.parityBits == 1) + doAssert( I64A.parityBits == 1) + doAssert( U64A.countSetBits == 29) + doAssert( I64A.countSetBits == 29) + doAssert( U64A.rotateLeftBits(37) == 0b00101001_00001111_01000010_00101000_10000111_11101111_10010001_01010011'u64) + doAssert( U64A.rotateRightBits(37) == 0b01010100_11001010_01000011_11010000_10001010_00100001_11111011_11100100'u64) - doAssert U64B.firstSetBit == 36 - doAssert I64B.firstSetBit == 36 + doAssert( U64B.firstSetBit == 36) + doAssert( I64B.firstSetBit == 36) - doAssert U32.fastLog2 == 31 - doAssert I32.fastLog2 == 31 - doAssert U32.countLeadingZeroBits == 0 - doAssert I32.countLeadingZeroBits == 0 - doAssert U32.countTrailingZeroBits == 4 - doAssert I32.countTrailingZeroBits == 4 - doAssert U32.firstSetBit == 5 - doAssert I32.firstSetBit == 5 - doAssert U32.parityBits == 0 - doAssert I32.parityBits == 0 - doAssert U32.countSetBits == 16 - doAssert I32.countSetBits == 16 - doAssert U32.rotateLeftBits(21) == 0b01001010_00011010_10110011_10011011'u32 - doAssert U32.rotateRightBits(21) == 0b11100110_11010010_10000110_10101100'u32 + doAssert( U32.fastLog2 == 31) + doAssert( I32.fastLog2 == 31) + doAssert( U32.countLeadingZeroBits == 0) + doAssert( I32.countLeadingZeroBits == 0) + doAssert( U32.countTrailingZeroBits == 4) + doAssert( I32.countTrailingZeroBits == 4) + doAssert( U32.firstSetBit == 5) + doAssert( I32.firstSetBit == 5) + doAssert( U32.parityBits == 0) + doAssert( I32.parityBits == 0) + doAssert( U32.countSetBits == 16) + doAssert( I32.countSetBits == 16) + doAssert( U32.rotateLeftBits(21) == 0b01001010_00011010_10110011_10011011'u32) + doAssert( U32.rotateRightBits(21) == 0b11100110_11010010_10000110_10101100'u32) - doAssert U16.fastLog2 == 13 - doAssert I16.fastLog2 == 13 - doAssert U16.countLeadingZeroBits == 2 - doAssert I16.countLeadingZeroBits == 2 - doAssert U16.countTrailingZeroBits == 3 - doAssert I16.countTrailingZeroBits == 3 - doAssert U16.firstSetBit == 4 - doAssert I16.firstSetBit == 4 - doAssert U16.parityBits == 0 - doAssert I16.parityBits == 0 - doAssert U16.countSetBits == 6 - doAssert I16.countSetBits == 6 - doAssert U16.rotateLeftBits(12) == 0b10000010_01110010'u16 - doAssert U16.rotateRightBits(12) == 0b01110010_10000010'u16 + doAssert( U16.fastLog2 == 13) + doAssert( I16.fastLog2 == 13) + doAssert( U16.countLeadingZeroBits == 2) + doAssert( I16.countLeadingZeroBits == 2) + doAssert( U16.countTrailingZeroBits == 3) + doAssert( I16.countTrailingZeroBits == 3) + doAssert( U16.firstSetBit == 4) + doAssert( I16.firstSetBit == 4) + doAssert( U16.parityBits == 0) + doAssert( I16.parityBits == 0) + doAssert( U16.countSetBits == 6) + doAssert( I16.countSetBits == 6) + doAssert( U16.rotateLeftBits(12) == 0b10000010_01110010'u16) + doAssert( U16.rotateRightBits(12) == 0b01110010_10000010'u16) - doAssert U8.fastLog2 == 5 - doAssert I8.fastLog2 == 5 - doAssert U8.countLeadingZeroBits == 2 - doAssert I8.countLeadingZeroBits == 2 - doAssert U8.countTrailingZeroBits == 1 - doAssert I8.countTrailingZeroBits == 1 - doAssert U8.firstSetBit == 2 - doAssert I8.firstSetBit == 2 - doAssert U8.parityBits == 1 - doAssert I8.parityBits == 1 - doAssert U8.countSetBits == 3 - doAssert I8.countSetBits == 3 - doAssert U8.rotateLeftBits(3) == 0b10010001'u8 - doAssert U8.rotateRightBits(3) == 0b0100_0110'u8 + doAssert( U8.fastLog2 == 5) + doAssert( I8.fastLog2 == 5) + doAssert( U8.countLeadingZeroBits == 2) + doAssert( I8.countLeadingZeroBits == 2) + doAssert( U8.countTrailingZeroBits == 1) + doAssert( I8.countTrailingZeroBits == 1) + doAssert( U8.firstSetBit == 2) + doAssert( I8.firstSetBit == 2) + doAssert( U8.parityBits == 1) + doAssert( I8.parityBits == 1) + doAssert( U8.countSetBits == 3) + doAssert( I8.countSetBits == 3) + doAssert( U8.rotateLeftBits(3) == 0b10010001'u8) + doAssert( U8.rotateRightBits(3) == 0b0100_0110'u8) template test_undefined_impl(ffunc: untyped; expected: int; is_static: bool) = - doAssert ffunc(0'u8) == expected - doAssert ffunc(0'i8) == expected - doAssert ffunc(0'u16) == expected - doAssert ffunc(0'i16) == expected - doAssert ffunc(0'u32) == expected - doAssert ffunc(0'i32) == expected - doAssert ffunc(0'u64) == expected - doAssert ffunc(0'i64) == expected + doAssert( ffunc(0'u8) == expected) + doAssert( ffunc(0'i8) == expected) + doAssert( ffunc(0'u16) == expected) + doAssert( ffunc(0'i16) == expected) + doAssert( ffunc(0'u32) == expected) + doAssert( ffunc(0'i32) == expected) + doAssert( ffunc(0'u64) == expected) + doAssert( ffunc(0'i64) == expected) template test_undefined(ffunc: untyped; expected: int) = test_undefined_impl(ffunc, expected, false) @@ -151,106 +140,37 @@ proc main() = test_undefined(fastLog2, -1) # check for undefined behavior with rotate by zero. - doAssert U8.rotateLeftBits(0) == U8 - doAssert U8.rotateRightBits(0) == U8 - doAssert U16.rotateLeftBits(0) == U16 - doAssert U16.rotateRightBits(0) == U16 - doAssert U32.rotateLeftBits(0) == U32 - doAssert U32.rotateRightBits(0) == U32 - doAssert U64A.rotateLeftBits(0) == U64A - doAssert U64A.rotateRightBits(0) == U64A + doAssert( U8.rotateLeftBits(0) == U8) + doAssert( U8.rotateRightBits(0) == U8) + doAssert( U16.rotateLeftBits(0) == U16) + doAssert( U16.rotateRightBits(0) == U16) + doAssert( U32.rotateLeftBits(0) == U32) + doAssert( U32.rotateRightBits(0) == U32) + doAssert( U64A.rotateLeftBits(0) == U64A) + doAssert( U64A.rotateRightBits(0) == U64A) # check for undefined behavior with rotate by integer width. - doAssert U8.rotateLeftBits(8) == U8 - doAssert U8.rotateRightBits(8) == U8 - doAssert U16.rotateLeftBits(16) == U16 - doAssert U16.rotateRightBits(16) == U16 - doAssert U32.rotateLeftBits(32) == U32 - doAssert U32.rotateRightBits(32) == U32 - doAssert U64A.rotateLeftBits(64) == U64A - doAssert U64A.rotateRightBits(64) == U64A + doAssert( U8.rotateLeftBits(8) == U8) + doAssert( U8.rotateRightBits(8) == U8) + doAssert( U16.rotateLeftBits(16) == U16) + doAssert( U16.rotateRightBits(16) == U16) + doAssert( U32.rotateLeftBits(32) == U32) + doAssert( U32.rotateRightBits(32) == U32) + doAssert( U64A.rotateLeftBits(64) == U64A) + doAssert( U64A.rotateRightBits(64) == U64A) block: - # basic mask operations (mutating) + # mask operations var v: uint8 v.setMask(0b1100_0000) v.setMask(0b0000_1100) - doAssert v == 0b1100_1100 + doAssert(v == 0b1100_1100) v.flipMask(0b0101_0101) - doAssert v == 0b1001_1001 + doAssert(v == 0b1001_1001) v.clearMask(0b1000_1000) - doAssert v == 0b0001_0001 + doAssert(v == 0b0001_0001) v.clearMask(0b0001_0001) - doAssert v == 0b0000_0000 - v.setMask(0b0001_1110) - doAssert v == 0b0001_1110 - v.mask(0b0101_0100) - doAssert v == 0b0001_0100 - block: - # basic mask operations (non-mutating) - let v = 0b1100_0000'u8 - doAssert v.masked(0b0000_1100) == 0b0000_0000 - doAssert v.masked(0b1000_1100) == 0b1000_0000 - doAssert v.setMasked(0b0000_1100) == 0b1100_1100 - doAssert v.setMasked(0b1000_1110) == 0b1100_1110 - doAssert v.flipMasked(0b1100_1000) == 0b0000_1000 - doAssert v.flipMasked(0b0000_1100) == 0b1100_1100 - let t = 0b1100_0110'u8 - doAssert t.clearMasked(0b0100_1100) == 0b1000_0010 - doAssert t.clearMasked(0b1100_0000) == 0b0000_0110 - block: - # basic bitslice opeartions - let a = 0b1111_1011'u8 - doAssert a.bitsliced(0 .. 3) == 0b1011 - doAssert a.bitsliced(2 .. 3) == 0b10 - doAssert a.bitsliced(4 .. 7) == 0b1111 - - # same thing, but with exclusive ranges. - doAssert a.bitsliced(0 ..< 4) == 0b1011 - doAssert a.bitsliced(2 ..< 4) == 0b10 - doAssert a.bitsliced(4 ..< 8) == 0b1111 - - # mutating - var b = 0b1111_1011'u8 - b.bitslice(1 .. 3) - doAssert b == 0b101 - - # loop test: - let c = 0b1111_1111'u8 - for i in 0 .. 7: - doAssert c.bitsliced(i .. 7) == c shr i - block: - # bitslice versions of mask operations (mutating) - var a = 0b1100_1100'u8 - let b = toMask[uint8](2 .. 3) - a.mask(b) - doAssert a == 0b0000_1100 - a.setMask(4 .. 7) - doAssert a == 0b1111_1100 - a.flipMask(1 .. 3) - doAssert a == 0b1111_0010 - a.flipMask(2 .. 4) - doAssert a == 0b1110_1110 - a.clearMask(2 .. 4) - doAssert a == 0b1110_0010 - a.mask(0 .. 3) - doAssert a == 0b0000_0010 - - # composition of mask from slices: - let c = bitor(toMask[uint8](2 .. 3), toMask[uint8](5 .. 7)) - doAssert c == 0b1110_1100'u8 - block: - # bitslice versions of mask operations (non-mutating) - let a = 0b1100_1100'u8 - doAssert a.masked(toMask[uint8](2 .. 3)) == 0b0000_1100 - doAssert a.masked(2 .. 3) == 0b0000_1100 - doAssert a.setMasked(0 .. 3) == 0b1100_1111 - doAssert a.setMasked(3 .. 4) == 0b1101_1100 - doAssert a.flipMasked(0 .. 3) == 0b1100_0011 - doAssert a.flipMasked(0 .. 7) == 0b0011_0011 - doAssert a.flipMasked(2 .. 3) == 0b1100_0000 - doAssert a.clearMasked(2 .. 3) == 0b1100_0000 - doAssert a.clearMasked(3 .. 6) == 0b1000_0100 + doAssert(v == 0b0000_0000) block: # single bit operations var v: uint8 @@ -264,8 +184,8 @@ proc main() = doAssert v == 0b1000_0010 v.flipBit(1) doAssert v == 0b1000_0000 - doAssert v.testBit(7) - doAssert not v.testBit(6) + doAssert v.testbit(7) + doAssert not v.testbit(6) block: # multi bit operations var v: uint8 @@ -287,7 +207,7 @@ proc main() = block: proc testReverseBitsInvo(x: SomeUnsignedInt) = - doAssert reverseBits(reverseBits(x)) == x + doAssert(reverseBits(reverseBits(x)) == x) proc testReverseBitsPerType(x, reversed: uint64) = doAssert reverseBits(x) == reversed @@ -329,16 +249,13 @@ proc main() = echo "OK" - # bug #7587 - doAssert popcount(0b11111111'i8) == 8 - block: # not ready for vm because exception is compile error try: var v: uint32 var i = 32 v.setBit(i) doAssert false - except RangeDefect: + except RangeError: discard except: doAssert false diff --git a/tests/stdlib/tbitops.nim.cfg b/tests/stdlib/tbitops.nim.cfg index 013e8d38e..f0d7668a7 100644 --- a/tests/stdlib/tbitops.nim.cfg +++ b/tests/stdlib/tbitops.nim.cfg @@ -1 +1 @@ --d:noUndefinedBitOpts +-d:noUndefinedBitOps diff --git a/tests/stdlib/tbitops2.nim b/tests/stdlib/tbitops2.nim new file mode 100644 index 000000000..e8c7318be --- /dev/null +++ b/tests/stdlib/tbitops2.nim @@ -0,0 +1,167 @@ +discard """ + output: "OK" +""" +import bitops + + +proc main() = + const U8 = 0b0011_0010'u8 + const I8 = 0b0011_0010'i8 + const U16 = 0b00100111_00101000'u16 + const I16 = 0b00100111_00101000'i16 + const U32 = 0b11010101_10011100_11011010_01010000'u32 + const I32 = 0b11010101_10011100_11011010_01010000'i32 + const U64A = 0b01000100_00111111_01111100_10001010_10011001_01001000_01111010_00010001'u64 + const I64A = 0b01000100_00111111_01111100_10001010_10011001_01001000_01111010_00010001'i64 + const U64B = 0b00110010_11011101_10001111_00101000_00000000_00000000_00000000_00000000'u64 + const I64B = 0b00110010_11011101_10001111_00101000_00000000_00000000_00000000_00000000'i64 + + doAssert( U64A.fastLog2 == 62) + doAssert( I64A.fastLog2 == 62) + doAssert( U64A.countLeadingZeroBits == 1) + doAssert( I64A.countLeadingZeroBits == 1) + doAssert( U64A.countTrailingZeroBits == 0) + doAssert( I64A.countTrailingZeroBits == 0) + doAssert( U64A.firstSetBit == 1) + doAssert( I64A.firstSetBit == 1) + doAssert( U64A.parityBits == 1) + doAssert( I64A.parityBits == 1) + doAssert( U64A.countSetBits == 29) + doAssert( I64A.countSetBits == 29) + doAssert( U64A.rotateLeftBits(37) == 0b00101001_00001111_01000010_00101000_10000111_11101111_10010001_01010011'u64) + doAssert( U64A.rotateRightBits(37) == 0b01010100_11001010_01000011_11010000_10001010_00100001_11111011_11100100'u64) + + doAssert( U64B.firstSetBit == 36) + doAssert( I64B.firstSetBit == 36) + + doAssert( U32.fastLog2 == 31) + doAssert( I32.fastLog2 == 31) + doAssert( U32.countLeadingZeroBits == 0) + doAssert( I32.countLeadingZeroBits == 0) + doAssert( U32.countTrailingZeroBits == 4) + doAssert( I32.countTrailingZeroBits == 4) + doAssert( U32.firstSetBit == 5) + doAssert( I32.firstSetBit == 5) + doAssert( U32.parityBits == 0) + doAssert( I32.parityBits == 0) + doAssert( U32.countSetBits == 16) + doAssert( I32.countSetBits == 16) + doAssert( U32.rotateLeftBits(21) == 0b01001010_00011010_10110011_10011011'u32) + doAssert( U32.rotateRightBits(21) == 0b11100110_11010010_10000110_10101100'u32) + + doAssert( U16.fastLog2 == 13) + doAssert( I16.fastLog2 == 13) + doAssert( U16.countLeadingZeroBits == 2) + doAssert( I16.countLeadingZeroBits == 2) + doAssert( U16.countTrailingZeroBits == 3) + doAssert( I16.countTrailingZeroBits == 3) + doAssert( U16.firstSetBit == 4) + doAssert( I16.firstSetBit == 4) + doAssert( U16.parityBits == 0) + doAssert( I16.parityBits == 0) + doAssert( U16.countSetBits == 6) + doAssert( I16.countSetBits == 6) + doAssert( U16.rotateLeftBits(12) == 0b10000010_01110010'u16) + doAssert( U16.rotateRightBits(12) == 0b01110010_10000010'u16) + + doAssert( U8.fastLog2 == 5) + doAssert( I8.fastLog2 == 5) + doAssert( U8.countLeadingZeroBits == 2) + doAssert( I8.countLeadingZeroBits == 2) + doAssert( U8.countTrailingZeroBits == 1) + doAssert( I8.countTrailingZeroBits == 1) + doAssert( U8.firstSetBit == 2) + doAssert( I8.firstSetBit == 2) + doAssert( U8.parityBits == 1) + doAssert( I8.parityBits == 1) + doAssert( U8.countSetBits == 3) + doAssert( I8.countSetBits == 3) + doAssert( U8.rotateLeftBits(3) == 0b10010001'u8) + doAssert( U8.rotateRightBits(3) == 0b0100_0110'u8) + + static : + # test bitopts at compile time with vm + doAssert( U8.fastLog2 == 5) + doAssert( I8.fastLog2 == 5) + doAssert( U8.countLeadingZeroBits == 2) + doAssert( I8.countLeadingZeroBits == 2) + doAssert( U8.countTrailingZeroBits == 1) + doAssert( I8.countTrailingZeroBits == 1) + doAssert( U8.firstSetBit == 2) + doAssert( I8.firstSetBit == 2) + doAssert( U8.parityBits == 1) + doAssert( I8.parityBits == 1) + doAssert( U8.countSetBits == 3) + doAssert( I8.countSetBits == 3) + doAssert( U8.rotateLeftBits(3) == 0b10010001'u8) + doAssert( U8.rotateRightBits(3) == 0b0100_0110'u8) + + + + template test_undefined_impl(ffunc: untyped; expected: int; is_static: bool) = + doAssert( ffunc(0'u8) == expected) + doAssert( ffunc(0'i8) == expected) + doAssert( ffunc(0'u16) == expected) + doAssert( ffunc(0'i16) == expected) + doAssert( ffunc(0'u32) == expected) + doAssert( ffunc(0'i32) == expected) + doAssert( ffunc(0'u64) == expected) + doAssert( ffunc(0'i64) == expected) + + template test_undefined(ffunc: untyped; expected: int) = + test_undefined_impl(ffunc, expected, false) + static: + test_undefined_impl(ffunc, expected, true) + + when defined(noUndefinedBitOpts): + # check for undefined behavior with zero. + test_undefined(countSetBits, 0) + test_undefined(parityBits, 0) + test_undefined(firstSetBit, 0) + test_undefined(countLeadingZeroBits, 0) + test_undefined(countTrailingZeroBits, 0) + test_undefined(fastLog2, -1) + + # check for undefined behavior with rotate by zero. + doAssert( U8.rotateLeftBits(0) == U8) + doAssert( U8.rotateRightBits(0) == U8) + doAssert( U16.rotateLeftBits(0) == U16) + doAssert( U16.rotateRightBits(0) == U16) + doAssert( U32.rotateLeftBits(0) == U32) + doAssert( U32.rotateRightBits(0) == U32) + doAssert( U64A.rotateLeftBits(0) == U64A) + doAssert( U64A.rotateRightBits(0) == U64A) + + # check for undefined behavior with rotate by integer width. + doAssert( U8.rotateLeftBits(8) == U8) + doAssert( U8.rotateRightBits(8) == U8) + doAssert( U16.rotateLeftBits(16) == U16) + doAssert( U16.rotateRightBits(16) == U16) + doAssert( U32.rotateLeftBits(32) == U32) + doAssert( U32.rotateRightBits(32) == U32) + doAssert( U64A.rotateLeftBits(64) == U64A) + doAssert( U64A.rotateRightBits(64) == U64A) + + static: # check for undefined behavior with rotate by zero. + doAssert( U8.rotateLeftBits(0) == U8) + doAssert( U8.rotateRightBits(0) == U8) + doAssert( U16.rotateLeftBits(0) == U16) + doAssert( U16.rotateRightBits(0) == U16) + doAssert( U32.rotateLeftBits(0) == U32) + doAssert( U32.rotateRightBits(0) == U32) + doAssert( U64A.rotateLeftBits(0) == U64A) + doAssert( U64A.rotateRightBits(0) == U64A) + + # check for undefined behavior with rotate by integer width. + doAssert( U8.rotateLeftBits(8) == U8) + doAssert( U8.rotateRightBits(8) == U8) + doAssert( U16.rotateLeftBits(16) == U16) + doAssert( U16.rotateRightBits(16) == U16) + doAssert( U32.rotateLeftBits(32) == U32) + doAssert( U32.rotateRightBits(32) == U32) + doAssert( U64A.rotateLeftBits(64) == U64A) + doAssert( U64A.rotateRightBits(64) == U64A) + + echo "OK" + +main() diff --git a/tests/stdlib/tbitops2.nim.cfg b/tests/stdlib/tbitops2.nim.cfg new file mode 100644 index 000000000..e1cb77e82 --- /dev/null +++ b/tests/stdlib/tbitops2.nim.cfg @@ -0,0 +1,2 @@ +-d:noIntrinsicsBitOpts +-d:noUndefinedBitOps diff --git a/tests/stdlib/tbitops_utils.nim b/tests/stdlib/tbitops_utils.nim deleted file mode 100644 index 7a64ea68d..000000000 --- a/tests/stdlib/tbitops_utils.nim +++ /dev/null @@ -1,15 +0,0 @@ -import std/private/bitops_utils -import std/assertions - -template chk(a, b) = - let a2 = castToUnsigned(a) - doAssert a2 == b - doAssert type(a2) is type(b) - doAssert type(b) is type(a2) - -chk 1'i8, 1'u8 -chk -1'i8, 255'u8 -chk 1'u8, 1'u8 -chk 1'u, 1'u -chk -1, cast[uint](-1) -chk -1'i64, cast[uint64](-1) diff --git a/tests/stdlib/tcgi.nim b/tests/stdlib/tcgi.nim index 7a52dc89b..bc177125e 100644 --- a/tests/stdlib/tcgi.nim +++ b/tests/stdlib/tcgi.nim @@ -1,11 +1,10 @@ -import std/unittest -import std/[cgi, strtabs, sugar] -import std/assertions +import unittest +import cgi, strtabs -block: # Test cgi module +suite "Test cgi module": const queryString = "foo=bar&фу=бар&checked=✓&list=1,2,3&with_space=text%20with%20space" - block: # test query parsing with readData + test "test query parsing with readData": let parsedQuery = readData(queryString) check parsedQuery["foo"] == "bar" @@ -16,12 +15,3 @@ block: # Test cgi module expect KeyError: discard parsedQuery["not_existing_key"] - -# bug #15369 -let queryString = "a=1&b=0&c=3&d&e&a=5&a=t%20e%20x%20t&e=http%3A%2F%2Fw3schools.com%2Fmy%20test.asp%3Fname%3Dst%C3%A5le%26car%3Dsaab" - -doAssert collect(for pair in decodeData(queryString): pair) == - @[("a", "1"), ("b", "0"), ("c", "3"), - ("d", ""),("e", ""), ("a", "5"), ("a", "t e x t"), - ("e", "http://w3schools.com/my test.asp?name=ståle&car=saab") -] diff --git a/tests/stdlib/tcmdline.nim b/tests/stdlib/tcmdline.nim deleted file mode 100644 index 5c0f71772..000000000 --- a/tests/stdlib/tcmdline.nim +++ /dev/null @@ -1,12 +0,0 @@ -discard """ - targets: "c js" - joinable: false -""" - -import std/os -import std/assertions - -var params = paramCount() -doAssert params == 0 -doAssert paramStr(0).len > 0 -doAssert commandLineParams().len == 0 diff --git a/tests/stdlib/tcomplex.nim b/tests/stdlib/tcomplex.nim deleted file mode 100644 index c7666be84..000000000 --- a/tests/stdlib/tcomplex.nim +++ /dev/null @@ -1,108 +0,0 @@ -import std/[complex, math] -import std/assertions - -proc `=~`[T](x, y: Complex[T]): bool = - result = abs(x.re-y.re) < 1e-6 and abs(x.im-y.im) < 1e-6 - -proc `=~`[T](x: Complex[T]; y: T): bool = - result = abs(x.re-y) < 1e-6 and abs(x.im) < 1e-6 - -let - z: Complex64 = complex(0.0, 0.0) - oo: Complex64 = complex(1.0, 1.0) - a: Complex64 = complex(1.0, 2.0) - b: Complex64 = complex(-1.0, -2.0) - m1: Complex64 = complex(-1.0, 0.0) - i: Complex64 = complex(0.0, 1.0) - one: Complex64 = complex(1.0, 0.0) - tt: Complex64 = complex(10.0, 20.0) - ipi: Complex64 = complex(0.0, -PI) - -doAssert(a/2.0 =~ complex(0.5, 1.0)) -doAssert(a == a) -doAssert((a-a) == z) -doAssert((a+b) == z) -doAssert((a+b) =~ 0.0) -doAssert((a/b) == m1) -doAssert((1.0/a) =~ complex(0.2, -0.4)) -doAssert((a*b) == complex(3.0, -4.0)) -doAssert(10.0*a == tt) -doAssert(a*10.0 == tt) -doAssert(tt/10.0 == a) -doAssert(oo+(-1.0) == i) -doAssert( (-1.0)+oo == i) -doAssert(abs(oo) == sqrt(2.0)) -doAssert(conjugate(a) == complex(1.0, -2.0)) -doAssert(sqrt(m1) == i) -doAssert(exp(ipi) =~ m1) - -doAssert(pow(a, b) =~ complex(-3.72999124927876, -1.68815826725068)) -doAssert(pow(z, a) =~ complex(0.0, 0.0)) -doAssert(pow(z, z) =~ complex(1.0, 0.0)) -doAssert(pow(a, one) =~ a) -doAssert(pow(a, m1) =~ complex(0.2, -0.4)) -doAssert(pow(a, 2.0) =~ complex(-3.0, 4.0)) -doAssert(pow(a, 2) =~ complex(-3.0, 4.0)) -doAssert(not(pow(a, 2.0) =~ a)) - -doAssert(ln(a) =~ complex(0.804718956217050, 1.107148717794090)) -doAssert(log10(a) =~ complex(0.349485002168009, 0.480828578784234)) -doAssert(log2(a) =~ complex(1.16096404744368, 1.59727796468811)) - -doAssert(sin(a) =~ complex(3.16577851321617, 1.95960104142161)) -doAssert(cos(a) =~ complex(2.03272300701967, -3.05189779915180)) -doAssert(tan(a) =~ complex(0.0338128260798967, 1.0147936161466335)) -doAssert(cot(a) =~ 1.0 / tan(a)) -doAssert(sec(a) =~ 1.0 / cos(a)) -doAssert(csc(a) =~ 1.0 / sin(a)) -doAssert(arcsin(a) =~ complex(0.427078586392476, 1.528570919480998)) -doAssert(arccos(a) =~ complex(1.14371774040242, -1.52857091948100)) -doAssert(arctan(a) =~ complex(1.338972522294494, 0.402359478108525)) -doAssert(arccot(a) =~ complex(0.2318238045004031, -0.402359478108525)) -doAssert(arcsec(a) =~ complex(1.384478272687081, 0.3965682301123288)) -doAssert(arccsc(a) =~ complex(0.1863180541078155, -0.3965682301123291)) - -doAssert(cosh(a) =~ complex(-0.642148124715520, 1.068607421382778)) -doAssert(sinh(a) =~ complex(-0.489056259041294, 1.403119250622040)) -doAssert(tanh(a) =~ complex(1.1667362572409199, -0.243458201185725)) -doAssert(sech(a) =~ 1.0 / cosh(a)) -doAssert(csch(a) =~ 1.0 / sinh(a)) -doAssert(coth(a) =~ 1.0 / tanh(a)) -doAssert(arccosh(a) =~ complex(1.528570919480998, 1.14371774040242)) -doAssert(arcsinh(a) =~ complex(1.469351744368185, 1.06344002357775)) -doAssert(arctanh(a) =~ complex(0.173286795139986, 1.17809724509617)) -doAssert(arcsech(a) =~ arccosh(1.0/a)) -doAssert(arccsch(a) =~ arcsinh(1.0/a)) -doAssert(arccoth(a) =~ arctanh(1.0/a)) - -doAssert(phase(a) == 1.1071487177940904) -let t = polar(a) -doAssert(rect(t.r, t.phi) =~ a) -doAssert(rect(1.0, 2.0) =~ complex(-0.4161468365471424, 0.9092974268256817)) - - -let - i64: Complex32 = complex(0.0f, 1.0f) - a64: Complex32 = 2.0f*i64 + 1.0.float32 - b64: Complex32 = complex(-1.0'f32, -2.0'f32) - -doAssert(a64 == a64) -doAssert(a64 == -b64) -doAssert(a64 + b64 =~ 0.0'f32) -doAssert(not(pow(a64, b64) =~ a64)) -doAssert(pow(a64, 0.5f) =~ sqrt(a64)) -doAssert(pow(a64, 2) =~ complex(-3.0'f32, 4.0'f32)) -doAssert(sin(arcsin(b64)) =~ b64) -doAssert(cosh(arccosh(a64)) =~ a64) - -doAssert(phase(a64) - 1.107149f < 1e-6) -let t64 = polar(a64) -doAssert(rect(t64.r, t64.phi) =~ a64) -doAssert(rect(1.0f, 2.0f) =~ complex(-0.4161468f, 0.90929742f)) -doAssert(sizeof(a64) == 8) -doAssert(sizeof(a) == 16) - -doAssert 123.0.im + 456.0 == complex64(456, 123) - -let localA = complex(0.1'f32) -doAssert localA.im is float32 diff --git a/tests/stdlib/tcookies.nim b/tests/stdlib/tcookies.nim deleted file mode 100644 index 4fe104dfc..000000000 --- a/tests/stdlib/tcookies.nim +++ /dev/null @@ -1,21 +0,0 @@ -discard """ - targets: "c js" -""" - - -import std/[cookies, times, strtabs] -import std/assertions - -let expire = fromUnix(0) + 1.seconds - -let theCookies = [ - setCookie("test", "value", expire), - setCookie("test", "value", expire.local), - setCookie("test", "value", expire.utc) -] -let expected = "Set-Cookie: test=value; Expires=Thu, 01 Jan 1970 00:00:01 GMT" -doAssert theCookies == [expected, expected, expected] - -let table = parseCookies("uid=1; kp=2") -doAssert table["uid"] == "1" -doAssert table["kp"] == "2" diff --git a/tests/stdlib/tcritbits.nim b/tests/stdlib/tcritbits.nim deleted file mode 100644 index 0c2e1d6fa..000000000 --- a/tests/stdlib/tcritbits.nim +++ /dev/null @@ -1,88 +0,0 @@ -discard """ - targets: "c js" -""" - -import std/[sequtils,critbits] -import std/assertions - -template main = - var r: CritBitTree[void] - r.incl "abc" - r.incl "xyz" - r.incl "def" - r.incl "definition" - r.incl "prefix" - r.incl "foo" - - doAssert r.contains"def" - - r.excl "def" - doAssert r.missingOrExcl("foo") == false - doAssert "foo" notin toSeq(r.items) - - doAssert r.missingOrExcl("foo") == true - - doAssert toSeq(r.items) == @["abc", "definition", "prefix", "xyz"] - - doAssert toSeq(r.itemsWithPrefix("de")) == @["definition"] - var c = CritBitTree[int]() - - c.inc("a") - doAssert c["a"] == 1 - - c.inc("a", 4) - doAssert c["a"] == 5 - - c.inc("a", -5) - doAssert c["a"] == 0 - - c.inc("b", 2) - doAssert c["b"] == 2 - - c.inc("c", 3) - doAssert c["c"] == 3 - - c.inc("a", 1) - doAssert c["a"] == 1 - - var cf = CritBitTree[float]() - - cf.incl("a", 1.0) - doAssert cf["a"] == 1.0 - - cf.incl("b", 2.0) - doAssert cf["b"] == 2.0 - - cf.incl("c", 3.0) - doAssert cf["c"] == 3.0 - - doAssert cf.len == 3 - cf.excl("c") - doAssert cf.len == 2 - - var cb: CritBitTree[string] - cb.incl("help", "help") - for k in cb.keysWithPrefix("helpp"): - doAssert false, "there is no prefix helpp" - - block: # bug #14339 - var strings: CritBitTree[int] - discard strings.containsOrIncl("foo", 3) - doAssert strings["foo"] == 3 - - block tcritbitsToString: - block: - var t: CritBitTree[int] - t["a"] = 1 - doAssert $t == """{"a": 1}""" - block: - var t: CritBitTree[string] - t["a"] = "1" - doAssert $t == """{"a": "1"}""" - block: - var t: CritBitTree[char] - t["a"] = '1' - doAssert $t == """{"a": '1'}""" - -main() -static: main() diff --git a/tests/stdlib/tcstring.nim b/tests/stdlib/tcstring.nim deleted file mode 100644 index d7fdd7738..000000000 --- a/tests/stdlib/tcstring.nim +++ /dev/null @@ -1,93 +0,0 @@ -discard """ - targets: "c cpp js" - matrix: "--gc:refc; --gc:arc" -""" - -from std/sugar import collect -from stdtest/testutils import whenRuntimeJs, whenVMorJs -import std/assertions - -template testMitems() = - block: - var a = "abc" - var b = a.cstring - let s = collect: - for bi in mitems(b): - if bi == 'b': bi = 'B' - bi - whenRuntimeJs: - discard # xxx mitems should give CT error instead of @['\x00', '\x00', '\x00'] - do: - doAssert s == @['a', 'B', 'c'] - - block: - var a = "abc\0def" - var b = a.cstring - let s = collect: - for bi in mitems(b): - if bi == 'b': bi = 'B' - bi - whenRuntimeJs: - discard # ditto - do: - doAssert s == @['a', 'B', 'c'] - -proc mainProc() = - testMitems() - -template main() = - block: # bug #13859 - let str = "abc".cstring - doAssert len(str).int8 == 3 - doAssert len(str).int16 == 3 - doAssert len(str).int32 == 3 - var str2 = "cde".cstring - doAssert len(str2).int8 == 3 - doAssert len(str2).int16 == 3 - doAssert len(str2).int32 == 3 - - const str3 = "abc".cstring - doAssert len(str3).int32 == 3 - doAssert len("abc".cstring).int16 == 3 - doAssert len("abc".cstring).float32 == 3.0 - - block: # bug #17159 - block: - var a = "abc" - var b = a.cstring - doAssert $(b, ) == """("abc",)""" - let s = collect: - for bi in b: bi - doAssert s == @['a', 'b', 'c'] - - block: - var a = "abc\0def" - var b = a.cstring - let s = collect: - for bi in b: bi - whenRuntimeJs: - doAssert $(b, ) == """("abc\x00def",)""" - doAssert s == @['a', 'b', 'c', '\x00', 'd', 'e', 'f'] - do: - doAssert $(b, ) == """("abc",)""" - doAssert s == @['a', 'b', 'c'] - - block: - when defined(gcArc): # xxx SIGBUS - discard - else: - mainProc() - when false: # xxx bug vm: Error: unhandled exception: 'node' is not accessible using discriminant 'kind' of type 'TFullReg' [FieldDefect] - testMitems() - - block: # bug #13321: [codegen] --gc:arc does not properly emit cstring, results in SIGSEGV - let a = "hello".cstring - doAssert $a == "hello" - doAssert $a[0] == "h" - doAssert $a[4] == "o" - whenVMorJs: discard # xxx this should work in vm, refs https://github.com/timotheecour/Nim/issues/619 - do: - doAssert a[a.len] == '\0' - -static: main() -main() diff --git a/tests/stdlib/tcstrutils.nim b/tests/stdlib/tcstrutils.nim deleted file mode 100644 index ec2b8596c..000000000 --- a/tests/stdlib/tcstrutils.nim +++ /dev/null @@ -1,38 +0,0 @@ -discard """ - targets: "c cpp js" -""" - -import std/cstrutils -import std/assertions - -proc main() = - let s = cstring "abcdef" - doAssert s.startsWith("a") - doAssert not s.startsWith("b") - doAssert s.endsWith("f") - doAssert not s.endsWith("a") - doAssert s.startsWith("") - doAssert s.endsWith("") - - let a = cstring "abracadabra" - doAssert a.startsWith("abra") - doAssert not a.startsWith("bra") - doAssert a.endsWith("abra") - doAssert not a.endsWith("dab") - doAssert a.startsWith("") - doAssert a.endsWith("") - - doAssert cmpIgnoreCase(cstring "FooBar", "foobar") == 0 - doAssert cmpIgnoreCase(cstring "bar", "Foo") < 0 - doAssert cmpIgnoreCase(cstring "Foo5", "foo4") > 0 - - doAssert cmpIgnoreStyle(cstring "foo_bar", "FooBar") == 0 - doAssert cmpIgnoreStyle(cstring "foo_bar_5", "FooBar4") > 0 - - doAssert cmpIgnoreCase(cstring "", cstring "") == 0 - doAssert cmpIgnoreCase(cstring "", cstring "Hello") < 0 - doAssert cmpIgnoreCase(cstring "wind", cstring "") > 0 - - -static: main() -main() diff --git a/tests/stdlib/tdb.nim b/tests/stdlib/tdb.nim deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/stdlib/tdb.nims b/tests/stdlib/tdb.nims deleted file mode 100644 index d31d0b26f..000000000 --- a/tests/stdlib/tdb.nims +++ /dev/null @@ -1 +0,0 @@ ---styleCheck:off \ No newline at end of file diff --git a/tests/stdlib/tdb_mysql.nim b/tests/stdlib/tdb_mysql.nim deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/stdlib/tdecls.nim b/tests/stdlib/tdecls.nim deleted file mode 100644 index 5cf352cfb..000000000 --- a/tests/stdlib/tdecls.nim +++ /dev/null @@ -1,49 +0,0 @@ -discard """ - targets: "c cpp js" -""" -import std/assertions -import std/decls - -template fun() = - var s = @[10,11,12] - var a {.byaddr.} = s[0] - a+=100 - doAssert s == @[110,11,12] - doAssert a is int - var b {.byaddr.}: int = s[0] - doAssert a.addr == b.addr - - when false: - # template specific redeclaration issue - # see https://github.com/nim-lang/Nim/issues/8275 - doAssert not compiles(block: - # redeclaration not allowed - var foo = 0 - var foo {.byaddr.} = s[0]) - - doAssert not compiles(block: - # ditto - var foo {.byaddr.} = s[0] - var foo {.byaddr.} = s[0]) - - block: - var b {.byaddr.} = s[1] # redeclaration ok in sub scope - b = 123 - - doAssert s == @[110,123,12] - - b = b * 10 - doAssert s == @[1100,123,12] - - doAssert not compiles(block: - var b2 {.byaddr.}: float = s[2]) - - doAssert compiles(block: - var b2 {.byaddr.}: int = s[2]) - -proc fun2() = fun() -fun() -fun2() -static: fun2() -when false: # pending bug #13887 - static: fun() diff --git a/tests/stdlib/tdecode_helpers.nim b/tests/stdlib/tdecode_helpers.nim deleted file mode 100644 index 1c0735e05..000000000 --- a/tests/stdlib/tdecode_helpers.nim +++ /dev/null @@ -1,27 +0,0 @@ -import std/private/decode_helpers -import std/assertions - -block: - var i = 0 - let c = decodePercent("%t9", i) - doAssert (i, c) == (0, '%') - -block: - var i = 0 - let c = decodePercent("19", i) - doAssert (i, c) == (0, '%') - -block: - var i = 0 - let c = decodePercent("%19", i) - doAssert (i, c) == (2, '\x19') - -block: - var i = 0 - let c = decodePercent("%A9", i) - doAssert (i, c) == (2, '\xA9') - -block: - var i = 0 - let c = decodePercent("%Aa", i) - doAssert (i, c) == (2, '\xAA') diff --git a/tests/stdlib/tdeques.nim b/tests/stdlib/tdeques.nim deleted file mode 100644 index fcfc278a9..000000000 --- a/tests/stdlib/tdeques.nim +++ /dev/null @@ -1,194 +0,0 @@ -discard """ - matrix: "--gc:refc; --gc:orc" - targets: "c cpp js" -""" - -import std/deques -from std/sequtils import toSeq -import std/assertions - -block: - proc index(self: Deque[int], idx: Natural): int = - self[idx] - - proc main = - var testDeque = initDeque[int]() - testDeque.addFirst(1) - doAssert testDeque.index(0) == 1 - - main() - -block: - var d = initDeque[int]() - d.addLast(1) - doAssert $d == "[1]" -block: - var d = initDeque[string]() - d.addLast("1") - doAssert $d == """["1"]""" -block: - var d = initDeque[char]() - d.addLast('1') - doAssert $d == "['1']" - -block: - var deq = initDeque[int](1) - deq.addLast(4) - deq.addFirst(9) - deq.addFirst(123) - var first = deq.popFirst() - deq.addLast(56) - doAssert(deq.peekLast() == 56) - deq.addLast(6) - doAssert(deq.peekLast() == 6) - var second = deq.popFirst() - deq.addLast(789) - doAssert(deq.peekLast() == 789) - - doAssert first == 123 - doAssert second == 9 - doAssert($deq == "[4, 56, 6, 789]") - doAssert deq == [4, 56, 6, 789].toDeque - - doAssert deq[0] == deq.peekFirst and deq.peekFirst == 4 - #doAssert deq[^1] == deq.peekLast and deq.peekLast == 789 - deq[0] = 42 - deq[deq.len - 1] = 7 - - doAssert 6 in deq and 789 notin deq - doAssert deq.find(6) >= 0 - doAssert deq.find(789) < 0 - - block: - var d = initDeque[int](1) - d.addLast 7 - d.addLast 8 - d.addLast 10 - d.addFirst 5 - d.addFirst 2 - d.addFirst 1 - d.addLast 20 - d.shrink(fromLast = 2) - doAssert($d == "[1, 2, 5, 7, 8]") - d.shrink(2, 1) - doAssert($d == "[5, 7]") - d.shrink(2, 2) - doAssert d.len == 0 - - for i in -2 .. 10: - if i in deq: - doAssert deq.contains(i) and deq.find(i) >= 0 - else: - doAssert(not deq.contains(i) and deq.find(i) < 0) - - when compileOption("boundChecks"): - try: - echo deq[99] - doAssert false - except IndexDefect: - discard - - try: - doAssert deq.len == 4 - for i in 0 ..< 5: deq.popFirst() - doAssert false - except IndexDefect: - discard - - # grabs some types of resize error. - deq = initDeque[int]() - for i in 1 .. 4: deq.addLast i - deq.popFirst() - deq.popLast() - for i in 5 .. 8: deq.addFirst i - doAssert $deq == "[8, 7, 6, 5, 2, 3]" - - # Similar to proc from the documentation example - proc foo(a, b: Positive) = # assume random positive values for `a` and `b`. - var deq = initDeque[int]() - doAssert deq.len == 0 - for i in 1 .. a: deq.addLast i - - if b < deq.len: # checking before indexed access. - doAssert deq[b] == b + 1 - - # The following two lines don't need any checking on access due to the logic - # of the program, but that would not be the case if `a` could be 0. - doAssert deq.peekFirst == 1 - doAssert deq.peekLast == a - - while deq.len > 0: # checking if the deque is empty - doAssert deq.popFirst() > 0 - - #foo(0,0) - foo(8, 5) - foo(10, 9) - foo(1, 1) - foo(2, 1) - foo(1, 5) - foo(3, 2) - -import std/sets - -block t13310: - proc main() = - var q = initDeque[HashSet[int16]](2) - q.addFirst([1'i16].toHashSet) - q.addFirst([2'i16].toHashSet) - q.addFirst([3'i16].toHashSet) - doAssert $q == "[{3}, {2}, {1}]" - - static: - main() - - -proc main() = - block: - let a = [10, 20, 30].toDeque - doAssert toSeq(a.pairs) == @[(0, 10), (1, 20), (2, 30)] - - block: - let q = [7, 9].toDeque - doAssert 7 in q - doAssert q.contains(7) - doAssert 8 notin q - - block: - let a = [10, 20, 30, 40, 50].toDeque - doAssert $a == "[10, 20, 30, 40, 50]" - doAssert a.peekFirst == 10 - doAssert len(a) == 5 - - block: - let a = [10, 20, 30, 40, 50].toDeque - doAssert $a == "[10, 20, 30, 40, 50]" - doAssert a.peekLast == 50 - doAssert len(a) == 5 - - block: - var a = [10, 20, 30, 40, 50].toDeque - doAssert $a == "[10, 20, 30, 40, 50]" - doAssert a.popFirst == 10 - doAssert $a == "[20, 30, 40, 50]" - - block: - var a = [10, 20, 30, 40, 50].toDeque - doAssert $a == "[10, 20, 30, 40, 50]" - doAssert a.popLast == 50 - doAssert $a == "[10, 20, 30, 40]" - - block: - var a = [10, 20, 30, 40, 50].toDeque - doAssert $a == "[10, 20, 30, 40, 50]" - clear(a) - doAssert len(a) == 0 - - block: # bug #21278 - var a = [10, 20, 30, 40].toDeque - - a.shrink(fromFirst = 0, fromLast = 1) - doAssert $a == "[10, 20, 30]" - - -static: main() -main() diff --git a/tests/stdlib/tdiff.nim b/tests/stdlib/tdiff.nim deleted file mode 100644 index cb9cebb3a..000000000 --- a/tests/stdlib/tdiff.nim +++ /dev/null @@ -1,74 +0,0 @@ -discard """ - targets: "c js" -""" - -import experimental/diff -import std/strutils -import std/assertions - -proc testHelper(f: seq[Item]): string = - for it in f: - result.add( - $it.deletedA & "." & $it.insertedB & "." & $it.startA & "." & $it.startB & "*" - ) - -proc main() = - var a, b: string - - # Diff Self Test - # test all changes - a = "a,b,c,d,e,f,g,h,i,j,k,l".replace(',', '\n') - b = "0,1,2,3,4,5,6,7,8,9".replace(',', '\n') - doAssert(testHelper(diffText(a, b)) == - "12.10.0.0*", - "all-changes test failed.") - # test all same - a = "a,b,c,d,e,f,g,h,i,j,k,l".replace(',', '\n') - b = a - doAssert(testHelper(diffText(a, b)) == - "", - "all-same test failed.") - - # test snake - a = "a,b,c,d,e,f".replace(',', '\n') - b = "b,c,d,e,f,x".replace(',', '\n') - doAssert(testHelper(diffText(a, b)) == - "1.0.0.0*0.1.6.5*", - "snake test failed.") - - # 2002.09.20 - repro - a = "c1,a,c2,b,c,d,e,g,h,i,j,c3,k,l".replace(',', '\n') - b = "C1,a,C2,b,c,d,e,I1,e,g,h,i,j,C3,k,I2,l".replace(',', '\n') - doAssert(testHelper(diffText(a, b)) == - "1.1.0.0*1.1.2.2*0.2.7.7*1.1.11.13*0.1.13.15*", - "repro20020920 test failed.") - - # 2003.02.07 - repro - a = "F".replace(',', '\n') - b = "0,F,1,2,3,4,5,6,7".replace(',', '\n') - doAssert(testHelper(diffText(a, b)) == - "0.1.0.0*0.7.1.2*", - "repro20030207 test failed.") - - # Muegel - repro - a = "HELLO\nWORLD" - b = "\n\nhello\n\n\n\nworld\n" - doAssert(testHelper(diffText(a, b)) == - "2.8.0.0*", - "repro20030409 test failed.") - - # test some differences - a = "a,b,-,c,d,e,f,f".replace(',', '\n') - b = "a,b,x,c,e,f".replace(',', '\n') - doAssert(testHelper(diffText(a, b)) == - "1.1.2.2*1.0.4.4*1.0.7.6*", - "some-changes test failed.") - - # test one change within long chain of repeats - a = "a,a,a,a,a,a,a,a,a,a".replace(',', '\n') - b = "a,a,a,a,-,a,a,a,a,a".replace(',', '\n') - doAssert(testHelper(diffText(a, b)) == - "0.1.4.4*1.0.9.10*", - "long chain of repeats test failed.") -main() -static: main() diff --git a/tests/stdlib/tdochelpers.nim b/tests/stdlib/tdochelpers.nim deleted file mode 100644 index 300ce76dc..000000000 --- a/tests/stdlib/tdochelpers.nim +++ /dev/null @@ -1,220 +0,0 @@ -discard """ - output: ''' - -[Suite] Integration with Nim -''' -""" - -# tests for dochelpers.nim module - -import ../../lib/packages/docutils/[rstast, rst, dochelpers] -import unittest -import std/assertions - -proc testMsgHandler(filename: string, line, col: int, msgkind: MsgKind, - arg: string) = - doAssert msgkind == mwBrokenLink - -proc fromRst(text: string): LangSymbol = - let r = rstParse(text, "-input-", LineRstInit, ColRstInit, - {roNimFile}, - msgHandler=testMsgHandler) - assert r.node.kind == rnRstRef - result = toLangSymbol(r.node) - -proc fromMd(text: string): LangSymbol = - let r = rstParse(text, "-input-", LineRstInit, ColRstInit, - {roPreferMarkdown, roSupportMarkdown, roNimFile}, - msgHandler=testMsgHandler) - assert r.node.kind == rnPandocRef - assert r.node.len == 2 - # this son is the target: - assert r.node.sons[1].kind == rnInner - result = toLangSymbol(r.node.sons[1]) - -suite "Integration with Nim": - test "simple symbol parsing (shortest form)": - let expected = LangSymbol(symKind: "", name: "g") - check "g_".fromRst == expected - check "[g]".fromMd == expected - # test also alternative syntax variants of Pandoc Markdown: - check "[g][]".fromMd == expected - check "[this symbol][g]".fromMd == expected - - test "simple symbol parsing (group of words)": - #let input1 = "`Y`_".rstParseTest - let expected1 = LangSymbol(symKind: "", name: "Y") - check "`Y`_".fromRst == expected1 - check "[Y]".fromMd == expected1 - - # this means not a statement 'type', it's a backticked identifier `type`: - let expected2 = LangSymbol(symKind: "", name: "type") - check "`type`_".fromRst == expected2 - check "[type]".fromMd == expected2 - - let expected3 = LangSymbol(symKind: "", name: "[]") - check "`[]`_".fromRst == expected3 - # Markdown syntax for this case is NOT [[]] - check "[`[]`]".fromMd == expected3 - - let expected4 = LangSymbol(symKind: "", name: "Xyz") - check "`X Y Z`_".fromRst == expected4 - check "[X Y Z]".fromMd == expected4 - - test "simple proc parsing": - let expected = LangSymbol(symKind: "proc", name: "f") - check "`proc f`_".fromRst == expected - check "[proc f]".fromMd == expected - - test "another backticked name": - let expected = LangSymbol(symKind: "template", name: "type") - check """`template \`type\``_""".fromRst == expected - # no backslash in Markdown: - check """[template `type`]""".fromMd == expected - - test "simple proc parsing with parameters": - let expected = LangSymbol(symKind: "proc", name: "f", - parametersProvided: true) - check "`proc f*()`_".fromRst == expected - check "`proc f()`_".fromRst == expected - check "[proc f*()]".fromMd == expected - check "[proc f()]".fromMd == expected - - test "symbol parsing with 1 parameter": - let expected = LangSymbol(symKind: "", name: "f", - parameters: @[("G[int]", "")], - parametersProvided: true) - check "`f(G[int])`_".fromRst == expected - check "[f(G[int])]".fromMd == expected - - test "more proc parsing": - let input1 = "`proc f[T](x:G[T]):M[T]`_".fromRst - let input2 = "`proc f[ T ] ( x: G [T] ): M[T]`_".fromRst - let input3 = "`proc f*[T](x: G[T]): M[T]`_".fromRst - let expected = LangSymbol(symKind: "proc", - name: "f", - generics: "[T]", - parameters: @[("x", "G[T]")], - parametersProvided: true, - outType: "M[T]") - check(input1 == expected) - check(input2 == expected) - check(input3 == expected) - - test "advanced proc parsing with Nim identifier normalization": - let inputRst = """`proc binarySearch*[T, K](a: openarray[T]; key: K; - cmp: proc (x: T; y: K): int)`_""" - let inputMd = """[proc binarySearch*[T, K](a: openarray[T]; key: K; - cmp: proc (x: T; y: K): int)]""" - let expected = LangSymbol(symKind: "proc", - name: "binarysearch", - generics: "[T,K]", - parameters: @[ - ("a", "openarray[T]"), - ("key", "K"), - ("cmp", "proc(x:T;y:K):int")], - parametersProvided: true, - outType: "") - check(inputRst.fromRst == expected) - check(inputMd.fromMd == expected) - - test "the same without proc": - let input = """`binarySearch*[T, K](a: openarray[T]; key: K; - cmp: proc (x: T; y: K): int {.closure.})`_""" - let expected = LangSymbol(symKind: "", - name: "binarysearch", - generics: "[T,K]", - parameters: @[ - ("a", "openarray[T]"), - ("key", "K"), - ("cmp", "proc(x:T;y:K):int")], - parametersProvided: true, - outType: "") - check(input.fromRst == expected) - let inputMd = """[binarySearch*[T, K](a: openarray[T]; key: K; - cmp: proc (x: T; y: K): int {.closure.})]""" - check(inputMd.fromMd == expected) - - test "operator $ with and without backticks": - let input1 = """`func \`$\`*[T](a: \`open Array\`[T]): string`_""" - let input1md = "[func `$`*[T](a: `open Array`[T]): string]" - let input2 = """`func $*[T](a: \`open Array\`[T]): string`_""" - let input2md = "[func $*[T](a: `open Array`[T]): string]" - let expected = LangSymbol(symKind: "func", - name: "$", - generics: "[T]", - parameters: @[("a", "openarray[T]")], - parametersProvided: true, - outType: "string") - check input1.fromRst == expected - check input2.fromRst == expected - check input1md.fromMd == expected - check input2md.fromMd == expected - - test "operator [] with and without backticks": - let input1 = """`func \`[]\`[T](a: \`open Array\`[T], idx: int): T`_""" - let input1md = "[func `[]`[T](a: `open Array`[T], idx: int): T]" - let input2 = """`func [][T](a: \`open Array\`[T], idx: int): T`_""" - let input2md = "[func [][T](a: `open Array`[T], idx: int): T]" - let expected = LangSymbol(symKind: "func", - name: "[]", - generics: "[T]", - parameters: @[("a", "openarray[T]"), - ("idx", "int")], - parametersProvided: true, - outType: "T") - check input1.fromRst == expected - check input2.fromRst == expected - check input1md.fromMd == expected - check input2md.fromMd == expected - - test "postfix symbol specifier #1": - let input = "`walkDir iterator`_" - let inputMd = "[walkDir iterator]" - let expected = LangSymbol(symKind: "iterator", - name: "walkdir") - check input.fromRst == expected - check inputMd.fromMd == expected - - test "postfix symbol specifier #2": - let input1 = """`\`[]\`[T](a: \`open Array\`[T], idx: int): T func`_""" - let input1md = "[`[]`[T](a: `open Array`[T], idx: int): T func]" - let input2 = """`[][T](a: \`open Array\`[T], idx: int): T func`_""" - # note again that ` is needed between 1st and second [ - let input2md = "[`[]`[T](a: `open Array`[T], idx: int): T func]" - let expected = LangSymbol(symKind: "func", - name: "[]", - generics: "[T]", - parameters: @[("a", "openarray[T]"), - ("idx", "int")], - parametersProvided: true, - outType: "T") - check input1.fromRst == expected - check input2.fromRst == expected - check input1md.fromMd == expected - check input2md.fromMd == expected - - test "type of type": - let inputRst = "`CopyFlag enum`_" - let inputMd = "[CopyFlag enum]" - let expected = LangSymbol(symKind: "type", - symTypeKind: "enum", - name: "Copyflag") - check inputRst.fromRst == expected - check inputMd.fromMd == expected - - test "prefixed module": - let inputRst = "`module std / paths`_" - let inputMd = "[module std / paths]" - let expected = LangSymbol(symKind: "module", - name: "std/paths") - check inputRst.fromRst == expected - check inputMd.fromMd == expected - - test "postfixed module": - let inputRst = "`std / paths module`_" - let inputMd = "[std / paths module]" - let expected = LangSymbol(symKind: "module", - name: "std/paths") - check inputRst.fromRst == expected - check inputMd.fromMd == expected diff --git a/tests/stdlib/teditdistance.nim b/tests/stdlib/teditdistance.nim deleted file mode 100644 index b3b323647..000000000 --- a/tests/stdlib/teditdistance.nim +++ /dev/null @@ -1,41 +0,0 @@ -import std/editdistance -import std/assertions - -doAssert editDistance("", "") == 0 -doAssert editDistance("kitten", "sitting") == 3 # from Wikipedia -doAssert editDistance("flaw", "lawn") == 2 # from Wikipedia - -doAssert editDistance("привет", "превет") == 1 -doAssert editDistance("Åge", "Age") == 1 -# editDistance, one string is longer in bytes, but shorter in rune length -# first string: 4 bytes, second: 6 bytes, but only 3 runes -doAssert editDistance("aaaa", "×××") == 4 - -block veryLongStringEditDistanceTest: - const cap = 256 - var - s1 = newStringOfCap(cap) - s2 = newStringOfCap(cap) - while len(s1) < cap: - s1.add 'a' - while len(s2) < cap: - s2.add 'b' - doAssert editDistance(s1, s2) == cap - -block combiningCodePointsEditDistanceTest: - const s = "A\xCC\x8Age" - doAssert editDistance(s, "Age") == 1 - -doAssert editDistanceAscii("", "") == 0 -doAssert editDistanceAscii("kitten", "sitting") == 3 # from Wikipedia -doAssert editDistanceAscii("flaw", "lawn") == 2 # from Wikipedia - - -doAssert(editDistance("prefix__hallo_suffix", "prefix__hallo_suffix") == 0) -doAssert(editDistance("prefix__hallo_suffix", "prefix__hallo_suffi1") == 1) -doAssert(editDistance("prefix__hallo_suffix", "prefix__HALLO_suffix") == 5) -doAssert(editDistance("prefix__hallo_suffix", "prefix__ha_suffix") == 3) -doAssert(editDistance("prefix__hallo_suffix", "prefix") == 14) -doAssert(editDistance("prefix__hallo_suffix", "suffix") == 14) -doAssert(editDistance("prefix__hallo_suffix", "prefix__hao_suffix") == 2) -doAssert(editDistance("main", "malign") == 2) \ No newline at end of file diff --git a/tests/stdlib/tencodings.nim b/tests/stdlib/tencodings.nim deleted file mode 100644 index 10d79f5d0..000000000 --- a/tests/stdlib/tencodings.nim +++ /dev/null @@ -1,99 +0,0 @@ -import std/encodings -import std/assertions - -var fromGBK = open("utf-8", "gbk") -var toGBK = open("gbk", "utf-8") - -var fromGB2312 = open("utf-8", "gb2312") -var toGB2312 = open("gb2312", "utf-8") - - -block: - let data = "\215\237\186\243\178\187\214\170\204\236\212\218\203\174\163\172\194\250\180\178\208\199\195\206\209\185\208\199\186\211" - doAssert fromGBK.convert(data) == "醉后不知天在水,满床星梦压星河" - -block: - let data = "万两黄金容易得,知心一个也难求" - doAssert toGBK.convert(data) == "\205\242\193\189\187\198\189\240\200\221\210\215\181\195\163\172\214\170\208\196\210\187\184\246\210\178\196\209\199\243" - - -block: - let data = "\215\212\208\197\200\203\201\250\182\254\176\217\196\234\163\172\187\225\181\177\203\174\187\247\200\253\199\167\192\239" - doAssert fromGB2312.convert(data) == "自信人生二百年,会当水击三千里" - -block: - let data = "谁怕?一蓑烟雨任平生" - doAssert toGB2312.convert(data) == "\203\173\197\194\163\191\210\187\203\242\209\204\211\234\200\206\198\189\201\250" - - -when defined(windows): - block should_throw_on_unsupported_conversions: - let original = "some string" - - doAssertRaises(EncodingError): - discard convert(original, "utf-8", "utf-32") - - doAssertRaises(EncodingError): - discard convert(original, "utf-8", "unicodeFFFE") - - doAssertRaises(EncodingError): - discard convert(original, "utf-8", "utf-32BE") - - doAssertRaises(EncodingError): - discard convert(original, "unicodeFFFE", "utf-8") - - doAssertRaises(EncodingError): - discard convert(original, "utf-32", "utf-8") - - doAssertRaises(EncodingError): - discard convert(original, "utf-32BE", "utf-8") - - block should_convert_from_utf16_to_utf8: - let original = "\x42\x04\x35\x04\x41\x04\x42\x04" # utf-16 little endian test string "тест" - let result = convert(original, "utf-8", "utf-16") - doAssert(result == "\xd1\x82\xd0\xb5\xd1\x81\xd1\x82") - - block should_convert_from_utf16_to_win1251: - let original = "\x42\x04\x35\x04\x41\x04\x42\x04" # utf-16 little endian test string "тест" - let result = convert(original, "windows-1251", "utf-16") - doAssert(result == "\xf2\xe5\xf1\xf2") - - block should_convert_from_win1251_to_koi8r: - let original = "\xf2\xe5\xf1\xf2" # win1251 test string "тест" - let result = convert(original, "koi8-r", "windows-1251") - doAssert(result == "\xd4\xc5\xd3\xd4") - - block should_convert_from_koi8r_to_win1251: - let original = "\xd4\xc5\xd3\xd4" # koi8r test string "тест" - let result = convert(original, "windows-1251", "koi8-r") - doAssert(result == "\xf2\xe5\xf1\xf2") - - block should_convert_from_utf8_to_win1251: - let original = "\xd1\x82\xd0\xb5\xd1\x81\xd1\x82" # utf-8 test string "тест" - let result = convert(original, "windows-1251", "utf-8") - doAssert(result == "\xf2\xe5\xf1\xf2") - - block should_convert_from_utf8_to_utf16: - let original = "\xd1\x82\xd0\xb5\xd1\x81\xd1\x82" # utf-8 test string "тест" - let result = convert(original, "utf-16", "utf-8") - doAssert(result == "\x42\x04\x35\x04\x41\x04\x42\x04") - - block should_handle_empty_string_for_any_conversion: - let original = "" - var result = convert(original, "utf-16", "utf-8") - doAssert(result == "") - result = convert(original, "utf-8", "utf-16") - doAssert(result == "") - result = convert(original, "windows-1251", "koi8-r") - doAssert(result == "") - - -block: - let - orig = "öäüß" - cp1252 = convert(orig, "CP1252", "UTF-8") - ibm850 = convert(cp1252, "ibm850", "CP1252") - current = getCurrentEncoding() - doAssert orig == "\195\182\195\164\195\188\195\159" - doAssert ibm850 == "\148\132\129\225" - doAssert convert(ibm850, current, "ibm850") == orig diff --git a/tests/stdlib/tenumerate.nim b/tests/stdlib/tenumerate.nim deleted file mode 100644 index b15b9e2db..000000000 --- a/tests/stdlib/tenumerate.nim +++ /dev/null @@ -1,20 +0,0 @@ -import std/enumerate -import std/assertions - -let a = @[1, 3, 5, 7] - -block: - var res: seq[(int, int)] - for i, x in enumerate(a): - res.add (i, x) - doAssert res == @[(0, 1), (1, 3), (2, 5), (3, 7)] -block: - var res: seq[(int, int)] - for (i, x) in enumerate(a.items): - res.add (i, x) - doAssert res == @[(0, 1), (1, 3), (2, 5), (3, 7)] -block: - var res: seq[(int, int)] - for i, x in enumerate(3, a): - res.add (i, x) - doAssert res == @[(3, 1), (4, 3), (5, 5), (6, 7)] diff --git a/tests/stdlib/tenumutils.nim b/tests/stdlib/tenumutils.nim deleted file mode 100644 index 63c563739..000000000 --- a/tests/stdlib/tenumutils.nim +++ /dev/null @@ -1,38 +0,0 @@ -discard """ - targets: "c js" -""" - -import std/enumutils -from std/sequtils import toSeq -import std/assertions - -template main = - block: # items - type A = enum a0 = 2, a1 = 4, a2 - type B[T] = enum b0 = 2, b1 = 4 - doAssert A.toSeq == [a0, a1, a2] - doAssert B[float].toSeq == [B[float].b0, B[float].b1] - - block: # symbolName - block: - type A2 = enum a20, a21, a22 - doAssert $a21 == "a21" - doAssert a21.symbolName == "a21" - proc `$`(a: A2): string = "foo" - doAssert $a21 == "foo" - doAssert a21.symbolName == "a21" - var a = a22 - doAssert $a == "foo" - doAssert a.symbolName == "a22" - - type B = enum - b0 = (10, "kb0") - b1 = "kb1" - b2 - let b = B.low - doAssert b.symbolName == "b0" - doAssert $b == "kb0" - static: doAssert B.high.symbolName == "b2" - -static: main() -main() diff --git a/tests/stdlib/tenvvars.nim b/tests/stdlib/tenvvars.nim deleted file mode 100644 index 03a46a013..000000000 --- a/tests/stdlib/tenvvars.nim +++ /dev/null @@ -1,162 +0,0 @@ -discard """ - matrix: "--threads:on" - joinable: false - targets: "c js cpp" -""" - -import std/envvars -from std/sequtils import toSeq -import stdtest/testutils -import std/[assertions] - -when not defined(js): - import std/typedthreads - -# "LATIN CAPITAL LETTER AE" in UTF-8 (0xc386) -const unicodeUtf8 = "\xc3\x86" - -template main = - block: # delEnv, existsEnv, getEnv, envPairs - for val in ["val", "", unicodeUtf8]: # ensures empty val works too - const key = "NIM_TESTS_TOSENV_KEY" - doAssert not existsEnv(key) - - putEnv(key, "tempval") - doAssert existsEnv(key) - doAssert getEnv(key) == "tempval" - - putEnv(key, val) # change a key that already exists - doAssert existsEnv(key) - doAssert getEnv(key) == val - - doAssert (key, val) in toSeq(envPairs()) - delEnv(key) - doAssert (key, val) notin toSeq(envPairs()) - doAssert not existsEnv(key) - delEnv(key) # deleting an already deleted env var - doAssert not existsEnv(key) - - block: - doAssert getEnv("NIM_TESTS_TOSENV_NONEXISTENT", "") == "" - doAssert getEnv("NIM_TESTS_TOSENV_NONEXISTENT", " ") == " " - doAssert getEnv("NIM_TESTS_TOSENV_NONEXISTENT", "defval") == "defval" - - whenVMorJs: discard # xxx improve - do: - doAssertRaises(OSError, putEnv("NIM_TESTS_TOSENV_PUT=DUMMY_VALUE", "NEW_DUMMY_VALUE")) - doAssertRaises(OSError, putEnv("", "NEW_DUMMY_VALUE")) - doAssert not existsEnv("") - doAssert not existsEnv("NIM_TESTS_TOSENV_PUT=DUMMY_VALUE") - doAssert not existsEnv("NIM_TESTS_TOSENV_PUT") - -static: main() -main() - -when defined(windows): - import std/widestrs - proc c_wgetenv(env: WideCString): WideCString {.importc: "_wgetenv", header: "".} -proc c_getenv(env: cstring): cstring {.importc: "getenv", header: "".} - -when not defined(js) and not defined(nimscript): - block: # bug #18533 - var thr: Thread[void] - proc threadFunc {.thread.} = putEnv("foo", "fooVal2") - - putEnv("foo", "fooVal1") - doAssert getEnv("foo") == "fooVal1" - createThread(thr, threadFunc) - joinThreads(thr) - when defined(windows): - doAssert getEnv("foo") == $c_wgetenv("foo".newWideCString) - else: - doAssert getEnv("foo") == $c_getenv("foo".cstring) - - doAssertRaises(OSError): delEnv("foo=bar") - -when defined(windows) and not defined(nimscript): - import std/encodings - - proc c_putenv(env: cstring): int32 {.importc: "putenv", header: "".} - proc c_wputenv(env: WideCString): int32 {.importc: "_wputenv", header: "".} - - block: # Bug #20083 - # These test that `getEnv`, `putEnv` and `existsEnv` handle Unicode - # characters correctly. This means that module X in the process calling the - # CRT environment variable API will get the correct string. Raw CRT API - # calls below represent module X. - - # Getting an env. var. with unicode characters returns the correct UTF-8 - # encoded string. - block: - const envName = "twin_envvars1" - doAssert c_wputenv(newWideCString(envName & "=" & unicodeUtf8)) == 0 - doAssert existsEnv(envName) - doAssert getEnv(envName) == unicodeUtf8 - - # Putting an env. var. with unicode characters gives the correct UTF-16 - # encoded string from low-level routine. - block: - const envName = "twin_envvars2" - putEnv(envName, unicodeUtf8) - doAssert $c_wgetenv(envName.newWideCString) == unicodeUtf8 - - # Env. name containing Unicode characters is retrieved correctly - block: - const envName = unicodeUtf8 & "1" - doAssert c_wputenv(newWideCString(envName & "=" & unicodeUtf8)) == 0 - doAssert existsEnv(envName) - doAssert getEnv(envName) == unicodeUtf8 - - # Env. name containing Unicode characters is set correctly - block: - const envName = unicodeUtf8 & "2" - putEnv(envName, unicodeUtf8) - doAssert existsEnv(envName) - doAssert $c_wgetenv(envName.newWideCString) == unicodeUtf8 - - # Env. name containing Unicode characters and empty value is set correctly - block: - const envName = unicodeUtf8 & "3" - putEnv(envName, "") - doAssert existsEnv(envName) - doAssert $c_wgetenv(envName.newWideCString) == "" - - # It's hard to test on Windows code pages, because there is no "change - # a process' locale" API. - if getCurrentEncoding(true) == "windows-1252": - const - unicodeAnsi = "\xc6" # `unicodeUtf8` in `windows-1252` encoding - - # Test that env. var. ANSI API has correct encoding - block: - const - envName = unicodeUtf8 & "4" - envNameAnsi = unicodeAnsi & "4" - putEnv(envName, unicodeUtf8) - doAssert $c_getenv(envNameAnsi.cstring) == unicodeAnsi - - block: - const - envName = unicodeUtf8 & "5" - envNameAnsi = unicodeAnsi & "5" - doAssert c_putenv((envNameAnsi & "=" & unicodeAnsi).cstring) == 0 - doAssert getEnv(envName) == unicodeUtf8 - - # Env. name containing Unicode characters and empty value is set correctly; - # and, if env. name. characters cannot be represented in codepage, don't - # raise an error. - # - # `win_setenv.nim` converts UTF-16 to ANSI when setting empty env. var. The - # windows-1250 locale has no representation of `abreveUtf8` below, so the - # conversion will fail, but this must not be fatal. It is expected that the - # routine ignores updating MBCS environment (`environ` global) and carries - # on. - block: - const - # "LATIN SMALL LETTER A WITH BREVE" in UTF-8 - abreveUtf8 = "\xc4\x83" - envName = abreveUtf8 & "6" - putEnv(envName, "") - doAssert existsEnv(envName) - doAssert $c_wgetenv(envName.newWideCString) == "" - doAssert getEnv(envName) == "" diff --git a/tests/stdlib/texitprocs.nim b/tests/stdlib/texitprocs.nim deleted file mode 100644 index 9d5378fe8..000000000 --- a/tests/stdlib/texitprocs.nim +++ /dev/null @@ -1,21 +0,0 @@ -discard """ -targets: "c cpp js" -output: ''' -ok4 -ok3 -ok2 -ok1 -''' -""" - -import std/exitprocs - -proc fun1() {.noconv.} = echo "ok1" -proc fun2() = echo "ok2" -proc fun3() {.noconv.} = echo "ok3" -proc fun4() = echo "ok4" - -addExitProc(fun1) -addExitProc(fun2) -addExitProc(fun3) -addExitProc(fun4) diff --git a/tests/stdlib/tfdleak.nim b/tests/stdlib/tfdleak.nim deleted file mode 100644 index 1ac746e48..000000000 --- a/tests/stdlib/tfdleak.nim +++ /dev/null @@ -1,152 +0,0 @@ -discard """ - exitcode: 0 - output: "" - matrix: "; -d:nimInheritHandles" - joinable: false -""" - -import os, osproc, strutils, nativesockets, net, selectors, memfiles, - asyncdispatch, asyncnet - -import std/[assertions, syncio] - -when defined(windows): - import winlean - - # Note: Windows 10-only API - proc compareObjectHandles(first, second: Handle): WINBOOL - {.stdcall, dynlib: "kernelbase", - importc: "CompareObjectHandles".} -else: - import posix - -proc leakCheck(f: AsyncFD | int | FileHandle | SocketHandle, msg: string, - expectLeak = defined(nimInheritHandles)) = - var args = @[$f.int, msg, $expectLeak] - - when defined(windows): - var refFd: Handle - # NOTE: This function shouldn't be used to duplicate sockets, - # as this function may mess with the socket internal refcounting. - # but due to the lack of type segmentation in the stdlib for - # Windows (AsyncFD can be a file or a socket), we will have to - # settle with this. - # - # Now, as a poor solution for the refcounting problem, we just - # simply let the duplicated handle leak. This should not interfere - # with the test since new handles can't occupy the slot held by - # the leaked ones. - if duplicateHandle(getCurrentProcess(), f.Handle, - getCurrentProcess(), addr refFd, - 0, 1, DUPLICATE_SAME_ACCESS) == 0: - raiseOSError osLastError(), "Couldn't create the reference handle" - args.add $refFd - - discard startProcess( - getAppFilename(), - args = args, - options = {poParentStreams} - ).waitForExit - -proc isValidHandle(f: int): bool = - ## Check if a handle is valid. Requires OS-native handles. - when defined(windows): - var flags: DWORD - result = getHandleInformation(f.Handle, addr flags) != 0 - else: - result = fcntl(f.cint, F_GETFD) != -1 - -proc main() = - if paramCount() == 0: - # Parent process - let f = syncio.open("__test_fdleak", fmReadWrite) - defer: close f - - leakCheck(f.getOsFileHandle, "system.open()") - - doAssert f.reopen("__test_fdleak2", fmReadWrite), "reopen failed" - - leakCheck(f.getOsFileHandle, "reopen") - - let sock = createNativeSocket() - defer: close sock - leakCheck(sock, "createNativeSocket()") - if sock.setInheritable(not defined(nimInheritHandles)): - leakCheck(sock, "createNativeSocket()", not defined(nimInheritHandles)) - else: - raiseOSError osLastError() - - let server = newSocket() - defer: close server - server.bindAddr(address = "127.0.0.1") - server.listen() - let (_, port) = server.getLocalAddr - - leakCheck(server.getFd, "newSocket()") - - let client = newSocket() - defer: close client - client.connect("127.0.0.1", port) - - var input: Socket - server.accept(input) - - leakCheck(input.getFd, "accept()") - - # ioselectors_select doesn't support returning a handle. - when not defined(windows): - let selector = newSelector[int]() - leakCheck(selector.getFd, "selector()", false) - - var mf = memfiles.open("__test_fdleak3", fmReadWrite, newFileSize = 1) - defer: close mf - when defined(windows): - leakCheck(mf.mapHandle, "memfiles.open().mapHandle", false) - else: - leakCheck(mf.handle, "memfiles.open().handle", false) - - let sockAsync = createAsyncNativeSocket() - defer: closeSocket sockAsync - leakCheck(sockAsync, "createAsyncNativeSocket()") - if sockAsync.setInheritable(not defined(nimInheritHandles)): - leakCheck(sockAsync, "createAsyncNativeSocket()", not defined(nimInheritHandles)) - else: - raiseOSError osLastError() - - let serverAsync = newAsyncSocket() - defer: close serverAsync - serverAsync.bindAddr(address = "127.0.0.1") - serverAsync.listen() - let (_, portAsync) = serverAsync.getLocalAddr - - leakCheck(serverAsync.getFd, "newAsyncSocket()") - - let clientAsync = newAsyncSocket() - defer: close clientAsync - waitFor clientAsync.connect("127.0.0.1", portAsync) - - let inputAsync = waitFor serverAsync.accept() - - leakCheck(inputAsync.getFd, "accept() async") - else: - let - fd = parseInt(paramStr 1) - expectLeak = parseBool(paramStr 3) - msg = (if expectLeak: "not " else: "") & "leaked " & paramStr 2 - let validHandle = - when defined(windows): - # On Windows, due to the use of winlean, causes the program to open - # a handle to the various dlls that's loaded. This handle might - # collide with the handle sent for testing. - # - # As a walkaround, we pass an another handle that's purposefully leaked - # as a reference so that we can verify whether the "leaked" handle - # is the right one. - let refFd = parseInt(paramStr 4) - fd.isValidHandle and compareObjectHandles(fd, refFd) != 0 - else: - fd.isValidHandle - if expectLeak xor validHandle: - echo msg - -when isMainModule: main() diff --git a/tests/stdlib/tfdleak_multiple.nim b/tests/stdlib/tfdleak_multiple.nim deleted file mode 100644 index c26681217..000000000 --- a/tests/stdlib/tfdleak_multiple.nim +++ /dev/null @@ -1,31 +0,0 @@ -discard """ -joinable: false -""" - -import os, osproc, strutils -import std/assertions - -const Iterations = 200 - -proc testFdLeak() = - var count = 0 - let - test = getAppDir() / "tfdleak" - exe = test.addFileExt(ExeExt).quoteShell - options = ["", "-d:nimInheritHandles"] - for opt in options: - let - run = "nim c $1 $2" % [opt, quoteShell test] - (output, status) = execCmdEx run - doAssert status == 0, "Test complination failed:\n$1\n$2" % [run, output] - for i in 1..Iterations: - let (output, status) = execCmdEx exe - doAssert status == 0, "Execution of " & exe & " failed" - if "leaked" in output: - count.inc - doAssert count == 0, "Leaked " & $count & " times" - -when defined(windows): - # tfdleak was only flaky for windows (and for netbsd, there is still a bug) - # note that this test is quite slow, 87 sec on windows. - testFdLeak() diff --git a/tests/stdlib/tfenv.nim b/tests/stdlib/tfenv.nim deleted file mode 100644 index a486b8a9d..000000000 --- a/tests/stdlib/tfenv.nim +++ /dev/null @@ -1,8 +0,0 @@ -import std/fenv -import std/assertions - - -func is_significant(x: float): bool = - x > minimumPositiveValue(float) and x < maximumPositiveValue(float) - -doAssert is_significant(10.0) diff --git a/tests/stdlib/tfilesanddirs.nim b/tests/stdlib/tfilesanddirs.nim deleted file mode 100644 index a1920d4f2..000000000 --- a/tests/stdlib/tfilesanddirs.nim +++ /dev/null @@ -1,36 +0,0 @@ -import std/[paths, files, dirs, appdirs] - -from stdtest/specialpaths import buildDir -import std/[syncio, assertions] - -block fileOperations: - let files = @[Path"these.txt", Path"are.x", Path"testing.r", Path"files.q"] - let dirs = @[Path"some", Path"created", Path"test", Path"dirs"] - - let dname = Path"__really_obscure_dir_name" - - createDir(dname.Path) - doAssert dirExists(Path(dname)) - - # Test creating files and dirs - for dir in dirs: - createDir(Path(dname/dir)) - doAssert dirExists(Path(dname/dir)) - - for file in files: - let fh = open(string(dname/file), fmReadWrite) # createFile - fh.close() - doAssert fileExists(Path(dname/file)) - -block: # getCacheDir - doAssert getCacheDir().dirExists - -block: # moveFile - let tempDir = getTempDir() / Path("D20221022T151608") - createDir(tempDir) - defer: removeDir(tempDir) - -block: # moveDir - let tempDir = getTempDir() / Path("D20220609T161443") - createDir(tempDir) - defer: removeDir(tempDir) diff --git a/tests/stdlib/tfrexp1.nim b/tests/stdlib/tfrexp1.nim index 6b4c3b6d3..a32ecbc23 100644 --- a/tests/stdlib/tfrexp1.nim +++ b/tests/stdlib/tfrexp1.nim @@ -1,9 +1,9 @@ discard """ - targets: "js c cpp" + targets: "js c c++" + output: '''ok''' """ -import std/math -import std/assertions +import math const manualTest = false @@ -41,14 +41,6 @@ when manualTest: frexp_test(-1000.0, 1000.0, 0.0125) else: - frexp_test(-200000.0, 200000.0, 0.125) + frexp_test(-1000000.0, 1000000.0, 0.125) - -doAssert frexp(8.0) == (0.5, 4) -doAssert frexp(-8.0) == (-0.5, 4) -doAssert frexp(0.0) == (0.0, 0) - -block: - var x: int - doAssert frexp(5.0, x) == 0.625 - doAssert x == 3 +echo "ok" diff --git a/tests/stdlib/tgenast.nim b/tests/stdlib/tgenast.nim deleted file mode 100644 index d99c9312e..000000000 --- a/tests/stdlib/tgenast.nim +++ /dev/null @@ -1,274 +0,0 @@ -discard """ - matrix: "--mm:orc; --mm:refc" -""" - -# xxx also test on js - -import std/genasts -import std/macros -from std/strformat import `&` -import std/assertions -import ./mgenast - -proc main = - block: - macro bar(x0: static Foo, x1: Foo, x2: Foo, xignored: Foo): untyped = - let s0 = "not captured!" - let s1 = "not captured!" - let xignoredLocal = kfoo4 - - # newLit optional: - let x3 = newLit kfoo4 - let x3b = kfoo4 - - result = genAstOpt({kDirtyTemplate}, s1=true, s2="asdf", x0, x1=x1, x2, x3, x3b): - doAssert not declared(xignored) - doAssert not declared(xignoredLocal) - (s1, s2, s0, x0, x1, x2, x3, x3b) - - let s0 = "caller scope!" - - doAssert bar(kfoo1, kfoo2, kfoo3, kfoo4) == - (true, "asdf", "caller scope!", kfoo1, kfoo2, kfoo3, kfoo4, kfoo4) - - block: - # doesn't have limitation mentioned in https://github.com/nim-lang/RFCs/issues/122#issue-401636535 - macro abc(name: untyped): untyped = - result = genAst(name): - type name = object - - abc(Bar) - doAssert Bar.default == Bar() - - block: - # backticks parser limitations / ambiguities not are an issue with `genAst`: - # (#10326 #9745 are fixed but `quote do` still has underlying ambiguity issue - # with backticks) - type Foo = object - a: int - - macro m1(): untyped = - # result = quote do: # Error: undeclared identifier: 'a1' - result = genAst: - template `a1=`(x: var Foo, val: int) = - x.a = val - - m1() - var x0: Foo - x0.a1 = 10 - doAssert x0 == Foo(a: 10) - - block: - # avoids bug #7375 - macro fun(b: static[bool], b2: bool): untyped = - result = newStmtList() - macro foo(c: bool): untyped = - var b = false - result = genAst(b, c): - fun(b, c) - - foo(true) - - block: - # avoids bug #7589 - # since `==` works with genAst, the problem goes away - macro foo2(): untyped = - # result = quote do: # Error: '==' cannot be passed to a procvar - result = genAst: - `==`(3,4) - doAssert not foo2() - - block: - # avoids bug #7726 - # expressions such as `a.len` are just passed as arguments to `genAst`, and - # caller scope is not polluted with definitions such as `let b = newLit a.len` - macro foo(): untyped = - let a = @[1, 2, 3, 4, 5] - result = genAst(a, b = a.len): # shows 2 ways to get a.len - (a.len, b) - doAssert foo() == (5, 5) - - block: - # avoids bug #9607 - proc fun1(info:LineInfo): string = "bar1" - proc fun2(info:int): string = "bar2" - - macro bar2(args: varargs[untyped]): untyped = - let info = args.lineInfoObj - let fun1 = bindSym"fun1" # optional; we can remove this and also the - # capture of fun1, as show in next example - result = genAst(info, fun1): - (fun1(info), fun2(info.line)) - doAssert bar2() == ("bar1", "bar2") - - macro bar3(args: varargs[untyped]): untyped = - let info = args.lineInfoObj - result = genAst(info): - (fun1(info), fun2(info.line)) - doAssert bar3() == ("bar1", "bar2") - - macro bar(args: varargs[untyped]): untyped = - let info = args.lineInfoObj - let fun1 = bindSym"fun1" - let fun2 = bindSym"fun2" - result = genAstOpt({kDirtyTemplate}, info): - (fun1(info), fun2(info.line)) - doAssert bar() == ("bar1", "bar2") - - block: - # example from bug #7889 works - # after changing method call syntax to regular call syntax; this is a - # limitation described in bug #7085 - # note that `quote do` would also work after that change in this example. - doAssert bindme2() == kfoo1 - doAssert bindme3() == kfoo1 - doAssert not compiles(bindme4()) # correctly gives Error: undeclared identifier: 'myLocalPriv' - proc myLocalPriv2(): auto = kfoo2 - doAssert bindme5UseExpose() == kfoo1 - - # example showing hijacking behavior when using `kDirtyTemplate` - doAssert bindme5UseExposeFalse() == kfoo2 - # local `myLocalPriv2` hijacks symbol `mgenast.myLocalPriv2`. In most - # use cases this is probably not what macro writer intends as it's - # surprising; hence `kDirtyTemplate` is not the default. - - when nimvm: # disabled because `newStringStream` is used - discard - else: - bindme6UseExpose() - bindme6UseExposeFalse() - - block: - macro mbar(x3: Foo, x3b: static Foo): untyped = - var x1=kfoo3 - var x2=newLit kfoo3 - var x4=kfoo3 - var xLocal=kfoo3 - - proc funLocal(): auto = kfoo4 - - result = genAst(x1, x2, x3, x4): - # local x1 overrides remote x1 - when false: - # one advantage of using `kDirtyTemplate` is that these would hold: - doAssert not declared xLocal - doAssert not compiles(echo xLocal) - # however, even without it, we at least correctly generate CT error - # if trying to use un-captured symbol; this correctly gives: - # Error: internal error: environment misses: xLocal - echo xLocal - - proc foo1(): auto = - # note that `funLocal` is captured implicitly, according to hygienic - # template rules; with `kDirtyTemplate` it would not unless - # captured in `genAst` capture list explicitly - (a0: xRemote, a1: x1, a2: x2, a3: x3, a4: x4, a5: funLocal()) - - return result - - proc main()= - var xRemote=kfoo1 - var x1=kfoo2 - mbar(kfoo4, kfoo4) - doAssert foo1() == (a0: kfoo1, a1: kfoo3, a2: kfoo3, a3: kfoo4, a4: kfoo3, a5: kfoo4) - - main() - - block: - # With `kDirtyTemplate`, the example from #8220 works. - # See https://nim-lang.github.io/Nim/strformat.html#limitations for - # an explanation of why {.dirty.} is needed. - macro foo(): untyped = - result = genAstOpt({kDirtyTemplate}): - let bar = "Hello, World" - &"Let's interpolate {bar} in the string" - doAssert foo() == "Let's interpolate Hello, World in the string" - - - block: # nested application of genAst - macro createMacro(name, obj, field: untyped): untyped = - result = genAst(obj = newDotExpr(obj, field), lit = 10, name, field): - # can't reuse `result` here, would clash - macro name(arg: untyped): untyped = - genAst(arg2=arg): # somehow `arg2` rename is needed - (obj, astToStr(field), lit, arg2) - - var x = @[1, 2, 3] - createMacro foo, x, len - doAssert (foo 20) == (3, "len", 10, 20) - - block: # test with kNoNewLit - macro bar(): untyped = - let s1 = true - template boo(x): untyped = - fun(x) - result = genAstOpt({kNoNewLit}, s1=newLit(s1), s1b=s1): (s1, s1b) - doAssert bar() == (true, 1) - - block: # sanity check: check passing `{}` also works - macro bar(): untyped = - result = genAstOpt({}, s1=true): s1 - doAssert bar() == true - - block: # test passing function and type symbols - proc z1(): auto = 41 - type Z4 = type(1'i8) - macro bar(Z1: typedesc): untyped = - proc z2(): auto = 42 - proc z3[T](a: T): auto = 43 - let Z2 = genAst(): - type(true) - let z4 = genAst(): - proc myfun(): auto = 44 - myfun - type Z3 = type(1'u8) - result = genAst(z4, Z1, Z2): - # z1, z2, z3, Z3, Z4 are captured automatically - # z1, z2, z3 can optionally be specified in capture list - (z1(), z2(), z3('a'), z4(), $Z1, $Z2, $Z3, $Z4) - type Z1 = type('c') - doAssert bar(Z1) == (41, 42, 43, 44, "char", "bool", "uint8", "int8") - - block: # fix bug #11986 - proc foo(): auto = - var s = { 'a', 'b' } - # var n = quote do: `s` # would print {97, 98} - var n = genAst(s): s - n.repr - static: doAssert foo() == "{'a', 'b'}" - - block: # also from #11986 - macro foo(): untyped = - var s = { 'a', 'b' } - # quote do: - # let t = `s` - # $typeof(t) # set[range 0..65535(int)] - genAst(s): - let t = s - $typeof(t) - doAssert foo() == "set[char]" - - block: - macro foo(): untyped = - type Foo = object - template baz2(a: int): untyped = a*10 - macro baz3(a: int): untyped = newLit 13 - result = newStmtList() - - result.add genAst(Foo, baz2, baz3) do: # shows you can pass types, templates etc - var x: Foo - $($typeof(x), baz2(3), baz3(4)) - - let ret = genAst() do: # shows you don't have to, since they're inject'd - var x: Foo - $($typeof(x), baz2(3), baz3(4)) - doAssert foo() == """("Foo", 30, 13)""" - - block: # illustrates how symbol visiblity can be controlled precisely using `mixin` - proc locafun1(): auto = "in locafun1 (caller scope)" # this will be used because of `mixin locafun1` => explicit hijacking is ok - proc locafun2(): auto = "in locafun2 (caller scope)" # this won't be used => no hijacking - proc locafun3(): auto = "in locafun3 (caller scope)" - doAssert mixinExample() == ("in locafun1 (caller scope)", "in locafun2", "in locafun3 (caller scope)") - -static: main() -main() diff --git a/tests/stdlib/tgetaddrinfo.nim b/tests/stdlib/tgetaddrinfo.nim index a8bcecb0c..225546aa9 100644 --- a/tests/stdlib/tgetaddrinfo.nim +++ b/tests/stdlib/tgetaddrinfo.nim @@ -6,7 +6,6 @@ discard """ # bug: https://github.com/nim-lang/Nim/issues/10198 import nativesockets -import std/assertions block DGRAM_UDP: let aiList = getAddrInfo("127.0.0.1", 999.Port, AF_INET, SOCK_DGRAM, IPPROTO_UDP) @@ -16,7 +15,7 @@ block DGRAM_UDP: doAssert aiList.ai_next == nil freeAddrInfo aiList -when defined(posix) and not defined(haiku) and not defined(freebsd) and not defined(openbsd) and not defined(netbsd): +when defined(posix) and not defined(haiku) and not defined(freebsd): block RAW_ICMP: # the port will be ignored diff --git a/tests/stdlib/tgetfileinfo.nim b/tests/stdlib/tgetfileinfo.nim index d0413f757..d5ccdea56 100644 --- a/tests/stdlib/tgetfileinfo.nim +++ b/tests/stdlib/tgetfileinfo.nim @@ -1,10 +1,8 @@ discard """ output: "pcDir\npcFile\npcLinkToDir\npcLinkToFile\n" - joinable: false """ import os, strutils -import std/[syncio, assertions] # Cases # 1 - String : Existing File : Symlink true # 2 - String : Existing File : Symlink false @@ -22,7 +20,7 @@ proc genBadFileName(limit = 100): string = var hitLimit = true for i in 0..100: - if fileExists(result): + if existsFile(result): result.add("a") else: hitLimit = false @@ -127,37 +125,10 @@ proc testGetFileInfo = echo pcLinkToDir echo pcLinkToFile - doAssert dirInfo.isSpecial == false - doAssert fileInfo.isSpecial == false - when defined(posix): - doAssert linkDirInfo.isSpecial == false - doAssert linkFileInfo.isSpecial == false - removeDir(dirPath) removeFile(filePath) when defined(posix): removeFile(linkDirPath) removeFile(linkFilePath) - # Test that `isSpecial` is set correctly - block: - when defined(posix): - let - tmp = getTempDir() - fifoPath = tmp / "test-fifo" - linkFifoPath = tmp / "test-link-fifo" - - doAssert execShellCmd("mkfifo " & fifoPath) == 0 - createSymlink(fifoPath, linkFifoPath) - - let - fifoInfo = getFileInfo(fifoPath) - linkFifoInfo = getFileInfo(linkFifoPath) - - doAssert fifoInfo.isSpecial == true - doAssert linkFifoInfo.isSpecial == true - - removeFile(fifoPath) - removeFile(linkFifoPath) - testGetFileInfo() diff --git a/tests/stdlib/tgetprotobyname.nim b/tests/stdlib/tgetprotobyname.nim deleted file mode 100644 index e524510b2..000000000 --- a/tests/stdlib/tgetprotobyname.nim +++ /dev/null @@ -1,15 +0,0 @@ -import nativesockets -import std/assertions - -doAssert getProtoByName("ipv6") == 41 -doAssert getProtoByName("tcp") == 6 -doAssert getProtoByName("udp") == 17 -doAssert getProtoByName("icmp") == 1 -doAssert getProtoByName("ipv6-icmp") == 58 - -when defined(windows): - doAssertRaises(OSError): - discard getProtoByName("raw") - -doAssertRaises(OSError): - discard getProtoByName("Error") diff --git a/tests/stdlib/tglobs.nim b/tests/stdlib/tglobs.nim deleted file mode 100644 index 69ff31938..000000000 --- a/tests/stdlib/tglobs.nim +++ /dev/null @@ -1,21 +0,0 @@ -import std/private/globs -import std/assertions - -template main = - when defined(windows): - doAssert nativeToUnixPath("C:") == "/C" - doAssert nativeToUnixPath(r"D:\") == "/D/" - doAssert nativeToUnixPath(r"E:\a") == "/E/a" - doAssert nativeToUnixPath(r"E:\a1\") == "/E/a1/" - doAssert nativeToUnixPath(r"E:\a1\bc") == "/E/a1/bc" - doAssert nativeToUnixPath(r"\a1\bc") == "/a1/bc" - doAssert nativeToUnixPath(r"a1\bc") == "a1/bc" - doAssert nativeToUnixPath("a1") == "a1" - doAssert nativeToUnixPath("") == "" - doAssert nativeToUnixPath(".") == "." - doAssert nativeToUnixPath("..") == ".." - doAssert nativeToUnixPath(r"..\") == "../" - doAssert nativeToUnixPath(r"..\..\.\") == "../.././" - -static: main() -main() diff --git a/tests/stdlib/thashes.nim b/tests/stdlib/thashes.nim index caae79213..2cd1e4e47 100644 --- a/tests/stdlib/thashes.nim +++ b/tests/stdlib/thashes.nim @@ -1,224 +1,17 @@ + discard """ - targets: "c cpp js" +output: ''' +[Suite] hashes + +[Suite] hashing + +''' """ -import std/hashes -from stdtest/testutils import disableVm, whenVMorJs -import std/assertions +import unittest, hashes -when not defined(js) and not defined(cpp): - block: - var x = 12 - iterator hello(): int {.closure.} = - yield x - - discard hash(hello) - -block hashes: - block hashing: - var dummy = 0.0 - doAssert hash(dummy) == hash(-dummy) - - # "VM and runtime should make the same hash value (hashIdentity)" - block: - const hi123 = hashIdentity(123) - doAssert hashIdentity(123) == hi123 - - # "VM and runtime should make the same hash value (hashWangYi1)" - block: - const wy123 = hashWangYi1(123) - doAssert wy123 != 0 - doAssert hashWangYi1(123) == wy123 - - - # "hashIdentity value incorrect at 456" - block: - doAssert hashIdentity(456) == 456 - - # "hashWangYi1 value incorrect at 456" - block: - when Hash.sizeof < 8: - doAssert hashWangYi1(456) == 1293320666 - else: - doAssert hashWangYi1(456) == -6421749900419628582 - -block empty: - var - a = "" - b = newSeq[char]() - c = newSeq[int]() - d = cstring"" - e = "abcd" - doAssert hash(a) == 0 - doAssert hash(b) == 0 - doAssert hash(c) == 0 - doAssert hash(d) == 0 - doAssert hashIgnoreCase(a) == 0 - doAssert hashIgnoreStyle(a) == 0 - doAssert hash(e, 3, 2) == 0 - -block sameButDifferent: - doAssert hash("aa bb aaaa1234") == hash("aa bb aaaa1234", 0, 13) - doAssert hash("aa bb aaaa1234") == hash(cstring"aa bb aaaa1234") - doAssert hashIgnoreCase("aA bb aAAa1234") == hashIgnoreCase("aa bb aaaa1234") - doAssert hashIgnoreStyle("aa_bb_AAaa1234") == hashIgnoreCase("aaBBAAAa1234") - -block smallSize: # no multibyte hashing - let - xx = @['H', 'i'] - ii = @[72'u8, 105] - ss = "Hi" - doAssert hash(xx) == hash(ii) - doAssert hash(xx) == hash(ss) - doAssert hash(xx) == hash(xx, 0, xx.high) - doAssert hash(ss) == hash(ss, 0, ss.high) - -block largeSize: # longer than 4 characters - let - xx = @['H', 'e', 'l', 'l', 'o'] - xxl = @['H', 'e', 'l', 'l', 'o', 'w', 'e', 'e', 'n', 's'] - ssl = "Helloweens" - doAssert hash(xxl) == hash(ssl) - doAssert hash(xxl) == hash(xxl, 0, xxl.high) - doAssert hash(ssl) == hash(ssl, 0, ssl.high) - doAssert hash(xx) == hash(xxl, 0, 4) - doAssert hash(xx) == hash(ssl, 0, 4) - doAssert hash(xx, 0, 3) == hash(xxl, 0, 3) - doAssert hash(xx, 0, 3) == hash(ssl, 0, 3) - -proc main() = - doAssert hash(0.0) == hash(0) - # bug #16061 - doAssert hash(cstring"abracadabra") == 97309975 - doAssert hash(cstring"abracadabra") == hash("abracadabra") - - when sizeof(int) == 8 or defined(js): - block: - var s: seq[Hash] - for a in [0.0, 1.0, -1.0, 1000.0, -1000.0]: - let b = hash(a) - doAssert b notin s - s.add b - when defined(js): - doAssert hash(0.345602) == 2035867618 - doAssert hash(234567.45) == -20468103 - doAssert hash(-9999.283456) == -43247422 - doAssert hash(84375674.0) == 707542256 - else: - doAssert hash(0.345602) == 387936373221941218 - doAssert hash(234567.45) == -8179139172229468551 - doAssert hash(-9999.283456) == 5876943921626224834 - doAssert hash(84375674.0) == 1964453089107524848 - else: - doAssert hash(0.345602) != 0 - doAssert hash(234567.45) != 0 - doAssert hash(-9999.283456) != 0 - doAssert hash(84375674.0) != 0 - - block: # bug #16555 - proc fn(): auto = - # avoids hardcoding values - var a = "abc\0def" - var b = a.cstring - result = (hash(a), hash(b)) - doAssert result[0] != result[1] - when not defined(js): - doAssert fn() == static(fn()) - else: - # xxx this is a tricky case; consistency of hashes for cstring's containing - # '\0\' matters for c backend but less for js backend since such strings - # are much less common in js backend; we make vm for js backend consistent - # with c backend instead of js backend because FFI code (or other) could - # run at CT, expecting c semantics. - discard - - block: # hash(object) - type - Obj = object - x: int - y: string - Obj2[T] = object - x: int - y: string - Obj3 = object - x: int - y: string - Obj4 = object - case t: bool - of false: - x: int - of true: - y: int - z: int - Obj5 = object - case t: bool - of false: - x: int - of true: - y: int - z: int - - proc hash(a: Obj2): Hash = hash(a.x) - proc hash(a: Obj3): Hash = hash((a.x,)) - proc hash(a: Obj5): Hash = - case a.t - of false: hash(a.x) - of true: hash(a.y) - - doAssert hash(Obj(x: 520, y: "Nim")) != hash(Obj(x: 520, y: "Nim2")) - doAssert hash(Obj2[float](x: 520, y: "Nim")) == hash(Obj2[float](x: 520, y: "Nim2")) - doAssert hash(Obj2[float](x: 520, y: "Nim")) != hash(Obj2[float](x: 521, y: "Nim2")) - doAssert hash(Obj3(x: 520, y: "Nim")) == hash(Obj3(x: 520, y: "Nim2")) - - doAssert hash(Obj4(t: false, x: 1)) == hash(Obj4(t: false, x: 1)) - doAssert hash(Obj4(t: false, x: 1)) != hash(Obj4(t: false, x: 2)) - doAssert hash(Obj4(t: false, x: 1)) != hash(Obj4(t: true, y: 1)) - - doAssert hash(Obj5(t: false, x: 1)) != hash(Obj5(t: false, x: 2)) - doAssert hash(Obj5(t: false, x: 1)) == hash(Obj5(t: true, y: 1)) - doAssert hash(Obj5(t: false, x: 1)) != hash(Obj5(t: true, y: 2)) - - block: # hash(ref|ptr|pointer) - var a: array[10, uint8] - # disableVm: - whenVMorJs: - # pending fix proposed in https://github.com/nim-lang/Nim/issues/15952#issuecomment-786312417 - discard - do: - doAssert a[0].addr.hash != a[1].addr.hash - doAssert cast[pointer](a[0].addr).hash == a[0].addr.hash - - block: # hash(ref) - type A = ref object - x: int - let a = A(x: 3) - disableVm: # xxx Error: VM does not support 'cast' from tyRef to tyPointer - let ha = a.hash - doAssert ha != A(x: 3).hash # A(x: 3) is a different ref object from `a`. - a.x = 4 - doAssert ha == a.hash # the hash only depends on the address - - block: # hash(proc) - proc fn(a: int): auto = a*2 - doAssert fn isnot "closure" - doAssert fn is (proc) - const fn2 = fn - let fn3 = fn - whenVMorJs: discard - do: - doAssert hash(fn2) == hash(fn) - doAssert hash(fn3) == hash(fn) - - block: # hash(closure) - proc outer() = - var a = 0 - proc inner() = a.inc - doAssert inner is "closure" - let inner2 = inner - whenVMorJs: discard - do: - doAssert hash(inner2) == hash(inner) - outer() - -static: main() -main() +suite "hashes": + suite "hashing": + test "0.0 and -0.0 should have the same hash value": + var dummy = 0.0 + check hash(dummy) == hash(-dummy) diff --git a/tests/stdlib/theapqueue.nim b/tests/stdlib/theapqueue.nim deleted file mode 100644 index bb40b6f93..000000000 --- a/tests/stdlib/theapqueue.nim +++ /dev/null @@ -1,102 +0,0 @@ -import std/heapqueue -import std/assertions - -proc toSortedSeq[T](h: HeapQueue[T]): seq[T] = - var tmp = h - result = @[] - while tmp.len > 0: - result.add(pop(tmp)) - -proc heapProperty[T](h: HeapQueue[T]): bool = - for k in 0 .. h.len - 2: # the last element is always a leaf - let left = 2 * k + 1 - if left < h.len and h[left] < h[k]: - return false - let right = left + 1 - if right < h.len and h[right] < h[k]: - return false - true - -template main() = - block: # simple sanity test - var heap = initHeapQueue[int]() - let data = [1, 3, 5, 7, 9, 2, 4, 6, 8, 0] - for item in data: - push(heap, item) - doAssert(heap == data.toHeapQueue) - doAssert(heap[0] == 0) - doAssert(heap.toSortedSeq == @[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) - - block: # test del - var heap = initHeapQueue[int]() - let data = [1, 3, 5, 7, 9, 2, 4, 6, 8, 0] - for item in data: push(heap, item) - - heap.del(0) - doAssert(heap[0] == 1) - - heap.del(heap.find(7)) - doAssert(heap.toSortedSeq == @[1, 2, 3, 4, 5, 6, 8, 9]) - - heap.del(heap.find(5)) - doAssert(heap.toSortedSeq == @[1, 2, 3, 4, 6, 8, 9]) - - heap.del(heap.find(6)) - doAssert(heap.toSortedSeq == @[1, 2, 3, 4, 8, 9]) - - heap.del(heap.find(2)) - doAssert(heap.toSortedSeq == @[1, 3, 4, 8, 9]) - - doAssert(heap.find(2) == -1) - - block: # test del last - var heap = initHeapQueue[int]() - let data = [1, 2, 3] - for item in data: push(heap, item) - - heap.del(2) - doAssert(heap.toSortedSeq == @[1, 2]) - - heap.del(1) - doAssert(heap.toSortedSeq == @[1]) - - heap.del(0) - doAssert(heap.toSortedSeq == @[]) - - block: # testing the heap proeprty - var heap = [1, 4, 2, 5].toHeapQueue - doAssert heapProperty(heap) - - heap.push(42) - doAssert heapProperty(heap) - heap.push(0) - doAssert heapProperty(heap) - heap.push(3) - doAssert heapProperty(heap) - heap.push(3) - doAssert heapProperty(heap) - - # [0, 3, 1, 4, 42, 2, 3, 5] - - discard heap.pop() - doAssert heapProperty(heap) - discard heap.pop() - doAssert heapProperty(heap) - - heap.del(2) - doAssert heapProperty(heap) - - # [2, 3, 5, 4, 42] - - discard heap.replace(12) - doAssert heapProperty(heap) - discard heap.replace(1) - doAssert heapProperty(heap) - - discard heap.pushpop(2) - doAssert heapProperty(heap) - discard heap.pushpop(0) - doAssert heapProperty(heap) - -static: main() -main() diff --git a/tests/stdlib/thighlite.nim b/tests/stdlib/thighlite.nim deleted file mode 100644 index d88bc7fec..000000000 --- a/tests/stdlib/thighlite.nim +++ /dev/null @@ -1,42 +0,0 @@ - -import unittest, strutils -import ../../lib/packages/docutils/highlite -import std/objectdollar - -block: # Nim tokenizing - test "string literals and escape seq": - check("\"ok1\\nok2\\nok3\"".tokenize(langNim) == - @[("\"ok1", gtStringLit), ("\\n", gtEscapeSequence), ("ok2", gtStringLit), - ("\\n", gtEscapeSequence), ("ok3\"", gtStringLit) - ]) - check("\"\"\"ok1\\nok2\\nok3\"\"\"".tokenize(langNim) == - @[("\"\"\"ok1\\nok2\\nok3\"\"\"", gtLongStringLit) - ]) - - test "whitespace at beginning of line is preserved": - check(" discard 1".tokenize(langNim) == - @[(" ", gtWhitespace), ("discard", gtKeyword), (" ", gtWhitespace), - ("1", gtDecNumber) - ]) - -block: # Cmd (shell) tokenizing - test "cmd with dollar and output": - check( - dedent""" - $ nim c file.nim - out: file [SuccessX]""" - .tokenize(langConsole) == - @[("$ ", gtPrompt), ("nim", gtProgram), - (" ", gtWhitespace), ("c", gtOption), (" ", gtWhitespace), - ("file.nim", gtIdentifier), ("\n", gtWhitespace), - ("out: file [SuccessX]", gtProgramOutput) - ]) - -block: # bug #21232 - let code = "/" - var toknizr: GeneralTokenizer - - initGeneralTokenizer(toknizr, code) - - getNextToken(toknizr, langC) - check $toknizr == """(kind: gtOperator, start: 0, length: 1, buf: "/", pos: 1, state: gtEof, lang: langC)""" diff --git a/tests/stdlib/thtmlparser.nim b/tests/stdlib/thtmlparser.nim index a27d41fe6..ccf2f6202 100644 --- a/tests/stdlib/thtmlparser.nim +++ b/tests/stdlib/thtmlparser.nim @@ -1,6 +1,6 @@ discard """ - targets: "c js" output: ''' +@[] true https://example.com/test?format=jpg&name=orig## https://example.com/test?format=jpg&name=orig##text @@ -11,7 +11,7 @@ import htmlparser import xmltree import strutils from streams import newStringStream -import std/assertions + block t2813: const @@ -40,14 +40,14 @@ block t2813: """ var errors: seq[string] = @[] let tree = parseHtml(newStringStream(html), "test.html", errors) - doAssert errors.len == 0 # Errors: expected,... + echo errors # Errors: expected,... var len = tree.findAll("tr").len # len = 6 var rows: seq[XmlNode] = @[] for n in tree.findAll("table"): n.findAll("tr", rows) # len = 2 break - doAssert tree.findAll("tr").len == rows.len + assert tree.findAll("tr").len == rows.len block t2814: @@ -110,21 +110,21 @@ block t6154: doAssert ps[0].attrsLen == 2 doAssert ps[0].attr("class") == "foo" doAssert ps[0].attr("id") == "bar" - doAssert ps[0].len == 0 + doassert ps[0].len == 0 doAssert ps[1].attrsLen == 1 doAssert ps[1].attr("something") == "\tfoo\tbar²" - doAssert ps[1].len == 0 + doassert ps[1].len == 0 doAssert ps[2].attrsLen == 2 doAssert ps[2].attr("something") == "\tfoo\tbar²" doAssert ps[2].attr("foo") == "bloo" - doAssert ps[2].len == 0 + doassert ps[2].len == 0 doAssert ps[3].attrsLen == 2 doAssert ps[3].attr("class") == "foo2" doAssert ps[3].attr("id") == "bar2" - doAssert ps[3].len == 0 + doassert ps[3].len == 0 doAssert ps[4].attrsLen == 1 doAssert ps[4].attr("wrong") == "" @@ -133,12 +133,12 @@ block t6154: doAssert ps[5].attr("data-foo") == "" doAssert ps[5].attr("data-bar") == "correct!" doAssert ps[5].attr("enabled") == "" - doAssert ps[5].len == 0 + doassert ps[5].len == 0 doAssert ps[6].attrsLen == 2 doAssert ps[6].attr("quux") == "" doAssert ps[6].attr("whatever") == "" - doAssert ps[6].len == 0 + doassert ps[6].len == 0 # bug #11713, #1034 var content = """ diff --git a/tests/stdlib/thttpclient.nim b/tests/stdlib/thttpclient.nim index c731c81b0..66fc123e3 100644 --- a/tests/stdlib/thttpclient.nim +++ b/tests/stdlib/thttpclient.nim @@ -1,30 +1,23 @@ discard """ cmd: "nim c --threads:on -d:ssl $file" - disabled: "openbsd" - disabled: "freebsd" - disabled: "windows" + exitcode: 0 + output: "OK" + disabled: true """ -#[ -disabled: see https://github.com/timotheecour/Nim/issues/528 -]# - import strutils from net import TimeoutError import nativesockets, os, httpclient, asyncdispatch -import std/[assertions, syncio] -from stdtest/testutils import enableRemoteNetworking - const manualTests = false proc makeIPv6HttpServer(hostname: string, port: Port, message: string): AsyncFD = - let fd = createNativeSocket(AF_INET6) + let fd = newNativeSocket(AF_INET6) setSockOptInt(fd, SOL_SOCKET, SO_REUSEADDR, 1) var aiList = getAddrInfo(hostname, port, AF_INET6) - if bindAddr(fd, aiList.ai_addr, aiList.ai_addrlen.SockLen) < 0'i32: + if bindAddr(fd, aiList.ai_addr, aiList.ai_addrlen.Socklen) < 0'i32: freeAddrInfo(aiList) raiseOSError(osLastError()) freeAddrInfo(aiList) @@ -46,7 +39,7 @@ proc makeIPv6HttpServer(hostname: string, port: Port, proc asyncTest() {.async.} = var client = newAsyncHttpClient() - var resp = await client.request("http://example.com/", HttpGet) + var resp = await client.request("http://example.com/") doAssert(resp.code.is2xx) var body = await resp.body body = await resp.body # Test caching @@ -55,7 +48,7 @@ proc asyncTest() {.async.} = resp = await client.request("http://example.com/404") doAssert(resp.code.is4xx) doAssert(resp.code == Http404) - doAssert(resp.status == $Http404) + doAssert(resp.status == Http404) resp = await client.request("https://google.com/") doAssert(resp.code.is2xx or resp.code.is3xx) @@ -109,14 +102,14 @@ proc asyncTest() {.async.} = proc syncTest() = var client = newHttpClient() - var resp = client.request("http://example.com/", HttpGet) + var resp = client.request("http://example.com/") doAssert(resp.code.is2xx) doAssert("Example Domain" in resp.body) resp = client.request("http://example.com/404") doAssert(resp.code.is4xx) doAssert(resp.code == Http404) - doAssert(resp.status == $Http404) + doAssert(resp.status == Http404) resp = client.request("https://google.com/") doAssert(resp.code.is2xx or resp.code.is3xx) @@ -151,12 +144,6 @@ proc syncTest() = client.close() - # SIGSEGV on HEAD body read: issue #16743 - block: - let client = newHttpClient() - let resp = client.head("http://httpbin.org/head") - doAssert(resp.body == "") - when false: # Disabled for now because it causes troubles with AppVeyor # Timeout test. @@ -179,7 +166,7 @@ proc ipv6Test() = client.close() ipv6Test() +syncTest() +waitFor(asyncTest()) -when enableRemoteNetworking: - syncTest() - waitFor(asyncTest()) +echo "OK" diff --git a/tests/stdlib/thttpclient_ssl.nim b/tests/stdlib/thttpclient_ssl.nim deleted file mode 100644 index feacd3e57..000000000 --- a/tests/stdlib/thttpclient_ssl.nim +++ /dev/null @@ -1,147 +0,0 @@ -discard """ - cmd: "nim $target --mm:refc -d:ssl $options $file" - disabled: "openbsd" -""" - -# Nim - Basic SSL integration tests -# (c) Copyright 2018 Nim contributors -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# -## Warning: this test performs local networking. -## Test with: -## ./bin/nim c -d:ssl -p:. --threads:on -r tests/stdlib/thttpclient_ssl.nim - -when not defined(windows): - # Disabled on Windows due to old OpenSSL version - import std/[formatfloat, syncio] - import - httpclient, - net, - openssl, - os, - strutils, - threadpool, - times, - unittest - - # bogus self-signed certificate - const - certFile = "tests/stdlib/thttpclient_ssl_cert.pem" - keyFile = "tests/stdlib/thttpclient_ssl_key.pem" - - proc log(msg: string) = - when defined(ssldebug): - echo " [" & $epochTime() & "] " & msg - # FIXME - echo " [" & $epochTime() & "] " & msg - discard - - proc runServer(port: Port): bool {.thread.} = - ## Run a trivial HTTPS server in a {.thread.} - ## Exit after serving one request - - var socket = newSocket() - socket.setSockOpt(OptReusePort, true) - socket.bindAddr(port) - - var ctx = newContext(certFile=certFile, keyFile=keyFile) - - ## Handle one connection - socket.listen() - - var client: Socket - var address = "" - - log "server: ready" - socket.acceptAddr(client, address) - log "server: incoming connection" - - var ssl: SslPtr = SSL_new(ctx.context) - discard SSL_set_fd(ssl, client.getFd()) - log "server: accepting connection" - ErrClearError() - if SSL_accept(ssl) <= 0: - ERR_print_errors_fp(stderr) - else: - const reply = "HTTP/1.0 200 OK\r\nServer: test\r\nContent-type: text/html\r\nContent-Length: 0\r\n\r\n" - log "server: sending reply" - discard SSL_write(ssl, reply.cstring, reply.len) - - log "server: receiving a line" - let line = client.recvLine() - log "server: received $# bytes" % $line.len - log "closing" - SSL_free(ssl) - close(client) - close(socket) - log "server: exited" - - - suite "SSL self signed certificate check": - - test "TCP socket": - const port = 12347.Port - let t = spawn runServer(port) - sleep(100) - var sock = newSocket() - var ctx = newContext() - ctx.wrapSocket(sock) - try: - log "client: connect" - sock.connect("127.0.0.1", port) - fail() - except: - let msg = getCurrentExceptionMsg() - check(msg.contains("certificate verify failed")) - - test "HttpClient default: no check": - const port = 12345.Port - let t = spawn runServer(port) - sleep(100) - - var client = newHttpClient(sslContext=newContext(verifyMode=CVerifyNone)) - try: - log "client: connect" - discard client.getContent("https://127.0.0.1:12345") - except: - let msg = getCurrentExceptionMsg() - log "client: unexpected exception: " & msg - fail() - - test "HttpClient with CVerifyPeer": - const port = 12346.Port - let t = spawn runServer(port) - sleep(100) - - var client = newHttpClient(sslContext=newContext(verifyMode=CVerifyPeer)) - try: - log "client: connect" - discard client.getContent("https://127.0.0.1:12346") - log "getContent should have raised an exception" - fail() - except: - let msg = getCurrentExceptionMsg() - log "client: exception: " & msg - # SSL_shutdown:shutdown while in init - if not (msg.contains("alert number 48") or - msg.contains("certificate verify failed")): - echo "CVerifyPeer exception: " & msg - check(false) - - test "HttpClient with CVerifyPeerUseEnvVars": - const port = 12346.Port - let t = spawn runServer(port) - sleep(100) - - putEnv("SSL_CERT_FILE", getCurrentDir() / certFile) - var client = newHttpClient(sslContext=newContext(verifyMode=CVerifyPeerUseEnvVars)) - try: - log "client: connect" - discard client.getContent("https://127.0.0.1:12346") - except: - let msg = getCurrentExceptionMsg() - log "client: exception: " & msg - log "getContent should not have raised an exception" - fail() diff --git a/tests/stdlib/thttpclient_ssl_cert.pem b/tests/stdlib/thttpclient_ssl_cert.pem deleted file mode 100644 index f15c15c52..000000000 --- a/tests/stdlib/thttpclient_ssl_cert.pem +++ /dev/null @@ -1,29 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIFCTCCAvGgAwIBAgIURYQOmGzeh3Vy7Gk6Go4uAPwcNwAwDQYJKoZIhvcNAQEL -BQAwFDESMBAGA1UEAwwJbG9jYWxob3N0MB4XDTE5MDEyMzAwMTgzNFoXDTQ2MDYw -OTAwMTgzNFowFDESMBAGA1UEAwwJbG9jYWxob3N0MIICIjANBgkqhkiG9w0BAQEF -AAOCAg8AMIICCgKCAgEAzoEVEl7yqY+RqIagXDD4JB7LyONDvh8aJvBMnJVBgjaL -JdkfQjvPGUzUkEbU5nc6u7lqFxzEv7hXrssQCB7TwJwfS2PT1Rj14IFlYPyw4DEe -P1RVS/awurtv3jwumarVl7LR+IQfo59kJ/P8jZt8H3HscDbyhXcHeOWI6q+XlfdV -mTUJVvABdUuOiIFjgfFVTpo+CKxy7c5caRDK7g1s9xB1/M9PUfJvHY1WrBWFOZf0 -Bl8iwn+ahuxfIVqsFL9leqLykgi1f4L20p7RaAK95TXCo3CszZm4Fsw9zhzkjoU7 -2h0nuYl197LZvRs3u/JJjzZERmsfVPIs5BtO8/MN1MvRn6hIGU5Q3kOVWqWxSkSl -njrf+uwUdn/24uSCnygNeDuJzwW/2q4N9YI3oovqNIGpkT3FbAm7UKwI4lwhwmqw -7WH+92ELj0BinmsMMRPD2OqvK+vzLVqwUIQkYug+Hjys6QGXMlrL0krrj7XOKSc3 -SvZa4j0S/Y5CKkw5xuZXxITsdaV6hGi3d/kuT+1ttOSfIIXJXDEiu4pYRfziKU1a -8EhHMEajEi6ueLw7QmEPVx398erRwiUuP2y43yZ4mwVwvN3i5jlVztl4XsglDmQ+ -hahstVdMMA34K2rK0U8q8YjdYm+z99NmGEPYrS6Qnpr1xrICN83FOWFI0k7ttyMC -AwEAAaNTMFEwHQYDVR0OBBYEFLqMY6eP3h3gu+ANs77xDBRnElxyMB8GA1UdIwQY -MBaAFLqMY6eP3h3gu+ANs77xDBRnElxyMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZI -hvcNAQELBQADggIBAJS+wyy0r+tVAlCa6V/xxlCDtW9n6L2nsqJXEjME0VvwGs3m -ima68LyTQJqCSjjxSotaNOYKzUu4vRA3JssV+fUDR+NpmhpRuM74XmO05HUQkp9U -dBEHyXp2aRQ9LSdvHo5D+RW+J4sHFb3PbU8NPx/t5Dg7il92S2QJQz1jNl+Nezc6 -2O8Vt1YbvWXfqM47URTpnQbWoo38pI44AgAuW3QagucKWsyounmhx65XcdtLn99g -oZt496pU+hBpYu/IpXuBKNC4FvOrXTWAPkAbbYP39UFyiKwIyTosK+qdbhBlt1xi -bBPn6N1W9L2BvUwM8fEB/qBuR9UfcMsIYJsWbbXMfyeF6lbaP7xD01rm+yU5PMMI -Co40abixMntz4J3T2ixdCptf0He1U/UegOHwG1ZGgQzvOG6qI/xkNktDaSA75KR7 -BvPV1CmZC4ovVo1L4STrwnoRz5J49PNOHi9Okj9zJ99H7nsmsK16oxpIYkYHJWn+ -45jpG8SlDp7oev1OGGk/z+ZOTz+LcNxyvsRQVN8w5zNmjCSWiGqz+UUgppCZg8qd -ECWokNQ5Lr20t1whynrX5bH0l887WPCQmm5VduRoyKFGhCRBSzcCtowSpiwZglUk -CV0jgFKoteItdzZgsND5I1GaNOxZlnK3wN4H0pgZv7HlW6SP1OYd2Y67waJ7 ------END CERTIFICATE----- diff --git a/tests/stdlib/thttpclient_ssl_key.pem b/tests/stdlib/thttpclient_ssl_key.pem deleted file mode 100644 index 6ab04122c..000000000 --- a/tests/stdlib/thttpclient_ssl_key.pem +++ /dev/null @@ -1,52 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIIJQwIBADANBgkqhkiG9w0BAQEFAASCCS0wggkpAgEAAoICAQDOgRUSXvKpj5Go -hqBcMPgkHsvI40O+Hxom8EyclUGCNosl2R9CO88ZTNSQRtTmdzq7uWoXHMS/uFeu -yxAIHtPAnB9LY9PVGPXggWVg/LDgMR4/VFVL9rC6u2/ePC6ZqtWXstH4hB+jn2Qn -8/yNm3wfcexwNvKFdwd45Yjqr5eV91WZNQlW8AF1S46IgWOB8VVOmj4IrHLtzlxp -EMruDWz3EHX8z09R8m8djVasFYU5l/QGXyLCf5qG7F8hWqwUv2V6ovKSCLV/gvbS -ntFoAr3lNcKjcKzNmbgWzD3OHOSOhTvaHSe5iXX3stm9Gze78kmPNkRGax9U8izk -G07z8w3Uy9GfqEgZTlDeQ5VapbFKRKWeOt/67BR2f/bi5IKfKA14O4nPBb/arg31 -gjeii+o0gamRPcVsCbtQrAjiXCHCarDtYf73YQuPQGKeawwxE8PY6q8r6/MtWrBQ -hCRi6D4ePKzpAZcyWsvSSuuPtc4pJzdK9lriPRL9jkIqTDnG5lfEhOx1pXqEaLd3 -+S5P7W205J8ghclcMSK7ilhF/OIpTVrwSEcwRqMSLq54vDtCYQ9XHf3x6tHCJS4/ -bLjfJnibBXC83eLmOVXO2XheyCUOZD6FqGy1V0wwDfgrasrRTyrxiN1ib7P302YY -Q9itLpCemvXGsgI3zcU5YUjSTu23IwIDAQABAoICAQCdR60/57cUs/dxjs/2R4nH -IPl/ELEYzeGCRMVlATz6qwZCFmN7c8ghceX32SrwOWEvd2G5Jr0ndIS76YdVV/1Z -ls8zAV5m0HL8wjDvtKYWqvJps5afm80w+++RKO8pNPcnahgIGsFqQszqrSbux7y6 -ym8VbJQ8WNMFHnWwoXpnyxCT9tQdNgE2UAzIJRwf7SpXCp0yx/1k6CZ0E0ksFGeo -qQ3kNhUoyegdbvfTazSkD/rZG36C+uM73i36Xm/wAXKN/CuaVC3AZ4QMGNBPUr9F -IzQSfY/vrCOMoZR1NoZRkmJqlogaBPsnZD34jRFfAYNLIz7PD2m2rhjIx4/Tt4wQ -5mUwga9ud0ly5wSzswudw07mTYtsLbWrUn6QdFxSwbQ0tXh9PJrqCSJDmYIptuu/ -6zjg8hQLg7y37xMDMCdKtviHx+ndVpW3StTwB/z7lDA6yuYY6nYN0dJTJS3qQheo -maPG4Xf4FBcD4Is73BjBCf3QR6WIv0ZOG3/GZ1OqLRrPg1u/3UJkpa4LE/6qNUxf -zdBZSPyQZExBvOqdklEI+1OcqofmWq2n7Amct45buDbFryehEhfJ1HHtkXkTEsut -azfQeaGem/jKxcTD+1bWs/Q5Nn+QFfKr0NFjXSLoITWQkgQD1qISw3DC72jYXlsm -S4CmCDW1dHZlmWZq+Mh34QKCAQEA+2JFRa1yYZ0tPt88sOjJYyw9yUxB9Nv9cKrs -kdkhKHKevF+0BUbRLfp9bod+Wlv66pgQi6ZGKkGD7lCam/3FIBlmmiG8AOoXdoGy -t17XCzlYy348mnHra2X+JBAN51ivPemdlGZShLbNMkGdL1khtjHL9vSr1KgFn3F/ -8nstVQ9nzHTCK0HWpBGn/EK3dd8lcYZDd7Fcgjz7E3xQDz/XZt0HMwwGaLnQ1L7T -glIyeNdqLBp4v0NT6L1AAk5rQJONo57AepblwacYhoW9mR5K0bm/BMo5+xwMtYz9 -69ZuMNW8qdaWrzeEsxM1PDbcOoVqChF10w0Ih/MkhKGpN/GxUQKCAQEA0kvWUkEK -1BBhwGyuKrMnUC3jnQ36KpsjlryMUArdjS2gVBztGW2p2CUWasEgZdxpwQmnqKyz -4hcZaU/JUleutTI5raxzju4Ve87c+koOiamhw/zaiLCpLn2j0Rh2qxp7QvPPRO0V -1MN347wjCTx/5/j8WffgWqWfqdrd8JheKal/OHlTZA3DG77FIVnUyov8Np+lTd1x -NpWr/AOreZlMBq/X/kmWCe+fP901fGdi3cdsKcJcdLPv9KFciSjBlAlaLMnBgLWo -RrIuNxdH3dRX4rzBSpdNq72n8NaH+A10eoXrlC4eWLo7vRSTe4WRgUAIbhVifnJk -z4B5FqC/aVgkMwKCAQEAtq983h0lcbDy76z2Ay65I/xDzqU/jX3OGfHtSDS+NxHN -L+JxBiCn5b0TKJ8JAQu1NoVaCNLGTPEdurQTF+f9OM2c1chMQ3HbqUCqKz6eEscT -M5dC3Y6KYptVbMnKAOVfPSQoY29U6qOaTbqHS6B/slNQAeFfeoS8yVmHfSVtFVLD -wT7c2OjY3pUCOn4Vq3CGWpETOMnJC9DbOhbua5aeqF9aWwuTIMpg7CrdtOidS1pp -CzIVrBF2yj22ZbatlNlmZpD5Gl3NDMWtOh25Yqwz/WP6YLXCGy4QQmP7KEfF/nFl -0RtkmGNFaYo89sx7kX/hRv3XXZAsMfhOAqElQ8W+cQKCAQAdL/lnIS/njv6CPpNN -yd/C+RuGSNJX54BhA3pWAawOVC7Ufc9KoDXakgsydeuRN65V5IkomA+/aYVVYIWI -sDLHY1kuCalgRRsmO+fftTefU7PoB8gtAJf6o+WAt+yAgwRonn4+Csnk5dxV917F -gWgfQieENSsmaaZnZME5C2zGS4gkxnIUiPRzfV7O6jDmi9dNnYrL69gyw0NDjx7V -mbk7lFxeJsh0SJXJv2IVCiRms68HfLpoWDENuvek8cssSMADR11cB9p7NW/Epa6L -01T/W0NYnvdgxsnwW1Yzz2pDNyMjReNgXTi9XYW6tyci0UhaPw2Ujzv+sM4dneHz -NRCRAoIBAHqXaeC1uTGSzfLvRz81ifgDRP8H9L1HLt7ZWL6XMp1ph+P6yYFXM4JK -WeP3cdKO/kQOD/fLuhYT92T2hHEadT8CQqpsBMQt29Zlm4oYWHB7ERiZqaGX3/T0 -U1TlL0WxthoHPY2HwA6pmDTmUzDk3tFlgk+XOmLsDacBdC6EsFwA+tyEPVxmkb0J -H+j7D4NxwysAyWCB9fWU1FV+JJJel+nz88i7Gb8uJ+kSktnFxjv/G9p+OkDYlaUt -j8lc6LOuNOA9M7XT1BIKpZytnSVtwZWkMmu23OLMM/d07tPJYtHIa92On7XKBPc2 -6THbQsJpR5AalTVvXs3X1RnCLnHiNYg= ------END PRIVATE KEY----- diff --git a/tests/stdlib/thttpclient_standalone.nim b/tests/stdlib/thttpclient_standalone.nim deleted file mode 100644 index 2f432eede..000000000 --- a/tests/stdlib/thttpclient_standalone.nim +++ /dev/null @@ -1,59 +0,0 @@ -discard """ - cmd: "nim c --threads:on $file" -""" - -import asynchttpserver, httpclient, asyncdispatch, strutils, net - -import std/assertions - -block: # bug #16436 - proc startServer(): AsyncHttpServer = - result = newAsyncHttpServer() - result.listen(Port(0)) - - proc processRequest(server: AsyncHttpServer) {.async.} = - proc cb(req: Request) {.async.} = - let headers = { "Content-length": "15"} # Provide invalid content-length - await req.respond(Http200, "Hello World", headers.newHttpHeaders()) - - await server.acceptRequest(cb) - - proc runClient(port: Port) {.async.} = - let c = newAsyncHttpClient(headers = {"Connection": "close"}.newHttpHeaders) - discard await c.getContent("http://127.0.0.1:" & $port) - doAssert false, "should fail earlier" - - let server = startServer() - asyncCheck processRequest(server) - let port = server.getPort() - doAssertRaises(ProtocolError): - waitFor runClient(port) - -block: # bug #14794 (And test for presence of content-length header when using postContent) - proc startServer(): AsyncHttpServer = - result = newAsyncHttpServer() - result.listen(Port(0)) - - proc runServer(server: AsyncHttpServer) {.async.} = - proc cb(req: Request) {.async.} = - doAssert(req.body.endsWith(httpNewLine), "Multipart body does not end with a newline.") - # this next line is probably not required because asynchttpserver does not call - # the callback when there is no content-length header. It instead errors with - # Error: unhandled exception: 411 Length Required - # Added for good measure in case the server becomes more permissive. - doAssert(req.headers.hasKey("content-length"), "Content-Length header is not present.") - asyncCheck req.respond(Http200, "OK") - - await server.acceptRequest(cb) - - proc runClient(port: Port) {.async.} = - let c = newAsyncHttpClient() - let data = newMultipartData() - data.add("file.txt", "This is intended to be an example text file.\r\nThis would be the second line.\r\n") - discard await c.postContent("http://127.0.0.1:" & $port, multipart = data) - c.close() - - let server = startServer() - let port = server.getPort() - asyncCheck runServer(server) - waitFor runClient(port) diff --git a/tests/stdlib/thttpcore.nim b/tests/stdlib/thttpcore.nim index 3b6b1efa0..889c734c5 100644 --- a/tests/stdlib/thttpcore.nim +++ b/tests/stdlib/thttpcore.nim @@ -1,99 +1,31 @@ -import httpcore, strutils -import std/assertions +discard """ +output: "[Suite] httpcore" +""" -block: - block HttpCode: - doAssert $Http418 == "418 I'm a teapot" - doAssert Http418.is4xx() == true - doAssert Http418.is2xx() == false +import unittest - block headers: +import httpcore + +suite "httpcore": + + test "HttpCode": + assert $Http418 == "418 I'm a teapot" + assert Http418.is4xx() == true + assert Http418.is2xx() == false + + test "headers": var h = newHttpHeaders() - doAssert h.len == 0 + assert h.len == 0 h.add("Cookie", "foo") - doAssert h.len == 1 - doAssert h.hasKey("cooKIE") - doAssert h["Cookie"] == "foo" - doAssert h["cookie"] == "foo" + assert h.len == 1 + assert h.hasKey("cooKIE") + assert h["Cookie"] == "foo" + assert h["cookie"] == "foo" h["cookie"] = @["bar", "x"] - doAssert h["Cookie"] == "bar" - doAssert h["Cookie", 1] == "x" - doAssert h["Cookie"].contains("BaR") == true - doAssert h["Cookie"].contains("X") == true - doAssert "baR" in h["cookiE"] + assert h["Cookie"] == "bar" + assert h["Cookie", 1] == "x" + assert h["Cookie"].contains("BaR") == true + assert h["Cookie"].contains("X") == true + assert "baR" in h["cookiE"] h.del("coOKie") - doAssert h.len == 0 - - # Test that header constructor works with repeated values - let h1 = newHttpHeaders({"a": "1", "a": "2", "A": "3"}) - - doAssert seq[string](h1["a"]).join(",") == "1,2,3" - - block test_cookies_with_comma: - doAssert parseHeader("cookie: foo, bar") == ("cookie", @["foo, bar"]) - doAssert parseHeader("cookie: foo, bar, prologue") == ("cookie", @["foo, bar, prologue"]) - doAssert parseHeader("cookie: foo, bar, prologue, starlight") == ("cookie", @["foo, bar, prologue, starlight"]) - - doAssert parseHeader("cookie: foo, bar") == ("cookie", @["foo, bar"]) - doAssert parseHeader("cookie: foo, bar, prologue") == ("cookie", @["foo, bar, prologue"]) - doAssert parseHeader("cookie: foo, bar, prologue, starlight") == ("cookie", @["foo, bar, prologue, starlight"]) - - doAssert parseHeader("Cookie: foo, bar") == (key: "Cookie", value: @["foo, bar"]) - doAssert parseHeader("Cookie: foo, bar, prologue") == (key: "Cookie", value: @["foo, bar, prologue"]) - doAssert parseHeader("Cookie: foo, bar, prologue, starlight") == (key: "Cookie", value: @["foo, bar, prologue, starlight"]) - - doAssert parseHeader("Accept: foo, bar") == (key: "Accept", value: @["foo", "bar"]) - doAssert parseHeader("Accept: foo, bar, prologue") == (key: "Accept", value: @["foo", "bar", "prologue"]) - doAssert parseHeader("Accept: foo, bar, prologue, starlight") == (key: "Accept", value: @["foo", "bar", "prologue", "starlight"]) - - block add_empty_sequence_to_HTTP_headers: - block: - var headers = newHttpHeaders() - headers["empty"] = @[] - - doAssert not headers.hasKey("empty") - - block: - var headers = newHttpHeaders() - headers["existing"] = "true" - headers["existing"] = @[] - - doAssert not headers.hasKey("existing") - - block: - var headers = newHttpHeaders() - headers["existing"] = @["true"] - headers["existing"] = @[] - - doAssert not headers.hasKey("existing") - - block: - var headers = newHttpHeaders() - headers["existing"] = @[] - headers["existing"] = @["true"] - doAssert headers.hasKey("existing") - -block: - var test = newHttpHeaders() - test["Connection"] = @["Upgrade", "Close"] - doAssert test["Connection", 0] == "Upgrade" - doAssert test["Connection", 1] == "Close" - test.add("Connection", "Test") - doAssert test["Connection", 2] == "Test" - doAssert "upgrade" in test["Connection"] - - # Bug #5344. - doAssert parseHeader("foobar: ") == ("foobar", @[""]) - let (key, value) = parseHeader("foobar: ") - test = newHttpHeaders() - test[key] = value - doAssert test["foobar"] == "" - - doAssert parseHeader("foobar:") == ("foobar", @[""]) - - block: # test title case - var testTitleCase = newHttpHeaders(titleCase=true) - testTitleCase.add("content-length", "1") - doAssert testTitleCase.hasKey("Content-Length") - for key, val in testTitleCase: - doAssert key == "Content-Length" + assert h.len == 0 diff --git a/tests/stdlib/timportutils.nim b/tests/stdlib/timportutils.nim deleted file mode 100644 index 33afd7def..000000000 --- a/tests/stdlib/timportutils.nim +++ /dev/null @@ -1,147 +0,0 @@ -import std/[importutils, assertions] -import stdtest/testutils -import mimportutils - -template main = - block: # privateAccess - assertAll: - var a: A - var b = initB() # B is private - compiles(a.a0) - compiles(b.b0) - not compiles(a.ha1) - not compiles(b.hb1) - - block: - assertAll: - privateAccess A - compiles(a.ha1) - a.ha1 == 0.0 - not compiles(a.hb1) - privateAccess b.typeof - b.hb1 = 3 - type B2 = b.typeof - let b2 = B2(b0: 4, hb1: 5) - b.hb1 == 3 - b2 == B2(b0: 4, hb1: 5) - - assertAll: - not compiles(a.ha1) - not compiles(b.hb1) - - block: - assertAll: - not compiles(C(c0: 1, hc1: 2)) - privateAccess C - let c = C(c0: 1, hc1: 2) - c.hc1 == 2 - - block: - assertAll: - not compiles(E[int](he1: 1)) - privateAccess E[int] - var e = E[int](he1: 1) - e.he1 == 1 - e.he1 = 2 - e.he1 == 2 - e.he1 += 3 - e.he1 == 5 - # xxx caveat: this currently compiles but in future, we may want - # to make `privateAccess E[int]` only affect a specific instantiation; - # note that `privateAccess E` does work to cover all instantiations. - var e2 = E[float](he1: 1) - - block: - assertAll: - not compiles(E[int](he1: 1)) - privateAccess E - var e = E[int](he1: 1) - e.he1 == 1 - - block: - assertAll: - not compiles(F[int, int](h3: 1)) - privateAccess F[int, int] - var e = F[int, int](h3: 1) - e.h3 == 1 - - block: - assertAll: - not compiles(F[int, int](h3: 1)) - privateAccess F[int, int].default[].typeof - var e = F[int, int](h3: 1) - e.h3 == 1 - - block: - assertAll: - var a = G[int]() - var b = a.addr - privateAccess b.type - discard b.he1 - discard b[][].he1 - - block: - assertAll: - privateAccess H[int] - var a = H[int](h5: 2) - - block: - assertAll: - privateAccess PA - var pa = PA(a0: 1, ha1: 2) - pa.ha1 == 2 - pa.ha1 = 3 - pa.ha1 == 3 - - block: - assertAll: - var b = BAalias() - not compiles(b.hb1) - privateAccess BAalias - discard b.hb1 - - block: - assertAll: - var a = A(a0: 1) - var a2 = a.addr - not compiles(a2.ha1) - privateAccess PtA - a2.type is PtA - a2.ha1 = 2 - a2.ha1 == 2 - a.ha1 = 3 - a2.ha1 == 3 - - block: - disableVm: - assertAll: - var a = A.create() - defer: dealloc(a) - a is PtA - a.typeof is PtA - not compiles(a.ha1) - privateAccess a.typeof - a.ha1 = 2 - a.ha1 == 2 - a[].ha1 = 3 - a.ha1 == 3 - - block: - disableVm: - assertAll: - var a = A.create() - defer: dealloc(a) - privateAccess PtA - a.ha1 == 0 - - block: - privateAccess PityRef - let x = PityRef[int](a: 1) # works - doAssert x.a == 1 - - privateAccess Hope - let y = Hope[int](a: 1) - doAssert y.a == 1 - -static: main() -main() diff --git a/tests/stdlib/tintsets.nim b/tests/stdlib/tintsets.nim deleted file mode 100644 index 191ef117e..000000000 --- a/tests/stdlib/tintsets.nim +++ /dev/null @@ -1,6 +0,0 @@ -import ./mintsets - -block: # bug https://github.com/nim-lang/Nim/pull/15564#issuecomment-729878104 - # related to bug #11167 - test1() - test2() diff --git a/tests/stdlib/tio.nim b/tests/stdlib/tio.nim deleted file mode 100644 index ca411379c..000000000 --- a/tests/stdlib/tio.nim +++ /dev/null @@ -1,56 +0,0 @@ -# xxx move to here other tests that belong here; io is a proper module - -import std/os -from stdtest/specialpaths import buildDir -import std/[assertions, syncio] - -block: # readChars - let file = buildDir / "D20201118T205105.txt" - let s = "he\0l\0lo" - writeFile(file, s) - defer: removeFile(file) - let f = open(file) - defer: close(f) - let n = f.getFileInfo.blockSize - var buf = newString(n) - template fn = - let n2 = f.readChars(buf) - doAssert n2 == s.len - doAssert buf[0.. json => T2 => json2` is such that json2 = json - let j = %t - doAssert $j == expected, $j - doAssert %(j.to(T)) == j - -proc testRoundtripVal[T](t: T, expected: string) = - # similar to testRoundtrip, but also checks that the `T => json => T2` is such that `T2 == T` - # note that this isn't always possible, e.g. for pointer-like types or nans - let j = %t - doAssert $j == expected, $j - let j2 = ($j).parseJson - doAssert $j2 == expected, $(j2, t) - let t2 = j2.to(T) - doAssert t2 == t - doAssert $(%* t2) == expected # sanity check, because -0.0 = 0.0 but their json representation differs - -let testJson = parseJson"""{ "a": [1, 2, 3, 4], "b": "asd", "c": "\ud83c\udf83", "d": "\u00E6"}""" -# nil passthrough -doAssert(testJson{"doesnt_exist"}{"anything"}.isNil) -testJson{["e", "f"]} = %true -doAssert(testJson["e"]["f"].bval) - -# make sure UTF-16 decoding works. -doAssert(testJson["c"].str == "🎃") -doAssert(testJson["d"].str == "æ") - -# make sure no memory leek when parsing invalid string -let startMemory = getOccupiedMem() -for i in 0 .. 10000: - try: - discard parseJson"""{ invalid""" - except: - discard -# memory diff should less than 4M -doAssert(abs(getOccupiedMem() - startMemory) < 4 * 1024 * 1024) # todo fixme doesn;t work for ORC - - -# test `$` -let stringified = $testJson -let parsedAgain = parseJson(stringified) -doAssert(parsedAgain["b"].str == "asd") - -parsedAgain["abc"] = %5 -doAssert parsedAgain["abc"].num == 5 - -# Bounds checking -when compileOption("boundChecks"): - try: - let a = testJson["a"][9] - doAssert(false, "IndexDefect not thrown") - except IndexDefect: - discard - try: - let a = testJson["a"][-1] - doAssert(false, "IndexDefect not thrown") - except IndexDefect: - discard - try: - doAssert(testJson["a"][0].num == 1, "Index doesn't correspond to its value") - except: - doAssert(false, "IndexDefect thrown for valid index") - -doAssert(testJson{"b"}.getStr() == "asd", "Couldn't fetch a singly nested key with {}") -doAssert(isNil(testJson{"nonexistent"}), "Non-existent keys should return nil") -doAssert(isNil(testJson{"a", "b"}), "Indexing through a list should return nil") -doAssert(isNil(testJson{"a", "b"}), "Indexing through a list should return nil") -doAssert(testJson{"a"} == parseJson"[1, 2, 3, 4]", "Didn't return a non-JObject when there was one to be found") -doAssert(isNil(parseJson("[1, 2, 3]"){"foo"}), "Indexing directly into a list should return nil") - -# Generator: -var j = %* [{"name": "John", "age": 30}, {"name": "Susan", "age": 31}] -doAssert j == %[%{"name": %"John", "age": %30}, %{"name": %"Susan", "age": %31}] - -var j2 = %* - [ - { - "name": "John", - "age": 30 - }, - { - "name": "Susan", - "age": 31 - } - ] -doAssert j2 == %[%{"name": %"John", "age": %30}, %{"name": %"Susan", "age": %31}] - -var name = "John" -let herAge = 30 -const hisAge = 31 - -var j3 = %* - [ {"name": "John" - , "age": herAge - } - , {"name": "Susan" - , "age": hisAge - } - ] -doAssert j3 == %[%{"name": %"John", "age": %30}, %{"name": %"Susan", "age": %31}] - -var j4 = %*{"test": nil} -doAssert j4 == %{"test": newJNull()} - -let seqOfNodes = @[%1, %2] -let jSeqOfNodes = %seqOfNodes -doAssert(jSeqOfNodes[1].num == 2) - -type MyObj = object - a, b: int - s: string - f32: float32 - f64: float64 - next: ref MyObj -var m: MyObj -m.s = "hi" -m.a = 5 -let jMyObj = %m -doAssert(jMyObj["a"].num == 5) -doAssert(jMyObj["s"].str == "hi") - -# Test loading of file. -when not defined(js): - var parsed = parseFile("tests/testdata/jsontest.json") - - try: - discard parsed["key2"][12123] - doAssert(false) - except IndexDefect: doAssert(true) - - var parsed2 = parseFile("tests/testdata/jsontest2.json") - doAssert(parsed2{"repository", "description"}.str == - "IRC Library for Haskell", "Couldn't fetch via multiply nested key using {}") - -doAssert escapeJsonUnquoted("\10Foo🎃barÄ") == "\\nFoo🎃barÄ" -doAssert escapeJsonUnquoted("\0\7\20") == "\\u0000\\u0007\\u0014" # for #7887 -doAssert escapeJson("\10Foo🎃barÄ") == "\"\\nFoo🎃barÄ\"" -doAssert escapeJson("\0\7\20") == "\"\\u0000\\u0007\\u0014\"" # for #7887 - -# Test with extra data -when not defined(js): - try: - discard parseJson("123 456") - doAssert(false) - except JsonParsingError: - doAssert getCurrentExceptionMsg().contains(errorMessages[errEofExpected]) - - try: - discard parseFile("tests/testdata/jsonwithextradata.json") - doAssert(false) - except JsonParsingError: - doAssert getCurrentExceptionMsg().contains(errorMessages[errEofExpected]) - -# bug #6438 -doAssert($ %*[] == "[]") -doAssert($ %*{} == "{}") - -doAssert(not compiles(%{"error": "No messages"})) - -# bug #9111 -block: - type - Bar = string - Foo = object - a: int - b: Bar - - let - js = """{"a": 123, "b": "abc"}""".parseJson - foo = js.to Foo - - doAssert(foo.b == "abc") - -# Generate constructors for range[T] types -block: - type - Q1 = range[0'u8 .. 50'u8] - Q2 = range[0'u16 .. 50'u16] - Q3 = range[0'u32 .. 50'u32] - Q4 = range[0'i8 .. 50'i8] - Q5 = range[0'i16 .. 50'i16] - Q6 = range[0'i32 .. 50'i32] - Q7 = range[0'f32 .. 50'f32] - Q8 = range[0'f64 .. 50'f64] - Q9 = range[0 .. 50] - - X = object - m1: Q1 - m2: Q2 - m3: Q3 - m4: Q4 - m5: Q5 - m6: Q6 - m7: Q7 - m8: Q8 - m9: Q9 - - let obj = X( - m1: Q1(42), - m2: Q2(42), - m3: Q3(42), - m4: Q4(42), - m5: Q5(42), - m6: Q6(42), - m7: Q7(42), - m8: Q8(42), - m9: Q9(42) - ) - - doAssert(obj == to(%obj, type(obj))) - - when not defined(js): - const fragments = """[1,2,3] {"hi":3} 12 [] """ - var res = "" - for x in parseJsonFragments(newStringStream(fragments)): - res.add($x) - res.add " " - doAssert res == fragments - - -# test isRefSkipDistinct -type - MyRef = ref object - MyObject = object - MyDistinct = distinct MyRef - MyOtherDistinct = distinct MyRef - -var x0: ref int -var x1: MyRef -var x2: MyObject -var x3: MyDistinct -var x4: MyOtherDistinct - -doAssert isRefSkipDistinct(x0) -doAssert isRefSkipDistinct(x1) -doAssert not isRefSkipDistinct(x2) -doAssert isRefSkipDistinct(x3) -doAssert isRefSkipDistinct(x4) - - -doAssert isRefSkipDistinct(ref int) -doAssert isRefSkipDistinct(MyRef) -doAssert not isRefSkipDistinct(MyObject) -doAssert isRefSkipDistinct(MyDistinct) -doAssert isRefSkipDistinct(MyOtherDistinct) - -let x = parseJson("9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999") - -doAssert x.kind == JString - -block: # bug #15835 - type - Foo = object - ii*: int - data*: JsonNode - - block: - const jt = """{"ii": 123, "data": ["some", "data"]}""" - let js = parseJson(jt) - discard js.to(Foo) - - block: - const jt = """{"ii": 123}""" - let js = parseJson(jt) - doAssertRaises(KeyError): - echo js.to(Foo) - -type - ContentNodeKind* = enum - P, - Br, - Text, - ContentNode* = object - case kind*: ContentNodeKind - of P: pChildren*: seq[ContentNode] - of Br: nil - of Text: textStr*: string - -let mynode = ContentNode(kind: P, pChildren: @[ - ContentNode(kind: Text, textStr: "mychild"), - ContentNode(kind: Br) -]) - -doAssert $mynode == """(kind: P, pChildren: @[(kind: Text, textStr: "mychild"), (kind: Br)])""" - -let jsonNode = %*mynode -doAssert $jsonNode == """{"kind":"P","pChildren":[{"kind":"Text","textStr":"mychild"},{"kind":"Br"}]}""" -doAssert $jsonNode.to(ContentNode) == """(kind: P, pChildren: @[(kind: Text, textStr: "mychild"), (kind: Br)])""" - -block: # bug #17383 - testRoundtrip(int32.high): "2147483647" - testRoundtrip(uint32.high): "4294967295" - when int.sizeof == 4: - testRoundtrip(int.high): "2147483647" - testRoundtrip(uint.high): "4294967295" - else: - testRoundtrip(int.high): "9223372036854775807" - testRoundtrip(uint.high): "18446744073709551615" - when not defined(js): - testRoundtrip(int64.high): "9223372036854775807" - testRoundtrip(uint64.high): "18446744073709551615" - -block: # bug #18007 - testRoundtrip([NaN, Inf, -Inf, 0.0, -0.0, 1.0]): """["nan","inf","-inf",0.0,-0.0,1.0]""" - # pending https://github.com/nim-lang/Nim/issues/18025 use: - # testRoundtrip([float32(NaN), Inf, -Inf, 0.0, -0.0, 1.0]) - let inf = float32(Inf) - testRoundtrip([float32(NaN), inf, -inf, 0.0, -0.0, 1.0]): """["nan","inf","-inf",0.0,-0.0,1.0]""" - when not defined(js): # because of Infinity vs inf - testRoundtripVal([inf, -inf, 0.0, -0.0, 1.0]): """["inf","-inf",0.0,-0.0,1.0]""" - let a = parseJson($(%NaN)).to(float) - doAssert a.isNaN - - whenRuntimeJs: discard # refs bug #18009 - do: - testRoundtripVal(0.0): "0.0" - testRoundtripVal(-0.0): "-0.0" - -block: # bug #15397, bug #13196 - testRoundtripVal(1.0 + epsilon(float64)): "1.0000000000000002" - testRoundtripVal(0.12345678901234567890123456789): "0.12345678901234568" - -block: - let a = "18446744073709551615" - let b = a.parseJson - doAssert b.kind == JString - let c = $b - when defined(js): - doAssert c == "18446744073709552000" - else: - doAssert c == "18446744073709551615" - -block: - let a = """ - [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ - [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ - [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ - [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ - [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ - [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ - [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ - [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ - [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ - [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ - [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ - [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ - [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ - [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ - [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ - [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ - [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ - [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ - [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ - [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ - [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ - [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ -""" - - when not defined(js): - try: - discard parseJson(a) - except JsonParsingError: - doAssert getCurrentExceptionMsg().contains("] expected") diff --git a/tests/stdlib/tjsonmacro.nim b/tests/stdlib/tjsonmacro.nim index 9c1fa833d..938030d8e 100644 --- a/tests/stdlib/tjsonmacro.nim +++ b/tests/stdlib/tjsonmacro.nim @@ -4,7 +4,6 @@ discard """ """ import json, strutils, options, tables -import std/assertions # The definition of the `%` proc needs to be here, since the `% c` calls below # can only find our custom `%` proc for `Pix` if defined in global scope. @@ -260,7 +259,7 @@ proc testJson() = colors: array[2, BirdColor] var red = BirdColor(name: "red", rgb: [1.0, 0.0, 0.0]) - var blue = BirdColor(name: "blue", rgb: [0.0, 0.0, 1.0]) + var blue = Birdcolor(name: "blue", rgb: [0.0, 0.0, 1.0]) var b = Bird(age: 3, height: 1.734, name: "bardo", colors: [red, blue]) let jnode = %b let data = jnode.to(Bird) @@ -498,7 +497,7 @@ proc testJson() = doAssert array[3, float](t.arr) == [1.0,2.0,7.0] doAssert MyRef(t.person).name == "boney" - doAssert MyObj(t.distfruit).color == 11 + doAssert MyObj(t.distFruit).color == 11 doAssert t.dog.name == "honey" doAssert t.fruit.color == 10 doAssert seq[string](t.emails) == @["abc", "123"] @@ -634,18 +633,6 @@ proc testJson() = except KeyError: doAssert getCurrentExceptionMsg().contains ".member.list[2].value" - block: - # Enum indexed array test - type Test = enum - one, two, three, four, five - let a = [ - one: 300, - two: 20, - three: 10, - four: 0, - five: -10 - ] - doAssert (%* a).to(a.typeof) == a testJson() diff --git a/tests/stdlib/tjsonutils.nim b/tests/stdlib/tjsonutils.nim deleted file mode 100644 index 1681f4a09..000000000 --- a/tests/stdlib/tjsonutils.nim +++ /dev/null @@ -1,471 +0,0 @@ -discard """ - targets: "c cpp js" -""" - -import std/jsonutils -import std/json -from std/math import isNaN, signbit -from std/fenv import epsilon -from stdtest/testutils import whenRuntimeJs -import std/[assertions, objectdollar] - -proc testRoundtrip[T](t: T, expected: string) = - # checks that `T => json => T2 => json2` is such that json2 = json - let j = t.toJson - doAssert $j == expected, "\n" & $j & "\n" & expected - doAssert j.jsonTo(T).toJson == j - var t2: T - t2.fromJson(j) - doAssert t2.toJson == j - -proc testRoundtripVal[T](t: T, expected: string) = - # similar to testRoundtrip, but also checks that the `T => json => T2` is such that `T2 == T` - # note that this isn't always possible, e.g. for pointer-like types. - let j = t.toJson - let j2 = $j - doAssert j2 == expected, j2 - let j3 = j2.parseJson - let t2 = j3.jsonTo(T) - doAssert t2 == t - doAssert $t2.toJson == j2 # still needed, because -0.0 = 0.0 but their json representation differs - -import tables, sets, algorithm, sequtils, options, strtabs -from strutils import contains - -type Foo = ref object - id: int - -proc `==`(a, b: Foo): bool = - a.id == b.id - -type MyEnum = enum me0, me1 = "me1Alt", me2, me3, me4 - -proc `$`(a: MyEnum): string = - # putting this here pending https://github.com/nim-lang/Nim/issues/13747 - if a == me2: "me2Modif" - else: system.`$`(a) - -template fn() = - block: # toJson, jsonTo - type Foo = distinct float - testRoundtrip('x', """120""") - when not defined(js): - testRoundtrip(cast[pointer](12345)): """12345""" - when nimvm: - discard - # bugs: - # Error: unhandled exception: 'intVal' is not accessible using discriminant 'kind' of type 'TNode' [ - # Error: VM does not support 'cast' from tyNil to tyPointer - else: - testRoundtrip(pointer(nil)): """0""" - testRoundtrip(cast[pointer](nil)): """0""" - - # causes workaround in `fromJson` potentially related to - # https://github.com/nim-lang/Nim/issues/12282 - testRoundtrip(Foo(1.5)): """1.5""" - - block: # OrderedTable - testRoundtrip({"z": "Z", "y": "Y"}.toOrderedTable): """{"z":"Z","y":"Y"}""" - doAssert toJson({"z": 10, "": 11}.newTable).`$`.contains """"":11""" # allows hash to change - testRoundtrip({"z".cstring: 1, "".cstring: 2}.toOrderedTable): """{"z":1,"":2}""" - testRoundtrip({"z": (f1: 'f'), }.toTable): """{"z":{"f1":102}}""" - - block: # StringTable - testRoundtrip({"name": "John", "city": "Monaco"}.newStringTable): """{"mode":"modeCaseSensitive","table":{"city":"Monaco","name":"John"}}""" - - block: # complex example - let t = {"z": "Z", "y": "Y"}.newStringTable - type A = ref object - a1: string - let a = (1.1, "fo", 'x', @[10,11], [true, false], [t,newStringTable()], [0'i8,3'i8], -4'i16, (foo: 0.5'f32, bar: A(a1: "abc"), bar2: A.default, cstring1: "foo", cstring2: "", cstring3: cstring(nil))) - testRoundtrip(a): - """[1.1,"fo",120,[10,11],[true,false],[{"mode":"modeCaseSensitive","table":{"y":"Y","z":"Z"}},{"mode":"modeCaseSensitive","table":{}}],[0,3],-4,{"foo":0.5,"bar":{"a1":"abc"},"bar2":null,"cstring1":"foo","cstring2":"","cstring3":null}]""" - - block: - # edge case when user defined `==` doesn't handle `nil` well, e.g.: - # https://github.com/nim-lang/nimble/blob/63695f490728e3935692c29f3d71944d83bb1e83/src/nimblepkg/version.nim#L105 - testRoundtrip(@[Foo(id: 10), nil]): """[{"id":10},null]""" - - block: # enum - type Foo = enum f1, f2, f3, f4, f5 - type Bar = enum b1, b2, b3, b4 - let a = [f2: b2, f3: b3, f4: b4] - doAssert b2.ord == 1 # explains the `1` - testRoundtrip(a): """[1,2,3]""" - - block: # JsonNode - let a = ((1, 2.5, "abc").toJson, (3, 4.5, "foo")) - testRoundtripVal(a): """[[1,2.5,"abc"],[3,4.5,"foo"]]""" - - block: - template toInt(a): untyped = cast[int](a) - - let a = 3.toJson - let b = (a, a) - - let c1 = b.toJson - doAssert c1[0].toInt == a.toInt - doAssert c1[1].toInt == a.toInt - - let c2 = b.toJson(ToJsonOptions(jsonNodeMode: joptJsonNodeAsCopy)) - doAssert c2[0].toInt != a.toInt - doAssert c2[1].toInt != c2[0].toInt - doAssert c2[1] == c2[0] - - let c3 = b.toJson(ToJsonOptions(jsonNodeMode: joptJsonNodeAsObject)) - doAssert $c3 == """[{"isUnquoted":false,"kind":2,"num":3},{"isUnquoted":false,"kind":2,"num":3}]""" - - block: # ToJsonOptions - let a = (me1, me2) - doAssert $a.toJson() == "[1,2]" - doAssert $a.toJson(ToJsonOptions(enumMode: joptEnumSymbol)) == """["me1","me2"]""" - doAssert $a.toJson(ToJsonOptions(enumMode: joptEnumString)) == """["me1Alt","me2Modif"]""" - - block: # set - type Foo = enum f1, f2, f3, f4, f5 - type Goo = enum g1 = 10, g2 = 15, g3 = 17, g4 - let a = ({f1, f3}, {1'u8, 7'u8}, {'0'..'9'}, {123'u16, 456, 789, 1121, 1122, 1542}, {g2, g3}) - testRoundtrip(a): """[[0,2],[1,7],[48,49,50,51,52,53,54,55,56,57],[123,456,789,1121,1122,1542],[15,17]]""" - - block: # bug #17383 - block: - let a = (int32.high, uint32.high) - testRoundtrip(a): "[2147483647,4294967295]" - when int.sizeof > 4: - block: - let a = (int64.high, uint64.high) - testRoundtrip(a): "[9223372036854775807,18446744073709551615]" - block: - let a = (int.high, uint.high) - when int.sizeof == 4: - testRoundtrip(a): "[2147483647,4294967295]" - else: - testRoundtrip(a): "[9223372036854775807,18446744073709551615]" - - block: # bug #18007 - testRoundtrip((NaN, Inf, -Inf, 0.0, -0.0, 1.0)): """["nan","inf","-inf",0.0,-0.0,1.0]""" - testRoundtrip((float32(NaN), Inf, -Inf, 0.0, -0.0, 1.0)): """["nan","inf","-inf",0.0,-0.0,1.0]""" - testRoundtripVal((Inf, -Inf, 0.0, -0.0, 1.0)): """["inf","-inf",0.0,-0.0,1.0]""" - doAssert ($NaN.toJson).parseJson.jsonTo(float).isNaN - - block: # bug #18009; unfixable unless we change parseJson (which would have overhead), - # but at least we can guarantee that the distinction between 0.0 and -0.0 is preserved. - let a = (0, 0.0, -0.0, 0.5, 1, 1.0) - testRoundtripVal(a): "[0,0.0,-0.0,0.5,1,1.0]" - let a2 = $($a.toJson).parseJson - whenRuntimeJs: - doAssert a2 == "[0,0,-0.0,0.5,1,1]" - do: - doAssert a2 == "[0,0.0,-0.0,0.5,1,1.0]" - let b = a2.parseJson.jsonTo(type(a)) - doAssert not b[1].signbit - doAssert b[2].signbit - doAssert not b[3].signbit - - block: # bug #15397, bug #13196 - let a = 0.1 - let x = 0.12345678901234567890123456789 - let b = (a + 0.2, 0.3, x) - testRoundtripVal(b): "[0.30000000000000004,0.3,0.12345678901234568]" - - testRoundtripVal(0.12345678901234567890123456789): "0.12345678901234568" - testRoundtripVal(epsilon(float64)): "2.220446049250313e-16" - testRoundtripVal(1.0 + epsilon(float64)): "1.0000000000000002" - - block: # case object - type Foo = object - x0: float - case t1: bool - of true: z1: int8 - of false: z2: uint16 - x1: string - testRoundtrip(Foo(t1: true, z1: 5, x1: "bar")): """{"x0":0.0,"t1":true,"z1":5,"x1":"bar"}""" - testRoundtrip(Foo(x0: 1.5, t1: false, z2: 6)): """{"x0":1.5,"t1":false,"z2":6,"x1":""}""" - type PFoo = ref Foo - testRoundtrip(PFoo(x0: 1.5, t1: false, z2: 6)): """{"x0":1.5,"t1":false,"z2":6,"x1":""}""" - - block: # ref case object - type Foo = ref object - x0: float - case t1: bool - of true: z1: int8 - of false: z2: uint16 - x1: string - testRoundtrip(Foo(t1: true, z1: 5, x1: "bar")): """{"x0":0.0,"t1":true,"z1":5,"x1":"bar"}""" - testRoundtrip(Foo(x0: 1.5, t1: false, z2: 6)): """{"x0":1.5,"t1":false,"z2":6,"x1":""}""" - - block: # generic case object - type Foo[T] = ref object - x0: float - case t1: bool - of true: z1: int8 - of false: z2: uint16 - x1: string - testRoundtrip(Foo[float](t1: true, z1: 5, x1: "bar")): """{"x0":0.0,"t1":true,"z1":5,"x1":"bar"}""" - testRoundtrip(Foo[int](x0: 1.5, t1: false, z2: 6)): """{"x0":1.5,"t1":false,"z2":6,"x1":""}""" - # sanity check: nesting inside a tuple - testRoundtrip((Foo[int](x0: 1.5, t1: false, z2: 6), "foo")): """[{"x0":1.5,"t1":false,"z2":6,"x1":""},"foo"]""" - - block: # case object: 2 discriminants, `when` branch, range discriminant - type Foo[T] = object - case t1: bool - of true: - z1: int8 - of false: - z2: uint16 - when T is float: - case t2: range[0..3] - of 0: z3: int8 - of 2,3: z4: uint16 - else: discard - testRoundtrip(Foo[float](t1: true, z1: 5, t2: 3, z4: 12)): """{"t1":true,"z1":5,"t2":3,"z4":12}""" - testRoundtrip(Foo[int](t1: false, z2: 7)): """{"t1":false,"z2":7}""" - # pending https://github.com/nim-lang/Nim/issues/14698, test with `type Foo[T] = ref object` - - block: # bug: pass opt params in fromJson - type Foo = object - a: int - b: string - c: float - type Bar = object - foo: Foo - boo: string - var f: seq[Foo] - try: - fromJson(f, parseJson """[{"b": "bbb"}]""") - doAssert false - except ValueError: - doAssert true - fromJson(f, parseJson """[{"b": "bbb"}]""", Joptions(allowExtraKeys: true, allowMissingKeys: true)) - doAssert f == @[Foo(a: 0, b: "bbb", c: 0.0)] - var b: Bar - fromJson(b, parseJson """{"foo": {"b": "bbb"}}""", Joptions(allowExtraKeys: true, allowMissingKeys: true)) - doAssert b == Bar(foo: Foo(a: 0, b: "bbb", c: 0.0)) - block: # jsonTo with `opt` - let b2 = """{"foo": {"b": "bbb"}}""".parseJson.jsonTo(Bar, Joptions(allowExtraKeys: true, allowMissingKeys: true)) - doAssert b2 == Bar(foo: Foo(a: 0, b: "bbb", c: 0.0)) - - block testHashSet: - testRoundtrip(HashSet[string]()): "[]" - testRoundtrip([""].toHashSet): """[""]""" - testRoundtrip(["one"].toHashSet): """["one"]""" - - var s: HashSet[string] - fromJson(s, parseJson("""["one","two"]""")) - doAssert s == ["one", "two"].toHashSet - - let jsonNode = toJson(s) - doAssert jsonNode.elems.mapIt(it.str).sorted == @["one", "two"] - - block testOrderedSet: - testRoundtrip(["one", "two", "three"].toOrderedSet): - """["one","two","three"]""" - - block testOption: - testRoundtrip(some("test")): "\"test\"" - testRoundtrip(none[string]()): "null" - testRoundtrip(some(42)): "42" - testRoundtrip(none[int]()): "null" - - block testStrtabs: - testRoundtrip(newStringTable(modeStyleInsensitive)): - """{"mode":"modeStyleInsensitive","table":{}}""" - - testRoundtrip( - newStringTable("name", "John", "surname", "Doe", modeCaseSensitive)): - """{"mode":"modeCaseSensitive","table":{"name":"John","surname":"Doe"}}""" - - block testJoptions: - type - AboutLifeUniverseAndEverythingElse = object - question: string - answer: int - - block testExceptionOnExtraKeys: - var guide: AboutLifeUniverseAndEverythingElse - let json = parseJson( - """{"question":"6*9=?","answer":42,"author":"Douglas Adams"}""") - doAssertRaises ValueError, fromJson(guide, json) - doAssertRaises ValueError, - fromJson(guide, json, Joptions(allowMissingKeys: true)) - - type - A = object - a1,a2,a3: int - var a: A - let j = parseJson("""{"a3": 1, "a4": 2}""") - doAssertRaises ValueError, - fromJson(a, j, Joptions(allowMissingKeys: true)) - - block testExceptionOnMissingKeys: - var guide: AboutLifeUniverseAndEverythingElse - let json = parseJson("""{"answer":42}""") - doAssertRaises ValueError, fromJson(guide, json) - doAssertRaises ValueError, - fromJson(guide, json, Joptions(allowExtraKeys: true)) - - block testAllowExtraKeys: - var guide: AboutLifeUniverseAndEverythingElse - let json = parseJson( - """{"question":"6*9=?","answer":42,"author":"Douglas Adams"}""") - fromJson(guide, json, Joptions(allowExtraKeys: true)) - doAssert guide == AboutLifeUniverseAndEverythingElse( - question: "6*9=?", answer: 42) - - block refObject: #bug 17986 - type A = ref object - case is_a: bool - of true: - a: int - else: - b: int - - var a = A() - fromJson(a, """{"is_a": true, "a":1, "extra_key": 1}""".parseJson, Joptions(allowExtraKeys: true)) - doAssert $a[] == "(is_a: true, a: 1)" - - block testAllowMissingKeys: - var guide = AboutLifeUniverseAndEverythingElse( - question: "6*9=?", answer: 54) - let json = parseJson("""{"answer":42}""") - fromJson(guide, json, Joptions(allowMissingKeys: true)) - doAssert guide == AboutLifeUniverseAndEverythingElse( - question: "6*9=?", answer: 42) - - block testAllowExtraAndMissingKeys: - var guide = AboutLifeUniverseAndEverythingElse( - question: "6*9=?", answer: 54) - let json = parseJson( - """{"answer":42,"author":"Douglas Adams"}""") - fromJson(guide, json, Joptions( - allowExtraKeys: true, allowMissingKeys: true)) - doAssert guide == AboutLifeUniverseAndEverythingElse( - question: "6*9=?", answer: 42) - - type - Foo = object - a: array[2, string] - case b: bool - of false: f: float - of true: t: tuple[i: int, s: string] - case c: range[0 .. 2] - of 0: c0: int - of 1: c1: float - of 2: c2: string - - block testExceptionOnMissingDiscriminantKey: - var foo: Foo - let json = parseJson("""{"a":["one","two"]}""") - doAssertRaises ValueError, fromJson(foo, json) - - block testDoNotResetMissingFieldsWhenHaveDiscriminantKey: - var foo = Foo(a: ["one", "two"], b: true, t: (i: 42, s: "s"), - c: 0, c0: 1) - let json = parseJson("""{"b":true,"c":2}""") - fromJson(foo, json, Joptions(allowMissingKeys: true)) - doAssert foo.a == ["one", "two"] - doAssert foo.b - doAssert foo.t == (i: 42, s: "s") - doAssert foo.c == 2 - doAssert foo.c2 == "" - - block testAllowMissingDiscriminantKeys: - var foo: Foo - let json = parseJson("""{"a":["one","two"],"c":1,"c1":3.14159}""") - fromJson(foo, json, Joptions(allowMissingKeys: true)) - doAssert foo.a == ["one", "two"] - doAssert not foo.b - doAssert foo.f == 0.0 - doAssert foo.c == 1 - doAssert foo.c1 == 3.14159 - - block testExceptionOnWrongDiscirminatBranchInJson: - var foo = Foo(b: false, f: 3.14159, c: 0, c0: 42) - let json = parseJson("""{"c2": "hello"}""") - doAssertRaises ValueError, - fromJson(foo, json, Joptions(allowMissingKeys: true)) - # Test that the original fields are not reset. - doAssert not foo.b - doAssert foo.f == 3.14159 - doAssert foo.c == 0 - doAssert foo.c0 == 42 - - block testNoExceptionOnRightDiscriminantBranchInJson: - var foo = Foo(b: false, f: 0, c:1, c1: 0) - let json = parseJson("""{"f":2.71828,"c1": 3.14159}""") - fromJson(foo, json, Joptions(allowMissingKeys: true)) - doAssert not foo.b - doAssert foo.f == 2.71828 - doAssert foo.c == 1 - doAssert foo.c1 == 3.14159 - - block testAllowExtraKeysInJsonOnWrongDisciriminatBranch: - var foo = Foo(b: false, f: 3.14159, c: 0, c0: 42) - let json = parseJson("""{"c2": "hello"}""") - fromJson(foo, json, Joptions(allowMissingKeys: true, - allowExtraKeys: true)) - # Test that the original fields are not reset. - doAssert not foo.b - doAssert foo.f == 3.14159 - doAssert foo.c == 0 - doAssert foo.c0 == 42 - - - block testInvalidTupleLength: - let json = parseJson("[0]") - # Should raise ValueError instead of index error - doAssertRaises(ValueError): - discard json.jsonTo((int, int)) - - type - InnerEnum = enum - A - B - C - InnerObject = object - x: string - y: InnerEnum - - block testOptionsArePassedWhenDeserialising: - let json = parseJson("""{"x": "hello"}""") - let inner = json.jsonTo(Option[InnerObject], Joptions(allowMissingKeys: true)) - doAssert inner.isSome() - doAssert inner.get().x == "hello" - doAssert inner.get().y == A - - block testOptionsArePassedWhenSerialising: - let inner = some InnerObject(x: "hello", y: A) - let json = inner.toJson(ToJsonOptions(enumMode: joptEnumSymbol)) - doAssert $json == """{"x":"hello","y":"A"}""" - - when false: - ## TODO: Implement support for nested variant objects allowing the tests - ## bellow to pass. - block testNestedVariantObjects: - type - Variant = object - case b: bool - of false: - case bf: bool - of false: bff: int - of true: bft: float - of true: - case bt: bool - of false: btf: string - of true: btt: char - - testRoundtrip(Variant(b: false, bf: false, bff: 42)): - """{"b": false, "bf": false, "bff": 42}""" - testRoundtrip(Variant(b: false, bf: true, bft: 3.14159)): - """{"b": false, "bf": true, "bft": 3.14159}""" - testRoundtrip(Variant(b: true, bt: false, btf: "test")): - """{"b": true, "bt": false, "btf": "test"}""" - testRoundtrip(Variant(b: true, bt: true, btt: 'c')): - """{"b": true, "bt": true, "btt": "c"}""" - - # TODO: Add additional tests with missing and extra JSON keys, both when - # allowed and forbidden analogous to the tests for the not nested - # variant objects. - -static: fn() -fn() diff --git a/tests/stdlib/tlists.nim b/tests/stdlib/tlists.nim index 701fb7974..a288af781 100644 --- a/tests/stdlib/tlists.nim +++ b/tests/stdlib/tlists.nim @@ -1,276 +1,67 @@ discard """ - targets: "c js" + output: '''true''' """ -import std/[lists, sequtils] -import std/assertions +import lists const data = [1, 2, 3, 4, 5, 6] +block SinglyLinkedListTest1: + var L: SinglyLinkedList[int] + for d in items(data): L.prepend(d) + for d in items(data): L.append(d) + assert($L == "[6, 5, 4, 3, 2, 1, 1, 2, 3, 4, 5, 6]") -template main = - block SinglyLinkedListTest1: - var L: SinglyLinkedList[int] - for d in items(data): L.prepend(d) - for d in items(data): L.add(d) - doAssert($L == "[6, 5, 4, 3, 2, 1, 1, 2, 3, 4, 5, 6]") + assert(4 in L) - doAssert(4 in L) +block SinglyLinkedListTest2: + var L: SinglyLinkedList[string] + for d in items(data): L.prepend($d) + assert($L == """["6", "5", "4", "3", "2", "1"]""") - block SinglyLinkedListTest2: - var L: SinglyLinkedList[string] - for d in items(data): L.prepend($d) - doAssert($L == """["6", "5", "4", "3", "2", "1"]""") - - doAssert("4" in L) + assert("4" in L) - block DoublyLinkedListTest1: - var L: DoublyLinkedList[int] - for d in items(data): L.prepend(d) - for d in items(data): L.add(d) - L.remove(L.find(1)) - doAssert($L == "[6, 5, 4, 3, 2, 1, 2, 3, 4, 5, 6]") +block DoublyLinkedListTest1: + var L: DoublyLinkedList[int] + for d in items(data): L.prepend(d) + for d in items(data): L.append(d) + L.remove(L.find(1)) + assert($L == "[6, 5, 4, 3, 2, 1, 2, 3, 4, 5, 6]") - doAssert(4 in L) + assert(4 in L) - block SinglyLinkedRingTest1: - var L: SinglyLinkedRing[int] - L.prepend(4) - doAssert($L == "[4]") - L.prepend(4) +block SinglyLinkedRingTest1: + var L: SinglyLinkedRing[int] + L.prepend(4) + assert($L == "[4]") + L.prepend(4) - doAssert($L == "[4, 4]") - doAssert(4 in L) + assert($L == "[4, 4]") + assert(4 in L) - block DoublyLinkedRingTest1: - var L: DoublyLinkedRing[int] - L.prepend(4) - doAssert($L == "[4]") - L.prepend(4) +block DoublyLinkedRingTest1: + var L: DoublyLinkedRing[int] + L.prepend(4) + assert($L == "[4]") + L.prepend(4) - doAssert($L == "[4, 4]") - doAssert(4 in L) + assert($L == "[4, 4]") + assert(4 in L) - L.add(3) - L.add(5) - doAssert($L == "[4, 4, 3, 5]") + L.append(3) + L.append(5) + assert($L == "[4, 4, 3, 5]") - L.remove(L.find(3)) - L.remove(L.find(5)) - L.remove(L.find(4)) - L.remove(L.find(4)) - doAssert($L == "[]") - doAssert(4 notin L) + L.remove(L.find(3)) + L.remove(L.find(5)) + L.remove(L.find(4)) + L.remove(L.find(4)) + assert($L == "[]") + assert(4 notin L) - block tlistsToString: - block: - var l = initDoublyLinkedList[int]() - l.add(1) - l.add(2) - l.add(3) - doAssert $l == "[1, 2, 3]" - block: - var l = initDoublyLinkedList[string]() - l.add("1") - l.add("2") - l.add("3") - doAssert $l == """["1", "2", "3"]""" - block: - var l = initDoublyLinkedList[char]() - l.add('1') - l.add('2') - l.add('3') - doAssert $l == """['1', '2', '3']""" - # Copied here until it is merged into sequtils - template take(a: untyped, max: int): untyped = - type T = typeof(block: (for ai in a: ai)) - var ret: seq[T] - var i = 0 - if max > 0: - for ai in a: - ret.add ai - i.inc - if i >= max: break - ret +echo "true" - template testCommon(initList, toList) = - - block: # toSinglyLinkedList, toDoublyLinkedList - let l = seq[int].default - doAssert l.toList.toSeq == [] - doAssert [1].toList.toSeq == [1] - doAssert [1, 2, 3].toList.toSeq == [1, 2, 3] - - block copy: - doAssert array[0, int].default.toList.copy.toSeq == [] - doAssert [1].toList.copy.toSeq == [1] - doAssert [1, 2].toList.copy.toSeq == [1, 2] - doAssert [1, 2, 3].toList.copy.toSeq == [1, 2, 3] - type Foo = ref object - x: int - var f0 = Foo(x: 0) - let f1 = Foo(x: 1) - var a = [f0].toList - var b = a.copy - b.add f1 - doAssert a.toSeq == [f0] - doAssert b.toSeq == [f0, f1] - f0.x = 42 - doAssert a.head.value.x == 42 - doAssert b.head.value.x == 42 - - block: # add, addMoved - block: - var - l0 = initList[int]() - l1 = [1].toList - l2 = [2, 3].toList - l3 = [4, 5, 6].toList - l0.add l3 - l1.add l3 - l2.addMoved l3 - doAssert l0.toSeq == [4, 5, 6] - doAssert l1.toSeq == [1, 4, 5, 6] - doAssert l2.toSeq == [2, 3, 4, 5, 6] - doAssert l3.toSeq == [] - l2.add l3 # re-adding l3 that was destroyed is now a no-op - doAssert l2.toSeq == [2, 3, 4, 5, 6] - doAssert l3.toSeq == [] - block: - var - l0 = initList[int]() - l1 = [1].toList - l2 = [2, 3].toList - l3 = [4, 5, 6].toList - l3.addMoved l0 - l2.addMoved l1 - doAssert l3.toSeq == [4, 5, 6] - doAssert l2.toSeq == [2, 3, 1] - l3.add l0 - doAssert l3.toSeq == [4, 5, 6] - block: - var c = [0, 1].toList - c.addMoved c - doAssert c.take(6) == [0, 1, 0, 1, 0, 1] - - block: # prepend, prependMoved - block: - var - l0 = initList[int]() - l1 = [1].toList - l2 = [2, 3].toList - l3 = [4, 5, 6].toList - l0.prepend l3 - l1.prepend l3 - doAssert l3.toSeq == [4, 5, 6] - l2.prependMoved l3 - doAssert l0.toSeq == [4, 5, 6] - doAssert l1.toSeq == [4, 5, 6, 1] - doAssert l2.toSeq == [4, 5, 6, 2, 3] - doAssert l3.toSeq == [] - l2.prepend l3 # re-prepending l3 that was destroyed is now a no-op - doAssert l2.toSeq == [4, 5, 6, 2, 3] - doAssert l3.toSeq == [] - block: - var - l0 = initList[int]() - l1 = [1].toList - l2 = [2, 3].toList - l3 = [4, 5, 6].toList - l3.prependMoved l0 - l2.prependMoved l1 - doAssert l3.toSeq == [4, 5, 6] - doAssert l2.toSeq == [1, 2, 3] - l3.prepend l0 - doAssert l3.toSeq == [4, 5, 6] - block: - var c = [0, 1].toList - c.prependMoved c - doAssert c.take(6) == [0, 1, 0, 1, 0, 1] - - block remove: - var l = [0, 1, 2, 3].toList - let - l0 = l.head - l1 = l0.next - l2 = l1.next - l3 = l2.next - l.remove l0 - doAssert l.toSeq == [1, 2, 3] - l.remove l2 - doAssert l.toSeq == [1, 3] - l.remove l2 - doAssert l.toSeq == [1, 3] - l.remove l3 - doAssert l.toSeq == [1] - l.remove l1 - doAssert l.toSeq == [] - # Cycle preservation - var a = [10, 11, 12].toList - a.addMoved a - doAssert a.take(6) == @[10, 11, 12, 10, 11, 12] - a.remove a.head.next - doAssert a.take(6) == @[10, 12, 10, 12, 10, 12] - a.remove a.head - doAssert a.take(6) == @[12, 12, 12, 12, 12, 12] - - testCommon initSinglyLinkedList, toSinglyLinkedList - testCommon initDoublyLinkedList, toDoublyLinkedList - - block remove: # return value check - var l = [0, 1, 2, 3].toSinglyLinkedList - let n = l.head.next.next - doAssert l.remove(n) == true - doAssert l.toSeq == [0, 1, 3] - doAssert l.remove(n) == false - doAssert l.toSeq == [0, 1, 3] - doAssert l.remove(l.head) == true - doAssert l.toSeq == [1, 3] - doAssert l.remove(l.head.next) == true - doAssert l.toSeq == [1] - doAssert l.remove(l.head) == true - doAssert l.toSeq == [] - - block issue19297: # add (appends a shallow copy) - var a: SinglyLinkedList[int] - var b: SinglyLinkedList[int] - - doAssert a.toSeq == @[] - a.add(1) - doAssert a.toSeq == @[1] - a.add(b) - doAssert a.toSeq == @[1] - a.add(2) - doAssert a.toSeq == @[1, 2] - - block issue19314: # add (appends a shallow copy) - var a: DoublyLinkedList[int] - var b: DoublyLinkedList[int] - - doAssert a.toSeq == @[] - a.add(1) - doAssert a.toSeq == @[1] - a.add(b) - doAssert a.toSeq == @[1] - a.add(2) - doAssert a.toSeq == @[1, 2] - - block RemoveLastNodeFromSinglyLinkedList: - var list = initSinglyLinkedList[string]() - let n1 = newSinglyLinkedNode("sonic") - let n2 = newSinglyLinkedNode("the") - let n3 = newSinglyLinkedNode("tiger") - let n4 = newSinglyLinkedNode("hedgehog") - list.add(n1) - list.add(n2) - list.add(n3) - list.remove(n3) - list.add(n4) - doAssert list.toSeq == @["sonic", "the", "hedgehog"] - -static: main() -main() diff --git a/tests/stdlib/tlocks.nim b/tests/stdlib/tlocks.nim index 9ce9afd13..e567cfde8 100644 --- a/tests/stdlib/tlocks.nim +++ b/tests/stdlib/tlocks.nim @@ -1,11 +1,10 @@ discard """ - targets: "c cpp js" - matrix: "--threads:on" + output: '''3''' + cmd: "nim $target --threads:on $options $file" """ #bug #6049 import uselocks -import std/assertions var m = createMyType[int]() -doAssert m.use() == 3 +echo $m.use() diff --git a/tests/stdlib/tlwip.nim b/tests/stdlib/tlwip.nim deleted file mode 100644 index fc53be592..000000000 --- a/tests/stdlib/tlwip.nim +++ /dev/null @@ -1,30 +0,0 @@ -discard """ - targets: "c" - cmd: "nim $target --compileOnly --os:freertos --gc:arc $options $file" - disabled: "bsd" - disabled: "windows" - action: compile -""" - -# Note: -# This file tests FreeRTOS/LwIP cross-compilation on UNIX platforms -# Windows should run when compiled with esp-idf, however I'm not -# sure how to test for only compilation on Windows without running -# a test exe -# -# Note: -# disabling *BSDs since they're not playing well with `gcc` - -import net -import asynchttpserver, asyncdispatch - -proc cb*(req: Request) {.async.} = - await req.respond(Http200, "Hello World") - -proc run_http_server*() {.exportc.} = - echo "starting http server" - var server = newAsyncHttpServer() - - waitFor server.serve(Port(8181), cb) - -echo("ok") diff --git a/tests/stdlib/tmacros.nim b/tests/stdlib/tmacros.nim deleted file mode 100644 index 9e3ebee83..000000000 --- a/tests/stdlib/tmacros.nim +++ /dev/null @@ -1,321 +0,0 @@ -#[ -xxx macros tests need to be reorganized to makes sure each API is tested once -See also: - tests/macros/tdumpast.nim for treeRepr + friends -]# - -import std/macros -import std/assertions - -block: # hasArgOfName - macro m(u: untyped): untyped = - for name in ["s","i","j","k","b","xs","ys"]: - doAssert hasArgOfName(params u,name) - doAssert not hasArgOfName(params u,"nonexistent") - - proc p(s: string; i,j,k: int; b: bool; xs,ys: seq[int] = @[]) {.m.} = discard - -block: # bug #17454 - proc f(v: NimNode): string {.raises: [].} = $v - -block: # unpackVarargs - block: - proc bar1(a: varargs[int]): string = - for ai in a: result.add " " & $ai - proc bar2(a: varargs[int]) = - let s1 = bar1(a) - let s2 = unpackVarargs(bar1, a) # `unpackVarargs` makes no difference here - doAssert s1 == s2 - bar2(1, 2, 3) - bar2(1) - bar2() - - block: - template call1(fun: typed; args: varargs[untyped]): untyped = - unpackVarargs(fun, args) - template call2(fun: typed; args: varargs[untyped]): untyped = - # fun(args) # works except for last case with empty `args`, pending bug #9996 - when varargsLen(args) > 0: fun(args) - else: fun() - - proc fn1(a = 0, b = 1) = discard (a, b) - - call1(fn1) - call1(fn1, 10) - call1(fn1, 10, 11) - - call2(fn1) - call2(fn1, 10) - call2(fn1, 10, 11) - - block: - template call1(fun: typed; args: varargs[typed]): untyped = - unpackVarargs(fun, args) - template call2(fun: typed; args: varargs[typed]): untyped = - # xxx this would give a confusing error message: - # required type for a: varargs[typed] [varargs] but expression '[10]' is of type: varargs[typed] [varargs] - when varargsLen(args) > 0: fun(args) - else: fun() - macro toString(a: varargs[typed, `$`]): string = - var msg = genSym(nskVar, "msg") - result = newStmtList() - result.add quote do: - var `msg` = "" - for ai in a: - result.add quote do: `msg`.add $`ai` - result.add quote do: `msg` - doAssert call1(toString) == "" - doAssert call1(toString, 10) == "10" - doAssert call1(toString, 10, 11) == "1011" - -block: # SameType - type - A = int - B = distinct int - C = object - Generic[T, Y] = object - macro isSameType(a, b: typed): untyped = - newLit(sameType(a, b)) - - static: - assert Generic[int, int].isSameType(Generic[int, int]) - assert Generic[A, string].isSameType(Generic[int, string]) - assert not Generic[A, string].isSameType(Generic[B, string]) - assert not Generic[int, string].isSameType(Generic[int, int]) - assert isSameType(int, A) - assert isSameType(10, 20) - assert isSameType("Hello", "world") - assert not isSameType("Hello", cstring"world") - assert not isSameType(int, B) - assert not isSameType(int, Generic[int, int]) - assert not isSameType(C, string) - assert not isSameType(C, int) - - - #[ - # compiler sameType fails for the following, read more in `types.nim`'s `sameTypeAux`. - type - D[T] = C - G[T] = T - static: - assert isSameType(D[int], C) - assert isSameType(D[int], D[float]) - assert isSameType(G[float](1.0), float(1.0)) - assert isSameType(float(1.0), G[float](1.0)) - ]# - - type Tensor[T] = object - data: T - - macro testTensorInt(x: typed): untyped = - let - tensorIntType = getTypeInst(Tensor[int])[1] - xTyp = x.getTypeInst - - newLit(xTyp.sameType(tensorIntType)) - - var - x: Tensor[int] - x1 = Tensor[float]() - x2 = Tensor[A]() - x3 = Tensor[B]() - - static: - assert testTensorInt(x) - assert not testTensorInt(x1) - assert testTensorInt(x2) - assert not testTensorInt(x3) - -block: # extractDocCommentsAndRunnables - macro checkRunnables(prc: untyped) = - let runnables = prc.body.extractDocCommentsAndRunnables() - doAssert runnables[0][0].eqIdent("runnableExamples") - - macro checkComments(comment: static[string], prc: untyped) = - let comments = prc.body.extractDocCommentsAndRunnables() - doAssert comments[0].strVal == comment - - proc a() {.checkRunnables.} = - runnableExamples: discard - discard - - proc b() {.checkRunnables.} = - runnableExamples "-d:ssl": discard - discard - - proc c() {.checkComments("Hello world").} = - ## Hello world - -block: # bug #19020 - type - foo = object - - template typ(T:typedesc) {.pragma.} - - proc bar() {.typ: foo.} = discard - - static: - doAssert $bar.getCustomPragmaVal(typ) == "foo" - doAssert $bar.getCustomPragmaVal(typ) == "foo" - -block hasCustomPragmaGeneric: - template examplePragma() {.pragma.} - type - Foo[T] {.examplePragma.} = object - x {.examplePragma.}: T - var f: Foo[string] - doAssert f.hasCustomPragma(examplePragma) - doAssert f.x.hasCustomPragma(examplePragma) - -block getCustomPragmaValGeneric: - template examplePragma(x: int) {.pragma.} - type - Foo[T] {.examplePragma(42).} = object - x {.examplePragma(25).}: T - var f: Foo[string] - doAssert f.getCustomPragmaVal(examplePragma) == 42 - doAssert f.x.getCustomPragmaVal(examplePragma) == 25 - -block: # bug #21326 - macro foo(body: untyped): untyped = - let a = body.lineInfoObj() - let aLit = a.newLit - result = quote do: - doAssert $`a` == $`aLit` - - foo: - let c = 1 - - template name(a: LineInfo): untyped = - discard a # `aLit` works though - - macro foo3(body: untyped): untyped = - let a = body.lineInfoObj() - # let ax = newLit(a) - result = getAst(name(a)) - - foo3: - let c = 1 - -block: # bug #7375 - macro fails(b: static[bool]): untyped = - doAssert b == false - result = newStmtList() - - macro foo(): untyped = - - var b = false - - ## Fails - result = quote do: - fails(`b`) - - foo() - - macro someMacro(): untyped = - template tmpl(boolean: bool) = - when boolean: - discard "it's true!" - else: - doAssert false - result = getAst(tmpl(true)) - - someMacro() - -block: - macro foo(): untyped = - result = quote do: `littleEndian` - - doAssert littleEndian == foo() - -block: - macro eqSym(x, y: untyped): untyped = - let eq = $x == $y # Unfortunately eqIdent compares to string. - result = quote do: `eq` - - var r, a, b: int - - template fma(result: var int, a, b: int, op: untyped) = - # fused multiple-add - when eqSym(op, `+=`): - discard "+=" - else: - discard "+" - - fma(r, a, b, `+=`) - -block: - template test(boolArg: bool) = - static: - doAssert typeof(boolArg) is bool - let x: bool = boolArg # compile error here, because boolArg became an int - - macro testWrapped1(boolArg: bool): untyped = - # forwarding boolArg directly works - result = getAst(test(boolArg)) - - macro testWrapped2(boolArg: bool): untyped = - # forwarding boolArg via a local variable also works - let b = boolArg - result = getAst(test(b)) - - macro testWrapped3(boolArg: bool): untyped = - # but using a literal `true` as a local variable will be converted to int - let b = true - result = getAst(test(b)) - - test(true) # ok - testWrapped1(true) # ok - testWrapped2(true) # ok - testWrapped3(true) - -block: - macro foo(): untyped = - var s = { 'a', 'b' } - quote do: - let t = `s` - doAssert $typeof(t) == "set[char]" - - foo() - -block: # bug #9607 - proc fun1(info:LineInfo): string = "bar" - proc fun2(info:int): string = "bar" - - macro echoL(args: varargs[untyped]): untyped = - let info = args.lineInfoObj - let fun1 = bindSym"fun1" - let fun2 = bindSym"fun2" - - # this would work instead - # result = newCall(bindSym"fun2", info.line.newLit) - - result = quote do: - - # BUG1: ???(0, 0) Error: internal error: genLiteral: ty is nil - `fun1`(`info`) - - macro echoM(args: varargs[untyped]): untyped = - let info = args.lineInfoObj - let fun1 = bindSym"fun1" - let fun2 = bindSym"fun2" - - # this would work instead - # result = newCall(bindSym"fun2", info.line.newLit) - - result = quote do: - - # BUG1: ???(0, 0) Error: internal error: genLiteral: ty is nil - `fun2`(`info`.line) - - - doAssert echoL() == "bar" - doAssert echoM() == "bar" - -block: - macro hello[T](x: T): untyped = - result = quote do: - let m: `T` = `x` - discard m - - hello(12) diff --git a/tests/stdlib/tmarshal.nim b/tests/stdlib/tmarshal.nim index f972332a2..a6fc6c1a5 100644 --- a/tests/stdlib/tmarshal.nim +++ b/tests/stdlib/tmarshal.nim @@ -1,24 +1,23 @@ discard """ - matrix: "--mm:orc; --mm:refc" + output: '''{"age": 12, "bio": "Я Cletus", "blob": [65, 66, 67, 128], "name": "Cletus"} +true +true +alpha 100 +omega 200 +''' """ -import std/marshal -import std/[assertions, objectdollar] +import marshal -# TODO: add static tests +template testit(x) = discard $$to[type(x)]($$x) -proc testit[T](x: T): string = $$to[T]($$x) - -template check1 = - let test1: array[0..1, array[0..4, string]] = [ - ["test", "1", "2", "3", "4"], ["test", "1", "2", "3", "4"]] - doAssert testit(test1) == - """[["test", "1", "2", "3", "4"], ["test", "1", "2", "3", "4"]]""" - let test2: tuple[name: string, s: int] = ("tuple test", 56) - doAssert testit(test2) == """{"Field0": "tuple test", "Field1": 56}""" - -static: check1() -check1() +var x: array[0..4, array[0..4, string]] = [ + ["test", "1", "2", "3", "4"], ["test", "1", "2", "3", "4"], + ["test", "1", "2", "3", "4"], ["test", "1", "2", "3", "4"], + ["test", "1", "2", "3", "4"]] +testit(x) +var test2: tuple[name: string, s: int] = ("tuple test", 56) +testit(test2) type TE = enum @@ -49,145 +48,73 @@ proc buildList(): PNode = result.prev.next = result result.prev.prev = result.next -let test3 = TestObj(test: 42, test2: blah) -doAssert testit(test3) == - """{"test": 42, "asd": 0, "test2": "blah", "help": ""}""" +var test3: TestObj +test3.test = 42 +test3.test2 = blah +testit(test3) var test4: ref tuple[a, b: string] new(test4) test4.a = "ref string test: A" test4.b = "ref string test: B" -discard testit(test4) # serialization uses the pointer address, which is not consistent +testit(test4) -let test5 = @[(0,1),(2,3),(4,5)] -doAssert testit(test5) == - """[{"Field0": 0, "Field1": 1}, {"Field0": 2, "Field1": 3}, {"Field0": 4, "Field1": 5}]""" +var test5 = @[(0,1),(2,3),(4,5)] +testit(test5) -let test6: set[char] = {'A'..'Z', '_'} -doAssert testit(test6) == - """[65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 95]""" +var test7 = buildList() +testit(test7) -let test7 = buildList() -discard testit(test7) # serialization uses the pointer address, which is not consistent +var test6: set[char] = {'A'..'Z', '_'} +testit(test6) # bug #1352 -block: - type - Entity = object of RootObj - name: string - Person = object of Entity - age: int - bio: string - blob: string +type + Entity = object of RootObj + name: string - let instance1 = Person(name: "Cletus", age: 12, - bio: "Я Cletus", - blob: "ABC\x80") - doAssert $$instance1 == """{"age": 12, "bio": "Я Cletus", "blob": [65, 66, 67, 128], "name": "Cletus"}""" - doAssert to[Person]($$instance1).bio == instance1.bio - doAssert to[Person]($$instance1).blob == instance1.blob + Person = object of Entity + age: int + bio: string + blob: string -# bug #5757 -block: - type - Something = object - x: string - y: int +var instance1 = Person(name: "Cletus", age: 12, + bio: "Я Cletus", + blob: "ABC\x80") +echo($$instance1) +echo(to[Person]($$instance1).bio == instance1.bio) +echo(to[Person]($$instance1).blob == instance1.blob) - let data1 = """{"x": "alpha", "y": 100}""" - let data2 = """{"x": "omega", "y": 200}""" +# bug 5757 - var r = to[Something](data1) - doAssert $r.x & " " & $r.y == "alpha 100" - r = to[Something](data2) - doAssert $r.x & " " & $r.y == "omega 200" +type + Something = object + x: string + y: int -block: - type - Foo = object - a1: string - a2: string - a3: seq[string] - a4: seq[int] - a5: seq[int] - a6: seq[int] - var foo = Foo(a2: "", a4: @[], a6: @[1]) - foo.a6.setLen 0 - doAssert $$foo == """{"a1": "", "a2": "", "a3": [], "a4": [], "a5": [], "a6": []}""" - doAssert testit(foo) == """{"a1": "", "a2": "", "a3": [], "a4": [], "a5": [], "a6": []}""" +var data1 = """{"x": "alpha", "y": 100}""" +var data2 = """{"x": "omega", "y": 200}""" -import std/[options, json] +var r = to[Something](data1) -# bug #15934 -block: - let - a1 = some(newJNull()) - a2 = none(JsonNode) - doAssert $($$a1).to[:Option[JsonNode]] == "some(null)" - doAssert $($$a2).to[:Option[JsonNode]] == "none(JsonNode)" - doAssert ($$a1).to[:Option[JsonNode]] == some(newJNull()) - doAssert ($$a2).to[:Option[JsonNode]] == none(JsonNode) +echo r.x, " ", r.y -# bug #15620 -block: - let str = """{"numeric": null}""" +r = to[Something](data2) - type - LegacyEntry = object - numeric: string +echo r.x, " ", r.y - let test = to[LegacyEntry](str) - doAssert $test == """(numeric: "")""" -block: - let str = """{"numeric": null}""" - - type - LegacyEntry = object - numeric: seq[int] - - var test = to[LegacyEntry](str) - doAssert $test == """(numeric: @[])""" - -# bug #16022 -block: - let p: proc (): string = proc (): string = "hello world" - let poc = to[typeof(p)]($$p) - doAssert poc() == "hello world" - -block: - type - A {.inheritable.} = object - B = object of A - f: int - - let a: ref A = new(B) - doAssert $$a[] == "{}" # not "{f: 0}" - -template checkMarshal(data: typed) = - let orig = data - let m = $$orig - - let old = to[typeof(orig)](m) - doAssert data == old - -template main() = - type - Book = object - page: int - name: string - - let book = Book(page: 12, name: "persona") - - checkMarshal(486) - checkMarshal(3.14) - checkMarshal("azure sky") - checkMarshal(book) - checkMarshal([1, 2, 3]) - checkMarshal(@[1.5, 2.7, 3.9, 4.2]) - checkMarshal(@["dream", "is", "possible"]) - -static: main() -main() +type + Foo = object + a1: string + a2: string + a3: seq[string] + a4: seq[int] + a5: seq[int] + a6: seq[int] +var foo = Foo(a2: "", a4: @[], a6: @[1]) +foo.a6.setLen 0 +doAssert $$foo == """{"a1": "", "a2": "", "a3": [], "a4": [], "a5": [], "a6": []}""" +testit(foo) diff --git a/tests/stdlib/tmath.nim b/tests/stdlib/tmath.nim index 66c1f8ca0..a023be86c 100644 --- a/tests/stdlib/tmath.nim +++ b/tests/stdlib/tmath.nim @@ -1,444 +1,147 @@ discard """ - targets: "c cpp js" - matrix:"; -d:danger" + action: run + output: '''[Suite] random int + +[Suite] random float + +[Suite] cumsum + +[Suite] random sample + +[Suite] ^ + +''' """ -# xxx: there should be a test with `-d:nimTmathCase2 -d:danger --passc:-ffast-math`, -# but it requires disabling certain lines with `when not defined(nimTmathCase2)` - -import std/math -import std/assertions - - -# Function for approximate comparison of floats -proc `==~`(x, y: float): bool = abs(x - y) < 1e-9 - - -template main() = - block: - when not defined(js): - # check for no side effect annotation - proc mySqrt(num: float): float {.noSideEffect.} = - # xxx unused - sqrt(num) - - # check gamma function - doAssert gamma(5.0) == 24.0 # 4! - doAssert almostEqual(gamma(0.5), sqrt(PI)) - doAssert almostEqual(gamma(-0.5), -2 * sqrt(PI)) - doAssert lgamma(1.0) == 0.0 # ln(1.0) == 0.0 - doAssert almostEqual(lgamma(0.5), 0.5 * ln(PI)) - doAssert erf(6.0) > erf(5.0) - doAssert erfc(6.0) < erfc(5.0) - - block: # sgn() tests - doAssert sgn(1'i8) == 1 - doAssert sgn(1'i16) == 1 - doAssert sgn(1'i32) == 1 - doAssert sgn(1'i64) == 1 - doAssert sgn(1'u8) == 1 - doAssert sgn(1'u16) == 1 - doAssert sgn(1'u32) == 1 - doAssert sgn(1'u64) == 1 - doAssert sgn(-12342.8844'f32) == -1 - doAssert sgn(123.9834'f64) == 1 - doAssert sgn(0'i32) == 0 - doAssert sgn(0'f32) == 0 - doAssert sgn(-0.0'f64) == 0 - doAssert sgn(NegInf) == -1 - doAssert sgn(Inf) == 1 - doAssert sgn(NaN) == 0 - - block: # fac() tests - when nimvm: discard - else: - try: - discard fac(-1) - except AssertionDefect: - discard - - doAssert fac(0) == 1 - doAssert fac(1) == 1 - doAssert fac(2) == 2 - doAssert fac(3) == 6 - doAssert fac(4) == 24 - doAssert fac(5) == 120 - - block: # floorMod/floorDiv - doAssert floorDiv(8, 3) == 2 - doAssert floorMod(8, 3) == 2 - - doAssert floorDiv(8, -3) == -3 - doAssert floorMod(8, -3) == -1 - - doAssert floorDiv(-8, 3) == -3 - doAssert floorMod(-8, 3) == 1 - - doAssert floorDiv(-8, -3) == 2 - doAssert floorMod(-8, -3) == -2 - - doAssert floorMod(8.0, -3.0) == -1.0 - doAssert floorMod(-8.5, 3.0) == 0.5 - - block: # euclDiv/euclMod - doAssert euclDiv(8, 3) == 2 - doAssert euclMod(8, 3) == 2 - - doAssert euclDiv(8, -3) == -2 - doAssert euclMod(8, -3) == 2 - - doAssert euclDiv(-8, 3) == -3 - doAssert euclMod(-8, 3) == 1 - - doAssert euclDiv(-8, -3) == 3 - doAssert euclMod(-8, -3) == 1 - - doAssert euclMod(8.0, -3.0) == 2.0 - doAssert euclMod(-8.5, 3.0) == 0.5 - - doAssert euclDiv(9, 3) == 3 - doAssert euclMod(9, 3) == 0 - - doAssert euclDiv(9, -3) == -3 - doAssert euclMod(9, -3) == 0 - - doAssert euclDiv(-9, 3) == -3 - doAssert euclMod(-9, 3) == 0 - - doAssert euclDiv(-9, -3) == 3 - doAssert euclMod(-9, -3) == 0 - - block: # ceilDiv - doAssert ceilDiv(8, 3) == 3 - doAssert ceilDiv(8, 4) == 2 - doAssert ceilDiv(8, 5) == 2 - doAssert ceilDiv(11, 3) == 4 - doAssert ceilDiv(12, 3) == 4 - doAssert ceilDiv(13, 3) == 5 - doAssert ceilDiv(41, 7) == 6 - doAssert ceilDiv(0, 1) == 0 - doAssert ceilDiv(1, 1) == 1 - doAssert ceilDiv(1, 2) == 1 - doAssert ceilDiv(2, 1) == 2 - doAssert ceilDiv(2, 2) == 1 - doAssert ceilDiv(0, high(int)) == 0 - doAssert ceilDiv(1, high(int)) == 1 - doAssert ceilDiv(0, high(int) - 1) == 0 - doAssert ceilDiv(1, high(int) - 1) == 1 - doAssert ceilDiv(high(int) div 2, high(int) div 2 + 1) == 1 - doAssert ceilDiv(high(int) div 2, high(int) div 2 + 2) == 1 - doAssert ceilDiv(high(int) div 2 + 1, high(int) div 2) == 2 - doAssert ceilDiv(high(int) div 2 + 2, high(int) div 2) == 2 - doAssert ceilDiv(high(int) div 2 + 1, high(int) div 2 + 1) == 1 - doAssert ceilDiv(high(int), 1) == high(int) - doAssert ceilDiv(high(int) - 1, 1) == high(int) - 1 - doAssert ceilDiv(high(int) - 1, 2) == high(int) div 2 - doAssert ceilDiv(high(int) - 1, high(int)) == 1 - doAssert ceilDiv(high(int) - 1, high(int) - 1) == 1 - doAssert ceilDiv(high(int) - 1, high(int) - 2) == 2 - doAssert ceilDiv(high(int), high(int)) == 1 - doAssert ceilDiv(high(int), high(int) - 1) == 2 - doAssert ceilDiv(255'u8, 1'u8) == 255'u8 - doAssert ceilDiv(254'u8, 2'u8) == 127'u8 - when not defined(danger): - doAssertRaises(AssertionDefect): discard ceilDiv(41, 0) - doAssertRaises(AssertionDefect): discard ceilDiv(41, -1) - doAssertRaises(AssertionDefect): discard ceilDiv(-1, 1) - doAssertRaises(AssertionDefect): discard ceilDiv(-1, -1) - doAssertRaises(AssertionDefect): discard ceilDiv(254'u8, 3'u8) - doAssertRaises(AssertionDefect): discard ceilDiv(255'u8, 2'u8) - - block: # splitDecimal() tests - doAssert splitDecimal(54.674).intpart == 54.0 - doAssert splitDecimal(54.674).floatpart ==~ 0.674 - doAssert splitDecimal(-693.4356).intpart == -693.0 - doAssert splitDecimal(-693.4356).floatpart ==~ -0.4356 - doAssert splitDecimal(0.0).intpart == 0.0 - doAssert splitDecimal(0.0).floatpart == 0.0 - - block: # trunc tests for vcc - doAssert trunc(-1.1) == -1 - doAssert trunc(1.1) == 1 - doAssert trunc(-0.1) == -0 - doAssert trunc(0.1) == 0 - - # special case - doAssert classify(trunc(1e1000000)) == fcInf - doAssert classify(trunc(-1e1000000)) == fcNegInf - when not defined(nimTmathCase2): - doAssert classify(trunc(0.0/0.0)) == fcNan - doAssert classify(trunc(0.0)) == fcZero - - # trick the compiler to produce signed zero - let - f_neg_one = -1.0 - f_zero = 0.0 - f_nan = f_zero / f_zero - - doAssert classify(trunc(f_neg_one*f_zero)) == fcNegZero - - doAssert trunc(-1.1'f32) == -1 - doAssert trunc(1.1'f32) == 1 - doAssert trunc(-0.1'f32) == -0 - doAssert trunc(0.1'f32) == 0 - doAssert classify(trunc(1e1000000'f32)) == fcInf - doAssert classify(trunc(-1e1000000'f32)) == fcNegInf - when not defined(nimTmathCase2): - doAssert classify(trunc(f_nan.float32)) == fcNan - doAssert classify(trunc(0.0'f32)) == fcZero - - block: # log - doAssert log(4.0, 3.0) ==~ ln(4.0) / ln(3.0) - doAssert log2(8.0'f64) == 3.0'f64 - doAssert log2(4.0'f64) == 2.0'f64 - doAssert log2(2.0'f64) == 1.0'f64 - doAssert log2(1.0'f64) == 0.0'f64 - doAssert classify(log2(0.0'f64)) == fcNegInf - - doAssert log2(8.0'f32) == 3.0'f32 - doAssert log2(4.0'f32) == 2.0'f32 - doAssert log2(2.0'f32) == 1.0'f32 - doAssert log2(1.0'f32) == 0.0'f32 - doAssert classify(log2(0.0'f32)) == fcNegInf - - block: # cumsum - block: # cumsum int seq return - let counts = [1, 2, 3, 4] - doAssert counts.cumsummed == @[1, 3, 6, 10] - let empty: seq[int] = @[] - doAssert empty.cumsummed == @[] - - block: # cumsum float seq return - let counts = [1.0, 2.0, 3.0, 4.0] - doAssert counts.cumsummed == @[1.0, 3.0, 6.0, 10.0] - let empty: seq[float] = @[] - doAssert empty.cumsummed == @[] - - block: # cumsum int in-place - var counts = [1, 2, 3, 4] - counts.cumsum - doAssert counts == [1, 3, 6, 10] - var empty: seq[int] = @[] - empty.cumsum - doAssert empty == @[] - - block: # cumsum float in-place - var counts = [1.0, 2.0, 3.0, 4.0] - counts.cumsum - doAssert counts == [1.0, 3.0, 6.0, 10.0] - var empty: seq[float] = @[] - empty.cumsum - doAssert empty == @[] - - block: # ^ compiles for valid types - doAssert: compiles(5 ^ 2) - doAssert: compiles(5.5 ^ 2) - doAssert: compiles(5.5 ^ 2.int8) - doAssert: compiles(5.5 ^ 2.uint) - doAssert: compiles(5.5 ^ 2.uint8) - doAssert: not compiles(5.5 ^ 2.2) - - block: # isNaN - doAssert NaN.isNaN - doAssert not Inf.isNaN - doAssert isNaN(Inf - Inf) - doAssert not isNaN(0.0) - doAssert not isNaN(3.1415926) - doAssert not isNaN(0'f32) - - block: # signbit - doAssert not signbit(0.0) - doAssert signbit(-0.0) - doAssert signbit(-0.1) - doAssert not signbit(0.1) - - doAssert not signbit(Inf) - doAssert signbit(-Inf) - doAssert not signbit(NaN) - - let x1 = NaN - let x2 = -NaN - let x3 = -x1 - - doAssert isNaN(x1) - doAssert isNaN(x2) - doAssert isNaN(x3) - doAssert not signbit(x1) - doAssert signbit(x2) - doAssert signbit(x3) - - block: # copySign - doAssert copySign(10.0, 1.0) == 10.0 - doAssert copySign(10.0, -1.0) == -10.0 - doAssert copySign(-10.0, -1.0) == -10.0 - doAssert copySign(-10.0, 1.0) == 10.0 - doAssert copySign(float(10), -1.0) == -10.0 - - doAssert copySign(10.0'f64, 1.0) == 10.0 - doAssert copySign(10.0'f64, -1.0) == -10.0 - doAssert copySign(-10.0'f64, -1.0) == -10.0 - doAssert copySign(-10.0'f64, 1.0) == 10.0 - doAssert copySign(10'f64, -1.0) == -10.0 - - doAssert copySign(10.0'f32, 1.0) == 10.0 - doAssert copySign(10.0'f32, -1.0) == -10.0 - doAssert copySign(-10.0'f32, -1.0) == -10.0 - doAssert copySign(-10.0'f32, 1.0) == 10.0 - doAssert copySign(10'f32, -1.0) == -10.0 - - doAssert copySign(Inf, -1.0) == -Inf - doAssert copySign(-Inf, 1.0) == Inf - doAssert copySign(Inf, 1.0) == Inf - doAssert copySign(-Inf, -1.0) == -Inf - doAssert copySign(Inf, 0.0) == Inf - doAssert copySign(Inf, -0.0) == -Inf - doAssert copySign(-Inf, 0.0) == Inf - doAssert copySign(-Inf, -0.0) == -Inf - doAssert copySign(1.0, -0.0) == -1.0 - doAssert copySign(0.0, -0.0) == -0.0 - doAssert copySign(-1.0, 0.0) == 1.0 - doAssert copySign(10.0, 0.0) == 10.0 - doAssert copySign(-1.0, NaN) == 1.0 - doAssert copySign(10.0, NaN) == 10.0 - - doAssert copySign(NaN, NaN).isNaN - doAssert copySign(-NaN, NaN).isNaN - doAssert copySign(NaN, -NaN).isNaN - doAssert copySign(-NaN, -NaN).isNaN - doAssert copySign(NaN, 0.0).isNaN - doAssert copySign(NaN, -0.0).isNaN - doAssert copySign(-NaN, 0.0).isNaN - doAssert copySign(-NaN, -0.0).isNaN - - doAssert copySign(-1.0, NaN) == 1.0 - doAssert copySign(-1.0, -NaN) == -1.0 - doAssert copySign(1.0, copySign(NaN, -1.0)) == -1.0 - - block: # almostEqual - doAssert almostEqual(3.141592653589793, 3.1415926535897936) - doAssert almostEqual(1.6777215e7'f32, 1.6777216e7'f32) - doAssert almostEqual(Inf, Inf) - doAssert almostEqual(-Inf, -Inf) - doAssert not almostEqual(Inf, -Inf) - doAssert not almostEqual(-Inf, Inf) - doAssert not almostEqual(Inf, NaN) - doAssert not almostEqual(NaN, NaN) - - block: # round - block: # Round to 0 decimal places - doAssert round(54.652) == 55.0 - doAssert round(54.352) == 54.0 - doAssert round(-54.652) == -55.0 - doAssert round(-54.352) == -54.0 - doAssert round(0.0) == 0.0 - doAssert 1 / round(0.0) == Inf - doAssert 1 / round(-0.0) == -Inf - doAssert round(Inf) == Inf - doAssert round(-Inf) == -Inf - doAssert round(NaN).isNaN - doAssert round(-NaN).isNaN - doAssert round(-0.5) == -1.0 - doAssert round(0.5) == 1.0 - doAssert round(-1.5) == -2.0 - doAssert round(1.5) == 2.0 - doAssert round(-2.5) == -3.0 - doAssert round(2.5) == 3.0 - doAssert round(2.5'f32) == 3.0'f32 - doAssert round(2.5'f64) == 3.0'f64 - - block: # func round*[T: float32|float64](x: T, places: int): T - doAssert round(54.345, 0) == 54.0 - template fn(x) = - doAssert round(x, 2).almostEqual 54.35 - doAssert round(x, 2).almostEqual 54.35 - doAssert round(x, -1).almostEqual 50.0 - doAssert round(x, -2).almostEqual 100.0 - doAssert round(x, -3).almostEqual 0.0 - fn(54.346) - fn(54.346'f32) - - block: # abs - doAssert 1.0 / abs(-0.0) == Inf - doAssert 1.0 / abs(0.0) == Inf - doAssert -1.0 / abs(-0.0) == -Inf - doAssert -1.0 / abs(0.0) == -Inf - doAssert abs(0.0) == 0.0 - doAssert abs(0.0'f32) == 0.0'f32 - - doAssert abs(Inf) == Inf - doAssert abs(-Inf) == Inf - doAssert abs(NaN).isNaN - doAssert abs(-NaN).isNaN - - block: # classify - doAssert classify(0.3) == fcNormal - doAssert classify(-0.3) == fcNormal - doAssert classify(5.0e-324) == fcSubnormal - doAssert classify(-5.0e-324) == fcSubnormal - doAssert classify(0.0) == fcZero - doAssert classify(-0.0) == fcNegZero - doAssert classify(NaN) == fcNan - doAssert classify(0.3 / 0.0) == fcInf - doAssert classify(Inf) == fcInf - doAssert classify(-0.3 / 0.0) == fcNegInf - doAssert classify(-Inf) == fcNegInf - - block: # sum - let empty: seq[int] = @[] - doAssert sum(empty) == 0 - doAssert sum([1, 2, 3, 4]) == 10 - doAssert sum([-4, 3, 5]) == 4 - - block: # prod - let empty: seq[int] = @[] - doAssert prod(empty) == 1 - doAssert prod([1, 2, 3, 4]) == 24 - doAssert prod([-4, 3, 5]) == -60 - doAssert almostEqual(prod([1.5, 3.4]), 5.1) - let x: seq[float] = @[] - doAssert prod(x) == 1.0 - - block: # clamp range - doAssert clamp(10, 1..5) == 5 - doAssert clamp(3, 1..5) == 3 - doAssert clamp(5, 1..5) == 5 - doAssert clamp(42.0, 1.0 .. 3.1415926535) == 3.1415926535 - doAssert clamp(NaN, 1.0 .. 2.0).isNaN - doAssert clamp(-Inf, -Inf .. -1.0) == -Inf - type A = enum a0, a1, a2, a3, a4, a5 - doAssert a1.clamp(a2..a4) == a2 - doAssert clamp((3, 0), (1, 0) .. (2, 9)) == (2, 9) - - block: # edge cases - doAssert sqrt(-4.0).isNaN - - doAssert ln(0.0) == -Inf - doAssert ln(-0.0) == -Inf - doAssert ln(-12.0).isNaN - - doAssert log10(0.0) == -Inf - doAssert log10(-0.0) == -Inf - doAssert log10(-12.0).isNaN - - doAssert log2(0.0) == -Inf - doAssert log2(-0.0) == -Inf - doAssert log2(-12.0).isNaN - - when nimvm: discard - else: - doAssert frexp(0.0) == (0.0, 0) - doAssert frexp(-0.0) == (-0.0, 0) - doAssert classify(frexp(-0.0)[0]) == fcNegZero - - when not defined(js): - doAssert gamma(0.0) == Inf - doAssert gamma(-0.0) == -Inf - doAssert gamma(-1.0).isNaN - - doAssert lgamma(0.0) == Inf - doAssert lgamma(-0.0) == Inf - doAssert lgamma(-1.0) == Inf - - -static: main() -main() +import math, random, os +import unittest +import sets, tables + +suite "random int": + test "there might be some randomness": + var set = initHashSet[int](128) + + for i in 1..1000: + incl(set, random(high(int))) + check len(set) == 1000 + test "single number bounds work": + + var rand: int + for i in 1..1000: + rand = random(1000) + check rand < 1000 + check rand > -1 + test "slice bounds work": + + var rand: int + for i in 1..1000: + rand = random(100..1000) + check rand < 1000 + check rand >= 100 + test " again gives new numbers": + + var rand1 = random(1000000) + os.sleep(200) + + var rand2 = random(1000000) + check rand1 != rand2 + + +suite "random float": + test "there might be some randomness": + var set = initSet[float](128) + + for i in 1..100: + incl(set, random(1.0)) + check len(set) == 100 + test "single number bounds work": + + var rand: float + for i in 1..1000: + rand = random(1000.0) + check rand < 1000.0 + check rand > -1.0 + test "slice bounds work": + + var rand: float + for i in 1..1000: + rand = random(100.0..1000.0) + check rand < 1000.0 + check rand >= 100.0 + test " again gives new numbers": + + var rand1:float = random(1000000.0) + os.sleep(200) + + var rand2:float = random(1000000.0) + check rand1 != rand2 + +suite "cumsum": + test "cumsum int seq return": + let counts = [ 1, 2, 3, 4 ] + check counts.cumsummed == [ 1, 3, 6, 10 ] + + test "cumsum float seq return": + let counts = [ 1.0, 2.0, 3.0, 4.0 ] + check counts.cumsummed == [ 1.0, 3.0, 6.0, 10.0 ] + + test "cumsum int in-place": + var counts = [ 1, 2, 3, 4 ] + counts.cumsum + check counts == [ 1, 3, 6, 10 ] + + test "cumsum float in-place": + var counts = [ 1.0, 2.0, 3.0, 4.0 ] + counts.cumsum + check counts == [ 1.0, 3.0, 6.0, 10.0 ] + +suite "random sample": + test "non-uniform array sample unnormalized int CDF": + let values = [ 10, 20, 30, 40, 50 ] # values + let counts = [ 4, 3, 2, 1, 0 ] # weights aka unnormalized probabilities + var histo = initCountTable[int]() + let cdf = counts.cumsummed # unnormalized CDF + for i in 0 ..< 5000: + histo.inc(sample(values, cdf)) + check histo.len == 4 # number of non-zero in `counts` + # Any one bin is a binomial random var for n samples, each with prob p of + # adding a count to k; E[k]=p*n, Var k=p*(1-p)*n, approximately Normal for + # big n. So, P(abs(k - p*n)/sqrt(p*(1-p)*n))>3.0) =~ 0.0027, while + # P(wholeTestFails) =~ 1 - P(binPasses)^4 =~ 1 - (1-0.0027)^4 =~ 0.01. + for i, c in counts: + if c == 0: + check values[i] notin histo + continue + let p = float(c) / float(cdf[^1]) + let n = 5000.0 + let expected = p * n + let stdDev = sqrt(n * p * (1.0 - p)) + check abs(float(histo[values[i]]) - expected) <= 3.0 * stdDev + + test "non-uniform array sample normalized float CDF": + let values = [ 10, 20, 30, 40, 50 ] # values + let counts = [ 0.4, 0.3, 0.2, 0.1, 0 ] # probabilities + var histo = initCountTable[int]() + let cdf = counts.cumsummed # normalized CDF + for i in 0 ..< 5000: + histo.inc(sample(values, cdf)) + check histo.len == 4 # number of non-zero in ``counts`` + for i, c in counts: + if c == 0: + check values[i] notin histo + continue + let p = float(c) / float(cdf[^1]) + let n = 5000.0 + let expected = p * n + let stdDev = sqrt(n * p * (1.0 - p)) + # NOTE: like unnormalized int CDF test, P(wholeTestFails) =~ 0.01. + check abs(float(histo[values[i]]) - expected) <= 3.0 * stdDev + +suite "^": + test "compiles for valid types": + check: compiles(5 ^ 2) + check: compiles(5.5 ^ 2) + check: compiles(5.5 ^ 2.int8) + check: compiles(5.5 ^ 2.uint) + check: compiles(5.5 ^ 2.uint8) + check: not compiles(5.5 ^ 2.2) \ No newline at end of file diff --git a/tests/stdlib/tmd5.nim b/tests/stdlib/tmd5.nim deleted file mode 100644 index 254eefea9..000000000 --- a/tests/stdlib/tmd5.nim +++ /dev/null @@ -1,17 +0,0 @@ -discard """ - targets: "c cpp js" -""" - -import md5 -import std/assertions - -proc main() {.raises: [].} = - doAssert(getMD5("Franz jagt im komplett verwahrlosten Taxi quer durch Bayern") == - "a3cca2b2aa1e3b5b3b5aad99a8529074") - doAssert(getMD5("Frank jagt im komplett verwahrlosten Taxi quer durch Bayern") == - "7e716d0e702df0505fc72e2b89467910") - doAssert($toMD5("") == "d41d8cd98f00b204e9800998ecf8427e") - -main() - -static: main() diff --git a/tests/stdlib/tmemfiles1.nim b/tests/stdlib/tmemfiles1.nim index 33657256c..21a65369f 100644 --- a/tests/stdlib/tmemfiles1.nim +++ b/tests/stdlib/tmemfiles1.nim @@ -1,6 +1,4 @@ import memfiles, os -import std/syncio - var mm: MemFile fn = "test.mmap" diff --git a/tests/stdlib/tmemfiles2.nim b/tests/stdlib/tmemfiles2.nim index c79f85ebf..1b249898e 100644 --- a/tests/stdlib/tmemfiles2.nim +++ b/tests/stdlib/tmemfiles2.nim @@ -4,9 +4,6 @@ discard """ Half read size: 10 Data: Hello''' """ import memfiles, os -import std/syncio - - const fn = "test.mmap" var @@ -15,9 +12,8 @@ var if fileExists(fn): removeFile(fn) -# Create a new file, data all zeros, starting at size 10 -mm = memfiles.open(fn, mode = fmReadWrite, newFileSize = 10, allowRemap=true) -mm.resize 20 # resize up to 20 +# Create a new file, data all zeros +mm = memfiles.open(fn, mode = fmReadWrite, newFileSize = 20) mm.close() # read, change diff --git a/tests/stdlib/tmemlinesBuf.nim b/tests/stdlib/tmemlinesBuf.nim index 7bd89d4f2..97ad751ee 100644 --- a/tests/stdlib/tmemlinesBuf.nim +++ b/tests/stdlib/tmemlinesBuf.nim @@ -1,9 +1,15 @@ -import std/[memfiles, assertions] +discard """ +output: "15" +disabled: "appveyor" +""" + +import memfiles var inp = memfiles.open("tests/stdlib/tmemlinesBuf.nim") -var buffer: string = "" +var buffer: TaintedString = "" var lineCount = 0 for line in lines(inp, buffer): lineCount += 1 close(inp) -doAssert lineCount == 9, $lineCount # this file's number of lines + +echo lineCount diff --git a/tests/stdlib/tmemmapstreams.nim b/tests/stdlib/tmemmapstreams.nim index 9cfae62c7..dd011d777 100644 --- a/tests/stdlib/tmemmapstreams.nim +++ b/tests/stdlib/tmemmapstreams.nim @@ -12,8 +12,6 @@ Readed line: Hello! Position after reading line: 7''' """ import os, streams, memfiles -import std/syncio - const fn = "test.mmapstream" var diff --git a/tests/stdlib/tmemory.nim b/tests/stdlib/tmemory.nim deleted file mode 100644 index 553037011..000000000 --- a/tests/stdlib/tmemory.nim +++ /dev/null @@ -1,16 +0,0 @@ -import std/assertions - -block: # cmpMem - type - SomeHash = array[15, byte] - - var - a: SomeHash - b: SomeHash - - a[^1] = byte(1) - let c = a - - doAssert cmpMem(a.addr, b.addr, sizeof(SomeHash)) > 0 - doAssert cmpMem(b.addr, a.addr, sizeof(SomeHash)) < 0 - doAssert cmpMem(a.addr, c.addr, sizeof(SomeHash)) == 0 diff --git a/tests/stdlib/tmersenne.nim b/tests/stdlib/tmersenne.nim deleted file mode 100644 index 64450a045..000000000 --- a/tests/stdlib/tmersenne.nim +++ /dev/null @@ -1,13 +0,0 @@ -import std/mersenne -import std/assertions - -template main() = - var mt = newMersenneTwister(2525) - - doAssert mt.getNum == 407788156'u32 - doAssert mt.getNum == 1071751096'u32 - doAssert mt.getNum == 3805347140'u32 - - -static: main() -main() diff --git a/tests/stdlib/tmget.nim b/tests/stdlib/tmget.nim index 52e61fd24..5e2e327f4 100644 --- a/tests/stdlib/tmget.nim +++ b/tests/stdlib/tmget.nim @@ -104,7 +104,7 @@ block: import sets block: - var x = initHashSet[int]() + var x = initSet[int]() x.incl 5 try: echo x[6] diff --git a/tests/stdlib/tmimetypes.nim b/tests/stdlib/tmimetypes.nim deleted file mode 100644 index 8263e37fd..000000000 --- a/tests/stdlib/tmimetypes.nim +++ /dev/null @@ -1,19 +0,0 @@ -discard """ - targets: "c js" -""" - -import std/mimetypes -import std/assertions - - -template main() = - var m = newMimetypes() - doAssert m.getMimetype("mp4") == "video/mp4" - doAssert m.getExt("application/json") == "json" - m.register("foo", "baa") - doAssert m.getMimetype("foo") == "baa" - # see also `runnableExamples`. - # xxx we should have a way to avoid duplicating code between runnableExamples and tests - -static: main() -main() diff --git a/tests/stdlib/tmisc_issues.nim b/tests/stdlib/tmisc_issues.nim deleted file mode 100644 index b5a02e614..000000000 --- a/tests/stdlib/tmisc_issues.nim +++ /dev/null @@ -1,19 +0,0 @@ -discard """ - targets: "c cpp js" -""" - -import std/assertions - -# bug #20227 -type - Data = object - id: int - - Test = distinct Data - - Object = object - data: Test - - -var x: Object = Object(data: Test(Data(id: 12))) -doAssert Data(x.data).id == 12 diff --git a/tests/stdlib/tmitems.nim b/tests/stdlib/tmitems.nim index 171604e33..17265e1f7 100644 --- a/tests/stdlib/tmitems.nim +++ b/tests/stdlib/tmitems.nim @@ -16,18 +16,7 @@ fpqeew - - - This is a Docbook title - - This is a Docbook paragraph containing emphasized, - literal and replaceable - text. Sometimes scrunched together like this: - literalreplaceable - and sometimes not: - literal replaceable - -''' +''' """ block: @@ -62,7 +51,6 @@ block: block: var x = "foobar" - prepareMutation(x) var y = cast[cstring](addr x[0]) for c in y.mitems: inc c @@ -76,7 +64,6 @@ block: block: var x = "foobar" - prepareMutation(x) var y = cast[cstring](addr x[0]) for i, c in y.mpairs: inc c, i @@ -136,7 +123,7 @@ block: x.num += 10 echo j -import xmltree, xmlparser, parsexml, streams, strtabs +import xmltree, xmlparser, streams, strtabs block: var d = parseXml(newStringStream """ @@ -147,17 +134,3 @@ block: x = <>Student(Name=x.attrs["Name"] & "foo") d[1].attrs["Name"] = "bar" echo d - -block: - var d = parseXml(newStringStream """ - This is a Docbook title - - This is a Docbook paragraph containing emphasized, - literal and replaceable - text. Sometimes scrunched together like this: - literalreplaceable - and sometimes not: - literal replaceable - -""",{reportComments, reportWhitespace}) - echo d diff --git a/tests/stdlib/tmonotimes.nim b/tests/stdlib/tmonotimes.nim deleted file mode 100644 index f10fef591..000000000 --- a/tests/stdlib/tmonotimes.nim +++ /dev/null @@ -1,21 +0,0 @@ -discard """ - targets: "c js" -""" - -import std/[monotimes, times] -import std/assertions - -let d = initDuration(nanoseconds = 10) -let t1 = getMonoTime() -let t2 = t1 + d - -doAssert t2 - t1 == d -doAssert t1 == t1 -doAssert t1 != t2 -doAssert t2 - d == t1 -doAssert t1 < t2 -doAssert t1 <= t2 -doAssert t1 <= t1 -doAssert not(t2 < t1) -doAssert t1 < high(MonoTime) -doAssert low(MonoTime) < t1 diff --git a/tests/stdlib/tnativesockets.nim b/tests/stdlib/tnativesockets.nim deleted file mode 100644 index b1bbf32c2..000000000 --- a/tests/stdlib/tnativesockets.nim +++ /dev/null @@ -1,26 +0,0 @@ -import std/nativesockets -import stdtest/testutils -import std/assertions - -block: - let hostname = getHostname() - doAssert hostname.len > 0 - -when defined(windows): - assertAll: - toInt(IPPROTO_IP) == 0 - toInt(IPPROTO_ICMP) == 1 - toInt(IPPROTO_TCP) == 6 - toInt(IPPROTO_UDP) == 17 - toInt(IPPROTO_IPV6) == 41 - toInt(IPPROTO_ICMPV6) == 58 - toInt(IPPROTO_RAW) == 20 - - # no changes to enum value - ord(IPPROTO_TCP) == 6 - ord(IPPROTO_UDP) == 17 - ord(IPPROTO_IP) == 18 - ord(IPPROTO_IPV6) == 19 - ord(IPPROTO_RAW) == 20 - ord(IPPROTO_ICMP) == 21 - ord(IPPROTO_ICMPV6) == 22 diff --git a/tests/stdlib/tnet.nim b/tests/stdlib/tnet.nim index 06ff44c3d..2dd22796c 100644 --- a/tests/stdlib/tnet.nim +++ b/tests/stdlib/tnet.nim @@ -4,88 +4,52 @@ outputsub: "" import net, nativesockets import unittest -import std/assertions -block: # isIpAddress tests - block: # 127.0.0.1 is valid +suite "isIpAddress tests": + test "127.0.0.1 is valid": check isIpAddress("127.0.0.1") == true - block: # ipv6 localhost is valid + test "ipv6 localhost is valid": check isIpAddress("::1") == true - block: # fqdn is not an ip address + test "fqdn is not an ip address": check isIpAddress("example.com") == false - block: # random string is not an ipaddress + test "random string is not an ipaddress": check isIpAddress("foo bar") == false - block: # 5127.0.0.1 is invalid + test "5127.0.0.1 is invalid": check isIpAddress("5127.0.0.1") == false - block: # ipv6 is valid + test "ipv6 is valid": check isIpAddress("2001:cdba:0000:0000:0000:0000:3257:9652") == true - block: # invalid ipv6 + test "invalid ipv6": check isIpAddress("gggg:cdba:0000:0000:0000:0000:3257:9652") == false -block: # parseIpAddress tests - block: # 127.0.0.1 is valid +suite "parseIpAddress tests": + test "127.0.0.1 is valid": discard parseIpAddress("127.0.0.1") - block: # ipv6 localhost is valid + test "ipv6 localhost is valid": discard parseIpAddress("::1") - block: # fqdn is not an ip address + test "fqdn is not an ip address": expect(ValueError): discard parseIpAddress("example.com") - block: # random string is not an ipaddress + test "random string is not an ipaddress": expect(ValueError): discard parseIpAddress("foo bar") - block: # ipv6 is valid + test "ipv6 is valid": discard parseIpAddress("2001:cdba:0000:0000:0000:0000:3257:9652") - block: # invalid ipv6 + test "invalid ipv6": expect(ValueError): discard parseIpAddress("gggg:cdba:0000:0000:0000:0000:3257:9652") - block: # ipv4-compatible ipv6 address (embedded ipv4 address) - check parseIpAddress("::ffff:10.0.0.23") == parseIpAddress("::ffff:0a00:0017") - - block: # octal number in ipv4 address - expect(ValueError): - discard parseIpAddress("010.8.8.8") - expect(ValueError): - discard parseIpAddress("8.010.8.8") - - block: # hexadecimal number in ipv4 address - expect(ValueError): - discard parseIpAddress("0xc0.168.0.1") - expect(ValueError): - discard parseIpAddress("192.0xa8.0.1") - - block: # less than 4 numbers in ipv4 address - expect(ValueError): - discard parseIpAddress("127.0.1") - - block: # octal number in embedded ipv4 address - expect(ValueError): - discard parseIpAddress("::ffff:010.8.8.8") - expect(ValueError): - discard parseIpAddress("::ffff:8.010.8.8") - - block: # hexadecimal number in embedded ipv4 address - expect(ValueError): - discard parseIpAddress("::ffff:0xc0.168.0.1") - expect(ValueError): - discard parseIpAddress("::ffff:192.0xa8.0.1") - - block: # less than 4 numbers in embedded ipv4 address - expect(ValueError): - discard parseIpAddress("::ffff:127.0.1") - block: # "IpAddress/Sockaddr conversion" proc test(ipaddrstr: string) = var ipaddr_1 = parseIpAddress(ipaddrstr) @@ -94,7 +58,7 @@ block: # "IpAddress/Sockaddr conversion" doAssert($ipaddrstr == $ipaddr_1) var sockaddr: Sockaddr_storage - var socklen: SockLen + var socklen: Socklen var ipaddr_2: IpAddress var port_2: Port diff --git a/tests/stdlib/tnet_ll.nim b/tests/stdlib/tnet_ll.nim index 13b56dbb9..2ac272fd1 100644 --- a/tests/stdlib/tnet_ll.nim +++ b/tests/stdlib/tnet_ll.nim @@ -1,51 +1,42 @@ -discard """ - action: run - output: ''' - -[Suite] inet_ntop tests -''' -""" - -when defined(windows): - import winlean -elif defined(posix): - import posix -else: - {.error: "Unsupported OS".} - -import unittest, strutils - -suite "inet_ntop tests": - - setup: - when defined(windows): - var wsa: WSAData - discard wsaStartup(0x101'i16, wsa.addr) - - test "IP V4": - # regular - var ip4 = InAddr() - ip4.s_addr = 0x10111213'u32 - check: ip4.s_addr == 0x10111213'u32 - - var buff: array[0..255, char] - let r = inet_ntop(AF_INET, cast[pointer](ip4.s_addr.addr), cast[cstring](buff[0].addr), buff.len.int32) - let res = if r == nil: "" else: $r - check: res == "19.18.17.16" - - test "IP V6": - when defined(windows): - let ipv6Support = (getVersion() and 0xff) > 0x5 - else: - let ipv6Support = true - - var ip6 = [0x1000'u16, 0x1001, 0x2000, 0x2001, 0x3000, 0x3001, 0x4000, 0x4001] - var buff: array[0..255, char] - let r = inet_ntop(AF_INET6, cast[pointer](ip6[0].addr), cast[cstring](buff[0].addr), buff.len.int32) - let res = if r == nil: "" else: $r - check: not ipv6Support or res == "10:110:20:120:30:130:40:140" - - test "InAddr": - # issue 19244 - var ip4 = InAddr(s_addr: 0x10111213'u32) - check: ip4.s_addr == 0x10111213'u32 +discard """ + action: run + output: ''' +[Suite] inet_ntop tests +''' +""" + +when defined(windows): + import winlean +elif defined(posix): + import posix +else: + {.error: "Unsupported OS".} + +import unittest, strutils + +suite "inet_ntop tests": + + setup: + when defined(windows): + var wsa: WSAData + discard wsaStartup(0x101'i16, wsa.addr) + + test "IP V4": + var ip4 = 0x10111213 + var buff: array[0..255, char] + let r = inet_ntop(AF_INET, ip4.addr, buff[0].addr, buff.sizeof.int32) + let res = if r == nil: "" else: $r + check: res == "19.18.17.16" + + + test "IP V6": + when defined(windows): + let ipv6Support = (getVersion() and 0xff) > 0x5 + else: + let ipv6Support = true + + var ip6 = [0x1000'u16, 0x1001, 0x2000, 0x2001, 0x3000, 0x3001, 0x4000, 0x4001] + var buff: array[0..255, char] + let r = inet_ntop(AF_INET6, ip6[0].addr, buff[0].addr, buff.sizeof.int32) + let res = if r == nil: "" else: $r + check: not ipv6Support or res == "10:110:20:120:30:130:40:140" diff --git a/tests/stdlib/tnetbind.nim b/tests/stdlib/tnetbind.nim index 734b6c5e7..b2bcf4b05 100644 --- a/tests/stdlib/tnetbind.nim +++ b/tests/stdlib/tnetbind.nim @@ -1,13 +1,3 @@ -discard """ -joinable: false -""" - -#[ -joinable: false -otherwise: -Error: unhandled exception: Address already in use [OSError] -]# - import net ## Test for net.bindAddr diff --git a/tests/stdlib/tnetconnect.nim b/tests/stdlib/tnetconnect.nim deleted file mode 100644 index ae654aed9..000000000 --- a/tests/stdlib/tnetconnect.nim +++ /dev/null @@ -1,30 +0,0 @@ -discard """ - disabled: "i386" - matrix: "-d:ssl" -""" - -import std/net -from std/strutils import `%` -from stdtest/testutils import enableRemoteNetworking - -# bug #15215 -proc test() = - let ctx = newContext() - - proc fn(url: string) = - let socket = newSocket() - defer: close(socket) - connect(socket, url, Port(443), 5000) # typically 20 could be enough - send(socket, "GET / HTTP/1.0\nHost: $#\nConnection: close\n\n" % [url]) - wrapSocket(ctx, socket) - - # trying 2 sites makes it more resilent: refs #17458 this could give: - # * Call to 'connect' timed out. [TimeoutError] - # * No route to host [OSError] - try: - fn("www.nim-lang.org") - except TimeoutError, OSError: - fn("www.google.com") - -when enableRemoteNetworking: - test() diff --git a/tests/stdlib/tnetdial.nim b/tests/stdlib/tnetdial.nim index a1e147ad5..3847a239c 100644 --- a/tests/stdlib/tnetdial.nim +++ b/tests/stdlib/tnetdial.nim @@ -5,17 +5,16 @@ discard """ """ import os, net, nativesockets, asyncdispatch -import std/[assertions, typedthreads] ## Test for net.dial const port = Port(28431) proc initIPv6Server(hostname: string, port: Port): AsyncFD = - let fd = createNativeSocket(AF_INET6) + let fd = newNativeSocket(AF_INET6) setSockOptInt(fd, SOL_SOCKET, SO_REUSEADDR, 1) var aiList = getAddrInfo(hostname, port, AF_INET6) - if bindAddr(fd, aiList.ai_addr, aiList.ai_addrlen.SockLen) < 0'i32: + if bindAddr(fd, aiList.ai_addr, aiList.ai_addrlen.Socklen) < 0'i32: freeAddrInfo(aiList) raiseOSError(osLastError()) freeAddrInfo(aiList) diff --git a/tests/stdlib/tnre.nim b/tests/stdlib/tnre.nim index f13c16052..0929956cb 100644 --- a/tests/stdlib/tnre.nim +++ b/tests/stdlib/tnre.nim @@ -2,6 +2,23 @@ discard """ # Since the tests for nre are all bundled together we treat failure in one test as an nre failure # When running 'testament/tester' a failed check() in the test suite will cause the exit # codes to differ and be reported as a failure + + output: + '''[Suite] Test NRE initialization + +[Suite] captures + +[Suite] find + +[Suite] string splitting + +[Suite] match + +[Suite] replace + +[Suite] escape strings + +[Suite] Misc tests''' """ import nre diff --git a/tests/stdlib/tntpath.nim b/tests/stdlib/tntpath.nim deleted file mode 100644 index dce0cf6f8..000000000 --- a/tests/stdlib/tntpath.nim +++ /dev/null @@ -1,46 +0,0 @@ -import std/private/ntpath -import std/assertions - -block: # From Python's `Lib/test/test_ntpath.py` - doAssert splitDrive(r"c:\foo\bar") == (r"c:", r"\foo\bar") - doAssert splitDrive(r"c:/foo/bar") == (r"c:", r"/foo/bar") - doAssert splitDrive(r"\\conky\mountpoint\foo\bar") == (r"\\conky\mountpoint", r"\foo\bar") - doAssert splitDrive(r"//conky/mountpoint/foo/bar") == (r"//conky/mountpoint", r"/foo/bar") - doAssert splitDrive(r"\\\conky\mountpoint\foo\bar") == (r"", r"\\\conky\mountpoint\foo\bar") - doAssert splitDrive(r"///conky/mountpoint/foo/bar") == (r"", r"///conky/mountpoint/foo/bar") - doAssert splitDrive(r"\\conky\\mountpoint\foo\bar") == (r"", r"\\conky\\mountpoint\foo\bar") - doAssert splitDrive(r"//conky//mountpoint/foo/bar") == (r"", r"//conky//mountpoint/foo/bar") - # Issue #19911: UNC part containing U+0130 - doAssert splitDrive(r"//conky/MOUNTPOİNT/foo/bar") == (r"//conky/MOUNTPOİNT", r"/foo/bar") - # gh-81790: support device namespace, including UNC drives. - doAssert splitDrive(r"//?/c:") == (r"//?/c:", r"") - doAssert splitDrive(r"//?/c:/") == (r"//?/c:", r"/") - doAssert splitDrive(r"//?/c:/dir") == (r"//?/c:", r"/dir") - doAssert splitDrive(r"//?/UNC") == (r"", r"//?/UNC") - doAssert splitDrive(r"//?/UNC/") == (r"", r"//?/UNC/") - doAssert splitDrive(r"//?/UNC/server/") == (r"//?/UNC/server/", r"") - doAssert splitDrive(r"//?/UNC/server/share") == (r"//?/UNC/server/share", r"") - doAssert splitDrive(r"//?/UNC/server/share/dir") == (r"//?/UNC/server/share", r"/dir") - doAssert splitDrive(r"//?/VOLUME{00000000-0000-0000-0000-000000000000}/spam") == (r"//?/VOLUME{00000000-0000-0000-0000-000000000000}", r"/spam") - doAssert splitDrive(r"//?/BootPartition/") == (r"//?/BootPartition", r"/") - - doAssert splitDrive(r"\\?\c:") == (r"\\?\c:", r"") - doAssert splitDrive(r"\\?\c:\") == (r"\\?\c:", r"\") - doAssert splitDrive(r"\\?\c:\dir") == (r"\\?\c:", r"\dir") - doAssert splitDrive(r"\\?\UNC") == (r"", r"\\?\UNC") - doAssert splitDrive(r"\\?\UNC\") == (r"", r"\\?\UNC\") - doAssert splitDrive(r"\\?\UNC\server\") == (r"\\?\UNC\server\", r"") - doAssert splitDrive(r"\\?\UNC\server\share") == (r"\\?\UNC\server\share", r"") - doAssert splitDrive(r"\\?\UNC\server\share\dir") == (r"\\?\UNC\server\share", r"\dir") - doAssert splitDrive(r"\\?\VOLUME{00000000-0000-0000-0000-000000000000}\spam") == (r"\\?\VOLUME{00000000-0000-0000-0000-000000000000}", r"\spam") - doAssert splitDrive(r"\\?\BootPartition\") == (r"\\?\BootPartition", r"\") - -block: - doAssert splitDrive(r"C:") == (r"C:", r"") - doAssert splitDrive(r"C:\") == (r"C:", r"\") - doAssert splitDrive(r"non/absolute/path") == (r"", r"non/absolute/path") - - # Special for `\`-rooted paths on Windows. I don't know if this is correct, - # rbut `\` is not recognized as a drive, in contrast to `C:` or `\?\c:`. - # This behavior is the same for Python's `splitdrive` function. - doAssert splitDrive(r"\\") == (r"", r"\\") diff --git a/tests/stdlib/tobjectdollar.nim b/tests/stdlib/tobjectdollar.nim deleted file mode 100644 index cf78fa255..000000000 --- a/tests/stdlib/tobjectdollar.nim +++ /dev/null @@ -1,14 +0,0 @@ -discard """ - matrix: "-d:nimPreviewSlimSystem" -""" - -import std/assertions - -type Foo = object - a, b: int - -let x = Foo(a: 23, b: 45) -doAssert not compiles($x) -import std/objectdollar -doAssert compiles($x) -doAssert $x == "(a: 23, b: 45)" diff --git a/tests/stdlib/toids.nim b/tests/stdlib/toids.nim deleted file mode 100644 index dd5b84c51..000000000 --- a/tests/stdlib/toids.nim +++ /dev/null @@ -1,15 +0,0 @@ -discard """ - matrix: "--mm:refc; --mm:orc" -""" - -import std/oids -import std/assertions - -block: # genOid - let x = genOid() - doAssert ($x).len == 24 - -block: - let x = genOid() - let y = parseOid(cstring($x)) - doAssert x == y diff --git a/tests/stdlib/topenssl.nim b/tests/stdlib/topenssl.nim deleted file mode 100644 index 3209437de..000000000 --- a/tests/stdlib/topenssl.nim +++ /dev/null @@ -1,42 +0,0 @@ -import std/wordwrap -import openssl -import std/assertions - -const PubKey = r"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAknKWvrdnncCIzBnIGrZ5qtZrPH+Yo3t7ag9WZIu6Gmc/JgIDDaZhJeyGW0YSnifeAEhooWvM4jDWhTEARzktalSHqYtmwI/1Oxwp6NTYH8akMe2LCpZ5pX9FVA6m9o2tkbdXatbDKRqeD4UA8Ow7Iyrdo6eb1SU8vk+26i+uXHTtsb25p8uf2ppOJrJCy+1vr8Gsnuwny1UdoYZTxMsxRFPf+UX/LrSXMHVq/oPVa3SJ4VHMpYrG/httAugVP6K58xiZ93jst63/dd0JL85mWJu1uS3uz92aL5O97xzth3wR4BbdmDUlN4LuTIwi6DtEcC7gUOTnOzH4zgp2b5RyHwIDAQAB" -const PrivateKey = r"MIIEpAIBAAKCAQEAknKWvrdnncCIzBnIGrZ5qtZrPH+Yo3t7ag9WZIu6Gmc/JgIDDaZhJeyGW0YSnifeAEhooWvM4jDWhTEARzktalSHqYtmwI/1Oxwp6NTYH8akMe2LCpZ5pX9FVA6m9o2tkbdXatbDKRqeD4UA8Ow7Iyrdo6eb1SU8vk+26i+uXHTtsb25p8uf2ppOJrJCy+1vr8Gsnuwny1UdoYZTxMsxRFPf+UX/LrSXMHVq/oPVa3SJ4VHMpYrG/httAugVP6K58xiZ93jst63/dd0JL85mWJu1uS3uz92aL5O97xzth3wR4BbdmDUlN4LuTIwi6DtEcC7gUOTnOzH4zgp2b5RyHwIDAQABAoIBACSOxmLFlfAjaALLTNCeTLEA5bQshgYJhT1sprxixQpiS7lJN0npBsdYzBFs5KjmetzHNpdVOcgdOO/204L0Gwo4H8WLLxNS3HztAulEeM813zc3fUYfWi6eHshk//j8VR/TDNd21TElm99z7FA4KGsXAE0iQhxrN0aqz5aWYIhjprtHA5KxXIiESnTkof5Cud8oXEnPiwPGNhq93QeQzh7xQIKSaDKBcdAa6edTFhzc4RLUQRfrik/GqJzouEDQ9v6H/uiOLTB3FxxwErQIf6dvSVhD9gs1nSLQfyj3S2Hxe9S2zglTl07EsawTQUxtVQkdZUOok67c7CPBxecZ2wECgYEA2c31gr/UJwczT+P/AE52GkHHETXMxqE3Hnh9n4CitfAFSD5X0VwZvGjZIlln2WjisTd92Ymf65eDylX2kCm93nzZ2GfXgS4zl4oY1N87+VeNQlx9f2+6GU7Hs0HFdfu8bGd+0sOuWA1PFqQCobxCACMPTkuzsG9M7knUTN59HS8CgYEArCEoP4ReYoOFveXUE0AteTPb4hryvR9VDEolP+LMoiPe8AzBMeB5fP493TPdjtnWmrPCXNLc7UAFSj2CZsRhau4PuiqnNrsb5iz/7iXVl3E8wZvS4w7WYpO4m33L0cijA6MdcdqilQu4Z5tw4nG45lAW9UYyOc9D4hJTzgtGHhECgYA6QyDoj931brSoK0ocT+DB11Sj4utbOuberMaV8zgTSRhwodSl+WgdAUMMMDRacPcrBrgQiAMSZ15msqYZHEFhEa7Id8arFKvSXquTzf9iDKyJ0unzO/ThLjS3W+GxVNyrdufzA0tQ3IaKfOcDUrOpC7fdbtyrVqqSl4dF5MI9GwKBgQCl3OF6qyOEDDZgsUk1L59h7k3QR6VmBf4e9IeGUxZamvQlHjU/yY1nm1mjgGnbUB/SPKtqZKoMV6eBTVoNiuhQcItpGda9D3mnx+7p3T0/TBd+fJeuwcplfPDjrEktogcq5w/leQc3Ve7gr1EMcwb3r28f8/9L42QHQR/OKODs8QKBgQCFAvxDRPyYg7V/AgD9rt1KzXi4+b3Pls5NXZa2g/w+hmdhHUNxV5IGmHlqFnptGyshgYgQGxMMkW0iJ1j8nLamFnkbFQOp5/UKbdPLRKiB86oPpxsqYtPXucDUqEfcMsp57mD1CpGVODbspogFpSUvQpMECkhvI0XLMbolMdo53g==" - -proc rsaPublicEncrypt(fr: string): string = - let mKey = "-----BEGIN PUBLIC KEY-----\n" & PubKey.wrapWords(64) & "\n-----END PUBLIC KEY-----" - let bio = bioNew(bioSMem()) - doAssert BIO_write(bio, mKey.cstring, mKey.len.cint) >= 0 - let rsa = PEM_read_bio_RSA_PUBKEY(bio, nil, nil, nil) - doAssert rsa != nil - doAssert BIO_free(bio) >= 0 - result = newString(RSA_size(rsa)) - let frdata = cast[ptr uint8](fr.cstring) - var todata = cast[ptr uint8](result.cstring) - doAssert RSA_public_encrypt(fr.len.cint, frdata, todata, rsa, RSA_PKCS1_PADDING) != -1 - RSA_free(rsa) - -proc rasPrivateDecrypt(fr: string): string = - let mKey = "-----BEGIN RSA PRIVATE KEY-----\n" & PrivateKey.wrapWords(64) & "\n-----END RSA PRIVATE KEY-----" - let bio = bioNew(bioSMem()) - doAssert BIO_write(bio, mKey.cstring, mKey.len.cint) >= 0 - let rsa = PEM_read_bio_RSAPrivateKey(bio, nil, nil, nil) - doAssert rsa != nil - doAssert BIO_free(bio) >= 0 - let rsaLen = RSA_size(rsa) - result = newString(rsaLen) - let frdata = cast[ptr uint8](fr.cstring) - var todata = cast[ptr uint8](result.cstring) - let lenOrig = RSA_private_decrypt(rsaLen, frdata, todata, rsa, RSA_PKCS1_PADDING) - doAssert lenOrig >= 0 and lenOrig < result.len - doAssert result[lenOrig] == '\0' - result.setLen lenOrig - RSA_free(rsa) - -let res = "TEST" -let miwen = rsaPublicEncrypt(res) -let mingwen = rasPrivateDecrypt(miwen) -doAssert mingwen == res - diff --git a/tests/stdlib/toptions.nim b/tests/stdlib/toptions.nim deleted file mode 100644 index 6065425b9..000000000 --- a/tests/stdlib/toptions.nim +++ /dev/null @@ -1,200 +0,0 @@ -discard """ - targets: "c js" -""" - -import std/[json, options] - -import std/assertions -import std/objectdollar - - -# RefPerson is used to test that overloaded `==` operator is not called by -# options. It is defined here in the global scope, because otherwise the test -# will not even consider the `==` operator. Different bug? -type RefPerson = ref object - name: string - -proc `==`(a, b: RefPerson): bool = - assert(not a.isNil and not b.isNil) - a.name == b.name - - -template disableJsVm(body) = - # something doesn't work in JS VM - when defined(js): - when nimvm: discard - else: body - else: - body - -proc main() = - type - Foo = ref object - test: string - Test = object - foo: Option[Foo] - - let js = """{"foo": {"test": "123"}}""" - let parsed = parseJson(js) - let a = parsed.to(Test) - doAssert $(%*a) == """{"foo":{"test":"123"}}""" - - block options: - # work around a bug in unittest - let intNone = none(int) - let stringNone = none(string) - - block example: - proc find(haystack: string, needle: char): Option[int] = - for i, c in haystack: - if c == needle: - return some i - - doAssert("abc".find('c').get() == 2) - - let result = "team".find('i') - - doAssert result == intNone - doAssert result.isNone - - block some: - doAssert some(6).get() == 6 - doAssert some("a").unsafeGet() == "a" - doAssert some(6).isSome - doAssert some("a").isSome - - block none: - doAssertRaises UnpackDefect: - discard none(int).get() - doAssert(none(int).isNone) - doAssert(not none(string).isSome) - - block equality: - doAssert some("a") == some("a") - doAssert some(7) != some(6) - doAssert some("a") != stringNone - doAssert intNone == intNone - - when compiles(some("a") == some(5)): - doAssert false - when compiles(none(string) == none(int)): - doAssert false - - block get_with_a_default_value: - doAssert(some("Correct").get("Wrong") == "Correct") - doAssert(stringNone.get("Correct") == "Correct") - - block stringify: - doAssert($(some("Correct")) == "some(\"Correct\")") - doAssert($(stringNone) == "none(string)") - - disableJsVm: - block map_with_a_void_result: - var procRan = 0 - # TODO closure anonymous functions doesn't work in VM with JS - # Error: cannot evaluate at compile time: procRan - some(123).map(proc (v: int) = procRan = v) - doAssert procRan == 123 - intNone.map(proc (v: int) = doAssert false) - - block map: - doAssert(some(123).map(proc (v: int): int = v * 2) == some(246)) - doAssert(intNone.map(proc (v: int): int = v * 2).isNone) - - block filter: - doAssert(some(123).filter(proc (v: int): bool = v == 123) == some(123)) - doAssert(some(456).filter(proc (v: int): bool = v == 123).isNone) - doAssert(intNone.filter(proc (v: int): bool = doAssert false).isNone) - - block flatMap: - proc addOneIfNotZero(v: int): Option[int] = - if v != 0: - result = some(v + 1) - else: - result = none(int) - - doAssert(some(1).flatMap(addOneIfNotZero) == some(2)) - doAssert(some(0).flatMap(addOneIfNotZero) == none(int)) - doAssert(some(1).flatMap(addOneIfNotZero).flatMap(addOneIfNotZero) == some(3)) - - proc maybeToString(v: int): Option[string] = - if v != 0: - result = some($v) - else: - result = none(string) - - doAssert(some(1).flatMap(maybeToString) == some("1")) - - proc maybeExclaim(v: string): Option[string] = - if v != "": - result = some v & "!" - else: - result = none(string) - - doAssert(some(1).flatMap(maybeToString).flatMap(maybeExclaim) == some("1!")) - doAssert(some(0).flatMap(maybeToString).flatMap(maybeExclaim) == none(string)) - - block SomePointer: - var intref: ref int - doAssert(option(intref).isNone) - intref.new - doAssert(option(intref).isSome) - - let tmp = option(intref) - doAssert(sizeof(tmp) == sizeof(ptr int)) - - var prc = proc (x: int): int = x + 1 - doAssert(option(prc).isSome) - prc = nil - doAssert(option(prc).isNone) - - block: - doAssert(none[int]().isNone) - doAssert(none(int) == none[int]()) - - # "$ on typed with .name" - block: - type Named = object - name: string - - let nobody = none(Named) - doAssert($nobody == "none(Named)") - - # "$ on type with name()" - block: - type Person = object - myname: string - - let noperson = none(Person) - doAssert($noperson == "none(Person)") - - # "Ref type with overloaded `==`" - block: - let p = some(RefPerson.new()) - doAssert p.isSome - - block: # test cstring - block: - let x = some("".cstring) - doAssert x.isSome - doAssert x.get == "" - - block: - let x = some("12345".cstring) - doAssert x.isSome - doAssert x.get == "12345" - - block: - let x = "12345".cstring - let y = some(x) - doAssert y.isSome - doAssert y.get == "12345" - - block: - let x = none(cstring) - doAssert x.isNone - doAssert $x == "none(cstring)" - - -static: main() -main() diff --git a/tests/stdlib/tos.nim b/tests/stdlib/tos.nim index b2891ef1b..03fc1f1e9 100644 --- a/tests/stdlib/tos.nim +++ b/tests/stdlib/tos.nim @@ -22,13 +22,10 @@ __really_obscure_dir_name/test Raises Raises ''' - joinable: false """ # test os path creation, iteration, and deletion import os, strutils, pathnorm -from stdtest/specialpaths import buildDir -import std/[syncio, assertions] block fileOperations: let files = @["these.txt", "are.x", "testing.r", "files.q"] @@ -39,30 +36,6 @@ block fileOperations: createDir(dname) doAssert dirExists(dname) - block: # copyFile, copyFileToDir - doAssertRaises(OSError): copyFile(dname/"nonexistent.txt", dname/"nonexistent.txt") - let fname = "D20201009T112235" - let fname2 = "D20201009T112235.2" - let str = "foo1\0foo2\nfoo3\0" - let file = dname/fname - let file2 = dname/fname2 - writeFile(file, str) - doAssert readFile(file) == str - let sub = "sub" - doAssertRaises(OSError): copyFile(file, dname/sub/fname2) - doAssertRaises(OSError): copyFileToDir(file, dname/sub) - doAssertRaises(ValueError): copyFileToDir(file, "") - copyFile(file, file2) - doAssert fileExists(file2) - doAssert readFile(file2) == str - createDir(dname/sub) - copyFileToDir(file, dname/sub) - doAssert fileExists(dname/sub/fname) - removeDir(dname/sub) - doAssert not dirExists(dname/sub) - removeFile(file) - removeFile(file2) - # Test creating files and dirs for dir in dirs: createDir(dname/dir) @@ -157,160 +130,6 @@ block fileOperations: doAssert fileExists("../dest/a/file.txt") removeDir("../dest") - # createDir should not fail if `dir` is empty - createDir("") - - # Symlink handling in `copyFile`, `copyFileWithPermissions`, `copyFileToDir`, - # `copyDir`, `copyDirWithPermissions`, `moveFile`, and `moveDir`. - block: - const symlinksAreHandled = not defined(windows) - const dname = buildDir/"D20210116T140629" - const subDir = dname/"sub" - const subDir2 = dname/"sub2" - const brokenSymlinkName = "D20210101T191320_BROKEN_SYMLINK" - const brokenSymlink = dname/brokenSymlinkName - const brokenSymlinkSrc = "D20210101T191320_nonexistent" - const brokenSymlinkCopy = brokenSymlink & "_COPY" - const brokenSymlinkInSubDir = subDir/brokenSymlinkName - const brokenSymlinkInSubDir2 = subDir2/brokenSymlinkName - - createDir(subDir) - createSymlink(brokenSymlinkSrc, brokenSymlink) - - # Test copyFile - when symlinksAreHandled: - doAssertRaises(OSError): - copyFile(brokenSymlink, brokenSymlinkCopy) - doAssertRaises(OSError): - copyFile(brokenSymlink, brokenSymlinkCopy, {cfSymlinkFollow}) - copyFile(brokenSymlink, brokenSymlinkCopy, {cfSymlinkIgnore}) - doAssert not fileExists(brokenSymlinkCopy) - copyFile(brokenSymlink, brokenSymlinkCopy, {cfSymlinkAsIs}) - when symlinksAreHandled: - doAssert expandSymlink(brokenSymlinkCopy) == brokenSymlinkSrc - removeFile(brokenSymlinkCopy) - else: - doAssert not fileExists(brokenSymlinkCopy) - doAssertRaises(AssertionDefect): - copyFile(brokenSymlink, brokenSymlinkCopy, - {cfSymlinkAsIs, cfSymlinkFollow}) - - # Test copyFileWithPermissions - when symlinksAreHandled: - doAssertRaises(OSError): - copyFileWithPermissions(brokenSymlink, brokenSymlinkCopy) - doAssertRaises(OSError): - copyFileWithPermissions(brokenSymlink, brokenSymlinkCopy, - options = {cfSymlinkFollow}) - copyFileWithPermissions(brokenSymlink, brokenSymlinkCopy, - options = {cfSymlinkIgnore}) - doAssert not fileExists(brokenSymlinkCopy) - copyFileWithPermissions(brokenSymlink, brokenSymlinkCopy, - options = {cfSymlinkAsIs}) - when symlinksAreHandled: - doAssert expandSymlink(brokenSymlinkCopy) == brokenSymlinkSrc - removeFile(brokenSymlinkCopy) - else: - doAssert not fileExists(brokenSymlinkCopy) - doAssertRaises(AssertionDefect): - copyFileWithPermissions(brokenSymlink, brokenSymlinkCopy, - options = {cfSymlinkAsIs, cfSymlinkFollow}) - - # Test copyFileToDir - when symlinksAreHandled: - doAssertRaises(OSError): - copyFileToDir(brokenSymlink, subDir) - doAssertRaises(OSError): - copyFileToDir(brokenSymlink, subDir, {cfSymlinkFollow}) - copyFileToDir(brokenSymlink, subDir, {cfSymlinkIgnore}) - doAssert not fileExists(brokenSymlinkInSubDir) - copyFileToDir(brokenSymlink, subDir, {cfSymlinkAsIs}) - when symlinksAreHandled: - doAssert expandSymlink(brokenSymlinkInSubDir) == brokenSymlinkSrc - removeFile(brokenSymlinkInSubDir) - else: - doAssert not fileExists(brokenSymlinkInSubDir) - - createSymlink(brokenSymlinkSrc, brokenSymlinkInSubDir) - - # Test copyDir - copyDir(subDir, subDir2) - when symlinksAreHandled: - doAssert expandSymlink(brokenSymlinkInSubDir2) == brokenSymlinkSrc - else: - doAssert not fileExists(brokenSymlinkInSubDir2) - removeDir(subDir2) - - # Test copyDirWithPermissions - copyDirWithPermissions(subDir, subDir2) - when symlinksAreHandled: - doAssert expandSymlink(brokenSymlinkInSubDir2) == brokenSymlinkSrc - else: - doAssert not fileExists(brokenSymlinkInSubDir2) - removeDir(subDir2) - - # Test moveFile - moveFile(brokenSymlink, brokenSymlinkCopy) - when not defined(windows): - doAssert expandSymlink(brokenSymlinkCopy) == brokenSymlinkSrc - else: - doAssert symlinkExists(brokenSymlinkCopy) - removeFile(brokenSymlinkCopy) - - # Test moveDir - moveDir(subDir, subDir2) - when not defined(windows): - doAssert expandSymlink(brokenSymlinkInSubDir2) == brokenSymlinkSrc - else: - doAssert symlinkExists(brokenSymlinkInSubDir2) - - removeDir(dname) - -block: # moveFile - let tempDir = getTempDir() / "D20210609T151608" - createDir(tempDir) - defer: removeDir(tempDir) - - writeFile(tempDir / "a.txt", "") - moveFile(tempDir / "a.txt", tempDir / "b.txt") - doAssert not fileExists(tempDir / "a.txt") - doAssert fileExists(tempDir / "b.txt") - removeFile(tempDir / "b.txt") - - createDir(tempDir / "moveFile_test") - writeFile(tempDir / "moveFile_test/a.txt", "") - moveFile(tempDir / "moveFile_test/a.txt", tempDir / "moveFile_test/b.txt") - doAssert not fileExists(tempDir / "moveFile_test/a.txt") - doAssert fileExists(tempDir / "moveFile_test/b.txt") - removeDir(tempDir / "moveFile_test") - - createDir(tempDir / "moveFile_test") - writeFile(tempDir / "a.txt", "") - moveFile(tempDir / "a.txt", tempDir / "moveFile_test/b.txt") - doAssert not fileExists(tempDir / "a.txt") - doAssert fileExists(tempDir / "moveFile_test/b.txt") - removeDir(tempDir / "moveFile_test") - -block: # moveDir - let tempDir = getTempDir() / "D20210609T161443" - createDir(tempDir) - defer: removeDir(tempDir) - - createDir(tempDir / "moveDir_test") - moveDir(tempDir / "moveDir_test/", tempDir / "moveDir_test_dest") - doAssert not dirExists(tempDir / "moveDir_test") - doAssert dirExists(tempDir / "moveDir_test_dest") - removeDir(tempDir / "moveDir_test_dest") - - createDir(tempDir / "moveDir_test") - writeFile(tempDir / "moveDir_test/a.txt", "") - moveDir(tempDir / "moveDir_test", tempDir / "moveDir_test_dest") - doAssert not dirExists(tempDir / "moveDir_test") - doAssert not fileExists(tempDir / "moveDir_test/a.txt") - doAssert dirExists(tempDir / "moveDir_test_dest") - doAssert fileExists(tempDir / "moveDir_test_dest/a.txt") - removeDir(tempDir / "moveDir_test_dest") - import times block modificationTime: # Test get/set modification times @@ -335,7 +154,7 @@ block walkDirRec: doAssert p.startsWith("walkdir_test") var s: seq[string] - for p in walkDirRec("walkdir_test", {pcFile}, {pcDir}, relative = true): + for p in walkDirRec("walkdir_test", {pcFile}, {pcDir}, relative=true): s.add(p) doAssert s.len == 2 @@ -344,36 +163,13 @@ block walkDirRec: removeDir("walkdir_test") -import std/sequtils - -block: # walkDir - doAssertRaises(OSError): - for a in walkDir("nonexistent", checkDir = true): discard - doAssertRaises(OSError): - for p in walkDirRec("nonexistent", checkDir = true): discard - - when not defined(windows): - block walkDirRelative: - createDir("walkdir_test") - createSymlink(".", "walkdir_test/c") - for k, p in walkDir("walkdir_test", true): - doAssert k == pcLinkToDir - removeDir("walkdir_test") - - when defined(posix): - block walkDirSpecial: - createDir("walkdir_test") - doAssert execShellCmd("mkfifo walkdir_test/fifo") == 0 - createSymlink("fifo", "walkdir_test/fifo_link") - let withSpecialFiles = toSeq(walkDir("walkdir_test", relative = true)) - doAssert (withSpecialFiles.len == 2 and - (pcFile, "fifo") in withSpecialFiles and - (pcLinkToFile, "fifo_link") in withSpecialFiles) - # now Unix special files are excluded from walkdir output: - let skipSpecialFiles = toSeq(walkDir("walkdir_test", relative = true, - skipSpecial = true)) - doAssert skipSpecialFiles.len == 0 - removeDir("walkdir_test") +when not defined(windows): + block walkDirRelative: + createDir("walkdir_test") + createSymlink(".", "walkdir_test/c") + for k, p in walkDir("walkdir_test", true): + doAssert k == pcLinkToDir + removeDir("walkdir_test") block normalizedPath: doAssert normalizedPath("") == "" @@ -420,7 +216,7 @@ block absolutePath: doAssertRaises(ValueError): discard absolutePath("a", "b") doAssert absolutePath("a") == getCurrentDir() / "a" doAssert absolutePath("a", "/b") == "/b" / "a" - when defined(posix): + when defined(Posix): doAssert absolutePath("a", "/b/") == "/b" / "a" doAssert absolutePath("a", "/b/c") == "/b/c" / "a" doAssert absolutePath("/a", "b/") == "/a" @@ -529,30 +325,19 @@ block ospaths: doAssert relativePath("/Users/me/bar/z.nim", "/Users/other/bad", '/') == "../../me/bar/z.nim" doAssert relativePath("/Users/me/bar/z.nim", "/Users/other", '/') == "../me/bar/z.nim" - - # `//` is a UNC path, `/` is the current working directory's drive, so can't - # run this test on Windows. - when not doslikeFileSystem: - doAssert relativePath("/Users///me/bar//z.nim", "//Users/", '/') == "me/bar/z.nim" + doAssert relativePath("/Users///me/bar//z.nim", "//Users/", '/') == "me/bar/z.nim" doAssert relativePath("/Users/me/bar/z.nim", "/Users/me", '/') == "bar/z.nim" doAssert relativePath("", "/users/moo", '/') == "" doAssert relativePath("foo", "", '/') == "foo" - doAssert relativePath("/foo", "/Foo", '/') == (when FileSystemCaseSensitive: "../foo" else: ".") - doAssert relativePath("/Foo", "/foo", '/') == (when FileSystemCaseSensitive: "../Foo" else: ".") - doAssert relativePath("/foo", "/fOO", '/') == (when FileSystemCaseSensitive: "../foo" else: ".") - doAssert relativePath("/foO", "/foo", '/') == (when FileSystemCaseSensitive: "../foO" else: ".") + doAssert relativePath("/foo", "/Foo", '/') == (when FileSystemCaseSensitive: "../foo" else: "") + doAssert relativePath("/Foo", "/foo", '/') == (when FileSystemCaseSensitive: "../Foo" else: "") + doAssert relativePath("/foo", "/fOO", '/') == (when FileSystemCaseSensitive: "../foo" else: "") + doAssert relativePath("/foO", "/foo", '/') == (when FileSystemCaseSensitive: "../foO" else: "") doAssert relativePath("foo", ".", '/') == "foo" doAssert relativePath(".", ".", '/') == "." doAssert relativePath("..", ".", '/') == ".." - doAssert relativePath("foo", "foo") == "." - doAssert relativePath("", "foo") == "" - doAssert relativePath("././/foo", "foo//./") == "." - - doAssert relativePath(getCurrentDir() / "bar", "foo") == "../bar".unixToNativePath - doAssert relativePath("bar", getCurrentDir() / "foo") == "../bar".unixToNativePath - when doslikeFileSystem: doAssert relativePath(r"c:\foo.nim", r"C:\") == r"foo.nim" doAssert relativePath(r"c:\foo\bar\baz.nim", r"c:\foo") == r"bar\baz.nim" @@ -568,50 +353,10 @@ block ospaths: doAssert relativePath(r"\\foo\bar\baz.nim", r"\foo") == r"\\foo\bar\baz.nim" doAssert relativePath(r"c:\foo.nim", r"\foo") == r"c:\foo.nim" - doAssert joinPath("usr", "") == unixToNativePath"usr" + doAssert joinPath("usr", "") == unixToNativePath"usr/" doAssert joinPath("", "lib") == "lib" doAssert joinPath("", "/lib") == unixToNativePath"/lib" doAssert joinPath("usr/", "/lib") == unixToNativePath"usr/lib" - doAssert joinPath("", "") == unixToNativePath"" # issue #13455 - doAssert joinPath("", "/") == unixToNativePath"/" - doAssert joinPath("/", "/") == unixToNativePath"/" - doAssert joinPath("/", "") == unixToNativePath"/" - doAssert joinPath("/" / "") == unixToNativePath"/" # weird test case... - doAssert joinPath("/", "/a/b/c") == unixToNativePath"/a/b/c" - doAssert joinPath("foo/", "") == unixToNativePath"foo/" - doAssert joinPath("foo/", "abc") == unixToNativePath"foo/abc" - doAssert joinPath("foo//./", "abc/.//") == unixToNativePath"foo/abc/" - doAssert joinPath("foo", "abc") == unixToNativePath"foo/abc" - doAssert joinPath("", "abc") == unixToNativePath"abc" - - doAssert joinPath("zook/.", "abc") == unixToNativePath"zook/abc" - - # controversial: inconsistent with `joinPath("zook/.","abc")` - # on linux, `./foo` and `foo` are treated a bit differently for executables - # but not `./foo/bar` and `foo/bar` - doAssert joinPath(".", "/lib") == unixToNativePath"./lib" - doAssert joinPath(".", "abc") == unixToNativePath"./abc" - - # cases related to issue #13455 - doAssert joinPath("foo", "", "") == "foo" - doAssert joinPath("foo", "") == "foo" - doAssert joinPath("foo/", "") == unixToNativePath"foo/" - doAssert joinPath("foo/", ".") == "foo" - doAssert joinPath("foo", "./") == unixToNativePath"foo/" - doAssert joinPath("foo", "", "bar/") == unixToNativePath"foo/bar/" - - # issue #13579 - doAssert joinPath("/foo", "../a") == unixToNativePath"/a" - doAssert joinPath("/foo/", "../a") == unixToNativePath"/a" - doAssert joinPath("/foo/.", "../a") == unixToNativePath"/a" - doAssert joinPath("/foo/.b", "../a") == unixToNativePath"/foo/a" - doAssert joinPath("/foo///", "..//a/") == unixToNativePath"/a/" - doAssert joinPath("foo/", "../a") == unixToNativePath"a" - - when doslikeFileSystem: - doAssert joinPath("C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\Common7\\Tools\\", "..\\..\\VC\\vcvarsall.bat") == r"C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" - doAssert joinPath("C:\\foo", "..\\a") == r"C:\a" - doAssert joinPath("C:\\foo\\", "..\\a") == r"C:\a" block getTempDir: block TMPDIR: @@ -627,8 +372,16 @@ block getTempDir: else: doAssert getTempDir() == "/tmp/" -block: # getCacheDir - doAssert getCacheDir().dirExists +block osenv: + block delEnv: + const dummyEnvVar = "DUMMY_ENV_VAR" # This env var wouldn't be likely to exist to begin with + doAssert existsEnv(dummyEnvVar) == false + putEnv(dummyEnvVar, "1") + doAssert existsEnv(dummyEnvVar) == true + delEnv(dummyEnvVar) + doAssert existsEnv(dummyEnvVar) == false + delEnv(dummyEnvVar) # deleting an already deleted env var + doAssert existsEnv(dummyEnvVar) == false block isRelativeTo: doAssert isRelativeTo("/foo", "/") @@ -641,191 +394,3 @@ block isRelativeTo: doAssert isRelativeTo("foo/bar", ".") doAssert not isRelativeTo("foo/bar.nims", "foo/bar.nim") doAssert not isRelativeTo("/foo2", "/foo") - -block: # quoteShellWindows - doAssert quoteShellWindows("aaa") == "aaa" - doAssert quoteShellWindows("aaa\"") == "aaa\\\"" - doAssert quoteShellWindows("") == "\"\"" - -block: # quoteShellCommand - when defined(windows): - doAssert quoteShellCommand(["a b c", "d", "e"]) == """"a b c" d e""" - doAssert quoteShellCommand(["""ab"c""", r"\", "d"]) == """ab\"c \ d""" - doAssert quoteShellCommand(["""ab"c""", """ \""", "d"]) == """ab\"c " \\" d""" - doAssert quoteShellCommand(["""a\\\b""", """de fg""", "h"]) == """a\\\b "de fg" h""" - doAssert quoteShellCommand(["""a\"b""", "c", "d"]) == """a\\\"b c d""" - doAssert quoteShellCommand(["""a\\b c""", "d", "e"]) == """"a\\b c" d e""" - doAssert quoteShellCommand(["""a\\b\ c""", "d", "e"]) == """"a\\b\ c" d e""" - doAssert quoteShellCommand(["ab", ""]) == """ab """"" - -block: # quoteShellPosix - doAssert quoteShellPosix("aaa") == "aaa" - doAssert quoteShellPosix("aaa a") == "'aaa a'" - doAssert quoteShellPosix("") == "''" - doAssert quoteShellPosix("a'a") == "'a'\"'\"'a'" - -block: # quoteShell - when defined(posix): - doAssert quoteShell("") == "''" - -block: # normalizePathEnd - # handle edge cases correctly: shouldn't affect whether path is - # absolute/relative - doAssert "".normalizePathEnd(true) == "" - doAssert "".normalizePathEnd(false) == "" - doAssert "/".normalizePathEnd(true) == $DirSep - doAssert "/".normalizePathEnd(false) == $DirSep - - when defined(posix): - doAssert "//".normalizePathEnd(false) == "/" - doAssert "foo.bar//".normalizePathEnd == "foo.bar" - doAssert "bar//".normalizePathEnd(trailingSep = true) == "bar/" - when defined(windows): - doAssert r"C:\foo\\".normalizePathEnd == r"C:\foo" - doAssert r"C:\foo".normalizePathEnd(trailingSep = true) == r"C:\foo\" - # this one is controversial: we could argue for returning `D:\` instead, - # but this is simplest. - doAssert r"D:\".normalizePathEnd == r"D:" - doAssert r"E:/".normalizePathEnd(trailingSep = true) == r"E:\" - doAssert "/".normalizePathEnd == r"\" - - -import sugar - -block: # normalizeExe - doAssert "".dup(normalizeExe) == "" - when defined(posix): - doAssert "foo".dup(normalizeExe) == "./foo" - doAssert "foo/../bar".dup(normalizeExe) == "foo/../bar" - when defined(windows): - doAssert "foo".dup(normalizeExe) == "foo" - -block: # isAdmin - let isAzure = existsEnv("TF_BUILD") # xxx factor with testament.specs.isAzure - # In Azure on Windows tests run as an admin user - if isAzure and defined(windows): doAssert isAdmin() - # In Azure on POSIX tests run as a normal user - if isAzure and defined(posix): doAssert not isAdmin() - - -import sugar - -block: # normalizeExe - doAssert "".dup(normalizeExe) == "" - when defined(posix): - doAssert "foo".dup(normalizeExe) == "./foo" - doAssert "foo/../bar".dup(normalizeExe) == "foo/../bar" - when defined(windows): - doAssert "foo".dup(normalizeExe) == "foo" - -block: # isAdmin - let isAzure = existsEnv("TF_BUILD") # xxx factor with testament.specs.isAzure - # In Azure on Windows tests run as an admin user - if isAzure and defined(windows): doAssert isAdmin() - # In Azure on POSIX tests run as a normal user - if isAzure and defined(posix): doAssert not isAdmin() - -when doslikeFileSystem: - import std/private/ntpath - - block: # Bug #19103 UNC paths - - # Easiest way of generating a valid, readable and writable UNC path - let tempDir = r"\\?\" & getTempDir() - doAssert dirExists tempDir - createDir tempDir / "test" - removeDir tempDir / "test" - createDir tempDir / "recursive" / "test" - removeDir tempDir / "recursive" / "test" - - let tempDir2 = getTempDir() - let (drive, pathNoDrive) = splitDrive(tempDir2) - setCurrentDir drive - doAssert cmpIgnoreCase(getCurrentDir().splitDrive.drive, drive) == 0 - - # Test `\Users` path syntax on Windows by stripping away drive. `\` - # resolves to the drive in current working directory. This drive will be - # the same as `tempDir2` because of the `setCurrentDir` above. - doAssert pathNoDrive[0] == '\\' - createDir pathNoDrive / "test" - doAssert dirExists pathNoDrive / "test" - removeDir pathNoDrive / "test" - - doAssert splitPath("//?/c:") == ("//?/c:", "") - - doAssert relativePath("//?/c:///Users//me", "//?/c:", '/') == "Users/me" - - doAssert parentDir(r"\\?\c:") == r"" - doAssert parentDir(r"//?/c:/Users") == r"\\?\c:" - doAssert parentDir(r"\\localhost\c$") == r"" - doAssert parentDir(r"\Users") == r"\" - - doAssert tailDir("//?/c:") == "" - doAssert tailDir("//?/c:/Users") == "Users" - doAssert tailDir(r"\\localhost\c$\Windows\System32") == r"Windows\System32" - - doAssert isRootDir("//?/c:") - doAssert isRootDir("//?/UNC/localhost/c$") - doAssert not isRootDir(r"\\?\c:\Users") - - doAssert parentDirs(r"C:\Users", fromRoot = true).toSeq == @[r"C:\", r"C:\Users"] - doAssert parentDirs(r"C:\Users", fromRoot = false).toSeq == @[r"C:\Users", r"C:"] - doAssert parentDirs(r"\\?\c:\Users", fromRoot = true).toSeq == - @[r"\\?\c:\", r"\\?\c:\Users"] - doAssert parentDirs(r"\\?\c:\Users", fromRoot = false).toSeq == - @[r"\\?\c:\Users", r"\\?\c:"] - doAssert parentDirs(r"//localhost/c$/Users", fromRoot = true).toSeq == - @[r"//localhost/c$/", r"//localhost/c$/Users"] - doAssert parentDirs(r"//?/UNC/localhost/c$/Users", fromRoot = false).toSeq == - @[r"//?/UNC/localhost/c$/Users", r"\\?\UNC\localhost\c$"] - doAssert parentDirs(r"\Users", fromRoot = true).toSeq == @[r"\", r"\Users"] - doAssert parentDirs(r"\Users", fromRoot = false).toSeq == @[r"\Users", r"\"] - - doAssert r"//?/c:" /../ "d/e" == r"\\?\c:\d\e" - doAssert r"//?/c:/Users" /../ "d/e" == r"\\?\c:\d\e" - doAssert r"\\localhost\c$" /../ "d/e" == r"\\localhost\c$\d\e" - - doAssert splitFile("//?/c:") == ("//?/c:", "", "") - doAssert splitFile("//?/c:/Users") == ("//?/c:", "Users", "") - doAssert splitFile(r"\\localhost\c$\test.txt") == (r"\\localhost\c$", "test", ".txt") - -else: - block: # parentDirs - doAssert parentDirs("/home", fromRoot=true).toSeq == @["/", "/home"] - doAssert parentDirs("/home", fromRoot=false).toSeq == @["/home", "/"] - doAssert parentDirs("home", fromRoot=true).toSeq == @["home"] - doAssert parentDirs("home", fromRoot=false).toSeq == @["home"] - - doAssert parentDirs("/home/user", fromRoot=true).toSeq == @["/", "/home/", "/home/user"] - doAssert parentDirs("/home/user", fromRoot=false).toSeq == @["/home/user", "/home", "/"] - doAssert parentDirs("home/user", fromRoot=true).toSeq == @["home/", "home/user"] - doAssert parentDirs("home/user", fromRoot=false).toSeq == @["home/user", "home"] - - -# https://github.com/nim-lang/Nim/pull/19643#issuecomment-1235102314 -block: # isValidFilename - # Negative Tests. - doAssert not isValidFilename("abcd", maxLen = 2) - doAssert not isValidFilename("0123456789", maxLen = 8) - doAssert not isValidFilename("con") - doAssert not isValidFilename("aux") - doAssert not isValidFilename("prn") - doAssert not isValidFilename("OwO|UwU") - doAssert not isValidFilename(" foo") - doAssert not isValidFilename("foo ") - doAssert not isValidFilename("foo.") - doAssert not isValidFilename("con.txt") - doAssert not isValidFilename("aux.bat") - doAssert not isValidFilename("prn.exe") - doAssert not isValidFilename("nim>.nim") - doAssert not isValidFilename(" foo.log") - # Positive Tests. - doAssert isValidFilename("abcd", maxLen = 42.Positive) - doAssert isValidFilename("c0n") - doAssert isValidFilename("foo.aux") - doAssert isValidFilename("bar.prn") - doAssert isValidFilename("OwO_UwU") - doAssert isValidFilename("cron") - doAssert isValidFilename("ux.bat") - doAssert isValidFilename("nim.nim") - doAssert isValidFilename("foo.log") diff --git a/tests/stdlib/tos_unc.nim b/tests/stdlib/tos_unc.nim index fc74a4b9d..e55de11ce 100644 --- a/tests/stdlib/tos_unc.nim +++ b/tests/stdlib/tos_unc.nim @@ -4,7 +4,6 @@ discard """ # bug 10952, UNC paths import os -import std/assertions doAssert r"\\hostname\foo\bar" / "baz" == r"\\hostname\foo\bar\baz" doAssert r"\\?\C:\foo" / "bar" == r"\\?\C:\foo\bar" diff --git a/tests/stdlib/tosenv.nim b/tests/stdlib/tosenv.nim deleted file mode 100644 index 20264102f..000000000 --- a/tests/stdlib/tosenv.nim +++ /dev/null @@ -1,163 +0,0 @@ -discard """ - matrix: "--threads" - joinable: false - targets: "c js cpp" -""" - -import std/os -from std/sequtils import toSeq -import stdtest/testutils - -when defined(nimPreviewSlimSystem): - import std/[assertions] - -# "LATIN CAPITAL LETTER AE" in UTF-8 (0xc386) -const unicodeUtf8 = "\xc3\x86" - -template main = - block: # delEnv, existsEnv, getEnv, envPairs - for val in ["val", "", unicodeUtf8]: # ensures empty val works too - const key = "NIM_TESTS_TOSENV_KEY" - doAssert not existsEnv(key) - - putEnv(key, "tempval") - doAssert existsEnv(key) - doAssert getEnv(key) == "tempval" - - putEnv(key, val) # change a key that already exists - doAssert existsEnv(key) - doAssert getEnv(key) == val - - doAssert (key, val) in toSeq(envPairs()) - delEnv(key) - doAssert (key, val) notin toSeq(envPairs()) - doAssert not existsEnv(key) - delEnv(key) # deleting an already deleted env var - doAssert not existsEnv(key) - - block: - doAssert getEnv("NIM_TESTS_TOSENV_NONEXISTENT", "") == "" - doAssert getEnv("NIM_TESTS_TOSENV_NONEXISTENT", " ") == " " - doAssert getEnv("NIM_TESTS_TOSENV_NONEXISTENT", "defval") == "defval" - - whenVMorJs: discard # xxx improve - do: - doAssertRaises(OSError, putEnv("NIM_TESTS_TOSENV_PUT=DUMMY_VALUE", "NEW_DUMMY_VALUE")) - doAssertRaises(OSError, putEnv("", "NEW_DUMMY_VALUE")) - doAssert not existsEnv("") - doAssert not existsEnv("NIM_TESTS_TOSENV_PUT=DUMMY_VALUE") - doAssert not existsEnv("NIM_TESTS_TOSENV_PUT") - -static: main() -main() - -when defined(windows): - import std/widestrs - proc c_wgetenv(env: WideCString): WideCString {.importc: "_wgetenv", header: "".} -proc c_getenv(env: cstring): cstring {.importc: "getenv", header: "".} - -when not defined(js) and not defined(nimscript): - when defined(nimPreviewSlimSystem): - import std/typedthreads - block: # bug #18533 - var thr: Thread[void] - proc threadFunc {.thread.} = putEnv("foo", "fooVal2") - - putEnv("foo", "fooVal1") - doAssert getEnv("foo") == "fooVal1" - createThread(thr, threadFunc) - joinThreads(thr) - when defined(windows): - doAssert getEnv("foo") == $c_wgetenv("foo".newWideCString) - else: - doAssert getEnv("foo") == $c_getenv("foo".cstring) - - doAssertRaises(OSError): delEnv("foo=bar") - -when defined(windows) and not defined(nimscript): - import std/encodings - - proc c_putenv(env: cstring): int32 {.importc: "putenv", header: "".} - proc c_wputenv(env: WideCString): int32 {.importc: "_wputenv", header: "".} - - block: # Bug #20083 - # These test that `getEnv`, `putEnv` and `existsEnv` handle Unicode - # characters correctly. This means that module X in the process calling the - # CRT environment variable API will get the correct string. Raw CRT API - # calls below represent module X. - - # Getting an env. var. with unicode characters returns the correct UTF-8 - # encoded string. - block: - const envName = "twin_envvars1" - doAssert c_wputenv(newWideCString(envName & "=" & unicodeUtf8)) == 0 - doAssert existsEnv(envName) - doAssert getEnv(envName) == unicodeUtf8 - - # Putting an env. var. with unicode characters gives the correct UTF-16 - # encoded string from low-level routine. - block: - const envName = "twin_envvars2" - putEnv(envName, unicodeUtf8) - doAssert $c_wgetenv(envName.newWideCString) == unicodeUtf8 - - # Env. name containing Unicode characters is retrieved correctly - block: - const envName = unicodeUtf8 & "1" - doAssert c_wputenv(newWideCString(envName & "=" & unicodeUtf8)) == 0 - doAssert existsEnv(envName) - doAssert getEnv(envName) == unicodeUtf8 - - # Env. name containing Unicode characters is set correctly - block: - const envName = unicodeUtf8 & "2" - putEnv(envName, unicodeUtf8) - doAssert existsEnv(envName) - doAssert $c_wgetenv(envName.newWideCString) == unicodeUtf8 - - # Env. name containing Unicode characters and empty value is set correctly - block: - const envName = unicodeUtf8 & "3" - putEnv(envName, "") - doAssert existsEnv(envName) - doAssert $c_wgetenv(envName.newWideCString) == "" - - # It's hard to test on Windows code pages, because there is no "change - # a process' locale" API. - if getCurrentEncoding(true) == "windows-1252": - const - unicodeAnsi = "\xc6" # `unicodeUtf8` in `windows-1252` encoding - - # Test that env. var. ANSI API has correct encoding - block: - const - envName = unicodeUtf8 & "4" - envNameAnsi = unicodeAnsi & "4" - putEnv(envName, unicodeUtf8) - doAssert $c_getenv(envNameAnsi.cstring) == unicodeAnsi - - block: - const - envName = unicodeUtf8 & "5" - envNameAnsi = unicodeAnsi & "5" - doAssert c_putenv((envNameAnsi & "=" & unicodeAnsi).cstring) == 0 - doAssert getEnv(envName) == unicodeUtf8 - - # Env. name containing Unicode characters and empty value is set correctly; - # and, if env. name. characters cannot be represented in codepage, don't - # raise an error. - # - # `win_setenv.nim` converts UTF-16 to ANSI when setting empty env. var. The - # windows-1250 locale has no representation of `abreveUtf8` below, so the - # conversion will fail, but this must not be fatal. It is expected that the - # routine ignores updating MBCS environment (`environ` global) and carries - # on. - block: - const - # "LATIN SMALL LETTER A WITH BREVE" in UTF-8 - abreveUtf8 = "\xc4\x83" - envName = abreveUtf8 & "6" - putEnv(envName, "") - doAssert existsEnv(envName) - doAssert $c_wgetenv(envName.newWideCString) == "" - doAssert getEnv(envName) == "" diff --git a/tests/stdlib/toserrors.nim b/tests/stdlib/toserrors.nim deleted file mode 100644 index e907dfe63..000000000 --- a/tests/stdlib/toserrors.nim +++ /dev/null @@ -1,9 +0,0 @@ -discard """ - action: compile -""" - -import std/oserrors - -let x1 = osLastError() -raiseOSError(x1) -echo osErrorMsg(x1) diff --git a/tests/stdlib/tosproc.nim b/tests/stdlib/tosproc.nim index e86f3853b..1859877e7 100644 --- a/tests/stdlib/tosproc.nim +++ b/tests/stdlib/tosproc.nim @@ -1,19 +1,11 @@ -discard """ -joinable: false -""" +# test the osproc module -#[ -joinable: false -because it'd need cleanup up stdout - -see also: tests/osproc/*.nim; consider merging those into a single test here -(easier to factor and test more things as a single self contained test) -]# -import std/[assertions, syncio] +import stdtest/specialpaths +import "../.." / compiler/unittest_light when defined(case_testfile): # compiled test file for child process from posix import exitnow - proc c_exit2(code: cint): void {.importc: "_exit", header: "".} + proc c_exit2(code: c_int): void {.importc: "_exit", header: "".} import os var a = 0 proc fun(b = 0) = @@ -30,12 +22,6 @@ when defined(case_testfile): # compiled test file for child process case arg of "exit_0": if true: quit(0) - of "exit_1": - if true: quit(1) - of "exit_2": - if true: quit(2) - of "exit_42": - if true: quit(42) of "exitnow_139": if true: exitnow(139) of "c_exit2_139": @@ -59,58 +45,22 @@ when defined(case_testfile): # compiled test file for child process echo args[1] main() -elif defined(case_testfile2): - import strutils - let x = stdin.readLine() - echo x.parseInt + 5 +else: -elif defined(case_testfile3): - echo "start ta_out" - stdout.writeLine("to stdout") - stdout.flushFile() - stdout.writeLine("to stdout") - stdout.flushFile() - - stderr.writeLine("to stderr") - stderr.flushFile() - stderr.writeLine("to stderr") - stderr.flushFile() - - stdout.writeLine("to stdout") - stdout.flushFile() - stdout.writeLine("to stdout") - stdout.flushFile() - echo "end ta_out" - -elif defined(case_testfile4): - import system # we could remove that - quit(QuitFailure) - -else: # main driver - import stdtest/[specialpaths, unittest_light] - import os, osproc, strutils + import os, osproc, strutils, posix const nim = getCurrentCompilerExe() - const sourcePath = currentSourcePath() - let dir = getCurrentDir() / "tests" / "osproc" - - template deferScoped(cleanup, body) = - # pending https://github.com/nim-lang/RFCs/issues/236#issuecomment-646855314 - # xxx move to std/sugar or (preferably) some low level module - try: body - finally: cleanup - - # we're testing `execShellCmd` so don't rely on it to compile test file - # note: this should be exported in posix.nim - proc c_system(cmd: cstring): cint {.importc: "system", header: "".} - - proc compileNimProg(opt: string, name: string): string = - result = buildDir / name.addFileExt(ExeExt) - let cmd = "$# c -o:$# --hints:off $# $#" % [nim.quoteShell, result.quoteShell, opt, sourcePath.quoteShell] - doAssert c_system(cmd) == 0, $cmd - doAssert result.fileExists block execShellCmdTest: - let output = compileNimProg("-d:release -d:case_testfile", "D20190111T024543") + ## first, compile child program + const sourcePath = currentSourcePath() + let output = buildDir / "D20190111T024543".addFileExt(ExeExt) + let cmd = "$# c -o:$# -d:release -d:case_testfile $#" % [nim, output, + sourcePath] + # we're testing `execShellCmd` so don't rely on it to compile test file + # note: this should be exported in posix.nim + proc c_system(cmd: cstring): cint {.importc: "system", + header: "".} + assertEquals c_system(cmd), 0 ## use it template runTest(arg: string, expected: int) = @@ -120,23 +70,11 @@ else: # main driver runTest("exit_0", 0) runTest("exitnow_139", 139) runTest("c_exit2_139", 139) - when defined(posix): - runTest("quit_139", 127) # The quit value gets saturated to 127 - else: - runTest("quit_139", 139) - - block execCmdTest: - let output = compileNimProg("-d:release -d:case_testfile", "D20220705T221100") - doAssert execCmd(output & " exit_0") == 0 - doAssert execCmd(output & " exit_1") == 1 - doAssert execCmd(output & " exit_2") == 2 - doAssert execCmd(output & " exit_42") == 42 - - import std/streams + runTest("quit_139", 139) block execProcessTest: - let dir = sourcePath.parentDir - let (_, err) = execCmdEx(nim & " c " & quoteShell(dir / "osproctest.nim")) + let dir = parentDir(currentSourcePath()) + let (outp, err) = execCmdEx(nim & " c " & quoteShell(dir / "osproctest.nim")) doAssert err == 0 let exePath = dir / addFileExt("osproctest", ExeExt) let outStr1 = execProcess(exePath, workingDir = dir, args = ["foo", @@ -151,167 +89,7 @@ else: # main driver doAssert outStr2 == absolutePath(testDir) & "\nx yz\n" removeDir(testDir) - - # test for PipeOutStream - var - p = startProcess(exePath, args = ["abcdefghi", "foo", "bar", "0123456"]) - outStrm = p.peekableOutputStream - - var tmp: string - doAssert outStrm.readLine(tmp) - doAssert outStrm.readChar == 'a' - doAssert outStrm.peekChar == 'b' - doAssert outStrm.readChar == 'b' - doAssert outStrm.readChar == 'c' - doAssert outStrm.peekChar == 'd' - doAssert outStrm.peekChar == 'd' - doAssert outStrm.readChar == 'd' - doAssert outStrm.readStr(2) == "ef" - doAssert outStrm.peekStr(2) == "gh" - doAssert outStrm.peekStr(2) == "gh" - doAssert outStrm.readStr(1) == "g" - doAssert outStrm.readStr(3) == "hi\n" - - doAssert outStrm.readLine == "foo" - doAssert outStrm.readChar == 'b' - doAssert outStrm.peekChar == 'a' - doAssert outStrm.readLine == "ar" - - tmp.setLen(4) - tmp[0] = 'n' - doAssert outStrm.readDataStr(tmp, 1..3) == 3 - doAssert tmp == "n012" - doAssert outStrm.peekStr(3) == "345" - doAssert outStrm.readDataStr(tmp, 1..2) == 2 - doAssert tmp == "n342" - doAssert outStrm.peekStr(2) == "56" - doAssert outStrm.readDataStr(tmp, 0..3) == 3 - doAssert tmp == "56\n2" - p.close - - p = startProcess(exePath, args = ["123"]) - outStrm = p.peekableOutputStream - let c = outStrm.peekChar - doAssert outStrm.readLine(tmp) - doAssert tmp[0] == c - tmp.setLen(7) - doAssert outStrm.peekData(addr tmp[0], 7) == 4 - doAssert tmp[0..3] == "123\n" - doAssert outStrm.peekData(addr tmp[0], 7) == 4 - doAssert tmp[0..3] == "123\n" - doAssert outStrm.readData(addr tmp[0], 7) == 4 - doAssert tmp[0..3] == "123\n" - p.close - try: removeFile(exePath) except OSError: discard - - block: # test for startProcess (more tests needed) - # bugfix: windows stdin.close was a noop and led to blocking reads - proc startProcessTest(command: string, options: set[ProcessOption] = { - poStdErrToStdOut, poUsePath}, input = ""): tuple[ - output: string, - exitCode: int] {.tags: - [ExecIOEffect, ReadIOEffect, RootEffect], gcsafe.} = - var p = startProcess(command, options = options + {poEvalCommand}) - var outp = outputStream(p) - if input.len > 0: inputStream(p).write(input) - close inputStream(p) - result = ("", -1) - var line = newStringOfCap(120) - while true: - if outp.readLine(line): - result[0].add(line) - result[0].add("\n") - else: - result[1] = peekExitCode(p) - if result[1] != -1: break - close(p) - - var result = startProcessTest("nim r --hints:off -", options = {}, input = "echo 3*4") - doAssert result == ("12\n", 0) - - block: # startProcess stdin (replaces old test `tstdin` + `ta_in`) - let output = compileNimProg("-d:case_testfile2", "D20200626T215919") - var p = startProcess(output, dir) # dir not needed though - p.inputStream.write("5\n") - p.inputStream.flush() - var line = "" - var s: seq[string] - while p.outputStream.readLine(line): - s.add line - doAssert s == @["10"] - - block: - let output = compileNimProg("-d:case_testfile3", "D20200626T221233") - var x = newStringOfCap(120) - block: # startProcess stdout poStdErrToStdOut (replaces old test `tstdout` + `ta_out`) - var p = startProcess(output, dir, options={poStdErrToStdOut}) - deferScoped: p.close() - do: - var sout: seq[string] - while p.outputStream.readLine(x): sout.add x - doAssert sout == @["start ta_out", "to stdout", "to stdout", "to stderr", "to stderr", "to stdout", "to stdout", "end ta_out"] - block: # startProcess stderr (replaces old test `tstderr` + `ta_out`) - var p = startProcess(output, dir, options={}) - deferScoped: p.close() - do: - var serr, sout: seq[string] - while p.errorStream.readLine(x): serr.add x - while p.outputStream.readLine(x): sout.add x - doAssert serr == @["to stderr", "to stderr"] - doAssert sout == @["start ta_out", "to stdout", "to stdout", "to stdout", "to stdout", "end ta_out"] - - block: # startProcess exit code (replaces old test `texitcode` + `tafalse`) - let output = compileNimProg("-d:case_testfile4", "D20200626T224758") - var p = startProcess(output, dir) - doAssert waitForExit(p) == QuitFailure - p = startProcess(output, dir) - var running = true - while running: - # xxx: avoid busyloop? - running = running(p) - doAssert waitForExit(p) == QuitFailure - - # make sure that first call to running() after process exit returns false - p = startProcess(output, dir) - for j in 0..<30: # refs #13449 - os.sleep(50) - if not running(p): break - doAssert not running(p) - doAssert waitForExit(p) == QuitFailure # avoid zombies - - import std/strtabs - block execProcessTest: - var result = execCmdEx("nim r --hints:off -", options = {}, input = "echo 3*4") - stripLineEnd(result[0]) - doAssert result == ("12", 0) - when not defined(windows): - doAssert execCmdEx("ls --nonexistent").exitCode != 0 - when false: - # bug: on windows, this raises; on posix, passes - doAssert execCmdEx("nonexistent").exitCode != 0 - when defined(posix): - doAssert execCmdEx("echo $FO", env = newStringTable({"FO": "B"})) == ("B\n", 0) - doAssert execCmdEx("echo $PWD", workingDir = "/") == ("/\n", 0) - - block: # bug #17749 - let output = compileNimProg("-d:case_testfile4", "D20210417T011153") - var p = startProcess(output, dir) - let inp = p.inputStream - var count = 0 - when defined(windows): - # xxx we should make osproc.hsWriteData raise IOError on windows, consistent - # with posix; we could also (in addition) make IOError a subclass of OSError. - type SIGPIPEError = OSError - else: - type SIGPIPEError = IOError - doAssertRaises(SIGPIPEError): - for i in 0..<100000: - count.inc - inp.writeLine "ok" # was giving SIGPIPE and crashing - doAssert count >= 100 - doAssert waitForExit(p) == QuitFailure - close(p) # xxx isn't that missing in other places? diff --git a/tests/stdlib/tosprocterminate.nim b/tests/stdlib/tosprocterminate.nim index 08b379569..a46d91d68 100644 --- a/tests/stdlib/tosprocterminate.nim +++ b/tests/stdlib/tosprocterminate.nim @@ -1,16 +1,11 @@ discard """ - cmd: "nim $target $options -r $file" - targets: "c cpp" - matrix: "--threads:on; " +outputsub: "SUCCESS" """ -import os, osproc, times, std / monotimes -import std/assertions +import os, osproc -when defined(windows): +when defined(Windows): const ProgramWhichDoesNotEnd = "notepad" -elif defined(openbsd): - const ProgramWhichDoesNotEnd = "/bin/cat" else: const ProgramWhichDoesNotEnd = "/bin/sh" @@ -24,21 +19,7 @@ while process.running() and TimeToWait > 0: sleep(100) TimeToWait = TimeToWait - 100 -doAssert not process.running() -echo("stopped process") - -process.close() - -echo("starting " & ProgramWhichDoesNotEnd) -process = startProcess(ProgramWhichDoesNotEnd) -echo("process should be stopped after 2s") - -let start = getMonoTime() -discard process.waitForExit(2000) -let took = getMonoTime() - start - -doAssert not process.running() -# some additional time to account for overhead -doAssert took < initDuration(seconds = 3) - -echo("stopped process after ", took) +if process.running(): + echo("FAILED") +else: + echo("SUCCESS") diff --git a/tests/stdlib/tpackedsets.nim b/tests/stdlib/tpackedsets.nim deleted file mode 100644 index 2c69f6b1b..000000000 --- a/tests/stdlib/tpackedsets.nim +++ /dev/null @@ -1,261 +0,0 @@ -import std/packedsets -import std/sets - -import sequtils -import algorithm - -import std/assertions - -block basicIntSetTests: - var y = initPackedSet[int]() - y.incl(1) - y.incl(2) - y.incl(7) - y.incl(1056) - - y.incl(1044) - y.excl(1044) - - doAssert y == [1, 2, 7, 1056].toPackedSet - doAssert toSeq(y.items) == [1, 2, 7, 1056] - - doAssert y.containsOrIncl(888) == false - doAssert 888 in y - doAssert y.containsOrIncl(888) == true - - doAssert y.missingOrExcl(888) == false - doAssert 888 notin y - doAssert y.missingOrExcl(888) == true - -proc sortedPairs[T](t: T): auto = toSeq(t.pairs).sorted -template sortedItems(t: untyped): untyped = sorted(toSeq(t)) - -type Id = distinct int -proc `$`(x: Id): string {.borrow.} -proc cmp(a: Id, b: Id): int {.borrow.} -proc `==`(a: Id, b: Id): bool {.borrow.} -proc `<`(a: Id, b: Id): bool {.borrow.} - -block genericTests: - # we use HashSet as groundtruth, it's well tested elsewhere - template testDel(A: typedesc, t: typed, t0: typed) = - - block: - template checkEquals() = - doAssert t.len == t0.len - for k in t0: - doAssert k in t - for k in t: - doAssert k in t0 - - doAssert sortedItems(t) == sortedItems(t0) - - template incl2(i) = - t.incl i - t0.incl i - - template excl2(i) = - t.excl i - t0.excl i - - var expected: seq[A] - let n = 100 - let n2 = n*2 - for i in 0.. / - initVars - addNormalizePath("//?/c:/./foo//bar/../baz", result, state, '/') - doAssert result == "//?/c:/foo/baz" - addNormalizePath("me", result, state, '/') - doAssert result == "//?/c:/foo/baz/me" - - block: # / -> \ - initVars - addNormalizePath(r"//?/c:/./foo//bar/../baz", result, state, '\\') - doAssert result == r"\\?\c:\foo\baz" - addNormalizePath("me", result, state, '\\') - doAssert result == r"\\?\c:\foo\baz\me" - - block: # Append path component to UNC drive - initVars - addNormalizePath(r"//?/c:", result, state, '\\') - doAssert result == r"\\?\c:" - addNormalizePath("Users", result, state, '\\') - doAssert result == r"\\?\c:\Users" - addNormalizePath("me", result, state, '\\') - doAssert result == r"\\?\c:\Users\me" diff --git a/tests/stdlib/tpaths.nim b/tests/stdlib/tpaths.nim deleted file mode 100644 index 2d1a3e2ca..000000000 --- a/tests/stdlib/tpaths.nim +++ /dev/null @@ -1,230 +0,0 @@ -import std/paths -import std/assertions -import pathnorm -from std/private/ospaths2 {.all.} import joinPathImpl -import std/sugar - - -proc normalizePath*(path: Path; dirSep = DirSep): Path = - result = Path(pathnorm.normalizePath(path.string, dirSep)) - -func `==`(x, y: Path): bool = - x.string == y.string - -func joinPath*(parts: varargs[Path]): Path = - var estimatedLen = 0 - var state = 0 - for p in parts: estimatedLen += p.string.len - var res = newStringOfCap(estimatedLen) - for i in 0..high(parts): - joinPathImpl(res, state, parts[i].string) - result = Path(res) - - -func joinPath(head, tail: Path): Path {.inline.} = - head / tail - -block absolutePath: - doAssertRaises(ValueError): discard absolutePath(Path"a", Path"b") - doAssert absolutePath(Path"a") == getCurrentDir() / Path"a" - doAssert absolutePath(Path"a", Path"/b") == Path"/b" / Path"a" - when defined(posix): - doAssert absolutePath(Path"a", Path"/b/") == Path"/b" / Path"a" - doAssert absolutePath(Path"a", Path"/b/c") == Path"/b/c" / Path"a" - doAssert absolutePath(Path"/a", Path"b/") == Path"/a" - -block splitFile: - doAssert splitFile(Path"") == (Path"", Path"", "") - doAssert splitFile(Path"abc/") == (Path"abc", Path"", "") - doAssert splitFile(Path"/") == (Path"/", Path"", "") - doAssert splitFile(Path"./abc") == (Path".", Path"abc", "") - doAssert splitFile(Path".txt") == (Path"", Path".txt", "") - doAssert splitFile(Path"abc/.txt") == (Path"abc", Path".txt", "") - doAssert splitFile(Path"abc") == (Path"", Path"abc", "") - doAssert splitFile(Path"abc.txt") == (Path"", Path"abc", ".txt") - doAssert splitFile(Path"/abc.txt") == (Path"/", Path"abc", ".txt") - doAssert splitFile(Path"/foo/abc.txt") == (Path"/foo", Path"abc", ".txt") - doAssert splitFile(Path"/foo/abc.txt.gz") == (Path"/foo", Path"abc.txt", ".gz") - doAssert splitFile(Path".") == (Path"", Path".", "") - doAssert splitFile(Path"abc/.") == (Path"abc", Path".", "") - doAssert splitFile(Path"..") == (Path"", Path"..", "") - doAssert splitFile(Path"a/..") == (Path"a", Path"..", "") - doAssert splitFile(Path"/foo/abc....txt") == (Path"/foo", Path"abc...", ".txt") - -# execShellCmd is tested in tosproc - -block ospaths: - doAssert unixToNativePath(Path"") == Path"" - doAssert unixToNativePath(Path".") == Path($CurDir) - doAssert unixToNativePath(Path"..") == Path($ParDir) - doAssert isAbsolute(unixToNativePath(Path"/")) - doAssert isAbsolute(unixToNativePath(Path"/", Path"a")) - doAssert isAbsolute(unixToNativePath(Path"/a")) - doAssert isAbsolute(unixToNativePath(Path"/a", Path"a")) - doAssert isAbsolute(unixToNativePath(Path"/a/b")) - doAssert isAbsolute(unixToNativePath(Path"/a/b", Path"a")) - doAssert unixToNativePath(Path"a/b") == joinPath(Path"a", Path"b") - - when defined(macos): - doAssert unixToNativePath(Path"./") == Path":" - doAssert unixToNativePath(Path"./abc") == Path":abc" - doAssert unixToNativePath(Path"../abc") == Path"::abc" - doAssert unixToNativePath(Path"../../abc") == Path":::abc" - doAssert unixToNativePath(Path"/abc", Path"a") == Path"abc" - doAssert unixToNativePath(Path"/abc/def", Path"a") == Path"abc:def" - elif doslikeFileSystem: - doAssert unixToNativePath(Path"./") == Path(".\\") - doAssert unixToNativePath(Path"./abc") == Path(".\\abc") - doAssert unixToNativePath(Path"../abc") == Path("..\\abc") - doAssert unixToNativePath(Path"../../abc") == Path("..\\..\\abc") - doAssert unixToNativePath(Path"/abc", Path"a") == Path("a:\\abc") - doAssert unixToNativePath(Path"/abc/def", Path"a") == Path("a:\\abc\\def") - else: - #Tests for unix - doAssert unixToNativePath(Path"./") == Path"./" - doAssert unixToNativePath(Path"./abc") == Path"./abc" - doAssert unixToNativePath(Path"../abc") == Path"../abc" - doAssert unixToNativePath(Path"../../abc") == Path"../../abc" - doAssert unixToNativePath(Path"/abc", Path"a") == Path"/abc" - doAssert unixToNativePath(Path"/abc/def", Path"a") == Path"/abc/def" - - block extractFilenameTest: - doAssert extractFilename(Path"") == Path"" - when defined(posix): - doAssert extractFilename(Path"foo/bar") == Path"bar" - doAssert extractFilename(Path"foo/bar.txt") == Path"bar.txt" - doAssert extractFilename(Path"foo/") == Path"" - doAssert extractFilename(Path"/") == Path"" - when doslikeFileSystem: - doAssert extractFilename(Path(r"foo\bar")) == Path"bar" - doAssert extractFilename(Path(r"foo\bar.txt")) == Path"bar.txt" - doAssert extractFilename(Path(r"foo\")) == Path"" - doAssert extractFilename(Path(r"C:\")) == Path"" - - block lastPathPartTest: - doAssert lastPathPart(Path"") == Path"" - when defined(posix): - doAssert lastPathPart(Path"foo/bar.txt") == Path"bar.txt" - doAssert lastPathPart(Path"foo/") == Path"foo" - doAssert lastPathPart(Path"/") == Path"" - when doslikeFileSystem: - doAssert lastPathPart(Path(r"foo\bar.txt")) == Path"bar.txt" - doAssert lastPathPart(Path(r"foo\")) == Path"foo" - - template canon(x): Path = normalizePath(Path(x), '/') - doAssert canon"/foo/../bar" == Path"/bar" - doAssert canon"foo/../bar" == Path"bar" - - doAssert canon"/f/../bar///" == Path"/bar" - doAssert canon"f/..////bar" == Path"bar" - - doAssert canon"../bar" == Path"../bar" - doAssert canon"/../bar" == Path"/../bar" - - doAssert canon("foo/../../bar/") == Path"../bar" - doAssert canon("./bla/blob/") == Path"bla/blob" - doAssert canon(".hiddenFile") == Path".hiddenFile" - doAssert canon("./bla/../../blob/./zoo.nim") == Path"../blob/zoo.nim" - - doAssert canon("C:/file/to/this/long") == Path"C:/file/to/this/long" - doAssert canon("") == Path"" - doAssert canon("foobar") == Path"foobar" - doAssert canon("f/////////") == Path"f" - - doAssert relativePath(Path"/foo/bar//baz.nim", Path"/foo", '/') == Path"bar/baz.nim" - doAssert normalizePath(Path"./foo//bar/../baz", '/') == Path"foo/baz" - - doAssert relativePath(Path"/Users/me/bar/z.nim", Path"/Users/other/bad", '/') == Path"../../me/bar/z.nim" - - doAssert relativePath(Path"/Users/me/bar/z.nim", Path"/Users/other", '/') == Path"../me/bar/z.nim" - - # `//` is a UNC path, `/` is the current working directory's drive, so can't - # run this test on Windows. - when not doslikeFileSystem: - doAssert relativePath(Path"/Users///me/bar//z.nim", Path"//Users/", '/') == Path"me/bar/z.nim" - doAssert relativePath(Path"/Users/me/bar/z.nim", Path"/Users/me", '/') == Path"bar/z.nim" - doAssert relativePath(Path"", Path"/users/moo", '/') == Path"" - doAssert relativePath(Path"foo", Path"", '/') == Path"foo" - doAssert relativePath(Path"/foo", Path"/Foo", '/') == (when FileSystemCaseSensitive: Path"../foo" else: Path".") - doAssert relativePath(Path"/Foo", Path"/foo", '/') == (when FileSystemCaseSensitive: Path"../Foo" else: Path".") - doAssert relativePath(Path"/foo", Path"/fOO", '/') == (when FileSystemCaseSensitive: Path"../foo" else: Path".") - doAssert relativePath(Path"/foO", Path"/foo", '/') == (when FileSystemCaseSensitive: Path"../foO" else: Path".") - - doAssert relativePath(Path"foo", Path".", '/') == Path"foo" - doAssert relativePath(Path".", Path".", '/') == Path"." - doAssert relativePath(Path"..", Path".", '/') == Path".." - - doAssert relativePath(Path"foo", Path"foo") == Path"." - doAssert relativePath(Path"", Path"foo") == Path"" - doAssert relativePath(Path"././/foo", Path"foo//./") == Path"." - - doAssert relativePath(getCurrentDir() / Path"bar", Path"foo") == Path"../bar".unixToNativePath - doAssert relativePath(Path"bar", getCurrentDir() / Path"foo") == Path"../bar".unixToNativePath - - when doslikeFileSystem: - doAssert relativePath(r"c:\foo.nim".Path, r"C:\".Path) == r"foo.nim".Path - doAssert relativePath(r"c:\foo\bar\baz.nim".Path, r"c:\foo".Path) == r"bar\baz.nim".Path - doAssert relativePath(r"c:\foo\bar\baz.nim".Path, r"d:\foo".Path) == r"c:\foo\bar\baz.nim".Path - doAssert relativePath(r"\foo\baz.nim".Path, r"\foo".Path) == r"baz.nim".Path - doAssert relativePath(r"\foo\bar\baz.nim".Path, r"\bar".Path) == r"..\foo\bar\baz.nim".Path - doAssert relativePath(r"\\foo\bar\baz.nim".Path, r"\\foo\bar".Path) == r"baz.nim".Path - doAssert relativePath(r"\\foo\bar\baz.nim".Path, r"\\foO\bar".Path) == r"baz.nim".Path - doAssert relativePath(r"\\foo\bar\baz.nim".Path, r"\\bar\bar".Path) == r"\\foo\bar\baz.nim".Path - doAssert relativePath(r"\\foo\bar\baz.nim".Path, r"\\foo\car".Path) == r"\\foo\bar\baz.nim".Path - doAssert relativePath(r"\\foo\bar\baz.nim".Path, r"\\goo\bar".Path) == r"\\foo\bar\baz.nim".Path - doAssert relativePath(r"\\foo\bar\baz.nim".Path, r"c:\".Path) == r"\\foo\bar\baz.nim".Path - doAssert relativePath(r"\\foo\bar\baz.nim".Path, r"\foo".Path) == r"\\foo\bar\baz.nim".Path - doAssert relativePath(r"c:\foo.nim".Path, r"\foo".Path) == r"c:\foo.nim".Path - - doAssert joinPath(Path"usr", Path"") == unixToNativePath(Path"usr") - doAssert joinPath(Path"usr", Path"") == (Path"usr").dup(add Path"") - doAssert joinPath(Path"", Path"lib") == Path"lib" - doAssert joinPath(Path"", Path"lib") == Path"".dup(add Path"lib") - doAssert joinPath(Path"", Path"/lib") == unixToNativePath(Path"/lib") - doAssert joinPath(Path"", Path"/lib") == unixToNativePath(Path"/lib") - doAssert joinPath(Path"usr/", Path"/lib") == Path"usr/".dup(add Path"/lib") - doAssert joinPath(Path"", Path"") == unixToNativePath(Path"") # issue #13455 - doAssert joinPath(Path"", Path"") == Path"".dup(add Path"") - doAssert joinPath(Path"", Path"/") == unixToNativePath(Path"/") - doAssert joinPath(Path"", Path"/") == Path"".dup(add Path"/") - doAssert joinPath(Path"/", Path"/") == unixToNativePath(Path"/") - doAssert joinPath(Path"/", Path"/") == Path"/".dup(add Path"/") - doAssert joinPath(Path"/", Path"") == unixToNativePath(Path"/") - doAssert joinPath(Path"/" / Path"") == unixToNativePath(Path"/") # weird test case... - doAssert joinPath(Path"/", Path"/a/b/c") == unixToNativePath(Path"/a/b/c") - doAssert joinPath(Path"foo/", Path"") == unixToNativePath(Path"foo/") - doAssert joinPath(Path"foo/", Path"abc") == unixToNativePath(Path"foo/abc") - doAssert joinPath(Path"foo//./", Path"abc/.//") == unixToNativePath(Path"foo/abc/") - doAssert Path"foo//./".dup(add Path"abc/.//") == unixToNativePath(Path"foo/abc/") - doAssert joinPath(Path"foo", Path"abc") == unixToNativePath(Path"foo/abc") - doAssert Path"foo".dup(add Path"abc") == unixToNativePath(Path"foo/abc") - doAssert joinPath(Path"", Path"abc") == unixToNativePath(Path"abc") - - doAssert joinPath(Path"zook/.", Path"abc") == unixToNativePath(Path"zook/abc") - - # controversial: inconsistent with `joinPath("zook/.","abc")` - # on linux, `./foo` and `foo` are treated a bit differently for executables - # but not `./foo/bar` and `foo/bar` - doAssert joinPath(Path".", Path"/lib") == unixToNativePath(Path"./lib") - doAssert joinPath(Path".", Path"abc") == unixToNativePath(Path"./abc") - - # cases related to issue #13455 - doAssert joinPath(Path"foo", Path"", Path"") == Path"foo" - doAssert joinPath(Path"foo", Path"") == Path"foo" - doAssert joinPath(Path"foo/", Path"") == unixToNativePath(Path"foo/") - doAssert joinPath(Path"foo/", Path".") == Path"foo" - doAssert joinPath(Path"foo", Path"./") == unixToNativePath(Path"foo/") - doAssert joinPath(Path"foo", Path"", Path"bar/") == unixToNativePath(Path"foo/bar/") - - # issue #13579 - doAssert joinPath(Path"/foo", Path"../a") == unixToNativePath(Path"/a") - doAssert joinPath(Path"/foo/", Path"../a") == unixToNativePath(Path"/a") - doAssert joinPath(Path"/foo/.", Path"../a") == unixToNativePath(Path"/a") - doAssert joinPath(Path"/foo/.b", Path"../a") == unixToNativePath(Path"/foo/a") - doAssert joinPath(Path"/foo///", Path"..//a/") == unixToNativePath(Path"/a/") - doAssert joinPath(Path"foo/", Path"../a") == unixToNativePath(Path"a") - - when doslikeFileSystem: - doAssert joinPath(Path"C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\Common7\\Tools\\", Path"..\\..\\VC\\vcvarsall.bat") == r"C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat".Path - doAssert joinPath(Path"C:\\foo", Path"..\\a") == r"C:\a".Path - doAssert joinPath(Path"C:\\foo\\", Path"..\\a") == r"C:\a".Path \ No newline at end of file diff --git a/tests/stdlib/tpegs.nim b/tests/stdlib/tpegs.nim index ab2a6d395..b07442dcb 100644 --- a/tests/stdlib/tpegs.nim +++ b/tests/stdlib/tpegs.nim @@ -1,5 +1,4 @@ discard """ - targets: "c cpp js" output: ''' PEG AST traversal output ------------------------ @@ -51,10 +50,8 @@ Event parser output ''' """ -when defined(nimHasEffectsOf): - {.experimental: "strictEffects".} - -import std/[strutils, streams, pegs, assertions] +import strutils, streams +import pegs const indent = " " @@ -106,9 +103,9 @@ block: block: var - pStack {.threadvar.}: seq[string] - valStack {.threadvar.}: seq[float] - opStack {.threadvar.}: string + pStack: seq[string] = @[] + valStack: seq[float] = @[] + opStack = "" let parseArithExpr = pegAst.eventParser: pkNonTerminal: @@ -127,7 +124,7 @@ block: discard of "Sum", "Product": try: - let val {.used.} = matchStr.parseFloat + let val = matchStr.parseFloat except ValueError: if valStack.len > 1 and opStack.len > 0: valStack[^2] = case opStack[^1] @@ -148,187 +145,4 @@ block: echo "Event parser output" echo "-------------------" let pLen = parseArithExpr(txt) - doAssert txt.len == pLen - - -import std/importutils - -block: - proc pegsTest() = - privateAccess(NonTerminal) - privateAccess(Captures) - - if "test" =~ peg"s <- {{\ident}}": # bug #19104 - doAssert matches[0] == "test" - doAssert matches[1] == "test", $matches[1] - - doAssert escapePeg("abc''def'") == r"'abc'\x27\x27'def'\x27" - doAssert match("(a b c)", peg"'(' @ ')'") - doAssert match("W_HI_Le", peg"\y 'while'") - doAssert(not match("W_HI_L", peg"\y 'while'")) - doAssert(not match("W_HI_Le", peg"\y v'while'")) - doAssert match("W_HI_Le", peg"y'while'") - - doAssert($ +digits == $peg"\d+") - doAssert "0158787".match(peg"\d+") - doAssert "ABC 0232".match(peg"\w+\s+\d+") - doAssert "ABC".match(peg"\d+ / \w+") - - var accum: seq[string] = @[] - for word in split("00232this02939is39an22example111", peg"\d+"): - accum.add(word) - doAssert(accum == @["this", "is", "an", "example"]) - - doAssert matchLen("key", ident) == 3 - - var pattern = sequence(ident, *whitespace, term('='), *whitespace, ident) - doAssert matchLen("key1= cal9", pattern) == 11 - - var ws = newNonTerminal("ws", 1, 1) - ws.rule = *whitespace - - var expr = newNonTerminal("expr", 1, 1) - expr.rule = sequence(capture(ident), *sequence( - nonterminal(ws), term('+'), nonterminal(ws), nonterminal(expr))) - - var c: Captures - var s = "a+b + c +d+e+f" - doAssert rawMatch(s, expr.rule, 0, c) == len(s) - var a = "" - for i in 0..c.ml-1: - a.add(substr(s, c.matches[i][0], c.matches[i][1])) - doAssert a == "abcdef" - #echo expr.rule - - #const filename = "lib/devel/peg/grammar.txt" - #var grammar = parsePeg(newFileStream(filename, fmRead), filename) - #echo "a <- [abc]*?".match(grammar) - doAssert find("_____abc_______", term("abc"), 2) == 5 - doAssert match("_______ana", peg"A <- 'ana' / . A") - doAssert match("abcs%%%", peg"A <- ..A / .A / '%'") - - var matches: array[0..MaxSubpatterns-1, string] - if "abc" =~ peg"{'a'}'bc' 'xyz' / {\ident}": - doAssert matches[0] == "abc" - else: - doAssert false - - var g2 = peg"""S <- A B / C D - A <- 'a'+ - B <- 'b'+ - C <- 'c'+ - D <- 'd'+ - """ - doAssert($g2 == "((A B) / (C D))") - doAssert match("cccccdddddd", g2) - doAssert("var1=key; var2=key2".replacef(peg"{\ident}'='{\ident}", "$1<-$2$2") == - "var1<-keykey; var2<-key2key2") - doAssert("var1=key; var2=key2".replace(peg"{\ident}'='{\ident}", "$1<-$2$2") == - "$1<-$2$2; $1<-$2$2") - doAssert "var1=key; var2=key2".endsWith(peg"{\ident}'='{\ident}") - - if "aaaaaa" =~ peg"'aa' !. / ({'a'})+": - doAssert matches[0] == "a" - else: - doAssert false - - if match("abcdefg", peg"c {d} ef {g}", matches, 2): - doAssert matches[0] == "d" - doAssert matches[1] == "g" - else: - doAssert false - - accum = @[] - for x in findAll("abcdef", peg".", 3): - accum.add(x) - doAssert(accum == @["d", "e", "f"]) - - for x in findAll("abcdef", peg"^{.}", 3): - doAssert x == "d" - - if "f(a, b)" =~ peg"{[0-9]+} / ({\ident} '(' {@} ')')": - doAssert matches[0] == "f" - doAssert matches[1] == "a, b" - else: - doAssert false - - doAssert match("eine übersicht und außerdem", peg"(\letter \white*)+") - # ß is not a lower cased letter?! - doAssert match("eine übersicht und auerdem", peg"(\lower \white*)+") - doAssert match("EINE ÜBERSICHT UND AUSSERDEM", peg"(\upper \white*)+") - doAssert(not match("456678", peg"(\letter)+")) - - doAssert("var1 = key; var2 = key2".replacef( - peg"\skip(\s*) {\ident}'='{\ident}", "$1<-$2$2") == - "var1<-keykey;var2<-key2key2") - - doAssert match("prefix/start", peg"^start$", 7) - - if "foo" =~ peg"{'a'}?.*": - doAssert matches[0].len == 0 - else: doAssert false - - if "foo" =~ peg"{''}.*": - doAssert matches[0] == "" - else: doAssert false - - if "foo" =~ peg"{'foo'}": - doAssert matches[0] == "foo" - else: doAssert false - - let empty_test = peg"^\d*" - let str = "XYZ" - - doAssert(str.find(empty_test) == 0) - doAssert(str.match(empty_test)) - - proc handleMatches(m: int, n: int, c: openArray[string]): string = - result = "" - - if m > 0: - result.add ", " - - result.add case n: - of 2: toLowerAscii(c[0]) & ": '" & c[1] & "'" - of 1: toLowerAscii(c[0]) & ": ''" - else: "" - - doAssert("Var1=key1;var2=Key2; VAR3". - replace(peg"{\ident}('='{\ident})* ';'* \s*", - handleMatches) == "var1: 'key1', var2: 'Key2', var3: ''") - - - doAssert "test1".match(peg"""{@}$""") - doAssert "test2".match(peg"""{(!$ .)*} $""") - - doAssert "abbb".match(peg"{a} {b} $2 $^1") - doAssert "abBA".match(peg"{a} {b} i$2 i$^2") - - doAssert "abba".match(peg"{a} {b} $^1 {} $^1") - - block: - let grammar = peg""" -program <- {''} stmt* $ -stmt <- call / block -call <- 'call()' EOL -EOL <- \n / $ -block <- 'block:' \n indBody -indBody <- {$^1 ' '+} stmt ($^1 stmt)* {} -""" - let program = """ -call() -block: - block: - call() - call() - call() -call() -""" - var c: Captures - doAssert program.len == program.rawMatch(grammar, 0, c) - doAssert c.ml == 1 - - pegsTest() - static: - pegsTest() - + assert txt.len == pLen diff --git a/tests/stdlib/tposix.nim b/tests/stdlib/tposix.nim index d06c5cd56..14f1fd6e2 100644 --- a/tests/stdlib/tposix.nim +++ b/tests/stdlib/tposix.nim @@ -7,7 +7,6 @@ outputsub: "" when not defined(windows): import posix - import std/[assertions, syncio] var u: Utsname @@ -18,46 +17,3 @@ when not defined(windows): writeLine(stdout, u.nodename) writeLine(stdout, u.release) writeLine(stdout, u.machine) - - when not (defined(nintendoswitch) or defined(macos) or defined(macosx)): - block: - type Message = object - value: int - - const MQ_PATH: cstring = "/top_level_file" - const MQ_PRIORITY: cuint = 170 - const MQ_MESSAGE_SIZE: csize_t = csize_t(sizeof(Message)) - - let mqd_a: posix.MqAttr = MqAttr(mq_maxmsg: 10, mq_msgsize: clong(MQ_MESSAGE_SIZE)) - let writable: posix.Mqd = posix.mq_open( - MQ_PATH, - posix.O_CREAT or posix.O_WRONLY or posix.O_NONBLOCK, - posix.S_IRWXU, - addr(mqd_a) - ) - let readable: posix.Mqd = posix.mq_open( - MQ_PATH, - posix.O_RDONLY or posix.O_NONBLOCK, - posix.S_IRWXU, - addr(mqd_a) - ) - - let sent: Message = Message(value: 88) - block: - let success: int = writable.mq_send( - cast[cstring](sent.addr), - MQ_MESSAGE_SIZE, - MQ_PRIORITY - ) - doAssert success == 0, $success - - block: - var buffer: Message - var priority: cuint - let bytesRead: int = readable.mq_receive( - cast[cstring](buffer.addr), - MQ_MESSAGE_SIZE, - priority - ) - doAssert buffer == sent - doAssert bytesRead == int(MQ_MESSAGE_SIZE) diff --git a/tests/stdlib/tprelude.nim b/tests/stdlib/tprelude.nim deleted file mode 100644 index 47f46b511..000000000 --- a/tests/stdlib/tprelude.nim +++ /dev/null @@ -1,16 +0,0 @@ -discard """ - targets: "c js" - matrix: "; -d:nimTestTpreludeCase1" -""" - -when defined nimTestTpreludeCase1: - include std/prelude -else: - include prelude - -import std/assertions - -template main() = - doAssert toSeq(1..3) == @[1,2,3] -static: main() -main() diff --git a/tests/stdlib/tquit.nim b/tests/stdlib/tquit.nim index 12385e57b..1f9283ec4 100644 --- a/tests/stdlib/tquit.nim +++ b/tests/stdlib/tquit.nim @@ -1,18 +1,13 @@ discard """ -disabled: true output: ''' just exiting... ''' joinable: false """ -# Test `addQuitProc` (now deprecated by `addExitProc`) - -import std/syncio +# Test the new beforeQuit variable: proc myExit() {.noconv.} = write(stdout, "just exiting...\n") -{.push warning[deprecated]: off.} addQuitProc(myExit) -{.pop.} diff --git a/tests/stdlib/trandom.nim b/tests/stdlib/trandom.nim deleted file mode 100644 index ef71c3442..000000000 --- a/tests/stdlib/trandom.nim +++ /dev/null @@ -1,274 +0,0 @@ -discard """ - joinable: false # to avoid messing with global rand state - targets: "c js" -""" -import std/[assertions, formatfloat] -import std/[random, math, stats, sets, tables] -when not defined(js): - import std/os - -randomize(233) - -proc main() = - var occur: array[1000, int] - - for i in 0..100_000: - let x = rand(high(occur)) - inc occur[x] - - doAssert max(occur) <= 140 and min(occur) >= 60 # gives some slack - - var a = [0, 1] - shuffle(a) - doAssert a in [[0,1], [1,0]] - - doAssert rand(0) == 0 - when not defined(nimscript): - doAssert sample("a") == 'a' - - when compileOption("rangeChecks") and not defined(nimscript): - doAssertRaises(RangeDefect): - discard rand(-1) - - doAssertRaises(RangeDefect): - discard rand(-1.0) - - # don't use causes integer overflow - doAssert compiles(rand[int](low(int) .. high(int))) - -main() - -block: - when not defined(js): - doAssert almostEqual(rand(12.5), 7.355175342026979) - doAssert almostEqual(rand(2233.3322), 499.342386778917) - - type DiceRoll = range[0..6] - when not defined(js): - doAssert rand(DiceRoll).int == 3 - else: - doAssert rand(DiceRoll).int == 6 - -var rs: RunningStat -for j in 1..5: - for i in 1 .. 100_000: - rs.push(gauss()) - doAssert abs(rs.mean-0) < 0.08, $rs.mean - doAssert abs(rs.standardDeviation()-1.0) < 0.1 - let bounds = [3.5, 5.0] - for a in [rs.max, -rs.min]: - doAssert a >= bounds[0] and a <= bounds[1] - rs.clear() - -block: - type DiceRoll = range[3..6] - var flag = false - for i in 0..<100: - if rand(5.DiceRoll) < 3: - flag = true - doAssert flag # because of: rand(max: int): int - - -block: # random int - block: # there might be some randomness - var set = initHashSet[int](128) - - for i in 1..1000: - incl(set, rand(high(int))) - doAssert len(set) == 1000 - - block: # single number bounds work - var rand: int - for i in 1..1000: - rand = rand(1000) - doAssert rand <= 1000 - doAssert rand >= 0 - - block: # slice bounds work - var rand: int - for i in 1..1000: - rand = rand(100..1000) - doAssert rand <= 1000 - doAssert rand >= 100 - - block: # again gives new numbers - var rand1 = rand(1000000) - when not (defined(js) or defined(nimscript)): - os.sleep(200) - - var rand2 = rand(1000000) - doAssert rand1 != rand2 - -block: # random float - block: # there might be some randomness - var set = initHashSet[float](128) - - for i in 1..100: - incl(set, rand(1.0)) - doAssert len(set) == 100 - - block: # single number bounds work - var rand: float - for i in 1..1000: - rand = rand(1000.0) - doAssert rand <= 1000.0 - doAssert rand >= 0.0 - - block: # slice bounds work - var rand: float - for i in 1..1000: - rand = rand(100.0..1000.0) - doAssert rand <= 1000.0 - doAssert rand >= 100.0 - - block: # again gives new numbers - var rand1: float = rand(1000000.0) - when not (defined(js) or defined(nimscript)): - os.sleep(200) - - var rand2: float = rand(1000000.0) - doAssert rand1 != rand2 - -block: # random sample - block: # "non-uniform array sample unnormalized int CDF - let values = [10, 20, 30, 40, 50] # values - let counts = [4, 3, 2, 1, 0] # weights aka unnormalized probabilities - var histo = initCountTable[int]() - let cdf = counts.cumsummed # unnormalized CDF - for i in 0 ..< 5000: - histo.inc(sample(values, cdf)) - doAssert histo.len == 4 # number of non-zero in `counts` - # Any one bin is a binomial random var for n samples, each with prob p of - # adding a count to k; E[k]=p*n, Var k=p*(1-p)*n, approximately Normal for - # big n. So, P(abs(k - p*n)/sqrt(p*(1-p)*n))>3.0) =~ 0.0027, while - # P(wholeTestFails) =~ 1 - P(binPasses)^4 =~ 1 - (1-0.0027)^4 =~ 0.01. - for i, c in counts: - if c == 0: - doAssert values[i] notin histo - continue - let p = float(c) / float(cdf[^1]) - let n = 5000.0 - let expected = p * n - let stdDev = sqrt(n * p * (1.0 - p)) - doAssert abs(float(histo[values[i]]) - expected) <= 3.0 * stdDev - - block: # non-uniform array sample normalized float CDF - let values = [10, 20, 30, 40, 50] # values - let counts = [0.4, 0.3, 0.2, 0.1, 0] # probabilities - var histo = initCountTable[int]() - let cdf = counts.cumsummed # normalized CDF - for i in 0 ..< 5000: - histo.inc(sample(values, cdf)) - doAssert histo.len == 4 # number of non-zero in ``counts`` - for i, c in counts: - if c == 0: - doAssert values[i] notin histo - continue - let p = float(c) / float(cdf[^1]) - let n = 5000.0 - let expected = p * n - let stdDev = sqrt(n * p * (1.0 - p)) - # NOTE: like unnormalized int CDF test, P(wholeTestFails) =~ 0.01. - doAssert abs(float(histo[values[i]]) - expected) <= 3.0 * stdDev - -block: - # 0 is a valid seed - var r = initRand(0) - doAssert r.rand(1.0) != r.rand(1.0) - r = initRand(10) - doAssert r.rand(1.0) != r.rand(1.0) - # changing the seed changes the sequence - var r1 = initRand(123) - var r2 = initRand(124) - doAssert r1.rand(1.0) != r2.rand(1.0) - -block: # bug #17467 - let n = 1000 - for i in -n .. n: - var r = initRand(i) - let x = r.rand(1.0) - doAssert x > 1e-4, $(x, i) - # This used to fail for each i in 0..<26844, i.e. the 1st produced value - # was predictable and < 1e-4, skewing distributions. - -const withUint = false # pending exporting `proc rand[T: uint | uint64](r: var Rand; max: T): T =` - -block: # bug #16360 - var r = initRand() - template test(a) = - let a2 = a - block: - let a3 = r.rand(a2) - doAssert a3 <= a2 - doAssert a3.type is a2.type - block: - let a3 = rand(a2) - doAssert a3 <= a2 - doAssert a3.type is a2.type - when withUint: - test cast[uint](int.high) - test cast[uint](int.high) + 1 - when not defined(js): - # pending bug #16411 - test uint64.high - test uint64.high - 1 - test uint.high - 2 - test uint.high - 1 - test uint.high - test int.high - test int.high - 1 - test int.high - 2 - test 0 - when withUint: - test 0'u - test 0'u64 - -block: # bug #16296 - var r = initRand() - template test(x) = - let a2 = x - let a3 = r.rand(a2) - doAssert a3 <= a2.b - doAssert a3 >= a2.a - doAssert a3.type is a2.a.type - test(-2 .. int.high-1) - test(int.low .. int.high) - test(int.low+1 .. int.high) - test(int.low .. int.high-1) - test(int.low .. 0) - test(int.low .. -1) - test(int.low .. 1) - test(int64.low .. 1'i64) - when not defined(js): - # pending bug #16411 - test(10'u64 .. uint64.high) - -block: # bug #17670 - when not defined(js): - # pending bug #16411 - type UInt48 = range[0'u64..2'u64^48-1] - let x = rand(UInt48) - doAssert x is UInt48 - -block: # bug #17898 - # Checks whether `initRand()` generates unique states. - # size should be 2^64, but we don't have time and space. - - # Disable this test for js until js gets proper skipRandomNumbers. - when not defined(js): - const size = 1000 - var - rands: array[size, Rand] - randSet: HashSet[Rand] - for i in 0.. 0 - - doAssert o == o - doAssert o >= o - doAssert not(o > o) - doAssert cmp(o, o) == 0 - doAssert cmp(z, z) == 0 - doAssert hash(o) == hash(o) - - doAssert a == b - doAssert a >= b - doAssert not(b > a) - doAssert cmp(a, b) == 0 - doAssert hash(a) == hash(b) - - var x = 1 // 3 - - x *= 5 // 1 - doAssert x == 5 // 3 - x += 2 // 9 - doAssert x == 17 // 9 - x -= 9 // 18 - doAssert x == 25 // 18 - x /= 1 // 2 - doAssert x == 50 // 18 - - var y = 1 // 3 - - y *= 4 - doAssert y == 4 // 3 - y += 5 - doAssert y == 19 // 3 - y -= 2 - doAssert y == 13 // 3 - y /= 9 - doAssert y == 13 // 27 - - doAssert toRational(5) == 5 // 1 - doAssert abs(toFloat(y) - 0.4814814814814815) < 1.0e-7 - doAssert toInt(z) == 0 - - when sizeof(int) == 8: - doAssert toRational(0.98765432) == 2111111029 // 2137499919 - doAssert toRational(PI) == 817696623 // 260280919 - when sizeof(int) == 4: - doAssert toRational(0.98765432) == 80 // 81 - doAssert toRational(PI) == 355 // 113 - - doAssert toRational(0.1) == 1 // 10 - doAssert toRational(0.9) == 9 // 10 - - doAssert toRational(0.0) == 0 // 1 - doAssert toRational(-0.25) == 1 // -4 - doAssert toRational(3.2) == 16 // 5 - doAssert toRational(0.33) == 33 // 100 - doAssert toRational(0.22) == 11 // 50 - doAssert toRational(10.0) == 10 // 1 - - doAssert (1 // 1) div (3 // 10) == 3 - doAssert (-1 // 1) div (3 // 10) == -3 - doAssert (3 // 10) mod (1 // 1) == 3 // 10 - doAssert (-3 // 10) mod (1 // 1) == -3 // 10 - doAssert floorDiv(1 // 1, 3 // 10) == 3 - doAssert floorDiv(-1 // 1, 3 // 10) == -4 - doAssert floorMod(3 // 10, 1 // 1) == 3 // 10 - doAssert floorMod(-3 // 10, 1 // 1) == 7 // 10 - - when sizeof(int) == 8: - doAssert almostEqual(PI.toRational.toFloat, PI) - -static: main() -main() diff --git a/tests/stdlib/tre.nim b/tests/stdlib/tre.nim deleted file mode 100644 index 3986934c4..000000000 --- a/tests/stdlib/tre.nim +++ /dev/null @@ -1,118 +0,0 @@ -import std/re -import std/assertions - -proc testAll() = - doAssert match("(a b c)", rex"\( .* \)") - doAssert match("WHiLe", re("while", {reIgnoreCase})) - - doAssert "0158787".match(re"\d+") - doAssert "ABC 0232".match(re"\w+\s+\d+") - doAssert "ABC".match(rex"\d+ | \w+") - - {.push warnings:off.} - doAssert matchLen("key", re"\b[a-zA-Z_]+[a-zA-Z_0-9]*\b") == 3 - {.pop.} - - var pattern = re"[a-z0-9]+\s*=\s*[a-z0-9]+" - doAssert matchLen("key1= cal9", pattern) == 11 - - doAssert find("_____abc_______", re"abc") == 5 - doAssert findBounds("_____abc_______", re"abc") == (5,7) - - var matches: array[6, string] - if match("abcdefg", re"c(d)ef(g)", matches, 2): - doAssert matches[0] == "d" - doAssert matches[1] == "g" - else: - doAssert false - - if "abc" =~ re"(a)bcxyz|(\w+)": - doAssert matches[1] == "abc" - else: - doAssert false - - if "abc" =~ re"(cba)?.*": - doAssert matches[0] == "" - else: doAssert false - - if "abc" =~ re"().*": - doAssert matches[0] == "" - else: doAssert false - - doAssert "var1=key; var2=key2".endsWith(re"\w+=\w+") - doAssert("var1=key; var2=key2".replacef(re"(\w+)=(\w+)", "$1<-$2$2") == - "var1<-keykey; var2<-key2key2") - doAssert("var1=key; var2=key2".replace(re"(\w+)=(\w+)", "$1<-$2$2") == - "$1<-$2$2; $1<-$2$2") - - var accum: seq[string] = @[] - for word in split("00232this02939is39an22example111", re"\d+"): - accum.add(word) - doAssert(accum == @["", "this", "is", "an", "example", ""]) - - accum = @[] - for word in split("00232this02939is39an22example111", re"\d+", maxsplit=2): - accum.add(word) - doAssert(accum == @["", "this", "is39an22example111"]) - - accum = @[] - for word in split("AAA : : BBB", re"\s*:\s*"): - accum.add(word) - doAssert(accum == @["AAA", "", "BBB"]) - - doAssert(split("abc", re"") == @["a", "b", "c"]) - doAssert(split("", re"") == @[]) - - doAssert(split("a;b;c", re";") == @["a", "b", "c"]) - doAssert(split(";a;b;c", re";") == @["", "a", "b", "c"]) - doAssert(split(";a;b;c;", re";") == @["", "a", "b", "c", ""]) - doAssert(split("a;b;c;", re";") == @["a", "b", "c", ""]) - doAssert(split("00232this02939is39an22example111", re"\d+", maxsplit=2) == @["", "this", "is39an22example111"]) - - - for x in findAll("abcdef", re"^{.}", 3): - doAssert x == "d" - accum = @[] - for x in findAll("abcdef", re".", 3): - accum.add(x) - doAssert(accum == @["d", "e", "f"]) - - doAssert("XYZ".find(re"^\d*") == 0) - doAssert("XYZ".match(re"^\d*") == true) - - block: - var matches: array[16, string] - if match("abcdefghijklmnop", re"(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)(k)(l)(m)(n)(o)(p)", matches): - for i in 0..matches.high: - doAssert matches[i] == $chr(i + 'a'.ord) - else: - doAssert false - - block: # Buffer based RE - var cs: cstring = "_____abc_______" - doAssert(cs.find(re"abc", bufSize=15) == 5) - doAssert(cs.matchLen(re"_*abc", bufSize=15) == 8) - doAssert(cs.matchLen(re"abc", start=5, bufSize=15) == 3) - doAssert(cs.matchLen(re"abc", start=5, bufSize=7) == -1) - doAssert(cs.matchLen(re"abc_*", start=5, bufSize=10) == 5) - var accum: seq[string] = @[] - for x in cs.findAll(re"[a-z]", start=3, bufSize=15): - accum.add($x) - doAssert(accum == @["a","b","c"]) - - block: # bug #9306 - doAssert replace("bar", re"^", "foo") == "foobar" - doAssert replace("foo", re"$", "bar") == "foobar" - - - block: # bug #9437 - doAssert replace("foo", re"", "-") == "-f-o-o-" - doAssert replace("ooo", re"o", "-") == "---" - - block: # bug #14468 - accum = @[] - for word in split("this is an example", re"\b"): - accum.add(word) - doAssert(accum == @["this", " ", "is", " ", "an", " ", "example"]) - -testAll() diff --git a/tests/stdlib/tregex.nim b/tests/stdlib/tregex.nim index cf80f8122..21f4e6743 100644 --- a/tests/stdlib/tregex.nim +++ b/tests/stdlib/tregex.nim @@ -11,7 +11,7 @@ when defined(powerpc64): else: import re - import std/syncio + if "keyA = valueA" =~ re"\s*(\w+)\s*\=\s*(\w+)": write(stdout, "key: ", matches[0]) elif "# comment!" =~ re.re"\s*(\#.*)": diff --git a/tests/stdlib/tregistry.nim b/tests/stdlib/tregistry.nim deleted file mode 100644 index 4956f8196..000000000 --- a/tests/stdlib/tregistry.nim +++ /dev/null @@ -1,16 +0,0 @@ -discard """ - disabled: "unix" - matrix: "--gc:refc; --gc:arc" -""" - -when defined(windows): - import std/registry - import std/assertions - - block: # bug #14010 - let path = "Environment" - let key = "D20210328T202842_key" - let val = "D20210328T202842_val" - let handle = HKEY_CURRENT_USER - setUnicodeValue("Environment", key, val, handle) - doAssert getUnicodeValue(path, key, handle) == val diff --git a/tests/stdlib/trepr.nim b/tests/stdlib/trepr.nim index 0511d1004..c1941bd38 100644 --- a/tests/stdlib/trepr.nim +++ b/tests/stdlib/trepr.nim @@ -1,326 +1,36 @@ discard """ - targets: "c cpp js" - matrix: ";--gc:arc" + output: '''{a, b}{'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'} +[1, 2, 3, 4, 5, 6]''' """ -# if excessive, could remove 'cpp' from targets +type + TEnum = enum + a, b -from strutils import endsWith, contains, strip -from std/macros import newLit -import std/assertions +var val = {a, b} +stdout.write(repr(val)) +stdout.writeLine(repr({'a'..'z', 'A'..'Z'})) -macro deb(a): string = newLit a.repr.strip -macro debTyped(a: typed): string = newLit a.repr.strip +type + TObj {.pure, inheritable.} = object + data: int + TFoo = ref object of TObj + d2: float +var foo: TFoo +new(foo) -template main() = - doAssert repr({3,5}) == "{3, 5}" +when false: + # cannot capture this output as it contains a memory address :-/ + echo foo.repr +#var testseq: seq[string] = @[ +# "a", "b", "c", "d", "e" +#] +#echo(repr(testseq)) - block: - type TEnum = enum a, b - var val = {a, b} - when nimvm: - discard - #[ - # BUG: - {0, 1} - {97..99, 65..67} - ]# - else: - doAssert repr(val) == "{a, b}" - doAssert repr({'a'..'c', 'A'..'C'}) == "{'A', 'B', 'C', 'a', 'b', 'c'}" +# bug #7878 +proc test(variable: var openarray[int]) = + echo repr(variable) - type - TObj {.pure, inheritable.} = object - data: int - TFoo = ref object of TObj - d2: float - var foo: TFoo - new(foo) +var arr = [1, 2, 3, 4, 5, 6] - #[ - BUG: - --gc:arc returns `"abc"` - regular gc returns with address, e.g. 0x1068aae60"abc", but only - for c,cpp backends (not js, vm) - ]# - block: - doAssert repr("abc").endsWith "\"abc\"" - var b: cstring = "def" - doAssert repr(b).endsWith "\"def\"" - - block: - var c = @[1,2] - when nimvm: - discard # BUG: this shows [1, 2] instead of @[1, 2] - else: - # BUG (already mentioned above): some backends / gc show address, others don't - doAssert repr(c).endsWith "@[1, 2]" - - let d = @["foo", "bar"] - let s = repr(d) - # depending on backend/gc, we get 0x106a1c350@[0x106a1c390"foo", 0x106a1c3c0"bar"] - doAssert "\"foo\"," in s - - var arr = [1, 2, 3] - doAssert repr(arr) == "[1, 2, 3]" - - block: # bug #7878 - proc reprOpenarray(variable: var openArray[int]): string = repr(variable) - when defined(js): discard # BUG: doesn't work - else: - doAssert reprOpenarray(arr) == "[1, 2, 3]" - - block: # bug #17292 repr with `do` - template foo(a, b, c, d) = discard - block: - let a = deb: - foo(1, 2, 3, 4) - doAssert a == "foo(1, 2, 3, 4)" - block: - let a = deb: - foo(1, 2, 3): 4 - doAssert a == """ -foo(1, 2, 3): - 4""" - - block: - let a = deb: - foo(1, 2): 3 - do: 4 - doAssert a == """ -foo(1, 2): - 3 -do: - 4""" - - block: - let a = deb: - foo(1): 3 - do: 3 - do: 4 - doAssert a == """ -foo(1): - 3 -do: - 3 -do: - 4""" - - block: - let a = deb: - foo(1): - 3 - do: - discard - 3 - do: - discard - 4 - - doAssert a == """ -foo(1): - 3 -do: - discard - 3 -do: - discard - 4""" - - block: - let a = deb: - foo: 1 - do: 2 - do: 3 - do: 4 - doAssert a == """ -foo: - 1 -do: - 2 -do: - 3 -do: - 4""" - - block: # bug #17292 repr with `(discard)` (`discard` would result in illegal code) - let a = deb: - let f {.inject.} = () => (discard) - doAssert a == """ -let f {.inject.} = () => - (discard )""" - - let a2 = deb: - block: - discard - discard - - block: - when true: discard - - # let a = b => discard # illegal - discard b => (discard) # legal - - block: - return - doAssert a2 == """ -block: - discard -discard -block: - when true: - discard -discard b => - (discard ) -block: - return""" - - block: # bug #17292 (bug 4) - let a = deb: - proc `=destroy`() = discard - proc `'foo`(): int = discard - proc `foo bar baz`(): int = discard - let a2 = """ -proc `=destroy`() = - discard - -proc `'foo`(): int = - discard - -proc `foo bar baz`(): int = - discard""" - doAssert a2 == a - - block: # setters: `foo=` - let a = deb: - proc `foo=`() = discard - doAssert a == """ -proc `foo=`() = - discard""" - - block: # bug #14850 - block: - let a = deb: - template bar(): untyped = - foo1: - discard - 4 - foo2(1): - discard - 4 - foo3(1): - discard - 4 - do: 1 - do: 2 - x.add foo4 - x.add: foo5: 3 - x.add foo6 do: 4 - a.add(foo7 do: - echo "baz" - 4) - - doAssert a == """ -template bar(): untyped = - foo1: - discard - 4 - foo2(1): - discard - 4 - foo3(1): - discard - 4 - do: - 1 - do: - 2 - x.add foo4 - x.add: - foo5: - 3 - x.add foo6 do: - 4 - a.add(foo7 do: - echo "baz" - 4)""" - - block: # one liner doc comments - let a1 = deb: - func fn1(): int = 1 ## comment - func fn2(): int = 1 - ## comment - let a2 = debTyped: - func fn1(): int = 1 ## comment - func fn2(): int = 1 - ## comment - doAssert a1 == """ -func fn1(): int = - ## comment - 1 - -func fn2(): int = - ## comment - 1""" - doAssert a2 == """ -func fn1(): int = - ## comment - result = 1 - -func fn2(): int = - ## comment - result = 1""" - - block: # block calls - let a = deb: - foo(a, b, (c, d)): - e - f - do: g - of h: i - elif j: k - except m: n - do () -> u: v - finally: o - - a + b: - c - d - do: - e - f - else: g - - *a: b - do: c - - doAssert a == """foo(a, b, (c, d)): - e - f -do: - g -of h: - i -elif j: - k -except m: - n -do -> u: - v -finally: - o -a + b: - c - d -do: - e - f -else: - g -*a: - b -do: - c""" - -static: main() -main() +test(arr) diff --git a/tests/stdlib/trepr2.nim b/tests/stdlib/trepr2.nim new file mode 100644 index 000000000..7b9f9db28 --- /dev/null +++ b/tests/stdlib/trepr2.nim @@ -0,0 +1,37 @@ +discard """ +outputsub: "" +""" + +# output not testable because repr prints pointer addresses +# test the new "repr" built-in proc + +type + TEnum = enum + en1, en2, en3, en4, en5, en6 + + TPoint {.final.} = object + x, y, z: int + s: array[0..1, string] + e: TEnum + +var + p: TPoint + q: ref TPoint + s: seq[ref TPoint] + +p.x = 0 +p.y = 13 +p.z = 45 +p.s[0] = "abc" +p.s[1] = "xyz" +p.e = en6 + +new(q) +q[] = p + +s = @[q, q, q, q] + +writeLine(stdout, repr(p)) +writeLine(stdout, repr(q)) +writeLine(stdout, repr(s)) +writeLine(stdout, repr(en4)) diff --git a/tests/stdlib/trlocks.nim b/tests/stdlib/trlocks.nim deleted file mode 100644 index 135d9b028..000000000 --- a/tests/stdlib/trlocks.nim +++ /dev/null @@ -1,14 +0,0 @@ -discard """ - action: "compile" - # Disallow joining to ensure it can compile in isolation. - # See #15584 - joinable: false - cmd: "nim $target --threads:on $options $file" -""" - -# bugfix #15584 - -import rlocks - -var r: RLock -r.initRLock() diff --git a/tests/stdlib/tropes.nim b/tests/stdlib/tropes.nim deleted file mode 100644 index 6d41e9e44..000000000 --- a/tests/stdlib/tropes.nim +++ /dev/null @@ -1,103 +0,0 @@ -discard """ - targets: "c js" -""" - -import std/ropes -import std/assertions - -template main() = - block: - let r: Rope = nil - doAssert r[0] == '\0' - doAssert $r == "" - - block: - var - r1 = rope("Hello, ") - r2 = rope("Nim-Lang") - - let r = r1 & r2 - let s = $r - doAssert s == "Hello, Nim-Lang" - for i in 0 ..< r.len: - doAssert r[i] == s[i] - - doAssert r[66] == '\0' - - block: - let r = rope("Hello, Nim-Lang") - - let s = $r - doAssert s == "Hello, Nim-Lang" - for i in 0 ..< r.len: - doAssert r[i] == s[i] - - doAssert r[66] == '\0' - - block: - var r: Rope - r.add rope("Nim ") - r.add rope("is ") - r.add rope("a ") - r.add rope("great ") - r.add rope("language") - - let s = $r - doAssert s == "Nim is a great language" - for i in 0 ..< r.len: - doAssert r[i] == s[i] - - doAssert r[66] == '\0' - - block: - var r: Rope - r.add rope("My Conquest") - r.add rope(" is ") - r.add rope("the Sea of Stars") - - let s = $r - doAssert s == "My Conquest is the Sea of Stars" - for i in 0 ..< r.len: - doAssert r[i] == s[i] - - doAssert r[66] == '\0' - - block: - var r: Rope - r.add rope("My Conquest") - r.add rope(" is ") - r.add rope("the Sea of Stars") - - doAssert $r == "My Conquest is the Sea of Stars" - - var i: int - for item in r: - doAssert r[i] == item - inc i - - doAssert r[66] == '\0' - - block: - let r1 = "$1 $2 $3" % [rope("Nim"), rope("is"), rope("a great language")] - doAssert $r1 == "Nim is a great language" - - let r2 = "$# $# $#" % [rope("Nim"), rope("is"), rope("a great language")] - doAssert $r2 == "Nim is a great language" - - block: # `[]` - let r1 = rope("Hello, Nim!") - - doAssert r1[-2] == '\0' - doAssert r1[0] == 'H' - doAssert r1[7] == 'N' - doAssert r1[22] == '\0' - - let r2 = rope("Hello") & rope(", Nim!") - - doAssert r2[-2] == '\0' - doAssert r2[0] == 'H' - doAssert r2[7] == 'N' - doAssert r2[22] == '\0' - -static: main() -main() diff --git a/tests/stdlib/trst.nim b/tests/stdlib/trst.nim index da787d274..6b1bd6897 100644 --- a/tests/stdlib/trst.nim +++ b/tests/stdlib/trst.nim @@ -1,1412 +1,15 @@ -discard """ - output: ''' - -[Suite] RST parsing - -[Suite] RST tables - -[Suite] RST indentation - -[Suite] Markdown indentation - -[Suite] Warnings - -[Suite] RST include directive - -[Suite] RST escaping - -[Suite] RST inline markup -''' -""" - # tests for rst module -import ../../lib/packages/docutils/[rstgen, rst, rstast] -import unittest, strutils -import std/private/miscdollars +import ../../lib/packages/docutils/rstgen +import ../../lib/packages/docutils/rst +import unittest import os -import std/[assertions, syncio] - -const preferMarkdown = {roPreferMarkdown, roSupportMarkdown, roNimFile, roSandboxDisabled} -const preferRst = {roSupportMarkdown, roNimFile, roSandboxDisabled} - -proc toAst(input: string, - rstOptions: RstParseOptions = preferMarkdown, - error: ref string = nil, - warnings: ref seq[string] = nil): string = - ## If `error` is nil then no errors should be generated. - ## The same goes for `warnings`. - proc testMsgHandler(filename: string, line, col: int, msgkind: MsgKind, - arg: string) = - let mc = msgkind.whichMsgClass - let a = $msgkind % arg - var message: string - toLocation(message, filename, line, col + ColRstOffset) - message.add " $1: $2" % [$mc, a] - if mc == mcError: - if error == nil: - raise newException(EParseError, "[unexpected error] " & message) - error[] = message - # we check only first error because subsequent ones may be meaningless - raise newException(EParseError, "") - else: - doAssert warnings != nil, "unexpected RST warning '" & message & "'" - warnings[].add message - try: - const filen = "input" - - proc myFindFile(filename: string): string = - # we don't find any files in online mode: - result = "" - - var (rst, _, _) = rstParse(input, filen, line=LineRstInit, column=ColRstInit, - rstOptions, myFindFile, nil, testMsgHandler) - result = treeRepr(rst) - except EParseError as e: - if e.msg != "": - result = e.msg - -suite "RST parsing": - test "References are whitespace-neutral and case-insensitive": - # refname is 'lexical-analysis', the same for all the 3 variants: - check(dedent""" - Lexical Analysis - ================ - - Ref. `Lexical Analysis`_ or `Lexical analysis`_ or `lexical analysis`_. - """.toAst == - dedent""" - rnInner - rnHeadline level=1 anchor='lexical-analysis' - rnLeaf 'Lexical' - rnLeaf ' ' - rnLeaf 'Analysis' - rnParagraph - rnLeaf 'Ref' - rnLeaf '.' - rnLeaf ' ' - rnInternalRef - rnInner - rnLeaf 'Lexical' - rnLeaf ' ' - rnLeaf 'Analysis' - rnLeaf 'lexical-analysis' - rnLeaf ' ' - rnLeaf 'or' - rnLeaf ' ' - rnInternalRef - rnInner - rnLeaf 'Lexical' - rnLeaf ' ' - rnLeaf 'analysis' - rnLeaf 'lexical-analysis' - rnLeaf ' ' - rnLeaf 'or' - rnLeaf ' ' - rnInternalRef - rnInner - rnLeaf 'lexical' - rnLeaf ' ' - rnLeaf 'analysis' - rnLeaf 'lexical-analysis' - rnLeaf '.' - rnLeaf ' ' - """) - - test "RST quoted literal blocks": - let expected = - dedent""" - rnInner - rnLeaf 'Paragraph' - rnLeaf ':' - rnLiteralBlock - rnLeaf '>x' - """ - - check(dedent""" - Paragraph:: - - >x""".toAst(rstOptions = preferRst) == expected) - - check(dedent""" - Paragraph:: - - >x""".toAst(rstOptions = preferRst) == expected) - - test "RST quoted literal blocks, :: at a separate line": - let expected = - dedent""" - rnInner - rnInner - rnLeaf 'Paragraph' - rnLiteralBlock - rnLeaf '>x - >>y' - """ - - check(dedent""" - Paragraph - - :: - - >x - >>y""".toAst(rstOptions = preferRst) == expected) - - check(dedent""" - Paragraph - - :: - - >x - >>y""".toAst(rstOptions = preferRst) == expected) - - test "Markdown quoted blocks": - check(dedent""" - Paragraph. - >x""".toAst == - dedent""" - rnInner - rnLeaf 'Paragraph' - rnLeaf '.' - rnMarkdownBlockQuote - rnMarkdownBlockQuoteItem quotationDepth=1 - rnLeaf 'x' - """) - - # bug #17987 - check(dedent""" - foo https://github.com/nim-lang/Nim/issues/8258 - - > bar""".toAst == - dedent""" - rnInner - rnInner - rnLeaf 'foo' - rnLeaf ' ' - rnStandaloneHyperlink - rnLeaf 'https://github.com/nim-lang/Nim/issues/8258' - rnMarkdownBlockQuote - rnMarkdownBlockQuoteItem quotationDepth=1 - rnLeaf 'bar' - """) - - let expected = dedent""" - rnInner - rnLeaf 'Paragraph' - rnLeaf '.' - rnMarkdownBlockQuote - rnMarkdownBlockQuoteItem quotationDepth=1 - rnInner - rnLeaf 'x1' - rnLeaf ' ' - rnLeaf 'x2' - rnMarkdownBlockQuoteItem quotationDepth=2 - rnInner - rnLeaf 'y1' - rnLeaf ' ' - rnLeaf 'y2' - rnMarkdownBlockQuoteItem quotationDepth=1 - rnLeaf 'z' - """ - - check(dedent""" - Paragraph. - >x1 x2 - >>y1 y2 - >z""".toAst == expected) - - check(dedent""" - Paragraph. - > x1 x2 - >> y1 y2 - > z""".toAst == expected) - - check(dedent""" - >x - >y - >z""".toAst == - dedent""" - rnMarkdownBlockQuote - rnMarkdownBlockQuoteItem quotationDepth=1 - rnInner - rnLeaf 'x' - rnLeaf ' ' - rnLeaf 'y' - rnLeaf ' ' - rnLeaf 'z' - """) - - check(dedent""" - > z - > > >y - """.toAst == - dedent""" - rnMarkdownBlockQuote - rnMarkdownBlockQuoteItem quotationDepth=1 - rnLeaf 'z' - rnMarkdownBlockQuoteItem quotationDepth=3 - rnLeaf 'y' - """) - - test "Markdown quoted blocks: lazy": - let expected = dedent""" - rnInner - rnMarkdownBlockQuote - rnMarkdownBlockQuoteItem quotationDepth=2 - rnInner - rnLeaf 'x' - rnLeaf ' ' - rnLeaf 'continuation1' - rnLeaf ' ' - rnLeaf 'continuation2' - rnParagraph - rnLeaf 'newParagraph' - """ - check(dedent""" - >>x - continuation1 - continuation2 - - newParagraph""".toAst == expected) - - check(dedent""" - >> x - continuation1 - continuation2 - - newParagraph""".toAst == expected) - - # however mixing more than 1 non-lazy line and lazy one(s) splits quote - # in our parser, which appeared the easiest way to handle such cases: - var warnings = new seq[string] - check(dedent""" - >> x - >> continuation1 - continuation2 - - newParagraph""".toAst(warnings=warnings) == - dedent""" - rnInner - rnMarkdownBlockQuote - rnMarkdownBlockQuoteItem quotationDepth=2 - rnLeaf 'x' - rnMarkdownBlockQuoteItem quotationDepth=2 - rnInner - rnLeaf 'continuation1' - rnLeaf ' ' - rnLeaf 'continuation2' - rnParagraph - rnLeaf 'newParagraph' - """) - check(warnings[] == @[ - "input(2, 1) Warning: RST style: two or more quoted lines " & - "are followed by unquoted line 3"]) - - test "Markdown quoted blocks: not lazy": - # here is where we deviate from CommonMark specification: 'bar' below is - # not considered as continuation of 2-level '>> foo' quote. - check(dedent""" - >>> foo - > bar - >> baz - """.toAst() == - dedent""" - rnMarkdownBlockQuote - rnMarkdownBlockQuoteItem quotationDepth=3 - rnLeaf 'foo' - rnMarkdownBlockQuoteItem quotationDepth=1 - rnLeaf 'bar' - rnMarkdownBlockQuoteItem quotationDepth=2 - rnLeaf 'baz' - """) - - - test "Markdown quoted blocks: inline markup works": - check(dedent""" - > hi **bold** text - """.toAst == dedent""" - rnMarkdownBlockQuote - rnMarkdownBlockQuoteItem quotationDepth=1 - rnInner - rnLeaf 'hi' - rnLeaf ' ' - rnStrongEmphasis - rnLeaf 'bold' - rnLeaf ' ' - rnLeaf 'text' - """) - - test "Markdown quoted blocks: blank line separator": - let expected = dedent""" - rnInner - rnMarkdownBlockQuote - rnMarkdownBlockQuoteItem quotationDepth=1 - rnInner - rnLeaf 'x' - rnLeaf ' ' - rnLeaf 'y' - rnMarkdownBlockQuote - rnMarkdownBlockQuoteItem quotationDepth=1 - rnInner - rnLeaf 'z' - rnLeaf ' ' - rnLeaf 't' - """ - check(dedent""" - >x - >y - - > z - > t""".toAst == expected) - - check(dedent""" - >x - y - - > z - t""".toAst == expected) - - test "Markdown quoted blocks: nested body blocks/elements work #1": - let expected = dedent""" - rnMarkdownBlockQuote - rnMarkdownBlockQuoteItem quotationDepth=1 - rnBulletList - rnBulletItem - rnInner - rnLeaf 'x' - rnBulletItem - rnInner - rnLeaf 'y' - """ - - check(dedent""" - > - x - - y - """.toAst == expected) - - # TODO: if bug #17340 point 28 is resolved then this may work: - # check(dedent""" - # > - x - # - y - # """.toAst == expected) - - check(dedent""" - > - x - > - y - """.toAst == expected) - - check(dedent""" - > - > - x - > - > - y - > - """.toAst == expected) - - test "Markdown quoted blocks: nested body blocks/elements work #2": - let expected = dedent""" - rnAdmonition adType=note - [nil] - [nil] - rnDefList - rnDefItem - rnDefName - rnLeaf 'deflist' - rnLeaf ':' - rnDefBody - rnMarkdownBlockQuote - rnMarkdownBlockQuoteItem quotationDepth=2 - rnInner - rnLeaf 'quote' - rnLeaf ' ' - rnLeaf 'continuation' - """ - - check(dedent""" - .. Note:: deflist: - >> quote - continuation - """.toAst(rstOptions = preferRst) == expected) - - check(dedent""" - .. Note:: - deflist: - >> quote - continuation - """.toAst(rstOptions = preferRst) == expected) - - check(dedent""" - .. Note:: - deflist: - >> quote - >> continuation - """.toAst(rstOptions = preferRst) == expected) - - # spaces are not significant between `>`: - check(dedent""" - .. Note:: - deflist: - > > quote - > > continuation - """.toAst(rstOptions = preferRst) == expected) - - test "Markdown quoted blocks: de-indent handled well": - check(dedent""" - > - > - x - > - y - > - > Paragraph. - """.toAst(rstOptions = preferRst) == dedent""" - rnMarkdownBlockQuote - rnMarkdownBlockQuoteItem quotationDepth=1 - rnInner - rnBlockQuote - rnBulletList - rnBulletItem - rnInner - rnLeaf 'x' - rnBulletItem - rnInner - rnLeaf 'y' - rnParagraph - rnLeaf 'Paragraph' - rnLeaf '.' - """) - - let expectCodeBlock = dedent""" - rnCodeBlock - [nil] - rnFieldList - rnField - rnFieldName - rnLeaf 'default-language' - rnFieldBody - rnLeaf 'Nim' - rnLiteralBlock - rnLeaf ' - let a = 1 - ```' - """ - - test "Markdown code blocks with more > 3 backticks": - check(dedent""" - ```` - let a = 1 - ``` - ````""".toAst == expectCodeBlock) - - test "Markdown code blocks with ~~~": - check(dedent""" - ~~~ - let a = 1 - ``` - ~~~""".toAst == expectCodeBlock) - check(dedent""" - ~~~~~ - let a = 1 - ``` - ~~~~~""".toAst == expectCodeBlock) - - test "Markdown code blocks with Nim-specific arguments": - check(dedent""" - ```nim number-lines=1 test - let a = 1 - ```""".toAst == - dedent""" - rnCodeBlock - rnDirArg - rnLeaf 'nim' - rnFieldList - rnField - rnFieldName - rnLeaf 'number-lines' - rnFieldBody - rnLeaf '1' - rnField - rnFieldName - rnLeaf 'test' - rnFieldBody - rnLiteralBlock - rnLeaf ' - let a = 1' - """) - - check(dedent""" - ```nim test = "nim c $1" number-lines = 1 - let a = 1 - ```""".toAst == - dedent""" - rnCodeBlock - rnDirArg - rnLeaf 'nim' - rnFieldList - rnField - rnFieldName - rnLeaf 'test' - rnFieldBody - rnLeaf '"nim c $1"' - rnField - rnFieldName - rnLeaf 'number-lines' - rnFieldBody - rnLeaf '1' - rnLiteralBlock - rnLeaf ' - let a = 1' - """) - - test "additional indentation < 4 spaces is handled fine": - check(dedent""" - Indentation - - ```nim - let a = 1 - ```""".toAst == - dedent""" - rnInner - rnParagraph - rnLeaf 'Indentation' - rnParagraph - rnCodeBlock - rnDirArg - rnLeaf 'nim' - [nil] - rnLiteralBlock - rnLeaf ' - let a = 1' - """) - # | | - # | \ indentation of exactly two spaces before 'let a = 1' - - test "no blank line is required before or after Markdown code block": - let inputBacktick = dedent""" - Some text - ``` - CodeBlock() - ``` - Other text""" - let inputTilde = dedent""" - Some text - ~~~~~~~~~ - CodeBlock() - ~~~~~~~~~ - Other text""" - let expected = dedent""" - rnInner - rnParagraph - rnLeaf 'Some' - rnLeaf ' ' - rnLeaf 'text' - rnParagraph - rnCodeBlock - [nil] - rnFieldList - rnField - rnFieldName - rnLeaf 'default-language' - rnFieldBody - rnLeaf 'Nim' - rnLiteralBlock - rnLeaf ' - CodeBlock()' - rnLeaf ' ' - rnLeaf 'Other' - rnLeaf ' ' - rnLeaf 'text' - """ - check inputBacktick.toAst == expected - check inputTilde.toAst == expected - - test "option list has priority over definition list": - for opt in [preferMarkdown, preferRst]: - check(dedent""" - --defusages - file - -o set - """.toAst(rstOptions = opt) == - dedent""" - rnOptionList - rnOptionListItem order=1 - rnOptionGroup - rnLeaf '--' - rnLeaf 'defusages' - rnDescription - rnInner - rnLeaf 'file' - rnOptionListItem order=2 - rnOptionGroup - rnLeaf '-' - rnLeaf 'o' - rnDescription - rnLeaf 'set' - """) - - test "items of 1 option list can be separated by blank lines": - check(dedent""" - -a desc1 - - -b desc2 - """.toAst == - dedent""" - rnOptionList - rnOptionListItem order=1 - rnOptionGroup - rnLeaf '-' - rnLeaf 'a' - rnDescription - rnLeaf 'desc1' - rnOptionListItem order=2 - rnOptionGroup - rnLeaf '-' - rnLeaf 'b' - rnDescription - rnLeaf 'desc2' - """) - - test "definition list does not gobble up the following blocks": - check(dedent""" - defName - defBody - - -b desc2 - """.toAst(rstOptions = preferRst) == - dedent""" - rnInner - rnDefList - rnDefItem - rnDefName - rnLeaf 'defName' - rnDefBody - rnInner - rnLeaf 'defBody' - rnOptionList - rnOptionListItem order=1 - rnOptionGroup - rnLeaf '-' - rnLeaf 'b' - rnDescription - rnLeaf 'desc2' - """) - - test "RST comment": - check(dedent""" - .. comment1 - comment2 - someParagraph""".toAst == - dedent""" - rnLeaf 'someParagraph' - """) - - check(dedent""" - .. - comment1 - comment2 - someParagraph""".toAst == - dedent""" - rnLeaf 'someParagraph' - """) - - test "check that additional line right after .. ends comment": - check(dedent""" - .. - - notAcomment1 - notAcomment2 - someParagraph""".toAst(rstOptions = preferRst) == - dedent""" - rnInner - rnBlockQuote - rnInner - rnLeaf 'notAcomment1' - rnLeaf ' ' - rnLeaf 'notAcomment2' - rnParagraph - rnLeaf 'someParagraph' - """) - - test "check that additional line right after .. ends comment (Markdown mode)": - # in Markdown small indentation does not matter so this should - # just be split to 2 paragraphs. - check(dedent""" - .. - - notAcomment1 - notAcomment2 - someParagraph""".toAst == - dedent""" - rnInner - rnInner - rnLeaf 'notAcomment1' - rnLeaf ' ' - rnLeaf 'notAcomment2' - rnParagraph - rnLeaf 'someParagraph' - """) - - test "but blank lines after 2nd non-empty line don't end the comment": - check(dedent""" - .. - comment1 - - - comment2 - someParagraph""".toAst == - dedent""" - rnLeaf 'someParagraph' - """) - - test "using .. as separator b/w directives and block quotes": - check(dedent""" - .. note:: someNote - - .. - - someBlockQuote""".toAst(rstOptions = preferRst) == - dedent""" - rnInner - rnAdmonition adType=note - [nil] - [nil] - rnLeaf 'someNote' - rnBlockQuote - rnInner - rnLeaf 'someBlockQuote' - """) - - test "no redundant blank lines in literal blocks": - check(dedent""" - Check:: - - - code - - """.toAst(rstOptions = preferRst) == - dedent""" - rnInner - rnLeaf 'Check' - rnLeaf ':' - rnLiteralBlock - rnLeaf 'code' - """) - - test "Markdown indented code blocks": - check(dedent""" - See - - some code""".toAst == - dedent""" - rnInner - rnInner - rnLeaf 'See' - rnLiteralBlock - rnLeaf 'some code' - """) - - # not a code block -- no blank line before: - check(dedent""" - See - some code""".toAst == - dedent""" - rnInner - rnLeaf 'See' - rnLeaf ' ' - rnLeaf 'some' - rnLeaf ' ' - rnLeaf 'code' - """) - -suite "RST tables": - - test "formatting in tables works": - check( - dedent""" - ========= === - `build` `a` - ========= === - """.toAst == - dedent""" - rnTable colCount=2 - rnTableRow - rnTableDataCell - rnInlineCode - rnDirArg - rnLeaf 'nim' - [nil] - rnLiteralBlock - rnLeaf 'build' - rnTableDataCell - rnInlineCode - rnDirArg - rnLeaf 'nim' - [nil] - rnLiteralBlock - rnLeaf 'a' - """) - - test "tables with slightly overflowed cells cause an error (1)": - var error = new string - check( - dedent""" - ====== ====== - Inputs Output - ====== ====== - """.toAst(error=error) == "") - check(error[] == "input(2, 2) Error: Illformed table: " & - "this word crosses table column from the right") - - test "tables with slightly overflowed cells cause an error (2)": - var error = new string - check("" == dedent""" - ===== ===== ====== - Input Output - ===== ===== ====== - False False False - ===== ===== ====== - """.toAst(error=error)) - check(error[] == "input(2, 8) Error: Illformed table: " & - "this word crosses table column from the right") - - test "tables with slightly underflowed cells cause an error": - var error = new string - check("" == dedent""" - ===== ===== ====== - Input Output - ===== ===== ====== - False False False - ===== ===== ====== - """.toAst(error=error)) - check(error[] == "input(2, 7) Error: Illformed table: " & - "this word crosses table column from the left") - - test "tables with unequal underlines should be reported (1)": - var error = new string - error[] = "none" - check("" == dedent""" - ===== ====== - Input Output - ===== ====== - False False - ===== ======= - """.toAst(error=error)) - check(error[] == "input(5, 14) Error: Illformed table: " & - "end of table column #2 should end at position 13") - - test "tables with unequal underlines should be reported (2)": - var error = new string - check("" == dedent""" - ===== ====== - Input Output - ===== ======= - False False - ===== ====== - """.toAst(error=error)) - check(error[] == "input(3, 14) Error: Illformed table: " & - "end of table column #2 should end at position 13") - - test "tables with empty first cells": - check( - dedent""" - = = = - x y z - t - = = = - """.toAst == - dedent""" - rnTable colCount=3 - rnTableRow - rnTableDataCell - rnLeaf 'x' - rnTableDataCell - rnInner - rnLeaf 'y' - rnLeaf ' ' - rnTableDataCell - rnInner - rnLeaf 'z' - rnLeaf ' ' - rnLeaf 't' - """) - - test "tables with spanning cells & separators": - check( - dedent""" - ===== ===== ====== - Inputs Output - ------------ ------ - A B A or B - ===== ===== ====== - False False False - True False True - ----- ----- ------ - False True True - True True True - ===== ===== ====== - """.toAst == - dedent""" - rnTable colCount=3 - rnTableRow - rnTableHeaderCell span=2 - rnLeaf 'Inputs' - rnTableHeaderCell span=1 - rnLeaf 'Output' - rnTableRow endsHeader - rnTableHeaderCell - rnLeaf 'A' - rnTableHeaderCell - rnLeaf 'B' - rnTableHeaderCell - rnInner - rnLeaf 'A' - rnLeaf ' ' - rnLeaf 'or' - rnLeaf ' ' - rnLeaf 'B' - rnTableRow - rnTableDataCell - rnLeaf 'False' - rnTableDataCell - rnLeaf 'False' - rnTableDataCell - rnLeaf 'False' - rnTableRow - rnTableDataCell span=1 - rnLeaf 'True' - rnTableDataCell span=1 - rnLeaf 'False' - rnTableDataCell span=1 - rnLeaf 'True' - rnTableRow - rnTableDataCell - rnLeaf 'False' - rnTableDataCell - rnLeaf 'True' - rnTableDataCell - rnLeaf 'True' - rnTableRow - rnTableDataCell - rnLeaf 'True' - rnTableDataCell - rnLeaf 'True' - rnTableDataCell - rnLeaf 'True' - """) - - test "tables with spanning cells with uneqal underlines cause an error": - var error = new string - check( - dedent""" - ===== ===== ====== - Inputs Output - ------------- ------ - A B A or B - ===== ===== ====== - """.toAst(error=error) == "") - check(error[] == "input(3, 1) Error: Illformed table: " & - "spanning underline does not match main table columns") - - let expTable = dedent""" - rnTable colCount=2 - rnTableRow - rnTableDataCell - rnLeaf 'Inputs' - rnTableDataCell - rnLeaf 'Output' - """ - - test "only tables with `=` columns specs are allowed (1)": - var warnings = new seq[string] - check( - dedent""" - ------ ------ - Inputs Output - ------ ------ - """.toAst(warnings=warnings) == - expTable) - check(warnings[] == - @["input(1, 1) Warning: RST style: " & - "only tables with `=` columns specification are allowed", - "input(3, 1) Warning: RST style: " & - "only tables with `=` columns specification are allowed"]) - - test "only tables with `=` columns specs are allowed (2)": - var warnings = new seq[string] - check( - dedent""" - ====== ====== - Inputs Output - ~~~~~~ ~~~~~~ - """.toAst(warnings=warnings) == - expTable) - check(warnings[] == - @["input(3, 1) Warning: RST style: "& - "only tables with `=` columns specification are allowed"]) - - -suite "RST indentation": - test "nested bullet lists": - let input = dedent """ - * - bullet1 - - bullet2 - * - bullet3 - - bullet4 - """ - let output = input.toAst - check(output == dedent""" - rnBulletList - rnBulletItem - rnBulletList - rnBulletItem - rnInner - rnLeaf 'bullet1' - rnBulletItem - rnInner - rnLeaf 'bullet2' - rnBulletItem - rnBulletList - rnBulletItem - rnInner - rnLeaf 'bullet3' - rnBulletItem - rnInner - rnLeaf 'bullet4' - """) - - test "nested markup blocks": - let input = dedent""" - #) .. Hint:: .. Error:: none - #) .. Warning:: term0 - Definition0 - #) some - paragraph1 - #) term1 - Definition1 - term2 - Definition2 - """ - check(input.toAst(rstOptions = preferRst) == dedent""" - rnEnumList labelFmt=1) - rnEnumItem - rnAdmonition adType=hint - [nil] - [nil] - rnAdmonition adType=error - [nil] - [nil] - rnLeaf 'none' - rnEnumItem - rnAdmonition adType=warning - [nil] - [nil] - rnDefList - rnDefItem - rnDefName - rnLeaf 'term0' - rnDefBody - rnInner - rnLeaf 'Definition0' - rnEnumItem - rnInner - rnLeaf 'some' - rnLeaf ' ' - rnLeaf 'paragraph1' - rnEnumItem - rnDefList - rnDefItem - rnDefName - rnLeaf 'term1' - rnDefBody - rnInner - rnLeaf 'Definition1' - rnDefItem - rnDefName - rnLeaf 'term2' - rnDefBody - rnInner - rnLeaf 'Definition2' - """) - - test "code-block parsing": - let input1 = dedent""" - .. code-block:: nim - :test: "nim c $1" - - template additive(typ: typedesc) = - discard - """ - let input2 = dedent""" - .. code-block:: nim - :test: "nim c $1" - - template additive(typ: typedesc) = - discard - """ - let input3 = dedent""" - .. code-block:: nim - :test: "nim c $1" - template additive(typ: typedesc) = - discard - """ - let inputWrong = dedent""" - .. code-block:: nim - :test: "nim c $1" - - template additive(typ: typedesc) = - discard - """ - let ast = dedent""" - rnCodeBlock - rnDirArg - rnLeaf 'nim' - rnFieldList - rnField - rnFieldName - rnLeaf 'test' - rnFieldBody - rnInner - rnLeaf '"' - rnLeaf 'nim' - rnLeaf ' ' - rnLeaf 'c' - rnLeaf ' ' - rnLeaf '$' - rnLeaf '1' - rnLeaf '"' - rnField - rnFieldName - rnLeaf 'default-language' - rnFieldBody - rnLeaf 'Nim' - rnLiteralBlock - rnLeaf 'template additive(typ: typedesc) = - discard' - """ - check input1.toAst == ast - check input2.toAst == ast - check input3.toAst == ast - # "template..." should be parsed as a definition list attached to ":test:": - check inputWrong.toAst != ast - - test "Markdown definition lists work in conjunction with bullet lists": - check(dedent""" - * some term - : the definition - - Paragraph.""".toAst == - dedent""" - rnInner - rnBulletList - rnBulletItem - rnMdDefList - rnDefItem - rnDefName - rnLeaf 'some' - rnLeaf ' ' - rnLeaf 'term' - rnDefBody - rnInner - rnLeaf 'the' - rnLeaf ' ' - rnLeaf 'definition' - rnParagraph - rnLeaf 'Paragraph' - rnLeaf '.' - """) - - test "Markdown definition lists work with blank lines and extra paragraphs": - check(dedent""" - Term1 - - : Definition1 - - Term2 *inline markup* - - : Definition2 - - Paragraph2 - - Term3 - : * point1 - * point2 - : term3definition2 - """.toAst == dedent""" - rnMdDefList - rnDefItem - rnDefName - rnLeaf 'Term1' - rnDefBody - rnInner - rnLeaf 'Definition1' - rnDefItem - rnDefName - rnLeaf 'Term2' - rnLeaf ' ' - rnEmphasis - rnLeaf 'inline' - rnLeaf ' ' - rnLeaf 'markup' - rnDefBody - rnParagraph - rnLeaf 'Definition2' - rnParagraph - rnLeaf 'Paragraph2' - rnDefItem - rnDefName - rnLeaf 'Term3' - rnDefBody - rnBulletList - rnBulletItem - rnInner - rnLeaf 'point1' - rnBulletItem - rnInner - rnLeaf 'point2' - rnDefBody - rnInner - rnLeaf 'term3definition2' - """) - -suite "Markdown indentation": - test "Markdown paragraph indentation": - # Additional spaces (<=3) of indentation does not break the paragraph. - # TODO: in 2nd case de-indentation causes paragraph to break, this is - # reasonable but does not seem to conform the Markdown spec. - check(dedent""" - Start1 - stop1 - - Start2 - stop2 - """.toAst == - dedent""" - rnInner - rnParagraph - rnLeaf 'Start1' - rnLeaf ' ' - rnLeaf 'stop1' - rnParagraph - rnLeaf 'Start2' - rnParagraph - rnLeaf 'stop2' - rnLeaf ' ' - """) - -suite "Warnings": - test "warnings for broken footnotes/links/substitutions": - let input = dedent""" - firstParagraph - - footnoteRef [som]_ - - link `a broken Link`_ - - substitution |undefined subst| - - link short.link_ - - lastParagraph - """ - var warnings = new seq[string] - let output = input.toAst(rstOptions=preferRst, warnings=warnings) - check(warnings[] == @[ - "input(3, 14) Warning: broken link 'citation-som'", - "input(5, 7) Warning: broken link 'a broken Link'", - "input(7, 15) Warning: unknown substitution 'undefined subst'", - "input(9, 6) Warning: broken link 'short.link'" - ]) - - test "Pandoc Markdown concise link warning points to target": - var warnings = new seq[string] - check( - "ref [here][target]".toAst(warnings=warnings) == - dedent""" - rnInner - rnLeaf 'ref' - rnLeaf ' ' - rnPandocRef - rnInner - rnLeaf 'here' - rnInner - rnLeaf 'target' - """) - check warnings[] == @["input(1, 12) Warning: broken link 'target'"] - - test "With include directive and blank lines at the beginning": - "other.rst".writeFile(dedent""" - - - firstParagraph - - here brokenLink_""") - let input = ".. include:: other.rst" - var warnings = new seq[string] - let output = input.toAst(warnings=warnings) - check warnings[] == @["other.rst(5, 6) Warning: broken link 'brokenLink'"] - check(output == dedent""" - rnInner - rnParagraph - rnLeaf 'firstParagraph' - rnParagraph - rnLeaf 'here' - rnLeaf ' ' - rnRstRef - rnLeaf 'brokenLink' - """) - removeFile("other.rst") - - test "warnings for ambiguous links (references + anchors)": - # Reference like `x`_ generates a link alias x that may clash with others - let input = dedent""" - Manual reference: `foo <#foo,string,string>`_ - - .. _foo: - - Paragraph. - - Ref foo_ - """ - var warnings = new seq[string] - let output = input.toAst(warnings=warnings) - check(warnings[] == @[ - dedent """ - input(7, 5) Warning: ambiguous doc link `foo` - clash: - (3, 8): (manual directive anchor) - (1, 45): (implicitly-generated hyperlink alias)""" - ]) - # reference should be resolved to the manually set anchor: - check(output == - dedent""" - rnInner - rnParagraph - rnLeaf 'Manual' - rnLeaf ' ' - rnLeaf 'reference' - rnLeaf ':' - rnLeaf ' ' - rnHyperlink - rnInner - rnLeaf 'foo' - rnInner - rnLeaf '#foo,string,string' - rnParagraph anchor='foo' - rnLeaf 'Paragraph' - rnLeaf '.' - rnParagraph - rnLeaf 'Ref' - rnLeaf ' ' - rnInternalRef - rnInner - rnLeaf 'foo' - rnLeaf 'foo' - rnLeaf ' ' - """) suite "RST include directive": test "Include whole": "other.rst".writeFile("**test1**") let input = ".. include:: other.rst" - doAssert "test1" == rstToHtml(input, {roSandboxDisabled}, defaultConfig()) + assert "test1" == rstTohtml(input, {}, defaultConfig()) removeFile("other.rst") test "Include starting from": @@ -1420,7 +23,7 @@ OtherStart .. include:: other.rst :start-after: OtherStart """ - check "Visible" == rstToHtml(input, {roSandboxDisabled}, defaultConfig()) + assert "Visible" == rstTohtml(input, {}, defaultConfig()) removeFile("other.rst") test "Include everything before": @@ -1434,7 +37,7 @@ And this should **NOT** be visible in `docs.html` .. include:: other.rst :end-before: OtherEnd """ - doAssert "Visible" == rstToHtml(input, {roSandboxDisabled}, defaultConfig()) + assert "Visible" == rstTohtml(input, {}, defaultConfig()) removeFile("other.rst") @@ -1452,7 +55,7 @@ And this should **NOT** be visible in `docs.html` :start-after: OtherStart :end-before: OtherEnd """ - check "Visible" == rstToHtml(input, {roSandboxDisabled}, defaultConfig()) + assert "Visible" == rstTohtml(input, {}, defaultConfig()) removeFile("other.rst") @@ -1472,360 +75,5 @@ And this should **NOT** be visible in `docs.html` :start-after: OtherStart :end-before: OtherEnd """ - doAssert "Visible" == rstToHtml(input, {roSandboxDisabled}, defaultConfig()) + assert "Visible" == rstTohtml(input, {}, defaultConfig()) removeFile("other.rst") - -suite "RST escaping": - test "backspaces": - check("""\ this""".toAst == dedent""" - rnLeaf 'this' - """) - - check("""\\ this""".toAst == dedent""" - rnInner - rnLeaf '\' - rnLeaf ' ' - rnLeaf 'this' - """) - - check("""\\\ this""".toAst == dedent""" - rnInner - rnLeaf '\' - rnLeaf 'this' - """) - - check("""\\\\ this""".toAst == dedent""" - rnInner - rnLeaf '\' - rnLeaf '\' - rnLeaf ' ' - rnLeaf 'this' - """) - -suite "RST inline markup": - test "* and ** surrounded by spaces are not inline markup": - check("a * b * c ** d ** e".toAst == dedent""" - rnInner - rnLeaf 'a' - rnLeaf ' ' - rnLeaf '*' - rnLeaf ' ' - rnLeaf 'b' - rnLeaf ' ' - rnLeaf '*' - rnLeaf ' ' - rnLeaf 'c' - rnLeaf ' ' - rnLeaf '**' - rnLeaf ' ' - rnLeaf 'd' - rnLeaf ' ' - rnLeaf '**' - rnLeaf ' ' - rnLeaf 'e' - """) - - test "end-string has repeating symbols": - check("*emphasis content****".toAst == dedent""" - rnEmphasis - rnLeaf 'emphasis' - rnLeaf ' ' - rnLeaf 'content' - rnLeaf '***' - """) - - check("""*emphasis content\****""".toAst == dedent""" - rnEmphasis - rnLeaf 'emphasis' - rnLeaf ' ' - rnLeaf 'content' - rnLeaf '*' - rnLeaf '**' - """) # exact configuration of leafs with * is not really essential, - # only total number of * is essential - - check("**strong content****".toAst == dedent""" - rnStrongEmphasis - rnLeaf 'strong' - rnLeaf ' ' - rnLeaf 'content' - rnLeaf '**' - """) - - check("""**strong content*\****""".toAst == dedent""" - rnStrongEmphasis - rnLeaf 'strong' - rnLeaf ' ' - rnLeaf 'content' - rnLeaf '*' - rnLeaf '*' - rnLeaf '*' - """) - - check("``lit content`````".toAst == dedent""" - rnInlineLiteral - rnLeaf 'lit' - rnLeaf ' ' - rnLeaf 'content' - rnLeaf '```' - """) - - test "interpreted text parsing: code fragments": - check(dedent""" - .. default-role:: option - - `--gc:refc`""".toAst == - dedent""" - rnInner - rnDefaultRole - rnDirArg - rnLeaf 'option' - [nil] - [nil] - rnParagraph - rnCodeFragment - rnInner - rnLeaf '--' - rnLeaf 'gc' - rnLeaf ':' - rnLeaf 'refc' - rnLeaf 'option' - """) - - test """interpreted text can be ended with \` """: - let output = (".. default-role:: literal\n" & """`\``""").toAst - check(output.endsWith """ - rnParagraph - rnInlineLiteral - rnLeaf '`'""" & "\n") - - let output2 = """`\``""".toAst - check(output2 == dedent""" - rnInlineCode - rnDirArg - rnLeaf 'nim' - [nil] - rnLiteralBlock - rnLeaf '`' - """) - - let output3 = """`proc \`+\``""".toAst - check(output3 == dedent""" - rnInlineCode - rnDirArg - rnLeaf 'nim' - [nil] - rnLiteralBlock - rnLeaf 'proc `+`' - """) - - check("""`\\`""".toAst == - dedent""" - rnInlineCode - rnDirArg - rnLeaf 'nim' - [nil] - rnLiteralBlock - rnLeaf '\\' - """) - - test "Markdown-style code/backtick": - # no whitespace is required before ` - check("`try`...`except`".toAst == - dedent""" - rnInner - rnInlineCode - rnDirArg - rnLeaf 'nim' - [nil] - rnLiteralBlock - rnLeaf 'try' - rnLeaf '...' - rnInlineCode - rnDirArg - rnLeaf 'nim' - [nil] - rnLiteralBlock - rnLeaf 'except' - """) - - - test """inline literals can contain \ anywhere""": - check("""``\``""".toAst == dedent""" - rnInlineLiteral - rnLeaf '\' - """) - - check("""``\\``""".toAst == dedent""" - rnInlineLiteral - rnLeaf '\' - rnLeaf '\' - """) - - check("""``\```""".toAst == dedent""" - rnInlineLiteral - rnLeaf '\' - rnLeaf '`' - """) - - check("""``\\```""".toAst == dedent""" - rnInlineLiteral - rnLeaf '\' - rnLeaf '\' - rnLeaf '`' - """) - - check("""``\````""".toAst == dedent""" - rnInlineLiteral - rnLeaf '\' - rnLeaf '`' - rnLeaf '`' - """) - - test "references with _ at the end": - check(dedent""" - .. _lnk: https - - lnk_""".toAst == - dedent""" - rnHyperlink - rnInner - rnLeaf 'lnk' - rnInner - rnLeaf 'https' - """) - - test "not a hyper link": - check(dedent""" - .. _lnk: https - - lnk___""".toAst == - dedent""" - rnInner - rnLeaf 'lnk' - rnLeaf '___' - """) - - test "no punctuation in the end of a standalone URI is allowed": - check(dedent""" - [see (http://no.org)], end""".toAst(rstOptions = preferRst) == - dedent""" - rnInner - rnLeaf '[' - rnLeaf 'see' - rnLeaf ' ' - rnLeaf '(' - rnStandaloneHyperlink - rnLeaf 'http://no.org' - rnLeaf ')' - rnLeaf ']' - rnLeaf ',' - rnLeaf ' ' - rnLeaf 'end' - """) - - # but `/` at the end is OK - check( - dedent""" - See http://no.org/ end""".toAst == - dedent""" - rnInner - rnLeaf 'See' - rnLeaf ' ' - rnStandaloneHyperlink - rnLeaf 'http://no.org/' - rnLeaf ' ' - rnLeaf 'end' - """) - - # a more complex URL with some made-up ending '&='. - # Github Markdown would include final &= and - # so would rst2html.py in contradiction with RST spec. - check( - dedent""" - See https://www.google.com/url?sa=t&source=web&cd=&cad=rja&url=https%3A%2F%2Fnim-lang.github.io%2FNim%2Frst.html%23features&usg=AO&= end""".toAst == - dedent""" - rnInner - rnLeaf 'See' - rnLeaf ' ' - rnStandaloneHyperlink - rnLeaf 'https://www.google.com/url?sa=t&source=web&cd=&cad=rja&url=https%3A%2F%2Fnim-lang.github.io%2FNim%2Frst.html%23features&usg=AO' - rnLeaf '&' - rnLeaf '=' - rnLeaf ' ' - rnLeaf 'end' - """) - - test "Markdown-style link can be split to a few lines": - check(dedent""" - is [term-rewriting - macros](manual.html#term-rewriting-macros)""".toAst == - dedent""" - rnInner - rnLeaf 'is' - rnLeaf ' ' - rnHyperlink - rnLeaf 'term-rewriting macros' - rnLeaf 'manual.html#term-rewriting-macros' - """) - - test "URL with balanced parentheses (Markdown rule)": - # 2 balanced parens, 1 unbalanced: - check(dedent""" - https://en.wikipedia.org/wiki/APL_((programming_language)))""".toAst == - dedent""" - rnInner - rnStandaloneHyperlink - rnLeaf 'https://en.wikipedia.org/wiki/APL_((programming_language))' - rnLeaf ')' - """) - - # the same for Markdown-style link: - check(dedent""" - [foo [bar]](https://en.wikipedia.org/wiki/APL_((programming_language))))""".toAst == - dedent""" - rnInner - rnHyperlink - rnLeaf 'foo [bar]' - rnLeaf 'https://en.wikipedia.org/wiki/APL_((programming_language))' - rnLeaf ')' - """) - - # unbalanced (here behavior is more RST-like actually): - check(dedent""" - https://en.wikipedia.org/wiki/APL_(programming_language(""".toAst == - dedent""" - rnInner - rnStandaloneHyperlink - rnLeaf 'https://en.wikipedia.org/wiki/APL_(programming_language' - rnLeaf '(' - """) - - # unbalanced [, but still acceptable: - check(dedent""" - [my {link example](http://example.com/bracket_(symbol_[))""".toAst == - dedent""" - rnHyperlink - rnLeaf 'my {link example' - rnLeaf 'http://example.com/bracket_(symbol_[)' - """) - - test "not a Markdown link": - # bug #17340 (27) `f` will be considered as a protocol and blocked as unsafe - var warnings = new seq[string] - check("[T](f: var Foo)".toAst(warnings = warnings) == - dedent""" - rnInner - rnLeaf '[' - rnLeaf 'T' - rnLeaf ']' - rnLeaf '(' - rnLeaf 'f' - rnLeaf ':' - rnLeaf ' ' - rnLeaf 'var' - rnLeaf ' ' - rnLeaf 'Foo' - rnLeaf ')' - """) - check(warnings[] == @["input(1, 5) Warning: broken link 'f'"]) diff --git a/tests/stdlib/trstgen.nim b/tests/stdlib/trstgen.nim index 8c07b35f0..8fdbf3911 100644 --- a/tests/stdlib/trstgen.nim +++ b/tests/stdlib/trstgen.nim @@ -6,53 +6,7 @@ outputsub: "" import ../../lib/packages/docutils/rstgen import ../../lib/packages/docutils/rst -import unittest, strutils, strtabs -import std/private/miscdollars -import std/assertions - -const - NoSandboxOpts = {roPreferMarkdown, roSupportMarkdown, roNimFile, roSandboxDisabled} - preferMarkdown = {roPreferMarkdown, roSupportMarkdown, roNimFile} - preferRst = {roSupportMarkdown, roNimFile} - -proc toHtml(input: string, - rstOptions: RstParseOptions = preferMarkdown, - error: ref string = nil, - warnings: ref seq[string] = nil): string = - ## If `error` is nil then no errors should be generated. - ## The same goes for `warnings`. - proc testMsgHandler(filename: string, line, col: int, msgkind: MsgKind, - arg: string) = - let mc = msgkind.whichMsgClass - let a = $msgkind % arg - var message: string - toLocation(message, filename, line, col + ColRstOffset) - message.add " $1: $2" % [$mc, a] - if mc == mcError: - if error == nil: - raise newException(EParseError, "[unexpected error] " & message) - error[] = message - # we check only first error because subsequent ones may be meaningless - raise newException(EParseError, "") - else: - doAssert warnings != nil, "unexpected RST warning '" & message & "'" - warnings[].add message - try: - result = rstToHtml(input, rstOptions, defaultConfig(), - msgHandler=testMsgHandler) - except EParseError as e: - if e.msg != "": - result = e.msg - -# inline code tags (for parsing originated from highlite.nim) -proc id(str: string): string = """""" & str & "" -proc op(str: string): string = """""" & str & "" -proc pu(str: string): string = """""" & str & "" -proc optionListLabel(opt: string): string = - """
      """ & - opt & - "
      " - +import unittest suite "YAML syntax highlighting": test "Basics": @@ -67,8 +21,8 @@ suite "YAML syntax highlighting": ? key : value ...""" - let output = input.toHtml({}) - doAssert output == """
      %YAML 1.2
      +    let output = rstTohtml(input, {}, defaultConfig())
      +    assert output == """
      %YAML 1.2
       ---
       a string: string
       a list:
      @@ -93,8 +47,8 @@ suite "YAML syntax highlighting":
           another literal block scalar:
             |+ # comment after header
            allowed, since more indented than parent"""
      -    let output = input.toHtml({})
      -    doAssert output == """
      a literal block scalar: |
      +    let output = rstToHtml(input, {}, defaultConfig())
      +    assert output == """
      a literal block scalar: |
         some text
         # not a comment
        # a comment, since less indented
      @@ -119,8 +73,8 @@ suite "YAML syntax highlighting":
           % not a directive
           ...
           %TAG ! !foo:"""
      -    let output = input.toHtml({})
      -    doAssert output == """
      %YAML 1.2
      +    let output = rstToHtml(input, {}, defaultConfig())
      +    assert output == """
      %YAML 1.2
       ---
       %not a directive
       ...
      @@ -140,8 +94,8 @@ suite "YAML syntax highlighting":
             more numbers: [-783, 11e78],
             not numbers: [ 42e, 0023, +32.37, 8 ball]
           }"""
      -    let output = input.toHtml({})
      -    doAssert output == """
      {
      +    let output = rstToHtml(input, {}, defaultConfig())
      +    assert output == """
      {
         "quoted string": 42,
         'single quoted string': false,
         [ list, "with", 'entries' ]: 73.32e-73,
      @@ -149,25 +103,6 @@ suite "YAML syntax highlighting":
         not numbers: [ 42e, 0023, +32.37, 8 ball]
       }
      """ - test "Directives: warnings": - let input = dedent""" - .. non-existent-warning: Paragraph. - - .. another.wrong:warning::: Paragraph. - """ - var warnings = new seq[string] - let output = input.toHtml(warnings=warnings) - check output == "" - doAssert warnings[].len == 2 - check "(1, 24) Warning: RST style:" in warnings[0] - check "double colon :: may be missing at end of 'non-existent-warning'" in warnings[0] - check "(3, 25) Warning: RST style:" in warnings[1] - check "RST style: too many colons for a directive (should be ::)" in warnings[1] - - test "not a directive": - let input = "..warning:: I am not a warning." - check input.toHtml == input - test "Anchors, Aliases, Tags": let input = """.. code-block:: yaml --- !!map @@ -176,8 +111,8 @@ suite "YAML syntax highlighting": : !localtag foo alias: *anchor """ - let output = input.toHtml({}) - doAssert output == """
      --- !!map
      +    let output = rstToHtml(input, {}, defaultConfig())
      +    assert output == """
      --- !!map
       !!str string: !<tag:yaml.org,2002:int> 42
       ? &anchor !!seq []:
       : !localtag foo
      @@ -196,8 +131,8 @@ suite "YAML syntax highlighting":
           example.com/not/a#comment:
             ?not a map key
           """
      -    let output = input.toHtml({})
      -    doAssert output == """
      ...
      +    let output = rstToHtml(input, {}, defaultConfig())
      +    assert output == """
      ...
        %a string:
         a:string:not:a:map
       ...
      @@ -209,1483 +144,12 @@ suite "YAML syntax highlighting":
         ?not a map key
      """ -suite "RST/Markdown general": - test "RST emphasis": - doAssert rstToHtml("*Hello* **world**!", {}, - newStringTable(modeStyleInsensitive)) == - "Hello world!" - test "Markdown links": - check("(( [Nim](https://nim-lang.org/) ))".toHtml == - """(( Nim ))""") - check("(([Nim](https://nim-lang.org/)))".toHtml == - """((Nim))""") - check("[[Nim](https://nim-lang.org/)]".toHtml == - """[Nim]""") - - test "Markdown tables": - let input1 = """ -| A1 header | A2 \| not fooled -| :--- | ----: | -| C1 | C2 **bold** | ignored | -| D1 `code \|` | D2 | also ignored -| E1 \| text | -| | F2 without pipe -not in table""" - let output1 = input1.toHtml - #[ - TODO: `\|` inside a table cell should render as `|` - `|` outside a table cell should render as `\|` - consistently with markdown, see https://stackoverflow.com/a/66557930/1426932 - ]# - check(output1 == """ - - - - - -
      A1 headerA2 | not fooled
      C1C2 bold
      D1 """ & id"code" & " " & op"\|" & """D2
      E1 | text
      F2 without pipe

      not in table

      """) - let input2 = """ -| A1 header | A2 | -| --- | --- |""" - let output2 = input2.toHtml - doAssert output2 == """ -
      A1 headerA2
      """ - - test "RST tables": - let input1 = """ -Test 2 column/4 rows table: -==== === -H0 H1 -==== === -A0 A1 -==== === -A2 A3 -==== === -A4 A5 -==== === """ - let output1 = rstToLatex(input1, {}) - doAssert "{LL}" in output1 # 2 columns - doAssert count(output1, "\\\\") == 4 # 4 rows - for cell in ["H0", "H1", "A0", "A1", "A2", "A3", "A4", "A5"]: - doAssert cell in output1 - - let input2 = """ -Now test 3 columns / 2 rows, and also borders containing 4 =, 3 =, 1 = signs: - -==== === = -H0 H1 H -==== === = -A0 A1 X - Ax Y -==== === = """ - let output2 = rstToLatex(input2, {}) - doAssert "{LLL}" in output2 # 3 columns - doAssert count(output2, "\\\\") == 2 # 2 rows - for cell in ["H0", "H1", "H", "A0", "A1", "X", "Ax", "Y"]: - doAssert cell in output2 - - - test "RST adornments": - let input1 = """ -Check that a few punctuation symbols are not parsed as adornments: -:word1: word2 .... word3 """ - let output1 = input1.toHtml - discard output1 - - test "RST sections": - let input1 = """ -Long chapter name -''''''''''''''''''' -""" - let output1 = input1.toHtml - doAssert "Long chapter name" in output1 and "Some chapter" in output6 - - # check that overline and underline match - let input7 = dedent """ - ------------ - Some chapter - ----------- - """ - var error7 = new string - let output7 = input7.toHtml(error=error7) - check(error7[] == "input(1, 1) Error: new section expected (underline " & - "\'-----------\' does not match overline \'------------\')") - - let input8 = dedent """ - ----------- - Overflow - ----------- - """ - var error8 = new string - let output8 = input8.toHtml(error=error8) - check(error8[] == "input(1, 1) Error: new section expected (overline " & - "\'-----------\' is too short)") - - # check that hierarchy of title styles works - let input9good = dedent """ - Level1 - ====== - - Level2 - ------ - - Level3 - ~~~~~~ - - L1 - == - - Another2 - -------- - - More3 - ~~~~~ - - """ - let output9good = input9good.toHtml(preferRst) - doAssert "

      Level1

      " in output9good - doAssert "

      Level2

      " in output9good - doAssert "

      Level3

      " in output9good - doAssert "

      L1

      " in output9good - doAssert "

      Another2

      " in output9good - doAssert "

      More3

      " in output9good - - # check that swap causes an exception - let input9Bad = dedent """ - Level1 - ====== - - Level2 - ------ - - Level3 - ~~~~~~ - - L1 - == - - More - ~~~~ - - Another - ------- - - """ - var error9Bad = new string - let output9Bad = input9Bad.toHtml(preferRst, error=error9Bad) - check(error9Bad[] == "input(15, 1) Error: new section expected (section " & - "level inconsistent: underline ~~~~~ unexpectedly found, while " & - "the following intermediate section level(s) are missing on " & - "lines 12..15: underline -----)") - - test "RST sections overline": - # the same as input9good but with overline headings - # first overline heading has a special meaning: document title - let input = dedent """ - ====== - Title0 - ====== - - +++++++++ - SubTitle0 - +++++++++ - - ------ - Level1 - ------ - - Level2 - ------ - - ~~~~~~ - Level3 - ~~~~~~ - - -- - L1 - -- - - Another2 - -------- - - ~~~~~ - More3 - ~~~~~ - - """ - var rstGenera: RstGenerator - var output: string - let (rst, files, _) = rstParse(input, "", 1, 1, {}) - rstGenera.initRstGenerator(outHtml, defaultConfig(), "input", filenames = files) - rstGenera.renderRstToOut(rst, output) - doAssert rstGenera.meta[metaTitle] == "Title0" - doAssert rstGenera.meta[metaSubtitle] == "SubTitle0" - doAssert "

      Level1

      " in output - doAssert "

      Level2

      " in output - doAssert "

      Level3

      " in output - doAssert "

      L1

      " in output - doAssert "

      Another2

      " in output - doAssert "

      More3

      " in output - - test "RST sections overline 2": - # check that a paragraph prevents interpreting overlines as document titles - let input = dedent """ - Paragraph - - ====== - Title0 - ====== - - +++++++++ - SubTitle0 - +++++++++ - """ - var rstGenera: RstGenerator - var output: string - let (rst, files, _) = rstParse(input, "", 1, 1, {}) - rstGenera.initRstGenerator(outHtml, defaultConfig(), "input", filenames=files) - rstGenera.renderRstToOut(rst, output) - doAssert rstGenera.meta[metaTitle] == "" - doAssert rstGenera.meta[metaSubtitle] == "" - doAssert "

      Title0

      " in output - doAssert "

      SubTitle0

      " in output - - test "RST+Markdown sections": - # check that RST and Markdown headings don't interfere - let input = dedent """ - ====== - Title0 - ====== - - MySection1a - +++++++++++ - - # MySection1b - - MySection1c - +++++++++++ - - ##### MySection5a - - MySection2a - ----------- - """ - var rstGenera: RstGenerator - var output: string - let (rst, files, _) = rstParse(input, "", 1, 1, {roSupportMarkdown}) - rstGenera.initRstGenerator(outHtml, defaultConfig(), "input", filenames=files) - rstGenera.renderRstToOut(rst, output) - doAssert rstGenera.meta[metaTitle] == "Title0" - doAssert rstGenera.meta[metaSubtitle] == "" - doAssert output == - "\n

      MySection1a

      " & # RST - "\n

      MySection1b

      " & # Markdown - "\n

      MySection1c

      " & # RST - "\n
      MySection5a
      " & # Markdown - "\n

      MySection2a

      " # RST - - test "RST inline text": - let input1 = "GC_step" - let output1 = input1.toHtml - doAssert output1 == "GC_step" - - test "RST anchors/links to headings": - # Currently in TOC mode anchors are modified (for making links from - # the TOC unique) - let inputNoToc = dedent""" - Type relations - ============== - - Convertible relation - -------------------- - - Ref. `Convertible relation`_ - """ - let outputNoToc = inputNoToc.toHtml - check outputNoToc.count("id=\"type-relations\"") == 1 - check outputNoToc.count("id=\"convertible-relation\"") == 1 - check outputNoToc.count("href=\"#convertible-relation\"") == 1 - - let inputTocCases = @[ - dedent""" - .. contents:: - - Type relations - ============== - - Convertible relation - -------------------- - - Ref. `Convertible relation`_ - - Guards and locks - ================ - """, - dedent""" - Ref. `Convertible relation`_ - - .. contents:: - - Type relations - ============== - - Convertible relation - -------------------- - - Guards and locks - ================ - """ - ] - for inputToc in inputTocCases: - let outputToc = inputToc.toHtml - check outputToc.count("id=\"type-relations\"") == 1 - check outputToc.count("id=\"type-relations-convertible-relation\"") == 1 - check outputToc.count("id=\"convertible-relation\">") == 0 - # Besides "Ref.", heading also contains link to itself: - check outputToc.count( - "href=\"#type-relations-convertible-relation\">") == 2 - check outputToc.count("href=\"#convertible-relation\"") == 0 - - test "RST links": - let input1 = """ -Want to learn about `my favorite programming language`_? - -.. _my favorite programming language: https://nim-lang.org""" - let output1 = input1.toHtml - doAssert "" in output1 - - test "Markdown code block": - let input1 = """ -``` -let x = 1 -``` """ - let output1 = input1.toHtml({roSupportMarkdown, roPreferMarkdown}) - doAssert """" & - id"foo" & op"." & id"bar" & "") - check("""`foo\`\`bar`""".toHtml == - """""" & - id"foo" & pu"`" & pu"`" & id"bar" & "") - check("""`foo\`bar`""".toHtml == - """""" & - id"foo" & pu"`" & id"bar" & "") - check("""`\`bar`""".toHtml == - """""" & - pu"`" & id"bar" & "") - check("""`a\b\x\\ar`""".toHtml == - """""" & - id"a" & op"""\""" & id"b" & op"""\""" & id"x" & op"""\\""" & id"ar" & - "") - - test "inline literal": - check """``foo.bar``""".toHtml == """foo.bar""" - check """``foo\bar``""".toHtml == """foo\bar""" - check """``f\`o\\o\b`ar``""".toHtml == """f\`o\\o\b`ar""" - - test "default-role": - # nim(default) -> literal -> nim -> code(=literal) - let input = dedent""" - Par1 `value1`. - - .. default-role:: literal - - Par2 `value2`. - - .. default-role:: nim - - Par3 `value3`. - - .. default-role:: code - - Par4 `value4`.""" - let p1 = """Par1 """ & id"value1" & "." - let p2 = """

      Par2 value2.

      """ - let p3 = """

      Par3 """ & id"value3" & ".

      " - let p4 = """

      Par4 value4.

      """ - let expected = p1 & p2 & "\n" & p3 & "\n" & p4 - check( - input.toHtml(NoSandboxOpts) == expected - ) - - test "role directive": - let input = dedent""" - .. role:: y(code) - :language: yaml - - .. role:: brainhelp(code) - :language: brainhelp - """ - var warnings = new seq[string] - let output = input.toHtml( - NoSandboxOpts, - warnings=warnings - ) - check(warnings[].len == 1 and "language 'brainhelp' not supported" in warnings[0]) - - test "RST comments": - let input1 = """ - -Check that comment disappears: - -.. - some comment """ - let output1 = input1.toHtml - doAssert output1 == "Check that comment disappears:" - - test "RST line blocks + headings": - let input = """ -===== -Test1 -===== - -| -| -| line block -| other line - -""" - var rstGenera: RstGenerator - var output: string - let (rst, files, _) = rstParse(input, "", 1, 1, {}) - rstGenera.initRstGenerator(outHtml, defaultConfig(), "input", filenames=files) - rstGenera.renderRstToOut(rst, output) - doAssert rstGenera.meta[metaTitle] == "Test1" - # check that title was not overwritten to '|' - doAssert output == "



      line block
      other line

      " - let output1l = rstToLatex(input, {}) - doAssert "line block\n\n" in output1l - doAssert "other line\n\n" in output1l - doAssert output1l.count("\\vspace") == 2 + 2 # +2 surrounding paddings - - test "RST line blocks": - let input2 = dedent""" - Paragraph1 - - | - - Paragraph2""" - - let output2 = input2.toHtml - doAssert "Paragraph1


      Paragraph2

      " == output2 - - let input3 = dedent""" - | xxx - | yyy - | zzz""" - - let output3 = input3.toHtml - doAssert "xxx
      " in output3 - doAssert "yyy
      " in output3 - doAssert "zzz
      " in output3 - - # check that '| ' with a few spaces is still parsed as new line - let input4 = dedent""" - | xxx - | - | zzz""" - - let output4 = input4.toHtml - doAssert "xxx

      " in output4 - doAssert "zzz
      " in output4 - - test "RST enumerated lists": - let input1 = dedent """ - 1. line1 - 1 - 2. line2 - 2 - - 3. line3 - 3 - - - 4. line4 - 4 - - - - 5. line5 - 5 - """ - let output1 = input1.toHtml - for i in 1..5: - doAssert ($i & ". line" & $i) notin output1 - doAssert ("
    • line" & $i & " " & $i & "
    • ") in output1 - - let input2 = dedent """ - 3. line3 - - 4. line4 - - - 5. line5 - - - - 7. line7 - - - - - 8. line8 - """ - let output2 = input2.toHtml - for i in [3, 4, 5, 7, 8]: - doAssert ($i & ". line" & $i) notin output2 - doAssert ("
    • line" & $i & "
    • ") in output2 - - # check that nested enumerated lists work - let input3 = dedent """ - 1. a) string1 - 2. string2 - """ - let output3 = input3.toHtml - doAssert count(output3, "
        ") == 2 - doAssert "
      1. string1
      2. " in output3 and "
      3. string2
      4. " in output3 - - let input4 = dedent """ - Check that enumeration specifiers are respected - - 9. string1 - 10. string2 - 12. string3 - - b) string4 - c) string5 - e) string6 - """ - let output4 = input4.toHtml - doAssert count(output4, "
          ") == 4 - for enumerator in [9, 12]: - doAssert "start=\"$1\"" % [$enumerator] in output4 - for enumerator in [2, 5]: # 2=b, 5=e - doAssert "start=\"$1\"" % [$enumerator] in output4 - - let input5 = dedent """ - Check that auto-numbered enumeration lists work. - - #. string1 - - #. string2 - - #. string3 - - #) string5 - #) string6 - """ - let output5 = input5.toHtml - doAssert count(output5, "
            ") == 2 - doAssert count(output5, "
          1. ") == 5 - - let input5a = dedent """ - Auto-numbered RST list can start with 1 even when Markdown support is on. - - 1. string1 - #. string2 - #. string3 - """ - let output5a = input5a.toHtml - doAssert count(output5a, "
              ") == 1 - doAssert count(output5a, "
            1. ") == 3 - - let input6 = dedent """ - ... And for alphabetic enumerators too! - - b. string1 - #. string2 - #. string3 - """ - let output6 = input6.toHtml - doAssert count(output6, "
                ") == 1 - doAssert count(output6, "
              1. ") == 3 - doAssert "start=\"2\"" in output6 and "class=\"loweralpha simple\"" in output6 - - let input7 = dedent """ - ... And for uppercase alphabetic enumerators. - - C. string1 - #. string2 - #. string3 - """ - let output7 = input7.toHtml - doAssert count(output7, "
                  ") == 1 - doAssert count(output7, "
                1. ") == 3 - doAssert "start=\"3\"" in output7 and "class=\"upperalpha simple\"" in output7 - - # check that it's not recognized as enum.list without indentation on 2nd line - let input8 = dedent """ - Paragraph. - - A. stringA - B. stringB - C. string1 - string2 - """ - var warnings8 = new seq[string] - let output8 = input8.toHtml(warnings = warnings8) - check(warnings8[].len == 1) - check("input(6, 1) Warning: RST style: \n" & - "not enough indentation on line 6" in warnings8[0]) - doAssert output8 == "Paragraph.
                    " & - "
                  1. stringA
                  2. \n
                  3. stringB
                  4. \n
                  \n

                  C. string1 string2

                  " - - test "Markdown enumerated lists": - let input1 = dedent """ - Below are 2 enumerated lists: Markdown-style (5 items) and RST (1 item) - 1. line1 - 1. line2 - 1. line3 - 1. line4 - - 1. line5 - - #. lineA - """ - let output1 = input1.toHtml - for i in 1..5: - doAssert ($i & ". line" & $i) notin output1 - doAssert ("
                2. line" & $i & "
                3. ") in output1 - doAssert count(output1, "
                    ") == 2 - - test "RST bullet lists": - let input1 = dedent """ - * line1 - 1 - * line2 - 2 - - * line3 - 3 - - - * line4 - 4 - - - - * line5 - 5 - """ - let output1 = input1.toHtml - for i in 1..5: - doAssert ("
                  1. line" & $i & " " & $i & "
                  2. ") in output1 - doAssert count(output1, "
                      ") == 1 - - test "Nim RST footnotes and citations": - # check that auto-label footnote enumerated properly after a manual one - let input1 = dedent """ - .. [1] Body1. - .. [#note] Body2 - - Ref. [#note]_ - """ - let output1 = input1.toHtml(preferRst) - doAssert output1.count(">[1]") == 1 - doAssert output1.count(">[2]") == 2 - doAssert "href=\"#footnote-note\"" in output1 - doAssert ">[-1]" notin output1 - doAssert "Body1." in output1 - doAssert "Body2" in output1 - - # check that there are NO footnotes/citations, only comments: - let input2 = dedent """ - .. [1 #] Body1. - .. [# note] Body2. - .. [wrong citation] That gives you a comment. - - .. [not&allowed] That gives you a comment. - - Not references[#note]_[1 #]_ [wrong citation]_ and [not&allowed]_. - """ - let output2 = input2.toHtml(preferRst) - doAssert output2 == "Not references[#note]_[1 #]_ [wrong citation]_ and [not&allowed]_." - - # check that auto-symbol footnotes work: - let input3 = dedent """ - Ref. [*]_ and [*]_ and [*]_. - - .. [*] Body1 - .. [*] Body2. - - - .. [*] Body3. - .. [*] Body4 - - And [*]_. - """ - let output3 = input3.toHtml(preferRst) - # both references and footnotes. Footnotes have link to themselves. - doAssert output3.count("href=\"#footnotesym-1\">[*]") == 2 - doAssert output3.count("href=\"#footnotesym-2\">[**]") == 2 - doAssert output3.count("href=\"#footnotesym-3\">[***]") == 2 - doAssert output3.count("href=\"#footnotesym-4\">[^]") == 2 - # footnote group - doAssert output3.count("
                      " & - "
                      ") == 1 - # footnotes - doAssert output3.count("
                      " & - "[*]
                      ") == 1 - doAssert output3.count("
                      " & - "[**]
                      ") == 1 - doAssert output3.count("
                      " & - "[***]
                      ") == 1 - doAssert output3.count("
                      " & - "[^]
                      ") == 1 - for i in 1 .. 4: doAssert ("Body" & $i) in output3 - - # check manual, auto-number and auto-label footnote enumeration - let input4 = dedent """ - .. [3] Manual1. - .. [#] Auto-number1. - .. [#mylabel] Auto-label1. - .. [#note] Auto-label2. - .. [#] Auto-number2. - - Ref. [#note]_ and [#]_ and [#]_. - """ - let output4 = input4.toHtml(preferRst) - doAssert ">[-1]" notin output1 - let order = @[ - "footnote-3", "[3]", "Manual1.", - "footnoteauto-1", "[1]", "Auto-number1", - "footnote-mylabel", "[2]", "Auto-label1", - "footnote-note", "[4]", "Auto-label2", - "footnoteauto-2", "[5]", "Auto-number2", - ] - for i in 0 .. order.len-2: - let pos1 = output4.find(order[i]) - let pos2 = output4.find(order[i+1]) - doAssert pos1 >= 0 - doAssert pos2 >= 0 - doAssert pos1 < pos2 - - # forgot [#]_ - let input5 = dedent """ - .. [3] Manual1. - .. [#] Auto-number1. - .. [#note] Auto-label2. - - Ref. [#note]_ - """ - var error5 = new string - let output5 = input5.toHtml(preferRst, error=error5) - check(error5[] == "input(1, 1) Error: mismatch in number of footnotes " & - "and their refs: 1 (lines 2) != 0 (lines ) for auto-numbered " & - "footnotes") - - # extra [*]_ - let input6 = dedent """ - Ref. [*]_ - - .. [*] Auto-Symbol. - - Ref. [*]_ - """ - var error6 = new string - let output6 = input6.toHtml(preferRst, error=error6) - check(error6[] == "input(1, 1) Error: mismatch in number of footnotes " & - "and their refs: 1 (lines 3) != 2 (lines 2, 6) for auto-symbol " & - "footnotes") - - let input7 = dedent """ - .. [Some:CITATION-2020] Citation. - - Ref. [some:citation-2020]_. - """ - let output7 = input7.toHtml(preferRst) - doAssert output7.count("href=\"#citation-somecoloncitationminus2020\"") == 2 - doAssert output7.count("[Some:CITATION-2020]") == 1 - doAssert output7.count("[some:citation-2020]") == 1 - doAssert output3.count("
                      " & - "
                      ") == 1 - - let input8 = dedent """ - .. [Some] Citation. - - Ref. [som]_. - """ - var warnings8 = new seq[string] - let output8 = input8.toHtml(preferRst, warnings=warnings8) - check(warnings8[] == @["input(3, 7) Warning: broken link 'citation-som'"]) - - # check that footnote group does not break parsing of other directives: - let input9 = dedent """ - .. [Some] Citation. - - .. _`internal anchor`: - - .. [Another] Citation. - .. just comment. - .. [Third] Citation. - - Paragraph1. - - Paragraph2 ref `internal anchor`_. - """ - let output9 = input9.toHtml - # _`internal anchor` got erased: - check "href=\"#internal-anchor\"" notin output9 - check "href=\"#citation-another\"" in output9 - doAssert output9.count("
                      " & - "
                      ") == 1 - doAssert output9.count("
                      ") == 3 - doAssert "just comment" notin output9 - - # check that nested citations/footnotes work - let input10 = dedent """ - Paragraph1 [#]_. - - .. [First] Citation. - - .. [#] Footnote. - - .. [Third] Citation. - """ - let output10 = input10.toHtml(preferRst) - doAssert output10.count("
                      " & - "
                      ") == 3 - doAssert output10.count("
                      ") == 3 - doAssert "[First]" in output10 - doAssert "[1]" in output10 - doAssert "[Third]" in output10 - - let input11 = ".. [note]\n" # should not crash - let output11 = input11.toHtml - doAssert "[note]" in output11 - - # check that references to auto-numbered footnotes work - let input12 = dedent """ - Ref. [#]_ and [#]_ STOP. - - .. [#] Body1. - .. [#] Body3 - .. [2] Body2. - """ - let output12 = input12.toHtml(preferRst) - let orderAuto = @[ - "#footnoteauto-1", "[1]", - "#footnoteauto-2", "[3]", - "STOP.", - "Body1.", "Body3", "Body2." - ] - for i in 0 .. orderAuto.len-2: - let pos1 = output12.find(orderAuto[i]) - let pos2 = output12.find(orderAuto[i+1]) - doAssert pos1 >= 0 - doAssert pos2 >= 0 - doAssert pos1 < pos2 - - test "Nim (RST extension) code-block": - # check that presence of fields doesn't consume the following text as - # its code (which is a literal block) - let input0 = dedent """ - .. code-block:: nim - :number-lines: 0 - - Paragraph1""" - let output0 = input0.toHtml - doAssert "

                      Paragraph1

                      " in output0 - - test "Nim code-block :number-lines:": - let input = dedent """ - .. code-block:: nim - :number-lines: 55 - - x - y - """ - check "
                      55\n56\n
                      " in input.toHtml - - test "Nim code-block indentation": - let input = dedent """ - .. code-block:: nim - :number-lines: 55 - - x - """ - let output = input.toHtml - check "
                      55\n
                      " in output - check "x" in output - - test "Nim code-block indentation": - let input = dedent """ - .. code-block:: nim - :number-lines: 55 - let a = 1 - """ - var error = new string - let output = input.toHtml(error=error) - check(error[] == "input(2, 3) Error: invalid field: " & - "extra arguments were given to number-lines: ' let a = 1'") - check "" == output - - test "code-block warning": - let input = dedent """ - .. code:: Nim - :unsupportedField: anything - - .. code:: unsupportedLang - - anything - - ```anotherLang - someCode - ``` - """ - let warnings = new seq[string] - let output = input.toHtml(warnings=warnings) - check(warnings[] == @[ - "input(2, 4) Warning: field 'unsupportedField' not supported", - "input(4, 11) Warning: language 'unsupportedLang' not supported", - "input(8, 4) Warning: language 'anotherLang' not supported" - ]) - check(output == "
                      anything
                      " & - "

                      \nsomeCode

                      ") - - test "RST admonitions": - # check that all admonitions are implemented - let input0 = dedent """ - .. admonition:: endOf admonition - .. attention:: endOf attention - .. caution:: endOf caution - .. danger:: endOf danger - .. error:: endOf error - .. hint:: endOf hint - .. important:: endOf important - .. note:: endOf note - .. tip:: endOf tip - .. warning:: endOf warning - """ - let output0 = input0.toHtml( - NoSandboxOpts - ) - for a in ["admonition", "attention", "caution", "danger", "error", "hint", - "important", "note", "tip", "warning" ]: - doAssert "endOf " & a & "
                      " in output0 - - # Test that admonition does not swallow up the next paragraph. - let input1 = dedent """ - .. error:: endOfError - - Test paragraph. - """ - let output1 = input1.toHtml( - NoSandboxOpts - ) - doAssert "endOfError
                      " in output1 - doAssert "

                      Test paragraph.

                      " in output1 - doAssert "class=\"admonition admonition-error\"" in output1 - - # Test that second line is parsed as continuation of the first line. - let input2 = dedent """ - .. error:: endOfError - Test2p. - - Test paragraph. - """ - let output2 = input2.toHtml( - NoSandboxOpts - ) - doAssert "endOfError Test2p.
                      " in output2 - doAssert "

                      Test paragraph.

                      " in output2 - doAssert "class=\"admonition admonition-error\"" in output2 - - let input3 = dedent """ - .. note:: endOfNote - """ - let output3 = input3.toHtml( - NoSandboxOpts - ) - doAssert "endOfNote
                      " in output3 - doAssert "class=\"admonition admonition-info\"" in output3 - - test "RST internal links": - let input1 = dedent """ - Start. - - .. _target000: - - Paragraph. - - .. _target001: - - * bullet list - * Y - - .. _target002: - - 1. enumeration list - 2. Y - - .. _target003: - - term 1 - Definition list 1. - - .. _target004: - - | line block - - .. _target005: - - :a: field list value - - .. _target006: - - -a option description - - .. _target007: - - :: - - Literal block - - .. _target008: - - Doctest blocks are not implemented. - - .. _target009: - - block quote - - .. _target010: - - ===== ===== ======= - A B A and B - ===== ===== ======= - False False False - ===== ===== ======= - - .. _target100: - - .. CAUTION:: admonition - - .. _target101: - - .. code:: nim - - const pi = 3.14 - - .. _target102: - - .. code-block:: - - const pi = 3.14 - - Paragraph2. - - .. _target202: - - ---- - - That was a transition. - """ - let output1 = input1.toHtml( - preferRst - ) - doAssert "

                      target300" in output2 - doAssert "href=\"#subsectiona\">target301" in output2 - doAssert "href=\"#citation-cit2020\">target103" in output2 - - let output2l = rstToLatex(input2, {}) - doAssert "\\label{section-xyz}\\hypertarget{section-xyz}{}" in output2l - doAssert "\\hyperlink{section-xyz}{target300}" in output2l - doAssert "\\hyperlink{subsectiona}{target301}" in output2l - - test "RST internal links (inline)": - let input1 = dedent """ - Paragraph with _`some definition`. - - Ref. `some definition`_. - """ - let output1 = input1.toHtml - doAssert "some definition" in output1 - doAssert "Ref. some definition" in output1 - - test "RST references (additional symbols)": - # check that ., _, -, +, : are allowed symbols in references without ` ` - let input1 = dedent """ - sec.1 - ----- - - 2-other:sec+c_2 - ^^^^^^^^^^^^^^^ - - .. _link.1_2021: - - Paragraph - - Ref. sec.1_! and 2-other:sec+c_2_;and link.1_2021_. - """ - let output1 = input1.toHtml - doAssert "id=\"secdot1\"" in output1 - doAssert "id=\"Z2minusothercolonsecplusc-2\"" in output1 - check "id=\"linkdot1-2021\"" in output1 - let ref1 = "sec.1" - let ref2 = "2-other:sec+c_2" - let ref3 = "link.1_2021" - let refline = "Ref. " & ref1 & "! and " & ref2 & ";and " & ref3 & "." - doAssert refline in output1 - - test "Option lists 1": - # check that "* b" is not consumed by previous bullet item because of - # incorrect indentation handling in option lists - let input = dedent """ - * a - -m desc - -n very long - desc - * b""" - let output = input.toHtml - check(output.count("") == 2) - check(output.count("

                      desc
                      """ in - output) - check(optionListLabel("-n") & - """
                      very long desc
                      """ in - output) - - test "Option lists 2": - # check that 2nd option list is not united with the 1st - let input = dedent """ - * a - -m desc - -n very long - desc - -d option""" - let output = input.toHtml - check(output.count("desc
    """ in - output) - check(optionListLabel("-n") & - """
    very long desc
    """ in - output) - check(optionListLabel("-d") & - """
    option
    """ in - output) - check "

    option

    " notin output - - test "Option list 3 (double /)": - let input = dedent """ - * a - //compile compile1 - //doc doc1 - cont - -d option""" - let output = input.toHtml - check(output.count("compile1""" in - output) - check(optionListLabel("doc") & - """
    doc1 cont
    """ in - output) - check(optionListLabel("-d") & - """
    option
    """ in - output) - check "

    option

    " notin output - - test "Roles: subscript prefix/postfix": - let expected = "See some text." - check "See :subscript:`some text`.".toHtml == expected - check "See `some text`:subscript:.".toHtml == expected - - test "Roles: correct parsing from beginning of line": - let expected = "3He is an isotope of helium." - check """:superscript:`3`\ He is an isotope of helium.""".toHtml == expected - check """:sup:`3`\ He is an isotope of helium.""".toHtml == expected - check """`3`:sup:\ He is an isotope of helium.""".toHtml == expected - check """`3`:superscript:\ He is an isotope of helium.""".toHtml == expected - - test "Roles: warnings": - let input = dedent""" - See function :py:func:`spam`. - - See also `egg`:py:class:. - """ - var warnings = new seq[string] - let output = input.toHtml(warnings=warnings) - doAssert warnings[].len == 2 - check "(1, 14) Warning: " in warnings[0] - check "language 'py:func' not supported" in warnings[0] - check "(3, 15) Warning: " in warnings[1] - check "language 'py:class' not supported" in warnings[1] - check("""

    See function spam.

    """ & "\n" & - """

    See also egg.

    """ == - output) - - test "(not) Roles: check escaping 1": - let expected = """See :subscript:""" & - """""" & id"some" & " " & id"text" & - "." - check """See \:subscript:`some text`.""".toHtml == expected - check """See :subscript\:`some text`.""".toHtml == expected - - test "(not) Roles: check escaping 2": - check("""See :subscript:\`some text\`.""".toHtml == - "See :subscript:`some text`.") - - test "Field list": - check(":field: text".toHtml == - """""" & - """""" & - """""" & - """""" & "\n
    field:text
    ") - - test "Field list: body after newline": - let output = dedent""" - :field: - text1""".toHtml - check "field:" in output - check "" in output - - test "Field list (incorrect)": - check ":field:text".toHtml == ":field:text" - -suite "RST/Code highlight": - test "Basic Python code highlight": - let pythonCode = """ - .. code-block:: python - - def f_name(arg=42): - print(f"{arg}") - - """ - - let expected = """

    def f_name(arg=42): - print(f"{arg}")

    """ - - check strip(rstToHtml(pythonCode, {}, newStringTable(modeCaseSensitive))) == - strip(expected) - - -suite "invalid targets": - test "invalid image target": - let input1 = dedent """.. image:: /images/myimage.jpg - :target: https://bar.com - :alt: Alt text for the image""" - let output1 = input1.toHtml - check output1 == """Alt text for the image""" - - let input2 = dedent """.. image:: /images/myimage.jpg - :target: javascript://bar.com - :alt: Alt text for the image""" - let output2 = input2.toHtml - check output2 == """Alt text for the image""" - - let input3 = dedent """.. image:: /images/myimage.jpg - :target: bar.com - :alt: Alt text for the image""" - let output3 = input3.toHtml - check output3 == """Alt text for the image""" - - test "invalid links": - check("(([Nim](https://nim-lang.org/)))".toHtml == - """((Nim))""") - # unknown protocol is treated just like plain text, not a link - var warnings = new seq[string] - check("(([Nim](javascript://nim-lang.org/)))".toHtml(warnings=warnings) == - """(([Nim](javascript://nim-lang.org/)))""") - check(warnings[] == @["input(1, 9) Warning: broken link 'javascript'"]) - warnings[].setLen 0 - check("`Nim `_".toHtml(warnings=warnings) == - """Nim <javascript://nim-lang.org/>""") - check(warnings[] == @["input(1, 33) Warning: broken link 'javascript'"]) - -suite "local file inclusion": - test "cannot include files in sandboxed mode": - var error = new string - discard ".. include:: ./readme.md".toHtml(error=error) - check(error[] == "input(1, 11) Error: disabled directive: 'include'") - - test "code-block file directive is disabled": - var error = new string - discard ".. code-block:: nim\n :file: ./readme.md".toHtml(error=error) - check(error[] == "input(2, 20) Error: disabled directive: 'file'") - - test "code-block file directive is disabled - Markdown": - var error = new string - discard "```nim file = ./readme.md\n```".toHtml(error=error) - check(error[] == "input(1, 23) Error: disabled directive: 'file'") - -proc documentToHtml*(doc: string, isMarkdown: bool = false): string {.gcsafe.} = - var options = {roSupportMarkdown} - if isMarkdown: - options.incl roPreferMarkdown - result = rstToHtml(doc, options, defaultConfig()) + let + a = rstToHtml("(( [Nim](https://nim-lang.org/) ))", {roSupportMarkdown}, defaultConfig()) + b = rstToHtml("(([Nim](https://nim-lang.org/)))", {roSupportMarkdown}, defaultConfig()) + c = rstToHtml("[[Nim](https://nim-lang.org/)]", {roSupportMarkdown}, defaultConfig()) + + assert a == """(( Nim ))""" + assert b == """((Nim))""" + assert c == """[Nim]""" diff --git a/tests/stdlib/tsequtils.nim b/tests/stdlib/tsequtils.nim deleted file mode 100644 index 176c00214..000000000 --- a/tests/stdlib/tsequtils.nim +++ /dev/null @@ -1,541 +0,0 @@ -discard """ - targets: "c js" -""" - -# xxx move all tests under `main` - -import std/sequtils -import strutils -from algorithm import sorted -import std/assertions - -{.experimental: "strictEffects".} -{.push warningAsError[Effect]: on.} -{.experimental: "strictFuncs".} - -# helper for testing double substitution side effects which are handled -# by `evalOnceAs` -var counter = 0 -proc identity[T](a: T): auto = - counter.inc - a - -block: # concat test - let - s1 = @[1, 2, 3] - s2 = @[4, 5] - s3 = @[6, 7] - total = concat(s1, s2, s3) - doAssert total == @[1, 2, 3, 4, 5, 6, 7] - -block: # count test - let - s1 = @[1, 2, 3, 2] - s2 = @['a', 'b', 'x', 'a'] - a1 = [1, 2, 3, 2] - a2 = ['a', 'b', 'x', 'a'] - r0 = count(s1, 0) - r1 = count(s1, 1) - r2 = count(s1, 2) - r3 = count(s2, 'y') - r4 = count(s2, 'x') - r5 = count(s2, 'a') - ar0 = count(a1, 0) - ar1 = count(a1, 1) - ar2 = count(a1, 2) - ar3 = count(a2, 'y') - ar4 = count(a2, 'x') - ar5 = count(a2, 'a') - doAssert r0 == 0 - doAssert r1 == 1 - doAssert r2 == 2 - doAssert r3 == 0 - doAssert r4 == 1 - doAssert r5 == 2 - doAssert ar0 == 0 - doAssert ar1 == 1 - doAssert ar2 == 2 - doAssert ar3 == 0 - doAssert ar4 == 1 - doAssert ar5 == 2 - -block: # cycle tests - let - a = @[1, 2, 3] - b: seq[int] = @[] - c = [1, 2, 3] - - doAssert a.cycle(3) == @[1, 2, 3, 1, 2, 3, 1, 2, 3] - doAssert a.cycle(0) == @[] - #doAssert a.cycle(-1) == @[] # will not compile! - doAssert b.cycle(3) == @[] - doAssert c.cycle(3) == @[1, 2, 3, 1, 2, 3, 1, 2, 3] - doAssert c.cycle(0) == @[] - -block: # repeat tests - doAssert repeat(10, 5) == @[10, 10, 10, 10, 10] - doAssert repeat(@[1, 2, 3], 2) == @[@[1, 2, 3], @[1, 2, 3]] - doAssert repeat([1, 2, 3], 2) == @[[1, 2, 3], [1, 2, 3]] - -block: # deduplicates test - let - dup1 = @[1, 1, 3, 4, 2, 2, 8, 1, 4] - dup2 = @["a", "a", "c", "d", "d"] - dup3 = [1, 1, 3, 4, 2, 2, 8, 1, 4] - dup4 = ["a", "a", "c", "d", "d"] - unique1 = deduplicate(dup1) - unique2 = deduplicate(dup2) - unique3 = deduplicate(dup3) - unique4 = deduplicate(dup4) - unique5 = deduplicate(dup1.sorted, true) - unique6 = deduplicate(dup2, true) - unique7 = deduplicate(dup3.sorted, true) - unique8 = deduplicate(dup4, true) - doAssert unique1 == @[1, 3, 4, 2, 8] - doAssert unique2 == @["a", "c", "d"] - doAssert unique3 == @[1, 3, 4, 2, 8] - doAssert unique4 == @["a", "c", "d"] - doAssert unique5 == @[1, 2, 3, 4, 8] - doAssert unique6 == @["a", "c", "d"] - doAssert unique7 == @[1, 2, 3, 4, 8] - doAssert unique8 == @["a", "c", "d"] - -block: # zip test - let - short = @[1, 2, 3] - long = @[6, 5, 4, 3, 2, 1] - words = @["one", "two", "three"] - ashort = [1, 2, 3] - along = [6, 5, 4, 3, 2, 1] - awords = ["one", "two", "three"] - zip1 = zip(short, long) - zip2 = zip(short, words) - zip3 = zip(ashort, along) - doAssert zip1 == @[(1, 6), (2, 5), (3, 4)] - doAssert zip2 == @[(1, "one"), (2, "two"), (3, "three")] - doAssert zip3 == @[(1, 6), (2, 5), (3, 4)] - doAssert zip1[2][1] == 4 - doAssert zip2[2][1] == "three" - doAssert zip3[2][1] == 4 - when (NimMajor, NimMinor) <= (1, 0): - let - # In Nim 1.0.x and older, zip returned a seq of tuple strictly - # with fields named "a" and "b". - zipAb = zip(ashort, awords) - doAssert zipAb == @[(a: 1, b: "one"), (2, "two"), (3, "three")] - doAssert zipAb[2].b == "three" - else: - let - # As zip returns seq of anonymous tuples, they can be assigned - # to any variable that's a sequence of named tuples too. - zipXy: seq[tuple[x: int, y: string]] = zip(ashort, awords) - zipMn: seq[tuple[m: int, n: string]] = zip(ashort, words) - doAssert zipXy == @[(x: 1, y: "one"), (2, "two"), (3, "three")] - doAssert zipMn == @[(m: 1, n: "one"), (2, "two"), (3, "three")] - doAssert zipXy[2].y == "three" - doAssert zipMn[2].n == "three" - -block: # distribute tests - let numbers = @[1, 2, 3, 4, 5, 6, 7] - doAssert numbers.distribute(3) == @[@[1, 2, 3], @[4, 5], @[6, 7]] - doAssert numbers.distribute(6)[0] == @[1, 2] - doAssert numbers.distribute(6)[5] == @[7] - let a = @[1, 2, 3, 4, 5, 6, 7] - doAssert a.distribute(1, true) == @[@[1, 2, 3, 4, 5, 6, 7]] - doAssert a.distribute(1, false) == @[@[1, 2, 3, 4, 5, 6, 7]] - doAssert a.distribute(2, true) == @[@[1, 2, 3, 4], @[5, 6, 7]] - doAssert a.distribute(2, false) == @[@[1, 2, 3, 4], @[5, 6, 7]] - doAssert a.distribute(3, true) == @[@[1, 2, 3], @[4, 5], @[6, 7]] - doAssert a.distribute(3, false) == @[@[1, 2, 3], @[4, 5, 6], @[7]] - doAssert a.distribute(4, true) == @[@[1, 2], @[3, 4], @[5, 6], @[7]] - doAssert a.distribute(4, false) == @[@[1, 2], @[3, 4], @[5, 6], @[7]] - doAssert a.distribute(5, true) == @[@[1, 2], @[3, 4], @[5], @[6], @[7]] - doAssert a.distribute(5, false) == @[@[1, 2], @[3, 4], @[5, 6], @[7], @[]] - doAssert a.distribute(6, true) == @[@[1, 2], @[3], @[4], @[5], @[6], @[7]] - doAssert a.distribute(6, false) == @[ - @[1, 2], @[3, 4], @[5, 6], @[7], @[], @[]] - doAssert a.distribute(8, false) == a.distribute(8, true) - doAssert a.distribute(90, false) == a.distribute(90, true) - var b = @[0] - for f in 1 .. 25: b.add(f) - doAssert b.distribute(5, true)[4].len == 5 - doAssert b.distribute(5, false)[4].len == 2 - -block: # map test - let - numbers = @[1, 4, 5, 8, 9, 7, 4] - anumbers = [1, 4, 5, 8, 9, 7, 4] - m1 = map(numbers, proc(x: int): int = 2*x) - m2 = map(anumbers, proc(x: int): int = 2*x) - doAssert m1 == @[2, 8, 10, 16, 18, 14, 8] - doAssert m2 == @[2, 8, 10, 16, 18, 14, 8] - -block: # apply test - var a = @["1", "2", "3", "4"] - apply(a, proc(x: var string) = x &= "42") - doAssert a == @["142", "242", "342", "442"] - -block: # filter proc test - let - colors = @["red", "yellow", "black"] - acolors = ["red", "yellow", "black"] - f1 = filter(colors, proc(x: string): bool = x.len < 6) - f2 = filter(colors) do (x: string) -> bool: x.len > 5 - f3 = filter(acolors, proc(x: string): bool = x.len < 6) - f4 = filter(acolors) do (x: string) -> bool: x.len > 5 - doAssert f1 == @["red", "black"] - doAssert f2 == @["yellow"] - doAssert f3 == @["red", "black"] - doAssert f4 == @["yellow"] - -block: # filter iterator test - let numbers = @[1, 4, 5, 8, 9, 7, 4] - let anumbers = [1, 4, 5, 8, 9, 7, 4] - doAssert toSeq(filter(numbers, proc (x: int): bool = x mod 2 == 0)) == - @[4, 8, 4] - doAssert toSeq(filter(anumbers, proc (x: int): bool = x mod 2 == 0)) == - @[4, 8, 4] - -block: # keepIf test - var floats = @[13.0, 12.5, 5.8, 2.0, 6.1, 9.9, 10.1] - keepIf(floats, proc(x: float): bool = x > 10) - doAssert floats == @[13.0, 12.5, 10.1] - -block: # insert tests - var dest = @[1, 1, 1, 1, 1, 1, 1, 1] - let - src = @[2, 2, 2, 2, 2, 2] - outcome = @[1, 1, 1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1] - dest.insert(src, 3) - doAssert dest == outcome, """\ - Inserting [2,2,2,2,2,2] into [1,1,1,1,1,1,1,1] - at 3 is [1,1,1,2,2,2,2,2,2,1,1,1,1,1]""" - -block: # filterIt test - let - temperatures = @[-272.15, -2.0, 24.5, 44.31, 99.9, -113.44] - acceptable = filterIt(temperatures, it < 50 and it > -10) - notAcceptable = filterIt(temperatures, it > 50 or it < -10) - doAssert acceptable == @[-2.0, 24.5, 44.31] - doAssert notAcceptable == @[-272.15, 99.9, -113.44] - -block: # keepItIf test - var candidates = @["foo", "bar", "baz", "foobar"] - keepItIf(candidates, it.len == 3 and it[0] == 'b') - doAssert candidates == @["bar", "baz"] - -block: # all - let - numbers = @[1, 4, 5, 8, 9, 7, 4] - anumbers = [1, 4, 5, 8, 9, 7, 4] - len0seq: seq[int] = @[] - doAssert all(numbers, proc (x: int): bool = return x < 10) == true - doAssert all(numbers, proc (x: int): bool = return x < 9) == false - doAssert all(len0seq, proc (x: int): bool = return false) == true - doAssert all(anumbers, proc (x: int): bool = return x < 10) == true - doAssert all(anumbers, proc (x: int): bool = return x < 9) == false - -block: # allIt - let - numbers = @[1, 4, 5, 8, 9, 7, 4] - anumbers = [1, 4, 5, 8, 9, 7, 4] - len0seq: seq[int] = @[] - doAssert allIt(numbers, it < 10) == true - doAssert allIt(numbers, it < 9) == false - doAssert allIt(len0seq, false) == true - doAssert allIt(anumbers, it < 10) == true - doAssert allIt(anumbers, it < 9) == false - -block: # any - let - numbers = @[1, 4, 5, 8, 9, 7, 4] - anumbers = [1, 4, 5, 8, 9, 7, 4] - len0seq: seq[int] = @[] - doAssert any(numbers, proc (x: int): bool = return x > 8) == true - doAssert any(numbers, proc (x: int): bool = return x > 9) == false - doAssert any(len0seq, proc (x: int): bool = return true) == false - doAssert any(anumbers, proc (x: int): bool = return x > 8) == true - doAssert any(anumbers, proc (x: int): bool = return x > 9) == false - -block: # anyIt - let - numbers = @[1, 4, 5, 8, 9, 7, 4] - anumbers = [1, 4, 5, 8, 9, 7, 4] - len0seq: seq[int] = @[] - doAssert anyIt(numbers, it > 8) == true - doAssert anyIt(numbers, it > 9) == false - doAssert anyIt(len0seq, true) == false - doAssert anyIt(anumbers, it > 8) == true - doAssert anyIt(anumbers, it > 9) == false - -block: # toSeq test - block: - let - numeric = @[1, 2, 3, 4, 5, 6, 7, 8, 9] - oddNumbers = toSeq(filter(numeric) do (x: int) -> bool: - if x mod 2 == 1: - result = true) - doAssert oddNumbers == @[1, 3, 5, 7, 9] - - block: - doAssert [1, 2].toSeq == @[1, 2] - doAssert @[1, 2].toSeq == @[1, 2] - - doAssert @[1, 2].toSeq == @[1, 2] - doAssert toSeq(@[1, 2]) == @[1, 2] - - block: - iterator myIter(seed: int): auto = - for i in 0.. arr[j]: let tmp = arr[i] arr[i] = arr[j] @@ -77,7 +77,7 @@ block t5349: const fn = "file9char.txt" writeFile(fn, "123456789") - var f = syncio.open(fn) + var f = system.open(fn) echo getFileSize(f) var line = newString(10) diff --git a/tests/stdlib/tstdlib_various.nim b/tests/stdlib/tstdlib_various.nim index ce9c9a7c5..d1723df78 100644 --- a/tests/stdlib/tstdlib_various.nim +++ b/tests/stdlib/tstdlib_various.nim @@ -1,5 +1,4 @@ discard """ -matrix: "--mm:refc" output: ''' abc def @@ -21,6 +20,12 @@ Hi Andreas! How do you feel, Rumpf? @[0, 2, 1] @[0, 1, 2] 055this should be the casehugh@["(", "+", " 1", " 2", ")"] +caught a crash! +caught a crash! +caught a crash! +caught a crash! +caught a crash! +caught a crash! [5] [4, 5] [3, 4, 5] @@ -33,9 +38,9 @@ true """ import - std/[critbits, sets, strutils, tables, random, algorithm, re, ropes, - segfaults, lists, parsesql, streams, os, htmlgen, xmltree, strtabs] -import std/[syncio, assertions] + critbits, sets, strutils, tables, random, algorithm, re, ropes, segfaults, + lists, parsesql, streams, os, htmlgen, xmltree, strtabs + block tcritbits: var r: CritBitTree[void] @@ -55,15 +60,15 @@ block tcritbits: block testequivalence: - doAssert(toHashSet(@[1,2,3]) <= toHashSet(@[1,2,3,4]), "equivalent or subset") - doAssert(toHashSet(@[1,2,3]) <= toHashSet(@[1,2,3]), "equivalent or subset") - doAssert((not(toHashSet(@[1,2,3]) <= toHashSet(@[1,2]))), "equivalent or subset") - doAssert(toHashSet(@[1,2,3]) <= toHashSet(@[1,2,3,4]), "strict subset") - doAssert((not(toHashSet(@[1,2,3]) < toHashSet(@[1,2,3]))), "strict subset") - doAssert((not(toHashSet(@[1,2,3]) < toHashSet(@[1,2]))), "strict subset") - doAssert((not(toHashSet(@[1,2,3]) == toHashSet(@[1,2,3,4]))), "==") - doAssert(toHashSet(@[1,2,3]) == toHashSet(@[1,2,3]), "==") - doAssert((not(toHashSet(@[1,2,3]) == toHashSet(@[1,2]))), "==") + doAssert(toSet(@[1,2,3]) <= toSet(@[1,2,3,4]), "equivalent or subset") + doAssert(toSet(@[1,2,3]) <= toSet(@[1,2,3]), "equivalent or subset") + doAssert((not(toSet(@[1,2,3]) <= toSet(@[1,2]))), "equivalent or subset") + doAssert(toSet(@[1,2,3]) <= toSet(@[1,2,3,4]), "strict subset") + doAssert((not(toSet(@[1,2,3]) < toSet(@[1,2,3]))), "strict subset") + doAssert((not(toSet(@[1,2,3]) < toSet(@[1,2]))), "strict subset") + doAssert((not(toSet(@[1,2,3]) == toSet(@[1,2,3,4]))), "==") + doAssert(toSet(@[1,2,3]) == toSet(@[1,2,3]), "==") + doAssert((not(toSet(@[1,2,3]) == toSet(@[1,2]))), "==") @@ -156,21 +161,18 @@ block tropes: block tsegfaults: - when not defined(arm64): - var crashes = 0 - proc main = + proc main = + try: + var x: ptr int + echo x[] try: - var x: ptr int - echo x[] - try: - raise newException(ValueError, "not a crash") - except ValueError: - discard - except NilAccessDefect: - inc crashes - for i in 0..5: - main() - assert crashes == 6 + raise newException(ValueError, "not a crash") + except ValueError: + discard + except NilAccessError: + echo "caught a crash!" + for i in 0..5: + main() @@ -210,7 +212,7 @@ block tsplit2: try: discard "hello".split("") echo "false" - except AssertionDefect: + except AssertionError: echo "true" diff --git a/tests/stdlib/tstrbasics.nim b/tests/stdlib/tstrbasics.nim deleted file mode 100644 index 9a624fec3..000000000 --- a/tests/stdlib/tstrbasics.nim +++ /dev/null @@ -1,103 +0,0 @@ -discard """ - targets: "c cpp js" - matrix: "--gc:refc; --gc:arc" -""" - -import std/[strbasics, sugar, assertions] - -template strip2(input: string, args: varargs[untyped]): untyped = - var a = input - when varargsLen(args) > 0: - strip(a, args) - else: - strip(a) - a - -proc main() = - block: # strip - block: # bug #17173 - var a = " vhellov " - strip(a) - doAssert a == "vhellov" - - doAssert strip2(" vhellov ") == "vhellov" - doAssert strip2(" vhellov ", leading = false) == " vhellov" - doAssert strip2(" vhellov ", trailing = false) == "vhellov " - doAssert strip2("vhellov", chars = {'v'}) == "hello" - doAssert strip2("vhellov", leading = false, chars = {'v'}) == "vhello" - doAssert strip2("blaXbla", chars = {'b', 'a'}) == "laXbl" - doAssert strip2("blaXbla", chars = {'b', 'a', 'l'}) == "X" - doAssert strip2("xxxxxx", chars={'x'}) == "" - doAssert strip2("x", chars={'x'}) == "" - doAssert strip2("x", chars={'1'}) == "x" - doAssert strip2("", chars={'x'}) == "" - doAssert strip2("xxx xxx", chars={'x'}) == " " - doAssert strip2("xxx wind", chars={'x'}) == " wind" - doAssert strip2("xxx iii", chars={'i'}) == "xxx " - - block: - var a = "xxx iii" - doAssert a.dup(strip(chars = {'i'})) == "xxx " - doAssert a.dup(strip(chars = {' '})) == "xxx iii" - doAssert a.dup(strip(chars = {'x'})) == " iii" - doAssert a.dup(strip(chars = {'x', ' '})) == "iii" - doAssert a.dup(strip(chars = {'x', 'i'})) == " " - doAssert a.dup(strip(chars = {'x', 'i', ' '})).len == 0 - - block: - var a = "x i" - doAssert a.dup(strip(chars = {'i'})) == "x " - doAssert a.dup(strip(chars = {' '})) == "x i" - doAssert a.dup(strip(chars = {'x'})) == " i" - doAssert a.dup(strip(chars = {'x', ' '})) == "i" - doAssert a.dup(strip(chars = {'x', 'i'})) == " " - doAssert a.dup(strip(chars = {'x', 'i', ' '})).len == 0 - - block: - var a = "" - doAssert a.dup(strip(chars = {'i'})).len == 0 - doAssert a.dup(strip(chars = {' '})).len == 0 - doAssert a.dup(strip(chars = {'x'})).len == 0 - doAssert a.dup(strip(chars = {'x', ' '})).len == 0 - doAssert a.dup(strip(chars = {'x', 'i'})).len == 0 - doAssert a.dup(strip(chars = {'x', 'i', ' '})).len == 0 - - block: - var a = " " - doAssert a.dup(strip(chars = {'i'})) == " " - doAssert a.dup(strip(chars = {' '})).len == 0 - doAssert a.dup(strip(chars = {'x'})) == " " - doAssert a.dup(strip(chars = {'x', ' '})).len == 0 - doAssert a.dup(strip(chars = {'x', 'i'})) == " " - doAssert a.dup(strip(chars = {'x', 'i', ' '})).len == 0 - - block: # setSlice - var a = "Hello, Nim!" - doAssert a.dup(setSlice(7 .. 9)) == "Nim" - doAssert a.dup(setSlice(0 .. 0)) == "H" - doAssert a.dup(setSlice(0 .. 1)) == "He" - doAssert a.dup(setSlice(0 .. 10)) == a - doAssert a.dup(setSlice(1 .. 0)).len == 0 - doAssert a.dup(setSlice(20 .. -1)).len == 0 - - doAssertRaises(AssertionDefect): - discard a.dup(setSlice(-1 .. 1)) - - doAssertRaises(AssertionDefect): - discard a.dup(setSlice(1 .. 11)) - - block: # add - var a0 = "hi" - var b0 = "foobar" - when nimvm: - discard # pending bug #15952 - else: - a0.add b0.toOpenArray(1,3) - doAssert a0 == "hioob" - proc fn(c: openArray[char]): string = - result.add c - doAssert fn("def") == "def" - doAssert fn(['d','\0', 'f'])[2] == 'f' - -static: main() -main() diff --git a/tests/stdlib/tstreams.nim b/tests/stdlib/tstreams.nim index 891b38e20..559824d85 100644 --- a/tests/stdlib/tstreams.nim +++ b/tests/stdlib/tstreams.nim @@ -1,22 +1,17 @@ discard """ - matrix: "--gc:refc; --gc:arc" - input: "Arne" - output: ''' +input: "Arne" +output: ''' Hello! What is your name? Nice name: Arne fs is: nil + threw exception -_heh_ -''' - nimout: ''' -I -AM -GROOT ''' +disabled: "windows" """ -import std/[syncio, streams, assertions] +import streams block tstreams: @@ -41,63 +36,5 @@ block tstreams2: block tstreams3: try: var fs = openFileStream("shouldneverexist.txt") - except IOError: + except IoError: echo "threw exception" - - static: - var s = newStringStream("I\nAM\nGROOT") - for line in s.lines: - echo line - s.close - - -block: - let fs = newFileStream("amissingfile.txt") - defer: fs.close() - doAssert isNil(fs) - -# bug #12410 - -var a = newStringStream "hehohihahuhyh" -a.readDataStrImpl = nil - -var buffer = "_ooo_" - -doAssert a.readDataStr(buffer, 1..3) == 3 - -echo buffer - - -block: - var ss = newStringStream("The quick brown fox jumped over the lazy dog.\nThe lazy dog ran") - doAssert(ss.getPosition == 0) - doAssert(ss.peekStr(5) == "The q") - doAssert(ss.getPosition == 0) # haven't moved - doAssert(ss.readStr(5) == "The q") - doAssert(ss.getPosition == 5) # did move - doAssert(ss.peekLine() == "uick brown fox jumped over the lazy dog.") - doAssert(ss.getPosition == 5) # haven't moved - var str = newString(100) - doAssert(ss.peekLine(str)) - doAssert(str == "uick brown fox jumped over the lazy dog.") - doAssert(ss.getPosition == 5) # haven't moved - # bug #19707 - Ensure we dont error with writing over literals on arc/orc - ss.setPosition(0) - ss.write("hello") - ss.setPosition(0) - doAssert(ss.peekStr(5) == "hello") - -# bug #19716 -static: # Ensure streams it doesnt break with nimscript on arc/orc #19716 - let s = newStringStream("a") - doAssert s.data == "a" - -template main = - var strm = newStringStream("abcde") - var buffer = "12345" - doAssert strm.readDataStr(buffer, 0..3) == 4 - doAssert buffer == "abcd5" - strm.close() - -static: main() -main() diff --git a/tests/stdlib/tstreams2.nim b/tests/stdlib/tstreams2.nim new file mode 100644 index 000000000..70f0bac32 --- /dev/null +++ b/tests/stdlib/tstreams2.nim @@ -0,0 +1,12 @@ +discard """ + output: '''fs is: nil''' +""" +import streams +var + fs = newFileStream("amissingfile.txt") + line = "" +echo "fs is: ",repr(fs) +if not isNil(fs): + while fs.readLine(line): + echo line + fs.close() diff --git a/tests/stdlib/tstreams3.nim b/tests/stdlib/tstreams3.nim new file mode 100644 index 000000000..89f45f275 --- /dev/null +++ b/tests/stdlib/tstreams3.nim @@ -0,0 +1,20 @@ +discard """ + output: "threw exception" + nimout: ''' +I +AM +GROOT +''' +""" +import streams + +try: + var fs = openFileStream("shouldneverexist.txt") +except IoError: + echo "threw exception" + +static: + var s = newStringStream("I\nAM\nGROOT") + for line in s.lines: + echo line + s.close diff --git a/tests/stdlib/tstrformat.nim b/tests/stdlib/tstrformat.nim index d332e8375..403372aed 100644 --- a/tests/stdlib/tstrformat.nim +++ b/tests/stdlib/tstrformat.nim @@ -1,565 +1,175 @@ -# xxx: test js target +discard """ +action: "run" +output: '''Received (name: "Foo", species: "Bar")''' +""" + +# issue #7632 import genericstrformat -import std/[strformat, strutils, times, tables, json] -import std/[assertions, formatfloat] -import std/objectdollar +doAssert works(5) == "formatted 5" +doAssert fails0(6) == "formatted 6" +doAssert fails(7) == "formatted 7" +doAssert fails2[0](8) == "formatted 8" -proc main() = - block: # issue #7632 - doAssert works(5) == "formatted 5" - doAssert fails0(6) == "formatted 6" - doAssert fails(7) == "formatted 7" - doAssert fails2[0](8) == "formatted 8" +# other tests - block: # other tests - type Obj = object +import strformat - proc `$`(o: Obj): string = "foobar" +type Obj = object - # for custom types, formatValue needs to be overloaded. - template formatValue(result: var string; value: Obj; specifier: string) = - result.formatValue($value, specifier) +proc `$`(o: Obj): string = "foobar" - var o: Obj - doAssert fmt"{o}" == "foobar" - doAssert fmt"{o:10}" == "foobar " +# for custom types, formatValue needs to be overloaded. +template formatValue(result: var string; value: Obj; specifier: string) = + result.formatValue($value, specifier) - doAssert fmt"{o=}" == "o=foobar" - doAssert fmt"{o=:10}" == "o=foobar " +var o: Obj +doAssert fmt"{o}" == "foobar" +doAssert fmt"{o:10}" == "foobar " - block: # see issue #7933 - var str = "abc" - doAssert fmt">7.1 :: {str:>7.1}" == ">7.1 :: a" - doAssert fmt">7.2 :: {str:>7.2}" == ">7.2 :: ab" - doAssert fmt">7.3 :: {str:>7.3}" == ">7.3 :: abc" - doAssert fmt">7.9 :: {str:>7.9}" == ">7.9 :: abc" - doAssert fmt">7.0 :: {str:>7.0}" == ">7.0 :: " - doAssert fmt" 7.1 :: {str:7.1}" == " 7.1 :: a " - doAssert fmt" 7.2 :: {str:7.2}" == " 7.2 :: ab " - doAssert fmt" 7.3 :: {str:7.3}" == " 7.3 :: abc " - doAssert fmt" 7.9 :: {str:7.9}" == " 7.9 :: abc " - doAssert fmt" 7.0 :: {str:7.0}" == " 7.0 :: " - doAssert fmt"^7.1 :: {str:^7.1}" == "^7.1 :: a " - doAssert fmt"^7.2 :: {str:^7.2}" == "^7.2 :: ab " - doAssert fmt"^7.3 :: {str:^7.3}" == "^7.3 :: abc " - doAssert fmt"^7.9 :: {str:^7.9}" == "^7.9 :: abc " - doAssert fmt"^7.0 :: {str:^7.0}" == "^7.0 :: " +# see issue #7933 +var str = "abc" +doAssert fmt">7.1 :: {str:>7.1}" == ">7.1 :: a" +doAssert fmt">7.2 :: {str:>7.2}" == ">7.2 :: ab" +doAssert fmt">7.3 :: {str:>7.3}" == ">7.3 :: abc" +doAssert fmt">7.9 :: {str:>7.9}" == ">7.9 :: abc" +doAssert fmt">7.0 :: {str:>7.0}" == ">7.0 :: " +doAssert fmt" 7.1 :: {str:7.1}" == " 7.1 :: a " +doAssert fmt" 7.2 :: {str:7.2}" == " 7.2 :: ab " +doAssert fmt" 7.3 :: {str:7.3}" == " 7.3 :: abc " +doAssert fmt" 7.9 :: {str:7.9}" == " 7.9 :: abc " +doAssert fmt" 7.0 :: {str:7.0}" == " 7.0 :: " +doAssert fmt"^7.1 :: {str:^7.1}" == "^7.1 :: a " +doAssert fmt"^7.2 :: {str:^7.2}" == "^7.2 :: ab " +doAssert fmt"^7.3 :: {str:^7.3}" == "^7.3 :: abc " +doAssert fmt"^7.9 :: {str:^7.9}" == "^7.9 :: abc " +doAssert fmt"^7.0 :: {str:^7.0}" == "^7.0 :: " +str = "äöüe\u0309\u0319o\u0307\u0359" +doAssert fmt"^7.1 :: {str:^7.1}" == "^7.1 :: ä " +doAssert fmt"^7.2 :: {str:^7.2}" == "^7.2 :: äö " +doAssert fmt"^7.3 :: {str:^7.3}" == "^7.3 :: äöü " +doAssert fmt"^7.0 :: {str:^7.0}" == "^7.0 :: " +# this is actually wrong, but the unicode module has no support for graphemes +doAssert fmt"^7.4 :: {str:^7.4}" == "^7.4 :: äöüe " +doAssert fmt"^7.9 :: {str:^7.9}" == "^7.9 :: äöüe\u0309\u0319o\u0307\u0359" - doAssert fmt">7.1 :: {str=:>7.1}" == ">7.1 :: str= a" - doAssert fmt">7.2 :: {str=:>7.2}" == ">7.2 :: str= ab" - doAssert fmt">7.3 :: {str=:>7.3}" == ">7.3 :: str= abc" - doAssert fmt">7.9 :: {str=:>7.9}" == ">7.9 :: str= abc" - doAssert fmt">7.0 :: {str=:>7.0}" == ">7.0 :: str= " - doAssert fmt" 7.1 :: {str=:7.1}" == " 7.1 :: str=a " - doAssert fmt" 7.2 :: {str=:7.2}" == " 7.2 :: str=ab " - doAssert fmt" 7.3 :: {str=:7.3}" == " 7.3 :: str=abc " - doAssert fmt" 7.9 :: {str=:7.9}" == " 7.9 :: str=abc " - doAssert fmt" 7.0 :: {str=:7.0}" == " 7.0 :: str= " - doAssert fmt"^7.1 :: {str=:^7.1}" == "^7.1 :: str= a " - doAssert fmt"^7.2 :: {str=:^7.2}" == "^7.2 :: str= ab " - doAssert fmt"^7.3 :: {str=:^7.3}" == "^7.3 :: str= abc " - doAssert fmt"^7.9 :: {str=:^7.9}" == "^7.9 :: str= abc " - doAssert fmt"^7.0 :: {str=:^7.0}" == "^7.0 :: str= " - str = "äöüe\u0309\u0319o\u0307\u0359" - doAssert fmt"^7.1 :: {str:^7.1}" == "^7.1 :: ä " - doAssert fmt"^7.2 :: {str:^7.2}" == "^7.2 :: äö " - doAssert fmt"^7.3 :: {str:^7.3}" == "^7.3 :: äöü " - doAssert fmt"^7.0 :: {str:^7.0}" == "^7.0 :: " +# see issue #7932 +doAssert fmt"{15:08}" == "00000015" # int, works +doAssert fmt"{1.5:08}" == "000001.5" # float, works +doAssert fmt"{1.5:0>8}" == "000001.5" # workaround using fill char works for positive floats +doAssert fmt"{-1.5:0>8}" == "0000-1.5" # even that does not work for negative floats +doAssert fmt"{-1.5:08}" == "-00001.5" # works +doAssert fmt"{1.5:+08}" == "+00001.5" # works +doAssert fmt"{1.5: 08}" == " 00001.5" # works - doAssert fmt"^7.1 :: {str=:^7.1}" == "^7.1 :: str= ä " - doAssert fmt"^7.2 :: {str=:^7.2}" == "^7.2 :: str= äö " - doAssert fmt"^7.3 :: {str=:^7.3}" == "^7.3 :: str= äöü " - doAssert fmt"^7.0 :: {str=:^7.0}" == "^7.0 :: str= " - # this is actually wrong, but the unicode module has no support for graphemes - doAssert fmt"^7.4 :: {str:^7.4}" == "^7.4 :: äöüe " - doAssert fmt"^7.9 :: {str:^7.9}" == "^7.9 :: äöüe\u0309\u0319o\u0307\u0359" +# only add explicitly requested sign if value != -0.0 (neg zero) +doAssert fmt"{-0.0:g}" == "-0" +doassert fmt"{-0.0:+g}" == "-0" +doassert fmt"{-0.0: g}" == "-0" +doAssert fmt"{0.0:g}" == "0" +doAssert fmt"{0.0:+g}" == "+0" +doAssert fmt"{0.0: g}" == " 0" - doAssert fmt"^7.4 :: {str=:^7.4}" == "^7.4 :: str= äöüe " - doAssert fmt"^7.9 :: {str=:^7.9}" == "^7.9 :: str=äöüe\u0309\u0319o\u0307\u0359" +# seq format - block: # see issue #7932 - doAssert fmt"{15:08}" == "00000015" # int, works - doAssert fmt"{1.5:08}" == "000001.5" # float, works - doAssert fmt"{1.5:0>8}" == "000001.5" # workaround using fill char works for positive floats - doAssert fmt"{-1.5:0>8}" == "0000-1.5" # even that does not work for negative floats - doAssert fmt"{-1.5:08}" == "-00001.5" # works - doAssert fmt"{1.5:+08}" == "+00001.5" # works - doAssert fmt"{1.5: 08}" == " 00001.5" # works +let data1 = [1'i64, 10000'i64, 10000000'i64] +let data2 = [10000000'i64, 100'i64, 1'i64] - doAssert fmt"{15=:08}" == "15=00000015" # int, works - doAssert fmt"{1.5=:08}" == "1.5=000001.5" # float, works - doAssert fmt"{1.5=:0>8}" == "1.5=000001.5" # workaround using fill char works for positive floats - doAssert fmt"{-1.5=:0>8}" == "-1.5=0000-1.5" # even that does not work for negative floats - doAssert fmt"{-1.5=:08}" == "-1.5=-00001.5" # works - doAssert fmt"{1.5=:+08}" == "1.5=+00001.5" # works - doAssert fmt"{1.5=: 08}" == "1.5= 00001.5" # works - - block: # only add explicitly requested sign if value != -0.0 (neg zero) - doAssert fmt"{-0.0:g}" == "-0" - doAssert fmt"{-0.0:+g}" == "-0" - doAssert fmt"{-0.0: g}" == "-0" - doAssert fmt"{0.0:g}" == "0" - doAssert fmt"{0.0:+g}" == "+0" - doAssert fmt"{0.0: g}" == " 0" - - doAssert fmt"{-0.0=:g}" == "-0.0=-0" - doAssert fmt"{-0.0=:+g}" == "-0.0=-0" - doAssert fmt"{-0.0=: g}" == "-0.0=-0" - doAssert fmt"{0.0=:g}" == "0.0=0" - doAssert fmt"{0.0=:+g}" == "0.0=+0" - doAssert fmt"{0.0=: g}" == "0.0= 0" - - block: # seq format - let data1 = [1'i64, 10000'i64, 10000000'i64] - let data2 = [10000000'i64, 100'i64, 1'i64] - - proc formatValue(result: var string; value: (array|seq|openArray); specifier: string) = - result.add "[" - for i, it in value: - if i != 0: - result.add ", " - result.formatValue(it, specifier) - result.add "]" - - doAssert fmt"data1: {data1:8} #" == "data1: [ 1, 10000, 10000000] #" - doAssert fmt"data2: {data2:8} =" == "data2: [10000000, 100, 1] =" - - doAssert fmt"data1: {data1=:8} #" == "data1: data1=[ 1, 10000, 10000000] #" - doAssert fmt"data2: {data2=:8} =" == "data2: data2=[10000000, 100, 1] =" - - block: # custom format Value - type - Vec2[T] = object - x,y: T - - proc formatValue[T](result: var string; value: Vec2[T]; specifier: string) = - result.add '[' - result.formatValue value.x, specifier +proc formatValue(result: var string; value: (array|seq|openArray); specifier: string) = + result.add "[" + for i, it in value: + if i != 0: result.add ", " - result.formatValue value.y, specifier - result.add "]" + result.formatValue(it, specifier) + result.add "]" - let v1 = Vec2[float32](x:1.0, y: 2.0) - let v2 = Vec2[int32](x:1, y: 1337) - doAssert fmt"v1: {v1:+08} v2: {v2:>4}" == "v1: [+0000001, +0000002] v2: [ 1, 1337]" - doAssert fmt"v1: {v1=:+08} v2: {v2=:>4}" == "v1: v1=[+0000001, +0000002] v2: v2=[ 1, 1337]" +doAssert fmt"data1: {data1:8} #" == "data1: [ 1, 10000, 10000000] #" +doAssert fmt"data2: {data2:8} =" == "data2: [10000000, 100, 1] =" - block: # bug #11012 - type - Animal = object - name, species: string - AnimalRef = ref Animal +# custom format Value - proc print_object(animalAddr: AnimalRef): string = - fmt"Received {animalAddr[]}" +type + Vec2[T] = object + x,y: T - doAssert print_object(AnimalRef(name: "Foo", species: "Bar")) == """Received (name: "Foo", species: "Bar")""" +proc formatValue[T](result: var string; value: Vec2[T]; specifier: string) = + result.add '[' + result.formatValue value.x, specifier + result.add ", " + result.formatValue value.y, specifier + result.add "]" - block: # bug #11723 - let pos: Positive = 64 - doAssert fmt"{pos:3}" == " 64" - doAssert fmt"{pos:3b}" == "1000000" - doAssert fmt"{pos:3d}" == " 64" - doAssert fmt"{pos:3o}" == "100" - doAssert fmt"{pos:3x}" == " 40" - doAssert fmt"{pos:3X}" == " 40" +let v1 = Vec2[float32](x:1.0, y: 2.0) +let v2 = Vec2[int32](x:1, y: 1337) +doAssert fmt"v1: {v1:+08} v2: {v2:>4}" == "v1: [+0000001, +0000002] v2: [ 1, 1337]" - doAssert fmt"{pos=:3}" == "pos= 64" - doAssert fmt"{pos=:3b}" == "pos=1000000" - doAssert fmt"{pos=:3d}" == "pos= 64" - doAssert fmt"{pos=:3o}" == "pos=100" - doAssert fmt"{pos=:3x}" == "pos= 40" - doAssert fmt"{pos=:3X}" == "pos= 40" +# bug #11012 - let nat: Natural = 64 - doAssert fmt"{nat:3}" == " 64" - doAssert fmt"{nat:3b}" == "1000000" - doAssert fmt"{nat:3d}" == " 64" - doAssert fmt"{nat:3o}" == "100" - doAssert fmt"{nat:3x}" == " 40" - doAssert fmt"{nat:3X}" == " 40" +type + Animal = object + name, species: string + AnimalRef = ref Animal - doAssert fmt"{nat=:3}" == "nat= 64" - doAssert fmt"{nat=:3b}" == "nat=1000000" - doAssert fmt"{nat=:3d}" == "nat= 64" - doAssert fmt"{nat=:3o}" == "nat=100" - doAssert fmt"{nat=:3x}" == "nat= 40" - doAssert fmt"{nat=:3X}" == "nat= 40" +proc print_object(animalAddr: AnimalRef) = + echo fmt"Received {animalAddr[]}" - block: # bug #12612 - proc my_proc() = - const value = "value" - const a = &"{value}" - doAssert a == value +print_object(AnimalRef(name: "Foo", species: "Bar")) - const b = &"{value=}" - doAssert b == "value=" & value +# bug #11723 - my_proc() +let pos: Positive = 64 +doAssert fmt"{pos:3}" == " 64" +doAssert fmt"{pos:3b}" == "1000000" +doAssert fmt"{pos:3d}" == " 64" +doAssert fmt"{pos:3o}" == "100" +doAssert fmt"{pos:3x}" == " 40" +doAssert fmt"{pos:3X}" == " 40" - block: - template fmt(pattern: string; openCloseChar: char): untyped = - fmt(pattern, openCloseChar, openCloseChar) +let nat: Natural = 64 +doAssert fmt"{nat:3}" == " 64" +doAssert fmt"{nat:3b}" == "1000000" +doAssert fmt"{nat:3d}" == " 64" +doAssert fmt"{nat:3o}" == "100" +doAssert fmt"{nat:3x}" == " 40" +doAssert fmt"{nat:3X}" == " 40" - let - testInt = 123 - testStr = "foobar" - testFlt = 3.141592 - doAssert ">><<".fmt('<', '>') == "><" - doAssert " >> << ".fmt('<', '>') == " > < " - doAssert "<<>>".fmt('<', '>') == "<>" - doAssert " << >> ".fmt('<', '>') == " < > " - doAssert "''".fmt('\'') == "'" - doAssert "''''".fmt('\'') == "''" - doAssert "'' ''".fmt('\'') == "' '" - doAssert "".fmt('<', '>') == "123" - doAssert "".fmt('<', '>') == "123" - doAssert "'testFlt:1.2f'".fmt('\'') == "3.14" - doAssert "".fmt('<', '>') == "123foobar" - doAssert """ ""{"123+123"}"" """.fmt('"') == " \"{246}\" " - doAssert "(((testFlt:1.2f)))((111))".fmt('(', ')') == "(3.14)(111)" - doAssert """(()"foo" & "bar"())""".fmt(')', '(') == "(foobar)" - doAssert "{}abc`testStr' `testFlt:1.2f' `1+1' ``".fmt('`', '\'') == "{}abcfoobar 3.14 2 `" - doAssert """x = '"foo" & "bar"' - y = '123 + 111' - z = '3 in {2..7}' - """.fmt('\'') == - """x = foobar - y = 234 - z = true - """ +# bug #12612 +proc my_proc = + const value = "value" + const a = &"{value}" + assert a == value - block: # tests from the very own strformat documentation! - let msg = "hello" - doAssert fmt"{msg}\n" == "hello\\n" +my_proc() - doAssert &"{msg}\n" == "hello\n" +block: + template fmt(pattern: string; openCloseChar: char): untyped = + fmt(pattern, openCloseChar, openCloseChar) - doAssert fmt"{msg}{'\n'}" == "hello\n" - doAssert fmt("{msg}\n") == "hello\n" - doAssert "{msg}\n".fmt == "hello\n" - - doAssert fmt"{msg=}\n" == "msg=hello\\n" - - doAssert &"{msg=}\n" == "msg=hello\n" - - doAssert fmt"{msg=}{'\n'}" == "msg=hello\n" - doAssert fmt("{msg=}\n") == "msg=hello\n" - doAssert "{msg=}\n".fmt == "msg=hello\n" - - doAssert &"""{"abc":>4}""" == " abc" - doAssert &"""{"abc":<4}""" == "abc " - - doAssert fmt"{-12345:08}" == "-0012345" - doAssert fmt"{-1:3}" == " -1" - doAssert fmt"{-1:03}" == "-01" - doAssert fmt"{16:#X}" == "0x10" - - doAssert fmt"{123.456}" == "123.456" - doAssert fmt"{123.456:>9.3f}" == " 123.456" - doAssert fmt"{123.456:9.3f}" == " 123.456" - doAssert fmt"{123.456:9.4f}" == " 123.4560" - doAssert fmt"{123.456:>9.0f}" == " 123." - doAssert fmt"{123.456:<9.4f}" == "123.4560 " - - doAssert fmt"{123.456:e}" == "1.234560e+02" - doAssert fmt"{123.456:>13e}" == " 1.234560e+02" - doAssert fmt"{123.456:13e}" == " 1.234560e+02" - - doAssert &"""{"abc"=:>4}""" == "\"abc\"= abc" - doAssert &"""{"abc"=:<4}""" == "\"abc\"=abc " - - doAssert fmt"{-12345=:08}" == "-12345=-0012345" - doAssert fmt"{-1=:3}" == "-1= -1" - doAssert fmt"{-1=:03}" == "-1=-01" - doAssert fmt"{16=:#X}" == "16=0x10" - - doAssert fmt"{123.456=}" == "123.456=123.456" - doAssert fmt"{123.456=:>9.3f}" == "123.456= 123.456" - doAssert fmt"{123.456=:9.3f}" == "123.456= 123.456" - doAssert fmt"{123.456=:9.4f}" == "123.456= 123.4560" - doAssert fmt"{123.456=:>9.0f}" == "123.456= 123." - doAssert fmt"{123.456=:<9.4f}" == "123.456=123.4560 " - - doAssert fmt"{123.456=:e}" == "123.456=1.234560e+02" - doAssert fmt"{123.456=:>13e}" == "123.456= 1.234560e+02" - doAssert fmt"{123.456=:13e}" == "123.456= 1.234560e+02" - - let x = 3.14 - doAssert fmt"{(if x!=0: 1.0/x else: 0):.5}" == "0.31847" - doAssert fmt"""{(block: - var res: string - for i in 1..15: - res.add (if i mod 15 == 0: "FizzBuzz" - elif i mod 5 == 0: "Buzz" - elif i mod 3 == 0: "Fizz" - else: $i) & " " - res)}""" == "1 2 Fizz 4 Buzz Fizz 7 8 Fizz Buzz 11 Fizz 13 14 FizzBuzz " - - doAssert fmt"""{ "\{(" & msg & ")\}" }""" == "{(hello)}" - doAssert fmt"""{{({ msg })}}""" == "{(hello)}" - doAssert fmt"""{ $(\{msg:1,"world":2\}) }""" == """[("hello", 1), ("world", 2)]""" - block: # tests for debug format string - var name = "hello" - let age = 21 - const hobby = "swim" - doAssert fmt"{age*9 + 16=}" == "age*9 + 16=205" - doAssert &"name: {name =}\nage: { age =: >7}\nhobby: { hobby= : 8}" == - "name: name =hello\nage: age = 21\nhobby: hobby= swim " - doAssert fmt"{age == 12}" == "false" - doAssert fmt"{name.toUpperAscii() = }" == "name.toUpperAscii() = HELLO" - doAssert fmt"{name.toUpperAscii( ) = }" == "name.toUpperAscii( ) = HELLO" - doAssert fmt"{ toUpperAscii( s = name ) = }" == " toUpperAscii( s = name ) = HELLO" - doAssert fmt"{ strutils.toUpperAscii( s = name ) = }" == " strutils.toUpperAscii( s = name ) = HELLO" - doAssert fmt"{age==12}" == "false" - doAssert fmt"{age!= 12}" == "true" - doAssert fmt"{age <= 12}" == "false" - for i in 1 .. 10: - doAssert fmt"{age.float =: .2f}" == "age.float = 21.00" - doAssert fmt"{age.float() =:.3f}" == "age.float() =21.000" - doAssert fmt"{float age= :.3f}" == "float age= 21.000" - doAssert fmt"{12 == int(`!=`(age, 12))}" == "false" - doAssert fmt"{0==1}" == "false" - - block: # It is space sensitive. - let x = "12" - doAssert fmt"{x=:}" == "x=12" - doAssert fmt"{x=}" == "x=12" - doAssert fmt"{x =:}" == "x =12" - doAssert fmt"{x =}" == "x =12" - doAssert fmt"{x= :}" == "x= 12" - doAssert fmt"{x= }" == "x= 12" - doAssert fmt"{x = :}" == "x = 12" - doAssert fmt"{x = }" == "x = 12" - doAssert fmt"{x = :}" == "x = 12" - doAssert fmt"{x = }" == "x = 12" - - block: - let x = "hello" - doAssert fmt"{x=}" == "x=hello" - doAssert fmt"{x =}" == "x =hello" - - let y = 3.1415926 - doAssert fmt"{y=:.2f}" == fmt"y={y:.2f}" - doAssert fmt"{y=}" == fmt"y={y}" - doAssert fmt"{y = : <8}" == fmt"y = 3.14159 " - - proc hello(a: string, b: float): int = 12 - template foo(a: string, b: float): int = 18 - - doAssert fmt"{hello(x, y)=}" == "hello(x, y)=12" - doAssert fmt"{hello(x, y) =}" == "hello(x, y) =12" - doAssert fmt"{hello(x, y)= }" == "hello(x, y)= 12" - doAssert fmt"{hello(x, y) = }" == "hello(x, y) = 12" - - doAssert fmt"{hello x, y=}" == "hello x, y=12" - doAssert fmt"{hello x, y =}" == "hello x, y =12" - doAssert fmt"{hello x, y= }" == "hello x, y= 12" - doAssert fmt"{hello x, y = }" == "hello x, y = 12" - - doAssert fmt"{x.hello(y)=}" == "x.hello(y)=12" - doAssert fmt"{x.hello(y) =}" == "x.hello(y) =12" - doAssert fmt"{x.hello(y)= }" == "x.hello(y)= 12" - doAssert fmt"{x.hello(y) = }" == "x.hello(y) = 12" - - doAssert fmt"{foo(x, y)=}" == "foo(x, y)=18" - doAssert fmt"{foo(x, y) =}" == "foo(x, y) =18" - doAssert fmt"{foo(x, y)= }" == "foo(x, y)= 18" - doAssert fmt"{foo(x, y) = }" == "foo(x, y) = 18" - - doAssert fmt"{x.foo(y)=}" == "x.foo(y)=18" - doAssert fmt"{x.foo(y) =}" == "x.foo(y) =18" - doAssert fmt"{x.foo(y)= }" == "x.foo(y)= 18" - doAssert fmt"{x.foo(y) = }" == "x.foo(y) = 18" - - block: - template check(actual, expected: string) = - doAssert actual == expected - - # Basic tests - let s = "string" - check &"{0} {s}", "0 string" - check &"{s[0..2].toUpperAscii}", "STR" - check &"{-10:04}", "-010" - check &"{-10:<04}", "-010" - check &"{-10:>04}", "-010" - check &"0x{10:02X}", "0x0A" - - check &"{10:#04X}", "0x0A" - - check &"""{"test":#>5}""", "#test" - check &"""{"test":>5}""", " test" - - check &"""{"test":#^7}""", "#test##" - - check &"""{"test": <5}""", "test " - check &"""{"test":<5}""", "test " - check &"{1f:.3f}", "1.000" - check &"Hello, {s}!", "Hello, string!" - - # Tests for identifiers without parenthesis - check &"{s} works{s}", "string worksstring" - check &"{s:>7}", " string" - doAssert(not compiles(&"{s_works}")) # parsed as identifier `s_works` - - # Misc general tests - check &"{{}}", "{}" - check &"{0}%", "0%" - check &"{0}%asdf", "0%asdf" - check &("\n{\"\\n\"}\n"), "\n\n\n" - check &"""{"abc"}s""", "abcs" - - # String tests - check &"""{"abc"}""", "abc" - check &"""{"abc":>4}""", " abc" - check &"""{"abc":<4}""", "abc " - check &"""{"":>4}""", " " - check &"""{"":<4}""", " " - - # Int tests - check &"{12345}", "12345" - check &"{ - 12345}", "-12345" - check &"{12345:6}", " 12345" - check &"{12345:>6}", " 12345" - check &"{12345:4}", "12345" - check &"{12345:08}", "00012345" - check &"{-12345:08}", "-0012345" - check &"{0:0}", "0" - check &"{0:02}", "00" - check &"{-1:3}", " -1" - check &"{-1:03}", "-01" - check &"{10}", "10" - check &"{16:#X}", "0x10" - check &"{16:^#7X}", " 0x10 " - check &"{16:^+#7X}", " +0x10 " - - # Hex tests - check &"{0:x}", "0" - check &"{-0:x}", "0" - check &"{255:x}", "ff" - check &"{255:X}", "FF" - check &"{-255:x}", "-ff" - check &"{-255:X}", "-FF" - check &"{255:x} uNaffeCteD CaSe", "ff uNaffeCteD CaSe" - check &"{255:X} uNaffeCteD CaSe", "FF uNaffeCteD CaSe" - check &"{255:4x}", " ff" - check &"{255:04x}", "00ff" - check &"{-255:4x}", " -ff" - check &"{-255:04x}", "-0ff" - - # Float tests - check &"{123.456}", "123.456" - check &"{-123.456}", "-123.456" - check &"{123.456:.3f}", "123.456" - check &"{123.456:+.3f}", "+123.456" - check &"{-123.456:+.3f}", "-123.456" - check &"{-123.456:.3f}", "-123.456" - check &"{123.456:1g}", "123.456" - check &"{123.456:.1f}", "123.5" - check &"{123.456:.0f}", "123." - check &"{123.456:>9.3f}", " 123.456" - check &"{123.456:9.3f}", " 123.456" - check &"{123.456:>9.4f}", " 123.4560" - check &"{123.456:>9.0f}", " 123." - check &"{123.456:<9.4f}", "123.4560 " - - # Float (scientific) tests - check &"{123.456:e}", "1.234560e+02" - check &"{123.456:>13e}", " 1.234560e+02" - check &"{123.456:<13e}", "1.234560e+02 " - check &"{123.456:.1e}", "1.2e+02" - check &"{123.456:.2e}", "1.23e+02" - check &"{123.456:.3e}", "1.235e+02" - - # Note: times.format adheres to the format protocol. Test that this - # works: - when nimvm: - discard - else: - var dt = dateTime(2000, mJan, 01, 00, 00, 00) - check &"{dt:yyyy-MM-dd}", "2000-01-01" - - var tm = fromUnix(0) - discard &"{tm}" - - var noww = now() - check &"{noww}", $noww - - # Unicode string tests - check &"""{"αβγ"}""", "αβγ" - check &"""{"αβγ":>5}""", " αβγ" - check &"""{"αβγ":<5}""", "αβγ " - check &"""a{"a"}α{"α"}€{"€"}𐍈{"𐍈"}""", "aaαα€€𐍈𐍈" - check &"""a{"a":2}α{"α":2}€{"€":2}𐍈{"𐍈":2}""", "aa αα €€ 𐍈𐍈 " - # Invalid unicode sequences should be handled as plain strings. - # Invalid examples taken from: https://stackoverflow.com/a/3886015/1804173 - let invalidUtf8 = [ - "\xc3\x28", "\xa0\xa1", - "\xe2\x28\xa1", "\xe2\x82\x28", - "\xf0\x28\x8c\xbc", "\xf0\x90\x28\xbc", "\xf0\x28\x8c\x28" - ] - for s in invalidUtf8: - check &"{s:>5}", repeat(" ", 5-s.len) & s - - # bug #11089 - let flfoo: float = 1.0 - check &"{flfoo}", "1.0" - - # bug #11092 - check &"{high(int64)}", "9223372036854775807" - check &"{low(int64)}", "-9223372036854775808" - - doAssert fmt"{'a'} {'b'}" == "a b" - - block: # test low(int64) - doAssert &"{low(int64):-}" == "-9223372036854775808" - block: #expressions plus formatting - doAssert fmt"{if true\: 123.456 else\: 0=:>9.3f}" == "if true: 123.456 else: 0= 123.456" - doAssert fmt"{(if true: 123.456 else: 0)=}" == "(if true: 123.456 else: 0)=123.456" - doAssert fmt"{if true\: 123.456 else\: 0=:9.3f}" == "if true: 123.456 else: 0= 123.456" - doAssert fmt"{(if true: 123.456 else: 0)=:9.4f}" == "(if true: 123.456 else: 0)= 123.4560" - doAssert fmt"{(if true: 123.456 else: 0)=:>9.0f}" == "(if true: 123.456 else: 0)= 123." - doAssert fmt"{if true\: 123.456 else\: 0=:<9.4f}" == "if true: 123.456 else: 0=123.4560 " - - doAssert fmt"""{(case true - of false: 0.0 - of true: 123.456)=:e}""" == """(case true - of false: 0.0 - of true: 123.456)=1.234560e+02""" - - doAssert fmt"""{block\: - var res = 0.000123456 - for _ in 0..5\: - res *= 10 - res=:>13e}""" == """block: - var res = 0.000123456 - for _ in 0..5: - res *= 10 - res= 1.234560e+02""" - #side effects - var x = 5 - doAssert fmt"{(x=7;123.456)=:13e}" == "(x=7;123.456)= 1.234560e+02" - doAssert x==7 - block: #curly bracket expressions and tuples - proc formatValue(result: var string; value:Table|bool|JsonNode; specifier:string) = result.add $value - - doAssert fmt"""{\{"a"\:1,"b"\:2\}.toTable() = }""" == """{"a":1,"b":2}.toTable() = {"a": 1, "b": 2}""" - doAssert fmt"""{(\{3: (1,"hi",0.9),4: (4,"lo",1.1)\}).toTable()}""" == """{3: (1, "hi", 0.9), 4: (4, "lo", 1.1)}""" - doAssert fmt"""{ (%* \{"name": "Isaac", "books": ["Robot Dreams"]\}) }""" == """{"name":"Isaac","books":["Robot Dreams"]}""" - doAssert """%( \%\* {"name": "Isaac"})*""".fmt('%','*') == """{"name":"Isaac"}""" - block: #parens in quotes that fool my syntax highlighter - doAssert fmt"{(if true: ')' else: '(')}" == ")" - doAssert fmt"{(if true: ']' else: ')')}" == "]" - doAssert fmt"""{(if true: "\")\"" else: "\"(")}""" == """")"""" - doAssert &"""{(if true: "\")" else: "")}""" == "\")" - doAssert &"{(if true: \"\\\")\" else: \"\")}" == "\")" - doAssert fmt"""{(if true: "')" else: "")}""" == "')" - doAssert fmt"""{(if true: "'" & "'" & ')' else: "")}""" == "'')" - doAssert &"""{(if true: "'" & "'" & ')' else: "")}""" == "'')" - doAssert &"{(if true: \"\'\" & \"'\" & ')' else: \"\")}" == "'')" - doAssert fmt"""{(if true: "'" & ')' else: "")}""" == "')" - -static: main() -main() + let + testInt = 123 + testStr = "foobar" + testFlt = 3.141592 + doAssert ">><<".fmt('<', '>') == "><" + doAssert " >> << ".fmt('<', '>') == " > < " + doAssert "<<>>".fmt('<', '>') == "<>" + doAssert " << >> ".fmt('<', '>') == " < > " + doAssert "''".fmt('\'') == "'" + doAssert "''''".fmt('\'') == "''" + doAssert "'' ''".fmt('\'') == "' '" + doAssert "".fmt('<', '>') == "123" + doAssert "".fmt('<', '>') == "123" + doAssert "'testFlt:1.2f'".fmt('\'') == "3.14" + doAssert "".fmt('<', '>') == "123foobar" + doAssert """ ""{"123+123"}"" """.fmt('"') == " \"{246}\" " + doAssert "(((testFlt:1.2f)))((111))".fmt('(', ')') == "(3.14)(111)" + doAssert """(()"foo" & "bar"())""".fmt(')', '(') == "(foobar)" + doAssert "{}abc`testStr' `testFlt:1.2f' `1+1' ``".fmt('`', '\'') == "{}abcfoobar 3.14 2 `" + doAssert """x = '"foo" & "bar"' + y = '123 + 111' + z = '3 in {2..7}' + """.fmt('\'') == + """x = foobar + y = 234 + z = true + """ diff --git a/tests/stdlib/tstrimpl.nim b/tests/stdlib/tstrimpl.nim deleted file mode 100644 index d12150f8e..000000000 --- a/tests/stdlib/tstrimpl.nim +++ /dev/null @@ -1,8 +0,0 @@ -import std/private/strimpl - -import std/assertions - -doAssert find(cstring"Hello Nim", cstring"Nim") == 6 -doAssert find(cstring"Hello Nim", cstring"N") == 6 -doAssert find(cstring"Hello Nim", cstring"I") == -1 -doAssert find(cstring"Hello Nim", cstring"O") == -1 diff --git a/tests/stdlib/tstring.nim b/tests/stdlib/tstring.nim index 2e8fe09e1..36a2e9800 100644 --- a/tests/stdlib/tstring.nim +++ b/tests/stdlib/tstring.nim @@ -1,123 +1,93 @@ discard """ - targets: "c cpp js" + output: '''OK +@[@[], @[], @[], @[], @[]] +''' """ +const characters = "abcdefghijklmnopqrstuvwxyz" +const numbers = "1234567890" -from std/sequtils import toSeq, map -from std/sugar import `=>` -import std/assertions +var s: string + +proc test_string_slice() = + # test "slice of length == len(characters)": + # replace characters completely by numbers + s = characters + s[0..^1] = numbers + doAssert s == numbers + + # test "slice of length > len(numbers)": + # replace characters by slice of same length + s = characters + s[1..16] = numbers + doAssert s == "a1234567890rstuvwxyz" + + # test "slice of length == len(numbers)": + # replace characters by slice of same length + s = characters + s[1..10] = numbers + doAssert s == "a1234567890lmnopqrstuvwxyz" + + # test "slice of length < len(numbers)": + # replace slice of length. and insert remaining chars + s = characters + s[1..4] = numbers + doAssert s == "a1234567890fghijklmnopqrstuvwxyz" + + # test "slice of length == 1": + # replace first character. and insert remaining 9 chars + s = characters + s[1..1] = numbers + doAssert s == "a1234567890cdefghijklmnopqrstuvwxyz" + + # test "slice of length == 0": + # insert chars at slice start index + s = characters + s[2..1] = numbers + doAssert s == "ab1234567890cdefghijklmnopqrstuvwxyz" + + # test "slice of negative length": + # same as slice of zero length + s = characters + s[2..0] = numbers + doAssert s == "ab1234567890cdefghijklmnopqrstuvwxyz" + + # bug #6223 + doAssertRaises(IndexError): + discard s[0..999] + + echo("OK") + +proc test_string_cmp() = + let world = "hello\0world" + let earth = "hello\0earth" + let short = "hello\0" + let hello = "hello" + let goodbye = "goodbye" + + doAssert world == world + doAssert world != earth + doAssert world != short + doAssert world != hello + doAssert world != goodbye + + doAssert cmp(world, world) == 0 + doAssert cmp(world, earth) > 0 + doAssert cmp(world, short) > 0 + doAssert cmp(world, hello) > 0 + doAssert cmp(world, goodbye) > 0 + +test_string_slice() +test_string_cmp() + + +#-------------------------- +# bug #7816 +import sugar +import sequtils proc tester[T](x: T) = let test = toSeq(0..4).map(i => newSeq[int]()) - doAssert $test == "@[@[], @[], @[], @[], @[]]" + echo test -func reverse*(a: string): string = - result = a - for i in 0 ..< a.len div 2: - swap(result[i], result[^(i + 1)]) +tester(1) -proc main() = - block: # .. - const - characters = "abcdefghijklmnopqrstuvwxyz" - numbers = "1234567890" - - # test "slice of length == len(characters)": - # replace characters completely by numbers - var s: string - s = characters - s[0..^1] = numbers - doAssert s == numbers - - # test "slice of length > len(numbers)": - # replace characters by slice of same length - s = characters - s[1..16] = numbers - doAssert s == "a1234567890rstuvwxyz" - - # test "slice of length == len(numbers)": - # replace characters by slice of same length - s = characters - s[1..10] = numbers - doAssert s == "a1234567890lmnopqrstuvwxyz" - - # test "slice of length < len(numbers)": - # replace slice of length. and insert remaining chars - s = characters - s[1..4] = numbers - doAssert s == "a1234567890fghijklmnopqrstuvwxyz" - - # test "slice of length == 1": - # replace first character. and insert remaining 9 chars - s = characters - s[1..1] = numbers - doAssert s == "a1234567890cdefghijklmnopqrstuvwxyz" - - # test "slice of length == 0": - # insert chars at slice start index - s = characters - s[2..1] = numbers - doAssert s == "ab1234567890cdefghijklmnopqrstuvwxyz" - - # test "slice of negative length": - # same as slice of zero length - s = characters - s[2..0] = numbers - doAssert s == "ab1234567890cdefghijklmnopqrstuvwxyz" - - when nimvm: - discard - else: - # bug #6223 - doAssertRaises(IndexDefect): - discard s[0..999] - - block: # ==, cmp - let world = "hello\0world" - let earth = "hello\0earth" - let short = "hello\0" - let hello = "hello" - let goodbye = "goodbye" - - doAssert world == world - doAssert world != earth - doAssert world != short - doAssert world != hello - doAssert world != goodbye - - doAssert cmp(world, world) == 0 - doAssert cmp(world, earth) > 0 - doAssert cmp(world, short) > 0 - doAssert cmp(world, hello) > 0 - doAssert cmp(world, goodbye) > 0 - - block: # bug #7816 - tester(1) - - block: # bug #14497, reverse - doAssert reverse("hello") == "olleh" - - block: # len, high - var a = "ab\0cd" - var b = a.cstring - doAssert a.len == 5 - block: # bug #16405 - when defined(js): - when nimvm: doAssert b.len == 2 - else: doAssert b.len == 5 - else: doAssert b.len == 2 - - doAssert a.high == a.len - 1 - doAssert b.high == b.len - 1 - - doAssert "".len == 0 - doAssert "".high == -1 - doAssert "".cstring.len == 0 - doAssert "".cstring.high == -1 - - block: # bug #16674 - var c: cstring = nil - doAssert c.len == 0 - doAssert c.high == -1 - -static: main() -main() diff --git a/tests/stdlib/tstrmiscs.nim b/tests/stdlib/tstrmiscs.nim deleted file mode 100644 index 76b14d27a..000000000 --- a/tests/stdlib/tstrmiscs.nim +++ /dev/null @@ -1,23 +0,0 @@ -import std/strmisc -import std/assertions - - -doAssert expandTabs("\t", 4) == " " -doAssert expandTabs("\tfoo\t", 4) == " foo " -doAssert expandTabs("\tfoo\tbar", 4) == " foo bar" -doAssert expandTabs("\tfoo\tbar\t", 4) == " foo bar " -doAssert expandTabs("", 4) == "" -doAssert expandTabs("", 0) == "" -doAssert expandTabs("\t\t\t", 0) == "" - -doAssert partition("foo:bar", ":") == ("foo", ":", "bar") -doAssert partition("foobarbar", "bar") == ("foo", "bar", "bar") -doAssert partition("foobarbar", "bank") == ("foobarbar", "", "") -doAssert partition("foobarbar", "foo") == ("", "foo", "barbar") -doAssert partition("foofoobar", "bar") == ("foofoo", "bar", "") - -doAssert rpartition("foo:bar", ":") == ("foo", ":", "bar") -doAssert rpartition("foobarbar", "bar") == ("foobar", "bar", "") -doAssert rpartition("foobarbar", "bank") == ("", "", "foobarbar") -doAssert rpartition("foobarbar", "foo") == ("", "foo", "barbar") -doAssert rpartition("foofoobar", "bar") == ("foofoo", "bar", "") diff --git a/tests/stdlib/tstrscans.nim b/tests/stdlib/tstrscans.nim index e30c86279..08fc14e45 100644 --- a/tests/stdlib/tstrscans.nim +++ b/tests/stdlib/tstrscans.nim @@ -2,7 +2,7 @@ discard """ output: "" """ -import std/[strscans, strutils, assertions] +import strscans block ParsePasswd: proc parsePasswd(content: string): seq[string] = @@ -15,7 +15,7 @@ block ParsePasswd: else: break - const etcPasswd = """root:x:0:0:root:/root:/bin/bash + const etc_passwd = """root:x:0:0:root:/root:/bin/bash daemon:x:1:1:daemon:/usr/sbin:/bin/sh bin:x:2:2:bin:/bin:/bin/sh sys:x:3:3:sys:/dev:/bin/sh @@ -23,7 +23,7 @@ nobody:x:65534:65534:nobody:/nonexistent:/bin/sh messagebus:x:103:107::/var/run/dbus:/bin/false """ - const parsedEtcPasswd = @[ + const parsed_etc_passwd = @[ "root:x:0:0:root:/root:/bin/bash", "daemon:x:1:1:daemon:/usr/sbin:/bin/sh", "bin:x:2:2:bin:/bin:/bin/sh", @@ -31,7 +31,7 @@ messagebus:x:103:107::/var/run/dbus:/bin/false "nobody:x:65534:65534:nobody:/nonexistent:/bin/sh", "messagebus:x:103:107::/var/run/dbus:/bin/false", ] - doAssert etcPasswd.parsePasswd == parsedEtcPasswd + doAssert etc_passwd.parsePasswd == parsed_etc_passwd block LastNot: var idx : int @@ -79,210 +79,8 @@ block EmptyTuple: block Arrow: let text = "foo;bar;baz;" var idx = 0 + var res = "" doAssert scanp(text, idx, +(~{';','\0'} -> (discard $_)), ';') doAssert scanp(text, idx, +(~{';','\0'} -> (discard $_)), ';') doAssert scanp(text, idx, +(~{';','\0'} -> (discard $_)), ';') doAssert scanp(text, idx, +(~{';','\0'} -> (discard $_)), ';') == false - - -block issue15064: - var nick1, msg1: string - doAssert scanf(" a", "<$+> $+", nick1, msg1) - doAssert nick1 == "abcd" - doAssert msg1 == "a" - - var nick2, msg2: string - doAssert(not scanf(" ", "<$+> $+", nick2, msg2)) - - var nick3, msg3: string - doAssert scanf(" ", "<$+> $*", nick3, msg3) - doAssert nick3 == "abcd" - doAssert msg3 == "" - - -block: - proc twoDigits(input: string; x: var int; start: int): int = - if start+1 < input.len and input[start] == '0' and input[start+1] == '0': - result = 2 - x = 13 - else: - result = 0 - - proc someSep(input: string; start: int; seps: set[char] = {';', ',', '-', '.'}): int = - result = 0 - while start+result < input.len and input[start+result] in seps: inc result - - proc demangle(s: string; res: var string; start: int): int = - while result+start < s.len and s[result+start] in {'_', '@'}: inc result - res = "" - while result+start < s.len and s[result+start] > ' ' and s[result+start] != '_': - res.add s[result+start] - inc result - while result+start < s.len and s[result+start] > ' ': - inc result - - proc parseGDB(resp: string): seq[string] = - const - digits = {'0'..'9'} - hexdigits = digits + {'a'..'f', 'A'..'F'} - whites = {' ', '\t', '\C', '\L'} - result = @[] - var idx = 0 - while true: - var prc = "" - var info = "" - if scanp(resp, idx, *`whites`, '#', *`digits`, +`whites`, ?("0x", *`hexdigits`, " in "), - demangle($input, prc, $index), *`whites`, '(', * ~ ')', ')', - *`whites`, "at ", +(~{'\C', '\L'} -> info.add($_))): - result.add prc & " " & info - else: - break - - var key, val: string - var intVal: int - var floatVal: float - doAssert scanf("abc:: xyz 89 33.25", "$w$s::$s$w$s$i $f", key, val, intVal, floatVal) - doAssert key == "abc" - doAssert val == "xyz" - doAssert intVal == 89 - doAssert floatVal == 33.25 - - var binVal: int - var octVal: int - var hexVal: int - doAssert scanf("0b0101 0o1234 0xabcd", "$b$s$o$s$h", binVal, octVal, hexVal) - doAssert binVal == 0b0101 - doAssert octVal == 0o1234 - doAssert hexVal == 0xabcd - - let xx = scanf("$abc", "$$$i", intVal) - doAssert xx == false - - - let xx2 = scanf("$1234", "$$$i", intVal) - doAssert xx2 - - let yy = scanf(";.--Breakpoint00 [output]", - "$[someSep]Breakpoint${twoDigits}$[someSep({';','.','-'})] [$+]$.", - intVal, key) - doAssert yy - doAssert key == "output" - doAssert intVal == 13 - - var ident = "" - var idx = 0 - let zz = scanp("foobar x x x xWZ", idx, +{'a'..'z'} -> add(ident, $_), *(*{ - ' ', '\t'}, "x"), ~'U', "Z") - doAssert zz - doAssert ident == "foobar" - - const digits = {'0'..'9'} - var year = 0 - var idx2 = 0 - if scanp("201655-8-9", idx2, `digits`{4, 6} -> (year = year * 10 + ord($_) - - ord('0')), "-8", "-9"): - doAssert year == 201655 - - const gdbOut = """ - #0 @foo_96013_1208911747@8 (x0=...) - at c:/users/anwender/projects/nim/temp.nim:11 - #1 0x00417754 in tempInit000 () at c:/users/anwender/projects/nim/temp.nim:13 - #2 0x0041768d in NimMainInner () - at c:/users/anwender/projects/nim/lib/system.nim:2605 - #3 0x004176b1 in NimMain () - at c:/users/anwender/projects/nim/lib/system.nim:2613 - #4 0x004176db in main (argc=1, args=0x712cc8, env=0x711ca8) - at c:/users/anwender/projects/nim/lib/system.nim:2620""" - const result = @["foo c:/users/anwender/projects/nim/temp.nim:11", - "tempInit000 c:/users/anwender/projects/nim/temp.nim:13", - "NimMainInner c:/users/anwender/projects/nim/lib/system.nim:2605", - "NimMain c:/users/anwender/projects/nim/lib/system.nim:2613", - "main c:/users/anwender/projects/nim/lib/system.nim:2620"] - doAssert parseGDB(gdbOut) == result - - # bug #6487 - var count = 0 - - proc test(): string = - inc count - result = ",123123" - - var a: int - discard scanf(test(), ",$i", a) - doAssert count == 1 - - -block: - let input = """1-3 s: abc -15-18 9: def -15-18 A: ghi -15-18 _: jkl -""" - var - lo, hi: int - w: string - c: char - res: int - for line in input.splitLines: - if line.scanf("$i-$i $c: $w", lo, hi, c, w): - inc res - doAssert res == 4 - -block: - #whenscanf testing - let input = """1-3 s: abc -15-18 9: def -15-18 A: ghi -15-18 _: jkl -""" - proc twoDigits(input: string; x: var int; start: int): int = - if start+1 < input.len and input[start] == '0' and input[start+1] == '0': - result = 2 - x = 13 - else: - result = 0 - - proc someSep(input: string; start: int; seps: set[char] = {';', ',', '-', '.'}): int = - result = 0 - while start+result < input.len and input[start+result] in seps: inc result - - type - ScanRetType = tuple - success: bool - lo: int - hi: int - ch: char - word: string - - var res = 0 - for line in input.splitLines: - let ret: ScanRetType = scanTuple(line, "$i-$i $c: $w") - if ret.success: - inc res - doAssert res == 4 - - let (_, key, val, intVal, floatVal) = scanTuple("abc:: xyz 89 33.25", "$w$s::$s$w$s$i $f") - doAssert key == "abc" - doAssert val == "xyz" - doAssert intVal == 89 - doAssert floatVal == 33.25 - - - let (_, binVal, octVal, hexVal) = scanTuple("0b0101 0o1234 0xabcd", "$b$s$o$s$h", binVal, octVal, hexVal) - doAssert binVal == 0b0101 - doAssert octVal == 0o1234 - doAssert hexVal == 0xabcd - - var (xx,_) = scanTuple("$abc", "$$$i") - doAssert xx == false - - - let (xx2, _) = block: scanTuple("$1234", "$$$i") - doAssert xx2 - - var (yy, intVal2, key2) = scanTuple(";.--Breakpoint00 [output]", - "$[someSep]Breakpoint${twoDigits}$[someSep({';','.','-'})] [$+]$.", - int) - doAssert yy - doAssert key2 == "output" - doAssert intVal2 == 13 diff --git a/tests/stdlib/tstrset.nim b/tests/stdlib/tstrset.nim index f0cf5cbe4..1b253f862 100644 --- a/tests/stdlib/tstrset.nim +++ b/tests/stdlib/tstrset.nim @@ -3,10 +3,10 @@ type TRadixNodeKind = enum rnLinear, rnFull, rnLeaf PRadixNode = ref TRadixNode - TRadixNode {.inheritable.} = object + TRadixNode = object {.inheritable.} kind: TRadixNodeKind TRadixNodeLinear = object of TRadixNode - len: uint8 + len: int8 keys: array[0..31, char] vals: array[0..31, PRadixNode] TRadixNodeFull = object of TRadixNode @@ -24,7 +24,7 @@ proc search(r: PRadixNode, s: string): PRadixNode = case r.kind of rnLinear: var x = PRadixNodeLinear(r) - for j in 0..int(x.len)-1: + for j in 0..ze(x.len)-1: if x.keys[j] == s[i]: if s[i] == '\0': return r r = x.vals[j] @@ -50,7 +50,7 @@ proc search(r: PRadixNode, s: string): PRadixNode = proc contains*(r: PRadixNode, s: string): bool = return search(r, s) != nil -proc testOrIncl*(r: var PRadixNode, s: string): bool = +proc testOrincl*(r: var PRadixNode, s: string): bool = nil proc incl*(r: var PRadixNode, s: string) = discard testOrIncl(r, s) @@ -63,9 +63,9 @@ proc excl*(r: var PRadixNode, s: string) = of rnFull: PRadixNodeFull(x).b['\0'] = nil of rnLinear: var x = PRadixNodeLinear(x) - for i in 0..int(x.len)-1: + for i in 0..ze(x.len)-1: if x.keys[i] == '\0': - swap(x.keys[i], x.keys[int(x.len)-1]) + swap(x.keys[i], x.keys[ze(x.len)-1]) dec(x.len) break diff --git a/tests/stdlib/tstrtabs.nim b/tests/stdlib/tstrtabs.nim index 036287bfd..5d7e8c762 100644 --- a/tests/stdlib/tstrtabs.nim +++ b/tests/stdlib/tstrtabs.nim @@ -88,7 +88,7 @@ value1 = value2 ''' """ -import std/[strtabs, assertions, syncio] +import strtabs var tab = newStringTable({"key1": "val1", "key2": "val2"}, modeStyleInsensitive) @@ -102,15 +102,3 @@ writeLine(stdout, "length of table ", $tab.len) writeLine(stdout, `%`("$key1 = $key2", tab, {useEnvironment})) tab.clear writeLine(stdout, "length of table ", $tab.len) - -block: - var x = {"k": "v", "11": "22", "565": "67"}.newStringTable - doAssert x["k"] == "v" - doAssert x["11"] == "22" - doAssert x["565"] == "67" - x["11"] = "23" - doAssert x["11"] == "23" - - x.clear(modeCaseInsensitive) - x["11"] = "22" - doAssert x["11"] == "22" diff --git a/tests/stdlib/tstrtabs.nims b/tests/stdlib/tstrtabs.nims deleted file mode 100644 index 3563ad0ad..000000000 --- a/tests/stdlib/tstrtabs.nims +++ /dev/null @@ -1,5 +0,0 @@ -import std/[strtabs, assertions] - -static: - let t = {"name": "John", "city": "Monaco"}.newStringTable - doAssert "${name} lives in ${city}" % t == "John lives in Monaco" diff --git a/tests/stdlib/tstrtabs2.nim b/tests/stdlib/tstrtabs2.nim deleted file mode 100644 index f055b5d33..000000000 --- a/tests/stdlib/tstrtabs2.nim +++ /dev/null @@ -1,16 +0,0 @@ -discard """ - targets: "c cpp js" -""" - -import std/strtabs -import std/assertions - -macro m = - var t = {"name": "John"}.newStringTable - doAssert t["name"] == "John" - -block: - var t = {"name": "John"}.newStringTable - doAssert t["name"] == "John" - -m() diff --git a/tests/stdlib/tstrutil.nim b/tests/stdlib/tstrutil.nim new file mode 100644 index 000000000..9dbc98912 --- /dev/null +++ b/tests/stdlib/tstrutil.nim @@ -0,0 +1,350 @@ +discard """ + output: "ha/home/a1xyz/usr/bin" +""" +# test the new strutils module + +import + strutils + +import macros + +template rejectParse(e) = + try: + discard e + raise newException(AssertionError, "This was supposed to fail: $#!" % astToStr(e)) + except ValueError: discard + +proc testStrip() = + write(stdout, strip(" ha ")) + +proc testRemoveSuffix = + var s = "hello\n\r" + s.removeSuffix + assert s == "hello" + s.removeSuffix + assert s == "hello" + + s = "hello\n\n" + s.removeSuffix + assert s == "hello" + + s = "hello\r" + s.removeSuffix + assert s == "hello" + + s = "hello \n there" + s.removeSuffix + assert s == "hello \n there" + + s = "hello" + s.removeSuffix("llo") + assert s == "he" + s.removeSuffix('e') + assert s == "h" + + s = "hellos" + s.removeSuffix({'s','z'}) + assert s == "hello" + s.removeSuffix({'l','o'}) + assert s == "he" + + s = "aeiou" + s.removeSuffix("") + assert s == "aeiou" + + s = "" + s.removeSuffix("") + assert s == "" + + s = " " + s.removeSuffix + assert s == " " + + s = " " + s.removeSuffix("") + assert s == " " + + s = " " + s.removeSuffix(" ") + assert s == " " + + s = " " + s.removeSuffix(' ') + assert s == "" + + # Contrary to Chomp in other languages + # empty string does not change behaviour + s = "hello\r\n\r\n" + s.removeSuffix("") + assert s == "hello\r\n\r\n" + +proc testRemovePrefix = + var s = "\n\rhello" + s.removePrefix + assert s == "hello" + s.removePrefix + assert s == "hello" + + s = "\n\nhello" + s.removePrefix + assert s == "hello" + + s = "\rhello" + s.removePrefix + assert s == "hello" + + s = "hello \n there" + s.removePrefix + assert s == "hello \n there" + + s = "hello" + s.removePrefix("hel") + assert s == "lo" + s.removePrefix('l') + assert s == "o" + + s = "hellos" + s.removePrefix({'h','e'}) + assert s == "llos" + s.removePrefix({'l','o'}) + assert s == "s" + + s = "aeiou" + s.removePrefix("") + assert s == "aeiou" + + s = "" + s.removePrefix("") + assert s == "" + + s = " " + s.removePrefix + assert s == " " + + s = " " + s.removePrefix("") + assert s == " " + + s = " " + s.removePrefix(" ") + assert s == " " + + s = " " + s.removePrefix(' ') + assert s == "" + + # Contrary to Chomp in other languages + # empty string does not change behaviour + s = "\r\n\r\nhello" + s.removePrefix("") + assert s == "\r\n\r\nhello" + +proc main() = + testStrip() + testRemoveSuffix() + testRemovePrefix() + for p in split("/home/a1:xyz:/usr/bin", {':'}): + write(stdout, p) + +proc testDelete = + var s = "0123456789ABCDEFGH" + delete(s, 4, 5) + assert s == "01236789ABCDEFGH" + delete(s, s.len-1, s.len-1) + assert s == "01236789ABCDEFG" + delete(s, 0, 0) + assert s == "1236789ABCDEFG" + +proc testFind = + assert "0123456789ABCDEFGH".find('A') == 10 + assert "0123456789ABCDEFGH".find('A', 5) == 10 + assert "0123456789ABCDEFGH".find('A', 5, 10) == 10 + assert "0123456789ABCDEFGH".find('A', 5, 9) == -1 + assert "0123456789ABCDEFGH".find("A") == 10 + assert "0123456789ABCDEFGH".find("A", 5) == 10 + assert "0123456789ABCDEFGH".find("A", 5, 10) == 10 + assert "0123456789ABCDEFGH".find("A", 5, 9) == -1 + assert "0123456789ABCDEFGH".find({'A'..'C'}) == 10 + assert "0123456789ABCDEFGH".find({'A'..'C'}, 5) == 10 + assert "0123456789ABCDEFGH".find({'A'..'C'}, 5, 10) == 10 + assert "0123456789ABCDEFGH".find({'A'..'C'}, 5, 9) == -1 + +proc testRFind = + assert "0123456789ABCDEFGAH".rfind('A') == 17 + assert "0123456789ABCDEFGAH".rfind('A', last=13) == 10 + assert "0123456789ABCDEFGAH".rfind('H', last=13) == -1 + assert "0123456789ABCDEFGAH".rfind("A") == 17 + assert "0123456789ABCDEFGAH".rfind("A", last=13) == 10 + assert "0123456789ABCDEFGAH".rfind("H", last=13) == -1 + assert "0123456789ABCDEFGAH".rfind({'A'..'C'}) == 17 + assert "0123456789ABCDEFGAH".rfind({'A'..'C'}, last=13) == 12 + assert "0123456789ABCDEFGAH".rfind({'G'..'H'}, last=13) == -1 + assert "0123456789ABCDEFGAH".rfind('A', start=18) == -1 + assert "0123456789ABCDEFGAH".rfind('A', start=11, last=17) == 17 + assert "0123456789ABCDEFGAH".rfind("0", start=0) == 0 + assert "0123456789ABCDEFGAH".rfind("0", start=1) == -1 + assert "0123456789ABCDEFGAH".rfind("H", start=11) == 18 + assert "0123456789ABCDEFGAH".rfind({'0'..'9'}, start=5) == 9 + assert "0123456789ABCDEFGAH".rfind({'0'..'9'}, start=10) == -1 + +proc testTrimZeros() = + var x = "1200" + x.trimZeros() + assert x == "1200" + x = "120.0" + x.trimZeros() + assert x == "120" + x = "0." + x.trimZeros() + assert x == "0" + x = "1.0e2" + x.trimZeros() + assert x == "1e2" + x = "78.90" + x.trimZeros() + assert x == "78.9" + x = "1.23e4" + x.trimZeros() + assert x == "1.23e4" + x = "1.01" + x.trimZeros() + assert x == "1.01" + x = "1.1001" + x.trimZeros() + assert x == "1.1001" + x = "0.0" + x.trimZeros() + assert x == "0" + x = "0.01" + x.trimZeros() + assert x == "0.01" + x = "1e0" + x.trimZeros() + assert x == "1e0" + +proc testSplitLines() = + let fixture = "a\nb\rc\r\nd" + assert len(fixture.splitLines) == 4 + assert splitLines(fixture) == @["a", "b", "c", "d"] + assert splitLines(fixture, keepEol=true) == @["a\n", "b\r", "c\r\n", "d"] + +proc testCountLines = + proc assertCountLines(s: string) = assert s.countLines == s.splitLines.len + assertCountLines("") + assertCountLines("\n") + assertCountLines("\n\n") + assertCountLines("abc") + assertCountLines("abc\n123") + assertCountLines("abc\n123\n") + assertCountLines("\nabc\n123") + assertCountLines("\nabc\n123\n") + +proc testParseInts = + # binary + assert "0b1111".parseBinInt == 15 + assert "0B1111".parseBinInt == 15 + assert "1111".parseBinInt == 15 + assert "1110".parseBinInt == 14 + assert "1_1_1_1".parseBinInt == 15 + assert "0b1_1_1_1".parseBinInt == 15 + rejectParse "".parseBinInt + rejectParse "_".parseBinInt + rejectParse "0b".parseBinInt + rejectParse "0b1234".parseBinInt + # hex + assert "0x72".parseHexInt == 114 + assert "0X72".parseHexInt == 114 + assert "#72".parseHexInt == 114 + assert "72".parseHexInt == 114 + assert "FF".parseHexInt == 255 + assert "ff".parseHexInt == 255 + assert "fF".parseHexInt == 255 + assert "0x7_2".parseHexInt == 114 + rejectParse "".parseHexInt + rejectParse "_".parseHexInt + rejectParse "0x".parseHexInt + rejectParse "0xFFG".parseHexInt + rejectParse "reject".parseHexInt + # octal + assert "0o17".parseOctInt == 15 + assert "0O17".parseOctInt == 15 + assert "17".parseOctInt == 15 + assert "10".parseOctInt == 8 + assert "0o1_0_0".parseOctInt == 64 + rejectParse "".parseOctInt + rejectParse "_".parseOctInt + rejectParse "0o".parseOctInt + rejectParse "9".parseOctInt + rejectParse "0o9".parseOctInt + rejectParse "reject".parseOctInt + +testDelete() +testFind() +testRFind() +testTrimZeros() +testSplitLines() +testCountLines() +testParseInts() + +assert(insertSep($1000_000) == "1_000_000") +assert(insertSep($232) == "232") +assert(insertSep($12345, ',') == "12,345") +assert(insertSep($0) == "0") + +assert "/1/2/3".rfind('/') == 4 +assert "/1/2/3".rfind('/', last=1) == 0 +assert "/1/2/3".rfind('0') == -1 + +assert(toHex(100i16, 32) == "00000000000000000000000000000064") +assert(toHex(-100i16, 32) == "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9C") + +assert "".parseHexStr == "" +assert "00Ff80".parseHexStr == "\0\xFF\x80" +try: + discard "00Ff8".parseHexStr + assert false, "Should raise ValueError" +except ValueError: + discard + +try: + discard "0k".parseHexStr + assert false, "Should raise ValueError" +except ValueError: + discard + +assert "".toHex == "" +assert "\x00\xFF\x80".toHex == "00FF80" +assert "0123456789abcdef".parseHexStr.toHex == "0123456789ABCDEF" + +assert(' '.repeat(8) == " ") +assert(" ".repeat(8) == " ") +assert(spaces(8) == " ") + +assert(' '.repeat(0) == "") +assert(" ".repeat(0) == "") +assert(spaces(0) == "") + +# bug #11369 + +var num: int64 = -1 +assert num.toBin(64) == "1111111111111111111111111111111111111111111111111111111111111111" +assert num.toOct(24) == "001777777777777777777777" + + +# bug #8911 +when true: + static: + let a = "" + let a2 = a.replace("\n", "\\n") + +when true: + static: + let b = "b" + let b2 = b.replace("\n", "\\n") + +when true: + let c = "" + let c2 = c.replace("\n", "\\n") + +main() +#OUT ha/home/a1xyz/usr/bin diff --git a/tests/stdlib/tstrutils.nim b/tests/stdlib/tstrutils.nim deleted file mode 100644 index 4e88197ff..000000000 --- a/tests/stdlib/tstrutils.nim +++ /dev/null @@ -1,880 +0,0 @@ -discard """ - targets: "c cpp js" -""" - -import std/strutils -from stdtest/testutils import disableVm -import std/assertions -# xxx each instance of `disableVm` and `when not defined js:` should eventually be fixed - -template rejectParse(e) = - try: - discard e - raise newException(AssertionDefect, "This was supposed to fail: $#!" % astToStr(e)) - except ValueError: discard - -template main() = - block: # strip - doAssert strip(" ha ") == "ha" - doAssert strip(" foofoofoo ") == "foofoofoo" - doAssert strip("sfoofoofoos", chars = {'s'}) == "foofoofoo" - doAssert strip("barfoofoofoobar", chars = {'b', 'a', 'r'}) == "foofoofoo" - doAssert strip("stripme but don't strip this stripme", - chars = {'s', 't', 'r', 'i', 'p', 'm', 'e'}) == - " but don't strip this " - doAssert strip("sfoofoofoos", leading = false, chars = {'s'}) == "sfoofoofoo" - doAssert strip("sfoofoofoos", trailing = false, chars = {'s'}) == "foofoofoos" - - block: - let a = "xxxxxx" - doAssert a.strip(chars={'x'}).len == 0 - - doAssert "".strip(chars={'x'}).len == 0 - doAssert " ".strip(chars={'x'}) == " " - doAssert "xxx xxx".strip(chars={'x'}) == " " - doAssert "xxx wind".strip(chars={'x'}) == " wind" - doAssert "xxx iii".strip(chars={'i'}) == "xxx " - doAssert "x".strip(leading = false, chars={'x'}).len == 0 - doAssert "x".strip(trailing = false, chars={'x'}).len == 0 - doAssert "x".strip(leading = false, trailing = false, chars={'x'}) == "x" - - block: # split - var ret: seq[string] # or use `toSeq` or `collect` - for p in split("/home/a1:xyz:/usr/bin", {':'}): ret.add p - doAssert ret == @["/home/a1", "xyz", "/usr/bin"] - - let s = " this is an example " - let s2 = ":this;is;an:example;;" - - doAssert s.split() == @["", "this", "is", "an", "example", "", ""] - doAssert s2.split(seps = {':', ';'}) == @["", "this", "is", "an", "example", - "", ""] - doAssert s.split(maxsplit = 4) == @["", "this", "is", "an", "example "] - doAssert s.split(' ', maxsplit = 1) == @["", "this is an example "] - doAssert s.split(" ", maxsplit = 4) == @["", "this", "is", "an", "example "] - - block: # splitLines - let fixture = "a\nb\rc\r\nd" - doAssert len(fixture.splitLines) == 4 - doAssert splitLines(fixture) == @["a", "b", "c", "d"] - doAssert splitLines(fixture, keepEol=true) == @["a\n", "b\r", "c\r\n", "d"] - - block: # rsplit - doAssert rsplit("foo bar", seps = Whitespace) == @["foo", "bar"] - doAssert rsplit(" foo bar", seps = Whitespace, maxsplit = 1) == @[" foo", "bar"] - doAssert rsplit(" foo bar ", seps = Whitespace, maxsplit = 1) == @[ - " foo bar", ""] - doAssert rsplit(":foo:bar", sep = ':') == @["", "foo", "bar"] - doAssert rsplit(":foo:bar", sep = ':', maxsplit = 2) == @["", "foo", "bar"] - doAssert rsplit(":foo:bar", sep = ':', maxsplit = 3) == @["", "foo", "bar"] - doAssert rsplit("foothebar", sep = "the") == @["foo", "bar"] - - block: # splitWhitespace - let s = " this is an example " - doAssert s.splitWhitespace() == @["this", "is", "an", "example"] - doAssert s.splitWhitespace(maxsplit = 1) == @["this", "is an example "] - doAssert s.splitWhitespace(maxsplit = 2) == @["this", "is", "an example "] - doAssert s.splitWhitespace(maxsplit = 3) == @["this", "is", "an", "example "] - doAssert s.splitWhitespace(maxsplit = 4) == @["this", "is", "an", "example"] - - block: # removeSuffix - var s = "hello\n\r" - s.removeSuffix - doAssert s == "hello" - s.removeSuffix - doAssert s == "hello" - - s = "hello\n\n" - s.removeSuffix - doAssert s == "hello" - - s = "hello\r" - s.removeSuffix - doAssert s == "hello" - - s = "hello \n there" - s.removeSuffix - doAssert s == "hello \n there" - - s = "hello" - s.removeSuffix("llo") - doAssert s == "he" - s.removeSuffix('e') - doAssert s == "h" - - s = "hellos" - s.removeSuffix({'s','z'}) - doAssert s == "hello" - s.removeSuffix({'l','o'}) - doAssert s == "he" - - s = "aeiou" - s.removeSuffix("") - doAssert s == "aeiou" - - s = "" - s.removeSuffix("") - doAssert s == "" - - s = " " - s.removeSuffix - doAssert s == " " - - s = " " - s.removeSuffix("") - doAssert s == " " - - s = " " - s.removeSuffix(" ") - doAssert s == " " - - s = " " - s.removeSuffix(' ') - doAssert s == "" - - # Contrary to Chomp in other languages - # empty string does not change behaviour - s = "hello\r\n\r\n" - s.removeSuffix("") - doAssert s == "hello\r\n\r\n" - - block: # removePrefix - var s = "\n\rhello" - s.removePrefix - doAssert s == "hello" - s.removePrefix - doAssert s == "hello" - - s = "\n\nhello" - s.removePrefix - doAssert s == "hello" - - s = "\rhello" - s.removePrefix - doAssert s == "hello" - - s = "hello \n there" - s.removePrefix - doAssert s == "hello \n there" - - s = "hello" - s.removePrefix("hel") - doAssert s == "lo" - s.removePrefix('l') - doAssert s == "o" - - s = "hellos" - s.removePrefix({'h','e'}) - doAssert s == "llos" - s.removePrefix({'l','o'}) - doAssert s == "s" - - s = "aeiou" - s.removePrefix("") - doAssert s == "aeiou" - - s = "" - s.removePrefix("") - doAssert s == "" - - s = " " - s.removePrefix - doAssert s == " " - - s = " " - s.removePrefix("") - doAssert s == " " - - s = " " - s.removePrefix(" ") - doAssert s == " " - - s = " " - s.removePrefix(' ') - doAssert s == "" - - # Contrary to Chomp in other languages - # empty string does not change behaviour - s = "\r\n\r\nhello" - s.removePrefix("") - doAssert s == "\r\n\r\nhello" - - block: # delete(slice) - var s = "0123456789ABCDEFGH" - delete(s, 4 .. 5) - doAssert s == "01236789ABCDEFGH" - delete(s, s.len-1 .. s.len-1) - doAssert s == "01236789ABCDEFG" - delete(s, 0..0) - doAssert s == "1236789ABCDEFG" - s = "" - doAssertRaises(IndexDefect): delete(s, 0..0) - doAssert s == "" - s = "abc" - doAssertRaises(IndexDefect): delete(s, -1 .. -2) - doAssertRaises(IndexDefect): delete(s, 2..3) - doAssertRaises(IndexDefect): delete(s, 3..2) - delete(s, 2..2) - doAssert s == "ab" - delete(s, 1..0) - doAssert s == "ab" - delete(s, 0..0) - doAssert s == "b" - - block: # delete(first, last) - {.push warning[deprecated]:off.} - var s = "0123456789ABCDEFGH" - delete(s, 4, 5) - doAssert s == "01236789ABCDEFGH" - delete(s, s.len-1, s.len-1) - doAssert s == "01236789ABCDEFG" - delete(s, 0, 0) - doAssert s == "1236789ABCDEFG" - {.pop.} - - block: # find - const haystack: string = "0123456789ABCDEFGH" - doAssert haystack.find('A') == 10 - doAssert haystack.find('A', 5) == 10 - doAssert haystack.find('A', 5, 10) == 10 - doAssert haystack.find('A', 5, 9) == -1 - doAssert haystack.find("A") == 10 - doAssert haystack.find("A", 5) == 10 - doAssert haystack.find("A", 5, 10) == 10 - doAssert haystack.find("A", 5, 9) == -1 - doAssert haystack.find({'A'..'C'}) == 10 - doAssert haystack.find({'A'..'C'}, 5) == 10 - doAssert haystack.find({'A'..'C'}, 5, 10) == 10 - doAssert haystack.find({'A'..'C'}, 5, 9) == -1 - doAssert haystack.find('A', 0, 0) == -1 # search limited to the first char - doAssert haystack.find('A', 5, 0) == -1 # last < start - doAssert haystack.find('A', 5, 4) == -1 # last < start - - block: - const haystack: string = "ABCABABABABCAB" - doAssert haystack.len == 14 - - # only last argument - doAssert haystack.find("ABC") == 0 - doAssert haystack.find("ABC", last=13) == 0 # after the second ABC - doAssert haystack.find("ABC", last=5) == 0 # before the second ABC - - # only start argument - doAssert haystack.find("ABC", start=0) == 0 - doAssert haystack.find("ABC", start=1) == 9 - doAssert haystack.find("ABC", start=9) == 9 - doAssert haystack.find("ABC", start=10) == -1 - - # both start and last arguments - doAssert haystack.find("ABC", start=0, last=14) == 0 - doAssert haystack.find("ABC", start=0, last=13) == 0 - doAssert haystack.find("ABC", start=0, last=12) == 0 - doAssert haystack.find("ABC", start=1, last=13) == 9 - doAssert haystack.find("ABC", start=1, last=12) == 9 - doAssert haystack.find("ABC", start=1, last=11) == 9 - doAssert haystack.find("ABC", start=1, last=10) == -1 - - doAssert "".find("/") == -1 - doAssert "/".find("/") == 0 - doAssert "/".find("//") == -1 - doAssert "///".find("//", start=3) == -1 - - # searching for empty string - doAssert "".find("") == 0 - doAssert "abc".find("") == 0 - doAssert "abc".find("", start=1) == 1 - doAssert "abc".find("", start=2) == 2 - doAssert "abc".find("", start=3) == 3 - doAssert "abc".find("", start=4) == -1 - doAssert "abc".find("", start=400) == -1 - doAssert "abc".find("", start=1, last=3) == 1 - doAssert "abc".find("", start=1, last=2) == 1 - doAssert "abc".find("", start=1, last=1) == 1 - doAssert "abc".find("", start=1, last=0) == 1 - doAssert "abc".find("", start=1, last = -1) == 1 - - # when last <= start, searching for non-empty string - block: - let last: int = -1 # searching through whole line - doAssert "abcd".find("ab", start=0, last=last) == 0 - doAssert "abcd".find("ab", start=1, last=last) == -1 - doAssert "abcd".find("bc", start=1, last=last) == 1 - doAssert "abcd".find("bc", start=2, last=last) == -1 - block: - let last: int = 0 - doAssert "abcd".find("ab", start=0, last=last) == -1 - doAssert "abcd".find("ab", start=1, last=last) == -1 - doAssert "abcd".find("bc", start=1, last=last) == -1 - doAssert "abcd".find("bc", start=2, last=last) == -1 - block: - let last: int = 1 - doAssert "abcd".find("ab", start=0, last=last) == 0 - doAssert "abcd".find("ab", start=1, last=last) == -1 - doAssert "abcd".find("bc", start=1, last=last) == -1 - doAssert "abcd".find("bc", start=2, last=last) == -1 - - block: # rfind - doAssert "0123456789ABCDEFGAH".rfind('A') == 17 - doAssert "0123456789ABCDEFGAH".rfind('A', last=13) == 10 - doAssert "0123456789ABCDEFGAH".rfind('H', last=13) == -1 - doAssert "0123456789ABCDEFGAH".rfind("A") == 17 - doAssert "0123456789ABCDEFGAH".rfind("A", last=13) == 10 - doAssert "0123456789ABCDEFGAH".rfind("H", last=13) == -1 - doAssert "0123456789ABCDEFGAH".rfind({'A'..'C'}) == 17 - doAssert "0123456789ABCDEFGAH".rfind({'A'..'C'}, last=13) == 12 - doAssert "0123456789ABCDEFGAH".rfind({'G'..'H'}, last=13) == -1 - doAssert "0123456789ABCDEFGAH".rfind('A', start=18) == -1 - doAssert "0123456789ABCDEFGAH".rfind('A', start=11, last=17) == 17 - doAssert "0123456789ABCDEFGAH".rfind("0", start=0) == 0 - doAssert "0123456789ABCDEFGAH".rfind("0", start=1) == -1 - doAssert "0123456789ABCDEFGAH".rfind("H", start=11) == 18 - doAssert "0123456789ABCDEFGAH".rfind({'0'..'9'}, start=5) == 9 - doAssert "0123456789ABCDEFGAH".rfind({'0'..'9'}, start=10) == -1 - - doAssert "/1/2/3".rfind('/') == 4 - doAssert "/1/2/3".rfind('/', last=1) == 0 - doAssert "/1/2/3".rfind('0') == -1 - - block: - const haystack: string = "ABCABABABABCAB" - doAssert haystack.len == 14 - doAssert haystack.rfind("ABC") == 9 - doAssert haystack.rfind("ABC", last=13) == 9 - doAssert haystack.rfind("ABC", last=12) == 9 - doAssert haystack.rfind("ABC", last=11) == 9 - doAssert haystack.rfind("ABC", last=10) == 0 - - doAssert haystack.rfind("ABC", start=0) == 9 - doAssert haystack.rfind("ABC", start=1) == 9 - doAssert haystack.rfind("ABC", start=9) == 9 - doAssert haystack.rfind("ABC", start=10) == -1 - - doAssert haystack.rfind("ABC", start=0, last=13) == 9 - doAssert haystack.rfind("ABC", start=0, last=12) == 9 - doAssert haystack.rfind("ABC", start=0, last=11) == 9 - doAssert haystack.rfind("ABC", start=0, last=10) == 0 - doAssert haystack.rfind("ABC", start=1, last=10) == -1 - - doAssert "".rfind("/") == -1 - doAssert "/".rfind("/") == 0 - doAssert "/".rfind("//") == -1 - doAssert "///".rfind("//", start=3) == -1 - - # searching for empty string - doAssert "".rfind("") == 0 - doAssert "abc".rfind("") == 3 - doAssert "abc".rfind("", start=1) == 3 - doAssert "abc".rfind("", start=2) == 3 - doAssert "abc".rfind("", start=3) == 3 - doAssert "abc".rfind("", start=4) == 4 - doAssert "abc".rfind("", start=400) == 400 - - doAssert "abc".rfind("", start=1, last=3) == 3 - doAssert "abc".rfind("", start=1, last=2) == 2 - doAssert "abc".rfind("", start=1, last=1) == 1 - # This returns the start index instead of the last index - # because start > last - doAssert "abc".rfind("", start=1, last=0) == 1 - doAssert "abc".rfind("", start=1, last = -1) == 3 - - doAssert "abc".rfind("", start=0, last=0) == 0 - - # when last <= start, searching for non-empty string - block: - let last: int = -1 - doAssert "abcd".rfind("ab", start=0, last=last) == 0 - doAssert "abcd".rfind("ab", start=1, last=last) == -1 - doAssert "abcd".rfind("bc", start=1, last=last) == 1 - doAssert "abcd".rfind("bc", start=2, last=last) == -1 - block: - let last: int = 0 - doAssert "abcd".rfind("ab", start=0, last=last) == -1 - doAssert "abcd".rfind("ab", start=1, last=last) == -1 - doAssert "abcd".rfind("bc", start=1, last=last) == -1 - doAssert "abcd".rfind("bc", start=2, last=last) == -1 - block: - let last: int = 1 - doAssert "abcd".rfind("ab", start=0, last=last) == 0 - doAssert "abcd".rfind("ab", start=1, last=last) == -1 - doAssert "abcd".rfind("bc", start=1, last=last) == -1 - doAssert "abcd".rfind("bc", start=2, last=last) == -1 - - block: # trimZeros - var x = "1200" - x.trimZeros() - doAssert x == "1200" - x = "120.0" - x.trimZeros() - doAssert x == "120" - x = "0." - x.trimZeros() - doAssert x == "0" - x = "1.0e2" - x.trimZeros() - doAssert x == "1e2" - x = "78.90" - x.trimZeros() - doAssert x == "78.9" - x = "1.23e4" - x.trimZeros() - doAssert x == "1.23e4" - x = "1.01" - x.trimZeros() - doAssert x == "1.01" - x = "1.1001" - x.trimZeros() - doAssert x == "1.1001" - x = "0.0" - x.trimZeros() - doAssert x == "0" - x = "0.01" - x.trimZeros() - doAssert x == "0.01" - x = "1e0" - x.trimZeros() - doAssert x == "1e0" - x = "1.23" - x.trimZeros() - doAssert x == "1.23" - - block: # countLines - proc assertCountLines(s: string) = doAssert s.countLines == s.splitLines.len - assertCountLines("") - assertCountLines("\n") - assertCountLines("\n\n") - assertCountLines("abc") - assertCountLines("abc\n123") - assertCountLines("abc\n123\n") - assertCountLines("\nabc\n123") - assertCountLines("\nabc\n123\n") - - block: # parseBinInt, parseHexInt, parseOctInt - # binary - doAssert "0b1111".parseBinInt == 15 - doAssert "0B1111".parseBinInt == 15 - doAssert "1111".parseBinInt == 15 - doAssert "1110".parseBinInt == 14 - doAssert "1_1_1_1".parseBinInt == 15 - doAssert "0b1_1_1_1".parseBinInt == 15 - rejectParse "".parseBinInt - rejectParse "_".parseBinInt - rejectParse "0b".parseBinInt - rejectParse "0b1234".parseBinInt - # hex - doAssert "0x72".parseHexInt == 114 - doAssert "0X72".parseHexInt == 114 - doAssert "#72".parseHexInt == 114 - doAssert "72".parseHexInt == 114 - doAssert "FF".parseHexInt == 255 - doAssert "ff".parseHexInt == 255 - doAssert "fF".parseHexInt == 255 - doAssert "0x7_2".parseHexInt == 114 - rejectParse "".parseHexInt - rejectParse "_".parseHexInt - rejectParse "0x".parseHexInt - rejectParse "0xFFG".parseHexInt - rejectParse "reject".parseHexInt - # octal - doAssert "0o17".parseOctInt == 15 - doAssert "0O17".parseOctInt == 15 - doAssert "17".parseOctInt == 15 - doAssert "10".parseOctInt == 8 - doAssert "0o1_0_0".parseOctInt == 64 - rejectParse "".parseOctInt - rejectParse "_".parseOctInt - rejectParse "0o".parseOctInt - rejectParse "9".parseOctInt - rejectParse "0o9".parseOctInt - rejectParse "reject".parseOctInt - - block: # parseHexStr - doAssert "".parseHexStr == "" - doAssert "00Ff80".parseHexStr == "\0\xFF\x80" - try: - discard "00Ff8".parseHexStr - doAssert false, "Should raise ValueError" - except ValueError: - discard - - try: - discard "0k".parseHexStr - doAssert false, "Should raise ValueError" - except ValueError: - discard - - doAssert "".toHex == "" - doAssert "\x00\xFF\x80".toHex == "00FF80" - doAssert "0123456789abcdef".parseHexStr.toHex == "0123456789ABCDEF" - - block: # toHex - doAssert(toHex(100i16, 32) == "00000000000000000000000000000064") - doAssert(toHex(-100i16, 32) == "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9C") - when not defined js: - doAssert(toHex(high(uint64)) == "FFFFFFFFFFFFFFFF") - doAssert(toHex(high(uint64), 16) == "FFFFFFFFFFFFFFFF") - doAssert(toHex(high(uint64), 32) == "0000000000000000FFFFFFFFFFFFFFFF") - - block: # insertSep - doAssert(insertSep($1000_000) == "1_000_000") - doAssert(insertSep($232) == "232") - doAssert(insertSep($12345, ',') == "12,345") - doAssert(insertSep($0) == "0") - - block: # repeat, spaces - doAssert(' '.repeat(8) == " ") - doAssert(" ".repeat(8) == " ") - doAssert(spaces(8) == " ") - - doAssert(' '.repeat(0) == "") - doAssert(" ".repeat(0) == "") - doAssert(spaces(0) == "") - - block: # toBin, toOct - block:# bug #11369 - var num: int64 = -1 - when not defined js: - doAssert num.toBin(64) == "1111111111111111111111111111111111111111111111111111111111111111" - doAssert num.toOct(24) == "001777777777777777777777" - - block: # replace - doAssert "oo".replace("", "abc") == "oo" - # bug #8911 - static: - let a = "" - let a2 = a.replace("\n", "\\n") - - static: - let b = "b" - let b2 = b.replace("\n", "\\n") - - block: - let c = "" - let c2 = c.replace("\n", "\\n") - - block: # replaceWord - doAssert "-ld a-ldz -ld".replaceWord("-ld") == " a-ldz " - doAssert "-lda-ldz -ld abc".replaceWord("-ld") == "-lda-ldz abc" - doAssert "-lda-ldz -ld abc".replaceWord("") == "-lda-ldz -ld abc" - - block: # multiReplace - doAssert "abba".multiReplace(("a", "b"), ("b", "a")) == "baab" - doAssert "Hello World.".multiReplace(("ello", "ELLO"), ("World.", - "PEOPLE!")) == "HELLO PEOPLE!" - doAssert "aaaa".multiReplace(("a", "aa"), ("aa", "bb")) == "aaaaaaaa" - - # `parseEnum`, ref issue #14030 - # check enum defined at top level # xxx this is probably irrelevant, and pollutes scope - # for remaining tests - type - Foo = enum - A = -10 - B = "bb" - C = (-5, "ccc") - D = 15 - E = "ee" # check that we count enum fields correctly - - block: # parseEnum - block: - let a = parseEnum[Foo]("A") - let b = parseEnum[Foo]("bb") - let c = parseEnum[Foo]("ccc") - let d = parseEnum[Foo]("D") - let e = parseEnum[Foo]("ee") - doAssert a == A - doAssert b == B - doAssert c == C - doAssert d == D - doAssert e == E - try: - let f = parseEnum[Foo]("Bar") - doAssert false - except ValueError: - discard - - # finally using default - let g = parseEnum[Foo]("Bar", A) - doAssert g == A - - block: # bug #19463 - const CAMPAIGN_TABLE = "wikientries_campaign" - const CHARACTER_TABLE = "wikientries_character" - - type Tables = enum - a = CAMPAIGN_TABLE, - b = CHARACTER_TABLE, - - let myA = CAMPAIGN_TABLE - doAssert $parseEnum[Tables](myA) == "wikientries_campaign" - - block: # check enum defined in block - type - Bar = enum - V - W = "ww" - X = (3, "xx") - Y = 10 - Z = "zz" # check that we count enum fields correctly - - let a = parseEnum[Bar]("V") - let b = parseEnum[Bar]("ww") - let c = parseEnum[Bar]("xx") - let d = parseEnum[Bar]("Y") - let e = parseEnum[Bar]("zz") - doAssert a == V - doAssert b == W - doAssert c == X - doAssert d == Y - doAssert e == Z - try: - let f = parseEnum[Bar]("Baz") - doAssert false - except ValueError: - discard - - # finally using default - let g = parseEnum[Bar]("Baz", V) - doAssert g == V - - block: # check ambiguous enum fails to parse - type - Ambig = enum - f1 = "A" - f2 = "B" - f3 = "A" - - doAssert not compiles((let a = parseEnum[Ambig]("A"))) - - block: # check almost ambiguous enum - type - AlmostAmbig = enum - f1 = "someA" - f2 = "someB" - f3 = "SomeA" - - let a = parseEnum[AlmostAmbig]("someA") - let b = parseEnum[AlmostAmbig]("someB") - let c = parseEnum[AlmostAmbig]("SomeA") - doAssert a == f1 - doAssert b == f2 - doAssert c == f3 - - block: # parseEnum TODO: merge above - type MyEnum = enum enA, enB, enC, enuD, enE - doAssert parseEnum[MyEnum]("enu_D") == enuD - - doAssert parseEnum("invalid enum value", enC) == enC - - block: # indentation - doAssert 0 == indentation """ -hey - low - there -""" - doAssert 2 == indentation """ - hey - low - there -""" - doAssert 2 == indentation """ hey - low - there -""" - doAssert 2 == indentation """ hey - low - there""" - doAssert 0 == indentation "" - doAssert 0 == indentation " \n \n" - doAssert 0 == indentation " " - - block: # indent - doAssert " foo\n bar".indent(4, "Q") == "QQQQ foo\nQQQQ bar" - - block: # unindent - doAssert """~~!!foo -~~!!bar -~~!!baz""".unindent(2, "~~!!") == "foo\nbar\nbaz" - - doAssert """~~!!foo -~~!!bar -~~!!baz""".unindent(2, "~~!!aa") == "~~!!foo\n~~!!bar\n~~!!baz" - doAssert """~~foo -~~ bar -~~ baz""".unindent(4, "~") == "foo\n bar\n baz" - doAssert """foo -bar - baz - """.unindent(4) == "foo\nbar\nbaz\n" - doAssert """foo - bar - baz - """.unindent(2) == "foo\n bar\n baz\n" - doAssert """foo - bar - baz - """.unindent(100) == "foo\nbar\nbaz\n" - - doAssert """foo - foo - bar - """.unindent() == "foo\nfoo\nbar\n" - - block: # formatBiggestFloat - disableVm: - doAssert formatBiggestFloat(1234.567, ffDecimal, -1) == "1234.567000" - when not defined(js): - doAssert formatBiggestFloat(1234.567, ffDecimal, 0) == "1235." # bugs 8242, 12586 - doAssert formatBiggestFloat(1234.567, ffDecimal, 1) == "1234.6" - doAssert formatBiggestFloat(0.00000000001, ffDecimal, 11) == "0.00000000001" - doAssert formatBiggestFloat(0.00000000001, ffScientific, 1, ',') in - ["1,0e-11", "1,0e-011"] - block: # formatFloat - disableVm: - # bug #6589 - when not defined(js): - doAssert formatFloat(123.456, ffScientific, precision = -1) == "1.234560e+02" - - block: # `%` - doAssert "$# $3 $# $#" % ["a", "b", "c"] == "a c b c" - doAssert "${1}12 ${-1}$2" % ["a", "b"] == "a12 bb" - doAssert "$animal eats $food." % ["animal", "The cat", "food", "fish"] == - "The cat eats fish." - - block: # formatSize - disableVm: - when not defined(js): - doAssert formatSize((1'i64 shl 31) + (300'i64 shl 20)) == "2.293GiB" # <=== bug #8231 - doAssert formatSize((2.234*1024*1024).int) == "2.234MiB" - doAssert formatSize(4096) == "4KiB" - doAssert formatSize(4096, prefix = bpColloquial, includeSpace = true) == "4 kB" - doAssert formatSize(4096, includeSpace = true) == "4 KiB" - doAssert formatSize(5_378_934, prefix = bpColloquial, decimalSep = ',') == "5,13MB" - - block: # formatEng - disableVm: - doAssert formatEng(0, 2, trim = false) == "0.00" - doAssert formatEng(0, 2) == "0" - doAssert formatEng(53, 2, trim = false) == "53.00" - doAssert formatEng(0.053, 2, trim = false) == "53.00e-3" - doAssert formatEng(0.053, 4, trim = false) == "53.0000e-3" - doAssert formatEng(0.053, 4, trim = true) == "53e-3" - doAssert formatEng(0.053, 0) == "53e-3" - doAssert formatEng(52731234) == "52.731234e6" - doAssert formatEng(-52731234) == "-52.731234e6" - doAssert formatEng(52731234, 1) == "52.7e6" - doAssert formatEng(-52731234, 1) == "-52.7e6" - doAssert formatEng(52731234, 1, decimalSep = ',') == "52,7e6" - doAssert formatEng(-52731234, 1, decimalSep = ',') == "-52,7e6" - - doAssert formatEng(4100, siPrefix = true, unit = "V") == "4.1 kV" - doAssert formatEng(4.1, siPrefix = true, unit = "V", - useUnitSpace = true) == "4.1 V" - doAssert formatEng(4.1, siPrefix = true) == "4.1" # Note lack of space - doAssert formatEng(4100, siPrefix = true) == "4.1 k" - doAssert formatEng(4.1, siPrefix = true, unit = "", - useUnitSpace = true) == "4.1 " # Includes space - doAssert formatEng(4100, siPrefix = true, unit = "") == "4.1 k" - doAssert formatEng(4100) == "4.1e3" - doAssert formatEng(4100, unit = "V", useUnitSpace = true) == "4.1e3 V" - doAssert formatEng(4100, unit = "", useUnitSpace = true) == "4.1e3 " - # Don't use SI prefix as number is too big - doAssert formatEng(3.1e22, siPrefix = true, unit = "a", - useUnitSpace = true) == "31e21 a" - # Don't use SI prefix as number is too small - doAssert formatEng(3.1e-25, siPrefix = true, unit = "A", - useUnitSpace = true) == "310e-27 A" - - block: # align - doAssert align("abc", 4) == " abc" - doAssert align("a", 0) == "a" - doAssert align("1232", 6) == " 1232" - doAssert align("1232", 6, '#') == "##1232" - - block: # alignLeft - doAssert alignLeft("abc", 4) == "abc " - doAssert alignLeft("a", 0) == "a" - doAssert alignLeft("1232", 6) == "1232 " - doAssert alignLeft("1232", 6, '#') == "1232##" - - block: # center - doAssert center("foo", 13) == " foo " - doAssert center("foo", 0) == "foo" - doAssert center("foo", 3, fillChar = 'a') == "foo" - doAssert center("foo", 10, fillChar = '\t') == "\t\t\tfoo\t\t\t\t" - - block: # count - doAssert count("foofoofoo", "foofoo") == 1 - doAssert count("foofoofoo", "foofoo", overlapping = true) == 2 - doAssert count("foofoofoo", 'f') == 3 - doAssert count("foofoofoobar", {'f', 'b'}) == 4 - - block: # isAlphaAscii - doAssert isAlphaAscii('r') - doAssert isAlphaAscii('A') - doAssert(not isAlphaAscii('$')) - - block: # isAlphaNumeric - doAssert isAlphaNumeric('3') - doAssert isAlphaNumeric('R') - doAssert(not isAlphaNumeric('!')) - - block: # isDigit - doAssert isDigit('3') - doAssert(not isDigit('a')) - doAssert(not isDigit('%')) - - block: # isSpaceAscii - doAssert isSpaceAscii('\t') - doAssert isSpaceAscii('\l') - doAssert(not isSpaceAscii('A')) - - block: # isEmptyOrWhitespace - doAssert(isEmptyOrWhitespace("")) - doAssert(isEmptyOrWhitespace(" ")) - doAssert(isEmptyOrWhitespace("\t\l \v\r\f")) - doAssert(not isEmptyOrWhitespace("ABc \td")) - - block: # isLowerAscii - doAssert isLowerAscii('a') - doAssert isLowerAscii('z') - doAssert(not isLowerAscii('A')) - doAssert(not isLowerAscii('5')) - doAssert(not isLowerAscii('&')) - doAssert(not isLowerAscii(' ')) - - block: # isUpperAscii - doAssert isUpperAscii('A') - doAssert(not isUpperAscii('b')) - doAssert(not isUpperAscii('5')) - doAssert(not isUpperAscii('%')) - - block: # unescape - doAssert(unescape(r"\x013", "", "") == "\x013") - - block: # join - doAssert join(["foo", "bar", "baz"]) == "foobarbaz" - doAssert join(@["foo", "bar", "baz"], ", ") == "foo, bar, baz" - doAssert join([1, 2, 3]) == "123" - doAssert join(@[1, 2, 3], ", ") == "1, 2, 3" - - block: # startsWith / endsWith - var s = "abcdef" - doAssert s.startsWith('a') - doAssert s.startsWith('b') == false - doAssert s.endsWith('f') - doAssert s.endsWith('a') == false - doAssert s.endsWith('\0') == false - - block: # nimIdentNormalize - doAssert nimIdentNormalize("") == "" - doAssert nimIdentNormalize("foo") == "foo" - doAssert nimIdentNormalize("foo_bar") == "foobar" - doAssert nimIdentNormalize("Foo_bar") == "Foobar" - doAssert nimIdentNormalize("_Foo_bar") == "_foobar" - - block: # bug #19500 - doAssert "abc \0 def".find("def") == 6 - doAssert "abc \0 def".find('d') == 6 - - -static: main() -main() diff --git a/tests/stdlib/tsugar.nim b/tests/stdlib/tsugar.nim deleted file mode 100644 index 1b629165a..000000000 --- a/tests/stdlib/tsugar.nim +++ /dev/null @@ -1,305 +0,0 @@ -discard """ - output: ''' -x + y = 30 -''' -""" -import std/[sugar, algorithm, random, sets, tables, strutils, sequtils] -import std/[syncio, assertions] - -type # for capture test, ref #20679 - FooCapture = ref object - x: int - -template main() = - block: # `=>` - block: - let f1 = () => 42 - doAssert f1() == 42 - - let f2 = (x: int) => x + 1 - doAssert f2(42) == 43 - - let f3 = (x, y: int) => x + y - doAssert f3(1, 2) == 3 - - var x = 0 - let f4 = () => (x = 12) - f4() - doAssert x == 12 - - let f5 = () => (discard) # simplest proc that returns void - f5() - - block: - proc call1(f: () -> int): int = f() - doAssert call1(() => 12) == 12 - - proc call2(f: int -> int): int = f(42) - doAssert call2(x => x) == 42 - doAssert call2((x) => x) == 42 - doAssert call2((x: int) => x) == 42 - - proc call3(f: (int, int) -> int): int = f(1, 2) - doAssert call3((x, y) => x + y) == 3 - doAssert call3((x, y: int) => x + y) == 3 - doAssert call3((x: int, y: int) => x + y) == 3 - - var a = 0 - proc call4(f: int -> void) = f(42) - call4((x: int) => (a = x)) - doAssert a == 42 - - proc call5(f: (int {.noSideEffect.} -> int)): int = f(42) - doAssert call5(x {.noSideEffect.} => x + 1) == 43 - - block: # `->` - doAssert $(() -> int) == "proc (): int{.closure.}" - doAssert $(float -> int) == "proc (i0: float): int{.closure.}" - doAssert $((float) -> int) == "proc (i0: float): int{.closure.}" - doAssert $((float, bool) -> int) == "proc (i0: float, i1: bool): int{.closure.}" - - doAssert $(() -> void) == "proc (){.closure.}" - doAssert $(float -> void) == "proc (i0: float){.closure.}" - doAssert $((float) -> void) == "proc (i0: float){.closure.}" - doAssert $((float, bool) -> void) == "proc (i0: float, i1: bool){.closure.}" - - doAssert $(() {.inline.} -> int) == "proc (): int{.inline.}" - doAssert $(float {.inline.} -> int) == "proc (i0: float): int{.inline.}" - doAssert $((float) {.inline.} -> int) == "proc (i0: float): int{.inline.}" - doAssert $((float, bool) {.inline.} -> int) == "proc (i0: float, i1: bool): int{.inline.}" - - block: # capture - var closure1: () -> int - for i in 0 .. 10: - if i == 5: - capture i: - closure1 = () => i - doAssert closure1() == 5 - - var closure2: () -> (int, int) - for i in 0 .. 10: - for j in 0 .. 10: - if i == 5 and j == 3: - capture i, j: - closure2 = () => (i, j) - doAssert closure2() == (5, 3) - - block: # bug #16967 - var s = newSeq[proc (): int](5) - {.push exportc.} - proc bar() = - for i in 0 ..< s.len: - let foo = i + 1 - capture foo: - s[i] = proc(): int = foo - {.pop.} - - bar() - - for i, p in s.pairs: - let foo = i + 1 - doAssert p() == foo - - block: # issue #20679 - # this should compile. Previously was broken as `var int` is an `nnkHiddenDeref` - # which was not handled correctly - - block: - var x = 5 - var s1 = newSeq[proc (): int](2) - proc function(data: var int) = - for i in 0 ..< 2: - data = (i+1) * data - capture data: - s1[i] = proc(): int = data - function(x) - doAssert s1[0]() == 5 - doAssert s1[1]() == 10 - - - block: - var y = @[5, 10] - var s2 = newSeq[proc (): seq[int]](2) - proc functionS(data: var seq[int]) = - for i in 0 ..< 2: - data.add (i+1) * 5 - capture data: - s2[i] = proc(): seq[int] = data - functionS(y) - doAssert s2[0]() == @[5, 10, 5] - doAssert s2[1]() == @[5, 10, 5, 10] - - - template typeT(typ, val: untyped): untyped = - var x = val - var s = newSeq[proc (): typ](2) - - proc functionT[T](data: var T) = - for i in 0 ..< 2: - if i == 1: - data = default(T) - capture data: - s[i] = proc (): T = data - - functionT(x) - doAssert s[0]() == val - doAssert s[1]() == x # == default - doAssert s[1]() == default(typ) - - block: - var x = 1.1 - typeT(float, x) - block: - var x = "hello" - typeT(string, x) - block: - var f = FooCapture(x: 5) - typeT(FooCapture, f) - - block: # dup - block dup_with_field: - type - Foo = object - col, pos: int - name: string - - proc inc_col(foo: var Foo) = inc(foo.col) - proc inc_pos(foo: var Foo) = inc(foo.pos) - proc name_append(foo: var Foo, s: string) = foo.name &= s - - let a = Foo(col: 1, pos: 2, name: "foo") - block: - let b = a.dup(inc_col, inc_pos): - _.pos = 3 - name_append("bar") - inc_pos - - doAssert(b == Foo(col: 2, pos: 4, name: "foobar")) - - block: - let b = a.dup(inc_col, pos = 3, name = "bar"): - name_append("bar") - inc_pos - - doAssert(b == Foo(col: 2, pos: 4, name: "barbar")) - - block: - var a = @[1, 2, 3, 4, 5, 6, 7, 8, 9] - doAssert dup(a, sort(_)) == sorted(a) - doAssert a.dup(sort) == sorted(a) - # Chaining: - var aCopy = a - aCopy.insert(10) - doAssert a.dup(insert(10)).dup(sort()) == sorted(aCopy) - - block: - when nimvm: discard - else: - const b = @[0, 1, 2] - discard b.dup shuffle() - doAssert b[0] == 0 - doAssert b[1] == 1 - - block: # collect - let data = @["bird", "word"] # if this gets stuck in your head, its not my fault - - doAssert collect(newSeq, for (i, d) in data.pairs: (if i mod 2 == 0: d)) == @["bird"] - doAssert collect(initTable(2), for (i, d) in data.pairs: {i: d}) == - {0: "bird", 1: "word"}.toTable - doAssert collect(initHashSet(), for d in data.items: {d}) == data.toHashSet - - block: - let x = collect(newSeqOfCap(4)): - for (i, d) in data.pairs: - if i mod 2 == 0: d - doAssert x == @["bird"] - - block: # bug #12874 - let bug = collect( - newSeq, - for (i, d) in data.pairs:( - block: - if i mod 2 == 0: - d - else: - d & d - ) - ) - doAssert bug == @["bird", "wordword"] - - block: - let y = collect(newSeq): - for (i, d) in data.pairs: - try: parseInt(d) except: 0 - doAssert y == @[0, 0] - - block: - let z = collect(newSeq): - for (i, d) in data.pairs: - case d - of "bird": "word" - else: d - doAssert z == @["word", "word"] - - block: - proc tforum(): seq[int] = - collect(newSeq): - for y in 0..10: - if y mod 5 == 2: - for x in 0..y: - x - doAssert tforum() == @[0, 1, 2, 0, 1, 2, 3, 4, 5, 6, 7] - - block: - let x = collect: - for d in data.items: - when d is int: "word" - else: d - doAssert x == @["bird", "word"] - - block: - doAssert collect(for (i, d) in pairs(data): (i, d)) == @[(0, "bird"), (1, "word")] - doAssert collect(for d in data.items: (try: parseInt(d) except: 0)) == @[0, 0] - doAssert collect(for (i, d) in pairs(data): {i: d}) == - {1: "word", 0: "bird"}.toTable - doAssert collect(for d in data.items: {d}) == data.toHashSet - - block: # bug #14332 - template foo = - discard collect(newSeq, for i in 1..3: i) - foo() - -proc mainProc() = - block: # dump - # symbols in templates are gensym'd - let - x = 10 - y = 20 - dump(x + y) # x + y = 30 - - block: # dumpToString - template square(x): untyped = x * x - let x = 10 - doAssert dumpToString(square(x)) == "square(x): x * x = 100" - let s = dumpToString(doAssert 1+1 == 2) - doAssert "failedAssertImpl" in s - let s2 = dumpToString: - doAssertRaises(AssertionDefect): doAssert false - doAssert "except AssertionDefect" in s2 - - block: # bug #20704 - proc test() = - var xs, ys: seq[int] - for i in 0..5: - xs.add(i) - - xs.apply(d => ys.add(d)) - doAssert ys == @[0, 1, 2, 3, 4, 5] - - test() - -static: - main() - mainProc() -main() -mainProc() diff --git a/tests/stdlib/tsums.nim b/tests/stdlib/tsums.nim deleted file mode 100644 index 071e0b303..000000000 --- a/tests/stdlib/tsums.nim +++ /dev/null @@ -1,23 +0,0 @@ -import std/sums -from math import pow -import std/assertions - -var epsilon = 1.0 -while 1.0 + epsilon != 1.0: - epsilon /= 2.0 -let data = @[1.0, epsilon, -epsilon] -doAssert sumKbn(data) == 1.0 -# doAssert sumPairs(data) != 1.0 # known to fail in 64 bits -doAssert (1.0 + epsilon) - epsilon != 1.0 - -var tc1: seq[float] -for n in 1 .. 1000: - tc1.add 1.0 / n.float -doAssert sumKbn(tc1) == 7.485470860550345 -doAssert sumPairs(tc1) == 7.485470860550345 - -var tc2: seq[float] -for n in 1 .. 1000: - tc2.add pow(-1.0, n.float) / n.float -doAssert sumKbn(tc2) == -0.6926474305598203 -doAssert sumPairs(tc2) == -0.6926474305598204 diff --git a/tests/stdlib/tsysrand.nim b/tests/stdlib/tsysrand.nim deleted file mode 100644 index e6b65e70f..000000000 --- a/tests/stdlib/tsysrand.nim +++ /dev/null @@ -1,34 +0,0 @@ -discard """ - targets: "c cpp js" - matrix: "--experimental:vmopsDanger" -""" - -import std/sysrand -import std/assertions - -template main() = - block: - var x = array[5, byte].default - doAssert urandom(x) - - block: - var x = newSeq[byte](5) - doAssert urandom(x) - - block: - var x = @[byte(0), 0, 0, 0, 0] - doAssert urandom(x) - - block: - var x = @[byte(1), 2, 3, 4, 5] - doAssert urandom(x) - - block: - doAssert urandom(0).len == 0 - doAssert urandom(10).len == 10 - doAssert urandom(20).len == 20 - doAssert urandom(120).len == 120 - doAssert urandom(113).len == 113 - doAssert urandom(1234) != urandom(1234) # unlikely to fail in practice - -main() diff --git a/tests/stdlib/tsystem.nim b/tests/stdlib/tsystem.nim deleted file mode 100644 index 810c3af04..000000000 --- a/tests/stdlib/tsystem.nim +++ /dev/null @@ -1,171 +0,0 @@ -discard """ - targets: "c cpp js" -""" - -import stdtest/testutils -import std/assertions - -# TODO: in future work move existing `system` tests here, where they belong - - -template main = - block: # closure - proc outer() = - var a = 0 - proc inner1 = a.inc - proc inner2 = discard - doAssert inner1 is "closure" - doAssert inner2 isnot "closure" - doAssert inner1 is (proc) - doAssert inner2 is (proc) - let inner1b = inner1 - doAssert inner1b is "closure" - doAssert inner1b == inner1 - outer() - - block: # rawProc, rawProc, bug #17911 - proc outer() = - var a = 0 - var b = 0 - proc inner1() = a.inc - proc inner2() = a += 2 - proc inner3() = b.inc - let inner1b = inner1 - doAssert inner2 != inner1 - doAssert inner3 != inner1 - whenVMorJs: discard - do: - doAssert rawProc(inner1b) == rawProc(inner1) - doAssert rawProc(inner2) != rawProc(inner1) - doAssert rawProc(inner3) != rawProc(inner1) - - doAssert rawEnv(inner1b) == rawEnv(inner1) - doAssert rawEnv(inner2) == rawEnv(inner1) # because both use `a` - # doAssert rawEnv(inner3) != rawEnv(inner1) # because `a` vs `b` # this doesn't hold - outer() - - block: # system.delete - block: - var s = @[1] - s.delete(0) - doAssert s == @[] - - block: - var s = @["foo", "bar"] - s.delete(1) - doAssert s == @["foo"] - - when false: - var s: seq[string] - doAssertRaises(IndexDefect): - s.delete(0) - - block: - doAssert not compiles(@["foo"].delete(-1)) - - block: # bug #6710 - var s = @["foo"] - s.delete(0) - doAssert s == @[] - - when false: # bug #16544: deleting out of bounds index should raise - var s = @["foo"] - doAssertRaises(IndexDefect): - s.delete(1) - -static: main() -main() - -# bug #19967 -block: - type - X = object - a: string - b: set[char] - - var y = X(b: {'a'}) - - reset(y) - - doAssert y.b == {} - -block: - type - X = object - a: string - b: int - - var y = X(b: 1314) - - reset(y) - - doAssert y.b == 0 - -block: - type - X = object - a: string - b: float - - var y = X(b: 1314.521) - - reset(y) - - doAssert y.b == 0.0 - -block: - type - X = object - a: string - b: string - - var y = X(b: "1314") - - reset(y) - - doAssert y.b == "" - -block: - type - X = object - a: string - b: seq[int] - - var y = X(b: @[1, 3]) - - reset(y) - - doAssert y.b == @[] - -block: - type - X = object - a: string - b: tuple[a: int, b: string] - - var y = X(b: (1, "cc")) - - reset(y) - - doAssert y.b == (0, "") - -block: - type - Color = enum - Red, Blue, Yellow - X = object - a: string - b: set[Color] - - var y = X(b: {Red, Blue}) - - reset(y) - doAssert y.b == {} - -block: # bug #20516 - type Foo = object - x {.bitsize:4.}: uint - y {.bitsize:4.}: uint - - when not defined(js): - let a = create(Foo) diff --git a/tests/stdlib/ttables.nim b/tests/stdlib/ttables.nim deleted file mode 100644 index ab6502411..000000000 --- a/tests/stdlib/ttables.nim +++ /dev/null @@ -1,312 +0,0 @@ -import tables, hashes -import std/assertions - -type - Person = object - firstName, lastName: string - -proc hash(x: Person): Hash = - ## Piggyback on the already available string hash proc. - ## - ## Without this proc nothing works! - result = x.firstName.hash !& x.lastName.hash - result = !$result - -var - salaries = initTable[Person, int]() - p1, p2: Person -p1.firstName = "Jon" -p1.lastName = "Ross" -salaries[p1] = 30_000 -p2.firstName = "소진" -p2.lastName = "박" -salaries[p2] = 45_000 -var - s2 = initOrderedTable[Person, int]() - s3 = initCountTable[Person]() -s2[p1] = 30_000 -s2[p2] = 45_000 -s3[p1] = 30_000 -s3[p2] = 45_000 - -block: # Ordered table should preserve order after deletion - var - s4 = initOrderedTable[int, int]() - s4[1] = 1 - s4[2] = 2 - s4[3] = 3 - - var prev = 0 - for i in s4.values: - doAssert(prev < i) - prev = i - - s4.del(2) - doAssert(2 notin s4) - doAssert(s4.len == 2) - prev = 0 - for i in s4.values: - doAssert(prev < i) - prev = i - -block: # Deletion from OrderedTable should account for collision groups. See issue #5057. - # The bug is reproducible only with exact keys - const key1 = "boy_jackpot.inGamma" - const key2 = "boy_jackpot.outBlack" - - var t = { - key1: 0, - key2: 0 - }.toOrderedTable() - - t.del(key1) - doAssert(t.len == 1) - doAssert(key2 in t) - -var - t1 = initCountTable[string]() - t2 = initCountTable[string]() -t1.inc("foo") -t1.inc("bar", 2) -t1.inc("baz", 3) -t2.inc("foo", 4) -t2.inc("bar") -t2.inc("baz", 11) -merge(t1, t2) -doAssert(t1["foo"] == 5) -doAssert(t1["bar"] == 3) -doAssert(t1["baz"] == 14) - -let - t1r = newCountTable[string]() - t2r = newCountTable[string]() -t1r.inc("foo") -t1r.inc("bar", 2) -t1r.inc("baz", 3) -t2r.inc("foo", 4) -t2r.inc("bar") -t2r.inc("baz", 11) -merge(t1r, t2r) -doAssert(t1r["foo"] == 5) -doAssert(t1r["bar"] == 3) -doAssert(t1r["baz"] == 14) - -var - t1l = initCountTable[string]() - t2l = initCountTable[string]() -t1l.inc("foo") -t1l.inc("bar", 2) -t1l.inc("baz", 3) -t2l.inc("foo", 4) -t2l.inc("bar") -t2l.inc("baz", 11) - -block: - const testKey = "TESTKEY" - let t: CountTableRef[string] = newCountTable[string]() - - # Before, does not compile with error message: - #test_counttable.nim(7, 43) template/generic instantiation from here - #lib/pure/collections/tables.nim(117, 21) template/generic instantiation from here - #lib/pure/collections/tableimpl.nim(32, 27) Error: undeclared field: 'hcode - doAssert 0 == t[testKey] - t.inc(testKey, 3) - doAssert 3 == t[testKey] - -block: - # Clear tests - var clearTable = newTable[int, string]() - clearTable[42] = "asd" - clearTable[123123] = "piuyqwb " - doAssert clearTable[42] == "asd" - clearTable.clear() - doAssert(not clearTable.hasKey(123123)) - doAssert clearTable.getOrDefault(42) == "" - -block: #5482 - var a = [("wrong?", "foo"), ("wrong?", "foo2")].newOrderedTable() - var b = newOrderedTable[string, string](initialSize = 2) - b["wrong?"] = "foo" - b["wrong?"] = "foo2" - doAssert a == b - -block: #5482 - var a = {"wrong?": "foo", "wrong?": "foo2"}.newOrderedTable() - var b = newOrderedTable[string, string](initialSize = 2) - b["wrong?"] = "foo" - b["wrong?"] = "foo2" - doAssert a == b - -block: #5487 - var a = {"wrong?": "foo", "wrong?": "foo2"}.newOrderedTable() - var b = newOrderedTable[string, string]() # notice, default size! - b["wrong?"] = "foo" - b["wrong?"] = "foo2" - doAssert a == b - -block: #5487 - var a = [("wrong?", "foo"), ("wrong?", "foo2")].newOrderedTable() - var b = newOrderedTable[string, string]() # notice, default size! - b["wrong?"] = "foo" - b["wrong?"] = "foo2" - doAssert a == b - -block: - var a = {"wrong?": "foo", "wrong?": "foo2"}.newOrderedTable() - var b = [("wrong?", "foo"), ("wrong?", "foo2")].newOrderedTable() - var c = newOrderedTable[string, string]() # notice, default size! - c["wrong?"] = "foo" - c["wrong?"] = "foo2" - doAssert a == b - doAssert a == c - -block: #6250 - let - a = {3: 1}.toOrderedTable - b = {3: 2}.toOrderedTable - doAssert((a == b) == false) - doAssert((b == a) == false) - -block: #6250 - let - a = {3: 2}.toOrderedTable - b = {3: 2}.toOrderedTable - doAssert((a == b) == true) - doAssert((b == a) == true) - -block: # CountTable.smallest - let t = toCountTable([0, 0, 5, 5, 5]) - doAssert t.smallest == (0, 2) - -block: #10065 - let t = toCountTable("abracadabra") - doAssert t['z'] == 0 - - var t_mut = toCountTable("abracadabra") - doAssert t_mut['z'] == 0 - # the previous read may not have modified the table. - doAssert t_mut.hasKey('z') == false - t_mut['z'] = 1 - doAssert t_mut['z'] == 1 - doAssert t_mut.hasKey('z') == true - -block: #12813 #13079 - var t = toCountTable("abracadabra") - doAssert len(t) == 5 - - t['a'] = 0 # remove a key - doAssert len(t) == 4 - -block: - var tp: Table[string, string] = initTable[string, string]() - doAssert "test1" == tp.getOrDefault("test1", "test1") - tp["test2"] = "test2" - doAssert "test2" == tp.getOrDefault("test2", "test1") - var tr: TableRef[string, string] = newTable[string, string]() - doAssert "test1" == tr.getOrDefault("test1", "test1") - tr["test2"] = "test2" - doAssert "test2" == tr.getOrDefault("test2", "test1") - var op: OrderedTable[string, string] = initOrderedTable[string, string]() - doAssert "test1" == op.getOrDefault("test1", "test1") - op["test2"] = "test2" - doAssert "test2" == op.getOrDefault("test2", "test1") - var orf: OrderedTableRef[string, string] = newOrderedTable[string, string]() - doAssert "test1" == orf.getOrDefault("test1", "test1") - orf["test2"] = "test2" - doAssert "test2" == orf.getOrDefault("test2", "test1") - -block tableWithoutInit: - var - a: Table[string, int] - b: Table[string, int] - c: Table[string, int] - d: Table[string, int] - e: Table[string, int] - - a["a"] = 7 - doAssert a.hasKey("a") - doAssert a.len == 1 - doAssert a["a"] == 7 - a["a"] = 9 - doAssert a.len == 1 - doAssert a["a"] == 9 - - doAssert b.hasKeyOrPut("b", 5) == false - doAssert b.hasKey("b") - doAssert b.hasKeyOrPut("b", 8) - doAssert b["b"] == 5 - - doAssert c.getOrDefault("a") == 0 - doAssert c.getOrDefault("a", 3) == 3 - c["a"] = 6 - doAssert c.getOrDefault("a", 3) == 6 - - doAssert d.mgetOrPut("a", 3) == 3 - doAssert d.mgetOrPut("a", 6) == 3 - - var x = 99 - doAssert e.pop("a", x) == false - doAssert x == 99 - e["a"] = 77 - doAssert e.pop("a", x) - doAssert x == 77 - -block orderedTableWithoutInit: - var - a: OrderedTable[string, int] - b: OrderedTable[string, int] - c: OrderedTable[string, int] - d: OrderedTable[string, int] - - a["a"] = 7 - doAssert a.hasKey("a") - doAssert a.len == 1 - doAssert a["a"] == 7 - a["a"] = 9 - doAssert a.len == 1 - doAssert a["a"] == 9 - - doAssert b.hasKeyOrPut("b", 5) == false - doAssert b.hasKey("b") - doAssert b.hasKeyOrPut("b", 8) - doAssert b["b"] == 5 - - doAssert c.getOrDefault("a") == 0 - doAssert c.getOrDefault("a", 3) == 3 - c["a"] = 6 - doAssert c.getOrDefault("a", 3) == 6 - - doAssert d.mgetOrPut("a", 3) == 3 - doAssert d.mgetOrPut("a", 6) == 3 - -block countTableWithoutInit: - var - a: CountTable[string] - b: CountTable[string] - c: CountTable[string] - d: CountTable[string] - e: CountTable[string] - - a["a"] = 7 - doAssert a.hasKey("a") - doAssert a.len == 1 - doAssert a["a"] == 7 - a["a"] = 9 - doAssert a.len == 1 - doAssert a["a"] == 9 - - doAssert b["b"] == 0 - b.inc("b") - doAssert b["b"] == 1 - - doAssert c.getOrDefault("a") == 0 - doAssert c.getOrDefault("a", 3) == 3 - c["a"] = 6 - doAssert c.getOrDefault("a", 3) == 6 - - e["f"] = 3 - merge(d, e) - doAssert d.hasKey("f") - d.inc("f") - merge(d, e) - doAssert d["f"] == 7 diff --git a/tests/stdlib/ttasks.nim b/tests/stdlib/ttasks.nim deleted file mode 100644 index 4889d49d9..000000000 --- a/tests/stdlib/ttasks.nim +++ /dev/null @@ -1,507 +0,0 @@ -discard """ - targets: "c cpp" - matrix: "--gc:orc --threads:off" -""" - -import std/[tasks, strformat] -import std/assertions - -block: - var s = "" - proc `+`(x: int, y: string) = - s.add $x & y - - let literal = "Nim" - let t = toTask(521 + literal) - t.invoke() - - doAssert s == "521Nim" - -block: - var s = "" - proc `!`(x: int) = - s.add $x - - let t = toTask !12 - t.invoke() - - doAssert s == "12" - - -block: - block: - var called = 0 - proc hello(x: static range[1 .. 5]) = - called += x - - let b = toTask hello(3) - b.invoke() - doAssert called == 3 - b.invoke() - doAssert called == 6 - - block: - var called = 0 - proc hello(x: range[1 .. 5]) = - called += x - - let b = toTask hello(3) - b.invoke() - doAssert called == 3 - b.invoke() - doAssert called == 6 - - block: - var called = 0 - proc hello(x: 1 .. 5) = - called += x - - let b = toTask hello(3) - b.invoke() - doAssert called == 3 - b.invoke() - doAssert called == 6 - - block: - var temp = "" - proc hello(a: int or seq[string]) = - when a is seq[string]: - for s in a: - temp.add s - else: - temp.addInt a - - let x = @["1", "2", "3", "4"] - let b = toTask hello(x) - b.invoke() - doAssert temp == "1234" - b.invoke() - doAssert temp == "12341234" - - - block: - var temp = "" - - proc hello(a: int or string) = - when a is string: - temp.add a - - let x = "!2" - - let b = toTask hello(x) - b.invoke() - doAssert temp == x - - block: - var temp = "" - proc hello(a: int or string) = - when a is string: - temp.add a - - let x = "!2" - let b = toTask hello(x) - b.invoke() - doAssert temp == x - - block: - var x = 0 - proc hello(typ: typedesc) = - x += typ(12) - - let b = toTask hello(int) - b.invoke() - doAssert x == 12 - - block: - var temp = "" - proc hello(a: int or seq[string]) = - when a is seq[string]: - for s in a: - temp.add s - - let x = @["1", "2", "3", "4"] - let b = toTask hello(x) - b.invoke() - doAssert temp == "1234" - - block: - var temp = "" - proc hello(a: int | string) = - when a is string: - temp.add a - - let x = "!2" - let b = toTask hello(x) - b.invoke() - doAssert temp == x - - block: - var x = 0 - proc hello(a: int | string) = - when a is int: - x = a - - let b = toTask hello(12) - b.invoke() - doAssert x == 12 - - block: - var a1: seq[int] - var a2 = 0 - proc hello(c: seq[int], a: int) = - a1 = c - a2 = a - - let x = 12 - var y = @[1, 3, 1, 4, 5, x, 1] - let b = toTask hello(y, 12) - b.invoke() - - doAssert a1 == y - doAssert a2 == x - - block: - var a1: seq[int] - var a2 = 0 - proc hello(c: seq[int], a: int) = - a1 = c - a2 = a - var x = 2 - let b = toTask hello(@[1, 3, 1, 4, 5, x, 1], 12) - b.invoke() - - doAssert a1 == @[1, 3, 1, 4, 5, x, 1] - doAssert a2 == 12 - - block: - var a1: array[7, int] - var a2 = 0 - proc hello(c: array[7, int], a: int) = - a1 = c - a2 = a - - let b = toTask hello([1, 3, 1, 4, 5, 2, 1], 12) - b.invoke() - - doAssert a1 == [1, 3, 1, 4, 5, 2, 1] - doAssert a2 == 12 - - block: - var a1: seq[int] - var a2 = 0 - proc hello(c: seq[int], a: int) = - a1 = c - a2 = a - - let b = toTask hello(@[1, 3, 1, 4, 5, 2, 1], 12) - b.invoke() - - doAssert a1 == @[1, 3, 1, 4, 5, 2, 1] - doAssert a2 == 12 - - block: - var a1: seq[int] - var a2 = 0 - proc hello(a: int, c: seq[int]) = - a1 = c - a2 = a - - let b = toTask hello(8, @[1, 3, 1, 4, 5, 2, 1]) - b.invoke() - - doAssert a1 == @[1, 3, 1, 4, 5, 2, 1] - doAssert a2 == 8 - - let c = toTask 8.hello(@[1, 3, 1, 4, 5, 2, 1]) - c.invoke() - - doAssert a1 == @[1, 3, 1, 4, 5, 2, 1] - doAssert a2 == 8 - - block: - var a1: seq[seq[int]] - var a2: int - proc hello(a: int, c: openArray[seq[int]]) = - a1 = @c - a2 = a - - let b = toTask hello(8, @[@[3], @[4], @[5], @[6], @[12], @[7]]) - b.invoke() - - doAssert a1 == @[@[3], @[4], @[5], @[6], @[12], @[7]] - doAssert a2 == 8 - - block: - var a1: seq[int] - var a2: int - proc hello(a: int, c: openArray[int]) = - a1 = @c - a2 = a - - let b = toTask hello(8, @[3, 4, 5, 6, 12, 7]) - b.invoke() - - doAssert a1 == @[3, 4, 5, 6, 12, 7] - doAssert a2 == 8 - - block: - var a1: seq[int] - var a2: int - proc hello(a: int, c: static varargs[int]) = - a1 = @c - a2 = a - - let b = toTask hello(8, @[3, 4, 5, 6, 12, 7]) - b.invoke() - - doAssert a1 == @[3, 4, 5, 6, 12, 7] - doAssert a2 == 8 - - block: - var a1: seq[int] - var a2: int - proc hello(a: int, c: static varargs[int]) = - a1 = @c - a2 = a - - let b = toTask hello(8, [3, 4, 5, 6, 12, 7]) - b.invoke() - - doAssert a1 == @[3, 4, 5, 6, 12, 7] - doAssert a2 == 8 - - block: - var a1: seq[int] - var a2: int - proc hello(a: int, c: varargs[int]) = - a1 = @c - a2 = a - - let x = 12 - let b = toTask hello(8, 3, 4, 5, 6, x, 7) - b.invoke() - - doAssert a1 == @[3, 4, 5, 6, 12, 7] - doAssert a2 == 8 - - block: - var x = 12 - - proc hello(x: ptr int) = - x[] += 12 - - let b = toTask hello(addr x) - b.invoke() - - doAssert x == 24 - - let c = toTask x.addr.hello - invoke(c) - - doAssert x == 36 - block: - type - Test = ref object - id: int - - var x = 0 - proc hello(a: int, c: static Test) = - x += a - x += c.id - - let b = toTask hello(8, Test(id: 12)) - b.invoke() - - doAssert x == 20 - - block: - type - Test = object - id: int - - var x = 0 - proc hello(a: int, c: static Test) = - x += a - x += c.id - - let b = toTask hello(8, Test(id: 12)) - b.invoke() - doAssert x == 20 - - block: - var x = 0 - proc hello(a: int, c: static seq[int]) = - x += a - for i in c: - x += i - - let b = toTask hello(8, @[3, 4, 5, 6, 12, 7]) - b.invoke() - doAssert x == 45 - - block: - var x = 0 - proc hello(a: int, c: static array[5, int]) = - x += a - for i in c: - x += i - - let b = toTask hello(8, [3, 4, 5, 6, 12]) - b.invoke() - doAssert x == 38 - - block: - var aVal = 0 - var cVal = "" - - proc hello(a: int, c: static string) = - aVal += a - cVal.add c - - var x = 1314 - let b = toTask hello(x, "hello") - b.invoke() - - doAssert aVal == x - doAssert cVal == "hello" - - block: - var aVal = "" - - proc hello(a: static string) = - aVal.add a - let b = toTask hello("hello") - b.invoke() - - doAssert aVal == "hello" - - block: - var aVal = 0 - var cVal = "" - - proc hello(a: static int, c: static string) = - aVal += a - cVal.add c - let b = toTask hello(8, "hello") - b.invoke() - - doAssert aVal == 8 - doAssert cVal == "hello" - - block: - var aVal = 0 - var cVal = 0 - - proc hello(a: static int, c: int) = - aVal += a - cVal += c - - let b = toTask hello(c = 0, a = 8) - b.invoke() - - doAssert aVal == 8 - doAssert cVal == 0 - - block: - var aVal = 0 - var cVal = 0 - - proc hello(a: int, c: static int) = - aVal += a - cVal += c - - let b = toTask hello(c = 0, a = 8) - b.invoke() - - doAssert aVal == 8 - doAssert cVal == 0 - - block: - var aVal = 0 - var cVal = 0 - - proc hello(a: static int, c: static int) = - aVal += a - cVal += c - - let b = toTask hello(0, 8) - b.invoke() - - doAssert aVal == 0 - doAssert cVal == 8 - - block: - var temp = "" - proc hello(x: int, y: seq[string], d = 134) = - temp = fmt"{x=} {y=} {d=}" - - - proc main() = - var x = @["23456"] - let t = toTask hello(2233, x) - t.invoke() - - doAssert temp == """x=2233 y=@["23456"] d=134""" - - main() - - - block: - var temp = "" - proc hello(x: int, y: seq[string], d = 134) = - temp.add fmt"{x=} {y=} {d=}" - - proc ok() = - temp = "ok" - - proc main() = - var x = @["23456"] - let t = toTask hello(2233, x) - t.invoke() - t.invoke() - - doAssert temp == """x=2233 y=@["23456"] d=134x=2233 y=@["23456"] d=134""" - - main() - - var x = @["4"] - let m = toTask hello(2233, x, 7) - m.invoke() - - doAssert temp == """x=2233 y=@["23456"] d=134x=2233 y=@["23456"] d=134x=2233 y=@["4"] d=7""" - - let n = toTask ok() - n.invoke() - - doAssert temp == "ok" - - block: - var called = 0 - block: - proc hello() = - inc called - - let a = toTask hello() - invoke(a) - - doAssert called == 1 - - block: - proc hello(a: int) = - inc called, a - - let b = toTask hello(13) - let c = toTask hello(a = 14) - b.invoke() - c.invoke() - - doAssert called == 28 - - block: - proc hello(a: int, c: int) = - inc called, a - - let b = toTask hello(c = 0, a = 8) - b.invoke() - - doAssert called == 36 diff --git a/tests/stdlib/ttempfiles.nim b/tests/stdlib/ttempfiles.nim deleted file mode 100644 index 1159e08ef..000000000 --- a/tests/stdlib/ttempfiles.nim +++ /dev/null @@ -1,50 +0,0 @@ -discard """ - joinable: false # not strictly necessary -""" - -import std/tempfiles -import std/[os, nre] -import std/[assertions, syncio] - -const - prefix = "D20210502T100442" # safety precaution to only affect files/dirs with this prefix - suffix = ".tmp" - -block: - var t1 = createTempFile(prefix, suffix) - var t2 = createTempFile(prefix, suffix) - defer: - close(t1.cfile) - close(t2.cfile) - removeFile(t1.path) - removeFile(t2.path) - - doAssert t1.path != t2.path - - let s = "1234" - write(t1.cfile, s) - doAssert readAll(t2.cfile) == "" - doAssert readAll(t1.cfile) == "" - t1.cfile.setFilePos 0 - doAssert readAll(t1.cfile) == s - -block: # createTempDir - doAssertRaises(OSError): discard createTempDir(prefix, suffix, "nonexistent") - - block: - let dir1 = createTempDir(prefix, suffix) - let dir2 = createTempDir(prefix, suffix) - defer: - removeDir(dir1) - removeDir(dir2) - doAssert dir1 != dir2 - - doAssert dirExists(dir1) - doAssert dir1.lastPathPart.contains(re"^D20210502T100442(\w+).tmp$") - doAssert dir1.parentDir == getTempDir().normalizePathEnd() - - block: - let dir3 = createTempDir(prefix, "_mytmp", ".") - doAssert dir3.lastPathPart.contains(re"^D20210502T100442(\w+)_mytmp$") - doAssert dir3.parentDir == "." # not getCurrentDir(): we honor the absolute/relative state of input `dir` - removeDir(dir3) diff --git a/tests/stdlib/tterminal.nim b/tests/stdlib/tterminal.nim deleted file mode 100644 index 16365e71c..000000000 --- a/tests/stdlib/tterminal.nim +++ /dev/null @@ -1,7 +0,0 @@ -discard """ - action: compile -""" -import terminal, colors - -styledEcho fgColor, colRed, "Test" -styledEcho bgColor, colBlue, "Test" diff --git a/tests/stdlib/tterminal_12759.nim b/tests/stdlib/tterminal_12759.nim deleted file mode 100644 index e9ea3127c..000000000 --- a/tests/stdlib/tterminal_12759.nim +++ /dev/null @@ -1,11 +0,0 @@ -discard """ - action: "compile" -""" - -import terminal -import std/syncio - -proc test() {.raises:[IOError, ValueError].} = - setBackgroundColor(stdout, bgRed) - -test() diff --git a/tests/stdlib/tterminal_15874.nim b/tests/stdlib/tterminal_15874.nim deleted file mode 100644 index c3455c350..000000000 --- a/tests/stdlib/tterminal_15874.nim +++ /dev/null @@ -1,8 +0,0 @@ -discard """ - cmd: "nim c --app:console $file" - action: "compile" -""" - -import terminal - -writeStyled("hello", {styleBright}) diff --git a/tests/stdlib/ttestutils.nim b/tests/stdlib/ttestutils.nim deleted file mode 100644 index 0f8bf16cf..000000000 --- a/tests/stdlib/ttestutils.nim +++ /dev/null @@ -1,40 +0,0 @@ -import stdtest/testutils -import std/assertions - -block: # assertAll - assertAll: - 1+1 == 2 - var a = 3 - a == 3 - - doAssertRaises(AssertionDefect): - assertAll: - 1+1 == 2 - var a = 3 - a == 4 - -block: # greedyOrderedSubsetLines - assertAll: - greedyOrderedSubsetLines("a1\na3", "a0\na1\na2\na3\na4") - not greedyOrderedSubsetLines("a3\na1", "a0\na1\na2\na3\na4") # out of order - not greedyOrderedSubsetLines("a1\na5", "a0\na1\na2\na3\na4") # a5 not in lhs - - not greedyOrderedSubsetLines("a1\na5", "a0\na1\na2\na3\na4\nprefix:a5") - not greedyOrderedSubsetLines("a1\na5", "a0\na1\na2\na3\na4\na5:suffix") - not greedyOrderedSubsetLines("a5", "a0\na1\na2\na3\na4\nprefix:a5") - not greedyOrderedSubsetLines("a5", "a0\na1\na2\na3\na4\na5:suffix") - -block: # greedyOrderedSubsetLines with allowPrefixMatch = true - template fn(a, b): bool = - greedyOrderedSubsetLines(a, b, allowPrefixMatch = true) - assertAll: - fn("a1\na3", "a0\na1\na2\na3_suffix\na4") - not fn("a1\na3", "a0\na1\na2\nprefix_a3\na4") - # these are same as above, could be refactored - not fn("a3\na1", "a0\na1\na2\na3\na4") # out of order - not fn("a1\na5", "a0\na1\na2\na3\na4") # a5 not in lhs - - not fn("a1\na5", "a0\na1\na2\na3\na4\nprefix:a5") - fn("a1\na5", "a0\na1\na2\na3\na4\na5:suffix") - not fn("a5", "a0\na1\na2\na3\na4\nprefix:a5") - fn("a5", "a0\na1\na2\na3\na4\na5:suffix") diff --git a/tests/stdlib/tthreadpool.nim b/tests/stdlib/tthreadpool.nim deleted file mode 100644 index bc574faeb..000000000 --- a/tests/stdlib/tthreadpool.nim +++ /dev/null @@ -1,14 +0,0 @@ -discard """ - matrix: "--threads:on --gc:arc" - disabled: "freebsd" - output: "42" -""" -import std/assertions -from std/threadpool import spawn, `^`, sync -block: # bug #12005 - proc doworkok(i: int) {.thread.} = echo i - spawn(doworkok(42)) - sync() # this works when returning void! - - proc doworkbad(i: int): int {.thread.} = i - doAssert ^spawn(doworkbad(42)) == 42 # bug was here diff --git a/tests/stdlib/ttimes.nim b/tests/stdlib/ttimes.nim index f6159d942..97945b21d 100644 --- a/tests/stdlib/ttimes.nim +++ b/tests/stdlib/ttimes.nim @@ -1,27 +1,32 @@ discard """ - targets: "c js" + target: "c js" """ import times, strutils, unittest -import std/assertions when not defined(js): import os +# Normally testament configures unittest with environment variables, +# but that doesn't work for the JS target. So instead we must set the correct +# settings here. +addOutputFormatter( + newConsoleOutputFormatter(PRINT_FAILURES, colorOutput = false)) + proc staticTz(hours, minutes, seconds: int = 0): Timezone {.noSideEffect.} = let offset = hours * 3600 + minutes * 60 + seconds - proc zonedTimeFromAdjTime(adjTime: Time): ZonedTime = + proc zonedTimeFromAdjTime(adjTime: Time): ZonedTime {.locks: 0.} = result.isDst = false result.utcOffset = offset result.time = adjTime + initDuration(seconds = offset) - proc zonedTimeFromTime(time: Time): ZonedTime = + proc zonedTimeFromTime(time: Time): ZonedTime {.locks: 0.}= result.isDst = false result.utcOffset = offset result.time = time - newTimezone("", zonedTimeFromTime, zonedTimeFromAdjTime) + newTimezone("", zonedTimeFromTime, zonedTImeFromAdjTime) template parseTest(s, f, sExpected: string, ydExpected: int) = let @@ -85,10 +90,6 @@ template runTimezoneTests() = "2001-01-12T08:04:05Z", 11) parseTest("2001-01-12T15:04:05 +07:30:59", "yyyy-MM-dd'T'HH:mm:ss zzzz", "2001-01-12T07:33:06Z", 11) - parseTest("2001-01-12T15:04:05 +0700", "yyyy-MM-dd'T'HH:mm:ss ZZZ", - "2001-01-12T08:04:05Z", 11) - parseTest("2001-01-12T15:04:05 +073059", "yyyy-MM-dd'T'HH:mm:ss ZZZZ", - "2001-01-12T07:33:06Z", 11) # Kitchen = "3:04PM" parseTestTimeOnly("3:04PM", "h:mmtt", "15:04:00") @@ -121,7 +122,7 @@ template usingTimezone(tz: string, body: untyped) = body putEnv("TZ", oldZone) -block: # ttimes +suite "ttimes": # Generate tests for multiple timezone files where available # Set the TZ env var for each test @@ -148,7 +149,7 @@ block: # ttimes test "parseTest": runTimezoneTests() - block: # dst handling + test "dst handling": usingTimezone("Europe/Stockholm"): # In case of an impossible time, the time is moved to after the # impossible time period @@ -168,7 +169,7 @@ block: # ttimes check initDateTime(21, mOct, 2017, 01, 00, 00).format(f) == "2017-10-21 01:00 +02:00" - block: # issue #6520 + test "issue #6520": usingTimezone("Europe/Stockholm"): var local = fromUnix(1469275200).local var utc = fromUnix(1469275200).utc @@ -177,19 +178,19 @@ block: # ttimes local.utcOffset = 0 check claimedOffset == utc.toTime - local.toTime - block: # issue #5704 + test "issue #5704": usingTimezone("Asia/Seoul"): let diff = parse("19700101-000000", "yyyyMMdd-hhmmss").toTime - parse("19000101-000000", "yyyyMMdd-hhmmss").toTime check diff == initDuration(seconds = 2208986872) - block: # issue #6465 + test "issue #6465": usingTimezone("Europe/Stockholm"): let dt = parse("2017-03-25 12:00", "yyyy-MM-dd hh:mm") check $(dt + initTimeInterval(days = 1)) == "2017-03-26T12:00:00+02:00" check $(dt + initDuration(days = 1)) == "2017-03-26T13:00:00+02:00" - block: # adding/subtracting time across dst + test "adding/subtracting time across dst": usingTimezone("Europe/Stockholm"): let dt1 = initDateTime(26, mMar, 2017, 03, 00, 00) check $(dt1 - 1.seconds) == "2017-03-26T01:59:59+01:00" @@ -197,55 +198,55 @@ block: # ttimes var dt2 = initDateTime(29, mOct, 2017, 02, 59, 59) check $(dt2 + 1.seconds) == "2017-10-29T02:00:00+01:00" - block: # datetime before epoch + test "datetime before epoch": check $fromUnix(-2147483648).utc == "1901-12-13T20:45:52Z" - block: # incorrect inputs: empty string + test "incorrect inputs: empty string": parseTestExcp("", "yyyy-MM-dd") - block: # incorrect inputs: year + test "incorrect inputs: year": parseTestExcp("20-02-19", "yyyy-MM-dd") - block: # incorrect inputs: month number + test "incorrect inputs: month number": parseTestExcp("2018-2-19", "yyyy-MM-dd") - block: # incorrect inputs: month name + test "incorrect inputs: month name": parseTestExcp("2018-Fe", "yyyy-MMM-dd") - block: # incorrect inputs: day + test "incorrect inputs: day": parseTestExcp("2018-02-1", "yyyy-MM-dd") - block: # incorrect inputs: day of week + test "incorrect inputs: day of week": parseTestExcp("2018-Feb-Mo", "yyyy-MMM-ddd") - block: # incorrect inputs: hour + test "incorrect inputs: hour": parseTestExcp("2018-02-19 1:30", "yyyy-MM-dd hh:mm") - block: # incorrect inputs: minute + test "incorrect inputs: minute": parseTestExcp("2018-02-19 16:3", "yyyy-MM-dd hh:mm") - block: # incorrect inputs: second + test "incorrect inputs: second": parseTestExcp("2018-02-19 16:30:0", "yyyy-MM-dd hh:mm:ss") - block: # incorrect inputs: timezone (z) + test "incorrect inputs: timezone (z)": parseTestExcp("2018-02-19 16:30:00 ", "yyyy-MM-dd hh:mm:ss z") - block: # incorrect inputs: timezone (zz) 1 + test "incorrect inputs: timezone (zz) 1": parseTestExcp("2018-02-19 16:30:00 ", "yyyy-MM-dd hh:mm:ss zz") - block: # incorrect inputs: timezone (zz) 2 + test "incorrect inputs: timezone (zz) 2": parseTestExcp("2018-02-19 16:30:00 +1", "yyyy-MM-dd hh:mm:ss zz") - block: # incorrect inputs: timezone (zzz) 1 + test "incorrect inputs: timezone (zzz) 1": parseTestExcp("2018-02-19 16:30:00 ", "yyyy-MM-dd hh:mm:ss zzz") - block: # incorrect inputs: timezone (zzz) 2 + test "incorrect inputs: timezone (zzz) 2": parseTestExcp("2018-02-19 16:30:00 +01:", "yyyy-MM-dd hh:mm:ss zzz") - block: # incorrect inputs: timezone (zzz) 3 + test "incorrect inputs: timezone (zzz) 3": parseTestExcp("2018-02-19 16:30:00 +01:0", "yyyy-MM-dd hh:mm:ss zzz") - block: # incorrect inputs: year (yyyy/uuuu) + test "incorrect inputs: year (yyyy/uuuu)": parseTestExcp("-0001", "yyyy") parseTestExcp("-0001", "YYYY") parseTestExcp("1", "yyyy") @@ -254,7 +255,7 @@ block: # ttimes parseTestExcp("12345", "uuuu") parseTestExcp("-1 BC", "UUUU g") - block: # incorrect inputs: invalid sign + test "incorrect inputs: invalid sign": parseTestExcp("+1", "YYYY") parseTestExcp("+1", "dd") parseTestExcp("+1", "MM") @@ -262,10 +263,10 @@ block: # ttimes parseTestExcp("+1", "mm") parseTestExcp("+1", "ss") - block: # _ as a separator + test "_ as a separator": discard parse("2000_01_01", "YYYY'_'MM'_'dd") - block: # dynamic timezone + test "dynamic timezone": let tz = staticTz(seconds = -9000) let dt = initDateTime(1, mJan, 2000, 12, 00, 00, tz) check dt.utcOffset == -9000 @@ -274,13 +275,13 @@ block: # ttimes check $dt.utc == "2000-01-01T09:30:00Z" check $dt.utc.inZone(tz) == $dt - block: # isLeapYear + test "isLeapYear": check isLeapYear(2016) check (not isLeapYear(2015)) check isLeapYear(2000) check (not isLeapYear(1900)) - block: # TimeInterval + test "TimeInterval": let t = fromUnix(876124714).utc # Mon 6 Oct 08:58:34 BST 1997 # Interval tests let t2 = t - 2.years @@ -292,7 +293,7 @@ block: # ttimes check (t + 1.hours).toTime.toUnix == t.toTime.toUnix + 60 * 60 check (t - 1.hours).toTime.toUnix == t.toTime.toUnix - 60 * 60 - block: # TimeInterval - months + test "TimeInterval - months": var dt = initDateTime(1, mFeb, 2017, 00, 00, 00, utc()) check $(dt - initTimeInterval(months = 1)) == "2017-01-01T00:00:00Z" dt = initDateTime(15, mMar, 2017, 00, 00, 00, utc()) @@ -301,14 +302,14 @@ block: # ttimes # This happens due to monthday overflow. It's consistent with Phobos. check $(dt - initTimeInterval(months = 1)) == "2017-03-03T00:00:00Z" - block: # duration + test "duration": let d = initDuration check d(hours = 48) + d(days = 5) == d(weeks = 1) let dt = initDateTime(01, mFeb, 2000, 00, 00, 00, 0, utc()) + d(milliseconds = 1) check dt.nanosecond == convert(Milliseconds, Nanoseconds, 1) check d(seconds = 1, milliseconds = 500) * 2 == d(seconds = 3) check d(seconds = 3) div 2 == d(seconds = 1, milliseconds = 500) - check d(milliseconds = 1001).inSeconds == 1 + check d(milliseconds = 1001).seconds == 1 check d(seconds = 1, milliseconds = 500) - d(milliseconds = 1250) == d(milliseconds = 250) check d(seconds = 1, milliseconds = 1) < d(seconds = 1, milliseconds = 2) @@ -321,7 +322,7 @@ block: # ttimes check (initDuration(seconds = 1, nanoseconds = 3) <= initDuration(seconds = 1, nanoseconds = 1)).not - block: # large/small dates + test "large/small dates": discard initDateTime(1, mJan, -35_000, 12, 00, 00, utc()) # with local tz discard initDateTime(1, mJan, -35_000, 12, 00, 00) @@ -333,7 +334,7 @@ block: # ttimes let dt2 = dt + 35_001.years check $dt2 == "0001-01-01T12:00:01Z" - block: # compare datetimes + test "compare datetimes": var dt1 = now() var dt2 = dt1 check dt1 == dt2 @@ -341,27 +342,23 @@ block: # ttimes dt2 = dt2 + 1.seconds check dt1 < dt2 - block: # adding/subtracting TimeInterval + test "adding/subtracting TimeInterval": # add/subtract TimeIntervals and Time/TimeInfo let now = getTime().utc - let isSpecial = now.isLeapDay check now + convert(Seconds, Nanoseconds, 1).nanoseconds == now + 1.seconds check now + 1.weeks == now + 7.days check now - 1.seconds == now - 3.seconds + 2.seconds check now + 65.seconds == now + 1.minutes + 5.seconds check now + 60.minutes == now + 1.hours check now + 24.hours == now + 1.days - if not isSpecial: - check now + 13.months == now + 1.years + 1.months + check now + 13.months == now + 1.years + 1.months check toUnix(fromUnix(0) + 2.seconds) == 2 check toUnix(fromUnix(0) - 2.seconds) == -2 var ti1 = now + 1.years ti1 = ti1 - 1.years - if not isSpecial: - check ti1 == now + check ti1 == now ti1 = ti1 + 1.days - if not isSpecial: - check ti1 == now + 1.days + check ti1 == now + 1.days # Bug with adding a day to a Time let day = 24.hours @@ -379,14 +376,14 @@ block: # ttimes check initTime(0, 101).toWinTime.fromWinTime.nanosecond == 100 check initTime(0, 101).toWinTime.fromWinTime.nanosecond == 100 - block: # issue 7620 + test "issue 7620": let layout = "M/d/yyyy' 'h:mm:ss' 'tt' 'z" let t7620_am = parse("4/15/2017 12:01:02 AM +0", layout, utc()) check t7620_am.format(layout) == "4/15/2017 12:01:02 AM Z" let t7620_pm = parse("4/15/2017 12:01:02 PM +0", layout, utc()) check t7620_pm.format(layout) == "4/15/2017 12:01:02 PM Z" - block: # format + test "format": var dt = initDateTime(1, mJan, -0001, 17, 01, 02, 123_456_789, staticTz(hours = 1, minutes = 2, seconds = 3)) @@ -455,7 +452,7 @@ block: # ttimes doAssert dt.format("zz") == tz[2] doAssert dt.format("zzz") == tz[3] - block: # format locale + test "format locale": let loc = DateTimeLocale( MMM: ["Fir","Sec","Thi","Fou","Fif","Six","Sev","Eig","Nin","Ten","Ele","Twe"], MMMM: ["Firsty", "Secondy", "Thirdy", "Fourthy", "Fifthy", "Sixthy", "Seventhy", "Eighthy", "Ninthy", "Tenthy", "Eleventhy", "Twelfthy"], @@ -472,7 +469,7 @@ block: # ttimes check dt.format("MMM", loc) == "Fir" check dt.format("MMMM", loc) == "Firsty" - block: # parse + test "parse": check $parse("20180101", "yyyyMMdd", utc()) == "2018-01-01T00:00:00Z" parseTestExcp("+120180101", "yyyyMMdd") @@ -493,7 +490,7 @@ block: # ttimes parseTestExcp("2000 A", "yyyy g") - block: # parse locale + test "parse locale": let loc = DateTimeLocale( MMM: ["Fir","Sec","Thi","Fou","Fif","Six","Sev","Eig","Nin","Ten","Ele","Twe"], MMMM: ["Firsty", "Secondy", "Thirdy", "Fourthy", "Fifthy", "Sixthy", "Seventhy", "Eighthy", "Ninthy", "Tenthy", "Eleventhy", "Twelfthy"], @@ -503,7 +500,13 @@ block: # ttimes check $parse("02 Fir 2019", "dd MMM yyyy", utc(), loc) == "2019-01-02T00:00:00Z" check $parse("Fourthy 6, 2017", "MMMM d, yyyy", utc(), loc) == "2017-04-06T00:00:00Z" - block: # timezoneConversion + test "countLeapYears": + # 1920, 2004 and 2020 are leap years, and should be counted starting at the following year + check countLeapYears(1920) + 1 == countLeapYears(1921) + check countLeapYears(2004) + 1 == countLeapYears(2005) + check countLeapYears(2020) + 1 == countLeapYears(2021) + + test "timezoneConversion": var l = now() let u = l.utc l = u.local @@ -511,7 +514,7 @@ block: # ttimes check l.timezone == local() check u.timezone == utc() - block: # getDayOfWeek + test "getDayOfWeek": check getDayOfWeek(01, mJan, 0000) == dSat check getDayOfWeek(01, mJan, -0023) == dSat check getDayOfWeek(21, mSep, 1900) == dFri @@ -520,29 +523,29 @@ block: # ttimes check getDayOfWeek(01, mJan, 2000) == dSat check getDayOfWeek(01, mJan, 2021) == dFri - block: # between - simple + test "between - simple": let x = initDateTime(10, mJan, 2018, 13, 00, 00) let y = initDateTime(11, mJan, 2018, 12, 00, 00) doAssert x + between(x, y) == y - block: # between - dst start + test "between - dst start": usingTimezone("Europe/Stockholm"): let x = initDateTime(25, mMar, 2018, 00, 00, 00) let y = initDateTime(25, mMar, 2018, 04, 00, 00) doAssert x + between(x, y) == y - block: # between - empty interval + test "between - empty interval": let x = now() let y = x doAssert x + between(x, y) == y - block: # between - dst end + test "between - dst end": usingTimezone("Europe/Stockholm"): let x = initDateTime(27, mOct, 2018, 02, 00, 00) let y = initDateTime(28, mOct, 2018, 01, 00, 00) doAssert x + between(x, y) == y - block: # between - long day + test "between - long day": usingTimezone("Europe/Stockholm"): # This day is 25 hours long in Europe/Stockholm let x = initDateTime(28, mOct, 2018, 00, 30, 00) @@ -550,7 +553,7 @@ block: # ttimes doAssert between(x, y) == 24.hours + 30.minutes doAssert x + between(x, y) == y - block: # between - offset change edge case + test "between - offset change edge case": # This test case is important because in this case # `x + between(x.utc, y.utc) == y` is not true, which is very rare. usingTimezone("America/Belem"): @@ -559,19 +562,19 @@ block: # ttimes doAssert x + between(x, y) == y doAssert y + between(y, x) == x - block: # between - all units + test "between - all units": let x = initDateTime(1, mJan, 2000, 00, 00, 00, utc()) let ti = initTimeInterval(1, 1, 1, 1, 1, 1, 1, 1, 1, 1) let y = x + ti doAssert between(x, y) == ti doAssert between(y, x) == -ti - block: # between - monthday overflow + test "between - monthday overflow": let x = initDateTime(31, mJan, 2001, 00, 00, 00, utc()) let y = initDateTime(1, mMar, 2001, 00, 00, 00, utc()) doAssert x + between(x, y) == y - block: # between - misc + test "between - misc": block: let x = initDateTime(31, mDec, 2000, 12, 00, 00, utc()) let y = initDateTime(01, mJan, 2001, 00, 00, 00, utc()) @@ -613,33 +616,7 @@ block: # ttimes doAssert x + between(x, y) == y doAssert between(x, y) == 1.months + 1.weeks - block: # default DateTime https://github.com/nim-lang/RFCs/issues/211 - var num = 0 - for ai in Month: num.inc - check num == 12 - - var a: DateTime - check a == DateTime.default - check not a.isInitialized - check $a == "Uninitialized DateTime" - - expect(AssertionDefect): discard getDayOfWeek(a.monthday, a.month, a.year) - expect(AssertionDefect): discard a.toTime - expect(AssertionDefect): discard a.utc() - expect(AssertionDefect): discard a.local() - expect(AssertionDefect): discard a.inZone(utc()) - expect(AssertionDefect): discard a + initDuration(seconds = 1) - expect(AssertionDefect): discard a + initTimeInterval(seconds = 1) - expect(AssertionDefect): discard a.isLeapDay - expect(AssertionDefect): discard a < a - expect(AssertionDefect): discard a <= a - expect(AssertionDefect): discard getDateStr(a) - expect(AssertionDefect): discard getClockStr(a) - expect(AssertionDefect): discard a.format "yyyy" - expect(AssertionDefect): discard a.format initTimeFormat("yyyy") - expect(AssertionDefect): discard between(a, a) - - block: # inX procs + test "inX procs": doAssert initDuration(seconds = 1).inSeconds == 1 doAssert initDuration(seconds = -1).inSeconds == -1 doAssert initDuration(seconds = -1, nanoseconds = 1).inSeconds == 0 @@ -647,98 +624,3 @@ block: # ttimes doAssert initDuration(milliseconds = 500).inMilliseconds == 500 doAssert initDuration(milliseconds = -500).inMilliseconds == -500 doAssert initDuration(nanoseconds = -999999999).inMilliseconds == -999 - - block: # getIsoWeekAndYear - doAssert getIsoWeekAndYear(initDateTime(04, mNov, 2019, 00, 00, 00)) == (isoweek: 45.IsoWeekRange, isoyear: 2019.IsoYear) - doAssert initDateTime(dMon, 45, 2019.IsoYear, 00, 00, 00) == initDateTime(04, mNov, 2019, 00, 00, 00) - doAssert getIsoWeekAndYear(initDateTime(28, mDec, 2019, 00, 00, 00)) == (isoweek: 52.IsoWeekRange, isoyear: 2019.IsoYear) - doAssert initDateTime(dSat, 52, 2019.IsoYear, 00, 00, 00) == initDateTime(28, mDec, 2019, 00, 00, 00) - doAssert getIsoWeekAndYear(initDateTime(29, mDec, 2019, 00, 00, 00)) == (isoweek: 52.IsoWeekRange, isoyear: 2019.IsoYear) - doAssert initDateTime(dSun, 52, 2019.IsoYear, 00, 00, 00) == initDateTime(29, mDec, 2019, 00, 00, 00) - doAssert getIsoWeekAndYear(initDateTime(30, mDec, 2019, 00, 00, 00)) == (isoweek: 01.IsoWeekRange, isoyear: 2020.IsoYear) - doAssert initDateTime(dMon, 01, 2020.IsoYear, 00, 00, 00) == initDateTime(30, mDec, 2019, 00, 00, 00) - doAssert getIsoWeekAndYear(initDateTime(31, mDec, 2019, 00, 00, 00)) == (isoweek: 01.IsoWeekRange, isoyear: 2020.IsoYear) - doAssert initDateTime(dTue, 01, 2020.IsoYear, 00, 00, 00) == initDateTime(31, mDec, 2019, 00, 00, 00) - doAssert getIsoWeekAndYear(initDateTime(01, mJan, 2020, 00, 00, 00)) == (isoweek: 01.IsoWeekRange, isoyear: 2020.IsoYear) - doAssert initDateTime(dWed, 01, 2020.IsoYear, 00, 00, 00) == initDateTime(01, mJan, 2020, 00, 00, 00) - doAssert getIsoWeekAndYear(initDateTime(02, mJan, 2020, 00, 00, 00)) == (isoweek: 01.IsoWeekRange, isoyear: 2020.IsoYear) - doAssert initDateTime(dThu, 01, 2020.IsoYear, 00, 00, 00) == initDateTime(02, mJan, 2020, 00, 00, 00) - doAssert getIsoWeekAndYear(initDateTime(05, mApr, 2020, 00, 00, 00)) == (isoweek: 14.IsoWeekRange, isoyear: 2020.IsoYear) - doAssert initDateTime(dSun, 14, 2020.IsoYear, 00, 00, 00) == initDateTime(05, mApr, 2020, 00, 00, 00) - doAssert getIsoWeekAndYear(initDateTime(06, mApr, 2020, 00, 00, 00)) == (isoweek: 15.IsoWeekRange, isoyear: 2020.IsoYear) - doAssert initDateTime(dMon, 15, 2020.IsoYear, 00, 00, 00) == initDateTime(06, mApr, 2020, 00, 00, 00) - doAssert getIsoWeekAndYear(initDateTime(10, mApr, 2020, 00, 00, 00)) == (isoweek: 15.IsoWeekRange, isoyear: 2020.IsoYear) - doAssert initDateTime(dFri, 15, 2020.IsoYear, 00, 00, 00) == initDateTime(10, mApr, 2020, 00, 00, 00) - doAssert getIsoWeekAndYear(initDateTime(12, mApr, 2020, 00, 00, 00)) == (isoweek: 15.IsoWeekRange, isoyear: 2020.IsoYear) - doAssert initDateTime(dSun, 15, 2020.IsoYear, 00, 00, 00) == initDateTime(12, mApr, 2020, 00, 00, 00) - doAssert getIsoWeekAndYear(initDateTime(13, mApr, 2020, 00, 00, 00)) == (isoweek: 16.IsoWeekRange, isoyear: 2020.IsoYear) - doAssert initDateTime(dMon, 16, 2020.IsoYear, 00, 00, 00) == initDateTime(13, mApr, 2020, 00, 00, 00) - doAssert getIsoWeekAndYear(initDateTime(15, mApr, 2020, 00, 00, 00)) == (isoweek: 16.IsoWeekRange, isoyear: 2020.IsoYear) - doAssert initDateTime(dThu, 16, 2020.IsoYear, 00, 00, 00) == initDateTime(16, mApr, 2020, 00, 00, 00) - doAssert getIsoWeekAndYear(initDateTime(17, mJul, 2020, 00, 00, 00)) == (isoweek: 29.IsoWeekRange, isoyear: 2020.IsoYear) - doAssert initDateTime(dFri, 29, 2020.IsoYear, 00, 00, 00) == initDateTime(17, mJul, 2020, 00, 00, 00) - doAssert getIsoWeekAndYear(initDateTime(19, mJul, 2020, 00, 00, 00)) == (isoweek: 29.IsoWeekRange, isoyear: 2020.IsoYear) - doAssert initDateTime(dSun, 29, 2020.IsoYear, 00, 00, 00) == initDateTime(19, mJul, 2020, 00, 00, 00) - doAssert getIsoWeekAndYear(initDateTime(20, mJul, 2020, 00, 00, 00)) == (isoweek: 30.IsoWeekRange, isoyear: 2020.IsoYear) - doAssert initDateTime(dMon, 30, 2020.IsoYear, 00, 00, 00) == initDateTime(20, mJul, 2020, 00, 00, 00) - doAssert getIsoWeekAndYear(initDateTime(23, mJul, 2020, 00, 00, 00)) == (isoweek: 30.IsoWeekRange, isoyear: 2020.IsoYear) - doAssert initDateTime(dThu, 30, 2020.IsoYear, 00, 00, 00) == initDateTime(23, mJul, 2020, 00, 00, 00) - doAssert getIsoWeekAndYear(initDateTime(31, mDec, 2020, 00, 00, 00)) == (isoweek: 53.IsoWeekRange, isoyear: 2020.IsoYear) - doAssert initDateTime(dThu, 53, 2020.IsoYear, 00, 00, 00) == initDateTime(31, mDec, 2020, 00, 00, 00) - doAssert getIsoWeekAndYear(initDateTime(01, mJan, 2021, 00, 00, 00)) == (isoweek: 53.IsoWeekRange, isoyear: 2020.IsoYear) - doAssert initDateTime(dFri, 53, 2020.IsoYear, 00, 00, 00) == initDateTime(01, mJan, 2021, 00, 00, 00) - doAssert getIsoWeekAndYear(initDateTime(02, mJan, 2021, 00, 00, 00)) == (isoweek: 53.IsoWeekRange, isoyear: 2020.IsoYear) - doAssert initDateTime(dSat, 53, 2020.IsoYear, 00, 00, 00) == initDateTime(02, mJan, 2021, 00, 00, 00) - doAssert getIsoWeekAndYear(initDateTime(03, mJan, 2021, 00, 00, 00)) == (isoweek: 53.IsoWeekRange, isoyear: 2020.IsoYear) - doAssert initDateTime(dSun, 53, 2020.IsoYear, 00, 00, 00) == initDateTime(03, mJan, 2021, 00, 00, 00) - doAssert getIsoWeekAndYear(initDateTime(04, mJan, 2021, 00, 00, 00)) == (isoweek: 01.IsoWeekRange, isoyear: 2021.IsoYear) - doAssert initDateTime(dMon, 01, 2021.IsoYear, 00, 00, 00) == initDateTime(04, mJan, 2021, 00, 00, 00) - doAssert getIsoWeekAndYear(initDateTime(01, mFeb, 2021, 00, 00, 00)) == (isoweek: 05.IsoWeekRange, isoyear: 2021.IsoYear) - doAssert initDateTime(dMon, 05, 2021.IsoYear, 00, 00, 00) == initDateTime(01, mFeb, 2021, 00, 00, 00) - - doAssert getIsoWeekAndYear(initDateTime(01, mFeb, 2021, 01, 02, 03, 400_000_000, staticTz(hours=1))) == (isoweek: 05.IsoWeekRange, isoyear: 2021.IsoYear) - doAssert initDateTime(dMon, 05, 2021.IsoYear, 01, 02, 03, 400_000_000, staticTz(hours=1)) == initDateTime(01, mFeb, 2021, 01, 02, 03, 400_000_000, staticTz(hours=1)) - - doAssert getIsoWeekAndYear(initDateTime(01, mApr, +0001, 00, 00, 00)) == (isoweek: 13.IsoWeekRange, isoyear: 0001.IsoYear) - doAssert initDateTime(dSun, 13, 0001.IsoYear, 00, 00, 00) == initDateTime(01, mApr, 0001, 00, 00, 00) - doAssert getIsoWeekAndYear(initDateTime(01, mApr, +0000, 00, 00, 00)) == (isoweek: 13.IsoWeekRange, isoyear: 0000.IsoYear) - doAssert initDateTime(dSat, 13, 0000.IsoYear, 00, 00, 00) == initDateTime(01, mApr, 0000, 00, 00, 00) - doAssert getIsoWeekAndYear(initDateTime(01, mApr, -0001, 00, 00, 00)) == (isoweek: 13.IsoWeekRange, isoyear: (-0001).IsoYear) - doAssert initDateTime(dThu, 13, (-0001).IsoYear, 00, 00, 00) == initDateTime(01, mApr, -0001, 00, 00, 00) - doAssert getIsoWeekAndYear(initDateTime(01, mApr, -0002, 00, 00, 00)) == (isoweek: 14.IsoWeekRange, isoyear: (-0002).IsoYear) - doAssert initDateTime(dWed, 14, (-0002).IsoYear, 00, 00, 00) == initDateTime(01, mApr, -0002, 00, 00, 00) - doAssert getIsoWeekAndYear(initDateTime(01, mApr, -0753, 00, 00, 00)) == (isoweek: 14.IsoWeekRange, isoyear: (-0753).IsoYear) - doAssert initDateTime(dMon, 14, (-0753).IsoYear, 00, 00, 00) == initDateTime(01, mApr, -0753, 00, 00, 00) - - block: # getWeeksInIsoYear - doAssert getWeeksInIsoYear((-0014).IsoYear) == 52 - doAssert getWeeksInIsoYear((-0013).IsoYear) == 53 - doAssert getWeeksInIsoYear((-0012).IsoYear) == 52 - - doAssert getWeeksInIsoYear((-0009).IsoYear) == 52 - doAssert getWeeksInIsoYear((-0008).IsoYear) == 53 - doAssert getWeeksInIsoYear((-0007).IsoYear) == 52 - - doAssert getWeeksInIsoYear((-0003).IsoYear) == 52 - doAssert getWeeksInIsoYear((-0002).IsoYear) == 53 - doAssert getWeeksInIsoYear((-0001).IsoYear) == 52 - - doAssert getWeeksInIsoYear(0003.IsoYear) == 52 - doAssert getWeeksInIsoYear(0004.IsoYear) == 53 - doAssert getWeeksInIsoYear(0005.IsoYear) == 52 - - doAssert getWeeksInIsoYear(1653.IsoYear) == 52 - doAssert getWeeksInIsoYear(1654.IsoYear) == 53 - doAssert getWeeksInIsoYear(1655.IsoYear) == 52 - - doAssert getWeeksInIsoYear(1997.IsoYear) == 52 - doAssert getWeeksInIsoYear(1998.IsoYear) == 53 - doAssert getWeeksInIsoYear(1999.IsoYear) == 52 - - doAssert getWeeksInIsoYear(2008.IsoYear) == 52 - doAssert getWeeksInIsoYear(2009.IsoYear) == 53 - doAssert getWeeksInIsoYear(2010.IsoYear) == 52 - - doAssert getWeeksInIsoYear(2014.IsoYear) == 52 - doAssert getWeeksInIsoYear(2015.IsoYear) == 53 - doAssert getWeeksInIsoYear(2016.IsoYear) == 52 diff --git a/tests/stdlib/ttypeinfo.nim b/tests/stdlib/ttypeinfo.nim deleted file mode 100644 index 5e17c151a..000000000 --- a/tests/stdlib/ttypeinfo.nim +++ /dev/null @@ -1,72 +0,0 @@ -import std/typeinfo -import std/assertions - -type - TE = enum - blah, blah2 - - TestObj = object - test, asd: int - case test2: TE - of blah: - help: string - else: - nil - - -var test = @[0,1,2,3,4] -var x = toAny(test) -var y = 78 -x[4] = toAny(y) -doAssert x[2].getInt == 2 - -var test2: tuple[name: string, s: int] = ("test", 56) -var x2 = toAny(test2) -var i = 0 -for n, a in fields(x2): - case i - of 0: doAssert n == "Field0" and $a.kind == "akString" - of 1: doAssert n == "Field1" and $a.kind == "akInt" - else: doAssert false - inc i - -var test3: TestObj -test3.test = 42 -test3 = TestObj(test2: blah2) -var x3 = toAny(test3) -i = 0 -for n, a in fields(x3): - case i - of 0: doAssert n == "test" and $a.kind == "akInt" - of 1: doAssert n == "asd" and $a.kind == "akInt" - of 2: doAssert n == "test2" and $a.kind == "akEnum" - else: doAssert false - inc i - -var test4: ref string -new(test4) -test4[] = "test" -var x4 = toAny(test4) -doAssert($x4[].kind() == "akString") - -block: - # gimme a new scope dammit - var myArr: array[0..4, array[0..4, string]] = [ - ["test", "1", "2", "3", "4"], ["test", "1", "2", "3", "4"], - ["test", "1", "2", "3", "4"], ["test", "1", "2", "3", "4"], - ["test", "1", "2", "3", "4"]] - var m = toAny(myArr) - for i in 0 .. m.len-1: - for j in 0 .. m[i].len-1: - doAssert getString(m[i][j]) == myArr[i][j] - -block: - type - Test = enum - Hello, he_llo - - var x = hello - var y = x.toAny - - doAssert getEnumOrdinal(y, "Hello") == 0 - doAssert getEnumOrdinal(y, "hello") == 1 diff --git a/tests/stdlib/ttypeinfo.nims b/tests/stdlib/ttypeinfo.nims deleted file mode 100644 index d31d0b26f..000000000 --- a/tests/stdlib/ttypeinfo.nims +++ /dev/null @@ -1 +0,0 @@ ---styleCheck:off \ No newline at end of file diff --git a/tests/stdlib/ttypetraits.nim b/tests/stdlib/ttypetraits.nim deleted file mode 100644 index 574204da6..000000000 --- a/tests/stdlib/ttypetraits.nim +++ /dev/null @@ -1,93 +0,0 @@ -discard """ - targets: "c cpp js" -""" - -# xxx merge with tests/metatype/ttypetraits.nim - -import std/typetraits -import std/assertions - -macro testClosure(fn: typed, flag: static bool) = - if flag: - doAssert hasClosure(fn) - else: - doAssert not hasClosure(fn) - -block: - proc h1() = - echo 1 - - testClosure(h1, false) - - proc h2() {.nimcall.} = - echo 2 - - testClosure(h2, false) - - -block: - proc fn(): auto = - proc hello() {.nimcall.} = - echo 3 - hello - - let name = fn() - testClosure(name, false) - -block: - proc fn(): auto = - proc hello() = - echo 3 - hello - - let name = fn() - testClosure(name, false) - -block: - proc fn(): auto = - var x = 0 - proc hello() = - echo 3 - inc x - hello - - let name = fn() - testClosure(name, true) - -block: - proc fn(): auto = - var x = 0 - proc hello() {.closure.} = - echo 3 - inc x - hello - - let name = fn() - testClosure(name, true) - -block: - proc fn(): auto = - var x = 0 - proc hello() {.closure.} = - echo 3 - inc x - hello - - let name = fn() - testClosure(name, true) - - let name2 = name - testClosure(name2, true) - -block: - iterator hello(): int = - yield 1 - - testClosure(hello, false) - -when not defined(js): - block: - iterator hello(): int {.closure.}= - yield 1 - - testClosure(hello, true) diff --git a/tests/stdlib/tunicode.nim b/tests/stdlib/tunicode.nim deleted file mode 100644 index 2b1cb2385..000000000 --- a/tests/stdlib/tunicode.nim +++ /dev/null @@ -1,222 +0,0 @@ -import std/unicode -import std/assertions - -proc asRune(s: static[string]): Rune = - ## Compile-time conversion proc for converting string literals to a Rune - ## value. Returns the first Rune of the specified string. - ## - ## Shortcuts code like ``"å".runeAt(0)`` to ``"å".asRune`` and returns a - ## compile-time constant. - if s.len == 0: Rune(0) - else: s.runeAt(0) - -let - someString = "öÑ" - someRunes = toRunes(someString) - compared = (someString == $someRunes) -doAssert compared == true - -proc testReplacements(word: string): string = - case word - of "two": - return "2" - of "foo": - return "BAR" - of "βeta": - return "beta" - of "alpha": - return "αlpha" - else: - return "12345" - -doAssert translate("two not alpha foo βeta", testReplacements) == "2 12345 αlpha BAR beta" -doAssert translate(" two not foo βeta ", testReplacements) == " 2 12345 BAR beta " - -doAssert title("foo bar") == "Foo Bar" -doAssert title("αlpha βeta γamma") == "Αlpha Βeta Γamma" -doAssert title("") == "" - -doAssert capitalize("βeta") == "Βeta" -doAssert capitalize("foo") == "Foo" -doAssert capitalize("") == "" - -doAssert swapCase("FooBar") == "fOObAR" -doAssert swapCase(" ") == " " -doAssert swapCase("Αlpha Βeta Γamma") == "αLPHA βETA γAMMA" -doAssert swapCase("a✓B") == "A✓b" -doAssert swapCase("Јамогујестистаклоитоминештети") == "јАМОГУЈЕСТИСТАКЛОИТОМИНЕШТЕТИ" -doAssert swapCase("ὕαλονϕαγεῖνδύναμαιτοῦτοοὔμεβλάπτει") == "ὝΑΛΟΝΦΑΓΕῖΝΔΎΝΑΜΑΙΤΟῦΤΟΟὔΜΕΒΛΆΠΤΕΙ" -doAssert swapCase("Կրնամապակիուտեևինծիանհանգիստչըներ") == "կՐՆԱՄԱՊԱԿԻՈՒՏԵևԻՆԾԻԱՆՀԱՆԳԻՍՏՉԸՆԵՐ" -doAssert swapCase("") == "" - -doAssert isAlpha("r") -doAssert isAlpha("α") -doAssert isAlpha("ϙ") -doAssert isAlpha("ஶ") -doAssert(not isAlpha("$")) -doAssert(not isAlpha("")) - -doAssert isAlpha("Βeta") -doAssert isAlpha("Args") -doAssert isAlpha("𐌼𐌰𐌲𐌲𐌻𐌴𐍃𐍄𐌰𐌽") -doAssert isAlpha("ὕαλονϕαγεῖνδύναμαιτοῦτοοὔμεβλάπτει") -doAssert isAlpha("Јамогујестистаклоитоминештети") -doAssert isAlpha("Կրնամապակիուտեևինծիանհանգիստչըներ") -doAssert(not isAlpha("$Foo✓")) -doAssert(not isAlpha("⠙⠕⠑⠎⠝⠞")) - -doAssert isSpace("\t") -doAssert isSpace("\l") -doAssert(not isSpace("Β")) -doAssert(not isSpace("Βeta")) - -doAssert isSpace("\t\l \v\r\f") -doAssert isSpace(" ") -doAssert(not isSpace("")) -doAssert(not isSpace("ΑΓc \td")) - -doAssert(not isLower(' '.Rune)) - -doAssert(not isUpper(' '.Rune)) - -doAssert toUpper("Γ") == "Γ" -doAssert toUpper("b") == "B" -doAssert toUpper("α") == "Α" -doAssert toUpper("✓") == "✓" -doAssert toUpper("ϙ") == "Ϙ" -doAssert toUpper("") == "" - -doAssert toUpper("ΑΒΓ") == "ΑΒΓ" -doAssert toUpper("AAccβ") == "AACCΒ" -doAssert toUpper("A✓$β") == "A✓$Β" - -doAssert toLower("a") == "a" -doAssert toLower("γ") == "γ" -doAssert toLower("Γ") == "γ" -doAssert toLower("4") == "4" -doAssert toLower("Ϙ") == "ϙ" -doAssert toLower("") == "" - -doAssert toLower("abcdγ") == "abcdγ" -doAssert toLower("abCDΓ") == "abcdγ" -doAssert toLower("33aaΓ") == "33aaγ" - -doAssert reversed("Reverse this!") == "!siht esreveR" -doAssert reversed("先秦兩漢") == "漢兩秦先" -doAssert reversed("as⃝df̅") == "f̅ds⃝a" -doAssert reversed("a⃞b⃞c⃞") == "c⃞b⃞a⃞" -doAssert reversed("ὕαλονϕαγεῖνδύναμαιτοῦτοοὔμεβλάπτει") == "ιετπάλβεμὔοοτῦοτιαμανύδνῖεγαϕνολαὕ" -doAssert reversed("Јамогујестистаклоитоминештети") == "итетшенимотиолкатситсејугомаЈ" -doAssert reversed("Կրնամապակիուտեևինծիանհանգիստչըներ") == "րենըչտսիգնահնաիծնիևետւոիկապամանրԿ" -doAssert len(toRunes("as⃝df̅")) == runeLen("as⃝df̅") -const test = "as⃝" -doAssert lastRune(test, test.len-1)[1] == 3 -doAssert graphemeLen("è", 0) == 2 - -# test for rune positioning and runeSubStr() -let s = "Hänsel ««: 10,00€" - -var t = "" -for c in s.utf8: - t.add c - -doAssert(s == t) - -doAssert(runeReverseOffset(s, 1) == (20, 18)) -doAssert(runeReverseOffset(s, 19) == (-1, 18)) - -doAssert(runeStrAtPos(s, 0) == "H") -doAssert(runeSubStr(s, 0, 1) == "H") -doAssert(runeStrAtPos(s, 10) == ":") -doAssert(runeSubStr(s, 10, 1) == ":") -doAssert(runeStrAtPos(s, 9) == "«") -doAssert(runeSubStr(s, 9, 1) == "«") -doAssert(runeStrAtPos(s, 17) == "€") -doAssert(runeSubStr(s, 17, 1) == "€") -# echo runeStrAtPos(s, 18) # index error - -doAssert(runeSubStr(s, 0) == "Hänsel ««: 10,00€") -doAssert(runeSubStr(s, -18) == "Hänsel ««: 10,00€") -doAssert(runeSubStr(s, 10) == ": 10,00€") -doAssert(runeSubStr(s, 18) == "") -doAssert(runeSubStr(s, 0, 10) == "Hänsel ««") - -doAssert(runeSubStr(s, 12) == "10,00€") -doAssert(runeSubStr(s, -6) == "10,00€") - -doAssert(runeSubStr(s, 12, 5) == "10,00") -doAssert(runeSubStr(s, 12, -1) == "10,00") -doAssert(runeSubStr(s, -6, 5) == "10,00") -doAssert(runeSubStr(s, -6, -1) == "10,00") - -doAssert(runeSubStr(s, 0, 100) == "Hänsel ««: 10,00€") -doAssert(runeSubStr(s, -100, 100) == "Hänsel ««: 10,00€") -doAssert(runeSubStr(s, 0, -100) == "") -doAssert(runeSubStr(s, 100, -100) == "") - -block splitTests: - let s = " this is an example " - let s2 = ":this;is;an:example;;" - let s3 = ":this×is×an:example××" - doAssert s.split() == @["", "this", "is", "an", "example", "", ""] - doAssert s2.split(seps = [':'.Rune, ';'.Rune]) == @["", "this", "is", "an", - "example", "", ""] - doAssert s3.split(seps = [':'.Rune, "×".asRune]) == @["", "this", "is", - "an", "example", "", ""] - doAssert s.split(maxsplit = 4) == @["", "this", "is", "an", "example "] - doAssert s.split(' '.Rune, maxsplit = 1) == @["", "this is an example "] - doAssert s3.split("×".runeAt(0)) == @[":this", "is", "an:example", "", ""] - -block stripTests: - doAssert(strip("") == "") - doAssert(strip(" ") == "") - doAssert(strip("y") == "y") - doAssert(strip(" foofoofoo ") == "foofoofoo") - doAssert(strip("sfoofoofoos", runes = ['s'.Rune]) == "foofoofoo") - - block: - let stripTestRunes = ['b'.Rune, 'a'.Rune, 'r'.Rune] - doAssert(strip("barfoofoofoobar", runes = stripTestRunes) == "foofoofoo") - doAssert(strip("sfoofoofoos", leading = false, runes = ['s'.Rune]) == "sfoofoofoo") - doAssert(strip("sfoofoofoos", trailing = false, runes = ['s'.Rune]) == "foofoofoos") - - block: - let stripTestRunes = ["«".asRune, "»".asRune] - doAssert(strip("«TEXT»", runes = stripTestRunes) == "TEXT") - doAssert(strip("copyright©", leading = false, runes = ["©".asRune]) == "copyright") - doAssert(strip("¿Question?", trailing = false, runes = ["¿".asRune]) == "Question?") - doAssert(strip("×text×", leading = false, runes = ["×".asRune]) == "×text") - doAssert(strip("×text×", trailing = false, runes = ["×".asRune]) == "text×") - -block repeatTests: - doAssert repeat('c'.Rune, 5) == "ccccc" - doAssert repeat("×".asRune, 5) == "×××××" - -block alignTests: - doAssert align("abc", 4) == " abc" - doAssert align("a", 0) == "a" - doAssert align("1232", 6) == " 1232" - doAssert align("1232", 6, '#'.Rune) == "##1232" - doAssert align("1232", 6, "×".asRune) == "××1232" - doAssert alignLeft("abc", 4) == "abc " - doAssert alignLeft("a", 0) == "a" - doAssert alignLeft("1232", 6) == "1232 " - doAssert alignLeft("1232", 6, '#'.Rune) == "1232##" - doAssert alignLeft("1232", 6, "×".asRune) == "1232××" - -block differentSizes: - # upper and lower variants have different number of bytes - doAssert toLower("AẞC") == "aßc" - doAssert toLower("ȺẞCD") == "ⱥßcd" - doAssert toUpper("ⱥbc") == "ȺBC" - doAssert toUpper("rsⱦuv") == "RSȾUV" - doAssert swapCase("ⱥbCd") == "ȺBcD" - doAssert swapCase("XyꟆaB") == "xYᶎAb" - doAssert swapCase("aᵹcᲈd") == "AꝽCꙊD" - -block: # bug #17768 - let s1 = "abcdef" - let s2 = "abcdéf" - - doAssert s1.runeSubStr(0, -1) == "abcde" - doAssert s2.runeSubStr(0, -1) == "abcdé" diff --git a/tests/stdlib/tunidecode.nim b/tests/stdlib/tunidecode.nim index 653016ea9..689453c76 100644 --- a/tests/stdlib/tunidecode.nim +++ b/tests/stdlib/tunidecode.nim @@ -1,13 +1,12 @@ discard """ cmd: "nim $target --hints:on -d:embedUnidecodeTable $options $file" + output: "Ausserst" """ import unidecode -import std/unidecode # #14112 -import std/assertions - loadUnidecodeTable("lib/pure/unidecode/unidecode.dat") -doAssert unidecode("北京") == "Bei Jing " -doAssert unidecode("Äußerst") == "Ausserst" +#assert unidecode("\x53\x17\x4E\xB0") == "Bei Jing" +echo unidecode("Äußerst") + diff --git a/tests/stdlib/tunittest.nim b/tests/stdlib/tunittest.nim index 606c9bc70..65baefef0 100644 --- a/tests/stdlib/tunittest.nim +++ b/tests/stdlib/tunittest.nim @@ -1,7 +1,5 @@ discard """ - output: ''' - -[Suite] suite with only teardown + output: '''[Suite] suite with only teardown [Suite] suite with only setup @@ -18,12 +16,11 @@ discard """ [Suite] test suite [Suite] test name filtering + ''' -targets: "c js" """ -import std/[unittest, sequtils, assertions] -from std/unittest {.all.} import matchFilter +import unittest, sequtils proc doThings(spuds: var int): int = spuds = 24 @@ -34,12 +31,12 @@ test "#964": check spuds == 24 -from std/strutils import toUpperAscii +from strutils import toUpperAscii test "#1384": check(@["hello", "world"].map(toUpperAscii) == @["HELLO", "WORLD"]) -import std/options +import options test "unittest typedescs": check(none(int) == none(int)) check(none(int) != some(1)) @@ -50,16 +47,16 @@ test "unittest multiple requires": require(true) -import std/random -from std/strutils import parseInt +import math, random +from strutils import parseInt proc defectiveRobot() = - case rand(1..4) + case random(1..4) of 1: raise newException(OSError, "CANNOT COMPUTE!") of 2: discard parseInt("Hello World!") of 3: raise newException(IOError, "I can't do that Dave.") - else: doAssert 2 + 2 == 5 + else: assert 2 + 2 == 5 test "unittest expect": - expect IOError, OSError, ValueError, AssertionDefect: + expect IOError, OSError, ValueError, AssertionError: defectiveRobot() var @@ -144,50 +141,38 @@ suite "test suite": check(a == b) -suite "test name filtering": - test "test name": - check matchFilter("suite1", "foo", "") - check matchFilter("suite1", "foo", "foo") - check matchFilter("suite1", "foo", "::") - check matchFilter("suite1", "foo", "*") - check matchFilter("suite1", "foo", "::foo") - check matchFilter("suite1", "::foo", "::foo") +when defined(testing): + suite "test name filtering": + test "test name": + check matchFilter("suite1", "foo", "") + check matchFilter("suite1", "foo", "foo") + check matchFilter("suite1", "foo", "::") + check matchFilter("suite1", "foo", "*") + check matchFilter("suite1", "foo", "::foo") + check matchFilter("suite1", "::foo", "::foo") - test "test name - glob": - check matchFilter("suite1", "foo", "f*") - check matchFilter("suite1", "foo", "*oo") - check matchFilter("suite1", "12345", "12*345") - check matchFilter("suite1", "q*wefoo", "q*wefoo") - check false == matchFilter("suite1", "foo", "::x") - check false == matchFilter("suite1", "foo", "::x*") - check false == matchFilter("suite1", "foo", "::*x") - # overlap - check false == matchFilter("suite1", "12345", "123*345") - check matchFilter("suite1", "ab*c::d*e::f", "ab*c::d*e::f") + test "test name - glob": + check matchFilter("suite1", "foo", "f*") + check matchFilter("suite1", "foo", "*oo") + check matchFilter("suite1", "12345", "12*345") + check matchFilter("suite1", "q*wefoo", "q*wefoo") + check false == matchFilter("suite1", "foo", "::x") + check false == matchFilter("suite1", "foo", "::x*") + check false == matchFilter("suite1", "foo", "::*x") + # overlap + check false == matchFilter("suite1", "12345", "123*345") + check matchFilter("suite1", "ab*c::d*e::f", "ab*c::d*e::f") - test "suite name": - check matchFilter("suite1", "foo", "suite1::") - check false == matchFilter("suite1", "foo", "suite2::") - check matchFilter("suite1", "qwe::foo", "qwe::foo") - check matchFilter("suite1", "qwe::foo", "suite1::qwe::foo") + test "suite name": + check matchFilter("suite1", "foo", "suite1::") + check false == matchFilter("suite1", "foo", "suite2::") + check matchFilter("suite1", "qwe::foo", "qwe::foo") + check matchFilter("suite1", "qwe::foo", "suite1::qwe::foo") - test "suite name - glob": - check matchFilter("suite1", "foo", "::*") - check matchFilter("suite1", "foo", "*::*") - check matchFilter("suite1", "foo", "*::foo") - check false == matchFilter("suite1", "foo", "*ite2::") - check matchFilter("suite1", "q**we::foo", "q**we::foo") - check matchFilter("suite1", "a::b*c::d*e", "a::b*c::d*e") - - -block: - type MyFoo = object - var obj = MyFoo() - let check = 1 - check(obj == obj) - -block: - let check = 123 - var a = 1 - var b = 1 - check(a == b) + test "suite name - glob": + check matchFilter("suite1", "foo", "::*") + check matchFilter("suite1", "foo", "*::*") + check matchFilter("suite1", "foo", "*::foo") + check false == matchFilter("suite1", "foo", "*ite2::") + check matchFilter("suite1", "q**we::foo", "q**we::foo") + check matchFilter("suite1", "a::b*c::d*e", "a::b*c::d*e") diff --git a/tests/stdlib/tunittest_error.nim b/tests/stdlib/tunittest_error.nim deleted file mode 100644 index 7f05ec2a9..000000000 --- a/tests/stdlib/tunittest_error.nim +++ /dev/null @@ -1,22 +0,0 @@ -discard """ - exitcode: 1 - outputsub: "failed: 1 == 3" - matrix: "-d:case1; -d:case2" - targets: "c js" - joinable: false -""" - -when defined case1: - import unittest - suite "Test": - test "test require": - check 1==2 - check 1==3 - -when defined case2: - import unittest - suite "Test": - test "test require": - require 1 == 3 - if true: - quit 0 # intentional diff --git a/tests/stdlib/tunittestpass.nim b/tests/stdlib/tunittestpass.nim deleted file mode 100644 index cff37a3b7..000000000 --- a/tests/stdlib/tunittestpass.nim +++ /dev/null @@ -1,19 +0,0 @@ -discard """ - targets: "c js" -""" - - -import unittest - -block: - check (type(1.0)) is float - check type(1.0) is float - check (typeof(1)) isnot float - check typeof(1) isnot float - - check 1.0 is float - check 1 isnot float - - type T = type(0.1) - check T is float - check T isnot int diff --git a/tests/stdlib/tunittesttemplate.nim b/tests/stdlib/tunittesttemplate.nim index c29e0de01..2ca50a18b 100644 --- a/tests/stdlib/tunittesttemplate.nim +++ b/tests/stdlib/tunittesttemplate.nim @@ -8,9 +8,9 @@ discard """ """ - # bug #6736 -import std/unittest + +import unittest type A = object diff --git a/tests/stdlib/turi.nim b/tests/stdlib/turi.nim deleted file mode 100644 index 77ba02dd1..000000000 --- a/tests/stdlib/turi.nim +++ /dev/null @@ -1,322 +0,0 @@ -discard """ - targets: "c js" -""" - -import std/uri -from std/uri {.all.} as uri2 import removeDotSegments -from std/sequtils import toSeq -import std/assertions - -template main() = - block: # encodeUrl, decodeUrl - const test1 = "abc\L+def xyz" - doAssert encodeUrl(test1) == "abc%0A%2Bdef+xyz" - doAssert decodeUrl(encodeUrl(test1)) == test1 - doAssert encodeUrl(test1, false) == "abc%0A%2Bdef%20xyz" - doAssert decodeUrl(encodeUrl(test1, false), false) == test1 - doAssert decodeUrl(encodeUrl(test1)) == test1 - - block: # removeDotSegments - doAssert removeDotSegments("/foo/bar/baz") == "/foo/bar/baz" - doAssert removeDotSegments("") == "" # empty test - doAssert removeDotSegments(".") == "." # trailing period - doAssert removeDotSegments("a1/a2/../a3/a4/a5/./a6/a7/././") == "a1/a3/a4/a5/a6/a7/" - doAssert removeDotSegments("https://a1/a2/../a3/a4/a5/./a6/a7/././") == "https://a1/a3/a4/a5/a6/a7/" - doAssert removeDotSegments("http://a1/a2") == "http://a1/a2" - doAssert removeDotSegments("http://www.ai.") == "http://www.ai." - when false: # xxx these cases are buggy - # this should work, refs https://webmasters.stackexchange.com/questions/73934/how-can-urls-have-a-dot-at-the-end-e-g-www-bla-de - doAssert removeDotSegments("http://www.ai./") == "http://www.ai./" # fails - echo removeDotSegments("http://www.ai./") # http://www.ai/ - echo removeDotSegments("a/b.../c") # b.c - echo removeDotSegments("a/b../c") # bc - echo removeDotSegments("a/.../c") # .c - echo removeDotSegments("a//../b") # a/b - echo removeDotSegments("a/b/c//") # a/b/c// - - block: # parseUri - block: - let org = "udp://[2001:0db8:85a3:0000:0000:8a2e:0370:7334]:8080" - let url = parseUri(org) - doAssert url.hostname == "2001:0db8:85a3:0000:0000:8a2e:0370:7334" # true - let newUrl = parseUri($url) - doAssert newUrl.hostname == "2001:0db8:85a3:0000:0000:8a2e:0370:7334" # true - - block: - let str = "http://localhost" - let test = parseUri(str) - doAssert test.path == "" - - block: - let str = "http://localhost/" - let test = parseUri(str) - doAssert test.path == "/" - - block: - let str = "http://localhost:8080/test" - let test = parseUri(str) - doAssert test.scheme == "http" - doAssert test.port == "8080" - doAssert test.path == "/test" - doAssert test.hostname == "localhost" - doAssert($test == str) - - block: - let str = "foo://username:password@example.com:8042/over/there" & - "/index.dtb?type=animal&name=narwhal#nose" - let test = parseUri(str) - doAssert test.scheme == "foo" - doAssert test.username == "username" - doAssert test.password == "password" - doAssert test.hostname == "example.com" - doAssert test.port == "8042" - doAssert test.path == "/over/there/index.dtb" - doAssert test.query == "type=animal&name=narwhal" - doAssert test.anchor == "nose" - doAssert($test == str) - - block: - # IPv6 address - let str = "foo://[::1]:1234/bar?baz=true&qux#quux" - let uri = parseUri(str) - doAssert uri.scheme == "foo" - doAssert uri.hostname == "::1" - doAssert uri.port == "1234" - doAssert uri.path == "/bar" - doAssert uri.query == "baz=true&qux" - doAssert uri.anchor == "quux" - - block: - let str = "urn:example:animal:ferret:nose" - let test = parseUri(str) - doAssert test.scheme == "urn" - doAssert test.path == "example:animal:ferret:nose" - doAssert($test == str) - - block: - let str = "mailto:username@example.com?subject=Topic" - let test = parseUri(str) - doAssert test.scheme == "mailto" - doAssert test.username == "username" - doAssert test.hostname == "example.com" - doAssert test.query == "subject=Topic" - doAssert($test == str) - - block: - let str = "magnet:?xt=urn:sha1:72hsga62ba515sbd62&dn=foobar" - let test = parseUri(str) - doAssert test.scheme == "magnet" - doAssert test.query == "xt=urn:sha1:72hsga62ba515sbd62&dn=foobar" - doAssert($test == str) - - block: - let str = "/test/foo/bar?q=2#asdf" - let test = parseUri(str) - doAssert test.scheme == "" - doAssert test.path == "/test/foo/bar" - doAssert test.query == "q=2" - doAssert test.anchor == "asdf" - doAssert($test == str) - - block: - let str = "test/no/slash" - let test = parseUri(str) - doAssert test.path == "test/no/slash" - doAssert($test == str) - - block: - let str = "//git@github.com:dom96/packages" - let test = parseUri(str) - doAssert test.scheme == "" - doAssert test.username == "git" - doAssert test.hostname == "github.com" - doAssert test.port == "dom96" - doAssert test.path == "/packages" - - block: - let str = "file:///foo/bar/baz.txt" - let test = parseUri(str) - doAssert test.scheme == "file" - doAssert test.username == "" - doAssert test.hostname == "" - doAssert test.port == "" - doAssert test.path == "/foo/bar/baz.txt" - - block: # combine - block: - let concat = combine(parseUri("http://google.com/foo/bar/"), parseUri("baz")) - doAssert concat.path == "/foo/bar/baz" - doAssert concat.hostname == "google.com" - doAssert concat.scheme == "http" - - block: - let concat = combine(parseUri("http://google.com/foo"), parseUri("/baz")) - doAssert concat.path == "/baz" - doAssert concat.hostname == "google.com" - doAssert concat.scheme == "http" - - block: - let concat = combine(parseUri("http://google.com/foo/test"), parseUri("bar")) - doAssert concat.path == "/foo/bar" - - block: - let concat = combine(parseUri("http://google.com/foo/test"), parseUri("/bar")) - doAssert concat.path == "/bar" - - block: - let concat = combine(parseUri("http://google.com/foo/test"), parseUri("bar")) - doAssert concat.path == "/foo/bar" - - block: - let concat = combine(parseUri("http://google.com/foo/test/"), parseUri("bar")) - doAssert concat.path == "/foo/test/bar" - - block: - let concat = combine(parseUri("http://google.com/foo/test/"), parseUri("bar/")) - doAssert concat.path == "/foo/test/bar/" - - block: - let concat = combine(parseUri("http://google.com/foo/test/"), parseUri("bar/"), - parseUri("baz")) - doAssert concat.path == "/foo/test/bar/baz" - - block: # `/` - block: - let test = parseUri("http://example.com/foo") / "bar/asd" - doAssert test.path == "/foo/bar/asd" - - block: - let test = parseUri("http://example.com/foo/") / "/bar/asd" - doAssert test.path == "/foo/bar/asd" - - block: # bug #3207 - doAssert parseUri("http://qq/1").combine(parseUri("https://qqq")).`$` == "https://qqq" - - block: # bug #4959 - let foo = parseUri("http://example.com") / "/baz" - doAssert foo.path == "/baz" - - block: # bug found on stream 13/10/17 - let foo = parseUri("http://localhost:9515") / "status" - doAssert $foo == "http://localhost:9515/status" - - block: # bug #6649 #6652 - var foo = parseUri("http://example.com") - foo.hostname = "example.com" - foo.path = "baz" - doAssert $foo == "http://example.com/baz" - - foo.hostname = "example.com/" - foo.path = "baz" - doAssert $foo == "http://example.com/baz" - - foo.hostname = "example.com" - foo.path = "/baz" - doAssert $foo == "http://example.com/baz" - - foo.hostname = "example.com/" - foo.path = "/baz" - doAssert $foo == "http://example.com/baz" - - foo.hostname = "example.com/" - foo.port = "8000" - foo.path = "baz" - doAssert $foo == "http://example.com:8000/baz" - - foo = parseUri("file:/dir/file") - foo.path = "relative" - doAssert $foo == "file:relative" - - block: # isAbsolute tests - doAssert "www.google.com".parseUri().isAbsolute() == false - doAssert "http://www.google.com".parseUri().isAbsolute() == true - doAssert "file:/dir/file".parseUri().isAbsolute() == true - doAssert "file://localhost/dir/file".parseUri().isAbsolute() == true - doAssert "urn:ISSN:1535-3613".parseUri().isAbsolute() == true - - # path-relative URL *relative - doAssert "about".parseUri().isAbsolute == false - doAssert "about/staff.html".parseUri().isAbsolute == false - doAssert "about/staff.html?".parseUri().isAbsolute == false - doAssert "about/staff.html?parameters".parseUri().isAbsolute == false - - # absolute-path-relative URL *relative - doAssert "/".parseUri().isAbsolute == false - doAssert "/about".parseUri().isAbsolute == false - doAssert "/about/staff.html".parseUri().isAbsolute == false - doAssert "/about/staff.html?".parseUri().isAbsolute == false - doAssert "/about/staff.html?parameters".parseUri().isAbsolute == false - - # scheme-relative URL *relative - doAssert "//username:password@example.com:8888".parseUri().isAbsolute == false - doAssert "//username@example.com".parseUri().isAbsolute == false - doAssert "//example.com".parseUri().isAbsolute == false - doAssert "//example.com/".parseUri().isAbsolute == false - doAssert "//example.com/about".parseUri().isAbsolute == false - doAssert "//example.com/about/staff.html".parseUri().isAbsolute == false - doAssert "//example.com/about/staff.html?".parseUri().isAbsolute == false - doAssert "//example.com/about/staff.html?parameters".parseUri().isAbsolute == false - - # absolute URL *absolute - doAssert "https://username:password@example.com:8888".parseUri().isAbsolute == true - doAssert "https://username@example.com".parseUri().isAbsolute == true - doAssert "https://example.com".parseUri().isAbsolute == true - doAssert "https://example.com/".parseUri().isAbsolute == true - doAssert "https://example.com/about".parseUri().isAbsolute == true - doAssert "https://example.com/about/staff.html".parseUri().isAbsolute == true - doAssert "https://example.com/about/staff.html?".parseUri().isAbsolute == true - doAssert "https://example.com/about/staff.html?parameters".parseUri().isAbsolute == true - - block: # encodeQuery tests - doAssert encodeQuery({:}) == "" - doAssert encodeQuery({"foo": "bar"}) == "foo=bar" - doAssert encodeQuery({"foo": "bar & baz"}) == "foo=bar+%26+baz" - doAssert encodeQuery({"foo": "bar & baz"}, usePlus = false) == "foo=bar%20%26%20baz" - doAssert encodeQuery({"foo": ""}) == "foo" - doAssert encodeQuery({"foo": ""}, omitEq = false) == "foo=" - doAssert encodeQuery({"a": "1", "b": "", "c": "3"}) == "a=1&b&c=3" - doAssert encodeQuery({"a": "1", "b": "", "c": "3"}, sep = ';') == "a=1;b;c=3" - doAssert encodeQuery({"a": "1", "b": "", "c": "3"}, omitEq = false) == "a=1&b=&c=3" - doAssert encodeQuery({"a": "1", "b": "", "c": "3"}, omitEq = false, sep = ';') == "a=1;b=;c=3" - - block: # `?` - block: - var foo = parseUri("http://example.com") / "foo" ? {"bar": "1", "baz": "qux"} - var foo1 = parseUri("http://example.com/foo?bar=1&baz=qux") - doAssert foo == foo1 - block: - var foo = parseUri("http://example.com") / "foo" ? {"do": "do", "bar": ""} - var foo1 = parseUri("http://example.com/foo?do=do&bar") - doAssert foo == foo1 - - block: # getDataUri, dataUriBase64 - doAssert getDataUri("", "text/plain") == "data:text/plain;charset=utf-8;base64," - doAssert getDataUri(" ", "text/plain") == "data:text/plain;charset=utf-8;base64,IA==" - doAssert getDataUri("c\xf7>", "text/plain") == "data:text/plain;charset=utf-8;base64,Y/c+" - doAssert getDataUri("Hello World", "text/plain") == "data:text/plain;charset=utf-8;base64,SGVsbG8gV29ybGQ=" - doAssert getDataUri("leasure.", "text/plain") == "data:text/plain;charset=utf-8;base64,bGVhc3VyZS4=" - doAssert getDataUri("""!@#$%^&*()_+""", "text/plain") == "data:text/plain;charset=utf-8;base64,IUAjJCVeJiooKV8r" - doAssert(getDataUri("the quick brown dog jumps over the lazy fox", "text/plain") == - "data:text/plain;charset=utf-8;base64,dGhlIHF1aWNrIGJyb3duIGRvZyBqdW1wcyBvdmVyIHRoZSBsYXp5IGZveA==") - doAssert(getDataUri("The present is theirs\n The future, for which I really worked, is mine.", "text/plain") == - "data:text/plain;charset=utf-8;base64,VGhlIHByZXNlbnQgaXMgdGhlaXJzCiAgICAgIFRoZSBmdXR1cmUsIGZvciB3aGljaCBJIHJlYWxseSB3b3JrZWQsIGlzIG1pbmUu") - - block: # decodeQuery - doAssert toSeq(decodeQuery("a=1&b=0")) == @[("a", "1"), ("b", "0")] - doAssert toSeq(decodeQuery("a=1;b=0", sep = ';')) == @[("a", "1"), ("b", "0")] - doAssert toSeq(decodeQuery("a=1&b=2c=6")) == @[("a", "1"), ("b", "2c=6")] - doAssert toSeq(decodeQuery("a=1;b=2c=6", sep = ';')) == @[("a", "1"), ("b", "2c=6")] - - block: # bug #17481 - let u1 = parseUri("./") - let u2 = parseUri("./path") - let u3 = parseUri("a/path") - doAssert u1.scheme.len == 0 - doAssert u1.path == "./" - doAssert u2.scheme.len == 0 - doAssert u2.path == "./path" - doAssert u3.scheme.len == 0 - doAssert u3.path == "a/path" - -static: main() -main() diff --git a/tests/stdlib/tuserlocks.nim b/tests/stdlib/tuserlocks.nim deleted file mode 100644 index ba8ea050e..000000000 --- a/tests/stdlib/tuserlocks.nim +++ /dev/null @@ -1,21 +0,0 @@ -discard """ - matrix: "--threads:on" -""" - -import std/rlocks -import std/assertions - -var r: RLock -r.initRLock() -doAssert r.tryAcquire() -doAssert r.tryAcquire() -r.release() -r.release() - -block: - var x = 12 - withRLock r: - inc x - doAssert x == 13 - -r.deinitRLock() diff --git a/tests/stdlib/tvarargs.nim b/tests/stdlib/tvarargs.nim deleted file mode 100644 index 3207572b5..000000000 --- a/tests/stdlib/tvarargs.nim +++ /dev/null @@ -1,18 +0,0 @@ -discard """ - targets: "c js" - matrix: "--gc:refc; --gc:arc" -""" -import std/assertions - -template main = - proc hello(x: varargs[string]): seq[string] = - var s: seq[string] - s.add x - s - - doAssert hello() == @[] - doAssert hello("a1") == @["a1"] - doAssert hello("a1", "a2") == @["a1", "a2"] - -static: main() -main() diff --git a/tests/stdlib/tvarints.nim b/tests/stdlib/tvarints.nim deleted file mode 100644 index bb0d3d37f..000000000 --- a/tests/stdlib/tvarints.nim +++ /dev/null @@ -1,69 +0,0 @@ -import std/varints -import std/assertions - -# xxx doesn't work with js: tvarints.nim(18, 14) `wrLen == rdLen` [AssertionDefect] - -block: - var dest: array[50, byte] - var got: uint64 - - for test in [0xFFFF_FFFF_FFFFF_FFFFu64, 77u64, 0u64, 10_000_000u64, uint64(high(int64)), - uint64(high(int32)), uint64(high(int32)), uint64(high(int64))]: - let wrLen = writeVu64(dest, test) - let rdLen = readVu64(dest, got) - doAssert wrLen == rdLen - doAssert got == test - - for test in 0u64..300u64: - let wrLen = writeVu64(dest, test) - let rdLen = readVu64(dest, got) - doAssert wrLen == rdLen - doAssert got == test - - # check this also works for floats: - for test in [0.0, 0.1, 2.0, +Inf, NegInf]: - let t = cast[uint64](test) - let wrLenB = writeVu64(dest, t) - let rdLenB = readVu64(dest, got) - doAssert wrLenB == rdLenB - doAssert cast[float64](got) == test - -block: - var hugeIntArray: array[50, byte] - var readedInt: uint64 - - template chk(a) = - let b = cast[uint64](a) - doAssert writeVu64(hugeIntArray, b) == readVu64(hugeIntArray, readedInt) - doAssert readedInt == b - - chk 0 - chk uint64.high - chk int64.high - chk int32.high - chk int16.high - chk int16.high - chk int8.high - chk 0.0 - chk -0.0 - chk 0.1 - chk Inf - chk NegInf - chk NaN - chk 3.1415926535897932384626433 - -block: - template chk(a) = - let b = cast[uint64](a) - doAssert encodeZigzag(decodeZigzag(b)) == b - chk 0 - chk uint32.high - chk int32.high - chk int16.high - chk int8.high - chk 0.0 - chk 0.1 - chk 0.9555555555555555555555501 - chk Inf - chk 3.1415926535897932384626433 - chk 2.71828182845904523536028747 diff --git a/tests/stdlib/tvmutils.nim b/tests/stdlib/tvmutils.nim deleted file mode 100644 index f43557ad8..000000000 --- a/tests/stdlib/tvmutils.nim +++ /dev/null @@ -1,31 +0,0 @@ -discard """ - joinable: false - nimout: ''' -0 -1 -2 -tvmutils.nim(28, 13) [opcLdImmInt] if i == 4: -tvmutils.nim(28, 10) [opcEqInt] if i == 4: -tvmutils.nim(28, 10) [opcFJmp] if i == 4: -tvmutils.nim(28, 13) [opcLdImmInt] if i == 4: -tvmutils.nim(28, 10) [opcEqInt] if i == 4: -tvmutils.nim(28, 10) [opcFJmp] if i == 4: -tvmutils.nim(29, 7) [opcLdConst] vmTrace(false) -tvmutils.nim(29, 15) [opcLdImmInt] vmTrace(false) -tvmutils.nim(29, 14) [opcIndCall] vmTrace(false) -5 -6 -''' -""" -# line 20 (only showing a subset of nimout to avoid making the test rigid) -import std/vmutils - -proc main() = - for i in 0..<7: - echo i - if i == 2: - vmTrace(true) - if i == 4: - vmTrace(false) - -static: main() diff --git a/tests/stdlib/twchartoutf8.nim b/tests/stdlib/twchartoutf8.nim index 0b6cf696e..a6602e3e3 100644 --- a/tests/stdlib/twchartoutf8.nim +++ b/tests/stdlib/twchartoutf8.nim @@ -2,15 +2,12 @@ discard """ output: '''OK''' """ -import std/[syncio, assertions] - #assume WideCharToMultiByte always produce correct result #windows only when not defined(windows): echo "OK" else: - import std/widestrs {.push gcsafe.} const CP_UTF8 = 65001'i32 @@ -69,7 +66,8 @@ else: #RFC-2781 "UTF-16, an encoding of ISO 10646" - var wc: WideCString = newWideCString(1024 * 2) + var wc: WideCString + unsafeNew(wc, 1024 * 4 + 2) #U+0000 to U+D7FF #skip the U+0000 diff --git a/tests/stdlib/twith.nim b/tests/stdlib/twith.nim deleted file mode 100644 index b2d72bd0c..000000000 --- a/tests/stdlib/twith.nim +++ /dev/null @@ -1,24 +0,0 @@ -import std/with -import std/[assertions, formatfloat] - -type - Foo = object - col, pos: string - name: string - -proc setColor(f: var Foo; r, g, b: int) = f.col = $(r, g, b) -proc setPosition(f: var Foo; x, y: float) = f.pos = $(x, y) - -var f: Foo -with(f, setColor(2, 3, 4), setPosition(0.0, 1.0)) -doAssert f.col == "(2, 3, 4)" -doAssert f.pos == "(0.0, 1.0)" - -f = Foo() -with f: - col = $(2, 3, 4) - pos = $(0.0, 1.0) - _.name = "bar" -doAssert f.col == "(2, 3, 4)" -doAssert f.pos == "(0.0, 1.0)" -doAssert f.name == "bar" diff --git a/tests/stdlib/twordwrap.nim b/tests/stdlib/twordwrap.nim deleted file mode 100644 index a08e64cf9..000000000 --- a/tests/stdlib/twordwrap.nim +++ /dev/null @@ -1,44 +0,0 @@ -import std/wordwrap -import std/assertions - -when true: - let - inp = """ this is a long text -- muchlongerthan10chars and here - it goes""" - outp = " this is a\nlong text\n--\nmuchlongerthan10chars\nand here\nit goes" - doAssert wrapWords(inp, 10, false) == outp - - let - longInp = """ThisIsOneVeryLongStringWhichWeWillSplitIntoEightSeparatePartsNow""" - longOutp = "ThisIsOn\neVeryLon\ngStringW\nhichWeWi\nllSplitI\nntoEight\nSeparate\nPartsNow" - doAssert wrapWords(longInp, 8, true) == longOutp - -# test we don't break Umlauts into invalid bytes: -let fies = "äöüöäöüöäöüöäöüööäöüöäößßßßüöäößßßßßß" -let fiesRes = "ä\nö\nü\nö\nä\nö\nü\nö\nä\nö\nü\nö\nä\nö\nü\nö\nö\nä\nö\nü\nö\nä\nö\nß\nß\nß\nß\nü\nö\nä\nö\nß\nß\nß\nß\nß\nß" -doAssert wrapWords(fies, 1, true) == fiesRes - -let longlongword = """abc uitdaeröägfßhydüäpydqfü,träpydqgpmüdträpydföägpydörztdüöäfguiaeowäzjdtrüöäp psnrtuiydrözenrüöäpyfdqazpesnrtulocjtüö -äzydgyqgfqfgprtnwjlcydkqgfüöezmäzydydqüüöäpdtrnvwfhgckdumböäpydfgtdgfhtdrntdrntydfogiayqfguiatrnydrntüöärtniaoeydfgaoeiqfglwcßqfgxvlcwgtfhiaoen -rsüöäapmböäptdrniaoydfglckqfhouenrtsüöäptrniaoeyqfgulocfqclgwxßqflgcwßqfxglcwrniatrnmüböäpmöäbpümöäbpüöämpbaoestnriaesnrtdiaesrtdniaesdrtnaetdr -iaoenvlcyfglwckßqfgvwkßqgfvlwkßqfgvlwckßqvlwkgfUIαοιαοιαχολωχσωχνωκψρχκψρτιεαοσηζϵηζιοεννκεωνιαλωσωκνκψρκγτφγτχκγτεκργτιχνκιωχσιλωσλωχξλξλξωχωχ -ξχλωωχαοεοιαεοαεοιαεοαεοιαοεσναοεκνρκψγκψφϵιηαααοε""" -let longlongwordRes = """ -abc uitdaeröägfßhydüäpydqfü,träpydqgpmüdträpydföägpydörztdüöäfguiaeowäzjdtrüöäp -psnrtuiydrözenrüöäpyfdqazpesnrtulocjtüöäzydgyqgfqfgprtnwjlcydkqgfüöezmäzydydqüü -öäpdtrnvwfhgckdumböäpydfgtdgfhtdrntdrntydfogiayqfguiatrnydrntüöärtniaoeydfgaoeiq -fglwcßqfgxvlcwgtfhiaoenrsüöäapmböäptdrniaoydfglckqfhouenrtsüöäptrniaoeyqfgulocf -qclgwxßqflgcwßqfxglcwrniatrnmüböäpmöäbpümöäbpüöämpbaoestnriaesnrtdiaesrtdniaesdr -tnaetdriaoenvlcyfglwckßqfgvwkßqgfvlwkßqfgvlwckßqvlwkgfUIαοιαοιαχολωχσωχνωκψρχκψ -ρτιεαοσηζϵηζιοεννκεωνιαλωσωκνκψρκγτφγτχκγτεκργτιχνκιωχσιλωσλωχξλξλξωχωχ -ξχλωωχαοεοιαεοαεοιαεοαεοιαοεσναοεκνρκψγκψφϵιηαααοε""" -doAssert wrapWords(longlongword) == longlongwordRes - -# bug #14579 -const input60 = """ -This string is wrapped to 60 characters. If we call -wrapwords on it it will be re-wrapped to 80 characters. -""" -const input60Res = """This string is wrapped to 60 characters. If we call wrapwords on it it will be -re-wrapped to 80 characters.""" -doAssert wrapWords(input60) == input60Res \ No newline at end of file diff --git a/tests/stdlib/twrapnils.nim b/tests/stdlib/twrapnils.nim index 5d5c1ab2d..b20c67479 100644 --- a/tests/stdlib/twrapnils.nim +++ b/tests/stdlib/twrapnils.nim @@ -1,220 +1,82 @@ import std/wrapnils -from std/options import get, isSome -import std/assertions + +const wrapnilExtendedExports = declared(wrapnil) + # for now, wrapnil, isValid, unwrap are not exported proc checkNotZero(x: float): float = doAssert x != 0 x +var witness = 0 + proc main() = - var witness = 0 - block: - type Bar = object - b1: int - b2: ptr string + type Bar = object + b1: int + b2: ptr string - type Foo = ref object - x1: float - x2: Foo - x3: string - x4: Bar - x5: seq[int] - x6: ptr Bar - x7: array[2, string] - x8: seq[int] - x9: ref Bar + type Foo = ref object + x1: float + x2: Foo + x3: string + x4: Bar + x5: seq[int] + x6: ptr Bar + x7: array[2, string] + x8: seq[int] + x9: ref Bar - type Goo = ref object - foo: Foo + type Gook = ref object + foo: Foo - proc fun(a: Bar): auto = a.b2 + proc fun(a: Bar): auto = a.b2 - var a: Foo + var a: Foo + var x6 = create(Bar) + x6.b1 = 42 + var a2 = Foo(x1: 1.0, x5: @[10, 11], x6: x6) + var a3 = Foo(x1: 1.2, x3: "abc") + a3.x2 = a3 - var x6: ptr Bar - when nimvm: discard # pending https://github.com/timotheecour/Nim/issues/568 - else: - x6 = create(Bar) - x6.b1 = 42 - var a2 = Foo(x1: 1.0, x5: @[10, 11], x6: x6) - var a3 = Foo(x1: 1.2, x3: "abc") - a3.x2 = a3 + var gook = Gook(foo: a) - var goo = Goo(foo: a) + proc initFoo(x1: float): auto = + witness.inc + result = Foo(x1: x1) - proc initFoo(x1: float): auto = - witness.inc - result = Foo(x1: x1) + doAssert ?.a.x2.x2.x1 == 0.0 + doAssert ?.a3.x2.x2.x1 == 1.2 + doAssert ?.a3.x2.x2.x3[1] == 'b' - doAssert ?.a.x2.x2.x1 == 0.0 - doAssert ?.a3.x2.x2.x1 == 1.2 - doAssert ?.a3.x2.x2.x3[1] == 'b' + doAssert ?.a3.x2.x2.x5.len == 0 + doAssert a3.x2.x2.x3.len == 3 - doAssert ?.a3.x2.x2.x5.len == 0 - doAssert a3.x2.x2.x3.len == 3 + when wrapnilExtendedExports: + # example calling wrapnil directly, with and without unwrap + doAssert a3.wrapnil.x2.x2.x3.len == wrapnil(3) + doAssert a3.wrapnil.x2.x2.x3.len.unwrap == 3 + doAssert a2.wrapnil.x4.isValid + doAssert not a.wrapnil.x4.isValid - doAssert ?.a.x2.x2.x3[1] == default(char) - # here we only apply wrapnil around goo.foo, not goo (and assume goo is not nil) - doAssert ?.(goo.foo).x2.x2.x1 == 0.0 + doAssert ?.a.x2.x2.x3[1] == default(char) + # here we only apply wrapnil around gook.foo, not gook (and assume gook is not nil) + doAssert ?.(gook.foo).x2.x2.x1 == 0.0 - when nimvm: discard - else: - doAssert ?.a2.x6[] == Bar(b1: 42) # deref for ptr Bar + doAssert ?.a2.x6[] == Bar(b1: 42) # deref for ptr Bar - doAssert ?.a2.x1.checkNotZero == 1.0 - doAssert a == nil - # shows that checkNotZero won't be called if a nil is found earlier in chain - doAssert ?.a.x1.checkNotZero == 0.0 + doAssert ?.a2.x1.checkNotZero == 1.0 + doAssert a == nil + # shows that checkNotZero won't be called if a nil is found earlier in chain + doAssert ?.a.x1.checkNotZero == 0.0 - when nimvm: discard - else: - # checks that a chain without nil but with an empty seq still raises - doAssertRaises(IndexDefect): discard ?.a2.x8[3] + # checks that a chain without nil but with an empty seq still throws IndexError + doAssertRaises(IndexError): discard ?.a2.x8[3] - # make sure no double evaluation bug - doAssert witness == 0 - doAssert ?.initFoo(1.3).x1 == 1.3 - doAssert witness == 1 + # make sure no double evaluation bug + doAssert witness == 0 + doAssert ?.initFoo(1.3).x1 == 1.3 + doAssert witness == 1 - # here, it's used twice, to deref `ref Bar` and then `ptr string` - doAssert ?.a.x9[].fun[] == "" - - block: # `??.` - doAssert (??.a3.x2.x2.x3.len).get == 3 - doAssert (??.a2.x4).isSome - doAssert not (??.a.x4).isSome - - block: - type - A = object - b: B - B = object - c: C - C = object - d: D - D = ref object - e: E - e2: array[2, E] - e3: seq[E] - d3: D - i4: int - E = object - f: int - d2: D - proc identity[T](a: T): T = a - proc identity2[T](a: T, ignore: int): T = a - var a: A - doAssert ?.a.b.c.d.e.f == 0 - doAssert ?.a.b.c.d.e.d2.d3[].d3.e.d2.e.f == 0 - doAssert ?.a.b.c.d.d3[].e.f == 0 - doAssert ?.a.b.c.d.e2[0].d2.e3[0].f == 0 - doAssert ?.a == A.default - doAssert ?.a.b.c.d.e == E.default - doAssert ?.a.b.c.d.e.d2 == nil - - doAssert ?.a.identity.b.c.identity2(12).d.d3.e.f == 0 - doAssert ?.a.b.c.d.d3.e2[0].f == 0 - a.b.c.d = D() - a.b.c.d.d3 = a.b.c.d - a.b.c.d.e2[0].f = 5 - doAssert ?.a.b.c.d.d3.e2[0].f == 5 - - var d: D = nil - doAssert ?.d.identity.i4 == 0 - doAssert ?.d.i4.identity == 0 - - block: # case objects - type - Kind = enum k0, k1, k2 - V = object - case kind: Kind - of k0: - x0: int - of k1: - x1: int - of k2: - x2: int - A = object - v0: V - - block: - var a = V(kind: k0, x0: 3) - doAssert ?.a.x0 == 3 - doAssert ?.a.x1 == 0 - a = V(kind: k1, x1: 5) - doAssert ?.a.x0 == 0 - doAssert ?.a.x1 == 5 - - block: - var a = A(v0: V(kind: k0, x0: 10)) - doAssert ?.a.v0.x0 == 10 - doAssert ?.a.v0.x1 == 0 - a.v0 = V(kind: k2, x2: 8) - doAssert ?.a.v0.x0 == 0 - doAssert ?.a.v0.x1 == 0 - doAssert ?.a.v0.x2 == 8 - - block: # `nnkCall` - type - A = object - a0: int - d: D - D = ref object - i4: int - - proc identity[T](a: T): T = a - var d: D = nil - doAssert ?.d.i4.identity == 0 - doAssert ?.identity(?.d.i4) == 0 - doAssert ?.identity(d.i4) == 0 - doAssert ?.identity(d) == nil - doAssert ?.identity(d[]) == default(typeof(d[])) - doAssert ?.identity(d[]).i4 == 0 - var a: A - doAssert ?.identity(a) == default(A) - doAssert ?.identity(a.a0) == 0 - doAssert ?.identity(a.d) == nil - doAssert ?.identity(a.d.i4) == 0 - - block: # lvalue semantic propagation - type - A = ref object - a0: A - a1: seq[A] - a2: int - - B = object - b0: int - case cond: bool - of false: discard - of true: - b1: float - - block: - var a: A - doAssert ?.a.a0.a1[0].a2.addr == nil - a = A(a2: 3) - doAssert ?.a.a0.a1[0].a2.addr == nil - a.a0 = a - a.a1 = @[a] - let p = ?.a.a0.a1[0].a2.addr - doAssert p != nil - p[] = 5 - doAssert a.a2 == 5 - - block: - var b = B(cond: false, b0: 3) - let p = ?.b.b1.addr - doAssert p == nil - b = B(cond: true, b1: 4.5) - let p2 = ?.b.b1.addr - doAssert p2 != nil - p2[] = 4.6 - doAssert b.b1 == 4.6 - # useful pattern, impossible with Options - if (let p3 = ?.b.b1.addr; p3 != nil): - p3[] = 4.7 - doAssert b.b1 == 4.7 + # here, it's used twice, to deref `ref Bar` and then `ptr string` + doAssert ?.a.x9[].fun[] == "" main() -static: main() diff --git a/tests/stdlib/txmltree.nim b/tests/stdlib/txmltree.nim deleted file mode 100644 index 4362f5ec3..000000000 --- a/tests/stdlib/txmltree.nim +++ /dev/null @@ -1,101 +0,0 @@ -import std/[xmltree, assertions, xmlparser] - - -block: - var - x: XmlNode - - x = <>a(href = "http://nim-lang.org", newText("Nim rules.")) - doAssert $x == """Nim rules.""" - - x = <>outer(<>inner()) - doAssert $x == """ - -""" - - x = <>outer(<>middle(<>inner1(), <>inner2(), <>inner3(), <>inner4())) - doAssert $x == """ - - - - - - -""" - - x = <>l0(<>l1(<>l2(<>l3(<>l4())))) - doAssert $x == """ - - - - - - - -""" - - x = <>l0(<>l1p1(), <>l1p2(), <>l1p3()) - doAssert $x == """ - - - -""" - - x = <>l0(<>l1(<>l2p1(), <>l2p2())) - doAssert $x == """ - - - - -""" - - x = <>l0(<>l1(<>l2_1(), <>l2_2(<>l3_1(), <>l3_2(), <>l3_3(<>l4_1(), <>l4_2(), <>l4_3())), <>l2_3(), <>l2_4())) - doAssert $x == """ - - - - - - - - - - - - - - -""" - - let - innermost = newElement("innermost") - middle = newXmlTree("middle", [innermost]) - innermost.add newText("innermost text") - x = newXmlTree("outer", [middle]) - doAssert $x == """ - - innermost text - -""" - - x = newElement("myTag") - x.add newText("my text") - x.add newElement("sonTag") - x.add newEntity("my entity") - doAssert $x == "my text&my entity;" - -block: # bug #21290 - let x = newXmlTree("foo",[ - newXmlTree("bar",[ - newText("Hola"), - newXmlTree("qux",[ - newXmlTree("plugh",[]) - ]) - ]) - ]) - - let s = $x - doAssert $parseXml(s) == s - doAssert s == """ - Hola -""" diff --git a/tests/stdlib/tyield.nim b/tests/stdlib/tyield.nim deleted file mode 100644 index 0cf52999c..000000000 --- a/tests/stdlib/tyield.nim +++ /dev/null @@ -1,257 +0,0 @@ -discard """ - targets: "c cpp js" -""" - -import std/[sugar, algorithm] -import std/assertions - -block: - var x = @[(6.0, 6, '6'), - (5.0, 5, '5'), - (4.0, 4, '4'), - (3.0, 3, '3'), - (2.0, 2, '2'), - (1.0, 1, '1')] - - let y = x.reversed - - block: - let res = collect: - for (f, i, c) in x: - (f, i, c) - - doAssert res == x - - iterator popAscending[T](q: var seq[T]): T = - while q.len > 0: yield q.pop - - block: - var res = collect: - for f, i, c in popAscending(x): - (f, i, c) - - doAssert res == y - - let z = reversed(res) - let res2 = collect: - for (f, i, c) in popAscending(res): - (f, i, c) - - doAssert res2 == z - - -block: - var visits = 0 - block: - proc bar(): (int, int) = - inc visits - (visits, visits) - - iterator foo(): (int, int) = - yield bar() - - for a, b in foo(): - doAssert a == b - - doAssert visits == 1 - - block: - proc iterAux(a: seq[int], i: var int): (int, string) = - result = (a[i], $a[i]) - inc i - - iterator pairs(a: seq[int]): (int, string) = - var i = 0 - while i < a.len: - yield iterAux(a, i) - - var x = newSeq[int](10) - for i in 0 ..< x.len: - x[i] = i - - let res = collect: - for k, v in x: - (k, v) - - let expected = collect: - for i in 0 ..< x.len: - (i, $i) - - doAssert res == expected - - block: - proc bar(): (int, int, int) = - inc visits - (visits, visits, visits) - - iterator foo(): (int, int, int) = - yield bar() - - for a, b, c in foo(): - doAssert a == b - - doAssert visits == 2 - - - block: - - proc bar(): int = - inc visits - visits - - proc car(): int = - inc visits - visits - - iterator foo(): (int, int) = - yield (bar(), car()) - yield (bar(), car()) - - for a, b in foo(): - doAssert b == a + 1 - - doAssert visits == 6 - - - block: - proc bar(): (int, int) = - inc visits - (visits, visits) - - proc t2(): int = 99 - - iterator foo(): (int, int) = - yield (12, t2()) - yield bar() - - let res = collect: - for (a, b) in foo(): - (a, b) - - doAssert res == @[(12, 99), (7, 7)] - doAssert visits == 7 - - block: - proc bar(): (int, int) = - inc visits - (visits, visits) - - proc t2(): int = 99 - - iterator foo(): (int, int) = - yield ((12, t2())) - yield (bar()) - - let res = collect: - for (a, b) in foo(): - (a, b) - - doAssert res == @[(12, 99), (8, 8)] - doAssert visits == 8 - - block: - proc bar(): (int, int) = - inc visits - (visits, visits) - - proc t1(): int = 99 - proc t2(): int = 99 - - iterator foo(): (int, int) = - yield (t1(), t2()) - yield bar() - - let res = collect: - for a, b in foo(): - (a, b) - - doAssert res == @[(99, 99), (9, 9)] - doAssert visits == 9 - - - block: - proc bar(): ((int, int), string) = - inc visits - ((visits, visits), $visits) - - proc t2(): int = 99 - - iterator foo(): ((int, int), string) = - yield ((1, 2), $t2()) - yield bar() - - let res = collect: - for a, b in foo(): - (a, b) - - doAssert res == @[((1, 2), "99"), ((10, 10), "10")] - doAssert visits == 10 - - - block: - proc bar(): (int, int) = - inc visits - (visits, visits) - - iterator foo(): (int, int) = - yield (for i in 0 ..< 10: discard bar(); bar()) - yield (bar()) - - let res = collect: - for (a, b) in foo(): - (a, b) - - doAssert res == @[(21, 21), (22, 22)] - - block: - proc bar(): (int, int) = - inc visits - (visits, visits) - - proc t2(): int = 99 - - iterator foo(): (int, int) = - yield if true: bar() else: (t2(), t2()) - yield (bar()) - - let res = collect: - for a, b in foo(): - (a, b) - - doAssert res == @[(23, 23), (24, 24)] - - -block: - iterator foo(): (int, int, int) = - var time = 777 - yield (1, time, 3) - - let res = collect: - for a, b, c in foo(): - (a, b, c) - - doAssert res == @[(1, 777, 3)] - -block: - iterator foo(): (int, int, int) = - var time = 777 - yield (1, time, 3) - - let res = collect: - for t in foo(): - (t[0], t[1], t[2]) - - doAssert res == @[(1, 777, 3)] - - -block: - proc bar(): (int, int, int) = - (1, 2, 3) - iterator foo(): (int, int, int) = - yield bar() - - let res = collect: - for a, b, c in foo(): - (a, b, c) - - doAssert res == @[(1, 2, 3)] diff --git a/tests/stdlib/uselocks.nim b/tests/stdlib/uselocks.nim index f87623b5e..cde9641b2 100644 --- a/tests/stdlib/uselocks.nim +++ b/tests/stdlib/uselocks.nim @@ -1,5 +1,4 @@ import locks -import std/assertions type MyType* [T] = object lock: Lock @@ -10,7 +9,3 @@ proc createMyType*[T]: MyType[T] = proc use* (m: var MyType): int = withLock m.lock: result = 3 - -block: - var l: Lock - doAssert $l == "()" diff --git a/tests/stmt/tforloop_tuple_multiple_underscore.nim b/tests/stmt/tforloop_tuple_multiple_underscore.nim deleted file mode 100644 index 2afdb0b77..000000000 --- a/tests/stmt/tforloop_tuple_multiple_underscore.nim +++ /dev/null @@ -1,10 +0,0 @@ -discard """ - errormsg: "undeclared identifier: '_'" -""" - -iterator iter(): (int, int, int) = - yield (1, 1, 2) - - -for (_, i, _) in iter(): - echo _ \ No newline at end of file diff --git a/tests/stmt/tforloop_tuple_underscore.nim b/tests/stmt/tforloop_tuple_underscore.nim deleted file mode 100644 index 8cbb0fc10..000000000 --- a/tests/stmt/tforloop_tuple_underscore.nim +++ /dev/null @@ -1,16 +0,0 @@ -discard """ - errormsg: "undeclared identifier: '_'" -""" - -iterator iter(): (int, int) = - yield (1, 2) - yield (3, 4) - yield (1, 2) - yield (3, 4) - yield (1, 2) - yield (3, 4) - - -for (_, i) in iter(): - echo _ - diff --git a/tests/stmt/tforloop_underscore.nim b/tests/stmt/tforloop_underscore.nim deleted file mode 100644 index c5b49da77..000000000 --- a/tests/stmt/tforloop_underscore.nim +++ /dev/null @@ -1,6 +0,0 @@ -discard """ - errormsg: "undeclared identifier: '_'" -""" - -for _ in ["a"]: - echo _ diff --git a/tests/strictnotnil/tnilcheck.nim b/tests/strictnotnil/tnilcheck.nim deleted file mode 100644 index b8057de74..000000000 --- a/tests/strictnotnil/tnilcheck.nim +++ /dev/null @@ -1,381 +0,0 @@ -discard """ -action: compile -""" - -import tables - -{.experimental: "strictNotNil".} - -type - Nilable* = ref object - a*: int - field*: Nilable - - NonNilable* = Nilable not nil - - Nilable2* = nil NonNilable - - -# proc `[]`(a: Nilable, b: int): Nilable = -# nil - - -# Nilable tests - - - -# test deref -proc testDeref(a: Nilable) = - echo a.a > 0 #[tt.Warning - ^ can't deref a, it might be nil - ]# - - - -# # # test if else -proc testIfElse(a: Nilable) = - if a.isNil: - echo a.a #[tt.Warning - ^ can't deref a, it is nil - ]# - else: - echo a.a # ok - -proc testIfNoElse(a: Nilable) = - if a.isNil: - echo a.a #[tt.Warning - ^ can't deref a, it is nil - ]# - echo a.a #[tt.Warning - ^ can't deref a, it might be nil - ]# - -proc testIfReturn(a: Nilable) = - if not a.isNil: - return - echo a.a #[tt.Warning - ^ can't deref a, it is nil - ]# - -proc testIfBreak(a: seq[Nilable]) = - for b in a: - if not b.isNil: - break - echo b.a #[tt.Warning - ^ can't deref b, it is nil - ]# - -proc testIfContinue(a: seq[Nilable]) = - for b in a: - if not b.isNil: - continue - echo b.a #[tt.Warning - ^ can't deref b, it is nil - ]# - -proc testIfRaise(a: Nilable) = - if not a.isNil: - raise newException(ValueError, "") - echo a.a #[tt.Warning - ^ can't deref a, it is nil - ]# - -proc testIfElif(a: Nilable) = - var c = 0 - if c == 0: - echo a.a #[tt.Warning - ^ can't deref a, it might be nil - ]# - elif c == 1: - echo a.a #[tt.Warning - ^ can't deref a, it might be nil - ]# - elif not a.isNil: - echo a.a # ok - elif c == 2: - echo 0 - else: - echo a.a #[tt.Warning - ^ can't deref a, it is nil - ]# - -proc testAssignUnify(a: Nilable, b: int) = - var a2 = a - if b == 0: - a2 = Nilable() - echo a2.a #[tt.Warning - ^ can't deref a2, it might be nil - ]# - - -# # test assign in branch and unifiying that with the main block after end of branch -proc testAssignUnifyNil(a: Nilable, b: int) = - var a2 = a - if b == 0: - a2 = nil - echo a2.a #[tt.Warning - ^ can't deref a2, it might be nil - ]# - -# test loop -proc testForLoop(a: Nilable) = - var b = Nilable() - for i in 0 .. 5: - echo b.a #[tt.Warning - ^ can't deref b, it might be nil - ]# - if i == 2: - b = a - echo b.a #[tt.Warning - ^ can't deref b, it might be nil - ]# - - - -# # TODO implement this after discussion -# # proc testResultCompoundNonNilableElement(a: Nilable): (NonNilable, NonNilable) = #[t t.Warning -# # ^ result might be not initialized, so it or an element might be nil -# # ]# -# # if not a.isNil: -# # result[0] = a #[t t.Warning -# # ^ can't assign nilable to non nilable: it might be nil -# # #] - -# # proc testNonNilDeref(a: NonNilable) = -# # echo a.a # ok - - - -# # # not only calls: we can use partitions for dependencies for field aliases -# # # so we can detect on change what does this affect or was this mutated between us and the original field - -# # proc testRootAliasField(a: Nilable) = -# # var aliasA = a -# # if not a.isNil and not a.field.isNil: -# # aliasA.field = nil -# # # a.field = nil -# # # aliasA = nil -# # echo a.field.a # [tt.Warning -# # ^ can't deref a.field, it might be nil -# # ]# - - -proc testAliasChanging(a: Nilable) = - var b = a - var aliasA = b - b = Nilable() - if not b.isNil: - echo aliasA.a #[tt.Warning - ^ can't deref aliasA, it might be nil - ]# - -# # TODO -# # proc testAliasUnion(a: Nilable) = -# # var a2 = a -# # var b = a2 -# # if a.isNil: -# # b = Nilable() -# # a2 = nil -# # else: -# # a2 = Nilable() -# # b = a2 -# # if not b.isNil: -# # echo a2.a #[ tt.Warning -# # ^ can't deref a2, it might be nil -# # ]# - -# # TODO after alias support -# #proc callVar(a: var Nilable) = -# # a.field = nil - - -# # TODO ptr support -# # proc testPtrAlias(a: Nilable) = -# # # pointer to a: hm. -# # # alias to a? -# # var ptrA = a.addr # {0, 1} -# # if not a.isNil: # {0, 1} -# # ptrA[] = nil # {0, 1} 0: MaybeNil 1: MaybeNil -# # echo a.a #[ tt.Warning -# # ^ can't deref a, it might be nil -# # ]# - -# # TODO field stuff -# # currently it just doesnt support dot, so accidentally it shows a warning but because that -# # not alias i think -# # proc testFieldAlias(a: Nilable) = -# # var b = a # {0, 1} {2} -# # if not a.isNil and not a.field.isNil: # {0, 1} {2} -# # callVar(b) # {0, 1} {2} 0: Safe 1: Safe -# # echo a.field.a #[ tt.Warning -# # ^ can't deref a.field, it might be nil -# # ]# -# # -# # proc testUniqueHashTree(a: Nilable): Nilable = -# # # TODO what would be a clash -# # var field = 0 -# # if not a.isNil and not a.field.isNil: -# # # echo a.field.a -# # echo a[field].a -# # result = Nilable() - -# # proc testSeparateShadowingResult(a: Nilable): Nilable = -# # result = Nilable() -# # if not a.isNil: -# # var result: Nilable = nil -# # echo result.a - - -proc testCStringDeref(a: cstring) = - echo a[0] #[tt.Warning - ^ can't deref a, it might be nil - ]# - - -proc testNilablePtr(a: ptr int) = - if not a.isNil: - echo a[] # ok - echo a[] #[tt.Warning - ^ can't deref a, it might be nil - ]# - -# # proc testNonNilPtr(a: ptr int not nil) = -# # echo a[] # ok - -proc raiseCall: NonNilable = #[tt.Warning -^ return value is nil -]# - raise newException(ValueError, "raise for test") - -# proc testTryCatch(a: Nilable) = -# var other = a -# try: -# other = raiseCall() -# except: -# discard -# echo other.a #[ tt.Warning -# ^ can't deref other, it might be nil -# ]# - -# # proc testTryCatchDetectNoRaise(a: Nilable) = -# # var other = Nilable() -# # try: -# # other = nil -# # other = a -# # other = Nilable() -# # except: -# # other = nil -# # echo other.a # ok - -# # proc testTryCatchDetectFinally = -# # var other = Nilable() -# # try: -# # other = nil -# # other = Nilable() -# # except: -# # other = Nilable() -# # finally: -# # other = nil -# # echo other.a # can't deref other: it is nil - -# # proc testTryCatchDetectNilableWithRaise(b: bool) = -# # var other = Nilable() -# # try: -# # if b: -# # other = nil -# # else: -# # other = Nilable() -# # var other2 = raiseCall() -# # except: -# # echo other.a # ok - -# # echo other.a # can't deref a: it might be nil - -# # proc testRaise(a: Nilable) = -# # if a.isNil: -# # raise newException(ValueError, "a == nil") -# # echo a.a # ok - - -# # proc testBlockScope(a: Nilable) = -# # var other = a -# # block: -# # var other = Nilable() -# # echo other.a # ok -# # echo other.a # can't deref other: it might be nil - -# # ok we can't really get the nil value from here, so should be ok -# # proc testDirectRaiseCall: NonNilable = -# # var a = raiseCall() -# # result = NonNilable() - -# # proc testStmtList = -# # var a = Nilable() -# # block: -# # a = nil -# # a = Nilable() -# # echo a.a # ok - -proc callChange(a: Nilable) = - if not a.isNil: - a.field = nil - -proc testCallChangeField = - var a = Nilable() - a.field = Nilable() - callChange(a) - echo a.field.a #[ tt.Warning - ^ can't deref a.field, it might be nil - ]# - -proc testReassignVarWithField = - var a = Nilable() - a.field = Nilable() - echo a.field.a # ok - a = Nilable() - echo a.field.a #[ tt.Warning - ^ can't deref a.field, it might be nil - ]# - - -proc testItemDeref(a: var seq[Nilable]) = - echo a[0].a #[tt.Warning - ^ can't deref a[0], it might be nil - ]# - a[0] = Nilable() # good: now .. if we dont track, how do we know - echo a[0].a # ok - echo a[1].a #[tt.Warning - ^ can't deref a[1], it might be nil - ]# - var b = 1 - if a[b].isNil: - echo a[1].a #[tt.Warning - ^ can't deref a[1], it might be nil - ]# - var c = 0 - echo a[c].a #[tt.Warning - ^ can't deref a[c], it might be nil - ]# - - # known false positive - if not a[b].isNil: - echo a[b].a #[tt.Warning - ^ can't deref a[b], it might be nil - ]# - - const c = 0 - if a[c].isNil: - echo a[0].a #[tt.Warning - ^ can't deref a[0], it is nil - ]# - a[c] = Nilable() - echo a[0].a # ok - - - -# # # proc test10(a: Nilable) = -# # # if not a.isNil and not a.b.isNil: -# # # c_memset(globalA.addr, 0, globalA.sizeOf.csize_t) -# # # globalA = nil -# # # echo a.a # can't deref a: it might be nil - diff --git a/tests/strictnotnil/tnilcheck_no_warnings.nim b/tests/strictnotnil/tnilcheck_no_warnings.nim deleted file mode 100644 index 5ec9bc575..000000000 --- a/tests/strictnotnil/tnilcheck_no_warnings.nim +++ /dev/null @@ -1,182 +0,0 @@ -discard """ -cmd: "nim check --warningAsError:StrictNotNil $file" -action: "compile" -""" - -import tables - -{.experimental: "strictNotNil".} - -type - Nilable* = ref object - a*: int - field*: Nilable - - NonNilable* = Nilable not nil - - Nilable2* = nil NonNilable - - -# proc `[]`(a: Nilable, b: int): Nilable = -# nil - - -# Nilable tests - - - -# # test and -proc testAnd(a: Nilable) = - echo not a.isNil and a.a > 0 # ok - - -# test else branch and inferring not isNil -# proc testElse(a: Nilable, b: int) = -# if a.isNil: -# echo 0 -# else: -# echo a.a - -# test that here we can infer that n can't be nil anymore -proc testNotNilAfterAssign(a: Nilable, b: int) = - var n = a # a: MaybeNil n: MaybeNil - if n.isNil: # n: Safe a: MaybeNil - n = Nilable() # n: Safe a: MaybeNil - echo n.a # ok - -proc callVar(a: var Nilable) = - a = nil - -proc testVarAlias(a: Nilable) = # a: 0 aliasA: 1 {0} {1} - var aliasA = a # {0, 1} 0 MaybeNil 1 MaybeNil - if not a.isNil: # {0, 1} 0 Safe 1 Safe - callVar(aliasA) # {0, 1} 0 MaybeNil 1 MaybeNil - # if aliasA stops being in alias: it might be nil, but then a is still not nil - # if not: it cant be nil as it still points here - echo a.a # ok - -proc testAliasCheck(a: Nilable) = - var aliasA = a - if not a.isNil: - echo aliasA.a # ok - -proc testFieldCheck(a: Nilable) = - if not a.isNil and not a.field.isNil: - echo a.field.a # ok - -proc testTrackField = - var a = Nilable(field: Nilable()) - echo a.field.a # ok - -proc testNonNilDeref(a: NonNilable) = - echo a.a # ok - -# # not only calls: we can use partitions for dependencies for field aliases -# # so we can detect on change what does this affect or was this mutated between us and the original field - - -# proc testUniqueHashTree(a: Nilable): Nilable = -# # TODO what would be a clash -# var field = 0 -# if not a.isNil and not a.field.isNil: -# # echo a.field.a -# echo a[field].a -# result = Nilable() - -proc testSeparateShadowingResult(a: Nilable): Nilable = - result = Nilable() - if not a.isNil: - var result: Nilable = nil - echo result.a - - -proc testNonNilCString(a: cstring not nil) = - echo a[0] # ok - -proc testNonNilPtr(a: ptr int not nil) = - echo a[] # ok - - -# proc testTryCatchDetectNoRaise(a: Nilable) = -# var other = Nilable() -# try: -# other = nil -# other = a -# other = Nilable() -# except: -# other = nil -# echo other.a # ok - -# proc testTryCatchDetectFinally = -# var other = Nilable() -# try: -# other = nil -# other = Nilable() -# except: -# other = Nilable() -# finally: -# other = nil -# echo other.a # can't deref other: it is nil - -# proc testTryCatchDetectNilableWithRaise(b: bool) = -# var other = Nilable() -# try: -# if b: -# other = nil -# else: -# other = Nilable() -# var other2 = raiseCall() -# except: -# echo other.a # ok - -# echo other.a # can't deref a: it might be nil - -proc testRaise(a: Nilable) = - if a.isNil: - raise newException(ValueError, "a == nil") - echo a.a # ok - -# proc testBlockScope(a: Nilable) = -# var other = a -# block: -# var other = Nilable() -# echo other.a # ok -# echo other.a # can't deref other: it might be nil - -# # (ask Araq about this: not supported yet) ok we can't really get the nil value from here, so should be ok -# proc testDirectRaiseCall: NonNilable = -# var a = raiseCall() -# result = NonNilable() - -proc testStmtList = - var a = Nilable() - block: - a = nil - a = Nilable() - echo a.a # ok - -proc testItemDerefNoWarning(a: var seq[Nilable]) = - a[0] = Nilable() # good: now .. if we dont track, how do we know - echo a[0].a # ok - var b = 1 - - const c = 0 - a[c] = Nilable() - echo a[0].a # ok - -# proc callChange(a: Nilable) = -# a.field = nil - -# proc testCallAlias = -# var a = Nilable(field: Nilable()) -# callChange(a) -# echo a.field.a # can't deref a.field, it might be nil - -# # proc test10(a: Nilable) = -# # if not a.isNil and not a.b.isNil: -# # c_memset(globalA.addr, 0, globalA.sizeOf.csize_t) -# # globalA = nil -# # echo a.a # can't deref a: it might be nil - -var nilable: Nilable -var withField = Nilable(a: 0, field: Nilable()) diff --git a/tests/stylecheck/fileinfo.nim b/tests/stylecheck/fileinfo.nim deleted file mode 100644 index d6faf0c73..000000000 --- a/tests/stylecheck/fileinfo.nim +++ /dev/null @@ -1,2 +0,0 @@ -# fileinfo.nim -type FileInfo* = object \ No newline at end of file diff --git a/tests/stylecheck/t20397.nim b/tests/stylecheck/t20397.nim deleted file mode 100644 index 486a97d73..000000000 --- a/tests/stylecheck/t20397.nim +++ /dev/null @@ -1,4 +0,0 @@ -{.hintAsError[Name]:on.} -var a_b = 1 -discard a_b -{.hintAsError[Name]:off.} \ No newline at end of file diff --git a/tests/stylecheck/t20397_1.nim b/tests/stylecheck/t20397_1.nim deleted file mode 100644 index 76c03dca1..000000000 --- a/tests/stylecheck/t20397_1.nim +++ /dev/null @@ -1,8 +0,0 @@ -discard """ - matrix: "--styleCheck:off --hint:Name:on" -""" - -{.hintAsError[Name]:on.} -var a_b = 1 -discard a_b -{.hintAsError[Name]:off.} diff --git a/tests/stylecheck/t20397_2.nim b/tests/stylecheck/t20397_2.nim deleted file mode 100644 index 3b8e1c4d6..000000000 --- a/tests/stylecheck/t20397_2.nim +++ /dev/null @@ -1,7 +0,0 @@ -discard """ - errormsg: "'a_b' should be: 'aB'" - matrix: "--styleCheck:error" -""" - -var a_b = 1 -discard a_b \ No newline at end of file diff --git a/tests/stylecheck/taccept.nim b/tests/stylecheck/taccept.nim deleted file mode 100644 index 43a9ab71f..000000000 --- a/tests/stylecheck/taccept.nim +++ /dev/null @@ -1,22 +0,0 @@ -discard """ - matrix: "--styleCheck:error --styleCheck:usages" -""" - -import std/[asyncdispatch, nre] - -type - Name = object - id: int - -template hello = - var iD = "string" - var name: Name - doAssert name.id == 0 - doAssert iD == "string" - -hello() - -# bug #12955 -import os -import fileinfo -var xs: seq[fileinfo.FileInfo] diff --git a/tests/stylecheck/treject.nim b/tests/stylecheck/treject.nim deleted file mode 100644 index 458a2d039..000000000 --- a/tests/stylecheck/treject.nim +++ /dev/null @@ -1,17 +0,0 @@ -discard """ - action: reject - nimout: '''treject.nim(14, 13) Error: 'iD' should be: 'id' [field declared in treject.nim(9, 5)]''' - matrix: "--styleCheck:error --styleCheck:usages --hint:Name:on" -""" - -type - Name = object - id: int - -template hello = - var iD = "string" - var name: Name - echo name.iD - echo iD - -hello() diff --git a/tests/stylecheck/tusages.nim b/tests/stylecheck/tusages.nim deleted file mode 100644 index b689dabb3..000000000 --- a/tests/stylecheck/tusages.nim +++ /dev/null @@ -1,22 +0,0 @@ -discard """ - action: reject - nimout: '''tusages.nim(20, 5) Error: 'BAD_STYLE' should be: 'BADSTYLE' [proc declared in tusages.nim(9, 6)]''' - matrix: "--styleCheck:error --styleCheck:usages --hint:all:off --hint:Name:on" -""" - -import strutils - -proc BADSTYLE(c: char) = discard - -proc toSnakeCase(s: string): string = - result = newStringOfCap(s.len + 3) - for i in 0.. 0 and s[i-1] in {'a'..'z'}: - result.add '_' - result.add toLowerAscii(s[i]) - else: - result.add s[i] - BAD_STYLE(s[i]) - -echo toSnakeCase("fooBarBaz Yes") diff --git a/tests/system/talloc.nim b/tests/system/talloc.nim index a81fef481..9b970fda0 100644 --- a/tests/system/talloc.nim +++ b/tests/system/talloc.nim @@ -1,4 +1,8 @@ -# was: appveyor is "out of memory" +discard """ +disabled: "appveyor" +""" + +# appveyor is "out of memory" var x: ptr int diff --git a/tests/system/talloc2.nim b/tests/system/talloc2.nim index 9d1687f34..a321fe741 100644 --- a/tests/system/talloc2.nim +++ b/tests/system/talloc2.nim @@ -1,11 +1,10 @@ discard """ disabled: "windows" -disabled: "openbsd" joinable: false disabled: 32bit """ # no point to test this on system with smaller address space -# was: appveyor is "out of memory" +# appveyor is "out of memory" const nmax = 2*1024*1024*1024 diff --git a/tests/system/tatomics1.nim b/tests/system/tatomics1.nim deleted file mode 100644 index 217fd07fa..000000000 --- a/tests/system/tatomics1.nim +++ /dev/null @@ -1,9 +0,0 @@ -discard """ - targets: "c cpp js" -""" - -var x = 10 -atomicInc(x) -doAssert x == 11 -atomicDec(x) -doAssert x == 10 diff --git a/tests/system/tdeepcopy.nim b/tests/system/tdeepcopy.nim index 92ba48115..383d2e8d1 100644 --- a/tests/system/tdeepcopy.nim +++ b/tests/system/tdeepcopy.nim @@ -1,5 +1,4 @@ discard """ - matrix: "--mm:refc; --mm:orc --deepcopy:on" output: "ok" """ diff --git a/tests/system/tdollars.nim b/tests/system/tdollars.nim deleted file mode 100644 index 93fa5cb9e..000000000 --- a/tests/system/tdollars.nim +++ /dev/null @@ -1,198 +0,0 @@ -discard """ - targets: "c cpp js" -""" - -#[ -if https://github.com/nim-lang/Nim/pull/14043 is merged (or at least its -tests/system/tostring.nim diff subset), merge -tests/system/tostring.nim into this file, named after dollars.nim - -The goal is to increase test coverage across backends while minimizing test code -duplication (which always results in weaker test coverage in practice). -]# - -import std/unittest -template test[T](a: T, expected: string) = - check $a == expected - var b = a - check $b == expected - static: - doAssert $a == expected - -template testType(T: typedesc) = - when T is bool: - test true, "true" - test false, "false" - elif T is char: - test char, "\0" - test char.high, static($T.high) - else: - test T.default, "0" - test 1.T, "1" - test T.low, static($T.low) - test T.high, static($T.high) - -block: # `$`(SomeInteger) - # direct tests - check $0'u8 == "0" - check $255'u8 == "255" - check $(-127'i8) == "-127" - - # known limitation: Error: number out of range: '128'i8', - # see https://github.com/timotheecour/Nim/issues/125 - # check $(-128'i8) == "-128" - - check $int8.low == "-128" - check $int8(-128) == "-128" - when not defined js: # pending https://github.com/nim-lang/Nim/issues/14127 - check $cast[int8](-128) == "-128" - - var a = 12345'u16 - check $a == "12345" - check $12345678'u64 == "12345678" - check $12345678'i64 == "12345678" - check $(-12345678'i64) == "-12345678" - - # systematic tests - testType uint8 - testType uint16 - testType uint32 - testType uint - - testType int8 - testType int16 - testType int32 - - testType int - testType bool - - when not defined(js): # requires BigInt support - testType uint64 - testType int64 - testType BiggestInt - -block: # #14350, #16674, #16686 for JS - var cstr: cstring - doAssert cstr == cstring(nil) - doAssert cstr == nil - doAssert cstr.isNil - doAssert cstr != cstring("") - doAssert cstr.len == 0 - - when defined(js): - cstr.add(cstring("abc")) - doAssert cstr == cstring("abc") - - var nil1, nil2: cstring = nil - - nil1.add(nil2) - doAssert nil1 == cstring(nil) - doAssert nil2 == cstring(nil) - - nil1.add(cstring("")) - doAssert nil1 == cstring("") - doAssert nil2 == cstring(nil) - - nil1.add(nil2) - doAssert nil1 == cstring("") - doAssert nil2 == cstring(nil) - - nil2.add(nil1) - doAssert nil1 == cstring("") - doAssert nil2 == cstring("") - -block: - when defined(js): # bug #18591 - let a1 = -1'i8 - let a2 = uint8(a1) - # if `uint8(a1)` changes meaning to `cast[uint8](a1)` in future, update this test; - # until then, this is the correct semantics. - let a3 = $a2 - doAssert a2 < 3 - doAssert a3 == "-1" - proc intToStr(a: uint8): cstring {.importjs: "(# + \"\")".} - doAssert $intToStr(a2) == "-1" - else: - block: - let x = -1'i8 - let y = uint32(x) - doAssert $y == "4294967295" - block: - let x = -1'i16 - let y = uint32(x) - doAssert $y == "4294967295" - block: - let x = -1'i32 - let y = uint32(x) - doAssert $y == "4294967295" - block: - proc foo1(arg: int): string = - let x = uint32(arg) - $x - doAssert $foo1(-1) == "4294967295" - - block: - let x = 4294967295'u32 - doAssert $x == "4294967295" - block: - doAssert $(4294967295'u32) == "4294967295" - -proc main()= - block: - let a = -0.0 - doAssert $a == "-0.0" - doAssert $(-0.0) == "-0.0" - - block: - let a = 0.0 - doAssert $a == "0.0" - doAssert $(0.0) == "0.0" - - block: - let b = -0 - doAssert $b == "0" - doAssert $(-0) == "0" - - block: - let b = 0 - doAssert $b == "0" - doAssert $(0) == "0" - - doAssert $uint32.high == "4294967295" - - block: # addInt - var res = newStringOfCap(24) - template test2(a, b) = - res.setLen(0) - res.addInt a - doAssert res == b - - for i in 0 .. 9: - res.addInt int64(i) - doAssert res == "0123456789" - - res.setLen(0) - for i in -9 .. 0: - res.addInt int64(i) - doAssert res == "-9-8-7-6-5-4-3-2-10" - - when not defined(js): - test2 high(int64), "9223372036854775807" - test2 low(int64), "-9223372036854775808" - - test2 high(int32), "2147483647" - test2 low(int32), "-2147483648" - test2 high(int16), "32767" - test2 low(int16), "-32768" - test2 high(int8), "127" - test2 low(int8), "-128" - - block: - const - a: array[3, char] = ['N', 'i', 'm'] - aStr = $(a) - - doAssert aStr == """['N', 'i', 'm']""" - -static: main() -main() diff --git a/tests/system/tenum_array_repr.nim b/tests/system/tenum_array_repr.nim index 39b1a5f9a..3634692e3 100644 --- a/tests/system/tenum_array_repr.nim +++ b/tests/system/tenum_array_repr.nim @@ -2,8 +2,10 @@ discard """ output: ''' 1 [a, b] + 2 [c, d] + 4 [e, f]''' """ diff --git a/tests/system/tgcnone.nim b/tests/system/tgcnone.nim deleted file mode 100644 index 47c6c6014..000000000 --- a/tests/system/tgcnone.nim +++ /dev/null @@ -1,6 +0,0 @@ -discard """ - matrix: "--gc:none -d:useMalloc --threads:off" -""" -# bug #15617 -let x = 4 -doAssert x == 4 diff --git a/tests/system/tio.nim b/tests/system/tio.nim index 52a21837a..c4d041560 100644 --- a/tests/system/tio.nim +++ b/tests/system/tio.nim @@ -22,12 +22,12 @@ proc echoLoop(str: string): string = while not output.atEnd: result.add(output.readLine) -block: # io - block: # readAll - block: # stdin +suite "io": + suite "readAll": + test "stdin": check: echoLoop(STRING_DATA) == STRING_DATA - block: # file + test "file": check: readFile(TEST_FILE).strip == STRING_DATA diff --git a/tests/system/tvarargslen.nim b/tests/system/tlenvarargs.nim similarity index 84% rename from tests/system/tvarargslen.nim rename to tests/system/tlenvarargs.nim index 24b54a1e0..ca12c8171 100644 --- a/tests/system/tvarargslen.nim +++ b/tests/system/tlenvarargs.nim @@ -1,9 +1,9 @@ discard """ output: ''' -tvarargslen.nim:35:2 (1, 2) -tvarargslen.nim:36:2 12 -tvarargslen.nim:37:2 1 -tvarargslen.nim:38:8 +tlenvarargs.nim:35:9 (1, 2) +tlenvarargs.nim:36:9 12 +tlenvarargs.nim:37:9 1 +tlenvarargs.nim:38:8 done ''' """ @@ -14,19 +14,19 @@ template myecho*(a: varargs[untyped]) = ## on macros.nim) so can be used in more contexts const info = instantiationInfo(-1, false) const loc = info.filename & ":" & $info.line & ":" & $info.column & " " - when varargsLen(a) > 0: + when lenVarargs(a) > 0: echo(loc, a) else: echo(loc) template fun*(a: varargs[untyped]): untyped = - varargsLen(a) + lenVarargs(a) template fun2*(a: varargs[typed]): untyped = - a.varargsLen + a.lenVarargs template fun3*(a: varargs[int]): untyped = - a.varargsLen + a.lenVarargs template fun4*(a: varargs[untyped]): untyped = len(a) @@ -49,12 +49,11 @@ proc main()= doAssert fun3(10) == 1 doAssert fun3(10, 11) == 2 - ## shows why `varargsLen` can't be named `len` + ## shows why `lenVarargs` can't be named `len` doAssert fun4("abcdef") == len("abcdef") ## workaround for BUG:D20191218T171447 whereby if testament expected output ends ## in space, testament strips it from expected output but not actual output, ## which leads to a mismatch when running test via megatest echo "done" - main() diff --git a/tests/system/tnilconcats.nim b/tests/system/tnilconcats.nim index 69fc3913c..c1126405c 100644 --- a/tests/system/tnilconcats.nim +++ b/tests/system/tnilconcats.nim @@ -26,8 +26,7 @@ when true: # casting an empty string as sequence with shallow() should not segfault var s2: string - when defined(gcRefc): - shallow(s2) + shallow(s2) s2 &= "foo" doAssert s2 == "foo" diff --git a/tests/system/tnim_stacktrace_override.nim b/tests/system/tnim_stacktrace_override.nim deleted file mode 100644 index c75da9d9b..000000000 --- a/tests/system/tnim_stacktrace_override.nim +++ /dev/null @@ -1,18 +0,0 @@ -discard """ - cmd: "nim c -d:nimStacktraceOverride $file" - output: '''begin -Traceback (most recent call last, using override) -Error: unhandled exception: stack trace produced [ValueError] -''' - exitcode: 1 -""" - -import asyncfutures - -proc main = - echo "begin" - if true: - raise newException(ValueError, "stack trace produced") - echo "unreachable" - -main() diff --git a/tests/system/tostring.nim b/tests/system/tostring.nim index bb6e453fb..ea4a44417 100644 --- a/tests/system/tostring.nim +++ b/tests/system/tostring.nim @@ -1,3 +1,7 @@ +discard """ + output: "DONE: tostring.nim" +""" + doAssert "@[23, 45]" == $(@[23, 45]) doAssert "[32, 45]" == $([32, 45]) doAssert """@["", "foo", "bar"]""" == $(@["", "foo", "bar"]) @@ -47,7 +51,7 @@ import strutils let arr = ['H','e','l','l','o',' ','W','o','r','l','d','!','\0'] doAssert $arr == "['H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd', '!', '\\x00']" -doAssert $cast[cstring](addr arr) == "Hello World!" +doAssert $cstring(unsafeAddr arr) == "Hello World!" proc takes(c: cstring) = doAssert c == cstring"" @@ -68,7 +72,7 @@ doAssert yy == "" proc bar(arg: cstring) = doAssert arg[0] == '\0' -proc baz(arg: openArray[char]) = +proc baz(arg: openarray[char]) = doAssert arg.len == 0 proc stringCompare() = @@ -79,9 +83,9 @@ proc stringCompare() = doAssert b == "bee" b.add g doAssert b == "bee" - c.addFloat 123.456 + c.add 123.456 doAssert c == "123.456" - d.addInt 123456 + d.add 123456 doAssert d == "123456" doAssert e == "" @@ -104,7 +108,7 @@ bar(nilstring) static: stringCompare() -# issue #8847 +# bug 8847 var a2: cstring = "fo\"o2" block: @@ -112,14 +116,5 @@ block: s.addQuoted a2 doAssert s == "\"fo\\\"o2\"" -# issue #16650 -template fn() = - doAssert len(cstring"ab\0c") == 5 - doAssert len(cstring("ab\0c")) == 2 - when nimvm: - discard - else: - let c = cstring("ab\0c") - doAssert len(c) == 2 -fn() -static: fn() + +echo "DONE: tostring.nim" diff --git a/tests/system/trealloc.nim b/tests/system/trealloc.nim index 1d3e00aff..7180b8eda 100644 --- a/tests/system/trealloc.nim +++ b/tests/system/trealloc.nim @@ -1,7 +1,6 @@ discard """ output: '''success''' joinable: false - disabled: "openbsd" """ # bug #4818 @@ -12,12 +11,12 @@ const BUFFER_SIZE = 5000 var buffer = cast[ptr uint16](alloc(BUFFER_SIZE)) var total_size: int64 = 0 -for i in 0 .. 1000: - let size = BUFFER_SIZE * i - #echo "requesting ", size - total_size += size.int64 - buffer = cast[ptr uint16](realloc(buffer, size)) - #echo totalSize, " total: ", getTotalMem(), " occupied: ", getOccupiedMem(), " free: ", getFreeMem() +for i in 0 .. 4000: + let size = BUFFER_SIZE * i + #echo "requesting ", size + total_size += size.int64 + buffer = cast[ptr uint16](realloc(buffer, size)) + #echo totalSize, " total: ", getTotalMem(), " occupied: ", getOccupiedMem(), " free: ", getFreeMem() dealloc(buffer) echo "success" diff --git a/tests/system/trefs.nim b/tests/system/trefs.nim deleted file mode 100644 index 8c36aec52..000000000 --- a/tests/system/trefs.nim +++ /dev/null @@ -1,15 +0,0 @@ -discard """ - targets: "c js" -""" - -# bug #21317 -proc parseHook*(v: var ref int) = - var a: ref int - new(a) - a[] = 123 - v = a - -proc fromJson2*(): ref int = - parseHook(result) - -doAssert fromJson2()[] == 123 diff --git a/tests/system/tsigexitcode.nim b/tests/system/tsigexitcode.nim deleted file mode 100644 index 249256b40..000000000 --- a/tests/system/tsigexitcode.nim +++ /dev/null @@ -1,23 +0,0 @@ -discard """ - joinable: false - disabled: windows -""" - -import os, osproc, posix, strutils - -proc main() = - if paramCount() > 0: - let signal = cint parseInt paramStr(1) - discard posix.raise(signal) - else: - # synchronize this list with lib/system/except.nim:registerSignalHandler() - let sigs = [SIGINT, SIGSEGV, SIGABRT, SIGFPE, SIGILL, SIGBUS, SIGPIPE] - for s in sigs: - let (_, exitCode) = execCmdEx(quoteShellCommand [getAppFilename(), $s]) - if s == SIGPIPE: - # SIGPIPE should be ignored - doAssert exitCode == 0, $(exitCode, s) - else: - doAssert exitCode == 128+s, $(exitCode, s) - -main() diff --git a/tests/system/tslimsystem.nim b/tests/system/tslimsystem.nim deleted file mode 100644 index 690f4ee9b..000000000 --- a/tests/system/tslimsystem.nim +++ /dev/null @@ -1,6 +0,0 @@ -discard """ - output: "123" - matrix: "-d:nimPreviewSlimSystem" -""" - -echo 123 \ No newline at end of file diff --git a/tests/system/tstatic.nim b/tests/system/tstatic.nim deleted file mode 100644 index 6e2893e2b..000000000 --- a/tests/system/tstatic.nim +++ /dev/null @@ -1,58 +0,0 @@ -discard """ - targets: "c cpp js" -""" - -import std/strutils - -# bug #6133 -template main() = - block: - block: - proc foo(q: string, a: int): int = - result = q.len - - proc foo(q: static[string]): int = - result = foo(q, 5) - - doAssert foo("123") == 3 - - block: - type E = enum A - - if false: - var e = A - discard $e - - proc foo(a: string): int = - len(a) # 16640 - - proc foo(a: static[bool]): int {.used.} = - discard - - doAssert foo("") == 0 - - block: - proc foo(a: string): int = - len(a) - - proc foo(a: static[bool]): int {.used.} = - discard - - doAssert foo("abc") == 3 - - block: - proc parseInt(f: static[bool]): int {.used.} = discard - - doAssert "123".parseInt == 123 - block: - type - MyType = object - field: float32 - AType[T: static MyType] = distinct range[0f32 .. T.field] - var a: AType[MyType(field: 5f32)] - proc n(S: static Slice[int]): range[S.a..S.b] = discard - assert typeof(n 1..2) is range[1..2] - - -static: main() -main() diff --git a/tests/system/tstatic_callable.nim b/tests/system/tstatic_callable.nim deleted file mode 100644 index 92d1fca8d..000000000 --- a/tests/system/tstatic_callable.nim +++ /dev/null @@ -1,12 +0,0 @@ -# bug #16987 - -proc getNum(a: int): int = a - -# Below calls "doAssert getNum(123) == 123" at compile time. -static: - doAssert getNum(123) == 123 - -# Below calls evaluate the "getNum(123)" at compile time, but the -# results of those calls get used at run time. -doAssert (static getNum(123)) == 123 -doAssert (static(getNum(123))) == 123 diff --git a/tests/system/tstatic_callable_error.nim b/tests/system/tstatic_callable_error.nim deleted file mode 100644 index c6f1e3d07..000000000 --- a/tests/system/tstatic_callable_error.nim +++ /dev/null @@ -1,14 +0,0 @@ -# bug #16987 - -discard """ -errormsg: "cannot evaluate at compile time: inp" -nimout: ''' -tstatic_callable_error.nim(14, 21) Error: cannot evaluate at compile time: inp''' -""" - - -# line 10 -proc getNum(a: int): int = a - -let inp = 123 -echo (static getNum(inp)) diff --git a/tests/system/tsystem_misc.nim b/tests/system/tsystem_misc.nim index 7f5914725..56af97f36 100644 --- a/tests/system/tsystem_misc.nim +++ b/tests/system/tsystem_misc.nim @@ -59,6 +59,11 @@ doAssert high(float) > low(float) doAssert high(float32) > low(float32) doAssert high(float64) > low(float64) +# bug #6710 +var s = @[1] +s.delete(0) + + proc foo(a: openArray[int]) = for x in a: echo x @@ -76,13 +81,13 @@ foo(toOpenArray(seqq, 1, 3)) # empty openArray issue #7904 foo(toOpenArray(seqq, 0, -1)) foo(toOpenArray(seqq, 1, 0)) -doAssertRaises(IndexDefect): +doAssertRaises(IndexError): foo(toOpenArray(seqq, 0, -2)) foo(toOpenArray(arr, 9, 8)) foo(toOpenArray(arr, 0, -1)) foo(toOpenArray(arr, 1, 0)) -doAssertRaises(IndexDefect): +doAssertRaises(IndexError): foo(toOpenArray(arr, 10, 8)) # test openArray of openArray @@ -101,11 +106,11 @@ var arrNeg: array[-3 .. -1, int] = [1, 2, 3] foo(toOpenArray(arrNeg, -3, -1)) foo(toOpenArray(arrNeg, 0, -1)) foo(toOpenArray(arrNeg, -3, -4)) -doAssertRaises(IndexDefect): +doAssertRaises(IndexError): foo(toOpenArray(arrNeg, -4, -1)) -doAssertRaises(IndexDefect): +doAssertRaises(IndexError): foo(toOpenArray(arrNeg, -1, 0)) -doAssertRaises(IndexDefect): +doAssertRaises(IndexError): foo(toOpenArray(arrNeg, -1, -3)) doAssertRaises(Exception): raise newException(Exception, "foo") @@ -113,9 +118,9 @@ doAssertRaises(Exception): block: var didThrow = false try: - doAssertRaises(IndexDefect): # should fail since it's wrong exception - raise newException(FieldDefect, "foo") - except AssertionDefect: + doAssertRaises(IndexError): # should fail since it's wrong exception + raise newException(FieldError, "foo") + except AssertionError: # ok, throwing was correct behavior didThrow = true doAssert didThrow @@ -131,12 +136,12 @@ let str = "0123456789" foo(toOpenArrayByte(str, 0, str.high)) -template boundedOpenArray[T](x: seq[T], first, last: int): openArray[T] = +template boundedOpenArray[T](x: seq[T], first, last: int): openarray[T] = toOpenarray(x, max(0, first), min(x.high, last)) # bug #9281 -proc foo[T](x: openArray[T]) = +proc foo[T](x: openarray[T]) = echo x.len let a = @[1, 2, 3] @@ -188,27 +193,3 @@ block: a = {k1} b = {k1,k2} doAssert a < b - - -block: # Ordinal - doAssert int is Ordinal - doAssert uint is Ordinal - doAssert int64 is Ordinal - doAssert uint64 is Ordinal - doAssert char is Ordinal - type Foo = enum k1, k2 - doAssert Foo is Ordinal - doAssert Foo is SomeOrdinal - doAssert enum is SomeOrdinal - - # these fail: - # doAssert enum is Ordinal # fails - # doAssert Ordinal is SomeOrdinal - # doAssert SomeOrdinal is Ordinal - -block: - proc p() = discard - - doAssert not compiles(echo p.rawProc.repr) - doAssert not compiles(echo p.rawEnv.repr) - doAssert not compiles(echo p.finished) diff --git a/tests/system/tuse_version.nim b/tests/system/tuse_version.nim deleted file mode 100644 index 745319f50..000000000 --- a/tests/system/tuse_version.nim +++ /dev/null @@ -1,49 +0,0 @@ -discard """ - matrix: "--useVersion:1.0" -""" - -{.warning[UnusedImport]: off.} - -import std/[ - # Core: - bitops, typetraits, lenientops, macros, volatile, - - # Algorithms: - algorithm, sequtils, - - # Collections: - critbits, deques, heapqueue, intsets, lists, options, sets, - sharedlist, tables, - - # Strings: - editdistance, wordwrap, parseutils, ropes, - pegs, strformat, strmisc, strscans, strtabs, - strutils, unicode, unidecode, - - # Generic operator system services: - os, streams, - - # Math libraries: - complex, math, mersenne, random, rationals, stats, sums, - - # Internet protocols: - httpcore, mimetypes, uri, - - # Parsers: - htmlparser, json, lexbase, parsecfg, parsecsv, parsesql, parsexml, - - # XML processing: - xmltree, xmlparser, - - # Generators: - htmlgen, - - # Hashing: - base64, hashes, - - # Miscellaneous: - colors, sugar, varints, -] - - -doAssert NimVersion == "1.0.100" diff --git a/tests/system/tuse_version16.nim b/tests/system/tuse_version16.nim deleted file mode 100644 index 88f9728ec..000000000 --- a/tests/system/tuse_version16.nim +++ /dev/null @@ -1,49 +0,0 @@ -discard """ - matrix: "--useVersion:1.6" -""" - -{.warning[UnusedImport]: off.} - -import std/[ - # Core: - bitops, typetraits, lenientops, macros, volatile, - - # Algorithms: - algorithm, sequtils, - - # Collections: - critbits, deques, heapqueue, intsets, lists, options, sets, - sharedlist, tables, - - # Strings: - editdistance, wordwrap, parseutils, ropes, - pegs, strformat, strmisc, strscans, strtabs, - strutils, unicode, unidecode, - - # Generic operator system services: - os, streams, - - # Math libraries: - complex, math, mersenne, random, rationals, stats, sums, - - # Internet protocols: - httpcore, mimetypes, uri, - - # Parsers: - htmlparser, json, lexbase, parsecfg, parsecsv, parsesql, parsexml, - - # XML processing: - xmltree, xmlparser, - - # Generators: - htmlgen, - - # Hashing: - base64, hashes, - - # Miscellaneous: - colors, sugar, varints, -] - - -doAssert NimVersion == "1.6.100" diff --git a/tests/template/m1027a.nim b/tests/template/m1027a.nim deleted file mode 100644 index fad915a2f..000000000 --- a/tests/template/m1027a.nim +++ /dev/null @@ -1 +0,0 @@ -const version_str* = "mod a" diff --git a/tests/template/m1027b.nim b/tests/template/m1027b.nim deleted file mode 100644 index 5ff0b9714..000000000 --- a/tests/template/m1027b.nim +++ /dev/null @@ -1 +0,0 @@ -const version_str* = "mod b" diff --git a/tests/template/otests.nim b/tests/template/otests.nim index 9cb9d7fcb..120146343 100644 --- a/tests/template/otests.nim +++ b/tests/template/otests.nim @@ -163,7 +163,7 @@ when true: #embeddingTest """ # Expression template - proc test_expression(nums: openArray[int] = []): string = + proc test_expression(nums: openarray[int] = []): string = var i = 2 tmpli html""" $(no_substitution()) @@ -171,7 +171,7 @@ when true: #embeddingTest
    Age: $($nums[i] & "!!")
    """ - proc test_statements(nums: openArray[int] = []): string = + proc test_statements(nums: openarray[int] = []): string = tmpli html""" $(test_expression(nums)) $if true { diff --git a/tests/template/sunset.nimf b/tests/template/sunset.nimf index bd57bb8e1..465b12a5e 100644 --- a/tests/template/sunset.nimf +++ b/tests/template/sunset.nimf @@ -1,6 +1,6 @@ #? stdtmpl #proc sunsetTemplate*(current, ticker, content: string, -# tabs: openArray[array[0..1, string]]): string = +# tabs: openarray[array[0..1, string]]): string = # result = "" diff --git a/tests/template/t1027.nim b/tests/template/t1027.nim deleted file mode 100644 index fe03c4ea9..000000000 --- a/tests/template/t1027.nim +++ /dev/null @@ -1,22 +0,0 @@ -discard """ - cmd: "nim check --hints:off $file" - errormsg: "" - nimout: ''' -t1027.nim(20, 19) Error: ambiguous identifier: 'version_str' -- use one of the following: - m1027a.version_str: string - m1027b.version_str: string -''' -""" - - - - - - -import m1027a, m1027b - -# bug #1027 -template wrap_me(stuff): untyped = - echo "Using " & version_str - -wrap_me("hey") diff --git a/tests/template/t11705.nim b/tests/template/t11705.nim deleted file mode 100644 index 65ddc7e6c..000000000 --- a/tests/template/t11705.nim +++ /dev/null @@ -1,17 +0,0 @@ -type RefObj = ref object - -proc `[]`(val: static[int]) = # works with different name/overload or without static arg - discard - -template noRef*(T: typedesc): typedesc = # works without template indirection - typeof(default(T)[]) - -proc `=destroy`(x: var noRef(RefObj)) = - discard - -proc foo = - var x = new RefObj - doAssert $(x[]) == "()" - -# bug #11705 -foo() diff --git a/tests/template/t13515.nim b/tests/template/t13515.nim deleted file mode 100644 index ffebedcbe..000000000 --- a/tests/template/t13515.nim +++ /dev/null @@ -1,16 +0,0 @@ -discard """ - action: compile -""" - -template test: bool = true - -# compiles: -if not test: - echo "wtf" - -# does not compile: -template x = - if not test: - echo "wtf" - -x diff --git a/tests/template/t17433.nim b/tests/template/t17433.nim deleted file mode 100644 index 053d33ff0..000000000 --- a/tests/template/t17433.nim +++ /dev/null @@ -1,16 +0,0 @@ -# Inside template bodies, ensure return types referencing a param are replaced. -# This helps guarantee that return parameter analysis happens after argument -# analysis. - -# bug #17433 - -from std/macros import expandMacros - -proc bar(a: typedesc): a = default(a) -doAssert bar(float) == 0.0 -doAssert bar(string) == "" - -template main = - proc baz(a: typedesc): a = default(a) - doAssert baz(float) == 0.0 -main() diff --git a/tests/template/t18113.nim b/tests/template/t18113.nim deleted file mode 100644 index a84b3fd0e..000000000 --- a/tests/template/t18113.nim +++ /dev/null @@ -1,14 +0,0 @@ -# ensure template pragma handling doesn't eagerly attempt to add an implicit -# 'pushed' pragma to the evaluation of any intermediate AST prior to -# substitution. - -# bug #18113 - -import sequtils - -{.push raises: [Defect].} - -var a = toSeq([1, 2, 3, 5, 10]).filterIt(it > 5) - -doAssert a.len == 1 -doAssert a[0] == 10 diff --git a/tests/template/t19149.nim b/tests/template/t19149.nim deleted file mode 100644 index 631e8fc30..000000000 --- a/tests/template/t19149.nim +++ /dev/null @@ -1,19 +0,0 @@ -type Foo = tuple[active: bool, index: int] - - -var f: Foo - -# template result type during match stage -# f:var Foo -# a:Foo -# tyVar -# tyTuple -# after change to proc -# f:Foo -# a:Foo -# tyTuple -# tyTuple - -template cursor(): var Foo = f -discard cursor() - diff --git a/tests/template/t19700.nim b/tests/template/t19700.nim deleted file mode 100644 index cc2944944..000000000 --- a/tests/template/t19700.nim +++ /dev/null @@ -1,10 +0,0 @@ -discard """ - errormsg: "type mismatch: got " -""" - -type Obj = object - -proc apply[T, R](a, b: T; f: proc(x, y: T): R): R = f(a, b) - -let a, b = Obj() -discard apply(a, b, `!=`) diff --git a/tests/template/t6217.nim b/tests/template/t6217.nim deleted file mode 100644 index b27b61881..000000000 --- a/tests/template/t6217.nim +++ /dev/null @@ -1,19 +0,0 @@ -discard """ - output: ''' -start -side effect! -end -''' -""" - -# bug #6217 - -template optMul{`*`(a, 2)}(a: int{noSideEffect}): int = a+a - -proc f(): int = - echo "side effect!" - result = 55 - -echo "start" -doAssert f() * 2 == 110 -echo "end" diff --git a/tests/template/t9534.nim b/tests/template/t9534.nim deleted file mode 100644 index 8d66f42a0..000000000 --- a/tests/template/t9534.nim +++ /dev/null @@ -1,21 +0,0 @@ -discard """ - targets: "c cpp" -""" - -# bug #9534 -type - Object = object - data: int - -template test() = - proc methodName(o: Object): int = - var p: pointer - doAssert o.data == 521 - let f {.used.} = cast[proc (o: int): int {.nimcall.}](p) - doAssert o.data == 521 - result = 1314 - - var a = Object(data: 521) - doAssert methodName(a) == 1314 - -test() diff --git a/tests/template/tcallsitelineinfo.nim b/tests/template/tcallsitelineinfo.nim deleted file mode 100644 index 5fed93363..000000000 --- a/tests/template/tcallsitelineinfo.nim +++ /dev/null @@ -1,17 +0,0 @@ -discard """ - nimout: ''' -tcallsitelineinfo.nim(17, 4) Warning: abc [User] -''' - exitcode: 1 - outputsub: ''' -tcallsitelineinfo.nim(17) tcallsitelineinfo -Error: unhandled exception: def [ValueError] -''' -""" - -template foo(): untyped {.callsite.} = - {.warning: "abc".} - raise newException(ValueError, "def") - echo "hello" - -foo() diff --git a/tests/template/tcallsitelineinfo2.nim b/tests/template/tcallsitelineinfo2.nim deleted file mode 100644 index d5f257474..000000000 --- a/tests/template/tcallsitelineinfo2.nim +++ /dev/null @@ -1,20 +0,0 @@ -discard """ - nimout: ''' -tcallsitelineinfo2.nim(18, 1) Warning: abc [User] -tcallsitelineinfo2.nim(19, 12) Warning: def [User] -''' - exitcode: 1 - outputsub: ''' -tcallsitelineinfo2.nim(20) tcallsitelineinfo2 -Error: unhandled exception: ghi [ValueError] -''' -""" - -template foo(a: untyped): untyped {.callsite.} = - {.warning: "abc".} - a - echo "hello" - -foo: # with `{.line.}:`, the following do not keep their line information: - {.warning: "def".} - raise newException(ValueError, "ghi") diff --git a/tests/template/template_issues.nim b/tests/template/template_issues.nim index 1fed694ef..e56d44480 100644 --- a/tests/template/template_issues.nim +++ b/tests/template/template_issues.nim @@ -8,11 +8,6 @@ hi Hello, World! (e: 42) hey -foo -foo -foo -false -true ''' """ @@ -173,7 +168,7 @@ block t2585: st echo "a ", $fb - proc render(rdat: var RenderData; passes: var openArray[RenderPass]; proj: Mat2; + proc render(rdat: var RenderData; passes: var openarray[RenderPass]; proj: Mat2; indexType = 1) = for i in 0 ..< len(passes): echo "blah ", repr(passes[i]) @@ -250,49 +245,3 @@ proc foo(): auto = echo "hey" discard foo() - - -# bug #4722 -type - IteratorF*[In] = iterator() : In {.closure.} - -template foof(In: untyped) : untyped = - proc ggg*(arg: IteratorF[In]) = - for i in arg(): - echo "foo" - - -iterator hello() : int {.closure.} = - for i in 1 .. 3: - yield i - -foof(int) -ggg(hello) - - -# bug #2586 -var z = 10'u8 -echo z < 9 # Works -echo z > 9 # Error: type mismatch - - -# bug #5993 -template foo(p: proc) = - var bla = 5 - p(bla) - -foo() do(t: var int): - discard - t = 5 - -proc bar(t: var int) = - t = 5 - -foo(bar) - -block: # bug #12595 - template test() = - let i = 42 - discard {i: ""} - - test() diff --git a/tests/template/template_pragmas.nim b/tests/template/template_pragmas.nim index da532b010..d6c99080d 100644 --- a/tests/template/template_pragmas.nim +++ b/tests/template/template_pragmas.nim @@ -3,7 +3,7 @@ proc output_x:string {.compileTime.} = "x" template t = const x = output_x() let - bar {.exportc:"bar" & x.} = 100 + bar {.exportC:"bar" & x.} = 100 static: doAssert(compiles (t())) diff --git a/tests/template/template_various.nim b/tests/template/template_various.nim index a3b549e18..ac7e91fa2 100644 --- a/tests/template/template_various.nim +++ b/tests/template/template_various.nim @@ -10,28 +10,6 @@ bar7 4true 132 20 -1 --1 -4 -11 -26 -57 --1-1-1 - 4 -4 - 4 - 11 -11 - 4 - 11 - 26 -26 - 4 - 11 - 26 - 57 -57 --1-1-1 ''' """ @@ -94,7 +72,7 @@ block generic_templates: var i3: int = t1[int]("xx") -from strutils import contains + block tgetast_typeliar: proc error(s: string) = quit s @@ -107,13 +85,11 @@ block tgetast_typeliar: error("Assertion failed: " & $(`message`) & "\n" & `line`) return - macro assertOrReturn(condition: bool) = + macro assertOrReturn(condition: bool): typed = var message : NimNode = newLit(condition.repr) # echo message result = getAst assertOrReturn2(condition, message) - # echo result.repr - let s = result.repr - doAssert """error("Assertion failed:""" in s + echo result.repr proc point(size: int16): tuple[x, y: int16] = # returns random point in square area with given `size` @@ -269,102 +245,3 @@ template parse9(body: untyped): untyped = parse9: echo val9("1") - - -block gensym1: - template x: untyped = -1 - template t1() = - template x: untyped {.gensym, redefine.} = 1 - echo x() # 1 - template t2() = - template x: untyped {.redefine.} = 1 # defaults to {.inject.} - echo x() # -1 injected x not available during template definition - t1() - t2() - -block gensym2: - let x,y,z = -1 - template `!`(xx,yy: typed): untyped = - template x: untyped {.gensym.} = xx - template y: untyped {.gensym.} = yy - let z = x + x + y - z - var - a = 1 - b = 2 - c = 3 - d = 4 - e = 5 - echo a ! b - echo a ! b ! c - echo a ! b ! c ! d - echo a ! b ! c ! d ! e - echo x,y,z - -block gensym3: - macro liftStmts(body: untyped): auto = - # convert - # template x: untyped {.gensym.} = - # let z = a + a + b - # echo z - # z - # to - # let z = a + a + b - # echo z - # template x: untyped {.gensym.} = - # z - #echo body.repr - body.expectKind nnkStmtList - result = newNimNode nnkStmtList - for s in body: - s.expectKind nnkTemplateDef - var sle = s[6] - while sle.kind == nnkStmtList: - doAssert(sle.len==1) - sle = sle[0] - if sle.kind == nnkStmtListExpr: - let n = sle.len - for i in 0..(n-2): - result.add sle[i] - var td = newNimNode nnkTemplateDef - for i in 0..5: - td.add s[i] - td.add sle[n-1] - result.add td - else: - result.add s - #echo result.repr - let x,y,z = -1 - template `!`(xx,yy: typed): untyped = - liftStmts: - template x: untyped {.gensym.} = xx - template y: untyped {.gensym.} = yy - let z = x + x + y - echo " ", z - z - var - a = 1 - b = 2 - c = 3 - d = 4 - e = 5 - echo a ! b - echo a ! b ! c - echo a ! b ! c ! d - echo a ! b ! c ! d ! e - echo x,y,z - - -block identifier_construction_with_overridden_symbol: - # could use add, but wanna make sure it's an override no matter what - func examplefn = discard - func examplefn(x: int) = discard - - # the function our template wants to use - func examplefn1 = discard - - template exampletempl(n) = - # attempt to build a name using the overridden symbol "examplefn" - `examplefn n`() - - exampletempl(1) diff --git a/tests/template/tgensym_instantiationinfo.nim b/tests/template/tgensym_instantiationinfo.nim index 4b997ed6a..305e7e1c3 100644 --- a/tests/template/tgensym_instantiationinfo.nim +++ b/tests/template/tgensym_instantiationinfo.nim @@ -5,7 +5,7 @@ discard """ # bug #7937 template printError(error: typed) = - # Error: inconsistent typing for reintroduced symbol 'instInfo': previous type was: tuple[filename: string, line: int, column: int]; new type is: (string, int, int) + # Error: inconsistent typing for reintroduced symbol 'instInfo': previous type was: tuple[filename: string, line: int, column: int]; new type is: tuple of (string, int, int) let instInfo {.gensym.} = instantiationInfo() echo "Error at ", instInfo.filename, ':', instInfo.line, ": ", error diff --git a/tests/template/tgensymregression.nim b/tests/template/tgensymregression.nim index 2a5dca934..a743d3a08 100644 --- a/tests/template/tgensymregression.nim +++ b/tests/template/tgensymregression.nim @@ -1,6 +1,8 @@ discard """ output: '''[0.0, 0.0, 0.0] + [0.0, 0.0, 0.0, 0.0] + 5050 123''' """ @@ -55,7 +57,7 @@ converter int2string(x: int): string = $x template wrap(body: typed): untyped = body -macro makeProc() = +macro makeProc(): typed = # Make a template tree result = quote do: proc someProc* = diff --git a/tests/template/tinnerouterproc.nim b/tests/template/tinnerouterproc.nim deleted file mode 100644 index 1f15fb13e..000000000 --- a/tests/template/tinnerouterproc.nim +++ /dev/null @@ -1,8 +0,0 @@ -block: # #20002 - proc bar(x: int): int = 10 - template foo = - proc bar(x: int): int {.gensym.} = x + 2 - doAssert bar(3) == 5 - discard 3.bar # evaluates to 10 but only check if it compiles for now - block: - foo() diff --git a/tests/template/tmodulealias.nim b/tests/template/tmodulealias.nim index 79b5ec9c6..6681379fb 100644 --- a/tests/template/tmodulealias.nim +++ b/tests/template/tmodulealias.nim @@ -7,7 +7,7 @@ when defined(windows): else: import posix -when defined(windows): +when defined(Windows): template orig: expr = winlean else: diff --git a/tests/template/tparams_gensymed.nim b/tests/template/tparams_gensymed.nim index b68d7e253..a35d878d5 100644 --- a/tests/template/tparams_gensymed.nim +++ b/tests/template/tparams_gensymed.nim @@ -15,7 +15,6 @@ wth 0 (total: 6) S1 -5 ''' """ # bug #1915 @@ -72,7 +71,7 @@ proc concreteProc(x: int) = forStatic i, 0..3: echo i -proc genericProc(x: auto) = +proc genericProc(x: any) = forStatic i, 0..3: echo i @@ -196,201 +195,3 @@ mystate_machine: state_push(S1) echo state_current() state_pop() - -# bug #15075 -block: #Doesn't work - template genGenTempl: untyped = - proc loop(locals: int) - proc loop(locals: int) = discard - genGenTempl() - let pool = loop - -block: #Doesn't work - macro genGenMacro: untyped = - quote do: - proc loop(locals: int) - proc loop(locals: int) = discard - genGenMacro() - let pool = loop - -block: #This works - proc loop(locals: int) - proc loop(locals: int) = discard - let pool = loop - -#Now somewhat recursive: -type Cont = ref object of RootObj - fn*: proc(c: Cont): Cont {.nimcall.} - -block: #Doesn't work - template genGenTempl(): untyped = - proc loop(locals: Cont): Cont - proc loop(locals: Cont): Cont = - return Cont(fn: loop) - proc doServer(): Cont = - return Cont(fn: loop) - genGenTempl() - discard doServer() - -block: #Doesn't work - macro genGenMacro(): untyped = - quote: - proc loop(locals: Cont): Cont - proc loop(locals: Cont): Cont = - return Cont(fn: loop) - proc doServer(): Cont = - return Cont(fn: loop) - genGenMacro() - discard doServer() - -block: #This works - proc loop(locals: Cont): Cont - proc loop(locals: Cont): Cont = - return Cont(fn: loop) - proc doServer(): Cont = - return Cont(fn: loop) - discard doServer() - -#And fully recursive: -block: #Doesn't work - template genGenTempl: untyped = - proc loop(locals: int) - proc loop(locals: int) = loop(locals) - genGenTempl() - let pool = loop - -block: #Doesn't work - macro genGenMacro: untyped = - quote do: - proc loop(locals: int) - proc loop(locals: int) = loop(locals) - genGenMacro() - let pool = loop - -block: #This works - proc loop(locals: int) - proc loop(locals: int) = loop(locals) - let pool = loop - -block: - template genAndCallLoop: untyped = - proc loop() {.gensym.} - proc loop() {.gensym.} = - discard - loop() - genAndCallLoop - -block: #Fully recursive and gensymmed: - template genGenTempl: untyped = - proc loop(locals: int) {.gensym.} - proc loop(locals: int) {.gensym.} = loop(locals) - let pool = loop - genGenTempl() - -block: #Make sure gensymmed symbol doesn't overwrite the forward decl - proc loop() - proc loop() = discard - template genAndCallLoop: untyped = - proc loop() {.gensym.} = - discard - loop() - genAndCallLoop() - -template genLoopDecl: untyped = - proc loop() -template genLoopDef: untyped = - proc loop() = discard -block: - genLoopDecl - genLoopDef - loop() -block: - proc loop() - genLoopDef - loop() -block: - genLoopDecl - proc loop() = discard - loop() - -block: #Gensymmed sym sharing forward decl - macro genGenMacro: untyped = - let sym = genSym(nskProc, "loop") - nnkStmtList.newTree( - newProc(sym, body = newEmptyNode()), - newCall(sym), - newProc(sym, body = newStmtList()), - ) - genGenMacro - -# inject pragma on params - -template test(procname, body: untyped): untyped = - proc procname(data {.inject.}: var int = 0) = - body - -test(hello): - echo data - data = 3 - -var data = 5 - -hello(data) - -# bug #5691 - -template bar(x: typed) = discard -macro barry(x: typed) = discard - -var a = 0 - -bar: - var a = 10 - -barry: - var a = 20 - -bar: - var b = 10 - -barry: - var b = 20 - -var b = 30 - -# template bar(x: static int) = discard -#You may think that this should work: -# bar((var c = 1; echo "hey"; c)) -# echo c -#But it must not! Since this would be incorrect: -# bar((var b = 3; const c = 1; echo "hey"; c)) -# echo b # <- b wouldn't exist - -discard not (let xx = 1; true) -discard xx - -template barrel(a: typed): untyped = a - -barrel: - var aa* = 1 - var bb = 3 - export bb - -# Test declaredInScope within params -template test1: untyped = - when not declaredInScope(thing): - var thing {.inject.}: int - -proc chunkedReadLoop = - test1 - test1 - -template test2: untyped = - when not not not declaredInScope(thing): - var thing {.inject.}: int - -proc chunkedReadLoop2 = - test2 - test2 - -test1(); test2() diff --git a/tests/template/tparamscope.nim b/tests/template/tparamscope.nim deleted file mode 100644 index 177c682cf..000000000 --- a/tests/template/tparamscope.nim +++ /dev/null @@ -1,10 +0,0 @@ -discard """ - errormsg: "undeclared identifier: 'a'" - line: 10 -""" - - -template secondArg(a, b: typed): untyped = - b - -echo secondArg((var a = 1; 1), a) diff --git a/tests/template/tredefinition_override.nim b/tests/template/tredefinition_override.nim deleted file mode 100644 index 7ae232bba..000000000 --- a/tests/template/tredefinition_override.nim +++ /dev/null @@ -1,33 +0,0 @@ -{.push warningAsError[ImplicitTemplateRedefinition]: on.} - -doAssert not (compiles do: - template foo(): int = 1 - template foo(): int = 2) -doAssert (compiles do: - template foo(): int = 1 - template foo(): int {.redefine.} = 2) -doAssert not (compiles do: - block: - template foo() = - template bar: string {.gensym.} = "a" - template bar: string {.gensym.} = "b" - foo()) -doAssert (compiles do: - block: - template foo() = - template bar: string {.gensym.} = "a" - template bar: string {.gensym, redefine.} = "b" - foo()) - -block: - template foo(): int = 1 - template foo(): int {.redefine.} = 2 - doAssert foo() == 2 -block: - template foo(): string = - template bar: string {.gensym.} = "a" - template bar: string {.gensym, redefine.} = "b" - bar() - doAssert foo() == "b" - -{.pop.} diff --git a/tests/template/tshadow.nim b/tests/template/tshadow.nim deleted file mode 100644 index a4de71592..000000000 --- a/tests/template/tshadow.nim +++ /dev/null @@ -1,29 +0,0 @@ -discard """ - output: '''fish -fish''' -""" - -import macros - -block: - template init(initHook: proc(s: string)) = - proc dostuff = - var s = "fish" - initHook(s) - dostuff() - - init do(s: string): - echo s - -block: - macro init(initHook: proc(s: string)) = - result = newStmtList( - newProc(name = ident("dostuff"), body = newStmtList( - newVarStmt(ident("s"), newStrLitNode("fish")), - newCall(initHook, ident("s")) - )), - newCall("dostuff") - ) - - init proc(s: string) = - echo s diff --git a/tests/template/tunderscore1.nim b/tests/template/tunderscore1.nim deleted file mode 100644 index 71af39501..000000000 --- a/tests/template/tunderscore1.nim +++ /dev/null @@ -1,11 +0,0 @@ -discard """ - errormsg: "undeclared identifier: '_'" -""" - -# issue #12094, #13804 - -template foo = - let _ = 1 - echo _ - -foo() diff --git a/tests/template/twhenintemplates.nim b/tests/template/twhenintemplates.nim deleted file mode 100644 index 6fded856d..000000000 --- a/tests/template/twhenintemplates.nim +++ /dev/null @@ -1,11 +0,0 @@ -# bug #3670 - -template someTempl(someConst: bool) = - when someConst: - var a : int - if true: - when not someConst: - var a : int - a = 5 - -someTempl(true) diff --git a/tests/template/twrongmapit.nim b/tests/template/twrongmapit.nim index 13f53d119..5b8663cf9 100644 --- a/tests/template/twrongmapit.nim +++ b/tests/template/twrongmapit.nim @@ -1,5 +1,4 @@ discard """ - disabled: true output: "####" """ # unfortunately our tester doesn't support multiple lines of compiler diff --git a/tests/template/utemplates.nim b/tests/template/utemplates.nim index d70746578..017166250 100644 --- a/tests/template/utemplates.nim +++ b/tests/template/utemplates.nim @@ -3,11 +3,11 @@ import unittest template t(a: int): string = "int" template t(a: string): string = "string" -block: # templates can be overloaded +test "templates can be overloaded": check t(10) == "int" check t("test") == "string" -block: # previous definitions can be further overloaded or hidden in local scopes +test "previous definitions can be further overloaded or hidden in local scopes": template t(a: bool): string = "bool" check t(true) == "bool" @@ -17,12 +17,12 @@ block: # previous definitions can be further overloaded or hidden in local scope check t(10) == "inner int" check t("test") == "string" -block: # templates can be redefined multiple times +test "templates can be redefined multiple times": template customAssert(cond: bool, msg: string): typed {.dirty.} = if not cond: fail(msg) template assertionFailed(body: untyped) {.dirty.} = - template fail(msg: string): typed {.redefine.} = + template fail(msg: string): typed = body assertionFailed: diff --git a/tests/test_nimscript.nims b/tests/test_nimscript.nims index 725e75ebc..3efbb0a4c 100644 --- a/tests/test_nimscript.nims +++ b/tests/test_nimscript.nims @@ -1,138 +1,25 @@ # This nimscript is used to test if the following modules can be imported # http://nim-lang.org/docs/nims.html -{.warning[UnusedImport]: off.} - -from stdtest/specialpaths import buildDir - -when defined(nimPreviewSlimSystem): - import std/[ - syncio, assertions, formatfloat, objectdollar, widestrs - ] - -import std/[ - # Core: - bitops, typetraits, lenientops, macros, volatile, - # fails due to FFI: typeinfo - # fails due to cstring cast/copyMem: endians - # works but uses FFI: cpuinfo, rlocks, locks - - # Algorithms: - algorithm, enumutils, sequtils, setutils, - - # Collections: - critbits, deques, heapqueue, intsets, lists, options, sets, - tables, packedsets, - - # Strings: - editdistance, wordwrap, parseutils, ropes, - pegs, strformat, strmisc, strscans, strtabs, - strutils, unicode, unidecode, cstrutils, - # works but uses FFI: encodings - - # Time handling: - # fails due to FFI: monotimes, times - # but times.getTime() implemented for VM - - # Generic operator system services: - os, streams, distros, - # fails due to FFI: memfiles, osproc, terminal - # works but uses FFI: dynlib - # intentionally fails: marshal - - # Math libraries: - complex, math, random, rationals, stats, sums, - # works but uses FFI: fenv, sysrand - - # Internet protocols: - httpcore, mimetypes, uri, - # fails due to FFI: asyncdispatch, asyncfile, asyncftpclient, asynchttpserver, - # asyncnet, cgi, cookies, httpclient, nativesockets, net, selectors, smtp - # works but no need to test: asyncstreams, asyncfutures - - # Threading: - # fails due to FFI: threadpool - - # Parsers: - htmlparser, json, lexbase, parsecfg, parsecsv, parsesql, parsexml, - parseopt, jsonutils, - - # XML processing: - xmltree, xmlparser, - - # Generators: - htmlgen, - - # Hashing: - base64, hashes, md5, - # fails due to cstring cast/times import/endians import: oids - # fails due to copyMem/endians import: sha1 - - # Miscellaneous: - colors, sugar, varints, enumerate, with, - # fails due to FFI: browsers, coro, segfaults - # fails due to times import/methods: logging - # fails due to methods: unittest - - # Modules for JS backend: - # fails intentionally: asyncjs, dom, jsconsole, jscore, jsffi, jsbigints, - # jsfetch, jsformdata, jsheaders - - # Unlisted in lib.html: - decls, compilesettings, wrapnils, effecttraits, genasts, - importutils, isolation -] - -# non-std imports -import stdtest/testutils -# tests (increase coverage via code reuse) -import stdlib/trandom -import stdlib/tosenv +import algorithm +import base64 +import colors +import hashes +import lists +import math +# import marshal +import options +import os +# import parsecfg +# import parseopt +import parseutils +# import pegs +import deques +import sequtils +import strutils +import tables +import unicode +import uri +import macros echo "Nimscript imports are successful." - -block: - doAssert "./foo//./bar/".normalizedPath == "foo/bar".unixToNativePath -block: - doAssert $3'u == "3" - doAssert $3'u64 == "3" - -block: # #14142 - discard dirExists("/usr") - discard fileExists("/usr/foo") - discard findExe("nim") - -block: - doAssertRaises(AssertionDefect): doAssert false - try: doAssert false - except Exception as e: - discard - -block: # cpDir, cpFile, dirExists, fileExists, mkDir, mvDir, mvFile, rmDir, rmFile - const dname = buildDir/"D20210121T175016" - const subDir = dname/"sub" - const subDir2 = dname/"sub2" - const fpath = subDir/"f" - const fpath2 = subDir/"f2" - const fpath3 = subDir2/"f" - mkDir(subDir) - writeFile(fpath, "some text") - cpFile(fpath, fpath2) - doAssert fileExists(fpath2) - rmFile(fpath2) - cpDir(subDir, subDir2) - doAssert fileExists(fpath3) - rmDir(subDir2) - mvFile(fpath, fpath2) - doAssert not fileExists(fpath) - doAssert fileExists(fpath2) - mvFile(fpath2, fpath) - mvDir(subDir, subDir2) - doAssert not dirExists(subDir) - doAssert dirExists(subDir2) - mvDir(subDir2, subDir) - rmDir(dname) - -block: - # check parseopt can get command line: - discard initOptParser() diff --git a/tests/testament/t16576.nim b/tests/testament/t16576.nim deleted file mode 100644 index 8d0dd57e3..000000000 --- a/tests/testament/t16576.nim +++ /dev/null @@ -1,7 +0,0 @@ -discard """ - matrix:"-d:nimTest_t16576" -""" - -# bug #16576 -doAssert defined(nimTest_t16576) -doAssert not defined(nimMegatest) diff --git a/tests/testament/tinlinemsg.nim b/tests/testament/tinlinemsg.nim deleted file mode 100644 index 199c263e9..000000000 --- a/tests/testament/tinlinemsg.nim +++ /dev/null @@ -1,8 +0,0 @@ -discard """ - matrix: "--errorMax:0 --styleCheck:error" -""" - -proc generic_proc*[T](a_a: int) = #[tt.Error - ^ 'generic_proc' should be: 'genericProc'; tt.Error - ^ 'a_a' should be: 'aA' ]# - discard diff --git a/tests/testament/tjoinable.nim b/tests/testament/tjoinable.nim deleted file mode 100644 index c651780de..000000000 --- a/tests/testament/tjoinable.nim +++ /dev/null @@ -1,9 +0,0 @@ -discard """ - output: "ok" -""" - -# checks that this is joinable -# checks that megatest allows duplicate names, see also `tests/misc/tjoinable.nim` -doAssert defined(testing) -doAssert defined(nimMegatest) -echo "ok" # intentional to make sure this doesn't prevent `isJoinableSpec` diff --git a/tests/testament/treject.nim b/tests/testament/treject.nim deleted file mode 100644 index be2db86a9..000000000 --- a/tests/testament/treject.nim +++ /dev/null @@ -1,6 +0,0 @@ -discard """ -action: "reject" -""" - -# this line does not compile, so the test should pass, since action="reject" -let x: int = "type mismatch" diff --git a/tests/testament/tshould_not_work.nim b/tests/testament/tshould_not_work.nim index 8c99510a0..aca73c308 100644 --- a/tests/testament/tshould_not_work.nim +++ b/tests/testament/tshould_not_work.nim @@ -1,53 +1,33 @@ discard """ - joinable: false -""" - -const expected = """ -FAIL: tests/shouldfail/tccodecheck.nim +cmd: "testament/testament --directory:testament --colors:off --backendLogging:off --nim:../compiler/nim category shouldfail" +action: compile +nimout: ''' +FAIL: tests/shouldfail/tccodecheck.nim C Failure: reCodegenFailure Expected: baz -FAIL: tests/shouldfail/tcolumn.nim +FAIL: tests/shouldfail/tcolumn.nim C Failure: reLinesDiffer -FAIL: tests/shouldfail/terrormsg.nim +FAIL: tests/shouldfail/terrormsg.nim C Failure: reMsgsDiffer -FAIL: tests/shouldfail/texitcode1.nim +FAIL: tests/shouldfail/texitcode1.nim C Failure: reExitcodesDiffer -FAIL: tests/shouldfail/tfile.nim +FAIL: tests/shouldfail/tfile.nim C Failure: reFilesDiffer -FAIL: tests/shouldfail/tline.nim +FAIL: tests/shouldfail/tline.nim C Failure: reLinesDiffer -FAIL: tests/shouldfail/tmaxcodesize.nim +FAIL: tests/shouldfail/tmaxcodesize.nim C Failure: reCodegenFailure max allowed size: 1 -FAIL: tests/shouldfail/tnimout.nim +FAIL: tests/shouldfail/tnimout.nim C Failure: reMsgsDiffer -FAIL: tests/shouldfail/tnimoutfull.nim -Failure: reMsgsDiffer -FAIL: tests/shouldfail/toutput.nim +FAIL: tests/shouldfail/toutput.nim C Failure: reOutputsDiffer -FAIL: tests/shouldfail/toutputsub.nim +FAIL: tests/shouldfail/toutputsub.nim C Failure: reOutputsDiffer -FAIL: tests/shouldfail/treject.nim -Failure: reFilesDiffer -FAIL: tests/shouldfail/tsortoutput.nim +FAIL: tests/shouldfail/tsortoutput.nim C Failure: reOutputsDiffer -FAIL: tests/shouldfail/ttimeout.nim +FAIL: tests/shouldfail/ttimeout.nim C Failure: reTimeout -FAIL: tests/shouldfail/tvalgrind.nim -Failure: reExitcodesDiffer +''' """ - -import std/[os,strformat,osproc] -import stdtest/testutils - -proc main = - const nim = getCurrentCompilerExe() - let testamentExe = "bin/testament" - let cmd = fmt"{testamentExe} --directory:testament --colors:off --backendLogging:off --nim:{nim} category shouldfail" - let (outp, status) = execCmdEx(cmd) - doAssert status == 1, $status - - let ok = greedyOrderedSubsetLines(expected, outp, allowPrefixMatch = true) - doAssert ok, &"\nexpected:\n{expected}\noutp:\n{outp}" -main() diff --git a/tests/testament/tspecialpaths.nim b/tests/testament/tspecialpaths.nim deleted file mode 100644 index 3c97dc88a..000000000 --- a/tests/testament/tspecialpaths.nim +++ /dev/null @@ -1,9 +0,0 @@ -import stdtest/specialpaths -import std/os -block: # splitTestFile - doAssert splitTestFile("tests/fakedir/tfakename.nim") == ("fakedir", "tests/fakedir/tfakename.nim".unixToNativePath) - doAssert splitTestFile("/pathto/tests/fakedir/tfakename.nim") == ("fakedir", "/pathto/tests/fakedir/tfakename.nim".unixToNativePath) - doAssert splitTestFile(getCurrentDir() / "tests/fakedir/tfakename.nim") == ("fakedir", "tests/fakedir/tfakename.nim".unixToNativePath) - doAssert splitTestFile(getCurrentDir() / "sub/tests/fakedir/tfakename.nim") == ("fakedir", "sub/tests/fakedir/tfakename.nim".unixToNativePath) - doAssertRaises(AssertionDefect): discard splitTestFile("testsbad/fakedir/tfakename.nim") - doAssertRaises(AssertionDefect): discard splitTestFile("tests/tfakename.nim") diff --git a/tests/testdata/mycert.pem b/tests/testdata/mycert.pem index 61dcb685c..69039fe04 100644 --- a/tests/testdata/mycert.pem +++ b/tests/testdata/mycert.pem @@ -1,81 +1,32 @@ -----BEGIN PRIVATE KEY----- -MIIJQwIBADANBgkqhkiG9w0BAQEFAASCCS0wggkpAgEAAoICAQDgpWhnNdNSUbwJ -39mKf+PA879K1wyT23LC3Ipo5g5vaRjB4vrSh5vzrjK5Q/z42yRDLQ2ojEdUne19 -1xMaM+WqTXnfkf9sou4VJ0HsdQ6jOU1LDRPrPvCjHLZjyMu18sGvQf4FATBwWN3n -QhmvcbleTeyv2pgMNeQDfjuIhRJ/aCIi/WYQ466+Rcj0y3/udYX1yPYf2mszXnSE -i2iWgdsjx0qkDU/nJhnKXhKfucAm9Ds0YfQdZYN3rEzfGkJzZUhDG1n30ghu+vUg -qqLi6HU/HqBxKxBlJf2HdMNK4VLkJuFC+wCI0JfF6VYhcNmtZzlQy3M9WjYvbXUY -nvMkQzUECaSaAtmbhFFfgey1Q3IEQS/j1lsVxtuGUE3YaoyaK22/CkVInDz0aka9 -CKq77x7S/V5PP/wwPV4s8XsbT6/34KemuY3oU84+bf5SBuWdzBY0hnDO9c/FaOnZ -4yjLMQi285HLpK417Z32DmzIkb7GjKtP9WLvsWGgbgquEjcFaIT+erkN09cDjsG/ -URWbKcsQkz8v9E4zj0rxdanXoJEtg1gm+dPsiXokZOLTeaMVtDoTkWeCM/VAp25J -MTc656QRUTSzUODK5tXQ3JgE2XIPGV/PsMi7T/q9xFBQmhUk5kfLNlQ1cy/aiTWK -8pjHcmxbyD121AimuTtv9CFYnYtzyQIDAQABAoICAAMYZFrfs/yzYZrlObMd1f6H -nUAjvGmhIXCr50BQwywnz46EWR5jffOal9pTpH2tT0+ZpFGJNUZmMqqENyAqTOTO -0noRIerWR9+EvfTLHBuFo5oAISEhqeEleSHg12W3ZZHLn/tjq84we0Y/c+kl8P7q -pfM6WNP6Ph0KNTnJU5rrzWScBzb+XB8FCSLOVwHrHqBnV3TS5p07lPFqllNUkLdq -fI3MHSi7LqnKKAmJXqtqvBIZs2pgRrJ0bk64pue+IoPCMbgnbbRRwuTjVQE5YLww -6NcGV+B86IRgSHyUpDa+jmYE3VoFPcIdV/F4A5fPD0wcsYbL4mk+4dkn/4OlZWqV -NZILp2IGejKaKtM1fr7fV2IRUbGUBN/+rX4I0SRnuq6Q4Ipx8VASbpgXQPBo9XTg -SHHsFbEu2DL8BHVgXdOy4PW6jQ0Ux2LhuJk6AQ5nIlFBYA+c8rSlZQXJbEbk1VZu -1i7iSOn/kx3ULMjUfhI/Ddm6rQqtiLbXSubXCzu1HMPT1FG9LUfAbq6EpiVkpAk1 -TqlciBHsyz//mk2RmIEx0Bt+0bX8FFGTIUiGyrp5s4hAHbgQZbXBAUYMRzWxhZ2Q -G0KBXx46bv3hJUb0GOgbNVxcaPnyrXaS/Hafcbx2LXlEtKiwGnC/yKJ7Hmcrt+AQ -RTaqNU1o/bkSYC7vHMZdAoIBAQD79uYPZPv5GLCKPZ64gc3+tbFXNqkmL7qv14yD -Gr3VubRbJe3Fx+T1cS+t9cjgOofhjFnwsDaFRoyWOYqRV/znwFsvvsDhHOLBr1u6 -qWQiF2CT1uMdXR3P6KD8h2DUVNNccxKqqIJNCR5oD/ngnnByWkQobzlsnoIdXgZm -ozBZjGr2XUMO5dJqUxaXZwY3j4I2hk/Ka9uroApyptl+DTVbPHvjk3MzU9QKUNor -vXEtQ8EmM8Oy6v/33HBmNs6cF5fMpgWz6u+B357OTxAfu8B42jZ18OeLrvkHFxzu -phOB1uXvqtQ0tdksSHHWj3IIZRK7GDGudnDEZ23vbCaxH4zbAoIBAQDkPn+5N3px -7UAECWrvT10TD3xKeqMkFhqRA9gmDE4N9AdoN6T6PzD7Tr3gOgGLq1tXjCjBqAlx -ZIDTnih3IK3xoRk2zmhq5+LfM8LQRAxAC8IsoQMXAsmW1KlS6MR70m50pFR8NK6r -UmOdrwVUKp3K6Mecid3LmMVLXGMUKwIJc1k7LJHtwrfi0i5xfBtiqQeaR0lJg4Zr -+zEL/4rHfcq06/P3k0+4uLKZ1LGOvwLPiTA3DADPWZbzUXo7McKOFWF/ycGQBrJq -AJikx15dVLnB16bnHXdxrlrd0LON2R+XfT4+dfRymqZLzrBI3L39t/elTmVYnD3P -punkmZuVwNErAoIBAQD5xOiOPibh6S2n/CmI8XQImIgx0kefSRUhFuV9WVbxtOMq -r9CijONUw1zmb40vahYk6gKGa8fAGg1nJadNKRHVkoNSMx/0h7PpGDIwOZa/jLj6 -FLyS8SmKXiqn6nN8SJI1RQUuE1kHkJCJy7yCg80oLn7+LjOYjxCgmAJ0YDSfsGif -zBebfws0xyTP9RrenO4RqtcR7BWYbk+tE+Tp5aIMzUpqcFJ0gRbjGv8K+QJmQpIH -kqzegcI4LFdnm9D4PxMFlVZ14eCGt+wuy4VKT84efwIZrDN77nmCI9FUaWFRBnxt -NsShc9rS4QWoEg6Sb88/lF47ecGTkIwUGPvJ/WKdAoIBAQClF7/zDPn4Zg+j29wJ -dXJxUwYoKUTP2V0l/43dF5Ft7lFdRMKEcCjR3kbhZZOwnyXW0X65dP4/kt7MMt46 -LN0kpc5DIlHM4iXsJNiJJG9n9BljhqNhhZajDvfbDJrypWdX33Vs0f511YZQjERi -eODh4DZiOCbCGaK7u/u+ns0+YLzuXHLBc9Lmsfj+BTMZzgG9ykpsbkJQ4MS9VP3h -BlAVRYaWUWucxZwKQRqdkfRKgYTqjDgZw0e4f/rVzkxX0YdQk3L65p0up3fB2KOd -BqfGWmJTUbEP/XmkcE0wERkUznazX0aNjucydjJ0wZZ7axIp8+bCjWD4TldoDuPH -Ek05AoIBAECgPfBHLQTAsI+wHbFsu/are28BOiJCSEXjRv88CbUbj/qgAppFuXbx -900WwJ1rVWd5x3LFa3VfyuAqYMi5jzmX9kWgEsC0WhgfyIRFiynw45LlcT4u3fWg -vJEx01lGgFVjnYfFUDS9d1MuiXGxIHrNhzHOP2x2CsS5vrFHav7iwG9YULEk8tJr -My0wzjF3UJ2/5DjGK56WuzauLYKrQ6Faw8dWUy4e/bNYId8wglhQQW548JwJEGmq -nq+EzTfEupXH57Bw7MGEOfdlhv98zNT9VcvBAN09vHeF3Hh6AM4aiGSUIt2HIkto -zvw+fqZ2Sk9O5qva+KE1QMVtY1EICI8= +MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAL9QXX/nuiFbizdI +Uhg1D9gG0GIANENvKwdWTlOlZAoOqvjXPFLGh+87yhvkq4f5FcICkSDao2SfeZcP +JsgD7T01owt8x48898+d91i7nIpr6IXGPyBxHOuaxAITY1D+MbbkhIGUVrEqKEOm +qfS9cqPZaDNkx8xVef0HPCmqEme9AgMBAAECgYBxqrQCvJFQJG3QiL2N+GjTdyj0 +MR7cOf6cu2CKPifz+ccHVgpXO/Gj6Cgq7nAjt5B/1rqXhI+zxzSc1bm6+OpIfakS +E0DLCFacECmL0v3c+XLxTtMhFZF5u7Yq0UMsuWmDSfRb4sbRjC+s+c51i5N0485k +b3un/MDI/i/jD/YZGQJBAPLtcuMIwEblUR1uw7NFezXdauXCRFkekoSlJNvpdM/Z +XDRcuWioek5yD8FvMpTz7H2e26Ev645JT5lIuN4Eti8CQQDJm+Qt9NYUohRsU279 +GYI3vXsXKKqmA22at4I3KRXPSeYV1vtQLYWWqGAXzgGkUEVBY0chmHyDcNwkUsNw +svHTAkEAwOTpD/vX6bOXOD7GqKgoULozcqNScE2FXExhuzliJtTakT17f+4fyABs +IFWynXIevBUTIqeRbJcr3HRRTwIAwwJBAJQ8XkL4IaxcG/4mPpY0ek13sZiumwKj +xKQcx869E78tS9LFFlW2kuHafYUjQIvLRZC1aWinUO3oPsUqYW9s82cCQFjoods5 +YsWEJB2RKCT5nhyAXEZLehxF+FXr+JjLMHkuEINKTnHHKjHJ7LbMcTCKUJAcKDTA +qZFEq5N1aT6DrAU= -----END PRIVATE KEY----- -----BEGIN CERTIFICATE----- -MIIFCTCCAvGgAwIBAgIUKqDcJ71wiMObIQ5sga2sZItNseowDQYJKoZIhvcNAQEL -BQAwFDESMBAGA1UEAwwJbG9jYWxob3N0MB4XDTIyMDUwNDExMzAwN1oXDTIyMDYw -MzExMzAwN1owFDESMBAGA1UEAwwJbG9jYWxob3N0MIICIjANBgkqhkiG9w0BAQEF -AAOCAg8AMIICCgKCAgEA4KVoZzXTUlG8Cd/Zin/jwPO/StcMk9tywtyKaOYOb2kY -weL60oeb864yuUP8+NskQy0NqIxHVJ3tfdcTGjPlqk1535H/bKLuFSdB7HUOozlN -Sw0T6z7woxy2Y8jLtfLBr0H+BQEwcFjd50IZr3G5Xk3sr9qYDDXkA347iIUSf2gi -Iv1mEOOuvkXI9Mt/7nWF9cj2H9prM150hItoloHbI8dKpA1P5yYZyl4Sn7nAJvQ7 -NGH0HWWDd6xM3xpCc2VIQxtZ99IIbvr1IKqi4uh1Px6gcSsQZSX9h3TDSuFS5Cbh -QvsAiNCXxelWIXDZrWc5UMtzPVo2L211GJ7zJEM1BAmkmgLZm4RRX4HstUNyBEEv -49ZbFcbbhlBN2GqMmittvwpFSJw89GpGvQiqu+8e0v1eTz/8MD1eLPF7G0+v9+Cn -prmN6FPOPm3+UgblncwWNIZwzvXPxWjp2eMoyzEItvORy6SuNe2d9g5syJG+xoyr -T/Vi77FhoG4KrhI3BWiE/nq5DdPXA47Bv1EVmynLEJM/L/ROM49K8XWp16CRLYNY -JvnT7Il6JGTi03mjFbQ6E5FngjP1QKduSTE3OuekEVE0s1DgyubV0NyYBNlyDxlf -z7DIu0/6vcRQUJoVJOZHyzZUNXMv2ok1ivKYx3JsW8g9dtQIprk7b/QhWJ2Lc8kC -AwEAAaNTMFEwHQYDVR0OBBYEFEZcUeqH6MfIzC56BlD3NSs2mCgGMB8GA1UdIwQY -MBaAFEZcUeqH6MfIzC56BlD3NSs2mCgGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZI -hvcNAQELBQADggIBADGc7WONP6I6Trb7ici9fQ9qT3wh/RGDcmUDmDtARn9SFtOF -hsbszOMZg1Flj10fuD6OYDonKz4rv+Ieo5VkAYXxxd3J+bx2x1pqd1YSIsvugTwv -pnx39uBR9cjOmt4W7RyzhFnXoVfuSBE6LpkBUjcrqi5xwrQ31mOSCPwe8uDZYEWS -pX49MiHXGTyjQ481QLiOtTBZJa5igfnHUJbJbyZMa86zBQ/clS7+OeDwkvaEpjov -2VQf3QouVLghfLZYWSxWdEKD9+IWHn8rV6qksEb/Ogu4ZtzDRGqJow4j0DeSSEu7 -ns1YeT2mVTFwHjGXCWS+0iE885NDVX/b5YptlwH5PW7aqeXyCS9Hrd1C1GnXoXGp -NHltYRTyNWm974xWg7eu2gbbB8Ng02chXysdkBq7l+7OyA0a2EfX3Cbz3/49+Mqn -viqwNO5toSHVCdfV9Jd0p0CcqryYgyt2YNpJB+2nUQpiW4jviAs49PZg2PpCVw/2 -0cqtaPeUh26Si8UzDOuT697PIuGkZ9Q9QVwccVXtCyA0UpJ13P0fMrA+yEMhtwSs -k1tRm0pUQa6t3v26/cAy+kMhviHBJFwi5dx+y3OMvqQqpQJrgfZawm/o2ZQHy1KP -8m4ngrJzb13evKf216qCwllmQo6Ts4yeI1Ddx8UpdX7RUWpD8Uw4zSi7Th4r +MIICgDCCAemgAwIBAgIJANpVfZSDAyNgMA0GCSqGSIb3DQEBBQUAMFkxCzAJBgNV +BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX +aWRnaXRzIFB0eSBMdGQxEjAQBgNVBAMMCWxvY2FsaG9zdDAeFw0xMjA2MDMxMjI4 +MDhaFw0xMzA2MDMxMjI4MDhaMFkxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21l +LVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxEjAQBgNV +BAMMCWxvY2FsaG9zdDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAv1Bdf+e6 +IVuLN0hSGDUP2AbQYgA0Q28rB1ZOU6VkCg6q+Nc8UsaH7zvKG+Srh/kVwgKRINqj +ZJ95lw8myAPtPTWjC3zHjzz3z533WLucimvohcY/IHEc65rEAhNjUP4xtuSEgZRW +sSooQ6ap9L1yo9loM2THzFV5/Qc8KaoSZ70CAwEAAaNQME4wHQYDVR0OBBYEFF2n +Of61swO+XSNrYb4T02tGx8afMB8GA1UdIwQYMBaAFF2nOf61swO+XSNrYb4T02tG +x8afMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEAEPHofdf4acaph5/e ++BzZGsMfRqdPgwp5sxjFKeTQI1A49VL7ykkb0iLKGfKZtvE8MjMrYjzt20E2bIZj +8eCivT6TbNrVRoACCly/lH9fZfWOG6dBu/85IrTAhSKi8yjbRzmjWUkdrcEJ+ZtV +1cahfFar4l4QwYgqp2pDd6ie+zE= -----END CERTIFICATE----- diff --git a/tests/threads/t7172.nim b/tests/threads/t7172.nim deleted file mode 100644 index 87e89417b..000000000 --- a/tests/threads/t7172.nim +++ /dev/null @@ -1,34 +0,0 @@ -discard """ - disabled: i386 - output: ''' -In doStuff() -In initProcess() -TEST -initProcess() done -Crashes before getting here! -''' - joinable: false -""" - -import std/os -import std/typedthreads - -proc whatever() {.thread, nimcall.} = - echo("TEST") - -proc initProcess(): void = - echo("In initProcess()") - var thread: Thread[void] - createThread(thread, whatever) - joinThread(thread) - echo("initProcess() done") - -proc doStuff(): void = - echo("In doStuff()") - # ... - initProcess() - sleep(500) - # ... - echo("Crashes before getting here!") - -doStuff() diff --git a/tests/threads/t8535.nim b/tests/threads/t8535.nim index a4296df11..dfc95547d 100644 --- a/tests/threads/t8535.nim +++ b/tests/threads/t8535.nim @@ -1,5 +1,4 @@ discard """ - disabled: i386 output: '''0 hello''' """ @@ -23,7 +22,7 @@ import asyncdispatch import threadpool proc f1() = - waitFor sleepAsync(20) + waitFor sleepAsync(100) echo "hello" spawn f1() diff --git a/tests/threads/threadex.nim b/tests/threads/threadex.nim index 90119aee7..50a1a4d34 100644 --- a/tests/threads/threadex.nim +++ b/tests/threads/threadex.nim @@ -1,5 +1,4 @@ discard """ - disabled: i386 outputsub: "Just a simple text for test" """ diff --git a/tests/threads/tjsthreads.nim b/tests/threads/tjsthreads.nim deleted file mode 100644 index 5122c9cd6..000000000 --- a/tests/threads/tjsthreads.nim +++ /dev/null @@ -1,6 +0,0 @@ -discard """ - targets: "js" - matrix: "--threads:on" -""" - -echo 123 diff --git a/tests/threads/tmanyjoin.nim b/tests/threads/tmanyjoin.nim index af5bc460e..2c1cda494 100644 --- a/tests/threads/tmanyjoin.nim +++ b/tests/threads/tmanyjoin.nim @@ -1,5 +1,4 @@ discard """ - disabled: i386 outputsub: "129" """ @@ -13,7 +12,7 @@ type const ThreadsCount = 129 - SleepTime = 250 + SleepTime = 1000 proc worker(p: Marker) {.thread.} = acquire(p.lock) diff --git a/tests/threads/tonthreadcreation.nim b/tests/threads/tonthreadcreation.nim index 61529477d..f588a21c9 100644 --- a/tests/threads/tonthreadcreation.nim +++ b/tests/threads/tonthreadcreation.nim @@ -1,6 +1,4 @@ discard """ - disabled: i386 - matrix: "--mm:refc; --mm:orc --deepcopy:on" output: '''some string here dying some string here''' """ diff --git a/tests/threads/tracy_allocator.nim b/tests/threads/tracy_allocator.nim index f3b39f4dc..e8f0ec927 100644 --- a/tests/threads/tracy_allocator.nim +++ b/tests/threads/tracy_allocator.nim @@ -1,5 +1,4 @@ discard """ - disabled: i386 output: '''true''' """ diff --git a/tests/threads/treusetvar.nim b/tests/threads/treusetvar.nim index f0337801a..672da6bdd 100644 --- a/tests/threads/treusetvar.nim +++ b/tests/threads/treusetvar.nim @@ -1,9 +1,8 @@ discard """ - disabled: i386 - outputsub: "65" + outputsub: "129" """ -import locks +import os, locks type MarkerObj = object @@ -12,7 +11,7 @@ type Marker = ptr MarkerObj const - ThreadsCount = 65 + ThreadsCount = 129 proc worker(p: Marker) {.thread.} = acquire(p.lock) diff --git a/tests/threads/tthreadanalysis2.nim b/tests/threads/tthreadanalysis2.nim new file mode 100644 index 000000000..067e186a8 --- /dev/null +++ b/tests/threads/tthreadanalysis2.nim @@ -0,0 +1,51 @@ +discard """ + errormsg: "'threadFunc' is not GC-safe" + file: "tthreadanalysis2.nim" + line: 37 + cmd: "nim $target --hints:on --threads:on $options $file" +""" + +import os + +var + thr: array[0..5, Thread[tuple[a, b: int]]] + +proc doNothing() = discard + +type + PNode = ref TNode + TNode = object {.pure.} + le, ri: PNode + data: string + +var + root: PNode + +proc buildTree(depth: int): PNode = + if depth == 3: return nil + new(result) + result.le = buildTree(depth-1) + result.ri = buildTree(depth-1) + result.data = $depth + +proc echoLeTree(n: PNode) = + var it = n + while it != nil: + echo it.data + it = it.le + +proc threadFunc(interval: tuple[a, b: int]) {.thread.} = + doNothing() + for i in interval.a..interval.b: + var r = buildTree(i) + echoLeTree(r) # for local data + root = buildTree(2) # BAD! + #echoLeTree(root) # and the same for foreign data :-) + +proc main = + root = buildTree(5) + for i in 0..high(thr): + createThread(thr[i], threadFunc, (i*100, i*100+50)) + joinThreads(thr) + +main() diff --git a/tests/threads/tthreadvars.nim b/tests/threads/tthreadvars.nim index 745e3562c..81aa2e5ec 100644 --- a/tests/threads/tthreadvars.nim +++ b/tests/threads/tthreadvars.nim @@ -1,5 +1,4 @@ discard """ -disabled: i386 output: ''' 10 1111 diff --git a/tests/threads/ttryrecv.nim b/tests/threads/ttryrecv.nim index fcff94e78..87dec6e79 100644 --- a/tests/threads/ttryrecv.nim +++ b/tests/threads/ttryrecv.nim @@ -1,5 +1,4 @@ discard """ - matrix: "--mm:refc" outputsub: "channel is empty" """ @@ -12,7 +11,7 @@ type PComm = ptr Channel[int] proc doAction(outC: PComm) {.thread.} = for i in 0 ..< 5: - sleep(rand(50)) + sleep(rand(100)) send(outC[], i) var diff --git a/tests/tools/compile/config.nims b/tests/tools/compile/config.nims deleted file mode 100644 index a19545668..000000000 --- a/tests/tools/compile/config.nims +++ /dev/null @@ -1 +0,0 @@ -switch("path", "$lib/../") \ No newline at end of file diff --git a/tests/tools/compile/readme.md b/tests/tools/compile/readme.md deleted file mode 100644 index cb5058e02..000000000 --- a/tests/tools/compile/readme.md +++ /dev/null @@ -1 +0,0 @@ -Test whether the tools compile. \ No newline at end of file diff --git a/tests/tools/compile/tdeps.nim b/tests/tools/compile/tdeps.nim deleted file mode 100644 index 971ca1b8e..000000000 --- a/tests/tools/compile/tdeps.nim +++ /dev/null @@ -1,5 +0,0 @@ -discard """ - action: compile -""" - -include tools/deps diff --git a/tests/tools/compile/tdetect.nim b/tests/tools/compile/tdetect.nim deleted file mode 100644 index 253fc0d39..000000000 --- a/tests/tools/compile/tdetect.nim +++ /dev/null @@ -1,5 +0,0 @@ -discard """ - action: compile -""" - -include tools/detect/detect diff --git a/tests/tools/compile/tkoch.nim b/tests/tools/compile/tkoch.nim deleted file mode 100644 index 008721dc0..000000000 --- a/tests/tools/compile/tkoch.nim +++ /dev/null @@ -1,5 +0,0 @@ -discard """ - action: compile -""" - -include koch \ No newline at end of file diff --git a/tests/tools/config.nims b/tests/tools/config.nims deleted file mode 100644 index b4bb92b30..000000000 --- a/tests/tools/config.nims +++ /dev/null @@ -1,2 +0,0 @@ ---d:nimPreviewSlimSystem ---d:nimPreviewCstringConversion \ No newline at end of file diff --git a/tests/tools/second.nim b/tests/tools/second.nim index ee94af25f..0dbe72adb 100644 --- a/tests/tools/second.nim +++ b/tests/tools/second.nim @@ -1,3 +1,3 @@ -import tables - -let dataEx* = {1: 2, 3: 4}.toTable +import tables + +let dataEx* = {1: 2, 3: 4}.toTable diff --git a/tests/tools/tlinter.nim b/tests/tools/tlinter.nim index 16f67905e..a0ed9bfc2 100644 --- a/tests/tools/tlinter.nim +++ b/tests/tools/tlinter.nim @@ -1,13 +1,13 @@ discard """ cmd: '''nim c --styleCheck:hint $file''' nimout: ''' -tlinter.nim(25, 1) Hint: 'tyPE' should be: 'type' [Name] tlinter.nim(21, 14) Hint: 'nosideeffect' should be: 'noSideEffect' [Name] -tlinter.nim(21, 28) Hint: 'myown' should be: 'myOwn' [template declared in tlinter.nim(19, 9)] [Name] +tlinter.nim(21, 28) Hint: 'myown' should be: 'myOwn' [Name] tlinter.nim(21, 35) Hint: 'inLine' should be: 'inline' [Name] -tlinter.nim(23, 1) Hint: 'foO' should be: 'foo' [proc declared in tlinter.nim(21, 6)] [Name] -tlinter.nim(27, 14) Hint: 'Foo_bar' should be: 'FooBar' [type declared in tlinter.nim(25, 6)] [Name] -tlinter.nim(29, 6) Hint: 'someVAR' should be: 'someVar' [var declared in tlinter.nim(27, 5)] [Name] +tlinter.nim(25, 1) Hint: 'tyPE' should be: 'type' [Name] +tlinter.nim(23, 1) Hint: 'foO' should be: 'foo' [Name] +tlinter.nim(27, 14) Hint: 'Foo_bar' should be: 'FooBar' [Name] +tlinter.nim(29, 6) Hint: 'someVAR' should be: 'someVar' [Name] tlinter.nim(32, 7) Hint: 'i_fool' should be: 'iFool' [Name] tlinter.nim(39, 5) Hint: 'meh_field' should be: 'mehField' [Name] ''' diff --git a/tests/tools/tnimgrep.nim b/tests/tools/tnimgrep.nim deleted file mode 100644 index 890a36e79..000000000 --- a/tests/tools/tnimgrep.nim +++ /dev/null @@ -1,404 +0,0 @@ -discard """ - output: ''' - -[Suite] nimgrep filesystem - -[Suite] nimgrep contents filtering -''' -""" -## Authors: quantimnot, a-mr - -import std/[osproc, os, streams, unittest, strutils] - -import std/syncio - -#======= -# setup -#======= - -var process: Process -var ngStdOut, ngStdErr: string -var ngExitCode: int -let previousDir = getCurrentDir() -let tempDir = getTempDir() -let testFilesRoot = tempDir / "nimgrep_test_files" - -template nimgrep(optsAndArgs): untyped = - process = startProcess(previousDir / "bin/nimgrep " & optsAndArgs, - options = {poEvalCommand}) - ngExitCode = process.waitForExit - ngStdOut = process.outputStream.readAll - ngStdErr = process.errorStream.readAll - -func fixSlash(s: string): string = - if DirSep == '/': - result = s - else: # on Windows - result = s.replace('/', DirSep) - -func initString(len = 1000, val = ' '): string = - result = newString(len) - for i in 0.. can't use a template +block t4479: + type + MyTuple = tuple + num: int + strings: seq[string] + ints: seq[int] -static: - main() - mainProc() + var foo = MyTuple(( + num: 7, + strings: @[], + ints: @[], + )) -main() -mainProc() + var bar = ( + num: 7, + strings: @[], + ints: @[], + ).MyTuple + + var fooUnnamed = MyTuple((7, @[], @[])) + var n = 7 + var fooSym = MyTuple((num: n, strings: @[], ints: @[])) + + +block t1910: + var p = newOrderedTable[tuple[a:int], int]() + var q = newOrderedTable[tuple[x:int], int]() + for key in p.keys: + echo key.a + for key in q.keys: + echo key.x + + +block t2121: + type + Item[K,V] = tuple + key: K + value: V + + var q = newseq[Item[int,int]](1) + let (x,y) = q[0] + + +block t2369: + type HashedElem[T] = tuple[num: int, storedVal: ref T] + + proc append[T](tab: var seq[HashedElem[T]], n: int, val: ref T) = + #tab.add((num: n, storedVal: val)) + var he: HashedElem[T] = (num: n, storedVal: val) + #tab.add(he) + + var g: seq[HashedElem[int]] = @[] + + proc foo() = + var x: ref int + new(x) + x[] = 77 + g.append(44, x) + + +block t1986: + proc test(): int64 = + return 0xdeadbeef.int64 + + const items = [ + (var1: test(), var2: 100'u32), + (var1: test(), var2: 192'u32) + ] diff --git a/tests/tuples/tuple_with_nil.nim b/tests/tuples/tuple_with_nil.nim index 9cad6eccd..b3ed2a96b 100644 --- a/tests/tuples/tuple_with_nil.nim +++ b/tests/tuples/tuple_with_nil.nim @@ -1,16 +1,23 @@ import macros +from strutils import IdentStartChars import parseutils import unicode import math +import fenv import pegs import streams type - FormatError = object of CatchableError ## Error in the format string. + FormatError = object of Exception ## Error in the format string. Writer = concept W ## Writer to output a character `c`. - write(W, 'c') + when (NimMajor, NimMinor, NimPatch) > (0, 10, 2): + write(W, 'c') + else: + block: + var x: W + write(x, char) FmtAlign = enum ## Format alignment faDefault ## default for given format type @@ -477,7 +484,7 @@ proc writeformat(o: var Writer; b: bool; fmt: Format) = else: raise newException(FormatError, "Boolean values must of one of the following types: s,b,o,x,X,d,n") -proc writeformat(o: var Writer; ary: openArray[system.any]; fmt: Format) = +proc writeformat(o: var Writer; ary: openarray[system.any]; fmt: Format) = ## Write array `ary` according to format `fmt` using output object ## `o` and output function `add`. if ary.len == 0: return @@ -657,7 +664,7 @@ proc literal[T](x: T): NimNode {.compiletime, nosideeffect.} = result = newLit(x) proc generatefmt(fmtstr: string; - args: var openArray[tuple[arg:NimNode, cnt:int]]; + args: var openarray[tuple[arg:NimNode, cnt:int]]; arg: var int;): seq[tuple[val, fmt:NimNode]] {.compiletime.} = ## fmtstr ## the format string diff --git a/tests/typerel/t4799_1.nim b/tests/typerel/t4799_1.nim index 03d2a0cfa..e66aa1a9a 100644 --- a/tests/typerel/t4799_1.nim +++ b/tests/typerel/t4799_1.nim @@ -1,7 +1,6 @@ discard """ - matrix: "--mm:refc" targets: "c cpp" - outputsub: '''ObjectAssignmentDefect''' + outputsub: '''ObjectAssignmentError''' exitcode: "1" """ diff --git a/tests/typerel/t4799_2.nim b/tests/typerel/t4799_2.nim index ef8571f25..ff20c2426 100644 --- a/tests/typerel/t4799_2.nim +++ b/tests/typerel/t4799_2.nim @@ -1,7 +1,6 @@ discard """ - matrix: "--mm:refc" targets: "c cpp" - outputsub: '''ObjectAssignmentDefect''' + outputsub: '''ObjectAssignmentError''' exitcode: "1" """ diff --git a/tests/typerel/t4799_3.nim b/tests/typerel/t4799_3.nim index 26258b983..4a8a158dd 100644 --- a/tests/typerel/t4799_3.nim +++ b/tests/typerel/t4799_3.nim @@ -1,7 +1,6 @@ discard """ - matrix: "--mm:refc" targets: "c cpp" - outputsub: '''ObjectAssignmentDefect''' + outputsub: '''ObjectAssignmentError''' exitcode: "1" """ diff --git a/tests/typerel/t7600_1.nim b/tests/typerel/t7600_1.nim index 83f93ae7f..e9d01bd0d 100644 --- a/tests/typerel/t7600_1.nim +++ b/tests/typerel/t7600_1.nim @@ -1,6 +1,6 @@ discard """ errormsg: "type mismatch: got " -nimout: '''t7600_1.nim(21, 1) Error: type mismatch: got +nimout: '''t7600_1.nim(21, 6) Error: type mismatch: got but expected one of: proc test[T](x: Paper[T]) first type mismatch at position: 1 diff --git a/tests/typerel/t7600_2.nim b/tests/typerel/t7600_2.nim index 9488a44bc..371707f4c 100644 --- a/tests/typerel/t7600_2.nim +++ b/tests/typerel/t7600_2.nim @@ -1,6 +1,6 @@ discard """ errormsg: "type mismatch: got " -nimout: '''t7600_2.nim(20, 1) Error: type mismatch: got +nimout: '''t7600_2.nim(20, 6) Error: type mismatch: got but expected one of: proc test(x: Paper) first type mismatch at position: 1 diff --git a/tests/typerel/tcommontype.nim b/tests/typerel/tcommontype.nim index f32228177..8215ebd5e 100644 --- a/tests/typerel/tcommontype.nim +++ b/tests/typerel/tcommontype.nim @@ -1,5 +1,5 @@ type - TAnimal{.inheritable.}=object + TAnimal=object {.inheritable.} PAnimal=ref TAnimal TDog=object of TAnimal @@ -12,7 +12,7 @@ type proc newDog():PDog = new(result) proc newCat():PCat = new(result) -proc test(a:openArray[PAnimal])= +proc test(a:openarray[PAnimal])= echo("dummy") #test(newDog(),newCat()) #does not work diff --git a/tests/typerel/texplicitcmp.nim b/tests/typerel/texplicitcmp.nim index 57f1e81b6..b11aa2f4e 100644 --- a/tests/typerel/texplicitcmp.nim +++ b/tests/typerel/texplicitcmp.nim @@ -8,7 +8,7 @@ discard """ import json, tables, algorithm -proc outp(a: openArray[int]) = +proc outp(a: openarray[int]) = stdout.write "[" for i in a: stdout.write($i & " ") stdout.write "]\n" diff --git a/tests/typerel/tint.nim b/tests/typerel/tint.nim deleted file mode 100644 index de0e78a81..000000000 --- a/tests/typerel/tint.nim +++ /dev/null @@ -1,4 +0,0 @@ - -template a(T: type int32) = discard -template a(T: type int64) = discard -a(int) diff --git a/tests/typerel/tnoargopenarray.nim b/tests/typerel/tnoargopenarray.nim new file mode 100644 index 000000000..9e2b2fb86 --- /dev/null +++ b/tests/typerel/tnoargopenarray.nim @@ -0,0 +1,8 @@ +discard """ +action: compile +""" + +import db_sqlite + +var db: DbConn +exec(db, sql"create table blabla()") diff --git a/tests/typerel/tsigmatch.nim b/tests/typerel/tsigmatch.nim deleted file mode 100644 index 7541f2028..000000000 --- a/tests/typerel/tsigmatch.nim +++ /dev/null @@ -1,6 +0,0 @@ -block: # bug #13618 - proc test(x: Natural or BackwardsIndex): int = - int(x) - - doAssert test(^1) == 1 - doAssert test(1) == 1 diff --git a/tests/typerel/tstr_as_openarray.nim b/tests/typerel/tstr_as_openarray.nim index 14cd21479..fc28d6c93 100644 --- a/tests/typerel/tstr_as_openarray.nim +++ b/tests/typerel/tstr_as_openarray.nim @@ -3,18 +3,18 @@ discard """ """ var s = "HI" -proc x (zz: openArray[char]) = +proc x (zz: openarray[char]) = discard x s -proc z [T] (zz: openArray[T]) = +proc z [T] (zz: openarray[T]) = discard z s z([s,s,s]) -proc y [T] (arg: var openArray[T]) = +proc y [T] (arg: var openarray[T]) = arg[0] = 'X' y s doAssert s == "XI" diff --git a/tests/typerel/ttypedesc_as_genericparam1.nim b/tests/typerel/ttypedesc_as_genericparam1.nim index 8fdcf217e..b7c3e727d 100644 --- a/tests/typerel/ttypedesc_as_genericparam1.nim +++ b/tests/typerel/ttypedesc_as_genericparam1.nim @@ -1,7 +1,6 @@ discard """ - matrix: "--mm:refc" - errormsg: "type mismatch: got " - line: 7 + errormsg: "type mismatch: got " + line: 6 """ # bug #3079, #1146 -echo repr(int) \ No newline at end of file +echo repr(int) diff --git a/tests/typerel/ttypedesc_as_genericparam1_orc.nim b/tests/typerel/ttypedesc_as_genericparam1_orc.nim deleted file mode 100644 index d528a7421..000000000 --- a/tests/typerel/ttypedesc_as_genericparam1_orc.nim +++ /dev/null @@ -1,5 +0,0 @@ -discard """ - matrix: "--mm:orc" -""" - -doAssert repr(int) == "int" diff --git a/tests/typerel/ttypedesc_as_genericparam2.nim b/tests/typerel/ttypedesc_as_genericparam2.nim index 882f66584..ea06606f9 100644 --- a/tests/typerel/ttypedesc_as_genericparam2.nim +++ b/tests/typerel/ttypedesc_as_genericparam2.nim @@ -1,7 +1,6 @@ discard """ - matrix: "--mm:refc" errormsg: "'repr' doesn't support 'void' type" - line: 10 + line: 9 """ # bug #2879 diff --git a/tests/typerel/ttypelessemptyset.nim b/tests/typerel/ttypelessemptyset.nim index a4b6f003a..5f49c33fd 100644 --- a/tests/typerel/ttypelessemptyset.nim +++ b/tests/typerel/ttypelessemptyset.nim @@ -1,5 +1,5 @@ discard """ - errormsg: "statement returns no value that can be discarded" + errormsg: "internal error: invalid kind for lastOrd(tyEmpty)" """ var q = false discard (if q: {} else: {}) diff --git a/tests/typerel/ttypenoval.nim b/tests/typerel/ttypenoval.nim index ca6c920ec..c7829f9dd 100644 --- a/tests/typerel/ttypenoval.nim +++ b/tests/typerel/ttypenoval.nim @@ -1,5 +1,5 @@ discard """ - errormsg: "type mismatch: got but expected 'int'" + errormsg: "type mismatch: got but expected 'int'" file: "ttypenoval.nim" line: 38 """ diff --git a/tests/typerel/ttypenovalue.nim b/tests/typerel/ttypenovalue.nim index 4664253ea..b86baf8b4 100644 --- a/tests/typerel/ttypenovalue.nim +++ b/tests/typerel/ttypenovalue.nim @@ -1,6 +1,7 @@ discard """ - errormsg: "invalid type: 'typedesc[seq[tuple[title: string, body: string]]]' for var" + errormsg: "value expected, but got a type" line: 7 + disabled: true """ proc crashAndBurn() = diff --git a/tests/typerel/tvoid.nim b/tests/typerel/tvoid.nim index 8bb5691b8..1e46d016e 100644 --- a/tests/typerel/tvoid.nim +++ b/tests/typerel/tvoid.nim @@ -35,64 +35,3 @@ ReturnT[void]() echo ReturnT[string]("abc") nothing() -block: # typeof(stmt) - proc fn1(): auto = - discard - proc fn2(): auto = - 1 - doAssert type(fn1()) is void - doAssert typeof(fn1()) is void - doAssert typeof(fn1()) isnot int - - doAssert type(fn2()) isnot void - doAssert typeof(fn2()) isnot void - when typeof(fn1()) is void: discard - else: doAssert false - - doAssert typeof(1+1) is int - doAssert typeof((discard)) is void - - type A1 = typeof(fn1()) - doAssert A1 is void - type A2 = type(fn1()) - doAssert A2 is void - doAssert A2 is A1 - - when false: - # xxx: MCS/UFCS doesn't work here: Error: expression 'fn1()' has no type (or is ambiguous) - type A3 = fn1().type - proc bar[T](a: T): string = $T - doAssert bar(1) == "int" - doAssert bar(fn1()) == "void" - - proc bar2[T](a: T): bool = T is void - doAssert not bar2(1) - doAssert bar2(fn1()) - - block: - proc bar3[T](a: T): T = a - let a1 = bar3(1) - doAssert compiles(block: - let a1 = bar3(fn2())) - doAssert not compiles(block: - let a2 = bar3(fn1())) - doAssert compiles(block: bar3(fn1())) - doAssert compiles(bar3(fn1())) - doAssert typeof(bar3(fn1())) is void - doAssert not compiles(sizeof(bar3(fn1()))) - - block: - var a = 1 - doAssert typeof((a = 2)) is void - doAssert typeof((a = 2; a = 3)) is void - doAssert typeof(block: - a = 2; a = 3) is void - - block: - var a = 1 - template bad1 = echo (a; a = 2) - doAssert not compiles(bad1()) - - block: - template bad2 = echo (nonexistent; discard) - doAssert not compiles(bad2()) diff --git a/tests/typerel/typedescs2.nim b/tests/typerel/typedescs2.nim index a0308719d..43cd48ca6 100644 --- a/tests/typerel/typedescs2.nim +++ b/tests/typerel/typedescs2.nim @@ -1,10 +1,10 @@ discard """ - errormsg: "invalid type: 'typedesc[Table]' for const" + errormsg: "'typedesc' metatype is not valid here; typed '=' instead of ':'?" file: "typedescs2.nim" line: 16 """ -# bug #9961 +# issue #9961 import typetraits import tables diff --git a/tests/types/t14127_cast_number.nim b/tests/types/t14127_cast_number.nim deleted file mode 100644 index 4bb23f22f..000000000 --- a/tests/types/t14127_cast_number.nim +++ /dev/null @@ -1,30 +0,0 @@ -discard """ - targets: "c cpp js" -""" -block: # bug #14127 - template int2uint(T) = - var a = -1 - let b = cast[T](a) - doAssert b < 0 - let c = b + 1 - doAssert c is T - doAssert c == 0 - - int2uint(int8) - int2uint(int16) - int2uint(int32) - int2uint(int64) - -block: # maybe related - template uint2int(T) = - var a = 3 - let b = cast[T](a) - doAssert b > 0 - let c = b - 1 - doAssert c is T - doAssert c == 2 - - uint2int(uint8) - uint2int(uint16) - uint2int(uint32) - uint2int(uint64) diff --git a/tests/types/t15836.nim b/tests/types/t15836.nim deleted file mode 100644 index 9c0c26dec..000000000 --- a/tests/types/t15836.nim +++ /dev/null @@ -1,11 +0,0 @@ -discard """ - errormsg: "type mismatch: got but expected 'int'" - line: 11 -""" - -proc takesProc[T](x: T, f: proc(x: T): int) = - echo f(x) + 2 - -takesProc(1, proc (a: int): int = 2) # ok, prints 4 -takesProc(1, proc (a: auto): auto = 2) # ok, prints 4 -takesProc(1, proc (a: auto): auto = "uh uh") # prints garbage diff --git a/tests/types/t15836_2.nim b/tests/types/t15836_2.nim deleted file mode 100644 index 9afef416a..000000000 --- a/tests/types/t15836_2.nim +++ /dev/null @@ -1,26 +0,0 @@ - -discard """ - action: "compile" - disabled: true -""" -import std/sugar - -type Tensor[T] = object - x: T - -proc numerical_gradient*[T](input: T, f: (proc(x: T): T), h = T(1e-5)): T {.inline.} = - result = default(T) - -proc numerical_gradient*[T](input: Tensor[T], f: (proc(x: Tensor[T]): T), h = T(1e-5)): Tensor[T] {.noinit.} = - result = default(Tensor[T]) - -proc conv2d*[T](input: Tensor[T]): Tensor[T] {.inline.} = - result = default(Tensor[T]) - -proc sum*[T](arg: Tensor[T]): T = default(T) - -proc sum*[T](arg: Tensor[T], axis: int): Tensor[T] {.noinit.} = default(Tensor[T]) - -let dinput = Tensor[int](x: 1) -let target_grad_input = dinput.numerical_gradient( - x => conv2d(x).sum()) diff --git a/tests/types/t21027.nim b/tests/types/t21027.nim deleted file mode 100644 index 3a992177a..000000000 --- a/tests/types/t21027.nim +++ /dev/null @@ -1,5 +0,0 @@ -discard """ - errormsg: "Invalid usage of cast, cast requires a type to convert to, e.g., cast[int](0d)." -""" -# bug #21027 -let x: uint64 = cast(5) diff --git a/tests/types/t21260.nim b/tests/types/t21260.nim deleted file mode 100644 index 90d6613c1..000000000 --- a/tests/types/t21260.nim +++ /dev/null @@ -1,13 +0,0 @@ -discard """ - errormsg: "illegal recursion in type 'Foo'" - line: 8 -""" - -type - Kind = enum kA, kB - Foo = object - case k: Kind: - of kA: - foo: Foo - of kB: - discard diff --git a/tests/types/tcast1.nim b/tests/types/tcast1.nim index ab375b8b2..10e876ded 100644 --- a/tests/types/tcast1.nim +++ b/tests/types/tcast1.nim @@ -19,45 +19,3 @@ proc remap2[T](s: seq[int], typ: typedesc[T]): seq[T] = echo remap1(@[1,2,3], float) echo remap2(@[1,2,3], float) - - -#-------------------------------------------------------------------- -# conversion to bool, issue #13744 -proc test_conv_to_bool = - var - i0 = 0 - i1 = 1 - ih = high(uint) - il = low(int) - - f0 = 0.0 - f1 = 1.0 - fh = Inf - fl = -Inf - f_nan = NaN - - doAssert(bool(i0) == false) - doAssert(bool(i1) == true) - doAssert(bool(-i1) == true) - doAssert(bool(il) == true) - doAssert(bool(ih) == true) - - doAssert(bool(f0) == false) - doAssert(bool(-f0) == false) - doAssert(bool(f1) == true) - doAssert(bool(-f1) == true) - doAssert(bool(fh) == true) - doAssert(bool(fl) == true) - doAssert(bool(fnan) == true) # NaN to bool gives true according to standard - - -static: - doAssert(bool(0) == false) - doAssert(bool(-1) == true) - doAssert(bool(2) == true) - doAssert(bool(NaN) == true) - doAssert(bool(0.0) == false) - doAssert(bool(-0.0) == false) - test_conv_to_bool() -test_conv_to_bool() - diff --git a/tests/types/temptyseqs.nim b/tests/types/temptyseqs.nim index 6e7b58ced..28c3b87b8 100644 --- a/tests/types/temptyseqs.nim +++ b/tests/types/temptyseqs.nim @@ -75,16 +75,16 @@ varargso("foo", "bar", "baz") type Flago = enum - tfRequiresInit, tfNotNil + tfNeedsInit, tfNotNil -var s: set[Flago] = {tfRequiresInit} +var s: set[Flago] = {tfNeedsInit} -if {tfRequiresInit, tfNotNil} * s != {}: +if {tfNeedsInit, tfNotNil} * s != {}: echo "yes" else: echo "no" -if {tfRequiresInit, tfNotNil} * s <= {tfNotNil}: +if {tfNeedsInit, tfNotNil} * s <= {tfNotNil}: echo "yes" else: echo "no" diff --git a/tests/types/tfinalobj.nim b/tests/types/tfinalobj.nim index ad3085132..94f2e4f0e 100644 --- a/tests/types/tfinalobj.nim +++ b/tests/types/tfinalobj.nim @@ -3,7 +3,7 @@ discard """ """ type - TA {.pure, final.} = object + TA = object {.pure, final.} x: string var diff --git a/tests/types/tillegalseqrecursion.nim b/tests/types/tillegalseqrecursion.nim deleted file mode 100644 index 9221bb38a..000000000 --- a/tests/types/tillegalseqrecursion.nim +++ /dev/null @@ -1,6 +0,0 @@ -discard """ - errormsg: "illegal recursion in type 'CyclicSeq'" -""" -# issue #13715 -type - CyclicSeq = seq[ref CyclicSeq] diff --git a/tests/types/tillegaltuplerecursion.nim b/tests/types/tillegaltuplerecursion.nim index cb75ad9c3..c822e8880 100644 --- a/tests/types/tillegaltuplerecursion.nim +++ b/tests/types/tillegaltuplerecursion.nim @@ -35,6 +35,4 @@ type children: ptr MyType9 MyType9 = tuple - children: MyType10 - - MyType10 = distinct seq[MyType0] + children: MyType0 diff --git a/tests/types/tillegaltyperecursion.nim b/tests/types/tillegaltyperecursion.nim index 372615c4d..4c53a8b0e 100644 --- a/tests/types/tillegaltyperecursion.nim +++ b/tests/types/tillegaltyperecursion.nim @@ -1,17 +1,66 @@ discard """ cmd: "nim $target --threads:on $options $file" errormsg: "illegal recursion in type 'TIRC'" - line: 12 + line: 16 """ +import events import net import strutils import os type + TMessageReceivedEventArgs = object of EventArgs + Nick*: string + Message*: string TIRC = object + EventEmitter: EventEmitter + MessageReceivedHandler*: EventHandler Socket: Socket Thread: Thread[TIRC] proc initIRC*(): TIRC = result.Socket = socket() + result.EventEmitter = initEventEmitter() + result.MessageReceivedHandler = initEventHandler("MessageReceived") + +proc IsConnected*(irc: var TIRC): bool = + return running(irc.Thread) + + +proc sendRaw*(irc: var TIRC, message: string) = + irc.Socket.send(message & "\r\L") +proc handleData(irc: TIRC) {.thread.} = + var connected = False + while connected: + var tup = @[irc.Socket] + var o = select(tup, 200) + echo($o) + echo($len(tup)) + if len(tup) == 1: + #Connected + connected = True + + #Parse data here + + else: + #Disconnected + connected = False + return + +proc Connect*(irc: var TIRC, nick: string, host: string, port: int = 6667) = + connect(irc.Socket, host, TPort(port), TDomain.AF_INET) + send(irc.Socket,"USER " & nick & " " & nick & " " & nick & " " & nick & "\r\L") + send(irc.Socket,"NICK " & nick & "\r\L") + var thread: Thread[TIRC] + createThread(thread, handleData, irc) + irc.Thread = thread + + + + +when true: + var irc = initIRC() + irc.Connect("AmryBot[Nim]","irc.freenode.net",6667) + irc.sendRaw("JOIN #nim") + os.Sleep(4000) diff --git a/tests/types/tinheritref.nim b/tests/types/tinheritref.nim index b79926356..01f2307c0 100644 --- a/tests/types/tinheritref.nim +++ b/tests/types/tinheritref.nim @@ -11,11 +11,11 @@ ob = T[int](elem: 23) doAssert ob.elem == 23 type - TTreeIteratorA* {.inheritable.} = ref object + TTreeIteratorA* = ref object {.inheritable.} TKeysIteratorA* = ref object of TTreeIteratorA #compiles - TTreeIterator* [T,D] {.inheritable.} = ref object + TTreeIterator* [T,D] = ref object {.inheritable.} TKeysIterator* [T,D] = ref object of TTreeIterator[T,D] #this not diff --git a/tests/types/tisop.nim b/tests/types/tisop.nim index 5f9cba0d8..ad5928016 100644 --- a/tests/types/tisop.nim +++ b/tests/types/tisop.nim @@ -27,22 +27,22 @@ macro m(t: typedesc): typedesc = result = int var f: TFoo[int, int] -static: doAssert(f.y.type.name == "string") +static: assert(f.y.type.name == "string") when compiles(f.z): {.error: "Foo should not have a `z` field".} proc p(a, b: auto) = when a.type is int: - static: doAssert false + static: assert false var f: TFoo[m(a.type), b.type] static: - doAssert f.x.type.name == "int" + assert f.x.type.name == "int" echo f.y.type.name - doAssert f.y.type.name == "float" + assert f.y.type.name == "float" echo f.z.type.name - doAssert f.z.type.name == "float" + assert f.z.type.name == "float" p(A, f) diff --git a/tests/types/tisopr.nim b/tests/types/tisopr.nim index 67f1ce0c1..1bbd0da94 100644 --- a/tests/types/tisopr.nim +++ b/tests/types/tisopr.nim @@ -109,29 +109,3 @@ block: doAssert Foo2[int,float|int] is Foo doAssert Foo2[int,float|int] isnot Bar doAssert int is (int|float) - - -block: - # Slice[T] as static type issue - type - MyEnum = enum - x1, x2, x3, x4, x5, x6 - - proc enumGen[T: enum](s: static[Slice[T]]) = - doAssert($s.a & " " & $s.b == "x1 x3") - - enumGen(x1..x3) - -block: - # issue #11142 - type - MyObjParam[N: static int] = object - x: int - - MyObj[P: static MyObjParam] = object - y: int - - const P = MyObjParam[256](x: 2) - let Q = MyObj[P](y: 2) - doAssert($Q == "(y: 2)") - diff --git a/tests/types/tissues_types.nim b/tests/types/tissues_types.nim index 7ed0547bf..e5039fa61 100644 --- a/tests/types/tissues_types.nim +++ b/tests/types/tissues_types.nim @@ -8,8 +8,6 @@ ptr Foo (member: 123.456) (member: "hello world", x: ...) (member: 123.456, x: ...) -0 -false ''' joinable: false """ @@ -80,31 +78,3 @@ block t7905: foobarRec("hello world") foobarRec(123.456'f64) - -# bug #5170 - -when true: - type Foo = object - bar: bool - - type Bar = object - sameBody: string - - var b0: Bar - b0.sameBody = "abc" - -block: - type Foo = object - baz: int - - type Bar = object - sameBody: string - - var b1: Bar - b1.sameBody = "def" - - var f2: Foo - echo f2.baz - -var f1: Foo -echo f1.bar diff --git a/tests/types/titerable.nim b/tests/types/titerable.nim deleted file mode 100644 index fe27de4fd..000000000 --- a/tests/types/titerable.nim +++ /dev/null @@ -1,143 +0,0 @@ -discard """ - targets: "c js" -""" - -from stdtest/testutils import accept, reject, whenVMorJs - -# toSeq-like templates - -template toSeq2(a: iterable): auto = - var ret: seq[typeof(a)] - for ai in a: ret.add ai - ret - -template toSeq3(a: iterable[string]): auto = - var ret: seq[typeof(a)] - for ai in a: ret.add ai - ret - -template toSeq4[T](a: iterable[T]): auto = - var ret: seq[typeof(a)] - for ai in a: ret.add ai - ret - -template toSeq5[T: SomeInteger](a: iterable[T]): auto = - var ret: seq[typeof(a)] - for ai in a: ret.add ai - ret - -template toSeq6(a: iterable[int | float]): auto = - var ret: seq[typeof(a)] - for ai in a: ret.add ai - ret - -template toSeq7(a: iterable[seq]): auto = - var ret: seq[typeof(a)] - for ai in a: ret.add ai - ret - -template fn7b(a: untyped) = discard -template fn7c(a: typed) = discard -template fn7d(a: auto) = discard -template fn7e[T](a: T) = discard - -template fn8a(a: iterable) = discard -template fn8b[T](a: iterable[T]) = discard -template fn8c(a: iterable[int]) = discard - -template bad1 = - template fn4(a: int, b: iterable[float, int]) = - discard - -template bad2 = - proc fn4(a: iterable) = discard - -template bad3 = - proc fn4(a: iterable[int]) = discard - -template good4 = - template fn1(a: iterable) = discard - template fn2(a: iterable[int]) = discard - -# iterators -iterator iota(n: int): auto = - for i in 0..= 10: - a: int diff --git a/tests/untestable/gdb/gdb_pretty_printer_test.py b/tests/untestable/gdb/gdb_pretty_printer_test.py index aed0cfeb0..f002941ec 100644 --- a/tests/untestable/gdb/gdb_pretty_printer_test.py +++ b/tests/untestable/gdb/gdb_pretty_printer_test.py @@ -1,64 +1,36 @@ import gdb -import re -import sys # this test should test the gdb pretty printers of the nim # library. But be aware this test is not complete. It only tests the # command line version of gdb. It does not test anything for the # machine interface of gdb. This means if if this test passes gdb # frontends might still be broken. -gdb.execute("set python print-stack full") -gdb.execute("source ../../../tools/debug/nim-gdb.py") -# debug all instances of the generic function `myDebug`, should be 14 +gdb.execute("source ../../../tools/nim-gdb.py") +# debug all instances of the generic function `myDebug`, should be 8 gdb.execute("rbreak myDebug") gdb.execute("run") outputs = [ 'meTwo', - '""', '"meTwo"', '{meOne, meThree}', 'MyOtherEnum(1)', - '{MyOtherEnum(0), MyOtherEnum(2)}', + '5', 'array = {1, 2, 3, 4, 5}', - 'seq(0, 0)', - 'seq(0, 10)', - 'array = {"one", "two"}', - 'seq(3, 3) = {1, 2, 3}', 'seq(3, 3) = {"one", "two", "three"}', - 'Table(3, 64) = {[4] = "four", [5] = "five", [6] = "six"}', - 'Table(3, 8) = {["two"] = 2, ["three"] = 3, ["one"] = 1}', - '{a = 1, b = "some string"}', - '("hello", 42)' + 'Table(3, 64) = {["two"] = 2, ["three"] = 3, ["one"] = 1}', ] -argRegex = re.compile("^.* = (?:No suitable Nim \$ operator found for type: \w+\s*)*(.*)$") -# Remove this error message which can pop up -noSuitableRegex = re.compile("(No suitable Nim \$ operator found for type: \w+\s*)") - for i, expected in enumerate(outputs): - gdb.write(f"\x1b[38;5;105m{i+1}) expecting: {expected}: \x1b[0m", gdb.STDLOG) - gdb.flush() - currFrame = gdb.selected_frame() - functionSymbol = currFrame.block().function - assert functionSymbol.line == 24, str(functionSymbol.line) - raw = "" - if i == 6: + functionSymbol = gdb.selected_frame().block().function + assert functionSymbol.line == 21 + + if i == 5: # myArray is passed as pointer to int to myDebug. I look up myArray up in the stack gdb.execute("up") - raw = gdb.parse_and_eval("myArray") - elif i == 9: - # myOtherArray is passed as pointer to int to myDebug. I look up myOtherArray up in the stack - gdb.execute("up") - raw = gdb.parse_and_eval("myOtherArray") + output = str(gdb.parse_and_eval("myArray")) else: - rawArg = re.sub(noSuitableRegex, "", gdb.execute("info args", to_string = True)) - raw = rawArg.split("=", 1)[-1].strip() - output = str(raw) + output = str(gdb.parse_and_eval("arg")) - if output != expected: - gdb.write(f"\x1b[38;5;196m ({output}) != expected: ({expected})\x1b[0m\n", gdb.STDERR) - gdb.execute("quit 1") - else: - gdb.write("\x1b[38;5;34mpassed\x1b[0m\n", gdb.STDLOG) + assert output == expected, output + " != " + expected gdb.execute("continue") diff --git a/tests/untestable/gdb/gdb_pretty_printer_test_output.txt b/tests/untestable/gdb/gdb_pretty_printer_test_output.txt new file mode 100644 index 000000000..73d26016f --- /dev/null +++ b/tests/untestable/gdb/gdb_pretty_printer_test_output.txt @@ -0,0 +1,3 @@ +Loading Nim Runtime support. +NimEnumPrinter: lookup global symbol 'NTI__z9cu80OJCfNgw9bUdzn5ZEzw_ failed for tyEnum_MyOtherEnum__z9cu80OJCfNgw9bUdzn5ZEzw. +8 diff --git a/tests/untestable/gdb/gdb_pretty_printer_test_program.nim b/tests/untestable/gdb/gdb_pretty_printer_test_program.nim index 163c99860..458435c1a 100644 --- a/tests/untestable/gdb/gdb_pretty_printer_test_program.nim +++ b/tests/untestable/gdb/gdb_pretty_printer_test_program.nim @@ -14,10 +14,7 @@ type moTwo, moThree, moFoure, - - MyObj = object - a*: int - b*: string + var counter = 0 @@ -26,64 +23,31 @@ proc myDebug[T](arg: T): void = proc testProc(): void = var myEnum = meTwo - myDebug(myEnum) #1 - - # create a string, but don't allocate it - var myString: string - myDebug(myString) #2 - + myDebug(myEnum) # create a string object but also make the NTI for MyEnum is generated - myString = $myEnum - myDebug(myString) #3 - + var myString = $myEnum + myDebug(myString) var mySet = {meOne,meThree} - myDebug(mySet) #4 + myDebug(mySet) # for MyOtherEnum there is no NTI. This tests the fallback for the pretty printer. var moEnum = moTwo - myDebug(moEnum) #5 - + myDebug(moEnum) var moSet = {moOne,moThree} - myDebug(moSet) #6 + myDebug(moSet) let myArray = [1,2,3,4,5] - myDebug(myArray) #7 + myDebug(myArray) + let mySeq = @["one","two","three"] + myDebug(mySeq) - # implicitly initialized seq test - var mySeq: seq[string] - myDebug(mySeq) #8 + var myTable = initTable[string, int]() + myTable["one"] = 1 + myTable["two"] = 2 + myTable["three"] = 3 + myDebug(myTable) - # len not equal to capacity - let myOtherSeq = newSeqOfCap[string](10) - myDebug(myOtherSeq) #9 - - let myOtherArray = ["one","two"] - myDebug(myOtherArray) #10 - - # numeric sec - var mySeq3 = @[1,2,3] - myDebug(mySeq3) #11 - - # seq had to grow - var mySeq4 = @["one","two","three"] - myDebug(mySeq4) #12 - - var myTable = initTable[int, string]() - myTable[4] = "four" - myTable[5] = "five" - myTable[6] = "six" - myDebug(myTable) #13 - - var myOtherTable = {"one": 1, "two": 2, "three": 3}.toTable - myDebug(myOtherTable) #14 - - var obj = MyObj(a: 1, b: "some string") - myDebug(obj) #15 - - var tup = ("hello", 42) - myDebug(tup) # 16 - - assert counter == 16 + echo(counter) testProc() diff --git a/tests/untestable/gdb/gdb_pretty_printer_test_run.sh b/tests/untestable/gdb/gdb_pretty_printer_test_run.sh old mode 100755 new mode 100644 index 411c68435..525f54705 --- a/tests/untestable/gdb/gdb_pretty_printer_test_run.sh +++ b/tests/untestable/gdb/gdb_pretty_printer_test_run.sh @@ -1,13 +1,15 @@ #!/usr/bin/env bash +# Exit if anything fails set -e +#!/usr/bin/env bash # Compile the test project with fresh debug information. -nim c --debugger:native --mm:orc --out:gdbNew gdb_pretty_printer_test_program.nim -echo "Running new runtime tests..." +nim c --debugger:native gdb_pretty_printer_test_program.nim &> /dev/null # 2>&1 redirects stderr to stdout (all output in stdout) -gdb -x gdb_pretty_printer_test.py --batch-silent --args gdbNew 2>&1 - - -# Do it all again, but with old runtime -nim c --debugger:native --mm:refc --out:gdbOld gdb_pretty_printer_test_program.nim &> /dev/null -echo "Running old runtime tests" -gdb -x gdb_pretty_printer_test.py --batch-silent --args gdbOld 2>&1 +# <(...) is a bash feature that makes the output of a command into a +# file handle. +# diff compares the two files, the expected output, and the file +# handle that is created by the execution of gdb. +diff ./gdb_pretty_printer_test_output.txt <(gdb -x gdb_pretty_printer_test.py --batch-silent --args gdb_pretty_printer_test_program 2>&1) +# The exit code of diff is forwarded as the exit code of this +# script. So when the comparison fails, the exit code of this script +# won't be 0. So this script should be embeddable in a test suite. diff --git a/tests/untestable/thttpclient_ssl_disabled.nim b/tests/untestable/thttpclient_ssl_disabled.nim deleted file mode 100644 index b95dad2c6..000000000 --- a/tests/untestable/thttpclient_ssl_disabled.nim +++ /dev/null @@ -1,36 +0,0 @@ -# -# Nim - SSL integration tests -# (c) Copyright 2017 Nim contributors -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# -## Compile and run with: -## nim r --putenv:NIM_TESTAMENT_REMOTE_NETWORKING:1 -d:nimDisableCertificateValidation -d:ssl -p:. tests/untestable/thttpclient_ssl_disabled.nim - -from stdtest/testutils import enableRemoteNetworking -when enableRemoteNetworking and (defined(nimTestsEnableFlaky) or not defined(openbsd)): - import httpclient, net, unittest - - const expired = "https://expired.badssl.com/" - - doAssert defined(nimDisableCertificateValidation) - - suite "SSL certificate check - disabled": - - test "httpclient in insecure mode": - var ctx = newContext(verifyMode = CVerifyPeer) - var client = newHttpClient(sslContext = ctx) - let a = $client.getContent(expired) - - test "httpclient in insecure mode": - var ctx = newContext(verifyMode = CVerifyPeerUseEnvVars) - var client = newHttpClient(sslContext = ctx) - let a = $client.getContent(expired) - - test "net socket in insecure mode": - var sock = newSocket() - var ctx = newContext(verifyMode = CVerifyPeerUseEnvVars) - ctx.wrapSocket(sock) - sock.connect("expired.badssl.com", 443.Port) - sock.close diff --git a/tests/untestable/thttpclient_ssl_env_var.nim b/tests/untestable/thttpclient_ssl_env_var.nim deleted file mode 100644 index 3f25a6ff4..000000000 --- a/tests/untestable/thttpclient_ssl_env_var.nim +++ /dev/null @@ -1,74 +0,0 @@ -# -# Nim - SSL integration tests -# (c) Copyright 2017 Nim contributors -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# -## Warning: this test performs external networking. -## Compile with: -## ./bin/nim c -d:ssl -p:. tests/untestable/thttpclient_ssl_env_var.nim -## -## Test with: -## SSL_CERT_FILE=BogusInexistentFileName tests/untestable/thttpclient_ssl_env_var -## SSL_CERT_DIR=BogusInexistentDirName tests/untestable/thttpclient_ssl_env_var - -import httpclient, unittest, os -from net import newSocket, newContext, wrapSocket, connect, close, Port, - CVerifyPeerUseEnvVars -from strutils import contains - -const - expired = "https://expired.badssl.com/" - good = "https://google.com/" - - -suite "SSL certificate check": - - test "httpclient with inexistent file": - if existsEnv("SSL_CERT_FILE"): - var ctx = newContext(verifyMode=CVerifyPeerUseEnvVars) - var client = newHttpClient(sslContext=ctx) - checkpoint("Client created") - check client.getContent("https://google.com").contains("doctype") - checkpoint("Google ok") - try: - let a = $client.getContent(good) - echo "Connection should have failed" - fail() - except: - echo getCurrentExceptionMsg() - check getCurrentExceptionMsg().contains("certificate verify failed") - - elif existsEnv("SSL_CERT_DIR"): - try: - var ctx = newContext(verifyMode=CVerifyPeerUseEnvVars) - var client = newHttpClient(sslContext=ctx) - echo "Should have raised 'No SSL/TLS CA certificates found.'" - fail() - except: - check getCurrentExceptionMsg() == - "No SSL/TLS CA certificates found." - - test "net socket with inexistent file": - if existsEnv("SSL_CERT_FILE"): - var sock = newSocket() - var ctx = newContext(verifyMode=CVerifyPeerUseEnvVars) - ctx.wrapSocket(sock) - checkpoint("Socket created") - try: - sock.connect("expired.badssl.com", 443.Port) - fail() - except: - sock.close - check getCurrentExceptionMsg().contains("certificate verify failed") - - elif existsEnv("SSL_CERT_DIR"): - var sock = newSocket() - checkpoint("Socket created") - try: - var ctx = newContext(verifyMode=CVerifyPeerUseEnvVars) # raises here - fail() - except: - check getCurrentExceptionMsg() == - "No SSL/TLS CA certificates found." diff --git a/tests/untestable/thttpclient_ssl_remotenetwork.nim b/tests/untestable/thttpclient_ssl_remotenetwork.nim deleted file mode 100644 index d2366d9a9..000000000 --- a/tests/untestable/thttpclient_ssl_remotenetwork.nim +++ /dev/null @@ -1,218 +0,0 @@ -# -# -# Nim - SSL integration tests -# (c) Copyright 2017 Nim contributors -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# -## Test with: -## nim r --putenv:NIM_TESTAMENT_REMOTE_NETWORKING:1 -d:ssl -p:. --threads:on tests/untestable/thttpclient_ssl_remotenetwork.nim -## -## See https://github.com/FedericoCeratto/ssl-comparison/blob/master/README.md -## for a comparison with other clients. - -from stdtest/testutils import enableRemoteNetworking -when enableRemoteNetworking and (defined(nimTestsEnableFlaky) or not defined(windows) and not defined(openbsd)): - # Not supported on Windows due to old openssl version - import - httpclient, - net, - strutils, - threadpool, - unittest - - - type - # bad and dubious tests should not pass SSL validation - # "_broken" mark the test as skipped. Some tests have different - # behavior depending on OS and SSL version! - # TODO: chase and fix the broken tests - Category = enum - good, bad, dubious, good_broken, bad_broken, dubious_broken - CertTest = tuple[url:string, category:Category, desc: string] - - const certificate_tests: array[0..54, CertTest] = [ - ("https://wrong.host.badssl.com/", bad, "wrong.host"), - ("https://captive-portal.badssl.com/", bad, "captive-portal"), - ("https://expired.badssl.com/", bad, "expired"), - ("https://google.com/", good, "good"), - ("https://self-signed.badssl.com/", bad, "self-signed"), - ("https://untrusted-root.badssl.com/", bad, "untrusted-root"), - ("https://revoked.badssl.com/", bad_broken, "revoked"), - ("https://pinning-test.badssl.com/", bad_broken, "pinning-test"), - ("https://no-common-name.badssl.com/", bad, "no-common-name"), - ("https://no-subject.badssl.com/", bad, "no-subject"), - ("https://sha1-intermediate.badssl.com/", bad, "sha1-intermediate"), - ("https://sha256.badssl.com/", good, "sha256"), - ("https://sha384.badssl.com/", bad, "sha384"), - ("https://sha512.badssl.com/", bad, "sha512"), - ("https://1000-sans.badssl.com/", bad, "1000-sans"), - ("https://10000-sans.badssl.com/", good_broken, "10000-sans"), - ("https://ecc256.badssl.com/", good_broken, "ecc256"), - ("https://ecc384.badssl.com/", good_broken, "ecc384"), - ("https://rsa2048.badssl.com/", good, "rsa2048"), - ("https://rsa8192.badssl.com/", dubious_broken, "rsa8192"), - ("http://http.badssl.com/", good, "regular http"), - ("https://http.badssl.com/", bad_broken, "http on https URL"), # FIXME - ("https://cbc.badssl.com/", dubious, "cbc"), - ("https://rc4-md5.badssl.com/", bad, "rc4-md5"), - ("https://rc4.badssl.com/", bad, "rc4"), - ("https://3des.badssl.com/", bad, "3des"), - ("https://null.badssl.com/", bad, "null"), - ("https://mozilla-old.badssl.com/", bad_broken, "mozilla-old"), - ("https://mozilla-intermediate.badssl.com/", dubious_broken, "mozilla-intermediate"), - ("https://mozilla-modern.badssl.com/", good, "mozilla-modern"), - ("https://dh480.badssl.com/", bad, "dh480"), - ("https://dh512.badssl.com/", bad, "dh512"), - ("https://dh1024.badssl.com/", dubious_broken, "dh1024"), - ("https://dh2048.badssl.com/", good, "dh2048"), - ("https://dh-small-subgroup.badssl.com/", bad_broken, "dh-small-subgroup"), - ("https://dh-composite.badssl.com/", bad_broken, "dh-composite"), - ("https://static-rsa.badssl.com/", dubious, "static-rsa"), - ("https://tls-v1-0.badssl.com:1010/", dubious, "tls-v1-0"), - ("https://tls-v1-1.badssl.com:1011/", dubious, "tls-v1-1"), - ("https://invalid-expected-sct.badssl.com/", bad, "invalid-expected-sct"), - ("https://hsts.badssl.com/", good, "hsts"), - ("https://upgrade.badssl.com/", good, "upgrade"), - ("https://preloaded-hsts.badssl.com/", good, "preloaded-hsts"), - ("https://subdomain.preloaded-hsts.badssl.com/", bad, "subdomain.preloaded-hsts"), - ("https://https-everywhere.badssl.com/", good, "https-everywhere"), - ("https://long-extended-subdomain-name-containing-many-letters-and-dashes.badssl.com/", good, - "long-extended-subdomain-name-containing-many-letters-and-dashes"), - ("https://longextendedsubdomainnamewithoutdashesinordertotestwordwrapping.badssl.com/", good, - "longextendedsubdomainnamewithoutdashesinordertotestwordwrapping"), - ("https://superfish.badssl.com/", bad, "(Lenovo) Superfish"), - ("https://edellroot.badssl.com/", bad, "(Dell) eDellRoot"), - ("https://dsdtestprovider.badssl.com/", bad, "(Dell) DSD Test Provider"), - ("https://preact-cli.badssl.com/", bad, "preact-cli"), - ("https://webpack-dev-server.badssl.com/", bad, "webpack-dev-server"), - ("https://mitm-software.badssl.com/", bad, "mitm-software"), - ("https://sha1-2016.badssl.com/", dubious, "sha1-2016"), - ("https://sha1-2017.badssl.com/", bad, "sha1-2017"), - ] - - - template evaluate(exception_msg: string, category: Category, desc: string) = - # Evaluate test outcome. Tests flagged as `_broken` are evaluated and skipped - let raised = (exception_msg.len > 0) - let should_not_raise = category in {good, dubious_broken, bad_broken} - if should_not_raise xor raised: - # we are seeing a known behavior - if category in {good_broken, dubious_broken, bad_broken}: - skip() - if raised: - # check exception_msg == "No SSL certificate found." or - doAssert exception_msg == "No SSL certificate found." or - exception_msg == "SSL Certificate check failed." or - exception_msg.contains("certificate verify failed") or - exception_msg.contains("key too small") or - exception_msg.contains("alert handshake failure") or - exception_msg.contains("bad dh p length") or - # TODO: This one should only triggers for 10000-sans - exception_msg.contains("excessive message size"), exception_msg - - else: - # this is unexpected - var fatal = true - var msg = "" - if raised: - msg = " $# ($#) raised: $#" % [desc, $category, exception_msg] - if "500 Internal Server Error" in exception_msg: - # refs https://github.com/nim-lang/Nim/issues/16338#issuecomment-804300278 - # we got: `good (good) raised: 500 Internal Server Error` - fatal = false - msg.add " (http 500 => assuming this is not our problem)" - else: - msg = " $# ($#) did not raise" % [desc, $category] - - if category in {good, dubious, bad} and fatal: - echo "D20210322T121353: error: " & msg - fail() - else: - echo "D20210322T121353: warning: " & msg - - - suite "SSL certificate check - httpclient": - - for i, ct in certificate_tests: - - test ct.desc: - var ctx = newContext(verifyMode=CVerifyPeer) - var client = newHttpClient(sslContext=ctx) - let exception_msg = - try: - let a = $client.getContent(ct.url) - "" - except: - getCurrentExceptionMsg() - - evaluate(exception_msg, ct.category, ct.desc) - - - - # threaded tests - - - type - TTOutcome = ref object - desc, exception_msg: string - category: Category - - proc run_t_test(ct: CertTest): TTOutcome {.thread.} = - ## Run test in a {.thread.} - return by ref - result = TTOutcome(desc:ct.desc, exception_msg:"", category: ct.category) - try: - var ctx = newContext(verifyMode=CVerifyPeer) - var client = newHttpClient(sslContext=ctx) - let a = $client.getContent(ct.url) - except: - result.exception_msg = getCurrentExceptionMsg() - - - suite "SSL certificate check - httpclient - threaded": - when defined(nimTestsEnableFlaky) or not defined(linux): # xxx pending bug #16338 - # Spawn threads before the "test" blocks - var outcomes = newSeq[FlowVar[TTOutcome]](certificate_tests.len) - for i, ct in certificate_tests: - let t = spawn run_t_test(ct) - outcomes[i] = t - - # create "test" blocks and handle thread outputs - for t in outcomes: - let outcome = ^t # wait for a thread to terminate - test outcome.desc: - evaluate(outcome.exception_msg, outcome.category, outcome.desc) - else: - echo "skipped test" - - # net tests - - - type NetSocketTest = tuple[hostname: string, port: Port, category:Category, desc: string] - const net_tests:array[0..3, NetSocketTest] = [ - ("imap.gmail.com", 993.Port, good, "IMAP"), - ("wrong.host.badssl.com", 443.Port, bad, "wrong.host"), - ("captive-portal.badssl.com", 443.Port, bad, "captive-portal"), - ("expired.badssl.com", 443.Port, bad, "expired"), - ] - # TODO: ("null.badssl.com", 443.Port, bad_broken, "null"), - - - suite "SSL certificate check - sockets": - - for ct in net_tests: - - test ct.desc: - - var sock = newSocket() - var ctx = newContext() - ctx.wrapSocket(sock) - let exception_msg = - try: - sock.connect(ct.hostname, ct.port) - "" - except: - getCurrentExceptionMsg() - - evaluate(exception_msg, ct.category, ct.desc) diff --git a/tests/untestable/tpostgres.nim b/tests/untestable/tpostgres.nim index 8b1378917..d3397e53a 100644 --- a/tests/untestable/tpostgres.nim +++ b/tests/untestable/tpostgres.nim @@ -1 +1,328 @@ +import db_postgres, strutils + + +let db = open("localhost", "dom", "", "test") +db.exec(sql"DROP TABLE IF EXISTS myTable") +db.exec(sql("""CREATE TABLE myTable ( + id integer PRIMARY KEY, + name varchar(50) not null)""")) +let name = "Dom" +db.exec(sql"INSERT INTO myTable (id, name) VALUES (0, ?)", + name) +doAssert db.getValue(sql"SELECT name FROM myTable") == name +# Check issue #3513 +doAssert db.getValue(sql"SELECT name FROM myTable") == name + + +# issue #3560 +proc addToDb(conn: DbConn, fileId: int, fileName: string): int64 = + result = conn.insertId(sql("INSERT into files (id, filename) VALUES (?, ?)"), fileId, fileName) + +db.exec(sql"DROP TABLE IF EXISTS files") +db.exec(sql"DROP TABLE IF EXISTS fileobjects") +db.exec(sql("""CREATE TABLE FILEOBJECTS( + ID SERIAL PRIMARY KEY, + FILE_SIZE INT, + MD5 CHAR(32) NOT NULL UNIQUE + );""")) + +db.exec(sql("""CREATE TABLE FILES( + ID SERIAL PRIMARY KEY, + OBJECT_ID INT, + FILENAME TEXT NOT NULL, + URI TEXT, + SCHEME CHAR(10), + PUBLIC BOOLEAN DEFAULT FALSE, + CONSTRAINT fk1_fileobjs FOREIGN KEY (object_id) + REFERENCES fileobjects (id) MATCH SIMPLE + ON DELETE CASCADE + );""")) + +let f1 = db.addToDb(1, "hello.tmp") +doAssert f1 == 1 +let f2 = db.addToDb(2, "hello2.tmp") +doAssert f2 == 2 + +# PreparedStmt vs. normal query +try: + echo db.getValue(sql("select * from files where id = $1"), 1) + doAssert false, "Exception expected" +except DbError: + let msg = getCurrentExceptionMsg().normalize + doAssert "expects" in msg + doAssert "?" in msg + doAssert "parameter substitution" in msg + +doAssert db.getValue(sql("select filename from files where id = ?"), 1) == "hello.tmp" + +var first = prepare(db, "one", sql"select filename from files where id = $1", 1) +doAssert db.getValue(first, 1) == "hello.tmp" + +try: + var second = prepare(db, "two", sql"select filename from files where id = ?", 1) + doAssert false, "Exception expected" +except: + let msg = getCurrentExceptionMsg().normalize + doAssert "expects" in msg + doAssert "$1" in msg + doAssert "parameter substitution" in msg + +# issue #3569 +db.exec(SqlQuery("DROP TABLE IF EXISTS tags")) +db.exec(SqlQuery("CREATE TABLE tags(id serial UNIQUE, name varchar(255))")) + +for i in 1..10: + var name = "t" & $i + echo(name) + discard db.getRow( + SqlQuery("INSERT INTO tags(name) VALUES(\'$1\') RETURNING id" % [name])) + +# get column details +db.exec(SqlQuery("DROP TABLE IF EXISTS dbtypes;")) +db.exec(SqlQuery("DROP TYPE IF EXISTS custom_enum;")) +db.exec(SqlQuery("CREATE TYPE custom_enum AS ENUM ('1', '2', '3');")) +db.exec(SqlQuery("DROP TYPE IF EXISTS custom_composite;")) +db.exec(SqlQuery("CREATE TYPE custom_composite AS (r double precision, i double precision);")) +db.exec(SqlQuery("""CREATE TABLE dbtypes( + id serial UNIQUE, + bytea_col bytea, + smallint_col smallint, + integer_col integer, + bigint_col bigint, + decimal_col decimal, + numeric_col numeric, + real_col real, + double_precision_col double precision, + smallserial_col smallserial, + serial_col serial, + bigserial_col bigserial, + money_col money, + varchar_col varchar(10), + character_col character(1), + text_col text, + timestamp_col timestamp, + date_col date, + time_col time, + interval_col interval, + bool_col boolean, + custom_enum_col custom_enum, + point_col point, + line_col line, + lseg_col lseg, + box_col box, + path_col path, + polygon_col polygon, + circle_col circle, + cidr_col cidr, + inet_col inet, + macaddr_col macaddr, + bit_col bit, + varbit_col bit(3), + tsvector_col tsvector, + tsquery_col tsquery, + uuid_col uuid, + xml_col xml, + json_col json, + array_col integer[], + custom_composite_col custom_composite, + range_col int4range + );""")) +db.exec(SqlQuery("INSERT INTO dbtypes (id) VALUES(0);")) + +var dbCols : DbColumns = @[] +for row in db.instantRows(dbCols, sql"SELECT * FROM dbtypes"): + doAssert len(dbCols) == 42 + +doAssert dbCols[0].name == "id" +doAssert dbCols[0].typ.kind == DbTypeKind.dbInt +doAssert dbCols[0].typ.name == "int4" +doAssert dbCols[0].typ.size == 4 + +doAssert dbCols[1].name == "bytea_col" +doAssert dbCols[1].typ.kind == DbTypeKind.dbBlob +doAssert dbCols[1].typ.name == "bytea" + +doAssert dbCols[2].name == "smallint_col" +doAssert dbCols[2].typ.kind == DbTypeKind.dbInt +doAssert dbCols[2].typ.name == "int2" +doAssert dbCols[2].typ.size == 2 + +doAssert dbCols[3].name == "integer_col" +doAssert dbCols[3].typ.kind == DbTypeKind.dbInt +doAssert dbCols[3].typ.name == "int4" +doAssert dbCols[3].typ.size == 4 + +doAssert dbCols[4].name == "bigint_col" +doAssert dbCols[4].typ.kind == DbTypeKind.dbInt +doAssert dbCols[4].typ.name == "int8" +doAssert dbCols[4].typ.size == 8 + +doAssert dbCols[5].name == "decimal_col" +doAssert dbCols[5].typ.kind == DbTypeKind.dbDecimal +doAssert dbCols[5].typ.name == "numeric" + +doAssert dbCols[6].name == "numeric_col" +doAssert dbCols[6].typ.kind == DbTypeKind.dbDecimal +doAssert dbCols[6].typ.name == "numeric" + +doAssert dbCols[7].name == "real_col" +doAssert dbCols[7].typ.kind == DbTypeKind.dbFloat +doAssert dbCols[7].typ.name == "float4" + +doAssert dbCols[8].name == "double_precision_col" +doAssert dbCols[8].typ.kind == DbTypeKind.dbFloat +doAssert dbCols[8].typ.name == "float8" + +doAssert dbCols[9].name == "smallserial_col" +doAssert dbCols[9].typ.kind == DbTypeKind.dbInt +doAssert dbCols[9].typ.name == "int2" + +doAssert dbCols[10].name == "serial_col" +doAssert dbCols[10].typ.kind == DbTypeKind.dbInt +doAssert dbCols[10].typ.name == "int4" + +doAssert dbCols[11].name == "bigserial_col" +doAssert dbCols[11].typ.kind == DbTypeKind.dbInt +doAssert dbCols[11].typ.name == "int8" + +doAssert dbCols[12].name == "money_col" +doAssert dbCols[12].typ.kind == DbTypeKind.dbDecimal +doAssert dbCols[12].typ.name == "money" + +doAssert dbCols[13].name == "varchar_col" +doAssert dbCols[13].typ.kind == DbTypeKind.dbVarchar +doAssert dbCols[13].typ.name == "varchar" + +doAssert dbCols[14].name == "character_col" +doAssert dbCols[14].typ.kind == DbTypeKind.dbFixedChar +doAssert dbCols[14].typ.name == "bpchar" + +doAssert dbCols[15].name == "text_col" +doAssert dbCols[15].typ.kind == DbTypeKind.dbVarchar +doAssert dbCols[15].typ.name == "text" + +doAssert dbCols[16].name == "timestamp_col" +doAssert dbCols[16].typ.kind == DbTypeKind.dbTimestamp +doAssert dbCols[16].typ.name == "timestamp" + +doAssert dbCols[17].name == "date_col" +doAssert dbCols[17].typ.kind == DbTypeKind.dbDate +doAssert dbCols[17].typ.name == "date" + +doAssert dbCols[18].name == "time_col" +doAssert dbCols[18].typ.kind == DbTypeKind.dbTime +doAssert dbCols[18].typ.name == "time" + +doAssert dbCols[19].name == "interval_col" +doAssert dbCols[19].typ.kind == DbTypeKind.dbTimeInterval +doAssert dbCols[19].typ.name == "interval" + +doAssert dbCols[20].name == "bool_col" +doAssert dbCols[20].typ.kind == DbTypeKind.dbBool +doAssert dbCols[20].typ.name == "bool" + +doAssert dbCols[21].name == "custom_enum_col" +doAssert dbCols[21].typ.kind == DbTypeKind.dbUnknown +doAssert parseInt(dbCols[21].typ.name) > 0 + +doAssert dbCols[22].name == "point_col" +doAssert dbCols[22].typ.kind == DbTypeKind.dbPoint +doAssert dbCols[22].typ.name == "point" + +doAssert dbCols[23].name == "line_col" +doAssert dbCols[23].typ.kind == DbTypeKind.dbLine +doAssert dbCols[23].typ.name == "line" + +doAssert dbCols[24].name == "lseg_col" +doAssert dbCols[24].typ.kind == DbTypeKind.dbLseg +doAssert dbCols[24].typ.name == "lseg" + +doAssert dbCols[25].name == "box_col" +doAssert dbCols[25].typ.kind == DbTypeKind.dbBox +doAssert dbCols[25].typ.name == "box" + +doAssert dbCols[26].name == "path_col" +doAssert dbCols[26].typ.kind == DbTypeKind.dbPath +doAssert dbCols[26].typ.name == "path" + +doAssert dbCols[27].name == "polygon_col" +doAssert dbCols[27].typ.kind == DbTypeKind.dbPolygon +doAssert dbCols[27].typ.name == "polygon" + +doAssert dbCols[28].name == "circle_col" +doAssert dbCols[28].typ.kind == DbTypeKind.dbCircle +doAssert dbCols[28].typ.name == "circle" + +doAssert dbCols[29].name == "cidr_col" +doAssert dbCols[29].typ.kind == DbTypeKind.dbInet +doAssert dbCols[29].typ.name == "cidr" + +doAssert dbCols[30].name == "inet_col" +doAssert dbCols[30].typ.kind == DbTypeKind.dbInet +doAssert dbCols[30].typ.name == "inet" + +doAssert dbCols[31].name == "macaddr_col" +doAssert dbCols[31].typ.kind == DbTypeKind.dbMacAddress +doAssert dbCols[31].typ.name == "macaddr" + +doAssert dbCols[32].name == "bit_col" +doAssert dbCols[32].typ.kind == DbTypeKind.dbBit +doAssert dbCols[32].typ.name == "bit" + +doAssert dbCols[33].name == "varbit_col" +doAssert dbCols[33].typ.kind == DbTypeKind.dbBit +doAssert dbCols[33].typ.name == "bit" + +doAssert dbCols[34].name == "tsvector_col" +doAssert dbCols[34].typ.kind == DbTypeKind.dbVarchar +doAssert dbCols[34].typ.name == "tsvector" + +doAssert dbCols[35].name == "tsquery_col" +doAssert dbCols[35].typ.kind == DbTypeKind.dbVarchar +doAssert dbCols[35].typ.name == "tsquery" + +doAssert dbCols[36].name == "uuid_col" +doAssert dbCols[36].typ.kind == DbTypeKind.dbVarchar +doAssert dbCols[36].typ.name == "uuid" + +doAssert dbCols[37].name == "xml_col" +doAssert dbCols[37].typ.kind == DbTypeKind.dbXml +doAssert dbCols[37].typ.name == "xml" + +doAssert dbCols[38].name == "json_col" +doAssert dbCols[38].typ.kind == DbTypeKind.dbJson +doAssert dbCols[38].typ.name == "json" + +doAssert dbCols[39].name == "array_col" +doAssert dbCols[39].typ.kind == DbTypeKind.dbArray +doAssert dbCols[39].typ.name == "int4[]" + +doAssert dbCols[40].name == "custom_composite_col" +doAssert dbCols[40].typ.kind == DbTypeKind.dbUnknown +doAssert parseInt(dbCols[40].typ.name) > 0 + +doAssert dbCols[41].name == "range_col" +doAssert dbCols[41].typ.kind == DbTypeKind.dbComposite +doAssert dbCols[41].typ.name == "int4range" + +# issue 6571 +db.exec(sql"DROP TABLE IF EXISTS DICTIONARY") +db.exec(sql("""CREATE TABLE DICTIONARY( + id SERIAL PRIMARY KEY, + entry VARCHAR(1000) NOT NULL, + definition VARCHAR(4000) NOT NULL + );""")) +var entry = "あっそ" +var definition = "(int) (See ああそうそう) oh, really (uninterested)/oh yeah?/hmmmmm" +discard db.getRow( + SqlQuery("INSERT INTO DICTIONARY(entry, definition) VALUES(\'$1\', \'$2\') RETURNING id" % [entry, definition])) +doAssert db.getValue(sql"SELECT definition FROM DICTIONARY WHERE entry = ?", entry) == definition +entry = "Format string entry" +definition = "Format string definition" +db.exec(sql"INSERT INTO DICTIONARY(entry, definition) VALUES (?, ?)", entry, definition) +doAssert db.getValue(sql"SELECT definition FROM DICTIONARY WHERE entry = ?", entry) == definition + +echo("All tests succeeded!") + +db.close() diff --git a/tests/usingstmt/tthis.nim b/tests/usingstmt/tthis.nim new file mode 100644 index 000000000..83d75d08c --- /dev/null +++ b/tests/usingstmt/tthis.nim @@ -0,0 +1,15 @@ + +# bug #4177 + +type + Parent = object of RootObj + parentField: int + Child = object of Parent + childField: int + +{.this: self.} +proc sumFields(self: Child): int = + result = parentField + childField # Error: undeclared identifier: 'parentField' + +proc sumFieldsWorks(self: Child): int = + result = self.parentField + childField diff --git a/tests/misc/tcsharpusingstatement.nim b/tests/usingstmt/tusingstatement.nim similarity index 96% rename from tests/misc/tcsharpusingstatement.nim rename to tests/usingstmt/tusingstatement.nim index dd4cf589d..6e4998892 100644 --- a/tests/misc/tcsharpusingstatement.nim +++ b/tests/usingstmt/tusingstatement.nim @@ -38,7 +38,7 @@ macro autoClose(args: varargs[untyped]): untyped = varAssignment.add(varValue) variables.add(varAssignment) - closingCalls.add(newCall(newIdentNode("close"), varName)) + closingCalls.add(newCall(!"close", varName)) else: error "Using statement: Unexpected expression. Got " & $args[i].kind & " instead of assignment." diff --git a/tests/usingstmt/tusingstmt.nim b/tests/usingstmt/tusingstmt.nim deleted file mode 100644 index 11803878e..000000000 --- a/tests/usingstmt/tusingstmt.nim +++ /dev/null @@ -1,16 +0,0 @@ -type - Foo = object - -using - c: Foo - x, y: int - -proc usesSig(c) = discard - -proc foobar(c, y) = discard - -usesSig(Foo()) -foobar(Foo(), 123) -doAssert not compiles(usesSig(123)) -doAssert not compiles(foobar(Foo(), Foo())) -doAssert not compiles(foobar(123, 123)) diff --git a/tests/valgrind/tleak_arc.nim b/tests/valgrind/tleak_arc.nim deleted file mode 100644 index c47ee137a..000000000 --- a/tests/valgrind/tleak_arc.nim +++ /dev/null @@ -1,14 +0,0 @@ -discard """ -valgrind: true -cmd: "nim $target --gc:arc -d:useMalloc $options $file" -exitcode: 1 -outputsub: " definitely lost: 7 bytes in 2 blocks" -disabled: "freebsd" -disabled: "osx" -disabled: "openbsd" -disabled: "windows" -disabled: "32bit" -""" - -discard alloc(3) -discard alloc(4) diff --git a/tests/varres/tprevent_forloopvar_mutations.nim b/tests/varres/tprevent_forloopvar_mutations.nim index c9aeb94d8..398191658 100644 --- a/tests/varres/tprevent_forloopvar_mutations.nim +++ b/tests/varres/tprevent_forloopvar_mutations.nim @@ -1,10 +1,11 @@ discard """ - errormsg: "type mismatch: got " - nimout: '''tprevent_forloopvar_mutations.nim(16, 3) Error: type mismatch: got + errmsg: "type mismatch: got " + line: 17 + nimout: '''type mismatch: got but expected one of: -proc inc[T, V: Ordinal](x: var T; y: V = 1) +proc inc[T: Ordinal | uint | uint64](x: var T; y = 1) first type mismatch at position: 1 - required type for x: var T: Ordinal + required type for x: var T: Ordinal or uint or uint64 but expression 'i' is immutable, not 'var' expression: inc i diff --git a/tests/varres/tvarres0.nim b/tests/varres/tvarres0.nim index 94bdb4a06..fd10a73bd 100644 --- a/tests/varres/tvarres0.nim +++ b/tests/varres/tvarres0.nim @@ -4,7 +4,6 @@ discard """ 123 1234 12345 -123456 ''' """ @@ -29,113 +28,3 @@ getF().a = 1234 echo getF().a getF() = Foo(a: 12345) echo getF().a -(addr getF())[] = Foo(a: 123456) -echo getF().a - - -block: # #13848 - template fun() = - block: - var m = 1 - - proc identity(o: var int): var int = - result = o - result += 5 - - identity(m) += 3 - doAssert m == 5+4 - - block: - var m = 10 - proc identity2(o: var int): var int = - result = m - result += 100 - - var ignored = 27 - identity2(ignored) += 7 - doAssert m == 10 + 100 + 7 - - block: - iterator test3(o: var int): var int = yield o - var m = 1 - for m2 in test3(m): m2+=3 - doAssert m == 4 - - static: fun() - fun() - - template fun2() = - block: - var m = 1 - var m2 = 1 - iterator test3(o: var int): (var int, var int) = - yield (o, m2) - - for ti in test3(m): - ti[0]+=3 - ti[1]+=4 - - doAssert (m, m2) == (4, 5) - fun2() - # static: fun2() # BUG: Error: attempt to access a nil address kind: rkInt - - template fun3() = - block: - proc test4[T1](o: var T1): var int = o[1] - block: - var m = @[1,2] - test4(m) += 10 - doAssert m[1] == 2+10 - block: - var m = [1,2] - test4(m) += 10 - doAssert m[1] == 2+10 - block: - var m = (1, 2) - test4(m) += 10 - doAssert m[1] == 2+10 - - proc test5[T1](o: var T1): var int = o.x - block: - type Foo = object - x: int - var m = Foo(x: 2) - test5(m) += 10 - doAssert m.x == 2+10 - block: - type Foo = ref object - x: int - var m = Foo(x: 2) - test5(m) += 10 - doAssert m.x == 2+10 - - proc test6[T1](o: T1): var int = o.x - block: - type Foo = ref object - x: int - var m = Foo(x: 2) - test6(m) += 10 - doAssert m.x == 2+10 - - fun3() - static: fun3() - - when false: - # BUG: - # c: SIGSEGV - # cpp: error: call to implicitly-deleted default constructor of 'tyTuple__ILZebuYefUeQLAzY85QkHA' - proc test7[T](o: var T): (var int,) = - (o[1], ) - var m = @[1,2] - test7(m)[0] += 10 - -block: - # example from #13848 - type - MyType[T] = object - a,b: T - MyTypeAlias = MyType[float32] - - var m: MyTypeAlias - proc identity(o: var MyTypeAlias): var MyTypeAlias = o - discard identity(m) diff --git a/tests/views/t19986.nim b/tests/views/t19986.nim deleted file mode 100644 index 85a7cf97d..000000000 --- a/tests/views/t19986.nim +++ /dev/null @@ -1,42 +0,0 @@ -discard """ - cmd: '''nim check --hints:off $file''' - action: reject -nimout: ''' -t19986.nim(19, 7) Error: 'foo' borrows from the immutable location 'a' and attempts to mutate it -t19986.nim(28, 7) Error: 'foo' borrows from the immutable location 'a' and attempts to mutate it -t19986.nim(37, 7) Error: 'foo' borrows from the immutable location 'a' and attempts to mutate it -''' -""" - -{.experimental: "views".} - -type - Object = object - id: int - -proc foo() = - let a = Object(id: 3) - var foo: var Object = a - - foo.id = 777 - echo a - -foo() - -proc bar() = - let a = "123" - var foo: var string = a - - foo[0] = '7' - echo a - -bar() - -proc main() = - let a = 3 - var foo: var int = a - - foo = 777 - echo a - -main() diff --git a/tests/views/tcan_compile_nim.nim b/tests/views/tcan_compile_nim.nim deleted file mode 100644 index e990606cd..000000000 --- a/tests/views/tcan_compile_nim.nim +++ /dev/null @@ -1,4 +0,0 @@ -discard """ - cmd: "nim check --hints:on --experimental:strictFuncs --experimental:views compiler/nim.nim" - action: "compile" -""" diff --git a/tests/views/tcannot_borrow.nim b/tests/views/tcannot_borrow.nim deleted file mode 100644 index 0b8793159..000000000 --- a/tests/views/tcannot_borrow.nim +++ /dev/null @@ -1,22 +0,0 @@ -discard """ - errormsg: "cannot borrow" - nimout: '''tcannot_borrow.nim(20, 7) Error: cannot borrow meh; what it borrows from is potentially mutated -tcannot_borrow.nim(21, 3) the mutation is here''' -""" - - -{.experimental: "views".} - -type - Foo = object - field: string - -proc valid(s: var seq[Foo]) = - let v: lent Foo = s[0] # begin of borrow - echo v.field # end of borrow - s.setLen 0 # valid because 'v' isn't used afterwards - -proc dangerous(s: var seq[Foo]) = - let meh: lent Foo = s[0] - s.setLen 0 - echo meh.field diff --git a/tests/views/tconst_views.nim b/tests/views/tconst_views.nim deleted file mode 100644 index a85b03864..000000000 --- a/tests/views/tconst_views.nim +++ /dev/null @@ -1,37 +0,0 @@ -discard """ - cmd: "nim c --experimental:views $file" - output: '''(data: [1, 2, 3], other: 4) -[1, 20, 3]''' -""" - -type - Foo = object - data: openArray[int] - other: int - -const - c = Foo(data: [1, 2, 3], other: 4) - - c2 = Foo(data: [1, 20, 3], other: 4) - -proc `$`(x: openArray[int]): string = - result = "[" - for i in x: - if result.len > 1: result.add ", " - result.add $i - result.add "]" - -echo c -echo c2.data - - -type MyObj = object - data: openarray[char] - -const - val1 = Foo(data: toOpenArray([1, 2, 3], 1, 1)) - val2 = Foo(data: toOpenArray([1, 2, 3], 0, 2)) - val3 = MyObj(data: "Hello".toOpenArray(0, 2)) -assert val1.data == [2] -assert val2.data == [1, 2, 3] -assert val3.data == "Hel" diff --git a/tests/views/tdont_mutate.nim b/tests/views/tdont_mutate.nim deleted file mode 100644 index eb5a82cbf..000000000 --- a/tests/views/tdont_mutate.nim +++ /dev/null @@ -1,58 +0,0 @@ -discard """ - cmd: "nim check --hints:off $file" -""" - -import tables - -{.experimental: "views".} - -const - Whitespace = {' ', '\t', '\n', '\r'} - -proc split*(s: string, seps: set[char] = Whitespace, maxsplit: int = -1): Table[int, openArray[char]] #[tt.Error -^ 'result' borrows from the immutable location 's' and attempts to mutate it - ]# = - var last = 0 - var splits = maxsplit - result = initTable[int, openArray[char]]() - - while last <= len(s): - var first = last - while last < len(s) and s[last] notin seps: - inc(last) - if splits == 0: last = len(s) - result[first] = toOpenArray(s, first, last-1) - - result[first][0] = 'c' - - if splits == 0: break - dec(splits) - inc(last) - -proc `$`(x: openArray[char]): string = - result = newString(x.len) - for i in 0..".} proc c_printf(frmt: cstring): cint {.importc: "printf", header: "", varargs, discardable.} const snprintfName = when defined(windows): "_snprintf" else: "snprintf" -proc c_snprintf*(str: cstring, size: csize_t, format: cstring): cint {.importc: snprintfName, header: "", varargs .} +proc c_snprintf*(buffer: pointer, buf_size: uint, format: cstring): cint {.importc: snprintfName, header: "", varargs .} -proc c_malloc(size: csize_t): pointer {.importc:"malloc", header: "".} +proc c_malloc(size:uint):pointer {.importc:"malloc", header: "".} proc c_free(p: pointer) {.importc:"free", header: "".} proc fun() = @@ -35,15 +35,12 @@ proc fun() = block: # c_snprintf, c_malloc, c_free let n: uint = 50 - var buffer2 = cstring(cast[ptr char](c_malloc(n))) - + var buffer2: pointer = c_malloc(n) var s: cstring = "foobar" var age: cint = 25 - let num = c_snprintf(buffer2, n, "s1:%s s2:%s age:%d pi:%g", s, s, age, 3.14) - let numExp = 34 - doAssert num == numExp - c_printf("ret=[%s]\n", buffer2) - c_free(buffer2) + discard c_snprintf(buffer2, n, "s1:%s s2:%s age:%d pi:%g", s, s, age, 3.14) + c_printf("ret={%s}\n", buffer2) + c_free(buffer2) # not sure it has an effect block: # c_printf bug var a = 123 @@ -61,11 +58,10 @@ static: fun() fun() -when not defined nimEvalffiStderrWorkaround: - import system/ansi_c - block: - proc fun2()= - c_fprintf(cstderr, "hello world stderr\n") - write(stderr, "hi stderr\n") - static: fun2() - fun2() +import system/ansi_c +block: + proc fun2()= + c_fprintf(cstderr, "hello world stderr\n") + write(stderr, "hi stderr\n") + static: fun2() + fun2() diff --git a/tests/vm/t11637.nim b/tests/vm/t11637.nim deleted file mode 100644 index c061c6641..000000000 --- a/tests/vm/t11637.nim +++ /dev/null @@ -1,52 +0,0 @@ -type Foo = ref object - val: int - -proc `+`(a, b: Foo): Foo = - Foo(val: a.val + b.val) - -proc `*`(a: Foo, b: int): Foo = - Foo(val: a.val * b) - -proc `+=`(a: var Foo, b: Foo) = - a = Foo( - val: a.val + b.val - ) - -proc foobar(a, b, c: Foo): tuple[bar, baz, buzz: Foo] = - - let foo = a + b + c - result.bar = foo * 2 - - result.baz = foo * 3 - result.buzz = result.baz - - result.buzz += a * 10000 - result.baz += b - result.buzz += b - - -block: # Compile-Time - let - a {.compileTime.} = Foo(val: 1) - b {.compileTime.} = Foo(val: 2) - c {.compileTime.} = Foo(val: 3) - r {.compileTime.} = foobar(a, b, c) - - static: - doAssert r.bar.val == 12 - doAssert r.baz.val == 20 - doAssert r.buzz.val == 10020 - -#################################### - -block: # Run-time - let - a = Foo(val: 1) - b = Foo(val: 2) - c = Foo(val: 3) - r = foobar(a, b, c) - - # Expected values - doAssert r.bar.val == 12 - doAssert r.baz.val == 20 - doAssert r.buzz.val == 10020 diff --git a/tests/vm/t17039.nim b/tests/vm/t17039.nim deleted file mode 100644 index f92c93f30..000000000 --- a/tests/vm/t17039.nim +++ /dev/null @@ -1,10 +0,0 @@ -type - Obj1 = object - case kind: bool - of false: - field: seq[int] - else: discard - -static: - var obj1 = Obj1() - obj1.field.add(@[]) diff --git a/tests/vm/t17121.nim b/tests/vm/t17121.nim deleted file mode 100644 index bf2d6423f..000000000 --- a/tests/vm/t17121.nim +++ /dev/null @@ -1,9 +0,0 @@ -discard """ - errormsg: "cannot 'importc' variable at compile time; c_printf" -""" - -proc c_printf*(frmt: cstring): cint {.importc: "printf", header: "", varargs, discardable.} = - ## foo bar - runnableExamples: discard -static: - let a = c_printf("abc\n") diff --git a/tests/vm/t19075.nim b/tests/vm/t19075.nim deleted file mode 100644 index 89ca9cb19..000000000 --- a/tests/vm/t19075.nim +++ /dev/null @@ -1,19 +0,0 @@ -discard """ - timeout: 10 - joinable: false -""" - -# bug #19075 -const size = 50_000 - -const stuff = block: - var a: array[size, int] - a - -const zeugs = block: - var zeugs: array[size, int] - for i in 0..= m - a: - result -= m - result += a - -func mulmod_internal(a, b, m: Stuint): Stuint = - var (a, b) = (a, b) - swap(a, b) - debugEcho "x1 a: ", a - a = doublemod_internal(a, m) - debugEcho "x2 a: ", a - a = doublemod_internal(a, m) - debugEcho "x3 a: ", a - -func powmod_internal(a, m: Stuint): Stuint = - var a = a - debugEcho "z1 m: ", m - debugEcho "z2 a: ", a - result = mulmod_internal(result, a, m) - debugEcho "z3 a: ", a - a = mulmod_internal(a, a, m) - -func powmod*(a, m: Stuint) = - discard powmod_internal(a mod m, m) - -static: - var x = Stuint(lo: high(uint64)) - var y = Stuint(lo: 12) - - powmod(x, y) - -# bug #16780 -when true: - template swap*[T](a, b: var T) = - var a2 = addr(a) - var b2 = addr(b) - var aOld = a2[] - a2[] = b2[] - b2[] = aOld - - proc rather = - block: - var a = 1 - var b = 2 - swap(a, b) - echo (a,b) - - block: - type Foo = ref object - x: int - var a = Foo(x:1) - var b = Foo(x:2) - swap(a, b) - echo (a.x, b.x) - - block: - type Foo = object - x: int - var a = Foo(x:1) - var b = Foo(x:2) - swap(a, b) - echo (a.x,b.x) - - static: rather() - rather() - -# bug #16020 -when true: - block: - type Foo = object - f0: int - proc main= - var f = Foo(f0: 3) - var f2 = f.addr - f2[].f0 += 1 - f2.f0 += 1 - echo f - static: main() - main() - -import tables, strutils - -# bug #14553 -const PpcPatterns = @[("aaaa", "bbbb"), ("aaaaa", "bbbbb"), ("aaaaaa", "bbbbbb"), ("aaaaaaa", "bbbbbbb"), ("aaaaaaaa", "bbbbb")] - -static: - var - needSecondIdentifier = initTable[uint32, seq[(string, string)]]() - - for (name, pattern) in PpcPatterns: - let - firstPart = 0'u32 - lastPart = "test" - - needSecondIdentifier.mgetOrPut(firstPart, @[]).add((name, pattern)) - - doAssert needSecondIdentifier[0] == @[("aaaa", "bbbb"), ("aaaaa", "bbbbb"), ("aaaaaa", "bbbbbb"), ("aaaaaaa", "bbbbbbb"), ("aaaaaaaa", "bbbbb")] - -# bug #17864 -macro transform*(fn: typed) = - quote do: - `fn` - -var map: Table[string, HashSet[string]] -proc publish*(): void {.transform.} = - map["k"] = init_hash_set[string]() - map["k"].incl "d" - -publish() diff --git a/tests/vm/tnewseqofcap.nim b/tests/vm/tnewseqofcap.nim deleted file mode 100644 index a7dc07aa6..000000000 --- a/tests/vm/tnewseqofcap.nim +++ /dev/null @@ -1,14 +0,0 @@ -const - foo = @["aaa", "bbb", "ccc"] - -proc myTuple: tuple[n: int, bar: seq[string]] = - result.n = 42 - result.bar = newSeqOfCap[string](foo.len) - for f in foo: - result.bar.add(f) - -# It works if you change the below `const` to `let` -const - (n, bar) = myTuple() - -doAssert bar == @["aaa", "bbb", "ccc"] \ No newline at end of file diff --git a/tests/vm/topenarrays.nim b/tests/vm/topenarrays.nim deleted file mode 100644 index 0a822f583..000000000 --- a/tests/vm/topenarrays.nim +++ /dev/null @@ -1,69 +0,0 @@ -proc mutate(a: var openarray[int]) = - var i = 0 - for x in a.mitems: - x = i - inc i - -proc mutate(a: var openarray[char]) = - var i = 1 - for ch in a.mitems: - ch = 'a' - - -static: - var a = [10, 20, 30] - assert a.toOpenArray(1, 2).len == 2 - - mutate(a) - assert a.toOpenArray(0, 2) == [0, 1, 2] - assert a.toOpenArray(0, 0) == [0] - assert a.toOpenArray(1, 2) == [1, 2] - assert "Hello".toOpenArray(1, 4) == "ello" - var str = "Hello" - str.toOpenArray(2, 4).mutate() - assert str.toOpenArray(0, 4).len == 5 - assert str.toOpenArray(0, 0).len == 1 - assert str.toOpenArray(0, 0).high == 0 - assert str == "Heaaa" - assert str.toOpenArray(0, 4) == "Heaaa" - - var arr: array[3..4, int] = [1, 2] - assert arr.toOpenArray(3, 4) == [1, 2] - assert arr.toOpenArray(3, 4).len == 2 - assert arr.toOpenArray(3, 3).high == 0 - - assert arr.toOpenArray(3, 4).toOpenArray(0, 0) == [1] - - -proc doThing(s: static openArray[int]) = discard - -doThing([10, 20, 30].toOpenArray(0, 0)) - -# bug #19969 -proc f(): array[1, byte] = - var a: array[1, byte] - result[0..0] = a.toOpenArray(0, 0) - -doAssert static(f()) == [byte(0)] - - -# bug #15952 -proc main1[T](a: openArray[T]) = discard -proc main2[T](a: var openArray[T]) = discard - -proc main = - var a = [1,2,3,4,5] - main1(a.toOpenArray(1,3)) - main2(a.toOpenArray(1,3)) -static: main() -main() - -# bug #16306 -{.experimental: "views".} -proc test(x: openArray[int]): tuple[id: int] = - let y: openArray[int] = toOpenArray(x, 0, 2) - result = (y[0],) -template fn= - doAssert test([0,1,2,3,4,5]).id == 0 -fn() # ok -static: fn() diff --git a/tests/vm/toverflowopcaddimmint.nim b/tests/vm/toverflowopcaddimmint.nim index 4ff614e5b..c36b9ed9b 100644 --- a/tests/vm/toverflowopcaddimmint.nim +++ b/tests/vm/toverflowopcaddimmint.nim @@ -7,5 +7,5 @@ static: var x = int64.high discard x + 1 - doAssert false + assert false p() diff --git a/tests/vm/toverflowopcaddint.nim b/tests/vm/toverflowopcaddint.nim index d494245b1..6d96afc78 100644 --- a/tests/vm/toverflowopcaddint.nim +++ b/tests/vm/toverflowopcaddint.nim @@ -8,5 +8,5 @@ static: x = int64.high y = 1 discard x + y - doAssert false + assert false p() diff --git a/tests/vm/toverflowopcmulint.nim b/tests/vm/toverflowopcmulint.nim index 936eea6c2..5607c59a7 100644 --- a/tests/vm/toverflowopcmulint.nim +++ b/tests/vm/toverflowopcmulint.nim @@ -7,5 +7,5 @@ static: var x = 1'i64 shl 62 discard x * 2 - doAssert false + assert false p() diff --git a/tests/vm/toverflowopcsubimmint.nim b/tests/vm/toverflowopcsubimmint.nim index 08356590c..09d6f745b 100644 --- a/tests/vm/toverflowopcsubimmint.nim +++ b/tests/vm/toverflowopcsubimmint.nim @@ -6,5 +6,5 @@ static: proc p = var x = int64.low discard x - 1 - doAssert false + assert false p() diff --git a/tests/vm/toverflowopcsubint.nim b/tests/vm/toverflowopcsubint.nim index 74e34c6a4..8d114f200 100644 --- a/tests/vm/toverflowopcsubint.nim +++ b/tests/vm/toverflowopcsubint.nim @@ -8,5 +8,5 @@ static: x = int64.low y = 1 discard x - y - doAssert false + assert false p() diff --git a/tests/vm/tquadplus.nim b/tests/vm/tquadplus.nim index acf20cd96..552e8fef7 100644 --- a/tests/vm/tquadplus.nim +++ b/tests/vm/tquadplus.nim @@ -1,5 +1,8 @@ # bug #1023 +discard """ + output: "1 == 1" +""" type Quadruple = tuple[a, b, c, d: int] @@ -11,4 +14,4 @@ const B = (a: 0, b: -2, c: 1, d: 0) C = A + B -doAssert $C.d & " == " & $(A+B).d == "1 == 1" +echo C.d, " == ", (A+B).d diff --git a/tests/vm/tref.nim b/tests/vm/tref.nim index e70305225..f5cd23da5 100644 --- a/tests/vm/tref.nim +++ b/tests/vm/tref.nim @@ -59,13 +59,4 @@ static: static: # bug #8402 type R = ref object var empty: R - let otherEmpty = empty - -block: - # fix https://github.com/timotheecour/Nim/issues/88 - template fun() = - var s = @[10,11,12] - var a = s[0].addr - a[] += 100 # was giving SIGSEGV - doAssert a[] == 110 - static: fun() + let otherEmpty = empty \ No newline at end of file diff --git a/tests/vm/treset.nim b/tests/vm/treset.nim index 32fbc7f04..ff8bc5b83 100644 --- a/tests/vm/treset.nim +++ b/tests/vm/treset.nim @@ -1,3 +1,6 @@ +discard """ + output: '''0''' +""" static: type Obj = object field: int @@ -45,6 +48,6 @@ proc main = var x = 4 x = default(int) - doAssert x == 0 + echo x main() diff --git a/tests/vm/triangle_array.nim b/tests/vm/triangle_array.nim index 0704239c6..054c66f22 100644 --- a/tests/vm/triangle_array.nim +++ b/tests/vm/triangle_array.nim @@ -1,3 +1,7 @@ +discard """ + output: "56" +""" + # bug #1781 proc initCombinations: array[11, array[11, int]] = @@ -10,4 +14,4 @@ proc initCombinations: array[11, array[11, int]] = result[6][6 .. 10] = [52,53,54,55,56] const combinations = initCombinations() -doAssert combinations[6][10] == 56 +echo combinations[6][10] diff --git a/tests/vm/tslow_tables.nim b/tests/vm/tslow_tables.nim index e40187f18..f726c6323 100644 --- a/tests/vm/tslow_tables.nim +++ b/tests/vm/tslow_tables.nim @@ -1,5 +1,5 @@ discard """ - timeout: "7" + timeout: "4" action: "compile" nimout: '''create search @@ -26,5 +26,5 @@ proc hop(): bool = echo "done" -const r {.used.} = hop() +const r = hop() diff --git a/tests/vm/tstring_openarray.nim b/tests/vm/tstring_openarray.nim index 9318344f8..1b8a1304c 100644 --- a/tests/vm/tstring_openarray.nim +++ b/tests/vm/tstring_openarray.nim @@ -12,16 +12,16 @@ proc set_all[T](s: var openArray[T]; val: T) = for i in 0.. 0 - -import tables - -block: # bug #8007 - type - CostKind = enum - Fixed, - Dynamic - - Cost = object - case kind*: CostKind - of Fixed: - cost*: int - of Dynamic: - handler*: proc(value: int): int {.nimcall.} - - proc foo(value: int): int {.nimcall.} = - sizeof(value) - - const a: array[2, Cost] =[ - Cost(kind: Fixed, cost: 999), - Cost(kind: Dynamic, handler: foo) - ] - - # OK with arrays & object variants - doAssert $a == "[(kind: Fixed, cost: 999), (kind: Dynamic, handler: ...)]" - - const b: Table[int, Cost] = { - 0: Cost(kind: Fixed, cost: 999), - 1: Cost(kind: Dynamic, handler: foo) - }.toTable - - # KO with Tables & object variants - # echo b # {0: (kind: Fixed, cost: 0), 1: (kind: Dynamic, handler: ...)} # <----- wrong behaviour - doAssert $b == "{0: (kind: Fixed, cost: 999), 1: (kind: Dynamic, handler: ...)}" - - const c: Table[int, int] = { - 0: 100, - 1: 999 - }.toTable - - # OK with Tables and primitive int - doAssert $c == "{0: 100, 1: 999}" - - # For some reason the following gives - # Error: invalid type for const: Cost - const d0 = Cost(kind: Fixed, cost: 999) - - # OK with seq & object variants - const d = @[Cost(kind: Fixed, cost: 999), Cost(kind: Dynamic, handler: foo)] - doAssert $d == "@[(kind: Fixed, cost: 999), (kind: Dynamic, handler: ...)]" - -block: # bug #14340 - block: - proc opl3EnvelopeCalcSin0() = discard - type EnvelopeSinfunc = proc() - # const EnvelopeCalcSin0 = opl3EnvelopeCalcSin0 # ok - const EnvelopeCalcSin0: EnvelopeSinfunc = opl3EnvelopeCalcSin0 # was bug - const envelopeSin = [EnvelopeCalcSin0] - var a = 0 - envelopeSin[a]() - - block: - type Mutator = proc() {.noSideEffect, gcsafe.} - proc mutator0() = discard - const mTable = [Mutator(mutator0)] - var i=0 - mTable[i]() - -block: # VM wrong register free causes errors in unrelated code - block: # bug #15597 - #[ - Error: unhandled exception: 'sym' is not accessible using discriminant 'kind' of type 'TNode' [FieldDefect] - in /Users/timothee/git_clone/nim/Nim_prs/compiler/vm.nim(1176) rawExecute - in opcIndCall - in let prc = if not isClosure: bb.sym else: bb[0].sym - ]# - proc bar2(head: string): string = "asdf" - proc zook(u1: int) = discard - - type PathEntry = object - kind: int - path: string - - iterator globOpt(): int = - var u1: int - - zook(u1) - zook(u1) - zook(u1) - zook(u1) - zook(u1) - zook(u1) - zook(u1) - zook(u1) - zook(u1) - zook(u1) - zook(u1) - zook(u1) - zook(u1) - zook(u1) - - var entry = PathEntry() - entry.path = bar2("") - if false: - echo "here2" - - proc processAux(a: float) = discard - - template bar(iter: untyped): untyped = - var ret: float - for x in iter: break - ret - - proc main() = - processAux(bar(globOpt())) - static: main() - - block: # ditto - # D20201024T133245 - type Deque = object - proc initDeque2(initialSize: int = 4): Deque = Deque() - proc len2(a: Deque): int = 2 - proc baz(dir: string): bool = true - proc bar2(head: string): string = "asdf" - proc bar3(path: var string) = path = path - - type PathEntry = object - kind: int - path: string - - proc initGlobOpt(dir: string, a1=false,a2=false,a3=false,a4=false): string = dir - - iterator globOpt(dir: string): int = - var stack = initDeque2() - doAssert baz("") - let z = stack.len2 - if stack.len2 >= 0: - var entry = PathEntry() - let current = if true: stack.len2 else: stack.len2 - entry.path = bar2("") - bar3(entry.path) - if false: - echo "here2" # comment here => you get same error as https://github.com/nim-lang/Nim/issues/15704 - - proc processAux(a: float) = discard - - template bar(iter: untyped): untyped = - var ret: float - for x in iter: break - ret - proc main() = - processAux(bar(globOpt(initGlobOpt(".")))) - static: main() - - block: # bug #15704 - #[ - Error: attempt to access a nil address kind: rkFloat - ]# - type Deque = object - proc initDeque2(initialSize: int = 4): Deque = Deque() - proc len2(a: Deque): int = 2 - - proc baz(dir: string): bool = true - proc bar2(head: string): string = "asdf" - proc bar3(path: var string) = path = path - - type PathEntry = object - kind: int - path: string - depth: int - - proc initGlobOpt(dir: string, a1=false,a2=false,a3=false,a4=false): string = - dir - - iterator globOpt(dir: string): int = - var stack = initDeque2() - doAssert baz("") - let z = stack.len2 - var a5: int - if stack.len2 >= 0: - var entry = PathEntry() - if false: - echo "here" - let current = if true: stack.len2 else: stack.len2 - entry.depth = 1 - entry.path = bar2("") - bar3(entry.path) - proc processAux(a: float) = discard - template bar(iter: untyped): untyped = - var ret: float - for x in iter: - break - ret - const dir = "." - proc main() = - processAux(bar(globOpt(initGlobOpt(dir)))) - static: main() - -block: # bug #8015 - block: - type Foo = object - case b: bool - of false: v1: int - of true: v2: int - const t = [Foo(b: false, v1: 1), Foo(b: true, v2: 2)] - doAssert $t == "[(b: false, v1: 1), (b: true, v2: 2)]" - doAssert $t[0] == "(b: false, v1: 1)" # was failing - - block: - type - CostKind = enum - Fixed, - Dynamic - - Cost = object - case kind*: CostKind - of Fixed: - cost*: int - of Dynamic: - handler*: proc(): int {.nimcall.} - - proc foo1(): int {.nimcall.} = - 100 - - proc foo2(): int {.nimcall.} = - 200 - - # Change to `let` and it doesn't crash - const costTable = [ - 0: Cost(kind: Fixed, cost: 999), - 1: Cost(kind: Dynamic, handler: foo1), - 2: Cost(kind: Dynamic, handler: foo2) - ] - - doAssert $costTable[0] == "(kind: Fixed, cost: 999)" - doAssert costTable[1].handler() == 100 - doAssert costTable[2].handler() == 200 - - # Now trying to carry the table as an object field - type - Wrapper = object - table: array[3, Cost] - - proc procNewWrapper(): Wrapper = - result.table = costTable - - # Alternatively, change to `const` and it doesn't crash - let viaProc = procNewWrapper() - - doAssert viaProc.table[1].handler != nil - doAssert viaProc.table[2].handler != nil - doAssert $viaProc.table[0] == "(kind: Fixed, cost: 999)" - doAssert viaProc.table[1].handler() == 100 - doAssert viaProc.table[2].handler() == 200 - - -# bug #19198 - -block: - type - Foo[n: static int] = int - -block: - static: - let x = int 1 - doAssert $(x.type) == "Foo" # Foo - -block: - static: - let x = int 1 - let y = x + 1 - # Error: unhandled exception: value out of range: -8 notin 0 .. 65535 [RangeDefect] - doAssert y == 2 - - -type Atom* = object - bar: int - -proc main() = # bug #12994 - var s: seq[Atom] - var atom: Atom - var checked = 0 - for i in 0..<2: - atom.bar = 5 - s.add atom - atom.reset - if i == 0: - checked += 1 - doAssert $s == "@[(bar: 5)]" - else: - checked += 1 - doAssert $s == "@[(bar: 5), (bar: 5)]" - doAssert checked == 2 - -static: main() -main() - -# bug #19201 -proc foo(s: sink string) = doAssert s.len == 3 - -static: - foo("abc") - - -static: - for i in '1' .. '2': # bug #10938 - var s: set[char] - doAssert s == {} - incl(s, i) - - for _ in 0 ..< 3: # bug #13312 - var s: string - s.add("foo") - doAssert s == "foo" - - for i in 1 .. 5: # bug #13918 - var arr: array[3, int] - var val: int - doAssert arr == [0, 0, 0] and val == 0 - for j in 0 ..< len(arr): - arr[j] = i - val = i - -# bug #20985 -let a = block: - var groups: seq[seq[int]] - for i in 0 ..< 3: - var group: seq[int] - for j in 0 ..< 3: - group.add j - groups.add group - groups - -const b = block: - var groups: seq[seq[int]] - for i in 0 ..< 3: - var group: seq[int] - for j in 0 ..< 3: - group.add j - groups.add group - groups - -doAssert a == @[@[0, 1, 2], @[0, 1, 2], @[0, 1, 2]] -doAssert b == @[@[0, 1, 2], @[0, 1, 2], @[0, 1, 2]] - -macro m1(s: string): int = - var ProcID {.global, compileTime.}: int - inc(ProcID) - result = newLit(ProcID) - -proc macroGlobal = - doAssert m1("Macro argument") == 1 - doAssert m1("Macro argument") == 2 - doAssert m1("Macro argument") == 3 - -static: macroGlobal() -macroGlobal() diff --git a/tests/vm/tvmops.nim b/tests/vm/tvmops.nim index 3d8d5a9ac..6442c49d6 100644 --- a/tests/vm/tvmops.nim +++ b/tests/vm/tvmops.nim @@ -1,7 +1,3 @@ -discard """ - targets: "c cpp js" -""" - #[ test for vmops.nim ]# @@ -9,6 +5,16 @@ import os import math import strutils +template forceConst(a: untyped): untyped = + ## Force evaluation at CT, useful for example here: + ## `callFoo(forceConst(getBar1()), getBar2())` + ## instead of: + ## block: + ## const a = getBar1() + ## `callFoo(a, getBar2())` + const ret = a + ret + static: # TODO: add more tests block: #getAppFilename, gorgeEx, gorge @@ -16,7 +22,7 @@ static: let ret = gorgeEx(nim & " --version") doAssert ret.exitCode == 0 doAssert ret.output.contains "Nim Compiler" - let ret2 = gorgeEx(nim & " --nonxistent") + let ret2 = gorgeEx(nim & " --unexistant") doAssert ret2.exitCode != 0 let output3 = gorge(nim & " --version") doAssert output3.contains "Nim Compiler" @@ -41,6 +47,6 @@ static: block: # Check against bugs like #9176 - doAssert getCurrentCompilerExe() == getCurrentCompilerExe().static + doAssert getCurrentCompilerExe() == forceConst(getCurrentCompilerExe()) if false: #pending #9176 - doAssert gorgeEx("nonxistent") == gorgeEx("nonxistent").static + doAssert gorgeEx("unexistant") == forceConst(gorgeEx("unexistant")) diff --git a/tests/vm/tvmopsDanger.nim b/tests/vm/tvmopsDanger.nim deleted file mode 100644 index 5e7bac29a..000000000 --- a/tests/vm/tvmopsDanger.nim +++ /dev/null @@ -1,10 +0,0 @@ -discard """ - cmd: "nim c --experimental:vmopsDanger -r $file" -""" -when defined(nimPreviewSlimSystem): - import std/assertions -import std/times - -const foo = getTime() -let bar = foo -doAssert bar > low(Time) \ No newline at end of file diff --git a/tests/vm/twrong_concat.nim b/tests/vm/twrong_concat.nim index 59a10bdb9..538ea2527 100644 --- a/tests/vm/twrong_concat.nim +++ b/tests/vm/twrong_concat.nim @@ -1,3 +1,7 @@ +discard """ + output: '''success''' +""" + # bug #3804 #import sequtils @@ -19,4 +23,6 @@ static: sameBug(objs) # sameBug(objs) echo objs[0].field - doAssert(objs[0].field == "hello") # fails, because (objs[0].field == "hello bug") - mutated! + assert(objs[0].field == "hello") # fails, because (objs[0].field == "hello bug") - mutated! + +echo "success" diff --git a/tests/vm/twrongarray.nim b/tests/vm/twrongarray.nim index 7f24290e2..c1514d0e9 100644 --- a/tests/vm/twrongarray.nim +++ b/tests/vm/twrongarray.nim @@ -14,4 +14,4 @@ when false: proc two(dummy: int, size: int) = var x: array[size * 1, int] # compiles, but shouldn't? - # doAssert(x.len == size) # just for fun + #assert(x.len == size) # just for fun diff --git a/tests/vm/tyaytypedesc.nim b/tests/vm/tyaytypedesc.nim index 8cb402bff..a3ad9b707 100644 --- a/tests/vm/tyaytypedesc.nim +++ b/tests/vm/tyaytypedesc.nim @@ -1,3 +1,7 @@ +discard """ + output: "ntWhitespace" +""" + # bug #3357 type NodeType* = enum @@ -6,7 +10,7 @@ type NodeType* = enum type TokenType* = enum ttWhitespace -proc enumTable*[A, B, C](a: openArray[tuple[key: A, val: B]], ret: typedesc[C]): C = +proc enumTable*[A, B, C](a: openarray[tuple[key: A, val: B]], ret: typedesc[C]): C = for item in a: result[item.key] = item.val @@ -14,4 +18,4 @@ const tokenTypeToNodeType = { ttWhitespace: ntWhitespace, }.enumTable(array[ttWhitespace..ttWhitespace, NodeType]) -doAssert tokenTypeToNodeType[ttWhitespace] == ntWhitespace +echo tokenTypeToNodeType[ttWhitespace] diff --git a/tests/vm/tzero_extend.nim b/tests/vm/tzero_extend.nim index 418dbc486..1fed5d419 100644 --- a/tests/vm/tzero_extend.nim +++ b/tests/vm/tzero_extend.nim @@ -5,10 +5,10 @@ proc get_values(): (seq[int8], seq[int16], seq[int32]) = let i8 = -3'i8 let i16 = -3'i16 let i32 = -3'i32 - doAssert int(cast[uint8](i8)) == 0xFD - doAssert int64(cast[uint8](i8)) == 0xFD - doAssert int(cast[uint16](i16)) == 0xFFFD - doAssert int64(cast[uint16](i16)) == 0xFFFD + doAssert i8.ze == 0xFD + doAssert i8.ze64 == 0xFD + doAssert i16.ze == 0xFFFD + doAssert i16.ze64 == 0xFFFD result[0] = @[]; result[1] = @[]; result[2] = @[] diff --git a/tests/whenstmt/t12517.nim b/tests/whenstmt/t12517.nim deleted file mode 100644 index 8be0171e1..000000000 --- a/tests/whenstmt/t12517.nim +++ /dev/null @@ -1,21 +0,0 @@ -# Test based on issue #12517 - -discard """ - nimout: ''' -nimvm -both -''' - output: ''' -both -''' -""" - -proc test() = - when nimvm: - echo "nimvm" - echo "both" - -static: - test() -test() - diff --git a/tests/whenstmt/t19426.nim b/tests/whenstmt/t19426.nim deleted file mode 100644 index 95fb54a9e..000000000 --- a/tests/whenstmt/t19426.nim +++ /dev/null @@ -1,16 +0,0 @@ -type - MyInt = object - bitWidth: int - -template toRealType*(t: MyInt): typedesc = - when t.bitWidth == 32: int32 - elif t.bitWidth == 64: int64 - else: {.error.} - -proc doFail(T: typedesc): T = default(T) - -proc test = - const myInt = MyInt(bitWidth:32) - discard doFail(toRealType(myInt)) - -test() \ No newline at end of file diff --git a/tests/whenstmt/twhen.nim b/tests/whenstmt/twhen.nim deleted file mode 100644 index b155ddcfb..000000000 --- a/tests/whenstmt/twhen.nim +++ /dev/null @@ -1,47 +0,0 @@ -discard """ - nimout: ''' -nimvm - when -nimvm - whenElif -nimvm - whenElse -''' - output: ''' -when -whenElif -whenElse -''' -""" - -# test both when and when nimvm to ensure proper evaluation - -proc compileOrRuntimeProc(s: string) = - when nimvm: - echo "nimvm - " & s - else: - echo s - -template output(s: string) = - static: - compileOrRuntimeProc(s) - compileOrRuntimeProc(s) - -when compiles(1): - output("when") -elif compiles(2): - output("fail - whenElif") -else: - output("fail - whenElse") - -when compiles(nonexistent): - output("fail - when") -elif compiles(1): - output("whenElif") -else: - output("fail - whenElse") - -when compiles(nonexistent): - output("fail - when") -elif compiles(nonexistent): - output("fail - whenElif") -else: - output("whenElse") - diff --git a/tests/whenstmt/twhen_macro.nim b/tests/whenstmt/twhen_macro.nim deleted file mode 100644 index deb1dddc9..000000000 --- a/tests/whenstmt/twhen_macro.nim +++ /dev/null @@ -1,18 +0,0 @@ -import macros - -# test that when stmt works from within a macro - -macro output(s: string, xs: varargs[untyped]): auto = - result = quote do: - when compiles(`s`): - "when - " & `s` - elif compiles(`s`): - "elif - " & `s` - # should never get here so this should not break - broken.xs - else: - "else - " & `s` - # should never get here so this should not break - more.broken.xs - -doAssert output("test") == "when - test" \ No newline at end of file diff --git a/tests/xml/ttree_add.nim b/tests/xml/ttree_add.nim deleted file mode 100644 index 4c6ef6cf9..000000000 --- a/tests/xml/ttree_add.nim +++ /dev/null @@ -1,51 +0,0 @@ -discard """ - output: ''' - -
    Some text in body
    -
    Some more text in body
    - - - -
    Some text
    -
    Some more text
    - - -
    Some text in body
    -
    Some more text in body
    - -
    -''' -""" - -# Test xmltree add/insert/delete/replace operations -import xmlparser -import xmltree -var baseDocHead = """ - - -
    Some text
    -
    Some more text
    - -
    -""" -var baseDocHeadTree = parseXml(baseDocHead) -var baseDocBody = """ - -
    Some text in body
    -
    Some more text in body
    - -""" -var baseDocBodyTree = parseXml(baseDocBody) - -proc test_add() = - var testDoc = baseDocHeadTree - var newBody = newElement("body") - for item in baseDocBodyTree.items(): - newBody.add(item) - - echo $newBody - - testDoc.add(newBody) - echo $testDoc - -test_add() diff --git a/tests/xml/ttree_add1.nim b/tests/xml/ttree_add1.nim deleted file mode 100644 index 30ec83c02..000000000 --- a/tests/xml/ttree_add1.nim +++ /dev/null @@ -1,53 +0,0 @@ -discard """ - output: ''' - -
    Some text in body
    -
    Some more text in body
    - - - -
    Some text
    -
    Some more text
    - - -
    Some text in body
    -
    Some more text in body
    - -
    -''' -""" - -# Test xmltree add/insert/delete/replace operations -import xmlparser -import xmltree -var baseDocHead = """ - - -
    Some text
    -
    Some more text
    - -
    -""" -var baseDocHeadTree = parseXml(baseDocHead) -var baseDocBody = """ - -
    Some text in body
    -
    Some more text in body
    - -""" -var baseDocBodyTree = parseXml(baseDocBody) - -proc test_add() = - var testDoc = baseDocHeadTree - var newBody = newElement("body") - var bodyItems: seq[XmlNode] = @[] - for item in baseDocBodyTree.items(): - bodyItems.add(item) - newBody.add(bodyItems) - - echo $newBody - - testDoc.add(newBody) - echo $testDoc - -test_add() diff --git a/tests/xml/ttree_delete.nim b/tests/xml/ttree_delete.nim deleted file mode 100644 index 32b477839..000000000 --- a/tests/xml/ttree_delete.nim +++ /dev/null @@ -1,47 +0,0 @@ -discard """ - output: ''' - - -
    Some text
    -
    Some more text
    - - -
    Some text in body
    -
    Some more text in body
    - -
    -''' -""" - -# Test xmltree add/insert/delete/replace operations -import xmlparser -import xmltree -let initialDocBase = """ - - -
    Some text
    -
    Some more text
    - - -
    MORE TEXT
    -
    MORE TEXT Some more text
    -
    - -
    MORE TEXT
    -
    MORE TEXT Some more text
    -
    - -
    Some text in body
    -
    Some more text in body
    - -
    -""" -var initialDocBaseTree = parseXml(initialDocBase) - -proc test_delete() = - var testDoc = initialDocBaseTree - - testDoc.delete(1..2) - echo $testDoc - -test_delete() diff --git a/tests/xml/ttree_delete1.nim b/tests/xml/ttree_delete1.nim deleted file mode 100644 index a8442a093..000000000 --- a/tests/xml/ttree_delete1.nim +++ /dev/null @@ -1,48 +0,0 @@ -discard """ - output: ''' - - -
    Some text
    -
    Some more text
    - - -
    Some text in body
    -
    Some more text in body
    - -
    -''' -""" - -# Test xmltree add/insert/delete/replace operations -import xmlparser -import xmltree -let initialDocBase = """ - - -
    Some text
    -
    Some more text
    - - -
    MORE TEXT
    -
    MORE TEXT Some more text
    -
    - -
    MORE TEXT
    -
    MORE TEXT Some more text
    -
    - -
    Some text in body
    -
    Some more text in body
    - -
    -""" -var initialDocBaseTree = parseXml(initialDocBase) - -proc test_delete() = - var testDoc = initialDocBaseTree - - testDoc.delete(1) - testDoc.delete(1) - echo $testDoc - -test_delete() diff --git a/tests/xml/ttree_insert.nim b/tests/xml/ttree_insert.nim deleted file mode 100644 index b2941395b..000000000 --- a/tests/xml/ttree_insert.nim +++ /dev/null @@ -1,53 +0,0 @@ -discard """ - output: ''' - -
    Some text in body
    -
    Some more text in body
    - - - -
    Some text
    -
    Some more text
    - - -
    Some text in body
    -
    Some more text in body
    - -
    -''' -""" - -# Test xmltree add/insert/delete/replace operations -import xmlparser -import xmltree -var baseDocHead = """ - - -
    Some text
    -
    Some more text
    - -
    -""" -var baseDocHeadTree = parseXml(baseDocHead) -var baseDocBody = """ - -
    Some text in body
    -
    Some more text in body
    - -""" -var baseDocBodyTree = parseXml(baseDocBody) - -proc test_insert() = - var testDoc = baseDocHeadTree - var newBody = newElement("body") - var bodyItems: seq[XmlNode] = @[] - for item in baseDocBodyTree.items(): - bodyItems.insert(item, len(bodyItems)) - newBody.insert(bodyItems, 1) - - echo $newBody - - testDoc.insert(newBody, 1) - echo $testDoc - -test_insert() diff --git a/tests/xml/ttree_insert1.nim b/tests/xml/ttree_insert1.nim deleted file mode 100644 index 9aa3faf69..000000000 --- a/tests/xml/ttree_insert1.nim +++ /dev/null @@ -1,51 +0,0 @@ -discard """ - output: ''' - -
    Some text in body
    -
    Some more text in body
    - - - -
    Some text
    -
    Some more text
    - - -
    Some text in body
    -
    Some more text in body
    - -
    -''' -""" - -# Test xmltree add/insert/delete/replace operations -import xmlparser -import xmltree -var baseDocHead = """ - - -
    Some text
    -
    Some more text
    - -
    -""" -var baseDocHeadTree = parseXml(baseDocHead) -var baseDocBody = """ - -
    Some text in body
    -
    Some more text in body
    - -""" -var baseDocBodyTree = parseXml(baseDocBody) - -proc test_insert() = - var testDoc = baseDocHeadTree - var newBody = newElement("body") - for item in baseDocBodyTree.items(): - newBody.insert(item, len(newBody)) - - echo $newBody - - testDoc.insert(newBody, 1) - echo $testDoc - -test_insert() diff --git a/tests/xml/ttree_replace.nim b/tests/xml/ttree_replace.nim deleted file mode 100644 index 97d2db638..000000000 --- a/tests/xml/ttree_replace.nim +++ /dev/null @@ -1,46 +0,0 @@ -discard """ - output: ''' - - -
    Some text
    -
    Some more text
    - - -
    Some text in body
    -
    Some more text in body
    - -
    -''' -""" - -# Test xmltree add/insert/delete/replace operations -import xmlparser -import xmltree -var baseDocBody = """ - -
    Some text in body
    -
    Some more text in body
    - -""" -var baseDocBodyTree = parseXml(baseDocBody) -let initialDocBase = """ - - -
    Some text
    -
    Some more text
    - - -
    Some text in body before replace
    -
    Some more text in body before replace
    - -
    -""" -var initialDocBaseTree = parseXml(initialDocBase) - -proc test_replace() = - var testDoc = initialDocBaseTree - - testDoc.replace(1, @[baseDocBodyTree]) - echo $testDoc - -test_replace() diff --git a/tests/xml/ttree_replace1.nim b/tests/xml/ttree_replace1.nim deleted file mode 100644 index 059ce2085..000000000 --- a/tests/xml/ttree_replace1.nim +++ /dev/null @@ -1,53 +0,0 @@ -discard """ - output: ''' - - -
    Some text
    -
    Some more text
    - - -
    Some text in body
    -
    Some more text in body
    - -
    -''' -""" - -# Test xmltree add/insert/delete/replace operations -import xmlparser -import xmltree -var baseDocHead = """ - -
    Some text
    -
    Some more text
    - -""" -var baseDocHeadTree = parseXml(baseDocHead) -var baseDocBody = """ - -
    Some text in body
    -
    Some more text in body
    - -""" -var baseDocBodyTree = parseXml(baseDocBody) -let initialDocBase = """ - - -
    Some text before replace
    -
    Some more text before replace
    - - -
    Some text in body before replace
    -
    Some more text in body before replace
    - -
    -""" -var initialDocBaseTree = parseXml(initialDocBase) - -proc test_replace() = - var testDoc = initialDocBaseTree - - testDoc.replace(0..1, @[baseDocHeadTree, baseDocBodyTree]) - echo $testDoc - -test_replace() diff --git a/tinyc/arm-asm.c b/tinyc/arm-asm.c new file mode 100644 index 000000000..3b5ae661c --- /dev/null +++ b/tinyc/arm-asm.c @@ -0,0 +1,94 @@ +/*************************************************************/ +/* + * ARM dummy assembler for TCC + * + */ + +#ifdef TARGET_DEFS_ONLY + +#define CONFIG_TCC_ASM +#define NB_ASM_REGS 16 + +ST_FUNC void g(int c); +ST_FUNC void gen_le16(int c); +ST_FUNC void gen_le32(int c); + +/*************************************************************/ +#else +/*************************************************************/ + +#include "tcc.h" + +static void asm_error(void) +{ + tcc_error("ARM asm not implemented."); +} + +/* XXX: make it faster ? */ +ST_FUNC void g(int c) +{ + int ind1; + if (nocode_wanted) + return; + ind1 = ind + 1; + if (ind1 > cur_text_section->data_allocated) + section_realloc(cur_text_section, ind1); + cur_text_section->data[ind] = c; + ind = ind1; +} + +ST_FUNC void gen_le16 (int i) +{ + g(i); + g(i>>8); +} + +ST_FUNC void gen_le32 (int i) +{ + gen_le16(i); + gen_le16(i>>16); +} + +ST_FUNC void gen_expr32(ExprValue *pe) +{ + gen_le32(pe->v); +} + +ST_FUNC void asm_opcode(TCCState *s1, int opcode) +{ + asm_error(); +} + +ST_FUNC void subst_asm_operand(CString *add_str, SValue *sv, int modifier) +{ + asm_error(); +} + +/* generate prolog and epilog code for asm statement */ +ST_FUNC void asm_gen_code(ASMOperand *operands, int nb_operands, + int nb_outputs, int is_output, + uint8_t *clobber_regs, + int out_reg) +{ +} + +ST_FUNC void asm_compute_constraints(ASMOperand *operands, + int nb_operands, int nb_outputs, + const uint8_t *clobber_regs, + int *pout_reg) +{ +} + +ST_FUNC void asm_clobber(uint8_t *clobber_regs, const char *str) +{ + asm_error(); +} + +ST_FUNC int asm_parse_regvar (int t) +{ + asm_error(); + return -1; +} + +/*************************************************************/ +#endif /* ndef TARGET_DEFS_ONLY */ diff --git a/tinyc/arm-gen.c b/tinyc/arm-gen.c new file mode 100644 index 000000000..f535a09ce --- /dev/null +++ b/tinyc/arm-gen.c @@ -0,0 +1,2151 @@ +/* + * ARMv4 code generator for TCC + * + * Copyright (c) 2003 Daniel Glöckner + * Copyright (c) 2012 Thomas Preud'homme + * + * Based on i386-gen.c by Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifdef TARGET_DEFS_ONLY + +#if defined(TCC_ARM_EABI) && !defined(TCC_ARM_VFP) +#error "Currently TinyCC only supports float computation with VFP instructions" +#endif + +/* number of available registers */ +#ifdef TCC_ARM_VFP +#define NB_REGS 13 +#else +#define NB_REGS 9 +#endif + +#ifndef TCC_CPU_VERSION +# define TCC_CPU_VERSION 5 +#endif + +/* a register can belong to several classes. The classes must be + sorted from more general to more precise (see gv2() code which does + assumptions on it). */ +#define RC_INT 0x0001 /* generic integer register */ +#define RC_FLOAT 0x0002 /* generic float register */ +#define RC_R0 0x0004 +#define RC_R1 0x0008 +#define RC_R2 0x0010 +#define RC_R3 0x0020 +#define RC_R12 0x0040 +#define RC_F0 0x0080 +#define RC_F1 0x0100 +#define RC_F2 0x0200 +#define RC_F3 0x0400 +#ifdef TCC_ARM_VFP +#define RC_F4 0x0800 +#define RC_F5 0x1000 +#define RC_F6 0x2000 +#define RC_F7 0x4000 +#endif +#define RC_IRET RC_R0 /* function return: integer register */ +#define RC_LRET RC_R1 /* function return: second integer register */ +#define RC_FRET RC_F0 /* function return: float register */ + +/* pretty names for the registers */ +enum { + TREG_R0 = 0, + TREG_R1, + TREG_R2, + TREG_R3, + TREG_R12, + TREG_F0, + TREG_F1, + TREG_F2, + TREG_F3, +#ifdef TCC_ARM_VFP + TREG_F4, + TREG_F5, + TREG_F6, + TREG_F7, +#endif + TREG_SP = 13, + TREG_LR, +}; + +#ifdef TCC_ARM_VFP +#define T2CPR(t) (((t) & VT_BTYPE) != VT_FLOAT ? 0x100 : 0) +#endif + +/* return registers for function */ +#define REG_IRET TREG_R0 /* single word int return register */ +#define REG_LRET TREG_R1 /* second word return register (for long long) */ +#define REG_FRET TREG_F0 /* float return register */ + +#ifdef TCC_ARM_EABI +#define TOK___divdi3 TOK___aeabi_ldivmod +#define TOK___moddi3 TOK___aeabi_ldivmod +#define TOK___udivdi3 TOK___aeabi_uldivmod +#define TOK___umoddi3 TOK___aeabi_uldivmod +#endif + +/* defined if function parameters must be evaluated in reverse order */ +#define INVERT_FUNC_PARAMS + +/* defined if structures are passed as pointers. Otherwise structures + are directly pushed on stack. */ +/* #define FUNC_STRUCT_PARAM_AS_PTR */ + +/* pointer size, in bytes */ +#define PTR_SIZE 4 + +/* long double size and alignment, in bytes */ +#ifdef TCC_ARM_VFP +#define LDOUBLE_SIZE 8 +#endif + +#ifndef LDOUBLE_SIZE +#define LDOUBLE_SIZE 8 +#endif + +#ifdef TCC_ARM_EABI +#define LDOUBLE_ALIGN 8 +#else +#define LDOUBLE_ALIGN 4 +#endif + +/* maximum alignment (for aligned attribute support) */ +#define MAX_ALIGN 8 + +#define CHAR_IS_UNSIGNED + +/******************************************************/ +#else /* ! TARGET_DEFS_ONLY */ +/******************************************************/ +#include "tcc.h" + +enum float_abi float_abi; + +ST_DATA const int reg_classes[NB_REGS] = { + /* r0 */ RC_INT | RC_R0, + /* r1 */ RC_INT | RC_R1, + /* r2 */ RC_INT | RC_R2, + /* r3 */ RC_INT | RC_R3, + /* r12 */ RC_INT | RC_R12, + /* f0 */ RC_FLOAT | RC_F0, + /* f1 */ RC_FLOAT | RC_F1, + /* f2 */ RC_FLOAT | RC_F2, + /* f3 */ RC_FLOAT | RC_F3, +#ifdef TCC_ARM_VFP + /* d4/s8 */ RC_FLOAT | RC_F4, +/* d5/s10 */ RC_FLOAT | RC_F5, +/* d6/s12 */ RC_FLOAT | RC_F6, +/* d7/s14 */ RC_FLOAT | RC_F7, +#endif +}; + +static int func_sub_sp_offset, last_itod_magic; +static int leaffunc; + +#if defined(TCC_ARM_EABI) && defined(TCC_ARM_VFP) +static CType float_type, double_type, func_float_type, func_double_type; +ST_FUNC void arm_init(struct TCCState *s) +{ + float_type.t = VT_FLOAT; + double_type.t = VT_DOUBLE; + func_float_type.t = VT_FUNC; + func_float_type.ref = sym_push(SYM_FIELD, &float_type, FUNC_CDECL, FUNC_OLD); + func_double_type.t = VT_FUNC; + func_double_type.ref = sym_push(SYM_FIELD, &double_type, FUNC_CDECL, FUNC_OLD); + + float_abi = s->float_abi; +#ifndef TCC_ARM_HARDFLOAT + tcc_warning("soft float ABI currently not supported: default to softfp"); +#endif +} +#else +#define func_float_type func_old_type +#define func_double_type func_old_type +#define func_ldouble_type func_old_type +ST_FUNC void arm_init(struct TCCState *s) +{ +#if 0 +#if !defined (TCC_ARM_VFP) + tcc_warning("Support for FPA is deprecated and will be removed in next" + " release"); +#endif +#if !defined (TCC_ARM_EABI) + tcc_warning("Support for OABI is deprecated and will be removed in next" + " release"); +#endif +#endif +} +#endif + +static int two2mask(int a,int b) { + return (reg_classes[a]|reg_classes[b])&~(RC_INT|RC_FLOAT); +} + +static int regmask(int r) { + return reg_classes[r]&~(RC_INT|RC_FLOAT); +} + +/******************************************************/ + +#if defined(TCC_ARM_EABI) && !defined(CONFIG_TCC_ELFINTERP) +const char *default_elfinterp(struct TCCState *s) +{ + if (s->float_abi == ARM_HARD_FLOAT) + return "/lib/ld-linux-armhf.so.3"; + else + return "/lib/ld-linux.so.3"; +} +#endif + +void o(uint32_t i) +{ + /* this is a good place to start adding big-endian support*/ + int ind1; + if (nocode_wanted) + return; + ind1 = ind + 4; + if (!cur_text_section) + tcc_error("compiler error! This happens f.ex. if the compiler\n" + "can't evaluate constant expressions outside of a function."); + if (ind1 > cur_text_section->data_allocated) + section_realloc(cur_text_section, ind1); + cur_text_section->data[ind++] = i&255; + i>>=8; + cur_text_section->data[ind++] = i&255; + i>>=8; + cur_text_section->data[ind++] = i&255; + i>>=8; + cur_text_section->data[ind++] = i; +} + +static uint32_t stuff_const(uint32_t op, uint32_t c) +{ + int try_neg=0; + uint32_t nc = 0, negop = 0; + + switch(op&0x1F00000) + { + case 0x800000: //add + case 0x400000: //sub + try_neg=1; + negop=op^0xC00000; + nc=-c; + break; + case 0x1A00000: //mov + case 0x1E00000: //mvn + try_neg=1; + negop=op^0x400000; + nc=~c; + break; + case 0x200000: //xor + if(c==~0) + return (op&0xF010F000)|((op>>16)&0xF)|0x1E00000; + break; + case 0x0: //and + if(c==~0) + return (op&0xF010F000)|((op>>16)&0xF)|0x1A00000; + case 0x1C00000: //bic + try_neg=1; + negop=op^0x1C00000; + nc=~c; + break; + case 0x1800000: //orr + if(c==~0) + return (op&0xFFF0FFFF)|0x1E00000; + break; + } + do { + uint32_t m; + int i; + if(c<256) /* catch undefined <<32 */ + return op|c; + for(i=2;i<32;i+=2) { + m=(0xff>>i)|(0xff<<(32-i)); + if(!(c&~m)) + return op|(i<<7)|(c<>(32-i)); + } + op=negop; + c=nc; + } while(try_neg--); + return 0; +} + + +//only add,sub +void stuff_const_harder(uint32_t op, uint32_t v) { + uint32_t x; + x=stuff_const(op,v); + if(x) + o(x); + else { + uint32_t a[16], nv, no, o2, n2; + int i,j,k; + a[0]=0xff; + o2=(op&0xfff0ffff)|((op&0xf000)<<4);; + for(i=1;i<16;i++) + a[i]=(a[i-1]>>2)|(a[i-1]<<30); + for(i=0;i<12;i++) + for(j=i<4?i+12:15;j>=i+4;j--) + if((v&(a[i]|a[j]))==v) { + o(stuff_const(op,v&a[i])); + o(stuff_const(o2,v&a[j])); + return; + } + no=op^0xC00000; + n2=o2^0xC00000; + nv=-v; + for(i=0;i<12;i++) + for(j=i<4?i+12:15;j>=i+4;j--) + if((nv&(a[i]|a[j]))==nv) { + o(stuff_const(no,nv&a[i])); + o(stuff_const(n2,nv&a[j])); + return; + } + for(i=0;i<8;i++) + for(j=i+4;j<12;j++) + for(k=i<4?i+12:15;k>=j+4;k--) + if((v&(a[i]|a[j]|a[k]))==v) { + o(stuff_const(op,v&a[i])); + o(stuff_const(o2,v&a[j])); + o(stuff_const(o2,v&a[k])); + return; + } + no=op^0xC00000; + nv=-v; + for(i=0;i<8;i++) + for(j=i+4;j<12;j++) + for(k=i<4?i+12:15;k>=j+4;k--) + if((nv&(a[i]|a[j]|a[k]))==nv) { + o(stuff_const(no,nv&a[i])); + o(stuff_const(n2,nv&a[j])); + o(stuff_const(n2,nv&a[k])); + return; + } + o(stuff_const(op,v&a[0])); + o(stuff_const(o2,v&a[4])); + o(stuff_const(o2,v&a[8])); + o(stuff_const(o2,v&a[12])); + } +} + +uint32_t encbranch(int pos, int addr, int fail) +{ + addr-=pos+8; + addr/=4; + if(addr>=0x1000000 || addr<-0x1000000) { + if(fail) + tcc_error("FIXME: function bigger than 32MB"); + return 0; + } + return 0x0A000000|(addr&0xffffff); +} + +int decbranch(int pos) +{ + int x; + x=*(uint32_t *)(cur_text_section->data + pos); + x&=0x00ffffff; + if(x&0x800000) + x-=0x1000000; + return x*4+pos+8; +} + +/* output a symbol and patch all calls to it */ +void gsym_addr(int t, int a) +{ + uint32_t *x; + int lt; + while(t) { + x=(uint32_t *)(cur_text_section->data + t); + t=decbranch(lt=t); + if(a==lt+4) + *x=0xE1A00000; // nop + else { + *x &= 0xff000000; + *x |= encbranch(lt,a,1); + } + } +} + +void gsym(int t) +{ + gsym_addr(t, ind); +} + +#ifdef TCC_ARM_VFP +static uint32_t vfpr(int r) +{ + if(rTREG_F7) + tcc_error("compiler error! register %i is no vfp register",r); + return r - TREG_F0; +} +#else +static uint32_t fpr(int r) +{ + if(rTREG_F3) + tcc_error("compiler error! register %i is no fpa register",r); + return r - TREG_F0; +} +#endif + +static uint32_t intr(int r) +{ + if(r == TREG_R12) + return 12; + if(r >= TREG_R0 && r <= TREG_R3) + return r - TREG_R0; + if (r >= TREG_SP && r <= TREG_LR) + return r + (13 - TREG_SP); + tcc_error("compiler error! register %i is no int register",r); +} + +static void calcaddr(uint32_t *base, int *off, int *sgn, int maxoff, unsigned shift) +{ + if(*off>maxoff || *off&((1<r; + ft = sv->type.t; + fc = sv->c.i; + + if(fc>=0) + sign=0; + else { + sign=1; + fc=-fc; + } + + v = fr & VT_VALMASK; + if (fr & VT_LVAL) { + uint32_t base = 0xB; // fp + if(v == VT_LLOCAL) { + v1.type.t = VT_PTR; + v1.r = VT_LOCAL | VT_LVAL; + v1.c.i = sv->c.i; + load(TREG_LR, &v1); + base = 14; /* lr */ + fc=sign=0; + v=VT_LOCAL; + } else if(v == VT_CONST) { + v1.type.t = VT_PTR; + v1.r = fr&~VT_LVAL; + v1.c.i = sv->c.i; + v1.sym=sv->sym; + load(TREG_LR, &v1); + base = 14; /* lr */ + fc=sign=0; + v=VT_LOCAL; + } else if(v < VT_CONST) { + base=intr(v); + fc=sign=0; + v=VT_LOCAL; + } + if(v == VT_LOCAL) { + if(is_float(ft)) { + calcaddr(&base,&fc,&sign,1020,2); +#ifdef TCC_ARM_VFP + op=0xED100A00; /* flds */ + if(!sign) + op|=0x800000; + if ((ft & VT_BTYPE) != VT_FLOAT) + op|=0x100; /* flds -> fldd */ + o(op|(vfpr(r)<<12)|(fc>>2)|(base<<16)); +#else + op=0xED100100; + if(!sign) + op|=0x800000; +#if LDOUBLE_SIZE == 8 + if ((ft & VT_BTYPE) != VT_FLOAT) + op|=0x8000; +#else + if ((ft & VT_BTYPE) == VT_DOUBLE) + op|=0x8000; + else if ((ft & VT_BTYPE) == VT_LDOUBLE) + op|=0x400000; +#endif + o(op|(fpr(r)<<12)|(fc>>2)|(base<<16)); +#endif + } else if((ft & (VT_BTYPE|VT_UNSIGNED)) == VT_BYTE + || (ft & VT_BTYPE) == VT_SHORT) { + calcaddr(&base,&fc,&sign,255,0); + op=0xE1500090; + if ((ft & VT_BTYPE) == VT_SHORT) + op|=0x20; + if ((ft & VT_UNSIGNED) == 0) + op|=0x40; + if(!sign) + op|=0x800000; + o(op|(intr(r)<<12)|(base<<16)|((fc&0xf0)<<4)|(fc&0xf)); + } else { + calcaddr(&base,&fc,&sign,4095,0); + op=0xE5100000; + if(!sign) + op|=0x800000; + if ((ft & VT_BTYPE) == VT_BYTE || (ft & VT_BTYPE) == VT_BOOL) + op|=0x400000; + o(op|(intr(r)<<12)|fc|(base<<16)); + } + return; + } + } else { + if (v == VT_CONST) { + op=stuff_const(0xE3A00000|(intr(r)<<12),sv->c.i); + if (fr & VT_SYM || !op) { + o(0xE59F0000|(intr(r)<<12)); + o(0xEA000000); + if(fr & VT_SYM) + greloc(cur_text_section, sv->sym, ind, R_ARM_ABS32); + o(sv->c.i); + } else + o(op); + return; + } else if (v == VT_LOCAL) { + op=stuff_const(0xE28B0000|(intr(r)<<12),sv->c.i); + if (fr & VT_SYM || !op) { + o(0xE59F0000|(intr(r)<<12)); + o(0xEA000000); + if(fr & VT_SYM) // needed ? + greloc(cur_text_section, sv->sym, ind, R_ARM_ABS32); + o(sv->c.i); + o(0xE08B0000|(intr(r)<<12)|intr(r)); + } else + o(op); + return; + } else if(v == VT_CMP) { + o(mapcc(sv->c.i)|0x3A00001|(intr(r)<<12)); + o(mapcc(negcc(sv->c.i))|0x3A00000|(intr(r)<<12)); + return; + } else if (v == VT_JMP || v == VT_JMPI) { + int t; + t = v & 1; + o(0xE3A00000|(intr(r)<<12)|t); + o(0xEA000000); + gsym(sv->c.i); + o(0xE3A00000|(intr(r)<<12)|(t^1)); + return; + } else if (v < VT_CONST) { + if(is_float(ft)) +#ifdef TCC_ARM_VFP + o(0xEEB00A40|(vfpr(r)<<12)|vfpr(v)|T2CPR(ft)); /* fcpyX */ +#else + o(0xEE008180|(fpr(r)<<12)|fpr(v)); +#endif + else + o(0xE1A00000|(intr(r)<<12)|intr(v)); + return; + } + } + tcc_error("load unimplemented!"); +} + +/* store register 'r' in lvalue 'v' */ +void store(int r, SValue *sv) +{ + SValue v1; + int v, ft, fc, fr, sign; + uint32_t op; + + fr = sv->r; + ft = sv->type.t; + fc = sv->c.i; + + if(fc>=0) + sign=0; + else { + sign=1; + fc=-fc; + } + + v = fr & VT_VALMASK; + if (fr & VT_LVAL || fr == VT_LOCAL) { + uint32_t base = 0xb; /* fp */ + if(v < VT_CONST) { + base=intr(v); + v=VT_LOCAL; + fc=sign=0; + } else if(v == VT_CONST) { + v1.type.t = ft; + v1.r = fr&~VT_LVAL; + v1.c.i = sv->c.i; + v1.sym=sv->sym; + load(TREG_LR, &v1); + base = 14; /* lr */ + fc=sign=0; + v=VT_LOCAL; + } + if(v == VT_LOCAL) { + if(is_float(ft)) { + calcaddr(&base,&fc,&sign,1020,2); +#ifdef TCC_ARM_VFP + op=0xED000A00; /* fsts */ + if(!sign) + op|=0x800000; + if ((ft & VT_BTYPE) != VT_FLOAT) + op|=0x100; /* fsts -> fstd */ + o(op|(vfpr(r)<<12)|(fc>>2)|(base<<16)); +#else + op=0xED000100; + if(!sign) + op|=0x800000; +#if LDOUBLE_SIZE == 8 + if ((ft & VT_BTYPE) != VT_FLOAT) + op|=0x8000; +#else + if ((ft & VT_BTYPE) == VT_DOUBLE) + op|=0x8000; + if ((ft & VT_BTYPE) == VT_LDOUBLE) + op|=0x400000; +#endif + o(op|(fpr(r)<<12)|(fc>>2)|(base<<16)); +#endif + return; + } else if((ft & VT_BTYPE) == VT_SHORT) { + calcaddr(&base,&fc,&sign,255,0); + op=0xE14000B0; + if(!sign) + op|=0x800000; + o(op|(intr(r)<<12)|(base<<16)|((fc&0xf0)<<4)|(fc&0xf)); + } else { + calcaddr(&base,&fc,&sign,4095,0); + op=0xE5000000; + if(!sign) + op|=0x800000; + if ((ft & VT_BTYPE) == VT_BYTE || (ft & VT_BTYPE) == VT_BOOL) + op|=0x400000; + o(op|(intr(r)<<12)|fc|(base<<16)); + } + return; + } + } + tcc_error("store unimplemented"); +} + +static void gadd_sp(int val) +{ + stuff_const_harder(0xE28DD000,val); +} + +/* 'is_jmp' is '1' if it is a jump */ +static void gcall_or_jmp(int is_jmp) +{ + int r; + if ((vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST) { + uint32_t x; + /* constant case */ + x=encbranch(ind,ind+vtop->c.i,0); + if(x) { + if (vtop->r & VT_SYM) { + /* relocation case */ + greloc(cur_text_section, vtop->sym, ind, R_ARM_PC24); + } else + put_elf_reloc(symtab_section, cur_text_section, ind, R_ARM_PC24, 0); + o(x|(is_jmp?0xE0000000:0xE1000000)); + } else { + if(!is_jmp) + o(0xE28FE004); // add lr,pc,#4 + o(0xE51FF004); // ldr pc,[pc,#-4] + if (vtop->r & VT_SYM) + greloc(cur_text_section, vtop->sym, ind, R_ARM_ABS32); + o(vtop->c.i); + } + } else { + /* otherwise, indirect call */ + r = gv(RC_INT); + if(!is_jmp) + o(0xE1A0E00F); // mov lr,pc + o(0xE1A0F000|intr(r)); // mov pc,r + } +} + +static int unalias_ldbl(int btype) +{ +#if LDOUBLE_SIZE == 8 + if (btype == VT_LDOUBLE) + btype = VT_DOUBLE; +#endif + return btype; +} + +/* Return whether a structure is an homogeneous float aggregate or not. + The answer is true if all the elements of the structure are of the same + primitive float type and there is less than 4 elements. + + type: the type corresponding to the structure to be tested */ +static int is_hgen_float_aggr(CType *type) +{ + if ((type->t & VT_BTYPE) == VT_STRUCT) { + struct Sym *ref; + int btype, nb_fields = 0; + + ref = type->ref->next; + btype = unalias_ldbl(ref->type.t & VT_BTYPE); + if (btype == VT_FLOAT || btype == VT_DOUBLE) { + for(; ref && btype == unalias_ldbl(ref->type.t & VT_BTYPE); ref = ref->next, nb_fields++); + return !ref && nb_fields <= 4; + } + } + return 0; +} + +struct avail_regs { + signed char avail[3]; /* 3 holes max with only float and double alignments */ + int first_hole; /* first available hole */ + int last_hole; /* last available hole (none if equal to first_hole) */ + int first_free_reg; /* next free register in the sequence, hole excluded */ +}; + +#define AVAIL_REGS_INITIALIZER (struct avail_regs) { { 0, 0, 0}, 0, 0, 0 } + +/* Find suitable registers for a VFP Co-Processor Register Candidate (VFP CPRC + param) according to the rules described in the procedure call standard for + the ARM architecture (AAPCS). If found, the registers are assigned to this + VFP CPRC parameter. Registers are allocated in sequence unless a hole exists + and the parameter is a single float. + + avregs: opaque structure to keep track of available VFP co-processor regs + align: alignment constraints for the param, as returned by type_size() + size: size of the parameter, as returned by type_size() */ +int assign_vfpreg(struct avail_regs *avregs, int align, int size) +{ + int first_reg = 0; + + if (avregs->first_free_reg == -1) + return -1; + if (align >> 3) { /* double alignment */ + first_reg = avregs->first_free_reg; + /* alignment constraint not respected so use next reg and record hole */ + if (first_reg & 1) + avregs->avail[avregs->last_hole++] = first_reg++; + } else { /* no special alignment (float or array of float) */ + /* if single float and a hole is available, assign the param to it */ + if (size == 4 && avregs->first_hole != avregs->last_hole) + return avregs->avail[avregs->first_hole++]; + else + first_reg = avregs->first_free_reg; + } + if (first_reg + size / 4 <= 16) { + avregs->first_free_reg = first_reg + size / 4; + return first_reg; + } + avregs->first_free_reg = -1; + return -1; +} + +/* Returns whether all params need to be passed in core registers or not. + This is the case for function part of the runtime ABI. */ +int floats_in_core_regs(SValue *sval) +{ + if (!sval->sym) + return 0; + + switch (sval->sym->v) { + case TOK___floatundisf: + case TOK___floatundidf: + case TOK___fixunssfdi: + case TOK___fixunsdfdi: +#ifndef TCC_ARM_VFP + case TOK___fixunsxfdi: +#endif + case TOK___floatdisf: + case TOK___floatdidf: + case TOK___fixsfdi: + case TOK___fixdfdi: + return 1; + + default: + return 0; + } +} + +/* Return the number of registers needed to return the struct, or 0 if + returning via struct pointer. */ +ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *ret_align, int *regsize) { +#ifdef TCC_ARM_EABI + int size, align; + size = type_size(vt, &align); + if (float_abi == ARM_HARD_FLOAT && !variadic && + (is_float(vt->t) || is_hgen_float_aggr(vt))) { + *ret_align = 8; + *regsize = 8; + ret->ref = NULL; + ret->t = VT_DOUBLE; + return (size + 7) >> 3; + } else if (size <= 4) { + *ret_align = 4; + *regsize = 4; + ret->ref = NULL; + ret->t = VT_INT; + return 1; + } else + return 0; +#else + return 0; +#endif +} + +/* Parameters are classified according to how they are copied to their final + destination for the function call. Because the copying is performed class + after class according to the order in the union below, it is important that + some constraints about the order of the members of this union are respected: + - CORE_STRUCT_CLASS must come after STACK_CLASS; + - CORE_CLASS must come after STACK_CLASS, CORE_STRUCT_CLASS and + VFP_STRUCT_CLASS; + - VFP_STRUCT_CLASS must come after VFP_CLASS. + See the comment for the main loop in copy_params() for the reason. */ +enum reg_class { + STACK_CLASS = 0, + CORE_STRUCT_CLASS, + VFP_CLASS, + VFP_STRUCT_CLASS, + CORE_CLASS, + NB_CLASSES +}; + +struct param_plan { + int start; /* first reg or addr used depending on the class */ + int end; /* last reg used or next free addr depending on the class */ + SValue *sval; /* pointer to SValue on the value stack */ + struct param_plan *prev; /* previous element in this class */ +}; + +struct plan { + struct param_plan *pplans; /* array of all the param plans */ + struct param_plan *clsplans[NB_CLASSES]; /* per class lists of param plans */ +}; + +#define add_param_plan(plan,pplan,class) \ + do { \ + pplan.prev = plan->clsplans[class]; \ + plan->pplans[plan ## _nb] = pplan; \ + plan->clsplans[class] = &plan->pplans[plan ## _nb++]; \ + } while(0) + +/* Assign parameters to registers and stack with alignment according to the + rules in the procedure call standard for the ARM architecture (AAPCS). + The overall assignment is recorded in an array of per parameter structures + called parameter plans. The parameter plans are also further organized in a + number of linked lists, one per class of parameter (see the comment for the + definition of union reg_class). + + nb_args: number of parameters of the function for which a call is generated + float_abi: float ABI in use for this function call + plan: the structure where the overall assignment is recorded + todo: a bitmap that record which core registers hold a parameter + + Returns the amount of stack space needed for parameter passing + + Note: this function allocated an array in plan->pplans with tcc_malloc. It + is the responsibility of the caller to free this array once used (ie not + before copy_params). */ +static int assign_regs(int nb_args, int float_abi, struct plan *plan, int *todo) +{ + int i, size, align; + int ncrn /* next core register number */, nsaa /* next stacked argument address*/; + int plan_nb = 0; + struct param_plan pplan; + struct avail_regs avregs = AVAIL_REGS_INITIALIZER; + + ncrn = nsaa = 0; + *todo = 0; + plan->pplans = tcc_malloc(nb_args * sizeof(*plan->pplans)); + memset(plan->clsplans, 0, sizeof(plan->clsplans)); + for(i = nb_args; i-- ;) { + int j, start_vfpreg = 0; + CType type = vtop[-i].type; + type.t &= ~VT_ARRAY; + size = type_size(&type, &align); + size = (size + 3) & ~3; + align = (align + 3) & ~3; + switch(vtop[-i].type.t & VT_BTYPE) { + case VT_STRUCT: + case VT_FLOAT: + case VT_DOUBLE: + case VT_LDOUBLE: + if (float_abi == ARM_HARD_FLOAT) { + int is_hfa = 0; /* Homogeneous float aggregate */ + + if (is_float(vtop[-i].type.t) + || (is_hfa = is_hgen_float_aggr(&vtop[-i].type))) { + int end_vfpreg; + + start_vfpreg = assign_vfpreg(&avregs, align, size); + end_vfpreg = start_vfpreg + ((size - 1) >> 2); + if (start_vfpreg >= 0) { + pplan = (struct param_plan) {start_vfpreg, end_vfpreg, &vtop[-i]}; + if (is_hfa) + add_param_plan(plan, pplan, VFP_STRUCT_CLASS); + else + add_param_plan(plan, pplan, VFP_CLASS); + continue; + } else + break; + } + } + ncrn = (ncrn + (align-1)/4) & ~((align/4) - 1); + if (ncrn + size/4 <= 4 || (ncrn < 4 && start_vfpreg != -1)) { + /* The parameter is allocated both in core register and on stack. As + * such, it can be of either class: it would either be the last of + * CORE_STRUCT_CLASS or the first of STACK_CLASS. */ + for (j = ncrn; j < 4 && j < ncrn + size / 4; j++) + *todo|=(1< 4) + nsaa = (ncrn - 4) * 4; + } else { + ncrn = 4; + break; + } + continue; + default: + if (ncrn < 4) { + int is_long = (vtop[-i].type.t & VT_BTYPE) == VT_LLONG; + + if (is_long) { + ncrn = (ncrn + 1) & -2; + if (ncrn == 4) + break; + } + pplan = (struct param_plan) {ncrn, ncrn, &vtop[-i]}; + ncrn++; + if (is_long) + pplan.end = ncrn++; + add_param_plan(plan, pplan, CORE_CLASS); + continue; + } + } + nsaa = (nsaa + (align - 1)) & ~(align - 1); + pplan = (struct param_plan) {nsaa, nsaa + size, &vtop[-i]}; + add_param_plan(plan, pplan, STACK_CLASS); + nsaa += size; /* size already rounded up before */ + } + return nsaa; +} + +#undef add_param_plan + +/* Copy parameters to their final destination (core reg, VFP reg or stack) for + function call. + + nb_args: number of parameters the function take + plan: the overall assignment plan for parameters + todo: a bitmap indicating what core reg will hold a parameter + + Returns the number of SValue added by this function on the value stack */ +static int copy_params(int nb_args, struct plan *plan, int todo) +{ + int size, align, r, i, nb_extra_sval = 0; + struct param_plan *pplan; + int pass = 0; + + /* Several constraints require parameters to be copied in a specific order: + - structures are copied to the stack before being loaded in a reg; + - floats loaded to an odd numbered VFP reg are first copied to the + preceding even numbered VFP reg and then moved to the next VFP reg. + + It is thus important that: + - structures assigned to core regs must be copied after parameters + assigned to the stack but before structures assigned to VFP regs because + a structure can lie partly in core registers and partly on the stack; + - parameters assigned to the stack and all structures be copied before + parameters assigned to a core reg since copying a parameter to the stack + require using a core reg; + - parameters assigned to VFP regs be copied before structures assigned to + VFP regs as the copy might use an even numbered VFP reg that already + holds part of a structure. */ +again: + for(i = 0; i < NB_CLASSES; i++) { + for(pplan = plan->clsplans[i]; pplan; pplan = pplan->prev) { + + if (pass + && (i != CORE_CLASS || pplan->sval->r < VT_CONST)) + continue; + + vpushv(pplan->sval); + pplan->sval->r = pplan->sval->r2 = VT_CONST; /* disable entry */ + switch(i) { + case STACK_CLASS: + case CORE_STRUCT_CLASS: + case VFP_STRUCT_CLASS: + if ((pplan->sval->type.t & VT_BTYPE) == VT_STRUCT) { + int padding = 0; + size = type_size(&pplan->sval->type, &align); + /* align to stack align size */ + size = (size + 3) & ~3; + if (i == STACK_CLASS && pplan->prev) + padding = pplan->start - pplan->prev->end; + size += padding; /* Add padding if any */ + /* allocate the necessary size on stack */ + gadd_sp(-size); + /* generate structure store */ + r = get_reg(RC_INT); + o(0xE28D0000|(intr(r)<<12)|padding); /* add r, sp, padding */ + vset(&vtop->type, r | VT_LVAL, 0); + vswap(); + vstore(); /* memcpy to current sp + potential padding */ + + /* Homogeneous float aggregate are loaded to VFP registers + immediately since there is no way of loading data in multiple + non consecutive VFP registers as what is done for other + structures (see the use of todo). */ + if (i == VFP_STRUCT_CLASS) { + int first = pplan->start, nb = pplan->end - first + 1; + /* vpop.32 {pplan->start, ..., pplan->end} */ + o(0xECBD0A00|(first&1)<<22|(first>>1)<<12|nb); + /* No need to write the register used to a SValue since VFP regs + cannot be used for gcall_or_jmp */ + } + } else { + if (is_float(pplan->sval->type.t)) { +#ifdef TCC_ARM_VFP + r = vfpr(gv(RC_FLOAT)) << 12; + if ((pplan->sval->type.t & VT_BTYPE) == VT_FLOAT) + size = 4; + else { + size = 8; + r |= 0x101; /* vpush.32 -> vpush.64 */ + } + o(0xED2D0A01 + r); /* vpush */ +#else + r = fpr(gv(RC_FLOAT)) << 12; + if ((pplan->sval->type.t & VT_BTYPE) == VT_FLOAT) + size = 4; + else if ((pplan->sval->type.t & VT_BTYPE) == VT_DOUBLE) + size = 8; + else + size = LDOUBLE_SIZE; + + if (size == 12) + r |= 0x400000; + else if(size == 8) + r|=0x8000; + + o(0xED2D0100|r|(size>>2)); /* some kind of vpush for FPA */ +#endif + } else { + /* simple type (currently always same size) */ + /* XXX: implicit cast ? */ + size=4; + if ((pplan->sval->type.t & VT_BTYPE) == VT_LLONG) { + lexpand_nr(); + size = 8; + r = gv(RC_INT); + o(0xE52D0004|(intr(r)<<12)); /* push r */ + vtop--; + } + r = gv(RC_INT); + o(0xE52D0004|(intr(r)<<12)); /* push r */ + } + if (i == STACK_CLASS && pplan->prev) + gadd_sp(pplan->prev->end - pplan->start); /* Add padding if any */ + } + break; + + case VFP_CLASS: + gv(regmask(TREG_F0 + (pplan->start >> 1))); + if (pplan->start & 1) { /* Must be in upper part of double register */ + o(0xEEF00A40|((pplan->start>>1)<<12)|(pplan->start>>1)); /* vmov.f32 s(n+1), sn */ + vtop->r = VT_CONST; /* avoid being saved on stack by gv for next float */ + } + break; + + case CORE_CLASS: + if ((pplan->sval->type.t & VT_BTYPE) == VT_LLONG) { + lexpand_nr(); + gv(regmask(pplan->end)); + pplan->sval->r2 = vtop->r; + vtop--; + } + gv(regmask(pplan->start)); + /* Mark register as used so that gcall_or_jmp use another one + (regs >=4 are free as never used to pass parameters) */ + pplan->sval->r = vtop->r; + break; + } + vtop--; + } + } + + /* second pass to restore registers that were saved on stack by accident. + Maybe redundant after the "lvalue_save" patch in tccgen.c:gv() */ + if (++pass < 2) + goto again; + + /* Manually free remaining registers since next parameters are loaded + * manually, without the help of gv(int). */ + save_regs(nb_args); + + if(todo) { + o(0xE8BD0000|todo); /* pop {todo} */ + for(pplan = plan->clsplans[CORE_STRUCT_CLASS]; pplan; pplan = pplan->prev) { + int r; + pplan->sval->r = pplan->start; + /* An SValue can only pin 2 registers at best (r and r2) but a structure + can occupy more than 2 registers. Thus, we need to push on the value + stack some fake parameter to have on SValue for each registers used + by a structure (r2 is not used). */ + for (r = pplan->start + 1; r <= pplan->end; r++) { + if (todo & (1 << r)) { + nb_extra_sval++; + vpushi(0); + vtop->r = r; + } + } + } + } + return nb_extra_sval; +} + +/* Generate function call. The function address is pushed first, then + all the parameters in call order. This functions pops all the + parameters and the function address. */ +void gfunc_call(int nb_args) +{ + int r, args_size; + int def_float_abi = float_abi; + int todo; + struct plan plan; + +#ifdef TCC_ARM_EABI + int variadic; + + if (float_abi == ARM_HARD_FLOAT) { + variadic = (vtop[-nb_args].type.ref->f.func_type == FUNC_ELLIPSIS); + if (variadic || floats_in_core_regs(&vtop[-nb_args])) + float_abi = ARM_SOFTFP_FLOAT; + } +#endif + /* cannot let cpu flags if other instruction are generated. Also avoid leaving + VT_JMP anywhere except on the top of the stack because it would complicate + the code generator. */ + r = vtop->r & VT_VALMASK; + if (r == VT_CMP || (r & ~1) == VT_JMP) + gv(RC_INT); + + args_size = assign_regs(nb_args, float_abi, &plan, &todo); + +#ifdef TCC_ARM_EABI + if (args_size & 7) { /* Stack must be 8 byte aligned at fct call for EABI */ + args_size = (args_size + 7) & ~7; + o(0xE24DD004); /* sub sp, sp, #4 */ + } +#endif + + nb_args += copy_params(nb_args, &plan, todo); + tcc_free(plan.pplans); + + /* Move fct SValue on top as required by gcall_or_jmp */ + vrotb(nb_args + 1); + gcall_or_jmp(0); + if (args_size) + gadd_sp(args_size); /* pop all parameters passed on the stack */ +#if defined(TCC_ARM_EABI) && defined(TCC_ARM_VFP) + if(float_abi == ARM_SOFTFP_FLOAT && is_float(vtop->type.ref->type.t)) { + if((vtop->type.ref->type.t & VT_BTYPE) == VT_FLOAT) { + o(0xEE000A10); /*vmov s0, r0 */ + } else { + o(0xEE000B10); /* vmov.32 d0[0], r0 */ + o(0xEE201B10); /* vmov.32 d0[1], r1 */ + } + } +#endif + vtop -= nb_args + 1; /* Pop all params and fct address from value stack */ + leaffunc = 0; /* we are calling a function, so we aren't in a leaf function */ + float_abi = def_float_abi; +} + +/* generate function prolog of type 't' */ +void gfunc_prolog(CType *func_type) +{ + Sym *sym,*sym2; + int n, nf, size, align, rs, struct_ret = 0; + int addr, pn, sn; /* pn=core, sn=stack */ + CType ret_type; + +#ifdef TCC_ARM_EABI + struct avail_regs avregs = AVAIL_REGS_INITIALIZER; +#endif + + sym = func_type->ref; + func_vt = sym->type; + func_var = (func_type->ref->f.func_type == FUNC_ELLIPSIS); + + n = nf = 0; + if ((func_vt.t & VT_BTYPE) == VT_STRUCT && + !gfunc_sret(&func_vt, func_var, &ret_type, &align, &rs)) + { + n++; + struct_ret = 1; + func_vc = 12; /* Offset from fp of the place to store the result */ + } + for(sym2 = sym->next; sym2 && (n < 4 || nf < 16); sym2 = sym2->next) { + size = type_size(&sym2->type, &align); +#ifdef TCC_ARM_EABI + if (float_abi == ARM_HARD_FLOAT && !func_var && + (is_float(sym2->type.t) || is_hgen_float_aggr(&sym2->type))) { + int tmpnf = assign_vfpreg(&avregs, align, size); + tmpnf += (size + 3) / 4; + nf = (tmpnf > nf) ? tmpnf : nf; + } else +#endif + if (n < 4) + n += (size + 3) / 4; + } + o(0xE1A0C00D); /* mov ip,sp */ + if (func_var) + n=4; + if (n) { + if(n>4) + n=4; +#ifdef TCC_ARM_EABI + n=(n+1)&-2; +#endif + o(0xE92D0000|((1<16) + nf=16; + nf=(nf+1)&-2; /* nf => HARDFLOAT => EABI */ + o(0xED2D0A00|nf); /* save s0-s15 on stack if needed */ + } + o(0xE92D5800); /* save fp, ip, lr */ + o(0xE1A0B00D); /* mov fp, sp */ + func_sub_sp_offset = ind; + o(0xE1A00000); /* nop, leave space for stack adjustment in epilog */ + +#ifdef TCC_ARM_EABI + if (float_abi == ARM_HARD_FLOAT) { + func_vc += nf * 4; + avregs = AVAIL_REGS_INITIALIZER; + } +#endif + pn = struct_ret, sn = 0; + while ((sym = sym->next)) { + CType *type; + type = &sym->type; + size = type_size(type, &align); + size = (size + 3) >> 2; + align = (align + 3) & ~3; +#ifdef TCC_ARM_EABI + if (float_abi == ARM_HARD_FLOAT && !func_var && (is_float(sym->type.t) + || is_hgen_float_aggr(&sym->type))) { + int fpn = assign_vfpreg(&avregs, align, size << 2); + if (fpn >= 0) + addr = fpn * 4; + else + goto from_stack; + } else +#endif + if (pn < 4) { +#ifdef TCC_ARM_EABI + pn = (pn + (align-1)/4) & -(align/4); +#endif + addr = (nf + pn) * 4; + pn += size; + if (!sn && pn > 4) + sn = (pn - 4); + } else { +#ifdef TCC_ARM_EABI +from_stack: + sn = (sn + (align-1)/4) & -(align/4); +#endif + addr = (n + nf + sn) * 4; + sn += size; + } + sym_push(sym->v & ~SYM_FIELD, type, VT_LOCAL | lvalue_type(type->t), + addr + 12); + } + last_itod_magic=0; + leaffunc = 1; + loc = 0; +} + +/* generate function epilog */ +void gfunc_epilog(void) +{ + uint32_t x; + int diff; + /* Copy float return value to core register if base standard is used and + float computation is made with VFP */ +#if defined(TCC_ARM_EABI) && defined(TCC_ARM_VFP) + if ((float_abi == ARM_SOFTFP_FLOAT || func_var) && is_float(func_vt.t)) { + if((func_vt.t & VT_BTYPE) == VT_FLOAT) + o(0xEE100A10); /* fmrs r0, s0 */ + else { + o(0xEE100B10); /* fmrdl r0, d0 */ + o(0xEE301B10); /* fmrdh r1, d0 */ + } + } +#endif + o(0xE89BA800); /* restore fp, sp, pc */ + diff = (-loc + 3) & -4; +#ifdef TCC_ARM_EABI + if(!leaffunc) + diff = ((diff + 11) & -8) - 4; +#endif + if(diff > 0) { + x=stuff_const(0xE24BD000, diff); /* sub sp,fp,# */ + if(x) + *(uint32_t *)(cur_text_section->data + func_sub_sp_offset) = x; + else { + int addr; + addr=ind; + o(0xE59FC004); /* ldr ip,[pc+4] */ + o(0xE04BD00C); /* sub sp,fp,ip */ + o(0xE1A0F00E); /* mov pc,lr */ + o(diff); + *(uint32_t *)(cur_text_section->data + func_sub_sp_offset) = 0xE1000000|encbranch(func_sub_sp_offset,addr,1); + } + } +} + +/* generate a jump to a label */ +int gjmp(int t) +{ + int r; + if (nocode_wanted) + return t; + r=ind; + o(0xE0000000|encbranch(r,t,1)); + return r; +} + +/* generate a jump to a fixed address */ +void gjmp_addr(int a) +{ + gjmp(a); +} + +/* generate a test. set 'inv' to invert test. Stack entry is popped */ +int gtst(int inv, int t) +{ + int v, r; + uint32_t op; + + v = vtop->r & VT_VALMASK; + r=ind; + + if (nocode_wanted) { + ; + } else if (v == VT_CMP) { + op=mapcc(inv?negcc(vtop->c.i):vtop->c.i); + op|=encbranch(r,t,1); + o(op); + t=r; + } else if (v == VT_JMP || v == VT_JMPI) { + if ((v & 1) == inv) { + if(!vtop->c.i) + vtop->c.i=t; + else { + uint32_t *x; + int p,lp; + if(t) { + p = vtop->c.i; + do { + p = decbranch(lp=p); + } while(p); + x = (uint32_t *)(cur_text_section->data + lp); + *x &= 0xff000000; + *x |= encbranch(lp,t,1); + } + t = vtop->c.i; + } + } else { + t = gjmp(t); + gsym(vtop->c.i); + } + } + vtop--; + return t; +} + +/* generate an integer binary operation */ +void gen_opi(int op) +{ + int c, func = 0; + uint32_t opc = 0, r, fr; + unsigned short retreg = REG_IRET; + + c=0; + switch(op) { + case '+': + opc = 0x8; + c=1; + break; + case TOK_ADDC1: /* add with carry generation */ + opc = 0x9; + c=1; + break; + case '-': + opc = 0x4; + c=1; + break; + case TOK_SUBC1: /* sub with carry generation */ + opc = 0x5; + c=1; + break; + case TOK_ADDC2: /* add with carry use */ + opc = 0xA; + c=1; + break; + case TOK_SUBC2: /* sub with carry use */ + opc = 0xC; + c=1; + break; + case '&': + opc = 0x0; + c=1; + break; + case '^': + opc = 0x2; + c=1; + break; + case '|': + opc = 0x18; + c=1; + break; + case '*': + gv2(RC_INT, RC_INT); + r = vtop[-1].r; + fr = vtop[0].r; + vtop--; + o(0xE0000090|(intr(r)<<16)|(intr(r)<<8)|intr(fr)); + return; + case TOK_SHL: + opc = 0; + c=2; + break; + case TOK_SHR: + opc = 1; + c=2; + break; + case TOK_SAR: + opc = 2; + c=2; + break; + case '/': + case TOK_PDIV: + func=TOK___divsi3; + c=3; + break; + case TOK_UDIV: + func=TOK___udivsi3; + c=3; + break; + case '%': +#ifdef TCC_ARM_EABI + func=TOK___aeabi_idivmod; + retreg=REG_LRET; +#else + func=TOK___modsi3; +#endif + c=3; + break; + case TOK_UMOD: +#ifdef TCC_ARM_EABI + func=TOK___aeabi_uidivmod; + retreg=REG_LRET; +#else + func=TOK___umodsi3; +#endif + c=3; + break; + case TOK_UMULL: + gv2(RC_INT, RC_INT); + r=intr(vtop[-1].r2=get_reg(RC_INT)); + c=vtop[-1].r; + vtop[-1].r=get_reg_ex(RC_INT,regmask(c)); + vtop--; + o(0xE0800090|(r<<16)|(intr(vtop->r)<<12)|(intr(c)<<8)|intr(vtop[1].r)); + return; + default: + opc = 0x15; + c=1; + break; + } + switch(c) { + case 1: + if((vtop[-1].r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) { + if(opc == 4 || opc == 5 || opc == 0xc) { + vswap(); + opc|=2; // sub -> rsb + } + } + if ((vtop->r & VT_VALMASK) == VT_CMP || + (vtop->r & (VT_VALMASK & ~1)) == VT_JMP) + gv(RC_INT); + vswap(); + c=intr(gv(RC_INT)); + vswap(); + opc=0xE0000000|(opc<<20)|(c<<16); + if((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) { + uint32_t x; + x=stuff_const(opc|0x2000000,vtop->c.i); + if(x) { + r=intr(vtop[-1].r=get_reg_ex(RC_INT,regmask(vtop[-1].r))); + o(x|(r<<12)); + goto done; + } + } + fr=intr(gv(RC_INT)); + r=intr(vtop[-1].r=get_reg_ex(RC_INT,two2mask(vtop->r,vtop[-1].r))); + o(opc|(r<<12)|fr); +done: + vtop--; + if (op >= TOK_ULT && op <= TOK_GT) { + vtop->r = VT_CMP; + vtop->c.i = op; + } + break; + case 2: + opc=0xE1A00000|(opc<<5); + if ((vtop->r & VT_VALMASK) == VT_CMP || + (vtop->r & (VT_VALMASK & ~1)) == VT_JMP) + gv(RC_INT); + vswap(); + r=intr(gv(RC_INT)); + vswap(); + opc|=r; + if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) { + fr=intr(vtop[-1].r=get_reg_ex(RC_INT,regmask(vtop[-1].r))); + c = vtop->c.i & 0x1f; + o(opc|(c<<7)|(fr<<12)); + } else { + fr=intr(gv(RC_INT)); + c=intr(vtop[-1].r=get_reg_ex(RC_INT,two2mask(vtop->r,vtop[-1].r))); + o(opc|(c<<12)|(fr<<8)|0x10); + } + vtop--; + break; + case 3: + vpush_global_sym(&func_old_type, func); + vrott(3); + gfunc_call(2); + vpushi(0); + vtop->r = retreg; + break; + default: + tcc_error("gen_opi %i unimplemented!",op); + } +} + +#ifdef TCC_ARM_VFP +static int is_zero(int i) +{ + if((vtop[i].r & (VT_VALMASK | VT_LVAL | VT_SYM)) != VT_CONST) + return 0; + if (vtop[i].type.t == VT_FLOAT) + return (vtop[i].c.f == 0.f); + else if (vtop[i].type.t == VT_DOUBLE) + return (vtop[i].c.d == 0.0); + return (vtop[i].c.ld == 0.l); +} + +/* generate a floating point operation 'v = t1 op t2' instruction. The + * two operands are guaranteed to have the same floating point type */ +void gen_opf(int op) +{ + uint32_t x; + int fneg=0,r; + x=0xEE000A00|T2CPR(vtop->type.t); + switch(op) { + case '+': + if(is_zero(-1)) + vswap(); + if(is_zero(0)) { + vtop--; + return; + } + x|=0x300000; + break; + case '-': + x|=0x300040; + if(is_zero(0)) { + vtop--; + return; + } + if(is_zero(-1)) { + x|=0x810000; /* fsubX -> fnegX */ + vswap(); + vtop--; + fneg=1; + } + break; + case '*': + x|=0x200000; + break; + case '/': + x|=0x800000; + break; + default: + if(op < TOK_ULT || op > TOK_GT) { + tcc_error("unknown fp op %x!",op); + return; + } + if(is_zero(-1)) { + vswap(); + switch(op) { + case TOK_LT: op=TOK_GT; break; + case TOK_GE: op=TOK_ULE; break; + case TOK_LE: op=TOK_GE; break; + case TOK_GT: op=TOK_ULT; break; + } + } + x|=0xB40040; /* fcmpX */ + if(op!=TOK_EQ && op!=TOK_NE) + x|=0x80; /* fcmpX -> fcmpeX */ + if(is_zero(0)) { + vtop--; + o(x|0x10000|(vfpr(gv(RC_FLOAT))<<12)); /* fcmp(e)X -> fcmp(e)zX */ + } else { + x|=vfpr(gv(RC_FLOAT)); + vswap(); + o(x|(vfpr(gv(RC_FLOAT))<<12)); + vtop--; + } + o(0xEEF1FA10); /* fmstat */ + + switch(op) { + case TOK_LE: op=TOK_ULE; break; + case TOK_LT: op=TOK_ULT; break; + case TOK_UGE: op=TOK_GE; break; + case TOK_UGT: op=TOK_GT; break; + } + + vtop->r = VT_CMP; + vtop->c.i = op; + return; + } + r=gv(RC_FLOAT); + x|=vfpr(r); + r=regmask(r); + if(!fneg) { + int r2; + vswap(); + r2=gv(RC_FLOAT); + x|=vfpr(r2)<<16; + r|=regmask(r2); + } + vtop->r=get_reg_ex(RC_FLOAT,r); + if(!fneg) + vtop--; + o(x|(vfpr(vtop->r)<<12)); +} + +#else +static uint32_t is_fconst() +{ + long double f; + uint32_t r; + if((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) != VT_CONST) + return 0; + if (vtop->type.t == VT_FLOAT) + f = vtop->c.f; + else if (vtop->type.t == VT_DOUBLE) + f = vtop->c.d; + else + f = vtop->c.ld; + if(!ieee_finite(f)) + return 0; + r=0x8; + if(f<0.0) { + r=0x18; + f=-f; + } + if(f==0.0) + return r; + if(f==1.0) + return r|1; + if(f==2.0) + return r|2; + if(f==3.0) + return r|3; + if(f==4.0) + return r|4; + if(f==5.0) + return r|5; + if(f==0.5) + return r|6; + if(f==10.0) + return r|7; + return 0; +} + +/* generate a floating point operation 'v = t1 op t2' instruction. The + two operands are guaranteed to have the same floating point type */ +void gen_opf(int op) +{ + uint32_t x, r, r2, c1, c2; + //fputs("gen_opf\n",stderr); + vswap(); + c1 = is_fconst(); + vswap(); + c2 = is_fconst(); + x=0xEE000100; +#if LDOUBLE_SIZE == 8 + if ((vtop->type.t & VT_BTYPE) != VT_FLOAT) + x|=0x80; +#else + if ((vtop->type.t & VT_BTYPE) == VT_DOUBLE) + x|=0x80; + else if ((vtop->type.t & VT_BTYPE) == VT_LDOUBLE) + x|=0x80000; +#endif + switch(op) + { + case '+': + if(!c2) { + vswap(); + c2=c1; + } + vswap(); + r=fpr(gv(RC_FLOAT)); + vswap(); + if(c2) { + if(c2>0xf) + x|=0x200000; // suf + r2=c2&0xf; + } else { + r2=fpr(gv(RC_FLOAT)); + } + break; + case '-': + if(c2) { + if(c2<=0xf) + x|=0x200000; // suf + r2=c2&0xf; + vswap(); + r=fpr(gv(RC_FLOAT)); + vswap(); + } else if(c1 && c1<=0xf) { + x|=0x300000; // rsf + r2=c1; + r=fpr(gv(RC_FLOAT)); + vswap(); + } else { + x|=0x200000; // suf + vswap(); + r=fpr(gv(RC_FLOAT)); + vswap(); + r2=fpr(gv(RC_FLOAT)); + } + break; + case '*': + if(!c2 || c2>0xf) { + vswap(); + c2=c1; + } + vswap(); + r=fpr(gv(RC_FLOAT)); + vswap(); + if(c2 && c2<=0xf) + r2=c2; + else + r2=fpr(gv(RC_FLOAT)); + x|=0x100000; // muf + break; + case '/': + if(c2 && c2<=0xf) { + x|=0x400000; // dvf + r2=c2; + vswap(); + r=fpr(gv(RC_FLOAT)); + vswap(); + } else if(c1 && c1<=0xf) { + x|=0x500000; // rdf + r2=c1; + r=fpr(gv(RC_FLOAT)); + vswap(); + } else { + x|=0x400000; // dvf + vswap(); + r=fpr(gv(RC_FLOAT)); + vswap(); + r2=fpr(gv(RC_FLOAT)); + } + break; + default: + if(op >= TOK_ULT && op <= TOK_GT) { + x|=0xd0f110; // cmfe +/* bug (intention?) in Linux FPU emulator + doesn't set carry if equal */ + switch(op) { + case TOK_ULT: + case TOK_UGE: + case TOK_ULE: + case TOK_UGT: + tcc_error("unsigned comparison on floats?"); + break; + case TOK_LT: + op=TOK_Nset; + break; + case TOK_LE: + op=TOK_ULE; /* correct in unordered case only if AC bit in FPSR set */ + break; + case TOK_EQ: + case TOK_NE: + x&=~0x400000; // cmfe -> cmf + break; + } + if(c1 && !c2) { + c2=c1; + vswap(); + switch(op) { + case TOK_Nset: + op=TOK_GT; + break; + case TOK_GE: + op=TOK_ULE; + break; + case TOK_ULE: + op=TOK_GE; + break; + case TOK_GT: + op=TOK_Nset; + break; + } + } + vswap(); + r=fpr(gv(RC_FLOAT)); + vswap(); + if(c2) { + if(c2>0xf) + x|=0x200000; + r2=c2&0xf; + } else { + r2=fpr(gv(RC_FLOAT)); + } + vtop[-1].r = VT_CMP; + vtop[-1].c.i = op; + } else { + tcc_error("unknown fp op %x!",op); + return; + } + } + if(vtop[-1].r == VT_CMP) + c1=15; + else { + c1=vtop->r; + if(r2&0x8) + c1=vtop[-1].r; + vtop[-1].r=get_reg_ex(RC_FLOAT,two2mask(vtop[-1].r,c1)); + c1=fpr(vtop[-1].r); + } + vtop--; + o(x|(r<<16)|(c1<<12)|r2); +} +#endif + +/* convert integers to fp 't' type. Must handle 'int', 'unsigned int' + and 'long long' cases. */ +ST_FUNC void gen_cvt_itof1(int t) +{ + uint32_t r, r2; + int bt; + bt=vtop->type.t & VT_BTYPE; + if(bt == VT_INT || bt == VT_SHORT || bt == VT_BYTE) { +#ifndef TCC_ARM_VFP + uint32_t dsize = 0; +#endif + r=intr(gv(RC_INT)); +#ifdef TCC_ARM_VFP + r2=vfpr(vtop->r=get_reg(RC_FLOAT)); + o(0xEE000A10|(r<<12)|(r2<<16)); /* fmsr */ + r2|=r2<<12; + if(!(vtop->type.t & VT_UNSIGNED)) + r2|=0x80; /* fuitoX -> fsituX */ + o(0xEEB80A40|r2|T2CPR(t)); /* fYitoX*/ +#else + r2=fpr(vtop->r=get_reg(RC_FLOAT)); + if((t & VT_BTYPE) != VT_FLOAT) + dsize=0x80; /* flts -> fltd */ + o(0xEE000110|dsize|(r2<<16)|(r<<12)); /* flts */ + if((vtop->type.t & (VT_UNSIGNED|VT_BTYPE)) == (VT_UNSIGNED|VT_INT)) { + uint32_t off = 0; + o(0xE3500000|(r<<12)); /* cmp */ + r=fpr(get_reg(RC_FLOAT)); + if(last_itod_magic) { + off=ind+8-last_itod_magic; + off/=4; + if(off>255) + off=0; + } + o(0xBD1F0100|(r<<12)|off); /* ldflts */ + if(!off) { + o(0xEA000000); /* b */ + last_itod_magic=ind; + o(0x4F800000); /* 4294967296.0f */ + } + o(0xBE000100|dsize|(r2<<16)|(r2<<12)|r); /* adflt */ + } +#endif + return; + } else if(bt == VT_LLONG) { + int func; + CType *func_type = 0; + if((t & VT_BTYPE) == VT_FLOAT) { + func_type = &func_float_type; + if(vtop->type.t & VT_UNSIGNED) + func=TOK___floatundisf; + else + func=TOK___floatdisf; +#if LDOUBLE_SIZE != 8 + } else if((t & VT_BTYPE) == VT_LDOUBLE) { + func_type = &func_ldouble_type; + if(vtop->type.t & VT_UNSIGNED) + func=TOK___floatundixf; + else + func=TOK___floatdixf; + } else if((t & VT_BTYPE) == VT_DOUBLE) { +#else + } else if((t & VT_BTYPE) == VT_DOUBLE || (t & VT_BTYPE) == VT_LDOUBLE) { +#endif + func_type = &func_double_type; + if(vtop->type.t & VT_UNSIGNED) + func=TOK___floatundidf; + else + func=TOK___floatdidf; + } + if(func_type) { + vpush_global_sym(func_type, func); + vswap(); + gfunc_call(1); + vpushi(0); + vtop->r=TREG_F0; + return; + } + } + tcc_error("unimplemented gen_cvt_itof %x!",vtop->type.t); +} + +/* convert fp to int 't' type */ +void gen_cvt_ftoi(int t) +{ + uint32_t r, r2; + int u, func = 0; + u=t&VT_UNSIGNED; + t&=VT_BTYPE; + r2=vtop->type.t & VT_BTYPE; + if(t==VT_INT) { +#ifdef TCC_ARM_VFP + r=vfpr(gv(RC_FLOAT)); + u=u?0:0x10000; + o(0xEEBC0AC0|(r<<12)|r|T2CPR(r2)|u); /* ftoXizY */ + r2=intr(vtop->r=get_reg(RC_INT)); + o(0xEE100A10|(r<<16)|(r2<<12)); + return; +#else + if(u) { + if(r2 == VT_FLOAT) + func=TOK___fixunssfsi; +#if LDOUBLE_SIZE != 8 + else if(r2 == VT_LDOUBLE) + func=TOK___fixunsxfsi; + else if(r2 == VT_DOUBLE) +#else + else if(r2 == VT_LDOUBLE || r2 == VT_DOUBLE) +#endif + func=TOK___fixunsdfsi; + } else { + r=fpr(gv(RC_FLOAT)); + r2=intr(vtop->r=get_reg(RC_INT)); + o(0xEE100170|(r2<<12)|r); + return; + } +#endif + } else if(t == VT_LLONG) { // unsigned handled in gen_cvt_ftoi1 + if(r2 == VT_FLOAT) + func=TOK___fixsfdi; +#if LDOUBLE_SIZE != 8 + else if(r2 == VT_LDOUBLE) + func=TOK___fixxfdi; + else if(r2 == VT_DOUBLE) +#else + else if(r2 == VT_LDOUBLE || r2 == VT_DOUBLE) +#endif + func=TOK___fixdfdi; + } + if(func) { + vpush_global_sym(&func_old_type, func); + vswap(); + gfunc_call(1); + vpushi(0); + if(t == VT_LLONG) + vtop->r2 = REG_LRET; + vtop->r = REG_IRET; + return; + } + tcc_error("unimplemented gen_cvt_ftoi!"); +} + +/* convert from one floating point type to another */ +void gen_cvt_ftof(int t) +{ +#ifdef TCC_ARM_VFP + if(((vtop->type.t & VT_BTYPE) == VT_FLOAT) != ((t & VT_BTYPE) == VT_FLOAT)) { + uint32_t r = vfpr(gv(RC_FLOAT)); + o(0xEEB70AC0|(r<<12)|r|T2CPR(vtop->type.t)); + } +#else + /* all we have to do on i386 and FPA ARM is to put the float in a register */ + gv(RC_FLOAT); +#endif +} + +/* computed goto support */ +void ggoto(void) +{ + gcall_or_jmp(1); + vtop--; +} + +/* Save the stack pointer onto the stack and return the location of its address */ +ST_FUNC void gen_vla_sp_save(int addr) { + SValue v; + v.type.t = VT_PTR; + v.r = VT_LOCAL | VT_LVAL; + v.c.i = addr; + store(TREG_SP, &v); +} + +/* Restore the SP from a location on the stack */ +ST_FUNC void gen_vla_sp_restore(int addr) { + SValue v; + v.type.t = VT_PTR; + v.r = VT_LOCAL | VT_LVAL; + v.c.i = addr; + load(TREG_SP, &v); +} + +/* Subtract from the stack pointer, and push the resulting value onto the stack */ +ST_FUNC void gen_vla_alloc(CType *type, int align) { + int r = intr(gv(RC_INT)); + o(0xE04D0000|(r<<12)|r); /* sub r, sp, r */ +#ifdef TCC_ARM_EABI + if (align < 8) + align = 8; +#else + if (align < 4) + align = 4; +#endif + if (align & (align - 1)) + tcc_error("alignment is not a power of 2: %i", align); + o(stuff_const(0xE3C0D000|(r<<16), align - 1)); /* bic sp, r, #align-1 */ + vpop(); +} + +/* end of ARM code generator */ +/*************************************************************/ +#endif +/*************************************************************/ diff --git a/tinyc/arm-link.c b/tinyc/arm-link.c new file mode 100644 index 000000000..aee35afef --- /dev/null +++ b/tinyc/arm-link.c @@ -0,0 +1,392 @@ +#ifdef TARGET_DEFS_ONLY + +#define EM_TCC_TARGET EM_ARM + +/* relocation type for 32 bit data relocation */ +#define R_DATA_32 R_ARM_ABS32 +#define R_DATA_PTR R_ARM_ABS32 +#define R_JMP_SLOT R_ARM_JUMP_SLOT +#define R_GLOB_DAT R_ARM_GLOB_DAT +#define R_COPY R_ARM_COPY +#define R_RELATIVE R_ARM_RELATIVE + +#define R_NUM R_ARM_NUM + +#define ELF_START_ADDR 0x00008000 +#define ELF_PAGE_SIZE 0x1000 + +#define PCRELATIVE_DLLPLT 1 +#define RELOCATE_DLLPLT 0 + +enum float_abi { + ARM_SOFTFP_FLOAT, + ARM_HARD_FLOAT, +}; + +#else /* !TARGET_DEFS_ONLY */ + +#include "tcc.h" + +/* Returns 1 for a code relocation, 0 for a data relocation. For unknown + relocations, returns -1. */ +int code_reloc (int reloc_type) +{ + switch (reloc_type) { + case R_ARM_MOVT_ABS: + case R_ARM_MOVW_ABS_NC: + case R_ARM_THM_MOVT_ABS: + case R_ARM_THM_MOVW_ABS_NC: + case R_ARM_ABS32: + case R_ARM_REL32: + case R_ARM_GOTPC: + case R_ARM_GOTOFF: + case R_ARM_GOT32: + case R_ARM_COPY: + case R_ARM_GLOB_DAT: + case R_ARM_NONE: + return 0; + + case R_ARM_PC24: + case R_ARM_CALL: + case R_ARM_JUMP24: + case R_ARM_PLT32: + case R_ARM_THM_PC22: + case R_ARM_THM_JUMP24: + case R_ARM_PREL31: + case R_ARM_V4BX: + case R_ARM_JUMP_SLOT: + return 1; + } + + tcc_error ("Unknown relocation type: %d", reloc_type); + return -1; +} + +/* Returns an enumerator to describe whether and when the relocation needs a + GOT and/or PLT entry to be created. See tcc.h for a description of the + different values. */ +int gotplt_entry_type (int reloc_type) +{ + switch (reloc_type) { + case R_ARM_NONE: + case R_ARM_COPY: + case R_ARM_GLOB_DAT: + case R_ARM_JUMP_SLOT: + return NO_GOTPLT_ENTRY; + + case R_ARM_PC24: + case R_ARM_CALL: + case R_ARM_JUMP24: + case R_ARM_PLT32: + case R_ARM_THM_PC22: + case R_ARM_THM_JUMP24: + case R_ARM_MOVT_ABS: + case R_ARM_MOVW_ABS_NC: + case R_ARM_THM_MOVT_ABS: + case R_ARM_THM_MOVW_ABS_NC: + case R_ARM_PREL31: + case R_ARM_ABS32: + case R_ARM_REL32: + case R_ARM_V4BX: + return AUTO_GOTPLT_ENTRY; + + case R_ARM_GOTPC: + case R_ARM_GOTOFF: + return BUILD_GOT_ONLY; + + case R_ARM_GOT32: + return ALWAYS_GOTPLT_ENTRY; + } + + tcc_error ("Unknown relocation type: %d", reloc_type); + return -1; +} + +ST_FUNC unsigned create_plt_entry(TCCState *s1, unsigned got_offset, struct sym_attr *attr) +{ + Section *plt = s1->plt; + uint8_t *p; + unsigned plt_offset; + + /* when building a DLL, GOT entry accesses must be done relative to + start of GOT (see x86_64 example above) */ + if (s1->output_type == TCC_OUTPUT_DLL) + tcc_error("DLLs unimplemented!"); + + /* empty PLT: create PLT0 entry that push address of call site and + jump to ld.so resolution routine (GOT + 8) */ + if (plt->data_offset == 0) { + p = section_ptr_add(plt, 20); + write32le(p, 0xe52de004); /* push {lr} */ + write32le(p+4, 0xe59fe004); /* ldr lr, [pc, #4] */ + write32le(p+8, 0xe08fe00e); /* add lr, pc, lr */ + write32le(p+12, 0xe5bef008); /* ldr pc, [lr, #8]! */ + /* p+16 is set in relocate_plt */ + } + plt_offset = plt->data_offset; + + if (attr->plt_thumb_stub) { + p = section_ptr_add(plt, 4); + write32le(p, 0x4778); /* bx pc */ + write32le(p+2, 0x46c0); /* nop */ + } + p = section_ptr_add(plt, 16); + /* Jump to GOT entry where ld.so initially put address of PLT0 */ + write32le(p, 0xe59fc004); /* ldr ip, [pc, #4] */ + write32le(p+4, 0xe08fc00c); /* add ip, pc, ip */ + write32le(p+8, 0xe59cf000); /* ldr pc, [ip] */ + /* p + 12 contains offset to GOT entry once patched by relocate_plt */ + write32le(p+12, got_offset); + return plt_offset; +} + +/* relocate the PLT: compute addresses and offsets in the PLT now that final + address for PLT and GOT are known (see fill_program_header) */ +ST_FUNC void relocate_plt(TCCState *s1) +{ + uint8_t *p, *p_end; + + if (!s1->plt) + return; + + p = s1->plt->data; + p_end = p + s1->plt->data_offset; + + if (p < p_end) { + int x = s1->got->sh_addr - s1->plt->sh_addr - 12; + write32le(s1->plt->data + 16, x - 16); + p += 20; + while (p < p_end) { + if (read32le(p) == 0x46c04778) /* PLT Thumb stub present */ + p += 4; + add32le(p + 12, x + s1->plt->data - p); + p += 16; + } + } +} + +void relocate_init(Section *sr) {} + +void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t addr, addr_t val) +{ + ElfW(Sym) *sym; + int sym_index; + + sym_index = ELFW(R_SYM)(rel->r_info); + sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; + + switch(type) { + case R_ARM_PC24: + case R_ARM_CALL: + case R_ARM_JUMP24: + case R_ARM_PLT32: + { + int x, is_thumb, is_call, h, blx_avail, is_bl, th_ko; + x = (*(int *) ptr) & 0xffffff; +#ifdef DEBUG_RELOC + printf ("reloc %d: x=0x%x val=0x%x ", type, x, val); +#endif + (*(int *)ptr) &= 0xff000000; + if (x & 0x800000) + x -= 0x1000000; + x <<= 2; + blx_avail = (TCC_CPU_VERSION >= 5); + is_thumb = val & 1; + is_bl = (*(unsigned *) ptr) >> 24 == 0xeb; + is_call = (type == R_ARM_CALL || (type == R_ARM_PC24 && is_bl)); + x += val - addr; +#ifdef DEBUG_RELOC + printf (" newx=0x%x name=%s\n", x, + (char *) symtab_section->link->data + sym->st_name); +#endif + h = x & 2; + th_ko = (x & 3) && (!blx_avail || !is_call); + if (th_ko || x >= 0x2000000 || x < -0x2000000) + tcc_error("can't relocate value at %x,%d",addr, type); + x >>= 2; + x &= 0xffffff; + /* Only reached if blx is avail and it is a call */ + if (is_thumb) { + x |= h << 24; + (*(int *)ptr) = 0xfa << 24; /* bl -> blx */ + } + (*(int *) ptr) |= x; + } + return; + /* Since these relocations only concern Thumb-2 and blx instruction was + introduced before Thumb-2, we can assume blx is available and not + guard its use */ + case R_ARM_THM_PC22: + case R_ARM_THM_JUMP24: + { + int x, hi, lo, s, j1, j2, i1, i2, imm10, imm11; + int to_thumb, is_call, to_plt, blx_bit = 1 << 12; + Section *plt; + + /* weak reference */ + if (sym->st_shndx == SHN_UNDEF && + ELFW(ST_BIND)(sym->st_info) == STB_WEAK) + return; + + /* Get initial offset */ + hi = (*(uint16_t *)ptr); + lo = (*(uint16_t *)(ptr+2)); + s = (hi >> 10) & 1; + j1 = (lo >> 13) & 1; + j2 = (lo >> 11) & 1; + i1 = (j1 ^ s) ^ 1; + i2 = (j2 ^ s) ^ 1; + imm10 = hi & 0x3ff; + imm11 = lo & 0x7ff; + x = (s << 24) | (i1 << 23) | (i2 << 22) | + (imm10 << 12) | (imm11 << 1); + if (x & 0x01000000) + x -= 0x02000000; + + /* Relocation infos */ + to_thumb = val & 1; + plt = s1->plt; + to_plt = (val >= plt->sh_addr) && + (val < plt->sh_addr + plt->data_offset); + is_call = (type == R_ARM_THM_PC22); + + if (!to_thumb && !to_plt && !is_call) { + int index; + uint8_t *p; + char *name, buf[1024]; + Section *text_section; + + name = (char *) symtab_section->link->data + sym->st_name; + text_section = s1->sections[sym->st_shndx]; + /* Modify reloc to target a thumb stub to switch to ARM */ + snprintf(buf, sizeof(buf), "%s_from_thumb", name); + index = put_elf_sym(symtab_section, + text_section->data_offset + 1, + sym->st_size, sym->st_info, 0, + sym->st_shndx, buf); + to_thumb = 1; + val = text_section->data_offset + 1; + rel->r_info = ELFW(R_INFO)(index, type); + /* Create a thumb stub function to switch to ARM mode */ + put_elf_reloc(symtab_section, text_section, + text_section->data_offset + 4, R_ARM_JUMP24, + sym_index); + p = section_ptr_add(text_section, 8); + write32le(p, 0x4778); /* bx pc */ + write32le(p+2, 0x46c0); /* nop */ + write32le(p+4, 0xeafffffe); /* b $sym */ + } + + /* Compute final offset */ + x += val - addr; + if (!to_thumb && is_call) { + blx_bit = 0; /* bl -> blx */ + x = (x + 3) & -4; /* Compute offset from aligned PC */ + } + + /* Check that relocation is possible + * offset must not be out of range + * if target is to be entered in arm mode: + - bit 1 must not set + - instruction must be a call (bl) or a jump to PLT */ + if (!to_thumb || x >= 0x1000000 || x < -0x1000000) + if (to_thumb || (val & 2) || (!is_call && !to_plt)) + tcc_error("can't relocate value at %x,%d",addr, type); + + /* Compute and store final offset */ + s = (x >> 24) & 1; + i1 = (x >> 23) & 1; + i2 = (x >> 22) & 1; + j1 = s ^ (i1 ^ 1); + j2 = s ^ (i2 ^ 1); + imm10 = (x >> 12) & 0x3ff; + imm11 = (x >> 1) & 0x7ff; + (*(uint16_t *)ptr) = (uint16_t) ((hi & 0xf800) | + (s << 10) | imm10); + (*(uint16_t *)(ptr+2)) = (uint16_t) ((lo & 0xc000) | + (j1 << 13) | blx_bit | (j2 << 11) | + imm11); + } + return; + case R_ARM_MOVT_ABS: + case R_ARM_MOVW_ABS_NC: + { + int x, imm4, imm12; + if (type == R_ARM_MOVT_ABS) + val >>= 16; + imm12 = val & 0xfff; + imm4 = (val >> 12) & 0xf; + x = (imm4 << 16) | imm12; + if (type == R_ARM_THM_MOVT_ABS) + *(int *)ptr |= x; + else + *(int *)ptr += x; + } + return; + case R_ARM_THM_MOVT_ABS: + case R_ARM_THM_MOVW_ABS_NC: + { + int x, i, imm4, imm3, imm8; + if (type == R_ARM_THM_MOVT_ABS) + val >>= 16; + imm8 = val & 0xff; + imm3 = (val >> 8) & 0x7; + i = (val >> 11) & 1; + imm4 = (val >> 12) & 0xf; + x = (imm3 << 28) | (imm8 << 16) | (i << 10) | imm4; + if (type == R_ARM_THM_MOVT_ABS) + *(int *)ptr |= x; + else + *(int *)ptr += x; + } + return; + case R_ARM_PREL31: + { + int x; + x = (*(int *)ptr) & 0x7fffffff; + (*(int *)ptr) &= 0x80000000; + x = (x * 2) / 2; + x += val - addr; + if((x^(x>>1))&0x40000000) + tcc_error("can't relocate value at %x,%d",addr, type); + (*(int *)ptr) |= x & 0x7fffffff; + } + case R_ARM_ABS32: + *(int *)ptr += val; + return; + case R_ARM_REL32: + *(int *)ptr += val - addr; + return; + case R_ARM_GOTPC: + *(int *)ptr += s1->got->sh_addr - addr; + return; + case R_ARM_GOTOFF: + *(int *)ptr += val - s1->got->sh_addr; + return; + case R_ARM_GOT32: + /* we load the got offset */ + *(int *)ptr += s1->sym_attrs[sym_index].got_offset; + return; + case R_ARM_COPY: + return; + case R_ARM_V4BX: + /* trade Thumb support for ARMv4 support */ + if ((0x0ffffff0 & *(int*)ptr) == 0x012FFF10) + *(int*)ptr ^= 0xE12FFF10 ^ 0xE1A0F000; /* BX Rm -> MOV PC, Rm */ + return; + case R_ARM_GLOB_DAT: + case R_ARM_JUMP_SLOT: + *(addr_t *)ptr = val; + return; + case R_ARM_NONE: + /* Nothing to do. Normally used to indicate a dependency + on a certain symbol (like for exception handling under EABI). */ + return; + default: + fprintf(stderr,"FIXME: handle reloc type %x at %x [%p] to %x\n", + type, (unsigned)addr, ptr, (unsigned)val); + return; + } +} + +#endif /* !TARGET_DEFS_ONLY */ diff --git a/tinyc/arm64-gen.c b/tinyc/arm64-gen.c new file mode 100644 index 000000000..86b3af73b --- /dev/null +++ b/tinyc/arm64-gen.c @@ -0,0 +1,1837 @@ +/* + * A64 code generator for TCC + * + * Copyright (c) 2014-2015 Edmund Grimley Evans + * + * Copying and distribution of this file, with or without modification, + * are permitted in any medium without royalty provided the copyright + * notice and this notice are preserved. This file is offered as-is, + * without any warranty. + */ + +#ifdef TARGET_DEFS_ONLY + +// Number of registers available to allocator: +#define NB_REGS 28 // x0-x18, x30, v0-v7 + +#define TREG_R(x) (x) // x = 0..18 +#define TREG_R30 19 +#define TREG_F(x) (x + 20) // x = 0..7 + +// Register classes sorted from more general to more precise: +#define RC_INT (1 << 0) +#define RC_FLOAT (1 << 1) +#define RC_R(x) (1 << (2 + (x))) // x = 0..18 +#define RC_R30 (1 << 21) +#define RC_F(x) (1 << (22 + (x))) // x = 0..7 + +#define RC_IRET (RC_R(0)) // int return register class +#define RC_FRET (RC_F(0)) // float return register class + +#define REG_IRET (TREG_R(0)) // int return register number +#define REG_FRET (TREG_F(0)) // float return register number + +#define PTR_SIZE 8 + +#define LDOUBLE_SIZE 16 +#define LDOUBLE_ALIGN 16 + +#define MAX_ALIGN 16 + +#define CHAR_IS_UNSIGNED + +/******************************************************/ +#else /* ! TARGET_DEFS_ONLY */ +/******************************************************/ +#include "tcc.h" +#include + +ST_DATA const int reg_classes[NB_REGS] = { + RC_INT | RC_R(0), + RC_INT | RC_R(1), + RC_INT | RC_R(2), + RC_INT | RC_R(3), + RC_INT | RC_R(4), + RC_INT | RC_R(5), + RC_INT | RC_R(6), + RC_INT | RC_R(7), + RC_INT | RC_R(8), + RC_INT | RC_R(9), + RC_INT | RC_R(10), + RC_INT | RC_R(11), + RC_INT | RC_R(12), + RC_INT | RC_R(13), + RC_INT | RC_R(14), + RC_INT | RC_R(15), + RC_INT | RC_R(16), + RC_INT | RC_R(17), + RC_INT | RC_R(18), + RC_R30, // not in RC_INT as we make special use of x30 + RC_FLOAT | RC_F(0), + RC_FLOAT | RC_F(1), + RC_FLOAT | RC_F(2), + RC_FLOAT | RC_F(3), + RC_FLOAT | RC_F(4), + RC_FLOAT | RC_F(5), + RC_FLOAT | RC_F(6), + RC_FLOAT | RC_F(7) +}; + +#define IS_FREG(x) ((x) >= TREG_F(0)) + +static uint32_t intr(int r) +{ + assert(TREG_R(0) <= r && r <= TREG_R30); + return r < TREG_R30 ? r : 30; +} + +static uint32_t fltr(int r) +{ + assert(TREG_F(0) <= r && r <= TREG_F(7)); + return r - TREG_F(0); +} + +// Add an instruction to text section: +ST_FUNC void o(unsigned int c) +{ + int ind1 = ind + 4; + if (nocode_wanted) + return; + if (ind1 > cur_text_section->data_allocated) + section_realloc(cur_text_section, ind1); + write32le(cur_text_section->data + ind, c); + ind = ind1; +} + +static int arm64_encode_bimm64(uint64_t x) +{ + int neg = x & 1; + int rep, pos, len; + + if (neg) + x = ~x; + if (!x) + return -1; + + if (x >> 2 == (x & (((uint64_t)1 << (64 - 2)) - 1))) + rep = 2, x &= ((uint64_t)1 << 2) - 1; + else if (x >> 4 == (x & (((uint64_t)1 << (64 - 4)) - 1))) + rep = 4, x &= ((uint64_t)1 << 4) - 1; + else if (x >> 8 == (x & (((uint64_t)1 << (64 - 8)) - 1))) + rep = 8, x &= ((uint64_t)1 << 8) - 1; + else if (x >> 16 == (x & (((uint64_t)1 << (64 - 16)) - 1))) + rep = 16, x &= ((uint64_t)1 << 16) - 1; + else if (x >> 32 == (x & (((uint64_t)1 << (64 - 32)) - 1))) + rep = 32, x &= ((uint64_t)1 << 32) - 1; + else + rep = 64; + + pos = 0; + if (!(x & (((uint64_t)1 << 32) - 1))) x >>= 32, pos += 32; + if (!(x & (((uint64_t)1 << 16) - 1))) x >>= 16, pos += 16; + if (!(x & (((uint64_t)1 << 8) - 1))) x >>= 8, pos += 8; + if (!(x & (((uint64_t)1 << 4) - 1))) x >>= 4, pos += 4; + if (!(x & (((uint64_t)1 << 2) - 1))) x >>= 2, pos += 2; + if (!(x & (((uint64_t)1 << 1) - 1))) x >>= 1, pos += 1; + + len = 0; + if (!(~x & (((uint64_t)1 << 32) - 1))) x >>= 32, len += 32; + if (!(~x & (((uint64_t)1 << 16) - 1))) x >>= 16, len += 16; + if (!(~x & (((uint64_t)1 << 8) - 1))) x >>= 8, len += 8; + if (!(~x & (((uint64_t)1 << 4) - 1))) x >>= 4, len += 4; + if (!(~x & (((uint64_t)1 << 2) - 1))) x >>= 2, len += 2; + if (!(~x & (((uint64_t)1 << 1) - 1))) x >>= 1, len += 1; + + if (x) + return -1; + if (neg) { + pos = (pos + len) & (rep - 1); + len = rep - len; + } + return ((0x1000 & rep << 6) | (((rep - 1) ^ 31) << 1 & 63) | + ((rep - pos) & (rep - 1)) << 6 | (len - 1)); +} + +static uint32_t arm64_movi(int r, uint64_t x) +{ + uint64_t m = 0xffff; + int e; + if (!(x & ~m)) + return 0x52800000 | r | x << 5; // movz w(r),#(x) + if (!(x & ~(m << 16))) + return 0x52a00000 | r | x >> 11; // movz w(r),#(x >> 16),lsl #16 + if (!(x & ~(m << 32))) + return 0xd2c00000 | r | x >> 27; // movz x(r),#(x >> 32),lsl #32 + if (!(x & ~(m << 48))) + return 0xd2e00000 | r | x >> 43; // movz x(r),#(x >> 48),lsl #48 + if ((x & ~m) == m << 16) + return (0x12800000 | r | + (~x << 5 & 0x1fffe0)); // movn w(r),#(~x) + if ((x & ~(m << 16)) == m) + return (0x12a00000 | r | + (~x >> 11 & 0x1fffe0)); // movn w(r),#(~x >> 16),lsl #16 + if (!~(x | m)) + return (0x92800000 | r | + (~x << 5 & 0x1fffe0)); // movn x(r),#(~x) + if (!~(x | m << 16)) + return (0x92a00000 | r | + (~x >> 11 & 0x1fffe0)); // movn x(r),#(~x >> 16),lsl #16 + if (!~(x | m << 32)) + return (0x92c00000 | r | + (~x >> 27 & 0x1fffe0)); // movn x(r),#(~x >> 32),lsl #32 + if (!~(x | m << 48)) + return (0x92e00000 | r | + (~x >> 43 & 0x1fffe0)); // movn x(r),#(~x >> 32),lsl #32 + if (!(x >> 32) && (e = arm64_encode_bimm64(x | x << 32)) >= 0) + return 0x320003e0 | r | (uint32_t)e << 10; // movi w(r),#(x) + if ((e = arm64_encode_bimm64(x)) >= 0) + return 0xb20003e0 | r | (uint32_t)e << 10; // movi x(r),#(x) + return 0; +} + +static void arm64_movimm(int r, uint64_t x) +{ + uint32_t i; + if ((i = arm64_movi(r, x))) + o(i); // a single MOV + else { + // MOVZ/MOVN and 1-3 MOVKs + int z = 0, m = 0; + uint32_t mov1 = 0xd2800000; // movz + uint64_t x1 = x; + for (i = 0; i < 64; i += 16) { + z += !(x >> i & 0xffff); + m += !(~x >> i & 0xffff); + } + if (m > z) { + x1 = ~x; + mov1 = 0x92800000; // movn + } + for (i = 0; i < 64; i += 16) + if (x1 >> i & 0xffff) { + o(mov1 | r | (x1 >> i & 0xffff) << 5 | i << 17); + // movz/movn x(r),#(*),lsl #(i) + break; + } + for (i += 16; i < 64; i += 16) + if (x1 >> i & 0xffff) + o(0xf2800000 | r | (x >> i & 0xffff) << 5 | i << 17); + // movk x(r),#(*),lsl #(i) + } +} + +// Patch all branches in list pointed to by t to branch to a: +ST_FUNC void gsym_addr(int t_, int a_) +{ + uint32_t t = t_; + uint32_t a = a_; + while (t) { + unsigned char *ptr = cur_text_section->data + t; + uint32_t next = read32le(ptr); + if (a - t + 0x8000000 >= 0x10000000) + tcc_error("branch out of range"); + write32le(ptr, (a - t == 4 ? 0xd503201f : // nop + 0x14000000 | ((a - t) >> 2 & 0x3ffffff))); // b + t = next; + } +} + +// Patch all branches in list pointed to by t to branch to current location: +ST_FUNC void gsym(int t) +{ + gsym_addr(t, ind); +} + +static int arm64_type_size(int t) +{ + switch (t & VT_BTYPE) { + case VT_INT: return 2; + case VT_BYTE: return 0; + case VT_SHORT: return 1; + case VT_PTR: return 3; + case VT_FUNC: return 3; + case VT_FLOAT: return 2; + case VT_DOUBLE: return 3; + case VT_LDOUBLE: return 4; + case VT_BOOL: return 0; + case VT_LLONG: return 3; + } + assert(0); + return 0; +} + +static void arm64_spoff(int reg, uint64_t off) +{ + uint32_t sub = off >> 63; + if (sub) + off = -off; + if (off < 4096) + o(0x910003e0 | sub << 30 | reg | off << 10); + // (add|sub) x(reg),sp,#(off) + else { + arm64_movimm(30, off); // use x30 for offset + o(0x8b3e63e0 | sub << 30 | reg); // (add|sub) x(reg),sp,x30 + } +} + +static void arm64_ldrx(int sg, int sz_, int dst, int bas, uint64_t off) +{ + uint32_t sz = sz_; + if (sz >= 2) + sg = 0; + if (!(off & ~((uint32_t)0xfff << sz))) + o(0x39400000 | dst | bas << 5 | off << (10 - sz) | + (uint32_t)!!sg << 23 | sz << 30); // ldr(*) x(dst),[x(bas),#(off)] + else if (off < 256 || -off <= 256) + o(0x38400000 | dst | bas << 5 | (off & 511) << 12 | + (uint32_t)!!sg << 23 | sz << 30); // ldur(*) x(dst),[x(bas),#(off)] + else { + arm64_movimm(30, off); // use x30 for offset + o(0x38206800 | dst | bas << 5 | (uint32_t)30 << 16 | + (uint32_t)(!!sg + 1) << 22 | sz << 30); // ldr(*) x(dst),[x(bas),x30] + } +} + +static void arm64_ldrv(int sz_, int dst, int bas, uint64_t off) +{ + uint32_t sz = sz_; + if (!(off & ~((uint32_t)0xfff << sz))) + o(0x3d400000 | dst | bas << 5 | off << (10 - sz) | + (sz & 4) << 21 | (sz & 3) << 30); // ldr (s|d|q)(dst),[x(bas),#(off)] + else if (off < 256 || -off <= 256) + o(0x3c400000 | dst | bas << 5 | (off & 511) << 12 | + (sz & 4) << 21 | (sz & 3) << 30); // ldur (s|d|q)(dst),[x(bas),#(off)] + else { + arm64_movimm(30, off); // use x30 for offset + o(0x3c606800 | dst | bas << 5 | (uint32_t)30 << 16 | + sz << 30 | (sz & 4) << 21); // ldr (s|d|q)(dst),[x(bas),x30] + } +} + +static void arm64_ldrs(int reg_, int size) +{ + uint32_t reg = reg_; + // Use x30 for intermediate value in some cases. + switch (size) { + default: assert(0); break; + case 1: + arm64_ldrx(0, 0, reg, reg, 0); + break; + case 2: + arm64_ldrx(0, 1, reg, reg, 0); + break; + case 3: + arm64_ldrx(0, 1, 30, reg, 0); + arm64_ldrx(0, 0, reg, reg, 2); + o(0x2a0043c0 | reg | reg << 16); // orr x(reg),x30,x(reg),lsl #16 + break; + case 4: + arm64_ldrx(0, 2, reg, reg, 0); + break; + case 5: + arm64_ldrx(0, 2, 30, reg, 0); + arm64_ldrx(0, 0, reg, reg, 4); + o(0xaa0083c0 | reg | reg << 16); // orr x(reg),x30,x(reg),lsl #32 + break; + case 6: + arm64_ldrx(0, 2, 30, reg, 0); + arm64_ldrx(0, 1, reg, reg, 4); + o(0xaa0083c0 | reg | reg << 16); // orr x(reg),x30,x(reg),lsl #32 + break; + case 7: + arm64_ldrx(0, 2, 30, reg, 0); + arm64_ldrx(0, 2, reg, reg, 3); + o(0x53087c00 | reg | reg << 5); // lsr w(reg), w(reg), #8 + o(0xaa0083c0 | reg | reg << 16); // orr x(reg),x30,x(reg),lsl #32 + break; + case 8: + arm64_ldrx(0, 3, reg, reg, 0); + break; + case 9: + arm64_ldrx(0, 0, reg + 1, reg, 8); + arm64_ldrx(0, 3, reg, reg, 0); + break; + case 10: + arm64_ldrx(0, 1, reg + 1, reg, 8); + arm64_ldrx(0, 3, reg, reg, 0); + break; + case 11: + arm64_ldrx(0, 2, reg + 1, reg, 7); + o(0x53087c00 | (reg+1) | (reg+1) << 5); // lsr w(reg+1), w(reg+1), #8 + arm64_ldrx(0, 3, reg, reg, 0); + break; + case 12: + arm64_ldrx(0, 2, reg + 1, reg, 8); + arm64_ldrx(0, 3, reg, reg, 0); + break; + case 13: + arm64_ldrx(0, 3, reg + 1, reg, 5); + o(0xd358fc00 | (reg+1) | (reg+1) << 5); // lsr x(reg+1), x(reg+1), #24 + arm64_ldrx(0, 3, reg, reg, 0); + break; + case 14: + arm64_ldrx(0, 3, reg + 1, reg, 6); + o(0xd350fc00 | (reg+1) | (reg+1) << 5); // lsr x(reg+1), x(reg+1), #16 + arm64_ldrx(0, 3, reg, reg, 0); + break; + case 15: + arm64_ldrx(0, 3, reg + 1, reg, 7); + o(0xd348fc00 | (reg+1) | (reg+1) << 5); // lsr x(reg+1), x(reg+1), #8 + arm64_ldrx(0, 3, reg, reg, 0); + break; + case 16: + o(0xa9400000 | reg | (reg+1) << 10 | reg << 5); + // ldp x(reg),x(reg+1),[x(reg)] + break; + } +} + +static void arm64_strx(int sz_, int dst, int bas, uint64_t off) +{ + uint32_t sz = sz_; + if (!(off & ~((uint32_t)0xfff << sz))) + o(0x39000000 | dst | bas << 5 | off << (10 - sz) | sz << 30); + // str(*) x(dst),[x(bas],#(off)] + else if (off < 256 || -off <= 256) + o(0x38000000 | dst | bas << 5 | (off & 511) << 12 | sz << 30); + // stur(*) x(dst),[x(bas],#(off)] + else { + arm64_movimm(30, off); // use x30 for offset + o(0x38206800 | dst | bas << 5 | (uint32_t)30 << 16 | sz << 30); + // str(*) x(dst),[x(bas),x30] + } +} + +static void arm64_strv(int sz_, int dst, int bas, uint64_t off) +{ + uint32_t sz = sz_; + if (!(off & ~((uint32_t)0xfff << sz))) + o(0x3d000000 | dst | bas << 5 | off << (10 - sz) | + (sz & 4) << 21 | (sz & 3) << 30); // str (s|d|q)(dst),[x(bas),#(off)] + else if (off < 256 || -off <= 256) + o(0x3c000000 | dst | bas << 5 | (off & 511) << 12 | + (sz & 4) << 21 | (sz & 3) << 30); // stur (s|d|q)(dst),[x(bas),#(off)] + else { + arm64_movimm(30, off); // use x30 for offset + o(0x3c206800 | dst | bas << 5 | (uint32_t)30 << 16 | + sz << 30 | (sz & 4) << 21); // str (s|d|q)(dst),[x(bas),x30] + } +} + +static void arm64_sym(int r, Sym *sym, unsigned long addend) +{ + // Currently TCC's linker does not generate COPY relocations for + // STT_OBJECTs when tcc is invoked with "-run". This typically + // results in "R_AARCH64_ADR_PREL_PG_HI21 relocation failed" when + // a program refers to stdin. A workaround is to avoid that + // relocation and use only relocations with unlimited range. + int avoid_adrp = 1; + + if (avoid_adrp || sym->a.weak) { + // (GCC uses a R_AARCH64_ABS64 in this case.) + greloca(cur_text_section, sym, ind, R_AARCH64_MOVW_UABS_G0_NC, addend); + o(0xd2800000 | r); // mov x(rt),#0,lsl #0 + greloca(cur_text_section, sym, ind, R_AARCH64_MOVW_UABS_G1_NC, addend); + o(0xf2a00000 | r); // movk x(rt),#0,lsl #16 + greloca(cur_text_section, sym, ind, R_AARCH64_MOVW_UABS_G2_NC, addend); + o(0xf2c00000 | r); // movk x(rt),#0,lsl #32 + greloca(cur_text_section, sym, ind, R_AARCH64_MOVW_UABS_G3, addend); + o(0xf2e00000 | r); // movk x(rt),#0,lsl #48 + } + else { + greloca(cur_text_section, sym, ind, R_AARCH64_ADR_PREL_PG_HI21, addend); + o(0x90000000 | r); + greloca(cur_text_section, sym, ind, R_AARCH64_ADD_ABS_LO12_NC, addend); + o(0x91000000 | r | r << 5); + } +} + +ST_FUNC void load(int r, SValue *sv) +{ + int svtt = sv->type.t; + int svr = sv->r & ~VT_LVAL_TYPE; + int svrv = svr & VT_VALMASK; + uint64_t svcul = (uint32_t)sv->c.i; + svcul = svcul >> 31 & 1 ? svcul - ((uint64_t)1 << 32) : svcul; + + if (svr == (VT_LOCAL | VT_LVAL)) { + if (IS_FREG(r)) + arm64_ldrv(arm64_type_size(svtt), fltr(r), 29, svcul); + else + arm64_ldrx(!(svtt & VT_UNSIGNED), arm64_type_size(svtt), + intr(r), 29, svcul); + return; + } + + if ((svr & ~VT_VALMASK) == VT_LVAL && svrv < VT_CONST) { + if (IS_FREG(r)) + arm64_ldrv(arm64_type_size(svtt), fltr(r), intr(svrv), 0); + else + arm64_ldrx(!(svtt & VT_UNSIGNED), arm64_type_size(svtt), + intr(r), intr(svrv), 0); + return; + } + + if (svr == (VT_CONST | VT_LVAL | VT_SYM)) { + arm64_sym(30, sv->sym, svcul); // use x30 for address + if (IS_FREG(r)) + arm64_ldrv(arm64_type_size(svtt), fltr(r), 30, 0); + else + arm64_ldrx(!(svtt & VT_UNSIGNED), arm64_type_size(svtt), + intr(r), 30, 0); + return; + } + + if (svr == (VT_CONST | VT_SYM)) { + arm64_sym(intr(r), sv->sym, svcul); + return; + } + + if (svr == VT_CONST) { + if ((svtt & VT_BTYPE) != VT_VOID) + arm64_movimm(intr(r), arm64_type_size(svtt) == 3 ? + sv->c.i : (uint32_t)svcul); + return; + } + + if (svr < VT_CONST) { + if (IS_FREG(r) && IS_FREG(svr)) + if (svtt == VT_LDOUBLE) + o(0x4ea01c00 | fltr(r) | fltr(svr) << 5); + // mov v(r).16b,v(svr).16b + else + o(0x1e604000 | fltr(r) | fltr(svr) << 5); // fmov d(r),d(svr) + else if (!IS_FREG(r) && !IS_FREG(svr)) + o(0xaa0003e0 | intr(r) | intr(svr) << 16); // mov x(r),x(svr) + else + assert(0); + return; + } + + if (svr == VT_LOCAL) { + if (-svcul < 0x1000) + o(0xd10003a0 | intr(r) | -svcul << 10); // sub x(r),x29,#... + else { + arm64_movimm(30, -svcul); // use x30 for offset + o(0xcb0003a0 | intr(r) | (uint32_t)30 << 16); // sub x(r),x29,x30 + } + return; + } + + if (svr == VT_JMP || svr == VT_JMPI) { + int t = (svr == VT_JMPI); + arm64_movimm(intr(r), t); + o(0x14000002); // b .+8 + gsym(svcul); + arm64_movimm(intr(r), t ^ 1); + return; + } + + if (svr == (VT_LLOCAL | VT_LVAL)) { + arm64_ldrx(0, 3, 30, 29, svcul); // use x30 for offset + if (IS_FREG(r)) + arm64_ldrv(arm64_type_size(svtt), fltr(r), 30, 0); + else + arm64_ldrx(!(svtt & VT_UNSIGNED), arm64_type_size(svtt), + intr(r), 30, 0); + return; + } + + printf("load(%x, (%x, %x, %llx))\n", r, svtt, sv->r, (long long)svcul); + assert(0); +} + +ST_FUNC void store(int r, SValue *sv) +{ + int svtt = sv->type.t; + int svr = sv->r & ~VT_LVAL_TYPE; + int svrv = svr & VT_VALMASK; + uint64_t svcul = (uint32_t)sv->c.i; + svcul = svcul >> 31 & 1 ? svcul - ((uint64_t)1 << 32) : svcul; + + if (svr == (VT_LOCAL | VT_LVAL)) { + if (IS_FREG(r)) + arm64_strv(arm64_type_size(svtt), fltr(r), 29, svcul); + else + arm64_strx(arm64_type_size(svtt), intr(r), 29, svcul); + return; + } + + if ((svr & ~VT_VALMASK) == VT_LVAL && svrv < VT_CONST) { + if (IS_FREG(r)) + arm64_strv(arm64_type_size(svtt), fltr(r), intr(svrv), 0); + else + arm64_strx(arm64_type_size(svtt), intr(r), intr(svrv), 0); + return; + } + + if (svr == (VT_CONST | VT_LVAL | VT_SYM)) { + arm64_sym(30, sv->sym, svcul); // use x30 for address + if (IS_FREG(r)) + arm64_strv(arm64_type_size(svtt), fltr(r), 30, 0); + else + arm64_strx(arm64_type_size(svtt), intr(r), 30, 0); + return; + } + + printf("store(%x, (%x, %x, %llx))\n", r, svtt, sv->r, (long long)svcul); + assert(0); +} + +static void arm64_gen_bl_or_b(int b) +{ + if ((vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST) { + assert(!b && (vtop->r & VT_SYM)); + greloca(cur_text_section, vtop->sym, ind, R_AARCH64_CALL26, 0); + o(0x94000000); // bl . + } + else + o(0xd61f0000 | (uint32_t)!b << 21 | intr(gv(RC_R30)) << 5); // br/blr +} + +static int arm64_hfa_aux(CType *type, int *fsize, int num) +{ + if (is_float(type->t)) { + int a, n = type_size(type, &a); + if (num >= 4 || (*fsize && *fsize != n)) + return -1; + *fsize = n; + return num + 1; + } + else if ((type->t & VT_BTYPE) == VT_STRUCT) { + int is_struct = 0; // rather than union + Sym *field; + for (field = type->ref->next; field; field = field->next) + if (field->c) { + is_struct = 1; + break; + } + if (is_struct) { + int num0 = num; + for (field = type->ref->next; field; field = field->next) { + if (field->c != (num - num0) * *fsize) + return -1; + num = arm64_hfa_aux(&field->type, fsize, num); + if (num == -1) + return -1; + } + if (type->ref->c != (num - num0) * *fsize) + return -1; + return num; + } + else { // union + int num0 = num; + for (field = type->ref->next; field; field = field->next) { + int num1 = arm64_hfa_aux(&field->type, fsize, num0); + if (num1 == -1) + return -1; + num = num1 < num ? num : num1; + } + if (type->ref->c != (num - num0) * *fsize) + return -1; + return num; + } + } + else if (type->t & VT_ARRAY) { + int num1; + if (!type->ref->c) + return num; + num1 = arm64_hfa_aux(&type->ref->type, fsize, num); + if (num1 == -1 || (num1 != num && type->ref->c > 4)) + return -1; + num1 = num + type->ref->c * (num1 - num); + if (num1 > 4) + return -1; + return num1; + } + return -1; +} + +static int arm64_hfa(CType *type, int *fsize) +{ + if ((type->t & VT_BTYPE) == VT_STRUCT || (type->t & VT_ARRAY)) { + int sz = 0; + int n = arm64_hfa_aux(type, &sz, 0); + if (0 < n && n <= 4) { + if (fsize) + *fsize = sz; + return n; + } + } + return 0; +} + +static unsigned long arm64_pcs_aux(int n, CType **type, unsigned long *a) +{ + int nx = 0; // next integer register + int nv = 0; // next vector register + unsigned long ns = 32; // next stack offset + int i; + + for (i = 0; i < n; i++) { + int hfa = arm64_hfa(type[i], 0); + int size, align; + + if ((type[i]->t & VT_ARRAY) || + (type[i]->t & VT_BTYPE) == VT_FUNC) + size = align = 8; + else + size = type_size(type[i], &align); + + if (hfa) + // B.2 + ; + else if (size > 16) { + // B.3: replace with pointer + if (nx < 8) + a[i] = nx++ << 1 | 1; + else { + ns = (ns + 7) & ~7; + a[i] = ns | 1; + ns += 8; + } + continue; + } + else if ((type[i]->t & VT_BTYPE) == VT_STRUCT) + // B.4 + size = (size + 7) & ~7; + + // C.1 + if (is_float(type[i]->t) && nv < 8) { + a[i] = 16 + (nv++ << 1); + continue; + } + + // C.2 + if (hfa && nv + hfa <= 8) { + a[i] = 16 + (nv << 1); + nv += hfa; + continue; + } + + // C.3 + if (hfa) { + nv = 8; + size = (size + 7) & ~7; + } + + // C.4 + if (hfa || (type[i]->t & VT_BTYPE) == VT_LDOUBLE) { + ns = (ns + 7) & ~7; + ns = (ns + align - 1) & -align; + } + + // C.5 + if ((type[i]->t & VT_BTYPE) == VT_FLOAT) + size = 8; + + // C.6 + if (hfa || is_float(type[i]->t)) { + a[i] = ns; + ns += size; + continue; + } + + // C.7 + if ((type[i]->t & VT_BTYPE) != VT_STRUCT && size <= 8 && nx < 8) { + a[i] = nx++ << 1; + continue; + } + + // C.8 + if (align == 16) + nx = (nx + 1) & ~1; + + // C.9 + if ((type[i]->t & VT_BTYPE) != VT_STRUCT && size == 16 && nx < 7) { + a[i] = nx << 1; + nx += 2; + continue; + } + + // C.10 + if ((type[i]->t & VT_BTYPE) == VT_STRUCT && size <= (8 - nx) * 8) { + a[i] = nx << 1; + nx += (size + 7) >> 3; + continue; + } + + // C.11 + nx = 8; + + // C.12 + ns = (ns + 7) & ~7; + ns = (ns + align - 1) & -align; + + // C.13 + if ((type[i]->t & VT_BTYPE) == VT_STRUCT) { + a[i] = ns; + ns += size; + continue; + } + + // C.14 + if (size < 8) + size = 8; + + // C.15 + a[i] = ns; + ns += size; + } + + return ns - 32; +} + +static unsigned long arm64_pcs(int n, CType **type, unsigned long *a) +{ + unsigned long stack; + + // Return type: + if ((type[0]->t & VT_BTYPE) == VT_VOID) + a[0] = -1; + else { + arm64_pcs_aux(1, type, a); + assert(a[0] == 0 || a[0] == 1 || a[0] == 16); + } + + // Argument types: + stack = arm64_pcs_aux(n, type + 1, a + 1); + + if (0) { + int i; + for (i = 0; i <= n; i++) { + if (!i) + printf("arm64_pcs return: "); + else + printf("arm64_pcs arg %d: ", i); + if (a[i] == (unsigned long)-1) + printf("void\n"); + else if (a[i] == 1 && !i) + printf("X8 pointer\n"); + else if (a[i] < 16) + printf("X%lu%s\n", a[i] / 2, a[i] & 1 ? " pointer" : ""); + else if (a[i] < 32) + printf("V%lu\n", a[i] / 2 - 8); + else + printf("stack %lu%s\n", + (a[i] - 32) & ~1, a[i] & 1 ? " pointer" : ""); + } + } + + return stack; +} + +ST_FUNC void gfunc_call(int nb_args) +{ + CType *return_type; + CType **t; + unsigned long *a, *a1; + unsigned long stack; + int i; + + return_type = &vtop[-nb_args].type.ref->type; + if ((return_type->t & VT_BTYPE) == VT_STRUCT) + --nb_args; + + t = tcc_malloc((nb_args + 1) * sizeof(*t)); + a = tcc_malloc((nb_args + 1) * sizeof(*a)); + a1 = tcc_malloc((nb_args + 1) * sizeof(*a1)); + + t[0] = return_type; + for (i = 0; i < nb_args; i++) + t[nb_args - i] = &vtop[-i].type; + + stack = arm64_pcs(nb_args, t, a); + + // Allocate space for structs replaced by pointer: + for (i = nb_args; i; i--) + if (a[i] & 1) { + SValue *arg = &vtop[i - nb_args]; + int align, size = type_size(&arg->type, &align); + assert((arg->type.t & VT_BTYPE) == VT_STRUCT); + stack = (stack + align - 1) & -align; + a1[i] = stack; + stack += size; + } + + stack = (stack + 15) >> 4 << 4; + + assert(stack < 0x1000); + if (stack) + o(0xd10003ff | stack << 10); // sub sp,sp,#(n) + + // First pass: set all values on stack + for (i = nb_args; i; i--) { + vpushv(vtop - nb_args + i); + + if (a[i] & 1) { + // struct replaced by pointer + int r = get_reg(RC_INT); + arm64_spoff(intr(r), a1[i]); + vset(&vtop->type, r | VT_LVAL, 0); + vswap(); + vstore(); + if (a[i] >= 32) { + // pointer on stack + r = get_reg(RC_INT); + arm64_spoff(intr(r), a1[i]); + arm64_strx(3, intr(r), 31, (a[i] - 32) >> 1 << 1); + } + } + else if (a[i] >= 32) { + // value on stack + if ((vtop->type.t & VT_BTYPE) == VT_STRUCT) { + int r = get_reg(RC_INT); + arm64_spoff(intr(r), a[i] - 32); + vset(&vtop->type, r | VT_LVAL, 0); + vswap(); + vstore(); + } + else if (is_float(vtop->type.t)) { + gv(RC_FLOAT); + arm64_strv(arm64_type_size(vtop[0].type.t), + fltr(vtop[0].r), 31, a[i] - 32); + } + else { + gv(RC_INT); + arm64_strx(arm64_type_size(vtop[0].type.t), + intr(vtop[0].r), 31, a[i] - 32); + } + } + + --vtop; + } + + // Second pass: assign values to registers + for (i = nb_args; i; i--, vtop--) { + if (a[i] < 16 && !(a[i] & 1)) { + // value in general-purpose registers + if ((vtop->type.t & VT_BTYPE) == VT_STRUCT) { + int align, size = type_size(&vtop->type, &align); + vtop->type.t = VT_PTR; + gaddrof(); + gv(RC_R(a[i] / 2)); + arm64_ldrs(a[i] / 2, size); + } + else + gv(RC_R(a[i] / 2)); + } + else if (a[i] < 16) + // struct replaced by pointer in register + arm64_spoff(a[i] / 2, a1[i]); + else if (a[i] < 32) { + // value in floating-point registers + if ((vtop->type.t & VT_BTYPE) == VT_STRUCT) { + uint32_t j, sz, n = arm64_hfa(&vtop->type, &sz); + vtop->type.t = VT_PTR; + gaddrof(); + gv(RC_R30); + for (j = 0; j < n; j++) + o(0x3d4003c0 | + (sz & 16) << 19 | -(sz & 8) << 27 | (sz & 4) << 29 | + (a[i] / 2 - 8 + j) | + j << 10); // ldr ([sdq])(*),[x30,#(j * sz)] + } + else + gv(RC_F(a[i] / 2 - 8)); + } + } + + if ((return_type->t & VT_BTYPE) == VT_STRUCT) { + if (a[0] == 1) { + // indirect return: set x8 and discard the stack value + gv(RC_R(8)); + --vtop; + } + else + // return in registers: keep the address for after the call + vswap(); + } + + save_regs(0); + arm64_gen_bl_or_b(0); + --vtop; + if (stack) + o(0x910003ff | stack << 10); // add sp,sp,#(n) + + { + int rt = return_type->t; + int bt = rt & VT_BTYPE; + if (bt == VT_BYTE || bt == VT_SHORT) + // Promote small integers: + o(0x13001c00 | (bt == VT_SHORT) << 13 | + (uint32_t)!!(rt & VT_UNSIGNED) << 30); // [su]xt[bh] w0,w0 + else if (bt == VT_STRUCT && !(a[0] & 1)) { + // A struct was returned in registers, so write it out: + gv(RC_R(8)); + --vtop; + if (a[0] == 0) { + int align, size = type_size(return_type, &align); + assert(size <= 16); + if (size > 8) + o(0xa9000500); // stp x0,x1,[x8] + else if (size) + arm64_strx(size > 4 ? 3 : size > 2 ? 2 : size > 1, 0, 8, 0); + + } + else if (a[0] == 16) { + uint32_t j, sz, n = arm64_hfa(return_type, &sz); + for (j = 0; j < n; j++) + o(0x3d000100 | + (sz & 16) << 19 | -(sz & 8) << 27 | (sz & 4) << 29 | + (a[i] / 2 - 8 + j) | + j << 10); // str ([sdq])(*),[x8,#(j * sz)] + } + } + } + + tcc_free(a1); + tcc_free(a); + tcc_free(t); +} + +static unsigned long arm64_func_va_list_stack; +static int arm64_func_va_list_gr_offs; +static int arm64_func_va_list_vr_offs; +static int arm64_func_sub_sp_offset; + +ST_FUNC void gfunc_prolog(CType *func_type) +{ + int n = 0; + int i = 0; + Sym *sym; + CType **t; + unsigned long *a; + + // Why doesn't the caller (gen_function) set func_vt? + func_vt = func_type->ref->type; + func_vc = 144; // offset of where x8 is stored + + for (sym = func_type->ref; sym; sym = sym->next) + ++n; + t = tcc_malloc(n * sizeof(*t)); + a = tcc_malloc(n * sizeof(*a)); + + for (sym = func_type->ref; sym; sym = sym->next) + t[i++] = &sym->type; + + arm64_func_va_list_stack = arm64_pcs(n - 1, t, a); + + o(0xa9b27bfd); // stp x29,x30,[sp,#-224]! + o(0xad0087e0); // stp q0,q1,[sp,#16] + o(0xad018fe2); // stp q2,q3,[sp,#48] + o(0xad0297e4); // stp q4,q5,[sp,#80] + o(0xad039fe6); // stp q6,q7,[sp,#112] + o(0xa90923e8); // stp x8,x8,[sp,#144] + o(0xa90a07e0); // stp x0,x1,[sp,#160] + o(0xa90b0fe2); // stp x2,x3,[sp,#176] + o(0xa90c17e4); // stp x4,x5,[sp,#192] + o(0xa90d1fe6); // stp x6,x7,[sp,#208] + + arm64_func_va_list_gr_offs = -64; + arm64_func_va_list_vr_offs = -128; + + for (i = 1, sym = func_type->ref->next; sym; i++, sym = sym->next) { + int off = (a[i] < 16 ? 160 + a[i] / 2 * 8 : + a[i] < 32 ? 16 + (a[i] - 16) / 2 * 16 : + 224 + ((a[i] - 32) >> 1 << 1)); + sym_push(sym->v & ~SYM_FIELD, &sym->type, + (a[i] & 1 ? VT_LLOCAL : VT_LOCAL) | lvalue_type(sym->type.t), + off); + + if (a[i] < 16) { + int align, size = type_size(&sym->type, &align); + arm64_func_va_list_gr_offs = (a[i] / 2 - 7 + + (!(a[i] & 1) && size > 8)) * 8; + } + else if (a[i] < 32) { + uint32_t hfa = arm64_hfa(&sym->type, 0); + arm64_func_va_list_vr_offs = (a[i] / 2 - 16 + + (hfa ? hfa : 1)) * 16; + } + + // HFAs of float and double need to be written differently: + if (16 <= a[i] && a[i] < 32 && (sym->type.t & VT_BTYPE) == VT_STRUCT) { + uint32_t j, sz, k = arm64_hfa(&sym->type, &sz); + if (sz < 16) + for (j = 0; j < k; j++) { + o(0x3d0003e0 | -(sz & 8) << 27 | (sz & 4) << 29 | + ((a[i] - 16) / 2 + j) | (off / sz + j) << 10); + // str ([sdq])(*),[sp,#(j * sz)] + } + } + } + + tcc_free(a); + tcc_free(t); + + o(0x910003fd); // mov x29,sp + arm64_func_sub_sp_offset = ind; + // In gfunc_epilog these will be replaced with code to decrement SP: + o(0xd503201f); // nop + o(0xd503201f); // nop + loc = 0; +} + +ST_FUNC void gen_va_start(void) +{ + int r; + --vtop; // we don't need the "arg" + gaddrof(); + r = intr(gv(RC_INT)); + + if (arm64_func_va_list_stack) { + //xx could use add (immediate) here + arm64_movimm(30, arm64_func_va_list_stack + 224); + o(0x8b1e03be); // add x30,x29,x30 + } + else + o(0x910383be); // add x30,x29,#224 + o(0xf900001e | r << 5); // str x30,[x(r)] + + if (arm64_func_va_list_gr_offs) { + if (arm64_func_va_list_stack) + o(0x910383be); // add x30,x29,#224 + o(0xf900041e | r << 5); // str x30,[x(r),#8] + } + + if (arm64_func_va_list_vr_offs) { + o(0x910243be); // add x30,x29,#144 + o(0xf900081e | r << 5); // str x30,[x(r),#16] + } + + arm64_movimm(30, arm64_func_va_list_gr_offs); + o(0xb900181e | r << 5); // str w30,[x(r),#24] + + arm64_movimm(30, arm64_func_va_list_vr_offs); + o(0xb9001c1e | r << 5); // str w30,[x(r),#28] + + --vtop; +} + +ST_FUNC void gen_va_arg(CType *t) +{ + int align, size = type_size(t, &align); + int fsize, hfa = arm64_hfa(t, &fsize); + uint32_t r0, r1; + + if (is_float(t->t)) { + hfa = 1; + fsize = size; + } + + gaddrof(); + r0 = intr(gv(RC_INT)); + r1 = get_reg(RC_INT); + vtop[0].r = r1 | lvalue_type(t->t); + r1 = intr(r1); + + if (!hfa) { + uint32_t n = size > 16 ? 8 : (size + 7) & -8; + o(0xb940181e | r0 << 5); // ldr w30,[x(r0),#24] // __gr_offs + if (align == 16) { + assert(0); // this path untested but needed for __uint128_t + o(0x11003fde); // add w30,w30,#15 + o(0x121c6fde); // and w30,w30,#-16 + } + o(0x310003c0 | r1 | n << 10); // adds w(r1),w30,#(n) + o(0x540000ad); // b.le .+20 + o(0xf9400000 | r1 | r0 << 5); // ldr x(r1),[x(r0)] // __stack + o(0x9100001e | r1 << 5 | n << 10); // add x30,x(r1),#(n) + o(0xf900001e | r0 << 5); // str x30,[x(r0)] // __stack + o(0x14000004); // b .+16 + o(0xb9001800 | r1 | r0 << 5); // str w(r1),[x(r0),#24] // __gr_offs + o(0xf9400400 | r1 | r0 << 5); // ldr x(r1),[x(r0),#8] // __gr_top + o(0x8b3ec000 | r1 | r1 << 5); // add x(r1),x(r1),w30,sxtw + if (size > 16) + o(0xf9400000 | r1 | r1 << 5); // ldr x(r1),[x(r1)] + } + else { + uint32_t rsz = hfa << 4; + uint32_t ssz = (size + 7) & -(uint32_t)8; + uint32_t b1, b2; + o(0xb9401c1e | r0 << 5); // ldr w30,[x(r0),#28] // __vr_offs + o(0x310003c0 | r1 | rsz << 10); // adds w(r1),w30,#(rsz) + b1 = ind; o(0x5400000d); // b.le lab1 + o(0xf9400000 | r1 | r0 << 5); // ldr x(r1),[x(r0)] // __stack + if (fsize == 16) { + o(0x91003c00 | r1 | r1 << 5); // add x(r1),x(r1),#15 + o(0x927cec00 | r1 | r1 << 5); // and x(r1),x(r1),#-16 + } + o(0x9100001e | r1 << 5 | ssz << 10); // add x30,x(r1),#(ssz) + o(0xf900001e | r0 << 5); // str x30,[x(r0)] // __stack + b2 = ind; o(0x14000000); // b lab2 + // lab1: + write32le(cur_text_section->data + b1, 0x5400000d | (ind - b1) << 3); + o(0xb9001c00 | r1 | r0 << 5); // str w(r1),[x(r0),#28] // __vr_offs + o(0xf9400800 | r1 | r0 << 5); // ldr x(r1),[x(r0),#16] // __vr_top + if (hfa == 1 || fsize == 16) + o(0x8b3ec000 | r1 | r1 << 5); // add x(r1),x(r1),w30,sxtw + else { + // We need to change the layout of this HFA. + // Get some space on the stack using global variable "loc": + loc = (loc - size) & -(uint32_t)align; + o(0x8b3ec000 | 30 | r1 << 5); // add x30,x(r1),w30,sxtw + arm64_movimm(r1, loc); + o(0x8b0003a0 | r1 | r1 << 16); // add x(r1),x29,x(r1) + o(0x4c402bdc | (uint32_t)fsize << 7 | + (uint32_t)(hfa == 2) << 15 | + (uint32_t)(hfa == 3) << 14); // ld1 {v28.(4s|2d),...},[x30] + o(0x0d00801c | r1 << 5 | (fsize == 8) << 10 | + (uint32_t)(hfa != 2) << 13 | + (uint32_t)(hfa != 3) << 21); // st(hfa) {v28.(s|d),...}[0],[x(r1)] + } + // lab2: + write32le(cur_text_section->data + b2, 0x14000000 | (ind - b2) >> 2); + } +} + +ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, + int *align, int *regsize) +{ + return 0; +} + +ST_FUNC void gfunc_return(CType *func_type) +{ + CType *t = func_type; + unsigned long a; + + arm64_pcs(0, &t, &a); + switch (a) { + case -1: + break; + case 0: + if ((func_type->t & VT_BTYPE) == VT_STRUCT) { + int align, size = type_size(func_type, &align); + gaddrof(); + gv(RC_R(0)); + arm64_ldrs(0, size); + } + else + gv(RC_IRET); + break; + case 1: { + CType type = *func_type; + mk_pointer(&type); + vset(&type, VT_LOCAL | VT_LVAL, func_vc); + indir(); + vswap(); + vstore(); + break; + } + case 16: + if ((func_type->t & VT_BTYPE) == VT_STRUCT) { + uint32_t j, sz, n = arm64_hfa(&vtop->type, &sz); + gaddrof(); + gv(RC_R(0)); + for (j = 0; j < n; j++) + o(0x3d400000 | + (sz & 16) << 19 | -(sz & 8) << 27 | (sz & 4) << 29 | + j | j << 10); // ldr ([sdq])(*),[x0,#(j * sz)] + } + else + gv(RC_FRET); + break; + default: + assert(0); + } + vtop--; +} + +ST_FUNC void gfunc_epilog(void) +{ + if (loc) { + // Insert instructions to subtract size of stack frame from SP. + unsigned char *ptr = cur_text_section->data + arm64_func_sub_sp_offset; + uint64_t diff = (-loc + 15) & ~15; + if (!(diff >> 24)) { + if (diff & 0xfff) // sub sp,sp,#(diff & 0xfff) + write32le(ptr, 0xd10003ff | (diff & 0xfff) << 10); + if (diff >> 12) // sub sp,sp,#(diff >> 12),lsl #12 + write32le(ptr + 4, 0xd14003ff | (diff >> 12) << 10); + } + else { + // In this case we may subtract more than necessary, + // but always less than 17/16 of what we were aiming for. + int i = 0; + int j = 0; + while (diff >> 20) { + diff = (diff + 0xffff) >> 16; + ++i; + } + while (diff >> 16) { + diff = (diff + 1) >> 1; + ++j; + } + write32le(ptr, 0xd2800010 | diff << 5 | i << 21); + // mov x16,#(diff),lsl #(16 * i) + write32le(ptr + 4, 0xcb3063ff | j << 10); + // sub sp,sp,x16,lsl #(j) + } + } + o(0x910003bf); // mov sp,x29 + o(0xa8ce7bfd); // ldp x29,x30,[sp],#224 + + o(0xd65f03c0); // ret +} + +// Generate forward branch to label: +ST_FUNC int gjmp(int t) +{ + int r = ind; + if (nocode_wanted) + return t; + o(t); + return r; +} + +// Generate branch to known address: +ST_FUNC void gjmp_addr(int a) +{ + assert(a - ind + 0x8000000 < 0x10000000); + o(0x14000000 | ((a - ind) >> 2 & 0x3ffffff)); +} + +ST_FUNC int gtst(int inv, int t) +{ + int bt = vtop->type.t & VT_BTYPE; + if (bt == VT_LDOUBLE) { + uint32_t a, b, f = fltr(gv(RC_FLOAT)); + a = get_reg(RC_INT); + vpushi(0); + vtop[0].r = a; + b = get_reg(RC_INT); + a = intr(a); + b = intr(b); + o(0x4e083c00 | a | f << 5); // mov x(a),v(f).d[0] + o(0x4e183c00 | b | f << 5); // mov x(b),v(f).d[1] + o(0xaa000400 | a | a << 5 | b << 16); // orr x(a),x(a),x(b),lsl #1 + o(0xb4000040 | a | !!inv << 24); // cbz/cbnz x(a),.+8 + --vtop; + } + else if (bt == VT_FLOAT || bt == VT_DOUBLE) { + uint32_t a = fltr(gv(RC_FLOAT)); + o(0x1e202008 | a << 5 | (bt != VT_FLOAT) << 22); // fcmp + o(0x54000040 | !!inv); // b.eq/b.ne .+8 + } + else { + uint32_t ll = (bt == VT_PTR || bt == VT_LLONG); + uint32_t a = intr(gv(RC_INT)); + o(0x34000040 | a | !!inv << 24 | ll << 31); // cbz/cbnz wA,.+8 + } + --vtop; + return gjmp(t); +} + +static int arm64_iconst(uint64_t *val, SValue *sv) +{ + if ((sv->r & (VT_VALMASK | VT_LVAL | VT_SYM)) != VT_CONST) + return 0; + if (val) { + int t = sv->type.t; + int bt = t & VT_BTYPE; + *val = ((bt == VT_LLONG || bt == VT_PTR) ? sv->c.i : + (uint32_t)sv->c.i | + (t & VT_UNSIGNED ? 0 : -(sv->c.i & 0x80000000))); + } + return 1; +} + +static int arm64_gen_opic(int op, uint32_t l, int rev, uint64_t val, + uint32_t x, uint32_t a) +{ + if (op == '-' && !rev) { + val = -val; + op = '+'; + } + val = l ? val : (uint32_t)val; + + switch (op) { + + case '+': { + uint32_t s = l ? val >> 63 : val >> 31; + val = s ? -val : val; + val = l ? val : (uint32_t)val; + if (!(val & ~(uint64_t)0xfff)) + o(0x11000000 | l << 31 | s << 30 | x | a << 5 | val << 10); + else if (!(val & ~(uint64_t)0xfff000)) + o(0x11400000 | l << 31 | s << 30 | x | a << 5 | val >> 12 << 10); + else { + arm64_movimm(30, val); // use x30 + o(0x0b1e0000 | l << 31 | s << 30 | x | a << 5); + } + return 1; + } + + case '-': + if (!val) + o(0x4b0003e0 | l << 31 | x | a << 16); // neg + else if (val == (l ? (uint64_t)-1 : (uint32_t)-1)) + o(0x2a2003e0 | l << 31 | x | a << 16); // mvn + else { + arm64_movimm(30, val); // use x30 + o(0x4b0003c0 | l << 31 | x | a << 16); // sub + } + return 1; + + case '^': + if (val == -1 || (val == 0xffffffff && !l)) { + o(0x2a2003e0 | l << 31 | x | a << 16); // mvn + return 1; + } + // fall through + case '&': + case '|': { + int e = arm64_encode_bimm64(l ? val : val | val << 32); + if (e < 0) + return 0; + o((op == '&' ? 0x12000000 : + op == '|' ? 0x32000000 : 0x52000000) | + l << 31 | x | a << 5 | (uint32_t)e << 10); + return 1; + } + + case TOK_SAR: + case TOK_SHL: + case TOK_SHR: { + uint32_t n = 32 << l; + val = val & (n - 1); + if (rev) + return 0; + if (!val) + assert(0); + else if (op == TOK_SHL) + o(0x53000000 | l << 31 | l << 22 | x | a << 5 | + (n - val) << 16 | (n - 1 - val) << 10); // lsl + else + o(0x13000000 | (op == TOK_SHR) << 30 | l << 31 | l << 22 | + x | a << 5 | val << 16 | (n - 1) << 10); // lsr/asr + return 1; + } + + } + return 0; +} + +static void arm64_gen_opil(int op, uint32_t l) +{ + uint32_t x, a, b; + + // Special treatment for operations with a constant operand: + { + uint64_t val; + int rev = 1; + + if (arm64_iconst(0, &vtop[0])) { + vswap(); + rev = 0; + } + if (arm64_iconst(&val, &vtop[-1])) { + gv(RC_INT); + a = intr(vtop[0].r); + --vtop; + x = get_reg(RC_INT); + ++vtop; + if (arm64_gen_opic(op, l, rev, val, intr(x), a)) { + vtop[0].r = x; + vswap(); + --vtop; + return; + } + } + if (!rev) + vswap(); + } + + gv2(RC_INT, RC_INT); + assert(vtop[-1].r < VT_CONST && vtop[0].r < VT_CONST); + a = intr(vtop[-1].r); + b = intr(vtop[0].r); + vtop -= 2; + x = get_reg(RC_INT); + ++vtop; + vtop[0].r = x; + x = intr(x); + + switch (op) { + case '%': + // Use x30 for quotient: + o(0x1ac00c00 | l << 31 | 30 | a << 5 | b << 16); // sdiv + o(0x1b008000 | l << 31 | x | (uint32_t)30 << 5 | + b << 16 | a << 10); // msub + break; + case '&': + o(0x0a000000 | l << 31 | x | a << 5 | b << 16); // and + break; + case '*': + o(0x1b007c00 | l << 31 | x | a << 5 | b << 16); // mul + break; + case '+': + o(0x0b000000 | l << 31 | x | a << 5 | b << 16); // add + break; + case '-': + o(0x4b000000 | l << 31 | x | a << 5 | b << 16); // sub + break; + case '/': + o(0x1ac00c00 | l << 31 | x | a << 5 | b << 16); // sdiv + break; + case '^': + o(0x4a000000 | l << 31 | x | a << 5 | b << 16); // eor + break; + case '|': + o(0x2a000000 | l << 31 | x | a << 5 | b << 16); // orr + break; + case TOK_EQ: + o(0x6b00001f | l << 31 | a << 5 | b << 16); // cmp + o(0x1a9f17e0 | x); // cset wA,eq + break; + case TOK_GE: + o(0x6b00001f | l << 31 | a << 5 | b << 16); // cmp + o(0x1a9fb7e0 | x); // cset wA,ge + break; + case TOK_GT: + o(0x6b00001f | l << 31 | a << 5 | b << 16); // cmp + o(0x1a9fd7e0 | x); // cset wA,gt + break; + case TOK_LE: + o(0x6b00001f | l << 31 | a << 5 | b << 16); // cmp + o(0x1a9fc7e0 | x); // cset wA,le + break; + case TOK_LT: + o(0x6b00001f | l << 31 | a << 5 | b << 16); // cmp + o(0x1a9fa7e0 | x); // cset wA,lt + break; + case TOK_NE: + o(0x6b00001f | l << 31 | a << 5 | b << 16); // cmp + o(0x1a9f07e0 | x); // cset wA,ne + break; + case TOK_SAR: + o(0x1ac02800 | l << 31 | x | a << 5 | b << 16); // asr + break; + case TOK_SHL: + o(0x1ac02000 | l << 31 | x | a << 5 | b << 16); // lsl + break; + case TOK_SHR: + o(0x1ac02400 | l << 31 | x | a << 5 | b << 16); // lsr + break; + case TOK_UDIV: + case TOK_PDIV: + o(0x1ac00800 | l << 31 | x | a << 5 | b << 16); // udiv + break; + case TOK_UGE: + o(0x6b00001f | l << 31 | a << 5 | b << 16); // cmp + o(0x1a9f37e0 | x); // cset wA,cs + break; + case TOK_UGT: + o(0x6b00001f | l << 31 | a << 5 | b << 16); // cmp + o(0x1a9f97e0 | x); // cset wA,hi + break; + case TOK_ULT: + o(0x6b00001f | l << 31 | a << 5 | b << 16); // cmp + o(0x1a9f27e0 | x); // cset wA,cc + break; + case TOK_ULE: + o(0x6b00001f | l << 31 | a << 5 | b << 16); // cmp + o(0x1a9f87e0 | x); // cset wA,ls + break; + case TOK_UMOD: + // Use x30 for quotient: + o(0x1ac00800 | l << 31 | 30 | a << 5 | b << 16); // udiv + o(0x1b008000 | l << 31 | x | (uint32_t)30 << 5 | + b << 16 | a << 10); // msub + break; + default: + assert(0); + } +} + +ST_FUNC void gen_opi(int op) +{ + arm64_gen_opil(op, 0); +} + +ST_FUNC void gen_opl(int op) +{ + arm64_gen_opil(op, 1); +} + +ST_FUNC void gen_opf(int op) +{ + uint32_t x, a, b, dbl; + + if (vtop[0].type.t == VT_LDOUBLE) { + CType type = vtop[0].type; + int func = 0; + int cond = -1; + switch (op) { + case '*': func = TOK___multf3; break; + case '+': func = TOK___addtf3; break; + case '-': func = TOK___subtf3; break; + case '/': func = TOK___divtf3; break; + case TOK_EQ: func = TOK___eqtf2; cond = 1; break; + case TOK_NE: func = TOK___netf2; cond = 0; break; + case TOK_LT: func = TOK___lttf2; cond = 10; break; + case TOK_GE: func = TOK___getf2; cond = 11; break; + case TOK_LE: func = TOK___letf2; cond = 12; break; + case TOK_GT: func = TOK___gttf2; cond = 13; break; + default: assert(0); break; + } + vpush_global_sym(&func_old_type, func); + vrott(3); + gfunc_call(2); + vpushi(0); + vtop->r = cond < 0 ? REG_FRET : REG_IRET; + if (cond < 0) + vtop->type = type; + else { + o(0x7100001f); // cmp w0,#0 + o(0x1a9f07e0 | (uint32_t)cond << 12); // cset w0,(cond) + } + return; + } + + dbl = vtop[0].type.t != VT_FLOAT; + gv2(RC_FLOAT, RC_FLOAT); + assert(vtop[-1].r < VT_CONST && vtop[0].r < VT_CONST); + a = fltr(vtop[-1].r); + b = fltr(vtop[0].r); + vtop -= 2; + switch (op) { + case TOK_EQ: case TOK_NE: + case TOK_LT: case TOK_GE: case TOK_LE: case TOK_GT: + x = get_reg(RC_INT); + ++vtop; + vtop[0].r = x; + x = intr(x); + break; + default: + x = get_reg(RC_FLOAT); + ++vtop; + vtop[0].r = x; + x = fltr(x); + break; + } + + switch (op) { + case '*': + o(0x1e200800 | dbl << 22 | x | a << 5 | b << 16); // fmul + break; + case '+': + o(0x1e202800 | dbl << 22 | x | a << 5 | b << 16); // fadd + break; + case '-': + o(0x1e203800 | dbl << 22 | x | a << 5 | b << 16); // fsub + break; + case '/': + o(0x1e201800 | dbl << 22 | x | a << 5 | b << 16); // fdiv + break; + case TOK_EQ: + o(0x1e202000 | dbl << 22 | a << 5 | b << 16); // fcmp + o(0x1a9f17e0 | x); // cset w(x),eq + break; + case TOK_GE: + o(0x1e202000 | dbl << 22 | a << 5 | b << 16); // fcmp + o(0x1a9fb7e0 | x); // cset w(x),ge + break; + case TOK_GT: + o(0x1e202000 | dbl << 22 | a << 5 | b << 16); // fcmp + o(0x1a9fd7e0 | x); // cset w(x),gt + break; + case TOK_LE: + o(0x1e202000 | dbl << 22 | a << 5 | b << 16); // fcmp + o(0x1a9f87e0 | x); // cset w(x),ls + break; + case TOK_LT: + o(0x1e202000 | dbl << 22 | a << 5 | b << 16); // fcmp + o(0x1a9f57e0 | x); // cset w(x),mi + break; + case TOK_NE: + o(0x1e202000 | dbl << 22 | a << 5 | b << 16); // fcmp + o(0x1a9f07e0 | x); // cset w(x),ne + break; + default: + assert(0); + } +} + +// Generate sign extension from 32 to 64 bits: +ST_FUNC void gen_cvt_sxtw(void) +{ + uint32_t r = intr(gv(RC_INT)); + o(0x93407c00 | r | r << 5); // sxtw x(r),w(r) +} + +ST_FUNC void gen_cvt_itof(int t) +{ + if (t == VT_LDOUBLE) { + int f = vtop->type.t; + int func = (f & VT_BTYPE) == VT_LLONG ? + (f & VT_UNSIGNED ? TOK___floatunditf : TOK___floatditf) : + (f & VT_UNSIGNED ? TOK___floatunsitf : TOK___floatsitf); + vpush_global_sym(&func_old_type, func); + vrott(2); + gfunc_call(1); + vpushi(0); + vtop->type.t = t; + vtop->r = REG_FRET; + return; + } + else { + int d, n = intr(gv(RC_INT)); + int s = !(vtop->type.t & VT_UNSIGNED); + uint32_t l = ((vtop->type.t & VT_BTYPE) == VT_LLONG); + --vtop; + d = get_reg(RC_FLOAT); + ++vtop; + vtop[0].r = d; + o(0x1e220000 | (uint32_t)!s << 16 | + (uint32_t)(t != VT_FLOAT) << 22 | fltr(d) | + l << 31 | n << 5); // [us]cvtf [sd](d),[wx](n) + } +} + +ST_FUNC void gen_cvt_ftoi(int t) +{ + if ((vtop->type.t & VT_BTYPE) == VT_LDOUBLE) { + int func = (t & VT_BTYPE) == VT_LLONG ? + (t & VT_UNSIGNED ? TOK___fixunstfdi : TOK___fixtfdi) : + (t & VT_UNSIGNED ? TOK___fixunstfsi : TOK___fixtfsi); + vpush_global_sym(&func_old_type, func); + vrott(2); + gfunc_call(1); + vpushi(0); + vtop->type.t = t; + vtop->r = REG_IRET; + return; + } + else { + int d, n = fltr(gv(RC_FLOAT)); + uint32_t l = ((vtop->type.t & VT_BTYPE) != VT_FLOAT); + --vtop; + d = get_reg(RC_INT); + ++vtop; + vtop[0].r = d; + o(0x1e380000 | + (uint32_t)!!(t & VT_UNSIGNED) << 16 | + (uint32_t)((t & VT_BTYPE) == VT_LLONG) << 31 | intr(d) | + l << 22 | n << 5); // fcvtz[su] [wx](d),[sd](n) + } +} + +ST_FUNC void gen_cvt_ftof(int t) +{ + int f = vtop[0].type.t; + assert(t == VT_FLOAT || t == VT_DOUBLE || t == VT_LDOUBLE); + assert(f == VT_FLOAT || f == VT_DOUBLE || f == VT_LDOUBLE); + if (t == f) + return; + + if (t == VT_LDOUBLE || f == VT_LDOUBLE) { + int func = (t == VT_LDOUBLE) ? + (f == VT_FLOAT ? TOK___extendsftf2 : TOK___extenddftf2) : + (t == VT_FLOAT ? TOK___trunctfsf2 : TOK___trunctfdf2); + vpush_global_sym(&func_old_type, func); + vrott(2); + gfunc_call(1); + vpushi(0); + vtop->type.t = t; + vtop->r = REG_FRET; + } + else { + int x, a; + gv(RC_FLOAT); + assert(vtop[0].r < VT_CONST); + a = fltr(vtop[0].r); + --vtop; + x = get_reg(RC_FLOAT); + ++vtop; + vtop[0].r = x; + x = fltr(x); + + if (f == VT_FLOAT) + o(0x1e22c000 | x | a << 5); // fcvt d(x),s(a) + else + o(0x1e624000 | x | a << 5); // fcvt s(x),d(a) + } +} + +ST_FUNC void ggoto(void) +{ + arm64_gen_bl_or_b(1); + --vtop; +} + +ST_FUNC void gen_clear_cache(void) +{ + uint32_t beg, end, dsz, isz, p, lab1, b1; + gv2(RC_INT, RC_INT); + vpushi(0); + vtop->r = get_reg(RC_INT); + vpushi(0); + vtop->r = get_reg(RC_INT); + vpushi(0); + vtop->r = get_reg(RC_INT); + beg = intr(vtop[-4].r); // x0 + end = intr(vtop[-3].r); // x1 + dsz = intr(vtop[-2].r); // x2 + isz = intr(vtop[-1].r); // x3 + p = intr(vtop[0].r); // x4 + vtop -= 5; + + o(0xd53b0020 | isz); // mrs x(isz),ctr_el0 + o(0x52800080 | p); // mov w(p),#4 + o(0x53104c00 | dsz | isz << 5); // ubfx w(dsz),w(isz),#16,#4 + o(0x1ac02000 | dsz | p << 5 | dsz << 16); // lsl w(dsz),w(p),w(dsz) + o(0x12000c00 | isz | isz << 5); // and w(isz),w(isz),#15 + o(0x1ac02000 | isz | p << 5 | isz << 16); // lsl w(isz),w(p),w(isz) + o(0x51000400 | p | dsz << 5); // sub w(p),w(dsz),#1 + o(0x8a240004 | p | beg << 5 | p << 16); // bic x(p),x(beg),x(p) + b1 = ind; o(0x14000000); // b + lab1 = ind; + o(0xd50b7b20 | p); // dc cvau,x(p) + o(0x8b000000 | p | p << 5 | dsz << 16); // add x(p),x(p),x(dsz) + write32le(cur_text_section->data + b1, 0x14000000 | (ind - b1) >> 2); + o(0xeb00001f | p << 5 | end << 16); // cmp x(p),x(end) + o(0x54ffffa3 | ((lab1 - ind) << 3 & 0xffffe0)); // b.cc lab1 + o(0xd5033b9f); // dsb ish + o(0x51000400 | p | isz << 5); // sub w(p),w(isz),#1 + o(0x8a240004 | p | beg << 5 | p << 16); // bic x(p),x(beg),x(p) + b1 = ind; o(0x14000000); // b + lab1 = ind; + o(0xd50b7520 | p); // ic ivau,x(p) + o(0x8b000000 | p | p << 5 | isz << 16); // add x(p),x(p),x(isz) + write32le(cur_text_section->data + b1, 0x14000000 | (ind - b1) >> 2); + o(0xeb00001f | p << 5 | end << 16); // cmp x(p),x(end) + o(0x54ffffa3 | ((lab1 - ind) << 3 & 0xffffe0)); // b.cc lab1 + o(0xd5033b9f); // dsb ish + o(0xd5033fdf); // isb +} + +ST_FUNC void gen_vla_sp_save(int addr) { + uint32_t r = intr(get_reg(RC_INT)); + o(0x910003e0 | r); // mov x(r),sp + arm64_strx(3, r, 29, addr); +} + +ST_FUNC void gen_vla_sp_restore(int addr) { + // Use x30 because this function can be called when there + // is a live return value in x0 but there is nothing on + // the value stack to prevent get_reg from returning x0. + uint32_t r = 30; + arm64_ldrx(0, 3, r, 29, addr); + o(0x9100001f | r << 5); // mov sp,x(r) +} + +ST_FUNC void gen_vla_alloc(CType *type, int align) { + uint32_t r = intr(gv(RC_INT)); + o(0x91003c00 | r | r << 5); // add x(r),x(r),#15 + o(0x927cec00 | r | r << 5); // bic x(r),x(r),#15 + o(0xcb2063ff | r << 16); // sub sp,sp,x(r) + vpop(); +} + +/* end of A64 code generator */ +/*************************************************************/ +#endif +/*************************************************************/ diff --git a/tinyc/arm64-link.c b/tinyc/arm64-link.c new file mode 100644 index 000000000..73e503e6b --- /dev/null +++ b/tinyc/arm64-link.c @@ -0,0 +1,250 @@ +#ifdef TARGET_DEFS_ONLY + +#define EM_TCC_TARGET EM_AARCH64 + +#define R_DATA_32 R_AARCH64_ABS32 +#define R_DATA_PTR R_AARCH64_ABS64 +#define R_JMP_SLOT R_AARCH64_JUMP_SLOT +#define R_GLOB_DAT R_AARCH64_GLOB_DAT +#define R_COPY R_AARCH64_COPY +#define R_RELATIVE R_AARCH64_RELATIVE + +#define R_NUM R_AARCH64_NUM + +#define ELF_START_ADDR 0x00400000 +#define ELF_PAGE_SIZE 0x1000 + +#define PCRELATIVE_DLLPLT 1 +#define RELOCATE_DLLPLT 1 + +#else /* !TARGET_DEFS_ONLY */ + +#include "tcc.h" + +/* Returns 1 for a code relocation, 0 for a data relocation. For unknown + relocations, returns -1. */ +int code_reloc (int reloc_type) +{ + switch (reloc_type) { + case R_AARCH64_ABS32: + case R_AARCH64_ABS64: + case R_AARCH64_PREL32: + case R_AARCH64_MOVW_UABS_G0_NC: + case R_AARCH64_MOVW_UABS_G1_NC: + case R_AARCH64_MOVW_UABS_G2_NC: + case R_AARCH64_MOVW_UABS_G3: + case R_AARCH64_ADR_PREL_PG_HI21: + case R_AARCH64_ADD_ABS_LO12_NC: + case R_AARCH64_ADR_GOT_PAGE: + case R_AARCH64_LD64_GOT_LO12_NC: + case R_AARCH64_GLOB_DAT: + case R_AARCH64_COPY: + return 0; + + case R_AARCH64_JUMP26: + case R_AARCH64_CALL26: + case R_AARCH64_JUMP_SLOT: + return 1; + } + + tcc_error ("Unknown relocation type: %d", reloc_type); + return -1; +} + +/* Returns an enumerator to describe whether and when the relocation needs a + GOT and/or PLT entry to be created. See tcc.h for a description of the + different values. */ +int gotplt_entry_type (int reloc_type) +{ + switch (reloc_type) { + case R_AARCH64_PREL32: + case R_AARCH64_MOVW_UABS_G0_NC: + case R_AARCH64_MOVW_UABS_G1_NC: + case R_AARCH64_MOVW_UABS_G2_NC: + case R_AARCH64_MOVW_UABS_G3: + case R_AARCH64_ADR_PREL_PG_HI21: + case R_AARCH64_ADD_ABS_LO12_NC: + case R_AARCH64_GLOB_DAT: + case R_AARCH64_JUMP_SLOT: + case R_AARCH64_COPY: + return NO_GOTPLT_ENTRY; + + case R_AARCH64_ABS32: + case R_AARCH64_ABS64: + case R_AARCH64_JUMP26: + case R_AARCH64_CALL26: + return AUTO_GOTPLT_ENTRY; + + case R_AARCH64_ADR_GOT_PAGE: + case R_AARCH64_LD64_GOT_LO12_NC: + return ALWAYS_GOTPLT_ENTRY; + } + + tcc_error ("Unknown relocation type: %d", reloc_type); + return -1; +} + +ST_FUNC unsigned create_plt_entry(TCCState *s1, unsigned got_offset, struct sym_attr *attr) +{ + Section *plt = s1->plt; + uint8_t *p; + unsigned plt_offset; + + if (s1->output_type == TCC_OUTPUT_DLL) + tcc_error("DLLs unimplemented!"); + + if (plt->data_offset == 0) { + section_ptr_add(plt, 32); + } + plt_offset = plt->data_offset; + + p = section_ptr_add(plt, 16); + write32le(p, got_offset); + write32le(p + 4, (uint64_t) got_offset >> 32); + return plt_offset; +} + +/* relocate the PLT: compute addresses and offsets in the PLT now that final + address for PLT and GOT are known (see fill_program_header) */ +ST_FUNC void relocate_plt(TCCState *s1) +{ + uint8_t *p, *p_end; + + if (!s1->plt) + return; + + p = s1->plt->data; + p_end = p + s1->plt->data_offset; + + if (p < p_end) { + uint64_t plt = s1->plt->sh_addr; + uint64_t got = s1->got->sh_addr; + uint64_t off = (got >> 12) - (plt >> 12); + if ((off + ((uint32_t)1 << 20)) >> 21) + tcc_error("Failed relocating PLT (off=0x%lx, got=0x%lx, plt=0x%lx)", off, got, plt); + write32le(p, 0xa9bf7bf0); // stp x16,x30,[sp,#-16]! + write32le(p + 4, (0x90000010 | // adrp x16,... + (off & 0x1ffffc) << 3 | (off & 3) << 29)); + write32le(p + 8, (0xf9400211 | // ldr x17,[x16,#...] + (got & 0xff8) << 7)); + write32le(p + 12, (0x91000210 | // add x16,x16,#... + (got & 0xfff) << 10)); + write32le(p + 16, 0xd61f0220); // br x17 + write32le(p + 20, 0xd503201f); // nop + write32le(p + 24, 0xd503201f); // nop + write32le(p + 28, 0xd503201f); // nop + p += 32; + while (p < p_end) { + uint64_t pc = plt + (p - s1->plt->data); + uint64_t addr = got + read64le(p); + uint64_t off = (addr >> 12) - (pc >> 12); + if ((off + ((uint32_t)1 << 20)) >> 21) + tcc_error("Failed relocating PLT (off=0x%lx, addr=0x%lx, pc=0x%lx)", off, addr, pc); + write32le(p, (0x90000010 | // adrp x16,... + (off & 0x1ffffc) << 3 | (off & 3) << 29)); + write32le(p + 4, (0xf9400211 | // ldr x17,[x16,#...] + (addr & 0xff8) << 7)); + write32le(p + 8, (0x91000210 | // add x16,x16,#... + (addr & 0xfff) << 10)); + write32le(p + 12, 0xd61f0220); // br x17 + p += 16; + } + } +} + +void relocate_init(Section *sr) {} + +void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t addr, addr_t val) +{ + int sym_index = ELFW(R_SYM)(rel->r_info); +#ifdef DEBUG_RELOC + ElfW(Sym) *sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; +#endif + + switch(type) { + case R_AARCH64_ABS64: + write64le(ptr, val); + return; + case R_AARCH64_ABS32: + write32le(ptr, val); + return; + case R_AARCH64_PREL32: + write32le(ptr, val - addr); + return; + case R_AARCH64_MOVW_UABS_G0_NC: + write32le(ptr, ((read32le(ptr) & 0xffe0001f) | + (val & 0xffff) << 5)); + return; + case R_AARCH64_MOVW_UABS_G1_NC: + write32le(ptr, ((read32le(ptr) & 0xffe0001f) | + (val >> 16 & 0xffff) << 5)); + return; + case R_AARCH64_MOVW_UABS_G2_NC: + write32le(ptr, ((read32le(ptr) & 0xffe0001f) | + (val >> 32 & 0xffff) << 5)); + return; + case R_AARCH64_MOVW_UABS_G3: + write32le(ptr, ((read32le(ptr) & 0xffe0001f) | + (val >> 48 & 0xffff) << 5)); + return; + case R_AARCH64_ADR_PREL_PG_HI21: { + uint64_t off = (val >> 12) - (addr >> 12); + if ((off + ((uint64_t)1 << 20)) >> 21) + tcc_error("R_AARCH64_ADR_PREL_PG_HI21 relocation failed"); + write32le(ptr, ((read32le(ptr) & 0x9f00001f) | + (off & 0x1ffffc) << 3 | (off & 3) << 29)); + return; + } + case R_AARCH64_ADD_ABS_LO12_NC: + write32le(ptr, ((read32le(ptr) & 0xffc003ff) | + (val & 0xfff) << 10)); + return; + case R_AARCH64_JUMP26: + case R_AARCH64_CALL26: +#ifdef DEBUG_RELOC + printf ("reloc %d @ 0x%lx: val=0x%lx name=%s\n", type, addr, val, + (char *) symtab_section->link->data + sym->st_name); +#endif + if (((val - addr) + ((uint64_t)1 << 27)) & ~(uint64_t)0xffffffc) + tcc_error("R_AARCH64_(JUMP|CALL)26 relocation failed" + " (val=%lx, addr=%lx)", val, addr); + write32le(ptr, (0x14000000 | + (uint32_t)(type == R_AARCH64_CALL26) << 31 | + ((val - addr) >> 2 & 0x3ffffff))); + return; + case R_AARCH64_ADR_GOT_PAGE: { + uint64_t off = + (((s1->got->sh_addr + + s1->sym_attrs[sym_index].got_offset) >> 12) - (addr >> 12)); + if ((off + ((uint64_t)1 << 20)) >> 21) + tcc_error("R_AARCH64_ADR_GOT_PAGE relocation failed"); + write32le(ptr, ((read32le(ptr) & 0x9f00001f) | + (off & 0x1ffffc) << 3 | (off & 3) << 29)); + return; + } + case R_AARCH64_LD64_GOT_LO12_NC: + write32le(ptr, + ((read32le(ptr) & 0xfff803ff) | + ((s1->got->sh_addr + + s1->sym_attrs[sym_index].got_offset) & 0xff8) << 7)); + return; + case R_AARCH64_COPY: + return; + case R_AARCH64_GLOB_DAT: + case R_AARCH64_JUMP_SLOT: + /* They don't need addend */ +#ifdef DEBUG_RELOC + printf ("reloc %d @ 0x%lx: val=0x%lx name=%s\n", type, addr, + val - rel->r_addend, + (char *) symtab_section->link->data + sym->st_name); +#endif + write64le(ptr, val - rel->r_addend); + return; + default: + fprintf(stderr, "FIXME: handle reloc type %x at %x [%p] to %x\n", + type, (unsigned)addr, ptr, (unsigned)val); + return; + } +} + +#endif /* !TARGET_DEFS_ONLY */ diff --git a/tinyc/c67-gen.c b/tinyc/c67-gen.c new file mode 100644 index 000000000..bcb4b0e3e --- /dev/null +++ b/tinyc/c67-gen.c @@ -0,0 +1,2540 @@ +/* + * TMS320C67xx code generator for TCC + * + * Copyright (c) 2001, 2002 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifdef TARGET_DEFS_ONLY + +/* #define ASSEMBLY_LISTING_C67 */ + +/* number of available registers */ +#define NB_REGS 24 + +/* a register can belong to several classes. The classes must be + sorted from more general to more precise (see gv2() code which does + assumptions on it). */ +#define RC_INT 0x0001 /* generic integer register */ +#define RC_FLOAT 0x0002 /* generic float register */ +#define RC_EAX 0x0004 +#define RC_ST0 0x0008 +#define RC_ECX 0x0010 +#define RC_EDX 0x0020 +#define RC_INT_BSIDE 0x00000040 /* generic integer register on b side */ +#define RC_C67_A4 0x00000100 +#define RC_C67_A5 0x00000200 +#define RC_C67_B4 0x00000400 +#define RC_C67_B5 0x00000800 +#define RC_C67_A6 0x00001000 +#define RC_C67_A7 0x00002000 +#define RC_C67_B6 0x00004000 +#define RC_C67_B7 0x00008000 +#define RC_C67_A8 0x00010000 +#define RC_C67_A9 0x00020000 +#define RC_C67_B8 0x00040000 +#define RC_C67_B9 0x00080000 +#define RC_C67_A10 0x00100000 +#define RC_C67_A11 0x00200000 +#define RC_C67_B10 0x00400000 +#define RC_C67_B11 0x00800000 +#define RC_C67_A12 0x01000000 +#define RC_C67_A13 0x02000000 +#define RC_C67_B12 0x04000000 +#define RC_C67_B13 0x08000000 +#define RC_IRET RC_C67_A4 /* function return: integer register */ +#define RC_LRET RC_C67_A5 /* function return: second integer register */ +#define RC_FRET RC_C67_A4 /* function return: float register */ + +/* pretty names for the registers */ +enum { + TREG_EAX = 0, // really A2 + TREG_ECX, // really A3 + TREG_EDX, // really B0 + TREG_ST0, // really B1 + TREG_C67_A4, + TREG_C67_A5, + TREG_C67_B4, + TREG_C67_B5, + TREG_C67_A6, + TREG_C67_A7, + TREG_C67_B6, + TREG_C67_B7, + TREG_C67_A8, + TREG_C67_A9, + TREG_C67_B8, + TREG_C67_B9, + TREG_C67_A10, + TREG_C67_A11, + TREG_C67_B10, + TREG_C67_B11, + TREG_C67_A12, + TREG_C67_A13, + TREG_C67_B12, + TREG_C67_B13, +}; + +/* return registers for function */ +#define REG_IRET TREG_C67_A4 /* single word int return register */ +#define REG_LRET TREG_C67_A5 /* second word return register (for long long) */ +#define REG_FRET TREG_C67_A4 /* float return register */ + +/* defined if function parameters must be evaluated in reverse order */ +/* #define INVERT_FUNC_PARAMS */ + +/* defined if structures are passed as pointers. Otherwise structures + are directly pushed on stack. */ +/* #define FUNC_STRUCT_PARAM_AS_PTR */ + +/* pointer size, in bytes */ +#define PTR_SIZE 4 + +/* long double size and alignment, in bytes */ +#define LDOUBLE_SIZE 12 +#define LDOUBLE_ALIGN 4 +/* maximum alignment (for aligned attribute support) */ +#define MAX_ALIGN 8 + +/******************************************************/ +#else /* ! TARGET_DEFS_ONLY */ +/******************************************************/ +#include "tcc.h" + +ST_DATA const int reg_classes[NB_REGS] = { + /* eax */ RC_INT | RC_FLOAT | RC_EAX, + // only allow even regs for floats (allow for doubles) + /* ecx */ RC_INT | RC_ECX, + /* edx */ RC_INT | RC_INT_BSIDE | RC_FLOAT | RC_EDX, + // only allow even regs for floats (allow for doubles) + /* st0 */ RC_INT | RC_INT_BSIDE | RC_ST0, + /* A4 */ RC_C67_A4, + /* A5 */ RC_C67_A5, + /* B4 */ RC_C67_B4, + /* B5 */ RC_C67_B5, + /* A6 */ RC_C67_A6, + /* A7 */ RC_C67_A7, + /* B6 */ RC_C67_B6, + /* B7 */ RC_C67_B7, + /* A8 */ RC_C67_A8, + /* A9 */ RC_C67_A9, + /* B8 */ RC_C67_B8, + /* B9 */ RC_C67_B9, + /* A10 */ RC_C67_A10, + /* A11 */ RC_C67_A11, + /* B10 */ RC_C67_B10, + /* B11 */ RC_C67_B11, + /* A12 */ RC_C67_A10, + /* A13 */ RC_C67_A11, + /* B12 */ RC_C67_B10, + /* B13 */ RC_C67_B11 +}; + +// although tcc thinks it is passing parameters on the stack, +// the C67 really passes up to the first 10 params in special +// regs or regs pairs (for 64 bit params). So keep track of +// the stack offsets so we can translate to the appropriate +// reg (pair) + +#define NoCallArgsPassedOnStack 10 +int NoOfCurFuncArgs; +int TranslateStackToReg[NoCallArgsPassedOnStack]; +int ParamLocOnStack[NoCallArgsPassedOnStack]; +int TotalBytesPushedOnStack; + +#ifndef FALSE +# define FALSE 0 +# define TRUE 1 +#endif + +#undef BOOL +#define BOOL int + +#define ALWAYS_ASSERT(x) \ +do {\ + if (!(x))\ + tcc_error("internal compiler error file at %s:%d", __FILE__, __LINE__);\ +} while (0) + +/******************************************************/ +static unsigned long func_sub_sp_offset; +static int func_ret_sub; + +static BOOL C67_invert_test; +static int C67_compare_reg; + +#ifdef ASSEMBLY_LISTING_C67 +FILE *f = NULL; +#endif + +void C67_g(int c) +{ + int ind1; + if (nocode_wanted) + return; +#ifdef ASSEMBLY_LISTING_C67 + fprintf(f, " %08X", c); +#endif + ind1 = ind + 4; + if (ind1 > (int) cur_text_section->data_allocated) + section_realloc(cur_text_section, ind1); + cur_text_section->data[ind] = c & 0xff; + cur_text_section->data[ind + 1] = (c >> 8) & 0xff; + cur_text_section->data[ind + 2] = (c >> 16) & 0xff; + cur_text_section->data[ind + 3] = (c >> 24) & 0xff; + ind = ind1; +} + + +/* output a symbol and patch all calls to it */ +void gsym_addr(int t, int a) +{ + int n, *ptr; + while (t) { + ptr = (int *) (cur_text_section->data + t); + { + Sym *sym; + + // extract 32 bit address from MVKH/MVKL + n = ((*ptr >> 7) & 0xffff); + n |= ((*(ptr + 1) >> 7) & 0xffff) << 16; + + // define a label that will be relocated + + sym = get_sym_ref(&char_pointer_type, cur_text_section, a, 0); + greloc(cur_text_section, sym, t, R_C60LO16); + greloc(cur_text_section, sym, t + 4, R_C60HI16); + + // clear out where the pointer was + + *ptr &= ~(0xffff << 7); + *(ptr + 1) &= ~(0xffff << 7); + } + t = n; + } +} + +void gsym(int t) +{ + gsym_addr(t, ind); +} + +// these are regs that tcc doesn't really know about, +// but assign them unique values so the mapping routines +// can distinguish them + +#define C67_A0 105 +#define C67_SP 106 +#define C67_B3 107 +#define C67_FP 108 +#define C67_B2 109 +#define C67_CREG_ZERO -1 /* Special code for no condition reg test */ + + +int ConvertRegToRegClass(int r) +{ + // only works for A4-B13 + + return RC_C67_A4 << (r - TREG_C67_A4); +} + + +// map TCC reg to C67 reg number + +int C67_map_regn(int r) +{ + if (r == 0) // normal tcc regs + return 0x2; // A2 + else if (r == 1) // normal tcc regs + return 3; // A3 + else if (r == 2) // normal tcc regs + return 0; // B0 + else if (r == 3) // normal tcc regs + return 1; // B1 + else if (r >= TREG_C67_A4 && r <= TREG_C67_B13) // these form a pattern of alt pairs + return (((r & 0xfffffffc) >> 1) | (r & 1)) + 2; + else if (r == C67_A0) + return 0; // set to A0 (offset reg) + else if (r == C67_B2) + return 2; // set to B2 (offset reg) + else if (r == C67_B3) + return 3; // set to B3 (return address reg) + else if (r == C67_SP) + return 15; // set to SP (B15) (offset reg) + else if (r == C67_FP) + return 15; // set to FP (A15) (offset reg) + else if (r == C67_CREG_ZERO) + return 0; // Special code for no condition reg test + else + ALWAYS_ASSERT(FALSE); + + return 0; +} + +// mapping from tcc reg number to +// C67 register to condition code field +// +// valid condition code regs are: +// +// tcc reg 2 ->B0 -> 1 +// tcc reg 3 ->B1 -> 2 +// tcc reg 0 -> A2 -> 5 +// tcc reg 1 -> A3 -> X +// tcc reg B2 -> 3 + +int C67_map_regc(int r) +{ + if (r == 0) // normal tcc regs + return 0x5; + else if (r == 2) // normal tcc regs + return 0x1; + else if (r == 3) // normal tcc regs + return 0x2; + else if (r == C67_B2) // normal tcc regs + return 0x3; + else if (r == C67_CREG_ZERO) + return 0; // Special code for no condition reg test + else + ALWAYS_ASSERT(FALSE); + + return 0; +} + + +// map TCC reg to C67 reg side A or B + +int C67_map_regs(int r) +{ + if (r == 0) // normal tcc regs + return 0x0; + else if (r == 1) // normal tcc regs + return 0x0; + else if (r == 2) // normal tcc regs + return 0x1; + else if (r == 3) // normal tcc regs + return 0x1; + else if (r >= TREG_C67_A4 && r <= TREG_C67_B13) // these form a pattern of alt pairs + return (r & 2) >> 1; + else if (r == C67_A0) + return 0; // set to A side + else if (r == C67_B2) + return 1; // set to B side + else if (r == C67_B3) + return 1; // set to B side + else if (r == C67_SP) + return 0x1; // set to SP (B15) B side + else if (r == C67_FP) + return 0x0; // set to FP (A15) A side + else + ALWAYS_ASSERT(FALSE); + + return 0; +} + +int C67_map_S12(char *s) +{ + if (strstr(s, ".S1") != NULL) + return 0; + else if (strcmp(s, ".S2")) + return 1; + else + ALWAYS_ASSERT(FALSE); + + return 0; +} + +int C67_map_D12(char *s) +{ + if (strstr(s, ".D1") != NULL) + return 0; + else if (strcmp(s, ".D2")) + return 1; + else + ALWAYS_ASSERT(FALSE); + + return 0; +} + + + +void C67_asm(char *s, int a, int b, int c) +{ + BOOL xpath; + +#ifdef ASSEMBLY_LISTING_C67 + if (!f) { + f = fopen("TCC67_out.txt", "wt"); + } + fprintf(f, "%04X ", ind); +#endif + + if (strstr(s, "MVKL") == s) { + C67_g((C67_map_regn(b) << 23) | + ((a & 0xffff) << 7) | (0x0a << 2) | (C67_map_regs(b) << 1)); + } else if (strstr(s, "MVKH") == s) { + C67_g((C67_map_regn(b) << 23) | + (((a >> 16) & 0xffff) << 7) | + (0x1a << 2) | (C67_map_regs(b) << 1)); + } else if (strstr(s, "STW.D SP POST DEC") == s) { + C67_g((C67_map_regn(a) << 23) | //src + (15 << 18) | //SP B15 + (2 << 13) | //ucst5 (must keep 8 byte boundary !!) + (0xa << 9) | //mode a = post dec ucst + (0 << 8) | //r (LDDW bit 0) + (1 << 7) | //y D1/D2 use B side + (7 << 4) | //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU + (1 << 2) | //opcode + (C67_map_regs(a) << 1) | //side of src + (0 << 0)); //parallel + } else if (strstr(s, "STB.D *+SP[A0]") == s) { + C67_g((C67_map_regn(a) << 23) | //src + (15 << 18) | //base reg A15 + (0 << 13) | //offset reg A0 + (5 << 9) | //mode 5 = pos offset, base reg + off reg + (0 << 8) | //r (LDDW bit 0) + (0 << 7) | //y D1/D2 A side + (3 << 4) | //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU + (1 << 2) | //opcode + (C67_map_regs(a) << 1) | //side of src + (0 << 0)); //parallel + } else if (strstr(s, "STH.D *+SP[A0]") == s) { + C67_g((C67_map_regn(a) << 23) | //src + (15 << 18) | //base reg A15 + (0 << 13) | //offset reg A0 + (5 << 9) | //mode 5 = pos offset, base reg + off reg + (0 << 8) | //r (LDDW bit 0) + (0 << 7) | //y D1/D2 A side + (5 << 4) | //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU + (1 << 2) | //opcode + (C67_map_regs(a) << 1) | //side of src + (0 << 0)); //parallel + } else if (strstr(s, "STB.D *+SP[A0]") == s) { + C67_g((C67_map_regn(a) << 23) | //src + (15 << 18) | //base reg A15 + (0 << 13) | //offset reg A0 + (5 << 9) | //mode 5 = pos offset, base reg + off reg + (0 << 8) | //r (LDDW bit 0) + (0 << 7) | //y D1/D2 A side + (3 << 4) | //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU + (1 << 2) | //opcode + (C67_map_regs(a) << 1) | //side of src + (0 << 0)); //parallel + } else if (strstr(s, "STH.D *+SP[A0]") == s) { + C67_g((C67_map_regn(a) << 23) | //src + (15 << 18) | //base reg A15 + (0 << 13) | //offset reg A0 + (5 << 9) | //mode 5 = pos offset, base reg + off reg + (0 << 8) | //r (LDDW bit 0) + (0 << 7) | //y D1/D2 A side + (5 << 4) | //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU + (1 << 2) | //opcode + (C67_map_regs(a) << 1) | //side of src + (0 << 0)); //parallel + } else if (strstr(s, "STW.D *+SP[A0]") == s) { + C67_g((C67_map_regn(a) << 23) | //src + (15 << 18) | //base reg A15 + (0 << 13) | //offset reg A0 + (5 << 9) | //mode 5 = pos offset, base reg + off reg + (0 << 8) | //r (LDDW bit 0) + (0 << 7) | //y D1/D2 A side + (7 << 4) | //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU + (1 << 2) | //opcode + (C67_map_regs(a) << 1) | //side of src + (0 << 0)); //parallel + } else if (strstr(s, "STW.D *") == s) { + C67_g((C67_map_regn(a) << 23) | //src + (C67_map_regn(b) << 18) | //base reg A0 + (0 << 13) | //cst5 + (1 << 9) | //mode 1 = pos cst offset + (0 << 8) | //r (LDDW bit 0) + (C67_map_regs(b) << 7) | //y D1/D2 base reg side + (7 << 4) | //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU + (1 << 2) | //opcode + (C67_map_regs(a) << 1) | //side of src + (0 << 0)); //parallel + } else if (strstr(s, "STH.D *") == s) { + C67_g((C67_map_regn(a) << 23) | //src + (C67_map_regn(b) << 18) | //base reg A0 + (0 << 13) | //cst5 + (1 << 9) | //mode 1 = pos cst offset + (0 << 8) | //r (LDDW bit 0) + (C67_map_regs(b) << 7) | //y D1/D2 base reg side + (5 << 4) | //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU + (1 << 2) | //opcode + (C67_map_regs(a) << 1) | //side of src + (0 << 0)); //parallel + } else if (strstr(s, "STB.D *") == s) { + C67_g((C67_map_regn(a) << 23) | //src + (C67_map_regn(b) << 18) | //base reg A0 + (0 << 13) | //cst5 + (1 << 9) | //mode 1 = pos cst offset + (0 << 8) | //r (LDDW bit 0) + (C67_map_regs(b) << 7) | //y D1/D2 base reg side + (3 << 4) | //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU + (1 << 2) | //opcode + (C67_map_regs(a) << 1) | //side of src + (0 << 0)); //parallel + } else if (strstr(s, "STW.D +*") == s) { + ALWAYS_ASSERT(c < 32); + C67_g((C67_map_regn(a) << 23) | //src + (C67_map_regn(b) << 18) | //base reg A0 + (c << 13) | //cst5 + (1 << 9) | //mode 1 = pos cst offset + (0 << 8) | //r (LDDW bit 0) + (C67_map_regs(b) << 7) | //y D1/D2 base reg side + (7 << 4) | //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU + (1 << 2) | //opcode + (C67_map_regs(a) << 1) | //side of src + (0 << 0)); //parallel + } else if (strstr(s, "LDW.D SP PRE INC") == s) { + C67_g((C67_map_regn(a) << 23) | //dst + (15 << 18) | //base reg B15 + (2 << 13) | //ucst5 (must keep 8 byte boundary) + (9 << 9) | //mode 9 = pre inc ucst5 + (0 << 8) | //r (LDDW bit 0) + (1 << 7) | //y D1/D2 B side + (6 << 4) | //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU + (1 << 2) | //opcode + (C67_map_regs(a) << 1) | //side of dst + (0 << 0)); //parallel + } else if (strstr(s, "LDDW.D SP PRE INC") == s) { + C67_g((C67_map_regn(a) << 23) | //dst + (15 << 18) | //base reg B15 + (1 << 13) | //ucst5 (must keep 8 byte boundary) + (9 << 9) | //mode 9 = pre inc ucst5 + (1 << 8) | //r (LDDW bit 1) + (1 << 7) | //y D1/D2 B side + (6 << 4) | //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU + (1 << 2) | //opcode + (C67_map_regs(a) << 1) | //side of dst + (0 << 0)); //parallel + } else if (strstr(s, "LDW.D *+SP[A0]") == s) { + C67_g((C67_map_regn(a) << 23) | //dst + (15 << 18) | //base reg A15 + (0 << 13) | //offset reg A0 + (5 << 9) | //mode 5 = pos offset, base reg + off reg + (0 << 8) | //r (LDDW bit 0) + (0 << 7) | //y D1/D2 A side + (6 << 4) | //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU + (1 << 2) | //opcode + (C67_map_regs(a) << 1) | //side of dst + (0 << 0)); //parallel + } else if (strstr(s, "LDDW.D *+SP[A0]") == s) { + C67_g((C67_map_regn(a) << 23) | //dst + (15 << 18) | //base reg A15 + (0 << 13) | //offset reg A0 + (5 << 9) | //mode 5 = pos offset, base reg + off reg + (1 << 8) | //r (LDDW bit 1) + (0 << 7) | //y D1/D2 A side + (6 << 4) | //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU + (1 << 2) | //opcode + (C67_map_regs(a) << 1) | //side of dst + (0 << 0)); //parallel + } else if (strstr(s, "LDH.D *+SP[A0]") == s) { + C67_g((C67_map_regn(a) << 23) | //dst + (15 << 18) | //base reg A15 + (0 << 13) | //offset reg A0 + (5 << 9) | //mode 5 = pos offset, base reg + off reg + (0 << 8) | //r (LDDW bit 0) + (0 << 7) | //y D1/D2 A side + (4 << 4) | //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU + (1 << 2) | //opcode + (C67_map_regs(a) << 1) | //side of dst + (0 << 0)); //parallel + } else if (strstr(s, "LDB.D *+SP[A0]") == s) { + C67_g((C67_map_regn(a) << 23) | //dst + (15 << 18) | //base reg A15 + (0 << 13) | //offset reg A0 + (5 << 9) | //mode 5 = pos offset, base reg + off reg + (0 << 8) | //r (LDDW bit 0) + (0 << 7) | //y D1/D2 A side + (2 << 4) | //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU + (1 << 2) | //opcode + (C67_map_regs(a) << 1) | //side of dst + (0 << 0)); //parallel + } else if (strstr(s, "LDHU.D *+SP[A0]") == s) { + C67_g((C67_map_regn(a) << 23) | //dst + (15 << 18) | //base reg A15 + (0 << 13) | //offset reg A0 + (5 << 9) | //mode 5 = pos offset, base reg + off reg + (0 << 8) | //r (LDDW bit 0) + (0 << 7) | //y D1/D2 A side + (0 << 4) | //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU + (1 << 2) | //opcode + (C67_map_regs(a) << 1) | //side of dst + (0 << 0)); //parallel + } else if (strstr(s, "LDBU.D *+SP[A0]") == s) { + C67_g((C67_map_regn(a) << 23) | //dst + (15 << 18) | //base reg A15 + (0 << 13) | //offset reg A0 + (5 << 9) | //mode 5 = pos offset, base reg + off reg + (0 << 8) | //r (LDDW bit 0) + (0 << 7) | //y D1/D2 A side + (1 << 4) | //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU + (1 << 2) | //opcode + (C67_map_regs(a) << 1) | //side of dst + (0 << 0)); //parallel + } else if (strstr(s, "LDW.D *") == s) { + C67_g((C67_map_regn(b) << 23) | //dst + (C67_map_regn(a) << 18) | //base reg A15 + (0 << 13) | //cst5 + (1 << 9) | //mode 1 = pos cst offset + (0 << 8) | //r (LDDW bit 0) + (C67_map_regs(a) << 7) | //y D1/D2 src side + (6 << 4) | //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU + (1 << 2) | //opcode + (C67_map_regs(b) << 1) | //side of dst + (0 << 0)); //parallel + } else if (strstr(s, "LDDW.D *") == s) { + C67_g((C67_map_regn(b) << 23) | //dst + (C67_map_regn(a) << 18) | //base reg A15 + (0 << 13) | //cst5 + (1 << 9) | //mode 1 = pos cst offset + (1 << 8) | //r (LDDW bit 1) + (C67_map_regs(a) << 7) | //y D1/D2 src side + (6 << 4) | //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU + (1 << 2) | //opcode + (C67_map_regs(b) << 1) | //side of dst + (0 << 0)); //parallel + } else if (strstr(s, "LDH.D *") == s) { + C67_g((C67_map_regn(b) << 23) | //dst + (C67_map_regn(a) << 18) | //base reg A15 + (0 << 13) | //cst5 + (1 << 9) | //mode 1 = pos cst offset + (0 << 8) | //r (LDDW bit 0) + (C67_map_regs(a) << 7) | //y D1/D2 src side + (4 << 4) | //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU + (1 << 2) | //opcode + (C67_map_regs(b) << 1) | //side of dst + (0 << 0)); //parallel + } else if (strstr(s, "LDB.D *") == s) { + C67_g((C67_map_regn(b) << 23) | //dst + (C67_map_regn(a) << 18) | //base reg A15 + (0 << 13) | //cst5 + (1 << 9) | //mode 1 = pos cst offset + (0 << 8) | //r (LDDW bit 0) + (C67_map_regs(a) << 7) | //y D1/D2 src side + (2 << 4) | //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU + (1 << 2) | //opcode + (C67_map_regs(b) << 1) | //side of dst + (0 << 0)); //parallel + } else if (strstr(s, "LDHU.D *") == s) { + C67_g((C67_map_regn(b) << 23) | //dst + (C67_map_regn(a) << 18) | //base reg A15 + (0 << 13) | //cst5 + (1 << 9) | //mode 1 = pos cst offset + (0 << 8) | //r (LDDW bit 0) + (C67_map_regs(a) << 7) | //y D1/D2 src side + (0 << 4) | //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU + (1 << 2) | //opcode + (C67_map_regs(b) << 1) | //side of dst + (0 << 0)); //parallel + } else if (strstr(s, "LDBU.D *") == s) { + C67_g((C67_map_regn(b) << 23) | //dst + (C67_map_regn(a) << 18) | //base reg A15 + (0 << 13) | //cst5 + (1 << 9) | //mode 1 = pos cst offset + (0 << 8) | //r (LDDW bit 0) + (C67_map_regs(a) << 7) | //y D1/D2 src side + (1 << 4) | //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU + (1 << 2) | //opcode + (C67_map_regs(b) << 1) | //side of dst + (0 << 0)); //parallel + } else if (strstr(s, "LDW.D +*") == s) { + C67_g((C67_map_regn(b) << 23) | //dst + (C67_map_regn(a) << 18) | //base reg A15 + (1 << 13) | //cst5 + (1 << 9) | //mode 1 = pos cst offset + (0 << 8) | //r (LDDW bit 0) + (C67_map_regs(a) << 7) | //y D1/D2 src side + (6 << 4) | //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU + (1 << 2) | //opcode + (C67_map_regs(b) << 1) | //side of dst + (0 << 0)); //parallel + } else if (strstr(s, "CMPLTSP") == s) { + xpath = C67_map_regs(a) ^ C67_map_regs(b); + ALWAYS_ASSERT(C67_map_regs(c) == C67_map_regs(a)); + + C67_g((C67_map_regn(c) << 23) | //dst + (C67_map_regn(b) << 18) | //src2 + (C67_map_regn(a) << 13) | //src1 + (xpath << 12) | //x use cross path for src2 + (0x3a << 6) | //opcode + (0x8 << 2) | //opcode fixed + (C67_map_regs(c) << 1) | //side for reg c + (0 << 0)); //parallel + } else if (strstr(s, "CMPGTSP") == s) { + xpath = C67_map_regs(a) ^ C67_map_regs(b); + ALWAYS_ASSERT(C67_map_regs(c) == C67_map_regs(a)); + + C67_g((C67_map_regn(c) << 23) | //dst + (C67_map_regn(b) << 18) | //src2 + (C67_map_regn(a) << 13) | //src1 + (xpath << 12) | //x use cross path for src2 + (0x39 << 6) | //opcode + (0x8 << 2) | //opcode fixed + (C67_map_regs(c) << 1) | //side for reg c + (0 << 0)); //parallel + } else if (strstr(s, "CMPEQSP") == s) { + xpath = C67_map_regs(a) ^ C67_map_regs(b); + ALWAYS_ASSERT(C67_map_regs(c) == C67_map_regs(a)); + + C67_g((C67_map_regn(c) << 23) | //dst + (C67_map_regn(b) << 18) | //src2 + (C67_map_regn(a) << 13) | //src1 + (xpath << 12) | //x use cross path for src2 + (0x38 << 6) | //opcode + (0x8 << 2) | //opcode fixed + (C67_map_regs(c) << 1) | //side for reg c + (0 << 0)); //parallel + } + + else if (strstr(s, "CMPLTDP") == s) { + xpath = C67_map_regs(a) ^ C67_map_regs(b); + ALWAYS_ASSERT(C67_map_regs(c) == C67_map_regs(a)); + + C67_g((C67_map_regn(c) << 23) | //dst + (C67_map_regn(b) << 18) | //src2 + (C67_map_regn(a) << 13) | //src1 + (xpath << 12) | //x use cross path for src2 + (0x2a << 6) | //opcode + (0x8 << 2) | //opcode fixed + (C67_map_regs(c) << 1) | //side for reg c + (0 << 0)); //parallel + } else if (strstr(s, "CMPGTDP") == s) { + xpath = C67_map_regs(a) ^ C67_map_regs(b); + ALWAYS_ASSERT(C67_map_regs(c) == C67_map_regs(a)); + + C67_g((C67_map_regn(c) << 23) | //dst + (C67_map_regn(b) << 18) | //src2 + (C67_map_regn(a) << 13) | //src1 + (xpath << 12) | //x use cross path for src2 + (0x29 << 6) | //opcode + (0x8 << 2) | //opcode fixed + (C67_map_regs(c) << 1) | //side for reg c + (0 << 0)); //parallel + } else if (strstr(s, "CMPEQDP") == s) { + xpath = C67_map_regs(a) ^ C67_map_regs(b); + ALWAYS_ASSERT(C67_map_regs(c) == C67_map_regs(a)); + + C67_g((C67_map_regn(c) << 23) | //dst + (C67_map_regn(b) << 18) | //src2 + (C67_map_regn(a) << 13) | //src1 + (xpath << 12) | //x use cross path for src2 + (0x28 << 6) | //opcode + (0x8 << 2) | //opcode fixed + (C67_map_regs(c) << 1) | //side for reg c + (0 << 0)); //parallel + } else if (strstr(s, "CMPLT") == s) { + xpath = C67_map_regs(a) ^ C67_map_regs(b); + ALWAYS_ASSERT(C67_map_regs(c) == C67_map_regs(a)); + + C67_g((C67_map_regn(c) << 23) | //dst + (C67_map_regn(b) << 18) | //src2 + (C67_map_regn(a) << 13) | //src1 + (xpath << 12) | //x use cross path for src2 + (0x57 << 5) | //opcode + (0x6 << 2) | //opcode fixed + (C67_map_regs(c) << 1) | //side for reg c + (0 << 0)); //parallel + } else if (strstr(s, "CMPGT") == s) { + xpath = C67_map_regs(a) ^ C67_map_regs(b); + ALWAYS_ASSERT(C67_map_regs(c) == C67_map_regs(a)); + + C67_g((C67_map_regn(c) << 23) | //dst + (C67_map_regn(b) << 18) | //src2 + (C67_map_regn(a) << 13) | //src1 + (xpath << 12) | //x use cross path for src2 + (0x47 << 5) | //opcode + (0x6 << 2) | //opcode fixed + (C67_map_regs(c) << 1) | //side for reg c + (0 << 0)); //parallel + } else if (strstr(s, "CMPEQ") == s) { + xpath = C67_map_regs(a) ^ C67_map_regs(b); + ALWAYS_ASSERT(C67_map_regs(c) == C67_map_regs(a)); + + C67_g((C67_map_regn(c) << 23) | //dst + (C67_map_regn(b) << 18) | //src2 + (C67_map_regn(a) << 13) | //src1 + (xpath << 12) | //x use cross path for src2 + (0x53 << 5) | //opcode + (0x6 << 2) | //opcode fixed + (C67_map_regs(c) << 1) | //side for reg c + (0 << 0)); //parallel + } else if (strstr(s, "CMPLTU") == s) { + xpath = C67_map_regs(a) ^ C67_map_regs(b); + ALWAYS_ASSERT(C67_map_regs(c) == C67_map_regs(a)); + + C67_g((C67_map_regn(c) << 23) | //dst + (C67_map_regn(b) << 18) | //src2 + (C67_map_regn(a) << 13) | //src1 + (xpath << 12) | //x use cross path for src2 + (0x5f << 5) | //opcode + (0x6 << 2) | //opcode fixed + (C67_map_regs(c) << 1) | //side for reg c + (0 << 0)); //parallel + } else if (strstr(s, "CMPGTU") == s) { + xpath = C67_map_regs(a) ^ C67_map_regs(b); + ALWAYS_ASSERT(C67_map_regs(c) == C67_map_regs(a)); + + C67_g((C67_map_regn(c) << 23) | //dst + (C67_map_regn(b) << 18) | //src2 + (C67_map_regn(a) << 13) | //src1 + (xpath << 12) | //x use cross path for src2 + (0x4f << 5) | //opcode + (0x6 << 2) | //opcode fixed + (C67_map_regs(c) << 1) | //side for reg c + (0 << 0)); //parallel + } else if (strstr(s, "B DISP") == s) { + C67_g((0 << 29) | //creg + (0 << 28) | //z + (a << 7) | //cnst + (0x4 << 2) | //opcode fixed + (0 << 1) | //S0/S1 + (0 << 0)); //parallel + } else if (strstr(s, "B.") == s) { + xpath = C67_map_regs(c) ^ 1; + + C67_g((C67_map_regc(b) << 29) | //creg + (a << 28) | //inv + (0 << 23) | //dst + (C67_map_regn(c) << 18) | //src2 + (0 << 13) | // + (xpath << 12) | //x cross path if !B side + (0xd << 6) | //opcode + (0x8 << 2) | //opcode fixed + (1 << 1) | //must be S2 + (0 << 0)); //parallel + } else if (strstr(s, "MV.L") == s) { + xpath = C67_map_regs(b) ^ C67_map_regs(c); + + C67_g((0 << 29) | //creg + (0 << 28) | //inv + (C67_map_regn(c) << 23) | //dst + (C67_map_regn(b) << 18) | //src2 + (0 << 13) | //src1 (cst5) + (xpath << 12) | //x cross path if opposite sides + (0x2 << 5) | //opcode + (0x6 << 2) | //opcode fixed + (C67_map_regs(c) << 1) | //side of dest + (0 << 0)); //parallel + } else if (strstr(s, "SPTRUNC.L") == s) { + xpath = C67_map_regs(b) ^ C67_map_regs(c); + + C67_g((0 << 29) | //creg + (0 << 28) | //inv + (C67_map_regn(c) << 23) | //dst + (C67_map_regn(b) << 18) | //src2 + (0 << 13) | //src1 NA + (xpath << 12) | //x cross path if opposite sides + (0xb << 5) | //opcode + (0x6 << 2) | //opcode fixed + (C67_map_regs(c) << 1) | //side of dest + (0 << 0)); //parallel + } else if (strstr(s, "DPTRUNC.L") == s) { + xpath = C67_map_regs(b) ^ C67_map_regs(c); + + C67_g((0 << 29) | //creg + (0 << 28) | //inv + (C67_map_regn(c) << 23) | //dst + ((C67_map_regn(b) + 1) << 18) | //src2 WEIRD CPU must specify odd reg for some reason + (0 << 13) | //src1 NA + (xpath << 12) | //x cross path if opposite sides + (0x1 << 5) | //opcode + (0x6 << 2) | //opcode fixed + (C67_map_regs(c) << 1) | //side of dest + (0 << 0)); //parallel + } else if (strstr(s, "INTSP.L") == s) { + xpath = C67_map_regs(b) ^ C67_map_regs(c); + + C67_g((0 << 29) | //creg + (0 << 28) | //inv + (C67_map_regn(c) << 23) | //dst + (C67_map_regn(b) << 18) | //src2 + (0 << 13) | //src1 NA + (xpath << 12) | //x cross path if opposite sides + (0x4a << 5) | //opcode + (0x6 << 2) | //opcode fixed + (C67_map_regs(c) << 1) | //side of dest + (0 << 0)); //parallel + } else if (strstr(s, "INTSPU.L") == s) { + xpath = C67_map_regs(b) ^ C67_map_regs(c); + + C67_g((0 << 29) | //creg + (0 << 28) | //inv + (C67_map_regn(c) << 23) | //dst + (C67_map_regn(b) << 18) | //src2 + (0 << 13) | //src1 NA + (xpath << 12) | //x cross path if opposite sides + (0x49 << 5) | //opcode + (0x6 << 2) | //opcode fixed + (C67_map_regs(c) << 1) | //side of dest + (0 << 0)); //parallel + } else if (strstr(s, "INTDP.L") == s) { + xpath = C67_map_regs(b) ^ C67_map_regs(c); + + C67_g((0 << 29) | //creg + (0 << 28) | //inv + (C67_map_regn(c) << 23) | //dst + (C67_map_regn(b) << 18) | //src2 + (0 << 13) | //src1 NA + (xpath << 12) | //x cross path if opposite sides + (0x39 << 5) | //opcode + (0x6 << 2) | //opcode fixed + (C67_map_regs(c) << 1) | //side of dest + (0 << 0)); //parallel + } else if (strstr(s, "INTDPU.L") == s) { + xpath = C67_map_regs(b) ^ C67_map_regs(c); + + C67_g((0 << 29) | //creg + (0 << 28) | //inv + (C67_map_regn(c) << 23) | //dst + ((C67_map_regn(b) + 1) << 18) | //src2 WEIRD CPU must specify odd reg for some reason + (0 << 13) | //src1 NA + (xpath << 12) | //x cross path if opposite sides + (0x3b << 5) | //opcode + (0x6 << 2) | //opcode fixed + (C67_map_regs(c) << 1) | //side of dest + (0 << 0)); //parallel + } else if (strstr(s, "SPDP.L") == s) { + xpath = C67_map_regs(b) ^ C67_map_regs(c); + + C67_g((0 << 29) | //creg + (0 << 28) | //inv + (C67_map_regn(c) << 23) | //dst + (C67_map_regn(b) << 18) | //src2 + (0 << 13) | //src1 NA + (xpath << 12) | //x cross path if opposite sides + (0x2 << 6) | //opcode + (0x8 << 2) | //opcode fixed + (C67_map_regs(c) << 1) | //side of dest + (0 << 0)); //parallel + } else if (strstr(s, "DPSP.L") == s) { + ALWAYS_ASSERT(C67_map_regs(b) == C67_map_regs(c)); + + C67_g((0 << 29) | //creg + (0 << 28) | //inv + (C67_map_regn(c) << 23) | //dst + ((C67_map_regn(b) + 1) << 18) | //src2 WEIRD CPU must specify odd reg for some reason + (0 << 13) | //src1 NA + (0 << 12) | //x cross path if opposite sides + (0x9 << 5) | //opcode + (0x6 << 2) | //opcode fixed + (C67_map_regs(c) << 1) | //side of dest + (0 << 0)); //parallel + } else if (strstr(s, "ADD.L") == s) { + xpath = C67_map_regs(b) ^ C67_map_regs(c); + + ALWAYS_ASSERT(C67_map_regs(a) == C67_map_regs(c)); + + C67_g((0 << 29) | //creg + (0 << 28) | //inv + (C67_map_regn(c) << 23) | //dst + (C67_map_regn(b) << 18) | //src2 (possible x path) + (C67_map_regn(a) << 13) | //src1 + (xpath << 12) | //x cross path if opposite sides + (0x3 << 5) | //opcode + (0x6 << 2) | //opcode fixed + (C67_map_regs(c) << 1) | //side of dest + (0 << 0)); //parallel + } else if (strstr(s, "SUB.L") == s) { + xpath = C67_map_regs(b) ^ C67_map_regs(c); + + ALWAYS_ASSERT(C67_map_regs(a) == C67_map_regs(c)); + + C67_g((0 << 29) | //creg + (0 << 28) | //inv + (C67_map_regn(c) << 23) | //dst + (C67_map_regn(b) << 18) | //src2 (possible x path) + (C67_map_regn(a) << 13) | //src1 + (xpath << 12) | //x cross path if opposite sides + (0x7 << 5) | //opcode + (0x6 << 2) | //opcode fixed + (C67_map_regs(c) << 1) | //side of dest + (0 << 0)); //parallel + } else if (strstr(s, "OR.L") == s) { + xpath = C67_map_regs(b) ^ C67_map_regs(c); + + ALWAYS_ASSERT(C67_map_regs(a) == C67_map_regs(c)); + + C67_g((0 << 29) | //creg + (0 << 28) | //inv + (C67_map_regn(c) << 23) | //dst + (C67_map_regn(b) << 18) | //src2 (possible x path) + (C67_map_regn(a) << 13) | //src1 + (xpath << 12) | //x cross path if opposite sides + (0x7f << 5) | //opcode + (0x6 << 2) | //opcode fixed + (C67_map_regs(c) << 1) | //side of dest + (0 << 0)); //parallel + } else if (strstr(s, "AND.L") == s) { + xpath = C67_map_regs(b) ^ C67_map_regs(c); + + ALWAYS_ASSERT(C67_map_regs(a) == C67_map_regs(c)); + + C67_g((0 << 29) | //creg + (0 << 28) | //inv + (C67_map_regn(c) << 23) | //dst + (C67_map_regn(b) << 18) | //src2 (possible x path) + (C67_map_regn(a) << 13) | //src1 + (xpath << 12) | //x cross path if opposite sides + (0x7b << 5) | //opcode + (0x6 << 2) | //opcode fixed + (C67_map_regs(c) << 1) | //side of dest + (0 << 0)); //parallel + } else if (strstr(s, "XOR.L") == s) { + xpath = C67_map_regs(b) ^ C67_map_regs(c); + + ALWAYS_ASSERT(C67_map_regs(a) == C67_map_regs(c)); + + C67_g((0 << 29) | //creg + (0 << 28) | //inv + (C67_map_regn(c) << 23) | //dst + (C67_map_regn(b) << 18) | //src2 (possible x path) + (C67_map_regn(a) << 13) | //src1 + (xpath << 12) | //x cross path if opposite sides + (0x6f << 5) | //opcode + (0x6 << 2) | //opcode fixed + (C67_map_regs(c) << 1) | //side of dest + (0 << 0)); //parallel + } else if (strstr(s, "ADDSP.L") == s) { + xpath = C67_map_regs(b) ^ C67_map_regs(c); + + ALWAYS_ASSERT(C67_map_regs(a) == C67_map_regs(c)); + + C67_g((0 << 29) | //creg + (0 << 28) | //inv + (C67_map_regn(c) << 23) | //dst + (C67_map_regn(b) << 18) | //src2 (possible x path) + (C67_map_regn(a) << 13) | //src1 + (xpath << 12) | //x cross path if opposite sides + (0x10 << 5) | //opcode + (0x6 << 2) | //opcode fixed + (C67_map_regs(c) << 1) | //side of dest + (0 << 0)); //parallel + } else if (strstr(s, "ADDDP.L") == s) { + xpath = C67_map_regs(b) ^ C67_map_regs(c); + + ALWAYS_ASSERT(C67_map_regs(a) == C67_map_regs(c)); + + C67_g((0 << 29) | //creg + (0 << 28) | //inv + (C67_map_regn(c) << 23) | //dst + (C67_map_regn(b) << 18) | //src2 (possible x path) + (C67_map_regn(a) << 13) | //src1 + (xpath << 12) | //x cross path if opposite sides + (0x18 << 5) | //opcode + (0x6 << 2) | //opcode fixed + (C67_map_regs(c) << 1) | //side of dest + (0 << 0)); //parallel + } else if (strstr(s, "SUBSP.L") == s) { + xpath = C67_map_regs(b) ^ C67_map_regs(c); + + ALWAYS_ASSERT(C67_map_regs(a) == C67_map_regs(c)); + + C67_g((0 << 29) | //creg + (0 << 28) | //inv + (C67_map_regn(c) << 23) | //dst + (C67_map_regn(b) << 18) | //src2 (possible x path) + (C67_map_regn(a) << 13) | //src1 + (xpath << 12) | //x cross path if opposite sides + (0x11 << 5) | //opcode + (0x6 << 2) | //opcode fixed + (C67_map_regs(c) << 1) | //side of dest + (0 << 0)); //parallel + } else if (strstr(s, "SUBDP.L") == s) { + xpath = C67_map_regs(b) ^ C67_map_regs(c); + + ALWAYS_ASSERT(C67_map_regs(a) == C67_map_regs(c)); + + C67_g((0 << 29) | //creg + (0 << 28) | //inv + (C67_map_regn(c) << 23) | //dst + (C67_map_regn(b) << 18) | //src2 (possible x path) + (C67_map_regn(a) << 13) | //src1 + (xpath << 12) | //x cross path if opposite sides + (0x19 << 5) | //opcode + (0x6 << 2) | //opcode fixed + (C67_map_regs(c) << 1) | //side of dest + (0 << 0)); //parallel + } else if (strstr(s, "MPYSP.M") == s) { + xpath = C67_map_regs(b) ^ C67_map_regs(c); + + ALWAYS_ASSERT(C67_map_regs(a) == C67_map_regs(c)); + + C67_g((0 << 29) | //creg + (0 << 28) | //inv + (C67_map_regn(c) << 23) | //dst + (C67_map_regn(b) << 18) | //src2 (possible x path) + (C67_map_regn(a) << 13) | //src1 + (xpath << 12) | //x cross path if opposite sides + (0x1c << 7) | //opcode + (0x0 << 2) | //opcode fixed + (C67_map_regs(c) << 1) | //side of dest + (0 << 0)); //parallel + } else if (strstr(s, "MPYDP.M") == s) { + xpath = C67_map_regs(b) ^ C67_map_regs(c); + + ALWAYS_ASSERT(C67_map_regs(a) == C67_map_regs(c)); + + C67_g((0 << 29) | //creg + (0 << 28) | //inv + (C67_map_regn(c) << 23) | //dst + (C67_map_regn(b) << 18) | //src2 (possible x path) + (C67_map_regn(a) << 13) | //src1 + (xpath << 12) | //x cross path if opposite sides + (0x0e << 7) | //opcode + (0x0 << 2) | //opcode fixed + (C67_map_regs(c) << 1) | //side of dest + (0 << 0)); //parallel + } else if (strstr(s, "MPYI.M") == s) { + xpath = C67_map_regs(b) ^ C67_map_regs(c); + + ALWAYS_ASSERT(C67_map_regs(a) == C67_map_regs(c)); + + C67_g((0 << 29) | //creg + (0 << 28) | //inv + (C67_map_regn(c) << 23) | //dst + (C67_map_regn(b) << 18) | //src2 + (C67_map_regn(a) << 13) | //src1 (cst5) + (xpath << 12) | //x cross path if opposite sides + (0x4 << 7) | //opcode + (0x0 << 2) | //opcode fixed + (C67_map_regs(c) << 1) | //side of dest + (0 << 0)); //parallel + } else if (strstr(s, "SHR.S") == s) { + xpath = C67_map_regs(b) ^ C67_map_regs(c); + + ALWAYS_ASSERT(C67_map_regs(c) == C67_map_regs(a)); + + C67_g((0 << 29) | //creg + (0 << 28) | //inv + (C67_map_regn(c) << 23) | //dst + (C67_map_regn(b) << 18) | //src2 + (C67_map_regn(a) << 13) | //src1 + (xpath << 12) | //x cross path if opposite sides + (0x37 << 6) | //opcode + (0x8 << 2) | //opcode fixed + (C67_map_regs(c) << 1) | //side of dest + (0 << 0)); //parallel + } else if (strstr(s, "SHRU.S") == s) { + xpath = C67_map_regs(b) ^ C67_map_regs(c); + + ALWAYS_ASSERT(C67_map_regs(c) == C67_map_regs(a)); + + C67_g((0 << 29) | //creg + (0 << 28) | //inv + (C67_map_regn(c) << 23) | //dst + (C67_map_regn(b) << 18) | //src2 + (C67_map_regn(a) << 13) | //src1 + (xpath << 12) | //x cross path if opposite sides + (0x27 << 6) | //opcode + (0x8 << 2) | //opcode fixed + (C67_map_regs(c) << 1) | //side of dest + (0 << 0)); //parallel + } else if (strstr(s, "SHL.S") == s) { + xpath = C67_map_regs(b) ^ C67_map_regs(c); + + ALWAYS_ASSERT(C67_map_regs(c) == C67_map_regs(a)); + + C67_g((0 << 29) | //creg + (0 << 28) | //inv + (C67_map_regn(c) << 23) | //dst + (C67_map_regn(b) << 18) | //src2 + (C67_map_regn(a) << 13) | //src1 + (xpath << 12) | //x cross path if opposite sides + (0x33 << 6) | //opcode + (0x8 << 2) | //opcode fixed + (C67_map_regs(c) << 1) | //side of dest + (0 << 0)); //parallel + } else if (strstr(s, "||ADDK") == s) { + xpath = 0; // no xpath required just use the side of the src/dst + + C67_g((0 << 29) | //creg + (0 << 28) | //inv + (C67_map_regn(b) << 23) | //dst + (a << 07) | //scst16 + (0x14 << 2) | //opcode fixed + (C67_map_regs(b) << 1) | //side of dst + (1 << 0)); //parallel + } else if (strstr(s, "ADDK") == s) { + xpath = 0; // no xpath required just use the side of the src/dst + + C67_g((0 << 29) | //creg + (0 << 28) | //inv + (C67_map_regn(b) << 23) | //dst + (a << 07) | //scst16 + (0x14 << 2) | //opcode fixed + (C67_map_regs(b) << 1) | //side of dst + (0 << 0)); //parallel + } else if (strstr(s, "NOP") == s) { + C67_g(((a - 1) << 13) | //no of cycles + (0 << 0)); //parallel + } else + ALWAYS_ASSERT(FALSE); + +#ifdef ASSEMBLY_LISTING_C67 + fprintf(f, " %s %d %d %d\n", s, a, b, c); +#endif + +} + +//r=reg to load, fr=from reg, symbol for relocation, constant + +void C67_MVKL(int r, int fc) +{ + C67_asm("MVKL.", fc, r, 0); +} + +void C67_MVKH(int r, int fc) +{ + C67_asm("MVKH.", fc, r, 0); +} + +void C67_STB_SP_A0(int r) +{ + C67_asm("STB.D *+SP[A0]", r, 0, 0); // STB r,*+SP[A0] +} + +void C67_STH_SP_A0(int r) +{ + C67_asm("STH.D *+SP[A0]", r, 0, 0); // STH r,*+SP[A0] +} + +void C67_STW_SP_A0(int r) +{ + C67_asm("STW.D *+SP[A0]", r, 0, 0); // STW r,*+SP[A0] +} + +void C67_STB_PTR(int r, int r2) +{ + C67_asm("STB.D *", r, r2, 0); // STB r, *r2 +} + +void C67_STH_PTR(int r, int r2) +{ + C67_asm("STH.D *", r, r2, 0); // STH r, *r2 +} + +void C67_STW_PTR(int r, int r2) +{ + C67_asm("STW.D *", r, r2, 0); // STW r, *r2 +} + +void C67_STW_PTR_PRE_INC(int r, int r2, int n) +{ + C67_asm("STW.D +*", r, r2, n); // STW r, *+r2 +} + +void C67_PUSH(int r) +{ + C67_asm("STW.D SP POST DEC", r, 0, 0); // STW r,*SP-- +} + +void C67_LDW_SP_A0(int r) +{ + C67_asm("LDW.D *+SP[A0]", r, 0, 0); // LDW *+SP[A0],r +} + +void C67_LDDW_SP_A0(int r) +{ + C67_asm("LDDW.D *+SP[A0]", r, 0, 0); // LDDW *+SP[A0],r +} + +void C67_LDH_SP_A0(int r) +{ + C67_asm("LDH.D *+SP[A0]", r, 0, 0); // LDH *+SP[A0],r +} + +void C67_LDB_SP_A0(int r) +{ + C67_asm("LDB.D *+SP[A0]", r, 0, 0); // LDB *+SP[A0],r +} + +void C67_LDHU_SP_A0(int r) +{ + C67_asm("LDHU.D *+SP[A0]", r, 0, 0); // LDHU *+SP[A0],r +} + +void C67_LDBU_SP_A0(int r) +{ + C67_asm("LDBU.D *+SP[A0]", r, 0, 0); // LDBU *+SP[A0],r +} + +void C67_LDW_PTR(int r, int r2) +{ + C67_asm("LDW.D *", r, r2, 0); // LDW *r,r2 +} + +void C67_LDDW_PTR(int r, int r2) +{ + C67_asm("LDDW.D *", r, r2, 0); // LDDW *r,r2 +} + +void C67_LDH_PTR(int r, int r2) +{ + C67_asm("LDH.D *", r, r2, 0); // LDH *r,r2 +} + +void C67_LDB_PTR(int r, int r2) +{ + C67_asm("LDB.D *", r, r2, 0); // LDB *r,r2 +} + +void C67_LDHU_PTR(int r, int r2) +{ + C67_asm("LDHU.D *", r, r2, 0); // LDHU *r,r2 +} + +void C67_LDBU_PTR(int r, int r2) +{ + C67_asm("LDBU.D *", r, r2, 0); // LDBU *r,r2 +} + +void C67_LDW_PTR_PRE_INC(int r, int r2) +{ + C67_asm("LDW.D +*", r, r2, 0); // LDW *+r,r2 +} + +void C67_POP(int r) +{ + C67_asm("LDW.D SP PRE INC", r, 0, 0); // LDW *++SP,r +} + +void C67_POP_DW(int r) +{ + C67_asm("LDDW.D SP PRE INC", r, 0, 0); // LDDW *++SP,r +} + +void C67_CMPLT(int s1, int s2, int dst) +{ + C67_asm("CMPLT.L1", s1, s2, dst); +} + +void C67_CMPGT(int s1, int s2, int dst) +{ + C67_asm("CMPGT.L1", s1, s2, dst); +} + +void C67_CMPEQ(int s1, int s2, int dst) +{ + C67_asm("CMPEQ.L1", s1, s2, dst); +} + +void C67_CMPLTU(int s1, int s2, int dst) +{ + C67_asm("CMPLTU.L1", s1, s2, dst); +} + +void C67_CMPGTU(int s1, int s2, int dst) +{ + C67_asm("CMPGTU.L1", s1, s2, dst); +} + + +void C67_CMPLTSP(int s1, int s2, int dst) +{ + C67_asm("CMPLTSP.S1", s1, s2, dst); +} + +void C67_CMPGTSP(int s1, int s2, int dst) +{ + C67_asm("CMPGTSP.S1", s1, s2, dst); +} + +void C67_CMPEQSP(int s1, int s2, int dst) +{ + C67_asm("CMPEQSP.S1", s1, s2, dst); +} + +void C67_CMPLTDP(int s1, int s2, int dst) +{ + C67_asm("CMPLTDP.S1", s1, s2, dst); +} + +void C67_CMPGTDP(int s1, int s2, int dst) +{ + C67_asm("CMPGTDP.S1", s1, s2, dst); +} + +void C67_CMPEQDP(int s1, int s2, int dst) +{ + C67_asm("CMPEQDP.S1", s1, s2, dst); +} + + +void C67_IREG_B_REG(int inv, int r1, int r2) // [!R] B r2 +{ + C67_asm("B.S2", inv, r1, r2); +} + + +// call with how many 32 bit words to skip +// (0 would branch to the branch instruction) + +void C67_B_DISP(int disp) // B +2 Branch with constant displacement +{ + // Branch point is relative to the 8 word fetch packet + // + // we will assume the text section always starts on an 8 word (32 byte boundary) + // + // so add in how many words into the fetch packet the branch is + + + C67_asm("B DISP", disp + ((ind & 31) >> 2), 0, 0); +} + +void C67_NOP(int n) +{ + C67_asm("NOP", n, 0, 0); +} + +void C67_ADDK(int n, int r) +{ + ALWAYS_ASSERT(abs(n) < 32767); + + C67_asm("ADDK", n, r, 0); +} + +void C67_ADDK_PARALLEL(int n, int r) +{ + ALWAYS_ASSERT(abs(n) < 32767); + + C67_asm("||ADDK", n, r, 0); +} + +void C67_Adjust_ADDK(int *inst, int n) +{ + ALWAYS_ASSERT(abs(n) < 32767); + + *inst = (*inst & (~(0xffff << 7))) | ((n & 0xffff) << 7); +} + +void C67_MV(int r, int v) +{ + C67_asm("MV.L", 0, r, v); +} + + +void C67_DPTRUNC(int r, int v) +{ + C67_asm("DPTRUNC.L", 0, r, v); +} + +void C67_SPTRUNC(int r, int v) +{ + C67_asm("SPTRUNC.L", 0, r, v); +} + +void C67_INTSP(int r, int v) +{ + C67_asm("INTSP.L", 0, r, v); +} + +void C67_INTDP(int r, int v) +{ + C67_asm("INTDP.L", 0, r, v); +} + +void C67_INTSPU(int r, int v) +{ + C67_asm("INTSPU.L", 0, r, v); +} + +void C67_INTDPU(int r, int v) +{ + C67_asm("INTDPU.L", 0, r, v); +} + +void C67_SPDP(int r, int v) +{ + C67_asm("SPDP.L", 0, r, v); +} + +void C67_DPSP(int r, int v) // note regs must be on the same side +{ + C67_asm("DPSP.L", 0, r, v); +} + +void C67_ADD(int r, int v) +{ + C67_asm("ADD.L", v, r, v); +} + +void C67_SUB(int r, int v) +{ + C67_asm("SUB.L", v, r, v); +} + +void C67_AND(int r, int v) +{ + C67_asm("AND.L", v, r, v); +} + +void C67_OR(int r, int v) +{ + C67_asm("OR.L", v, r, v); +} + +void C67_XOR(int r, int v) +{ + C67_asm("XOR.L", v, r, v); +} + +void C67_ADDSP(int r, int v) +{ + C67_asm("ADDSP.L", v, r, v); +} + +void C67_SUBSP(int r, int v) +{ + C67_asm("SUBSP.L", v, r, v); +} + +void C67_MPYSP(int r, int v) +{ + C67_asm("MPYSP.M", v, r, v); +} + +void C67_ADDDP(int r, int v) +{ + C67_asm("ADDDP.L", v, r, v); +} + +void C67_SUBDP(int r, int v) +{ + C67_asm("SUBDP.L", v, r, v); +} + +void C67_MPYDP(int r, int v) +{ + C67_asm("MPYDP.M", v, r, v); +} + +void C67_MPYI(int r, int v) +{ + C67_asm("MPYI.M", v, r, v); +} + +void C67_SHL(int r, int v) +{ + C67_asm("SHL.S", r, v, v); +} + +void C67_SHRU(int r, int v) +{ + C67_asm("SHRU.S", r, v, v); +} + +void C67_SHR(int r, int v) +{ + C67_asm("SHR.S", r, v, v); +} + + + +/* load 'r' from value 'sv' */ +void load(int r, SValue * sv) +{ + int v, t, ft, fc, fr, size = 0, element; + BOOL Unsigned = FALSE; + SValue v1; + + fr = sv->r; + ft = sv->type.t; + fc = sv->c.i; + + v = fr & VT_VALMASK; + if (fr & VT_LVAL) { + if (v == VT_LLOCAL) { + v1.type.t = VT_INT; + v1.r = VT_LOCAL | VT_LVAL; + v1.c.i = fc; + load(r, &v1); + fr = r; + } else if ((ft & VT_BTYPE) == VT_LDOUBLE) { + tcc_error("long double not supported"); + } else if ((ft & VT_TYPE) == VT_BYTE) { + size = 1; + } else if ((ft & VT_TYPE) == (VT_BYTE | VT_UNSIGNED)) { + size = 1; + Unsigned = TRUE; + } else if ((ft & VT_TYPE) == VT_SHORT) { + size = 2; + } else if ((ft & VT_TYPE) == (VT_SHORT | VT_UNSIGNED)) { + size = 2; + Unsigned = TRUE; + } else if ((ft & VT_BTYPE) == VT_DOUBLE) { + size = 8; + } else { + size = 4; + } + + // check if fc is a positive reference on the stack, + // if it is tcc is referencing what it thinks is a parameter + // on the stack, so check if it is really in a register. + + + if (v == VT_LOCAL && fc > 0) { + int stack_pos = 8; + + for (t = 0; t < NoCallArgsPassedOnStack; t++) { + if (fc == stack_pos) + break; + + stack_pos += TranslateStackToReg[t]; + } + + // param has been pushed on stack, get it like a local var + + fc = ParamLocOnStack[t] - 8; + } + + if ((fr & VT_VALMASK) < VT_CONST) // check for pure indirect + { + if (size == 1) { + if (Unsigned) + C67_LDBU_PTR(v, r); // LDBU *v,r + else + C67_LDB_PTR(v, r); // LDB *v,r + } else if (size == 2) { + if (Unsigned) + C67_LDHU_PTR(v, r); // LDHU *v,r + else + C67_LDH_PTR(v, r); // LDH *v,r + } else if (size == 4) { + C67_LDW_PTR(v, r); // LDW *v,r + } else if (size == 8) { + C67_LDDW_PTR(v, r); // LDDW *v,r + } + + C67_NOP(4); // NOP 4 + return; + } else if (fr & VT_SYM) { + greloc(cur_text_section, sv->sym, ind, R_C60LO16); // rem the inst need to be patched + greloc(cur_text_section, sv->sym, ind + 4, R_C60HI16); + + + C67_MVKL(C67_A0, fc); //r=reg to load, constant + C67_MVKH(C67_A0, fc); //r=reg to load, constant + + + if (size == 1) { + if (Unsigned) + C67_LDBU_PTR(C67_A0, r); // LDBU *A0,r + else + C67_LDB_PTR(C67_A0, r); // LDB *A0,r + } else if (size == 2) { + if (Unsigned) + C67_LDHU_PTR(C67_A0, r); // LDHU *A0,r + else + C67_LDH_PTR(C67_A0, r); // LDH *A0,r + } else if (size == 4) { + C67_LDW_PTR(C67_A0, r); // LDW *A0,r + } else if (size == 8) { + C67_LDDW_PTR(C67_A0, r); // LDDW *A0,r + } + + C67_NOP(4); // NOP 4 + return; + } else { + element = size; + + // divide offset in bytes to create element index + C67_MVKL(C67_A0, (fc / element) + 8 / element); //r=reg to load, constant + C67_MVKH(C67_A0, (fc / element) + 8 / element); //r=reg to load, constant + + if (size == 1) { + if (Unsigned) + C67_LDBU_SP_A0(r); // LDBU r, SP[A0] + else + C67_LDB_SP_A0(r); // LDB r, SP[A0] + } else if (size == 2) { + if (Unsigned) + C67_LDHU_SP_A0(r); // LDHU r, SP[A0] + else + C67_LDH_SP_A0(r); // LDH r, SP[A0] + } else if (size == 4) { + C67_LDW_SP_A0(r); // LDW r, SP[A0] + } else if (size == 8) { + C67_LDDW_SP_A0(r); // LDDW r, SP[A0] + } + + + C67_NOP(4); // NOP 4 + return; + } + } else { + if (v == VT_CONST) { + if (fr & VT_SYM) { + greloc(cur_text_section, sv->sym, ind, R_C60LO16); // rem the inst need to be patched + greloc(cur_text_section, sv->sym, ind + 4, R_C60HI16); + } + C67_MVKL(r, fc); //r=reg to load, constant + C67_MVKH(r, fc); //r=reg to load, constant + } else if (v == VT_LOCAL) { + C67_MVKL(r, fc + 8); //r=reg to load, constant C67 stack points to next free + C67_MVKH(r, fc + 8); //r=reg to load, constant + C67_ADD(C67_FP, r); // MV v,r v -> r + } else if (v == VT_CMP) { + C67_MV(C67_compare_reg, r); // MV v,r v -> r + } else if (v == VT_JMP || v == VT_JMPI) { + t = v & 1; + C67_B_DISP(4); // Branch with constant displacement, skip over this branch, load, nop, load + C67_MVKL(r, t); // r=reg to load, 0 or 1 (do this while branching) + C67_NOP(4); // NOP 4 + gsym(fc); // modifies other branches to branch here + C67_MVKL(r, t ^ 1); // r=reg to load, 0 or 1 + } else if (v != r) { + C67_MV(v, r); // MV v,r v -> r + + if ((ft & VT_BTYPE) == VT_DOUBLE) + C67_MV(v + 1, r + 1); // MV v,r v -> r + } + } +} + + +/* store register 'r' in lvalue 'v' */ +void store(int r, SValue * v) +{ + int fr, bt, ft, fc, size, t, element; + + ft = v->type.t; + fc = v->c.i; + fr = v->r & VT_VALMASK; + bt = ft & VT_BTYPE; + /* XXX: incorrect if float reg to reg */ + + if (bt == VT_LDOUBLE) { + tcc_error("long double not supported"); + } else { + if (bt == VT_SHORT) + size = 2; + else if (bt == VT_BYTE) + size = 1; + else if (bt == VT_DOUBLE) + size = 8; + else + size = 4; + + if ((v->r & VT_VALMASK) == VT_CONST) { + /* constant memory reference */ + + if (v->r & VT_SYM) { + greloc(cur_text_section, v->sym, ind, R_C60LO16); // rem the inst need to be patched + greloc(cur_text_section, v->sym, ind + 4, R_C60HI16); + } + C67_MVKL(C67_A0, fc); //r=reg to load, constant + C67_MVKH(C67_A0, fc); //r=reg to load, constant + + if (size == 1) + C67_STB_PTR(r, C67_A0); // STB r, *A0 + else if (size == 2) + C67_STH_PTR(r, C67_A0); // STH r, *A0 + else if (size == 4 || size == 8) + C67_STW_PTR(r, C67_A0); // STW r, *A0 + + if (size == 8) + C67_STW_PTR_PRE_INC(r + 1, C67_A0, 1); // STW r, *+A0[1] + } else if ((v->r & VT_VALMASK) == VT_LOCAL) { + // check case of storing to passed argument that + // tcc thinks is on the stack but for C67 is + // passed as a reg. However it may have been + // saved to the stack, if that reg was required + // for a call to a child function + + if (fc > 0) // argument ?? + { + // walk through sizes and figure which param + + int stack_pos = 8; + + for (t = 0; t < NoCallArgsPassedOnStack; t++) { + if (fc == stack_pos) + break; + + stack_pos += TranslateStackToReg[t]; + } + + // param has been pushed on stack, get it like a local var + fc = ParamLocOnStack[t] - 8; + } + + if (size == 8) + element = 4; + else + element = size; + + // divide offset in bytes to create word index + C67_MVKL(C67_A0, (fc / element) + 8 / element); //r=reg to load, constant + C67_MVKH(C67_A0, (fc / element) + 8 / element); //r=reg to load, constant + + + + if (size == 1) + C67_STB_SP_A0(r); // STB r, SP[A0] + else if (size == 2) + C67_STH_SP_A0(r); // STH r, SP[A0] + else if (size == 4 || size == 8) + C67_STW_SP_A0(r); // STW r, SP[A0] + + if (size == 8) { + C67_ADDK(1, C67_A0); // ADDK 1,A0 + C67_STW_SP_A0(r + 1); // STW r, SP[A0] + } + } else { + if (size == 1) + C67_STB_PTR(r, fr); // STB r, *fr + else if (size == 2) + C67_STH_PTR(r, fr); // STH r, *fr + else if (size == 4 || size == 8) + C67_STW_PTR(r, fr); // STW r, *fr + + if (size == 8) { + C67_STW_PTR_PRE_INC(r + 1, fr, 1); // STW r, *+fr[1] + } + } + } +} + +/* 'is_jmp' is '1' if it is a jump */ +static void gcall_or_jmp(int is_jmp) +{ + int r; + Sym *sym; + + if ((vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST) { + /* constant case */ + if (vtop->r & VT_SYM) { + /* relocation case */ + + // get add into A0, then start the jump B3 + + greloc(cur_text_section, vtop->sym, ind, R_C60LO16); // rem the inst need to be patched + greloc(cur_text_section, vtop->sym, ind + 4, R_C60HI16); + + C67_MVKL(C67_A0, 0); //r=reg to load, constant + C67_MVKH(C67_A0, 0); //r=reg to load, constant + C67_IREG_B_REG(0, C67_CREG_ZERO, C67_A0); // B.S2x A0 + + if (is_jmp) { + C67_NOP(5); // simple jump, just put NOP + } else { + // Call, must load return address into B3 during delay slots + + sym = get_sym_ref(&char_pointer_type, cur_text_section, ind + 12, 0); // symbol for return address + greloc(cur_text_section, sym, ind, R_C60LO16); // rem the inst need to be patched + greloc(cur_text_section, sym, ind + 4, R_C60HI16); + C67_MVKL(C67_B3, 0); //r=reg to load, constant + C67_MVKH(C67_B3, 0); //r=reg to load, constant + C67_NOP(3); // put remaining NOPs + } + } else { + /* put an empty PC32 relocation */ + ALWAYS_ASSERT(FALSE); + } + } else { + /* otherwise, indirect call */ + r = gv(RC_INT); + C67_IREG_B_REG(0, C67_CREG_ZERO, r); // B.S2x r + + if (is_jmp) { + C67_NOP(5); // simple jump, just put NOP + } else { + // Call, must load return address into B3 during delay slots + + sym = get_sym_ref(&char_pointer_type, cur_text_section, ind + 12, 0); // symbol for return address + greloc(cur_text_section, sym, ind, R_C60LO16); // rem the inst need to be patched + greloc(cur_text_section, sym, ind + 4, R_C60HI16); + C67_MVKL(C67_B3, 0); //r=reg to load, constant + C67_MVKH(C67_B3, 0); //r=reg to load, constant + C67_NOP(3); // put remaining NOPs + } + } +} + +/* Return the number of registers needed to return the struct, or 0 if + returning via struct pointer. */ +ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *ret_align, int *regsize) { + *ret_align = 1; // Never have to re-align return values for x86-64 + return 0; +} + +/* generate function call with address in (vtop->t, vtop->c) and free function + context. Stack entry is popped */ +void gfunc_call(int nb_args) +{ + int i, r, size = 0; + int args_sizes[NoCallArgsPassedOnStack]; + + if (nb_args > NoCallArgsPassedOnStack) { + tcc_error("more than 10 function params not currently supported"); + // handle more than 10, put some on the stack + } + + for (i = 0; i < nb_args; i++) { + if ((vtop->type.t & VT_BTYPE) == VT_STRUCT) { + ALWAYS_ASSERT(FALSE); + } else { + /* simple type (currently always same size) */ + /* XXX: implicit cast ? */ + + + if ((vtop->type.t & VT_BTYPE) == VT_LLONG) { + tcc_error("long long not supported"); + } else if ((vtop->type.t & VT_BTYPE) == VT_LDOUBLE) { + tcc_error("long double not supported"); + } else if ((vtop->type.t & VT_BTYPE) == VT_DOUBLE) { + size = 8; + } else { + size = 4; + } + + // put the parameter into the corresponding reg (pair) + + r = gv(RC_C67_A4 << (2 * i)); + + // must put on stack because with 1 pass compiler , no way to tell + // if an up coming nested call might overwrite these regs + + C67_PUSH(r); + + if (size == 8) { + C67_STW_PTR_PRE_INC(r + 1, C67_SP, 3); // STW r, *+SP[3] (go back and put the other) + } + args_sizes[i] = size; + } + vtop--; + } + // POP all the params on the stack into registers for the + // immediate call (in reverse order) + + for (i = nb_args - 1; i >= 0; i--) { + + if (args_sizes[i] == 8) + C67_POP_DW(TREG_C67_A4 + i * 2); + else + C67_POP(TREG_C67_A4 + i * 2); + } + gcall_or_jmp(0); + vtop--; +} + + +// to be compatible with Code Composer for the C67 +// the first 10 parameters must be passed in registers +// (pairs for 64 bits) starting wit; A4:A5, then B4:B5 and +// ending with B12:B13. +// +// When a call is made, if the caller has its parameters +// in regs A4-B13 these must be saved before/as the call +// parameters are loaded and restored upon return (or if/when needed). + +/* generate function prolog of type 't' */ +void gfunc_prolog(CType * func_type) +{ + int addr, align, size, func_call, i; + Sym *sym; + CType *type; + + sym = func_type->ref; + func_call = sym->f.func_call; + addr = 8; + /* if the function returns a structure, then add an + implicit pointer parameter */ + func_vt = sym->type; + func_var = (sym->f.func_type == FUNC_ELLIPSIS); + if ((func_vt.t & VT_BTYPE) == VT_STRUCT) { + func_vc = addr; + addr += 4; + } + + NoOfCurFuncArgs = 0; + + /* define parameters */ + while ((sym = sym->next) != NULL) { + type = &sym->type; + sym_push(sym->v & ~SYM_FIELD, type, VT_LOCAL | lvalue_type(type->t), addr); + size = type_size(type, &align); + size = (size + 3) & ~3; + + // keep track of size of arguments so + // we can translate where tcc thinks they + // are on the stack into the appropriate reg + + TranslateStackToReg[NoOfCurFuncArgs] = size; + NoOfCurFuncArgs++; + +#ifdef FUNC_STRUCT_PARAM_AS_PTR + /* structs are passed as pointer */ + if ((type->t & VT_BTYPE) == VT_STRUCT) { + size = 4; + } +#endif + addr += size; + } + func_ret_sub = 0; + /* pascal type call ? */ + if (func_call == FUNC_STDCALL) + func_ret_sub = addr - 8; + + C67_MV(C67_FP, C67_A0); // move FP -> A0 + C67_MV(C67_SP, C67_FP); // move SP -> FP + + // place all the args passed in regs onto the stack + + loc = 0; + for (i = 0; i < NoOfCurFuncArgs; i++) { + + ParamLocOnStack[i] = loc; // remember where the param is + loc += -8; + + C67_PUSH(TREG_C67_A4 + i * 2); + + if (TranslateStackToReg[i] == 8) { + C67_STW_PTR_PRE_INC(TREG_C67_A4 + i * 2 + 1, C67_SP, 3); // STW r, *+SP[1] (go back and put the other) + } + } + + TotalBytesPushedOnStack = -loc; + + func_sub_sp_offset = ind; // remember where we put the stack instruction + C67_ADDK(0, C67_SP); // ADDK.L2 loc,SP (just put zero temporarily) + + C67_PUSH(C67_A0); + C67_PUSH(C67_B3); +} + +/* generate function epilog */ +void gfunc_epilog(void) +{ + { + int local = (-loc + 7) & -8; // stack must stay aligned to 8 bytes for LDDW instr + C67_POP(C67_B3); + C67_NOP(4); // NOP wait for load + C67_IREG_B_REG(0, C67_CREG_ZERO, C67_B3); // B.S2 B3 + C67_POP(C67_FP); + C67_ADDK(local, C67_SP); // ADDK.L2 loc,SP + C67_Adjust_ADDK((int *) (cur_text_section->data + + func_sub_sp_offset), + -local + TotalBytesPushedOnStack); + C67_NOP(3); // NOP + } +} + +/* generate a jump to a label */ +int gjmp(int t) +{ + int ind1 = ind; + if (nocode_wanted) + return t; + + C67_MVKL(C67_A0, t); //r=reg to load, constant + C67_MVKH(C67_A0, t); //r=reg to load, constant + C67_IREG_B_REG(0, C67_CREG_ZERO, C67_A0); // [!R] B.S2x A0 + C67_NOP(5); + return ind1; +} + +/* generate a jump to a fixed address */ +void gjmp_addr(int a) +{ + Sym *sym; + // I guess this routine is used for relative short + // local jumps, for now just handle it as the general + // case + + // define a label that will be relocated + + sym = get_sym_ref(&char_pointer_type, cur_text_section, a, 0); + greloc(cur_text_section, sym, ind, R_C60LO16); + greloc(cur_text_section, sym, ind + 4, R_C60HI16); + + gjmp(0); // place a zero there later the symbol will be added to it +} + +/* generate a test. set 'inv' to invert test. Stack entry is popped */ +int gtst(int inv, int t) +{ + int ind1, n; + int v, *p; + + v = vtop->r & VT_VALMASK; + if (nocode_wanted) { + ; + } else if (v == VT_CMP) { + /* fast case : can jump directly since flags are set */ + // C67 uses B2 sort of as flags register + ind1 = ind; + C67_MVKL(C67_A0, t); //r=reg to load, constant + C67_MVKH(C67_A0, t); //r=reg to load, constant + + if (C67_compare_reg != TREG_EAX && // check if not already in a conditional test reg + C67_compare_reg != TREG_EDX && + C67_compare_reg != TREG_ST0 && C67_compare_reg != C67_B2) { + C67_MV(C67_compare_reg, C67_B2); + C67_compare_reg = C67_B2; + } + + C67_IREG_B_REG(C67_invert_test ^ inv, C67_compare_reg, C67_A0); // [!R] B.S2x A0 + C67_NOP(5); + t = ind1; //return where we need to patch + + } else if (v == VT_JMP || v == VT_JMPI) { + /* && or || optimization */ + if ((v & 1) == inv) { + /* insert vtop->c jump list in t */ + + // I guess the idea is to traverse to the + // null at the end of the list and store t + // there + + n = vtop->c.i; + while (n != 0) { + p = (int *) (cur_text_section->data + n); + + // extract 32 bit address from MVKH/MVKL + n = ((*p >> 7) & 0xffff); + n |= ((*(p + 1) >> 7) & 0xffff) << 16; + } + *p |= (t & 0xffff) << 7; + *(p + 1) |= ((t >> 16) & 0xffff) << 7; + t = vtop->c.i; + + } else { + t = gjmp(t); + gsym(vtop->c.i); + } + } + vtop--; + return t; +} + +/* generate an integer binary operation */ +void gen_opi(int op) +{ + int r, fr, opc, t; + + switch (op) { + case '+': + case TOK_ADDC1: /* add with carry generation */ + opc = 0; + gen_op8: + + +// C67 can't do const compares, must load into a reg +// so just go to gv2 directly - tktk + + + + if (op >= TOK_ULT && op <= TOK_GT) + gv2(RC_INT_BSIDE, RC_INT); // make sure r (src1) is on the B Side of CPU + else + gv2(RC_INT, RC_INT); + + r = vtop[-1].r; + fr = vtop[0].r; + + C67_compare_reg = C67_B2; + + + if (op == TOK_LT) { + C67_CMPLT(r, fr, C67_B2); + C67_invert_test = FALSE; + } else if (op == TOK_GE) { + C67_CMPLT(r, fr, C67_B2); + C67_invert_test = TRUE; + } else if (op == TOK_GT) { + C67_CMPGT(r, fr, C67_B2); + C67_invert_test = FALSE; + } else if (op == TOK_LE) { + C67_CMPGT(r, fr, C67_B2); + C67_invert_test = TRUE; + } else if (op == TOK_EQ) { + C67_CMPEQ(r, fr, C67_B2); + C67_invert_test = FALSE; + } else if (op == TOK_NE) { + C67_CMPEQ(r, fr, C67_B2); + C67_invert_test = TRUE; + } else if (op == TOK_ULT) { + C67_CMPLTU(r, fr, C67_B2); + C67_invert_test = FALSE; + } else if (op == TOK_UGE) { + C67_CMPLTU(r, fr, C67_B2); + C67_invert_test = TRUE; + } else if (op == TOK_UGT) { + C67_CMPGTU(r, fr, C67_B2); + C67_invert_test = FALSE; + } else if (op == TOK_ULE) { + C67_CMPGTU(r, fr, C67_B2); + C67_invert_test = TRUE; + } else if (op == '+') + C67_ADD(fr, r); // ADD r,fr,r + else if (op == '-') + C67_SUB(fr, r); // SUB r,fr,r + else if (op == '&') + C67_AND(fr, r); // AND r,fr,r + else if (op == '|') + C67_OR(fr, r); // OR r,fr,r + else if (op == '^') + C67_XOR(fr, r); // XOR r,fr,r + else + ALWAYS_ASSERT(FALSE); + + vtop--; + if (op >= TOK_ULT && op <= TOK_GT) { + vtop->r = VT_CMP; + vtop->c.i = op; + } + break; + case '-': + case TOK_SUBC1: /* sub with carry generation */ + opc = 5; + goto gen_op8; + case TOK_ADDC2: /* add with carry use */ + opc = 2; + goto gen_op8; + case TOK_SUBC2: /* sub with carry use */ + opc = 3; + goto gen_op8; + case '&': + opc = 4; + goto gen_op8; + case '^': + opc = 6; + goto gen_op8; + case '|': + opc = 1; + goto gen_op8; + case '*': + case TOK_UMULL: + gv2(RC_INT, RC_INT); + r = vtop[-1].r; + fr = vtop[0].r; + vtop--; + C67_MPYI(fr, r); // 32 bit multiply fr,r,fr + C67_NOP(8); // NOP 8 for worst case + break; + case TOK_SHL: + gv2(RC_INT_BSIDE, RC_INT_BSIDE); // shift amount must be on same side as dst + r = vtop[-1].r; + fr = vtop[0].r; + vtop--; + C67_SHL(fr, r); // arithmetic/logical shift + break; + + case TOK_SHR: + gv2(RC_INT_BSIDE, RC_INT_BSIDE); // shift amount must be on same side as dst + r = vtop[-1].r; + fr = vtop[0].r; + vtop--; + C67_SHRU(fr, r); // logical shift + break; + + case TOK_SAR: + gv2(RC_INT_BSIDE, RC_INT_BSIDE); // shift amount must be on same side as dst + r = vtop[-1].r; + fr = vtop[0].r; + vtop--; + C67_SHR(fr, r); // arithmetic shift + break; + + case '/': + t = TOK__divi; + call_func: + vswap(); + /* call generic idiv function */ + vpush_global_sym(&func_old_type, t); + vrott(3); + gfunc_call(2); + vpushi(0); + vtop->r = REG_IRET; + vtop->r2 = VT_CONST; + break; + case TOK_UDIV: + case TOK_PDIV: + t = TOK__divu; + goto call_func; + case '%': + t = TOK__remi; + goto call_func; + case TOK_UMOD: + t = TOK__remu; + goto call_func; + + default: + opc = 7; + goto gen_op8; + } +} + +/* generate a floating point operation 'v = t1 op t2' instruction. The + two operands are guaranteed to have the same floating point type */ +/* XXX: need to use ST1 too */ +void gen_opf(int op) +{ + int ft, fc, fr, r; + + if (op >= TOK_ULT && op <= TOK_GT) + gv2(RC_EDX, RC_EAX); // make sure src2 is on b side + else + gv2(RC_FLOAT, RC_FLOAT); // make sure src2 is on b side + + ft = vtop->type.t; + fc = vtop->c.i; + r = vtop->r; + fr = vtop[-1].r; + + + if ((ft & VT_BTYPE) == VT_LDOUBLE) + tcc_error("long doubles not supported"); + + if (op >= TOK_ULT && op <= TOK_GT) { + + r = vtop[-1].r; + fr = vtop[0].r; + + C67_compare_reg = C67_B2; + + if (op == TOK_LT) { + if ((ft & VT_BTYPE) == VT_DOUBLE) + C67_CMPLTDP(r, fr, C67_B2); + else + C67_CMPLTSP(r, fr, C67_B2); + + C67_invert_test = FALSE; + } else if (op == TOK_GE) { + if ((ft & VT_BTYPE) == VT_DOUBLE) + C67_CMPLTDP(r, fr, C67_B2); + else + C67_CMPLTSP(r, fr, C67_B2); + + C67_invert_test = TRUE; + } else if (op == TOK_GT) { + if ((ft & VT_BTYPE) == VT_DOUBLE) + C67_CMPGTDP(r, fr, C67_B2); + else + C67_CMPGTSP(r, fr, C67_B2); + + C67_invert_test = FALSE; + } else if (op == TOK_LE) { + if ((ft & VT_BTYPE) == VT_DOUBLE) + C67_CMPGTDP(r, fr, C67_B2); + else + C67_CMPGTSP(r, fr, C67_B2); + + C67_invert_test = TRUE; + } else if (op == TOK_EQ) { + if ((ft & VT_BTYPE) == VT_DOUBLE) + C67_CMPEQDP(r, fr, C67_B2); + else + C67_CMPEQSP(r, fr, C67_B2); + + C67_invert_test = FALSE; + } else if (op == TOK_NE) { + if ((ft & VT_BTYPE) == VT_DOUBLE) + C67_CMPEQDP(r, fr, C67_B2); + else + C67_CMPEQSP(r, fr, C67_B2); + + C67_invert_test = TRUE; + } else { + ALWAYS_ASSERT(FALSE); + } + vtop->r = VT_CMP; // tell TCC that result is in "flags" actually B2 + } else { + if (op == '+') { + if ((ft & VT_BTYPE) == VT_DOUBLE) { + C67_ADDDP(r, fr); // ADD fr,r,fr + C67_NOP(6); + } else { + C67_ADDSP(r, fr); // ADD fr,r,fr + C67_NOP(3); + } + vtop--; + } else if (op == '-') { + if ((ft & VT_BTYPE) == VT_DOUBLE) { + C67_SUBDP(r, fr); // SUB fr,r,fr + C67_NOP(6); + } else { + C67_SUBSP(r, fr); // SUB fr,r,fr + C67_NOP(3); + } + vtop--; + } else if (op == '*') { + if ((ft & VT_BTYPE) == VT_DOUBLE) { + C67_MPYDP(r, fr); // MPY fr,r,fr + C67_NOP(9); + } else { + C67_MPYSP(r, fr); // MPY fr,r,fr + C67_NOP(3); + } + vtop--; + } else if (op == '/') { + if ((ft & VT_BTYPE) == VT_DOUBLE) { + // must call intrinsic DP floating point divide + vswap(); + /* call generic idiv function */ + vpush_global_sym(&func_old_type, TOK__divd); + vrott(3); + gfunc_call(2); + vpushi(0); + vtop->r = REG_FRET; + vtop->r2 = REG_LRET; + + } else { + // must call intrinsic SP floating point divide + vswap(); + /* call generic idiv function */ + vpush_global_sym(&func_old_type, TOK__divf); + vrott(3); + gfunc_call(2); + vpushi(0); + vtop->r = REG_FRET; + vtop->r2 = VT_CONST; + } + } else + ALWAYS_ASSERT(FALSE); + + + } +} + + +/* convert integers to fp 't' type. Must handle 'int', 'unsigned int' + and 'long long' cases. */ +void gen_cvt_itof(int t) +{ + int r; + + gv(RC_INT); + r = vtop->r; + + if ((t & VT_BTYPE) == VT_DOUBLE) { + if (t & VT_UNSIGNED) + C67_INTDPU(r, r); + else + C67_INTDP(r, r); + + C67_NOP(4); + vtop->type.t = VT_DOUBLE; + } else { + if (t & VT_UNSIGNED) + C67_INTSPU(r, r); + else + C67_INTSP(r, r); + C67_NOP(3); + vtop->type.t = VT_FLOAT; + } + +} + +/* convert fp to int 't' type */ +/* XXX: handle long long case */ +void gen_cvt_ftoi(int t) +{ + int r; + + gv(RC_FLOAT); + r = vtop->r; + + if (t != VT_INT) + tcc_error("long long not supported"); + else { + if ((vtop->type.t & VT_BTYPE) == VT_DOUBLE) { + C67_DPTRUNC(r, r); + C67_NOP(3); + } else { + C67_SPTRUNC(r, r); + C67_NOP(3); + } + + vtop->type.t = VT_INT; + + } +} + +/* convert from one floating point type to another */ +void gen_cvt_ftof(int t) +{ + int r, r2; + + if ((vtop->type.t & VT_BTYPE) == VT_DOUBLE && + (t & VT_BTYPE) == VT_FLOAT) { + // convert double to float + + gv(RC_FLOAT); // get it in a register pair + + r = vtop->r; + + C67_DPSP(r, r); // convert it to SP same register + C67_NOP(3); + + vtop->type.t = VT_FLOAT; + vtop->r2 = VT_CONST; // set this as unused + } else if ((vtop->type.t & VT_BTYPE) == VT_FLOAT && + (t & VT_BTYPE) == VT_DOUBLE) { + // convert float to double + + gv(RC_FLOAT); // get it in a register + + r = vtop->r; + + if (r == TREG_EAX) { // make sure the paired reg is avail + r2 = get_reg(RC_ECX); + } else if (r == TREG_EDX) { + r2 = get_reg(RC_ST0); + } else { + ALWAYS_ASSERT(FALSE); + r2 = 0; /* avoid warning */ + } + + C67_SPDP(r, r); // convert it to DP same register + C67_NOP(1); + + vtop->type.t = VT_DOUBLE; + vtop->r2 = r2; // set this as unused + } else { + ALWAYS_ASSERT(FALSE); + } +} + +/* computed goto support */ +void ggoto(void) +{ + gcall_or_jmp(1); + vtop--; +} + +/* Save the stack pointer onto the stack and return the location of its address */ +ST_FUNC void gen_vla_sp_save(int addr) { + tcc_error("variable length arrays unsupported for this target"); +} + +/* Restore the SP from a location on the stack */ +ST_FUNC void gen_vla_sp_restore(int addr) { + tcc_error("variable length arrays unsupported for this target"); +} + +/* Subtract from the stack pointer, and push the resulting value onto the stack */ +ST_FUNC void gen_vla_alloc(CType *type, int align) { + tcc_error("variable length arrays unsupported for this target"); +} + +/* end of C67 code generator */ +/*************************************************************/ +#endif +/*************************************************************/ diff --git a/tinyc/c67-link.c b/tinyc/c67-link.c new file mode 100644 index 000000000..de72e442f --- /dev/null +++ b/tinyc/c67-link.c @@ -0,0 +1,131 @@ +#ifdef TARGET_DEFS_ONLY + +#define EM_TCC_TARGET EM_C60 + +/* relocation type for 32 bit data relocation */ +#define R_DATA_32 R_C60_32 +#define R_DATA_PTR R_C60_32 +#define R_JMP_SLOT R_C60_JMP_SLOT +#define R_GLOB_DAT R_C60_GLOB_DAT +#define R_COPY R_C60_COPY +#define R_RELATIVE R_C60_RELATIVE + +#define R_NUM R_C60_NUM + +#define ELF_START_ADDR 0x00000400 +#define ELF_PAGE_SIZE 0x1000 + +#define PCRELATIVE_DLLPLT 0 +#define RELOCATE_DLLPLT 0 + +#else /* !TARGET_DEFS_ONLY */ + +#include "tcc.h" + +/* Returns 1 for a code relocation, 0 for a data relocation. For unknown + relocations, returns -1. */ +int code_reloc (int reloc_type) +{ + switch (reloc_type) { + case R_C60_32: + case R_C60LO16: + case R_C60HI16: + case R_C60_GOT32: + case R_C60_GOTOFF: + case R_C60_GOTPC: + case R_C60_COPY: + return 0; + + case R_C60_PLT32: + return 1; + } + + tcc_error ("Unknown relocation type: %d", reloc_type); + return -1; +} + +/* Returns an enumerator to describe whether and when the relocation needs a + GOT and/or PLT entry to be created. See tcc.h for a description of the + different values. */ +int gotplt_entry_type (int reloc_type) +{ + switch (reloc_type) { + case R_C60_32: + case R_C60LO16: + case R_C60HI16: + case R_C60_COPY: + return NO_GOTPLT_ENTRY; + + case R_C60_GOTOFF: + case R_C60_GOTPC: + return BUILD_GOT_ONLY; + + case R_C60_PLT32: + case R_C60_GOT32: + return ALWAYS_GOTPLT_ENTRY; + } + + tcc_error ("Unknown relocation type: %d", reloc_type); + return -1; +} + +ST_FUNC unsigned create_plt_entry(TCCState *s1, unsigned got_offset, struct sym_attr *attr) +{ + tcc_error("C67 got not implemented"); + return 0; +} + +/* relocate the PLT: compute addresses and offsets in the PLT now that final + address for PLT and GOT are known (see fill_program_header) */ +ST_FUNC void relocate_plt(TCCState *s1) +{ + uint8_t *p, *p_end; + + if (!s1->plt) + return; + + p = s1->plt->data; + p_end = p + s1->plt->data_offset; + + if (p < p_end) { + /* XXX: TODO */ + while (p < p_end) { + /* XXX: TODO */ + } + } +} + +void relocate_init(Section *sr) {} + +void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t addr, addr_t val) +{ + switch(type) { + case R_C60_32: + *(int *)ptr += val; + break; + case R_C60LO16: + { + uint32_t orig; + + /* put the low 16 bits of the absolute address add to what is + already there */ + orig = ((*(int *)(ptr )) >> 7) & 0xffff; + orig |= (((*(int *)(ptr+4)) >> 7) & 0xffff) << 16; + + /* patch both at once - assumes always in pairs Low - High */ + *(int *) ptr = (*(int *) ptr & (~(0xffff << 7)) ) | + (((val+orig) & 0xffff) << 7); + *(int *)(ptr+4) = (*(int *)(ptr+4) & (~(0xffff << 7)) ) | + ((((val+orig)>>16) & 0xffff) << 7); + } + break; + case R_C60HI16: + break; + default: + fprintf(stderr,"FIXME: handle reloc type %x at %x [%p] to %x\n", + type, (unsigned) addr, ptr, (unsigned) val); + break; + } +} + +#endif /* !TARGET_DEFS_ONLY */ diff --git a/tinyc/coff.h b/tinyc/coff.h new file mode 100644 index 000000000..e8e6185a6 --- /dev/null +++ b/tinyc/coff.h @@ -0,0 +1,446 @@ +/**************************************************************************/ +/* COFF.H */ +/* COFF data structures and related definitions used by the linker */ +/**************************************************************************/ + +/*------------------------------------------------------------------------*/ +/* COFF FILE HEADER */ +/*------------------------------------------------------------------------*/ +struct filehdr { + unsigned short f_magic; /* magic number */ + unsigned short f_nscns; /* number of sections */ + long f_timdat; /* time & date stamp */ + long f_symptr; /* file pointer to symtab */ + long f_nsyms; /* number of symtab entries */ + unsigned short f_opthdr; /* sizeof(optional hdr) */ + unsigned short f_flags; /* flags */ + unsigned short f_TargetID; /* for C6x = 0x0099 */ + }; + +/*------------------------------------------------------------------------*/ +/* File header flags */ +/*------------------------------------------------------------------------*/ +#define F_RELFLG 0x01 /* relocation info stripped from file */ +#define F_EXEC 0x02 /* file is executable (no unresolved refs) */ +#define F_LNNO 0x04 /* line numbers stripped from file */ +#define F_LSYMS 0x08 /* local symbols stripped from file */ +#define F_GSP10 0x10 /* 34010 version */ +#define F_GSP20 0x20 /* 34020 version */ +#define F_SWABD 0x40 /* bytes swabbed (in names) */ +#define F_AR16WR 0x80 /* byte ordering of an AR16WR (PDP-11) */ +#define F_LITTLE 0x100 /* byte ordering of an AR32WR (vax) */ +#define F_BIG 0x200 /* byte ordering of an AR32W (3B, maxi) */ +#define F_PATCH 0x400 /* contains "patch" list in optional header */ +#define F_NODF 0x400 + +#define F_VERSION (F_GSP10 | F_GSP20) +#define F_BYTE_ORDER (F_LITTLE | F_BIG) +#define FILHDR struct filehdr + +/* #define FILHSZ sizeof(FILHDR) */ +#define FILHSZ 22 /* above rounds to align on 4 bytes which causes problems */ + +#define COFF_C67_MAGIC 0x00c2 + +/*------------------------------------------------------------------------*/ +/* Macros to recognize magic numbers */ +/*------------------------------------------------------------------------*/ +#define ISMAGIC(x) (((unsigned short)(x))==(unsigned short)magic) +#define ISARCHIVE(x) ((((unsigned short)(x))==(unsigned short)ARTYPE)) +#define BADMAGIC(x) (((unsigned short)(x) & 0x8080) && !ISMAGIC(x)) + + +/*------------------------------------------------------------------------*/ +/* OPTIONAL FILE HEADER */ +/*------------------------------------------------------------------------*/ +typedef struct aouthdr { + short magic; /* see magic.h */ + short vstamp; /* version stamp */ + long tsize; /* text size in bytes, padded to FW bdry*/ + long dsize; /* initialized data " " */ + long bsize; /* uninitialized data " " */ + long entrypt; /* entry pt. */ + long text_start; /* base of text used for this file */ + long data_start; /* base of data used for this file */ +} AOUTHDR; + +#define AOUTSZ sizeof(AOUTHDR) + +/*----------------------------------------------------------------------*/ +/* When a UNIX aout header is to be built in the optional header, */ +/* the following magic numbers can appear in that header: */ +/* */ +/* AOUT1MAGIC : default : readonly sharable text segment */ +/* AOUT2MAGIC: : writable text segment */ +/* PAGEMAGIC : : configured for paging */ +/*----------------------------------------------------------------------*/ +#define AOUT1MAGIC 0410 +#define AOUT2MAGIC 0407 +#define PAGEMAGIC 0413 + + +/*------------------------------------------------------------------------*/ +/* COMMON ARCHIVE FILE STRUCTURES */ +/* */ +/* ARCHIVE File Organization: */ +/* _______________________________________________ */ +/* |__________ARCHIVE_MAGIC_STRING_______________| */ +/* |__________ARCHIVE_FILE_MEMBER_1______________| */ +/* | | */ +/* | Archive File Header "ar_hdr" | */ +/* |.............................................| */ +/* | Member Contents | */ +/* | 1. External symbol directory | */ +/* | 2. Text file | */ +/* |_____________________________________________| */ +/* |________ARCHIVE_FILE_MEMBER_2________________| */ +/* | "ar_hdr" | */ +/* |.............................................| */ +/* | Member Contents (.o or text file) | */ +/* |_____________________________________________| */ +/* | . . . | */ +/* | . . . | */ +/* | . . . | */ +/* |_____________________________________________| */ +/* |________ARCHIVE_FILE_MEMBER_n________________| */ +/* | "ar_hdr" | */ +/* |.............................................| */ +/* | Member Contents | */ +/* |_____________________________________________| */ +/* */ +/*------------------------------------------------------------------------*/ + +#define COFF_ARMAG "!\n" +#define SARMAG 8 +#define ARFMAG "`\n" + +struct ar_hdr /* archive file member header - printable ascii */ +{ + char ar_name[16]; /* file member name - `/' terminated */ + char ar_date[12]; /* file member date - decimal */ + char ar_uid[6]; /* file member user id - decimal */ + char ar_gid[6]; /* file member group id - decimal */ + char ar_mode[8]; /* file member mode - octal */ + char ar_size[10]; /* file member size - decimal */ + char ar_fmag[2]; /* ARFMAG - string to end header */ +}; + + +/*------------------------------------------------------------------------*/ +/* SECTION HEADER */ +/*------------------------------------------------------------------------*/ +struct scnhdr { + char s_name[8]; /* section name */ + long s_paddr; /* physical address */ + long s_vaddr; /* virtual address */ + long s_size; /* section size */ + long s_scnptr; /* file ptr to raw data for section */ + long s_relptr; /* file ptr to relocation */ + long s_lnnoptr; /* file ptr to line numbers */ + unsigned int s_nreloc; /* number of relocation entries */ + unsigned int s_nlnno; /* number of line number entries */ + unsigned int s_flags; /* flags */ + unsigned short s_reserved; /* reserved byte */ + unsigned short s_page; /* memory page id */ + }; + +#define SCNHDR struct scnhdr +#define SCNHSZ sizeof(SCNHDR) + +/*------------------------------------------------------------------------*/ +/* Define constants for names of "special" sections */ +/*------------------------------------------------------------------------*/ +/* #define _TEXT ".text" */ +#define _DATA ".data" +#define _BSS ".bss" +#define _CINIT ".cinit" +#define _TV ".tv" + +/*------------------------------------------------------------------------*/ +/* The low 4 bits of s_flags is used as a section "type" */ +/*------------------------------------------------------------------------*/ +#define STYP_REG 0x00 /* "regular" : allocated, relocated, loaded */ +#define STYP_DSECT 0x01 /* "dummy" : not allocated, relocated, not loaded */ +#define STYP_NOLOAD 0x02 /* "noload" : allocated, relocated, not loaded */ +#define STYP_GROUP 0x04 /* "grouped" : formed of input sections */ +#define STYP_PAD 0x08 /* "padding" : not allocated, not relocated, loaded */ +#define STYP_COPY 0x10 /* "copy" : used for C init tables - + not allocated, relocated, + loaded; reloc & lineno + entries processed normally */ +#define STYP_TEXT 0x20 /* section contains text only */ +#define STYP_DATA 0x40 /* section contains data only */ +#define STYP_BSS 0x80 /* section contains bss only */ + +#define STYP_ALIGN 0x100 /* align flag passed by old version assemblers */ +#define ALIGN_MASK 0x0F00 /* part of s_flags that is used for align vals */ +#define ALIGNSIZE(x) (1 << ((x & ALIGN_MASK) >> 8)) + + +/*------------------------------------------------------------------------*/ +/* RELOCATION ENTRIES */ +/*------------------------------------------------------------------------*/ +struct reloc +{ + long r_vaddr; /* (virtual) address of reference */ + short r_symndx; /* index into symbol table */ + unsigned short r_disp; /* additional bits for address calculation */ + unsigned short r_type; /* relocation type */ +}; + +#define RELOC struct reloc +#define RELSZ 10 /* sizeof(RELOC) */ + +/*--------------------------------------------------------------------------*/ +/* define all relocation types */ +/*--------------------------------------------------------------------------*/ + +#define R_ABS 0 /* absolute address - no relocation */ +#define R_DIR16 01 /* UNUSED */ +#define R_REL16 02 /* UNUSED */ +#define R_DIR24 04 /* UNUSED */ +#define R_REL24 05 /* 24 bits, direct */ +#define R_DIR32 06 /* UNUSED */ +#define R_RELBYTE 017 /* 8 bits, direct */ +#define R_RELWORD 020 /* 16 bits, direct */ +#define R_RELLONG 021 /* 32 bits, direct */ +#define R_PCRBYTE 022 /* 8 bits, PC-relative */ +#define R_PCRWORD 023 /* 16 bits, PC-relative */ +#define R_PCRLONG 024 /* 32 bits, PC-relative */ +#define R_OCRLONG 030 /* GSP: 32 bits, one's complement direct */ +#define R_GSPPCR16 031 /* GSP: 16 bits, PC relative (in words) */ +#define R_GSPOPR32 032 /* GSP: 32 bits, direct big-endian */ +#define R_PARTLS16 040 /* Brahma: 16 bit offset of 24 bit address*/ +#define R_PARTMS8 041 /* Brahma: 8 bit page of 24 bit address */ +#define R_PARTLS7 050 /* DSP: 7 bit offset of 16 bit address */ +#define R_PARTMS9 051 /* DSP: 9 bit page of 16 bit address */ +#define R_REL13 052 /* DSP: 13 bits, direct */ + + +/*------------------------------------------------------------------------*/ +/* LINE NUMBER ENTRIES */ +/*------------------------------------------------------------------------*/ +struct lineno +{ + union + { + long l_symndx ; /* sym. table index of function name + iff l_lnno == 0 */ + long l_paddr ; /* (physical) address of line number */ + } l_addr ; + unsigned short l_lnno ; /* line number */ +}; + +#define LINENO struct lineno +#define LINESZ 6 /* sizeof(LINENO) */ + + +/*------------------------------------------------------------------------*/ +/* STORAGE CLASSES */ +/*------------------------------------------------------------------------*/ +#define C_EFCN -1 /* physical end of function */ +#define C_NULL 0 +#define C_AUTO 1 /* automatic variable */ +#define C_EXT 2 /* external symbol */ +#define C_STAT 3 /* static */ +#define C_REG 4 /* register variable */ +#define C_EXTDEF 5 /* external definition */ +#define C_LABEL 6 /* label */ +#define C_ULABEL 7 /* undefined label */ +#define C_MOS 8 /* member of structure */ +#define C_ARG 9 /* function argument */ +#define C_STRTAG 10 /* structure tag */ +#define C_MOU 11 /* member of union */ +#define C_UNTAG 12 /* union tag */ +#define C_TPDEF 13 /* type definition */ +#define C_USTATIC 14 /* undefined static */ +#define C_ENTAG 15 /* enumeration tag */ +#define C_MOE 16 /* member of enumeration */ +#define C_REGPARM 17 /* register parameter */ +#define C_FIELD 18 /* bit field */ + +#define C_BLOCK 100 /* ".bb" or ".eb" */ +#define C_FCN 101 /* ".bf" or ".ef" */ +#define C_EOS 102 /* end of structure */ +#define C_FILE 103 /* file name */ +#define C_LINE 104 /* dummy sclass for line number entry */ +#define C_ALIAS 105 /* duplicate tag */ +#define C_HIDDEN 106 /* special storage class for external */ + /* symbols in dmert public libraries */ + +/*------------------------------------------------------------------------*/ +/* SYMBOL TABLE ENTRIES */ +/*------------------------------------------------------------------------*/ + +#define SYMNMLEN 8 /* Number of characters in a symbol name */ +#define FILNMLEN 14 /* Number of characters in a file name */ +#define DIMNUM 4 /* Number of array dimensions in auxiliary entry */ + + +struct syment +{ + union + { + char _n_name[SYMNMLEN]; /* old COFF version */ + struct + { + long _n_zeroes; /* new == 0 */ + long _n_offset; /* offset into string table */ + } _n_n; + char *_n_nptr[2]; /* allows for overlaying */ + } _n; + long n_value; /* value of symbol */ + short n_scnum; /* section number */ + unsigned short n_type; /* type and derived type */ + char n_sclass; /* storage class */ + char n_numaux; /* number of aux. entries */ +}; + +#define n_name _n._n_name +#define n_nptr _n._n_nptr[1] +#define n_zeroes _n._n_n._n_zeroes +#define n_offset _n._n_n._n_offset + +/*------------------------------------------------------------------------*/ +/* Relocatable symbols have a section number of the */ +/* section in which they are defined. Otherwise, section */ +/* numbers have the following meanings: */ +/*------------------------------------------------------------------------*/ +#define N_UNDEF 0 /* undefined symbol */ +#define N_ABS -1 /* value of symbol is absolute */ +#define N_DEBUG -2 /* special debugging symbol */ +#define N_TV (unsigned short)-3 /* needs transfer vector (preload) */ +#define P_TV (unsigned short)-4 /* needs transfer vector (postload) */ + + +/*------------------------------------------------------------------------*/ +/* The fundamental type of a symbol packed into the low */ +/* 4 bits of the word. */ +/*------------------------------------------------------------------------*/ +#define _EF ".ef" + +#define T_NULL 0 /* no type info */ +#define T_ARG 1 /* function argument (only used by compiler) */ +#define T_CHAR 2 /* character */ +#define T_SHORT 3 /* short integer */ +#define T_INT 4 /* integer */ +#define T_LONG 5 /* long integer */ +#define T_FLOAT 6 /* floating point */ +#define T_DOUBLE 7 /* double word */ +#define T_STRUCT 8 /* structure */ +#define T_UNION 9 /* union */ +#define T_ENUM 10 /* enumeration */ +#define T_MOE 11 /* member of enumeration */ +#define T_UCHAR 12 /* unsigned character */ +#define T_USHORT 13 /* unsigned short */ +#define T_UINT 14 /* unsigned integer */ +#define T_ULONG 15 /* unsigned long */ + +/*------------------------------------------------------------------------*/ +/* derived types are: */ +/*------------------------------------------------------------------------*/ +#define DT_NON 0 /* no derived type */ +#define DT_PTR 1 /* pointer */ +#define DT_FCN 2 /* function */ +#define DT_ARY 3 /* array */ + +#define MKTYPE(basic, d1,d2,d3,d4,d5,d6) \ + ((basic) | ((d1) << 4) | ((d2) << 6) | ((d3) << 8) |\ + ((d4) << 10) | ((d5) << 12) | ((d6) << 14)) + +/*------------------------------------------------------------------------*/ +/* type packing constants and macros */ +/*------------------------------------------------------------------------*/ +#define N_BTMASK_COFF 017 +#define N_TMASK_COFF 060 +#define N_TMASK1_COFF 0300 +#define N_TMASK2_COFF 0360 +#define N_BTSHFT_COFF 4 +#define N_TSHIFT_COFF 2 + +#define BTYPE_COFF(x) ((x) & N_BTMASK_COFF) +#define ISINT(x) (((x) >= T_CHAR && (x) <= T_LONG) || \ + ((x) >= T_UCHAR && (x) <= T_ULONG) || (x) == T_ENUM) +#define ISFLT_COFF(x) ((x) == T_DOUBLE || (x) == T_FLOAT) +#define ISPTR_COFF(x) (((x) & N_TMASK_COFF) == (DT_PTR << N_BTSHFT_COFF)) +#define ISFCN_COFF(x) (((x) & N_TMASK_COFF) == (DT_FCN << N_BTSHFT_COFF)) +#define ISARY_COFF(x) (((x) & N_TMASK_COFF) == (DT_ARY << N_BTSHFT_COFF)) +#define ISTAG_COFF(x) ((x)==C_STRTAG || (x)==C_UNTAG || (x)==C_ENTAG) + +#define INCREF_COFF(x) ((((x)&~N_BTMASK_COFF)<>N_TSHIFT_COFF)&~N_BTMASK_COFF)|((x)&N_BTMASK_COFF)) + + +/*------------------------------------------------------------------------*/ +/* AUXILIARY SYMBOL ENTRY */ +/*------------------------------------------------------------------------*/ +union auxent +{ + struct + { + long x_tagndx; /* str, un, or enum tag indx */ + union + { + struct + { + unsigned short x_lnno; /* declaration line number */ + unsigned short x_size; /* str, union, array size */ + } x_lnsz; + long x_fsize; /* size of function */ + } x_misc; + union + { + struct /* if ISFCN, tag, or .bb */ + { + long x_lnnoptr; /* ptr to fcn line # */ + long x_endndx; /* entry ndx past block end */ + } x_fcn; + struct /* if ISARY, up to 4 dimen. */ + { + unsigned short x_dimen[DIMNUM]; + } x_ary; + } x_fcnary; + unsigned short x_regcount; /* number of registers used by func */ + } x_sym; + struct + { + char x_fname[FILNMLEN]; + } x_file; + struct + { + long x_scnlen; /* section length */ + unsigned short x_nreloc; /* number of relocation entries */ + unsigned short x_nlinno; /* number of line numbers */ + } x_scn; +}; + +#define SYMENT struct syment +#define SYMESZ 18 /* sizeof(SYMENT) */ + +#define AUXENT union auxent +#define AUXESZ 18 /* sizeof(AUXENT) */ + +/*------------------------------------------------------------------------*/ +/* NAMES OF "SPECIAL" SYMBOLS */ +/*------------------------------------------------------------------------*/ +#define _STEXT ".text" +#define _ETEXT "etext" +#define _SDATA ".data" +#define _EDATA "edata" +#define _SBSS ".bss" +#define _END "end" +#define _CINITPTR "cinit" + +/*--------------------------------------------------------------------------*/ +/* ENTRY POINT SYMBOLS */ +/*--------------------------------------------------------------------------*/ +#define _START "_start" +#define _MAIN "_main" + /* _CSTART "_c_int00" (defined in params.h) */ + + +#define _TVORIG "_tvorig" +#define _TORIGIN "_torigin" +#define _DORIGIN "_dorigin" + +#define _SORIGIN "_sorigin" diff --git a/tinyc/config.h b/tinyc/config.h new file mode 100644 index 000000000..a27c7484a --- /dev/null +++ b/tinyc/config.h @@ -0,0 +1,22 @@ +/* Modified to not rely on a configure script: */ +#define CONFIG_SYSROOT "" +#define TCC_VERSION "0.9.27" + +#if defined(WIN32) || defined(_WIN32) +# define TCC_TARGET_PE 1 +# define TCC_TARGET_I386 +# define CONFIG_TCCDIR "." +#elif defined(__i386__) +# define CONFIG_USE_LIBGCC +# define TCC_TARGET_I386 +# define CONFIG_TCCDIR "/usr/local/lib/tcc" +# define GCC_MAJOR 4 +# define HOST_I386 1 +#else +# define CONFIG_USE_LIBGCC +# define TCC_TARGET_X86_64 +# define CONFIG_TCCDIR "/usr/local/lib/tcc" +# define GCC_MAJOR 4 +# define HOST_X86_64 1 +#endif + diff --git a/tinyc/conftest.c b/tinyc/conftest.c new file mode 100644 index 000000000..2824cc89d --- /dev/null +++ b/tinyc/conftest.c @@ -0,0 +1,87 @@ +#include + +/* Define architecture */ +#if defined(__i386__) || defined _M_IX86 +# define TRIPLET_ARCH "i386" +#elif defined(__x86_64__) || defined _M_AMD64 +# define TRIPLET_ARCH "x86_64" +#elif defined(__arm__) +# define TRIPLET_ARCH "arm" +#elif defined(__aarch64__) +# define TRIPLET_ARCH "aarch64" +#else +# define TRIPLET_ARCH "unknown" +#endif + +/* Define OS */ +#if defined (__linux__) +# define TRIPLET_OS "linux" +#elif defined (__FreeBSD__) || defined (__FreeBSD_kernel__) +# define TRIPLET_OS "kfreebsd" +#elif defined _WIN32 +# define TRIPLET_OS "win32" +#elif !defined (__GNU__) +# define TRIPLET_OS "unknown" +#endif + +/* Define calling convention and ABI */ +#if defined (__ARM_EABI__) +# if defined (__ARM_PCS_VFP) +# define TRIPLET_ABI "gnueabihf" +# else +# define TRIPLET_ABI "gnueabi" +# endif +#else +# define TRIPLET_ABI "gnu" +#endif + +#if defined _WIN32 +# define TRIPLET TRIPLET_ARCH "-" TRIPLET_OS +#elif defined __GNU__ +# define TRIPLET TRIPLET_ARCH "-" TRIPLET_ABI +#else +# define TRIPLET TRIPLET_ARCH "-" TRIPLET_OS "-" TRIPLET_ABI +#endif + +#if defined(_WIN32) +int _CRT_glob = 0; +#endif + +int main(int argc, char *argv[]) +{ + switch(argc == 2 ? argv[1][0] : 0) { + case 'b': + { + volatile unsigned foo = 0x01234567; + puts(*(unsigned char*)&foo == 0x67 ? "no" : "yes"); + break; + } +#ifdef __GNUC__ + case 'm': + printf("%d\n", __GNUC_MINOR__); + break; + case 'v': + printf("%d\n", __GNUC__); + break; +#elif defined __TINYC__ + case 'v': + puts("0"); + break; + case 'm': + printf("%d\n", __TINYC__); + break; +#else + case 'm': + case 'v': + puts("0"); + break; +#endif + case 't': + puts(TRIPLET); + break; + + default: + break; + } + return 0; +} diff --git a/tinyc/elf.h b/tinyc/elf.h new file mode 100644 index 000000000..9fed6eb73 --- /dev/null +++ b/tinyc/elf.h @@ -0,0 +1,3237 @@ +/* This file defines standard ELF types, structures, and macros. + Copyright (C) 1995-2012 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#ifndef _ELF_H +#define _ELF_H 1 + +#ifndef _WIN32 +#include +#else +#ifndef __int8_t_defined +#define __int8_t_defined +typedef signed char int8_t; +typedef short int int16_t; +typedef int int32_t; +typedef long long int int64_t; +typedef unsigned char uint8_t; +typedef unsigned short int uint16_t; +typedef unsigned int uint32_t; +typedef unsigned long long int uint64_t; +#endif +#endif + +/* Standard ELF types. */ + +/* Type for a 16-bit quantity. */ +typedef uint16_t Elf32_Half; +typedef uint16_t Elf64_Half; + +/* Types for signed and unsigned 32-bit quantities. */ +typedef uint32_t Elf32_Word; +typedef int32_t Elf32_Sword; +typedef uint32_t Elf64_Word; +typedef int32_t Elf64_Sword; + +/* Types for signed and unsigned 64-bit quantities. */ +typedef uint64_t Elf32_Xword; +typedef int64_t Elf32_Sxword; +typedef uint64_t Elf64_Xword; +typedef int64_t Elf64_Sxword; + +/* Type of addresses. */ +typedef uint32_t Elf32_Addr; +typedef uint64_t Elf64_Addr; + +/* Type of file offsets. */ +typedef uint32_t Elf32_Off; +typedef uint64_t Elf64_Off; + +/* Type for section indices, which are 16-bit quantities. */ +typedef uint16_t Elf32_Section; +typedef uint16_t Elf64_Section; + +/* Type for version symbol information. */ +typedef Elf32_Half Elf32_Versym; +typedef Elf64_Half Elf64_Versym; + + +/* The ELF file header. This appears at the start of every ELF file. */ + +#define EI_NIDENT (16) + +typedef struct +{ + unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */ + Elf32_Half e_type; /* Object file type */ + Elf32_Half e_machine; /* Architecture */ + Elf32_Word e_version; /* Object file version */ + Elf32_Addr e_entry; /* Entry point virtual address */ + Elf32_Off e_phoff; /* Program header table file offset */ + Elf32_Off e_shoff; /* Section header table file offset */ + Elf32_Word e_flags; /* Processor-specific flags */ + Elf32_Half e_ehsize; /* ELF header size in bytes */ + Elf32_Half e_phentsize; /* Program header table entry size */ + Elf32_Half e_phnum; /* Program header table entry count */ + Elf32_Half e_shentsize; /* Section header table entry size */ + Elf32_Half e_shnum; /* Section header table entry count */ + Elf32_Half e_shstrndx; /* Section header string table index */ +} Elf32_Ehdr; + +typedef struct +{ + unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */ + Elf64_Half e_type; /* Object file type */ + Elf64_Half e_machine; /* Architecture */ + Elf64_Word e_version; /* Object file version */ + Elf64_Addr e_entry; /* Entry point virtual address */ + Elf64_Off e_phoff; /* Program header table file offset */ + Elf64_Off e_shoff; /* Section header table file offset */ + Elf64_Word e_flags; /* Processor-specific flags */ + Elf64_Half e_ehsize; /* ELF header size in bytes */ + Elf64_Half e_phentsize; /* Program header table entry size */ + Elf64_Half e_phnum; /* Program header table entry count */ + Elf64_Half e_shentsize; /* Section header table entry size */ + Elf64_Half e_shnum; /* Section header table entry count */ + Elf64_Half e_shstrndx; /* Section header string table index */ +} Elf64_Ehdr; + +/* Fields in the e_ident array. The EI_* macros are indices into the + array. The macros under each EI_* macro are the values the byte + may have. */ + +#define EI_MAG0 0 /* File identification byte 0 index */ +#define ELFMAG0 0x7f /* Magic number byte 0 */ + +#define EI_MAG1 1 /* File identification byte 1 index */ +#define ELFMAG1 'E' /* Magic number byte 1 */ + +#define EI_MAG2 2 /* File identification byte 2 index */ +#define ELFMAG2 'L' /* Magic number byte 2 */ + +#define EI_MAG3 3 /* File identification byte 3 index */ +#define ELFMAG3 'F' /* Magic number byte 3 */ + +/* Conglomeration of the identification bytes, for easy testing as a word. */ +#define ELFMAG "\177ELF" +#define SELFMAG 4 + +#define EI_CLASS 4 /* File class byte index */ +#define ELFCLASSNONE 0 /* Invalid class */ +#define ELFCLASS32 1 /* 32-bit objects */ +#define ELFCLASS64 2 /* 64-bit objects */ +#define ELFCLASSNUM 3 + +#define EI_DATA 5 /* Data encoding byte index */ +#define ELFDATANONE 0 /* Invalid data encoding */ +#define ELFDATA2LSB 1 /* 2's complement, little endian */ +#define ELFDATA2MSB 2 /* 2's complement, big endian */ +#define ELFDATANUM 3 + +#define EI_VERSION 6 /* File version byte index */ + /* Value must be EV_CURRENT */ + +#define EI_OSABI 7 /* OS ABI identification */ +#define ELFOSABI_NONE 0 /* UNIX System V ABI */ +#define ELFOSABI_SYSV 0 /* Alias. */ +#define ELFOSABI_HPUX 1 /* HP-UX */ +#define ELFOSABI_NETBSD 2 /* NetBSD. */ +#define ELFOSABI_GNU 3 /* Object uses GNU ELF extensions. */ +#define ELFOSABI_LINUX ELFOSABI_GNU /* Compatibility alias. */ +#define ELFOSABI_SOLARIS 6 /* Sun Solaris. */ +#define ELFOSABI_AIX 7 /* IBM AIX. */ +#define ELFOSABI_IRIX 8 /* SGI Irix. */ +#define ELFOSABI_FREEBSD 9 /* FreeBSD. */ +#define ELFOSABI_TRU64 10 /* Compaq TRU64 UNIX. */ +#define ELFOSABI_MODESTO 11 /* Novell Modesto. */ +#define ELFOSABI_OPENBSD 12 /* OpenBSD. */ +#define ELFOSABI_ARM_AEABI 64 /* ARM EABI */ +#define ELFOSABI_ARM 97 /* ARM */ +#define ELFOSABI_STANDALONE 255 /* Standalone (embedded) application */ + +#define EI_ABIVERSION 8 /* ABI version */ + +#define EI_PAD 9 /* Byte index of padding bytes */ + +/* Legal values for e_type (object file type). */ + +#define ET_NONE 0 /* No file type */ +#define ET_REL 1 /* Relocatable file */ +#define ET_EXEC 2 /* Executable file */ +#define ET_DYN 3 /* Shared object file */ +#define ET_CORE 4 /* Core file */ +#define ET_NUM 5 /* Number of defined types */ +#define ET_LOOS 0xfe00 /* OS-specific range start */ +#define ET_HIOS 0xfeff /* OS-specific range end */ +#define ET_LOPROC 0xff00 /* Processor-specific range start */ +#define ET_HIPROC 0xffff /* Processor-specific range end */ + +/* Legal values for e_machine (architecture). */ + +#define EM_NONE 0 /* No machine */ +#define EM_M32 1 /* AT&T WE 32100 */ +#define EM_SPARC 2 /* SUN SPARC */ +#define EM_386 3 /* Intel 80386 */ +#define EM_68K 4 /* Motorola m68k family */ +#define EM_88K 5 /* Motorola m88k family */ +#define EM_860 7 /* Intel 80860 */ +#define EM_MIPS 8 /* MIPS R3000 big-endian */ +#define EM_S370 9 /* IBM System/370 */ +#define EM_MIPS_RS3_LE 10 /* MIPS R3000 little-endian */ + +#define EM_PARISC 15 /* HPPA */ +#define EM_VPP500 17 /* Fujitsu VPP500 */ +#define EM_SPARC32PLUS 18 /* Sun's "v8plus" */ +#define EM_960 19 /* Intel 80960 */ +#define EM_PPC 20 /* PowerPC */ +#define EM_PPC64 21 /* PowerPC 64-bit */ +#define EM_S390 22 /* IBM S390 */ + +#define EM_V800 36 /* NEC V800 series */ +#define EM_FR20 37 /* Fujitsu FR20 */ +#define EM_RH32 38 /* TRW RH-32 */ +#define EM_RCE 39 /* Motorola RCE */ +#define EM_ARM 40 /* ARM */ +#define EM_FAKE_ALPHA 41 /* Digital Alpha */ +#define EM_SH 42 /* Hitachi SH */ +#define EM_SPARCV9 43 /* SPARC v9 64-bit */ +#define EM_TRICORE 44 /* Siemens Tricore */ +#define EM_ARC 45 /* Argonaut RISC Core */ +#define EM_H8_300 46 /* Hitachi H8/300 */ +#define EM_H8_300H 47 /* Hitachi H8/300H */ +#define EM_H8S 48 /* Hitachi H8S */ +#define EM_H8_500 49 /* Hitachi H8/500 */ +#define EM_IA_64 50 /* Intel Merced */ +#define EM_MIPS_X 51 /* Stanford MIPS-X */ +#define EM_COLDFIRE 52 /* Motorola Coldfire */ +#define EM_68HC12 53 /* Motorola M68HC12 */ +#define EM_MMA 54 /* Fujitsu MMA Multimedia Accelerator*/ +#define EM_PCP 55 /* Siemens PCP */ +#define EM_NCPU 56 /* Sony nCPU embedded RISC */ +#define EM_NDR1 57 /* Denso NDR1 microprocessor */ +#define EM_STARCORE 58 /* Motorola Start*Core processor */ +#define EM_ME16 59 /* Toyota ME16 processor */ +#define EM_ST100 60 /* STMicroelectronic ST100 processor */ +#define EM_TINYJ 61 /* Advanced Logic Corp. Tinyj emb.fam*/ +#define EM_X86_64 62 /* AMD x86-64 architecture */ +#define EM_PDSP 63 /* Sony DSP Processor */ + +#define EM_FX66 66 /* Siemens FX66 microcontroller */ +#define EM_ST9PLUS 67 /* STMicroelectronics ST9+ 8/16 mc */ +#define EM_ST7 68 /* STMicroelectronics ST7 8 bit mc */ +#define EM_68HC16 69 /* Motorola MC68HC16 microcontroller */ +#define EM_68HC11 70 /* Motorola MC68HC11 microcontroller */ +#define EM_68HC08 71 /* Motorola MC68HC08 microcontroller */ +#define EM_68HC05 72 /* Motorola MC68HC05 microcontroller */ +#define EM_SVX 73 /* Silicon Graphics SVx */ +#define EM_ST19 74 /* STMicroelectronics ST19 8 bit mc */ +#define EM_VAX 75 /* Digital VAX */ +#define EM_CRIS 76 /* Axis Communications 32-bit embedded processor */ +#define EM_JAVELIN 77 /* Infineon Technologies 32-bit embedded processor */ +#define EM_FIREPATH 78 /* Element 14 64-bit DSP Processor */ +#define EM_ZSP 79 /* LSI Logic 16-bit DSP Processor */ +#define EM_MMIX 80 /* Donald Knuth's educational 64-bit processor */ +#define EM_HUANY 81 /* Harvard University machine-independent object files */ +#define EM_PRISM 82 /* SiTera Prism */ +#define EM_AVR 83 /* Atmel AVR 8-bit microcontroller */ +#define EM_FR30 84 /* Fujitsu FR30 */ +#define EM_D10V 85 /* Mitsubishi D10V */ +#define EM_D30V 86 /* Mitsubishi D30V */ +#define EM_V850 87 /* NEC v850 */ +#define EM_M32R 88 /* Mitsubishi M32R */ +#define EM_MN10300 89 /* Matsushita MN10300 */ +#define EM_MN10200 90 /* Matsushita MN10200 */ +#define EM_PJ 91 /* picoJava */ +#define EM_OPENRISC 92 /* OpenRISC 32-bit embedded processor */ +#define EM_ARC_A5 93 /* ARC Cores Tangent-A5 */ +#define EM_XTENSA 94 /* Tensilica Xtensa Architecture */ +#define EM_AARCH64 183 /* ARM AARCH64 */ +#define EM_TILEPRO 188 /* Tilera TILEPro */ +#define EM_TILEGX 191 /* Tilera TILE-Gx */ +#define EM_NUM 192 + +/* If it is necessary to assign new unofficial EM_* values, please + pick large random numbers (0x8523, 0xa7f2, etc.) to minimize the + chances of collision with official or non-GNU unofficial values. */ + +#define EM_ALPHA 0x9026 +#define EM_C60 0x9c60 + +/* Legal values for e_version (version). */ + +#define EV_NONE 0 /* Invalid ELF version */ +#define EV_CURRENT 1 /* Current version */ +#define EV_NUM 2 + +/* Section header. */ + +typedef struct +{ + Elf32_Word sh_name; /* Section name (string tbl index) */ + Elf32_Word sh_type; /* Section type */ + Elf32_Word sh_flags; /* Section flags */ + Elf32_Addr sh_addr; /* Section virtual addr at execution */ + Elf32_Off sh_offset; /* Section file offset */ + Elf32_Word sh_size; /* Section size in bytes */ + Elf32_Word sh_link; /* Link to another section */ + Elf32_Word sh_info; /* Additional section information */ + Elf32_Word sh_addralign; /* Section alignment */ + Elf32_Word sh_entsize; /* Entry size if section holds table */ +} Elf32_Shdr; + +typedef struct +{ + Elf64_Word sh_name; /* Section name (string tbl index) */ + Elf64_Word sh_type; /* Section type */ + Elf64_Xword sh_flags; /* Section flags */ + Elf64_Addr sh_addr; /* Section virtual addr at execution */ + Elf64_Off sh_offset; /* Section file offset */ + Elf64_Xword sh_size; /* Section size in bytes */ + Elf64_Word sh_link; /* Link to another section */ + Elf64_Word sh_info; /* Additional section information */ + Elf64_Xword sh_addralign; /* Section alignment */ + Elf64_Xword sh_entsize; /* Entry size if section holds table */ +} Elf64_Shdr; + +/* Special section indices. */ + +#define SHN_UNDEF 0 /* Undefined section */ +#define SHN_LORESERVE 0xff00 /* Start of reserved indices */ +#define SHN_LOPROC 0xff00 /* Start of processor-specific */ +#define SHN_BEFORE 0xff00 /* Order section before all others + (Solaris). */ +#define SHN_AFTER 0xff01 /* Order section after all others + (Solaris). */ +#define SHN_HIPROC 0xff1f /* End of processor-specific */ +#define SHN_LOOS 0xff20 /* Start of OS-specific */ +#define SHN_HIOS 0xff3f /* End of OS-specific */ +#define SHN_ABS 0xfff1 /* Associated symbol is absolute */ +#define SHN_COMMON 0xfff2 /* Associated symbol is common */ +#define SHN_XINDEX 0xffff /* Index is in extra table. */ +#define SHN_HIRESERVE 0xffff /* End of reserved indices */ + +/* Legal values for sh_type (section type). */ + +#define SHT_NULL 0 /* Section header table entry unused */ +#define SHT_PROGBITS 1 /* Program data */ +#define SHT_SYMTAB 2 /* Symbol table */ +#define SHT_STRTAB 3 /* String table */ +#define SHT_RELA 4 /* Relocation entries with addends */ +#define SHT_HASH 5 /* Symbol hash table */ +#define SHT_DYNAMIC 6 /* Dynamic linking information */ +#define SHT_NOTE 7 /* Notes */ +#define SHT_NOBITS 8 /* Program space with no data (bss) */ +#define SHT_REL 9 /* Relocation entries, no addends */ +#define SHT_SHLIB 10 /* Reserved */ +#define SHT_DYNSYM 11 /* Dynamic linker symbol table */ +#define SHT_INIT_ARRAY 14 /* Array of constructors */ +#define SHT_FINI_ARRAY 15 /* Array of destructors */ +#define SHT_PREINIT_ARRAY 16 /* Array of pre-constructors */ +#define SHT_GROUP 17 /* Section group */ +#define SHT_SYMTAB_SHNDX 18 /* Extended section indices */ +#define SHT_NUM 19 /* Number of defined types. */ +#define SHT_LOOS 0x60000000 /* Start OS-specific. */ +#define SHT_GNU_ATTRIBUTES 0x6ffffff5 /* Object attributes. */ +#define SHT_GNU_HASH 0x6ffffff6 /* GNU-style hash table. */ +#define SHT_GNU_LIBLIST 0x6ffffff7 /* Prelink library list */ +#define SHT_CHECKSUM 0x6ffffff8 /* Checksum for DSO content. */ +#define SHT_LOSUNW 0x6ffffffa /* Sun-specific low bound. */ +#define SHT_SUNW_move 0x6ffffffa +#define SHT_SUNW_COMDAT 0x6ffffffb +#define SHT_SUNW_syminfo 0x6ffffffc +#define SHT_GNU_verdef 0x6ffffffd /* Version definition section. */ +#define SHT_GNU_verneed 0x6ffffffe /* Version needs section. */ +#define SHT_GNU_versym 0x6fffffff /* Version symbol table. */ +#define SHT_HISUNW 0x6fffffff /* Sun-specific high bound. */ +#define SHT_HIOS 0x6fffffff /* End OS-specific type */ +#define SHT_LOPROC 0x70000000 /* Start of processor-specific */ +#define SHT_HIPROC 0x7fffffff /* End of processor-specific */ +#define SHT_LOUSER 0x80000000 /* Start of application-specific */ +#define SHT_HIUSER 0x8fffffff /* End of application-specific */ + +/* Legal values for sh_flags (section flags). */ + +#define SHF_WRITE (1 << 0) /* Writable */ +#define SHF_ALLOC (1 << 1) /* Occupies memory during execution */ +#define SHF_EXECINSTR (1 << 2) /* Executable */ +#define SHF_MERGE (1 << 4) /* Might be merged */ +#define SHF_STRINGS (1 << 5) /* Contains nul-terminated strings */ +#define SHF_INFO_LINK (1 << 6) /* `sh_info' contains SHT index */ +#define SHF_LINK_ORDER (1 << 7) /* Preserve order after combining */ +#define SHF_OS_NONCONFORMING (1 << 8) /* Non-standard OS specific handling + required */ +#define SHF_GROUP (1 << 9) /* Section is member of a group. */ +#define SHF_TLS (1 << 10) /* Section hold thread-local data. */ +#define SHF_COMPRESSED (1 << 11) /* Section with compressed data. */ +#define SHF_MASKOS 0x0ff00000 /* OS-specific. */ +#define SHF_MASKPROC 0xf0000000 /* Processor-specific */ +#define SHF_ORDERED (1 << 30) /* Special ordering requirement + (Solaris). */ +#define SHF_EXCLUDE (1 << 31) /* Section is excluded unless + referenced or allocated (Solaris).*/ + +/* Section group handling. */ +#define GRP_COMDAT 0x1 /* Mark group as COMDAT. */ + +/* Symbol table entry. */ + +typedef struct +{ + Elf32_Word st_name; /* Symbol name (string tbl index) */ + Elf32_Addr st_value; /* Symbol value */ + Elf32_Word st_size; /* Symbol size */ + unsigned char st_info; /* Symbol type and binding */ + unsigned char st_other; /* Symbol visibility */ + Elf32_Section st_shndx; /* Section index */ +} Elf32_Sym; + +typedef struct +{ + Elf64_Word st_name; /* Symbol name (string tbl index) */ + unsigned char st_info; /* Symbol type and binding */ + unsigned char st_other; /* Symbol visibility */ + Elf64_Section st_shndx; /* Section index */ + Elf64_Addr st_value; /* Symbol value */ + Elf64_Xword st_size; /* Symbol size */ +} Elf64_Sym; + +/* The syminfo section if available contains additional information about + every dynamic symbol. */ + +typedef struct +{ + Elf32_Half si_boundto; /* Direct bindings, symbol bound to */ + Elf32_Half si_flags; /* Per symbol flags */ +} Elf32_Syminfo; + +typedef struct +{ + Elf64_Half si_boundto; /* Direct bindings, symbol bound to */ + Elf64_Half si_flags; /* Per symbol flags */ +} Elf64_Syminfo; + +/* Possible values for si_boundto. */ +#define SYMINFO_BT_SELF 0xffff /* Symbol bound to self */ +#define SYMINFO_BT_PARENT 0xfffe /* Symbol bound to parent */ +#define SYMINFO_BT_LOWRESERVE 0xff00 /* Beginning of reserved entries */ + +/* Possible bitmasks for si_flags. */ +#define SYMINFO_FLG_DIRECT 0x0001 /* Direct bound symbol */ +#define SYMINFO_FLG_PASSTHRU 0x0002 /* Pass-thru symbol for translator */ +#define SYMINFO_FLG_COPY 0x0004 /* Symbol is a copy-reloc */ +#define SYMINFO_FLG_LAZYLOAD 0x0008 /* Symbol bound to object to be lazy + loaded */ +/* Syminfo version values. */ +#define SYMINFO_NONE 0 +#define SYMINFO_CURRENT 1 +#define SYMINFO_NUM 2 + + +/* How to extract and insert information held in the st_info field. */ + +#define ELF32_ST_BIND(val) (((unsigned char) (val)) >> 4) +#define ELF32_ST_TYPE(val) ((val) & 0xf) +#define ELF32_ST_INFO(bind, type) (((bind) << 4) + ((type) & 0xf)) + +/* Both Elf32_Sym and Elf64_Sym use the same one-byte st_info field. */ +#define ELF64_ST_BIND(val) ELF32_ST_BIND (val) +#define ELF64_ST_TYPE(val) ELF32_ST_TYPE (val) +#define ELF64_ST_INFO(bind, type) ELF32_ST_INFO ((bind), (type)) + +/* Legal values for ST_BIND subfield of st_info (symbol binding). */ + +#define STB_LOCAL 0 /* Local symbol */ +#define STB_GLOBAL 1 /* Global symbol */ +#define STB_WEAK 2 /* Weak symbol */ +#define STB_NUM 3 /* Number of defined types. */ +#define STB_LOOS 10 /* Start of OS-specific */ +#define STB_GNU_UNIQUE 10 /* Unique symbol. */ +#define STB_HIOS 12 /* End of OS-specific */ +#define STB_LOPROC 13 /* Start of processor-specific */ +#define STB_HIPROC 15 /* End of processor-specific */ + +/* Legal values for ST_TYPE subfield of st_info (symbol type). */ + +#define STT_NOTYPE 0 /* Symbol type is unspecified */ +#define STT_OBJECT 1 /* Symbol is a data object */ +#define STT_FUNC 2 /* Symbol is a code object */ +#define STT_SECTION 3 /* Symbol associated with a section */ +#define STT_FILE 4 /* Symbol's name is file name */ +#define STT_COMMON 5 /* Symbol is a common data object */ +#define STT_TLS 6 /* Symbol is thread-local data object*/ +#define STT_NUM 7 /* Number of defined types. */ +#define STT_LOOS 10 /* Start of OS-specific */ +#define STT_GNU_IFUNC 10 /* Symbol is indirect code object */ +#define STT_HIOS 12 /* End of OS-specific */ +#define STT_LOPROC 13 /* Start of processor-specific */ +#define STT_HIPROC 15 /* End of processor-specific */ + + +/* Symbol table indices are found in the hash buckets and chain table + of a symbol hash table section. This special index value indicates + the end of a chain, meaning no further symbols are found in that bucket. */ + +#define STN_UNDEF 0 /* End of a chain. */ + + +/* How to extract and insert information held in the st_other field. */ + +#define ELF32_ST_VISIBILITY(o) ((o) & 0x03) + +/* For ELF64 the definitions are the same. */ +#define ELF64_ST_VISIBILITY(o) ELF32_ST_VISIBILITY (o) + +/* Symbol visibility specification encoded in the st_other field. */ +#define STV_DEFAULT 0 /* Default symbol visibility rules */ +#define STV_INTERNAL 1 /* Processor specific hidden class */ +#define STV_HIDDEN 2 /* Sym unavailable in other modules */ +#define STV_PROTECTED 3 /* Not preemptible, not exported */ + + +/* Relocation table entry without addend (in section of type SHT_REL). */ + +typedef struct +{ + Elf32_Addr r_offset; /* Address */ + Elf32_Word r_info; /* Relocation type and symbol index */ +} Elf32_Rel; + +/* I have seen two different definitions of the Elf64_Rel and + Elf64_Rela structures, so we'll leave them out until Novell (or + whoever) gets their act together. */ +/* The following, at least, is used on Sparc v9, MIPS, and Alpha. */ + +typedef struct +{ + Elf64_Addr r_offset; /* Address */ + Elf64_Xword r_info; /* Relocation type and symbol index */ +} Elf64_Rel; + +/* Relocation table entry with addend (in section of type SHT_RELA). */ + +typedef struct +{ + Elf32_Addr r_offset; /* Address */ + Elf32_Word r_info; /* Relocation type and symbol index */ + Elf32_Sword r_addend; /* Addend */ +} Elf32_Rela; + +typedef struct +{ + Elf64_Addr r_offset; /* Address */ + Elf64_Xword r_info; /* Relocation type and symbol index */ + Elf64_Sxword r_addend; /* Addend */ +} Elf64_Rela; + +/* How to extract and insert information held in the r_info field. */ + +#define ELF32_R_SYM(val) ((val) >> 8) +#define ELF32_R_TYPE(val) ((val) & 0xff) +#define ELF32_R_INFO(sym, type) (((sym) << 8) + ((type) & 0xff)) + +#define ELF64_R_SYM(i) ((i) >> 32) +#define ELF64_R_TYPE(i) ((i) & 0xffffffff) +#define ELF64_R_INFO(sym,type) ((((Elf64_Xword) (sym)) << 32) + (type)) + +/* Program segment header. */ + +typedef struct +{ + Elf32_Word p_type; /* Segment type */ + Elf32_Off p_offset; /* Segment file offset */ + Elf32_Addr p_vaddr; /* Segment virtual address */ + Elf32_Addr p_paddr; /* Segment physical address */ + Elf32_Word p_filesz; /* Segment size in file */ + Elf32_Word p_memsz; /* Segment size in memory */ + Elf32_Word p_flags; /* Segment flags */ + Elf32_Word p_align; /* Segment alignment */ +} Elf32_Phdr; + +typedef struct +{ + Elf64_Word p_type; /* Segment type */ + Elf64_Word p_flags; /* Segment flags */ + Elf64_Off p_offset; /* Segment file offset */ + Elf64_Addr p_vaddr; /* Segment virtual address */ + Elf64_Addr p_paddr; /* Segment physical address */ + Elf64_Xword p_filesz; /* Segment size in file */ + Elf64_Xword p_memsz; /* Segment size in memory */ + Elf64_Xword p_align; /* Segment alignment */ +} Elf64_Phdr; + +/* Special value for e_phnum. This indicates that the real number of + program headers is too large to fit into e_phnum. Instead the real + value is in the field sh_info of section 0. */ + +#define PN_XNUM 0xffff + +/* Legal values for p_type (segment type). */ + +#define PT_NULL 0 /* Program header table entry unused */ +#define PT_LOAD 1 /* Loadable program segment */ +#define PT_DYNAMIC 2 /* Dynamic linking information */ +#define PT_INTERP 3 /* Program interpreter */ +#define PT_NOTE 4 /* Auxiliary information */ +#define PT_SHLIB 5 /* Reserved */ +#define PT_PHDR 6 /* Entry for header table itself */ +#define PT_TLS 7 /* Thread-local storage segment */ +#define PT_NUM 8 /* Number of defined types */ +#define PT_LOOS 0x60000000 /* Start of OS-specific */ +#define PT_GNU_EH_FRAME 0x6474e550 /* GCC .eh_frame_hdr segment */ +#define PT_GNU_STACK 0x6474e551 /* Indicates stack executability */ +#define PT_GNU_RELRO 0x6474e552 /* Read-only after relocation */ +#define PT_LOSUNW 0x6ffffffa +#define PT_SUNWBSS 0x6ffffffa /* Sun Specific segment */ +#define PT_SUNWSTACK 0x6ffffffb /* Stack segment */ +#define PT_HISUNW 0x6fffffff +#define PT_HIOS 0x6fffffff /* End of OS-specific */ +#define PT_LOPROC 0x70000000 /* Start of processor-specific */ +#define PT_HIPROC 0x7fffffff /* End of processor-specific */ + +/* Legal values for p_flags (segment flags). */ + +#define PF_X (1 << 0) /* Segment is executable */ +#define PF_W (1 << 1) /* Segment is writable */ +#define PF_R (1 << 2) /* Segment is readable */ +#define PF_MASKOS 0x0ff00000 /* OS-specific */ +#define PF_MASKPROC 0xf0000000 /* Processor-specific */ + +/* Legal values for note segment descriptor types for core files. */ + +#define NT_PRSTATUS 1 /* Contains copy of prstatus struct */ +#define NT_FPREGSET 2 /* Contains copy of fpregset struct */ +#define NT_PRPSINFO 3 /* Contains copy of prpsinfo struct */ +#define NT_PRXREG 4 /* Contains copy of prxregset struct */ +#define NT_TASKSTRUCT 4 /* Contains copy of task structure */ +#define NT_PLATFORM 5 /* String from sysinfo(SI_PLATFORM) */ +#define NT_AUXV 6 /* Contains copy of auxv array */ +#define NT_GWINDOWS 7 /* Contains copy of gwindows struct */ +#define NT_ASRS 8 /* Contains copy of asrset struct */ +#define NT_PSTATUS 10 /* Contains copy of pstatus struct */ +#define NT_PSINFO 13 /* Contains copy of psinfo struct */ +#define NT_PRCRED 14 /* Contains copy of prcred struct */ +#define NT_UTSNAME 15 /* Contains copy of utsname struct */ +#define NT_LWPSTATUS 16 /* Contains copy of lwpstatus struct */ +#define NT_LWPSINFO 17 /* Contains copy of lwpinfo struct */ +#define NT_PRFPXREG 20 /* Contains copy of fprxregset struct */ +#define NT_PRXFPREG 0x46e62b7f /* Contains copy of user_fxsr_struct */ +#define NT_PPC_VMX 0x100 /* PowerPC Altivec/VMX registers */ +#define NT_PPC_SPE 0x101 /* PowerPC SPE/EVR registers */ +#define NT_PPC_VSX 0x102 /* PowerPC VSX registers */ +#define NT_386_TLS 0x200 /* i386 TLS slots (struct user_desc) */ +#define NT_386_IOPERM 0x201 /* x86 io permission bitmap (1=deny) */ +#define NT_X86_XSTATE 0x202 /* x86 extended state using xsave */ +#define NT_S390_HIGH_GPRS 0x300 /* s390 upper register halves */ +#define NT_S390_TIMER 0x301 /* s390 timer register */ +#define NT_S390_TODCMP 0x302 /* s390 TOD clock comparator register */ +#define NT_S390_TODPREG 0x303 /* s390 TOD programmable register */ +#define NT_S390_CTRS 0x304 /* s390 control registers */ +#define NT_S390_PREFIX 0x305 /* s390 prefix register */ +#define NT_S390_LAST_BREAK 0x306 /* s390 breaking event address */ +#define NT_S390_SYSTEM_CALL 0x307 /* s390 system call restart data */ +#define NT_ARM_VFP 0x400 /* ARM VFP/NEON registers */ +#define NT_ARM_TLS 0x401 /* ARM TLS register */ +#define NT_ARM_HW_BREAK 0x402 /* ARM hardware breakpoint registers */ +#define NT_ARM_HW_WATCH 0x403 /* ARM hardware watchpoint registers */ + +/* Legal values for the note segment descriptor types for object files. */ + +#define NT_VERSION 1 /* Contains a version string. */ + + +/* Dynamic section entry. */ + +typedef struct +{ + Elf32_Sword d_tag; /* Dynamic entry type */ + union + { + Elf32_Word d_val; /* Integer value */ + Elf32_Addr d_ptr; /* Address value */ + } d_un; +} Elf32_Dyn; + +typedef struct +{ + Elf64_Sxword d_tag; /* Dynamic entry type */ + union + { + Elf64_Xword d_val; /* Integer value */ + Elf64_Addr d_ptr; /* Address value */ + } d_un; +} Elf64_Dyn; + +/* Legal values for d_tag (dynamic entry type). */ + +#define DT_NULL 0 /* Marks end of dynamic section */ +#define DT_NEEDED 1 /* Name of needed library */ +#define DT_PLTRELSZ 2 /* Size in bytes of PLT relocs */ +#define DT_PLTGOT 3 /* Processor defined value */ +#define DT_HASH 4 /* Address of symbol hash table */ +#define DT_STRTAB 5 /* Address of string table */ +#define DT_SYMTAB 6 /* Address of symbol table */ +#define DT_RELA 7 /* Address of Rela relocs */ +#define DT_RELASZ 8 /* Total size of Rela relocs */ +#define DT_RELAENT 9 /* Size of one Rela reloc */ +#define DT_STRSZ 10 /* Size of string table */ +#define DT_SYMENT 11 /* Size of one symbol table entry */ +#define DT_INIT 12 /* Address of init function */ +#define DT_FINI 13 /* Address of termination function */ +#define DT_SONAME 14 /* Name of shared object */ +#define DT_RPATH 15 /* Library search path (deprecated) */ +#define DT_SYMBOLIC 16 /* Start symbol search here */ +#define DT_REL 17 /* Address of Rel relocs */ +#define DT_RELSZ 18 /* Total size of Rel relocs */ +#define DT_RELENT 19 /* Size of one Rel reloc */ +#define DT_PLTREL 20 /* Type of reloc in PLT */ +#define DT_DEBUG 21 /* For debugging; unspecified */ +#define DT_TEXTREL 22 /* Reloc might modify .text */ +#define DT_JMPREL 23 /* Address of PLT relocs */ +#define DT_BIND_NOW 24 /* Process relocations of object */ +#define DT_INIT_ARRAY 25 /* Array with addresses of init fct */ +#define DT_FINI_ARRAY 26 /* Array with addresses of fini fct */ +#define DT_INIT_ARRAYSZ 27 /* Size in bytes of DT_INIT_ARRAY */ +#define DT_FINI_ARRAYSZ 28 /* Size in bytes of DT_FINI_ARRAY */ +#define DT_RUNPATH 29 /* Library search path */ +#define DT_FLAGS 30 /* Flags for the object being loaded */ +#define DT_ENCODING 32 /* Start of encoded range */ +#define DT_PREINIT_ARRAY 32 /* Array with addresses of preinit fct*/ +#define DT_PREINIT_ARRAYSZ 33 /* size in bytes of DT_PREINIT_ARRAY */ +#define DT_NUM 34 /* Number used */ +#define DT_LOOS 0x6000000d /* Start of OS-specific */ +#define DT_HIOS 0x6ffff000 /* End of OS-specific */ +#define DT_LOPROC 0x70000000 /* Start of processor-specific */ +#define DT_HIPROC 0x7fffffff /* End of processor-specific */ +#define DT_PROCNUM DT_MIPS_NUM /* Most used by any processor */ + +/* DT_* entries which fall between DT_VALRNGHI & DT_VALRNGLO use the + Dyn.d_un.d_val field of the Elf*_Dyn structure. This follows Sun's + approach. */ +#define DT_VALRNGLO 0x6ffffd00 +#define DT_GNU_PRELINKED 0x6ffffdf5 /* Prelinking timestamp */ +#define DT_GNU_CONFLICTSZ 0x6ffffdf6 /* Size of conflict section */ +#define DT_GNU_LIBLISTSZ 0x6ffffdf7 /* Size of library list */ +#define DT_CHECKSUM 0x6ffffdf8 +#define DT_PLTPADSZ 0x6ffffdf9 +#define DT_MOVEENT 0x6ffffdfa +#define DT_MOVESZ 0x6ffffdfb +#define DT_FEATURE_1 0x6ffffdfc /* Feature selection (DTF_*). */ +#define DT_POSFLAG_1 0x6ffffdfd /* Flags for DT_* entries, effecting + the following DT_* entry. */ +#define DT_SYMINSZ 0x6ffffdfe /* Size of syminfo table (in bytes) */ +#define DT_SYMINENT 0x6ffffdff /* Entry size of syminfo */ +#define DT_VALRNGHI 0x6ffffdff +#define DT_VALTAGIDX(tag) (DT_VALRNGHI - (tag)) /* Reverse order! */ +#define DT_VALNUM 12 + +/* DT_* entries which fall between DT_ADDRRNGHI & DT_ADDRRNGLO use the + Dyn.d_un.d_ptr field of the Elf*_Dyn structure. + + If any adjustment is made to the ELF object after it has been + built these entries will need to be adjusted. */ +#define DT_ADDRRNGLO 0x6ffffe00 +#define DT_GNU_HASH 0x6ffffef5 /* GNU-style hash table. */ +#define DT_TLSDESC_PLT 0x6ffffef6 +#define DT_TLSDESC_GOT 0x6ffffef7 +#define DT_GNU_CONFLICT 0x6ffffef8 /* Start of conflict section */ +#define DT_GNU_LIBLIST 0x6ffffef9 /* Library list */ +#define DT_CONFIG 0x6ffffefa /* Configuration information. */ +#define DT_DEPAUDIT 0x6ffffefb /* Dependency auditing. */ +#define DT_AUDIT 0x6ffffefc /* Object auditing. */ +#define DT_PLTPAD 0x6ffffefd /* PLT padding. */ +#define DT_MOVETAB 0x6ffffefe /* Move table. */ +#define DT_SYMINFO 0x6ffffeff /* Syminfo table. */ +#define DT_ADDRRNGHI 0x6ffffeff +#define DT_ADDRTAGIDX(tag) (DT_ADDRRNGHI - (tag)) /* Reverse order! */ +#define DT_ADDRNUM 11 + +/* The versioning entry types. The next are defined as part of the + GNU extension. */ +#define DT_VERSYM 0x6ffffff0 + +#define DT_RELACOUNT 0x6ffffff9 +#define DT_RELCOUNT 0x6ffffffa + +/* These were chosen by Sun. */ +#define DT_FLAGS_1 0x6ffffffb /* State flags, see DF_1_* below. */ +#define DT_VERDEF 0x6ffffffc /* Address of version definition + table */ +#define DT_VERDEFNUM 0x6ffffffd /* Number of version definitions */ +#define DT_VERNEED 0x6ffffffe /* Address of table with needed + versions */ +#define DT_VERNEEDNUM 0x6fffffff /* Number of needed versions */ +#define DT_VERSIONTAGIDX(tag) (DT_VERNEEDNUM - (tag)) /* Reverse order! */ +#define DT_VERSIONTAGNUM 16 + +/* Sun added these machine-independent extensions in the "processor-specific" + range. Be compatible. */ +#define DT_AUXILIARY 0x7ffffffd /* Shared object to load before self */ +#define DT_FILTER 0x7fffffff /* Shared object to get values from */ +#define DT_EXTRATAGIDX(tag) ((Elf32_Word)-((Elf32_Sword) (tag) <<1>>1)-1) +#define DT_EXTRANUM 3 + +/* Values of `d_un.d_val' in the DT_FLAGS entry. */ +#define DF_ORIGIN 0x00000001 /* Object may use DF_ORIGIN */ +#define DF_SYMBOLIC 0x00000002 /* Symbol resolutions starts here */ +#define DF_TEXTREL 0x00000004 /* Object contains text relocations */ +#define DF_BIND_NOW 0x00000008 /* No lazy binding for this object */ +#define DF_STATIC_TLS 0x00000010 /* Module uses the static TLS model */ + +/* State flags selectable in the `d_un.d_val' element of the DT_FLAGS_1 + entry in the dynamic section. */ +#define DF_1_NOW 0x00000001 /* Set RTLD_NOW for this object. */ +#define DF_1_GLOBAL 0x00000002 /* Set RTLD_GLOBAL for this object. */ +#define DF_1_GROUP 0x00000004 /* Set RTLD_GROUP for this object. */ +#define DF_1_NODELETE 0x00000008 /* Set RTLD_NODELETE for this object.*/ +#define DF_1_LOADFLTR 0x00000010 /* Trigger filtee loading at runtime.*/ +#define DF_1_INITFIRST 0x00000020 /* Set RTLD_INITFIRST for this object*/ +#define DF_1_NOOPEN 0x00000040 /* Set RTLD_NOOPEN for this object. */ +#define DF_1_ORIGIN 0x00000080 /* $ORIGIN must be handled. */ +#define DF_1_DIRECT 0x00000100 /* Direct binding enabled. */ +#define DF_1_TRANS 0x00000200 +#define DF_1_INTERPOSE 0x00000400 /* Object is used to interpose. */ +#define DF_1_NODEFLIB 0x00000800 /* Ignore default lib search path. */ +#define DF_1_NODUMP 0x00001000 /* Object can't be dldump'ed. */ +#define DF_1_CONFALT 0x00002000 /* Configuration alternative created.*/ +#define DF_1_ENDFILTEE 0x00004000 /* Filtee terminates filters search. */ +#define DF_1_DISPRELDNE 0x00008000 /* Disp reloc applied at build time. */ +#define DF_1_DISPRELPND 0x00010000 /* Disp reloc applied at run-time. */ +#define DF_1_NODIRECT 0x00020000 /* Object has no-direct binding. */ +#define DF_1_IGNMULDEF 0x00040000 +#define DF_1_NOKSYMS 0x00080000 +#define DF_1_NOHDR 0x00100000 +#define DF_1_EDITED 0x00200000 /* Object is modified after built. */ +#define DF_1_NORELOC 0x00400000 +#define DF_1_SYMINTPOSE 0x00800000 /* Object has individual interposers. */ +#define DF_1_GLOBAUDIT 0x01000000 /* Global auditing required. */ +#define DF_1_SINGLETON 0x02000000 /* Singleton symbols are used. */ + +/* Flags for the feature selection in DT_FEATURE_1. */ +#define DTF_1_PARINIT 0x00000001 +#define DTF_1_CONFEXP 0x00000002 + +/* Flags in the DT_POSFLAG_1 entry effecting only the next DT_* entry. */ +#define DF_P1_LAZYLOAD 0x00000001 /* Lazyload following object. */ +#define DF_P1_GROUPPERM 0x00000002 /* Symbols from next object are not + generally available. */ + +/* Version definition sections. */ + +typedef struct +{ + Elf32_Half vd_version; /* Version revision */ + Elf32_Half vd_flags; /* Version information */ + Elf32_Half vd_ndx; /* Version Index */ + Elf32_Half vd_cnt; /* Number of associated aux entries */ + Elf32_Word vd_hash; /* Version name hash value */ + Elf32_Word vd_aux; /* Offset in bytes to verdaux array */ + Elf32_Word vd_next; /* Offset in bytes to next verdef + entry */ +} Elf32_Verdef; + +typedef struct +{ + Elf64_Half vd_version; /* Version revision */ + Elf64_Half vd_flags; /* Version information */ + Elf64_Half vd_ndx; /* Version Index */ + Elf64_Half vd_cnt; /* Number of associated aux entries */ + Elf64_Word vd_hash; /* Version name hash value */ + Elf64_Word vd_aux; /* Offset in bytes to verdaux array */ + Elf64_Word vd_next; /* Offset in bytes to next verdef + entry */ +} Elf64_Verdef; + + +/* Legal values for vd_version (version revision). */ +#define VER_DEF_NONE 0 /* No version */ +#define VER_DEF_CURRENT 1 /* Current version */ +#define VER_DEF_NUM 2 /* Given version number */ + +/* Legal values for vd_flags (version information flags). */ +#define VER_FLG_BASE 0x1 /* Version definition of file itself */ +#define VER_FLG_WEAK 0x2 /* Weak version identifier */ + +/* Versym symbol index values. */ +#define VER_NDX_LOCAL 0 /* Symbol is local. */ +#define VER_NDX_GLOBAL 1 /* Symbol is global. */ +#define VER_NDX_LORESERVE 0xff00 /* Beginning of reserved entries. */ +#define VER_NDX_ELIMINATE 0xff01 /* Symbol is to be eliminated. */ + +/* Auxiliary version information. */ + +typedef struct +{ + Elf32_Word vda_name; /* Version or dependency names */ + Elf32_Word vda_next; /* Offset in bytes to next verdaux + entry */ +} Elf32_Verdaux; + +typedef struct +{ + Elf64_Word vda_name; /* Version or dependency names */ + Elf64_Word vda_next; /* Offset in bytes to next verdaux + entry */ +} Elf64_Verdaux; + + +/* Version dependency section. */ + +typedef struct +{ + Elf32_Half vn_version; /* Version of structure */ + Elf32_Half vn_cnt; /* Number of associated aux entries */ + Elf32_Word vn_file; /* Offset of filename for this + dependency */ + Elf32_Word vn_aux; /* Offset in bytes to vernaux array */ + Elf32_Word vn_next; /* Offset in bytes to next verneed + entry */ +} Elf32_Verneed; + +typedef struct +{ + Elf64_Half vn_version; /* Version of structure */ + Elf64_Half vn_cnt; /* Number of associated aux entries */ + Elf64_Word vn_file; /* Offset of filename for this + dependency */ + Elf64_Word vn_aux; /* Offset in bytes to vernaux array */ + Elf64_Word vn_next; /* Offset in bytes to next verneed + entry */ +} Elf64_Verneed; + + +/* Legal values for vn_version (version revision). */ +#define VER_NEED_NONE 0 /* No version */ +#define VER_NEED_CURRENT 1 /* Current version */ +#define VER_NEED_NUM 2 /* Given version number */ + +/* Auxiliary needed version information. */ + +typedef struct +{ + Elf32_Word vna_hash; /* Hash value of dependency name */ + Elf32_Half vna_flags; /* Dependency specific information */ + Elf32_Half vna_other; /* Unused */ + Elf32_Word vna_name; /* Dependency name string offset */ + Elf32_Word vna_next; /* Offset in bytes to next vernaux + entry */ +} Elf32_Vernaux; + +typedef struct +{ + Elf64_Word vna_hash; /* Hash value of dependency name */ + Elf64_Half vna_flags; /* Dependency specific information */ + Elf64_Half vna_other; /* Unused */ + Elf64_Word vna_name; /* Dependency name string offset */ + Elf64_Word vna_next; /* Offset in bytes to next vernaux + entry */ +} Elf64_Vernaux; + + +/* Legal values for vna_flags. */ +#define VER_FLG_WEAK 0x2 /* Weak version identifier */ + + +/* Auxiliary vector. */ + +/* This vector is normally only used by the program interpreter. The + usual definition in an ABI supplement uses the name auxv_t. The + vector is not usually defined in a standard file, but it + can't hurt. We rename it to avoid conflicts. The sizes of these + types are an arrangement between the exec server and the program + interpreter, so we don't fully specify them here. */ + +typedef struct +{ + uint32_t a_type; /* Entry type */ + union + { + uint32_t a_val; /* Integer value */ + /* We use to have pointer elements added here. We cannot do that, + though, since it does not work when using 32-bit definitions + on 64-bit platforms and vice versa. */ + } a_un; +} Elf32_auxv_t; + +typedef struct +{ + uint64_t a_type; /* Entry type */ + union + { + uint64_t a_val; /* Integer value */ + /* We use to have pointer elements added here. We cannot do that, + though, since it does not work when using 32-bit definitions + on 64-bit platforms and vice versa. */ + } a_un; +} Elf64_auxv_t; + +/* Legal values for a_type (entry type). */ + +#define AT_NULL 0 /* End of vector */ +#define AT_IGNORE 1 /* Entry should be ignored */ +#define AT_EXECFD 2 /* File descriptor of program */ +#define AT_PHDR 3 /* Program headers for program */ +#define AT_PHENT 4 /* Size of program header entry */ +#define AT_PHNUM 5 /* Number of program headers */ +#define AT_PAGESZ 6 /* System page size */ +#define AT_BASE 7 /* Base address of interpreter */ +#define AT_FLAGS 8 /* Flags */ +#define AT_ENTRY 9 /* Entry point of program */ +#define AT_NOTELF 10 /* Program is not ELF */ +#define AT_UID 11 /* Real uid */ +#define AT_EUID 12 /* Effective uid */ +#define AT_GID 13 /* Real gid */ +#define AT_EGID 14 /* Effective gid */ +#define AT_CLKTCK 17 /* Frequency of times() */ + +/* Some more special a_type values describing the hardware. */ +#define AT_PLATFORM 15 /* String identifying platform. */ +#define AT_HWCAP 16 /* Machine dependent hints about + processor capabilities. */ + +/* This entry gives some information about the FPU initialization + performed by the kernel. */ +#define AT_FPUCW 18 /* Used FPU control word. */ + +/* Cache block sizes. */ +#define AT_DCACHEBSIZE 19 /* Data cache block size. */ +#define AT_ICACHEBSIZE 20 /* Instruction cache block size. */ +#define AT_UCACHEBSIZE 21 /* Unified cache block size. */ + +/* A special ignored value for PPC, used by the kernel to control the + interpretation of the AUXV. Must be > 16. */ +#define AT_IGNOREPPC 22 /* Entry should be ignored. */ + +#define AT_SECURE 23 /* Boolean, was exec setuid-like? */ + +#define AT_BASE_PLATFORM 24 /* String identifying real platforms.*/ + +#define AT_RANDOM 25 /* Address of 16 random bytes. */ + +#define AT_EXECFN 31 /* Filename of executable. */ + +/* Pointer to the global system page used for system calls and other + nice things. */ +#define AT_SYSINFO 32 +#define AT_SYSINFO_EHDR 33 + +/* Shapes of the caches. Bits 0-3 contains associativity; bits 4-7 contains + log2 of line size; mask those to get cache size. */ +#define AT_L1I_CACHESHAPE 34 +#define AT_L1D_CACHESHAPE 35 +#define AT_L2_CACHESHAPE 36 +#define AT_L3_CACHESHAPE 37 + +/* Note section contents. Each entry in the note section begins with + a header of a fixed form. */ + +typedef struct +{ + Elf32_Word n_namesz; /* Length of the note's name. */ + Elf32_Word n_descsz; /* Length of the note's descriptor. */ + Elf32_Word n_type; /* Type of the note. */ +} Elf32_Nhdr; + +typedef struct +{ + Elf64_Word n_namesz; /* Length of the note's name. */ + Elf64_Word n_descsz; /* Length of the note's descriptor. */ + Elf64_Word n_type; /* Type of the note. */ +} Elf64_Nhdr; + +/* Known names of notes. */ + +/* Solaris entries in the note section have this name. */ +#define ELF_NOTE_SOLARIS "SUNW Solaris" + +/* Note entries for GNU systems have this name. */ +#define ELF_NOTE_GNU "GNU" + + +/* Defined types of notes for Solaris. */ + +/* Value of descriptor (one word) is desired pagesize for the binary. */ +#define ELF_NOTE_PAGESIZE_HINT 1 + + +/* Defined note types for GNU systems. */ + +/* ABI information. The descriptor consists of words: + word 0: OS descriptor + word 1: major version of the ABI + word 2: minor version of the ABI + word 3: subminor version of the ABI +*/ +#define NT_GNU_ABI_TAG 1 +#define ELF_NOTE_ABI NT_GNU_ABI_TAG /* Old name. */ + +/* Known OSes. These values can appear in word 0 of an + NT_GNU_ABI_TAG note section entry. */ +#define ELF_NOTE_OS_LINUX 0 +#define ELF_NOTE_OS_GNU 1 +#define ELF_NOTE_OS_SOLARIS2 2 +#define ELF_NOTE_OS_FREEBSD 3 + +/* Synthetic hwcap information. The descriptor begins with two words: + word 0: number of entries + word 1: bitmask of enabled entries + Then follow variable-length entries, one byte followed by a + '\0'-terminated hwcap name string. The byte gives the bit + number to test if enabled, (1U << bit) & bitmask. */ +#define NT_GNU_HWCAP 2 + +/* Build ID bits as generated by ld --build-id. + The descriptor consists of any nonzero number of bytes. */ +#define NT_GNU_BUILD_ID 3 + +/* Version note generated by GNU gold containing a version string. */ +#define NT_GNU_GOLD_VERSION 4 + + +/* Move records. */ +typedef struct +{ + Elf32_Xword m_value; /* Symbol value. */ + Elf32_Word m_info; /* Size and index. */ + Elf32_Word m_poffset; /* Symbol offset. */ + Elf32_Half m_repeat; /* Repeat count. */ + Elf32_Half m_stride; /* Stride info. */ +} Elf32_Move; + +typedef struct +{ + Elf64_Xword m_value; /* Symbol value. */ + Elf64_Xword m_info; /* Size and index. */ + Elf64_Xword m_poffset; /* Symbol offset. */ + Elf64_Half m_repeat; /* Repeat count. */ + Elf64_Half m_stride; /* Stride info. */ +} Elf64_Move; + +/* Macro to construct move records. */ +#define ELF32_M_SYM(info) ((info) >> 8) +#define ELF32_M_SIZE(info) ((unsigned char) (info)) +#define ELF32_M_INFO(sym, size) (((sym) << 8) + (unsigned char) (size)) + +#define ELF64_M_SYM(info) ELF32_M_SYM (info) +#define ELF64_M_SIZE(info) ELF32_M_SIZE (info) +#define ELF64_M_INFO(sym, size) ELF32_M_INFO (sym, size) + + +/* Motorola 68k specific definitions. */ + +/* Values for Elf32_Ehdr.e_flags. */ +#define EF_CPU32 0x00810000 + +/* m68k relocs. */ + +#define R_68K_NONE 0 /* No reloc */ +#define R_68K_32 1 /* Direct 32 bit */ +#define R_68K_16 2 /* Direct 16 bit */ +#define R_68K_8 3 /* Direct 8 bit */ +#define R_68K_PC32 4 /* PC relative 32 bit */ +#define R_68K_PC16 5 /* PC relative 16 bit */ +#define R_68K_PC8 6 /* PC relative 8 bit */ +#define R_68K_GOT32 7 /* 32 bit PC relative GOT entry */ +#define R_68K_GOT16 8 /* 16 bit PC relative GOT entry */ +#define R_68K_GOT8 9 /* 8 bit PC relative GOT entry */ +#define R_68K_GOT32O 10 /* 32 bit GOT offset */ +#define R_68K_GOT16O 11 /* 16 bit GOT offset */ +#define R_68K_GOT8O 12 /* 8 bit GOT offset */ +#define R_68K_PLT32 13 /* 32 bit PC relative PLT address */ +#define R_68K_PLT16 14 /* 16 bit PC relative PLT address */ +#define R_68K_PLT8 15 /* 8 bit PC relative PLT address */ +#define R_68K_PLT32O 16 /* 32 bit PLT offset */ +#define R_68K_PLT16O 17 /* 16 bit PLT offset */ +#define R_68K_PLT8O 18 /* 8 bit PLT offset */ +#define R_68K_COPY 19 /* Copy symbol at runtime */ +#define R_68K_GLOB_DAT 20 /* Create GOT entry */ +#define R_68K_JMP_SLOT 21 /* Create PLT entry */ +#define R_68K_RELATIVE 22 /* Adjust by program base */ +#define R_68K_TLS_GD32 25 /* 32 bit GOT offset for GD */ +#define R_68K_TLS_GD16 26 /* 16 bit GOT offset for GD */ +#define R_68K_TLS_GD8 27 /* 8 bit GOT offset for GD */ +#define R_68K_TLS_LDM32 28 /* 32 bit GOT offset for LDM */ +#define R_68K_TLS_LDM16 29 /* 16 bit GOT offset for LDM */ +#define R_68K_TLS_LDM8 30 /* 8 bit GOT offset for LDM */ +#define R_68K_TLS_LDO32 31 /* 32 bit module-relative offset */ +#define R_68K_TLS_LDO16 32 /* 16 bit module-relative offset */ +#define R_68K_TLS_LDO8 33 /* 8 bit module-relative offset */ +#define R_68K_TLS_IE32 34 /* 32 bit GOT offset for IE */ +#define R_68K_TLS_IE16 35 /* 16 bit GOT offset for IE */ +#define R_68K_TLS_IE8 36 /* 8 bit GOT offset for IE */ +#define R_68K_TLS_LE32 37 /* 32 bit offset relative to + static TLS block */ +#define R_68K_TLS_LE16 38 /* 16 bit offset relative to + static TLS block */ +#define R_68K_TLS_LE8 39 /* 8 bit offset relative to + static TLS block */ +#define R_68K_TLS_DTPMOD32 40 /* 32 bit module number */ +#define R_68K_TLS_DTPREL32 41 /* 32 bit module-relative offset */ +#define R_68K_TLS_TPREL32 42 /* 32 bit TP-relative offset */ +/* Keep this the last entry. */ +#define R_68K_NUM 43 + +/* Intel 80386 specific definitions. */ + +/* i386 relocs. */ + +#define R_386_NONE 0 /* No reloc */ +#define R_386_32 1 /* Direct 32 bit */ +#define R_386_PC32 2 /* PC relative 32 bit */ +#define R_386_GOT32 3 /* 32 bit GOT entry */ +#define R_386_PLT32 4 /* 32 bit PLT address */ +#define R_386_COPY 5 /* Copy symbol at runtime */ +#define R_386_GLOB_DAT 6 /* Create GOT entry */ +#define R_386_JMP_SLOT 7 /* Create PLT entry */ +#define R_386_RELATIVE 8 /* Adjust by program base */ +#define R_386_GOTOFF 9 /* 32 bit offset to GOT */ +#define R_386_GOTPC 10 /* 32 bit PC relative offset to GOT */ +#define R_386_32PLT 11 +#define R_386_TLS_TPOFF 14 /* Offset in static TLS block */ +#define R_386_TLS_IE 15 /* Address of GOT entry for static TLS + block offset */ +#define R_386_TLS_GOTIE 16 /* GOT entry for static TLS block + offset */ +#define R_386_TLS_LE 17 /* Offset relative to static TLS + block */ +#define R_386_TLS_GD 18 /* Direct 32 bit for GNU version of + general dynamic thread local data */ +#define R_386_TLS_LDM 19 /* Direct 32 bit for GNU version of + local dynamic thread local data + in LE code */ +#define R_386_16 20 +#define R_386_PC16 21 +#define R_386_8 22 +#define R_386_PC8 23 +#define R_386_TLS_GD_32 24 /* Direct 32 bit for general dynamic + thread local data */ +#define R_386_TLS_GD_PUSH 25 /* Tag for pushl in GD TLS code */ +#define R_386_TLS_GD_CALL 26 /* Relocation for call to + __tls_get_addr() */ +#define R_386_TLS_GD_POP 27 /* Tag for popl in GD TLS code */ +#define R_386_TLS_LDM_32 28 /* Direct 32 bit for local dynamic + thread local data in LE code */ +#define R_386_TLS_LDM_PUSH 29 /* Tag for pushl in LDM TLS code */ +#define R_386_TLS_LDM_CALL 30 /* Relocation for call to + __tls_get_addr() in LDM code */ +#define R_386_TLS_LDM_POP 31 /* Tag for popl in LDM TLS code */ +#define R_386_TLS_LDO_32 32 /* Offset relative to TLS block */ +#define R_386_TLS_IE_32 33 /* GOT entry for negated static TLS + block offset */ +#define R_386_TLS_LE_32 34 /* Negated offset relative to static + TLS block */ +#define R_386_TLS_DTPMOD32 35 /* ID of module containing symbol */ +#define R_386_TLS_DTPOFF32 36 /* Offset in TLS block */ +#define R_386_TLS_TPOFF32 37 /* Negated offset in static TLS block */ +/* 38? */ +#define R_386_TLS_GOTDESC 39 /* GOT offset for TLS descriptor. */ +#define R_386_TLS_DESC_CALL 40 /* Marker of call through TLS + descriptor for + relaxation. */ +#define R_386_TLS_DESC 41 /* TLS descriptor containing + pointer to code and to + argument, returning the TLS + offset for the symbol. */ +#define R_386_IRELATIVE 42 /* Adjust indirectly by program base */ +#define R_386_GOT32X 43 /* 32 bit GOT entry, relaxable */ +/* Keep this the last entry. */ +#define R_386_NUM 44 + +/* SUN SPARC specific definitions. */ + +/* Legal values for ST_TYPE subfield of st_info (symbol type). */ + +#define STT_SPARC_REGISTER 13 /* Global register reserved to app. */ + +/* Values for Elf64_Ehdr.e_flags. */ + +#define EF_SPARCV9_MM 3 +#define EF_SPARCV9_TSO 0 +#define EF_SPARCV9_PSO 1 +#define EF_SPARCV9_RMO 2 +#define EF_SPARC_LEDATA 0x800000 /* little endian data */ +#define EF_SPARC_EXT_MASK 0xFFFF00 +#define EF_SPARC_32PLUS 0x000100 /* generic V8+ features */ +#define EF_SPARC_SUN_US1 0x000200 /* Sun UltraSPARC1 extensions */ +#define EF_SPARC_HAL_R1 0x000400 /* HAL R1 extensions */ +#define EF_SPARC_SUN_US3 0x000800 /* Sun UltraSPARCIII extensions */ + +/* SPARC relocs. */ + +#define R_SPARC_NONE 0 /* No reloc */ +#define R_SPARC_8 1 /* Direct 8 bit */ +#define R_SPARC_16 2 /* Direct 16 bit */ +#define R_SPARC_32 3 /* Direct 32 bit */ +#define R_SPARC_DISP8 4 /* PC relative 8 bit */ +#define R_SPARC_DISP16 5 /* PC relative 16 bit */ +#define R_SPARC_DISP32 6 /* PC relative 32 bit */ +#define R_SPARC_WDISP30 7 /* PC relative 30 bit shifted */ +#define R_SPARC_WDISP22 8 /* PC relative 22 bit shifted */ +#define R_SPARC_HI22 9 /* High 22 bit */ +#define R_SPARC_22 10 /* Direct 22 bit */ +#define R_SPARC_13 11 /* Direct 13 bit */ +#define R_SPARC_LO10 12 /* Truncated 10 bit */ +#define R_SPARC_GOT10 13 /* Truncated 10 bit GOT entry */ +#define R_SPARC_GOT13 14 /* 13 bit GOT entry */ +#define R_SPARC_GOT22 15 /* 22 bit GOT entry shifted */ +#define R_SPARC_PC10 16 /* PC relative 10 bit truncated */ +#define R_SPARC_PC22 17 /* PC relative 22 bit shifted */ +#define R_SPARC_WPLT30 18 /* 30 bit PC relative PLT address */ +#define R_SPARC_COPY 19 /* Copy symbol at runtime */ +#define R_SPARC_GLOB_DAT 20 /* Create GOT entry */ +#define R_SPARC_JMP_SLOT 21 /* Create PLT entry */ +#define R_SPARC_RELATIVE 22 /* Adjust by program base */ +#define R_SPARC_UA32 23 /* Direct 32 bit unaligned */ + +/* Additional Sparc64 relocs. */ + +#define R_SPARC_PLT32 24 /* Direct 32 bit ref to PLT entry */ +#define R_SPARC_HIPLT22 25 /* High 22 bit PLT entry */ +#define R_SPARC_LOPLT10 26 /* Truncated 10 bit PLT entry */ +#define R_SPARC_PCPLT32 27 /* PC rel 32 bit ref to PLT entry */ +#define R_SPARC_PCPLT22 28 /* PC rel high 22 bit PLT entry */ +#define R_SPARC_PCPLT10 29 /* PC rel trunc 10 bit PLT entry */ +#define R_SPARC_10 30 /* Direct 10 bit */ +#define R_SPARC_11 31 /* Direct 11 bit */ +#define R_SPARC_64 32 /* Direct 64 bit */ +#define R_SPARC_OLO10 33 /* 10bit with secondary 13bit addend */ +#define R_SPARC_HH22 34 /* Top 22 bits of direct 64 bit */ +#define R_SPARC_HM10 35 /* High middle 10 bits of ... */ +#define R_SPARC_LM22 36 /* Low middle 22 bits of ... */ +#define R_SPARC_PC_HH22 37 /* Top 22 bits of pc rel 64 bit */ +#define R_SPARC_PC_HM10 38 /* High middle 10 bit of ... */ +#define R_SPARC_PC_LM22 39 /* Low middle 22 bits of ... */ +#define R_SPARC_WDISP16 40 /* PC relative 16 bit shifted */ +#define R_SPARC_WDISP19 41 /* PC relative 19 bit shifted */ +#define R_SPARC_GLOB_JMP 42 /* was part of v9 ABI but was removed */ +#define R_SPARC_7 43 /* Direct 7 bit */ +#define R_SPARC_5 44 /* Direct 5 bit */ +#define R_SPARC_6 45 /* Direct 6 bit */ +#define R_SPARC_DISP64 46 /* PC relative 64 bit */ +#define R_SPARC_PLT64 47 /* Direct 64 bit ref to PLT entry */ +#define R_SPARC_HIX22 48 /* High 22 bit complemented */ +#define R_SPARC_LOX10 49 /* Truncated 11 bit complemented */ +#define R_SPARC_H44 50 /* Direct high 12 of 44 bit */ +#define R_SPARC_M44 51 /* Direct mid 22 of 44 bit */ +#define R_SPARC_L44 52 /* Direct low 10 of 44 bit */ +#define R_SPARC_REGISTER 53 /* Global register usage */ +#define R_SPARC_UA64 54 /* Direct 64 bit unaligned */ +#define R_SPARC_UA16 55 /* Direct 16 bit unaligned */ +#define R_SPARC_TLS_GD_HI22 56 +#define R_SPARC_TLS_GD_LO10 57 +#define R_SPARC_TLS_GD_ADD 58 +#define R_SPARC_TLS_GD_CALL 59 +#define R_SPARC_TLS_LDM_HI22 60 +#define R_SPARC_TLS_LDM_LO10 61 +#define R_SPARC_TLS_LDM_ADD 62 +#define R_SPARC_TLS_LDM_CALL 63 +#define R_SPARC_TLS_LDO_HIX22 64 +#define R_SPARC_TLS_LDO_LOX10 65 +#define R_SPARC_TLS_LDO_ADD 66 +#define R_SPARC_TLS_IE_HI22 67 +#define R_SPARC_TLS_IE_LO10 68 +#define R_SPARC_TLS_IE_LD 69 +#define R_SPARC_TLS_IE_LDX 70 +#define R_SPARC_TLS_IE_ADD 71 +#define R_SPARC_TLS_LE_HIX22 72 +#define R_SPARC_TLS_LE_LOX10 73 +#define R_SPARC_TLS_DTPMOD32 74 +#define R_SPARC_TLS_DTPMOD64 75 +#define R_SPARC_TLS_DTPOFF32 76 +#define R_SPARC_TLS_DTPOFF64 77 +#define R_SPARC_TLS_TPOFF32 78 +#define R_SPARC_TLS_TPOFF64 79 +#define R_SPARC_GOTDATA_HIX22 80 +#define R_SPARC_GOTDATA_LOX10 81 +#define R_SPARC_GOTDATA_OP_HIX22 82 +#define R_SPARC_GOTDATA_OP_LOX10 83 +#define R_SPARC_GOTDATA_OP 84 +#define R_SPARC_H34 85 +#define R_SPARC_SIZE32 86 +#define R_SPARC_SIZE64 87 +#define R_SPARC_WDISP10 88 +#define R_SPARC_JMP_IREL 248 +#define R_SPARC_IRELATIVE 249 +#define R_SPARC_GNU_VTINHERIT 250 +#define R_SPARC_GNU_VTENTRY 251 +#define R_SPARC_REV32 252 +/* Keep this the last entry. */ +#define R_SPARC_NUM 253 + +/* For Sparc64, legal values for d_tag of Elf64_Dyn. */ + +#define DT_SPARC_REGISTER 0x70000001 +#define DT_SPARC_NUM 2 + +/* MIPS R3000 specific definitions. */ + +/* Legal values for e_flags field of Elf32_Ehdr. */ + +#define EF_MIPS_NOREORDER 1 /* A .noreorder directive was used */ +#define EF_MIPS_PIC 2 /* Contains PIC code */ +#define EF_MIPS_CPIC 4 /* Uses PIC calling sequence */ +#define EF_MIPS_XGOT 8 +#define EF_MIPS_64BIT_WHIRL 16 +#define EF_MIPS_ABI2 32 +#define EF_MIPS_ABI_ON32 64 +#define EF_MIPS_ARCH 0xf0000000 /* MIPS architecture level */ + +/* Legal values for MIPS architecture level. */ + +#define EF_MIPS_ARCH_1 0x00000000 /* -mips1 code. */ +#define EF_MIPS_ARCH_2 0x10000000 /* -mips2 code. */ +#define EF_MIPS_ARCH_3 0x20000000 /* -mips3 code. */ +#define EF_MIPS_ARCH_4 0x30000000 /* -mips4 code. */ +#define EF_MIPS_ARCH_5 0x40000000 /* -mips5 code. */ +#define EF_MIPS_ARCH_32 0x60000000 /* MIPS32 code. */ +#define EF_MIPS_ARCH_64 0x70000000 /* MIPS64 code. */ + +/* The following are non-official names and should not be used. */ + +#define E_MIPS_ARCH_1 0x00000000 /* -mips1 code. */ +#define E_MIPS_ARCH_2 0x10000000 /* -mips2 code. */ +#define E_MIPS_ARCH_3 0x20000000 /* -mips3 code. */ +#define E_MIPS_ARCH_4 0x30000000 /* -mips4 code. */ +#define E_MIPS_ARCH_5 0x40000000 /* -mips5 code. */ +#define E_MIPS_ARCH_32 0x60000000 /* MIPS32 code. */ +#define E_MIPS_ARCH_64 0x70000000 /* MIPS64 code. */ + +/* Special section indices. */ + +#define SHN_MIPS_ACOMMON 0xff00 /* Allocated common symbols */ +#define SHN_MIPS_TEXT 0xff01 /* Allocated test symbols. */ +#define SHN_MIPS_DATA 0xff02 /* Allocated data symbols. */ +#define SHN_MIPS_SCOMMON 0xff03 /* Small common symbols */ +#define SHN_MIPS_SUNDEFINED 0xff04 /* Small undefined symbols */ + +/* Legal values for sh_type field of Elf32_Shdr. */ + +#define SHT_MIPS_LIBLIST 0x70000000 /* Shared objects used in link */ +#define SHT_MIPS_MSYM 0x70000001 +#define SHT_MIPS_CONFLICT 0x70000002 /* Conflicting symbols */ +#define SHT_MIPS_GPTAB 0x70000003 /* Global data area sizes */ +#define SHT_MIPS_UCODE 0x70000004 /* Reserved for SGI/MIPS compilers */ +#define SHT_MIPS_DEBUG 0x70000005 /* MIPS ECOFF debugging information*/ +#define SHT_MIPS_REGINFO 0x70000006 /* Register usage information */ +#define SHT_MIPS_PACKAGE 0x70000007 +#define SHT_MIPS_PACKSYM 0x70000008 +#define SHT_MIPS_RELD 0x70000009 +#define SHT_MIPS_IFACE 0x7000000b +#define SHT_MIPS_CONTENT 0x7000000c +#define SHT_MIPS_OPTIONS 0x7000000d /* Miscellaneous options. */ +#define SHT_MIPS_SHDR 0x70000010 +#define SHT_MIPS_FDESC 0x70000011 +#define SHT_MIPS_EXTSYM 0x70000012 +#define SHT_MIPS_DENSE 0x70000013 +#define SHT_MIPS_PDESC 0x70000014 +#define SHT_MIPS_LOCSYM 0x70000015 +#define SHT_MIPS_AUXSYM 0x70000016 +#define SHT_MIPS_OPTSYM 0x70000017 +#define SHT_MIPS_LOCSTR 0x70000018 +#define SHT_MIPS_LINE 0x70000019 +#define SHT_MIPS_RFDESC 0x7000001a +#define SHT_MIPS_DELTASYM 0x7000001b +#define SHT_MIPS_DELTAINST 0x7000001c +#define SHT_MIPS_DELTACLASS 0x7000001d +#define SHT_MIPS_DWARF 0x7000001e /* DWARF debugging information. */ +#define SHT_MIPS_DELTADECL 0x7000001f +#define SHT_MIPS_SYMBOL_LIB 0x70000020 +#define SHT_MIPS_EVENTS 0x70000021 /* Event section. */ +#define SHT_MIPS_TRANSLATE 0x70000022 +#define SHT_MIPS_PIXIE 0x70000023 +#define SHT_MIPS_XLATE 0x70000024 +#define SHT_MIPS_XLATE_DEBUG 0x70000025 +#define SHT_MIPS_WHIRL 0x70000026 +#define SHT_MIPS_EH_REGION 0x70000027 +#define SHT_MIPS_XLATE_OLD 0x70000028 +#define SHT_MIPS_PDR_EXCEPTION 0x70000029 + +/* Legal values for sh_flags field of Elf32_Shdr. */ + +#define SHF_MIPS_GPREL 0x10000000 /* Must be part of global data area */ +#define SHF_MIPS_MERGE 0x20000000 +#define SHF_MIPS_ADDR 0x40000000 +#define SHF_MIPS_STRINGS 0x80000000 +#define SHF_MIPS_NOSTRIP 0x08000000 +#define SHF_MIPS_LOCAL 0x04000000 +#define SHF_MIPS_NAMES 0x02000000 +#define SHF_MIPS_NODUPE 0x01000000 + + +/* Symbol tables. */ + +/* MIPS specific values for `st_other'. */ +#define STO_MIPS_DEFAULT 0x0 +#define STO_MIPS_INTERNAL 0x1 +#define STO_MIPS_HIDDEN 0x2 +#define STO_MIPS_PROTECTED 0x3 +#define STO_MIPS_PLT 0x8 +#define STO_MIPS_SC_ALIGN_UNUSED 0xff + +/* MIPS specific values for `st_info'. */ +#define STB_MIPS_SPLIT_COMMON 13 + +/* Entries found in sections of type SHT_MIPS_GPTAB. */ + +typedef union +{ + struct + { + Elf32_Word gt_current_g_value; /* -G value used for compilation */ + Elf32_Word gt_unused; /* Not used */ + } gt_header; /* First entry in section */ + struct + { + Elf32_Word gt_g_value; /* If this value were used for -G */ + Elf32_Word gt_bytes; /* This many bytes would be used */ + } gt_entry; /* Subsequent entries in section */ +} Elf32_gptab; + +/* Entry found in sections of type SHT_MIPS_REGINFO. */ + +typedef struct +{ + Elf32_Word ri_gprmask; /* General registers used */ + Elf32_Word ri_cprmask[4]; /* Coprocessor registers used */ + Elf32_Sword ri_gp_value; /* $gp register value */ +} Elf32_RegInfo; + +/* Entries found in sections of type SHT_MIPS_OPTIONS. */ + +typedef struct +{ + unsigned char kind; /* Determines interpretation of the + variable part of descriptor. */ + unsigned char size; /* Size of descriptor, including header. */ + Elf32_Section section; /* Section header index of section affected, + 0 for global options. */ + Elf32_Word info; /* Kind-specific information. */ +} Elf_Options; + +/* Values for `kind' field in Elf_Options. */ + +#define ODK_NULL 0 /* Undefined. */ +#define ODK_REGINFO 1 /* Register usage information. */ +#define ODK_EXCEPTIONS 2 /* Exception processing options. */ +#define ODK_PAD 3 /* Section padding options. */ +#define ODK_HWPATCH 4 /* Hardware workarounds performed */ +#define ODK_FILL 5 /* record the fill value used by the linker. */ +#define ODK_TAGS 6 /* reserve space for desktop tools to write. */ +#define ODK_HWAND 7 /* HW workarounds. 'AND' bits when merging. */ +#define ODK_HWOR 8 /* HW workarounds. 'OR' bits when merging. */ + +/* Values for `info' in Elf_Options for ODK_EXCEPTIONS entries. */ + +#define OEX_FPU_MIN 0x1f /* FPE's which MUST be enabled. */ +#define OEX_FPU_MAX 0x1f00 /* FPE's which MAY be enabled. */ +#define OEX_PAGE0 0x10000 /* page zero must be mapped. */ +#define OEX_SMM 0x20000 /* Force sequential memory mode? */ +#define OEX_FPDBUG 0x40000 /* Force floating point debug mode? */ +#define OEX_PRECISEFP OEX_FPDBUG +#define OEX_DISMISS 0x80000 /* Dismiss invalid address faults? */ + +#define OEX_FPU_INVAL 0x10 +#define OEX_FPU_DIV0 0x08 +#define OEX_FPU_OFLO 0x04 +#define OEX_FPU_UFLO 0x02 +#define OEX_FPU_INEX 0x01 + +/* Masks for `info' in Elf_Options for an ODK_HWPATCH entry. */ + +#define OHW_R4KEOP 0x1 /* R4000 end-of-page patch. */ +#define OHW_R8KPFETCH 0x2 /* may need R8000 prefetch patch. */ +#define OHW_R5KEOP 0x4 /* R5000 end-of-page patch. */ +#define OHW_R5KCVTL 0x8 /* R5000 cvt.[ds].l bug. clean=1. */ + +#define OPAD_PREFIX 0x1 +#define OPAD_POSTFIX 0x2 +#define OPAD_SYMBOL 0x4 + +/* Entry found in `.options' section. */ + +typedef struct +{ + Elf32_Word hwp_flags1; /* Extra flags. */ + Elf32_Word hwp_flags2; /* Extra flags. */ +} Elf_Options_Hw; + +/* Masks for `info' in ElfOptions for ODK_HWAND and ODK_HWOR entries. */ + +#define OHWA0_R4KEOP_CHECKED 0x00000001 +#define OHWA1_R4KEOP_CLEAN 0x00000002 + +/* MIPS relocs. */ + +#define R_MIPS_NONE 0 /* No reloc */ +#define R_MIPS_16 1 /* Direct 16 bit */ +#define R_MIPS_32 2 /* Direct 32 bit */ +#define R_MIPS_REL32 3 /* PC relative 32 bit */ +#define R_MIPS_26 4 /* Direct 26 bit shifted */ +#define R_MIPS_HI16 5 /* High 16 bit */ +#define R_MIPS_LO16 6 /* Low 16 bit */ +#define R_MIPS_GPREL16 7 /* GP relative 16 bit */ +#define R_MIPS_LITERAL 8 /* 16 bit literal entry */ +#define R_MIPS_GOT16 9 /* 16 bit GOT entry */ +#define R_MIPS_PC16 10 /* PC relative 16 bit */ +#define R_MIPS_CALL16 11 /* 16 bit GOT entry for function */ +#define R_MIPS_GPREL32 12 /* GP relative 32 bit */ + +#define R_MIPS_SHIFT5 16 +#define R_MIPS_SHIFT6 17 +#define R_MIPS_64 18 +#define R_MIPS_GOT_DISP 19 +#define R_MIPS_GOT_PAGE 20 +#define R_MIPS_GOT_OFST 21 +#define R_MIPS_GOT_HI16 22 +#define R_MIPS_GOT_LO16 23 +#define R_MIPS_SUB 24 +#define R_MIPS_INSERT_A 25 +#define R_MIPS_INSERT_B 26 +#define R_MIPS_DELETE 27 +#define R_MIPS_HIGHER 28 +#define R_MIPS_HIGHEST 29 +#define R_MIPS_CALL_HI16 30 +#define R_MIPS_CALL_LO16 31 +#define R_MIPS_SCN_DISP 32 +#define R_MIPS_REL16 33 +#define R_MIPS_ADD_IMMEDIATE 34 +#define R_MIPS_PJUMP 35 +#define R_MIPS_RELGOT 36 +#define R_MIPS_JALR 37 +#define R_MIPS_TLS_DTPMOD32 38 /* Module number 32 bit */ +#define R_MIPS_TLS_DTPREL32 39 /* Module-relative offset 32 bit */ +#define R_MIPS_TLS_DTPMOD64 40 /* Module number 64 bit */ +#define R_MIPS_TLS_DTPREL64 41 /* Module-relative offset 64 bit */ +#define R_MIPS_TLS_GD 42 /* 16 bit GOT offset for GD */ +#define R_MIPS_TLS_LDM 43 /* 16 bit GOT offset for LDM */ +#define R_MIPS_TLS_DTPREL_HI16 44 /* Module-relative offset, high 16 bits */ +#define R_MIPS_TLS_DTPREL_LO16 45 /* Module-relative offset, low 16 bits */ +#define R_MIPS_TLS_GOTTPREL 46 /* 16 bit GOT offset for IE */ +#define R_MIPS_TLS_TPREL32 47 /* TP-relative offset, 32 bit */ +#define R_MIPS_TLS_TPREL64 48 /* TP-relative offset, 64 bit */ +#define R_MIPS_TLS_TPREL_HI16 49 /* TP-relative offset, high 16 bits */ +#define R_MIPS_TLS_TPREL_LO16 50 /* TP-relative offset, low 16 bits */ +#define R_MIPS_GLOB_DAT 51 +#define R_MIPS_COPY 126 +#define R_MIPS_JUMP_SLOT 127 +/* Keep this the last entry. */ +#define R_MIPS_NUM 128 + +/* Legal values for p_type field of Elf32_Phdr. */ + +#define PT_MIPS_REGINFO 0x70000000 /* Register usage information */ +#define PT_MIPS_RTPROC 0x70000001 /* Runtime procedure table. */ +#define PT_MIPS_OPTIONS 0x70000002 + +/* Special program header types. */ + +#define PF_MIPS_LOCAL 0x10000000 + +/* Legal values for d_tag field of Elf32_Dyn. */ + +#define DT_MIPS_RLD_VERSION 0x70000001 /* Runtime linker interface version */ +#define DT_MIPS_TIME_STAMP 0x70000002 /* Timestamp */ +#define DT_MIPS_ICHECKSUM 0x70000003 /* Checksum */ +#define DT_MIPS_IVERSION 0x70000004 /* Version string (string tbl index) */ +#define DT_MIPS_FLAGS 0x70000005 /* Flags */ +#define DT_MIPS_BASE_ADDRESS 0x70000006 /* Base address */ +#define DT_MIPS_MSYM 0x70000007 +#define DT_MIPS_CONFLICT 0x70000008 /* Address of CONFLICT section */ +#define DT_MIPS_LIBLIST 0x70000009 /* Address of LIBLIST section */ +#define DT_MIPS_LOCAL_GOTNO 0x7000000a /* Number of local GOT entries */ +#define DT_MIPS_CONFLICTNO 0x7000000b /* Number of CONFLICT entries */ +#define DT_MIPS_LIBLISTNO 0x70000010 /* Number of LIBLIST entries */ +#define DT_MIPS_SYMTABNO 0x70000011 /* Number of DYNSYM entries */ +#define DT_MIPS_UNREFEXTNO 0x70000012 /* First external DYNSYM */ +#define DT_MIPS_GOTSYM 0x70000013 /* First GOT entry in DYNSYM */ +#define DT_MIPS_HIPAGENO 0x70000014 /* Number of GOT page table entries */ +#define DT_MIPS_RLD_MAP 0x70000016 /* Address of run time loader map. */ +#define DT_MIPS_DELTA_CLASS 0x70000017 /* Delta C++ class definition. */ +#define DT_MIPS_DELTA_CLASS_NO 0x70000018 /* Number of entries in + DT_MIPS_DELTA_CLASS. */ +#define DT_MIPS_DELTA_INSTANCE 0x70000019 /* Delta C++ class instances. */ +#define DT_MIPS_DELTA_INSTANCE_NO 0x7000001a /* Number of entries in + DT_MIPS_DELTA_INSTANCE. */ +#define DT_MIPS_DELTA_RELOC 0x7000001b /* Delta relocations. */ +#define DT_MIPS_DELTA_RELOC_NO 0x7000001c /* Number of entries in + DT_MIPS_DELTA_RELOC. */ +#define DT_MIPS_DELTA_SYM 0x7000001d /* Delta symbols that Delta + relocations refer to. */ +#define DT_MIPS_DELTA_SYM_NO 0x7000001e /* Number of entries in + DT_MIPS_DELTA_SYM. */ +#define DT_MIPS_DELTA_CLASSSYM 0x70000020 /* Delta symbols that hold the + class declaration. */ +#define DT_MIPS_DELTA_CLASSSYM_NO 0x70000021 /* Number of entries in + DT_MIPS_DELTA_CLASSSYM. */ +#define DT_MIPS_CXX_FLAGS 0x70000022 /* Flags indicating for C++ flavor. */ +#define DT_MIPS_PIXIE_INIT 0x70000023 +#define DT_MIPS_SYMBOL_LIB 0x70000024 +#define DT_MIPS_LOCALPAGE_GOTIDX 0x70000025 +#define DT_MIPS_LOCAL_GOTIDX 0x70000026 +#define DT_MIPS_HIDDEN_GOTIDX 0x70000027 +#define DT_MIPS_PROTECTED_GOTIDX 0x70000028 +#define DT_MIPS_OPTIONS 0x70000029 /* Address of .options. */ +#define DT_MIPS_INTERFACE 0x7000002a /* Address of .interface. */ +#define DT_MIPS_DYNSTR_ALIGN 0x7000002b +#define DT_MIPS_INTERFACE_SIZE 0x7000002c /* Size of the .interface section. */ +#define DT_MIPS_RLD_TEXT_RESOLVE_ADDR 0x7000002d /* Address of rld_text_rsolve + function stored in GOT. */ +#define DT_MIPS_PERF_SUFFIX 0x7000002e /* Default suffix of dso to be added + by rld on dlopen() calls. */ +#define DT_MIPS_COMPACT_SIZE 0x7000002f /* (O32)Size of compact rel section. */ +#define DT_MIPS_GP_VALUE 0x70000030 /* GP value for aux GOTs. */ +#define DT_MIPS_AUX_DYNAMIC 0x70000031 /* Address of aux .dynamic. */ +/* The address of .got.plt in an executable using the new non-PIC ABI. */ +#define DT_MIPS_PLTGOT 0x70000032 +/* The base of the PLT in an executable using the new non-PIC ABI if that + PLT is writable. For a non-writable PLT, this is omitted or has a zero + value. */ +#define DT_MIPS_RWPLT 0x70000034 +#define DT_MIPS_NUM 0x35 + +/* Legal values for DT_MIPS_FLAGS Elf32_Dyn entry. */ + +#define RHF_NONE 0 /* No flags */ +#define RHF_QUICKSTART (1 << 0) /* Use quickstart */ +#define RHF_NOTPOT (1 << 1) /* Hash size not power of 2 */ +#define RHF_NO_LIBRARY_REPLACEMENT (1 << 2) /* Ignore LD_LIBRARY_PATH */ +#define RHF_NO_MOVE (1 << 3) +#define RHF_SGI_ONLY (1 << 4) +#define RHF_GUARANTEE_INIT (1 << 5) +#define RHF_DELTA_C_PLUS_PLUS (1 << 6) +#define RHF_GUARANTEE_START_INIT (1 << 7) +#define RHF_PIXIE (1 << 8) +#define RHF_DEFAULT_DELAY_LOAD (1 << 9) +#define RHF_REQUICKSTART (1 << 10) +#define RHF_REQUICKSTARTED (1 << 11) +#define RHF_CORD (1 << 12) +#define RHF_NO_UNRES_UNDEF (1 << 13) +#define RHF_RLD_ORDER_SAFE (1 << 14) + +/* Entries found in sections of type SHT_MIPS_LIBLIST. */ + +typedef struct +{ + Elf32_Word l_name; /* Name (string table index) */ + Elf32_Word l_time_stamp; /* Timestamp */ + Elf32_Word l_checksum; /* Checksum */ + Elf32_Word l_version; /* Interface version */ + Elf32_Word l_flags; /* Flags */ +} Elf32_Lib; + +typedef struct +{ + Elf64_Word l_name; /* Name (string table index) */ + Elf64_Word l_time_stamp; /* Timestamp */ + Elf64_Word l_checksum; /* Checksum */ + Elf64_Word l_version; /* Interface version */ + Elf64_Word l_flags; /* Flags */ +} Elf64_Lib; + + +/* Legal values for l_flags. */ + +#define LL_NONE 0 +#define LL_EXACT_MATCH (1 << 0) /* Require exact match */ +#define LL_IGNORE_INT_VER (1 << 1) /* Ignore interface version */ +#define LL_REQUIRE_MINOR (1 << 2) +#define LL_EXPORTS (1 << 3) +#define LL_DELAY_LOAD (1 << 4) +#define LL_DELTA (1 << 5) + +/* Entries found in sections of type SHT_MIPS_CONFLICT. */ + +typedef Elf32_Addr Elf32_Conflict; + + +/* HPPA specific definitions. */ + +/* Legal values for e_flags field of Elf32_Ehdr. */ + +#define EF_PARISC_TRAPNIL 0x00010000 /* Trap nil pointer dereference. */ +#define EF_PARISC_EXT 0x00020000 /* Program uses arch. extensions. */ +#define EF_PARISC_LSB 0x00040000 /* Program expects little endian. */ +#define EF_PARISC_WIDE 0x00080000 /* Program expects wide mode. */ +#define EF_PARISC_NO_KABP 0x00100000 /* No kernel assisted branch + prediction. */ +#define EF_PARISC_LAZYSWAP 0x00400000 /* Allow lazy swapping. */ +#define EF_PARISC_ARCH 0x0000ffff /* Architecture version. */ + +/* Defined values for `e_flags & EF_PARISC_ARCH' are: */ + +#define EFA_PARISC_1_0 0x020b /* PA-RISC 1.0 big-endian. */ +#define EFA_PARISC_1_1 0x0210 /* PA-RISC 1.1 big-endian. */ +#define EFA_PARISC_2_0 0x0214 /* PA-RISC 2.0 big-endian. */ + +/* Additional section indices. */ + +#define SHN_PARISC_ANSI_COMMON 0xff00 /* Section for tentatively declared + symbols in ANSI C. */ +#define SHN_PARISC_HUGE_COMMON 0xff01 /* Common blocks in huge model. */ + +/* Legal values for sh_type field of Elf32_Shdr. */ + +#define SHT_PARISC_EXT 0x70000000 /* Contains product specific ext. */ +#define SHT_PARISC_UNWIND 0x70000001 /* Unwind information. */ +#define SHT_PARISC_DOC 0x70000002 /* Debug info for optimized code. */ + +/* Legal values for sh_flags field of Elf32_Shdr. */ + +#define SHF_PARISC_SHORT 0x20000000 /* Section with short addressing. */ +#define SHF_PARISC_HUGE 0x40000000 /* Section far from gp. */ +#define SHF_PARISC_SBP 0x80000000 /* Static branch prediction code. */ + +/* Legal values for ST_TYPE subfield of st_info (symbol type). */ + +#define STT_PARISC_MILLICODE 13 /* Millicode function entry point. */ + +#define STT_HP_OPAQUE (STT_LOOS + 0x1) +#define STT_HP_STUB (STT_LOOS + 0x2) + +/* HPPA relocs. */ + +#define R_PARISC_NONE 0 /* No reloc. */ +#define R_PARISC_DIR32 1 /* Direct 32-bit reference. */ +#define R_PARISC_DIR21L 2 /* Left 21 bits of eff. address. */ +#define R_PARISC_DIR17R 3 /* Right 17 bits of eff. address. */ +#define R_PARISC_DIR17F 4 /* 17 bits of eff. address. */ +#define R_PARISC_DIR14R 6 /* Right 14 bits of eff. address. */ +#define R_PARISC_PCREL32 9 /* 32-bit rel. address. */ +#define R_PARISC_PCREL21L 10 /* Left 21 bits of rel. address. */ +#define R_PARISC_PCREL17R 11 /* Right 17 bits of rel. address. */ +#define R_PARISC_PCREL17F 12 /* 17 bits of rel. address. */ +#define R_PARISC_PCREL14R 14 /* Right 14 bits of rel. address. */ +#define R_PARISC_DPREL21L 18 /* Left 21 bits of rel. address. */ +#define R_PARISC_DPREL14R 22 /* Right 14 bits of rel. address. */ +#define R_PARISC_GPREL21L 26 /* GP-relative, left 21 bits. */ +#define R_PARISC_GPREL14R 30 /* GP-relative, right 14 bits. */ +#define R_PARISC_LTOFF21L 34 /* LT-relative, left 21 bits. */ +#define R_PARISC_LTOFF14R 38 /* LT-relative, right 14 bits. */ +#define R_PARISC_SECREL32 41 /* 32 bits section rel. address. */ +#define R_PARISC_SEGBASE 48 /* No relocation, set segment base. */ +#define R_PARISC_SEGREL32 49 /* 32 bits segment rel. address. */ +#define R_PARISC_PLTOFF21L 50 /* PLT rel. address, left 21 bits. */ +#define R_PARISC_PLTOFF14R 54 /* PLT rel. address, right 14 bits. */ +#define R_PARISC_LTOFF_FPTR32 57 /* 32 bits LT-rel. function pointer. */ +#define R_PARISC_LTOFF_FPTR21L 58 /* LT-rel. fct ptr, left 21 bits. */ +#define R_PARISC_LTOFF_FPTR14R 62 /* LT-rel. fct ptr, right 14 bits. */ +#define R_PARISC_FPTR64 64 /* 64 bits function address. */ +#define R_PARISC_PLABEL32 65 /* 32 bits function address. */ +#define R_PARISC_PLABEL21L 66 /* Left 21 bits of fdesc address. */ +#define R_PARISC_PLABEL14R 70 /* Right 14 bits of fdesc address. */ +#define R_PARISC_PCREL64 72 /* 64 bits PC-rel. address. */ +#define R_PARISC_PCREL22F 74 /* 22 bits PC-rel. address. */ +#define R_PARISC_PCREL14WR 75 /* PC-rel. address, right 14 bits. */ +#define R_PARISC_PCREL14DR 76 /* PC rel. address, right 14 bits. */ +#define R_PARISC_PCREL16F 77 /* 16 bits PC-rel. address. */ +#define R_PARISC_PCREL16WF 78 /* 16 bits PC-rel. address. */ +#define R_PARISC_PCREL16DF 79 /* 16 bits PC-rel. address. */ +#define R_PARISC_DIR64 80 /* 64 bits of eff. address. */ +#define R_PARISC_DIR14WR 83 /* 14 bits of eff. address. */ +#define R_PARISC_DIR14DR 84 /* 14 bits of eff. address. */ +#define R_PARISC_DIR16F 85 /* 16 bits of eff. address. */ +#define R_PARISC_DIR16WF 86 /* 16 bits of eff. address. */ +#define R_PARISC_DIR16DF 87 /* 16 bits of eff. address. */ +#define R_PARISC_GPREL64 88 /* 64 bits of GP-rel. address. */ +#define R_PARISC_GPREL14WR 91 /* GP-rel. address, right 14 bits. */ +#define R_PARISC_GPREL14DR 92 /* GP-rel. address, right 14 bits. */ +#define R_PARISC_GPREL16F 93 /* 16 bits GP-rel. address. */ +#define R_PARISC_GPREL16WF 94 /* 16 bits GP-rel. address. */ +#define R_PARISC_GPREL16DF 95 /* 16 bits GP-rel. address. */ +#define R_PARISC_LTOFF64 96 /* 64 bits LT-rel. address. */ +#define R_PARISC_LTOFF14WR 99 /* LT-rel. address, right 14 bits. */ +#define R_PARISC_LTOFF14DR 100 /* LT-rel. address, right 14 bits. */ +#define R_PARISC_LTOFF16F 101 /* 16 bits LT-rel. address. */ +#define R_PARISC_LTOFF16WF 102 /* 16 bits LT-rel. address. */ +#define R_PARISC_LTOFF16DF 103 /* 16 bits LT-rel. address. */ +#define R_PARISC_SECREL64 104 /* 64 bits section rel. address. */ +#define R_PARISC_SEGREL64 112 /* 64 bits segment rel. address. */ +#define R_PARISC_PLTOFF14WR 115 /* PLT-rel. address, right 14 bits. */ +#define R_PARISC_PLTOFF14DR 116 /* PLT-rel. address, right 14 bits. */ +#define R_PARISC_PLTOFF16F 117 /* 16 bits LT-rel. address. */ +#define R_PARISC_PLTOFF16WF 118 /* 16 bits PLT-rel. address. */ +#define R_PARISC_PLTOFF16DF 119 /* 16 bits PLT-rel. address. */ +#define R_PARISC_LTOFF_FPTR64 120 /* 64 bits LT-rel. function ptr. */ +#define R_PARISC_LTOFF_FPTR14WR 123 /* LT-rel. fct. ptr., right 14 bits. */ +#define R_PARISC_LTOFF_FPTR14DR 124 /* LT-rel. fct. ptr., right 14 bits. */ +#define R_PARISC_LTOFF_FPTR16F 125 /* 16 bits LT-rel. function ptr. */ +#define R_PARISC_LTOFF_FPTR16WF 126 /* 16 bits LT-rel. function ptr. */ +#define R_PARISC_LTOFF_FPTR16DF 127 /* 16 bits LT-rel. function ptr. */ +#define R_PARISC_LORESERVE 128 +#define R_PARISC_COPY 128 /* Copy relocation. */ +#define R_PARISC_IPLT 129 /* Dynamic reloc, imported PLT */ +#define R_PARISC_EPLT 130 /* Dynamic reloc, exported PLT */ +#define R_PARISC_TPREL32 153 /* 32 bits TP-rel. address. */ +#define R_PARISC_TPREL21L 154 /* TP-rel. address, left 21 bits. */ +#define R_PARISC_TPREL14R 158 /* TP-rel. address, right 14 bits. */ +#define R_PARISC_LTOFF_TP21L 162 /* LT-TP-rel. address, left 21 bits. */ +#define R_PARISC_LTOFF_TP14R 166 /* LT-TP-rel. address, right 14 bits.*/ +#define R_PARISC_LTOFF_TP14F 167 /* 14 bits LT-TP-rel. address. */ +#define R_PARISC_TPREL64 216 /* 64 bits TP-rel. address. */ +#define R_PARISC_TPREL14WR 219 /* TP-rel. address, right 14 bits. */ +#define R_PARISC_TPREL14DR 220 /* TP-rel. address, right 14 bits. */ +#define R_PARISC_TPREL16F 221 /* 16 bits TP-rel. address. */ +#define R_PARISC_TPREL16WF 222 /* 16 bits TP-rel. address. */ +#define R_PARISC_TPREL16DF 223 /* 16 bits TP-rel. address. */ +#define R_PARISC_LTOFF_TP64 224 /* 64 bits LT-TP-rel. address. */ +#define R_PARISC_LTOFF_TP14WR 227 /* LT-TP-rel. address, right 14 bits.*/ +#define R_PARISC_LTOFF_TP14DR 228 /* LT-TP-rel. address, right 14 bits.*/ +#define R_PARISC_LTOFF_TP16F 229 /* 16 bits LT-TP-rel. address. */ +#define R_PARISC_LTOFF_TP16WF 230 /* 16 bits LT-TP-rel. address. */ +#define R_PARISC_LTOFF_TP16DF 231 /* 16 bits LT-TP-rel. address. */ +#define R_PARISC_GNU_VTENTRY 232 +#define R_PARISC_GNU_VTINHERIT 233 +#define R_PARISC_TLS_GD21L 234 /* GD 21-bit left. */ +#define R_PARISC_TLS_GD14R 235 /* GD 14-bit right. */ +#define R_PARISC_TLS_GDCALL 236 /* GD call to __t_g_a. */ +#define R_PARISC_TLS_LDM21L 237 /* LD module 21-bit left. */ +#define R_PARISC_TLS_LDM14R 238 /* LD module 14-bit right. */ +#define R_PARISC_TLS_LDMCALL 239 /* LD module call to __t_g_a. */ +#define R_PARISC_TLS_LDO21L 240 /* LD offset 21-bit left. */ +#define R_PARISC_TLS_LDO14R 241 /* LD offset 14-bit right. */ +#define R_PARISC_TLS_DTPMOD32 242 /* DTP module 32-bit. */ +#define R_PARISC_TLS_DTPMOD64 243 /* DTP module 64-bit. */ +#define R_PARISC_TLS_DTPOFF32 244 /* DTP offset 32-bit. */ +#define R_PARISC_TLS_DTPOFF64 245 /* DTP offset 32-bit. */ +#define R_PARISC_TLS_LE21L R_PARISC_TPREL21L +#define R_PARISC_TLS_LE14R R_PARISC_TPREL14R +#define R_PARISC_TLS_IE21L R_PARISC_LTOFF_TP21L +#define R_PARISC_TLS_IE14R R_PARISC_LTOFF_TP14R +#define R_PARISC_TLS_TPREL32 R_PARISC_TPREL32 +#define R_PARISC_TLS_TPREL64 R_PARISC_TPREL64 +#define R_PARISC_HIRESERVE 255 + +/* Legal values for p_type field of Elf32_Phdr/Elf64_Phdr. */ + +#define PT_HP_TLS (PT_LOOS + 0x0) +#define PT_HP_CORE_NONE (PT_LOOS + 0x1) +#define PT_HP_CORE_VERSION (PT_LOOS + 0x2) +#define PT_HP_CORE_KERNEL (PT_LOOS + 0x3) +#define PT_HP_CORE_COMM (PT_LOOS + 0x4) +#define PT_HP_CORE_PROC (PT_LOOS + 0x5) +#define PT_HP_CORE_LOADABLE (PT_LOOS + 0x6) +#define PT_HP_CORE_STACK (PT_LOOS + 0x7) +#define PT_HP_CORE_SHM (PT_LOOS + 0x8) +#define PT_HP_CORE_MMF (PT_LOOS + 0x9) +#define PT_HP_PARALLEL (PT_LOOS + 0x10) +#define PT_HP_FASTBIND (PT_LOOS + 0x11) +#define PT_HP_OPT_ANNOT (PT_LOOS + 0x12) +#define PT_HP_HSL_ANNOT (PT_LOOS + 0x13) +#define PT_HP_STACK (PT_LOOS + 0x14) + +#define PT_PARISC_ARCHEXT 0x70000000 +#define PT_PARISC_UNWIND 0x70000001 + +/* Legal values for p_flags field of Elf32_Phdr/Elf64_Phdr. */ + +#define PF_PARISC_SBP 0x08000000 + +#define PF_HP_PAGE_SIZE 0x00100000 +#define PF_HP_FAR_SHARED 0x00200000 +#define PF_HP_NEAR_SHARED 0x00400000 +#define PF_HP_CODE 0x01000000 +#define PF_HP_MODIFY 0x02000000 +#define PF_HP_LAZYSWAP 0x04000000 +#define PF_HP_SBP 0x08000000 + + +/* Alpha specific definitions. */ + +/* Legal values for e_flags field of Elf64_Ehdr. */ + +#define EF_ALPHA_32BIT 1 /* All addresses must be < 2GB. */ +#define EF_ALPHA_CANRELAX 2 /* Relocations for relaxing exist. */ + +/* Legal values for sh_type field of Elf64_Shdr. */ + +/* These two are primarily concerned with ECOFF debugging info. */ +#define SHT_ALPHA_DEBUG 0x70000001 +#define SHT_ALPHA_REGINFO 0x70000002 + +/* Legal values for sh_flags field of Elf64_Shdr. */ + +#define SHF_ALPHA_GPREL 0x10000000 + +/* Legal values for st_other field of Elf64_Sym. */ +#define STO_ALPHA_NOPV 0x80 /* No PV required. */ +#define STO_ALPHA_STD_GPLOAD 0x88 /* PV only used for initial ldgp. */ + +/* Alpha relocs. */ + +#define R_ALPHA_NONE 0 /* No reloc */ +#define R_ALPHA_REFLONG 1 /* Direct 32 bit */ +#define R_ALPHA_REFQUAD 2 /* Direct 64 bit */ +#define R_ALPHA_GPREL32 3 /* GP relative 32 bit */ +#define R_ALPHA_LITERAL 4 /* GP relative 16 bit w/optimization */ +#define R_ALPHA_LITUSE 5 /* Optimization hint for LITERAL */ +#define R_ALPHA_GPDISP 6 /* Add displacement to GP */ +#define R_ALPHA_BRADDR 7 /* PC+4 relative 23 bit shifted */ +#define R_ALPHA_HINT 8 /* PC+4 relative 16 bit shifted */ +#define R_ALPHA_SREL16 9 /* PC relative 16 bit */ +#define R_ALPHA_SREL32 10 /* PC relative 32 bit */ +#define R_ALPHA_SREL64 11 /* PC relative 64 bit */ +#define R_ALPHA_GPRELHIGH 17 /* GP relative 32 bit, high 16 bits */ +#define R_ALPHA_GPRELLOW 18 /* GP relative 32 bit, low 16 bits */ +#define R_ALPHA_GPREL16 19 /* GP relative 16 bit */ +#define R_ALPHA_COPY 24 /* Copy symbol at runtime */ +#define R_ALPHA_GLOB_DAT 25 /* Create GOT entry */ +#define R_ALPHA_JMP_SLOT 26 /* Create PLT entry */ +#define R_ALPHA_RELATIVE 27 /* Adjust by program base */ +#define R_ALPHA_TLS_GD_HI 28 +#define R_ALPHA_TLSGD 29 +#define R_ALPHA_TLS_LDM 30 +#define R_ALPHA_DTPMOD64 31 +#define R_ALPHA_GOTDTPREL 32 +#define R_ALPHA_DTPREL64 33 +#define R_ALPHA_DTPRELHI 34 +#define R_ALPHA_DTPRELLO 35 +#define R_ALPHA_DTPREL16 36 +#define R_ALPHA_GOTTPREL 37 +#define R_ALPHA_TPREL64 38 +#define R_ALPHA_TPRELHI 39 +#define R_ALPHA_TPRELLO 40 +#define R_ALPHA_TPREL16 41 +/* Keep this the last entry. */ +#define R_ALPHA_NUM 46 + +/* Magic values of the LITUSE relocation addend. */ +#define LITUSE_ALPHA_ADDR 0 +#define LITUSE_ALPHA_BASE 1 +#define LITUSE_ALPHA_BYTOFF 2 +#define LITUSE_ALPHA_JSR 3 +#define LITUSE_ALPHA_TLS_GD 4 +#define LITUSE_ALPHA_TLS_LDM 5 + +/* Legal values for d_tag of Elf64_Dyn. */ +#define DT_ALPHA_PLTRO (DT_LOPROC + 0) +#define DT_ALPHA_NUM 1 + +/* PowerPC specific declarations */ + +/* Values for Elf32/64_Ehdr.e_flags. */ +#define EF_PPC_EMB 0x80000000 /* PowerPC embedded flag */ + +/* Cygnus local bits below */ +#define EF_PPC_RELOCATABLE 0x00010000 /* PowerPC -mrelocatable flag*/ +#define EF_PPC_RELOCATABLE_LIB 0x00008000 /* PowerPC -mrelocatable-lib + flag */ + +/* PowerPC relocations defined by the ABIs */ +#define R_PPC_NONE 0 +#define R_PPC_ADDR32 1 /* 32bit absolute address */ +#define R_PPC_ADDR24 2 /* 26bit address, 2 bits ignored. */ +#define R_PPC_ADDR16 3 /* 16bit absolute address */ +#define R_PPC_ADDR16_LO 4 /* lower 16bit of absolute address */ +#define R_PPC_ADDR16_HI 5 /* high 16bit of absolute address */ +#define R_PPC_ADDR16_HA 6 /* adjusted high 16bit */ +#define R_PPC_ADDR14 7 /* 16bit address, 2 bits ignored */ +#define R_PPC_ADDR14_BRTAKEN 8 +#define R_PPC_ADDR14_BRNTAKEN 9 +#define R_PPC_REL24 10 /* PC relative 26 bit */ +#define R_PPC_REL14 11 /* PC relative 16 bit */ +#define R_PPC_REL14_BRTAKEN 12 +#define R_PPC_REL14_BRNTAKEN 13 +#define R_PPC_GOT16 14 +#define R_PPC_GOT16_LO 15 +#define R_PPC_GOT16_HI 16 +#define R_PPC_GOT16_HA 17 +#define R_PPC_PLTREL24 18 +#define R_PPC_COPY 19 +#define R_PPC_GLOB_DAT 20 +#define R_PPC_JMP_SLOT 21 +#define R_PPC_RELATIVE 22 +#define R_PPC_LOCAL24PC 23 +#define R_PPC_UADDR32 24 +#define R_PPC_UADDR16 25 +#define R_PPC_REL32 26 +#define R_PPC_PLT32 27 +#define R_PPC_PLTREL32 28 +#define R_PPC_PLT16_LO 29 +#define R_PPC_PLT16_HI 30 +#define R_PPC_PLT16_HA 31 +#define R_PPC_SDAREL16 32 +#define R_PPC_SECTOFF 33 +#define R_PPC_SECTOFF_LO 34 +#define R_PPC_SECTOFF_HI 35 +#define R_PPC_SECTOFF_HA 36 + +/* PowerPC relocations defined for the TLS access ABI. */ +#define R_PPC_TLS 67 /* none (sym+add)@tls */ +#define R_PPC_DTPMOD32 68 /* word32 (sym+add)@dtpmod */ +#define R_PPC_TPREL16 69 /* half16* (sym+add)@tprel */ +#define R_PPC_TPREL16_LO 70 /* half16 (sym+add)@tprel@l */ +#define R_PPC_TPREL16_HI 71 /* half16 (sym+add)@tprel@h */ +#define R_PPC_TPREL16_HA 72 /* half16 (sym+add)@tprel@ha */ +#define R_PPC_TPREL32 73 /* word32 (sym+add)@tprel */ +#define R_PPC_DTPREL16 74 /* half16* (sym+add)@dtprel */ +#define R_PPC_DTPREL16_LO 75 /* half16 (sym+add)@dtprel@l */ +#define R_PPC_DTPREL16_HI 76 /* half16 (sym+add)@dtprel@h */ +#define R_PPC_DTPREL16_HA 77 /* half16 (sym+add)@dtprel@ha */ +#define R_PPC_DTPREL32 78 /* word32 (sym+add)@dtprel */ +#define R_PPC_GOT_TLSGD16 79 /* half16* (sym+add)@got@tlsgd */ +#define R_PPC_GOT_TLSGD16_LO 80 /* half16 (sym+add)@got@tlsgd@l */ +#define R_PPC_GOT_TLSGD16_HI 81 /* half16 (sym+add)@got@tlsgd@h */ +#define R_PPC_GOT_TLSGD16_HA 82 /* half16 (sym+add)@got@tlsgd@ha */ +#define R_PPC_GOT_TLSLD16 83 /* half16* (sym+add)@got@tlsld */ +#define R_PPC_GOT_TLSLD16_LO 84 /* half16 (sym+add)@got@tlsld@l */ +#define R_PPC_GOT_TLSLD16_HI 85 /* half16 (sym+add)@got@tlsld@h */ +#define R_PPC_GOT_TLSLD16_HA 86 /* half16 (sym+add)@got@tlsld@ha */ +#define R_PPC_GOT_TPREL16 87 /* half16* (sym+add)@got@tprel */ +#define R_PPC_GOT_TPREL16_LO 88 /* half16 (sym+add)@got@tprel@l */ +#define R_PPC_GOT_TPREL16_HI 89 /* half16 (sym+add)@got@tprel@h */ +#define R_PPC_GOT_TPREL16_HA 90 /* half16 (sym+add)@got@tprel@ha */ +#define R_PPC_GOT_DTPREL16 91 /* half16* (sym+add)@got@dtprel */ +#define R_PPC_GOT_DTPREL16_LO 92 /* half16* (sym+add)@got@dtprel@l */ +#define R_PPC_GOT_DTPREL16_HI 93 /* half16* (sym+add)@got@dtprel@h */ +#define R_PPC_GOT_DTPREL16_HA 94 /* half16* (sym+add)@got@dtprel@ha */ + +/* The remaining relocs are from the Embedded ELF ABI, and are not + in the SVR4 ELF ABI. */ +#define R_PPC_EMB_NADDR32 101 +#define R_PPC_EMB_NADDR16 102 +#define R_PPC_EMB_NADDR16_LO 103 +#define R_PPC_EMB_NADDR16_HI 104 +#define R_PPC_EMB_NADDR16_HA 105 +#define R_PPC_EMB_SDAI16 106 +#define R_PPC_EMB_SDA2I16 107 +#define R_PPC_EMB_SDA2REL 108 +#define R_PPC_EMB_SDA21 109 /* 16 bit offset in SDA */ +#define R_PPC_EMB_MRKREF 110 +#define R_PPC_EMB_RELSEC16 111 +#define R_PPC_EMB_RELST_LO 112 +#define R_PPC_EMB_RELST_HI 113 +#define R_PPC_EMB_RELST_HA 114 +#define R_PPC_EMB_BIT_FLD 115 +#define R_PPC_EMB_RELSDA 116 /* 16 bit relative offset in SDA */ + +/* Diab tool relocations. */ +#define R_PPC_DIAB_SDA21_LO 180 /* like EMB_SDA21, but lower 16 bit */ +#define R_PPC_DIAB_SDA21_HI 181 /* like EMB_SDA21, but high 16 bit */ +#define R_PPC_DIAB_SDA21_HA 182 /* like EMB_SDA21, adjusted high 16 */ +#define R_PPC_DIAB_RELSDA_LO 183 /* like EMB_RELSDA, but lower 16 bit */ +#define R_PPC_DIAB_RELSDA_HI 184 /* like EMB_RELSDA, but high 16 bit */ +#define R_PPC_DIAB_RELSDA_HA 185 /* like EMB_RELSDA, adjusted high 16 */ + +/* GNU extension to support local ifunc. */ +#define R_PPC_IRELATIVE 248 + +/* GNU relocs used in PIC code sequences. */ +#define R_PPC_REL16 249 /* half16 (sym+add-.) */ +#define R_PPC_REL16_LO 250 /* half16 (sym+add-.)@l */ +#define R_PPC_REL16_HI 251 /* half16 (sym+add-.)@h */ +#define R_PPC_REL16_HA 252 /* half16 (sym+add-.)@ha */ + +/* This is a phony reloc to handle any old fashioned TOC16 references + that may still be in object files. */ +#define R_PPC_TOC16 255 + +/* PowerPC specific values for the Dyn d_tag field. */ +#define DT_PPC_GOT (DT_LOPROC + 0) +#define DT_PPC_NUM 1 + +/* PowerPC64 relocations defined by the ABIs */ +#define R_PPC64_NONE R_PPC_NONE +#define R_PPC64_ADDR32 R_PPC_ADDR32 /* 32bit absolute address */ +#define R_PPC64_ADDR24 R_PPC_ADDR24 /* 26bit address, word aligned */ +#define R_PPC64_ADDR16 R_PPC_ADDR16 /* 16bit absolute address */ +#define R_PPC64_ADDR16_LO R_PPC_ADDR16_LO /* lower 16bits of address */ +#define R_PPC64_ADDR16_HI R_PPC_ADDR16_HI /* high 16bits of address. */ +#define R_PPC64_ADDR16_HA R_PPC_ADDR16_HA /* adjusted high 16bits. */ +#define R_PPC64_ADDR14 R_PPC_ADDR14 /* 16bit address, word aligned */ +#define R_PPC64_ADDR14_BRTAKEN R_PPC_ADDR14_BRTAKEN +#define R_PPC64_ADDR14_BRNTAKEN R_PPC_ADDR14_BRNTAKEN +#define R_PPC64_REL24 R_PPC_REL24 /* PC-rel. 26 bit, word aligned */ +#define R_PPC64_REL14 R_PPC_REL14 /* PC relative 16 bit */ +#define R_PPC64_REL14_BRTAKEN R_PPC_REL14_BRTAKEN +#define R_PPC64_REL14_BRNTAKEN R_PPC_REL14_BRNTAKEN +#define R_PPC64_GOT16 R_PPC_GOT16 +#define R_PPC64_GOT16_LO R_PPC_GOT16_LO +#define R_PPC64_GOT16_HI R_PPC_GOT16_HI +#define R_PPC64_GOT16_HA R_PPC_GOT16_HA + +#define R_PPC64_COPY R_PPC_COPY +#define R_PPC64_GLOB_DAT R_PPC_GLOB_DAT +#define R_PPC64_JMP_SLOT R_PPC_JMP_SLOT +#define R_PPC64_RELATIVE R_PPC_RELATIVE + +#define R_PPC64_UADDR32 R_PPC_UADDR32 +#define R_PPC64_UADDR16 R_PPC_UADDR16 +#define R_PPC64_REL32 R_PPC_REL32 +#define R_PPC64_PLT32 R_PPC_PLT32 +#define R_PPC64_PLTREL32 R_PPC_PLTREL32 +#define R_PPC64_PLT16_LO R_PPC_PLT16_LO +#define R_PPC64_PLT16_HI R_PPC_PLT16_HI +#define R_PPC64_PLT16_HA R_PPC_PLT16_HA + +#define R_PPC64_SECTOFF R_PPC_SECTOFF +#define R_PPC64_SECTOFF_LO R_PPC_SECTOFF_LO +#define R_PPC64_SECTOFF_HI R_PPC_SECTOFF_HI +#define R_PPC64_SECTOFF_HA R_PPC_SECTOFF_HA +#define R_PPC64_ADDR30 37 /* word30 (S + A - P) >> 2 */ +#define R_PPC64_ADDR64 38 /* doubleword64 S + A */ +#define R_PPC64_ADDR16_HIGHER 39 /* half16 #higher(S + A) */ +#define R_PPC64_ADDR16_HIGHERA 40 /* half16 #highera(S + A) */ +#define R_PPC64_ADDR16_HIGHEST 41 /* half16 #highest(S + A) */ +#define R_PPC64_ADDR16_HIGHESTA 42 /* half16 #highesta(S + A) */ +#define R_PPC64_UADDR64 43 /* doubleword64 S + A */ +#define R_PPC64_REL64 44 /* doubleword64 S + A - P */ +#define R_PPC64_PLT64 45 /* doubleword64 L + A */ +#define R_PPC64_PLTREL64 46 /* doubleword64 L + A - P */ +#define R_PPC64_TOC16 47 /* half16* S + A - .TOC */ +#define R_PPC64_TOC16_LO 48 /* half16 #lo(S + A - .TOC.) */ +#define R_PPC64_TOC16_HI 49 /* half16 #hi(S + A - .TOC.) */ +#define R_PPC64_TOC16_HA 50 /* half16 #ha(S + A - .TOC.) */ +#define R_PPC64_TOC 51 /* doubleword64 .TOC */ +#define R_PPC64_PLTGOT16 52 /* half16* M + A */ +#define R_PPC64_PLTGOT16_LO 53 /* half16 #lo(M + A) */ +#define R_PPC64_PLTGOT16_HI 54 /* half16 #hi(M + A) */ +#define R_PPC64_PLTGOT16_HA 55 /* half16 #ha(M + A) */ + +#define R_PPC64_ADDR16_DS 56 /* half16ds* (S + A) >> 2 */ +#define R_PPC64_ADDR16_LO_DS 57 /* half16ds #lo(S + A) >> 2 */ +#define R_PPC64_GOT16_DS 58 /* half16ds* (G + A) >> 2 */ +#define R_PPC64_GOT16_LO_DS 59 /* half16ds #lo(G + A) >> 2 */ +#define R_PPC64_PLT16_LO_DS 60 /* half16ds #lo(L + A) >> 2 */ +#define R_PPC64_SECTOFF_DS 61 /* half16ds* (R + A) >> 2 */ +#define R_PPC64_SECTOFF_LO_DS 62 /* half16ds #lo(R + A) >> 2 */ +#define R_PPC64_TOC16_DS 63 /* half16ds* (S + A - .TOC.) >> 2 */ +#define R_PPC64_TOC16_LO_DS 64 /* half16ds #lo(S + A - .TOC.) >> 2 */ +#define R_PPC64_PLTGOT16_DS 65 /* half16ds* (M + A) >> 2 */ +#define R_PPC64_PLTGOT16_LO_DS 66 /* half16ds #lo(M + A) >> 2 */ + +/* PowerPC64 relocations defined for the TLS access ABI. */ +#define R_PPC64_TLS 67 /* none (sym+add)@tls */ +#define R_PPC64_DTPMOD64 68 /* doubleword64 (sym+add)@dtpmod */ +#define R_PPC64_TPREL16 69 /* half16* (sym+add)@tprel */ +#define R_PPC64_TPREL16_LO 70 /* half16 (sym+add)@tprel@l */ +#define R_PPC64_TPREL16_HI 71 /* half16 (sym+add)@tprel@h */ +#define R_PPC64_TPREL16_HA 72 /* half16 (sym+add)@tprel@ha */ +#define R_PPC64_TPREL64 73 /* doubleword64 (sym+add)@tprel */ +#define R_PPC64_DTPREL16 74 /* half16* (sym+add)@dtprel */ +#define R_PPC64_DTPREL16_LO 75 /* half16 (sym+add)@dtprel@l */ +#define R_PPC64_DTPREL16_HI 76 /* half16 (sym+add)@dtprel@h */ +#define R_PPC64_DTPREL16_HA 77 /* half16 (sym+add)@dtprel@ha */ +#define R_PPC64_DTPREL64 78 /* doubleword64 (sym+add)@dtprel */ +#define R_PPC64_GOT_TLSGD16 79 /* half16* (sym+add)@got@tlsgd */ +#define R_PPC64_GOT_TLSGD16_LO 80 /* half16 (sym+add)@got@tlsgd@l */ +#define R_PPC64_GOT_TLSGD16_HI 81 /* half16 (sym+add)@got@tlsgd@h */ +#define R_PPC64_GOT_TLSGD16_HA 82 /* half16 (sym+add)@got@tlsgd@ha */ +#define R_PPC64_GOT_TLSLD16 83 /* half16* (sym+add)@got@tlsld */ +#define R_PPC64_GOT_TLSLD16_LO 84 /* half16 (sym+add)@got@tlsld@l */ +#define R_PPC64_GOT_TLSLD16_HI 85 /* half16 (sym+add)@got@tlsld@h */ +#define R_PPC64_GOT_TLSLD16_HA 86 /* half16 (sym+add)@got@tlsld@ha */ +#define R_PPC64_GOT_TPREL16_DS 87 /* half16ds* (sym+add)@got@tprel */ +#define R_PPC64_GOT_TPREL16_LO_DS 88 /* half16ds (sym+add)@got@tprel@l */ +#define R_PPC64_GOT_TPREL16_HI 89 /* half16 (sym+add)@got@tprel@h */ +#define R_PPC64_GOT_TPREL16_HA 90 /* half16 (sym+add)@got@tprel@ha */ +#define R_PPC64_GOT_DTPREL16_DS 91 /* half16ds* (sym+add)@got@dtprel */ +#define R_PPC64_GOT_DTPREL16_LO_DS 92 /* half16ds (sym+add)@got@dtprel@l */ +#define R_PPC64_GOT_DTPREL16_HI 93 /* half16 (sym+add)@got@dtprel@h */ +#define R_PPC64_GOT_DTPREL16_HA 94 /* half16 (sym+add)@got@dtprel@ha */ +#define R_PPC64_TPREL16_DS 95 /* half16ds* (sym+add)@tprel */ +#define R_PPC64_TPREL16_LO_DS 96 /* half16ds (sym+add)@tprel@l */ +#define R_PPC64_TPREL16_HIGHER 97 /* half16 (sym+add)@tprel@higher */ +#define R_PPC64_TPREL16_HIGHERA 98 /* half16 (sym+add)@tprel@highera */ +#define R_PPC64_TPREL16_HIGHEST 99 /* half16 (sym+add)@tprel@highest */ +#define R_PPC64_TPREL16_HIGHESTA 100 /* half16 (sym+add)@tprel@highesta */ +#define R_PPC64_DTPREL16_DS 101 /* half16ds* (sym+add)@dtprel */ +#define R_PPC64_DTPREL16_LO_DS 102 /* half16ds (sym+add)@dtprel@l */ +#define R_PPC64_DTPREL16_HIGHER 103 /* half16 (sym+add)@dtprel@higher */ +#define R_PPC64_DTPREL16_HIGHERA 104 /* half16 (sym+add)@dtprel@highera */ +#define R_PPC64_DTPREL16_HIGHEST 105 /* half16 (sym+add)@dtprel@highest */ +#define R_PPC64_DTPREL16_HIGHESTA 106 /* half16 (sym+add)@dtprel@highesta */ + +/* GNU extension to support local ifunc. */ +#define R_PPC64_JMP_IREL 247 +#define R_PPC64_IRELATIVE 248 +#define R_PPC64_REL16 249 /* half16 (sym+add-.) */ +#define R_PPC64_REL16_LO 250 /* half16 (sym+add-.)@l */ +#define R_PPC64_REL16_HI 251 /* half16 (sym+add-.)@h */ +#define R_PPC64_REL16_HA 252 /* half16 (sym+add-.)@ha */ + +/* PowerPC64 specific values for the Dyn d_tag field. */ +#define DT_PPC64_GLINK (DT_LOPROC + 0) +#define DT_PPC64_OPD (DT_LOPROC + 1) +#define DT_PPC64_OPDSZ (DT_LOPROC + 2) +#define DT_PPC64_NUM 3 + + +/* ARM specific declarations */ + +/* Processor specific flags for the ELF header e_flags field. */ +#define EF_ARM_RELEXEC 0x01 +#define EF_ARM_HASENTRY 0x02 +#define EF_ARM_INTERWORK 0x04 +#define EF_ARM_APCS_26 0x08 +#define EF_ARM_APCS_FLOAT 0x10 +#define EF_ARM_PIC 0x20 +#define EF_ARM_ALIGN8 0x40 /* 8-bit structure alignment is in use */ +#define EF_ARM_NEW_ABI 0x80 +#define EF_ARM_OLD_ABI 0x100 +#define EF_ARM_SOFT_FLOAT 0x200 +#define EF_ARM_VFP_FLOAT 0x400 +#define EF_ARM_MAVERICK_FLOAT 0x800 + +#define EF_ARM_ABI_FLOAT_SOFT 0x200 /* NB conflicts with EF_ARM_SOFT_FLOAT */ +#define EF_ARM_ABI_FLOAT_HARD 0x400 /* NB conflicts with EF_ARM_VFP_FLOAT */ + + +/* Other constants defined in the ARM ELF spec. version B-01. */ +/* NB. These conflict with values defined above. */ +#define EF_ARM_SYMSARESORTED 0x04 +#define EF_ARM_DYNSYMSUSESEGIDX 0x08 +#define EF_ARM_MAPSYMSFIRST 0x10 +#define EF_ARM_EABIMASK 0XFF000000 + +/* Constants defined in AAELF. */ +#define EF_ARM_BE8 0x00800000 +#define EF_ARM_LE8 0x00400000 + +#define EF_ARM_EABI_VERSION(flags) ((flags) & EF_ARM_EABIMASK) +#define EF_ARM_EABI_UNKNOWN 0x00000000 +#define EF_ARM_EABI_VER1 0x01000000 +#define EF_ARM_EABI_VER2 0x02000000 +#define EF_ARM_EABI_VER3 0x03000000 +#define EF_ARM_EABI_VER4 0x04000000 +#define EF_ARM_EABI_VER5 0x05000000 + +/* Additional symbol types for Thumb. */ +#define STT_ARM_TFUNC STT_LOPROC /* A Thumb function. */ +#define STT_ARM_16BIT STT_HIPROC /* A Thumb label. */ + +/* ARM-specific values for sh_flags */ +#define SHF_ARM_ENTRYSECT 0x10000000 /* Section contains an entry point */ +#define SHF_ARM_COMDEF 0x80000000 /* Section may be multiply defined + in the input to a link step. */ + +/* ARM-specific program header flags */ +#define PF_ARM_SB 0x10000000 /* Segment contains the location + addressed by the static base. */ +#define PF_ARM_PI 0x20000000 /* Position-independent segment. */ +#define PF_ARM_ABS 0x40000000 /* Absolute segment. */ + +/* Processor specific values for the Phdr p_type field. */ +#define PT_ARM_EXIDX (PT_LOPROC + 1) /* ARM unwind segment. */ + +/* Processor specific values for the Shdr sh_type field. */ +#define SHT_ARM_EXIDX (SHT_LOPROC + 1) /* ARM unwind section. */ +#define SHT_ARM_PREEMPTMAP (SHT_LOPROC + 2) /* Preemption details. */ +#define SHT_ARM_ATTRIBUTES (SHT_LOPROC + 3) /* ARM attributes section. */ + + +/* AArch64 relocs. */ + +#define R_AARCH64_NONE 0 /* No relocation. */ +#define R_AARCH64_ABS64 257 /* Direct 64 bit. */ +#define R_AARCH64_ABS32 258 /* Direct 32 bit. */ +#define R_AARCH64_ABS16 259 /* Direct 16-bit. */ +#define R_AARCH64_PREL64 260 /* PC-relative 64-bit. */ +#define R_AARCH64_PREL32 261 /* PC-relative 32-bit. */ +#define R_AARCH64_PREL16 262 /* PC-relative 16-bit. */ +#define R_AARCH64_MOVW_UABS_G0 263 /* Dir. MOVZ imm. from bits 15:0. */ +#define R_AARCH64_MOVW_UABS_G0_NC 264 /* Likewise for MOVK; no check. */ +#define R_AARCH64_MOVW_UABS_G1 265 /* Dir. MOVZ imm. from bits 31:16. */ +#define R_AARCH64_MOVW_UABS_G1_NC 266 /* Likewise for MOVK; no check. */ +#define R_AARCH64_MOVW_UABS_G2 267 /* Dir. MOVZ imm. from bits 47:32. */ +#define R_AARCH64_MOVW_UABS_G2_NC 268 /* Likewise for MOVK; no check. */ +#define R_AARCH64_MOVW_UABS_G3 269 /* Dir. MOV{K,Z} imm. from 63:48. */ +#define R_AARCH64_MOVW_SABS_G0 270 /* Dir. MOV{N,Z} imm. from 15:0. */ +#define R_AARCH64_MOVW_SABS_G1 271 /* Dir. MOV{N,Z} imm. from 31:16. */ +#define R_AARCH64_MOVW_SABS_G2 272 /* Dir. MOV{N,Z} imm. from 47:32. */ +#define R_AARCH64_LD_PREL_LO19 273 /* PC-rel. LD imm. from bits 20:2. */ +#define R_AARCH64_ADR_PREL_LO21 274 /* PC-rel. ADR imm. from bits 20:0. */ +#define R_AARCH64_ADR_PREL_PG_HI21 275 /* Page-rel. ADRP imm. from 32:12. */ +#define R_AARCH64_ADR_PREL_PG_HI21_NC 276 /* Likewise; no overflow check. */ +#define R_AARCH64_ADD_ABS_LO12_NC 277 /* Dir. ADD imm. from bits 11:0. */ +#define R_AARCH64_LDST8_ABS_LO12_NC 278 /* Likewise for LD/ST; no check. */ +#define R_AARCH64_TSTBR14 279 /* PC-rel. TBZ/TBNZ imm. from 15:2. */ +#define R_AARCH64_CONDBR19 280 /* PC-rel. cond. br. imm. from 20:2. */ +#define R_AARCH64_JUMP26 282 /* PC-rel. B imm. from bits 27:2. */ +#define R_AARCH64_CALL26 283 /* Likewise for CALL. */ +#define R_AARCH64_LDST16_ABS_LO12_NC 284 /* Dir. ADD imm. from bits 11:1. */ +#define R_AARCH64_LDST32_ABS_LO12_NC 285 /* Likewise for bits 11:2. */ +#define R_AARCH64_LDST64_ABS_LO12_NC 286 /* Likewise for bits 11:3. */ +#define R_AARCH64_MOVW_PREL_G0 287 /* PC-rel. MOV{N,Z} imm. from 15:0. */ +#define R_AARCH64_MOVW_PREL_G0_NC 288 /* Likewise for MOVK; no check. */ +#define R_AARCH64_MOVW_PREL_G1 289 /* PC-rel. MOV{N,Z} imm. from 31:16. */ +#define R_AARCH64_MOVW_PREL_G1_NC 290 /* Likewise for MOVK; no check. */ +#define R_AARCH64_MOVW_PREL_G2 291 /* PC-rel. MOV{N,Z} imm. from 47:32. */ +#define R_AARCH64_MOVW_PREL_G2_NC 292 /* Likewise for MOVK; no check. */ +#define R_AARCH64_MOVW_PREL_G3 293 /* PC-rel. MOV{N,Z} imm. from 63:48. */ +#define R_AARCH64_LDST128_ABS_LO12_NC 299 /* Dir. ADD imm. from bits 11:4. */ +#define R_AARCH64_MOVW_GOTOFF_G0 300 /* GOT-rel. off. MOV{N,Z} imm. 15:0. */ +#define R_AARCH64_MOVW_GOTOFF_G0_NC 301 /* Likewise for MOVK; no check. */ +#define R_AARCH64_MOVW_GOTOFF_G1 302 /* GOT-rel. o. MOV{N,Z} imm. 31:16. */ +#define R_AARCH64_MOVW_GOTOFF_G1_NC 303 /* Likewise for MOVK; no check. */ +#define R_AARCH64_MOVW_GOTOFF_G2 304 /* GOT-rel. o. MOV{N,Z} imm. 47:32. */ +#define R_AARCH64_MOVW_GOTOFF_G2_NC 305 /* Likewise for MOVK; no check. */ +#define R_AARCH64_MOVW_GOTOFF_G3 306 /* GOT-rel. o. MOV{N,Z} imm. 63:48. */ +#define R_AARCH64_GOTREL64 307 /* GOT-relative 64-bit. */ +#define R_AARCH64_GOTREL32 308 /* GOT-relative 32-bit. */ +#define R_AARCH64_GOT_LD_PREL19 309 /* PC-rel. GOT off. load imm. 20:2. */ +#define R_AARCH64_LD64_GOTOFF_LO15 310 /* GOT-rel. off. LD/ST imm. 14:3. */ +#define R_AARCH64_ADR_GOT_PAGE 311 /* P-page-rel. GOT off. ADRP 32:12. */ +#define R_AARCH64_LD64_GOT_LO12_NC 312 /* Dir. GOT off. LD/ST imm. 11:3. */ +#define R_AARCH64_LD64_GOTPAGE_LO15 313 /* GOT-page-rel. GOT off. LD/ST 14:3 */ +#define R_AARCH64_TLSGD_ADR_PREL21 512 /* PC-relative ADR imm. 20:0. */ +#define R_AARCH64_TLSGD_ADR_PAGE21 513 /* page-rel. ADRP imm. 32:12. */ +#define R_AARCH64_TLSGD_ADD_LO12_NC 514 /* direct ADD imm. from 11:0. */ +#define R_AARCH64_TLSGD_MOVW_G1 515 /* GOT-rel. MOV{N,Z} 31:16. */ +#define R_AARCH64_TLSGD_MOVW_G0_NC 516 /* GOT-rel. MOVK imm. 15:0. */ +#define R_AARCH64_TLSLD_ADR_PREL21 517 /* Like 512; local dynamic model. */ +#define R_AARCH64_TLSLD_ADR_PAGE21 518 /* Like 513; local dynamic model. */ +#define R_AARCH64_TLSLD_ADD_LO12_NC 519 /* Like 514; local dynamic model. */ +#define R_AARCH64_TLSLD_MOVW_G1 520 /* Like 515; local dynamic model. */ +#define R_AARCH64_TLSLD_MOVW_G0_NC 521 /* Like 516; local dynamic model. */ +#define R_AARCH64_TLSLD_LD_PREL19 522 /* TLS PC-rel. load imm. 20:2. */ +#define R_AARCH64_TLSLD_MOVW_DTPREL_G2 523 /* TLS DTP-rel. MOV{N,Z} 47:32. */ +#define R_AARCH64_TLSLD_MOVW_DTPREL_G1 524 /* TLS DTP-rel. MOV{N,Z} 31:16. */ +#define R_AARCH64_TLSLD_MOVW_DTPREL_G1_NC 525 /* Likewise; MOVK; no check. */ +#define R_AARCH64_TLSLD_MOVW_DTPREL_G0 526 /* TLS DTP-rel. MOV{N,Z} 15:0. */ +#define R_AARCH64_TLSLD_MOVW_DTPREL_G0_NC 527 /* Likewise; MOVK; no check. */ +#define R_AARCH64_TLSLD_ADD_DTPREL_HI12 528 /* DTP-rel. ADD imm. from 23:12. */ +#define R_AARCH64_TLSLD_ADD_DTPREL_LO12 529 /* DTP-rel. ADD imm. from 11:0. */ +#define R_AARCH64_TLSLD_ADD_DTPREL_LO12_NC 530 /* Likewise; no ovfl. check. */ +#define R_AARCH64_TLSLD_LDST8_DTPREL_LO12 531 /* DTP-rel. LD/ST imm. 11:0. */ +#define R_AARCH64_TLSLD_LDST8_DTPREL_LO12_NC 532 /* Likewise; no check. */ +#define R_AARCH64_TLSLD_LDST16_DTPREL_LO12 533 /* DTP-rel. LD/ST imm. 11:1. */ +#define R_AARCH64_TLSLD_LDST16_DTPREL_LO12_NC 534 /* Likewise; no check. */ +#define R_AARCH64_TLSLD_LDST32_DTPREL_LO12 535 /* DTP-rel. LD/ST imm. 11:2. */ +#define R_AARCH64_TLSLD_LDST32_DTPREL_LO12_NC 536 /* Likewise; no check. */ +#define R_AARCH64_TLSLD_LDST64_DTPREL_LO12 537 /* DTP-rel. LD/ST imm. 11:3. */ +#define R_AARCH64_TLSLD_LDST64_DTPREL_LO12_NC 538 /* Likewise; no check. */ +#define R_AARCH64_TLSIE_MOVW_GOTTPREL_G1 539 /* GOT-rel. MOV{N,Z} 31:16. */ +#define R_AARCH64_TLSIE_MOVW_GOTTPREL_G0_NC 540 /* GOT-rel. MOVK 15:0. */ +#define R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21 541 /* Page-rel. ADRP 32:12. */ +#define R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC 542 /* Direct LD off. 11:3. */ +#define R_AARCH64_TLSIE_LD_GOTTPREL_PREL19 543 /* PC-rel. load imm. 20:2. */ +#define R_AARCH64_TLSLE_MOVW_TPREL_G2 544 /* TLS TP-rel. MOV{N,Z} 47:32. */ +#define R_AARCH64_TLSLE_MOVW_TPREL_G1 545 /* TLS TP-rel. MOV{N,Z} 31:16. */ +#define R_AARCH64_TLSLE_MOVW_TPREL_G1_NC 546 /* Likewise; MOVK; no check. */ +#define R_AARCH64_TLSLE_MOVW_TPREL_G0 547 /* TLS TP-rel. MOV{N,Z} 15:0. */ +#define R_AARCH64_TLSLE_MOVW_TPREL_G0_NC 548 /* Likewise; MOVK; no check. */ +#define R_AARCH64_TLSLE_ADD_TPREL_HI12 549 /* TP-rel. ADD imm. 23:12. */ +#define R_AARCH64_TLSLE_ADD_TPREL_LO12 550 /* TP-rel. ADD imm. 11:0. */ +#define R_AARCH64_TLSLE_ADD_TPREL_LO12_NC 551 /* Likewise; no ovfl. check. */ +#define R_AARCH64_TLSLE_LDST8_TPREL_LO12 552 /* TP-rel. LD/ST off. 11:0. */ +#define R_AARCH64_TLSLE_LDST8_TPREL_LO12_NC 553 /* Likewise; no ovfl. check. */ +#define R_AARCH64_TLSLE_LDST16_TPREL_LO12 554 /* TP-rel. LD/ST off. 11:1. */ +#define R_AARCH64_TLSLE_LDST16_TPREL_LO12_NC 555 /* Likewise; no check. */ +#define R_AARCH64_TLSLE_LDST32_TPREL_LO12 556 /* TP-rel. LD/ST off. 11:2. */ +#define R_AARCH64_TLSLE_LDST32_TPREL_LO12_NC 557 /* Likewise; no check. */ +#define R_AARCH64_TLSLE_LDST64_TPREL_LO12 558 /* TP-rel. LD/ST off. 11:3. */ +#define R_AARCH64_TLSLE_LDST64_TPREL_LO12_NC 559 /* Likewise; no check. */ +#define R_AARCH64_TLSDESC_LD_PREL19 560 /* PC-rel. load immediate 20:2. */ +#define R_AARCH64_TLSDESC_ADR_PREL21 561 /* PC-rel. ADR immediate 20:0. */ +#define R_AARCH64_TLSDESC_ADR_PAGE21 562 /* Page-rel. ADRP imm. 32:12. */ +#define R_AARCH64_TLSDESC_LD64_LO12 563 /* Direct LD off. from 11:3. */ +#define R_AARCH64_TLSDESC_ADD_LO12 564 /* Direct ADD imm. from 11:0. */ +#define R_AARCH64_TLSDESC_OFF_G1 565 /* GOT-rel. MOV{N,Z} imm. 31:16. */ +#define R_AARCH64_TLSDESC_OFF_G0_NC 566 /* GOT-rel. MOVK imm. 15:0; no ck. */ +#define R_AARCH64_TLSDESC_LDR 567 /* Relax LDR. */ +#define R_AARCH64_TLSDESC_ADD 568 /* Relax ADD. */ +#define R_AARCH64_TLSDESC_CALL 569 /* Relax BLR. */ +#define R_AARCH64_TLSLE_LDST128_TPREL_LO12 570 /* TP-rel. LD/ST off. 11:4. */ +#define R_AARCH64_TLSLE_LDST128_TPREL_LO12_NC 571 /* Likewise; no check. */ +#define R_AARCH64_TLSLD_LDST128_DTPREL_LO12 572 /* DTP-rel. LD/ST imm. 11:4. */ +#define R_AARCH64_TLSLD_LDST128_DTPREL_LO12_NC 573 /* Likewise; no check. */ +#define R_AARCH64_COPY 1024 /* Copy symbol at runtime. */ +#define R_AARCH64_GLOB_DAT 1025 /* Create GOT entry. */ +#define R_AARCH64_JUMP_SLOT 1026 /* Create PLT entry. */ +#define R_AARCH64_RELATIVE 1027 /* Adjust by program base. */ +#define R_AARCH64_TLS_DTPMOD64 1028 /* Module number, 64 bit. */ +#define R_AARCH64_TLS_DTPREL64 1029 /* Module-relative offset, 64 bit. */ +#define R_AARCH64_TLS_TPREL64 1030 /* TP-relative offset, 64 bit. */ +#define R_AARCH64_TLSDESC 1031 /* TLS Descriptor. */ +#define R_AARCH64_IRELATIVE 1032 /* STT_GNU_IFUNC relocation. */ +/* Keep this the last entry. */ +#define R_AARCH64_NUM 1033 + +/* ARM relocs. */ + +#define R_ARM_NONE 0 /* No reloc */ +#define R_ARM_PC24 1 /* PC relative 26 bit branch */ +#define R_ARM_ABS32 2 /* Direct 32 bit */ +#define R_ARM_REL32 3 /* PC relative 32 bit */ +#define R_ARM_PC13 4 +#define R_ARM_ABS16 5 /* Direct 16 bit */ +#define R_ARM_ABS12 6 /* Direct 12 bit */ +#define R_ARM_THM_ABS5 7 +#define R_ARM_ABS8 8 /* Direct 8 bit */ +#define R_ARM_SBREL32 9 +#define R_ARM_THM_PC22 10 +#define R_ARM_THM_PC8 11 +#define R_ARM_AMP_VCALL9 12 +#define R_ARM_SWI24 13 /* Obsolete static relocation. */ +#define R_ARM_TLS_DESC 13 /* Dynamic relocation. */ +#define R_ARM_THM_SWI8 14 +#define R_ARM_XPC25 15 +#define R_ARM_THM_XPC22 16 +#define R_ARM_TLS_DTPMOD32 17 /* ID of module containing symbol */ +#define R_ARM_TLS_DTPOFF32 18 /* Offset in TLS block */ +#define R_ARM_TLS_TPOFF32 19 /* Offset in static TLS block */ +#define R_ARM_COPY 20 /* Copy symbol at runtime */ +#define R_ARM_GLOB_DAT 21 /* Create GOT entry */ +#define R_ARM_JUMP_SLOT 22 /* Create PLT entry */ +#define R_ARM_RELATIVE 23 /* Adjust by program base */ +#define R_ARM_GOTOFF 24 /* 32 bit offset to GOT */ +#define R_ARM_GOTPC 25 /* 32 bit PC relative offset to GOT */ +#define R_ARM_GOT32 26 /* 32 bit GOT entry */ +#define R_ARM_PLT32 27 /* 32 bit PLT address */ +#define R_ARM_CALL 28 +#define R_ARM_JUMP24 29 +#define R_ARM_THM_JUMP24 30 +#define R_ARM_ALU_PCREL_7_0 32 +#define R_ARM_ALU_PCREL_15_8 33 +#define R_ARM_ALU_PCREL_23_15 34 +#define R_ARM_LDR_SBREL_11_0 35 +#define R_ARM_ALU_SBREL_19_12 36 +#define R_ARM_ALU_SBREL_27_20 37 +#define R_ARM_V4BX 40 +#define R_ARM_PREL31 42 +#define R_ARM_MOVW_ABS_NC 43 +#define R_ARM_MOVT_ABS 44 +#define R_ARM_THM_MOVW_ABS_NC 47 +#define R_ARM_THM_MOVT_ABS 48 +#define R_ARM_TLS_GOTDESC 90 +#define R_ARM_TLS_CALL 91 +#define R_ARM_TLS_DESCSEQ 92 +#define R_ARM_THM_TLS_CALL 93 +#define R_ARM_GNU_VTENTRY 100 +#define R_ARM_GNU_VTINHERIT 101 +#define R_ARM_THM_PC11 102 /* thumb unconditional branch */ +#define R_ARM_THM_PC9 103 /* thumb conditional branch */ +#define R_ARM_TLS_GD32 104 /* PC-rel 32 bit for global dynamic + thread local data */ +#define R_ARM_TLS_LDM32 105 /* PC-rel 32 bit for local dynamic + thread local data */ +#define R_ARM_TLS_LDO32 106 /* 32 bit offset relative to TLS + block */ +#define R_ARM_TLS_IE32 107 /* PC-rel 32 bit for GOT entry of + static TLS block offset */ +#define R_ARM_TLS_LE32 108 /* 32 bit offset relative to static + TLS block */ +#define R_ARM_THM_TLS_DESCSEQ 129 +#define R_ARM_IRELATIVE 160 +#define R_ARM_RXPC25 249 +#define R_ARM_RSBREL32 250 +#define R_ARM_THM_RPC22 251 +#define R_ARM_RREL32 252 +#define R_ARM_RABS22 253 +#define R_ARM_RPC24 254 +#define R_ARM_RBASE 255 +/* Keep this the last entry. */ +#define R_ARM_NUM 256 + +/* TMS320C67xx specific declarations */ + +/* XXX: no ELF standard yet*/ + +/* TMS320C67xx relocs. */ +#define R_C60_32 1 +#define R_C60_GOT32 3 /* 32 bit GOT entry */ +#define R_C60_PLT32 4 /* 32 bit PLT address */ +#define R_C60_COPY 5 /* Copy symbol at runtime */ +#define R_C60_GLOB_DAT 6 /* Create GOT entry */ +#define R_C60_JMP_SLOT 7 /* Create PLT entry */ +#define R_C60_RELATIVE 8 /* Adjust by program base */ +#define R_C60_GOTOFF 9 /* 32 bit offset to GOT */ +#define R_C60_GOTPC 10 /* 32 bit PC relative offset to GOT */ + +#define R_C60LO16 0x54 /* low 16 bit MVKL embedded */ +#define R_C60HI16 0x55 /* high 16 bit MVKH embedded */ +/* Keep this the last entry. */ +#define R_C60_NUM 0x56 + +/* IA-64 specific declarations. */ + +/* Processor specific flags for the Ehdr e_flags field. */ +#define EF_IA_64_MASKOS 0x0000000f /* os-specific flags */ +#define EF_IA_64_ABI64 0x00000010 /* 64-bit ABI */ +#define EF_IA_64_ARCH 0xff000000 /* arch. version mask */ + +/* Processor specific values for the Phdr p_type field. */ +#define PT_IA_64_ARCHEXT (PT_LOPROC + 0) /* arch extension bits */ +#define PT_IA_64_UNWIND (PT_LOPROC + 1) /* ia64 unwind bits */ +#define PT_IA_64_HP_OPT_ANOT (PT_LOOS + 0x12) +#define PT_IA_64_HP_HSL_ANOT (PT_LOOS + 0x13) +#define PT_IA_64_HP_STACK (PT_LOOS + 0x14) + +/* Processor specific flags for the Phdr p_flags field. */ +#define PF_IA_64_NORECOV 0x80000000 /* spec insns w/o recovery */ + +/* Processor specific values for the Shdr sh_type field. */ +#define SHT_IA_64_EXT (SHT_LOPROC + 0) /* extension bits */ +#define SHT_IA_64_UNWIND (SHT_LOPROC + 1) /* unwind bits */ + +/* Processor specific flags for the Shdr sh_flags field. */ +#define SHF_IA_64_SHORT 0x10000000 /* section near gp */ +#define SHF_IA_64_NORECOV 0x20000000 /* spec insns w/o recovery */ + +/* Processor specific values for the Dyn d_tag field. */ +#define DT_IA_64_PLT_RESERVE (DT_LOPROC + 0) +#define DT_IA_64_NUM 1 + +/* IA-64 relocations. */ +#define R_IA64_NONE 0x00 /* none */ +#define R_IA64_IMM14 0x21 /* symbol + addend, add imm14 */ +#define R_IA64_IMM22 0x22 /* symbol + addend, add imm22 */ +#define R_IA64_IMM64 0x23 /* symbol + addend, mov imm64 */ +#define R_IA64_DIR32MSB 0x24 /* symbol + addend, data4 MSB */ +#define R_IA64_DIR32LSB 0x25 /* symbol + addend, data4 LSB */ +#define R_IA64_DIR64MSB 0x26 /* symbol + addend, data8 MSB */ +#define R_IA64_DIR64LSB 0x27 /* symbol + addend, data8 LSB */ +#define R_IA64_GPREL22 0x2a /* @gprel(sym + add), add imm22 */ +#define R_IA64_GPREL64I 0x2b /* @gprel(sym + add), mov imm64 */ +#define R_IA64_GPREL32MSB 0x2c /* @gprel(sym + add), data4 MSB */ +#define R_IA64_GPREL32LSB 0x2d /* @gprel(sym + add), data4 LSB */ +#define R_IA64_GPREL64MSB 0x2e /* @gprel(sym + add), data8 MSB */ +#define R_IA64_GPREL64LSB 0x2f /* @gprel(sym + add), data8 LSB */ +#define R_IA64_LTOFF22 0x32 /* @ltoff(sym + add), add imm22 */ +#define R_IA64_LTOFF64I 0x33 /* @ltoff(sym + add), mov imm64 */ +#define R_IA64_PLTOFF22 0x3a /* @pltoff(sym + add), add imm22 */ +#define R_IA64_PLTOFF64I 0x3b /* @pltoff(sym + add), mov imm64 */ +#define R_IA64_PLTOFF64MSB 0x3e /* @pltoff(sym + add), data8 MSB */ +#define R_IA64_PLTOFF64LSB 0x3f /* @pltoff(sym + add), data8 LSB */ +#define R_IA64_FPTR64I 0x43 /* @fptr(sym + add), mov imm64 */ +#define R_IA64_FPTR32MSB 0x44 /* @fptr(sym + add), data4 MSB */ +#define R_IA64_FPTR32LSB 0x45 /* @fptr(sym + add), data4 LSB */ +#define R_IA64_FPTR64MSB 0x46 /* @fptr(sym + add), data8 MSB */ +#define R_IA64_FPTR64LSB 0x47 /* @fptr(sym + add), data8 LSB */ +#define R_IA64_PCREL60B 0x48 /* @pcrel(sym + add), brl */ +#define R_IA64_PCREL21B 0x49 /* @pcrel(sym + add), ptb, call */ +#define R_IA64_PCREL21M 0x4a /* @pcrel(sym + add), chk.s */ +#define R_IA64_PCREL21F 0x4b /* @pcrel(sym + add), fchkf */ +#define R_IA64_PCREL32MSB 0x4c /* @pcrel(sym + add), data4 MSB */ +#define R_IA64_PCREL32LSB 0x4d /* @pcrel(sym + add), data4 LSB */ +#define R_IA64_PCREL64MSB 0x4e /* @pcrel(sym + add), data8 MSB */ +#define R_IA64_PCREL64LSB 0x4f /* @pcrel(sym + add), data8 LSB */ +#define R_IA64_LTOFF_FPTR22 0x52 /* @ltoff(@fptr(s+a)), imm22 */ +#define R_IA64_LTOFF_FPTR64I 0x53 /* @ltoff(@fptr(s+a)), imm64 */ +#define R_IA64_LTOFF_FPTR32MSB 0x54 /* @ltoff(@fptr(s+a)), data4 MSB */ +#define R_IA64_LTOFF_FPTR32LSB 0x55 /* @ltoff(@fptr(s+a)), data4 LSB */ +#define R_IA64_LTOFF_FPTR64MSB 0x56 /* @ltoff(@fptr(s+a)), data8 MSB */ +#define R_IA64_LTOFF_FPTR64LSB 0x57 /* @ltoff(@fptr(s+a)), data8 LSB */ +#define R_IA64_SEGREL32MSB 0x5c /* @segrel(sym + add), data4 MSB */ +#define R_IA64_SEGREL32LSB 0x5d /* @segrel(sym + add), data4 LSB */ +#define R_IA64_SEGREL64MSB 0x5e /* @segrel(sym + add), data8 MSB */ +#define R_IA64_SEGREL64LSB 0x5f /* @segrel(sym + add), data8 LSB */ +#define R_IA64_SECREL32MSB 0x64 /* @secrel(sym + add), data4 MSB */ +#define R_IA64_SECREL32LSB 0x65 /* @secrel(sym + add), data4 LSB */ +#define R_IA64_SECREL64MSB 0x66 /* @secrel(sym + add), data8 MSB */ +#define R_IA64_SECREL64LSB 0x67 /* @secrel(sym + add), data8 LSB */ +#define R_IA64_REL32MSB 0x6c /* data 4 + REL */ +#define R_IA64_REL32LSB 0x6d /* data 4 + REL */ +#define R_IA64_REL64MSB 0x6e /* data 8 + REL */ +#define R_IA64_REL64LSB 0x6f /* data 8 + REL */ +#define R_IA64_LTV32MSB 0x74 /* symbol + addend, data4 MSB */ +#define R_IA64_LTV32LSB 0x75 /* symbol + addend, data4 LSB */ +#define R_IA64_LTV64MSB 0x76 /* symbol + addend, data8 MSB */ +#define R_IA64_LTV64LSB 0x77 /* symbol + addend, data8 LSB */ +#define R_IA64_PCREL21BI 0x79 /* @pcrel(sym + add), 21bit inst */ +#define R_IA64_PCREL22 0x7a /* @pcrel(sym + add), 22bit inst */ +#define R_IA64_PCREL64I 0x7b /* @pcrel(sym + add), 64bit inst */ +#define R_IA64_IPLTMSB 0x80 /* dynamic reloc, imported PLT, MSB */ +#define R_IA64_IPLTLSB 0x81 /* dynamic reloc, imported PLT, LSB */ +#define R_IA64_COPY 0x84 /* copy relocation */ +#define R_IA64_SUB 0x85 /* Addend and symbol difference */ +#define R_IA64_LTOFF22X 0x86 /* LTOFF22, relaxable. */ +#define R_IA64_LDXMOV 0x87 /* Use of LTOFF22X. */ +#define R_IA64_TPREL14 0x91 /* @tprel(sym + add), imm14 */ +#define R_IA64_TPREL22 0x92 /* @tprel(sym + add), imm22 */ +#define R_IA64_TPREL64I 0x93 /* @tprel(sym + add), imm64 */ +#define R_IA64_TPREL64MSB 0x96 /* @tprel(sym + add), data8 MSB */ +#define R_IA64_TPREL64LSB 0x97 /* @tprel(sym + add), data8 LSB */ +#define R_IA64_LTOFF_TPREL22 0x9a /* @ltoff(@tprel(s+a)), imm2 */ +#define R_IA64_DTPMOD64MSB 0xa6 /* @dtpmod(sym + add), data8 MSB */ +#define R_IA64_DTPMOD64LSB 0xa7 /* @dtpmod(sym + add), data8 LSB */ +#define R_IA64_LTOFF_DTPMOD22 0xaa /* @ltoff(@dtpmod(sym + add)), imm22 */ +#define R_IA64_DTPREL14 0xb1 /* @dtprel(sym + add), imm14 */ +#define R_IA64_DTPREL22 0xb2 /* @dtprel(sym + add), imm22 */ +#define R_IA64_DTPREL64I 0xb3 /* @dtprel(sym + add), imm64 */ +#define R_IA64_DTPREL32MSB 0xb4 /* @dtprel(sym + add), data4 MSB */ +#define R_IA64_DTPREL32LSB 0xb5 /* @dtprel(sym + add), data4 LSB */ +#define R_IA64_DTPREL64MSB 0xb6 /* @dtprel(sym + add), data8 MSB */ +#define R_IA64_DTPREL64LSB 0xb7 /* @dtprel(sym + add), data8 LSB */ +#define R_IA64_LTOFF_DTPREL22 0xba /* @ltoff(@dtprel(s+a)), imm22 */ + +/* SH specific declarations */ + +/* Processor specific flags for the ELF header e_flags field. */ +#define EF_SH_MACH_MASK 0x1f +#define EF_SH_UNKNOWN 0x0 +#define EF_SH1 0x1 +#define EF_SH2 0x2 +#define EF_SH3 0x3 +#define EF_SH_DSP 0x4 +#define EF_SH3_DSP 0x5 +#define EF_SH4AL_DSP 0x6 +#define EF_SH3E 0x8 +#define EF_SH4 0x9 +#define EF_SH2E 0xb +#define EF_SH4A 0xc +#define EF_SH2A 0xd +#define EF_SH4_NOFPU 0x10 +#define EF_SH4A_NOFPU 0x11 +#define EF_SH4_NOMMU_NOFPU 0x12 +#define EF_SH2A_NOFPU 0x13 +#define EF_SH3_NOMMU 0x14 +#define EF_SH2A_SH4_NOFPU 0x15 +#define EF_SH2A_SH3_NOFPU 0x16 +#define EF_SH2A_SH4 0x17 +#define EF_SH2A_SH3E 0x18 + +/* SH relocs. */ +#define R_SH_NONE 0 +#define R_SH_DIR32 1 +#define R_SH_REL32 2 +#define R_SH_DIR8WPN 3 +#define R_SH_IND12W 4 +#define R_SH_DIR8WPL 5 +#define R_SH_DIR8WPZ 6 +#define R_SH_DIR8BP 7 +#define R_SH_DIR8W 8 +#define R_SH_DIR8L 9 +#define R_SH_SWITCH16 25 +#define R_SH_SWITCH32 26 +#define R_SH_USES 27 +#define R_SH_COUNT 28 +#define R_SH_ALIGN 29 +#define R_SH_CODE 30 +#define R_SH_DATA 31 +#define R_SH_LABEL 32 +#define R_SH_SWITCH8 33 +#define R_SH_GNU_VTINHERIT 34 +#define R_SH_GNU_VTENTRY 35 +#define R_SH_TLS_GD_32 144 +#define R_SH_TLS_LD_32 145 +#define R_SH_TLS_LDO_32 146 +#define R_SH_TLS_IE_32 147 +#define R_SH_TLS_LE_32 148 +#define R_SH_TLS_DTPMOD32 149 +#define R_SH_TLS_DTPOFF32 150 +#define R_SH_TLS_TPOFF32 151 +#define R_SH_GOT32 160 +#define R_SH_PLT32 161 +#define R_SH_COPY 162 +#define R_SH_GLOB_DAT 163 +#define R_SH_JMP_SLOT 164 +#define R_SH_RELATIVE 165 +#define R_SH_GOTOFF 166 +#define R_SH_GOTPC 167 +/* Keep this the last entry. */ +#define R_SH_NUM 256 + +/* S/390 specific definitions. */ + +/* Valid values for the e_flags field. */ + +#define EF_S390_HIGH_GPRS 0x00000001 /* High GPRs kernel facility needed. */ + +/* Additional s390 relocs */ + +#define R_390_NONE 0 /* No reloc. */ +#define R_390_8 1 /* Direct 8 bit. */ +#define R_390_12 2 /* Direct 12 bit. */ +#define R_390_16 3 /* Direct 16 bit. */ +#define R_390_32 4 /* Direct 32 bit. */ +#define R_390_PC32 5 /* PC relative 32 bit. */ +#define R_390_GOT12 6 /* 12 bit GOT offset. */ +#define R_390_GOT32 7 /* 32 bit GOT offset. */ +#define R_390_PLT32 8 /* 32 bit PC relative PLT address. */ +#define R_390_COPY 9 /* Copy symbol at runtime. */ +#define R_390_GLOB_DAT 10 /* Create GOT entry. */ +#define R_390_JMP_SLOT 11 /* Create PLT entry. */ +#define R_390_RELATIVE 12 /* Adjust by program base. */ +#define R_390_GOTOFF32 13 /* 32 bit offset to GOT. */ +#define R_390_GOTPC 14 /* 32 bit PC relative offset to GOT. */ +#define R_390_GOT16 15 /* 16 bit GOT offset. */ +#define R_390_PC16 16 /* PC relative 16 bit. */ +#define R_390_PC16DBL 17 /* PC relative 16 bit shifted by 1. */ +#define R_390_PLT16DBL 18 /* 16 bit PC rel. PLT shifted by 1. */ +#define R_390_PC32DBL 19 /* PC relative 32 bit shifted by 1. */ +#define R_390_PLT32DBL 20 /* 32 bit PC rel. PLT shifted by 1. */ +#define R_390_GOTPCDBL 21 /* 32 bit PC rel. GOT shifted by 1. */ +#define R_390_64 22 /* Direct 64 bit. */ +#define R_390_PC64 23 /* PC relative 64 bit. */ +#define R_390_GOT64 24 /* 64 bit GOT offset. */ +#define R_390_PLT64 25 /* 64 bit PC relative PLT address. */ +#define R_390_GOTENT 26 /* 32 bit PC rel. to GOT entry >> 1. */ +#define R_390_GOTOFF16 27 /* 16 bit offset to GOT. */ +#define R_390_GOTOFF64 28 /* 64 bit offset to GOT. */ +#define R_390_GOTPLT12 29 /* 12 bit offset to jump slot. */ +#define R_390_GOTPLT16 30 /* 16 bit offset to jump slot. */ +#define R_390_GOTPLT32 31 /* 32 bit offset to jump slot. */ +#define R_390_GOTPLT64 32 /* 64 bit offset to jump slot. */ +#define R_390_GOTPLTENT 33 /* 32 bit rel. offset to jump slot. */ +#define R_390_PLTOFF16 34 /* 16 bit offset from GOT to PLT. */ +#define R_390_PLTOFF32 35 /* 32 bit offset from GOT to PLT. */ +#define R_390_PLTOFF64 36 /* 16 bit offset from GOT to PLT. */ +#define R_390_TLS_LOAD 37 /* Tag for load insn in TLS code. */ +#define R_390_TLS_GDCALL 38 /* Tag for function call in general + dynamic TLS code. */ +#define R_390_TLS_LDCALL 39 /* Tag for function call in local + dynamic TLS code. */ +#define R_390_TLS_GD32 40 /* Direct 32 bit for general dynamic + thread local data. */ +#define R_390_TLS_GD64 41 /* Direct 64 bit for general dynamic + thread local data. */ +#define R_390_TLS_GOTIE12 42 /* 12 bit GOT offset for static TLS + block offset. */ +#define R_390_TLS_GOTIE32 43 /* 32 bit GOT offset for static TLS + block offset. */ +#define R_390_TLS_GOTIE64 44 /* 64 bit GOT offset for static TLS + block offset. */ +#define R_390_TLS_LDM32 45 /* Direct 32 bit for local dynamic + thread local data in LE code. */ +#define R_390_TLS_LDM64 46 /* Direct 64 bit for local dynamic + thread local data in LE code. */ +#define R_390_TLS_IE32 47 /* 32 bit address of GOT entry for + negated static TLS block offset. */ +#define R_390_TLS_IE64 48 /* 64 bit address of GOT entry for + negated static TLS block offset. */ +#define R_390_TLS_IEENT 49 /* 32 bit rel. offset to GOT entry for + negated static TLS block offset. */ +#define R_390_TLS_LE32 50 /* 32 bit negated offset relative to + static TLS block. */ +#define R_390_TLS_LE64 51 /* 64 bit negated offset relative to + static TLS block. */ +#define R_390_TLS_LDO32 52 /* 32 bit offset relative to TLS + block. */ +#define R_390_TLS_LDO64 53 /* 64 bit offset relative to TLS + block. */ +#define R_390_TLS_DTPMOD 54 /* ID of module containing symbol. */ +#define R_390_TLS_DTPOFF 55 /* Offset in TLS block. */ +#define R_390_TLS_TPOFF 56 /* Negated offset in static TLS + block. */ +#define R_390_20 57 /* Direct 20 bit. */ +#define R_390_GOT20 58 /* 20 bit GOT offset. */ +#define R_390_GOTPLT20 59 /* 20 bit offset to jump slot. */ +#define R_390_TLS_GOTIE20 60 /* 20 bit GOT offset for static TLS + block offset. */ +#define R_390_IRELATIVE 61 /* STT_GNU_IFUNC relocation. */ +/* Keep this the last entry. */ +#define R_390_NUM 62 + + +/* CRIS relocations. */ +#define R_CRIS_NONE 0 +#define R_CRIS_8 1 +#define R_CRIS_16 2 +#define R_CRIS_32 3 +#define R_CRIS_8_PCREL 4 +#define R_CRIS_16_PCREL 5 +#define R_CRIS_32_PCREL 6 +#define R_CRIS_GNU_VTINHERIT 7 +#define R_CRIS_GNU_VTENTRY 8 +#define R_CRIS_COPY 9 +#define R_CRIS_GLOB_DAT 10 +#define R_CRIS_JUMP_SLOT 11 +#define R_CRIS_RELATIVE 12 +#define R_CRIS_16_GOT 13 +#define R_CRIS_32_GOT 14 +#define R_CRIS_16_GOTPLT 15 +#define R_CRIS_32_GOTPLT 16 +#define R_CRIS_32_GOTREL 17 +#define R_CRIS_32_PLT_GOTREL 18 +#define R_CRIS_32_PLT_PCREL 19 + +#define R_CRIS_NUM 20 + + +/* AMD x86-64 relocations. */ +#define R_X86_64_NONE 0 /* No reloc */ +#define R_X86_64_64 1 /* Direct 64 bit */ +#define R_X86_64_PC32 2 /* PC relative 32 bit signed */ +#define R_X86_64_GOT32 3 /* 32 bit GOT entry */ +#define R_X86_64_PLT32 4 /* 32 bit PLT address */ +#define R_X86_64_COPY 5 /* Copy symbol at runtime */ +#define R_X86_64_GLOB_DAT 6 /* Create GOT entry */ +#define R_X86_64_JUMP_SLOT 7 /* Create PLT entry */ +#define R_X86_64_RELATIVE 8 /* Adjust by program base */ +#define R_X86_64_GOTPCREL 9 /* 32 bit signed PC relative + offset to GOT */ +#define R_X86_64_32 10 /* Direct 32 bit zero extended */ +#define R_X86_64_32S 11 /* Direct 32 bit sign extended */ +#define R_X86_64_16 12 /* Direct 16 bit zero extended */ +#define R_X86_64_PC16 13 /* 16 bit sign extended pc relative */ +#define R_X86_64_8 14 /* Direct 8 bit sign extended */ +#define R_X86_64_PC8 15 /* 8 bit sign extended pc relative */ +#define R_X86_64_DTPMOD64 16 /* ID of module containing symbol */ +#define R_X86_64_DTPOFF64 17 /* Offset in module's TLS block */ +#define R_X86_64_TPOFF64 18 /* Offset in initial TLS block */ +#define R_X86_64_TLSGD 19 /* 32 bit signed PC relative offset + to two GOT entries for GD symbol */ +#define R_X86_64_TLSLD 20 /* 32 bit signed PC relative offset + to two GOT entries for LD symbol */ +#define R_X86_64_DTPOFF32 21 /* Offset in TLS block */ +#define R_X86_64_GOTTPOFF 22 /* 32 bit signed PC relative offset + to GOT entry for IE symbol */ +#define R_X86_64_TPOFF32 23 /* Offset in initial TLS block */ +#define R_X86_64_PC64 24 /* PC relative 64 bit */ +#define R_X86_64_GOTOFF64 25 /* 64 bit offset to GOT */ +#define R_X86_64_GOTPC32 26 /* 32 bit signed pc relative + offset to GOT */ +#define R_X86_64_GOT64 27 /* 64-bit GOT entry offset */ +#define R_X86_64_GOTPCREL64 28 /* 64-bit PC relative offset + to GOT entry */ +#define R_X86_64_GOTPC64 29 /* 64-bit PC relative offset to GOT */ +#define R_X86_64_GOTPLT64 30 /* like GOT64, says PLT entry needed */ +#define R_X86_64_PLTOFF64 31 /* 64-bit GOT relative offset + to PLT entry */ +#define R_X86_64_SIZE32 32 /* Size of symbol plus 32-bit addend */ +#define R_X86_64_SIZE64 33 /* Size of symbol plus 64-bit addend */ +#define R_X86_64_GOTPC32_TLSDESC 34 /* GOT offset for TLS descriptor. */ +#define R_X86_64_TLSDESC_CALL 35 /* Marker for call through TLS + descriptor. */ +#define R_X86_64_TLSDESC 36 /* TLS descriptor. */ +#define R_X86_64_IRELATIVE 37 /* Adjust indirectly by program base */ +#define R_X86_64_RELATIVE64 38 /* 64-bit adjust by program base */ +#define R_X86_64_GOTPCRELX 41 /* like GOTPCREL, but optionally with + linker optimizations */ +#define R_X86_64_REX_GOTPCRELX 42 /* like GOTPCRELX, but a REX prefix + is present */ + +#define R_X86_64_NUM 43 + + +/* AM33 relocations. */ +#define R_MN10300_NONE 0 /* No reloc. */ +#define R_MN10300_32 1 /* Direct 32 bit. */ +#define R_MN10300_16 2 /* Direct 16 bit. */ +#define R_MN10300_8 3 /* Direct 8 bit. */ +#define R_MN10300_PCREL32 4 /* PC-relative 32-bit. */ +#define R_MN10300_PCREL16 5 /* PC-relative 16-bit signed. */ +#define R_MN10300_PCREL8 6 /* PC-relative 8-bit signed. */ +#define R_MN10300_GNU_VTINHERIT 7 /* Ancient C++ vtable garbage... */ +#define R_MN10300_GNU_VTENTRY 8 /* ... collection annotation. */ +#define R_MN10300_24 9 /* Direct 24 bit. */ +#define R_MN10300_GOTPC32 10 /* 32-bit PCrel offset to GOT. */ +#define R_MN10300_GOTPC16 11 /* 16-bit PCrel offset to GOT. */ +#define R_MN10300_GOTOFF32 12 /* 32-bit offset from GOT. */ +#define R_MN10300_GOTOFF24 13 /* 24-bit offset from GOT. */ +#define R_MN10300_GOTOFF16 14 /* 16-bit offset from GOT. */ +#define R_MN10300_PLT32 15 /* 32-bit PCrel to PLT entry. */ +#define R_MN10300_PLT16 16 /* 16-bit PCrel to PLT entry. */ +#define R_MN10300_GOT32 17 /* 32-bit offset to GOT entry. */ +#define R_MN10300_GOT24 18 /* 24-bit offset to GOT entry. */ +#define R_MN10300_GOT16 19 /* 16-bit offset to GOT entry. */ +#define R_MN10300_COPY 20 /* Copy symbol at runtime. */ +#define R_MN10300_GLOB_DAT 21 /* Create GOT entry. */ +#define R_MN10300_JMP_SLOT 22 /* Create PLT entry. */ +#define R_MN10300_RELATIVE 23 /* Adjust by program base. */ +#define R_MN10300_TLS_GD 24 /* 32-bit offset for global dynamic. */ +#define R_MN10300_TLS_LD 25 /* 32-bit offset for local dynamic. */ +#define R_MN10300_TLS_LDO 26 /* Module-relative offset. */ +#define R_MN10300_TLS_GOTIE 27 /* GOT offset for static TLS block + offset. */ +#define R_MN10300_TLS_IE 28 /* GOT address for static TLS block + offset. */ +#define R_MN10300_TLS_LE 29 /* Offset relative to static TLS + block. */ +#define R_MN10300_TLS_DTPMOD 30 /* ID of module containing symbol. */ +#define R_MN10300_TLS_DTPOFF 31 /* Offset in module TLS block. */ +#define R_MN10300_TLS_TPOFF 32 /* Offset in static TLS block. */ +#define R_MN10300_SYM_DIFF 33 /* Adjustment for next reloc as needed + by linker relaxation. */ +#define R_MN10300_ALIGN 34 /* Alignment requirement for linker + relaxation. */ +#define R_MN10300_NUM 35 + + +/* M32R relocs. */ +#define R_M32R_NONE 0 /* No reloc. */ +#define R_M32R_16 1 /* Direct 16 bit. */ +#define R_M32R_32 2 /* Direct 32 bit. */ +#define R_M32R_24 3 /* Direct 24 bit. */ +#define R_M32R_10_PCREL 4 /* PC relative 10 bit shifted. */ +#define R_M32R_18_PCREL 5 /* PC relative 18 bit shifted. */ +#define R_M32R_26_PCREL 6 /* PC relative 26 bit shifted. */ +#define R_M32R_HI16_ULO 7 /* High 16 bit with unsigned low. */ +#define R_M32R_HI16_SLO 8 /* High 16 bit with signed low. */ +#define R_M32R_LO16 9 /* Low 16 bit. */ +#define R_M32R_SDA16 10 /* 16 bit offset in SDA. */ +#define R_M32R_GNU_VTINHERIT 11 +#define R_M32R_GNU_VTENTRY 12 +/* M32R relocs use SHT_RELA. */ +#define R_M32R_16_RELA 33 /* Direct 16 bit. */ +#define R_M32R_32_RELA 34 /* Direct 32 bit. */ +#define R_M32R_24_RELA 35 /* Direct 24 bit. */ +#define R_M32R_10_PCREL_RELA 36 /* PC relative 10 bit shifted. */ +#define R_M32R_18_PCREL_RELA 37 /* PC relative 18 bit shifted. */ +#define R_M32R_26_PCREL_RELA 38 /* PC relative 26 bit shifted. */ +#define R_M32R_HI16_ULO_RELA 39 /* High 16 bit with unsigned low */ +#define R_M32R_HI16_SLO_RELA 40 /* High 16 bit with signed low */ +#define R_M32R_LO16_RELA 41 /* Low 16 bit */ +#define R_M32R_SDA16_RELA 42 /* 16 bit offset in SDA */ +#define R_M32R_RELA_GNU_VTINHERIT 43 +#define R_M32R_RELA_GNU_VTENTRY 44 +#define R_M32R_REL32 45 /* PC relative 32 bit. */ + +#define R_M32R_GOT24 48 /* 24 bit GOT entry */ +#define R_M32R_26_PLTREL 49 /* 26 bit PC relative to PLT shifted */ +#define R_M32R_COPY 50 /* Copy symbol at runtime */ +#define R_M32R_GLOB_DAT 51 /* Create GOT entry */ +#define R_M32R_JMP_SLOT 52 /* Create PLT entry */ +#define R_M32R_RELATIVE 53 /* Adjust by program base */ +#define R_M32R_GOTOFF 54 /* 24 bit offset to GOT */ +#define R_M32R_GOTPC24 55 /* 24 bit PC relative offset to GOT */ +#define R_M32R_GOT16_HI_ULO 56 /* High 16 bit GOT entry with unsigned + low */ +#define R_M32R_GOT16_HI_SLO 57 /* High 16 bit GOT entry with signed + low */ +#define R_M32R_GOT16_LO 58 /* Low 16 bit GOT entry */ +#define R_M32R_GOTPC_HI_ULO 59 /* High 16 bit PC relative offset to + GOT with unsigned low */ +#define R_M32R_GOTPC_HI_SLO 60 /* High 16 bit PC relative offset to + GOT with signed low */ +#define R_M32R_GOTPC_LO 61 /* Low 16 bit PC relative offset to + GOT */ +#define R_M32R_GOTOFF_HI_ULO 62 /* High 16 bit offset to GOT + with unsigned low */ +#define R_M32R_GOTOFF_HI_SLO 63 /* High 16 bit offset to GOT + with signed low */ +#define R_M32R_GOTOFF_LO 64 /* Low 16 bit offset to GOT */ +#define R_M32R_NUM 256 /* Keep this the last entry. */ + + +/* TILEPro relocations. */ +#define R_TILEPRO_NONE 0 /* No reloc */ +#define R_TILEPRO_32 1 /* Direct 32 bit */ +#define R_TILEPRO_16 2 /* Direct 16 bit */ +#define R_TILEPRO_8 3 /* Direct 8 bit */ +#define R_TILEPRO_32_PCREL 4 /* PC relative 32 bit */ +#define R_TILEPRO_16_PCREL 5 /* PC relative 16 bit */ +#define R_TILEPRO_8_PCREL 6 /* PC relative 8 bit */ +#define R_TILEPRO_LO16 7 /* Low 16 bit */ +#define R_TILEPRO_HI16 8 /* High 16 bit */ +#define R_TILEPRO_HA16 9 /* High 16 bit, adjusted */ +#define R_TILEPRO_COPY 10 /* Copy relocation */ +#define R_TILEPRO_GLOB_DAT 11 /* Create GOT entry */ +#define R_TILEPRO_JMP_SLOT 12 /* Create PLT entry */ +#define R_TILEPRO_RELATIVE 13 /* Adjust by program base */ +#define R_TILEPRO_BROFF_X1 14 /* X1 pipe branch offset */ +#define R_TILEPRO_JOFFLONG_X1 15 /* X1 pipe jump offset */ +#define R_TILEPRO_JOFFLONG_X1_PLT 16 /* X1 pipe jump offset to PLT */ +#define R_TILEPRO_IMM8_X0 17 /* X0 pipe 8-bit */ +#define R_TILEPRO_IMM8_Y0 18 /* Y0 pipe 8-bit */ +#define R_TILEPRO_IMM8_X1 19 /* X1 pipe 8-bit */ +#define R_TILEPRO_IMM8_Y1 20 /* Y1 pipe 8-bit */ +#define R_TILEPRO_MT_IMM15_X1 21 /* X1 pipe mtspr */ +#define R_TILEPRO_MF_IMM15_X1 22 /* X1 pipe mfspr */ +#define R_TILEPRO_IMM16_X0 23 /* X0 pipe 16-bit */ +#define R_TILEPRO_IMM16_X1 24 /* X1 pipe 16-bit */ +#define R_TILEPRO_IMM16_X0_LO 25 /* X0 pipe low 16-bit */ +#define R_TILEPRO_IMM16_X1_LO 26 /* X1 pipe low 16-bit */ +#define R_TILEPRO_IMM16_X0_HI 27 /* X0 pipe high 16-bit */ +#define R_TILEPRO_IMM16_X1_HI 28 /* X1 pipe high 16-bit */ +#define R_TILEPRO_IMM16_X0_HA 29 /* X0 pipe high 16-bit, adjusted */ +#define R_TILEPRO_IMM16_X1_HA 30 /* X1 pipe high 16-bit, adjusted */ +#define R_TILEPRO_IMM16_X0_PCREL 31 /* X0 pipe PC relative 16 bit */ +#define R_TILEPRO_IMM16_X1_PCREL 32 /* X1 pipe PC relative 16 bit */ +#define R_TILEPRO_IMM16_X0_LO_PCREL 33 /* X0 pipe PC relative low 16 bit */ +#define R_TILEPRO_IMM16_X1_LO_PCREL 34 /* X1 pipe PC relative low 16 bit */ +#define R_TILEPRO_IMM16_X0_HI_PCREL 35 /* X0 pipe PC relative high 16 bit */ +#define R_TILEPRO_IMM16_X1_HI_PCREL 36 /* X1 pipe PC relative high 16 bit */ +#define R_TILEPRO_IMM16_X0_HA_PCREL 37 /* X0 pipe PC relative ha() 16 bit */ +#define R_TILEPRO_IMM16_X1_HA_PCREL 38 /* X1 pipe PC relative ha() 16 bit */ +#define R_TILEPRO_IMM16_X0_GOT 39 /* X0 pipe 16-bit GOT offset */ +#define R_TILEPRO_IMM16_X1_GOT 40 /* X1 pipe 16-bit GOT offset */ +#define R_TILEPRO_IMM16_X0_GOT_LO 41 /* X0 pipe low 16-bit GOT offset */ +#define R_TILEPRO_IMM16_X1_GOT_LO 42 /* X1 pipe low 16-bit GOT offset */ +#define R_TILEPRO_IMM16_X0_GOT_HI 43 /* X0 pipe high 16-bit GOT offset */ +#define R_TILEPRO_IMM16_X1_GOT_HI 44 /* X1 pipe high 16-bit GOT offset */ +#define R_TILEPRO_IMM16_X0_GOT_HA 45 /* X0 pipe ha() 16-bit GOT offset */ +#define R_TILEPRO_IMM16_X1_GOT_HA 46 /* X1 pipe ha() 16-bit GOT offset */ +#define R_TILEPRO_MMSTART_X0 47 /* X0 pipe mm "start" */ +#define R_TILEPRO_MMEND_X0 48 /* X0 pipe mm "end" */ +#define R_TILEPRO_MMSTART_X1 49 /* X1 pipe mm "start" */ +#define R_TILEPRO_MMEND_X1 50 /* X1 pipe mm "end" */ +#define R_TILEPRO_SHAMT_X0 51 /* X0 pipe shift amount */ +#define R_TILEPRO_SHAMT_X1 52 /* X1 pipe shift amount */ +#define R_TILEPRO_SHAMT_Y0 53 /* Y0 pipe shift amount */ +#define R_TILEPRO_SHAMT_Y1 54 /* Y1 pipe shift amount */ +#define R_TILEPRO_DEST_IMM8_X1 55 /* X1 pipe destination 8-bit */ +/* Relocs 56-59 are currently not defined. */ +#define R_TILEPRO_TLS_GD_CALL 60 /* "jal" for TLS GD */ +#define R_TILEPRO_IMM8_X0_TLS_GD_ADD 61 /* X0 pipe "addi" for TLS GD */ +#define R_TILEPRO_IMM8_X1_TLS_GD_ADD 62 /* X1 pipe "addi" for TLS GD */ +#define R_TILEPRO_IMM8_Y0_TLS_GD_ADD 63 /* Y0 pipe "addi" for TLS GD */ +#define R_TILEPRO_IMM8_Y1_TLS_GD_ADD 64 /* Y1 pipe "addi" for TLS GD */ +#define R_TILEPRO_TLS_IE_LOAD 65 /* "lw_tls" for TLS IE */ +#define R_TILEPRO_IMM16_X0_TLS_GD 66 /* X0 pipe 16-bit TLS GD offset */ +#define R_TILEPRO_IMM16_X1_TLS_GD 67 /* X1 pipe 16-bit TLS GD offset */ +#define R_TILEPRO_IMM16_X0_TLS_GD_LO 68 /* X0 pipe low 16-bit TLS GD offset */ +#define R_TILEPRO_IMM16_X1_TLS_GD_LO 69 /* X1 pipe low 16-bit TLS GD offset */ +#define R_TILEPRO_IMM16_X0_TLS_GD_HI 70 /* X0 pipe high 16-bit TLS GD offset */ +#define R_TILEPRO_IMM16_X1_TLS_GD_HI 71 /* X1 pipe high 16-bit TLS GD offset */ +#define R_TILEPRO_IMM16_X0_TLS_GD_HA 72 /* X0 pipe ha() 16-bit TLS GD offset */ +#define R_TILEPRO_IMM16_X1_TLS_GD_HA 73 /* X1 pipe ha() 16-bit TLS GD offset */ +#define R_TILEPRO_IMM16_X0_TLS_IE 74 /* X0 pipe 16-bit TLS IE offset */ +#define R_TILEPRO_IMM16_X1_TLS_IE 75 /* X1 pipe 16-bit TLS IE offset */ +#define R_TILEPRO_IMM16_X0_TLS_IE_LO 76 /* X0 pipe low 16-bit TLS IE offset */ +#define R_TILEPRO_IMM16_X1_TLS_IE_LO 77 /* X1 pipe low 16-bit TLS IE offset */ +#define R_TILEPRO_IMM16_X0_TLS_IE_HI 78 /* X0 pipe high 16-bit TLS IE offset */ +#define R_TILEPRO_IMM16_X1_TLS_IE_HI 79 /* X1 pipe high 16-bit TLS IE offset */ +#define R_TILEPRO_IMM16_X0_TLS_IE_HA 80 /* X0 pipe ha() 16-bit TLS IE offset */ +#define R_TILEPRO_IMM16_X1_TLS_IE_HA 81 /* X1 pipe ha() 16-bit TLS IE offset */ +#define R_TILEPRO_TLS_DTPMOD32 82 /* ID of module containing symbol */ +#define R_TILEPRO_TLS_DTPOFF32 83 /* Offset in TLS block */ +#define R_TILEPRO_TLS_TPOFF32 84 /* Offset in static TLS block */ +#define R_TILEPRO_IMM16_X0_TLS_LE 85 /* X0 pipe 16-bit TLS LE offset */ +#define R_TILEPRO_IMM16_X1_TLS_LE 86 /* X1 pipe 16-bit TLS LE offset */ +#define R_TILEPRO_IMM16_X0_TLS_LE_LO 87 /* X0 pipe low 16-bit TLS LE offset */ +#define R_TILEPRO_IMM16_X1_TLS_LE_LO 88 /* X1 pipe low 16-bit TLS LE offset */ +#define R_TILEPRO_IMM16_X0_TLS_LE_HI 89 /* X0 pipe high 16-bit TLS LE offset */ +#define R_TILEPRO_IMM16_X1_TLS_LE_HI 90 /* X1 pipe high 16-bit TLS LE offset */ +#define R_TILEPRO_IMM16_X0_TLS_LE_HA 91 /* X0 pipe ha() 16-bit TLS LE offset */ +#define R_TILEPRO_IMM16_X1_TLS_LE_HA 92 /* X1 pipe ha() 16-bit TLS LE offset */ + +#define R_TILEPRO_GNU_VTINHERIT 128 /* GNU C++ vtable hierarchy */ +#define R_TILEPRO_GNU_VTENTRY 129 /* GNU C++ vtable member usage */ + +#define R_TILEPRO_NUM 130 + + +/* TILE-Gx relocations. */ +#define R_TILEGX_NONE 0 /* No reloc */ +#define R_TILEGX_64 1 /* Direct 64 bit */ +#define R_TILEGX_32 2 /* Direct 32 bit */ +#define R_TILEGX_16 3 /* Direct 16 bit */ +#define R_TILEGX_8 4 /* Direct 8 bit */ +#define R_TILEGX_64_PCREL 5 /* PC relative 64 bit */ +#define R_TILEGX_32_PCREL 6 /* PC relative 32 bit */ +#define R_TILEGX_16_PCREL 7 /* PC relative 16 bit */ +#define R_TILEGX_8_PCREL 8 /* PC relative 8 bit */ +#define R_TILEGX_HW0 9 /* hword 0 16-bit */ +#define R_TILEGX_HW1 10 /* hword 1 16-bit */ +#define R_TILEGX_HW2 11 /* hword 2 16-bit */ +#define R_TILEGX_HW3 12 /* hword 3 16-bit */ +#define R_TILEGX_HW0_LAST 13 /* last hword 0 16-bit */ +#define R_TILEGX_HW1_LAST 14 /* last hword 1 16-bit */ +#define R_TILEGX_HW2_LAST 15 /* last hword 2 16-bit */ +#define R_TILEGX_COPY 16 /* Copy relocation */ +#define R_TILEGX_GLOB_DAT 17 /* Create GOT entry */ +#define R_TILEGX_JMP_SLOT 18 /* Create PLT entry */ +#define R_TILEGX_RELATIVE 19 /* Adjust by program base */ +#define R_TILEGX_BROFF_X1 20 /* X1 pipe branch offset */ +#define R_TILEGX_JUMPOFF_X1 21 /* X1 pipe jump offset */ +#define R_TILEGX_JUMPOFF_X1_PLT 22 /* X1 pipe jump offset to PLT */ +#define R_TILEGX_IMM8_X0 23 /* X0 pipe 8-bit */ +#define R_TILEGX_IMM8_Y0 24 /* Y0 pipe 8-bit */ +#define R_TILEGX_IMM8_X1 25 /* X1 pipe 8-bit */ +#define R_TILEGX_IMM8_Y1 26 /* Y1 pipe 8-bit */ +#define R_TILEGX_DEST_IMM8_X1 27 /* X1 pipe destination 8-bit */ +#define R_TILEGX_MT_IMM14_X1 28 /* X1 pipe mtspr */ +#define R_TILEGX_MF_IMM14_X1 29 /* X1 pipe mfspr */ +#define R_TILEGX_MMSTART_X0 30 /* X0 pipe mm "start" */ +#define R_TILEGX_MMEND_X0 31 /* X0 pipe mm "end" */ +#define R_TILEGX_SHAMT_X0 32 /* X0 pipe shift amount */ +#define R_TILEGX_SHAMT_X1 33 /* X1 pipe shift amount */ +#define R_TILEGX_SHAMT_Y0 34 /* Y0 pipe shift amount */ +#define R_TILEGX_SHAMT_Y1 35 /* Y1 pipe shift amount */ +#define R_TILEGX_IMM16_X0_HW0 36 /* X0 pipe hword 0 */ +#define R_TILEGX_IMM16_X1_HW0 37 /* X1 pipe hword 0 */ +#define R_TILEGX_IMM16_X0_HW1 38 /* X0 pipe hword 1 */ +#define R_TILEGX_IMM16_X1_HW1 39 /* X1 pipe hword 1 */ +#define R_TILEGX_IMM16_X0_HW2 40 /* X0 pipe hword 2 */ +#define R_TILEGX_IMM16_X1_HW2 41 /* X1 pipe hword 2 */ +#define R_TILEGX_IMM16_X0_HW3 42 /* X0 pipe hword 3 */ +#define R_TILEGX_IMM16_X1_HW3 43 /* X1 pipe hword 3 */ +#define R_TILEGX_IMM16_X0_HW0_LAST 44 /* X0 pipe last hword 0 */ +#define R_TILEGX_IMM16_X1_HW0_LAST 45 /* X1 pipe last hword 0 */ +#define R_TILEGX_IMM16_X0_HW1_LAST 46 /* X0 pipe last hword 1 */ +#define R_TILEGX_IMM16_X1_HW1_LAST 47 /* X1 pipe last hword 1 */ +#define R_TILEGX_IMM16_X0_HW2_LAST 48 /* X0 pipe last hword 2 */ +#define R_TILEGX_IMM16_X1_HW2_LAST 49 /* X1 pipe last hword 2 */ +#define R_TILEGX_IMM16_X0_HW0_PCREL 50 /* X0 pipe PC relative hword 0 */ +#define R_TILEGX_IMM16_X1_HW0_PCREL 51 /* X1 pipe PC relative hword 0 */ +#define R_TILEGX_IMM16_X0_HW1_PCREL 52 /* X0 pipe PC relative hword 1 */ +#define R_TILEGX_IMM16_X1_HW1_PCREL 53 /* X1 pipe PC relative hword 1 */ +#define R_TILEGX_IMM16_X0_HW2_PCREL 54 /* X0 pipe PC relative hword 2 */ +#define R_TILEGX_IMM16_X1_HW2_PCREL 55 /* X1 pipe PC relative hword 2 */ +#define R_TILEGX_IMM16_X0_HW3_PCREL 56 /* X0 pipe PC relative hword 3 */ +#define R_TILEGX_IMM16_X1_HW3_PCREL 57 /* X1 pipe PC relative hword 3 */ +#define R_TILEGX_IMM16_X0_HW0_LAST_PCREL 58 /* X0 pipe PC-rel last hword 0 */ +#define R_TILEGX_IMM16_X1_HW0_LAST_PCREL 59 /* X1 pipe PC-rel last hword 0 */ +#define R_TILEGX_IMM16_X0_HW1_LAST_PCREL 60 /* X0 pipe PC-rel last hword 1 */ +#define R_TILEGX_IMM16_X1_HW1_LAST_PCREL 61 /* X1 pipe PC-rel last hword 1 */ +#define R_TILEGX_IMM16_X0_HW2_LAST_PCREL 62 /* X0 pipe PC-rel last hword 2 */ +#define R_TILEGX_IMM16_X1_HW2_LAST_PCREL 63 /* X1 pipe PC-rel last hword 2 */ +#define R_TILEGX_IMM16_X0_HW0_GOT 64 /* X0 pipe hword 0 GOT offset */ +#define R_TILEGX_IMM16_X1_HW0_GOT 65 /* X1 pipe hword 0 GOT offset */ +#define R_TILEGX_IMM16_X0_HW0_PLT_PCREL 66 /* X0 pipe PC-rel PLT hword 0 */ +#define R_TILEGX_IMM16_X1_HW0_PLT_PCREL 67 /* X1 pipe PC-rel PLT hword 0 */ +#define R_TILEGX_IMM16_X0_HW1_PLT_PCREL 68 /* X0 pipe PC-rel PLT hword 1 */ +#define R_TILEGX_IMM16_X1_HW1_PLT_PCREL 69 /* X1 pipe PC-rel PLT hword 1 */ +#define R_TILEGX_IMM16_X0_HW2_PLT_PCREL 70 /* X0 pipe PC-rel PLT hword 2 */ +#define R_TILEGX_IMM16_X1_HW2_PLT_PCREL 71 /* X1 pipe PC-rel PLT hword 2 */ +#define R_TILEGX_IMM16_X0_HW0_LAST_GOT 72 /* X0 pipe last hword 0 GOT offset */ +#define R_TILEGX_IMM16_X1_HW0_LAST_GOT 73 /* X1 pipe last hword 0 GOT offset */ +#define R_TILEGX_IMM16_X0_HW1_LAST_GOT 74 /* X0 pipe last hword 1 GOT offset */ +#define R_TILEGX_IMM16_X1_HW1_LAST_GOT 75 /* X1 pipe last hword 1 GOT offset */ +#define R_TILEGX_IMM16_X0_HW3_PLT_PCREL 76 /* X0 pipe PC-rel PLT hword 3 */ +#define R_TILEGX_IMM16_X1_HW3_PLT_PCREL 77 /* X1 pipe PC-rel PLT hword 3 */ +#define R_TILEGX_IMM16_X0_HW0_TLS_GD 78 /* X0 pipe hword 0 TLS GD offset */ +#define R_TILEGX_IMM16_X1_HW0_TLS_GD 79 /* X1 pipe hword 0 TLS GD offset */ +#define R_TILEGX_IMM16_X0_HW0_TLS_LE 80 /* X0 pipe hword 0 TLS LE offset */ +#define R_TILEGX_IMM16_X1_HW0_TLS_LE 81 /* X1 pipe hword 0 TLS LE offset */ +#define R_TILEGX_IMM16_X0_HW0_LAST_TLS_LE 82 /* X0 pipe last hword 0 LE off */ +#define R_TILEGX_IMM16_X1_HW0_LAST_TLS_LE 83 /* X1 pipe last hword 0 LE off */ +#define R_TILEGX_IMM16_X0_HW1_LAST_TLS_LE 84 /* X0 pipe last hword 1 LE off */ +#define R_TILEGX_IMM16_X1_HW1_LAST_TLS_LE 85 /* X1 pipe last hword 1 LE off */ +#define R_TILEGX_IMM16_X0_HW0_LAST_TLS_GD 86 /* X0 pipe last hword 0 GD off */ +#define R_TILEGX_IMM16_X1_HW0_LAST_TLS_GD 87 /* X1 pipe last hword 0 GD off */ +#define R_TILEGX_IMM16_X0_HW1_LAST_TLS_GD 88 /* X0 pipe last hword 1 GD off */ +#define R_TILEGX_IMM16_X1_HW1_LAST_TLS_GD 89 /* X1 pipe last hword 1 GD off */ +/* Relocs 90-91 are currently not defined. */ +#define R_TILEGX_IMM16_X0_HW0_TLS_IE 92 /* X0 pipe hword 0 TLS IE offset */ +#define R_TILEGX_IMM16_X1_HW0_TLS_IE 93 /* X1 pipe hword 0 TLS IE offset */ +#define R_TILEGX_IMM16_X0_HW0_LAST_PLT_PCREL 94 /* X0 pipe PC-rel PLT last hword 0 */ +#define R_TILEGX_IMM16_X1_HW0_LAST_PLT_PCREL 95 /* X1 pipe PC-rel PLT last hword 0 */ +#define R_TILEGX_IMM16_X0_HW1_LAST_PLT_PCREL 96 /* X0 pipe PC-rel PLT last hword 1 */ +#define R_TILEGX_IMM16_X1_HW1_LAST_PLT_PCREL 97 /* X1 pipe PC-rel PLT last hword 1 */ +#define R_TILEGX_IMM16_X0_HW2_LAST_PLT_PCREL 98 /* X0 pipe PC-rel PLT last hword 2 */ +#define R_TILEGX_IMM16_X1_HW2_LAST_PLT_PCREL 99 /* X1 pipe PC-rel PLT last hword 2 */ +#define R_TILEGX_IMM16_X0_HW0_LAST_TLS_IE 100 /* X0 pipe last hword 0 IE off */ +#define R_TILEGX_IMM16_X1_HW0_LAST_TLS_IE 101 /* X1 pipe last hword 0 IE off */ +#define R_TILEGX_IMM16_X0_HW1_LAST_TLS_IE 102 /* X0 pipe last hword 1 IE off */ +#define R_TILEGX_IMM16_X1_HW1_LAST_TLS_IE 103 /* X1 pipe last hword 1 IE off */ +/* Relocs 104-105 are currently not defined. */ +#define R_TILEGX_TLS_DTPMOD64 106 /* 64-bit ID of symbol's module */ +#define R_TILEGX_TLS_DTPOFF64 107 /* 64-bit offset in TLS block */ +#define R_TILEGX_TLS_TPOFF64 108 /* 64-bit offset in static TLS block */ +#define R_TILEGX_TLS_DTPMOD32 109 /* 32-bit ID of symbol's module */ +#define R_TILEGX_TLS_DTPOFF32 110 /* 32-bit offset in TLS block */ +#define R_TILEGX_TLS_TPOFF32 111 /* 32-bit offset in static TLS block */ +#define R_TILEGX_TLS_GD_CALL 112 /* "jal" for TLS GD */ +#define R_TILEGX_IMM8_X0_TLS_GD_ADD 113 /* X0 pipe "addi" for TLS GD */ +#define R_TILEGX_IMM8_X1_TLS_GD_ADD 114 /* X1 pipe "addi" for TLS GD */ +#define R_TILEGX_IMM8_Y0_TLS_GD_ADD 115 /* Y0 pipe "addi" for TLS GD */ +#define R_TILEGX_IMM8_Y1_TLS_GD_ADD 116 /* Y1 pipe "addi" for TLS GD */ +#define R_TILEGX_TLS_IE_LOAD 117 /* "ld_tls" for TLS IE */ +#define R_TILEGX_IMM8_X0_TLS_ADD 118 /* X0 pipe "addi" for TLS GD/IE */ +#define R_TILEGX_IMM8_X1_TLS_ADD 119 /* X1 pipe "addi" for TLS GD/IE */ +#define R_TILEGX_IMM8_Y0_TLS_ADD 120 /* Y0 pipe "addi" for TLS GD/IE */ +#define R_TILEGX_IMM8_Y1_TLS_ADD 121 /* Y1 pipe "addi" for TLS GD/IE */ + +#define R_TILEGX_GNU_VTINHERIT 128 /* GNU C++ vtable hierarchy */ +#define R_TILEGX_GNU_VTENTRY 129 /* GNU C++ vtable member usage */ + +#define R_TILEGX_NUM 130 + + +#endif /* elf.h */ diff --git a/tinyc/examples/ex1.c b/tinyc/examples/ex1.c new file mode 100644 index 000000000..3d2a3e18f --- /dev/null +++ b/tinyc/examples/ex1.c @@ -0,0 +1,8 @@ +#!/usr/local/bin/tcc -run +#include + +int main() +{ + printf("Hello World\n"); + return 0; +} diff --git a/tinyc/examples/ex2.c b/tinyc/examples/ex2.c new file mode 100644 index 000000000..d415e39d7 --- /dev/null +++ b/tinyc/examples/ex2.c @@ -0,0 +1,98 @@ +#include +#include + +#define N 20 + +int nb_num; +int tab[N]; +int stack_ptr; +int stack_op[N]; +int stack_res[60]; +int result; + +int find(int n, int i1, int a, int b, int op) +{ + int i, j; + int c; + + if (stack_ptr >= 0) { + stack_res[3*stack_ptr] = a; + stack_op[stack_ptr] = op; + stack_res[3*stack_ptr+1] = b; + stack_res[3*stack_ptr+2] = n; + if (n == result) + return 1; + tab[i1] = n; + } + + for(i=0;i + +int fib(n) +{ + if (n <= 2) + return 1; + else + return fib(n-1) + fib(n-2); +} + +int main(int argc, char **argv) +{ + int n; + if (argc < 2) { + printf("usage: fib n\n" + "Compute nth Fibonacci number\n"); + return 1; + } + + n = atoi(argv[1]); + printf("fib(%d) = %d\n", n, fib(n, 2)); + return 0; +} diff --git a/tinyc/examples/ex4.c b/tinyc/examples/ex4.c new file mode 100644 index 000000000..f92c0da9f --- /dev/null +++ b/tinyc/examples/ex4.c @@ -0,0 +1,26 @@ +#!/usr/local/bin/tcc -run -L/usr/X11R6/lib -lX11 +#include +#include +#include + +/* Yes, TCC can use X11 too ! */ + +int main(int argc, char **argv) +{ + Display *display; + Screen *screen; + + display = XOpenDisplay(""); + if (!display) { + fprintf(stderr, "Could not open X11 display\n"); + exit(1); + } + printf("X11 display opened.\n"); + screen = XScreenOfDisplay(display, 0); + printf("width = %d\nheight = %d\ndepth = %d\n", + screen->width, + screen->height, + screen->root_depth); + XCloseDisplay(display); + return 0; +} diff --git a/tinyc/examples/ex5.c b/tinyc/examples/ex5.c new file mode 100644 index 000000000..156425e39 --- /dev/null +++ b/tinyc/examples/ex5.c @@ -0,0 +1,8 @@ +#include +#include + +int main() +{ + printf("Hello World\n"); + return 0; +} diff --git a/tinyc/i386-asm.c b/tinyc/i386-asm.c new file mode 100644 index 000000000..2e184974e --- /dev/null +++ b/tinyc/i386-asm.c @@ -0,0 +1,1714 @@ +/* + * i386 specific functions for TCC assembler + * + * Copyright (c) 2001, 2002 Fabrice Bellard + * Copyright (c) 2009 Frédéric Feret (x86_64 support) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "tcc.h" + +#define MAX_OPERANDS 3 + +#define TOK_ASM_first TOK_ASM_clc +#define TOK_ASM_last TOK_ASM_emms +#define TOK_ASM_alllast TOK_ASM_subps + +#define OPC_B 0x01 /* only used with OPC_WL */ +#define OPC_WL 0x02 /* accepts w, l or no suffix */ +#define OPC_BWL (OPC_B | OPC_WL) /* accepts b, w, l or no suffix */ +#define OPC_REG 0x04 /* register is added to opcode */ +#define OPC_MODRM 0x08 /* modrm encoding */ + +#define OPCT_MASK 0x70 +#define OPC_FWAIT 0x10 /* add fwait opcode */ +#define OPC_SHIFT 0x20 /* shift opcodes */ +#define OPC_ARITH 0x30 /* arithmetic opcodes */ +#define OPC_FARITH 0x40 /* FPU arithmetic opcodes */ +#define OPC_TEST 0x50 /* test opcodes */ +#define OPCT_IS(v,i) (((v) & OPCT_MASK) == (i)) + +#define OPC_0F 0x100 /* Is secondary map (0x0f prefix) */ +#define OPC_48 0x200 /* Always has REX prefix */ +#ifdef TCC_TARGET_X86_64 +# define OPC_WLQ 0x1000 /* accepts w, l, q or no suffix */ +# define OPC_BWLQ (OPC_B | OPC_WLQ) /* accepts b, w, l, q or no suffix */ +# define OPC_WLX OPC_WLQ +# define OPC_BWLX OPC_BWLQ +#else +# define OPC_WLX OPC_WL +# define OPC_BWLX OPC_BWL +#endif + +#define OPC_GROUP_SHIFT 13 + +/* in order to compress the operand type, we use specific operands and + we or only with EA */ +enum { + OPT_REG8=0, /* warning: value is hardcoded from TOK_ASM_xxx */ + OPT_REG16, /* warning: value is hardcoded from TOK_ASM_xxx */ + OPT_REG32, /* warning: value is hardcoded from TOK_ASM_xxx */ +#ifdef TCC_TARGET_X86_64 + OPT_REG64, /* warning: value is hardcoded from TOK_ASM_xxx */ +#endif + OPT_MMX, /* warning: value is hardcoded from TOK_ASM_xxx */ + OPT_SSE, /* warning: value is hardcoded from TOK_ASM_xxx */ + OPT_CR, /* warning: value is hardcoded from TOK_ASM_xxx */ + OPT_TR, /* warning: value is hardcoded from TOK_ASM_xxx */ + OPT_DB, /* warning: value is hardcoded from TOK_ASM_xxx */ + OPT_SEG, + OPT_ST, +#ifdef TCC_TARGET_X86_64 + OPT_REG8_LOW, /* %spl,%bpl,%sil,%dil, encoded like ah,ch,dh,bh, but + with REX prefix, not used in insn templates */ +#endif + OPT_IM8, + OPT_IM8S, + OPT_IM16, + OPT_IM32, +#ifdef TCC_TARGET_X86_64 + OPT_IM64, +#endif + OPT_EAX, /* %al, %ax, %eax or %rax register */ + OPT_ST0, /* %st(0) register */ + OPT_CL, /* %cl register */ + OPT_DX, /* %dx register */ + OPT_ADDR, /* OP_EA with only offset */ + OPT_INDIR, /* *(expr) */ + /* composite types */ + OPT_COMPOSITE_FIRST, + OPT_IM, /* IM8 | IM16 | IM32 */ + OPT_REG, /* REG8 | REG16 | REG32 | REG64 */ + OPT_REGW, /* REG16 | REG32 | REG64 */ + OPT_IMW, /* IM16 | IM32 */ + OPT_MMXSSE, /* MMX | SSE */ + OPT_DISP, /* Like OPT_ADDR, but emitted as displacement (for jumps) */ + OPT_DISP8, /* Like OPT_ADDR, but only 8bit (short jumps) */ + /* can be ored with any OPT_xxx */ + OPT_EA = 0x80 +}; + +#define OP_REG8 (1 << OPT_REG8) +#define OP_REG16 (1 << OPT_REG16) +#define OP_REG32 (1 << OPT_REG32) +#define OP_MMX (1 << OPT_MMX) +#define OP_SSE (1 << OPT_SSE) +#define OP_CR (1 << OPT_CR) +#define OP_TR (1 << OPT_TR) +#define OP_DB (1 << OPT_DB) +#define OP_SEG (1 << OPT_SEG) +#define OP_ST (1 << OPT_ST) +#define OP_IM8 (1 << OPT_IM8) +#define OP_IM8S (1 << OPT_IM8S) +#define OP_IM16 (1 << OPT_IM16) +#define OP_IM32 (1 << OPT_IM32) +#define OP_EAX (1 << OPT_EAX) +#define OP_ST0 (1 << OPT_ST0) +#define OP_CL (1 << OPT_CL) +#define OP_DX (1 << OPT_DX) +#define OP_ADDR (1 << OPT_ADDR) +#define OP_INDIR (1 << OPT_INDIR) +#ifdef TCC_TARGET_X86_64 +# define OP_REG64 (1 << OPT_REG64) +# define OP_REG8_LOW (1 << OPT_REG8_LOW) +# define OP_IM64 (1 << OPT_IM64) +# define OP_EA32 (OP_EA << 1) +#else +# define OP_REG64 0 +# define OP_REG8_LOW 0 +# define OP_IM64 0 +# define OP_EA32 0 +#endif + +#define OP_EA 0x40000000 +#define OP_REG (OP_REG8 | OP_REG16 | OP_REG32 | OP_REG64) + +#ifdef TCC_TARGET_X86_64 +# define TREG_XAX TREG_RAX +# define TREG_XCX TREG_RCX +# define TREG_XDX TREG_RDX +#else +# define TREG_XAX TREG_EAX +# define TREG_XCX TREG_ECX +# define TREG_XDX TREG_EDX +#endif + +typedef struct ASMInstr { + uint16_t sym; + uint16_t opcode; + uint16_t instr_type; + uint8_t nb_ops; + uint8_t op_type[MAX_OPERANDS]; /* see OP_xxx */ +} ASMInstr; + +typedef struct Operand { + uint32_t type; + int8_t reg; /* register, -1 if none */ + int8_t reg2; /* second register, -1 if none */ + uint8_t shift; + ExprValue e; +} Operand; + +static const uint8_t reg_to_size[9] = { +/* + [OP_REG8] = 0, + [OP_REG16] = 1, + [OP_REG32] = 2, +#ifdef TCC_TARGET_X86_64 + [OP_REG64] = 3, +#endif +*/ + 0, 0, 1, 0, 2, 0, 0, 0, 3 +}; + +#define NB_TEST_OPCODES 30 + +static const uint8_t test_bits[NB_TEST_OPCODES] = { + 0x00, /* o */ + 0x01, /* no */ + 0x02, /* b */ + 0x02, /* c */ + 0x02, /* nae */ + 0x03, /* nb */ + 0x03, /* nc */ + 0x03, /* ae */ + 0x04, /* e */ + 0x04, /* z */ + 0x05, /* ne */ + 0x05, /* nz */ + 0x06, /* be */ + 0x06, /* na */ + 0x07, /* nbe */ + 0x07, /* a */ + 0x08, /* s */ + 0x09, /* ns */ + 0x0a, /* p */ + 0x0a, /* pe */ + 0x0b, /* np */ + 0x0b, /* po */ + 0x0c, /* l */ + 0x0c, /* nge */ + 0x0d, /* nl */ + 0x0d, /* ge */ + 0x0e, /* le */ + 0x0e, /* ng */ + 0x0f, /* nle */ + 0x0f, /* g */ +}; + +static const uint8_t segment_prefixes[] = { + 0x26, /* es */ + 0x2e, /* cs */ + 0x36, /* ss */ + 0x3e, /* ds */ + 0x64, /* fs */ + 0x65 /* gs */ +}; + +static const ASMInstr asm_instrs[] = { +#define ALT(x) x +/* This removes a 0x0f in the second byte */ +#define O(o) ((uint64_t) ((((o) & 0xff00) == 0x0f00) ? ((((o) >> 8) & ~0xff) | ((o) & 0xff)) : (o))) +/* This constructs instr_type from opcode, type and group. */ +#define T(o,i,g) ((i) | ((g) << OPC_GROUP_SHIFT) | ((((o) & 0xff00) == 0x0f00) ? OPC_0F : 0)) +#define DEF_ASM_OP0(name, opcode) +#define DEF_ASM_OP0L(name, opcode, group, instr_type) { TOK_ASM_ ## name, O(opcode), T(opcode, instr_type, group), 0, { 0 } }, +#define DEF_ASM_OP1(name, opcode, group, instr_type, op0) { TOK_ASM_ ## name, O(opcode), T(opcode, instr_type, group), 1, { op0 }}, +#define DEF_ASM_OP2(name, opcode, group, instr_type, op0, op1) { TOK_ASM_ ## name, O(opcode), T(opcode, instr_type, group), 2, { op0, op1 }}, +#define DEF_ASM_OP3(name, opcode, group, instr_type, op0, op1, op2) { TOK_ASM_ ## name, O(opcode), T(opcode, instr_type, group), 3, { op0, op1, op2 }}, +#ifdef TCC_TARGET_X86_64 +# include "x86_64-asm.h" +#else +# include "i386-asm.h" +#endif + /* last operation */ + { 0, }, +}; + +static const uint16_t op0_codes[] = { +#define ALT(x) +#define DEF_ASM_OP0(x, opcode) opcode, +#define DEF_ASM_OP0L(name, opcode, group, instr_type) +#define DEF_ASM_OP1(name, opcode, group, instr_type, op0) +#define DEF_ASM_OP2(name, opcode, group, instr_type, op0, op1) +#define DEF_ASM_OP3(name, opcode, group, instr_type, op0, op1, op2) +#ifdef TCC_TARGET_X86_64 +# include "x86_64-asm.h" +#else +# include "i386-asm.h" +#endif +}; + +static inline int get_reg_shift(TCCState *s1) +{ + int shift, v; + v = asm_int_expr(s1); + switch(v) { + case 1: + shift = 0; + break; + case 2: + shift = 1; + break; + case 4: + shift = 2; + break; + case 8: + shift = 3; + break; + default: + expect("1, 2, 4 or 8 constant"); + shift = 0; + break; + } + return shift; +} + +#ifdef TCC_TARGET_X86_64 +static int asm_parse_numeric_reg(int t, unsigned int *type) +{ + int reg = -1; + if (t >= TOK_IDENT && t < tok_ident) { + const char *s = table_ident[t - TOK_IDENT]->str; + char c; + *type = OP_REG64; + if (*s == 'c') { + s++; + *type = OP_CR; + } + if (*s++ != 'r') + return -1; + /* Don't allow leading '0'. */ + if ((c = *s++) >= '1' && c <= '9') + reg = c - '0'; + else + return -1; + if ((c = *s) >= '0' && c <= '5') + s++, reg = reg * 10 + c - '0'; + if (reg > 15) + return -1; + if ((c = *s) == 0) + ; + else if (*type != OP_REG64) + return -1; + else if (c == 'b' && !s[1]) + *type = OP_REG8; + else if (c == 'w' && !s[1]) + *type = OP_REG16; + else if (c == 'd' && !s[1]) + *type = OP_REG32; + else + return -1; + } + return reg; +} +#endif + +static int asm_parse_reg(unsigned int *type) +{ + int reg = 0; + *type = 0; + if (tok != '%') + goto error_32; + next(); + if (tok >= TOK_ASM_eax && tok <= TOK_ASM_edi) { + reg = tok - TOK_ASM_eax; + *type = OP_REG32; +#ifdef TCC_TARGET_X86_64 + } else if (tok >= TOK_ASM_rax && tok <= TOK_ASM_rdi) { + reg = tok - TOK_ASM_rax; + *type = OP_REG64; + } else if (tok == TOK_ASM_rip) { + reg = -2; /* Probably should use different escape code. */ + *type = OP_REG64; + } else if ((reg = asm_parse_numeric_reg(tok, type)) >= 0 + && (*type == OP_REG32 || *type == OP_REG64)) { + ; +#endif + } else { + error_32: + expect("register"); + } + next(); + return reg; +} + +static void parse_operand(TCCState *s1, Operand *op) +{ + ExprValue e; + int reg, indir; + const char *p; + + indir = 0; + if (tok == '*') { + next(); + indir = OP_INDIR; + } + + if (tok == '%') { + next(); + if (tok >= TOK_ASM_al && tok <= TOK_ASM_db7) { + reg = tok - TOK_ASM_al; + op->type = 1 << (reg >> 3); /* WARNING: do not change constant order */ + op->reg = reg & 7; + if ((op->type & OP_REG) && op->reg == TREG_XAX) + op->type |= OP_EAX; + else if (op->type == OP_REG8 && op->reg == TREG_XCX) + op->type |= OP_CL; + else if (op->type == OP_REG16 && op->reg == TREG_XDX) + op->type |= OP_DX; + } else if (tok >= TOK_ASM_dr0 && tok <= TOK_ASM_dr7) { + op->type = OP_DB; + op->reg = tok - TOK_ASM_dr0; + } else if (tok >= TOK_ASM_es && tok <= TOK_ASM_gs) { + op->type = OP_SEG; + op->reg = tok - TOK_ASM_es; + } else if (tok == TOK_ASM_st) { + op->type = OP_ST; + op->reg = 0; + next(); + if (tok == '(') { + next(); + if (tok != TOK_PPNUM) + goto reg_error; + p = tokc.str.data; + reg = p[0] - '0'; + if ((unsigned)reg >= 8 || p[1] != '\0') + goto reg_error; + op->reg = reg; + next(); + skip(')'); + } + if (op->reg == 0) + op->type |= OP_ST0; + goto no_skip; +#ifdef TCC_TARGET_X86_64 + } else if (tok >= TOK_ASM_spl && tok <= TOK_ASM_dil) { + op->type = OP_REG8 | OP_REG8_LOW; + op->reg = 4 + tok - TOK_ASM_spl; + } else if ((op->reg = asm_parse_numeric_reg(tok, &op->type)) >= 0) { + ; +#endif + } else { + reg_error: + tcc_error("unknown register %%%s", get_tok_str(tok, &tokc)); + } + next(); + no_skip: ; + } else if (tok == '$') { + /* constant value */ + next(); + asm_expr(s1, &e); + op->type = OP_IM32; + op->e = e; + if (!op->e.sym) { + if (op->e.v == (uint8_t)op->e.v) + op->type |= OP_IM8; + if (op->e.v == (int8_t)op->e.v) + op->type |= OP_IM8S; + if (op->e.v == (uint16_t)op->e.v) + op->type |= OP_IM16; +#ifdef TCC_TARGET_X86_64 + if (op->e.v != (int32_t)op->e.v && op->e.v != (uint32_t)op->e.v) + op->type = OP_IM64; +#endif + } + } else { + /* address(reg,reg2,shift) with all variants */ + op->type = OP_EA; + op->reg = -1; + op->reg2 = -1; + op->shift = 0; + if (tok != '(') { + asm_expr(s1, &e); + op->e = e; + } else { + next(); + if (tok == '%') { + unget_tok('('); + op->e.v = 0; + op->e.sym = NULL; + } else { + /* bracketed offset expression */ + asm_expr(s1, &e); + if (tok != ')') + expect(")"); + next(); + op->e.v = e.v; + op->e.sym = e.sym; + } + op->e.pcrel = 0; + } + if (tok == '(') { + unsigned int type = 0; + next(); + if (tok != ',') { + op->reg = asm_parse_reg(&type); + } + if (tok == ',') { + next(); + if (tok != ',') { + op->reg2 = asm_parse_reg(&type); + } + if (tok == ',') { + next(); + op->shift = get_reg_shift(s1); + } + } + if (type & OP_REG32) + op->type |= OP_EA32; + skip(')'); + } + if (op->reg == -1 && op->reg2 == -1) + op->type |= OP_ADDR; + } + op->type |= indir; +} + +/* XXX: unify with C code output ? */ +ST_FUNC void gen_expr32(ExprValue *pe) +{ + if (pe->pcrel) + /* If PC-relative, always set VT_SYM, even without symbol, + so as to force a relocation to be emitted. */ + gen_addrpc32(VT_SYM, pe->sym, pe->v); + else + gen_addr32(pe->sym ? VT_SYM : 0, pe->sym, pe->v); +} + +#ifdef TCC_TARGET_X86_64 +ST_FUNC void gen_expr64(ExprValue *pe) +{ + gen_addr64(pe->sym ? VT_SYM : 0, pe->sym, pe->v); +} +#endif + +/* XXX: unify with C code output ? */ +static void gen_disp32(ExprValue *pe) +{ + Sym *sym = pe->sym; + if (sym && sym->r == cur_text_section->sh_num) { + /* same section: we can output an absolute value. Note + that the TCC compiler behaves differently here because + it always outputs a relocation to ease (future) code + elimination in the linker */ + gen_le32(pe->v + sym->jnext - ind - 4); + } else { + if (sym && sym->type.t == VT_VOID) { + sym->type.t = VT_FUNC; + sym->type.ref = NULL; + } + gen_addrpc32(VT_SYM, sym, pe->v); + } +} + +/* generate the modrm operand */ +static inline int asm_modrm(int reg, Operand *op) +{ + int mod, reg1, reg2, sib_reg1; + + if (op->type & (OP_REG | OP_MMX | OP_SSE)) { + g(0xc0 + (reg << 3) + op->reg); + } else if (op->reg == -1 && op->reg2 == -1) { + /* displacement only */ +#ifdef TCC_TARGET_X86_64 + g(0x04 + (reg << 3)); + g(0x25); +#else + g(0x05 + (reg << 3)); +#endif + gen_expr32(&op->e); +#ifdef TCC_TARGET_X86_64 + } else if (op->reg == -2) { + ExprValue *pe = &op->e; + g(0x05 + (reg << 3)); + gen_addrpc32(pe->sym ? VT_SYM : 0, pe->sym, pe->v); + return ind; +#endif + } else { + sib_reg1 = op->reg; + /* fist compute displacement encoding */ + if (sib_reg1 == -1) { + sib_reg1 = 5; + mod = 0x00; + } else if (op->e.v == 0 && !op->e.sym && op->reg != 5) { + mod = 0x00; + } else if (op->e.v == (int8_t)op->e.v && !op->e.sym) { + mod = 0x40; + } else { + mod = 0x80; + } + /* compute if sib byte needed */ + reg1 = op->reg; + if (op->reg2 != -1) + reg1 = 4; + g(mod + (reg << 3) + reg1); + if (reg1 == 4) { + /* add sib byte */ + reg2 = op->reg2; + if (reg2 == -1) + reg2 = 4; /* indicate no index */ + g((op->shift << 6) + (reg2 << 3) + sib_reg1); + } + /* add offset */ + if (mod == 0x40) { + g(op->e.v); + } else if (mod == 0x80 || op->reg == -1) { + gen_expr32(&op->e); + } + } + return 0; +} + +#ifdef TCC_TARGET_X86_64 +#define REX_W 0x48 +#define REX_R 0x44 +#define REX_X 0x42 +#define REX_B 0x41 + +static void asm_rex(int width64, Operand *ops, int nb_ops, int *op_type, + int regi, int rmi) +{ + unsigned char rex = width64 ? 0x48 : 0; + int saw_high_8bit = 0; + int i; + if (rmi == -1) { + /* No mod/rm byte, but we might have a register op nevertheless + (we will add it to the opcode later). */ + for(i = 0; i < nb_ops; i++) { + if (op_type[i] & (OP_REG | OP_ST)) { + if (ops[i].reg >= 8) { + rex |= REX_B; + ops[i].reg -= 8; + } else if (ops[i].type & OP_REG8_LOW) + rex |= 0x40; + else if (ops[i].type & OP_REG8 && ops[i].reg >= 4) + /* An 8 bit reg >= 4 without REG8 is ah/ch/dh/bh */ + saw_high_8bit = ops[i].reg; + break; + } + } + } else { + if (regi != -1) { + if (ops[regi].reg >= 8) { + rex |= REX_R; + ops[regi].reg -= 8; + } else if (ops[regi].type & OP_REG8_LOW) + rex |= 0x40; + else if (ops[regi].type & OP_REG8 && ops[regi].reg >= 4) + /* An 8 bit reg >= 4 without REG8 is ah/ch/dh/bh */ + saw_high_8bit = ops[regi].reg; + } + if (ops[rmi].type & (OP_REG | OP_MMX | OP_SSE | OP_CR | OP_EA)) { + if (ops[rmi].reg >= 8) { + rex |= REX_B; + ops[rmi].reg -= 8; + } else if (ops[rmi].type & OP_REG8_LOW) + rex |= 0x40; + else if (ops[rmi].type & OP_REG8 && ops[rmi].reg >= 4) + /* An 8 bit reg >= 4 without REG8 is ah/ch/dh/bh */ + saw_high_8bit = ops[rmi].reg; + } + if (ops[rmi].type & OP_EA && ops[rmi].reg2 >= 8) { + rex |= REX_X; + ops[rmi].reg2 -= 8; + } + } + if (rex) { + if (saw_high_8bit) + tcc_error("can't encode register %%%ch when REX prefix is required", + "acdb"[saw_high_8bit-4]); + g(rex); + } +} +#endif + +static void maybe_print_stats (void) +{ + static int already = 1; + if (!already) + /* print stats about opcodes */ + { + const struct ASMInstr *pa; + int freq[4]; + int op_vals[500]; + int nb_op_vals, i, j; + + already = 1; + nb_op_vals = 0; + memset(freq, 0, sizeof(freq)); + for(pa = asm_instrs; pa->sym != 0; pa++) { + freq[pa->nb_ops]++; + //for(i=0;inb_ops;i++) { + for(j=0;jop_type[i] == op_vals[j]) + if (pa->instr_type == op_vals[j]) + goto found; + } + //op_vals[nb_op_vals++] = pa->op_type[i]; + op_vals[nb_op_vals++] = pa->instr_type; + found: ; + //} + } + for(i=0;i= TOK_ASM_wait && opcode <= TOK_ASM_repnz) + unget_tok(';'); + + /* get operands */ + pop = ops; + nb_ops = 0; + seg_prefix = 0; + alltypes = 0; + for(;;) { + if (tok == ';' || tok == TOK_LINEFEED) + break; + if (nb_ops >= MAX_OPERANDS) { + tcc_error("incorrect number of operands"); + } + parse_operand(s1, pop); + if (tok == ':') { + if (pop->type != OP_SEG || seg_prefix) + tcc_error("incorrect prefix"); + seg_prefix = segment_prefixes[pop->reg]; + next(); + parse_operand(s1, pop); + if (!(pop->type & OP_EA)) { + tcc_error("segment prefix must be followed by memory reference"); + } + } + pop++; + nb_ops++; + if (tok != ',') + break; + next(); + } + + s = 0; /* avoid warning */ + + /* optimize matching by using a lookup table (no hashing is needed + !) */ + for(pa = asm_instrs; pa->sym != 0; pa++) { + int it = pa->instr_type & OPCT_MASK; + s = 0; + if (it == OPC_FARITH) { + v = opcode - pa->sym; + if (!((unsigned)v < 8 * 6 && (v % 6) == 0)) + continue; + } else if (it == OPC_ARITH) { + if (!(opcode >= pa->sym && opcode < pa->sym + 8*NBWLX)) + continue; + s = (opcode - pa->sym) % NBWLX; + if ((pa->instr_type & OPC_BWLX) == OPC_WLX) + { + /* We need to reject the xxxb opcodes that we accepted above. + Note that pa->sym for WLX opcodes is the 'w' token, + to get the 'b' token subtract one. */ + if (((opcode - pa->sym + 1) % NBWLX) == 0) + continue; + s++; + } + } else if (it == OPC_SHIFT) { + if (!(opcode >= pa->sym && opcode < pa->sym + 7*NBWLX)) + continue; + s = (opcode - pa->sym) % NBWLX; + } else if (it == OPC_TEST) { + if (!(opcode >= pa->sym && opcode < pa->sym + NB_TEST_OPCODES)) + continue; + /* cmovxx is a test opcode but accepts multiple sizes. + TCC doesn't accept the suffixed mnemonic, instead we + simply force size autodetection always. */ + if (pa->instr_type & OPC_WLX) + s = NBWLX - 1; + } else if (pa->instr_type & OPC_B) { +#ifdef TCC_TARGET_X86_64 + /* Some instructions don't have the full size but only + bwl form. insb e.g. */ + if ((pa->instr_type & OPC_WLQ) != OPC_WLQ + && !(opcode >= pa->sym && opcode < pa->sym + NBWLX-1)) + continue; +#endif + if (!(opcode >= pa->sym && opcode < pa->sym + NBWLX)) + continue; + s = opcode - pa->sym; + } else if (pa->instr_type & OPC_WLX) { + if (!(opcode >= pa->sym && opcode < pa->sym + NBWLX-1)) + continue; + s = opcode - pa->sym + 1; + } else { + if (pa->sym != opcode) + continue; + } + if (pa->nb_ops != nb_ops) + continue; +#ifdef TCC_TARGET_X86_64 + /* Special case for moves. Selecting the IM64->REG64 form + should only be done if we really have an >32bit imm64, and that + is hardcoded. Ignore it here. */ + if (pa->opcode == 0xb0 && ops[0].type != OP_IM64 + && (ops[1].type & OP_REG) == OP_REG64 + && !(pa->instr_type & OPC_0F)) + continue; +#endif + /* now decode and check each operand */ + alltypes = 0; + for(i = 0; i < nb_ops; i++) { + int op1, op2; + op1 = pa->op_type[i]; + op2 = op1 & 0x1f; + switch(op2) { + case OPT_IM: + v = OP_IM8 | OP_IM16 | OP_IM32; + break; + case OPT_REG: + v = OP_REG8 | OP_REG16 | OP_REG32 | OP_REG64; + break; + case OPT_REGW: + v = OP_REG16 | OP_REG32 | OP_REG64; + break; + case OPT_IMW: + v = OP_IM16 | OP_IM32; + break; + case OPT_MMXSSE: + v = OP_MMX | OP_SSE; + break; + case OPT_DISP: + case OPT_DISP8: + v = OP_ADDR; + break; + default: + v = 1 << op2; + break; + } + if (op1 & OPT_EA) + v |= OP_EA; + op_type[i] = v; + if ((ops[i].type & v) == 0) + goto next; + alltypes |= ops[i].type; + } + /* all is matching ! */ + break; + next: ; + } + if (pa->sym == 0) { + if (opcode >= TOK_ASM_first && opcode <= TOK_ASM_last) { + int b; + b = op0_codes[opcode - TOK_ASM_first]; + if (b & 0xff00) + g(b >> 8); + g(b); + return; + } else if (opcode <= TOK_ASM_alllast) { + tcc_error("bad operand with opcode '%s'", + get_tok_str(opcode, NULL)); + } else { + tcc_error("unknown opcode '%s'", + get_tok_str(opcode, NULL)); + } + } + /* if the size is unknown, then evaluate it (OPC_B or OPC_WL case) */ + autosize = NBWLX-1; +#ifdef TCC_TARGET_X86_64 + /* XXX the autosize should rather be zero, to not have to adjust this + all the time. */ + if ((pa->instr_type & OPC_BWLQ) == OPC_B) + autosize = NBWLX-2; +#endif + if (s == autosize) { + /* Check for register operands providing hints about the size. + Start from the end, i.e. destination operands. This matters + only for opcodes accepting different sized registers, lar and lsl + are such opcodes. */ + for(i = nb_ops - 1; s == autosize && i >= 0; i--) { + if ((ops[i].type & OP_REG) && !(op_type[i] & (OP_CL | OP_DX))) + s = reg_to_size[ops[i].type & OP_REG]; + } + if (s == autosize) { + if ((opcode == TOK_ASM_push || opcode == TOK_ASM_pop) && + (ops[0].type & (OP_SEG | OP_IM8S | OP_IM32))) + s = 2; + else if ((opcode == TOK_ASM_push || opcode == TOK_ASM_pop) && + (ops[0].type & OP_EA)) + s = NBWLX - 2; + else + tcc_error("cannot infer opcode suffix"); + } + } + +#ifdef TCC_TARGET_X86_64 + /* Generate addr32 prefix if needed */ + for(i = 0; i < nb_ops; i++) { + if (ops[i].type & OP_EA32) { + g(0x67); + break; + } + } +#endif + /* generate data16 prefix if needed */ + p66 = 0; + if (s == 1) + p66 = 1; + else { + /* accepting mmx+sse in all operands --> needs 0x66 to + switch to sse mode. Accepting only sse in an operand --> is + already SSE insn and needs 0x66/f2/f3 handling. */ + for (i = 0; i < nb_ops; i++) + if ((op_type[i] & (OP_MMX | OP_SSE)) == (OP_MMX | OP_SSE) + && ops[i].type & OP_SSE) + p66 = 1; + } + if (p66) + g(0x66); +#ifdef TCC_TARGET_X86_64 + rex64 = 0; + if (pa->instr_type & OPC_48) + rex64 = 1; + else if (s == 3 || (alltypes & OP_REG64)) { + /* generate REX prefix */ + int default64 = 0; + for(i = 0; i < nb_ops; i++) { + if (op_type[i] == OP_REG64 && pa->opcode != 0xb8) { + /* If only 64bit regs are accepted in one operand + this is a default64 instruction without need for + REX prefixes, except for movabs(0xb8). */ + default64 = 1; + break; + } + } + /* XXX find better encoding for the default64 instructions. */ + if (((opcode != TOK_ASM_push && opcode != TOK_ASM_pop + && opcode != TOK_ASM_pushw && opcode != TOK_ASM_pushl + && opcode != TOK_ASM_pushq && opcode != TOK_ASM_popw + && opcode != TOK_ASM_popl && opcode != TOK_ASM_popq + && opcode != TOK_ASM_call && opcode != TOK_ASM_jmp)) + && !default64) + rex64 = 1; + } +#endif + + /* now generates the operation */ + if (OPCT_IS(pa->instr_type, OPC_FWAIT)) + g(0x9b); + if (seg_prefix) + g(seg_prefix); + + v = pa->opcode; + if (pa->instr_type & OPC_0F) + v = ((v & ~0xff) << 8) | 0x0f00 | (v & 0xff); + if ((v == 0x69 || v == 0x6b) && nb_ops == 2) { + /* kludge for imul $im, %reg */ + nb_ops = 3; + ops[2] = ops[1]; + op_type[2] = op_type[1]; + } else if (v == 0xcd && ops[0].e.v == 3 && !ops[0].e.sym) { + v--; /* int $3 case */ + nb_ops = 0; + } else if ((v == 0x06 || v == 0x07)) { + if (ops[0].reg >= 4) { + /* push/pop %fs or %gs */ + v = 0x0fa0 + (v - 0x06) + ((ops[0].reg - 4) << 3); + } else { + v += ops[0].reg << 3; + } + nb_ops = 0; + } else if (v <= 0x05) { + /* arith case */ + v += ((opcode - TOK_ASM_addb) / NBWLX) << 3; + } else if ((pa->instr_type & (OPCT_MASK | OPC_MODRM)) == OPC_FARITH) { + /* fpu arith case */ + v += ((opcode - pa->sym) / 6) << 3; + } + + /* search which operand will be used for modrm */ + modrm_index = -1; + modreg_index = -1; + if (pa->instr_type & OPC_MODRM) { + if (!nb_ops) { + /* A modrm opcode without operands is a special case (e.g. mfence). + It has a group and acts as if there's an register operand 0 + (ax). */ + i = 0; + ops[i].type = OP_REG; + ops[i].reg = 0; + goto modrm_found; + } + /* first look for an ea operand */ + for(i = 0;i < nb_ops; i++) { + if (op_type[i] & OP_EA) + goto modrm_found; + } + /* then if not found, a register or indirection (shift instructions) */ + for(i = 0;i < nb_ops; i++) { + if (op_type[i] & (OP_REG | OP_MMX | OP_SSE | OP_INDIR)) + goto modrm_found; + } +#ifdef ASM_DEBUG + tcc_error("bad op table"); +#endif + modrm_found: + modrm_index = i; + /* if a register is used in another operand then it is + used instead of group */ + for(i = 0;i < nb_ops; i++) { + int t = op_type[i]; + if (i != modrm_index && + (t & (OP_REG | OP_MMX | OP_SSE | OP_CR | OP_TR | OP_DB | OP_SEG))) { + modreg_index = i; + break; + } + } + } +#ifdef TCC_TARGET_X86_64 + asm_rex (rex64, ops, nb_ops, op_type, modreg_index, modrm_index); +#endif + + if (pa->instr_type & OPC_REG) { + /* mov $im, %reg case */ + if (v == 0xb0 && s >= 1) + v += 7; + for(i = 0; i < nb_ops; i++) { + if (op_type[i] & (OP_REG | OP_ST)) { + v += ops[i].reg; + break; + } + } + } + if (pa->instr_type & OPC_B) + v += s >= 1; + if (nb_ops == 1 && pa->op_type[0] == OPT_DISP8) { + Sym *sym; + int jmp_disp; + + /* see if we can really generate the jump with a byte offset */ + sym = ops[0].e.sym; + if (!sym) + goto no_short_jump; + if (sym->r != cur_text_section->sh_num) + goto no_short_jump; + jmp_disp = ops[0].e.v + sym->jnext - ind - 2 - (v >= 0xff); + if (jmp_disp == (int8_t)jmp_disp) { + /* OK to generate jump */ + ops[0].e.sym = 0; + ops[0].e.v = jmp_disp; + op_type[0] = OP_IM8S; + } else { + no_short_jump: + /* long jump will be allowed. need to modify the + opcode slightly */ + if (v == 0xeb) /* jmp */ + v = 0xe9; + else if (v == 0x70) /* jcc */ + v += 0x0f10; + else + tcc_error("invalid displacement"); + } + } + if (OPCT_IS(pa->instr_type, OPC_TEST)) + v += test_bits[opcode - pa->sym]; + op1 = v >> 16; + if (op1) + g(op1); + op1 = (v >> 8) & 0xff; + if (op1) + g(op1); + g(v); + + if (OPCT_IS(pa->instr_type, OPC_SHIFT)) { + reg = (opcode - pa->sym) / NBWLX; + if (reg == 6) + reg = 7; + } else if (OPCT_IS(pa->instr_type, OPC_ARITH)) { + reg = (opcode - pa->sym) / NBWLX; + } else if (OPCT_IS(pa->instr_type, OPC_FARITH)) { + reg = (opcode - pa->sym) / 6; + } else { + reg = (pa->instr_type >> OPC_GROUP_SHIFT) & 7; + } + + pc = 0; + if (pa->instr_type & OPC_MODRM) { + /* if a register is used in another operand then it is + used instead of group */ + if (modreg_index >= 0) + reg = ops[modreg_index].reg; + pc = asm_modrm(reg, &ops[modrm_index]); + } + + /* emit constants */ +#ifndef TCC_TARGET_X86_64 + if (!(pa->instr_type & OPC_0F) + && (pa->opcode == 0x9a || pa->opcode == 0xea)) { + /* ljmp or lcall kludge */ + gen_expr32(&ops[1].e); + if (ops[0].e.sym) + tcc_error("cannot relocate"); + gen_le16(ops[0].e.v); + return; + } +#endif + for(i = 0;i < nb_ops; i++) { + v = op_type[i]; + if (v & (OP_IM8 | OP_IM16 | OP_IM32 | OP_IM64 | OP_IM8S | OP_ADDR)) { + /* if multiple sizes are given it means we must look + at the op size */ + if ((v | OP_IM8 | OP_IM64) == (OP_IM8 | OP_IM16 | OP_IM32 | OP_IM64)) { + if (s == 0) + v = OP_IM8; + else if (s == 1) + v = OP_IM16; + else if (s == 2 || (v & OP_IM64) == 0) + v = OP_IM32; + else + v = OP_IM64; + } + + if ((v & (OP_IM8 | OP_IM8S | OP_IM16)) && ops[i].e.sym) + tcc_error("cannot relocate"); + + if (v & (OP_IM8 | OP_IM8S)) { + g(ops[i].e.v); + } else if (v & OP_IM16) { + gen_le16(ops[i].e.v); +#ifdef TCC_TARGET_X86_64 + } else if (v & OP_IM64) { + gen_expr64(&ops[i].e); +#endif + } else if (pa->op_type[i] == OPT_DISP || pa->op_type[i] == OPT_DISP8) { + gen_disp32(&ops[i].e); + } else { + gen_expr32(&ops[i].e); + } + } + } + + /* after immediate operands, adjust pc-relative address */ + if (pc) + add32le(cur_text_section->data + pc - 4, pc - ind); +} + +/* return the constraint priority (we allocate first the lowest + numbered constraints) */ +static inline int constraint_priority(const char *str) +{ + int priority, c, pr; + + /* we take the lowest priority */ + priority = 0; + for(;;) { + c = *str; + if (c == '\0') + break; + str++; + switch(c) { + case 'A': + pr = 0; + break; + case 'a': + case 'b': + case 'c': + case 'd': + case 'S': + case 'D': + pr = 1; + break; + case 'q': + pr = 2; + break; + case 'r': + case 'R': + case 'p': + pr = 3; + break; + case 'N': + case 'M': + case 'I': + case 'e': + case 'i': + case 'm': + case 'g': + pr = 4; + break; + default: + tcc_error("unknown constraint '%c'", c); + pr = 0; + } + if (pr > priority) + priority = pr; + } + return priority; +} + +static const char *skip_constraint_modifiers(const char *p) +{ + while (*p == '=' || *p == '&' || *p == '+' || *p == '%') + p++; + return p; +} + +/* If T (a token) is of the form "%reg" returns the register + number and type, otherwise return -1. */ +ST_FUNC int asm_parse_regvar (int t) +{ + const char *s; + Operand op; + if (t < TOK_IDENT) + return -1; + s = table_ident[t - TOK_IDENT]->str; + if (s[0] != '%') + return -1; + t = tok_alloc(s+1, strlen(s)-1)->tok; + unget_tok(t); + unget_tok('%'); + parse_operand(tcc_state, &op); + /* Accept only integer regs for now. */ + if (op.type & OP_REG) + return op.reg; + else + return -1; +} + +#define REG_OUT_MASK 0x01 +#define REG_IN_MASK 0x02 + +#define is_reg_allocated(reg) (regs_allocated[reg] & reg_mask) + +ST_FUNC void asm_compute_constraints(ASMOperand *operands, + int nb_operands, int nb_outputs, + const uint8_t *clobber_regs, + int *pout_reg) +{ + ASMOperand *op; + int sorted_op[MAX_ASM_OPERANDS]; + int i, j, k, p1, p2, tmp, reg, c, reg_mask; + const char *str; + uint8_t regs_allocated[NB_ASM_REGS]; + + /* init fields */ + for(i=0;iinput_index = -1; + op->ref_index = -1; + op->reg = -1; + op->is_memory = 0; + op->is_rw = 0; + } + /* compute constraint priority and evaluate references to output + constraints if input constraints */ + for(i=0;iconstraint; + str = skip_constraint_modifiers(str); + if (isnum(*str) || *str == '[') { + /* this is a reference to another constraint */ + k = find_constraint(operands, nb_operands, str, NULL); + if ((unsigned)k >= i || i < nb_outputs) + tcc_error("invalid reference in constraint %d ('%s')", + i, str); + op->ref_index = k; + if (operands[k].input_index >= 0) + tcc_error("cannot reference twice the same operand"); + operands[k].input_index = i; + op->priority = 5; + } else if ((op->vt->r & VT_VALMASK) == VT_LOCAL + && op->vt->sym + && (reg = op->vt->sym->r & VT_VALMASK) < VT_CONST) { + op->priority = 1; + op->reg = reg; + } else { + op->priority = constraint_priority(str); + } + } + + /* sort operands according to their priority */ + for(i=0;iconstraint; + /* no need to allocate references */ + if (op->ref_index >= 0) + continue; + /* select if register is used for output, input or both */ + if (op->input_index >= 0) { + reg_mask = REG_IN_MASK | REG_OUT_MASK; + } else if (j < nb_outputs) { + reg_mask = REG_OUT_MASK; + } else { + reg_mask = REG_IN_MASK; + } + if (op->reg >= 0) { + if (is_reg_allocated(op->reg)) + tcc_error("asm regvar requests register that's taken already"); + reg = op->reg; + goto reg_found; + } + try_next: + c = *str++; + switch(c) { + case '=': + goto try_next; + case '+': + op->is_rw = 1; + /* FALL THRU */ + case '&': + if (j >= nb_outputs) + tcc_error("'%c' modifier can only be applied to outputs", c); + reg_mask = REG_IN_MASK | REG_OUT_MASK; + goto try_next; + case 'A': + /* allocate both eax and edx */ + if (is_reg_allocated(TREG_XAX) || + is_reg_allocated(TREG_XDX)) + goto try_next; + op->is_llong = 1; + op->reg = TREG_XAX; + regs_allocated[TREG_XAX] |= reg_mask; + regs_allocated[TREG_XDX] |= reg_mask; + break; + case 'a': + reg = TREG_XAX; + goto alloc_reg; + case 'b': + reg = 3; + goto alloc_reg; + case 'c': + reg = TREG_XCX; + goto alloc_reg; + case 'd': + reg = TREG_XDX; + goto alloc_reg; + case 'S': + reg = 6; + goto alloc_reg; + case 'D': + reg = 7; + alloc_reg: + if (is_reg_allocated(reg)) + goto try_next; + goto reg_found; + case 'q': + /* eax, ebx, ecx or edx */ + for(reg = 0; reg < 4; reg++) { + if (!is_reg_allocated(reg)) + goto reg_found; + } + goto try_next; + case 'r': + case 'R': + case 'p': /* A general address, for x86(64) any register is acceptable*/ + /* any general register */ + for(reg = 0; reg < 8; reg++) { + if (!is_reg_allocated(reg)) + goto reg_found; + } + goto try_next; + reg_found: + /* now we can reload in the register */ + op->is_llong = 0; + op->reg = reg; + regs_allocated[reg] |= reg_mask; + break; + case 'e': + case 'i': + if (!((op->vt->r & (VT_VALMASK | VT_LVAL)) == VT_CONST)) + goto try_next; + break; + case 'I': + case 'N': + case 'M': + if (!((op->vt->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST)) + goto try_next; + break; + case 'm': + case 'g': + /* nothing special to do because the operand is already in + memory, except if the pointer itself is stored in a + memory variable (VT_LLOCAL case) */ + /* XXX: fix constant case */ + /* if it is a reference to a memory zone, it must lie + in a register, so we reserve the register in the + input registers and a load will be generated + later */ + if (j < nb_outputs || c == 'm') { + if ((op->vt->r & VT_VALMASK) == VT_LLOCAL) { + /* any general register */ + for(reg = 0; reg < 8; reg++) { + if (!(regs_allocated[reg] & REG_IN_MASK)) + goto reg_found1; + } + goto try_next; + reg_found1: + /* now we can reload in the register */ + regs_allocated[reg] |= REG_IN_MASK; + op->reg = reg; + op->is_memory = 1; + } + } + break; + default: + tcc_error("asm constraint %d ('%s') could not be satisfied", + j, op->constraint); + break; + } + /* if a reference is present for that operand, we assign it too */ + if (op->input_index >= 0) { + operands[op->input_index].reg = op->reg; + operands[op->input_index].is_llong = op->is_llong; + } + } + + /* compute out_reg. It is used to store outputs registers to memory + locations references by pointers (VT_LLOCAL case) */ + *pout_reg = -1; + for(i=0;ireg >= 0 && + (op->vt->r & VT_VALMASK) == VT_LLOCAL && + !op->is_memory) { + for(reg = 0; reg < 8; reg++) { + if (!(regs_allocated[reg] & REG_OUT_MASK)) + goto reg_found2; + } + tcc_error("could not find free output register for reloading"); + reg_found2: + *pout_reg = reg; + break; + } + } + + /* print sorted constraints */ +#ifdef ASM_DEBUG + for(i=0;iid ? get_tok_str(op->id, NULL) : "", + op->constraint, + op->vt->r, + op->reg); + } + if (*pout_reg >= 0) + printf("out_reg=%d\n", *pout_reg); +#endif +} + +ST_FUNC void subst_asm_operand(CString *add_str, + SValue *sv, int modifier) +{ + int r, reg, size, val; + char buf[64]; + + r = sv->r; + if ((r & VT_VALMASK) == VT_CONST) { + if (!(r & VT_LVAL) && modifier != 'c' && modifier != 'n' && + modifier != 'P') + cstr_ccat(add_str, '$'); + if (r & VT_SYM) { + const char *name = get_tok_str(sv->sym->v, NULL); + if (sv->sym->v >= SYM_FIRST_ANOM) { + /* In case of anonymous symbols ("L.42", used + for static data labels) we can't find them + in the C symbol table when later looking up + this name. So enter them now into the asm label + list when we still know the symbol. */ + get_asm_sym(tok_alloc(name, strlen(name))->tok, sv->sym); + } + cstr_cat(add_str, name, -1); + if ((uint32_t)sv->c.i == 0) + goto no_offset; + cstr_ccat(add_str, '+'); + } + val = sv->c.i; + if (modifier == 'n') + val = -val; + snprintf(buf, sizeof(buf), "%d", (int)sv->c.i); + cstr_cat(add_str, buf, -1); + no_offset:; +#ifdef TCC_TARGET_X86_64 + if (r & VT_LVAL) + cstr_cat(add_str, "(%rip)", -1); +#endif + } else if ((r & VT_VALMASK) == VT_LOCAL) { +#ifdef TCC_TARGET_X86_64 + snprintf(buf, sizeof(buf), "%d(%%rbp)", (int)sv->c.i); +#else + snprintf(buf, sizeof(buf), "%d(%%ebp)", (int)sv->c.i); +#endif + cstr_cat(add_str, buf, -1); + } else if (r & VT_LVAL) { + reg = r & VT_VALMASK; + if (reg >= VT_CONST) + tcc_error("internal compiler error"); + snprintf(buf, sizeof(buf), "(%%%s)", +#ifdef TCC_TARGET_X86_64 + get_tok_str(TOK_ASM_rax + reg, NULL) +#else + get_tok_str(TOK_ASM_eax + reg, NULL) +#endif + ); + cstr_cat(add_str, buf, -1); + } else { + /* register case */ + reg = r & VT_VALMASK; + if (reg >= VT_CONST) + tcc_error("internal compiler error"); + + /* choose register operand size */ + if ((sv->type.t & VT_BTYPE) == VT_BYTE || + (sv->type.t & VT_BTYPE) == VT_BOOL) + size = 1; + else if ((sv->type.t & VT_BTYPE) == VT_SHORT) + size = 2; +#ifdef TCC_TARGET_X86_64 + else if ((sv->type.t & VT_BTYPE) == VT_LLONG || + (sv->type.t & VT_BTYPE) == VT_PTR) + size = 8; +#endif + else + size = 4; + if (size == 1 && reg >= 4) + size = 4; + + if (modifier == 'b') { + if (reg >= 4) + tcc_error("cannot use byte register"); + size = 1; + } else if (modifier == 'h') { + if (reg >= 4) + tcc_error("cannot use byte register"); + size = -1; + } else if (modifier == 'w') { + size = 2; + } else if (modifier == 'k') { + size = 4; +#ifdef TCC_TARGET_X86_64 + } else if (modifier == 'q') { + size = 8; +#endif + } + + switch(size) { + case -1: + reg = TOK_ASM_ah + reg; + break; + case 1: + reg = TOK_ASM_al + reg; + break; + case 2: + reg = TOK_ASM_ax + reg; + break; + default: + reg = TOK_ASM_eax + reg; + break; +#ifdef TCC_TARGET_X86_64 + case 8: + reg = TOK_ASM_rax + reg; + break; +#endif + } + snprintf(buf, sizeof(buf), "%%%s", get_tok_str(reg, NULL)); + cstr_cat(add_str, buf, -1); + } +} + +/* generate prolog and epilog code for asm statement */ +ST_FUNC void asm_gen_code(ASMOperand *operands, int nb_operands, + int nb_outputs, int is_output, + uint8_t *clobber_regs, + int out_reg) +{ + uint8_t regs_allocated[NB_ASM_REGS]; + ASMOperand *op; + int i, reg; + + /* Strictly speaking %Xbp and %Xsp should be included in the + call-preserved registers, but currently it doesn't matter. */ +#ifdef TCC_TARGET_X86_64 +#ifdef TCC_TARGET_PE + static uint8_t reg_saved[] = { 3, 6, 7, 12, 13, 14, 15 }; +#else + static uint8_t reg_saved[] = { 3, 12, 13, 14, 15 }; +#endif +#else + static uint8_t reg_saved[] = { 3, 6, 7 }; +#endif + + /* mark all used registers */ + memcpy(regs_allocated, clobber_regs, sizeof(regs_allocated)); + for(i = 0; i < nb_operands;i++) { + op = &operands[i]; + if (op->reg >= 0) + regs_allocated[op->reg] = 1; + } + if (!is_output) { + /* generate reg save code */ + for(i = 0; i < sizeof(reg_saved)/sizeof(reg_saved[0]); i++) { + reg = reg_saved[i]; + if (regs_allocated[reg]) { + if (reg >= 8) + g(0x41), reg-=8; + g(0x50 + reg); + } + } + + /* generate load code */ + for(i = 0; i < nb_operands; i++) { + op = &operands[i]; + if (op->reg >= 0) { + if ((op->vt->r & VT_VALMASK) == VT_LLOCAL && + op->is_memory) { + /* memory reference case (for both input and + output cases) */ + SValue sv; + sv = *op->vt; + sv.r = (sv.r & ~VT_VALMASK) | VT_LOCAL | VT_LVAL; + sv.type.t = VT_PTR; + load(op->reg, &sv); + } else if (i >= nb_outputs || op->is_rw) { + /* load value in register */ + load(op->reg, op->vt); + if (op->is_llong) { + SValue sv; + sv = *op->vt; + sv.c.i += 4; + load(TREG_XDX, &sv); + } + } + } + } + } else { + /* generate save code */ + for(i = 0 ; i < nb_outputs; i++) { + op = &operands[i]; + if (op->reg >= 0) { + if ((op->vt->r & VT_VALMASK) == VT_LLOCAL) { + if (!op->is_memory) { + SValue sv; + sv = *op->vt; + sv.r = (sv.r & ~VT_VALMASK) | VT_LOCAL; + sv.type.t = VT_PTR; + load(out_reg, &sv); + + sv = *op->vt; + sv.r = (sv.r & ~VT_VALMASK) | out_reg; + store(op->reg, &sv); + } + } else { + store(op->reg, op->vt); + if (op->is_llong) { + SValue sv; + sv = *op->vt; + sv.c.i += 4; + store(TREG_XDX, &sv); + } + } + } + } + /* generate reg restore code */ + for(i = sizeof(reg_saved)/sizeof(reg_saved[0]) - 1; i >= 0; i--) { + reg = reg_saved[i]; + if (regs_allocated[reg]) { + if (reg >= 8) + g(0x41), reg-=8; + g(0x58 + reg); + } + } + } +} + +ST_FUNC void asm_clobber(uint8_t *clobber_regs, const char *str) +{ + int reg; + TokenSym *ts; +#ifdef TCC_TARGET_X86_64 + unsigned int type; +#endif + + if (!strcmp(str, "memory") || + !strcmp(str, "cc") || + !strcmp(str, "flags")) + return; + ts = tok_alloc(str, strlen(str)); + reg = ts->tok; + if (reg >= TOK_ASM_eax && reg <= TOK_ASM_edi) { + reg -= TOK_ASM_eax; + } else if (reg >= TOK_ASM_ax && reg <= TOK_ASM_di) { + reg -= TOK_ASM_ax; +#ifdef TCC_TARGET_X86_64 + } else if (reg >= TOK_ASM_rax && reg <= TOK_ASM_rdi) { + reg -= TOK_ASM_rax; + } else if ((reg = asm_parse_numeric_reg(reg, &type)) >= 0) { + ; +#endif + } else { + tcc_error("invalid clobber register '%s'", str); + } + clobber_regs[reg] = 1; +} diff --git a/tinyc/i386-asm.h b/tinyc/i386-asm.h new file mode 100644 index 000000000..65d517955 --- /dev/null +++ b/tinyc/i386-asm.h @@ -0,0 +1,480 @@ + DEF_ASM_OP0(clc, 0xf8) /* must be first OP0 */ + DEF_ASM_OP0(cld, 0xfc) + DEF_ASM_OP0(cli, 0xfa) + DEF_ASM_OP0(clts, 0x0f06) + DEF_ASM_OP0(cmc, 0xf5) + DEF_ASM_OP0(lahf, 0x9f) + DEF_ASM_OP0(sahf, 0x9e) + DEF_ASM_OP0(pusha, 0x60) + DEF_ASM_OP0(popa, 0x61) + DEF_ASM_OP0(pushfl, 0x9c) + DEF_ASM_OP0(popfl, 0x9d) + DEF_ASM_OP0(pushf, 0x9c) + DEF_ASM_OP0(popf, 0x9d) + DEF_ASM_OP0(stc, 0xf9) + DEF_ASM_OP0(std, 0xfd) + DEF_ASM_OP0(sti, 0xfb) + DEF_ASM_OP0(aaa, 0x37) + DEF_ASM_OP0(aas, 0x3f) + DEF_ASM_OP0(daa, 0x27) + DEF_ASM_OP0(das, 0x2f) + DEF_ASM_OP0(aad, 0xd50a) + DEF_ASM_OP0(aam, 0xd40a) + DEF_ASM_OP0(cbw, 0x6698) + DEF_ASM_OP0(cwd, 0x6699) + DEF_ASM_OP0(cwde, 0x98) + DEF_ASM_OP0(cdq, 0x99) + DEF_ASM_OP0(cbtw, 0x6698) + DEF_ASM_OP0(cwtl, 0x98) + DEF_ASM_OP0(cwtd, 0x6699) + DEF_ASM_OP0(cltd, 0x99) + DEF_ASM_OP0(int3, 0xcc) + DEF_ASM_OP0(into, 0xce) + DEF_ASM_OP0(iret, 0xcf) + DEF_ASM_OP0(rsm, 0x0faa) + DEF_ASM_OP0(hlt, 0xf4) + DEF_ASM_OP0(nop, 0x90) + DEF_ASM_OP0(pause, 0xf390) + DEF_ASM_OP0(xlat, 0xd7) + + /* strings */ +ALT(DEF_ASM_OP0L(cmpsb, 0xa6, 0, OPC_BWLX)) +ALT(DEF_ASM_OP0L(scmpb, 0xa6, 0, OPC_BWLX)) + +ALT(DEF_ASM_OP0L(insb, 0x6c, 0, OPC_BWL)) +ALT(DEF_ASM_OP0L(outsb, 0x6e, 0, OPC_BWL)) + +ALT(DEF_ASM_OP0L(lodsb, 0xac, 0, OPC_BWLX)) +ALT(DEF_ASM_OP0L(slodb, 0xac, 0, OPC_BWLX)) + +ALT(DEF_ASM_OP0L(movsb, 0xa4, 0, OPC_BWLX)) +ALT(DEF_ASM_OP0L(smovb, 0xa4, 0, OPC_BWLX)) + +ALT(DEF_ASM_OP0L(scasb, 0xae, 0, OPC_BWLX)) +ALT(DEF_ASM_OP0L(sscab, 0xae, 0, OPC_BWLX)) + +ALT(DEF_ASM_OP0L(stosb, 0xaa, 0, OPC_BWLX)) +ALT(DEF_ASM_OP0L(sstob, 0xaa, 0, OPC_BWLX)) + + /* bits */ + +ALT(DEF_ASM_OP2(bsfw, 0x0fbc, 0, OPC_MODRM | OPC_WLX, OPT_REGW | OPT_EA, OPT_REGW)) +ALT(DEF_ASM_OP2(bsrw, 0x0fbd, 0, OPC_MODRM | OPC_WLX, OPT_REGW | OPT_EA, OPT_REGW)) + +ALT(DEF_ASM_OP2(btw, 0x0fa3, 0, OPC_MODRM | OPC_WLX, OPT_REGW, OPT_REGW | OPT_EA)) +ALT(DEF_ASM_OP2(btw, 0x0fba, 4, OPC_MODRM | OPC_WLX, OPT_IM8, OPT_REGW | OPT_EA)) + +ALT(DEF_ASM_OP2(btsw, 0x0fab, 0, OPC_MODRM | OPC_WLX, OPT_REGW, OPT_REGW | OPT_EA)) +ALT(DEF_ASM_OP2(btsw, 0x0fba, 5, OPC_MODRM | OPC_WLX, OPT_IM8, OPT_REGW | OPT_EA)) + +ALT(DEF_ASM_OP2(btrw, 0x0fb3, 0, OPC_MODRM | OPC_WLX, OPT_REGW, OPT_REGW | OPT_EA)) +ALT(DEF_ASM_OP2(btrw, 0x0fba, 6, OPC_MODRM | OPC_WLX, OPT_IM8, OPT_REGW | OPT_EA)) + +ALT(DEF_ASM_OP2(btcw, 0x0fbb, 0, OPC_MODRM | OPC_WLX, OPT_REGW, OPT_REGW | OPT_EA)) +ALT(DEF_ASM_OP2(btcw, 0x0fba, 7, OPC_MODRM | OPC_WLX, OPT_IM8, OPT_REGW | OPT_EA)) + + /* prefixes */ + DEF_ASM_OP0(wait, 0x9b) + DEF_ASM_OP0(fwait, 0x9b) + DEF_ASM_OP0(aword, 0x67) + DEF_ASM_OP0(addr16, 0x67) + ALT(DEF_ASM_OP0(word, 0x66)) + DEF_ASM_OP0(data16, 0x66) + DEF_ASM_OP0(lock, 0xf0) + DEF_ASM_OP0(rep, 0xf3) + DEF_ASM_OP0(repe, 0xf3) + DEF_ASM_OP0(repz, 0xf3) + DEF_ASM_OP0(repne, 0xf2) + DEF_ASM_OP0(repnz, 0xf2) + + DEF_ASM_OP0(invd, 0x0f08) + DEF_ASM_OP0(wbinvd, 0x0f09) + DEF_ASM_OP0(cpuid, 0x0fa2) + DEF_ASM_OP0(wrmsr, 0x0f30) + DEF_ASM_OP0(rdtsc, 0x0f31) + DEF_ASM_OP0(rdmsr, 0x0f32) + DEF_ASM_OP0(rdpmc, 0x0f33) + DEF_ASM_OP0(ud2, 0x0f0b) + + /* NOTE: we took the same order as gas opcode definition order */ +ALT(DEF_ASM_OP2(movb, 0xa0, 0, OPC_BWLX, OPT_ADDR, OPT_EAX)) +ALT(DEF_ASM_OP2(movb, 0xa2, 0, OPC_BWLX, OPT_EAX, OPT_ADDR)) +ALT(DEF_ASM_OP2(movb, 0x88, 0, OPC_MODRM | OPC_BWLX, OPT_REG, OPT_EA | OPT_REG)) +ALT(DEF_ASM_OP2(movb, 0x8a, 0, OPC_MODRM | OPC_BWLX, OPT_EA | OPT_REG, OPT_REG)) +ALT(DEF_ASM_OP2(movb, 0xb0, 0, OPC_REG | OPC_BWLX, OPT_IM, OPT_REG)) +ALT(DEF_ASM_OP2(movb, 0xc6, 0, OPC_MODRM | OPC_BWLX, OPT_IM, OPT_REG | OPT_EA)) + +ALT(DEF_ASM_OP2(movw, 0x8c, 0, OPC_MODRM | OPC_WLX, OPT_SEG, OPT_EA | OPT_REG)) +ALT(DEF_ASM_OP2(movw, 0x8e, 0, OPC_MODRM | OPC_WLX, OPT_EA | OPT_REG, OPT_SEG)) + +ALT(DEF_ASM_OP2(movw, 0x0f20, 0, OPC_MODRM | OPC_WLX, OPT_CR, OPT_REG32)) +ALT(DEF_ASM_OP2(movw, 0x0f21, 0, OPC_MODRM | OPC_WLX, OPT_DB, OPT_REG32)) +ALT(DEF_ASM_OP2(movw, 0x0f24, 0, OPC_MODRM | OPC_WLX, OPT_TR, OPT_REG32)) +ALT(DEF_ASM_OP2(movw, 0x0f22, 0, OPC_MODRM | OPC_WLX, OPT_REG32, OPT_CR)) +ALT(DEF_ASM_OP2(movw, 0x0f23, 0, OPC_MODRM | OPC_WLX, OPT_REG32, OPT_DB)) +ALT(DEF_ASM_OP2(movw, 0x0f26, 0, OPC_MODRM | OPC_WLX, OPT_REG32, OPT_TR)) + +ALT(DEF_ASM_OP2(movsbl, 0x0fbe, 0, OPC_MODRM, OPT_REG8 | OPT_EA, OPT_REG32)) +ALT(DEF_ASM_OP2(movsbw, 0x660fbe, 0, OPC_MODRM, OPT_REG8 | OPT_EA, OPT_REG16)) +ALT(DEF_ASM_OP2(movswl, 0x0fbf, 0, OPC_MODRM, OPT_REG16 | OPT_EA, OPT_REG32)) +ALT(DEF_ASM_OP2(movzbw, 0x0fb6, 0, OPC_MODRM | OPC_WLX, OPT_REG8 | OPT_EA, OPT_REGW)) +ALT(DEF_ASM_OP2(movzwl, 0x0fb7, 0, OPC_MODRM, OPT_REG16 | OPT_EA, OPT_REG32)) + +ALT(DEF_ASM_OP1(pushw, 0x50, 0, OPC_REG | OPC_WLX, OPT_REGW)) +ALT(DEF_ASM_OP1(pushw, 0xff, 6, OPC_MODRM | OPC_WLX, OPT_REGW | OPT_EA)) +ALT(DEF_ASM_OP1(pushw, 0x6a, 0, OPC_WLX, OPT_IM8S)) +ALT(DEF_ASM_OP1(pushw, 0x68, 0, OPC_WLX, OPT_IM32)) +ALT(DEF_ASM_OP1(pushw, 0x06, 0, OPC_WLX, OPT_SEG)) + +ALT(DEF_ASM_OP1(popw, 0x58, 0, OPC_REG | OPC_WLX, OPT_REGW)) +ALT(DEF_ASM_OP1(popw, 0x8f, 0, OPC_MODRM | OPC_WLX, OPT_REGW | OPT_EA)) +ALT(DEF_ASM_OP1(popw, 0x07, 0, OPC_WLX, OPT_SEG)) + +ALT(DEF_ASM_OP2(xchgw, 0x90, 0, OPC_REG | OPC_WLX, OPT_REGW, OPT_EAX)) +ALT(DEF_ASM_OP2(xchgw, 0x90, 0, OPC_REG | OPC_WLX, OPT_EAX, OPT_REGW)) +ALT(DEF_ASM_OP2(xchgb, 0x86, 0, OPC_MODRM | OPC_BWLX, OPT_REG, OPT_EA | OPT_REG)) +ALT(DEF_ASM_OP2(xchgb, 0x86, 0, OPC_MODRM | OPC_BWLX, OPT_EA | OPT_REG, OPT_REG)) + +ALT(DEF_ASM_OP2(inb, 0xe4, 0, OPC_BWL, OPT_IM8, OPT_EAX)) +ALT(DEF_ASM_OP1(inb, 0xe4, 0, OPC_BWL, OPT_IM8)) +ALT(DEF_ASM_OP2(inb, 0xec, 0, OPC_BWL, OPT_DX, OPT_EAX)) +ALT(DEF_ASM_OP1(inb, 0xec, 0, OPC_BWL, OPT_DX)) + +ALT(DEF_ASM_OP2(outb, 0xe6, 0, OPC_BWL, OPT_EAX, OPT_IM8)) +ALT(DEF_ASM_OP1(outb, 0xe6, 0, OPC_BWL, OPT_IM8)) +ALT(DEF_ASM_OP2(outb, 0xee, 0, OPC_BWL, OPT_EAX, OPT_DX)) +ALT(DEF_ASM_OP1(outb, 0xee, 0, OPC_BWL, OPT_DX)) + +ALT(DEF_ASM_OP2(leaw, 0x8d, 0, OPC_MODRM | OPC_WLX, OPT_EA, OPT_REG)) + +ALT(DEF_ASM_OP2(les, 0xc4, 0, OPC_MODRM, OPT_EA, OPT_REG32)) +ALT(DEF_ASM_OP2(lds, 0xc5, 0, OPC_MODRM, OPT_EA, OPT_REG32)) +ALT(DEF_ASM_OP2(lss, 0x0fb2, 0, OPC_MODRM, OPT_EA, OPT_REG32)) +ALT(DEF_ASM_OP2(lfs, 0x0fb4, 0, OPC_MODRM, OPT_EA, OPT_REG32)) +ALT(DEF_ASM_OP2(lgs, 0x0fb5, 0, OPC_MODRM, OPT_EA, OPT_REG32)) + + /* arith */ +ALT(DEF_ASM_OP2(addb, 0x00, 0, OPC_ARITH | OPC_MODRM | OPC_BWLX, OPT_REG, OPT_EA | OPT_REG)) /* XXX: use D bit ? */ +ALT(DEF_ASM_OP2(addb, 0x02, 0, OPC_ARITH | OPC_MODRM | OPC_BWLX, OPT_EA | OPT_REG, OPT_REG)) +ALT(DEF_ASM_OP2(addb, 0x04, 0, OPC_ARITH | OPC_BWLX, OPT_IM, OPT_EAX)) +ALT(DEF_ASM_OP2(addw, 0x83, 0, OPC_ARITH | OPC_MODRM | OPC_WLX, OPT_IM8S, OPT_EA | OPT_REGW)) +ALT(DEF_ASM_OP2(addb, 0x80, 0, OPC_ARITH | OPC_MODRM | OPC_BWLX, OPT_IM, OPT_EA | OPT_REG)) + +ALT(DEF_ASM_OP2(testb, 0x84, 0, OPC_MODRM | OPC_BWLX, OPT_REG, OPT_EA | OPT_REG)) +ALT(DEF_ASM_OP2(testb, 0x84, 0, OPC_MODRM | OPC_BWLX, OPT_EA | OPT_REG, OPT_REG)) +ALT(DEF_ASM_OP2(testb, 0xa8, 0, OPC_BWLX, OPT_IM, OPT_EAX)) +ALT(DEF_ASM_OP2(testb, 0xf6, 0, OPC_MODRM | OPC_BWLX, OPT_IM, OPT_EA | OPT_REG)) + +ALT(DEF_ASM_OP1(incw, 0x40, 0, OPC_REG | OPC_WLX, OPT_REGW)) +ALT(DEF_ASM_OP1(incb, 0xfe, 0, OPC_MODRM | OPC_BWLX, OPT_REG | OPT_EA)) +ALT(DEF_ASM_OP1(decw, 0x48, 0, OPC_REG | OPC_WLX, OPT_REGW)) +ALT(DEF_ASM_OP1(decb, 0xfe, 1, OPC_MODRM | OPC_BWLX, OPT_REG | OPT_EA)) + +ALT(DEF_ASM_OP1(notb, 0xf6, 2, OPC_MODRM | OPC_BWLX, OPT_REG | OPT_EA)) +ALT(DEF_ASM_OP1(negb, 0xf6, 3, OPC_MODRM | OPC_BWLX, OPT_REG | OPT_EA)) + +ALT(DEF_ASM_OP1(mulb, 0xf6, 4, OPC_MODRM | OPC_BWLX, OPT_REG | OPT_EA)) +ALT(DEF_ASM_OP1(imulb, 0xf6, 5, OPC_MODRM | OPC_BWLX, OPT_REG | OPT_EA)) + +ALT(DEF_ASM_OP2(imulw, 0x0faf, 0, OPC_MODRM | OPC_WLX, OPT_REG | OPT_EA, OPT_REG)) +ALT(DEF_ASM_OP3(imulw, 0x6b, 0, OPC_MODRM | OPC_WLX, OPT_IM8S, OPT_REGW | OPT_EA, OPT_REGW)) +ALT(DEF_ASM_OP2(imulw, 0x6b, 0, OPC_MODRM | OPC_WLX, OPT_IM8S, OPT_REGW)) +ALT(DEF_ASM_OP3(imulw, 0x69, 0, OPC_MODRM | OPC_WLX, OPT_IMW, OPT_REGW | OPT_EA, OPT_REGW)) +ALT(DEF_ASM_OP2(imulw, 0x69, 0, OPC_MODRM | OPC_WLX, OPT_IMW, OPT_REGW)) + +ALT(DEF_ASM_OP1(divb, 0xf6, 6, OPC_MODRM | OPC_BWLX, OPT_REG | OPT_EA)) +ALT(DEF_ASM_OP2(divb, 0xf6, 6, OPC_MODRM | OPC_BWLX, OPT_REG | OPT_EA, OPT_EAX)) +ALT(DEF_ASM_OP1(idivb, 0xf6, 7, OPC_MODRM | OPC_BWLX, OPT_REG | OPT_EA)) +ALT(DEF_ASM_OP2(idivb, 0xf6, 7, OPC_MODRM | OPC_BWLX, OPT_REG | OPT_EA, OPT_EAX)) + + /* shifts */ +ALT(DEF_ASM_OP2(rolb, 0xc0, 0, OPC_MODRM | OPC_BWLX | OPC_SHIFT, OPT_IM8, OPT_EA | OPT_REG)) +ALT(DEF_ASM_OP2(rolb, 0xd2, 0, OPC_MODRM | OPC_BWLX | OPC_SHIFT, OPT_CL, OPT_EA | OPT_REG)) +ALT(DEF_ASM_OP1(rolb, 0xd0, 0, OPC_MODRM | OPC_BWLX | OPC_SHIFT, OPT_EA | OPT_REG)) + +ALT(DEF_ASM_OP3(shldw, 0x0fa4, 0, OPC_MODRM | OPC_WLX, OPT_IM8, OPT_REGW, OPT_EA | OPT_REGW)) +ALT(DEF_ASM_OP3(shldw, 0x0fa5, 0, OPC_MODRM | OPC_WLX, OPT_CL, OPT_REGW, OPT_EA | OPT_REGW)) +ALT(DEF_ASM_OP2(shldw, 0x0fa5, 0, OPC_MODRM | OPC_WLX, OPT_REGW, OPT_EA | OPT_REGW)) +ALT(DEF_ASM_OP3(shrdw, 0x0fac, 0, OPC_MODRM | OPC_WLX, OPT_IM8, OPT_REGW, OPT_EA | OPT_REGW)) +ALT(DEF_ASM_OP3(shrdw, 0x0fad, 0, OPC_MODRM | OPC_WLX, OPT_CL, OPT_REGW, OPT_EA | OPT_REGW)) +ALT(DEF_ASM_OP2(shrdw, 0x0fad, 0, OPC_MODRM | OPC_WLX, OPT_REGW, OPT_EA | OPT_REGW)) + +ALT(DEF_ASM_OP1(call, 0xff, 2, OPC_MODRM, OPT_INDIR)) +ALT(DEF_ASM_OP1(call, 0xe8, 0, 0, OPT_DISP)) +ALT(DEF_ASM_OP1(jmp, 0xff, 4, OPC_MODRM, OPT_INDIR)) +ALT(DEF_ASM_OP1(jmp, 0xeb, 0, 0, OPT_DISP8)) + +ALT(DEF_ASM_OP2(lcall, 0x9a, 0, 0, OPT_IM16, OPT_IM32)) +ALT(DEF_ASM_OP1(lcall, 0xff, 3, OPC_MODRM, OPT_EA)) +ALT(DEF_ASM_OP2(ljmp, 0xea, 0, 0, OPT_IM16, OPT_IM32)) +ALT(DEF_ASM_OP1(ljmp, 0xff, 5, OPC_MODRM, OPT_EA)) + +ALT(DEF_ASM_OP1(int, 0xcd, 0, 0, OPT_IM8)) +ALT(DEF_ASM_OP1(seto, 0x0f90, 0, OPC_MODRM | OPC_TEST, OPT_REG8 | OPT_EA)) +ALT(DEF_ASM_OP1(setob, 0x0f90, 0, OPC_MODRM | OPC_TEST, OPT_REG8 | OPT_EA)) + DEF_ASM_OP2(enter, 0xc8, 0, 0, OPT_IM16, OPT_IM8) + DEF_ASM_OP0(leave, 0xc9) + DEF_ASM_OP0(ret, 0xc3) + DEF_ASM_OP0(retl,0xc3) +ALT(DEF_ASM_OP1(retl,0xc2, 0, 0, OPT_IM16)) +ALT(DEF_ASM_OP1(ret, 0xc2, 0, 0, OPT_IM16)) + DEF_ASM_OP0(lret, 0xcb) +ALT(DEF_ASM_OP1(lret, 0xca, 0, 0, OPT_IM16)) + +ALT(DEF_ASM_OP1(jo, 0x70, 0, OPC_TEST, OPT_DISP8)) + DEF_ASM_OP1(loopne, 0xe0, 0, 0, OPT_DISP8) + DEF_ASM_OP1(loopnz, 0xe0, 0, 0, OPT_DISP8) + DEF_ASM_OP1(loope, 0xe1, 0, 0, OPT_DISP8) + DEF_ASM_OP1(loopz, 0xe1, 0, 0, OPT_DISP8) + DEF_ASM_OP1(loop, 0xe2, 0, 0, OPT_DISP8) + DEF_ASM_OP1(jecxz, 0xe3, 0, 0, OPT_DISP8) + + /* float */ + /* specific fcomp handling */ +ALT(DEF_ASM_OP0L(fcomp, 0xd8d9, 0, 0)) + +ALT(DEF_ASM_OP1(fadd, 0xd8c0, 0, OPC_FARITH | OPC_REG, OPT_ST)) +ALT(DEF_ASM_OP2(fadd, 0xd8c0, 0, OPC_FARITH | OPC_REG, OPT_ST, OPT_ST0)) +ALT(DEF_ASM_OP2(fadd, 0xdcc0, 0, OPC_FARITH | OPC_REG, OPT_ST0, OPT_ST)) +ALT(DEF_ASM_OP2(fmul, 0xdcc8, 0, OPC_FARITH | OPC_REG, OPT_ST0, OPT_ST)) +ALT(DEF_ASM_OP0L(fadd, 0xdec1, 0, OPC_FARITH)) +ALT(DEF_ASM_OP1(faddp, 0xdec0, 0, OPC_FARITH | OPC_REG, OPT_ST)) +ALT(DEF_ASM_OP2(faddp, 0xdec0, 0, OPC_FARITH | OPC_REG, OPT_ST, OPT_ST0)) +ALT(DEF_ASM_OP2(faddp, 0xdec0, 0, OPC_FARITH | OPC_REG, OPT_ST0, OPT_ST)) +ALT(DEF_ASM_OP0L(faddp, 0xdec1, 0, OPC_FARITH)) +ALT(DEF_ASM_OP1(fadds, 0xd8, 0, OPC_FARITH | OPC_MODRM, OPT_EA)) +ALT(DEF_ASM_OP1(fiaddl, 0xda, 0, OPC_FARITH | OPC_MODRM, OPT_EA)) +ALT(DEF_ASM_OP1(faddl, 0xdc, 0, OPC_FARITH | OPC_MODRM, OPT_EA)) +ALT(DEF_ASM_OP1(fiadds, 0xde, 0, OPC_FARITH | OPC_MODRM, OPT_EA)) + + DEF_ASM_OP0(fucompp, 0xdae9) + DEF_ASM_OP0(ftst, 0xd9e4) + DEF_ASM_OP0(fxam, 0xd9e5) + DEF_ASM_OP0(fld1, 0xd9e8) + DEF_ASM_OP0(fldl2t, 0xd9e9) + DEF_ASM_OP0(fldl2e, 0xd9ea) + DEF_ASM_OP0(fldpi, 0xd9eb) + DEF_ASM_OP0(fldlg2, 0xd9ec) + DEF_ASM_OP0(fldln2, 0xd9ed) + DEF_ASM_OP0(fldz, 0xd9ee) + + DEF_ASM_OP0(f2xm1, 0xd9f0) + DEF_ASM_OP0(fyl2x, 0xd9f1) + DEF_ASM_OP0(fptan, 0xd9f2) + DEF_ASM_OP0(fpatan, 0xd9f3) + DEF_ASM_OP0(fxtract, 0xd9f4) + DEF_ASM_OP0(fprem1, 0xd9f5) + DEF_ASM_OP0(fdecstp, 0xd9f6) + DEF_ASM_OP0(fincstp, 0xd9f7) + DEF_ASM_OP0(fprem, 0xd9f8) + DEF_ASM_OP0(fyl2xp1, 0xd9f9) + DEF_ASM_OP0(fsqrt, 0xd9fa) + DEF_ASM_OP0(fsincos, 0xd9fb) + DEF_ASM_OP0(frndint, 0xd9fc) + DEF_ASM_OP0(fscale, 0xd9fd) + DEF_ASM_OP0(fsin, 0xd9fe) + DEF_ASM_OP0(fcos, 0xd9ff) + DEF_ASM_OP0(fchs, 0xd9e0) + DEF_ASM_OP0(fabs, 0xd9e1) + DEF_ASM_OP0(fninit, 0xdbe3) + DEF_ASM_OP0(fnclex, 0xdbe2) + DEF_ASM_OP0(fnop, 0xd9d0) + + /* fp load */ + DEF_ASM_OP1(fld, 0xd9c0, 0, OPC_REG, OPT_ST) + DEF_ASM_OP1(fldl, 0xd9c0, 0, OPC_REG, OPT_ST) + DEF_ASM_OP1(flds, 0xd9, 0, OPC_MODRM, OPT_EA) +ALT(DEF_ASM_OP1(fldl, 0xdd, 0, OPC_MODRM, OPT_EA)) + DEF_ASM_OP1(fildl, 0xdb, 0, OPC_MODRM, OPT_EA) + DEF_ASM_OP1(fildq, 0xdf, 5, OPC_MODRM, OPT_EA) + DEF_ASM_OP1(fildll, 0xdf, 5, OPC_MODRM,OPT_EA) + DEF_ASM_OP1(fldt, 0xdb, 5, OPC_MODRM, OPT_EA) + DEF_ASM_OP1(fbld, 0xdf, 4, OPC_MODRM, OPT_EA) + + /* fp store */ + DEF_ASM_OP1(fst, 0xddd0, 0, OPC_REG, OPT_ST) + DEF_ASM_OP1(fstl, 0xddd0, 0, OPC_REG, OPT_ST) + DEF_ASM_OP1(fsts, 0xd9, 2, OPC_MODRM, OPT_EA) + DEF_ASM_OP1(fstps, 0xd9, 3, OPC_MODRM, OPT_EA) +ALT(DEF_ASM_OP1(fstl, 0xdd, 2, OPC_MODRM, OPT_EA)) + DEF_ASM_OP1(fstpl, 0xdd, 3, OPC_MODRM, OPT_EA) + DEF_ASM_OP1(fist, 0xdf, 2, OPC_MODRM, OPT_EA) + DEF_ASM_OP1(fistp, 0xdf, 3, OPC_MODRM, OPT_EA) + DEF_ASM_OP1(fistl, 0xdb, 2, OPC_MODRM, OPT_EA) + DEF_ASM_OP1(fistpl, 0xdb, 3, OPC_MODRM, OPT_EA) + + DEF_ASM_OP1(fstp, 0xddd8, 0, OPC_REG, OPT_ST) + DEF_ASM_OP1(fistpq, 0xdf, 7, OPC_MODRM, OPT_EA) + DEF_ASM_OP1(fistpll, 0xdf, 7, OPC_MODRM, OPT_EA) + DEF_ASM_OP1(fstpt, 0xdb, 7, OPC_MODRM, OPT_EA) + DEF_ASM_OP1(fbstp, 0xdf, 6, OPC_MODRM, OPT_EA) + + /* exchange */ + DEF_ASM_OP0(fxch, 0xd9c9) +ALT(DEF_ASM_OP1(fxch, 0xd9c8, 0, OPC_REG, OPT_ST)) + + /* misc FPU */ + DEF_ASM_OP1(fucom, 0xdde0, 0, OPC_REG, OPT_ST ) + DEF_ASM_OP1(fucomp, 0xdde8, 0, OPC_REG, OPT_ST ) + + DEF_ASM_OP0L(finit, 0xdbe3, 0, OPC_FWAIT) + DEF_ASM_OP1(fldcw, 0xd9, 5, OPC_MODRM, OPT_EA ) + DEF_ASM_OP1(fnstcw, 0xd9, 7, OPC_MODRM, OPT_EA ) + DEF_ASM_OP1(fstcw, 0xd9, 7, OPC_MODRM | OPC_FWAIT, OPT_EA ) + DEF_ASM_OP0(fnstsw, 0xdfe0) +ALT(DEF_ASM_OP1(fnstsw, 0xdfe0, 0, 0, OPT_EAX )) +ALT(DEF_ASM_OP1(fnstsw, 0xdd, 7, OPC_MODRM, OPT_EA )) + DEF_ASM_OP1(fstsw, 0xdfe0, 0, OPC_FWAIT, OPT_EAX ) +ALT(DEF_ASM_OP0L(fstsw, 0xdfe0, 0, OPC_FWAIT)) +ALT(DEF_ASM_OP1(fstsw, 0xdd, 7, OPC_MODRM | OPC_FWAIT, OPT_EA )) + DEF_ASM_OP0L(fclex, 0xdbe2, 0, OPC_FWAIT) + DEF_ASM_OP1(fnstenv, 0xd9, 6, OPC_MODRM, OPT_EA ) + DEF_ASM_OP1(fstenv, 0xd9, 6, OPC_MODRM | OPC_FWAIT, OPT_EA ) + DEF_ASM_OP1(fldenv, 0xd9, 4, OPC_MODRM, OPT_EA ) + DEF_ASM_OP1(fnsave, 0xdd, 6, OPC_MODRM, OPT_EA ) + DEF_ASM_OP1(fsave, 0xdd, 6, OPC_MODRM | OPC_FWAIT, OPT_EA ) + DEF_ASM_OP1(frstor, 0xdd, 4, OPC_MODRM, OPT_EA ) + DEF_ASM_OP1(ffree, 0xddc0, 4, OPC_REG, OPT_ST ) + DEF_ASM_OP1(ffreep, 0xdfc0, 4, OPC_REG, OPT_ST ) + DEF_ASM_OP1(fxsave, 0x0fae, 0, OPC_MODRM, OPT_EA ) + DEF_ASM_OP1(fxrstor, 0x0fae, 1, OPC_MODRM, OPT_EA ) + + /* segments */ + DEF_ASM_OP2(arpl, 0x63, 0, OPC_MODRM, OPT_REG16, OPT_REG16 | OPT_EA) +ALT(DEF_ASM_OP2(larw, 0x0f02, 0, OPC_MODRM | OPC_WLX, OPT_REG | OPT_EA, OPT_REG)) + DEF_ASM_OP1(lgdt, 0x0f01, 2, OPC_MODRM, OPT_EA) + DEF_ASM_OP1(lidt, 0x0f01, 3, OPC_MODRM, OPT_EA) + DEF_ASM_OP1(lldt, 0x0f00, 2, OPC_MODRM, OPT_EA | OPT_REG) + DEF_ASM_OP1(lmsw, 0x0f01, 6, OPC_MODRM, OPT_EA | OPT_REG) +ALT(DEF_ASM_OP2(lslw, 0x0f03, 0, OPC_MODRM | OPC_WLX, OPT_EA | OPT_REG, OPT_REG)) + DEF_ASM_OP1(ltr, 0x0f00, 3, OPC_MODRM, OPT_EA | OPT_REG) + DEF_ASM_OP1(sgdt, 0x0f01, 0, OPC_MODRM, OPT_EA) + DEF_ASM_OP1(sidt, 0x0f01, 1, OPC_MODRM, OPT_EA) + DEF_ASM_OP1(sldt, 0x0f00, 0, OPC_MODRM, OPT_REG | OPT_EA) + DEF_ASM_OP1(smsw, 0x0f01, 4, OPC_MODRM, OPT_REG | OPT_EA) + DEF_ASM_OP1(str, 0x0f00, 1, OPC_MODRM, OPT_REG16| OPT_EA) + DEF_ASM_OP1(verr, 0x0f00, 4, OPC_MODRM, OPT_REG | OPT_EA) + DEF_ASM_OP1(verw, 0x0f00, 5, OPC_MODRM, OPT_REG | OPT_EA) + + /* 486 */ + DEF_ASM_OP1(bswap, 0x0fc8, 0, OPC_REG, OPT_REG32 ) +ALT(DEF_ASM_OP2(xaddb, 0x0fc0, 0, OPC_MODRM | OPC_BWLX, OPT_REG, OPT_REG | OPT_EA )) +ALT(DEF_ASM_OP2(cmpxchgb, 0x0fb0, 0, OPC_MODRM | OPC_BWLX, OPT_REG, OPT_REG | OPT_EA )) + DEF_ASM_OP1(invlpg, 0x0f01, 7, OPC_MODRM, OPT_EA ) + + DEF_ASM_OP2(boundl, 0x62, 0, OPC_MODRM, OPT_REG32, OPT_EA) + DEF_ASM_OP2(boundw, 0x6662, 0, OPC_MODRM, OPT_REG16, OPT_EA) + + /* pentium */ + DEF_ASM_OP1(cmpxchg8b, 0x0fc7, 1, OPC_MODRM, OPT_EA ) + + /* pentium pro */ +ALT(DEF_ASM_OP2(cmovo, 0x0f40, 0, OPC_MODRM | OPC_TEST | OPC_WLX, OPT_REGW | OPT_EA, OPT_REGW)) + DEF_ASM_OP2(fcmovb, 0xdac0, 0, OPC_REG, OPT_ST, OPT_ST0 ) + DEF_ASM_OP2(fcmove, 0xdac8, 0, OPC_REG, OPT_ST, OPT_ST0 ) + DEF_ASM_OP2(fcmovbe, 0xdad0, 0, OPC_REG, OPT_ST, OPT_ST0 ) + DEF_ASM_OP2(fcmovu, 0xdad8, 0, OPC_REG, OPT_ST, OPT_ST0 ) + DEF_ASM_OP2(fcmovnb, 0xdbc0, 0, OPC_REG, OPT_ST, OPT_ST0 ) + DEF_ASM_OP2(fcmovne, 0xdbc8, 0, OPC_REG, OPT_ST, OPT_ST0 ) + DEF_ASM_OP2(fcmovnbe, 0xdbd0, 0, OPC_REG, OPT_ST, OPT_ST0 ) + DEF_ASM_OP2(fcmovnu, 0xdbd8, 0, OPC_REG, OPT_ST, OPT_ST0 ) + + DEF_ASM_OP2(fucomi, 0xdbe8, 0, OPC_REG, OPT_ST, OPT_ST0 ) + DEF_ASM_OP2(fcomi, 0xdbf0, 0, OPC_REG, OPT_ST, OPT_ST0 ) + DEF_ASM_OP2(fucomip, 0xdfe8, 0, OPC_REG, OPT_ST, OPT_ST0 ) + DEF_ASM_OP2(fcomip, 0xdff0, 0, OPC_REG, OPT_ST, OPT_ST0 ) + + /* mmx */ + DEF_ASM_OP0(emms, 0x0f77) /* must be last OP0 */ + DEF_ASM_OP2(movd, 0x0f6e, 0, OPC_MODRM, OPT_EA | OPT_REG32, OPT_MMXSSE ) + DEF_ASM_OP2(movq, 0x0f6f, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX ) +ALT(DEF_ASM_OP2(movd, 0x0f7e, 0, OPC_MODRM, OPT_MMXSSE, OPT_EA | OPT_REG32 )) +ALT(DEF_ASM_OP2(movq, 0x0f7f, 0, OPC_MODRM, OPT_MMX, OPT_EA | OPT_MMX )) +ALT(DEF_ASM_OP2(movq, 0x660fd6, 0, OPC_MODRM, OPT_SSE, OPT_EA | OPT_SSE )) +ALT(DEF_ASM_OP2(movq, 0xf30f7e, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE )) + + DEF_ASM_OP2(packssdw, 0x0f6b, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(packsswb, 0x0f63, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(packuswb, 0x0f67, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(paddb, 0x0ffc, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(paddw, 0x0ffd, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(paddd, 0x0ffe, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(paddsb, 0x0fec, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(paddsw, 0x0fed, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(paddusb, 0x0fdc, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(paddusw, 0x0fdd, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(pand, 0x0fdb, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(pandn, 0x0fdf, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(pcmpeqb, 0x0f74, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(pcmpeqw, 0x0f75, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(pcmpeqd, 0x0f76, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(pcmpgtb, 0x0f64, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(pcmpgtw, 0x0f65, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(pcmpgtd, 0x0f66, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(pmaddwd, 0x0ff5, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(pmulhw, 0x0fe5, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(pmullw, 0x0fd5, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(por, 0x0feb, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(psllw, 0x0ff1, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) +ALT(DEF_ASM_OP2(psllw, 0x0f71, 6, OPC_MODRM, OPT_IM8, OPT_MMXSSE )) + DEF_ASM_OP2(pslld, 0x0ff2, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) +ALT(DEF_ASM_OP2(pslld, 0x0f72, 6, OPC_MODRM, OPT_IM8, OPT_MMXSSE )) + DEF_ASM_OP2(psllq, 0x0ff3, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) +ALT(DEF_ASM_OP2(psllq, 0x0f73, 6, OPC_MODRM, OPT_IM8, OPT_MMXSSE )) + DEF_ASM_OP2(psraw, 0x0fe1, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) +ALT(DEF_ASM_OP2(psraw, 0x0f71, 4, OPC_MODRM, OPT_IM8, OPT_MMXSSE )) + DEF_ASM_OP2(psrad, 0x0fe2, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) +ALT(DEF_ASM_OP2(psrad, 0x0f72, 4, OPC_MODRM, OPT_IM8, OPT_MMXSSE )) + DEF_ASM_OP2(psrlw, 0x0fd1, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) +ALT(DEF_ASM_OP2(psrlw, 0x0f71, 2, OPC_MODRM, OPT_IM8, OPT_MMXSSE )) + DEF_ASM_OP2(psrld, 0x0fd2, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) +ALT(DEF_ASM_OP2(psrld, 0x0f72, 2, OPC_MODRM, OPT_IM8, OPT_MMXSSE )) + DEF_ASM_OP2(psrlq, 0x0fd3, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) +ALT(DEF_ASM_OP2(psrlq, 0x0f73, 2, OPC_MODRM, OPT_IM8, OPT_MMXSSE )) + DEF_ASM_OP2(psubb, 0x0ff8, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(psubw, 0x0ff9, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(psubd, 0x0ffa, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(psubsb, 0x0fe8, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(psubsw, 0x0fe9, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(psubusb, 0x0fd8, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(psubusw, 0x0fd9, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(punpckhbw, 0x0f68, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(punpckhwd, 0x0f69, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(punpckhdq, 0x0f6a, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(punpcklbw, 0x0f60, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(punpcklwd, 0x0f61, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(punpckldq, 0x0f62, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(pxor, 0x0fef, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + + /* sse */ + DEF_ASM_OP2(movups, 0x0f10, 0, OPC_MODRM, OPT_EA | OPT_REG32, OPT_SSE ) +ALT(DEF_ASM_OP2(movups, 0x0f11, 0, OPC_MODRM, OPT_SSE, OPT_EA | OPT_REG32 )) + DEF_ASM_OP2(movaps, 0x0f28, 0, OPC_MODRM, OPT_EA | OPT_REG32, OPT_SSE ) +ALT(DEF_ASM_OP2(movaps, 0x0f29, 0, OPC_MODRM, OPT_SSE, OPT_EA | OPT_REG32 )) + DEF_ASM_OP2(movhps, 0x0f16, 0, OPC_MODRM, OPT_EA | OPT_REG32, OPT_SSE ) +ALT(DEF_ASM_OP2(movhps, 0x0f17, 0, OPC_MODRM, OPT_SSE, OPT_EA | OPT_REG32 )) + DEF_ASM_OP2(addps, 0x0f58, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE ) + DEF_ASM_OP2(cvtpi2ps, 0x0f2a, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_SSE ) + DEF_ASM_OP2(cvtps2pi, 0x0f2d, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_MMX ) + DEF_ASM_OP2(cvttps2pi, 0x0f2c, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_MMX ) + DEF_ASM_OP2(divps, 0x0f5e, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE ) + DEF_ASM_OP2(maxps, 0x0f5f, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE ) + DEF_ASM_OP2(minps, 0x0f5d, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE ) + DEF_ASM_OP2(mulps, 0x0f59, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE ) + DEF_ASM_OP2(pavgb, 0x0fe0, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE ) + DEF_ASM_OP2(pavgw, 0x0fe3, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE ) + DEF_ASM_OP2(pmaxsw, 0x0fee, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(pmaxub, 0x0fde, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(pminsw, 0x0fea, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(pminub, 0x0fda, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(rcpss, 0x0f53, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE ) + DEF_ASM_OP2(rsqrtps, 0x0f52, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE ) + DEF_ASM_OP2(sqrtps, 0x0f51, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE ) + DEF_ASM_OP2(subps, 0x0f5c, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE ) + +#undef ALT +#undef DEF_ASM_OP0 +#undef DEF_ASM_OP0L +#undef DEF_ASM_OP1 +#undef DEF_ASM_OP2 +#undef DEF_ASM_OP3 diff --git a/tinyc/i386-gen.c b/tinyc/i386-gen.c new file mode 100644 index 000000000..b9c3599fd --- /dev/null +++ b/tinyc/i386-gen.c @@ -0,0 +1,1164 @@ +/* + * X86 code generator for TCC + * + * Copyright (c) 2001-2004 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifdef TARGET_DEFS_ONLY + +/* number of available registers */ +#define NB_REGS 5 +#define NB_ASM_REGS 8 +#define CONFIG_TCC_ASM + +/* a register can belong to several classes. The classes must be + sorted from more general to more precise (see gv2() code which does + assumptions on it). */ +#define RC_INT 0x0001 /* generic integer register */ +#define RC_FLOAT 0x0002 /* generic float register */ +#define RC_EAX 0x0004 +#define RC_ST0 0x0008 +#define RC_ECX 0x0010 +#define RC_EDX 0x0020 +#define RC_EBX 0x0040 + +#define RC_IRET RC_EAX /* function return: integer register */ +#define RC_LRET RC_EDX /* function return: second integer register */ +#define RC_FRET RC_ST0 /* function return: float register */ + +/* pretty names for the registers */ +enum { + TREG_EAX = 0, + TREG_ECX, + TREG_EDX, + TREG_EBX, + TREG_ST0, + TREG_ESP = 4 +}; + +/* return registers for function */ +#define REG_IRET TREG_EAX /* single word int return register */ +#define REG_LRET TREG_EDX /* second word return register (for long long) */ +#define REG_FRET TREG_ST0 /* float return register */ + +/* defined if function parameters must be evaluated in reverse order */ +#define INVERT_FUNC_PARAMS + +/* defined if structures are passed as pointers. Otherwise structures + are directly pushed on stack. */ +/* #define FUNC_STRUCT_PARAM_AS_PTR */ + +/* pointer size, in bytes */ +#define PTR_SIZE 4 + +/* long double size and alignment, in bytes */ +#define LDOUBLE_SIZE 12 +#define LDOUBLE_ALIGN 4 +/* maximum alignment (for aligned attribute support) */ +#define MAX_ALIGN 8 + +/******************************************************/ +#else /* ! TARGET_DEFS_ONLY */ +/******************************************************/ +#include "tcc.h" + +/* define to 1/0 to [not] have EBX as 4th register */ +#define USE_EBX 0 + +ST_DATA const int reg_classes[NB_REGS] = { + /* eax */ RC_INT | RC_EAX, + /* ecx */ RC_INT | RC_ECX, + /* edx */ RC_INT | RC_EDX, + /* ebx */ (RC_INT | RC_EBX) * USE_EBX, + /* st0 */ RC_FLOAT | RC_ST0, +}; + +static unsigned long func_sub_sp_offset; +static int func_ret_sub; +#ifdef CONFIG_TCC_BCHECK +static addr_t func_bound_offset; +static unsigned long func_bound_ind; +#endif + +/* XXX: make it faster ? */ +ST_FUNC void g(int c) +{ + int ind1; + if (nocode_wanted) + return; + ind1 = ind + 1; + if (ind1 > cur_text_section->data_allocated) + section_realloc(cur_text_section, ind1); + cur_text_section->data[ind] = c; + ind = ind1; +} + +ST_FUNC void o(unsigned int c) +{ + while (c) { + g(c); + c = c >> 8; + } +} + +ST_FUNC void gen_le16(int v) +{ + g(v); + g(v >> 8); +} + +ST_FUNC void gen_le32(int c) +{ + g(c); + g(c >> 8); + g(c >> 16); + g(c >> 24); +} + +/* output a symbol and patch all calls to it */ +ST_FUNC void gsym_addr(int t, int a) +{ + while (t) { + unsigned char *ptr = cur_text_section->data + t; + uint32_t n = read32le(ptr); /* next value */ + write32le(ptr, a - t - 4); + t = n; + } +} + +ST_FUNC void gsym(int t) +{ + gsym_addr(t, ind); +} + +/* instruction + 4 bytes data. Return the address of the data */ +static int oad(int c, int s) +{ + int t; + if (nocode_wanted) + return s; + o(c); + t = ind; + gen_le32(s); + return t; +} + +/* generate jmp to a label */ +#define gjmp2(instr,lbl) oad(instr,lbl) + +/* output constant with relocation if 'r & VT_SYM' is true */ +ST_FUNC void gen_addr32(int r, Sym *sym, int c) +{ + if (r & VT_SYM) + greloc(cur_text_section, sym, ind, R_386_32); + gen_le32(c); +} + +ST_FUNC void gen_addrpc32(int r, Sym *sym, int c) +{ + if (r & VT_SYM) + greloc(cur_text_section, sym, ind, R_386_PC32); + gen_le32(c - 4); +} + +/* generate a modrm reference. 'op_reg' contains the additional 3 + opcode bits */ +static void gen_modrm(int op_reg, int r, Sym *sym, int c) +{ + op_reg = op_reg << 3; + if ((r & VT_VALMASK) == VT_CONST) { + /* constant memory reference */ + o(0x05 | op_reg); + gen_addr32(r, sym, c); + } else if ((r & VT_VALMASK) == VT_LOCAL) { + /* currently, we use only ebp as base */ + if (c == (char)c) { + /* short reference */ + o(0x45 | op_reg); + g(c); + } else { + oad(0x85 | op_reg, c); + } + } else { + g(0x00 | op_reg | (r & VT_VALMASK)); + } +} + +/* load 'r' from value 'sv' */ +ST_FUNC void load(int r, SValue *sv) +{ + int v, t, ft, fc, fr; + SValue v1; + +#ifdef TCC_TARGET_PE + SValue v2; + sv = pe_getimport(sv, &v2); +#endif + + fr = sv->r; + ft = sv->type.t & ~VT_DEFSIGN; + fc = sv->c.i; + + ft &= ~(VT_VOLATILE | VT_CONSTANT); + + v = fr & VT_VALMASK; + if (fr & VT_LVAL) { + if (v == VT_LLOCAL) { + v1.type.t = VT_INT; + v1.r = VT_LOCAL | VT_LVAL; + v1.c.i = fc; + fr = r; + if (!(reg_classes[fr] & RC_INT)) + fr = get_reg(RC_INT); + load(fr, &v1); + } + if ((ft & VT_BTYPE) == VT_FLOAT) { + o(0xd9); /* flds */ + r = 0; + } else if ((ft & VT_BTYPE) == VT_DOUBLE) { + o(0xdd); /* fldl */ + r = 0; + } else if ((ft & VT_BTYPE) == VT_LDOUBLE) { + o(0xdb); /* fldt */ + r = 5; + } else if ((ft & VT_TYPE) == VT_BYTE || (ft & VT_TYPE) == VT_BOOL) { + o(0xbe0f); /* movsbl */ + } else if ((ft & VT_TYPE) == (VT_BYTE | VT_UNSIGNED)) { + o(0xb60f); /* movzbl */ + } else if ((ft & VT_TYPE) == VT_SHORT) { + o(0xbf0f); /* movswl */ + } else if ((ft & VT_TYPE) == (VT_SHORT | VT_UNSIGNED)) { + o(0xb70f); /* movzwl */ + } else { + o(0x8b); /* movl */ + } + gen_modrm(r, fr, sv->sym, fc); + } else { + if (v == VT_CONST) { + o(0xb8 + r); /* mov $xx, r */ + gen_addr32(fr, sv->sym, fc); + } else if (v == VT_LOCAL) { + if (fc) { + o(0x8d); /* lea xxx(%ebp), r */ + gen_modrm(r, VT_LOCAL, sv->sym, fc); + } else { + o(0x89); + o(0xe8 + r); /* mov %ebp, r */ + } + } else if (v == VT_CMP) { + oad(0xb8 + r, 0); /* mov $0, r */ + o(0x0f); /* setxx %br */ + o(fc); + o(0xc0 + r); + } else if (v == VT_JMP || v == VT_JMPI) { + t = v & 1; + oad(0xb8 + r, t); /* mov $1, r */ + o(0x05eb); /* jmp after */ + gsym(fc); + oad(0xb8 + r, t ^ 1); /* mov $0, r */ + } else if (v != r) { + o(0x89); + o(0xc0 + r + v * 8); /* mov v, r */ + } + } +} + +/* store register 'r' in lvalue 'v' */ +ST_FUNC void store(int r, SValue *v) +{ + int fr, bt, ft, fc; + +#ifdef TCC_TARGET_PE + SValue v2; + v = pe_getimport(v, &v2); +#endif + + ft = v->type.t; + fc = v->c.i; + fr = v->r & VT_VALMASK; + ft &= ~(VT_VOLATILE | VT_CONSTANT); + bt = ft & VT_BTYPE; + /* XXX: incorrect if float reg to reg */ + if (bt == VT_FLOAT) { + o(0xd9); /* fsts */ + r = 2; + } else if (bt == VT_DOUBLE) { + o(0xdd); /* fstpl */ + r = 2; + } else if (bt == VT_LDOUBLE) { + o(0xc0d9); /* fld %st(0) */ + o(0xdb); /* fstpt */ + r = 7; + } else { + if (bt == VT_SHORT) + o(0x66); + if (bt == VT_BYTE || bt == VT_BOOL) + o(0x88); + else + o(0x89); + } + if (fr == VT_CONST || + fr == VT_LOCAL || + (v->r & VT_LVAL)) { + gen_modrm(r, v->r, v->sym, fc); + } else if (fr != r) { + o(0xc0 + fr + r * 8); /* mov r, fr */ + } +} + +static void gadd_sp(int val) +{ + if (val == (char)val) { + o(0xc483); + g(val); + } else { + oad(0xc481, val); /* add $xxx, %esp */ + } +} + +#if defined CONFIG_TCC_BCHECK || defined TCC_TARGET_PE +static void gen_static_call(int v) +{ + Sym *sym; + + sym = external_global_sym(v, &func_old_type, 0); + oad(0xe8, -4); + greloc(cur_text_section, sym, ind-4, R_386_PC32); +} +#endif + +/* 'is_jmp' is '1' if it is a jump */ +static void gcall_or_jmp(int is_jmp) +{ + int r; + if ((vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST && (vtop->r & VT_SYM)) { + /* constant and relocation case */ + greloc(cur_text_section, vtop->sym, ind + 1, R_386_PC32); + oad(0xe8 + is_jmp, vtop->c.i - 4); /* call/jmp im */ + } else { + /* otherwise, indirect call */ + r = gv(RC_INT); + o(0xff); /* call/jmp *r */ + o(0xd0 + r + (is_jmp << 4)); + } + if (!is_jmp) { + int rt; + /* extend the return value to the whole register if necessary + visual studio and gcc do not always set the whole eax register + when assigning the return value of a function */ + rt = vtop->type.ref->type.t; + switch (rt & VT_BTYPE) { + case VT_BYTE: + if (rt & VT_UNSIGNED) { + o(0xc0b60f); /* movzx %al, %eax */ + } + else { + o(0xc0be0f); /* movsx %al, %eax */ + } + break; + case VT_SHORT: + if (rt & VT_UNSIGNED) { + o(0xc0b70f); /* movzx %ax, %eax */ + } + else { + o(0xc0bf0f); /* movsx %ax, %eax */ + } + break; + default: + break; + } + } +} + +static uint8_t fastcall_regs[3] = { TREG_EAX, TREG_EDX, TREG_ECX }; +static uint8_t fastcallw_regs[2] = { TREG_ECX, TREG_EDX }; + +/* Return the number of registers needed to return the struct, or 0 if + returning via struct pointer. */ +ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *ret_align, int *regsize) +{ +#ifdef TCC_TARGET_PE + int size, align; + *ret_align = 1; // Never have to re-align return values for x86 + *regsize = 4; + size = type_size(vt, &align); + if (size > 8 || (size & (size - 1))) + return 0; + if (size == 8) + ret->t = VT_LLONG; + else if (size == 4) + ret->t = VT_INT; + else if (size == 2) + ret->t = VT_SHORT; + else + ret->t = VT_BYTE; + ret->ref = NULL; + return 1; +#else + *ret_align = 1; // Never have to re-align return values for x86 + return 0; +#endif +} + +/* Generate function call. The function address is pushed first, then + all the parameters in call order. This functions pops all the + parameters and the function address. */ +ST_FUNC void gfunc_call(int nb_args) +{ + int size, align, r, args_size, i, func_call; + Sym *func_sym; + + args_size = 0; + for(i = 0;i < nb_args; i++) { + if ((vtop->type.t & VT_BTYPE) == VT_STRUCT) { + size = type_size(&vtop->type, &align); + /* align to stack align size */ + size = (size + 3) & ~3; + /* allocate the necessary size on stack */ + oad(0xec81, size); /* sub $xxx, %esp */ + /* generate structure store */ + r = get_reg(RC_INT); + o(0x89); /* mov %esp, r */ + o(0xe0 + r); + vset(&vtop->type, r | VT_LVAL, 0); + vswap(); + vstore(); + args_size += size; + } else if (is_float(vtop->type.t)) { + gv(RC_FLOAT); /* only one float register */ + if ((vtop->type.t & VT_BTYPE) == VT_FLOAT) + size = 4; + else if ((vtop->type.t & VT_BTYPE) == VT_DOUBLE) + size = 8; + else + size = 12; + oad(0xec81, size); /* sub $xxx, %esp */ + if (size == 12) + o(0x7cdb); + else + o(0x5cd9 + size - 4); /* fstp[s|l] 0(%esp) */ + g(0x24); + g(0x00); + args_size += size; + } else { + /* simple type (currently always same size) */ + /* XXX: implicit cast ? */ + r = gv(RC_INT); + if ((vtop->type.t & VT_BTYPE) == VT_LLONG) { + size = 8; + o(0x50 + vtop->r2); /* push r */ + } else { + size = 4; + } + o(0x50 + r); /* push r */ + args_size += size; + } + vtop--; + } + save_regs(0); /* save used temporary registers */ + func_sym = vtop->type.ref; + func_call = func_sym->f.func_call; + /* fast call case */ + if ((func_call >= FUNC_FASTCALL1 && func_call <= FUNC_FASTCALL3) || + func_call == FUNC_FASTCALLW) { + int fastcall_nb_regs; + uint8_t *fastcall_regs_ptr; + if (func_call == FUNC_FASTCALLW) { + fastcall_regs_ptr = fastcallw_regs; + fastcall_nb_regs = 2; + } else { + fastcall_regs_ptr = fastcall_regs; + fastcall_nb_regs = func_call - FUNC_FASTCALL1 + 1; + } + for(i = 0;i < fastcall_nb_regs; i++) { + if (args_size <= 0) + break; + o(0x58 + fastcall_regs_ptr[i]); /* pop r */ + /* XXX: incorrect for struct/floats */ + args_size -= 4; + } + } +#ifndef TCC_TARGET_PE + else if ((vtop->type.ref->type.t & VT_BTYPE) == VT_STRUCT) + args_size -= 4; +#endif + gcall_or_jmp(0); + + if (args_size && func_call != FUNC_STDCALL && func_call != FUNC_FASTCALLW) + gadd_sp(args_size); + vtop--; +} + +#ifdef TCC_TARGET_PE +#define FUNC_PROLOG_SIZE (10 + USE_EBX) +#else +#define FUNC_PROLOG_SIZE (9 + USE_EBX) +#endif + +/* generate function prolog of type 't' */ +ST_FUNC void gfunc_prolog(CType *func_type) +{ + int addr, align, size, func_call, fastcall_nb_regs; + int param_index, param_addr; + uint8_t *fastcall_regs_ptr; + Sym *sym; + CType *type; + + sym = func_type->ref; + func_call = sym->f.func_call; + addr = 8; + loc = 0; + func_vc = 0; + + if (func_call >= FUNC_FASTCALL1 && func_call <= FUNC_FASTCALL3) { + fastcall_nb_regs = func_call - FUNC_FASTCALL1 + 1; + fastcall_regs_ptr = fastcall_regs; + } else if (func_call == FUNC_FASTCALLW) { + fastcall_nb_regs = 2; + fastcall_regs_ptr = fastcallw_regs; + } else { + fastcall_nb_regs = 0; + fastcall_regs_ptr = NULL; + } + param_index = 0; + + ind += FUNC_PROLOG_SIZE; + func_sub_sp_offset = ind; + /* if the function returns a structure, then add an + implicit pointer parameter */ + func_vt = sym->type; + func_var = (sym->f.func_type == FUNC_ELLIPSIS); +#ifdef TCC_TARGET_PE + size = type_size(&func_vt,&align); + if (((func_vt.t & VT_BTYPE) == VT_STRUCT) + && (size > 8 || (size & (size - 1)))) { +#else + if ((func_vt.t & VT_BTYPE) == VT_STRUCT) { +#endif + /* XXX: fastcall case ? */ + func_vc = addr; + addr += 4; + param_index++; + } + /* define parameters */ + while ((sym = sym->next) != NULL) { + type = &sym->type; + size = type_size(type, &align); + size = (size + 3) & ~3; +#ifdef FUNC_STRUCT_PARAM_AS_PTR + /* structs are passed as pointer */ + if ((type->t & VT_BTYPE) == VT_STRUCT) { + size = 4; + } +#endif + if (param_index < fastcall_nb_regs) { + /* save FASTCALL register */ + loc -= 4; + o(0x89); /* movl */ + gen_modrm(fastcall_regs_ptr[param_index], VT_LOCAL, NULL, loc); + param_addr = loc; + } else { + param_addr = addr; + addr += size; + } + sym_push(sym->v & ~SYM_FIELD, type, + VT_LOCAL | lvalue_type(type->t), param_addr); + param_index++; + } + func_ret_sub = 0; + /* pascal type call or fastcall ? */ + if (func_call == FUNC_STDCALL || func_call == FUNC_FASTCALLW) + func_ret_sub = addr - 8; +#ifndef TCC_TARGET_PE + else if (func_vc) + func_ret_sub = 4; +#endif + +#ifdef CONFIG_TCC_BCHECK + /* leave some room for bound checking code */ + if (tcc_state->do_bounds_check) { + func_bound_offset = lbounds_section->data_offset; + func_bound_ind = ind; + oad(0xb8, 0); /* lbound section pointer */ + oad(0xb8, 0); /* call to function */ + } +#endif +} + +/* generate function epilog */ +ST_FUNC void gfunc_epilog(void) +{ + addr_t v, saved_ind; + +#ifdef CONFIG_TCC_BCHECK + if (tcc_state->do_bounds_check + && func_bound_offset != lbounds_section->data_offset) { + addr_t saved_ind; + addr_t *bounds_ptr; + Sym *sym_data; + + /* add end of table info */ + bounds_ptr = section_ptr_add(lbounds_section, sizeof(addr_t)); + *bounds_ptr = 0; + + /* generate bound local allocation */ + saved_ind = ind; + ind = func_bound_ind; + sym_data = get_sym_ref(&char_pointer_type, lbounds_section, + func_bound_offset, lbounds_section->data_offset); + greloc(cur_text_section, sym_data, + ind + 1, R_386_32); + oad(0xb8, 0); /* mov %eax, xxx */ + gen_static_call(TOK___bound_local_new); + ind = saved_ind; + + /* generate bound check local freeing */ + o(0x5250); /* save returned value, if any */ + greloc(cur_text_section, sym_data, ind + 1, R_386_32); + oad(0xb8, 0); /* mov %eax, xxx */ + gen_static_call(TOK___bound_local_delete); + o(0x585a); /* restore returned value, if any */ + } +#endif + + /* align local size to word & save local variables */ + v = (-loc + 3) & -4; + +#if USE_EBX + o(0x8b); + gen_modrm(TREG_EBX, VT_LOCAL, NULL, -(v+4)); +#endif + + o(0xc9); /* leave */ + if (func_ret_sub == 0) { + o(0xc3); /* ret */ + } else { + o(0xc2); /* ret n */ + g(func_ret_sub); + g(func_ret_sub >> 8); + } + saved_ind = ind; + ind = func_sub_sp_offset - FUNC_PROLOG_SIZE; +#ifdef TCC_TARGET_PE + if (v >= 4096) { + oad(0xb8, v); /* mov stacksize, %eax */ + gen_static_call(TOK___chkstk); /* call __chkstk, (does the stackframe too) */ + } else +#endif + { + o(0xe58955); /* push %ebp, mov %esp, %ebp */ + o(0xec81); /* sub esp, stacksize */ + gen_le32(v); +#ifdef TCC_TARGET_PE + o(0x90); /* adjust to FUNC_PROLOG_SIZE */ +#endif + } + o(0x53 * USE_EBX); /* push ebx */ + ind = saved_ind; +} + +/* generate a jump to a label */ +ST_FUNC int gjmp(int t) +{ + return gjmp2(0xe9, t); +} + +/* generate a jump to a fixed address */ +ST_FUNC void gjmp_addr(int a) +{ + int r; + r = a - ind - 2; + if (r == (char)r) { + g(0xeb); + g(r); + } else { + oad(0xe9, a - ind - 5); + } +} + +ST_FUNC void gtst_addr(int inv, int a) +{ + int v = vtop->r & VT_VALMASK; + if (v == VT_CMP) { + inv ^= (vtop--)->c.i; + a -= ind + 2; + if (a == (char)a) { + g(inv - 32); + g(a); + } else { + g(0x0f); + oad(inv - 16, a - 4); + } + } else if ((v & ~1) == VT_JMP) { + if ((v & 1) != inv) { + gjmp_addr(a); + gsym(vtop->c.i); + } else { + gsym(vtop->c.i); + o(0x05eb); + gjmp_addr(a); + } + vtop--; + } +} + +/* generate a test. set 'inv' to invert test. Stack entry is popped */ +ST_FUNC int gtst(int inv, int t) +{ + int v = vtop->r & VT_VALMASK; + if (nocode_wanted) { + ; + } else if (v == VT_CMP) { + /* fast case : can jump directly since flags are set */ + g(0x0f); + t = gjmp2((vtop->c.i - 16) ^ inv, t); + } else if (v == VT_JMP || v == VT_JMPI) { + /* && or || optimization */ + if ((v & 1) == inv) { + /* insert vtop->c jump list in t */ + uint32_t n1, n = vtop->c.i; + if (n) { + while ((n1 = read32le(cur_text_section->data + n))) + n = n1; + write32le(cur_text_section->data + n, t); + t = vtop->c.i; + } + } else { + t = gjmp(t); + gsym(vtop->c.i); + } + } + vtop--; + return t; +} + +/* generate an integer binary operation */ +ST_FUNC void gen_opi(int op) +{ + int r, fr, opc, c; + + switch(op) { + case '+': + case TOK_ADDC1: /* add with carry generation */ + opc = 0; + gen_op8: + if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) { + /* constant case */ + vswap(); + r = gv(RC_INT); + vswap(); + c = vtop->c.i; + if (c == (char)c) { + /* generate inc and dec for smaller code */ + if (c==1 && opc==0 && op != TOK_ADDC1) { + o (0x40 | r); // inc + } else if (c==1 && opc==5 && op != TOK_SUBC1) { + o (0x48 | r); // dec + } else { + o(0x83); + o(0xc0 | (opc << 3) | r); + g(c); + } + } else { + o(0x81); + oad(0xc0 | (opc << 3) | r, c); + } + } else { + gv2(RC_INT, RC_INT); + r = vtop[-1].r; + fr = vtop[0].r; + o((opc << 3) | 0x01); + o(0xc0 + r + fr * 8); + } + vtop--; + if (op >= TOK_ULT && op <= TOK_GT) { + vtop->r = VT_CMP; + vtop->c.i = op; + } + break; + case '-': + case TOK_SUBC1: /* sub with carry generation */ + opc = 5; + goto gen_op8; + case TOK_ADDC2: /* add with carry use */ + opc = 2; + goto gen_op8; + case TOK_SUBC2: /* sub with carry use */ + opc = 3; + goto gen_op8; + case '&': + opc = 4; + goto gen_op8; + case '^': + opc = 6; + goto gen_op8; + case '|': + opc = 1; + goto gen_op8; + case '*': + gv2(RC_INT, RC_INT); + r = vtop[-1].r; + fr = vtop[0].r; + vtop--; + o(0xaf0f); /* imul fr, r */ + o(0xc0 + fr + r * 8); + break; + case TOK_SHL: + opc = 4; + goto gen_shift; + case TOK_SHR: + opc = 5; + goto gen_shift; + case TOK_SAR: + opc = 7; + gen_shift: + opc = 0xc0 | (opc << 3); + if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) { + /* constant case */ + vswap(); + r = gv(RC_INT); + vswap(); + c = vtop->c.i & 0x1f; + o(0xc1); /* shl/shr/sar $xxx, r */ + o(opc | r); + g(c); + } else { + /* we generate the shift in ecx */ + gv2(RC_INT, RC_ECX); + r = vtop[-1].r; + o(0xd3); /* shl/shr/sar %cl, r */ + o(opc | r); + } + vtop--; + break; + case '/': + case TOK_UDIV: + case TOK_PDIV: + case '%': + case TOK_UMOD: + case TOK_UMULL: + /* first operand must be in eax */ + /* XXX: need better constraint for second operand */ + gv2(RC_EAX, RC_ECX); + r = vtop[-1].r; + fr = vtop[0].r; + vtop--; + save_reg(TREG_EDX); + /* save EAX too if used otherwise */ + save_reg_upstack(TREG_EAX, 1); + if (op == TOK_UMULL) { + o(0xf7); /* mul fr */ + o(0xe0 + fr); + vtop->r2 = TREG_EDX; + r = TREG_EAX; + } else { + if (op == TOK_UDIV || op == TOK_UMOD) { + o(0xf7d231); /* xor %edx, %edx, div fr, %eax */ + o(0xf0 + fr); + } else { + o(0xf799); /* cltd, idiv fr, %eax */ + o(0xf8 + fr); + } + if (op == '%' || op == TOK_UMOD) + r = TREG_EDX; + else + r = TREG_EAX; + } + vtop->r = r; + break; + default: + opc = 7; + goto gen_op8; + } +} + +/* generate a floating point operation 'v = t1 op t2' instruction. The + two operands are guaranteed to have the same floating point type */ +/* XXX: need to use ST1 too */ +ST_FUNC void gen_opf(int op) +{ + int a, ft, fc, swapped, r; + + /* convert constants to memory references */ + if ((vtop[-1].r & (VT_VALMASK | VT_LVAL)) == VT_CONST) { + vswap(); + gv(RC_FLOAT); + vswap(); + } + if ((vtop[0].r & (VT_VALMASK | VT_LVAL)) == VT_CONST) + gv(RC_FLOAT); + + /* must put at least one value in the floating point register */ + if ((vtop[-1].r & VT_LVAL) && + (vtop[0].r & VT_LVAL)) { + vswap(); + gv(RC_FLOAT); + vswap(); + } + swapped = 0; + /* swap the stack if needed so that t1 is the register and t2 is + the memory reference */ + if (vtop[-1].r & VT_LVAL) { + vswap(); + swapped = 1; + } + if (op >= TOK_ULT && op <= TOK_GT) { + /* load on stack second operand */ + load(TREG_ST0, vtop); + save_reg(TREG_EAX); /* eax is used by FP comparison code */ + if (op == TOK_GE || op == TOK_GT) + swapped = !swapped; + else if (op == TOK_EQ || op == TOK_NE) + swapped = 0; + if (swapped) + o(0xc9d9); /* fxch %st(1) */ + if (op == TOK_EQ || op == TOK_NE) + o(0xe9da); /* fucompp */ + else + o(0xd9de); /* fcompp */ + o(0xe0df); /* fnstsw %ax */ + if (op == TOK_EQ) { + o(0x45e480); /* and $0x45, %ah */ + o(0x40fC80); /* cmp $0x40, %ah */ + } else if (op == TOK_NE) { + o(0x45e480); /* and $0x45, %ah */ + o(0x40f480); /* xor $0x40, %ah */ + op = TOK_NE; + } else if (op == TOK_GE || op == TOK_LE) { + o(0x05c4f6); /* test $0x05, %ah */ + op = TOK_EQ; + } else { + o(0x45c4f6); /* test $0x45, %ah */ + op = TOK_EQ; + } + vtop--; + vtop->r = VT_CMP; + vtop->c.i = op; + } else { + /* no memory reference possible for long double operations */ + if ((vtop->type.t & VT_BTYPE) == VT_LDOUBLE) { + load(TREG_ST0, vtop); + swapped = !swapped; + } + + switch(op) { + default: + case '+': + a = 0; + break; + case '-': + a = 4; + if (swapped) + a++; + break; + case '*': + a = 1; + break; + case '/': + a = 6; + if (swapped) + a++; + break; + } + ft = vtop->type.t; + fc = vtop->c.i; + if ((ft & VT_BTYPE) == VT_LDOUBLE) { + o(0xde); /* fxxxp %st, %st(1) */ + o(0xc1 + (a << 3)); + } else { + /* if saved lvalue, then we must reload it */ + r = vtop->r; + if ((r & VT_VALMASK) == VT_LLOCAL) { + SValue v1; + r = get_reg(RC_INT); + v1.type.t = VT_INT; + v1.r = VT_LOCAL | VT_LVAL; + v1.c.i = fc; + load(r, &v1); + fc = 0; + } + + if ((ft & VT_BTYPE) == VT_DOUBLE) + o(0xdc); + else + o(0xd8); + gen_modrm(a, r, vtop->sym, fc); + } + vtop--; + } +} + +/* convert integers to fp 't' type. Must handle 'int', 'unsigned int' + and 'long long' cases. */ +ST_FUNC void gen_cvt_itof(int t) +{ + save_reg(TREG_ST0); + gv(RC_INT); + if ((vtop->type.t & VT_BTYPE) == VT_LLONG) { + /* signed long long to float/double/long double (unsigned case + is handled generically) */ + o(0x50 + vtop->r2); /* push r2 */ + o(0x50 + (vtop->r & VT_VALMASK)); /* push r */ + o(0x242cdf); /* fildll (%esp) */ + o(0x08c483); /* add $8, %esp */ + } else if ((vtop->type.t & (VT_BTYPE | VT_UNSIGNED)) == + (VT_INT | VT_UNSIGNED)) { + /* unsigned int to float/double/long double */ + o(0x6a); /* push $0 */ + g(0x00); + o(0x50 + (vtop->r & VT_VALMASK)); /* push r */ + o(0x242cdf); /* fildll (%esp) */ + o(0x08c483); /* add $8, %esp */ + } else { + /* int to float/double/long double */ + o(0x50 + (vtop->r & VT_VALMASK)); /* push r */ + o(0x2404db); /* fildl (%esp) */ + o(0x04c483); /* add $4, %esp */ + } + vtop->r = TREG_ST0; +} + +/* convert fp to int 't' type */ +ST_FUNC void gen_cvt_ftoi(int t) +{ + int bt = vtop->type.t & VT_BTYPE; + if (bt == VT_FLOAT) + vpush_global_sym(&func_old_type, TOK___fixsfdi); + else if (bt == VT_LDOUBLE) + vpush_global_sym(&func_old_type, TOK___fixxfdi); + else + vpush_global_sym(&func_old_type, TOK___fixdfdi); + vswap(); + gfunc_call(1); + vpushi(0); + vtop->r = REG_IRET; + vtop->r2 = REG_LRET; +} + +/* convert from one floating point type to another */ +ST_FUNC void gen_cvt_ftof(int t) +{ + /* all we have to do on i386 is to put the float in a register */ + gv(RC_FLOAT); +} + +/* computed goto support */ +ST_FUNC void ggoto(void) +{ + gcall_or_jmp(1); + vtop--; +} + +/* bound check support functions */ +#ifdef CONFIG_TCC_BCHECK + +/* generate a bounded pointer addition */ +ST_FUNC void gen_bounded_ptr_add(void) +{ + /* prepare fast i386 function call (args in eax and edx) */ + gv2(RC_EAX, RC_EDX); + /* save all temporary registers */ + vtop -= 2; + save_regs(0); + /* do a fast function call */ + gen_static_call(TOK___bound_ptr_add); + /* returned pointer is in eax */ + vtop++; + vtop->r = TREG_EAX | VT_BOUNDED; + /* address of bounding function call point */ + vtop->c.i = (cur_text_section->reloc->data_offset - sizeof(Elf32_Rel)); +} + +/* patch pointer addition in vtop so that pointer dereferencing is + also tested */ +ST_FUNC void gen_bounded_ptr_deref(void) +{ + addr_t func; + int size, align; + Elf32_Rel *rel; + Sym *sym; + + size = 0; + /* XXX: put that code in generic part of tcc */ + if (!is_float(vtop->type.t)) { + if (vtop->r & VT_LVAL_BYTE) + size = 1; + else if (vtop->r & VT_LVAL_SHORT) + size = 2; + } + if (!size) + size = type_size(&vtop->type, &align); + switch(size) { + case 1: func = TOK___bound_ptr_indir1; break; + case 2: func = TOK___bound_ptr_indir2; break; + case 4: func = TOK___bound_ptr_indir4; break; + case 8: func = TOK___bound_ptr_indir8; break; + case 12: func = TOK___bound_ptr_indir12; break; + case 16: func = TOK___bound_ptr_indir16; break; + default: + tcc_error("unhandled size when dereferencing bounded pointer"); + func = 0; + break; + } + + /* patch relocation */ + /* XXX: find a better solution ? */ + rel = (Elf32_Rel *)(cur_text_section->reloc->data + vtop->c.i); + sym = external_global_sym(func, &func_old_type, 0); + if (!sym->c) + put_extern_sym(sym, NULL, 0, 0); + rel->r_info = ELF32_R_INFO(sym->c, ELF32_R_TYPE(rel->r_info)); +} +#endif + +/* Save the stack pointer onto the stack */ +ST_FUNC void gen_vla_sp_save(int addr) { + /* mov %esp,addr(%ebp)*/ + o(0x89); + gen_modrm(TREG_ESP, VT_LOCAL, NULL, addr); +} + +/* Restore the SP from a location on the stack */ +ST_FUNC void gen_vla_sp_restore(int addr) { + o(0x8b); + gen_modrm(TREG_ESP, VT_LOCAL, NULL, addr); +} + +/* Subtract from the stack pointer, and push the resulting value onto the stack */ +ST_FUNC void gen_vla_alloc(CType *type, int align) { +#ifdef TCC_TARGET_PE + /* alloca does more than just adjust %rsp on Windows */ + vpush_global_sym(&func_old_type, TOK_alloca); + vswap(); /* Move alloca ref past allocation size */ + gfunc_call(1); +#else + int r; + r = gv(RC_INT); /* allocation size */ + /* sub r,%rsp */ + o(0x2b); + o(0xe0 | r); + /* We align to 16 bytes rather than align */ + /* and ~15, %esp */ + o(0xf0e483); + vpop(); +#endif +} + +/* end of X86 code generator */ +/*************************************************************/ +#endif +/*************************************************************/ diff --git a/tinyc/i386-link.c b/tinyc/i386-link.c new file mode 100644 index 000000000..b44664404 --- /dev/null +++ b/tinyc/i386-link.c @@ -0,0 +1,244 @@ +#ifdef TARGET_DEFS_ONLY + +#define EM_TCC_TARGET EM_386 + +/* relocation type for 32 bit data relocation */ +#define R_DATA_32 R_386_32 +#define R_DATA_PTR R_386_32 +#define R_JMP_SLOT R_386_JMP_SLOT +#define R_GLOB_DAT R_386_GLOB_DAT +#define R_COPY R_386_COPY +#define R_RELATIVE R_386_RELATIVE + +#define R_NUM R_386_NUM + +#define ELF_START_ADDR 0x08048000 +#define ELF_PAGE_SIZE 0x1000 + +#define PCRELATIVE_DLLPLT 0 +#define RELOCATE_DLLPLT 0 + +#else /* !TARGET_DEFS_ONLY */ + +#include "tcc.h" + +/* Returns 1 for a code relocation, 0 for a data relocation. For unknown + relocations, returns -1. */ +int code_reloc (int reloc_type) +{ + switch (reloc_type) { + case R_386_RELATIVE: + case R_386_16: + case R_386_32: + case R_386_GOTPC: + case R_386_GOTOFF: + case R_386_GOT32: + case R_386_GOT32X: + case R_386_GLOB_DAT: + case R_386_COPY: + return 0; + + case R_386_PC16: + case R_386_PC32: + case R_386_PLT32: + case R_386_JMP_SLOT: + return 1; + } + + tcc_error ("Unknown relocation type: %d", reloc_type); + return -1; +} + +/* Returns an enumerator to describe whether and when the relocation needs a + GOT and/or PLT entry to be created. See tcc.h for a description of the + different values. */ +int gotplt_entry_type (int reloc_type) +{ + switch (reloc_type) { + case R_386_RELATIVE: + case R_386_16: + case R_386_GLOB_DAT: + case R_386_JMP_SLOT: + case R_386_COPY: + return NO_GOTPLT_ENTRY; + + case R_386_32: + /* This relocations shouldn't normally need GOT or PLT + slots if it weren't for simplicity in the code generator. + See our caller for comments. */ + return AUTO_GOTPLT_ENTRY; + + case R_386_PC16: + case R_386_PC32: + return AUTO_GOTPLT_ENTRY; + + case R_386_GOTPC: + case R_386_GOTOFF: + return BUILD_GOT_ONLY; + + case R_386_GOT32: + case R_386_GOT32X: + case R_386_PLT32: + return ALWAYS_GOTPLT_ENTRY; + } + + tcc_error ("Unknown relocation type: %d", reloc_type); + return -1; +} + +ST_FUNC unsigned create_plt_entry(TCCState *s1, unsigned got_offset, struct sym_attr *attr) +{ + Section *plt = s1->plt; + uint8_t *p; + int modrm; + unsigned plt_offset, relofs; + + /* on i386 if we build a DLL, we add a %ebx offset */ + if (s1->output_type == TCC_OUTPUT_DLL) + modrm = 0xa3; + else + modrm = 0x25; + + /* empty PLT: create PLT0 entry that pushes the library identifier + (GOT + PTR_SIZE) and jumps to ld.so resolution routine + (GOT + 2 * PTR_SIZE) */ + if (plt->data_offset == 0) { + p = section_ptr_add(plt, 16); + p[0] = 0xff; /* pushl got + PTR_SIZE */ + p[1] = modrm + 0x10; + write32le(p + 2, PTR_SIZE); + p[6] = 0xff; /* jmp *(got + PTR_SIZE * 2) */ + p[7] = modrm; + write32le(p + 8, PTR_SIZE * 2); + } + plt_offset = plt->data_offset; + + /* The PLT slot refers to the relocation entry it needs via offset. + The reloc entry is created below, so its offset is the current + data_offset */ + relofs = s1->got->reloc ? s1->got->reloc->data_offset : 0; + + /* Jump to GOT entry where ld.so initially put the address of ip + 4 */ + p = section_ptr_add(plt, 16); + p[0] = 0xff; /* jmp *(got + x) */ + p[1] = modrm; + write32le(p + 2, got_offset); + p[6] = 0x68; /* push $xxx */ + write32le(p + 7, relofs); + p[11] = 0xe9; /* jmp plt_start */ + write32le(p + 12, -(plt->data_offset)); + return plt_offset; +} + +/* relocate the PLT: compute addresses and offsets in the PLT now that final + address for PLT and GOT are known (see fill_program_header) */ +ST_FUNC void relocate_plt(TCCState *s1) +{ + uint8_t *p, *p_end; + + if (!s1->plt) + return; + + p = s1->plt->data; + p_end = p + s1->plt->data_offset; + + if (p < p_end) { + add32le(p + 2, s1->got->sh_addr); + add32le(p + 8, s1->got->sh_addr); + p += 16; + while (p < p_end) { + add32le(p + 2, s1->got->sh_addr); + p += 16; + } + } +} + +static ElfW_Rel *qrel; /* ptr to next reloc entry reused */ + +void relocate_init(Section *sr) +{ + qrel = (ElfW_Rel *) sr->data; +} + +void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t addr, addr_t val) +{ + int sym_index, esym_index; + + sym_index = ELFW(R_SYM)(rel->r_info); + + switch (type) { + case R_386_32: + if (s1->output_type == TCC_OUTPUT_DLL) { + esym_index = s1->sym_attrs[sym_index].dyn_index; + qrel->r_offset = rel->r_offset; + if (esym_index) { + qrel->r_info = ELFW(R_INFO)(esym_index, R_386_32); + qrel++; + return; + } else { + qrel->r_info = ELFW(R_INFO)(0, R_386_RELATIVE); + qrel++; + } + } + add32le(ptr, val); + return; + case R_386_PC32: + if (s1->output_type == TCC_OUTPUT_DLL) { + /* DLL relocation */ + esym_index = s1->sym_attrs[sym_index].dyn_index; + if (esym_index) { + qrel->r_offset = rel->r_offset; + qrel->r_info = ELFW(R_INFO)(esym_index, R_386_PC32); + qrel++; + return; + } + } + add32le(ptr, val - addr); + return; + case R_386_PLT32: + add32le(ptr, val - addr); + return; + case R_386_GLOB_DAT: + case R_386_JMP_SLOT: + write32le(ptr, val); + return; + case R_386_GOTPC: + add32le(ptr, s1->got->sh_addr - addr); + return; + case R_386_GOTOFF: + add32le(ptr, val - s1->got->sh_addr); + return; + case R_386_GOT32: + case R_386_GOT32X: + /* we load the got offset */ + add32le(ptr, s1->sym_attrs[sym_index].got_offset); + return; + case R_386_16: + if (s1->output_format != TCC_OUTPUT_FORMAT_BINARY) { + output_file: + tcc_error("can only produce 16-bit binary files"); + } + write16le(ptr, read16le(ptr) + val); + return; + case R_386_PC16: + if (s1->output_format != TCC_OUTPUT_FORMAT_BINARY) + goto output_file; + write16le(ptr, read16le(ptr) + val - addr); + return; + case R_386_RELATIVE: + /* do nothing */ + return; + case R_386_COPY: + /* This relocation must copy initialized data from the library + to the program .bss segment. Currently made like for ARM + (to remove noise of default case). Is this true? + */ + return; + default: + fprintf(stderr,"FIXME: handle reloc type %d at %x [%p] to %x\n", + type, (unsigned)addr, ptr, (unsigned)val); + return; + } +} + +#endif /* !TARGET_DEFS_ONLY */ diff --git a/tinyc/i386-tok.h b/tinyc/i386-tok.h new file mode 100644 index 000000000..8c25af09d --- /dev/null +++ b/tinyc/i386-tok.h @@ -0,0 +1,253 @@ +/* ------------------------------------------------------------------ */ +/* WARNING: relative order of tokens is important. */ + +/* register */ + DEF_ASM(al) + DEF_ASM(cl) + DEF_ASM(dl) + DEF_ASM(bl) + DEF_ASM(ah) + DEF_ASM(ch) + DEF_ASM(dh) + DEF_ASM(bh) + DEF_ASM(ax) + DEF_ASM(cx) + DEF_ASM(dx) + DEF_ASM(bx) + DEF_ASM(sp) + DEF_ASM(bp) + DEF_ASM(si) + DEF_ASM(di) + DEF_ASM(eax) + DEF_ASM(ecx) + DEF_ASM(edx) + DEF_ASM(ebx) + DEF_ASM(esp) + DEF_ASM(ebp) + DEF_ASM(esi) + DEF_ASM(edi) +#ifdef TCC_TARGET_X86_64 + DEF_ASM(rax) + DEF_ASM(rcx) + DEF_ASM(rdx) + DEF_ASM(rbx) + DEF_ASM(rsp) + DEF_ASM(rbp) + DEF_ASM(rsi) + DEF_ASM(rdi) +#endif + DEF_ASM(mm0) + DEF_ASM(mm1) + DEF_ASM(mm2) + DEF_ASM(mm3) + DEF_ASM(mm4) + DEF_ASM(mm5) + DEF_ASM(mm6) + DEF_ASM(mm7) + DEF_ASM(xmm0) + DEF_ASM(xmm1) + DEF_ASM(xmm2) + DEF_ASM(xmm3) + DEF_ASM(xmm4) + DEF_ASM(xmm5) + DEF_ASM(xmm6) + DEF_ASM(xmm7) + DEF_ASM(cr0) + DEF_ASM(cr1) + DEF_ASM(cr2) + DEF_ASM(cr3) + DEF_ASM(cr4) + DEF_ASM(cr5) + DEF_ASM(cr6) + DEF_ASM(cr7) + DEF_ASM(tr0) + DEF_ASM(tr1) + DEF_ASM(tr2) + DEF_ASM(tr3) + DEF_ASM(tr4) + DEF_ASM(tr5) + DEF_ASM(tr6) + DEF_ASM(tr7) + DEF_ASM(db0) + DEF_ASM(db1) + DEF_ASM(db2) + DEF_ASM(db3) + DEF_ASM(db4) + DEF_ASM(db5) + DEF_ASM(db6) + DEF_ASM(db7) + DEF_ASM(dr0) + DEF_ASM(dr1) + DEF_ASM(dr2) + DEF_ASM(dr3) + DEF_ASM(dr4) + DEF_ASM(dr5) + DEF_ASM(dr6) + DEF_ASM(dr7) + DEF_ASM(es) + DEF_ASM(cs) + DEF_ASM(ss) + DEF_ASM(ds) + DEF_ASM(fs) + DEF_ASM(gs) + DEF_ASM(st) + DEF_ASM(rip) + +#ifdef TCC_TARGET_X86_64 + /* The four low parts of sp/bp/si/di that exist only on + x86-64 (encoding aliased to ah,ch,dh,dh when not using REX). */ + DEF_ASM(spl) + DEF_ASM(bpl) + DEF_ASM(sil) + DEF_ASM(dil) +#endif + /* generic two operands */ + DEF_BWLX(mov) + + DEF_BWLX(add) + DEF_BWLX(or) + DEF_BWLX(adc) + DEF_BWLX(sbb) + DEF_BWLX(and) + DEF_BWLX(sub) + DEF_BWLX(xor) + DEF_BWLX(cmp) + + /* unary ops */ + DEF_BWLX(inc) + DEF_BWLX(dec) + DEF_BWLX(not) + DEF_BWLX(neg) + DEF_BWLX(mul) + DEF_BWLX(imul) + DEF_BWLX(div) + DEF_BWLX(idiv) + + DEF_BWLX(xchg) + DEF_BWLX(test) + + /* shifts */ + DEF_BWLX(rol) + DEF_BWLX(ror) + DEF_BWLX(rcl) + DEF_BWLX(rcr) + DEF_BWLX(shl) + DEF_BWLX(shr) + DEF_BWLX(sar) + + DEF_WLX(shld) + DEF_WLX(shrd) + + DEF_ASM(pushw) + DEF_ASM(pushl) +#ifdef TCC_TARGET_X86_64 + DEF_ASM(pushq) +#endif + DEF_ASM(push) + + DEF_ASM(popw) + DEF_ASM(popl) +#ifdef TCC_TARGET_X86_64 + DEF_ASM(popq) +#endif + DEF_ASM(pop) + + DEF_BWL(in) + DEF_BWL(out) + + DEF_WLX(movzb) + DEF_ASM(movzwl) + DEF_ASM(movsbw) + DEF_ASM(movsbl) + DEF_ASM(movswl) +#ifdef TCC_TARGET_X86_64 + DEF_ASM(movsbq) + DEF_ASM(movswq) + DEF_ASM(movzwq) + DEF_ASM(movslq) +#endif + + DEF_WLX(lea) + + DEF_ASM(les) + DEF_ASM(lds) + DEF_ASM(lss) + DEF_ASM(lfs) + DEF_ASM(lgs) + + DEF_ASM(call) + DEF_ASM(jmp) + DEF_ASM(lcall) + DEF_ASM(ljmp) + + DEF_ASMTEST(j,) + + DEF_ASMTEST(set,) + DEF_ASMTEST(set,b) + DEF_ASMTEST(cmov,) + + DEF_WLX(bsf) + DEF_WLX(bsr) + DEF_WLX(bt) + DEF_WLX(bts) + DEF_WLX(btr) + DEF_WLX(btc) + + DEF_WLX(lar) + DEF_WLX(lsl) + + /* generic FP ops */ + DEF_FP(add) + DEF_FP(mul) + + DEF_ASM(fcom) + DEF_ASM(fcom_1) /* non existent op, just to have a regular table */ + DEF_FP1(com) + + DEF_FP(comp) + DEF_FP(sub) + DEF_FP(subr) + DEF_FP(div) + DEF_FP(divr) + + DEF_BWLX(xadd) + DEF_BWLX(cmpxchg) + + /* string ops */ + DEF_BWLX(cmps) + DEF_BWLX(scmp) + DEF_BWL(ins) + DEF_BWL(outs) + DEF_BWLX(lods) + DEF_BWLX(slod) + DEF_BWLX(movs) + DEF_BWLX(smov) + DEF_BWLX(scas) + DEF_BWLX(ssca) + DEF_BWLX(stos) + DEF_BWLX(ssto) + + /* generic asm ops */ +#define ALT(x) +#define DEF_ASM_OP0(name, opcode) DEF_ASM(name) +#define DEF_ASM_OP0L(name, opcode, group, instr_type) +#define DEF_ASM_OP1(name, opcode, group, instr_type, op0) +#define DEF_ASM_OP2(name, opcode, group, instr_type, op0, op1) +#define DEF_ASM_OP3(name, opcode, group, instr_type, op0, op1, op2) +#ifdef TCC_TARGET_X86_64 +# include "x86_64-asm.h" +#else +# include "i386-asm.h" +#endif + +#define ALT(x) +#define DEF_ASM_OP0(name, opcode) +#define DEF_ASM_OP0L(name, opcode, group, instr_type) DEF_ASM(name) +#define DEF_ASM_OP1(name, opcode, group, instr_type, op0) DEF_ASM(name) +#define DEF_ASM_OP2(name, opcode, group, instr_type, op0, op1) DEF_ASM(name) +#define DEF_ASM_OP3(name, opcode, group, instr_type, op0, op1, op2) DEF_ASM(name) +#ifdef TCC_TARGET_X86_64 +# include "x86_64-asm.h" +#else +# include "i386-asm.h" +#endif diff --git a/tinyc/il-gen.c b/tinyc/il-gen.c new file mode 100644 index 000000000..bb670ccb0 --- /dev/null +++ b/tinyc/il-gen.c @@ -0,0 +1,657 @@ +/* + * CIL code generator for TCC + * + * Copyright (c) 2002 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#error this code has bit-rotted since 2003 + +/* number of available registers */ +#define NB_REGS 3 + +/* a register can belong to several classes. The classes must be + sorted from more general to more precise (see gv2() code which does + assumptions on it). */ +#define RC_ST 0x0001 /* any stack entry */ +#define RC_ST0 0x0002 /* top of stack */ +#define RC_ST1 0x0004 /* top - 1 */ + +#define RC_INT RC_ST +#define RC_FLOAT RC_ST +#define RC_IRET RC_ST0 /* function return: integer register */ +#define RC_LRET RC_ST0 /* function return: second integer register */ +#define RC_FRET RC_ST0 /* function return: float register */ + +/* pretty names for the registers */ +enum { + REG_ST0 = 0, + REG_ST1, + REG_ST2, +}; + +const int reg_classes[NB_REGS] = { + /* ST0 */ RC_ST | RC_ST0, + /* ST1 */ RC_ST | RC_ST1, + /* ST2 */ RC_ST, +}; + +/* return registers for function */ +#define REG_IRET REG_ST0 /* single word int return register */ +#define REG_LRET REG_ST0 /* second word return register (for long long) */ +#define REG_FRET REG_ST0 /* float return register */ + +/* defined if function parameters must be evaluated in reverse order */ +/* #define INVERT_FUNC_PARAMS */ + +/* defined if structures are passed as pointers. Otherwise structures + are directly pushed on stack. */ +/* #define FUNC_STRUCT_PARAM_AS_PTR */ + +/* pointer size, in bytes */ +#define PTR_SIZE 4 + +/* long double size and alignment, in bytes */ +#define LDOUBLE_SIZE 8 +#define LDOUBLE_ALIGN 8 + +/* function call context */ +typedef struct GFuncContext { + int func_call; /* func call type (FUNC_STDCALL or FUNC_CDECL) */ +} GFuncContext; + +/******************************************************/ +/* opcode definitions */ + +#define IL_OP_PREFIX 0xFE + +enum ILOPCodes { +#define OP(name, str, n) IL_OP_ ## name = n, +#include "il-opcodes.h" +#undef OP +}; + +char *il_opcodes_str[] = { +#define OP(name, str, n) [n] = str, +#include "il-opcodes.h" +#undef OP +}; + +/******************************************************/ + +/* arguments variable numbers start from there */ +#define ARG_BASE 0x70000000 + +static FILE *il_outfile; + +static void out_byte(int c) +{ + *(char *)ind++ = c; +} + +static void out_le32(int c) +{ + out_byte(c); + out_byte(c >> 8); + out_byte(c >> 16); + out_byte(c >> 24); +} + +static void init_outfile(void) +{ + if (!il_outfile) { + il_outfile = stdout; + fprintf(il_outfile, + ".assembly extern mscorlib\n" + "{\n" + ".ver 1:0:2411:0\n" + "}\n\n"); + } +} + +static void out_op1(int op) +{ + if (op & 0x100) + out_byte(IL_OP_PREFIX); + out_byte(op & 0xff); +} + +/* output an opcode with prefix */ +static void out_op(int op) +{ + out_op1(op); + fprintf(il_outfile, " %s\n", il_opcodes_str[op]); +} + +static void out_opb(int op, int c) +{ + out_op1(op); + out_byte(c); + fprintf(il_outfile, " %s %d\n", il_opcodes_str[op], c); +} + +static void out_opi(int op, int c) +{ + out_op1(op); + out_le32(c); + fprintf(il_outfile, " %s 0x%x\n", il_opcodes_str[op], c); +} + +/* XXX: not complete */ +static void il_type_to_str(char *buf, int buf_size, + int t, const char *varstr) +{ + int bt; + Sym *s, *sa; + char buf1[256]; + const char *tstr; + + t = t & VT_TYPE; + bt = t & VT_BTYPE; + buf[0] = '\0'; + if (t & VT_UNSIGNED) + pstrcat(buf, buf_size, "unsigned "); + switch(bt) { + case VT_VOID: + tstr = "void"; + goto add_tstr; + case VT_BOOL: + tstr = "bool"; + goto add_tstr; + case VT_BYTE: + tstr = "int8"; + goto add_tstr; + case VT_SHORT: + tstr = "int16"; + goto add_tstr; + case VT_ENUM: + case VT_INT: + case VT_LONG: + tstr = "int32"; + goto add_tstr; + case VT_LLONG: + tstr = "int64"; + goto add_tstr; + case VT_FLOAT: + tstr = "float32"; + goto add_tstr; + case VT_DOUBLE: + case VT_LDOUBLE: + tstr = "float64"; + add_tstr: + pstrcat(buf, buf_size, tstr); + break; + case VT_STRUCT: + tcc_error("structures not handled yet"); + break; + case VT_FUNC: + s = sym_find((unsigned)t >> VT_STRUCT_SHIFT); + il_type_to_str(buf, buf_size, s->t, varstr); + pstrcat(buf, buf_size, "("); + sa = s->next; + while (sa != NULL) { + il_type_to_str(buf1, sizeof(buf1), sa->t, NULL); + pstrcat(buf, buf_size, buf1); + sa = sa->next; + if (sa) + pstrcat(buf, buf_size, ", "); + } + pstrcat(buf, buf_size, ")"); + goto no_var; + case VT_PTR: + s = sym_find((unsigned)t >> VT_STRUCT_SHIFT); + pstrcpy(buf1, sizeof(buf1), "*"); + if (varstr) + pstrcat(buf1, sizeof(buf1), varstr); + il_type_to_str(buf, buf_size, s->t, buf1); + goto no_var; + } + if (varstr) { + pstrcat(buf, buf_size, " "); + pstrcat(buf, buf_size, varstr); + } + no_var: ; +} + + +/* patch relocation entry with value 'val' */ +void greloc_patch1(Reloc *p, int val) +{ +} + +/* output a symbol and patch all calls to it */ +void gsym_addr(t, a) +{ +} + +/* output jump and return symbol */ +static int out_opj(int op, int c) +{ + out_op1(op); + out_le32(0); + if (c == 0) { + c = ind - (int)cur_text_section->data; + } + fprintf(il_outfile, " %s L%d\n", il_opcodes_str[op], c); + return c; +} + +void gsym(int t) +{ + fprintf(il_outfile, "L%d:\n", t); +} + +/* load 'r' from value 'sv' */ +void load(int r, SValue *sv) +{ + int v, fc, ft; + + v = sv->r & VT_VALMASK; + fc = sv->c.i; + ft = sv->t; + + if (sv->r & VT_LVAL) { + if (v == VT_LOCAL) { + if (fc >= ARG_BASE) { + fc -= ARG_BASE; + if (fc >= 0 && fc <= 4) { + out_op(IL_OP_LDARG_0 + fc); + } else if (fc <= 0xff) { + out_opb(IL_OP_LDARG_S, fc); + } else { + out_opi(IL_OP_LDARG, fc); + } + } else { + if (fc >= 0 && fc <= 4) { + out_op(IL_OP_LDLOC_0 + fc); + } else if (fc <= 0xff) { + out_opb(IL_OP_LDLOC_S, fc); + } else { + out_opi(IL_OP_LDLOC, fc); + } + } + } else if (v == VT_CONST) { + /* XXX: handle globals */ + out_opi(IL_OP_LDSFLD, 0); + } else { + if ((ft & VT_BTYPE) == VT_FLOAT) { + out_op(IL_OP_LDIND_R4); + } else if ((ft & VT_BTYPE) == VT_DOUBLE) { + out_op(IL_OP_LDIND_R8); + } else if ((ft & VT_BTYPE) == VT_LDOUBLE) { + out_op(IL_OP_LDIND_R8); + } else if ((ft & VT_TYPE) == VT_BYTE) + out_op(IL_OP_LDIND_I1); + else if ((ft & VT_TYPE) == (VT_BYTE | VT_UNSIGNED)) + out_op(IL_OP_LDIND_U1); + else if ((ft & VT_TYPE) == VT_SHORT) + out_op(IL_OP_LDIND_I2); + else if ((ft & VT_TYPE) == (VT_SHORT | VT_UNSIGNED)) + out_op(IL_OP_LDIND_U2); + else + out_op(IL_OP_LDIND_I4); + } + } else { + if (v == VT_CONST) { + /* XXX: handle globals */ + if (fc >= -1 && fc <= 8) { + out_op(IL_OP_LDC_I4_M1 + fc + 1); + } else { + out_opi(IL_OP_LDC_I4, fc); + } + } else if (v == VT_LOCAL) { + if (fc >= ARG_BASE) { + fc -= ARG_BASE; + if (fc <= 0xff) { + out_opb(IL_OP_LDARGA_S, fc); + } else { + out_opi(IL_OP_LDARGA, fc); + } + } else { + if (fc <= 0xff) { + out_opb(IL_OP_LDLOCA_S, fc); + } else { + out_opi(IL_OP_LDLOCA, fc); + } + } + } else { + /* XXX: do it */ + } + } +} + +/* store register 'r' in lvalue 'v' */ +void store(int r, SValue *sv) +{ + int v, fc, ft; + + v = sv->r & VT_VALMASK; + fc = sv->c.i; + ft = sv->t; + if (v == VT_LOCAL) { + if (fc >= ARG_BASE) { + fc -= ARG_BASE; + /* XXX: check IL arg store semantics */ + if (fc <= 0xff) { + out_opb(IL_OP_STARG_S, fc); + } else { + out_opi(IL_OP_STARG, fc); + } + } else { + if (fc >= 0 && fc <= 4) { + out_op(IL_OP_STLOC_0 + fc); + } else if (fc <= 0xff) { + out_opb(IL_OP_STLOC_S, fc); + } else { + out_opi(IL_OP_STLOC, fc); + } + } + } else if (v == VT_CONST) { + /* XXX: handle globals */ + out_opi(IL_OP_STSFLD, 0); + } else { + if ((ft & VT_BTYPE) == VT_FLOAT) + out_op(IL_OP_STIND_R4); + else if ((ft & VT_BTYPE) == VT_DOUBLE) + out_op(IL_OP_STIND_R8); + else if ((ft & VT_BTYPE) == VT_LDOUBLE) + out_op(IL_OP_STIND_R8); + else if ((ft & VT_BTYPE) == VT_BYTE) + out_op(IL_OP_STIND_I1); + else if ((ft & VT_BTYPE) == VT_SHORT) + out_op(IL_OP_STIND_I2); + else + out_op(IL_OP_STIND_I4); + } +} + +/* start function call and return function call context */ +void gfunc_start(GFuncContext *c, int func_call) +{ + c->func_call = func_call; +} + +/* push function parameter which is in (vtop->t, vtop->c). Stack entry + is then popped. */ +void gfunc_param(GFuncContext *c) +{ + if ((vtop->t & VT_BTYPE) == VT_STRUCT) { + tcc_error("structures passed as value not handled yet"); + } else { + /* simply push on stack */ + gv(RC_ST0); + } + vtop--; +} + +/* generate function call with address in (vtop->t, vtop->c) and free function + context. Stack entry is popped */ +void gfunc_call(GFuncContext *c) +{ + char buf[1024]; + + if ((vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST) { + /* XXX: more info needed from tcc */ + il_type_to_str(buf, sizeof(buf), vtop->t, "xxx"); + fprintf(il_outfile, " call %s\n", buf); + } else { + /* indirect call */ + gv(RC_INT); + il_type_to_str(buf, sizeof(buf), vtop->t, NULL); + fprintf(il_outfile, " calli %s\n", buf); + } + vtop--; +} + +/* generate function prolog of type 't' */ +void gfunc_prolog(int t) +{ + int addr, u, func_call; + Sym *sym; + char buf[1024]; + + init_outfile(); + + /* XXX: pass function name to gfunc_prolog */ + il_type_to_str(buf, sizeof(buf), t, funcname); + fprintf(il_outfile, ".method static %s il managed\n", buf); + fprintf(il_outfile, "{\n"); + /* XXX: cannot do better now */ + fprintf(il_outfile, " .maxstack %d\n", NB_REGS); + fprintf(il_outfile, " .locals (int32, int32, int32, int32, int32, int32, int32, int32)\n"); + + if (!strcmp(funcname, "main")) + fprintf(il_outfile, " .entrypoint\n"); + + sym = sym_find((unsigned)t >> VT_STRUCT_SHIFT); + func_call = sym->r; + + addr = ARG_BASE; + /* if the function returns a structure, then add an + implicit pointer parameter */ + func_vt = sym->t; + func_var = (sym->c == FUNC_ELLIPSIS); + if ((func_vt & VT_BTYPE) == VT_STRUCT) { + func_vc = addr; + addr++; + } + /* define parameters */ + while ((sym = sym->next) != NULL) { + u = sym->t; + sym_push(sym->v & ~SYM_FIELD, u, + VT_LOCAL | lvalue_type(sym->type.t), addr); + addr++; + } +} + +/* generate function epilog */ +void gfunc_epilog(void) +{ + out_op(IL_OP_RET); + fprintf(il_outfile, "}\n\n"); +} + +/* generate a jump to a label */ +int gjmp(int t) +{ + return out_opj(IL_OP_BR, t); +} + +/* generate a jump to a fixed address */ +void gjmp_addr(int a) +{ + /* XXX: handle syms */ + out_opi(IL_OP_BR, a); +} + +/* generate a test. set 'inv' to invert test. Stack entry is popped */ +int gtst(int inv, int t) +{ + int v, *p, c; + + v = vtop->r & VT_VALMASK; + if (v == VT_CMP) { + c = vtop->c.i ^ inv; + switch(c) { + case TOK_EQ: + c = IL_OP_BEQ; + break; + case TOK_NE: + c = IL_OP_BNE_UN; + break; + case TOK_LT: + c = IL_OP_BLT; + break; + case TOK_LE: + c = IL_OP_BLE; + break; + case TOK_GT: + c = IL_OP_BGT; + break; + case TOK_GE: + c = IL_OP_BGE; + break; + case TOK_ULT: + c = IL_OP_BLT_UN; + break; + case TOK_ULE: + c = IL_OP_BLE_UN; + break; + case TOK_UGT: + c = IL_OP_BGT_UN; + break; + case TOK_UGE: + c = IL_OP_BGE_UN; + break; + } + t = out_opj(c, t); + } else if (v == VT_JMP || v == VT_JMPI) { + /* && or || optimization */ + if ((v & 1) == inv) { + /* insert vtop->c jump list in t */ + p = &vtop->c.i; + while (*p != 0) + p = (int *)*p; + *p = t; + t = vtop->c.i; + } else { + t = gjmp(t); + gsym(vtop->c.i); + } + } + vtop--; + return t; +} + +/* generate an integer binary operation */ +void gen_opi(int op) +{ + gv2(RC_ST1, RC_ST0); + switch(op) { + case '+': + out_op(IL_OP_ADD); + goto std_op; + case '-': + out_op(IL_OP_SUB); + goto std_op; + case '&': + out_op(IL_OP_AND); + goto std_op; + case '^': + out_op(IL_OP_XOR); + goto std_op; + case '|': + out_op(IL_OP_OR); + goto std_op; + case '*': + out_op(IL_OP_MUL); + goto std_op; + case TOK_SHL: + out_op(IL_OP_SHL); + goto std_op; + case TOK_SHR: + out_op(IL_OP_SHR_UN); + goto std_op; + case TOK_SAR: + out_op(IL_OP_SHR); + goto std_op; + case '/': + case TOK_PDIV: + out_op(IL_OP_DIV); + goto std_op; + case TOK_UDIV: + out_op(IL_OP_DIV_UN); + goto std_op; + case '%': + out_op(IL_OP_REM); + goto std_op; + case TOK_UMOD: + out_op(IL_OP_REM_UN); + std_op: + vtop--; + vtop[0].r = REG_ST0; + break; + case TOK_EQ: + case TOK_NE: + case TOK_LT: + case TOK_LE: + case TOK_GT: + case TOK_GE: + case TOK_ULT: + case TOK_ULE: + case TOK_UGT: + case TOK_UGE: + vtop--; + vtop[0].r = VT_CMP; + vtop[0].c.i = op; + break; + } +} + +/* generate a floating point operation 'v = t1 op t2' instruction. The + two operands are guaranteed to have the same floating point type */ +void gen_opf(int op) +{ + /* same as integer */ + gen_opi(op); +} + +/* convert integers to fp 't' type. Must handle 'int', 'unsigned int' + and 'long long' cases. */ +void gen_cvt_itof(int t) +{ + gv(RC_ST0); + if (t == VT_FLOAT) + out_op(IL_OP_CONV_R4); + else + out_op(IL_OP_CONV_R8); +} + +/* convert fp to int 't' type */ +/* XXX: handle long long case */ +void gen_cvt_ftoi(int t) +{ + gv(RC_ST0); + switch(t) { + case VT_INT | VT_UNSIGNED: + out_op(IL_OP_CONV_U4); + break; + case VT_LLONG: + out_op(IL_OP_CONV_I8); + break; + case VT_LLONG | VT_UNSIGNED: + out_op(IL_OP_CONV_U8); + break; + default: + out_op(IL_OP_CONV_I4); + break; + } +} + +/* convert from one floating point type to another */ +void gen_cvt_ftof(int t) +{ + gv(RC_ST0); + if (t == VT_FLOAT) { + out_op(IL_OP_CONV_R4); + } else { + out_op(IL_OP_CONV_R8); + } +} + +/* end of CIL code generator */ +/*************************************************************/ + diff --git a/tinyc/il-opcodes.h b/tinyc/il-opcodes.h new file mode 100644 index 000000000..d53ffb2c5 --- /dev/null +++ b/tinyc/il-opcodes.h @@ -0,0 +1,251 @@ +/* + * CIL opcode definition + * + * Copyright (c) 2002 Fabrice Bellard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +OP(NOP, "nop", 0x00) +OP(BREAK, "break", 0x01) +OP(LDARG_0, "ldarg.0", 0x02) +OP(LDARG_1, "ldarg.1", 0x03) +OP(LDARG_2, "ldarg.2", 0x04) +OP(LDARG_3, "ldarg.3", 0x05) +OP(LDLOC_0, "ldloc.0", 0x06) +OP(LDLOC_1, "ldloc.1", 0x07) +OP(LDLOC_2, "ldloc.2", 0x08) +OP(LDLOC_3, "ldloc.3", 0x09) +OP(STLOC_0, "stloc.0", 0x0a) +OP(STLOC_1, "stloc.1", 0x0b) +OP(STLOC_2, "stloc.2", 0x0c) +OP(STLOC_3, "stloc.3", 0x0d) +OP(LDARG_S, "ldarg.s", 0x0e) +OP(LDARGA_S, "ldarga.s", 0x0f) +OP(STARG_S, "starg.s", 0x10) +OP(LDLOC_S, "ldloc.s", 0x11) +OP(LDLOCA_S, "ldloca.s", 0x12) +OP(STLOC_S, "stloc.s", 0x13) +OP(LDNULL, "ldnull", 0x14) +OP(LDC_I4_M1, "ldc.i4.m1", 0x15) +OP(LDC_I4_0, "ldc.i4.0", 0x16) +OP(LDC_I4_1, "ldc.i4.1", 0x17) +OP(LDC_I4_2, "ldc.i4.2", 0x18) +OP(LDC_I4_3, "ldc.i4.3", 0x19) +OP(LDC_I4_4, "ldc.i4.4", 0x1a) +OP(LDC_I4_5, "ldc.i4.5", 0x1b) +OP(LDC_I4_6, "ldc.i4.6", 0x1c) +OP(LDC_I4_7, "ldc.i4.7", 0x1d) +OP(LDC_I4_8, "ldc.i4.8", 0x1e) +OP(LDC_I4_S, "ldc.i4.s", 0x1f) +OP(LDC_I4, "ldc.i4", 0x20) +OP(LDC_I8, "ldc.i8", 0x21) +OP(LDC_R4, "ldc.r4", 0x22) +OP(LDC_R8, "ldc.r8", 0x23) +OP(LDPTR, "ldptr", 0x24) +OP(DUP, "dup", 0x25) +OP(POP, "pop", 0x26) +OP(JMP, "jmp", 0x27) +OP(CALL, "call", 0x28) +OP(CALLI, "calli", 0x29) +OP(RET, "ret", 0x2a) +OP(BR_S, "br.s", 0x2b) +OP(BRFALSE_S, "brfalse.s", 0x2c) +OP(BRTRUE_S, "brtrue.s", 0x2d) +OP(BEQ_S, "beq.s", 0x2e) +OP(BGE_S, "bge.s", 0x2f) +OP(BGT_S, "bgt.s", 0x30) +OP(BLE_S, "ble.s", 0x31) +OP(BLT_S, "blt.s", 0x32) +OP(BNE_UN_S, "bne.un.s", 0x33) +OP(BGE_UN_S, "bge.un.s", 0x34) +OP(BGT_UN_S, "bgt.un.s", 0x35) +OP(BLE_UN_S, "ble.un.s", 0x36) +OP(BLT_UN_S, "blt.un.s", 0x37) +OP(BR, "br", 0x38) +OP(BRFALSE, "brfalse", 0x39) +OP(BRTRUE, "brtrue", 0x3a) +OP(BEQ, "beq", 0x3b) +OP(BGE, "bge", 0x3c) +OP(BGT, "bgt", 0x3d) +OP(BLE, "ble", 0x3e) +OP(BLT, "blt", 0x3f) +OP(BNE_UN, "bne.un", 0x40) +OP(BGE_UN, "bge.un", 0x41) +OP(BGT_UN, "bgt.un", 0x42) +OP(BLE_UN, "ble.un", 0x43) +OP(BLT_UN, "blt.un", 0x44) +OP(SWITCH, "switch", 0x45) +OP(LDIND_I1, "ldind.i1", 0x46) +OP(LDIND_U1, "ldind.u1", 0x47) +OP(LDIND_I2, "ldind.i2", 0x48) +OP(LDIND_U2, "ldind.u2", 0x49) +OP(LDIND_I4, "ldind.i4", 0x4a) +OP(LDIND_U4, "ldind.u4", 0x4b) +OP(LDIND_I8, "ldind.i8", 0x4c) +OP(LDIND_I, "ldind.i", 0x4d) +OP(LDIND_R4, "ldind.r4", 0x4e) +OP(LDIND_R8, "ldind.r8", 0x4f) +OP(LDIND_REF, "ldind.ref", 0x50) +OP(STIND_REF, "stind.ref", 0x51) +OP(STIND_I1, "stind.i1", 0x52) +OP(STIND_I2, "stind.i2", 0x53) +OP(STIND_I4, "stind.i4", 0x54) +OP(STIND_I8, "stind.i8", 0x55) +OP(STIND_R4, "stind.r4", 0x56) +OP(STIND_R8, "stind.r8", 0x57) +OP(ADD, "add", 0x58) +OP(SUB, "sub", 0x59) +OP(MUL, "mul", 0x5a) +OP(DIV, "div", 0x5b) +OP(DIV_UN, "div.un", 0x5c) +OP(REM, "rem", 0x5d) +OP(REM_UN, "rem.un", 0x5e) +OP(AND, "and", 0x5f) +OP(OR, "or", 0x60) +OP(XOR, "xor", 0x61) +OP(SHL, "shl", 0x62) +OP(SHR, "shr", 0x63) +OP(SHR_UN, "shr.un", 0x64) +OP(NEG, "neg", 0x65) +OP(NOT, "not", 0x66) +OP(CONV_I1, "conv.i1", 0x67) +OP(CONV_I2, "conv.i2", 0x68) +OP(CONV_I4, "conv.i4", 0x69) +OP(CONV_I8, "conv.i8", 0x6a) +OP(CONV_R4, "conv.r4", 0x6b) +OP(CONV_R8, "conv.r8", 0x6c) +OP(CONV_U4, "conv.u4", 0x6d) +OP(CONV_U8, "conv.u8", 0x6e) +OP(CALLVIRT, "callvirt", 0x6f) +OP(CPOBJ, "cpobj", 0x70) +OP(LDOBJ, "ldobj", 0x71) +OP(LDSTR, "ldstr", 0x72) +OP(NEWOBJ, "newobj", 0x73) +OP(CASTCLASS, "castclass", 0x74) +OP(ISINST, "isinst", 0x75) +OP(CONV_R_UN, "conv.r.un", 0x76) +OP(ANN_DATA_S, "ann.data.s", 0x77) +OP(UNBOX, "unbox", 0x79) +OP(THROW, "throw", 0x7a) +OP(LDFLD, "ldfld", 0x7b) +OP(LDFLDA, "ldflda", 0x7c) +OP(STFLD, "stfld", 0x7d) +OP(LDSFLD, "ldsfld", 0x7e) +OP(LDSFLDA, "ldsflda", 0x7f) +OP(STSFLD, "stsfld", 0x80) +OP(STOBJ, "stobj", 0x81) +OP(CONV_OVF_I1_UN, "conv.ovf.i1.un", 0x82) +OP(CONV_OVF_I2_UN, "conv.ovf.i2.un", 0x83) +OP(CONV_OVF_I4_UN, "conv.ovf.i4.un", 0x84) +OP(CONV_OVF_I8_UN, "conv.ovf.i8.un", 0x85) +OP(CONV_OVF_U1_UN, "conv.ovf.u1.un", 0x86) +OP(CONV_OVF_U2_UN, "conv.ovf.u2.un", 0x87) +OP(CONV_OVF_U4_UN, "conv.ovf.u4.un", 0x88) +OP(CONV_OVF_U8_UN, "conv.ovf.u8.un", 0x89) +OP(CONV_OVF_I_UN, "conv.ovf.i.un", 0x8a) +OP(CONV_OVF_U_UN, "conv.ovf.u.un", 0x8b) +OP(BOX, "box", 0x8c) +OP(NEWARR, "newarr", 0x8d) +OP(LDLEN, "ldlen", 0x8e) +OP(LDELEMA, "ldelema", 0x8f) +OP(LDELEM_I1, "ldelem.i1", 0x90) +OP(LDELEM_U1, "ldelem.u1", 0x91) +OP(LDELEM_I2, "ldelem.i2", 0x92) +OP(LDELEM_U2, "ldelem.u2", 0x93) +OP(LDELEM_I4, "ldelem.i4", 0x94) +OP(LDELEM_U4, "ldelem.u4", 0x95) +OP(LDELEM_I8, "ldelem.i8", 0x96) +OP(LDELEM_I, "ldelem.i", 0x97) +OP(LDELEM_R4, "ldelem.r4", 0x98) +OP(LDELEM_R8, "ldelem.r8", 0x99) +OP(LDELEM_REF, "ldelem.ref", 0x9a) +OP(STELEM_I, "stelem.i", 0x9b) +OP(STELEM_I1, "stelem.i1", 0x9c) +OP(STELEM_I2, "stelem.i2", 0x9d) +OP(STELEM_I4, "stelem.i4", 0x9e) +OP(STELEM_I8, "stelem.i8", 0x9f) +OP(STELEM_R4, "stelem.r4", 0xa0) +OP(STELEM_R8, "stelem.r8", 0xa1) +OP(STELEM_REF, "stelem.ref", 0xa2) +OP(CONV_OVF_I1, "conv.ovf.i1", 0xb3) +OP(CONV_OVF_U1, "conv.ovf.u1", 0xb4) +OP(CONV_OVF_I2, "conv.ovf.i2", 0xb5) +OP(CONV_OVF_U2, "conv.ovf.u2", 0xb6) +OP(CONV_OVF_I4, "conv.ovf.i4", 0xb7) +OP(CONV_OVF_U4, "conv.ovf.u4", 0xb8) +OP(CONV_OVF_I8, "conv.ovf.i8", 0xb9) +OP(CONV_OVF_U8, "conv.ovf.u8", 0xba) +OP(REFANYVAL, "refanyval", 0xc2) +OP(CKFINITE, "ckfinite", 0xc3) +OP(MKREFANY, "mkrefany", 0xc6) +OP(ANN_CALL, "ann.call", 0xc7) +OP(ANN_CATCH, "ann.catch", 0xc8) +OP(ANN_DEAD, "ann.dead", 0xc9) +OP(ANN_HOISTED, "ann.hoisted", 0xca) +OP(ANN_HOISTED_CALL, "ann.hoisted.call", 0xcb) +OP(ANN_LAB, "ann.lab", 0xcc) +OP(ANN_DEF, "ann.def", 0xcd) +OP(ANN_REF_S, "ann.ref.s", 0xce) +OP(ANN_PHI, "ann.phi", 0xcf) +OP(LDTOKEN, "ldtoken", 0xd0) +OP(CONV_U2, "conv.u2", 0xd1) +OP(CONV_U1, "conv.u1", 0xd2) +OP(CONV_I, "conv.i", 0xd3) +OP(CONV_OVF_I, "conv.ovf.i", 0xd4) +OP(CONV_OVF_U, "conv.ovf.u", 0xd5) +OP(ADD_OVF, "add.ovf", 0xd6) +OP(ADD_OVF_UN, "add.ovf.un", 0xd7) +OP(MUL_OVF, "mul.ovf", 0xd8) +OP(MUL_OVF_UN, "mul.ovf.un", 0xd9) +OP(SUB_OVF, "sub.ovf", 0xda) +OP(SUB_OVF_UN, "sub.ovf.un", 0xdb) +OP(ENDFINALLY, "endfinally", 0xdc) +OP(LEAVE, "leave", 0xdd) +OP(LEAVE_S, "leave.s", 0xde) +OP(STIND_I, "stind.i", 0xdf) +OP(CONV_U, "conv.u", 0xe0) + +/* prefix instructions. we use an opcode >= 256 to ease coding */ + +OP(ARGLIST, "arglist", 0x100) +OP(CEQ, "ceq", 0x101) +OP(CGT, "cgt", 0x102) +OP(CGT_UN, "cgt.un", 0x103) +OP(CLT, "clt", 0x104) +OP(CLT_UN, "clt.un", 0x105) +OP(LDFTN, "ldftn", 0x106) +OP(LDVIRTFTN, "ldvirtftn", 0x107) +OP(JMPI, "jmpi", 0x108) +OP(LDARG, "ldarg", 0x109) +OP(LDARGA, "ldarga", 0x10a) +OP(STARG, "starg", 0x10b) +OP(LDLOC, "ldloc", 0x10c) +OP(LDLOCA, "ldloca", 0x10d) +OP(STLOC, "stloc", 0x10e) +OP(LOCALLOC, "localloc", 0x10f) +OP(ENDFILTER, "endfilter", 0x111) +OP(UNALIGNED, "unaligned", 0x112) +OP(VOLATILE, "volatile", 0x113) +OP(TAIL, "tail", 0x114) +OP(INITOBJ, "initobj", 0x115) +OP(ANN_LIVE, "ann.live", 0x116) +OP(CPBLK, "cpblk", 0x117) +OP(INITBLK, "initblk", 0x118) +OP(ANN_REF, "ann.ref", 0x119) +OP(RETHROW, "rethrow", 0x11a) +OP(SIZEOF, "sizeof", 0x11c) +OP(REFANYTYPE, "refanytype", 0x11d) +OP(ANN_DATA, "ann.data", 0x122) +OP(ANN_ARG, "ann.arg", 0x123) diff --git a/tinyc/include/float.h b/tinyc/include/float.h new file mode 100644 index 000000000..f16f1f0cb --- /dev/null +++ b/tinyc/include/float.h @@ -0,0 +1,57 @@ +#ifndef _FLOAT_H_ +#define _FLOAT_H_ + +#define FLT_RADIX 2 + +/* IEEE float */ +#define FLT_MANT_DIG 24 +#define FLT_DIG 6 +#define FLT_ROUNDS 1 +#define FLT_EPSILON 1.19209290e-07F +#define FLT_MIN_EXP (-125) +#define FLT_MIN 1.17549435e-38F +#define FLT_MIN_10_EXP (-37) +#define FLT_MAX_EXP 128 +#define FLT_MAX 3.40282347e+38F +#define FLT_MAX_10_EXP 38 + +/* IEEE double */ +#define DBL_MANT_DIG 53 +#define DBL_DIG 15 +#define DBL_EPSILON 2.2204460492503131e-16 +#define DBL_MIN_EXP (-1021) +#define DBL_MIN 2.2250738585072014e-308 +#define DBL_MIN_10_EXP (-307) +#define DBL_MAX_EXP 1024 +#define DBL_MAX 1.7976931348623157e+308 +#define DBL_MAX_10_EXP 308 + +/* horrible intel long double */ +#if defined __i386__ || defined __x86_64__ + +#define LDBL_MANT_DIG 64 +#define LDBL_DIG 18 +#define LDBL_EPSILON 1.08420217248550443401e-19L +#define LDBL_MIN_EXP (-16381) +#define LDBL_MIN 3.36210314311209350626e-4932L +#define LDBL_MIN_10_EXP (-4931) +#define LDBL_MAX_EXP 16384 +#define LDBL_MAX 1.18973149535723176502e+4932L +#define LDBL_MAX_10_EXP 4932 + +#else + +/* same as IEEE double */ +#define LDBL_MANT_DIG 53 +#define LDBL_DIG 15 +#define LDBL_EPSILON 2.2204460492503131e-16 +#define LDBL_MIN_EXP (-1021) +#define LDBL_MIN 2.2250738585072014e-308 +#define LDBL_MIN_10_EXP (-307) +#define LDBL_MAX_EXP 1024 +#define LDBL_MAX 1.7976931348623157e+308 +#define LDBL_MAX_10_EXP 308 + +#endif + +#endif /* _FLOAT_H_ */ diff --git a/tinyc/include/stdarg.h b/tinyc/include/stdarg.h new file mode 100644 index 000000000..10ce733b4 --- /dev/null +++ b/tinyc/include/stdarg.h @@ -0,0 +1,79 @@ +#ifndef _STDARG_H +#define _STDARG_H + +#ifdef __x86_64__ +#ifndef _WIN64 + +//This should be in sync with the declaration on our lib/libtcc1.c +/* GCC compatible definition of va_list. */ +typedef struct { + unsigned int gp_offset; + unsigned int fp_offset; + union { + unsigned int overflow_offset; + char *overflow_arg_area; + }; + char *reg_save_area; +} __va_list_struct; + +typedef __va_list_struct va_list[1]; + +void __va_start(__va_list_struct *ap, void *fp); +void *__va_arg(__va_list_struct *ap, int arg_type, int size, int align); + +#define va_start(ap, last) __va_start(ap, __builtin_frame_address(0)) +#define va_arg(ap, type) \ + (*(type *)(__va_arg(ap, __builtin_va_arg_types(type), sizeof(type), __alignof__(type)))) +#define va_copy(dest, src) (*(dest) = *(src)) +#define va_end(ap) + +/* avoid conflicting definition for va_list on Macs. */ +#define _VA_LIST_T + +#else /* _WIN64 */ +typedef char *va_list; +#define va_start(ap,last) __builtin_va_start(ap,last) +#define va_arg(ap, t) ((sizeof(t) > 8 || (sizeof(t) & (sizeof(t) - 1))) \ + ? **(t **)((ap += 8) - 8) : *(t *)((ap += 8) - 8)) +#define va_copy(dest, src) ((dest) = (src)) +#define va_end(ap) +#endif + +#elif __arm__ +typedef char *va_list; +#define _tcc_alignof(type) ((int)&((struct {char c;type x;} *)0)->x) +#define _tcc_align(addr,type) (((unsigned)addr + _tcc_alignof(type) - 1) \ + & ~(_tcc_alignof(type) - 1)) +#define va_start(ap,last) ap = ((char *)&(last)) + ((sizeof(last)+3)&~3) +#define va_arg(ap,type) (ap = (void *) ((_tcc_align(ap,type)+sizeof(type)+3) \ + &~3), *(type *)(ap - ((sizeof(type)+3)&~3))) +#define va_copy(dest, src) (dest) = (src) +#define va_end(ap) + +#elif defined(__aarch64__) +typedef struct { + void *__stack; + void *__gr_top; + void *__vr_top; + int __gr_offs; + int __vr_offs; +} va_list; +#define va_start(ap, last) __va_start(ap, last) +#define va_arg(ap, type) __va_arg(ap, type) +#define va_end(ap) +#define va_copy(dest, src) ((dest) = (src)) + +#else /* __i386__ */ +typedef char *va_list; +/* only correct for i386 */ +#define va_start(ap,last) ap = ((char *)&(last)) + ((sizeof(last)+3)&~3) +#define va_arg(ap,type) (ap += (sizeof(type)+3)&~3, *(type *)(ap - ((sizeof(type)+3)&~3))) +#define va_copy(dest, src) (dest) = (src) +#define va_end(ap) +#endif + +/* fix a buggy dependency on GCC in libio.h */ +typedef va_list __gnuc_va_list; +#define _VA_LIST_DEFINED + +#endif /* _STDARG_H */ diff --git a/tinyc/include/stdbool.h b/tinyc/include/stdbool.h new file mode 100644 index 000000000..d2ee446e7 --- /dev/null +++ b/tinyc/include/stdbool.h @@ -0,0 +1,11 @@ +#ifndef _STDBOOL_H +#define _STDBOOL_H + +/* ISOC99 boolean */ + +#define bool _Bool +#define true 1 +#define false 0 +#define __bool_true_false_are_defined 1 + +#endif /* _STDBOOL_H */ diff --git a/tinyc/include/stddef.h b/tinyc/include/stddef.h new file mode 100644 index 000000000..694d50375 --- /dev/null +++ b/tinyc/include/stddef.h @@ -0,0 +1,54 @@ +#ifndef _STDDEF_H +#define _STDDEF_H + +typedef __SIZE_TYPE__ size_t; +typedef __PTRDIFF_TYPE__ ssize_t; +typedef __WCHAR_TYPE__ wchar_t; +typedef __PTRDIFF_TYPE__ ptrdiff_t; +typedef __PTRDIFF_TYPE__ intptr_t; +typedef __SIZE_TYPE__ uintptr_t; + +#ifndef __int8_t_defined +#define __int8_t_defined +typedef signed char int8_t; +typedef signed short int int16_t; +typedef signed int int32_t; +#ifdef __LP64__ +typedef signed long int int64_t; +#else +typedef signed long long int int64_t; +#endif +typedef unsigned char uint8_t; +typedef unsigned short int uint16_t; +typedef unsigned int uint32_t; +#ifdef __LP64__ +typedef unsigned long int uint64_t; +#else +typedef unsigned long long int uint64_t; +#endif +#endif + +#ifndef NULL +#define NULL ((void*)0) +#endif + +#define offsetof(type, field) ((size_t)&((type *)0)->field) + +void *alloca(size_t size); + +#endif + +/* Older glibc require a wint_t from (when requested + by __need_wint_t, as otherwise stddef.h isn't allowed to + define this type). Note that this must be outside the normal + _STDDEF_H guard, so that it works even when we've included the file + already (without requiring wint_t). Some other libs define _WINT_T + if they've already provided that type, so we can use that as guard. + TCC defines __WINT_TYPE__ for us. */ +#if defined (__need_wint_t) +#ifndef _WINT_T +#define _WINT_T +typedef __WINT_TYPE__ wint_t; +#endif +#undef __need_wint_t +#endif diff --git a/tinyc/include/varargs.h b/tinyc/include/varargs.h new file mode 100644 index 000000000..d614366ed --- /dev/null +++ b/tinyc/include/varargs.h @@ -0,0 +1,12 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _VARARGS_H +#define _VARARGS_H + +#error "TinyCC no longer implements ." +#error "Revise your code to use ." + +#endif diff --git a/tinyc/lib/alloca-arm.S b/tinyc/lib/alloca-arm.S new file mode 100644 index 000000000..68556e36d --- /dev/null +++ b/tinyc/lib/alloca-arm.S @@ -0,0 +1,17 @@ + .text + .align 2 + .global alloca + .type alloca, %function +alloca: +#ifdef __TINYC__ + .int 0xe060d00d + .int 0xe3cdd007 + .int 0xe1a0000d + .int 0xe1a0f00e +#else + rsb sp, r0, sp + bic sp, sp, #7 + mov r0, sp + mov pc, lr +#endif + .size alloca, .-alloca diff --git a/tinyc/lib/alloca86-bt.S b/tinyc/lib/alloca86-bt.S new file mode 100644 index 000000000..4f95cf134 --- /dev/null +++ b/tinyc/lib/alloca86-bt.S @@ -0,0 +1,47 @@ +/* ---------------------------------------------- */ +/* alloca86-bt.S */ + +.globl __bound_alloca + +__bound_alloca: + pop %edx + pop %eax + mov %eax, %ecx + add $3,%eax + and $-4,%eax + jz p6 + +#ifdef _WIN32 +p4: + cmp $4096,%eax + jbe p5 + test %eax,-4096(%esp) + sub $4096,%esp + sub $4096,%eax + jmp p4 + +p5: +#endif + + sub %eax,%esp + mov %esp,%eax + + push %edx + push %eax + push %ecx + push %eax + call __bound_new_region + add $8, %esp + pop %eax + pop %edx + +p6: + push %edx + push %edx + ret + +/* mark stack as nonexecutable */ +#if defined __ELF__ && defined __linux__ + .section .note.GNU-stack,"",@progbits +#endif +/* ---------------------------------------------- */ diff --git a/tinyc/lib/alloca86.S b/tinyc/lib/alloca86.S new file mode 100644 index 000000000..bb7a2c24a --- /dev/null +++ b/tinyc/lib/alloca86.S @@ -0,0 +1,31 @@ +/* ---------------------------------------------- */ +/* alloca86.S */ + +.globl alloca + +alloca: + pop %edx + pop %eax + add $3,%eax + and $-4,%eax + jz p3 + +#ifdef _WIN32 +p1: + cmp $4096,%eax + jbe p2 + test %eax,-4096(%esp) + sub $4096,%esp + sub $4096,%eax + jmp p1 +p2: +#endif + + sub %eax,%esp + mov %esp,%eax +p3: + push %edx + push %edx + ret + +/* ---------------------------------------------- */ diff --git a/tinyc/lib/alloca86_64-bt.S b/tinyc/lib/alloca86_64-bt.S new file mode 100644 index 000000000..4cbad90f8 --- /dev/null +++ b/tinyc/lib/alloca86_64-bt.S @@ -0,0 +1,56 @@ +/* ---------------------------------------------- */ +/* alloca86_64.S */ + +.globl __bound_alloca +__bound_alloca: + +#ifdef _WIN32 + # bound checking is not implemented + pop %rdx + mov %rcx,%rax + add $15,%rax + and $-16,%rax + jz p3 + +p1: + cmp $4096,%rax + jbe p2 + test %rax,-4096(%rsp) + sub $4096,%rsp + sub $4096,%rax + jmp p1 +p2: + + sub %rax,%rsp + mov %rsp,%rax + add $32,%rax + +p3: + push %rdx + ret +#else + pop %rdx + mov %rdi,%rax + mov %rax,%rsi # size, a second parm to the __bound_new_region + + add $15,%rax + and $-16,%rax + jz p3 + + + sub %rax,%rsp + mov %rsp,%rdi # pointer, a first parm to the __bound_new_region + mov %rsp,%rax + + push %rdx + push %rax + call __bound_new_region + pop %rax + pop %rdx + +p3: + push %rdx + ret +#endif + +/* ---------------------------------------------- */ diff --git a/tinyc/lib/alloca86_64.S b/tinyc/lib/alloca86_64.S new file mode 100644 index 000000000..ae3c97de3 --- /dev/null +++ b/tinyc/lib/alloca86_64.S @@ -0,0 +1,34 @@ +/* ---------------------------------------------- */ +/* alloca86_64.S */ + +.globl alloca + +alloca: + pop %rdx +#ifdef _WIN32 + mov %rcx,%rax +#else + mov %rdi,%rax +#endif + add $15,%rax + and $-16,%rax + jz p3 + +#ifdef _WIN32 +p1: + cmp $4096,%rax + jbe p2 + test %rax,-4096(%rsp) + sub $4096,%rsp + sub $4096,%rax + jmp p1 +p2: +#endif + + sub %rax,%rsp + mov %rsp,%rax +p3: + push %rdx + ret + +/* ---------------------------------------------- */ diff --git a/tinyc/lib/armeabi.c b/tinyc/lib/armeabi.c new file mode 100644 index 000000000..a59640dd0 --- /dev/null +++ b/tinyc/lib/armeabi.c @@ -0,0 +1,501 @@ +/* TCC ARM runtime EABI + Copyright (C) 2013 Thomas Preud'homme + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE.*/ + +#ifdef __TINYC__ +#define INT_MIN (-2147483647 - 1) +#define INT_MAX 2147483647 +#define UINT_MAX 0xffffffff +#define LONG_MIN (-2147483647L - 1) +#define LONG_MAX 2147483647L +#define ULONG_MAX 0xffffffffUL +#define LLONG_MAX 9223372036854775807LL +#define LLONG_MIN (-9223372036854775807LL - 1) +#define ULLONG_MAX 0xffffffffffffffffULL +#else +#include +#endif + +/* We rely on the little endianness and EABI calling convention for this to + work */ + +typedef struct double_unsigned_struct { + unsigned low; + unsigned high; +} double_unsigned_struct; + +typedef struct unsigned_int_struct { + unsigned low; + int high; +} unsigned_int_struct; + +#define REGS_RETURN(name, type) \ + void name ## _return(type ret) {} + + +/* Float helper functions */ + +#define FLOAT_EXP_BITS 8 +#define FLOAT_FRAC_BITS 23 + +#define DOUBLE_EXP_BITS 11 +#define DOUBLE_FRAC_BITS 52 + +#define ONE_EXP(type) ((1 << (type ## _EXP_BITS - 1)) - 1) + +REGS_RETURN(unsigned_int_struct, unsigned_int_struct) +REGS_RETURN(double_unsigned_struct, double_unsigned_struct) + +/* float -> integer: (sign) 1.fraction x 2^(exponent - exp_for_one) */ + + +/* float to [unsigned] long long conversion */ +#define DEFINE__AEABI_F2XLZ(name, with_sign) \ +void __aeabi_ ## name(unsigned val) \ +{ \ + int exp, high_shift, sign; \ + double_unsigned_struct ret; \ + \ + /* compute sign */ \ + sign = val >> 31; \ + \ + /* compute real exponent */ \ + exp = val >> FLOAT_FRAC_BITS; \ + exp &= (1 << FLOAT_EXP_BITS) - 1; \ + exp -= ONE_EXP(FLOAT); \ + \ + /* undefined behavior if truncated value cannot be represented */ \ + if (with_sign) { \ + if (exp > 62) /* |val| too big, double cannot represent LLONG_MAX */ \ + return; \ + } else { \ + if ((sign && exp >= 0) || exp > 63) /* if val < 0 || val too big */ \ + return; \ + } \ + \ + val &= (1 << FLOAT_FRAC_BITS) - 1; \ + if (exp >= 32) { \ + ret.high = 1 << (exp - 32); \ + if (exp - 32 >= FLOAT_FRAC_BITS) { \ + ret.high |= val << (exp - 32 - FLOAT_FRAC_BITS); \ + ret.low = 0; \ + } else { \ + high_shift = FLOAT_FRAC_BITS - (exp - 32); \ + ret.high |= val >> high_shift; \ + ret.low = val << (32 - high_shift); \ + } \ + } else { \ + ret.high = 0; \ + ret.low = 1 << exp; \ + if (exp > FLOAT_FRAC_BITS) \ + ret.low |= val << (exp - FLOAT_FRAC_BITS); \ + else \ + ret.low |= val >> (FLOAT_FRAC_BITS - exp); \ + } \ + \ + /* encode negative integer using 2's complement */ \ + if (with_sign && sign) { \ + ret.low = ~ret.low; \ + ret.high = ~ret.high; \ + if (ret.low == UINT_MAX) { \ + ret.low = 0; \ + ret.high++; \ + } else \ + ret.low++; \ + } \ + \ + double_unsigned_struct_return(ret); \ +} + +/* float to unsigned long long conversion */ +DEFINE__AEABI_F2XLZ(f2ulz, 0) + +/* float to long long conversion */ +DEFINE__AEABI_F2XLZ(f2lz, 1) + +/* double to [unsigned] long long conversion */ +#define DEFINE__AEABI_D2XLZ(name, with_sign) \ +void __aeabi_ ## name(double_unsigned_struct val) \ +{ \ + int exp, high_shift, sign; \ + double_unsigned_struct ret; \ + \ + /* compute sign */ \ + sign = val.high >> 31; \ + \ + /* compute real exponent */ \ + exp = (val.high >> (DOUBLE_FRAC_BITS - 32)); \ + exp &= (1 << DOUBLE_EXP_BITS) - 1; \ + exp -= ONE_EXP(DOUBLE); \ + \ + /* undefined behavior if truncated value cannot be represented */ \ + if (with_sign) { \ + if (exp > 62) /* |val| too big, double cannot represent LLONG_MAX */ \ + return; \ + } else { \ + if ((sign && exp >= 0) || exp > 63) /* if val < 0 || val too big */ \ + return; \ + } \ + \ + val.high &= (1 << (DOUBLE_FRAC_BITS - 32)) - 1; \ + if (exp >= 32) { \ + ret.high = 1 << (exp - 32); \ + if (exp >= DOUBLE_FRAC_BITS) { \ + high_shift = exp - DOUBLE_FRAC_BITS; \ + ret.high |= val.high << high_shift; \ + ret.high |= val.low >> (32 - high_shift); \ + ret.low = val.low << high_shift; \ + } else { \ + high_shift = DOUBLE_FRAC_BITS - exp; \ + ret.high |= val.high >> high_shift; \ + ret.low = val.high << (32 - high_shift); \ + ret.low |= val.low >> high_shift; \ + } \ + } else { \ + ret.high = 0; \ + ret.low = 1 << exp; \ + if (exp > DOUBLE_FRAC_BITS - 32) { \ + high_shift = exp - DOUBLE_FRAC_BITS - 32; \ + ret.low |= val.high << high_shift; \ + ret.low |= val.low >> (32 - high_shift); \ + } else \ + ret.low |= val.high >> (DOUBLE_FRAC_BITS - 32 - exp); \ + } \ + \ + /* encode negative integer using 2's complement */ \ + if (with_sign && sign) { \ + ret.low = ~ret.low; \ + ret.high = ~ret.high; \ + if (ret.low == UINT_MAX) { \ + ret.low = 0; \ + ret.high++; \ + } else \ + ret.low++; \ + } \ + \ + double_unsigned_struct_return(ret); \ +} + +/* double to unsigned long long conversion */ +DEFINE__AEABI_D2XLZ(d2ulz, 0) + +/* double to long long conversion */ +DEFINE__AEABI_D2XLZ(d2lz, 1) + +/* long long to float conversion */ +#define DEFINE__AEABI_XL2F(name, with_sign) \ +unsigned __aeabi_ ## name(unsigned long long v) \ +{ \ + int s /* shift */, flb /* first lost bit */, sign = 0; \ + unsigned p = 0 /* power */, ret; \ + double_unsigned_struct val; \ + \ + /* fraction in negative float is encoded in 1's complement */ \ + if (with_sign && (v & (1ULL << 63))) { \ + sign = 1; \ + v = ~v + 1; \ + } \ + val.low = v; \ + val.high = v >> 32; \ + /* fill fraction bits */ \ + for (s = 31, p = 1 << 31; p && !(val.high & p); s--, p >>= 1); \ + if (p) { \ + ret = val.high & (p - 1); \ + if (s < FLOAT_FRAC_BITS) { \ + ret <<= FLOAT_FRAC_BITS - s; \ + ret |= val.low >> (32 - (FLOAT_FRAC_BITS - s)); \ + flb = (val.low >> (32 - (FLOAT_FRAC_BITS - s - 1))) & 1; \ + } else { \ + flb = (ret >> (s - FLOAT_FRAC_BITS - 1)) & 1; \ + ret >>= s - FLOAT_FRAC_BITS; \ + } \ + s += 32; \ + } else { \ + for (s = 31, p = 1 << 31; p && !(val.low & p); s--, p >>= 1); \ + if (p) { \ + ret = val.low & (p - 1); \ + if (s <= FLOAT_FRAC_BITS) { \ + ret <<= FLOAT_FRAC_BITS - s; \ + flb = 0; \ + } else { \ + flb = (ret >> (s - FLOAT_FRAC_BITS - 1)) & 1; \ + ret >>= s - FLOAT_FRAC_BITS; \ + } \ + } else \ + return 0; \ + } \ + if (flb) \ + ret++; \ + \ + /* fill exponent bits */ \ + ret |= (s + ONE_EXP(FLOAT)) << FLOAT_FRAC_BITS; \ + \ + /* fill sign bit */ \ + ret |= sign << 31; \ + \ + return ret; \ +} + +/* unsigned long long to float conversion */ +DEFINE__AEABI_XL2F(ul2f, 0) + +/* long long to float conversion */ +DEFINE__AEABI_XL2F(l2f, 1) + +/* long long to double conversion */ +#define __AEABI_XL2D(name, with_sign) \ +void __aeabi_ ## name(unsigned long long v) \ +{ \ + int s /* shift */, high_shift, sign = 0; \ + unsigned tmp, p = 0; \ + double_unsigned_struct val, ret; \ + \ + /* fraction in negative float is encoded in 1's complement */ \ + if (with_sign && (v & (1ULL << 63))) { \ + sign = 1; \ + v = ~v + 1; \ + } \ + val.low = v; \ + val.high = v >> 32; \ + \ + /* fill fraction bits */ \ + for (s = 31, p = 1 << 31; p && !(val.high & p); s--, p >>= 1); \ + if (p) { \ + tmp = val.high & (p - 1); \ + if (s < DOUBLE_FRAC_BITS - 32) { \ + high_shift = DOUBLE_FRAC_BITS - 32 - s; \ + ret.high = tmp << high_shift; \ + ret.high |= val.low >> (32 - high_shift); \ + ret.low = val.low << high_shift; \ + } else { \ + high_shift = s - (DOUBLE_FRAC_BITS - 32); \ + ret.high = tmp >> high_shift; \ + ret.low = tmp << (32 - high_shift); \ + ret.low |= val.low >> high_shift; \ + if ((val.low >> (high_shift - 1)) & 1) { \ + if (ret.low == UINT_MAX) { \ + ret.high++; \ + ret.low = 0; \ + } else \ + ret.low++; \ + } \ + } \ + s += 32; \ + } else { \ + for (s = 31, p = 1 << 31; p && !(val.low & p); s--, p >>= 1); \ + if (p) { \ + tmp = val.low & (p - 1); \ + if (s <= DOUBLE_FRAC_BITS - 32) { \ + high_shift = DOUBLE_FRAC_BITS - 32 - s; \ + ret.high = tmp << high_shift; \ + ret.low = 0; \ + } else { \ + high_shift = s - (DOUBLE_FRAC_BITS - 32); \ + ret.high = tmp >> high_shift; \ + ret.low = tmp << (32 - high_shift); \ + } \ + } else { \ + ret.high = ret.low = 0; \ + double_unsigned_struct_return(ret); \ + } \ + } \ + \ + /* fill exponent bits */ \ + ret.high |= (s + ONE_EXP(DOUBLE)) << (DOUBLE_FRAC_BITS - 32); \ + \ + /* fill sign bit */ \ + ret.high |= sign << 31; \ + \ + double_unsigned_struct_return(ret); \ +} + +/* unsigned long long to double conversion */ +__AEABI_XL2D(ul2d, 0) + +/* long long to double conversion */ +__AEABI_XL2D(l2d, 1) + + +/* Long long helper functions */ + +/* TODO: add error in case of den == 0 (see §4.3.1 and §4.3.2) */ + +#define define_aeabi_xdivmod_signed_type(basetype, type) \ +typedef struct type { \ + basetype quot; \ + unsigned basetype rem; \ +} type + +#define define_aeabi_xdivmod_unsigned_type(basetype, type) \ +typedef struct type { \ + basetype quot; \ + basetype rem; \ +} type + +#define AEABI_UXDIVMOD(name,type, rettype, typemacro) \ +static inline rettype aeabi_ ## name (type num, type den) \ +{ \ + rettype ret; \ + type quot = 0; \ + \ + /* Increase quotient while it is less than numerator */ \ + while (num >= den) { \ + type q = 1; \ + \ + /* Find closest power of two */ \ + while ((q << 1) * den <= num && q * den <= typemacro ## _MAX / 2) \ + q <<= 1; \ + \ + /* Compute difference between current quotient and numerator */ \ + num -= q * den; \ + quot += q; \ + } \ + ret.quot = quot; \ + ret.rem = num; \ + return ret; \ +} + +#define __AEABI_XDIVMOD(name, type, uiname, rettype, urettype, typemacro) \ +void __aeabi_ ## name(type numerator, type denominator) \ +{ \ + unsigned type num, den; \ + urettype uxdiv_ret; \ + rettype ret; \ + \ + if (numerator >= 0) \ + num = numerator; \ + else \ + num = 0 - numerator; \ + if (denominator >= 0) \ + den = denominator; \ + else \ + den = 0 - denominator; \ + uxdiv_ret = aeabi_ ## uiname(num, den); \ + /* signs differ */ \ + if ((numerator & typemacro ## _MIN) != (denominator & typemacro ## _MIN)) \ + ret.quot = 0 - uxdiv_ret.quot; \ + else \ + ret.quot = uxdiv_ret.quot; \ + if (numerator < 0) \ + ret.rem = 0 - uxdiv_ret.rem; \ + else \ + ret.rem = uxdiv_ret.rem; \ + \ + rettype ## _return(ret); \ +} + +define_aeabi_xdivmod_signed_type(long long, lldiv_t); +define_aeabi_xdivmod_unsigned_type(unsigned long long, ulldiv_t); +define_aeabi_xdivmod_signed_type(int, idiv_t); +define_aeabi_xdivmod_unsigned_type(unsigned, uidiv_t); + +REGS_RETURN(lldiv_t, lldiv_t) +REGS_RETURN(ulldiv_t, ulldiv_t) +REGS_RETURN(idiv_t, idiv_t) +REGS_RETURN(uidiv_t, uidiv_t) + +AEABI_UXDIVMOD(uldivmod, unsigned long long, ulldiv_t, ULLONG) + +__AEABI_XDIVMOD(ldivmod, long long, uldivmod, lldiv_t, ulldiv_t, LLONG) + +void __aeabi_uldivmod(unsigned long long num, unsigned long long den) +{ + ulldiv_t_return(aeabi_uldivmod(num, den)); +} + +void __aeabi_llsl(double_unsigned_struct val, int shift) +{ + double_unsigned_struct ret; + + if (shift >= 32) { + val.high = val.low; + val.low = 0; + shift -= 32; + } + if (shift > 0) { + ret.low = val.low << shift; + ret.high = (val.high << shift) | (val.low >> (32 - shift)); + double_unsigned_struct_return(ret); + return; + } + double_unsigned_struct_return(val); +} + +#define aeabi_lsr(val, shift, fill, type) \ + type ## _struct ret; \ + \ + if (shift >= 32) { \ + val.low = val.high; \ + val.high = fill; \ + shift -= 32; \ + } \ + if (shift > 0) { \ + ret.high = val.high >> shift; \ + ret.low = (val.high << (32 - shift)) | (val.low >> shift); \ + type ## _struct_return(ret); \ + return; \ + } \ + type ## _struct_return(val); + +void __aeabi_llsr(double_unsigned_struct val, int shift) +{ + aeabi_lsr(val, shift, 0, double_unsigned); +} + +void __aeabi_lasr(unsigned_int_struct val, int shift) +{ + aeabi_lsr(val, shift, val.high >> 31, unsigned_int); +} + + +/* Integer division functions */ + +AEABI_UXDIVMOD(uidivmod, unsigned, uidiv_t, UINT) + +int __aeabi_idiv(int numerator, int denominator) +{ + unsigned num, den; + uidiv_t ret; + + if (numerator >= 0) + num = numerator; + else + num = 0 - numerator; + if (denominator >= 0) + den = denominator; + else + den = 0 - denominator; + ret = aeabi_uidivmod(num, den); + if ((numerator & INT_MIN) != (denominator & INT_MIN)) /* signs differ */ + ret.quot *= -1; + return ret.quot; +} + +unsigned __aeabi_uidiv(unsigned num, unsigned den) +{ + return aeabi_uidivmod(num, den).quot; +} + +__AEABI_XDIVMOD(idivmod, int, uidivmod, idiv_t, uidiv_t, INT) + +void __aeabi_uidivmod(unsigned num, unsigned den) +{ + uidiv_t_return(aeabi_uidivmod(num, den)); +} diff --git a/tinyc/lib/armflush.c b/tinyc/lib/armflush.c new file mode 100644 index 000000000..eae32605f --- /dev/null +++ b/tinyc/lib/armflush.c @@ -0,0 +1,58 @@ +/* armflush.c - flush the instruction cache + + __clear_cache is used in tccrun.c, It is a built-in + intrinsic with gcc. However tcc in order to compile + itself needs this function */ + +#ifdef __TINYC__ + +/* syscall wrapper */ +unsigned syscall(unsigned syscall_nr, ...); + +/* arm-tcc supports only fake asm currently */ +__asm__( + ".global syscall\n" + "syscall:\n" + ".int 0xe92d4080\n" // push {r7, lr} + ".int 0xe1a07000\n" // mov r7, r0 + ".int 0xe1a00001\n" // mov r0, r1 + ".int 0xe1a01002\n" // mov r1, r2 + ".int 0xe1a02003\n" // mov r2, r3 + ".int 0xef000000\n" // svc 0x00000000 + ".int 0xe8bd8080\n" // pop {r7, pc} + ); + +/* from unistd.h: */ +#if defined(__thumb__) || defined(__ARM_EABI__) +# define __NR_SYSCALL_BASE 0x0 +#else +# define __NR_SYSCALL_BASE 0x900000 +#endif +#define __ARM_NR_BASE (__NR_SYSCALL_BASE+0x0f0000) +#define __ARM_NR_cacheflush (__ARM_NR_BASE+2) + +#else + +#define _GNU_SOURCE +#include +#include +#include + +#endif + +/* Flushing for tccrun */ +void __clear_cache(void *beginning, void *end) +{ +/* __ARM_NR_cacheflush is kernel private and should not be used in user space. + * However, there is no ARM asm parser in tcc so we use it for now */ +#if 1 + syscall(__ARM_NR_cacheflush, beginning, end, 0); +#else + __asm__ ("push {r7}\n\t" + "mov r7, #0xf0002\n\t" + "mov r2, #0\n\t" + "swi 0\n\t" + "pop {r7}\n\t" + "ret"); +#endif +} diff --git a/tinyc/lib/bcheck.c b/tinyc/lib/bcheck.c new file mode 100644 index 000000000..90f0ad2c3 --- /dev/null +++ b/tinyc/lib/bcheck.c @@ -0,0 +1,979 @@ +/* + * Tiny C Memory and bounds checker + * + * Copyright (c) 2002 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include +#include +#include + +#if !defined(__FreeBSD__) \ + && !defined(__FreeBSD_kernel__) \ + && !defined(__DragonFly__) \ + && !defined(__OpenBSD__) \ + && !defined(__NetBSD__) +#include +#endif + +#if !defined(_WIN32) +#include +#endif + +/* #define BOUND_DEBUG */ + +#ifdef BOUND_DEBUG + #define dprintf(a...) fprintf(a) +#else + #define dprintf(a...) +#endif + +/* define so that bound array is static (faster, but use memory if + bound checking not used) */ +/* #define BOUND_STATIC */ + +/* use malloc hooks. Currently the code cannot be reliable if no hooks */ +#define CONFIG_TCC_MALLOC_HOOKS +#define HAVE_MEMALIGN + +#if defined(__FreeBSD__) \ + || defined(__FreeBSD_kernel__) \ + || defined(__DragonFly__) \ + || defined(__OpenBSD__) \ + || defined(__NetBSD__) \ + || defined(__dietlibc__) \ + || defined(_WIN32) +//#warning Bound checking does not support malloc (etc.) in this environment. +#undef CONFIG_TCC_MALLOC_HOOKS +#undef HAVE_MEMALIGN +#endif + +#define BOUND_T1_BITS 13 +#define BOUND_T2_BITS 11 +#define BOUND_T3_BITS (sizeof(size_t)*8 - BOUND_T1_BITS - BOUND_T2_BITS) +#define BOUND_E_BITS (sizeof(size_t)) + +#define BOUND_T1_SIZE ((size_t)1 << BOUND_T1_BITS) +#define BOUND_T2_SIZE ((size_t)1 << BOUND_T2_BITS) +#define BOUND_T3_SIZE ((size_t)1 << BOUND_T3_BITS) + +#define BOUND_T23_BITS (BOUND_T2_BITS + BOUND_T3_BITS) +#define BOUND_T23_SIZE ((size_t)1 << BOUND_T23_BITS) + + +/* this pointer is generated when bound check is incorrect */ +#define INVALID_POINTER ((void *)(-2)) +/* size of an empty region */ +#define EMPTY_SIZE ((size_t)(-1)) +/* size of an invalid region */ +#define INVALID_SIZE 0 + +typedef struct BoundEntry { + size_t start; + size_t size; + struct BoundEntry *next; + size_t is_invalid; /* true if pointers outside region are invalid */ +} BoundEntry; + +/* external interface */ +void __bound_init(void); +void __bound_new_region(void *p, size_t size); +int __bound_delete_region(void *p); + +#ifdef __attribute__ + /* an __attribute__ macro is defined in the system headers */ + #undef __attribute__ +#endif +#define FASTCALL __attribute__((regparm(3))) + +void *__bound_malloc(size_t size, const void *caller); +void *__bound_memalign(size_t size, size_t align, const void *caller); +void __bound_free(void *ptr, const void *caller); +void *__bound_realloc(void *ptr, size_t size, const void *caller); +static void *libc_malloc(size_t size); +static void libc_free(void *ptr); +static void install_malloc_hooks(void); +static void restore_malloc_hooks(void); + +#ifdef CONFIG_TCC_MALLOC_HOOKS +static void *saved_malloc_hook; +static void *saved_free_hook; +static void *saved_realloc_hook; +static void *saved_memalign_hook; +#endif + +/* TCC definitions */ +extern char __bounds_start; /* start of static bounds table */ +/* error message, just for TCC */ +const char *__bound_error_msg; + +/* runtime error output */ +extern void rt_error(size_t pc, const char *fmt, ...); + +#ifdef BOUND_STATIC +static BoundEntry *__bound_t1[BOUND_T1_SIZE]; /* page table */ +#else +static BoundEntry **__bound_t1; /* page table */ +#endif +static BoundEntry *__bound_empty_t2; /* empty page, for unused pages */ +static BoundEntry *__bound_invalid_t2; /* invalid page, for invalid pointers */ + +static BoundEntry *__bound_find_region(BoundEntry *e1, void *p) +{ + size_t addr, tmp; + BoundEntry *e; + + e = e1; + while (e != NULL) { + addr = (size_t)p; + addr -= e->start; + if (addr <= e->size) { + /* put region at the head */ + tmp = e1->start; + e1->start = e->start; + e->start = tmp; + tmp = e1->size; + e1->size = e->size; + e->size = tmp; + return e1; + } + e = e->next; + } + /* no entry found: return empty entry or invalid entry */ + if (e1->is_invalid) + return __bound_invalid_t2; + else + return __bound_empty_t2; +} + +/* print a bound error message */ +static void bound_error(const char *fmt, ...) +{ + __bound_error_msg = fmt; + fprintf(stderr,"%s %s: %s\n", __FILE__, __FUNCTION__, fmt); + *(void **)0 = 0; /* force a runtime error */ +} + +static void bound_alloc_error(void) +{ + bound_error("not enough memory for bound checking code"); +} + +/* return '(p + offset)' for pointer arithmetic (a pointer can reach + the end of a region in this case */ +void * FASTCALL __bound_ptr_add(void *p, size_t offset) +{ + size_t addr = (size_t)p; + BoundEntry *e; + + dprintf(stderr, "%s %s: %p %x\n", + __FILE__, __FUNCTION__, p, (unsigned)offset); + + __bound_init(); + + e = __bound_t1[addr >> (BOUND_T2_BITS + BOUND_T3_BITS)]; + e = (BoundEntry *)((char *)e + + ((addr >> (BOUND_T3_BITS - BOUND_E_BITS)) & + ((BOUND_T2_SIZE - 1) << BOUND_E_BITS))); + addr -= e->start; + if (addr > e->size) { + e = __bound_find_region(e, p); + addr = (size_t)p - e->start; + } + addr += offset; + if (addr >= e->size) { + fprintf(stderr,"%s %s: %p is outside of the region\n", + __FILE__, __FUNCTION__, p + offset); + return INVALID_POINTER; /* return an invalid pointer */ + } + return p + offset; +} + +/* return '(p + offset)' for pointer indirection (the resulting must + be strictly inside the region */ +#define BOUND_PTR_INDIR(dsize) \ +void * FASTCALL __bound_ptr_indir ## dsize (void *p, size_t offset) \ +{ \ + size_t addr = (size_t)p; \ + BoundEntry *e; \ + \ + dprintf(stderr, "%s %s: %p %x start\n", \ + __FILE__, __FUNCTION__, p, (unsigned)offset); \ + \ + __bound_init(); \ + e = __bound_t1[addr >> (BOUND_T2_BITS + BOUND_T3_BITS)]; \ + e = (BoundEntry *)((char *)e + \ + ((addr >> (BOUND_T3_BITS - BOUND_E_BITS)) & \ + ((BOUND_T2_SIZE - 1) << BOUND_E_BITS))); \ + addr -= e->start; \ + if (addr > e->size) { \ + e = __bound_find_region(e, p); \ + addr = (size_t)p - e->start; \ + } \ + addr += offset + dsize; \ + if (addr > e->size) { \ + fprintf(stderr,"%s %s: %p is outside of the region\n", \ + __FILE__, __FUNCTION__, p + offset); \ + return INVALID_POINTER; /* return an invalid pointer */ \ + } \ + dprintf(stderr, "%s %s: return p+offset = %p\n", \ + __FILE__, __FUNCTION__, p + offset); \ + return p + offset; \ +} + +BOUND_PTR_INDIR(1) +BOUND_PTR_INDIR(2) +BOUND_PTR_INDIR(4) +BOUND_PTR_INDIR(8) +BOUND_PTR_INDIR(12) +BOUND_PTR_INDIR(16) + +#if defined(__GNUC__) && (__GNUC__ >= 6) +/* + * At least gcc 6.2 complains when __builtin_frame_address is used with + * nonzero argument. + */ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wframe-address" +#endif + +/* return the frame pointer of the caller */ +#define GET_CALLER_FP(fp)\ +{\ + fp = (size_t)__builtin_frame_address(1);\ +} + +/* called when entering a function to add all the local regions */ +void FASTCALL __bound_local_new(void *p1) +{ + size_t addr, size, fp, *p = p1; + + dprintf(stderr, "%s, %s start p1=%p\n", __FILE__, __FUNCTION__, p); + GET_CALLER_FP(fp); + for(;;) { + addr = p[0]; + if (addr == 0) + break; + addr += fp; + size = p[1]; + p += 2; + __bound_new_region((void *)addr, size); + } + dprintf(stderr, "%s, %s end\n", __FILE__, __FUNCTION__); +} + +/* called when leaving a function to delete all the local regions */ +void FASTCALL __bound_local_delete(void *p1) +{ + size_t addr, fp, *p = p1; + GET_CALLER_FP(fp); + for(;;) { + addr = p[0]; + if (addr == 0) + break; + addr += fp; + p += 2; + __bound_delete_region((void *)addr); + } +} + +#if defined(__GNUC__) && (__GNUC__ >= 6) +#pragma GCC diagnostic pop +#endif + +static BoundEntry *__bound_new_page(void) +{ + BoundEntry *page; + size_t i; + + page = libc_malloc(sizeof(BoundEntry) * BOUND_T2_SIZE); + if (!page) + bound_alloc_error(); + for(i=0;i> BOUND_T3_BITS; + if (end != 0) + t2_end = end >> BOUND_T3_BITS; + else + t2_end = 1 << (BOUND_T1_BITS + BOUND_T2_BITS); + +#if 0 + dprintf(stderr, "mark_invalid: start = %x %x\n", t2_start, t2_end); +#endif + + /* first we handle full pages */ + t1_start = (t2_start + BOUND_T2_SIZE - 1) >> BOUND_T2_BITS; + t1_end = t2_end >> BOUND_T2_BITS; + + i = t2_start & (BOUND_T2_SIZE - 1); + j = t2_end & (BOUND_T2_SIZE - 1); + + if (t1_start == t1_end) { + page = get_page(t2_start >> BOUND_T2_BITS); + for(; i < j; i++) { + page[i].size = INVALID_SIZE; + page[i].is_invalid = 1; + } + } else { + if (i > 0) { + page = get_page(t2_start >> BOUND_T2_BITS); + for(; i < BOUND_T2_SIZE; i++) { + page[i].size = INVALID_SIZE; + page[i].is_invalid = 1; + } + } + for(i = t1_start; i < t1_end; i++) { + __bound_t1[i] = __bound_invalid_t2; + } + if (j != 0) { + page = get_page(t1_end); + for(i = 0; i < j; i++) { + page[i].size = INVALID_SIZE; + page[i].is_invalid = 1; + } + } + } +} + +void __bound_init(void) +{ + size_t i; + BoundEntry *page; + size_t start, size; + size_t *p; + + static int inited; + if (inited) + return; + + inited = 1; + + dprintf(stderr, "%s, %s() start\n", __FILE__, __FUNCTION__); + + /* save malloc hooks and install bound check hooks */ + install_malloc_hooks(); + +#ifndef BOUND_STATIC + __bound_t1 = libc_malloc(BOUND_T1_SIZE * sizeof(BoundEntry *)); + if (!__bound_t1) + bound_alloc_error(); +#endif + __bound_empty_t2 = __bound_new_page(); + for(i=0;i= v3.3, the alternative is to read + * start_brk from /proc/self/stat + */ + start = (size_t)sbrk(0); + size = 128 * 0x100000; + mark_invalid(start, size); +#endif + + /* add all static bound check values */ + p = (size_t *)&__bounds_start; + while (p[0] != 0) { + __bound_new_region((void *)p[0], p[1]); + p += 2; + } + + dprintf(stderr, "%s, %s() end\n\n", __FILE__, __FUNCTION__); +} + +void __bound_main_arg(void **p) +{ + void *start = p; + while (*p++); + + dprintf(stderr, "%s, %s calling __bound_new_region(%p %x)\n", + __FILE__, __FUNCTION__, start, (unsigned)((void *)p - start)); + + __bound_new_region(start, (void *) p - start); +} + +void __bound_exit(void) +{ + dprintf(stderr, "%s, %s()\n", __FILE__, __FUNCTION__); + restore_malloc_hooks(); +} + +static inline void add_region(BoundEntry *e, + size_t start, size_t size) +{ + BoundEntry *e1; + if (e->start == 0) { + /* no region : add it */ + e->start = start; + e->size = size; + } else { + /* already regions in the list: add it at the head */ + e1 = bound_new_entry(); + e1->start = e->start; + e1->size = e->size; + e1->next = e->next; + e->start = start; + e->size = size; + e->next = e1; + } +} + +/* create a new region. It should not already exist in the region list */ +void __bound_new_region(void *p, size_t size) +{ + size_t start, end; + BoundEntry *page, *e, *e2; + size_t t1_start, t1_end, i, t2_start, t2_end; + + dprintf(stderr, "%s, %s(%p, %x) start\n", + __FILE__, __FUNCTION__, p, (unsigned)size); + + __bound_init(); + + start = (size_t)p; + end = start + size; + t1_start = start >> (BOUND_T2_BITS + BOUND_T3_BITS); + t1_end = end >> (BOUND_T2_BITS + BOUND_T3_BITS); + + /* start */ + page = get_page(t1_start); + t2_start = (start >> (BOUND_T3_BITS - BOUND_E_BITS)) & + ((BOUND_T2_SIZE - 1) << BOUND_E_BITS); + t2_end = (end >> (BOUND_T3_BITS - BOUND_E_BITS)) & + ((BOUND_T2_SIZE - 1) << BOUND_E_BITS); + + + e = (BoundEntry *)((char *)page + t2_start); + add_region(e, start, size); + + if (t1_end == t1_start) { + /* same ending page */ + e2 = (BoundEntry *)((char *)page + t2_end); + if (e2 > e) { + e++; + for(;estart = start; + e->size = size; + } + add_region(e, start, size); + } + } else { + /* mark until end of page */ + e2 = page + BOUND_T2_SIZE; + e++; + for(;estart = start; + e->size = size; + } + /* mark intermediate pages, if any */ + for(i=t1_start+1;istart = start; + e->size = size; + } + } + /* last page */ + page = get_page(t1_end); + e2 = (BoundEntry *)((char *)page + t2_end); + for(e=page;estart = start; + e->size = size; + } + add_region(e, start, size); + } + + dprintf(stderr, "%s, %s end\n", __FILE__, __FUNCTION__); +} + +/* delete a region */ +static inline void delete_region(BoundEntry *e, void *p, size_t empty_size) +{ + size_t addr; + BoundEntry *e1; + + addr = (size_t)p; + addr -= e->start; + if (addr <= e->size) { + /* region found is first one */ + e1 = e->next; + if (e1 == NULL) { + /* no more region: mark it empty */ + e->start = 0; + e->size = empty_size; + } else { + /* copy next region in head */ + e->start = e1->start; + e->size = e1->size; + e->next = e1->next; + bound_free_entry(e1); + } + } else { + /* find the matching region */ + for(;;) { + e1 = e; + e = e->next; + /* region not found: do nothing */ + if (e == NULL) + break; + addr = (size_t)p - e->start; + if (addr <= e->size) { + /* found: remove entry */ + e1->next = e->next; + bound_free_entry(e); + break; + } + } + } +} + +/* WARNING: 'p' must be the starting point of the region. */ +/* return non zero if error */ +int __bound_delete_region(void *p) +{ + size_t start, end, addr, size, empty_size; + BoundEntry *page, *e, *e2; + size_t t1_start, t1_end, t2_start, t2_end, i; + + dprintf(stderr, "%s %s() start\n", __FILE__, __FUNCTION__); + + __bound_init(); + + start = (size_t)p; + t1_start = start >> (BOUND_T2_BITS + BOUND_T3_BITS); + t2_start = (start >> (BOUND_T3_BITS - BOUND_E_BITS)) & + ((BOUND_T2_SIZE - 1) << BOUND_E_BITS); + + /* find region size */ + page = __bound_t1[t1_start]; + e = (BoundEntry *)((char *)page + t2_start); + addr = start - e->start; + if (addr > e->size) + e = __bound_find_region(e, p); + /* test if invalid region */ + if (e->size == EMPTY_SIZE || (size_t)p != e->start) + return -1; + /* compute the size we put in invalid regions */ + if (e->is_invalid) + empty_size = INVALID_SIZE; + else + empty_size = EMPTY_SIZE; + size = e->size; + end = start + size; + + /* now we can free each entry */ + t1_end = end >> (BOUND_T2_BITS + BOUND_T3_BITS); + t2_end = (end >> (BOUND_T3_BITS - BOUND_E_BITS)) & + ((BOUND_T2_SIZE - 1) << BOUND_E_BITS); + + delete_region(e, p, empty_size); + if (t1_end == t1_start) { + /* same ending page */ + e2 = (BoundEntry *)((char *)page + t2_end); + if (e2 > e) { + e++; + for(;estart = 0; + e->size = empty_size; + } + delete_region(e, p, empty_size); + } + } else { + /* mark until end of page */ + e2 = page + BOUND_T2_SIZE; + e++; + for(;estart = 0; + e->size = empty_size; + } + /* mark intermediate pages, if any */ + /* XXX: should free them */ + for(i=t1_start+1;istart = 0; + e->size = empty_size; + } + } + /* last page */ + page = get_page(t1_end); + e2 = (BoundEntry *)((char *)page + t2_end); + for(e=page;estart = 0; + e->size = empty_size; + } + delete_region(e, p, empty_size); + } + + dprintf(stderr, "%s %s() end\n", __FILE__, __FUNCTION__); + + return 0; +} + +/* return the size of the region starting at p, or EMPTY_SIZE if non + existent region. */ +static size_t get_region_size(void *p) +{ + size_t addr = (size_t)p; + BoundEntry *e; + + e = __bound_t1[addr >> (BOUND_T2_BITS + BOUND_T3_BITS)]; + e = (BoundEntry *)((char *)e + + ((addr >> (BOUND_T3_BITS - BOUND_E_BITS)) & + ((BOUND_T2_SIZE - 1) << BOUND_E_BITS))); + addr -= e->start; + if (addr > e->size) + e = __bound_find_region(e, p); + if (e->start != (size_t)p) + return EMPTY_SIZE; + return e->size; +} + +/* patched memory functions */ + +/* force compiler to perform stores coded up to this point */ +#define barrier() __asm__ __volatile__ ("": : : "memory") + +static void install_malloc_hooks(void) +{ +#ifdef CONFIG_TCC_MALLOC_HOOKS + saved_malloc_hook = __malloc_hook; + saved_free_hook = __free_hook; + saved_realloc_hook = __realloc_hook; + saved_memalign_hook = __memalign_hook; + __malloc_hook = __bound_malloc; + __free_hook = __bound_free; + __realloc_hook = __bound_realloc; + __memalign_hook = __bound_memalign; + + barrier(); +#endif +} + +static void restore_malloc_hooks(void) +{ +#ifdef CONFIG_TCC_MALLOC_HOOKS + __malloc_hook = saved_malloc_hook; + __free_hook = saved_free_hook; + __realloc_hook = saved_realloc_hook; + __memalign_hook = saved_memalign_hook; + + barrier(); +#endif +} + +static void *libc_malloc(size_t size) +{ + void *ptr; + restore_malloc_hooks(); + ptr = malloc(size); + install_malloc_hooks(); + return ptr; +} + +static void libc_free(void *ptr) +{ + restore_malloc_hooks(); + free(ptr); + install_malloc_hooks(); +} + +/* XXX: we should use a malloc which ensure that it is unlikely that + two malloc'ed data have the same address if 'free' are made in + between. */ +void *__bound_malloc(size_t size, const void *caller) +{ + void *ptr; + + /* we allocate one more byte to ensure the regions will be + separated by at least one byte. With the glibc malloc, it may + be in fact not necessary */ + ptr = libc_malloc(size + 1); + + if (!ptr) + return NULL; + + dprintf(stderr, "%s, %s calling __bound_new_region(%p, %x)\n", + __FILE__, __FUNCTION__, ptr, (unsigned)size); + + __bound_new_region(ptr, size); + return ptr; +} + +void *__bound_memalign(size_t size, size_t align, const void *caller) +{ + void *ptr; + + restore_malloc_hooks(); + +#ifndef HAVE_MEMALIGN + if (align > 4) { + /* XXX: handle it ? */ + ptr = NULL; + } else { + /* we suppose that malloc aligns to at least four bytes */ + ptr = malloc(size + 1); + } +#else + /* we allocate one more byte to ensure the regions will be + separated by at least one byte. With the glibc malloc, it may + be in fact not necessary */ + ptr = memalign(size + 1, align); +#endif + + install_malloc_hooks(); + + if (!ptr) + return NULL; + + dprintf(stderr, "%s, %s calling __bound_new_region(%p, %x)\n", + __FILE__, __FUNCTION__, ptr, (unsigned)size); + + __bound_new_region(ptr, size); + return ptr; +} + +void __bound_free(void *ptr, const void *caller) +{ + if (ptr == NULL) + return; + if (__bound_delete_region(ptr) != 0) + bound_error("freeing invalid region"); + + libc_free(ptr); +} + +void *__bound_realloc(void *ptr, size_t size, const void *caller) +{ + void *ptr1; + size_t old_size; + + if (size == 0) { + __bound_free(ptr, caller); + return NULL; + } else { + ptr1 = __bound_malloc(size, caller); + if (ptr == NULL || ptr1 == NULL) + return ptr1; + old_size = get_region_size(ptr); + if (old_size == EMPTY_SIZE) + bound_error("realloc'ing invalid pointer"); + memcpy(ptr1, ptr, old_size); + __bound_free(ptr, caller); + return ptr1; + } +} + +#ifndef CONFIG_TCC_MALLOC_HOOKS +void *__bound_calloc(size_t nmemb, size_t size) +{ + void *ptr; + size = size * nmemb; + ptr = __bound_malloc(size, NULL); + if (!ptr) + return NULL; + memset(ptr, 0, size); + return ptr; +} +#endif + +#if 0 +static void bound_dump(void) +{ + BoundEntry *page, *e; + size_t i, j; + + fprintf(stderr, "region dump:\n"); + for(i=0;isize != EMPTY_SIZE && e->start != 0) { + fprintf(stderr, "%08x:", + (i << (BOUND_T2_BITS + BOUND_T3_BITS)) + + (j << BOUND_T3_BITS)); + do { + fprintf(stderr, " %08lx:%08lx", e->start, e->start + e->size); + e = e->next; + } while (e != NULL); + fprintf(stderr, "\n"); + } + } + } +} +#endif + +/* some useful checked functions */ + +/* check that (p ... p + size - 1) lies inside 'p' region, if any */ +static void __bound_check(const void *p, size_t size) +{ + if (size == 0) + return; + p = __bound_ptr_add((void *)p, size - 1); + if (p == INVALID_POINTER) + bound_error("invalid pointer"); +} + +void *__bound_memcpy(void *dst, const void *src, size_t size) +{ + void* p; + + dprintf(stderr, "%s %s: start, dst=%p src=%p size=%x\n", + __FILE__, __FUNCTION__, dst, src, (unsigned)size); + + __bound_check(dst, size); + __bound_check(src, size); + /* check also region overlap */ + if (src >= dst && src < dst + size) + bound_error("overlapping regions in memcpy()"); + + p = memcpy(dst, src, size); + + dprintf(stderr, "%s %s: end, p=%p\n", __FILE__, __FUNCTION__, p); + return p; +} + +void *__bound_memmove(void *dst, const void *src, size_t size) +{ + __bound_check(dst, size); + __bound_check(src, size); + return memmove(dst, src, size); +} + +void *__bound_memset(void *dst, int c, size_t size) +{ + __bound_check(dst, size); + return memset(dst, c, size); +} + +/* XXX: could be optimized */ +int __bound_strlen(const char *s) +{ + const char *p; + size_t len; + + len = 0; + for(;;) { + p = __bound_ptr_indir1((char *)s, len); + if (p == INVALID_POINTER) + bound_error("bad pointer in strlen()"); + if (*p == '\0') + break; + len++; + } + return len; +} + +char *__bound_strcpy(char *dst, const char *src) +{ + size_t len; + void *p; + + dprintf(stderr, "%s %s: strcpy start, dst=%p src=%p\n", + __FILE__, __FUNCTION__, dst, src); + len = __bound_strlen(src); + p = __bound_memcpy(dst, src, len + 1); + dprintf(stderr, "%s %s: strcpy end, p = %p\n", + __FILE__, __FUNCTION__, p); + return p; +} diff --git a/tinyc/lib/lib-arm64.c b/tinyc/lib/lib-arm64.c new file mode 100644 index 000000000..b8fd9e85a --- /dev/null +++ b/tinyc/lib/lib-arm64.c @@ -0,0 +1,664 @@ +/* + * TCC runtime library for arm64. + * + * Copyright (c) 2015 Edmund Grimley Evans + * + * Copying and distribution of this file, with or without modification, + * are permitted in any medium without royalty provided the copyright + * notice and this notice are preserved. This file is offered as-is, + * without any warranty. + */ + +#ifdef __TINYC__ +typedef signed char int8_t; +typedef unsigned char uint8_t; +typedef short int16_t; +typedef unsigned short uint16_t; +typedef int int32_t; +typedef unsigned uint32_t; +typedef long long int64_t; +typedef unsigned long long uint64_t; +void *memcpy(void*,void*,__SIZE_TYPE__); +#else +#include +#include +#endif + +void __clear_cache(void *beg, void *end) +{ + __arm64_clear_cache(beg, end); +} + +typedef struct { + uint64_t x0, x1; +} u128_t; + +static long double f3_zero(int sgn) +{ + long double f; + u128_t x = { 0, (uint64_t)sgn << 63 }; + memcpy(&f, &x, 16); + return f; +} + +static long double f3_infinity(int sgn) +{ + long double f; + u128_t x = { 0, (uint64_t)sgn << 63 | 0x7fff000000000000 }; + memcpy(&f, &x, 16); + return f; +} + +static long double f3_NaN(void) +{ + long double f; +#if 0 + // ARM's default NaN usually has just the top fraction bit set: + u128_t x = { 0, 0x7fff800000000000 }; +#else + // GCC's library sets all fraction bits: + u128_t x = { -1, 0x7fffffffffffffff }; +#endif + memcpy(&f, &x, 16); + return f; +} + +static int fp3_convert_NaN(long double *f, int sgn, u128_t mnt) +{ + u128_t x = { mnt.x0, + mnt.x1 | 0x7fff800000000000 | (uint64_t)sgn << 63 }; + memcpy(f, &x, 16); + return 1; +} + +static int fp3_detect_NaNs(long double *f, + int a_sgn, int a_exp, u128_t a, + int b_sgn, int b_exp, u128_t b) +{ + // Detect signalling NaNs: + if (a_exp == 32767 && (a.x0 | a.x1 << 16) && !(a.x1 >> 47 & 1)) + return fp3_convert_NaN(f, a_sgn, a); + if (b_exp == 32767 && (b.x0 | b.x1 << 16) && !(b.x1 >> 47 & 1)) + return fp3_convert_NaN(f, b_sgn, b); + + // Detect quiet NaNs: + if (a_exp == 32767 && (a.x0 | a.x1 << 16)) + return fp3_convert_NaN(f, a_sgn, a); + if (b_exp == 32767 && (b.x0 | b.x1 << 16)) + return fp3_convert_NaN(f, b_sgn, b); + + return 0; +} + +static void f3_unpack(int *sgn, int32_t *exp, u128_t *mnt, long double f) +{ + u128_t x; + memcpy(&x, &f, 16); + *sgn = x.x1 >> 63; + *exp = x.x1 >> 48 & 32767; + x.x1 = x.x1 << 16 >> 16; + if (*exp) + x.x1 |= (uint64_t)1 << 48; + else + *exp = 1; + *mnt = x; +} + +static u128_t f3_normalise(int32_t *exp, u128_t mnt) +{ + int sh; + if (!(mnt.x0 | mnt.x1)) + return mnt; + if (!mnt.x1) { + mnt.x1 = mnt.x0; + mnt.x0 = 0; + *exp -= 64; + } + for (sh = 32; sh; sh >>= 1) { + if (!(mnt.x1 >> (64 - sh))) { + mnt.x1 = mnt.x1 << sh | mnt.x0 >> (64 - sh); + mnt.x0 = mnt.x0 << sh; + *exp -= sh; + } + } + return mnt; +} + +static u128_t f3_sticky_shift(int32_t sh, u128_t x) +{ + if (sh >= 128) { + x.x0 = !!(x.x0 | x.x1); + x.x1 = 0; + return x; + } + if (sh >= 64) { + x.x0 = x.x1 | !!x.x0; + x.x1 = 0; + sh -= 64; + } + if (sh > 0) { + x.x0 = x.x0 >> sh | x.x1 << (64 - sh) | !!(x.x0 << (64 - sh)); + x.x1 = x.x1 >> sh; + } + return x; +} + +static long double f3_round(int sgn, int32_t exp, u128_t x) +{ + long double f; + int error; + + if (exp > 0) { + x = f3_sticky_shift(13, x); + } + else { + x = f3_sticky_shift(14 - exp, x); + exp = 0; + } + + error = x.x0 & 3; + x.x0 = x.x0 >> 2 | x.x1 << 62; + x.x1 = x.x1 >> 2; + + if (error == 3 || ((error == 2) & (x.x0 & 1))) { + if (!++x.x0) { + ++x.x1; + if (x.x1 == (uint64_t)1 << 48) + exp = 1; + else if (x.x1 == (uint64_t)1 << 49) { + ++exp; + x.x0 = x.x0 >> 1 | x.x1 << 63; + x.x1 = x.x1 >> 1; + } + } + } + + if (exp >= 32767) + return f3_infinity(sgn); + + x.x1 = x.x1 << 16 >> 16 | (uint64_t)exp << 48 | (uint64_t)sgn << 63; + memcpy(&f, &x, 16); + return f; +} + +static long double f3_add(long double fa, long double fb, int neg) +{ + u128_t a, b, x; + int32_t a_exp, b_exp, x_exp; + int a_sgn, b_sgn, x_sgn; + long double fx; + + f3_unpack(&a_sgn, &a_exp, &a, fa); + f3_unpack(&b_sgn, &b_exp, &b, fb); + + if (fp3_detect_NaNs(&fx, a_sgn, a_exp, a, b_sgn, b_exp, b)) + return fx; + + b_sgn ^= neg; + + // Handle infinities and zeroes: + if (a_exp == 32767 && b_exp == 32767 && a_sgn != b_sgn) + return f3_NaN(); + if (a_exp == 32767) + return f3_infinity(a_sgn); + if (b_exp == 32767) + return f3_infinity(b_sgn); + if (!(a.x0 | a.x1 | b.x0 | b.x1)) + return f3_zero(a_sgn & b_sgn); + + a.x1 = a.x1 << 3 | a.x0 >> 61; + a.x0 = a.x0 << 3; + b.x1 = b.x1 << 3 | b.x0 >> 61; + b.x0 = b.x0 << 3; + + if (a_exp <= b_exp) { + a = f3_sticky_shift(b_exp - a_exp, a); + a_exp = b_exp; + } + else { + b = f3_sticky_shift(a_exp - b_exp, b); + b_exp = a_exp; + } + + x_sgn = a_sgn; + x_exp = a_exp; + if (a_sgn == b_sgn) { + x.x0 = a.x0 + b.x0; + x.x1 = a.x1 + b.x1 + (x.x0 < a.x0); + } + else { + x.x0 = a.x0 - b.x0; + x.x1 = a.x1 - b.x1 - (x.x0 > a.x0); + if (x.x1 >> 63) { + x_sgn ^= 1; + x.x0 = -x.x0; + x.x1 = -x.x1 - !!x.x0; + } + } + + if (!(x.x0 | x.x1)) + return f3_zero(0); + + x = f3_normalise(&x_exp, x); + + return f3_round(x_sgn, x_exp + 12, x); +} + +long double __addtf3(long double a, long double b) +{ + return f3_add(a, b, 0); +} + +long double __subtf3(long double a, long double b) +{ + return f3_add(a, b, 1); +} + +long double __multf3(long double fa, long double fb) +{ + u128_t a, b, x; + int32_t a_exp, b_exp, x_exp; + int a_sgn, b_sgn, x_sgn; + long double fx; + + f3_unpack(&a_sgn, &a_exp, &a, fa); + f3_unpack(&b_sgn, &b_exp, &b, fb); + + if (fp3_detect_NaNs(&fx, a_sgn, a_exp, a, b_sgn, b_exp, b)) + return fx; + + // Handle infinities and zeroes: + if ((a_exp == 32767 && !(b.x0 | b.x1)) || + (b_exp == 32767 && !(a.x0 | a.x1))) + return f3_NaN(); + if (a_exp == 32767 || b_exp == 32767) + return f3_infinity(a_sgn ^ b_sgn); + if (!(a.x0 | a.x1) || !(b.x0 | b.x1)) + return f3_zero(a_sgn ^ b_sgn); + + a = f3_normalise(&a_exp, a); + b = f3_normalise(&b_exp, b); + + x_sgn = a_sgn ^ b_sgn; + x_exp = a_exp + b_exp - 16352; + + { + // Convert to base (1 << 30), discarding bottom 6 bits, which are zero, + // so there are (32, 30, 30, 30) bits in (a3, a2, a1, a0): + uint64_t a0 = a.x0 << 28 >> 34; + uint64_t b0 = b.x0 << 28 >> 34; + uint64_t a1 = a.x0 >> 36 | a.x1 << 62 >> 34; + uint64_t b1 = b.x0 >> 36 | b.x1 << 62 >> 34; + uint64_t a2 = a.x1 << 32 >> 34; + uint64_t b2 = b.x1 << 32 >> 34; + uint64_t a3 = a.x1 >> 32; + uint64_t b3 = b.x1 >> 32; + // Use 16 small multiplications and additions that do not overflow: + uint64_t x0 = a0 * b0; + uint64_t x1 = (x0 >> 30) + a0 * b1 + a1 * b0; + uint64_t x2 = (x1 >> 30) + a0 * b2 + a1 * b1 + a2 * b0; + uint64_t x3 = (x2 >> 30) + a0 * b3 + a1 * b2 + a2 * b1 + a3 * b0; + uint64_t x4 = (x3 >> 30) + a1 * b3 + a2 * b2 + a3 * b1; + uint64_t x5 = (x4 >> 30) + a2 * b3 + a3 * b2; + uint64_t x6 = (x5 >> 30) + a3 * b3; + // We now have (64, 30, 30, ...) bits in (x6, x5, x4, ...). + // Take the top 128 bits, setting bottom bit if any lower bits were set: + uint64_t y0 = (x5 << 34 | x4 << 34 >> 30 | x3 << 34 >> 60 | + !!(x3 << 38 | (x2 | x1 | x0) << 34)); + uint64_t y1 = x6; + // Top bit may be zero. Renormalise: + if (!(y1 >> 63)) { + y1 = y1 << 1 | y0 >> 63; + y0 = y0 << 1; + --x_exp; + } + x.x0 = y0; + x.x1 = y1; + } + + return f3_round(x_sgn, x_exp, x); +} + +long double __divtf3(long double fa, long double fb) +{ + u128_t a, b, x; + int32_t a_exp, b_exp, x_exp; + int a_sgn, b_sgn, x_sgn, i; + long double fx; + + f3_unpack(&a_sgn, &a_exp, &a, fa); + f3_unpack(&b_sgn, &b_exp, &b, fb); + + if (fp3_detect_NaNs(&fx, a_sgn, a_exp, a, b_sgn, b_exp, b)) + return fx; + + // Handle infinities and zeroes: + if ((a_exp == 32767 && b_exp == 32767) || + (!(a.x0 | a.x1) && !(b.x0 | b.x1))) + return f3_NaN(); + if (a_exp == 32767 || !(b.x0 | b.x1)) + return f3_infinity(a_sgn ^ b_sgn); + if (!(a.x0 | a.x1) || b_exp == 32767) + return f3_zero(a_sgn ^ b_sgn); + + a = f3_normalise(&a_exp, a); + b = f3_normalise(&b_exp, b); + + x_sgn = a_sgn ^ b_sgn; + x_exp = a_exp - b_exp + 16395; + + a.x0 = a.x0 >> 1 | a.x1 << 63; + a.x1 = a.x1 >> 1; + b.x0 = b.x0 >> 1 | b.x1 << 63; + b.x1 = b.x1 >> 1; + x.x0 = 0; + x.x1 = 0; + for (i = 0; i < 116; i++) { + x.x1 = x.x1 << 1 | x.x0 >> 63; + x.x0 = x.x0 << 1; + if (a.x1 > b.x1 || (a.x1 == b.x1 && a.x0 >= b.x0)) { + a.x1 = a.x1 - b.x1 - (a.x0 < b.x0); + a.x0 = a.x0 - b.x0; + x.x0 |= 1; + } + a.x1 = a.x1 << 1 | a.x0 >> 63; + a.x0 = a.x0 << 1; + } + x.x0 |= !!(a.x0 | a.x1); + + x = f3_normalise(&x_exp, x); + + return f3_round(x_sgn, x_exp, x); +} + +long double __extendsftf2(float f) +{ + long double fx; + u128_t x; + uint32_t a; + uint64_t aa; + memcpy(&a, &f, 4); + aa = a; + x.x0 = 0; + if (!(a << 1)) + x.x1 = aa << 32; + else if (a << 1 >> 24 == 255) + x.x1 = (0x7fff000000000000 | aa >> 31 << 63 | aa << 41 >> 16 | + (uint64_t)!!(a << 9) << 47); + else + x.x1 = (aa >> 31 << 63 | ((aa >> 23 & 255) + 16256) << 48 | + aa << 41 >> 16); + memcpy(&fx, &x, 16); + return fx; +} + +long double __extenddftf2(double f) +{ + long double fx; + u128_t x; + uint64_t a; + memcpy(&a, &f, 8); + x.x0 = a << 60; + if (!(a << 1)) + x.x1 = a; + else if (a << 1 >> 53 == 2047) + x.x1 = (0x7fff000000000000 | a >> 63 << 63 | a << 12 >> 16 | + (uint64_t)!!(a << 12) << 47); + else + x.x1 = a >> 63 << 63 | ((a >> 52 & 2047) + 15360) << 48 | a << 12 >> 16; + memcpy(&fx, &x, 16); + return fx; +} + +float __trunctfsf2(long double f) +{ + u128_t mnt; + int32_t exp; + int sgn; + uint32_t x; + float fx; + + f3_unpack(&sgn, &exp, &mnt, f); + + if (exp == 32767 && (mnt.x0 | mnt.x1 << 16)) + x = 0x7fc00000 | (uint32_t)sgn << 31 | (mnt.x1 >> 25 & 0x007fffff); + else if (exp > 16510) + x = 0x7f800000 | (uint32_t)sgn << 31; + else if (exp < 16233) + x = (uint32_t)sgn << 31; + else { + exp -= 16257; + x = mnt.x1 >> 23 | !!(mnt.x0 | mnt.x1 << 41); + if (exp < 0) { + x = x >> -exp | !!(x << (32 + exp)); + exp = 0; + } + if ((x & 3) == 3 || (x & 7) == 6) + x += 4; + x = ((x >> 2) + (exp << 23)) | (uint32_t)sgn << 31; + } + memcpy(&fx, &x, 4); + return fx; +} + +double __trunctfdf2(long double f) +{ + u128_t mnt; + int32_t exp; + int sgn; + uint64_t x; + double fx; + + f3_unpack(&sgn, &exp, &mnt, f); + + if (exp == 32767 && (mnt.x0 | mnt.x1 << 16)) + x = (0x7ff8000000000000 | (uint64_t)sgn << 63 | + mnt.x1 << 16 >> 12 | mnt.x0 >> 60); + else if (exp > 17406) + x = 0x7ff0000000000000 | (uint64_t)sgn << 63; + else if (exp < 15308) + x = (uint64_t)sgn << 63; + else { + exp -= 15361; + x = mnt.x1 << 6 | mnt.x0 >> 58 | !!(mnt.x0 << 6); + if (exp < 0) { + x = x >> -exp | !!(x << (64 + exp)); + exp = 0; + } + if ((x & 3) == 3 || (x & 7) == 6) + x += 4; + x = ((x >> 2) + ((uint64_t)exp << 52)) | (uint64_t)sgn << 63; + } + memcpy(&fx, &x, 8); + return fx; +} + +int32_t __fixtfsi(long double fa) +{ + u128_t a; + int32_t a_exp; + int a_sgn; + int32_t x; + f3_unpack(&a_sgn, &a_exp, &a, fa); + if (a_exp < 16369) + return 0; + if (a_exp > 16413) + return a_sgn ? -0x80000000 : 0x7fffffff; + x = a.x1 >> (16431 - a_exp); + return a_sgn ? -x : x; +} + +int64_t __fixtfdi(long double fa) +{ + u128_t a; + int32_t a_exp; + int a_sgn; + int64_t x; + f3_unpack(&a_sgn, &a_exp, &a, fa); + if (a_exp < 16383) + return 0; + if (a_exp > 16445) + return a_sgn ? -0x8000000000000000 : 0x7fffffffffffffff; + x = (a.x1 << 15 | a.x0 >> 49) >> (16446 - a_exp); + return a_sgn ? -x : x; +} + +uint32_t __fixunstfsi(long double fa) +{ + u128_t a; + int32_t a_exp; + int a_sgn; + f3_unpack(&a_sgn, &a_exp, &a, fa); + if (a_sgn || a_exp < 16369) + return 0; + if (a_exp > 16414) + return -1; + return a.x1 >> (16431 - a_exp); +} + +uint64_t __fixunstfdi(long double fa) +{ + u128_t a; + int32_t a_exp; + int a_sgn; + f3_unpack(&a_sgn, &a_exp, &a, fa); + if (a_sgn || a_exp < 16383) + return 0; + if (a_exp > 16446) + return -1; + return (a.x1 << 15 | a.x0 >> 49) >> (16446 - a_exp); +} + +long double __floatsitf(int32_t a) +{ + int sgn = 0; + int exp = 16414; + uint32_t mnt = a; + u128_t x = { 0, 0 }; + long double f; + int i; + if (a) { + if (a < 0) { + sgn = 1; + mnt = -mnt; + } + for (i = 16; i; i >>= 1) + if (!(mnt >> (32 - i))) { + mnt <<= i; + exp -= i; + } + x.x1 = ((uint64_t)sgn << 63 | (uint64_t)exp << 48 | + (uint64_t)(mnt << 1) << 16); + } + memcpy(&f, &x, 16); + return f; +} + +long double __floatditf(int64_t a) +{ + int sgn = 0; + int exp = 16446; + uint64_t mnt = a; + u128_t x = { 0, 0 }; + long double f; + int i; + if (a) { + if (a < 0) { + sgn = 1; + mnt = -mnt; + } + for (i = 32; i; i >>= 1) + if (!(mnt >> (64 - i))) { + mnt <<= i; + exp -= i; + } + x.x0 = mnt << 49; + x.x1 = (uint64_t)sgn << 63 | (uint64_t)exp << 48 | mnt << 1 >> 16; + } + memcpy(&f, &x, 16); + return f; +} + +long double __floatunsitf(uint32_t a) +{ + int exp = 16414; + uint32_t mnt = a; + u128_t x = { 0, 0 }; + long double f; + int i; + if (a) { + for (i = 16; i; i >>= 1) + if (!(mnt >> (32 - i))) { + mnt <<= i; + exp -= i; + } + x.x1 = (uint64_t)exp << 48 | (uint64_t)(mnt << 1) << 16; + } + memcpy(&f, &x, 16); + return f; +} + +long double __floatunditf(uint64_t a) +{ + int exp = 16446; + uint64_t mnt = a; + u128_t x = { 0, 0 }; + long double f; + int i; + if (a) { + for (i = 32; i; i >>= 1) + if (!(mnt >> (64 - i))) { + mnt <<= i; + exp -= i; + } + x.x0 = mnt << 49; + x.x1 = (uint64_t)exp << 48 | mnt << 1 >> 16; + } + memcpy(&f, &x, 16); + return f; +} + +static int f3_cmp(long double fa, long double fb) +{ + u128_t a, b; + memcpy(&a, &fa, 16); + memcpy(&b, &fb, 16); + return (!(a.x0 | a.x1 << 1 | b.x0 | b.x1 << 1) ? 0 : + ((a.x1 << 1 >> 49 == 0x7fff && (a.x0 | a.x1 << 16)) || + (b.x1 << 1 >> 49 == 0x7fff && (b.x0 | b.x1 << 16))) ? 2 : + a.x1 >> 63 != b.x1 >> 63 ? (int)(b.x1 >> 63) - (int)(a.x1 >> 63) : + a.x1 < b.x1 ? (int)(a.x1 >> 63 << 1) - 1 : + a.x1 > b.x1 ? 1 - (int)(a.x1 >> 63 << 1) : + a.x0 < b.x0 ? (int)(a.x1 >> 63 << 1) - 1 : + b.x0 < a.x0 ? 1 - (int)(a.x1 >> 63 << 1) : 0); +} + +int __eqtf2(long double a, long double b) +{ + return !!f3_cmp(a, b); +} + +int __netf2(long double a, long double b) +{ + return !!f3_cmp(a, b); +} + +int __lttf2(long double a, long double b) +{ + return f3_cmp(a, b); +} + +int __letf2(long double a, long double b) +{ + return f3_cmp(a, b); +} + +int __gttf2(long double a, long double b) +{ + return -f3_cmp(b, a); +} + +int __getf2(long double a, long double b) +{ + return -f3_cmp(b, a); +} diff --git a/tinyc/lib/libtcc1.c b/tinyc/lib/libtcc1.c new file mode 100644 index 000000000..0e466180c --- /dev/null +++ b/tinyc/lib/libtcc1.c @@ -0,0 +1,622 @@ +/* TCC runtime library. + Parts of this code are (c) 2002 Fabrice Bellard + + Copyright (C) 1987, 1988, 1992, 1994, 1995 Free Software Foundation, Inc. + +This file is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +In addition to the permissions in the GNU General Public License, the +Free Software Foundation gives you unlimited permission to link the +compiled version of this file into combinations with other programs, +and to distribute those combinations without any restriction coming +from the use of this file. (The General Public License restrictions +do apply in other respects; for example, they cover modification of +the file, and distribution when not linked into a combine +executable.) + +This file is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. +*/ + +#define W_TYPE_SIZE 32 +#define BITS_PER_UNIT 8 + +typedef int Wtype; +typedef unsigned int UWtype; +typedef unsigned int USItype; +typedef long long DWtype; +typedef unsigned long long UDWtype; + +struct DWstruct { + Wtype low, high; +}; + +typedef union +{ + struct DWstruct s; + DWtype ll; +} DWunion; + +typedef long double XFtype; +#define WORD_SIZE (sizeof (Wtype) * BITS_PER_UNIT) +#define HIGH_WORD_COEFF (((UDWtype) 1) << WORD_SIZE) + +/* the following deal with IEEE single-precision numbers */ +#define EXCESS 126 +#define SIGNBIT 0x80000000 +#define HIDDEN (1 << 23) +#define SIGN(fp) ((fp) & SIGNBIT) +#define EXP(fp) (((fp) >> 23) & 0xFF) +#define MANT(fp) (((fp) & 0x7FFFFF) | HIDDEN) +#define PACK(s,e,m) ((s) | ((e) << 23) | (m)) + +/* the following deal with IEEE double-precision numbers */ +#define EXCESSD 1022 +#define HIDDEND (1 << 20) +#define EXPD(fp) (((fp.l.upper) >> 20) & 0x7FF) +#define SIGND(fp) ((fp.l.upper) & SIGNBIT) +#define MANTD(fp) (((((fp.l.upper) & 0xFFFFF) | HIDDEND) << 10) | \ + (fp.l.lower >> 22)) +#define HIDDEND_LL ((long long)1 << 52) +#define MANTD_LL(fp) ((fp.ll & (HIDDEND_LL-1)) | HIDDEND_LL) +#define PACKD_LL(s,e,m) (((long long)((s)+((e)<<20))<<32)|(m)) + +/* the following deal with x86 long double-precision numbers */ +#define EXCESSLD 16382 +#define EXPLD(fp) (fp.l.upper & 0x7fff) +#define SIGNLD(fp) ((fp.l.upper) & 0x8000) + +/* only for x86 */ +union ldouble_long { + long double ld; + struct { + unsigned long long lower; + unsigned short upper; + } l; +}; + +union double_long { + double d; +#if 1 + struct { + unsigned int lower; + int upper; + } l; +#else + struct { + int upper; + unsigned int lower; + } l; +#endif + long long ll; +}; + +union float_long { + float f; + unsigned int l; +}; + +/* XXX: we don't support several builtin supports for now */ +#if !defined __x86_64__ && !defined __arm__ + +/* XXX: use gcc/tcc intrinsic ? */ +#if defined __i386__ +#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ + __asm__ ("subl %5,%1\n\tsbbl %3,%0" \ + : "=r" ((USItype) (sh)), \ + "=&r" ((USItype) (sl)) \ + : "0" ((USItype) (ah)), \ + "g" ((USItype) (bh)), \ + "1" ((USItype) (al)), \ + "g" ((USItype) (bl))) +#define umul_ppmm(w1, w0, u, v) \ + __asm__ ("mull %3" \ + : "=a" ((USItype) (w0)), \ + "=d" ((USItype) (w1)) \ + : "%0" ((USItype) (u)), \ + "rm" ((USItype) (v))) +#define udiv_qrnnd(q, r, n1, n0, dv) \ + __asm__ ("divl %4" \ + : "=a" ((USItype) (q)), \ + "=d" ((USItype) (r)) \ + : "0" ((USItype) (n0)), \ + "1" ((USItype) (n1)), \ + "rm" ((USItype) (dv))) +#define count_leading_zeros(count, x) \ + do { \ + USItype __cbtmp; \ + __asm__ ("bsrl %1,%0" \ + : "=r" (__cbtmp) : "rm" ((USItype) (x))); \ + (count) = __cbtmp ^ 31; \ + } while (0) +#else +#error unsupported CPU type +#endif + +/* most of this code is taken from libgcc2.c from gcc */ + +static UDWtype __udivmoddi4 (UDWtype n, UDWtype d, UDWtype *rp) +{ + DWunion ww; + DWunion nn, dd; + DWunion rr; + UWtype d0, d1, n0, n1, n2; + UWtype q0, q1; + UWtype b, bm; + + nn.ll = n; + dd.ll = d; + + d0 = dd.s.low; + d1 = dd.s.high; + n0 = nn.s.low; + n1 = nn.s.high; + +#if !defined(UDIV_NEEDS_NORMALIZATION) + if (d1 == 0) + { + if (d0 > n1) + { + /* 0q = nn / 0D */ + + udiv_qrnnd (q0, n0, n1, n0, d0); + q1 = 0; + + /* Remainder in n0. */ + } + else + { + /* qq = NN / 0d */ + + if (d0 == 0) + d0 = 1 / d0; /* Divide intentionally by zero. */ + + udiv_qrnnd (q1, n1, 0, n1, d0); + udiv_qrnnd (q0, n0, n1, n0, d0); + + /* Remainder in n0. */ + } + + if (rp != 0) + { + rr.s.low = n0; + rr.s.high = 0; + *rp = rr.ll; + } + } + +#else /* UDIV_NEEDS_NORMALIZATION */ + + if (d1 == 0) + { + if (d0 > n1) + { + /* 0q = nn / 0D */ + + count_leading_zeros (bm, d0); + + if (bm != 0) + { + /* Normalize, i.e. make the most significant bit of the + denominator set. */ + + d0 = d0 << bm; + n1 = (n1 << bm) | (n0 >> (W_TYPE_SIZE - bm)); + n0 = n0 << bm; + } + + udiv_qrnnd (q0, n0, n1, n0, d0); + q1 = 0; + + /* Remainder in n0 >> bm. */ + } + else + { + /* qq = NN / 0d */ + + if (d0 == 0) + d0 = 1 / d0; /* Divide intentionally by zero. */ + + count_leading_zeros (bm, d0); + + if (bm == 0) + { + /* From (n1 >= d0) /\ (the most significant bit of d0 is set), + conclude (the most significant bit of n1 is set) /\ (the + leading quotient digit q1 = 1). + + This special case is necessary, not an optimization. + (Shifts counts of W_TYPE_SIZE are undefined.) */ + + n1 -= d0; + q1 = 1; + } + else + { + /* Normalize. */ + + b = W_TYPE_SIZE - bm; + + d0 = d0 << bm; + n2 = n1 >> b; + n1 = (n1 << bm) | (n0 >> b); + n0 = n0 << bm; + + udiv_qrnnd (q1, n1, n2, n1, d0); + } + + /* n1 != d0... */ + + udiv_qrnnd (q0, n0, n1, n0, d0); + + /* Remainder in n0 >> bm. */ + } + + if (rp != 0) + { + rr.s.low = n0 >> bm; + rr.s.high = 0; + *rp = rr.ll; + } + } +#endif /* UDIV_NEEDS_NORMALIZATION */ + + else + { + if (d1 > n1) + { + /* 00 = nn / DD */ + + q0 = 0; + q1 = 0; + + /* Remainder in n1n0. */ + if (rp != 0) + { + rr.s.low = n0; + rr.s.high = n1; + *rp = rr.ll; + } + } + else + { + /* 0q = NN / dd */ + + count_leading_zeros (bm, d1); + if (bm == 0) + { + /* From (n1 >= d1) /\ (the most significant bit of d1 is set), + conclude (the most significant bit of n1 is set) /\ (the + quotient digit q0 = 0 or 1). + + This special case is necessary, not an optimization. */ + + /* The condition on the next line takes advantage of that + n1 >= d1 (true due to program flow). */ + if (n1 > d1 || n0 >= d0) + { + q0 = 1; + sub_ddmmss (n1, n0, n1, n0, d1, d0); + } + else + q0 = 0; + + q1 = 0; + + if (rp != 0) + { + rr.s.low = n0; + rr.s.high = n1; + *rp = rr.ll; + } + } + else + { + UWtype m1, m0; + /* Normalize. */ + + b = W_TYPE_SIZE - bm; + + d1 = (d1 << bm) | (d0 >> b); + d0 = d0 << bm; + n2 = n1 >> b; + n1 = (n1 << bm) | (n0 >> b); + n0 = n0 << bm; + + udiv_qrnnd (q0, n1, n2, n1, d1); + umul_ppmm (m1, m0, q0, d0); + + if (m1 > n1 || (m1 == n1 && m0 > n0)) + { + q0--; + sub_ddmmss (m1, m0, m1, m0, d1, d0); + } + + q1 = 0; + + /* Remainder in (n1n0 - m1m0) >> bm. */ + if (rp != 0) + { + sub_ddmmss (n1, n0, n1, n0, m1, m0); + rr.s.low = (n1 << b) | (n0 >> bm); + rr.s.high = n1 >> bm; + *rp = rr.ll; + } + } + } + } + + ww.s.low = q0; + ww.s.high = q1; + return ww.ll; +} + +#define __negdi2(a) (-(a)) + +long long __divdi3(long long u, long long v) +{ + int c = 0; + DWunion uu, vv; + DWtype w; + + uu.ll = u; + vv.ll = v; + + if (uu.s.high < 0) { + c = ~c; + uu.ll = __negdi2 (uu.ll); + } + if (vv.s.high < 0) { + c = ~c; + vv.ll = __negdi2 (vv.ll); + } + w = __udivmoddi4 (uu.ll, vv.ll, (UDWtype *) 0); + if (c) + w = __negdi2 (w); + return w; +} + +long long __moddi3(long long u, long long v) +{ + int c = 0; + DWunion uu, vv; + DWtype w; + + uu.ll = u; + vv.ll = v; + + if (uu.s.high < 0) { + c = ~c; + uu.ll = __negdi2 (uu.ll); + } + if (vv.s.high < 0) + vv.ll = __negdi2 (vv.ll); + + __udivmoddi4 (uu.ll, vv.ll, (UDWtype *) &w); + if (c) + w = __negdi2 (w); + return w; +} + +unsigned long long __udivdi3(unsigned long long u, unsigned long long v) +{ + return __udivmoddi4 (u, v, (UDWtype *) 0); +} + +unsigned long long __umoddi3(unsigned long long u, unsigned long long v) +{ + UDWtype w; + + __udivmoddi4 (u, v, &w); + return w; +} + +/* XXX: fix tcc's code generator to do this instead */ +long long __ashrdi3(long long a, int b) +{ +#ifdef __TINYC__ + DWunion u; + u.ll = a; + if (b >= 32) { + u.s.low = u.s.high >> (b - 32); + u.s.high = u.s.high >> 31; + } else if (b != 0) { + u.s.low = ((unsigned)u.s.low >> b) | (u.s.high << (32 - b)); + u.s.high = u.s.high >> b; + } + return u.ll; +#else + return a >> b; +#endif +} + +/* XXX: fix tcc's code generator to do this instead */ +unsigned long long __lshrdi3(unsigned long long a, int b) +{ +#ifdef __TINYC__ + DWunion u; + u.ll = a; + if (b >= 32) { + u.s.low = (unsigned)u.s.high >> (b - 32); + u.s.high = 0; + } else if (b != 0) { + u.s.low = ((unsigned)u.s.low >> b) | (u.s.high << (32 - b)); + u.s.high = (unsigned)u.s.high >> b; + } + return u.ll; +#else + return a >> b; +#endif +} + +/* XXX: fix tcc's code generator to do this instead */ +long long __ashldi3(long long a, int b) +{ +#ifdef __TINYC__ + DWunion u; + u.ll = a; + if (b >= 32) { + u.s.high = (unsigned)u.s.low << (b - 32); + u.s.low = 0; + } else if (b != 0) { + u.s.high = ((unsigned)u.s.high << b) | ((unsigned)u.s.low >> (32 - b)); + u.s.low = (unsigned)u.s.low << b; + } + return u.ll; +#else + return a << b; +#endif +} + +#endif /* !__x86_64__ */ + +/* XXX: fix tcc's code generator to do this instead */ +float __floatundisf(unsigned long long a) +{ + DWunion uu; + XFtype r; + + uu.ll = a; + if (uu.s.high >= 0) { + return (float)uu.ll; + } else { + r = (XFtype)uu.ll; + r += 18446744073709551616.0; + return (float)r; + } +} + +double __floatundidf(unsigned long long a) +{ + DWunion uu; + XFtype r; + + uu.ll = a; + if (uu.s.high >= 0) { + return (double)uu.ll; + } else { + r = (XFtype)uu.ll; + r += 18446744073709551616.0; + return (double)r; + } +} + +long double __floatundixf(unsigned long long a) +{ + DWunion uu; + XFtype r; + + uu.ll = a; + if (uu.s.high >= 0) { + return (long double)uu.ll; + } else { + r = (XFtype)uu.ll; + r += 18446744073709551616.0; + return (long double)r; + } +} + +unsigned long long __fixunssfdi (float a1) +{ + register union float_long fl1; + register int exp; + register unsigned long l; + + fl1.f = a1; + + if (fl1.l == 0) + return (0); + + exp = EXP (fl1.l) - EXCESS - 24; + + l = MANT(fl1.l); + if (exp >= 41) + return (unsigned long long)-1; + else if (exp >= 0) + return (unsigned long long)l << exp; + else if (exp >= -23) + return l >> -exp; + else + return 0; +} + +long long __fixsfdi (float a1) +{ + long long ret; int s; + ret = __fixunssfdi((s = a1 >= 0) ? a1 : -a1); + return s ? ret : -ret; +} + +unsigned long long __fixunsdfdi (double a1) +{ + register union double_long dl1; + register int exp; + register unsigned long long l; + + dl1.d = a1; + + if (dl1.ll == 0) + return (0); + + exp = EXPD (dl1) - EXCESSD - 53; + + l = MANTD_LL(dl1); + + if (exp >= 12) + return (unsigned long long)-1; + else if (exp >= 0) + return l << exp; + else if (exp >= -52) + return l >> -exp; + else + return 0; +} + +long long __fixdfdi (double a1) +{ + long long ret; int s; + ret = __fixunsdfdi((s = a1 >= 0) ? a1 : -a1); + return s ? ret : -ret; +} + +#ifndef __arm__ +unsigned long long __fixunsxfdi (long double a1) +{ + register union ldouble_long dl1; + register int exp; + register unsigned long long l; + + dl1.ld = a1; + + if (dl1.l.lower == 0 && dl1.l.upper == 0) + return (0); + + exp = EXPLD (dl1) - EXCESSLD - 64; + + l = dl1.l.lower; + + if (exp > 0) + return (unsigned long long)-1; + else if (exp >= -63) + return l >> -exp; + else + return 0; +} + +long long __fixxfdi (long double a1) +{ + long long ret; int s; + ret = __fixunsxfdi((s = a1 >= 0) ? a1 : -a1); + return s ? ret : -ret; +} +#endif /* !ARM */ diff --git a/tinyc/lib/va_list.c b/tinyc/lib/va_list.c new file mode 100644 index 000000000..8749f46f8 --- /dev/null +++ b/tinyc/lib/va_list.c @@ -0,0 +1,65 @@ +/* va_list.c - tinycc support for va_list on X86_64 */ + +#if defined __x86_64__ + +/* Avoid include files, they may not be available when cross compiling */ +extern void *memset(void *s, int c, __SIZE_TYPE__ n); +extern void abort(void); + +/* This should be in sync with our include/stdarg.h */ +enum __va_arg_type { + __va_gen_reg, __va_float_reg, __va_stack +}; + +/* GCC compatible definition of va_list. */ +typedef struct { + unsigned int gp_offset; + unsigned int fp_offset; + union { + unsigned int overflow_offset; + char *overflow_arg_area; + }; + char *reg_save_area; +} __va_list_struct; + +void __va_start(__va_list_struct *ap, void *fp) +{ + memset(ap, 0, sizeof(__va_list_struct)); + *ap = *(__va_list_struct *)((char *)fp - 16); + ap->overflow_arg_area = (char *)fp + ap->overflow_offset; + ap->reg_save_area = (char *)fp - 176 - 16; +} + +void *__va_arg(__va_list_struct *ap, + enum __va_arg_type arg_type, + int size, int align) +{ + size = (size + 7) & ~7; + align = (align + 7) & ~7; + switch (arg_type) { + case __va_gen_reg: + if (ap->gp_offset + size <= 48) { + ap->gp_offset += size; + return ap->reg_save_area + ap->gp_offset - size; + } + goto use_overflow_area; + + case __va_float_reg: + if (ap->fp_offset < 128 + 48) { + ap->fp_offset += 16; + return ap->reg_save_area + ap->fp_offset - 16; + } + size = 8; + goto use_overflow_area; + + case __va_stack: + use_overflow_area: + ap->overflow_arg_area += size; + ap->overflow_arg_area = (char*)((long long)(ap->overflow_arg_area + align - 1) & -align); + return ap->overflow_arg_area - size; + + default: /* should never happen */ + abort(); + } +} +#endif diff --git a/tinyc/libtcc.c b/tinyc/libtcc.c new file mode 100644 index 000000000..092c0ba32 --- /dev/null +++ b/tinyc/libtcc.c @@ -0,0 +1,1982 @@ +/* + * TCC - Tiny C Compiler + * + * Copyright (c) 2001-2004 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "tcc.h" + +/********************************************************/ +/* global variables */ + +/* use GNU C extensions */ +ST_DATA int gnu_ext = 1; + +/* use TinyCC extensions */ +ST_DATA int tcc_ext = 1; + +/* XXX: get rid of this ASAP */ +ST_DATA struct TCCState *tcc_state; + +static int nb_states; + +/********************************************************/ + +#if ONE_SOURCE +#include "tccpp.c" +#include "tccgen.c" +#include "tccelf.c" +#include "tccrun.c" +#ifdef TCC_TARGET_I386 +#include "i386-gen.c" +#include "i386-link.c" +#include "i386-asm.c" +#endif +#ifdef TCC_TARGET_ARM +#include "arm-gen.c" +#include "arm-link.c" +#include "arm-asm.c" +#endif +#ifdef TCC_TARGET_ARM64 +#include "arm64-gen.c" +#include "arm64-link.c" +#endif +#ifdef TCC_TARGET_C67 +#include "c67-gen.c" +#include "c67-link.c" +#include "tcccoff.c" +#endif +#ifdef TCC_TARGET_X86_64 +#include "x86_64-gen.c" +#include "x86_64-link.c" +#include "i386-asm.c" +#endif +#ifdef CONFIG_TCC_ASM +#include "tccasm.c" +#endif +#ifdef TCC_TARGET_PE +#include "tccpe.c" +#endif +#endif /* ONE_SOURCE */ + +/********************************************************/ +#ifndef CONFIG_TCC_ASM +ST_FUNC void asm_instr(void) +{ + tcc_error("inline asm() not supported"); +} +ST_FUNC void asm_global_instr(void) +{ + tcc_error("inline asm() not supported"); +} +#endif + +/********************************************************/ +#ifdef _WIN32 +ST_FUNC char *normalize_slashes(char *path) +{ + char *p; + for (p = path; *p; ++p) + if (*p == '\\') + *p = '/'; + return path; +} + +static HMODULE tcc_module; + +/* on win32, we suppose the lib and includes are at the location of 'tcc.exe' */ +static void tcc_set_lib_path_w32(TCCState *s) +{ + char path[1024], *p; + GetModuleFileNameA(tcc_module, path, sizeof path); + p = tcc_basename(normalize_slashes(strlwr(path))); + if (p > path) + --p; + *p = 0; + tcc_set_lib_path(s, path); +} + +#ifdef TCC_TARGET_PE +static void tcc_add_systemdir(TCCState *s) +{ + char buf[1000]; + GetSystemDirectory(buf, sizeof buf); + tcc_add_library_path(s, normalize_slashes(buf)); +} +#endif + +#ifdef LIBTCC_AS_DLL +BOOL WINAPI DllMain (HINSTANCE hDll, DWORD dwReason, LPVOID lpReserved) +{ + if (DLL_PROCESS_ATTACH == dwReason) + tcc_module = hDll; + return TRUE; +} +#endif +#endif + +/********************************************************/ +/* copy a string and truncate it. */ +ST_FUNC char *pstrcpy(char *buf, int buf_size, const char *s) +{ + char *q, *q_end; + int c; + + if (buf_size > 0) { + q = buf; + q_end = buf + buf_size - 1; + while (q < q_end) { + c = *s++; + if (c == '\0') + break; + *q++ = c; + } + *q = '\0'; + } + return buf; +} + +/* strcat and truncate. */ +ST_FUNC char *pstrcat(char *buf, int buf_size, const char *s) +{ + int len; + len = strlen(buf); + if (len < buf_size) + pstrcpy(buf + len, buf_size - len, s); + return buf; +} + +ST_FUNC char *pstrncpy(char *out, const char *in, size_t num) +{ + memcpy(out, in, num); + out[num] = '\0'; + return out; +} + +/* extract the basename of a file */ +PUB_FUNC char *tcc_basename(const char *name) +{ + char *p = strchr(name, 0); + while (p > name && !IS_DIRSEP(p[-1])) + --p; + return p; +} + +/* extract extension part of a file + * + * (if no extension, return pointer to end-of-string) + */ +PUB_FUNC char *tcc_fileextension (const char *name) +{ + char *b = tcc_basename(name); + char *e = strrchr(b, '.'); + return e ? e : strchr(b, 0); +} + +/********************************************************/ +/* memory management */ + +#undef free +#undef malloc +#undef realloc + +#ifndef MEM_DEBUG + +PUB_FUNC void tcc_free(void *ptr) +{ + free(ptr); +} + +PUB_FUNC void *tcc_malloc(unsigned long size) +{ + void *ptr; + ptr = malloc(size); + if (!ptr && size) + tcc_error("memory full (malloc)"); + return ptr; +} + +PUB_FUNC void *tcc_mallocz(unsigned long size) +{ + void *ptr; + ptr = tcc_malloc(size); + memset(ptr, 0, size); + return ptr; +} + +PUB_FUNC void *tcc_realloc(void *ptr, unsigned long size) +{ + void *ptr1; + ptr1 = realloc(ptr, size); + if (!ptr1 && size) + tcc_error("memory full (realloc)"); + return ptr1; +} + +PUB_FUNC char *tcc_strdup(const char *str) +{ + char *ptr; + ptr = tcc_malloc(strlen(str) + 1); + strcpy(ptr, str); + return ptr; +} + +PUB_FUNC void tcc_memcheck(void) +{ +} + +#else + +#define MEM_DEBUG_MAGIC1 0xFEEDDEB1 +#define MEM_DEBUG_MAGIC2 0xFEEDDEB2 +#define MEM_DEBUG_MAGIC3 0xFEEDDEB3 +#define MEM_DEBUG_FILE_LEN 40 +#define MEM_DEBUG_CHECK3(header) \ + ((mem_debug_header_t*)((char*)header + header->size))->magic3 +#define MEM_USER_PTR(header) \ + ((char *)header + offsetof(mem_debug_header_t, magic3)) +#define MEM_HEADER_PTR(ptr) \ + (mem_debug_header_t *)((char*)ptr - offsetof(mem_debug_header_t, magic3)) + +struct mem_debug_header { + unsigned magic1; + unsigned size; + struct mem_debug_header *prev; + struct mem_debug_header *next; + int line_num; + char file_name[MEM_DEBUG_FILE_LEN + 1]; + unsigned magic2; + ALIGNED(16) unsigned magic3; +}; + +typedef struct mem_debug_header mem_debug_header_t; + +static mem_debug_header_t *mem_debug_chain; +static unsigned mem_cur_size; +static unsigned mem_max_size; + +static mem_debug_header_t *malloc_check(void *ptr, const char *msg) +{ + mem_debug_header_t * header = MEM_HEADER_PTR(ptr); + if (header->magic1 != MEM_DEBUG_MAGIC1 || + header->magic2 != MEM_DEBUG_MAGIC2 || + MEM_DEBUG_CHECK3(header) != MEM_DEBUG_MAGIC3 || + header->size == (unsigned)-1) { + fprintf(stderr, "%s check failed\n", msg); + if (header->magic1 == MEM_DEBUG_MAGIC1) + fprintf(stderr, "%s:%u: block allocated here.\n", + header->file_name, header->line_num); + exit(1); + } + return header; +} + +PUB_FUNC void *tcc_malloc_debug(unsigned long size, const char *file, int line) +{ + int ofs; + mem_debug_header_t *header; + + header = malloc(sizeof(mem_debug_header_t) + size); + if (!header) + tcc_error("memory full (malloc)"); + + header->magic1 = MEM_DEBUG_MAGIC1; + header->magic2 = MEM_DEBUG_MAGIC2; + header->size = size; + MEM_DEBUG_CHECK3(header) = MEM_DEBUG_MAGIC3; + header->line_num = line; + ofs = strlen(file) - MEM_DEBUG_FILE_LEN; + strncpy(header->file_name, file + (ofs > 0 ? ofs : 0), MEM_DEBUG_FILE_LEN); + header->file_name[MEM_DEBUG_FILE_LEN] = 0; + + header->next = mem_debug_chain; + header->prev = NULL; + if (header->next) + header->next->prev = header; + mem_debug_chain = header; + + mem_cur_size += size; + if (mem_cur_size > mem_max_size) + mem_max_size = mem_cur_size; + + return MEM_USER_PTR(header); +} + +PUB_FUNC void tcc_free_debug(void *ptr) +{ + mem_debug_header_t *header; + if (!ptr) + return; + header = malloc_check(ptr, "tcc_free"); + mem_cur_size -= header->size; + header->size = (unsigned)-1; + if (header->next) + header->next->prev = header->prev; + if (header->prev) + header->prev->next = header->next; + if (header == mem_debug_chain) + mem_debug_chain = header->next; + free(header); +} + +PUB_FUNC void *tcc_mallocz_debug(unsigned long size, const char *file, int line) +{ + void *ptr; + ptr = tcc_malloc_debug(size,file,line); + memset(ptr, 0, size); + return ptr; +} + +PUB_FUNC void *tcc_realloc_debug(void *ptr, unsigned long size, const char *file, int line) +{ + mem_debug_header_t *header; + int mem_debug_chain_update = 0; + if (!ptr) + return tcc_malloc_debug(size, file, line); + header = malloc_check(ptr, "tcc_realloc"); + mem_cur_size -= header->size; + mem_debug_chain_update = (header == mem_debug_chain); + header = realloc(header, sizeof(mem_debug_header_t) + size); + if (!header) + tcc_error("memory full (realloc)"); + header->size = size; + MEM_DEBUG_CHECK3(header) = MEM_DEBUG_MAGIC3; + if (header->next) + header->next->prev = header; + if (header->prev) + header->prev->next = header; + if (mem_debug_chain_update) + mem_debug_chain = header; + mem_cur_size += size; + if (mem_cur_size > mem_max_size) + mem_max_size = mem_cur_size; + return MEM_USER_PTR(header); +} + +PUB_FUNC char *tcc_strdup_debug(const char *str, const char *file, int line) +{ + char *ptr; + ptr = tcc_malloc_debug(strlen(str) + 1, file, line); + strcpy(ptr, str); + return ptr; +} + +PUB_FUNC void tcc_memcheck(void) +{ + if (mem_cur_size) { + mem_debug_header_t *header = mem_debug_chain; + fprintf(stderr, "MEM_DEBUG: mem_leak= %d bytes, mem_max_size= %d bytes\n", + mem_cur_size, mem_max_size); + while (header) { + fprintf(stderr, "%s:%u: error: %u bytes leaked\n", + header->file_name, header->line_num, header->size); + header = header->next; + } +#if MEM_DEBUG-0 == 2 + exit(2); +#endif + } +} +#endif /* MEM_DEBUG */ + +#define free(p) use_tcc_free(p) +#define malloc(s) use_tcc_malloc(s) +#define realloc(p, s) use_tcc_realloc(p, s) + +/********************************************************/ +/* dynarrays */ + +ST_FUNC void dynarray_add(void *ptab, int *nb_ptr, void *data) +{ + int nb, nb_alloc; + void **pp; + + nb = *nb_ptr; + pp = *(void ***)ptab; + /* every power of two we double array size */ + if ((nb & (nb - 1)) == 0) { + if (!nb) + nb_alloc = 1; + else + nb_alloc = nb * 2; + pp = tcc_realloc(pp, nb_alloc * sizeof(void *)); + *(void***)ptab = pp; + } + pp[nb++] = data; + *nb_ptr = nb; +} + +ST_FUNC void dynarray_reset(void *pp, int *n) +{ + void **p; + for (p = *(void***)pp; *n; ++p, --*n) + if (*p) + tcc_free(*p); + tcc_free(*(void**)pp); + *(void**)pp = NULL; +} + +static void tcc_split_path(TCCState *s, void *p_ary, int *p_nb_ary, const char *in) +{ + const char *p; + do { + int c; + CString str; + + cstr_new(&str); + for (p = in; c = *p, c != '\0' && c != PATHSEP[0]; ++p) { + if (c == '{' && p[1] && p[2] == '}') { + c = p[1], p += 2; + if (c == 'B') + cstr_cat(&str, s->tcc_lib_path, -1); + } else { + cstr_ccat(&str, c); + } + } + if (str.size) { + cstr_ccat(&str, '\0'); + dynarray_add(p_ary, p_nb_ary, tcc_strdup(str.data)); + } + cstr_free(&str); + in = p+1; + } while (*p); +} + +/********************************************************/ + +static void strcat_vprintf(char *buf, int buf_size, const char *fmt, va_list ap) +{ + int len; + len = strlen(buf); + vsnprintf(buf + len, buf_size - len, fmt, ap); +} + +static void strcat_printf(char *buf, int buf_size, const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + strcat_vprintf(buf, buf_size, fmt, ap); + va_end(ap); +} + +static void error1(TCCState *s1, int is_warning, const char *fmt, va_list ap) +{ + char buf[2048]; + BufferedFile **pf, *f; + + buf[0] = '\0'; + /* use upper file if inline ":asm:" or token ":paste:" */ + for (f = file; f && f->filename[0] == ':'; f = f->prev) + ; + if (f) { + for(pf = s1->include_stack; pf < s1->include_stack_ptr; pf++) + strcat_printf(buf, sizeof(buf), "In file included from %s:%d:\n", + (*pf)->filename, (*pf)->line_num); + if (f->line_num > 0) { + strcat_printf(buf, sizeof(buf), "%s:%d: ", + f->filename, f->line_num - !!(tok_flags & TOK_FLAG_BOL)); + } else { + strcat_printf(buf, sizeof(buf), "%s: ", + f->filename); + } + } else { + strcat_printf(buf, sizeof(buf), "tcc: "); + } + if (is_warning) + strcat_printf(buf, sizeof(buf), "warning: "); + else + strcat_printf(buf, sizeof(buf), "error: "); + strcat_vprintf(buf, sizeof(buf), fmt, ap); + + if (!s1->error_func) { + /* default case: stderr */ + if (s1->output_type == TCC_OUTPUT_PREPROCESS && s1->ppfp == stdout) + /* print a newline during tcc -E */ + printf("\n"), fflush(stdout); + fflush(stdout); /* flush -v output */ + fprintf(stderr, "%s\n", buf); + fflush(stderr); /* print error/warning now (win32) */ + } else { + s1->error_func(s1->error_opaque, buf); + } + if (!is_warning || s1->warn_error) + s1->nb_errors++; +} + +LIBTCCAPI void tcc_set_error_func(TCCState *s, void *error_opaque, + void (*error_func)(void *opaque, const char *msg)) +{ + s->error_opaque = error_opaque; + s->error_func = error_func; +} + +/* error without aborting current compilation */ +PUB_FUNC void tcc_error_noabort(const char *fmt, ...) +{ + TCCState *s1 = tcc_state; + va_list ap; + + va_start(ap, fmt); + error1(s1, 0, fmt, ap); + va_end(ap); +} + +PUB_FUNC void tcc_error(const char *fmt, ...) +{ + TCCState *s1 = tcc_state; + va_list ap; + + va_start(ap, fmt); + error1(s1, 0, fmt, ap); + va_end(ap); + /* better than nothing: in some cases, we accept to handle errors */ + if (s1->error_set_jmp_enabled) { + longjmp(s1->error_jmp_buf, 1); + } else { + /* XXX: eliminate this someday */ + exit(1); + } +} + +PUB_FUNC void tcc_warning(const char *fmt, ...) +{ + TCCState *s1 = tcc_state; + va_list ap; + + if (s1->warn_none) + return; + + va_start(ap, fmt); + error1(s1, 1, fmt, ap); + va_end(ap); +} + +/********************************************************/ +/* I/O layer */ + +ST_FUNC void tcc_open_bf(TCCState *s1, const char *filename, int initlen) +{ + BufferedFile *bf; + int buflen = initlen ? initlen : IO_BUF_SIZE; + + bf = tcc_mallocz(sizeof(BufferedFile) + buflen); + bf->buf_ptr = bf->buffer; + bf->buf_end = bf->buffer + initlen; + bf->buf_end[0] = CH_EOB; /* put eob symbol */ + pstrcpy(bf->filename, sizeof(bf->filename), filename); + bf->true_filename = bf->filename; + bf->line_num = 1; + bf->ifdef_stack_ptr = s1->ifdef_stack_ptr; + bf->fd = -1; + bf->prev = file; + file = bf; + tok_flags = TOK_FLAG_BOL | TOK_FLAG_BOF; +} + +ST_FUNC void tcc_close(void) +{ + BufferedFile *bf = file; + if (bf->fd > 0) { + close(bf->fd); + total_lines += bf->line_num; + } + if (bf->true_filename != bf->filename) + tcc_free(bf->true_filename); + file = bf->prev; + tcc_free(bf); +} + +ST_FUNC int tcc_open(TCCState *s1, const char *filename) +{ + int fd; + if (strcmp(filename, "-") == 0) + fd = 0, filename = ""; + else + fd = open(filename, O_RDONLY | O_BINARY); + if ((s1->verbose == 2 && fd >= 0) || s1->verbose == 3) + printf("%s %*s%s\n", fd < 0 ? "nf":"->", + (int)(s1->include_stack_ptr - s1->include_stack), "", filename); + if (fd < 0) + return -1; + tcc_open_bf(s1, filename, 0); +#ifdef _WIN32 + normalize_slashes(file->filename); +#endif + file->fd = fd; + return fd; +} + +/* compile the file opened in 'file'. Return non zero if errors. */ +static int tcc_compile(TCCState *s1) +{ + Sym *define_start; + int filetype, is_asm; + + define_start = define_stack; + filetype = s1->filetype; + is_asm = filetype == AFF_TYPE_ASM || filetype == AFF_TYPE_ASMPP; + + if (setjmp(s1->error_jmp_buf) == 0) { + s1->nb_errors = 0; + s1->error_set_jmp_enabled = 1; + + preprocess_start(s1, is_asm); + if (s1->output_type == TCC_OUTPUT_PREPROCESS) { + tcc_preprocess(s1); + } else if (is_asm) { +#ifdef CONFIG_TCC_ASM + tcc_assemble(s1, filetype == AFF_TYPE_ASMPP); +#else + tcc_error_noabort("asm not supported"); +#endif + } else { + tccgen_compile(s1); + } + } + s1->error_set_jmp_enabled = 0; + + preprocess_end(s1); + free_inline_functions(s1); + /* reset define stack, but keep -D and built-ins */ + free_defines(define_start); + sym_pop(&global_stack, NULL, 0); + sym_pop(&local_stack, NULL, 0); + return s1->nb_errors != 0 ? -1 : 0; +} + +LIBTCCAPI int tcc_compile_string(TCCState *s, const char *str) +{ + int len, ret; + + len = strlen(str); + tcc_open_bf(s, "", len); + memcpy(file->buffer, str, len); + ret = tcc_compile(s); + tcc_close(); + return ret; +} + +/* define a preprocessor symbol. A value can also be provided with the '=' operator */ +LIBTCCAPI void tcc_define_symbol(TCCState *s1, const char *sym, const char *value) +{ + int len1, len2; + /* default value */ + if (!value) + value = "1"; + len1 = strlen(sym); + len2 = strlen(value); + + /* init file structure */ + tcc_open_bf(s1, "", len1 + len2 + 1); + memcpy(file->buffer, sym, len1); + file->buffer[len1] = ' '; + memcpy(file->buffer + len1 + 1, value, len2); + + /* parse with define parser */ + next_nomacro(); + parse_define(); + tcc_close(); +} + +/* undefine a preprocessor symbol */ +LIBTCCAPI void tcc_undefine_symbol(TCCState *s1, const char *sym) +{ + TokenSym *ts; + Sym *s; + ts = tok_alloc(sym, strlen(sym)); + s = define_find(ts->tok); + /* undefine symbol by putting an invalid name */ + if (s) + define_undef(s); +} + +/* cleanup all static data used during compilation */ +static void tcc_cleanup(void) +{ + if (NULL == tcc_state) + return; + while (file) + tcc_close(); + tccpp_delete(tcc_state); + tcc_state = NULL; + /* free sym_pools */ + dynarray_reset(&sym_pools, &nb_sym_pools); + /* reset symbol stack */ + sym_free_first = NULL; +} + +LIBTCCAPI TCCState *tcc_new(void) +{ + TCCState *s; + + tcc_cleanup(); + + s = tcc_mallocz(sizeof(TCCState)); + if (!s) + return NULL; + tcc_state = s; + ++nb_states; + + s->alacarte_link = 1; + s->nocommon = 1; + s->warn_implicit_function_declaration = 1; + s->ms_extensions = 1; + +#ifdef CHAR_IS_UNSIGNED + s->char_is_unsigned = 1; +#endif +#ifdef TCC_TARGET_I386 + s->seg_size = 32; +#endif + /* enable this if you want symbols with leading underscore on windows: */ +#if 0 /* def TCC_TARGET_PE */ + s->leading_underscore = 1; +#endif +#ifdef _WIN32 + tcc_set_lib_path_w32(s); +#else + tcc_set_lib_path(s, CONFIG_TCCDIR); +#endif + tccelf_new(s); + tccpp_new(s); + + /* we add dummy defines for some special macros to speed up tests + and to have working defined() */ + define_push(TOK___LINE__, MACRO_OBJ, NULL, NULL); + define_push(TOK___FILE__, MACRO_OBJ, NULL, NULL); + define_push(TOK___DATE__, MACRO_OBJ, NULL, NULL); + define_push(TOK___TIME__, MACRO_OBJ, NULL, NULL); + define_push(TOK___COUNTER__, MACRO_OBJ, NULL, NULL); + { + /* define __TINYC__ 92X */ + char buffer[32]; int a,b,c; + sscanf(TCC_VERSION, "%d.%d.%d", &a, &b, &c); + sprintf(buffer, "%d", a*10000 + b*100 + c); + tcc_define_symbol(s, "__TINYC__", buffer); + } + + /* standard defines */ + tcc_define_symbol(s, "__STDC__", NULL); + tcc_define_symbol(s, "__STDC_VERSION__", "199901L"); + tcc_define_symbol(s, "__STDC_HOSTED__", NULL); + + /* target defines */ +#if defined(TCC_TARGET_I386) + tcc_define_symbol(s, "__i386__", NULL); + tcc_define_symbol(s, "__i386", NULL); + tcc_define_symbol(s, "i386", NULL); +#elif defined(TCC_TARGET_X86_64) + tcc_define_symbol(s, "__x86_64__", NULL); +#elif defined(TCC_TARGET_ARM) + tcc_define_symbol(s, "__ARM_ARCH_4__", NULL); + tcc_define_symbol(s, "__arm_elf__", NULL); + tcc_define_symbol(s, "__arm_elf", NULL); + tcc_define_symbol(s, "arm_elf", NULL); + tcc_define_symbol(s, "__arm__", NULL); + tcc_define_symbol(s, "__arm", NULL); + tcc_define_symbol(s, "arm", NULL); + tcc_define_symbol(s, "__APCS_32__", NULL); + tcc_define_symbol(s, "__ARMEL__", NULL); +#if defined(TCC_ARM_EABI) + tcc_define_symbol(s, "__ARM_EABI__", NULL); +#endif +#if defined(TCC_ARM_HARDFLOAT) + s->float_abi = ARM_HARD_FLOAT; + tcc_define_symbol(s, "__ARM_PCS_VFP", NULL); +#else + s->float_abi = ARM_SOFTFP_FLOAT; +#endif +#elif defined(TCC_TARGET_ARM64) + tcc_define_symbol(s, "__aarch64__", NULL); +#elif defined TCC_TARGET_C67 + tcc_define_symbol(s, "__C67__", NULL); +#endif + +#ifdef TCC_TARGET_PE + tcc_define_symbol(s, "_WIN32", NULL); +# ifdef TCC_TARGET_X86_64 + tcc_define_symbol(s, "_WIN64", NULL); +# endif +#else + tcc_define_symbol(s, "__unix__", NULL); + tcc_define_symbol(s, "__unix", NULL); + tcc_define_symbol(s, "unix", NULL); +# if defined(__linux__) + tcc_define_symbol(s, "__linux__", NULL); + tcc_define_symbol(s, "__linux", NULL); +# endif +# if defined(__FreeBSD__) + tcc_define_symbol(s, "__FreeBSD__", "__FreeBSD__"); + /* No 'Thread Storage Local' on FreeBSD with tcc */ + tcc_define_symbol(s, "__NO_TLS", NULL); +# endif +# if defined(__FreeBSD_kernel__) + tcc_define_symbol(s, "__FreeBSD_kernel__", NULL); +# endif +# if defined(__NetBSD__) + tcc_define_symbol(s, "__NetBSD__", "__NetBSD__"); +# endif +# if defined(__OpenBSD__) + tcc_define_symbol(s, "__OpenBSD__", "__OpenBSD__"); +# endif +#endif + + /* TinyCC & gcc defines */ +#if PTR_SIZE == 4 + /* 32bit systems. */ + tcc_define_symbol(s, "__SIZE_TYPE__", "unsigned int"); + tcc_define_symbol(s, "__PTRDIFF_TYPE__", "int"); + tcc_define_symbol(s, "__ILP32__", NULL); +#elif LONG_SIZE == 4 + /* 64bit Windows. */ + tcc_define_symbol(s, "__SIZE_TYPE__", "unsigned long long"); + tcc_define_symbol(s, "__PTRDIFF_TYPE__", "long long"); + tcc_define_symbol(s, "__LLP64__", NULL); +#else + /* Other 64bit systems. */ + tcc_define_symbol(s, "__SIZE_TYPE__", "unsigned long"); + tcc_define_symbol(s, "__PTRDIFF_TYPE__", "long"); + tcc_define_symbol(s, "__LP64__", NULL); +#endif + +#ifdef TCC_TARGET_PE + tcc_define_symbol(s, "__WCHAR_TYPE__", "unsigned short"); + tcc_define_symbol(s, "__WINT_TYPE__", "unsigned short"); +#else + tcc_define_symbol(s, "__WCHAR_TYPE__", "int"); + /* wint_t is unsigned int by default, but (signed) int on BSDs + and unsigned short on windows. Other OSes might have still + other conventions, sigh. */ +# if defined(__FreeBSD__) || defined (__FreeBSD_kernel__) \ + || defined(__NetBSD__) || defined(__OpenBSD__) + tcc_define_symbol(s, "__WINT_TYPE__", "int"); +# ifdef __FreeBSD__ + /* define __GNUC__ to have some useful stuff from sys/cdefs.h + that are unconditionally used in FreeBSDs other system headers :/ */ + tcc_define_symbol(s, "__GNUC__", "2"); + tcc_define_symbol(s, "__GNUC_MINOR__", "7"); + tcc_define_symbol(s, "__builtin_alloca", "alloca"); +# endif +# else + tcc_define_symbol(s, "__WINT_TYPE__", "unsigned int"); + /* glibc defines */ + tcc_define_symbol(s, "__REDIRECT(name, proto, alias)", + "name proto __asm__ (#alias)"); + tcc_define_symbol(s, "__REDIRECT_NTH(name, proto, alias)", + "name proto __asm__ (#alias) __THROW"); +# endif +# if defined(TCC_MUSL) + tcc_define_symbol(s, "__DEFINED_va_list", ""); + tcc_define_symbol(s, "__DEFINED___isoc_va_list", ""); + tcc_define_symbol(s, "__isoc_va_list", "void *"); +# endif /* TCC_MUSL */ + /* Some GCC builtins that are simple to express as macros. */ + tcc_define_symbol(s, "__builtin_extract_return_addr(x)", "x"); +#endif /* ndef TCC_TARGET_PE */ + return s; +} + +LIBTCCAPI void tcc_delete(TCCState *s1) +{ + tcc_cleanup(); + + /* free sections */ + tccelf_delete(s1); + + /* free library paths */ + dynarray_reset(&s1->library_paths, &s1->nb_library_paths); + dynarray_reset(&s1->crt_paths, &s1->nb_crt_paths); + + /* free include paths */ + dynarray_reset(&s1->cached_includes, &s1->nb_cached_includes); + dynarray_reset(&s1->include_paths, &s1->nb_include_paths); + dynarray_reset(&s1->sysinclude_paths, &s1->nb_sysinclude_paths); + dynarray_reset(&s1->cmd_include_files, &s1->nb_cmd_include_files); + + tcc_free(s1->tcc_lib_path); + tcc_free(s1->soname); + tcc_free(s1->rpath); + tcc_free(s1->init_symbol); + tcc_free(s1->fini_symbol); + tcc_free(s1->outfile); + tcc_free(s1->deps_outfile); + dynarray_reset(&s1->files, &s1->nb_files); + dynarray_reset(&s1->target_deps, &s1->nb_target_deps); + dynarray_reset(&s1->pragma_libs, &s1->nb_pragma_libs); + dynarray_reset(&s1->argv, &s1->argc); + +#ifdef TCC_IS_NATIVE + /* free runtime memory */ + tcc_run_free(s1); +#endif + + tcc_free(s1); + if (0 == --nb_states) + tcc_memcheck(); +} + +LIBTCCAPI int tcc_set_output_type(TCCState *s, int output_type) +{ + s->output_type = output_type; + + /* always elf for objects */ + if (output_type == TCC_OUTPUT_OBJ) + s->output_format = TCC_OUTPUT_FORMAT_ELF; + + if (s->char_is_unsigned) + tcc_define_symbol(s, "__CHAR_UNSIGNED__", NULL); + + if (!s->nostdinc) { + /* default include paths */ + /* -isystem paths have already been handled */ + tcc_add_sysinclude_path(s, CONFIG_TCC_SYSINCLUDEPATHS); + } + +#ifdef CONFIG_TCC_BCHECK + if (s->do_bounds_check) { + /* if bound checking, then add corresponding sections */ + tccelf_bounds_new(s); + /* define symbol */ + tcc_define_symbol(s, "__BOUNDS_CHECKING_ON", NULL); + } +#endif + if (s->do_debug) { + /* add debug sections */ + tccelf_stab_new(s); + } + + tcc_add_library_path(s, CONFIG_TCC_LIBPATHS); + +#ifdef TCC_TARGET_PE +# ifdef _WIN32 + if (!s->nostdlib && output_type != TCC_OUTPUT_OBJ) + tcc_add_systemdir(s); +# endif +#else + /* paths for crt objects */ + tcc_split_path(s, &s->crt_paths, &s->nb_crt_paths, CONFIG_TCC_CRTPREFIX); + /* add libc crt1/crti objects */ + if ((output_type == TCC_OUTPUT_EXE || output_type == TCC_OUTPUT_DLL) && + !s->nostdlib) { + if (output_type != TCC_OUTPUT_DLL) + tcc_add_crt(s, "crt1.o"); + tcc_add_crt(s, "crti.o"); + } +#endif + return 0; +} + +LIBTCCAPI int tcc_add_include_path(TCCState *s, const char *pathname) +{ + tcc_split_path(s, &s->include_paths, &s->nb_include_paths, pathname); + return 0; +} + +LIBTCCAPI int tcc_add_sysinclude_path(TCCState *s, const char *pathname) +{ + tcc_split_path(s, &s->sysinclude_paths, &s->nb_sysinclude_paths, pathname); + return 0; +} + +ST_FUNC int tcc_add_file_internal(TCCState *s1, const char *filename, int flags) +{ + int ret; + + /* open the file */ + ret = tcc_open(s1, filename); + if (ret < 0) { + if (flags & AFF_PRINT_ERROR) + tcc_error_noabort("file '%s' not found", filename); + return ret; + } + + /* update target deps */ + dynarray_add(&s1->target_deps, &s1->nb_target_deps, + tcc_strdup(filename)); + + if (flags & AFF_TYPE_BIN) { + ElfW(Ehdr) ehdr; + int fd, obj_type; + + fd = file->fd; + obj_type = tcc_object_type(fd, &ehdr); + lseek(fd, 0, SEEK_SET); + + /* do not display line number if error */ + file->line_num = 0; + +#ifdef TCC_TARGET_MACHO + if (0 == obj_type && 0 == strcmp(tcc_fileextension(filename), ".dylib")) + obj_type = AFF_BINTYPE_DYN; +#endif + + switch (obj_type) { + case AFF_BINTYPE_REL: + ret = tcc_load_object_file(s1, fd, 0); + break; +#ifndef TCC_TARGET_PE + case AFF_BINTYPE_DYN: + if (s1->output_type == TCC_OUTPUT_MEMORY) { + ret = 0; +#ifdef TCC_IS_NATIVE + if (NULL == dlopen(filename, RTLD_GLOBAL | RTLD_LAZY)) + ret = -1; +#endif + } else { + ret = tcc_load_dll(s1, fd, filename, + (flags & AFF_REFERENCED_DLL) != 0); + } + break; +#endif + case AFF_BINTYPE_AR: + ret = tcc_load_archive(s1, fd); + break; +#ifdef TCC_TARGET_COFF + case AFF_BINTYPE_C67: + ret = tcc_load_coff(s1, fd); + break; +#endif + default: +#ifdef TCC_TARGET_PE + ret = pe_load_file(s1, filename, fd); +#else + /* as GNU ld, consider it is an ld script if not recognized */ + ret = tcc_load_ldscript(s1); +#endif + if (ret < 0) + tcc_error_noabort("unrecognized file type"); + break; + } + } else { + ret = tcc_compile(s1); + } + tcc_close(); + return ret; +} + +LIBTCCAPI int tcc_add_file(TCCState *s, const char *filename) +{ + int filetype = s->filetype; + int flags = AFF_PRINT_ERROR; + if (filetype == 0) { + /* use a file extension to detect a filetype */ + const char *ext = tcc_fileextension(filename); + if (ext[0]) { + ext++; + if (!strcmp(ext, "S")) + filetype = AFF_TYPE_ASMPP; + else if (!strcmp(ext, "s")) + filetype = AFF_TYPE_ASM; + else if (!PATHCMP(ext, "c") || !PATHCMP(ext, "i")) + filetype = AFF_TYPE_C; + else + flags |= AFF_TYPE_BIN; + } else { + filetype = AFF_TYPE_C; + } + s->filetype = filetype; + } + return tcc_add_file_internal(s, filename, flags); +} + +LIBTCCAPI int tcc_add_library_path(TCCState *s, const char *pathname) +{ + tcc_split_path(s, &s->library_paths, &s->nb_library_paths, pathname); + return 0; +} + +static int tcc_add_library_internal(TCCState *s, const char *fmt, + const char *filename, int flags, char **paths, int nb_paths) +{ + char buf[1024]; + int i; + + for(i = 0; i < nb_paths; i++) { + snprintf(buf, sizeof(buf), fmt, paths[i], filename); + if (tcc_add_file_internal(s, buf, flags | AFF_TYPE_BIN) == 0) + return 0; + } + return -1; +} + +/* find and load a dll. Return non zero if not found */ +/* XXX: add '-rpath' option support ? */ +ST_FUNC int tcc_add_dll(TCCState *s, const char *filename, int flags) +{ + return tcc_add_library_internal(s, "%s/%s", filename, flags, + s->library_paths, s->nb_library_paths); +} + +ST_FUNC int tcc_add_crt(TCCState *s, const char *filename) +{ + if (-1 == tcc_add_library_internal(s, "%s/%s", + filename, 0, s->crt_paths, s->nb_crt_paths)) + tcc_error_noabort("file '%s' not found", filename); + return 0; +} + +/* the library name is the same as the argument of the '-l' option */ +LIBTCCAPI int tcc_add_library(TCCState *s, const char *libraryname) +{ +#if defined TCC_TARGET_PE + const char *libs[] = { "%s/%s.def", "%s/lib%s.def", "%s/%s.dll", "%s/lib%s.dll", "%s/lib%s.a", NULL }; + const char **pp = s->static_link ? libs + 4 : libs; +#elif defined TCC_TARGET_MACHO + const char *libs[] = { "%s/lib%s.dylib", "%s/lib%s.a", NULL }; + const char **pp = s->static_link ? libs + 1 : libs; +#else + const char *libs[] = { "%s/lib%s.so", "%s/lib%s.a", NULL }; + const char **pp = s->static_link ? libs + 1 : libs; +#endif + while (*pp) { + if (0 == tcc_add_library_internal(s, *pp, + libraryname, 0, s->library_paths, s->nb_library_paths)) + return 0; + ++pp; + } + return -1; +} + +PUB_FUNC int tcc_add_library_err(TCCState *s, const char *libname) +{ + int ret = tcc_add_library(s, libname); + if (ret < 0) + tcc_error_noabort("library '%s' not found", libname); + return ret; +} + +/* handle #pragma comment(lib,) */ +ST_FUNC void tcc_add_pragma_libs(TCCState *s1) +{ + int i; + for (i = 0; i < s1->nb_pragma_libs; i++) + tcc_add_library_err(s1, s1->pragma_libs[i]); +} + +LIBTCCAPI int tcc_add_symbol(TCCState *s, const char *name, const void *val) +{ +#ifdef TCC_TARGET_PE + /* On x86_64 'val' might not be reachable with a 32bit offset. + So it is handled here as if it were in a DLL. */ + pe_putimport(s, 0, name, (uintptr_t)val); +#else + set_elf_sym(symtab_section, (uintptr_t)val, 0, + ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0, + SHN_ABS, name); +#endif + return 0; +} + +LIBTCCAPI void tcc_set_lib_path(TCCState *s, const char *path) +{ + tcc_free(s->tcc_lib_path); + s->tcc_lib_path = tcc_strdup(path); +} + +#define WD_ALL 0x0001 /* warning is activated when using -Wall */ +#define FD_INVERT 0x0002 /* invert value before storing */ + +typedef struct FlagDef { + uint16_t offset; + uint16_t flags; + const char *name; +} FlagDef; + +static int no_flag(const char **pp) +{ + const char *p = *pp; + if (*p != 'n' || *++p != 'o' || *++p != '-') + return 0; + *pp = p + 1; + return 1; +} + +ST_FUNC int set_flag(TCCState *s, const FlagDef *flags, const char *name) +{ + int value, ret; + const FlagDef *p; + const char *r; + + value = 1; + r = name; + if (no_flag(&r)) + value = 0; + + for (ret = -1, p = flags; p->name; ++p) { + if (ret) { + if (strcmp(r, p->name)) + continue; + } else { + if (0 == (p->flags & WD_ALL)) + continue; + } + if (p->offset) { + *(int*)((char *)s + p->offset) = + p->flags & FD_INVERT ? !value : value; + if (ret) + return 0; + } else { + ret = 0; + } + } + return ret; +} + +static int strstart(const char *val, const char **str) +{ + const char *p, *q; + p = *str; + q = val; + while (*q) { + if (*p != *q) + return 0; + p++; + q++; + } + *str = p; + return 1; +} + +/* Like strstart, but automatically takes into account that ld options can + * + * - start with double or single dash (e.g. '--soname' or '-soname') + * - arguments can be given as separate or after '=' (e.g. '-Wl,-soname,x.so' + * or '-Wl,-soname=x.so') + * + * you provide `val` always in 'option[=]' form (no leading -) + */ +static int link_option(const char *str, const char *val, const char **ptr) +{ + const char *p, *q; + int ret; + + /* there should be 1 or 2 dashes */ + if (*str++ != '-') + return 0; + if (*str == '-') + str++; + + /* then str & val should match (potentially up to '=') */ + p = str; + q = val; + + ret = 1; + if (q[0] == '?') { + ++q; + if (no_flag(&p)) + ret = -1; + } + + while (*q != '\0' && *q != '=') { + if (*p != *q) + return 0; + p++; + q++; + } + + /* '=' near eos means ',' or '=' is ok */ + if (*q == '=') { + if (*p == 0) + *ptr = p; + if (*p != ',' && *p != '=') + return 0; + p++; + } else if (*p) { + return 0; + } + *ptr = p; + return ret; +} + +static const char *skip_linker_arg(const char **str) +{ + const char *s1 = *str; + const char *s2 = strchr(s1, ','); + *str = s2 ? s2++ : (s2 = s1 + strlen(s1)); + return s2; +} + +static void copy_linker_arg(char **pp, const char *s, int sep) +{ + const char *q = s; + char *p = *pp; + int l = 0; + if (p && sep) + p[l = strlen(p)] = sep, ++l; + skip_linker_arg(&q); + pstrncpy(l + (*pp = tcc_realloc(p, q - s + l + 1)), s, q - s); +} + +/* set linker options */ +static int tcc_set_linker(TCCState *s, const char *option) +{ + while (*option) { + + const char *p = NULL; + char *end = NULL; + int ignoring = 0; + int ret; + + if (link_option(option, "Bsymbolic", &p)) { + s->symbolic = 1; + } else if (link_option(option, "nostdlib", &p)) { + s->nostdlib = 1; + } else if (link_option(option, "fini=", &p)) { + copy_linker_arg(&s->fini_symbol, p, 0); + ignoring = 1; + } else if (link_option(option, "image-base=", &p) + || link_option(option, "Ttext=", &p)) { + s->text_addr = strtoull(p, &end, 16); + s->has_text_addr = 1; + } else if (link_option(option, "init=", &p)) { + copy_linker_arg(&s->init_symbol, p, 0); + ignoring = 1; + } else if (link_option(option, "oformat=", &p)) { +#if defined(TCC_TARGET_PE) + if (strstart("pe-", &p)) { +#elif PTR_SIZE == 8 + if (strstart("elf64-", &p)) { +#else + if (strstart("elf32-", &p)) { +#endif + s->output_format = TCC_OUTPUT_FORMAT_ELF; + } else if (!strcmp(p, "binary")) { + s->output_format = TCC_OUTPUT_FORMAT_BINARY; +#ifdef TCC_TARGET_COFF + } else if (!strcmp(p, "coff")) { + s->output_format = TCC_OUTPUT_FORMAT_COFF; +#endif + } else + goto err; + + } else if (link_option(option, "as-needed", &p)) { + ignoring = 1; + } else if (link_option(option, "O", &p)) { + ignoring = 1; + } else if (link_option(option, "export-all-symbols", &p)) { + s->rdynamic = 1; + } else if (link_option(option, "rpath=", &p)) { + copy_linker_arg(&s->rpath, p, ':'); + } else if (link_option(option, "enable-new-dtags", &p)) { + s->enable_new_dtags = 1; + } else if (link_option(option, "section-alignment=", &p)) { + s->section_align = strtoul(p, &end, 16); + } else if (link_option(option, "soname=", &p)) { + copy_linker_arg(&s->soname, p, 0); +#ifdef TCC_TARGET_PE + } else if (link_option(option, "large-address-aware", &p)) { + s->pe_characteristics |= 0x20; + } else if (link_option(option, "file-alignment=", &p)) { + s->pe_file_align = strtoul(p, &end, 16); + } else if (link_option(option, "stack=", &p)) { + s->pe_stack_size = strtoul(p, &end, 10); + } else if (link_option(option, "subsystem=", &p)) { +#if defined(TCC_TARGET_I386) || defined(TCC_TARGET_X86_64) + if (!strcmp(p, "native")) { + s->pe_subsystem = 1; + } else if (!strcmp(p, "console")) { + s->pe_subsystem = 3; + } else if (!strcmp(p, "gui") || !strcmp(p, "windows")) { + s->pe_subsystem = 2; + } else if (!strcmp(p, "posix")) { + s->pe_subsystem = 7; + } else if (!strcmp(p, "efiapp")) { + s->pe_subsystem = 10; + } else if (!strcmp(p, "efiboot")) { + s->pe_subsystem = 11; + } else if (!strcmp(p, "efiruntime")) { + s->pe_subsystem = 12; + } else if (!strcmp(p, "efirom")) { + s->pe_subsystem = 13; +#elif defined(TCC_TARGET_ARM) + if (!strcmp(p, "wince")) { + s->pe_subsystem = 9; +#endif + } else + goto err; +#endif + } else if (ret = link_option(option, "?whole-archive", &p), ret) { + s->alacarte_link = ret < 0; + } else if (p) { + return 0; + } else { + err: + tcc_error("unsupported linker option '%s'", option); + } + + if (ignoring && s->warn_unsupported) + tcc_warning("unsupported linker option '%s'", option); + + option = skip_linker_arg(&p); + } + return 1; +} + +typedef struct TCCOption { + const char *name; + uint16_t index; + uint16_t flags; +} TCCOption; + +enum { + TCC_OPTION_HELP, + TCC_OPTION_HELP2, + TCC_OPTION_v, + TCC_OPTION_I, + TCC_OPTION_D, + TCC_OPTION_U, + TCC_OPTION_P, + TCC_OPTION_L, + TCC_OPTION_B, + TCC_OPTION_l, + TCC_OPTION_bench, + TCC_OPTION_bt, + TCC_OPTION_b, + TCC_OPTION_g, + TCC_OPTION_c, + TCC_OPTION_dumpversion, + TCC_OPTION_d, + TCC_OPTION_static, + TCC_OPTION_std, + TCC_OPTION_shared, + TCC_OPTION_soname, + TCC_OPTION_o, + TCC_OPTION_r, + TCC_OPTION_s, + TCC_OPTION_traditional, + TCC_OPTION_Wl, + TCC_OPTION_Wp, + TCC_OPTION_W, + TCC_OPTION_O, + TCC_OPTION_mfloat_abi, + TCC_OPTION_m, + TCC_OPTION_f, + TCC_OPTION_isystem, + TCC_OPTION_iwithprefix, + TCC_OPTION_include, + TCC_OPTION_nostdinc, + TCC_OPTION_nostdlib, + TCC_OPTION_print_search_dirs, + TCC_OPTION_rdynamic, + TCC_OPTION_param, + TCC_OPTION_pedantic, + TCC_OPTION_pthread, + TCC_OPTION_run, + TCC_OPTION_w, + TCC_OPTION_pipe, + TCC_OPTION_E, + TCC_OPTION_MD, + TCC_OPTION_MF, + TCC_OPTION_x, + TCC_OPTION_ar, + TCC_OPTION_impdef +}; + +#define TCC_OPTION_HAS_ARG 0x0001 +#define TCC_OPTION_NOSEP 0x0002 /* cannot have space before option and arg */ + +static const TCCOption tcc_options[] = { + { "h", TCC_OPTION_HELP, 0 }, + { "-help", TCC_OPTION_HELP, 0 }, + { "?", TCC_OPTION_HELP, 0 }, + { "hh", TCC_OPTION_HELP2, 0 }, + { "v", TCC_OPTION_v, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP }, + { "I", TCC_OPTION_I, TCC_OPTION_HAS_ARG }, + { "D", TCC_OPTION_D, TCC_OPTION_HAS_ARG }, + { "U", TCC_OPTION_U, TCC_OPTION_HAS_ARG }, + { "P", TCC_OPTION_P, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP }, + { "L", TCC_OPTION_L, TCC_OPTION_HAS_ARG }, + { "B", TCC_OPTION_B, TCC_OPTION_HAS_ARG }, + { "l", TCC_OPTION_l, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP }, + { "bench", TCC_OPTION_bench, 0 }, +#ifdef CONFIG_TCC_BACKTRACE + { "bt", TCC_OPTION_bt, TCC_OPTION_HAS_ARG }, +#endif +#ifdef CONFIG_TCC_BCHECK + { "b", TCC_OPTION_b, 0 }, +#endif + { "g", TCC_OPTION_g, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP }, + { "c", TCC_OPTION_c, 0 }, + { "dumpversion", TCC_OPTION_dumpversion, 0}, + { "d", TCC_OPTION_d, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP }, + { "static", TCC_OPTION_static, 0 }, + { "std", TCC_OPTION_std, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP }, + { "shared", TCC_OPTION_shared, 0 }, + { "soname", TCC_OPTION_soname, TCC_OPTION_HAS_ARG }, + { "o", TCC_OPTION_o, TCC_OPTION_HAS_ARG }, + { "-param", TCC_OPTION_param, TCC_OPTION_HAS_ARG }, + { "pedantic", TCC_OPTION_pedantic, 0}, + { "pthread", TCC_OPTION_pthread, 0}, + { "run", TCC_OPTION_run, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP }, + { "rdynamic", TCC_OPTION_rdynamic, 0 }, + { "r", TCC_OPTION_r, 0 }, + { "s", TCC_OPTION_s, 0 }, + { "traditional", TCC_OPTION_traditional, 0 }, + { "Wl,", TCC_OPTION_Wl, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP }, + { "Wp,", TCC_OPTION_Wp, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP }, + { "W", TCC_OPTION_W, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP }, + { "O", TCC_OPTION_O, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP }, +#ifdef TCC_TARGET_ARM + { "mfloat-abi", TCC_OPTION_mfloat_abi, TCC_OPTION_HAS_ARG }, +#endif + { "m", TCC_OPTION_m, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP }, + { "f", TCC_OPTION_f, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP }, + { "isystem", TCC_OPTION_isystem, TCC_OPTION_HAS_ARG }, + { "include", TCC_OPTION_include, TCC_OPTION_HAS_ARG }, + { "nostdinc", TCC_OPTION_nostdinc, 0 }, + { "nostdlib", TCC_OPTION_nostdlib, 0 }, + { "print-search-dirs", TCC_OPTION_print_search_dirs, 0 }, + { "w", TCC_OPTION_w, 0 }, + { "pipe", TCC_OPTION_pipe, 0}, + { "E", TCC_OPTION_E, 0}, + { "MD", TCC_OPTION_MD, 0}, + { "MF", TCC_OPTION_MF, TCC_OPTION_HAS_ARG }, + { "x", TCC_OPTION_x, TCC_OPTION_HAS_ARG }, + { "ar", TCC_OPTION_ar, 0}, +#ifdef TCC_TARGET_PE + { "impdef", TCC_OPTION_impdef, 0}, +#endif + { NULL, 0, 0 }, +}; + +static const FlagDef options_W[] = { + { 0, 0, "all" }, + { offsetof(TCCState, warn_unsupported), 0, "unsupported" }, + { offsetof(TCCState, warn_write_strings), 0, "write-strings" }, + { offsetof(TCCState, warn_error), 0, "error" }, + { offsetof(TCCState, warn_gcc_compat), 0, "gcc-compat" }, + { offsetof(TCCState, warn_implicit_function_declaration), WD_ALL, + "implicit-function-declaration" }, + { 0, 0, NULL } +}; + +static const FlagDef options_f[] = { + { offsetof(TCCState, char_is_unsigned), 0, "unsigned-char" }, + { offsetof(TCCState, char_is_unsigned), FD_INVERT, "signed-char" }, + { offsetof(TCCState, nocommon), FD_INVERT, "common" }, + { offsetof(TCCState, leading_underscore), 0, "leading-underscore" }, + { offsetof(TCCState, ms_extensions), 0, "ms-extensions" }, + { offsetof(TCCState, dollars_in_identifiers), 0, "dollars-in-identifiers" }, + { 0, 0, NULL } +}; + +static const FlagDef options_m[] = { + { offsetof(TCCState, ms_bitfields), 0, "ms-bitfields" }, +#ifdef TCC_TARGET_X86_64 + { offsetof(TCCState, nosse), FD_INVERT, "sse" }, +#endif + { 0, 0, NULL } +}; + +static void parse_option_D(TCCState *s1, const char *optarg) +{ + char *sym = tcc_strdup(optarg); + char *value = strchr(sym, '='); + if (value) + *value++ = '\0'; + tcc_define_symbol(s1, sym, value); + tcc_free(sym); +} + +static void args_parser_add_file(TCCState *s, const char* filename, int filetype) +{ + struct filespec *f = tcc_malloc(sizeof *f + strlen(filename)); + f->type = filetype; + f->alacarte = s->alacarte_link; + strcpy(f->name, filename); + dynarray_add(&s->files, &s->nb_files, f); +} + +static int args_parser_make_argv(const char *r, int *argc, char ***argv) +{ + int ret = 0, q, c; + CString str; + for(;;) { + while (c = (unsigned char)*r, c && c <= ' ') + ++r; + if (c == 0) + break; + q = 0; + cstr_new(&str); + while (c = (unsigned char)*r, c) { + ++r; + if (c == '\\' && (*r == '"' || *r == '\\')) { + c = *r++; + } else if (c == '"') { + q = !q; + continue; + } else if (q == 0 && c <= ' ') { + break; + } + cstr_ccat(&str, c); + } + cstr_ccat(&str, 0); + //printf("<%s>\n", str.data), fflush(stdout); + dynarray_add(argv, argc, tcc_strdup(str.data)); + cstr_free(&str); + ++ret; + } + return ret; +} + +/* read list file */ +static void args_parser_listfile(TCCState *s, + const char *filename, int optind, int *pargc, char ***pargv) +{ + int fd, i; + size_t len; + char *p; + int argc = 0; + char **argv = NULL; + + fd = open(filename, O_RDONLY | O_BINARY); + if (fd < 0) + tcc_error("listfile '%s' not found", filename); + + len = lseek(fd, 0, SEEK_END); + p = tcc_malloc(len + 1), p[len] = 0; + lseek(fd, 0, SEEK_SET), read(fd, p, len), close(fd); + + for (i = 0; i < *pargc; ++i) + if (i == optind) + args_parser_make_argv(p, &argc, &argv); + else + dynarray_add(&argv, &argc, tcc_strdup((*pargv)[i])); + + tcc_free(p); + dynarray_reset(&s->argv, &s->argc); + *pargc = s->argc = argc, *pargv = s->argv = argv; +} + +PUB_FUNC int tcc_parse_args(TCCState *s, int *pargc, char ***pargv, int optind) +{ + const TCCOption *popt; + const char *optarg, *r; + const char *run = NULL; + int last_o = -1; + int x; + CString linker_arg; /* collect -Wl options */ + int tool = 0, arg_start = 0, noaction = optind; + char **argv = *pargv; + int argc = *pargc; + + cstr_new(&linker_arg); + + while (optind < argc) { + r = argv[optind]; + if (r[0] == '@' && r[1] != '\0') { + args_parser_listfile(s, r + 1, optind, &argc, &argv); + continue; + } + optind++; + if (tool) { + if (r[0] == '-' && r[1] == 'v' && r[2] == 0) + ++s->verbose; + continue; + } +reparse: + if (r[0] != '-' || r[1] == '\0') { + if (r[0] != '@') /* allow "tcc file(s) -run @ args ..." */ + args_parser_add_file(s, r, s->filetype); + if (run) { + tcc_set_options(s, run); + arg_start = optind - 1; + break; + } + continue; + } + + /* find option in table */ + for(popt = tcc_options; ; ++popt) { + const char *p1 = popt->name; + const char *r1 = r + 1; + if (p1 == NULL) + tcc_error("invalid option -- '%s'", r); + if (!strstart(p1, &r1)) + continue; + optarg = r1; + if (popt->flags & TCC_OPTION_HAS_ARG) { + if (*r1 == '\0' && !(popt->flags & TCC_OPTION_NOSEP)) { + if (optind >= argc) + arg_err: + tcc_error("argument to '%s' is missing", r); + optarg = argv[optind++]; + } + } else if (*r1 != '\0') + continue; + break; + } + + switch(popt->index) { + case TCC_OPTION_HELP: + return OPT_HELP; + case TCC_OPTION_HELP2: + return OPT_HELP2; + case TCC_OPTION_I: + tcc_add_include_path(s, optarg); + break; + case TCC_OPTION_D: + parse_option_D(s, optarg); + break; + case TCC_OPTION_U: + tcc_undefine_symbol(s, optarg); + break; + case TCC_OPTION_L: + tcc_add_library_path(s, optarg); + break; + case TCC_OPTION_B: + /* set tcc utilities path (mainly for tcc development) */ + tcc_set_lib_path(s, optarg); + break; + case TCC_OPTION_l: + args_parser_add_file(s, optarg, AFF_TYPE_LIB); + s->nb_libraries++; + break; + case TCC_OPTION_pthread: + parse_option_D(s, "_REENTRANT"); + s->option_pthread = 1; + break; + case TCC_OPTION_bench: + s->do_bench = 1; + break; +#ifdef CONFIG_TCC_BACKTRACE + case TCC_OPTION_bt: + tcc_set_num_callers(atoi(optarg)); + break; +#endif +#ifdef CONFIG_TCC_BCHECK + case TCC_OPTION_b: + s->do_bounds_check = 1; + s->do_debug = 1; + break; +#endif + case TCC_OPTION_g: + s->do_debug = 1; + break; + case TCC_OPTION_c: + x = TCC_OUTPUT_OBJ; + set_output_type: + if (s->output_type) + tcc_warning("-%s: overriding compiler action already specified", popt->name); + s->output_type = x; + break; + case TCC_OPTION_d: + if (*optarg == 'D') + s->dflag = 3; + else if (*optarg == 'M') + s->dflag = 7; + else if (*optarg == 't') + s->dflag = 16; + else if (isnum(*optarg)) + g_debug = atoi(optarg); + else + goto unsupported_option; + break; + case TCC_OPTION_static: + s->static_link = 1; + break; + case TCC_OPTION_std: + /* silently ignore, a current purpose: + allow to use a tcc as a reference compiler for "make test" */ + break; + case TCC_OPTION_shared: + x = TCC_OUTPUT_DLL; + goto set_output_type; + case TCC_OPTION_soname: + s->soname = tcc_strdup(optarg); + break; + case TCC_OPTION_o: + if (s->outfile) { + tcc_warning("multiple -o option"); + tcc_free(s->outfile); + } + s->outfile = tcc_strdup(optarg); + break; + case TCC_OPTION_r: + /* generate a .o merging several output files */ + s->option_r = 1; + x = TCC_OUTPUT_OBJ; + goto set_output_type; + case TCC_OPTION_isystem: + tcc_add_sysinclude_path(s, optarg); + break; + case TCC_OPTION_include: + dynarray_add(&s->cmd_include_files, + &s->nb_cmd_include_files, tcc_strdup(optarg)); + break; + case TCC_OPTION_nostdinc: + s->nostdinc = 1; + break; + case TCC_OPTION_nostdlib: + s->nostdlib = 1; + break; + case TCC_OPTION_run: +#ifndef TCC_IS_NATIVE + tcc_error("-run is not available in a cross compiler"); +#endif + run = optarg; + x = TCC_OUTPUT_MEMORY; + goto set_output_type; + case TCC_OPTION_v: + do ++s->verbose; while (*optarg++ == 'v'); + ++noaction; + break; + case TCC_OPTION_f: + if (set_flag(s, options_f, optarg) < 0) + goto unsupported_option; + break; +#ifdef TCC_TARGET_ARM + case TCC_OPTION_mfloat_abi: + /* tcc doesn't support soft float yet */ + if (!strcmp(optarg, "softfp")) { + s->float_abi = ARM_SOFTFP_FLOAT; + tcc_undefine_symbol(s, "__ARM_PCS_VFP"); + } else if (!strcmp(optarg, "hard")) + s->float_abi = ARM_HARD_FLOAT; + else + tcc_error("unsupported float abi '%s'", optarg); + break; +#endif + case TCC_OPTION_m: + if (set_flag(s, options_m, optarg) < 0) { + if (x = atoi(optarg), x != 32 && x != 64) + goto unsupported_option; + if (PTR_SIZE != x/8) + return x; + ++noaction; + } + break; + case TCC_OPTION_W: + if (set_flag(s, options_W, optarg) < 0) + goto unsupported_option; + break; + case TCC_OPTION_w: + s->warn_none = 1; + break; + case TCC_OPTION_rdynamic: + s->rdynamic = 1; + break; + case TCC_OPTION_Wl: + if (linker_arg.size) + --linker_arg.size, cstr_ccat(&linker_arg, ','); + cstr_cat(&linker_arg, optarg, 0); + if (tcc_set_linker(s, linker_arg.data)) + cstr_free(&linker_arg); + break; + case TCC_OPTION_Wp: + r = optarg; + goto reparse; + case TCC_OPTION_E: + x = TCC_OUTPUT_PREPROCESS; + goto set_output_type; + case TCC_OPTION_P: + s->Pflag = atoi(optarg) + 1; + break; + case TCC_OPTION_MD: + s->gen_deps = 1; + break; + case TCC_OPTION_MF: + s->deps_outfile = tcc_strdup(optarg); + break; + case TCC_OPTION_dumpversion: + printf ("%s\n", TCC_VERSION); + exit(0); + break; + case TCC_OPTION_x: + if (*optarg == 'c') + s->filetype = AFF_TYPE_C; + else if (*optarg == 'a') + s->filetype = AFF_TYPE_ASMPP; + else if (*optarg == 'n') + s->filetype = AFF_TYPE_NONE; + else + tcc_warning("unsupported language '%s'", optarg); + break; + case TCC_OPTION_O: + last_o = atoi(optarg); + break; + case TCC_OPTION_print_search_dirs: + x = OPT_PRINT_DIRS; + goto extra_action; + case TCC_OPTION_impdef: + x = OPT_IMPDEF; + goto extra_action; + case TCC_OPTION_ar: + x = OPT_AR; + extra_action: + arg_start = optind - 1; + if (arg_start != noaction) + tcc_error("cannot parse %s here", r); + tool = x; + break; + case TCC_OPTION_traditional: + case TCC_OPTION_pedantic: + case TCC_OPTION_pipe: + case TCC_OPTION_s: + /* ignored */ + break; + default: +unsupported_option: + if (s->warn_unsupported) + tcc_warning("unsupported option '%s'", r); + break; + } + } + if (last_o > 0) + tcc_define_symbol(s, "__OPTIMIZE__", NULL); + if (linker_arg.size) { + r = linker_arg.data; + goto arg_err; + } + *pargc = argc - arg_start; + *pargv = argv + arg_start; + if (tool) + return tool; + if (optind != noaction) + return 0; + if (s->verbose == 2) + return OPT_PRINT_DIRS; + if (s->verbose) + return OPT_V; + return OPT_HELP; +} + +LIBTCCAPI void tcc_set_options(TCCState *s, const char *r) +{ + char **argv = NULL; + int argc = 0; + args_parser_make_argv(r, &argc, &argv); + tcc_parse_args(s, &argc, &argv, 0); + dynarray_reset(&argv, &argc); +} + +PUB_FUNC void tcc_print_stats(TCCState *s, unsigned total_time) +{ + if (total_time < 1) + total_time = 1; + if (total_bytes < 1) + total_bytes = 1; + fprintf(stderr, "* %d idents, %d lines, %d bytes\n" + "* %0.3f s, %u lines/s, %0.1f MB/s\n", + tok_ident - TOK_IDENT, total_lines, total_bytes, + (double)total_time/1000, + (unsigned)total_lines*1000/total_time, + (double)total_bytes/1000/total_time); +#ifdef MEM_DEBUG + fprintf(stderr, "* %d bytes memory used\n", mem_max_size); +#endif +} diff --git a/tinyc/libtcc.h b/tinyc/libtcc.h new file mode 100644 index 000000000..a1b31e300 --- /dev/null +++ b/tinyc/libtcc.h @@ -0,0 +1,100 @@ +#ifndef LIBTCC_H +#define LIBTCC_H + +#ifndef LIBTCCAPI +# define LIBTCCAPI +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +struct TCCState; + +typedef struct TCCState TCCState; + +/* create a new TCC compilation context */ +LIBTCCAPI TCCState *tcc_new(void); + +/* free a TCC compilation context */ +LIBTCCAPI void tcc_delete(TCCState *s); + +/* set CONFIG_TCCDIR at runtime */ +LIBTCCAPI void tcc_set_lib_path(TCCState *s, const char *path); + +/* set error/warning display callback */ +LIBTCCAPI void tcc_set_error_func(TCCState *s, void *error_opaque, + void (*error_func)(void *opaque, const char *msg)); + +/* set options as from command line (multiple supported) */ +LIBTCCAPI void tcc_set_options(TCCState *s, const char *str); + +/*****************************/ +/* preprocessor */ + +/* add include path */ +LIBTCCAPI int tcc_add_include_path(TCCState *s, const char *pathname); + +/* add in system include path */ +LIBTCCAPI int tcc_add_sysinclude_path(TCCState *s, const char *pathname); + +/* define preprocessor symbol 'sym'. Can put optional value */ +LIBTCCAPI void tcc_define_symbol(TCCState *s, const char *sym, const char *value); + +/* undefine preprocess symbol 'sym' */ +LIBTCCAPI void tcc_undefine_symbol(TCCState *s, const char *sym); + +/*****************************/ +/* compiling */ + +/* add a file (C file, dll, object, library, ld script). Return -1 if error. */ +LIBTCCAPI int tcc_add_file(TCCState *s, const char *filename); + +/* compile a string containing a C source. Return -1 if error. */ +LIBTCCAPI int tcc_compile_string(TCCState *s, const char *buf); + +/*****************************/ +/* linking commands */ + +/* set output type. MUST BE CALLED before any compilation */ +LIBTCCAPI int tcc_set_output_type(TCCState *s, int output_type); +#define TCC_OUTPUT_MEMORY 1 /* output will be run in memory (default) */ +#define TCC_OUTPUT_EXE 2 /* executable file */ +#define TCC_OUTPUT_DLL 3 /* dynamic library */ +#define TCC_OUTPUT_OBJ 4 /* object file */ +#define TCC_OUTPUT_PREPROCESS 5 /* only preprocess (used internally) */ + +/* equivalent to -Lpath option */ +LIBTCCAPI int tcc_add_library_path(TCCState *s, const char *pathname); + +/* the library name is the same as the argument of the '-l' option */ +LIBTCCAPI int tcc_add_library(TCCState *s, const char *libraryname); + +/* add a symbol to the compiled program */ +LIBTCCAPI int tcc_add_symbol(TCCState *s, const char *name, const void *val); + +/* output an executable, library or object file. DO NOT call + tcc_relocate() before. */ +LIBTCCAPI int tcc_output_file(TCCState *s, const char *filename); + +/* link and run main() function and return its value. DO NOT call + tcc_relocate() before. */ +LIBTCCAPI int tcc_run(TCCState *s, int argc, char **argv); + +/* do all relocations (needed before using tcc_get_symbol()) */ +LIBTCCAPI int tcc_relocate(TCCState *s1, void *ptr); +/* possible values for 'ptr': + - TCC_RELOCATE_AUTO : Allocate and manage memory internally + - NULL : return required memory size for the step below + - memory address : copy code to memory passed by the caller + returns -1 if error. */ +#define TCC_RELOCATE_AUTO (void*)1 + +/* return symbol value or NULL if not found */ +LIBTCCAPI void *tcc_get_symbol(TCCState *s, const char *name); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/tinyc/stab.def b/tinyc/stab.def new file mode 100644 index 000000000..48ea231e6 --- /dev/null +++ b/tinyc/stab.def @@ -0,0 +1,234 @@ +/* Table of DBX symbol codes for the GNU system. + Copyright (C) 1988, 1997 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +/* This contains contribution from Cygnus Support. */ + +/* Global variable. Only the name is significant. + To find the address, look in the corresponding external symbol. */ +__define_stab (N_GSYM, 0x20, "GSYM") + +/* Function name for BSD Fortran. Only the name is significant. + To find the address, look in the corresponding external symbol. */ +__define_stab (N_FNAME, 0x22, "FNAME") + +/* Function name or text-segment variable for C. Value is its address. + Desc is supposedly starting line number, but GCC doesn't set it + and DBX seems not to miss it. */ +__define_stab (N_FUN, 0x24, "FUN") + +/* Data-segment variable with internal linkage. Value is its address. + "Static Sym". */ +__define_stab (N_STSYM, 0x26, "STSYM") + +/* BSS-segment variable with internal linkage. Value is its address. */ +__define_stab (N_LCSYM, 0x28, "LCSYM") + +/* Name of main routine. Only the name is significant. + This is not used in C. */ +__define_stab (N_MAIN, 0x2a, "MAIN") + +/* Global symbol in Pascal. + Supposedly the value is its line number; I'm skeptical. */ +__define_stab (N_PC, 0x30, "PC") + +/* Number of symbols: 0, files,,funcs,lines according to Ultrix V4.0. */ +__define_stab (N_NSYMS, 0x32, "NSYMS") + +/* "No DST map for sym: name, ,0,type,ignored" according to Ultrix V4.0. */ +__define_stab (N_NOMAP, 0x34, "NOMAP") + +/* New stab from Solaris. I don't know what it means, but it + don't seem to contain useful information. */ +__define_stab (N_OBJ, 0x38, "OBJ") + +/* New stab from Solaris. I don't know what it means, but it + don't seem to contain useful information. Possibly related to the + optimization flags used in this module. */ +__define_stab (N_OPT, 0x3c, "OPT") + +/* Register variable. Value is number of register. */ +__define_stab (N_RSYM, 0x40, "RSYM") + +/* Modula-2 compilation unit. Can someone say what info it contains? */ +__define_stab (N_M2C, 0x42, "M2C") + +/* Line number in text segment. Desc is the line number; + value is corresponding address. */ +__define_stab (N_SLINE, 0x44, "SLINE") + +/* Similar, for data segment. */ +__define_stab (N_DSLINE, 0x46, "DSLINE") + +/* Similar, for bss segment. */ +__define_stab (N_BSLINE, 0x48, "BSLINE") + +/* Sun's source-code browser stabs. ?? Don't know what the fields are. + Supposedly the field is "path to associated .cb file". THIS VALUE + OVERLAPS WITH N_BSLINE! */ +__define_stab (N_BROWS, 0x48, "BROWS") + +/* GNU Modula-2 definition module dependency. Value is the modification time + of the definition file. Other is non-zero if it is imported with the + GNU M2 keyword %INITIALIZE. Perhaps N_M2C can be used if there + are enough empty fields? */ +__define_stab(N_DEFD, 0x4a, "DEFD") + +/* THE FOLLOWING TWO STAB VALUES CONFLICT. Happily, one is for Modula-2 + and one is for C++. Still,... */ +/* GNU C++ exception variable. Name is variable name. */ +__define_stab (N_EHDECL, 0x50, "EHDECL") +/* Modula2 info "for imc": name,,0,0,0 according to Ultrix V4.0. */ +__define_stab (N_MOD2, 0x50, "MOD2") + +/* GNU C++ `catch' clause. Value is its address. Desc is nonzero if + this entry is immediately followed by a CAUGHT stab saying what exception + was caught. Multiple CAUGHT stabs means that multiple exceptions + can be caught here. If Desc is 0, it means all exceptions are caught + here. */ +__define_stab (N_CATCH, 0x54, "CATCH") + +/* Structure or union element. Value is offset in the structure. */ +__define_stab (N_SSYM, 0x60, "SSYM") + +/* Name of main source file. + Value is starting text address of the compilation. */ +__define_stab (N_SO, 0x64, "SO") + +/* Automatic variable in the stack. Value is offset from frame pointer. + Also used for type descriptions. */ +__define_stab (N_LSYM, 0x80, "LSYM") + +/* Beginning of an include file. Only Sun uses this. + In an object file, only the name is significant. + The Sun linker puts data into some of the other fields. */ +__define_stab (N_BINCL, 0x82, "BINCL") + +/* Name of sub-source file (#include file). + Value is starting text address of the compilation. */ +__define_stab (N_SOL, 0x84, "SOL") + +/* Parameter variable. Value is offset from argument pointer. + (On most machines the argument pointer is the same as the frame pointer. */ +__define_stab (N_PSYM, 0xa0, "PSYM") + +/* End of an include file. No name. + This and N_BINCL act as brackets around the file's output. + In an object file, there is no significant data in this entry. + The Sun linker puts data into some of the fields. */ +__define_stab (N_EINCL, 0xa2, "EINCL") + +/* Alternate entry point. Value is its address. */ +__define_stab (N_ENTRY, 0xa4, "ENTRY") + +/* Beginning of lexical block. + The desc is the nesting level in lexical blocks. + The value is the address of the start of the text for the block. + The variables declared inside the block *precede* the N_LBRAC symbol. */ +__define_stab (N_LBRAC, 0xc0, "LBRAC") + +/* Place holder for deleted include file. Replaces a N_BINCL and everything + up to the corresponding N_EINCL. The Sun linker generates these when + it finds multiple identical copies of the symbols from an include file. + This appears only in output from the Sun linker. */ +__define_stab (N_EXCL, 0xc2, "EXCL") + +/* Modula-2 scope information. Can someone say what info it contains? */ +__define_stab (N_SCOPE, 0xc4, "SCOPE") + +/* End of a lexical block. Desc matches the N_LBRAC's desc. + The value is the address of the end of the text for the block. */ +__define_stab (N_RBRAC, 0xe0, "RBRAC") + +/* Begin named common block. Only the name is significant. */ +__define_stab (N_BCOMM, 0xe2, "BCOMM") + +/* End named common block. Only the name is significant + (and it should match the N_BCOMM). */ +__define_stab (N_ECOMM, 0xe4, "ECOMM") + +/* End common (local name): value is address. + I'm not sure how this is used. */ +__define_stab (N_ECOML, 0xe8, "ECOML") + +/* These STAB's are used on Gould systems for Non-Base register symbols + or something like that. FIXME. I have assigned the values at random + since I don't have a Gould here. Fixups from Gould folk welcome... */ +__define_stab (N_NBTEXT, 0xF0, "NBTEXT") +__define_stab (N_NBDATA, 0xF2, "NBDATA") +__define_stab (N_NBBSS, 0xF4, "NBBSS") +__define_stab (N_NBSTS, 0xF6, "NBSTS") +__define_stab (N_NBLCS, 0xF8, "NBLCS") + +/* Second symbol entry containing a length-value for the preceding entry. + The value is the length. */ +__define_stab (N_LENG, 0xfe, "LENG") + +/* The above information, in matrix format. + + STAB MATRIX + _________________________________________________ + | 00 - 1F are not dbx stab symbols | + | In most cases, the low bit is the EXTernal bit| + + | 00 UNDEF | 02 ABS | 04 TEXT | 06 DATA | + | 01 |EXT | 03 |EXT | 05 |EXT | 07 |EXT | + + | 08 BSS | 0A INDR | 0C FN_SEQ | 0E | + | 09 |EXT | 0B | 0D | 0F | + + | 10 | 12 COMM | 14 SETA | 16 SETT | + | 11 | 13 | 15 | 17 | + + | 18 SETD | 1A SETB | 1C SETV | 1E WARNING| + | 19 | 1B | 1D | 1F FN | + + |_______________________________________________| + | Debug entries with bit 01 set are unused. | + | 20 GSYM | 22 FNAME | 24 FUN | 26 STSYM | + | 28 LCSYM | 2A MAIN | 2C | 2E | + | 30 PC | 32 NSYMS | 34 NOMAP | 36 | + | 38 OBJ | 3A | 3C OPT | 3E | + | 40 RSYM | 42 M2C | 44 SLINE | 46 DSLINE | + | 48 BSLINE*| 4A DEFD | 4C | 4E | + | 50 EHDECL*| 52 | 54 CATCH | 56 | + | 58 | 5A | 5C | 5E | + | 60 SSYM | 62 | 64 SO | 66 | + | 68 | 6A | 6C | 6E | + | 70 | 72 | 74 | 76 | + | 78 | 7A | 7C | 7E | + | 80 LSYM | 82 BINCL | 84 SOL | 86 | + | 88 | 8A | 8C | 8E | + | 90 | 92 | 94 | 96 | + | 98 | 9A | 9C | 9E | + | A0 PSYM | A2 EINCL | A4 ENTRY | A6 | + | A8 | AA | AC | AE | + | B0 | B2 | B4 | B6 | + | B8 | BA | BC | BE | + | C0 LBRAC | C2 EXCL | C4 SCOPE | C6 | + | C8 | CA | CC | CE | + | D0 | D2 | D4 | D6 | + | D8 | DA | DC | DE | + | E0 RBRAC | E2 BCOMM | E4 ECOMM | E6 | + | E8 ECOML | EA | EC | EE | + | F0 | F2 | F4 | F6 | + | F8 | FA | FC | FE LENG | + +-----------------------------------------------+ + * 50 EHDECL is also MOD2. + * 48 BSLINE is also BROWS. + */ diff --git a/tinyc/stab.h b/tinyc/stab.h new file mode 100644 index 000000000..80bd594a3 --- /dev/null +++ b/tinyc/stab.h @@ -0,0 +1,17 @@ +#ifndef __GNU_STAB__ + +/* Indicate the GNU stab.h is in use. */ + +#define __GNU_STAB__ + +#define __define_stab(NAME, CODE, STRING) NAME=CODE, + +enum __stab_debug_code +{ +#include "stab.def" +LAST_UNUSED_STAB_CODE +}; + +#undef __define_stab + +#endif /* __GNU_STAB_ */ diff --git a/tinyc/tcc-doc.texi b/tinyc/tcc-doc.texi new file mode 100644 index 000000000..5e718a2c5 --- /dev/null +++ b/tinyc/tcc-doc.texi @@ -0,0 +1,1326 @@ +\input texinfo @c -*- texinfo -*- +@c %**start of header +@setfilename tcc-doc.info +@settitle Tiny C Compiler Reference Documentation +@dircategory Software development +@direntry +* TCC: (tcc-doc). The Tiny C Compiler. +@end direntry +@c %**end of header + +@include config.texi + +@iftex +@titlepage +@afourpaper +@sp 7 +@center @titlefont{Tiny C Compiler Reference Documentation} +@sp 3 +@end titlepage +@headings double +@end iftex + +@contents + +@node Top, Introduction, (dir), (dir) +@top Tiny C Compiler Reference Documentation + +This manual documents version @value{VERSION} of the Tiny C Compiler. + +@menu +* Introduction:: Introduction to tcc. +* Invoke:: Invocation of tcc (command line, options). +* Clang:: ANSI C and extensions. +* asm:: Assembler syntax. +* linker:: Output file generation and supported targets. +* Bounds:: Automatic bounds-checking of C code. +* Libtcc:: The libtcc library. +* devel:: Guide for Developers. +@end menu + + +@node Introduction +@chapter Introduction + +TinyCC (aka TCC) is a small but hyper fast C compiler. Unlike other C +compilers, it is meant to be self-relying: you do not need an +external assembler or linker because TCC does that for you. + +TCC compiles so @emph{fast} that even for big projects @code{Makefile}s may +not be necessary. + +TCC not only supports ANSI C, but also most of the new ISO C99 +standard and many GNUC extensions including inline assembly. + +TCC can also be used to make @emph{C scripts}, i.e. pieces of C source +that you run as a Perl or Python script. Compilation is so fast that +your script will be as fast as if it was an executable. + +TCC can also automatically generate memory and bound checks +(@pxref{Bounds}) while allowing all C pointers operations. TCC can do +these checks even if non patched libraries are used. + +With @code{libtcc}, you can use TCC as a backend for dynamic code +generation (@pxref{Libtcc}). + +TCC mainly supports the i386 target on Linux and Windows. There are alpha +ports for the ARM (@code{arm-tcc}) and the TMS320C67xx targets +(@code{c67-tcc}). More information about the ARM port is available at +@url{http://lists.gnu.org/archive/html/tinycc-devel/2003-10/msg00044.html}. + +For usage on Windows, see also @url{tcc-win32.txt}. + +@node Invoke +@chapter Command line invocation + +@section Quick start + +@example +@c man begin SYNOPSIS +usage: tcc [options] [@var{infile1} @var{infile2}@dots{}] [@option{-run} @var{infile} @var{args}@dots{}] +@c man end +@end example + +@noindent +@c man begin DESCRIPTION +TCC options are a very much like gcc options. The main difference is that TCC +can also execute directly the resulting program and give it runtime +arguments. + +Here are some examples to understand the logic: + +@table @code +@item @samp{tcc -run a.c} +Compile @file{a.c} and execute it directly + +@item @samp{tcc -run a.c arg1} +Compile a.c and execute it directly. arg1 is given as first argument to +the @code{main()} of a.c. + +@item @samp{tcc a.c -run b.c arg1} +Compile @file{a.c} and @file{b.c}, link them together and execute them. arg1 is given +as first argument to the @code{main()} of the resulting program. +@ignore +Because multiple C files are specified, @option{--} are necessary to clearly +separate the program arguments from the TCC options. +@end ignore + +@item @samp{tcc -o myprog a.c b.c} +Compile @file{a.c} and @file{b.c}, link them and generate the executable @file{myprog}. + +@item @samp{tcc -o myprog a.o b.o} +link @file{a.o} and @file{b.o} together and generate the executable @file{myprog}. + +@item @samp{tcc -c a.c} +Compile @file{a.c} and generate object file @file{a.o}. + +@item @samp{tcc -c asmfile.S} +Preprocess with C preprocess and assemble @file{asmfile.S} and generate +object file @file{asmfile.o}. + +@item @samp{tcc -c asmfile.s} +Assemble (but not preprocess) @file{asmfile.s} and generate object file +@file{asmfile.o}. + +@item @samp{tcc -r -o ab.o a.c b.c} +Compile @file{a.c} and @file{b.c}, link them together and generate the object file @file{ab.o}. + +@end table + +Scripting: + +TCC can be invoked from @emph{scripts}, just as shell scripts. You just +need to add @code{#!/usr/local/bin/tcc -run} at the start of your C source: + +@example +#!/usr/local/bin/tcc -run +#include + +int main() +@{ + printf("Hello World\n"); + return 0; +@} +@end example + +TCC can read C source code from @emph{standard input} when @option{-} is used in +place of @option{infile}. Example: + +@example +echo 'main()@{puts("hello");@}' | tcc -run - +@end example +@c man end + +@section Option summary + +General Options: + +@c man begin OPTIONS +@table @option +@item -c +Generate an object file. + +@item -o outfile +Put object file, executable, or dll into output file @file{outfile}. + +@item -run source [args...] +Compile file @var{source} and run it with the command line arguments +@var{args}. In order to be able to give more than one argument to a +script, several TCC options can be given @emph{after} the +@option{-run} option, separated by spaces: +@example +tcc "-run -L/usr/X11R6/lib -lX11" ex4.c +@end example +In a script, it gives the following header: +@example +#!/usr/local/bin/tcc -run -L/usr/X11R6/lib -lX11 +@end example + +@item -v +Display TCC version. + +@item -vv +Show included files. As sole argument, print search dirs. -vvv shows tries too. + +@item -bench +Display compilation statistics. + +@end table + +Preprocessor options: + +@table @option +@item -Idir +Specify an additional include path. Include paths are searched in the +order they are specified. + +System include paths are always searched after. The default system +include paths are: @file{/usr/local/include}, @file{/usr/include} +and @file{PREFIX/lib/tcc/include}. (@file{PREFIX} is usually +@file{/usr} or @file{/usr/local}). + +@item -Dsym[=val] +Define preprocessor symbol @samp{sym} to +val. If val is not present, its value is @samp{1}. Function-like macros can +also be defined: @option{-DF(a)=a+1} + +@item -Usym +Undefine preprocessor symbol @samp{sym}. + +@item -E +Preprocess only, to stdout or file (with -o). + +@end table + +Compilation flags: + +Note: each of the following options has a negative form beginning with +@option{-fno-}. + +@table @option +@item -funsigned-char +Let the @code{char} type be unsigned. + +@item -fsigned-char +Let the @code{char} type be signed. + +@item -fno-common +Do not generate common symbols for uninitialized data. + +@item -fleading-underscore +Add a leading underscore at the beginning of each C symbol. + +@item -fms-extensions +Allow a MS C compiler extensions to the language. Currently this +assumes a nested named structure declaration without an identifier +behaves like an unnamed one. + +@item -fdollars-in-identifiers +Allow dollar signs in identifiers + +@end table + +Warning options: + +@table @option +@item -w +Disable all warnings. + +@end table + +Note: each of the following warning options has a negative form beginning with +@option{-Wno-}. + +@table @option +@item -Wimplicit-function-declaration +Warn about implicit function declaration. + +@item -Wunsupported +Warn about unsupported GCC features that are ignored by TCC. + +@item -Wwrite-strings +Make string constants be of type @code{const char *} instead of @code{char +*}. + +@item -Werror +Abort compilation if warnings are issued. + +@item -Wall +Activate all warnings, except @option{-Werror}, @option{-Wunusupported} and +@option{-Wwrite-strings}. + +@end table + +Linker options: + +@table @option +@item -Ldir +Specify an additional static library path for the @option{-l} option. The +default library paths are @file{/usr/local/lib}, @file{/usr/lib} and @file{/lib}. + +@item -lxxx +Link your program with dynamic library libxxx.so or static library +libxxx.a. The library is searched in the paths specified by the +@option{-L} option and @env{LIBRARY_PATH} variable. + +@item -Bdir +Set the path where the tcc internal libraries (and include files) can be +found (default is @file{PREFIX/lib/tcc}). + +@item -shared +Generate a shared library instead of an executable. + +@item -soname name +set name for shared library to be used at runtime + +@item -static +Generate a statically linked executable (default is a shared linked +executable). + +@item -rdynamic +Export global symbols to the dynamic linker. It is useful when a library +opened with @code{dlopen()} needs to access executable symbols. + +@item -r +Generate an object file combining all input files. + +@item -Wl,-rpath=path +Put custom search path for dynamic libraries into executable. + +@item -Wl,--enable-new-dtags +When putting a custom search path for dynamic libraries into the executable, +create the new ELF dynamic tag DT_RUNPATH instead of the old legacy DT_RPATH. + +@item -Wl,--oformat=fmt +Use @var{fmt} as output format. The supported output formats are: +@table @code +@item elf32-i386 +ELF output format (default) +@item binary +Binary image (only for executable output) +@item coff +COFF output format (only for executable output for TMS320C67xx target) +@end table + +@item -Wl,-subsystem=console/gui/wince/... +Set type for PE (Windows) executables. + +@item -Wl,-[Ttext=# | section-alignment=# | file-alignment=# | image-base=# | stack=#] +Modify executable layout. + +@item -Wl,-Bsymbolic +Set DT_SYMBOLIC tag. + +@item -Wl,-(no-)whole-archive +Turn on/off linking of all objects in archives. + +@end table + +Debugger options: + +@table @option +@item -g +Generate run time debug information so that you get clear run time +error messages: @code{ test.c:68: in function 'test5()': dereferencing +invalid pointer} instead of the laconic @code{Segmentation +fault}. + +@item -b +Generate additional support code to check +memory allocations and array/pointer bounds. @option{-g} is implied. Note +that the generated code is slower and bigger in this case. + +Note: @option{-b} is only available on i386 when using libtcc for the moment. + +@item -bt N +Display N callers in stack traces. This is useful with @option{-g} or +@option{-b}. + +@end table + +Misc options: + +@table @option +@item -MD +Generate makefile fragment with dependencies. + +@item -MF depfile +Use @file{depfile} as output for -MD. + +@item -print-search-dirs +Print the configured installation directory and a list of library +and include directories tcc will search. + +@item -dumpversion +Print version. + +@end table + +Target specific options: + +@table @option +@item -mms-bitfields +Use an algorithm for bitfield alignment consistent with MSVC. Default is +gcc's algorithm. + +@item -mfloat-abi (ARM only) +Select the float ABI. Possible values: @code{softfp} and @code{hard} + +@item -mno-sse +Do not use sse registers on x86_64 + +@item -m32, -m64 +Pass command line to the i386/x86_64 cross compiler. + +@end table + +Note: GCC options @option{-Ox}, @option{-fx} and @option{-mx} are +ignored. +@c man end + +@c man begin ENVIRONMENT +Environment variables that affect how tcc operates. + +@table @option + +@item CPATH +@item C_INCLUDE_PATH +A colon-separated list of directories searched for include files, +directories given with @option{-I} are searched first. + +@item LIBRARY_PATH +A colon-separated list of directories searched for libraries for the +@option{-l} option, directories given with @option{-L} are searched first. + +@end table + +@c man end + +@ignore + +@setfilename tcc +@settitle Tiny C Compiler + +@c man begin SEEALSO +cpp(1), +gcc(1) +@c man end + +@c man begin AUTHOR +Fabrice Bellard +@c man end + +@end ignore + +@node Clang +@chapter C language support + +@section ANSI C + +TCC implements all the ANSI C standard, including structure bit fields +and floating point numbers (@code{long double}, @code{double}, and +@code{float} fully supported). + +@section ISOC99 extensions + +TCC implements many features of the new C standard: ISO C99. Currently +missing items are: complex and imaginary numbers. + +Currently implemented ISOC99 features: + +@itemize + +@item variable length arrays. + +@item 64 bit @code{long long} types are fully supported. + +@item The boolean type @code{_Bool} is supported. + +@item @code{__func__} is a string variable containing the current +function name. + +@item Variadic macros: @code{__VA_ARGS__} can be used for + function-like macros: +@example + #define dprintf(level, __VA_ARGS__) printf(__VA_ARGS__) +@end example + +@noindent +@code{dprintf} can then be used with a variable number of parameters. + +@item Declarations can appear anywhere in a block (as in C++). + +@item Array and struct/union elements can be initialized in any order by + using designators: +@example + struct @{ int x, y; @} st[10] = @{ [0].x = 1, [0].y = 2 @}; + + int tab[10] = @{ 1, 2, [5] = 5, [9] = 9@}; +@end example + +@item Compound initializers are supported: +@example + int *p = (int [])@{ 1, 2, 3 @}; +@end example +to initialize a pointer pointing to an initialized array. The same +works for structures and strings. + +@item Hexadecimal floating point constants are supported: +@example + double d = 0x1234p10; +@end example + +@noindent +is the same as writing +@example + double d = 4771840.0; +@end example + +@item @code{inline} keyword is ignored. + +@item @code{restrict} keyword is ignored. +@end itemize + +@section GNU C extensions + +TCC implements some GNU C extensions: + +@itemize + +@item array designators can be used without '=': +@example + int a[10] = @{ [0] 1, [5] 2, 3, 4 @}; +@end example + +@item Structure field designators can be a label: +@example + struct @{ int x, y; @} st = @{ x: 1, y: 1@}; +@end example +instead of +@example + struct @{ int x, y; @} st = @{ .x = 1, .y = 1@}; +@end example + +@item @code{\e} is ASCII character 27. + +@item case ranges : ranges can be used in @code{case}s: +@example + switch(a) @{ + case 1 @dots{} 9: + printf("range 1 to 9\n"); + break; + default: + printf("unexpected\n"); + break; + @} +@end example + +@cindex aligned attribute +@cindex packed attribute +@cindex section attribute +@cindex unused attribute +@cindex cdecl attribute +@cindex stdcall attribute +@cindex regparm attribute +@cindex dllexport attribute + +@item The keyword @code{__attribute__} is handled to specify variable or +function attributes. The following attributes are supported: + @itemize + + @item @code{aligned(n)}: align a variable or a structure field to n bytes +(must be a power of two). + + @item @code{packed}: force alignment of a variable or a structure field to + 1. + + @item @code{section(name)}: generate function or data in assembly section +name (name is a string containing the section name) instead of the default +section. + + @item @code{unused}: specify that the variable or the function is unused. + + @item @code{cdecl}: use standard C calling convention (default). + + @item @code{stdcall}: use Pascal-like calling convention. + + @item @code{regparm(n)}: use fast i386 calling convention. @var{n} must be +between 1 and 3. The first @var{n} function parameters are respectively put in +registers @code{%eax}, @code{%edx} and @code{%ecx}. + + @item @code{dllexport}: export function from dll/executable (win32 only) + + @end itemize + +Here are some examples: +@example + int a __attribute__ ((aligned(8), section(".mysection"))); +@end example + +@noindent +align variable @code{a} to 8 bytes and put it in section @code{.mysection}. + +@example + int my_add(int a, int b) __attribute__ ((section(".mycodesection"))) + @{ + return a + b; + @} +@end example + +@noindent +generate function @code{my_add} in section @code{.mycodesection}. + +@item GNU style variadic macros: +@example + #define dprintf(fmt, args@dots{}) printf(fmt, ## args) + + dprintf("no arg\n"); + dprintf("one arg %d\n", 1); +@end example + +@item @code{__FUNCTION__} is interpreted as C99 @code{__func__} +(so it has not exactly the same semantics as string literal GNUC +where it is a string literal). + +@item The @code{__alignof__} keyword can be used as @code{sizeof} +to get the alignment of a type or an expression. + +@item The @code{typeof(x)} returns the type of @code{x}. +@code{x} is an expression or a type. + +@item Computed gotos: @code{&&label} returns a pointer of type +@code{void *} on the goto label @code{label}. @code{goto *expr} can be +used to jump on the pointer resulting from @code{expr}. + +@item Inline assembly with asm instruction: +@cindex inline assembly +@cindex assembly, inline +@cindex __asm__ +@example +static inline void * my_memcpy(void * to, const void * from, size_t n) +@{ +int d0, d1, d2; +__asm__ __volatile__( + "rep ; movsl\n\t" + "testb $2,%b4\n\t" + "je 1f\n\t" + "movsw\n" + "1:\ttestb $1,%b4\n\t" + "je 2f\n\t" + "movsb\n" + "2:" + : "=&c" (d0), "=&D" (d1), "=&S" (d2) + :"0" (n/4), "q" (n),"1" ((long) to),"2" ((long) from) + : "memory"); +return (to); +@} +@end example + +@noindent +@cindex gas +TCC includes its own x86 inline assembler with a @code{gas}-like (GNU +assembler) syntax. No intermediate files are generated. GCC 3.x named +operands are supported. + +@item @code{__builtin_types_compatible_p()} and @code{__builtin_constant_p()} +are supported. + +@item @code{#pragma pack} is supported for win32 compatibility. + +@end itemize + +@section TinyCC extensions + +@itemize + +@item @code{__TINYC__} is a predefined macro to indicate that you use TCC. + +@item @code{#!} at the start of a line is ignored to allow scripting. + +@item Binary digits can be entered (@code{0b101} instead of +@code{5}). + +@item @code{__BOUNDS_CHECKING_ON} is defined if bound checking is activated. + +@end itemize + +@node asm +@chapter TinyCC Assembler + +Since version 0.9.16, TinyCC integrates its own assembler. TinyCC +assembler supports a gas-like syntax (GNU assembler). You can +deactivate assembler support if you want a smaller TinyCC executable +(the C compiler does not rely on the assembler). + +TinyCC Assembler is used to handle files with @file{.S} (C +preprocessed assembler) and @file{.s} extensions. It is also used to +handle the GNU inline assembler with the @code{asm} keyword. + +@section Syntax + +TinyCC Assembler supports most of the gas syntax. The tokens are the +same as C. + +@itemize + +@item C and C++ comments are supported. + +@item Identifiers are the same as C, so you cannot use '.' or '$'. + +@item Only 32 bit integer numbers are supported. + +@end itemize + +@section Expressions + +@itemize + +@item Integers in decimal, octal and hexa are supported. + +@item Unary operators: +, -, ~. + +@item Binary operators in decreasing priority order: + +@enumerate +@item *, /, % +@item &, |, ^ +@item +, - +@end enumerate + +@item A value is either an absolute number or a label plus an offset. +All operators accept absolute values except '+' and '-'. '+' or '-' can be +used to add an offset to a label. '-' supports two labels only if they +are the same or if they are both defined and in the same section. + +@end itemize + +@section Labels + +@itemize + +@item All labels are considered as local, except undefined ones. + +@item Numeric labels can be used as local @code{gas}-like labels. +They can be defined several times in the same source. Use 'b' +(backward) or 'f' (forward) as suffix to reference them: + +@example + 1: + jmp 1b /* jump to '1' label before */ + jmp 1f /* jump to '1' label after */ + 1: +@end example + +@end itemize + +@section Directives +@cindex assembler directives +@cindex directives, assembler +@cindex align directive +@cindex skip directive +@cindex space directive +@cindex byte directive +@cindex word directive +@cindex short directive +@cindex int directive +@cindex long directive +@cindex quad directive +@cindex globl directive +@cindex global directive +@cindex section directive +@cindex text directive +@cindex data directive +@cindex bss directive +@cindex fill directive +@cindex org directive +@cindex previous directive +@cindex string directive +@cindex asciz directive +@cindex ascii directive + +All directives are preceded by a '.'. The following directives are +supported: + +@itemize +@item .align n[,value] +@item .skip n[,value] +@item .space n[,value] +@item .byte value1[,...] +@item .word value1[,...] +@item .short value1[,...] +@item .int value1[,...] +@item .long value1[,...] +@item .quad immediate_value1[,...] +@item .globl symbol +@item .global symbol +@item .section section +@item .text +@item .data +@item .bss +@item .fill repeat[,size[,value]] +@item .org n +@item .previous +@item .string string[,...] +@item .asciz string[,...] +@item .ascii string[,...] +@end itemize + +@section X86 Assembler +@cindex assembler + +All X86 opcodes are supported. Only ATT syntax is supported (source +then destination operand order). If no size suffix is given, TinyCC +tries to guess it from the operand sizes. + +Currently, MMX opcodes are supported but not SSE ones. + +@node linker +@chapter TinyCC Linker +@cindex linker + +@section ELF file generation +@cindex ELF + +TCC can directly output relocatable ELF files (object files), +executable ELF files and dynamic ELF libraries without relying on an +external linker. + +Dynamic ELF libraries can be output but the C compiler does not generate +position independent code (PIC). It means that the dynamic library +code generated by TCC cannot be factorized among processes yet. + +TCC linker eliminates unreferenced object code in libraries. A single pass is +done on the object and library list, so the order in which object files and +libraries are specified is important (same constraint as GNU ld). No grouping +options (@option{--start-group} and @option{--end-group}) are supported. + +@section ELF file loader + +TCC can load ELF object files, archives (.a files) and dynamic +libraries (.so). + +@section PE-i386 file generation +@cindex PE-i386 + +TCC for Windows supports the native Win32 executable file format (PE-i386). It +generates EXE files (console and gui) and DLL files. + +For usage on Windows, see also tcc-win32.txt. + +@section GNU Linker Scripts +@cindex scripts, linker +@cindex linker scripts +@cindex GROUP, linker command +@cindex FILE, linker command +@cindex OUTPUT_FORMAT, linker command +@cindex TARGET, linker command + +Because on many Linux systems some dynamic libraries (such as +@file{/usr/lib/libc.so}) are in fact GNU ld link scripts (horrible!), +the TCC linker also supports a subset of GNU ld scripts. + +The @code{GROUP} and @code{FILE} commands are supported. @code{OUTPUT_FORMAT} +and @code{TARGET} are ignored. + +Example from @file{/usr/lib/libc.so}: +@example +/* GNU ld script + Use the shared library, but some functions are only in + the static library, so try that secondarily. */ +GROUP ( /lib/libc.so.6 /usr/lib/libc_nonshared.a ) +@end example + +@node Bounds +@chapter TinyCC Memory and Bound checks +@cindex bound checks +@cindex memory checks + +This feature is activated with the @option{-b} (@pxref{Invoke}). + +Note that pointer size is @emph{unchanged} and that code generated +with bound checks is @emph{fully compatible} with unchecked +code. When a pointer comes from unchecked code, it is assumed to be +valid. Even very obscure C code with casts should work correctly. + +For more information about the ideas behind this method, see +@url{http://www.doc.ic.ac.uk/~phjk/BoundsChecking.html}. + +Here are some examples of caught errors: + +@table @asis + +@item Invalid range with standard string function: +@example +@{ + char tab[10]; + memset(tab, 0, 11); +@} +@end example + +@item Out of bounds-error in global or local arrays: +@example +@{ + int tab[10]; + for(i=0;i<11;i++) @{ + sum += tab[i]; + @} +@} +@end example + +@item Out of bounds-error in malloc'ed data: +@example +@{ + int *tab; + tab = malloc(20 * sizeof(int)); + for(i=0;i<21;i++) @{ + sum += tab4[i]; + @} + free(tab); +@} +@end example + +@item Access of freed memory: +@example +@{ + int *tab; + tab = malloc(20 * sizeof(int)); + free(tab); + for(i=0;i<20;i++) @{ + sum += tab4[i]; + @} +@} +@end example + +@item Double free: +@example +@{ + int *tab; + tab = malloc(20 * sizeof(int)); + free(tab); + free(tab); +@} +@end example + +@end table + +@node Libtcc +@chapter The @code{libtcc} library + +The @code{libtcc} library enables you to use TCC as a backend for +dynamic code generation. + +Read the @file{libtcc.h} to have an overview of the API. Read +@file{libtcc_test.c} to have a very simple example. + +The idea consists in giving a C string containing the program you want +to compile directly to @code{libtcc}. Then you can access to any global +symbol (function or variable) defined. + +@node devel +@chapter Developer's guide + +This chapter gives some hints to understand how TCC works. You can skip +it if you do not intend to modify the TCC code. + +@section File reading + +The @code{BufferedFile} structure contains the context needed to read a +file, including the current line number. @code{tcc_open()} opens a new +file and @code{tcc_close()} closes it. @code{inp()} returns the next +character. + +@section Lexer + +@code{next()} reads the next token in the current +file. @code{next_nomacro()} reads the next token without macro +expansion. + +@code{tok} contains the current token (see @code{TOK_xxx}) +constants. Identifiers and keywords are also keywords. @code{tokc} +contains additional infos about the token (for example a constant value +if number or string token). + +@section Parser + +The parser is hardcoded (yacc is not necessary). It does only one pass, +except: + +@itemize + +@item For initialized arrays with unknown size, a first pass +is done to count the number of elements. + +@item For architectures where arguments are evaluated in +reverse order, a first pass is done to reverse the argument order. + +@end itemize + +@section Types + +The types are stored in a single 'int' variable. It was chosen in the +first stages of development when tcc was much simpler. Now, it may not +be the best solution. + +@example +#define VT_INT 0 /* integer type */ +#define VT_BYTE 1 /* signed byte type */ +#define VT_SHORT 2 /* short type */ +#define VT_VOID 3 /* void type */ +#define VT_PTR 4 /* pointer */ +#define VT_ENUM 5 /* enum definition */ +#define VT_FUNC 6 /* function type */ +#define VT_STRUCT 7 /* struct/union definition */ +#define VT_FLOAT 8 /* IEEE float */ +#define VT_DOUBLE 9 /* IEEE double */ +#define VT_LDOUBLE 10 /* IEEE long double */ +#define VT_BOOL 11 /* ISOC99 boolean type */ +#define VT_LLONG 12 /* 64 bit integer */ +#define VT_LONG 13 /* long integer (NEVER USED as type, only + during parsing) */ +#define VT_BTYPE 0x000f /* mask for basic type */ +#define VT_UNSIGNED 0x0010 /* unsigned type */ +#define VT_ARRAY 0x0020 /* array type (also has VT_PTR) */ +#define VT_VLA 0x20000 /* VLA type (also has VT_PTR and VT_ARRAY) */ +#define VT_BITFIELD 0x0040 /* bitfield modifier */ +#define VT_CONSTANT 0x0800 /* const modifier */ +#define VT_VOLATILE 0x1000 /* volatile modifier */ +#define VT_DEFSIGN 0x2000 /* signed type */ + +#define VT_STRUCT_SHIFT 18 /* structure/enum name shift (14 bits left) */ +@end example + +When a reference to another type is needed (for pointers, functions and +structures), the @code{32 - VT_STRUCT_SHIFT} high order bits are used to +store an identifier reference. + +The @code{VT_UNSIGNED} flag can be set for chars, shorts, ints and long +longs. + +Arrays are considered as pointers @code{VT_PTR} with the flag +@code{VT_ARRAY} set. Variable length arrays are considered as special +arrays and have flag @code{VT_VLA} set instead of @code{VT_ARRAY}. + +The @code{VT_BITFIELD} flag can be set for chars, shorts, ints and long +longs. If it is set, then the bitfield position is stored from bits +VT_STRUCT_SHIFT to VT_STRUCT_SHIFT + 5 and the bit field size is stored +from bits VT_STRUCT_SHIFT + 6 to VT_STRUCT_SHIFT + 11. + +@code{VT_LONG} is never used except during parsing. + +During parsing, the storage of an object is also stored in the type +integer: + +@example +#define VT_EXTERN 0x00000080 /* extern definition */ +#define VT_STATIC 0x00000100 /* static variable */ +#define VT_TYPEDEF 0x00000200 /* typedef definition */ +#define VT_INLINE 0x00000400 /* inline definition */ +#define VT_IMPORT 0x00004000 /* win32: extern data imported from dll */ +#define VT_EXPORT 0x00008000 /* win32: data exported from dll */ +#define VT_WEAK 0x00010000 /* win32: data exported from dll */ +@end example + +@section Symbols + +All symbols are stored in hashed symbol stacks. Each symbol stack +contains @code{Sym} structures. + +@code{Sym.v} contains the symbol name (remember +an identifier is also a token, so a string is never necessary to store +it). @code{Sym.t} gives the type of the symbol. @code{Sym.r} is usually +the register in which the corresponding variable is stored. @code{Sym.c} is +usually a constant associated to the symbol like its address for normal +symbols, and the number of entries for symbols representing arrays. +Variable length array types use @code{Sym.c} as a location on the stack +which holds the runtime sizeof for the type. + +Four main symbol stacks are defined: + +@table @code + +@item define_stack +for the macros (@code{#define}s). + +@item global_stack +for the global variables, functions and types. + +@item local_stack +for the local variables, functions and types. + +@item global_label_stack +for the local labels (for @code{goto}). + +@item label_stack +for GCC block local labels (see the @code{__label__} keyword). + +@end table + +@code{sym_push()} is used to add a new symbol in the local symbol +stack. If no local symbol stack is active, it is added in the global +symbol stack. + +@code{sym_pop(st,b)} pops symbols from the symbol stack @var{st} until +the symbol @var{b} is on the top of stack. If @var{b} is NULL, the stack +is emptied. + +@code{sym_find(v)} return the symbol associated to the identifier +@var{v}. The local stack is searched first from top to bottom, then the +global stack. + +@section Sections + +The generated code and data are written in sections. The structure +@code{Section} contains all the necessary information for a given +section. @code{new_section()} creates a new section. ELF file semantics +is assumed for each section. + +The following sections are predefined: + +@table @code + +@item text_section +is the section containing the generated code. @var{ind} contains the +current position in the code section. + +@item data_section +contains initialized data + +@item bss_section +contains uninitialized data + +@item bounds_section +@itemx lbounds_section +are used when bound checking is activated + +@item stab_section +@itemx stabstr_section +are used when debugging is active to store debug information + +@item symtab_section +@itemx strtab_section +contain the exported symbols (currently only used for debugging). + +@end table + +@section Code generation +@cindex code generation + +@subsection Introduction + +The TCC code generator directly generates linked binary code in one +pass. It is rather unusual these days (see gcc for example which +generates text assembly), but it can be very fast and surprisingly +little complicated. + +The TCC code generator is register based. Optimization is only done at +the expression level. No intermediate representation of expression is +kept except the current values stored in the @emph{value stack}. + +On x86, three temporary registers are used. When more registers are +needed, one register is spilled into a new temporary variable on the stack. + +@subsection The value stack +@cindex value stack, introduction + +When an expression is parsed, its value is pushed on the value stack +(@var{vstack}). The top of the value stack is @var{vtop}. Each value +stack entry is the structure @code{SValue}. + +@code{SValue.t} is the type. @code{SValue.r} indicates how the value is +currently stored in the generated code. It is usually a CPU register +index (@code{REG_xxx} constants), but additional values and flags are +defined: + +@example +#define VT_CONST 0x00f0 +#define VT_LLOCAL 0x00f1 +#define VT_LOCAL 0x00f2 +#define VT_CMP 0x00f3 +#define VT_JMP 0x00f4 +#define VT_JMPI 0x00f5 +#define VT_LVAL 0x0100 +#define VT_SYM 0x0200 +#define VT_MUSTCAST 0x0400 +#define VT_MUSTBOUND 0x0800 +#define VT_BOUNDED 0x8000 +#define VT_LVAL_BYTE 0x1000 +#define VT_LVAL_SHORT 0x2000 +#define VT_LVAL_UNSIGNED 0x4000 +#define VT_LVAL_TYPE (VT_LVAL_BYTE | VT_LVAL_SHORT | VT_LVAL_UNSIGNED) +@end example + +@table @code + +@item VT_CONST +indicates that the value is a constant. It is stored in the union +@code{SValue.c}, depending on its type. + +@item VT_LOCAL +indicates a local variable pointer at offset @code{SValue.c.i} in the +stack. + +@item VT_CMP +indicates that the value is actually stored in the CPU flags (i.e. the +value is the consequence of a test). The value is either 0 or 1. The +actual CPU flags used is indicated in @code{SValue.c.i}. + +If any code is generated which destroys the CPU flags, this value MUST be +put in a normal register. + +@item VT_JMP +@itemx VT_JMPI +indicates that the value is the consequence of a conditional jump. For VT_JMP, +it is 1 if the jump is taken, 0 otherwise. For VT_JMPI it is inverted. + +These values are used to compile the @code{||} and @code{&&} logical +operators. + +If any code is generated, this value MUST be put in a normal +register. Otherwise, the generated code won't be executed if the jump is +taken. + +@item VT_LVAL +is a flag indicating that the value is actually an lvalue (left value of +an assignment). It means that the value stored is actually a pointer to +the wanted value. + +Understanding the use @code{VT_LVAL} is very important if you want to +understand how TCC works. + +@item VT_LVAL_BYTE +@itemx VT_LVAL_SHORT +@itemx VT_LVAL_UNSIGNED +if the lvalue has an integer type, then these flags give its real +type. The type alone is not enough in case of cast optimisations. + +@item VT_LLOCAL +is a saved lvalue on the stack. @code{VT_LVAL} must also be set with +@code{VT_LLOCAL}. @code{VT_LLOCAL} can arise when a @code{VT_LVAL} in +a register has to be saved to the stack, or it can come from an +architecture-specific calling convention. + +@item VT_MUSTCAST +indicates that a cast to the value type must be performed if the value +is used (lazy casting). + +@item VT_SYM +indicates that the symbol @code{SValue.sym} must be added to the constant. + +@item VT_MUSTBOUND +@itemx VT_BOUNDED +are only used for optional bound checking. + +@end table + +@subsection Manipulating the value stack +@cindex value stack + +@code{vsetc()} and @code{vset()} pushes a new value on the value +stack. If the previous @var{vtop} was stored in a very unsafe place(for +example in the CPU flags), then some code is generated to put the +previous @var{vtop} in a safe storage. + +@code{vpop()} pops @var{vtop}. In some cases, it also generates cleanup +code (for example if stacked floating point registers are used as on +x86). + +The @code{gv(rc)} function generates code to evaluate @var{vtop} (the +top value of the stack) into registers. @var{rc} selects in which +register class the value should be put. @code{gv()} is the @emph{most +important function} of the code generator. + +@code{gv2()} is the same as @code{gv()} but for the top two stack +entries. + +@subsection CPU dependent code generation +@cindex CPU dependent +See the @file{i386-gen.c} file to have an example. + +@table @code + +@item load() +must generate the code needed to load a stack value into a register. + +@item store() +must generate the code needed to store a register into a stack value +lvalue. + +@item gfunc_start() +@itemx gfunc_param() +@itemx gfunc_call() +should generate a function call + +@item gfunc_prolog() +@itemx gfunc_epilog() +should generate a function prolog/epilog. + +@item gen_opi(op) +must generate the binary integer operation @var{op} on the two top +entries of the stack which are guaranteed to contain integer types. + +The result value should be put on the stack. + +@item gen_opf(op) +same as @code{gen_opi()} for floating point operations. The two top +entries of the stack are guaranteed to contain floating point values of +same types. + +@item gen_cvt_itof() +integer to floating point conversion. + +@item gen_cvt_ftoi() +floating point to integer conversion. + +@item gen_cvt_ftof() +floating point to floating point of different size conversion. + +@item gen_bounded_ptr_add() +@item gen_bounded_ptr_deref() +are only used for bounds checking. + +@end table + +@section Optimizations done +@cindex optimizations +@cindex constant propagation +@cindex strength reduction +@cindex comparison operators +@cindex caching processor flags +@cindex flags, caching +@cindex jump optimization +Constant propagation is done for all operations. Multiplications and +divisions are optimized to shifts when appropriate. Comparison +operators are optimized by maintaining a special cache for the +processor flags. &&, || and ! are optimized by maintaining a special +'jump target' value. No other jump optimization is currently performed +because it would require to store the code in a more abstract fashion. + +@unnumbered Concept Index +@printindex cp + +@bye + +@c Local variables: +@c fill-column: 78 +@c texinfo-column-for-description: 32 +@c End: diff --git a/tinyc/tcc.c b/tinyc/tcc.c new file mode 100644 index 000000000..c347a06ea --- /dev/null +++ b/tinyc/tcc.c @@ -0,0 +1,371 @@ +/* + * TCC - Tiny C Compiler + * + * Copyright (c) 2001-2004 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "tcc.h" +#if ONE_SOURCE +# include "libtcc.c" +#endif +#include "tcctools.c" + +static const char help[] = + "Tiny C Compiler "TCC_VERSION" - Copyright (C) 2001-2006 Fabrice Bellard\n" + "Usage: tcc [options...] [-o outfile] [-c] infile(s)...\n" + " tcc [options...] -run infile [arguments...]\n" + "General options:\n" + " -c compile only - generate an object file\n" + " -o outfile set output filename\n" + " -run run compiled source\n" + " -fflag set or reset (with 'no-' prefix) 'flag' (see tcc -hh)\n" + " -Wwarning set or reset (with 'no-' prefix) 'warning' (see tcc -hh)\n" + " -w disable all warnings\n" + " -v -vv show version, show search paths or loaded files\n" + " -h -hh show this, show more help\n" + " -bench show compilation statistics\n" + " - use stdin pipe as infile\n" + " @listfile read arguments from listfile\n" + "Preprocessor options:\n" + " -Idir add include path 'dir'\n" + " -Dsym[=val] define 'sym' with value 'val'\n" + " -Usym undefine 'sym'\n" + " -E preprocess only\n" + "Linker options:\n" + " -Ldir add library path 'dir'\n" + " -llib link with dynamic or static library 'lib'\n" + " -r generate (relocatable) object file\n" + " -shared generate a shared library/dll\n" + " -rdynamic export all global symbols to dynamic linker\n" + " -soname set name for shared library to be used at runtime\n" + " -Wl,-opt[=val] set linker option (see tcc -hh)\n" + "Debugger options:\n" + " -g generate runtime debug info\n" +#ifdef CONFIG_TCC_BCHECK + " -b compile with built-in memory and bounds checker (implies -g)\n" +#endif +#ifdef CONFIG_TCC_BACKTRACE + " -bt N show N callers in stack traces\n" +#endif + "Misc. options:\n" + " -x[c|a|n] specify type of the next infile\n" + " -nostdinc do not use standard system include paths\n" + " -nostdlib do not link with standard crt and libraries\n" + " -Bdir set tcc's private include/library dir\n" + " -MD generate dependency file for make\n" + " -MF file specify dependency file name\n" + " -m32/64 defer to i386/x86_64 cross compiler\n" + "Tools:\n" + " create library : tcc -ar [rcsv] lib.a files\n" +#ifdef TCC_TARGET_PE + " create def file : tcc -impdef lib.dll [-v] [-o lib.def]\n" +#endif + ; + +static const char help2[] = + "Tiny C Compiler "TCC_VERSION" - More Options\n" + "Special options:\n" + " -P -P1 with -E: no/alternative #line output\n" + " -dD -dM with -E: output #define directives\n" + " -pthread same as -D_REENTRANT and -lpthread\n" + " -On same as -D__OPTIMIZE__ for n > 0\n" + " -Wp,-opt same as -opt\n" + " -include file include 'file' above each input file\n" + " -isystem dir add 'dir' to system include path\n" + " -static link to static libraries (not recommended)\n" + " -dumpversion print version\n" + " -print-search-dirs print search paths\n" + " -dt with -run/-E: auto-define 'test_...' macros\n" + "Ignored options:\n" + " --param -pedantic -pipe -s -std -traditional\n" + "-W... warnings:\n" + " all turn on some (*) warnings\n" + " error stop after first warning\n" + " unsupported warn about ignored options, pragmas, etc.\n" + " write-strings strings are const\n" + " implicit-function-declaration warn for missing prototype (*)\n" + "-f[no-]... flags:\n" + " unsigned-char default char is unsigned\n" + " signed-char default char is signed\n" + " common use common section instead of bss\n" + " leading-underscore decorate extern symbols\n" + " ms-extensions allow anonymous struct in struct\n" + " dollars-in-identifiers allow '$' in C symbols\n" + "-m... target specific options:\n" + " ms-bitfields use MSVC bitfield layout\n" +#ifdef TCC_TARGET_ARM + " float-abi hard/softfp on arm\n" +#endif +#ifdef TCC_TARGET_X86_64 + " no-sse disable floats on x86_64\n" +#endif + "-Wl,... linker options:\n" + " -nostdlib do not link with standard crt/libs\n" + " -[no-]whole-archive load lib(s) fully/only as needed\n" + " -export-all-symbols same as -rdynamic\n" + " -image-base= -Ttext= set base address of executable\n" + " -section-alignment= set section alignment in executable\n" +#ifdef TCC_TARGET_PE + " -file-alignment= set PE file alignment\n" + " -stack= set PE stack reserve\n" + " -large-address-aware set related PE option\n" + " -subsystem=[console/windows] set PE subsystem\n" + " -oformat=[pe-* binary] set executable output format\n" + "Predefined macros:\n" + " tcc -E -dM - < nul\n" +#else + " -rpath= set dynamic library search path\n" + " -enable-new-dtags set DT_RUNPATH instead of DT_RPATH\n" + " -soname= set DT_SONAME elf tag\n" + " -Bsymbolic set DT_SYMBOLIC elf tag\n" + " -oformat=[elf32/64-* binary] set executable output format\n" + " -init= -fini= -as-needed -O (ignored)\n" + "Predefined macros:\n" + " tcc -E -dM - < /dev/null\n" +#endif + "See also the manual for more details.\n" + ; + +static const char version[] = + "tcc version "TCC_VERSION" (" +#ifdef TCC_TARGET_I386 + "i386" +#elif defined TCC_TARGET_X86_64 + "x86_64" +#elif defined TCC_TARGET_C67 + "C67" +#elif defined TCC_TARGET_ARM + "ARM" +#elif defined TCC_TARGET_ARM64 + "AArch64" +#endif +#ifdef TCC_ARM_HARDFLOAT + " Hard Float" +#endif +#ifdef TCC_TARGET_PE + " Windows" +#elif defined(TCC_TARGET_MACHO) + " Darwin" +#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) + " FreeBSD" +#else + " Linux" +#endif + ")\n" + ; + +static void print_dirs(const char *msg, char **paths, int nb_paths) +{ + int i; + printf("%s:\n%s", msg, nb_paths ? "" : " -\n"); + for(i = 0; i < nb_paths; i++) + printf(" %s\n", paths[i]); +} + +static void print_search_dirs(TCCState *s) +{ + printf("install: %s\n", s->tcc_lib_path); + /* print_dirs("programs", NULL, 0); */ + print_dirs("include", s->sysinclude_paths, s->nb_sysinclude_paths); + print_dirs("libraries", s->library_paths, s->nb_library_paths); +#ifndef TCC_TARGET_PE + print_dirs("crt", s->crt_paths, s->nb_crt_paths); + printf("libtcc1:\n %s/"TCC_LIBTCC1"\n", s->tcc_lib_path); + printf("elfinterp:\n %s\n", DEFAULT_ELFINTERP(s)); +#endif +} + +static void set_environment(TCCState *s) +{ + char * path; + + path = getenv("C_INCLUDE_PATH"); + if(path != NULL) { + tcc_add_sysinclude_path(s, path); + } + path = getenv("CPATH"); + if(path != NULL) { + tcc_add_include_path(s, path); + } + path = getenv("LIBRARY_PATH"); + if(path != NULL) { + tcc_add_library_path(s, path); + } +} + +static char *default_outputfile(TCCState *s, const char *first_file) +{ + char buf[1024]; + char *ext; + const char *name = "a"; + + if (first_file && strcmp(first_file, "-")) + name = tcc_basename(first_file); + snprintf(buf, sizeof(buf), "%s", name); + ext = tcc_fileextension(buf); +#ifdef TCC_TARGET_PE + if (s->output_type == TCC_OUTPUT_DLL) + strcpy(ext, ".dll"); + else + if (s->output_type == TCC_OUTPUT_EXE) + strcpy(ext, ".exe"); + else +#endif + if (s->output_type == TCC_OUTPUT_OBJ && !s->option_r && *ext) + strcpy(ext, ".o"); + else + strcpy(buf, "a.out"); + return tcc_strdup(buf); +} + +static unsigned getclock_ms(void) +{ +#ifdef _WIN32 + return GetTickCount(); +#else + struct timeval tv; + gettimeofday(&tv, NULL); + return tv.tv_sec*1000 + (tv.tv_usec+500)/1000; +#endif +} + +int main(int argc0, char **argv0) +{ + TCCState *s; + int ret, opt, n = 0, t = 0; + unsigned start_time = 0; + const char *first_file; + int argc; char **argv; + FILE *ppfp = stdout; + +redo: + argc = argc0, argv = argv0; + s = tcc_new(); + opt = tcc_parse_args(s, &argc, &argv, 1); + + if ((n | t) == 0) { + if (opt == OPT_HELP) + return printf(help), 1; + if (opt == OPT_HELP2) + return printf(help2), 1; + if (opt == OPT_M32 || opt == OPT_M64) + tcc_tool_cross(s, argv, opt); /* never returns */ + if (s->verbose) + printf(version); + if (opt == OPT_AR) + return tcc_tool_ar(s, argc, argv); +#ifdef TCC_TARGET_PE + if (opt == OPT_IMPDEF) + return tcc_tool_impdef(s, argc, argv); +#endif + if (opt == OPT_V) + return 0; + if (opt == OPT_PRINT_DIRS) { + /* initialize search dirs */ + set_environment(s); + tcc_set_output_type(s, TCC_OUTPUT_MEMORY); + print_search_dirs(s); + return 0; + } + + n = s->nb_files; + if (n == 0) + tcc_error("no input files\n"); + + if (s->output_type == TCC_OUTPUT_PREPROCESS) { + if (s->outfile) { + ppfp = fopen(s->outfile, "w"); + if (!ppfp) + tcc_error("could not write '%s'", s->outfile); + } + } else if (s->output_type == TCC_OUTPUT_OBJ && !s->option_r) { + if (s->nb_libraries) + tcc_error("cannot specify libraries with -c"); + if (n > 1 && s->outfile) + tcc_error("cannot specify output file with -c many files"); + } else { + if (s->option_pthread) + tcc_set_options(s, "-lpthread"); + } + + if (s->do_bench) + start_time = getclock_ms(); + } + + set_environment(s); + if (s->output_type == 0) + s->output_type = TCC_OUTPUT_EXE; + tcc_set_output_type(s, s->output_type); + s->ppfp = ppfp; + + if ((s->output_type == TCC_OUTPUT_MEMORY + || s->output_type == TCC_OUTPUT_PREPROCESS) && (s->dflag & 16)) + s->dflag |= t ? 32 : 0, s->run_test = ++t, n = s->nb_files; + + /* compile or add each files or library */ + for (first_file = NULL, ret = 0;;) { + struct filespec *f = s->files[s->nb_files - n]; + s->filetype = f->type; + s->alacarte_link = f->alacarte; + if (f->type == AFF_TYPE_LIB) { + if (tcc_add_library_err(s, f->name) < 0) + ret = 1; + } else { + if (1 == s->verbose) + printf("-> %s\n", f->name); + if (!first_file) + first_file = f->name; + if (tcc_add_file(s, f->name) < 0) + ret = 1; + } + s->filetype = 0; + s->alacarte_link = 1; + if (--n == 0 || ret + || (s->output_type == TCC_OUTPUT_OBJ && !s->option_r)) + break; + } + + if (s->run_test) { + t = 0; + } else if (s->output_type == TCC_OUTPUT_PREPROCESS) { + ; + } else if (0 == ret) { + if (s->output_type == TCC_OUTPUT_MEMORY) { +#ifdef TCC_IS_NATIVE + ret = tcc_run(s, argc, argv); +#endif + } else { + if (!s->outfile) + s->outfile = default_outputfile(s, first_file); + if (tcc_output_file(s, s->outfile)) + ret = 1; + else if (s->gen_deps) + gen_makedeps(s, s->outfile, s->deps_outfile); + } + } + + if (s->do_bench && (n | t | ret) == 0) + tcc_print_stats(s, getclock_ms() - start_time); + tcc_delete(s); + if (ret == 0 && n) + goto redo; /* compile more files with -c */ + if (t) + goto redo; /* run more tests with -dt -run */ + if (ppfp && ppfp != stdout) + fclose(ppfp); + return ret; +} diff --git a/tinyc/tcc.h b/tinyc/tcc.h new file mode 100644 index 000000000..da26298fb --- /dev/null +++ b/tinyc/tcc.h @@ -0,0 +1,1657 @@ +/* + * TCC - Tiny C Compiler + * + * Copyright (c) 2001-2004 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _TCC_H +#define _TCC_H + +#define _GNU_SOURCE +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef _WIN32 +# include +# include +# ifndef CONFIG_TCC_STATIC +# include +# endif +/* XXX: need to define this to use them in non ISOC99 context */ +extern float strtof (const char *__nptr, char **__endptr); +extern long double strtold (const char *__nptr, char **__endptr); +#endif + +#ifdef _WIN32 +# include +# include /* open, close etc. */ +# include /* getcwd */ +# ifdef __GNUC__ +# include +# endif +# define inline __inline +# define snprintf _snprintf +# define vsnprintf _vsnprintf +# ifndef __GNUC__ +# define strtold (long double)strtod +# define strtof (float)strtod +# define strtoll _strtoi64 +# define strtoull _strtoui64 +# endif +# ifdef LIBTCC_AS_DLL +# define LIBTCCAPI __declspec(dllexport) +# define PUB_FUNC LIBTCCAPI +# endif +# define inp next_inp /* inp is an intrinsic on msvc/mingw */ +# ifdef _MSC_VER +# pragma warning (disable : 4244) // conversion from 'uint64_t' to 'int', possible loss of data +# pragma warning (disable : 4267) // conversion from 'size_t' to 'int', possible loss of data +# pragma warning (disable : 4996) // The POSIX name for this item is deprecated. Instead, use the ISO C and C++ conformant name +# pragma warning (disable : 4018) // signed/unsigned mismatch +# pragma warning (disable : 4146) // unary minus operator applied to unsigned type, result still unsigned +# define ssize_t intptr_t +# endif +# undef CONFIG_TCC_STATIC +#endif + +#ifndef O_BINARY +# define O_BINARY 0 +#endif + +#ifndef offsetof +#define offsetof(type, field) ((size_t) &((type *)0)->field) +#endif + +#ifndef countof +#define countof(tab) (sizeof(tab) / sizeof((tab)[0])) +#endif + +#ifdef _MSC_VER +# define NORETURN __declspec(noreturn) +# define ALIGNED(x) __declspec(align(x)) +#else +# define NORETURN __attribute__((noreturn)) +# define ALIGNED(x) __attribute__((aligned(x))) +#endif + +#ifdef _WIN32 +# define IS_DIRSEP(c) (c == '/' || c == '\\') +# define IS_ABSPATH(p) (IS_DIRSEP(p[0]) || (p[0] && p[1] == ':' && IS_DIRSEP(p[2]))) +# define PATHCMP stricmp +# define PATHSEP ";" +#else +# define IS_DIRSEP(c) (c == '/') +# define IS_ABSPATH(p) IS_DIRSEP(p[0]) +# define PATHCMP strcmp +# define PATHSEP ":" +#endif + +/* -------------------------------------------- */ + +/* parser debug */ +/* #define PARSE_DEBUG */ +/* preprocessor debug */ +/* #define PP_DEBUG */ +/* include file debug */ +/* #define INC_DEBUG */ +/* memory leak debug */ +/* #define MEM_DEBUG */ +/* assembler debug */ +/* #define ASM_DEBUG */ + +/* target selection */ +/* #define TCC_TARGET_I386 *//* i386 code generator */ +/* #define TCC_TARGET_X86_64 *//* x86-64 code generator */ +/* #define TCC_TARGET_ARM *//* ARMv4 code generator */ +/* #define TCC_TARGET_ARM64 *//* ARMv8 code generator */ +/* #define TCC_TARGET_C67 *//* TMS320C67xx code generator */ + +/* default target is I386 */ +#if !defined(TCC_TARGET_I386) && !defined(TCC_TARGET_ARM) && \ + !defined(TCC_TARGET_ARM64) && !defined(TCC_TARGET_C67) && \ + !defined(TCC_TARGET_X86_64) +# if defined __x86_64__ || defined _AMD64_ +# define TCC_TARGET_X86_64 +# elif defined __arm__ +# define TCC_TARGET_ARM +# define TCC_ARM_EABI +# define TCC_ARM_HARDFLOAT +# elif defined __aarch64__ +# define TCC_TARGET_ARM64 +# else +# define TCC_TARGET_I386 +# endif +# ifdef _WIN32 +# define TCC_TARGET_PE 1 +# endif +#endif + +/* only native compiler supports -run */ +#if defined _WIN32 == defined TCC_TARGET_PE +# if (defined __i386__ || defined _X86_) && defined TCC_TARGET_I386 +# define TCC_IS_NATIVE +# elif (defined __x86_64__ || defined _AMD64_) && defined TCC_TARGET_X86_64 +# define TCC_IS_NATIVE +# elif defined __arm__ && defined TCC_TARGET_ARM +# define TCC_IS_NATIVE +# elif defined __aarch64__ && defined TCC_TARGET_ARM64 +# define TCC_IS_NATIVE +# endif +#endif + +#if defined TCC_IS_NATIVE && !defined CONFIG_TCCBOOT +# define CONFIG_TCC_BACKTRACE +# if (defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64) \ + && !defined TCC_UCLIBC && !defined TCC_MUSL +# define CONFIG_TCC_BCHECK /* enable bound checking code */ +# endif +#endif + +/* ------------ path configuration ------------ */ + +#ifndef CONFIG_SYSROOT +# define CONFIG_SYSROOT "" +#endif +#ifndef CONFIG_TCCDIR +# define CONFIG_TCCDIR "/usr/local/lib/tcc" +#endif +#ifndef CONFIG_LDDIR +# define CONFIG_LDDIR "lib" +#endif +#ifdef CONFIG_TRIPLET +# define USE_TRIPLET(s) s "/" CONFIG_TRIPLET +# define ALSO_TRIPLET(s) USE_TRIPLET(s) ":" s +#else +# define USE_TRIPLET(s) s +# define ALSO_TRIPLET(s) s +#endif + +/* path to find crt1.o, crti.o and crtn.o */ +#ifndef CONFIG_TCC_CRTPREFIX +# define CONFIG_TCC_CRTPREFIX USE_TRIPLET(CONFIG_SYSROOT "/usr/" CONFIG_LDDIR) +#endif + +/* Below: {B} is substituted by CONFIG_TCCDIR (rsp. -B option) */ + +/* system include paths */ +#ifndef CONFIG_TCC_SYSINCLUDEPATHS +# ifdef TCC_TARGET_PE +# define CONFIG_TCC_SYSINCLUDEPATHS "{B}/include"PATHSEP"{B}/include/winapi" +# else +# define CONFIG_TCC_SYSINCLUDEPATHS \ + "{B}/include" \ + ":" ALSO_TRIPLET(CONFIG_SYSROOT "/usr/local/include") \ + ":" ALSO_TRIPLET(CONFIG_SYSROOT "/usr/include") +# endif +#endif + +/* library search paths */ +#ifndef CONFIG_TCC_LIBPATHS +# ifdef TCC_TARGET_PE +# define CONFIG_TCC_LIBPATHS "{B}/lib" +# else +# define CONFIG_TCC_LIBPATHS \ + ALSO_TRIPLET(CONFIG_SYSROOT "/usr/" CONFIG_LDDIR) \ + ":" ALSO_TRIPLET(CONFIG_SYSROOT "/" CONFIG_LDDIR) \ + ":" ALSO_TRIPLET(CONFIG_SYSROOT "/usr/local/" CONFIG_LDDIR) +# endif +#endif + +/* name of ELF interpreter */ +#ifndef CONFIG_TCC_ELFINTERP +# if defined __FreeBSD__ +# define CONFIG_TCC_ELFINTERP "/libexec/ld-elf.so.1" +# elif defined __FreeBSD_kernel__ +# if defined(TCC_TARGET_X86_64) +# define CONFIG_TCC_ELFINTERP "/lib/ld-kfreebsd-x86-64.so.1" +# else +# define CONFIG_TCC_ELFINTERP "/lib/ld.so.1" +# endif +# elif defined __DragonFly__ +# define CONFIG_TCC_ELFINTERP "/usr/libexec/ld-elf.so.2" +# elif defined __NetBSD__ +# define CONFIG_TCC_ELFINTERP "/usr/libexec/ld.elf_so" +# elif defined __GNU__ +# define CONFIG_TCC_ELFINTERP "/lib/ld.so" +# elif defined(TCC_TARGET_PE) +# define CONFIG_TCC_ELFINTERP "-" +# elif defined(TCC_UCLIBC) +# define CONFIG_TCC_ELFINTERP "/lib/ld-uClibc.so.0" /* is there a uClibc for x86_64 ? */ +# elif defined TCC_TARGET_ARM64 +# if defined(TCC_MUSL) +# define CONFIG_TCC_ELFINTERP "/lib/ld-musl-aarch64.so.1" +# else +# define CONFIG_TCC_ELFINTERP "/lib/ld-linux-aarch64.so.1" +# endif +# elif defined(TCC_TARGET_X86_64) +# if defined(TCC_MUSL) +# define CONFIG_TCC_ELFINTERP "/lib/ld-musl-x86_64.so.1" +# else +# define CONFIG_TCC_ELFINTERP "/lib64/ld-linux-x86-64.so.2" +# endif +# elif !defined(TCC_ARM_EABI) +# if defined(TCC_MUSL) +# define CONFIG_TCC_ELFINTERP "/lib/ld-musl-arm.so.1" +# else +# define CONFIG_TCC_ELFINTERP "/lib/ld-linux.so.2" +# endif +# endif +#endif + +/* var elf_interp dans *-gen.c */ +#ifdef CONFIG_TCC_ELFINTERP +# define DEFAULT_ELFINTERP(s) CONFIG_TCC_ELFINTERP +#else +# define DEFAULT_ELFINTERP(s) default_elfinterp(s) +#endif + +/* (target specific) libtcc1.a */ +#ifndef TCC_LIBTCC1 +# define TCC_LIBTCC1 "libtcc1.a" +#endif + +/* library to use with CONFIG_USE_LIBGCC instead of libtcc1.a */ +#if defined CONFIG_USE_LIBGCC && !defined TCC_LIBGCC +#define TCC_LIBGCC USE_TRIPLET(CONFIG_SYSROOT "/" CONFIG_LDDIR) "/libgcc_s.so.1" +#endif + +/* -------------------------------------------- */ + +#include "libtcc.h" +#include "elf.h" +#include "stab.h" + +/* -------------------------------------------- */ + +#ifndef PUB_FUNC /* functions used by tcc.c but not in libtcc.h */ +# define PUB_FUNC +#endif + +#ifndef ONE_SOURCE +# define ONE_SOURCE 1 +#endif + +#if ONE_SOURCE +#define ST_INLN static inline +#define ST_FUNC static +#define ST_DATA static +#else +#define ST_INLN +#define ST_FUNC +#define ST_DATA extern +#endif + +#ifdef TCC_PROFILE /* profile all functions */ +# define static +#endif + +/* -------------------------------------------- */ +/* include the target specific definitions */ + +#define TARGET_DEFS_ONLY +#ifdef TCC_TARGET_I386 +# include "i386-gen.c" +# include "i386-link.c" +#endif +#ifdef TCC_TARGET_X86_64 +# include "x86_64-gen.c" +# include "x86_64-link.c" +#endif +#ifdef TCC_TARGET_ARM +# include "arm-gen.c" +# include "arm-link.c" +# include "arm-asm.c" +#endif +#ifdef TCC_TARGET_ARM64 +# include "arm64-gen.c" +# include "arm64-link.c" +#endif +#ifdef TCC_TARGET_C67 +# define TCC_TARGET_COFF +# include "coff.h" +# include "c67-gen.c" +# include "c67-link.c" +#endif +#undef TARGET_DEFS_ONLY + +/* -------------------------------------------- */ + +#if PTR_SIZE == 8 +# define ELFCLASSW ELFCLASS64 +# define ElfW(type) Elf##64##_##type +# define ELFW(type) ELF##64##_##type +# define ElfW_Rel ElfW(Rela) +# define SHT_RELX SHT_RELA +# define REL_SECTION_FMT ".rela%s" +#else +# define ELFCLASSW ELFCLASS32 +# define ElfW(type) Elf##32##_##type +# define ELFW(type) ELF##32##_##type +# define ElfW_Rel ElfW(Rel) +# define SHT_RELX SHT_REL +# define REL_SECTION_FMT ".rel%s" +#endif +/* target address type */ +#define addr_t ElfW(Addr) + +#if PTR_SIZE == 8 && !defined TCC_TARGET_PE +# define LONG_SIZE 8 +#else +# define LONG_SIZE 4 +#endif + +/* -------------------------------------------- */ + +#define INCLUDE_STACK_SIZE 32 +#define IFDEF_STACK_SIZE 64 +#define VSTACK_SIZE 256 +#define STRING_MAX_SIZE 1024 +#define TOKSTR_MAX_SIZE 256 +#define PACK_STACK_SIZE 8 + +#define TOK_HASH_SIZE 16384 /* must be a power of two */ +#define TOK_ALLOC_INCR 512 /* must be a power of two */ +#define TOK_MAX_SIZE 4 /* token max size in int unit when stored in string */ + +/* token symbol management */ +typedef struct TokenSym { + struct TokenSym *hash_next; + struct Sym *sym_define; /* direct pointer to define */ + struct Sym *sym_label; /* direct pointer to label */ + struct Sym *sym_struct; /* direct pointer to structure */ + struct Sym *sym_identifier; /* direct pointer to identifier */ + int tok; /* token number */ + int len; + char str[1]; +} TokenSym; + +#ifdef TCC_TARGET_PE +typedef unsigned short nwchar_t; +#else +typedef int nwchar_t; +#endif + +typedef struct CString { + int size; /* size in bytes */ + void *data; /* either 'char *' or 'nwchar_t *' */ + int size_allocated; +} CString; + +/* type definition */ +typedef struct CType { + int t; + struct Sym *ref; +} CType; + +/* constant value */ +typedef union CValue { + long double ld; + double d; + float f; + uint64_t i; + struct { + int size; + const void *data; + } str; + int tab[LDOUBLE_SIZE/4]; +} CValue; + +/* value on stack */ +typedef struct SValue { + CType type; /* type */ + unsigned short r; /* register + flags */ + unsigned short r2; /* second register, used for 'long long' + type. If not used, set to VT_CONST */ + CValue c; /* constant, if VT_CONST */ + struct Sym *sym; /* symbol, if (VT_SYM | VT_CONST), or if + result of unary() for an identifier. */ +} SValue; + +/* symbol attributes */ +struct SymAttr { + unsigned short + aligned : 5, /* alignment as log2+1 (0 == unspecified) */ + packed : 1, + weak : 1, + visibility : 2, + dllexport : 1, + dllimport : 1, + unused : 5; +}; + +/* function attributes or temporary attributes for parsing */ +struct FuncAttr { + unsigned + func_call : 3, /* calling convention (0..5), see below */ + func_type : 2, /* FUNC_OLD/NEW/ELLIPSIS */ + func_body : 1, /* body was defined */ + func_args : 8; /* PE __stdcall args */ +}; + +/* GNUC attribute definition */ +typedef struct AttributeDef { + struct SymAttr a; + struct FuncAttr f; + struct Section *section; + int alias_target; /* token */ + int asm_label; /* associated asm label */ + char attr_mode; /* __attribute__((__mode__(...))) */ +} AttributeDef; + +/* symbol management */ +typedef struct Sym { + int v; /* symbol token */ + unsigned short r; /* associated register or VT_CONST/VT_LOCAL and LVAL type */ + struct SymAttr a; /* symbol attributes */ + union { + struct { + int c; /* associated number or Elf symbol index */ + union { + int sym_scope; /* scope level for locals */ + int jnext; /* next jump label */ + struct FuncAttr f; /* function attributes */ + int auxtype; /* bitfield access type */ + }; + }; + long long enum_val; /* enum constant if IS_ENUM_VAL */ + int *d; /* define token stream */ + }; + CType type; /* associated type */ + union { + struct Sym *next; /* next related symbol (for fields and anoms) */ + int asm_label; /* associated asm label */ + }; + struct Sym *prev; /* prev symbol in stack */ + struct Sym *prev_tok; /* previous symbol for this token */ +} Sym; + +/* section definition */ +/* XXX: use directly ELF structure for parameters ? */ +/* special flag to indicate that the section should not be linked to + the other ones */ +#define SHF_PRIVATE 0x80000000 + +/* special flag, too */ +#define SECTION_ABS ((void *)1) + +typedef struct Section { + unsigned long data_offset; /* current data offset */ + unsigned char *data; /* section data */ + unsigned long data_allocated; /* used for realloc() handling */ + int sh_name; /* elf section name (only used during output) */ + int sh_num; /* elf section number */ + int sh_type; /* elf section type */ + int sh_flags; /* elf section flags */ + int sh_info; /* elf section info */ + int sh_addralign; /* elf section alignment */ + int sh_entsize; /* elf entry size */ + unsigned long sh_size; /* section size (only used during output) */ + addr_t sh_addr; /* address at which the section is relocated */ + unsigned long sh_offset; /* file offset */ + int nb_hashed_syms; /* used to resize the hash table */ + struct Section *link; /* link to another section */ + struct Section *reloc; /* corresponding section for relocation, if any */ + struct Section *hash; /* hash table for symbols */ + struct Section *prev; /* previous section on section stack */ + char name[1]; /* section name */ +} Section; + +typedef struct DLLReference { + int level; + void *handle; + char name[1]; +} DLLReference; + +/* -------------------------------------------------- */ + +#define SYM_STRUCT 0x40000000 /* struct/union/enum symbol space */ +#define SYM_FIELD 0x20000000 /* struct/union field symbol space */ +#define SYM_FIRST_ANOM 0x10000000 /* first anonymous sym */ + +/* stored in 'Sym->f.func_type' field */ +#define FUNC_NEW 1 /* ansi function prototype */ +#define FUNC_OLD 2 /* old function prototype */ +#define FUNC_ELLIPSIS 3 /* ansi function prototype with ... */ + +/* stored in 'Sym->f.func_call' field */ +#define FUNC_CDECL 0 /* standard c call */ +#define FUNC_STDCALL 1 /* pascal c call */ +#define FUNC_FASTCALL1 2 /* first param in %eax */ +#define FUNC_FASTCALL2 3 /* first parameters in %eax, %edx */ +#define FUNC_FASTCALL3 4 /* first parameter in %eax, %edx, %ecx */ +#define FUNC_FASTCALLW 5 /* first parameter in %ecx, %edx */ + +/* field 'Sym.t' for macros */ +#define MACRO_OBJ 0 /* object like macro */ +#define MACRO_FUNC 1 /* function like macro */ + +/* field 'Sym.r' for C labels */ +#define LABEL_DEFINED 0 /* label is defined */ +#define LABEL_FORWARD 1 /* label is forward defined */ +#define LABEL_DECLARED 2 /* label is declared but never used */ + +/* type_decl() types */ +#define TYPE_ABSTRACT 1 /* type without variable */ +#define TYPE_DIRECT 2 /* type with variable */ + +#define IO_BUF_SIZE 8192 + +typedef struct BufferedFile { + uint8_t *buf_ptr; + uint8_t *buf_end; + int fd; + struct BufferedFile *prev; + int line_num; /* current line number - here to simplify code */ + int line_ref; /* tcc -E: last printed line */ + int ifndef_macro; /* #ifndef macro / #endif search */ + int ifndef_macro_saved; /* saved ifndef_macro */ + int *ifdef_stack_ptr; /* ifdef_stack value at the start of the file */ + int include_next_index; /* next search path */ + char filename[1024]; /* filename */ + char *true_filename; /* filename not modified by # line directive */ + unsigned char unget[4]; + unsigned char buffer[1]; /* extra size for CH_EOB char */ +} BufferedFile; + +#define CH_EOB '\\' /* end of buffer or '\0' char in file */ +#define CH_EOF (-1) /* end of file */ + +/* used to record tokens */ +typedef struct TokenString { + int *str; + int len; + int lastlen; + int allocated_len; + int last_line_num; + int save_line_num; + /* used to chain token-strings with begin/end_macro() */ + struct TokenString *prev; + const int *prev_ptr; + char alloc; +} TokenString; + +/* inline functions */ +typedef struct InlineFunc { + TokenString *func_str; + Sym *sym; + char filename[1]; +} InlineFunc; + +/* include file cache, used to find files faster and also to eliminate + inclusion if the include file is protected by #ifndef ... #endif */ +typedef struct CachedInclude { + int ifndef_macro; + int once; + int hash_next; /* -1 if none */ + char filename[1]; /* path specified in #include */ +} CachedInclude; + +#define CACHED_INCLUDES_HASH_SIZE 32 + +#ifdef CONFIG_TCC_ASM +typedef struct ExprValue { + uint64_t v; + Sym *sym; + int pcrel; +} ExprValue; + +#define MAX_ASM_OPERANDS 30 +typedef struct ASMOperand { + int id; /* GCC 3 optional identifier (0 if number only supported */ + char *constraint; + char asm_str[16]; /* computed asm string for operand */ + SValue *vt; /* C value of the expression */ + int ref_index; /* if >= 0, gives reference to a output constraint */ + int input_index; /* if >= 0, gives reference to an input constraint */ + int priority; /* priority, used to assign registers */ + int reg; /* if >= 0, register number used for this operand */ + int is_llong; /* true if double register value */ + int is_memory; /* true if memory operand */ + int is_rw; /* for '+' modifier */ +} ASMOperand; +#endif + +/* extra symbol attributes (not in symbol table) */ +struct sym_attr { + unsigned got_offset; + unsigned plt_offset; + int plt_sym; + int dyn_index; +#ifdef TCC_TARGET_ARM + unsigned char plt_thumb_stub:1; +#endif +}; + +struct TCCState { + + int verbose; /* if true, display some information during compilation */ + int nostdinc; /* if true, no standard headers are added */ + int nostdlib; /* if true, no standard libraries are added */ + int nocommon; /* if true, do not use common symbols for .bss data */ + int static_link; /* if true, static linking is performed */ + int rdynamic; /* if true, all symbols are exported */ + int symbolic; /* if true, resolve symbols in the current module first */ + int alacarte_link; /* if true, only link in referenced objects from archive */ + + char *tcc_lib_path; /* CONFIG_TCCDIR or -B option */ + char *soname; /* as specified on the command line (-soname) */ + char *rpath; /* as specified on the command line (-Wl,-rpath=) */ + int enable_new_dtags; /* ditto, (-Wl,--enable-new-dtags) */ + + /* output type, see TCC_OUTPUT_XXX */ + int output_type; + /* output format, see TCC_OUTPUT_FORMAT_xxx */ + int output_format; + + /* C language options */ + int char_is_unsigned; + int leading_underscore; + int ms_extensions; /* allow nested named struct w/o identifier behave like unnamed */ + int dollars_in_identifiers; /* allows '$' char in identifiers */ + int ms_bitfields; /* if true, emulate MS algorithm for aligning bitfields */ + + /* warning switches */ + int warn_write_strings; + int warn_unsupported; + int warn_error; + int warn_none; + int warn_implicit_function_declaration; + int warn_gcc_compat; + + /* compile with debug symbol (and use them if error during execution) */ + int do_debug; +#ifdef CONFIG_TCC_BCHECK + /* compile with built-in memory and bounds checker */ + int do_bounds_check; +#endif +#ifdef TCC_TARGET_ARM + enum float_abi float_abi; /* float ABI of the generated code*/ +#endif + int run_test; /* nth test to run with -dt -run */ + + addr_t text_addr; /* address of text section */ + int has_text_addr; + + unsigned section_align; /* section alignment */ + + char *init_symbol; /* symbols to call at load-time (not used currently) */ + char *fini_symbol; /* symbols to call at unload-time (not used currently) */ + +#ifdef TCC_TARGET_I386 + int seg_size; /* 32. Can be 16 with i386 assembler (.code16) */ +#endif +#ifdef TCC_TARGET_X86_64 + int nosse; /* For -mno-sse support. */ +#endif + + /* array of all loaded dlls (including those referenced by loaded dlls) */ + DLLReference **loaded_dlls; + int nb_loaded_dlls; + + /* include paths */ + char **include_paths; + int nb_include_paths; + + char **sysinclude_paths; + int nb_sysinclude_paths; + + /* library paths */ + char **library_paths; + int nb_library_paths; + + /* crt?.o object path */ + char **crt_paths; + int nb_crt_paths; + + /* -include files */ + char **cmd_include_files; + int nb_cmd_include_files; + + /* error handling */ + void *error_opaque; + void (*error_func)(void *opaque, const char *msg); + int error_set_jmp_enabled; + jmp_buf error_jmp_buf; + int nb_errors; + + /* output file for preprocessing (-E) */ + FILE *ppfp; + enum { + LINE_MACRO_OUTPUT_FORMAT_GCC, + LINE_MACRO_OUTPUT_FORMAT_NONE, + LINE_MACRO_OUTPUT_FORMAT_STD, + LINE_MACRO_OUTPUT_FORMAT_P10 = 11 + } Pflag; /* -P switch */ + char dflag; /* -dX value */ + + /* for -MD/-MF: collected dependencies for this compilation */ + char **target_deps; + int nb_target_deps; + + /* compilation */ + BufferedFile *include_stack[INCLUDE_STACK_SIZE]; + BufferedFile **include_stack_ptr; + + int ifdef_stack[IFDEF_STACK_SIZE]; + int *ifdef_stack_ptr; + + /* included files enclosed with #ifndef MACRO */ + int cached_includes_hash[CACHED_INCLUDES_HASH_SIZE]; + CachedInclude **cached_includes; + int nb_cached_includes; + + /* #pragma pack stack */ + int pack_stack[PACK_STACK_SIZE]; + int *pack_stack_ptr; + char **pragma_libs; + int nb_pragma_libs; + + /* inline functions are stored as token lists and compiled last + only if referenced */ + struct InlineFunc **inline_fns; + int nb_inline_fns; + + /* sections */ + Section **sections; + int nb_sections; /* number of sections, including first dummy section */ + + Section **priv_sections; + int nb_priv_sections; /* number of private sections */ + + /* got & plt handling */ + Section *got; + Section *plt; + + /* temporary dynamic symbol sections (for dll loading) */ + Section *dynsymtab_section; + /* exported dynamic symbol section */ + Section *dynsym; + /* copy of the global symtab_section variable */ + Section *symtab; + /* extra attributes (eg. GOT/PLT value) for symtab symbols */ + struct sym_attr *sym_attrs; + int nb_sym_attrs; + /* tiny assembler state */ + Sym *asm_labels; + +#ifdef TCC_TARGET_PE + /* PE info */ + int pe_subsystem; + unsigned pe_characteristics; + unsigned pe_file_align; + unsigned pe_stack_size; +# ifdef TCC_TARGET_X86_64 + Section *uw_pdata; + int uw_sym; + unsigned uw_offs; +# endif +#endif + +#ifdef TCC_IS_NATIVE + const char *runtime_main; + void **runtime_mem; + int nb_runtime_mem; +#endif + + /* used by main and tcc_parse_args only */ + struct filespec **files; /* files seen on command line */ + int nb_files; /* number thereof */ + int nb_libraries; /* number of libs thereof */ + int filetype; + char *outfile; /* output filename */ + int option_r; /* option -r */ + int do_bench; /* option -bench */ + int gen_deps; /* option -MD */ + char *deps_outfile; /* option -MF */ + int option_pthread; /* -pthread option */ + int argc; + char **argv; +}; + +struct filespec { + char type; + char alacarte; + char name[1]; +}; + +/* The current value can be: */ +#define VT_VALMASK 0x003f /* mask for value location, register or: */ +#define VT_CONST 0x0030 /* constant in vc (must be first non register value) */ +#define VT_LLOCAL 0x0031 /* lvalue, offset on stack */ +#define VT_LOCAL 0x0032 /* offset on stack */ +#define VT_CMP 0x0033 /* the value is stored in processor flags (in vc) */ +#define VT_JMP 0x0034 /* value is the consequence of jmp true (even) */ +#define VT_JMPI 0x0035 /* value is the consequence of jmp false (odd) */ +#define VT_LVAL 0x0100 /* var is an lvalue */ +#define VT_SYM 0x0200 /* a symbol value is added */ +#define VT_MUSTCAST 0x0400 /* value must be casted to be correct (used for + char/short stored in integer registers) */ +#define VT_MUSTBOUND 0x0800 /* bound checking must be done before + dereferencing value */ +#define VT_BOUNDED 0x8000 /* value is bounded. The address of the + bounding function call point is in vc */ +#define VT_LVAL_BYTE 0x1000 /* lvalue is a byte */ +#define VT_LVAL_SHORT 0x2000 /* lvalue is a short */ +#define VT_LVAL_UNSIGNED 0x4000 /* lvalue is unsigned */ +#define VT_LVAL_TYPE (VT_LVAL_BYTE | VT_LVAL_SHORT | VT_LVAL_UNSIGNED) + +/* types */ +#define VT_BTYPE 0x000f /* mask for basic type */ +#define VT_VOID 0 /* void type */ +#define VT_BYTE 1 /* signed byte type */ +#define VT_SHORT 2 /* short type */ +#define VT_INT 3 /* integer type */ +#define VT_LLONG 4 /* 64 bit integer */ +#define VT_PTR 5 /* pointer */ +#define VT_FUNC 6 /* function type */ +#define VT_STRUCT 7 /* struct/union definition */ +#define VT_FLOAT 8 /* IEEE float */ +#define VT_DOUBLE 9 /* IEEE double */ +#define VT_LDOUBLE 10 /* IEEE long double */ +#define VT_BOOL 11 /* ISOC99 boolean type */ +#define VT_QLONG 13 /* 128-bit integer. Only used for x86-64 ABI */ +#define VT_QFLOAT 14 /* 128-bit float. Only used for x86-64 ABI */ + +#define VT_UNSIGNED 0x0010 /* unsigned type */ +#define VT_DEFSIGN 0x0020 /* explicitly signed or unsigned */ +#define VT_ARRAY 0x0040 /* array type (also has VT_PTR) */ +#define VT_BITFIELD 0x0080 /* bitfield modifier */ +#define VT_CONSTANT 0x0100 /* const modifier */ +#define VT_VOLATILE 0x0200 /* volatile modifier */ +#define VT_VLA 0x0400 /* VLA type (also has VT_PTR and VT_ARRAY) */ +#define VT_LONG 0x0800 /* long type (also has VT_INT rsp. VT_LLONG) */ + +/* storage */ +#define VT_EXTERN 0x00001000 /* extern definition */ +#define VT_STATIC 0x00002000 /* static variable */ +#define VT_TYPEDEF 0x00004000 /* typedef definition */ +#define VT_INLINE 0x00008000 /* inline definition */ +/* currently unused: 0x000[1248]0000 */ + +#define VT_STRUCT_SHIFT 20 /* shift for bitfield shift values (32 - 2*6) */ +#define VT_STRUCT_MASK (((1 << (6+6)) - 1) << VT_STRUCT_SHIFT | VT_BITFIELD) +#define BIT_POS(t) (((t) >> VT_STRUCT_SHIFT) & 0x3f) +#define BIT_SIZE(t) (((t) >> (VT_STRUCT_SHIFT + 6)) & 0x3f) + +#define VT_UNION (1 << VT_STRUCT_SHIFT | VT_STRUCT) +#define VT_ENUM (2 << VT_STRUCT_SHIFT) /* integral type is an enum really */ +#define VT_ENUM_VAL (3 << VT_STRUCT_SHIFT) /* integral type is an enum constant really */ + +#define IS_ENUM(t) ((t & VT_STRUCT_MASK) == VT_ENUM) +#define IS_ENUM_VAL(t) ((t & VT_STRUCT_MASK) == VT_ENUM_VAL) +#define IS_UNION(t) ((t & (VT_STRUCT_MASK|VT_BTYPE)) == VT_UNION) + +/* type mask (except storage) */ +#define VT_STORAGE (VT_EXTERN | VT_STATIC | VT_TYPEDEF | VT_INLINE) +#define VT_TYPE (~(VT_STORAGE|VT_STRUCT_MASK)) + +/* token values */ + +/* warning: the following compare tokens depend on i386 asm code */ +#define TOK_ULT 0x92 +#define TOK_UGE 0x93 +#define TOK_EQ 0x94 +#define TOK_NE 0x95 +#define TOK_ULE 0x96 +#define TOK_UGT 0x97 +#define TOK_Nset 0x98 +#define TOK_Nclear 0x99 +#define TOK_LT 0x9c +#define TOK_GE 0x9d +#define TOK_LE 0x9e +#define TOK_GT 0x9f + +#define TOK_LAND 0xa0 +#define TOK_LOR 0xa1 +#define TOK_DEC 0xa2 +#define TOK_MID 0xa3 /* inc/dec, to void constant */ +#define TOK_INC 0xa4 +#define TOK_UDIV 0xb0 /* unsigned division */ +#define TOK_UMOD 0xb1 /* unsigned modulo */ +#define TOK_PDIV 0xb2 /* fast division with undefined rounding for pointers */ + +/* tokens that carry values (in additional token string space / tokc) --> */ +#define TOK_CCHAR 0xb3 /* char constant in tokc */ +#define TOK_LCHAR 0xb4 +#define TOK_CINT 0xb5 /* number in tokc */ +#define TOK_CUINT 0xb6 /* unsigned int constant */ +#define TOK_CLLONG 0xb7 /* long long constant */ +#define TOK_CULLONG 0xb8 /* unsigned long long constant */ +#define TOK_STR 0xb9 /* pointer to string in tokc */ +#define TOK_LSTR 0xba +#define TOK_CFLOAT 0xbb /* float constant */ +#define TOK_CDOUBLE 0xbc /* double constant */ +#define TOK_CLDOUBLE 0xbd /* long double constant */ +#define TOK_PPNUM 0xbe /* preprocessor number */ +#define TOK_PPSTR 0xbf /* preprocessor string */ +#define TOK_LINENUM 0xc0 /* line number info */ +#define TOK_TWODOTS 0xa8 /* C++ token ? */ +/* <-- */ + +#define TOK_UMULL 0xc2 /* unsigned 32x32 -> 64 mul */ +#define TOK_ADDC1 0xc3 /* add with carry generation */ +#define TOK_ADDC2 0xc4 /* add with carry use */ +#define TOK_SUBC1 0xc5 /* add with carry generation */ +#define TOK_SUBC2 0xc6 /* add with carry use */ +#define TOK_ARROW 0xc7 +#define TOK_DOTS 0xc8 /* three dots */ +#define TOK_SHR 0xc9 /* unsigned shift right */ +#define TOK_TWOSHARPS 0xca /* ## preprocessing token */ +#define TOK_PLCHLDR 0xcb /* placeholder token as defined in C99 */ +#define TOK_NOSUBST 0xcc /* means following token has already been pp'd */ +#define TOK_PPJOIN 0xcd /* A '##' in the right position to mean pasting */ +#define TOK_CLONG 0xce /* long constant */ +#define TOK_CULONG 0xcf /* unsigned long constant */ + +#define TOK_SHL 0x01 /* shift left */ +#define TOK_SAR 0x02 /* signed shift right */ + +/* assignment operators : normal operator or 0x80 */ +#define TOK_A_MOD 0xa5 +#define TOK_A_AND 0xa6 +#define TOK_A_MUL 0xaa +#define TOK_A_ADD 0xab +#define TOK_A_SUB 0xad +#define TOK_A_DIV 0xaf +#define TOK_A_XOR 0xde +#define TOK_A_OR 0xfc +#define TOK_A_SHL 0x81 +#define TOK_A_SAR 0x82 + +#define TOK_EOF (-1) /* end of file */ +#define TOK_LINEFEED 10 /* line feed */ + +/* all identifiers and strings have token above that */ +#define TOK_IDENT 256 + +#define DEF_ASM(x) DEF(TOK_ASM_ ## x, #x) +#define TOK_ASM_int TOK_INT +#define DEF_ASMDIR(x) DEF(TOK_ASMDIR_ ## x, "." #x) +#define TOK_ASMDIR_FIRST TOK_ASMDIR_byte +#define TOK_ASMDIR_LAST TOK_ASMDIR_section + +#if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64 +/* only used for i386 asm opcodes definitions */ +#define DEF_BWL(x) \ + DEF(TOK_ASM_ ## x ## b, #x "b") \ + DEF(TOK_ASM_ ## x ## w, #x "w") \ + DEF(TOK_ASM_ ## x ## l, #x "l") \ + DEF(TOK_ASM_ ## x, #x) +#define DEF_WL(x) \ + DEF(TOK_ASM_ ## x ## w, #x "w") \ + DEF(TOK_ASM_ ## x ## l, #x "l") \ + DEF(TOK_ASM_ ## x, #x) +#ifdef TCC_TARGET_X86_64 +# define DEF_BWLQ(x) \ + DEF(TOK_ASM_ ## x ## b, #x "b") \ + DEF(TOK_ASM_ ## x ## w, #x "w") \ + DEF(TOK_ASM_ ## x ## l, #x "l") \ + DEF(TOK_ASM_ ## x ## q, #x "q") \ + DEF(TOK_ASM_ ## x, #x) +# define DEF_WLQ(x) \ + DEF(TOK_ASM_ ## x ## w, #x "w") \ + DEF(TOK_ASM_ ## x ## l, #x "l") \ + DEF(TOK_ASM_ ## x ## q, #x "q") \ + DEF(TOK_ASM_ ## x, #x) +# define DEF_BWLX DEF_BWLQ +# define DEF_WLX DEF_WLQ +/* number of sizes + 1 */ +# define NBWLX 5 +#else +# define DEF_BWLX DEF_BWL +# define DEF_WLX DEF_WL +/* number of sizes + 1 */ +# define NBWLX 4 +#endif + +#define DEF_FP1(x) \ + DEF(TOK_ASM_ ## f ## x ## s, "f" #x "s") \ + DEF(TOK_ASM_ ## fi ## x ## l, "fi" #x "l") \ + DEF(TOK_ASM_ ## f ## x ## l, "f" #x "l") \ + DEF(TOK_ASM_ ## fi ## x ## s, "fi" #x "s") + +#define DEF_FP(x) \ + DEF(TOK_ASM_ ## f ## x, "f" #x ) \ + DEF(TOK_ASM_ ## f ## x ## p, "f" #x "p") \ + DEF_FP1(x) + +#define DEF_ASMTEST(x,suffix) \ + DEF_ASM(x ## o ## suffix) \ + DEF_ASM(x ## no ## suffix) \ + DEF_ASM(x ## b ## suffix) \ + DEF_ASM(x ## c ## suffix) \ + DEF_ASM(x ## nae ## suffix) \ + DEF_ASM(x ## nb ## suffix) \ + DEF_ASM(x ## nc ## suffix) \ + DEF_ASM(x ## ae ## suffix) \ + DEF_ASM(x ## e ## suffix) \ + DEF_ASM(x ## z ## suffix) \ + DEF_ASM(x ## ne ## suffix) \ + DEF_ASM(x ## nz ## suffix) \ + DEF_ASM(x ## be ## suffix) \ + DEF_ASM(x ## na ## suffix) \ + DEF_ASM(x ## nbe ## suffix) \ + DEF_ASM(x ## a ## suffix) \ + DEF_ASM(x ## s ## suffix) \ + DEF_ASM(x ## ns ## suffix) \ + DEF_ASM(x ## p ## suffix) \ + DEF_ASM(x ## pe ## suffix) \ + DEF_ASM(x ## np ## suffix) \ + DEF_ASM(x ## po ## suffix) \ + DEF_ASM(x ## l ## suffix) \ + DEF_ASM(x ## nge ## suffix) \ + DEF_ASM(x ## nl ## suffix) \ + DEF_ASM(x ## ge ## suffix) \ + DEF_ASM(x ## le ## suffix) \ + DEF_ASM(x ## ng ## suffix) \ + DEF_ASM(x ## nle ## suffix) \ + DEF_ASM(x ## g ## suffix) + +#endif /* defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64 */ + +enum tcc_token { + TOK_LAST = TOK_IDENT - 1 +#define DEF(id, str) ,id +#include "tcctok.h" +#undef DEF +}; + +/* keywords: tok >= TOK_IDENT && tok < TOK_UIDENT */ +#define TOK_UIDENT TOK_DEFINE + +/* ------------ libtcc.c ------------ */ + +/* use GNU C extensions */ +ST_DATA int gnu_ext; +/* use Tiny C extensions */ +ST_DATA int tcc_ext; +/* XXX: get rid of this ASAP */ +ST_DATA struct TCCState *tcc_state; + +/* public functions currently used by the tcc main function */ +ST_FUNC char *pstrcpy(char *buf, int buf_size, const char *s); +ST_FUNC char *pstrcat(char *buf, int buf_size, const char *s); +ST_FUNC char *pstrncpy(char *out, const char *in, size_t num); +PUB_FUNC char *tcc_basename(const char *name); +PUB_FUNC char *tcc_fileextension (const char *name); + +#ifndef MEM_DEBUG +PUB_FUNC void tcc_free(void *ptr); +PUB_FUNC void *tcc_malloc(unsigned long size); +PUB_FUNC void *tcc_mallocz(unsigned long size); +PUB_FUNC void *tcc_realloc(void *ptr, unsigned long size); +PUB_FUNC char *tcc_strdup(const char *str); +#else +#define tcc_free(ptr) tcc_free_debug(ptr) +#define tcc_malloc(size) tcc_malloc_debug(size, __FILE__, __LINE__) +#define tcc_mallocz(size) tcc_mallocz_debug(size, __FILE__, __LINE__) +#define tcc_realloc(ptr,size) tcc_realloc_debug(ptr, size, __FILE__, __LINE__) +#define tcc_strdup(str) tcc_strdup_debug(str, __FILE__, __LINE__) +PUB_FUNC void tcc_free_debug(void *ptr); +PUB_FUNC void *tcc_malloc_debug(unsigned long size, const char *file, int line); +PUB_FUNC void *tcc_mallocz_debug(unsigned long size, const char *file, int line); +PUB_FUNC void *tcc_realloc_debug(void *ptr, unsigned long size, const char *file, int line); +PUB_FUNC char *tcc_strdup_debug(const char *str, const char *file, int line); +#endif + +#define free(p) use_tcc_free(p) +#define malloc(s) use_tcc_malloc(s) +#define realloc(p, s) use_tcc_realloc(p, s) +#undef strdup +#define strdup(s) use_tcc_strdup(s) +PUB_FUNC void tcc_memcheck(void); +PUB_FUNC void tcc_error_noabort(const char *fmt, ...); +PUB_FUNC NORETURN void tcc_error(const char *fmt, ...); +PUB_FUNC void tcc_warning(const char *fmt, ...); + +/* other utilities */ +ST_FUNC void dynarray_add(void *ptab, int *nb_ptr, void *data); +ST_FUNC void dynarray_reset(void *pp, int *n); +ST_INLN void cstr_ccat(CString *cstr, int ch); +ST_FUNC void cstr_cat(CString *cstr, const char *str, int len); +ST_FUNC void cstr_wccat(CString *cstr, int ch); +ST_FUNC void cstr_new(CString *cstr); +ST_FUNC void cstr_free(CString *cstr); +ST_FUNC void cstr_reset(CString *cstr); + +ST_INLN void sym_free(Sym *sym); +ST_FUNC Sym *sym_push2(Sym **ps, int v, int t, int c); +ST_FUNC Sym *sym_find2(Sym *s, int v); +ST_FUNC Sym *sym_push(int v, CType *type, int r, int c); +ST_FUNC void sym_pop(Sym **ptop, Sym *b, int keep); +ST_INLN Sym *struct_find(int v); +ST_INLN Sym *sym_find(int v); +ST_FUNC Sym *global_identifier_push(int v, int t, int c); + +ST_FUNC void tcc_open_bf(TCCState *s1, const char *filename, int initlen); +ST_FUNC int tcc_open(TCCState *s1, const char *filename); +ST_FUNC void tcc_close(void); + +ST_FUNC int tcc_add_file_internal(TCCState *s1, const char *filename, int flags); +/* flags: */ +#define AFF_PRINT_ERROR 0x10 /* print error if file not found */ +#define AFF_REFERENCED_DLL 0x20 /* load a referenced dll from another dll */ +#define AFF_TYPE_BIN 0x40 /* file to add is binary */ +/* s->filetype: */ +#define AFF_TYPE_NONE 0 +#define AFF_TYPE_C 1 +#define AFF_TYPE_ASM 2 +#define AFF_TYPE_ASMPP 3 +#define AFF_TYPE_LIB 4 +/* values from tcc_object_type(...) */ +#define AFF_BINTYPE_REL 1 +#define AFF_BINTYPE_DYN 2 +#define AFF_BINTYPE_AR 3 +#define AFF_BINTYPE_C67 4 + + +ST_FUNC int tcc_add_crt(TCCState *s, const char *filename); +ST_FUNC int tcc_add_dll(TCCState *s, const char *filename, int flags); +ST_FUNC void tcc_add_pragma_libs(TCCState *s1); +PUB_FUNC int tcc_add_library_err(TCCState *s, const char *f); +PUB_FUNC void tcc_print_stats(TCCState *s, unsigned total_time); +PUB_FUNC int tcc_parse_args(TCCState *s, int *argc, char ***argv, int optind); +#ifdef _WIN32 +ST_FUNC char *normalize_slashes(char *path); +#endif + +/* tcc_parse_args return codes: */ +#define OPT_HELP 1 +#define OPT_HELP2 2 +#define OPT_V 3 +#define OPT_PRINT_DIRS 4 +#define OPT_AR 5 +#define OPT_IMPDEF 6 +#define OPT_M32 32 +#define OPT_M64 64 + +/* ------------ tccpp.c ------------ */ + +ST_DATA struct BufferedFile *file; +ST_DATA int ch, tok; +ST_DATA CValue tokc; +ST_DATA const int *macro_ptr; +ST_DATA int parse_flags; +ST_DATA int tok_flags; +ST_DATA CString tokcstr; /* current parsed string, if any */ + +/* display benchmark infos */ +ST_DATA int total_lines; +ST_DATA int total_bytes; +ST_DATA int tok_ident; +ST_DATA TokenSym **table_ident; + +#define TOK_FLAG_BOL 0x0001 /* beginning of line before */ +#define TOK_FLAG_BOF 0x0002 /* beginning of file before */ +#define TOK_FLAG_ENDIF 0x0004 /* a endif was found matching starting #ifdef */ +#define TOK_FLAG_EOF 0x0008 /* end of file */ + +#define PARSE_FLAG_PREPROCESS 0x0001 /* activate preprocessing */ +#define PARSE_FLAG_TOK_NUM 0x0002 /* return numbers instead of TOK_PPNUM */ +#define PARSE_FLAG_LINEFEED 0x0004 /* line feed is returned as a + token. line feed is also + returned at eof */ +#define PARSE_FLAG_ASM_FILE 0x0008 /* we processing an asm file: '#' can be used for line comment, etc. */ +#define PARSE_FLAG_SPACES 0x0010 /* next() returns space tokens (for -E) */ +#define PARSE_FLAG_ACCEPT_STRAYS 0x0020 /* next() returns '\\' token */ +#define PARSE_FLAG_TOK_STR 0x0040 /* return parsed strings instead of TOK_PPSTR */ + +/* isidnum_table flags: */ +#define IS_SPC 1 +#define IS_ID 2 +#define IS_NUM 4 + +ST_FUNC TokenSym *tok_alloc(const char *str, int len); +ST_FUNC const char *get_tok_str(int v, CValue *cv); +ST_FUNC void begin_macro(TokenString *str, int alloc); +ST_FUNC void end_macro(void); +ST_FUNC int set_idnum(int c, int val); +ST_INLN void tok_str_new(TokenString *s); +ST_FUNC TokenString *tok_str_alloc(void); +ST_FUNC void tok_str_free(TokenString *s); +ST_FUNC void tok_str_free_str(int *str); +ST_FUNC void tok_str_add(TokenString *s, int t); +ST_FUNC void tok_str_add_tok(TokenString *s); +ST_INLN void define_push(int v, int macro_type, int *str, Sym *first_arg); +ST_FUNC void define_undef(Sym *s); +ST_INLN Sym *define_find(int v); +ST_FUNC void free_defines(Sym *b); +ST_FUNC Sym *label_find(int v); +ST_FUNC Sym *label_push(Sym **ptop, int v, int flags); +ST_FUNC void label_pop(Sym **ptop, Sym *slast, int keep); +ST_FUNC void parse_define(void); +ST_FUNC void preprocess(int is_bof); +ST_FUNC void next_nomacro(void); +ST_FUNC void next(void); +ST_INLN void unget_tok(int last_tok); +ST_FUNC void preprocess_start(TCCState *s1, int is_asm); +ST_FUNC void preprocess_end(TCCState *s1); +ST_FUNC void tccpp_new(TCCState *s); +ST_FUNC void tccpp_delete(TCCState *s); +ST_FUNC int tcc_preprocess(TCCState *s1); +ST_FUNC void skip(int c); +ST_FUNC NORETURN void expect(const char *msg); + +/* space excluding newline */ +static inline int is_space(int ch) { + return ch == ' ' || ch == '\t' || ch == '\v' || ch == '\f' || ch == '\r'; +} +static inline int isid(int c) { + return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_'; +} +static inline int isnum(int c) { + return c >= '0' && c <= '9'; +} +static inline int isoct(int c) { + return c >= '0' && c <= '7'; +} +static inline int toup(int c) { + return (c >= 'a' && c <= 'z') ? c - 'a' + 'A' : c; +} + +/* ------------ tccgen.c ------------ */ + +#define SYM_POOL_NB (8192 / sizeof(Sym)) +ST_DATA Sym *sym_free_first; +ST_DATA void **sym_pools; +ST_DATA int nb_sym_pools; + +ST_DATA Sym *global_stack; +ST_DATA Sym *local_stack; +ST_DATA Sym *local_label_stack; +ST_DATA Sym *global_label_stack; +ST_DATA Sym *define_stack; +ST_DATA CType char_pointer_type, func_old_type, int_type, size_type; +ST_DATA SValue __vstack[1+/*to make bcheck happy*/ VSTACK_SIZE], *vtop, *pvtop; +#define vstack (__vstack + 1) +ST_DATA int rsym, anon_sym, ind, loc; + +ST_DATA int const_wanted; /* true if constant wanted */ +ST_DATA int nocode_wanted; /* true if no code generation wanted for an expression */ +ST_DATA int global_expr; /* true if compound literals must be allocated globally (used during initializers parsing */ +ST_DATA CType func_vt; /* current function return type (used by return instruction) */ +ST_DATA int func_var; /* true if current function is variadic */ +ST_DATA int func_vc; +ST_DATA int last_line_num, last_ind, func_ind; /* debug last line number and pc */ +ST_DATA const char *funcname; +ST_DATA int g_debug; + +ST_FUNC void tcc_debug_start(TCCState *s1); +ST_FUNC void tcc_debug_end(TCCState *s1); +ST_FUNC void tcc_debug_funcstart(TCCState *s1, Sym *sym); +ST_FUNC void tcc_debug_funcend(TCCState *s1, int size); +ST_FUNC void tcc_debug_line(TCCState *s1); + +ST_FUNC int tccgen_compile(TCCState *s1); +ST_FUNC void free_inline_functions(TCCState *s); +ST_FUNC void check_vstack(void); + +ST_INLN int is_float(int t); +ST_FUNC int ieee_finite(double d); +ST_FUNC void test_lvalue(void); +ST_FUNC void vpushi(int v); +ST_FUNC Sym *external_global_sym(int v, CType *type, int r); +ST_FUNC void vset(CType *type, int r, int v); +ST_FUNC void vswap(void); +ST_FUNC void vpush_global_sym(CType *type, int v); +ST_FUNC void vrote(SValue *e, int n); +ST_FUNC void vrott(int n); +ST_FUNC void vrotb(int n); +#ifdef TCC_TARGET_ARM +ST_FUNC int get_reg_ex(int rc, int rc2); +ST_FUNC void lexpand_nr(void); +#endif +ST_FUNC void vpushv(SValue *v); +ST_FUNC void save_reg(int r); +ST_FUNC void save_reg_upstack(int r, int n); +ST_FUNC int get_reg(int rc); +ST_FUNC void save_regs(int n); +ST_FUNC void gaddrof(void); +ST_FUNC int gv(int rc); +ST_FUNC void gv2(int rc1, int rc2); +ST_FUNC void vpop(void); +ST_FUNC void gen_op(int op); +ST_FUNC int type_size(CType *type, int *a); +ST_FUNC void mk_pointer(CType *type); +ST_FUNC void vstore(void); +ST_FUNC void inc(int post, int c); +ST_FUNC void parse_mult_str (CString *astr, const char *msg); +ST_FUNC void parse_asm_str(CString *astr); +ST_FUNC int lvalue_type(int t); +ST_FUNC void indir(void); +ST_FUNC void unary(void); +ST_FUNC void expr_prod(void); +ST_FUNC void expr_sum(void); +ST_FUNC void gexpr(void); +ST_FUNC int expr_const(void); +#if defined CONFIG_TCC_BCHECK || defined TCC_TARGET_C67 +ST_FUNC Sym *get_sym_ref(CType *type, Section *sec, unsigned long offset, unsigned long size); +#endif +#if defined TCC_TARGET_X86_64 && !defined TCC_TARGET_PE +ST_FUNC int classify_x86_64_va_arg(CType *ty); +#endif + +/* ------------ tccelf.c ------------ */ + +#define TCC_OUTPUT_FORMAT_ELF 0 /* default output format: ELF */ +#define TCC_OUTPUT_FORMAT_BINARY 1 /* binary image output */ +#define TCC_OUTPUT_FORMAT_COFF 2 /* COFF */ + +#define ARMAG "!\012" /* For COFF and a.out archives */ + +typedef struct { + unsigned int n_strx; /* index into string table of name */ + unsigned char n_type; /* type of symbol */ + unsigned char n_other; /* misc info (usually empty) */ + unsigned short n_desc; /* description field */ + unsigned int n_value; /* value of symbol */ +} Stab_Sym; + +ST_DATA Section *text_section, *data_section, *bss_section; /* predefined sections */ +ST_DATA Section *common_section; +ST_DATA Section *cur_text_section; /* current section where function code is generated */ +#ifdef CONFIG_TCC_ASM +ST_DATA Section *last_text_section; /* to handle .previous asm directive */ +#endif +#ifdef CONFIG_TCC_BCHECK +/* bound check related sections */ +ST_DATA Section *bounds_section; /* contains global data bound description */ +ST_DATA Section *lbounds_section; /* contains local data bound description */ +ST_FUNC void tccelf_bounds_new(TCCState *s); +#endif +/* symbol sections */ +ST_DATA Section *symtab_section, *strtab_section; +/* debug sections */ +ST_DATA Section *stab_section, *stabstr_section; + +ST_FUNC void tccelf_new(TCCState *s); +ST_FUNC void tccelf_delete(TCCState *s); +ST_FUNC void tccelf_stab_new(TCCState *s); + +ST_FUNC Section *new_section(TCCState *s1, const char *name, int sh_type, int sh_flags); +ST_FUNC void section_realloc(Section *sec, unsigned long new_size); +ST_FUNC size_t section_add(Section *sec, addr_t size, int align); +ST_FUNC void *section_ptr_add(Section *sec, addr_t size); +ST_FUNC void section_reserve(Section *sec, unsigned long size); +ST_FUNC Section *find_section(TCCState *s1, const char *name); +ST_FUNC Section *new_symtab(TCCState *s1, const char *symtab_name, int sh_type, int sh_flags, const char *strtab_name, const char *hash_name, int hash_sh_flags); + +ST_FUNC void put_extern_sym2(Sym *sym, Section *section, addr_t value, unsigned long size, int can_add_underscore); +ST_FUNC void put_extern_sym(Sym *sym, Section *section, addr_t value, unsigned long size); +#if PTR_SIZE == 4 +ST_FUNC void greloc(Section *s, Sym *sym, unsigned long offset, int type); +#endif +ST_FUNC void greloca(Section *s, Sym *sym, unsigned long offset, int type, addr_t addend); + +ST_FUNC int put_elf_str(Section *s, const char *sym); +ST_FUNC int put_elf_sym(Section *s, addr_t value, unsigned long size, int info, int other, int shndx, const char *name); +ST_FUNC int set_elf_sym(Section *s, addr_t value, unsigned long size, int info, int other, int shndx, const char *name); +ST_FUNC int find_elf_sym(Section *s, const char *name); +ST_FUNC void put_elf_reloc(Section *symtab, Section *s, unsigned long offset, int type, int symbol); +ST_FUNC void put_elf_reloca(Section *symtab, Section *s, unsigned long offset, int type, int symbol, addr_t addend); + +ST_FUNC void put_stabs(const char *str, int type, int other, int desc, unsigned long value); +ST_FUNC void put_stabs_r(const char *str, int type, int other, int desc, unsigned long value, Section *sec, int sym_index); +ST_FUNC void put_stabn(int type, int other, int desc, int value); +ST_FUNC void put_stabd(int type, int other, int desc); + +ST_FUNC void relocate_common_syms(void); +ST_FUNC void relocate_syms(TCCState *s1, Section *symtab, int do_resolve); +ST_FUNC void relocate_section(TCCState *s1, Section *s); + +ST_FUNC void tcc_add_linker_symbols(TCCState *s1); +ST_FUNC int tcc_object_type(int fd, ElfW(Ehdr) *h); +ST_FUNC int tcc_load_object_file(TCCState *s1, int fd, unsigned long file_offset); +ST_FUNC int tcc_load_archive(TCCState *s1, int fd); +ST_FUNC void tcc_add_bcheck(TCCState *s1); +ST_FUNC void tcc_add_runtime(TCCState *s1); + +ST_FUNC void build_got_entries(TCCState *s1); +ST_FUNC struct sym_attr *get_sym_attr(TCCState *s1, int index, int alloc); +ST_FUNC void squeeze_multi_relocs(Section *sec, size_t oldrelocoffset); + +ST_FUNC addr_t get_elf_sym_addr(TCCState *s, const char *name, int err); +#if defined TCC_IS_NATIVE || defined TCC_TARGET_PE +ST_FUNC void *tcc_get_symbol_err(TCCState *s, const char *name); +#endif + +#ifndef TCC_TARGET_PE +ST_FUNC int tcc_load_dll(TCCState *s1, int fd, const char *filename, int level); +ST_FUNC int tcc_load_ldscript(TCCState *s1); +ST_FUNC uint8_t *parse_comment(uint8_t *p); +ST_FUNC void minp(void); +ST_INLN void inp(void); +ST_FUNC int handle_eob(void); +#endif + +/* ------------ xxx-link.c ------------ */ + +/* Whether to generate a GOT/PLT entry and when. NO_GOTPLT_ENTRY is first so + that unknown relocation don't create a GOT or PLT entry */ +enum gotplt_entry { + NO_GOTPLT_ENTRY, /* never generate (eg. GLOB_DAT & JMP_SLOT relocs) */ + BUILD_GOT_ONLY, /* only build GOT (eg. TPOFF relocs) */ + AUTO_GOTPLT_ENTRY, /* generate if sym is UNDEF */ + ALWAYS_GOTPLT_ENTRY /* always generate (eg. PLTOFF relocs) */ +}; + +ST_FUNC int code_reloc (int reloc_type); +ST_FUNC int gotplt_entry_type (int reloc_type); +ST_FUNC unsigned create_plt_entry(TCCState *s1, unsigned got_offset, struct sym_attr *attr); +ST_FUNC void relocate_init(Section *sr); +ST_FUNC void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t addr, addr_t val); +ST_FUNC void relocate_plt(TCCState *s1); + +/* ------------ xxx-gen.c ------------ */ + +ST_DATA const int reg_classes[NB_REGS]; + +ST_FUNC void gsym_addr(int t, int a); +ST_FUNC void gsym(int t); +ST_FUNC void load(int r, SValue *sv); +ST_FUNC void store(int r, SValue *v); +ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *align, int *regsize); +ST_FUNC void gfunc_call(int nb_args); +ST_FUNC void gfunc_prolog(CType *func_type); +ST_FUNC void gfunc_epilog(void); +ST_FUNC int gjmp(int t); +ST_FUNC void gjmp_addr(int a); +ST_FUNC int gtst(int inv, int t); +#if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64 +ST_FUNC void gtst_addr(int inv, int a); +#else +#define gtst_addr(inv, a) gsym_addr(gtst(inv, 0), a) +#endif +ST_FUNC void gen_opi(int op); +ST_FUNC void gen_opf(int op); +ST_FUNC void gen_cvt_ftoi(int t); +ST_FUNC void gen_cvt_ftof(int t); +ST_FUNC void ggoto(void); +#ifndef TCC_TARGET_C67 +ST_FUNC void o(unsigned int c); +#endif +#ifndef TCC_TARGET_ARM +ST_FUNC void gen_cvt_itof(int t); +#endif +ST_FUNC void gen_vla_sp_save(int addr); +ST_FUNC void gen_vla_sp_restore(int addr); +ST_FUNC void gen_vla_alloc(CType *type, int align); + +static inline uint16_t read16le(unsigned char *p) { + return p[0] | (uint16_t)p[1] << 8; +} +static inline void write16le(unsigned char *p, uint16_t x) { + p[0] = x & 255; p[1] = x >> 8 & 255; +} +static inline uint32_t read32le(unsigned char *p) { + return read16le(p) | (uint32_t)read16le(p + 2) << 16; +} +static inline void write32le(unsigned char *p, uint32_t x) { + write16le(p, x); write16le(p + 2, x >> 16); +} +static inline void add32le(unsigned char *p, int32_t x) { + write32le(p, read32le(p) + x); +} +static inline uint64_t read64le(unsigned char *p) { + return read32le(p) | (uint64_t)read32le(p + 4) << 32; +} +static inline void write64le(unsigned char *p, uint64_t x) { + write32le(p, x); write32le(p + 4, x >> 32); +} +static inline void add64le(unsigned char *p, int64_t x) { + write64le(p, read64le(p) + x); +} + +/* ------------ i386-gen.c ------------ */ +#if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64 +ST_FUNC void g(int c); +ST_FUNC void gen_le16(int c); +ST_FUNC void gen_le32(int c); +ST_FUNC void gen_addr32(int r, Sym *sym, int c); +ST_FUNC void gen_addrpc32(int r, Sym *sym, int c); +#endif + +#ifdef CONFIG_TCC_BCHECK +ST_FUNC void gen_bounded_ptr_add(void); +ST_FUNC void gen_bounded_ptr_deref(void); +#endif + +/* ------------ x86_64-gen.c ------------ */ +#ifdef TCC_TARGET_X86_64 +ST_FUNC void gen_addr64(int r, Sym *sym, int64_t c); +ST_FUNC void gen_opl(int op); +#endif + +/* ------------ arm-gen.c ------------ */ +#ifdef TCC_TARGET_ARM +#if defined(TCC_ARM_EABI) && !defined(CONFIG_TCC_ELFINTERP) +PUB_FUNC const char *default_elfinterp(struct TCCState *s); +#endif +ST_FUNC void arm_init(struct TCCState *s); +ST_FUNC void gen_cvt_itof1(int t); +#endif + +/* ------------ arm64-gen.c ------------ */ +#ifdef TCC_TARGET_ARM64 +ST_FUNC void gen_cvt_sxtw(void); +ST_FUNC void gen_opl(int op); +ST_FUNC void gfunc_return(CType *func_type); +ST_FUNC void gen_va_start(void); +ST_FUNC void gen_va_arg(CType *t); +ST_FUNC void gen_clear_cache(void); +#endif + +/* ------------ c67-gen.c ------------ */ +#ifdef TCC_TARGET_C67 +#endif + +/* ------------ tcccoff.c ------------ */ + +#ifdef TCC_TARGET_COFF +ST_FUNC int tcc_output_coff(TCCState *s1, FILE *f); +ST_FUNC int tcc_load_coff(TCCState * s1, int fd); +#endif + +/* ------------ tccasm.c ------------ */ +ST_FUNC void asm_instr(void); +ST_FUNC void asm_global_instr(void); +#ifdef CONFIG_TCC_ASM +ST_FUNC int find_constraint(ASMOperand *operands, int nb_operands, const char *name, const char **pp); +ST_FUNC Sym* get_asm_sym(int name, Sym *csym); +ST_FUNC void asm_expr(TCCState *s1, ExprValue *pe); +ST_FUNC int asm_int_expr(TCCState *s1); +ST_FUNC int tcc_assemble(TCCState *s1, int do_preprocess); +/* ------------ i386-asm.c ------------ */ +ST_FUNC void gen_expr32(ExprValue *pe); +#ifdef TCC_TARGET_X86_64 +ST_FUNC void gen_expr64(ExprValue *pe); +#endif +ST_FUNC void asm_opcode(TCCState *s1, int opcode); +ST_FUNC int asm_parse_regvar(int t); +ST_FUNC void asm_compute_constraints(ASMOperand *operands, int nb_operands, int nb_outputs, const uint8_t *clobber_regs, int *pout_reg); +ST_FUNC void subst_asm_operand(CString *add_str, SValue *sv, int modifier); +ST_FUNC void asm_gen_code(ASMOperand *operands, int nb_operands, int nb_outputs, int is_output, uint8_t *clobber_regs, int out_reg); +ST_FUNC void asm_clobber(uint8_t *clobber_regs, const char *str); +#endif + +/* ------------ tccpe.c -------------- */ +#ifdef TCC_TARGET_PE +ST_FUNC int pe_load_file(struct TCCState *s1, const char *filename, int fd); +ST_FUNC int pe_output_file(TCCState * s1, const char *filename); +ST_FUNC int pe_putimport(TCCState *s1, int dllindex, const char *name, addr_t value); +#if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64 +ST_FUNC SValue *pe_getimport(SValue *sv, SValue *v2); +#endif +#ifdef TCC_TARGET_X86_64 +ST_FUNC void pe_add_unwind_data(unsigned start, unsigned end, unsigned stack); +#endif +PUB_FUNC int tcc_get_dllexports(const char *filename, char **pp); +/* symbol properties stored in Elf32_Sym->st_other */ +# define ST_PE_EXPORT 0x10 +# define ST_PE_IMPORT 0x20 +# define ST_PE_STDCALL 0x40 +#endif +/* ------------ tccrun.c ----------------- */ +#ifdef TCC_IS_NATIVE +#ifdef CONFIG_TCC_STATIC +#define RTLD_LAZY 0x001 +#define RTLD_NOW 0x002 +#define RTLD_GLOBAL 0x100 +#define RTLD_DEFAULT NULL +/* dummy function for profiling */ +ST_FUNC void *dlopen(const char *filename, int flag); +ST_FUNC void dlclose(void *p); +ST_FUNC const char *dlerror(void); +ST_FUNC void *dlsym(void *handle, const char *symbol); +#endif +#ifdef CONFIG_TCC_BACKTRACE +ST_DATA int rt_num_callers; +ST_DATA const char **rt_bound_error_msg; +ST_DATA void *rt_prog_main; +ST_FUNC void tcc_set_num_callers(int n); +#endif +ST_FUNC void tcc_run_free(TCCState *s1); +#endif + +/* ------------ tcctools.c ----------------- */ +#if 0 /* included in tcc.c */ +ST_FUNC int tcc_tool_ar(TCCState *s, int argc, char **argv); +#ifdef TCC_TARGET_PE +ST_FUNC int tcc_tool_impdef(TCCState *s, int argc, char **argv); +#endif +ST_FUNC void tcc_tool_cross(TCCState *s, char **argv, int option); +ST_FUNC void gen_makedeps(TCCState *s, const char *target, const char *filename); +#endif + +/********************************************************/ +#undef ST_DATA +#if ONE_SOURCE +#define ST_DATA static +#else +#define ST_DATA +#endif +/********************************************************/ +#endif /* _TCC_H */ diff --git a/tinyc/tccasm.c b/tinyc/tccasm.c new file mode 100644 index 000000000..ac1618a52 --- /dev/null +++ b/tinyc/tccasm.c @@ -0,0 +1,1303 @@ +/* + * GAS like assembler for TCC + * + * Copyright (c) 2001-2004 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "tcc.h" +#ifdef CONFIG_TCC_ASM + +ST_FUNC int asm_get_local_label_name(TCCState *s1, unsigned int n) +{ + char buf[64]; + TokenSym *ts; + + snprintf(buf, sizeof(buf), "L..%u", n); + ts = tok_alloc(buf, strlen(buf)); + return ts->tok; +} + +ST_FUNC void asm_expr(TCCState *s1, ExprValue *pe); +static int tcc_assemble_internal(TCCState *s1, int do_preprocess, int global); +static Sym sym_dot; + +/* Return a symbol we can use inside the assembler, having name NAME. + The assembler symbol table is different from the C symbol table + (and the Sym members are used differently). But we must be able + to look up file-global C symbols from inside the assembler, e.g. + for global asm blocks to be able to refer to defined C symbols. + + This routine gives back either an existing asm-internal + symbol, or a new one. In the latter case the new asm-internal + symbol is initialized with info from the C symbol table. + + If CSYM is non-null we take symbol info from it, otherwise + we look up NAME in the C symbol table and use that. */ +ST_FUNC Sym* get_asm_sym(int name, Sym *csym) +{ + Sym *sym = label_find(name); + if (!sym) { + sym = label_push(&tcc_state->asm_labels, name, 0); + sym->type.t = VT_VOID | VT_EXTERN; + if (!csym) { + csym = sym_find(name); + /* We might be called for an asm block from inside a C routine + and so might have local decls on the identifier stack. Search + for the first global one. */ + while (csym && csym->sym_scope) + csym = csym->prev_tok; + } + /* Now, if we have a defined global symbol copy over + section and offset. */ + if (csym && + ((csym->r & (VT_SYM|VT_CONST)) == (VT_SYM|VT_CONST)) && + csym->c) { + ElfW(Sym) *esym; + esym = &((ElfW(Sym) *)symtab_section->data)[csym->c]; + sym->c = csym->c; + sym->r = esym->st_shndx; + sym->jnext = esym->st_value; + /* XXX can't yet store st_size anywhere. */ + sym->type.t &= ~VT_EXTERN; + /* Mark that this asm symbol doesn't need to be fed back. */ + sym->a.dllimport = 1; + } else { + sym->type.t |= VT_STATIC; + } + } + return sym; +} + +/* We do not use the C expression parser to handle symbols. Maybe the + C expression parser could be tweaked to do so. */ + +static void asm_expr_unary(TCCState *s1, ExprValue *pe) +{ + Sym *sym; + int op, label; + uint64_t n; + const char *p; + + switch(tok) { + case TOK_PPNUM: + p = tokc.str.data; + n = strtoull(p, (char **)&p, 0); + if (*p == 'b' || *p == 'f') { + /* backward or forward label */ + label = asm_get_local_label_name(s1, n); + sym = label_find(label); + if (*p == 'b') { + /* backward : find the last corresponding defined label */ + if (sym && sym->r == 0) + sym = sym->prev_tok; + if (!sym) + tcc_error("local label '%d' not found backward", n); + } else { + /* forward */ + if (!sym || sym->r) { + /* if the last label is defined, then define a new one */ + sym = label_push(&s1->asm_labels, label, 0); + sym->type.t = VT_STATIC | VT_VOID | VT_EXTERN; + } + } + pe->v = 0; + pe->sym = sym; + pe->pcrel = 0; + } else if (*p == '\0') { + pe->v = n; + pe->sym = NULL; + pe->pcrel = 0; + } else { + tcc_error("invalid number syntax"); + } + next(); + break; + case '+': + next(); + asm_expr_unary(s1, pe); + break; + case '-': + case '~': + op = tok; + next(); + asm_expr_unary(s1, pe); + if (pe->sym) + tcc_error("invalid operation with label"); + if (op == '-') + pe->v = -pe->v; + else + pe->v = ~pe->v; + break; + case TOK_CCHAR: + case TOK_LCHAR: + pe->v = tokc.i; + pe->sym = NULL; + pe->pcrel = 0; + next(); + break; + case '(': + next(); + asm_expr(s1, pe); + skip(')'); + break; + case '.': + pe->v = 0; + pe->sym = &sym_dot; + pe->pcrel = 0; + sym_dot.type.t = VT_VOID | VT_STATIC; + sym_dot.r = cur_text_section->sh_num; + sym_dot.jnext = ind; + next(); + break; + default: + if (tok >= TOK_IDENT) { + /* label case : if the label was not found, add one */ + sym = get_asm_sym(tok, NULL); + if (sym->r == SHN_ABS) { + /* if absolute symbol, no need to put a symbol value */ + pe->v = sym->jnext; + pe->sym = NULL; + pe->pcrel = 0; + } else { + pe->v = 0; + pe->sym = sym; + pe->pcrel = 0; + } + next(); + } else { + tcc_error("bad expression syntax [%s]", get_tok_str(tok, &tokc)); + } + break; + } +} + +static void asm_expr_prod(TCCState *s1, ExprValue *pe) +{ + int op; + ExprValue e2; + + asm_expr_unary(s1, pe); + for(;;) { + op = tok; + if (op != '*' && op != '/' && op != '%' && + op != TOK_SHL && op != TOK_SAR) + break; + next(); + asm_expr_unary(s1, &e2); + if (pe->sym || e2.sym) + tcc_error("invalid operation with label"); + switch(op) { + case '*': + pe->v *= e2.v; + break; + case '/': + if (e2.v == 0) { + div_error: + tcc_error("division by zero"); + } + pe->v /= e2.v; + break; + case '%': + if (e2.v == 0) + goto div_error; + pe->v %= e2.v; + break; + case TOK_SHL: + pe->v <<= e2.v; + break; + default: + case TOK_SAR: + pe->v >>= e2.v; + break; + } + } +} + +static void asm_expr_logic(TCCState *s1, ExprValue *pe) +{ + int op; + ExprValue e2; + + asm_expr_prod(s1, pe); + for(;;) { + op = tok; + if (op != '&' && op != '|' && op != '^') + break; + next(); + asm_expr_prod(s1, &e2); + if (pe->sym || e2.sym) + tcc_error("invalid operation with label"); + switch(op) { + case '&': + pe->v &= e2.v; + break; + case '|': + pe->v |= e2.v; + break; + default: + case '^': + pe->v ^= e2.v; + break; + } + } +} + +static inline void asm_expr_sum(TCCState *s1, ExprValue *pe) +{ + int op; + ExprValue e2; + + asm_expr_logic(s1, pe); + for(;;) { + op = tok; + if (op != '+' && op != '-') + break; + next(); + asm_expr_logic(s1, &e2); + if (op == '+') { + if (pe->sym != NULL && e2.sym != NULL) + goto cannot_relocate; + pe->v += e2.v; + if (pe->sym == NULL && e2.sym != NULL) + pe->sym = e2.sym; + } else { + pe->v -= e2.v; + /* NOTE: we are less powerful than gas in that case + because we store only one symbol in the expression */ + if (!e2.sym) { + /* OK */ + } else if (pe->sym == e2.sym) { + /* OK */ + pe->sym = NULL; /* same symbols can be subtracted to NULL */ + } else if (pe->sym && pe->sym->r == e2.sym->r && pe->sym->r != 0) { + /* we also accept defined symbols in the same section */ + pe->v += pe->sym->jnext - e2.sym->jnext; + pe->sym = NULL; + } else if (e2.sym->r == cur_text_section->sh_num) { + /* When subtracting a defined symbol in current section + this actually makes the value PC-relative. */ + pe->v -= e2.sym->jnext - ind - 4; + pe->pcrel = 1; + e2.sym = NULL; + } else { + cannot_relocate: + tcc_error("invalid operation with label"); + } + } + } +} + +static inline void asm_expr_cmp(TCCState *s1, ExprValue *pe) +{ + int op; + ExprValue e2; + + asm_expr_sum(s1, pe); + for(;;) { + op = tok; + if (op != TOK_EQ && op != TOK_NE + && (op > TOK_GT || op < TOK_ULE)) + break; + next(); + asm_expr_sum(s1, &e2); + if (pe->sym || e2.sym) + tcc_error("invalid operation with label"); + switch(op) { + case TOK_EQ: + pe->v = pe->v == e2.v; + break; + case TOK_NE: + pe->v = pe->v != e2.v; + break; + case TOK_LT: + pe->v = (int64_t)pe->v < (int64_t)e2.v; + break; + case TOK_GE: + pe->v = (int64_t)pe->v >= (int64_t)e2.v; + break; + case TOK_LE: + pe->v = (int64_t)pe->v <= (int64_t)e2.v; + break; + case TOK_GT: + pe->v = (int64_t)pe->v > (int64_t)e2.v; + break; + default: + break; + } + /* GAS compare results are -1/0 not 1/0. */ + pe->v = -(int64_t)pe->v; + } +} + +ST_FUNC void asm_expr(TCCState *s1, ExprValue *pe) +{ + asm_expr_cmp(s1, pe); +} + +ST_FUNC int asm_int_expr(TCCState *s1) +{ + ExprValue e; + asm_expr(s1, &e); + if (e.sym) + expect("constant"); + return e.v; +} + +/* NOTE: the same name space as C labels is used to avoid using too + much memory when storing labels in TokenStrings */ +static Sym* asm_new_label1(TCCState *s1, int label, int is_local, + int sh_num, int value) +{ + Sym *sym; + + sym = label_find(label); + if (sym) { + /* A VT_EXTERN symbol, even if it has a section is considered + overridable. This is how we "define" .set targets. Real + definitions won't have VT_EXTERN set. */ + if (sym->r && !(sym->type.t & VT_EXTERN)) { + /* the label is already defined */ + if (!is_local) { + tcc_error("assembler label '%s' already defined", + get_tok_str(label, NULL)); + } else { + /* redefinition of local labels is possible */ + goto new_label; + } + } + } else { + new_label: + sym = label_push(&s1->asm_labels, label, 0); + /* If we need a symbol to hold a value, mark it as + tentative only (for .set). If this is for a real label + we'll remove VT_EXTERN. */ + sym->type.t = VT_STATIC | VT_VOID | VT_EXTERN; + } + sym->r = sh_num; + sym->jnext = value; + return sym; +} + +static Sym* asm_new_label(TCCState *s1, int label, int is_local) +{ + return asm_new_label1(s1, label, is_local, cur_text_section->sh_num, ind); +} + +/* Set the value of LABEL to that of some expression (possibly + involving other symbols). LABEL can be overwritten later still. */ +static Sym* set_symbol(TCCState *s1, int label) +{ + long n; + ExprValue e; + next(); + asm_expr(s1, &e); + n = e.v; + if (e.sym) + n += e.sym->jnext; + return asm_new_label1(s1, label, 0, e.sym ? e.sym->r : SHN_ABS, n); +} + +static void asm_free_labels(TCCState *st) +{ + Sym *s, *s1; + Section *sec; + + for(s = st->asm_labels; s != NULL; s = s1) { + s1 = s->prev; + /* define symbol value in object file */ + s->type.t &= ~VT_EXTERN; + if (s->r && !s->a.dllimport) { + if (s->r == SHN_ABS) + sec = SECTION_ABS; + else + sec = st->sections[s->r]; + put_extern_sym2(s, sec, s->jnext, 0, 0); + } + /* remove label */ + table_ident[s->v - TOK_IDENT]->sym_label = NULL; + sym_free(s); + } + st->asm_labels = NULL; +} + +static void use_section1(TCCState *s1, Section *sec) +{ + cur_text_section->data_offset = ind; + cur_text_section = sec; + ind = cur_text_section->data_offset; +} + +static void use_section(TCCState *s1, const char *name) +{ + Section *sec; + sec = find_section(s1, name); + use_section1(s1, sec); +} + +static void push_section(TCCState *s1, const char *name) +{ + Section *sec = find_section(s1, name); + sec->prev = cur_text_section; + use_section1(s1, sec); +} + +static void pop_section(TCCState *s1) +{ + Section *prev = cur_text_section->prev; + if (!prev) + tcc_error(".popsection without .pushsection"); + cur_text_section->prev = NULL; + use_section1(s1, prev); +} + +static void asm_parse_directive(TCCState *s1, int global) +{ + int n, offset, v, size, tok1; + Section *sec; + uint8_t *ptr; + + /* assembler directive */ + sec = cur_text_section; + switch(tok) { + case TOK_ASMDIR_align: + case TOK_ASMDIR_balign: + case TOK_ASMDIR_p2align: + case TOK_ASMDIR_skip: + case TOK_ASMDIR_space: + tok1 = tok; + next(); + n = asm_int_expr(s1); + if (tok1 == TOK_ASMDIR_p2align) + { + if (n < 0 || n > 30) + tcc_error("invalid p2align, must be between 0 and 30"); + n = 1 << n; + tok1 = TOK_ASMDIR_align; + } + if (tok1 == TOK_ASMDIR_align || tok1 == TOK_ASMDIR_balign) { + if (n < 0 || (n & (n-1)) != 0) + tcc_error("alignment must be a positive power of two"); + offset = (ind + n - 1) & -n; + size = offset - ind; + /* the section must have a compatible alignment */ + if (sec->sh_addralign < n) + sec->sh_addralign = n; + } else { + if (n < 0) + n = 0; + size = n; + } + v = 0; + if (tok == ',') { + next(); + v = asm_int_expr(s1); + } + zero_pad: + if (sec->sh_type != SHT_NOBITS) { + sec->data_offset = ind; + ptr = section_ptr_add(sec, size); + memset(ptr, v, size); + } + ind += size; + break; + case TOK_ASMDIR_quad: +#ifdef TCC_TARGET_X86_64 + size = 8; + goto asm_data; +#else + next(); + for(;;) { + uint64_t vl; + const char *p; + + p = tokc.str.data; + if (tok != TOK_PPNUM) { + error_constant: + tcc_error("64 bit constant"); + } + vl = strtoll(p, (char **)&p, 0); + if (*p != '\0') + goto error_constant; + next(); + if (sec->sh_type != SHT_NOBITS) { + /* XXX: endianness */ + gen_le32(vl); + gen_le32(vl >> 32); + } else { + ind += 8; + } + if (tok != ',') + break; + next(); + } + break; +#endif + case TOK_ASMDIR_byte: + size = 1; + goto asm_data; + case TOK_ASMDIR_word: + case TOK_ASMDIR_short: + size = 2; + goto asm_data; + case TOK_ASMDIR_long: + case TOK_ASMDIR_int: + size = 4; + asm_data: + next(); + for(;;) { + ExprValue e; + asm_expr(s1, &e); + if (sec->sh_type != SHT_NOBITS) { + if (size == 4) { + gen_expr32(&e); +#ifdef TCC_TARGET_X86_64 + } else if (size == 8) { + gen_expr64(&e); +#endif + } else { + if (e.sym) + expect("constant"); + if (size == 1) + g(e.v); + else + gen_le16(e.v); + } + } else { + ind += size; + } + if (tok != ',') + break; + next(); + } + break; + case TOK_ASMDIR_fill: + { + int repeat, size, val, i, j; + uint8_t repeat_buf[8]; + next(); + repeat = asm_int_expr(s1); + if (repeat < 0) { + tcc_error("repeat < 0; .fill ignored"); + break; + } + size = 1; + val = 0; + if (tok == ',') { + next(); + size = asm_int_expr(s1); + if (size < 0) { + tcc_error("size < 0; .fill ignored"); + break; + } + if (size > 8) + size = 8; + if (tok == ',') { + next(); + val = asm_int_expr(s1); + } + } + /* XXX: endianness */ + repeat_buf[0] = val; + repeat_buf[1] = val >> 8; + repeat_buf[2] = val >> 16; + repeat_buf[3] = val >> 24; + repeat_buf[4] = 0; + repeat_buf[5] = 0; + repeat_buf[6] = 0; + repeat_buf[7] = 0; + for(i = 0; i < repeat; i++) { + for(j = 0; j < size; j++) { + g(repeat_buf[j]); + } + } + } + break; + case TOK_ASMDIR_rept: + { + int repeat; + TokenString *init_str; + next(); + repeat = asm_int_expr(s1); + init_str = tok_str_alloc(); + while (next(), tok != TOK_ASMDIR_endr) { + if (tok == CH_EOF) + tcc_error("we at end of file, .endr not found"); + tok_str_add_tok(init_str); + } + tok_str_add(init_str, -1); + tok_str_add(init_str, 0); + begin_macro(init_str, 1); + while (repeat-- > 0) { + tcc_assemble_internal(s1, (parse_flags & PARSE_FLAG_PREPROCESS), + global); + macro_ptr = init_str->str; + } + end_macro(); + next(); + break; + } + case TOK_ASMDIR_org: + { + unsigned long n; + ExprValue e; + next(); + asm_expr(s1, &e); + n = e.v; + if (e.sym) { + if (e.sym->r != cur_text_section->sh_num) + expect("constant or same-section symbol"); + n += e.sym->jnext; + } + if (n < ind) + tcc_error("attempt to .org backwards"); + v = 0; + size = n - ind; + goto zero_pad; + } + break; + case TOK_ASMDIR_set: + next(); + tok1 = tok; + next(); + /* Also accept '.set stuff', but don't do anything with this. + It's used in GAS to set various features like '.set mips16'. */ + if (tok == ',') + set_symbol(s1, tok1); + break; + case TOK_ASMDIR_globl: + case TOK_ASMDIR_global: + case TOK_ASMDIR_weak: + case TOK_ASMDIR_hidden: + tok1 = tok; + do { + Sym *sym; + + next(); + sym = get_asm_sym(tok, NULL); + if (tok1 != TOK_ASMDIR_hidden) + sym->type.t &= ~VT_STATIC; + if (tok1 == TOK_ASMDIR_weak) + sym->a.weak = 1; + else if (tok1 == TOK_ASMDIR_hidden) + sym->a.visibility = STV_HIDDEN; + next(); + } while (tok == ','); + break; + case TOK_ASMDIR_string: + case TOK_ASMDIR_ascii: + case TOK_ASMDIR_asciz: + { + const uint8_t *p; + int i, size, t; + + t = tok; + next(); + for(;;) { + if (tok != TOK_STR) + expect("string constant"); + p = tokc.str.data; + size = tokc.str.size; + if (t == TOK_ASMDIR_ascii && size > 0) + size--; + for(i = 0; i < size; i++) + g(p[i]); + next(); + if (tok == ',') { + next(); + } else if (tok != TOK_STR) { + break; + } + } + } + break; + case TOK_ASMDIR_text: + case TOK_ASMDIR_data: + case TOK_ASMDIR_bss: + { + char sname[64]; + tok1 = tok; + n = 0; + next(); + if (tok != ';' && tok != TOK_LINEFEED) { + n = asm_int_expr(s1); + next(); + } + if (n) + sprintf(sname, "%s%d", get_tok_str(tok1, NULL), n); + else + sprintf(sname, "%s", get_tok_str(tok1, NULL)); + use_section(s1, sname); + } + break; + case TOK_ASMDIR_file: + { + char filename[512]; + + filename[0] = '\0'; + next(); + + if (tok == TOK_STR) + pstrcat(filename, sizeof(filename), tokc.str.data); + else + pstrcat(filename, sizeof(filename), get_tok_str(tok, NULL)); + + if (s1->warn_unsupported) + tcc_warning("ignoring .file %s", filename); + + next(); + } + break; + case TOK_ASMDIR_ident: + { + char ident[256]; + + ident[0] = '\0'; + next(); + + if (tok == TOK_STR) + pstrcat(ident, sizeof(ident), tokc.str.data); + else + pstrcat(ident, sizeof(ident), get_tok_str(tok, NULL)); + + if (s1->warn_unsupported) + tcc_warning("ignoring .ident %s", ident); + + next(); + } + break; + case TOK_ASMDIR_size: + { + Sym *sym; + + next(); + sym = label_find(tok); + if (!sym) { + tcc_error("label not found: %s", get_tok_str(tok, NULL)); + } + + /* XXX .size name,label2-label1 */ + if (s1->warn_unsupported) + tcc_warning("ignoring .size %s,*", get_tok_str(tok, NULL)); + + next(); + skip(','); + while (tok != TOK_LINEFEED && tok != ';' && tok != CH_EOF) { + next(); + } + } + break; + case TOK_ASMDIR_type: + { + Sym *sym; + const char *newtype; + + next(); + sym = get_asm_sym(tok, NULL); + next(); + skip(','); + if (tok == TOK_STR) { + newtype = tokc.str.data; + } else { + if (tok == '@' || tok == '%') + next(); + newtype = get_tok_str(tok, NULL); + } + + if (!strcmp(newtype, "function") || !strcmp(newtype, "STT_FUNC")) { + sym->type.t = (sym->type.t & ~VT_BTYPE) | VT_FUNC; + } + else if (s1->warn_unsupported) + tcc_warning("change type of '%s' from 0x%x to '%s' ignored", + get_tok_str(sym->v, NULL), sym->type.t, newtype); + + next(); + } + break; + case TOK_ASMDIR_pushsection: + case TOK_ASMDIR_section: + { + char sname[256]; + int old_nb_section = s1->nb_sections; + + tok1 = tok; + /* XXX: support more options */ + next(); + sname[0] = '\0'; + while (tok != ';' && tok != TOK_LINEFEED && tok != ',') { + if (tok == TOK_STR) + pstrcat(sname, sizeof(sname), tokc.str.data); + else + pstrcat(sname, sizeof(sname), get_tok_str(tok, NULL)); + next(); + } + if (tok == ',') { + /* skip section options */ + next(); + if (tok != TOK_STR) + expect("string constant"); + next(); + if (tok == ',') { + next(); + if (tok == '@' || tok == '%') + next(); + next(); + } + } + last_text_section = cur_text_section; + if (tok1 == TOK_ASMDIR_section) + use_section(s1, sname); + else + push_section(s1, sname); + /* If we just allocated a new section reset its alignment to + 1. new_section normally acts for GCC compatibility and + sets alignment to PTR_SIZE. The assembler behaves different. */ + if (old_nb_section != s1->nb_sections) + cur_text_section->sh_addralign = 1; + } + break; + case TOK_ASMDIR_previous: + { + Section *sec; + next(); + if (!last_text_section) + tcc_error("no previous section referenced"); + sec = cur_text_section; + use_section1(s1, last_text_section); + last_text_section = sec; + } + break; + case TOK_ASMDIR_popsection: + next(); + pop_section(s1); + break; +#ifdef TCC_TARGET_I386 + case TOK_ASMDIR_code16: + { + next(); + s1->seg_size = 16; + } + break; + case TOK_ASMDIR_code32: + { + next(); + s1->seg_size = 32; + } + break; +#endif +#ifdef TCC_TARGET_X86_64 + /* added for compatibility with GAS */ + case TOK_ASMDIR_code64: + next(); + break; +#endif + default: + tcc_error("unknown assembler directive '.%s'", get_tok_str(tok, NULL)); + break; + } +} + + +/* assemble a file */ +static int tcc_assemble_internal(TCCState *s1, int do_preprocess, int global) +{ + int opcode; + int saved_parse_flags = parse_flags; + + /* XXX: undefine C labels */ + parse_flags = PARSE_FLAG_ASM_FILE | PARSE_FLAG_TOK_STR; + if (do_preprocess) + parse_flags |= PARSE_FLAG_PREPROCESS; + for(;;) { + next(); + if (tok == TOK_EOF) + break; + /* generate line number info */ + if (global && s1->do_debug) + tcc_debug_line(s1); + parse_flags |= PARSE_FLAG_LINEFEED; /* XXX: suppress that hack */ + redo: + if (tok == '#') { + /* horrible gas comment */ + while (tok != TOK_LINEFEED) + next(); + } else if (tok >= TOK_ASMDIR_FIRST && tok <= TOK_ASMDIR_LAST) { + asm_parse_directive(s1, global); + } else if (tok == TOK_PPNUM) { + Sym *sym; + const char *p; + int n; + p = tokc.str.data; + n = strtoul(p, (char **)&p, 10); + if (*p != '\0') + expect("':'"); + /* new local label */ + sym = asm_new_label(s1, asm_get_local_label_name(s1, n), 1); + /* Remove the marker for tentative definitions. */ + sym->type.t &= ~VT_EXTERN; + next(); + skip(':'); + goto redo; + } else if (tok >= TOK_IDENT) { + /* instruction or label */ + opcode = tok; + next(); + if (tok == ':') { + /* handle "extern void vide(void); __asm__("vide: ret");" as + "__asm__("globl vide\nvide: ret");" */ + Sym *sym = sym_find(opcode); + if (sym && (sym->type.t & VT_EXTERN) && global) { + sym = label_find(opcode); + if (!sym) { + sym = label_push(&s1->asm_labels, opcode, 0); + sym->type.t = VT_VOID | VT_EXTERN; + } + } + /* new label */ + sym = asm_new_label(s1, opcode, 0); + sym->type.t &= ~VT_EXTERN; + next(); + goto redo; + } else if (tok == '=') { + set_symbol(s1, opcode); + goto redo; + } else { + asm_opcode(s1, opcode); + } + } + /* end of line */ + if (tok != ';' && tok != TOK_LINEFEED) + expect("end of line"); + parse_flags &= ~PARSE_FLAG_LINEFEED; /* XXX: suppress that hack */ + } + + asm_free_labels(s1); + parse_flags = saved_parse_flags; + return 0; +} + +/* Assemble the current file */ +ST_FUNC int tcc_assemble(TCCState *s1, int do_preprocess) +{ + int ret; + tcc_debug_start(s1); + /* default section is text */ + cur_text_section = text_section; + ind = cur_text_section->data_offset; + nocode_wanted = 0; + ret = tcc_assemble_internal(s1, do_preprocess, 1); + cur_text_section->data_offset = ind; + tcc_debug_end(s1); + return ret; +} + +/********************************************************************/ +/* GCC inline asm support */ + +/* assemble the string 'str' in the current C compilation unit without + C preprocessing. NOTE: str is modified by modifying the '\0' at the + end */ +static void tcc_assemble_inline(TCCState *s1, char *str, int len, int global) +{ + const int *saved_macro_ptr = macro_ptr; + int dotid = set_idnum('.', IS_ID); + + tcc_open_bf(s1, ":asm:", len); + memcpy(file->buffer, str, len); + macro_ptr = NULL; + tcc_assemble_internal(s1, 0, global); + tcc_close(); + + set_idnum('.', dotid); + macro_ptr = saved_macro_ptr; +} + +/* find a constraint by its number or id (gcc 3 extended + syntax). return -1 if not found. Return in *pp in char after the + constraint */ +ST_FUNC int find_constraint(ASMOperand *operands, int nb_operands, + const char *name, const char **pp) +{ + int index; + TokenSym *ts; + const char *p; + + if (isnum(*name)) { + index = 0; + while (isnum(*name)) { + index = (index * 10) + (*name) - '0'; + name++; + } + if ((unsigned)index >= nb_operands) + index = -1; + } else if (*name == '[') { + name++; + p = strchr(name, ']'); + if (p) { + ts = tok_alloc(name, p - name); + for(index = 0; index < nb_operands; index++) { + if (operands[index].id == ts->tok) + goto found; + } + index = -1; + found: + name = p + 1; + } else { + index = -1; + } + } else { + index = -1; + } + if (pp) + *pp = name; + return index; +} + +static void subst_asm_operands(ASMOperand *operands, int nb_operands, + CString *out_str, CString *in_str) +{ + int c, index, modifier; + const char *str; + ASMOperand *op; + SValue sv; + + cstr_new(out_str); + str = in_str->data; + for(;;) { + c = *str++; + if (c == '%') { + if (*str == '%') { + str++; + goto add_char; + } + modifier = 0; + if (*str == 'c' || *str == 'n' || + *str == 'b' || *str == 'w' || *str == 'h' || *str == 'k' || + *str == 'q' || + /* P in GCC would add "@PLT" to symbol refs in PIC mode, + and make literal operands not be decorated with '$'. */ + *str == 'P') + modifier = *str++; + index = find_constraint(operands, nb_operands, str, &str); + if (index < 0) + tcc_error("invalid operand reference after %%"); + op = &operands[index]; + sv = *op->vt; + if (op->reg >= 0) { + sv.r = op->reg; + if ((op->vt->r & VT_VALMASK) == VT_LLOCAL && op->is_memory) + sv.r |= VT_LVAL; + } + subst_asm_operand(out_str, &sv, modifier); + } else { + add_char: + cstr_ccat(out_str, c); + if (c == '\0') + break; + } + } +} + + +static void parse_asm_operands(ASMOperand *operands, int *nb_operands_ptr, + int is_output) +{ + ASMOperand *op; + int nb_operands; + + if (tok != ':') { + nb_operands = *nb_operands_ptr; + for(;;) { + CString astr; + if (nb_operands >= MAX_ASM_OPERANDS) + tcc_error("too many asm operands"); + op = &operands[nb_operands++]; + op->id = 0; + if (tok == '[') { + next(); + if (tok < TOK_IDENT) + expect("identifier"); + op->id = tok; + next(); + skip(']'); + } + parse_mult_str(&astr, "string constant"); + op->constraint = tcc_malloc(astr.size); + strcpy(op->constraint, astr.data); + cstr_free(&astr); + skip('('); + gexpr(); + if (is_output) { + if (!(vtop->type.t & VT_ARRAY)) + test_lvalue(); + } else { + /* we want to avoid LLOCAL case, except when the 'm' + constraint is used. Note that it may come from + register storage, so we need to convert (reg) + case */ + if ((vtop->r & VT_LVAL) && + ((vtop->r & VT_VALMASK) == VT_LLOCAL || + (vtop->r & VT_VALMASK) < VT_CONST) && + !strchr(op->constraint, 'm')) { + gv(RC_INT); + } + } + op->vt = vtop; + skip(')'); + if (tok == ',') { + next(); + } else { + break; + } + } + *nb_operands_ptr = nb_operands; + } +} + +/* parse the GCC asm() instruction */ +ST_FUNC void asm_instr(void) +{ + CString astr, astr1; + ASMOperand operands[MAX_ASM_OPERANDS]; + int nb_outputs, nb_operands, i, must_subst, out_reg; + uint8_t clobber_regs[NB_ASM_REGS]; + + next(); + /* since we always generate the asm() instruction, we can ignore + volatile */ + if (tok == TOK_VOLATILE1 || tok == TOK_VOLATILE2 || tok == TOK_VOLATILE3) { + next(); + } + parse_asm_str(&astr); + nb_operands = 0; + nb_outputs = 0; + must_subst = 0; + memset(clobber_regs, 0, sizeof(clobber_regs)); + if (tok == ':') { + next(); + must_subst = 1; + /* output args */ + parse_asm_operands(operands, &nb_operands, 1); + nb_outputs = nb_operands; + if (tok == ':') { + next(); + if (tok != ')') { + /* input args */ + parse_asm_operands(operands, &nb_operands, 0); + if (tok == ':') { + /* clobber list */ + /* XXX: handle registers */ + next(); + for(;;) { + if (tok != TOK_STR) + expect("string constant"); + asm_clobber(clobber_regs, tokc.str.data); + next(); + if (tok == ',') { + next(); + } else { + break; + } + } + } + } + } + } + skip(')'); + /* NOTE: we do not eat the ';' so that we can restore the current + token after the assembler parsing */ + if (tok != ';') + expect("';'"); + + /* save all values in the memory */ + save_regs(0); + + /* compute constraints */ + asm_compute_constraints(operands, nb_operands, nb_outputs, + clobber_regs, &out_reg); + + /* substitute the operands in the asm string. No substitution is + done if no operands (GCC behaviour) */ +#ifdef ASM_DEBUG + printf("asm: \"%s\"\n", (char *)astr.data); +#endif + if (must_subst) { + subst_asm_operands(operands, nb_operands, &astr1, &astr); + cstr_free(&astr); + } else { + astr1 = astr; + } +#ifdef ASM_DEBUG + printf("subst_asm: \"%s\"\n", (char *)astr1.data); +#endif + + /* generate loads */ + asm_gen_code(operands, nb_operands, nb_outputs, 0, + clobber_regs, out_reg); + + /* assemble the string with tcc internal assembler */ + tcc_assemble_inline(tcc_state, astr1.data, astr1.size - 1, 0); + + /* restore the current C token */ + next(); + + /* store the output values if needed */ + asm_gen_code(operands, nb_operands, nb_outputs, 1, + clobber_regs, out_reg); + + /* free everything */ + for(i=0;iconstraint); + vpop(); + } + cstr_free(&astr1); +} + +ST_FUNC void asm_global_instr(void) +{ + CString astr; + int saved_nocode_wanted = nocode_wanted; + + /* Global asm blocks are always emitted. */ + nocode_wanted = 0; + next(); + parse_asm_str(&astr); + skip(')'); + /* NOTE: we do not eat the ';' so that we can restore the current + token after the assembler parsing */ + if (tok != ';') + expect("';'"); + +#ifdef ASM_DEBUG + printf("asm_global: \"%s\"\n", (char *)astr.data); +#endif + cur_text_section = text_section; + ind = cur_text_section->data_offset; + + /* assemble the string with tcc internal assembler */ + tcc_assemble_inline(tcc_state, astr.data, astr.size - 1, 1); + + cur_text_section->data_offset = ind; + + /* restore the current C token */ + next(); + + cstr_free(&astr); + nocode_wanted = saved_nocode_wanted; +} +#endif /* CONFIG_TCC_ASM */ diff --git a/tinyc/tcccoff.c b/tinyc/tcccoff.c new file mode 100644 index 000000000..1421ca265 --- /dev/null +++ b/tinyc/tcccoff.c @@ -0,0 +1,948 @@ +/* + * COFF file handling for TCC + * + * Copyright (c) 2003, 2004 TK + * Copyright (c) 2004 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "tcc.h" + +#define MAXNSCNS 255 /* MAXIMUM NUMBER OF SECTIONS */ +#define MAX_STR_TABLE 1000000 +AOUTHDR o_filehdr; /* OPTIONAL (A.OUT) FILE HEADER */ + +SCNHDR section_header[MAXNSCNS]; + +#define MAX_FUNCS 1000 +#define MAX_FUNC_NAME_LENGTH 128 + +int nFuncs; +char Func[MAX_FUNCS][MAX_FUNC_NAME_LENGTH]; +char AssociatedFile[MAX_FUNCS][MAX_FUNC_NAME_LENGTH]; +int LineNoFilePtr[MAX_FUNCS]; +int EndAddress[MAX_FUNCS]; +int LastLineNo[MAX_FUNCS]; +int FuncEntries[MAX_FUNCS]; + +int OutputTheSection(Section * sect); +short int GetCoffFlags(const char *s); +void SortSymbolTable(void); +Section *FindSection(TCCState * s1, const char *sname); + +int C67_main_entry_point; + +int FindCoffSymbolIndex(const char *func_name); +int nb_syms; + +typedef struct { + long tag; + long size; + long fileptr; + long nextsym; + short int dummy; +} AUXFUNC; + +typedef struct { + long regmask; + unsigned short lineno; + unsigned short nentries; + int localframe; + int nextentry; + short int dummy; +} AUXBF; + +typedef struct { + long dummy; + unsigned short lineno; + unsigned short dummy1; + int dummy2; + int dummy3; + unsigned short dummy4; +} AUXEF; + +ST_FUNC int tcc_output_coff(TCCState *s1, FILE *f) +{ + Section *tcc_sect; + SCNHDR *coff_sec; + int file_pointer; + char *Coff_str_table, *pCoff_str_table; + int CoffTextSectionNo, coff_nb_syms; + FILHDR file_hdr; /* FILE HEADER STRUCTURE */ + Section *stext, *sdata, *sbss; + int i, NSectionsToOutput = 0; + + Coff_str_table = pCoff_str_table = NULL; + + stext = FindSection(s1, ".text"); + sdata = FindSection(s1, ".data"); + sbss = FindSection(s1, ".bss"); + + nb_syms = symtab_section->data_offset / sizeof(Elf32_Sym); + coff_nb_syms = FindCoffSymbolIndex("XXXXXXXXXX1"); + + file_hdr.f_magic = COFF_C67_MAGIC; /* magic number */ + file_hdr.f_timdat = 0; /* time & date stamp */ + file_hdr.f_opthdr = sizeof(AOUTHDR); /* sizeof(optional hdr) */ + file_hdr.f_flags = 0x1143; /* flags (copied from what code composer does) */ + file_hdr.f_TargetID = 0x99; /* for C6x = 0x0099 */ + + o_filehdr.magic = 0x0108; /* see magic.h */ + o_filehdr.vstamp = 0x0190; /* version stamp */ + o_filehdr.tsize = stext->data_offset; /* text size in bytes, padded to FW bdry */ + o_filehdr.dsize = sdata->data_offset; /* initialized data " " */ + o_filehdr.bsize = sbss->data_offset; /* uninitialized data " " */ + o_filehdr.entrypt = C67_main_entry_point; /* entry pt. */ + o_filehdr.text_start = stext->sh_addr; /* base of text used for this file */ + o_filehdr.data_start = sdata->sh_addr; /* base of data used for this file */ + + + // create all the section headers + + file_pointer = FILHSZ + sizeof(AOUTHDR); + + CoffTextSectionNo = -1; + + for (i = 1; i < s1->nb_sections; i++) { + coff_sec = §ion_header[i]; + tcc_sect = s1->sections[i]; + + if (OutputTheSection(tcc_sect)) { + NSectionsToOutput++; + + if (CoffTextSectionNo == -1 && tcc_sect == stext) + CoffTextSectionNo = NSectionsToOutput; // rem which coff sect number the .text sect is + + strcpy(coff_sec->s_name, tcc_sect->name); /* section name */ + + coff_sec->s_paddr = tcc_sect->sh_addr; /* physical address */ + coff_sec->s_vaddr = tcc_sect->sh_addr; /* virtual address */ + coff_sec->s_size = tcc_sect->data_offset; /* section size */ + coff_sec->s_scnptr = 0; /* file ptr to raw data for section */ + coff_sec->s_relptr = 0; /* file ptr to relocation */ + coff_sec->s_lnnoptr = 0; /* file ptr to line numbers */ + coff_sec->s_nreloc = 0; /* number of relocation entries */ + coff_sec->s_flags = GetCoffFlags(coff_sec->s_name); /* flags */ + coff_sec->s_reserved = 0; /* reserved byte */ + coff_sec->s_page = 0; /* memory page id */ + + file_pointer += sizeof(SCNHDR); + } + } + + file_hdr.f_nscns = NSectionsToOutput; /* number of sections */ + + // now loop through and determine file pointer locations + // for the raw data + + + for (i = 1; i < s1->nb_sections; i++) { + coff_sec = §ion_header[i]; + tcc_sect = s1->sections[i]; + + if (OutputTheSection(tcc_sect)) { + // put raw data + coff_sec->s_scnptr = file_pointer; /* file ptr to raw data for section */ + file_pointer += coff_sec->s_size; + } + } + + // now loop through and determine file pointer locations + // for the relocation data + + for (i = 1; i < s1->nb_sections; i++) { + coff_sec = §ion_header[i]; + tcc_sect = s1->sections[i]; + + if (OutputTheSection(tcc_sect)) { + // put relocations data + if (coff_sec->s_nreloc > 0) { + coff_sec->s_relptr = file_pointer; /* file ptr to relocation */ + file_pointer += coff_sec->s_nreloc * sizeof(struct reloc); + } + } + } + + // now loop through and determine file pointer locations + // for the line number data + + for (i = 1; i < s1->nb_sections; i++) { + coff_sec = §ion_header[i]; + tcc_sect = s1->sections[i]; + + coff_sec->s_nlnno = 0; + coff_sec->s_lnnoptr = 0; + + if (s1->do_debug && tcc_sect == stext) { + // count how many line nos data + + // also find association between source file name and function + // so we can sort the symbol table + + + Stab_Sym *sym, *sym_end; + char func_name[MAX_FUNC_NAME_LENGTH], + last_func_name[MAX_FUNC_NAME_LENGTH]; + unsigned long func_addr, last_pc, pc; + const char *incl_files[INCLUDE_STACK_SIZE]; + int incl_index, len, last_line_num; + const char *str, *p; + + coff_sec->s_lnnoptr = file_pointer; /* file ptr to linno */ + + + func_name[0] = '\0'; + func_addr = 0; + incl_index = 0; + last_func_name[0] = '\0'; + last_pc = 0xffffffff; + last_line_num = 1; + sym = (Stab_Sym *) stab_section->data + 1; + sym_end = + (Stab_Sym *) (stab_section->data + + stab_section->data_offset); + + nFuncs = 0; + while (sym < sym_end) { + switch (sym->n_type) { + /* function start or end */ + case N_FUN: + if (sym->n_strx == 0) { + // end of function + + coff_sec->s_nlnno++; + file_pointer += LINESZ; + + pc = sym->n_value + func_addr; + func_name[0] = '\0'; + func_addr = 0; + EndAddress[nFuncs] = pc; + FuncEntries[nFuncs] = + (file_pointer - + LineNoFilePtr[nFuncs]) / LINESZ - 1; + LastLineNo[nFuncs++] = last_line_num + 1; + } else { + // beginning of function + + LineNoFilePtr[nFuncs] = file_pointer; + coff_sec->s_nlnno++; + file_pointer += LINESZ; + + str = + (const char *) stabstr_section->data + + sym->n_strx; + + p = strchr(str, ':'); + if (!p) { + pstrcpy(func_name, sizeof(func_name), str); + pstrcpy(Func[nFuncs], sizeof(func_name), str); + } else { + len = p - str; + if (len > sizeof(func_name) - 1) + len = sizeof(func_name) - 1; + memcpy(func_name, str, len); + memcpy(Func[nFuncs], str, len); + func_name[len] = '\0'; + } + + // save the file that it came in so we can sort later + pstrcpy(AssociatedFile[nFuncs], sizeof(func_name), + incl_files[incl_index - 1]); + + func_addr = sym->n_value; + } + break; + + /* line number info */ + case N_SLINE: + pc = sym->n_value + func_addr; + + last_pc = pc; + last_line_num = sym->n_desc; + + /* XXX: slow! */ + strcpy(last_func_name, func_name); + + coff_sec->s_nlnno++; + file_pointer += LINESZ; + break; + /* include files */ + case N_BINCL: + str = + (const char *) stabstr_section->data + sym->n_strx; + add_incl: + if (incl_index < INCLUDE_STACK_SIZE) { + incl_files[incl_index++] = str; + } + break; + case N_EINCL: + if (incl_index > 1) + incl_index--; + break; + case N_SO: + if (sym->n_strx == 0) { + incl_index = 0; /* end of translation unit */ + } else { + str = + (const char *) stabstr_section->data + + sym->n_strx; + /* do not add path */ + len = strlen(str); + if (len > 0 && str[len - 1] != '/') + goto add_incl; + } + break; + } + sym++; + } + } + + } + + file_hdr.f_symptr = file_pointer; /* file pointer to symtab */ + + if (s1->do_debug) + file_hdr.f_nsyms = coff_nb_syms; /* number of symtab entries */ + else + file_hdr.f_nsyms = 0; + + file_pointer += file_hdr.f_nsyms * SYMNMLEN; + + // OK now we are all set to write the file + + + fwrite(&file_hdr, FILHSZ, 1, f); + fwrite(&o_filehdr, sizeof(o_filehdr), 1, f); + + // write section headers + for (i = 1; i < s1->nb_sections; i++) { + coff_sec = §ion_header[i]; + tcc_sect = s1->sections[i]; + + if (OutputTheSection(tcc_sect)) { + fwrite(coff_sec, sizeof(SCNHDR), 1, f); + } + } + + // write raw data + for (i = 1; i < s1->nb_sections; i++) { + coff_sec = §ion_header[i]; + tcc_sect = s1->sections[i]; + + if (OutputTheSection(tcc_sect)) { + fwrite(tcc_sect->data, tcc_sect->data_offset, 1, f); + } + } + + // write relocation data + for (i = 1; i < s1->nb_sections; i++) { + coff_sec = §ion_header[i]; + tcc_sect = s1->sections[i]; + + if (OutputTheSection(tcc_sect)) { + // put relocations data + if (coff_sec->s_nreloc > 0) { + fwrite(tcc_sect->reloc, + coff_sec->s_nreloc * sizeof(struct reloc), 1, f); + } + } + } + + + // group the symbols in order of filename, func1, func2, etc + // finally global symbols + + if (s1->do_debug) + SortSymbolTable(); + + // write line no data + + for (i = 1; i < s1->nb_sections; i++) { + coff_sec = §ion_header[i]; + tcc_sect = s1->sections[i]; + + if (s1->do_debug && tcc_sect == stext) { + // count how many line nos data + + + Stab_Sym *sym, *sym_end; + char func_name[128], last_func_name[128]; + unsigned long func_addr, last_pc, pc; + const char *incl_files[INCLUDE_STACK_SIZE]; + int incl_index, len, last_line_num; + const char *str, *p; + + LINENO CoffLineNo; + + func_name[0] = '\0'; + func_addr = 0; + incl_index = 0; + last_func_name[0] = '\0'; + last_pc = 0; + last_line_num = 1; + sym = (Stab_Sym *) stab_section->data + 1; + sym_end = + (Stab_Sym *) (stab_section->data + + stab_section->data_offset); + + while (sym < sym_end) { + switch (sym->n_type) { + /* function start or end */ + case N_FUN: + if (sym->n_strx == 0) { + // end of function + + CoffLineNo.l_addr.l_paddr = last_pc; + CoffLineNo.l_lnno = last_line_num + 1; + fwrite(&CoffLineNo, 6, 1, f); + + pc = sym->n_value + func_addr; + func_name[0] = '\0'; + func_addr = 0; + } else { + // beginning of function + + str = + (const char *) stabstr_section->data + + sym->n_strx; + + + p = strchr(str, ':'); + if (!p) { + pstrcpy(func_name, sizeof(func_name), str); + } else { + len = p - str; + if (len > sizeof(func_name) - 1) + len = sizeof(func_name) - 1; + memcpy(func_name, str, len); + func_name[len] = '\0'; + } + func_addr = sym->n_value; + last_pc = func_addr; + last_line_num = -1; + + // output a function begin + + CoffLineNo.l_addr.l_symndx = + FindCoffSymbolIndex(func_name); + CoffLineNo.l_lnno = 0; + + fwrite(&CoffLineNo, 6, 1, f); + } + break; + + /* line number info */ + case N_SLINE: + pc = sym->n_value + func_addr; + + + /* XXX: slow! */ + strcpy(last_func_name, func_name); + + // output a line reference + + CoffLineNo.l_addr.l_paddr = last_pc; + + if (last_line_num == -1) { + CoffLineNo.l_lnno = sym->n_desc; + } else { + CoffLineNo.l_lnno = last_line_num + 1; + } + + fwrite(&CoffLineNo, 6, 1, f); + + last_pc = pc; + last_line_num = sym->n_desc; + + break; + + /* include files */ + case N_BINCL: + str = + (const char *) stabstr_section->data + sym->n_strx; + add_incl2: + if (incl_index < INCLUDE_STACK_SIZE) { + incl_files[incl_index++] = str; + } + break; + case N_EINCL: + if (incl_index > 1) + incl_index--; + break; + case N_SO: + if (sym->n_strx == 0) { + incl_index = 0; /* end of translation unit */ + } else { + str = + (const char *) stabstr_section->data + + sym->n_strx; + /* do not add path */ + len = strlen(str); + if (len > 0 && str[len - 1] != '/') + goto add_incl2; + } + break; + } + sym++; + } + } + } + + // write symbol table + if (s1->do_debug) { + int k; + struct syment csym; + AUXFUNC auxfunc; + AUXBF auxbf; + AUXEF auxef; + int i; + Elf32_Sym *p; + const char *name; + int nstr; + int n = 0; + + Coff_str_table = (char *) tcc_malloc(MAX_STR_TABLE); + pCoff_str_table = Coff_str_table; + nstr = 0; + + p = (Elf32_Sym *) symtab_section->data; + + + for (i = 0; i < nb_syms; i++) { + + name = symtab_section->link->data + p->st_name; + + for (k = 0; k < 8; k++) + csym._n._n_name[k] = 0; + + if (strlen(name) <= 8) { + strcpy(csym._n._n_name, name); + } else { + if (pCoff_str_table - Coff_str_table + strlen(name) > + MAX_STR_TABLE - 1) + tcc_error("String table too large"); + + csym._n._n_n._n_zeroes = 0; + csym._n._n_n._n_offset = + pCoff_str_table - Coff_str_table + 4; + + strcpy(pCoff_str_table, name); + pCoff_str_table += strlen(name) + 1; // skip over null + nstr++; + } + + if (p->st_info == 4) { + // put a filename symbol + csym.n_value = 33; // ????? + csym.n_scnum = N_DEBUG; + csym.n_type = 0; + csym.n_sclass = C_FILE; + csym.n_numaux = 0; + fwrite(&csym, 18, 1, f); + n++; + + } else if (p->st_info == 0x12) { + // find the function data + + for (k = 0; k < nFuncs; k++) { + if (strcmp(name, Func[k]) == 0) + break; + } + + if (k >= nFuncs) { + tcc_error("debug info can't find function: %s", name); + } + // put a Function Name + + csym.n_value = p->st_value; // physical address + csym.n_scnum = CoffTextSectionNo; + csym.n_type = MKTYPE(T_INT, DT_FCN, 0, 0, 0, 0, 0); + csym.n_sclass = C_EXT; + csym.n_numaux = 1; + fwrite(&csym, 18, 1, f); + + // now put aux info + + auxfunc.tag = 0; + auxfunc.size = EndAddress[k] - p->st_value; + auxfunc.fileptr = LineNoFilePtr[k]; + auxfunc.nextsym = n + 6; // tktk + auxfunc.dummy = 0; + fwrite(&auxfunc, 18, 1, f); + + // put a .bf + + strcpy(csym._n._n_name, ".bf"); + csym.n_value = p->st_value; // physical address + csym.n_scnum = CoffTextSectionNo; + csym.n_type = 0; + csym.n_sclass = C_FCN; + csym.n_numaux = 1; + fwrite(&csym, 18, 1, f); + + // now put aux info + + auxbf.regmask = 0; + auxbf.lineno = 0; + auxbf.nentries = FuncEntries[k]; + auxbf.localframe = 0; + auxbf.nextentry = n + 6; + auxbf.dummy = 0; + fwrite(&auxbf, 18, 1, f); + + // put a .ef + + strcpy(csym._n._n_name, ".ef"); + csym.n_value = EndAddress[k]; // physical address + csym.n_scnum = CoffTextSectionNo; + csym.n_type = 0; + csym.n_sclass = C_FCN; + csym.n_numaux = 1; + fwrite(&csym, 18, 1, f); + + // now put aux info + + auxef.dummy = 0; + auxef.lineno = LastLineNo[k]; + auxef.dummy1 = 0; + auxef.dummy2 = 0; + auxef.dummy3 = 0; + auxef.dummy4 = 0; + fwrite(&auxef, 18, 1, f); + + n += 6; + + } else { + // try an put some type info + + if ((p->st_other & VT_BTYPE) == VT_DOUBLE) { + csym.n_type = T_DOUBLE; // int + csym.n_sclass = C_EXT; + } else if ((p->st_other & VT_BTYPE) == VT_FLOAT) { + csym.n_type = T_FLOAT; + csym.n_sclass = C_EXT; + } else if ((p->st_other & VT_BTYPE) == VT_INT) { + csym.n_type = T_INT; // int + csym.n_sclass = C_EXT; + } else if ((p->st_other & VT_BTYPE) == VT_SHORT) { + csym.n_type = T_SHORT; + csym.n_sclass = C_EXT; + } else if ((p->st_other & VT_BTYPE) == VT_BYTE) { + csym.n_type = T_CHAR; + csym.n_sclass = C_EXT; + } else { + csym.n_type = T_INT; // just mark as a label + csym.n_sclass = C_LABEL; + } + + + csym.n_value = p->st_value; + csym.n_scnum = 2; + csym.n_numaux = 1; + fwrite(&csym, 18, 1, f); + + auxfunc.tag = 0; + auxfunc.size = 0x20; + auxfunc.fileptr = 0; + auxfunc.nextsym = 0; + auxfunc.dummy = 0; + fwrite(&auxfunc, 18, 1, f); + n++; + n++; + + } + + p++; + } + } + + if (s1->do_debug) { + // write string table + + // first write the size + i = pCoff_str_table - Coff_str_table; + fwrite(&i, 4, 1, f); + + // then write the strings + fwrite(Coff_str_table, i, 1, f); + + tcc_free(Coff_str_table); + } + + return 0; +} + + + +// group the symbols in order of filename, func1, func2, etc +// finally global symbols + +void SortSymbolTable(void) +{ + int i, j, k, n = 0; + Elf32_Sym *p, *p2, *NewTable; + char *name, *name2; + + NewTable = (Elf32_Sym *) tcc_malloc(nb_syms * sizeof(Elf32_Sym)); + + p = (Elf32_Sym *) symtab_section->data; + + + // find a file symbol, copy it over + // then scan the whole symbol list and copy any function + // symbols that match the file association + + for (i = 0; i < nb_syms; i++) { + if (p->st_info == 4) { + name = (char *) symtab_section->link->data + p->st_name; + + // this is a file symbol, copy it over + + NewTable[n++] = *p; + + p2 = (Elf32_Sym *) symtab_section->data; + + for (j = 0; j < nb_syms; j++) { + if (p2->st_info == 0x12) { + // this is a func symbol + + name2 = + (char *) symtab_section->link->data + p2->st_name; + + // find the function data index + + for (k = 0; k < nFuncs; k++) { + if (strcmp(name2, Func[k]) == 0) + break; + } + + if (k >= nFuncs) { + tcc_error("debug (sort) info can't find function: %s", name2); + } + + if (strcmp(AssociatedFile[k], name) == 0) { + // yes they match copy it over + + NewTable[n++] = *p2; + } + } + p2++; + } + } + p++; + } + + // now all the filename and func symbols should have been copied over + // copy all the rest over (all except file and funcs) + + p = (Elf32_Sym *) symtab_section->data; + for (i = 0; i < nb_syms; i++) { + if (p->st_info != 4 && p->st_info != 0x12) { + NewTable[n++] = *p; + } + p++; + } + + if (n != nb_syms) + tcc_error("Internal Compiler error, debug info"); + + // copy it all back + + p = (Elf32_Sym *) symtab_section->data; + for (i = 0; i < nb_syms; i++) { + *p++ = NewTable[i]; + } + + tcc_free(NewTable); +} + + +int FindCoffSymbolIndex(const char *func_name) +{ + int i, n = 0; + Elf32_Sym *p; + char *name; + + p = (Elf32_Sym *) symtab_section->data; + + for (i = 0; i < nb_syms; i++) { + + name = (char *) symtab_section->link->data + p->st_name; + + if (p->st_info == 4) { + // put a filename symbol + n++; + } else if (p->st_info == 0x12) { + + if (strcmp(func_name, name) == 0) + return n; + + n += 6; + + // put a Function Name + + // now put aux info + + // put a .bf + + // now put aux info + + // put a .ef + + // now put aux info + + } else { + n += 2; + } + + p++; + } + + return n; // total number of symbols +} + +int OutputTheSection(Section * sect) +{ + const char *s = sect->name; + + if (!strcmp(s, ".text")) + return 1; + else if (!strcmp(s, ".data")) + return 1; + else + return 0; +} + +short int GetCoffFlags(const char *s) +{ + if (!strcmp(s, ".text")) + return STYP_TEXT | STYP_DATA | STYP_ALIGN | 0x400; + else if (!strcmp(s, ".data")) + return STYP_DATA; + else if (!strcmp(s, ".bss")) + return STYP_BSS; + else if (!strcmp(s, ".stack")) + return STYP_BSS | STYP_ALIGN | 0x200; + else if (!strcmp(s, ".cinit")) + return STYP_COPY | STYP_DATA | STYP_ALIGN | 0x200; + else + return 0; +} + +Section *FindSection(TCCState * s1, const char *sname) +{ + Section *s; + int i; + + for (i = 1; i < s1->nb_sections; i++) { + s = s1->sections[i]; + + if (!strcmp(sname, s->name)) + return s; + } + + tcc_error("could not find section %s", sname); + return 0; +} + +ST_FUNC int tcc_load_coff(TCCState * s1, int fd) +{ +// tktk TokenSym *ts; + + FILE *f; + unsigned int str_size; + char *Coff_str_table, *name; + int i, k; + struct syment csym; + char name2[9]; + FILHDR file_hdr; /* FILE HEADER STRUCTURE */ + + f = fdopen(fd, "rb"); + if (!f) { + tcc_error("Unable to open .out file for input"); + } + + if (fread(&file_hdr, FILHSZ, 1, f) != 1) + tcc_error("error reading .out file for input"); + + if (fread(&o_filehdr, sizeof(o_filehdr), 1, f) != 1) + tcc_error("error reading .out file for input"); + + // first read the string table + + if (fseek(f, file_hdr.f_symptr + file_hdr.f_nsyms * SYMESZ, SEEK_SET)) + tcc_error("error reading .out file for input"); + + if (fread(&str_size, sizeof(int), 1, f) != 1) + tcc_error("error reading .out file for input"); + + + Coff_str_table = (char *) tcc_malloc(str_size); + + if (fread(Coff_str_table, str_size - 4, 1, f) != 1) + tcc_error("error reading .out file for input"); + + // read/process all the symbols + + // seek back to symbols + + if (fseek(f, file_hdr.f_symptr, SEEK_SET)) + tcc_error("error reading .out file for input"); + + for (i = 0; i < file_hdr.f_nsyms; i++) { + if (fread(&csym, SYMESZ, 1, f) != 1) + tcc_error("error reading .out file for input"); + + if (csym._n._n_n._n_zeroes == 0) { + name = Coff_str_table + csym._n._n_n._n_offset - 4; + } else { + name = csym._n._n_name; + + if (name[7] != 0) { + for (k = 0; k < 8; k++) + name2[k] = name[k]; + + name2[8] = 0; + + name = name2; + } + } +// if (strcmp("_DAC_Buffer",name)==0) // tktk +// name[0]=0; + + if (((csym.n_type & 0x30) == 0x20 && csym.n_sclass == 0x2) || ((csym.n_type & 0x30) == 0x30 && csym.n_sclass == 0x2) || (csym.n_type == 0x4 && csym.n_sclass == 0x2) || (csym.n_type == 0x8 && csym.n_sclass == 0x2) || // structures + (csym.n_type == 0x18 && csym.n_sclass == 0x2) || // pointer to structure + (csym.n_type == 0x7 && csym.n_sclass == 0x2) || // doubles + (csym.n_type == 0x6 && csym.n_sclass == 0x2)) // floats + { + // strip off any leading underscore (except for other main routine) + + if (name[0] == '_' && strcmp(name, "_main") != 0) + name++; + + tcc_add_symbol(s1, name, (void*)(uintptr_t)csym.n_value); + } + // skip any aux records + + if (csym.n_numaux == 1) { + if (fread(&csym, SYMESZ, 1, f) != 1) + tcc_error("error reading .out file for input"); + i++; + } + } + + return 0; +} diff --git a/tinyc/tccelf.c b/tinyc/tccelf.c new file mode 100644 index 000000000..22ce5df9c --- /dev/null +++ b/tinyc/tccelf.c @@ -0,0 +1,2994 @@ +/* + * ELF file handling for TCC + * + * Copyright (c) 2001-2004 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "tcc.h" + +/* Define this to get some debug output during relocation processing. */ +#undef DEBUG_RELOC + +/********************************************************/ +/* global variables */ + +ST_DATA Section *text_section, *data_section, *bss_section; /* predefined sections */ +ST_DATA Section *common_section; +ST_DATA Section *cur_text_section; /* current section where function code is generated */ +#ifdef CONFIG_TCC_ASM +ST_DATA Section *last_text_section; /* to handle .previous asm directive */ +#endif +#ifdef CONFIG_TCC_BCHECK +/* bound check related sections */ +ST_DATA Section *bounds_section; /* contains global data bound description */ +ST_DATA Section *lbounds_section; /* contains local data bound description */ +#endif +/* symbol sections */ +ST_DATA Section *symtab_section, *strtab_section; +/* debug sections */ +ST_DATA Section *stab_section, *stabstr_section; + +/* XXX: avoid static variable */ +static int new_undef_sym = 0; /* Is there a new undefined sym since last new_undef_sym() */ + +/* ------------------------------------------------------------------------- */ + +ST_FUNC void tccelf_new(TCCState *s) +{ + /* no section zero */ + dynarray_add(&s->sections, &s->nb_sections, NULL); + + /* create standard sections */ + text_section = new_section(s, ".text", SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR); + data_section = new_section(s, ".data", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE); + bss_section = new_section(s, ".bss", SHT_NOBITS, SHF_ALLOC | SHF_WRITE); + common_section = new_section(s, ".common", SHT_NOBITS, SHF_PRIVATE); + common_section->sh_num = SHN_COMMON; + + /* symbols are always generated for linking stage */ + symtab_section = new_symtab(s, ".symtab", SHT_SYMTAB, 0, + ".strtab", + ".hashtab", SHF_PRIVATE); + strtab_section = symtab_section->link; + s->symtab = symtab_section; + + /* private symbol table for dynamic symbols */ + s->dynsymtab_section = new_symtab(s, ".dynsymtab", SHT_SYMTAB, SHF_PRIVATE, + ".dynstrtab", + ".dynhashtab", SHF_PRIVATE); + get_sym_attr(s, 0, 1); +} + +#ifdef CONFIG_TCC_BCHECK +ST_FUNC void tccelf_bounds_new(TCCState *s) +{ + /* create bounds sections */ + bounds_section = new_section(s, ".bounds", + SHT_PROGBITS, SHF_ALLOC); + lbounds_section = new_section(s, ".lbounds", + SHT_PROGBITS, SHF_ALLOC); +} +#endif + +ST_FUNC void tccelf_stab_new(TCCState *s) +{ + stab_section = new_section(s, ".stab", SHT_PROGBITS, 0); + stab_section->sh_entsize = sizeof(Stab_Sym); + stabstr_section = new_section(s, ".stabstr", SHT_STRTAB, 0); + put_elf_str(stabstr_section, ""); + stab_section->link = stabstr_section; + /* put first entry */ + put_stabs("", 0, 0, 0, 0); +} + +static void free_section(Section *s) +{ + tcc_free(s->data); +} + +ST_FUNC void tccelf_delete(TCCState *s1) +{ + int i; + + /* free all sections */ + for(i = 1; i < s1->nb_sections; i++) + free_section(s1->sections[i]); + dynarray_reset(&s1->sections, &s1->nb_sections); + + for(i = 0; i < s1->nb_priv_sections; i++) + free_section(s1->priv_sections[i]); + dynarray_reset(&s1->priv_sections, &s1->nb_priv_sections); + + /* free any loaded DLLs */ +#ifdef TCC_IS_NATIVE + for ( i = 0; i < s1->nb_loaded_dlls; i++) { + DLLReference *ref = s1->loaded_dlls[i]; + if ( ref->handle ) +# ifdef _WIN32 + FreeLibrary((HMODULE)ref->handle); +# else + dlclose(ref->handle); +# endif + } +#endif + /* free loaded dlls array */ + dynarray_reset(&s1->loaded_dlls, &s1->nb_loaded_dlls); + tcc_free(s1->sym_attrs); +} + +ST_FUNC Section *new_section(TCCState *s1, const char *name, int sh_type, int sh_flags) +{ + Section *sec; + + sec = tcc_mallocz(sizeof(Section) + strlen(name)); + strcpy(sec->name, name); + sec->sh_type = sh_type; + sec->sh_flags = sh_flags; + switch(sh_type) { + case SHT_HASH: + case SHT_REL: + case SHT_RELA: + case SHT_DYNSYM: + case SHT_SYMTAB: + case SHT_DYNAMIC: + sec->sh_addralign = 4; + break; + case SHT_STRTAB: + sec->sh_addralign = 1; + break; + default: + sec->sh_addralign = PTR_SIZE; /* gcc/pcc default alignment */ + break; + } + + if (sh_flags & SHF_PRIVATE) { + dynarray_add(&s1->priv_sections, &s1->nb_priv_sections, sec); + } else { + sec->sh_num = s1->nb_sections; + dynarray_add(&s1->sections, &s1->nb_sections, sec); + } + + return sec; +} + +ST_FUNC Section *new_symtab(TCCState *s1, + const char *symtab_name, int sh_type, int sh_flags, + const char *strtab_name, + const char *hash_name, int hash_sh_flags) +{ + Section *symtab, *strtab, *hash; + int *ptr, nb_buckets; + + symtab = new_section(s1, symtab_name, sh_type, sh_flags); + symtab->sh_entsize = sizeof(ElfW(Sym)); + strtab = new_section(s1, strtab_name, SHT_STRTAB, sh_flags); + put_elf_str(strtab, ""); + symtab->link = strtab; + put_elf_sym(symtab, 0, 0, 0, 0, 0, NULL); + + nb_buckets = 1; + + hash = new_section(s1, hash_name, SHT_HASH, hash_sh_flags); + hash->sh_entsize = sizeof(int); + symtab->hash = hash; + hash->link = symtab; + + ptr = section_ptr_add(hash, (2 + nb_buckets + 1) * sizeof(int)); + ptr[0] = nb_buckets; + ptr[1] = 1; + memset(ptr + 2, 0, (nb_buckets + 1) * sizeof(int)); + return symtab; +} + +/* realloc section and set its content to zero */ +ST_FUNC void section_realloc(Section *sec, unsigned long new_size) +{ + unsigned long size; + unsigned char *data; + + size = sec->data_allocated; + if (size == 0) + size = 1; + while (size < new_size) + size = size * 2; + data = tcc_realloc(sec->data, size); + memset(data + sec->data_allocated, 0, size - sec->data_allocated); + sec->data = data; + sec->data_allocated = size; +} + +/* reserve at least 'size' bytes aligned per 'align' in section + 'sec' from current offset, and return the aligned offset */ +ST_FUNC size_t section_add(Section *sec, addr_t size, int align) +{ + size_t offset, offset1; + + offset = (sec->data_offset + align - 1) & -align; + offset1 = offset + size; + if (sec->sh_type != SHT_NOBITS && offset1 > sec->data_allocated) + section_realloc(sec, offset1); + sec->data_offset = offset1; + if (align > sec->sh_addralign) + sec->sh_addralign = align; + return offset; +} + +/* reserve at least 'size' bytes in section 'sec' from + sec->data_offset. */ +ST_FUNC void *section_ptr_add(Section *sec, addr_t size) +{ + size_t offset = section_add(sec, size, 1); + return sec->data + offset; +} + +/* reserve at least 'size' bytes from section start */ +ST_FUNC void section_reserve(Section *sec, unsigned long size) +{ + if (size > sec->data_allocated) + section_realloc(sec, size); + if (size > sec->data_offset) + sec->data_offset = size; +} + +/* return a reference to a section, and create it if it does not + exists */ +ST_FUNC Section *find_section(TCCState *s1, const char *name) +{ + Section *sec; + int i; + for(i = 1; i < s1->nb_sections; i++) { + sec = s1->sections[i]; + if (!strcmp(name, sec->name)) + return sec; + } + /* sections are created as PROGBITS */ + return new_section(s1, name, SHT_PROGBITS, SHF_ALLOC); +} + +/* ------------------------------------------------------------------------- */ + +ST_FUNC int put_elf_str(Section *s, const char *sym) +{ + int offset, len; + char *ptr; + + len = strlen(sym) + 1; + offset = s->data_offset; + ptr = section_ptr_add(s, len); + memcpy(ptr, sym, len); + return offset; +} + +/* elf symbol hashing function */ +static unsigned long elf_hash(const unsigned char *name) +{ + unsigned long h = 0, g; + + while (*name) { + h = (h << 4) + *name++; + g = h & 0xf0000000; + if (g) + h ^= g >> 24; + h &= ~g; + } + return h; +} + +/* rebuild hash table of section s */ +/* NOTE: we do factorize the hash table code to go faster */ +static void rebuild_hash(Section *s, unsigned int nb_buckets) +{ + ElfW(Sym) *sym; + int *ptr, *hash, nb_syms, sym_index, h; + unsigned char *strtab; + + strtab = s->link->data; + nb_syms = s->data_offset / sizeof(ElfW(Sym)); + + s->hash->data_offset = 0; + ptr = section_ptr_add(s->hash, (2 + nb_buckets + nb_syms) * sizeof(int)); + ptr[0] = nb_buckets; + ptr[1] = nb_syms; + ptr += 2; + hash = ptr; + memset(hash, 0, (nb_buckets + 1) * sizeof(int)); + ptr += nb_buckets + 1; + + sym = (ElfW(Sym) *)s->data + 1; + for(sym_index = 1; sym_index < nb_syms; sym_index++) { + if (ELFW(ST_BIND)(sym->st_info) != STB_LOCAL) { + h = elf_hash(strtab + sym->st_name) % nb_buckets; + *ptr = hash[h]; + hash[h] = sym_index; + } else { + *ptr = 0; + } + ptr++; + sym++; + } +} + +/* return the symbol number */ +ST_FUNC int put_elf_sym(Section *s, addr_t value, unsigned long size, + int info, int other, int shndx, const char *name) +{ + int name_offset, sym_index; + int nbuckets, h; + ElfW(Sym) *sym; + Section *hs; + + sym = section_ptr_add(s, sizeof(ElfW(Sym))); + if (name) + name_offset = put_elf_str(s->link, name); + else + name_offset = 0; + /* XXX: endianness */ + sym->st_name = name_offset; + sym->st_value = value; + sym->st_size = size; + sym->st_info = info; + sym->st_other = other; + sym->st_shndx = shndx; + sym_index = sym - (ElfW(Sym) *)s->data; + hs = s->hash; + if (hs) { + int *ptr, *base; + ptr = section_ptr_add(hs, sizeof(int)); + base = (int *)hs->data; + /* only add global or weak symbols */ + if (ELFW(ST_BIND)(info) != STB_LOCAL) { + /* add another hashing entry */ + nbuckets = base[0]; + h = elf_hash((unsigned char *) name) % nbuckets; + *ptr = base[2 + h]; + base[2 + h] = sym_index; + base[1]++; + /* we resize the hash table */ + hs->nb_hashed_syms++; + if (hs->nb_hashed_syms > 2 * nbuckets) { + rebuild_hash(s, 2 * nbuckets); + } + } else { + *ptr = 0; + base[1]++; + } + } + return sym_index; +} + +/* find global ELF symbol 'name' and return its index. Return 0 if not + found. */ +ST_FUNC int find_elf_sym(Section *s, const char *name) +{ + ElfW(Sym) *sym; + Section *hs; + int nbuckets, sym_index, h; + const char *name1; + + hs = s->hash; + if (!hs) + return 0; + nbuckets = ((int *)hs->data)[0]; + h = elf_hash((unsigned char *) name) % nbuckets; + sym_index = ((int *)hs->data)[2 + h]; + while (sym_index != 0) { + sym = &((ElfW(Sym) *)s->data)[sym_index]; + name1 = (char *) s->link->data + sym->st_name; + if (!strcmp(name, name1)) + return sym_index; + sym_index = ((int *)hs->data)[2 + nbuckets + sym_index]; + } + return 0; +} + +/* return elf symbol value, signal error if 'err' is nonzero */ +ST_FUNC addr_t get_elf_sym_addr(TCCState *s, const char *name, int err) +{ + int sym_index; + ElfW(Sym) *sym; + + sym_index = find_elf_sym(s->symtab, name); + sym = &((ElfW(Sym) *)s->symtab->data)[sym_index]; + if (!sym_index || sym->st_shndx == SHN_UNDEF) { + if (err) + tcc_error("%s not defined", name); + return 0; + } + return sym->st_value; +} + +/* return elf symbol value */ +LIBTCCAPI void *tcc_get_symbol(TCCState *s, const char *name) +{ + return (void*)(uintptr_t)get_elf_sym_addr(s, name, 0); +} + +#if defined TCC_IS_NATIVE || defined TCC_TARGET_PE +/* return elf symbol value or error */ +ST_FUNC void* tcc_get_symbol_err(TCCState *s, const char *name) +{ + return (void*)(uintptr_t)get_elf_sym_addr(s, name, 1); +} +#endif + +/* add an elf symbol : check if it is already defined and patch + it. Return symbol index. NOTE that sh_num can be SHN_UNDEF. */ +ST_FUNC int set_elf_sym(Section *s, addr_t value, unsigned long size, + int info, int other, int shndx, const char *name) +{ + ElfW(Sym) *esym; + int sym_bind, sym_index, sym_type, esym_bind; + unsigned char sym_vis, esym_vis, new_vis; + + sym_bind = ELFW(ST_BIND)(info); + sym_type = ELFW(ST_TYPE)(info); + sym_vis = ELFW(ST_VISIBILITY)(other); + + sym_index = find_elf_sym(s, name); + esym = &((ElfW(Sym) *)s->data)[sym_index]; + if (sym_index && esym->st_value == value && esym->st_size == size + && esym->st_info == info && esym->st_other == other + && esym->st_shndx == shndx) + return sym_index; + + if (sym_bind != STB_LOCAL) { + /* we search global or weak symbols */ + if (!sym_index) + goto do_def; + if (esym->st_shndx != SHN_UNDEF) { + esym_bind = ELFW(ST_BIND)(esym->st_info); + /* propagate the most constraining visibility */ + /* STV_DEFAULT(0)st_other); + if (esym_vis == STV_DEFAULT) { + new_vis = sym_vis; + } else if (sym_vis == STV_DEFAULT) { + new_vis = esym_vis; + } else { + new_vis = (esym_vis < sym_vis) ? esym_vis : sym_vis; + } + esym->st_other = (esym->st_other & ~ELFW(ST_VISIBILITY)(-1)) + | new_vis; + other = esym->st_other; /* in case we have to patch esym */ + if (shndx == SHN_UNDEF) { + /* ignore adding of undefined symbol if the + corresponding symbol is already defined */ + } else if (sym_bind == STB_GLOBAL && esym_bind == STB_WEAK) { + /* global overrides weak, so patch */ + goto do_patch; + } else if (sym_bind == STB_WEAK && esym_bind == STB_GLOBAL) { + /* weak is ignored if already global */ + } else if (sym_bind == STB_WEAK && esym_bind == STB_WEAK) { + /* keep first-found weak definition, ignore subsequents */ + } else if (sym_vis == STV_HIDDEN || sym_vis == STV_INTERNAL) { + /* ignore hidden symbols after */ + } else if ((esym->st_shndx == SHN_COMMON + || esym->st_shndx == bss_section->sh_num) + && (shndx < SHN_LORESERVE + && shndx != bss_section->sh_num)) { + /* data symbol gets precedence over common/bss */ + goto do_patch; + } else if (shndx == SHN_COMMON || shndx == bss_section->sh_num) { + /* data symbol keeps precedence over common/bss */ + } else if (s == tcc_state->dynsymtab_section) { + /* we accept that two DLL define the same symbol */ + } else { +#if 0 + printf("new_bind=%x new_shndx=%x new_vis=%x old_bind=%x old_shndx=%x old_vis=%x\n", + sym_bind, shndx, new_vis, esym_bind, esym->st_shndx, esym_vis); +#endif + tcc_error_noabort("'%s' defined twice", name); + } + } else { + do_patch: + esym->st_info = ELFW(ST_INFO)(sym_bind, sym_type); + esym->st_shndx = shndx; + new_undef_sym = 1; + esym->st_value = value; + esym->st_size = size; + esym->st_other = other; + } + } else { + do_def: + sym_index = put_elf_sym(s, value, size, + ELFW(ST_INFO)(sym_bind, sym_type), other, + shndx, name); + } + return sym_index; +} + +/* put relocation */ +ST_FUNC void put_elf_reloca(Section *symtab, Section *s, unsigned long offset, + int type, int symbol, addr_t addend) +{ + char buf[256]; + Section *sr; + ElfW_Rel *rel; + + sr = s->reloc; + if (!sr) { + /* if no relocation section, create it */ + snprintf(buf, sizeof(buf), REL_SECTION_FMT, s->name); + /* if the symtab is allocated, then we consider the relocation + are also */ + sr = new_section(tcc_state, buf, SHT_RELX, symtab->sh_flags); + sr->sh_entsize = sizeof(ElfW_Rel); + sr->link = symtab; + sr->sh_info = s->sh_num; + s->reloc = sr; + } + rel = section_ptr_add(sr, sizeof(ElfW_Rel)); + rel->r_offset = offset; + rel->r_info = ELFW(R_INFO)(symbol, type); +#if SHT_RELX == SHT_RELA + rel->r_addend = addend; +#else + if (addend) + tcc_error("non-zero addend on REL architecture"); +#endif +} + +ST_FUNC void put_elf_reloc(Section *symtab, Section *s, unsigned long offset, + int type, int symbol) +{ + put_elf_reloca(symtab, s, offset, type, symbol, 0); +} + +/* Remove relocations for section S->reloc starting at oldrelocoffset + that are to the same place, retaining the last of them. As side effect + the relocations are sorted. Possibly reduces the number of relocs. */ +ST_FUNC void squeeze_multi_relocs(Section *s, size_t oldrelocoffset) +{ + Section *sr = s->reloc; + ElfW_Rel *r, *dest; + ssize_t a; + ElfW(Addr) addr; + + if (oldrelocoffset + sizeof(*r) >= sr->data_offset) + return; + /* The relocs we're dealing with are the result of initializer parsing. + So they will be mostly in order and there aren't many of them. + Secondly we need a stable sort (which qsort isn't). We use + a simple insertion sort. */ + for (a = oldrelocoffset + sizeof(*r); a < sr->data_offset; a += sizeof(*r)) { + ssize_t i = a - sizeof(*r); + addr = ((ElfW_Rel*)(sr->data + a))->r_offset; + for (; i >= (ssize_t)oldrelocoffset && + ((ElfW_Rel*)(sr->data + i))->r_offset > addr; i -= sizeof(*r)) { + ElfW_Rel tmp = *(ElfW_Rel*)(sr->data + a); + *(ElfW_Rel*)(sr->data + a) = *(ElfW_Rel*)(sr->data + i); + *(ElfW_Rel*)(sr->data + i) = tmp; + } + } + + r = (ElfW_Rel*)(sr->data + oldrelocoffset); + dest = r; + for (; r < (ElfW_Rel*)(sr->data + sr->data_offset); r++) { + if (dest->r_offset != r->r_offset) + dest++; + *dest = *r; + } + sr->data_offset = (unsigned char*)dest - sr->data + sizeof(*r); +} + +/* put stab debug information */ + +ST_FUNC void put_stabs(const char *str, int type, int other, int desc, + unsigned long value) +{ + Stab_Sym *sym; + + sym = section_ptr_add(stab_section, sizeof(Stab_Sym)); + if (str) { + sym->n_strx = put_elf_str(stabstr_section, str); + } else { + sym->n_strx = 0; + } + sym->n_type = type; + sym->n_other = other; + sym->n_desc = desc; + sym->n_value = value; +} + +ST_FUNC void put_stabs_r(const char *str, int type, int other, int desc, + unsigned long value, Section *sec, int sym_index) +{ + put_stabs(str, type, other, desc, value); + put_elf_reloc(symtab_section, stab_section, + stab_section->data_offset - sizeof(unsigned int), + R_DATA_32, sym_index); +} + +ST_FUNC void put_stabn(int type, int other, int desc, int value) +{ + put_stabs(NULL, type, other, desc, value); +} + +ST_FUNC void put_stabd(int type, int other, int desc) +{ + put_stabs(NULL, type, other, desc, 0); +} + +ST_FUNC struct sym_attr *get_sym_attr(TCCState *s1, int index, int alloc) +{ + int n; + struct sym_attr *tab; + + if (index >= s1->nb_sym_attrs) { + if (!alloc) + return s1->sym_attrs; + /* find immediately bigger power of 2 and reallocate array */ + n = 1; + while (index >= n) + n *= 2; + tab = tcc_realloc(s1->sym_attrs, n * sizeof(*s1->sym_attrs)); + s1->sym_attrs = tab; + memset(s1->sym_attrs + s1->nb_sym_attrs, 0, + (n - s1->nb_sym_attrs) * sizeof(*s1->sym_attrs)); + s1->nb_sym_attrs = n; + } + return &s1->sym_attrs[index]; +} + +/* Browse each elem of type in section starting at elem + using variable */ +#define for_each_elem(sec, startoff, elem, type) \ + for (elem = (type *) sec->data + startoff; \ + elem < (type *) (sec->data + sec->data_offset); elem++) + +/* In an ELF file symbol table, the local symbols must appear below + the global and weak ones. Since TCC cannot sort it while generating + the code, we must do it after. All the relocation tables are also + modified to take into account the symbol table sorting */ +static void sort_syms(TCCState *s1, Section *s) +{ + int *old_to_new_syms; + ElfW(Sym) *new_syms; + int nb_syms, i; + ElfW(Sym) *p, *q; + ElfW_Rel *rel; + Section *sr; + int type, sym_index; + + nb_syms = s->data_offset / sizeof(ElfW(Sym)); + new_syms = tcc_malloc(nb_syms * sizeof(ElfW(Sym))); + old_to_new_syms = tcc_malloc(nb_syms * sizeof(int)); + + /* first pass for local symbols */ + p = (ElfW(Sym) *)s->data; + q = new_syms; + for(i = 0; i < nb_syms; i++) { + if (ELFW(ST_BIND)(p->st_info) == STB_LOCAL) { + old_to_new_syms[i] = q - new_syms; + *q++ = *p; + } + p++; + } + /* save the number of local symbols in section header */ + if( s->sh_size ) /* this 'if' makes IDA happy */ + s->sh_info = q - new_syms; + + /* then second pass for non local symbols */ + p = (ElfW(Sym) *)s->data; + for(i = 0; i < nb_syms; i++) { + if (ELFW(ST_BIND)(p->st_info) != STB_LOCAL) { + old_to_new_syms[i] = q - new_syms; + *q++ = *p; + } + p++; + } + + /* we copy the new symbols to the old */ + memcpy(s->data, new_syms, nb_syms * sizeof(ElfW(Sym))); + tcc_free(new_syms); + + /* now we modify all the relocations */ + for(i = 1; i < s1->nb_sections; i++) { + sr = s1->sections[i]; + if (sr->sh_type == SHT_RELX && sr->link == s) { + for_each_elem(sr, 0, rel, ElfW_Rel) { + sym_index = ELFW(R_SYM)(rel->r_info); + type = ELFW(R_TYPE)(rel->r_info); + sym_index = old_to_new_syms[sym_index]; + rel->r_info = ELFW(R_INFO)(sym_index, type); + } + } + } + + tcc_free(old_to_new_syms); +} + +/* relocate common symbols in the .bss section */ +ST_FUNC void relocate_common_syms(void) +{ + ElfW(Sym) *sym; + + for_each_elem(symtab_section, 1, sym, ElfW(Sym)) { + if (sym->st_shndx == SHN_COMMON) { + /* symbol alignment is in st_value for SHN_COMMONs */ + sym->st_value = section_add(bss_section, sym->st_size, + sym->st_value); + sym->st_shndx = bss_section->sh_num; + } + } +} + +/* relocate symbol table, resolve undefined symbols if do_resolve is + true and output error if undefined symbol. */ +ST_FUNC void relocate_syms(TCCState *s1, Section *symtab, int do_resolve) +{ + ElfW(Sym) *sym; + int sym_bind, sh_num; + const char *name; + + for_each_elem(symtab, 1, sym, ElfW(Sym)) { + sh_num = sym->st_shndx; + if (sh_num == SHN_UNDEF) { + name = (char *) strtab_section->data + sym->st_name; + /* Use ld.so to resolve symbol for us (for tcc -run) */ + if (do_resolve) { +#if defined TCC_IS_NATIVE && !defined TCC_TARGET_PE + void *addr = dlsym(RTLD_DEFAULT, name); + if (addr) { + sym->st_value = (addr_t) addr; +#ifdef DEBUG_RELOC + printf ("relocate_sym: %s -> 0x%lx\n", name, sym->st_value); +#endif + goto found; + } +#endif + /* if dynamic symbol exist, it will be used in relocate_section */ + } else if (s1->dynsym && find_elf_sym(s1->dynsym, name)) + goto found; + /* XXX: _fp_hw seems to be part of the ABI, so we ignore + it */ + if (!strcmp(name, "_fp_hw")) + goto found; + /* only weak symbols are accepted to be undefined. Their + value is zero */ + sym_bind = ELFW(ST_BIND)(sym->st_info); + if (sym_bind == STB_WEAK) + sym->st_value = 0; + else + tcc_error_noabort("undefined symbol '%s'", name); + } else if (sh_num < SHN_LORESERVE) { + /* add section base */ + sym->st_value += s1->sections[sym->st_shndx]->sh_addr; + } + found: ; + } +} + +/* relocate a given section (CPU dependent) by applying the relocations + in the associated relocation section */ +ST_FUNC void relocate_section(TCCState *s1, Section *s) +{ + Section *sr = s->reloc; + ElfW_Rel *rel; + ElfW(Sym) *sym; + int type, sym_index; + unsigned char *ptr; + addr_t tgt, addr; + + relocate_init(sr); + + for_each_elem(sr, 0, rel, ElfW_Rel) { + ptr = s->data + rel->r_offset; + sym_index = ELFW(R_SYM)(rel->r_info); + sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; + type = ELFW(R_TYPE)(rel->r_info); + tgt = sym->st_value; +#if SHT_RELX == SHT_RELA + tgt += rel->r_addend; +#endif + addr = s->sh_addr + rel->r_offset; + relocate(s1, rel, type, ptr, addr, tgt); + } + /* if the relocation is allocated, we change its symbol table */ + if (sr->sh_flags & SHF_ALLOC) + sr->link = s1->dynsym; +} + +/* relocate relocation table in 'sr' */ +static void relocate_rel(TCCState *s1, Section *sr) +{ + Section *s; + ElfW_Rel *rel; + + s = s1->sections[sr->sh_info]; + for_each_elem(sr, 0, rel, ElfW_Rel) + rel->r_offset += s->sh_addr; +} + +/* count the number of dynamic relocations so that we can reserve + their space */ +static int prepare_dynamic_rel(TCCState *s1, Section *sr) +{ + ElfW_Rel *rel; + int sym_index, type, count; + + count = 0; + for_each_elem(sr, 0, rel, ElfW_Rel) { + sym_index = ELFW(R_SYM)(rel->r_info); + type = ELFW(R_TYPE)(rel->r_info); + switch(type) { +#if defined(TCC_TARGET_I386) + case R_386_32: + if (!get_sym_attr(s1, sym_index, 0)->dyn_index + && ((ElfW(Sym)*)symtab_section->data + sym_index)->st_shndx == SHN_UNDEF) { + /* don't fixup unresolved (weak) symbols */ + rel->r_info = ELFW(R_INFO)(sym_index, R_386_RELATIVE); + break; + } +#elif defined(TCC_TARGET_X86_64) + case R_X86_64_32: + case R_X86_64_32S: + case R_X86_64_64: +#endif + count++; + break; +#if defined(TCC_TARGET_I386) + case R_386_PC32: +#elif defined(TCC_TARGET_X86_64) + case R_X86_64_PC32: +#endif + if (get_sym_attr(s1, sym_index, 0)->dyn_index) + count++; + break; + default: + break; + } + } + if (count) { + /* allocate the section */ + sr->sh_flags |= SHF_ALLOC; + sr->sh_size = count * sizeof(ElfW_Rel); + } + return count; +} + +static void build_got(TCCState *s1) +{ + /* if no got, then create it */ + s1->got = new_section(s1, ".got", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE); + s1->got->sh_entsize = 4; + set_elf_sym(symtab_section, 0, 4, ELFW(ST_INFO)(STB_GLOBAL, STT_OBJECT), + 0, s1->got->sh_num, "_GLOBAL_OFFSET_TABLE_"); + /* keep space for _DYNAMIC pointer and two dummy got entries */ + section_ptr_add(s1->got, 3 * PTR_SIZE); +} + +/* Create a GOT and (for function call) a PLT entry corresponding to a symbol + in s1->symtab. When creating the dynamic symbol table entry for the GOT + relocation, use 'size' and 'info' for the corresponding symbol metadata. + Returns the offset of the GOT or (if any) PLT entry. */ +static struct sym_attr * put_got_entry(TCCState *s1, int dyn_reloc_type, + unsigned long size, + int info, int sym_index) +{ + int need_plt_entry; + const char *name; + ElfW(Sym) *sym; + struct sym_attr *attr; + unsigned got_offset; + char plt_name[100]; + int len; + + need_plt_entry = (dyn_reloc_type == R_JMP_SLOT); + attr = get_sym_attr(s1, sym_index, 1); + + /* In case a function is both called and its address taken 2 GOT entries + are created, one for taking the address (GOT) and the other for the PLT + entry (PLTGOT). */ + if (need_plt_entry ? attr->plt_offset : attr->got_offset) + return attr; + + /* create the GOT entry */ + got_offset = s1->got->data_offset; + section_ptr_add(s1->got, PTR_SIZE); + + /* Create the GOT relocation that will insert the address of the object or + function of interest in the GOT entry. This is a static relocation for + memory output (dlsym will give us the address of symbols) and dynamic + relocation otherwise (executable and DLLs). The relocation should be + done lazily for GOT entry with *_JUMP_SLOT relocation type (the one + associated to a PLT entry) but is currently done at load time for an + unknown reason. */ + + sym = &((ElfW(Sym) *) symtab_section->data)[sym_index]; + name = (char *) symtab_section->link->data + sym->st_name; + + if (s1->dynsym) { + if (ELFW(ST_BIND)(sym->st_info) == STB_LOCAL) { + /* Hack alarm. We don't want to emit dynamic symbols + and symbol based relocs for STB_LOCAL symbols, but rather + want to resolve them directly. At this point the symbol + values aren't final yet, so we must defer this. We will later + have to create a RELATIVE reloc anyway, so we misuse the + relocation slot to smuggle the symbol reference until + fill_local_got_entries. Not that the sym_index is + relative to symtab_section, not s1->dynsym! Nevertheless + we use s1->dyn_sym so that if this is the first call + that got->reloc is correctly created. Also note that + RELATIVE relocs are not normally created for the .got, + so the types serves as a marker for later (and is retained + also for the final output, which is okay because then the + got is just normal data). */ + put_elf_reloc(s1->dynsym, s1->got, got_offset, R_RELATIVE, + sym_index); + } else { + if (0 == attr->dyn_index) + attr->dyn_index = set_elf_sym(s1->dynsym, sym->st_value, size, + info, 0, sym->st_shndx, name); + put_elf_reloc(s1->dynsym, s1->got, got_offset, dyn_reloc_type, + attr->dyn_index); + } + } else { + put_elf_reloc(symtab_section, s1->got, got_offset, dyn_reloc_type, + sym_index); + } + + if (need_plt_entry) { + if (!s1->plt) { + s1->plt = new_section(s1, ".plt", SHT_PROGBITS, + SHF_ALLOC | SHF_EXECINSTR); + s1->plt->sh_entsize = 4; + } + + attr->plt_offset = create_plt_entry(s1, got_offset, attr); + + /* create a symbol 'sym@plt' for the PLT jump vector */ + len = strlen(name); + if (len > sizeof plt_name - 5) + len = sizeof plt_name - 5; + memcpy(plt_name, name, len); + strcpy(plt_name + len, "@plt"); + attr->plt_sym = put_elf_sym(s1->symtab, attr->plt_offset, sym->st_size, + ELFW(ST_INFO)(STB_GLOBAL, STT_FUNC), 0, s1->plt->sh_num, plt_name); + + } else { + attr->got_offset = got_offset; + } + + return attr; +} + +/* build GOT and PLT entries */ +ST_FUNC void build_got_entries(TCCState *s1) +{ + Section *s; + ElfW_Rel *rel; + ElfW(Sym) *sym; + int i, type, gotplt_entry, reloc_type, sym_index; + struct sym_attr *attr; + + for(i = 1; i < s1->nb_sections; i++) { + s = s1->sections[i]; + if (s->sh_type != SHT_RELX) + continue; + /* no need to handle got relocations */ + if (s->link != symtab_section) + continue; + for_each_elem(s, 0, rel, ElfW_Rel) { + type = ELFW(R_TYPE)(rel->r_info); + gotplt_entry = gotplt_entry_type(type); + sym_index = ELFW(R_SYM)(rel->r_info); + sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; + + if (gotplt_entry == NO_GOTPLT_ENTRY) { + continue; + } + + /* Automatically create PLT/GOT [entry] if it is an undefined + reference (resolved at runtime), or the symbol is absolute, + probably created by tcc_add_symbol, and thus on 64-bit + targets might be too far from application code. */ + if (gotplt_entry == AUTO_GOTPLT_ENTRY) { + if (sym->st_shndx == SHN_UNDEF) { + ElfW(Sym) *esym; + int dynindex; + if (s1->output_type == TCC_OUTPUT_DLL && ! PCRELATIVE_DLLPLT) + continue; + /* Relocations for UNDEF symbols would normally need + to be transferred into the executable or shared object. + If that were done AUTO_GOTPLT_ENTRY wouldn't exist. + But TCC doesn't do that (at least for exes), so we + need to resolve all such relocs locally. And that + means PLT slots for functions in DLLs and COPY relocs for + data symbols. COPY relocs were generated in + bind_exe_dynsyms (and the symbol adjusted to be defined), + and for functions we were generated a dynamic symbol + of function type. */ + if (s1->dynsym) { + /* dynsym isn't set for -run :-/ */ + dynindex = get_sym_attr(s1, sym_index, 0)->dyn_index; + esym = (ElfW(Sym) *)s1->dynsym->data + dynindex; + if (dynindex + && (ELFW(ST_TYPE)(esym->st_info) == STT_FUNC + || (ELFW(ST_TYPE)(esym->st_info) == STT_NOTYPE + && ELFW(ST_TYPE)(sym->st_info) == STT_FUNC))) + goto jmp_slot; + } + } else if (!(sym->st_shndx == SHN_ABS +#ifndef TCC_TARGET_ARM + && PTR_SIZE == 8 +#endif + )) + continue; + } + +#ifdef TCC_TARGET_X86_64 + if ((type == R_X86_64_PLT32 || type == R_X86_64_PC32) && + (ELFW(ST_VISIBILITY)(sym->st_other) != STV_DEFAULT || + ELFW(ST_BIND)(sym->st_info) == STB_LOCAL)) { + rel->r_info = ELFW(R_INFO)(sym_index, R_X86_64_PC32); + continue; + } +#endif + if (code_reloc(type)) { + jmp_slot: + reloc_type = R_JMP_SLOT; + } else + reloc_type = R_GLOB_DAT; + + if (!s1->got) + build_got(s1); + + if (gotplt_entry == BUILD_GOT_ONLY) + continue; + + attr = put_got_entry(s1, reloc_type, sym->st_size, sym->st_info, + sym_index); + + if (reloc_type == R_JMP_SLOT) + rel->r_info = ELFW(R_INFO)(attr->plt_sym, type); + } + } +} + +/* put dynamic tag */ +static void put_dt(Section *dynamic, int dt, addr_t val) +{ + ElfW(Dyn) *dyn; + dyn = section_ptr_add(dynamic, sizeof(ElfW(Dyn))); + dyn->d_tag = dt; + dyn->d_un.d_val = val; +} + +#ifndef TCC_TARGET_PE +static void add_init_array_defines(TCCState *s1, const char *section_name) +{ + Section *s; + long end_offset; + char sym_start[1024]; + char sym_end[1024]; + + snprintf(sym_start, sizeof(sym_start), "__%s_start", section_name + 1); + snprintf(sym_end, sizeof(sym_end), "__%s_end", section_name + 1); + + s = find_section(s1, section_name); + if (!s) { + end_offset = 0; + s = data_section; + } else { + end_offset = s->data_offset; + } + + set_elf_sym(symtab_section, + 0, 0, + ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0, + s->sh_num, sym_start); + set_elf_sym(symtab_section, + end_offset, 0, + ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0, + s->sh_num, sym_end); +} +#endif + +static int tcc_add_support(TCCState *s1, const char *filename) +{ + char buf[1024]; + snprintf(buf, sizeof(buf), "%s/%s", s1->tcc_lib_path, filename); + return tcc_add_file(s1, buf); +} + +ST_FUNC void tcc_add_bcheck(TCCState *s1) +{ +#ifdef CONFIG_TCC_BCHECK + addr_t *ptr; + int sym_index; + + if (0 == s1->do_bounds_check) + return; + /* XXX: add an object file to do that */ + ptr = section_ptr_add(bounds_section, sizeof(*ptr)); + *ptr = 0; + set_elf_sym(symtab_section, 0, 0, + ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0, + bounds_section->sh_num, "__bounds_start"); + /* pull bcheck.o from libtcc1.a */ + sym_index = set_elf_sym(symtab_section, 0, 0, + ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0, + SHN_UNDEF, "__bound_init"); + if (s1->output_type != TCC_OUTPUT_MEMORY) { + /* add 'call __bound_init()' in .init section */ + Section *init_section = find_section(s1, ".init"); + unsigned char *pinit = section_ptr_add(init_section, 5); + pinit[0] = 0xe8; + write32le(pinit + 1, -4); + put_elf_reloc(symtab_section, init_section, + init_section->data_offset - 4, R_386_PC32, sym_index); + /* R_386_PC32 = R_X86_64_PC32 = 2 */ + } +#endif +} + +/* add tcc runtime libraries */ +ST_FUNC void tcc_add_runtime(TCCState *s1) +{ + tcc_add_bcheck(s1); + tcc_add_pragma_libs(s1); + /* add libc */ + if (!s1->nostdlib) { + tcc_add_library_err(s1, "c"); +#ifdef TCC_LIBGCC + if (!s1->static_link) { + if (TCC_LIBGCC[0] == '/') + tcc_add_file(s1, TCC_LIBGCC); + else + tcc_add_dll(s1, TCC_LIBGCC, 0); + } +#endif + tcc_add_support(s1, TCC_LIBTCC1); + /* add crt end if not memory output */ + if (s1->output_type != TCC_OUTPUT_MEMORY) + tcc_add_crt(s1, "crtn.o"); + } +} + +/* add various standard linker symbols (must be done after the + sections are filled (for example after allocating common + symbols)) */ +ST_FUNC void tcc_add_linker_symbols(TCCState *s1) +{ + char buf[1024]; + int i; + Section *s; + + set_elf_sym(symtab_section, + text_section->data_offset, 0, + ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0, + text_section->sh_num, "_etext"); + set_elf_sym(symtab_section, + data_section->data_offset, 0, + ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0, + data_section->sh_num, "_edata"); + set_elf_sym(symtab_section, + bss_section->data_offset, 0, + ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0, + bss_section->sh_num, "_end"); +#ifndef TCC_TARGET_PE + /* horrible new standard ldscript defines */ + add_init_array_defines(s1, ".preinit_array"); + add_init_array_defines(s1, ".init_array"); + add_init_array_defines(s1, ".fini_array"); +#endif + + /* add start and stop symbols for sections whose name can be + expressed in C */ + for(i = 1; i < s1->nb_sections; i++) { + s = s1->sections[i]; + if (s->sh_type == SHT_PROGBITS && + (s->sh_flags & SHF_ALLOC)) { + const char *p; + int ch; + + /* check if section name can be expressed in C */ + p = s->name; + for(;;) { + ch = *p; + if (!ch) + break; + if (!isid(ch) && !isnum(ch)) + goto next_sec; + p++; + } + snprintf(buf, sizeof(buf), "__start_%s", s->name); + set_elf_sym(symtab_section, + 0, 0, + ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0, + s->sh_num, buf); + snprintf(buf, sizeof(buf), "__stop_%s", s->name); + set_elf_sym(symtab_section, + s->data_offset, 0, + ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0, + s->sh_num, buf); + } + next_sec: ; + } +} + +static void tcc_output_binary(TCCState *s1, FILE *f, + const int *sec_order) +{ + Section *s; + int i, offset, size; + + offset = 0; + for(i=1;inb_sections;i++) { + s = s1->sections[sec_order[i]]; + if (s->sh_type != SHT_NOBITS && + (s->sh_flags & SHF_ALLOC)) { + while (offset < s->sh_offset) { + fputc(0, f); + offset++; + } + size = s->sh_size; + fwrite(s->data, 1, size, f); + offset += size; + } + } +} + +ST_FUNC void fill_got_entry(TCCState *s1, ElfW_Rel *rel) +{ + int sym_index = ELFW(R_SYM) (rel->r_info); + ElfW(Sym) *sym = &((ElfW(Sym) *) symtab_section->data)[sym_index]; + struct sym_attr *attr = get_sym_attr(s1, sym_index, 0); + unsigned offset = attr->got_offset; + + if (0 == offset) + return; + section_reserve(s1->got, offset + PTR_SIZE); +#ifdef TCC_TARGET_X86_64 + write64le(s1->got->data + offset, sym->st_value); +#else + write32le(s1->got->data + offset, sym->st_value); +#endif +} + +/* Perform relocation to GOT or PLT entries */ +ST_FUNC void fill_got(TCCState *s1) +{ + Section *s; + ElfW_Rel *rel; + int i; + + for(i = 1; i < s1->nb_sections; i++) { + s = s1->sections[i]; + if (s->sh_type != SHT_RELX) + continue; + /* no need to handle got relocations */ + if (s->link != symtab_section) + continue; + for_each_elem(s, 0, rel, ElfW_Rel) { + switch (ELFW(R_TYPE) (rel->r_info)) { + case R_X86_64_GOT32: + case R_X86_64_GOTPCREL: + case R_X86_64_GOTPCRELX: + case R_X86_64_REX_GOTPCRELX: + case R_X86_64_PLT32: + fill_got_entry(s1, rel); + break; + } + } + } +} + +/* See put_got_entry for a description. This is the second stage + where GOT references to local defined symbols are rewritten. */ +static void fill_local_got_entries(TCCState *s1) +{ + ElfW_Rel *rel; + for_each_elem(s1->got->reloc, 0, rel, ElfW_Rel) { + if (ELFW(R_TYPE)(rel->r_info) == R_RELATIVE) { + int sym_index = ELFW(R_SYM) (rel->r_info); + ElfW(Sym) *sym = &((ElfW(Sym) *) symtab_section->data)[sym_index]; + struct sym_attr *attr = get_sym_attr(s1, sym_index, 0); + unsigned offset = attr->got_offset; + if (offset != rel->r_offset - s1->got->sh_addr) + tcc_error_noabort("huh"); + rel->r_info = ELFW(R_INFO)(0, R_RELATIVE); +#if SHT_RELX == SHT_RELA + rel->r_addend = sym->st_value; +#else + /* All our REL architectures also happen to be 32bit LE. */ + write32le(s1->got->data + offset, sym->st_value); +#endif + } + } +} + +/* Bind symbols of executable: resolve undefined symbols from exported symbols + in shared libraries and export non local defined symbols to shared libraries + if -rdynamic switch was given on command line */ +static void bind_exe_dynsyms(TCCState *s1) +{ + const char *name; + int sym_index, index; + ElfW(Sym) *sym, *esym; + int type; + + /* Resolve undefined symbols from dynamic symbols. When there is a match: + - if STT_FUNC or STT_GNU_IFUNC symbol -> add it in PLT + - if STT_OBJECT symbol -> add it in .bss section with suitable reloc */ + for_each_elem(symtab_section, 1, sym, ElfW(Sym)) { + if (sym->st_shndx == SHN_UNDEF) { + name = (char *) symtab_section->link->data + sym->st_name; + sym_index = find_elf_sym(s1->dynsymtab_section, name); + if (sym_index) { + esym = &((ElfW(Sym) *)s1->dynsymtab_section->data)[sym_index]; + type = ELFW(ST_TYPE)(esym->st_info); + if ((type == STT_FUNC) || (type == STT_GNU_IFUNC)) { + /* Indirect functions shall have STT_FUNC type in executable + * dynsym section. Indeed, a dlsym call following a lazy + * resolution would pick the symbol value from the + * executable dynsym entry which would contain the address + * of the function wanted by the caller of dlsym instead of + * the address of the function that would return that + * address */ + int dynindex + = put_elf_sym(s1->dynsym, 0, esym->st_size, + ELFW(ST_INFO)(STB_GLOBAL,STT_FUNC), 0, 0, + name); + int index = sym - (ElfW(Sym) *) symtab_section->data; + get_sym_attr(s1, index, 1)->dyn_index = dynindex; + } else if (type == STT_OBJECT) { + unsigned long offset; + ElfW(Sym) *dynsym; + offset = bss_section->data_offset; + /* XXX: which alignment ? */ + offset = (offset + 16 - 1) & -16; + set_elf_sym (s1->symtab, offset, esym->st_size, + esym->st_info, 0, bss_section->sh_num, name); + index = put_elf_sym(s1->dynsym, offset, esym->st_size, + esym->st_info, 0, bss_section->sh_num, + name); + + /* Ensure R_COPY works for weak symbol aliases */ + if (ELFW(ST_BIND)(esym->st_info) == STB_WEAK) { + for_each_elem(s1->dynsymtab_section, 1, dynsym, ElfW(Sym)) { + if ((dynsym->st_value == esym->st_value) + && (ELFW(ST_BIND)(dynsym->st_info) == STB_GLOBAL)) { + char *dynname = (char *) s1->dynsymtab_section->link->data + + dynsym->st_name; + put_elf_sym(s1->dynsym, offset, dynsym->st_size, + dynsym->st_info, 0, + bss_section->sh_num, dynname); + break; + } + } + } + + put_elf_reloc(s1->dynsym, bss_section, + offset, R_COPY, index); + offset += esym->st_size; + bss_section->data_offset = offset; + } + } else { + /* STB_WEAK undefined symbols are accepted */ + /* XXX: _fp_hw seems to be part of the ABI, so we ignore it */ + if (ELFW(ST_BIND)(sym->st_info) == STB_WEAK || + !strcmp(name, "_fp_hw")) { + } else { + tcc_error_noabort("undefined symbol '%s'", name); + } + } + } else if (s1->rdynamic && ELFW(ST_BIND)(sym->st_info) != STB_LOCAL) { + /* if -rdynamic option, then export all non local symbols */ + name = (char *) symtab_section->link->data + sym->st_name; + set_elf_sym(s1->dynsym, sym->st_value, sym->st_size, sym->st_info, + 0, sym->st_shndx, name); + } + } +} + +/* Bind symbols of libraries: export all non local symbols of executable that + are referenced by shared libraries. The reason is that the dynamic loader + search symbol first in executable and then in libraries. Therefore a + reference to a symbol already defined by a library can still be resolved by + a symbol in the executable. */ +static void bind_libs_dynsyms(TCCState *s1) +{ + const char *name; + int sym_index; + ElfW(Sym) *sym, *esym; + + for_each_elem(s1->dynsymtab_section, 1, esym, ElfW(Sym)) { + name = (char *) s1->dynsymtab_section->link->data + esym->st_name; + sym_index = find_elf_sym(symtab_section, name); + sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; + if (sym_index && sym->st_shndx != SHN_UNDEF + && ELFW(ST_BIND)(sym->st_info) != STB_LOCAL) { + set_elf_sym(s1->dynsym, sym->st_value, sym->st_size, + sym->st_info, 0, sym->st_shndx, name); + } else if (esym->st_shndx == SHN_UNDEF) { + /* weak symbols can stay undefined */ + if (ELFW(ST_BIND)(esym->st_info) != STB_WEAK) + tcc_warning("undefined dynamic symbol '%s'", name); + } + } +} + +/* Export all non local symbols. This is used by shared libraries so that the + non local symbols they define can resolve a reference in another shared + library or in the executable. Correspondingly, it allows undefined local + symbols to be resolved by other shared libraries or by the executable. */ +static void export_global_syms(TCCState *s1) +{ + int dynindex, index; + const char *name; + ElfW(Sym) *sym; + + for_each_elem(symtab_section, 1, sym, ElfW(Sym)) { + if (ELFW(ST_BIND)(sym->st_info) != STB_LOCAL) { + name = (char *) symtab_section->link->data + sym->st_name; + dynindex = put_elf_sym(s1->dynsym, sym->st_value, sym->st_size, + sym->st_info, 0, sym->st_shndx, name); + index = sym - (ElfW(Sym) *) symtab_section->data; + get_sym_attr(s1, index, 1)->dyn_index = dynindex; + } + } +} + +/* Allocate strings for section names and decide if an unallocated section + should be output. + NOTE: the strsec section comes last, so its size is also correct ! */ +static int alloc_sec_names(TCCState *s1, int file_type, Section *strsec) +{ + int i; + Section *s; + int textrel = 0; + + /* Allocate strings for section names */ + for(i = 1; i < s1->nb_sections; i++) { + s = s1->sections[i]; + /* when generating a DLL, we include relocations but we may + patch them */ + if (file_type == TCC_OUTPUT_DLL && + s->sh_type == SHT_RELX && + !(s->sh_flags & SHF_ALLOC) && + (s1->sections[s->sh_info]->sh_flags & SHF_ALLOC) && + prepare_dynamic_rel(s1, s)) { + if (s1->sections[s->sh_info]->sh_flags & SHF_EXECINSTR) + textrel = 1; + } else if (s1->do_debug || + file_type == TCC_OUTPUT_OBJ || + (s->sh_flags & SHF_ALLOC) || + i == (s1->nb_sections - 1)) { + /* we output all sections if debug or object file */ + s->sh_size = s->data_offset; + } + if (s->sh_size || (s->sh_flags & SHF_ALLOC)) + s->sh_name = put_elf_str(strsec, s->name); + } + strsec->sh_size = strsec->data_offset; + return textrel; +} + +/* Info to be copied in dynamic section */ +struct dyn_inf { + Section *dynamic; + Section *dynstr; + unsigned long data_offset; + addr_t rel_addr; + addr_t rel_size; +#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) + addr_t bss_addr; + addr_t bss_size; +#endif +}; + +/* Assign sections to segments and decide how are sections laid out when loaded + in memory. This function also fills corresponding program headers. */ +static int layout_sections(TCCState *s1, ElfW(Phdr) *phdr, int phnum, + Section *interp, Section* strsec, + struct dyn_inf *dyninf, int *sec_order) +{ + int i, j, k, file_type, sh_order_index, file_offset; + unsigned long s_align; + long long tmp; + addr_t addr; + ElfW(Phdr) *ph; + Section *s; + + file_type = s1->output_type; + sh_order_index = 1; + file_offset = 0; + if (s1->output_format == TCC_OUTPUT_FORMAT_ELF) + file_offset = sizeof(ElfW(Ehdr)) + phnum * sizeof(ElfW(Phdr)); + s_align = ELF_PAGE_SIZE; + if (s1->section_align) + s_align = s1->section_align; + + if (phnum > 0) { + if (s1->has_text_addr) { + int a_offset, p_offset; + addr = s1->text_addr; + /* we ensure that (addr % ELF_PAGE_SIZE) == file_offset % + ELF_PAGE_SIZE */ + a_offset = (int) (addr & (s_align - 1)); + p_offset = file_offset & (s_align - 1); + if (a_offset < p_offset) + a_offset += s_align; + file_offset += (a_offset - p_offset); + } else { + if (file_type == TCC_OUTPUT_DLL) + addr = 0; + else + addr = ELF_START_ADDR; + /* compute address after headers */ + addr += (file_offset & (s_align - 1)); + } + + ph = &phdr[0]; + /* Leave one program headers for the program interpreter and one for + the program header table itself if needed. These are done later as + they require section layout to be done first. */ + if (interp) + ph += 2; + + /* dynamic relocation table information, for .dynamic section */ + dyninf->rel_addr = dyninf->rel_size = 0; +#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) + dyninf->bss_addr = dyninf->bss_size = 0; +#endif + + for(j = 0; j < 2; j++) { + ph->p_type = PT_LOAD; + if (j == 0) + ph->p_flags = PF_R | PF_X; + else + ph->p_flags = PF_R | PF_W; + ph->p_align = s_align; + + /* Decide the layout of sections loaded in memory. This must + be done before program headers are filled since they contain + info about the layout. We do the following ordering: interp, + symbol tables, relocations, progbits, nobits */ + /* XXX: do faster and simpler sorting */ + for(k = 0; k < 5; k++) { + for(i = 1; i < s1->nb_sections; i++) { + s = s1->sections[i]; + /* compute if section should be included */ + if (j == 0) { + if ((s->sh_flags & (SHF_ALLOC | SHF_WRITE)) != + SHF_ALLOC) + continue; + } else { + if ((s->sh_flags & (SHF_ALLOC | SHF_WRITE)) != + (SHF_ALLOC | SHF_WRITE)) + continue; + } + if (s == interp) { + if (k != 0) + continue; + } else if (s->sh_type == SHT_DYNSYM || + s->sh_type == SHT_STRTAB || + s->sh_type == SHT_HASH) { + if (k != 1) + continue; + } else if (s->sh_type == SHT_RELX) { + if (k != 2) + continue; + } else if (s->sh_type == SHT_NOBITS) { + if (k != 4) + continue; + } else { + if (k != 3) + continue; + } + sec_order[sh_order_index++] = i; + + /* section matches: we align it and add its size */ + tmp = addr; + addr = (addr + s->sh_addralign - 1) & + ~(s->sh_addralign - 1); + file_offset += (int) ( addr - tmp ); + s->sh_offset = file_offset; + s->sh_addr = addr; + + /* update program header infos */ + if (ph->p_offset == 0) { + ph->p_offset = file_offset; + ph->p_vaddr = addr; + ph->p_paddr = ph->p_vaddr; + } + /* update dynamic relocation infos */ + if (s->sh_type == SHT_RELX) { +#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) + if (!strcmp(strsec->data + s->sh_name, ".rel.got")) { + dyninf->rel_addr = addr; + dyninf->rel_size += s->sh_size; /* XXX only first rel. */ + } + if (!strcmp(strsec->data + s->sh_name, ".rel.bss")) { + dyninf->bss_addr = addr; + dyninf->bss_size = s->sh_size; /* XXX only first rel. */ + } +#else + if (dyninf->rel_size == 0) + dyninf->rel_addr = addr; + dyninf->rel_size += s->sh_size; +#endif + } + addr += s->sh_size; + if (s->sh_type != SHT_NOBITS) + file_offset += s->sh_size; + } + } + if (j == 0) { + /* Make the first PT_LOAD segment include the program + headers itself (and the ELF header as well), it'll + come out with same memory use but will make various + tools like binutils strip work better. */ + ph->p_offset &= ~(ph->p_align - 1); + ph->p_vaddr &= ~(ph->p_align - 1); + ph->p_paddr &= ~(ph->p_align - 1); + } + ph->p_filesz = file_offset - ph->p_offset; + ph->p_memsz = addr - ph->p_vaddr; + ph++; + if (j == 0) { + if (s1->output_format == TCC_OUTPUT_FORMAT_ELF) { + /* if in the middle of a page, we duplicate the page in + memory so that one copy is RX and the other is RW */ + if ((addr & (s_align - 1)) != 0) + addr += s_align; + } else { + addr = (addr + s_align - 1) & ~(s_align - 1); + file_offset = (file_offset + s_align - 1) & ~(s_align - 1); + } + } + } + } + + /* all other sections come after */ + for(i = 1; i < s1->nb_sections; i++) { + s = s1->sections[i]; + if (phnum > 0 && (s->sh_flags & SHF_ALLOC)) + continue; + sec_order[sh_order_index++] = i; + + file_offset = (file_offset + s->sh_addralign - 1) & + ~(s->sh_addralign - 1); + s->sh_offset = file_offset; + if (s->sh_type != SHT_NOBITS) + file_offset += s->sh_size; + } + + return file_offset; +} + +static void fill_unloadable_phdr(ElfW(Phdr) *phdr, int phnum, Section *interp, + Section *dynamic) +{ + ElfW(Phdr) *ph; + + /* if interpreter, then add corresponding program header */ + if (interp) { + ph = &phdr[0]; + + ph->p_type = PT_PHDR; + ph->p_offset = sizeof(ElfW(Ehdr)); + ph->p_filesz = ph->p_memsz = phnum * sizeof(ElfW(Phdr)); + ph->p_vaddr = interp->sh_addr - ph->p_filesz; + ph->p_paddr = ph->p_vaddr; + ph->p_flags = PF_R | PF_X; + ph->p_align = 4; /* interp->sh_addralign; */ + ph++; + + ph->p_type = PT_INTERP; + ph->p_offset = interp->sh_offset; + ph->p_vaddr = interp->sh_addr; + ph->p_paddr = ph->p_vaddr; + ph->p_filesz = interp->sh_size; + ph->p_memsz = interp->sh_size; + ph->p_flags = PF_R; + ph->p_align = interp->sh_addralign; + } + + /* if dynamic section, then add corresponding program header */ + if (dynamic) { + ph = &phdr[phnum - 1]; + + ph->p_type = PT_DYNAMIC; + ph->p_offset = dynamic->sh_offset; + ph->p_vaddr = dynamic->sh_addr; + ph->p_paddr = ph->p_vaddr; + ph->p_filesz = dynamic->sh_size; + ph->p_memsz = dynamic->sh_size; + ph->p_flags = PF_R | PF_W; + ph->p_align = dynamic->sh_addralign; + } +} + +/* Fill the dynamic section with tags describing the address and size of + sections */ +static void fill_dynamic(TCCState *s1, struct dyn_inf *dyninf) +{ + Section *dynamic = dyninf->dynamic; + + /* put dynamic section entries */ + put_dt(dynamic, DT_HASH, s1->dynsym->hash->sh_addr); + put_dt(dynamic, DT_STRTAB, dyninf->dynstr->sh_addr); + put_dt(dynamic, DT_SYMTAB, s1->dynsym->sh_addr); + put_dt(dynamic, DT_STRSZ, dyninf->dynstr->data_offset); + put_dt(dynamic, DT_SYMENT, sizeof(ElfW(Sym))); +#if PTR_SIZE == 8 + put_dt(dynamic, DT_RELA, dyninf->rel_addr); + put_dt(dynamic, DT_RELASZ, dyninf->rel_size); + put_dt(dynamic, DT_RELAENT, sizeof(ElfW_Rel)); +#else +#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) + put_dt(dynamic, DT_PLTGOT, s1->got->sh_addr); + put_dt(dynamic, DT_PLTRELSZ, dyninf->rel_size); + put_dt(dynamic, DT_JMPREL, dyninf->rel_addr); + put_dt(dynamic, DT_PLTREL, DT_REL); + put_dt(dynamic, DT_REL, dyninf->bss_addr); + put_dt(dynamic, DT_RELSZ, dyninf->bss_size); +#else + put_dt(dynamic, DT_REL, dyninf->rel_addr); + put_dt(dynamic, DT_RELSZ, dyninf->rel_size); + put_dt(dynamic, DT_RELENT, sizeof(ElfW_Rel)); +#endif +#endif + if (s1->do_debug) + put_dt(dynamic, DT_DEBUG, 0); + put_dt(dynamic, DT_NULL, 0); +} + +/* Relocate remaining sections and symbols (that is those not related to + dynamic linking) */ +static int final_sections_reloc(TCCState *s1) +{ + int i; + Section *s; + + relocate_syms(s1, s1->symtab, 0); + + if (s1->nb_errors != 0) + return -1; + + /* relocate sections */ + /* XXX: ignore sections with allocated relocations ? */ + for(i = 1; i < s1->nb_sections; i++) { + s = s1->sections[i]; +#if defined(TCC_TARGET_I386) || defined(TCC_MUSL) + if (s->reloc && s != s1->got && (s->sh_flags & SHF_ALLOC)) //gr + /* On X86 gdb 7.3 works in any case but gdb 6.6 will crash if SHF_ALLOC + checking is removed */ +#else + if (s->reloc && s != s1->got) + /* On X86_64 gdb 7.3 will crash if SHF_ALLOC checking is present */ +#endif + relocate_section(s1, s); + } + + /* relocate relocation entries if the relocation tables are + allocated in the executable */ + for(i = 1; i < s1->nb_sections; i++) { + s = s1->sections[i]; + if ((s->sh_flags & SHF_ALLOC) && + s->sh_type == SHT_RELX) { + relocate_rel(s1, s); + } + } + return 0; +} + +/* Create an ELF file on disk. + This function handle ELF specific layout requirements */ +static void tcc_output_elf(TCCState *s1, FILE *f, int phnum, ElfW(Phdr) *phdr, + int file_offset, int *sec_order) +{ + int i, shnum, offset, size, file_type; + Section *s; + ElfW(Ehdr) ehdr; + ElfW(Shdr) shdr, *sh; + + file_type = s1->output_type; + shnum = s1->nb_sections; + + memset(&ehdr, 0, sizeof(ehdr)); + + if (phnum > 0) { + ehdr.e_phentsize = sizeof(ElfW(Phdr)); + ehdr.e_phnum = phnum; + ehdr.e_phoff = sizeof(ElfW(Ehdr)); + } + + /* align to 4 */ + file_offset = (file_offset + 3) & -4; + + /* fill header */ + ehdr.e_ident[0] = ELFMAG0; + ehdr.e_ident[1] = ELFMAG1; + ehdr.e_ident[2] = ELFMAG2; + ehdr.e_ident[3] = ELFMAG3; + ehdr.e_ident[4] = ELFCLASSW; + ehdr.e_ident[5] = ELFDATA2LSB; + ehdr.e_ident[6] = EV_CURRENT; +#if !defined(TCC_TARGET_PE) && (defined(__FreeBSD__) || defined(__FreeBSD_kernel__)) + /* FIXME: should set only for freebsd _target_, but we exclude only PE target */ + ehdr.e_ident[EI_OSABI] = ELFOSABI_FREEBSD; +#endif +#ifdef TCC_TARGET_ARM +#ifdef TCC_ARM_EABI + ehdr.e_ident[EI_OSABI] = 0; + ehdr.e_flags = EF_ARM_EABI_VER4; + if (file_type == TCC_OUTPUT_EXE || file_type == TCC_OUTPUT_DLL) + ehdr.e_flags |= EF_ARM_HASENTRY; + if (s1->float_abi == ARM_HARD_FLOAT) + ehdr.e_flags |= EF_ARM_VFP_FLOAT; + else + ehdr.e_flags |= EF_ARM_SOFT_FLOAT; +#else + ehdr.e_ident[EI_OSABI] = ELFOSABI_ARM; +#endif +#endif + switch(file_type) { + default: + case TCC_OUTPUT_EXE: + ehdr.e_type = ET_EXEC; + ehdr.e_entry = get_elf_sym_addr(s1, "_start", 1); + break; + case TCC_OUTPUT_DLL: + ehdr.e_type = ET_DYN; + ehdr.e_entry = text_section->sh_addr; /* XXX: is it correct ? */ + break; + case TCC_OUTPUT_OBJ: + ehdr.e_type = ET_REL; + break; + } + ehdr.e_machine = EM_TCC_TARGET; + ehdr.e_version = EV_CURRENT; + ehdr.e_shoff = file_offset; + ehdr.e_ehsize = sizeof(ElfW(Ehdr)); + ehdr.e_shentsize = sizeof(ElfW(Shdr)); + ehdr.e_shnum = shnum; + ehdr.e_shstrndx = shnum - 1; + + fwrite(&ehdr, 1, sizeof(ElfW(Ehdr)), f); + fwrite(phdr, 1, phnum * sizeof(ElfW(Phdr)), f); + offset = sizeof(ElfW(Ehdr)) + phnum * sizeof(ElfW(Phdr)); + + sort_syms(s1, symtab_section); + for(i = 1; i < s1->nb_sections; i++) { + s = s1->sections[sec_order[i]]; + if (s->sh_type != SHT_NOBITS) { + while (offset < s->sh_offset) { + fputc(0, f); + offset++; + } + size = s->sh_size; + if (size) + fwrite(s->data, 1, size, f); + offset += size; + } + } + + /* output section headers */ + while (offset < ehdr.e_shoff) { + fputc(0, f); + offset++; + } + + for(i = 0; i < s1->nb_sections; i++) { + sh = &shdr; + memset(sh, 0, sizeof(ElfW(Shdr))); + s = s1->sections[i]; + if (s) { + sh->sh_name = s->sh_name; + sh->sh_type = s->sh_type; + sh->sh_flags = s->sh_flags; + sh->sh_entsize = s->sh_entsize; + sh->sh_info = s->sh_info; + if (s->link) + sh->sh_link = s->link->sh_num; + sh->sh_addralign = s->sh_addralign; + sh->sh_addr = s->sh_addr; + sh->sh_offset = s->sh_offset; + sh->sh_size = s->sh_size; + } + fwrite(sh, 1, sizeof(ElfW(Shdr)), f); + } +} + +/* Write an elf, coff or "binary" file */ +static int tcc_write_elf_file(TCCState *s1, const char *filename, int phnum, + ElfW(Phdr) *phdr, int file_offset, int *sec_order) +{ + int fd, mode, file_type; + FILE *f; + + file_type = s1->output_type; + if (file_type == TCC_OUTPUT_OBJ) + mode = 0666; + else + mode = 0777; + unlink(filename); + fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, mode); + if (fd < 0) { + tcc_error_noabort("could not write '%s'", filename); + return -1; + } + f = fdopen(fd, "wb"); + if (s1->verbose) + printf("<- %s\n", filename); + +#ifdef TCC_TARGET_COFF + if (s1->output_format == TCC_OUTPUT_FORMAT_COFF) + tcc_output_coff(s1, f); + else +#endif + if (s1->output_format == TCC_OUTPUT_FORMAT_ELF) + tcc_output_elf(s1, f, phnum, phdr, file_offset, sec_order); + else + tcc_output_binary(s1, f, sec_order); + fclose(f); + + return 0; +} + +/* Sort section headers by assigned sh_addr, remove sections + that we aren't going to output. */ +static void tidy_section_headers(TCCState *s1, int *sec_order) +{ + int i, nnew, l, *backmap; + Section **snew, *s; + ElfW(Sym) *sym; + + snew = tcc_malloc(s1->nb_sections * sizeof(snew[0])); + backmap = tcc_malloc(s1->nb_sections * sizeof(backmap[0])); + for (i = 0, nnew = 0, l = s1->nb_sections; i < s1->nb_sections; i++) { + s = s1->sections[sec_order[i]]; + if (!i || s->sh_name) { + backmap[sec_order[i]] = nnew; + snew[nnew] = s; + ++nnew; + } else { + backmap[sec_order[i]] = 0; + snew[--l] = s; + } + } + for (i = 0; i < nnew; i++) { + s = snew[i]; + if (s) { + s->sh_num = i; + if (s->sh_type == SHT_RELX) + s->sh_info = backmap[s->sh_info]; + } + } + + for_each_elem(symtab_section, 1, sym, ElfW(Sym)) + if (sym->st_shndx != SHN_UNDEF && sym->st_shndx < SHN_LORESERVE) + sym->st_shndx = backmap[sym->st_shndx]; + if( !s1->static_link ) { + for_each_elem(s1->dynsym, 1, sym, ElfW(Sym)) + if (sym->st_shndx != SHN_UNDEF && sym->st_shndx < SHN_LORESERVE) + sym->st_shndx = backmap[sym->st_shndx]; + } + for (i = 0; i < s1->nb_sections; i++) + sec_order[i] = i; + tcc_free(s1->sections); + s1->sections = snew; + s1->nb_sections = nnew; + tcc_free(backmap); +} + +/* Output an elf, coff or binary file */ +/* XXX: suppress unneeded sections */ +static int elf_output_file(TCCState *s1, const char *filename) +{ + int i, ret, phnum, shnum, file_type, file_offset, *sec_order; + struct dyn_inf dyninf = {0}; + ElfW(Phdr) *phdr; + ElfW(Sym) *sym; + Section *strsec, *interp, *dynamic, *dynstr; + int textrel; + + file_type = s1->output_type; + s1->nb_errors = 0; + ret = -1; + phdr = NULL; + sec_order = NULL; + interp = dynamic = dynstr = NULL; /* avoid warning */ + textrel = 0; + + if (file_type != TCC_OUTPUT_OBJ) { + /* if linking, also link in runtime libraries (libc, libgcc, etc.) */ + tcc_add_runtime(s1); + relocate_common_syms(); + tcc_add_linker_symbols(s1); + + if (!s1->static_link) { + if (file_type == TCC_OUTPUT_EXE) { + char *ptr; + /* allow override the dynamic loader */ + const char *elfint = getenv("LD_SO"); + if (elfint == NULL) + elfint = DEFAULT_ELFINTERP(s1); + /* add interpreter section only if executable */ + interp = new_section(s1, ".interp", SHT_PROGBITS, SHF_ALLOC); + interp->sh_addralign = 1; + ptr = section_ptr_add(interp, 1 + strlen(elfint)); + strcpy(ptr, elfint); + } + + /* add dynamic symbol table */ + s1->dynsym = new_symtab(s1, ".dynsym", SHT_DYNSYM, SHF_ALLOC, + ".dynstr", + ".hash", SHF_ALLOC); + dynstr = s1->dynsym->link; + + /* add dynamic section */ + dynamic = new_section(s1, ".dynamic", SHT_DYNAMIC, + SHF_ALLOC | SHF_WRITE); + dynamic->link = dynstr; + dynamic->sh_entsize = sizeof(ElfW(Dyn)); + + build_got(s1); + + if (file_type == TCC_OUTPUT_EXE) { + bind_exe_dynsyms(s1); + if (s1->nb_errors) + goto the_end; + bind_libs_dynsyms(s1); + } else { + /* shared library case: simply export all global symbols */ + export_global_syms(s1); + } + } + build_got_entries(s1); + } + + /* we add a section for symbols */ + strsec = new_section(s1, ".shstrtab", SHT_STRTAB, 0); + put_elf_str(strsec, ""); + + /* Allocate strings for section names */ + textrel = alloc_sec_names(s1, file_type, strsec); + + if (dynamic) { + /* add a list of needed dlls */ + for(i = 0; i < s1->nb_loaded_dlls; i++) { + DLLReference *dllref = s1->loaded_dlls[i]; + if (dllref->level == 0) + put_dt(dynamic, DT_NEEDED, put_elf_str(dynstr, dllref->name)); + } + + if (s1->rpath) + put_dt(dynamic, s1->enable_new_dtags ? DT_RUNPATH : DT_RPATH, + put_elf_str(dynstr, s1->rpath)); + + if (file_type == TCC_OUTPUT_DLL) { + if (s1->soname) + put_dt(dynamic, DT_SONAME, put_elf_str(dynstr, s1->soname)); + /* XXX: currently, since we do not handle PIC code, we + must relocate the readonly segments */ + if (textrel) + put_dt(dynamic, DT_TEXTREL, 0); + } + + if (s1->symbolic) + put_dt(dynamic, DT_SYMBOLIC, 0); + + dyninf.dynamic = dynamic; + dyninf.dynstr = dynstr; + /* remember offset and reserve space for 2nd call below */ + dyninf.data_offset = dynamic->data_offset; + fill_dynamic(s1, &dyninf); + dynamic->sh_size = dynamic->data_offset; + dynstr->sh_size = dynstr->data_offset; + } + + /* compute number of program headers */ + if (file_type == TCC_OUTPUT_OBJ) + phnum = 0; + else if (file_type == TCC_OUTPUT_DLL) + phnum = 3; + else if (s1->static_link) + phnum = 2; + else + phnum = 5; + + /* allocate program segment headers */ + phdr = tcc_mallocz(phnum * sizeof(ElfW(Phdr))); + + /* compute number of sections */ + shnum = s1->nb_sections; + + /* this array is used to reorder sections in the output file */ + sec_order = tcc_malloc(sizeof(int) * shnum); + sec_order[0] = 0; + + /* compute section to program header mapping */ + file_offset = layout_sections(s1, phdr, phnum, interp, strsec, &dyninf, + sec_order); + + /* Fill remaining program header and finalize relocation related to dynamic + linking. */ + if (file_type != TCC_OUTPUT_OBJ) { + fill_unloadable_phdr(phdr, phnum, interp, dynamic); + if (dynamic) { + dynamic->data_offset = dyninf.data_offset; + fill_dynamic(s1, &dyninf); + + /* put in GOT the dynamic section address and relocate PLT */ + write32le(s1->got->data, dynamic->sh_addr); + if (file_type == TCC_OUTPUT_EXE + || (RELOCATE_DLLPLT && file_type == TCC_OUTPUT_DLL)) + relocate_plt(s1); + + /* relocate symbols in .dynsym now that final addresses are known */ + for_each_elem(s1->dynsym, 1, sym, ElfW(Sym)) { + if (sym->st_shndx != SHN_UNDEF && sym->st_shndx < SHN_LORESERVE) { + /* do symbol relocation */ + sym->st_value += s1->sections[sym->st_shndx]->sh_addr; + } + } + } + + /* if building executable or DLL, then relocate each section + except the GOT which is already relocated */ + ret = final_sections_reloc(s1); + if (ret) + goto the_end; + tidy_section_headers(s1, sec_order); + + /* Perform relocation to GOT or PLT entries */ + if (file_type == TCC_OUTPUT_EXE && s1->static_link) + fill_got(s1); + else if (s1->got) + fill_local_got_entries(s1); + } + + /* Create the ELF file with name 'filename' */ + ret = tcc_write_elf_file(s1, filename, phnum, phdr, file_offset, sec_order); + s1->nb_sections = shnum; + the_end: + tcc_free(sec_order); + tcc_free(phdr); + return ret; +} + +LIBTCCAPI int tcc_output_file(TCCState *s, const char *filename) +{ + int ret; +#ifdef TCC_TARGET_PE + if (s->output_type != TCC_OUTPUT_OBJ) { + ret = pe_output_file(s, filename); + } else +#endif + ret = elf_output_file(s, filename); + return ret; +} + +static void *load_data(int fd, unsigned long file_offset, unsigned long size) +{ + void *data; + + data = tcc_malloc(size); + lseek(fd, file_offset, SEEK_SET); + read(fd, data, size); + return data; +} + +typedef struct SectionMergeInfo { + Section *s; /* corresponding existing section */ + unsigned long offset; /* offset of the new section in the existing section */ + uint8_t new_section; /* true if section 's' was added */ + uint8_t link_once; /* true if link once section */ +} SectionMergeInfo; + +ST_FUNC int tcc_object_type(int fd, ElfW(Ehdr) *h) +{ + int size = read(fd, h, sizeof *h); + if (size == sizeof *h && 0 == memcmp(h, ELFMAG, 4)) { + if (h->e_type == ET_REL) + return AFF_BINTYPE_REL; + if (h->e_type == ET_DYN) + return AFF_BINTYPE_DYN; + } else if (size >= 8) { + if (0 == memcmp(h, ARMAG, 8)) + return AFF_BINTYPE_AR; +#ifdef TCC_TARGET_COFF + if (((struct filehdr*)h)->f_magic == COFF_C67_MAGIC) + return AFF_BINTYPE_C67; +#endif + } + return 0; +} + +/* load an object file and merge it with current files */ +/* XXX: handle correctly stab (debug) info */ +ST_FUNC int tcc_load_object_file(TCCState *s1, + int fd, unsigned long file_offset) +{ + ElfW(Ehdr) ehdr; + ElfW(Shdr) *shdr, *sh; + int size, i, j, offset, offseti, nb_syms, sym_index, ret, seencompressed; + unsigned char *strsec, *strtab; + int *old_to_new_syms; + char *sh_name, *name; + SectionMergeInfo *sm_table, *sm; + ElfW(Sym) *sym, *symtab; + ElfW_Rel *rel; + Section *s; + + int stab_index; + int stabstr_index; + + stab_index = stabstr_index = 0; + + lseek(fd, file_offset, SEEK_SET); + if (tcc_object_type(fd, &ehdr) != AFF_BINTYPE_REL) + goto fail1; + /* test CPU specific stuff */ + if (ehdr.e_ident[5] != ELFDATA2LSB || + ehdr.e_machine != EM_TCC_TARGET) { + fail1: + tcc_error_noabort("invalid object file"); + return -1; + } + /* read sections */ + shdr = load_data(fd, file_offset + ehdr.e_shoff, + sizeof(ElfW(Shdr)) * ehdr.e_shnum); + sm_table = tcc_mallocz(sizeof(SectionMergeInfo) * ehdr.e_shnum); + + /* load section names */ + sh = &shdr[ehdr.e_shstrndx]; + strsec = load_data(fd, file_offset + sh->sh_offset, sh->sh_size); + + /* load symtab and strtab */ + old_to_new_syms = NULL; + symtab = NULL; + strtab = NULL; + nb_syms = 0; + seencompressed = 0; + for(i = 1; i < ehdr.e_shnum; i++) { + sh = &shdr[i]; + if (sh->sh_type == SHT_SYMTAB) { + if (symtab) { + tcc_error_noabort("object must contain only one symtab"); + fail: + ret = -1; + goto the_end; + } + nb_syms = sh->sh_size / sizeof(ElfW(Sym)); + symtab = load_data(fd, file_offset + sh->sh_offset, sh->sh_size); + sm_table[i].s = symtab_section; + + /* now load strtab */ + sh = &shdr[sh->sh_link]; + strtab = load_data(fd, file_offset + sh->sh_offset, sh->sh_size); + } + if (sh->sh_flags & SHF_COMPRESSED) + seencompressed = 1; + } + + /* now examine each section and try to merge its content with the + ones in memory */ + for(i = 1; i < ehdr.e_shnum; i++) { + /* no need to examine section name strtab */ + if (i == ehdr.e_shstrndx) + continue; + sh = &shdr[i]; + sh_name = (char *) strsec + sh->sh_name; + /* ignore sections types we do not handle */ + if (sh->sh_type != SHT_PROGBITS && + sh->sh_type != SHT_RELX && +#ifdef TCC_ARM_EABI + sh->sh_type != SHT_ARM_EXIDX && +#endif + sh->sh_type != SHT_NOBITS && + sh->sh_type != SHT_PREINIT_ARRAY && + sh->sh_type != SHT_INIT_ARRAY && + sh->sh_type != SHT_FINI_ARRAY && + strcmp(sh_name, ".stabstr") + ) + continue; + if (seencompressed + && (!strncmp(sh_name, ".debug_", sizeof(".debug_")-1) + || (sh->sh_type == SHT_RELX + && !strncmp((char*)strsec + shdr[sh->sh_info].sh_name, + ".debug_", sizeof(".debug_")-1)))) + continue; + if (sh->sh_addralign < 1) + sh->sh_addralign = 1; + /* find corresponding section, if any */ + for(j = 1; j < s1->nb_sections;j++) { + s = s1->sections[j]; + if (!strcmp(s->name, sh_name)) { + if (!strncmp(sh_name, ".gnu.linkonce", + sizeof(".gnu.linkonce") - 1)) { + /* if a 'linkonce' section is already present, we + do not add it again. It is a little tricky as + symbols can still be defined in + it. */ + sm_table[i].link_once = 1; + goto next; + } else { + goto found; + } + } + } + /* not found: create new section */ + s = new_section(s1, sh_name, sh->sh_type, sh->sh_flags & ~SHF_GROUP); + /* take as much info as possible from the section. sh_link and + sh_info will be updated later */ + s->sh_addralign = sh->sh_addralign; + s->sh_entsize = sh->sh_entsize; + sm_table[i].new_section = 1; + found: + if (sh->sh_type != s->sh_type) { + tcc_error_noabort("invalid section type"); + goto fail; + } + + /* align start of section */ + offset = s->data_offset; + + if (0 == strcmp(sh_name, ".stab")) { + stab_index = i; + goto no_align; + } + if (0 == strcmp(sh_name, ".stabstr")) { + stabstr_index = i; + goto no_align; + } + + size = sh->sh_addralign - 1; + offset = (offset + size) & ~size; + if (sh->sh_addralign > s->sh_addralign) + s->sh_addralign = sh->sh_addralign; + s->data_offset = offset; + no_align: + sm_table[i].offset = offset; + sm_table[i].s = s; + /* concatenate sections */ + size = sh->sh_size; + if (sh->sh_type != SHT_NOBITS) { + unsigned char *ptr; + lseek(fd, file_offset + sh->sh_offset, SEEK_SET); + ptr = section_ptr_add(s, size); + read(fd, ptr, size); + } else { + s->data_offset += size; + } + next: ; + } + + /* gr relocate stab strings */ + if (stab_index && stabstr_index) { + Stab_Sym *a, *b; + unsigned o; + s = sm_table[stab_index].s; + a = (Stab_Sym *)(s->data + sm_table[stab_index].offset); + b = (Stab_Sym *)(s->data + s->data_offset); + o = sm_table[stabstr_index].offset; + while (a < b) + a->n_strx += o, a++; + } + + /* second short pass to update sh_link and sh_info fields of new + sections */ + for(i = 1; i < ehdr.e_shnum; i++) { + s = sm_table[i].s; + if (!s || !sm_table[i].new_section) + continue; + sh = &shdr[i]; + if (sh->sh_link > 0) + s->link = sm_table[sh->sh_link].s; + if (sh->sh_type == SHT_RELX) { + s->sh_info = sm_table[sh->sh_info].s->sh_num; + /* update backward link */ + s1->sections[s->sh_info]->reloc = s; + } + } + sm = sm_table; + + /* resolve symbols */ + old_to_new_syms = tcc_mallocz(nb_syms * sizeof(int)); + + sym = symtab + 1; + for(i = 1; i < nb_syms; i++, sym++) { + if (sym->st_shndx != SHN_UNDEF && + sym->st_shndx < SHN_LORESERVE) { + sm = &sm_table[sym->st_shndx]; + if (sm->link_once) { + /* if a symbol is in a link once section, we use the + already defined symbol. It is very important to get + correct relocations */ + if (ELFW(ST_BIND)(sym->st_info) != STB_LOCAL) { + name = (char *) strtab + sym->st_name; + sym_index = find_elf_sym(symtab_section, name); + if (sym_index) + old_to_new_syms[i] = sym_index; + } + continue; + } + /* if no corresponding section added, no need to add symbol */ + if (!sm->s) + continue; + /* convert section number */ + sym->st_shndx = sm->s->sh_num; + /* offset value */ + sym->st_value += sm->offset; + } + /* add symbol */ + name = (char *) strtab + sym->st_name; + sym_index = set_elf_sym(symtab_section, sym->st_value, sym->st_size, + sym->st_info, sym->st_other, + sym->st_shndx, name); + old_to_new_syms[i] = sym_index; + } + + /* third pass to patch relocation entries */ + for(i = 1; i < ehdr.e_shnum; i++) { + s = sm_table[i].s; + if (!s) + continue; + sh = &shdr[i]; + offset = sm_table[i].offset; + switch(s->sh_type) { + case SHT_RELX: + /* take relocation offset information */ + offseti = sm_table[sh->sh_info].offset; + for_each_elem(s, (offset / sizeof(*rel)), rel, ElfW_Rel) { + int type; + unsigned sym_index; + /* convert symbol index */ + type = ELFW(R_TYPE)(rel->r_info); + sym_index = ELFW(R_SYM)(rel->r_info); + /* NOTE: only one symtab assumed */ + if (sym_index >= nb_syms) + goto invalid_reloc; + sym_index = old_to_new_syms[sym_index]; + /* ignore link_once in rel section. */ + if (!sym_index && !sm->link_once +#ifdef TCC_TARGET_ARM + && type != R_ARM_V4BX +#endif + ) { + invalid_reloc: + tcc_error_noabort("Invalid relocation entry [%2d] '%s' @ %.8x", + i, strsec + sh->sh_name, rel->r_offset); + goto fail; + } + rel->r_info = ELFW(R_INFO)(sym_index, type); + /* offset the relocation offset */ + rel->r_offset += offseti; +#ifdef TCC_TARGET_ARM + /* Jumps and branches from a Thumb code to a PLT entry need + special handling since PLT entries are ARM code. + Unconditional bl instructions referencing PLT entries are + handled by converting these instructions into blx + instructions. Other case of instructions referencing a PLT + entry require to add a Thumb stub before the PLT entry to + switch to ARM mode. We set bit plt_thumb_stub of the + attribute of a symbol to indicate such a case. */ + if (type == R_ARM_THM_JUMP24) + get_sym_attr(s1, sym_index, 1)->plt_thumb_stub = 1; +#endif + } + break; + default: + break; + } + } + + ret = 0; + the_end: + tcc_free(symtab); + tcc_free(strtab); + tcc_free(old_to_new_syms); + tcc_free(sm_table); + tcc_free(strsec); + tcc_free(shdr); + return ret; +} + +typedef struct ArchiveHeader { + char ar_name[16]; /* name of this member */ + char ar_date[12]; /* file mtime */ + char ar_uid[6]; /* owner uid; printed as decimal */ + char ar_gid[6]; /* owner gid; printed as decimal */ + char ar_mode[8]; /* file mode, printed as octal */ + char ar_size[10]; /* file size, printed as decimal */ + char ar_fmag[2]; /* should contain ARFMAG */ +} ArchiveHeader; + +static int get_be32(const uint8_t *b) +{ + return b[3] | (b[2] << 8) | (b[1] << 16) | (b[0] << 24); +} + +static long get_be64(const uint8_t *b) +{ + long long ret = get_be32(b); + ret = (ret << 32) | (unsigned)get_be32(b+4); + return (long)ret; +} + +/* load only the objects which resolve undefined symbols */ +static int tcc_load_alacarte(TCCState *s1, int fd, int size, int entrysize) +{ + long i, bound, nsyms, sym_index, off, ret; + uint8_t *data; + const char *ar_names, *p; + const uint8_t *ar_index; + ElfW(Sym) *sym; + + data = tcc_malloc(size); + if (read(fd, data, size) != size) + goto fail; + nsyms = entrysize == 4 ? get_be32(data) : get_be64(data); + ar_index = data + entrysize; + ar_names = (char *) ar_index + nsyms * entrysize; + + do { + bound = 0; + for(p = ar_names, i = 0; i < nsyms; i++, p += strlen(p)+1) { + sym_index = find_elf_sym(symtab_section, p); + if(sym_index) { + sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; + if(sym->st_shndx == SHN_UNDEF) { + off = (entrysize == 4 + ? get_be32(ar_index + i * 4) + : get_be64(ar_index + i * 8)) + + sizeof(ArchiveHeader); + ++bound; + if(tcc_load_object_file(s1, fd, off) < 0) { + fail: + ret = -1; + goto the_end; + } + } + } + } + } while(bound); + ret = 0; + the_end: + tcc_free(data); + return ret; +} + +/* load a '.a' file */ +ST_FUNC int tcc_load_archive(TCCState *s1, int fd) +{ + ArchiveHeader hdr; + char ar_size[11]; + char ar_name[17]; + char magic[8]; + int size, len, i; + unsigned long file_offset; + + /* skip magic which was already checked */ + read(fd, magic, sizeof(magic)); + + for(;;) { + len = read(fd, &hdr, sizeof(hdr)); + if (len == 0) + break; + if (len != sizeof(hdr)) { + tcc_error_noabort("invalid archive"); + return -1; + } + memcpy(ar_size, hdr.ar_size, sizeof(hdr.ar_size)); + ar_size[sizeof(hdr.ar_size)] = '\0'; + size = strtol(ar_size, NULL, 0); + memcpy(ar_name, hdr.ar_name, sizeof(hdr.ar_name)); + for(i = sizeof(hdr.ar_name) - 1; i >= 0; i--) { + if (ar_name[i] != ' ') + break; + } + ar_name[i + 1] = '\0'; + file_offset = lseek(fd, 0, SEEK_CUR); + /* align to even */ + size = (size + 1) & ~1; + if (!strcmp(ar_name, "/")) { + /* coff symbol table : we handle it */ + if(s1->alacarte_link) + return tcc_load_alacarte(s1, fd, size, 4); + } else if (!strcmp(ar_name, "/SYM64/")) { + if(s1->alacarte_link) + return tcc_load_alacarte(s1, fd, size, 8); + } else { + ElfW(Ehdr) ehdr; + if (tcc_object_type(fd, &ehdr) == AFF_BINTYPE_REL) { + if (tcc_load_object_file(s1, fd, file_offset) < 0) + return -1; + } + } + lseek(fd, file_offset + size, SEEK_SET); + } + return 0; +} + +#ifndef TCC_TARGET_PE +/* load a DLL and all referenced DLLs. 'level = 0' means that the DLL + is referenced by the user (so it should be added as DT_NEEDED in + the generated ELF file) */ +ST_FUNC int tcc_load_dll(TCCState *s1, int fd, const char *filename, int level) +{ + ElfW(Ehdr) ehdr; + ElfW(Shdr) *shdr, *sh, *sh1; + int i, j, nb_syms, nb_dts, sym_bind, ret; + ElfW(Sym) *sym, *dynsym; + ElfW(Dyn) *dt, *dynamic; + unsigned char *dynstr; + const char *name, *soname; + DLLReference *dllref; + + read(fd, &ehdr, sizeof(ehdr)); + + /* test CPU specific stuff */ + if (ehdr.e_ident[5] != ELFDATA2LSB || + ehdr.e_machine != EM_TCC_TARGET) { + tcc_error_noabort("bad architecture"); + return -1; + } + + /* read sections */ + shdr = load_data(fd, ehdr.e_shoff, sizeof(ElfW(Shdr)) * ehdr.e_shnum); + + /* load dynamic section and dynamic symbols */ + nb_syms = 0; + nb_dts = 0; + dynamic = NULL; + dynsym = NULL; /* avoid warning */ + dynstr = NULL; /* avoid warning */ + for(i = 0, sh = shdr; i < ehdr.e_shnum; i++, sh++) { + switch(sh->sh_type) { + case SHT_DYNAMIC: + nb_dts = sh->sh_size / sizeof(ElfW(Dyn)); + dynamic = load_data(fd, sh->sh_offset, sh->sh_size); + break; + case SHT_DYNSYM: + nb_syms = sh->sh_size / sizeof(ElfW(Sym)); + dynsym = load_data(fd, sh->sh_offset, sh->sh_size); + sh1 = &shdr[sh->sh_link]; + dynstr = load_data(fd, sh1->sh_offset, sh1->sh_size); + break; + default: + break; + } + } + + /* compute the real library name */ + soname = tcc_basename(filename); + + for(i = 0, dt = dynamic; i < nb_dts; i++, dt++) { + if (dt->d_tag == DT_SONAME) { + soname = (char *) dynstr + dt->d_un.d_val; + } + } + + /* if the dll is already loaded, do not load it */ + for(i = 0; i < s1->nb_loaded_dlls; i++) { + dllref = s1->loaded_dlls[i]; + if (!strcmp(soname, dllref->name)) { + /* but update level if needed */ + if (level < dllref->level) + dllref->level = level; + ret = 0; + goto the_end; + } + } + + /* add the dll and its level */ + dllref = tcc_mallocz(sizeof(DLLReference) + strlen(soname)); + dllref->level = level; + strcpy(dllref->name, soname); + dynarray_add(&s1->loaded_dlls, &s1->nb_loaded_dlls, dllref); + + /* add dynamic symbols in dynsym_section */ + for(i = 1, sym = dynsym + 1; i < nb_syms; i++, sym++) { + sym_bind = ELFW(ST_BIND)(sym->st_info); + if (sym_bind == STB_LOCAL) + continue; + name = (char *) dynstr + sym->st_name; + set_elf_sym(s1->dynsymtab_section, sym->st_value, sym->st_size, + sym->st_info, sym->st_other, sym->st_shndx, name); + } + + /* load all referenced DLLs */ + for(i = 0, dt = dynamic; i < nb_dts; i++, dt++) { + switch(dt->d_tag) { + case DT_NEEDED: + name = (char *) dynstr + dt->d_un.d_val; + for(j = 0; j < s1->nb_loaded_dlls; j++) { + dllref = s1->loaded_dlls[j]; + if (!strcmp(name, dllref->name)) + goto already_loaded; + } + if (tcc_add_dll(s1, name, AFF_REFERENCED_DLL) < 0) { + tcc_error_noabort("referenced dll '%s' not found", name); + ret = -1; + goto the_end; + } + already_loaded: + break; + } + } + ret = 0; + the_end: + tcc_free(dynstr); + tcc_free(dynsym); + tcc_free(dynamic); + tcc_free(shdr); + return ret; +} + +#define LD_TOK_NAME 256 +#define LD_TOK_EOF (-1) + +/* return next ld script token */ +static int ld_next(TCCState *s1, char *name, int name_size) +{ + int c; + char *q; + + redo: + switch(ch) { + case ' ': + case '\t': + case '\f': + case '\v': + case '\r': + case '\n': + inp(); + goto redo; + case '/': + minp(); + if (ch == '*') { + file->buf_ptr = parse_comment(file->buf_ptr); + ch = file->buf_ptr[0]; + goto redo; + } else { + q = name; + *q++ = '/'; + goto parse_name; + } + break; + case '\\': + ch = handle_eob(); + if (ch != '\\') + goto redo; + /* fall through */ + /* case 'a' ... 'z': */ + case 'a': + case 'b': + case 'c': + case 'd': + case 'e': + case 'f': + case 'g': + case 'h': + case 'i': + case 'j': + case 'k': + case 'l': + case 'm': + case 'n': + case 'o': + case 'p': + case 'q': + case 'r': + case 's': + case 't': + case 'u': + case 'v': + case 'w': + case 'x': + case 'y': + case 'z': + /* case 'A' ... 'z': */ + case 'A': + case 'B': + case 'C': + case 'D': + case 'E': + case 'F': + case 'G': + case 'H': + case 'I': + case 'J': + case 'K': + case 'L': + case 'M': + case 'N': + case 'O': + case 'P': + case 'Q': + case 'R': + case 'S': + case 'T': + case 'U': + case 'V': + case 'W': + case 'X': + case 'Y': + case 'Z': + case '_': + case '.': + case '$': + case '~': + q = name; + parse_name: + for(;;) { + if (!((ch >= 'a' && ch <= 'z') || + (ch >= 'A' && ch <= 'Z') || + (ch >= '0' && ch <= '9') || + strchr("/.-_+=$:\\,~", ch))) + break; + if ((q - name) < name_size - 1) { + *q++ = ch; + } + minp(); + } + *q = '\0'; + c = LD_TOK_NAME; + break; + case CH_EOF: + c = LD_TOK_EOF; + break; + default: + c = ch; + inp(); + break; + } + return c; +} + +static int ld_add_file(TCCState *s1, const char filename[]) +{ + if (filename[0] == '/') { + if (CONFIG_SYSROOT[0] == '\0' + && tcc_add_file_internal(s1, filename, AFF_TYPE_BIN) == 0) + return 0; + filename = tcc_basename(filename); + } + return tcc_add_dll(s1, filename, 0); +} + +static inline int new_undef_syms(void) +{ + int ret = 0; + ret = new_undef_sym; + new_undef_sym = 0; + return ret; +} + +static int ld_add_file_list(TCCState *s1, const char *cmd, int as_needed) +{ + char filename[1024], libname[1024]; + int t, group, nblibs = 0, ret = 0; + char **libs = NULL; + + group = !strcmp(cmd, "GROUP"); + if (!as_needed) + new_undef_syms(); + t = ld_next(s1, filename, sizeof(filename)); + if (t != '(') + expect("("); + t = ld_next(s1, filename, sizeof(filename)); + for(;;) { + libname[0] = '\0'; + if (t == LD_TOK_EOF) { + tcc_error_noabort("unexpected end of file"); + ret = -1; + goto lib_parse_error; + } else if (t == ')') { + break; + } else if (t == '-') { + t = ld_next(s1, filename, sizeof(filename)); + if ((t != LD_TOK_NAME) || (filename[0] != 'l')) { + tcc_error_noabort("library name expected"); + ret = -1; + goto lib_parse_error; + } + pstrcpy(libname, sizeof libname, &filename[1]); + if (s1->static_link) { + snprintf(filename, sizeof filename, "lib%s.a", libname); + } else { + snprintf(filename, sizeof filename, "lib%s.so", libname); + } + } else if (t != LD_TOK_NAME) { + tcc_error_noabort("filename expected"); + ret = -1; + goto lib_parse_error; + } + if (!strcmp(filename, "AS_NEEDED")) { + ret = ld_add_file_list(s1, cmd, 1); + if (ret) + goto lib_parse_error; + } else { + /* TODO: Implement AS_NEEDED support. Ignore it for now */ + if (!as_needed) { + ret = ld_add_file(s1, filename); + if (ret) + goto lib_parse_error; + if (group) { + /* Add the filename *and* the libname to avoid future conversions */ + dynarray_add(&libs, &nblibs, tcc_strdup(filename)); + if (libname[0] != '\0') + dynarray_add(&libs, &nblibs, tcc_strdup(libname)); + } + } + } + t = ld_next(s1, filename, sizeof(filename)); + if (t == ',') { + t = ld_next(s1, filename, sizeof(filename)); + } + } + if (group && !as_needed) { + while (new_undef_syms()) { + int i; + + for (i = 0; i < nblibs; i ++) + ld_add_file(s1, libs[i]); + } + } +lib_parse_error: + dynarray_reset(&libs, &nblibs); + return ret; +} + +/* interpret a subset of GNU ldscripts to handle the dummy libc.so + files */ +ST_FUNC int tcc_load_ldscript(TCCState *s1) +{ + char cmd[64]; + char filename[1024]; + int t, ret; + + ch = handle_eob(); + for(;;) { + t = ld_next(s1, cmd, sizeof(cmd)); + if (t == LD_TOK_EOF) + return 0; + else if (t != LD_TOK_NAME) + return -1; + if (!strcmp(cmd, "INPUT") || + !strcmp(cmd, "GROUP")) { + ret = ld_add_file_list(s1, cmd, 0); + if (ret) + return ret; + } else if (!strcmp(cmd, "OUTPUT_FORMAT") || + !strcmp(cmd, "TARGET")) { + /* ignore some commands */ + t = ld_next(s1, cmd, sizeof(cmd)); + if (t != '(') + expect("("); + for(;;) { + t = ld_next(s1, filename, sizeof(filename)); + if (t == LD_TOK_EOF) { + tcc_error_noabort("unexpected end of file"); + return -1; + } else if (t == ')') { + break; + } + } + } else { + return -1; + } + } + return 0; +} +#endif /* !TCC_TARGET_PE */ diff --git a/tinyc/tccgen.c b/tinyc/tccgen.c new file mode 100644 index 000000000..7d554b5b1 --- /dev/null +++ b/tinyc/tccgen.c @@ -0,0 +1,7369 @@ +/* + * TCC - Tiny C Compiler + * + * Copyright (c) 2001-2004 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "tcc.h" + +/********************************************************/ +/* global variables */ + +/* loc : local variable index + ind : output code index + rsym: return symbol + anon_sym: anonymous symbol index +*/ +ST_DATA int rsym, anon_sym, ind, loc; + +ST_DATA Sym *sym_free_first; +ST_DATA void **sym_pools; +ST_DATA int nb_sym_pools; + +ST_DATA Sym *global_stack; +ST_DATA Sym *local_stack; +ST_DATA Sym *define_stack; +ST_DATA Sym *global_label_stack; +ST_DATA Sym *local_label_stack; +static int local_scope; +static int in_sizeof; +static int section_sym; + +ST_DATA int vlas_in_scope; /* number of VLAs that are currently in scope */ +ST_DATA int vla_sp_root_loc; /* vla_sp_loc for SP before any VLAs were pushed */ +ST_DATA int vla_sp_loc; /* Pointer to variable holding location to store stack pointer on the stack when modifying stack pointer */ + +ST_DATA SValue __vstack[1+VSTACK_SIZE], *vtop, *pvtop; + +ST_DATA int const_wanted; /* true if constant wanted */ +ST_DATA int nocode_wanted; /* no code generation wanted */ +#define NODATA_WANTED (nocode_wanted > 0) /* no static data output wanted either */ +#define STATIC_DATA_WANTED (nocode_wanted & 0xC0000000) /* only static data output */ +ST_DATA int global_expr; /* true if compound literals must be allocated globally (used during initializers parsing */ +ST_DATA CType func_vt; /* current function return type (used by return instruction) */ +ST_DATA int func_var; /* true if current function is variadic (used by return instruction) */ +ST_DATA int func_vc; +ST_DATA int last_line_num, last_ind, func_ind; /* debug last line number and pc */ +ST_DATA const char *funcname; +ST_DATA int g_debug; + +ST_DATA CType char_pointer_type, func_old_type, int_type, size_type, ptrdiff_type; + +ST_DATA struct switch_t { + struct case_t { + int64_t v1, v2; + int sym; + } **p; int n; /* list of case ranges */ + int def_sym; /* default symbol */ +} *cur_switch; /* current switch */ + +/* ------------------------------------------------------------------------- */ + +static void gen_cast(CType *type); +static void gen_cast_s(int t); +static inline CType *pointed_type(CType *type); +static int is_compatible_types(CType *type1, CType *type2); +static int parse_btype(CType *type, AttributeDef *ad); +static CType *type_decl(CType *type, AttributeDef *ad, int *v, int td); +static void parse_expr_type(CType *type); +static void init_putv(CType *type, Section *sec, unsigned long c); +static void decl_initializer(CType *type, Section *sec, unsigned long c, int first, int size_only); +static void block(int *bsym, int *csym, int is_expr); +static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, int has_init, int v, int scope); +static void decl(int l); +static int decl0(int l, int is_for_loop_init, Sym *); +static void expr_eq(void); +static void vla_runtime_type_size(CType *type, int *a); +static void vla_sp_restore(void); +static void vla_sp_restore_root(void); +static int is_compatible_unqualified_types(CType *type1, CType *type2); +static inline int64_t expr_const64(void); +static void vpush64(int ty, unsigned long long v); +static void vpush(CType *type); +static int gvtst(int inv, int t); +static void gen_inline_functions(TCCState *s); +static void skip_or_save_block(TokenString **str); +static void gv_dup(void); + +ST_INLN int is_float(int t) +{ + int bt; + bt = t & VT_BTYPE; + return bt == VT_LDOUBLE || bt == VT_DOUBLE || bt == VT_FLOAT || bt == VT_QFLOAT; +} + +/* we use our own 'finite' function to avoid potential problems with + non standard math libs */ +/* XXX: endianness dependent */ +ST_FUNC int ieee_finite(double d) +{ + int p[4]; + memcpy(p, &d, sizeof(double)); + return ((unsigned)((p[1] | 0x800fffff) + 1)) >> 31; +} + +/* compiling intel long double natively */ +#if (defined __i386__ || defined __x86_64__) \ + && (defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64) +# define TCC_IS_NATIVE_387 +#endif + +ST_FUNC void test_lvalue(void) +{ + if (!(vtop->r & VT_LVAL)) + expect("lvalue"); +} + +ST_FUNC void check_vstack(void) +{ + if (pvtop != vtop) + tcc_error("internal compiler error: vstack leak (%d)", vtop - pvtop); +} + +/* ------------------------------------------------------------------------- */ +/* vstack debugging aid */ + +#if 0 +void pv (const char *lbl, int a, int b) +{ + int i; + for (i = a; i < a + b; ++i) { + SValue *p = &vtop[-i]; + printf("%s vtop[-%d] : type.t:%04x r:%04x r2:%04x c.i:%d\n", + lbl, i, p->type.t, p->r, p->r2, (int)p->c.i); + } +} +#endif + +/* ------------------------------------------------------------------------- */ +/* start of translation unit info */ +ST_FUNC void tcc_debug_start(TCCState *s1) +{ + if (s1->do_debug) { + char buf[512]; + + /* file info: full path + filename */ + section_sym = put_elf_sym(symtab_section, 0, 0, + ELFW(ST_INFO)(STB_LOCAL, STT_SECTION), 0, + text_section->sh_num, NULL); + getcwd(buf, sizeof(buf)); +#ifdef _WIN32 + normalize_slashes(buf); +#endif + pstrcat(buf, sizeof(buf), "/"); + put_stabs_r(buf, N_SO, 0, 0, + text_section->data_offset, text_section, section_sym); + put_stabs_r(file->filename, N_SO, 0, 0, + text_section->data_offset, text_section, section_sym); + last_ind = 0; + last_line_num = 0; + } + + /* an elf symbol of type STT_FILE must be put so that STB_LOCAL + symbols can be safely used */ + put_elf_sym(symtab_section, 0, 0, + ELFW(ST_INFO)(STB_LOCAL, STT_FILE), 0, + SHN_ABS, file->filename); +} + +/* put end of translation unit info */ +ST_FUNC void tcc_debug_end(TCCState *s1) +{ + if (!s1->do_debug) + return; + put_stabs_r(NULL, N_SO, 0, 0, + text_section->data_offset, text_section, section_sym); + +} + +/* generate line number info */ +ST_FUNC void tcc_debug_line(TCCState *s1) +{ + if (!s1->do_debug) + return; + if ((last_line_num != file->line_num || last_ind != ind)) { + put_stabn(N_SLINE, 0, file->line_num, ind - func_ind); + last_ind = ind; + last_line_num = file->line_num; + } +} + +/* put function symbol */ +ST_FUNC void tcc_debug_funcstart(TCCState *s1, Sym *sym) +{ + char buf[512]; + + if (!s1->do_debug) + return; + + /* stabs info */ + /* XXX: we put here a dummy type */ + snprintf(buf, sizeof(buf), "%s:%c1", + funcname, sym->type.t & VT_STATIC ? 'f' : 'F'); + put_stabs_r(buf, N_FUN, 0, file->line_num, 0, + cur_text_section, sym->c); + /* //gr gdb wants a line at the function */ + put_stabn(N_SLINE, 0, file->line_num, 0); + + last_ind = 0; + last_line_num = 0; +} + +/* put function size */ +ST_FUNC void tcc_debug_funcend(TCCState *s1, int size) +{ + if (!s1->do_debug) + return; + put_stabn(N_FUN, 0, 0, size); +} + +/* ------------------------------------------------------------------------- */ +ST_FUNC int tccgen_compile(TCCState *s1) +{ + cur_text_section = NULL; + funcname = ""; + anon_sym = SYM_FIRST_ANOM; + section_sym = 0; + const_wanted = 0; + nocode_wanted = 0x80000000; + + /* define some often used types */ + int_type.t = VT_INT; + char_pointer_type.t = VT_BYTE; + mk_pointer(&char_pointer_type); +#if PTR_SIZE == 4 + size_type.t = VT_INT | VT_UNSIGNED; + ptrdiff_type.t = VT_INT; +#elif LONG_SIZE == 4 + size_type.t = VT_LLONG | VT_UNSIGNED; + ptrdiff_type.t = VT_LLONG; +#else + size_type.t = VT_LONG | VT_LLONG | VT_UNSIGNED; + ptrdiff_type.t = VT_LONG | VT_LLONG; +#endif + func_old_type.t = VT_FUNC; + func_old_type.ref = sym_push(SYM_FIELD, &int_type, 0, 0); + func_old_type.ref->f.func_call = FUNC_CDECL; + func_old_type.ref->f.func_type = FUNC_OLD; + + tcc_debug_start(s1); + +#ifdef TCC_TARGET_ARM + arm_init(s1); +#endif + +#ifdef INC_DEBUG + printf("%s: **** new file\n", file->filename); +#endif + + parse_flags = PARSE_FLAG_PREPROCESS | PARSE_FLAG_TOK_NUM | PARSE_FLAG_TOK_STR; + next(); + decl(VT_CONST); + gen_inline_functions(s1); + check_vstack(); + /* end of translation unit info */ + tcc_debug_end(s1); + return 0; +} + +/* ------------------------------------------------------------------------- */ +/* apply storage attributes to Elf symbol */ + +static void update_storage(Sym *sym) +{ + ElfW(Sym) *esym; + if (0 == sym->c) + return; + esym = &((ElfW(Sym) *)symtab_section->data)[sym->c]; + if (sym->a.visibility) + esym->st_other = (esym->st_other & ~ELFW(ST_VISIBILITY)(-1)) + | sym->a.visibility; + if (sym->a.weak) + esym->st_info = ELFW(ST_INFO)(STB_WEAK, ELFW(ST_TYPE)(esym->st_info)); +#ifdef TCC_TARGET_PE + if (sym->a.dllimport) + esym->st_other |= ST_PE_IMPORT; + if (sym->a.dllexport) + esym->st_other |= ST_PE_EXPORT; +#endif +#if 0 + printf("storage %s: vis=%d weak=%d exp=%d imp=%d\n", + get_tok_str(sym->v, NULL), + sym->a.visibility, + sym->a.weak, + sym->a.dllexport, + sym->a.dllimport + ); +#endif +} + +/* ------------------------------------------------------------------------- */ +/* update sym->c so that it points to an external symbol in section + 'section' with value 'value' */ + +ST_FUNC void put_extern_sym2(Sym *sym, Section *section, + addr_t value, unsigned long size, + int can_add_underscore) +{ + int sym_type, sym_bind, sh_num, info, other, t; + ElfW(Sym) *esym; + const char *name; + char buf1[256]; +#ifdef CONFIG_TCC_BCHECK + char buf[32]; +#endif + + if (section == NULL) + sh_num = SHN_UNDEF; + else if (section == SECTION_ABS) + sh_num = SHN_ABS; + else + sh_num = section->sh_num; + + if (!sym->c) { + name = get_tok_str(sym->v, NULL); +#ifdef CONFIG_TCC_BCHECK + if (tcc_state->do_bounds_check) { + /* XXX: avoid doing that for statics ? */ + /* if bound checking is activated, we change some function + names by adding the "__bound" prefix */ + switch(sym->v) { +#ifdef TCC_TARGET_PE + /* XXX: we rely only on malloc hooks */ + case TOK_malloc: + case TOK_free: + case TOK_realloc: + case TOK_memalign: + case TOK_calloc: +#endif + case TOK_memcpy: + case TOK_memmove: + case TOK_memset: + case TOK_strlen: + case TOK_strcpy: + case TOK_alloca: + strcpy(buf, "__bound_"); + strcat(buf, name); + name = buf; + break; + } + } +#endif + t = sym->type.t; + if ((t & VT_BTYPE) == VT_FUNC) { + sym_type = STT_FUNC; + } else if ((t & VT_BTYPE) == VT_VOID) { + sym_type = STT_NOTYPE; + } else { + sym_type = STT_OBJECT; + } + if (t & VT_STATIC) + sym_bind = STB_LOCAL; + else + sym_bind = STB_GLOBAL; + other = 0; +#ifdef TCC_TARGET_PE + if (sym_type == STT_FUNC && sym->type.ref) { + Sym *ref = sym->type.ref; + if (ref->f.func_call == FUNC_STDCALL && can_add_underscore) { + sprintf(buf1, "_%s@%d", name, ref->f.func_args * PTR_SIZE); + name = buf1; + other |= ST_PE_STDCALL; + can_add_underscore = 0; + } + } +#endif + if (tcc_state->leading_underscore && can_add_underscore) { + buf1[0] = '_'; + pstrcpy(buf1 + 1, sizeof(buf1) - 1, name); + name = buf1; + } + if (sym->asm_label) + name = get_tok_str(sym->asm_label, NULL); + info = ELFW(ST_INFO)(sym_bind, sym_type); + sym->c = set_elf_sym(symtab_section, value, size, info, other, sh_num, name); + } else { + esym = &((ElfW(Sym) *)symtab_section->data)[sym->c]; + esym->st_value = value; + esym->st_size = size; + esym->st_shndx = sh_num; + } + update_storage(sym); +} + +ST_FUNC void put_extern_sym(Sym *sym, Section *section, + addr_t value, unsigned long size) +{ + put_extern_sym2(sym, section, value, size, 1); +} + +/* add a new relocation entry to symbol 'sym' in section 's' */ +ST_FUNC void greloca(Section *s, Sym *sym, unsigned long offset, int type, + addr_t addend) +{ + int c = 0; + + if (nocode_wanted && s == cur_text_section) + return; + + if (sym) { + if (0 == sym->c) + put_extern_sym(sym, NULL, 0, 0); + c = sym->c; + } + + /* now we can add ELF relocation info */ + put_elf_reloca(symtab_section, s, offset, type, c, addend); +} + +#if PTR_SIZE == 4 +ST_FUNC void greloc(Section *s, Sym *sym, unsigned long offset, int type) +{ + greloca(s, sym, offset, type, 0); +} +#endif + +/* ------------------------------------------------------------------------- */ +/* symbol allocator */ +static Sym *__sym_malloc(void) +{ + Sym *sym_pool, *sym, *last_sym; + int i; + + sym_pool = tcc_malloc(SYM_POOL_NB * sizeof(Sym)); + dynarray_add(&sym_pools, &nb_sym_pools, sym_pool); + + last_sym = sym_free_first; + sym = sym_pool; + for(i = 0; i < SYM_POOL_NB; i++) { + sym->next = last_sym; + last_sym = sym; + sym++; + } + sym_free_first = last_sym; + return last_sym; +} + +static inline Sym *sym_malloc(void) +{ + Sym *sym; +#ifndef SYM_DEBUG + sym = sym_free_first; + if (!sym) + sym = __sym_malloc(); + sym_free_first = sym->next; + return sym; +#else + sym = tcc_malloc(sizeof(Sym)); + return sym; +#endif +} + +ST_INLN void sym_free(Sym *sym) +{ +#ifndef SYM_DEBUG + sym->next = sym_free_first; + sym_free_first = sym; +#else + tcc_free(sym); +#endif +} + +/* push, without hashing */ +ST_FUNC Sym *sym_push2(Sym **ps, int v, int t, int c) +{ + Sym *s; + + s = sym_malloc(); + memset(s, 0, sizeof *s); + s->v = v; + s->type.t = t; + s->c = c; + /* add in stack */ + s->prev = *ps; + *ps = s; + return s; +} + +/* find a symbol and return its associated structure. 's' is the top + of the symbol stack */ +ST_FUNC Sym *sym_find2(Sym *s, int v) +{ + while (s) { + if (s->v == v) + return s; + else if (s->v == -1) + return NULL; + s = s->prev; + } + return NULL; +} + +/* structure lookup */ +ST_INLN Sym *struct_find(int v) +{ + v -= TOK_IDENT; + if ((unsigned)v >= (unsigned)(tok_ident - TOK_IDENT)) + return NULL; + return table_ident[v]->sym_struct; +} + +/* find an identifier */ +ST_INLN Sym *sym_find(int v) +{ + v -= TOK_IDENT; + if ((unsigned)v >= (unsigned)(tok_ident - TOK_IDENT)) + return NULL; + return table_ident[v]->sym_identifier; +} + +/* push a given symbol on the symbol stack */ +ST_FUNC Sym *sym_push(int v, CType *type, int r, int c) +{ + Sym *s, **ps; + TokenSym *ts; + + if (local_stack) + ps = &local_stack; + else + ps = &global_stack; + s = sym_push2(ps, v, type->t, c); + s->type.ref = type->ref; + s->r = r; + /* don't record fields or anonymous symbols */ + /* XXX: simplify */ + if (!(v & SYM_FIELD) && (v & ~SYM_STRUCT) < SYM_FIRST_ANOM) { + /* record symbol in token array */ + ts = table_ident[(v & ~SYM_STRUCT) - TOK_IDENT]; + if (v & SYM_STRUCT) + ps = &ts->sym_struct; + else + ps = &ts->sym_identifier; + s->prev_tok = *ps; + *ps = s; + s->sym_scope = local_scope; + if (s->prev_tok && s->prev_tok->sym_scope == s->sym_scope) + tcc_error("redeclaration of '%s'", + get_tok_str(v & ~SYM_STRUCT, NULL)); + } + return s; +} + +/* push a global identifier */ +ST_FUNC Sym *global_identifier_push(int v, int t, int c) +{ + Sym *s, **ps; + s = sym_push2(&global_stack, v, t, c); + /* don't record anonymous symbol */ + if (v < SYM_FIRST_ANOM) { + ps = &table_ident[v - TOK_IDENT]->sym_identifier; + /* modify the top most local identifier, so that + sym_identifier will point to 's' when popped */ + while (*ps != NULL) + ps = &(*ps)->prev_tok; + s->prev_tok = NULL; + *ps = s; + } + return s; +} + +/* pop symbols until top reaches 'b'. If KEEP is non-zero don't really + pop them yet from the list, but do remove them from the token array. */ +ST_FUNC void sym_pop(Sym **ptop, Sym *b, int keep) +{ + Sym *s, *ss, **ps; + TokenSym *ts; + int v; + + s = *ptop; + while(s != b) { + ss = s->prev; + v = s->v; + /* remove symbol in token array */ + /* XXX: simplify */ + if (!(v & SYM_FIELD) && (v & ~SYM_STRUCT) < SYM_FIRST_ANOM) { + ts = table_ident[(v & ~SYM_STRUCT) - TOK_IDENT]; + if (v & SYM_STRUCT) + ps = &ts->sym_struct; + else + ps = &ts->sym_identifier; + *ps = s->prev_tok; + } + if (!keep) + sym_free(s); + s = ss; + } + if (!keep) + *ptop = b; +} + +/* ------------------------------------------------------------------------- */ + +static void vsetc(CType *type, int r, CValue *vc) +{ + int v; + + if (vtop >= vstack + (VSTACK_SIZE - 1)) + tcc_error("memory full (vstack)"); + /* cannot let cpu flags if other instruction are generated. Also + avoid leaving VT_JMP anywhere except on the top of the stack + because it would complicate the code generator. + + Don't do this when nocode_wanted. vtop might come from + !nocode_wanted regions (see 88_codeopt.c) and transforming + it to a register without actually generating code is wrong + as their value might still be used for real. All values + we push under nocode_wanted will eventually be popped + again, so that the VT_CMP/VT_JMP value will be in vtop + when code is unsuppressed again. + + Same logic below in vswap(); */ + if (vtop >= vstack && !nocode_wanted) { + v = vtop->r & VT_VALMASK; + if (v == VT_CMP || (v & ~1) == VT_JMP) + gv(RC_INT); + } + + vtop++; + vtop->type = *type; + vtop->r = r; + vtop->r2 = VT_CONST; + vtop->c = *vc; + vtop->sym = NULL; +} + +ST_FUNC void vswap(void) +{ + SValue tmp; + /* cannot vswap cpu flags. See comment at vsetc() above */ + if (vtop >= vstack && !nocode_wanted) { + int v = vtop->r & VT_VALMASK; + if (v == VT_CMP || (v & ~1) == VT_JMP) + gv(RC_INT); + } + tmp = vtop[0]; + vtop[0] = vtop[-1]; + vtop[-1] = tmp; +} + +/* pop stack value */ +ST_FUNC void vpop(void) +{ + int v; + v = vtop->r & VT_VALMASK; +#if defined(TCC_TARGET_I386) || defined(TCC_TARGET_X86_64) + /* for x86, we need to pop the FP stack */ + if (v == TREG_ST0) { + o(0xd8dd); /* fstp %st(0) */ + } else +#endif + if (v == VT_JMP || v == VT_JMPI) { + /* need to put correct jump if && or || without test */ + gsym(vtop->c.i); + } + vtop--; +} + +/* push constant of type "type" with useless value */ +ST_FUNC void vpush(CType *type) +{ + vset(type, VT_CONST, 0); +} + +/* push integer constant */ +ST_FUNC void vpushi(int v) +{ + CValue cval; + cval.i = v; + vsetc(&int_type, VT_CONST, &cval); +} + +/* push a pointer sized constant */ +static void vpushs(addr_t v) +{ + CValue cval; + cval.i = v; + vsetc(&size_type, VT_CONST, &cval); +} + +/* push arbitrary 64bit constant */ +ST_FUNC void vpush64(int ty, unsigned long long v) +{ + CValue cval; + CType ctype; + ctype.t = ty; + ctype.ref = NULL; + cval.i = v; + vsetc(&ctype, VT_CONST, &cval); +} + +/* push long long constant */ +static inline void vpushll(long long v) +{ + vpush64(VT_LLONG, v); +} + +ST_FUNC void vset(CType *type, int r, int v) +{ + CValue cval; + + cval.i = v; + vsetc(type, r, &cval); +} + +static void vseti(int r, int v) +{ + CType type; + type.t = VT_INT; + type.ref = NULL; + vset(&type, r, v); +} + +ST_FUNC void vpushv(SValue *v) +{ + if (vtop >= vstack + (VSTACK_SIZE - 1)) + tcc_error("memory full (vstack)"); + vtop++; + *vtop = *v; +} + +static void vdup(void) +{ + vpushv(vtop); +} + +/* rotate n first stack elements to the bottom + I1 ... In -> I2 ... In I1 [top is right] +*/ +ST_FUNC void vrotb(int n) +{ + int i; + SValue tmp; + + tmp = vtop[-n + 1]; + for(i=-n+1;i!=0;i++) + vtop[i] = vtop[i+1]; + vtop[0] = tmp; +} + +/* rotate the n elements before entry e towards the top + I1 ... In ... -> In I1 ... I(n-1) ... [top is right] + */ +ST_FUNC void vrote(SValue *e, int n) +{ + int i; + SValue tmp; + + tmp = *e; + for(i = 0;i < n - 1; i++) + e[-i] = e[-i - 1]; + e[-n + 1] = tmp; +} + +/* rotate n first stack elements to the top + I1 ... In -> In I1 ... I(n-1) [top is right] + */ +ST_FUNC void vrott(int n) +{ + vrote(vtop, n); +} + +/* push a symbol value of TYPE */ +static inline void vpushsym(CType *type, Sym *sym) +{ + CValue cval; + cval.i = 0; + vsetc(type, VT_CONST | VT_SYM, &cval); + vtop->sym = sym; +} + +/* Return a static symbol pointing to a section */ +ST_FUNC Sym *get_sym_ref(CType *type, Section *sec, unsigned long offset, unsigned long size) +{ + int v; + Sym *sym; + + v = anon_sym++; + sym = global_identifier_push(v, type->t | VT_STATIC, 0); + sym->type.ref = type->ref; + sym->r = VT_CONST | VT_SYM; + put_extern_sym(sym, sec, offset, size); + return sym; +} + +/* push a reference to a section offset by adding a dummy symbol */ +static void vpush_ref(CType *type, Section *sec, unsigned long offset, unsigned long size) +{ + vpushsym(type, get_sym_ref(type, sec, offset, size)); +} + +/* define a new external reference to a symbol 'v' of type 'u' */ +ST_FUNC Sym *external_global_sym(int v, CType *type, int r) +{ + Sym *s; + + s = sym_find(v); + if (!s) { + /* push forward reference */ + s = global_identifier_push(v, type->t | VT_EXTERN, 0); + s->type.ref = type->ref; + s->r = r | VT_CONST | VT_SYM; + } + return s; +} + +/* Merge some storage attributes. */ +static void patch_storage(Sym *sym, AttributeDef *ad, CType *type) +{ + if (type && !is_compatible_types(&sym->type, type)) + tcc_error("incompatible types for redefinition of '%s'", + get_tok_str(sym->v, NULL)); +#ifdef TCC_TARGET_PE + if (sym->a.dllimport != ad->a.dllimport) + tcc_error("incompatible dll linkage for redefinition of '%s'", + get_tok_str(sym->v, NULL)); +#endif + sym->a.dllexport |= ad->a.dllexport; + sym->a.weak |= ad->a.weak; + if (ad->a.visibility) { + int vis = sym->a.visibility; + int vis2 = ad->a.visibility; + if (vis == STV_DEFAULT) + vis = vis2; + else if (vis2 != STV_DEFAULT) + vis = (vis < vis2) ? vis : vis2; + sym->a.visibility = vis; + } + if (ad->a.aligned) + sym->a.aligned = ad->a.aligned; + if (ad->asm_label) + sym->asm_label = ad->asm_label; + update_storage(sym); +} + +/* define a new external reference to a symbol 'v' */ +static Sym *external_sym(int v, CType *type, int r, AttributeDef *ad) +{ + Sym *s; + s = sym_find(v); + if (!s) { + /* push forward reference */ + s = sym_push(v, type, r | VT_CONST | VT_SYM, 0); + s->type.t |= VT_EXTERN; + s->a = ad->a; + s->sym_scope = 0; + } else { + if (s->type.ref == func_old_type.ref) { + s->type.ref = type->ref; + s->r = r | VT_CONST | VT_SYM; + s->type.t |= VT_EXTERN; + } + patch_storage(s, ad, type); + } + return s; +} + +/* push a reference to global symbol v */ +ST_FUNC void vpush_global_sym(CType *type, int v) +{ + vpushsym(type, external_global_sym(v, type, 0)); +} + +/* save registers up to (vtop - n) stack entry */ +ST_FUNC void save_regs(int n) +{ + SValue *p, *p1; + for(p = vstack, p1 = vtop - n; p <= p1; p++) + save_reg(p->r); +} + +/* save r to the memory stack, and mark it as being free */ +ST_FUNC void save_reg(int r) +{ + save_reg_upstack(r, 0); +} + +/* save r to the memory stack, and mark it as being free, + if seen up to (vtop - n) stack entry */ +ST_FUNC void save_reg_upstack(int r, int n) +{ + int l, saved, size, align; + SValue *p, *p1, sv; + CType *type; + + if ((r &= VT_VALMASK) >= VT_CONST) + return; + if (nocode_wanted) + return; + + /* modify all stack values */ + saved = 0; + l = 0; + for(p = vstack, p1 = vtop - n; p <= p1; p++) { + if ((p->r & VT_VALMASK) == r || + ((p->type.t & VT_BTYPE) == VT_LLONG && (p->r2 & VT_VALMASK) == r)) { + /* must save value on stack if not already done */ + if (!saved) { + /* NOTE: must reload 'r' because r might be equal to r2 */ + r = p->r & VT_VALMASK; + /* store register in the stack */ + type = &p->type; + if ((p->r & VT_LVAL) || + (!is_float(type->t) && (type->t & VT_BTYPE) != VT_LLONG)) +#if PTR_SIZE == 8 + type = &char_pointer_type; +#else + type = &int_type; +#endif + size = type_size(type, &align); + loc = (loc - size) & -align; + sv.type.t = type->t; + sv.r = VT_LOCAL | VT_LVAL; + sv.c.i = loc; + store(r, &sv); +#if defined(TCC_TARGET_I386) || defined(TCC_TARGET_X86_64) + /* x86 specific: need to pop fp register ST0 if saved */ + if (r == TREG_ST0) { + o(0xd8dd); /* fstp %st(0) */ + } +#endif +#if PTR_SIZE == 4 + /* special long long case */ + if ((type->t & VT_BTYPE) == VT_LLONG) { + sv.c.i += 4; + store(p->r2, &sv); + } +#endif + l = loc; + saved = 1; + } + /* mark that stack entry as being saved on the stack */ + if (p->r & VT_LVAL) { + /* also clear the bounded flag because the + relocation address of the function was stored in + p->c.i */ + p->r = (p->r & ~(VT_VALMASK | VT_BOUNDED)) | VT_LLOCAL; + } else { + p->r = lvalue_type(p->type.t) | VT_LOCAL; + } + p->r2 = VT_CONST; + p->c.i = l; + } + } +} + +#ifdef TCC_TARGET_ARM +/* find a register of class 'rc2' with at most one reference on stack. + * If none, call get_reg(rc) */ +ST_FUNC int get_reg_ex(int rc, int rc2) +{ + int r; + SValue *p; + + for(r=0;rr & VT_VALMASK) == r || + (p->r2 & VT_VALMASK) == r) + n++; + } + if (n <= 1) + return r; + } + } + return get_reg(rc); +} +#endif + +/* find a free register of class 'rc'. If none, save one register */ +ST_FUNC int get_reg(int rc) +{ + int r; + SValue *p; + + /* find a free register */ + for(r=0;rr & VT_VALMASK) == r || + (p->r2 & VT_VALMASK) == r) + goto notfound; + } + return r; + } + notfound: ; + } + + /* no register left : free the first one on the stack (VERY + IMPORTANT to start from the bottom to ensure that we don't + spill registers used in gen_opi()) */ + for(p=vstack;p<=vtop;p++) { + /* look at second register (if long long) */ + r = p->r2 & VT_VALMASK; + if (r < VT_CONST && (reg_classes[r] & rc)) + goto save_found; + r = p->r & VT_VALMASK; + if (r < VT_CONST && (reg_classes[r] & rc)) { + save_found: + save_reg(r); + return r; + } + } + /* Should never comes here */ + return -1; +} + +/* move register 's' (of type 't') to 'r', and flush previous value of r to memory + if needed */ +static void move_reg(int r, int s, int t) +{ + SValue sv; + + if (r != s) { + save_reg(r); + sv.type.t = t; + sv.type.ref = NULL; + sv.r = s; + sv.c.i = 0; + load(r, &sv); + } +} + +/* get address of vtop (vtop MUST BE an lvalue) */ +ST_FUNC void gaddrof(void) +{ + vtop->r &= ~VT_LVAL; + /* tricky: if saved lvalue, then we can go back to lvalue */ + if ((vtop->r & VT_VALMASK) == VT_LLOCAL) + vtop->r = (vtop->r & ~(VT_VALMASK | VT_LVAL_TYPE)) | VT_LOCAL | VT_LVAL; + + +} + +#ifdef CONFIG_TCC_BCHECK +/* generate lvalue bound code */ +static void gbound(void) +{ + int lval_type; + CType type1; + + vtop->r &= ~VT_MUSTBOUND; + /* if lvalue, then use checking code before dereferencing */ + if (vtop->r & VT_LVAL) { + /* if not VT_BOUNDED value, then make one */ + if (!(vtop->r & VT_BOUNDED)) { + lval_type = vtop->r & (VT_LVAL_TYPE | VT_LVAL); + /* must save type because we must set it to int to get pointer */ + type1 = vtop->type; + vtop->type.t = VT_PTR; + gaddrof(); + vpushi(0); + gen_bounded_ptr_add(); + vtop->r |= lval_type; + vtop->type = type1; + } + /* then check for dereferencing */ + gen_bounded_ptr_deref(); + } +} +#endif + +static void incr_bf_adr(int o) +{ + vtop->type = char_pointer_type; + gaddrof(); + vpushi(o); + gen_op('+'); + vtop->type.t = (vtop->type.t & ~(VT_BTYPE|VT_DEFSIGN)) + | (VT_BYTE|VT_UNSIGNED); + vtop->r = (vtop->r & ~VT_LVAL_TYPE) + | (VT_LVAL_BYTE|VT_LVAL_UNSIGNED|VT_LVAL); +} + +/* single-byte load mode for packed or otherwise unaligned bitfields */ +static void load_packed_bf(CType *type, int bit_pos, int bit_size) +{ + int n, o, bits; + save_reg_upstack(vtop->r, 1); + vpush64(type->t & VT_BTYPE, 0); // B X + bits = 0, o = bit_pos >> 3, bit_pos &= 7; + do { + vswap(); // X B + incr_bf_adr(o); + vdup(); // X B B + n = 8 - bit_pos; + if (n > bit_size) + n = bit_size; + if (bit_pos) + vpushi(bit_pos), gen_op(TOK_SHR), bit_pos = 0; // X B Y + if (n < 8) + vpushi((1 << n) - 1), gen_op('&'); + gen_cast(type); + if (bits) + vpushi(bits), gen_op(TOK_SHL); + vrotb(3); // B Y X + gen_op('|'); // B X + bits += n, bit_size -= n, o = 1; + } while (bit_size); + vswap(), vpop(); + if (!(type->t & VT_UNSIGNED)) { + n = ((type->t & VT_BTYPE) == VT_LLONG ? 64 : 32) - bits; + vpushi(n), gen_op(TOK_SHL); + vpushi(n), gen_op(TOK_SAR); + } +} + +/* single-byte store mode for packed or otherwise unaligned bitfields */ +static void store_packed_bf(int bit_pos, int bit_size) +{ + int bits, n, o, m, c; + + c = (vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST; + vswap(); // X B + save_reg_upstack(vtop->r, 1); + bits = 0, o = bit_pos >> 3, bit_pos &= 7; + do { + incr_bf_adr(o); // X B + vswap(); //B X + c ? vdup() : gv_dup(); // B V X + vrott(3); // X B V + if (bits) + vpushi(bits), gen_op(TOK_SHR); + if (bit_pos) + vpushi(bit_pos), gen_op(TOK_SHL); + n = 8 - bit_pos; + if (n > bit_size) + n = bit_size; + if (n < 8) { + m = ((1 << n) - 1) << bit_pos; + vpushi(m), gen_op('&'); // X B V1 + vpushv(vtop-1); // X B V1 B + vpushi(m & 0x80 ? ~m & 0x7f : ~m); + gen_op('&'); // X B V1 B1 + gen_op('|'); // X B V2 + } + vdup(), vtop[-1] = vtop[-2]; // X B B V2 + vstore(), vpop(); // X B + bits += n, bit_size -= n, bit_pos = 0, o = 1; + } while (bit_size); + vpop(), vpop(); +} + +static int adjust_bf(SValue *sv, int bit_pos, int bit_size) +{ + int t; + if (0 == sv->type.ref) + return 0; + t = sv->type.ref->auxtype; + if (t != -1 && t != VT_STRUCT) { + sv->type.t = (sv->type.t & ~VT_BTYPE) | t; + sv->r = (sv->r & ~VT_LVAL_TYPE) | lvalue_type(sv->type.t); + } + return t; +} + +/* store vtop a register belonging to class 'rc'. lvalues are + converted to values. Cannot be used if cannot be converted to + register value (such as structures). */ +ST_FUNC int gv(int rc) +{ + int r, bit_pos, bit_size, size, align, rc2; + + /* NOTE: get_reg can modify vstack[] */ + if (vtop->type.t & VT_BITFIELD) { + CType type; + + bit_pos = BIT_POS(vtop->type.t); + bit_size = BIT_SIZE(vtop->type.t); + /* remove bit field info to avoid loops */ + vtop->type.t &= ~VT_STRUCT_MASK; + + type.ref = NULL; + type.t = vtop->type.t & VT_UNSIGNED; + if ((vtop->type.t & VT_BTYPE) == VT_BOOL) + type.t |= VT_UNSIGNED; + + r = adjust_bf(vtop, bit_pos, bit_size); + + if ((vtop->type.t & VT_BTYPE) == VT_LLONG) + type.t |= VT_LLONG; + else + type.t |= VT_INT; + + if (r == VT_STRUCT) { + load_packed_bf(&type, bit_pos, bit_size); + } else { + int bits = (type.t & VT_BTYPE) == VT_LLONG ? 64 : 32; + /* cast to int to propagate signedness in following ops */ + gen_cast(&type); + /* generate shifts */ + vpushi(bits - (bit_pos + bit_size)); + gen_op(TOK_SHL); + vpushi(bits - bit_size); + /* NOTE: transformed to SHR if unsigned */ + gen_op(TOK_SAR); + } + r = gv(rc); + } else { + if (is_float(vtop->type.t) && + (vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST) { + unsigned long offset; + /* CPUs usually cannot use float constants, so we store them + generically in data segment */ + size = type_size(&vtop->type, &align); + if (NODATA_WANTED) + size = 0, align = 1; + offset = section_add(data_section, size, align); + vpush_ref(&vtop->type, data_section, offset, size); + vswap(); + init_putv(&vtop->type, data_section, offset); + vtop->r |= VT_LVAL; + } +#ifdef CONFIG_TCC_BCHECK + if (vtop->r & VT_MUSTBOUND) + gbound(); +#endif + + r = vtop->r & VT_VALMASK; + rc2 = (rc & RC_FLOAT) ? RC_FLOAT : RC_INT; +#ifndef TCC_TARGET_ARM64 + if (rc == RC_IRET) + rc2 = RC_LRET; +#ifdef TCC_TARGET_X86_64 + else if (rc == RC_FRET) + rc2 = RC_QRET; +#endif +#endif + /* need to reload if: + - constant + - lvalue (need to dereference pointer) + - already a register, but not in the right class */ + if (r >= VT_CONST + || (vtop->r & VT_LVAL) + || !(reg_classes[r] & rc) +#if PTR_SIZE == 8 + || ((vtop->type.t & VT_BTYPE) == VT_QLONG && !(reg_classes[vtop->r2] & rc2)) + || ((vtop->type.t & VT_BTYPE) == VT_QFLOAT && !(reg_classes[vtop->r2] & rc2)) +#else + || ((vtop->type.t & VT_BTYPE) == VT_LLONG && !(reg_classes[vtop->r2] & rc2)) +#endif + ) + { + r = get_reg(rc); +#if PTR_SIZE == 8 + if (((vtop->type.t & VT_BTYPE) == VT_QLONG) || ((vtop->type.t & VT_BTYPE) == VT_QFLOAT)) { + int addr_type = VT_LLONG, load_size = 8, load_type = ((vtop->type.t & VT_BTYPE) == VT_QLONG) ? VT_LLONG : VT_DOUBLE; +#else + if ((vtop->type.t & VT_BTYPE) == VT_LLONG) { + int addr_type = VT_INT, load_size = 4, load_type = VT_INT; + unsigned long long ll; +#endif + int r2, original_type; + original_type = vtop->type.t; + /* two register type load : expand to two words + temporarily */ +#if PTR_SIZE == 4 + if ((vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST) { + /* load constant */ + ll = vtop->c.i; + vtop->c.i = ll; /* first word */ + load(r, vtop); + vtop->r = r; /* save register value */ + vpushi(ll >> 32); /* second word */ + } else +#endif + if (vtop->r & VT_LVAL) { + /* We do not want to modifier the long long + pointer here, so the safest (and less + efficient) is to save all the other registers + in the stack. XXX: totally inefficient. */ + #if 0 + save_regs(1); + #else + /* lvalue_save: save only if used further down the stack */ + save_reg_upstack(vtop->r, 1); + #endif + /* load from memory */ + vtop->type.t = load_type; + load(r, vtop); + vdup(); + vtop[-1].r = r; /* save register value */ + /* increment pointer to get second word */ + vtop->type.t = addr_type; + gaddrof(); + vpushi(load_size); + gen_op('+'); + vtop->r |= VT_LVAL; + vtop->type.t = load_type; + } else { + /* move registers */ + load(r, vtop); + vdup(); + vtop[-1].r = r; /* save register value */ + vtop->r = vtop[-1].r2; + } + /* Allocate second register. Here we rely on the fact that + get_reg() tries first to free r2 of an SValue. */ + r2 = get_reg(rc2); + load(r2, vtop); + vpop(); + /* write second register */ + vtop->r2 = r2; + vtop->type.t = original_type; + } else if ((vtop->r & VT_LVAL) && !is_float(vtop->type.t)) { + int t1, t; + /* lvalue of scalar type : need to use lvalue type + because of possible cast */ + t = vtop->type.t; + t1 = t; + /* compute memory access type */ + if (vtop->r & VT_LVAL_BYTE) + t = VT_BYTE; + else if (vtop->r & VT_LVAL_SHORT) + t = VT_SHORT; + if (vtop->r & VT_LVAL_UNSIGNED) + t |= VT_UNSIGNED; + vtop->type.t = t; + load(r, vtop); + /* restore wanted type */ + vtop->type.t = t1; + } else { + /* one register type load */ + load(r, vtop); + } + } + vtop->r = r; +#ifdef TCC_TARGET_C67 + /* uses register pairs for doubles */ + if ((vtop->type.t & VT_BTYPE) == VT_DOUBLE) + vtop->r2 = r+1; +#endif + } + return r; +} + +/* generate vtop[-1] and vtop[0] in resp. classes rc1 and rc2 */ +ST_FUNC void gv2(int rc1, int rc2) +{ + int v; + + /* generate more generic register first. But VT_JMP or VT_CMP + values must be generated first in all cases to avoid possible + reload errors */ + v = vtop[0].r & VT_VALMASK; + if (v != VT_CMP && (v & ~1) != VT_JMP && rc1 <= rc2) { + vswap(); + gv(rc1); + vswap(); + gv(rc2); + /* test if reload is needed for first register */ + if ((vtop[-1].r & VT_VALMASK) >= VT_CONST) { + vswap(); + gv(rc1); + vswap(); + } + } else { + gv(rc2); + vswap(); + gv(rc1); + vswap(); + /* test if reload is needed for first register */ + if ((vtop[0].r & VT_VALMASK) >= VT_CONST) { + gv(rc2); + } + } +} + +#ifndef TCC_TARGET_ARM64 +/* wrapper around RC_FRET to return a register by type */ +static int rc_fret(int t) +{ +#ifdef TCC_TARGET_X86_64 + if (t == VT_LDOUBLE) { + return RC_ST0; + } +#endif + return RC_FRET; +} +#endif + +/* wrapper around REG_FRET to return a register by type */ +static int reg_fret(int t) +{ +#ifdef TCC_TARGET_X86_64 + if (t == VT_LDOUBLE) { + return TREG_ST0; + } +#endif + return REG_FRET; +} + +#if PTR_SIZE == 4 +/* expand 64bit on stack in two ints */ +static void lexpand(void) +{ + int u, v; + u = vtop->type.t & (VT_DEFSIGN | VT_UNSIGNED); + v = vtop->r & (VT_VALMASK | VT_LVAL); + if (v == VT_CONST) { + vdup(); + vtop[0].c.i >>= 32; + } else if (v == (VT_LVAL|VT_CONST) || v == (VT_LVAL|VT_LOCAL)) { + vdup(); + vtop[0].c.i += 4; + } else { + gv(RC_INT); + vdup(); + vtop[0].r = vtop[-1].r2; + vtop[0].r2 = vtop[-1].r2 = VT_CONST; + } + vtop[0].type.t = vtop[-1].type.t = VT_INT | u; +} +#endif + +#ifdef TCC_TARGET_ARM +/* expand long long on stack */ +ST_FUNC void lexpand_nr(void) +{ + int u,v; + + u = vtop->type.t & (VT_DEFSIGN | VT_UNSIGNED); + vdup(); + vtop->r2 = VT_CONST; + vtop->type.t = VT_INT | u; + v=vtop[-1].r & (VT_VALMASK | VT_LVAL); + if (v == VT_CONST) { + vtop[-1].c.i = vtop->c.i; + vtop->c.i = vtop->c.i >> 32; + vtop->r = VT_CONST; + } else if (v == (VT_LVAL|VT_CONST) || v == (VT_LVAL|VT_LOCAL)) { + vtop->c.i += 4; + vtop->r = vtop[-1].r; + } else if (v > VT_CONST) { + vtop--; + lexpand(); + } else + vtop->r = vtop[-1].r2; + vtop[-1].r2 = VT_CONST; + vtop[-1].type.t = VT_INT | u; +} +#endif + +#if PTR_SIZE == 4 +/* build a long long from two ints */ +static void lbuild(int t) +{ + gv2(RC_INT, RC_INT); + vtop[-1].r2 = vtop[0].r; + vtop[-1].type.t = t; + vpop(); +} +#endif + +/* convert stack entry to register and duplicate its value in another + register */ +static void gv_dup(void) +{ + int rc, t, r, r1; + SValue sv; + + t = vtop->type.t; +#if PTR_SIZE == 4 + if ((t & VT_BTYPE) == VT_LLONG) { + if (t & VT_BITFIELD) { + gv(RC_INT); + t = vtop->type.t; + } + lexpand(); + gv_dup(); + vswap(); + vrotb(3); + gv_dup(); + vrotb(4); + /* stack: H L L1 H1 */ + lbuild(t); + vrotb(3); + vrotb(3); + vswap(); + lbuild(t); + vswap(); + } else +#endif + { + /* duplicate value */ + rc = RC_INT; + sv.type.t = VT_INT; + if (is_float(t)) { + rc = RC_FLOAT; +#ifdef TCC_TARGET_X86_64 + if ((t & VT_BTYPE) == VT_LDOUBLE) { + rc = RC_ST0; + } +#endif + sv.type.t = t; + } + r = gv(rc); + r1 = get_reg(rc); + sv.r = r; + sv.c.i = 0; + load(r1, &sv); /* move r to r1 */ + vdup(); + /* duplicates value */ + if (r != r1) + vtop->r = r1; + } +} + +/* Generate value test + * + * Generate a test for any value (jump, comparison and integers) */ +ST_FUNC int gvtst(int inv, int t) +{ + int v = vtop->r & VT_VALMASK; + if (v != VT_CMP && v != VT_JMP && v != VT_JMPI) { + vpushi(0); + gen_op(TOK_NE); + } + if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) { + /* constant jmp optimization */ + if ((vtop->c.i != 0) != inv) + t = gjmp(t); + vtop--; + return t; + } + return gtst(inv, t); +} + +#if PTR_SIZE == 4 +/* generate CPU independent (unsigned) long long operations */ +static void gen_opl(int op) +{ + int t, a, b, op1, c, i; + int func; + unsigned short reg_iret = REG_IRET; + unsigned short reg_lret = REG_LRET; + SValue tmp; + + switch(op) { + case '/': + case TOK_PDIV: + func = TOK___divdi3; + goto gen_func; + case TOK_UDIV: + func = TOK___udivdi3; + goto gen_func; + case '%': + func = TOK___moddi3; + goto gen_mod_func; + case TOK_UMOD: + func = TOK___umoddi3; + gen_mod_func: +#ifdef TCC_ARM_EABI + reg_iret = TREG_R2; + reg_lret = TREG_R3; +#endif + gen_func: + /* call generic long long function */ + vpush_global_sym(&func_old_type, func); + vrott(3); + gfunc_call(2); + vpushi(0); + vtop->r = reg_iret; + vtop->r2 = reg_lret; + break; + case '^': + case '&': + case '|': + case '*': + case '+': + case '-': + //pv("gen_opl A",0,2); + t = vtop->type.t; + vswap(); + lexpand(); + vrotb(3); + lexpand(); + /* stack: L1 H1 L2 H2 */ + tmp = vtop[0]; + vtop[0] = vtop[-3]; + vtop[-3] = tmp; + tmp = vtop[-2]; + vtop[-2] = vtop[-3]; + vtop[-3] = tmp; + vswap(); + /* stack: H1 H2 L1 L2 */ + //pv("gen_opl B",0,4); + if (op == '*') { + vpushv(vtop - 1); + vpushv(vtop - 1); + gen_op(TOK_UMULL); + lexpand(); + /* stack: H1 H2 L1 L2 ML MH */ + for(i=0;i<4;i++) + vrotb(6); + /* stack: ML MH H1 H2 L1 L2 */ + tmp = vtop[0]; + vtop[0] = vtop[-2]; + vtop[-2] = tmp; + /* stack: ML MH H1 L2 H2 L1 */ + gen_op('*'); + vrotb(3); + vrotb(3); + gen_op('*'); + /* stack: ML MH M1 M2 */ + gen_op('+'); + gen_op('+'); + } else if (op == '+' || op == '-') { + /* XXX: add non carry method too (for MIPS or alpha) */ + if (op == '+') + op1 = TOK_ADDC1; + else + op1 = TOK_SUBC1; + gen_op(op1); + /* stack: H1 H2 (L1 op L2) */ + vrotb(3); + vrotb(3); + gen_op(op1 + 1); /* TOK_xxxC2 */ + } else { + gen_op(op); + /* stack: H1 H2 (L1 op L2) */ + vrotb(3); + vrotb(3); + /* stack: (L1 op L2) H1 H2 */ + gen_op(op); + /* stack: (L1 op L2) (H1 op H2) */ + } + /* stack: L H */ + lbuild(t); + break; + case TOK_SAR: + case TOK_SHR: + case TOK_SHL: + if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) { + t = vtop[-1].type.t; + vswap(); + lexpand(); + vrotb(3); + /* stack: L H shift */ + c = (int)vtop->c.i; + /* constant: simpler */ + /* NOTE: all comments are for SHL. the other cases are + done by swapping words */ + vpop(); + if (op != TOK_SHL) + vswap(); + if (c >= 32) { + /* stack: L H */ + vpop(); + if (c > 32) { + vpushi(c - 32); + gen_op(op); + } + if (op != TOK_SAR) { + vpushi(0); + } else { + gv_dup(); + vpushi(31); + gen_op(TOK_SAR); + } + vswap(); + } else { + vswap(); + gv_dup(); + /* stack: H L L */ + vpushi(c); + gen_op(op); + vswap(); + vpushi(32 - c); + if (op == TOK_SHL) + gen_op(TOK_SHR); + else + gen_op(TOK_SHL); + vrotb(3); + /* stack: L L H */ + vpushi(c); + if (op == TOK_SHL) + gen_op(TOK_SHL); + else + gen_op(TOK_SHR); + gen_op('|'); + } + if (op != TOK_SHL) + vswap(); + lbuild(t); + } else { + /* XXX: should provide a faster fallback on x86 ? */ + switch(op) { + case TOK_SAR: + func = TOK___ashrdi3; + goto gen_func; + case TOK_SHR: + func = TOK___lshrdi3; + goto gen_func; + case TOK_SHL: + func = TOK___ashldi3; + goto gen_func; + } + } + break; + default: + /* compare operations */ + t = vtop->type.t; + vswap(); + lexpand(); + vrotb(3); + lexpand(); + /* stack: L1 H1 L2 H2 */ + tmp = vtop[-1]; + vtop[-1] = vtop[-2]; + vtop[-2] = tmp; + /* stack: L1 L2 H1 H2 */ + /* compare high */ + op1 = op; + /* when values are equal, we need to compare low words. since + the jump is inverted, we invert the test too. */ + if (op1 == TOK_LT) + op1 = TOK_LE; + else if (op1 == TOK_GT) + op1 = TOK_GE; + else if (op1 == TOK_ULT) + op1 = TOK_ULE; + else if (op1 == TOK_UGT) + op1 = TOK_UGE; + a = 0; + b = 0; + gen_op(op1); + if (op == TOK_NE) { + b = gvtst(0, 0); + } else { + a = gvtst(1, 0); + if (op != TOK_EQ) { + /* generate non equal test */ + vpushi(TOK_NE); + vtop->r = VT_CMP; + b = gvtst(0, 0); + } + } + /* compare low. Always unsigned */ + op1 = op; + if (op1 == TOK_LT) + op1 = TOK_ULT; + else if (op1 == TOK_LE) + op1 = TOK_ULE; + else if (op1 == TOK_GT) + op1 = TOK_UGT; + else if (op1 == TOK_GE) + op1 = TOK_UGE; + gen_op(op1); + a = gvtst(1, a); + gsym(b); + vseti(VT_JMPI, a); + break; + } +} +#endif + +static uint64_t gen_opic_sdiv(uint64_t a, uint64_t b) +{ + uint64_t x = (a >> 63 ? -a : a) / (b >> 63 ? -b : b); + return (a ^ b) >> 63 ? -x : x; +} + +static int gen_opic_lt(uint64_t a, uint64_t b) +{ + return (a ^ (uint64_t)1 << 63) < (b ^ (uint64_t)1 << 63); +} + +/* handle integer constant optimizations and various machine + independent opt */ +static void gen_opic(int op) +{ + SValue *v1 = vtop - 1; + SValue *v2 = vtop; + int t1 = v1->type.t & VT_BTYPE; + int t2 = v2->type.t & VT_BTYPE; + int c1 = (v1->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST; + int c2 = (v2->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST; + uint64_t l1 = c1 ? v1->c.i : 0; + uint64_t l2 = c2 ? v2->c.i : 0; + int shm = (t1 == VT_LLONG) ? 63 : 31; + + if (t1 != VT_LLONG && (PTR_SIZE != 8 || t1 != VT_PTR)) + l1 = ((uint32_t)l1 | + (v1->type.t & VT_UNSIGNED ? 0 : -(l1 & 0x80000000))); + if (t2 != VT_LLONG && (PTR_SIZE != 8 || t2 != VT_PTR)) + l2 = ((uint32_t)l2 | + (v2->type.t & VT_UNSIGNED ? 0 : -(l2 & 0x80000000))); + + if (c1 && c2) { + switch(op) { + case '+': l1 += l2; break; + case '-': l1 -= l2; break; + case '&': l1 &= l2; break; + case '^': l1 ^= l2; break; + case '|': l1 |= l2; break; + case '*': l1 *= l2; break; + + case TOK_PDIV: + case '/': + case '%': + case TOK_UDIV: + case TOK_UMOD: + /* if division by zero, generate explicit division */ + if (l2 == 0) { + if (const_wanted) + tcc_error("division by zero in constant"); + goto general_case; + } + switch(op) { + default: l1 = gen_opic_sdiv(l1, l2); break; + case '%': l1 = l1 - l2 * gen_opic_sdiv(l1, l2); break; + case TOK_UDIV: l1 = l1 / l2; break; + case TOK_UMOD: l1 = l1 % l2; break; + } + break; + case TOK_SHL: l1 <<= (l2 & shm); break; + case TOK_SHR: l1 >>= (l2 & shm); break; + case TOK_SAR: + l1 = (l1 >> 63) ? ~(~l1 >> (l2 & shm)) : l1 >> (l2 & shm); + break; + /* tests */ + case TOK_ULT: l1 = l1 < l2; break; + case TOK_UGE: l1 = l1 >= l2; break; + case TOK_EQ: l1 = l1 == l2; break; + case TOK_NE: l1 = l1 != l2; break; + case TOK_ULE: l1 = l1 <= l2; break; + case TOK_UGT: l1 = l1 > l2; break; + case TOK_LT: l1 = gen_opic_lt(l1, l2); break; + case TOK_GE: l1 = !gen_opic_lt(l1, l2); break; + case TOK_LE: l1 = !gen_opic_lt(l2, l1); break; + case TOK_GT: l1 = gen_opic_lt(l2, l1); break; + /* logical */ + case TOK_LAND: l1 = l1 && l2; break; + case TOK_LOR: l1 = l1 || l2; break; + default: + goto general_case; + } + if (t1 != VT_LLONG && (PTR_SIZE != 8 || t1 != VT_PTR)) + l1 = ((uint32_t)l1 | + (v1->type.t & VT_UNSIGNED ? 0 : -(l1 & 0x80000000))); + v1->c.i = l1; + vtop--; + } else { + /* if commutative ops, put c2 as constant */ + if (c1 && (op == '+' || op == '&' || op == '^' || + op == '|' || op == '*')) { + vswap(); + c2 = c1; //c = c1, c1 = c2, c2 = c; + l2 = l1; //l = l1, l1 = l2, l2 = l; + } + if (!const_wanted && + c1 && ((l1 == 0 && + (op == TOK_SHL || op == TOK_SHR || op == TOK_SAR)) || + (l1 == -1 && op == TOK_SAR))) { + /* treat (0 << x), (0 >> x) and (-1 >> x) as constant */ + vtop--; + } else if (!const_wanted && + c2 && ((l2 == 0 && (op == '&' || op == '*')) || + (op == '|' && + (l2 == -1 || (l2 == 0xFFFFFFFF && t2 != VT_LLONG))) || + (l2 == 1 && (op == '%' || op == TOK_UMOD)))) { + /* treat (x & 0), (x * 0), (x | -1) and (x % 1) as constant */ + if (l2 == 1) + vtop->c.i = 0; + vswap(); + vtop--; + } else if (c2 && (((op == '*' || op == '/' || op == TOK_UDIV || + op == TOK_PDIV) && + l2 == 1) || + ((op == '+' || op == '-' || op == '|' || op == '^' || + op == TOK_SHL || op == TOK_SHR || op == TOK_SAR) && + l2 == 0) || + (op == '&' && + (l2 == -1 || (l2 == 0xFFFFFFFF && t2 != VT_LLONG))))) { + /* filter out NOP operations like x*1, x-0, x&-1... */ + vtop--; + } else if (c2 && (op == '*' || op == TOK_PDIV || op == TOK_UDIV)) { + /* try to use shifts instead of muls or divs */ + if (l2 > 0 && (l2 & (l2 - 1)) == 0) { + int n = -1; + while (l2) { + l2 >>= 1; + n++; + } + vtop->c.i = n; + if (op == '*') + op = TOK_SHL; + else if (op == TOK_PDIV) + op = TOK_SAR; + else + op = TOK_SHR; + } + goto general_case; + } else if (c2 && (op == '+' || op == '-') && + (((vtop[-1].r & (VT_VALMASK | VT_LVAL | VT_SYM)) == (VT_CONST | VT_SYM)) + || (vtop[-1].r & (VT_VALMASK | VT_LVAL)) == VT_LOCAL)) { + /* symbol + constant case */ + if (op == '-') + l2 = -l2; + l2 += vtop[-1].c.i; + /* The backends can't always deal with addends to symbols + larger than +-1<<31. Don't construct such. */ + if ((int)l2 != l2) + goto general_case; + vtop--; + vtop->c.i = l2; + } else { + general_case: + /* call low level op generator */ + if (t1 == VT_LLONG || t2 == VT_LLONG || + (PTR_SIZE == 8 && (t1 == VT_PTR || t2 == VT_PTR))) + gen_opl(op); + else + gen_opi(op); + } + } +} + +/* generate a floating point operation with constant propagation */ +static void gen_opif(int op) +{ + int c1, c2; + SValue *v1, *v2; +#if defined _MSC_VER && defined _AMD64_ + /* avoid bad optimization with f1 -= f2 for f1:-0.0, f2:0.0 */ + volatile +#endif + long double f1, f2; + + v1 = vtop - 1; + v2 = vtop; + /* currently, we cannot do computations with forward symbols */ + c1 = (v1->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST; + c2 = (v2->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST; + if (c1 && c2) { + if (v1->type.t == VT_FLOAT) { + f1 = v1->c.f; + f2 = v2->c.f; + } else if (v1->type.t == VT_DOUBLE) { + f1 = v1->c.d; + f2 = v2->c.d; + } else { + f1 = v1->c.ld; + f2 = v2->c.ld; + } + + /* NOTE: we only do constant propagation if finite number (not + NaN or infinity) (ANSI spec) */ + if (!ieee_finite(f1) || !ieee_finite(f2)) + goto general_case; + + switch(op) { + case '+': f1 += f2; break; + case '-': f1 -= f2; break; + case '*': f1 *= f2; break; + case '/': + if (f2 == 0.0) { + if (const_wanted) + tcc_error("division by zero in constant"); + goto general_case; + } + f1 /= f2; + break; + /* XXX: also handles tests ? */ + default: + goto general_case; + } + /* XXX: overflow test ? */ + if (v1->type.t == VT_FLOAT) { + v1->c.f = f1; + } else if (v1->type.t == VT_DOUBLE) { + v1->c.d = f1; + } else { + v1->c.ld = f1; + } + vtop--; + } else { + general_case: + gen_opf(op); + } +} + +static int pointed_size(CType *type) +{ + int align; + return type_size(pointed_type(type), &align); +} + +static void vla_runtime_pointed_size(CType *type) +{ + int align; + vla_runtime_type_size(pointed_type(type), &align); +} + +static inline int is_null_pointer(SValue *p) +{ + if ((p->r & (VT_VALMASK | VT_LVAL | VT_SYM)) != VT_CONST) + return 0; + return ((p->type.t & VT_BTYPE) == VT_INT && (uint32_t)p->c.i == 0) || + ((p->type.t & VT_BTYPE) == VT_LLONG && p->c.i == 0) || + ((p->type.t & VT_BTYPE) == VT_PTR && + (PTR_SIZE == 4 ? (uint32_t)p->c.i == 0 : p->c.i == 0)); +} + +static inline int is_integer_btype(int bt) +{ + return (bt == VT_BYTE || bt == VT_SHORT || + bt == VT_INT || bt == VT_LLONG); +} + +/* check types for comparison or subtraction of pointers */ +static void check_comparison_pointer_types(SValue *p1, SValue *p2, int op) +{ + CType *type1, *type2, tmp_type1, tmp_type2; + int bt1, bt2; + + /* null pointers are accepted for all comparisons as gcc */ + if (is_null_pointer(p1) || is_null_pointer(p2)) + return; + type1 = &p1->type; + type2 = &p2->type; + bt1 = type1->t & VT_BTYPE; + bt2 = type2->t & VT_BTYPE; + /* accept comparison between pointer and integer with a warning */ + if ((is_integer_btype(bt1) || is_integer_btype(bt2)) && op != '-') { + if (op != TOK_LOR && op != TOK_LAND ) + tcc_warning("comparison between pointer and integer"); + return; + } + + /* both must be pointers or implicit function pointers */ + if (bt1 == VT_PTR) { + type1 = pointed_type(type1); + } else if (bt1 != VT_FUNC) + goto invalid_operands; + + if (bt2 == VT_PTR) { + type2 = pointed_type(type2); + } else if (bt2 != VT_FUNC) { + invalid_operands: + tcc_error("invalid operands to binary %s", get_tok_str(op, NULL)); + } + if ((type1->t & VT_BTYPE) == VT_VOID || + (type2->t & VT_BTYPE) == VT_VOID) + return; + tmp_type1 = *type1; + tmp_type2 = *type2; + tmp_type1.t &= ~(VT_DEFSIGN | VT_UNSIGNED | VT_CONSTANT | VT_VOLATILE); + tmp_type2.t &= ~(VT_DEFSIGN | VT_UNSIGNED | VT_CONSTANT | VT_VOLATILE); + if (!is_compatible_types(&tmp_type1, &tmp_type2)) { + /* gcc-like error if '-' is used */ + if (op == '-') + goto invalid_operands; + else + tcc_warning("comparison of distinct pointer types lacks a cast"); + } +} + +/* generic gen_op: handles types problems */ +ST_FUNC void gen_op(int op) +{ + int u, t1, t2, bt1, bt2, t; + CType type1; + +redo: + t1 = vtop[-1].type.t; + t2 = vtop[0].type.t; + bt1 = t1 & VT_BTYPE; + bt2 = t2 & VT_BTYPE; + + if (bt1 == VT_STRUCT || bt2 == VT_STRUCT) { + tcc_error("operation on a struct"); + } else if (bt1 == VT_FUNC || bt2 == VT_FUNC) { + if (bt2 == VT_FUNC) { + mk_pointer(&vtop->type); + gaddrof(); + } + if (bt1 == VT_FUNC) { + vswap(); + mk_pointer(&vtop->type); + gaddrof(); + vswap(); + } + goto redo; + } else if (bt1 == VT_PTR || bt2 == VT_PTR) { + /* at least one operand is a pointer */ + /* relational op: must be both pointers */ + if (op >= TOK_ULT && op <= TOK_LOR) { + check_comparison_pointer_types(vtop - 1, vtop, op); + /* pointers are handled are unsigned */ +#if PTR_SIZE == 8 + t = VT_LLONG | VT_UNSIGNED; +#else + t = VT_INT | VT_UNSIGNED; +#endif + goto std_op; + } + /* if both pointers, then it must be the '-' op */ + if (bt1 == VT_PTR && bt2 == VT_PTR) { + if (op != '-') + tcc_error("cannot use pointers here"); + check_comparison_pointer_types(vtop - 1, vtop, op); + /* XXX: check that types are compatible */ + if (vtop[-1].type.t & VT_VLA) { + vla_runtime_pointed_size(&vtop[-1].type); + } else { + vpushi(pointed_size(&vtop[-1].type)); + } + vrott(3); + gen_opic(op); + vtop->type.t = ptrdiff_type.t; + vswap(); + gen_op(TOK_PDIV); + } else { + /* exactly one pointer : must be '+' or '-'. */ + if (op != '-' && op != '+') + tcc_error("cannot use pointers here"); + /* Put pointer as first operand */ + if (bt2 == VT_PTR) { + vswap(); + t = t1, t1 = t2, t2 = t; + } +#if PTR_SIZE == 4 + if ((vtop[0].type.t & VT_BTYPE) == VT_LLONG) + /* XXX: truncate here because gen_opl can't handle ptr + long long */ + gen_cast_s(VT_INT); +#endif + type1 = vtop[-1].type; + type1.t &= ~VT_ARRAY; + if (vtop[-1].type.t & VT_VLA) + vla_runtime_pointed_size(&vtop[-1].type); + else { + u = pointed_size(&vtop[-1].type); + if (u < 0) + tcc_error("unknown array element size"); +#if PTR_SIZE == 8 + vpushll(u); +#else + /* XXX: cast to int ? (long long case) */ + vpushi(u); +#endif + } + gen_op('*'); +#if 0 +/* #ifdef CONFIG_TCC_BCHECK + The main reason to removing this code: + #include + int main () + { + int v[10]; + int i = 10; + int j = 9; + fprintf(stderr, "v+i-j = %p\n", v+i-j); + fprintf(stderr, "v+(i-j) = %p\n", v+(i-j)); + } + When this code is on. then the output looks like + v+i-j = 0xfffffffe + v+(i-j) = 0xbff84000 + */ + /* if evaluating constant expression, no code should be + generated, so no bound check */ + if (tcc_state->do_bounds_check && !const_wanted) { + /* if bounded pointers, we generate a special code to + test bounds */ + if (op == '-') { + vpushi(0); + vswap(); + gen_op('-'); + } + gen_bounded_ptr_add(); + } else +#endif + { + gen_opic(op); + } + /* put again type if gen_opic() swaped operands */ + vtop->type = type1; + } + } else if (is_float(bt1) || is_float(bt2)) { + /* compute bigger type and do implicit casts */ + if (bt1 == VT_LDOUBLE || bt2 == VT_LDOUBLE) { + t = VT_LDOUBLE; + } else if (bt1 == VT_DOUBLE || bt2 == VT_DOUBLE) { + t = VT_DOUBLE; + } else { + t = VT_FLOAT; + } + /* floats can only be used for a few operations */ + if (op != '+' && op != '-' && op != '*' && op != '/' && + (op < TOK_ULT || op > TOK_GT)) + tcc_error("invalid operands for binary operation"); + goto std_op; + } else if (op == TOK_SHR || op == TOK_SAR || op == TOK_SHL) { + t = bt1 == VT_LLONG ? VT_LLONG : VT_INT; + if ((t1 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (t | VT_UNSIGNED)) + t |= VT_UNSIGNED; + t |= (VT_LONG & t1); + goto std_op; + } else if (bt1 == VT_LLONG || bt2 == VT_LLONG) { + /* cast to biggest op */ + t = VT_LLONG | VT_LONG; + if (bt1 == VT_LLONG) + t &= t1; + if (bt2 == VT_LLONG) + t &= t2; + /* convert to unsigned if it does not fit in a long long */ + if ((t1 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (VT_LLONG | VT_UNSIGNED) || + (t2 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (VT_LLONG | VT_UNSIGNED)) + t |= VT_UNSIGNED; + goto std_op; + } else { + /* integer operations */ + t = VT_INT | (VT_LONG & (t1 | t2)); + /* convert to unsigned if it does not fit in an integer */ + if ((t1 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (VT_INT | VT_UNSIGNED) || + (t2 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (VT_INT | VT_UNSIGNED)) + t |= VT_UNSIGNED; + std_op: + /* XXX: currently, some unsigned operations are explicit, so + we modify them here */ + if (t & VT_UNSIGNED) { + if (op == TOK_SAR) + op = TOK_SHR; + else if (op == '/') + op = TOK_UDIV; + else if (op == '%') + op = TOK_UMOD; + else if (op == TOK_LT) + op = TOK_ULT; + else if (op == TOK_GT) + op = TOK_UGT; + else if (op == TOK_LE) + op = TOK_ULE; + else if (op == TOK_GE) + op = TOK_UGE; + } + vswap(); + type1.t = t; + type1.ref = NULL; + gen_cast(&type1); + vswap(); + /* special case for shifts and long long: we keep the shift as + an integer */ + if (op == TOK_SHR || op == TOK_SAR || op == TOK_SHL) + type1.t = VT_INT; + gen_cast(&type1); + if (is_float(t)) + gen_opif(op); + else + gen_opic(op); + if (op >= TOK_ULT && op <= TOK_GT) { + /* relational op: the result is an int */ + vtop->type.t = VT_INT; + } else { + vtop->type.t = t; + } + } + // Make sure that we have converted to an rvalue: + if (vtop->r & VT_LVAL) + gv(is_float(vtop->type.t & VT_BTYPE) ? RC_FLOAT : RC_INT); +} + +#ifndef TCC_TARGET_ARM +/* generic itof for unsigned long long case */ +static void gen_cvt_itof1(int t) +{ +#ifdef TCC_TARGET_ARM64 + gen_cvt_itof(t); +#else + if ((vtop->type.t & (VT_BTYPE | VT_UNSIGNED)) == + (VT_LLONG | VT_UNSIGNED)) { + + if (t == VT_FLOAT) + vpush_global_sym(&func_old_type, TOK___floatundisf); +#if LDOUBLE_SIZE != 8 + else if (t == VT_LDOUBLE) + vpush_global_sym(&func_old_type, TOK___floatundixf); +#endif + else + vpush_global_sym(&func_old_type, TOK___floatundidf); + vrott(2); + gfunc_call(1); + vpushi(0); + vtop->r = reg_fret(t); + } else { + gen_cvt_itof(t); + } +#endif +} +#endif + +/* generic ftoi for unsigned long long case */ +static void gen_cvt_ftoi1(int t) +{ +#ifdef TCC_TARGET_ARM64 + gen_cvt_ftoi(t); +#else + int st; + + if (t == (VT_LLONG | VT_UNSIGNED)) { + /* not handled natively */ + st = vtop->type.t & VT_BTYPE; + if (st == VT_FLOAT) + vpush_global_sym(&func_old_type, TOK___fixunssfdi); +#if LDOUBLE_SIZE != 8 + else if (st == VT_LDOUBLE) + vpush_global_sym(&func_old_type, TOK___fixunsxfdi); +#endif + else + vpush_global_sym(&func_old_type, TOK___fixunsdfdi); + vrott(2); + gfunc_call(1); + vpushi(0); + vtop->r = REG_IRET; + vtop->r2 = REG_LRET; + } else { + gen_cvt_ftoi(t); + } +#endif +} + +/* force char or short cast */ +static void force_charshort_cast(int t) +{ + int bits, dbt; + + /* cannot cast static initializers */ + if (STATIC_DATA_WANTED) + return; + + dbt = t & VT_BTYPE; + /* XXX: add optimization if lvalue : just change type and offset */ + if (dbt == VT_BYTE) + bits = 8; + else + bits = 16; + if (t & VT_UNSIGNED) { + vpushi((1 << bits) - 1); + gen_op('&'); + } else { + if ((vtop->type.t & VT_BTYPE) == VT_LLONG) + bits = 64 - bits; + else + bits = 32 - bits; + vpushi(bits); + gen_op(TOK_SHL); + /* result must be signed or the SAR is converted to an SHL + This was not the case when "t" was a signed short + and the last value on the stack was an unsigned int */ + vtop->type.t &= ~VT_UNSIGNED; + vpushi(bits); + gen_op(TOK_SAR); + } +} + +/* cast 'vtop' to 'type'. Casting to bitfields is forbidden. */ +static void gen_cast_s(int t) +{ + CType type; + type.t = t; + type.ref = NULL; + gen_cast(&type); +} + +static void gen_cast(CType *type) +{ + int sbt, dbt, sf, df, c, p; + + /* special delayed cast for char/short */ + /* XXX: in some cases (multiple cascaded casts), it may still + be incorrect */ + if (vtop->r & VT_MUSTCAST) { + vtop->r &= ~VT_MUSTCAST; + force_charshort_cast(vtop->type.t); + } + + /* bitfields first get cast to ints */ + if (vtop->type.t & VT_BITFIELD) { + gv(RC_INT); + } + + dbt = type->t & (VT_BTYPE | VT_UNSIGNED); + sbt = vtop->type.t & (VT_BTYPE | VT_UNSIGNED); + + if (sbt != dbt) { + sf = is_float(sbt); + df = is_float(dbt); + c = (vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST; + p = (vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == (VT_CONST | VT_SYM); +#if !defined TCC_IS_NATIVE && !defined TCC_IS_NATIVE_387 + c &= dbt != VT_LDOUBLE; +#endif + if (c) { + /* constant case: we can do it now */ + /* XXX: in ISOC, cannot do it if error in convert */ + if (sbt == VT_FLOAT) + vtop->c.ld = vtop->c.f; + else if (sbt == VT_DOUBLE) + vtop->c.ld = vtop->c.d; + + if (df) { + if ((sbt & VT_BTYPE) == VT_LLONG) { + if ((sbt & VT_UNSIGNED) || !(vtop->c.i >> 63)) + vtop->c.ld = vtop->c.i; + else + vtop->c.ld = -(long double)-vtop->c.i; + } else if(!sf) { + if ((sbt & VT_UNSIGNED) || !(vtop->c.i >> 31)) + vtop->c.ld = (uint32_t)vtop->c.i; + else + vtop->c.ld = -(long double)-(uint32_t)vtop->c.i; + } + + if (dbt == VT_FLOAT) + vtop->c.f = (float)vtop->c.ld; + else if (dbt == VT_DOUBLE) + vtop->c.d = (double)vtop->c.ld; + } else if (sf && dbt == (VT_LLONG|VT_UNSIGNED)) { + vtop->c.i = vtop->c.ld; + } else if (sf && dbt == VT_BOOL) { + vtop->c.i = (vtop->c.ld != 0); + } else { + if(sf) + vtop->c.i = vtop->c.ld; + else if (sbt == (VT_LLONG|VT_UNSIGNED)) + ; + else if (sbt & VT_UNSIGNED) + vtop->c.i = (uint32_t)vtop->c.i; +#if PTR_SIZE == 8 + else if (sbt == VT_PTR) + ; +#endif + else if (sbt != VT_LLONG) + vtop->c.i = ((uint32_t)vtop->c.i | + -(vtop->c.i & 0x80000000)); + + if (dbt == (VT_LLONG|VT_UNSIGNED)) + ; + else if (dbt == VT_BOOL) + vtop->c.i = (vtop->c.i != 0); +#if PTR_SIZE == 8 + else if (dbt == VT_PTR) + ; +#endif + else if (dbt != VT_LLONG) { + uint32_t m = ((dbt & VT_BTYPE) == VT_BYTE ? 0xff : + (dbt & VT_BTYPE) == VT_SHORT ? 0xffff : + 0xffffffff); + vtop->c.i &= m; + if (!(dbt & VT_UNSIGNED)) + vtop->c.i |= -(vtop->c.i & ((m >> 1) + 1)); + } + } + } else if (p && dbt == VT_BOOL) { + vtop->r = VT_CONST; + vtop->c.i = 1; + } else { + /* non constant case: generate code */ + if (sf && df) { + /* convert from fp to fp */ + gen_cvt_ftof(dbt); + } else if (df) { + /* convert int to fp */ + gen_cvt_itof1(dbt); + } else if (sf) { + /* convert fp to int */ + if (dbt == VT_BOOL) { + vpushi(0); + gen_op(TOK_NE); + } else { + /* we handle char/short/etc... with generic code */ + if (dbt != (VT_INT | VT_UNSIGNED) && + dbt != (VT_LLONG | VT_UNSIGNED) && + dbt != VT_LLONG) + dbt = VT_INT; + gen_cvt_ftoi1(dbt); + if (dbt == VT_INT && (type->t & (VT_BTYPE | VT_UNSIGNED)) != dbt) { + /* additional cast for char/short... */ + vtop->type.t = dbt; + gen_cast(type); + } + } +#if PTR_SIZE == 4 + } else if ((dbt & VT_BTYPE) == VT_LLONG) { + if ((sbt & VT_BTYPE) != VT_LLONG) { + /* scalar to long long */ + /* machine independent conversion */ + gv(RC_INT); + /* generate high word */ + if (sbt == (VT_INT | VT_UNSIGNED)) { + vpushi(0); + gv(RC_INT); + } else { + if (sbt == VT_PTR) { + /* cast from pointer to int before we apply + shift operation, which pointers don't support*/ + gen_cast_s(VT_INT); + } + gv_dup(); + vpushi(31); + gen_op(TOK_SAR); + } + /* patch second register */ + vtop[-1].r2 = vtop->r; + vpop(); + } +#else + } else if ((dbt & VT_BTYPE) == VT_LLONG || + (dbt & VT_BTYPE) == VT_PTR || + (dbt & VT_BTYPE) == VT_FUNC) { + if ((sbt & VT_BTYPE) != VT_LLONG && + (sbt & VT_BTYPE) != VT_PTR && + (sbt & VT_BTYPE) != VT_FUNC) { + /* need to convert from 32bit to 64bit */ + gv(RC_INT); + if (sbt != (VT_INT | VT_UNSIGNED)) { +#if defined(TCC_TARGET_ARM64) + gen_cvt_sxtw(); +#elif defined(TCC_TARGET_X86_64) + int r = gv(RC_INT); + /* x86_64 specific: movslq */ + o(0x6348); + o(0xc0 + (REG_VALUE(r) << 3) + REG_VALUE(r)); +#else +#error +#endif + } + } +#endif + } else if (dbt == VT_BOOL) { + /* scalar to bool */ + vpushi(0); + gen_op(TOK_NE); + } else if ((dbt & VT_BTYPE) == VT_BYTE || + (dbt & VT_BTYPE) == VT_SHORT) { + if (sbt == VT_PTR) { + vtop->type.t = VT_INT; + tcc_warning("nonportable conversion from pointer to char/short"); + } + force_charshort_cast(dbt); +#if PTR_SIZE == 4 + } else if ((dbt & VT_BTYPE) == VT_INT) { + /* scalar to int */ + if ((sbt & VT_BTYPE) == VT_LLONG) { + /* from long long: just take low order word */ + lexpand(); + vpop(); + } + /* if lvalue and single word type, nothing to do because + the lvalue already contains the real type size (see + VT_LVAL_xxx constants) */ +#endif + } + } + } else if ((dbt & VT_BTYPE) == VT_PTR && !(vtop->r & VT_LVAL)) { + /* if we are casting between pointer types, + we must update the VT_LVAL_xxx size */ + vtop->r = (vtop->r & ~VT_LVAL_TYPE) + | (lvalue_type(type->ref->type.t) & VT_LVAL_TYPE); + } + vtop->type = *type; +} + +/* return type size as known at compile time. Put alignment at 'a' */ +ST_FUNC int type_size(CType *type, int *a) +{ + Sym *s; + int bt; + + bt = type->t & VT_BTYPE; + if (bt == VT_STRUCT) { + /* struct/union */ + s = type->ref; + *a = s->r; + return s->c; + } else if (bt == VT_PTR) { + if (type->t & VT_ARRAY) { + int ts; + + s = type->ref; + ts = type_size(&s->type, a); + + if (ts < 0 && s->c < 0) + ts = -ts; + + return ts * s->c; + } else { + *a = PTR_SIZE; + return PTR_SIZE; + } + } else if (IS_ENUM(type->t) && type->ref->c == -1) { + return -1; /* incomplete enum */ + } else if (bt == VT_LDOUBLE) { + *a = LDOUBLE_ALIGN; + return LDOUBLE_SIZE; + } else if (bt == VT_DOUBLE || bt == VT_LLONG) { +#ifdef TCC_TARGET_I386 +#ifdef TCC_TARGET_PE + *a = 8; +#else + *a = 4; +#endif +#elif defined(TCC_TARGET_ARM) +#ifdef TCC_ARM_EABI + *a = 8; +#else + *a = 4; +#endif +#else + *a = 8; +#endif + return 8; + } else if (bt == VT_INT || bt == VT_FLOAT) { + *a = 4; + return 4; + } else if (bt == VT_SHORT) { + *a = 2; + return 2; + } else if (bt == VT_QLONG || bt == VT_QFLOAT) { + *a = 8; + return 16; + } else { + /* char, void, function, _Bool */ + *a = 1; + return 1; + } +} + +/* push type size as known at runtime time on top of value stack. Put + alignment at 'a' */ +ST_FUNC void vla_runtime_type_size(CType *type, int *a) +{ + if (type->t & VT_VLA) { + type_size(&type->ref->type, a); + vset(&int_type, VT_LOCAL|VT_LVAL, type->ref->c); + } else { + vpushi(type_size(type, a)); + } +} + +static void vla_sp_restore(void) { + if (vlas_in_scope) { + gen_vla_sp_restore(vla_sp_loc); + } +} + +static void vla_sp_restore_root(void) { + if (vlas_in_scope) { + gen_vla_sp_restore(vla_sp_root_loc); + } +} + +/* return the pointed type of t */ +static inline CType *pointed_type(CType *type) +{ + return &type->ref->type; +} + +/* modify type so that its it is a pointer to type. */ +ST_FUNC void mk_pointer(CType *type) +{ + Sym *s; + s = sym_push(SYM_FIELD, type, 0, -1); + type->t = VT_PTR | (type->t & VT_STORAGE); + type->ref = s; +} + +/* compare function types. OLD functions match any new functions */ +static int is_compatible_func(CType *type1, CType *type2) +{ + Sym *s1, *s2; + + s1 = type1->ref; + s2 = type2->ref; + if (!is_compatible_types(&s1->type, &s2->type)) + return 0; + /* check func_call */ + if (s1->f.func_call != s2->f.func_call) + return 0; + /* XXX: not complete */ + if (s1->f.func_type == FUNC_OLD || s2->f.func_type == FUNC_OLD) + return 1; + if (s1->f.func_type != s2->f.func_type) + return 0; + while (s1 != NULL) { + if (s2 == NULL) + return 0; + if (!is_compatible_unqualified_types(&s1->type, &s2->type)) + return 0; + s1 = s1->next; + s2 = s2->next; + } + if (s2) + return 0; + return 1; +} + +/* return true if type1 and type2 are the same. If unqualified is + true, qualifiers on the types are ignored. + + - enums are not checked as gcc __builtin_types_compatible_p () + */ +static int compare_types(CType *type1, CType *type2, int unqualified) +{ + int bt1, t1, t2; + + t1 = type1->t & VT_TYPE; + t2 = type2->t & VT_TYPE; + if (unqualified) { + /* strip qualifiers before comparing */ + t1 &= ~(VT_CONSTANT | VT_VOLATILE); + t2 &= ~(VT_CONSTANT | VT_VOLATILE); + } + + /* Default Vs explicit signedness only matters for char */ + if ((t1 & VT_BTYPE) != VT_BYTE) { + t1 &= ~VT_DEFSIGN; + t2 &= ~VT_DEFSIGN; + } + /* XXX: bitfields ? */ + if (t1 != t2) + return 0; + /* test more complicated cases */ + bt1 = t1 & VT_BTYPE; + if (bt1 == VT_PTR) { + type1 = pointed_type(type1); + type2 = pointed_type(type2); + return is_compatible_types(type1, type2); + } else if (bt1 == VT_STRUCT) { + return (type1->ref == type2->ref); + } else if (bt1 == VT_FUNC) { + return is_compatible_func(type1, type2); + } else { + return 1; + } +} + +/* return true if type1 and type2 are exactly the same (including + qualifiers). +*/ +static int is_compatible_types(CType *type1, CType *type2) +{ + return compare_types(type1,type2,0); +} + +/* return true if type1 and type2 are the same (ignoring qualifiers). +*/ +static int is_compatible_unqualified_types(CType *type1, CType *type2) +{ + return compare_types(type1,type2,1); +} + +/* print a type. If 'varstr' is not NULL, then the variable is also + printed in the type */ +/* XXX: union */ +/* XXX: add array and function pointers */ +static void type_to_str(char *buf, int buf_size, + CType *type, const char *varstr) +{ + int bt, v, t; + Sym *s, *sa; + char buf1[256]; + const char *tstr; + + t = type->t; + bt = t & VT_BTYPE; + buf[0] = '\0'; + + if (t & VT_EXTERN) + pstrcat(buf, buf_size, "extern "); + if (t & VT_STATIC) + pstrcat(buf, buf_size, "static "); + if (t & VT_TYPEDEF) + pstrcat(buf, buf_size, "typedef "); + if (t & VT_INLINE) + pstrcat(buf, buf_size, "inline "); + if (t & VT_VOLATILE) + pstrcat(buf, buf_size, "volatile "); + if (t & VT_CONSTANT) + pstrcat(buf, buf_size, "const "); + + if (((t & VT_DEFSIGN) && bt == VT_BYTE) + || ((t & VT_UNSIGNED) + && (bt == VT_SHORT || bt == VT_INT || bt == VT_LLONG) + && !IS_ENUM(t) + )) + pstrcat(buf, buf_size, (t & VT_UNSIGNED) ? "unsigned " : "signed "); + + buf_size -= strlen(buf); + buf += strlen(buf); + + switch(bt) { + case VT_VOID: + tstr = "void"; + goto add_tstr; + case VT_BOOL: + tstr = "_Bool"; + goto add_tstr; + case VT_BYTE: + tstr = "char"; + goto add_tstr; + case VT_SHORT: + tstr = "short"; + goto add_tstr; + case VT_INT: + tstr = "int"; + goto maybe_long; + case VT_LLONG: + tstr = "long long"; + maybe_long: + if (t & VT_LONG) + tstr = "long"; + if (!IS_ENUM(t)) + goto add_tstr; + tstr = "enum "; + goto tstruct; + case VT_FLOAT: + tstr = "float"; + goto add_tstr; + case VT_DOUBLE: + tstr = "double"; + goto add_tstr; + case VT_LDOUBLE: + tstr = "long double"; + add_tstr: + pstrcat(buf, buf_size, tstr); + break; + case VT_STRUCT: + tstr = "struct "; + if (IS_UNION(t)) + tstr = "union "; + tstruct: + pstrcat(buf, buf_size, tstr); + v = type->ref->v & ~SYM_STRUCT; + if (v >= SYM_FIRST_ANOM) + pstrcat(buf, buf_size, ""); + else + pstrcat(buf, buf_size, get_tok_str(v, NULL)); + break; + case VT_FUNC: + s = type->ref; + type_to_str(buf, buf_size, &s->type, varstr); + pstrcat(buf, buf_size, "("); + sa = s->next; + while (sa != NULL) { + type_to_str(buf1, sizeof(buf1), &sa->type, NULL); + pstrcat(buf, buf_size, buf1); + sa = sa->next; + if (sa) + pstrcat(buf, buf_size, ", "); + } + pstrcat(buf, buf_size, ")"); + goto no_var; + case VT_PTR: + s = type->ref; + if (t & VT_ARRAY) { + snprintf(buf1, sizeof(buf1), "%s[%d]", varstr ? varstr : "", s->c); + type_to_str(buf, buf_size, &s->type, buf1); + goto no_var; + } + pstrcpy(buf1, sizeof(buf1), "*"); + if (t & VT_CONSTANT) + pstrcat(buf1, buf_size, "const "); + if (t & VT_VOLATILE) + pstrcat(buf1, buf_size, "volatile "); + if (varstr) + pstrcat(buf1, sizeof(buf1), varstr); + type_to_str(buf, buf_size, &s->type, buf1); + goto no_var; + } + if (varstr) { + pstrcat(buf, buf_size, " "); + pstrcat(buf, buf_size, varstr); + } + no_var: ; +} + +/* verify type compatibility to store vtop in 'dt' type, and generate + casts if needed. */ +static void gen_assign_cast(CType *dt) +{ + CType *st, *type1, *type2; + char buf1[256], buf2[256]; + int dbt, sbt; + + st = &vtop->type; /* source type */ + dbt = dt->t & VT_BTYPE; + sbt = st->t & VT_BTYPE; + if (sbt == VT_VOID || dbt == VT_VOID) { + if (sbt == VT_VOID && dbt == VT_VOID) + ; /* + It is Ok if both are void + A test program: + void func1() {} + void func2() { + return func1(); + } + gcc accepts this program + */ + else + tcc_error("cannot cast from/to void"); + } + if (dt->t & VT_CONSTANT) + tcc_warning("assignment of read-only location"); + switch(dbt) { + case VT_PTR: + /* special cases for pointers */ + /* '0' can also be a pointer */ + if (is_null_pointer(vtop)) + goto type_ok; + /* accept implicit pointer to integer cast with warning */ + if (is_integer_btype(sbt)) { + tcc_warning("assignment makes pointer from integer without a cast"); + goto type_ok; + } + type1 = pointed_type(dt); + /* a function is implicitly a function pointer */ + if (sbt == VT_FUNC) { + if ((type1->t & VT_BTYPE) != VT_VOID && + !is_compatible_types(pointed_type(dt), st)) + tcc_warning("assignment from incompatible pointer type"); + goto type_ok; + } + if (sbt != VT_PTR) + goto error; + type2 = pointed_type(st); + if ((type1->t & VT_BTYPE) == VT_VOID || + (type2->t & VT_BTYPE) == VT_VOID) { + /* void * can match anything */ + } else { + //printf("types %08x %08x\n", type1->t, type2->t); + /* exact type match, except for qualifiers */ + if (!is_compatible_unqualified_types(type1, type2)) { + /* Like GCC don't warn by default for merely changes + in pointer target signedness. Do warn for different + base types, though, in particular for unsigned enums + and signed int targets. */ + if ((type1->t & (VT_BTYPE|VT_LONG)) != (type2->t & (VT_BTYPE|VT_LONG)) + || IS_ENUM(type1->t) || IS_ENUM(type2->t) + ) + tcc_warning("assignment from incompatible pointer type"); + } + } + /* check const and volatile */ + if ((!(type1->t & VT_CONSTANT) && (type2->t & VT_CONSTANT)) || + (!(type1->t & VT_VOLATILE) && (type2->t & VT_VOLATILE))) + tcc_warning("assignment discards qualifiers from pointer target type"); + break; + case VT_BYTE: + case VT_SHORT: + case VT_INT: + case VT_LLONG: + if (sbt == VT_PTR || sbt == VT_FUNC) { + tcc_warning("assignment makes integer from pointer without a cast"); + } else if (sbt == VT_STRUCT) { + goto case_VT_STRUCT; + } + /* XXX: more tests */ + break; + case VT_STRUCT: + case_VT_STRUCT: + if (!is_compatible_unqualified_types(dt, st)) { + error: + type_to_str(buf1, sizeof(buf1), st, NULL); + type_to_str(buf2, sizeof(buf2), dt, NULL); + tcc_error("cannot cast '%s' to '%s'", buf1, buf2); + } + break; + } + type_ok: + gen_cast(dt); +} + +/* store vtop in lvalue pushed on stack */ +ST_FUNC void vstore(void) +{ + int sbt, dbt, ft, r, t, size, align, bit_size, bit_pos, rc, delayed_cast; + + ft = vtop[-1].type.t; + sbt = vtop->type.t & VT_BTYPE; + dbt = ft & VT_BTYPE; + if ((((sbt == VT_INT || sbt == VT_SHORT) && dbt == VT_BYTE) || + (sbt == VT_INT && dbt == VT_SHORT)) + && !(vtop->type.t & VT_BITFIELD)) { + /* optimize char/short casts */ + delayed_cast = VT_MUSTCAST; + vtop->type.t = ft & VT_TYPE; + /* XXX: factorize */ + if (ft & VT_CONSTANT) + tcc_warning("assignment of read-only location"); + } else { + delayed_cast = 0; + if (!(ft & VT_BITFIELD)) + gen_assign_cast(&vtop[-1].type); + } + + if (sbt == VT_STRUCT) { + /* if structure, only generate pointer */ + /* structure assignment : generate memcpy */ + /* XXX: optimize if small size */ + size = type_size(&vtop->type, &align); + + /* destination */ + vswap(); + vtop->type.t = VT_PTR; + gaddrof(); + + /* address of memcpy() */ +#ifdef TCC_ARM_EABI + if(!(align & 7)) + vpush_global_sym(&func_old_type, TOK_memcpy8); + else if(!(align & 3)) + vpush_global_sym(&func_old_type, TOK_memcpy4); + else +#endif + /* Use memmove, rather than memcpy, as dest and src may be same: */ + vpush_global_sym(&func_old_type, TOK_memmove); + + vswap(); + /* source */ + vpushv(vtop - 2); + vtop->type.t = VT_PTR; + gaddrof(); + /* type size */ + vpushi(size); + gfunc_call(3); + + /* leave source on stack */ + } else if (ft & VT_BITFIELD) { + /* bitfield store handling */ + + /* save lvalue as expression result (example: s.b = s.a = n;) */ + vdup(), vtop[-1] = vtop[-2]; + + bit_pos = BIT_POS(ft); + bit_size = BIT_SIZE(ft); + /* remove bit field info to avoid loops */ + vtop[-1].type.t = ft & ~VT_STRUCT_MASK; + + if ((ft & VT_BTYPE) == VT_BOOL) { + gen_cast(&vtop[-1].type); + vtop[-1].type.t = (vtop[-1].type.t & ~VT_BTYPE) | (VT_BYTE | VT_UNSIGNED); + } + + r = adjust_bf(vtop - 1, bit_pos, bit_size); + if (r == VT_STRUCT) { + gen_cast_s((ft & VT_BTYPE) == VT_LLONG ? VT_LLONG : VT_INT); + store_packed_bf(bit_pos, bit_size); + } else { + unsigned long long mask = (1ULL << bit_size) - 1; + if ((ft & VT_BTYPE) != VT_BOOL) { + /* mask source */ + if ((vtop[-1].type.t & VT_BTYPE) == VT_LLONG) + vpushll(mask); + else + vpushi((unsigned)mask); + gen_op('&'); + } + /* shift source */ + vpushi(bit_pos); + gen_op(TOK_SHL); + vswap(); + /* duplicate destination */ + vdup(); + vrott(3); + /* load destination, mask and or with source */ + if ((vtop->type.t & VT_BTYPE) == VT_LLONG) + vpushll(~(mask << bit_pos)); + else + vpushi(~((unsigned)mask << bit_pos)); + gen_op('&'); + gen_op('|'); + /* store result */ + vstore(); + /* ... and discard */ + vpop(); + } + } else if (dbt == VT_VOID) { + --vtop; + } else { +#ifdef CONFIG_TCC_BCHECK + /* bound check case */ + if (vtop[-1].r & VT_MUSTBOUND) { + vswap(); + gbound(); + vswap(); + } +#endif + rc = RC_INT; + if (is_float(ft)) { + rc = RC_FLOAT; +#ifdef TCC_TARGET_X86_64 + if ((ft & VT_BTYPE) == VT_LDOUBLE) { + rc = RC_ST0; + } else if ((ft & VT_BTYPE) == VT_QFLOAT) { + rc = RC_FRET; + } +#endif + } + r = gv(rc); /* generate value */ + /* if lvalue was saved on stack, must read it */ + if ((vtop[-1].r & VT_VALMASK) == VT_LLOCAL) { + SValue sv; + t = get_reg(RC_INT); +#if PTR_SIZE == 8 + sv.type.t = VT_PTR; +#else + sv.type.t = VT_INT; +#endif + sv.r = VT_LOCAL | VT_LVAL; + sv.c.i = vtop[-1].c.i; + load(t, &sv); + vtop[-1].r = t | VT_LVAL; + } + /* two word case handling : store second register at word + 4 (or +8 for x86-64) */ +#if PTR_SIZE == 8 + if (((ft & VT_BTYPE) == VT_QLONG) || ((ft & VT_BTYPE) == VT_QFLOAT)) { + int addr_type = VT_LLONG, load_size = 8, load_type = ((vtop->type.t & VT_BTYPE) == VT_QLONG) ? VT_LLONG : VT_DOUBLE; +#else + if ((ft & VT_BTYPE) == VT_LLONG) { + int addr_type = VT_INT, load_size = 4, load_type = VT_INT; +#endif + vtop[-1].type.t = load_type; + store(r, vtop - 1); + vswap(); + /* convert to int to increment easily */ + vtop->type.t = addr_type; + gaddrof(); + vpushi(load_size); + gen_op('+'); + vtop->r |= VT_LVAL; + vswap(); + vtop[-1].type.t = load_type; + /* XXX: it works because r2 is spilled last ! */ + store(vtop->r2, vtop - 1); + } else { + store(r, vtop - 1); + } + + vswap(); + vtop--; /* NOT vpop() because on x86 it would flush the fp stack */ + vtop->r |= delayed_cast; + } +} + +/* post defines POST/PRE add. c is the token ++ or -- */ +ST_FUNC void inc(int post, int c) +{ + test_lvalue(); + vdup(); /* save lvalue */ + if (post) { + gv_dup(); /* duplicate value */ + vrotb(3); + vrotb(3); + } + /* add constant */ + vpushi(c - TOK_MID); + gen_op('+'); + vstore(); /* store value */ + if (post) + vpop(); /* if post op, return saved value */ +} + +ST_FUNC void parse_mult_str (CString *astr, const char *msg) +{ + /* read the string */ + if (tok != TOK_STR) + expect(msg); + cstr_new(astr); + while (tok == TOK_STR) { + /* XXX: add \0 handling too ? */ + cstr_cat(astr, tokc.str.data, -1); + next(); + } + cstr_ccat(astr, '\0'); +} + +/* If I is >= 1 and a power of two, returns log2(i)+1. + If I is 0 returns 0. */ +static int exact_log2p1(int i) +{ + int ret; + if (!i) + return 0; + for (ret = 1; i >= 1 << 8; ret += 8) + i >>= 8; + if (i >= 1 << 4) + ret += 4, i >>= 4; + if (i >= 1 << 2) + ret += 2, i >>= 2; + if (i >= 1 << 1) + ret++; + return ret; +} + +/* Parse __attribute__((...)) GNUC extension. */ +static void parse_attribute(AttributeDef *ad) +{ + int t, n; + CString astr; + +redo: + if (tok != TOK_ATTRIBUTE1 && tok != TOK_ATTRIBUTE2) + return; + next(); + skip('('); + skip('('); + while (tok != ')') { + if (tok < TOK_IDENT) + expect("attribute name"); + t = tok; + next(); + switch(t) { + case TOK_SECTION1: + case TOK_SECTION2: + skip('('); + parse_mult_str(&astr, "section name"); + ad->section = find_section(tcc_state, (char *)astr.data); + skip(')'); + cstr_free(&astr); + break; + case TOK_ALIAS1: + case TOK_ALIAS2: + skip('('); + parse_mult_str(&astr, "alias(\"target\")"); + ad->alias_target = /* save string as token, for later */ + tok_alloc((char*)astr.data, astr.size-1)->tok; + skip(')'); + cstr_free(&astr); + break; + case TOK_VISIBILITY1: + case TOK_VISIBILITY2: + skip('('); + parse_mult_str(&astr, + "visibility(\"default|hidden|internal|protected\")"); + if (!strcmp (astr.data, "default")) + ad->a.visibility = STV_DEFAULT; + else if (!strcmp (astr.data, "hidden")) + ad->a.visibility = STV_HIDDEN; + else if (!strcmp (astr.data, "internal")) + ad->a.visibility = STV_INTERNAL; + else if (!strcmp (astr.data, "protected")) + ad->a.visibility = STV_PROTECTED; + else + expect("visibility(\"default|hidden|internal|protected\")"); + skip(')'); + cstr_free(&astr); + break; + case TOK_ALIGNED1: + case TOK_ALIGNED2: + if (tok == '(') { + next(); + n = expr_const(); + if (n <= 0 || (n & (n - 1)) != 0) + tcc_error("alignment must be a positive power of two"); + skip(')'); + } else { + n = MAX_ALIGN; + } + ad->a.aligned = exact_log2p1(n); + if (n != 1 << (ad->a.aligned - 1)) + tcc_error("alignment of %d is larger than implemented", n); + break; + case TOK_PACKED1: + case TOK_PACKED2: + ad->a.packed = 1; + break; + case TOK_WEAK1: + case TOK_WEAK2: + ad->a.weak = 1; + break; + case TOK_UNUSED1: + case TOK_UNUSED2: + /* currently, no need to handle it because tcc does not + track unused objects */ + break; + case TOK_NORETURN1: + case TOK_NORETURN2: + /* currently, no need to handle it because tcc does not + track unused objects */ + break; + case TOK_CDECL1: + case TOK_CDECL2: + case TOK_CDECL3: + ad->f.func_call = FUNC_CDECL; + break; + case TOK_STDCALL1: + case TOK_STDCALL2: + case TOK_STDCALL3: + ad->f.func_call = FUNC_STDCALL; + break; +#ifdef TCC_TARGET_I386 + case TOK_REGPARM1: + case TOK_REGPARM2: + skip('('); + n = expr_const(); + if (n > 3) + n = 3; + else if (n < 0) + n = 0; + if (n > 0) + ad->f.func_call = FUNC_FASTCALL1 + n - 1; + skip(')'); + break; + case TOK_FASTCALL1: + case TOK_FASTCALL2: + case TOK_FASTCALL3: + ad->f.func_call = FUNC_FASTCALLW; + break; +#endif + case TOK_MODE: + skip('('); + switch(tok) { + case TOK_MODE_DI: + ad->attr_mode = VT_LLONG + 1; + break; + case TOK_MODE_QI: + ad->attr_mode = VT_BYTE + 1; + break; + case TOK_MODE_HI: + ad->attr_mode = VT_SHORT + 1; + break; + case TOK_MODE_SI: + case TOK_MODE_word: + ad->attr_mode = VT_INT + 1; + break; + default: + tcc_warning("__mode__(%s) not supported\n", get_tok_str(tok, NULL)); + break; + } + next(); + skip(')'); + break; + case TOK_DLLEXPORT: + ad->a.dllexport = 1; + break; + case TOK_DLLIMPORT: + ad->a.dllimport = 1; + break; + default: + if (tcc_state->warn_unsupported) + tcc_warning("'%s' attribute ignored", get_tok_str(t, NULL)); + /* skip parameters */ + if (tok == '(') { + int parenthesis = 0; + do { + if (tok == '(') + parenthesis++; + else if (tok == ')') + parenthesis--; + next(); + } while (parenthesis && tok != -1); + } + break; + } + if (tok != ',') + break; + next(); + } + skip(')'); + skip(')'); + goto redo; +} + +static Sym * find_field (CType *type, int v) +{ + Sym *s = type->ref; + v |= SYM_FIELD; + while ((s = s->next) != NULL) { + if ((s->v & SYM_FIELD) && + (s->type.t & VT_BTYPE) == VT_STRUCT && + (s->v & ~SYM_FIELD) >= SYM_FIRST_ANOM) { + Sym *ret = find_field (&s->type, v); + if (ret) + return ret; + } + if (s->v == v) + break; + } + return s; +} + +static void struct_add_offset (Sym *s, int offset) +{ + while ((s = s->next) != NULL) { + if ((s->v & SYM_FIELD) && + (s->type.t & VT_BTYPE) == VT_STRUCT && + (s->v & ~SYM_FIELD) >= SYM_FIRST_ANOM) { + struct_add_offset(s->type.ref, offset); + } else + s->c += offset; + } +} + +static void struct_layout(CType *type, AttributeDef *ad) +{ + int size, align, maxalign, offset, c, bit_pos, bit_size; + int packed, a, bt, prevbt, prev_bit_size; + int pcc = !tcc_state->ms_bitfields; + int pragma_pack = *tcc_state->pack_stack_ptr; + Sym *f; + + maxalign = 1; + offset = 0; + c = 0; + bit_pos = 0; + prevbt = VT_STRUCT; /* make it never match */ + prev_bit_size = 0; + +//#define BF_DEBUG + + for (f = type->ref->next; f; f = f->next) { + if (f->type.t & VT_BITFIELD) + bit_size = BIT_SIZE(f->type.t); + else + bit_size = -1; + size = type_size(&f->type, &align); + a = f->a.aligned ? 1 << (f->a.aligned - 1) : 0; + packed = 0; + + if (pcc && bit_size == 0) { + /* in pcc mode, packing does not affect zero-width bitfields */ + + } else { + /* in pcc mode, attribute packed overrides if set. */ + if (pcc && (f->a.packed || ad->a.packed)) + align = packed = 1; + + /* pragma pack overrides align if lesser and packs bitfields always */ + if (pragma_pack) { + packed = 1; + if (pragma_pack < align) + align = pragma_pack; + /* in pcc mode pragma pack also overrides individual align */ + if (pcc && pragma_pack < a) + a = 0; + } + } + /* some individual align was specified */ + if (a) + align = a; + + if (type->ref->type.t == VT_UNION) { + if (pcc && bit_size >= 0) + size = (bit_size + 7) >> 3; + offset = 0; + if (size > c) + c = size; + + } else if (bit_size < 0) { + if (pcc) + c += (bit_pos + 7) >> 3; + c = (c + align - 1) & -align; + offset = c; + if (size > 0) + c += size; + bit_pos = 0; + prevbt = VT_STRUCT; + prev_bit_size = 0; + + } else { + /* A bit-field. Layout is more complicated. There are two + options: PCC (GCC) compatible and MS compatible */ + if (pcc) { + /* In PCC layout a bit-field is placed adjacent to the + preceding bit-fields, except if: + - it has zero-width + - an individual alignment was given + - it would overflow its base type container and + there is no packing */ + if (bit_size == 0) { + new_field: + c = (c + ((bit_pos + 7) >> 3) + align - 1) & -align; + bit_pos = 0; + } else if (f->a.aligned) { + goto new_field; + } else if (!packed) { + int a8 = align * 8; + int ofs = ((c * 8 + bit_pos) % a8 + bit_size + a8 - 1) / a8; + if (ofs > size / align) + goto new_field; + } + + /* in pcc mode, long long bitfields have type int if they fit */ + if (size == 8 && bit_size <= 32) + f->type.t = (f->type.t & ~VT_BTYPE) | VT_INT, size = 4; + + while (bit_pos >= align * 8) + c += align, bit_pos -= align * 8; + offset = c; + + /* In PCC layout named bit-fields influence the alignment + of the containing struct using the base types alignment, + except for packed fields (which here have correct align). */ + if (f->v & SYM_FIRST_ANOM + // && bit_size // ??? gcc on ARM/rpi does that + ) + align = 1; + + } else { + bt = f->type.t & VT_BTYPE; + if ((bit_pos + bit_size > size * 8) + || (bit_size > 0) == (bt != prevbt) + ) { + c = (c + align - 1) & -align; + offset = c; + bit_pos = 0; + /* In MS bitfield mode a bit-field run always uses + at least as many bits as the underlying type. + To start a new run it's also required that this + or the last bit-field had non-zero width. */ + if (bit_size || prev_bit_size) + c += size; + } + /* In MS layout the records alignment is normally + influenced by the field, except for a zero-width + field at the start of a run (but by further zero-width + fields it is again). */ + if (bit_size == 0 && prevbt != bt) + align = 1; + prevbt = bt; + prev_bit_size = bit_size; + } + + f->type.t = (f->type.t & ~(0x3f << VT_STRUCT_SHIFT)) + | (bit_pos << VT_STRUCT_SHIFT); + bit_pos += bit_size; + } + if (align > maxalign) + maxalign = align; + +#ifdef BF_DEBUG + printf("set field %s offset %-2d size %-2d align %-2d", + get_tok_str(f->v & ~SYM_FIELD, NULL), offset, size, align); + if (f->type.t & VT_BITFIELD) { + printf(" pos %-2d bits %-2d", + BIT_POS(f->type.t), + BIT_SIZE(f->type.t) + ); + } + printf("\n"); +#endif + + if (f->v & SYM_FIRST_ANOM && (f->type.t & VT_BTYPE) == VT_STRUCT) { + Sym *ass; + /* An anonymous struct/union. Adjust member offsets + to reflect the real offset of our containing struct. + Also set the offset of this anon member inside + the outer struct to be zero. Via this it + works when accessing the field offset directly + (from base object), as well as when recursing + members in initializer handling. */ + int v2 = f->type.ref->v; + if (!(v2 & SYM_FIELD) && + (v2 & ~SYM_STRUCT) < SYM_FIRST_ANOM) { + Sym **pps; + /* This happens only with MS extensions. The + anon member has a named struct type, so it + potentially is shared with other references. + We need to unshare members so we can modify + them. */ + ass = f->type.ref; + f->type.ref = sym_push(anon_sym++ | SYM_FIELD, + &f->type.ref->type, 0, + f->type.ref->c); + pps = &f->type.ref->next; + while ((ass = ass->next) != NULL) { + *pps = sym_push(ass->v, &ass->type, 0, ass->c); + pps = &((*pps)->next); + } + *pps = NULL; + } + struct_add_offset(f->type.ref, offset); + f->c = 0; + } else { + f->c = offset; + } + + f->r = 0; + } + + if (pcc) + c += (bit_pos + 7) >> 3; + + /* store size and alignment */ + a = bt = ad->a.aligned ? 1 << (ad->a.aligned - 1) : 1; + if (a < maxalign) + a = maxalign; + type->ref->r = a; + if (pragma_pack && pragma_pack < maxalign && 0 == pcc) { + /* can happen if individual align for some member was given. In + this case MSVC ignores maxalign when aligning the size */ + a = pragma_pack; + if (a < bt) + a = bt; + } + c = (c + a - 1) & -a; + type->ref->c = c; + +#ifdef BF_DEBUG + printf("struct size %-2d align %-2d\n\n", c, a), fflush(stdout); +#endif + + /* check whether we can access bitfields by their type */ + for (f = type->ref->next; f; f = f->next) { + int s, px, cx, c0; + CType t; + + if (0 == (f->type.t & VT_BITFIELD)) + continue; + f->type.ref = f; + f->auxtype = -1; + bit_size = BIT_SIZE(f->type.t); + if (bit_size == 0) + continue; + bit_pos = BIT_POS(f->type.t); + size = type_size(&f->type, &align); + if (bit_pos + bit_size <= size * 8 && f->c + size <= c) + continue; + + /* try to access the field using a different type */ + c0 = -1, s = align = 1; + for (;;) { + px = f->c * 8 + bit_pos; + cx = (px >> 3) & -align; + px = px - (cx << 3); + if (c0 == cx) + break; + s = (px + bit_size + 7) >> 3; + if (s > 4) { + t.t = VT_LLONG; + } else if (s > 2) { + t.t = VT_INT; + } else if (s > 1) { + t.t = VT_SHORT; + } else { + t.t = VT_BYTE; + } + s = type_size(&t, &align); + c0 = cx; + } + + if (px + bit_size <= s * 8 && cx + s <= c) { + /* update offset and bit position */ + f->c = cx; + bit_pos = px; + f->type.t = (f->type.t & ~(0x3f << VT_STRUCT_SHIFT)) + | (bit_pos << VT_STRUCT_SHIFT); + if (s != size) + f->auxtype = t.t; +#ifdef BF_DEBUG + printf("FIX field %s offset %-2d size %-2d align %-2d " + "pos %-2d bits %-2d\n", + get_tok_str(f->v & ~SYM_FIELD, NULL), + cx, s, align, px, bit_size); +#endif + } else { + /* fall back to load/store single-byte wise */ + f->auxtype = VT_STRUCT; +#ifdef BF_DEBUG + printf("FIX field %s : load byte-wise\n", + get_tok_str(f->v & ~SYM_FIELD, NULL)); +#endif + } + } +} + +/* enum/struct/union declaration. u is VT_ENUM/VT_STRUCT/VT_UNION */ +static void struct_decl(CType *type, int u) +{ + int v, c, size, align, flexible; + int bit_size, bsize, bt; + Sym *s, *ss, **ps; + AttributeDef ad, ad1; + CType type1, btype; + + memset(&ad, 0, sizeof ad); + next(); + parse_attribute(&ad); + if (tok != '{') { + v = tok; + next(); + /* struct already defined ? return it */ + if (v < TOK_IDENT) + expect("struct/union/enum name"); + s = struct_find(v); + if (s && (s->sym_scope == local_scope || tok != '{')) { + if (u == s->type.t) + goto do_decl; + if (u == VT_ENUM && IS_ENUM(s->type.t)) + goto do_decl; + tcc_error("redefinition of '%s'", get_tok_str(v, NULL)); + } + } else { + v = anon_sym++; + } + /* Record the original enum/struct/union token. */ + type1.t = u == VT_ENUM ? u | VT_INT | VT_UNSIGNED : u; + type1.ref = NULL; + /* we put an undefined size for struct/union */ + s = sym_push(v | SYM_STRUCT, &type1, 0, -1); + s->r = 0; /* default alignment is zero as gcc */ +do_decl: + type->t = s->type.t; + type->ref = s; + + if (tok == '{') { + next(); + if (s->c != -1) + tcc_error("struct/union/enum already defined"); + /* cannot be empty */ + /* non empty enums are not allowed */ + ps = &s->next; + if (u == VT_ENUM) { + long long ll = 0, pl = 0, nl = 0; + CType t; + t.ref = s; + /* enum symbols have static storage */ + t.t = VT_INT|VT_STATIC|VT_ENUM_VAL; + for(;;) { + v = tok; + if (v < TOK_UIDENT) + expect("identifier"); + ss = sym_find(v); + if (ss && !local_stack) + tcc_error("redefinition of enumerator '%s'", + get_tok_str(v, NULL)); + next(); + if (tok == '=') { + next(); + ll = expr_const64(); + } + ss = sym_push(v, &t, VT_CONST, 0); + ss->enum_val = ll; + *ps = ss, ps = &ss->next; + if (ll < nl) + nl = ll; + if (ll > pl) + pl = ll; + if (tok != ',') + break; + next(); + ll++; + /* NOTE: we accept a trailing comma */ + if (tok == '}') + break; + } + skip('}'); + /* set integral type of the enum */ + t.t = VT_INT; + if (nl >= 0) { + if (pl != (unsigned)pl) + t.t = (LONG_SIZE==8 ? VT_LLONG|VT_LONG : VT_LLONG); + t.t |= VT_UNSIGNED; + } else if (pl != (int)pl || nl != (int)nl) + t.t = (LONG_SIZE==8 ? VT_LLONG|VT_LONG : VT_LLONG); + s->type.t = type->t = t.t | VT_ENUM; + s->c = 0; + /* set type for enum members */ + for (ss = s->next; ss; ss = ss->next) { + ll = ss->enum_val; + if (ll == (int)ll) /* default is int if it fits */ + continue; + if (t.t & VT_UNSIGNED) { + ss->type.t |= VT_UNSIGNED; + if (ll == (unsigned)ll) + continue; + } + ss->type.t = (ss->type.t & ~VT_BTYPE) + | (LONG_SIZE==8 ? VT_LLONG|VT_LONG : VT_LLONG); + } + } else { + c = 0; + flexible = 0; + while (tok != '}') { + if (!parse_btype(&btype, &ad1)) { + skip(';'); + continue; + } + while (1) { + if (flexible) + tcc_error("flexible array member '%s' not at the end of struct", + get_tok_str(v, NULL)); + bit_size = -1; + v = 0; + type1 = btype; + if (tok != ':') { + if (tok != ';') + type_decl(&type1, &ad1, &v, TYPE_DIRECT); + if (v == 0) { + if ((type1.t & VT_BTYPE) != VT_STRUCT) + expect("identifier"); + else { + int v = btype.ref->v; + if (!(v & SYM_FIELD) && (v & ~SYM_STRUCT) < SYM_FIRST_ANOM) { + if (tcc_state->ms_extensions == 0) + expect("identifier"); + } + } + } + if (type_size(&type1, &align) < 0) { + if ((u == VT_STRUCT) && (type1.t & VT_ARRAY) && c) + flexible = 1; + else + tcc_error("field '%s' has incomplete type", + get_tok_str(v, NULL)); + } + if ((type1.t & VT_BTYPE) == VT_FUNC || + (type1.t & VT_STORAGE)) + tcc_error("invalid type for '%s'", + get_tok_str(v, NULL)); + } + if (tok == ':') { + next(); + bit_size = expr_const(); + /* XXX: handle v = 0 case for messages */ + if (bit_size < 0) + tcc_error("negative width in bit-field '%s'", + get_tok_str(v, NULL)); + if (v && bit_size == 0) + tcc_error("zero width for bit-field '%s'", + get_tok_str(v, NULL)); + parse_attribute(&ad1); + } + size = type_size(&type1, &align); + if (bit_size >= 0) { + bt = type1.t & VT_BTYPE; + if (bt != VT_INT && + bt != VT_BYTE && + bt != VT_SHORT && + bt != VT_BOOL && + bt != VT_LLONG) + tcc_error("bitfields must have scalar type"); + bsize = size * 8; + if (bit_size > bsize) { + tcc_error("width of '%s' exceeds its type", + get_tok_str(v, NULL)); + } else if (bit_size == bsize + && !ad.a.packed && !ad1.a.packed) { + /* no need for bit fields */ + ; + } else if (bit_size == 64) { + tcc_error("field width 64 not implemented"); + } else { + type1.t = (type1.t & ~VT_STRUCT_MASK) + | VT_BITFIELD + | (bit_size << (VT_STRUCT_SHIFT + 6)); + } + } + if (v != 0 || (type1.t & VT_BTYPE) == VT_STRUCT) { + /* Remember we've seen a real field to check + for placement of flexible array member. */ + c = 1; + } + /* If member is a struct or bit-field, enforce + placing into the struct (as anonymous). */ + if (v == 0 && + ((type1.t & VT_BTYPE) == VT_STRUCT || + bit_size >= 0)) { + v = anon_sym++; + } + if (v) { + ss = sym_push(v | SYM_FIELD, &type1, 0, 0); + ss->a = ad1.a; + *ps = ss; + ps = &ss->next; + } + if (tok == ';' || tok == TOK_EOF) + break; + skip(','); + } + skip(';'); + } + skip('}'); + parse_attribute(&ad); + struct_layout(type, &ad); + } + } +} + +static void sym_to_attr(AttributeDef *ad, Sym *s) +{ + if (s->a.aligned && 0 == ad->a.aligned) + ad->a.aligned = s->a.aligned; + if (s->f.func_call && 0 == ad->f.func_call) + ad->f.func_call = s->f.func_call; + if (s->f.func_type && 0 == ad->f.func_type) + ad->f.func_type = s->f.func_type; + if (s->a.packed) + ad->a.packed = 1; +} + +/* Add type qualifiers to a type. If the type is an array then the qualifiers + are added to the element type, copied because it could be a typedef. */ +static void parse_btype_qualify(CType *type, int qualifiers) +{ + while (type->t & VT_ARRAY) { + type->ref = sym_push(SYM_FIELD, &type->ref->type, 0, type->ref->c); + type = &type->ref->type; + } + type->t |= qualifiers; +} + +/* return 0 if no type declaration. otherwise, return the basic type + and skip it. + */ +static int parse_btype(CType *type, AttributeDef *ad) +{ + int t, u, bt, st, type_found, typespec_found, g; + Sym *s; + CType type1; + + memset(ad, 0, sizeof(AttributeDef)); + type_found = 0; + typespec_found = 0; + t = VT_INT; + bt = st = -1; + type->ref = NULL; + + while(1) { + switch(tok) { + case TOK_EXTENSION: + /* currently, we really ignore extension */ + next(); + continue; + + /* basic types */ + case TOK_CHAR: + u = VT_BYTE; + basic_type: + next(); + basic_type1: + if (u == VT_SHORT || u == VT_LONG) { + if (st != -1 || (bt != -1 && bt != VT_INT)) + tmbt: tcc_error("too many basic types"); + st = u; + } else { + if (bt != -1 || (st != -1 && u != VT_INT)) + goto tmbt; + bt = u; + } + if (u != VT_INT) + t = (t & ~(VT_BTYPE|VT_LONG)) | u; + typespec_found = 1; + break; + case TOK_VOID: + u = VT_VOID; + goto basic_type; + case TOK_SHORT: + u = VT_SHORT; + goto basic_type; + case TOK_INT: + u = VT_INT; + goto basic_type; + case TOK_LONG: + if ((t & VT_BTYPE) == VT_DOUBLE) { + t = (t & ~(VT_BTYPE|VT_LONG)) | VT_LDOUBLE; + } else if ((t & (VT_BTYPE|VT_LONG)) == VT_LONG) { + t = (t & ~(VT_BTYPE|VT_LONG)) | VT_LLONG; + } else { + u = VT_LONG; + goto basic_type; + } + next(); + break; +#ifdef TCC_TARGET_ARM64 + case TOK_UINT128: + /* GCC's __uint128_t appears in some Linux header files. Make it a + synonym for long double to get the size and alignment right. */ + u = VT_LDOUBLE; + goto basic_type; +#endif + case TOK_BOOL: + u = VT_BOOL; + goto basic_type; + case TOK_FLOAT: + u = VT_FLOAT; + goto basic_type; + case TOK_DOUBLE: + if ((t & (VT_BTYPE|VT_LONG)) == VT_LONG) { + t = (t & ~(VT_BTYPE|VT_LONG)) | VT_LDOUBLE; + } else { + u = VT_DOUBLE; + goto basic_type; + } + next(); + break; + case TOK_ENUM: + struct_decl(&type1, VT_ENUM); + basic_type2: + u = type1.t; + type->ref = type1.ref; + goto basic_type1; + case TOK_STRUCT: + struct_decl(&type1, VT_STRUCT); + goto basic_type2; + case TOK_UNION: + struct_decl(&type1, VT_UNION); + goto basic_type2; + + /* type modifiers */ + case TOK_CONST1: + case TOK_CONST2: + case TOK_CONST3: + type->t = t; + parse_btype_qualify(type, VT_CONSTANT); + t = type->t; + next(); + break; + case TOK_VOLATILE1: + case TOK_VOLATILE2: + case TOK_VOLATILE3: + type->t = t; + parse_btype_qualify(type, VT_VOLATILE); + t = type->t; + next(); + break; + case TOK_SIGNED1: + case TOK_SIGNED2: + case TOK_SIGNED3: + if ((t & (VT_DEFSIGN|VT_UNSIGNED)) == (VT_DEFSIGN|VT_UNSIGNED)) + tcc_error("signed and unsigned modifier"); + t |= VT_DEFSIGN; + next(); + typespec_found = 1; + break; + case TOK_REGISTER: + case TOK_AUTO: + case TOK_RESTRICT1: + case TOK_RESTRICT2: + case TOK_RESTRICT3: + next(); + break; + case TOK_UNSIGNED: + if ((t & (VT_DEFSIGN|VT_UNSIGNED)) == VT_DEFSIGN) + tcc_error("signed and unsigned modifier"); + t |= VT_DEFSIGN | VT_UNSIGNED; + next(); + typespec_found = 1; + break; + + /* storage */ + case TOK_EXTERN: + g = VT_EXTERN; + goto storage; + case TOK_STATIC: + g = VT_STATIC; + goto storage; + case TOK_TYPEDEF: + g = VT_TYPEDEF; + goto storage; + storage: + if (t & (VT_EXTERN|VT_STATIC|VT_TYPEDEF) & ~g) + tcc_error("multiple storage classes"); + t |= g; + next(); + break; + case TOK_INLINE1: + case TOK_INLINE2: + case TOK_INLINE3: + t |= VT_INLINE; + next(); + break; + + /* GNUC attribute */ + case TOK_ATTRIBUTE1: + case TOK_ATTRIBUTE2: + parse_attribute(ad); + if (ad->attr_mode) { + u = ad->attr_mode -1; + t = (t & ~(VT_BTYPE|VT_LONG)) | u; + } + break; + /* GNUC typeof */ + case TOK_TYPEOF1: + case TOK_TYPEOF2: + case TOK_TYPEOF3: + next(); + parse_expr_type(&type1); + /* remove all storage modifiers except typedef */ + type1.t &= ~(VT_STORAGE&~VT_TYPEDEF); + if (type1.ref) + sym_to_attr(ad, type1.ref); + goto basic_type2; + default: + if (typespec_found) + goto the_end; + s = sym_find(tok); + if (!s || !(s->type.t & VT_TYPEDEF)) + goto the_end; + t &= ~(VT_BTYPE|VT_LONG); + u = t & ~(VT_CONSTANT | VT_VOLATILE), t ^= u; + type->t = (s->type.t & ~VT_TYPEDEF) | u; + type->ref = s->type.ref; + if (t) + parse_btype_qualify(type, t); + t = type->t; + /* get attributes from typedef */ + sym_to_attr(ad, s); + next(); + typespec_found = 1; + st = bt = -2; + break; + } + type_found = 1; + } +the_end: + if (tcc_state->char_is_unsigned) { + if ((t & (VT_DEFSIGN|VT_BTYPE)) == VT_BYTE) + t |= VT_UNSIGNED; + } + /* VT_LONG is used just as a modifier for VT_INT / VT_LLONG */ + bt = t & (VT_BTYPE|VT_LONG); + if (bt == VT_LONG) + t |= LONG_SIZE == 8 ? VT_LLONG : VT_INT; +#ifdef TCC_TARGET_PE + if (bt == VT_LDOUBLE) + t = (t & ~(VT_BTYPE|VT_LONG)) | VT_DOUBLE; +#endif + type->t = t; + return type_found; +} + +/* convert a function parameter type (array to pointer and function to + function pointer) */ +static inline void convert_parameter_type(CType *pt) +{ + /* remove const and volatile qualifiers (XXX: const could be used + to indicate a const function parameter */ + pt->t &= ~(VT_CONSTANT | VT_VOLATILE); + /* array must be transformed to pointer according to ANSI C */ + pt->t &= ~VT_ARRAY; + if ((pt->t & VT_BTYPE) == VT_FUNC) { + mk_pointer(pt); + } +} + +ST_FUNC void parse_asm_str(CString *astr) +{ + skip('('); + parse_mult_str(astr, "string constant"); +} + +/* Parse an asm label and return the token */ +static int asm_label_instr(void) +{ + int v; + CString astr; + + next(); + parse_asm_str(&astr); + skip(')'); +#ifdef ASM_DEBUG + printf("asm_alias: \"%s\"\n", (char *)astr.data); +#endif + v = tok_alloc(astr.data, astr.size - 1)->tok; + cstr_free(&astr); + return v; +} + +static int post_type(CType *type, AttributeDef *ad, int storage, int td) +{ + int n, l, t1, arg_size, align; + Sym **plast, *s, *first; + AttributeDef ad1; + CType pt; + + if (tok == '(') { + /* function type, or recursive declarator (return if so) */ + next(); + if (td && !(td & TYPE_ABSTRACT)) + return 0; + if (tok == ')') + l = 0; + else if (parse_btype(&pt, &ad1)) + l = FUNC_NEW; + else if (td) + return 0; + else + l = FUNC_OLD; + first = NULL; + plast = &first; + arg_size = 0; + if (l) { + for(;;) { + /* read param name and compute offset */ + if (l != FUNC_OLD) { + if ((pt.t & VT_BTYPE) == VT_VOID && tok == ')') + break; + type_decl(&pt, &ad1, &n, TYPE_DIRECT | TYPE_ABSTRACT); + if ((pt.t & VT_BTYPE) == VT_VOID) + tcc_error("parameter declared as void"); + arg_size += (type_size(&pt, &align) + PTR_SIZE - 1) / PTR_SIZE; + } else { + n = tok; + if (n < TOK_UIDENT) + expect("identifier"); + pt.t = VT_VOID; /* invalid type */ + next(); + } + convert_parameter_type(&pt); + s = sym_push(n | SYM_FIELD, &pt, 0, 0); + *plast = s; + plast = &s->next; + if (tok == ')') + break; + skip(','); + if (l == FUNC_NEW && tok == TOK_DOTS) { + l = FUNC_ELLIPSIS; + next(); + break; + } + if (l == FUNC_NEW && !parse_btype(&pt, &ad1)) + tcc_error("invalid type"); + } + } else + /* if no parameters, then old type prototype */ + l = FUNC_OLD; + skip(')'); + /* NOTE: const is ignored in returned type as it has a special + meaning in gcc / C++ */ + type->t &= ~VT_CONSTANT; + /* some ancient pre-K&R C allows a function to return an array + and the array brackets to be put after the arguments, such + that "int c()[]" means something like "int[] c()" */ + if (tok == '[') { + next(); + skip(']'); /* only handle simple "[]" */ + mk_pointer(type); + } + /* we push a anonymous symbol which will contain the function prototype */ + ad->f.func_args = arg_size; + ad->f.func_type = l; + s = sym_push(SYM_FIELD, type, 0, 0); + s->a = ad->a; + s->f = ad->f; + s->next = first; + type->t = VT_FUNC; + type->ref = s; + } else if (tok == '[') { + int saved_nocode_wanted = nocode_wanted; + /* array definition */ + next(); + if (tok == TOK_RESTRICT1) + next(); + n = -1; + t1 = 0; + if (tok != ']') { + if (!local_stack || (storage & VT_STATIC)) + vpushi(expr_const()); + else { + /* VLAs (which can only happen with local_stack && !VT_STATIC) + length must always be evaluated, even under nocode_wanted, + so that its size slot is initialized (e.g. under sizeof + or typeof). */ + nocode_wanted = 0; + gexpr(); + } + if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) { + n = vtop->c.i; + if (n < 0) + tcc_error("invalid array size"); + } else { + if (!is_integer_btype(vtop->type.t & VT_BTYPE)) + tcc_error("size of variable length array should be an integer"); + t1 = VT_VLA; + } + } + skip(']'); + /* parse next post type */ + post_type(type, ad, storage, 0); + if (type->t == VT_FUNC) + tcc_error("declaration of an array of functions"); + t1 |= type->t & VT_VLA; + + if (t1 & VT_VLA) { + loc -= type_size(&int_type, &align); + loc &= -align; + n = loc; + + vla_runtime_type_size(type, &align); + gen_op('*'); + vset(&int_type, VT_LOCAL|VT_LVAL, n); + vswap(); + vstore(); + } + if (n != -1) + vpop(); + nocode_wanted = saved_nocode_wanted; + + /* we push an anonymous symbol which will contain the array + element type */ + s = sym_push(SYM_FIELD, type, 0, n); + type->t = (t1 ? VT_VLA : VT_ARRAY) | VT_PTR; + type->ref = s; + } + return 1; +} + +/* Parse a type declarator (except basic type), and return the type + in 'type'. 'td' is a bitmask indicating which kind of type decl is + expected. 'type' should contain the basic type. 'ad' is the + attribute definition of the basic type. It can be modified by + type_decl(). If this (possibly abstract) declarator is a pointer chain + it returns the innermost pointed to type (equals *type, but is a different + pointer), otherwise returns type itself, that's used for recursive calls. */ +static CType *type_decl(CType *type, AttributeDef *ad, int *v, int td) +{ + CType *post, *ret; + int qualifiers, storage; + + /* recursive type, remove storage bits first, apply them later again */ + storage = type->t & VT_STORAGE; + type->t &= ~VT_STORAGE; + post = ret = type; + + while (tok == '*') { + qualifiers = 0; + redo: + next(); + switch(tok) { + case TOK_CONST1: + case TOK_CONST2: + case TOK_CONST3: + qualifiers |= VT_CONSTANT; + goto redo; + case TOK_VOLATILE1: + case TOK_VOLATILE2: + case TOK_VOLATILE3: + qualifiers |= VT_VOLATILE; + goto redo; + case TOK_RESTRICT1: + case TOK_RESTRICT2: + case TOK_RESTRICT3: + goto redo; + /* XXX: clarify attribute handling */ + case TOK_ATTRIBUTE1: + case TOK_ATTRIBUTE2: + parse_attribute(ad); + break; + } + mk_pointer(type); + type->t |= qualifiers; + if (ret == type) + /* innermost pointed to type is the one for the first derivation */ + ret = pointed_type(type); + } + + if (tok == '(') { + /* This is possibly a parameter type list for abstract declarators + ('int ()'), use post_type for testing this. */ + if (!post_type(type, ad, 0, td)) { + /* It's not, so it's a nested declarator, and the post operations + apply to the innermost pointed to type (if any). */ + /* XXX: this is not correct to modify 'ad' at this point, but + the syntax is not clear */ + parse_attribute(ad); + post = type_decl(type, ad, v, td); + skip(')'); + } + } else if (tok >= TOK_IDENT && (td & TYPE_DIRECT)) { + /* type identifier */ + *v = tok; + next(); + } else { + if (!(td & TYPE_ABSTRACT)) + expect("identifier"); + *v = 0; + } + post_type(post, ad, storage, 0); + parse_attribute(ad); + type->t |= storage; + return ret; +} + +/* compute the lvalue VT_LVAL_xxx needed to match type t. */ +ST_FUNC int lvalue_type(int t) +{ + int bt, r; + r = VT_LVAL; + bt = t & VT_BTYPE; + if (bt == VT_BYTE || bt == VT_BOOL) + r |= VT_LVAL_BYTE; + else if (bt == VT_SHORT) + r |= VT_LVAL_SHORT; + else + return r; + if (t & VT_UNSIGNED) + r |= VT_LVAL_UNSIGNED; + return r; +} + +/* indirection with full error checking and bound check */ +ST_FUNC void indir(void) +{ + if ((vtop->type.t & VT_BTYPE) != VT_PTR) { + if ((vtop->type.t & VT_BTYPE) == VT_FUNC) + return; + expect("pointer"); + } + if (vtop->r & VT_LVAL) + gv(RC_INT); + vtop->type = *pointed_type(&vtop->type); + /* Arrays and functions are never lvalues */ + if (!(vtop->type.t & VT_ARRAY) && !(vtop->type.t & VT_VLA) + && (vtop->type.t & VT_BTYPE) != VT_FUNC) { + vtop->r |= lvalue_type(vtop->type.t); + /* if bound checking, the referenced pointer must be checked */ +#ifdef CONFIG_TCC_BCHECK + if (tcc_state->do_bounds_check) + vtop->r |= VT_MUSTBOUND; +#endif + } +} + +/* pass a parameter to a function and do type checking and casting */ +static void gfunc_param_typed(Sym *func, Sym *arg) +{ + int func_type; + CType type; + + func_type = func->f.func_type; + if (func_type == FUNC_OLD || + (func_type == FUNC_ELLIPSIS && arg == NULL)) { + /* default casting : only need to convert float to double */ + if ((vtop->type.t & VT_BTYPE) == VT_FLOAT) { + gen_cast_s(VT_DOUBLE); + } else if (vtop->type.t & VT_BITFIELD) { + type.t = vtop->type.t & (VT_BTYPE | VT_UNSIGNED); + type.ref = vtop->type.ref; + gen_cast(&type); + } + } else if (arg == NULL) { + tcc_error("too many arguments to function"); + } else { + type = arg->type; + type.t &= ~VT_CONSTANT; /* need to do that to avoid false warning */ + gen_assign_cast(&type); + } +} + +/* parse an expression and return its type without any side effect. */ +static void expr_type(CType *type, void (*expr_fn)(void)) +{ + nocode_wanted++; + expr_fn(); + *type = vtop->type; + vpop(); + nocode_wanted--; +} + +/* parse an expression of the form '(type)' or '(expr)' and return its + type */ +static void parse_expr_type(CType *type) +{ + int n; + AttributeDef ad; + + skip('('); + if (parse_btype(type, &ad)) { + type_decl(type, &ad, &n, TYPE_ABSTRACT); + } else { + expr_type(type, gexpr); + } + skip(')'); +} + +static void parse_type(CType *type) +{ + AttributeDef ad; + int n; + + if (!parse_btype(type, &ad)) { + expect("type"); + } + type_decl(type, &ad, &n, TYPE_ABSTRACT); +} + +static void parse_builtin_params(int nc, const char *args) +{ + char c, sep = '('; + CType t; + if (nc) + nocode_wanted++; + next(); + while ((c = *args++)) { + skip(sep); + sep = ','; + switch (c) { + case 'e': expr_eq(); continue; + case 't': parse_type(&t); vpush(&t); continue; + default: tcc_error("internal error"); break; + } + } + skip(')'); + if (nc) + nocode_wanted--; +} + +ST_FUNC void unary(void) +{ + int n, t, align, size, r, sizeof_caller; + CType type; + Sym *s; + AttributeDef ad; + + sizeof_caller = in_sizeof; + in_sizeof = 0; + type.ref = NULL; + /* XXX: GCC 2.95.3 does not generate a table although it should be + better here */ + tok_next: + switch(tok) { + case TOK_EXTENSION: + next(); + goto tok_next; + case TOK_LCHAR: +#ifdef TCC_TARGET_PE + t = VT_SHORT|VT_UNSIGNED; + goto push_tokc; +#endif + case TOK_CINT: + case TOK_CCHAR: + t = VT_INT; + push_tokc: + type.t = t; + vsetc(&type, VT_CONST, &tokc); + next(); + break; + case TOK_CUINT: + t = VT_INT | VT_UNSIGNED; + goto push_tokc; + case TOK_CLLONG: + t = VT_LLONG; + goto push_tokc; + case TOK_CULLONG: + t = VT_LLONG | VT_UNSIGNED; + goto push_tokc; + case TOK_CFLOAT: + t = VT_FLOAT; + goto push_tokc; + case TOK_CDOUBLE: + t = VT_DOUBLE; + goto push_tokc; + case TOK_CLDOUBLE: + t = VT_LDOUBLE; + goto push_tokc; + case TOK_CLONG: + t = (LONG_SIZE == 8 ? VT_LLONG : VT_INT) | VT_LONG; + goto push_tokc; + case TOK_CULONG: + t = (LONG_SIZE == 8 ? VT_LLONG : VT_INT) | VT_LONG | VT_UNSIGNED; + goto push_tokc; + case TOK___FUNCTION__: + if (!gnu_ext) + goto tok_identifier; + /* fall thru */ + case TOK___FUNC__: + { + void *ptr; + int len; + /* special function name identifier */ + len = strlen(funcname) + 1; + /* generate char[len] type */ + type.t = VT_BYTE; + mk_pointer(&type); + type.t |= VT_ARRAY; + type.ref->c = len; + vpush_ref(&type, data_section, data_section->data_offset, len); + if (!NODATA_WANTED) { + ptr = section_ptr_add(data_section, len); + memcpy(ptr, funcname, len); + } + next(); + } + break; + case TOK_LSTR: +#ifdef TCC_TARGET_PE + t = VT_SHORT | VT_UNSIGNED; +#else + t = VT_INT; +#endif + goto str_init; + case TOK_STR: + /* string parsing */ + t = VT_BYTE; + if (tcc_state->char_is_unsigned) + t = VT_BYTE | VT_UNSIGNED; + str_init: + if (tcc_state->warn_write_strings) + t |= VT_CONSTANT; + type.t = t; + mk_pointer(&type); + type.t |= VT_ARRAY; + memset(&ad, 0, sizeof(AttributeDef)); + decl_initializer_alloc(&type, &ad, VT_CONST, 2, 0, 0); + break; + case '(': + next(); + /* cast ? */ + if (parse_btype(&type, &ad)) { + type_decl(&type, &ad, &n, TYPE_ABSTRACT); + skip(')'); + /* check ISOC99 compound literal */ + if (tok == '{') { + /* data is allocated locally by default */ + if (global_expr) + r = VT_CONST; + else + r = VT_LOCAL; + /* all except arrays are lvalues */ + if (!(type.t & VT_ARRAY)) + r |= lvalue_type(type.t); + memset(&ad, 0, sizeof(AttributeDef)); + decl_initializer_alloc(&type, &ad, r, 1, 0, 0); + } else { + if (sizeof_caller) { + vpush(&type); + return; + } + unary(); + gen_cast(&type); + } + } else if (tok == '{') { + int saved_nocode_wanted = nocode_wanted; + if (const_wanted) + tcc_error("expected constant"); + /* save all registers */ + save_regs(0); + /* statement expression : we do not accept break/continue + inside as GCC does. We do retain the nocode_wanted state, + as statement expressions can't ever be entered from the + outside, so any reactivation of code emission (from labels + or loop heads) can be disabled again after the end of it. */ + block(NULL, NULL, 1); + nocode_wanted = saved_nocode_wanted; + skip(')'); + } else { + gexpr(); + skip(')'); + } + break; + case '*': + next(); + unary(); + indir(); + break; + case '&': + next(); + unary(); + /* functions names must be treated as function pointers, + except for unary '&' and sizeof. Since we consider that + functions are not lvalues, we only have to handle it + there and in function calls. */ + /* arrays can also be used although they are not lvalues */ + if ((vtop->type.t & VT_BTYPE) != VT_FUNC && + !(vtop->type.t & VT_ARRAY)) + test_lvalue(); + mk_pointer(&vtop->type); + gaddrof(); + break; + case '!': + next(); + unary(); + if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) { + gen_cast_s(VT_BOOL); + vtop->c.i = !vtop->c.i; + } else if ((vtop->r & VT_VALMASK) == VT_CMP) + vtop->c.i ^= 1; + else { + save_regs(1); + vseti(VT_JMP, gvtst(1, 0)); + } + break; + case '~': + next(); + unary(); + vpushi(-1); + gen_op('^'); + break; + case '+': + next(); + unary(); + if ((vtop->type.t & VT_BTYPE) == VT_PTR) + tcc_error("pointer not accepted for unary plus"); + /* In order to force cast, we add zero, except for floating point + where we really need an noop (otherwise -0.0 will be transformed + into +0.0). */ + if (!is_float(vtop->type.t)) { + vpushi(0); + gen_op('+'); + } + break; + case TOK_SIZEOF: + case TOK_ALIGNOF1: + case TOK_ALIGNOF2: + t = tok; + next(); + in_sizeof++; + expr_type(&type, unary); /* Perform a in_sizeof = 0; */ + s = vtop[1].sym; /* hack: accessing previous vtop */ + size = type_size(&type, &align); + if (s && s->a.aligned) + align = 1 << (s->a.aligned - 1); + if (t == TOK_SIZEOF) { + if (!(type.t & VT_VLA)) { + if (size < 0) + tcc_error("sizeof applied to an incomplete type"); + vpushs(size); + } else { + vla_runtime_type_size(&type, &align); + } + } else { + vpushs(align); + } + vtop->type.t |= VT_UNSIGNED; + break; + + case TOK_builtin_expect: + /* __builtin_expect is a no-op for now */ + parse_builtin_params(0, "ee"); + vpop(); + break; + case TOK_builtin_types_compatible_p: + parse_builtin_params(0, "tt"); + vtop[-1].type.t &= ~(VT_CONSTANT | VT_VOLATILE); + vtop[0].type.t &= ~(VT_CONSTANT | VT_VOLATILE); + n = is_compatible_types(&vtop[-1].type, &vtop[0].type); + vtop -= 2; + vpushi(n); + break; + case TOK_builtin_choose_expr: + { + int64_t c; + next(); + skip('('); + c = expr_const64(); + skip(','); + if (!c) { + nocode_wanted++; + } + expr_eq(); + if (!c) { + vpop(); + nocode_wanted--; + } + skip(','); + if (c) { + nocode_wanted++; + } + expr_eq(); + if (c) { + vpop(); + nocode_wanted--; + } + skip(')'); + } + break; + case TOK_builtin_constant_p: + parse_builtin_params(1, "e"); + n = (vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST; + vtop--; + vpushi(n); + break; + case TOK_builtin_frame_address: + case TOK_builtin_return_address: + { + int tok1 = tok; + int level; + next(); + skip('('); + if (tok != TOK_CINT) { + tcc_error("%s only takes positive integers", + tok1 == TOK_builtin_return_address ? + "__builtin_return_address" : + "__builtin_frame_address"); + } + level = (uint32_t)tokc.i; + next(); + skip(')'); + type.t = VT_VOID; + mk_pointer(&type); + vset(&type, VT_LOCAL, 0); /* local frame */ + while (level--) { + mk_pointer(&vtop->type); + indir(); /* -> parent frame */ + } + if (tok1 == TOK_builtin_return_address) { + // assume return address is just above frame pointer on stack + vpushi(PTR_SIZE); + gen_op('+'); + mk_pointer(&vtop->type); + indir(); + } + } + break; +#ifdef TCC_TARGET_X86_64 +#ifdef TCC_TARGET_PE + case TOK_builtin_va_start: + parse_builtin_params(0, "ee"); + r = vtop->r & VT_VALMASK; + if (r == VT_LLOCAL) + r = VT_LOCAL; + if (r != VT_LOCAL) + tcc_error("__builtin_va_start expects a local variable"); + vtop->r = r; + vtop->type = char_pointer_type; + vtop->c.i += 8; + vstore(); + break; +#else + case TOK_builtin_va_arg_types: + parse_builtin_params(0, "t"); + vpushi(classify_x86_64_va_arg(&vtop->type)); + vswap(); + vpop(); + break; +#endif +#endif + +#ifdef TCC_TARGET_ARM64 + case TOK___va_start: { + parse_builtin_params(0, "ee"); + //xx check types + gen_va_start(); + vpushi(0); + vtop->type.t = VT_VOID; + break; + } + case TOK___va_arg: { + parse_builtin_params(0, "et"); + type = vtop->type; + vpop(); + //xx check types + gen_va_arg(&type); + vtop->type = type; + break; + } + case TOK___arm64_clear_cache: { + parse_builtin_params(0, "ee"); + gen_clear_cache(); + vpushi(0); + vtop->type.t = VT_VOID; + break; + } +#endif + /* pre operations */ + case TOK_INC: + case TOK_DEC: + t = tok; + next(); + unary(); + inc(0, t); + break; + case '-': + next(); + unary(); + t = vtop->type.t & VT_BTYPE; + if (is_float(t)) { + /* In IEEE negate(x) isn't subtract(0,x), but rather + subtract(-0, x). */ + vpush(&vtop->type); + if (t == VT_FLOAT) + vtop->c.f = -1.0 * 0.0; + else if (t == VT_DOUBLE) + vtop->c.d = -1.0 * 0.0; + else + vtop->c.ld = -1.0 * 0.0; + } else + vpushi(0); + vswap(); + gen_op('-'); + break; + case TOK_LAND: + if (!gnu_ext) + goto tok_identifier; + next(); + /* allow to take the address of a label */ + if (tok < TOK_UIDENT) + expect("label identifier"); + s = label_find(tok); + if (!s) { + s = label_push(&global_label_stack, tok, LABEL_FORWARD); + } else { + if (s->r == LABEL_DECLARED) + s->r = LABEL_FORWARD; + } + if (!s->type.t) { + s->type.t = VT_VOID; + mk_pointer(&s->type); + s->type.t |= VT_STATIC; + } + vpushsym(&s->type, s); + next(); + break; + + case TOK_GENERIC: + { + CType controlling_type; + int has_default = 0; + int has_match = 0; + int learn = 0; + TokenString *str = NULL; + + next(); + skip('('); + expr_type(&controlling_type, expr_eq); + controlling_type.t &= ~(VT_CONSTANT | VT_VOLATILE | VT_ARRAY); + for (;;) { + learn = 0; + skip(','); + if (tok == TOK_DEFAULT) { + if (has_default) + tcc_error("too many 'default'"); + has_default = 1; + if (!has_match) + learn = 1; + next(); + } else { + AttributeDef ad_tmp; + int itmp; + CType cur_type; + parse_btype(&cur_type, &ad_tmp); + type_decl(&cur_type, &ad_tmp, &itmp, TYPE_ABSTRACT); + if (compare_types(&controlling_type, &cur_type, 0)) { + if (has_match) { + tcc_error("type match twice"); + } + has_match = 1; + learn = 1; + } + } + skip(':'); + if (learn) { + if (str) + tok_str_free(str); + skip_or_save_block(&str); + } else { + skip_or_save_block(NULL); + } + if (tok == ')') + break; + } + if (!str) { + char buf[60]; + type_to_str(buf, sizeof buf, &controlling_type, NULL); + tcc_error("type '%s' does not match any association", buf); + } + begin_macro(str, 1); + next(); + expr_eq(); + if (tok != TOK_EOF) + expect(","); + end_macro(); + next(); + break; + } + // special qnan , snan and infinity values + case TOK___NAN__: + vpush64(VT_DOUBLE, 0x7ff8000000000000ULL); + next(); + break; + case TOK___SNAN__: + vpush64(VT_DOUBLE, 0x7ff0000000000001ULL); + next(); + break; + case TOK___INF__: + vpush64(VT_DOUBLE, 0x7ff0000000000000ULL); + next(); + break; + + default: + tok_identifier: + t = tok; + next(); + if (t < TOK_UIDENT) + expect("identifier"); + s = sym_find(t); + if (!s) { + const char *name = get_tok_str(t, NULL); + if (tok != '(') + tcc_error("'%s' undeclared", name); + /* for simple function calls, we tolerate undeclared + external reference to int() function */ + if (tcc_state->warn_implicit_function_declaration +#ifdef TCC_TARGET_PE + /* people must be warned about using undeclared WINAPI functions + (which usually start with uppercase letter) */ + || (name[0] >= 'A' && name[0] <= 'Z') +#endif + ) + tcc_warning("implicit declaration of function '%s'", name); + s = external_global_sym(t, &func_old_type, 0); + } + + r = s->r; + /* A symbol that has a register is a local register variable, + which starts out as VT_LOCAL value. */ + if ((r & VT_VALMASK) < VT_CONST) + r = (r & ~VT_VALMASK) | VT_LOCAL; + + vset(&s->type, r, s->c); + /* Point to s as backpointer (even without r&VT_SYM). + Will be used by at least the x86 inline asm parser for + regvars. */ + vtop->sym = s; + + if (r & VT_SYM) { + vtop->c.i = 0; + } else if (r == VT_CONST && IS_ENUM_VAL(s->type.t)) { + vtop->c.i = s->enum_val; + } + break; + } + + /* post operations */ + while (1) { + if (tok == TOK_INC || tok == TOK_DEC) { + inc(1, tok); + next(); + } else if (tok == '.' || tok == TOK_ARROW || tok == TOK_CDOUBLE) { + int qualifiers; + /* field */ + if (tok == TOK_ARROW) + indir(); + qualifiers = vtop->type.t & (VT_CONSTANT | VT_VOLATILE); + test_lvalue(); + gaddrof(); + /* expect pointer on structure */ + if ((vtop->type.t & VT_BTYPE) != VT_STRUCT) + expect("struct or union"); + if (tok == TOK_CDOUBLE) + expect("field name"); + next(); + if (tok == TOK_CINT || tok == TOK_CUINT) + expect("field name"); + s = find_field(&vtop->type, tok); + if (!s) + tcc_error("field not found: %s", get_tok_str(tok & ~SYM_FIELD, &tokc)); + /* add field offset to pointer */ + vtop->type = char_pointer_type; /* change type to 'char *' */ + vpushi(s->c); + gen_op('+'); + /* change type to field type, and set to lvalue */ + vtop->type = s->type; + vtop->type.t |= qualifiers; + /* an array is never an lvalue */ + if (!(vtop->type.t & VT_ARRAY)) { + vtop->r |= lvalue_type(vtop->type.t); +#ifdef CONFIG_TCC_BCHECK + /* if bound checking, the referenced pointer must be checked */ + if (tcc_state->do_bounds_check && (vtop->r & VT_VALMASK) != VT_LOCAL) + vtop->r |= VT_MUSTBOUND; +#endif + } + next(); + } else if (tok == '[') { + next(); + gexpr(); + gen_op('+'); + indir(); + skip(']'); + } else if (tok == '(') { + SValue ret; + Sym *sa; + int nb_args, ret_nregs, ret_align, regsize, variadic; + + /* function call */ + if ((vtop->type.t & VT_BTYPE) != VT_FUNC) { + /* pointer test (no array accepted) */ + if ((vtop->type.t & (VT_BTYPE | VT_ARRAY)) == VT_PTR) { + vtop->type = *pointed_type(&vtop->type); + if ((vtop->type.t & VT_BTYPE) != VT_FUNC) + goto error_func; + } else { + error_func: + expect("function pointer"); + } + } else { + vtop->r &= ~VT_LVAL; /* no lvalue */ + } + /* get return type */ + s = vtop->type.ref; + next(); + sa = s->next; /* first parameter */ + nb_args = regsize = 0; + ret.r2 = VT_CONST; + /* compute first implicit argument if a structure is returned */ + if ((s->type.t & VT_BTYPE) == VT_STRUCT) { + variadic = (s->f.func_type == FUNC_ELLIPSIS); + ret_nregs = gfunc_sret(&s->type, variadic, &ret.type, + &ret_align, ®size); + if (!ret_nregs) { + /* get some space for the returned structure */ + size = type_size(&s->type, &align); +#ifdef TCC_TARGET_ARM64 + /* On arm64, a small struct is return in registers. + It is much easier to write it to memory if we know + that we are allowed to write some extra bytes, so + round the allocated space up to a power of 2: */ + if (size < 16) + while (size & (size - 1)) + size = (size | (size - 1)) + 1; +#endif + loc = (loc - size) & -align; + ret.type = s->type; + ret.r = VT_LOCAL | VT_LVAL; + /* pass it as 'int' to avoid structure arg passing + problems */ + vseti(VT_LOCAL, loc); + ret.c = vtop->c; + nb_args++; + } + } else { + ret_nregs = 1; + ret.type = s->type; + } + + if (ret_nregs) { + /* return in register */ + if (is_float(ret.type.t)) { + ret.r = reg_fret(ret.type.t); +#ifdef TCC_TARGET_X86_64 + if ((ret.type.t & VT_BTYPE) == VT_QFLOAT) + ret.r2 = REG_QRET; +#endif + } else { +#ifndef TCC_TARGET_ARM64 +#ifdef TCC_TARGET_X86_64 + if ((ret.type.t & VT_BTYPE) == VT_QLONG) +#else + if ((ret.type.t & VT_BTYPE) == VT_LLONG) +#endif + ret.r2 = REG_LRET; +#endif + ret.r = REG_IRET; + } + ret.c.i = 0; + } + if (tok != ')') { + for(;;) { + expr_eq(); + gfunc_param_typed(s, sa); + nb_args++; + if (sa) + sa = sa->next; + if (tok == ')') + break; + skip(','); + } + } + if (sa) + tcc_error("too few arguments to function"); + skip(')'); + gfunc_call(nb_args); + + /* return value */ + for (r = ret.r + ret_nregs + !ret_nregs; r-- > ret.r;) { + vsetc(&ret.type, r, &ret.c); + vtop->r2 = ret.r2; /* Loop only happens when r2 is VT_CONST */ + } + + /* handle packed struct return */ + if (((s->type.t & VT_BTYPE) == VT_STRUCT) && ret_nregs) { + int addr, offset; + + size = type_size(&s->type, &align); + /* We're writing whole regs often, make sure there's enough + space. Assume register size is power of 2. */ + if (regsize > align) + align = regsize; + loc = (loc - size) & -align; + addr = loc; + offset = 0; + for (;;) { + vset(&ret.type, VT_LOCAL | VT_LVAL, addr + offset); + vswap(); + vstore(); + vtop--; + if (--ret_nregs == 0) + break; + offset += regsize; + } + vset(&s->type, VT_LOCAL | VT_LVAL, addr); + } + } else { + break; + } + } +} + +ST_FUNC void expr_prod(void) +{ + int t; + + unary(); + while (tok == '*' || tok == '/' || tok == '%') { + t = tok; + next(); + unary(); + gen_op(t); + } +} + +ST_FUNC void expr_sum(void) +{ + int t; + + expr_prod(); + while (tok == '+' || tok == '-') { + t = tok; + next(); + expr_prod(); + gen_op(t); + } +} + +static void expr_shift(void) +{ + int t; + + expr_sum(); + while (tok == TOK_SHL || tok == TOK_SAR) { + t = tok; + next(); + expr_sum(); + gen_op(t); + } +} + +static void expr_cmp(void) +{ + int t; + + expr_shift(); + while ((tok >= TOK_ULE && tok <= TOK_GT) || + tok == TOK_ULT || tok == TOK_UGE) { + t = tok; + next(); + expr_shift(); + gen_op(t); + } +} + +static void expr_cmpeq(void) +{ + int t; + + expr_cmp(); + while (tok == TOK_EQ || tok == TOK_NE) { + t = tok; + next(); + expr_cmp(); + gen_op(t); + } +} + +static void expr_and(void) +{ + expr_cmpeq(); + while (tok == '&') { + next(); + expr_cmpeq(); + gen_op('&'); + } +} + +static void expr_xor(void) +{ + expr_and(); + while (tok == '^') { + next(); + expr_and(); + gen_op('^'); + } +} + +static void expr_or(void) +{ + expr_xor(); + while (tok == '|') { + next(); + expr_xor(); + gen_op('|'); + } +} + +static void expr_land(void) +{ + expr_or(); + if (tok == TOK_LAND) { + int t = 0; + for(;;) { + if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) { + gen_cast_s(VT_BOOL); + if (vtop->c.i) { + vpop(); + } else { + nocode_wanted++; + while (tok == TOK_LAND) { + next(); + expr_or(); + vpop(); + } + nocode_wanted--; + if (t) + gsym(t); + gen_cast_s(VT_INT); + break; + } + } else { + if (!t) + save_regs(1); + t = gvtst(1, t); + } + if (tok != TOK_LAND) { + if (t) + vseti(VT_JMPI, t); + else + vpushi(1); + break; + } + next(); + expr_or(); + } + } +} + +static void expr_lor(void) +{ + expr_land(); + if (tok == TOK_LOR) { + int t = 0; + for(;;) { + if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) { + gen_cast_s(VT_BOOL); + if (!vtop->c.i) { + vpop(); + } else { + nocode_wanted++; + while (tok == TOK_LOR) { + next(); + expr_land(); + vpop(); + } + nocode_wanted--; + if (t) + gsym(t); + gen_cast_s(VT_INT); + break; + } + } else { + if (!t) + save_regs(1); + t = gvtst(0, t); + } + if (tok != TOK_LOR) { + if (t) + vseti(VT_JMP, t); + else + vpushi(0); + break; + } + next(); + expr_land(); + } + } +} + +/* Assuming vtop is a value used in a conditional context + (i.e. compared with zero) return 0 if it's false, 1 if + true and -1 if it can't be statically determined. */ +static int condition_3way(void) +{ + int c = -1; + if ((vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST && + (!(vtop->r & VT_SYM) || !vtop->sym->a.weak)) { + vdup(); + gen_cast_s(VT_BOOL); + c = vtop->c.i; + vpop(); + } + return c; +} + +static void expr_cond(void) +{ + int tt, u, r1, r2, rc, t1, t2, bt1, bt2, islv, c, g; + SValue sv; + CType type, type1, type2; + + expr_lor(); + if (tok == '?') { + next(); + c = condition_3way(); + g = (tok == ':' && gnu_ext); + if (c < 0) { + /* needed to avoid having different registers saved in + each branch */ + if (is_float(vtop->type.t)) { + rc = RC_FLOAT; +#ifdef TCC_TARGET_X86_64 + if ((vtop->type.t & VT_BTYPE) == VT_LDOUBLE) { + rc = RC_ST0; + } +#endif + } else + rc = RC_INT; + gv(rc); + save_regs(1); + if (g) + gv_dup(); + tt = gvtst(1, 0); + + } else { + if (!g) + vpop(); + tt = 0; + } + + if (1) { + if (c == 0) + nocode_wanted++; + if (!g) + gexpr(); + + type1 = vtop->type; + sv = *vtop; /* save value to handle it later */ + vtop--; /* no vpop so that FP stack is not flushed */ + skip(':'); + + u = 0; + if (c < 0) + u = gjmp(0); + gsym(tt); + + if (c == 0) + nocode_wanted--; + if (c == 1) + nocode_wanted++; + expr_cond(); + if (c == 1) + nocode_wanted--; + + type2 = vtop->type; + t1 = type1.t; + bt1 = t1 & VT_BTYPE; + t2 = type2.t; + bt2 = t2 & VT_BTYPE; + type.ref = NULL; + + /* cast operands to correct type according to ISOC rules */ + if (is_float(bt1) || is_float(bt2)) { + if (bt1 == VT_LDOUBLE || bt2 == VT_LDOUBLE) { + type.t = VT_LDOUBLE; + + } else if (bt1 == VT_DOUBLE || bt2 == VT_DOUBLE) { + type.t = VT_DOUBLE; + } else { + type.t = VT_FLOAT; + } + } else if (bt1 == VT_LLONG || bt2 == VT_LLONG) { + /* cast to biggest op */ + type.t = VT_LLONG | VT_LONG; + if (bt1 == VT_LLONG) + type.t &= t1; + if (bt2 == VT_LLONG) + type.t &= t2; + /* convert to unsigned if it does not fit in a long long */ + if ((t1 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (VT_LLONG | VT_UNSIGNED) || + (t2 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (VT_LLONG | VT_UNSIGNED)) + type.t |= VT_UNSIGNED; + } else if (bt1 == VT_PTR || bt2 == VT_PTR) { + /* If one is a null ptr constant the result type + is the other. */ + if (is_null_pointer (vtop)) + type = type1; + else if (is_null_pointer (&sv)) + type = type2; + /* XXX: test pointer compatibility, C99 has more elaborate + rules here. */ + else + type = type1; + } else if (bt1 == VT_FUNC || bt2 == VT_FUNC) { + /* XXX: test function pointer compatibility */ + type = bt1 == VT_FUNC ? type1 : type2; + } else if (bt1 == VT_STRUCT || bt2 == VT_STRUCT) { + /* XXX: test structure compatibility */ + type = bt1 == VT_STRUCT ? type1 : type2; + } else if (bt1 == VT_VOID || bt2 == VT_VOID) { + /* NOTE: as an extension, we accept void on only one side */ + type.t = VT_VOID; + } else { + /* integer operations */ + type.t = VT_INT | (VT_LONG & (t1 | t2)); + /* convert to unsigned if it does not fit in an integer */ + if ((t1 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (VT_INT | VT_UNSIGNED) || + (t2 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (VT_INT | VT_UNSIGNED)) + type.t |= VT_UNSIGNED; + } + /* keep structs lvalue by transforming `(expr ? a : b)` to `*(expr ? &a : &b)` so + that `(expr ? a : b).mem` does not error with "lvalue expected" */ + islv = (vtop->r & VT_LVAL) && (sv.r & VT_LVAL) && VT_STRUCT == (type.t & VT_BTYPE); + islv &= c < 0; + + /* now we convert second operand */ + if (c != 1) { + gen_cast(&type); + if (islv) { + mk_pointer(&vtop->type); + gaddrof(); + } else if (VT_STRUCT == (vtop->type.t & VT_BTYPE)) + gaddrof(); + } + + rc = RC_INT; + if (is_float(type.t)) { + rc = RC_FLOAT; +#ifdef TCC_TARGET_X86_64 + if ((type.t & VT_BTYPE) == VT_LDOUBLE) { + rc = RC_ST0; + } +#endif + } else if ((type.t & VT_BTYPE) == VT_LLONG) { + /* for long longs, we use fixed registers to avoid having + to handle a complicated move */ + rc = RC_IRET; + } + + tt = r2 = 0; + if (c < 0) { + r2 = gv(rc); + tt = gjmp(0); + } + gsym(u); + + /* this is horrible, but we must also convert first + operand */ + if (c != 0) { + *vtop = sv; + gen_cast(&type); + if (islv) { + mk_pointer(&vtop->type); + gaddrof(); + } else if (VT_STRUCT == (vtop->type.t & VT_BTYPE)) + gaddrof(); + } + + if (c < 0) { + r1 = gv(rc); + move_reg(r2, r1, type.t); + vtop->r = r2; + gsym(tt); + if (islv) + indir(); + } + } + } +} + +static void expr_eq(void) +{ + int t; + + expr_cond(); + if (tok == '=' || + (tok >= TOK_A_MOD && tok <= TOK_A_DIV) || + tok == TOK_A_XOR || tok == TOK_A_OR || + tok == TOK_A_SHL || tok == TOK_A_SAR) { + test_lvalue(); + t = tok; + next(); + if (t == '=') { + expr_eq(); + } else { + vdup(); + expr_eq(); + gen_op(t & 0x7f); + } + vstore(); + } +} + +ST_FUNC void gexpr(void) +{ + while (1) { + expr_eq(); + if (tok != ',') + break; + vpop(); + next(); + } +} + +/* parse a constant expression and return value in vtop. */ +static void expr_const1(void) +{ + const_wanted++; + nocode_wanted++; + expr_cond(); + nocode_wanted--; + const_wanted--; +} + +/* parse an integer constant and return its value. */ +static inline int64_t expr_const64(void) +{ + int64_t c; + expr_const1(); + if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) != VT_CONST) + expect("constant expression"); + c = vtop->c.i; + vpop(); + return c; +} + +/* parse an integer constant and return its value. + Complain if it doesn't fit 32bit (signed or unsigned). */ +ST_FUNC int expr_const(void) +{ + int c; + int64_t wc = expr_const64(); + c = wc; + if (c != wc && (unsigned)c != wc) + tcc_error("constant exceeds 32 bit"); + return c; +} + +/* return the label token if current token is a label, otherwise + return zero */ +static int is_label(void) +{ + int last_tok; + + /* fast test first */ + if (tok < TOK_UIDENT) + return 0; + /* no need to save tokc because tok is an identifier */ + last_tok = tok; + next(); + if (tok == ':') { + return last_tok; + } else { + unget_tok(last_tok); + return 0; + } +} + +#ifndef TCC_TARGET_ARM64 +static void gfunc_return(CType *func_type) +{ + if ((func_type->t & VT_BTYPE) == VT_STRUCT) { + CType type, ret_type; + int ret_align, ret_nregs, regsize; + ret_nregs = gfunc_sret(func_type, func_var, &ret_type, + &ret_align, ®size); + if (0 == ret_nregs) { + /* if returning structure, must copy it to implicit + first pointer arg location */ + type = *func_type; + mk_pointer(&type); + vset(&type, VT_LOCAL | VT_LVAL, func_vc); + indir(); + vswap(); + /* copy structure value to pointer */ + vstore(); + } else { + /* returning structure packed into registers */ + int r, size, addr, align; + size = type_size(func_type,&align); + if ((vtop->r != (VT_LOCAL | VT_LVAL) || + (vtop->c.i & (ret_align-1))) + && (align & (ret_align-1))) { + loc = (loc - size) & -ret_align; + addr = loc; + type = *func_type; + vset(&type, VT_LOCAL | VT_LVAL, addr); + vswap(); + vstore(); + vpop(); + vset(&ret_type, VT_LOCAL | VT_LVAL, addr); + } + vtop->type = ret_type; + if (is_float(ret_type.t)) + r = rc_fret(ret_type.t); + else + r = RC_IRET; + + if (ret_nregs == 1) + gv(r); + else { + for (;;) { + vdup(); + gv(r); + vpop(); + if (--ret_nregs == 0) + break; + /* We assume that when a structure is returned in multiple + registers, their classes are consecutive values of the + suite s(n) = 2^n */ + r <<= 1; + vtop->c.i += regsize; + } + } + } + } else if (is_float(func_type->t)) { + gv(rc_fret(func_type->t)); + } else { + gv(RC_IRET); + } + vtop--; /* NOT vpop() because on x86 it would flush the fp stack */ +} +#endif + +static int case_cmp(const void *pa, const void *pb) +{ + int64_t a = (*(struct case_t**) pa)->v1; + int64_t b = (*(struct case_t**) pb)->v1; + return a < b ? -1 : a > b; +} + +static void gcase(struct case_t **base, int len, int *bsym) +{ + struct case_t *p; + int e; + int ll = (vtop->type.t & VT_BTYPE) == VT_LLONG; + gv(RC_INT); + while (len > 4) { + /* binary search */ + p = base[len/2]; + vdup(); + if (ll) + vpushll(p->v2); + else + vpushi(p->v2); + gen_op(TOK_LE); + e = gtst(1, 0); + vdup(); + if (ll) + vpushll(p->v1); + else + vpushi(p->v1); + gen_op(TOK_GE); + gtst_addr(0, p->sym); /* v1 <= x <= v2 */ + /* x < v1 */ + gcase(base, len/2, bsym); + if (cur_switch->def_sym) + gjmp_addr(cur_switch->def_sym); + else + *bsym = gjmp(*bsym); + /* x > v2 */ + gsym(e); + e = len/2 + 1; + base += e; len -= e; + } + /* linear scan */ + while (len--) { + p = *base++; + vdup(); + if (ll) + vpushll(p->v2); + else + vpushi(p->v2); + if (p->v1 == p->v2) { + gen_op(TOK_EQ); + gtst_addr(0, p->sym); + } else { + gen_op(TOK_LE); + e = gtst(1, 0); + vdup(); + if (ll) + vpushll(p->v1); + else + vpushi(p->v1); + gen_op(TOK_GE); + gtst_addr(0, p->sym); + gsym(e); + } + } +} + +static void block(int *bsym, int *csym, int is_expr) +{ + int a, b, c, d, cond; + Sym *s; + + /* generate line number info */ + if (tcc_state->do_debug) + tcc_debug_line(tcc_state); + + if (is_expr) { + /* default return value is (void) */ + vpushi(0); + vtop->type.t = VT_VOID; + } + + if (tok == TOK_IF) { + /* if test */ + int saved_nocode_wanted = nocode_wanted; + next(); + skip('('); + gexpr(); + skip(')'); + cond = condition_3way(); + if (cond == 1) + a = 0, vpop(); + else + a = gvtst(1, 0); + if (cond == 0) + nocode_wanted |= 0x20000000; + block(bsym, csym, 0); + if (cond != 1) + nocode_wanted = saved_nocode_wanted; + c = tok; + if (c == TOK_ELSE) { + next(); + d = gjmp(0); + gsym(a); + if (cond == 1) + nocode_wanted |= 0x20000000; + block(bsym, csym, 0); + gsym(d); /* patch else jmp */ + if (cond != 0) + nocode_wanted = saved_nocode_wanted; + } else + gsym(a); + } else if (tok == TOK_WHILE) { + int saved_nocode_wanted; + nocode_wanted &= ~0x20000000; + next(); + d = ind; + vla_sp_restore(); + skip('('); + gexpr(); + skip(')'); + a = gvtst(1, 0); + b = 0; + ++local_scope; + saved_nocode_wanted = nocode_wanted; + block(&a, &b, 0); + nocode_wanted = saved_nocode_wanted; + --local_scope; + gjmp_addr(d); + gsym(a); + gsym_addr(b, d); + } else if (tok == '{') { + Sym *llabel; + int block_vla_sp_loc = vla_sp_loc, saved_vlas_in_scope = vlas_in_scope; + + next(); + /* record local declaration stack position */ + s = local_stack; + llabel = local_label_stack; + ++local_scope; + + /* handle local labels declarations */ + if (tok == TOK_LABEL) { + next(); + for(;;) { + if (tok < TOK_UIDENT) + expect("label identifier"); + label_push(&local_label_stack, tok, LABEL_DECLARED); + next(); + if (tok == ',') { + next(); + } else { + skip(';'); + break; + } + } + } + while (tok != '}') { + if ((a = is_label())) + unget_tok(a); + else + decl(VT_LOCAL); + if (tok != '}') { + if (is_expr) + vpop(); + block(bsym, csym, is_expr); + } + } + /* pop locally defined labels */ + label_pop(&local_label_stack, llabel, is_expr); + /* pop locally defined symbols */ + --local_scope; + /* In the is_expr case (a statement expression is finished here), + vtop might refer to symbols on the local_stack. Either via the + type or via vtop->sym. We can't pop those nor any that in turn + might be referred to. To make it easier we don't roll back + any symbols in that case; some upper level call to block() will + do that. We do have to remove such symbols from the lookup + tables, though. sym_pop will do that. */ + sym_pop(&local_stack, s, is_expr); + + /* Pop VLA frames and restore stack pointer if required */ + if (vlas_in_scope > saved_vlas_in_scope) { + vla_sp_loc = saved_vlas_in_scope ? block_vla_sp_loc : vla_sp_root_loc; + vla_sp_restore(); + } + vlas_in_scope = saved_vlas_in_scope; + + next(); + } else if (tok == TOK_RETURN) { + next(); + if (tok != ';') { + gexpr(); + gen_assign_cast(&func_vt); + if ((func_vt.t & VT_BTYPE) == VT_VOID) + vtop--; + else + gfunc_return(&func_vt); + } + skip(';'); + /* jump unless last stmt in top-level block */ + if (tok != '}' || local_scope != 1) + rsym = gjmp(rsym); + nocode_wanted |= 0x20000000; + } else if (tok == TOK_BREAK) { + /* compute jump */ + if (!bsym) + tcc_error("cannot break"); + *bsym = gjmp(*bsym); + next(); + skip(';'); + nocode_wanted |= 0x20000000; + } else if (tok == TOK_CONTINUE) { + /* compute jump */ + if (!csym) + tcc_error("cannot continue"); + vla_sp_restore_root(); + *csym = gjmp(*csym); + next(); + skip(';'); + } else if (tok == TOK_FOR) { + int e; + int saved_nocode_wanted; + nocode_wanted &= ~0x20000000; + next(); + skip('('); + s = local_stack; + ++local_scope; + if (tok != ';') { + /* c99 for-loop init decl? */ + if (!decl0(VT_LOCAL, 1, NULL)) { + /* no, regular for-loop init expr */ + gexpr(); + vpop(); + } + } + skip(';'); + d = ind; + c = ind; + vla_sp_restore(); + a = 0; + b = 0; + if (tok != ';') { + gexpr(); + a = gvtst(1, 0); + } + skip(';'); + if (tok != ')') { + e = gjmp(0); + c = ind; + vla_sp_restore(); + gexpr(); + vpop(); + gjmp_addr(d); + gsym(e); + } + skip(')'); + saved_nocode_wanted = nocode_wanted; + block(&a, &b, 0); + nocode_wanted = saved_nocode_wanted; + gjmp_addr(c); + gsym(a); + gsym_addr(b, c); + --local_scope; + sym_pop(&local_stack, s, 0); + + } else + if (tok == TOK_DO) { + int saved_nocode_wanted; + nocode_wanted &= ~0x20000000; + next(); + a = 0; + b = 0; + d = ind; + vla_sp_restore(); + saved_nocode_wanted = nocode_wanted; + block(&a, &b, 0); + skip(TOK_WHILE); + skip('('); + gsym(b); + gexpr(); + c = gvtst(0, 0); + gsym_addr(c, d); + nocode_wanted = saved_nocode_wanted; + skip(')'); + gsym(a); + skip(';'); + } else + if (tok == TOK_SWITCH) { + struct switch_t *saved, sw; + int saved_nocode_wanted = nocode_wanted; + SValue switchval; + next(); + skip('('); + gexpr(); + skip(')'); + switchval = *vtop--; + a = 0; + b = gjmp(0); /* jump to first case */ + sw.p = NULL; sw.n = 0; sw.def_sym = 0; + saved = cur_switch; + cur_switch = &sw; + block(&a, csym, 0); + nocode_wanted = saved_nocode_wanted; + a = gjmp(a); /* add implicit break */ + /* case lookup */ + gsym(b); + qsort(sw.p, sw.n, sizeof(void*), case_cmp); + for (b = 1; b < sw.n; b++) + if (sw.p[b - 1]->v2 >= sw.p[b]->v1) + tcc_error("duplicate case value"); + /* Our switch table sorting is signed, so the compared + value needs to be as well when it's 64bit. */ + if ((switchval.type.t & VT_BTYPE) == VT_LLONG) + switchval.type.t &= ~VT_UNSIGNED; + vpushv(&switchval); + gcase(sw.p, sw.n, &a); + vpop(); + if (sw.def_sym) + gjmp_addr(sw.def_sym); + dynarray_reset(&sw.p, &sw.n); + cur_switch = saved; + /* break label */ + gsym(a); + } else + if (tok == TOK_CASE) { + struct case_t *cr = tcc_malloc(sizeof(struct case_t)); + if (!cur_switch) + expect("switch"); + nocode_wanted &= ~0x20000000; + next(); + cr->v1 = cr->v2 = expr_const64(); + if (gnu_ext && tok == TOK_DOTS) { + next(); + cr->v2 = expr_const64(); + if (cr->v2 < cr->v1) + tcc_warning("empty case range"); + } + cr->sym = ind; + dynarray_add(&cur_switch->p, &cur_switch->n, cr); + skip(':'); + is_expr = 0; + goto block_after_label; + } else + if (tok == TOK_DEFAULT) { + next(); + skip(':'); + if (!cur_switch) + expect("switch"); + if (cur_switch->def_sym) + tcc_error("too many 'default'"); + cur_switch->def_sym = ind; + is_expr = 0; + goto block_after_label; + } else + if (tok == TOK_GOTO) { + next(); + if (tok == '*' && gnu_ext) { + /* computed goto */ + next(); + gexpr(); + if ((vtop->type.t & VT_BTYPE) != VT_PTR) + expect("pointer"); + ggoto(); + } else if (tok >= TOK_UIDENT) { + s = label_find(tok); + /* put forward definition if needed */ + if (!s) { + s = label_push(&global_label_stack, tok, LABEL_FORWARD); + } else { + if (s->r == LABEL_DECLARED) + s->r = LABEL_FORWARD; + } + vla_sp_restore_root(); + if (s->r & LABEL_FORWARD) + s->jnext = gjmp(s->jnext); + else + gjmp_addr(s->jnext); + next(); + } else { + expect("label identifier"); + } + skip(';'); + } else if (tok == TOK_ASM1 || tok == TOK_ASM2 || tok == TOK_ASM3) { + asm_instr(); + } else { + b = is_label(); + if (b) { + /* label case */ + next(); + s = label_find(b); + if (s) { + if (s->r == LABEL_DEFINED) + tcc_error("duplicate label '%s'", get_tok_str(s->v, NULL)); + gsym(s->jnext); + s->r = LABEL_DEFINED; + } else { + s = label_push(&global_label_stack, b, LABEL_DEFINED); + } + s->jnext = ind; + vla_sp_restore(); + /* we accept this, but it is a mistake */ + block_after_label: + nocode_wanted &= ~0x20000000; + if (tok == '}') { + tcc_warning("deprecated use of label at end of compound statement"); + } else { + if (is_expr) + vpop(); + block(bsym, csym, is_expr); + } + } else { + /* expression case */ + if (tok != ';') { + if (is_expr) { + vpop(); + gexpr(); + } else { + gexpr(); + vpop(); + } + } + skip(';'); + } + } +} + +/* This skips over a stream of tokens containing balanced {} and () + pairs, stopping at outer ',' ';' and '}' (or matching '}' if we started + with a '{'). If STR then allocates and stores the skipped tokens + in *STR. This doesn't check if () and {} are nested correctly, + i.e. "({)}" is accepted. */ +static void skip_or_save_block(TokenString **str) +{ + int braces = tok == '{'; + int level = 0; + if (str) + *str = tok_str_alloc(); + + while ((level > 0 || (tok != '}' && tok != ',' && tok != ';' && tok != ')'))) { + int t; + if (tok == TOK_EOF) { + if (str || level > 0) + tcc_error("unexpected end of file"); + else + break; + } + if (str) + tok_str_add_tok(*str); + t = tok; + next(); + if (t == '{' || t == '(') { + level++; + } else if (t == '}' || t == ')') { + level--; + if (level == 0 && braces && t == '}') + break; + } + } + if (str) { + tok_str_add(*str, -1); + tok_str_add(*str, 0); + } +} + +#define EXPR_CONST 1 +#define EXPR_ANY 2 + +static void parse_init_elem(int expr_type) +{ + int saved_global_expr; + switch(expr_type) { + case EXPR_CONST: + /* compound literals must be allocated globally in this case */ + saved_global_expr = global_expr; + global_expr = 1; + expr_const1(); + global_expr = saved_global_expr; + /* NOTE: symbols are accepted, as well as lvalue for anon symbols + (compound literals). */ + if (((vtop->r & (VT_VALMASK | VT_LVAL)) != VT_CONST + && ((vtop->r & (VT_SYM|VT_LVAL)) != (VT_SYM|VT_LVAL) + || vtop->sym->v < SYM_FIRST_ANOM)) +#ifdef TCC_TARGET_PE + || ((vtop->r & VT_SYM) && vtop->sym->a.dllimport) +#endif + ) + tcc_error("initializer element is not constant"); + break; + case EXPR_ANY: + expr_eq(); + break; + } +} + +/* put zeros for variable based init */ +static void init_putz(Section *sec, unsigned long c, int size) +{ + if (sec) { + /* nothing to do because globals are already set to zero */ + } else { + vpush_global_sym(&func_old_type, TOK_memset); + vseti(VT_LOCAL, c); +#ifdef TCC_TARGET_ARM + vpushs(size); + vpushi(0); +#else + vpushi(0); + vpushs(size); +#endif + gfunc_call(3); + } +} + +/* t is the array or struct type. c is the array or struct + address. cur_field is the pointer to the current + field, for arrays the 'c' member contains the current start + index. 'size_only' is true if only size info is needed (only used + in arrays). al contains the already initialized length of the + current container (starting at c). This returns the new length of that. */ +static int decl_designator(CType *type, Section *sec, unsigned long c, + Sym **cur_field, int size_only, int al) +{ + Sym *s, *f; + int index, index_last, align, l, nb_elems, elem_size; + unsigned long corig = c; + + elem_size = 0; + nb_elems = 1; + if (gnu_ext && (l = is_label()) != 0) + goto struct_field; + /* NOTE: we only support ranges for last designator */ + while (nb_elems == 1 && (tok == '[' || tok == '.')) { + if (tok == '[') { + if (!(type->t & VT_ARRAY)) + expect("array type"); + next(); + index = index_last = expr_const(); + if (tok == TOK_DOTS && gnu_ext) { + next(); + index_last = expr_const(); + } + skip(']'); + s = type->ref; + if (index < 0 || (s->c >= 0 && index_last >= s->c) || + index_last < index) + tcc_error("invalid index"); + if (cur_field) + (*cur_field)->c = index_last; + type = pointed_type(type); + elem_size = type_size(type, &align); + c += index * elem_size; + nb_elems = index_last - index + 1; + } else { + next(); + l = tok; + struct_field: + next(); + if ((type->t & VT_BTYPE) != VT_STRUCT) + expect("struct/union type"); + f = find_field(type, l); + if (!f) + expect("field"); + if (cur_field) + *cur_field = f; + type = &f->type; + c += f->c; + } + cur_field = NULL; + } + if (!cur_field) { + if (tok == '=') { + next(); + } else if (!gnu_ext) { + expect("="); + } + } else { + if (type->t & VT_ARRAY) { + index = (*cur_field)->c; + if (type->ref->c >= 0 && index >= type->ref->c) + tcc_error("index too large"); + type = pointed_type(type); + c += index * type_size(type, &align); + } else { + f = *cur_field; + while (f && (f->v & SYM_FIRST_ANOM) && (f->type.t & VT_BITFIELD)) + *cur_field = f = f->next; + if (!f) + tcc_error("too many field init"); + type = &f->type; + c += f->c; + } + } + /* must put zero in holes (note that doing it that way + ensures that it even works with designators) */ + if (!size_only && c - corig > al) + init_putz(sec, corig + al, c - corig - al); + decl_initializer(type, sec, c, 0, size_only); + + /* XXX: make it more general */ + if (!size_only && nb_elems > 1) { + unsigned long c_end; + uint8_t *src, *dst; + int i; + + if (!sec) { + vset(type, VT_LOCAL|VT_LVAL, c); + for (i = 1; i < nb_elems; i++) { + vset(type, VT_LOCAL|VT_LVAL, c + elem_size * i); + vswap(); + vstore(); + } + vpop(); + } else if (!NODATA_WANTED) { + c_end = c + nb_elems * elem_size; + if (c_end > sec->data_allocated) + section_realloc(sec, c_end); + src = sec->data + c; + dst = src; + for(i = 1; i < nb_elems; i++) { + dst += elem_size; + memcpy(dst, src, elem_size); + } + } + } + c += nb_elems * type_size(type, &align); + if (c - corig > al) + al = c - corig; + return al; +} + +/* store a value or an expression directly in global data or in local array */ +static void init_putv(CType *type, Section *sec, unsigned long c) +{ + int bt; + void *ptr; + CType dtype; + + dtype = *type; + dtype.t &= ~VT_CONSTANT; /* need to do that to avoid false warning */ + + if (sec) { + int size, align; + /* XXX: not portable */ + /* XXX: generate error if incorrect relocation */ + gen_assign_cast(&dtype); + bt = type->t & VT_BTYPE; + + if ((vtop->r & VT_SYM) + && bt != VT_PTR + && bt != VT_FUNC + && (bt != (PTR_SIZE == 8 ? VT_LLONG : VT_INT) + || (type->t & VT_BITFIELD)) + && !((vtop->r & VT_CONST) && vtop->sym->v >= SYM_FIRST_ANOM) + ) + tcc_error("initializer element is not computable at load time"); + + if (NODATA_WANTED) { + vtop--; + return; + } + + size = type_size(type, &align); + section_reserve(sec, c + size); + ptr = sec->data + c; + + /* XXX: make code faster ? */ + if ((vtop->r & (VT_SYM|VT_CONST)) == (VT_SYM|VT_CONST) && + vtop->sym->v >= SYM_FIRST_ANOM && + /* XXX This rejects compound literals like + '(void *){ptr}'. The problem is that '&sym' is + represented the same way, which would be ruled out + by the SYM_FIRST_ANOM check above, but also '"string"' + in 'char *p = "string"' is represented the same + with the type being VT_PTR and the symbol being an + anonymous one. That is, there's no difference in vtop + between '(void *){x}' and '&(void *){x}'. Ignore + pointer typed entities here. Hopefully no real code + will every use compound literals with scalar type. */ + (vtop->type.t & VT_BTYPE) != VT_PTR) { + /* These come from compound literals, memcpy stuff over. */ + Section *ssec; + ElfW(Sym) *esym; + ElfW_Rel *rel; + esym = &((ElfW(Sym) *)symtab_section->data)[vtop->sym->c]; + ssec = tcc_state->sections[esym->st_shndx]; + memmove (ptr, ssec->data + esym->st_value, size); + if (ssec->reloc) { + /* We need to copy over all memory contents, and that + includes relocations. Use the fact that relocs are + created it order, so look from the end of relocs + until we hit one before the copied region. */ + int num_relocs = ssec->reloc->data_offset / sizeof(*rel); + rel = (ElfW_Rel*)(ssec->reloc->data + ssec->reloc->data_offset); + while (num_relocs--) { + rel--; + if (rel->r_offset >= esym->st_value + size) + continue; + if (rel->r_offset < esym->st_value) + break; + /* Note: if the same fields are initialized multiple + times (possible with designators) then we possibly + add multiple relocations for the same offset here. + That would lead to wrong code, the last reloc needs + to win. We clean this up later after the whole + initializer is parsed. */ + put_elf_reloca(symtab_section, sec, + c + rel->r_offset - esym->st_value, + ELFW(R_TYPE)(rel->r_info), + ELFW(R_SYM)(rel->r_info), +#if PTR_SIZE == 8 + rel->r_addend +#else + 0 +#endif + ); + } + } + } else { + if (type->t & VT_BITFIELD) { + int bit_pos, bit_size, bits, n; + unsigned char *p, v, m; + bit_pos = BIT_POS(vtop->type.t); + bit_size = BIT_SIZE(vtop->type.t); + p = (unsigned char*)ptr + (bit_pos >> 3); + bit_pos &= 7, bits = 0; + while (bit_size) { + n = 8 - bit_pos; + if (n > bit_size) + n = bit_size; + v = vtop->c.i >> bits << bit_pos; + m = ((1 << n) - 1) << bit_pos; + *p = (*p & ~m) | (v & m); + bits += n, bit_size -= n, bit_pos = 0, ++p; + } + } else + switch(bt) { + /* XXX: when cross-compiling we assume that each type has the + same representation on host and target, which is likely to + be wrong in the case of long double */ + case VT_BOOL: + vtop->c.i = vtop->c.i != 0; + case VT_BYTE: + *(char *)ptr |= vtop->c.i; + break; + case VT_SHORT: + *(short *)ptr |= vtop->c.i; + break; + case VT_FLOAT: + *(float*)ptr = vtop->c.f; + break; + case VT_DOUBLE: + *(double *)ptr = vtop->c.d; + break; + case VT_LDOUBLE: +#if defined TCC_IS_NATIVE_387 + if (sizeof (long double) >= 10) /* zero pad ten-byte LD */ + memcpy(ptr, &vtop->c.ld, 10); +#ifdef __TINYC__ + else if (sizeof (long double) == sizeof (double)) + __asm__("fldl %1\nfstpt %0\n" : "=m" (ptr) : "m" (vtop->c.ld)); +#endif + else +#endif + if (sizeof(long double) == LDOUBLE_SIZE) + *(long double*)ptr = vtop->c.ld; + else if (sizeof(double) == LDOUBLE_SIZE) + *(double *)ptr = (double)vtop->c.ld; + else + tcc_error("can't cross compile long double constants"); + break; +#if PTR_SIZE != 8 + case VT_LLONG: + *(long long *)ptr |= vtop->c.i; + break; +#else + case VT_LLONG: +#endif + case VT_PTR: + { + addr_t val = vtop->c.i; +#if PTR_SIZE == 8 + if (vtop->r & VT_SYM) + greloca(sec, vtop->sym, c, R_DATA_PTR, val); + else + *(addr_t *)ptr |= val; +#else + if (vtop->r & VT_SYM) + greloc(sec, vtop->sym, c, R_DATA_PTR); + *(addr_t *)ptr |= val; +#endif + break; + } + default: + { + int val = vtop->c.i; +#if PTR_SIZE == 8 + if (vtop->r & VT_SYM) + greloca(sec, vtop->sym, c, R_DATA_PTR, val); + else + *(int *)ptr |= val; +#else + if (vtop->r & VT_SYM) + greloc(sec, vtop->sym, c, R_DATA_PTR); + *(int *)ptr |= val; +#endif + break; + } + } + } + vtop--; + } else { + vset(&dtype, VT_LOCAL|VT_LVAL, c); + vswap(); + vstore(); + vpop(); + } +} + +/* 't' contains the type and storage info. 'c' is the offset of the + object in section 'sec'. If 'sec' is NULL, it means stack based + allocation. 'first' is true if array '{' must be read (multi + dimension implicit array init handling). 'size_only' is true if + size only evaluation is wanted (only for arrays). */ +static void decl_initializer(CType *type, Section *sec, unsigned long c, + int first, int size_only) +{ + int len, n, no_oblock, nb, i; + int size1, align1; + int have_elem; + Sym *s, *f; + Sym indexsym; + CType *t1; + + /* If we currently are at an '}' or ',' we have read an initializer + element in one of our callers, and not yet consumed it. */ + have_elem = tok == '}' || tok == ','; + if (!have_elem && tok != '{' && + /* In case of strings we have special handling for arrays, so + don't consume them as initializer value (which would commit them + to some anonymous symbol). */ + tok != TOK_LSTR && tok != TOK_STR && + !size_only) { + parse_init_elem(!sec ? EXPR_ANY : EXPR_CONST); + have_elem = 1; + } + + if (have_elem && + !(type->t & VT_ARRAY) && + /* Use i_c_parameter_t, to strip toplevel qualifiers. + The source type might have VT_CONSTANT set, which is + of course assignable to non-const elements. */ + is_compatible_unqualified_types(type, &vtop->type)) { + init_putv(type, sec, c); + } else if (type->t & VT_ARRAY) { + s = type->ref; + n = s->c; + t1 = pointed_type(type); + size1 = type_size(t1, &align1); + + no_oblock = 1; + if ((first && tok != TOK_LSTR && tok != TOK_STR) || + tok == '{') { + if (tok != '{') + tcc_error("character array initializer must be a literal," + " optionally enclosed in braces"); + skip('{'); + no_oblock = 0; + } + + /* only parse strings here if correct type (otherwise: handle + them as ((w)char *) expressions */ + if ((tok == TOK_LSTR && +#ifdef TCC_TARGET_PE + (t1->t & VT_BTYPE) == VT_SHORT && (t1->t & VT_UNSIGNED) +#else + (t1->t & VT_BTYPE) == VT_INT +#endif + ) || (tok == TOK_STR && (t1->t & VT_BTYPE) == VT_BYTE)) { + len = 0; + while (tok == TOK_STR || tok == TOK_LSTR) { + int cstr_len, ch; + + /* compute maximum number of chars wanted */ + if (tok == TOK_STR) + cstr_len = tokc.str.size; + else + cstr_len = tokc.str.size / sizeof(nwchar_t); + cstr_len--; + nb = cstr_len; + if (n >= 0 && nb > (n - len)) + nb = n - len; + if (!size_only) { + if (cstr_len > nb) + tcc_warning("initializer-string for array is too long"); + /* in order to go faster for common case (char + string in global variable, we handle it + specifically */ + if (sec && tok == TOK_STR && size1 == 1) { + if (!NODATA_WANTED) + memcpy(sec->data + c + len, tokc.str.data, nb); + } else { + for(i=0;it & VT_ARRAY) { + ++indexsym.c; + /* special test for multi dimensional arrays (may not + be strictly correct if designators are used at the + same time) */ + if (no_oblock && len >= n*size1) + break; + } else { + if (s->type.t == VT_UNION) + f = NULL; + else + f = f->next; + if (no_oblock && f == NULL) + break; + } + + if (tok == '}') + break; + skip(','); + } + } + /* put zeros at the end */ + if (!size_only && len < n*size1) + init_putz(sec, c + len, n*size1 - len); + if (!no_oblock) + skip('}'); + /* patch type size if needed, which happens only for array types */ + if (n < 0) + s->c = size1 == 1 ? len : ((len + size1 - 1)/size1); + } else if ((type->t & VT_BTYPE) == VT_STRUCT) { + size1 = 1; + no_oblock = 1; + if (first || tok == '{') { + skip('{'); + no_oblock = 0; + } + s = type->ref; + f = s->next; + n = s->c; + goto do_init_list; + } else if (tok == '{') { + next(); + decl_initializer(type, sec, c, first, size_only); + skip('}'); + } else if (size_only) { + /* If we supported only ISO C we wouldn't have to accept calling + this on anything than an array size_only==1 (and even then + only on the outermost level, so no recursion would be needed), + because initializing a flex array member isn't supported. + But GNU C supports it, so we need to recurse even into + subfields of structs and arrays when size_only is set. */ + /* just skip expression */ + skip_or_save_block(NULL); + } else { + if (!have_elem) { + /* This should happen only when we haven't parsed + the init element above for fear of committing a + string constant to memory too early. */ + if (tok != TOK_STR && tok != TOK_LSTR) + expect("string constant"); + parse_init_elem(!sec ? EXPR_ANY : EXPR_CONST); + } + init_putv(type, sec, c); + } +} + +/* parse an initializer for type 't' if 'has_init' is non zero, and + allocate space in local or global data space ('r' is either + VT_LOCAL or VT_CONST). If 'v' is non zero, then an associated + variable 'v' of scope 'scope' is declared before initializers + are parsed. If 'v' is zero, then a reference to the new object + is put in the value stack. If 'has_init' is 2, a special parsing + is done to handle string constants. */ +static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, + int has_init, int v, int scope) +{ + int size, align, addr; + TokenString *init_str = NULL; + + Section *sec; + Sym *flexible_array; + Sym *sym = NULL; + int saved_nocode_wanted = nocode_wanted; +#ifdef CONFIG_TCC_BCHECK + int bcheck = tcc_state->do_bounds_check && !NODATA_WANTED; +#endif + + if (type->t & VT_STATIC) + nocode_wanted |= NODATA_WANTED ? 0x40000000 : 0x80000000; + + flexible_array = NULL; + if ((type->t & VT_BTYPE) == VT_STRUCT) { + Sym *field = type->ref->next; + if (field) { + while (field->next) + field = field->next; + if (field->type.t & VT_ARRAY && field->type.ref->c < 0) + flexible_array = field; + } + } + + size = type_size(type, &align); + /* If unknown size, we must evaluate it before + evaluating initializers because + initializers can generate global data too + (e.g. string pointers or ISOC99 compound + literals). It also simplifies local + initializers handling */ + if (size < 0 || (flexible_array && has_init)) { + if (!has_init) + tcc_error("unknown type size"); + /* get all init string */ + if (has_init == 2) { + init_str = tok_str_alloc(); + /* only get strings */ + while (tok == TOK_STR || tok == TOK_LSTR) { + tok_str_add_tok(init_str); + next(); + } + tok_str_add(init_str, -1); + tok_str_add(init_str, 0); + } else { + skip_or_save_block(&init_str); + } + unget_tok(0); + + /* compute size */ + begin_macro(init_str, 1); + next(); + decl_initializer(type, NULL, 0, 1, 1); + /* prepare second initializer parsing */ + macro_ptr = init_str->str; + next(); + + /* if still unknown size, error */ + size = type_size(type, &align); + if (size < 0) + tcc_error("unknown type size"); + } + /* If there's a flex member and it was used in the initializer + adjust size. */ + if (flexible_array && + flexible_array->type.ref->c > 0) + size += flexible_array->type.ref->c + * pointed_size(&flexible_array->type); + /* take into account specified alignment if bigger */ + if (ad->a.aligned) { + int speca = 1 << (ad->a.aligned - 1); + if (speca > align) + align = speca; + } else if (ad->a.packed) { + align = 1; + } + + if (NODATA_WANTED) + size = 0, align = 1; + + if ((r & VT_VALMASK) == VT_LOCAL) { + sec = NULL; +#ifdef CONFIG_TCC_BCHECK + if (bcheck && (type->t & VT_ARRAY)) { + loc--; + } +#endif + loc = (loc - size) & -align; + addr = loc; +#ifdef CONFIG_TCC_BCHECK + /* handles bounds */ + /* XXX: currently, since we do only one pass, we cannot track + '&' operators, so we add only arrays */ + if (bcheck && (type->t & VT_ARRAY)) { + addr_t *bounds_ptr; + /* add padding between regions */ + loc--; + /* then add local bound info */ + bounds_ptr = section_ptr_add(lbounds_section, 2 * sizeof(addr_t)); + bounds_ptr[0] = addr; + bounds_ptr[1] = size; + } +#endif + if (v) { + /* local variable */ +#ifdef CONFIG_TCC_ASM + if (ad->asm_label) { + int reg = asm_parse_regvar(ad->asm_label); + if (reg >= 0) + r = (r & ~VT_VALMASK) | reg; + } +#endif + sym = sym_push(v, type, r, addr); + sym->a = ad->a; + } else { + /* push local reference */ + vset(type, r, addr); + } + } else { + if (v && scope == VT_CONST) { + /* see if the symbol was already defined */ + sym = sym_find(v); + if (sym) { + patch_storage(sym, ad, type); + if (sym->type.t & VT_EXTERN) { + /* if the variable is extern, it was not allocated */ + sym->type.t &= ~VT_EXTERN; + /* set array size if it was omitted in extern + declaration */ + if ((sym->type.t & VT_ARRAY) && + sym->type.ref->c < 0 && + type->ref->c >= 0) + sym->type.ref->c = type->ref->c; + } else if (!has_init) { + /* we accept several definitions of the same + global variable. this is tricky, because we + must play with the SHN_COMMON type of the symbol */ + /* no init data, we won't add more to the symbol */ + goto no_alloc; + } else if (sym->c) { + ElfW(Sym) *esym; + esym = &((ElfW(Sym) *)symtab_section->data)[sym->c]; + if (esym->st_shndx == data_section->sh_num) + tcc_error("redefinition of '%s'", get_tok_str(v, NULL)); + } + } + } + + /* allocate symbol in corresponding section */ + sec = ad->section; + if (!sec) { + if (has_init) + sec = data_section; + else if (tcc_state->nocommon) + sec = bss_section; + } + + if (sec) { + addr = section_add(sec, size, align); +#ifdef CONFIG_TCC_BCHECK + /* add padding if bound check */ + if (bcheck) + section_add(sec, 1, 1); +#endif + } else { + addr = align; /* SHN_COMMON is special, symbol value is align */ + sec = common_section; + } + + if (v) { + if (!sym) { + sym = sym_push(v, type, r | VT_SYM, 0); + patch_storage(sym, ad, NULL); + } + /* Local statics have a scope until now (for + warnings), remove it here. */ + sym->sym_scope = 0; + /* update symbol definition */ + put_extern_sym(sym, sec, addr, size); + } else { + /* push global reference */ + sym = get_sym_ref(type, sec, addr, size); + vpushsym(type, sym); + vtop->r |= r; + } + +#ifdef CONFIG_TCC_BCHECK + /* handles bounds now because the symbol must be defined + before for the relocation */ + if (bcheck) { + addr_t *bounds_ptr; + + greloca(bounds_section, sym, bounds_section->data_offset, R_DATA_PTR, 0); + /* then add global bound info */ + bounds_ptr = section_ptr_add(bounds_section, 2 * sizeof(addr_t)); + bounds_ptr[0] = 0; /* relocated */ + bounds_ptr[1] = size; + } +#endif + } + + if (type->t & VT_VLA) { + int a; + + if (NODATA_WANTED) + goto no_alloc; + + /* save current stack pointer */ + if (vlas_in_scope == 0) { + if (vla_sp_root_loc == -1) + vla_sp_root_loc = (loc -= PTR_SIZE); + gen_vla_sp_save(vla_sp_root_loc); + } + + vla_runtime_type_size(type, &a); + gen_vla_alloc(type, a); + gen_vla_sp_save(addr); + vla_sp_loc = addr; + vlas_in_scope++; + + } else if (has_init) { + size_t oldreloc_offset = 0; + if (sec && sec->reloc) + oldreloc_offset = sec->reloc->data_offset; + decl_initializer(type, sec, addr, 1, 0); + if (sec && sec->reloc) + squeeze_multi_relocs(sec, oldreloc_offset); + /* patch flexible array member size back to -1, */ + /* for possible subsequent similar declarations */ + if (flexible_array) + flexible_array->type.ref->c = -1; + } + + no_alloc: + /* restore parse state if needed */ + if (init_str) { + end_macro(); + next(); + } + + nocode_wanted = saved_nocode_wanted; +} + +/* parse a function defined by symbol 'sym' and generate its code in + 'cur_text_section' */ +static void gen_function(Sym *sym) +{ + nocode_wanted = 0; + ind = cur_text_section->data_offset; + /* NOTE: we patch the symbol size later */ + put_extern_sym(sym, cur_text_section, ind, 0); + funcname = get_tok_str(sym->v, NULL); + func_ind = ind; + /* Initialize VLA state */ + vla_sp_loc = -1; + vla_sp_root_loc = -1; + /* put debug symbol */ + tcc_debug_funcstart(tcc_state, sym); + /* push a dummy symbol to enable local sym storage */ + sym_push2(&local_stack, SYM_FIELD, 0, 0); + local_scope = 1; /* for function parameters */ + gfunc_prolog(&sym->type); + local_scope = 0; + rsym = 0; + block(NULL, NULL, 0); + nocode_wanted = 0; + gsym(rsym); + gfunc_epilog(); + cur_text_section->data_offset = ind; + label_pop(&global_label_stack, NULL, 0); + /* reset local stack */ + local_scope = 0; + sym_pop(&local_stack, NULL, 0); + /* end of function */ + /* patch symbol size */ + ((ElfW(Sym) *)symtab_section->data)[sym->c].st_size = + ind - func_ind; + tcc_debug_funcend(tcc_state, ind - func_ind); + /* It's better to crash than to generate wrong code */ + cur_text_section = NULL; + funcname = ""; /* for safety */ + func_vt.t = VT_VOID; /* for safety */ + func_var = 0; /* for safety */ + ind = 0; /* for safety */ + nocode_wanted = 0x80000000; + check_vstack(); +} + +static void gen_inline_functions(TCCState *s) +{ + Sym *sym; + int inline_generated, i, ln; + struct InlineFunc *fn; + + ln = file->line_num; + /* iterate while inline function are referenced */ + do { + inline_generated = 0; + for (i = 0; i < s->nb_inline_fns; ++i) { + fn = s->inline_fns[i]; + sym = fn->sym; + if (sym && sym->c) { + /* the function was used: generate its code and + convert it to a normal function */ + fn->sym = NULL; + if (file) + pstrcpy(file->filename, sizeof file->filename, fn->filename); + sym->type.t &= ~VT_INLINE; + + begin_macro(fn->func_str, 1); + next(); + cur_text_section = text_section; + gen_function(sym); + end_macro(); + + inline_generated = 1; + } + } + } while (inline_generated); + file->line_num = ln; +} + +ST_FUNC void free_inline_functions(TCCState *s) +{ + int i; + /* free tokens of unused inline functions */ + for (i = 0; i < s->nb_inline_fns; ++i) { + struct InlineFunc *fn = s->inline_fns[i]; + if (fn->sym) + tok_str_free(fn->func_str); + } + dynarray_reset(&s->inline_fns, &s->nb_inline_fns); +} + +/* 'l' is VT_LOCAL or VT_CONST to define default storage type, or VT_CMP + if parsing old style parameter decl list (and FUNC_SYM is set then) */ +static int decl0(int l, int is_for_loop_init, Sym *func_sym) +{ + int v, has_init, r; + CType type, btype; + Sym *sym; + AttributeDef ad; + + while (1) { + if (!parse_btype(&btype, &ad)) { + if (is_for_loop_init) + return 0; + /* skip redundant ';' if not in old parameter decl scope */ + if (tok == ';' && l != VT_CMP) { + next(); + continue; + } + if (l != VT_CONST) + break; + if (tok == TOK_ASM1 || tok == TOK_ASM2 || tok == TOK_ASM3) { + /* global asm block */ + asm_global_instr(); + continue; + } + if (tok >= TOK_UIDENT) { + /* special test for old K&R protos without explicit int + type. Only accepted when defining global data */ + btype.t = VT_INT; + } else { + if (tok != TOK_EOF) + expect("declaration"); + break; + } + } + if (tok == ';') { + if ((btype.t & VT_BTYPE) == VT_STRUCT) { + int v = btype.ref->v; + if (!(v & SYM_FIELD) && (v & ~SYM_STRUCT) >= SYM_FIRST_ANOM) + tcc_warning("unnamed struct/union that defines no instances"); + next(); + continue; + } + if (IS_ENUM(btype.t)) { + next(); + continue; + } + } + while (1) { /* iterate thru each declaration */ + type = btype; + /* If the base type itself was an array type of unspecified + size (like in 'typedef int arr[]; arr x = {1};') then + we will overwrite the unknown size by the real one for + this decl. We need to unshare the ref symbol holding + that size. */ + if ((type.t & VT_ARRAY) && type.ref->c < 0) { + type.ref = sym_push(SYM_FIELD, &type.ref->type, 0, type.ref->c); + } + type_decl(&type, &ad, &v, TYPE_DIRECT); +#if 0 + { + char buf[500]; + type_to_str(buf, sizeof(buf), &type, get_tok_str(v, NULL)); + printf("type = '%s'\n", buf); + } +#endif + if ((type.t & VT_BTYPE) == VT_FUNC) { + if ((type.t & VT_STATIC) && (l == VT_LOCAL)) { + tcc_error("function without file scope cannot be static"); + } + /* if old style function prototype, we accept a + declaration list */ + sym = type.ref; + if (sym->f.func_type == FUNC_OLD && l == VT_CONST) + decl0(VT_CMP, 0, sym); + } + + if (gnu_ext && (tok == TOK_ASM1 || tok == TOK_ASM2 || tok == TOK_ASM3)) { + ad.asm_label = asm_label_instr(); + /* parse one last attribute list, after asm label */ + parse_attribute(&ad); + if (tok == '{') + expect(";"); + } + +#ifdef TCC_TARGET_PE + if (ad.a.dllimport || ad.a.dllexport) { + if (type.t & (VT_STATIC|VT_TYPEDEF)) + tcc_error("cannot have dll linkage with static or typedef"); + if (ad.a.dllimport) { + if ((type.t & VT_BTYPE) == VT_FUNC) + ad.a.dllimport = 0; + else + type.t |= VT_EXTERN; + } + } +#endif + if (tok == '{') { + if (l != VT_CONST) + tcc_error("cannot use local functions"); + if ((type.t & VT_BTYPE) != VT_FUNC) + expect("function definition"); + + /* reject abstract declarators in function definition + make old style params without decl have int type */ + sym = type.ref; + while ((sym = sym->next) != NULL) { + if (!(sym->v & ~SYM_FIELD)) + expect("identifier"); + if (sym->type.t == VT_VOID) + sym->type = int_type; + } + + /* XXX: cannot do better now: convert extern line to static inline */ + if ((type.t & (VT_EXTERN | VT_INLINE)) == (VT_EXTERN | VT_INLINE)) + type.t = (type.t & ~VT_EXTERN) | VT_STATIC; + + sym = sym_find(v); + if (sym) { + Sym *ref; + if ((sym->type.t & VT_BTYPE) != VT_FUNC) + goto func_error1; + + ref = sym->type.ref; + + /* use func_call from prototype if not defined */ + if (ref->f.func_call != FUNC_CDECL + && type.ref->f.func_call == FUNC_CDECL) + type.ref->f.func_call = ref->f.func_call; + + /* use static from prototype */ + if (sym->type.t & VT_STATIC) + type.t = (type.t & ~VT_EXTERN) | VT_STATIC; + + /* If the definition has no visibility use the + one from prototype. */ + if (!type.ref->a.visibility) + type.ref->a.visibility = ref->a.visibility; + /* apply other storage attributes from prototype */ + type.ref->a.dllexport |= ref->a.dllexport; + type.ref->a.weak |= ref->a.weak; + + if (!is_compatible_types(&sym->type, &type)) { + func_error1: + tcc_error("incompatible types for redefinition of '%s'", + get_tok_str(v, NULL)); + } + if (ref->f.func_body) + tcc_error("redefinition of '%s'", get_tok_str(v, NULL)); + /* if symbol is already defined, then put complete type */ + sym->type = type; + + } else { + /* put function symbol */ + sym = global_identifier_push(v, type.t, 0); + sym->type.ref = type.ref; + } + + sym->type.ref->f.func_body = 1; + sym->r = VT_SYM | VT_CONST; + patch_storage(sym, &ad, NULL); + + /* static inline functions are just recorded as a kind + of macro. Their code will be emitted at the end of + the compilation unit only if they are used */ + if ((type.t & (VT_INLINE | VT_STATIC)) == + (VT_INLINE | VT_STATIC)) { + struct InlineFunc *fn; + const char *filename; + + filename = file ? file->filename : ""; + fn = tcc_malloc(sizeof *fn + strlen(filename)); + strcpy(fn->filename, filename); + fn->sym = sym; + skip_or_save_block(&fn->func_str); + dynarray_add(&tcc_state->inline_fns, + &tcc_state->nb_inline_fns, fn); + } else { + /* compute text section */ + cur_text_section = ad.section; + if (!cur_text_section) + cur_text_section = text_section; + gen_function(sym); + } + break; + } else { + if (l == VT_CMP) { + /* find parameter in function parameter list */ + for (sym = func_sym->next; sym; sym = sym->next) + if ((sym->v & ~SYM_FIELD) == v) + goto found; + tcc_error("declaration for parameter '%s' but no such parameter", + get_tok_str(v, NULL)); +found: + if (type.t & VT_STORAGE) /* 'register' is okay */ + tcc_error("storage class specified for '%s'", + get_tok_str(v, NULL)); + if (sym->type.t != VT_VOID) + tcc_error("redefinition of parameter '%s'", + get_tok_str(v, NULL)); + convert_parameter_type(&type); + sym->type = type; + } else if (type.t & VT_TYPEDEF) { + /* save typedefed type */ + /* XXX: test storage specifiers ? */ + sym = sym_find(v); + if (sym && sym->sym_scope == local_scope) { + if (!is_compatible_types(&sym->type, &type) + || !(sym->type.t & VT_TYPEDEF)) + tcc_error("incompatible redefinition of '%s'", + get_tok_str(v, NULL)); + sym->type = type; + } else { + sym = sym_push(v, &type, 0, 0); + } + sym->a = ad.a; + sym->f = ad.f; + } else { + r = 0; + if ((type.t & VT_BTYPE) == VT_FUNC) { + /* external function definition */ + /* specific case for func_call attribute */ + type.ref->f = ad.f; + } else if (!(type.t & VT_ARRAY)) { + /* not lvalue if array */ + r |= lvalue_type(type.t); + } + has_init = (tok == '='); + if (has_init && (type.t & VT_VLA)) + tcc_error("variable length array cannot be initialized"); + if (((type.t & VT_EXTERN) && (!has_init || l != VT_CONST)) || + ((type.t & VT_BTYPE) == VT_FUNC) || + ((type.t & VT_ARRAY) && (type.t & VT_STATIC) && + !has_init && l == VT_CONST && type.ref->c < 0)) { + /* external variable or function */ + /* NOTE: as GCC, uninitialized global static + arrays of null size are considered as + extern */ + sym = external_sym(v, &type, r, &ad); + if (ad.alias_target) { + Section tsec; + ElfW(Sym) *esym; + Sym *alias_target; + alias_target = sym_find(ad.alias_target); + if (!alias_target || !alias_target->c) + tcc_error("unsupported forward __alias__ attribute"); + esym = &((ElfW(Sym) *)symtab_section->data)[alias_target->c]; + tsec.sh_num = esym->st_shndx; + /* Local statics have a scope until now (for + warnings), remove it here. */ + sym->sym_scope = 0; + put_extern_sym2(sym, &tsec, esym->st_value, esym->st_size, 0); + } + } else { + if (type.t & VT_STATIC) + r |= VT_CONST; + else + r |= l; + if (has_init) + next(); + decl_initializer_alloc(&type, &ad, r, has_init, v, l); + } + } + if (tok != ',') { + if (is_for_loop_init) + return 1; + skip(';'); + break; + } + next(); + } + ad.a.aligned = 0; + } + } + return 0; +} + +static void decl(int l) +{ + decl0(l, 0, NULL); +} + +/* ------------------------------------------------------------------------- */ diff --git a/tinyc/tcclib.h b/tinyc/tcclib.h new file mode 100644 index 000000000..8d59e4c9a --- /dev/null +++ b/tinyc/tcclib.h @@ -0,0 +1,80 @@ +/* Simple libc header for TCC + * + * Add any function you want from the libc there. This file is here + * only for your convenience so that you do not need to put the whole + * glibc include files on your floppy disk + */ +#ifndef _TCCLIB_H +#define _TCCLIB_H + +#include +#include + +/* stdlib.h */ +void *calloc(size_t nmemb, size_t size); +void *malloc(size_t size); +void free(void *ptr); +void *realloc(void *ptr, size_t size); +int atoi(const char *nptr); +long int strtol(const char *nptr, char **endptr, int base); +unsigned long int strtoul(const char *nptr, char **endptr, int base); +void exit(int); + +/* stdio.h */ +typedef struct __FILE FILE; +#define EOF (-1) +extern FILE *stdin; +extern FILE *stdout; +extern FILE *stderr; +FILE *fopen(const char *path, const char *mode); +FILE *fdopen(int fildes, const char *mode); +FILE *freopen(const char *path, const char *mode, FILE *stream); +int fclose(FILE *stream); +size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream); +size_t fwrite(void *ptr, size_t size, size_t nmemb, FILE *stream); +int fgetc(FILE *stream); +char *fgets(char *s, int size, FILE *stream); +int getc(FILE *stream); +int getchar(void); +char *gets(char *s); +int ungetc(int c, FILE *stream); +int fflush(FILE *stream); +int putchar (int c); + +int printf(const char *format, ...); +int fprintf(FILE *stream, const char *format, ...); +int sprintf(char *str, const char *format, ...); +int snprintf(char *str, size_t size, const char *format, ...); +int asprintf(char **strp, const char *format, ...); +int dprintf(int fd, const char *format, ...); +int vprintf(const char *format, va_list ap); +int vfprintf(FILE *stream, const char *format, va_list ap); +int vsprintf(char *str, const char *format, va_list ap); +int vsnprintf(char *str, size_t size, const char *format, va_list ap); +int vasprintf(char **strp, const char *format, va_list ap); +int vdprintf(int fd, const char *format, va_list ap); + +void perror(const char *s); + +/* string.h */ +char *strcat(char *dest, const char *src); +char *strchr(const char *s, int c); +char *strrchr(const char *s, int c); +char *strcpy(char *dest, const char *src); +void *memcpy(void *dest, const void *src, size_t n); +void *memmove(void *dest, const void *src, size_t n); +void *memset(void *s, int c, size_t n); +char *strdup(const char *s); +size_t strlen(const char *s); + +/* dlfcn.h */ +#define RTLD_LAZY 0x001 +#define RTLD_NOW 0x002 +#define RTLD_GLOBAL 0x100 + +void *dlopen(const char *filename, int flag); +const char *dlerror(void); +void *dlsym(void *handle, char *symbol); +int dlclose(void *handle); + +#endif /* _TCCLIB_H */ diff --git a/tinyc/tccpe.c b/tinyc/tccpe.c new file mode 100644 index 000000000..a67023dd2 --- /dev/null +++ b/tinyc/tccpe.c @@ -0,0 +1,2014 @@ +/* + * TCCPE.C - PE file output for the Tiny C Compiler + * + * Copyright (c) 2005-2007 grischka + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "tcc.h" + +#define PE_MERGE_DATA +/* #define PE_PRINT_SECTIONS */ + +#ifndef _WIN32 +#define stricmp strcasecmp +#define strnicmp strncasecmp +#include /* chmod() */ +#endif + +#ifdef TCC_TARGET_X86_64 +# define ADDR3264 ULONGLONG +# define PE_IMAGE_REL IMAGE_REL_BASED_DIR64 +# define REL_TYPE_DIRECT R_X86_64_64 +# define R_XXX_THUNKFIX R_X86_64_PC32 +# define R_XXX_RELATIVE R_X86_64_RELATIVE +# define IMAGE_FILE_MACHINE 0x8664 +# define RSRC_RELTYPE 3 + +#elif defined TCC_TARGET_ARM +# define ADDR3264 DWORD +# define PE_IMAGE_REL IMAGE_REL_BASED_HIGHLOW +# define REL_TYPE_DIRECT R_ARM_ABS32 +# define R_XXX_THUNKFIX R_ARM_ABS32 +# define R_XXX_RELATIVE R_ARM_RELATIVE +# define IMAGE_FILE_MACHINE 0x01C0 +# define RSRC_RELTYPE 7 /* ??? (not tested) */ + +#elif defined TCC_TARGET_I386 +# define ADDR3264 DWORD +# define PE_IMAGE_REL IMAGE_REL_BASED_HIGHLOW +# define REL_TYPE_DIRECT R_386_32 +# define R_XXX_THUNKFIX R_386_32 +# define R_XXX_RELATIVE R_386_RELATIVE +# define IMAGE_FILE_MACHINE 0x014C +# define RSRC_RELTYPE 7 /* DIR32NB */ + +#endif + +#ifndef IMAGE_NT_SIGNATURE +/* ----------------------------------------------------------- */ +/* definitions below are from winnt.h */ + +typedef unsigned char BYTE; +typedef unsigned short WORD; +typedef unsigned int DWORD; +typedef unsigned long long ULONGLONG; +#pragma pack(push, 1) + +typedef struct _IMAGE_DOS_HEADER { /* DOS .EXE header */ + WORD e_magic; /* Magic number */ + WORD e_cblp; /* Bytes on last page of file */ + WORD e_cp; /* Pages in file */ + WORD e_crlc; /* Relocations */ + WORD e_cparhdr; /* Size of header in paragraphs */ + WORD e_minalloc; /* Minimum extra paragraphs needed */ + WORD e_maxalloc; /* Maximum extra paragraphs needed */ + WORD e_ss; /* Initial (relative) SS value */ + WORD e_sp; /* Initial SP value */ + WORD e_csum; /* Checksum */ + WORD e_ip; /* Initial IP value */ + WORD e_cs; /* Initial (relative) CS value */ + WORD e_lfarlc; /* File address of relocation table */ + WORD e_ovno; /* Overlay number */ + WORD e_res[4]; /* Reserved words */ + WORD e_oemid; /* OEM identifier (for e_oeminfo) */ + WORD e_oeminfo; /* OEM information; e_oemid specific */ + WORD e_res2[10]; /* Reserved words */ + DWORD e_lfanew; /* File address of new exe header */ +} IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER; + +#define IMAGE_NT_SIGNATURE 0x00004550 /* PE00 */ +#define SIZE_OF_NT_SIGNATURE 4 + +typedef struct _IMAGE_FILE_HEADER { + WORD Machine; + WORD NumberOfSections; + DWORD TimeDateStamp; + DWORD PointerToSymbolTable; + DWORD NumberOfSymbols; + WORD SizeOfOptionalHeader; + WORD Characteristics; +} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER; + + +#define IMAGE_SIZEOF_FILE_HEADER 20 + +typedef struct _IMAGE_DATA_DIRECTORY { + DWORD VirtualAddress; + DWORD Size; +} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY; + + +typedef struct _IMAGE_OPTIONAL_HEADER { + /* Standard fields. */ + WORD Magic; + BYTE MajorLinkerVersion; + BYTE MinorLinkerVersion; + DWORD SizeOfCode; + DWORD SizeOfInitializedData; + DWORD SizeOfUninitializedData; + DWORD AddressOfEntryPoint; + DWORD BaseOfCode; +#ifndef TCC_TARGET_X86_64 + DWORD BaseOfData; +#endif + /* NT additional fields. */ + ADDR3264 ImageBase; + DWORD SectionAlignment; + DWORD FileAlignment; + WORD MajorOperatingSystemVersion; + WORD MinorOperatingSystemVersion; + WORD MajorImageVersion; + WORD MinorImageVersion; + WORD MajorSubsystemVersion; + WORD MinorSubsystemVersion; + DWORD Win32VersionValue; + DWORD SizeOfImage; + DWORD SizeOfHeaders; + DWORD CheckSum; + WORD Subsystem; + WORD DllCharacteristics; + ADDR3264 SizeOfStackReserve; + ADDR3264 SizeOfStackCommit; + ADDR3264 SizeOfHeapReserve; + ADDR3264 SizeOfHeapCommit; + DWORD LoaderFlags; + DWORD NumberOfRvaAndSizes; + IMAGE_DATA_DIRECTORY DataDirectory[16]; +} IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, IMAGE_OPTIONAL_HEADER; + +#define IMAGE_DIRECTORY_ENTRY_EXPORT 0 /* Export Directory */ +#define IMAGE_DIRECTORY_ENTRY_IMPORT 1 /* Import Directory */ +#define IMAGE_DIRECTORY_ENTRY_RESOURCE 2 /* Resource Directory */ +#define IMAGE_DIRECTORY_ENTRY_EXCEPTION 3 /* Exception Directory */ +#define IMAGE_DIRECTORY_ENTRY_SECURITY 4 /* Security Directory */ +#define IMAGE_DIRECTORY_ENTRY_BASERELOC 5 /* Base Relocation Table */ +#define IMAGE_DIRECTORY_ENTRY_DEBUG 6 /* Debug Directory */ +/* IMAGE_DIRECTORY_ENTRY_COPYRIGHT 7 (X86 usage) */ +#define IMAGE_DIRECTORY_ENTRY_ARCHITECTURE 7 /* Architecture Specific Data */ +#define IMAGE_DIRECTORY_ENTRY_GLOBALPTR 8 /* RVA of GP */ +#define IMAGE_DIRECTORY_ENTRY_TLS 9 /* TLS Directory */ +#define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 10 /* Load Configuration Directory */ +#define IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT 11 /* Bound Import Directory in headers */ +#define IMAGE_DIRECTORY_ENTRY_IAT 12 /* Import Address Table */ +#define IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT 13 /* Delay Load Import Descriptors */ +#define IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR 14 /* COM Runtime descriptor */ + +/* Section header format. */ +#define IMAGE_SIZEOF_SHORT_NAME 8 + +typedef struct _IMAGE_SECTION_HEADER { + BYTE Name[IMAGE_SIZEOF_SHORT_NAME]; + union { + DWORD PhysicalAddress; + DWORD VirtualSize; + } Misc; + DWORD VirtualAddress; + DWORD SizeOfRawData; + DWORD PointerToRawData; + DWORD PointerToRelocations; + DWORD PointerToLinenumbers; + WORD NumberOfRelocations; + WORD NumberOfLinenumbers; + DWORD Characteristics; +} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER; + +#define IMAGE_SIZEOF_SECTION_HEADER 40 + +typedef struct _IMAGE_EXPORT_DIRECTORY { + DWORD Characteristics; + DWORD TimeDateStamp; + WORD MajorVersion; + WORD MinorVersion; + DWORD Name; + DWORD Base; + DWORD NumberOfFunctions; + DWORD NumberOfNames; + DWORD AddressOfFunctions; + DWORD AddressOfNames; + DWORD AddressOfNameOrdinals; +} IMAGE_EXPORT_DIRECTORY,*PIMAGE_EXPORT_DIRECTORY; + +typedef struct _IMAGE_IMPORT_DESCRIPTOR { + union { + DWORD Characteristics; + DWORD OriginalFirstThunk; + }; + DWORD TimeDateStamp; + DWORD ForwarderChain; + DWORD Name; + DWORD FirstThunk; +} IMAGE_IMPORT_DESCRIPTOR; + +typedef struct _IMAGE_BASE_RELOCATION { + DWORD VirtualAddress; + DWORD SizeOfBlock; +// WORD TypeOffset[1]; +} IMAGE_BASE_RELOCATION; + +#define IMAGE_SIZEOF_BASE_RELOCATION 8 + +#define IMAGE_REL_BASED_ABSOLUTE 0 +#define IMAGE_REL_BASED_HIGH 1 +#define IMAGE_REL_BASED_LOW 2 +#define IMAGE_REL_BASED_HIGHLOW 3 +#define IMAGE_REL_BASED_HIGHADJ 4 +#define IMAGE_REL_BASED_MIPS_JMPADDR 5 +#define IMAGE_REL_BASED_SECTION 6 +#define IMAGE_REL_BASED_REL32 7 +#define IMAGE_REL_BASED_DIR64 10 + +#pragma pack(pop) + +/* ----------------------------------------------------------- */ +#endif /* ndef IMAGE_NT_SIGNATURE */ +/* ----------------------------------------------------------- */ + +#ifndef IMAGE_REL_BASED_DIR64 +# define IMAGE_REL_BASED_DIR64 10 +#endif + +#pragma pack(push, 1) +struct pe_header +{ + IMAGE_DOS_HEADER doshdr; + BYTE dosstub[0x40]; + DWORD nt_sig; + IMAGE_FILE_HEADER filehdr; +#ifdef TCC_TARGET_X86_64 + IMAGE_OPTIONAL_HEADER64 opthdr; +#else +#ifdef _WIN64 + IMAGE_OPTIONAL_HEADER32 opthdr; +#else + IMAGE_OPTIONAL_HEADER opthdr; +#endif +#endif +}; + +struct pe_reloc_header { + DWORD offset; + DWORD size; +}; + +struct pe_rsrc_header { + struct _IMAGE_FILE_HEADER filehdr; + struct _IMAGE_SECTION_HEADER sectionhdr; +}; + +struct pe_rsrc_reloc { + DWORD offset; + DWORD size; + WORD type; +}; +#pragma pack(pop) + +/* ------------------------------------------------------------- */ +/* internal temporary structures */ + +/* +#define IMAGE_SCN_CNT_CODE 0x00000020 +#define IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040 +#define IMAGE_SCN_CNT_UNINITIALIZED_DATA 0x00000080 +#define IMAGE_SCN_MEM_DISCARDABLE 0x02000000 +#define IMAGE_SCN_MEM_SHARED 0x10000000 +#define IMAGE_SCN_MEM_EXECUTE 0x20000000 +#define IMAGE_SCN_MEM_READ 0x40000000 +#define IMAGE_SCN_MEM_WRITE 0x80000000 +*/ + +enum { + sec_text = 0, + sec_data , + sec_bss , + sec_idata , + sec_pdata , + sec_other , + sec_rsrc , + sec_stab , + sec_reloc , + sec_last +}; + +static const DWORD pe_sec_flags[] = { + 0x60000020, /* ".text" , */ + 0xC0000040, /* ".data" , */ + 0xC0000080, /* ".bss" , */ + 0x40000040, /* ".idata" , */ + 0x40000040, /* ".pdata" , */ + 0xE0000060, /* < other > , */ + 0x40000040, /* ".rsrc" , */ + 0x42000802, /* ".stab" , */ + 0x42000040, /* ".reloc" , */ +}; + +struct section_info { + int cls, ord; + char name[32]; + DWORD sh_addr; + DWORD sh_size; + DWORD sh_flags; + unsigned char *data; + DWORD data_size; + IMAGE_SECTION_HEADER ish; +}; + +struct import_symbol { + int sym_index; + int iat_index; + int thk_offset; +}; + +struct pe_import_info { + int dll_index; + int sym_count; + struct import_symbol **symbols; +}; + +struct pe_info { + TCCState *s1; + Section *reloc; + Section *thunk; + const char *filename; + int type; + DWORD sizeofheaders; + ADDR3264 imagebase; + const char *start_symbol; + DWORD start_addr; + DWORD imp_offs; + DWORD imp_size; + DWORD iat_offs; + DWORD iat_size; + DWORD exp_offs; + DWORD exp_size; + int subsystem; + DWORD section_align; + DWORD file_align; + struct section_info *sec_info; + int sec_count; + struct pe_import_info **imp_info; + int imp_count; +}; + +#define PE_NUL 0 +#define PE_DLL 1 +#define PE_GUI 2 +#define PE_EXE 3 +#define PE_RUN 4 + +/* --------------------------------------------*/ + +static const char *pe_export_name(TCCState *s1, ElfW(Sym) *sym) +{ + const char *name = (char*)symtab_section->link->data + sym->st_name; + if (s1->leading_underscore && name[0] == '_' && !(sym->st_other & ST_PE_STDCALL)) + return name + 1; + return name; +} + +static int pe_find_import(TCCState * s1, ElfW(Sym) *sym) +{ + char buffer[200]; + const char *s, *p; + int sym_index = 0, n = 0; + int a, err = 0; + + do { + s = pe_export_name(s1, sym); + a = 0; + if (n) { + /* second try: */ + if (sym->st_other & ST_PE_STDCALL) { + /* try w/0 stdcall deco (windows API convention) */ + p = strrchr(s, '@'); + if (!p || s[0] != '_') + break; + strcpy(buffer, s+1)[p-s-1] = 0; + } else if (s[0] != '_') { /* try non-ansi function */ + buffer[0] = '_', strcpy(buffer + 1, s); + } else if (0 == memcmp(s, "__imp_", 6)) { /* mingw 2.0 */ + strcpy(buffer, s + 6), a = 1; + } else if (0 == memcmp(s, "_imp__", 6)) { /* mingw 3.7 */ + strcpy(buffer, s + 6), a = 1; + } else { + continue; + } + s = buffer; + } + sym_index = find_elf_sym(s1->dynsymtab_section, s); + // printf("find (%d) %d %s\n", n, sym_index, s); + if (sym_index + && ELFW(ST_TYPE)(sym->st_info) == STT_OBJECT + && 0 == (sym->st_other & ST_PE_IMPORT) + && 0 == a + ) err = -1, sym_index = 0; + } while (0 == sym_index && ++n < 2); + return n == 2 ? err : sym_index; +} + +/*----------------------------------------------------------------------------*/ + +static int dynarray_assoc(void **pp, int n, int key) +{ + int i; + for (i = 0; i < n; ++i, ++pp) + if (key == **(int **) pp) + return i; + return -1; +} + +#if 0 +ST_FN DWORD umin(DWORD a, DWORD b) +{ + return a < b ? a : b; +} +#endif + +static DWORD umax(DWORD a, DWORD b) +{ + return a < b ? b : a; +} + +static DWORD pe_file_align(struct pe_info *pe, DWORD n) +{ + return (n + (pe->file_align - 1)) & ~(pe->file_align - 1); +} + +static DWORD pe_virtual_align(struct pe_info *pe, DWORD n) +{ + return (n + (pe->section_align - 1)) & ~(pe->section_align - 1); +} + +static void pe_align_section(Section *s, int a) +{ + int i = s->data_offset & (a-1); + if (i) + section_ptr_add(s, a - i); +} + +static void pe_set_datadir(struct pe_header *hdr, int dir, DWORD addr, DWORD size) +{ + hdr->opthdr.DataDirectory[dir].VirtualAddress = addr; + hdr->opthdr.DataDirectory[dir].Size = size; +} + +static int pe_fwrite(void *data, unsigned len, FILE *fp, DWORD *psum) +{ + if (psum) { + DWORD sum = *psum; + WORD *p = data; + int i; + for (i = len; i > 0; i -= 2) { + sum += (i >= 2) ? *p++ : *(BYTE*)p; + sum = (sum + (sum >> 16)) & 0xFFFF; + } + *psum = sum; + } + return len == fwrite(data, 1, len, fp) ? 0 : -1; +} + +static void pe_fpad(FILE *fp, DWORD new_pos) +{ + DWORD pos = ftell(fp); + while (++pos <= new_pos) + fputc(0, fp); +} + +/*----------------------------------------------------------------------------*/ +static int pe_write(struct pe_info *pe) +{ + static const struct pe_header pe_template = { + { + /* IMAGE_DOS_HEADER doshdr */ + 0x5A4D, /*WORD e_magic; Magic number */ + 0x0090, /*WORD e_cblp; Bytes on last page of file */ + 0x0003, /*WORD e_cp; Pages in file */ + 0x0000, /*WORD e_crlc; Relocations */ + + 0x0004, /*WORD e_cparhdr; Size of header in paragraphs */ + 0x0000, /*WORD e_minalloc; Minimum extra paragraphs needed */ + 0xFFFF, /*WORD e_maxalloc; Maximum extra paragraphs needed */ + 0x0000, /*WORD e_ss; Initial (relative) SS value */ + + 0x00B8, /*WORD e_sp; Initial SP value */ + 0x0000, /*WORD e_csum; Checksum */ + 0x0000, /*WORD e_ip; Initial IP value */ + 0x0000, /*WORD e_cs; Initial (relative) CS value */ + 0x0040, /*WORD e_lfarlc; File address of relocation table */ + 0x0000, /*WORD e_ovno; Overlay number */ + {0,0,0,0}, /*WORD e_res[4]; Reserved words */ + 0x0000, /*WORD e_oemid; OEM identifier (for e_oeminfo) */ + 0x0000, /*WORD e_oeminfo; OEM information; e_oemid specific */ + {0,0,0,0,0,0,0,0,0,0}, /*WORD e_res2[10]; Reserved words */ + 0x00000080 /*DWORD e_lfanew; File address of new exe header */ + },{ + /* BYTE dosstub[0x40] */ + /* 14 code bytes + "This program cannot be run in DOS mode.\r\r\n$" + 6 * 0x00 */ + 0x0e,0x1f,0xba,0x0e,0x00,0xb4,0x09,0xcd,0x21,0xb8,0x01,0x4c,0xcd,0x21,0x54,0x68, + 0x69,0x73,0x20,0x70,0x72,0x6f,0x67,0x72,0x61,0x6d,0x20,0x63,0x61,0x6e,0x6e,0x6f, + 0x74,0x20,0x62,0x65,0x20,0x72,0x75,0x6e,0x20,0x69,0x6e,0x20,0x44,0x4f,0x53,0x20, + 0x6d,0x6f,0x64,0x65,0x2e,0x0d,0x0d,0x0a,0x24,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + }, + 0x00004550, /* DWORD nt_sig = IMAGE_NT_SIGNATURE */ + { + /* IMAGE_FILE_HEADER filehdr */ + IMAGE_FILE_MACHINE, /*WORD Machine; */ + 0x0003, /*WORD NumberOfSections; */ + 0x00000000, /*DWORD TimeDateStamp; */ + 0x00000000, /*DWORD PointerToSymbolTable; */ + 0x00000000, /*DWORD NumberOfSymbols; */ +#if defined(TCC_TARGET_X86_64) + 0x00F0, /*WORD SizeOfOptionalHeader; */ + 0x022F /*WORD Characteristics; */ +#define CHARACTERISTICS_DLL 0x222E +#elif defined(TCC_TARGET_I386) + 0x00E0, /*WORD SizeOfOptionalHeader; */ + 0x030F /*WORD Characteristics; */ +#define CHARACTERISTICS_DLL 0x230E +#elif defined(TCC_TARGET_ARM) + 0x00E0, /*WORD SizeOfOptionalHeader; */ + 0x010F, /*WORD Characteristics; */ +#define CHARACTERISTICS_DLL 0x230F +#endif +},{ + /* IMAGE_OPTIONAL_HEADER opthdr */ + /* Standard fields. */ +#ifdef TCC_TARGET_X86_64 + 0x020B, /*WORD Magic; */ +#else + 0x010B, /*WORD Magic; */ +#endif + 0x06, /*BYTE MajorLinkerVersion; */ + 0x00, /*BYTE MinorLinkerVersion; */ + 0x00000000, /*DWORD SizeOfCode; */ + 0x00000000, /*DWORD SizeOfInitializedData; */ + 0x00000000, /*DWORD SizeOfUninitializedData; */ + 0x00000000, /*DWORD AddressOfEntryPoint; */ + 0x00000000, /*DWORD BaseOfCode; */ +#ifndef TCC_TARGET_X86_64 + 0x00000000, /*DWORD BaseOfData; */ +#endif + /* NT additional fields. */ +#if defined(TCC_TARGET_ARM) + 0x00100000, /*DWORD ImageBase; */ +#else + 0x00400000, /*DWORD ImageBase; */ +#endif + 0x00001000, /*DWORD SectionAlignment; */ + 0x00000200, /*DWORD FileAlignment; */ + 0x0004, /*WORD MajorOperatingSystemVersion; */ + 0x0000, /*WORD MinorOperatingSystemVersion; */ + 0x0000, /*WORD MajorImageVersion; */ + 0x0000, /*WORD MinorImageVersion; */ + 0x0004, /*WORD MajorSubsystemVersion; */ + 0x0000, /*WORD MinorSubsystemVersion; */ + 0x00000000, /*DWORD Win32VersionValue; */ + 0x00000000, /*DWORD SizeOfImage; */ + 0x00000200, /*DWORD SizeOfHeaders; */ + 0x00000000, /*DWORD CheckSum; */ + 0x0002, /*WORD Subsystem; */ + 0x0000, /*WORD DllCharacteristics; */ + 0x00100000, /*DWORD SizeOfStackReserve; */ + 0x00001000, /*DWORD SizeOfStackCommit; */ + 0x00100000, /*DWORD SizeOfHeapReserve; */ + 0x00001000, /*DWORD SizeOfHeapCommit; */ + 0x00000000, /*DWORD LoaderFlags; */ + 0x00000010, /*DWORD NumberOfRvaAndSizes; */ + + /* IMAGE_DATA_DIRECTORY DataDirectory[16]; */ + {{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}} + }}; + + struct pe_header pe_header = pe_template; + + int i; + FILE *op; + DWORD file_offset, sum; + struct section_info *si; + IMAGE_SECTION_HEADER *psh; + + op = fopen(pe->filename, "wb"); + if (NULL == op) { + tcc_error_noabort("could not write '%s': %s", pe->filename, strerror(errno)); + return -1; + } + + pe->sizeofheaders = pe_file_align(pe, + sizeof (struct pe_header) + + pe->sec_count * sizeof (IMAGE_SECTION_HEADER) + ); + + file_offset = pe->sizeofheaders; + + if (2 == pe->s1->verbose) + printf("-------------------------------" + "\n virt file size section" "\n"); + for (i = 0; i < pe->sec_count; ++i) { + DWORD addr, size; + const char *sh_name; + + si = pe->sec_info + i; + sh_name = si->name; + addr = si->sh_addr - pe->imagebase; + size = si->sh_size; + psh = &si->ish; + + if (2 == pe->s1->verbose) + printf("%6x %6x %6x %s\n", + (unsigned)addr, (unsigned)file_offset, (unsigned)size, sh_name); + + switch (si->cls) { + case sec_text: + pe_header.opthdr.BaseOfCode = addr; + break; + + case sec_data: +#ifndef TCC_TARGET_X86_64 + pe_header.opthdr.BaseOfData = addr; +#endif + break; + + case sec_bss: + break; + + case sec_reloc: + pe_set_datadir(&pe_header, IMAGE_DIRECTORY_ENTRY_BASERELOC, addr, size); + break; + + case sec_rsrc: + pe_set_datadir(&pe_header, IMAGE_DIRECTORY_ENTRY_RESOURCE, addr, size); + break; + + case sec_pdata: + pe_set_datadir(&pe_header, IMAGE_DIRECTORY_ENTRY_EXCEPTION, addr, size); + break; + + case sec_stab: + break; + } + + if (pe->thunk == pe->s1->sections[si->ord]) { + if (pe->imp_size) { + pe_set_datadir(&pe_header, IMAGE_DIRECTORY_ENTRY_IMPORT, + pe->imp_offs + addr, pe->imp_size); + pe_set_datadir(&pe_header, IMAGE_DIRECTORY_ENTRY_IAT, + pe->iat_offs + addr, pe->iat_size); + } + if (pe->exp_size) { + pe_set_datadir(&pe_header, IMAGE_DIRECTORY_ENTRY_EXPORT, + pe->exp_offs + addr, pe->exp_size); + } + } + + strncpy((char*)psh->Name, sh_name, sizeof psh->Name); + + psh->Characteristics = pe_sec_flags[si->cls]; + psh->VirtualAddress = addr; + psh->Misc.VirtualSize = size; + pe_header.opthdr.SizeOfImage = + umax(pe_virtual_align(pe, size + addr), pe_header.opthdr.SizeOfImage); + + if (si->data_size) { + psh->PointerToRawData = file_offset; + file_offset = pe_file_align(pe, file_offset + si->data_size); + psh->SizeOfRawData = file_offset - psh->PointerToRawData; + if (si->cls == sec_text) + pe_header.opthdr.SizeOfCode += psh->SizeOfRawData; + else + pe_header.opthdr.SizeOfInitializedData += psh->SizeOfRawData; + } + } + + //pe_header.filehdr.TimeDateStamp = time(NULL); + pe_header.filehdr.NumberOfSections = pe->sec_count; + pe_header.opthdr.AddressOfEntryPoint = pe->start_addr; + pe_header.opthdr.SizeOfHeaders = pe->sizeofheaders; + pe_header.opthdr.ImageBase = pe->imagebase; + pe_header.opthdr.Subsystem = pe->subsystem; + if (pe->s1->pe_stack_size) + pe_header.opthdr.SizeOfStackReserve = pe->s1->pe_stack_size; + if (PE_DLL == pe->type) + pe_header.filehdr.Characteristics = CHARACTERISTICS_DLL; + pe_header.filehdr.Characteristics |= pe->s1->pe_characteristics; + + sum = 0; + pe_fwrite(&pe_header, sizeof pe_header, op, &sum); + for (i = 0; i < pe->sec_count; ++i) + pe_fwrite(&pe->sec_info[i].ish, sizeof(IMAGE_SECTION_HEADER), op, &sum); + pe_fpad(op, pe->sizeofheaders); + for (i = 0; i < pe->sec_count; ++i) { + si = pe->sec_info + i; + psh = &si->ish; + if (si->data_size) { + pe_fwrite(si->data, si->data_size, op, &sum); + file_offset = psh->PointerToRawData + psh->SizeOfRawData; + pe_fpad(op, file_offset); + } + } + + pe_header.opthdr.CheckSum = sum + file_offset; + fseek(op, offsetof(struct pe_header, opthdr.CheckSum), SEEK_SET); + pe_fwrite(&pe_header.opthdr.CheckSum, sizeof pe_header.opthdr.CheckSum, op, NULL); + fclose (op); +#ifndef _WIN32 + chmod(pe->filename, 0777); +#endif + + if (2 == pe->s1->verbose) + printf("-------------------------------\n"); + if (pe->s1->verbose) + printf("<- %s (%u bytes)\n", pe->filename, (unsigned)file_offset); + + return 0; +} + +/*----------------------------------------------------------------------------*/ + +static struct import_symbol *pe_add_import(struct pe_info *pe, int sym_index) +{ + int i; + int dll_index; + struct pe_import_info *p; + struct import_symbol *s; + ElfW(Sym) *isym; + + isym = (ElfW(Sym) *)pe->s1->dynsymtab_section->data + sym_index; + dll_index = isym->st_size; + + i = dynarray_assoc ((void**)pe->imp_info, pe->imp_count, dll_index); + if (-1 != i) { + p = pe->imp_info[i]; + goto found_dll; + } + p = tcc_mallocz(sizeof *p); + p->dll_index = dll_index; + dynarray_add(&pe->imp_info, &pe->imp_count, p); + +found_dll: + i = dynarray_assoc ((void**)p->symbols, p->sym_count, sym_index); + if (-1 != i) + return p->symbols[i]; + + s = tcc_mallocz(sizeof *s); + dynarray_add(&p->symbols, &p->sym_count, s); + s->sym_index = sym_index; + return s; +} + +void pe_free_imports(struct pe_info *pe) +{ + int i; + for (i = 0; i < pe->imp_count; ++i) { + struct pe_import_info *p = pe->imp_info[i]; + dynarray_reset(&p->symbols, &p->sym_count); + } + dynarray_reset(&pe->imp_info, &pe->imp_count); +} + +/*----------------------------------------------------------------------------*/ +static void pe_build_imports(struct pe_info *pe) +{ + int thk_ptr, ent_ptr, dll_ptr, sym_cnt, i; + DWORD rva_base = pe->thunk->sh_addr - pe->imagebase; + int ndlls = pe->imp_count; + + for (sym_cnt = i = 0; i < ndlls; ++i) + sym_cnt += pe->imp_info[i]->sym_count; + + if (0 == sym_cnt) + return; + + pe_align_section(pe->thunk, 16); + + pe->imp_offs = dll_ptr = pe->thunk->data_offset; + pe->imp_size = (ndlls + 1) * sizeof(IMAGE_IMPORT_DESCRIPTOR); + pe->iat_offs = dll_ptr + pe->imp_size; + pe->iat_size = (sym_cnt + ndlls) * sizeof(ADDR3264); + section_ptr_add(pe->thunk, pe->imp_size + 2*pe->iat_size); + + thk_ptr = pe->iat_offs; + ent_ptr = pe->iat_offs + pe->iat_size; + + for (i = 0; i < pe->imp_count; ++i) { + IMAGE_IMPORT_DESCRIPTOR *hdr; + int k, n, dllindex; + ADDR3264 v; + struct pe_import_info *p = pe->imp_info[i]; + const char *name; + DLLReference *dllref; + + dllindex = p->dll_index; + if (dllindex) + name = (dllref = pe->s1->loaded_dlls[dllindex-1])->name; + else + name = "", dllref = NULL; + + /* put the dll name into the import header */ + v = put_elf_str(pe->thunk, name); + hdr = (IMAGE_IMPORT_DESCRIPTOR*)(pe->thunk->data + dll_ptr); + hdr->FirstThunk = thk_ptr + rva_base; + hdr->OriginalFirstThunk = ent_ptr + rva_base; + hdr->Name = v + rva_base; + + for (k = 0, n = p->sym_count; k <= n; ++k) { + if (k < n) { + int iat_index = p->symbols[k]->iat_index; + int sym_index = p->symbols[k]->sym_index; + ElfW(Sym) *imp_sym = (ElfW(Sym) *)pe->s1->dynsymtab_section->data + sym_index; + ElfW(Sym) *org_sym = (ElfW(Sym) *)symtab_section->data + iat_index; + const char *name = (char*)pe->s1->dynsymtab_section->link->data + imp_sym->st_name; + int ordinal; + + org_sym->st_value = thk_ptr; + org_sym->st_shndx = pe->thunk->sh_num; + + if (dllref) + v = 0, ordinal = imp_sym->st_value; /* ordinal from pe_load_def */ + else + ordinal = 0, v = imp_sym->st_value; /* address from tcc_add_symbol() */ + +#ifdef TCC_IS_NATIVE + if (pe->type == PE_RUN) { + if (dllref) { + if ( !dllref->handle ) + dllref->handle = LoadLibrary(dllref->name); + v = (ADDR3264)GetProcAddress(dllref->handle, ordinal?(char*)0+ordinal:name); + } + if (!v) + tcc_error_noabort("can't build symbol '%s'", name); + } else +#endif + if (ordinal) { + v = ordinal | (ADDR3264)1 << (sizeof(ADDR3264)*8 - 1); + } else { + v = pe->thunk->data_offset + rva_base; + section_ptr_add(pe->thunk, sizeof(WORD)); /* hint, not used */ + put_elf_str(pe->thunk, name); + } + + } else { + v = 0; /* last entry is zero */ + } + + *(ADDR3264*)(pe->thunk->data+thk_ptr) = + *(ADDR3264*)(pe->thunk->data+ent_ptr) = v; + thk_ptr += sizeof (ADDR3264); + ent_ptr += sizeof (ADDR3264); + } + dll_ptr += sizeof(IMAGE_IMPORT_DESCRIPTOR); + } +} + +/* ------------------------------------------------------------- */ + +struct pe_sort_sym +{ + int index; + const char *name; +}; + +static int sym_cmp(const void *va, const void *vb) +{ + const char *ca = (*(struct pe_sort_sym**)va)->name; + const char *cb = (*(struct pe_sort_sym**)vb)->name; + return strcmp(ca, cb); +} + +static void pe_build_exports(struct pe_info *pe) +{ + ElfW(Sym) *sym; + int sym_index, sym_end; + DWORD rva_base, func_o, name_o, ord_o, str_o; + IMAGE_EXPORT_DIRECTORY *hdr; + int sym_count, ord; + struct pe_sort_sym **sorted, *p; + + FILE *op; + char buf[260]; + const char *dllname; + const char *name; + + rva_base = pe->thunk->sh_addr - pe->imagebase; + sym_count = 0, sorted = NULL, op = NULL; + + sym_end = symtab_section->data_offset / sizeof(ElfW(Sym)); + for (sym_index = 1; sym_index < sym_end; ++sym_index) { + sym = (ElfW(Sym)*)symtab_section->data + sym_index; + name = pe_export_name(pe->s1, sym); + if ((sym->st_other & ST_PE_EXPORT) + /* export only symbols from actually written sections */ + && pe->s1->sections[sym->st_shndx]->sh_addr) { + p = tcc_malloc(sizeof *p); + p->index = sym_index; + p->name = name; + dynarray_add(&sorted, &sym_count, p); + } +#if 0 + if (sym->st_other & ST_PE_EXPORT) + printf("export: %s\n", name); + if (sym->st_other & ST_PE_STDCALL) + printf("stdcall: %s\n", name); +#endif + } + + if (0 == sym_count) + return; + + qsort (sorted, sym_count, sizeof *sorted, sym_cmp); + + pe_align_section(pe->thunk, 16); + dllname = tcc_basename(pe->filename); + + pe->exp_offs = pe->thunk->data_offset; + func_o = pe->exp_offs + sizeof(IMAGE_EXPORT_DIRECTORY); + name_o = func_o + sym_count * sizeof (DWORD); + ord_o = name_o + sym_count * sizeof (DWORD); + str_o = ord_o + sym_count * sizeof(WORD); + + hdr = section_ptr_add(pe->thunk, str_o - pe->exp_offs); + hdr->Characteristics = 0; + hdr->Base = 1; + hdr->NumberOfFunctions = sym_count; + hdr->NumberOfNames = sym_count; + hdr->AddressOfFunctions = func_o + rva_base; + hdr->AddressOfNames = name_o + rva_base; + hdr->AddressOfNameOrdinals = ord_o + rva_base; + hdr->Name = str_o + rva_base; + put_elf_str(pe->thunk, dllname); + +#if 1 + /* automatically write exports to .def */ + pstrcpy(buf, sizeof buf, pe->filename); + strcpy(tcc_fileextension(buf), ".def"); + op = fopen(buf, "w"); + if (NULL == op) { + tcc_error_noabort("could not create '%s': %s", buf, strerror(errno)); + } else { + fprintf(op, "LIBRARY %s\n\nEXPORTS\n", dllname); + if (pe->s1->verbose) + printf("<- %s (%d symbol%s)\n", buf, sym_count, &"s"[sym_count < 2]); + } +#endif + + for (ord = 0; ord < sym_count; ++ord) + { + p = sorted[ord], sym_index = p->index, name = p->name; + /* insert actual address later in pe_relocate_rva */ + put_elf_reloc(symtab_section, pe->thunk, + func_o, R_XXX_RELATIVE, sym_index); + *(DWORD*)(pe->thunk->data + name_o) + = pe->thunk->data_offset + rva_base; + *(WORD*)(pe->thunk->data + ord_o) + = ord; + put_elf_str(pe->thunk, name); + func_o += sizeof (DWORD); + name_o += sizeof (DWORD); + ord_o += sizeof (WORD); + if (op) + fprintf(op, "%s\n", name); + } + pe->exp_size = pe->thunk->data_offset - pe->exp_offs; + dynarray_reset(&sorted, &sym_count); + if (op) + fclose(op); +} + +/* ------------------------------------------------------------- */ +static void pe_build_reloc (struct pe_info *pe) +{ + DWORD offset, block_ptr, addr; + int count, i; + ElfW_Rel *rel, *rel_end; + Section *s = NULL, *sr; + + offset = addr = block_ptr = count = i = 0; + rel = rel_end = NULL; + + for(;;) { + if (rel < rel_end) { + int type = ELFW(R_TYPE)(rel->r_info); + addr = rel->r_offset + s->sh_addr; + ++ rel; + if (type != REL_TYPE_DIRECT) + continue; + if (count == 0) { /* new block */ + block_ptr = pe->reloc->data_offset; + section_ptr_add(pe->reloc, sizeof(struct pe_reloc_header)); + offset = addr & 0xFFFFFFFF<<12; + } + if ((addr -= offset) < (1<<12)) { /* one block spans 4k addresses */ + WORD *wp = section_ptr_add(pe->reloc, sizeof (WORD)); + *wp = addr | PE_IMAGE_REL<<12; + ++count; + continue; + } + -- rel; + + } else if (i < pe->sec_count) { + sr = (s = pe->s1->sections[pe->sec_info[i++].ord])->reloc; + if (sr) { + rel = (ElfW_Rel *)sr->data; + rel_end = (ElfW_Rel *)(sr->data + sr->data_offset); + } + continue; + } + + if (count) { + /* store the last block and ready for a new one */ + struct pe_reloc_header *hdr; + if (count & 1) /* align for DWORDS */ + section_ptr_add(pe->reloc, sizeof(WORD)), ++count; + hdr = (struct pe_reloc_header *)(pe->reloc->data + block_ptr); + hdr -> offset = offset - pe->imagebase; + hdr -> size = count * sizeof(WORD) + sizeof(struct pe_reloc_header); + count = 0; + } + + if (rel >= rel_end) + break; + } +} + +/* ------------------------------------------------------------- */ +static int pe_section_class(Section *s) +{ + int type, flags; + const char *name; + + type = s->sh_type; + flags = s->sh_flags; + name = s->name; + if (flags & SHF_ALLOC) { + if (type == SHT_PROGBITS) { + if (flags & SHF_EXECINSTR) + return sec_text; + if (flags & SHF_WRITE) + return sec_data; + if (0 == strcmp(name, ".rsrc")) + return sec_rsrc; + if (0 == strcmp(name, ".iedat")) + return sec_idata; + if (0 == strcmp(name, ".pdata")) + return sec_pdata; + return sec_other; + } else if (type == SHT_NOBITS) { + if (flags & SHF_WRITE) + return sec_bss; + } + } else { + if (0 == strcmp(name, ".reloc")) + return sec_reloc; + if (0 == strncmp(name, ".stab", 5)) /* .stab and .stabstr */ + return sec_stab; + } + return -1; +} + +static int pe_assign_addresses (struct pe_info *pe) +{ + int i, k, o, c; + DWORD addr; + int *section_order; + struct section_info *si; + Section *s; + + if (PE_DLL == pe->type) + pe->reloc = new_section(pe->s1, ".reloc", SHT_PROGBITS, 0); + + // pe->thunk = new_section(pe->s1, ".iedat", SHT_PROGBITS, SHF_ALLOC); + + section_order = tcc_malloc(pe->s1->nb_sections * sizeof (int)); + for (o = k = 0 ; k < sec_last; ++k) { + for (i = 1; i < pe->s1->nb_sections; ++i) { + s = pe->s1->sections[i]; + if (k == pe_section_class(s)) { + // printf("%s %d\n", s->name, k); + s->sh_addr = pe->imagebase; + section_order[o++] = i; + } + } + } + + pe->sec_info = tcc_mallocz(o * sizeof (struct section_info)); + addr = pe->imagebase + 1; + + for (i = 0; i < o; ++i) + { + k = section_order[i]; + s = pe->s1->sections[k]; + c = pe_section_class(s); + si = &pe->sec_info[pe->sec_count]; + +#ifdef PE_MERGE_DATA + if (c == sec_bss && pe->sec_count && si[-1].cls == sec_data) { + /* append .bss to .data */ + s->sh_addr = addr = ((addr-1) | (s->sh_addralign-1)) + 1; + addr += s->data_offset; + si[-1].sh_size = addr - si[-1].sh_addr; + continue; + } +#endif + if (c == sec_stab && 0 == pe->s1->do_debug) + continue; + + strcpy(si->name, s->name); + si->cls = c; + si->ord = k; + si->sh_addr = s->sh_addr = addr = pe_virtual_align(pe, addr); + si->sh_flags = s->sh_flags; + + if (c == sec_data && NULL == pe->thunk) + pe->thunk = s; + + if (s == pe->thunk) { + pe_build_imports(pe); + pe_build_exports(pe); + } + + if (c == sec_reloc) + pe_build_reloc (pe); + + if (s->data_offset) + { + if (s->sh_type != SHT_NOBITS) { + si->data = s->data; + si->data_size = s->data_offset; + } + + addr += s->data_offset; + si->sh_size = s->data_offset; + ++pe->sec_count; + } + // printf("%08x %05x %s\n", si->sh_addr, si->sh_size, si->name); + } + +#if 0 + for (i = 1; i < pe->s1->nb_sections; ++i) { + Section *s = pe->s1->sections[i]; + int type = s->sh_type; + int flags = s->sh_flags; + printf("section %-16s %-10s %5x %s,%s,%s\n", + s->name, + type == SHT_PROGBITS ? "progbits" : + type == SHT_NOBITS ? "nobits" : + type == SHT_SYMTAB ? "symtab" : + type == SHT_STRTAB ? "strtab" : + type == SHT_RELX ? "rel" : "???", + s->data_offset, + flags & SHF_ALLOC ? "alloc" : "", + flags & SHF_WRITE ? "write" : "", + flags & SHF_EXECINSTR ? "exec" : "" + ); + } + pe->s1->verbose = 2; +#endif + + tcc_free(section_order); + return 0; +} + +/* ------------------------------------------------------------- */ +static void pe_relocate_rva (struct pe_info *pe, Section *s) +{ + Section *sr = s->reloc; + ElfW_Rel *rel, *rel_end; + rel_end = (ElfW_Rel *)(sr->data + sr->data_offset); + for(rel = (ElfW_Rel *)sr->data; rel < rel_end; rel++) { + if (ELFW(R_TYPE)(rel->r_info) == R_XXX_RELATIVE) { + int sym_index = ELFW(R_SYM)(rel->r_info); + DWORD addr = s->sh_addr; + if (sym_index) { + ElfW(Sym) *sym = (ElfW(Sym) *)symtab_section->data + sym_index; + addr = sym->st_value; + } + // printf("reloc rva %08x %08x %s\n", (DWORD)rel->r_offset, addr, s->name); + *(DWORD*)(s->data + rel->r_offset) += addr - pe->imagebase; + } + } +} + +/*----------------------------------------------------------------------------*/ + +static int pe_isafunc(int sym_index) +{ + Section *sr = text_section->reloc; + ElfW_Rel *rel, *rel_end; + Elf32_Word info = ELF32_R_INFO(sym_index, R_386_PC32); + if (!sr) + return 0; + rel_end = (ElfW_Rel *)(sr->data + sr->data_offset); + for (rel = (ElfW_Rel *)sr->data; rel < rel_end; rel++) + if (rel->r_info == info) + return 1; + return 0; +} + +/*----------------------------------------------------------------------------*/ +static int pe_check_symbols(struct pe_info *pe) +{ + ElfW(Sym) *sym; + int sym_index, sym_end; + int ret = 0; + + pe_align_section(text_section, 8); + + sym_end = symtab_section->data_offset / sizeof(ElfW(Sym)); + for (sym_index = 1; sym_index < sym_end; ++sym_index) { + + sym = (ElfW(Sym) *)symtab_section->data + sym_index; + if (sym->st_shndx == SHN_UNDEF) { + + const char *name = (char*)symtab_section->link->data + sym->st_name; + unsigned type = ELFW(ST_TYPE)(sym->st_info); + int imp_sym = pe_find_import(pe->s1, sym); + struct import_symbol *is; + + if (imp_sym <= 0) + goto not_found; + + if (type == STT_NOTYPE) { + /* symbols from assembler have no type, find out which */ + if (pe_isafunc(sym_index)) + type = STT_FUNC; + else + type = STT_OBJECT; + } + + is = pe_add_import(pe, imp_sym); + + if (type == STT_FUNC) { + unsigned long offset = is->thk_offset; + if (offset) { + /* got aliased symbol, like stricmp and _stricmp */ + + } else { + char buffer[100]; + WORD *p; + + offset = text_section->data_offset; + /* add the 'jmp IAT[x]' instruction */ +#ifdef TCC_TARGET_ARM + p = section_ptr_add(text_section, 8+4); // room for code and address + (*(DWORD*)(p)) = 0xE59FC000; // arm code ldr ip, [pc] ; PC+8+0 = 0001xxxx + (*(DWORD*)(p+2)) = 0xE59CF000; // arm code ldr pc, [ip] +#else + p = section_ptr_add(text_section, 8); + *p = 0x25FF; +#ifdef TCC_TARGET_X86_64 + *(DWORD*)(p+1) = (DWORD)-4; +#endif +#endif + /* add a helper symbol, will be patched later in + pe_build_imports */ + sprintf(buffer, "IAT.%s", name); + is->iat_index = put_elf_sym( + symtab_section, 0, sizeof(DWORD), + ELFW(ST_INFO)(STB_GLOBAL, STT_OBJECT), + 0, SHN_UNDEF, buffer); +#ifdef TCC_TARGET_ARM + put_elf_reloc(symtab_section, text_section, + offset + 8, R_XXX_THUNKFIX, is->iat_index); // offset to IAT position +#else + put_elf_reloc(symtab_section, text_section, + offset + 2, R_XXX_THUNKFIX, is->iat_index); +#endif + is->thk_offset = offset; + } + + /* tcc_realloc might have altered sym's address */ + sym = (ElfW(Sym) *)symtab_section->data + sym_index; + + /* patch the original symbol */ + sym->st_value = offset; + sym->st_shndx = text_section->sh_num; + sym->st_other &= ~ST_PE_EXPORT; /* do not export */ + continue; + } + + if (type == STT_OBJECT) { /* data, ptr to that should be */ + if (0 == is->iat_index) { + /* original symbol will be patched later in pe_build_imports */ + is->iat_index = sym_index; + continue; + } + } + + not_found: + if (ELFW(ST_BIND)(sym->st_info) == STB_WEAK) + /* STB_WEAK undefined symbols are accepted */ + continue; + tcc_error_noabort("undefined symbol '%s'%s", name, + imp_sym < 0 ? ", missing __declspec(dllimport)?":""); + ret = -1; + + } else if (pe->s1->rdynamic + && ELFW(ST_BIND)(sym->st_info) != STB_LOCAL) { + /* if -rdynamic option, then export all non local symbols */ + sym->st_other |= ST_PE_EXPORT; + } + } + return ret; +} + +/*----------------------------------------------------------------------------*/ +#ifdef PE_PRINT_SECTIONS +static void pe_print_section(FILE * f, Section * s) +{ + /* just if you're curious */ + BYTE *p, *e, b; + int i, n, l, m; + p = s->data; + e = s->data + s->data_offset; + l = e - p; + + fprintf(f, "section \"%s\"", s->name); + if (s->link) + fprintf(f, "\nlink \"%s\"", s->link->name); + if (s->reloc) + fprintf(f, "\nreloc \"%s\"", s->reloc->name); + fprintf(f, "\nv_addr %08X", (unsigned)s->sh_addr); + fprintf(f, "\ncontents %08X", (unsigned)l); + fprintf(f, "\n\n"); + + if (s->sh_type == SHT_NOBITS) + return; + + if (0 == l) + return; + + if (s->sh_type == SHT_SYMTAB) + m = sizeof(ElfW(Sym)); + else if (s->sh_type == SHT_RELX) + m = sizeof(ElfW_Rel); + else + m = 16; + + fprintf(f, "%-8s", "offset"); + for (i = 0; i < m; ++i) + fprintf(f, " %02x", i); + n = 56; + + if (s->sh_type == SHT_SYMTAB || s->sh_type == SHT_RELX) { + const char *fields1[] = { + "name", + "value", + "size", + "bind", + "type", + "other", + "shndx", + NULL + }; + + const char *fields2[] = { + "offs", + "type", + "symb", + NULL + }; + + const char **p; + + if (s->sh_type == SHT_SYMTAB) + p = fields1, n = 106; + else + p = fields2, n = 58; + + for (i = 0; p[i]; ++i) + fprintf(f, "%6s", p[i]); + fprintf(f, " symbol"); + } + + fprintf(f, "\n"); + for (i = 0; i < n; ++i) + fprintf(f, "-"); + fprintf(f, "\n"); + + for (i = 0; i < l;) + { + fprintf(f, "%08X", i); + for (n = 0; n < m; ++n) { + if (n + i < l) + fprintf(f, " %02X", p[i + n]); + else + fprintf(f, " "); + } + + if (s->sh_type == SHT_SYMTAB) { + ElfW(Sym) *sym = (ElfW(Sym) *) (p + i); + const char *name = s->link->data + sym->st_name; + fprintf(f, " %04X %04X %04X %02X %02X %02X %04X \"%s\"", + (unsigned)sym->st_name, + (unsigned)sym->st_value, + (unsigned)sym->st_size, + (unsigned)ELFW(ST_BIND)(sym->st_info), + (unsigned)ELFW(ST_TYPE)(sym->st_info), + (unsigned)sym->st_other, + (unsigned)sym->st_shndx, + name); + + } else if (s->sh_type == SHT_RELX) { + ElfW_Rel *rel = (ElfW_Rel *) (p + i); + ElfW(Sym) *sym = + (ElfW(Sym) *) s->link->data + ELFW(R_SYM)(rel->r_info); + const char *name = s->link->link->data + sym->st_name; + fprintf(f, " %04X %02X %04X \"%s\"", + (unsigned)rel->r_offset, + (unsigned)ELFW(R_TYPE)(rel->r_info), + (unsigned)ELFW(R_SYM)(rel->r_info), + name); + } else { + fprintf(f, " "); + for (n = 0; n < m; ++n) { + if (n + i < l) { + b = p[i + n]; + if (b < 32 || b >= 127) + b = '.'; + fprintf(f, "%c", b); + } + } + } + i += m; + fprintf(f, "\n"); + } + fprintf(f, "\n\n"); +} + +static void pe_print_sections(TCCState *s1, const char *fname) +{ + Section *s; + FILE *f; + int i; + f = fopen(fname, "w"); + for (i = 1; i < s1->nb_sections; ++i) { + s = s1->sections[i]; + pe_print_section(f, s); + } + pe_print_section(f, s1->dynsymtab_section); + fclose(f); +} +#endif + +/* ------------------------------------------------------------- */ +/* helper function for load/store to insert one more indirection */ + +#if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64 +ST_FUNC SValue *pe_getimport(SValue *sv, SValue *v2) +{ + int r2; + if ((sv->r & (VT_VALMASK|VT_SYM)) != (VT_CONST|VT_SYM) || (sv->r2 != VT_CONST)) + return sv; + if (!sv->sym->a.dllimport) + return sv; + // printf("import %04x %04x %04x %s\n", sv->type.t, sv->sym->type.t, sv->r, get_tok_str(sv->sym->v, NULL)); + memset(v2, 0, sizeof *v2); + v2->type.t = VT_PTR; + v2->r = VT_CONST | VT_SYM | VT_LVAL; + v2->sym = sv->sym; + + r2 = get_reg(RC_INT); + load(r2, v2); + v2->r = r2; + if ((uint32_t)sv->c.i) { + vpushv(v2); + vpushi(sv->c.i); + gen_opi('+'); + *v2 = *vtop--; + } + v2->type.t = sv->type.t; + v2->r |= sv->r & VT_LVAL; + return v2; +} +#endif + +ST_FUNC int pe_putimport(TCCState *s1, int dllindex, const char *name, addr_t value) +{ + return set_elf_sym( + s1->dynsymtab_section, + value, + dllindex, /* st_size */ + ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), + 0, + value ? SHN_ABS : SHN_UNDEF, + name + ); +} + +static int add_dllref(TCCState *s1, const char *dllname) +{ + DLLReference *dllref; + int i; + for (i = 0; i < s1->nb_loaded_dlls; ++i) + if (0 == strcmp(s1->loaded_dlls[i]->name, dllname)) + return i + 1; + dllref = tcc_mallocz(sizeof(DLLReference) + strlen(dllname)); + strcpy(dllref->name, dllname); + dynarray_add(&s1->loaded_dlls, &s1->nb_loaded_dlls, dllref); + return s1->nb_loaded_dlls; +} + +/* ------------------------------------------------------------- */ + +static int read_mem(int fd, unsigned offset, void *buffer, unsigned len) +{ + lseek(fd, offset, SEEK_SET); + return len == read(fd, buffer, len); +} + +/* ------------------------------------------------------------- */ + +PUB_FUNC int tcc_get_dllexports(const char *filename, char **pp) +{ + int l, i, n, n0, ret; + char *p; + int fd; + + IMAGE_SECTION_HEADER ish; + IMAGE_EXPORT_DIRECTORY ied; + IMAGE_DOS_HEADER dh; + IMAGE_FILE_HEADER ih; + DWORD sig, ref, addr, ptr, namep; + + int pef_hdroffset, opt_hdroffset, sec_hdroffset; + + n = n0 = 0; + p = NULL; + ret = -1; + + fd = open(filename, O_RDONLY | O_BINARY); + if (fd < 0) + goto the_end_1; + ret = 1; + if (!read_mem(fd, 0, &dh, sizeof dh)) + goto the_end; + if (!read_mem(fd, dh.e_lfanew, &sig, sizeof sig)) + goto the_end; + if (sig != 0x00004550) + goto the_end; + pef_hdroffset = dh.e_lfanew + sizeof sig; + if (!read_mem(fd, pef_hdroffset, &ih, sizeof ih)) + goto the_end; + opt_hdroffset = pef_hdroffset + sizeof ih; + if (ih.Machine == 0x014C) { + IMAGE_OPTIONAL_HEADER32 oh; + sec_hdroffset = opt_hdroffset + sizeof oh; + if (!read_mem(fd, opt_hdroffset, &oh, sizeof oh)) + goto the_end; + if (IMAGE_DIRECTORY_ENTRY_EXPORT >= oh.NumberOfRvaAndSizes) + goto the_end_0; + addr = oh.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress; + } else if (ih.Machine == 0x8664) { + IMAGE_OPTIONAL_HEADER64 oh; + sec_hdroffset = opt_hdroffset + sizeof oh; + if (!read_mem(fd, opt_hdroffset, &oh, sizeof oh)) + goto the_end; + if (IMAGE_DIRECTORY_ENTRY_EXPORT >= oh.NumberOfRvaAndSizes) + goto the_end_0; + addr = oh.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress; + } else + goto the_end; + + //printf("addr: %08x\n", addr); + for (i = 0; i < ih.NumberOfSections; ++i) { + if (!read_mem(fd, sec_hdroffset + i * sizeof ish, &ish, sizeof ish)) + goto the_end; + //printf("vaddr: %08x\n", ish.VirtualAddress); + if (addr >= ish.VirtualAddress && addr < ish.VirtualAddress + ish.SizeOfRawData) + goto found; + } + goto the_end_0; + +found: + ref = ish.VirtualAddress - ish.PointerToRawData; + if (!read_mem(fd, addr - ref, &ied, sizeof ied)) + goto the_end; + + namep = ied.AddressOfNames - ref; + for (i = 0; i < ied.NumberOfNames; ++i) { + if (!read_mem(fd, namep, &ptr, sizeof ptr)) + goto the_end; + namep += sizeof ptr; + for (l = 0;;) { + if (n+1 >= n0) + p = tcc_realloc(p, n0 = n0 ? n0 * 2 : 256); + if (!read_mem(fd, ptr - ref + l++, p + n, 1)) { + tcc_free(p), p = NULL; + goto the_end; + } + if (p[n++] == 0) + break; + } + } + if (p) + p[n] = 0; +the_end_0: + ret = 0; +the_end: + close(fd); +the_end_1: + *pp = p; + return ret; +} + +/* ------------------------------------------------------------- + * This is for compiled windows resources in 'coff' format + * as generated by 'windres.exe -O coff ...'. + */ + +static int pe_load_res(TCCState *s1, int fd) +{ + struct pe_rsrc_header hdr; + Section *rsrc_section; + int i, ret = -1; + BYTE *ptr; + unsigned offs; + + if (!read_mem(fd, 0, &hdr, sizeof hdr)) + goto quit; + + if (hdr.filehdr.Machine != IMAGE_FILE_MACHINE + || hdr.filehdr.NumberOfSections != 1 + || strcmp((char*)hdr.sectionhdr.Name, ".rsrc") != 0) + goto quit; + + rsrc_section = new_section(s1, ".rsrc", SHT_PROGBITS, SHF_ALLOC); + ptr = section_ptr_add(rsrc_section, hdr.sectionhdr.SizeOfRawData); + offs = hdr.sectionhdr.PointerToRawData; + if (!read_mem(fd, offs, ptr, hdr.sectionhdr.SizeOfRawData)) + goto quit; + offs = hdr.sectionhdr.PointerToRelocations; + for (i = 0; i < hdr.sectionhdr.NumberOfRelocations; ++i) + { + struct pe_rsrc_reloc rel; + if (!read_mem(fd, offs, &rel, sizeof rel)) + goto quit; + // printf("rsrc_reloc: %x %x %x\n", rel.offset, rel.size, rel.type); + if (rel.type != RSRC_RELTYPE) + goto quit; + put_elf_reloc(symtab_section, rsrc_section, + rel.offset, R_XXX_RELATIVE, 0); + offs += sizeof rel; + } + ret = 0; +quit: + return ret; +} + +/* ------------------------------------------------------------- */ + +static char *trimfront(char *p) +{ + while (*p && (unsigned char)*p <= ' ') + ++p; + return p; +} + +static char *trimback(char *a, char *e) +{ + while (e > a && (unsigned char)e[-1] <= ' ') + --e; + *e = 0;; + return a; +} + +/* ------------------------------------------------------------- */ +static int pe_load_def(TCCState *s1, int fd) +{ + int state = 0, ret = -1, dllindex = 0, ord; + char line[400], dllname[80], *p, *x; + FILE *fp; + + fp = fdopen(dup(fd), "rb"); + while (fgets(line, sizeof line, fp)) + { + p = trimfront(trimback(line, strchr(line, 0))); + if (0 == *p || ';' == *p) + continue; + + switch (state) { + case 0: + if (0 != strnicmp(p, "LIBRARY", 7)) + goto quit; + pstrcpy(dllname, sizeof dllname, trimfront(p+7)); + ++state; + continue; + + case 1: + if (0 != stricmp(p, "EXPORTS")) + goto quit; + ++state; + continue; + + case 2: + dllindex = add_dllref(s1, dllname); + ++state; + /* fall through */ + default: + /* get ordinal and will store in sym->st_value */ + ord = 0; + x = strchr(p, ' '); + if (x) { + *x = 0, x = strrchr(x + 1, '@'); + if (x) { + char *d; + ord = (int)strtol(x + 1, &d, 10); + if (*d) + ord = 0; + } + } + pe_putimport(s1, dllindex, p, ord); + continue; + } + } + ret = 0; +quit: + fclose(fp); + return ret; +} + +/* ------------------------------------------------------------- */ +static int pe_load_dll(TCCState *s1, const char *filename) +{ + char *p, *q; + int index, ret; + + ret = tcc_get_dllexports(filename, &p); + if (ret) { + return -1; + } else if (p) { + index = add_dllref(s1, tcc_basename(filename)); + for (q = p; *q; q += 1 + strlen(q)) + pe_putimport(s1, index, q, 0); + tcc_free(p); + } + return 0; +} + +/* ------------------------------------------------------------- */ +ST_FUNC int pe_load_file(struct TCCState *s1, const char *filename, int fd) +{ + int ret = -1; + char buf[10]; + if (0 == strcmp(tcc_fileextension(filename), ".def")) + ret = pe_load_def(s1, fd); + else if (pe_load_res(s1, fd) == 0) + ret = 0; + else if (read_mem(fd, 0, buf, 4) && 0 == memcmp(buf, "MZ\220", 4)) + ret = pe_load_dll(s1, filename); + return ret; +} + +/* ------------------------------------------------------------- */ +#ifdef TCC_TARGET_X86_64 +static unsigned pe_add_uwwind_info(TCCState *s1) +{ + if (NULL == s1->uw_pdata) { + s1->uw_pdata = find_section(tcc_state, ".pdata"); + s1->uw_pdata->sh_addralign = 4; + s1->uw_sym = put_elf_sym(symtab_section, 0, 0, 0, 0, text_section->sh_num, NULL); + } + + if (0 == s1->uw_offs) { + /* As our functions all have the same stackframe, we use one entry for all */ + static const unsigned char uw_info[] = { + 0x01, // UBYTE: 3 Version , UBYTE: 5 Flags + 0x04, // UBYTE Size of prolog + 0x02, // UBYTE Count of unwind codes + 0x05, // UBYTE: 4 Frame Register (rbp), UBYTE: 4 Frame Register offset (scaled) + // USHORT * n Unwind codes array + // 0x0b, 0x01, 0xff, 0xff, // stack size + 0x04, 0x03, // set frame ptr (mov rsp -> rbp) + 0x01, 0x50 // push reg (rbp) + }; + + Section *s = text_section; + unsigned char *p; + + section_ptr_add(s, -s->data_offset & 3); /* align */ + s1->uw_offs = s->data_offset; + p = section_ptr_add(s, sizeof uw_info); + memcpy(p, uw_info, sizeof uw_info); + } + + return s1->uw_offs; +} + +ST_FUNC void pe_add_unwind_data(unsigned start, unsigned end, unsigned stack) +{ + TCCState *s1 = tcc_state; + Section *pd; + unsigned o, n, d; + struct /* _RUNTIME_FUNCTION */ { + DWORD BeginAddress; + DWORD EndAddress; + DWORD UnwindData; + } *p; + + d = pe_add_uwwind_info(s1); + pd = s1->uw_pdata; + o = pd->data_offset; + p = section_ptr_add(pd, sizeof *p); + + /* record this function */ + p->BeginAddress = start; + p->EndAddress = end; + p->UnwindData = d; + + /* put relocations on it */ + for (n = o + sizeof *p; o < n; o += sizeof p->BeginAddress) + put_elf_reloc(symtab_section, pd, o, R_X86_64_RELATIVE, s1->uw_sym); +} +#endif +/* ------------------------------------------------------------- */ +#ifdef TCC_TARGET_X86_64 +#define PE_STDSYM(n,s) n +#else +#define PE_STDSYM(n,s) "_" n s +#endif + +static void pe_add_runtime(TCCState *s1, struct pe_info *pe) +{ + const char *start_symbol; + int pe_type = 0; + int unicode_entry = 0; + + if (find_elf_sym(symtab_section, PE_STDSYM("WinMain","@16"))) + pe_type = PE_GUI; + else + if (find_elf_sym(symtab_section, PE_STDSYM("wWinMain","@16"))) { + pe_type = PE_GUI; + unicode_entry = PE_GUI; + } + else + if (TCC_OUTPUT_DLL == s1->output_type) { + pe_type = PE_DLL; + /* need this for 'tccelf.c:relocate_section()' */ + s1->output_type = TCC_OUTPUT_EXE; + } + else { + pe_type = PE_EXE; + if (find_elf_sym(symtab_section, "wmain")) + unicode_entry = PE_EXE; + } + + start_symbol = + TCC_OUTPUT_MEMORY == s1->output_type + ? PE_GUI == pe_type ? (unicode_entry ? "__runwwinmain" : "__runwinmain") + : (unicode_entry ? "__runwmain" : "__runmain") + : PE_DLL == pe_type ? PE_STDSYM("__dllstart","@12") + : PE_GUI == pe_type ? (unicode_entry ? "__wwinstart": "__winstart") + : (unicode_entry ? "__wstart" : "__start") + ; + + if (!s1->leading_underscore || strchr(start_symbol, '@')) + ++start_symbol; + + /* grab the startup code from libtcc1 */ +#ifdef TCC_IS_NATIVE + if (TCC_OUTPUT_MEMORY != s1->output_type || s1->runtime_main) +#endif + set_elf_sym(symtab_section, + 0, 0, + ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0, + SHN_UNDEF, start_symbol); + + tcc_add_pragma_libs(s1); + + if (0 == s1->nostdlib) { + static const char *libs[] = { + TCC_LIBTCC1, "msvcrt", "kernel32", "", "user32", "gdi32", NULL + }; + const char **pp, *p; + for (pp = libs; 0 != (p = *pp); ++pp) { + if (0 == *p) { + if (PE_DLL != pe_type && PE_GUI != pe_type) + break; + } else if (pp == libs && tcc_add_dll(s1, p, 0) >= 0) { + continue; + } else { + tcc_add_library_err(s1, p); + } + } + } + + if (TCC_OUTPUT_MEMORY == s1->output_type) + pe_type = PE_RUN; + pe->type = pe_type; + pe->start_symbol = start_symbol; +} + +static void pe_set_options(TCCState * s1, struct pe_info *pe) +{ + if (PE_DLL == pe->type) { + /* XXX: check if is correct for arm-pe target */ + pe->imagebase = 0x10000000; + } else { +#if defined(TCC_TARGET_ARM) + pe->imagebase = 0x00010000; +#else + pe->imagebase = 0x00400000; +#endif + } + +#if defined(TCC_TARGET_ARM) + /* we use "console" subsystem by default */ + pe->subsystem = 9; +#else + if (PE_DLL == pe->type || PE_GUI == pe->type) + pe->subsystem = 2; + else + pe->subsystem = 3; +#endif + /* Allow override via -Wl,-subsystem=... option */ + if (s1->pe_subsystem != 0) + pe->subsystem = s1->pe_subsystem; + + /* set default file/section alignment */ + if (pe->subsystem == 1) { + pe->section_align = 0x20; + pe->file_align = 0x20; + } else { + pe->section_align = 0x1000; + pe->file_align = 0x200; + } + + if (s1->section_align != 0) + pe->section_align = s1->section_align; + if (s1->pe_file_align != 0) + pe->file_align = s1->pe_file_align; + + if ((pe->subsystem >= 10) && (pe->subsystem <= 12)) + pe->imagebase = 0; + + if (s1->has_text_addr) + pe->imagebase = s1->text_addr; +} + +ST_FUNC int pe_output_file(TCCState *s1, const char *filename) +{ + int ret; + struct pe_info pe; + int i; + + memset(&pe, 0, sizeof pe); + pe.filename = filename; + pe.s1 = s1; + + tcc_add_bcheck(s1); + pe_add_runtime(s1, &pe); + relocate_common_syms(); /* assign bss addresses */ + tcc_add_linker_symbols(s1); + pe_set_options(s1, &pe); + + ret = pe_check_symbols(&pe); + if (ret) + ; + else if (filename) { + pe_assign_addresses(&pe); + relocate_syms(s1, s1->symtab, 0); + for (i = 1; i < s1->nb_sections; ++i) { + Section *s = s1->sections[i]; + if (s->reloc) { + relocate_section(s1, s); + pe_relocate_rva(&pe, s); + } + } + pe.start_addr = (DWORD) + ((uintptr_t)tcc_get_symbol_err(s1, pe.start_symbol) + - pe.imagebase); + if (s1->nb_errors) + ret = -1; + else + ret = pe_write(&pe); + tcc_free(pe.sec_info); + } else { +#ifdef TCC_IS_NATIVE + pe.thunk = data_section; + pe_build_imports(&pe); + s1->runtime_main = pe.start_symbol; +#endif + } + + pe_free_imports(&pe); + +#ifdef PE_PRINT_SECTIONS + pe_print_sections(s1, "tcc.log"); +#endif + return ret; +} + +/* ------------------------------------------------------------- */ diff --git a/tinyc/tccpp.c b/tinyc/tccpp.c new file mode 100644 index 000000000..76f9e428e --- /dev/null +++ b/tinyc/tccpp.c @@ -0,0 +1,3903 @@ +/* + * TCC - Tiny C Compiler + * + * Copyright (c) 2001-2004 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "tcc.h" + +/********************************************************/ +/* global variables */ + +ST_DATA int tok_flags; +ST_DATA int parse_flags; + +ST_DATA struct BufferedFile *file; +ST_DATA int ch, tok; +ST_DATA CValue tokc; +ST_DATA const int *macro_ptr; +ST_DATA CString tokcstr; /* current parsed string, if any */ + +/* display benchmark infos */ +ST_DATA int total_lines; +ST_DATA int total_bytes; +ST_DATA int tok_ident; +ST_DATA TokenSym **table_ident; + +/* ------------------------------------------------------------------------- */ + +static TokenSym *hash_ident[TOK_HASH_SIZE]; +static char token_buf[STRING_MAX_SIZE + 1]; +static CString cstr_buf; +static CString macro_equal_buf; +static TokenString tokstr_buf; +static unsigned char isidnum_table[256 - CH_EOF]; +static int pp_debug_tok, pp_debug_symv; +static int pp_once; +static int pp_expr; +static int pp_counter; +static void tok_print(const char *msg, const int *str); + +static struct TinyAlloc *toksym_alloc; +static struct TinyAlloc *tokstr_alloc; +static struct TinyAlloc *cstr_alloc; + +static TokenString *macro_stack; + +static const char tcc_keywords[] = +#define DEF(id, str) str "\0" +#include "tcctok.h" +#undef DEF +; + +/* WARNING: the content of this string encodes token numbers */ +static const unsigned char tok_two_chars[] = +/* outdated -- gr + "<=\236>=\235!=\225&&\240||\241++\244--\242==\224<<\1>>\2+=\253" + "-=\255*=\252/=\257%=\245&=\246^=\336|=\374->\313..\250##\266"; +*/{ + '<','=', TOK_LE, + '>','=', TOK_GE, + '!','=', TOK_NE, + '&','&', TOK_LAND, + '|','|', TOK_LOR, + '+','+', TOK_INC, + '-','-', TOK_DEC, + '=','=', TOK_EQ, + '<','<', TOK_SHL, + '>','>', TOK_SAR, + '+','=', TOK_A_ADD, + '-','=', TOK_A_SUB, + '*','=', TOK_A_MUL, + '/','=', TOK_A_DIV, + '%','=', TOK_A_MOD, + '&','=', TOK_A_AND, + '^','=', TOK_A_XOR, + '|','=', TOK_A_OR, + '-','>', TOK_ARROW, + '.','.', TOK_TWODOTS, + '#','#', TOK_TWOSHARPS, + 0 +}; + +static void next_nomacro_spc(void); + +ST_FUNC void skip(int c) +{ + if (tok != c) + tcc_error("'%c' expected (got \"%s\")", c, get_tok_str(tok, &tokc)); + next(); +} + +ST_FUNC void expect(const char *msg) +{ + tcc_error("%s expected", msg); +} + +/* ------------------------------------------------------------------------- */ +/* Custom allocator for tiny objects */ + +#define USE_TAL + +#ifndef USE_TAL +#define tal_free(al, p) tcc_free(p) +#define tal_realloc(al, p, size) tcc_realloc(p, size) +#define tal_new(a,b,c) +#define tal_delete(a) +#else +#if !defined(MEM_DEBUG) +#define tal_free(al, p) tal_free_impl(al, p) +#define tal_realloc(al, p, size) tal_realloc_impl(&al, p, size) +#define TAL_DEBUG_PARAMS +#else +#define TAL_DEBUG 1 +//#define TAL_INFO 1 /* collect and dump allocators stats */ +#define tal_free(al, p) tal_free_impl(al, p, __FILE__, __LINE__) +#define tal_realloc(al, p, size) tal_realloc_impl(&al, p, size, __FILE__, __LINE__) +#define TAL_DEBUG_PARAMS , const char *file, int line +#define TAL_DEBUG_FILE_LEN 40 +#endif + +#define TOKSYM_TAL_SIZE (768 * 1024) /* allocator for tiny TokenSym in table_ident */ +#define TOKSTR_TAL_SIZE (768 * 1024) /* allocator for tiny TokenString instances */ +#define CSTR_TAL_SIZE (256 * 1024) /* allocator for tiny CString instances */ +#define TOKSYM_TAL_LIMIT 256 /* prefer unique limits to distinguish allocators debug msgs */ +#define TOKSTR_TAL_LIMIT 128 /* 32 * sizeof(int) */ +#define CSTR_TAL_LIMIT 1024 + +typedef struct TinyAlloc { + unsigned limit; + unsigned size; + uint8_t *buffer; + uint8_t *p; + unsigned nb_allocs; + struct TinyAlloc *next, *top; +#ifdef TAL_INFO + unsigned nb_peak; + unsigned nb_total; + unsigned nb_missed; + uint8_t *peak_p; +#endif +} TinyAlloc; + +typedef struct tal_header_t { + unsigned size; +#ifdef TAL_DEBUG + int line_num; /* negative line_num used for double free check */ + char file_name[TAL_DEBUG_FILE_LEN + 1]; +#endif +} tal_header_t; + +/* ------------------------------------------------------------------------- */ + +static TinyAlloc *tal_new(TinyAlloc **pal, unsigned limit, unsigned size) +{ + TinyAlloc *al = tcc_mallocz(sizeof(TinyAlloc)); + al->p = al->buffer = tcc_malloc(size); + al->limit = limit; + al->size = size; + if (pal) *pal = al; + return al; +} + +static void tal_delete(TinyAlloc *al) +{ + TinyAlloc *next; + +tail_call: + if (!al) + return; +#ifdef TAL_INFO + fprintf(stderr, "limit=%5d, size=%5g MB, nb_peak=%6d, nb_total=%8d, nb_missed=%6d, usage=%5.1f%%\n", + al->limit, al->size / 1024.0 / 1024.0, al->nb_peak, al->nb_total, al->nb_missed, + (al->peak_p - al->buffer) * 100.0 / al->size); +#endif +#ifdef TAL_DEBUG + if (al->nb_allocs > 0) { + uint8_t *p; + fprintf(stderr, "TAL_DEBUG: memory leak %d chunk(s) (limit= %d)\n", + al->nb_allocs, al->limit); + p = al->buffer; + while (p < al->p) { + tal_header_t *header = (tal_header_t *)p; + if (header->line_num > 0) { + fprintf(stderr, "%s:%d: chunk of %d bytes leaked\n", + header->file_name, header->line_num, header->size); + } + p += header->size + sizeof(tal_header_t); + } +#if MEM_DEBUG-0 == 2 + exit(2); +#endif + } +#endif + next = al->next; + tcc_free(al->buffer); + tcc_free(al); + al = next; + goto tail_call; +} + +static void tal_free_impl(TinyAlloc *al, void *p TAL_DEBUG_PARAMS) +{ + if (!p) + return; +tail_call: + if (al->buffer <= (uint8_t *)p && (uint8_t *)p < al->buffer + al->size) { +#ifdef TAL_DEBUG + tal_header_t *header = (((tal_header_t *)p) - 1); + if (header->line_num < 0) { + fprintf(stderr, "%s:%d: TAL_DEBUG: double frees chunk from\n", + file, line); + fprintf(stderr, "%s:%d: %d bytes\n", + header->file_name, (int)-header->line_num, (int)header->size); + } else + header->line_num = -header->line_num; +#endif + al->nb_allocs--; + if (!al->nb_allocs) + al->p = al->buffer; + } else if (al->next) { + al = al->next; + goto tail_call; + } + else + tcc_free(p); +} + +static void *tal_realloc_impl(TinyAlloc **pal, void *p, unsigned size TAL_DEBUG_PARAMS) +{ + tal_header_t *header; + void *ret; + int is_own; + unsigned adj_size = (size + 3) & -4; + TinyAlloc *al = *pal; + +tail_call: + is_own = (al->buffer <= (uint8_t *)p && (uint8_t *)p < al->buffer + al->size); + if ((!p || is_own) && size <= al->limit) { + if (al->p + adj_size + sizeof(tal_header_t) < al->buffer + al->size) { + header = (tal_header_t *)al->p; + header->size = adj_size; +#ifdef TAL_DEBUG + { int ofs = strlen(file) - TAL_DEBUG_FILE_LEN; + strncpy(header->file_name, file + (ofs > 0 ? ofs : 0), TAL_DEBUG_FILE_LEN); + header->file_name[TAL_DEBUG_FILE_LEN] = 0; + header->line_num = line; } +#endif + ret = al->p + sizeof(tal_header_t); + al->p += adj_size + sizeof(tal_header_t); + if (is_own) { + header = (((tal_header_t *)p) - 1); + memcpy(ret, p, header->size); +#ifdef TAL_DEBUG + header->line_num = -header->line_num; +#endif + } else { + al->nb_allocs++; + } +#ifdef TAL_INFO + if (al->nb_peak < al->nb_allocs) + al->nb_peak = al->nb_allocs; + if (al->peak_p < al->p) + al->peak_p = al->p; + al->nb_total++; +#endif + return ret; + } else if (is_own) { + al->nb_allocs--; + ret = tal_realloc(*pal, 0, size); + header = (((tal_header_t *)p) - 1); + memcpy(ret, p, header->size); +#ifdef TAL_DEBUG + header->line_num = -header->line_num; +#endif + return ret; + } + if (al->next) { + al = al->next; + } else { + TinyAlloc *bottom = al, *next = al->top ? al->top : al; + + al = tal_new(pal, next->limit, next->size * 2); + al->next = next; + bottom->top = al; + } + goto tail_call; + } + if (is_own) { + al->nb_allocs--; + ret = tcc_malloc(size); + header = (((tal_header_t *)p) - 1); + memcpy(ret, p, header->size); +#ifdef TAL_DEBUG + header->line_num = -header->line_num; +#endif + } else if (al->next) { + al = al->next; + goto tail_call; + } else + ret = tcc_realloc(p, size); +#ifdef TAL_INFO + al->nb_missed++; +#endif + return ret; +} + +#endif /* USE_TAL */ + +/* ------------------------------------------------------------------------- */ +/* CString handling */ +static void cstr_realloc(CString *cstr, int new_size) +{ + int size; + + size = cstr->size_allocated; + if (size < 8) + size = 8; /* no need to allocate a too small first string */ + while (size < new_size) + size = size * 2; + cstr->data = tal_realloc(cstr_alloc, cstr->data, size); + cstr->size_allocated = size; +} + +/* add a byte */ +ST_INLN void cstr_ccat(CString *cstr, int ch) +{ + int size; + size = cstr->size + 1; + if (size > cstr->size_allocated) + cstr_realloc(cstr, size); + ((unsigned char *)cstr->data)[size - 1] = ch; + cstr->size = size; +} + +ST_FUNC void cstr_cat(CString *cstr, const char *str, int len) +{ + int size; + if (len <= 0) + len = strlen(str) + 1 + len; + size = cstr->size + len; + if (size > cstr->size_allocated) + cstr_realloc(cstr, size); + memmove(((unsigned char *)cstr->data) + cstr->size, str, len); + cstr->size = size; +} + +/* add a wide char */ +ST_FUNC void cstr_wccat(CString *cstr, int ch) +{ + int size; + size = cstr->size + sizeof(nwchar_t); + if (size > cstr->size_allocated) + cstr_realloc(cstr, size); + *(nwchar_t *)(((unsigned char *)cstr->data) + size - sizeof(nwchar_t)) = ch; + cstr->size = size; +} + +ST_FUNC void cstr_new(CString *cstr) +{ + memset(cstr, 0, sizeof(CString)); +} + +/* free string and reset it to NULL */ +ST_FUNC void cstr_free(CString *cstr) +{ + tal_free(cstr_alloc, cstr->data); + cstr_new(cstr); +} + +/* reset string to empty */ +ST_FUNC void cstr_reset(CString *cstr) +{ + cstr->size = 0; +} + +/* XXX: unicode ? */ +static void add_char(CString *cstr, int c) +{ + if (c == '\'' || c == '\"' || c == '\\') { + /* XXX: could be more precise if char or string */ + cstr_ccat(cstr, '\\'); + } + if (c >= 32 && c <= 126) { + cstr_ccat(cstr, c); + } else { + cstr_ccat(cstr, '\\'); + if (c == '\n') { + cstr_ccat(cstr, 'n'); + } else { + cstr_ccat(cstr, '0' + ((c >> 6) & 7)); + cstr_ccat(cstr, '0' + ((c >> 3) & 7)); + cstr_ccat(cstr, '0' + (c & 7)); + } + } +} + +/* ------------------------------------------------------------------------- */ +/* allocate a new token */ +static TokenSym *tok_alloc_new(TokenSym **pts, const char *str, int len) +{ + TokenSym *ts, **ptable; + int i; + + if (tok_ident >= SYM_FIRST_ANOM) + tcc_error("memory full (symbols)"); + + /* expand token table if needed */ + i = tok_ident - TOK_IDENT; + if ((i % TOK_ALLOC_INCR) == 0) { + ptable = tcc_realloc(table_ident, (i + TOK_ALLOC_INCR) * sizeof(TokenSym *)); + table_ident = ptable; + } + + ts = tal_realloc(toksym_alloc, 0, sizeof(TokenSym) + len); + table_ident[i] = ts; + ts->tok = tok_ident++; + ts->sym_define = NULL; + ts->sym_label = NULL; + ts->sym_struct = NULL; + ts->sym_identifier = NULL; + ts->len = len; + ts->hash_next = NULL; + memcpy(ts->str, str, len); + ts->str[len] = '\0'; + *pts = ts; + return ts; +} + +#define TOK_HASH_INIT 1 +#define TOK_HASH_FUNC(h, c) ((h) + ((h) << 5) + ((h) >> 27) + (c)) + + +/* find a token and add it if not found */ +ST_FUNC TokenSym *tok_alloc(const char *str, int len) +{ + TokenSym *ts, **pts; + int i; + unsigned int h; + + h = TOK_HASH_INIT; + for(i=0;ilen == len && !memcmp(ts->str, str, len)) + return ts; + pts = &(ts->hash_next); + } + return tok_alloc_new(pts, str, len); +} + +/* XXX: buffer overflow */ +/* XXX: float tokens */ +ST_FUNC const char *get_tok_str(int v, CValue *cv) +{ + char *p; + int i, len; + + cstr_reset(&cstr_buf); + p = cstr_buf.data; + + switch(v) { + case TOK_CINT: + case TOK_CUINT: + case TOK_CLONG: + case TOK_CULONG: + case TOK_CLLONG: + case TOK_CULLONG: + /* XXX: not quite exact, but only useful for testing */ +#ifdef _WIN32 + sprintf(p, "%u", (unsigned)cv->i); +#else + sprintf(p, "%llu", (unsigned long long)cv->i); +#endif + break; + case TOK_LCHAR: + cstr_ccat(&cstr_buf, 'L'); + case TOK_CCHAR: + cstr_ccat(&cstr_buf, '\''); + add_char(&cstr_buf, cv->i); + cstr_ccat(&cstr_buf, '\''); + cstr_ccat(&cstr_buf, '\0'); + break; + case TOK_PPNUM: + case TOK_PPSTR: + return (char*)cv->str.data; + case TOK_LSTR: + cstr_ccat(&cstr_buf, 'L'); + case TOK_STR: + cstr_ccat(&cstr_buf, '\"'); + if (v == TOK_STR) { + len = cv->str.size - 1; + for(i=0;istr.data)[i]); + } else { + len = (cv->str.size / sizeof(nwchar_t)) - 1; + for(i=0;istr.data)[i]); + } + cstr_ccat(&cstr_buf, '\"'); + cstr_ccat(&cstr_buf, '\0'); + break; + + case TOK_CFLOAT: + cstr_cat(&cstr_buf, "", 0); + break; + case TOK_CDOUBLE: + cstr_cat(&cstr_buf, "", 0); + break; + case TOK_CLDOUBLE: + cstr_cat(&cstr_buf, "", 0); + break; + case TOK_LINENUM: + cstr_cat(&cstr_buf, "", 0); + break; + + /* above tokens have value, the ones below don't */ + case TOK_LT: + v = '<'; + goto addv; + case TOK_GT: + v = '>'; + goto addv; + case TOK_DOTS: + return strcpy(p, "..."); + case TOK_A_SHL: + return strcpy(p, "<<="); + case TOK_A_SAR: + return strcpy(p, ">>="); + case TOK_EOF: + return strcpy(p, ""); + default: + if (v < TOK_IDENT) { + /* search in two bytes table */ + const unsigned char *q = tok_two_chars; + while (*q) { + if (q[2] == v) { + *p++ = q[0]; + *p++ = q[1]; + *p = '\0'; + return cstr_buf.data; + } + q += 3; + } + if (v >= 127) { + sprintf(cstr_buf.data, "<%02x>", v); + return cstr_buf.data; + } + addv: + *p++ = v; + *p = '\0'; + } else if (v < tok_ident) { + return table_ident[v - TOK_IDENT]->str; + } else if (v >= SYM_FIRST_ANOM) { + /* special name for anonymous symbol */ + sprintf(p, "L.%u", v - SYM_FIRST_ANOM); + } else { + /* should never happen */ + return NULL; + } + break; + } + return cstr_buf.data; +} + +/* return the current character, handling end of block if necessary + (but not stray) */ +ST_FUNC int handle_eob(void) +{ + BufferedFile *bf = file; + int len; + + /* only tries to read if really end of buffer */ + if (bf->buf_ptr >= bf->buf_end) { + if (bf->fd >= 0) { +#if defined(PARSE_DEBUG) + len = 1; +#else + len = IO_BUF_SIZE; +#endif + len = read(bf->fd, bf->buffer, len); + if (len < 0) + len = 0; + } else { + len = 0; + } + total_bytes += len; + bf->buf_ptr = bf->buffer; + bf->buf_end = bf->buffer + len; + *bf->buf_end = CH_EOB; + } + if (bf->buf_ptr < bf->buf_end) { + return bf->buf_ptr[0]; + } else { + bf->buf_ptr = bf->buf_end; + return CH_EOF; + } +} + +/* read next char from current input file and handle end of input buffer */ +ST_INLN void inp(void) +{ + ch = *(++(file->buf_ptr)); + /* end of buffer/file handling */ + if (ch == CH_EOB) + ch = handle_eob(); +} + +/* handle '\[\r]\n' */ +static int handle_stray_noerror(void) +{ + while (ch == '\\') { + inp(); + if (ch == '\n') { + file->line_num++; + inp(); + } else if (ch == '\r') { + inp(); + if (ch != '\n') + goto fail; + file->line_num++; + inp(); + } else { + fail: + return 1; + } + } + return 0; +} + +static void handle_stray(void) +{ + if (handle_stray_noerror()) + tcc_error("stray '\\' in program"); +} + +/* skip the stray and handle the \\n case. Output an error if + incorrect char after the stray */ +static int handle_stray1(uint8_t *p) +{ + int c; + + file->buf_ptr = p; + if (p >= file->buf_end) { + c = handle_eob(); + if (c != '\\') + return c; + p = file->buf_ptr; + } + ch = *p; + if (handle_stray_noerror()) { + if (!(parse_flags & PARSE_FLAG_ACCEPT_STRAYS)) + tcc_error("stray '\\' in program"); + *--file->buf_ptr = '\\'; + } + p = file->buf_ptr; + c = *p; + return c; +} + +/* handle just the EOB case, but not stray */ +#define PEEKC_EOB(c, p)\ +{\ + p++;\ + c = *p;\ + if (c == '\\') {\ + file->buf_ptr = p;\ + c = handle_eob();\ + p = file->buf_ptr;\ + }\ +} + +/* handle the complicated stray case */ +#define PEEKC(c, p)\ +{\ + p++;\ + c = *p;\ + if (c == '\\') {\ + c = handle_stray1(p);\ + p = file->buf_ptr;\ + }\ +} + +/* input with '\[\r]\n' handling. Note that this function cannot + handle other characters after '\', so you cannot call it inside + strings or comments */ +ST_FUNC void minp(void) +{ + inp(); + if (ch == '\\') + handle_stray(); +} + +/* single line C++ comments */ +static uint8_t *parse_line_comment(uint8_t *p) +{ + int c; + + p++; + for(;;) { + c = *p; + redo: + if (c == '\n' || c == CH_EOF) { + break; + } else if (c == '\\') { + file->buf_ptr = p; + c = handle_eob(); + p = file->buf_ptr; + if (c == '\\') { + PEEKC_EOB(c, p); + if (c == '\n') { + file->line_num++; + PEEKC_EOB(c, p); + } else if (c == '\r') { + PEEKC_EOB(c, p); + if (c == '\n') { + file->line_num++; + PEEKC_EOB(c, p); + } + } + } else { + goto redo; + } + } else { + p++; + } + } + return p; +} + +/* C comments */ +ST_FUNC uint8_t *parse_comment(uint8_t *p) +{ + int c; + + p++; + for(;;) { + /* fast skip loop */ + for(;;) { + c = *p; + if (c == '\n' || c == '*' || c == '\\') + break; + p++; + c = *p; + if (c == '\n' || c == '*' || c == '\\') + break; + p++; + } + /* now we can handle all the cases */ + if (c == '\n') { + file->line_num++; + p++; + } else if (c == '*') { + p++; + for(;;) { + c = *p; + if (c == '*') { + p++; + } else if (c == '/') { + goto end_of_comment; + } else if (c == '\\') { + file->buf_ptr = p; + c = handle_eob(); + p = file->buf_ptr; + if (c == CH_EOF) + tcc_error("unexpected end of file in comment"); + if (c == '\\') { + /* skip '\[\r]\n', otherwise just skip the stray */ + while (c == '\\') { + PEEKC_EOB(c, p); + if (c == '\n') { + file->line_num++; + PEEKC_EOB(c, p); + } else if (c == '\r') { + PEEKC_EOB(c, p); + if (c == '\n') { + file->line_num++; + PEEKC_EOB(c, p); + } + } else { + goto after_star; + } + } + } + } else { + break; + } + } + after_star: ; + } else { + /* stray, eob or eof */ + file->buf_ptr = p; + c = handle_eob(); + p = file->buf_ptr; + if (c == CH_EOF) { + tcc_error("unexpected end of file in comment"); + } else if (c == '\\') { + p++; + } + } + } + end_of_comment: + p++; + return p; +} + +ST_FUNC int set_idnum(int c, int val) +{ + int prev = isidnum_table[c - CH_EOF]; + isidnum_table[c - CH_EOF] = val; + return prev; +} + +#define cinp minp + +static inline void skip_spaces(void) +{ + while (isidnum_table[ch - CH_EOF] & IS_SPC) + cinp(); +} + +static inline int check_space(int t, int *spc) +{ + if (t < 256 && (isidnum_table[t - CH_EOF] & IS_SPC)) { + if (*spc) + return 1; + *spc = 1; + } else + *spc = 0; + return 0; +} + +/* parse a string without interpreting escapes */ +static uint8_t *parse_pp_string(uint8_t *p, + int sep, CString *str) +{ + int c; + p++; + for(;;) { + c = *p; + if (c == sep) { + break; + } else if (c == '\\') { + file->buf_ptr = p; + c = handle_eob(); + p = file->buf_ptr; + if (c == CH_EOF) { + unterminated_string: + /* XXX: indicate line number of start of string */ + tcc_error("missing terminating %c character", sep); + } else if (c == '\\') { + /* escape : just skip \[\r]\n */ + PEEKC_EOB(c, p); + if (c == '\n') { + file->line_num++; + p++; + } else if (c == '\r') { + PEEKC_EOB(c, p); + if (c != '\n') + expect("'\n' after '\r'"); + file->line_num++; + p++; + } else if (c == CH_EOF) { + goto unterminated_string; + } else { + if (str) { + cstr_ccat(str, '\\'); + cstr_ccat(str, c); + } + p++; + } + } + } else if (c == '\n') { + file->line_num++; + goto add_char; + } else if (c == '\r') { + PEEKC_EOB(c, p); + if (c != '\n') { + if (str) + cstr_ccat(str, '\r'); + } else { + file->line_num++; + goto add_char; + } + } else { + add_char: + if (str) + cstr_ccat(str, c); + p++; + } + } + p++; + return p; +} + +/* skip block of text until #else, #elif or #endif. skip also pairs of + #if/#endif */ +static void preprocess_skip(void) +{ + int a, start_of_line, c, in_warn_or_error; + uint8_t *p; + + p = file->buf_ptr; + a = 0; +redo_start: + start_of_line = 1; + in_warn_or_error = 0; + for(;;) { + redo_no_start: + c = *p; + switch(c) { + case ' ': + case '\t': + case '\f': + case '\v': + case '\r': + p++; + goto redo_no_start; + case '\n': + file->line_num++; + p++; + goto redo_start; + case '\\': + file->buf_ptr = p; + c = handle_eob(); + if (c == CH_EOF) { + expect("#endif"); + } else if (c == '\\') { + ch = file->buf_ptr[0]; + handle_stray_noerror(); + } + p = file->buf_ptr; + goto redo_no_start; + /* skip strings */ + case '\"': + case '\'': + if (in_warn_or_error) + goto _default; + p = parse_pp_string(p, c, NULL); + break; + /* skip comments */ + case '/': + if (in_warn_or_error) + goto _default; + file->buf_ptr = p; + ch = *p; + minp(); + p = file->buf_ptr; + if (ch == '*') { + p = parse_comment(p); + } else if (ch == '/') { + p = parse_line_comment(p); + } + break; + case '#': + p++; + if (start_of_line) { + file->buf_ptr = p; + next_nomacro(); + p = file->buf_ptr; + if (a == 0 && + (tok == TOK_ELSE || tok == TOK_ELIF || tok == TOK_ENDIF)) + goto the_end; + if (tok == TOK_IF || tok == TOK_IFDEF || tok == TOK_IFNDEF) + a++; + else if (tok == TOK_ENDIF) + a--; + else if( tok == TOK_ERROR || tok == TOK_WARNING) + in_warn_or_error = 1; + else if (tok == TOK_LINEFEED) + goto redo_start; + else if (parse_flags & PARSE_FLAG_ASM_FILE) + p = parse_line_comment(p - 1); + } else if (parse_flags & PARSE_FLAG_ASM_FILE) + p = parse_line_comment(p - 1); + break; +_default: + default: + p++; + break; + } + start_of_line = 0; + } + the_end: ; + file->buf_ptr = p; +} + +#if 0 +/* return the number of additional 'ints' necessary to store the + token */ +static inline int tok_size(const int *p) +{ + switch(*p) { + /* 4 bytes */ + case TOK_CINT: + case TOK_CUINT: + case TOK_CCHAR: + case TOK_LCHAR: + case TOK_CFLOAT: + case TOK_LINENUM: + return 1 + 1; + case TOK_STR: + case TOK_LSTR: + case TOK_PPNUM: + case TOK_PPSTR: + return 1 + ((sizeof(CString) + ((CString *)(p+1))->size + 3) >> 2); + case TOK_CLONG: + case TOK_CULONG: + return 1 + LONG_SIZE / 4; + case TOK_CDOUBLE: + case TOK_CLLONG: + case TOK_CULLONG: + return 1 + 2; + case TOK_CLDOUBLE: + return 1 + LDOUBLE_SIZE / 4; + default: + return 1 + 0; + } +} +#endif + +/* token string handling */ +ST_INLN void tok_str_new(TokenString *s) +{ + s->str = NULL; + s->len = s->lastlen = 0; + s->allocated_len = 0; + s->last_line_num = -1; +} + +ST_FUNC TokenString *tok_str_alloc(void) +{ + TokenString *str = tal_realloc(tokstr_alloc, 0, sizeof *str); + tok_str_new(str); + return str; +} + +ST_FUNC int *tok_str_dup(TokenString *s) +{ + int *str; + + str = tal_realloc(tokstr_alloc, 0, s->len * sizeof(int)); + memcpy(str, s->str, s->len * sizeof(int)); + return str; +} + +ST_FUNC void tok_str_free_str(int *str) +{ + tal_free(tokstr_alloc, str); +} + +ST_FUNC void tok_str_free(TokenString *str) +{ + tok_str_free_str(str->str); + tal_free(tokstr_alloc, str); +} + +ST_FUNC int *tok_str_realloc(TokenString *s, int new_size) +{ + int *str, size; + + size = s->allocated_len; + if (size < 16) + size = 16; + while (size < new_size) + size = size * 2; + if (size > s->allocated_len) { + str = tal_realloc(tokstr_alloc, s->str, size * sizeof(int)); + s->allocated_len = size; + s->str = str; + } + return s->str; +} + +ST_FUNC void tok_str_add(TokenString *s, int t) +{ + int len, *str; + + len = s->len; + str = s->str; + if (len >= s->allocated_len) + str = tok_str_realloc(s, len + 1); + str[len++] = t; + s->len = len; +} + +ST_FUNC void begin_macro(TokenString *str, int alloc) +{ + str->alloc = alloc; + str->prev = macro_stack; + str->prev_ptr = macro_ptr; + str->save_line_num = file->line_num; + macro_ptr = str->str; + macro_stack = str; +} + +ST_FUNC void end_macro(void) +{ + TokenString *str = macro_stack; + macro_stack = str->prev; + macro_ptr = str->prev_ptr; + file->line_num = str->save_line_num; + if (str->alloc == 2) { + str->alloc = 3; /* just mark as finished */ + } else { + tok_str_free(str); + } +} + +static void tok_str_add2(TokenString *s, int t, CValue *cv) +{ + int len, *str; + + len = s->lastlen = s->len; + str = s->str; + + /* allocate space for worst case */ + if (len + TOK_MAX_SIZE >= s->allocated_len) + str = tok_str_realloc(s, len + TOK_MAX_SIZE + 1); + str[len++] = t; + switch(t) { + case TOK_CINT: + case TOK_CUINT: + case TOK_CCHAR: + case TOK_LCHAR: + case TOK_CFLOAT: + case TOK_LINENUM: +#if LONG_SIZE == 4 + case TOK_CLONG: + case TOK_CULONG: +#endif + str[len++] = cv->tab[0]; + break; + case TOK_PPNUM: + case TOK_PPSTR: + case TOK_STR: + case TOK_LSTR: + { + /* Insert the string into the int array. */ + size_t nb_words = + 1 + (cv->str.size + sizeof(int) - 1) / sizeof(int); + if (len + nb_words >= s->allocated_len) + str = tok_str_realloc(s, len + nb_words + 1); + str[len] = cv->str.size; + memcpy(&str[len + 1], cv->str.data, cv->str.size); + len += nb_words; + } + break; + case TOK_CDOUBLE: + case TOK_CLLONG: + case TOK_CULLONG: +#if LONG_SIZE == 8 + case TOK_CLONG: + case TOK_CULONG: +#endif +#if LDOUBLE_SIZE == 8 + case TOK_CLDOUBLE: +#endif + str[len++] = cv->tab[0]; + str[len++] = cv->tab[1]; + break; +#if LDOUBLE_SIZE == 12 + case TOK_CLDOUBLE: + str[len++] = cv->tab[0]; + str[len++] = cv->tab[1]; + str[len++] = cv->tab[2]; +#elif LDOUBLE_SIZE == 16 + case TOK_CLDOUBLE: + str[len++] = cv->tab[0]; + str[len++] = cv->tab[1]; + str[len++] = cv->tab[2]; + str[len++] = cv->tab[3]; +#elif LDOUBLE_SIZE != 8 +#error add long double size support +#endif + break; + default: + break; + } + s->len = len; +} + +/* add the current parse token in token string 's' */ +ST_FUNC void tok_str_add_tok(TokenString *s) +{ + CValue cval; + + /* save line number info */ + if (file->line_num != s->last_line_num) { + s->last_line_num = file->line_num; + cval.i = s->last_line_num; + tok_str_add2(s, TOK_LINENUM, &cval); + } + tok_str_add2(s, tok, &tokc); +} + +/* get a token from an integer array and increment pointer + accordingly. we code it as a macro to avoid pointer aliasing. */ +static inline void TOK_GET(int *t, const int **pp, CValue *cv) +{ + const int *p = *pp; + int n, *tab; + + tab = cv->tab; + switch(*t = *p++) { +#if LONG_SIZE == 4 + case TOK_CLONG: +#endif + case TOK_CINT: + case TOK_CCHAR: + case TOK_LCHAR: + case TOK_LINENUM: + cv->i = *p++; + break; +#if LONG_SIZE == 4 + case TOK_CULONG: +#endif + case TOK_CUINT: + cv->i = (unsigned)*p++; + break; + case TOK_CFLOAT: + tab[0] = *p++; + break; + case TOK_STR: + case TOK_LSTR: + case TOK_PPNUM: + case TOK_PPSTR: + cv->str.size = *p++; + cv->str.data = p; + p += (cv->str.size + sizeof(int) - 1) / sizeof(int); + break; + case TOK_CDOUBLE: + case TOK_CLLONG: + case TOK_CULLONG: +#if LONG_SIZE == 8 + case TOK_CLONG: + case TOK_CULONG: +#endif + n = 2; + goto copy; + case TOK_CLDOUBLE: +#if LDOUBLE_SIZE == 16 + n = 4; +#elif LDOUBLE_SIZE == 12 + n = 3; +#elif LDOUBLE_SIZE == 8 + n = 2; +#else +# error add long double size support +#endif + copy: + do + *tab++ = *p++; + while (--n); + break; + default: + break; + } + *pp = p; +} + +static int macro_is_equal(const int *a, const int *b) +{ + CValue cv; + int t; + + if (!a || !b) + return 1; + + while (*a && *b) { + /* first time preallocate macro_equal_buf, next time only reset position to start */ + cstr_reset(¯o_equal_buf); + TOK_GET(&t, &a, &cv); + cstr_cat(¯o_equal_buf, get_tok_str(t, &cv), 0); + TOK_GET(&t, &b, &cv); + if (strcmp(macro_equal_buf.data, get_tok_str(t, &cv))) + return 0; + } + return !(*a || *b); +} + +/* defines handling */ +ST_INLN void define_push(int v, int macro_type, int *str, Sym *first_arg) +{ + Sym *s, *o; + + o = define_find(v); + s = sym_push2(&define_stack, v, macro_type, 0); + s->d = str; + s->next = first_arg; + table_ident[v - TOK_IDENT]->sym_define = s; + + if (o && !macro_is_equal(o->d, s->d)) + tcc_warning("%s redefined", get_tok_str(v, NULL)); +} + +/* undefined a define symbol. Its name is just set to zero */ +ST_FUNC void define_undef(Sym *s) +{ + int v = s->v; + if (v >= TOK_IDENT && v < tok_ident) + table_ident[v - TOK_IDENT]->sym_define = NULL; +} + +ST_INLN Sym *define_find(int v) +{ + v -= TOK_IDENT; + if ((unsigned)v >= (unsigned)(tok_ident - TOK_IDENT)) + return NULL; + return table_ident[v]->sym_define; +} + +/* free define stack until top reaches 'b' */ +ST_FUNC void free_defines(Sym *b) +{ + while (define_stack != b) { + Sym *top = define_stack; + define_stack = top->prev; + tok_str_free_str(top->d); + define_undef(top); + sym_free(top); + } + + /* restore remaining (-D or predefined) symbols if they were + #undef'd in the file */ + while (b) { + int v = b->v; + if (v >= TOK_IDENT && v < tok_ident) { + Sym **d = &table_ident[v - TOK_IDENT]->sym_define; + if (!*d) + *d = b; + } + b = b->prev; + } +} + +/* label lookup */ +ST_FUNC Sym *label_find(int v) +{ + v -= TOK_IDENT; + if ((unsigned)v >= (unsigned)(tok_ident - TOK_IDENT)) + return NULL; + return table_ident[v]->sym_label; +} + +ST_FUNC Sym *label_push(Sym **ptop, int v, int flags) +{ + Sym *s, **ps; + s = sym_push2(ptop, v, 0, 0); + s->r = flags; + ps = &table_ident[v - TOK_IDENT]->sym_label; + if (ptop == &global_label_stack) { + /* modify the top most local identifier, so that + sym_identifier will point to 's' when popped */ + while (*ps != NULL) + ps = &(*ps)->prev_tok; + } + s->prev_tok = *ps; + *ps = s; + return s; +} + +/* pop labels until element last is reached. Look if any labels are + undefined. Define symbols if '&&label' was used. */ +ST_FUNC void label_pop(Sym **ptop, Sym *slast, int keep) +{ + Sym *s, *s1; + for(s = *ptop; s != slast; s = s1) { + s1 = s->prev; + if (s->r == LABEL_DECLARED) { + tcc_warning("label '%s' declared but not used", get_tok_str(s->v, NULL)); + } else if (s->r == LABEL_FORWARD) { + tcc_error("label '%s' used but not defined", + get_tok_str(s->v, NULL)); + } else { + if (s->c) { + /* define corresponding symbol. A size of + 1 is put. */ + put_extern_sym(s, cur_text_section, s->jnext, 1); + } + } + /* remove label */ + table_ident[s->v - TOK_IDENT]->sym_label = s->prev_tok; + if (!keep) + sym_free(s); + } + if (!keep) + *ptop = slast; +} + +/* fake the nth "#if defined test_..." for tcc -dt -run */ +static void maybe_run_test(TCCState *s) +{ + const char *p; + if (s->include_stack_ptr != s->include_stack) + return; + p = get_tok_str(tok, NULL); + if (0 != memcmp(p, "test_", 5)) + return; + if (0 != --s->run_test) + return; + fprintf(s->ppfp, "\n[%s]\n" + !(s->dflag & 32), p), fflush(s->ppfp); + define_push(tok, MACRO_OBJ, NULL, NULL); +} + +/* eval an expression for #if/#elif */ +static int expr_preprocess(void) +{ + int c, t; + TokenString *str; + + str = tok_str_alloc(); + pp_expr = 1; + while (tok != TOK_LINEFEED && tok != TOK_EOF) { + next(); /* do macro subst */ + if (tok == TOK_DEFINED) { + next_nomacro(); + t = tok; + if (t == '(') + next_nomacro(); + if (tok < TOK_IDENT) + expect("identifier"); + if (tcc_state->run_test) + maybe_run_test(tcc_state); + c = define_find(tok) != 0; + if (t == '(') { + next_nomacro(); + if (tok != ')') + expect("')'"); + } + tok = TOK_CINT; + tokc.i = c; + } else if (tok >= TOK_IDENT) { + /* if undefined macro */ + tok = TOK_CINT; + tokc.i = 0; + } + tok_str_add_tok(str); + } + pp_expr = 0; + tok_str_add(str, -1); /* simulate end of file */ + tok_str_add(str, 0); + /* now evaluate C constant expression */ + begin_macro(str, 1); + next(); + c = expr_const(); + end_macro(); + return c != 0; +} + + +/* parse after #define */ +ST_FUNC void parse_define(void) +{ + Sym *s, *first, **ps; + int v, t, varg, is_vaargs, spc; + int saved_parse_flags = parse_flags; + + v = tok; + if (v < TOK_IDENT || v == TOK_DEFINED) + tcc_error("invalid macro name '%s'", get_tok_str(tok, &tokc)); + /* XXX: should check if same macro (ANSI) */ + first = NULL; + t = MACRO_OBJ; + /* We have to parse the whole define as if not in asm mode, in particular + no line comment with '#' must be ignored. Also for function + macros the argument list must be parsed without '.' being an ID + character. */ + parse_flags = ((parse_flags & ~PARSE_FLAG_ASM_FILE) | PARSE_FLAG_SPACES); + /* '(' must be just after macro definition for MACRO_FUNC */ + next_nomacro_spc(); + if (tok == '(') { + int dotid = set_idnum('.', 0); + next_nomacro(); + ps = &first; + if (tok != ')') for (;;) { + varg = tok; + next_nomacro(); + is_vaargs = 0; + if (varg == TOK_DOTS) { + varg = TOK___VA_ARGS__; + is_vaargs = 1; + } else if (tok == TOK_DOTS && gnu_ext) { + is_vaargs = 1; + next_nomacro(); + } + if (varg < TOK_IDENT) + bad_list: + tcc_error("bad macro parameter list"); + s = sym_push2(&define_stack, varg | SYM_FIELD, is_vaargs, 0); + *ps = s; + ps = &s->next; + if (tok == ')') + break; + if (tok != ',' || is_vaargs) + goto bad_list; + next_nomacro(); + } + next_nomacro_spc(); + t = MACRO_FUNC; + set_idnum('.', dotid); + } + + tokstr_buf.len = 0; + spc = 2; + parse_flags |= PARSE_FLAG_ACCEPT_STRAYS | PARSE_FLAG_SPACES | PARSE_FLAG_LINEFEED; + /* The body of a macro definition should be parsed such that identifiers + are parsed like the file mode determines (i.e. with '.' being an + ID character in asm mode). But '#' should be retained instead of + regarded as line comment leader, so still don't set ASM_FILE + in parse_flags. */ + while (tok != TOK_LINEFEED && tok != TOK_EOF) { + /* remove spaces around ## and after '#' */ + if (TOK_TWOSHARPS == tok) { + if (2 == spc) + goto bad_twosharp; + if (1 == spc) + --tokstr_buf.len; + spc = 3; + tok = TOK_PPJOIN; + } else if ('#' == tok) { + spc = 4; + } else if (check_space(tok, &spc)) { + goto skip; + } + tok_str_add2(&tokstr_buf, tok, &tokc); + skip: + next_nomacro_spc(); + } + + parse_flags = saved_parse_flags; + if (spc == 1) + --tokstr_buf.len; /* remove trailing space */ + tok_str_add(&tokstr_buf, 0); + if (3 == spc) +bad_twosharp: + tcc_error("'##' cannot appear at either end of macro"); + define_push(v, t, tok_str_dup(&tokstr_buf), first); +} + +static CachedInclude *search_cached_include(TCCState *s1, const char *filename, int add) +{ + const unsigned char *s; + unsigned int h; + CachedInclude *e; + int i; + + h = TOK_HASH_INIT; + s = (unsigned char *) filename; + while (*s) { +#ifdef _WIN32 + h = TOK_HASH_FUNC(h, toup(*s)); +#else + h = TOK_HASH_FUNC(h, *s); +#endif + s++; + } + h &= (CACHED_INCLUDES_HASH_SIZE - 1); + + i = s1->cached_includes_hash[h]; + for(;;) { + if (i == 0) + break; + e = s1->cached_includes[i - 1]; + if (0 == PATHCMP(e->filename, filename)) + return e; + i = e->hash_next; + } + if (!add) + return NULL; + + e = tcc_malloc(sizeof(CachedInclude) + strlen(filename)); + strcpy(e->filename, filename); + e->ifndef_macro = e->once = 0; + dynarray_add(&s1->cached_includes, &s1->nb_cached_includes, e); + /* add in hash table */ + e->hash_next = s1->cached_includes_hash[h]; + s1->cached_includes_hash[h] = s1->nb_cached_includes; +#ifdef INC_DEBUG + printf("adding cached '%s'\n", filename); +#endif + return e; +} + +static void pragma_parse(TCCState *s1) +{ + next_nomacro(); + if (tok == TOK_push_macro || tok == TOK_pop_macro) { + int t = tok, v; + Sym *s; + + if (next(), tok != '(') + goto pragma_err; + if (next(), tok != TOK_STR) + goto pragma_err; + v = tok_alloc(tokc.str.data, tokc.str.size - 1)->tok; + if (next(), tok != ')') + goto pragma_err; + if (t == TOK_push_macro) { + while (NULL == (s = define_find(v))) + define_push(v, 0, NULL, NULL); + s->type.ref = s; /* set push boundary */ + } else { + for (s = define_stack; s; s = s->prev) + if (s->v == v && s->type.ref == s) { + s->type.ref = NULL; + break; + } + } + if (s) + table_ident[v - TOK_IDENT]->sym_define = s->d ? s : NULL; + else + tcc_warning("unbalanced #pragma pop_macro"); + pp_debug_tok = t, pp_debug_symv = v; + + } else if (tok == TOK_once) { + search_cached_include(s1, file->filename, 1)->once = pp_once; + + } else if (s1->output_type == TCC_OUTPUT_PREPROCESS) { + /* tcc -E: keep pragmas below unchanged */ + unget_tok(' '); + unget_tok(TOK_PRAGMA); + unget_tok('#'); + unget_tok(TOK_LINEFEED); + + } else if (tok == TOK_pack) { + /* This may be: + #pragma pack(1) // set + #pragma pack() // reset to default + #pragma pack(push,1) // push & set + #pragma pack(pop) // restore previous */ + next(); + skip('('); + if (tok == TOK_ASM_pop) { + next(); + if (s1->pack_stack_ptr <= s1->pack_stack) { + stk_error: + tcc_error("out of pack stack"); + } + s1->pack_stack_ptr--; + } else { + int val = 0; + if (tok != ')') { + if (tok == TOK_ASM_push) { + next(); + if (s1->pack_stack_ptr >= s1->pack_stack + PACK_STACK_SIZE - 1) + goto stk_error; + s1->pack_stack_ptr++; + skip(','); + } + if (tok != TOK_CINT) + goto pragma_err; + val = tokc.i; + if (val < 1 || val > 16 || (val & (val - 1)) != 0) + goto pragma_err; + next(); + } + *s1->pack_stack_ptr = val; + } + if (tok != ')') + goto pragma_err; + + } else if (tok == TOK_comment) { + char *p; int t; + next(); + skip('('); + t = tok; + next(); + skip(','); + if (tok != TOK_STR) + goto pragma_err; + p = tcc_strdup((char *)tokc.str.data); + next(); + if (tok != ')') + goto pragma_err; + if (t == TOK_lib) { + dynarray_add(&s1->pragma_libs, &s1->nb_pragma_libs, p); + } else { + if (t == TOK_option) + tcc_set_options(s1, p); + tcc_free(p); + } + + } else if (s1->warn_unsupported) { + tcc_warning("#pragma %s is ignored", get_tok_str(tok, &tokc)); + } + return; + +pragma_err: + tcc_error("malformed #pragma directive"); + return; +} + +/* is_bof is true if first non space token at beginning of file */ +ST_FUNC void preprocess(int is_bof) +{ + TCCState *s1 = tcc_state; + int i, c, n, saved_parse_flags; + char buf[1024], *q; + Sym *s; + + saved_parse_flags = parse_flags; + parse_flags = PARSE_FLAG_PREPROCESS + | PARSE_FLAG_TOK_NUM + | PARSE_FLAG_TOK_STR + | PARSE_FLAG_LINEFEED + | (parse_flags & PARSE_FLAG_ASM_FILE) + ; + + next_nomacro(); + redo: + switch(tok) { + case TOK_DEFINE: + pp_debug_tok = tok; + next_nomacro(); + pp_debug_symv = tok; + parse_define(); + break; + case TOK_UNDEF: + pp_debug_tok = tok; + next_nomacro(); + pp_debug_symv = tok; + s = define_find(tok); + /* undefine symbol by putting an invalid name */ + if (s) + define_undef(s); + break; + case TOK_INCLUDE: + case TOK_INCLUDE_NEXT: + ch = file->buf_ptr[0]; + /* XXX: incorrect if comments : use next_nomacro with a special mode */ + skip_spaces(); + if (ch == '<') { + c = '>'; + goto read_name; + } else if (ch == '\"') { + c = ch; + read_name: + inp(); + q = buf; + while (ch != c && ch != '\n' && ch != CH_EOF) { + if ((q - buf) < sizeof(buf) - 1) + *q++ = ch; + if (ch == '\\') { + if (handle_stray_noerror() == 0) + --q; + } else + inp(); + } + *q = '\0'; + minp(); +#if 0 + /* eat all spaces and comments after include */ + /* XXX: slightly incorrect */ + while (ch1 != '\n' && ch1 != CH_EOF) + inp(); +#endif + } else { + int len; + /* computed #include : concatenate everything up to linefeed, + the result must be one of the two accepted forms. + Don't convert pp-tokens to tokens here. */ + parse_flags = (PARSE_FLAG_PREPROCESS + | PARSE_FLAG_LINEFEED + | (parse_flags & PARSE_FLAG_ASM_FILE)); + next(); + buf[0] = '\0'; + while (tok != TOK_LINEFEED) { + pstrcat(buf, sizeof(buf), get_tok_str(tok, &tokc)); + next(); + } + len = strlen(buf); + /* check syntax and remove '<>|""' */ + if ((len < 2 || ((buf[0] != '"' || buf[len-1] != '"') && + (buf[0] != '<' || buf[len-1] != '>')))) + tcc_error("'#include' expects \"FILENAME\" or "); + c = buf[len-1]; + memmove(buf, buf + 1, len - 2); + buf[len - 2] = '\0'; + } + + if (s1->include_stack_ptr >= s1->include_stack + INCLUDE_STACK_SIZE) + tcc_error("#include recursion too deep"); + /* store current file in stack, but increment stack later below */ + *s1->include_stack_ptr = file; + i = tok == TOK_INCLUDE_NEXT ? file->include_next_index : 0; + n = 2 + s1->nb_include_paths + s1->nb_sysinclude_paths; + for (; i < n; ++i) { + char buf1[sizeof file->filename]; + CachedInclude *e; + const char *path; + + if (i == 0) { + /* check absolute include path */ + if (!IS_ABSPATH(buf)) + continue; + buf1[0] = 0; + + } else if (i == 1) { + /* search in file's dir if "header.h" */ + if (c != '\"') + continue; + /* https://savannah.nongnu.org/bugs/index.php?50847 */ + path = file->true_filename; + pstrncpy(buf1, path, tcc_basename(path) - path); + + } else { + /* search in all the include paths */ + int j = i - 2, k = j - s1->nb_include_paths; + path = k < 0 ? s1->include_paths[j] : s1->sysinclude_paths[k]; + pstrcpy(buf1, sizeof(buf1), path); + pstrcat(buf1, sizeof(buf1), "/"); + } + + pstrcat(buf1, sizeof(buf1), buf); + e = search_cached_include(s1, buf1, 0); + if (e && (define_find(e->ifndef_macro) || e->once == pp_once)) { + /* no need to parse the include because the 'ifndef macro' + is defined (or had #pragma once) */ +#ifdef INC_DEBUG + printf("%s: skipping cached %s\n", file->filename, buf1); +#endif + goto include_done; + } + + if (tcc_open(s1, buf1) < 0) + continue; + + file->include_next_index = i + 1; +#ifdef INC_DEBUG + printf("%s: including %s\n", file->prev->filename, file->filename); +#endif + /* update target deps */ + dynarray_add(&s1->target_deps, &s1->nb_target_deps, + tcc_strdup(buf1)); + /* push current file in stack */ + ++s1->include_stack_ptr; + /* add include file debug info */ + if (s1->do_debug) + put_stabs(file->filename, N_BINCL, 0, 0, 0); + tok_flags |= TOK_FLAG_BOF | TOK_FLAG_BOL; + ch = file->buf_ptr[0]; + goto the_end; + } + tcc_error("include file '%s' not found", buf); +include_done: + break; + case TOK_IFNDEF: + c = 1; + goto do_ifdef; + case TOK_IF: + c = expr_preprocess(); + goto do_if; + case TOK_IFDEF: + c = 0; + do_ifdef: + next_nomacro(); + if (tok < TOK_IDENT) + tcc_error("invalid argument for '#if%sdef'", c ? "n" : ""); + if (is_bof) { + if (c) { +#ifdef INC_DEBUG + printf("#ifndef %s\n", get_tok_str(tok, NULL)); +#endif + file->ifndef_macro = tok; + } + } + c = (define_find(tok) != 0) ^ c; + do_if: + if (s1->ifdef_stack_ptr >= s1->ifdef_stack + IFDEF_STACK_SIZE) + tcc_error("memory full (ifdef)"); + *s1->ifdef_stack_ptr++ = c; + goto test_skip; + case TOK_ELSE: + if (s1->ifdef_stack_ptr == s1->ifdef_stack) + tcc_error("#else without matching #if"); + if (s1->ifdef_stack_ptr[-1] & 2) + tcc_error("#else after #else"); + c = (s1->ifdef_stack_ptr[-1] ^= 3); + goto test_else; + case TOK_ELIF: + if (s1->ifdef_stack_ptr == s1->ifdef_stack) + tcc_error("#elif without matching #if"); + c = s1->ifdef_stack_ptr[-1]; + if (c > 1) + tcc_error("#elif after #else"); + /* last #if/#elif expression was true: we skip */ + if (c == 1) { + c = 0; + } else { + c = expr_preprocess(); + s1->ifdef_stack_ptr[-1] = c; + } + test_else: + if (s1->ifdef_stack_ptr == file->ifdef_stack_ptr + 1) + file->ifndef_macro = 0; + test_skip: + if (!(c & 1)) { + preprocess_skip(); + is_bof = 0; + goto redo; + } + break; + case TOK_ENDIF: + if (s1->ifdef_stack_ptr <= file->ifdef_stack_ptr) + tcc_error("#endif without matching #if"); + s1->ifdef_stack_ptr--; + /* '#ifndef macro' was at the start of file. Now we check if + an '#endif' is exactly at the end of file */ + if (file->ifndef_macro && + s1->ifdef_stack_ptr == file->ifdef_stack_ptr) { + file->ifndef_macro_saved = file->ifndef_macro; + /* need to set to zero to avoid false matches if another + #ifndef at middle of file */ + file->ifndef_macro = 0; + while (tok != TOK_LINEFEED) + next_nomacro(); + tok_flags |= TOK_FLAG_ENDIF; + goto the_end; + } + break; + case TOK_PPNUM: + n = strtoul((char*)tokc.str.data, &q, 10); + goto _line_num; + case TOK_LINE: + next(); + if (tok != TOK_CINT) + _line_err: + tcc_error("wrong #line format"); + n = tokc.i; + _line_num: + next(); + if (tok != TOK_LINEFEED) { + if (tok == TOK_STR) { + if (file->true_filename == file->filename) + file->true_filename = tcc_strdup(file->filename); + pstrcpy(file->filename, sizeof(file->filename), (char *)tokc.str.data); + } else if (parse_flags & PARSE_FLAG_ASM_FILE) + break; + else + goto _line_err; + --n; + } + if (file->fd > 0) + total_lines += file->line_num - n; + file->line_num = n; + if (s1->do_debug) + put_stabs(file->filename, N_BINCL, 0, 0, 0); + break; + case TOK_ERROR: + case TOK_WARNING: + c = tok; + ch = file->buf_ptr[0]; + skip_spaces(); + q = buf; + while (ch != '\n' && ch != CH_EOF) { + if ((q - buf) < sizeof(buf) - 1) + *q++ = ch; + if (ch == '\\') { + if (handle_stray_noerror() == 0) + --q; + } else + inp(); + } + *q = '\0'; + if (c == TOK_ERROR) + tcc_error("#error %s", buf); + else + tcc_warning("#warning %s", buf); + break; + case TOK_PRAGMA: + pragma_parse(s1); + break; + case TOK_LINEFEED: + goto the_end; + default: + /* ignore gas line comment in an 'S' file. */ + if (saved_parse_flags & PARSE_FLAG_ASM_FILE) + goto ignore; + if (tok == '!' && is_bof) + /* '!' is ignored at beginning to allow C scripts. */ + goto ignore; + tcc_warning("Ignoring unknown preprocessing directive #%s", get_tok_str(tok, &tokc)); + ignore: + file->buf_ptr = parse_line_comment(file->buf_ptr - 1); + goto the_end; + } + /* ignore other preprocess commands or #! for C scripts */ + while (tok != TOK_LINEFEED) + next_nomacro(); + the_end: + parse_flags = saved_parse_flags; +} + +/* evaluate escape codes in a string. */ +static void parse_escape_string(CString *outstr, const uint8_t *buf, int is_long) +{ + int c, n; + const uint8_t *p; + + p = buf; + for(;;) { + c = *p; + if (c == '\0') + break; + if (c == '\\') { + p++; + /* escape */ + c = *p; + switch(c) { + case '0': case '1': case '2': case '3': + case '4': case '5': case '6': case '7': + /* at most three octal digits */ + n = c - '0'; + p++; + c = *p; + if (isoct(c)) { + n = n * 8 + c - '0'; + p++; + c = *p; + if (isoct(c)) { + n = n * 8 + c - '0'; + p++; + } + } + c = n; + goto add_char_nonext; + case 'x': + case 'u': + case 'U': + p++; + n = 0; + for(;;) { + c = *p; + if (c >= 'a' && c <= 'f') + c = c - 'a' + 10; + else if (c >= 'A' && c <= 'F') + c = c - 'A' + 10; + else if (isnum(c)) + c = c - '0'; + else + break; + n = n * 16 + c; + p++; + } + c = n; + goto add_char_nonext; + case 'a': + c = '\a'; + break; + case 'b': + c = '\b'; + break; + case 'f': + c = '\f'; + break; + case 'n': + c = '\n'; + break; + case 'r': + c = '\r'; + break; + case 't': + c = '\t'; + break; + case 'v': + c = '\v'; + break; + case 'e': + if (!gnu_ext) + goto invalid_escape; + c = 27; + break; + case '\'': + case '\"': + case '\\': + case '?': + break; + default: + invalid_escape: + if (c >= '!' && c <= '~') + tcc_warning("unknown escape sequence: \'\\%c\'", c); + else + tcc_warning("unknown escape sequence: \'\\x%x\'", c); + break; + } + } else if (is_long && c >= 0x80) { + /* assume we are processing UTF-8 sequence */ + /* reference: The Unicode Standard, Version 10.0, ch3.9 */ + + int cont; /* count of continuation bytes */ + int skip; /* how many bytes should skip when error occurred */ + int i; + + /* decode leading byte */ + if (c < 0xC2) { + skip = 1; goto invalid_utf8_sequence; + } else if (c <= 0xDF) { + cont = 1; n = c & 0x1f; + } else if (c <= 0xEF) { + cont = 2; n = c & 0xf; + } else if (c <= 0xF4) { + cont = 3; n = c & 0x7; + } else { + skip = 1; goto invalid_utf8_sequence; + } + + /* decode continuation bytes */ + for (i = 1; i <= cont; i++) { + int l = 0x80, h = 0xBF; + + /* adjust limit for second byte */ + if (i == 1) { + switch (c) { + case 0xE0: l = 0xA0; break; + case 0xED: h = 0x9F; break; + case 0xF0: l = 0x90; break; + case 0xF4: h = 0x8F; break; + } + } + + if (p[i] < l || p[i] > h) { + skip = i; goto invalid_utf8_sequence; + } + + n = (n << 6) | (p[i] & 0x3f); + } + + /* advance pointer */ + p += 1 + cont; + c = n; + goto add_char_nonext; + + /* error handling */ + invalid_utf8_sequence: + tcc_warning("ill-formed UTF-8 subsequence starting with: \'\\x%x\'", c); + c = 0xFFFD; + p += skip; + goto add_char_nonext; + + } + p++; + add_char_nonext: + if (!is_long) + cstr_ccat(outstr, c); + else { +#ifdef TCC_TARGET_PE + /* store as UTF-16 */ + if (c < 0x10000) { + cstr_wccat(outstr, c); + } else { + c -= 0x10000; + cstr_wccat(outstr, (c >> 10) + 0xD800); + cstr_wccat(outstr, (c & 0x3FF) + 0xDC00); + } +#else + cstr_wccat(outstr, c); +#endif + } + } + /* add a trailing '\0' */ + if (!is_long) + cstr_ccat(outstr, '\0'); + else + cstr_wccat(outstr, '\0'); +} + +static void parse_string(const char *s, int len) +{ + uint8_t buf[1000], *p = buf; + int is_long, sep; + + if ((is_long = *s == 'L')) + ++s, --len; + sep = *s++; + len -= 2; + if (len >= sizeof buf) + p = tcc_malloc(len + 1); + memcpy(p, s, len); + p[len] = 0; + + cstr_reset(&tokcstr); + parse_escape_string(&tokcstr, p, is_long); + if (p != buf) + tcc_free(p); + + if (sep == '\'') { + int char_size, i, n, c; + /* XXX: make it portable */ + if (!is_long) + tok = TOK_CCHAR, char_size = 1; + else + tok = TOK_LCHAR, char_size = sizeof(nwchar_t); + n = tokcstr.size / char_size - 1; + if (n < 1) + tcc_error("empty character constant"); + if (n > 1) + tcc_warning("multi-character character constant"); + for (c = i = 0; i < n; ++i) { + if (is_long) + c = ((nwchar_t *)tokcstr.data)[i]; + else + c = (c << 8) | ((char *)tokcstr.data)[i]; + } + tokc.i = c; + } else { + tokc.str.size = tokcstr.size; + tokc.str.data = tokcstr.data; + if (!is_long) + tok = TOK_STR; + else + tok = TOK_LSTR; + } +} + +/* we use 64 bit numbers */ +#define BN_SIZE 2 + +/* bn = (bn << shift) | or_val */ +static void bn_lshift(unsigned int *bn, int shift, int or_val) +{ + int i; + unsigned int v; + for(i=0;i> (32 - shift); + } +} + +static void bn_zero(unsigned int *bn) +{ + int i; + for(i=0;i= 'a' && ch <= 'f') + t = ch - 'a' + 10; + else if (ch >= 'A' && ch <= 'F') + t = ch - 'A' + 10; + else if (isnum(ch)) + t = ch - '0'; + else + break; + if (t >= b) + break; + if (q >= token_buf + STRING_MAX_SIZE) { + num_too_long: + tcc_error("number too long"); + } + *q++ = ch; + ch = *p++; + } + if (ch == '.' || + ((ch == 'e' || ch == 'E') && b == 10) || + ((ch == 'p' || ch == 'P') && (b == 16 || b == 2))) { + if (b != 10) { + /* NOTE: strtox should support that for hexa numbers, but + non ISOC99 libcs do not support it, so we prefer to do + it by hand */ + /* hexadecimal or binary floats */ + /* XXX: handle overflows */ + *q = '\0'; + if (b == 16) + shift = 4; + else + shift = 1; + bn_zero(bn); + q = token_buf; + while (1) { + t = *q++; + if (t == '\0') { + break; + } else if (t >= 'a') { + t = t - 'a' + 10; + } else if (t >= 'A') { + t = t - 'A' + 10; + } else { + t = t - '0'; + } + bn_lshift(bn, shift, t); + } + frac_bits = 0; + if (ch == '.') { + ch = *p++; + while (1) { + t = ch; + if (t >= 'a' && t <= 'f') { + t = t - 'a' + 10; + } else if (t >= 'A' && t <= 'F') { + t = t - 'A' + 10; + } else if (t >= '0' && t <= '9') { + t = t - '0'; + } else { + break; + } + if (t >= b) + tcc_error("invalid digit"); + bn_lshift(bn, shift, t); + frac_bits += shift; + ch = *p++; + } + } + if (ch != 'p' && ch != 'P') + expect("exponent"); + ch = *p++; + s = 1; + exp_val = 0; + if (ch == '+') { + ch = *p++; + } else if (ch == '-') { + s = -1; + ch = *p++; + } + if (ch < '0' || ch > '9') + expect("exponent digits"); + while (ch >= '0' && ch <= '9') { + exp_val = exp_val * 10 + ch - '0'; + ch = *p++; + } + exp_val = exp_val * s; + + /* now we can generate the number */ + /* XXX: should patch directly float number */ + d = (double)bn[1] * 4294967296.0 + (double)bn[0]; + d = ldexp(d, exp_val - frac_bits); + t = toup(ch); + if (t == 'F') { + ch = *p++; + tok = TOK_CFLOAT; + /* float : should handle overflow */ + tokc.f = (float)d; + } else if (t == 'L') { + ch = *p++; +#ifdef TCC_TARGET_PE + tok = TOK_CDOUBLE; + tokc.d = d; +#else + tok = TOK_CLDOUBLE; + /* XXX: not large enough */ + tokc.ld = (long double)d; +#endif + } else { + tok = TOK_CDOUBLE; + tokc.d = d; + } + } else { + /* decimal floats */ + if (ch == '.') { + if (q >= token_buf + STRING_MAX_SIZE) + goto num_too_long; + *q++ = ch; + ch = *p++; + float_frac_parse: + while (ch >= '0' && ch <= '9') { + if (q >= token_buf + STRING_MAX_SIZE) + goto num_too_long; + *q++ = ch; + ch = *p++; + } + } + if (ch == 'e' || ch == 'E') { + if (q >= token_buf + STRING_MAX_SIZE) + goto num_too_long; + *q++ = ch; + ch = *p++; + if (ch == '-' || ch == '+') { + if (q >= token_buf + STRING_MAX_SIZE) + goto num_too_long; + *q++ = ch; + ch = *p++; + } + if (ch < '0' || ch > '9') + expect("exponent digits"); + while (ch >= '0' && ch <= '9') { + if (q >= token_buf + STRING_MAX_SIZE) + goto num_too_long; + *q++ = ch; + ch = *p++; + } + } + *q = '\0'; + t = toup(ch); + errno = 0; + if (t == 'F') { + ch = *p++; + tok = TOK_CFLOAT; + tokc.f = strtof(token_buf, NULL); + } else if (t == 'L') { + ch = *p++; +#ifdef TCC_TARGET_PE + tok = TOK_CDOUBLE; + tokc.d = strtod(token_buf, NULL); +#else + tok = TOK_CLDOUBLE; + tokc.ld = strtold(token_buf, NULL); +#endif + } else { + tok = TOK_CDOUBLE; + tokc.d = strtod(token_buf, NULL); + } + } + } else { + unsigned long long n, n1; + int lcount, ucount, ov = 0; + const char *p1; + + /* integer number */ + *q = '\0'; + q = token_buf; + if (b == 10 && *q == '0') { + b = 8; + q++; + } + n = 0; + while(1) { + t = *q++; + /* no need for checks except for base 10 / 8 errors */ + if (t == '\0') + break; + else if (t >= 'a') + t = t - 'a' + 10; + else if (t >= 'A') + t = t - 'A' + 10; + else + t = t - '0'; + if (t >= b) + tcc_error("invalid digit"); + n1 = n; + n = n * b + t; + /* detect overflow */ + if (n1 >= 0x1000000000000000ULL && n / b != n1) + ov = 1; + } + + /* Determine the characteristics (unsigned and/or 64bit) the type of + the constant must have according to the constant suffix(es) */ + lcount = ucount = 0; + p1 = p; + for(;;) { + t = toup(ch); + if (t == 'L') { + if (lcount >= 2) + tcc_error("three 'l's in integer constant"); + if (lcount && *(p - 1) != ch) + tcc_error("incorrect integer suffix: %s", p1); + lcount++; + ch = *p++; + } else if (t == 'U') { + if (ucount >= 1) + tcc_error("two 'u's in integer constant"); + ucount++; + ch = *p++; + } else { + break; + } + } + + /* Determine if it needs 64 bits and/or unsigned in order to fit */ + if (ucount == 0 && b == 10) { + if (lcount <= (LONG_SIZE == 4)) { + if (n >= 0x80000000U) + lcount = (LONG_SIZE == 4) + 1; + } + if (n >= 0x8000000000000000ULL) + ov = 1, ucount = 1; + } else { + if (lcount <= (LONG_SIZE == 4)) { + if (n >= 0x100000000ULL) + lcount = (LONG_SIZE == 4) + 1; + else if (n >= 0x80000000U) + ucount = 1; + } + if (n >= 0x8000000000000000ULL) + ucount = 1; + } + + if (ov) + tcc_warning("integer constant overflow"); + + tok = TOK_CINT; + if (lcount) { + tok = TOK_CLONG; + if (lcount == 2) + tok = TOK_CLLONG; + } + if (ucount) + ++tok; /* TOK_CU... */ + tokc.i = n; + } + if (ch) + tcc_error("invalid number\n"); +} + + +#define PARSE2(c1, tok1, c2, tok2) \ + case c1: \ + PEEKC(c, p); \ + if (c == c2) { \ + p++; \ + tok = tok2; \ + } else { \ + tok = tok1; \ + } \ + break; + +/* return next token without macro substitution */ +static inline void next_nomacro1(void) +{ + int t, c, is_long, len; + TokenSym *ts; + uint8_t *p, *p1; + unsigned int h; + + p = file->buf_ptr; + redo_no_start: + c = *p; + switch(c) { + case ' ': + case '\t': + tok = c; + p++; + if (parse_flags & PARSE_FLAG_SPACES) + goto keep_tok_flags; + while (isidnum_table[*p - CH_EOF] & IS_SPC) + ++p; + goto redo_no_start; + case '\f': + case '\v': + case '\r': + p++; + goto redo_no_start; + case '\\': + /* first look if it is in fact an end of buffer */ + c = handle_stray1(p); + p = file->buf_ptr; + if (c == '\\') + goto parse_simple; + if (c != CH_EOF) + goto redo_no_start; + { + TCCState *s1 = tcc_state; + if ((parse_flags & PARSE_FLAG_LINEFEED) + && !(tok_flags & TOK_FLAG_EOF)) { + tok_flags |= TOK_FLAG_EOF; + tok = TOK_LINEFEED; + goto keep_tok_flags; + } else if (!(parse_flags & PARSE_FLAG_PREPROCESS)) { + tok = TOK_EOF; + } else if (s1->ifdef_stack_ptr != file->ifdef_stack_ptr) { + tcc_error("missing #endif"); + } else if (s1->include_stack_ptr == s1->include_stack) { + /* no include left : end of file. */ + tok = TOK_EOF; + } else { + tok_flags &= ~TOK_FLAG_EOF; + /* pop include file */ + + /* test if previous '#endif' was after a #ifdef at + start of file */ + if (tok_flags & TOK_FLAG_ENDIF) { +#ifdef INC_DEBUG + printf("#endif %s\n", get_tok_str(file->ifndef_macro_saved, NULL)); +#endif + search_cached_include(s1, file->filename, 1) + ->ifndef_macro = file->ifndef_macro_saved; + tok_flags &= ~TOK_FLAG_ENDIF; + } + + /* add end of include file debug info */ + if (tcc_state->do_debug) { + put_stabd(N_EINCL, 0, 0); + } + /* pop include stack */ + tcc_close(); + s1->include_stack_ptr--; + p = file->buf_ptr; + if (p == file->buffer) + tok_flags = TOK_FLAG_BOF|TOK_FLAG_BOL; + goto redo_no_start; + } + } + break; + + case '\n': + file->line_num++; + tok_flags |= TOK_FLAG_BOL; + p++; +maybe_newline: + if (0 == (parse_flags & PARSE_FLAG_LINEFEED)) + goto redo_no_start; + tok = TOK_LINEFEED; + goto keep_tok_flags; + + case '#': + /* XXX: simplify */ + PEEKC(c, p); + if ((tok_flags & TOK_FLAG_BOL) && + (parse_flags & PARSE_FLAG_PREPROCESS)) { + file->buf_ptr = p; + preprocess(tok_flags & TOK_FLAG_BOF); + p = file->buf_ptr; + goto maybe_newline; + } else { + if (c == '#') { + p++; + tok = TOK_TWOSHARPS; + } else { + if (parse_flags & PARSE_FLAG_ASM_FILE) { + p = parse_line_comment(p - 1); + goto redo_no_start; + } else { + tok = '#'; + } + } + } + break; + + /* dollar is allowed to start identifiers when not parsing asm */ + case '$': + if (!(isidnum_table[c - CH_EOF] & IS_ID) + || (parse_flags & PARSE_FLAG_ASM_FILE)) + goto parse_simple; + + case 'a': case 'b': case 'c': case 'd': + case 'e': case 'f': case 'g': case 'h': + case 'i': case 'j': case 'k': case 'l': + case 'm': case 'n': case 'o': case 'p': + case 'q': case 'r': case 's': case 't': + case 'u': case 'v': case 'w': case 'x': + case 'y': case 'z': + case 'A': case 'B': case 'C': case 'D': + case 'E': case 'F': case 'G': case 'H': + case 'I': case 'J': case 'K': + case 'M': case 'N': case 'O': case 'P': + case 'Q': case 'R': case 'S': case 'T': + case 'U': case 'V': case 'W': case 'X': + case 'Y': case 'Z': + case '_': + parse_ident_fast: + p1 = p; + h = TOK_HASH_INIT; + h = TOK_HASH_FUNC(h, c); + while (c = *++p, isidnum_table[c - CH_EOF] & (IS_ID|IS_NUM)) + h = TOK_HASH_FUNC(h, c); + len = p - p1; + if (c != '\\') { + TokenSym **pts; + + /* fast case : no stray found, so we have the full token + and we have already hashed it */ + h &= (TOK_HASH_SIZE - 1); + pts = &hash_ident[h]; + for(;;) { + ts = *pts; + if (!ts) + break; + if (ts->len == len && !memcmp(ts->str, p1, len)) + goto token_found; + pts = &(ts->hash_next); + } + ts = tok_alloc_new(pts, (char *) p1, len); + token_found: ; + } else { + /* slower case */ + cstr_reset(&tokcstr); + cstr_cat(&tokcstr, (char *) p1, len); + p--; + PEEKC(c, p); + parse_ident_slow: + while (isidnum_table[c - CH_EOF] & (IS_ID|IS_NUM)) + { + cstr_ccat(&tokcstr, c); + PEEKC(c, p); + } + ts = tok_alloc(tokcstr.data, tokcstr.size); + } + tok = ts->tok; + break; + case 'L': + t = p[1]; + if (t != '\\' && t != '\'' && t != '\"') { + /* fast case */ + goto parse_ident_fast; + } else { + PEEKC(c, p); + if (c == '\'' || c == '\"') { + is_long = 1; + goto str_const; + } else { + cstr_reset(&tokcstr); + cstr_ccat(&tokcstr, 'L'); + goto parse_ident_slow; + } + } + break; + + case '0': case '1': case '2': case '3': + case '4': case '5': case '6': case '7': + case '8': case '9': + t = c; + PEEKC(c, p); + /* after the first digit, accept digits, alpha, '.' or sign if + prefixed by 'eEpP' */ + parse_num: + cstr_reset(&tokcstr); + for(;;) { + cstr_ccat(&tokcstr, t); + if (!((isidnum_table[c - CH_EOF] & (IS_ID|IS_NUM)) + || c == '.' + || ((c == '+' || c == '-') + && (((t == 'e' || t == 'E') + && !(parse_flags & PARSE_FLAG_ASM_FILE + /* 0xe+1 is 3 tokens in asm */ + && ((char*)tokcstr.data)[0] == '0' + && toup(((char*)tokcstr.data)[1]) == 'X')) + || t == 'p' || t == 'P')))) + break; + t = c; + PEEKC(c, p); + } + /* We add a trailing '\0' to ease parsing */ + cstr_ccat(&tokcstr, '\0'); + tokc.str.size = tokcstr.size; + tokc.str.data = tokcstr.data; + tok = TOK_PPNUM; + break; + + case '.': + /* special dot handling because it can also start a number */ + PEEKC(c, p); + if (isnum(c)) { + t = '.'; + goto parse_num; + } else if ((isidnum_table['.' - CH_EOF] & IS_ID) + && (isidnum_table[c - CH_EOF] & (IS_ID|IS_NUM))) { + *--p = c = '.'; + goto parse_ident_fast; + } else if (c == '.') { + PEEKC(c, p); + if (c == '.') { + p++; + tok = TOK_DOTS; + } else { + *--p = '.'; /* may underflow into file->unget[] */ + tok = '.'; + } + } else { + tok = '.'; + } + break; + case '\'': + case '\"': + is_long = 0; + str_const: + cstr_reset(&tokcstr); + if (is_long) + cstr_ccat(&tokcstr, 'L'); + cstr_ccat(&tokcstr, c); + p = parse_pp_string(p, c, &tokcstr); + cstr_ccat(&tokcstr, c); + cstr_ccat(&tokcstr, '\0'); + tokc.str.size = tokcstr.size; + tokc.str.data = tokcstr.data; + tok = TOK_PPSTR; + break; + + case '<': + PEEKC(c, p); + if (c == '=') { + p++; + tok = TOK_LE; + } else if (c == '<') { + PEEKC(c, p); + if (c == '=') { + p++; + tok = TOK_A_SHL; + } else { + tok = TOK_SHL; + } + } else { + tok = TOK_LT; + } + break; + case '>': + PEEKC(c, p); + if (c == '=') { + p++; + tok = TOK_GE; + } else if (c == '>') { + PEEKC(c, p); + if (c == '=') { + p++; + tok = TOK_A_SAR; + } else { + tok = TOK_SAR; + } + } else { + tok = TOK_GT; + } + break; + + case '&': + PEEKC(c, p); + if (c == '&') { + p++; + tok = TOK_LAND; + } else if (c == '=') { + p++; + tok = TOK_A_AND; + } else { + tok = '&'; + } + break; + + case '|': + PEEKC(c, p); + if (c == '|') { + p++; + tok = TOK_LOR; + } else if (c == '=') { + p++; + tok = TOK_A_OR; + } else { + tok = '|'; + } + break; + + case '+': + PEEKC(c, p); + if (c == '+') { + p++; + tok = TOK_INC; + } else if (c == '=') { + p++; + tok = TOK_A_ADD; + } else { + tok = '+'; + } + break; + + case '-': + PEEKC(c, p); + if (c == '-') { + p++; + tok = TOK_DEC; + } else if (c == '=') { + p++; + tok = TOK_A_SUB; + } else if (c == '>') { + p++; + tok = TOK_ARROW; + } else { + tok = '-'; + } + break; + + PARSE2('!', '!', '=', TOK_NE) + PARSE2('=', '=', '=', TOK_EQ) + PARSE2('*', '*', '=', TOK_A_MUL) + PARSE2('%', '%', '=', TOK_A_MOD) + PARSE2('^', '^', '=', TOK_A_XOR) + + /* comments or operator */ + case '/': + PEEKC(c, p); + if (c == '*') { + p = parse_comment(p); + /* comments replaced by a blank */ + tok = ' '; + goto keep_tok_flags; + } else if (c == '/') { + p = parse_line_comment(p); + tok = ' '; + goto keep_tok_flags; + } else if (c == '=') { + p++; + tok = TOK_A_DIV; + } else { + tok = '/'; + } + break; + + /* simple tokens */ + case '(': + case ')': + case '[': + case ']': + case '{': + case '}': + case ',': + case ';': + case ':': + case '?': + case '~': + case '@': /* only used in assembler */ + parse_simple: + tok = c; + p++; + break; + default: + if (c >= 0x80 && c <= 0xFF) /* utf8 identifiers */ + goto parse_ident_fast; + if (parse_flags & PARSE_FLAG_ASM_FILE) + goto parse_simple; + tcc_error("unrecognized character \\x%02x", c); + break; + } + tok_flags = 0; +keep_tok_flags: + file->buf_ptr = p; +#if defined(PARSE_DEBUG) + printf("token = %d %s\n", tok, get_tok_str(tok, &tokc)); +#endif +} + +/* return next token without macro substitution. Can read input from + macro_ptr buffer */ +static void next_nomacro_spc(void) +{ + if (macro_ptr) { + redo: + tok = *macro_ptr; + if (tok) { + TOK_GET(&tok, ¯o_ptr, &tokc); + if (tok == TOK_LINENUM) { + file->line_num = tokc.i; + goto redo; + } + } + } else { + next_nomacro1(); + } + //printf("token = %s\n", get_tok_str(tok, &tokc)); +} + +ST_FUNC void next_nomacro(void) +{ + do { + next_nomacro_spc(); + } while (tok < 256 && (isidnum_table[tok - CH_EOF] & IS_SPC)); +} + + +static void macro_subst( + TokenString *tok_str, + Sym **nested_list, + const int *macro_str + ); + +/* substitute arguments in replacement lists in macro_str by the values in + args (field d) and return allocated string */ +static int *macro_arg_subst(Sym **nested_list, const int *macro_str, Sym *args) +{ + int t, t0, t1, spc; + const int *st; + Sym *s; + CValue cval; + TokenString str; + CString cstr; + + tok_str_new(&str); + t0 = t1 = 0; + while(1) { + TOK_GET(&t, ¯o_str, &cval); + if (!t) + break; + if (t == '#') { + /* stringize */ + TOK_GET(&t, ¯o_str, &cval); + if (!t) + goto bad_stringy; + s = sym_find2(args, t); + if (s) { + cstr_new(&cstr); + cstr_ccat(&cstr, '\"'); + st = s->d; + spc = 0; + while (*st >= 0) { + TOK_GET(&t, &st, &cval); + if (t != TOK_PLCHLDR + && t != TOK_NOSUBST + && 0 == check_space(t, &spc)) { + const char *s = get_tok_str(t, &cval); + while (*s) { + if (t == TOK_PPSTR && *s != '\'') + add_char(&cstr, *s); + else + cstr_ccat(&cstr, *s); + ++s; + } + } + } + cstr.size -= spc; + cstr_ccat(&cstr, '\"'); + cstr_ccat(&cstr, '\0'); +#ifdef PP_DEBUG + printf("\nstringize: <%s>\n", (char *)cstr.data); +#endif + /* add string */ + cval.str.size = cstr.size; + cval.str.data = cstr.data; + tok_str_add2(&str, TOK_PPSTR, &cval); + cstr_free(&cstr); + } else { + bad_stringy: + expect("macro parameter after '#'"); + } + } else if (t >= TOK_IDENT) { + s = sym_find2(args, t); + if (s) { + int l0 = str.len; + st = s->d; + /* if '##' is present before or after, no arg substitution */ + if (*macro_str == TOK_PPJOIN || t1 == TOK_PPJOIN) { + /* special case for var arg macros : ## eats the ',' + if empty VA_ARGS variable. */ + if (t1 == TOK_PPJOIN && t0 == ',' && gnu_ext && s->type.t) { + if (*st <= 0) { + /* suppress ',' '##' */ + str.len -= 2; + } else { + /* suppress '##' and add variable */ + str.len--; + goto add_var; + } + } + } else { + add_var: + if (!s->next) { + /* Expand arguments tokens and store them. In most + cases we could also re-expand each argument if + used multiple times, but not if the argument + contains the __COUNTER__ macro. */ + TokenString str2; + sym_push2(&s->next, s->v, s->type.t, 0); + tok_str_new(&str2); + macro_subst(&str2, nested_list, st); + tok_str_add(&str2, 0); + s->next->d = str2.str; + } + st = s->next->d; + } + for(;;) { + int t2; + TOK_GET(&t2, &st, &cval); + if (t2 <= 0) + break; + tok_str_add2(&str, t2, &cval); + } + if (str.len == l0) /* expanded to empty string */ + tok_str_add(&str, TOK_PLCHLDR); + } else { + tok_str_add(&str, t); + } + } else { + tok_str_add2(&str, t, &cval); + } + t0 = t1, t1 = t; + } + tok_str_add(&str, 0); + return str.str; +} + +static char const ab_month_name[12][4] = +{ + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" +}; + +static int paste_tokens(int t1, CValue *v1, int t2, CValue *v2) +{ + CString cstr; + int n, ret = 1; + + cstr_new(&cstr); + if (t1 != TOK_PLCHLDR) + cstr_cat(&cstr, get_tok_str(t1, v1), -1); + n = cstr.size; + if (t2 != TOK_PLCHLDR) + cstr_cat(&cstr, get_tok_str(t2, v2), -1); + cstr_ccat(&cstr, '\0'); + + tcc_open_bf(tcc_state, ":paste:", cstr.size); + memcpy(file->buffer, cstr.data, cstr.size); + tok_flags = 0; + for (;;) { + next_nomacro1(); + if (0 == *file->buf_ptr) + break; + if (is_space(tok)) + continue; + tcc_warning("pasting \"%.*s\" and \"%s\" does not give a valid" + " preprocessing token", n, cstr.data, (char*)cstr.data + n); + ret = 0; + break; + } + tcc_close(); + //printf("paste <%s>\n", (char*)cstr.data); + cstr_free(&cstr); + return ret; +} + +/* handle the '##' operator. Return NULL if no '##' seen. Otherwise + return the resulting string (which must be freed). */ +static inline int *macro_twosharps(const int *ptr0) +{ + int t; + CValue cval; + TokenString macro_str1; + int start_of_nosubsts = -1; + const int *ptr; + + /* we search the first '##' */ + for (ptr = ptr0;;) { + TOK_GET(&t, &ptr, &cval); + if (t == TOK_PPJOIN) + break; + if (t == 0) + return NULL; + } + + tok_str_new(¯o_str1); + + //tok_print(" $$$", ptr0); + for (ptr = ptr0;;) { + TOK_GET(&t, &ptr, &cval); + if (t == 0) + break; + if (t == TOK_PPJOIN) + continue; + while (*ptr == TOK_PPJOIN) { + int t1; CValue cv1; + /* given 'a##b', remove nosubsts preceding 'a' */ + if (start_of_nosubsts >= 0) + macro_str1.len = start_of_nosubsts; + /* given 'a##b', remove nosubsts preceding 'b' */ + while ((t1 = *++ptr) == TOK_NOSUBST) + ; + if (t1 && t1 != TOK_PPJOIN) { + TOK_GET(&t1, &ptr, &cv1); + if (t != TOK_PLCHLDR || t1 != TOK_PLCHLDR) { + if (paste_tokens(t, &cval, t1, &cv1)) { + t = tok, cval = tokc; + } else { + tok_str_add2(¯o_str1, t, &cval); + t = t1, cval = cv1; + } + } + } + } + if (t == TOK_NOSUBST) { + if (start_of_nosubsts < 0) + start_of_nosubsts = macro_str1.len; + } else { + start_of_nosubsts = -1; + } + tok_str_add2(¯o_str1, t, &cval); + } + tok_str_add(¯o_str1, 0); + //tok_print(" ###", macro_str1.str); + return macro_str1.str; +} + +/* peek or read [ws_str == NULL] next token from function macro call, + walking up macro levels up to the file if necessary */ +static int next_argstream(Sym **nested_list, TokenString *ws_str) +{ + int t; + const int *p; + Sym *sa; + + for (;;) { + if (macro_ptr) { + p = macro_ptr, t = *p; + if (ws_str) { + while (is_space(t) || TOK_LINEFEED == t || TOK_PLCHLDR == t) + tok_str_add(ws_str, t), t = *++p; + } + if (t == 0) { + end_macro(); + /* also, end of scope for nested defined symbol */ + sa = *nested_list; + while (sa && sa->v == 0) + sa = sa->prev; + if (sa) + sa->v = 0; + continue; + } + } else { + ch = handle_eob(); + if (ws_str) { + while (is_space(ch) || ch == '\n' || ch == '/') { + if (ch == '/') { + int c; + uint8_t *p = file->buf_ptr; + PEEKC(c, p); + if (c == '*') { + p = parse_comment(p); + file->buf_ptr = p - 1; + } else if (c == '/') { + p = parse_line_comment(p); + file->buf_ptr = p - 1; + } else + break; + ch = ' '; + } + if (ch == '\n') + file->line_num++; + if (!(ch == '\f' || ch == '\v' || ch == '\r')) + tok_str_add(ws_str, ch); + cinp(); + } + } + t = ch; + } + + if (ws_str) + return t; + next_nomacro_spc(); + return tok; + } +} + +/* do macro substitution of current token with macro 's' and add + result to (tok_str,tok_len). 'nested_list' is the list of all + macros we got inside to avoid recursing. Return non zero if no + substitution needs to be done */ +static int macro_subst_tok( + TokenString *tok_str, + Sym **nested_list, + Sym *s) +{ + Sym *args, *sa, *sa1; + int parlevel, t, t1, spc; + TokenString str; + char *cstrval; + CValue cval; + CString cstr; + char buf[32]; + + /* if symbol is a macro, prepare substitution */ + /* special macros */ + if (tok == TOK___LINE__ || tok == TOK___COUNTER__) { + t = tok == TOK___LINE__ ? file->line_num : pp_counter++; + snprintf(buf, sizeof(buf), "%d", t); + cstrval = buf; + t1 = TOK_PPNUM; + goto add_cstr1; + } else if (tok == TOK___FILE__) { + cstrval = file->filename; + goto add_cstr; + } else if (tok == TOK___DATE__ || tok == TOK___TIME__) { + time_t ti; + struct tm *tm; + + time(&ti); + tm = localtime(&ti); + if (tok == TOK___DATE__) { + snprintf(buf, sizeof(buf), "%s %2d %d", + ab_month_name[tm->tm_mon], tm->tm_mday, tm->tm_year + 1900); + } else { + snprintf(buf, sizeof(buf), "%02d:%02d:%02d", + tm->tm_hour, tm->tm_min, tm->tm_sec); + } + cstrval = buf; + add_cstr: + t1 = TOK_STR; + add_cstr1: + cstr_new(&cstr); + cstr_cat(&cstr, cstrval, 0); + cval.str.size = cstr.size; + cval.str.data = cstr.data; + tok_str_add2(tok_str, t1, &cval); + cstr_free(&cstr); + } else if (s->d) { + int saved_parse_flags = parse_flags; + int *joined_str = NULL; + int *mstr = s->d; + + if (s->type.t == MACRO_FUNC) { + /* whitespace between macro name and argument list */ + TokenString ws_str; + tok_str_new(&ws_str); + + spc = 0; + parse_flags |= PARSE_FLAG_SPACES | PARSE_FLAG_LINEFEED + | PARSE_FLAG_ACCEPT_STRAYS; + + /* get next token from argument stream */ + t = next_argstream(nested_list, &ws_str); + if (t != '(') { + /* not a macro substitution after all, restore the + * macro token plus all whitespace we've read. + * whitespace is intentionally not merged to preserve + * newlines. */ + parse_flags = saved_parse_flags; + tok_str_add(tok_str, tok); + if (parse_flags & PARSE_FLAG_SPACES) { + int i; + for (i = 0; i < ws_str.len; i++) + tok_str_add(tok_str, ws_str.str[i]); + } + tok_str_free_str(ws_str.str); + return 0; + } else { + tok_str_free_str(ws_str.str); + } + do { + next_nomacro(); /* eat '(' */ + } while (tok == TOK_PLCHLDR); + + /* argument macro */ + args = NULL; + sa = s->next; + /* NOTE: empty args are allowed, except if no args */ + for(;;) { + do { + next_argstream(nested_list, NULL); + } while (is_space(tok) || TOK_LINEFEED == tok); + empty_arg: + /* handle '()' case */ + if (!args && !sa && tok == ')') + break; + if (!sa) + tcc_error("macro '%s' used with too many args", + get_tok_str(s->v, 0)); + tok_str_new(&str); + parlevel = spc = 0; + /* NOTE: non zero sa->t indicates VA_ARGS */ + while ((parlevel > 0 || + (tok != ')' && + (tok != ',' || sa->type.t)))) { + if (tok == TOK_EOF || tok == 0) + break; + if (tok == '(') + parlevel++; + else if (tok == ')') + parlevel--; + if (tok == TOK_LINEFEED) + tok = ' '; + if (!check_space(tok, &spc)) + tok_str_add2(&str, tok, &tokc); + next_argstream(nested_list, NULL); + } + if (parlevel) + expect(")"); + str.len -= spc; + tok_str_add(&str, -1); + tok_str_add(&str, 0); + sa1 = sym_push2(&args, sa->v & ~SYM_FIELD, sa->type.t, 0); + sa1->d = str.str; + sa = sa->next; + if (tok == ')') { + /* special case for gcc var args: add an empty + var arg argument if it is omitted */ + if (sa && sa->type.t && gnu_ext) + goto empty_arg; + break; + } + if (tok != ',') + expect(","); + } + if (sa) { + tcc_error("macro '%s' used with too few args", + get_tok_str(s->v, 0)); + } + + parse_flags = saved_parse_flags; + + /* now subst each arg */ + mstr = macro_arg_subst(nested_list, mstr, args); + /* free memory */ + sa = args; + while (sa) { + sa1 = sa->prev; + tok_str_free_str(sa->d); + if (sa->next) { + tok_str_free_str(sa->next->d); + sym_free(sa->next); + } + sym_free(sa); + sa = sa1; + } + } + + sym_push2(nested_list, s->v, 0, 0); + parse_flags = saved_parse_flags; + joined_str = macro_twosharps(mstr); + macro_subst(tok_str, nested_list, joined_str ? joined_str : mstr); + + /* pop nested defined symbol */ + sa1 = *nested_list; + *nested_list = sa1->prev; + sym_free(sa1); + if (joined_str) + tok_str_free_str(joined_str); + if (mstr != s->d) + tok_str_free_str(mstr); + } + return 0; +} + +/* do macro substitution of macro_str and add result to + (tok_str,tok_len). 'nested_list' is the list of all macros we got + inside to avoid recursing. */ +static void macro_subst( + TokenString *tok_str, + Sym **nested_list, + const int *macro_str + ) +{ + Sym *s; + int t, spc, nosubst; + CValue cval; + + spc = nosubst = 0; + + while (1) { + TOK_GET(&t, ¯o_str, &cval); + if (t <= 0) + break; + + if (t >= TOK_IDENT && 0 == nosubst) { + s = define_find(t); + if (s == NULL) + goto no_subst; + + /* if nested substitution, do nothing */ + if (sym_find2(*nested_list, t)) { + /* and mark it as TOK_NOSUBST, so it doesn't get subst'd again */ + tok_str_add2(tok_str, TOK_NOSUBST, NULL); + goto no_subst; + } + + { + TokenString str; + str.str = (int*)macro_str; + begin_macro(&str, 2); + + tok = t; + macro_subst_tok(tok_str, nested_list, s); + + if (str.alloc == 3) { + /* already finished by reading function macro arguments */ + break; + } + + macro_str = macro_ptr; + end_macro (); + } + if (tok_str->len) + spc = is_space(t = tok_str->str[tok_str->lastlen]); + } else { + if (t == '\\' && !(parse_flags & PARSE_FLAG_ACCEPT_STRAYS)) + tcc_error("stray '\\' in program"); +no_subst: + if (!check_space(t, &spc)) + tok_str_add2(tok_str, t, &cval); + + if (nosubst) { + if (nosubst > 1 && (spc || (++nosubst == 3 && t == '('))) + continue; + nosubst = 0; + } + if (t == TOK_NOSUBST) + nosubst = 1; + } + /* GCC supports 'defined' as result of a macro substitution */ + if (t == TOK_DEFINED && pp_expr) + nosubst = 2; + } +} + +/* return next token with macro substitution */ +ST_FUNC void next(void) +{ + redo: + if (parse_flags & PARSE_FLAG_SPACES) + next_nomacro_spc(); + else + next_nomacro(); + + if (macro_ptr) { + if (tok == TOK_NOSUBST || tok == TOK_PLCHLDR) { + /* discard preprocessor markers */ + goto redo; + } else if (tok == 0) { + /* end of macro or unget token string */ + end_macro(); + goto redo; + } + } else if (tok >= TOK_IDENT && (parse_flags & PARSE_FLAG_PREPROCESS)) { + Sym *s; + /* if reading from file, try to substitute macros */ + s = define_find(tok); + if (s) { + Sym *nested_list = NULL; + tokstr_buf.len = 0; + macro_subst_tok(&tokstr_buf, &nested_list, s); + tok_str_add(&tokstr_buf, 0); + begin_macro(&tokstr_buf, 2); + goto redo; + } + } + /* convert preprocessor tokens into C tokens */ + if (tok == TOK_PPNUM) { + if (parse_flags & PARSE_FLAG_TOK_NUM) + parse_number((char *)tokc.str.data); + } else if (tok == TOK_PPSTR) { + if (parse_flags & PARSE_FLAG_TOK_STR) + parse_string((char *)tokc.str.data, tokc.str.size - 1); + } +} + +/* push back current token and set current token to 'last_tok'. Only + identifier case handled for labels. */ +ST_INLN void unget_tok(int last_tok) +{ + + TokenString *str = tok_str_alloc(); + tok_str_add2(str, tok, &tokc); + tok_str_add(str, 0); + begin_macro(str, 1); + tok = last_tok; +} + +ST_FUNC void preprocess_start(TCCState *s1, int is_asm) +{ + CString cstr; + int i; + + s1->include_stack_ptr = s1->include_stack; + s1->ifdef_stack_ptr = s1->ifdef_stack; + file->ifdef_stack_ptr = s1->ifdef_stack_ptr; + pp_expr = 0; + pp_counter = 0; + pp_debug_tok = pp_debug_symv = 0; + pp_once++; + pvtop = vtop = vstack - 1; + s1->pack_stack[0] = 0; + s1->pack_stack_ptr = s1->pack_stack; + + set_idnum('$', s1->dollars_in_identifiers ? IS_ID : 0); + set_idnum('.', is_asm ? IS_ID : 0); + + cstr_new(&cstr); + cstr_cat(&cstr, "\"", -1); + cstr_cat(&cstr, file->filename, -1); + cstr_cat(&cstr, "\"", 0); + tcc_define_symbol(s1, "__BASE_FILE__", cstr.data); + + cstr_reset(&cstr); + for (i = 0; i < s1->nb_cmd_include_files; i++) { + cstr_cat(&cstr, "#include \"", -1); + cstr_cat(&cstr, s1->cmd_include_files[i], -1); + cstr_cat(&cstr, "\"\n", -1); + } + if (cstr.size) { + *s1->include_stack_ptr++ = file; + tcc_open_bf(s1, "", cstr.size); + memcpy(file->buffer, cstr.data, cstr.size); + } + cstr_free(&cstr); + + if (is_asm) + tcc_define_symbol(s1, "__ASSEMBLER__", NULL); + + parse_flags = is_asm ? PARSE_FLAG_ASM_FILE : 0; + tok_flags = TOK_FLAG_BOL | TOK_FLAG_BOF; +} + +/* cleanup from error/setjmp */ +ST_FUNC void preprocess_end(TCCState *s1) +{ + while (macro_stack) + end_macro(); + macro_ptr = NULL; +} + +ST_FUNC void tccpp_new(TCCState *s) +{ + int i, c; + const char *p, *r; + + /* might be used in error() before preprocess_start() */ + s->include_stack_ptr = s->include_stack; + s->ppfp = stdout; + + /* init isid table */ + for(i = CH_EOF; i<128; i++) + set_idnum(i, + is_space(i) ? IS_SPC + : isid(i) ? IS_ID + : isnum(i) ? IS_NUM + : 0); + + for(i = 128; i<256; i++) + set_idnum(i, IS_ID); + + /* init allocators */ + tal_new(&toksym_alloc, TOKSYM_TAL_LIMIT, TOKSYM_TAL_SIZE); + tal_new(&tokstr_alloc, TOKSTR_TAL_LIMIT, TOKSTR_TAL_SIZE); + tal_new(&cstr_alloc, CSTR_TAL_LIMIT, CSTR_TAL_SIZE); + + memset(hash_ident, 0, TOK_HASH_SIZE * sizeof(TokenSym *)); + cstr_new(&cstr_buf); + cstr_realloc(&cstr_buf, STRING_MAX_SIZE); + tok_str_new(&tokstr_buf); + tok_str_realloc(&tokstr_buf, TOKSTR_MAX_SIZE); + + tok_ident = TOK_IDENT; + p = tcc_keywords; + while (*p) { + r = p; + for(;;) { + c = *r++; + if (c == '\0') + break; + } + tok_alloc(p, r - p - 1); + p = r; + } +} + +ST_FUNC void tccpp_delete(TCCState *s) +{ + int i, n; + + /* free -D and compiler defines */ + free_defines(NULL); + + /* free tokens */ + n = tok_ident - TOK_IDENT; + for(i = 0; i < n; i++) + tal_free(toksym_alloc, table_ident[i]); + tcc_free(table_ident); + table_ident = NULL; + + /* free static buffers */ + cstr_free(&tokcstr); + cstr_free(&cstr_buf); + cstr_free(¯o_equal_buf); + tok_str_free_str(tokstr_buf.str); + + /* free allocators */ + tal_delete(toksym_alloc); + toksym_alloc = NULL; + tal_delete(tokstr_alloc); + tokstr_alloc = NULL; + tal_delete(cstr_alloc); + cstr_alloc = NULL; +} + +/* ------------------------------------------------------------------------- */ +/* tcc -E [-P[1]] [-dD} support */ + +static void tok_print(const char *msg, const int *str) +{ + FILE *fp; + int t, s = 0; + CValue cval; + + fp = tcc_state->ppfp; + fprintf(fp, "%s", msg); + while (str) { + TOK_GET(&t, &str, &cval); + if (!t) + break; + fprintf(fp, " %s" + s, get_tok_str(t, &cval)), s = 1; + } + fprintf(fp, "\n"); +} + +static void pp_line(TCCState *s1, BufferedFile *f, int level) +{ + int d = f->line_num - f->line_ref; + + if (s1->dflag & 4) + return; + + if (s1->Pflag == LINE_MACRO_OUTPUT_FORMAT_NONE) { + ; + } else if (level == 0 && f->line_ref && d < 8) { + while (d > 0) + fputs("\n", s1->ppfp), --d; + } else if (s1->Pflag == LINE_MACRO_OUTPUT_FORMAT_STD) { + fprintf(s1->ppfp, "#line %d \"%s\"\n", f->line_num, f->filename); + } else { + fprintf(s1->ppfp, "# %d \"%s\"%s\n", f->line_num, f->filename, + level > 0 ? " 1" : level < 0 ? " 2" : ""); + } + f->line_ref = f->line_num; +} + +static void define_print(TCCState *s1, int v) +{ + FILE *fp; + Sym *s; + + s = define_find(v); + if (NULL == s || NULL == s->d) + return; + + fp = s1->ppfp; + fprintf(fp, "#define %s", get_tok_str(v, NULL)); + if (s->type.t == MACRO_FUNC) { + Sym *a = s->next; + fprintf(fp,"("); + if (a) + for (;;) { + fprintf(fp,"%s", get_tok_str(a->v & ~SYM_FIELD, NULL)); + if (!(a = a->next)) + break; + fprintf(fp,","); + } + fprintf(fp,")"); + } + tok_print("", s->d); +} + +static void pp_debug_defines(TCCState *s1) +{ + int v, t; + const char *vs; + FILE *fp; + + t = pp_debug_tok; + if (t == 0) + return; + + file->line_num--; + pp_line(s1, file, 0); + file->line_ref = ++file->line_num; + + fp = s1->ppfp; + v = pp_debug_symv; + vs = get_tok_str(v, NULL); + if (t == TOK_DEFINE) { + define_print(s1, v); + } else if (t == TOK_UNDEF) { + fprintf(fp, "#undef %s\n", vs); + } else if (t == TOK_push_macro) { + fprintf(fp, "#pragma push_macro(\"%s\")\n", vs); + } else if (t == TOK_pop_macro) { + fprintf(fp, "#pragma pop_macro(\"%s\")\n", vs); + } + pp_debug_tok = 0; +} + +static void pp_debug_builtins(TCCState *s1) +{ + int v; + for (v = TOK_IDENT; v < tok_ident; ++v) + define_print(s1, v); +} + +/* Add a space between tokens a and b to avoid unwanted textual pasting */ +static int pp_need_space(int a, int b) +{ + return 'E' == a ? '+' == b || '-' == b + : '+' == a ? TOK_INC == b || '+' == b + : '-' == a ? TOK_DEC == b || '-' == b + : a >= TOK_IDENT ? b >= TOK_IDENT + : a == TOK_PPNUM ? b >= TOK_IDENT + : 0; +} + +/* maybe hex like 0x1e */ +static int pp_check_he0xE(int t, const char *p) +{ + if (t == TOK_PPNUM && toup(strchr(p, 0)[-1]) == 'E') + return 'E'; + return t; +} + +/* Preprocess the current file */ +ST_FUNC int tcc_preprocess(TCCState *s1) +{ + BufferedFile **iptr; + int token_seen, spcs, level; + const char *p; + char white[400]; + + parse_flags = PARSE_FLAG_PREPROCESS + | (parse_flags & PARSE_FLAG_ASM_FILE) + | PARSE_FLAG_LINEFEED + | PARSE_FLAG_SPACES + | PARSE_FLAG_ACCEPT_STRAYS + ; + /* Credits to Fabrice Bellard's initial revision to demonstrate its + capability to compile and run itself, provided all numbers are + given as decimals. tcc -E -P10 will do. */ + if (s1->Pflag == LINE_MACRO_OUTPUT_FORMAT_P10) + parse_flags |= PARSE_FLAG_TOK_NUM, s1->Pflag = 1; + +#ifdef PP_BENCH + /* for PP benchmarks */ + do next(); while (tok != TOK_EOF); + return 0; +#endif + + if (s1->dflag & 1) { + pp_debug_builtins(s1); + s1->dflag &= ~1; + } + + token_seen = TOK_LINEFEED, spcs = 0; + pp_line(s1, file, 0); + for (;;) { + iptr = s1->include_stack_ptr; + next(); + if (tok == TOK_EOF) + break; + + level = s1->include_stack_ptr - iptr; + if (level) { + if (level > 0) + pp_line(s1, *iptr, 0); + pp_line(s1, file, level); + } + if (s1->dflag & 7) { + pp_debug_defines(s1); + if (s1->dflag & 4) + continue; + } + + if (is_space(tok)) { + if (spcs < sizeof white - 1) + white[spcs++] = tok; + continue; + } else if (tok == TOK_LINEFEED) { + spcs = 0; + if (token_seen == TOK_LINEFEED) + continue; + ++file->line_ref; + } else if (token_seen == TOK_LINEFEED) { + pp_line(s1, file, 0); + } else if (spcs == 0 && pp_need_space(token_seen, tok)) { + white[spcs++] = ' '; + } + + white[spcs] = 0, fputs(white, s1->ppfp), spcs = 0; + fputs(p = get_tok_str(tok, &tokc), s1->ppfp); + token_seen = pp_check_he0xE(tok, p); + } + return 0; +} + +/* ------------------------------------------------------------------------- */ diff --git a/tinyc/tccrun.c b/tinyc/tccrun.c new file mode 100644 index 000000000..b9a052b19 --- /dev/null +++ b/tinyc/tccrun.c @@ -0,0 +1,840 @@ +/* + * TCC - Tiny C Compiler - Support for -run switch + * + * Copyright (c) 2001-2004 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "tcc.h" + +/* only native compiler supports -run */ +#ifdef TCC_IS_NATIVE + +#ifndef _WIN32 +# include +#endif + +#ifdef CONFIG_TCC_BACKTRACE +# ifndef _WIN32 +# include +# ifndef __OpenBSD__ +# include +# endif +# else +# define ucontext_t CONTEXT +# endif +ST_DATA int rt_num_callers = 6; +ST_DATA const char **rt_bound_error_msg; +ST_DATA void *rt_prog_main; +static int rt_get_caller_pc(addr_t *paddr, ucontext_t *uc, int level); +static void rt_error(ucontext_t *uc, const char *fmt, ...); +static void set_exception_handler(void); +#endif + +static void set_pages_executable(void *ptr, unsigned long length); +static int tcc_relocate_ex(TCCState *s1, void *ptr, addr_t ptr_diff); + +#ifdef _WIN64 +static void *win64_add_function_table(TCCState *s1); +static void win64_del_function_table(void *); +#endif + +/* ------------------------------------------------------------- */ +/* Do all relocations (needed before using tcc_get_symbol()) + Returns -1 on error. */ + +LIBTCCAPI int tcc_relocate(TCCState *s1, void *ptr) +{ + int size; + addr_t ptr_diff = 0; + + if (TCC_RELOCATE_AUTO != ptr) + return tcc_relocate_ex(s1, ptr, 0); + + size = tcc_relocate_ex(s1, NULL, 0); + if (size < 0) + return -1; + +#ifdef HAVE_SELINUX +{ + /* Using mmap instead of malloc */ + void *prx; + char tmpfname[] = "/tmp/.tccrunXXXXXX"; + int fd = mkstemp(tmpfname); + unlink(tmpfname); + ftruncate(fd, size); + + ptr = mmap (NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); + prx = mmap (NULL, size, PROT_READ|PROT_EXEC, MAP_SHARED, fd, 0); + if (ptr == MAP_FAILED || prx == MAP_FAILED) + tcc_error("tccrun: could not map memory"); + dynarray_add(&s1->runtime_mem, &s1->nb_runtime_mem, (void*)(addr_t)size); + dynarray_add(&s1->runtime_mem, &s1->nb_runtime_mem, prx); + ptr_diff = (char*)prx - (char*)ptr; +} +#else + ptr = tcc_malloc(size); +#endif + tcc_relocate_ex(s1, ptr, ptr_diff); /* no more errors expected */ + dynarray_add(&s1->runtime_mem, &s1->nb_runtime_mem, ptr); + return 0; +} + +ST_FUNC void tcc_run_free(TCCState *s1) +{ + int i; + + for (i = 0; i < s1->nb_runtime_mem; ++i) { +#ifdef HAVE_SELINUX + unsigned size = (unsigned)(addr_t)s1->runtime_mem[i++]; + munmap(s1->runtime_mem[i++], size); + munmap(s1->runtime_mem[i], size); +#else +#ifdef _WIN64 + win64_del_function_table(*(void**)s1->runtime_mem[i]); +#endif + tcc_free(s1->runtime_mem[i]); +#endif + } + tcc_free(s1->runtime_mem); +} + +/* launch the compiled program with the given arguments */ +LIBTCCAPI int tcc_run(TCCState *s1, int argc, char **argv) +{ + int (*prog_main)(int, char **); + + s1->runtime_main = "main"; + if ((s1->dflag & 16) && !find_elf_sym(s1->symtab, s1->runtime_main)) + return 0; + if (tcc_relocate(s1, TCC_RELOCATE_AUTO) < 0) + return -1; + prog_main = tcc_get_symbol_err(s1, s1->runtime_main); + +#ifdef CONFIG_TCC_BACKTRACE + if (s1->do_debug) { + set_exception_handler(); + rt_prog_main = prog_main; + } +#endif + + errno = 0; /* clean errno value */ + +#ifdef CONFIG_TCC_BCHECK + if (s1->do_bounds_check) { + void (*bound_init)(void); + void (*bound_exit)(void); + void (*bound_new_region)(void *p, addr_t size); + int (*bound_delete_region)(void *p); + int i, ret; + + /* set error function */ + rt_bound_error_msg = tcc_get_symbol_err(s1, "__bound_error_msg"); + /* XXX: use .init section so that it also work in binary ? */ + bound_init = tcc_get_symbol_err(s1, "__bound_init"); + bound_exit = tcc_get_symbol_err(s1, "__bound_exit"); + bound_new_region = tcc_get_symbol_err(s1, "__bound_new_region"); + bound_delete_region = tcc_get_symbol_err(s1, "__bound_delete_region"); + + bound_init(); + /* mark argv area as valid */ + bound_new_region(argv, argc*sizeof(argv[0])); + for (i=0; inb_errors = 0; +#ifdef TCC_TARGET_PE + pe_output_file(s1, NULL); +#else + tcc_add_runtime(s1); + relocate_common_syms(); + tcc_add_linker_symbols(s1); + build_got_entries(s1); +#endif + if (s1->nb_errors) + return -1; + } + + offset = 0, mem = (addr_t)ptr; + fill = -mem & RUN_SECTION_ALIGNMENT; +#ifdef _WIN64 + offset += sizeof (void*); +#endif + for (k = 0; k < 2; ++k) { + for(i = 1; i < s1->nb_sections; i++) { + s = s1->sections[i]; + if (0 == (s->sh_flags & SHF_ALLOC)) + continue; + if (k != !(s->sh_flags & SHF_EXECINSTR)) + continue; + offset += fill; + if (!mem) + s->sh_addr = 0; + else if (s->sh_flags & SHF_EXECINSTR) + s->sh_addr = mem + offset + ptr_diff; + else + s->sh_addr = mem + offset; +#if 0 + if (mem) + printf("%-16s +%02lx %p %04x\n", + s->name, fill, (void*)s->sh_addr, (unsigned)s->data_offset); +#endif + offset += s->data_offset; + fill = -(mem + offset) & 15; + } +#if RUN_SECTION_ALIGNMENT > 15 + /* To avoid that x86 processors would reload cached instructions each time + when data is written in the near, we need to make sure that code and data + do not share the same 64 byte unit */ + fill = -(mem + offset) & RUN_SECTION_ALIGNMENT; +#endif + } + + /* relocate symbols */ + relocate_syms(s1, s1->symtab, 1); + if (s1->nb_errors) + return -1; + + if (0 == mem) + return offset + RUN_SECTION_ALIGNMENT; + + /* relocate each section */ + for(i = 1; i < s1->nb_sections; i++) { + s = s1->sections[i]; + if (s->reloc) + relocate_section(s1, s); + } + relocate_plt(s1); + +#ifdef _WIN64 + *(void**)ptr = win64_add_function_table(s1); +#endif + + for(i = 1; i < s1->nb_sections; i++) { + s = s1->sections[i]; + if (0 == (s->sh_flags & SHF_ALLOC)) + continue; + length = s->data_offset; + ptr = (void*)s->sh_addr; + if (s->sh_flags & SHF_EXECINSTR) + ptr = (char*)ptr - ptr_diff; + if (NULL == s->data || s->sh_type == SHT_NOBITS) + memset(ptr, 0, length); + else + memcpy(ptr, s->data, length); + /* mark executable sections as executable in memory */ + if (s->sh_flags & SHF_EXECINSTR) + set_pages_executable((char*)ptr + ptr_diff, length); + } + return 0; +} + +/* ------------------------------------------------------------- */ +/* allow to run code in memory */ + +static void set_pages_executable(void *ptr, unsigned long length) +{ +#ifdef _WIN32 + unsigned long old_protect; + VirtualProtect(ptr, length, PAGE_EXECUTE_READWRITE, &old_protect); +#else + void __clear_cache(void *beginning, void *end); +# ifndef HAVE_SELINUX + addr_t start, end; +# ifndef PAGESIZE +# define PAGESIZE 4096 +# endif + start = (addr_t)ptr & ~(PAGESIZE - 1); + end = (addr_t)ptr + length; + end = (end + PAGESIZE - 1) & ~(PAGESIZE - 1); + if (mprotect((void *)start, end - start, PROT_READ | PROT_WRITE | PROT_EXEC)) + tcc_error("mprotect failed: did you mean to configure --with-selinux?"); +# endif +# if defined TCC_TARGET_ARM || defined TCC_TARGET_ARM64 + __clear_cache(ptr, (char *)ptr + length); +# endif +#endif +} + +#ifdef _WIN64 +static void *win64_add_function_table(TCCState *s1) +{ + void *p = NULL; + if (s1->uw_pdata) { + p = (void*)s1->uw_pdata->sh_addr; + RtlAddFunctionTable( + (RUNTIME_FUNCTION*)p, + s1->uw_pdata->data_offset / sizeof (RUNTIME_FUNCTION), + text_section->sh_addr + ); + s1->uw_pdata = NULL; + } + return p;; +} + +static void win64_del_function_table(void *p) +{ + if (p) { + RtlDeleteFunctionTable((RUNTIME_FUNCTION*)p); + } +} +#endif + +/* ------------------------------------------------------------- */ +#ifdef CONFIG_TCC_BACKTRACE + +ST_FUNC void tcc_set_num_callers(int n) +{ + rt_num_callers = n; +} + +/* print the position in the source file of PC value 'pc' by reading + the stabs debug information */ +static addr_t rt_printline(addr_t wanted_pc, const char *msg) +{ + char func_name[128], last_func_name[128]; + addr_t func_addr, last_pc, pc; + const char *incl_files[INCLUDE_STACK_SIZE]; + int incl_index, len, last_line_num, i; + const char *str, *p; + + Stab_Sym *stab_sym = NULL, *stab_sym_end, *sym; + int stab_len = 0; + char *stab_str = NULL; + + if (stab_section) { + stab_len = stab_section->data_offset; + stab_sym = (Stab_Sym *)stab_section->data; + stab_str = (char *) stabstr_section->data; + } + + func_name[0] = '\0'; + func_addr = 0; + incl_index = 0; + last_func_name[0] = '\0'; + last_pc = (addr_t)-1; + last_line_num = 1; + + if (!stab_sym) + goto no_stabs; + + stab_sym_end = (Stab_Sym*)((char*)stab_sym + stab_len); + for (sym = stab_sym + 1; sym < stab_sym_end; ++sym) { + switch(sym->n_type) { + /* function start or end */ + case N_FUN: + if (sym->n_strx == 0) { + /* we test if between last line and end of function */ + pc = sym->n_value + func_addr; + if (wanted_pc >= last_pc && wanted_pc < pc) + goto found; + func_name[0] = '\0'; + func_addr = 0; + } else { + str = stab_str + sym->n_strx; + p = strchr(str, ':'); + if (!p) { + pstrcpy(func_name, sizeof(func_name), str); + } else { + len = p - str; + if (len > sizeof(func_name) - 1) + len = sizeof(func_name) - 1; + memcpy(func_name, str, len); + func_name[len] = '\0'; + } + func_addr = sym->n_value; + } + break; + /* line number info */ + case N_SLINE: + pc = sym->n_value + func_addr; + if (wanted_pc >= last_pc && wanted_pc < pc) + goto found; + last_pc = pc; + last_line_num = sym->n_desc; + /* XXX: slow! */ + strcpy(last_func_name, func_name); + break; + /* include files */ + case N_BINCL: + str = stab_str + sym->n_strx; + add_incl: + if (incl_index < INCLUDE_STACK_SIZE) { + incl_files[incl_index++] = str; + } + break; + case N_EINCL: + if (incl_index > 1) + incl_index--; + break; + case N_SO: + if (sym->n_strx == 0) { + incl_index = 0; /* end of translation unit */ + } else { + str = stab_str + sym->n_strx; + /* do not add path */ + len = strlen(str); + if (len > 0 && str[len - 1] != '/') + goto add_incl; + } + break; + } + } + +no_stabs: + /* second pass: we try symtab symbols (no line number info) */ + incl_index = 0; + if (symtab_section) + { + ElfW(Sym) *sym, *sym_end; + int type; + + sym_end = (ElfW(Sym) *)(symtab_section->data + symtab_section->data_offset); + for(sym = (ElfW(Sym) *)symtab_section->data + 1; + sym < sym_end; + sym++) { + type = ELFW(ST_TYPE)(sym->st_info); + if (type == STT_FUNC || type == STT_GNU_IFUNC) { + if (wanted_pc >= sym->st_value && + wanted_pc < sym->st_value + sym->st_size) { + pstrcpy(last_func_name, sizeof(last_func_name), + (char *) strtab_section->data + sym->st_name); + func_addr = sym->st_value; + goto found; + } + } + } + } + /* did not find any info: */ + fprintf(stderr, "%s %p ???\n", msg, (void*)wanted_pc); + fflush(stderr); + return 0; + found: + i = incl_index; + if (i > 0) + fprintf(stderr, "%s:%d: ", incl_files[--i], last_line_num); + fprintf(stderr, "%s %p", msg, (void*)wanted_pc); + if (last_func_name[0] != '\0') + fprintf(stderr, " %s()", last_func_name); + if (--i >= 0) { + fprintf(stderr, " (included from "); + for (;;) { + fprintf(stderr, "%s", incl_files[i]); + if (--i < 0) + break; + fprintf(stderr, ", "); + } + fprintf(stderr, ")"); + } + fprintf(stderr, "\n"); + fflush(stderr); + return func_addr; +} + +/* emit a run time error at position 'pc' */ +static void rt_error(ucontext_t *uc, const char *fmt, ...) +{ + va_list ap; + addr_t pc; + int i; + + fprintf(stderr, "Runtime error: "); + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + fprintf(stderr, "\n"); + + for(i=0;isi_code) { + case FPE_INTDIV: + case FPE_FLTDIV: + rt_error(uc, "division by zero"); + break; + default: + rt_error(uc, "floating point exception"); + break; + } + break; + case SIGBUS: + case SIGSEGV: + if (rt_bound_error_msg && *rt_bound_error_msg) + rt_error(uc, *rt_bound_error_msg); + else + rt_error(uc, "dereferencing invalid pointer"); + break; + case SIGILL: + rt_error(uc, "illegal instruction"); + break; + case SIGABRT: + rt_error(uc, "abort() called"); + break; + default: + rt_error(uc, "caught signal %d", signum); + break; + } + exit(255); +} + +#ifndef SA_SIGINFO +# define SA_SIGINFO 0x00000004u +#endif + +/* Generate a stack backtrace when a CPU exception occurs. */ +static void set_exception_handler(void) +{ + struct sigaction sigact; + /* install TCC signal handlers to print debug info on fatal + runtime errors */ + sigact.sa_flags = SA_SIGINFO | SA_RESETHAND; + sigact.sa_sigaction = sig_error; + sigemptyset(&sigact.sa_mask); + sigaction(SIGFPE, &sigact, NULL); + sigaction(SIGILL, &sigact, NULL); + sigaction(SIGSEGV, &sigact, NULL); + sigaction(SIGBUS, &sigact, NULL); + sigaction(SIGABRT, &sigact, NULL); +} + +/* ------------------------------------------------------------- */ +#ifdef __i386__ + +/* fix for glibc 2.1 */ +#ifndef REG_EIP +#define REG_EIP EIP +#define REG_EBP EBP +#endif + +/* return the PC at frame level 'level'. Return negative if not found */ +static int rt_get_caller_pc(addr_t *paddr, ucontext_t *uc, int level) +{ + addr_t fp; + int i; + + if (level == 0) { +#if defined(__APPLE__) + *paddr = uc->uc_mcontext->__ss.__eip; +#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__) + *paddr = uc->uc_mcontext.mc_eip; +#elif defined(__dietlibc__) + *paddr = uc->uc_mcontext.eip; +#elif defined(__NetBSD__) + *paddr = uc->uc_mcontext.__gregs[_REG_EIP]; +#elif defined(__OpenBSD__) + *paddr = uc->sc_eip; +#else + *paddr = uc->uc_mcontext.gregs[REG_EIP]; +#endif + return 0; + } else { +#if defined(__APPLE__) + fp = uc->uc_mcontext->__ss.__ebp; +#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__) + fp = uc->uc_mcontext.mc_ebp; +#elif defined(__dietlibc__) + fp = uc->uc_mcontext.ebp; +#elif defined(__NetBSD__) + fp = uc->uc_mcontext.__gregs[_REG_EBP]; +#elif defined(__OpenBSD__) + *paddr = uc->sc_ebp; +#else + fp = uc->uc_mcontext.gregs[REG_EBP]; +#endif + for(i=1;i= 0xc0000000) + return -1; + fp = ((addr_t *)fp)[0]; + } + *paddr = ((addr_t *)fp)[1]; + return 0; + } +} + +/* ------------------------------------------------------------- */ +#elif defined(__x86_64__) + +/* return the PC at frame level 'level'. Return negative if not found */ +static int rt_get_caller_pc(addr_t *paddr, ucontext_t *uc, int level) +{ + addr_t fp; + int i; + + if (level == 0) { + /* XXX: only support linux */ +#if defined(__APPLE__) + *paddr = uc->uc_mcontext->__ss.__rip; +#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__) + *paddr = uc->uc_mcontext.mc_rip; +#elif defined(__NetBSD__) + *paddr = uc->uc_mcontext.__gregs[_REG_RIP]; +#else + *paddr = uc->uc_mcontext.gregs[REG_RIP]; +#endif + return 0; + } else { +#if defined(__APPLE__) + fp = uc->uc_mcontext->__ss.__rbp; +#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__) + fp = uc->uc_mcontext.mc_rbp; +#elif defined(__NetBSD__) + fp = uc->uc_mcontext.__gregs[_REG_RBP]; +#else + fp = uc->uc_mcontext.gregs[REG_RBP]; +#endif + for(i=1;iuc_mcontext.arm_pc; +#else + return -1; +#endif + return 0; + } else { +#if defined(__linux__) + fp = uc->uc_mcontext.arm_fp; + sp = uc->uc_mcontext.arm_sp; + if (sp < 0x1000) + sp = 0x1000; +#else + return -1; +#endif + /* XXX: specific to tinycc stack frames */ + if (fp < sp + 12 || fp & 3) + return -1; + for(i = 1; i < level; i++) { + sp = ((addr_t *)fp)[-2]; + if (sp < fp || sp - fp > 16 || sp & 3) + return -1; + fp = ((addr_t *)fp)[-3]; + if (fp <= sp || fp - sp < 12 || fp & 3) + return -1; + } + /* XXX: check address validity with program info */ + *paddr = ((addr_t *)fp)[-1]; + return 0; + } +} + +/* ------------------------------------------------------------- */ +#elif defined(__aarch64__) + +static int rt_get_caller_pc(addr_t *paddr, ucontext_t *uc, int level) +{ + if (level < 0) + return -1; + else if (level == 0) { + *paddr = uc->uc_mcontext.pc; + return 0; + } + else { + addr_t *fp = (addr_t *)uc->uc_mcontext.regs[29]; + int i; + for (i = 1; i < level; i++) + fp = (addr_t *)fp[0]; + *paddr = fp[1]; + return 0; + } +} + +/* ------------------------------------------------------------- */ +#else + +#warning add arch specific rt_get_caller_pc() +static int rt_get_caller_pc(addr_t *paddr, ucontext_t *uc, int level) +{ + return -1; +} + +#endif /* !__i386__ */ + +/* ------------------------------------------------------------- */ +#else /* WIN32 */ + +static long __stdcall cpu_exception_handler(EXCEPTION_POINTERS *ex_info) +{ + EXCEPTION_RECORD *er = ex_info->ExceptionRecord; + CONTEXT *uc = ex_info->ContextRecord; + switch (er->ExceptionCode) { + case EXCEPTION_ACCESS_VIOLATION: + if (rt_bound_error_msg && *rt_bound_error_msg) + rt_error(uc, *rt_bound_error_msg); + else + rt_error(uc, "access violation"); + break; + case EXCEPTION_STACK_OVERFLOW: + rt_error(uc, "stack overflow"); + break; + case EXCEPTION_INT_DIVIDE_BY_ZERO: + rt_error(uc, "division by zero"); + break; + default: + rt_error(uc, "exception caught"); + break; + } + return EXCEPTION_EXECUTE_HANDLER; +} + +/* Generate a stack backtrace when a CPU exception occurs. */ +static void set_exception_handler(void) +{ + SetUnhandledExceptionFilter(cpu_exception_handler); +} + +/* return the PC at frame level 'level'. Return non zero if not found */ +static int rt_get_caller_pc(addr_t *paddr, CONTEXT *uc, int level) +{ + addr_t fp, pc; + int i; +#ifdef _WIN64 + pc = uc->Rip; + fp = uc->Rbp; +#else + pc = uc->Eip; + fp = uc->Ebp; +#endif + if (level > 0) { + for(i=1;i= 0xc0000000) + return -1; + fp = ((addr_t*)fp)[0]; + } + pc = ((addr_t*)fp)[1]; + } + *paddr = pc; + return 0; +} + +#endif /* _WIN32 */ +#endif /* CONFIG_TCC_BACKTRACE */ +/* ------------------------------------------------------------- */ +#ifdef CONFIG_TCC_STATIC + +/* dummy function for profiling */ +ST_FUNC void *dlopen(const char *filename, int flag) +{ + return NULL; +} + +ST_FUNC void dlclose(void *p) +{ +} + +ST_FUNC const char *dlerror(void) +{ + return "error"; +} + +typedef struct TCCSyms { + char *str; + void *ptr; +} TCCSyms; + + +/* add the symbol you want here if no dynamic linking is done */ +static TCCSyms tcc_syms[] = { +#if !defined(CONFIG_TCCBOOT) +#define TCCSYM(a) { #a, &a, }, + TCCSYM(printf) + TCCSYM(fprintf) + TCCSYM(fopen) + TCCSYM(fclose) +#undef TCCSYM +#endif + { NULL, NULL }, +}; + +ST_FUNC void *dlsym(void *handle, const char *symbol) +{ + TCCSyms *p; + p = tcc_syms; + while (p->str != NULL) { + if (!strcmp(p->str, symbol)) + return p->ptr; + p++; + } + return NULL; +} + +#endif /* CONFIG_TCC_STATIC */ +#endif /* TCC_IS_NATIVE */ +/* ------------------------------------------------------------- */ diff --git a/tinyc/tcctok.h b/tinyc/tcctok.h new file mode 100644 index 000000000..317f64cd7 --- /dev/null +++ b/tinyc/tcctok.h @@ -0,0 +1,350 @@ +/* keywords */ + DEF(TOK_INT, "int") + DEF(TOK_VOID, "void") + DEF(TOK_CHAR, "char") + DEF(TOK_IF, "if") + DEF(TOK_ELSE, "else") + DEF(TOK_WHILE, "while") + DEF(TOK_BREAK, "break") + DEF(TOK_RETURN, "return") + DEF(TOK_FOR, "for") + DEF(TOK_EXTERN, "extern") + DEF(TOK_STATIC, "static") + DEF(TOK_UNSIGNED, "unsigned") + DEF(TOK_GOTO, "goto") + DEF(TOK_DO, "do") + DEF(TOK_CONTINUE, "continue") + DEF(TOK_SWITCH, "switch") + DEF(TOK_CASE, "case") + + DEF(TOK_CONST1, "const") + DEF(TOK_CONST2, "__const") /* gcc keyword */ + DEF(TOK_CONST3, "__const__") /* gcc keyword */ + DEF(TOK_VOLATILE1, "volatile") + DEF(TOK_VOLATILE2, "__volatile") /* gcc keyword */ + DEF(TOK_VOLATILE3, "__volatile__") /* gcc keyword */ + DEF(TOK_LONG, "long") + DEF(TOK_REGISTER, "register") + DEF(TOK_SIGNED1, "signed") + DEF(TOK_SIGNED2, "__signed") /* gcc keyword */ + DEF(TOK_SIGNED3, "__signed__") /* gcc keyword */ + DEF(TOK_AUTO, "auto") + DEF(TOK_INLINE1, "inline") + DEF(TOK_INLINE2, "__inline") /* gcc keyword */ + DEF(TOK_INLINE3, "__inline__") /* gcc keyword */ + DEF(TOK_RESTRICT1, "restrict") + DEF(TOK_RESTRICT2, "__restrict") + DEF(TOK_RESTRICT3, "__restrict__") + DEF(TOK_EXTENSION, "__extension__") /* gcc keyword */ + + DEF(TOK_GENERIC, "_Generic") + + DEF(TOK_FLOAT, "float") + DEF(TOK_DOUBLE, "double") + DEF(TOK_BOOL, "_Bool") + DEF(TOK_SHORT, "short") + DEF(TOK_STRUCT, "struct") + DEF(TOK_UNION, "union") + DEF(TOK_TYPEDEF, "typedef") + DEF(TOK_DEFAULT, "default") + DEF(TOK_ENUM, "enum") + DEF(TOK_SIZEOF, "sizeof") + DEF(TOK_ATTRIBUTE1, "__attribute") + DEF(TOK_ATTRIBUTE2, "__attribute__") + DEF(TOK_ALIGNOF1, "__alignof") + DEF(TOK_ALIGNOF2, "__alignof__") + DEF(TOK_TYPEOF1, "typeof") + DEF(TOK_TYPEOF2, "__typeof") + DEF(TOK_TYPEOF3, "__typeof__") + DEF(TOK_LABEL, "__label__") + DEF(TOK_ASM1, "asm") + DEF(TOK_ASM2, "__asm") + DEF(TOK_ASM3, "__asm__") + +#ifdef TCC_TARGET_ARM64 + DEF(TOK_UINT128, "__uint128_t") +#endif + +/*********************************************************************/ +/* the following are not keywords. They are included to ease parsing */ +/* preprocessor only */ + DEF(TOK_DEFINE, "define") + DEF(TOK_INCLUDE, "include") + DEF(TOK_INCLUDE_NEXT, "include_next") + DEF(TOK_IFDEF, "ifdef") + DEF(TOK_IFNDEF, "ifndef") + DEF(TOK_ELIF, "elif") + DEF(TOK_ENDIF, "endif") + DEF(TOK_DEFINED, "defined") + DEF(TOK_UNDEF, "undef") + DEF(TOK_ERROR, "error") + DEF(TOK_WARNING, "warning") + DEF(TOK_LINE, "line") + DEF(TOK_PRAGMA, "pragma") + DEF(TOK___LINE__, "__LINE__") + DEF(TOK___FILE__, "__FILE__") + DEF(TOK___DATE__, "__DATE__") + DEF(TOK___TIME__, "__TIME__") + DEF(TOK___FUNCTION__, "__FUNCTION__") + DEF(TOK___VA_ARGS__, "__VA_ARGS__") + DEF(TOK___COUNTER__, "__COUNTER__") + +/* special identifiers */ + DEF(TOK___FUNC__, "__func__") + +/* special floating point values */ + DEF(TOK___NAN__, "__nan__") + DEF(TOK___SNAN__, "__snan__") + DEF(TOK___INF__, "__inf__") + +/* attribute identifiers */ +/* XXX: handle all tokens generically since speed is not critical */ + DEF(TOK_SECTION1, "section") + DEF(TOK_SECTION2, "__section__") + DEF(TOK_ALIGNED1, "aligned") + DEF(TOK_ALIGNED2, "__aligned__") + DEF(TOK_PACKED1, "packed") + DEF(TOK_PACKED2, "__packed__") + DEF(TOK_WEAK1, "weak") + DEF(TOK_WEAK2, "__weak__") + DEF(TOK_ALIAS1, "alias") + DEF(TOK_ALIAS2, "__alias__") + DEF(TOK_UNUSED1, "unused") + DEF(TOK_UNUSED2, "__unused__") + DEF(TOK_CDECL1, "cdecl") + DEF(TOK_CDECL2, "__cdecl") + DEF(TOK_CDECL3, "__cdecl__") + DEF(TOK_STDCALL1, "stdcall") + DEF(TOK_STDCALL2, "__stdcall") + DEF(TOK_STDCALL3, "__stdcall__") + DEF(TOK_FASTCALL1, "fastcall") + DEF(TOK_FASTCALL2, "__fastcall") + DEF(TOK_FASTCALL3, "__fastcall__") + DEF(TOK_REGPARM1, "regparm") + DEF(TOK_REGPARM2, "__regparm__") + + DEF(TOK_MODE, "__mode__") + DEF(TOK_MODE_QI, "__QI__") + DEF(TOK_MODE_DI, "__DI__") + DEF(TOK_MODE_HI, "__HI__") + DEF(TOK_MODE_SI, "__SI__") + DEF(TOK_MODE_word, "__word__") + + DEF(TOK_DLLEXPORT, "dllexport") + DEF(TOK_DLLIMPORT, "dllimport") + DEF(TOK_NORETURN1, "noreturn") + DEF(TOK_NORETURN2, "__noreturn__") + DEF(TOK_VISIBILITY1, "visibility") + DEF(TOK_VISIBILITY2, "__visibility__") + + DEF(TOK_builtin_types_compatible_p, "__builtin_types_compatible_p") + DEF(TOK_builtin_choose_expr, "__builtin_choose_expr") + DEF(TOK_builtin_constant_p, "__builtin_constant_p") + DEF(TOK_builtin_frame_address, "__builtin_frame_address") + DEF(TOK_builtin_return_address, "__builtin_return_address") + DEF(TOK_builtin_expect, "__builtin_expect") + /*DEF(TOK_builtin_va_list, "__builtin_va_list")*/ +#if defined TCC_TARGET_PE && defined TCC_TARGET_X86_64 + DEF(TOK_builtin_va_start, "__builtin_va_start") +#elif defined TCC_TARGET_X86_64 + DEF(TOK_builtin_va_arg_types, "__builtin_va_arg_types") +#elif defined TCC_TARGET_ARM64 + DEF(TOK___va_start, "__va_start") + DEF(TOK___va_arg, "__va_arg") +#endif + +/* pragma */ + DEF(TOK_pack, "pack") +#if !defined(TCC_TARGET_I386) && !defined(TCC_TARGET_X86_64) + /* already defined for assembler */ + DEF(TOK_ASM_push, "push") + DEF(TOK_ASM_pop, "pop") +#endif + DEF(TOK_comment, "comment") + DEF(TOK_lib, "lib") + DEF(TOK_push_macro, "push_macro") + DEF(TOK_pop_macro, "pop_macro") + DEF(TOK_once, "once") + DEF(TOK_option, "option") + +/* builtin functions or variables */ +#ifndef TCC_ARM_EABI + DEF(TOK_memcpy, "memcpy") + DEF(TOK_memmove, "memmove") + DEF(TOK_memset, "memset") + DEF(TOK___divdi3, "__divdi3") + DEF(TOK___moddi3, "__moddi3") + DEF(TOK___udivdi3, "__udivdi3") + DEF(TOK___umoddi3, "__umoddi3") + DEF(TOK___ashrdi3, "__ashrdi3") + DEF(TOK___lshrdi3, "__lshrdi3") + DEF(TOK___ashldi3, "__ashldi3") + DEF(TOK___floatundisf, "__floatundisf") + DEF(TOK___floatundidf, "__floatundidf") +# ifndef TCC_ARM_VFP + DEF(TOK___floatundixf, "__floatundixf") + DEF(TOK___fixunsxfdi, "__fixunsxfdi") +# endif + DEF(TOK___fixunssfdi, "__fixunssfdi") + DEF(TOK___fixunsdfdi, "__fixunsdfdi") +#endif + +#if defined TCC_TARGET_ARM +# ifdef TCC_ARM_EABI + DEF(TOK_memcpy, "__aeabi_memcpy") + DEF(TOK_memcpy4, "__aeabi_memcpy4") + DEF(TOK_memcpy8, "__aeabi_memcpy8") + DEF(TOK_memmove, "__aeabi_memmove") + DEF(TOK_memset, "__aeabi_memset") + DEF(TOK___aeabi_ldivmod, "__aeabi_ldivmod") + DEF(TOK___aeabi_uldivmod, "__aeabi_uldivmod") + DEF(TOK___aeabi_idivmod, "__aeabi_idivmod") + DEF(TOK___aeabi_uidivmod, "__aeabi_uidivmod") + DEF(TOK___divsi3, "__aeabi_idiv") + DEF(TOK___udivsi3, "__aeabi_uidiv") + DEF(TOK___floatdisf, "__aeabi_l2f") + DEF(TOK___floatdidf, "__aeabi_l2d") + DEF(TOK___fixsfdi, "__aeabi_f2lz") + DEF(TOK___fixdfdi, "__aeabi_d2lz") + DEF(TOK___ashrdi3, "__aeabi_lasr") + DEF(TOK___lshrdi3, "__aeabi_llsr") + DEF(TOK___ashldi3, "__aeabi_llsl") + DEF(TOK___floatundisf, "__aeabi_ul2f") + DEF(TOK___floatundidf, "__aeabi_ul2d") + DEF(TOK___fixunssfdi, "__aeabi_f2ulz") + DEF(TOK___fixunsdfdi, "__aeabi_d2ulz") +# else + DEF(TOK___modsi3, "__modsi3") + DEF(TOK___umodsi3, "__umodsi3") + DEF(TOK___divsi3, "__divsi3") + DEF(TOK___udivsi3, "__udivsi3") + DEF(TOK___floatdisf, "__floatdisf") + DEF(TOK___floatdidf, "__floatdidf") +# ifndef TCC_ARM_VFP + DEF(TOK___floatdixf, "__floatdixf") + DEF(TOK___fixunssfsi, "__fixunssfsi") + DEF(TOK___fixunsdfsi, "__fixunsdfsi") + DEF(TOK___fixunsxfsi, "__fixunsxfsi") + DEF(TOK___fixxfdi, "__fixxfdi") +# endif + DEF(TOK___fixsfdi, "__fixsfdi") + DEF(TOK___fixdfdi, "__fixdfdi") +# endif +#endif + +#if defined TCC_TARGET_C67 + DEF(TOK__divi, "_divi") + DEF(TOK__divu, "_divu") + DEF(TOK__divf, "_divf") + DEF(TOK__divd, "_divd") + DEF(TOK__remi, "_remi") + DEF(TOK__remu, "_remu") +#endif + +#if defined TCC_TARGET_I386 + DEF(TOK___fixsfdi, "__fixsfdi") + DEF(TOK___fixdfdi, "__fixdfdi") + DEF(TOK___fixxfdi, "__fixxfdi") +#endif + +#if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64 + DEF(TOK_alloca, "alloca") +#endif + +#if defined TCC_TARGET_PE + DEF(TOK___chkstk, "__chkstk") +#endif +#ifdef TCC_TARGET_ARM64 + DEF(TOK___arm64_clear_cache, "__arm64_clear_cache") + DEF(TOK___addtf3, "__addtf3") + DEF(TOK___subtf3, "__subtf3") + DEF(TOK___multf3, "__multf3") + DEF(TOK___divtf3, "__divtf3") + DEF(TOK___extendsftf2, "__extendsftf2") + DEF(TOK___extenddftf2, "__extenddftf2") + DEF(TOK___trunctfsf2, "__trunctfsf2") + DEF(TOK___trunctfdf2, "__trunctfdf2") + DEF(TOK___fixtfsi, "__fixtfsi") + DEF(TOK___fixtfdi, "__fixtfdi") + DEF(TOK___fixunstfsi, "__fixunstfsi") + DEF(TOK___fixunstfdi, "__fixunstfdi") + DEF(TOK___floatsitf, "__floatsitf") + DEF(TOK___floatditf, "__floatditf") + DEF(TOK___floatunsitf, "__floatunsitf") + DEF(TOK___floatunditf, "__floatunditf") + DEF(TOK___eqtf2, "__eqtf2") + DEF(TOK___netf2, "__netf2") + DEF(TOK___lttf2, "__lttf2") + DEF(TOK___letf2, "__letf2") + DEF(TOK___gttf2, "__gttf2") + DEF(TOK___getf2, "__getf2") +#endif + +/* bound checking symbols */ +#ifdef CONFIG_TCC_BCHECK + DEF(TOK___bound_ptr_add, "__bound_ptr_add") + DEF(TOK___bound_ptr_indir1, "__bound_ptr_indir1") + DEF(TOK___bound_ptr_indir2, "__bound_ptr_indir2") + DEF(TOK___bound_ptr_indir4, "__bound_ptr_indir4") + DEF(TOK___bound_ptr_indir8, "__bound_ptr_indir8") + DEF(TOK___bound_ptr_indir12, "__bound_ptr_indir12") + DEF(TOK___bound_ptr_indir16, "__bound_ptr_indir16") + DEF(TOK___bound_main_arg, "__bound_main_arg") + DEF(TOK___bound_local_new, "__bound_local_new") + DEF(TOK___bound_local_delete, "__bound_local_delete") +# ifdef TCC_TARGET_PE + DEF(TOK_malloc, "malloc") + DEF(TOK_free, "free") + DEF(TOK_realloc, "realloc") + DEF(TOK_memalign, "memalign") + DEF(TOK_calloc, "calloc") +# endif + DEF(TOK_strlen, "strlen") + DEF(TOK_strcpy, "strcpy") +#endif + +/* Tiny Assembler */ + DEF_ASMDIR(byte) /* must be first directive */ + DEF_ASMDIR(word) + DEF_ASMDIR(align) + DEF_ASMDIR(balign) + DEF_ASMDIR(p2align) + DEF_ASMDIR(set) + DEF_ASMDIR(skip) + DEF_ASMDIR(space) + DEF_ASMDIR(string) + DEF_ASMDIR(asciz) + DEF_ASMDIR(ascii) + DEF_ASMDIR(file) + DEF_ASMDIR(globl) + DEF_ASMDIR(global) + DEF_ASMDIR(weak) + DEF_ASMDIR(hidden) + DEF_ASMDIR(ident) + DEF_ASMDIR(size) + DEF_ASMDIR(type) + DEF_ASMDIR(text) + DEF_ASMDIR(data) + DEF_ASMDIR(bss) + DEF_ASMDIR(previous) + DEF_ASMDIR(pushsection) + DEF_ASMDIR(popsection) + DEF_ASMDIR(fill) + DEF_ASMDIR(rept) + DEF_ASMDIR(endr) + DEF_ASMDIR(org) + DEF_ASMDIR(quad) +#if defined(TCC_TARGET_I386) + DEF_ASMDIR(code16) + DEF_ASMDIR(code32) +#elif defined(TCC_TARGET_X86_64) + DEF_ASMDIR(code64) +#endif + DEF_ASMDIR(short) + DEF_ASMDIR(long) + DEF_ASMDIR(int) + DEF_ASMDIR(section) /* must be last directive */ + +#if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64 +#include "i386-tok.h" +#endif diff --git a/tinyc/tcctools.c b/tinyc/tcctools.c new file mode 100644 index 000000000..53d88be6a --- /dev/null +++ b/tinyc/tcctools.c @@ -0,0 +1,546 @@ +/* -------------------------------------------------------------- */ +/* + * TCC - Tiny C Compiler + * + * tcctools.c - extra tools and and -m32/64 support + * + */ + +/* -------------------------------------------------------------- */ +/* + * This program is for making libtcc1.a without ar + * tiny_libmaker - tiny elf lib maker + * usage: tiny_libmaker [lib] files... + * Copyright (c) 2007 Timppa + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "tcc.h" + +//#define ARMAG "!\n" +#define ARFMAG "`\n" + +typedef struct { + char ar_name[16]; + char ar_date[12]; + char ar_uid[6]; + char ar_gid[6]; + char ar_mode[8]; + char ar_size[10]; + char ar_fmag[2]; +} ArHdr; + +static unsigned long le2belong(unsigned long ul) { + return ((ul & 0xFF0000)>>8)+((ul & 0xFF000000)>>24) + + ((ul & 0xFF)<<24)+((ul & 0xFF00)<<8); +} + +/* Returns 1 if s contains any of the chars of list, else 0 */ +static int contains_any(const char *s, const char *list) { + const char *l; + for (; *s; s++) { + for (l = list; *l; l++) { + if (*s == *l) + return 1; + } + } + return 0; +} + +static int ar_usage(int ret) { + fprintf(stderr, "usage: tcc -ar [rcsv] lib file...\n"); + fprintf(stderr, "create library ([abdioptxN] not supported).\n"); + return ret; +} + +ST_FUNC int tcc_tool_ar(TCCState *s1, int argc, char **argv) +{ + static ArHdr arhdr = { + "/ ", + " ", + "0 ", + "0 ", + "0 ", + " ", + ARFMAG + }; + + static ArHdr arhdro = { + " ", + " ", + "0 ", + "0 ", + "0 ", + " ", + ARFMAG + }; + + FILE *fi, *fh = NULL, *fo = NULL; + ElfW(Ehdr) *ehdr; + ElfW(Shdr) *shdr; + ElfW(Sym) *sym; + int i, fsize, i_lib, i_obj; + char *buf, *shstr, *symtab = NULL, *strtab = NULL; + int symtabsize = 0;//, strtabsize = 0; + char *anames = NULL; + int *afpos = NULL; + int istrlen, strpos = 0, fpos = 0, funccnt = 0, funcmax, hofs; + char tfile[260], stmp[20]; + char *file, *name; + int ret = 2; + const char *ops_conflict = "habdioptxN"; // unsupported but destructive if ignored. + int verbose = 0; + + i_lib = 0; i_obj = 0; // will hold the index of the lib and first obj + for (i = 1; i < argc; i++) { + const char *a = argv[i]; + if (*a == '-' && strstr(a, ".")) + ret = 1; // -x.y is always invalid (same as gnu ar) + if ((*a == '-') || (i == 1 && !strstr(a, "."))) { // options argument + if (contains_any(a, ops_conflict)) + ret = 1; + if (strstr(a, "v")) + verbose = 1; + } else { // lib or obj files: don't abort - keep validating all args. + if (!i_lib) // first file is the lib + i_lib = i; + else if (!i_obj) // second file is the first obj + i_obj = i; + } + } + + if (!i_obj) // i_obj implies also i_lib. we require both. + ret = 1; + + if (ret == 1) + return ar_usage(ret); + + if ((fh = fopen(argv[i_lib], "wb")) == NULL) + { + fprintf(stderr, "tcc: ar: can't open file %s \n", argv[i_lib]); + goto the_end; + } + + sprintf(tfile, "%s.tmp", argv[i_lib]); + if ((fo = fopen(tfile, "wb+")) == NULL) + { + fprintf(stderr, "tcc: ar: can't create temporary file %s\n", tfile); + goto the_end; + } + + funcmax = 250; + afpos = tcc_realloc(NULL, funcmax * sizeof *afpos); // 250 func + memcpy(&arhdro.ar_mode, "100666", 6); + + // i_obj = first input object file + while (i_obj < argc) + { + if (*argv[i_obj] == '-') { // by now, all options start with '-' + i_obj++; + continue; + } + if ((fi = fopen(argv[i_obj], "rb")) == NULL) { + fprintf(stderr, "tcc: ar: can't open file %s \n", argv[i_obj]); + goto the_end; + } + if (verbose) + printf("a - %s\n", argv[i_obj]); + + fseek(fi, 0, SEEK_END); + fsize = ftell(fi); + fseek(fi, 0, SEEK_SET); + buf = tcc_malloc(fsize + 1); + fread(buf, fsize, 1, fi); + fclose(fi); + + // elf header + ehdr = (ElfW(Ehdr) *)buf; + if (ehdr->e_ident[4] != ELFCLASSW) + { + fprintf(stderr, "tcc: ar: Unsupported Elf Class: %s\n", argv[i_obj]); + goto the_end; + } + + shdr = (ElfW(Shdr) *) (buf + ehdr->e_shoff + ehdr->e_shstrndx * ehdr->e_shentsize); + shstr = (char *)(buf + shdr->sh_offset); + for (i = 0; i < ehdr->e_shnum; i++) + { + shdr = (ElfW(Shdr) *) (buf + ehdr->e_shoff + i * ehdr->e_shentsize); + if (!shdr->sh_offset) + continue; + if (shdr->sh_type == SHT_SYMTAB) + { + symtab = (char *)(buf + shdr->sh_offset); + symtabsize = shdr->sh_size; + } + if (shdr->sh_type == SHT_STRTAB) + { + if (!strcmp(shstr + shdr->sh_name, ".strtab")) + { + strtab = (char *)(buf + shdr->sh_offset); + //strtabsize = shdr->sh_size; + } + } + } + + if (symtab && symtabsize) + { + int nsym = symtabsize / sizeof(ElfW(Sym)); + //printf("symtab: info size shndx name\n"); + for (i = 1; i < nsym; i++) + { + sym = (ElfW(Sym) *) (symtab + i * sizeof(ElfW(Sym))); + if (sym->st_shndx && + (sym->st_info == 0x10 + || sym->st_info == 0x11 + || sym->st_info == 0x12 + )) { + //printf("symtab: %2Xh %4Xh %2Xh %s\n", sym->st_info, sym->st_size, sym->st_shndx, strtab + sym->st_name); + istrlen = strlen(strtab + sym->st_name)+1; + anames = tcc_realloc(anames, strpos+istrlen); + strcpy(anames + strpos, strtab + sym->st_name); + strpos += istrlen; + if (++funccnt >= funcmax) { + funcmax += 250; + afpos = tcc_realloc(afpos, funcmax * sizeof *afpos); // 250 func more + } + afpos[funccnt] = fpos; + } + } + } + + file = argv[i_obj]; + for (name = strchr(file, 0); + name > file && name[-1] != '/' && name[-1] != '\\'; + --name); + istrlen = strlen(name); + if (istrlen >= sizeof(arhdro.ar_name)) + istrlen = sizeof(arhdro.ar_name) - 1; + memset(arhdro.ar_name, ' ', sizeof(arhdro.ar_name)); + memcpy(arhdro.ar_name, name, istrlen); + arhdro.ar_name[istrlen] = '/'; + sprintf(stmp, "%-10d", fsize); + memcpy(&arhdro.ar_size, stmp, 10); + fwrite(&arhdro, sizeof(arhdro), 1, fo); + fwrite(buf, fsize, 1, fo); + tcc_free(buf); + i_obj++; + fpos += (fsize + sizeof(arhdro)); + } + hofs = 8 + sizeof(arhdr) + strpos + (funccnt+1) * sizeof(int); + fpos = 0; + if ((hofs & 1)) // align + hofs++, fpos = 1; + // write header + fwrite("!\n", 8, 1, fh); + sprintf(stmp, "%-10d", (int)(strpos + (funccnt+1) * sizeof(int))); + memcpy(&arhdr.ar_size, stmp, 10); + fwrite(&arhdr, sizeof(arhdr), 1, fh); + afpos[0] = le2belong(funccnt); + for (i=1; i<=funccnt; i++) + afpos[i] = le2belong(afpos[i] + hofs); + fwrite(afpos, (funccnt+1) * sizeof(int), 1, fh); + fwrite(anames, strpos, 1, fh); + if (fpos) + fwrite("", 1, 1, fh); + // write objects + fseek(fo, 0, SEEK_END); + fsize = ftell(fo); + fseek(fo, 0, SEEK_SET); + buf = tcc_malloc(fsize + 1); + fread(buf, fsize, 1, fo); + fwrite(buf, fsize, 1, fh); + tcc_free(buf); + ret = 0; +the_end: + if (anames) + tcc_free(anames); + if (afpos) + tcc_free(afpos); + if (fh) + fclose(fh); + if (fo) + fclose(fo), remove(tfile); + return ret; +} + +/* -------------------------------------------------------------- */ +/* + * tiny_impdef creates an export definition file (.def) from a dll + * on MS-Windows. Usage: tiny_impdef library.dll [-o outputfile]" + * + * Copyright (c) 2005,2007 grischka + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifdef TCC_TARGET_PE + +ST_FUNC int tcc_tool_impdef(TCCState *s1, int argc, char **argv) +{ + int ret, v, i; + char infile[260]; + char outfile[260]; + + const char *file; + char *p, *q; + FILE *fp, *op; + +#ifdef _WIN32 + char path[260]; +#endif + + infile[0] = outfile[0] = 0; + fp = op = NULL; + ret = 1; + p = NULL; + v = 0; + + for (i = 1; i < argc; ++i) { + const char *a = argv[i]; + if ('-' == a[0]) { + if (0 == strcmp(a, "-v")) { + v = 1; + } else if (0 == strcmp(a, "-o")) { + if (++i == argc) + goto usage; + strcpy(outfile, argv[i]); + } else + goto usage; + } else if (0 == infile[0]) + strcpy(infile, a); + else + goto usage; + } + + if (0 == infile[0]) { +usage: + fprintf(stderr, + "usage: tcc -impdef library.dll [-v] [-o outputfile]\n" + "create export definition file (.def) from dll\n" + ); + goto the_end; + } + + if (0 == outfile[0]) { + strcpy(outfile, tcc_basename(infile)); + q = strrchr(outfile, '.'); + if (NULL == q) + q = strchr(outfile, 0); + strcpy(q, ".def"); + } + + file = infile; +#ifdef _WIN32 + if (SearchPath(NULL, file, ".dll", sizeof path, path, NULL)) + file = path; +#endif + ret = tcc_get_dllexports(file, &p); + if (ret || !p) { + fprintf(stderr, "tcc: impdef: %s '%s'\n", + ret == -1 ? "can't find file" : + ret == 1 ? "can't read symbols" : + ret == 0 ? "no symbols found in" : + "unknown file type", file); + ret = 1; + goto the_end; + } + + if (v) + printf("-> %s\n", file); + + op = fopen(outfile, "w"); + if (NULL == op) { + fprintf(stderr, "tcc: impdef: could not create output file: %s\n", outfile); + goto the_end; + } + + fprintf(op, "LIBRARY %s\n\nEXPORTS\n", tcc_basename(file)); + for (q = p, i = 0; *q; ++i) { + fprintf(op, "%s\n", q); + q += strlen(q) + 1; + } + + if (v) + printf("<- %s (%d symbol%s)\n", outfile, i, &"s"[i<2]); + + ret = 0; + +the_end: + /* cannot free memory received from tcc_get_dllexports + if it came from a dll */ + /* if (p) + tcc_free(p); */ + if (fp) + fclose(fp); + if (op) + fclose(op); + return ret; +} + +#endif /* TCC_TARGET_PE */ + +/* -------------------------------------------------------------- */ +/* + * TCC - Tiny C Compiler + * + * Copyright (c) 2001-2004 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* re-execute the i386/x86_64 cross-compilers with tcc -m32/-m64: */ + +#if !defined TCC_TARGET_I386 && !defined TCC_TARGET_X86_64 + +ST_FUNC void tcc_tool_cross(TCCState *s, char **argv, int option) +{ + tcc_error("-m%d not implemented.", option); +} + +#else +#ifdef _WIN32 +#include + +static char *str_replace(const char *str, const char *p, const char *r) +{ + const char *s, *s0; + char *d, *d0; + int sl, pl, rl; + + sl = strlen(str); + pl = strlen(p); + rl = strlen(r); + for (d0 = NULL;; d0 = tcc_malloc(sl + 1)) { + for (d = d0, s = str; s0 = s, s = strstr(s, p), s; s += pl) { + if (d) { + memcpy(d, s0, sl = s - s0), d += sl; + memcpy(d, r, rl), d += rl; + } else + sl += rl - pl; + } + if (d) { + strcpy(d, s0); + return d0; + } + } +} + +static int execvp_win32(const char *prog, char **argv) +{ + int ret; char **p; + /* replace all " by \" */ + for (p = argv; *p; ++p) + if (strchr(*p, '"')) + *p = str_replace(*p, "\"", "\\\""); + ret = _spawnvp(P_NOWAIT, prog, (const char *const*)argv); + if (-1 == ret) + return ret; + _cwait(&ret, ret, WAIT_CHILD); + exit(ret); +} +#define execvp execvp_win32 +#endif /* _WIN32 */ + +ST_FUNC void tcc_tool_cross(TCCState *s, char **argv, int target) +{ + char program[4096]; + char *a0 = argv[0]; + int prefix = tcc_basename(a0) - a0; + + snprintf(program, sizeof program, + "%.*s%s" +#ifdef TCC_TARGET_PE + "-win32" +#endif + "-tcc" +#ifdef _WIN32 + ".exe" +#endif + , prefix, a0, target == 64 ? "x86_64" : "i386"); + + if (strcmp(a0, program)) + execvp(argv[0] = program, argv); + tcc_error("could not run '%s'", program); +} + +#endif /* TCC_TARGET_I386 && TCC_TARGET_X86_64 */ +/* -------------------------------------------------------------- */ +/* enable commandline wildcard expansion (tcc -o x.exe *.c) */ + +#ifdef _WIN32 +int _CRT_glob = 1; +#ifndef _CRT_glob +int _dowildcard = 1; +#endif +#endif + +/* -------------------------------------------------------------- */ +/* generate xxx.d file */ + +ST_FUNC void gen_makedeps(TCCState *s, const char *target, const char *filename) +{ + FILE *depout; + char buf[1024]; + int i; + + if (!filename) { + /* compute filename automatically: dir/file.o -> dir/file.d */ + snprintf(buf, sizeof buf, "%.*s.d", + (int)(tcc_fileextension(target) - target), target); + filename = buf; + } + + if (s->verbose) + printf("<- %s\n", filename); + + /* XXX return err codes instead of error() ? */ + depout = fopen(filename, "w"); + if (!depout) + tcc_error("could not open '%s'", filename); + + fprintf(depout, "%s: \\\n", target); + for (i=0; inb_target_deps; ++i) + fprintf(depout, " %s \\\n", s->target_deps[i]); + fprintf(depout, "\n"); + fclose(depout); +} + +/* -------------------------------------------------------------- */ diff --git a/tinyc/tests/42test.h b/tinyc/tests/42test.h new file mode 100644 index 000000000..5db7d1c47 --- /dev/null +++ b/tinyc/tests/42test.h @@ -0,0 +1,13 @@ +/* This file is to test compute #include directives. It's named so + that it starts with a pre-processing number which isn't a valid + number (42test.h). Including this must work. */ +#ifndef INC42_FIRST +int have_included_42test_h; +#define INC42_FIRST +#elif !defined INC42_SECOND +#define INC42_SECOND +int have_included_42test_h_second; +#else +#define INC42_THIRD +int have_included_42test_h_third; +#endif diff --git a/tinyc/tests/abitest.c b/tinyc/tests/abitest.c new file mode 100644 index 000000000..4a192bd23 --- /dev/null +++ b/tinyc/tests/abitest.c @@ -0,0 +1,691 @@ +#include +#include +#include +#include +#include + +// MinGW has 80-bit rather than 64-bit long double which isn't compatible with TCC or MSVC +#if defined(_WIN32) && defined(__GNUC__) +#define LONG_DOUBLE double +#define LONG_DOUBLE_LITERAL(x) x +#else +#define LONG_DOUBLE long double +#define LONG_DOUBLE_LITERAL(x) x ## L +#endif + +static int g_argc; +static char **g_argv; + +static void set_options(TCCState *s, int argc, char **argv) +{ + int i; + for (i = 1; i < argc; ++i) { + char *a = argv[i]; + if (a[0] == '-') { + if (a[1] == 'B') + tcc_set_lib_path(s, a+2); + else if (a[1] == 'I') + tcc_add_include_path(s, a+2); + else if (a[1] == 'L') + tcc_add_library_path(s, a+2); + } + } +} + +typedef int (*callback_type) (void*); + +/* + * Compile source code and call a callback with a pointer to the symbol "f". + */ +static int run_callback(const char *src, callback_type callback) { + TCCState *s; + int result; + void *ptr; + + s = tcc_new(); + if (!s) + return -1; + + set_options(s, g_argc, g_argv); + + if (tcc_set_output_type(s, TCC_OUTPUT_MEMORY) == -1) + return -1; + if (tcc_compile_string(s, src) == -1) + return -1; + if (tcc_relocate(s, TCC_RELOCATE_AUTO) == -1) + return -1; + + ptr = tcc_get_symbol(s, "f"); + if (!ptr) + return -1; + result = callback(ptr); + + tcc_delete(s); + + return result; +} + +#define STR2(x) #x +#define STR(x) STR2(x) + +#define RET_PRIMITIVE_TEST(name, type, val) \ + static int ret_ ## name ## _test_callback(void *ptr) { \ + type (*callback) (type) = (type(*)(type))ptr; \ + type x = val; \ + type y = callback(x); \ + return (y == x+x) ? 0 : -1; \ + } \ + \ + static int ret_ ## name ## _test(void) { \ + const char *src = STR(type) " f(" STR(type) " x) {return x+x;}"; \ + return run_callback(src, ret_ ## name ## _test_callback); \ + } + +RET_PRIMITIVE_TEST(int, int, 70000) +RET_PRIMITIVE_TEST(longlong, long long, 4333369356528LL) +RET_PRIMITIVE_TEST(float, float, 63.0) +RET_PRIMITIVE_TEST(double, double, 14789798.0) +RET_PRIMITIVE_TEST(longdouble, LONG_DOUBLE, LONG_DOUBLE_LITERAL(378943892.0)) + +/* + * ret_2float_test: + * + * On x86-64, a struct with 2 floats should be packed into a single + * SSE register (VT_DOUBLE is used for this purpose). + */ +typedef struct ret_2float_test_type_s {float x, y;} ret_2float_test_type; +typedef ret_2float_test_type (*ret_2float_test_function_type) (ret_2float_test_type); + +static int ret_2float_test_callback(void *ptr) { + ret_2float_test_function_type f = (ret_2float_test_function_type)ptr; + ret_2float_test_type a = {10, 35}; + ret_2float_test_type r; + r = f(a); + return ((r.x == a.x*5) && (r.y == a.y*3)) ? 0 : -1; +} + +static int ret_2float_test(void) { + const char *src = + "typedef struct ret_2float_test_type_s {float x, y;} ret_2float_test_type;" + "ret_2float_test_type f(ret_2float_test_type a) {\n" + " ret_2float_test_type r = {a.x*5, a.y*3};\n" + " return r;\n" + "}\n"; + + return run_callback(src, ret_2float_test_callback); +} + +/* + * ret_2double_test: + * + * On x86-64, a struct with 2 doubles should be passed in two SSE + * registers. + */ +typedef struct ret_2double_test_type_s {double x, y;} ret_2double_test_type; +typedef ret_2double_test_type (*ret_2double_test_function_type) (ret_2double_test_type); + +static int ret_2double_test_callback(void *ptr) { + ret_2double_test_function_type f = (ret_2double_test_function_type)ptr; + ret_2double_test_type a = {10, 35}; + ret_2double_test_type r; + r = f(a); + return ((r.x == a.x*5) && (r.y == a.y*3)) ? 0 : -1; +} + +static int ret_2double_test(void) { + const char *src = + "typedef struct ret_2double_test_type_s {double x, y;} ret_2double_test_type;" + "ret_2double_test_type f(ret_2double_test_type a) {\n" + " ret_2double_test_type r = {a.x*5, a.y*3};\n" + " return r;\n" + "}\n"; + + return run_callback(src, ret_2double_test_callback); +} + +/* + * ret_8plus2double_test: + * + * This catches a corner case in the x86_64 ABI code: the first 7 + * arguments fit into registers, the 8th doesn't, but the 9th argument + * fits into the 8th XMM register. + * + * Note that the purpose of the 10th argument is to avoid a situation + * in which gcc would accidentally put the double at the right + * address, thus causing a success message even though TCC actually + * generated incorrect code. + */ +typedef ret_2double_test_type (*ret_8plus2double_test_function_type) (double, double, double, double, double, double, double, ret_2double_test_type, double, double); + +static int ret_8plus2double_test_callback(void *ptr) { + ret_8plus2double_test_function_type f = (ret_8plus2double_test_function_type)ptr; + ret_2double_test_type a = {10, 35}; + ret_2double_test_type r; + r = f(0, 0, 0, 0, 0, 0, 0, a, 37, 38); + return ((r.x == 37) && (r.y == 37)) ? 0 : -1; +} + +static int ret_8plus2double_test(void) { + const char *src = + "typedef struct ret_2double_test_type_s {double x, y;} ret_2double_test_type;" + "ret_2double_test_type f(double x1, double x2, double x3, double x4, double x5, double x6, double x7, ret_2double_test_type a, double x8, double x9) {\n" + " ret_2double_test_type r = { x8, x8 };\n" + " return r;\n" + "}\n"; + + return run_callback(src, ret_8plus2double_test_callback); +} + +/* + * ret_mixed_test: + * + * On x86-64, a struct with a double and a 64-bit integer should be + * passed in one SSE register and one integer register. + */ +typedef struct ret_mixed_test_type_s {double x; long long y;} ret_mixed_test_type; +typedef ret_mixed_test_type (*ret_mixed_test_function_type) (ret_mixed_test_type); + +static int ret_mixed_test_callback(void *ptr) { + ret_mixed_test_function_type f = (ret_mixed_test_function_type)ptr; + ret_mixed_test_type a = {10, 35}; + ret_mixed_test_type r; + r = f(a); + return ((r.x == a.x*5) && (r.y == a.y*3)) ? 0 : -1; +} + +static int ret_mixed_test(void) { + const char *src = + "typedef struct ret_mixed_test_type_s {double x; long long y;} ret_mixed_test_type;" + "ret_mixed_test_type f(ret_mixed_test_type a) {\n" + " ret_mixed_test_type r = {a.x*5, a.y*3};\n" + " return r;\n" + "}\n"; + + return run_callback(src, ret_mixed_test_callback); +} + +/* + * ret_mixed2_test: + * + * On x86-64, a struct with two floats and two 32-bit integers should + * be passed in one SSE register and one integer register. + */ +typedef struct ret_mixed2_test_type_s {float x,x2; int y,y2;} ret_mixed2_test_type; +typedef ret_mixed2_test_type (*ret_mixed2_test_function_type) (ret_mixed2_test_type); + +static int ret_mixed2_test_callback(void *ptr) { + ret_mixed2_test_function_type f = (ret_mixed2_test_function_type)ptr; + ret_mixed2_test_type a = {10, 5, 35, 7 }; + ret_mixed2_test_type r; + r = f(a); + return ((r.x == a.x*5) && (r.y == a.y*3)) ? 0 : -1; +} + +static int ret_mixed2_test(void) { + const char *src = + "typedef struct ret_mixed2_test_type_s {float x, x2; int y,y2;} ret_mixed2_test_type;" + "ret_mixed2_test_type f(ret_mixed2_test_type a) {\n" + " ret_mixed2_test_type r = {a.x*5, 0, a.y*3, 0};\n" + " return r;\n" + "}\n"; + + return run_callback(src, ret_mixed2_test_callback); +} + +/* + * ret_mixed3_test: + * + * On x86-64, this struct should be passed in two integer registers. + */ +typedef struct ret_mixed3_test_type_s {float x; int y; float x2; int y2;} ret_mixed3_test_type; +typedef ret_mixed3_test_type (*ret_mixed3_test_function_type) (ret_mixed3_test_type); + +static int ret_mixed3_test_callback(void *ptr) { + ret_mixed3_test_function_type f = (ret_mixed3_test_function_type)ptr; + ret_mixed3_test_type a = {10, 5, 35, 7 }; + ret_mixed3_test_type r; + r = f(a); + return ((r.x == a.x*5) && (r.y2 == a.y*3)) ? 0 : -1; +} + +static int ret_mixed3_test(void) { + const char *src = + "typedef struct ret_mixed3_test_type_s {float x; int y; float x2; int y2;} ret_mixed3_test_type;" + "ret_mixed3_test_type f(ret_mixed3_test_type a) {\n" + " ret_mixed3_test_type r = {a.x*5, 0, 0, a.y*3};\n" + " return r;\n" + "}\n"; + + return run_callback(src, ret_mixed3_test_callback); +} + +/* + * reg_pack_test: return a small struct which should be packed into + * registers (Win32) during return. + */ +typedef struct reg_pack_test_type_s {int x, y;} reg_pack_test_type; +typedef reg_pack_test_type (*reg_pack_test_function_type) (reg_pack_test_type); + +static int reg_pack_test_callback(void *ptr) { + reg_pack_test_function_type f = (reg_pack_test_function_type)ptr; + reg_pack_test_type a = {10, 35}; + reg_pack_test_type r; + r = f(a); + return ((r.x == a.x*5) && (r.y == a.y*3)) ? 0 : -1; +} + +static int reg_pack_test(void) { + const char *src = + "typedef struct reg_pack_test_type_s {int x, y;} reg_pack_test_type;" + "reg_pack_test_type f(reg_pack_test_type a) {\n" + " reg_pack_test_type r = {a.x*5, a.y*3};\n" + " return r;\n" + "}\n"; + + return run_callback(src, reg_pack_test_callback); +} + +/* + * reg_pack_longlong_test: return a small struct which should be packed into + * registers (x86-64) during return. + */ +typedef struct reg_pack_longlong_test_type_s {long long x, y;} reg_pack_longlong_test_type; +typedef reg_pack_longlong_test_type (*reg_pack_longlong_test_function_type) (reg_pack_longlong_test_type); + +static int reg_pack_longlong_test_callback(void *ptr) { + reg_pack_longlong_test_function_type f = (reg_pack_longlong_test_function_type)ptr; + reg_pack_longlong_test_type a = {10, 35}; + reg_pack_longlong_test_type r; + r = f(a); + return ((r.x == a.x*5) && (r.y == a.y*3)) ? 0 : -1; +} + +static int reg_pack_longlong_test(void) { + const char *src = + "typedef struct reg_pack_longlong_test_type_s {long long x, y;} reg_pack_longlong_test_type;" + "reg_pack_longlong_test_type f(reg_pack_longlong_test_type a) {\n" + " reg_pack_longlong_test_type r = {a.x*5, a.y*3};\n" + " return r;\n" + "}\n"; + + return run_callback(src, reg_pack_longlong_test_callback); +} + +/* + * ret_6plus2longlong_test: + * + * This catches a corner case in the x86_64 ABI code: the first 5 + * arguments fit into registers, the 6th doesn't, but the 7th argument + * fits into the 6th argument integer register, %r9. + * + * Note that the purpose of the 10th argument is to avoid a situation + * in which gcc would accidentally put the longlong at the right + * address, thus causing a success message even though TCC actually + * generated incorrect code. + */ +typedef reg_pack_longlong_test_type (*ret_6plus2longlong_test_function_type) (long long, long long, long long, long long, long long, reg_pack_longlong_test_type, long long, long long); + +static int ret_6plus2longlong_test_callback(void *ptr) { + ret_6plus2longlong_test_function_type f = (ret_6plus2longlong_test_function_type)ptr; + reg_pack_longlong_test_type a = {10, 35}; + reg_pack_longlong_test_type r; + r = f(0, 0, 0, 0, 0, a, 37, 38); + return ((r.x == 37) && (r.y == 37)) ? 0 : -1; +} + +static int ret_6plus2longlong_test(void) { + const char *src = + "typedef struct reg_pack_longlong_test_type_s {long long x, y;} reg_pack_longlong_test_type;" + "reg_pack_longlong_test_type f(long long x1, long long x2, long long x3, long long x4, long long x5, reg_pack_longlong_test_type a, long long x8, long long x9) {\n" + " reg_pack_longlong_test_type r = { x8, x8 };\n" + " return r;\n" + "}\n"; + + return run_callback(src, ret_6plus2longlong_test_callback); +} + +/* + * sret_test: Create a struct large enough to be returned via sret + * (hidden pointer as first function argument) + */ +typedef struct sret_test_type_s {long long a, b, c;} sret_test_type; +typedef sret_test_type (*sret_test_function_type) (sret_test_type); + +static int sret_test_callback(void *ptr) { + sret_test_function_type f = (sret_test_function_type)(ptr); + sret_test_type x = {5436LL, 658277698LL, 43878957LL}; + sret_test_type r = f(x); + return ((r.a==x.a*35)&&(r.b==x.b*19)&&(r.c==x.c*21)) ? 0 : -1; +} + +static int sret_test(void) { + const char *src = + "typedef struct sret_test_type_s {long long a, b, c;} sret_test_type;\n" + "sret_test_type f(sret_test_type x) {\n" + " sret_test_type r = {x.a*35, x.b*19, x.c*21};\n" + " return r;\n" + "}\n"; + + return run_callback(src, sret_test_callback); +} + +/* + * one_member_union_test: + * + * In the x86-64 ABI a union should always be passed on the stack. However + * it appears that a single member union is treated by GCC as its member. + */ +typedef union one_member_union_test_type_u {int x;} one_member_union_test_type; +typedef one_member_union_test_type (*one_member_union_test_function_type) (one_member_union_test_type); + +static int one_member_union_test_callback(void *ptr) { + one_member_union_test_function_type f = (one_member_union_test_function_type)ptr; + one_member_union_test_type a, b; + a.x = 34; + b = f(a); + return (b.x == a.x*2) ? 0 : -1; +} + +static int one_member_union_test(void) { + const char *src = + "typedef union one_member_union_test_type_u {int x;} one_member_union_test_type;\n" + "one_member_union_test_type f(one_member_union_test_type a) {\n" + " one_member_union_test_type b;\n" + " b.x = a.x * 2;\n" + " return b;\n" + "}\n"; + return run_callback(src, one_member_union_test_callback); +} + +/* + * two_member_union_test: + * + * In the x86-64 ABI a union should always be passed on the stack. + */ +typedef union two_member_union_test_type_u {int x; long y;} two_member_union_test_type; +typedef two_member_union_test_type (*two_member_union_test_function_type) (two_member_union_test_type); + +static int two_member_union_test_callback(void *ptr) { + two_member_union_test_function_type f = (two_member_union_test_function_type)ptr; + two_member_union_test_type a, b; + a.x = 34; + b = f(a); + return (b.x == a.x*2) ? 0 : -1; +} + +static int two_member_union_test(void) { + const char *src = + "typedef union two_member_union_test_type_u {int x; long y;} two_member_union_test_type;\n" + "two_member_union_test_type f(two_member_union_test_type a) {\n" + " two_member_union_test_type b;\n" + " b.x = a.x * 2;\n" + " return b;\n" + "}\n"; + return run_callback(src, two_member_union_test_callback); +} + +/* + * Win64 calling convention test. + */ + +typedef struct many_struct_test_type_s {long long a, b, c;} many_struct_test_type; +typedef many_struct_test_type (*many_struct_test_function_type) (many_struct_test_type,many_struct_test_type,many_struct_test_type,many_struct_test_type,many_struct_test_type,many_struct_test_type); + +static int many_struct_test_callback(void *ptr) { + many_struct_test_function_type f = (many_struct_test_function_type)ptr; + many_struct_test_type v = {1, 2, 3}; + many_struct_test_type r = f(v,v,v,v,v,v); + return ((r.a == 6) && (r.b == 12) && (r.c == 18))?0:-1; +} + +static int many_struct_test(void) { + const char *src = + "typedef struct many_struct_test_type_s {long long a, b, c;} many_struct_test_type;\n" + "many_struct_test_type f(many_struct_test_type x1, many_struct_test_type x2, many_struct_test_type x3, many_struct_test_type x4, many_struct_test_type x5, many_struct_test_type x6) {\n" + " many_struct_test_type y;\n" + " y.a = x1.a + x2.a + x3.a + x4.a + x5.a + x6.a;\n" + " y.b = x1.b + x2.b + x3.b + x4.b + x5.b + x6.b;\n" + " y.c = x1.c + x2.c + x3.c + x4.c + x5.c + x6.c;\n" + " return y;\n" + "}\n"; + return run_callback(src, many_struct_test_callback); +} + +/* + * Win64 calling convention test. + */ + +typedef struct many_struct_test_2_type_s {int a, b;} many_struct_test_2_type; +typedef many_struct_test_2_type (*many_struct_test_2_function_type) (many_struct_test_2_type,many_struct_test_2_type,many_struct_test_2_type,many_struct_test_2_type,many_struct_test_2_type,many_struct_test_2_type); + +static int many_struct_test_2_callback(void *ptr) { + many_struct_test_2_function_type f = (many_struct_test_2_function_type)ptr; + many_struct_test_2_type v = {1,2}; + many_struct_test_2_type r = f(v,v,v,v,v,v); + return ((r.a == 6) && (r.b == 12))?0:-1; +} + +static int many_struct_test_2(void) { + const char *src = + "typedef struct many_struct_test_2_type_s {int a, b;} many_struct_test_2_type;\n" + "many_struct_test_2_type f(many_struct_test_2_type x1, many_struct_test_2_type x2, many_struct_test_2_type x3, many_struct_test_2_type x4, many_struct_test_2_type x5, many_struct_test_2_type x6) {\n" + " many_struct_test_2_type y;\n" + " y.a = x1.a + x2.a + x3.a + x4.a + x5.a + x6.a;\n" + " y.b = x1.b + x2.b + x3.b + x4.b + x5.b + x6.b;\n" + " return y;\n" + "}\n"; + return run_callback(src, many_struct_test_2_callback); +} + +/* + * Win64 calling convention test. + */ + +typedef struct many_struct_test_3_type_s {int a, b;} many_struct_test_3_type; +typedef many_struct_test_3_type (*many_struct_test_3_function_type) (many_struct_test_3_type,many_struct_test_3_type,many_struct_test_3_type,many_struct_test_3_type,many_struct_test_3_type,many_struct_test_3_type, ...); +typedef struct many_struct_test_3_struct_type { many_struct_test_3_function_type f; many_struct_test_3_function_type *f2; } many_struct_test_3_struct_type; + +static void many_struct_test_3_dummy(double d, ...) +{ + volatile double x = d; +} + +static int many_struct_test_3_callback(void *ptr) { + many_struct_test_3_struct_type s = { ptr, }; + many_struct_test_3_struct_type *s2 = &s; + s2->f2 = &s2->f; + many_struct_test_3_dummy(1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, &s2); + many_struct_test_3_function_type f = *(s2->f2); + many_struct_test_3_type v = {1,2}; + many_struct_test_3_type r = (*((s2->f2=&f)+0))(v,v,v,v,v,v,1.0); + return ((r.a == 6) && (r.b == 12))?0:-1; +} + +static int many_struct_test_3(void) { + const char *src = + "typedef struct many_struct_test_3_type_s {int a, b;} many_struct_test_3_type;\n" + "many_struct_test_3_type f(many_struct_test_3_type x1, many_struct_test_3_type x2, many_struct_test_3_type x3, many_struct_test_3_type x4, many_struct_test_3_type x5, many_struct_test_3_type x6, ...) {\n" + " many_struct_test_3_type y;\n" + " y.a = x1.a + x2.a + x3.a + x4.a + x5.a + x6.a;\n" + " y.b = x1.b + x2.b + x3.b + x4.b + x5.b + x6.b;\n" + " return y;\n" + "}\n"; + return run_callback(src, many_struct_test_3_callback); +} + +/* + * stdarg_test: Test variable argument list ABI + */ + +typedef struct {long long a, b, c;} stdarg_test_struct_type; +typedef void (*stdarg_test_function_type) (int,int,int,...); + +static int stdarg_test_callback(void *ptr) { + stdarg_test_function_type f = (stdarg_test_function_type)ptr; + int x; + double y; + stdarg_test_struct_type z = {1, 2, 3}, w; + f(10, 10, 5, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, &x, + 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, &y, + z, z, z, z, z, &w); + return ((x == 55) && (y == 55) && (w.a == 5) && (w.b == 10) && (w.c == 15)) ? 0 : -1; +} + +static int stdarg_test(void) { + const char *src = + "#include \n" + "typedef struct {long long a, b, c;} stdarg_test_struct_type;\n" + "void f(int n_int, int n_float, int n_struct, ...) {\n" + " int i, ti = 0;\n" + " double td = 0.0;\n" + " stdarg_test_struct_type ts = {0,0,0}, tmp;\n" + " va_list ap;\n" + " va_start(ap, n_struct);\n" + " for (i = 0, ti = 0; i < n_int; ++i)\n" + " ti += va_arg(ap, int);\n" + " *va_arg(ap, int*) = ti;\n" + " for (i = 0, td = 0; i < n_float; ++i)\n" + " td += va_arg(ap, double);\n" + " *va_arg(ap, double*) = td;\n" + " for (i = 0; i < n_struct; ++i) {\n" + " tmp = va_arg(ap, stdarg_test_struct_type);\n" + " ts.a += tmp.a; ts.b += tmp.b; ts.c += tmp.c;" + " }\n" + " *va_arg(ap, stdarg_test_struct_type*) = ts;\n" + " va_end(ap);" + "}\n"; + return run_callback(src, stdarg_test_callback); +} + +typedef struct {long long a, b;} stdarg_many_test_struct_type; +typedef void (*stdarg_many_test_function_type) (int, int, int, int, int, + stdarg_many_test_struct_type, + int, int, ...); + +static int stdarg_many_test_callback(void *ptr) +{ + stdarg_many_test_function_type f = (stdarg_many_test_function_type)ptr; + int x; + stdarg_many_test_struct_type l = {10, 11}; + f(1, 2, 3, 4, 5, l, 6, 7, &x, 44); + return x == 44 ? 0 : -1; +} + +static int stdarg_many_test(void) +{ + const char *src = + "#include \n" + "typedef struct {long long a, b;} stdarg_many_test_struct_type;\n" + "void f (int a, int b, int c, int d, int e, stdarg_many_test_struct_type l, int f, int g, ...){\n" + " va_list ap;\n" + " int *p;\n" + " va_start (ap, g);\n" + " p = va_arg(ap, int*);\n" + " *p = va_arg(ap, int);\n" + " va_end (ap);\n" + "}\n"; + return run_callback(src, stdarg_many_test_callback); +} + +/* + * Test Win32 stdarg handling, since the calling convention will pass a pointer + * to the struct and the stdarg pointer must point to that pointer initially. + */ + +typedef struct {long long a, b, c;} stdarg_struct_test_struct_type; +typedef int (*stdarg_struct_test_function_type) (stdarg_struct_test_struct_type a, ...); + +static int stdarg_struct_test_callback(void *ptr) { + stdarg_struct_test_function_type f = (stdarg_struct_test_function_type)ptr; + stdarg_struct_test_struct_type v = {10, 35, 99}; + int x = f(v, 234); + return (x == 378) ? 0 : -1; +} + +static int stdarg_struct_test(void) { + const char *src = + "#include \n" + "typedef struct {long long a, b, c;} stdarg_struct_test_struct_type;\n" + "int f(stdarg_struct_test_struct_type a, ...) {\n" + " va_list ap;\n" + " va_start(ap, a);\n" + " int z = va_arg(ap, int);\n" + " va_end(ap);\n" + " return z + a.a + a.b + a.c;\n" + "}\n"; + return run_callback(src, stdarg_struct_test_callback); +} + +/* Test that x86-64 arranges the stack correctly for arguments with alignment >8 bytes */ + +typedef LONG_DOUBLE (*arg_align_test_callback_type) (LONG_DOUBLE,int,LONG_DOUBLE,int,LONG_DOUBLE); + +static int arg_align_test_callback(void *ptr) { + arg_align_test_callback_type f = (arg_align_test_callback_type)ptr; + long double x = f(12, 0, 25, 0, 37); + return (x == 74) ? 0 : -1; +} + +static int arg_align_test(void) { + const char *src = + "long double f(long double a, int b, long double c, int d, long double e) {\n" + " return a + c + e;\n" + "}\n"; + return run_callback(src, arg_align_test_callback); +} + +#define RUN_TEST(t) \ + if (!testname || (strcmp(#t, testname) == 0)) { \ + fputs(#t "... ", stdout); \ + fflush(stdout); \ + if (t() == 0) { \ + fputs("success\n", stdout); \ + } else { \ + fputs("failure\n", stdout); \ + retval = EXIT_FAILURE; \ + } \ + } + +int main(int argc, char **argv) { + int i; + const char *testname = NULL; + int retval = EXIT_SUCCESS; + + /* if tcclib.h and libtcc1.a are not installed, where can we find them */ + for (i = 1; i < argc; ++i) { + if (!memcmp(argv[i], "run_test=", 9)) + testname = argv[i] + 9; + } + + g_argv = argv, g_argc = argc; + + RUN_TEST(ret_int_test); + RUN_TEST(ret_longlong_test); + RUN_TEST(ret_float_test); + RUN_TEST(ret_double_test); + RUN_TEST(ret_longdouble_test); + RUN_TEST(ret_2float_test); + RUN_TEST(ret_2double_test); + RUN_TEST(ret_8plus2double_test); + RUN_TEST(ret_6plus2longlong_test); +#if !defined __x86_64__ || defined _WIN32 + /* currently broken on x86_64 linux */ + RUN_TEST(ret_mixed_test); + RUN_TEST(ret_mixed2_test); +#endif + RUN_TEST(ret_mixed3_test); + RUN_TEST(reg_pack_test); + RUN_TEST(reg_pack_longlong_test); + RUN_TEST(sret_test); + RUN_TEST(one_member_union_test); + RUN_TEST(two_member_union_test); + RUN_TEST(many_struct_test); + RUN_TEST(many_struct_test_2); + RUN_TEST(many_struct_test_3); + RUN_TEST(stdarg_test); + RUN_TEST(stdarg_many_test); + RUN_TEST(stdarg_struct_test); + RUN_TEST(arg_align_test); + return retval; +} diff --git a/tinyc/tests/asmtest.S b/tinyc/tests/asmtest.S new file mode 100644 index 000000000..55787054a --- /dev/null +++ b/tinyc/tests/asmtest.S @@ -0,0 +1,975 @@ +# gas comment with ``gnu'' style quotes + +/* some directive tests */ + + .byte 0xff + .byte 1, 2, 3 + .short 1, 2, 3 + .word 1, 2, 3 + .long 1, 2, 3 + .int 1, 2, 3 + .align 8 + .byte 1 +/* .align 16, 0x90 gas is too clever for us with 0x90 fill */ + .balign 4, 0x92 + .align 16, 0x91 /* 0x91 tests the non-clever behaviour */ + .skip 3 + .skip 15, 0x90 + .string "hello\0world" +/* Macro expansion should work like with C, the #n shouldn't be parsed + as asm line comment */ +#define __stringify(n) #n +#define stringify(n) __stringify(n) + .skip 8,0x90 + .asciz stringify(BLA) + .skip 8,0x90 + +# 28 "asmtest.S" # a line directive (and a line comment) + movl %eax, %ebx # some more asm comment +/* some label tests */ +L1: + movl %eax, %ebx + mov 0x10000, %eax +L2: + movl $L2 - L1, %ecx +var1: + nop ; nop ; nop ; nop + + mov var1, %eax + +/* instruction tests */ +movl %eax, %ebx +mov 0x10000, %eax +mov 0x10000, %ax +mov 0x10000, %al +mov %al, 0x10000 + +mov $1, %edx +mov $1, %dx +mov $1, %cl +movb $2, 0x100(%ebx,%edx,2) +movw $2, 0x100(%ebx,%edx,2) +movl $2, 0x100(%ebx,%edx,2) +movl %eax, 0x100(%ebx,%edx,2) +movl 0x100(%ebx,%edx,2), %edx +movw %ax, 0x100(%ebx,%edx,2) + +movw $0x1122,%si +movl $0x112233,%edx +movl $0x80000000, %esi +movl $-0x7fffffff, %edi +#ifdef __x86_64__ +mov $0x11223344,%rbx +movq $0x11223344,%rbx +mov $0x1122334455,%rbx +movq $0x1122334455,%rbx +movl $0x11334455,(%rbx) +#endif + +mov %eax, 0x12(,%edx,2) + +#ifdef __i386__ +mov %cr3, %edx +mov %ecx, %cr3 +movl %cr3, %eax +movl %tr3, %eax +movl %db3, %ebx +movl %dr6, %eax +#else +mov %cr3, %rdx +mov %rcx, %cr3 +movq %cr3, %rax +movq %db3, %rbx +movq %dr6, %rax +mov %cr8, %rsi +mov %rdi, %cr8 +#endif +movl %fs, %ecx +movl %ebx, %fs + +#ifdef __x86_64__ +movq %r8, %r9 +movq %r10, %r11 +movq %r12, %r13 +movq %r14, %r15 +movq %rax, %r9 +movq %r15, %rsi +inc %r9b +dec %r10w +not %r11d +negq %r12 +decb %r13b +incw %r14w +notl %r15d +#endif + + movsbl 0x1000, %eax + movsbw 0x1000, %ax + movswl 0x1000, %eax + + movzbl 0x1000, %eax + movzbw 0x1000, %ax + movzwl 0x1000, %eax + + movzb 0x1000, %eax + movzb 0x1000, %ax + + mov $0x12345678,%eax + +#ifdef __x86_64__ + movzb 0x1000, %rax + movzbq 0x1000, %rbx + movsbq 0x1000, %rdx + movzwq 0x1000, %rdi + movswq 0x1000, %rdx + movslq %eax, %rcx + mov $0x12345678,%rax + mov $0x12345678,%rdx + mov $0x12345678,%r10 + mov $0x123456789abcdef0,%rax + mov $0x123456789abcdef0,%rcx + mov $0x123456789abcdef0,%r11 +#endif + +#ifdef __i386__ + pushl %eax + push %eax + push %cs +#else + pushq %rax + push %rax +#endif + pushw %ax + push %gs + push $1 + push $100 + push 0x42(%eax) + pop 0x43(%esi) + +#ifdef __i386__ + popl %eax + pop %eax + pop %ds +#else + popq %rax + pop %rax +#endif + popw %ax + pop %fs + + xchg %eax, %ecx + xchg %edx, %eax + xchg %bx, 0x10000 + xchg 0x10000, %ebx + xchg 0x10000, %dl + + in $100, %al + in $100, %ax + in $100, %eax + in %dx, %al + in %dx, %ax + in %dx, %eax + inb %dx + inw %dx + inl %dx + + out %al, $100 + out %ax, $100 + out %eax, $100 + + /* NOTE: gas is bugged here, so size must be added */ + outb %al, %dx + outw %ax, %dx + outl %eax, %dx + + leal 0x1000(%ebx), %ecx + lea 0x1000(%ebx), %ecx + +#ifdef __i386__ + les 0x2000, %eax + lds 0x2000, %ebx + lss 0x2000, %edx +#endif + lfs 0x2000, %ecx + lgs 0x2000, %edx + +addl $0x123, %eax +add $0x123, %ebx +add $-16, %ecx +add $-0x123, %esi +add $1, %bx +add $1, %ebx +add $-1, %bx +add $-1, %ebx +add $127, %bx +addl $127, %ebx +addl $-128, %ebx +addl $-128, %ebx +addl $-129, %ebx +addl $128, %ebx +addl $255, %ebx +addl $256, %ebx +andb $0xf, %ah +andb $-15, %cl +xorb $127, %dh +cmpb $42, (%eax) +addl $0x123, 0x100 +addl $0x123, 0x100(%ebx) +addl $0x123, 0x100(%ebx,%edx,2) +addl $0x123, 0x100(%esp) +addl $0x123, (3*8)(%esp) +addl $0x123, (%ebp) +addl $0x123, (%esp) +cmpl $0x123, (%esp) + +#ifdef __x86_64__ +xor %bl,%ah +xor %bl,%r8b +xor %r9b,%bl +xor %sil,%cl +add %eax,(%r8d) +add %ebx,(%r9) +add %edx,(%r10d,%r11d) +add %ecx,(%r12,%r13) +add %esi,(%r14,%r15,4) +add %edi,0x1000(%rbx,%r12,8) +add %r11,0x1000(%ebp,%r9d,8) +movb $12, %ah +movb $13, %bpl +movb $14, %dil +movb $15, %r12b +#endif + +add %eax, (%ebx) +add (%ebx), %eax + +or %dx, (%ebx) +or (%ebx), %si + +add %cl, (%ebx) +add (%ebx), %dl + + inc %edx + incl 0x10000 + incb 0x10000 + dec %dx + + test $1, %al + test $1, %cl + + testl $1, 0x1000 + testb $1, 0x1000 + testw $1, 0x1000 + test %eax, %ebx + test %eax, 0x1000 + test 0x1000, %edx + + not %edx + notw 0x10000 + notl 0x10000 + notb 0x10000 + + neg %edx + negw 0x10000 + negl 0x10000 + negb 0x10000 + + imul %ecx + mul %edx + mulb %cl + + imul %eax, %ecx + imul 0x1000, %cx + imul $10, %eax, %ecx + imul $10, %ax, %cx + imul $10, %eax + imul $0x1100000, %eax + imul $1, %eax + + idivw 0x1000 + div %ecx + div %bl + div %ecx, %eax + +and $15,%bx +and $-20,%edx + +shl %edx +shl $10, %edx +shl %cl, %edx + +shld $1, %eax, %edx +shld %cl, %eax, %edx +shld %eax, %edx + +shrd $1, %eax, %edx +shrd %cl, %eax, %edx +shrd %eax, %edx + +L4: +call 0x1000 +call L4 +#ifdef __i386__ +call *%eax +#else +call *%rax +#endif +call *0x1000 +call func1 + +.global L5,L6 + +L5: +L6: + +#ifdef __i386__ +lcall $0x100, $0x1000 +#else +lcall *0x100 +lcall *(%rax) +#endif + +jmp 0x1000 +jmp *(%edi) +#ifdef __i386__ +jmp *%eax +#else +jmp *%rax +#endif +jmp *0x1000 + +#ifdef __i386__ +ljmp $0x100, $0x1000 +#else +ljmp *0x100 +ljmp *(%rdi) +ljmpl *(%esi) +ljmpw *(%esi) +#endif + +ret +ret $10 +#ifdef __i386__ +retl +retl $10 +#else +retq +retq $10 +#endif + +lret + +lret $10 + +enter $1234, $10 + +L3: + jo 0x1000 + jnp 0x1001 + jne 0x1002 + jg 0x1003 + + jo L3 + jnp L3 + jne L3 + jg L3 + + loopne L3 + loopnz L3 + loope L3 + loopz L3 + loop L3 + jecxz L3 + + + seto %al + setc %al + setcb %al + setnp 0x1000 + setl 0xaaaa + setg %dl + + fadd + fadd %st(1), %st + fadd %st(0), %st(1) + fadd %st(3) + + fmul %st(0),%st(0) + fmul %st(0),%st(1) + + faddp %st(5) + faddp + faddp %st(1), %st + + fadds 0x1000 + fiadds 0x1002 + faddl 0x1004 + fiaddl 0x1006 + + fmul + fmul %st(1), %st + fmul %st(3) + + fmulp %st(5) + fmulp + fmulp %st(1), %st + + fmuls 0x1000 + fimuls 0x1002 + fmull 0x1004 + fimull 0x1006 + + fsub + fsub %st(1), %st + fsub %st(3) + + fsubp %st(5) + fsubp + fsubp %st(1), %st + + fsubs 0x1000 + fisubs 0x1002 + fsubl 0x1004 + fisubl 0x1006 + + fsubr + fsubr %st(1), %st + fsubr %st(3) + + fsubrp %st(5) + fsubrp + fsubrp %st(1), %st + + fsubrs 0x1000 + fisubrs 0x1002 + fsubrl 0x1004 + fisubrl 0x1006 + + fdiv + fdiv %st(1), %st + fdiv %st(3) + + fdivp %st(5) + fdivp + fdivp %st(1), %st + + fdivs 0x1000 + fidivs 0x1002 + fdivl 0x1004 + fidivl 0x1006 + + fcom %st(3) + + fcoms 0x1000 + ficoms 0x1002 + fcoml 0x1004 + ficoml 0x1006 + + fcomp %st(5) + fcomp + fcompp + + fcomps 0x1000 + ficomps 0x1002 + fcompl 0x1004 + ficompl 0x1006 + + fld %st(5) + fldl 0x1000 + flds 0x1002 + fildl 0x1004 + fst %st(4) + fstp %st(6) + fstpt 0x1006 + fbstp 0x1008 + + fxch + fxch %st(4) + + fucom %st(6) + fucomp %st(3) + fucompp + + finit + fninit + fldcw 0x1000 + fnstcw 0x1002 + fstcw 0x1002 + fnstsw 0x1004 + fnstsw (%eax) + fstsw 0x1004 + fstsw (%eax) + fnclex + fclex + fnstenv 0x1000 + fstenv 0x1000 + fldenv 0x1000 + fnsave 0x1002 + fsave 0x1000 + frstor 0x1000 + ffree %st(7) + ffreep %st(6) + + ftst + fxam + fld1 + fldl2t + fldl2e + fldpi + fldlg2 + fldln2 + fldz + + f2xm1 + fyl2x + fptan + fpatan + fxtract + fprem1 + fdecstp + fincstp + fprem + fyl2xp1 + fsqrt + fsincos + frndint + fscale + fsin + fcos + fchs + fabs + fnop + fwait + +bswap %edx +bswapl %ecx +xadd %ecx, %edx +xaddb %dl, 0x1000 +xaddw %ax, 0x1000 +xaddl %eax, 0x1000 +cmpxchg %ecx, %edx +cmpxchgb %dl, 0x1000 +cmpxchgw %ax, 0x1000 +cmpxchgl %eax, 0x1000 +invlpg 0x1000 +cmpxchg8b 0x1002 +#ifdef __x86_64__ +cmpxchg16b (%rax) +cmpxchg16b (%r10,%r11) +#endif + +fcmovb %st(5), %st +fcmove %st(5), %st +fcmovbe %st(5), %st +fcmovu %st(5), %st +fcmovnb %st(5), %st +fcmovne %st(5), %st +fcmovnbe %st(5), %st +fcmovnu %st(5), %st +fcomi %st(5), %st +fucomi %st(5), %st +fcomip %st(5), %st +fucomip %st(5), %st + + + + cmovo 0x1000, %eax + cmovs 0x1000, %eax + cmovns %edx, %edi + cmovne %ax, %si +#ifdef __x86_64__ + bswapq %rsi + bswapq %r10 + cmovz %rdi,%rbx +#endif + +int $3 +int $0x10 + +#ifdef __i386__ + pusha + popa +#endif + clc # another comment + cld # a comment with embedded ' tick + cli + clts + cmc + lahf + sahf +#ifdef __i386__ + pushfl + popfl +#else + pushfq + popfq +#endif + pushf + popf + stc + std + sti +#ifdef __i386__ + aaa + aas + daa + das + aad + aam + into +#endif + cbw + cwd + cwde + cdq + cbtw + cwtd + cwtl + cltd + leave + int3 + iret + rsm + hlt + wait + nop + + /* XXX: handle prefixes */ +#if 0 + aword + addr16 +#endif + lock + rep + repe + repz + repne + repnz + nop + + lock ;negl (%eax) + wait ;pushf + rep ;stosb + repe ;lodsb + repz ;cmpsb + repne;movsb + repnz;outsb + + /* handle one-line prefix + ops */ + lock negl (%eax) + wait pushf + rep stosb + repe lodsb + repz cmpsb + repne movsb + repnz outsb + + invd + wbinvd + cpuid + wrmsr + rdtsc + rdmsr + rdpmc + ud2 +#ifdef __x86_64__ + syscall + sysret + sysretq + lfence + mfence + sfence + prefetchnta 0x18(%rdx) + prefetcht0 (%rcx) + prefetcht1 (%rsi) + prefetcht2 (%rdi) + prefetchw (%rdi) + clflush 0x1000(%rax,%rcx) + fxsaveq (%rdx) + fxsaveq (%r11) + fxrstorq (%rcx) + fxrstorq (%r10) + +#endif + + lar %ax,%dx + lar %eax,%dx + lar %ax,%edx + lar %eax,%edx +#ifdef __x86_64__ + lar %ax,%rdx + lar %eax,%rdx +#endif + emms + movd %edx, %mm3 + movd 0x1000, %mm2 + movd %mm4, %ecx + movd %mm5, 0x1000 + + movq 0x1000, %mm2 + movq %mm4, 0x1000 + + pand 0x1000, %mm3 + pand %mm4, %mm5 + + psllw $1, %mm6 + psllw 0x1000, %mm7 + psllw %mm2, %mm7 + + xlat + cmpsb + scmpw + insl + outsw + lodsb + slodl + movsb + movsl + smovb + scasb + sscaw + stosw + sstol + + bsf 0x1000, %ebx + bsr 0x1000, %ebx + bt %edx, 0x1000 + btl $2, 0x1000 + btc %edx, 0x1000 + btcl $2, 0x1000 + btr %edx, 0x1000 + btrl $2, 0x1000 + bts %edx, 0x1000 + btsl $2, 0x1000 + + + +#ifdef __i386__ + boundl %edx, 0x10000 + boundw %bx, 0x1000 + + arpl %bx, 0x1000 +#endif + lar 0x1000, %eax + lgdt 0x1000 + lidt 0x1000 + lldt 0x1000 + sgdt 0x1000 + sidt 0x1000 + sldt 0x1000 +#ifdef __x86_64__ + lgdtq 0x1000 + lidtq 0x1000 + sgdtq 0x1000 + sidtq 0x1000 + + swapgs + + str %rdx + str %r9 +#endif + + lmsw 0x1000 + lsl 0x1000, %ecx + ltr 0x1000 + ltr %si + smsw 0x1000 + str 0x1000 + str %ecx + str %dx + + verr 0x1000 + verw 0x1000 + +#ifdef __i386__ + push %ds + pushw %ds + pushl %ds + pop %ds + popw %ds + popl %ds +#endif + fxsave 1(%ebx) + fxrstor 1(%ecx) +#ifdef __i386__ + pushl $1 +#else + pushq $1 +#endif + pushw $1 + push $1 + +#ifdef __ASSEMBLER__ // should be defined, for S files + inc %eax +#endif + +#ifndef _WIN32 +ft1: ft2: ft3: ft4: ft5: ft6: ft7: ft8: ft9: + xor %eax, %eax + ret + +.type ft1,STT_FUNC +.type ft2,@STT_FUNC +.type ft3,%STT_FUNC +.type ft4,"STT_FUNC" +.type ft5,function +.type ft6,@function +.type ft7,%function +.type ft8,"function" +#endif + + pause +.rept 6 + nop +.endr +.fill 4,1,0x90 + +.section .text.one,"ax" +nop +.previous +.pushsection .text.one,"ax" +nop +.pushsection .text.two,"ax" +nop +.popsection +.popsection + +1: ud2 +.pushsection __bug_table,"a" +.align 8 +2: .long 1b - 2b + .long 0x600000 - 2b + .long 1b + 42 + .long 43 + 1b + .long 2b + 144 + .long 145 + 2b + .word 164, 0 + .org 2b+32 +#ifdef __x86_64__ + .quad 1b +#else + .long 1b +#endif +.popsection +3: mov %eax,%ecx +4: +.pushsection .text.three, "ax" +nop +.skip (-((4b-3b) > 0) * 2) , 0x90 +.popsection + +.globl overrideme +.weak overrideme + nop +.globl notimplemented +notimplemented: + ret +.set overrideme, notimplemented +overrideme = notimplemented +overrideme: + ret + + movd %esi, %mm1 + movd %edi, %xmm2 + movd (%ebx), %mm3 + movd (%ebx), %xmm3 + movd %mm1, %esi + movd %xmm2, %edi + movd %mm3, (%edx) + movd %xmm3, (%edx) +#ifdef __x86_64__ + movd %rsi, %mm1 + movd %rdi, %xmm2 + movd (%rbx), %mm3 + movd (%rbx), %xmm3 + movd %mm1, %r12 + movd %xmm2, %rdi + movd %mm3, (%r8) + movd %xmm3, (%r13) +#endif + + movq (%ebp), %mm1 + movq %mm2, (%edi) + movq (%edi), %xmm3 + movq %mm4, %mm5 +#ifdef __x86_64__ + movq %rcx, %mm1 + movq %rdx, %xmm2 + movq %r13, %xmm3 + /* movq mem64->xmm is encoded as f30f7e by GAS, but as + 660f6e by tcc (which really is a movd and would need + a REX.W prefix to be movq). */ + movq (%rsi), %xmm3 + movq %mm1, %rdx + movq %xmm3, %rcx + movq %xmm4, (%rsi) +#endif + +#define TEST_MMX_SSE(insn) \ + insn %mm1, %mm2; \ + insn %xmm2, %xmm3; \ + insn (%ebx), %xmm3; +#define TEST_MMX_SSE_I8(insn) \ + TEST_MMX_SSE(insn) \ + insn $0x42, %mm4; \ + insn $0x42, %xmm4; + + TEST_MMX_SSE(packssdw) + TEST_MMX_SSE(packsswb) + TEST_MMX_SSE(packuswb) + TEST_MMX_SSE(paddb) + TEST_MMX_SSE(paddw) + TEST_MMX_SSE(paddd) + TEST_MMX_SSE(paddsb) + TEST_MMX_SSE(paddsw) + TEST_MMX_SSE(paddusb) + TEST_MMX_SSE(paddusw) + TEST_MMX_SSE(pand) + TEST_MMX_SSE(pandn) + TEST_MMX_SSE(pcmpeqb) + TEST_MMX_SSE(pcmpeqw) + TEST_MMX_SSE(pcmpeqd) + TEST_MMX_SSE(pcmpgtb) + TEST_MMX_SSE(pcmpgtw) + TEST_MMX_SSE(pcmpgtd) + TEST_MMX_SSE(pmaddwd) + TEST_MMX_SSE(pmulhw) + TEST_MMX_SSE(pmullw) + TEST_MMX_SSE(por) + TEST_MMX_SSE(psllw) +TEST_MMX_SSE_I8(psllw) + TEST_MMX_SSE(pslld) +TEST_MMX_SSE_I8(pslld) + TEST_MMX_SSE(psllq) +TEST_MMX_SSE_I8(psllq) + TEST_MMX_SSE(psraw) +TEST_MMX_SSE_I8(psraw) + TEST_MMX_SSE(psrad) +TEST_MMX_SSE_I8(psrad) + TEST_MMX_SSE(psrlw) +TEST_MMX_SSE_I8(psrlw) + TEST_MMX_SSE(psrld) +TEST_MMX_SSE_I8(psrld) + TEST_MMX_SSE(psrlq) +TEST_MMX_SSE_I8(psrlq) + TEST_MMX_SSE(psubb) + TEST_MMX_SSE(psubw) + TEST_MMX_SSE(psubd) + TEST_MMX_SSE(psubsb) + TEST_MMX_SSE(psubsw) + TEST_MMX_SSE(psubusb) + TEST_MMX_SSE(psubusw) + TEST_MMX_SSE(punpckhbw) + TEST_MMX_SSE(punpckhwd) + TEST_MMX_SSE(punpckhdq) + TEST_MMX_SSE(punpcklbw) + TEST_MMX_SSE(punpcklwd) + TEST_MMX_SSE(punpckldq) + TEST_MMX_SSE(pxor) + + cvtpi2ps %mm1, %xmm2 + cvtpi2ps (%ebx), %xmm2 + TEST_MMX_SSE(pmaxsw) + TEST_MMX_SSE(pmaxub) + TEST_MMX_SSE(pminsw) + TEST_MMX_SSE(pminub) diff --git a/tinyc/tests/boundtest.c b/tinyc/tests/boundtest.c new file mode 100644 index 000000000..15bffb4ed --- /dev/null +++ b/tinyc/tests/boundtest.c @@ -0,0 +1,285 @@ +#include +#include +#include + +#define NB_ITS 1000000 +//#define NB_ITS 1 +#define TAB_SIZE 100 + +int tab[TAB_SIZE]; +int ret_sum; +char tab3[256]; + +int test1(void) +{ + int i, sum = 0; + for(i=0;i= 2) + index = atoi(argv[1]) - 1; + + if ((index < 0) || (index >= index_max)) { + printf("N is outside of the valid range (%d)\n", index); + exit(2); + } + + /* well, we also use bounds on this ! */ + ftest = table_test[index]; + ftest(); + + return 0; +} + +/* + * without bound 0.77 s + * with bounds 4.73 + */ diff --git a/tinyc/tests/gcctestsuite.sh b/tinyc/tests/gcctestsuite.sh new file mode 100644 index 000000000..f3cc538de --- /dev/null +++ b/tinyc/tests/gcctestsuite.sh @@ -0,0 +1,33 @@ +#!/bin/sh + +TESTSUITE_PATH=$HOME/gcc/gcc-3.2/gcc/testsuite/gcc.c-torture +TCC="./tcc -B. -I. -DNO_TRAMPOLINES" +rm -f tcc.sum tcc.log +nb_failed="0" + +for src in $TESTSUITE_PATH/compile/*.c ; do + echo $TCC -o /tmp/test.o -c $src + $TCC -o /tmp/test.o -c $src >> tcc.log 2>&1 + if [ "$?" = "0" ] ; then + result="PASS" + else + result="FAIL" + nb_failed=$(( $nb_failed + 1 )) + fi + echo "$result: $src" >> tcc.sum +done + +for src in $TESTSUITE_PATH/execute/*.c ; do + echo $TCC $src + $TCC $src >> tcc.log 2>&1 + if [ "$?" = "0" ] ; then + result="PASS" + else + result="FAIL" + nb_failed=$(( $nb_failed + 1 )) + fi + echo "$result: $src" >> tcc.sum +done + +echo "$nb_failed test(s) failed." >> tcc.sum +echo "$nb_failed test(s) failed." diff --git a/tinyc/tests/libtcc_test.c b/tinyc/tests/libtcc_test.c new file mode 100644 index 000000000..480d31488 --- /dev/null +++ b/tinyc/tests/libtcc_test.c @@ -0,0 +1,96 @@ +/* + * Simple Test program for libtcc + * + * libtcc can be useful to use tcc as a "backend" for a code generator. + */ +#include +#include +#include + +#include "libtcc.h" + +/* this function is called by the generated code */ +int add(int a, int b) +{ + return a + b; +} + +/* this strinc is referenced by the generated code */ +const char hello[] = "Hello World!"; + +char my_program[] = +"#include \n" /* include the "Simple libc header for TCC" */ +"extern int add(int a, int b);\n" +"#ifdef _WIN32\n" /* dynamically linked data needs 'dllimport' */ +" __attribute__((dllimport))\n" +"#endif\n" +"extern const char hello[];\n" +"int fib(int n)\n" +"{\n" +" if (n <= 2)\n" +" return 1;\n" +" else\n" +" return fib(n-1) + fib(n-2);\n" +"}\n" +"\n" +"int foo(int n)\n" +"{\n" +" printf(\"%s\\n\", hello);\n" +" printf(\"fib(%d) = %d\\n\", n, fib(n));\n" +" printf(\"add(%d, %d) = %d\\n\", n, 2 * n, add(n, 2 * n));\n" +" return 0;\n" +"}\n"; + +int main(int argc, char **argv) +{ + TCCState *s; + int i; + int (*func)(int); + + s = tcc_new(); + if (!s) { + fprintf(stderr, "Could not create tcc state\n"); + exit(1); + } + + /* if tcclib.h and libtcc1.a are not installed, where can we find them */ + for (i = 1; i < argc; ++i) { + char *a = argv[i]; + if (a[0] == '-') { + if (a[1] == 'B') + tcc_set_lib_path(s, a+2); + else if (a[1] == 'I') + tcc_add_include_path(s, a+2); + else if (a[1] == 'L') + tcc_add_library_path(s, a+2); + } + } + + /* MUST BE CALLED before any compilation */ + tcc_set_output_type(s, TCC_OUTPUT_MEMORY); + + if (tcc_compile_string(s, my_program) == -1) + return 1; + + /* as a test, we add symbols that the compiled program can use. + You may also open a dll with tcc_add_dll() and use symbols from that */ + tcc_add_symbol(s, "add", add); + tcc_add_symbol(s, "hello", hello); + + /* relocate the code */ + if (tcc_relocate(s, TCC_RELOCATE_AUTO) < 0) + return 1; + + /* get entry symbol */ + func = tcc_get_symbol(s, "foo"); + if (!func) + return 1; + + /* run the code */ + func(32); + + /* delete the state */ + tcc_delete(s); + + return 0; +} diff --git a/tinyc/tests/pp/01.c b/tinyc/tests/pp/01.c new file mode 100644 index 000000000..2fc3d7960 --- /dev/null +++ b/tinyc/tests/pp/01.c @@ -0,0 +1,6 @@ +#define hash_hash # ## # +#define mkstr(a) # a +#define in_between(a) mkstr(a) +#define join(c, d) in_between(c hash_hash d) +char p[] = join(x, y); +// char p[] = "x ## y"; diff --git a/tinyc/tests/pp/01.expect b/tinyc/tests/pp/01.expect new file mode 100644 index 000000000..cf5b15340 --- /dev/null +++ b/tinyc/tests/pp/01.expect @@ -0,0 +1 @@ +char p[] = "x ## y"; diff --git a/tinyc/tests/pp/02.c b/tinyc/tests/pp/02.c new file mode 100644 index 000000000..feb1254e3 --- /dev/null +++ b/tinyc/tests/pp/02.c @@ -0,0 +1,28 @@ +#define x 3 +#define f(a) f(x * (a)) +#undef x +#define x 2 +#define g f +#define z z[0] +#define h g(~ +#define m(a) a(w) +#define w 0,1 +#define t(a) a +#define p() int +#define q(x) x +#define r(x,y) x ## y +#define str(x) # x +f(y+1) + f(f(z)) % t(t(g)(0) + t)(1); +g(x+(3,4)-w) | h 5) & m +(f)^m(m); +char c[2][6] = { str(hello), str() }; +/* + * f(2 * (y+1)) + f(2 * (f(2 * (z[0])))) % f(2 * (0)) + t(1); + * f(2 * (2+(3,4)-0,1)) | f(2 * (~ 5)) & f(2 * (0,1))^m(0,1); + * char c[2][6] = { "hello", "" }; + */ +#define L21 f(y+1) + f(f(z)) % t(t(g)(0) + t)(1); +#define L22 g(x+(3,4)-w) | h 5) & m\ +(f)^m(m); +L21 +L22 diff --git a/tinyc/tests/pp/02.expect b/tinyc/tests/pp/02.expect new file mode 100644 index 000000000..8ae2eb9ea --- /dev/null +++ b/tinyc/tests/pp/02.expect @@ -0,0 +1,5 @@ +f(2 * (y+1)) + f(2 * (f(2 * (z[0])))) % f(2 * (0)) + t(1); +f(2 * (2 +(3,4)-0,1)) | f(2 * (~ 5)) & f(2 * (0,1))^m(0,1); +char c[2][6] = { "hello", "" }; +f(2 * (y+1)) + f(2 * (f(2 * (z[0])))) % f(2 * (0)) + t(1); +f(2 * (2 +(3,4)-0,1)) | f(2 * (~ 5)) & f(2 * (0,1))^m(0,1); diff --git a/tinyc/tests/pp/03.c b/tinyc/tests/pp/03.c new file mode 100644 index 000000000..a659245ec --- /dev/null +++ b/tinyc/tests/pp/03.c @@ -0,0 +1,15 @@ +#define str(s) # s +#define xstr(s) str(s) +#define debug(s, t) printf("x" # s "= %d, x" # t "= %s", \ + x ## s, x ## t) +#define INCFILE(n) vers ## n +#define glue(a, b) a ## b +#define xglue(a, b) glue(a, b) +#define HIGHLOW "hello" +#define LOW LOW ", world" +debug(1, 2); +fputs(str(strncmp("abc\0d", "abc", '\4') // this goes away + == 0) str(: @\n), s); +\#include xstr(INCFILE(2).h) +glue(HIGH, LOW); +xglue(HIGH, LOW) diff --git a/tinyc/tests/pp/03.expect b/tinyc/tests/pp/03.expect new file mode 100644 index 000000000..44aad0ae1 --- /dev/null +++ b/tinyc/tests/pp/03.expect @@ -0,0 +1,5 @@ +printf("x" "1" "= %d, x" "2" "= %s", x1, x2); +fputs("strncmp(\"abc\\0d\", \"abc\", '\\4') == 0" ": @\n", s); +\#include "vers2.h" +"hello"; +"hello" ", world" diff --git a/tinyc/tests/pp/04.c b/tinyc/tests/pp/04.c new file mode 100644 index 000000000..0068f3751 --- /dev/null +++ b/tinyc/tests/pp/04.c @@ -0,0 +1,4 @@ +#define foobar 1 +#define C(x,y) x##y +#define D(x) (C(x,bar)) +D(foo) diff --git a/tinyc/tests/pp/04.expect b/tinyc/tests/pp/04.expect new file mode 100644 index 000000000..7c67b0104 --- /dev/null +++ b/tinyc/tests/pp/04.expect @@ -0,0 +1 @@ +(1) diff --git a/tinyc/tests/pp/05.c b/tinyc/tests/pp/05.c new file mode 100644 index 000000000..72749416c --- /dev/null +++ b/tinyc/tests/pp/05.c @@ -0,0 +1,7 @@ +#define t(x,y,z) x ## y ## z +#define xxx(s) int s[] = { t(1,2,3), t(,4,5), t(6,,7), t(8,9,), \ + t(10,,), t(,11,), t(,,12), t(,,) }; + +int j[] = { t(1,2,3), t(,4,5), t(6,,7), t(8,9,), + t(10,,), t(,11,), t(,,12), t(,,) }; +xxx(j) diff --git a/tinyc/tests/pp/05.expect b/tinyc/tests/pp/05.expect new file mode 100644 index 000000000..9f9be378f --- /dev/null +++ b/tinyc/tests/pp/05.expect @@ -0,0 +1,3 @@ +int j[] = { 123, 45, 67, 89, + 10, 11, 12, }; +int j[] = { 123, 45, 67, 89, 10, 11, 12, }; diff --git a/tinyc/tests/pp/06.c b/tinyc/tests/pp/06.c new file mode 100644 index 000000000..28cfddece --- /dev/null +++ b/tinyc/tests/pp/06.c @@ -0,0 +1,5 @@ +#define X(a,b, \ + c,d) \ + foo + +X(1,2,3,4) diff --git a/tinyc/tests/pp/06.expect b/tinyc/tests/pp/06.expect new file mode 100644 index 000000000..257cc5642 --- /dev/null +++ b/tinyc/tests/pp/06.expect @@ -0,0 +1 @@ +foo diff --git a/tinyc/tests/pp/07.c b/tinyc/tests/pp/07.c new file mode 100644 index 000000000..b22b22bbc --- /dev/null +++ b/tinyc/tests/pp/07.c @@ -0,0 +1,4 @@ +#define a() YES +#define b() a +b() +b()() diff --git a/tinyc/tests/pp/07.expect b/tinyc/tests/pp/07.expect new file mode 100644 index 000000000..ad0e20a66 --- /dev/null +++ b/tinyc/tests/pp/07.expect @@ -0,0 +1,2 @@ +a +YES diff --git a/tinyc/tests/pp/08.c b/tinyc/tests/pp/08.c new file mode 100644 index 000000000..93018e11f --- /dev/null +++ b/tinyc/tests/pp/08.c @@ -0,0 +1,4 @@ +// test macro expansion in arguments +#define s_pos s_s.s_pos +#define foo(x) (x) +foo(hej.s_pos) diff --git a/tinyc/tests/pp/08.expect b/tinyc/tests/pp/08.expect new file mode 100644 index 000000000..2b2e3eebd --- /dev/null +++ b/tinyc/tests/pp/08.expect @@ -0,0 +1 @@ +(hej.s_s.s_pos) diff --git a/tinyc/tests/pp/09.c b/tinyc/tests/pp/09.c new file mode 100644 index 000000000..315b297cd --- /dev/null +++ b/tinyc/tests/pp/09.c @@ -0,0 +1,4 @@ +#define C(a,b,c) a##b##c +#define N(x,y) C(x,_,y) +#define A_O aaaaoooo +N(A,O) diff --git a/tinyc/tests/pp/09.expect b/tinyc/tests/pp/09.expect new file mode 100644 index 000000000..adce0f95e --- /dev/null +++ b/tinyc/tests/pp/09.expect @@ -0,0 +1 @@ +aaaaoooo diff --git a/tinyc/tests/pp/10.c b/tinyc/tests/pp/10.c new file mode 100644 index 000000000..f180eff1e --- /dev/null +++ b/tinyc/tests/pp/10.c @@ -0,0 +1,10 @@ +#define f(x) x +#define g(x) f(x) f(x +#define i(x) g(x)) g(x +#define h(x) i(x))) i(x +#define k(x) i(x))) i(x)))) +f(x) +g(x)) +i(x))) +h(x)))) +k(x)))) diff --git a/tinyc/tests/pp/10.expect b/tinyc/tests/pp/10.expect new file mode 100644 index 000000000..bd18e18e5 --- /dev/null +++ b/tinyc/tests/pp/10.expect @@ -0,0 +1,5 @@ +x +x x +x x x x +x x x x x x x x +x x x x x x x x)))) diff --git a/tinyc/tests/pp/11.c b/tinyc/tests/pp/11.c new file mode 100644 index 000000000..c0edf629c --- /dev/null +++ b/tinyc/tests/pp/11.c @@ -0,0 +1,31 @@ +#define D1(s, ...) s +#define D2(s, ...) s D1(__VA_ARGS__) +#define D3(s, ...) s D2(__VA_ARGS__) +#define D4(s, ...) s D3(__VA_ARGS__) + +D1(a) +D2(a, b) +D3(a, b, c) +D4(a, b, c, d) + +x D4(a, b, c, d) y +x D4(a, b, c) y +x D4(a, b) y +x D4(a) y +x D4() y + +#define GNU_COMMA(X,Y...) X,## Y + +x GNU_COMMA(A,B,C) y +x GNU_COMMA(A,B) y +x GNU_COMMA(A) y +x GNU_COMMA() y + +#define __sun_attr___noreturn__ __attribute__((__noreturn__)) +#define ___sun_attr_inner(__a) __sun_attr_##__a +#define __sun_attr__(__a) ___sun_attr_inner __a +#define __NORETURN __sun_attr__((__noreturn__)) +__NORETURN +#define X(...) +#define Y(...) 1 __VA_ARGS__ 2 +Y(X X() ()) diff --git a/tinyc/tests/pp/11.expect b/tinyc/tests/pp/11.expect new file mode 100644 index 000000000..6b9806c6c --- /dev/null +++ b/tinyc/tests/pp/11.expect @@ -0,0 +1,15 @@ +a +a b +a b c +a b c d +x a b c d y +x a b c y +x a b y +x a y +x y +x A,B,C y +x A,B y +x A y +x y +__attribute__((__noreturn__)) +1 2 diff --git a/tinyc/tests/pp/12.S b/tinyc/tests/pp/12.S new file mode 100644 index 000000000..597ccb4cb --- /dev/null +++ b/tinyc/tests/pp/12.S @@ -0,0 +1,8 @@ +#define SRC(y...) \ + 9999: y; \ + .section __ex_table, "a"; \ + .long 9999b, 6001f ; \ + // .previous + + SRC(1: movw (%esi), %bx) +6001: diff --git a/tinyc/tests/pp/12.expect b/tinyc/tests/pp/12.expect new file mode 100644 index 000000000..17a861c25 --- /dev/null +++ b/tinyc/tests/pp/12.expect @@ -0,0 +1,2 @@ + 9999: 1: movw (%esi), %bx; .section __ex_table, "a"; .long 9999b, 6001f ; +6001: diff --git a/tinyc/tests/pp/13.S b/tinyc/tests/pp/13.S new file mode 100644 index 000000000..bf0b525f9 --- /dev/null +++ b/tinyc/tests/pp/13.S @@ -0,0 +1,6 @@ +# `modelist' label. Each video mode record looks like: +#ifdef AAA +# modelist' label. Each video mode record looks like: +#endif +.text +endtext: diff --git a/tinyc/tests/pp/13.expect b/tinyc/tests/pp/13.expect new file mode 100644 index 000000000..c7a32305f --- /dev/null +++ b/tinyc/tests/pp/13.expect @@ -0,0 +1,2 @@ +.text +endtext: diff --git a/tinyc/tests/pp/14.c b/tinyc/tests/pp/14.c new file mode 100644 index 000000000..e15468c5f --- /dev/null +++ b/tinyc/tests/pp/14.c @@ -0,0 +1,13 @@ +#define W Z +#define Z(X) W(X,2) +#define Y(X) Z(X) +#define X Y +return X(X(1)); + +#define P Q +#define Q(n) P(n,2) +return P(1); + +#define A (B * B) +#define B (A + A) +return A + B; diff --git a/tinyc/tests/pp/14.expect b/tinyc/tests/pp/14.expect new file mode 100644 index 000000000..37860440c --- /dev/null +++ b/tinyc/tests/pp/14.expect @@ -0,0 +1,3 @@ +return Z(Z(1,2),2); +return Q(1,2); +return ((A + A) * (A + A)) + ((B * B) + (B * B)); diff --git a/tinyc/tests/pp/15.c b/tinyc/tests/pp/15.c new file mode 100644 index 000000000..cf13f9a89 --- /dev/null +++ b/tinyc/tests/pp/15.c @@ -0,0 +1,18 @@ +// insert a space between two tokens if otherwise they +// would form a single token when read back + +#define n(x) x + +return (n(long)n(double))d; +return n(A)n(++)n(+)n(B); +return n(A)n(+)n(++)n(B); +return n(A)n(++)n(+)n(+)n(B); + +// not a hex float +return n(0x1E)n(-1); + +// unlike gcc but correct +// XXX: return n(x)+n(x)-n(1)+n(1)-2; + +// unlike gcc, but cannot appear in valid C +// XXX: return n(x)n(x)n(1)n(2)n(x); diff --git a/tinyc/tests/pp/15.expect b/tinyc/tests/pp/15.expect new file mode 100644 index 000000000..b4f885e95 --- /dev/null +++ b/tinyc/tests/pp/15.expect @@ -0,0 +1,5 @@ +return (long double)d; +return A+++B; +return A+ ++B; +return A+++ +B; +return 0x1E -1; diff --git a/tinyc/tests/pp/16.c b/tinyc/tests/pp/16.c new file mode 100644 index 000000000..8b5b6428c --- /dev/null +++ b/tinyc/tests/pp/16.c @@ -0,0 +1,3 @@ +/* The following should warn */ +#define A ... +#define A <<= diff --git a/tinyc/tests/pp/16.expect b/tinyc/tests/pp/16.expect new file mode 100644 index 000000000..695d6d41c --- /dev/null +++ b/tinyc/tests/pp/16.expect @@ -0,0 +1,2 @@ + +16.c:3: warning: A redefined diff --git a/tinyc/tests/pp/17.c b/tinyc/tests/pp/17.c new file mode 100644 index 000000000..f12196fe8 --- /dev/null +++ b/tinyc/tests/pp/17.c @@ -0,0 +1,14 @@ +#define STR1(u) # u +#define pass(a) a +#define __ASM_REG(reg) STR1(one##reg) +#define _ASM_DX __ASM_REG(tok) +X162 pass(__ASM_REG(tok)) +X161 pass(_ASM_DX) +X163 pass(STR1(one##tok)) + +X170 pass(x ## y) +X171 pass(x pass(##) y) + +#define Y(x) Z(x) +#define X Y +X180 return X(X(1)); diff --git a/tinyc/tests/pp/17.expect b/tinyc/tests/pp/17.expect new file mode 100644 index 000000000..e95aafef8 --- /dev/null +++ b/tinyc/tests/pp/17.expect @@ -0,0 +1,6 @@ +X162 "onetok" +X161 "onetok" +X163 "one##tok" +X170 x ## y +X171 x ## y +X180 return Z(Z(1)); diff --git a/tinyc/tests/pp/18.c b/tinyc/tests/pp/18.c new file mode 100644 index 000000000..0961426ac --- /dev/null +++ b/tinyc/tests/pp/18.c @@ -0,0 +1,15 @@ +#define M_RETI_ARG27(x,y,z,aa, ...) aa +#define M_RET_ARG27(...) M_RETI_ARG27(__VA_ARGS__) +#define M_COMMA_P(...) M_RET_ARG27(__VA_ARGS__, 1, 1, 0, useless) +#define M_EMPTYI_DETECT(...) 0, 1, +#define M_EMPTYI_P_C1(...) M_COMMA_P(M_EMPTYI_DETECT __VA_ARGS__ () ) +#define EX +#define empty(x) +#define fnlike(x) yeah x +/* If the following macro is called with empty arg (X183), the use + of 'x' between fnlike and '(' doesn't hinder the recognition of this + being a further fnlike macro invocation. */ +#define usefnlike(x) fnlike x (x) +X181 M_EMPTYI_P_C1() +X182 M_EMPTYI_P_C1(x) +X183 usefnlike() diff --git a/tinyc/tests/pp/18.expect b/tinyc/tests/pp/18.expect new file mode 100644 index 000000000..447a9b2ed --- /dev/null +++ b/tinyc/tests/pp/18.expect @@ -0,0 +1,3 @@ +X181 1 +X182 0 +X183 yeah diff --git a/tinyc/tests/pp/19.c b/tinyc/tests/pp/19.c new file mode 100644 index 000000000..aa91abe0d --- /dev/null +++ b/tinyc/tests/pp/19.c @@ -0,0 +1,101 @@ +#define M_C2I(a, ...) a ## __VA_ARGS__ +#define M_C(a, ...) M_C2I(a, __VA_ARGS__) +#define M_C3I(a, b, ...) a ## b ## __VA_ARGS__ +#define M_C3(a, b, ...) M_C3I(a ,b, __VA_ARGS__) + +#define M_RETI_ARG2(a, b, ...) b +#define M_RET_ARG2(...) M_RETI_ARG2(__VA_ARGS__) +#define M_RETI_ARG27(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,aa, ...) aa +#define M_RET_ARG27(...) M_RETI_ARG27(__VA_ARGS__) + +#define M_TOBOOLI_0 1, 0, +#define M_BOOL(x) M_RET_ARG2(M_C(M_TOBOOLI_, x), 1, useless) + +#define M_IFI_0(true_macro, ...) __VA_ARGS__ +#define M_IFI_1(true_macro, ...) true_macro +#define M_IF(c) M_C(M_IFI_, M_BOOL(c)) + +#define M_FLAT(...) __VA_ARGS__ +#define M_INVI_0 1 +#define M_INVI_1 0 +#define M_INV(x) M_C(M_INVI_, x) + +#define M_ANDI_00 0 +#define M_ANDI_01 0 +#define M_ANDI_10 0 +#define M_ANDI_11 1 +#define M_AND(x,y) M_C3(M_ANDI_, x, y) + +#define M_ORI_00 0 +#define M_ORI_01 1 +#define M_ORI_10 1 +#define M_ORI_11 1 +#define M_OR(x,y) M_C3(M_ORI_, x, y) + +#define M_COMMA_P(...) M_RET_ARG27(__VA_ARGS__, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, useless) + +#define M_EMPTYI_DETECT(...) 0, 1, +#define M_EMPTYI_P_C1(...) M_COMMA_P(M_EMPTYI_DETECT __VA_ARGS__ ()) +#define M_EMPTYI_P_C2(...) M_COMMA_P(M_EMPTYI_DETECT __VA_ARGS__) +#define M_EMPTYI_P_C3(...) M_COMMA_P(__VA_ARGS__ () ) +#define M_EMPTY_P(...) M_AND(M_EMPTYI_P_C1(__VA_ARGS__), M_INV(M_OR(M_OR(M_EMPTYI_P_C2(__VA_ARGS__), M_COMMA_P(__VA_ARGS__)),M_EMPTYI_P_C3(__VA_ARGS__)))) +#define M_APPLY_FUNC2B(func, arg1, arg2) \ + M_IF(M_EMPTY_P(arg2))(,func(arg1, arg2)) +#define M_MAP2B_0(func, data, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z,...) \ + M_APPLY_FUNC2B(func, data, a) M_APPLY_FUNC2B(func, data, b) M_APPLY_FUNC2B(func, data, c) \ + M_APPLY_FUNC2B(func, data, d) M_APPLY_FUNC2B(func, data, e) M_APPLY_FUNC2B(func, data, f) \ + M_APPLY_FUNC2B(func, data, g) M_APPLY_FUNC2B(func, data, h) M_APPLY_FUNC2B(func, data, i) \ + M_APPLY_FUNC2B(func, data, j) M_APPLY_FUNC2B(func, data, k) M_APPLY_FUNC2B(func, data, l) \ + M_APPLY_FUNC2B(func, data, m) M_APPLY_FUNC2B(func, data, n) M_APPLY_FUNC2B(func, data, o) \ + M_APPLY_FUNC2B(func, data, p) M_APPLY_FUNC2B(func, data, q) M_APPLY_FUNC2B(func, data, r) \ + M_APPLY_FUNC2B(func, data, s) M_APPLY_FUNC2B(func, data, t) M_APPLY_FUNC2B(func, data, u) \ + M_APPLY_FUNC2B(func, data, v) M_APPLY_FUNC2B(func, data, w) M_APPLY_FUNC2B(func, data, x) \ + M_APPLY_FUNC2B(func, data, y) M_APPLY_FUNC2B(func, data, z) +#define M_MAP2B(f, ...) M_MAP2B_0(f, __VA_ARGS__, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ) +#define M_INIT_INIT(a) ,a, + +#define M_GET_METHOD(method, method_default, ...) \ + M_RET_ARG2 (M_MAP2B(M_C, M_C3(M_, method, _), __VA_ARGS__), method_default,) + +#define M_TEST_METHOD_P(method, oplist) \ + M_BOOL(M_GET_METHOD (method, 0, M_FLAT oplist)) + +#define TRUE 1 +#define TEST1(n) \ + M_IF(n)(ok,nok) +#define TEST2(op) \ + M_TEST_METHOD_P(INIT, op) +#define TEST3(op) \ + M_IF(M_TEST_METHOD_P(INIT, op))(ok, nok) +#define TEST4(op) \ + TEST1(TEST2(op)) +#define KO(a) ((void)1) + +/* This checks that the various expansions that ultimately lead to + something like 'KO(arg,arg)', where 'KO' comes from a macro + expansion reducing from a large macro chain do not are regarded + as funclike macro invocation of KO. E.g. X93 and X94 expand to 'KO', + but X95 must not consume the (a,b) arguments outside the M_IF() + invocation to reduce the 'KO' macro to an invocation. Instead + X95 should reduce via M_IF(KO)(a,b) to 'a'. + + The other lines here are variations on this scheme, with X1 to + X6 coming from the bug report at + http://lists.nongnu.org/archive/html/tinycc-devel/2017-07/msg00017.html */ +X92 M_IF(KO) +X93 M_GET_METHOD(INIT, 0, INIT(KO)) +X94 M_GET_METHOD(INIT, 0, M_FLAT (INIT(KO))) +X95 M_IF(M_GET_METHOD(INIT, 0, INIT(KO)))(a,b) +X96 M_IF(M_GET_METHOD(INIT, 0, M_FLAT (INIT(KO)))) +X97 M_IF(M_GET_METHOD(INIT, 0, M_FLAT (INIT(KO))))(ok,nok) +X98 (M_TEST_METHOD_P(INIT, (INIT(KO))))(ok, nok) +X99 M_IF(M_TEST_METHOD_P(INIT, (INIT(KO))))(ok, nok) +// test begins +X1 TEST1(TRUE) // ==> expect ok, get ok +// First test with a token which is not a macro +X2 TEST2((INIT(ok))) // ==> expect 1, get 1 +X3 TEST3((INIT(ok))) // ==> expect ok, get ok +// Then test with a token which is a macro, but should not be expanded. +X4 TEST2((INIT(KO))) // ==> expect 1, get 1 +X5 TEST4(INIT(KO)) +X6 TEST3((INIT(KO))) // ==> expect ok, get "error: macro 'KO' used with too many args" diff --git a/tinyc/tests/pp/19.expect b/tinyc/tests/pp/19.expect new file mode 100644 index 000000000..08c08581e --- /dev/null +++ b/tinyc/tests/pp/19.expect @@ -0,0 +1,14 @@ +X92 M_IFI_1 +X93 KO +X94 KO +X95 a +X96 M_IFI_1 +X97 ok +X98 (1)(ok, nok) +X99 ok +X1 ok +X2 1 +X3 ok +X4 1 +X5 nok +X6 ok diff --git a/tinyc/tests/pp/20.c b/tinyc/tests/pp/20.c new file mode 100644 index 000000000..7944d62bc --- /dev/null +++ b/tinyc/tests/pp/20.c @@ -0,0 +1,13 @@ +/* Various things I encountered while hacking the pre processor */ +#define wrap(x) x +#define pr_warning(fmt, ...) printk(KERN_WARNING fmt, ##__VA_ARGS__) +#define pr_warn(x,y) pr_warning(x,y) +#define net_ratelimited_function(function, ...) function(__VA_ARGS__) +X1 net_ratelimited_function(pr_warn, "pipapo", bla); +X2 net_ratelimited_function(wrap(pr_warn), "bla", foo); +#define two m n +#define chain4(a,b,c,d) a ## b ## c ## d +X2 chain4(two,o,p,q) +X3 chain4(o,two,p,q) +X4 chain4(o,p,two,q) +X5 chain4(o,p,q,two) diff --git a/tinyc/tests/pp/20.expect b/tinyc/tests/pp/20.expect new file mode 100644 index 000000000..d19405d74 --- /dev/null +++ b/tinyc/tests/pp/20.expect @@ -0,0 +1,6 @@ +X1 printk(KERN_WARNING "pipapo",bla); +X2 printk(KERN_WARNING "bla",foo); +X2 twoopq +X3 otwopq +X4 optwoq +X5 opqtwo diff --git a/tinyc/tests/pp/21.c b/tinyc/tests/pp/21.c new file mode 100644 index 000000000..1316226a2 --- /dev/null +++ b/tinyc/tests/pp/21.c @@ -0,0 +1,36 @@ +/* accept 'defined' as result of substitution */ + +----- 1 ------ +#define AAA 2 +#define BBB +#define CCC (defined ( AAA ) && AAA > 1 && !defined BBB) +#if !CCC +OK +#else +NOT OK +#endif + +----- 2 ------ +#undef BBB +#if CCC +OK +#else +NOT OK +#endif + +----- 3 ------ +#define DEFINED defined +#define DDD (DEFINED ( AAA ) && AAA > 1 && !DEFINED BBB) +#if (DDD) +OK +#else +NOT OK +#endif + +----- 4 ------ +#undef AAA +#if !(DDD) +OK +#else +NOT OK +#endif diff --git a/tinyc/tests/pp/21.expect b/tinyc/tests/pp/21.expect new file mode 100644 index 000000000..5a1376bb1 --- /dev/null +++ b/tinyc/tests/pp/21.expect @@ -0,0 +1,8 @@ +----- 1 ------ +OK +----- 2 ------ +OK +----- 3 ------ +OK +----- 4 ------ +OK diff --git a/tinyc/tests/pp/pp-counter.c b/tinyc/tests/pp/pp-counter.c new file mode 100644 index 000000000..3978e1a7e --- /dev/null +++ b/tinyc/tests/pp/pp-counter.c @@ -0,0 +1,27 @@ +X1 __COUNTER__ +X2 __COUNTER__ +#if __COUNTER__ +X3 __COUNTER__ +#endif +#define pass(x) x +#define a x __COUNTER__ y +#define a2 pass(__COUNTER__) +#define f(c) c __COUNTER__ +#define apply(d) d d __COUNTER__ x2 f(d) y2 __COUNTER__ +#define _paste(a,b) a ## b +#define paste(a,b) _paste(a,b) +#define _paste3(a,b,c) a ## b ## c +#define doublepaste(a,b) _paste3(a,b,b) +#define str(x) #x +X4 a +X5 f(a) +X6 f(b) +X7 f(__COUNTER__) +X8 apply(a) +X9 apply(f(a)) +X10 apply(__COUNTER__) +X11 apply(a2) +X12 str(__COUNTER__) +X13 paste(x,__COUNTER__) +X14 _paste(x,__COUNTER__) +X15 doublepaste(x,__COUNTER__) diff --git a/tinyc/tests/pp/pp-counter.expect b/tinyc/tests/pp/pp-counter.expect new file mode 100644 index 000000000..02fc535bc --- /dev/null +++ b/tinyc/tests/pp/pp-counter.expect @@ -0,0 +1,15 @@ +X1 0 +X2 1 +X3 3 +X4 x 4 y +X5 x 5 y 6 +X6 b 7 +X7 8 9 +X8 x 10 y x 10 y 11 x2 x 10 y 12 y2 13 +X9 x 14 y 15 x 14 y 15 16 x2 x 14 y 15 17 y2 18 +X10 19 19 20 x2 19 21 y2 22 +X11 23 23 24 x2 23 25 y2 26 +X12 "__COUNTER__" +X13 x27 +X14 x__COUNTER__ +X15 x2828 diff --git a/tinyc/tests/tcctest.c b/tinyc/tests/tcctest.c new file mode 100644 index 000000000..099fc3544 --- /dev/null +++ b/tinyc/tests/tcctest.c @@ -0,0 +1,3813 @@ +/* + * TCC auto test program + */ +#include "config.h" + +#if GCC_MAJOR >= 3 + +/* Unfortunately, gcc version < 3 does not handle that! */ +#define ALL_ISOC99 + +/* only gcc 3 handles _Bool correctly */ +#define BOOL_ISOC99 + +/* gcc 2.95.3 does not handle correctly CR in strings or after strays */ +#define CORRECT_CR_HANDLING + +#endif + +#if defined(_WIN32) +#define LONG_LONG_FORMAT "%lld" +#define ULONG_LONG_FORMAT "%llu" +#else +#define LONG_LONG_FORMAT "%Ld" +#define ULONG_LONG_FORMAT "%Lu" +#endif + +// MinGW has 80-bit rather than 64-bit long double which isn't compatible with TCC or MSVC +#if defined(_WIN32) && defined(__GNUC__) +#define LONG_DOUBLE double +#define LONG_DOUBLE_LITERAL(x) x +#else +#define LONG_DOUBLE long double +#define LONG_DOUBLE_LITERAL(x) x ## L +#endif + +/* deprecated and no longer supported in gcc 3.3 */ +//#define ACCEPT_CR_IN_STRINGS + +/* __VA_ARGS__ and __func__ support */ +#define C99_MACROS + +/* test various include syntaxes */ + +#define TCCLIB_INC +#define TCCLIB_INC1 +#define TCCLIB_INC3 "tcclib.h" + +#include TCCLIB_INC + +#include TCCLIB_INC1.TCCLIB_INC2 + +#include TCCLIB_INC1.h> + +#include TCCLIB_INC3 + +#include + +#include "tcclib.h" + +#include "tcctest.h" + +/* Test two more ways to include a file named like a pp-number */ +#define INC(name) +#define funnyname 42test.h +#define incdir tests/ +#define incname < incdir funnyname > +#define __stringify(x) #x +#define stringify(x) __stringify(x) +#include INC(42test) +#include incname +#include stringify(funnyname) + +void intdiv_test(); +void string_test(); +void expr_test(); +void macro_test(); +void recursive_macro_test(); +void scope_test(); +void forward_test(); +void funcptr_test(); +void loop_test(); +void switch_test(); +void goto_test(); +void enum_test(); +void typedef_test(); +void struct_test(); +void array_test(); +void expr_ptr_test(); +void bool_test(); +void optimize_out(); +void expr2_test(); +void constant_expr_test(); +void expr_cmp_test(); +void char_short_test(); +void init_test(void); +void compound_literal_test(void); +int kr_test(); +void struct_assign_test(void); +void cast_test(void); +void bitfield_test(void); +void c99_bool_test(void); +void float_test(void); +void longlong_test(void); +void manyarg_test(void); +void stdarg_test(void); +void whitespace_test(void); +void relocation_test(void); +void old_style_function(void); +void alloca_test(void); +void c99_vla_test(int size1, int size2); +void sizeof_test(void); +void typeof_test(void); +void local_label_test(void); +void statement_expr_test(void); +void asm_test(void); +void builtin_test(void); +void weak_test(void); +void global_data_test(void); +void cmp_comparison_test(void); +void math_cmp_test(void); +void callsave_test(void); +void builtin_frame_address_test(void); +void attrib_test(void); + +int fib(int n); +void num(int n); +void forward_ref(void); +int isid(int c); + +/* Line joining happens before tokenization, so the following + must be parsed as ellipsis. */ +void funny_line_continuation (int, ..\ +. ); + +char via_volatile (char); + +#define A 2 +#define N 1234 + A +#define pf printf +#define M1(a, b) (a) + (b) + +#define str\ +(s) # s +#define glue(a, b) a ## b +#define xglue(a, b) glue(a, b) +#define HIGHLOW "hello" +#define LOW LOW ", world" + +static int onetwothree = 123; +#define onetwothree4 onetwothree +#define onetwothree xglue(onetwothree,4) + +#define min(a, b) ((a) < (b) ? (a) : (b)) + +#ifdef C99_MACROS +#define dprintf(level,...) printf(__VA_ARGS__) +#endif + +/* gcc vararg macros */ +#define dprintf1(level, fmt, args...) printf(fmt, ## args) + +#define MACRO_NOARGS() + +#define AAA 3 +#undef AAA +#define AAA 4 + +#if 1 +#define B3 1 +#elif 1 +#define B3 2 +#elif 0 +#define B3 3 +#else +#define B3 4 +#endif + +#ifdef __TINYC__ +/* We try to handle this syntax. Make at least sure it doesn't segfault. */ +char invalid_function_def()[] {} +#endif + +#define __INT64_C(c) c ## LL +#define INT64_MIN (-__INT64_C(9223372036854775807)-1) + +int qq(int x) +{ + return x + 40; +} +#define qq(x) x + +#define spin_lock(lock) do { } while (0) +#define wq_spin_lock spin_lock +#define TEST2() wq_spin_lock(a) + +#define UINT_MAX ((unsigned) -1) + +void intdiv_test(void) +{ + printf("18/21=%u\n", 18/21); + printf("18%%21=%u\n", 18%21); + printf("41/21=%u\n", 41/21); + printf("41%%21=%u\n", 41%21); + printf("42/21=%u\n", 42/21); + printf("42%%21=%u\n", 42%21); + printf("43/21=%u\n", 43/21); + printf("43%%21=%u\n", 43%21); + printf("126/21=%u\n", 126/21); + printf("126%%21=%u\n", 126%21); + printf("131/21=%u\n", 131/21); + printf("131%%21=%u\n", 131%21); + printf("(UINT_MAX/2+3)/2=%u\n", (UINT_MAX/2+3)/2); + printf("(UINT_MAX/2+3)%%2=%u\n", (UINT_MAX/2+3)%2); + + printf("18/-21=%u\n", 18/-21); + printf("18%%-21=%u\n", 18%-21); + printf("41/-21=%u\n", 41/-21); + printf("41%%-21=%u\n", 41%-21); + printf("42/-21=%u\n", 42/-21); + printf("42%%-21=%u\n", 42%-21); + printf("43/-21=%u\n", 43/-21); + printf("43%%-21=%u\n", 43%-21); + printf("126/-21=%u\n", 126/-21); + printf("126%%-21=%u\n", 126%-21); + printf("131/-21=%u\n", 131/-21); + printf("131%%-21=%u\n", 131%-21); + printf("(UINT_MAX/2+3)/-2=%u\n", (UINT_MAX/2+3)/-2); + printf("(UINT_MAX/2+3)%%-2=%u\n", (UINT_MAX/2+3)%-2); + + printf("-18/21=%u\n", -18/21); + printf("-18%%21=%u\n", -18%21); + printf("-41/21=%u\n", -41/21); + printf("-41%%21=%u\n", -41%21); + printf("-42/21=%u\n", -42/21); + printf("-42%%21=%u\n", -42%21); + printf("-43/21=%u\n", -43/21); + printf("-43%%21=%u\n", -43%21); + printf("-126/21=%u\n", -126/21); + printf("-126%%21=%u\n", -126%21); + printf("-131/21=%u\n", -131/21); + printf("-131%%21=%u\n", -131%21); + printf("-(UINT_MAX/2+3)/2=%u\n", (0-(UINT_MAX/2+3))/2); + printf("-(UINT_MAX/2+3)%%2=%u\n", (0-(UINT_MAX/2+3))%2); + + printf("-18/-21=%u\n", -18/-21); + printf("-18%%-21=%u\n", -18%-21); + printf("-41/-21=%u\n", -41/-21); + printf("-41%%-21=%u\n", -41%-21); + printf("-42/-21=%u\n", -42/-21); + printf("-42%%-21=%u\n", -42%-21); + printf("-43/-21=%u\n", -43/-21); + printf("-43%%-21=%u\n", -43%-21); + printf("-126/-21=%u\n", -126/-21); + printf("-126%%-21=%u\n", -126%-21); + printf("-131/-21=%u\n", -131/-21); + printf("-131%%-21=%u\n", -131%-21); + printf("-(UINT_MAX/2+3)/-2=%u\n", (0-(UINT_MAX/2+3))/-2); + printf("-(UINT_MAX/2+3)%%-2=%u\n", (0-(UINT_MAX/2+3))%-2); +} + +void macro_test(void) +{ + printf("macro:\n"); + pf("N=%d\n", N); + printf("aaa=%d\n", AAA); + + printf("min=%d\n", min(1, min(2, -1))); + + printf("s1=%s\n", glue(HIGH, LOW)); + printf("s2=%s\n", xglue(HIGH, LOW)); + printf("s3=%s\n", str("c")); + printf("s4=%s\n", str(a1)); + printf("B3=%d\n", B3); + + printf("onetwothree=%d\n", onetwothree); + +#ifdef A + printf("A defined\n"); +#endif +#ifdef B + printf("B defined\n"); +#endif +#ifdef A + printf("A defined\n"); +#else + printf("A not defined\n"); +#endif +#ifdef B + printf("B defined\n"); +#else + printf("B not defined\n"); +#endif + +#ifdef A + printf("A defined\n"); +#ifdef B + printf("B1 defined\n"); +#else + printf("B1 not defined\n"); +#endif +#else + printf("A not defined\n"); +#ifdef B + printf("B2 defined\n"); +#else + printf("B2 not defined\n"); +#endif +#endif + +#if 1+1 + printf("test true1\n"); +#endif +#if 0 + printf("test true2\n"); +#endif +#if 1-1 + printf("test true3\n"); +#endif +#if defined(A) + printf("test trueA\n"); +#endif +#if defined(B) + printf("test trueB\n"); +#endif + +#if 0 + printf("test 0\n"); +#elif 0 + printf("test 1\n"); +#elif 2 + printf("test 2\n"); +#else + printf("test 3\n"); +#endif + + MACRO_NOARGS(); + +#ifdef __LINE__ + printf("__LINE__ defined\n"); +#endif + + printf("__LINE__=%d __FILE__=%s\n", + __LINE__, __FILE__); +#if 0 +#line 200 + printf("__LINE__=%d __FILE__=%s\n", + __LINE__, __FILE__); +#line 203 "test" + printf("__LINE__=%d __FILE__=%s\n", + __LINE__, __FILE__); +#line 227 "tcctest.c" +#endif + + /* not strictly preprocessor, but we test it there */ +#ifdef C99_MACROS + printf("__func__ = %s\n", __func__); + dprintf(1, "vaarg=%d\n", 1); +#endif + dprintf1(1, "vaarg1\n"); + dprintf1(1, "vaarg1=%d\n", 2); + dprintf1(1, "vaarg1=%d %d\n", 1, 2); + + /* gcc extension */ + printf("func='%s'\n", __FUNCTION__); + + /* complicated macros in glibc */ + printf("INT64_MIN=" LONG_LONG_FORMAT "\n", INT64_MIN); + { + int a; + a = 1; + glue(a+, +); + printf("a=%d\n", a); + glue(a <, <= 2); + printf("a=%d\n", a); + } + + /* macro function with argument outside the macro string */ +#define MF_s MF_hello +#define MF_hello(msg) printf("%s\n",msg) + +#define MF_t printf("tralala\n"); MF_hello + + MF_s("hi"); + MF_t("hi"); + + /* test macro substitution inside args (should not eat stream) */ + printf("qq=%d\n", qq(qq)(2)); + + /* test zero argument case. NOTE: gcc 2.95.x does not accept a + null argument without a space. gcc 3.2 fixes that. */ + +#define qq1(x) 1 + printf("qq1=%d\n", qq1( )); + + /* comment with stray handling *\ +/ + /* this is a valid *\/ comment */ + /* this is a valid comment *\*/ + // this is a valid\ +comment + + /* test function macro substitution when the function name is + substituted */ + TEST2(); + + /* And again when the name and parentheses are separated by a + comment. */ + TEST2 /* the comment */ (); + + printf("%s\n", get_basefile_from_header()); + printf("%s\n", __BASE_FILE__); + printf("%s\n", get_file_from_header()); + printf("%s\n", __FILE__); + + /* Check that funnily named include was in fact included */ + have_included_42test_h = 1; + have_included_42test_h_second = 1; + have_included_42test_h_third = 1; +} + + +static void print_num(char *fn, int line, int num) { + printf("fn %s, line %d, num %d\n", fn, line, num); +} + +void recursive_macro_test(void) +{ + +#define ELF32_ST_TYPE(val) ((val) & 0xf) +#define ELF32_ST_INFO(bind, type) (((bind) << 4) + ((type) & 0xf)) +#define STB_WEAK 2 /* Weak symbol */ +#define ELFW(type) ELF##32##_##type + printf("%d\n", ELFW(ST_INFO)(STB_WEAK, ELFW(ST_TYPE)(123))); + +#define WRAP(x) x + +#define print_num(x) print_num(__FILE__,__LINE__,x) + print_num(123); + WRAP(print_num(123)); + WRAP(WRAP(print_num(123))); + +static struct recursive_macro { int rm_field; } G; +#define rm_field (G.rm_field) + printf("rm_field = %d\n", rm_field); + printf("rm_field = %d\n", WRAP(rm_field)); + WRAP((printf("rm_field = %d %d\n", rm_field, WRAP(rm_field)))); +} + +int op(a,b) +{ + return a / b; +} + +int ret(a) +{ + if (a == 2) + return 1; + if (a == 3) + return 2; + return 0; +} + +void ps(const char *s) +{ + int c; + while (1) { + c = *s; + if (c == 0) + break; + printf("%c", c); + s++; + } +} + +const char foo1_string[] = "\ +bar\n\ +test\14\ +1"; + +void string_test() +{ + unsigned int b; + printf("string:\n"); + printf("\141\1423\143\n");/* dezdez test */ + printf("\x41\x42\x43\x3a\n"); + printf("c=%c\n", 'r'); + printf("wc=%C 0x%lx %C\n", L'a', L'\x1234', L'c'); + printf("foo1_string='%s'\n", foo1_string); +#if 0 + printf("wstring=%S\n", L"abc"); + printf("wstring=%S\n", L"abc" L"def" "ghi"); + printf("'\\377'=%d '\\xff'=%d\n", '\377', '\xff'); + printf("L'\\377'=%d L'\\xff'=%d\n", L'\377', L'\xff'); +#endif + ps("test\n"); + b = 32; + while ((b = b + 1) < 96) { + printf("%c", b); + } + printf("\n"); + printf("fib=%d\n", fib(33)); + b = 262144; + while (b != 0x80000000) { + num(b); + b = b * 2; + } +} + +void loop_test() +{ + int i; + i = 0; + while (i < 10) + printf("%d", i++); + printf("\n"); + for(i = 0; i < 10;i++) + printf("%d", i); + printf("\n"); + i = 0; + do { + printf("%d", i++); + } while (i < 10); + printf("\n"); + + char count = 123; + /* c99 for loop init test */ + for (size_t count = 1; count < 3; count++) + printf("count=%d\n", count); + printf("count = %d\n", count); + + /* break/continue tests */ + i = 0; + while (1) { + if (i == 6) + break; + i++; + if (i == 3) + continue; + printf("%d", i); + } + printf("\n"); + + /* break/continue tests */ + i = 0; + do { + if (i == 6) + break; + i++; + if (i == 3) + continue; + printf("%d", i); + } while(1); + printf("\n"); + + for(i = 0;i < 10;i++) { + if (i == 3) + continue; + printf("%d", i); + } + printf("\n"); +} + +typedef int typedef_and_label; + +void goto_test() +{ + int i; + static void *label_table[3] = { &&label1, &&label2, &&label3 }; + + printf("goto:\n"); + i = 0; + /* This needs to parse as label, not as start of decl. */ + typedef_and_label: + s_loop: + if (i >= 10) + goto s_end; + printf("%d", i); + i++; + goto s_loop; + s_end: + printf("\n"); + + /* we also test computed gotos (GCC extension) */ + for(i=0;i<3;i++) { + goto *label_table[i]; + label1: + printf("label1\n"); + goto next; + label2: + printf("label2\n"); + goto next; + label3: + printf("label3\n"); + next: ; + } +} + +enum { + E0, + E1 = 2, + E2 = 4, + E3, + E4, +}; + +enum test { + E5 = 1000, +}; + +struct S_enum { + enum {E6 = 42, E7, E8} e:8; +}; + +enum ELong { + /* This is either 0 on L32 machines, or a large number + on L64 machines. We should be able to store this. */ + EL_large = ((unsigned long)0xf000 << 31) << 1, +}; + +enum { BIASU = -1U<<31 }; +enum { BIASS = -1 << 31 }; + +static int getint(int i) +{ + if (i) + return 0; + else + return (int)(-1U << 31); +} + +void enum_test() +{ + enum test b1; + /* The following should give no warning */ + unsigned *p = &b1; + struct S_enum s = {E7}; + printf("enum: %d\n", s.e); + printf("enum:\n%d %d %d %d %d %d\n", + E0, E1, E2, E3, E4, E5); + b1 = 1; + printf("b1=%d\n", b1); + printf("enum large: %ld\n", EL_large); + + if (getint(0) == BIASU) + printf("enum unsigned: ok\n"); + else + printf("enum unsigned: wrong\n"); + if (getint(0) == BIASS) + printf("enum unsigned: ok\n"); + else + printf("enum unsigned: wrong\n"); +} + +typedef int *my_ptr; + +typedef int mytype1; +typedef int mytype2; + +void typedef_test() +{ + my_ptr a; + mytype1 mytype2; + int b; + + a = &b; + *a = 1234; + printf("typedef:\n"); + printf("a=%d\n", *a); + mytype2 = 2; + printf("mytype2=%d\n", mytype2); +} + +void forward_test() +{ + printf("forward:\n"); + forward_ref(); + forward_ref(); +} + + +void forward_ref(void) +{ + printf("forward ok\n"); +} + +typedef struct struct1 { + int f1; + int f2, f3; + union union1 { + int v1; + int v2; + } u; + char str[3]; +} struct1; + +struct struct2 { + int a; + char b; +}; + +union union2 { + int w1; + int w2; +}; + +struct struct1 st1, st2; + +struct empty_mem { + /* nothing */ ; + int x; +}; + +int main(int argc, char **argv) +{ + string_test(); + expr_test(); + macro_test(); + recursive_macro_test(); + scope_test(); + forward_test(); + funcptr_test(); + loop_test(); + switch_test(); + goto_test(); + enum_test(); + typedef_test(); + struct_test(); + array_test(); + expr_ptr_test(); + bool_test(); + optimize_out(); + expr2_test(); + constant_expr_test(); + expr_cmp_test(); + char_short_test(); + init_test(); + compound_literal_test(); + kr_test(); + struct_assign_test(); + cast_test(); + bitfield_test(); + c99_bool_test(); + float_test(); + longlong_test(); + manyarg_test(); + stdarg_test(); + whitespace_test(); + relocation_test(); + old_style_function(); + alloca_test(); + c99_vla_test(5, 2); + sizeof_test(); + typeof_test(); + statement_expr_test(); + local_label_test(); + asm_test(); + builtin_test(); +#ifndef _WIN32 + weak_test(); +#endif + global_data_test(); + cmp_comparison_test(); + math_cmp_test(); + callsave_test(); + builtin_frame_address_test(); + intdiv_test(); + if (via_volatile (42) != 42) + printf ("via_volatile broken\n"); + attrib_test(); + return 0; +} + +int tab[3]; +int tab2[3][2]; + +int g; + +void f1(g) +{ + printf("g1=%d\n", g); +} + +void scope_test() +{ + printf("scope:\n"); + g = 2; + f1(1); + printf("g2=%d\n", g); + { + int g; + g = 3; + printf("g3=%d\n", g); + { + int g; + g = 4; + printf("g4=%d\n", g); + } + } + printf("g5=%d\n", g); +} + +void array_test() +{ + int i, j, a[4]; + + printf("array:\n"); + printf("sizeof(a) = %d\n", sizeof(a)); + printf("sizeof(\"a\") = %d\n", sizeof("a")); +#ifdef C99_MACROS + printf("sizeof(__func__) = %d\n", sizeof(__func__)); +#endif + printf("sizeof tab %d\n", sizeof(tab)); + printf("sizeof tab2 %d\n", sizeof tab2); + tab[0] = 1; + tab[1] = 2; + tab[2] = 3; + printf("%d %d %d\n", tab[0], tab[1], tab[2]); + for(i=0;i<3;i++) + for(j=0;j<2;j++) + tab2[i][j] = 10 * i + j; + for(i=0;i<3*2;i++) { + printf(" %3d", ((int *)tab2)[i]); + } + printf("\n"); + printf("sizeof(size_t)=%d\n", sizeof(size_t)); + printf("sizeof(ptrdiff_t)=%d\n", sizeof(ptrdiff_t)); +} + +void expr_test() +{ + int a, b; + a = 0; + printf("%d\n", a += 1); + printf("%d\n", a -= 2); + printf("%d\n", a *= 31232132); + printf("%d\n", a /= 4); + printf("%d\n", a %= 20); + printf("%d\n", a &= 6); + printf("%d\n", a ^= 7); + printf("%d\n", a |= 8); + printf("%d\n", a >>= 3); + printf("%d\n", a <<= 4); + + a = 22321; + b = -22321; + printf("%d\n", a + 1); + printf("%d\n", a - 2); + printf("%d\n", a * 312); + printf("%d\n", a / 4); + printf("%d\n", b / 4); + printf("%d\n", (unsigned)b / 4); + printf("%d\n", a % 20); + printf("%d\n", b % 20); + printf("%d\n", (unsigned)b % 20); + printf("%d\n", a & 6); + printf("%d\n", a ^ 7); + printf("%d\n", a | 8); + printf("%d\n", a >> 3); + printf("%d\n", b >> 3); + printf("%d\n", (unsigned)b >> 3); + printf("%d\n", a << 4); + printf("%d\n", ~a); + printf("%d\n", -a); + printf("%d\n", +a); + + printf("%d\n", 12 + 1); + printf("%d\n", 12 - 2); + printf("%d\n", 12 * 312); + printf("%d\n", 12 / 4); + printf("%d\n", 12 % 20); + printf("%d\n", 12 & 6); + printf("%d\n", 12 ^ 7); + printf("%d\n", 12 | 8); + printf("%d\n", 12 >> 2); + printf("%d\n", 12 << 4); + printf("%d\n", ~12); + printf("%d\n", -12); + printf("%d\n", +12); + printf("%d %d %d %d\n", + isid('a'), + isid('g'), + isid('T'), + isid('(')); +} + +int isid(int c) +{ + return (c >= 'a' & c <= 'z') | (c >= 'A' & c <= 'Z') | c == '_'; +} + +/**********************/ + +int vstack[10], *vstack_ptr; + +void vpush(int vt, int vc) +{ + *vstack_ptr++ = vt; + *vstack_ptr++ = vc; +} + +void vpop(int *ft, int *fc) +{ + *fc = *--vstack_ptr; + *ft = *--vstack_ptr; +} + +void expr2_test() +{ + int a, b; + + printf("expr2:\n"); + vstack_ptr = vstack; + vpush(1432432, 2); + vstack_ptr[-2] &= ~0xffffff80; + vpop(&a, &b); + printf("res= %d %d\n", a, b); +} + +void constant_expr_test() +{ + int a; + printf("constant_expr:\n"); + a = 3; + printf("%d\n", a * 16); + printf("%d\n", a * 1); + printf("%d\n", a + 0); +} + +int tab4[10]; + +void expr_ptr_test() +{ + int *p, *q; + int i = -1; + + printf("expr_ptr:\n"); + p = tab4; + q = tab4 + 10; + printf("diff=%d\n", q - p); + p++; + printf("inc=%d\n", p - tab4); + p--; + printf("dec=%d\n", p - tab4); + ++p; + printf("inc=%d\n", p - tab4); + --p; + printf("dec=%d\n", p - tab4); + printf("add=%d\n", p + 3 - tab4); + printf("add=%d\n", 3 + p - tab4); + + /* check if 64bit support is ok */ + q = p = 0; + q += i; + printf("%p %p %ld\n", q, p, p-q); + printf("%d %d %d %d %d %d\n", + p == q, p != q, p < q, p <= q, p >= q, p > q); + i = 0xf0000000; + p += i; + printf("%p %p %ld\n", q, p, p-q); + printf("%d %d %d %d %d %d\n", + p == q, p != q, p < q, p <= q, p >= q, p > q); + p = (int *)((char *)p + 0xf0000000); + printf("%p %p %ld\n", q, p, p-q); + printf("%d %d %d %d %d %d\n", + p == q, p != q, p < q, p <= q, p >= q, p > q); + p += 0xf0000000; + printf("%p %p %ld\n", q, p, p-q); + printf("%d %d %d %d %d %d\n", + p == q, p != q, p < q, p <= q, p >= q, p > q); + { + struct size12 { + int i, j, k; + }; + struct size12 s[2], *sp = s; + int i, j; + sp->i = 42; + sp++; + j = -1; + printf("%d\n", sp[j].i); + } +#ifdef __LP64__ + i = 1; + p = (int*)0x100000000UL + i; + i = ((long)p) >> 32; + printf("largeptr: %p %d\n", p, i); +#endif +} + +void expr_cmp_test() +{ + int a, b; + printf("constant_expr:\n"); + a = -1; + b = 1; + printf("%d\n", a == a); + printf("%d\n", a != a); + + printf("%d\n", a < b); + printf("%d\n", a <= b); + printf("%d\n", a <= a); + printf("%d\n", b >= a); + printf("%d\n", a >= a); + printf("%d\n", b > a); + + printf("%d\n", (unsigned)a < b); + printf("%d\n", (unsigned)a <= b); + printf("%d\n", (unsigned)a <= a); + printf("%d\n", (unsigned)b >= a); + printf("%d\n", (unsigned)a >= a); + printf("%d\n", (unsigned)b > a); +} + +struct empty { +}; + +struct aligntest1 { + char a[10]; +}; + +struct aligntest2 { + int a; + char b[10]; +}; + +struct aligntest3 { + double a, b; +}; + +struct aligntest4 { + double a[0]; +}; + +struct __attribute__((aligned(16))) aligntest5 +{ + int i; +}; +struct aligntest6 +{ + int i; +} __attribute__((aligned(16))); +struct aligntest7 +{ + int i; +}; +struct aligntest5 altest5[2]; +struct aligntest6 altest6[2]; +int pad1; +/* altest7 is correctly aligned to 16 bytes also with TCC, + but __alignof__ returns the wrong result (4) because we + can't store the alignment yet when specified on symbols + directly (it's stored in the type so we'd need to make + a copy of it). -- FIXED */ +struct aligntest7 altest7[2] __attribute__((aligned(16))); + +struct aligntest8 +{ + int i; +} __attribute__((aligned(4096))); + +struct Large { + unsigned long flags; + union { + void *u1; + int *u2; + }; + + struct { + union { + unsigned long index; + void *freelist; + }; + union { + unsigned long counters; + struct { + int bla; + }; + }; + }; + + union { + struct { + long u3; + long u4; + }; + void *u5; + struct { + unsigned long compound_head; + unsigned int compound_dtor; + unsigned int compound_order; + }; + }; +} __attribute__((aligned(2 * sizeof(long)))); + +typedef unsigned long long __attribute__((aligned(4))) unaligned_u64; + +struct aligntest9 { + unsigned int buf_nr; + unaligned_u64 start_lba; +}; + +struct aligntest10 { + unsigned int buf_nr; + unsigned long long start_lba; +}; + +void struct_test() +{ + struct1 *s; + union union2 u; + struct Large ls; + + printf("struct:\n"); + printf("sizes: %d %d %d %d\n", + sizeof(struct struct1), + sizeof(struct struct2), + sizeof(union union1), + sizeof(union union2)); + printf("offsets: %d\n", (int)((char*)&st1.u.v1 - (char*)&st1)); + st1.f1 = 1; + st1.f2 = 2; + st1.f3 = 3; + printf("st1: %d %d %d\n", + st1.f1, st1.f2, st1.f3); + st1.u.v1 = 1; + st1.u.v2 = 2; + printf("union1: %d\n", st1.u.v1); + u.w1 = 1; + u.w2 = 2; + printf("union2: %d\n", u.w1); + s = &st2; + s->f1 = 3; + s->f2 = 2; + s->f3 = 1; + printf("st2: %d %d %d\n", + s->f1, s->f2, s->f3); + printf("str_addr=%x\n", (int)st1.str - (int)&st1.f1); + + /* align / size tests */ + printf("aligntest1 sizeof=%d alignof=%d\n", + sizeof(struct aligntest1), __alignof__(struct aligntest1)); + printf("aligntest2 sizeof=%d alignof=%d\n", + sizeof(struct aligntest2), __alignof__(struct aligntest2)); + printf("aligntest3 sizeof=%d alignof=%d\n", + sizeof(struct aligntest3), __alignof__(struct aligntest3)); + printf("aligntest4 sizeof=%d alignof=%d\n", + sizeof(struct aligntest4), __alignof__(struct aligntest4)); + printf("aligntest5 sizeof=%d alignof=%d\n", + sizeof(struct aligntest5), __alignof__(struct aligntest5)); + printf("aligntest6 sizeof=%d alignof=%d\n", + sizeof(struct aligntest6), __alignof__(struct aligntest6)); + printf("aligntest7 sizeof=%d alignof=%d\n", + sizeof(struct aligntest7), __alignof__(struct aligntest7)); + printf("aligntest8 sizeof=%d alignof=%d\n", + sizeof(struct aligntest8), __alignof__(struct aligntest8)); + printf("aligntest9 sizeof=%d alignof=%d\n", + sizeof(struct aligntest9), __alignof__(struct aligntest9)); + printf("aligntest10 sizeof=%d alignof=%d\n", + sizeof(struct aligntest10), __alignof__(struct aligntest10)); + printf("altest5 sizeof=%d alignof=%d\n", + sizeof(altest5), __alignof__(altest5)); + printf("altest6 sizeof=%d alignof=%d\n", + sizeof(altest6), __alignof__(altest6)); + printf("altest7 sizeof=%d alignof=%d\n", + sizeof(altest7), __alignof__(altest7)); + + /* empty structures (GCC extension) */ + printf("sizeof(struct empty) = %d\n", sizeof(struct empty)); + printf("alignof(struct empty) = %d\n", __alignof__(struct empty)); + + printf("Large: sizeof=%d\n", sizeof(ls)); + memset(&ls, 0, sizeof(ls)); + ls.compound_head = 42; + printf("Large: offsetof(compound_head)=%d\n", (int)((char*)&ls.compound_head - (char*)&ls)); +} + +/* XXX: depend on endianness */ +void char_short_test() +{ + int var1, var2; + + printf("char_short:\n"); + + var1 = 0x01020304; + var2 = 0xfffefdfc; + printf("s8=%d %d\n", + *(char *)&var1, *(char *)&var2); + printf("u8=%d %d\n", + *(unsigned char *)&var1, *(unsigned char *)&var2); + printf("s16=%d %d\n", + *(short *)&var1, *(short *)&var2); + printf("u16=%d %d\n", + *(unsigned short *)&var1, *(unsigned short *)&var2); + printf("s32=%d %d\n", + *(int *)&var1, *(int *)&var2); + printf("u32=%d %d\n", + *(unsigned int *)&var1, *(unsigned int *)&var2); + *(char *)&var1 = 0x08; + printf("var1=%x\n", var1); + *(short *)&var1 = 0x0809; + printf("var1=%x\n", var1); + *(int *)&var1 = 0x08090a0b; + printf("var1=%x\n", var1); +} + +/******************/ + +typedef struct Sym { + int v; + int t; + int c; + struct Sym *next; + struct Sym *prev; +} Sym; + +#define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +#define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) + +static int toupper1(int a) +{ + return TOUPPER(a); +} + +static unsigned int calc_vm_flags(unsigned int prot) +{ + unsigned int prot_bits; + /* This used to segfault in some revisions: */ + prot_bits = ((0x1==0x00000001)?(prot&0x1):(prot&0x1)?0x00000001:0); + return prot_bits; +} + +void bool_test() +{ + int *s, a, b, t, f, i; + + a = 0; + s = (void*)0; + printf("!s=%d\n", !s); + + if (!s || !s[0]) + a = 1; + printf("a=%d\n", a); + + printf("a=%d %d %d\n", 0 || 0, 0 || 1, 1 || 1); + printf("a=%d %d %d\n", 0 && 0, 0 && 1, 1 && 1); + printf("a=%d %d\n", 1 ? 1 : 0, 0 ? 1 : 0); +#if 1 && 1 + printf("a1\n"); +#endif +#if 1 || 0 + printf("a2\n"); +#endif +#if 1 ? 0 : 1 + printf("a3\n"); +#endif +#if 0 ? 0 : 1 + printf("a4\n"); +#endif + + a = 4; + printf("b=%d\n", a + (0 ? 1 : a / 2)); + + /* test register spilling */ + a = 10; + b = 10; + a = (a + b) * ((a < b) ? + ((b - a) * (a - b)): a + b); + printf("a=%d\n", a); + + /* test complex || or && expressions */ + t = 1; + f = 0; + a = 32; + printf("exp=%d\n", f == (32 <= a && a <= 3)); + printf("r=%d\n", (t || f) + (t && f)); + + /* test ? : cast */ + { + int aspect_on; + int aspect_native = 65536; + double bfu_aspect = 1.0; + int aspect; + for(aspect_on = 0; aspect_on < 2; aspect_on++) { + aspect=aspect_on?(aspect_native*bfu_aspect+0.5):65535UL; + printf("aspect=%d\n", aspect); + } + } + + /* test ? : GCC extension */ + { + static int v1 = 34 ? : -1; /* constant case */ + static int v2 = 0 ? : -1; /* constant case */ + int a = 30; + + printf("%d %d\n", v1, v2); + printf("%d %d\n", a - 30 ? : a * 2, a + 1 ? : a * 2); + } + + /* again complex expression */ + for(i=0;i<256;i++) { + if (toupper1 (i) != TOUPPER (i)) + printf("error %d\n", i); + } + printf ("bits = 0x%x\n", calc_vm_flags (0x1)); +} + +extern int undefined_function(void); +extern int defined_function(void); + +static inline void refer_to_undefined(void) +{ + undefined_function(); +} + +void optimize_out(void) +{ + int i = 0 ? undefined_function() : defined_function(); + printf ("oo:%d\n", i); + int j = 1 ? defined_function() : undefined_function(); + printf ("oo:%d\n", j); + if (0) + printf("oo:%d\n", undefined_function()); + else + printf("oo:%d\n", defined_function()); + if (1) + printf("oo:%d\n", defined_function()); + else + printf("oo:%d\n", undefined_function()); + while (1) { + printf("oow:%d\n", defined_function()); + break; + printf("oow:%d\n", undefined_function()); + } + j = 1; + /* Following is a switch without {} block intentionally. */ + switch (j) + case 1: break; + printf ("oos:%d\n", defined_function()); + /* The following break shouldn't lead to disabled code after + the while. */ + while (1) + break; + printf ("ool1:%d\n", defined_function()); + /* Same for the other types of loops. */ + do + break; + while (1); + printf ("ool2:%d\n", defined_function()); + for (;;) + break; + printf ("ool3:%d\n", defined_function()); + /* Normal {} blocks without controlling statements + shouldn't reactivate code emission */ + while (1) { + { + break; + } + printf ("ool4:%d\n", undefined_function()); + } + j = 1; + while (j) { + if (j == 0) + break; /* this break shouldn't disable code outside the if. */ + printf("ool5:%d\n", defined_function()); + j--; + } + + j = 1; + while (j) { + if (1) + j--; + else + breakhere: break; + printf("ool6:%d\n", defined_function()); + goto breakhere; + } + + /* Test that constants in logical && are optimized: */ + i = 0 && undefined_function(); + i = defined_function() && 0 && undefined_function(); + if (0 && undefined_function()) + undefined_function(); + if (defined_function() && 0) + undefined_function(); + if (0 && 0) + undefined_function(); + if (defined_function() && 0 && undefined_function()) + undefined_function(); + /* The same for || : */ + i = 1 || undefined_function(); + i = defined_function() || 1 || undefined_function(); + if (1 || undefined_function()) + ; + else + undefined_function(); + if (defined_function() || 1) + ; + else + undefined_function(); + if (1 || 1) + ; + else + undefined_function(); + if (defined_function() || 1 || undefined_function()) + ; + else + undefined_function(); + + if (defined_function() && 0) + refer_to_undefined(); + + if (0) { + (void)sizeof( ({ + do { } while (0); + 0; + }) ); + undefined_function(); + } + + /* Leave the "if(1)return; printf()" in this order and last in the function */ + if (1) + return; + printf ("oor:%d\n", undefined_function()); +} + +int defined_function(void) +{ + static int i = 40; + return i++; +} + +/* GCC accepts that */ +static int tab_reinit[]; +static int tab_reinit[10]; + +//int cinit1; /* a global variable can be defined several times without error ! */ +int cinit1; +int cinit1; +int cinit1 = 0; +int *cinit2 = (int []){3, 2, 1}; + +void compound_literal_test(void) +{ + int *p, i; + char *q, *q3; + + printf("compound_test:\n"); + + p = (int []){1, 2, 3}; + for(i=0;i<3;i++) + printf(" %d", p[i]); + printf("\n"); + + for(i=0;i<3;i++) + printf("%d", cinit2[i]); + printf("\n"); + + q = "tralala1"; + printf("q1=%s\n", q); + + q = (char *){ "tralala2" }; + printf("q2=%s\n", q); + + q3 = (char *){ q }; + printf("q3=%s\n", q3); + + q = (char []){ "tralala3" }; + printf("q4=%s\n", q); + +#ifdef ALL_ISOC99 + p = (int []){1, 2, cinit1 + 3}; + for(i=0;i<3;i++) + printf(" %d", p[i]); + printf("\n"); + + for(i=0;i<3;i++) { + p = (int []){1, 2, 4 + i}; + printf("%d %d %d\n", + p[0], + p[1], + p[2]); + } +#endif +} + +/* K & R protos */ + +kr_func1(a, b) +{ + return a + b; +} + +int kr_func2(a, b) +{ + return a + b; +} + +kr_test() +{ + printf("kr_test:\n"); + printf("func1=%d\n", kr_func1(3, 4)); + printf("func2=%d\n", kr_func2(3, 4)); + return 0; +} + +void num(int n) +{ + char *tab, *p; + tab = (char*)malloc(20); + p = tab; + while (1) { + *p = 48 + (n % 10); + p++; + n = n / 10; + if (n == 0) + break; + } + while (p != tab) { + p--; + printf("%c", *p); + } + printf("\n"); + free(tab); +} + +/* structure assignment tests */ +struct structa1 { + int f1; + char f2; +}; + +struct structa1 ssta1; + +void struct_assign_test1(struct structa1 s1, int t, float f) +{ + printf("%d %d %d %f\n", s1.f1, s1.f2, t, f); +} + +struct structa1 struct_assign_test2(struct structa1 s1, int t) +{ + s1.f1 += t; + s1.f2 -= t; + return s1; +} + +void struct_assign_test(void) +{ + struct S { + struct structa1 lsta1, lsta2; + int i; + } s, *ps; + + ps = &s; + ps->i = 4; +#if 0 + printf("struct_assign_test:\n"); + + s.lsta1.f1 = 1; + s.lsta1.f2 = 2; + printf("%d %d\n", s.lsta1.f1, s.lsta1.f2); + s.lsta2 = s.lsta1; + printf("%d %d\n", s.lsta2.f1, s.lsta2.f2); +#else + s.lsta2.f1 = 1; + s.lsta2.f2 = 2; +#endif + struct_assign_test1(ps->lsta2, 3, 4.5); + + printf("before call: %d %d\n", s.lsta2.f1, s.lsta2.f2); + ps->lsta2 = struct_assign_test2(ps->lsta2, ps->i); + printf("after call: %d %d\n", ps->lsta2.f1, ps->lsta2.f2); + + static struct { + void (*elem)(); + } t[] = { + /* XXX: we should allow this even without braces */ + { struct_assign_test } + }; + printf("%d\n", struct_assign_test == t[0].elem); +} + +/* casts to short/char */ + +void cast1(char a, short b, unsigned char c, unsigned short d) +{ + printf("%d %d %d %d\n", a, b, c, d); +} + +char bcast; +short scast; + +void cast_test() +{ + int a; + char c; + char tab[10]; + unsigned b,d; + short s; + char *p = NULL; + p -= 0x700000000042; + + printf("cast_test:\n"); + a = 0xfffff; + cast1(a, a, a, a); + a = 0xffffe; + printf("%d %d %d %d\n", + (char)(a + 1), + (short)(a + 1), + (unsigned char)(a + 1), + (unsigned short)(a + 1)); + printf("%d %d %d %d\n", + (char)0xfffff, + (short)0xfffff, + (unsigned char)0xfffff, + (unsigned short)0xfffff); + + a = (bcast = 128) + 1; + printf("%d\n", a); + a = (scast = 65536) + 1; + printf("%d\n", a); + + printf("sizeof(c) = %d, sizeof((int)c) = %d\n", sizeof(c), sizeof((int)c)); + + /* test cast from unsigned to signed short to int */ + b = 0xf000; + d = (short)b; + printf("((unsigned)(short)0x%08x) = 0x%08x\n", b, d); + b = 0xf0f0; + d = (char)b; + printf("((unsigned)(char)0x%08x) = 0x%08x\n", b, d); + + /* test implicit int casting for array accesses */ + c = 0; + tab[1] = 2; + tab[c] = 1; + printf("%d %d\n", tab[0], tab[1]); + + /* test implicit casting on some operators */ + printf("sizeof(+(char)'a') = %d\n", sizeof(+(char)'a')); + printf("sizeof(-(char)'a') = %d\n", sizeof(-(char)'a')); + printf("sizeof(~(char)'a') = %d\n", sizeof(-(char)'a')); + + /* from pointer to integer types */ + printf("%d %d %ld %ld %lld %lld\n", + (int)p, (unsigned int)p, + (long)p, (unsigned long)p, + (long long)p, (unsigned long long)p); + + /* from integers to pointers */ + printf("%p %p %p %p\n", + (void *)a, (void *)b, (void *)c, (void *)d); +} + +/* initializers tests */ +struct structinit1 { + int f1; + char f2; + short f3; + int farray[3]; +}; + +int sinit1 = 2; +int sinit2 = { 3 }; +int sinit3[3] = { 1, 2, {{3}}, }; +int sinit4[3][2] = { {1, 2}, {3, 4}, {5, 6} }; +int sinit5[3][2] = { 1, 2, 3, 4, 5, 6 }; +int sinit6[] = { 1, 2, 3 }; +int sinit7[] = { [2] = 3, [0] = 1, 2 }; +char sinit8[] = "hello" "trala"; + +struct structinit1 sinit9 = { 1, 2, 3 }; +struct structinit1 sinit10 = { .f2 = 2, 3, .f1 = 1 }; +struct structinit1 sinit11 = { .f2 = 2, 3, .f1 = 1, +#ifdef ALL_ISOC99 + .farray[0] = 10, + .farray[1] = 11, + .farray[2] = 12, +#endif +}; + +char *sinit12 = "hello world"; +char *sinit13[] = { + "test1", + "test2", + "test3", +}; +char sinit14[10] = { "abc" }; +int sinit15[3] = { sizeof(sinit15), 1, 2 }; + +struct { int a[3], b; } sinit16[] = { { 1 }, 2 }; + +struct bar { + char *s; + int len; +} sinit17[] = { + "a1", 4, + "a2", 1 +}; + +int sinit18[10] = { + [2 ... 5] = 20, + 2, + [8] = 10, +}; + +struct complexinit0 { + int a; + int b; +}; + +struct complexinit { + int a; + const struct complexinit0 *b; +}; + +const static struct complexinit cix[] = { + [0] = { + .a = 2000, + .b = (const struct complexinit0[]) { + { 2001, 2002 }, + { 2003, 2003 }, + {} + } + } +}; + +struct complexinit2 { + int a; + int b[]; +}; + +struct complexinit2 cix20; + +struct complexinit2 cix21 = { + .a = 3000, + .b = { 3001, 3002, 3003 } +}; + +struct complexinit2 cix22 = { + .a = 4000, + .b = { 4001, 4002, 4003, 4004, 4005, 4006 } +}; + +typedef int arrtype1[]; +arrtype1 sinit19 = {1}; +arrtype1 sinit20 = {2,3}; +typedef int arrtype2[3]; +arrtype2 sinit21 = {4}; +arrtype2 sinit22 = {5,6,7}; + +/* Address comparisons of non-weak symbols with zero can be const-folded */ +int sinit23[2] = { "astring" ? sizeof("astring") : -1, + &sinit23 ? 42 : -1 }; + +extern int external_inited = 42; + +void init_test(void) +{ + int linit1 = 2; + int linit2 = { 3 }; + int linit4[3][2] = { {1, 2}, {3, 4}, {5, 6} }; + int linit6[] = { 1, 2, 3 }; + int i, j; + char linit8[] = "hello" "trala"; + int linit12[10] = { 1, 2 }; + int linit13[10] = { 1, 2, [7] = 3, [3] = 4, }; + char linit14[10] = "abc"; + int linit15[10] = { linit1, linit1 + 1, [6] = linit1 + 2, }; + struct linit16 { int a1, a2, a3, a4; } linit16 = { 1, .a3 = 2 }; + int linit17 = sizeof(linit17); + int zero = 0; + /* Addresses on non-weak symbols are non-zero, but not the access itself */ + int linit18[2] = {&zero ? 1 : -1, zero ? -1 : 1 }; + + printf("init_test:\n"); + + printf("sinit1=%d\n", sinit1); + printf("sinit2=%d\n", sinit2); + printf("sinit3=%d %d %d %d\n", + sizeof(sinit3), + sinit3[0], + sinit3[1], + sinit3[2] + ); + printf("sinit6=%d\n", sizeof(sinit6)); + printf("sinit7=%d %d %d %d\n", + sizeof(sinit7), + sinit7[0], + sinit7[1], + sinit7[2] + ); + printf("sinit8=%s\n", sinit8); + printf("sinit9=%d %d %d\n", + sinit9.f1, + sinit9.f2, + sinit9.f3 + ); + printf("sinit10=%d %d %d\n", + sinit10.f1, + sinit10.f2, + sinit10.f3 + ); + printf("sinit11=%d %d %d %d %d %d\n", + sinit11.f1, + sinit11.f2, + sinit11.f3, + sinit11.farray[0], + sinit11.farray[1], + sinit11.farray[2] + ); + + for(i=0;i<3;i++) + for(j=0;j<2;j++) + printf("[%d][%d] = %d %d %d\n", + i, j, sinit4[i][j], sinit5[i][j], linit4[i][j]); + printf("linit1=%d\n", linit1); + printf("linit2=%d\n", linit2); + printf("linit6=%d\n", sizeof(linit6)); + printf("linit8=%d %s\n", sizeof(linit8), linit8); + + printf("sinit12=%s\n", sinit12); + printf("sinit13=%d %s %s %s\n", + sizeof(sinit13), + sinit13[0], + sinit13[1], + sinit13[2]); + printf("sinit14=%s\n", sinit14); + + for(i=0;i<10;i++) printf(" %d", linit12[i]); + printf("\n"); + for(i=0;i<10;i++) printf(" %d", linit13[i]); + printf("\n"); + for(i=0;i<10;i++) printf(" %d", linit14[i]); + printf("\n"); + for(i=0;i<10;i++) printf(" %d", linit15[i]); + printf("\n"); + printf("%d %d %d %d\n", + linit16.a1, + linit16.a2, + linit16.a3, + linit16.a4); + /* test that initialisation is done after variable declare */ + printf("linit17=%d\n", linit17); + printf("sinit15=%d\n", sinit15[0]); + printf("sinit16=%d %d\n", sinit16[0].a[0], sinit16[1].a[0]); + printf("sinit17=%s %d %s %d\n", + sinit17[0].s, sinit17[0].len, + sinit17[1].s, sinit17[1].len); + for(i=0;i<10;i++) + printf("%x ", sinit18[i]); + printf("\n"); + /* complex init check */ + printf("cix: %d %d %d %d %d %d %d\n", + cix[0].a, + cix[0].b[0].a, cix[0].b[0].b, + cix[0].b[1].a, cix[0].b[1].b, + cix[0].b[2].a, cix[0].b[2].b); + printf("cix2: %d %d\n", cix21.b[2], cix22.b[5]); + printf("sizeof cix20 %d, cix21 %d, sizeof cix22 %d\n", sizeof cix20, sizeof cix21, sizeof cix22); + + printf("arrtype1: %d %d %d\n", sinit19[0], sinit20[0], sinit20[1]); + printf("arrtype2: %d %d\n", sizeof(sinit19), sizeof(sinit20)); + printf("arrtype3: %d %d %d\n", sinit21[0], sinit21[1], sinit21[2]); + printf("arrtype4: %d %d %d\n", sinit22[0], sinit22[1], sinit22[2]); + printf("arrtype5: %d %d\n", sizeof(sinit21), sizeof(sinit22)); + printf("arrtype6: %d\n", sizeof(arrtype2)); + + printf("sinit23= %d %d\n", sinit23[0], sinit23[1]); + printf("linit18= %d %d\n", linit18[0], linit18[1]); +} + +void switch_uc(unsigned char uc) +{ + switch (uc) { + case 0xfb ... 0xfe: + printf("ucsw:1\n"); + break; + case 0xff: + printf("ucsw:2\n"); + break; + case 0 ... 5: + printf("ucsw:3\n"); + break; + default: + printf("ucsw: broken!\n"); + } +} + +void switch_sc(signed char sc) +{ + switch (sc) { + case -5 ... -2: + printf("scsw:1\n"); + break; + case -1: + printf("scsw:2\n"); + break; + case 0 ... 5: + printf("scsw:3\n"); + break; + default: + printf("scsw: broken!\n"); + } +} + +void switch_test() +{ + int i; + unsigned long long ull; + long long ll; + + for(i=0;i<15;i++) { + switch(i) { + case 0: + case 1: + printf("a"); + break; + default: + printf("%d", i); + break; + case 8 ... 12: + printf("c"); + break; + case 3: + printf("b"); + break; + case 0xc33c6b9fU: + case 0x7c9eeeb9U: + break; + } + } + printf("\n"); + + for (i = 1; i <= 5; i++) { + ull = (unsigned long long)i << 61; + switch (ull) { + case 1ULL << 61: + printf("ullsw:1\n"); + break; + case 2ULL << 61: + printf("ullsw:2\n"); + break; + case 3ULL << 61: + printf("ullsw:3\n"); + break; + case 4ULL << 61: + printf("ullsw:4\n"); + break; + case 5ULL << 61: + printf("ullsw:5\n"); + break; + default: + printf("ullsw: broken!\n"); + } + } + + for (i = 1; i <= 5; i++) { + ll = (long long)i << 61; + switch (ll) { + case 1LL << 61: + printf("llsw:1\n"); + break; + case 2LL << 61: + printf("llsw:2\n"); + break; + case 3LL << 61: + printf("llsw:3\n"); + break; + case 4LL << 61: + printf("llsw:4\n"); + break; + case 5LL << 61: + printf("llsw:5\n"); + break; + default: + printf("llsw: broken!\n"); + } + } + + for (i = -5; i <= 5; i++) { + switch_uc((unsigned char)i); + } + + for (i = -5; i <= 5; i++) { + switch_sc ((signed char)i); + } +} + +/* ISOC99 _Bool type */ +void c99_bool_test(void) +{ +#ifdef BOOL_ISOC99 + int a; + _Bool b; + + printf("bool_test:\n"); + printf("sizeof(_Bool) = %d\n", sizeof(_Bool)); + a = 3; + printf("cast: %d %d %d\n", (_Bool)10, (_Bool)0, (_Bool)a); + b = 3; + printf("b = %d\n", b); + b++; + printf("b = %d\n", b); +#endif +} + +void bitfield_test(void) +{ + int a; + short sa; + unsigned char ca; + struct sbf1 { + int f1 : 3; + int : 2; + int f2 : 1; + int : 0; + int f3 : 5; + int f4 : 7; + unsigned int f5 : 7; + } st1; + printf("bitfield_test:"); + printf("sizeof(st1) = %d\n", sizeof(st1)); + + st1.f1 = 3; + st1.f2 = 1; + st1.f3 = 15; + a = 120; + st1.f4 = a; + st1.f5 = a; + st1.f5++; + printf("%d %d %d %d %d\n", + st1.f1, st1.f2, st1.f3, st1.f4, st1.f5); + sa = st1.f5; + ca = st1.f5; + printf("%d %d\n", sa, ca); + + st1.f1 = 7; + if (st1.f1 == -1) + printf("st1.f1 == -1\n"); + else + printf("st1.f1 != -1\n"); + if (st1.f2 == -1) + printf("st1.f2 == -1\n"); + else + printf("st1.f2 != -1\n"); + + struct sbf2 { + long long f1 : 45; + long long : 2; + long long f2 : 35; + unsigned long long f3 : 38; + } st2; + st2.f1 = 0x123456789ULL; + a = 120; + st2.f2 = (long long)a << 25; + st2.f3 = a; + st2.f2++; + printf("%lld %lld %lld\n", st2.f1, st2.f2, st2.f3); + +#if 0 + Disabled for now until further clarification re GCC compatibility + struct sbf3 { + int f1 : 7; + int f2 : 1; + char f3; + int f4 : 8; + int f5 : 1; + int f6 : 16; + } st3; + printf("sizeof(st3) = %d\n", sizeof(st3)); +#endif + + struct sbf4 { + int x : 31; + char y : 2; + } st4; + st4.y = 1; + printf("st4.y == %d\n", st4.y); + struct sbf5 { + int a; + char b; + int x : 12, y : 4, : 0, : 4, z : 3; + char c; + } st5 = { 1, 2, 3, 4, -3, 6 }; + printf("st5 = %d %d %d %d %d %d\n", st5.a, st5.b, st5.x, st5.y, st5.z, st5.c); + struct sbf6 { + short x : 12; + unsigned char y : 2; + } st6; + st6.y = 1; + printf("st6.y == %d\n", st6.y); +} + +#ifdef __x86_64__ +#define FLOAT_FMT "%f\n" +#else +/* x86's float isn't compatible with GCC */ +#define FLOAT_FMT "%.5f\n" +#endif + +/* declare strto* functions as they are C99 */ +double strtod(const char *nptr, char **endptr); + +#if defined(_WIN32) +float strtof(const char *nptr, char **endptr) {return (float)strtod(nptr, endptr);} +LONG_DOUBLE strtold(const char *nptr, char **endptr) {return (LONG_DOUBLE)strtod(nptr, endptr);} +#else +float strtof(const char *nptr, char **endptr); +LONG_DOUBLE strtold(const char *nptr, char **endptr); +#endif + +#define FTEST(prefix, typename, type, fmt)\ +void prefix ## cmp(type a, type b)\ +{\ + printf("%d %d %d %d %d %d\n",\ + a == b,\ + a != b,\ + a < b,\ + a > b,\ + a >= b,\ + a <= b);\ + printf(fmt " " fmt " " fmt " " fmt " " fmt " " fmt " " fmt "\n",\ + a,\ + b,\ + a + b,\ + a - b,\ + a * b,\ + a / b,\ + -a);\ + printf(fmt "\n", ++a);\ + printf(fmt "\n", a++);\ + printf(fmt "\n", a);\ + b = 0;\ + printf("%d %d\n", !a, !b);\ +}\ +void prefix ## fcast(type a)\ +{\ + float fa;\ + double da;\ + LONG_DOUBLE la;\ + int ia;\ + long long llia;\ + unsigned int ua;\ + unsigned long long llua;\ + type b;\ + fa = a;\ + da = a;\ + la = a;\ + printf("ftof: %f %f %Lf\n", fa, da, la);\ + ia = (int)a;\ + llia = (long long)a;\ + a = (a >= 0) ? a : -a;\ + ua = (unsigned int)a;\ + llua = (unsigned long long)a;\ + printf("ftoi: %d %u %lld %llu\n", ia, ua, llia, llua);\ + ia = -1234;\ + ua = 0x81234500;\ + llia = -0x123456789012345LL;\ + llua = 0xf123456789012345LLU;\ + b = ia;\ + printf("itof: " fmt "\n", b);\ + b = ua;\ + printf("utof: " fmt "\n", b);\ + b = llia;\ + printf("lltof: " fmt "\n", b);\ + b = llua;\ + printf("ulltof: " fmt "\n", b);\ +}\ +\ +float prefix ## retf(type a) { return a; }\ +double prefix ## retd(type a) { return a; }\ +LONG_DOUBLE prefix ## retld(type a) { return a; }\ +\ +void prefix ## call(void)\ +{\ + printf("float: " FLOAT_FMT, prefix ## retf(42.123456789));\ + printf("double: %f\n", prefix ## retd(42.123456789));\ + printf("long double: %Lf\n", prefix ## retld(42.123456789));\ + printf("strto%s: %f\n", #prefix, (double)strto ## prefix("1.2", NULL));\ +}\ +\ +void prefix ## signed_zeros(void) \ +{\ + type x = 0.0, y = -0.0, n, p;\ + if (x == y)\ + printf ("Test 1.0 / x != 1.0 / y returns %d (should be 1).\n",\ + 1.0 / x != 1.0 / y);\ + else\ + printf ("x != y; this is wrong!\n");\ +\ + n = -x;\ + if (x == n)\ + printf ("Test 1.0 / x != 1.0 / -x returns %d (should be 1).\n",\ + 1.0 / x != 1.0 / n);\ + else\ + printf ("x != -x; this is wrong!\n");\ +\ + p = +y;\ + if (x == p)\ + printf ("Test 1.0 / x != 1.0 / +y returns %d (should be 1).\n",\ + 1.0 / x != 1.0 / p);\ + else\ + printf ("x != +y; this is wrong!\n");\ + p = -y;\ + if (x == p)\ + printf ("Test 1.0 / x != 1.0 / -y returns %d (should be 0).\n",\ + 1.0 / x != 1.0 / p);\ + else\ + printf ("x != -y; this is wrong!\n");\ +}\ +void prefix ## test(void)\ +{\ + printf("testing '%s'\n", #typename);\ + prefix ## cmp(1, 2.5);\ + prefix ## cmp(2, 1.5);\ + prefix ## cmp(1, 1);\ + prefix ## fcast(234.6);\ + prefix ## fcast(-2334.6);\ + prefix ## call();\ + prefix ## signed_zeros();\ +} + +FTEST(f, float, float, "%f") +FTEST(d, double, double, "%f") +FTEST(ld, long double, LONG_DOUBLE, "%Lf") + +double ftab1[3] = { 1.2, 3.4, -5.6 }; + + +void float_test(void) +{ +#if !defined(__arm__) || defined(__ARM_PCS_VFP) + float fa, fb; + double da, db; + int a; + unsigned int b; + + printf("float_test:\n"); + printf("sizeof(float) = %d\n", sizeof(float)); + printf("sizeof(double) = %d\n", sizeof(double)); + printf("sizeof(long double) = %d\n", sizeof(LONG_DOUBLE)); + ftest(); + dtest(); + ldtest(); + printf("%f %f %f\n", ftab1[0], ftab1[1], ftab1[2]); + printf("%f %f %f\n", 2.12, .5, 2.3e10); + // printf("%f %f %f\n", 0x1234p12, 0x1e23.23p10, 0x12dp-10); + da = 123; + printf("da=%f\n", da); + fa = 123; + printf("fa=%f\n", fa); + a = 4000000000; + da = a; + printf("da = %f\n", da); + b = 4000000000; + db = b; + printf("db = %f\n", db); +#endif +} + +int fib(int n) +{ + if (n <= 2) + return 1; + else + return fib(n-1) + fib(n-2); +} + +void funcptr_test() +{ + void (*func)(int); + int a; + struct { + int dummy; + void (*func)(int); + } st1; + long diff; + + printf("funcptr:\n"); + func = # + (*func)(12345); + func = num; + a = 1; + a = 1; + func(12345); + /* more complicated pointer computation */ + st1.func = num; + st1.func(12346); + printf("sizeof1 = %d\n", sizeof(funcptr_test)); + printf("sizeof2 = %d\n", sizeof funcptr_test); + printf("sizeof3 = %d\n", sizeof(&funcptr_test)); + printf("sizeof4 = %d\n", sizeof &funcptr_test); + a = 0; + func = num + a; + diff = func - num; + func(42); + (func + diff)(42); + (num + a)(43); +} + +void lloptest(long long a, long long b) +{ + unsigned long long ua, ub; + + ua = a; + ub = b; + /* arith */ + printf("arith: " LONG_LONG_FORMAT " " LONG_LONG_FORMAT " " LONG_LONG_FORMAT "\n", + a + b, + a - b, + a * b); + + if (b != 0) { + printf("arith1: " LONG_LONG_FORMAT " " LONG_LONG_FORMAT "\n", + a / b, + a % b); + } + + /* binary */ + printf("bin: " LONG_LONG_FORMAT " " LONG_LONG_FORMAT " " LONG_LONG_FORMAT "\n", + a & b, + a | b, + a ^ b); + + /* tests */ + printf("test: %d %d %d %d %d %d\n", + a == b, + a != b, + a < b, + a > b, + a >= b, + a <= b); + + printf("utest: %d %d %d %d %d %d\n", + ua == ub, + ua != ub, + ua < ub, + ua > ub, + ua >= ub, + ua <= ub); + + /* arith2 */ + a++; + b++; + printf("arith2: " LONG_LONG_FORMAT " " LONG_LONG_FORMAT "\n", a, b); + printf("arith2: " LONG_LONG_FORMAT " " LONG_LONG_FORMAT "\n", a++, b++); + printf("arith2: " LONG_LONG_FORMAT " " LONG_LONG_FORMAT "\n", --a, --b); + printf("arith2: " LONG_LONG_FORMAT " " LONG_LONG_FORMAT "\n", a, b); + b = ub = 0; + printf("not: %d %d %d %d\n", !a, !ua, !b, !ub); +} + +void llshift(long long a, int b) +{ + printf("shift: " LONG_LONG_FORMAT " " LONG_LONG_FORMAT " " LONG_LONG_FORMAT "\n", + (unsigned long long)a >> b, + a >> b, + a << b); + printf("shiftc: " LONG_LONG_FORMAT " " LONG_LONG_FORMAT " " LONG_LONG_FORMAT "\n", + (unsigned long long)a >> 3, + a >> 3, + a << 3); + printf("shiftc: " LONG_LONG_FORMAT " " LONG_LONG_FORMAT " " LONG_LONG_FORMAT "\n", + (unsigned long long)a >> 35, + a >> 35, + a << 35); +} + +void llfloat(void) +{ + float fa; + double da; + LONG_DOUBLE lda; + long long la, lb, lc; + unsigned long long ula, ulb, ulc; + la = 0x12345678; + ula = 0x72345678; + la = (la << 20) | 0x12345; + ula = ula << 33; + printf("la=" LONG_LONG_FORMAT " ula=" ULONG_LONG_FORMAT "\n", la, ula); + + fa = la; + da = la; + lda = la; + printf("lltof: %f %f %Lf\n", fa, da, lda); + + la = fa; + lb = da; + lc = lda; + printf("ftoll: " LONG_LONG_FORMAT " " LONG_LONG_FORMAT " " LONG_LONG_FORMAT "\n", la, lb, lc); + + fa = ula; + da = ula; + lda = ula; + printf("ulltof: %f %f %Lf\n", fa, da, lda); + + ula = fa; + ulb = da; + ulc = lda; + printf("ftoull: " ULONG_LONG_FORMAT " " ULONG_LONG_FORMAT " " ULONG_LONG_FORMAT "\n", ula, ulb, ulc); +} + +long long llfunc1(int a) +{ + return a * 2; +} + +struct S { + int id; + char item; +}; + +long long int value(struct S *v) +{ + return ((long long int)v->item); +} + +long long llfunc2(long long x, long long y, int z) +{ + return x * y * z; +} + +void longlong_test(void) +{ + long long a, b, c; + int ia; + unsigned int ua; + printf("longlong_test:\n"); + printf("sizeof(long long) = %d\n", sizeof(long long)); + ia = -1; + ua = -2; + a = ia; + b = ua; + printf(LONG_LONG_FORMAT " " LONG_LONG_FORMAT "\n", a, b); + printf(LONG_LONG_FORMAT " " LONG_LONG_FORMAT " " LONG_LONG_FORMAT " %Lx\n", + (long long)1, + (long long)-2, + 1LL, + 0x1234567812345679); + a = llfunc1(-3); + printf(LONG_LONG_FORMAT "\n", a); + + lloptest(1000, 23); + lloptest(0xff, 0x1234); + b = 0x72345678 << 10; + lloptest(-3, b); + llshift(0x123, 5); + llshift(-23, 5); + b = 0x72345678LL << 10; + llshift(b, 47); + + llfloat(); +#if 1 + b = 0x12345678; + a = -1; + c = a + b; + printf("%Lx\n", c); +#endif + + /* long long reg spill test */ + { + struct S a; + + a.item = 3; + printf("%lld\n", value(&a)); + } + lloptest(0x80000000, 0); + + { + long long *p, v, **pp; + v = 1; + p = &v; + p[0]++; + printf("another long long spill test : %lld\n", *p); + pp = &p; + + v = llfunc2(**pp, **pp, ia); + printf("a long long function (arm-)reg-args test : %lld\n", v); + } + a = 68719476720LL; + b = 4294967295LL; + printf("%d %d %d %d\n", a > b, a < b, a >= b, a <= b); + + printf(LONG_LONG_FORMAT "\n", 0x123456789LLU); + + /* long long pointer deref in argument passing test */ + a = 0x123; + long long *p = &a; + llshift(*p, 5); +} + +void manyarg_test(void) +{ + LONG_DOUBLE ld = 1234567891234LL; + printf("manyarg_test:\n"); + printf("%d %d %d %d %d %d %d %d %f %f %f %f %f %f %f %f %f %f\n", + 1, 2, 3, 4, 5, 6, 7, 8, + 0.1, 1.2, 2.3, 3.4, 4.5, 5.6, 6.7, 7.8, 8.9, 9.0); + printf("%d %d %d %d %d %d %d %d %f %f %f %f %f %f %f %f %f %f " + LONG_LONG_FORMAT " " LONG_LONG_FORMAT " %f %f\n", + 1, 2, 3, 4, 5, 6, 7, 8, + 0.1, 1.2, 2.3, 3.4, 4.5, 5.6, 6.7, 7.8, 8.9, 9.0, + 1234567891234LL, 987654321986LL, + 42.0, 43.0); + printf("%Lf %d %d %d %d %d %d %d %d %f %f %f %f %f %f %f %f %f %f " + LONG_LONG_FORMAT " " LONG_LONG_FORMAT " %f %f\n", + ld, 1, 2, 3, 4, 5, 6, 7, 8, + 0.1, 1.2, 2.3, 3.4, 4.5, 5.6, 6.7, 7.8, 8.9, 9.0, + 1234567891234LL, 987654321986LL, + 42.0, 43.0); + printf("%d %d %d %d %d %d %d %d %Lf\n", + 1, 2, 3, 4, 5, 6, 7, 8, ld); + printf("%d %d %d %d %d %d %d %d %f %f %f %f %f %f %f %f %f %f " + LONG_LONG_FORMAT " " LONG_LONG_FORMAT "%f %f %Lf\n", + 1, 2, 3, 4, 5, 6, 7, 8, + 0.1, 1.2, 2.3, 3.4, 4.5, 5.6, 6.7, 7.8, 8.9, 9.0, + 1234567891234LL, 987654321986LL, + 42.0, 43.0, ld); + printf("%d %d %d %d %d %d %d %d %f %f %f %f %f %f %f %f %f %f " + "%Lf " LONG_LONG_FORMAT " " LONG_LONG_FORMAT " %f %f %Lf\n", + 1, 2, 3, 4, 5, 6, 7, 8, + 0.1, 1.2, 2.3, 3.4, 4.5, 5.6, 6.7, 7.8, 8.9, 9.0, + ld, 1234567891234LL, 987654321986LL, + 42.0, 43.0, ld); +} + +void vprintf1(const char *fmt, ...) +{ + va_list ap, aq; + const char *p; + int c, i; + double d; + long long ll; + LONG_DOUBLE ld; + + va_start(aq, fmt); + va_copy(ap, aq); + + p = fmt; + for(;;) { + c = *p; + if (c == '\0') + break; + p++; + if (c == '%') { + c = *p; + switch(c) { + case '\0': + goto the_end; + case 'd': + i = va_arg(ap, int); + printf("%d", i); + break; + case 'f': + d = va_arg(ap, double); + printf("%f", d); + break; + case 'l': + ll = va_arg(ap, long long); + printf(LONG_LONG_FORMAT, ll); + break; + case 'F': + ld = va_arg(ap, LONG_DOUBLE); + printf("%Lf", ld); + break; + } + p++; + } else { + putchar(c); + } + } + the_end: + va_end(aq); + va_end(ap); +} + +struct myspace { + short int profile; +}; + +void stdarg_for_struct(struct myspace bob, ...) +{ + struct myspace george, bill; + va_list ap; + short int validate; + + va_start(ap, bob); + bill = va_arg(ap, struct myspace); + george = va_arg(ap, struct myspace); + validate = va_arg(ap, int); + printf("stdarg_for_struct: %d %d %d %d\n", + bob.profile, bill.profile, george.profile, validate); + va_end(ap); +} + +void stdarg_for_libc(const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + vprintf(fmt, args); + va_end(args); +} + +void stdarg_test(void) +{ + LONG_DOUBLE ld = 1234567891234LL; + struct myspace bob; + + vprintf1("%d %d %d\n", 1, 2, 3); + vprintf1("%f %d %f\n", 1.0, 2, 3.0); + vprintf1("%l %l %d %f\n", 1234567891234LL, 987654321986LL, 3, 1234.0); + vprintf1("%F %F %F\n", LONG_DOUBLE_LITERAL(1.2), LONG_DOUBLE_LITERAL(2.3), LONG_DOUBLE_LITERAL(3.4)); + vprintf1("%d %f %l %F %d %f %l %F\n", + 1, 1.2, 3LL, LONG_DOUBLE_LITERAL(4.5), 6, 7.8, 9LL, LONG_DOUBLE_LITERAL(0.1)); + vprintf1("%d %d %d %d %d %d %d %d %f %f %f %f %f %f %f %f\n", + 1, 2, 3, 4, 5, 6, 7, 8, + 0.1, 1.2, 2.3, 3.4, 4.5, 5.6, 6.7, 7.8); + vprintf1("%d %d %d %d %d %d %d %d %f %f %f %f %f %f %f %f %f %f\n", + 1, 2, 3, 4, 5, 6, 7, 8, + 0.1, 1.2, 2.3, 3.4, 4.5, 5.6, 6.7, 7.8, 8.9, 9.0); + vprintf1("%d %d %d %d %d %d %d %d %f %f %f %f %f %f %f %f %f %f " + "%l %l %f %f\n", + 1, 2, 3, 4, 5, 6, 7, 8, + 0.1, 1.2, 2.3, 3.4, 4.5, 5.6, 6.7, 7.8, 8.9, 9.0, + 1234567891234LL, 987654321986LL, + 42.0, 43.0); + vprintf1("%F %d %d %d %d %d %d %d %d %f %f %f %f %f %f %f %f %f %f " + "%l %l %f %f\n", + ld, 1, 2, 3, 4, 5, 6, 7, 8, + 0.1, 1.2, 2.3, 3.4, 4.5, 5.6, 6.7, 7.8, 8.9, 9.0, + 1234567891234LL, 987654321986LL, + 42.0, 43.0); + vprintf1("%d %d %d %d %d %d %d %d %F\n", + 1, 2, 3, 4, 5, 6, 7, 8, ld); + vprintf1("%d %d %d %d %d %d %d %d %f %f %f %f %f %f %f %f %f %f " + "%l %l %f %f %F\n", + 1, 2, 3, 4, 5, 6, 7, 8, + 0.1, 1.2, 2.3, 3.4, 4.5, 5.6, 6.7, 7.8, 8.9, 9.0, + 1234567891234LL, 987654321986LL, + 42.0, 43.0, ld); + vprintf1("%d %d %d %d %d %d %d %d %f %f %f %f %f %f %f %f %f %f " + "%F %l %l %f %f %F\n", + 1, 2, 3, 4, 5, 6, 7, 8, + 0.1, 1.2, 2.3, 3.4, 4.5, 5.6, 6.7, 7.8, 8.9, 9.0, + ld, 1234567891234LL, 987654321986LL, + 42.0, 43.0, ld); + + bob.profile = 42; + stdarg_for_struct(bob, bob, bob, bob.profile); + stdarg_for_libc("stdarg_for_libc: %s %.2f %d\n", "string", 1.23, 456); +} + +void whitespace_test(void) +{ + char *str; + + #if 1 + pri\ +ntf("whitspace:\n"); +#endif + pf("N=%d\n", 2); + +#ifdef CORRECT_CR_HANDLING + pri\ +ntf("aaa=%d\n", 3); +#endif + + pri\ +\ +ntf("min=%d\n", 4); + +#ifdef ACCEPT_CR_IN_STRINGS + printf("len1=%d\n", strlen(" +")); +#ifdef CORRECT_CR_HANDLING + str = " +"; + printf("len1=%d str[0]=%d\n", strlen(str), str[0]); +#endif + printf("len1=%d\n", strlen(" a +")); +#endif /* ACCEPT_CR_IN_STRINGS */ +} + +int reltab[3] = { 1, 2, 3 }; + +int *rel1 = &reltab[1]; +int *rel2 = &reltab[2]; + +#ifdef _WIN64 +void relocation_test(void) {} +#else +void getmyaddress(void) +{ + printf("in getmyaddress\n"); +} + +#ifdef __LP64__ +long __pa_symbol(void) +{ + /* This 64bit constant was handled incorrectly, it was used as addend + (which can hold 64bit just fine) in connection with a symbol, + and TCC generates wrong code for that (displacements are 32bit only). + This effectively is "+ 0x80000000", and if addresses of globals + are below 2GB the result should be a number without high 32 bits set. */ + return ((long)(((unsigned long)(&rel1))) - (0xffffffff80000000UL)); +} +#endif + +unsigned long theaddress = (unsigned long)getmyaddress; +void relocation_test(void) +{ + void (*fptr)(void) = (void (*)(void))theaddress; + printf("*rel1=%d\n", *rel1); + printf("*rel2=%d\n", *rel2); + fptr(); +#ifdef __LP64__ + printf("pa_symbol=0x%lx\n", __pa_symbol() >> 63); +#endif +} +#endif + +void old_style_f(a,b,c) + int a, b; + double c; +{ + printf("a=%d b=%d b=%f\n", a, b, c); +} + +void decl_func1(int cmpfn()) +{ + printf("cmpfn=%lx\n", (long)cmpfn); +} + +void decl_func2(cmpfn) +int cmpfn(); +{ + printf("cmpfn=%lx\n", (long)cmpfn); +} + +void old_style_function(void) +{ + old_style_f((void *)1, 2, 3.0); + decl_func1(NULL); + decl_func2(NULL); +} + +void alloca_test() +{ +#if defined __i386__ || defined __x86_64__ || defined __arm__ + char *p = alloca(16); + strcpy(p,"123456789012345"); + printf("alloca: p is %s\n", p); + char *demo = "This is only a test.\n"; + /* Test alloca embedded in a larger expression */ + printf("alloca: %s\n", strcpy(alloca(strlen(demo)+1),demo) ); +#endif +} + +void *bounds_checking_is_enabled() +{ + char ca[10], *cp = ca-1; + return (ca != cp + 1) ? cp : NULL; +} + +typedef int constant_negative_array_size_as_compile_time_assertion_idiom[(1 ? 2 : 0) - 1]; + +void c99_vla_test(int size1, int size2) +{ +#if defined __i386__ || defined __x86_64__ + int size = size1 * size2; + int tab1[size][2], tab2[10][2]; + void *tab1_ptr, *tab2_ptr, *bad_ptr; + + /* "size" should have been 'captured' at tab1 declaration, + so modifying it should have no effect on VLA behaviour. */ + size = size-1; + + printf("Test C99 VLA 1 (sizeof): "); + printf("%s\n", (sizeof tab1 == size1 * size2 * 2 * sizeof(int)) ? "PASSED" : "FAILED"); + tab1_ptr = tab1; + tab2_ptr = tab2; + printf("Test C99 VLA 2 (ptrs subtract): "); + printf("%s\n", (tab2 - tab1 == (tab2_ptr - tab1_ptr) / (sizeof(int) * 2)) ? "PASSED" : "FAILED"); + printf("Test C99 VLA 3 (ptr add): "); + printf("%s\n", &tab1[5][1] == (tab1_ptr + (5 * 2 + 1) * sizeof(int)) ? "PASSED" : "FAILED"); + printf("Test C99 VLA 4 (ptr access): "); + tab1[size1][1] = 42; + printf("%s\n", (*((int *) (tab1_ptr + (size1 * 2 + 1) * sizeof(int))) == 42) ? "PASSED" : "FAILED"); + + printf("Test C99 VLA 5 (bounds checking (might be disabled)): "); + if (bad_ptr = bounds_checking_is_enabled()) { + int *t1 = &tab1[size1 * size2 - 1][3]; + int *t2 = &tab2[9][3]; + printf("%s ", bad_ptr == t1 ? "PASSED" : "FAILED"); + printf("%s ", bad_ptr == t2 ? "PASSED" : "FAILED"); + + char*c1 = 1 + sizeof(tab1) + (char*)tab1; + char*c2 = 1 + sizeof(tab2) + (char*)tab2; + printf("%s ", bad_ptr == c1 ? "PASSED" : "FAILED"); + printf("%s ", bad_ptr == c2 ? "PASSED" : "FAILED"); + + int *i1 = tab1[-1]; + int *i2 = tab2[-1]; + printf("%s ", bad_ptr == i1 ? "PASSED" : "FAILED"); + printf("%s ", bad_ptr == i2 ? "PASSED" : "FAILED"); + + int *x1 = tab1[size1 * size2 + 1]; + int *x2 = tab2[10 + 1]; + printf("%s ", bad_ptr == x1 ? "PASSED" : "FAILED"); + printf("%s ", bad_ptr == x2 ? "PASSED" : "FAILED"); + } else { + printf("PASSED PASSED PASSED PASSED PASSED PASSED PASSED PASSED "); + } + printf("\n"); +#endif +} + +#ifndef __TINYC__ +typedef __SIZE_TYPE__ uintptr_t; +#endif + +void sizeof_test(void) +{ + int a; + int **ptr; + + printf("sizeof(int) = %d\n", sizeof(int)); + printf("sizeof(unsigned int) = %d\n", sizeof(unsigned int)); + printf("sizeof(long) = %d\n", sizeof(long)); + printf("sizeof(unsigned long) = %d\n", sizeof(unsigned long)); + printf("sizeof(short) = %d\n", sizeof(short)); + printf("sizeof(unsigned short) = %d\n", sizeof(unsigned short)); + printf("sizeof(char) = %d\n", sizeof(char)); + printf("sizeof(unsigned char) = %d\n", sizeof(unsigned char)); + printf("sizeof(func) = %d\n", sizeof sizeof_test()); + a = 1; + printf("sizeof(a++) = %d\n", sizeof a++); + printf("a=%d\n", a); + ptr = NULL; + printf("sizeof(**ptr) = %d\n", sizeof (**ptr)); + + /* The type of sizeof should be as large as a pointer, actually + it should be size_t. */ + printf("sizeof(sizeof(int) = %d\n", sizeof(sizeof(int))); + uintptr_t t = 1; + uintptr_t t2; + /* Effectively <<32, but defined also on 32bit machines. */ + t <<= 16; + t <<= 16; + t++; + /* This checks that sizeof really can be used to manipulate + uintptr_t objects, without truncation. */ + t2 = t & -sizeof(uintptr_t); + printf ("%lu %lu\n", t, t2); + + /* some alignof tests */ + printf("__alignof__(int) = %d\n", __alignof__(int)); + printf("__alignof__(unsigned int) = %d\n", __alignof__(unsigned int)); + printf("__alignof__(short) = %d\n", __alignof__(short)); + printf("__alignof__(unsigned short) = %d\n", __alignof__(unsigned short)); + printf("__alignof__(char) = %d\n", __alignof__(char)); + printf("__alignof__(unsigned char) = %d\n", __alignof__(unsigned char)); + printf("__alignof__(func) = %d\n", __alignof__ sizeof_test()); + + /* sizes of VLAs need to be evaluated even inside sizeof: */ + a = 2; + printf("sizeof(char[1+2*a]) = %d\n", sizeof(char[1+2*a])); + /* And checking if sizeof compound literal works. Parenthesized: */ + printf("sizeof( (struct {int i; int j;}){4,5} ) = %d\n", + sizeof( (struct {int i; int j;}){4,5} )); + /* And as direct sizeof argument (as unary expression): */ + printf("sizeof (struct {short i; short j;}){4,5} = %d\n", + sizeof (struct {short i; short j;}){4,5} ); + + /* sizeof(x && y) should be sizeof(int), even if constant + evaluating is possible. */ + printf("sizeof(t && 0) = %d\n", sizeof(t && 0)); + printf("sizeof(1 && 1) = %d\n", sizeof(1 && 1)); + printf("sizeof(t || 1) = %d\n", sizeof(t || 1)); + printf("sizeof(0 || 0) = %d\n", sizeof(0 || 0)); +} + +void typeof_test(void) +{ + double a; + typeof(a) b; + typeof(float) c; + + a = 1.5; + b = 2.5; + c = 3.5; + printf("a=%f b=%f c=%f\n", a, b, c); +} + + +struct hlist_node; +struct hlist_head { + struct hlist_node *first, *last; +}; + +void consume_ulong (unsigned long i) +{ + i = 0; +} + +void statement_expr_test(void) +{ + int a, i; + + /* Basic stmt expr test */ + a = 0; + for(i=0;i<10;i++) { + a += 1 + + ( { int b, j; + b = 0; + for(j=0;j<5;j++) + b += j; b; + } ); + } + printf("a=%d\n", a); + + /* Test that symbols aren't freed prematurely. + With SYM_DEBUG valgrind will show a read from a freed + symbol, and tcc will show an (invalid) warning on the initialization + of 'ptr' below, if symbols are popped after the stmt expr. */ + void *v = (void*)39; + typeof(({ + (struct hlist_node *)v; + })) x; + typeof (x) + ptr = (struct hlist_node *)v; + + /* This part used to segfault when symbols were popped prematurely. + The symbols for the static local would be overwritten with + helper symbols from the pre-processor expansions in between. */ +#define some_attr __attribute__((aligned(1))) +#define tps(str) ({ \ + static const char *t some_attr = str; \ + t; \ + }) + printf ("stmtexpr: %s %s\n", + tps("somerandomlongstring"), + tps("anotherlongstring")); + + /* Test that the three decls of 't' don't interact. */ + int t = 40; + int b = ({ int t = 41; t; }); + int c = ({ int t = 42; t; }); + + /* Test that aggregate return values work. */ + struct hlist_head h + = ({ + typedef struct hlist_head T; + long pre = 48; + T t = { (void*)43, (void*)44 }; + long post = 49; + t; + }); + printf ("stmtexpr: %d %d %d\n", t, b, c); + printf ("stmtexpr: %ld %ld\n", (long)h.first, (long)h.last); + + /* Test that we can give out addresses of local labels. */ + consume_ulong(({ __label__ __here; __here: (unsigned long)&&__here; })); +} + +void local_label_test(void) +{ + int a; + goto l1; + l2: + a = 1 + ({ + __label__ l1, l2, l3, l4; + goto l1; + l4: + printf("aa1\n"); + goto l3; + l2: + printf("aa3\n"); + goto l4; + l1: + printf("aa2\n"); + goto l2; + l3:; + 1; + }); + printf("a=%d\n", a); + return; + l4: + printf("bb1\n"); + goto l2; + l1: + printf("bb2\n"); + goto l4; +} + +/* inline assembler test */ +#if defined(__i386__) || defined(__x86_64__) + +/* from linux kernel */ +static char * strncat1(char * dest,const char * src,size_t count) +{ +long d0, d1, d2, d3; +__asm__ __volatile__( + "repne\n\t" + "scasb\n\t" + "dec %1\n\t" + "mov %8,%3\n" + "1:\tdec %3\n\t" + "js 2f\n\t" + "lodsb\n\t" + "stosb\n\t" + "testb %%al,%%al\n\t" + "jne 1b\n" + "2:\txor %2,%2\n\t" + "stosb" + : "=&S" (d0), "=&D" (d1), "=&a" (d2), "=&c" (d3) + : "0" (src),"1" (dest),"2" (0),"3" (0xffffffff), "g" (count) + : "memory"); +return dest; +} + +static char * strncat2(char * dest,const char * src,size_t count) +{ +long d0, d1, d2, d3; +__asm__ __volatile__( + "repne scasb\n\t" /* one-line repne prefix + string op */ + "dec %1\n\t" + "mov %8,%3\n" + "1:\tdec %3\n\t" + "js 2f\n\t" + "lodsb\n\t" + "stosb\n\t" + "testb %%al,%%al\n\t" + "jne 1b\n" + "2:\txor %2,%2\n\t" + "stosb" + : "=&S" (d0), "=&D" (d1), "=&a" (d2), "=&c" (d3) + : "0" (src),"1" (dest),"2" (0),"3" (0xffffffff), "g" (count) + : "memory"); +return dest; +} + +static inline void * memcpy1(void * to, const void * from, size_t n) +{ +long d0, d1, d2; +__asm__ __volatile__( + "rep ; movsl\n\t" + "testb $2,%b4\n\t" + "je 1f\n\t" + "movsw\n" + "1:\ttestb $1,%b4\n\t" + "je 2f\n\t" + "movsb\n" + "2:" + : "=&c" (d0), "=&D" (d1), "=&S" (d2) + :"0" (n/4), "q" (n),"1" ((long) to),"2" ((long) from) + : "memory"); +return (to); +} + +static inline void * memcpy2(void * to, const void * from, size_t n) +{ +long d0, d1, d2; +__asm__ __volatile__( + "rep movsl\n\t" /* one-line rep prefix + string op */ + "testb $2,%b4\n\t" + "je 1f\n\t" + "movsw\n" + "1:\ttestb $1,%b4\n\t" + "je 2f\n\t" + "movsb\n" + "2:" + : "=&c" (d0), "=&D" (d1), "=&S" (d2) + :"0" (n/4), "q" (n),"1" ((long) to),"2" ((long) from) + : "memory"); +return (to); +} + +static __inline__ void sigaddset1(unsigned int *set, int _sig) +{ + __asm__("btsl %1,%0" : "=m"(*set) : "Ir"(_sig - 1) : "cc"); +} + +static __inline__ void sigdelset1(unsigned int *set, int _sig) +{ + asm("btrl %1,%0" : "=m"(*set) : "Ir"(_sig - 1) : "cc", "flags"); +} + +static __inline__ __const__ unsigned int swab32(unsigned int x) +{ + __asm__("xchgb %b0,%h0\n\t" /* swap lower bytes */ + "rorl $16,%0\n\t" /* swap words */ + "xchgb %b0,%h0" /* swap higher bytes */ + :"=" "q" (x) + : "0" (x)); + return x; +} + +static __inline__ unsigned long long mul64(unsigned int a, unsigned int b) +{ + unsigned long long res; +#ifdef __x86_64__ + /* Using the A constraint is wrong (it means rdx:rax, which is too large) + but still test the 32bit->64bit mull. */ + unsigned int resh, resl; + __asm__("mull %2" : "=a" (resl), "=d" (resh) : "a" (a), "r" (b)); + res = ((unsigned long long)resh << 32) | resl; +#else + __asm__("mull %2" : "=A" (res) : "a" (a), "r" (b)); +#endif + return res; +} + +static __inline__ unsigned long long inc64(unsigned long long a) +{ + unsigned long long res; +#ifdef __x86_64__ + /* Using the A constraint is wrong, and increments are tested + elsewhere. */ + res = a + 1; +#else + __asm__("addl $1, %%eax ; adcl $0, %%edx" : "=A" (res) : "A" (a)); +#endif + return res; +} + +struct struct123 { + int a; + int b; +}; +struct struct1231 { + unsigned long addr; +}; + +unsigned long mconstraint_test(struct struct1231 *r) +{ + unsigned long ret; + unsigned int a[2]; + a[0] = 0; + __asm__ volatile ("lea %2,%0; movl 4(%0),%k0; addl %2,%k0; movl $51,%2; movl $52,4%2; movl $63,%1" + : "=&r" (ret), "=m" (a) + : "m" (*(struct struct123 *)r->addr)); + return ret + a[0]; +} + +#ifdef __x86_64__ +int fls64(unsigned long long x) +{ + int bitpos = -1; + asm("bsrq %1,%q0" + : "+r" (bitpos) + : "rm" (x)); + return bitpos + 1; +} +#endif + +void other_constraints_test(void) +{ + unsigned long ret; + int var; +#ifndef _WIN64 + __asm__ volatile ("mov %P1,%0" : "=r" (ret) : "p" (&var)); + printf ("oc1: %d\n", ret == (unsigned long)&var); +#endif +} + +#ifndef _WIN32 +/* Test global asm blocks playing with aliases. */ +void base_func(void) +{ + printf ("asmc: base\n"); +} + +extern void override_func1 (void); +extern void override_func2 (void); + +asm(".weak override_func1\n.set override_func1, base_func"); +asm(".set override_func1, base_func"); +asm(".set override_func2, base_func"); + +void override_func2 (void) +{ + printf ("asmc: override2\n"); +} + +/* This checks a construct used by the linux kernel to encode + references to strings by PC relative references. */ +extern int bug_table[] __attribute__((section("__bug_table"))); +char * get_asm_string (void) +{ + extern int some_symbol; + asm volatile (".globl some_symbol\n" + "jmp .+6\n" + "1:\n" + "some_symbol: .long 0\n" + ".pushsection __bug_table, \"a\"\n" + ".globl bug_table\n" + "bug_table:\n" + /* The first entry (1b-2b) is unused in this test, + but we include it to check if cross-section + PC-relative references work. */ + "2:\t.long 1b - 2b, %c0 - 2b\n" + ".popsection\n" : : "i" ("A string")); + char * str = ((char*)bug_table) + bug_table[1]; + return str; +} + +/* This checks another constructs with local labels. */ +extern unsigned char alld_stuff[]; +asm(".data\n" + ".byte 41\n" + "alld_stuff:\n" + "661:\n" + ".byte 42\n" + "662:\n" + ".pushsection .data.ignore\n" + ".long 661b - .\n" /* This reference to 661 generates an external sym + which shouldn't somehow overwrite the offset that's + already determined for it. */ + ".popsection\n" + ".byte 662b - 661b\n" /* So that this value is undeniably 1. */); + +void asm_local_label_diff (void) +{ + printf ("asm_local_label_diff: %d %d\n", alld_stuff[0], alld_stuff[1]); +} + +/* This checks that static local variables are available from assembler. */ +void asm_local_statics (void) +{ + static int localint = 41; + asm("incl %0" : "+m" (localint)); + printf ("asm_local_statics: %d\n", localint); +} +#endif + +static +unsigned int set; + +void fancy_copy (unsigned *in, unsigned *out) +{ + asm volatile ("" : "=r" (*out) : "0" (*in)); +} + +void fancy_copy2 (unsigned *in, unsigned *out) +{ + asm volatile ("mov %0,(%1)" : : "r" (*in), "r" (out) : "memory"); +} + +#if defined __x86_64__ && !defined _WIN64 +void clobber_r12(void) +{ + asm volatile("mov $1, %%r12" ::: "r12"); +} +#endif + +void test_high_clobbers(void) +{ +#if defined __x86_64__ && !defined _WIN64 + register long val asm("r12"); + long val2; + /* This tests if asm clobbers correctly save/restore callee saved + registers if they are clobbered and if it's the high 8 x86-64 + registers. This is fragile for GCC as the constraints do not + correctly capture the data flow, but good enough for us. */ + asm volatile("mov $0x4542, %%r12" : "=r" (val):: "memory"); + clobber_r12(); + asm volatile("mov %%r12, %0" : "=r" (val2) : "r" (val): "memory"); + printf("asmhc: 0x%x\n", val2); +#endif +} + +static long cpu_number; +void trace_console(long len, long len2) +{ +#ifdef __x86_64__ + /* This generated invalid code when the emission of the switch + table isn't disabled. The asms are necessary to show the bug, + normal statements don't work (they need to generate some code + even under nocode_wanted, which normal statements don't do, + but asms do). Also at least these number of cases is necessary + to generate enough "random" bytes. They ultimately are enough + to create invalid instruction patterns to which the first + skip-to-decision-table jump jumps. If decision table emission + is disabled all of this is no problem. + + It also is necessary that the switches are in a statement expression + (which has the property of not being enterable from outside. no + matter what). */ + if (0 + && + ({ + long pscr_ret__; + switch(len) { + case 4: + { + long pfo_ret__; + switch (len2) { + case 8: printf("bla"); pfo_ret__ = 42; break; + } + pscr_ret__ = pfo_ret__; + } + break; + case 8: + { + long pfo_ret__; + switch (len2) { + case 1:asm("movq %1,%0": "=r" (pfo_ret__) : "m" (cpu_number)); break; + case 2:asm("movq %1,%0": "=r" (pfo_ret__) : "m" (cpu_number)); break; + case 4:asm("movq %1,%0": "=r" (pfo_ret__) : "m" (cpu_number)); break; + case 8:asm("movq %1,%0": "=r" (pfo_ret__) : "m" (cpu_number)); break; + default: printf("impossible\n"); + } + pscr_ret__ = pfo_ret__; + }; + break; + } + pscr_ret__; + })) + { + printf("huh?\n"); + } +#endif +} + +void test_asm_dead_code(void) +{ + long rdi; + /* Try to make sure that xdi contains a zero, and hence will + lead to a segfault if the next asm is evaluated without + arguments being set up. */ + asm volatile ("" : "=D" (rdi) : "0" (0)); + (void)sizeof (({ + int var; + /* This shouldn't trigger a segfault, either the argument + registers need to be set up and the asm emitted despite + this being in an unevaluated context, or both the argument + setup _and_ the asm emission need to be suppressed. The latter + is better. Disabling asm code gen when suppression is on + also fixes the above trace_console bug, but that came earlier + than asm suppression. */ + asm volatile ("movl $0,(%0)" : : "D" (&var) : "memory"); + var; + })); +} + +void asm_test(void) +{ + char buf[128]; + unsigned int val, val2; + struct struct123 s1; + struct struct1231 s2 = { (unsigned long)&s1 }; + /* Hide the outer base_func, but check later that the inline + asm block gets the outer one. */ + int base_func = 42; + void override_func3 (void); + unsigned long asmret; +#ifdef BOOL_ISOC99 + _Bool somebool; +#endif + register int regvar asm("%esi"); + + printf("inline asm:\n"); + + // parse 0x1E-1 as 3 tokens in asm mode + asm volatile ("mov $0x1E-1,%eax"); + + /* test the no operand case */ + asm volatile ("xorl %eax, %eax"); + + memcpy1(buf, "hello", 6); + strncat1(buf, " worldXXXXX", 3); + printf("%s\n", buf); + + memcpy2(buf, "hello", 6); + strncat2(buf, " worldXXXXX", 3); + printf("%s\n", buf); + + /* 'A' constraint test */ + printf("mul64=0x%Lx\n", mul64(0x12345678, 0xabcd1234)); + printf("inc64=0x%Lx\n", inc64(0x12345678ffffffff)); + + s1.a = 42; + s1.b = 43; + printf("mconstraint: %d", mconstraint_test(&s2)); + printf(" %d %d\n", s1.a, s1.b); + other_constraints_test(); + set = 0xff; + sigdelset1(&set, 2); + sigaddset1(&set, 16); + /* NOTE: we test here if C labels are correctly restored after the + asm statement */ + goto label1; + label2: + __asm__("btsl %1,%0" : "=m"(set) : "Ir"(20) : "cc"); + printf("set=0x%x\n", set); + val = 0x01020304; + printf("swab32(0x%08x) = 0x%0x\n", val, swab32(val)); +#ifndef _WIN32 + override_func1(); + override_func2(); + /* The base_func ref from the following inline asm should find + the global one, not the local decl from this function. */ + asm volatile(".weak override_func3\n.set override_func3, base_func"); + override_func3(); + printf("asmstr: %s\n", get_asm_string()); + asm_local_label_diff(); + asm_local_statics(); +#endif + /* Check that we can also load structs of appropriate layout + into registers. */ + asm volatile("" : "=r" (asmret) : "0"(s2)); + if (asmret != s2.addr) + printf("asmstr: failed\n"); +#ifdef BOOL_ISOC99 + /* Check that the typesize correctly sets the register size to + 8 bit. */ + asm volatile("cmp %1,%2; sete %0" : "=a"(somebool) : "r"(1), "r"(2)); + if (!somebool) + printf("asmbool: failed\n"); +#endif + val = 43; + fancy_copy (&val, &val2); + printf ("fancycpy(%d)=%d\n", val, val2); + val = 44; + fancy_copy2 (&val, &val2); + printf ("fancycpy2(%d)=%d\n", val, val2); + asm volatile ("mov $0x4243, %%esi" : "=r" (regvar)); + printf ("regvar=%x\n", regvar); + test_high_clobbers(); + trace_console(8, 8); + test_asm_dead_code(); + return; + label1: + goto label2; +} + +#else + +void asm_test(void) +{ +} + +#endif + +#define COMPAT_TYPE(type1, type2) \ +{\ + printf("__builtin_types_compatible_p(%s, %s) = %d\n", #type1, #type2, \ + __builtin_types_compatible_p (type1, type2));\ +} + +int constant_p_var; + +void builtin_test(void) +{ + short s; + int i; + long long ll; +#if GCC_MAJOR >= 3 + COMPAT_TYPE(int, int); + COMPAT_TYPE(int, unsigned int); + COMPAT_TYPE(int, char); + COMPAT_TYPE(int, const int); + COMPAT_TYPE(int, volatile int); + COMPAT_TYPE(int *, int *); + COMPAT_TYPE(int *, void *); + COMPAT_TYPE(int *, const int *); + COMPAT_TYPE(char *, unsigned char *); + COMPAT_TYPE(char *, signed char *); + COMPAT_TYPE(char *, char *); +/* space is needed because tcc preprocessor introduces a space between each token */ + COMPAT_TYPE(char * *, void *); +#endif + printf("res = %d\n", __builtin_constant_p(1)); + printf("res = %d\n", __builtin_constant_p(1 + 2)); + printf("res = %d\n", __builtin_constant_p(&constant_p_var)); + printf("res = %d\n", __builtin_constant_p(constant_p_var)); + printf("res = %d\n", __builtin_constant_p(100000 / constant_p_var)); + s = 1; + ll = 2; + i = __builtin_choose_expr (1 != 0, ll, s); + printf("bce: %d\n", i); + i = __builtin_choose_expr (1 != 1, ll, s); + printf("bce: %d\n", i); + i = sizeof (__builtin_choose_expr (1, ll, s)); + printf("bce: %d\n", i); + i = sizeof (__builtin_choose_expr (0, ll, s)); + printf("bce: %d\n", i); + + //printf("bera: %p\n", __builtin_extract_return_addr((void*)43)); +} + +#ifndef _WIN32 +extern int __attribute__((weak)) weak_f1(void); +extern int __attribute__((weak)) weak_f2(void); +extern int weak_f3(void); +extern int __attribute__((weak)) weak_v1; +extern int __attribute__((weak)) weak_v2; +extern int weak_v3; + +extern int (*weak_fpa)() __attribute__((weak)); +extern int __attribute__((weak)) (*weak_fpb)(); +extern __attribute__((weak)) int (*weak_fpc)(); + +extern int weak_asm_f1(void) asm("weak_asm_f1x") __attribute((weak)); +extern int __attribute((weak)) weak_asm_f2(void) asm("weak_asm_f2x") ; +extern int __attribute((weak)) weak_asm_f3(void) asm("weak_asm_f3x") __attribute((weak)); +extern int weak_asm_v1 asm("weak_asm_v1x") __attribute((weak)); +extern int __attribute((weak)) weak_asm_v2 asm("weak_asm_v2x") ; +extern int __attribute((weak)) weak_asm_v3(void) asm("weak_asm_v3x") __attribute((weak)); + +static const size_t dummy = 0; +extern __typeof(dummy) weak_dummy1 __attribute__((weak, alias("dummy"))); +extern __typeof(dummy) __attribute__((weak, alias("dummy"))) weak_dummy2; +extern __attribute__((weak, alias("dummy"))) __typeof(dummy) weak_dummy3; + +int some_lib_func(void); +int dummy_impl_of_slf(void) { return 444; } +int some_lib_func(void) __attribute__((weak, alias("dummy_impl_of_slf"))); + +int weak_toolate() __attribute__((weak)); +int weak_toolate() { return 0; } + +void __attribute__((weak)) weak_test(void) +{ + printf("weak_f1=%d\n", weak_f1 ? weak_f1() : 123); + printf("weak_f2=%d\n", weak_f2 ? weak_f2() : 123); + printf("weak_f3=%d\n", weak_f3 ? weak_f3() : 123); + printf("weak_v1=%d\n",&weak_v1 ? weak_v1 : 123); + printf("weak_v2=%d\n",&weak_v2 ? weak_v2 : 123); + printf("weak_v3=%d\n",&weak_v3 ? weak_v3 : 123); + + printf("weak_fpa=%d\n",&weak_fpa ? weak_fpa() : 123); + printf("weak_fpb=%d\n",&weak_fpb ? weak_fpb() : 123); + printf("weak_fpc=%d\n",&weak_fpc ? weak_fpc() : 123); + + printf("weak_asm_f1=%d\n", weak_asm_f1 != NULL); + printf("weak_asm_f2=%d\n", weak_asm_f2 != NULL); + printf("weak_asm_f3=%d\n", weak_asm_f3 != NULL); + printf("weak_asm_v1=%d\n",&weak_asm_v1 != NULL); + printf("weak_asm_v2=%d\n",&weak_asm_v2 != NULL); + printf("weak_asm_v3=%d\n",&weak_asm_v3 != NULL); + printf("some_lib_func=%d\n", &some_lib_func ? some_lib_func() : 0); +} + +int __attribute__((weak)) weak_f2() { return 222; } +int __attribute__((weak)) weak_f3() { return 333; } +int __attribute__((weak)) weak_v2 = 222; +int __attribute__((weak)) weak_v3 = 333; +#endif + +void const_func(const int a) +{ +} + +void const_warn_test(void) +{ + const_func(1); +} + +struct condstruct { + int i; +}; + +int getme (struct condstruct *s, int i) +{ + int i1 = (i == 0 ? 0 : s)->i; + int i2 = (i == 0 ? s : 0)->i; + int i3 = (i == 0 ? (void*)0 : s)->i; + int i4 = (i == 0 ? s : (void*)0)->i; + return i1 + i2 + i3 + i4; +} + +struct global_data +{ + int a[40]; + int *b[40]; +}; + +struct global_data global_data; + +int global_data_getstuff (int *, int); + +void global_data_callit (int i) +{ + *global_data.b[i] = global_data_getstuff (global_data.b[i], 1); +} + +int global_data_getstuff (int *p, int i) +{ + return *p + i; +} + +void global_data_test (void) +{ + global_data.a[0] = 42; + global_data.b[0] = &global_data.a[0]; + global_data_callit (0); + printf ("%d\n", global_data.a[0]); +} + +struct cmpcmpS +{ + unsigned char fill : 3; + unsigned char b1 : 1; + unsigned char b2 : 1; + unsigned char fill2 : 3; +}; + +int glob1, glob2, glob3; + +void compare_comparisons (struct cmpcmpS *s) +{ + if (s->b1 != (glob1 == glob2) + || (s->b2 != (glob1 == glob3))) + printf ("comparing comparisons broken\n"); +} + +void cmp_comparison_test(void) +{ + struct cmpcmpS s; + s.b1 = 1; + glob1 = 42; glob2 = 42; + s.b2 = 0; + glob3 = 43; + compare_comparisons (&s); +} + +int fcompare (double a, double b, int code) +{ + switch (code) { + case 0: return a == b; + case 1: return a != b; + case 2: return a < b; + case 3: return a >= b; + case 4: return a > b; + case 5: return a <= b; + } +} + +void math_cmp_test(void) +{ + double nan = 0.0/0.0; + double one = 1.0; + double two = 2.0; + int comp = 0; +#define bug(a,b,op,iop,part) printf("Test broken: %s %s %s %s %d\n", #a, #b, #op, #iop, part) + + /* This asserts that "a op b" is _not_ true, but "a iop b" is true. + And it does this in various ways so that all code generation paths + are checked (generating inverted tests, or non-inverted tests, or + producing a 0/1 value without jumps (that's done in the fcompare + function). */ +#define FCMP(a,b,op,iop,code) \ + if (fcompare (a,b,code)) \ + bug (a,b,op,iop,1); \ + if (a op b) \ + bug (a,b,op,iop,2); \ + if (a iop b) \ + ; \ + else \ + bug (a,b,op,iop,3); \ + if ((a op b) || comp) \ + bug (a,b,op,iop,4); \ + if ((a iop b) || comp) \ + ; \ + else \ + bug (a,b,op,iop,5); + + /* Equality tests. */ + FCMP(nan, nan, ==, !=, 0); + FCMP(one, two, ==, !=, 0); + FCMP(one, one, !=, ==, 1); + /* Non-equality is a bit special. */ + if (!fcompare (nan, nan, 1)) + bug (nan, nan, !=, ==, 6); + + /* Relational tests on numbers. */ + FCMP(two, one, <, >=, 2); + FCMP(one, two, >=, <, 3); + FCMP(one, two, >, <=, 4); + FCMP(two, one, <=, >, 5); + + /* Relational tests on NaNs. Note that the inverse op here is + always !=, there's no operator in C that is equivalent to !(a < b), + when NaNs are involved, same for the other relational ops. */ + FCMP(nan, nan, <, !=, 2); + FCMP(nan, nan, >=, !=, 3); + FCMP(nan, nan, >, !=, 4); + FCMP(nan, nan, <=, !=, 5); +} + +double get100 () { return 100.0; } + +void callsave_test(void) +{ +#if defined __i386__ || defined __x86_64__ || defined __arm__ + int i, s; double *d; double t; + s = sizeof (double); + printf ("callsavetest: %d\n", s); + d = alloca (sizeof(double)); + d[0] = 10.0; + /* x86-64 had a bug were the next call to get100 would evict + the lvalue &d[0] as VT_LLOCAL, and the reload would be done + in int type, not pointer type. When alloca returns a pointer + with the high 32 bit set (which is likely on x86-64) the access + generates a segfault. */ + i = d[0] > get100 (); + printf ("%d\n", i); +#endif +} + + +void bfa3(ptrdiff_t str_offset) +{ + printf("bfa3: %s\n", (char *)__builtin_frame_address(3) + str_offset); +} +void bfa2(ptrdiff_t str_offset) +{ + printf("bfa2: %s\n", (char *)__builtin_frame_address(2) + str_offset); + bfa3(str_offset); +} +void bfa1(ptrdiff_t str_offset) +{ + printf("bfa1: %s\n", (char *)__builtin_frame_address(1) + str_offset); + bfa2(str_offset); +} + +void builtin_frame_address_test(void) +{ +/* builtin_frame_address fails on ARM with gcc which make test3 fail */ +#ifndef __arm__ + char str[] = "__builtin_frame_address"; + char *fp0 = __builtin_frame_address(0); + + printf("str: %s\n", str); + bfa1(str-fp0); +#endif +} + +char via_volatile (char i) +{ + char volatile vi; + vi = i; + return vi; +} + +struct __attribute__((__packed__)) Spacked { + char a; + short b; + int c; +}; +struct Spacked spacked; +typedef struct __attribute__((__packed__)) { + char a; + short b; + int c; +} Spacked2; +Spacked2 spacked2; +typedef struct Spacked3_s { + char a; + short b; + int c; +} __attribute__((__packed__)) Spacked3; +Spacked3 spacked3; +struct gate_struct64 { + unsigned short offset_low; + unsigned short segment; + unsigned ist : 3, zero0 : 5, type : 5, dpl : 2, p : 1; + unsigned short offset_middle; + unsigned offset_high; + unsigned zero1; +} __attribute__((packed)); +typedef struct gate_struct64 gate_desc; +gate_desc a_gate_desc; +void attrib_test(void) +{ +#ifndef _WIN32 + printf("attr: %d %d %d %d\n", sizeof(struct Spacked), + sizeof(spacked), sizeof(Spacked2), sizeof(spacked2)); + printf("attr: %d %d\n", sizeof(Spacked3), sizeof(spacked3)); + printf("attr: %d %d\n", sizeof(gate_desc), sizeof(a_gate_desc)); +#endif +} +extern __attribute__((__unused__)) char * __attribute__((__unused__)) * +strange_attrib_placement (void); + +void * __attribute__((__unused__)) get_void_ptr (void *a) +{ + return a; +} + +/* This part checks for a bug in TOK_GET (used for inline expansion), + where the large long long constant left the the high bits set for + the integer constant token. */ +static inline +int __get_order(unsigned long long size) +{ + int order; + size -= 0xffff880000000000ULL; // this const left high bits set in the token + { + struct S { int i : 1; } s; // constructed for this '1' + } + order = size; + return order; +} + +/* This just forces the above inline function to be actually emitted. */ +int force_get_order(unsigned long s) +{ + return __get_order(s); +} diff --git a/tinyc/tests/tcctest.h b/tinyc/tests/tcctest.h new file mode 100644 index 000000000..b301c7c16 --- /dev/null +++ b/tinyc/tests/tcctest.h @@ -0,0 +1,9 @@ +static inline const char *get_basefile_from_header(void) +{ + return __BASE_FILE__; +} + +static inline const char *get_file_from_header(void) +{ + return __FILE__; +} diff --git a/tinyc/tests/testfp.c b/tinyc/tests/testfp.c new file mode 100644 index 000000000..63342b422 --- /dev/null +++ b/tinyc/tests/testfp.c @@ -0,0 +1,510 @@ +/* + * Test 128-bit floating-point arithmetic on arm64: + * build with two different compilers and compare the output. + * + * Copyright (c) 2015 Edmund Grimley Evans + * + * Copying and distribution of this file, with or without modification, + * are permitted in any medium without royalty provided the copyright + * notice and this notice are preserved. This file is offered as-is, + * without any warranty. + */ + +#include +#include +#include +#include + +#define check(x) ((x) ? (void)0 : check_fail(#x, __FILE__, __LINE__)) + +void check_fail(const char *assertion, const char *file, unsigned int line) +{ + printf("%s:%d: Check (%s) failed.", file, line, assertion); + exit(1); +} + +typedef struct { + unsigned long long x0, x1; +} u128_t; + +float copy_fi(uint32_t x) +{ + float f; + memcpy(&f, &x, 4); + return f; +} + +double copy_di(uint64_t x) +{ + double f; + memcpy(&f, &x, 8); + return f; +} + +long double copy_ldi(u128_t x) +{ + long double f; + memcpy(&f, &x, 16); + return f; +} + +uint32_t copy_if(float f) +{ + uint32_t x; + memcpy(&x, &f, 4); + return x; +} + +uint64_t copy_id(double f) +{ + uint64_t x; + memcpy(&x, &f, 8); + return x; +} + +u128_t copy_ild(long double f) +{ + u128_t x; + memcpy(&x, &f, 16); + return x; +} + +long double make(int sgn, int exp, uint64_t high, uint64_t low) +{ + u128_t x = { low, + (0x0000ffffffffffff & high) | + (0x7fff000000000000 & (uint64_t)exp << 48) | + (0x8000000000000000 & (uint64_t)sgn << 63) }; + return copy_ldi(x); +} + +void cmp(long double a, long double b) +{ + u128_t ax = copy_ild(a); + u128_t bx = copy_ild(b); + int eq = (a == b); + int ne = (a != b); + int lt = (a < b); + int le = (a <= b); + int gt = (a > b); + int ge = (a >= b); + + check(eq == 0 || eq == 1); + check(lt == 0 || lt == 1); + check(gt == 0 || gt == 1); + check(ne == !eq && le == (lt | eq) && ge == (gt | eq)); + check(eq + lt + gt < 2); + + printf("cmp %016llx%016llx %016llx%016llx %d %d %d\n", + ax.x1, ax.x0, bx.x1, bx.x0, lt, eq, gt); +} + +void cmps(void) +{ + int i, j; + + for (i = 0; i < 2; i++) + for (j = 0; j < 2; j++) + cmp(make(i, 0, 0, 0), make(j, 0, 0, 0)); + + for (i = 0; i < 2; i++) { + for (j = 0; j < 64; j++) { + long double f1 = make(i, 32767, (uint64_t)1 << j, 0); + long double f2 = make(i, 32767, 0, (uint64_t)1 << j); + cmp(f1, 0); + cmp(f2, 0); + cmp(0, f1); + cmp(0, f2); + } + } + + for (i = 0; i < 6; i++) + for (j = 0; j < 6; j++) + cmp(make(i & 1, i >> 1, 0, 0), + make(j & 1, j >> 1, 0, 0)); + + for (i = 0; i < 2; i++) { + for (j = 0; j < 2; j++) { + int a, b; + for (a = 0; a < 2; a++) { + for (b = 0; b < 2; b++) { + cmp(make(i, j, a, b), make(i, j, 0, 0)); + cmp(make(i, j, 0, 0), make(i, j, a, b)); + } + } + } + } +} + +void xop(const char *name, long double a, long double b, long double c) +{ + u128_t ax = copy_ild(a); + u128_t bx = copy_ild(b); + u128_t cx = copy_ild(c); + printf("%s %016llx%016llx %016llx%016llx %016llx%016llx\n", + name, ax.x1, ax.x0, bx.x1, bx.x0, cx.x1, cx.x0); +} + +void fadd(long double a, long double b) +{ + xop("add", a, b, a + b); +} + +void fsub(long double a, long double b) +{ + xop("sub", a, b, a - b); +} + +void fmul(long double a, long double b) +{ + xop("mul", a, b, a * b); +} + +void fdiv(long double a, long double b) +{ + xop("div", a, b, a / b); +} + +void nanz(void) +{ + // Check NaNs: + { + long double x[7]; + int i, j, n = 0; + x[n++] = make(0, 32000, 0x95132b76effc, 0xd79035214b4f8d53); + x[n++] = make(1, 32001, 0xbe71d7a51587, 0x30601c6815d6c3ac); + x[n++] = make(0, 32767, 0, 1); + x[n++] = make(0, 32767, (uint64_t)1 << 46, 0); + x[n++] = make(1, 32767, (uint64_t)1 << 47, 0); + x[n++] = make(1, 32767, 0x7596c7099ad5, 0xe25fed2c58f73fc9); + x[n++] = make(0, 32767, 0x835d143360f9, 0x5e315efb35630666); + check(n == sizeof(x) / sizeof(*x)); + for (i = 0; i < n; i++) { + for (j = 0; j < n; j++) { + fadd(x[i], x[j]); + fsub(x[i], x[j]); + fmul(x[i], x[j]); + fdiv(x[i], x[j]); + } + } + } + + // Check infinities and zeroes: + { + long double x[6]; + int i, j, n = 0; + x[n++] = make(1, 32000, 0x62acda85f700, 0x47b6c9f35edc4044); + x[n++] = make(0, 32001, 0x94b7abf55af7, 0x9f425fe354428e19); + x[n++] = make(0, 32767, 0, 0); + x[n++] = make(1, 32767, 0, 0); + x[n++] = make(0, 0, 0, 0); + x[n++] = make(1, 0, 0, 0); + check(n == sizeof(x) / sizeof(*x)); + for (i = 0; i < n; i++) { + for (j = 0; j < n; j++) { + fadd(x[i], x[j]); + fsub(x[i], x[j]); + fmul(x[i], x[j]); + fdiv(x[i], x[j]); + } + } + } +} + +void adds(void) +{ + // Check shifting and add/sub: + { + int i; + for (i = -130; i <= 130; i++) { + int s1 = (uint32_t)i % 3 < 1; + int s2 = (uint32_t)i % 5 < 2; + fadd(make(s1, 16384 , 0x502c065e4f71a65d, 0xd2f9bdb031f4f031), + make(s2, 16384 + i, 0xae267395a9bc1033, 0xb56b5800da1ba448)); + } + } + + // Check normalisation: + { + uint64_t a0 = 0xc6bab0a6afbef5ed; + uint64_t a1 = 0x4f84136c4a2e9b52; + int ee[] = { 0, 1, 10000 }; + int e, i; + for (e = 0; e < sizeof(ee) / sizeof(*ee); e++) { + int exp = ee[e]; + fsub(make(0, exp, a1, a0), make(0, 0, 0, 0)); + for (i = 63; i >= 0; i--) + fsub(make(0, exp, a1 | (uint64_t)1 << i >> 1, a0), + make(0, exp, a1 >> i << i, 0)); + for (i = 63; i >=0; i--) + fsub(make(0, exp, a1, a0 | (uint64_t)1 << i >> 1), + make(0, exp, a1, a0 >> i << i)); + } + } + + // Carry/overflow from rounding: + { + fadd(make(0, 114, -1, -1), make(0, 1, 0, 0)); + fadd(make(0, 32766, -1, -1), make(0, 32653, 0, 0)); + fsub(make(1, 32766, -1, -1), make(0, 32653, 0, 0)); + } +} + +void muls(void) +{ + int i, j; + + { + long double max = make(0, 32766, -1, -1); + long double min = make(0, 0, 0, 1); + fmul(max, max); + fmul(max, min); + fmul(min, min); + } + + for (i = 117; i > 0; i--) + fmul(make(0, 16268, 0x643dcea76edc, 0xe0877a598403627a), + make(i & 1, i, 0, 0)); + + fmul(make(0, 16383, -1, -3), make(0, 16383, 0, 1)); + // Round to next exponent: + fmul(make(0, 16383, -1, -2), make(0, 16383, 0, 1)); + // Round from subnormal to normal: + fmul(make(0, 1, -1, -1), make(0, 16382, 0, 0)); + + for (i = 0; i < 2; i++) + for (j = 0; j < 112; j++) + fmul(make(0, 16383, (uint64_t)1 << i, 0), + make(0, 16383, + j < 64 ? 0 : (uint64_t)1 << (j - 64), + j < 64 ? (uint64_t)1 << j : 0)); +} + +void divs(void) +{ + int i; + + { + long double max = make(0, 32766, -1, -1); + long double min = make(0, 0, 0, 1); + fdiv(max, max); + fdiv(max, min); + fdiv(min, max); + fdiv(min, min); + } + + for (i = 0; i < 64; i++) + fdiv(make(0, 16383, -1, -1), make(0, 16383, -1, -(uint64_t)1 << i)); + for (i = 0; i < 48; i++) + fdiv(make(0, 16383, -1, -1), make(0, 16383, -(uint64_t)1 << i, 0)); +} + +void cvtlsw(int32_t a) +{ + long double f = a; + u128_t x = copy_ild(f); + printf("cvtlsw %08lx %016llx%016llx\n", (long)(uint32_t)a, x.x1, x.x0); +} + +void cvtlsx(int64_t a) +{ + long double f = a; + u128_t x = copy_ild(f); + printf("cvtlsx %016llx %016llx%016llx\n", + (long long)(uint64_t)a, x.x1, x.x0); +} + +void cvtluw(uint32_t a) +{ + long double f = a; + u128_t x = copy_ild(f); + printf("cvtluw %08lx %016llx%016llx\n", (long)a, x.x1, x.x0); +} + +void cvtlux(uint64_t a) +{ + long double f = a; + u128_t x = copy_ild(f); + printf("cvtlux %016llx %016llx%016llx\n", (long long)a, x.x1, x.x0); +} + +void cvtil(long double a) +{ + u128_t x = copy_ild(a); + int32_t b1 = a; + int64_t b2 = a; + uint32_t b3 = a; + uint64_t b4 = a; + printf("cvtswl %016llx%016llx %08lx\n", + x.x1, x.x0, (long)(uint32_t)b1); + printf("cvtsxl %016llx%016llx %016llx\n", + x.x1, x.x0, (long long)(uint64_t)b2); + printf("cvtuwl %016llx%016llx %08lx\n", + x.x1, x.x0, (long)b3); + printf("cvtuxl %016llx%016llx %016llx\n", + x.x1, x.x0, (long long)b4); +} + +void cvtlf(float a) +{ + uint32_t ax = copy_if(a); + long double b = a; + u128_t bx = copy_ild(b); + printf("cvtlf %08lx %016llx%016llx\n", (long)ax, bx.x1, bx.x0); +} + +void cvtld(double a) +{ + uint64_t ax = copy_id(a); + long double b = a; + u128_t bx = copy_ild(b); + printf("cvtld %016llx %016llx%016llx\n", (long long)ax, bx.x1, bx.x0); +} + +void cvtfl(long double a) +{ + u128_t ax = copy_ild(a); + float b = a; + uint32_t bx = copy_if(b); + printf("cvtfl %016llx%016llx %08lx\n", ax.x1, ax.x0, (long)bx); +} + +void cvtdl(long double a) +{ + u128_t ax = copy_ild(a); + double b = a; + uint64_t bx = copy_id(b); + printf("cvtdl %016llx%016llx %016llx\n", ax.x1, ax.x0, (long long)bx); +} + +void cvts(void) +{ + int i, j; + + { + uint32_t x = 0xad040c5b; + cvtlsw(0); + for (i = 0; i < 31; i++) + cvtlsw(x >> (31 - i)); + for (i = 0; i < 31; i++) + cvtlsw(-(x >> (31 - i))); + cvtlsw(0x80000000); + } + { + uint64_t x = 0xb630a248cad9afd2; + cvtlsx(0); + for (i = 0; i < 63; i++) + cvtlsx(x >> (63 - i)); + for (i = 0; i < 63; i++) + cvtlsx(-(x >> (63 - i))); + cvtlsx(0x8000000000000000); + } + { + uint32_t x = 0xad040c5b; + cvtluw(0); + for (i = 0; i < 32; i++) + cvtluw(x >> (31 - i)); + } + { + uint64_t x = 0xb630a248cad9afd2; + cvtlux(0); + for (i = 0; i < 64; i++) + cvtlux(x >> (63 - i)); + } + + for (i = 0; i < 2; i++) { + cvtil(make(i, 32767, 0, 1)); + cvtil(make(i, 32767, (uint64_t)1 << 47, 0)); + cvtil(make(i, 32767, 123, 456)); + cvtil(make(i, 32767, 0, 0)); + cvtil(make(i, 16382, -1, -1)); + cvtil(make(i, 16383, -1, -1)); + cvtil(make(i, 16384, 0x7fffffffffff, -1)); + cvtil(make(i, 16384, 0x800000000000, 0)); + for (j = 0; j < 68; j++) + cvtil(make(i, 16381 + j, 0xd4822c0a10ec, 0x1fe2f8b2669f5c9d)); + } + + cvtlf(copy_fi(0x00000000)); + cvtlf(copy_fi(0x456789ab)); + cvtlf(copy_fi(0x7f800000)); + cvtlf(copy_fi(0x7f923456)); + cvtlf(copy_fi(0x7fdbcdef)); + cvtlf(copy_fi(0x80000000)); + cvtlf(copy_fi(0xabcdef12)); + cvtlf(copy_fi(0xff800000)); + cvtlf(copy_fi(0xff923456)); + cvtlf(copy_fi(0xffdbcdef)); + + cvtld(copy_di(0x0000000000000000)); + cvtld(copy_di(0x456789abcdef0123)); + cvtld(copy_di(0x7ff0000000000000)); + cvtld(copy_di(0x7ff123456789abcd)); + cvtld(copy_di(0x7ffabcdef1234567)); + cvtld(copy_di(0x8000000000000000)); + cvtld(copy_di(0xcdef123456789abc)); + cvtld(copy_di(0xfff0000000000000)); + cvtld(copy_di(0xfff123456789abcd)); + cvtld(copy_di(0xfffabcdef1234567)); + + for (i = 0; i < 2; i++) { \ + cvtfl(make(i, 0, 0, 0)); + cvtfl(make(i, 16232, -1, -1)); + cvtfl(make(i, 16233, 0, 0)); + cvtfl(make(i, 16233, 0, 1)); + cvtfl(make(i, 16383, 0xab0ffd000000, 0)); + cvtfl(make(i, 16383, 0xab0ffd000001, 0)); + cvtfl(make(i, 16383, 0xab0ffeffffff, 0)); + cvtfl(make(i, 16383, 0xab0fff000000, 0)); + cvtfl(make(i, 16383, 0xab0fff000001, 0)); + cvtfl(make(i, 16510, 0xfffffeffffff, -1)); + cvtfl(make(i, 16510, 0xffffff000000, 0)); + cvtfl(make(i, 16511, 0, 0)); + cvtfl(make(i, 32767, 0, 0)); + cvtfl(make(i, 32767, 0, 1)); + cvtfl(make(i, 32767, 0x4cbe01ac5f40, 0x75cee3c6afbb00b5)); + cvtfl(make(i, 32767, 0x800000000000, 1)); + cvtfl(make(i, 32767, 0xa11caaaf6a52, 0x696033e871eab099)); + } + + for (i = 0; i < 2; i++) { + cvtdl(make(i, 0, 0, 0)); + cvtdl(make(i, 15307, -1, -1)); + cvtdl(make(i, 15308, 0, 0)); + cvtdl(make(i, 15308, 0, 1)); + cvtdl(make(i, 16383, 0xabc123abc0ff, 0xe800000000000000)); + cvtdl(make(i, 16383, 0xabc123abc0ff, 0xe800000000000001)); + cvtdl(make(i, 16383, 0xabc123abc0ff, 0xf7ffffffffffffff)); + cvtdl(make(i, 16383, 0xabc123abc0ff, 0xf800000000000000)); + cvtdl(make(i, 16383, 0xabc123abc0ff, 0xf800000000000001)); + cvtdl(make(i, 17406, 0xffffffffffff, 0xf7ffffffffffffff)); + cvtdl(make(i, 17406, 0xffffffffffff, 0xf800000000000000)); + cvtdl(make(i, 17407, 0, 0)); + cvtdl(make(i, 32767, 0, 0)); + cvtdl(make(i, 32767, 0, 1)); + cvtdl(make(i, 32767, 0x4cbe01ac5f40, 0x75cee3c6afbb00b5)); + cvtdl(make(i, 32767, 0x800000000000, 1)); + cvtdl(make(i, 32767, 0xa11caaaf6a52, 0x696033e871eab099)); + } +} + +void tests(void) +{ + cmps(); + nanz(); + adds(); + muls(); + divs(); + cvts(); +} + +int main() +{ +#ifdef __aarch64__ + tests(); +#else + printf("This test program is intended for a little-endian architecture\n" + "with an IEEE-standard 128-bit long double.\n"); +#endif + return 0; +} diff --git a/tinyc/tests/tests2/00_assignment.c b/tinyc/tests/tests2/00_assignment.c new file mode 100644 index 000000000..c96109fdc --- /dev/null +++ b/tinyc/tests/tests2/00_assignment.c @@ -0,0 +1,18 @@ +#include + +int main() +{ + int a; + a = 42; + printf("%d\n", a); + + int b = 64; + printf("%d\n", b); + + int c = 12, d = 34; + printf("%d, %d\n", c, d); + + return 0; +} + +// vim: set expandtab ts=4 sw=3 sts=3 tw=80 : diff --git a/tinyc/tests/tests2/00_assignment.expect b/tinyc/tests/tests2/00_assignment.expect new file mode 100644 index 000000000..d4407f3fe --- /dev/null +++ b/tinyc/tests/tests2/00_assignment.expect @@ -0,0 +1,3 @@ +42 +64 +12, 34 diff --git a/tinyc/tests/tests2/01_comment.c b/tinyc/tests/tests2/01_comment.c new file mode 100644 index 000000000..a2e6bc63d --- /dev/null +++ b/tinyc/tests/tests2/01_comment.c @@ -0,0 +1,14 @@ +#include + +int main() +{ + printf("Hello\n"); + printf("Hello\n"); /* this is a comment */ printf("Hello\n"); + printf("Hello\n"); + // this is also a comment sayhello(); + printf("Hello\n"); + + return 0; +} + +// vim: set expandtab ts=4 sw=3 sts=3 tw=80 : diff --git a/tinyc/tests/tests2/01_comment.expect b/tinyc/tests/tests2/01_comment.expect new file mode 100644 index 000000000..b1387ad09 --- /dev/null +++ b/tinyc/tests/tests2/01_comment.expect @@ -0,0 +1,5 @@ +Hello +Hello +Hello +Hello +Hello diff --git a/tinyc/tests/tests2/02_printf.c b/tinyc/tests/tests2/02_printf.c new file mode 100644 index 000000000..4c34dd874 --- /dev/null +++ b/tinyc/tests/tests2/02_printf.c @@ -0,0 +1,18 @@ +#include + +int main() +{ + printf("Hello world\n"); + + int Count; + for (Count = -5; Count <= 5; Count++) + printf("Count = %d\n", Count); + + printf("String 'hello', 'there' is '%s', '%s'\n", "hello", "there"); + printf("Character 'A' is '%c'\n", 65); + printf("Character 'a' is '%c'\n", 'a'); + + return 0; +} + +// vim: set expandtab ts=4 sw=3 sts=3 tw=80 : diff --git a/tinyc/tests/tests2/02_printf.expect b/tinyc/tests/tests2/02_printf.expect new file mode 100644 index 000000000..f67a0f6e3 --- /dev/null +++ b/tinyc/tests/tests2/02_printf.expect @@ -0,0 +1,15 @@ +Hello world +Count = -5 +Count = -4 +Count = -3 +Count = -2 +Count = -1 +Count = 0 +Count = 1 +Count = 2 +Count = 3 +Count = 4 +Count = 5 +String 'hello', 'there' is 'hello', 'there' +Character 'A' is 'A' +Character 'a' is 'a' diff --git a/tinyc/tests/tests2/03_struct.c b/tinyc/tests/tests2/03_struct.c new file mode 100644 index 000000000..c5d48c5ab --- /dev/null +++ b/tinyc/tests/tests2/03_struct.c @@ -0,0 +1,31 @@ +#include + +struct fred +{ + int boris; + int natasha; +}; + +int main() +{ + struct fred bloggs; + + bloggs.boris = 12; + bloggs.natasha = 34; + + printf("%d\n", bloggs.boris); + printf("%d\n", bloggs.natasha); + + struct fred jones[2]; + jones[0].boris = 12; + jones[0].natasha = 34; + jones[1].boris = 56; + jones[1].natasha = 78; + + printf("%d\n", jones[0].boris); + printf("%d\n", jones[0].natasha); + printf("%d\n", jones[1].boris); + printf("%d\n", jones[1].natasha); + + return 0; +} diff --git a/tinyc/tests/tests2/03_struct.expect b/tinyc/tests/tests2/03_struct.expect new file mode 100644 index 000000000..ecbf58937 --- /dev/null +++ b/tinyc/tests/tests2/03_struct.expect @@ -0,0 +1,6 @@ +12 +34 +12 +34 +56 +78 diff --git a/tinyc/tests/tests2/04_for.c b/tinyc/tests/tests2/04_for.c new file mode 100644 index 000000000..312fed855 --- /dev/null +++ b/tinyc/tests/tests2/04_for.c @@ -0,0 +1,15 @@ +#include + +int main() +{ + int Count; + + for (Count = 1; Count <= 10; Count++) + { + printf("%d\n", Count); + } + + return 0; +} + +// vim: set expandtab ts=4 sw=3 sts=3 tw=80 : diff --git a/tinyc/tests/tests2/04_for.expect b/tinyc/tests/tests2/04_for.expect new file mode 100644 index 000000000..f00c965d8 --- /dev/null +++ b/tinyc/tests/tests2/04_for.expect @@ -0,0 +1,10 @@ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 diff --git a/tinyc/tests/tests2/05_array.c b/tinyc/tests/tests2/05_array.c new file mode 100644 index 000000000..c218f3163 --- /dev/null +++ b/tinyc/tests/tests2/05_array.c @@ -0,0 +1,21 @@ +#include + +int main() +{ + int Count; + int Array[10]; + + for (Count = 1; Count <= 10; Count++) + { + Array[Count-1] = Count * Count; + } + + for (Count = 0; Count < 10; Count++) + { + printf("%d\n", Array[Count]); + } + + return 0; +} + +// vim: set expandtab ts=4 sw=3 sts=3 tw=80 : diff --git a/tinyc/tests/tests2/05_array.expect b/tinyc/tests/tests2/05_array.expect new file mode 100644 index 000000000..bc7257c0f --- /dev/null +++ b/tinyc/tests/tests2/05_array.expect @@ -0,0 +1,10 @@ +1 +4 +9 +16 +25 +36 +49 +64 +81 +100 diff --git a/tinyc/tests/tests2/06_case.c b/tinyc/tests/tests2/06_case.c new file mode 100644 index 000000000..c0191e2b0 --- /dev/null +++ b/tinyc/tests/tests2/06_case.c @@ -0,0 +1,29 @@ +#include + +int main() +{ + int Count; + + for (Count = 0; Count < 4; Count++) + { + printf("%d\n", Count); + switch (Count) + { + case 1: + printf("%d\n", 1); + break; + + case 2: + printf("%d\n", 2); + break; + + default: + printf("%d\n", 0); + break; + } + } + + return 0; +} + +// vim: set expandtab ts=4 sw=3 sts=3 tw=80 : diff --git a/tinyc/tests/tests2/06_case.expect b/tinyc/tests/tests2/06_case.expect new file mode 100644 index 000000000..fab2c201a --- /dev/null +++ b/tinyc/tests/tests2/06_case.expect @@ -0,0 +1,8 @@ +0 +0 +1 +1 +2 +2 +3 +0 diff --git a/tinyc/tests/tests2/07_function.c b/tinyc/tests/tests2/07_function.c new file mode 100644 index 000000000..0477ce14e --- /dev/null +++ b/tinyc/tests/tests2/07_function.c @@ -0,0 +1,30 @@ +#include + +int myfunc(int x) +{ + return x * x; +} + +void vfunc(int a) +{ + printf("a=%d\n", a); +} + +void qfunc() +{ + printf("qfunc()\n"); +} + +int main() +{ + printf("%d\n", myfunc(3)); + printf("%d\n", myfunc(4)); + + vfunc(1234); + + qfunc(); + + return 0; +} + +// vim: set expandtab ts=4 sw=3 sts=3 tw=80 : diff --git a/tinyc/tests/tests2/07_function.expect b/tinyc/tests/tests2/07_function.expect new file mode 100644 index 000000000..8ffb0a702 --- /dev/null +++ b/tinyc/tests/tests2/07_function.expect @@ -0,0 +1,4 @@ +9 +16 +a=1234 +qfunc() diff --git a/tinyc/tests/tests2/08_while.c b/tinyc/tests/tests2/08_while.c new file mode 100644 index 000000000..602ffc737 --- /dev/null +++ b/tinyc/tests/tests2/08_while.c @@ -0,0 +1,24 @@ +#include + +int main() +{ + int a; + int p; + int t; + + a = 1; + p = 0; + t = 0; + + while (a < 100) + { + printf("%d\n", a); + t = a; + a = t + p; + p = t; + } + + return 0; +} + +// vim: set expandtab ts=4 sw=3 sts=3 tw=80 : diff --git a/tinyc/tests/tests2/08_while.expect b/tinyc/tests/tests2/08_while.expect new file mode 100644 index 000000000..702d4c0fc --- /dev/null +++ b/tinyc/tests/tests2/08_while.expect @@ -0,0 +1,11 @@ +1 +1 +2 +3 +5 +8 +13 +21 +34 +55 +89 diff --git a/tinyc/tests/tests2/09_do_while.c b/tinyc/tests/tests2/09_do_while.c new file mode 100644 index 000000000..1d3315d3a --- /dev/null +++ b/tinyc/tests/tests2/09_do_while.c @@ -0,0 +1,24 @@ +#include + +int main() +{ + int a; + int p; + int t; + + a = 1; + p = 0; + t = 0; + + do + { + printf("%d\n", a); + t = a; + a = t + p; + p = t; + } while (a < 100); + + return 0; +} + +// vim: set expandtab ts=4 sw=3 sts=3 tw=80 : diff --git a/tinyc/tests/tests2/09_do_while.expect b/tinyc/tests/tests2/09_do_while.expect new file mode 100644 index 000000000..702d4c0fc --- /dev/null +++ b/tinyc/tests/tests2/09_do_while.expect @@ -0,0 +1,11 @@ +1 +1 +2 +3 +5 +8 +13 +21 +34 +55 +89 diff --git a/tinyc/tests/tests2/10_pointer.c b/tinyc/tests/tests2/10_pointer.c new file mode 100644 index 000000000..0177f4d81 --- /dev/null +++ b/tinyc/tests/tests2/10_pointer.c @@ -0,0 +1,40 @@ +#include + +struct ziggy +{ + int a; + int b; + int c; +} bolshevic; + +int main() +{ + int a; + int *b; + int c; + + a = 42; + b = &a; + printf("a = %d\n", *b); + + bolshevic.a = 12; + bolshevic.b = 34; + bolshevic.c = 56; + + printf("bolshevic.a = %d\n", bolshevic.a); + printf("bolshevic.b = %d\n", bolshevic.b); + printf("bolshevic.c = %d\n", bolshevic.c); + + struct ziggy *tsar = &bolshevic; + + printf("tsar->a = %d\n", tsar->a); + printf("tsar->b = %d\n", tsar->b); + printf("tsar->c = %d\n", tsar->c); + + b = &(bolshevic.b); + printf("bolshevic.b = %d\n", *b); + + return 0; +} + +// vim: set expandtab ts=4 sw=3 sts=3 tw=80 : diff --git a/tinyc/tests/tests2/10_pointer.expect b/tinyc/tests/tests2/10_pointer.expect new file mode 100644 index 000000000..1e3c473f0 --- /dev/null +++ b/tinyc/tests/tests2/10_pointer.expect @@ -0,0 +1,8 @@ +a = 42 +bolshevic.a = 12 +bolshevic.b = 34 +bolshevic.c = 56 +tsar->a = 12 +tsar->b = 34 +tsar->c = 56 +bolshevic.b = 34 diff --git a/tinyc/tests/tests2/11_precedence.c b/tinyc/tests/tests2/11_precedence.c new file mode 100644 index 000000000..db2049dfe --- /dev/null +++ b/tinyc/tests/tests2/11_precedence.c @@ -0,0 +1,40 @@ +#include + +int main() +{ + int a; + int b; + int c; + int d; + int e; + int f; + int x; + int y; + + a = 12; + b = 34; + c = 56; + d = 78; + e = 0; + f = 1; + + printf("%d\n", c + d); + printf("%d\n", (y = c + d)); + printf("%d\n", e || e && f); + printf("%d\n", e || f && f); + printf("%d\n", e && e || f); + printf("%d\n", e && f || f); + printf("%d\n", a && f | f); + printf("%d\n", a | b ^ c & d); + printf("%d, %d\n", a == a, a == b); + printf("%d, %d\n", a != a, a != b); + printf("%d\n", a != b && c != d); + printf("%d\n", a + b * c / f); + printf("%d\n", a + b * c / f); + printf("%d\n", (4 << 4)); + printf("%d\n", (64 >> 4)); + + return 0; +} + +// vim: set expandtab ts=4 sw=3 sts=3 tw=80 : diff --git a/tinyc/tests/tests2/11_precedence.expect b/tinyc/tests/tests2/11_precedence.expect new file mode 100644 index 000000000..b6923966e --- /dev/null +++ b/tinyc/tests/tests2/11_precedence.expect @@ -0,0 +1,15 @@ +134 +134 +0 +1 +1 +1 +1 +46 +1, 0 +0, 1 +1 +1916 +1916 +64 +4 diff --git a/tinyc/tests/tests2/12_hashdefine.c b/tinyc/tests/tests2/12_hashdefine.c new file mode 100644 index 000000000..5c521e02b --- /dev/null +++ b/tinyc/tests/tests2/12_hashdefine.c @@ -0,0 +1,14 @@ +#include + +#define FRED 12 +#define BLOGGS(x) (12*(x)) + +int main() +{ + printf("%d\n", FRED); + printf("%d, %d, %d\n", BLOGGS(1), BLOGGS(2), BLOGGS(3)); + + return 0; +} + +// vim: set expandtab ts=4 sw=3 sts=3 tw=80 : diff --git a/tinyc/tests/tests2/12_hashdefine.expect b/tinyc/tests/tests2/12_hashdefine.expect new file mode 100644 index 000000000..99f2ed5d9 --- /dev/null +++ b/tinyc/tests/tests2/12_hashdefine.expect @@ -0,0 +1,2 @@ +12 +12, 24, 36 diff --git a/tinyc/tests/tests2/13_integer_literals.c b/tinyc/tests/tests2/13_integer_literals.c new file mode 100644 index 000000000..7cee98b1f --- /dev/null +++ b/tinyc/tests/tests2/13_integer_literals.c @@ -0,0 +1,20 @@ +#include + +int main() +{ + int a = 24680; + int b = 01234567; + int c = 0x2468ac; + int d = 0x2468AC; + int e = 0b010101010101; + + printf("%d\n", a); + printf("%d\n", b); + printf("%d\n", c); + printf("%d\n", d); + printf("%d\n", e); + + return 0; +} + +// vim: set expandtab ts=4 sw=3 sts=3 tw=80 : diff --git a/tinyc/tests/tests2/13_integer_literals.expect b/tinyc/tests/tests2/13_integer_literals.expect new file mode 100644 index 000000000..f5aca06f7 --- /dev/null +++ b/tinyc/tests/tests2/13_integer_literals.expect @@ -0,0 +1,5 @@ +24680 +342391 +2386092 +2386092 +1365 diff --git a/tinyc/tests/tests2/14_if.c b/tinyc/tests/tests2/14_if.c new file mode 100644 index 000000000..2bd255051 --- /dev/null +++ b/tinyc/tests/tests2/14_if.c @@ -0,0 +1,21 @@ +#include + +int main() +{ + int a = 1; + + if (a) + printf("a is true\n"); + else + printf("a is false\n"); + + int b = 0; + if (b) + printf("b is true\n"); + else + printf("b is false\n"); + + return 0; +} + +// vim: set expandtab ts=4 sw=3 sts=3 tw=80 : diff --git a/tinyc/tests/tests2/14_if.expect b/tinyc/tests/tests2/14_if.expect new file mode 100644 index 000000000..c32c4159c --- /dev/null +++ b/tinyc/tests/tests2/14_if.expect @@ -0,0 +1,2 @@ +a is true +b is false diff --git a/tinyc/tests/tests2/15_recursion.c b/tinyc/tests/tests2/15_recursion.c new file mode 100644 index 000000000..f79a00df5 --- /dev/null +++ b/tinyc/tests/tests2/15_recursion.c @@ -0,0 +1,21 @@ +#include + +int factorial(int i) +{ + if (i < 2) + return i; + else + return i * factorial(i - 1); +} + +int main() +{ + int Count; + + for (Count = 1; Count <= 10; Count++) + printf("%d\n", factorial(Count)); + + return 0; +} + +/* vim: set expandtab ts=4 sw=3 sts=3 tw=80 :*/ diff --git a/tinyc/tests/tests2/15_recursion.expect b/tinyc/tests/tests2/15_recursion.expect new file mode 100644 index 000000000..db47b283d --- /dev/null +++ b/tinyc/tests/tests2/15_recursion.expect @@ -0,0 +1,10 @@ +1 +2 +6 +24 +120 +720 +5040 +40320 +362880 +3628800 diff --git a/tinyc/tests/tests2/16_nesting.c b/tinyc/tests/tests2/16_nesting.c new file mode 100644 index 000000000..2b72cc028 --- /dev/null +++ b/tinyc/tests/tests2/16_nesting.c @@ -0,0 +1,21 @@ +#include + +int main() +{ + int x, y, z; + + for (x = 0; x < 2; x++) + { + for (y = 0; y < 3; y++) + { + for (z = 0; z < 3; z++) + { + printf("%d %d %d\n", x, y, z); + } + } + } + + return 0; +} + +/* vim: set expandtab ts=4 sw=3 sts=3 tw=80 :*/ diff --git a/tinyc/tests/tests2/16_nesting.expect b/tinyc/tests/tests2/16_nesting.expect new file mode 100644 index 000000000..5a3431ee0 --- /dev/null +++ b/tinyc/tests/tests2/16_nesting.expect @@ -0,0 +1,18 @@ +0 0 0 +0 0 1 +0 0 2 +0 1 0 +0 1 1 +0 1 2 +0 2 0 +0 2 1 +0 2 2 +1 0 0 +1 0 1 +1 0 2 +1 1 0 +1 1 1 +1 1 2 +1 2 0 +1 2 1 +1 2 2 diff --git a/tinyc/tests/tests2/17_enum.c b/tinyc/tests/tests2/17_enum.c new file mode 100644 index 000000000..e2bc73629 --- /dev/null +++ b/tinyc/tests/tests2/17_enum.c @@ -0,0 +1,72 @@ +#include + +enum fred +{ + a, + b, + c, + d, + e = 54, + f = 73, + g, + h +}; + +/* All following uses of enum efoo should compile + without warning. While forward enums aren't ISO C, + it's accepted by GCC also in strict mode, and only warned + about with -pedantic. This happens in the real world. */ +/* Strict ISO C doesn't allow this kind of forward declaration of + enums, but GCC accepts it (and gives only pedantic warning), and + it occurs in the wild. */ +enum efoo; +struct Sforward_use { + int (*fmember) (enum efoo x); +}; + +extern enum efoo it_real_fn(void); +enum efoo { + ONE, + TWO, +}; +struct S2 { + enum efoo (*f2) (void); +}; +void should_compile(struct S2 *s) +{ + s->f2 = it_real_fn; +} + +enum efoo it_real_fn(void) +{ + return TWO; +} + +static unsigned int deref_uintptr(unsigned int *p) +{ + return *p; +} + +enum Epositive { + epos_one, epos_two +}; + +int main() +{ + enum fred frod; + enum Epositive epos = epos_two; + + printf("%d %d %d %d %d %d %d %d\n", a, b, c, d, e, f, g, h); + /* printf("%d\n", frod); */ + frod = 12; + printf("%d\n", frod); + frod = e; + printf("%d\n", frod); + + /* Following should compile without warning. */ + printf ("enum to int: %u\n", deref_uintptr(&epos)); + + return 0; +} + +/* vim: set expandtab ts=4 sw=3 sts=3 tw=80 :*/ diff --git a/tinyc/tests/tests2/17_enum.expect b/tinyc/tests/tests2/17_enum.expect new file mode 100644 index 000000000..d453a617b --- /dev/null +++ b/tinyc/tests/tests2/17_enum.expect @@ -0,0 +1,4 @@ +0 1 2 3 54 73 74 75 +12 +54 +enum to int: 1 diff --git a/tinyc/tests/tests2/18_include.c b/tinyc/tests/tests2/18_include.c new file mode 100644 index 000000000..dbae3aa2e --- /dev/null +++ b/tinyc/tests/tests2/18_include.c @@ -0,0 +1,12 @@ +#include + +int main() +{ + printf("including\n"); +#include "18_include.h" + printf("done\n"); + + return 0; +} + +/* vim: set expandtab ts=4 sw=3 sts=3 tw=80 :*/ diff --git a/tinyc/tests/tests2/18_include.expect b/tinyc/tests/tests2/18_include.expect new file mode 100644 index 000000000..58c6d29a0 --- /dev/null +++ b/tinyc/tests/tests2/18_include.expect @@ -0,0 +1,3 @@ +including +included +done diff --git a/tinyc/tests/tests2/18_include.h b/tinyc/tests/tests2/18_include.h new file mode 100644 index 000000000..dc8608025 --- /dev/null +++ b/tinyc/tests/tests2/18_include.h @@ -0,0 +1 @@ +printf("included\n"); diff --git a/tinyc/tests/tests2/19_pointer_arithmetic.c b/tinyc/tests/tests2/19_pointer_arithmetic.c new file mode 100644 index 000000000..aff65e5b5 --- /dev/null +++ b/tinyc/tests/tests2/19_pointer_arithmetic.c @@ -0,0 +1,28 @@ +#include + +int main() +{ + int a; + int *b; + int *c; + + a = 42; + b = &a; + c = NULL; + + printf("%d\n", *b); + + if (b == NULL) + printf("b is NULL\n"); + else + printf("b is not NULL\n"); + + if (c == NULL) + printf("c is NULL\n"); + else + printf("c is not NULL\n"); + + return 0; +} + +/* vim: set expandtab ts=4 sw=3 sts=3 tw=80 :*/ diff --git a/tinyc/tests/tests2/19_pointer_arithmetic.expect b/tinyc/tests/tests2/19_pointer_arithmetic.expect new file mode 100644 index 000000000..0cf781b9e --- /dev/null +++ b/tinyc/tests/tests2/19_pointer_arithmetic.expect @@ -0,0 +1,3 @@ +42 +b is not NULL +c is NULL diff --git a/tinyc/tests/tests2/20_pointer_comparison.c b/tinyc/tests/tests2/20_pointer_comparison.c new file mode 100644 index 000000000..825f7787d --- /dev/null +++ b/tinyc/tests/tests2/20_pointer_comparison.c @@ -0,0 +1,24 @@ +#include + +int main() +{ + int a; + int b; + int *d; + int *e; + d = &a; + e = &b; + a = 12; + b = 34; + printf("%d\n", *d); + printf("%d\n", *e); + printf("%d\n", d == e); + printf("%d\n", d != e); + d = e; + printf("%d\n", d == e); + printf("%d\n", d != e); + + return 0; +} + +/* vim: set expandtab ts=4 sw=3 sts=3 tw=80 :*/ diff --git a/tinyc/tests/tests2/20_pointer_comparison.expect b/tinyc/tests/tests2/20_pointer_comparison.expect new file mode 100644 index 000000000..5d1e5f5c7 --- /dev/null +++ b/tinyc/tests/tests2/20_pointer_comparison.expect @@ -0,0 +1,6 @@ +12 +34 +0 +1 +1 +0 diff --git a/tinyc/tests/tests2/21_char_array.c b/tinyc/tests/tests2/21_char_array.c new file mode 100644 index 000000000..f22f5275c --- /dev/null +++ b/tinyc/tests/tests2/21_char_array.c @@ -0,0 +1,33 @@ +#include + +int main() +{ + int x = 'a'; + char y = x; + + char *a = "hello"; + + printf("%s\n", a); + + int c; + c = *a; + + char *b; + for (b = a; *b != 0; b++) + printf("%c: %d\n", *b, *b); + + char destarray[10]; + char *dest = &destarray[0]; + char *src = a; + + while (*src != 0) + *dest++ = *src++; + + *dest = 0; + + printf("copied string is %s\n", destarray); + + return 0; +} + +/* vim: set expandtab ts=4 sw=3 sts=3 tw=80 :*/ diff --git a/tinyc/tests/tests2/21_char_array.expect b/tinyc/tests/tests2/21_char_array.expect new file mode 100644 index 000000000..dbc60683c --- /dev/null +++ b/tinyc/tests/tests2/21_char_array.expect @@ -0,0 +1,7 @@ +hello +h: 104 +e: 101 +l: 108 +l: 108 +o: 111 +copied string is hello diff --git a/tinyc/tests/tests2/22_floating_point.c b/tinyc/tests/tests2/22_floating_point.c new file mode 100644 index 000000000..e3491f5c6 --- /dev/null +++ b/tinyc/tests/tests2/22_floating_point.c @@ -0,0 +1,50 @@ +#include +#include + +int main() +{ + // variables + float a = 12.34 + 56.78; + printf("%f\n", a); + + // infix operators + printf("%f\n", 12.34 + 56.78); + printf("%f\n", 12.34 - 56.78); + printf("%f\n", 12.34 * 56.78); + printf("%f\n", 12.34 / 56.78); + + // comparison operators + printf("%d %d %d %d %d %d\n", 12.34 < 56.78, 12.34 <= 56.78, 12.34 == 56.78, 12.34 >= 56.78, 12.34 > 56.78, 12.34 != 56.78); + printf("%d %d %d %d %d %d\n", 12.34 < 12.34, 12.34 <= 12.34, 12.34 == 12.34, 12.34 >= 12.34, 12.34 > 12.34, 12.34 != 12.34); + printf("%d %d %d %d %d %d\n", 56.78 < 12.34, 56.78 <= 12.34, 56.78 == 12.34, 56.78 >= 12.34, 56.78 > 12.34, 56.78 != 12.34); + + // assignment operators + a = 12.34; + a += 56.78; + printf("%f\n", a); + + a = 12.34; + a -= 56.78; + printf("%f\n", a); + + a = 12.34; + a *= 56.78; + printf("%f\n", a); + + a = 12.34; + a /= 56.78; + printf("%f\n", a); + + // prefix operators + printf("%f\n", +12.34); + printf("%f\n", -12.34); + + // type coercion + a = 2; + printf("%f\n", a); + printf("%f\n", sin(2)); + + return 0; +} + +/* vim: set expandtab ts=4 sw=3 sts=3 tw=80 :*/ diff --git a/tinyc/tests/tests2/22_floating_point.expect b/tinyc/tests/tests2/22_floating_point.expect new file mode 100644 index 000000000..75ea3a7e2 --- /dev/null +++ b/tinyc/tests/tests2/22_floating_point.expect @@ -0,0 +1,16 @@ +69.120003 +69.120000 +-44.440000 +700.665200 +0.217330 +1 1 0 0 0 1 +0 1 1 1 0 0 +0 0 0 1 1 1 +69.120003 +-44.439999 +700.665222 +0.217330 +12.340000 +-12.340000 +2.000000 +0.909297 diff --git a/tinyc/tests/tests2/23_type_coercion.c b/tinyc/tests/tests2/23_type_coercion.c new file mode 100644 index 000000000..1fcc33519 --- /dev/null +++ b/tinyc/tests/tests2/23_type_coercion.c @@ -0,0 +1,54 @@ +#include + +void charfunc(char a) +{ + printf("char: %c\n", a); +} + +void intfunc(int a) +{ + printf("int: %d\n", a); +} + +void floatfunc(float a) +{ + printf("float: %f\n", a); +} + +int main() +{ + charfunc('a'); + charfunc(98); + charfunc(99.0); + + intfunc('a'); + intfunc(98); + intfunc(99.0); + + floatfunc('a'); + floatfunc(98); + floatfunc(99.0); + + /* printf("%c %d %f\n", 'a', 'b', 'c'); */ + /* printf("%c %d %f\n", 97, 98, 99); */ + /* printf("%c %d %f\n", 97.0, 98.0, 99.0); */ + + char b = 97; + char c = 97.0; + + printf("%d %d\n", b, c); + + int d = 'a'; + int e = 97.0; + + printf("%d %d\n", d, e); + + float f = 'a'; + float g = 97; + + printf("%f %f\n", f, g); + + return 0; +} + +/* vim: set expandtab ts=4 sw=3 sts=3 tw=80 :*/ diff --git a/tinyc/tests/tests2/23_type_coercion.expect b/tinyc/tests/tests2/23_type_coercion.expect new file mode 100644 index 000000000..d9076f018 --- /dev/null +++ b/tinyc/tests/tests2/23_type_coercion.expect @@ -0,0 +1,12 @@ +char: a +char: b +char: c +int: 97 +int: 98 +int: 99 +float: 97.000000 +float: 98.000000 +float: 99.000000 +97 97 +97 97 +97.000000 97.000000 diff --git a/tinyc/tests/tests2/24_math_library.c b/tinyc/tests/tests2/24_math_library.c new file mode 100644 index 000000000..514a25f63 --- /dev/null +++ b/tinyc/tests/tests2/24_math_library.c @@ -0,0 +1,30 @@ +#define _ISOC99_SOURCE 1 + +#include +#include + +int main() +{ + printf("%f\n", sin(0.12)); + printf("%f\n", cos(0.12)); + printf("%f\n", tan(0.12)); + printf("%f\n", asin(0.12)); + printf("%f\n", acos(0.12)); + printf("%f\n", atan(0.12)); + printf("%f\n", sinh(0.12)); + printf("%f\n", cosh(0.12)); + printf("%f\n", tanh(0.12)); + printf("%f\n", exp(0.12)); + printf("%f\n", fabs(-0.12)); + printf("%f\n", log(0.12)); + printf("%f\n", log10(0.12)); + printf("%f\n", pow(0.12, 0.12)); + printf("%f\n", sqrt(0.12)); + printf("%f\n", round(12.34)); + printf("%f\n", ceil(12.34)); + printf("%f\n", floor(12.34)); + + return 0; +} + +/* vim: set expandtab ts=4 sw=3 sts=3 tw=80 :*/ diff --git a/tinyc/tests/tests2/24_math_library.expect b/tinyc/tests/tests2/24_math_library.expect new file mode 100644 index 000000000..99f7299cc --- /dev/null +++ b/tinyc/tests/tests2/24_math_library.expect @@ -0,0 +1,18 @@ +0.119712 +0.992809 +0.120579 +0.120290 +1.450506 +0.119429 +0.120288 +1.007209 +0.119427 +1.127497 +0.120000 +-2.120264 +-0.920819 +0.775357 +0.346410 +12.000000 +13.000000 +12.000000 diff --git a/tinyc/tests/tests2/25_quicksort.c b/tinyc/tests/tests2/25_quicksort.c new file mode 100644 index 000000000..5cc08bd9d --- /dev/null +++ b/tinyc/tests/tests2/25_quicksort.c @@ -0,0 +1,83 @@ +#include + +int array[16]; + +//Swap integer values by array indexes +void swap(int a, int b) +{ + int tmp = array[a]; + array[a] = array[b]; + array[b] = tmp; +} + +//Partition the array into two halves and return the +//index about which the array is partitioned +int partition(int left, int right) +{ + int pivotIndex = left; + int pivotValue = array[pivotIndex]; + int index = left; + int i; + + swap(pivotIndex, right); + for(i = left; i < right; i++) + { + if(array[i] < pivotValue) + { + swap(i, index); + index += 1; + } + } + swap(right, index); + + return index; +} + +//Quicksort the array +void quicksort(int left, int right) +{ + if(left >= right) + return; + + int index = partition(left, right); + quicksort(left, index - 1); + quicksort(index + 1, right); +} + +int main() +{ + int i; + + array[0] = 62; + array[1] = 83; + array[2] = 4; + array[3] = 89; + array[4] = 36; + array[5] = 21; + array[6] = 74; + array[7] = 37; + array[8] = 65; + array[9] = 33; + array[10] = 96; + array[11] = 38; + array[12] = 53; + array[13] = 16; + array[14] = 74; + array[15] = 55; + + for (i = 0; i < 16; i++) + printf("%d ", array[i]); + + printf("\n"); + + quicksort(0, 15); + + for (i = 0; i < 16; i++) + printf("%d ", array[i]); + + printf("\n"); + + return 0; +} + +/* vim: set expandtab ts=4 sw=3 sts=3 tw=80 :*/ diff --git a/tinyc/tests/tests2/25_quicksort.expect b/tinyc/tests/tests2/25_quicksort.expect new file mode 100644 index 000000000..2d39cd327 --- /dev/null +++ b/tinyc/tests/tests2/25_quicksort.expect @@ -0,0 +1,2 @@ +62 83 4 89 36 21 74 37 65 33 96 38 53 16 74 55 +4 16 21 33 36 37 38 53 55 62 65 74 74 83 89 96 diff --git a/tinyc/tests/tests2/26_character_constants.c b/tinyc/tests/tests2/26_character_constants.c new file mode 100644 index 000000000..95c442371 --- /dev/null +++ b/tinyc/tests/tests2/26_character_constants.c @@ -0,0 +1,17 @@ +#include + +int main() +{ + printf("%d\n", '\1'); + printf("%d\n", '\10'); + printf("%d\n", '\100'); + printf("%d\n", '\x01'); + printf("%d\n", '\x0e'); + printf("%d\n", '\x10'); + printf("%d\n", '\x40'); + printf("test \x40\n"); + + return 0; +} + +/* vim: set expandtab ts=4 sw=3 sts=3 tw=80 :*/ diff --git a/tinyc/tests/tests2/26_character_constants.expect b/tinyc/tests/tests2/26_character_constants.expect new file mode 100644 index 000000000..8f8bfa48c --- /dev/null +++ b/tinyc/tests/tests2/26_character_constants.expect @@ -0,0 +1,8 @@ +1 +8 +64 +1 +14 +16 +64 +test @ diff --git a/tinyc/tests/tests2/27_sizeof.c b/tinyc/tests/tests2/27_sizeof.c new file mode 100644 index 000000000..5ae0ede54 --- /dev/null +++ b/tinyc/tests/tests2/27_sizeof.c @@ -0,0 +1,18 @@ +#include + +int main() +{ + char a; + int b; + double c; + + printf("%d\n", sizeof(a)); + printf("%d\n", sizeof(b)); + printf("%d\n", sizeof(c)); + + printf("%d\n", sizeof(!a)); + + return 0; +} + +/* vim: set expandtab ts=4 sw=3 sts=3 tw=80 :*/ diff --git a/tinyc/tests/tests2/27_sizeof.expect b/tinyc/tests/tests2/27_sizeof.expect new file mode 100644 index 000000000..a47ea3a40 --- /dev/null +++ b/tinyc/tests/tests2/27_sizeof.expect @@ -0,0 +1,4 @@ +1 +4 +8 +4 diff --git a/tinyc/tests/tests2/28_strings.c b/tinyc/tests/tests2/28_strings.c new file mode 100644 index 000000000..2db22986e --- /dev/null +++ b/tinyc/tests/tests2/28_strings.c @@ -0,0 +1,45 @@ +#include +#include + +int main() +{ + char a[10]; + + strcpy(a, "hello"); + printf("%s\n", a); + + strncpy(a, "gosh", 2); + printf("%s\n", a); + + printf("%d\n", strcmp(a, "apple") > 0); + printf("%d\n", strcmp(a, "goere") > 0); + printf("%d\n", strcmp(a, "zebra") < 0); + + printf("%d\n", strlen(a)); + + strcat(a, "!"); + printf("%s\n", a); + + printf("%d\n", strncmp(a, "apple", 2) > 0); + printf("%d\n", strncmp(a, "goere", 2) == 0); + printf("%d\n", strncmp(a, "goerg", 2) == 0); + printf("%d\n", strncmp(a, "zebra", 2) < 0); + + printf("%s\n", strchr(a, 'o')); + printf("%s\n", strrchr(a, 'l')); + printf("%d\n", strrchr(a, 'x') == NULL); + + memset(&a[1], 'r', 4); + printf("%s\n", a); + + memcpy(&a[2], a, 2); + printf("%s\n", a); + + printf("%d\n", memcmp(a, "apple", 4) > 0); + printf("%d\n", memcmp(a, "grgr", 4) == 0); + printf("%d\n", memcmp(a, "zebra", 4) < 0); + + return 0; +} + +/* vim: set expandtab ts=4 sw=3 sts=3 tw=80 :*/ diff --git a/tinyc/tests/tests2/28_strings.expect b/tinyc/tests/tests2/28_strings.expect new file mode 100644 index 000000000..fd9217a22 --- /dev/null +++ b/tinyc/tests/tests2/28_strings.expect @@ -0,0 +1,19 @@ +hello +gollo +1 +1 +1 +5 +gollo! +1 +1 +1 +1 +ollo! +lo! +1 +grrrr! +grgrr! +1 +1 +1 diff --git a/tinyc/tests/tests2/29_array_address.c b/tinyc/tests/tests2/29_array_address.c new file mode 100644 index 000000000..bda5ddde2 --- /dev/null +++ b/tinyc/tests/tests2/29_array_address.c @@ -0,0 +1,13 @@ +#include +#include + +int main() +{ + char a[10]; + strcpy(a, "abcdef"); + printf("%s\n", &a[1]); + + return 0; +} + +/* vim: set expandtab ts=4 sw=3 sts=3 tw=80 :*/ diff --git a/tinyc/tests/tests2/29_array_address.expect b/tinyc/tests/tests2/29_array_address.expect new file mode 100644 index 000000000..9bc868324 --- /dev/null +++ b/tinyc/tests/tests2/29_array_address.expect @@ -0,0 +1 @@ +bcdef diff --git a/tinyc/tests/tests2/30_hanoi.c b/tinyc/tests/tests2/30_hanoi.c new file mode 100644 index 000000000..7c0893b1a --- /dev/null +++ b/tinyc/tests/tests2/30_hanoi.c @@ -0,0 +1,122 @@ +/* example from http://barnyard.syr.edu/quickies/hanoi.c */ + +/* hanoi.c: solves the tower of hanoi problem. (Programming exercise.) */ +/* By Terry R. McConnell (12/2/97) */ +/* Compile: cc -o hanoi hanoi.c */ + +/* This program does no error checking. But then, if it's right, + it's right ... right ? */ + + +/* The original towers of hanoi problem seems to have been originally posed + by one M. Claus in 1883. There is a popular legend that goes along with + it that has been often repeated and paraphrased. It goes something like this: + In the great temple at Benares there are 3 golden spikes. On one of them, + God placed 64 disks increasing in size from bottom to top, at the beginning + of time. Since then, and to this day, the priest on duty constantly transfers + disks, one at a time, in such a way that no larger disk is ever put on top + of a smaller one. When the disks have been transferred entirely to another + spike the Universe will come to an end in a large thunderclap. + + This paraphrases the original legend due to DeParville, La Nature, Paris 1884, + Part I, 285-286. For this and further information see: Mathematical + Recreations & Essays, W.W. Rouse Ball, MacMillan, NewYork, 11th Ed. 1967, + 303-305. + * + * + */ + +#include +#include + +#define TRUE 1 +#define FALSE 0 + +/* This is the number of "disks" on tower A initially. Taken to be 64 in the + * legend. The number of moves required, in general, is 2^N - 1. For N = 64, + * this is 18,446,744,073,709,551,615 */ +#define N 4 + +/* These are the three towers. For example if the state of A is 0,1,3,4, that + * means that there are three discs on A of sizes 1, 3, and 4. (Think of right + * as being the "down" direction.) */ +int A[N], B[N], C[N]; + +void Hanoi(int,int*,int*,int*); + +/* Print the current configuration of A, B, and C to the screen */ +void PrintAll() +{ + int i; + + printf("A: "); + for(i=0;i + +int main(int argc, char **argv) +{ + int Count; + + printf("hello world %d\n", argc); + for (Count = 1; Count < argc; Count++) + printf("arg %d: %s\n", Count, argv[Count]); + + return 0; +} + +/* vim: set expandtab ts=4 sw=3 sts=3 tw=80 :*/ diff --git a/tinyc/tests/tests2/31_args.expect b/tinyc/tests/tests2/31_args.expect new file mode 100644 index 000000000..8c60bfc5b --- /dev/null +++ b/tinyc/tests/tests2/31_args.expect @@ -0,0 +1,6 @@ +hello world 6 +arg 1: arg1 +arg 2: arg2 +arg 3: arg3 +arg 4: arg4 +arg 5: arg5 diff --git a/tinyc/tests/tests2/32_led.c b/tinyc/tests/tests2/32_led.c new file mode 100644 index 000000000..5596cbfd3 --- /dev/null +++ b/tinyc/tests/tests2/32_led.c @@ -0,0 +1,266 @@ +/* example from http://barnyard.syr.edu/quickies/led.c */ + +/* led.c: print out number as if on 7 line led display. I.e., write integer + given on command line like this: + _ _ _ + | _| _| |_| |_ + | |_ _| | _| etc. + + We assume the terminal behaves like a classical teletype. So the top + lines of all digits have to be printed first, then the middle lines of + all digits, etc. + + By Terry R. McConnell + +compile: cc -o led led.c + +If you just want to link in the subroutine print_led that does all the +work, compile with -DNO_MAIN, and declare the following in any source file +that uses the call: + +extern void print_led(unsigned long x, char *buf); + +Bug: you cannot call repeatedly to print more than one number to a line. +That would require curses or some other terminal API that allows moving the +cursor to a previous line. + +*/ + + + +#include +#include + +#define MAX_DIGITS 32 +#define NO_MAIN + + +/* Print the top line of the digit d into buffer. + Does not null terminate buffer. */ + +void topline(int d, char *p){ + + *p++ = ' '; + switch(d){ + + /* all these have _ on top line */ + + case 0: + case 2: + case 3: + case 5: + case 7: + case 8: + case 9: + *p++ = '_'; + break; + default: + *p++=' '; + + } + *p++=' '; +} + +/* Print the middle line of the digit d into the buffer. + Does not null terminate. */ + +void midline(int d, char *p){ + + switch(d){ + + /* those that have leading | on middle line */ + + case 0: + case 4: + case 5: + case 6: + case 8: + case 9: + *p++='|'; + break; + default: + *p++=' '; + } + switch(d){ + + /* those that have _ on middle line */ + + case 2: + case 3: + case 4: + case 5: + case 6: + case 8: + case 9: + *p++='_'; + break; + default: + *p++=' '; + + } + switch(d){ + + /* those that have closing | on middle line */ + + case 0: + case 1: + case 2: + case 3: + case 4: + case 7: + case 8: + case 9: + *p++='|'; + break; + default: + *p++=' '; + + } +} + +/* Print the bottom line of the digit d. Does not null terminate. */ + +void botline(int d, char *p){ + + + switch(d){ + + /* those that have leading | on bottom line */ + + case 0: + case 2: + case 6: + case 8: + *p++='|'; + break; + default: + *p++=' '; + } + switch(d){ + + /* those that have _ on bottom line */ + + case 0: + case 2: + case 3: + case 5: + case 6: + case 8: + *p++='_'; + break; + default: + *p++=' '; + + } + switch(d){ + + /* those that have closing | on bottom line */ + + case 0: + case 1: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + *p++='|'; + break; + default: + *p++=' '; + + } +} + +/* Write the led representation of integer to string buffer. */ + +void print_led(unsigned long x, char *buf) +{ + + int i=0,n; + static int d[MAX_DIGITS]; + + + /* extract digits from x */ + + n = ( x == 0L ? 1 : 0 ); /* 0 is a digit, hence a special case */ + + while(x){ + d[n++] = (int)(x%10L); + if(n >= MAX_DIGITS)break; + x = x/10L; + } + + /* print top lines of all digits */ + + for(i=n-1;i>=0;i--){ + topline(d[i],buf); + buf += 3; + *buf++=' '; + } + *buf++='\n'; /* move teletype to next line */ + + /* print middle lines of all digits */ + + for(i=n-1;i>=0;i--){ + midline(d[i],buf); + buf += 3; + *buf++=' '; + } + *buf++='\n'; + + /* print bottom lines of all digits */ + + for(i=n-1;i>=0;i--){ + botline(d[i],buf); + buf += 3; + *buf++=' '; + } + *buf++='\n'; + *buf='\0'; +} + +int main() +{ + char buf[5*MAX_DIGITS]; + print_led(1234567, buf); + printf("%s\n",buf); + + return 0; +} + +#ifndef NO_MAIN +int main(int argc, char **argv) +{ + + int i=0,n; + long x; + static int d[MAX_DIGITS]; + char buf[5*MAX_DIGITS]; + + if(argc != 2){ + fprintf(stderr,"led: usage: led integer\n"); + return 1; + } + + /* fetch argument from command line */ + + x = atol(argv[1]); + + /* sanity check */ + + if(x<0){ + fprintf(stderr,"led: %d must be non-negative\n",x); + return 1; + } + + print_led(x,buf); + printf("%s\n",buf); + + return 0; + +} +#endif + +/* vim: set expandtab ts=4 sw=3 sts=3 tw=80 :*/ diff --git a/tinyc/tests/tests2/32_led.expect b/tinyc/tests/tests2/32_led.expect new file mode 100644 index 000000000..c53b58ae0 --- /dev/null +++ b/tinyc/tests/tests2/32_led.expect @@ -0,0 +1,4 @@ + _ _ _ _ + | _| _| |_| |_ |_ | + | |_ _| | _| |_| | + diff --git a/tinyc/tests/tests2/33_ternary_op.c b/tinyc/tests/tests2/33_ternary_op.c new file mode 100644 index 000000000..8579b5029 --- /dev/null +++ b/tinyc/tests/tests2/33_ternary_op.c @@ -0,0 +1,15 @@ +#include + +int main() +{ + int Count; + + for (Count = 0; Count < 10; Count++) + { + printf("%d\n", (Count < 5) ? (Count*Count) : (Count * 3)); + } + + return 0; +} + +/* vim: set expandtab ts=4 sw=3 sts=3 tw=80 :*/ diff --git a/tinyc/tests/tests2/33_ternary_op.expect b/tinyc/tests/tests2/33_ternary_op.expect new file mode 100644 index 000000000..45ea507a5 --- /dev/null +++ b/tinyc/tests/tests2/33_ternary_op.expect @@ -0,0 +1,10 @@ +0 +1 +4 +9 +16 +15 +18 +21 +24 +27 diff --git a/tinyc/tests/tests2/34_array_assignment.c b/tinyc/tests/tests2/34_array_assignment.c new file mode 100644 index 000000000..5885c9732 --- /dev/null +++ b/tinyc/tests/tests2/34_array_assignment.c @@ -0,0 +1,23 @@ +#include + +int main() +{ + int a[4]; + + a[0] = 12; + a[1] = 23; + a[2] = 34; + a[3] = 45; + + printf("%d %d %d %d\n", a[0], a[1], a[2], a[3]); + + int b[4]; + + b = a; + + printf("%d %d %d %d\n", b[0], b[1], b[2], b[3]); + + return 0; +} + +/* vim: set expandtab ts=4 sw=3 sts=3 tw=80 :*/ diff --git a/tinyc/tests/tests2/34_array_assignment.expect b/tinyc/tests/tests2/34_array_assignment.expect new file mode 100644 index 000000000..9736bf508 --- /dev/null +++ b/tinyc/tests/tests2/34_array_assignment.expect @@ -0,0 +1,2 @@ +12 23 34 45 +12 23 34 45 diff --git a/tinyc/tests/tests2/35_sizeof.c b/tinyc/tests/tests2/35_sizeof.c new file mode 100644 index 000000000..672e87e7f --- /dev/null +++ b/tinyc/tests/tests2/35_sizeof.c @@ -0,0 +1,14 @@ +#include + +int main() +{ + char a; + short b; + + printf("%d %d\n", sizeof(char), sizeof(a)); + printf("%d %d\n", sizeof(short), sizeof(b)); + + return 0; +} + +/* vim: set expandtab ts=4 sw=3 sts=3 tw=80 :*/ diff --git a/tinyc/tests/tests2/35_sizeof.expect b/tinyc/tests/tests2/35_sizeof.expect new file mode 100644 index 000000000..534fb831b --- /dev/null +++ b/tinyc/tests/tests2/35_sizeof.expect @@ -0,0 +1,2 @@ +1 1 +2 2 diff --git a/tinyc/tests/tests2/36_array_initialisers.c b/tinyc/tests/tests2/36_array_initialisers.c new file mode 100644 index 000000000..1bc8ee088 --- /dev/null +++ b/tinyc/tests/tests2/36_array_initialisers.c @@ -0,0 +1,21 @@ +#include + +int main() +{ + int Count; + + int Array[10] = { 12, 34, 56, 78, 90, 123, 456, 789, 8642, 9753 }; + + for (Count = 0; Count < 10; Count++) + printf("%d: %d\n", Count, Array[Count]); + + int Array2[10] = { 12, 34, 56, 78, 90, 123, 456, 789, 8642, 9753, }; + + for (Count = 0; Count < 10; Count++) + printf("%d: %d\n", Count, Array2[Count]); + + + return 0; +} + +/* vim: set expandtab ts=4 sw=3 sts=3 tw=80 :*/ diff --git a/tinyc/tests/tests2/36_array_initialisers.expect b/tinyc/tests/tests2/36_array_initialisers.expect new file mode 100644 index 000000000..3ac6c7729 --- /dev/null +++ b/tinyc/tests/tests2/36_array_initialisers.expect @@ -0,0 +1,20 @@ +0: 12 +1: 34 +2: 56 +3: 78 +4: 90 +5: 123 +6: 456 +7: 789 +8: 8642 +9: 9753 +0: 12 +1: 34 +2: 56 +3: 78 +4: 90 +5: 123 +6: 456 +7: 789 +8: 8642 +9: 9753 diff --git a/tinyc/tests/tests2/37_sprintf.c b/tinyc/tests/tests2/37_sprintf.c new file mode 100644 index 000000000..1dd1dce28 --- /dev/null +++ b/tinyc/tests/tests2/37_sprintf.c @@ -0,0 +1,17 @@ +#include + +int main() +{ + char Buf[100]; + int Count; + + for (Count = 1; Count <= 20; Count++) + { + sprintf(Buf, "->%02d<-\n", Count); + printf("%s", Buf); + } + + return 0; +} + +/* vim: set expandtab ts=4 sw=3 sts=3 tw=80 :*/ diff --git a/tinyc/tests/tests2/37_sprintf.expect b/tinyc/tests/tests2/37_sprintf.expect new file mode 100644 index 000000000..a643da842 --- /dev/null +++ b/tinyc/tests/tests2/37_sprintf.expect @@ -0,0 +1,20 @@ +->01<- +->02<- +->03<- +->04<- +->05<- +->06<- +->07<- +->08<- +->09<- +->10<- +->11<- +->12<- +->13<- +->14<- +->15<- +->16<- +->17<- +->18<- +->19<- +->20<- diff --git a/tinyc/tests/tests2/38_multiple_array_index.c b/tinyc/tests/tests2/38_multiple_array_index.c new file mode 100644 index 000000000..4e1868efe --- /dev/null +++ b/tinyc/tests/tests2/38_multiple_array_index.c @@ -0,0 +1,32 @@ +#include + +int main() +{ + int a[4][4]; + int b = 0; + int x; + int y; + + for (x = 0; x < 4; x++) + { + for (y = 0; y < 4; y++) + { + b++; + a[x][y] = b; + } + } + + for (x = 0; x < 4; x++) + { + printf("x=%d: ", x); + for (y = 0; y < 4; y++) + { + printf("%d ", a[x][y]); + } + printf("\n"); + } + + return 0; +} + +/* vim: set expandtab ts=4 sw=3 sts=3 tw=80 :*/ diff --git a/tinyc/tests/tests2/38_multiple_array_index.expect b/tinyc/tests/tests2/38_multiple_array_index.expect new file mode 100644 index 000000000..747ad751d --- /dev/null +++ b/tinyc/tests/tests2/38_multiple_array_index.expect @@ -0,0 +1,4 @@ +x=0: 1 2 3 4 +x=1: 5 6 7 8 +x=2: 9 10 11 12 +x=3: 13 14 15 16 diff --git a/tinyc/tests/tests2/39_typedef.c b/tinyc/tests/tests2/39_typedef.c new file mode 100644 index 000000000..da73f71e6 --- /dev/null +++ b/tinyc/tests/tests2/39_typedef.c @@ -0,0 +1,65 @@ +#include + +typedef int MyInt; + +struct FunStruct +{ + int i; + int j; +}; + +typedef struct FunStruct MyFunStruct; + +typedef MyFunStruct *MoreFunThanEver; + +int main() +{ + MyInt a = 1; + printf("%d\n", a); + + MyFunStruct b; + b.i = 12; + b.j = 34; + printf("%d,%d\n", b.i, b.j); + + MoreFunThanEver c = &b; + printf("%d,%d\n", c->i, c->j); + + return 0; +} + +/* "If the specification of an array type includes any type qualifiers, + the element type is so-qualified, not the array type." */ + +typedef int A[3]; +extern A const ca; +extern const A ca; +extern const int ca[3]; + +typedef A B[1][2]; +extern B const cb; +extern const B cb; +extern const int cb[1][2][3]; + +extern B b; +extern int b[1][2][3]; + +/* Funny but valid function declaration. */ +typedef int functype (int); +extern functype func; +int func(int i) +{ + return i + 1; +} + +/* Even funnier function decl and definition using typeof. */ +int set_anon_super(void); +int set_anon_super(void) +{ + return 42; +} +typedef int sas_type (void); +extern typeof(set_anon_super) set_anon_super; +extern sas_type set_anon_super; + +/* vim: set expandtab ts=4 sw=3 sts=3 tw=80 :*/ diff --git a/tinyc/tests/tests2/39_typedef.expect b/tinyc/tests/tests2/39_typedef.expect new file mode 100644 index 000000000..b9050a9b6 --- /dev/null +++ b/tinyc/tests/tests2/39_typedef.expect @@ -0,0 +1,3 @@ +1 +12,34 +12,34 diff --git a/tinyc/tests/tests2/40_stdio.c b/tinyc/tests/tests2/40_stdio.c new file mode 100644 index 000000000..b98609302 --- /dev/null +++ b/tinyc/tests/tests2/40_stdio.c @@ -0,0 +1,52 @@ +#include + +int main() +{ + FILE *f = fopen("fred.txt", "w"); + fwrite("hello\nhello\n", 1, 12, f); + fclose(f); + + char freddy[7]; + f = fopen("fred.txt", "r"); + if (fread(freddy, 1, 6, f) != 6) + printf("couldn't read fred.txt\n"); + + freddy[6] = '\0'; + fclose(f); + + printf("%s", freddy); + + int InChar; + char ShowChar; + f = fopen("fred.txt", "r"); + while ( (InChar = fgetc(f)) != EOF) + { + ShowChar = InChar; + if (ShowChar < ' ') + ShowChar = '.'; + + printf("ch: %d '%c'\n", InChar, ShowChar); + } + fclose(f); + + f = fopen("fred.txt", "r"); + while ( (InChar = getc(f)) != EOF) + { + ShowChar = InChar; + if (ShowChar < ' ') + ShowChar = '.'; + + printf("ch: %d '%c'\n", InChar, ShowChar); + } + fclose(f); + + f = fopen("fred.txt", "r"); + while (fgets(freddy, sizeof(freddy), f) != NULL) + printf("x: %s", freddy); + + fclose(f); + + return 0; +} + +/* vim: set expandtab ts=4 sw=3 sts=3 tw=80 :*/ diff --git a/tinyc/tests/tests2/40_stdio.expect b/tinyc/tests/tests2/40_stdio.expect new file mode 100644 index 000000000..e08167a6e --- /dev/null +++ b/tinyc/tests/tests2/40_stdio.expect @@ -0,0 +1,27 @@ +hello +ch: 104 'h' +ch: 101 'e' +ch: 108 'l' +ch: 108 'l' +ch: 111 'o' +ch: 10 '.' +ch: 104 'h' +ch: 101 'e' +ch: 108 'l' +ch: 108 'l' +ch: 111 'o' +ch: 10 '.' +ch: 104 'h' +ch: 101 'e' +ch: 108 'l' +ch: 108 'l' +ch: 111 'o' +ch: 10 '.' +ch: 104 'h' +ch: 101 'e' +ch: 108 'l' +ch: 108 'l' +ch: 111 'o' +ch: 10 '.' +x: hello +x: hello diff --git a/tinyc/tests/tests2/41_hashif.c b/tinyc/tests/tests2/41_hashif.c new file mode 100644 index 000000000..cb37b9eb0 --- /dev/null +++ b/tinyc/tests/tests2/41_hashif.c @@ -0,0 +1,85 @@ +#include + +int main() +{ + printf("#include test\n"); + +#if 1 +#if 0 + printf("a\n"); +#else + printf("b\n"); +#endif +#else +#if 0 + printf("c\n"); +#else + printf("d\n"); +#endif +#endif + +#if 0 +#if 1 + printf("e\n"); +#else + printf("f\n"); +#endif +#else +#if 1 + printf("g\n"); +#else + printf("h\n"); +#endif +#endif + +#define DEF + +#ifdef DEF +#ifdef DEF + printf("i\n"); +#else + printf("j\n"); +#endif +#else +#ifdef DEF + printf("k\n"); +#else + printf("l\n"); +#endif +#endif + +#ifndef DEF +#ifndef DEF + printf("m\n"); +#else + printf("n\n"); +#endif +#else +#ifndef DEF + printf("o\n"); +#else + printf("p\n"); +#endif +#endif + +#define ONE 1 +#define ZERO 0 + +#if ONE +#if ZERO + printf("q\n"); +#else + printf("r\n"); +#endif +#else +#if ZERO + printf("s\n"); +#else + printf("t\n"); +#endif +#endif + + return 0; +} + +/* vim: set expandtab ts=4 sw=3 sts=3 tw=80 :*/ diff --git a/tinyc/tests/tests2/41_hashif.expect b/tinyc/tests/tests2/41_hashif.expect new file mode 100644 index 000000000..5fd414bd0 --- /dev/null +++ b/tinyc/tests/tests2/41_hashif.expect @@ -0,0 +1,6 @@ +#include test +b +g +i +p +r diff --git a/tinyc/tests/tests2/42_function_pointer.c b/tinyc/tests/tests2/42_function_pointer.c new file mode 100644 index 000000000..697bd79a6 --- /dev/null +++ b/tinyc/tests/tests2/42_function_pointer.c @@ -0,0 +1,22 @@ +#include + +int fred(int p) +{ + printf("yo %d\n", p); + return 42; +} + +int (*f)(int) = &fred; + +/* To test what this is supposed to test the destination function + (fprint here) must not be called directly anywhere in the test. */ +int (*fprintfptr)(FILE *, const char *, ...) = &fprintf; + +int main() +{ + fprintfptr(stdout, "%d\n", (*f)(24)); + + return 0; +} + +/* vim: set expandtab ts=4 sw=3 sts=3 tw=80 :*/ diff --git a/tinyc/tests/tests2/42_function_pointer.expect b/tinyc/tests/tests2/42_function_pointer.expect new file mode 100644 index 000000000..6c8b6ce45 --- /dev/null +++ b/tinyc/tests/tests2/42_function_pointer.expect @@ -0,0 +1,2 @@ +yo 24 +42 diff --git a/tinyc/tests/tests2/43_void_param.c b/tinyc/tests/tests2/43_void_param.c new file mode 100644 index 000000000..de17098b2 --- /dev/null +++ b/tinyc/tests/tests2/43_void_param.c @@ -0,0 +1,15 @@ +#include + +void fred(void) +{ + printf("yo\n"); +} + +int main() +{ + fred(); + + return 0; +} + +/* vim: set expandtab ts=4 sw=3 sts=3 tw=80 :*/ diff --git a/tinyc/tests/tests2/43_void_param.expect b/tinyc/tests/tests2/43_void_param.expect new file mode 100644 index 000000000..092bfb9bd --- /dev/null +++ b/tinyc/tests/tests2/43_void_param.expect @@ -0,0 +1 @@ +yo diff --git a/tinyc/tests/tests2/44_scoped_declarations.c b/tinyc/tests/tests2/44_scoped_declarations.c new file mode 100644 index 000000000..f38664fc5 --- /dev/null +++ b/tinyc/tests/tests2/44_scoped_declarations.c @@ -0,0 +1,17 @@ +#include + +int main() +{ + int a; + + for (a = 0; a < 2; a++) + { + int b = a; + } + + printf("it's all good\n"); + + return 0; +} + +/* vim: set expandtab ts=4 sw=3 sts=3 tw=80 :*/ diff --git a/tinyc/tests/tests2/44_scoped_declarations.expect b/tinyc/tests/tests2/44_scoped_declarations.expect new file mode 100644 index 000000000..231ccc0c5 --- /dev/null +++ b/tinyc/tests/tests2/44_scoped_declarations.expect @@ -0,0 +1 @@ +it's all good diff --git a/tinyc/tests/tests2/45_empty_for.c b/tinyc/tests/tests2/45_empty_for.c new file mode 100644 index 000000000..7cef513f8 --- /dev/null +++ b/tinyc/tests/tests2/45_empty_for.c @@ -0,0 +1,18 @@ +#include + +int main() +{ + int Count = 0; + + for (;;) + { + Count++; + printf("%d\n", Count); + if (Count >= 10) + break; + } + + return 0; +} + +/* vim: set expandtab ts=4 sw=3 sts=3 tw=80 :*/ diff --git a/tinyc/tests/tests2/45_empty_for.expect b/tinyc/tests/tests2/45_empty_for.expect new file mode 100644 index 000000000..f00c965d8 --- /dev/null +++ b/tinyc/tests/tests2/45_empty_for.expect @@ -0,0 +1,10 @@ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 diff --git a/tinyc/tests/tests2/46_grep.c b/tinyc/tests/tests2/46_grep.c new file mode 100644 index 000000000..049dfb15e --- /dev/null +++ b/tinyc/tests/tests2/46_grep.c @@ -0,0 +1,568 @@ +/* + * The information in this document is subject to change + * without notice and should not be construed as a commitment + * by Digital Equipment Corporation or by DECUS. + * + * Neither Digital Equipment Corporation, DECUS, nor the authors + * assume any responsibility for the use or reliability of this + * document or the described software. + * + * Copyright (C) 1980, DECUS + * + * General permission to copy or modify, but not for profit, is + * hereby granted, provided that the above copyright notice is + * included and reference made to the fact that reproduction + * privileges were granted by DECUS. + */ +#include +#include +#include // tolower() + +/* + * grep + * + * Runs on the Decus compiler or on vms, On vms, define as: + * grep :== "$disk:[account]grep" (native) + * grep :== "$disk:[account]grep grep" (Decus) + * See below for more information. + */ + +char *documentation[] = { + "grep searches a file for a given pattern. Execute by", + " grep [flags] regular_expression file_list\n", + "Flags are single characters preceded by '-':", + " -c Only a count of matching lines is printed", + " -f Print file name for matching lines switch, see below", + " -n Each line is preceded by its line number", + " -v Only print non-matching lines\n", + "The file_list is a list of files (wildcards are acceptable on RSX modes).", + "\nThe file name is normally printed if there is a file given.", + "The -f flag reverses this action (print name no file, not if more).\n", + 0 }; + +char *patdoc[] = { + "The regular_expression defines the pattern to search for. Upper- and", + "lower-case are always ignored. Blank lines never match. The expression", + "should be quoted to prevent file-name translation.", + "x An ordinary character (not mentioned below) matches that character.", + "'\\' The backslash quotes any character. \"\\$\" matches a dollar-sign.", + "'^' A circumflex at the beginning of an expression matches the", + " beginning of a line.", + "'$' A dollar-sign at the end of an expression matches the end of a line.", + "'.' A period matches any character except \"new-line\".", + "':a' A colon matches a class of characters described by the following", + "':d' character. \":a\" matches any alphabetic, \":d\" matches digits,", + "':n' \":n\" matches alphanumerics, \": \" matches spaces, tabs, and", + "': ' other control characters, such as new-line.", + "'*' An expression followed by an asterisk matches zero or more", + " occurrences of that expression: \"fo*\" matches \"f\", \"fo\"", + " \"foo\", etc.", + "'+' An expression followed by a plus sign matches one or more", + " occurrences of that expression: \"fo+\" matches \"fo\", etc.", + "'-' An expression followed by a minus sign optionally matches", + " the expression.", + "'[]' A string enclosed in square brackets matches any character in", + " that string, but no others. If the first character in the", + " string is a circumflex, the expression matches any character", + " except \"new-line\" and the characters in the string. For", + " example, \"[xyz]\" matches \"xx\" and \"zyx\", while \"[^xyz]\"", + " matches \"abc\" but not \"axb\". A range of characters may be", + " specified by two characters separated by \"-\". Note that,", + " [a-z] matches alphabetics, while [z-a] never matches.", + "The concatenation of regular expressions is a regular expression.", + 0}; + +#define LMAX 512 +#define PMAX 256 + +#define CHAR 1 +#define BOL 2 +#define EOL 3 +#define ANY 4 +#define CLASS 5 +#define NCLASS 6 +#define STAR 7 +#define PLUS 8 +#define MINUS 9 +#define ALPHA 10 +#define DIGIT 11 +#define NALPHA 12 +#define PUNCT 13 +#define RANGE 14 +#define ENDPAT 15 + +int cflag=0, fflag=0, nflag=0, vflag=0, nfile=0, debug=0; + +char *pp, lbuf[LMAX], pbuf[PMAX]; + +char *cclass(); +char *pmatch(); +void store(int); +void error(char *); +void badpat(char *, char *, char *); +int match(void); + + +/*** Display a file name *******************************/ +void file(char *s) +{ + printf("File %s:\n", s); +} + +/*** Report unopenable file ****************************/ +void cant(char *s) +{ + fprintf(stderr, "%s: cannot open\n", s); +} + +/*** Give good help ************************************/ +void help(char **hp) +{ + char **dp; + + for (dp = hp; *dp; ++dp) + printf("%s\n", *dp); +} + +/*** Display usage summary *****************************/ +void usage(char *s) +{ + fprintf(stderr, "?GREP-E-%s\n", s); + fprintf(stderr, + "Usage: grep [-cfnv] pattern [file ...]. grep ? for help\n"); + exit(1); +} + +/*** Compile the pattern into global pbuf[] ************/ +void compile(char *source) +{ + char *s; /* Source string pointer */ + char *lp; /* Last pattern pointer */ + int c; /* Current character */ + int o; /* Temp */ + char *spp; /* Save beginning of pattern */ + + s = source; + if (debug) + printf("Pattern = \"%s\"\n", s); + pp = pbuf; + while (c = *s++) { + /* + * STAR, PLUS and MINUS are special. + */ + if (c == '*' || c == '+' || c == '-') { + if (pp == pbuf || + (o=pp[-1]) == BOL || + o == EOL || + o == STAR || + o == PLUS || + o == MINUS) + badpat("Illegal occurrence op.", source, s); + store(ENDPAT); + store(ENDPAT); + spp = pp; /* Save pattern end */ + while (--pp > lp) /* Move pattern down */ + *pp = pp[-1]; /* one byte */ + *pp = (c == '*') ? STAR : + (c == '-') ? MINUS : PLUS; + pp = spp; /* Restore pattern end */ + continue; + } + /* + * All the rest. + */ + lp = pp; /* Remember start */ + switch(c) { + + case '^': + store(BOL); + break; + + case '$': + store(EOL); + break; + + case '.': + store(ANY); + break; + + case '[': + s = cclass(source, s); + break; + + case ':': + if (*s) { + switch(tolower(c = *s++)) { + + case 'a': + case 'A': + store(ALPHA); + break; + + case 'd': + case 'D': + store(DIGIT); + break; + + case 'n': + case 'N': + store(NALPHA); + break; + + case ' ': + store(PUNCT); + break; + + default: + badpat("Unknown : type", source, s); + + } + break; + } + else badpat("No : type", source, s); + + case '\\': + if (*s) + c = *s++; + + default: + store(CHAR); + store(tolower(c)); + } + } + store(ENDPAT); + store(0); /* Terminate string */ + if (debug) { + for (lp = pbuf; lp < pp;) { + if ((c = (*lp++ & 0377)) < ' ') + printf("\\%o ", c); + else printf("%c ", c); + } + printf("\n"); + } +} + +/*** Compile a class (within []) ***********************/ +char *cclass(char *source, char *src) + /* char *source; // Pattern start -- for error msg. */ + /* char *src; // Class start */ +{ + char *s; /* Source pointer */ + char *cp; /* Pattern start */ + int c; /* Current character */ + int o; /* Temp */ + + s = src; + o = CLASS; + if (*s == '^') { + ++s; + o = NCLASS; + } + store(o); + cp = pp; + store(0); /* Byte count */ + while ((c = *s++) && c!=']') { + if (c == '\\') { /* Store quoted char */ + if ((c = *s++) == '\0') /* Gotta get something */ + badpat("Class terminates badly", source, s); + else store(tolower(c)); + } + else if (c == '-' && + (pp - cp) > 1 && *s != ']' && *s != '\0') { + c = pp[-1]; /* Range start */ + pp[-1] = RANGE; /* Range signal */ + store(c); /* Re-store start */ + c = *s++; /* Get end char and*/ + store(tolower(c)); /* Store it */ + } + else { + store(tolower(c)); /* Store normal char */ + } + } + if (c != ']') + badpat("Unterminated class", source, s); + if ((c = (pp - cp)) >= 256) + badpat("Class too large", source, s); + if (c == 0) + badpat("Empty class", source, s); + *cp = c; + return(s); +} + +/*** Store an entry in the pattern buffer **************/ +void store(int op) +{ + if (pp >= &pbuf[PMAX]) + error("Pattern too complex\n"); + *pp++ = op; +} + +/*** Report a bad pattern specification ****************/ +void badpat(char *message, char *source, char *stop) + /* char *message; // Error message */ + /* char *source; // Pattern start */ + /* char *stop; // Pattern end */ +{ + fprintf(stderr, "-GREP-E-%s, pattern is\"%s\"\n", message, source); + fprintf(stderr, "-GREP-E-Stopped at byte %ld, '%c'\n", + stop-source, stop[-1]); + error("?GREP-E-Bad pattern\n"); +} + +/*** Scan the file for the pattern in pbuf[] ***********/ +void grep(FILE *fp, char *fn) + /* FILE *fp; // File to process */ + /* char *fn; // File name (for -f option) */ +{ + int lno, count, m; + + lno = 0; + count = 0; + while (fgets(lbuf, LMAX, fp)) { + ++lno; + m = match(); + if ((m && !vflag) || (!m && vflag)) { + ++count; + if (!cflag) { + if (fflag && fn) { + file(fn); + fn = 0; + } + if (nflag) + printf("%d\t", lno); + printf("%s\n", lbuf); + } + } + } + if (cflag) { + if (fflag && fn) + file(fn); + printf("%d\n", count); + } +} + +/*** Match line (lbuf) with pattern (pbuf) return 1 if match ***/ +int match() +{ + char *l; /* Line pointer */ + + for (l = lbuf; *l; ++l) { + if (pmatch(l, pbuf)) + return(1); + } + return(0); +} + +/*** Match partial line with pattern *******************/ +char *pmatch(char *line, char *pattern) + /* char *line; // (partial) line to match */ + /* char *pattern; // (partial) pattern to match */ +{ + char *l; /* Current line pointer */ + char *p; /* Current pattern pointer */ + char c; /* Current character */ + char *e; /* End for STAR and PLUS match */ + int op; /* Pattern operation */ + int n; /* Class counter */ + char *are; /* Start of STAR match */ + + l = line; + if (debug > 1) + printf("pmatch(\"%s\")\n", line); + p = pattern; + while ((op = *p++) != ENDPAT) { + if (debug > 1) + printf("byte[%ld] = 0%o, '%c', op = 0%o\n", + l-line, *l, *l, op); + switch(op) { + + case CHAR: + if (tolower(*l++) != *p++) + return(0); + break; + + case BOL: + if (l != lbuf) + return(0); + break; + + case EOL: + if (*l != '\0') + return(0); + break; + + case ANY: + if (*l++ == '\0') + return(0); + break; + + case DIGIT: + if ((c = *l++) < '0' || (c > '9')) + return(0); + break; + + case ALPHA: + c = tolower(*l++); + if (c < 'a' || c > 'z') + return(0); + break; + + case NALPHA: + c = tolower(*l++); + if (c >= 'a' && c <= 'z') + break; + else if (c < '0' || c > '9') + return(0); + break; + + case PUNCT: + c = *l++; + if (c == 0 || c > ' ') + return(0); + break; + + case CLASS: + case NCLASS: + c = tolower(*l++); + n = *p++ & 0377; + do { + if (*p == RANGE) { + p += 3; + n -= 2; + if (c >= p[-2] && c <= p[-1]) + break; + } + else if (c == *p++) + break; + } while (--n > 1); + if ((op == CLASS) == (n <= 1)) + return(0); + if (op == CLASS) + p += n - 2; + break; + + case MINUS: + e = pmatch(l, p); /* Look for a match */ + while (*p++ != ENDPAT); /* Skip over pattern */ + if (e) /* Got a match? */ + l = e; /* Yes, update string */ + break; /* Always succeeds */ + + case PLUS: /* One or more ... */ + if ((l = pmatch(l, p)) == 0) + return(0); /* Gotta have a match */ + case STAR: /* Zero or more ... */ + are = l; /* Remember line start */ + while (*l && (e = pmatch(l, p))) + l = e; /* Get longest match */ + while (*p++ != ENDPAT); /* Skip over pattern */ + while (l >= are) { /* Try to match rest */ + if (e = pmatch(l, p)) + return(e); + --l; /* Nope, try earlier */ + } + return(0); /* Nothing else worked */ + + default: + printf("Bad op code %d\n", op); + error("Cannot happen -- match\n"); + } + } + return(l); +} + +/*** Report an error ***********************************/ +void error(char *s) +{ + fprintf(stderr, "%s", s); + exit(1); +} + +/*** Main program - parse arguments & grep *************/ +int main(int argc, char **argv) +{ + char *p; + int c, i; + int gotpattern; + + FILE *f; + + if (argc <= 1) + usage("No arguments"); + if (argc == 2 && argv[1][0] == '?' && argv[1][1] == 0) { + help(documentation); + help(patdoc); + return 0; + } + nfile = argc-1; + gotpattern = 0; + for (i=1; i < argc; ++i) { + p = argv[i]; + if (*p == '-') { + ++p; + while (c = *p++) { + switch(tolower(c)) { + + case '?': + help(documentation); + break; + + case 'C': + case 'c': + ++cflag; + break; + + case 'D': + case 'd': + ++debug; + break; + + case 'F': + case 'f': + ++fflag; + break; + + case 'n': + case 'N': + ++nflag; + break; + + case 'v': + case 'V': + ++vflag; + break; + + default: + usage("Unknown flag"); + } + } + argv[i] = 0; + --nfile; + } else if (!gotpattern) { + compile(p); + argv[i] = 0; + ++gotpattern; + --nfile; + } + } + if (!gotpattern) + usage("No pattern"); + if (nfile == 0) + grep(stdin, 0); + else { + fflag = fflag ^ (nfile > 0); + for (i=1; i < argc; ++i) { + if (p = argv[i]) { + if ((f=fopen(p, "r")) == NULL) + cant(p); + else { + grep(f, p); + fclose(f); + } + } + } + } + return 0; +} + +/* vim: set expandtab ts=4 sw=3 sts=3 tw=80 :*/ diff --git a/tinyc/tests/tests2/46_grep.expect b/tinyc/tests/tests2/46_grep.expect new file mode 100644 index 000000000..e8a67916b --- /dev/null +++ b/tinyc/tests/tests2/46_grep.expect @@ -0,0 +1,3 @@ +File 46_grep.c: +/* vim: set expandtab ts=4 sw=3 sts=3 tw=80 :*/ + diff --git a/tinyc/tests/tests2/47_switch_return.c b/tinyc/tests/tests2/47_switch_return.c new file mode 100644 index 000000000..1ec7924c4 --- /dev/null +++ b/tinyc/tests/tests2/47_switch_return.c @@ -0,0 +1,24 @@ +#include + +void fred(int x) +{ + switch (x) + { + case 1: printf("1\n"); return; + case 2: printf("2\n"); break; + case 3: printf("3\n"); return; + } + + printf("out\n"); +} + +int main() +{ + fred(1); + fred(2); + fred(3); + + return 0; +} + +/* vim: set expandtab ts=4 sw=3 sts=3 tw=80 :*/ diff --git a/tinyc/tests/tests2/47_switch_return.expect b/tinyc/tests/tests2/47_switch_return.expect new file mode 100644 index 000000000..b6deb7e9e --- /dev/null +++ b/tinyc/tests/tests2/47_switch_return.expect @@ -0,0 +1,4 @@ +1 +2 +out +3 diff --git a/tinyc/tests/tests2/48_nested_break.c b/tinyc/tests/tests2/48_nested_break.c new file mode 100644 index 000000000..5bc5ba47f --- /dev/null +++ b/tinyc/tests/tests2/48_nested_break.c @@ -0,0 +1,26 @@ +#include + +int main() +{ + int a; + char b; + + a = 0; + while (a < 2) + { + printf("%d", a++); + break; + + b = 'A'; + while (b < 'C') + { + printf("%c", b++); + } + printf("e"); + } + printf("\n"); + + return 0; +} + +/* vim: set expandtab ts=4 sw=3 sts=3 tw=80 :*/ diff --git a/tinyc/tests/tests2/48_nested_break.expect b/tinyc/tests/tests2/48_nested_break.expect new file mode 100644 index 000000000..573541ac9 --- /dev/null +++ b/tinyc/tests/tests2/48_nested_break.expect @@ -0,0 +1 @@ +0 diff --git a/tinyc/tests/tests2/49_bracket_evaluation.c b/tinyc/tests/tests2/49_bracket_evaluation.c new file mode 100644 index 000000000..0cbe57d62 --- /dev/null +++ b/tinyc/tests/tests2/49_bracket_evaluation.c @@ -0,0 +1,23 @@ +#include + +struct point +{ + double x; + double y; +}; + +struct point point_array[100]; + +int main() +{ + int my_point = 10; + + point_array[my_point].x = 12.34; + point_array[my_point].y = 56.78; + + printf("%f, %f\n", point_array[my_point].x, point_array[my_point].y); + + return 0; +} + +/* vim: set expandtab ts=4 sw=3 sts=3 tw=80 :*/ diff --git a/tinyc/tests/tests2/49_bracket_evaluation.expect b/tinyc/tests/tests2/49_bracket_evaluation.expect new file mode 100644 index 000000000..1da66dbeb --- /dev/null +++ b/tinyc/tests/tests2/49_bracket_evaluation.expect @@ -0,0 +1 @@ +12.340000, 56.780000 diff --git a/tinyc/tests/tests2/50_logical_second_arg.c b/tinyc/tests/tests2/50_logical_second_arg.c new file mode 100644 index 000000000..ddec08c87 --- /dev/null +++ b/tinyc/tests/tests2/50_logical_second_arg.c @@ -0,0 +1,29 @@ +#include + +int fred() +{ + printf("fred\n"); + return 0; +} + +int joe() +{ + printf("joe\n"); + return 1; +} + +int main() +{ + printf("%d\n", fred() && joe()); + printf("%d\n", fred() || joe()); + printf("%d\n", joe() && fred()); + printf("%d\n", joe() || fred()); + printf("%d\n", fred() && (1 + joe())); + printf("%d\n", fred() || (0 + joe())); + printf("%d\n", joe() && (0 + fred())); + printf("%d\n", joe() || (1 + fred())); + + return 0; +} + +/* vim: set expandtab ts=4 sw=3 sts=3 tw=80 :*/ diff --git a/tinyc/tests/tests2/50_logical_second_arg.expect b/tinyc/tests/tests2/50_logical_second_arg.expect new file mode 100644 index 000000000..d6174ae7d --- /dev/null +++ b/tinyc/tests/tests2/50_logical_second_arg.expect @@ -0,0 +1,20 @@ +fred +0 +fred +joe +1 +joe +fred +0 +joe +1 +fred +0 +fred +joe +1 +joe +fred +0 +joe +1 diff --git a/tinyc/tests/tests2/51_static.c b/tinyc/tests/tests2/51_static.c new file mode 100644 index 000000000..d6c0917cf --- /dev/null +++ b/tinyc/tests/tests2/51_static.c @@ -0,0 +1,30 @@ +#include + +static int fred = 1234; +static int joe; + +void henry() +{ + static int fred = 4567; + + printf("%d\n", fred); + fred++; +} + +int main() +{ + printf("%d\n", fred); + henry(); + henry(); + henry(); + henry(); + printf("%d\n", fred); + fred = 8901; + joe = 2345; + printf("%d\n", fred); + printf("%d\n", joe); + + return 0; +} + +/* vim: set expandtab ts=4 sw=3 sts=3 tw=80 :*/ diff --git a/tinyc/tests/tests2/51_static.expect b/tinyc/tests/tests2/51_static.expect new file mode 100644 index 000000000..18224fa3e --- /dev/null +++ b/tinyc/tests/tests2/51_static.expect @@ -0,0 +1,8 @@ +1234 +4567 +4568 +4569 +4570 +1234 +8901 +2345 diff --git a/tinyc/tests/tests2/52_unnamed_enum.c b/tinyc/tests/tests2/52_unnamed_enum.c new file mode 100644 index 000000000..d0395b202 --- /dev/null +++ b/tinyc/tests/tests2/52_unnamed_enum.c @@ -0,0 +1,27 @@ +#include + +enum fred { a, b, c }; + +int main() +{ + printf("a=%d\n", a); + printf("b=%d\n", b); + printf("c=%d\n", c); + + enum fred d; + + typedef enum { e, f, g } h; + typedef enum { i, j, k } m; + + printf("e=%d\n", e); + printf("f=%d\n", f); + printf("g=%d\n", g); + + printf("i=%d\n", i); + printf("j=%d\n", j); + printf("k=%d\n", k); + + return 0; +} + +/* vim: set expandtab ts=4 sw=3 sts=3 tw=80 :*/ diff --git a/tinyc/tests/tests2/52_unnamed_enum.expect b/tinyc/tests/tests2/52_unnamed_enum.expect new file mode 100644 index 000000000..84f2ac846 --- /dev/null +++ b/tinyc/tests/tests2/52_unnamed_enum.expect @@ -0,0 +1,9 @@ +a=0 +b=1 +c=2 +e=0 +f=1 +g=2 +i=0 +j=1 +k=2 diff --git a/tinyc/tests/tests2/54_goto.c b/tinyc/tests/tests2/54_goto.c new file mode 100644 index 000000000..2e151bb76 --- /dev/null +++ b/tinyc/tests/tests2/54_goto.c @@ -0,0 +1,56 @@ +#include + +void fred() +{ + printf("In fred()\n"); + goto done; + printf("In middle\n"); +done: + printf("At end\n"); +} + +void joe() +{ + int b = 5678; + + printf("In joe()\n"); + + { + int c = 1234; + printf("c = %d\n", c); + goto outer; + printf("uh-oh\n"); + } + +outer: + + printf("done\n"); +} + +void henry() +{ + int a; + + printf("In henry()\n"); + goto inner; + + { + int b; +inner: + b = 1234; + printf("b = %d\n", b); + } + + printf("done\n"); +} + +int main() +{ + fred(); + joe(); + henry(); + + return 0; +} + +/* vim: set expandtab ts=4 sw=3 sts=3 tw=80 :*/ diff --git a/tinyc/tests/tests2/54_goto.expect b/tinyc/tests/tests2/54_goto.expect new file mode 100644 index 000000000..8e553fa62 --- /dev/null +++ b/tinyc/tests/tests2/54_goto.expect @@ -0,0 +1,8 @@ +In fred() +At end +In joe() +c = 1234 +done +In henry() +b = 1234 +done diff --git a/tinyc/tests/tests2/55_lshift_type.c b/tinyc/tests/tests2/55_lshift_type.c new file mode 100644 index 000000000..aa3e51a16 --- /dev/null +++ b/tinyc/tests/tests2/55_lshift_type.c @@ -0,0 +1,52 @@ +/* $Id: lshift-type.c 53089 2012-07-06 11:18:26Z vinc17/ypig $ + +Tests on left-shift type, written by Vincent Lefevre . + +ISO C99 TC3 says: [6.5.7#3] "The integer promotions are performed on +each of the operands. The type of the result is that of the promoted +left operand." +*/ + +#include + +#define PTYPE(M) ((M) < 0 || -(M) < 0 ? -1 : 1) * (int) sizeof((M)+0) +#define CHECK(X,T) check(#X, PTYPE(X), PTYPE((X) << (T) 1)) +#define TEST1(X,T) do { CHECK(X,T); CHECK(X,unsigned T); } while (0) +#define TEST2(X) \ + do \ + { \ + TEST1((X),short); \ + TEST1((X),int); \ + TEST1((X),long); \ + TEST1((X),long long); \ + } \ + while (0) +#define TEST3(X,T) do { TEST2((T)(X)); TEST2((unsigned T)(X)); } while (0) +#define TEST4(X) \ + do \ + { \ + TEST3((X),short); \ + TEST3((X),int); \ + TEST3((X),long); \ + TEST3((X),long long); \ + } \ + while (0) + +static int debug, nfailed = 0; + +static void check (const char *s, int arg1, int shift) +{ + int failed = arg1 != shift; + if (debug || failed) + printf ("%s %d %d\n", s, arg1, shift); + nfailed += failed; +} + +int main (int argc, char **argv) +{ + debug = argc > 1; + TEST4(1); + TEST4(-1); + printf ("%d test(s) failed\n", nfailed); + return nfailed != 0; +} diff --git a/tinyc/tests/tests2/55_lshift_type.expect b/tinyc/tests/tests2/55_lshift_type.expect new file mode 100644 index 000000000..8523767af --- /dev/null +++ b/tinyc/tests/tests2/55_lshift_type.expect @@ -0,0 +1 @@ +0 test(s) failed diff --git a/tinyc/tests/tests2/60_errors_and_warnings.c b/tinyc/tests/tests2/60_errors_and_warnings.c new file mode 100644 index 000000000..0028caffb --- /dev/null +++ b/tinyc/tests/tests2/60_errors_and_warnings.c @@ -0,0 +1,51 @@ +#if defined test_56_btype_excess_1 +struct A {} int i; + +#elif defined test_57_btype_excess_2 +char int i; + +#elif defined test_58_function_redefinition +int f(void) { return 0; } +int f(void) { return 1; } + +#elif defined test_global_redefinition +int xxx = 1; +int xxx; +int xxx = 2; + +#elif defined test_59_function_array +int (*fct)[42](int x); + +#elif defined test_60_enum_redefinition +enum color { RED, GREEN, BLUE }; +enum color { R, G, B }; +enum color c; + +#elif defined test_62_enumerator_redefinition +enum color { RED, GREEN, BLUE }; +enum rgb { RED, G, B}; +enum color c = RED; + +#elif defined test_63_local_enumerator_redefinition +enum { + FOO, + BAR +}; + +int main(void) +{ + enum { + FOO = 2, + BAR + }; + + return BAR - FOO; +} + +#elif defined test_61_undefined_enum +enum rgb3 c = 42; + +#elif defined test_74_non_const_init +int i = i++; + +#endif diff --git a/tinyc/tests/tests2/60_errors_and_warnings.expect b/tinyc/tests/tests2/60_errors_and_warnings.expect new file mode 100644 index 000000000..ed6a69019 --- /dev/null +++ b/tinyc/tests/tests2/60_errors_and_warnings.expect @@ -0,0 +1,28 @@ +[test_56_btype_excess_1] +60_errors_and_warnings.c:2: error: too many basic types + +[test_57_btype_excess_2] +60_errors_and_warnings.c:5: error: too many basic types + +[test_58_function_redefinition] +60_errors_and_warnings.c:9: error: redefinition of 'f' + +[test_global_redefinition] +60_errors_and_warnings.c:14: error: redefinition of 'xxx' + +[test_59_function_array] +60_errors_and_warnings.c:17: error: declaration of an array of functions + +[test_60_enum_redefinition] +60_errors_and_warnings.c:21: error: struct/union/enum already defined + +[test_62_enumerator_redefinition] +60_errors_and_warnings.c:26: error: redefinition of enumerator 'RED' + +[test_63_local_enumerator_redefinition] + +[test_61_undefined_enum] +60_errors_and_warnings.c:46: error: unknown type size + +[test_74_non_const_init] +60_errors_and_warnings.c:49: error: initializer element is not constant diff --git a/tinyc/tests/tests2/64_macro_nesting.c b/tinyc/tests/tests2/64_macro_nesting.c new file mode 100644 index 000000000..676e5d3ef --- /dev/null +++ b/tinyc/tests/tests2/64_macro_nesting.c @@ -0,0 +1,12 @@ +#include // printf() + +#define CAT2(a,b) a##b +#define CAT(a,b) CAT2(a,b) +#define AB(x) CAT(x,y) + +int main(void) +{ + int xy = 42; + printf("%d\n", CAT(A,B)(x)); + return 0; +} diff --git a/tinyc/tests/tests2/64_macro_nesting.expect b/tinyc/tests/tests2/64_macro_nesting.expect new file mode 100644 index 000000000..d81cc0710 --- /dev/null +++ b/tinyc/tests/tests2/64_macro_nesting.expect @@ -0,0 +1 @@ +42 diff --git a/tinyc/tests/tests2/67_macro_concat.c b/tinyc/tests/tests2/67_macro_concat.c new file mode 100644 index 000000000..c580d3a64 --- /dev/null +++ b/tinyc/tests/tests2/67_macro_concat.c @@ -0,0 +1,14 @@ +#include + +#define P(A,B) A ## B ; bob +#define Q(A,B) A ## B+ + +int main(void) +{ + int bob, jim = 21; + bob = P(jim,) *= 2; + printf("jim: %d, bob: %d\n", jim, bob); + jim = 60 Q(+,)3; + printf("jim: %d\n", jim); + return 0; +} diff --git a/tinyc/tests/tests2/67_macro_concat.expect b/tinyc/tests/tests2/67_macro_concat.expect new file mode 100644 index 000000000..8386c2d6c --- /dev/null +++ b/tinyc/tests/tests2/67_macro_concat.expect @@ -0,0 +1,2 @@ +jim: 21, bob: 42 +jim: 63 diff --git a/tinyc/tests/tests2/70_floating_point_literals.c b/tinyc/tests/tests2/70_floating_point_literals.c new file mode 100644 index 000000000..012fb4fab --- /dev/null +++ b/tinyc/tests/tests2/70_floating_point_literals.c @@ -0,0 +1,77 @@ +#include + +int main() +{ + /* decimal floating constant */ + float fa0 = .123f; + float fa1 = .123E12F; + float fa2 = .123e-12f; + float fa3 = .123e+12f; + printf("%f\n%f\n%f\n%f\n\n", fa0, fa1, fa2, fa3); + + float fb0 = 123.123f; + float fb1 = 123.123E12F; + float fb2 = 123.123e-12f; + float fb3 = 123.123e+12f; + printf("%f\n%f\n%f\n%f\n\n", fb0, fb1, fb2, fb3); + + float fc0 = 123.f; + float fc1 = 123.E12F; + float fc2 = 123.e-12f; + float fc3 = 123.e+12f; + printf("%f\n%f\n%f\n%f\n\n", fc0, fc1, fc2, fc3); + + float fd0 = 123E12F; + float fd1 = 123e-12f; + float fd2 = 123e+12f; + printf("%f\n%f\n%f\n\n", fd0, fd1, fd2); + printf("\n"); + + /* hexadecimal floating constant */ + double da0 = 0X.1ACP12; + double da1 = 0x.1acp-12; + double da2 = 0x.1acp+12; + printf("%f\n%f\n%f\n\n", da0, da1, da2); + + double db0 = 0X1AC.BDP12; + double db1 = 0x1ac.bdp-12; + double db2 = 0x1ac.dbp+12; + printf("%f\n%f\n%f\n\n", db0, db1, db2); + + double dc0 = 0X1AC.P12; + double dc1 = 0x1ac.p-12; + double dc2 = 0x1ac.p+12; + printf("%f\n%f\n%f\n\n", dc0, dc1, dc2); + + double dd0 = 0X1ACP12; + double dd1 = 0x1acp-12; + double dd2 = 0x1acp+12; + printf("%f\n%f\n%f\n\n", dd0, dd1, dd2); + printf("\n"); + +#ifdef __TINYC__ + /* TCC extension + binary floating constant */ + long double la0 = 0B.110101100P12L; + long double la1 = 0b.110101100p-12l; + long double la2 = 0b.110101100p+12l; + printf("%Lf\n%Lf\n%Lf\n\n", la0, la1, la2); + + long double lb0 = 0B110101100.10111101P12L; + long double lb1 = 0b110101100.10111101p-12l; + long double lb2 = 0b110101100.10111101p+12l; + printf("%Lf\n%Lf\n%Lf\n\n", lb0, lb1, lb2); + + long double lc0 = 0B110101100.P12L; + long double lc1 = 0b110101100.p-12l; + long double lc2 = 0b110101100.p+12l; + printf("%Lf\n%Lf\n%Lf\n\n", lc0, lc1, lc2); + + long double ld0 = 0B110101100P12L; + long double ld1 = 0b110101100p-12l; + long double ld2 = 0b110101100p+12l; + printf("%Lf\n%Lf\n%Lf\n\n", ld0, ld1, ld2); +#endif + + return 0; +} diff --git a/tinyc/tests/tests2/70_floating_point_literals.expect b/tinyc/tests/tests2/70_floating_point_literals.expect new file mode 100644 index 000000000..7eb1efb9e --- /dev/null +++ b/tinyc/tests/tests2/70_floating_point_literals.expect @@ -0,0 +1,53 @@ +0.123000 +122999996416.000000 +0.000000 +122999996416.000000 + +123.123001 +123122997002240.000000 +0.000000 +123122997002240.000000 + +123.000000 +123000003231744.000000 +0.000000 +123000003231744.000000 + +123000003231744.000000 +0.000000 +123000003231744.000000 + + +428.000000 +0.000026 +428.000000 + +1756112.000000 +0.104672 +1756592.000000 + +1753088.000000 +0.104492 +1753088.000000 + +1753088.000000 +0.104492 +1753088.000000 + + +3424.000000 +0.000204 +3424.000000 + +1756112.000000 +0.104672 +1756112.000000 + +1753088.000000 +0.104492 +1753088.000000 + +1753088.000000 +0.104492 +1753088.000000 + diff --git a/tinyc/tests/tests2/71_macro_empty_arg.c b/tinyc/tests/tests2/71_macro_empty_arg.c new file mode 100644 index 000000000..f0d3511b9 --- /dev/null +++ b/tinyc/tests/tests2/71_macro_empty_arg.c @@ -0,0 +1,9 @@ +#include + +#define T(a,b,c) a b c + +int main(void) +{ + printf("%d", T(1,+,2) T(+,,) T(,2,*) T(,7,) T(,,)); + return 0; +} diff --git a/tinyc/tests/tests2/71_macro_empty_arg.expect b/tinyc/tests/tests2/71_macro_empty_arg.expect new file mode 100644 index 000000000..98d9bcb75 --- /dev/null +++ b/tinyc/tests/tests2/71_macro_empty_arg.expect @@ -0,0 +1 @@ +17 diff --git a/tinyc/tests/tests2/72_long_long_constant.c b/tinyc/tests/tests2/72_long_long_constant.c new file mode 100644 index 000000000..66082133d --- /dev/null +++ b/tinyc/tests/tests2/72_long_long_constant.c @@ -0,0 +1,19 @@ +#include + +int main() +{ + long long int res = 0; + + if (res < -2147483648LL) { + printf("Error: 0 < -2147483648\n"); + return 1; + } + else + if (2147483647LL < res) { + printf("Error: 2147483647 < 0\n"); + return 2; + } + else + printf("long long constant test ok.\n"); + return 0; +} diff --git a/tinyc/tests/tests2/72_long_long_constant.expect b/tinyc/tests/tests2/72_long_long_constant.expect new file mode 100644 index 000000000..dda9e660d --- /dev/null +++ b/tinyc/tests/tests2/72_long_long_constant.expect @@ -0,0 +1 @@ +long long constant test ok. diff --git a/tinyc/tests/tests2/73_arm64.c b/tinyc/tests/tests2/73_arm64.c new file mode 100644 index 000000000..8de61b388 --- /dev/null +++ b/tinyc/tests/tests2/73_arm64.c @@ -0,0 +1,527 @@ +// This program is designed to test some arm64-specific things, such as the +// calling convention, but should give the same results on any architecture. + +#include +#include +#include + +struct s1 { char x[1]; } s1 = { "0" }; +struct s2 { char x[2]; } s2 = { "12" }; +struct s3 { char x[3]; } s3 = { "345" }; +struct s4 { char x[4]; } s4 = { "6789" }; +struct s5 { char x[5]; } s5 = { "abcde" }; +struct s6 { char x[6]; } s6 = { "fghijk" }; +struct s7 { char x[7]; } s7 = { "lmnopqr" }; +struct s8 { char x[8]; } s8 = { "stuvwxyz" }; +struct s9 { char x[9]; } s9 = { "ABCDEFGHI" }; +struct s10 { char x[10]; } s10 = { "JKLMNOPQRS" }; +struct s11 { char x[11]; } s11 = { "TUVWXYZ0123" }; +struct s12 { char x[12]; } s12 = { "456789abcdef" }; +struct s13 { char x[13]; } s13 = { "ghijklmnopqrs" }; +struct s14 { char x[14]; } s14 = { "tuvwxyzABCDEFG" }; +struct s15 { char x[15]; } s15 = { "HIJKLMNOPQRSTUV" }; +struct s16 { char x[16]; } s16 = { "WXYZ0123456789ab" }; +struct s17 { char x[17]; } s17 = { "cdefghijklmnopqrs" }; + +struct hfa11 { float a; } hfa11 = { 11.1 }; +struct hfa12 { float a, b; } hfa12 = { 12.1, 12.2 }; +struct hfa13 { float a, b, c; } hfa13 = { 13.1, 13.2, 13.3 }; +struct hfa14 { float a, b, c, d; } hfa14 = { 14.1, 14.2, 14.3, 14.4 }; + +struct hfa21 { double a; } hfa21 = { 21.1 }; +struct hfa22 { double a, b; } hfa22 = { 22.1, 22.2 }; +struct hfa23 { double a, b, c; } hfa23 = { 23.1, 23.2, 23.3 }; +struct hfa24 { double a, b, c, d; } hfa24 = { 24.1, 24.2, 24.3, 24.4 }; + +struct hfa31 { long double a; } hfa31 = { 31.1 }; +struct hfa32 { long double a, b; } hfa32 = { 32.1, 32.2 }; +struct hfa33 { long double a, b, c; } hfa33 = { 33.1, 33.2, 33.3 }; +struct hfa34 { long double a, b, c, d; } hfa34 = { 34.1, 34.2, 34.3, 34.4 }; + +void fa_s1(struct s1 a) { printf("%.1s\n", a.x); } +void fa_s2(struct s2 a) { printf("%.2s\n", a.x); } +void fa_s3(struct s3 a) { printf("%.3s\n", a.x); } +void fa_s4(struct s4 a) { printf("%.4s\n", a.x); } +void fa_s5(struct s5 a) { printf("%.5s\n", a.x); } +void fa_s6(struct s6 a) { printf("%.6s\n", a.x); } +void fa_s7(struct s7 a) { printf("%.7s\n", a.x); } +void fa_s8(struct s8 a) { printf("%.8s\n", a.x); } +void fa_s9(struct s9 a) { printf("%.9s\n", a.x); } +void fa_s10(struct s10 a) { printf("%.10s\n", a.x); } +void fa_s11(struct s11 a) { printf("%.11s\n", a.x); } +void fa_s12(struct s12 a) { printf("%.12s\n", a.x); } +void fa_s13(struct s13 a) { printf("%.13s\n", a.x); } +void fa_s14(struct s14 a) { printf("%.14s\n", a.x); } +void fa_s15(struct s15 a) { printf("%.15s\n", a.x); } +void fa_s16(struct s16 a) { printf("%.16s\n", a.x); } +void fa_s17(struct s17 a) { printf("%.17s\n", a.x); } + +void fa_hfa11(struct hfa11 a) +{ printf("%.1f\n", a.a); } +void fa_hfa12(struct hfa12 a) +{ printf("%.1f %.1f\n", a.a, a.a); } +void fa_hfa13(struct hfa13 a) +{ printf("%.1f %.1f %.1f\n", a.a, a.b, a.c); } +void fa_hfa14(struct hfa14 a) +{ printf("%.1f %.1f %.1f %.1f\n", a.a, a.b, a.c, a.d); } + +void fa_hfa21(struct hfa21 a) +{ printf("%.1f\n", a.a); } +void fa_hfa22(struct hfa22 a) +{ printf("%.1f %.1f\n", a.a, a.a); } +void fa_hfa23(struct hfa23 a) +{ printf("%.1f %.1f %.1f\n", a.a, a.b, a.c); } +void fa_hfa24(struct hfa24 a) +{ printf("%.1f %.1f %.1f %.1f\n", a.a, a.b, a.c, a.d); } + +void fa_hfa31(struct hfa31 a) +{ printf("%.1Lf\n", a.a); } +void fa_hfa32(struct hfa32 a) +{ printf("%.1Lf %.1Lf\n", a.a, a.a); } +void fa_hfa33(struct hfa33 a) +{ printf("%.1Lf %.1Lf %.1Lf\n", a.a, a.b, a.c); } +void fa_hfa34(struct hfa34 a) +{ printf("%.1Lf %.1Lf %.1Lf %.1Lf\n", a.a, a.b, a.c, a.d); } + +void fa1(struct s8 a, struct s9 b, struct s10 c, struct s11 d, + struct s12 e, struct s13 f) +{ + printf("%.3s %.3s %.3s %.3s %.3s %.3s\n", a.x, b.x, c.x, d.x, e.x, f.x); +} + +void fa2(struct s9 a, struct s10 b, struct s11 c, struct s12 d, + struct s13 e, struct s14 f) +{ + printf("%.3s %.3s %.3s %.3s %.3s %.3s\n", a.x, b.x, c.x, d.x, e.x, f.x); +} + +void fa3(struct hfa14 a, struct hfa23 b, struct hfa32 c) +{ + printf("%.1f %.1f %.1f %.1f %.1Lf %.1Lf\n", + a.a, a.d, b.a, b.c, c.a, c.b); +} + +void fa4(struct s1 a, struct hfa14 b, struct s2 c, struct hfa24 d, + struct s3 e, struct hfa34 f) +{ + printf("%.1s %.1f %.1f %.2s %.1f %.1f %.3s %.1Lf %.1Lf\n", + a.x, b.a, b.d, c.x, d.a, d.d, e.x, f.a, f.d); +} + +void arg(void) +{ + printf("Arguments:\n"); + fa_s1(s1); + fa_s2(s2); + fa_s3(s3); + fa_s4(s4); + fa_s5(s5); + fa_s6(s6); + fa_s7(s7); + fa_s8(s8); + fa_s9(s9); + fa_s10(s10); + fa_s11(s11); + fa_s12(s12); + fa_s13(s13); + fa_s14(s14); + fa_s15(s15); + fa_s16(s16); + fa_s17(s17); + fa_hfa11(hfa11); + fa_hfa12(hfa12); + fa_hfa13(hfa13); + fa_hfa14(hfa14); + fa_hfa21(hfa21); + fa_hfa22(hfa22); + fa_hfa23(hfa23); + fa_hfa24(hfa24); + fa_hfa31(hfa31); + fa_hfa32(hfa32); + fa_hfa33(hfa33); + fa_hfa34(hfa34); + fa1(s8, s9, s10, s11, s12, s13); + fa2(s9, s10, s11, s12, s13, s14); + fa3(hfa14, hfa23, hfa32); + fa4(s1, hfa14, s2, hfa24, s3, hfa34); +} + +struct s1 fr_s1(void) { return s1; } +struct s2 fr_s2(void) { return s2; } +struct s3 fr_s3(void) { return s3; } +struct s4 fr_s4(void) { return s4; } +struct s5 fr_s5(void) { return s5; } +struct s6 fr_s6(void) { return s6; } +struct s7 fr_s7(void) { return s7; } +struct s8 fr_s8(void) { return s8; } +struct s9 fr_s9(void) { return s9; } +struct s10 fr_s10(void) { return s10; } +struct s11 fr_s11(void) { return s11; } +struct s12 fr_s12(void) { return s12; } +struct s13 fr_s13(void) { return s13; } +struct s14 fr_s14(void) { return s14; } +struct s15 fr_s15(void) { return s15; } +struct s16 fr_s16(void) { return s16; } +struct s17 fr_s17(void) { return s17; } + +struct hfa11 fr_hfa11(void) { return hfa11; } +struct hfa12 fr_hfa12(void) { return hfa12; } +struct hfa13 fr_hfa13(void) { return hfa13; } +struct hfa14 fr_hfa14(void) { return hfa14; } + +struct hfa21 fr_hfa21(void) { return hfa21; } +struct hfa22 fr_hfa22(void) { return hfa22; } +struct hfa23 fr_hfa23(void) { return hfa23; } +struct hfa24 fr_hfa24(void) { return hfa24; } + +struct hfa31 fr_hfa31(void) { return hfa31; } +struct hfa32 fr_hfa32(void) { return hfa32; } +struct hfa33 fr_hfa33(void) { return hfa33; } +struct hfa34 fr_hfa34(void) { return hfa34; } + +void ret(void) +{ + struct s1 t1 = fr_s1(); + struct s2 t2 = fr_s2(); + struct s3 t3 = fr_s3(); + struct s4 t4 = fr_s4(); + struct s5 t5 = fr_s5(); + struct s6 t6 = fr_s6(); + struct s7 t7 = fr_s7(); + struct s8 t8 = fr_s8(); + struct s9 t9 = fr_s9(); + struct s10 t10 = fr_s10(); + struct s11 t11 = fr_s11(); + struct s12 t12 = fr_s12(); + struct s13 t13 = fr_s13(); + struct s14 t14 = fr_s14(); + struct s15 t15 = fr_s15(); + struct s16 t16 = fr_s16(); + struct s17 t17 = fr_s17(); + printf("Return values:\n"); + printf("%.1s\n", t1.x); + printf("%.2s\n", t2.x); + printf("%.3s\n", t3.x); + printf("%.4s\n", t4.x); + printf("%.5s\n", t5.x); + printf("%.6s\n", t6.x); + printf("%.7s\n", t7.x); + printf("%.8s\n", t8.x); + printf("%.9s\n", t9.x); + printf("%.10s\n", t10.x); + printf("%.11s\n", t11.x); + printf("%.12s\n", t12.x); + printf("%.13s\n", t13.x); + printf("%.14s\n", t14.x); + printf("%.15s\n", t15.x); + printf("%.16s\n", t16.x); + printf("%.17s\n", t17.x); + printf("%.1f\n", fr_hfa11().a); + printf("%.1f %.1f\n", fr_hfa12().a, fr_hfa12().b); + printf("%.1f %.1f\n", fr_hfa13().a, fr_hfa13().c); + printf("%.1f %.1f\n", fr_hfa14().a, fr_hfa14().d); + printf("%.1f\n", fr_hfa21().a); + printf("%.1f %.1f\n", fr_hfa22().a, fr_hfa22().b); + printf("%.1f %.1f\n", fr_hfa23().a, fr_hfa23().c); + printf("%.1f %.1f\n", fr_hfa24().a, fr_hfa24().d); + printf("%.1Lf\n", fr_hfa31().a); + printf("%.1Lf %.1Lf\n", fr_hfa32().a, fr_hfa32().b); + printf("%.1Lf %.1Lf\n", fr_hfa33().a, fr_hfa33().c); + printf("%.1Lf %.1Lf\n", fr_hfa34().a, fr_hfa34().d); +} + +int match(const char **s, const char *f) +{ + const char *p = *s; + for (p = *s; *f && *f == *p; f++, p++) + ; + if (!*f) { + *s = p - 1; + return 1; + } + return 0; +} + +void myprintf(const char *format, ...) +{ + const char *s; + va_list ap; + va_start(ap, format); + for (s = format; *s; s++) { + if (match(&s, "%7s")) { + struct s7 t7 = va_arg(ap, struct s7); + printf("%.7s", t7.x); + } + else if (match(&s, "%9s")) { + struct s9 t9 = va_arg(ap, struct s9); + printf("%.9s", t9.x); + } + else if (match(&s, "%hfa11")) { + struct hfa11 x = va_arg(ap, struct hfa11); + printf("%.1f,%.1f", x.a, x.a); + } + else if (match(&s, "%hfa12")) { + struct hfa12 x = va_arg(ap, struct hfa12); + printf("%.1f,%.1f", x.a, x.b); + } + else if (match(&s, "%hfa13")) { + struct hfa13 x = va_arg(ap, struct hfa13); + printf("%.1f,%.1f", x.a, x.c); + } + else if (match(&s, "%hfa14")) { + struct hfa14 x = va_arg(ap, struct hfa14); + printf("%.1f,%.1f", x.a, x.d); + } + else if (match(&s, "%hfa21")) { + struct hfa21 x = va_arg(ap, struct hfa21); + printf("%.1f,%.1f", x.a, x.a); + } + else if (match(&s, "%hfa22")) { + struct hfa22 x = va_arg(ap, struct hfa22); + printf("%.1f,%.1f", x.a, x.b); + } + else if (match(&s, "%hfa23")) { + struct hfa23 x = va_arg(ap, struct hfa23); + printf("%.1f,%.1f", x.a, x.c); + } + else if (match(&s, "%hfa24")) { + struct hfa24 x = va_arg(ap, struct hfa24); + printf("%.1f,%.1f", x.a, x.d); + } + else if (match(&s, "%hfa31")) { + struct hfa31 x = va_arg(ap, struct hfa31); + printf("%.1Lf,%.1Lf", x.a, x.a); + } + else if (match(&s, "%hfa32")) { + struct hfa32 x = va_arg(ap, struct hfa32); + printf("%.1Lf,%.1Lf", x.a, x.b); + } + else if (match(&s, "%hfa33")) { + struct hfa33 x = va_arg(ap, struct hfa33); + printf("%.1Lf,%.1Lf", x.a, x.c); + } + else if (match(&s, "%hfa34")) { + struct hfa34 x = va_arg(ap, struct hfa34); + printf("%.1Lf,%.1Lf", x.a, x.d); + } + else + putchar(*s); + } + putchar('\n'); +} + +void stdarg(void) +{ + printf("stdarg:\n"); + myprintf("%9s %9s %9s %9s %9s %9s", s9, s9, s9, s9, s9, s9); + myprintf("%7s %9s %9s %9s %9s %9s", s7, s9, s9, s9, s9, s9); + + myprintf("HFA long double:"); + myprintf("%hfa34 %hfa34 %hfa34 %hfa34", hfa34, hfa34, hfa34, hfa34); + myprintf("%hfa33 %hfa34 %hfa34 %hfa34", hfa33, hfa34, hfa34, hfa34); + myprintf("%hfa32 %hfa34 %hfa34 %hfa34", hfa32, hfa34, hfa34, hfa34); + myprintf("%hfa31 %hfa34 %hfa34 %hfa34", hfa31, hfa34, hfa34, hfa34); + + myprintf("%hfa32 %hfa33 %hfa33 %hfa33 %hfa33", + hfa32, hfa33, hfa33, hfa33, hfa33); + myprintf("%hfa31 %hfa33 %hfa33 %hfa33 %hfa33", + hfa31, hfa33, hfa33, hfa33, hfa33); + myprintf("%hfa33 %hfa33 %hfa33 %hfa33", + hfa33, hfa33, hfa33, hfa33); + + myprintf("%hfa34 %hfa32 %hfa32 %hfa32 %hfa32", + hfa34, hfa32, hfa32, hfa32, hfa32); + myprintf("%hfa33 %hfa32 %hfa32 %hfa32 %hfa32", + hfa33, hfa32, hfa32, hfa32, hfa32); + + myprintf("%hfa34 %hfa32 %hfa31 %hfa31 %hfa31 %hfa31", + hfa34, hfa32, hfa31, hfa31, hfa31, hfa31); + + myprintf("HFA double:"); + myprintf("%hfa24 %hfa24 %hfa24 %hfa24", hfa24, hfa24, hfa24, hfa24); + myprintf("%hfa23 %hfa24 %hfa24 %hfa24", hfa23, hfa24, hfa24, hfa24); + myprintf("%hfa22 %hfa24 %hfa24 %hfa24", hfa22, hfa24, hfa24, hfa24); + myprintf("%hfa21 %hfa24 %hfa24 %hfa24", hfa21, hfa24, hfa24, hfa24); + + myprintf("%hfa22 %hfa23 %hfa23 %hfa23 %hfa23", + hfa22, hfa23, hfa23, hfa23, hfa23); + myprintf("%hfa21 %hfa23 %hfa23 %hfa23 %hfa23", + hfa21, hfa23, hfa23, hfa23, hfa23); + myprintf("%hfa23 %hfa23 %hfa23 %hfa23", + hfa23, hfa23, hfa23, hfa23); + + myprintf("%hfa24 %hfa22 %hfa22 %hfa22 %hfa22", + hfa24, hfa22, hfa22, hfa22, hfa22); + myprintf("%hfa23 %hfa22 %hfa22 %hfa22 %hfa22", + hfa23, hfa22, hfa22, hfa22, hfa22); + + myprintf("%hfa24 %hfa22 %hfa21 %hfa21 %hfa21 %hfa21", + hfa24, hfa22, hfa21, hfa21, hfa21, hfa21); + + myprintf("HFA float:"); + myprintf("%hfa14 %hfa14 %hfa14 %hfa14", hfa14, hfa14, hfa14, hfa14); + myprintf("%hfa13 %hfa14 %hfa14 %hfa14", hfa13, hfa14, hfa14, hfa14); + myprintf("%hfa12 %hfa14 %hfa14 %hfa14", hfa12, hfa14, hfa14, hfa14); + myprintf("%hfa11 %hfa14 %hfa14 %hfa14", hfa11, hfa14, hfa14, hfa14); + + myprintf("%hfa12 %hfa13 %hfa13 %hfa13 %hfa13", + hfa12, hfa13, hfa13, hfa13, hfa13); + myprintf("%hfa11 %hfa13 %hfa13 %hfa13 %hfa13", + hfa11, hfa13, hfa13, hfa13, hfa13); + myprintf("%hfa13 %hfa13 %hfa13 %hfa13", + hfa13, hfa13, hfa13, hfa13); + + myprintf("%hfa14 %hfa12 %hfa12 %hfa12 %hfa12", + hfa14, hfa12, hfa12, hfa12, hfa12); + myprintf("%hfa13 %hfa12 %hfa12 %hfa12 %hfa12", + hfa13, hfa12, hfa12, hfa12, hfa12); + + myprintf("%hfa14 %hfa12 %hfa11 %hfa11 %hfa11 %hfa11", + hfa14, hfa12, hfa11, hfa11, hfa11, hfa11); +} + +void pll(unsigned long long x) +{ + printf("%llx\n", x); +} + +void movi(void) +{ + printf("MOVI:\n"); + pll(0); + pll(0xabcd); + pll(0xabcd0000); + pll(0xabcd00000000); + pll(0xabcd000000000000); + pll(0xffffabcd); + pll(0xabcdffff); + pll(0xffffffffffffabcd); + pll(0xffffffffabcdffff); + pll(0xffffabcdffffffff); + pll(0xabcdffffffffffff); + pll(0xaaaaaaaa); + pll(0x5555555555555555); + pll(0x77777777); + pll(0x3333333333333333); + pll(0xf8f8f8f8); + pll(0x1e1e1e1e1e1e1e1e); + pll(0x3f803f80); + pll(0x01ff01ff01ff01ff); + pll(0x007fffc0); + pll(0x03fff80003fff800); + pll(0x0007fffffffffe00); + + pll(0xabcd1234); + pll(0xabcd00001234); + pll(0xabcd000000001234); + pll(0xabcd12340000); + pll(0xabcd000012340000); + pll(0xabcd123400000000); + pll(0xffffffffabcd1234); + pll(0xffffabcdffff1234); + pll(0xabcdffffffff1234); + pll(0xffffabcd1234ffff); + pll(0xabcdffff1234ffff); + pll(0xabcd1234ffffffff); + + pll(0xffffef0123456789); + pll(0xabcdef012345ffff); + + pll(0xabcdef0123456789); +} + +static uint32_t addip0(uint32_t x) { return x + 0; } +static uint64_t sublp0(uint64_t x) { return x - 0; } +static uint32_t addip123(uint32_t x) { return x + 123; } +static uint64_t addlm123(uint64_t x) { return x + -123; } +static uint64_t sublp4095(uint64_t x) { return x - 4095; } +static uint32_t subim503808(uint32_t x) { return x - -503808; } +static uint64_t addp12345(uint64_t x) { return x + 12345; } +static uint32_t subp12345(uint32_t x) { return x - 12345; } + +static uint32_t mvni(uint32_t x) { return 0xffffffff - x; } +static uint64_t negl(uint64_t x) { return 0 - x; } +static uint32_t rsbi123(uint32_t x) { return 123 - x; } +static uint64_t rsbl123(uint64_t x) { return 123 - x; } + +static uint32_t andi0(uint32_t x) { return x & 0; } +static uint64_t andlm1(uint64_t x) { return x & -1; } +static uint64_t orrl0(uint64_t x) { return x | 0; } +static uint32_t orrim1(uint32_t x) { return x | -1; } +static uint32_t eori0(uint32_t x) { return x ^ 0; } +static uint64_t eorlm1(uint64_t x) { return x ^ -1; } +static uint32_t and0xf0(uint32_t x) { return x & 0xf0; } +static uint64_t orr0xf0(uint64_t x) { return x | 0xf0; } +static uint64_t eor0xf0(uint64_t x) { return x ^ 0xf0; } + +static uint32_t lsli0(uint32_t x) { return x << 0; } +static uint32_t lsri0(uint32_t x) { return x >> 0; } +static int64_t asrl0(int64_t x) { return x >> 0; } +static uint32_t lsli1(uint32_t x) { return x << 1; } +static uint32_t lsli31(uint32_t x) { return x << 31; } +static uint64_t lsll1(uint64_t x) { return x << 1; } +static uint64_t lsll63(uint64_t x) { return x << 63; } +static uint32_t lsri1(uint32_t x) { return x >> 1; } +static uint32_t lsri31(uint32_t x) { return x >> 31; } +static uint64_t lsrl1(uint64_t x) { return x >> 1; } +static uint64_t lsrl63(uint64_t x) { return x >> 63; } +static int32_t asri1(int32_t x) { return x >> 1; } +static int32_t asri31(int32_t x) { return x >> 31; } +static int64_t asrl1(int64_t x) { return x >> 1; } +static int64_t asrl63(int64_t x) { return x >> 63; } + +void opi(void) +{ + int x = 1000; + pll(addip0(x)); + pll(sublp0(x)); + pll(addip123(x)); + pll(addlm123(x)); + pll(sublp4095(x)); + pll(subim503808(x)); + pll(addp12345(x)); + pll(subp12345(x)); + pll(mvni(x)); + pll(negl(x)); + pll(rsbi123(x)); + pll(rsbl123(x)); + pll(andi0(x)); + pll(andlm1(x)); + pll(orrl0(x)); + pll(orrim1(x)); + pll(eori0(x)); + pll(eorlm1(x)); + pll(and0xf0(x)); + pll(orr0xf0(x)); + pll(eor0xf0(x)); + pll(lsli0(x)); + pll(lsri0(x)); + pll(asrl0(x)); + pll(lsli1(x)); + pll(lsli31(x)); + pll(lsll1(x)); + pll(lsll63(x)); + pll(lsri1(x)); + pll(lsri31(x)); + pll(lsrl1(x)); + pll(lsrl63(x)); + pll(asri1(x)); + pll(asri31(x)); + pll(asrl1(x)); + pll(asrl63(x)); +} + +void pcs(void) +{ + arg(); + ret(); + stdarg(); + movi(); + opi(); +} + +int main() +{ + pcs(); + return 0; +} diff --git a/tinyc/tests/tests2/73_arm64.expect b/tinyc/tests/tests2/73_arm64.expect new file mode 100644 index 000000000..7bdebd307 --- /dev/null +++ b/tinyc/tests/tests2/73_arm64.expect @@ -0,0 +1,174 @@ +Arguments: +0 +12 +345 +6789 +abcde +fghijk +lmnopqr +stuvwxyz +ABCDEFGHI +JKLMNOPQRS +TUVWXYZ0123 +456789abcdef +ghijklmnopqrs +tuvwxyzABCDEFG +HIJKLMNOPQRSTUV +WXYZ0123456789ab +cdefghijklmnopqrs +11.1 +12.1 12.1 +13.1 13.2 13.3 +14.1 14.2 14.3 14.4 +21.1 +22.1 22.1 +23.1 23.2 23.3 +24.1 24.2 24.3 24.4 +31.1 +32.1 32.1 +33.1 33.2 33.3 +34.1 34.2 34.3 34.4 +stu ABC JKL TUV 456 ghi +ABC JKL TUV 456 ghi tuv +14.1 14.4 23.1 23.3 32.1 32.2 +0 14.1 14.4 12 24.1 24.4 345 34.1 34.4 +Return values: +0 +12 +345 +6789 +abcde +fghijk +lmnopqr +stuvwxyz +ABCDEFGHI +JKLMNOPQRS +TUVWXYZ0123 +456789abcdef +ghijklmnopqrs +tuvwxyzABCDEFG +HIJKLMNOPQRSTUV +WXYZ0123456789ab +cdefghijklmnopqrs +11.1 +12.1 12.2 +13.1 13.3 +14.1 14.4 +21.1 +22.1 22.2 +23.1 23.3 +24.1 24.4 +31.1 +32.1 32.2 +33.1 33.3 +34.1 34.4 +stdarg: +ABCDEFGHI ABCDEFGHI ABCDEFGHI ABCDEFGHI ABCDEFGHI ABCDEFGHI +lmnopqr ABCDEFGHI ABCDEFGHI ABCDEFGHI ABCDEFGHI ABCDEFGHI +HFA long double: +34.1,34.4 34.1,34.4 34.1,34.4 34.1,34.4 +33.1,33.3 34.1,34.4 34.1,34.4 34.1,34.4 +32.1,32.2 34.1,34.4 34.1,34.4 34.1,34.4 +31.1,31.1 34.1,34.4 34.1,34.4 34.1,34.4 +32.1,32.2 33.1,33.3 33.1,33.3 33.1,33.3 33.1,33.3 +31.1,31.1 33.1,33.3 33.1,33.3 33.1,33.3 33.1,33.3 +33.1,33.3 33.1,33.3 33.1,33.3 33.1,33.3 +34.1,34.4 32.1,32.2 32.1,32.2 32.1,32.2 32.1,32.2 +33.1,33.3 32.1,32.2 32.1,32.2 32.1,32.2 32.1,32.2 +34.1,34.4 32.1,32.2 31.1,31.1 31.1,31.1 31.1,31.1 31.1,31.1 +HFA double: +24.1,24.4 24.1,24.4 24.1,24.4 24.1,24.4 +23.1,23.3 24.1,24.4 24.1,24.4 24.1,24.4 +22.1,22.2 24.1,24.4 24.1,24.4 24.1,24.4 +21.1,21.1 24.1,24.4 24.1,24.4 24.1,24.4 +22.1,22.2 23.1,23.3 23.1,23.3 23.1,23.3 23.1,23.3 +21.1,21.1 23.1,23.3 23.1,23.3 23.1,23.3 23.1,23.3 +23.1,23.3 23.1,23.3 23.1,23.3 23.1,23.3 +24.1,24.4 22.1,22.2 22.1,22.2 22.1,22.2 22.1,22.2 +23.1,23.3 22.1,22.2 22.1,22.2 22.1,22.2 22.1,22.2 +24.1,24.4 22.1,22.2 21.1,21.1 21.1,21.1 21.1,21.1 21.1,21.1 +HFA float: +14.1,14.4 14.1,14.4 14.1,14.4 14.1,14.4 +13.1,13.3 14.1,14.4 14.1,14.4 14.1,14.4 +12.1,12.2 14.1,14.4 14.1,14.4 14.1,14.4 +11.1,11.1 14.1,14.4 14.1,14.4 14.1,14.4 +12.1,12.2 13.1,13.3 13.1,13.3 13.1,13.3 13.1,13.3 +11.1,11.1 13.1,13.3 13.1,13.3 13.1,13.3 13.1,13.3 +13.1,13.3 13.1,13.3 13.1,13.3 13.1,13.3 +14.1,14.4 12.1,12.2 12.1,12.2 12.1,12.2 12.1,12.2 +13.1,13.3 12.1,12.2 12.1,12.2 12.1,12.2 12.1,12.2 +14.1,14.4 12.1,12.2 11.1,11.1 11.1,11.1 11.1,11.1 11.1,11.1 +MOVI: +0 +abcd +abcd0000 +abcd00000000 +abcd000000000000 +ffffabcd +abcdffff +ffffffffffffabcd +ffffffffabcdffff +ffffabcdffffffff +abcdffffffffffff +aaaaaaaa +5555555555555555 +77777777 +3333333333333333 +f8f8f8f8 +1e1e1e1e1e1e1e1e +3f803f80 +1ff01ff01ff01ff +7fffc0 +3fff80003fff800 +7fffffffffe00 +abcd1234 +abcd00001234 +abcd000000001234 +abcd12340000 +abcd000012340000 +abcd123400000000 +ffffffffabcd1234 +ffffabcdffff1234 +abcdffffffff1234 +ffffabcd1234ffff +abcdffff1234ffff +abcd1234ffffffff +ffffef0123456789 +abcdef012345ffff +abcdef0123456789 +3e8 +3e8 +463 +36d +fffffffffffff3e9 +7b3e8 +3421 +ffffd3af +fffffc17 +fffffffffffffc18 +fffffc93 +fffffffffffffc93 +0 +3e8 +3e8 +ffffffff +3e8 +fffffffffffffc17 +e0 +3f8 +318 +3e8 +3e8 +3e8 +7d0 +0 +7d0 +0 +1f4 +0 +1f4 +0 +1f4 +0 +1f4 +0 diff --git a/tinyc/tests/tests2/75_array_in_struct_init.c b/tinyc/tests/tests2/75_array_in_struct_init.c new file mode 100644 index 000000000..234e3c4fa --- /dev/null +++ b/tinyc/tests/tests2/75_array_in_struct_init.c @@ -0,0 +1,33 @@ +#include + +/* This test is a snippet from the J interpreter */ + +typedef long I; +typedef struct{I c[4];I b,e,k;} PT; + +PT cases[] = { + ((I)4194304L +(I)2097152L +(I)67108864L), (I)262144L, (((I)1L +(I)256L +(I)4L +(I)8L +(I)16L +(I)64L +(I)128L +(I)268435456L +(I)536870912L +(I)1024L +(I)4096L +(I)8192L +(I)16384L)+((I)2L +(I)131072L +(I)2048L)+(I)32L +(I)32768L +(I)65536L), -1L, 1,2,1, + ((I)+4194304L +(I)2097152L +(I)67108864L)+( (I)524288L +(I)262144L +(((I)1L +(I)256L +(I)4L +(I)8L +(I)16L +(I)64L +(I)128L +(I)268435456L +(I)536870912L +(I)1024L +(I)4096L +(I)8192L +(I)16384L)+((I)2L +(I)131072L +(I)2048L)+(I)32L +(I)32768L +(I)65536L)), (I)262144L, (I)262144L, (((I)1L +(I)256L +(I)4L +(I)8L +(I)16L +(I)64L +(I)128L +(I)268435456L +(I)536870912L +(I)1024L +(I)4096L +(I)8192L +(I)16384L)+((I)2L +(I)131072L +(I)2048L)+(I)32L +(I)32768L +(I)65536L), 2,3,2, + ((I)4194304L +(I)2097152L +(I)67108864L)+( (I)524288L +(I)262144L +(((I)1L +(I)256L +(I)4L +(I)8L +(I)16L +(I)64L +(I)128L +(I)268435456L +(I)536870912L +(I)1024L +(I)4096L +(I)8192L +(I)16384L)+((I)2L +(I)131072L +(I)2048L)+(I)32L +(I)32768L +(I)65536L)), (((I)1L +(I)256L +(I)4L +(I)8L +(I)16L +(I)64L +(I)128L +(I)268435456L +(I)536870912L +(I)1024L +(I)4096L +(I)8192L +(I)16384L)+((I)2L +(I)131072L +(I)2048L)+(I)32L +(I)32768L +(I)65536L), (I)262144L, (((I)1L +(I)256L +(I)4L +(I)8L +(I)16L +(I)64L +(I)128L +(I)268435456L +(I)536870912L +(I)1024L +(I)4096L +(I)8192L +(I)16384L)+((I)2L +(I)131072L +(I)2048L)+(I)32L +(I)32768L +(I)65536L), 1,3,2, + ((I)4194304L +(I)2097152L +(I)67108864L)+( (I)524288L +(I)262144L +(((I)1L +(I)256L +(I)4L +(I)8L +(I)16L +(I)64L +(I)128L +(I)268435456L +(I)536870912L +(I)1024L +(I)4096L +(I)8192L +(I)16384L)+((I)2L +(I)131072L +(I)2048L)+(I)32L +(I)32768L +(I)65536L)), (I)262144L +(((I)1L +(I)256L +(I)4L +(I)8L +(I)16L +(I)64L +(I)128L +(I)268435456L +(I)536870912L +(I)1024L +(I)4096L +(I)8192L +(I)16384L)+((I)2L +(I)131072L +(I)2048L)+(I)32L +(I)32768L +(I)65536L), (I)524288L, -1L, 1,2,1, + ((I)4194304L +(I)2097152L +(I)67108864L)+( (I)524288L +(I)262144L +(((I)1L +(I)256L +(I)4L +(I)8L +(I)16L +(I)64L +(I)128L +(I)268435456L +(I)536870912L +(I)1024L +(I)4096L +(I)8192L +(I)16384L)+((I)2L +(I)131072L +(I)2048L)+(I)32L +(I)32768L +(I)65536L)), (I)262144L +(((I)1L +(I)256L +(I)4L +(I)8L +(I)16L +(I)64L +(I)128L +(I)268435456L +(I)536870912L +(I)1024L +(I)4096L +(I)8192L +(I)16384L)+((I)2L +(I)131072L +(I)2048L)+(I)32L +(I)32768L +(I)65536L), (I)1048576L, (I)262144L +(((I)1L +(I)256L +(I)4L +(I)8L +(I)16L +(I)64L +(I)128L +(I)268435456L +(I)536870912L +(I)1024L +(I)4096L +(I)8192L +(I)16384L)+((I)2L +(I)131072L +(I)2048L)+(I)32L +(I)32768L +(I)65536L), 1,3,1, + ((I)4194304L +(I)2097152L +(I)67108864L)+( (I)524288L +(I)262144L +(((I)1L +(I)256L +(I)4L +(I)8L +(I)16L +(I)64L +(I)128L +(I)268435456L +(I)536870912L +(I)1024L +(I)4096L +(I)8192L +(I)16384L)+((I)2L +(I)131072L +(I)2048L)+(I)32L +(I)32768L +(I)65536L)), (I)262144L +(((I)1L +(I)256L +(I)4L +(I)8L +(I)16L +(I)64L +(I)128L +(I)268435456L +(I)536870912L +(I)1024L +(I)4096L +(I)8192L +(I)16384L)+((I)2L +(I)131072L +(I)2048L)+(I)32L +(I)32768L +(I)65536L), (I)262144L, (I)262144L, 1,3,1, + ((I)4194304L +(I)2097152L +(I)67108864L), ((I)1048576L +(I)524288L +(I)262144L +(((I)1L +(I)256L +(I)4L +(I)8L +(I)16L +(I)64L +(I)128L +(I)268435456L +(I)536870912L +(I)1024L +(I)4096L +(I)8192L +(I)16384L)+((I)2L +(I)131072L +(I)2048L)+(I)32L +(I)32768L +(I)65536L)), ((I)1048576L +(I)524288L +(I)262144L +(((I)1L +(I)256L +(I)4L +(I)8L +(I)16L +(I)64L +(I)128L +(I)268435456L +(I)536870912L +(I)1024L +(I)4096L +(I)8192L +(I)16384L)+((I)2L +(I)131072L +(I)2048L)+(I)32L +(I)32768L +(I)65536L)), -1L, 1,2,1, + (I)33554432L +(((I)1L +(I)256L +(I)4L +(I)8L +(I)16L +(I)64L +(I)128L +(I)268435456L +(I)536870912L +(I)1024L +(I)4096L +(I)8192L +(I)16384L)+((I)2L +(I)131072L +(I)2048L)+(I)32L +(I)32768L +(I)65536L), (I)2097152L, ((I)1048576L +(I)524288L +(I)262144L +(((I)1L +(I)256L +(I)4L +(I)8L +(I)16L +(I)64L +(I)128L +(I)268435456L +(I)536870912L +(I)1024L +(I)4096L +(I)8192L +(I)16384L)+((I)2L +(I)131072L +(I)2048L)+(I)32L +(I)32768L +(I)65536L)), -1L, 0,2,1, + (I)67108864L, ((I)1048576L +(I)524288L +(I)262144L +(((I)1L +(I)256L +(I)4L +(I)8L +(I)16L +(I)64L +(I)128L +(I)268435456L +(I)536870912L +(I)1024L +(I)4096L +(I)8192L +(I)16384L)+((I)2L +(I)131072L +(I)2048L)+(I)32L +(I)32768L +(I)65536L)), (I)134217728L, -1L, 0,2,0, +}; + +int main() { + int i, j; + + for(j=0; j < sizeof(cases)/sizeof(cases[0]); j++) { + for(i=0; i < sizeof(cases->c)/sizeof(cases->c[0]); i++) + printf("cases[%d].c[%d]=%ld\n", j, i, cases[j].c[i]); + + printf("cases[%d].b=%ld\n", j, cases[j].b); + printf("cases[%d].e=%ld\n", j, cases[j].e); + printf("cases[%d].k=%ld\n", j, cases[j].k); + printf("\n"); + } + return 0; +} diff --git a/tinyc/tests/tests2/75_array_in_struct_init.expect b/tinyc/tests/tests2/75_array_in_struct_init.expect new file mode 100644 index 000000000..2b75aa59d --- /dev/null +++ b/tinyc/tests/tests2/75_array_in_struct_init.expect @@ -0,0 +1,72 @@ +cases[0].c[0]=73400320 +cases[0].c[1]=262144 +cases[0].c[2]=805567999 +cases[0].c[3]=-1 +cases[0].b=1 +cases[0].e=2 +cases[0].k=1 + +cases[1].c[0]=879754751 +cases[1].c[1]=262144 +cases[1].c[2]=262144 +cases[1].c[3]=805567999 +cases[1].b=2 +cases[1].e=3 +cases[1].k=2 + +cases[2].c[0]=879754751 +cases[2].c[1]=805567999 +cases[2].c[2]=262144 +cases[2].c[3]=805567999 +cases[2].b=1 +cases[2].e=3 +cases[2].k=2 + +cases[3].c[0]=879754751 +cases[3].c[1]=805830143 +cases[3].c[2]=524288 +cases[3].c[3]=-1 +cases[3].b=1 +cases[3].e=2 +cases[3].k=1 + +cases[4].c[0]=879754751 +cases[4].c[1]=805830143 +cases[4].c[2]=1048576 +cases[4].c[3]=805830143 +cases[4].b=1 +cases[4].e=3 +cases[4].k=1 + +cases[5].c[0]=879754751 +cases[5].c[1]=805830143 +cases[5].c[2]=262144 +cases[5].c[3]=262144 +cases[5].b=1 +cases[5].e=3 +cases[5].k=1 + +cases[6].c[0]=73400320 +cases[6].c[1]=807403007 +cases[6].c[2]=807403007 +cases[6].c[3]=-1 +cases[6].b=1 +cases[6].e=2 +cases[6].k=1 + +cases[7].c[0]=839122431 +cases[7].c[1]=2097152 +cases[7].c[2]=807403007 +cases[7].c[3]=-1 +cases[7].b=0 +cases[7].e=2 +cases[7].k=1 + +cases[8].c[0]=67108864 +cases[8].c[1]=807403007 +cases[8].c[2]=134217728 +cases[8].c[3]=-1 +cases[8].b=0 +cases[8].e=2 +cases[8].k=0 + diff --git a/tinyc/tests/tests2/76_dollars_in_identifiers.c b/tinyc/tests/tests2/76_dollars_in_identifiers.c new file mode 100644 index 000000000..c5fcf99e0 --- /dev/null +++ b/tinyc/tests/tests2/76_dollars_in_identifiers.c @@ -0,0 +1,41 @@ +#include + +#define $(x) x +#define $fred 10 +#define joe$ 20 +#define hen$y 30 + +#define $10(x) x*10 +#define _$10(x) x/10 + +int main() +{ + printf("fred=%d\n", $fred); + printf("joe=%d\n", joe$); + printf("henry=%d\n", hen$y); + + printf("fred2=%d\n", $($fred)); + printf("joe2=%d\n", $(joe$)); + printf("henry2=%d\n", $(hen$y)); + + printf("fred10=%d\n", $10($fred)); + printf("joe_10=%d\n", _$10(joe$)); + + int $ = 10; + int a100$ = 100; + int a$$ = 1000; + int a$c$b = 2121; + int $100 = 10000; + const char *$$$ = "money"; + + printf("local=%d\n", $); + printf("a100$=%d\n", a100$); + printf("a$$=%d\n", a$$); + printf("a$c$b=%d\n", a$c$b); + printf("$100=%d\n", $100); + printf("$$$=%s", $$$); + + return 0; +} + +/* vim: set expandtab ts=4 sw=3 sts=3 tw=80 :*/ diff --git a/tinyc/tests/tests2/76_dollars_in_identifiers.expect b/tinyc/tests/tests2/76_dollars_in_identifiers.expect new file mode 100644 index 000000000..4a20a52e6 --- /dev/null +++ b/tinyc/tests/tests2/76_dollars_in_identifiers.expect @@ -0,0 +1,14 @@ +fred=10 +joe=20 +henry=30 +fred2=10 +joe2=20 +henry2=30 +fred10=100 +joe_10=2 +local=10 +a100$=100 +a$$=1000 +a$c$b=2121 +$100=10000 +$$$=money diff --git a/tinyc/tests/tests2/77_push_pop_macro.c b/tinyc/tests/tests2/77_push_pop_macro.c new file mode 100644 index 000000000..d38e0bfe3 --- /dev/null +++ b/tinyc/tests/tests2/77_push_pop_macro.c @@ -0,0 +1,30 @@ +#include + +int main() +{ + /* must not affect how #pragma ppop_macro works */ + #define pop_macro foobar1 + + /* must not affect how #pragma push_macro works */ + #define push_macro foobar2 + + #undef abort + #define abort "111" + printf("abort = %s\n", abort); + + #pragma push_macro("abort") + #undef abort + #define abort "222" + printf("abort = %s\n", abort); + + #pragma push_macro("abort") + #undef abort + #define abort "333" + printf("abort = %s\n", abort); + + #pragma pop_macro("abort") + printf("abort = %s\n", abort); + + #pragma pop_macro("abort") + printf("abort = %s\n", abort); +} diff --git a/tinyc/tests/tests2/77_push_pop_macro.expect b/tinyc/tests/tests2/77_push_pop_macro.expect new file mode 100644 index 000000000..d8a55305a --- /dev/null +++ b/tinyc/tests/tests2/77_push_pop_macro.expect @@ -0,0 +1,5 @@ +abort = 111 +abort = 222 +abort = 333 +abort = 222 +abort = 111 diff --git a/tinyc/tests/tests2/78_vla_label.c b/tinyc/tests/tests2/78_vla_label.c new file mode 100644 index 000000000..4096495d9 --- /dev/null +++ b/tinyc/tests/tests2/78_vla_label.c @@ -0,0 +1,45 @@ +#include + +/* This test segfaults as of April 27, 2015. */ +void f1(int argc) +{ + char test[argc]; + if(0) + label: + printf("boom!\n"); + if(argc-- == 0) + return; + goto label; +} + +/* This segfaulted on 2015-11-19. */ +void f2(void) +{ + goto start; + { + int a[1 && 1]; /* not a variable-length array */ + int b[1 || 1]; /* not a variable-length array */ + int c[1 ? 1 : 1]; /* not a variable-length array */ + start: + a[0] = 0; + b[0] = 0; + c[0] = 0; + } +} + +void f3(void) +{ + printf("%d\n", 0 ? printf("x1\n") : 11); + printf("%d\n", 1 ? 12 : printf("x2\n")); + printf("%d\n", 0 && printf("x3\n")); + printf("%d\n", 1 || printf("x4\n")); +} + +int main() +{ + f1(2); + f2(); + f3(); + + return 0; +} diff --git a/tinyc/tests/tests2/78_vla_label.expect b/tinyc/tests/tests2/78_vla_label.expect new file mode 100644 index 000000000..3f4063bec --- /dev/null +++ b/tinyc/tests/tests2/78_vla_label.expect @@ -0,0 +1,6 @@ +boom! +boom! +11 +12 +0 +1 diff --git a/tinyc/tests/tests2/79_vla_continue.c b/tinyc/tests/tests2/79_vla_continue.c new file mode 100644 index 000000000..91215c99e --- /dev/null +++ b/tinyc/tests/tests2/79_vla_continue.c @@ -0,0 +1,116 @@ +#include + +int f(void) +{ + return 5; +} + +void test1() +{ + int count = 10; + void *addr[10]; + for(;count--;) { + int a[f()]; + + addr[count] = a; + + continue; + } + + if(addr[9] == addr[0]) { + printf("OK\n"); + } else { + printf("NOT OK\n"); + } +} + +void test2() +{ + int count = 10; + void *addr[count]; + for(;count--;) { + int a[f()]; + + addr[count] = a; + + continue; + } + + if(addr[9] == addr[0]) { + printf("OK\n"); + } else { + printf("NOT OK\n"); + } +} + +void test3() +{ + int count = 10; + void *addr[count]; + while(count--) { + int a[f()]; + + addr[count] = a; + + continue; + } + + if(addr[9] == addr[0]) { + printf("OK\n"); + } else { + printf("NOT OK\n"); + } +} + +void test4() +{ + int count = 10; + void *addr[count]; + do { + int a[f()]; + + addr[--count] = a; + + continue; + } while (count); + + if(addr[9] == addr[0]) { + printf("OK\n"); + } else { + printf("NOT OK\n"); + } +} + +void test5() +{ + int count = 10; + int a[f()]; + int c[f()]; + + c[0] = 42; + + for(;count--;) { + int b[f()]; + int i; + for (i=0; i +struct wchar { + char *data; char mem[]; +}; +struct wint { + char *data; int mem[]; +}; +int f1char (void) { + char s[9]="nonono"; + struct wchar q = {"bugs"}; + return !s[0]; +} +int f1int (void) { + char s[9]="nonono"; + struct wint q = {"bugs"}; + return !s[0]; +} +int main (void) { + char s[9]="nonono"; + static struct wchar q = {"bugs", {'c'}}; + //printf ("tcc has %s %s\n", s, q.data); + if (f1char() || f1int()) + printf ("bla\n"); + return !s[0]; +} diff --git a/tests/newconfig/bar/config.nims b/tinyc/tests/tests2/80_flexarray.expect similarity index 100% rename from tests/newconfig/bar/config.nims rename to tinyc/tests/tests2/80_flexarray.expect diff --git a/tinyc/tests/tests2/81_types.c b/tinyc/tests/tests2/81_types.c new file mode 100644 index 000000000..fd6d71b0c --- /dev/null +++ b/tinyc/tests/tests2/81_types.c @@ -0,0 +1,43 @@ +/* The following are all valid decls, even though some subtypes + are incomplete. */ +enum E *e; +const enum E *e1; +enum E const *e2; +struct S *s; +const struct S *s1; +struct S const *s2; + +/* Various strangely looking declarators, which are all valid + and have to map to the same numbered typedefs. */ +typedef int (*fptr1)(); +int f1 (int (), int); +typedef int (*fptr2)(int x); +int f2 (int (int x), int); +typedef int (*fptr3)(int); +int f3 (int (int), int); +typedef int (*fptr4[4])(int); +int f4 (int (*[4])(int), int); +typedef int (*fptr5)(fptr1); +int f5 (int (int()), fptr1); +int f1 (fptr1 fp, int i) +{ + return (*fp)(i); +} +int f2 (fptr2 fp, int i) +{ + return (*fp)(i); +} +int f3 (fptr3 fp, int i) +{ + return (*fp)(i); +} +int f4 (fptr4 fp, int i) +{ + return (*fp[i])(i); +} +int f5 (fptr5 fp, fptr1 i) +{ + return fp(i); +} +int f8 (int ([4]), int); +int main () { return 0; } diff --git a/tests/newconfig/bar/mfoo.nim b/tinyc/tests/tests2/81_types.expect similarity index 100% rename from tests/newconfig/bar/mfoo.nim rename to tinyc/tests/tests2/81_types.expect diff --git a/tinyc/tests/tests2/82_attribs_position.c b/tinyc/tests/tests2/82_attribs_position.c new file mode 100644 index 000000000..7c9f98726 --- /dev/null +++ b/tinyc/tests/tests2/82_attribs_position.c @@ -0,0 +1,19 @@ +typedef unsigned short uint16_t; +typedef unsigned char uint8_t; + +typedef union Unaligned16a { + uint16_t u; + uint8_t b[2]; +} __attribute__((packed)) Unaligned16a; + +typedef union __attribute__((packed)) Unaligned16b { + uint16_t u; + uint8_t b[2]; +} Unaligned16b; + +extern void foo (void) __attribute__((stdcall)); +void __attribute__((stdcall)) foo (void) +{ +} + +int main () { return 0; } diff --git a/tests/newconfig/bar/mfoo.nim.cfg b/tinyc/tests/tests2/82_attribs_position.expect similarity index 100% rename from tests/newconfig/bar/mfoo.nim.cfg rename to tinyc/tests/tests2/82_attribs_position.expect diff --git a/tinyc/tests/tests2/83_utf8_in_identifiers.c b/tinyc/tests/tests2/83_utf8_in_identifiers.c new file mode 100644 index 000000000..1f8609525 --- /dev/null +++ b/tinyc/tests/tests2/83_utf8_in_identifiers.c @@ -0,0 +1,9 @@ +#include +double привет=0.1; +int Lefèvre=2; +int main(){ + printf("привет=%g\n",привет); + printf("Lefèvre=%d\n",Lefèvre); + return 0; +} +// pcc & tcc only diff --git a/tinyc/tests/tests2/83_utf8_in_identifiers.expect b/tinyc/tests/tests2/83_utf8_in_identifiers.expect new file mode 100644 index 000000000..1553f5f6f --- /dev/null +++ b/tinyc/tests/tests2/83_utf8_in_identifiers.expect @@ -0,0 +1,2 @@ +привет=0.1 +Lefèvre=2 diff --git a/tinyc/tests/tests2/84_hex-float.c b/tinyc/tests/tests2/84_hex-float.c new file mode 100644 index 000000000..0ef09bfc2 --- /dev/null +++ b/tinyc/tests/tests2/84_hex-float.c @@ -0,0 +1,12 @@ +extern int printf(const char *format, ...); + +#define ACPI_TYPE_INVALID 0x1E +#define NUM_NS_TYPES ACPI_TYPE_INVALID+1 +int array[NUM_NS_TYPES]; + +#define n 0xe +int main() +{ + printf("n+1 = %d\n", n+1); +// printf("n+1 = %d\n", 0xe+1); +} diff --git a/tinyc/tests/tests2/84_hex-float.expect b/tinyc/tests/tests2/84_hex-float.expect new file mode 100644 index 000000000..2175385aa --- /dev/null +++ b/tinyc/tests/tests2/84_hex-float.expect @@ -0,0 +1 @@ +n+1 = 15 diff --git a/tinyc/tests/tests2/85_asm-outside-function.c b/tinyc/tests/tests2/85_asm-outside-function.c new file mode 100644 index 000000000..dc5639a46 --- /dev/null +++ b/tinyc/tests/tests2/85_asm-outside-function.c @@ -0,0 +1,9 @@ +extern int printf (const char *, ...); +extern void vide(void); +__asm__("vide: ret"); + +int main() { + vide(); + printf ("okay\n"); + return 0; +} diff --git a/tinyc/tests/tests2/85_asm-outside-function.expect b/tinyc/tests/tests2/85_asm-outside-function.expect new file mode 100644 index 000000000..dcf02b2fb --- /dev/null +++ b/tinyc/tests/tests2/85_asm-outside-function.expect @@ -0,0 +1 @@ +okay diff --git a/tinyc/tests/tests2/86_memory-model.c b/tinyc/tests/tests2/86_memory-model.c new file mode 100644 index 000000000..744c3e207 --- /dev/null +++ b/tinyc/tests/tests2/86_memory-model.c @@ -0,0 +1,38 @@ +#include + +int +main() +{ +#if defined(__LLP64__) + if (sizeof(short) == 2 + && sizeof(int) == 4 + && sizeof(long int) == 4 + && sizeof(long long int) == 8 + && sizeof(void*) == 8) { + (void)printf("Ok\n"); + } else { + (void)printf("KO __LLP64__\n"); + } +#elif defined(__LP64__) + if (sizeof(short) == 2 + && sizeof(int) == 4 + && sizeof(long int) == 8 + && sizeof(long long int) == 8 + && sizeof(void*) == 8) { + (void)printf("Ok\n"); + } else { + (void)printf("KO __LP64__\n"); + } +#elif defined(__ILP32__) + if (sizeof(short) == 2 + && sizeof(int) == 4 + && sizeof(long int) == 4 + && sizeof(void*) == 4) { + (void)printf("Ok\n"); + } else { + (void)printf("KO __ILP32__\n"); + } +#else + (void)printf("KO no __*LP*__ defined.\n"); +#endif +} diff --git a/tinyc/tests/tests2/86_memory-model.expect b/tinyc/tests/tests2/86_memory-model.expect new file mode 100644 index 000000000..7326d9603 --- /dev/null +++ b/tinyc/tests/tests2/86_memory-model.expect @@ -0,0 +1 @@ +Ok diff --git a/tinyc/tests/tests2/87_dead_code.c b/tinyc/tests/tests2/87_dead_code.c new file mode 100644 index 000000000..98d4566c5 --- /dev/null +++ b/tinyc/tests/tests2/87_dead_code.c @@ -0,0 +1,122 @@ +/* This checks various ways of dead code inside if statements + where there are non-obvious ways of how the code is actually + not dead due to reachable by labels. */ +extern int printf (const char *, ...); +static void kb_wait_1(void) +{ + unsigned long timeout = 2; + do { + /* Here the else arm is a statement expression that's supposed + to be suppressed. The label inside the while would unsuppress + code generation again if not handled correctly. And that + would wreak havoc to the cond-expression because there's no + jump-around emitted, the whole statement expression really + needs to not generate code (perhaps except useless forward jumps). */ + (1 ? + printf("timeout=%ld\n", timeout) : + ({ + int i = 1; + while (1) + while (i--) + some_label: + printf("error\n"); + goto some_label; + }) + ); + timeout--; + } while (timeout); +} +int main (void) +{ + int i = 1; + kb_wait_1(); + + /* Simple test of dead code at first sight which isn't actually dead. */ + if (0) { +yeah: + printf ("yeah\n"); + } else { + printf ("boo\n"); + } + if (i--) + goto yeah; + + /* Some more non-obvious uses where the problems are loops, so that even + the first loop statements aren't actually dead. */ + i = 1; + if (0) { + while (i--) { + printf ("once\n"); +enterloop: + printf ("twice\n"); + } + } + if (i >= 0) + goto enterloop; + + /* The same with statement expressions. One might be tempted to + handle them specially by counting if inside statement exprs and + not unsuppressing code at loops at all then. + See kb_wait_1 for the other side of the medal where that wouldn't work. */ + i = ({ + int j = 1; + if (0) { + while (j--) { + printf ("SEonce\n"); + enterexprloop: + printf ("SEtwice\n"); + } + } + if (j >= 0) + goto enterexprloop; + j; }); + + /* The other two loop forms: */ + i = 1; + if (0) { + for (i = 1; i--;) { + printf ("once2\n"); +enterloop2: + printf ("twice2\n"); + } + } + if (i > 0) + goto enterloop2; + + i = 1; + if (0) { + do { + printf ("once3\n"); +enterloop3: + printf ("twice3\n"); + } while (i--); + } + if (i > 0) + goto enterloop3; + + /* And check that case and default labels have the same effect + of disabling code suppression. */ + i = 41; + switch (i) { + if (0) { + printf ("error\n"); + case 42: + printf ("error2\n"); + case 41: + printf ("caseok\n"); + } + } + + i = 41; + switch (i) { + if (0) { + printf ("error3\n"); + default: + printf ("caseok2\n"); + break; + case 42: + printf ("error4\n"); + } + } + return 0; +} diff --git a/tinyc/tests/tests2/87_dead_code.expect b/tinyc/tests/tests2/87_dead_code.expect new file mode 100644 index 000000000..0b3ec1d9d --- /dev/null +++ b/tinyc/tests/tests2/87_dead_code.expect @@ -0,0 +1,18 @@ +timeout=2 +timeout=1 +boo +yeah +twice +once +twice +SEtwice +SEonce +SEtwice +twice2 +once2 +twice2 +twice3 +once3 +twice3 +caseok +caseok2 diff --git a/tinyc/tests/tests2/88_codeopt.c b/tinyc/tests/tests2/88_codeopt.c new file mode 100644 index 000000000..647626f9e --- /dev/null +++ b/tinyc/tests/tests2/88_codeopt.c @@ -0,0 +1,68 @@ +/* Check some way in where code suppression caused various + miscompilations. */ +extern int printf (const char *, ...); +typedef unsigned long size_t; + +size_t _brk_start, _brk_end; +void * extend_brk(size_t size, size_t align) +{ + size_t mask = align - 1; + void *ret = 0; + + do { + if (__builtin_expect(!!(_brk_start == 0), 0)) + do { + printf("wrong1\n"); + } while (0); + } while (0); + _brk_end = (_brk_end + mask) & ~mask; + ret = (void *)_brk_end; + _brk_end += size; + + return ret; +} + +static void get_args (int a, int b) +{ + if (a != 1) + printf("wrong2\n"); + else + printf("okay\n"); +} + +void bla(void) +{ + int __ret = 42; + ({ + if (__builtin_expect(!!(0), 0)) { + if (__builtin_expect(!!__ret, 0)) + printf("wrong3\n"); + int x = !!(__ret); + } + __ret; + }); + get_args(!!__ret, sizeof(__ret)); +} + +_Bool chk(unsigned long addr, unsigned long limit, unsigned long size) +{ + _Bool ret; + /* This just needs to compile, no runtime test. (And it doesn't compile + only with certain internal checking added that's not committed). */ + if (0) + ret = 0 != (!!(addr > limit - size)); +} + +int main() +{ + void *r; + _brk_start = 1024; + _brk_end = 1024; + r = extend_brk (4096, 16); + if (!r) + printf("wrong4\n"); + else + printf("okay\n"); + bla(); + return 0; +} diff --git a/tinyc/tests/tests2/88_codeopt.expect b/tinyc/tests/tests2/88_codeopt.expect new file mode 100644 index 000000000..439edfd8f --- /dev/null +++ b/tinyc/tests/tests2/88_codeopt.expect @@ -0,0 +1,2 @@ +okay +okay diff --git a/tinyc/tests/tests2/89_nocode_wanted.c b/tinyc/tests/tests2/89_nocode_wanted.c new file mode 100644 index 000000000..73e0a4bc8 --- /dev/null +++ b/tinyc/tests/tests2/89_nocode_wanted.c @@ -0,0 +1,112 @@ +extern int printf(const char *format, ...); +static void kb_wait_1(void) +{ + unsigned long timeout = 2; + do { + (1 ? + printf("timeout=%ld\n", timeout) : + ({ + while (1) + printf("error\n"); + }) + ); + timeout--; + } while (timeout); +} +static void kb_wait_2(void) +{ + unsigned long timeout = 2; + do { + (1 ? + printf("timeout=%ld\n", timeout) : + ({ + for (;;) + printf("error\n"); + }) + ); + timeout--; + } while (timeout); +} +static void kb_wait_2_1(void) +{ + unsigned long timeout = 2; + do { + (1 ? + printf("timeout=%ld\n", timeout) : + ({ + do { + printf("error\n"); + } while (1); + }) + ); + timeout--; + } while (timeout); +} +static void kb_wait_2_2(void) +{ + unsigned long timeout = 2; + do { + (1 ? + printf("timeout=%ld\n", timeout) : + ({ + label: + printf("error\n"); + goto label; + }) + ); + timeout--; + } while (timeout); +} +static void kb_wait_3(void) +{ + unsigned long timeout = 2; + do { + (1 ? + printf("timeout=%ld\n", timeout) : + ({ + int i = 1; + goto label; + i = i + 2; + label: + i = i + 3; + }) + ); + timeout--; + } while (timeout); +} +static void kb_wait_4(void) +{ + unsigned long timeout = 2; + do { + (1 ? + printf("timeout=%ld\n", timeout) : + ({ + switch(timeout) { + case 2: + printf("timeout is 2"); + break; + case 1: + printf("timeout is 1"); + break; + default: + printf("timeout is 0?"); + break; + }; + // return; + }) + ); + timeout--; + } while (timeout); +} +int main() +{ + printf("begin\n"); + kb_wait_1(); + kb_wait_2(); + kb_wait_2_1(); + kb_wait_2_2(); + kb_wait_3(); + kb_wait_4(); + printf("end\n"); + return 0; +} diff --git a/tinyc/tests/tests2/89_nocode_wanted.expect b/tinyc/tests/tests2/89_nocode_wanted.expect new file mode 100644 index 000000000..c44d4ea6c --- /dev/null +++ b/tinyc/tests/tests2/89_nocode_wanted.expect @@ -0,0 +1,14 @@ +begin +timeout=2 +timeout=1 +timeout=2 +timeout=1 +timeout=2 +timeout=1 +timeout=2 +timeout=1 +timeout=2 +timeout=1 +timeout=2 +timeout=1 +end diff --git a/tinyc/tests/tests2/90_struct-init.c b/tinyc/tests/tests2/90_struct-init.c new file mode 100644 index 000000000..d931e2378 --- /dev/null +++ b/tinyc/tests/tests2/90_struct-init.c @@ -0,0 +1,282 @@ +typedef unsigned char u8; +typedef struct {} empty_s; +struct contains_empty { + u8 a; + empty_s empty; + u8 b; +}; +struct contains_empty ce = { { (1) }, (empty_s){}, 022, }; +/* The following decl of 'q' would demonstrate the TCC bug in init_putv when + handling copying compound literals. (Compound literals + aren't acceptable constant initializers in isoc99, but + we accept them like gcc, except for this case) +//char *q = (char *){ "trara" }; */ +struct SS {u8 a[3], b; }; +struct SS sinit16[] = { { 1 }, 2 }; +struct S +{ + u8 a,b; + u8 c[2]; +}; + +struct T +{ + u8 s[16]; + u8 a; +}; + +struct U +{ + u8 a; + struct S s; + u8 b; + struct T t; +}; + +struct V +{ + struct S s; + struct T t; + u8 a; +}; + +struct W +{ + struct V t; + struct S s[]; +}; + +struct S gs = ((struct S){1, 2, 3, 4}); +struct S gs2 = {1, 2, {3, 4}}; +struct T gt = {"hello", 42}; +struct U gu = {3, 5,6,7,8, 4, "huhu", 43}; +struct U gu2 = {3, {5,6,7,8}, 4, {"huhu", 43}}; +/* Optional braces around scalar initializers. Accepted, but with + a warning. */ +struct U gu3 = { {3}, {5,6,7,8,}, 4, {"huhu", 43}}; +/* Many superfluous braces and leaving out one initializer for U.s.c[1] */ +struct U gu4 = { 3, {5,6,7,}, 5, { "bla", {44}} }; +/* Superfluous braces and useless parens around values */ +struct S gs3 = { (1), {(2)}, {(((3))), {4}}}; +/* Superfluous braces, and leaving out braces for V.t, plus cast */ +struct V gv = {{{3},4,{5,6}}, "haha", (u8)45, 46}; +/* Compound literal */ +struct V gv2 = {(struct S){7,8,{9,10}}, {"hihi", 47}, 48}; +/* Parens around compound literal */ +struct V gv3 = {((struct S){7,8,{9,10}}), {"hoho", 49}, 50}; +/* Initialization of a flex array member (warns in GCC) */ +struct W gw = {{1,2,3,4}, {1,2,3,4,5}}; + +union UU { + u8 a; + u8 b; +}; +struct SU { + union UU u; + u8 c; +}; +struct SU gsu = {5,6}; + +/* Unnamed struct/union members aren't ISO C, but it's a widely accepted + extension. See below for further extensions to that under -fms-extension.*/ +union UV { + struct {u8 a,b;}; + struct S s; +}; +union UV guv = {{6,5}}; +union UV guv2 = {{.b = 7, .a = 8}}; +union UV guv3 = {.b = 8, .a = 7}; + +/* Under -fms-extensions also the following is valid: +union UV2 { + struct Anon {u8 a,b;}; // unnamed member, but tagged struct, ... + struct S s; +}; +struct Anon gan = { 10, 11 }; // ... which makes it available here. +union UV2 guv4 = {{4,3}}; // and the other inits from above as well +*/ + +struct in6_addr { + union { + u8 u6_addr8[16]; + unsigned short u6_addr16[8]; + } u; +}; +struct flowi6 { + struct in6_addr saddr, daddr; +}; +struct pkthdr { + struct in6_addr daddr, saddr; +}; +struct pkthdr phdr = { { { 6,5,4,3 } }, { { 9,8,7,6 } } }; + +struct Wrap { + void *func; +}; +int global; +void inc_global (void) +{ + global++; +} + +struct Wrap global_wrap[] = { + ((struct Wrap) {inc_global}), + inc_global, +}; + +#include +void print_ (const char *name, const u8 *p, long size) +{ + printf ("%s:", name); + while (size--) { + printf (" %x", *p++); + } + printf ("\n"); +} +#define print(x) print_(#x, (u8*)&x, sizeof (x)) +#if 1 +void foo (struct W *w, struct pkthdr *phdr_) +{ + struct S ls = {1, 2, 3, 4}; + struct S ls2 = {1, 2, {3, 4}}; + struct T lt = {"hello", 42}; + struct U lu = {3, 5,6,7,8, 4, "huhu", 43}; + struct U lu1 = {3, ls, 4, {"huhu", 43}}; + struct U lu2 = {3, (ls), 4, {"huhu", 43}}; + const struct S *pls = &ls; + struct S ls21 = *pls; + struct U lu22 = {3, *pls, 4, {"huhu", 43}}; + /* Incomplete bracing. */ + struct U lu21 = {3, ls, 4, "huhu", 43}; + /* Optional braces around scalar initializers. Accepted, but with + a warning. */ + struct U lu3 = { 3, {5,6,7,8,}, 4, {"huhu", 43}}; + /* Many superfluous braces and leaving out one initializer for U.s.c[1] */ + struct U lu4 = { 3, {5,6,7,}, 5, { "bla", 44} }; + /* Superfluous braces and useless parens around values */ + struct S ls3 = { (1), (2), {(((3))), 4}}; + /* Superfluous braces, and leaving out braces for V.t, plus cast */ + struct V lv = {{3,4,{5,6}}, "haha", (u8)45, 46}; + /* Compound literal */ + struct V lv2 = {(struct S)w->t.s, {"hihi", 47}, 48}; + /* Parens around compound literal */ + struct V lv3 = {((struct S){7,8,{9,10}}), ((const struct W *)w)->t.t, 50}; + const struct pkthdr *phdr = phdr_; + struct flowi6 flow = { .daddr = phdr->daddr, .saddr = phdr->saddr }; + int elt = 0x42; + /* Range init, overlapping */ + struct T lt2 = { { [1 ... 5] = 9, [6 ... 10] = elt, [4 ... 7] = elt+1 }, 1 }; + print(ls); + print(ls2); + print(lt); + print(lu); + print(lu1); + print(lu2); + print(ls21); + print(lu21); + print(lu22); + print(lu3); + print(lu4); + print(ls3); + print(lv); + print(lv2); + print(lv3); + print(lt2); + print(flow); +} +#endif + +void test_compound_with_relocs (void) +{ + struct Wrap local_wrap[] = { + ((struct Wrap) {inc_global}), + inc_global, + }; + void (*p)(void); + p = global_wrap[0].func; p(); + p = global_wrap[1].func; p(); + p = local_wrap[0].func; p(); + p = local_wrap[1].func; p(); +} + +void sys_ni(void) { printf("ni\n"); } +void sys_one(void) { printf("one\n"); } +void sys_two(void) { printf("two\n"); } +void sys_three(void) { printf("three\n"); } +typedef void (*fptr)(void); +const fptr table[3] = { + [0 ... 2] = &sys_ni, + [0] = sys_one, + [1] = sys_two, + [2] = sys_three, +}; + +void test_multi_relocs(void) +{ + int i; + for (i = 0; i < sizeof(table)/sizeof(table[0]); i++) + table[i](); +} + +/* Following is from GCC gcc.c-torture/execute/20050613-1.c. */ + +struct SEA { int i; int j; int k; int l; }; +struct SEB { struct SEA a; int r[1]; }; +struct SEC { struct SEA a; int r[0]; }; +struct SED { struct SEA a; int r[]; }; + +static void +test_correct_filling (struct SEA *x) +{ + static int i; + if (x->i != 0 || x->j != 5 || x->k != 0 || x->l != 0) + printf("sea_fill%d: wrong\n", i); + else + printf("sea_fill%d: okay\n", i); + i++; +} + +int +test_zero_init (void) +{ + /* The peculiarity here is that only a.j is initialized. That + means that all other members must be zero initialized. TCC + once didn't do that for sub-level designators. */ + struct SEB b = { .a.j = 5 }; + struct SEC c = { .a.j = 5 }; + struct SED d = { .a.j = 5 }; + test_correct_filling (&b.a); + test_correct_filling (&c.a); + test_correct_filling (&d.a); + return 0; +} + +int main() +{ + print(ce); + print(gs); + print(gs2); + print(gt); + print(gu); + print(gu2); + print(gu3); + print(gu4); + print(gs3); + print(gv); + print(gv2); + print(gv3); + print(sinit16); + print(gw); + print(gsu); + print(guv); + print(guv.b); + print(guv2); + print(guv3); + print(phdr); + foo(&gw, &phdr); + //printf("q: %s\n", q); + test_compound_with_relocs(); + test_multi_relocs(); + test_zero_init(); + return 0; +} diff --git a/tinyc/tests/tests2/90_struct-init.expect b/tinyc/tests/tests2/90_struct-init.expect new file mode 100644 index 000000000..e366121a5 --- /dev/null +++ b/tinyc/tests/tests2/90_struct-init.expect @@ -0,0 +1,43 @@ +ce: 1 12 +gs: 1 2 3 4 +gs2: 1 2 3 4 +gt: 68 65 6c 6c 6f 0 0 0 0 0 0 0 0 0 0 0 2a +gu: 3 5 6 7 8 4 68 75 68 75 0 0 0 0 0 0 0 0 0 0 0 0 2b +gu2: 3 5 6 7 8 4 68 75 68 75 0 0 0 0 0 0 0 0 0 0 0 0 2b +gu3: 3 5 6 7 8 4 68 75 68 75 0 0 0 0 0 0 0 0 0 0 0 0 2b +gu4: 3 5 6 7 0 5 62 6c 61 0 0 0 0 0 0 0 0 0 0 0 0 0 2c +gs3: 1 2 3 4 +gv: 3 4 5 6 68 61 68 61 0 0 0 0 0 0 0 0 0 0 0 0 2d 2e +gv2: 7 8 9 a 68 69 68 69 0 0 0 0 0 0 0 0 0 0 0 0 2f 30 +gv3: 7 8 9 a 68 6f 68 6f 0 0 0 0 0 0 0 0 0 0 0 0 31 32 +sinit16: 1 0 0 0 2 0 0 0 +gw: 1 2 3 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +gsu: 5 6 +guv: 6 5 0 0 +guv.b: 5 +guv2: 8 7 0 0 +guv3: 7 8 0 0 +phdr: 6 5 4 3 0 0 0 0 0 0 0 0 0 0 0 0 9 8 7 6 0 0 0 0 0 0 0 0 0 0 0 0 +ls: 1 2 3 4 +ls2: 1 2 3 4 +lt: 68 65 6c 6c 6f 0 0 0 0 0 0 0 0 0 0 0 2a +lu: 3 5 6 7 8 4 68 75 68 75 0 0 0 0 0 0 0 0 0 0 0 0 2b +lu1: 3 1 2 3 4 4 68 75 68 75 0 0 0 0 0 0 0 0 0 0 0 0 2b +lu2: 3 1 2 3 4 4 68 75 68 75 0 0 0 0 0 0 0 0 0 0 0 0 2b +ls21: 1 2 3 4 +lu21: 3 1 2 3 4 4 68 75 68 75 0 0 0 0 0 0 0 0 0 0 0 0 2b +lu22: 3 1 2 3 4 4 68 75 68 75 0 0 0 0 0 0 0 0 0 0 0 0 2b +lu3: 3 5 6 7 8 4 68 75 68 75 0 0 0 0 0 0 0 0 0 0 0 0 2b +lu4: 3 5 6 7 0 5 62 6c 61 0 0 0 0 0 0 0 0 0 0 0 0 0 2c +ls3: 1 2 3 4 +lv: 3 4 5 6 68 61 68 61 0 0 0 0 0 0 0 0 0 0 0 0 2d 2e +lv2: 1 2 3 4 68 69 68 69 0 0 0 0 0 0 0 0 0 0 0 0 2f 30 +lv3: 7 8 9 a 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 32 +lt2: 0 9 9 9 43 43 43 43 42 42 42 0 0 0 0 0 1 +flow: 9 8 7 6 0 0 0 0 0 0 0 0 0 0 0 0 6 5 4 3 0 0 0 0 0 0 0 0 0 0 0 0 +one +two +three +sea_fill0: okay +sea_fill1: okay +sea_fill2: okay diff --git a/tinyc/tests/tests2/91_ptr_longlong_arith32.c b/tinyc/tests/tests2/91_ptr_longlong_arith32.c new file mode 100644 index 000000000..bf07915ab --- /dev/null +++ b/tinyc/tests/tests2/91_ptr_longlong_arith32.c @@ -0,0 +1,15 @@ +int printf(const char *, ...); +char t[] = "012345678"; + +int main(void) +{ + char *data = t; + unsigned long long r = 4; + unsigned a = 5; + unsigned long long b = 12; + + *(unsigned*)(data + r) += a - b; + + printf("data = \"%s\"\n", data); + return 0; +} diff --git a/tinyc/tests/tests2/91_ptr_longlong_arith32.expect b/tinyc/tests/tests2/91_ptr_longlong_arith32.expect new file mode 100644 index 000000000..f91e4b420 --- /dev/null +++ b/tinyc/tests/tests2/91_ptr_longlong_arith32.expect @@ -0,0 +1 @@ +data = "0123-5678" diff --git a/tinyc/tests/tests2/92_enum_bitfield.c b/tinyc/tests/tests2/92_enum_bitfield.c new file mode 100644 index 000000000..bb6dc35d2 --- /dev/null +++ b/tinyc/tests/tests2/92_enum_bitfield.c @@ -0,0 +1,57 @@ +/* This checks if enums needing 8 bit but only having positive + values are correctly zero extended (instead of sign extended) + when stored into/loaded from a 8 bit bit-field of enum type (which + itself is implementation defined, so isn't necessarily supported by all + other compilers). */ +enum tree_code { + SOME_CODE = 148, /* has bit 7 set, and hence all further enum values as well */ + LAST_AND_UNUSED_TREE_CODE +}; +typedef union tree_node *tree; +struct tree_common +{ + union tree_node *chain; + union tree_node *type; + enum tree_code code : 8; + unsigned side_effects_flag : 1; +}; +union tree_node +{ + struct tree_common common; + }; +enum c_tree_code { + C_DUMMY_TREE_CODE = LAST_AND_UNUSED_TREE_CODE, + STMT_EXPR, + LAST_C_TREE_CODE +}; +enum cplus_tree_code { + CP_DUMMY_TREE_CODE = LAST_C_TREE_CODE, + AMBIG_CONV, + LAST_CPLUS_TREE_CODE +}; + +extern int printf(const char *, ...); +int blah(){return 0;} + +int convert_like_real (tree convs) +{ + switch (((enum tree_code) (convs)->common.code)) + { + case AMBIG_CONV: /* This has bit 7 set, which must not be the sign + bit in tree_common.code, i.e. the bitfield must + be somehow marked unsigned. */ + return blah(); + default: + break; + }; + printf("unsigned enum bit-fields broken\n"); +} + +int main() +{ + union tree_node convs; + + convs.common.code = AMBIG_CONV; + convert_like_real (&convs); + return 0; +} diff --git a/tests/newconfig/bar/mfoo.nims b/tinyc/tests/tests2/92_enum_bitfield.expect similarity index 100% rename from tests/newconfig/bar/mfoo.nims rename to tinyc/tests/tests2/92_enum_bitfield.expect diff --git a/tinyc/tests/tests2/93_integer_promotion.c b/tinyc/tests/tests2/93_integer_promotion.c new file mode 100644 index 000000000..a1176fc6b --- /dev/null +++ b/tinyc/tests/tests2/93_integer_promotion.c @@ -0,0 +1,71 @@ +/* integer promotion */ + +int printf(const char*, ...); +#define promote(s) printf(" %ssigned : %s\n", (s) - 100 < 0 ? " " : "un", #s); + +int main (void) +{ + struct { + unsigned ub:3; + unsigned u:32; + unsigned long long ullb:35; + unsigned long long ull:64; + unsigned char c; + } s = { 1, 1, 1 }; + + promote(s.ub); + promote(s.u); + promote(s.ullb); + promote(s.ull); + promote(s.c); + printf("\n"); + + promote((1 ? s.ub : 1)); + promote((1 ? s.u : 1)); + promote((1 ? s.ullb : 1)); + promote((1 ? s.ull : 1)); + promote((1 ? s.c : 1)); + printf("\n"); + + promote(s.ub << 1); + promote(s.u << 1); + promote(s.ullb << 1); + promote(s.ull << 1); + promote(s.c << 1); + printf("\n"); + + promote(+s.ub); + promote(+s.u); + promote(+s.ullb); + promote(+s.ull); + promote(+s.c); + printf("\n"); + + promote(-s.ub); + promote(-s.u); + promote(-s.ullb); + promote(-s.ull); + promote(-s.c); + printf("\n"); + + promote(~s.ub); + promote(~s.u); + promote(~s.ullb); + promote(~s.ull); + promote(~s.c); + printf("\n"); + + promote(!s.ub); + promote(!s.u); + promote(!s.ullb); + promote(!s.ull); + promote(!s.c); + printf("\n"); + + promote(+(unsigned)s.ub); + promote(-(unsigned)s.ub); + promote(~(unsigned)s.ub); + promote(!(unsigned)s.ub); + + return 0; +} diff --git a/tinyc/tests/tests2/93_integer_promotion.expect b/tinyc/tests/tests2/93_integer_promotion.expect new file mode 100644 index 000000000..34b9c145c --- /dev/null +++ b/tinyc/tests/tests2/93_integer_promotion.expect @@ -0,0 +1,46 @@ + signed : s.ub + unsigned : s.u + signed : s.ullb + unsigned : s.ull + signed : s.c + + signed : (1 ? s.ub : 1) + unsigned : (1 ? s.u : 1) + signed : (1 ? s.ullb : 1) + unsigned : (1 ? s.ull : 1) + signed : (1 ? s.c : 1) + + signed : s.ub << 1 + unsigned : s.u << 1 + signed : s.ullb << 1 + unsigned : s.ull << 1 + signed : s.c << 1 + + signed : +s.ub + unsigned : +s.u + signed : +s.ullb + unsigned : +s.ull + signed : +s.c + + signed : -s.ub + unsigned : -s.u + signed : -s.ullb + unsigned : -s.ull + signed : -s.c + + signed : ~s.ub + unsigned : ~s.u + signed : ~s.ullb + unsigned : ~s.ull + signed : ~s.c + + signed : !s.ub + signed : !s.u + signed : !s.ullb + signed : !s.ull + signed : !s.c + + unsigned : +(unsigned)s.ub + unsigned : -(unsigned)s.ub + unsigned : ~(unsigned)s.ub + signed : !(unsigned)s.ub diff --git a/tinyc/tests/tests2/94_generic.c b/tinyc/tests/tests2/94_generic.c new file mode 100644 index 000000000..d7fb5fc3b --- /dev/null +++ b/tinyc/tests/tests2/94_generic.c @@ -0,0 +1,64 @@ +#include + +const int a = 0; + +struct a { + int a; +}; + +struct b { + int a; +}; + +int a_f() +{ + return 20; +} + +int b_f() +{ + return 10; +} + +typedef int int_type1; + +#define gen_sw(a) _Generic(a, const char *: 1, default: 8, int: 123); + +int main() +{ + int i = 0; + signed long int l = 2; + struct b titi; + const int * const ptr; + const char *ti; + int_type1 i2; + + i = _Generic(a, int: a_f, const int: b_f)(); + printf("%d\n", i); + i = _Generic(a, int: a_f() / 2, const int: b_f() / 2); + printf("%d\n", i); + i = _Generic(ptr, int *:1, int * const:2, default:20); + printf("%d\n", i); + i = gen_sw(a); + printf("%d\n", i); + i = _Generic(titi, struct a:1, struct b:2, default:20); + printf("%d\n", i); + i = _Generic(i2, char: 1, int : 0); + printf("%d\n", i); + i = _Generic(a, char:1, int[4]:2, default:5); + printf("%d\n", i); + i = _Generic(17, int :1, int **:2); + printf("%d\n", i); + i = _Generic(17L, int :1, long :2, long long : 3); + printf("%d\n", i); + i = _Generic("17, io", char *: 3, const char *: 1); + printf("%d\n", i); + i = _Generic(ti, const unsigned char *:1, const char *:4, char *:3, + const signed char *:2); + printf("%d\n", i); + printf("%s\n", _Generic(i + 2L, long: "long", int: "int", + long long: "long long")); + i = _Generic(l, long: 1, int: 2); + printf("%d\n", i); + return 0; +} diff --git a/tinyc/tests/tests2/94_generic.expect b/tinyc/tests/tests2/94_generic.expect new file mode 100644 index 000000000..9aa927530 --- /dev/null +++ b/tinyc/tests/tests2/94_generic.expect @@ -0,0 +1,13 @@ +20 +10 +20 +123 +2 +0 +5 +1 +2 +3 +4 +long +1 \ No newline at end of file diff --git a/tinyc/tests/tests2/95_bitfields.c b/tinyc/tests/tests2/95_bitfields.c new file mode 100644 index 000000000..f025c575d --- /dev/null +++ b/tinyc/tests/tests2/95_bitfields.c @@ -0,0 +1,218 @@ +/* ----------------------------------------------------------------------- */ +#if TEST == 1 +{ + struct M P A __s + { + unsigned x : 12; + unsigned char y : 7; + unsigned z : 28; + unsigned a: 4; + unsigned b: 5; + }; + TEST_STRUCT(0x333,0x44,0x555555,6,7); +} + +/* ----------------------------------------------------------------------- */ +#elif TEST == 2 +{ + struct M P __s + { + int x: 12; + char y: 6; + long long z:63; + A char a:4; + long long b:2; + + }; + TEST_STRUCT(3,30,0x123456789abcdef0LL,5,2); +} + +/* ----------------------------------------------------------------------- */ +#elif TEST == 3 +{ + struct M P __s + { + unsigned x:5, y:5, :0, z:5; char a:5; A short b:5; + }; + TEST_STRUCT(21,23,25,6,14); +} + +/* ----------------------------------------------------------------------- */ +#elif TEST == 4 +{ + struct M P __s { + int x : 3; + int : 2; + int y : 1; + int : 0; + int z : 5; + int a : 7; + unsigned int b : 7; + }; + TEST_STRUCT(3,1,15,120,120); +} + +/* ----------------------------------------------------------------------- */ +#elif TEST == 5 +{ + struct M P __s { + long long x : 45; + long long : 2; + long long y : 30; + unsigned long long z : 38; + char a; short b; + }; + TEST_STRUCT(0x123456789ULL, 120<<25, 120, 0x44, 0x77); +} + +/* ----------------------------------------------------------------------- */ +#elif TEST == 6 +{ + struct M P __s { + int a; + signed char b; + int x : 12, y : 4, : 0, : 4, z : 3; + char d; + }; + TEST_STRUCT(1,2,3,4,-3); +} + +/* ----------------------------------------------------------------------- */ +#elif defined PACK + +#if PACK +# pragma pack(push,1) +# define P //_P +#else +# define P +#endif + +printf("\n\n" + 2*top); +#define TEST 1 +#include SELF +top = 0; +#define TEST 2 +#include SELF +#define TEST 3 +#include SELF +#define TEST 4 +#include SELF +#define TEST 5 +#include SELF +#define TEST 6 +#include SELF + +#if PACK +# pragma pack(pop) +#endif + +#undef P +#undef PACK + +/* ----------------------------------------------------------------------- */ +#elif defined ALIGN + +#if ALIGN +# define A _A(16) +#else +# define A +#endif + +#define PACK 0 +#include SELF +#define PACK 1 +#include SELF + +#undef A +#undef ALIGN + +/* ----------------------------------------------------------------------- */ +#elif defined MS_BF + +#if MS_BF +# ifdef __TINYC__ +# pragma comment(option, "-mms-bitfields") +# elif defined __GNUC__ +# define M __attribute__((ms_struct)) +# endif +#else +# ifdef __TINYC__ +# pragma comment(option, "-mno-ms-bitfields") +# elif defined __GNUC__ +# define M __attribute__((gcc_struct)) +# endif +#endif +#ifndef M +# define M +#endif + +#define ALIGN 0 +#include SELF +#define ALIGN 1 +#include SELF + +#undef M +#undef MS_BF + +/* ----------------------------------------------------------------------- */ +#else + +#include +#include +/* some gcc headers #define __attribute__ to empty if it's not gcc */ +#undef __attribute__ + +void dump(void *p, int s) +{ + int i; + for (i = s; --i >= 0;) + printf("%02X", ((unsigned char*)p)[i]); + printf("\n"); +} + +#define pv(m) \ + printf(sizeof (s->m + 0) == 8 ? " %016llx" : " %02x", s->m) + +#define TEST_STRUCT(v1,v2,v3,v4,v5) { \ + struct __s _s, *s = & _s; \ + printf("\n---- TEST %d%s%s%s ----\n" + top, \ + TEST, MS_BF?" - MS-BITFIELDS":"", \ + PACK?" - PACKED":"", \ + ALIGN?" - WITH ALIGN":""); \ + memset(s, 0, sizeof *s); \ + s->x = -1, s->y = -1, s->z = -1, s->a = -1, s->b = -1; \ + printf("bits in use : "), dump(s, sizeof *s); \ + s->x = v1, s->y = v2, s->z = v3, s->a += v4, ++s->a, s->b = v5; \ + printf("bits as set : "), dump(s, sizeof *s); \ + printf("values :"), pv(x), pv(y), pv(z), pv(a), pv(b), printf("\n"); \ + printf("align/size : %d %d\n", alignof(struct __s),sizeof(struct __s)); \ + } + +#ifdef _MSC_VER +# define _A(n) __declspec(align(n)) +# define _P +# define alignof(x) __alignof(x) +#else +# define _A(n) __attribute__((aligned(n))) +# define _P __attribute__((packed)) +# define alignof(x) __alignof__(x) +#endif + +#ifndef MS_BITFIELDS +# define MS_BITFIELDS 0 +#endif + +#define SELF "95_bitfields.c" + +int top = 1; + +int main() +{ +#define MS_BF MS_BITFIELDS +#include SELF + return 0; +} + +/* ----------------------------------------------------------------------- */ +#endif +#undef TEST diff --git a/tinyc/tests/tests2/95_bitfields.expect b/tinyc/tests/tests2/95_bitfields.expect new file mode 100644 index 000000000..6a8fd9abd --- /dev/null +++ b/tinyc/tests/tests2/95_bitfields.expect @@ -0,0 +1,149 @@ +---- TEST 1 ---- +bits in use : 0000001FFFFFFFFF007F0FFF +bits as set : 000000076055555500440333 +values : 333 44 555555 06 07 +align/size : 4 12 + +---- TEST 2 ---- +bits in use : 000000000000003F7FFFFFFFFFFFFFFF00000000003F0FFF +bits as set : 0000000000000025123456789ABCDEF000000000001E0003 +values : 03 1e 123456789abcdef0 05 fffffffe +align/size : 8 24 + +---- TEST 3 ---- +bits in use : 001F1F1F000003FF +bits as set : 000E0619000002F5 +values : 15 17 19 06 0e +align/size : 4 8 + +---- TEST 4 ---- +bits in use : 0007FFFF00000027 +bits as set : 00078F0F00000023 +values : 03 ffffffff 0f fffffff8 78 +align/size : 4 8 + +---- TEST 5 ---- +bits in use : FFFFFF3FFFFFFFFF000000003FFFFFFF00001FFFFFFFFFFF +bits as set : 007744000000007800000000300000000000000123456789 +values : 0000000123456789 f0000000 0000000000000078 44 77 +align/size : 8 24 + +---- TEST 6 ---- +bits in use : 0000007000FFFFFFFFFFFFFF +bits as set : 00000030002001FD00000004 +values : 01 02 03 04 fffffffd +align/size : 4 12 + + + +---- TEST 1 - PACKED ---- +bits in use : FFFFFFFFFFFFFF +bits as set : 3B02AAAAAC4333 +values : 333 44 555555 06 07 +align/size : 1 7 + +---- TEST 2 - PACKED ---- +bits in use : 7FFFFFFFFFFFFFFFFFFFFF +bits as set : 4A48D159E26AF37BC1E003 +values : 03 1e 123456789abcdef0 05 fffffffe +align/size : 1 11 + +---- TEST 3 - PACKED ---- +bits in use : 7FFF000003FF +bits as set : 38D9000002F5 +values : 15 17 19 06 0e +align/size : 1 6 + +---- TEST 4 - PACKED ---- +bits in use : 07FFFF00000027 +bits as set : 078F0F00000023 +values : 03 ffffffff 0f fffffff8 78 +align/size : 1 7 + +---- TEST 5 - PACKED ---- +bits in use : FFFFFF07FFFFFFFFFFFFFFFF9FFFFFFFFFFF +bits as set : 007744000000000F18000000000123456789 +values : 0000000123456789 f0000000 0000000000000078 44 77 +align/size : 1 18 + +---- TEST 6 - PACKED ---- +bits in use : 007000FFFFFFFFFFFFFF +bits as set : 0030002001FD00000004 +values : 01 02 03 04 fffffffd +align/size : 1 10 + + + +---- TEST 1 - WITH ALIGN ---- +bits in use : 000000000000001FFFFFFFFF007F0FFF +bits as set : 00000000000000076055555500440333 +values : 333 44 555555 06 07 +align/size : 16 16 + +---- TEST 2 - WITH ALIGN ---- +bits in use : 0000000000000000000000000000003F7FFFFFFFFFFFFFFF00000000003F0FFF +bits as set : 00000000000000000000000000000025123456789ABCDEF000000000001E0003 +values : 03 1e 123456789abcdef0 05 fffffffe +align/size : 16 32 + +---- TEST 3 - WITH ALIGN ---- +bits in use : 0000000000000000000000000000001F000000000000000000001F1F000003FF +bits as set : 0000000000000000000000000000000E000000000000000000000619000002F5 +values : 15 17 19 06 0e +align/size : 16 32 + +---- TEST 4 - WITH ALIGN ---- +bits in use : 0007FFFF00000027 +bits as set : 00078F0F00000023 +values : 03 ffffffff 0f fffffff8 78 +align/size : 4 8 + +---- TEST 5 - WITH ALIGN ---- +bits in use : FFFFFF3FFFFFFFFF000000003FFFFFFF00001FFFFFFFFFFF +bits as set : 007744000000007800000000300000000000000123456789 +values : 0000000123456789 f0000000 0000000000000078 44 77 +align/size : 8 24 + +---- TEST 6 - WITH ALIGN ---- +bits in use : 0000007000FFFFFFFFFFFFFF +bits as set : 00000030002001FD00000004 +values : 01 02 03 04 fffffffd +align/size : 4 12 + + + +---- TEST 1 - PACKED - WITH ALIGN ---- +bits in use : 000000000000000000FFFFFFFFFFFFFF +bits as set : 0000000000000000003B02AAAAAC4333 +values : 333 44 555555 06 07 +align/size : 16 16 + +---- TEST 2 - PACKED - WITH ALIGN ---- +bits in use : 3F01FFFFFFFFFFFFFFFFFFFF +bits as set : 250048D159E26AF37BC1E003 +values : 03 1e 123456789abcdef0 05 fffffffe +align/size : 1 12 + +---- TEST 3 - PACKED - WITH ALIGN ---- +bits in use : 1F03FF000003FF +bits as set : 0E00D9000002F5 +values : 15 17 19 06 0e +align/size : 1 7 + +---- TEST 4 - PACKED - WITH ALIGN ---- +bits in use : 07FFFF00000027 +bits as set : 078F0F00000023 +values : 03 ffffffff 0f fffffff8 78 +align/size : 1 7 + +---- TEST 5 - PACKED - WITH ALIGN ---- +bits in use : FFFFFF07FFFFFFFFFFFFFFFF9FFFFFFFFFFF +bits as set : 007744000000000F18000000000123456789 +values : 0000000123456789 f0000000 0000000000000078 44 77 +align/size : 1 18 + +---- TEST 6 - PACKED - WITH ALIGN ---- +bits in use : 007000FFFFFFFFFFFFFF +bits as set : 0030002001FD00000004 +values : 01 02 03 04 fffffffd +align/size : 1 10 diff --git a/tinyc/tests/tests2/95_bitfields_ms.c b/tinyc/tests/tests2/95_bitfields_ms.c new file mode 100644 index 000000000..b196fbd66 --- /dev/null +++ b/tinyc/tests/tests2/95_bitfields_ms.c @@ -0,0 +1,2 @@ +#define MS_BITFIELDS 1 +#include "95_bitfields.c" diff --git a/tinyc/tests/tests2/95_bitfields_ms.expect b/tinyc/tests/tests2/95_bitfields_ms.expect new file mode 100644 index 000000000..8ccafb78d --- /dev/null +++ b/tinyc/tests/tests2/95_bitfields_ms.expect @@ -0,0 +1,149 @@ +---- TEST 1 - MS-BITFIELDS ---- +bits in use : 0000001FFFFFFFFF0000007F00000FFF +bits as set : 00000007605555550000004400000333 +values : 333 44 555555 06 07 +align/size : 4 16 + +---- TEST 2 - MS-BITFIELDS ---- +bits in use : 0000000000000003000000000000000F7FFFFFFFFFFFFFFF0000003F00000FFF +bits as set : 00000000000000020000000000000005123456789ABCDEF00000001E00000003 +values : 03 1e 123456789abcdef0 05 fffffffffffffffe +align/size : 8 32 + +---- TEST 3 - MS-BITFIELDS ---- +bits in use : 001F001F0000001F000003FF +bits as set : 000E000600000019000002F5 +values : 15 17 19 06 0e +align/size : 4 12 + +---- TEST 4 - MS-BITFIELDS ---- +bits in use : 0007FFFF00000027 +bits as set : 00078F0F00000023 +values : 03 ffffffff 0f fffffff8 78 +align/size : 4 8 + +---- TEST 5 - MS-BITFIELDS ---- +bits in use : 00000000FFFF00FF0000003FFFFFFFFF000000003FFFFFFF00001FFFFFFFFFFF +bits as set : 0000000000770044000000000000007800000000300000000000000123456789 +values : 0000000123456789 fffffffff0000000 0000000000000078 44 77 +align/size : 8 32 + +---- TEST 6 - MS-BITFIELDS ---- +bits in use : 00000000000000700000FFFF000000FFFFFFFFFF +bits as set : 000000000000003000002001000000FD00000004 +values : 01 02 03 04 fffffffd +align/size : 4 20 + + + +---- TEST 1 - MS-BITFIELDS - PACKED ---- +bits in use : 0000001FFFFFFFFF7F00000FFF +bits as set : 00000007605555554400000333 +values : 333 44 555555 06 07 +align/size : 1 13 + +---- TEST 2 - MS-BITFIELDS - PACKED ---- +bits in use : 00000000000000030F7FFFFFFFFFFFFFFF3F00000FFF +bits as set : 000000000000000205123456789ABCDEF01E00000003 +values : 03 1e 123456789abcdef0 05 fffffffffffffffe +align/size : 1 22 + +---- TEST 3 - MS-BITFIELDS - PACKED ---- +bits in use : 001F1F0000001F000003FF +bits as set : 000E0600000019000002F5 +values : 15 17 19 06 0e +align/size : 1 11 + +---- TEST 4 - MS-BITFIELDS - PACKED ---- +bits in use : 0007FFFF00000027 +bits as set : 00078F0F00000023 +values : 03 ffffffff 0f fffffff8 78 +align/size : 1 8 + +---- TEST 5 - MS-BITFIELDS - PACKED ---- +bits in use : FFFFFF0000003FFFFFFFFF000000003FFFFFFF00001FFFFFFFFFFF +bits as set : 007744000000000000007800000000300000000000000123456789 +values : 0000000123456789 fffffffff0000000 0000000000000078 44 77 +align/size : 1 27 + +---- TEST 6 - MS-BITFIELDS - PACKED ---- +bits in use : 00000000700000FFFFFFFFFFFFFF +bits as set : 000000003000002001FD00000004 +values : 01 02 03 04 fffffffd +align/size : 1 14 + + + +---- TEST 1 - MS-BITFIELDS - WITH ALIGN ---- +bits in use : 0000001FFFFFFFFF0000007F00000FFF +bits as set : 00000007605555550000004400000333 +values : 333 44 555555 06 07 +align/size : 16 16 + +---- TEST 2 - MS-BITFIELDS - WITH ALIGN ---- +bits in use : 0000000000000003000000000000000F7FFFFFFFFFFFFFFF0000003F00000FFF +bits as set : 00000000000000020000000000000005123456789ABCDEF00000001E00000003 +values : 03 1e 123456789abcdef0 05 fffffffffffffffe +align/size : 16 32 + +---- TEST 3 - MS-BITFIELDS - WITH ALIGN ---- +bits in use : 0000000000000000000000000000001F000000000000001F0000001F000003FF +bits as set : 0000000000000000000000000000000E000000000000000600000019000002F5 +values : 15 17 19 06 0e +align/size : 16 32 + +---- TEST 4 - MS-BITFIELDS - WITH ALIGN ---- +bits in use : 0007FFFF00000027 +bits as set : 00078F0F00000023 +values : 03 ffffffff 0f fffffff8 78 +align/size : 4 8 + +---- TEST 5 - MS-BITFIELDS - WITH ALIGN ---- +bits in use : 00000000FFFF00FF0000003FFFFFFFFF000000003FFFFFFF00001FFFFFFFFFFF +bits as set : 0000000000770044000000000000007800000000300000000000000123456789 +values : 0000000123456789 fffffffff0000000 0000000000000078 44 77 +align/size : 8 32 + +---- TEST 6 - MS-BITFIELDS - WITH ALIGN ---- +bits in use : 00000000000000700000FFFF000000FFFFFFFFFF +bits as set : 000000000000003000002001000000FD00000004 +values : 01 02 03 04 fffffffd +align/size : 4 20 + + + +---- TEST 1 - MS-BITFIELDS - PACKED - WITH ALIGN ---- +bits in use : 0000000000001FFFFFFFFF7F00000FFF +bits as set : 00000000000007605555554400000333 +values : 333 44 555555 06 07 +align/size : 16 16 + +---- TEST 2 - MS-BITFIELDS - PACKED - WITH ALIGN ---- +bits in use : 00000000000000030F0000007FFFFFFFFFFFFFFF3F00000FFF +bits as set : 000000000000000205000000123456789ABCDEF01E00000003 +values : 03 1e 123456789abcdef0 05 fffffffffffffffe +align/size : 16 25 + +---- TEST 3 - MS-BITFIELDS - PACKED - WITH ALIGN ---- +bits in use : 001F000000000000001F0000001F000003FF +bits as set : 000E000000000000000600000019000002F5 +values : 15 17 19 06 0e +align/size : 16 18 + +---- TEST 4 - MS-BITFIELDS - PACKED - WITH ALIGN ---- +bits in use : 0007FFFF00000027 +bits as set : 00078F0F00000023 +values : 03 ffffffff 0f fffffff8 78 +align/size : 1 8 + +---- TEST 5 - MS-BITFIELDS - PACKED - WITH ALIGN ---- +bits in use : FFFFFF0000003FFFFFFFFF000000003FFFFFFF00001FFFFFFFFFFF +bits as set : 007744000000000000007800000000300000000000000123456789 +values : 0000000123456789 fffffffff0000000 0000000000000078 44 77 +align/size : 1 27 + +---- TEST 6 - MS-BITFIELDS - PACKED - WITH ALIGN ---- +bits in use : 00000000700000FFFFFFFFFFFFFF +bits as set : 000000003000002001FD00000004 +values : 01 02 03 04 fffffffd +align/size : 1 14 diff --git a/tinyc/tests/tests2/96_nodata_wanted.c b/tinyc/tests/tests2/96_nodata_wanted.c new file mode 100644 index 000000000..cc211d36b --- /dev/null +++ b/tinyc/tests/tests2/96_nodata_wanted.c @@ -0,0 +1,84 @@ +/*****************************************************************************/ +/* test 'nodata_wanted' data output suppression */ + +#if defined test_static_data_error +void foo() { + if (1) { + static short w = (int)&foo; /* initializer not computable */ + } +} + +#elif defined test_static_nodata_error +void foo() { + if (0) { + static short w = (int)&foo; /* initializer not computable */ + } +} + +#elif defined test_global_data_error +void foo(); +static short w = (int)&foo; /* initializer not computable */ + + +#elif defined test_local_data_noerror +void foo() { + short w = &foo; /* 2 cast warnings */ +} + +#elif defined test_data_suppression_off || defined test_data_suppression_on + +#if defined test_data_suppression_on +# define SKIP 1 +#else +# define SKIP 0 +#endif + +#include +/* some gcc headers #define __attribute__ to empty if it's not gcc */ +#undef __attribute__ + +int main() +{ + __label__ ts0, te0, ts1, te1; + int tl, dl; + + static char ds0 = 0; + static char de0 = 0; + /* get reference size of empty jmp */ +ts0:; + if (!SKIP) {} +te0:; + dl = -(&de0 - &ds0); + tl = -(&&te0 - &&ts0); + + /* test data and code suppression */ + static char ds1 = 0; +ts1:; + if (!SKIP) { + static void *p = (void*)&main; + static char cc[] = "static string"; + static double d = 8.0; + + static struct __attribute__((packed)) { + unsigned x : 12; + unsigned char y : 7; + unsigned z : 28, a: 4, b: 5; + } s = { 0x333,0x44,0x555555,6,7 }; + + printf("data:\n"); + printf(" %d - %.1f - %.1f - %s - %s\n", + sizeof 8.0, 8.0, d, __FUNCTION__, cc); + printf(" %x %x %x %x %x\n", + s.x, s.y, s.z, s.a, s.b); + } +te1:; + static char de1 = 0; + + dl += &de1 - &ds1; + tl += &&te1 - &&ts1; + printf("size of data/text:\n %s/%s\n", + dl ? "non-zero":"zero", tl ? "non-zero":"zero"); + /*printf("# %d/%d\n", dl, tl);*/ +} + +#endif diff --git a/tinyc/tests/tests2/96_nodata_wanted.expect b/tinyc/tests/tests2/96_nodata_wanted.expect new file mode 100644 index 000000000..2749109a0 --- /dev/null +++ b/tinyc/tests/tests2/96_nodata_wanted.expect @@ -0,0 +1,23 @@ +[test_static_data_error] +96_nodata_wanted.c:7: error: initializer element is not computable at load time + +[test_static_nodata_error] +96_nodata_wanted.c:14: error: initializer element is not computable at load time + +[test_global_data_error] +96_nodata_wanted.c:20: error: initializer element is not computable at load time + +[test_local_data_noerror] +96_nodata_wanted.c:25: warning: assignment makes integer from pointer without a cast +96_nodata_wanted.c:25: warning: nonportable conversion from pointer to char/short + +[test_data_suppression_off] +data: + 8 - 8.0 - 8.0 - main - static string + 333 44 555555 6 7 +size of data/text: + non-zero/non-zero + +[test_data_suppression_on] +size of data/text: + zero/zero diff --git a/tinyc/tests/tests2/97_utf8_string_literal.c b/tinyc/tests/tests2/97_utf8_string_literal.c new file mode 100644 index 000000000..96fbab0d1 --- /dev/null +++ b/tinyc/tests/tests2/97_utf8_string_literal.c @@ -0,0 +1,12 @@ +// this file contains BMP chars encoded in UTF-8 +#include +#include + +int main() +{ + wchar_t s[] = L"hello$$你好¢¢世界€€world"; + wchar_t *p; + for (p = s; *p; p++) printf("%04X ", (unsigned) *p); + printf("\n"); + return 0; +} diff --git a/tinyc/tests/tests2/97_utf8_string_literal.expect b/tinyc/tests/tests2/97_utf8_string_literal.expect new file mode 100644 index 000000000..9a1593cdd --- /dev/null +++ b/tinyc/tests/tests2/97_utf8_string_literal.expect @@ -0,0 +1 @@ +0068 0065 006C 006C 006F 0024 0024 4F60 597D 00A2 00A2 4E16 754C 20AC 20AC 0077 006F 0072 006C 0064 diff --git a/tinyc/tests/tests2/98_al_ax_extend.c b/tinyc/tests/tests2/98_al_ax_extend.c new file mode 100644 index 000000000..9b4e02fe7 --- /dev/null +++ b/tinyc/tests/tests2/98_al_ax_extend.c @@ -0,0 +1,41 @@ +#include +#include +asm ( + ".text;" + ".globl _us;.globl _ss;.globl _uc;.globl _sc;" + "_us:;_ss:;_uc:;_sc:;" + "movl $0x1234ABCD, %eax;" + "ret;" +); + +#if 1 +#define us _us +#define ss _ss +#define uc _uc +#define sc _sc +#endif + +int main() +{ + unsigned short us(void); + short ss(void); + unsigned char uc(void); + signed char sc(void); + + unsigned short (*fpus)(void) = us; + short (*fpss)(void) = ss; + unsigned char (*fpuc)(void) = uc; + signed char (*fpsc)(void) = sc; + + printf("%08X %08X\n", us() + 1, fpus() + 1); + printf("%08X %08X\n", ss() + 1, fpss() + 1); + printf("%08X %08X\n", uc() + 1, fpuc() + 1); + printf("%08X %08X\n", sc() + 1, fpsc() + 1); + printf("\n"); + printf("%08X %08X\n", fpus() + 1, us() + 1); + printf("%08X %08X\n", fpss() + 1, ss() + 1); + printf("%08X %08X\n", fpuc() + 1, uc() + 1); + printf("%08X %08X\n", fpsc() + 1, sc() + 1); + + return 0; +} diff --git a/tinyc/tests/tests2/98_al_ax_extend.expect b/tinyc/tests/tests2/98_al_ax_extend.expect new file mode 100644 index 000000000..c5752e843 --- /dev/null +++ b/tinyc/tests/tests2/98_al_ax_extend.expect @@ -0,0 +1,9 @@ +0000ABCE 0000ABCE +FFFFABCE FFFFABCE +000000CE 000000CE +FFFFFFCE FFFFFFCE + +0000ABCE 0000ABCE +FFFFABCE FFFFABCE +000000CE 000000CE +FFFFFFCE FFFFFFCE diff --git a/tinyc/tests/tests2/99_fastcall.c b/tinyc/tests/tests2/99_fastcall.c new file mode 100644 index 000000000..ee4b67d20 --- /dev/null +++ b/tinyc/tests/tests2/99_fastcall.c @@ -0,0 +1,276 @@ +#include +#include + +#ifndef _WIN32 +#define __fastcall __attribute((fastcall)) +#endif + +#if 1 +#define SYMBOL(x) _##x +#else +#define SYMBOL(x) x +#endif + +///////////////////////////////////////////////////////////////////////// +////////// TRAP FRAMEWORK +///////////////////////////////////////////////////////////////////////// +// if you cast 'TRAP' to a function pointer and call it, +// it will save all 8 registers, +// and jump into C-code (previously set using 'SET_TRAP_HANDLER(x)'), +// in C-code you can pop DWORDs from stack and modify registers +// + +void *SYMBOL(trap_handler); + +extern unsigned char SYMBOL(trap)[]; +asm ( + ".text;" + "_trap:;" + "pushl %esp;" + "pusha;" + "addl $0x4, 0xc(%esp);" + "pushl %esp;" + "call *_trap_handler;" + "addl $0x4, %esp;" + "movl 0xc(%esp), %eax;" + "movl %eax, 0x20(%esp);" + "popa;" + "popl %esp;" + "ret;" +); + +struct trapframe { + unsigned edi, esi, ebp, esp, ebx, edx, ecx, eax; +}; + + +#define M_FLOAT(addr) (*(float *)(addr)) +#define M_DWORD(addr) (*(unsigned *)(addr)) +#define M_WORD(addr) (*(unsigned short *)(addr)) +#define M_BYTE(addr) (*(unsigned char *)(addr)) +#define R_EAX ((tf)->eax) +#define R_ECX ((tf)->ecx) +#define R_EDX ((tf)->edx) +#define R_EBX ((tf)->ebx) +#define R_ESP ((tf)->esp) +#define R_EBP ((tf)->ebp) +#define R_ESI ((tf)->esi) +#define R_EDI ((tf)->edi) + +#define ARG(x) (M_DWORD(R_ESP + (x) * 4)) + +#define RETN(x) do { \ + M_DWORD(R_ESP + (x)) = M_DWORD(R_ESP); \ + R_ESP += (x); \ +} while (0) + +#define DUMP() do { \ + unsigned i; \ + printf("EAX: %08X\n", R_EAX); \ + printf("ECX: %08X\n", R_ECX); \ + printf("EDX: %08X\n", R_EDX); \ + printf("EBX: %08X\n", R_EBX); \ + printf("ESP: %08X\n", R_ESP); \ + printf("EBP: %08X\n", R_EBP); \ + printf("ESI: %08X\n", R_ESI); \ + printf("EDI: %08X\n", R_EDI); \ + printf("\n"); \ + printf("[RETADDR]: %08X\n", M_DWORD(R_ESP)); \ + for (i = 1; i <= 8; i++) { \ + printf("[ARG%4d]: %08X\n", i, ARG(i)); \ + } \ +} while (0) + +#define SET_TRAP_HANDLER(x) ((SYMBOL(trap_handler)) = (x)) +#define TRAP ((void *) &SYMBOL(trap)) + + + +///////////////////////////////////////////////////////////////////////// +////////// SAFECALL FRAMEWORK +///////////////////////////////////////////////////////////////////////// +// this framework will convert any calling convention to cdecl +// usage: first set call target with 'SET_SAFECALL_TARGET(x)' +// then cast 'SAFECALL' to target function pointer type and invoke it +// after calling, 'ESPDIFF' is the difference of old and new esp + +void *SYMBOL(sc_call_target); +unsigned SYMBOL(sc_retn_addr); +unsigned SYMBOL(sc_old_esp); +unsigned SYMBOL(sc_new_esp); + +extern unsigned char SYMBOL(safecall)[]; +asm ( + ".text;" + "_safecall:;" + "popl _sc_retn_addr;" + "movl %esp, _sc_old_esp;" + "call *_sc_call_target;" + "movl %esp, _sc_new_esp;" + "movl _sc_old_esp, %esp;" + "jmp *_sc_retn_addr;" +); + +#define SET_SAFECALL_TARGET(x) ((SYMBOL(sc_call_target)) = (x)) +#define SAFECALL ((void *) &SYMBOL(safecall)) +#define ESPDIFF (SYMBOL(sc_new_esp) - SYMBOL(sc_old_esp)) + + +///////////////////////////////////////////////////////////////////////// +////////// TEST FASTCALL INVOKE +///////////////////////////////////////////////////////////////////////// + +void check_fastcall_invoke_0(struct trapframe *tf) +{ + //DUMP(); + RETN(0); +} + +void check_fastcall_invoke_1(struct trapframe *tf) +{ + //DUMP(); + assert(R_ECX == 0x11111111); + RETN(0); +} +void check_fastcall_invoke_2(struct trapframe *tf) +{ + //DUMP(); + assert(R_ECX == 0x11111111); + assert(R_EDX == 0x22222222); + RETN(0); +} +void check_fastcall_invoke_3(struct trapframe *tf) +{ + //DUMP(); + assert(R_ECX == 0x11111111); + assert(R_EDX == 0x22222222); + assert(ARG(1) == 0x33333333); + RETN(1*4); +} +void check_fastcall_invoke_4(struct trapframe *tf) +{ + //DUMP(); + assert(R_ECX == 0x11111111); + assert(R_EDX == 0x22222222); + assert(ARG(1) == 0x33333333); + assert(ARG(2) == 0x44444444); + RETN(2*4); +} + +void check_fastcall_invoke_5(struct trapframe *tf) +{ + //DUMP(); + assert(R_ECX == 0x11111111); + assert(R_EDX == 0x22222222); + assert(ARG(1) == 0x33333333); + assert(ARG(2) == 0x44444444); + assert(ARG(3) == 0x55555555); + RETN(3*4); +} + +void test_fastcall_invoke() +{ + SET_TRAP_HANDLER(check_fastcall_invoke_0); + ((void __fastcall (*)(void)) TRAP)(); + + SET_TRAP_HANDLER(check_fastcall_invoke_1); + ((void __fastcall (*)(unsigned)) TRAP)(0x11111111); + + SET_TRAP_HANDLER(check_fastcall_invoke_2); + ((void __fastcall (*)(unsigned, unsigned)) TRAP)(0x11111111, 0x22222222); + + SET_TRAP_HANDLER(check_fastcall_invoke_3); + ((void __fastcall (*)(unsigned, unsigned, unsigned)) TRAP)(0x11111111, 0x22222222, 0x33333333); + + SET_TRAP_HANDLER(check_fastcall_invoke_4); + ((void __fastcall (*)(unsigned, unsigned, unsigned, unsigned)) TRAP)(0x11111111, 0x22222222, 0x33333333, 0x44444444); + + SET_TRAP_HANDLER(check_fastcall_invoke_5); + ((void __fastcall (*)(unsigned, unsigned, unsigned, unsigned, unsigned)) TRAP)(0x11111111, 0x22222222, 0x33333333, 0x44444444, 0x55555555); +} + + +///////////////////////////////////////////////////////////////////////// +////////// TEST FUNCTION CODE GENERATION +///////////////////////////////////////////////////////////////////////// + +int __fastcall check_fastcall_espdiff_0(void) +{ + return 0; +} + +int __fastcall check_fastcall_espdiff_1(int a) +{ + return a; +} + +int __fastcall check_fastcall_espdiff_2(int a, int b) +{ + return a + b; +} + +int __fastcall check_fastcall_espdiff_3(int a, int b, int c) +{ + return a + b + c; +} + +int __fastcall check_fastcall_espdiff_4(int a, int b, int c, int d) +{ + return a + b + c + d; +} + +int __fastcall check_fastcall_espdiff_5(int a, int b, int c, int d, int e) +{ + return a + b + c + d + e; +} + +void test_fastcall_espdiff() +{ + int x; + SET_SAFECALL_TARGET(check_fastcall_espdiff_0); + x = ((typeof(&check_fastcall_espdiff_0))SAFECALL)(); + assert(x == 0); + assert(ESPDIFF == 0); + + SET_SAFECALL_TARGET(check_fastcall_espdiff_1); + x = ((typeof(&check_fastcall_espdiff_1))SAFECALL)(1); + assert(x == 1); + assert(ESPDIFF == 0); + + SET_SAFECALL_TARGET(check_fastcall_espdiff_2); + x = ((typeof(&check_fastcall_espdiff_2))SAFECALL)(1, 2); + assert(x == 1 + 2); + assert(ESPDIFF == 0); + + SET_SAFECALL_TARGET(check_fastcall_espdiff_3); + x = ((typeof(&check_fastcall_espdiff_3))SAFECALL)(1, 2, 3); + assert(x == 1 + 2 + 3); + assert(ESPDIFF == 1*4); + + SET_SAFECALL_TARGET(check_fastcall_espdiff_4); + x = ((typeof(&check_fastcall_espdiff_4))SAFECALL)(1, 2, 3, 4); + assert(x == 1 + 2 + 3 + 4); + assert(ESPDIFF == 2*4); + + SET_SAFECALL_TARGET(check_fastcall_espdiff_5); + x = ((typeof(&check_fastcall_espdiff_5))SAFECALL)(1, 2, 3, 4, 5); + assert(x == 1 + 2 + 3 + 4 + 5); + assert(ESPDIFF == 3*4); +} + +int main() +{ +#define N 10000 + int i; + + for (i = 1; i <= N; i++) { + test_fastcall_espdiff(); + } + + for (i = 1; i <= N; i++) { + test_fastcall_invoke(); + } + + puts("TEST OK"); + return 0; +} diff --git a/tinyc/tests/tests2/99_fastcall.expect b/tinyc/tests/tests2/99_fastcall.expect new file mode 100644 index 000000000..3835d63df --- /dev/null +++ b/tinyc/tests/tests2/99_fastcall.expect @@ -0,0 +1 @@ +TEST OK diff --git a/tinyc/tests/vla_test.c b/tinyc/tests/vla_test.c new file mode 100644 index 000000000..3616c46d4 --- /dev/null +++ b/tinyc/tests/vla_test.c @@ -0,0 +1,84 @@ +/* + * Test that allocating a variable length array in a loop + * does not use up a linear amount of memory + */ + +#include +#include +#include + +#define LOOP_COUNT 1000 +#define ARRAY_SIZE 100 + +/* Overwrite a VLA. This will overwrite the return address if SP is incorrect */ +void smash(char *p, int n) { + memset(p, 0, n); +} + +int test1(int n) { + int i; + char *array_ptrs[LOOP_COUNT]; + + for (i = 0; i < LOOP_COUNT; ++i) { + char test[n]; + smash(test, n); + array_ptrs[i] = test; + } + + return (array_ptrs[0]-array_ptrs[LOOP_COUNT-1] < n) ? 0 : 1; +} + +/* ensure goto does not circumvent array free */ +int test2(int n) { + char *array_ptrs[LOOP_COUNT]; + + int i = 0; +loop:; + char test[n]; + smash(test, n); + if (i >= LOOP_COUNT) + goto end; + array_ptrs[i] = test; + ++i; + goto loop; + +end: + smash(test, n); + char test2[n]; + smash(test2, n); + return (array_ptrs[0] - array_ptrs[LOOP_COUNT-1] < n) ? 0 : 1; +} + +int test3(int n) { + char test[n]; + smash(test, n); + goto label; +label: + smash(test, n); + char test2[n]; + smash(test2, n); + return (test-test2 >= n) ? 0 : 1; +} + +#define RUN_TEST(t) \ + if (!testname || (strcmp(#t, testname) == 0)) { \ + fputs(#t "... ", stdout); \ + fflush(stdout); \ + if (t(ARRAY_SIZE) == 0) { \ + fputs("success\n", stdout); \ + } else { \ + fputs("failure\n", stdout); \ + retval = EXIT_FAILURE; \ + } \ + } + +int main(int argc, char **argv) { + const char *testname = NULL; + int retval = EXIT_SUCCESS; + if (argc > 1) + testname = argv[1]; + RUN_TEST(test1) + RUN_TEST(test2) + RUN_TEST(test3) + return retval; +} diff --git a/tinyc/texi2pod.pl b/tinyc/texi2pod.pl new file mode 100644 index 000000000..d86e176f1 --- /dev/null +++ b/tinyc/texi2pod.pl @@ -0,0 +1,427 @@ +#! /usr/bin/perl -w + +# Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc. + +# This file is part of GNU CC. + +# GNU CC is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# GNU CC is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with GNU CC; see the file COPYING. If not, write to +# the Free Software Foundation, 59 Temple Place - Suite 330, +# Boston MA 02111-1307, USA. + +# This does trivial (and I mean _trivial_) conversion of Texinfo +# markup to Perl POD format. It's intended to be used to extract +# something suitable for a manpage from a Texinfo document. + +$output = 0; +$skipping = 0; +%sects = (); +$section = ""; +@icstack = (); +@endwstack = (); +@skstack = (); +@instack = (); +$shift = ""; +%defs = (); +$fnno = 1; +$inf = ""; +$ibase = ""; + +while ($_ = shift) { + if (/^-D(.*)$/) { + if ($1 ne "") { + $flag = $1; + } else { + $flag = shift; + } + $value = ""; + ($flag, $value) = ($flag =~ /^([^=]+)(?:=(.+))?/); + die "no flag specified for -D\n" + unless $flag ne ""; + die "flags may only contain letters, digits, hyphens, dashes and underscores\n" + unless $flag =~ /^[a-zA-Z0-9_-]+$/; + $defs{$flag} = $value; + } elsif (/^-/) { + usage(); + } else { + $in = $_, next unless defined $in; + $out = $_, next unless defined $out; + usage(); + } +} + +if (defined $in) { + $inf = gensym(); + open($inf, "<$in") or die "opening \"$in\": $!\n"; + $ibase = $1 if $in =~ m|^(.+)/[^/]+$|; +} else { + $inf = \*STDIN; +} + +if (defined $out) { + open(STDOUT, ">$out") or die "opening \"$out\": $!\n"; +} + +while(defined $inf) { +while(<$inf>) { + # Certain commands are discarded without further processing. + /^\@(?: + [a-z]+index # @*index: useful only in complete manual + |need # @need: useful only in printed manual + |(?:end\s+)?group # @group .. @end group: ditto + |page # @page: ditto + |node # @node: useful only in .info file + |(?:end\s+)?ifnottex # @ifnottex .. @end ifnottex: use contents + )\b/x and next; + + chomp; + + # Look for filename and title markers. + /^\@setfilename\s+([^.]+)/ and $fn = $1, next; + /^\@settitle\s+([^.]+)/ and $tl = postprocess($1), next; + + # Identify a man title but keep only the one we are interested in. + /^\@c\s+man\s+title\s+([A-Za-z0-9-]+)\s+(.+)/ and do { + if (exists $defs{$1}) { + $fn = $1; + $tl = postprocess($2); + } + next; + }; + + # Look for blocks surrounded by @c man begin SECTION ... @c man end. + # This really oughta be @ifman ... @end ifman and the like, but such + # would require rev'ing all other Texinfo translators. + /^\@c\s+man\s+begin\s+([A-Z]+)\s+([A-Za-z0-9-]+)/ and do { + $output = 1 if exists $defs{$2}; + $sect = $1; + next; + }; + /^\@c\s+man\s+begin\s+([A-Z]+)/ and $sect = $1, $output = 1, next; + /^\@c\s+man\s+end/ and do { + $sects{$sect} = "" unless exists $sects{$sect}; + $sects{$sect} .= postprocess($section); + $section = ""; + $output = 0; + next; + }; + + # handle variables + /^\@set\s+([a-zA-Z0-9_-]+)\s*(.*)$/ and do { + $defs{$1} = $2; + next; + }; + /^\@clear\s+([a-zA-Z0-9_-]+)/ and do { + delete $defs{$1}; + next; + }; + + next unless $output; + + # Discard comments. (Can't do it above, because then we'd never see + # @c man lines.) + /^\@c\b/ and next; + + # End-block handler goes up here because it needs to operate even + # if we are skipping. + /^\@end\s+([a-z]+)/ and do { + # Ignore @end foo, where foo is not an operation which may + # cause us to skip, if we are presently skipping. + my $ended = $1; + next if $skipping && $ended !~ /^(?:ifset|ifclear|ignore|menu|iftex)$/; + + die "\@end $ended without \@$ended at line $.\n" unless defined $endw; + die "\@$endw ended by \@end $ended at line $.\n" unless $ended eq $endw; + + $endw = pop @endwstack; + + if ($ended =~ /^(?:ifset|ifclear|ignore|menu|iftex)$/) { + $skipping = pop @skstack; + next; + } elsif ($ended =~ /^(?:example|smallexample|display)$/) { + $shift = ""; + $_ = ""; # need a paragraph break + } elsif ($ended =~ /^(?:itemize|enumerate|[fv]?table)$/) { + $_ = "\n=back\n"; + $ic = pop @icstack; + } else { + die "unknown command \@end $ended at line $.\n"; + } + }; + + # We must handle commands which can cause skipping even while we + # are skipping, otherwise we will not process nested conditionals + # correctly. + /^\@ifset\s+([a-zA-Z0-9_-]+)/ and do { + push @endwstack, $endw; + push @skstack, $skipping; + $endw = "ifset"; + $skipping = 1 unless exists $defs{$1}; + next; + }; + + /^\@ifclear\s+([a-zA-Z0-9_-]+)/ and do { + push @endwstack, $endw; + push @skstack, $skipping; + $endw = "ifclear"; + $skipping = 1 if exists $defs{$1}; + next; + }; + + /^\@(ignore|menu|iftex)\b/ and do { + push @endwstack, $endw; + push @skstack, $skipping; + $endw = $1; + $skipping = 1; + next; + }; + + next if $skipping; + + # Character entities. First the ones that can be replaced by raw text + # or discarded outright: + s/\@copyright\{\}/(c)/g; + s/\@dots\{\}/.../g; + s/\@enddots\{\}/..../g; + s/\@([.!? ])/$1/g; + s/\@[:-]//g; + s/\@bullet(?:\{\})?/*/g; + s/\@TeX\{\}/TeX/g; + s/\@pounds\{\}/\#/g; + s/\@minus(?:\{\})?/-/g; + s/\\,/,/g; + + # Now the ones that have to be replaced by special escapes + # (which will be turned back into text by unmunge()) + s/&/&/g; + s/\@\{/{/g; + s/\@\}/}/g; + s/\@\@/&at;/g; + + # Inside a verbatim block, handle @var specially. + if ($shift ne "") { + s/\@var\{([^\}]*)\}/<$1>/g; + } + + # POD doesn't interpret E<> inside a verbatim block. + if ($shift eq "") { + s//>/g; + } else { + s//>/g; + } + + # Single line command handlers. + + /^\@include\s+(.+)$/ and do { + push @instack, $inf; + $inf = gensym(); + + # Try cwd and $ibase. + open($inf, "<" . $1) + or open($inf, "<" . $ibase . "/" . $1) + or die "cannot open $1 or $ibase/$1: $!\n"; + next; + }; + + /^\@(?:section|unnumbered|unnumberedsec|center)\s+(.+)$/ + and $_ = "\n=head2 $1\n"; + /^\@subsection\s+(.+)$/ + and $_ = "\n=head3 $1\n"; + + # Block command handlers: + /^\@itemize\s+(\@[a-z]+|\*|-)/ and do { + push @endwstack, $endw; + push @icstack, $ic; + $ic = $1; + $_ = "\n=over 4\n"; + $endw = "itemize"; + }; + + /^\@enumerate(?:\s+([a-zA-Z0-9]+))?/ and do { + push @endwstack, $endw; + push @icstack, $ic; + if (defined $1) { + $ic = $1 . "."; + } else { + $ic = "1."; + } + $_ = "\n=over 4\n"; + $endw = "enumerate"; + }; + + /^\@([fv]?table)\s+(\@[a-z]+)/ and do { + push @endwstack, $endw; + push @icstack, $ic; + $endw = $1; + $ic = $2; + $ic =~ s/\@(?:samp|strong|key|gcctabopt|option|env)/B/; + $ic =~ s/\@(?:code|kbd)/C/; + $ic =~ s/\@(?:dfn|var|emph|cite|i)/I/; + $ic =~ s/\@(?:file)/F/; + $_ = "\n=over 4\n"; + }; + + /^\@((?:small)?example|display)/ and do { + push @endwstack, $endw; + $endw = $1; + $shift = "\t"; + $_ = ""; # need a paragraph break + }; + + /^\@itemx?\s*(.+)?$/ and do { + if (defined $1) { + # Entity escapes prevent munging by the <> processing below. + $_ = "\n=item $ic\<$1\>\n"; + } else { + $_ = "\n=item $ic\n"; + $ic =~ y/A-Ya-y/B-Zb-z/; + $ic =~ s/(\d+)/$1 + 1/eg; + } + }; + + $section .= $shift.$_."\n"; +} +# End of current file. +close($inf); +$inf = pop @instack; +} + +die "No filename or title\n" unless defined $fn && defined $tl; + +$sects{NAME} = "$fn \- $tl\n"; +$sects{FOOTNOTES} .= "=back\n" if exists $sects{FOOTNOTES}; + +for $sect (qw(NAME SYNOPSIS DESCRIPTION OPTIONS ENVIRONMENT FILES + BUGS NOTES FOOTNOTES SEEALSO AUTHOR COPYRIGHT)) { + if(exists $sects{$sect}) { + $head = $sect; + $head =~ s/SEEALSO/SEE ALSO/; + print "=head1 $head\n\n"; + print scalar unmunge ($sects{$sect}); + print "\n"; + } +} + +sub usage +{ + die "usage: $0 [-D toggle...] [infile [outfile]]\n"; +} + +sub postprocess +{ + local $_ = $_[0]; + + # @value{foo} is replaced by whatever 'foo' is defined as. + while (m/(\@value\{([a-zA-Z0-9_-]+)\})/g) { + if (! exists $defs{$2}) { + print STDERR "Option $2 not defined\n"; + s/\Q$1\E//; + } else { + $value = $defs{$2}; + s/\Q$1\E/$value/; + } + } + + # Formatting commands. + # Temporary escape for @r. + s/\@r\{([^\}]*)\}/R<$1>/g; + s/\@(?:dfn|var|emph|cite|i)\{([^\}]*)\}/I<$1>/g; + s/\@(?:code|kbd)\{([^\}]*)\}/C<$1>/g; + s/\@(?:gccoptlist|samp|strong|key|option|env|command|b)\{([^\}]*)\}/B<$1>/g; + s/\@sc\{([^\}]*)\}/\U$1/g; + s/\@file\{([^\}]*)\}/F<$1>/g; + s/\@w\{([^\}]*)\}/S<$1>/g; + s/\@(?:dmn|math)\{([^\}]*)\}/$1/g; + + # Cross references are thrown away, as are @noindent and @refill. + # (@noindent is impossible in .pod, and @refill is unnecessary.) + # @* is also impossible in .pod; we discard it and any newline that + # follows it. Similarly, our macro @gol must be discarded. + + s/\(?\@xref\{(?:[^\}]*)\}(?:[^.<]|(?:<[^<>]*>))*\.\)?//g; + s/\s+\(\@pxref\{(?:[^\}]*)\}\)//g; + s/;\s+\@pxref\{(?:[^\}]*)\}//g; + s/\@noindent\s*//g; + s/\@refill//g; + s/\@gol//g; + s/\@\*\s*\n?//g; + + # @uref can take one, two, or three arguments, with different + # semantics each time. @url and @email are just like @uref with + # one argument, for our purposes. + s/\@(?:uref|url|email)\{([^\},]*)\}/<B<$1>>/g; + s/\@uref\{([^\},]*),([^\},]*)\}/$2 (C<$1>)/g; + s/\@uref\{([^\},]*),([^\},]*),([^\},]*)\}/$3/g; + + # Turn B blah> into B I B to + # match Texinfo semantics of @emph inside @samp. Also handle @r + # inside bold. + s/<//g; + 1 while s/B<((?:[^<>]|I<[^<>]*>)*)R<([^>]*)>/B<$1>${2}B]*)I<([^>]+)>/B<$1>I<$2>B]*)B<([^>]+)>/I<$1>B<$2>I//g; + s/([BI])<(\s+)([^>]+)>/$2$1<$3>/g; + s/([BI])<([^>]+?)(\s+)>/$1<$2>$3/g; + + # Extract footnotes. This has to be done after all other + # processing because otherwise the regexp will choke on formatting + # inside @footnote. + while (/\@footnote/g) { + s/\@footnote\{([^\}]+)\}/[$fnno]/; + add_footnote($1, $fnno); + $fnno++; + } + + return $_; +} + +sub unmunge +{ + # Replace escaped symbols with their equivalents. + local $_ = $_[0]; + + s/</E/g; + s/>/E/g; + s/{/\{/g; + s/}/\}/g; + s/&at;/\@/g; + s/&/&/g; + return $_; +} + +sub add_footnote +{ + unless (exists $sects{FOOTNOTES}) { + $sects{FOOTNOTES} = "\n=over 4\n\n"; + } + + $sects{FOOTNOTES} .= "=item $fnno.\n\n"; $fnno++; + $sects{FOOTNOTES} .= $_[0]; + $sects{FOOTNOTES} .= "\n\n"; +} + +# stolen from Symbol.pm +{ + my $genseq = 0; + sub gensym + { + my $name = "GEN" . $genseq++; + my $ref = \*{$name}; + delete $::{$name}; + return $ref; + } +} diff --git a/tinyc/win32/build-tcc.bat b/tinyc/win32/build-tcc.bat new file mode 100644 index 000000000..ceb4411ff --- /dev/null +++ b/tinyc/win32/build-tcc.bat @@ -0,0 +1,189 @@ +@rem ------------------------------------------------------ +@rem batch file to build tcc using mingw, msvc or tcc itself +@rem ------------------------------------------------------ + +@echo off +setlocal +if (%1)==(-clean) goto :cleanup +set CC=gcc +set /p VERSION= < ..\VERSION +set INST= +set BIN= +set DOC=no +set EXES_ONLY=no +goto :a0 +:a2 +shift +:a3 +shift +:a0 +if not (%1)==(-c) goto :a1 +set CC=%~2 +if (%2)==(cl) set CC=@call :cl +goto :a2 +:a1 +if (%1)==(-t) set T=%2&& goto :a2 +if (%1)==(-v) set VERSION=%~2&& goto :a2 +if (%1)==(-i) set INST=%2&& goto :a2 +if (%1)==(-b) set BIN=%2&& goto :a2 +if (%1)==(-d) set DOC=yes&& goto :a3 +if (%1)==(-x) set EXES_ONLY=yes&& goto :a3 +if (%1)==() goto :p1 +:usage +echo usage: build-tcc.bat [ options ... ] +echo options: +echo -c prog use prog (gcc/tcc/cl) to compile tcc +echo -c "prog options" use prog with options to compile tcc +echo -t 32/64 force 32/64 bit default target +echo -v "version" set tcc version +echo -i tccdir install tcc into tccdir +echo -b bindir optionally install binaries into bindir elsewhere +echo -d create tcc-doc.html too (needs makeinfo) +echo -x just create the executables +echo -clean delete all previously produced files and directories +exit /B 1 + +@rem ------------------------------------------------------ +@rem sub-routines + +:cleanup +set LOG=echo +%LOG% removing files: +for %%f in (*tcc.exe libtcc.dll lib\*.a) do call :del_file %%f +for %%f in (..\config.h ..\config.texi) do call :del_file %%f +for %%f in (include\*.h) do @if exist ..\%%f call :del_file %%f +for %%f in (include\tcclib.h examples\libtcc_test.c) do call :del_file %%f +for %%f in (*.o *.obj *.def *.pdb *.lib *.exp *.ilk) do call :del_file %%f +%LOG% removing directories: +for %%f in (doc libtcc) do call :del_dir %%f +%LOG% done. +exit /B 0 +:del_file +if exist %1 del %1 && %LOG% %1 +exit /B 0 +:del_dir +if exist %1 rmdir /Q/S %1 && %LOG% %1 +exit /B 0 + +:cl +@echo off +set CMD=cl +:c0 +set ARG=%1 +set ARG=%ARG:.dll=.lib% +if (%1)==(-shared) set ARG=-LD +if (%1)==(-o) shift && set ARG=-Fe%2 +set CMD=%CMD% %ARG% +shift +if not (%1)==() goto :c0 +echo on +%CMD% -O1 -W2 -Zi -MT -GS- -nologo -link -opt:ref,icf +@exit /B %ERRORLEVEL% + +@rem ------------------------------------------------------ +@rem main program + +:p1 +if not %T%_==_ goto :p2 +set T=32 +if %PROCESSOR_ARCHITECTURE%_==AMD64_ set T=64 +if %PROCESSOR_ARCHITEW6432%_==AMD64_ set T=64 +:p2 +if "%CC:~-3%"=="gcc" set CC=%CC% -Os -s -static +set D32=-DTCC_TARGET_PE -DTCC_TARGET_I386 +set D64=-DTCC_TARGET_PE -DTCC_TARGET_X86_64 +set P32=i386-win32 +set P64=x86_64-win32 +if %T%==64 goto :t64 +set D=%D32% +set DX=%D64% +set PX=%P64% +goto :p3 +:t64 +set D=%D64% +set DX=%D32% +set PX=%P32% +goto :p3 + +:p3 +@echo on + +:config.h +echo>..\config.h #define TCC_VERSION "%VERSION%" +echo>> ..\config.h #ifdef TCC_TARGET_X86_64 +echo>> ..\config.h #define TCC_LIBTCC1 "libtcc1-64.a" +echo>> ..\config.h #else +echo>> ..\config.h #define TCC_LIBTCC1 "libtcc1-32.a" +echo>> ..\config.h #endif + +for %%f in (*tcc.exe *tcc.dll) do @del %%f + +:compiler +%CC% -o libtcc.dll -shared ..\libtcc.c %D% -DLIBTCC_AS_DLL +@if errorlevel 1 goto :the_end +%CC% -o tcc.exe ..\tcc.c libtcc.dll %D% -DONE_SOURCE"=0" +%CC% -o %PX%-tcc.exe ..\tcc.c %DX% + +@if (%EXES_ONLY%)==(yes) goto :files-done + +if not exist libtcc mkdir libtcc +if not exist doc mkdir doc +copy>nul ..\include\*.h include +copy>nul ..\tcclib.h include +copy>nul ..\libtcc.h libtcc +copy>nul ..\tests\libtcc_test.c examples +copy>nul tcc-win32.txt doc + +.\tcc -impdef libtcc.dll -o libtcc\libtcc.def +@if errorlevel 1 goto :the_end + +:libtcc1.a +@set O1=libtcc1.o crt1.o crt1w.o wincrt1.o wincrt1w.o dllcrt1.o dllmain.o chkstk.o bcheck.o +.\tcc -m32 -c ../lib/libtcc1.c +.\tcc -m32 -c lib/crt1.c +.\tcc -m32 -c lib/crt1w.c +.\tcc -m32 -c lib/wincrt1.c +.\tcc -m32 -c lib/wincrt1w.c +.\tcc -m32 -c lib/dllcrt1.c +.\tcc -m32 -c lib/dllmain.c +.\tcc -m32 -c lib/chkstk.S +.\tcc -m32 -w -c ../lib/bcheck.c +.\tcc -m32 -c ../lib/alloca86.S +.\tcc -m32 -c ../lib/alloca86-bt.S +.\tcc -m32 -ar lib/libtcc1-32.a %O1% alloca86.o alloca86-bt.o +@if errorlevel 1 goto :the_end +.\tcc -m64 -c ../lib/libtcc1.c +.\tcc -m64 -c lib/crt1.c +.\tcc -m64 -c lib/crt1w.c +.\tcc -m64 -c lib/wincrt1.c +.\tcc -m64 -c lib/wincrt1w.c +.\tcc -m64 -c lib/dllcrt1.c +.\tcc -m64 -c lib/dllmain.c +.\tcc -m64 -c lib/chkstk.S +.\tcc -m64 -w -c ../lib/bcheck.c +.\tcc -m64 -c ../lib/alloca86_64.S +.\tcc -m64 -c ../lib/alloca86_64-bt.S +.\tcc -m64 -ar lib/libtcc1-64.a %O1% alloca86_64.o alloca86_64-bt.o +@if errorlevel 1 goto :the_end + +:tcc-doc.html +@if not (%DOC%)==(yes) goto :doc-done +echo>..\config.texi @set VERSION %VERSION% +cmd /c makeinfo --html --no-split ../tcc-doc.texi -o doc/tcc-doc.html +:doc-done + +:files-done +for %%f in (*.o *.def) do @del %%f + +:copy-install +@if (%INST%)==() goto :the_end +if not exist %INST% mkdir %INST% +@if (%BIN%)==() set BIN=%INST% +if not exist %BIN% mkdir %BIN% +for %%f in (*tcc.exe *tcc.dll) do @copy>nul %%f %BIN%\%%f +@if not exist %INST%\lib mkdir %INST%\lib +for %%f in (lib\*.a lib\*.def) do @copy>nul %%f %INST%\%%f +for %%f in (include examples libtcc doc) do @xcopy>nul /s/i/q/y %%f %INST%\%%f + +:the_end +exit /B %ERRORLEVEL% diff --git a/tinyc/win32/examples/dll.c b/tinyc/win32/examples/dll.c new file mode 100644 index 000000000..052a05644 --- /dev/null +++ b/tinyc/win32/examples/dll.c @@ -0,0 +1,13 @@ +//+--------------------------------------------------------------------------- +// +// dll.c - Windows DLL example - dynamically linked part +// + +#include + +__declspec(dllexport) const char *hello_data = "(not set)"; + +__declspec(dllexport) void hello_func (void) +{ + MessageBox (0, hello_data, "From DLL", MB_ICONINFORMATION); +} diff --git a/tinyc/win32/examples/fib.c b/tinyc/win32/examples/fib.c new file mode 100644 index 000000000..8da26bce6 --- /dev/null +++ b/tinyc/win32/examples/fib.c @@ -0,0 +1,24 @@ +#include +#include // atoi() + +int fib(n) +{ + if (n <= 2) + return 1; + else + return fib(n-1) + fib(n-2); +} + +int main(int argc, char **argv) +{ + int n; + if (argc < 2) { + printf("usage: fib n\n" + "Compute nth Fibonacci number\n"); + return 1; + } + + n = atoi(argv[1]); + printf("fib(%d) = %d\n", n, fib(n)); + return 0; +} diff --git a/tinyc/win32/examples/hello_dll.c b/tinyc/win32/examples/hello_dll.c new file mode 100644 index 000000000..4813c5b94 --- /dev/null +++ b/tinyc/win32/examples/hello_dll.c @@ -0,0 +1,20 @@ +//+--------------------------------------------------------------------------- +// +// HELLO_DLL.C - Windows DLL example - main application part +// + +#include + +void hello_func (void); +__declspec(dllimport) extern const char *hello_data; + +int WINAPI WinMain( + HINSTANCE hInstance, + HINSTANCE hPrevInstance, + LPSTR lpCmdLine, + int nCmdShow) +{ + hello_data = "Hello World!"; + hello_func(); + return 0; +} diff --git a/tinyc/win32/examples/hello_win.c b/tinyc/win32/examples/hello_win.c new file mode 100644 index 000000000..96546e415 --- /dev/null +++ b/tinyc/win32/examples/hello_win.c @@ -0,0 +1,163 @@ +//+--------------------------------------------------------------------------- +// +// HELLO_WIN.C - Windows GUI 'Hello World!' Example +// +//+--------------------------------------------------------------------------- + +#include + +#define APPNAME "HELLO_WIN" + +char szAppName[] = APPNAME; // The name of this application +char szTitle[] = APPNAME; // The title bar text +const char *pWindowText; + +void CenterWindow(HWND hWnd); + +//+--------------------------------------------------------------------------- +// +// Function: WndProc +// +// Synopsis: very unusual type of function - gets called by system to +// process windows messages. +// +// Arguments: same as always. +//---------------------------------------------------------------------------- + +LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + switch (message) { + + // ----------------------- first and last + case WM_CREATE: + CenterWindow(hwnd); + break; + + case WM_DESTROY: + PostQuitMessage(0); + break; + + // ----------------------- get out of it... + case WM_RBUTTONUP: + DestroyWindow(hwnd); + break; + + case WM_KEYDOWN: + if (VK_ESCAPE == wParam) + DestroyWindow(hwnd); + break; + + // ----------------------- display our minimal info + case WM_PAINT: + { + PAINTSTRUCT ps; + HDC hdc; + RECT rc; + hdc = BeginPaint(hwnd, &ps); + + GetClientRect(hwnd, &rc); + SetTextColor(hdc, RGB(240,240,96)); + SetBkMode(hdc, TRANSPARENT); + DrawText(hdc, pWindowText, -1, &rc, DT_CENTER|DT_SINGLELINE|DT_VCENTER); + + EndPaint(hwnd, &ps); + break; + } + + // ----------------------- let windows do all other stuff + default: + return DefWindowProc(hwnd, message, wParam, lParam); + } + return 0; +} + +//+--------------------------------------------------------------------------- +// +// Function: WinMain +// +// Synopsis: standard entrypoint for GUI Win32 apps +// +//---------------------------------------------------------------------------- +int APIENTRY WinMain( + HINSTANCE hInstance, + HINSTANCE hPrevInstance, + LPSTR lpCmdLine, + int nCmdShow + ) +{ + MSG msg; + WNDCLASS wc; + HWND hwnd; + + pWindowText = lpCmdLine[0] ? lpCmdLine : "Hello Windows!"; + + // Fill in window class structure with parameters that describe + // the main window. + + ZeroMemory(&wc, sizeof wc); + wc.hInstance = hInstance; + wc.lpszClassName = szAppName; + wc.lpfnWndProc = (WNDPROC)WndProc; + wc.style = CS_DBLCLKS|CS_VREDRAW|CS_HREDRAW; + wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); + wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); + wc.hCursor = LoadCursor(NULL, IDC_ARROW); + + if (FALSE == RegisterClass(&wc)) + return 0; + + // create the browser + hwnd = CreateWindow( + szAppName, + szTitle, + WS_OVERLAPPEDWINDOW|WS_VISIBLE, + CW_USEDEFAULT, + CW_USEDEFAULT, + 360,//CW_USEDEFAULT, + 240,//CW_USEDEFAULT, + 0, + 0, + hInstance, + 0); + + if (NULL == hwnd) + return 0; + + // Main message loop: + while (GetMessage(&msg, NULL, 0, 0) > 0) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + + return msg.wParam; +} + +//+--------------------------------------------------------------------------- + +//+--------------------------------------------------------------------------- + +void CenterWindow(HWND hwnd_self) +{ + HWND hwnd_parent; + RECT rw_self, rc_parent, rw_parent; + int xpos, ypos; + + hwnd_parent = GetParent(hwnd_self); + if (NULL == hwnd_parent) + hwnd_parent = GetDesktopWindow(); + + GetWindowRect(hwnd_parent, &rw_parent); + GetClientRect(hwnd_parent, &rc_parent); + GetWindowRect(hwnd_self, &rw_self); + + xpos = rw_parent.left + (rc_parent.right + rw_self.left - rw_self.right) / 2; + ypos = rw_parent.top + (rc_parent.bottom + rw_self.top - rw_self.bottom) / 2; + + SetWindowPos( + hwnd_self, NULL, + xpos, ypos, 0, 0, + SWP_NOSIZE|SWP_NOZORDER|SWP_NOACTIVATE + ); +} + +//+--------------------------------------------------------------------------- diff --git a/tinyc/win32/include/_mingw.h b/tinyc/win32/include/_mingw.h new file mode 100644 index 000000000..2fc979872 --- /dev/null +++ b/tinyc/win32/include/_mingw.h @@ -0,0 +1,170 @@ +/* + * _mingw.h + * + * This file is for TinyCC and not part of the Mingw32 package. + * + * THIS SOFTWARE IS NOT COPYRIGHTED + * + * This source code is offered for use in the public domain. You may + * use, modify or distribute it freely. + * + * This code is distributed in the hope that it will be useful but + * WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY + * DISCLAIMED. This includes but is not limited to warranties of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + */ + +#ifndef __MINGW_H +#define __MINGW_H + +/* some winapi files define these before including _mingw.h --> */ +#undef __cdecl +#undef _X86_ +#undef WIN32 +/* <-- */ + +#include +#include + +#define __int8 char +#define __int16 short +#define __int32 int +#define __int64 long long +#define _HAVE_INT64 + +#define __cdecl +#define __declspec(x) __attribute__((x)) +#define __unaligned __attribute__((packed)) +#define __fastcall __attribute__((fastcall)) + +#define __MSVCRT__ 1 +#undef _MSVCRT_ +#define __MINGW_IMPORT extern __declspec(dllimport) +#define __MINGW_ATTRIB_NORETURN +#define __MINGW_ATTRIB_CONST +#define __MINGW_ATTRIB_DEPRECATED +#define __MINGW_ATTRIB_MALLOC +#define __MINGW_ATTRIB_PURE +#define __MINGW_ATTRIB_NONNULL(arg) +#define __MINGW_NOTHROW +#define __GNUC_VA_LIST + +#define _CRTIMP extern +#define __CRT_INLINE extern __inline__ + +#define _CRT_ALIGN(x) __attribute__((aligned(x))) +#define DECLSPEC_ALIGN(x) __attribute__((aligned(x))) +#define _CRT_PACKING 8 +#define __CRT_UNALIGNED +#define _CONST_RETURN + +#ifndef _TRUNCATE +#define _TRUNCATE ((size_t)-1) +#endif + +#define __CRT_STRINGIZE(_Value) #_Value +#define _CRT_STRINGIZE(_Value) __CRT_STRINGIZE(_Value) +#define __CRT_WIDE(_String) L ## _String +#define _CRT_WIDE(_String) __CRT_WIDE(_String) + +#ifdef _WIN64 +#define __stdcall +#define _AMD64_ 1 +#define __x86_64 1 +#define _M_X64 100 /* Visual Studio */ +#define _M_AMD64 100 /* Visual Studio */ +#define USE_MINGW_SETJMP_TWO_ARGS +#define mingw_getsp tinyc_getbp +#define __TRY__ +#else +#define __stdcall __attribute__((__stdcall__)) +#define _X86_ 1 +#define _M_IX86 300 /* Visual Studio */ +#define WIN32 1 +#define _USE_32BIT_TIME_T +#ifdef __arm__ +#define __TRY__ +#else +#define __TRY__ void __try__(void**), *_sehrec[6]; __try__(_sehrec); +#endif +#endif + +/* in stddef.h */ +#define _SIZE_T_DEFINED +#define _SSIZE_T_DEFINED +#define _PTRDIFF_T_DEFINED +#define _WCHAR_T_DEFINED +#define _UINTPTR_T_DEFINED +#define _INTPTR_T_DEFINED +#define _INTEGRAL_MAX_BITS 64 + +#ifndef _TIME32_T_DEFINED +#define _TIME32_T_DEFINED +typedef long __time32_t; +#endif + +#ifndef _TIME64_T_DEFINED +#define _TIME64_T_DEFINED +typedef long long __time64_t; +#endif + +#ifndef _TIME_T_DEFINED +#define _TIME_T_DEFINED +#ifdef _USE_32BIT_TIME_T +typedef __time32_t time_t; +#else +typedef __time64_t time_t; +#endif +#endif + +#ifndef _WCTYPE_T_DEFINED +#define _WCTYPE_T_DEFINED +typedef wchar_t wctype_t; +#endif + +#ifndef _WINT_T +#define _WINT_T +typedef __WINT_TYPE__ wint_t; +#endif + +typedef int errno_t; +#define _ERRCODE_DEFINED + +typedef struct threadlocaleinfostruct *pthreadlocinfo; +typedef struct threadmbcinfostruct *pthreadmbcinfo; +typedef struct localeinfo_struct _locale_tstruct,*_locale_t; + +/* for winapi */ +#define _ANONYMOUS_UNION +#define _ANONYMOUS_STRUCT +#define DECLSPEC_NORETURN +#define DECLARE_STDCALL_P(type) __stdcall type +#define NOSERVICE 1 +#define NOMCX 1 +#define NOIME 1 +#define __INTRIN_H_ +#ifndef DUMMYUNIONNAME +# define DUMMYUNIONNAME +# define DUMMYUNIONNAME1 +# define DUMMYUNIONNAME2 +# define DUMMYUNIONNAME3 +# define DUMMYUNIONNAME4 +# define DUMMYUNIONNAME5 +#endif +#ifndef DUMMYSTRUCTNAME +# define DUMMYSTRUCTNAME +#endif +#ifndef WINVER +# define WINVER 0x0502 +#endif +#ifndef _WIN32_WINNT +# define _WIN32_WINNT 0x502 +#endif + +#define __C89_NAMELESS +#define __MINGW_EXTENSION +#define WINAPI_FAMILY_PARTITION(X) 1 +#define MINGW_HAS_SECURE_API + +#endif /* __MINGW_H */ diff --git a/tinyc/win32/include/assert.h b/tinyc/win32/include/assert.h new file mode 100644 index 000000000..466d4571a --- /dev/null +++ b/tinyc/win32/include/assert.h @@ -0,0 +1,57 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef __ASSERT_H_ +#define __ASSERT_H_ + +#include <_mingw.h> +#ifdef __cplusplus +#include +#endif + +#ifdef NDEBUG +#ifndef assert +#define assert(_Expression) ((void)0) +#endif +#else + +#ifndef _CRT_TERMINATE_DEFINED +#define _CRT_TERMINATE_DEFINED + void __cdecl __MINGW_NOTHROW exit(int _Code) __MINGW_ATTRIB_NORETURN; + _CRTIMP void __cdecl __MINGW_NOTHROW _exit(int _Code) __MINGW_ATTRIB_NORETURN; +#if !defined __NO_ISOCEXT /* extern stub in static libmingwex.a */ +/* C99 function name */ +void __cdecl _Exit(int) __MINGW_ATTRIB_NORETURN; +__CRT_INLINE __MINGW_ATTRIB_NORETURN void __cdecl _Exit(int status) +{ _exit(status); } +#endif + +#pragma push_macro("abort") +#undef abort + void __cdecl __declspec(noreturn) abort(void); +#pragma pop_macro("abort") + +#endif + +#ifdef __cplusplus +extern "C" { +#endif + + +extern void __cdecl _wassert(const wchar_t *_Message,const wchar_t *_File,unsigned _Line); +extern void __cdecl _assert(const char *, const char *, unsigned); + +#ifdef __cplusplus +} +#endif + +#ifndef assert +//#define assert(_Expression) (void)((!!(_Expression)) || (_wassert(_CRT_WIDE(#_Expression),_CRT_WIDE(__FILE__),__LINE__),0)) +#define assert(e) ((e) ? (void)0 : _assert(#e, __FILE__, __LINE__)) +#endif + +#endif + +#endif diff --git a/tinyc/win32/include/conio.h b/tinyc/win32/include/conio.h new file mode 100644 index 000000000..39f779eb0 --- /dev/null +++ b/tinyc/win32/include/conio.h @@ -0,0 +1,409 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _INC_CONIO +#define _INC_CONIO + +#include <_mingw.h> + +#ifdef __cplusplus +extern "C" { +#endif + + _CRTIMP char *_cgets(char *_Buffer); + _CRTIMP int __cdecl _cprintf(const char *_Format,...); + _CRTIMP int __cdecl _cputs(const char *_Str); + _CRTIMP int __cdecl _cscanf(const char *_Format,...); + _CRTIMP int __cdecl _cscanf_l(const char *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _getch(void); + _CRTIMP int __cdecl _getche(void); + _CRTIMP int __cdecl _vcprintf(const char *_Format,va_list _ArgList); + _CRTIMP int __cdecl _cprintf_p(const char *_Format,...); + _CRTIMP int __cdecl _vcprintf_p(const char *_Format,va_list _ArgList); + _CRTIMP int __cdecl _cprintf_l(const char *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vcprintf_l(const char *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _cprintf_p_l(const char *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vcprintf_p_l(const char *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _kbhit(void); + +#if defined(_X86_) && !defined(__x86_64) + int __cdecl _inp(unsigned short); + unsigned short __cdecl _inpw(unsigned short); + unsigned long __cdecl _inpd(unsigned short); + int __cdecl _outp(unsigned short,int); + unsigned short __cdecl _outpw(unsigned short,unsigned short); + unsigned long __cdecl _outpd(unsigned short,unsigned long); +#endif + + _CRTIMP int __cdecl _putch(int _Ch); + _CRTIMP int __cdecl _ungetch(int _Ch); + _CRTIMP int __cdecl _getch_nolock(void); + _CRTIMP int __cdecl _getche_nolock(void); + _CRTIMP int __cdecl _putch_nolock(int _Ch); + _CRTIMP int __cdecl _ungetch_nolock(int _Ch); + +#ifndef _WCONIO_DEFINED +#define _WCONIO_DEFINED + +#ifndef WEOF +#define WEOF (wint_t)(0xFFFF) +#endif + + _CRTIMP wchar_t *_cgetws(wchar_t *_Buffer); + _CRTIMP wint_t __cdecl _getwch(void); + _CRTIMP wint_t __cdecl _getwche(void); + _CRTIMP wint_t __cdecl _putwch(wchar_t _WCh); + _CRTIMP wint_t __cdecl _ungetwch(wint_t _WCh); + _CRTIMP int __cdecl _cputws(const wchar_t *_String); + _CRTIMP int __cdecl _cwprintf(const wchar_t *_Format,...); + _CRTIMP int __cdecl _cwscanf(const wchar_t *_Format,...); + _CRTIMP int __cdecl _cwscanf_l(const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vcwprintf(const wchar_t *_Format,va_list _ArgList); + _CRTIMP int __cdecl _cwprintf_p(const wchar_t *_Format,...); + _CRTIMP int __cdecl _vcwprintf_p(const wchar_t *_Format,va_list _ArgList); + _CRTIMP int __cdecl _cwprintf_l(const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vcwprintf_l(const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _cwprintf_p_l(const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vcwprintf_p_l(const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP wint_t __cdecl _putwch_nolock(wchar_t _WCh); + _CRTIMP wint_t __cdecl _getwch_nolock(void); + _CRTIMP wint_t __cdecl _getwche_nolock(void); + _CRTIMP wint_t __cdecl _ungetwch_nolock(wint_t _WCh); +#endif + +#ifndef NO_OLDNAMES + char *__cdecl cgets(char *_Buffer); + int __cdecl cprintf(const char *_Format,...); + int __cdecl cputs(const char *_Str); + int __cdecl cscanf(const char *_Format,...); + int __cdecl getch(void); + int __cdecl getche(void); + int __cdecl kbhit(void); + int __cdecl putch(int _Ch); + int __cdecl ungetch(int _Ch); + +#if (defined(_X86_) && !defined(__x86_64)) + int __cdecl inp(unsigned short); + unsigned short __cdecl inpw(unsigned short); + int __cdecl outp(unsigned short,int); + unsigned short __cdecl outpw(unsigned short,unsigned short); +#endif + + /* I/O intrin functions. */ + __CRT_INLINE unsigned char __inbyte(unsigned short Port) + { + unsigned char value; + __asm__ __volatile__ ("inb %w1,%b0" + : "=a" (value) + : "Nd" (Port)); + return value; + } + __CRT_INLINE unsigned short __inword(unsigned short Port) + { + unsigned short value; + __asm__ __volatile__ ("inw %w1,%w0" + : "=a" (value) + : "Nd" (Port)); + return value; + } + __CRT_INLINE unsigned long __indword(unsigned short Port) + { + unsigned long value; + __asm__ __volatile__ ("inl %w1,%0" + : "=a" (value) + : "Nd" (Port)); + return value; + } + __CRT_INLINE void __outbyte(unsigned short Port,unsigned char Data) + { + __asm__ __volatile__ ("outb %b0,%w1" + : + : "a" (Data), "Nd" (Port)); + } + __CRT_INLINE void __outword(unsigned short Port,unsigned short Data) + { + __asm__ __volatile__ ("outw %w0,%w1" + : + : "a" (Data), "Nd" (Port)); + } + __CRT_INLINE void __outdword(unsigned short Port,unsigned long Data) + { + __asm__ __volatile__ ("outl %0,%w1" + : + : "a" (Data), "Nd" (Port)); + } + __CRT_INLINE void __inbytestring(unsigned short Port,unsigned char *Buffer,unsigned long Count) + { + __asm__ __volatile__ ( + "cld ; rep ; insb " + : "=D" (Buffer), "=c" (Count) + : "d"(Port), "0"(Buffer), "1" (Count) + ); + } + __CRT_INLINE void __inwordstring(unsigned short Port,unsigned short *Buffer,unsigned long Count) + { + __asm__ __volatile__ ( + "cld ; rep ; insw " + : "=D" (Buffer), "=c" (Count) + : "d"(Port), "0"(Buffer), "1" (Count) + ); + } + __CRT_INLINE void __indwordstring(unsigned short Port,unsigned long *Buffer,unsigned long Count) + { + __asm__ __volatile__ ( + "cld ; rep ; insl " + : "=D" (Buffer), "=c" (Count) + : "d"(Port), "0"(Buffer), "1" (Count) + ); + } + + __CRT_INLINE void __outbytestring(unsigned short Port,unsigned char *Buffer,unsigned long Count) + { + __asm__ __volatile__ ( + "cld ; rep ; outsb " + : "=S" (Buffer), "=c" (Count) + : "d"(Port), "0"(Buffer), "1" (Count) + ); + } + __CRT_INLINE void __outwordstring(unsigned short Port,unsigned short *Buffer,unsigned long Count) + { + __asm__ __volatile__ ( + "cld ; rep ; outsw " + : "=S" (Buffer), "=c" (Count) + : "d"(Port), "0"(Buffer), "1" (Count) + ); + } + __CRT_INLINE void __outdwordstring(unsigned short Port,unsigned long *Buffer,unsigned long Count) + { + __asm__ __volatile__ ( + "cld ; rep ; outsl " + : "=S" (Buffer), "=c" (Count) + : "d"(Port), "0"(Buffer), "1" (Count) + ); + } + + __CRT_INLINE unsigned __int64 __readcr0(void) + { + unsigned __int64 value; + __asm__ __volatile__ ( + "mov %%cr0, %[value]" + : [value] "=q" (value)); + return value; + } + + /* Register sizes are different between 32/64 bit mode. So we have to do this for _WIN64 and _WIN32 + separately. */ + +#ifdef _WIN64 + __CRT_INLINE void __writecr0(unsigned __int64 Data) + { + __asm__ __volatile__ ( + "mov %[Data], %%cr0" + : + : [Data] "q" (Data) + : "memory"); + } + + __CRT_INLINE unsigned __int64 __readcr2(void) + { + unsigned __int64 value; + __asm__ __volatile__ ( + "mov %%cr2, %[value]" + : [value] "=q" (value)); + return value; + } + + __CRT_INLINE void __writecr2(unsigned __int64 Data) + { + __asm__ __volatile__ ( + "mov %[Data], %%cr2" + : + : [Data] "q" (Data) + : "memory"); + } + + __CRT_INLINE unsigned __int64 __readcr3(void) + { + unsigned __int64 value; + __asm__ __volatile__ ( + "mov %%cr3, %[value]" + : [value] "=q" (value)); + return value; + } + + __CRT_INLINE void __writecr3(unsigned __int64 Data) + { + __asm__ __volatile__ ( + "mov %[Data], %%cr3" + : + : [Data] "q" (Data) + : "memory"); + } + + __CRT_INLINE unsigned __int64 __readcr4(void) + { + unsigned __int64 value; + __asm__ __volatile__ ( + "mov %%cr4, %[value]" + : [value] "=q" (value)); + return value; + } + + __CRT_INLINE void __writecr4(unsigned __int64 Data) + { + __asm__ __volatile__ ( + "mov %[Data], %%cr4" + : + : [Data] "q" (Data) + : "memory"); + } + + __CRT_INLINE unsigned __int64 __readcr8(void) + { + unsigned __int64 value; + __asm__ __volatile__ ( + "mov %%cr8, %[value]" + : [value] "=q" (value)); + return value; + } + + __CRT_INLINE void __writecr8(unsigned __int64 Data) + { + __asm__ __volatile__ ( + "mov %[Data], %%cr8" + : + : [Data] "q" (Data) + : "memory"); + } + +#elif defined(_WIN32) + + __CRT_INLINE void __writecr0(unsigned Data) + { + __asm__ __volatile__ ( + "mov %[Data], %%cr0" + : + : [Data] "q" (Data) + : "memory"); + } + + __CRT_INLINE unsigned long __readcr2(void) + { + unsigned long value; + __asm__ __volatile__ ( + "mov %%cr2, %[value]" + : [value] "=q" (value)); + return value; + } + + __CRT_INLINE void __writecr2(unsigned Data) + { + __asm__ __volatile__ ( + "mov %[Data], %%cr2" + : + : [Data] "q" (Data) + : "memory"); + } + + __CRT_INLINE unsigned long __readcr3(void) + { + unsigned long value; + __asm__ __volatile__ ( + "mov %%cr3, %[value]" + : [value] "=q" (value)); + return value; + } + + __CRT_INLINE void __writecr3(unsigned Data) + { + __asm__ __volatile__ ( + "mov %[Data], %%cr3" + : + : [Data] "q" (Data) + : "memory"); + } + + __CRT_INLINE unsigned long __readcr4(void) + { + unsigned long value; + __asm__ __volatile__ ( + "mov %%cr4, %[value]" + : [value] "=q" (value)); + return value; + } + + __CRT_INLINE void __writecr4(unsigned Data) + { + __asm__ __volatile__ ( + "mov %[Data], %%cr4" + : + : [Data] "q" (Data) + : "memory"); + } + + __CRT_INLINE unsigned long __readcr8(void) + { + unsigned long value; __asm__ __volatile__ ( + "mov %%cr8, %[value]" + : [value] "=q" (value)); + return value; + } + + __CRT_INLINE void __writecr8(unsigned Data) + { + __asm__ __volatile__ ( + "mov %[Data], %%cr8" + : + : [Data] "q" (Data) + : "memory"); + } + +#endif + + __CRT_INLINE unsigned __int64 __readmsr(unsigned long msr) + { + unsigned __int64 val1, val2; + __asm__ __volatile__( + "rdmsr" + : "=a" (val1), "=d" (val2) + : "c" (msr)); + return val1 | (val2 << 32); + } + + __CRT_INLINE void __writemsr (unsigned long msr, unsigned __int64 Value) + { + unsigned long val1 = Value, val2 = Value >> 32; + __asm__ __volatile__ ( + "wrmsr" + : + : "c" (msr), "a" (val1), "d" (val2)); + } + + __CRT_INLINE unsigned __int64 __rdtsc(void) + { + unsigned __int64 val1, val2; + __asm__ __volatile__ ( + "rdtsc" + : "=a" (val1), "=d" (val2)); + return val1 | (val2 << 32); + } + + __CRT_INLINE void __cpuid(int CPUInfo[4], int InfoType) + { + __asm__ __volatile__ ( + "cpuid" + : "=a" (CPUInfo [0]), "=b" (CPUInfo [1]), "=c" (CPUInfo [2]), "=d" (CPUInfo [3]) + : "a" (InfoType)); + } + +#endif + +#ifdef __cplusplus +} +#endif + +#include + +#endif diff --git a/tinyc/win32/include/ctype.h b/tinyc/win32/include/ctype.h new file mode 100644 index 000000000..7e9010026 --- /dev/null +++ b/tinyc/win32/include/ctype.h @@ -0,0 +1,281 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _INC_CTYPE +#define _INC_CTYPE + +#include <_mingw.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef WEOF +#define WEOF (wint_t)(0xFFFF) +#endif + +#ifndef _CRT_CTYPEDATA_DEFINED +#define _CRT_CTYPEDATA_DEFINED +#ifndef _CTYPE_DISABLE_MACROS + +#ifndef __PCTYPE_FUNC +#define __PCTYPE_FUNC __pctype_func() +#ifdef _MSVCRT_ +#define __pctype_func() (_pctype) +#else +#define __pctype_func() (*_imp___pctype) +#endif +#endif + +#ifndef _pctype +#ifdef _MSVCRT_ + extern unsigned short *_pctype; +#else + extern unsigned short **_imp___pctype; +#define _pctype (*_imp___pctype) +#endif +#endif + +#endif +#endif + +#ifndef _CRT_WCTYPEDATA_DEFINED +#define _CRT_WCTYPEDATA_DEFINED +#ifndef _CTYPE_DISABLE_MACROS +#ifndef _wctype +#ifdef _MSVCRT_ + extern unsigned short *_wctype; +#else + extern unsigned short **_imp___wctype; +#define _wctype (*_imp___wctype) +#endif +#endif +#ifdef _MSVCRT_ +#define __pwctype_func() (_pwctype) +#ifndef _pwctype + extern unsigned short *_pwctype; +#endif +#else +#define __pwctype_func() (*_imp___pwctype) +#ifndef _pwctype + extern unsigned short **_imp___pwctype; +#define _pwctype (*_imp___pwctype) +#endif +#endif +#endif +#endif + + /* CRT stuff */ +#if 1 + extern const unsigned char __newclmap[]; + extern const unsigned char __newcumap[]; + extern pthreadlocinfo __ptlocinfo; + extern pthreadmbcinfo __ptmbcinfo; + extern int __globallocalestatus; + extern int __locale_changed; + extern struct threadlocaleinfostruct __initiallocinfo; + extern _locale_tstruct __initiallocalestructinfo; + pthreadlocinfo __cdecl __updatetlocinfo(void); + pthreadmbcinfo __cdecl __updatetmbcinfo(void); +#endif + +#define _UPPER 0x1 +#define _LOWER 0x2 +#define _DIGIT 0x4 +#define _SPACE 0x8 + +#define _PUNCT 0x10 +#define _CONTROL 0x20 +#define _BLANK 0x40 +#define _HEX 0x80 + +#define _LEADBYTE 0x8000 +#define _ALPHA (0x0100|_UPPER|_LOWER) + +#ifndef _CTYPE_DEFINED +#define _CTYPE_DEFINED + + _CRTIMP int __cdecl _isctype(int _C,int _Type); + _CRTIMP int __cdecl _isctype_l(int _C,int _Type,_locale_t _Locale); + _CRTIMP int __cdecl isalpha(int _C); + _CRTIMP int __cdecl _isalpha_l(int _C,_locale_t _Locale); + _CRTIMP int __cdecl isupper(int _C); + _CRTIMP int __cdecl _isupper_l(int _C,_locale_t _Locale); + _CRTIMP int __cdecl islower(int _C); + _CRTIMP int __cdecl _islower_l(int _C,_locale_t _Locale); + _CRTIMP int __cdecl isdigit(int _C); + _CRTIMP int __cdecl _isdigit_l(int _C,_locale_t _Locale); + _CRTIMP int __cdecl isxdigit(int _C); + _CRTIMP int __cdecl _isxdigit_l(int _C,_locale_t _Locale); + _CRTIMP int __cdecl isspace(int _C); + _CRTIMP int __cdecl _isspace_l(int _C,_locale_t _Locale); + _CRTIMP int __cdecl ispunct(int _C); + _CRTIMP int __cdecl _ispunct_l(int _C,_locale_t _Locale); + _CRTIMP int __cdecl isalnum(int _C); + _CRTIMP int __cdecl _isalnum_l(int _C,_locale_t _Locale); + _CRTIMP int __cdecl isprint(int _C); + _CRTIMP int __cdecl _isprint_l(int _C,_locale_t _Locale); + _CRTIMP int __cdecl isgraph(int _C); + _CRTIMP int __cdecl _isgraph_l(int _C,_locale_t _Locale); + _CRTIMP int __cdecl iscntrl(int _C); + _CRTIMP int __cdecl _iscntrl_l(int _C,_locale_t _Locale); + _CRTIMP int __cdecl toupper(int _C); + _CRTIMP int __cdecl tolower(int _C); + _CRTIMP int __cdecl _tolower(int _C); + _CRTIMP int __cdecl _tolower_l(int _C,_locale_t _Locale); + _CRTIMP int __cdecl _toupper(int _C); + _CRTIMP int __cdecl _toupper_l(int _C,_locale_t _Locale); + _CRTIMP int __cdecl __isascii(int _C); + _CRTIMP int __cdecl __toascii(int _C); + _CRTIMP int __cdecl __iscsymf(int _C); + _CRTIMP int __cdecl __iscsym(int _C); + +#if (defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || !defined (NO_OLDNAMES) +int __cdecl isblank(int _C); +#endif +#endif + +#ifndef _WCTYPE_DEFINED +#define _WCTYPE_DEFINED + + int __cdecl iswalpha(wint_t _C); + _CRTIMP int __cdecl _iswalpha_l(wint_t _C,_locale_t _Locale); + int __cdecl iswupper(wint_t _C); + _CRTIMP int __cdecl _iswupper_l(wint_t _C,_locale_t _Locale); + int __cdecl iswlower(wint_t _C); + _CRTIMP int __cdecl _iswlower_l(wint_t _C,_locale_t _Locale); + int __cdecl iswdigit(wint_t _C); + _CRTIMP int __cdecl _iswdigit_l(wint_t _C,_locale_t _Locale); + int __cdecl iswxdigit(wint_t _C); + _CRTIMP int __cdecl _iswxdigit_l(wint_t _C,_locale_t _Locale); + int __cdecl iswspace(wint_t _C); + _CRTIMP int __cdecl _iswspace_l(wint_t _C,_locale_t _Locale); + int __cdecl iswpunct(wint_t _C); + _CRTIMP int __cdecl _iswpunct_l(wint_t _C,_locale_t _Locale); + int __cdecl iswalnum(wint_t _C); + _CRTIMP int __cdecl _iswalnum_l(wint_t _C,_locale_t _Locale); + int __cdecl iswprint(wint_t _C); + _CRTIMP int __cdecl _iswprint_l(wint_t _C,_locale_t _Locale); + int __cdecl iswgraph(wint_t _C); + _CRTIMP int __cdecl _iswgraph_l(wint_t _C,_locale_t _Locale); + int __cdecl iswcntrl(wint_t _C); + _CRTIMP int __cdecl _iswcntrl_l(wint_t _C,_locale_t _Locale); + int __cdecl iswascii(wint_t _C); + int __cdecl isleadbyte(int _C); + _CRTIMP int __cdecl _isleadbyte_l(int _C,_locale_t _Locale); + wint_t __cdecl towupper(wint_t _C); + _CRTIMP wint_t __cdecl _towupper_l(wint_t _C,_locale_t _Locale); + wint_t __cdecl towlower(wint_t _C); + _CRTIMP wint_t __cdecl _towlower_l(wint_t _C,_locale_t _Locale); + int __cdecl iswctype(wint_t _C,wctype_t _Type); + _CRTIMP int __cdecl _iswctype_l(wint_t _C,wctype_t _Type,_locale_t _Locale); + _CRTIMP int __cdecl __iswcsymf(wint_t _C); + _CRTIMP int __cdecl _iswcsymf_l(wint_t _C,_locale_t _Locale); + _CRTIMP int __cdecl __iswcsym(wint_t _C); + _CRTIMP int __cdecl _iswcsym_l(wint_t _C,_locale_t _Locale); + int __cdecl is_wctype(wint_t _C,wctype_t _Type); + +#if (defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || !defined (NO_OLDNAMES) +int __cdecl iswblank(wint_t _C); +#endif +#endif + +#ifndef _CTYPE_DISABLE_MACROS + +#ifndef MB_CUR_MAX +#define MB_CUR_MAX ___mb_cur_max_func() +#ifndef __mb_cur_max +#ifdef _MSVCRT_ + extern int __mb_cur_max; +#else +#define __mb_cur_max (*_imp____mb_cur_max) + extern int *_imp____mb_cur_max; +#endif +#endif +#ifdef _MSVCRT_ +#define ___mb_cur_max_func() (__mb_cur_max) +#else +#define ___mb_cur_max_func() (*_imp____mb_cur_max) +#endif +#endif + +#define __chvalidchk(a,b) (__PCTYPE_FUNC[(a)] & (b)) +#define _chvalidchk_l(_Char,_Flag,_Locale) (!_Locale ? __chvalidchk(_Char,_Flag) : ((_locale_t)_Locale)->locinfo->pctype[_Char] & (_Flag)) +#define _ischartype_l(_Char,_Flag,_Locale) (((_Locale)!=NULL && (((_locale_t)(_Locale))->locinfo->mb_cur_max) > 1) ? _isctype_l(_Char,(_Flag),_Locale) : _chvalidchk_l(_Char,_Flag,_Locale)) +#define _isalpha_l(_Char,_Locale) _ischartype_l(_Char,_ALPHA,_Locale) +#define _isupper_l(_Char,_Locale) _ischartype_l(_Char,_UPPER,_Locale) +#define _islower_l(_Char,_Locale) _ischartype_l(_Char,_LOWER,_Locale) +#define _isdigit_l(_Char,_Locale) _ischartype_l(_Char,_DIGIT,_Locale) +#define _isxdigit_l(_Char,_Locale) _ischartype_l(_Char,_HEX,_Locale) +#define _isspace_l(_Char,_Locale) _ischartype_l(_Char,_SPACE,_Locale) +#define _ispunct_l(_Char,_Locale) _ischartype_l(_Char,_PUNCT,_Locale) +#define _isalnum_l(_Char,_Locale) _ischartype_l(_Char,_ALPHA|_DIGIT,_Locale) +#define _isprint_l(_Char,_Locale) _ischartype_l(_Char,_BLANK|_PUNCT|_ALPHA|_DIGIT,_Locale) +#define _isgraph_l(_Char,_Locale) _ischartype_l(_Char,_PUNCT|_ALPHA|_DIGIT,_Locale) +#define _iscntrl_l(_Char,_Locale) _ischartype_l(_Char,_CONTROL,_Locale) +#define _tolower(_Char) ((_Char)-'A'+'a') +#define _toupper(_Char) ((_Char)-'a'+'A') +#define __isascii(_Char) ((unsigned)(_Char) < 0x80) +#define __toascii(_Char) ((_Char) & 0x7f) + +#ifndef _WCTYPE_INLINE_DEFINED +#define _WCTYPE_INLINE_DEFINED + +#undef _CRT_WCTYPE_NOINLINE +#ifndef __cplusplus +#define iswalpha(_c) (iswctype(_c,_ALPHA)) +#define iswupper(_c) (iswctype(_c,_UPPER)) +#define iswlower(_c) (iswctype(_c,_LOWER)) +#define iswdigit(_c) (iswctype(_c,_DIGIT)) +#define iswxdigit(_c) (iswctype(_c,_HEX)) +#define iswspace(_c) (iswctype(_c,_SPACE)) +#define iswpunct(_c) (iswctype(_c,_PUNCT)) +#define iswalnum(_c) (iswctype(_c,_ALPHA|_DIGIT)) +#define iswprint(_c) (iswctype(_c,_BLANK|_PUNCT|_ALPHA|_DIGIT)) +#define iswgraph(_c) (iswctype(_c,_PUNCT|_ALPHA|_DIGIT)) +#define iswcntrl(_c) (iswctype(_c,_CONTROL)) +#define iswascii(_c) ((unsigned)(_c) < 0x80) +#define _iswalpha_l(_c,_p) (_iswctype_l(_c,_ALPHA,_p)) +#define _iswupper_l(_c,_p) (_iswctype_l(_c,_UPPER,_p)) +#define _iswlower_l(_c,_p) (_iswctype_l(_c,_LOWER,_p)) +#define _iswdigit_l(_c,_p) (_iswctype_l(_c,_DIGIT,_p)) +#define _iswxdigit_l(_c,_p) (_iswctype_l(_c,_HEX,_p)) +#define _iswspace_l(_c,_p) (_iswctype_l(_c,_SPACE,_p)) +#define _iswpunct_l(_c,_p) (_iswctype_l(_c,_PUNCT,_p)) +#define _iswalnum_l(_c,_p) (_iswctype_l(_c,_ALPHA|_DIGIT,_p)) +#define _iswprint_l(_c,_p) (_iswctype_l(_c,_BLANK|_PUNCT|_ALPHA|_DIGIT,_p)) +#define _iswgraph_l(_c,_p) (_iswctype_l(_c,_PUNCT|_ALPHA|_DIGIT,_p)) +#define _iswcntrl_l(_c,_p) (_iswctype_l(_c,_CONTROL,_p)) +#endif +#endif + +#define __iscsymf(_c) (isalpha(_c) || ((_c)=='_')) +#define __iscsym(_c) (isalnum(_c) || ((_c)=='_')) +#define __iswcsymf(_c) (iswalpha(_c) || ((_c)=='_')) +#define __iswcsym(_c) (iswalnum(_c) || ((_c)=='_')) +#define _iscsymf_l(_c,_p) (_isalpha_l(_c,_p) || ((_c)=='_')) +#define _iscsym_l(_c,_p) (_isalnum_l(_c,_p) || ((_c)=='_')) +#define _iswcsymf_l(_c,_p) (_iswalpha_l(_c,_p) || ((_c)=='_')) +#define _iswcsym_l(_c,_p) (_iswalnum_l(_c,_p) || ((_c)=='_')) +#endif + +#ifndef NO_OLDNAMES +#ifndef _CTYPE_DEFINED + int __cdecl isascii(int _C); + int __cdecl toascii(int _C); + int __cdecl iscsymf(int _C); + int __cdecl iscsym(int _C); +#else +#define isascii __isascii +#define toascii __toascii +#define iscsymf __iscsymf +#define iscsym __iscsym +#endif +#endif + +#ifdef __cplusplus +} +#endif +#endif diff --git a/tinyc/win32/include/dir.h b/tinyc/win32/include/dir.h new file mode 100644 index 000000000..f38f750d2 --- /dev/null +++ b/tinyc/win32/include/dir.h @@ -0,0 +1,31 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +/* + * dir.h + * + * This file OBSOLESCENT and only provided for backward compatibility. + * Please use io.h instead. + * + * This file is part of the Mingw32 package. + * + * Contributors: + * Created by Colin Peters + * Mumit Khan + * + * THIS SOFTWARE IS NOT COPYRIGHTED + * + * This source code is offered for use in the public domain. You may + * use, modify or distribute it freely. + * + * This code is distributed in the hope that it will be useful but + * WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY + * DISCLAIMED. This includes but is not limited to warranties of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + */ + +#include + diff --git a/tinyc/win32/include/direct.h b/tinyc/win32/include/direct.h new file mode 100644 index 000000000..99ce69db7 --- /dev/null +++ b/tinyc/win32/include/direct.h @@ -0,0 +1,68 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _INC_DIRECT +#define _INC_DIRECT + +#include <_mingw.h> +#include + +#pragma pack(push,_CRT_PACKING) + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _DISKFREE_T_DEFINED +#define _DISKFREE_T_DEFINED + struct _diskfree_t { + unsigned total_clusters; + unsigned avail_clusters; + unsigned sectors_per_cluster; + unsigned bytes_per_sector; + }; +#endif + + _CRTIMP char *__cdecl _getcwd(char *_DstBuf,int _SizeInBytes); + _CRTIMP char *__cdecl _getdcwd(int _Drive,char *_DstBuf,int _SizeInBytes); + char *__cdecl _getdcwd_nolock(int _Drive,char *_DstBuf,int _SizeInBytes); + _CRTIMP int __cdecl _chdir(const char *_Path); + _CRTIMP int __cdecl _mkdir(const char *_Path); + _CRTIMP int __cdecl _rmdir(const char *_Path); + _CRTIMP int __cdecl _chdrive(int _Drive); + _CRTIMP int __cdecl _getdrive(void); + _CRTIMP unsigned long __cdecl _getdrives(void); + +#ifndef _GETDISKFREE_DEFINED +#define _GETDISKFREE_DEFINED + _CRTIMP unsigned __cdecl _getdiskfree(unsigned _Drive,struct _diskfree_t *_DiskFree); +#endif + +#ifndef _WDIRECT_DEFINED +#define _WDIRECT_DEFINED + _CRTIMP wchar_t *__cdecl _wgetcwd(wchar_t *_DstBuf,int _SizeInWords); + _CRTIMP wchar_t *__cdecl _wgetdcwd(int _Drive,wchar_t *_DstBuf,int _SizeInWords); + wchar_t *__cdecl _wgetdcwd_nolock(int _Drive,wchar_t *_DstBuf,int _SizeInWords); + _CRTIMP int __cdecl _wchdir(const wchar_t *_Path); + _CRTIMP int __cdecl _wmkdir(const wchar_t *_Path); + _CRTIMP int __cdecl _wrmdir(const wchar_t *_Path); +#endif + +#ifndef NO_OLDNAMES + +#define diskfree_t _diskfree_t + + char *__cdecl getcwd(char *_DstBuf,int _SizeInBytes); + int __cdecl chdir(const char *_Path); + int __cdecl mkdir(const char *_Path); + int __cdecl rmdir(const char *_Path); +#endif + +#ifdef __cplusplus +} +#endif + +#pragma pack(pop) +#endif diff --git a/tinyc/win32/include/dirent.h b/tinyc/win32/include/dirent.h new file mode 100644 index 000000000..cd31f59e0 --- /dev/null +++ b/tinyc/win32/include/dirent.h @@ -0,0 +1,135 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +/* All the headers include this file. */ +#include <_mingw.h> + +#ifndef __STRICT_ANSI__ + +#ifndef _DIRENT_H_ +#define _DIRENT_H_ + + +#pragma pack(push,_CRT_PACKING) + +#include + +#ifndef RC_INVOKED + +#ifdef __cplusplus +extern "C" { +#endif + + struct dirent + { + long d_ino; /* Always zero. */ + unsigned short d_reclen; /* Always zero. */ + unsigned short d_namlen; /* Length of name in d_name. */ + char* d_name; /* File name. */ + /* NOTE: The name in the dirent structure points to the name in the + * finddata_t structure in the DIR. */ + }; + + /* + * This is an internal data structure. Good programmers will not use it + * except as an argument to one of the functions below. + * dd_stat field is now int (was short in older versions). + */ + typedef struct + { + /* disk transfer area for this dir */ + struct _finddata_t dd_dta; + + /* dirent struct to return from dir (NOTE: this makes this thread + * safe as long as only one thread uses a particular DIR struct at + * a time) */ + struct dirent dd_dir; + + /* _findnext handle */ + long dd_handle; + + /* + * Status of search: + * 0 = not started yet (next entry to read is first entry) + * -1 = off the end + * positive = 0 based index of next entry + */ + int dd_stat; + + /* given path for dir with search pattern (struct is extended) */ + char dd_name[1]; + } DIR; + + DIR* __cdecl opendir (const char*); + struct dirent* __cdecl readdir (DIR*); + int __cdecl closedir (DIR*); + void __cdecl rewinddir (DIR*); + long __cdecl telldir (DIR*); + void __cdecl seekdir (DIR*, long); + + + /* wide char versions */ + + struct _wdirent + { + long d_ino; /* Always zero. */ + unsigned short d_reclen; /* Always zero. */ + unsigned short d_namlen; /* Length of name in d_name. */ + wchar_t* d_name; /* File name. */ + /* NOTE: The name in the dirent structure points to the name in the * wfinddata_t structure in the _WDIR. */ + }; + + /* + * This is an internal data structure. Good programmers will not use it + * except as an argument to one of the functions below. + */ + typedef struct + { + /* disk transfer area for this dir */ + struct _wfinddata_t dd_dta; + + /* dirent struct to return from dir (NOTE: this makes this thread + * safe as long as only one thread uses a particular DIR struct at + * a time) */ + struct _wdirent dd_dir; + + /* _findnext handle */ + long dd_handle; + + /* + * Status of search: + * 0 = not started yet (next entry to read is first entry) + * -1 = off the end + * positive = 0 based index of next entry + */ + int dd_stat; + + /* given path for dir with search pattern (struct is extended) */ + wchar_t dd_name[1]; + } _WDIR; + + + + _WDIR* __cdecl _wopendir (const wchar_t*); + struct _wdirent* __cdecl _wreaddir (_WDIR*); + int __cdecl _wclosedir (_WDIR*); + void __cdecl _wrewinddir (_WDIR*); + long __cdecl _wtelldir (_WDIR*); + void __cdecl _wseekdir (_WDIR*, long); + + +#ifdef __cplusplus +} +#endif + +#endif /* Not RC_INVOKED */ + +#pragma pack(pop) + +#endif /* Not _DIRENT_H_ */ + + +#endif /* Not __STRICT_ANSI__ */ + diff --git a/tinyc/win32/include/dos.h b/tinyc/win32/include/dos.h new file mode 100644 index 000000000..294e8fe1b --- /dev/null +++ b/tinyc/win32/include/dos.h @@ -0,0 +1,55 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _INC_DOS +#define _INC_DOS + +#include <_mingw.h> +#include + +#pragma pack(push,_CRT_PACKING) + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _DISKFREE_T_DEFINED +#define _DISKFREE_T_DEFINED + + struct _diskfree_t { + unsigned total_clusters; + unsigned avail_clusters; + unsigned sectors_per_cluster; + unsigned bytes_per_sector; + }; +#endif + +#define _A_NORMAL 0x00 +#define _A_RDONLY 0x01 +#define _A_HIDDEN 0x02 +#define _A_SYSTEM 0x04 +#define _A_SUBDIR 0x10 +#define _A_ARCH 0x20 + +#ifndef _GETDISKFREE_DEFINED +#define _GETDISKFREE_DEFINED + _CRTIMP unsigned __cdecl _getdiskfree(unsigned _Drive,struct _diskfree_t *_DiskFree); +#endif + +#if (defined(_X86_) && !defined(__x86_64)) + void __cdecl _disable(void); + void __cdecl _enable(void); +#endif + +#ifndef NO_OLDNAMES +#define diskfree_t _diskfree_t +#endif + +#ifdef __cplusplus +} +#endif + +#pragma pack(pop) +#endif diff --git a/tinyc/win32/include/errno.h b/tinyc/win32/include/errno.h new file mode 100644 index 000000000..c2df01581 --- /dev/null +++ b/tinyc/win32/include/errno.h @@ -0,0 +1,75 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _INC_ERRNO +#define _INC_ERRNO + +#include <_mingw.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _CRT_ERRNO_DEFINED +#define _CRT_ERRNO_DEFINED + _CRTIMP extern int *__cdecl _errno(void); +#define errno (*_errno()) + + errno_t __cdecl _set_errno(int _Value); + errno_t __cdecl _get_errno(int *_Value); +#endif + +#define EPERM 1 +#define ENOENT 2 +#define ESRCH 3 +#define EINTR 4 +#define EIO 5 +#define ENXIO 6 +#define E2BIG 7 +#define ENOEXEC 8 +#define EBADF 9 +#define ECHILD 10 +#define EAGAIN 11 +#define ENOMEM 12 +#define EACCES 13 +#define EFAULT 14 +#define EBUSY 16 +#define EEXIST 17 +#define EXDEV 18 +#define ENODEV 19 +#define ENOTDIR 20 +#define EISDIR 21 +#define ENFILE 23 +#define EMFILE 24 +#define ENOTTY 25 +#define EFBIG 27 +#define ENOSPC 28 +#define ESPIPE 29 +#define EROFS 30 +#define EMLINK 31 +#define EPIPE 32 +#define EDOM 33 +#define EDEADLK 36 +#define ENAMETOOLONG 38 +#define ENOLCK 39 +#define ENOSYS 40 +#define ENOTEMPTY 41 + +#ifndef RC_INVOKED +#if !defined(_SECURECRT_ERRCODE_VALUES_DEFINED) +#define _SECURECRT_ERRCODE_VALUES_DEFINED +#define EINVAL 22 +#define ERANGE 34 +#define EILSEQ 42 +#define STRUNCATE 80 +#endif +#endif + +#define EDEADLOCK EDEADLK + +#ifdef __cplusplus +} +#endif +#endif diff --git a/tinyc/win32/include/excpt.h b/tinyc/win32/include/excpt.h new file mode 100644 index 000000000..26cc9437c --- /dev/null +++ b/tinyc/win32/include/excpt.h @@ -0,0 +1,123 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _INC_EXCPT +#define _INC_EXCPT + +#include <_mingw.h> + +#pragma pack(push,_CRT_PACKING) + +#ifdef __cplusplus +extern "C" { +#endif + + struct _EXCEPTION_POINTERS; + +#ifndef EXCEPTION_DISPOSITION +#define EXCEPTION_DISPOSITION int +#endif +#define ExceptionContinueExecution 0 +#define ExceptionContinueSearch 1 +#define ExceptionNestedException 2 +#define ExceptionCollidedUnwind 3 + +#if (defined(_X86_) && !defined(__x86_64)) + struct _EXCEPTION_RECORD; + struct _CONTEXT; + + EXCEPTION_DISPOSITION __cdecl _except_handler(struct _EXCEPTION_RECORD *_ExceptionRecord,void *_EstablisherFrame,struct _CONTEXT *_ContextRecord,void *_DispatcherContext); +#elif defined(__ia64__) + + typedef struct _EXCEPTION_POINTERS *Exception_info_ptr; + struct _EXCEPTION_RECORD; + struct _CONTEXT; + struct _DISPATCHER_CONTEXT; + + _CRTIMP EXCEPTION_DISPOSITION __cdecl __C_specific_handler (struct _EXCEPTION_RECORD *_ExceptionRecord,unsigned __int64 _MemoryStackFp,unsigned __int64 _BackingStoreFp,struct _CONTEXT *_ContextRecord,struct _DISPATCHER_CONTEXT *_DispatcherContext,unsigned __int64 _GlobalPointer); +#elif defined(__x86_64) + + struct _EXCEPTION_RECORD; + struct _CONTEXT; +#endif + +#define GetExceptionCode _exception_code +#define exception_code _exception_code +#define GetExceptionInformation (struct _EXCEPTION_POINTERS *)_exception_info +#define exception_info (struct _EXCEPTION_POINTERS *)_exception_info +#define AbnormalTermination _abnormal_termination +#define abnormal_termination _abnormal_termination + + unsigned long __cdecl _exception_code(void); + void *__cdecl _exception_info(void); + int __cdecl _abnormal_termination(void); + +#define EXCEPTION_EXECUTE_HANDLER 1 +#define EXCEPTION_CONTINUE_SEARCH 0 +#define EXCEPTION_CONTINUE_EXECUTION -1 + + /* CRT stuff */ + typedef void (__cdecl * _PHNDLR)(int); + + struct _XCPT_ACTION { + unsigned long XcptNum; + int SigNum; + _PHNDLR XcptAction; + }; + + extern struct _XCPT_ACTION _XcptActTab[]; + extern int _XcptActTabCount; + extern int _XcptActTabSize; + extern int _First_FPE_Indx; + extern int _Num_FPE; + + int __cdecl __CppXcptFilter(unsigned long _ExceptionNum,struct _EXCEPTION_POINTERS * _ExceptionPtr); + int __cdecl _XcptFilter(unsigned long _ExceptionNum,struct _EXCEPTION_POINTERS * _ExceptionPtr); + + /* + * The type of function that is expected as an exception handler to be + * installed with _try1. + */ + typedef EXCEPTION_DISPOSITION (*PEXCEPTION_HANDLER)(struct _EXCEPTION_RECORD*, void*, struct _CONTEXT*, void*); + +#ifndef HAVE_NO_SEH + /* + * This is not entirely necessary, but it is the structure installed by + * the _try1 primitive below. + */ + typedef struct _EXCEPTION_REGISTRATION { + struct _EXCEPTION_REGISTRATION *prev; + EXCEPTION_DISPOSITION (*handler)(struct _EXCEPTION_RECORD*, void*, struct _CONTEXT*, void*); + } EXCEPTION_REGISTRATION, *PEXCEPTION_REGISTRATION; + + typedef EXCEPTION_REGISTRATION EXCEPTION_REGISTRATION_RECORD; + typedef PEXCEPTION_REGISTRATION PEXCEPTION_REGISTRATION_RECORD; +#endif + +#if (defined(_X86_) && !defined(__x86_64)) +#define __try1(pHandler) \ + __asm__ ("pushl %0;pushl %%fs:0;movl %%esp,%%fs:0;" : : "g" (pHandler)); + +#define __except1 \ + __asm__ ("movl (%%esp),%%eax;movl %%eax,%%fs:0;addl $8,%%esp;" \ + : : : "%eax"); +#elif defined(__x86_64) +#define __try1(pHandler) \ + __asm__ ("pushq %0;pushq %%gs:0;movq %%rsp,%%gs:0;" : : "g" (pHandler)); + +#define __except1 \ + __asm__ ("movq (%%rsp),%%rax;movq %%rax,%%gs:0;addq $16,%%rsp;" \ + : : : "%rax"); +#else +#define __try1(pHandler) +#define __except1 +#endif + +#ifdef __cplusplus +} +#endif + +#pragma pack(pop) +#endif diff --git a/tinyc/win32/include/fcntl.h b/tinyc/win32/include/fcntl.h new file mode 100644 index 000000000..9202b08cc --- /dev/null +++ b/tinyc/win32/include/fcntl.h @@ -0,0 +1,52 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#include <_mingw.h> + +#include + +#ifndef _INC_FCNTL +#define _INC_FCNTL + +#define _O_RDONLY 0x0000 +#define _O_WRONLY 0x0001 +#define _O_RDWR 0x0002 +#define _O_APPEND 0x0008 +#define _O_CREAT 0x0100 +#define _O_TRUNC 0x0200 +#define _O_EXCL 0x0400 +#define _O_TEXT 0x4000 +#define _O_BINARY 0x8000 +#define _O_WTEXT 0x10000 +#define _O_U16TEXT 0x20000 +#define _O_U8TEXT 0x40000 +#define _O_ACCMODE (_O_RDONLY|_O_WRONLY|_O_RDWR) + +#define _O_RAW _O_BINARY +#define _O_NOINHERIT 0x0080 +#define _O_TEMPORARY 0x0040 +#define _O_SHORT_LIVED 0x1000 + +#define _O_SEQUENTIAL 0x0020 +#define _O_RANDOM 0x0010 + +#if !defined(NO_OLDNAMES) || defined(_POSIX) +#define O_RDONLY _O_RDONLY +#define O_WRONLY _O_WRONLY +#define O_RDWR _O_RDWR +#define O_APPEND _O_APPEND +#define O_CREAT _O_CREAT +#define O_TRUNC _O_TRUNC +#define O_EXCL _O_EXCL +#define O_TEXT _O_TEXT +#define O_BINARY _O_BINARY +#define O_RAW _O_BINARY +#define O_TEMPORARY _O_TEMPORARY +#define O_NOINHERIT _O_NOINHERIT +#define O_SEQUENTIAL _O_SEQUENTIAL +#define O_RANDOM _O_RANDOM +#define O_ACCMODE _O_ACCMODE +#endif +#endif diff --git a/tinyc/win32/include/fenv.h b/tinyc/win32/include/fenv.h new file mode 100644 index 000000000..258f3a5d9 --- /dev/null +++ b/tinyc/win32/include/fenv.h @@ -0,0 +1,108 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _FENV_H_ +#define _FENV_H_ + +#include <_mingw.h> + +/* FPU status word exception flags */ +#define FE_INVALID 0x01 +#define FE_DENORMAL 0x02 +#define FE_DIVBYZERO 0x04 +#define FE_OVERFLOW 0x08 +#define FE_UNDERFLOW 0x10 +#define FE_INEXACT 0x20 +#define FE_ALL_EXCEPT (FE_INVALID | FE_DENORMAL | FE_DIVBYZERO \ + | FE_OVERFLOW | FE_UNDERFLOW | FE_INEXACT) + +/* FPU control word rounding flags */ +#define FE_TONEAREST 0x0000 +#define FE_DOWNWARD 0x0400 +#define FE_UPWARD 0x0800 +#define FE_TOWARDZERO 0x0c00 + +/* The MXCSR exception flags are the same as the + FE flags. */ +#define __MXCSR_EXCEPT_FLAG_SHIFT 0 + +/* How much to shift FE status word exception flags + to get MXCSR rounding flags, */ +#define __MXCSR_ROUND_FLAG_SHIFT 3 + +#ifndef RC_INVOKED +/* + For now, support only for the basic abstraction of flags that are + either set or clear. fexcept_t could be structure that holds more + info about the fp environment. +*/ +typedef unsigned short fexcept_t; + +/* This 32-byte struct represents the entire floating point + environment as stored by fnstenv or fstenv, augmented by + the contents of the MXCSR register, as stored by stmxcsr + (if CPU supports it). */ +typedef struct +{ + unsigned short __control_word; + unsigned short __unused0; + unsigned short __status_word; + unsigned short __unused1; + unsigned short __tag_word; + unsigned short __unused2; + unsigned int __ip_offset; /* instruction pointer offset */ + unsigned short __ip_selector; + unsigned short __opcode; + unsigned int __data_offset; + unsigned short __data_selector; + unsigned short __unused3; + unsigned int __mxcsr; /* contents of the MXCSR register */ +} fenv_t; + + +/*The C99 standard (7.6.9) allows us to define implementation-specific macros for + different fp environments */ + +/* The default Intel x87 floating point environment (64-bit mantissa) */ +#define FE_PC64_ENV ((const fenv_t *)-1) + +/* The floating point environment set by MSVCRT _fpreset (53-bit mantissa) */ +#define FE_PC53_ENV ((const fenv_t *)-2) + +/* The FE_DFL_ENV macro is required by standard. + fesetenv will use the environment set at app startup.*/ +#define FE_DFL_ENV ((const fenv_t *) 0) + +#ifdef __cplusplus +extern "C" { +#endif + +/*TODO: Some of these could be inlined */ +/* 7.6.2 Exception */ + +extern int __cdecl feclearexcept (int); +extern int __cdecl fegetexceptflag (fexcept_t * flagp, int excepts); +extern int __cdecl feraiseexcept (int excepts ); +extern int __cdecl fesetexceptflag (const fexcept_t *, int); +extern int __cdecl fetestexcept (int excepts); + +/* 7.6.3 Rounding */ + +extern int __cdecl fegetround (void); +extern int __cdecl fesetround (int mode); + +/* 7.6.4 Environment */ + +extern int __cdecl fegetenv(fenv_t * envp); +extern int __cdecl fesetenv(const fenv_t * ); +extern int __cdecl feupdateenv(const fenv_t *); +extern int __cdecl feholdexcept(fenv_t *); + +#ifdef __cplusplus +} +#endif +#endif /* Not RC_INVOKED */ + +#endif /* ndef _FENV_H */ diff --git a/tinyc/win32/include/inttypes.h b/tinyc/win32/include/inttypes.h new file mode 100644 index 000000000..736009195 --- /dev/null +++ b/tinyc/win32/include/inttypes.h @@ -0,0 +1,297 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +/* 7.8 Format conversion of integer types */ + +#ifndef _INTTYPES_H_ +#define _INTTYPES_H_ + +#include <_mingw.h> +#include +#define __need_wchar_t +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + intmax_t quot; + intmax_t rem; + } imaxdiv_t; + +#if !defined(__cplusplus) || defined(__STDC_FORMAT_MACROS) + +/* 7.8.1 Macros for format specifiers + * + * MS runtime does not yet understand C9x standard "ll" + * length specifier. It appears to treat "ll" as "l". + * The non-standard I64 length specifier causes warning in GCC, + * but understood by MS runtime functions. + */ + +/* fprintf macros for signed types */ +#define PRId8 "d" +#define PRId16 "d" +#define PRId32 "d" +#define PRId64 "I64d" + +#define PRIdLEAST8 "d" +#define PRIdLEAST16 "d" +#define PRIdLEAST32 "d" +#define PRIdLEAST64 "I64d" + +#define PRIdFAST8 "d" +#define PRIdFAST16 "d" +#define PRIdFAST32 "d" +#define PRIdFAST64 "I64d" + +#define PRIdMAX "I64d" + +#define PRIi8 "i" +#define PRIi16 "i" +#define PRIi32 "i" +#define PRIi64 "I64i" + +#define PRIiLEAST8 "i" +#define PRIiLEAST16 "i" +#define PRIiLEAST32 "i" +#define PRIiLEAST64 "I64i" + +#define PRIiFAST8 "i" +#define PRIiFAST16 "i" +#define PRIiFAST32 "i" +#define PRIiFAST64 "I64i" + +#define PRIiMAX "I64i" + +#define PRIo8 "o" +#define PRIo16 "o" +#define PRIo32 "o" +#define PRIo64 "I64o" + +#define PRIoLEAST8 "o" +#define PRIoLEAST16 "o" +#define PRIoLEAST32 "o" +#define PRIoLEAST64 "I64o" + +#define PRIoFAST8 "o" +#define PRIoFAST16 "o" +#define PRIoFAST32 "o" +#define PRIoFAST64 "I64o" + +#define PRIoMAX "I64o" + +/* fprintf macros for unsigned types */ +#define PRIu8 "u" +#define PRIu16 "u" +#define PRIu32 "u" +#define PRIu64 "I64u" + + +#define PRIuLEAST8 "u" +#define PRIuLEAST16 "u" +#define PRIuLEAST32 "u" +#define PRIuLEAST64 "I64u" + +#define PRIuFAST8 "u" +#define PRIuFAST16 "u" +#define PRIuFAST32 "u" +#define PRIuFAST64 "I64u" + +#define PRIuMAX "I64u" + +#define PRIx8 "x" +#define PRIx16 "x" +#define PRIx32 "x" +#define PRIx64 "I64x" + +#define PRIxLEAST8 "x" +#define PRIxLEAST16 "x" +#define PRIxLEAST32 "x" +#define PRIxLEAST64 "I64x" + +#define PRIxFAST8 "x" +#define PRIxFAST16 "x" +#define PRIxFAST32 "x" +#define PRIxFAST64 "I64x" + +#define PRIxMAX "I64x" + +#define PRIX8 "X" +#define PRIX16 "X" +#define PRIX32 "X" +#define PRIX64 "I64X" + +#define PRIXLEAST8 "X" +#define PRIXLEAST16 "X" +#define PRIXLEAST32 "X" +#define PRIXLEAST64 "I64X" + +#define PRIXFAST8 "X" +#define PRIXFAST16 "X" +#define PRIXFAST32 "X" +#define PRIXFAST64 "I64X" + +#define PRIXMAX "I64X" + +/* + * fscanf macros for signed int types + * NOTE: if 32-bit int is used for int_fast8_t and int_fast16_t + * (see stdint.h, 7.18.1.3), FAST8 and FAST16 should have + * no length identifiers + */ + +#define SCNd16 "hd" +#define SCNd32 "d" +#define SCNd64 "I64d" + +#define SCNdLEAST16 "hd" +#define SCNdLEAST32 "d" +#define SCNdLEAST64 "I64d" + +#define SCNdFAST16 "hd" +#define SCNdFAST32 "d" +#define SCNdFAST64 "I64d" + +#define SCNdMAX "I64d" + +#define SCNi16 "hi" +#define SCNi32 "i" +#define SCNi64 "I64i" + +#define SCNiLEAST16 "hi" +#define SCNiLEAST32 "i" +#define SCNiLEAST64 "I64i" + +#define SCNiFAST16 "hi" +#define SCNiFAST32 "i" +#define SCNiFAST64 "I64i" + +#define SCNiMAX "I64i" + +#define SCNo16 "ho" +#define SCNo32 "o" +#define SCNo64 "I64o" + +#define SCNoLEAST16 "ho" +#define SCNoLEAST32 "o" +#define SCNoLEAST64 "I64o" + +#define SCNoFAST16 "ho" +#define SCNoFAST32 "o" +#define SCNoFAST64 "I64o" + +#define SCNoMAX "I64o" + +#define SCNx16 "hx" +#define SCNx32 "x" +#define SCNx64 "I64x" + +#define SCNxLEAST16 "hx" +#define SCNxLEAST32 "x" +#define SCNxLEAST64 "I64x" + +#define SCNxFAST16 "hx" +#define SCNxFAST32 "x" +#define SCNxFAST64 "I64x" + +#define SCNxMAX "I64x" + +/* fscanf macros for unsigned int types */ + +#define SCNu16 "hu" +#define SCNu32 "u" +#define SCNu64 "I64u" + +#define SCNuLEAST16 "hu" +#define SCNuLEAST32 "u" +#define SCNuLEAST64 "I64u" + +#define SCNuFAST16 "hu" +#define SCNuFAST32 "u" +#define SCNuFAST64 "I64u" + +#define SCNuMAX "I64u" + +#ifdef _WIN64 +#define PRIdPTR "I64d" +#define PRIiPTR "I64i" +#define PRIoPTR "I64o" +#define PRIuPTR "I64u" +#define PRIxPTR "I64x" +#define PRIXPTR "I64X" +#define SCNdPTR "I64d" +#define SCNiPTR "I64i" +#define SCNoPTR "I64o" +#define SCNxPTR "I64x" +#define SCNuPTR "I64u" +#else +#define PRIdPTR "d" +#define PRIiPTR "i" +#define PRIoPTR "o" +#define PRIuPTR "u" +#define PRIxPTR "x" +#define PRIXPTR "X" +#define SCNdPTR "d" +#define SCNiPTR "i" +#define SCNoPTR "o" +#define SCNxPTR "x" +#define SCNuPTR "u" +#endif + +#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L +/* + * no length modifier for char types prior to C9x + * MS runtime scanf appears to treat "hh" as "h" + */ + +/* signed char */ +#define SCNd8 "hhd" +#define SCNdLEAST8 "hhd" +#define SCNdFAST8 "hhd" + +#define SCNi8 "hhi" +#define SCNiLEAST8 "hhi" +#define SCNiFAST8 "hhi" + +#define SCNo8 "hho" +#define SCNoLEAST8 "hho" +#define SCNoFAST8 "hho" + +#define SCNx8 "hhx" +#define SCNxLEAST8 "hhx" +#define SCNxFAST8 "hhx" + +/* unsigned char */ +#define SCNu8 "hhu" +#define SCNuLEAST8 "hhu" +#define SCNuFAST8 "hhu" +#endif /* __STDC_VERSION__ >= 199901 */ + +#endif /* !defined(__cplusplus) || defined(__STDC_FORMAT_MACROS) */ + +intmax_t __cdecl imaxabs (intmax_t j); +__CRT_INLINE intmax_t __cdecl imaxabs (intmax_t j) + {return (j >= 0 ? j : -j);} +imaxdiv_t __cdecl imaxdiv (intmax_t numer, intmax_t denom); + +/* 7.8.2 Conversion functions for greatest-width integer types */ + +intmax_t __cdecl strtoimax (const char* __restrict__ nptr, + char** __restrict__ endptr, int base); +uintmax_t __cdecl strtoumax (const char* __restrict__ nptr, + char** __restrict__ endptr, int base); + +intmax_t __cdecl wcstoimax (const wchar_t* __restrict__ nptr, + wchar_t** __restrict__ endptr, int base); +uintmax_t __cdecl wcstoumax (const wchar_t* __restrict__ nptr, + wchar_t** __restrict__ endptr, int base); + +#ifdef __cplusplus +} +#endif + +#endif /* ndef _INTTYPES_H */ diff --git a/tinyc/win32/include/io.h b/tinyc/win32/include/io.h new file mode 100644 index 000000000..e2aeec3db --- /dev/null +++ b/tinyc/win32/include/io.h @@ -0,0 +1,418 @@ + +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _IO_H_ +#define _IO_H_ + +#include <_mingw.h> +#include + +#pragma pack(push,_CRT_PACKING) + +#ifndef _POSIX_ + +#ifdef __cplusplus +extern "C" { +#endif + +_CRTIMP char* __cdecl _getcwd (char*, int); +#ifndef _FSIZE_T_DEFINED + typedef unsigned long _fsize_t; +#define _FSIZE_T_DEFINED +#endif + +#ifndef _FINDDATA_T_DEFINED + + struct _finddata32_t { + unsigned attrib; + __time32_t time_create; + __time32_t time_access; + __time32_t time_write; + _fsize_t size; + char name[260]; + }; + +/*#if _INTEGRAL_MAX_BITS >= 64*/ + + struct _finddata32i64_t { + unsigned attrib; + __time32_t time_create; + __time32_t time_access; + __time32_t time_write; + __int64 size; + char name[260]; + }; + + struct _finddata64i32_t { + unsigned attrib; + __time64_t time_create; + __time64_t time_access; + __time64_t time_write; + _fsize_t size; + char name[260]; + }; + + struct __finddata64_t { + unsigned attrib; + __time64_t time_create; + __time64_t time_access; + __time64_t time_write; + __int64 size; + char name[260]; + }; +/* #endif */ + +#ifdef _USE_32BIT_TIME_T +#define _finddata_t _finddata32_t +#define _finddatai64_t _finddata32i64_t + +#ifdef _WIN64 +#define _findfirst _findfirst32 +#define _findnext _findnext32 +#else +#define _findfirst32 _findfirst +#define _findnext32 _findnext +#endif +#define _findfirsti64 _findfirst32i64 +#define _findnexti64 _findnext32i64 +#else +#define _finddata_t _finddata64i32_t +#define _finddatai64_t __finddata64_t + +#define _findfirst _findfirst64i32 +#define _findnext _findnext64i32 +#define _findfirsti64 _findfirst64 +#define _findnexti64 _findnext64 +#endif + +#define _FINDDATA_T_DEFINED +#endif + +#ifndef _WFINDDATA_T_DEFINED + + struct _wfinddata32_t { + unsigned attrib; + __time32_t time_create; + __time32_t time_access; + __time32_t time_write; + _fsize_t size; + wchar_t name[260]; + }; + +/* #if _INTEGRAL_MAX_BITS >= 64 */ + + struct _wfinddata32i64_t { + unsigned attrib; + __time32_t time_create; + __time32_t time_access; + __time32_t time_write; + __int64 size; + wchar_t name[260]; + }; + + struct _wfinddata64i32_t { + unsigned attrib; + __time64_t time_create; + __time64_t time_access; + __time64_t time_write; + _fsize_t size; + wchar_t name[260]; + }; + + struct _wfinddata64_t { + unsigned attrib; + __time64_t time_create; + __time64_t time_access; + __time64_t time_write; + __int64 size; + wchar_t name[260]; + }; +/* #endif */ + +#ifdef _USE_32BIT_TIME_T +#define _wfinddata_t _wfinddata32_t +#define _wfinddatai64_t _wfinddata32i64_t + +#define _wfindfirst _wfindfirst32 +#define _wfindnext _wfindnext32 +#define _wfindfirsti64 _wfindfirst32i64 +#define _wfindnexti64 _wfindnext32i64 +#else +#define _wfinddata_t _wfinddata64i32_t +#define _wfinddatai64_t _wfinddata64_t + +#define _wfindfirst _wfindfirst64i32 +#define _wfindnext _wfindnext64i32 +#define _wfindfirsti64 _wfindfirst64 +#define _wfindnexti64 _wfindnext64 +#endif + +#define _WFINDDATA_T_DEFINED +#endif + +#define _A_NORMAL 0x00 +#define _A_RDONLY 0x01 +#define _A_HIDDEN 0x02 +#define _A_SYSTEM 0x04 +#define _A_SUBDIR 0x10 +#define _A_ARCH 0x20 + +#ifndef _SIZE_T_DEFINED +#define _SIZE_T_DEFINED +#undef size_t +#ifdef _WIN64 +#if defined(__GNUC__) && defined(__STRICT_ANSI__) + typedef unsigned int size_t __attribute__ ((mode (DI))); +#else + typedef unsigned __int64 size_t; +#endif +#else + typedef unsigned int size_t; +#endif +#endif + +#ifndef _SSIZE_T_DEFINED +#define _SSIZE_T_DEFINED +#undef ssize_t +#ifdef _WIN64 +#if defined(__GNUC__) && defined(__STRICT_ANSI__) + typedef int ssize_t __attribute__ ((mode (DI))); +#else + typedef __int64 ssize_t; +#endif +#else + typedef int ssize_t; +#endif +#endif + +#ifndef _OFF_T_DEFINED +#define _OFF_T_DEFINED +#ifndef _OFF_T_ +#define _OFF_T_ + typedef long _off_t; +#if !defined(NO_OLDNAMES) || defined(_POSIX) + typedef long off_t; +#endif +#endif +#endif + +#ifndef _OFF64_T_DEFINED +#define _OFF64_T_DEFINED +#if defined(__GNUC__) && defined(__STRICT_ANSI__) + typedef int _off64_t __attribute__ ((mode (DI))); +#if !defined(NO_OLDNAMES) || defined(_POSIX) + typedef int off64_t __attribute__ ((mode (DI))); +#endif +#else + typedef long long _off64_t; +#if !defined(NO_OLDNAMES) || defined(_POSIX) + typedef long long off64_t; +#endif +#endif +#endif + + /* Some defines for _access nAccessMode (MS doesn't define them, but + * it doesn't seem to hurt to add them). */ +#define F_OK 0 /* Check for file existence */ +#define X_OK 1 /* Check for execute permission. */ +#define W_OK 2 /* Check for write permission */ +#define R_OK 4 /* Check for read permission */ + + _CRTIMP int __cdecl _access(const char *_Filename,int _AccessMode); + _CRTIMP int __cdecl _chmod(const char *_Filename,int _Mode); + _CRTIMP int __cdecl _chsize(int _FileHandle,long _Size); + _CRTIMP int __cdecl _close(int _FileHandle); + _CRTIMP int __cdecl _commit(int _FileHandle); + _CRTIMP int __cdecl _creat(const char *_Filename,int _PermissionMode); + _CRTIMP int __cdecl _dup(int _FileHandle); + _CRTIMP int __cdecl _dup2(int _FileHandleSrc,int _FileHandleDst); + _CRTIMP int __cdecl _eof(int _FileHandle); + _CRTIMP long __cdecl _filelength(int _FileHandle); + _CRTIMP intptr_t __cdecl _findfirst32(const char *_Filename,struct _finddata32_t *_FindData); + _CRTIMP int __cdecl _findnext32(intptr_t _FindHandle,struct _finddata32_t *_FindData); + _CRTIMP int __cdecl _findclose(intptr_t _FindHandle); + _CRTIMP int __cdecl _isatty(int _FileHandle); + _CRTIMP int __cdecl _locking(int _FileHandle,int _LockMode,long _NumOfBytes); + _CRTIMP long __cdecl _lseek(int _FileHandle,long _Offset,int _Origin); + _off64_t lseek64(int fd,_off64_t offset, int whence); + _CRTIMP char *__cdecl _mktemp(char *_TemplateName); + _CRTIMP int __cdecl _pipe(int *_PtHandles,unsigned int _PipeSize,int _TextMode); + _CRTIMP int __cdecl _read(int _FileHandle,void *_DstBuf,unsigned int _MaxCharCount); + +#ifndef _CRT_DIRECTORY_DEFINED +#define _CRT_DIRECTORY_DEFINED + int __cdecl remove(const char *_Filename); + int __cdecl rename(const char *_OldFilename,const char *_NewFilename); + _CRTIMP int __cdecl _unlink(const char *_Filename); +#ifndef NO_OLDNAMES + int __cdecl unlink(const char *_Filename); +#endif +#endif + + _CRTIMP int __cdecl _setmode(int _FileHandle,int _Mode); + _CRTIMP long __cdecl _tell(int _FileHandle); + _CRTIMP int __cdecl _umask(int _Mode); + _CRTIMP int __cdecl _write(int _FileHandle,const void *_Buf,unsigned int _MaxCharCount); + +#if _INTEGRAL_MAX_BITS >= 64 + _CRTIMP __int64 __cdecl _filelengthi64(int _FileHandle); + _CRTIMP intptr_t __cdecl _findfirst32i64(const char *_Filename,struct _finddata32i64_t *_FindData); + _CRTIMP intptr_t __cdecl _findfirst64(const char *_Filename,struct __finddata64_t *_FindData); +#ifdef __cplusplus +#include +#endif + intptr_t __cdecl _findfirst64i32(const char *_Filename,struct _finddata64i32_t *_FindData); + __CRT_INLINE intptr_t __cdecl _findfirst64i32(const char *_Filename,struct _finddata64i32_t *_FindData) + { + struct __finddata64_t fd; + intptr_t ret = _findfirst64(_Filename,&fd); + _FindData->attrib=fd.attrib; + _FindData->time_create=fd.time_create; + _FindData->time_access=fd.time_access; + _FindData->time_write=fd.time_write; + _FindData->size=(_fsize_t) fd.size; + strncpy(_FindData->name,fd.name,260); + return ret; + } + _CRTIMP int __cdecl _findnext32i64(intptr_t _FindHandle,struct _finddata32i64_t *_FindData); + _CRTIMP int __cdecl _findnext64(intptr_t _FindHandle,struct __finddata64_t *_FindData); + int __cdecl _findnext64i32(intptr_t _FindHandle,struct _finddata64i32_t *_FindData); + __CRT_INLINE int __cdecl _findnext64i32(intptr_t _FindHandle,struct _finddata64i32_t *_FindData) + { + struct __finddata64_t fd; + int ret = _findnext64(_FindHandle,&fd); + _FindData->attrib=fd.attrib; + _FindData->time_create=fd.time_create; + _FindData->time_access=fd.time_access; + _FindData->time_write=fd.time_write; + _FindData->size=(_fsize_t) fd.size; + strncpy(_FindData->name,fd.name,260); + return ret; + } + __int64 __cdecl _lseeki64(int _FileHandle,__int64 _Offset,int _Origin); + __int64 __cdecl _telli64(int _FileHandle); +#endif +#ifndef NO_OLDNAMES + +#ifndef _UWIN + int __cdecl chdir (const char *); + char *__cdecl getcwd (char *, int); + int __cdecl mkdir (const char *); + char *__cdecl mktemp(char *); + int __cdecl rmdir (const char*); + int __cdecl chmod (const char *, int); +#endif /* _UWIN */ + +#endif /* Not NO_OLDNAMES */ + + _CRTIMP errno_t __cdecl _sopen_s(int *_FileHandle,const char *_Filename,int _OpenFlag,int _ShareFlag,int _PermissionMode); + +#ifndef __cplusplus + _CRTIMP int __cdecl _open(const char *_Filename,int _OpenFlag,...); + _CRTIMP int __cdecl _sopen(const char *_Filename,int _OpenFlag,int _ShareFlag,...); +#else + extern "C++" _CRTIMP int __cdecl _open(const char *_Filename,int _Openflag,int _PermissionMode = 0); + extern "C++" _CRTIMP int __cdecl _sopen(const char *_Filename,int _Openflag,int _ShareFlag,int _PermissionMode = 0); +#endif + +#ifndef _WIO_DEFINED +#define _WIO_DEFINED + _CRTIMP int __cdecl _waccess(const wchar_t *_Filename,int _AccessMode); + _CRTIMP int __cdecl _wchmod(const wchar_t *_Filename,int _Mode); + _CRTIMP int __cdecl _wcreat(const wchar_t *_Filename,int _PermissionMode); + _CRTIMP intptr_t __cdecl _wfindfirst32(const wchar_t *_Filename,struct _wfinddata32_t *_FindData); + _CRTIMP int __cdecl _wfindnext32(intptr_t _FindHandle,struct _wfinddata32_t *_FindData); + _CRTIMP int __cdecl _wunlink(const wchar_t *_Filename); + _CRTIMP int __cdecl _wrename(const wchar_t *_NewFilename,const wchar_t *_OldFilename); + _CRTIMP wchar_t *__cdecl _wmktemp(wchar_t *_TemplateName); + +#if _INTEGRAL_MAX_BITS >= 64 + _CRTIMP intptr_t __cdecl _wfindfirst32i64(const wchar_t *_Filename,struct _wfinddata32i64_t *_FindData); + intptr_t __cdecl _wfindfirst64i32(const wchar_t *_Filename,struct _wfinddata64i32_t *_FindData); + _CRTIMP intptr_t __cdecl _wfindfirst64(const wchar_t *_Filename,struct _wfinddata64_t *_FindData); + _CRTIMP int __cdecl _wfindnext32i64(intptr_t _FindHandle,struct _wfinddata32i64_t *_FindData); + int __cdecl _wfindnext64i32(intptr_t _FindHandle,struct _wfinddata64i32_t *_FindData); + _CRTIMP int __cdecl _wfindnext64(intptr_t _FindHandle,struct _wfinddata64_t *_FindData); +#endif + + _CRTIMP errno_t __cdecl _wsopen_s(int *_FileHandle,const wchar_t *_Filename,int _OpenFlag,int _ShareFlag,int _PermissionFlag); + +#if !defined(__cplusplus) || !(defined(_X86_) && !defined(__x86_64)) + _CRTIMP int __cdecl _wopen(const wchar_t *_Filename,int _OpenFlag,...); + _CRTIMP int __cdecl _wsopen(const wchar_t *_Filename,int _OpenFlag,int _ShareFlag,...); +#else + extern "C++" _CRTIMP int __cdecl _wopen(const wchar_t *_Filename,int _OpenFlag,int _PermissionMode = 0); + extern "C++" _CRTIMP int __cdecl _wsopen(const wchar_t *_Filename,int _OpenFlag,int _ShareFlag,int _PermissionMode = 0); +#endif + +#endif + + int __cdecl __lock_fhandle(int _Filehandle); + void __cdecl _unlock_fhandle(int _Filehandle); + _CRTIMP intptr_t __cdecl _get_osfhandle(int _FileHandle); + _CRTIMP int __cdecl _open_osfhandle(intptr_t _OSFileHandle,int _Flags); + +#ifndef NO_OLDNAMES + int __cdecl access(const char *_Filename,int _AccessMode); + int __cdecl chmod(const char *_Filename,int _AccessMode); + int __cdecl chsize(int _FileHandle,long _Size); + int __cdecl close(int _FileHandle); + int __cdecl creat(const char *_Filename,int _PermissionMode); + int __cdecl dup(int _FileHandle); + int __cdecl dup2(int _FileHandleSrc,int _FileHandleDst); + int __cdecl eof(int _FileHandle); + long __cdecl filelength(int _FileHandle); + int __cdecl isatty(int _FileHandle); + int __cdecl locking(int _FileHandle,int _LockMode,long _NumOfBytes); + long __cdecl lseek(int _FileHandle,long _Offset,int _Origin); + char *__cdecl mktemp(char *_TemplateName); + int __cdecl open(const char *_Filename,int _OpenFlag,...); + int __cdecl read(int _FileHandle,void *_DstBuf,unsigned int _MaxCharCount); + int __cdecl setmode(int _FileHandle,int _Mode); + int __cdecl sopen(const char *_Filename,int _OpenFlag,int _ShareFlag,...); + long __cdecl tell(int _FileHandle); + int __cdecl umask(int _Mode); + int __cdecl write(int _Filehandle,const void *_Buf,unsigned int _MaxCharCount); +#endif + +#ifdef __cplusplus +} +#endif +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* Misc stuff */ +char *getlogin(void); +#ifdef __USE_MINGW_ALARM +unsigned int alarm(unsigned int seconds); +#endif + +#ifdef __USE_MINGW_ACCESS +/* Old versions of MSVCRT access() just ignored X_OK, while the version + shipped with Vista, returns an error code. This will restore the + old behaviour */ +static inline int __mingw_access (const char *__fname, int __mode) { + return _access (__fname, __mode & ~X_OK); +} + +#define access(__f,__m) __mingw_access (__f, __m) +#endif + + +#ifdef __cplusplus +} +#endif + + +#pragma pack(pop) + +#include + +#endif /* End _IO_H_ */ + diff --git a/tinyc/win32/include/limits.h b/tinyc/win32/include/limits.h new file mode 100644 index 000000000..fafb04a46 --- /dev/null +++ b/tinyc/win32/include/limits.h @@ -0,0 +1,111 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#include <_mingw.h> + +#ifndef _INC_LIMITS +#define _INC_LIMITS + +/* +* File system limits +* +* TODO: NAME_MAX and OPEN_MAX are file system limits or not? Are they the +* same as FILENAME_MAX and FOPEN_MAX from stdio.h? +* NOTE: Apparently the actual size of PATH_MAX is 260, but a space is +* required for the NUL. TODO: Test? +*/ +#define PATH_MAX (259) + +#define CHAR_BIT 8 +#define SCHAR_MIN (-128) +#define SCHAR_MAX 127 +#define UCHAR_MAX 0xff + +#define CHAR_MIN SCHAR_MIN +#define CHAR_MAX SCHAR_MAX + +#define MB_LEN_MAX 5 +#define SHRT_MIN (-32768) +#define SHRT_MAX 32767 +#define USHRT_MAX 0xffff +#define INT_MIN (-2147483647 - 1) +#define INT_MAX 2147483647 +#define UINT_MAX 0xffffffff +#define LONG_MIN (-2147483647L - 1) +#define LONG_MAX 2147483647L +#define ULONG_MAX 0xffffffffUL +#define LLONG_MAX 9223372036854775807ll +#define LLONG_MIN (-9223372036854775807ll - 1) +#define ULLONG_MAX 0xffffffffffffffffull + +#if _INTEGRAL_MAX_BITS >= 8 +#define _I8_MIN (-127 - 1) +#define _I8_MAX 127i8 +#define _UI8_MAX 0xffu +#endif + +#if _INTEGRAL_MAX_BITS >= 16 +#define _I16_MIN (-32767 - 1) +#define _I16_MAX 32767i16 +#define _UI16_MAX 0xffffu +#endif + +#if _INTEGRAL_MAX_BITS >= 32 +#define _I32_MIN (-2147483647 - 1) +#define _I32_MAX 2147483647 +#define _UI32_MAX 0xffffffffu +#endif + +#if defined(__GNUC__) +#undef LONG_LONG_MAX +#define LONG_LONG_MAX 9223372036854775807ll +#undef LONG_LONG_MIN +#define LONG_LONG_MIN (-LONG_LONG_MAX-1) +#undef ULONG_LONG_MAX +#define ULONG_LONG_MAX (2ull * LONG_LONG_MAX + 1ull) +#endif + +#if _INTEGRAL_MAX_BITS >= 64 +#define _I64_MIN (-9223372036854775807ll - 1) +#define _I64_MAX 9223372036854775807ll +#define _UI64_MAX 0xffffffffffffffffull +#endif + +#ifndef SIZE_MAX +#ifdef _WIN64 +#define SIZE_MAX _UI64_MAX +#else +#define SIZE_MAX UINT_MAX +#endif +#endif + +#ifdef _POSIX_ +#define _POSIX_ARG_MAX 4096 +#define _POSIX_CHILD_MAX 6 +#define _POSIX_LINK_MAX 8 +#define _POSIX_MAX_CANON 255 +#define _POSIX_MAX_INPUT 255 +#define _POSIX_NAME_MAX 14 +#define _POSIX_NGROUPS_MAX 0 +#define _POSIX_OPEN_MAX 16 +#define _POSIX_PATH_MAX 255 +#define _POSIX_PIPE_BUF 512 +#define _POSIX_SSIZE_MAX 32767 +#define _POSIX_STREAM_MAX 8 +#define _POSIX_TZNAME_MAX 3 +#define ARG_MAX 14500 +#define LINK_MAX 1024 +#define MAX_CANON _POSIX_MAX_CANON +#define MAX_INPUT _POSIX_MAX_INPUT +#define NAME_MAX 255 +#define NGROUPS_MAX 16 +#define OPEN_MAX 32 +#define PATH_MAX 512 +#define PIPE_BUF _POSIX_PIPE_BUF +#define SSIZE_MAX _POSIX_SSIZE_MAX +#define STREAM_MAX 20 +#define TZNAME_MAX 10 +#endif +#endif diff --git a/tinyc/win32/include/locale.h b/tinyc/win32/include/locale.h new file mode 100644 index 000000000..686aa9bae --- /dev/null +++ b/tinyc/win32/include/locale.h @@ -0,0 +1,91 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _INC_LOCALE +#define _INC_LOCALE + +#include <_mingw.h> + +#pragma pack(push,_CRT_PACKING) + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef NULL +#ifdef __cplusplus +#define NULL 0 +#else +#define NULL ((void *)0) +#endif +#endif + +#define LC_ALL 0 +#define LC_COLLATE 1 +#define LC_CTYPE 2 +#define LC_MONETARY 3 +#define LC_NUMERIC 4 +#define LC_TIME 5 + +#define LC_MIN LC_ALL +#define LC_MAX LC_TIME + +#ifndef _LCONV_DEFINED +#define _LCONV_DEFINED + struct lconv { + char *decimal_point; + char *thousands_sep; + char *grouping; + char *int_curr_symbol; + char *currency_symbol; + char *mon_decimal_point; + char *mon_thousands_sep; + char *mon_grouping; + char *positive_sign; + char *negative_sign; + char int_frac_digits; + char frac_digits; + char p_cs_precedes; + char p_sep_by_space; + char n_cs_precedes; + char n_sep_by_space; + char p_sign_posn; + char n_sign_posn; + }; +#endif + +#ifndef _CONFIG_LOCALE_SWT +#define _CONFIG_LOCALE_SWT + +#define _ENABLE_PER_THREAD_LOCALE 0x1 +#define _DISABLE_PER_THREAD_LOCALE 0x2 +#define _ENABLE_PER_THREAD_LOCALE_GLOBAL 0x10 +#define _DISABLE_PER_THREAD_LOCALE_GLOBAL 0x20 +#define _ENABLE_PER_THREAD_LOCALE_NEW 0x100 +#define _DISABLE_PER_THREAD_LOCALE_NEW 0x200 + +#endif + + int __cdecl _configthreadlocale(int _Flag); + char *__cdecl setlocale(int _Category,const char *_Locale); + _CRTIMP struct lconv *__cdecl localeconv(void); + _locale_t __cdecl _get_current_locale(void); + _locale_t __cdecl _create_locale(int _Category,const char *_Locale); + void __cdecl _free_locale(_locale_t _Locale); + _locale_t __cdecl __get_current_locale(void); + _locale_t __cdecl __create_locale(int _Category,const char *_Locale); + void __cdecl __free_locale(_locale_t _Locale); + +#ifndef _WLOCALE_DEFINED +#define _WLOCALE_DEFINED + _CRTIMP wchar_t *__cdecl _wsetlocale(int _Category,const wchar_t *_Locale); +#endif + +#ifdef __cplusplus +} +#endif + +#pragma pack(pop) +#endif diff --git a/tinyc/win32/include/malloc.h b/tinyc/win32/include/malloc.h new file mode 100644 index 000000000..fc783a8e3 --- /dev/null +++ b/tinyc/win32/include/malloc.h @@ -0,0 +1,181 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _MALLOC_H_ +#define _MALLOC_H_ + +#include <_mingw.h> + +#pragma pack(push,_CRT_PACKING) + +#ifndef _MM_MALLOC_H_INCLUDED +#define _MM_MALLOC_H_INCLUDED +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef _WIN64 +#define _HEAP_MAXREQ 0xFFFFFFFFFFFFFFE0 +#else +#define _HEAP_MAXREQ 0xFFFFFFE0 +#endif + +#ifndef _STATIC_ASSERT +#define _STATIC_ASSERT(expr) extern void __static_assert_t(int [(expr)?1:-1]) +#endif + +/* Return codes for _heapwalk() */ +#define _HEAPEMPTY (-1) +#define _HEAPOK (-2) +#define _HEAPBADBEGIN (-3) +#define _HEAPBADNODE (-4) +#define _HEAPEND (-5) +#define _HEAPBADPTR (-6) + +/* Values for _heapinfo.useflag */ +#define _FREEENTRY 0 +#define _USEDENTRY 1 + +#ifndef _HEAPINFO_DEFINED +#define _HEAPINFO_DEFINED + /* The structure used to walk through the heap with _heapwalk. */ + typedef struct _heapinfo { + int *_pentry; + size_t _size; + int _useflag; + } _HEAPINFO; +#endif + + extern unsigned int _amblksiz; + +#define _mm_free(a) _aligned_free(a) +#define _mm_malloc(a,b) _aligned_malloc(a,b) + +#ifndef _CRT_ALLOCATION_DEFINED +#define _CRT_ALLOCATION_DEFINED + void *__cdecl calloc(size_t _NumOfElements,size_t _SizeOfElements); + void __cdecl free(void *_Memory); + void *__cdecl malloc(size_t _Size); + void *__cdecl realloc(void *_Memory,size_t _NewSize); + _CRTIMP void *__cdecl _recalloc(void *_Memory,size_t _Count,size_t _Size); + /* _CRTIMP void __cdecl _aligned_free(void *_Memory); + _CRTIMP void *__cdecl _aligned_malloc(size_t _Size,size_t _Alignment); */ + _CRTIMP void *__cdecl _aligned_offset_malloc(size_t _Size,size_t _Alignment,size_t _Offset); + _CRTIMP void *__cdecl _aligned_realloc(void *_Memory,size_t _Size,size_t _Alignment); + _CRTIMP void *__cdecl _aligned_recalloc(void *_Memory,size_t _Count,size_t _Size,size_t _Alignment); + _CRTIMP void *__cdecl _aligned_offset_realloc(void *_Memory,size_t _Size,size_t _Alignment,size_t _Offset); + _CRTIMP void *__cdecl _aligned_offset_recalloc(void *_Memory,size_t _Count,size_t _Size,size_t _Alignment,size_t _Offset); +#endif + +#define _MAX_WAIT_MALLOC_CRT 60000 + + _CRTIMP int __cdecl _resetstkoflw (void); + _CRTIMP unsigned long __cdecl _set_malloc_crt_max_wait(unsigned long _NewValue); + + _CRTIMP void *__cdecl _expand(void *_Memory,size_t _NewSize); + _CRTIMP size_t __cdecl _msize(void *_Memory); +#ifdef __GNUC__ +#undef _alloca +#define _alloca(x) __builtin_alloca((x)) +#else + /* tcc implements alloca internally and exposes it (since commit d778bde7). + /* alloca is declared at include/stddef.h (which is distributed with tcc). + */ +#ifdef _alloca +#undef _alloca +#endif +#define _alloca(x) alloca((x)) +#endif + _CRTIMP size_t __cdecl _get_sbh_threshold(void); + _CRTIMP int __cdecl _set_sbh_threshold(size_t _NewValue); + _CRTIMP errno_t __cdecl _set_amblksiz(size_t _Value); + _CRTIMP errno_t __cdecl _get_amblksiz(size_t *_Value); + _CRTIMP int __cdecl _heapadd(void *_Memory,size_t _Size); + _CRTIMP int __cdecl _heapchk(void); + _CRTIMP int __cdecl _heapmin(void); + _CRTIMP int __cdecl _heapset(unsigned int _Fill); + _CRTIMP int __cdecl _heapwalk(_HEAPINFO *_EntryInfo); + _CRTIMP size_t __cdecl _heapused(size_t *_Used,size_t *_Commit); + _CRTIMP intptr_t __cdecl _get_heap_handle(void); + +#define _ALLOCA_S_THRESHOLD 1024 +#define _ALLOCA_S_STACK_MARKER 0xCCCC +#define _ALLOCA_S_HEAP_MARKER 0xDDDD + +#if(defined(_X86_) && !defined(__x86_64)) +#define _ALLOCA_S_MARKER_SIZE 8 +#elif defined(__ia64__) || defined(__x86_64) +#define _ALLOCA_S_MARKER_SIZE 16 +#endif + +#if !defined(RC_INVOKED) + static __inline void *_MarkAllocaS(void *_Ptr,unsigned int _Marker) { + if(_Ptr) { + *((unsigned int*)_Ptr) = _Marker; + _Ptr = (char*)_Ptr + _ALLOCA_S_MARKER_SIZE; + } + return _Ptr; + } +#endif + +#undef _malloca +#define _malloca(size) \ + ((((size) + _ALLOCA_S_MARKER_SIZE) <= _ALLOCA_S_THRESHOLD) ? \ + _MarkAllocaS(_alloca((size) + _ALLOCA_S_MARKER_SIZE),_ALLOCA_S_STACK_MARKER) : \ + _MarkAllocaS(malloc((size) + _ALLOCA_S_MARKER_SIZE),_ALLOCA_S_HEAP_MARKER)) +#undef _FREEA_INLINE +#define _FREEA_INLINE + +#ifndef RC_INVOKED +#undef _freea + static __inline void __cdecl _freea(void *_Memory) { + unsigned int _Marker; + if(_Memory) { + _Memory = (char*)_Memory - _ALLOCA_S_MARKER_SIZE; + _Marker = *(unsigned int *)_Memory; + if(_Marker==_ALLOCA_S_HEAP_MARKER) { + free(_Memory); + } +#ifdef _ASSERTE + else if(_Marker!=_ALLOCA_S_STACK_MARKER) { + _ASSERTE(("Corrupted pointer passed to _freea",0)); + } +#endif + } + } +#endif /* RC_INVOKED */ + +#ifndef NO_OLDNAMES +#ifdef __GNUC__ +#undef alloca +#define alloca(x) __builtin_alloca((x)) +#endif +#endif + +#ifdef HEAPHOOK +#ifndef _HEAPHOOK_DEFINED +#define _HEAPHOOK_DEFINED + typedef int (__cdecl *_HEAPHOOK)(int,size_t,void *,void **); +#endif + + _CRTIMP _HEAPHOOK __cdecl _setheaphook(_HEAPHOOK _NewHook); + +#define _HEAP_MALLOC 1 +#define _HEAP_CALLOC 2 +#define _HEAP_FREE 3 +#define _HEAP_REALLOC 4 +#define _HEAP_MSIZE 5 +#define _HEAP_EXPAND 6 +#endif + +#ifdef __cplusplus +} +#endif + +#pragma pack(pop) + +#endif /* _MALLOC_H_ */ diff --git a/tinyc/win32/include/math.h b/tinyc/win32/include/math.h new file mode 100644 index 000000000..74add20e9 --- /dev/null +++ b/tinyc/win32/include/math.h @@ -0,0 +1,737 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _MATH_H_ +#define _MATH_H_ + +#if __GNUC__ >= 3 +#pragma GCC system_header +#endif + +#include <_mingw.h> + +struct exception; + +#pragma pack(push,_CRT_PACKING) + +#define _DOMAIN 1 +#define _SING 2 +#define _OVERFLOW 3 +#define _UNDERFLOW 4 +#define _TLOSS 5 +#define _PLOSS 6 + +#ifndef __STRICT_ANSI__ +#ifndef NO_OLDNAMES +#define DOMAIN _DOMAIN +#define SING _SING +#define OVERFLOW _OVERFLOW +#define UNDERFLOW _UNDERFLOW +#define TLOSS _TLOSS +#define PLOSS _PLOSS +#endif +#endif + +#ifndef __STRICT_ANSI__ +#define M_E 2.71828182845904523536 +#define M_LOG2E 1.44269504088896340736 +#define M_LOG10E 0.434294481903251827651 +#define M_LN2 0.693147180559945309417 +#define M_LN10 2.30258509299404568402 +#define M_PI 3.14159265358979323846 +#define M_PI_2 1.57079632679489661923 +#define M_PI_4 0.785398163397448309616 +#define M_1_PI 0.318309886183790671538 +#define M_2_PI 0.636619772367581343076 +#define M_2_SQRTPI 1.12837916709551257390 +#define M_SQRT2 1.41421356237309504880 +#define M_SQRT1_2 0.707106781186547524401 +#endif + +#ifndef __STRICT_ANSI__ +/* See also float.h */ +#ifndef __MINGW_FPCLASS_DEFINED +#define __MINGW_FPCLASS_DEFINED 1 +#define _FPCLASS_SNAN 0x0001 /* Signaling "Not a Number" */ +#define _FPCLASS_QNAN 0x0002 /* Quiet "Not a Number" */ +#define _FPCLASS_NINF 0x0004 /* Negative Infinity */ +#define _FPCLASS_NN 0x0008 /* Negative Normal */ +#define _FPCLASS_ND 0x0010 /* Negative Denormal */ +#define _FPCLASS_NZ 0x0020 /* Negative Zero */ +#define _FPCLASS_PZ 0x0040 /* Positive Zero */ +#define _FPCLASS_PD 0x0080 /* Positive Denormal */ +#define _FPCLASS_PN 0x0100 /* Positive Normal */ +#define _FPCLASS_PINF 0x0200 /* Positive Infinity */ +#endif +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _EXCEPTION_DEFINED +#define _EXCEPTION_DEFINED + struct _exception { + int type; + char *name; + double arg1; + double arg2; + double retval; + }; +#endif + +#ifndef _COMPLEX_DEFINED +#define _COMPLEX_DEFINED + struct _complex { + double x,y; + }; +#endif + +#define EDOM 33 +#define ERANGE 34 + +#ifndef _HUGE +#ifdef _MSVCRT_ + extern double *_HUGE; +#else + extern double *_imp___HUGE; +#define _HUGE (*_imp___HUGE) +#endif +#endif + +#define HUGE_VAL _HUGE + +#ifndef _CRT_ABS_DEFINED +#define _CRT_ABS_DEFINED + int __cdecl abs(int _X); + long __cdecl labs(long _X); +#endif + double __cdecl acos(double _X); + double __cdecl asin(double _X); + double __cdecl atan(double _X); + double __cdecl atan2(double _Y,double _X); +#ifndef _SIGN_DEFINED +#define _SIGN_DEFINED + _CRTIMP double __cdecl _copysign (double _Number,double _Sign); + _CRTIMP double __cdecl _chgsign (double _X); +#endif + double __cdecl cos(double _X); + double __cdecl cosh(double _X); + double __cdecl exp(double _X); + double __cdecl expm1(double _X); + double __cdecl fabs(double _X); + double __cdecl fmod(double _X,double _Y); + double __cdecl log(double _X); + double __cdecl log10(double _X); + double __cdecl pow(double _X,double _Y); + double __cdecl sin(double _X); + double __cdecl sinh(double _X); + double __cdecl tan(double _X); + double __cdecl tanh(double _X); + double __cdecl sqrt(double _X); +#ifndef _CRT_ATOF_DEFINED +#define _CRT_ATOF_DEFINED + double __cdecl atof(const char *_String); + double __cdecl _atof_l(const char *_String,_locale_t _Locale); +#endif + + _CRTIMP double __cdecl _cabs(struct _complex _ComplexA); + double __cdecl ceil(double _X); + double __cdecl floor(double _X); + double __cdecl frexp(double _X,int *_Y); + double __cdecl _hypot(double _X,double _Y); + _CRTIMP double __cdecl _j0(double _X); + _CRTIMP double __cdecl _j1(double _X); + _CRTIMP double __cdecl _jn(int _X,double _Y); + double __cdecl ldexp(double _X,int _Y); +#ifndef _CRT_MATHERR_DEFINED +#define _CRT_MATHERR_DEFINED + int __cdecl _matherr(struct _exception *_Except); +#endif + double __cdecl modf(double _X,double *_Y); + _CRTIMP double __cdecl _y0(double _X); + _CRTIMP double __cdecl _y1(double _X); + _CRTIMP double __cdecl _yn(int _X,double _Y); + +#if(defined(_X86_) && !defined(__x86_64)) + _CRTIMP int __cdecl _set_SSE2_enable(int _Flag); + /* from libmingwex */ + float __cdecl _hypotf(float _X,float _Y); +#endif + + float frexpf(float _X,int *_Y); + float __cdecl ldexpf(float _X,int _Y); + long double __cdecl ldexpl(long double _X,int _Y); + float __cdecl acosf(float _X); + float __cdecl asinf(float _X); + float __cdecl atanf(float _X); + float __cdecl atan2f(float _X,float _Y); + float __cdecl cosf(float _X); + float __cdecl sinf(float _X); + float __cdecl tanf(float _X); + float __cdecl coshf(float _X); + float __cdecl sinhf(float _X); + float __cdecl tanhf(float _X); + float __cdecl expf(float _X); + float __cdecl expm1f(float _X); + float __cdecl logf(float _X); + float __cdecl log10f(float _X); + float __cdecl modff(float _X,float *_Y); + float __cdecl powf(float _X,float _Y); + float __cdecl sqrtf(float _X); + float __cdecl ceilf(float _X); + float __cdecl floorf(float _X); + float __cdecl fmodf(float _X,float _Y); + float __cdecl _hypotf(float _X,float _Y); + float __cdecl fabsf(float _X); +#if !defined(__ia64__) + /* from libmingwex */ + float __cdecl _copysignf (float _Number,float _Sign); + float __cdecl _chgsignf (float _X); + float __cdecl _logbf(float _X); + float __cdecl _nextafterf(float _X,float _Y); + int __cdecl _finitef(float _X); + int __cdecl _isnanf(float _X); + int __cdecl _fpclassf(float _X); +#endif + +#ifndef __cplusplus + __CRT_INLINE long double __cdecl fabsl (long double x) + { + long double res; + __asm__ ("fabs;" : "=t" (res) : "0" (x)); + return res; + } +#define _hypotl(x,y) ((long double)_hypot((double)(x),(double)(y))) +#define _matherrl _matherr + __CRT_INLINE long double _chgsignl(long double _Number) { return _chgsign((double)(_Number)); } + __CRT_INLINE long double _copysignl(long double _Number,long double _Sign) { return _copysign((double)(_Number),(double)(_Sign)); } + __CRT_INLINE float frexpf(float _X,int *_Y) { return ((float)frexp((double)_X,_Y)); } + +#if !defined (__ia64__) + __CRT_INLINE float __cdecl fabsf (float x) + { + float res; + __asm__ ("fabs;" : "=t" (res) : "0" (x)); + return res; + } + + __CRT_INLINE float __cdecl ldexpf (float x, int expn) { return (float) ldexp (x, expn); } +#endif +#else + // cplusplus + __CRT_INLINE long double __cdecl fabsl (long double x) + { + long double res; + __asm__ ("fabs;" : "=t" (res) : "0" (x)); + return res; + } + __CRT_INLINE long double modfl(long double _X,long double *_Y) { + double _Di,_Df = modf((double)_X,&_Di); + *_Y = (long double)_Di; + return (_Df); + } + __CRT_INLINE long double _chgsignl(long double _Number) { return _chgsign(static_cast(_Number)); } + __CRT_INLINE long double _copysignl(long double _Number,long double _Sign) { return _copysign(static_cast(_Number),static_cast(_Sign)); } + __CRT_INLINE float frexpf(float _X,int *_Y) { return ((float)frexp((double)_X,_Y)); } +#ifndef __ia64__ + __CRT_INLINE float __cdecl fabsf (float x) + { + float res; + __asm__ ("fabs;" : "=t" (res) : "0" (x)); + return res; + } + __CRT_INLINE float __cdecl ldexpf (float x, int expn) { return (float) ldexp (x, expn); } +#ifndef __x86_64 + __CRT_INLINE float acosf(float _X) { return ((float)acos((double)_X)); } + __CRT_INLINE float asinf(float _X) { return ((float)asin((double)_X)); } + __CRT_INLINE float atanf(float _X) { return ((float)atan((double)_X)); } + __CRT_INLINE float atan2f(float _X,float _Y) { return ((float)atan2((double)_X,(double)_Y)); } + __CRT_INLINE float ceilf(float _X) { return ((float)ceil((double)_X)); } + __CRT_INLINE float cosf(float _X) { return ((float)cos((double)_X)); } + __CRT_INLINE float coshf(float _X) { return ((float)cosh((double)_X)); } + __CRT_INLINE float expf(float _X) { return ((float)exp((double)_X)); } + __CRT_INLINE float floorf(float _X) { return ((float)floor((double)_X)); } + __CRT_INLINE float fmodf(float _X,float _Y) { return ((float)fmod((double)_X,(double)_Y)); } + __CRT_INLINE float logf(float _X) { return ((float)log((double)_X)); } + __CRT_INLINE float log10f(float _X) { return ((float)log10((double)_X)); } + __CRT_INLINE float modff(float _X,float *_Y) { + double _Di,_Df = modf((double)_X,&_Di); + *_Y = (float)_Di; + return ((float)_Df); + } + __CRT_INLINE float powf(float _X,float _Y) { return ((float)pow((double)_X,(double)_Y)); } + __CRT_INLINE float sinf(float _X) { return ((float)sin((double)_X)); } + __CRT_INLINE float sinhf(float _X) { return ((float)sinh((double)_X)); } + __CRT_INLINE float sqrtf(float _X) { return ((float)sqrt((double)_X)); } + __CRT_INLINE float tanf(float _X) { return ((float)tan((double)_X)); } + __CRT_INLINE float tanhf(float _X) { return ((float)tanh((double)_X)); } +#endif +#endif +#endif + +#ifndef NO_OLDNAMES +#define matherr _matherr + +#define HUGE _HUGE + /* double __cdecl cabs(struct _complex _X); */ + double __cdecl hypot(double _X,double _Y); + _CRTIMP double __cdecl j0(double _X); + _CRTIMP double __cdecl j1(double _X); + _CRTIMP double __cdecl jn(int _X,double _Y); + _CRTIMP double __cdecl y0(double _X); + _CRTIMP double __cdecl y1(double _X); + _CRTIMP double __cdecl yn(int _X,double _Y); +#endif + +#ifndef __NO_ISOCEXT +#if (defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) \ + || !defined __STRICT_ANSI__ || defined __GLIBCPP__ + +#define NAN (0.0F/0.0F) +#define HUGE_VALF (1.0F/0.0F) +#define HUGE_VALL (1.0L/0.0L) +#define INFINITY (1.0F/0.0F) + + +#define FP_NAN 0x0100 +#define FP_NORMAL 0x0400 +#define FP_INFINITE (FP_NAN | FP_NORMAL) +#define FP_ZERO 0x4000 +#define FP_SUBNORMAL (FP_NORMAL | FP_ZERO) + /* 0x0200 is signbit mask */ + + + /* + We can't __CRT_INLINE float or double, because we want to ensure truncation + to semantic type before classification. + (A normal long double value might become subnormal when + converted to double, and zero when converted to float.) + */ + + extern int __cdecl __fpclassifyf (float); + extern int __cdecl __fpclassify (double); + extern int __cdecl __fpclassifyl (long double); + +/* Implemented at tcc/tcc_libm.h */ +#define fpclassify(x) (sizeof (x) == sizeof (float) ? __fpclassifyf (x) \ + : sizeof (x) == sizeof (double) ? __fpclassify (x) \ + : __fpclassifyl (x)) + + /* 7.12.3.2 */ +#define isfinite(x) ((fpclassify(x) & FP_NAN) == 0) + + /* 7.12.3.3 */ +#define isinf(x) (fpclassify(x) == FP_INFINITE) + + /* 7.12.3.4 */ + /* We don't need to worry about truncation here: + A NaN stays a NaN. */ +#define isnan(x) (fpclassify(x) == FP_NAN) + + /* 7.12.3.5 */ +#define isnormal(x) (fpclassify(x) == FP_NORMAL) + + /* 7.12.3.6 The signbit macro */ + + extern int __cdecl __signbitf (float); + extern int __cdecl __signbit (double); + extern int __cdecl __signbitl (long double); + +/* Implemented at tcc/tcc_libm.h */ +#define signbit(x) (sizeof (x) == sizeof (float) ? __signbitf (x) \ + : sizeof (x) == sizeof (double) ? __signbit (x) \ + : __signbitl (x)) + + extern double __cdecl exp2(double); + extern float __cdecl exp2f(float); + extern long double __cdecl exp2l(long double); + +#define FP_ILOGB0 ((int)0x80000000) +#define FP_ILOGBNAN ((int)0x80000000) + extern int __cdecl ilogb (double); + extern int __cdecl ilogbf (float); + extern int __cdecl ilogbl (long double); + + extern double __cdecl log1p(double); + extern float __cdecl log1pf(float); + extern long double __cdecl log1pl(long double); + + extern double __cdecl log2 (double); + extern float __cdecl log2f (float); + extern long double __cdecl log2l (long double); + + extern double __cdecl logb (double); + extern float __cdecl logbf (float); + extern long double __cdecl logbl (long double); + + __CRT_INLINE double __cdecl logb (double x) + { + double res; + __asm__ ("fxtract\n\t" + "fstp %%st" : "=t" (res) : "0" (x)); + return res; + } + + __CRT_INLINE float __cdecl logbf (float x) + { + float res; + __asm__ ("fxtract\n\t" + "fstp %%st" : "=t" (res) : "0" (x)); + return res; + } + + __CRT_INLINE long double __cdecl logbl (long double x) + { + long double res; + __asm__ ("fxtract\n\t" + "fstp %%st" : "=t" (res) : "0" (x)); + return res; + } + + extern long double __cdecl modfl (long double, long double*); + + /* 7.12.6.13 */ + extern double __cdecl scalbn (double, int); + extern float __cdecl scalbnf (float, int); + extern long double __cdecl scalbnl (long double, int); + + extern double __cdecl scalbln (double, long); + extern float __cdecl scalblnf (float, long); + extern long double __cdecl scalblnl (long double, long); + + /* 7.12.7.1 */ + /* Implementations adapted from Cephes versions */ + extern double __cdecl cbrt (double); + extern float __cdecl cbrtf (float); + extern long double __cdecl cbrtl (long double); + + __CRT_INLINE float __cdecl hypotf (float x, float y) + { return (float) hypot (x, y);} + extern long double __cdecl hypotl (long double, long double); + + extern long double __cdecl powl (long double, long double); + extern long double __cdecl expl(long double); + extern long double __cdecl expm1l(long double); + extern long double __cdecl coshl(long double); + extern long double __cdecl fabsl (long double); + extern long double __cdecl acosl(long double); + extern long double __cdecl asinl(long double); + extern long double __cdecl atanl(long double); + extern long double __cdecl atan2l(long double,long double); + extern long double __cdecl sinhl(long double); + extern long double __cdecl tanhl(long double); + + /* 7.12.8.1 The erf functions */ + extern double __cdecl erf (double); + extern float __cdecl erff (float); + /* TODO + extern long double __cdecl erfl (long double); + */ + + /* 7.12.8.2 The erfc functions */ + extern double __cdecl erfc (double); + extern float __cdecl erfcf (float); + /* TODO + extern long double __cdecl erfcl (long double); + */ + + /* 7.12.8.3 The lgamma functions */ + extern double __cdecl lgamma (double); + extern float __cdecl lgammaf (float); + extern long double __cdecl lgammal (long double); + + /* 7.12.8.4 The tgamma functions */ + extern double __cdecl tgamma (double); + extern float __cdecl tgammaf (float); + extern long double __cdecl tgammal (long double); + + extern long double __cdecl ceill (long double); + extern long double __cdecl floorl (long double); + extern long double __cdecl frexpl(long double,int *); + extern long double __cdecl log10l(long double); + extern long double __cdecl logl(long double); + extern long double __cdecl cosl(long double); + extern long double __cdecl sinl(long double); + extern long double __cdecl tanl(long double); + extern long double sqrtl(long double); + + /* 7.12.9.3 */ + extern double __cdecl nearbyint ( double); + extern float __cdecl nearbyintf (float); + extern long double __cdecl nearbyintl (long double); + + /* 7.12.9.4 */ + /* round, using fpu control word settings */ + __CRT_INLINE double __cdecl rint (double x) + { + double retval; + __asm__ ( + "fldl %1\n" + "frndint \n" + "fstl %0\n" : "=m" (retval) : "m" (x)); + return retval; + } + + __CRT_INLINE float __cdecl rintf (float x) + { + float retval; + __asm__ ( + "flds %1\n" + "frndint \n" + "fsts %0\n" : "=m" (retval) : "m" (x)); + return retval; + } + + __CRT_INLINE long double __cdecl rintl (long double x) + { + long double retval; + __asm__ ( + "fldt %1\n" + "frndint \n" + "fstt %0\n" : "=m" (retval) : "m" (x)); + return retval; + } + + /* 7.12.9.5 */ + __CRT_INLINE long __cdecl lrint (double x) + { + long retval; + __asm__ __volatile__ \ + ("fldl %1\n" \ + "fistpl %0" : "=m" (retval) : "m" (x)); \ + return retval; + } + + __CRT_INLINE long __cdecl lrintf (float x) + { + long retval; + __asm__ __volatile__ \ + ("flds %1\n" \ + "fistpl %0" : "=m" (retval) : "m" (x)); \ + return retval; + } + + __CRT_INLINE long __cdecl lrintl (long double x) + { + long retval; + __asm__ __volatile__ \ + ("fldt %1\n" \ + "fistpl %0" : "=m" (retval) : "m" (x)); \ + return retval; + } + + __CRT_INLINE long long __cdecl llrint (double x) + { + long long retval; + __asm__ __volatile__ \ + ("fldl %1\n" \ + "fistpll %0" : "=m" (retval) : "m" (x)); \ + return retval; + } + + __CRT_INLINE long long __cdecl llrintf (float x) + { + long long retval; + __asm__ __volatile__ \ + ("flds %1\n" \ + "fistpll %0" : "=m" (retval) : "m" (x)); \ + return retval; + } + + __CRT_INLINE long long __cdecl llrintl (long double x) + { + long long retval; + __asm__ __volatile__ \ + ("fldt %1\n" \ + "fistpll %0" : "=m" (retval) : "m" (x)); \ + return retval; + } + + #define FE_TONEAREST 0x0000 + #define FE_DOWNWARD 0x0400 + #define FE_UPWARD 0x0800 + #define FE_TOWARDZERO 0x0c00 + + __CRT_INLINE double trunc (double _x) + { + double retval; + unsigned short saved_cw; + unsigned short tmp_cw; + __asm__ ("fnstcw %0;" : "=m" (saved_cw)); /* save FPU control word */ + tmp_cw = (saved_cw & ~(FE_TONEAREST | FE_DOWNWARD | FE_UPWARD | FE_TOWARDZERO)) + | FE_TOWARDZERO; + __asm__ ("fldcw %0;" : : "m" (tmp_cw)); + __asm__ ("fldl %1;" + "frndint;" + "fstl %0;" : "=m" (retval) : "m" (_x)); /* round towards zero */ + __asm__ ("fldcw %0;" : : "m" (saved_cw) ); /* restore saved control word */ + return retval; + } + + /* 7.12.9.6 */ + /* round away from zero, regardless of fpu control word settings */ + extern double __cdecl round (double); + extern float __cdecl roundf (float); + extern long double __cdecl roundl (long double); + + /* 7.12.9.7 */ + extern long __cdecl lround (double); + extern long __cdecl lroundf (float); + extern long __cdecl lroundl (long double); + + extern long long __cdecl llround (double); + extern long long __cdecl llroundf (float); + extern long long __cdecl llroundl (long double); + + /* 7.12.9.8 */ + /* round towards zero, regardless of fpu control word settings */ + extern double __cdecl trunc (double); + extern float __cdecl truncf (float); + extern long double __cdecl truncl (long double); + + extern long double __cdecl fmodl (long double, long double); + + /* 7.12.10.2 */ + extern double __cdecl remainder (double, double); + extern float __cdecl remainderf (float, float); + extern long double __cdecl remainderl (long double, long double); + + /* 7.12.10.3 */ + extern double __cdecl remquo(double, double, int *); + extern float __cdecl remquof(float, float, int *); + extern long double __cdecl remquol(long double, long double, int *); + + /* 7.12.11.1 */ + extern double __cdecl copysign (double, double); /* in libmoldname.a */ + extern float __cdecl copysignf (float, float); + extern long double __cdecl copysignl (long double, long double); + + /* 7.12.11.2 Return a NaN */ + extern double __cdecl nan(const char *tagp); + extern float __cdecl nanf(const char *tagp); + extern long double __cdecl nanl(const char *tagp); + +#ifndef __STRICT_ANSI__ +#define _nan() nan("") +#define _nanf() nanf("") +#define _nanl() nanl("") +#endif + + /* 7.12.11.3 */ + extern double __cdecl nextafter (double, double); /* in libmoldname.a */ + extern float __cdecl nextafterf (float, float); + extern long double __cdecl nextafterl (long double, long double); + + /* 7.12.11.4 The nexttoward functions: TODO */ + + /* 7.12.12.1 */ + /* x > y ? (x - y) : 0.0 */ + extern double __cdecl fdim (double x, double y); + extern float __cdecl fdimf (float x, float y); + extern long double __cdecl fdiml (long double x, long double y); + + /* fmax and fmin. + NaN arguments are treated as missing data: if one argument is a NaN + and the other numeric, then these functions choose the numeric + value. */ + + /* 7.12.12.2 */ + extern double __cdecl fmax (double, double); + extern float __cdecl fmaxf (float, float); + extern long double __cdecl fmaxl (long double, long double); + + /* 7.12.12.3 */ + extern double __cdecl fmin (double, double); + extern float __cdecl fminf (float, float); + extern long double __cdecl fminl (long double, long double); + + /* 7.12.13.1 */ + /* return x * y + z as a ternary op */ + extern double __cdecl fma (double, double, double); + extern float __cdecl fmaf (float, float, float); + extern long double __cdecl fmal (long double, long double, long double); + + +#if 0 // gr: duplicate, see below + /* 7.12.14 */ + /* + * With these functions, comparisons involving quiet NaNs set the FP + * condition code to "unordered". The IEEE floating-point spec + * dictates that the result of floating-point comparisons should be + * false whenever a NaN is involved, with the exception of the != op, + * which always returns true: yes, (NaN != NaN) is true). + */ + +#if __GNUC__ >= 3 + +#define isgreater(x, y) __builtin_isgreater(x, y) +#define isgreaterequal(x, y) __builtin_isgreaterequal(x, y) +#define isless(x, y) __builtin_isless(x, y) +#define islessequal(x, y) __builtin_islessequal(x, y) +#define islessgreater(x, y) __builtin_islessgreater(x, y) +#define isunordered(x, y) __builtin_isunordered(x, y) + +#else + /* helper */ + __CRT_INLINE int __cdecl + __fp_unordered_compare (long double x, long double y){ + unsigned short retval; + __asm__ ("fucom %%st(1);" + "fnstsw;": "=a" (retval) : "t" (x), "u" (y)); + return retval; + } + +#define isgreater(x, y) ((__fp_unordered_compare(x, y) \ + & 0x4500) == 0) +#define isless(x, y) ((__fp_unordered_compare (y, x) \ + & 0x4500) == 0) +#define isgreaterequal(x, y) ((__fp_unordered_compare (x, y) \ + & FP_INFINITE) == 0) +#define islessequal(x, y) ((__fp_unordered_compare(y, x) \ + & FP_INFINITE) == 0) +#define islessgreater(x, y) ((__fp_unordered_compare(x, y) \ + & FP_SUBNORMAL) == 0) +#define isunordered(x, y) ((__fp_unordered_compare(x, y) \ + & 0x4500) == 0x4500) + +#endif +#endif //0 + + +#endif /* __STDC_VERSION__ >= 199901L */ +#endif /* __NO_ISOCEXT */ + +#ifdef __cplusplus +} +extern "C++" { + template inline _Ty _Pow_int(_Ty _X,int _Y) { + unsigned int _N; + if(_Y >= 0) _N = (unsigned int)_Y; + else _N = (unsigned int)(-_Y); + for(_Ty _Z = _Ty(1);;_X *= _X) { + if((_N & 1)!=0) _Z *= _X; + if((_N >>= 1)==0) return (_Y < 0 ? _Ty(1) / _Z : _Z); + } + } +} +#endif + +#pragma pack(pop) + +/* 7.12.14 */ +/* + * With these functions, comparisons involving quiet NaNs set the FP + * condition code to "unordered". The IEEE floating-point spec + * dictates that the result of floating-point comparisons should be + * false whenever a NaN is involved, with the exception of the != op, + * which always returns true: yes, (NaN != NaN) is true). + */ + +/* Mini libm (inline __fpclassify*, __signbit* and variants) */ +#include "tcc/tcc_libm.h" + +#endif /* End _MATH_H_ */ + diff --git a/tinyc/win32/include/mem.h b/tinyc/win32/include/mem.h new file mode 100644 index 000000000..255202359 --- /dev/null +++ b/tinyc/win32/include/mem.h @@ -0,0 +1,13 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +/* + * This file is part of the Mingw32 package. + * + * mem.h maps to string.h + */ +#ifndef __STRICT_ANSI__ +#include +#endif diff --git a/tinyc/win32/include/memory.h b/tinyc/win32/include/memory.h new file mode 100644 index 000000000..90d88aedd --- /dev/null +++ b/tinyc/win32/include/memory.h @@ -0,0 +1,40 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _INC_MEMORY +#define _INC_MEMORY + +#include <_mingw.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _CONST_RETURN +#define _CONST_RETURN +#endif + +#define _WConst_return _CONST_RETURN + +#ifndef _CRT_MEMORY_DEFINED +#define _CRT_MEMORY_DEFINED + _CRTIMP void *__cdecl _memccpy(void *_Dst,const void *_Src,int _Val,size_t _MaxCount); + _CONST_RETURN void *__cdecl memchr(const void *_Buf ,int _Val,size_t _MaxCount); + _CRTIMP int __cdecl _memicmp(const void *_Buf1,const void *_Buf2,size_t _Size); + _CRTIMP int __cdecl _memicmp_l(const void *_Buf1,const void *_Buf2,size_t _Size,_locale_t _Locale); + int __cdecl memcmp(const void *_Buf1,const void *_Buf2,size_t _Size); + void *__cdecl memcpy(void *_Dst,const void *_Src,size_t _Size); + void *__cdecl memset(void *_Dst,int _Val,size_t _Size); + +#ifndef NO_OLDNAMES + void *__cdecl memccpy(void *_Dst,const void *_Src,int _Val,size_t _Size); + int __cdecl memicmp(const void *_Buf1,const void *_Buf2,size_t _Size); +#endif +#endif + +#ifdef __cplusplus +} +#endif +#endif diff --git a/tinyc/win32/include/process.h b/tinyc/win32/include/process.h new file mode 100644 index 000000000..dadaf2b7d --- /dev/null +++ b/tinyc/win32/include/process.h @@ -0,0 +1,176 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _INC_PROCESS +#define _INC_PROCESS + +#include <_mingw.h> + +/* Includes a definition of _pid_t and pid_t */ +#include + +#ifndef _POSIX_ +#ifdef __cplusplus +extern "C" { +#endif + +#define _P_WAIT 0 +#define _P_NOWAIT 1 +#define _OLD_P_OVERLAY 2 +#define _P_NOWAITO 3 +#define _P_DETACH 4 +#define _P_OVERLAY 2 + +#define _WAIT_CHILD 0 +#define _WAIT_GRANDCHILD 1 + + _CRTIMP uintptr_t __cdecl _beginthread(void (__cdecl *_StartAddress) (void *),unsigned _StackSize,void *_ArgList); + _CRTIMP void __cdecl _endthread(void); + _CRTIMP uintptr_t __cdecl _beginthreadex(void *_Security,unsigned _StackSize,unsigned (__stdcall *_StartAddress) (void *),void *_ArgList,unsigned _InitFlag,unsigned *_ThrdAddr); + _CRTIMP void __cdecl _endthreadex(unsigned _Retval); + +#ifndef _CRT_TERMINATE_DEFINED +#define _CRT_TERMINATE_DEFINED + void __cdecl __MINGW_NOTHROW exit(int _Code) __MINGW_ATTRIB_NORETURN; + _CRTIMP void __cdecl __MINGW_NOTHROW _exit(int _Code) __MINGW_ATTRIB_NORETURN; + +#pragma push_macro("abort") +#undef abort + void __cdecl __declspec(noreturn) abort(void); +#pragma pop_macro("abort") + +#endif + + _CRTIMP void __cdecl __MINGW_NOTHROW _cexit(void); + _CRTIMP void __cdecl __MINGW_NOTHROW _c_exit(void); + _CRTIMP int __cdecl _getpid(void); + _CRTIMP intptr_t __cdecl _cwait(int *_TermStat,intptr_t _ProcHandle,int _Action); + _CRTIMP intptr_t __cdecl _execl(const char *_Filename,const char *_ArgList,...); + _CRTIMP intptr_t __cdecl _execle(const char *_Filename,const char *_ArgList,...); + _CRTIMP intptr_t __cdecl _execlp(const char *_Filename,const char *_ArgList,...); + _CRTIMP intptr_t __cdecl _execlpe(const char *_Filename,const char *_ArgList,...); + _CRTIMP intptr_t __cdecl _execv(const char *_Filename,const char *const *_ArgList); + _CRTIMP intptr_t __cdecl _execve(const char *_Filename,const char *const *_ArgList,const char *const *_Env); + _CRTIMP intptr_t __cdecl _execvp(const char *_Filename,const char *const *_ArgList); + _CRTIMP intptr_t __cdecl _execvpe(const char *_Filename,const char *const *_ArgList,const char *const *_Env); + _CRTIMP intptr_t __cdecl _spawnl(int _Mode,const char *_Filename,const char *_ArgList,...); + _CRTIMP intptr_t __cdecl _spawnle(int _Mode,const char *_Filename,const char *_ArgList,...); + _CRTIMP intptr_t __cdecl _spawnlp(int _Mode,const char *_Filename,const char *_ArgList,...); + _CRTIMP intptr_t __cdecl _spawnlpe(int _Mode,const char *_Filename,const char *_ArgList,...); + _CRTIMP intptr_t __cdecl _spawnv(int _Mode,const char *_Filename,const char *const *_ArgList); + _CRTIMP intptr_t __cdecl _spawnve(int _Mode,const char *_Filename,const char *const *_ArgList,const char *const *_Env); + _CRTIMP intptr_t __cdecl _spawnvp(int _Mode,const char *_Filename,const char *const *_ArgList); + _CRTIMP intptr_t __cdecl _spawnvpe(int _Mode,const char *_Filename,const char *const *_ArgList,const char *const *_Env); + +#ifndef _CRT_SYSTEM_DEFINED +#define _CRT_SYSTEM_DEFINED + int __cdecl system(const char *_Command); +#endif + +#ifndef _WPROCESS_DEFINED +#define _WPROCESS_DEFINED + _CRTIMP intptr_t __cdecl _wexecl(const wchar_t *_Filename,const wchar_t *_ArgList,...); + _CRTIMP intptr_t __cdecl _wexecle(const wchar_t *_Filename,const wchar_t *_ArgList,...); + _CRTIMP intptr_t __cdecl _wexeclp(const wchar_t *_Filename,const wchar_t *_ArgList,...); + _CRTIMP intptr_t __cdecl _wexeclpe(const wchar_t *_Filename,const wchar_t *_ArgList,...); + _CRTIMP intptr_t __cdecl _wexecv(const wchar_t *_Filename,const wchar_t *const *_ArgList); + _CRTIMP intptr_t __cdecl _wexecve(const wchar_t *_Filename,const wchar_t *const *_ArgList,const wchar_t *const *_Env); + _CRTIMP intptr_t __cdecl _wexecvp(const wchar_t *_Filename,const wchar_t *const *_ArgList); + _CRTIMP intptr_t __cdecl _wexecvpe(const wchar_t *_Filename,const wchar_t *const *_ArgList,const wchar_t *const *_Env); + _CRTIMP intptr_t __cdecl _wspawnl(int _Mode,const wchar_t *_Filename,const wchar_t *_ArgList,...); + _CRTIMP intptr_t __cdecl _wspawnle(int _Mode,const wchar_t *_Filename,const wchar_t *_ArgList,...); + _CRTIMP intptr_t __cdecl _wspawnlp(int _Mode,const wchar_t *_Filename,const wchar_t *_ArgList,...); + _CRTIMP intptr_t __cdecl _wspawnlpe(int _Mode,const wchar_t *_Filename,const wchar_t *_ArgList,...); + _CRTIMP intptr_t __cdecl _wspawnv(int _Mode,const wchar_t *_Filename,const wchar_t *const *_ArgList); + _CRTIMP intptr_t __cdecl _wspawnve(int _Mode,const wchar_t *_Filename,const wchar_t *const *_ArgList,const wchar_t *const *_Env); + _CRTIMP intptr_t __cdecl _wspawnvp(int _Mode,const wchar_t *_Filename,const wchar_t *const *_ArgList); + _CRTIMP intptr_t __cdecl _wspawnvpe(int _Mode,const wchar_t *_Filename,const wchar_t *const *_ArgList,const wchar_t *const *_Env); +#ifndef _CRT_WSYSTEM_DEFINED +#define _CRT_WSYSTEM_DEFINED + _CRTIMP int __cdecl _wsystem(const wchar_t *_Command); +#endif +#endif + + void __cdecl __security_init_cookie(void); +#if (defined(_X86_) && !defined(__x86_64)) + void __fastcall __security_check_cookie(uintptr_t _StackCookie); + __declspec(noreturn) void __cdecl __report_gsfailure(void); +#else + void __cdecl __security_check_cookie(uintptr_t _StackCookie); + __declspec(noreturn) void __cdecl __report_gsfailure(uintptr_t _StackCookie); +#endif + extern uintptr_t __security_cookie; + + intptr_t __cdecl _loaddll(char *_Filename); + int __cdecl _unloaddll(intptr_t _Handle); + int (__cdecl *__cdecl _getdllprocaddr(intptr_t _Handle,char *_ProcedureName,intptr_t _Ordinal))(void); + +#ifdef _DECL_DLLMAIN +#ifdef _WINDOWS_ + WINBOOL WINAPI DllMain(HANDLE _HDllHandle,DWORD _Reason,LPVOID _Reserved); + WINBOOL WINAPI _CRT_INIT(HANDLE _HDllHandle,DWORD _Reason,LPVOID _Reserved); + WINBOOL WINAPI _wCRT_INIT(HANDLE _HDllHandle,DWORD _Reason,LPVOID _Reserved); + extern WINBOOL (WINAPI *const _pRawDllMain)(HANDLE,DWORD,LPVOID); +#else + int __stdcall DllMain(void *_HDllHandle,unsigned _Reason,void *_Reserved); + int __stdcall _CRT_INIT(void *_HDllHandle,unsigned _Reason,void *_Reserved); + int __stdcall _wCRT_INIT(void *_HDllHandle,unsigned _Reason,void *_Reserved); + extern int (__stdcall *const _pRawDllMain)(void *,unsigned,void *); +#endif +#endif + +#ifndef NO_OLDNAMES +#define P_WAIT _P_WAIT +#define P_NOWAIT _P_NOWAIT +#define P_OVERLAY _P_OVERLAY +#define OLD_P_OVERLAY _OLD_P_OVERLAY +#define P_NOWAITO _P_NOWAITO +#define P_DETACH _P_DETACH +#define WAIT_CHILD _WAIT_CHILD +#define WAIT_GRANDCHILD _WAIT_GRANDCHILD + + intptr_t __cdecl cwait(int *_TermStat,intptr_t _ProcHandle,int _Action); +#ifdef __GNUC__ + int __cdecl execl(const char *_Filename,const char *_ArgList,...); + int __cdecl execle(const char *_Filename,const char *_ArgList,...); + int __cdecl execlp(const char *_Filename,const char *_ArgList,...); + int __cdecl execlpe(const char *_Filename,const char *_ArgList,...); +#else + intptr_t __cdecl execl(const char *_Filename,const char *_ArgList,...); + intptr_t __cdecl execle(const char *_Filename,const char *_ArgList,...); + intptr_t __cdecl execlp(const char *_Filename,const char *_ArgList,...); + intptr_t __cdecl execlpe(const char *_Filename,const char *_ArgList,...); +#endif + intptr_t __cdecl spawnl(int,const char *_Filename,const char *_ArgList,...); + intptr_t __cdecl spawnle(int,const char *_Filename,const char *_ArgList,...); + intptr_t __cdecl spawnlp(int,const char *_Filename,const char *_ArgList,...); + intptr_t __cdecl spawnlpe(int,const char *_Filename,const char *_ArgList,...); + int __cdecl getpid(void); +#ifdef __GNUC__ + /* Those methods are predefined by gcc builtins to return int. So to prevent + stupid warnings, define them in POSIX way. This is save, because those + methods do not return in success case, so that the return value is not + really dependent to its scalar width. */ + int __cdecl execv(const char *_Filename,const char *const _ArgList[]); + int __cdecl execve(const char *_Filename,const char *const _ArgList[],const char *const _Env[]); + int __cdecl execvp(const char *_Filename,const char *const _ArgList[]); + int __cdecl execvpe(const char *_Filename,const char *const _ArgList[],const char *const _Env[]); +#else + intptr_t __cdecl execv(const char *_Filename,const char *const _ArgList[]); + intptr_t __cdecl execve(const char *_Filename,const char *const _ArgList[],const char *const _Env[]); + intptr_t __cdecl execvp(const char *_Filename,const char *const _ArgList[]); + intptr_t __cdecl execvpe(const char *_Filename,const char *const _ArgList[],const char *const _Env[]); +#endif + intptr_t __cdecl spawnv(int,const char *_Filename,const char *const _ArgList[]); + intptr_t __cdecl spawnve(int,const char *_Filename,const char *const _ArgList[],const char *const _Env[]); + intptr_t __cdecl spawnvp(int,const char *_Filename,const char *const _ArgList[]); + intptr_t __cdecl spawnvpe(int,const char *_Filename,const char *const _ArgList[],char *const _Env[]); +#endif + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/tinyc/win32/include/sec_api/conio_s.h b/tinyc/win32/include/sec_api/conio_s.h new file mode 100644 index 000000000..98d97ba2e --- /dev/null +++ b/tinyc/win32/include/sec_api/conio_s.h @@ -0,0 +1,42 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ + +#ifndef _INC_CONIO_S +#define _INC_CONIO_S + +#include + +#if defined(MINGW_HAS_SECURE_API) + +#ifdef __cplusplus +extern "C" { +#endif + + _CRTIMP errno_t __cdecl _cgets_s(char *_Buffer,size_t _Size,size_t *_SizeRead); + _CRTIMP int __cdecl _cprintf_s(const char *_Format,...); + _CRTIMP int __cdecl _cscanf_s(const char *_Format,...); + _CRTIMP int __cdecl _cscanf_s_l(const char *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vcprintf_s(const char *_Format,va_list _ArgList); + _CRTIMP int __cdecl _cprintf_s_l(const char *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vcprintf_s_l(const char *_Format,_locale_t _Locale,va_list _ArgList); + +#ifndef _WCONIO_DEFINED_S +#define _WCONIO_DEFINED_S + _CRTIMP errno_t __cdecl _cgetws_s(wchar_t *_Buffer,size_t _SizeInWords,size_t *_SizeRead); + _CRTIMP int __cdecl _cwprintf_s(const wchar_t *_Format,...); + _CRTIMP int __cdecl _cwscanf_s(const wchar_t *_Format,...); + _CRTIMP int __cdecl _cwscanf_s_l(const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vcwprintf_s(const wchar_t *_Format,va_list _ArgList); + _CRTIMP int __cdecl _cwprintf_s_l(const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vcwprintf_s_l(const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); +#endif + +#ifdef __cplusplus +} +#endif + +#endif +#endif diff --git a/tinyc/win32/include/sec_api/crtdbg_s.h b/tinyc/win32/include/sec_api/crtdbg_s.h new file mode 100644 index 000000000..4598b4f7c --- /dev/null +++ b/tinyc/win32/include/sec_api/crtdbg_s.h @@ -0,0 +1,19 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ + +#ifndef _INC_CRTDBG_S +#define _INC_CRTDBG_S + +#include + +#if defined(MINGW_HAS_SECURE_API) + +#define _dupenv_s_dbg(ps1,size,s2,t,f,l) _dupenv_s(ps1,size,s2) +#define _wdupenv_s_dbg(ps1,size,s2,t,f,l) _wdupenv_s(ps1,size,s2) + +#endif + +#endif diff --git a/tinyc/win32/include/sec_api/io_s.h b/tinyc/win32/include/sec_api/io_s.h new file mode 100644 index 000000000..ec565a617 --- /dev/null +++ b/tinyc/win32/include/sec_api/io_s.h @@ -0,0 +1,33 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _INC_IO_S +#define _INC_IO_S + +#include + +#if defined(MINGW_HAS_SECURE_API) + +#ifdef __cplusplus +extern "C" { +#endif + + _CRTIMP errno_t __cdecl _access_s(const char *_Filename,int _AccessMode); + _CRTIMP errno_t __cdecl _chsize_s(int _FileHandle,__int64 _Size); + _CRTIMP errno_t __cdecl _mktemp_s(char *_TemplateName,size_t _Size); + _CRTIMP errno_t __cdecl _umask_s(int _NewMode,int *_OldMode); + +#ifndef _WIO_S_DEFINED +#define _WIO_S_DEFINED + _CRTIMP errno_t __cdecl _waccess_s(const wchar_t *_Filename,int _AccessMode); + _CRTIMP errno_t __cdecl _wmktemp_s(wchar_t *_TemplateName,size_t _SizeInWords); +#endif + +#ifdef __cplusplus +} +#endif + +#endif +#endif diff --git a/tinyc/win32/include/sec_api/mbstring_s.h b/tinyc/win32/include/sec_api/mbstring_s.h new file mode 100644 index 000000000..6b2b188f8 --- /dev/null +++ b/tinyc/win32/include/sec_api/mbstring_s.h @@ -0,0 +1,52 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _INC_MBSTRING_S +#define _INC_MBSTRING_S + +#include + +#if defined(MINGW_HAS_SECURE_API) + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _MBSTRING_S_DEFINED +#define _MBSTRING_S_DEFINED + _CRTIMP errno_t __cdecl _mbscat_s(unsigned char *_Dst,size_t _DstSizeInBytes,const unsigned char *_Src); + _CRTIMP errno_t __cdecl _mbscat_s_l(unsigned char *_Dst,size_t _DstSizeInBytes,const unsigned char *_Src,_locale_t _Locale); + _CRTIMP errno_t __cdecl _mbscpy_s(unsigned char *_Dst,size_t _DstSizeInBytes,const unsigned char *_Src); + _CRTIMP errno_t __cdecl _mbscpy_s_l(unsigned char *_Dst,size_t _DstSizeInBytes,const unsigned char *_Src,_locale_t _Locale); + _CRTIMP errno_t __cdecl _mbslwr_s(unsigned char *_Str,size_t _SizeInBytes); + _CRTIMP errno_t __cdecl _mbslwr_s_l(unsigned char *_Str,size_t _SizeInBytes,_locale_t _Locale); + _CRTIMP errno_t __cdecl _mbsnbcat_s(unsigned char *_Dst,size_t _DstSizeInBytes,const unsigned char *_Src,size_t _MaxCount); + _CRTIMP errno_t __cdecl _mbsnbcat_s_l(unsigned char *_Dst,size_t _DstSizeInBytes,const unsigned char *_Src,size_t _MaxCount,_locale_t _Locale); + _CRTIMP errno_t __cdecl _mbsnbcpy_s(unsigned char *_Dst,size_t _DstSizeInBytes,const unsigned char *_Src,size_t _MaxCount); + _CRTIMP errno_t __cdecl _mbsnbcpy_s_l(unsigned char *_Dst,size_t _DstSizeInBytes,const unsigned char *_Src,size_t _MaxCount,_locale_t _Locale); + _CRTIMP errno_t __cdecl _mbsnbset_s(unsigned char *_Dst,size_t _DstSizeInBytes,unsigned int _Ch,size_t _MaxCount); + _CRTIMP errno_t __cdecl _mbsnbset_s_l(unsigned char *_Dst,size_t _DstSizeInBytes,unsigned int _Ch,size_t _MaxCount,_locale_t _Locale); + _CRTIMP errno_t __cdecl _mbsncat_s(unsigned char *_Dst,size_t _DstSizeInBytes,const unsigned char *_Src,size_t _MaxCount); + _CRTIMP errno_t __cdecl _mbsncat_s_l(unsigned char *_Dst,size_t _DstSizeInBytes,const unsigned char *_Src,size_t _MaxCount,_locale_t _Locale); + _CRTIMP errno_t __cdecl _mbsncpy_s(unsigned char *_Dst,size_t _DstSizeInBytes,const unsigned char *_Src,size_t _MaxCount); + _CRTIMP errno_t __cdecl _mbsncpy_s_l(unsigned char *_Dst,size_t _DstSizeInBytes,const unsigned char *_Src,size_t _MaxCount,_locale_t _Locale); + _CRTIMP errno_t __cdecl _mbsnset_s(unsigned char *_Dst,size_t _DstSizeInBytes,unsigned int _Val,size_t _MaxCount); + _CRTIMP errno_t __cdecl _mbsnset_s_l(unsigned char *_Dst,size_t _DstSizeInBytes,unsigned int _Val,size_t _MaxCount,_locale_t _Locale); + _CRTIMP errno_t __cdecl _mbsset_s(unsigned char *_Dst,size_t _DstSizeInBytes,unsigned int _Val); + _CRTIMP errno_t __cdecl _mbsset_s_l(unsigned char *_Dst,size_t _DstSizeInBytes,unsigned int _Val,_locale_t _Locale); + _CRTIMP unsigned char *__cdecl _mbstok_s(unsigned char *_Str,const unsigned char *_Delim,unsigned char **_Context); + _CRTIMP unsigned char *__cdecl _mbstok_s_l(unsigned char *_Str,const unsigned char *_Delim,unsigned char **_Context,_locale_t _Locale); + _CRTIMP errno_t __cdecl _mbsupr_s(unsigned char *_Str,size_t _SizeInBytes); + _CRTIMP errno_t __cdecl _mbsupr_s_l(unsigned char *_Str,size_t _SizeInBytes,_locale_t _Locale); + _CRTIMP errno_t __cdecl _mbccpy_s(unsigned char *_Dst,size_t _DstSizeInBytes,int *_PCopied,const unsigned char *_Src); + _CRTIMP errno_t __cdecl _mbccpy_s_l(unsigned char *_Dst,size_t _DstSizeInBytes,int *_PCopied,const unsigned char *_Src,_locale_t _Locale); +#endif + +#ifdef __cplusplus +} +#endif + +#endif +#endif diff --git a/tinyc/win32/include/sec_api/search_s.h b/tinyc/win32/include/sec_api/search_s.h new file mode 100644 index 000000000..cae899898 --- /dev/null +++ b/tinyc/win32/include/sec_api/search_s.h @@ -0,0 +1,25 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _INC_SEARCH_S +#define _INC_SEARCH_S + +#include + +#if defined(MINGW_HAS_SECURE_API) + +#ifdef __cplusplus +extern "C" { +#endif + + _CRTIMP void *__cdecl _lfind_s(const void *_Key,const void *_Base,unsigned int *_NumOfElements,size_t _SizeOfElements,int (__cdecl *_PtFuncCompare)(void *,const void *,const void *),void *_Context); + _CRTIMP void *__cdecl _lsearch_s(const void *_Key,void *_Base,unsigned int *_NumOfElements,size_t _SizeOfElements,int (__cdecl *_PtFuncCompare)(void *,const void *,const void *),void *_Context); + +#ifdef __cplusplus +} +#endif + +#endif +#endif diff --git a/tinyc/win32/include/sec_api/stdio_s.h b/tinyc/win32/include/sec_api/stdio_s.h new file mode 100644 index 000000000..c9b803b12 --- /dev/null +++ b/tinyc/win32/include/sec_api/stdio_s.h @@ -0,0 +1,145 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _INC_STDIO_S +#define _INC_STDIO_S + +#include + +#if defined(MINGW_HAS_SECURE_API) + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _STDIO_S_DEFINED +#define _STDIO_S_DEFINED + _CRTIMP errno_t __cdecl clearerr_s(FILE *_File); + int __cdecl fprintf_s(FILE *_File,const char *_Format,...); + size_t __cdecl fread_s(void *_DstBuf,size_t _DstSize,size_t _ElementSize,size_t _Count,FILE *_File); + _CRTIMP int __cdecl _fscanf_s_l(FILE *_File,const char *_Format,_locale_t _Locale,...); + int __cdecl printf_s(const char *_Format,...); + _CRTIMP int __cdecl _scanf_l(const char *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _scanf_s_l(const char *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _snprintf_s(char *_DstBuf,size_t _DstSize,size_t _MaxCount,const char *_Format,...); + _CRTIMP int __cdecl _snprintf_c(char *_DstBuf,size_t _MaxCount,const char *_Format,...); + _CRTIMP int __cdecl _vsnprintf_c(char *_DstBuf,size_t _MaxCount,const char *_Format,va_list _ArgList); + int __cdecl sprintf_s(char *_DstBuf,size_t _DstSize,const char *_Format,...); + _CRTIMP int __cdecl _fscanf_l(FILE *_File,const char *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _sscanf_l(const char *_Src,const char *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _sscanf_s_l(const char *_Src,const char *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _snscanf_s(const char *_Src,size_t _MaxCount,const char *_Format,...); + _CRTIMP int __cdecl _snscanf_l(const char *_Src,size_t _MaxCount,const char *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _snscanf_s_l(const char *_Src,size_t _MaxCount,const char *_Format,_locale_t _Locale,...); + int __cdecl vfprintf_s(FILE *_File,const char *_Format,va_list _ArgList); + int __cdecl vprintf_s(const char *_Format,va_list _ArgList); + int __cdecl vsnprintf_s(char *_DstBuf,size_t _DstSize,size_t _MaxCount,const char *_Format,va_list _ArgList); + _CRTIMP int __cdecl _vsnprintf_s(char *_DstBuf,size_t _DstSize,size_t _MaxCount,const char *_Format,va_list _ArgList); + int __cdecl vsprintf_s(char *_DstBuf,size_t _Size,const char *_Format,va_list _ArgList); + _CRTIMP int __cdecl _fprintf_p(FILE *_File,const char *_Format,...); + _CRTIMP int __cdecl _printf_p(const char *_Format,...); + _CRTIMP int __cdecl _sprintf_p(char *_Dst,size_t _MaxCount,const char *_Format,...); + _CRTIMP int __cdecl _vfprintf_p(FILE *_File,const char *_Format,va_list _ArgList); + _CRTIMP int __cdecl _vprintf_p(const char *_Format,va_list _ArgList); + _CRTIMP int __cdecl _vsprintf_p(char *_Dst,size_t _MaxCount,const char *_Format,va_list _ArgList); + _CRTIMP int __cdecl _scprintf_p(const char *_Format,...); + _CRTIMP int __cdecl _vscprintf_p(const char *_Format,va_list _ArgList); + _CRTIMP int __cdecl _printf_l(const char *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _printf_p_l(const char *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vprintf_l(const char *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _vprintf_p_l(const char *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _fprintf_l(FILE *_File,const char *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _fprintf_p_l(FILE *_File,const char *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vfprintf_l(FILE *_File,const char *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _vfprintf_p_l(FILE *_File,const char *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _sprintf_l(char *_DstBuf,const char *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _sprintf_p_l(char *_DstBuf,size_t _MaxCount,const char *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vsprintf_l(char *_DstBuf,const char *_Format,_locale_t,va_list _ArgList); + _CRTIMP int __cdecl _vsprintf_p_l(char *_DstBuf,size_t _MaxCount,const char *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _scprintf_l(const char *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _scprintf_p_l(const char *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vscprintf_l(const char *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _vscprintf_p_l(const char *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _printf_s_l(const char *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vprintf_s_l(const char *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _fprintf_s_l(FILE *_File,const char *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vfprintf_s_l(FILE *_File,const char *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _sprintf_s_l(char *_DstBuf,size_t _DstSize,const char *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vsprintf_s_l(char *_DstBuf,size_t _DstSize,const char *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _snprintf_s_l(char *_DstBuf,size_t _DstSize,size_t _MaxCount,const char *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vsnprintf_s_l(char *_DstBuf,size_t _DstSize,size_t _MaxCount,const char *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _snprintf_l(char *_DstBuf,size_t _MaxCount,const char *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _snprintf_c_l(char *_DstBuf,size_t _MaxCount,const char *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vsnprintf_l(char *_DstBuf,size_t _MaxCount,const char *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _vsnprintf_c_l(char *_DstBuf,size_t _MaxCount,const char *,_locale_t _Locale,va_list _ArgList); + +#ifndef _WSTDIO_S_DEFINED +#define _WSTDIO_S_DEFINED + _CRTIMP wchar_t *__cdecl _getws_s(wchar_t *_Str,size_t _SizeInWords); + int __cdecl fwprintf_s(FILE *_File,const wchar_t *_Format,...); + int __cdecl wprintf_s(const wchar_t *_Format,...); + int __cdecl vwprintf_s(const wchar_t *_Format,va_list _ArgList); + int __cdecl swprintf_s(wchar_t *_Dst,size_t _SizeInWords,const wchar_t *_Format,...); + int __cdecl vswprintf_s(wchar_t *_Dst,size_t _SizeInWords,const wchar_t *_Format,va_list _ArgList); + _CRTIMP int __cdecl _snwprintf_s(wchar_t *_DstBuf,size_t _DstSizeInWords,size_t _MaxCount,const wchar_t *_Format,...); + _CRTIMP int __cdecl _vsnwprintf_s(wchar_t *_DstBuf,size_t _DstSizeInWords,size_t _MaxCount,const wchar_t *_Format,va_list _ArgList); + _CRTIMP int __cdecl _wprintf_s_l(const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vwprintf_s_l(const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _fwprintf_s_l(FILE *_File,const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vfwprintf_s_l(FILE *_File,const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _swprintf_s_l(wchar_t *_DstBuf,size_t _DstSize,const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vswprintf_s_l(wchar_t *_DstBuf,size_t _DstSize,const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _snwprintf_s_l(wchar_t *_DstBuf,size_t _DstSize,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vsnwprintf_s_l(wchar_t *_DstBuf,size_t _DstSize,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _fwscanf_s_l(FILE *_File,const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _swscanf_s_l(const wchar_t *_Src,const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _snwscanf_s(const wchar_t *_Src,size_t _MaxCount,const wchar_t *_Format,...); + _CRTIMP int __cdecl _snwscanf_s_l(const wchar_t *_Src,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _wscanf_s_l(const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP errno_t __cdecl _wfopen_s(FILE **_File,const wchar_t *_Filename,const wchar_t *_Mode); + _CRTIMP errno_t __cdecl _wfreopen_s(FILE **_File,const wchar_t *_Filename,const wchar_t *_Mode,FILE *_OldFile); + _CRTIMP errno_t __cdecl _wtmpnam_s(wchar_t *_DstBuf,size_t _SizeInWords); + _CRTIMP int __cdecl _fwprintf_p(FILE *_File,const wchar_t *_Format,...); + _CRTIMP int __cdecl _wprintf_p(const wchar_t *_Format,...); + _CRTIMP int __cdecl _vfwprintf_p(FILE *_File,const wchar_t *_Format,va_list _ArgList); + _CRTIMP int __cdecl _vwprintf_p(const wchar_t *_Format,va_list _ArgList); + _CRTIMP int __cdecl _swprintf_p(wchar_t *_DstBuf,size_t _MaxCount,const wchar_t *_Format,...); + _CRTIMP int __cdecl _vswprintf_p(wchar_t *_DstBuf,size_t _MaxCount,const wchar_t *_Format,va_list _ArgList); + _CRTIMP int __cdecl _scwprintf_p(const wchar_t *_Format,...); + _CRTIMP int __cdecl _vscwprintf_p(const wchar_t *_Format,va_list _ArgList); + _CRTIMP int __cdecl _wprintf_l(const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _wprintf_p_l(const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vwprintf_l(const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _vwprintf_p_l(const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _fwprintf_l(FILE *_File,const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _fwprintf_p_l(FILE *_File,const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vfwprintf_l(FILE *_File,const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _vfwprintf_p_l(FILE *_File,const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _swprintf_c_l(wchar_t *_DstBuf,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _swprintf_p_l(wchar_t *_DstBuf,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vswprintf_c_l(wchar_t *_DstBuf,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _vswprintf_p_l(wchar_t *_DstBuf,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _scwprintf_l(const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _scwprintf_p_l(const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vscwprintf_p_l(const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _snwprintf_l(wchar_t *_DstBuf,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vsnwprintf_l(wchar_t *_DstBuf,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl __swprintf_l(wchar_t *_Dest,const wchar_t *_Format,_locale_t _Plocinfo,...); + _CRTIMP int __cdecl __vswprintf_l(wchar_t *_Dest,const wchar_t *_Format,_locale_t _Plocinfo,va_list _Args); + _CRTIMP int __cdecl _vscwprintf_l(const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _fwscanf_l(FILE *_File,const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _swscanf_l(const wchar_t *_Src,const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _snwscanf_l(const wchar_t *_Src,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _wscanf_l(const wchar_t *_Format,_locale_t _Locale,...); +#endif +#endif + + _CRTIMP size_t __cdecl _fread_nolock_s(void *_DstBuf,size_t _DstSize,size_t _ElementSize,size_t _Count,FILE *_File); + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/tinyc/win32/include/sec_api/stdlib_s.h b/tinyc/win32/include/sec_api/stdlib_s.h new file mode 100644 index 000000000..f98262ccc --- /dev/null +++ b/tinyc/win32/include/sec_api/stdlib_s.h @@ -0,0 +1,67 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _INC_STDLIB_S +#define _INC_STDLIB_S + +#include + +#if defined(MINGW_HAS_SECURE_API) + +#ifdef __cplusplus +extern "C" { +#endif + + _CRTIMP errno_t __cdecl _dupenv_s(char **_PBuffer,size_t *_PBufferSizeInBytes,const char *_VarName); + _CRTIMP errno_t __cdecl _itoa_s(int _Value,char *_DstBuf,size_t _Size,int _Radix); +#if _INTEGRAL_MAX_BITS >= 64 + _CRTIMP errno_t __cdecl _i64toa_s(__int64 _Val,char *_DstBuf,size_t _Size,int _Radix); + _CRTIMP errno_t __cdecl _ui64toa_s(unsigned __int64 _Val,char *_DstBuf,size_t _Size,int _Radix); +#endif + _CRTIMP errno_t __cdecl _ltoa_s(long _Val,char *_DstBuf,size_t _Size,int _Radix); + _CRTIMP errno_t __cdecl mbstowcs_s(size_t *_PtNumOfCharConverted,wchar_t *_DstBuf,size_t _SizeInWords,const char *_SrcBuf,size_t _MaxCount); + _CRTIMP errno_t __cdecl _mbstowcs_s_l(size_t *_PtNumOfCharConverted,wchar_t *_DstBuf,size_t _SizeInWords,const char *_SrcBuf,size_t _MaxCount,_locale_t _Locale); + _CRTIMP errno_t __cdecl _ultoa_s(unsigned long _Val,char *_DstBuf,size_t _Size,int _Radix); + _CRTIMP errno_t __cdecl _wctomb_s_l(int *_SizeConverted,char *_MbCh,size_t _SizeInBytes,wchar_t _WCh,_locale_t _Locale); + _CRTIMP errno_t __cdecl wcstombs_s(size_t *_PtNumOfCharConverted,char *_Dst,size_t _DstSizeInBytes,const wchar_t *_Src,size_t _MaxCountInBytes); + _CRTIMP errno_t __cdecl _wcstombs_s_l(size_t *_PtNumOfCharConverted,char *_Dst,size_t _DstSizeInBytes,const wchar_t *_Src,size_t _MaxCountInBytes,_locale_t _Locale); + +#ifndef _WSTDLIB_S_DEFINED +#define _WSTDLIB_S_DEFINED + _CRTIMP errno_t __cdecl _itow_s (int _Val,wchar_t *_DstBuf,size_t _SizeInWords,int _Radix); + _CRTIMP errno_t __cdecl _ltow_s (long _Val,wchar_t *_DstBuf,size_t _SizeInWords,int _Radix); + _CRTIMP errno_t __cdecl _ultow_s (unsigned long _Val,wchar_t *_DstBuf,size_t _SizeInWords,int _Radix); + _CRTIMP errno_t __cdecl _wgetenv_s(size_t *_ReturnSize,wchar_t *_DstBuf,size_t _DstSizeInWords,const wchar_t *_VarName); + _CRTIMP errno_t __cdecl _wdupenv_s(wchar_t **_Buffer,size_t *_BufferSizeInWords,const wchar_t *_VarName); +#if _INTEGRAL_MAX_BITS >= 64 + _CRTIMP errno_t __cdecl _i64tow_s(__int64 _Val,wchar_t *_DstBuf,size_t _SizeInWords,int _Radix); + _CRTIMP errno_t __cdecl _ui64tow_s(unsigned __int64 _Val,wchar_t *_DstBuf,size_t _SizeInWords,int _Radix); +#endif +#endif + +#ifndef _POSIX_ + _CRTIMP errno_t __cdecl _ecvt_s(char *_DstBuf,size_t _Size,double _Val,int _NumOfDights,int *_PtDec,int *_PtSign); + _CRTIMP errno_t __cdecl _fcvt_s(char *_DstBuf,size_t _Size,double _Val,int _NumOfDec,int *_PtDec,int *_PtSign); + _CRTIMP errno_t __cdecl _gcvt_s(char *_DstBuf,size_t _Size,double _Val,int _NumOfDigits); + _CRTIMP errno_t __cdecl _makepath_s(char *_PathResult,size_t _Size,const char *_Drive,const char *_Dir,const char *_Filename,const char *_Ext); + _CRTIMP errno_t __cdecl _putenv_s(const char *_Name,const char *_Value); + _CRTIMP errno_t __cdecl _searchenv_s(const char *_Filename,const char *_EnvVar,char *_ResultPath,size_t _SizeInBytes); + _CRTIMP errno_t __cdecl _splitpath_s(const char *_FullPath,char *_Drive,size_t _DriveSize,char *_Dir,size_t _DirSize,char *_Filename,size_t _FilenameSize,char *_Ext,size_t _ExtSize); + +#ifndef _WSTDLIBP_S_DEFINED +#define _WSTDLIBP_S_DEFINED + _CRTIMP errno_t __cdecl _wmakepath_s(wchar_t *_PathResult,size_t _SizeInWords,const wchar_t *_Drive,const wchar_t *_Dir,const wchar_t *_Filename,const wchar_t *_Ext); + _CRTIMP errno_t __cdecl _wputenv_s(const wchar_t *_Name,const wchar_t *_Value); + _CRTIMP errno_t __cdecl _wsearchenv_s(const wchar_t *_Filename,const wchar_t *_EnvVar,wchar_t *_ResultPath,size_t _SizeInWords); + _CRTIMP errno_t __cdecl _wsplitpath_s(const wchar_t *_FullPath,wchar_t *_Drive,size_t _DriveSizeInWords,wchar_t *_Dir,size_t _DirSizeInWords,wchar_t *_Filename,size_t _FilenameSizeInWords,wchar_t *_Ext,size_t _ExtSizeInWords); +#endif +#endif + +#ifdef __cplusplus +} +#endif + +#endif +#endif diff --git a/tinyc/win32/include/sec_api/stralign_s.h b/tinyc/win32/include/sec_api/stralign_s.h new file mode 100644 index 000000000..5b78f5860 --- /dev/null +++ b/tinyc/win32/include/sec_api/stralign_s.h @@ -0,0 +1,30 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef __STRALIGN_H_S_ +#define __STRALIGN_H_S_ + +#include + +#if defined(MINGW_HAS_SECURE_API) + +#ifdef __cplusplus +extern "C" { +#endif + +#if !defined(I_X86_) && defined(_WSTRING_S_DEFINED) +#if defined(__cplusplus) && defined(_WConst_Return) + static __inline PUWSTR ua_wcscpy_s(PUWSTR Destination,size_t DestinationSize,PCUWSTR Source) { + if(WSTR_ALIGNED(Source) && WSTR_ALIGNED(Destination)) return (wcscpy_s((PWSTR)Destination,DestinationSize,(PCWSTR)Source)==0 ? Destination : NULL); + return uaw_wcscpy((PCUWSTR)String,Character); + } +#endif +#endif + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/tinyc/win32/include/sec_api/string_s.h b/tinyc/win32/include/sec_api/string_s.h new file mode 100644 index 000000000..9db70e77d --- /dev/null +++ b/tinyc/win32/include/sec_api/string_s.h @@ -0,0 +1,41 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _INC_STRING_S +#define _INC_STRING_S + +#include + +#if defined(MINGW_HAS_SECURE_API) + +#ifdef __cplusplus +extern "C" { +#endif + + _CRTIMP errno_t __cdecl _strset_s(char *_Dst,size_t _DstSize,int _Value); + _CRTIMP errno_t __cdecl _strerror_s(char *_Buf,size_t _SizeInBytes,const char *_ErrMsg); + _CRTIMP errno_t __cdecl _strlwr_s(char *_Str,size_t _Size); + _CRTIMP errno_t __cdecl _strlwr_s_l(char *_Str,size_t _Size,_locale_t _Locale); + _CRTIMP errno_t __cdecl _strnset_s(char *_Str,size_t _Size,int _Val,size_t _MaxCount); + _CRTIMP errno_t __cdecl _strupr_s(char *_Str,size_t _Size); + _CRTIMP errno_t __cdecl _strupr_s_l(char *_Str,size_t _Size,_locale_t _Locale); +#ifndef _WSTRING_S_DEFINED +#define _WSTRING_S_DEFINED + _CRTIMP wchar_t *__cdecl wcstok_s(wchar_t *_Str,const wchar_t *_Delim,wchar_t **_Context); + _CRTIMP errno_t __cdecl _wcserror_s(wchar_t *_Buf,size_t _SizeInWords,int _ErrNum); + _CRTIMP errno_t __cdecl __wcserror_s(wchar_t *_Buffer,size_t _SizeInWords,const wchar_t *_ErrMsg); + _CRTIMP errno_t __cdecl _wcsnset_s(wchar_t *_Dst,size_t _DstSizeInWords,wchar_t _Val,size_t _MaxCount); + _CRTIMP errno_t __cdecl _wcsset_s(wchar_t *_Str,size_t _SizeInWords,wchar_t _Val); + _CRTIMP errno_t __cdecl _wcslwr_s(wchar_t *_Str,size_t _SizeInWords); + _CRTIMP errno_t __cdecl _wcslwr_s_l(wchar_t *_Str,size_t _SizeInWords,_locale_t _Locale); + _CRTIMP errno_t __cdecl _wcsupr_s(wchar_t *_Str,size_t _Size); + _CRTIMP errno_t __cdecl _wcsupr_s_l(wchar_t *_Str,size_t _Size,_locale_t _Locale); +#endif + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/tinyc/win32/include/sec_api/sys/timeb_s.h b/tinyc/win32/include/sec_api/sys/timeb_s.h new file mode 100644 index 000000000..af5ef098f --- /dev/null +++ b/tinyc/win32/include/sec_api/sys/timeb_s.h @@ -0,0 +1,34 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ + +#ifndef _TIMEB_H_S +#define _TIMEB_H_S + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(MINGW_HAS_SECURE_API) + +#ifdef _USE_32BIT_TIME_T +#define _ftime_s _ftime32_s +#else +#define _ftime_s _ftime64_s +#endif + + _CRTIMP errno_t __cdecl _ftime32_s(struct __timeb32 *_Time); +#if _INTEGRAL_MAX_BITS >= 64 + _CRTIMP errno_t __cdecl _ftime64_s(struct __timeb64 *_Time); +#endif +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/tinyc/win32/include/sec_api/tchar_s.h b/tinyc/win32/include/sec_api/tchar_s.h new file mode 100644 index 000000000..343d348eb --- /dev/null +++ b/tinyc/win32/include/sec_api/tchar_s.h @@ -0,0 +1,266 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _INC_TCHAR_S +#define _INC_TCHAR_S + +#include + +#if defined(MINGW_HAS_SECURE_API) + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef _UNICODE + +#define _tprintf_s wprintf_s +#define _tprintf_s_l _wprintf_s_l +#define _tcprintf_s _cwprintf_s +#define _tcprintf_s_l _cwprintf_s_l +#define _vtcprintf_s _vcwprintf_s +#define _vtcprintf_s_l _vcwprintf_s_l +#define _ftprintf_s fwprintf_s +#define _ftprintf_s_l _fwprintf_s_l +#define _stprintf_s swprintf_s +#define _stprintf_s_l _swprintf_s_l +#define _sntprintf_s _snwprintf_s +#define _sntprintf_s_l _snwprintf_s_l +#define _vtprintf_s vwprintf_s +#define _vtprintf_s_l _vwprintf_s_l +#define _vftprintf_s vfwprintf_s +#define _vftprintf_s_l _vfwprintf_s_l +#define _vstprintf_s vswprintf_s +#define _vstprintf_s_l _vswprintf_s_l +#define _vsntprintf_s _vsnwprintf_s +#define _vsntprintf_s_l _vsnwprintf_s_l + +#define _tscanf_s wscanf_s +#define _tscanf_s_l _wscanf_s_l +#define _tcscanf_s _cwscanf_s +#define _tcscanf_s_l _cwscanf_s_l +#define _ftscanf_s fwscanf_s +#define _ftscanf_s_l _fwscanf_s_l +#define _stscanf_s swscanf_s +#define _stscanf_s_l _swscanf_s_l +#define _sntscanf_s _snwscanf_s +#define _sntscanf_s_l _snwscanf_s_l + +#define _cgetts_s _cgetws_s +#define _getts_s _getws_s + +#define _itot_s _itow_s +#define _ltot_s _ltow_s +#define _ultot_s _ultow_s +#define _i64tot_s _i64tow_s +#define _ui64tot_s _ui64tow_s + +#define _tcscat_s wcscat_s +#define _tcscpy_s wcscpy_s +#define _tcsncat_s wcsncat_s +#define _tcsncat_s_l _wcsncat_s_l +#define _tcsncpy_s wcsncpy_s +#define _tcsncpy_s_l _wcsncpy_s_l +#define _tcstok_s wcstok_s +#define _tcstok_s_l _wcstok_s_l +#define _tcserror_s _wcserror_s +#define __tcserror_s __wcserror_s + +#define _tcsnset_s _wcsnset_s +#define _tcsnset_s_l _wcsnset_s_l +#define _tcsset_s _wcsset_s +#define _tcsset_s_l _wcsset_s_l + +#define _tasctime_s _wasctime_s +#define _tctime_s _wctime_s +#define _tctime32_s _wctime32_s +#define _tctime64_s _wctime64_s +#define _tstrdate_s _wstrdate_s +#define _tstrtime_s _wstrtime_s + +#define _tgetenv_s _wgetenv_s +#define _tdupenv_s _wdupenv_s +#define _tmakepath_s _wmakepath_s +#define _tputenv_s _wputenv_s +#define _tsearchenv_s _wsearchenv_s +#define _tsplitpath_s _wsplitpath_s + +#define _tfopen_s _wfopen_s +#define _tfreopen_s _wfreopen_s +#define _ttmpnam_s _wtmpnam_s +#define _taccess_s _waccess_s +#define _tmktemp_s _wmktemp_s + +#define _tcsnccat_s wcsncat_s +#define _tcsnccat_s_l _wcsncat_s_l +#define _tcsnccpy_s wcsncpy_s +#define _tcsnccpy_s_l _wcsncpy_s_l + +#define _tcslwr_s _wcslwr_s +#define _tcslwr_s_l _wcslwr_s_l +#define _tcsupr_s _wcsupr_s +#define _tcsupr_s_l _wcsupr_s_l + +#define _wcstok_s_l(_String,_Delimiters,_Current_position,_Locale) (wcstok_s(_String,_Delimiters,_Current_position)) +#define _wcsnset_s_l(_Destination,_Destination_size_chars,_Value,_Count,_Locale) (_wcsnset_s(_Destination,_Destination_size_chars,_Value,_Count)) +#define _wcsset_s_l(_Destination,_Destination_size_chars,_Value,_Locale) (_wcsset_s(_Destination,_Destination_size_chars,_Value)) + +#else + +#define _tprintf_s printf_s +#define _tprintf_s_l _printf_s_l +#define _tcprintf_s _cprintf_s +#define _tcprintf_s_l _cprintf_s_l +#define _vtcprintf_s _vcprintf_s +#define _vtcprintf_s_l _vcprintf_s_l +#define _ftprintf_s fprintf_s +#define _ftprintf_s_l _fprintf_s_l +#define _stprintf_s sprintf_s +#define _stprintf_s_l _sprintf_s_l +#define _sntprintf_s _snprintf_s +#define _sntprintf_s_l _snprintf_s_l +#define _vtprintf_s vprintf_s +#define _vtprintf_s_l _vprintf_s_l +#define _vftprintf_s vfprintf_s +#define _vftprintf_s_l _vfprintf_s_l +#define _vstprintf_s vsprintf_s +#define _vstprintf_s_l _vsprintf_s_l +#define _vsntprintf_s _vsnprintf_s +#define _vsntprintf_s_l _vsnprintf_s_l +#define _tscanf_s scanf_s +#define _tscanf_s_l _scanf_s_l +#define _tcscanf_s _cscanf_s +#define _tcscanf_s_l _cscanf_s_l +#define _ftscanf_s fscanf_s +#define _ftscanf_s_l _fscanf_s_l +#define _stscanf_s sscanf_s +#define _stscanf_s_l _sscanf_s_l +#define _sntscanf_s _snscanf_s +#define _sntscanf_s_l _snscanf_s_l + +#define _getts_s gets_s +#define _cgetts_s _cgets_s +#define _itot_s _itoa_s +#define _ltot_s _ltoa_s +#define _ultot_s _ultoa_s +#define _i64tot_s _i64toa_s +#define _ui64tot_s _ui64toa_s + +#define _tcscat_s strcat_s +#define _tcscpy_s strcpy_s +#define _tcserror_s strerror_s +#define __tcserror_s _strerror_s + +#define _tasctime_s asctime_s +#define _tctime_s ctime_s +#define _tctime32_s _ctime32_s +#define _tctime64_s _ctime64_s +#define _tstrdate_s _strdate_s +#define _tstrtime_s _strtime_s + +#define _tgetenv_s getenv_s +#define _tdupenv_s _dupenv_s +#define _tmakepath_s _makepath_s +#define _tputenv_s _putenv_s +#define _tsearchenv_s _searchenv_s +#define _tsplitpath_s _splitpath_s + +#define _tfopen_s fopen_s +#define _tfreopen_s freopen_s +#define _ttmpnam_s tmpnam_s +#define _tmktemp_s _mktemp_s + +#ifndef _POSIX_ +#define _taccess_s _access_s +#endif + +#define _tsopen_s _sopen_s + +#ifdef _MBCS + +#ifdef _MB_MAP_DIRECT + +#define _tcsncat_s _mbsnbcat_s +#define _tcsncat_s_l _mbsnbcat_s_l +#define _tcsncpy_s _mbsnbcpy_s +#define _tcsncpy_s_l _mbsnbcpy_s_l +#define _tcstok_s _mbstok_s +#define _tcstok_s_l _mbstok_s_l + +#define _tcsnset_s _mbsnbset_s +#define _tcsnset_s_l _mbsnbset_s_l +#define _tcsset_s _mbsset_s +#define _tcsset_s_l _mbsset_s_l + +#define _tcsnccat_s _mbsncat_s +#define _tcsnccat_s_l _mbsncat_s_l +#define _tcsnccpy_s _mbsncpy_s +#define _tcsnccpy_s_l _mbsncpy_s_l +#define _tcsncset_s _mbsnset_s +#define _tcsncset_s_l _mbsnset_s_l + +#define _tcslwr_s _mbslwr_s +#define _tcslwr_s_l _mbslwr_s_l +#define _tcsupr_s _mbsupr_s +#define _tcsupr_s_l _mbsupr_s_l + +#define _tccpy_s _mbccpy_s +#define _tccpy_s_l _mbccpy_s_l +#else + + _CRTIMP char *__cdecl _tcsncat_s(char *_Dst,size_t _DstSizeInChars,const char *_Src,size_t _MaxCount); + _CRTIMP char *__cdecl _tcsncat_s_l(char *_Dst,size_t _DstSizeInChars,const char *_Src,size_t _MaxCount,_locale_t _Locale); + _CRTIMP char *__cdecl _tcsncpy_s(char *_Dst,size_t _DstSizeInChars,const char *_Src,size_t _MaxCount); + _CRTIMP char *__cdecl _tcsncpy_s_l(char *_Dst,size_t _DstSizeInChars,const char *_Src,size_t _MaxCount,_locale_t _Locale); + _CRTIMP char *__cdecl _tcstok_s(char *_Str,const char *_Delim,char **_Context); + _CRTIMP char *__cdecl _tcstok_s_l(char *_Str,const char *_Delim,char **_Context,_locale_t _Locale); + _CRTIMP errno_t __cdecl _tcsset_s(char *_Str,size_t _SizeInChars,unsigned int _Val); + _CRTIMP errno_t __cdecl _tcsset_s_l(char *_Str,size_t _SizeInChars,unsigned int,_locale_t _Locale); + _CRTIMP char *__cdecl _tcsnccat_s(char *_Dst,size_t _DstSizeInChars,const char *_Src,size_t _MaxCount); + _CRTIMP char *__cdecl _tcsnccat_s_l(char *_Dst,size_t _DstSizeInChars,const char *_Src,size_t _MaxCount,_locale_t _Locale); + _CRTIMP char *__cdecl _tcsnccpy_s(char *_Dst,size_t _DstSizeInChars,const char *_Src,size_t _MaxCount); + _CRTIMP char *__cdecl _tcsnccpy_s_l(char *_Dst,size_t _DstSizeInChars,const char *_Src,size_t _MaxCount,_locale_t _Locale); + _CRTIMP char *__cdecl _tcslwr_s(char *_Str,size_t _SizeInChars); + _CRTIMP char *__cdecl _tcslwr_s_l(char *_Str,size_t _SizeInChars,_locale_t _Locale); + _CRTIMP char *__cdecl _tcsupr_s(char *_Str,size_t _SizeInChars); + _CRTIMP char *__cdecl _tcsupr_s_l(char *_Str,size_t _SizeInChars,_locale_t _Locale); + +#endif + +#else + +#define _tcsncat_s strncat_s +#define _tcsncat_s_l _strncat_s_l +#define _tcsncpy_s strncpy_s +#define _tcsncpy_s_l _strncpy_s_l +#define _tcstok_s strtok_s +#define _tcstok_s_l _strtok_s_l + +#define _tcsnset_s _strnset_s +#define _tcsnset_s_l _strnset_s_l +#define _tcsset_s _strset_s +#define _tcsset_s _strset_s +#define _tcsset_s_l _strset_s_l + +#define _tcsnccat_s strncat_s +#define _tcsnccat_s_l _strncat_s_l +#define _tcsnccpy_s strncpy_s +#define _tcsnccpy_s_l _strncpy_s_l + +#define _tcslwr_s _strlwr_s +#define _tcslwr_s_l _strlwr_s_l +#define _tcsupr_s _strupr_s +#define _tcsupr_s_l _strupr_s_l + +#define _strnset_s_l(_Destination,_Destination_size_chars,_Value,_Count,_Locale) (_strnset_s(_Destination,_Destination_size_chars,_Value,_Count)) +#define _strset_s_l(_Destination,_Destination_size_chars,_Value,_Locale) (_strset_s(_Destination,_Destination_size_chars,_Value)) +#endif +#endif + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/tinyc/win32/include/sec_api/time_s.h b/tinyc/win32/include/sec_api/time_s.h new file mode 100644 index 000000000..9603b94fc --- /dev/null +++ b/tinyc/win32/include/sec_api/time_s.h @@ -0,0 +1,61 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _TIME_H__S +#define _TIME_H__S + +#include + +#if defined(MINGW_HAS_SECURE_API) + +#ifdef __cplusplus +extern "C" { +#endif + + _CRTIMP errno_t __cdecl _ctime32_s(char *_Buf,size_t _SizeInBytes,const __time32_t *_Time); + _CRTIMP errno_t __cdecl _gmtime32_s(struct tm *_Tm,const __time32_t *_Time); + _CRTIMP errno_t __cdecl _localtime32_s(struct tm *_Tm,const __time32_t *_Time); + _CRTIMP errno_t __cdecl _strdate_s(char *_Buf,size_t _SizeInBytes); + _CRTIMP errno_t __cdecl _strtime_s(char *_Buf ,size_t _SizeInBytes); +#if _INTEGRAL_MAX_BITS >= 64 + _CRTIMP errno_t __cdecl _ctime64_s(char *_Buf,size_t _SizeInBytes,const __time64_t *_Time); + _CRTIMP errno_t __cdecl _gmtime64_s(struct tm *_Tm,const __time64_t *_Time); + _CRTIMP errno_t __cdecl _localtime64_s(struct tm *_Tm,const __time64_t *_Time); +#endif + +#ifndef _WTIME_S_DEFINED +#define _WTIME_S_DEFINED + _CRTIMP errno_t __cdecl _wasctime_s(wchar_t *_Buf,size_t _SizeInWords,const struct tm *_Tm); + _CRTIMP errno_t __cdecl _wctime32_s(wchar_t *_Buf,size_t _SizeInWords,const __time32_t *_Time); + _CRTIMP errno_t __cdecl _wstrdate_s(wchar_t *_Buf,size_t _SizeInWords); + _CRTIMP errno_t __cdecl _wstrtime_s(wchar_t *_Buf,size_t _SizeInWords); +#if _INTEGRAL_MAX_BITS >= 64 + _CRTIMP errno_t __cdecl _wctime64_s(wchar_t *_Buf,size_t _SizeInWords,const __time64_t *_Time); +#endif + +#if !defined (RC_INVOKED) && !defined (_INC_WTIME_S_INL) +#define _INC_WTIME_S_INL +#ifdef _USE_32BIT_TIME_T +__CRT_INLINE errno_t __cdecl _wctime_s(wchar_t *_Buffer,size_t _SizeInWords,const time_t *_Time) { return _wctime32_s(_Buffer,_SizeInWords,_Time); } +#else +__CRT_INLINE errno_t __cdecl _wctime_s(wchar_t *_Buffer,size_t _SizeInWords,const time_t *_Time) { return _wctime64_s(_Buffer,_SizeInWords,_Time); } +#endif +#endif +#endif + +#ifndef RC_INVOKED +#ifdef _USE_32BIT_TIME_T +__CRT_INLINE errno_t __cdecl localtime_s(struct tm *_Tm,const time_t *_Time) { return _localtime32_s(_Tm,_Time); } +#else +__CRT_INLINE errno_t __cdecl localtime_s(struct tm *_Tm,const time_t *_Time) { return _localtime64_s(_Tm,_Time); } +#endif +#endif + +#ifdef __cplusplus +} +#endif + +#endif +#endif diff --git a/tinyc/win32/include/sec_api/wchar_s.h b/tinyc/win32/include/sec_api/wchar_s.h new file mode 100644 index 000000000..94251aa8b --- /dev/null +++ b/tinyc/win32/include/sec_api/wchar_s.h @@ -0,0 +1,128 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _INC_WCHAR_S +#define _INC_WCHAR_S + +#include + +#if defined(MINGW_HAS_SECURE_API) + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _WIO_S_DEFINED +#define _WIO_S_DEFINED + _CRTIMP errno_t __cdecl _waccess_s(const wchar_t *_Filename,int _AccessMode); + _CRTIMP errno_t __cdecl _wmktemp_s(wchar_t *_TemplateName,size_t _SizeInWords); +#endif + +#ifndef _WCONIO_S_DEFINED +#define _WCONIO_S_DEFINED + _CRTIMP errno_t __cdecl _cgetws_s(wchar_t *_Buffer,size_t _SizeInWords,size_t *_SizeRead); + _CRTIMP int __cdecl _cwprintf_s(const wchar_t *_Format,...); + _CRTIMP int __cdecl _cwscanf_s(const wchar_t *_Format,...); + _CRTIMP int __cdecl _cwscanf_s_l(const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vcwprintf_s(const wchar_t *_Format,va_list _ArgList); + _CRTIMP int __cdecl _cwprintf_s_l(const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vcwprintf_s_l(const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); +#endif + +#ifndef _WSTDIO_S_DEFINED +#define _WSTDIO_S_DEFINED + _CRTIMP wchar_t *__cdecl _getws_s(wchar_t *_Str,size_t _SizeInWords); + int __cdecl fwprintf_s(FILE *_File,const wchar_t *_Format,...); + int __cdecl wprintf_s(const wchar_t *_Format,...); + int __cdecl vfwprintf_s(FILE *_File,const wchar_t *_Format,va_list _ArgList); + int __cdecl vwprintf_s(const wchar_t *_Format,va_list _ArgList); + int __cdecl swprintf_s(wchar_t *_Dst,size_t _SizeInWords,const wchar_t *_Format,...); + int __cdecl vswprintf_s(wchar_t *_Dst,size_t _SizeInWords,const wchar_t *_Format,va_list _ArgList); + _CRTIMP int __cdecl _snwprintf_s(wchar_t *_DstBuf,size_t _DstSizeInWords,size_t _MaxCount,const wchar_t *_Format,...); + _CRTIMP int __cdecl _vsnwprintf_s(wchar_t *_DstBuf,size_t _DstSizeInWords,size_t _MaxCount,const wchar_t *_Format,va_list _ArgList); + _CRTIMP int __cdecl _wprintf_s_l(const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vwprintf_s_l(const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _fwprintf_s_l(FILE *_File,const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vfwprintf_s_l(FILE *_File,const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _swprintf_s_l(wchar_t *_DstBuf,size_t _DstSize,const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vswprintf_s_l(wchar_t *_DstBuf,size_t _DstSize,const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _snwprintf_s_l(wchar_t *_DstBuf,size_t _DstSize,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vsnwprintf_s_l(wchar_t *_DstBuf,size_t _DstSize,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _fwscanf_s_l(FILE *_File,const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _swscanf_s_l(const wchar_t *_Src,const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _snwscanf_s(const wchar_t *_Src,size_t _MaxCount,const wchar_t *_Format,...); + _CRTIMP int __cdecl _snwscanf_s_l(const wchar_t *_Src,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _wscanf_s_l(const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP errno_t __cdecl _wfopen_s(FILE **_File,const wchar_t *_Filename,const wchar_t *_Mode); + _CRTIMP errno_t __cdecl _wfreopen_s(FILE **_File,const wchar_t *_Filename,const wchar_t *_Mode,FILE *_OldFile); + _CRTIMP errno_t __cdecl _wtmpnam_s(wchar_t *_DstBuf,size_t _SizeInWords); +#endif + +#ifndef _WSTDLIB_S_DEFINED +#define _WSTDLIB_S_DEFINED + _CRTIMP errno_t __cdecl _itow_s (int _Val,wchar_t *_DstBuf,size_t _SizeInWords,int _Radix); + _CRTIMP errno_t __cdecl _ltow_s (long _Val,wchar_t *_DstBuf,size_t _SizeInWords,int _Radix); + _CRTIMP errno_t __cdecl _ultow_s (unsigned long _Val,wchar_t *_DstBuf,size_t _SizeInWords,int _Radix); + _CRTIMP errno_t __cdecl _wgetenv_s(size_t *_ReturnSize,wchar_t *_DstBuf,size_t _DstSizeInWords,const wchar_t *_VarName); + _CRTIMP errno_t __cdecl _wdupenv_s(wchar_t **_Buffer,size_t *_BufferSizeInWords,const wchar_t *_VarName); +#if _INTEGRAL_MAX_BITS >= 64 + _CRTIMP errno_t __cdecl _i64tow_s(__int64 _Val,wchar_t *_DstBuf,size_t _SizeInWords,int _Radix); + _CRTIMP errno_t __cdecl _ui64tow_s(unsigned __int64 _Val,wchar_t *_DstBuf,size_t _SizeInWords,int _Radix); +#endif +#endif + +#ifndef _POSIX_ +#ifndef _WSTDLIBP_S_DEFINED +#define _WSTDLIBP_S_DEFINED + _CRTIMP errno_t __cdecl _wmakepath_s(wchar_t *_PathResult,size_t _SizeInWords,const wchar_t *_Drive,const wchar_t *_Dir,const wchar_t *_Filename,const wchar_t *_Ext); + _CRTIMP errno_t __cdecl _wputenv_s(const wchar_t *_Name,const wchar_t *_Value); + _CRTIMP errno_t __cdecl _wsearchenv_s(const wchar_t *_Filename,const wchar_t *_EnvVar,wchar_t *_ResultPath,size_t _SizeInWords); + _CRTIMP errno_t __cdecl _wsplitpath_s(const wchar_t *_FullPath,wchar_t *_Drive,size_t _DriveSizeInWords,wchar_t *_Dir,size_t _DirSizeInWords,wchar_t *_Filename,size_t _FilenameSizeInWords,wchar_t *_Ext,size_t _ExtSizeInWords); +#endif +#endif + +#ifndef _WSTRING_S_DEFINED +#define _WSTRING_S_DEFINED + _CRTIMP wchar_t *__cdecl wcstok_s(wchar_t *_Str,const wchar_t *_Delim,wchar_t **_Context); + _CRTIMP errno_t __cdecl _wcserror_s(wchar_t *_Buf,size_t _SizeInWords,int _ErrNum); + _CRTIMP errno_t __cdecl __wcserror_s(wchar_t *_Buffer,size_t _SizeInWords,const wchar_t *_ErrMsg); + _CRTIMP errno_t __cdecl _wcsnset_s(wchar_t *_Dst,size_t _DstSizeInWords,wchar_t _Val,size_t _MaxCount); + _CRTIMP errno_t __cdecl _wcsset_s(wchar_t *_Str,size_t _SizeInWords,wchar_t _Val); + _CRTIMP errno_t __cdecl _wcslwr_s(wchar_t *_Str,size_t _SizeInWords); + _CRTIMP errno_t __cdecl _wcslwr_s_l(wchar_t *_Str,size_t _SizeInWords,_locale_t _Locale); + _CRTIMP errno_t __cdecl _wcsupr_s(wchar_t *_Str,size_t _Size); + _CRTIMP errno_t __cdecl _wcsupr_s_l(wchar_t *_Str,size_t _Size,_locale_t _Locale); +#endif + +#ifndef _WTIME_S_DEFINED +#define _WTIME_S_DEFINED + _CRTIMP errno_t __cdecl _wasctime_s(wchar_t *_Buf,size_t _SizeInWords,const struct tm *_Tm); + _CRTIMP errno_t __cdecl _wctime32_s(wchar_t *_Buf,size_t _SizeInWords,const __time32_t *_Time); + _CRTIMP errno_t __cdecl _wstrdate_s(wchar_t *_Buf,size_t _SizeInWords); + _CRTIMP errno_t __cdecl _wstrtime_s(wchar_t *_Buf,size_t _SizeInWords); +#if _INTEGRAL_MAX_BITS >= 64 + _CRTIMP errno_t __cdecl _wctime64_s(wchar_t *_Buf,size_t _SizeInWords,const __time64_t *_Time); +#endif + +#if !defined (RC_INVOKED) && !defined (_INC_WTIME_S_INL) +#define _INC_WTIME_S_INL +#ifdef _USE_32BIT_TIME_T +__CRT_INLINE errno_t __cdecl _wctime_s(wchar_t *_Buffer,size_t _SizeInWords,const time_t *_Time) { return _wctime32_s(_Buffer,_SizeInWords,_Time); } +#else +__CRT_INLINE errno_t __cdecl _wctime_s(wchar_t *_Buffer,size_t _SizeInWords,const time_t *_Time) { return _wctime64_s(_Buffer,_SizeInWords,_Time); } +#endif +#endif +#endif + + _CRTIMP errno_t __cdecl mbsrtowcs_s(size_t *_Retval,wchar_t *_Dst,size_t _SizeInWords,const char **_PSrc,size_t _N,mbstate_t *_State); + _CRTIMP errno_t __cdecl wcrtomb_s(size_t *_Retval,char *_Dst,size_t _SizeInBytes,wchar_t _Ch,mbstate_t *_State); + _CRTIMP errno_t __cdecl wcsrtombs_s(size_t *_Retval,char *_Dst,size_t _SizeInBytes,const wchar_t **_Src,size_t _Size,mbstate_t *_State); + +#ifdef __cplusplus +} +#endif + +#endif +#endif diff --git a/tinyc/win32/include/setjmp.h b/tinyc/win32/include/setjmp.h new file mode 100644 index 000000000..e4f142a3f --- /dev/null +++ b/tinyc/win32/include/setjmp.h @@ -0,0 +1,160 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _INC_SETJMP +#define _INC_SETJMP + +#include <_mingw.h> + +#pragma pack(push,_CRT_PACKING) + +#ifdef __cplusplus +extern "C" { +#endif + +#if (defined(_X86_) && !defined(__x86_64)) + +#define _JBLEN 16 +#define _JBTYPE int + + typedef struct __JUMP_BUFFER { + unsigned long Ebp; + unsigned long Ebx; + unsigned long Edi; + unsigned long Esi; + unsigned long Esp; + unsigned long Eip; + unsigned long Registration; + unsigned long TryLevel; + unsigned long Cookie; + unsigned long UnwindFunc; + unsigned long UnwindData[6]; + } _JUMP_BUFFER; +#elif defined(__ia64__) + typedef _CRT_ALIGN(16) struct _SETJMP_FLOAT128 { + __int64 LowPart; + __int64 HighPart; + } SETJMP_FLOAT128; + +#define _JBLEN 33 + typedef SETJMP_FLOAT128 _JBTYPE; + + typedef struct __JUMP_BUFFER { + + unsigned long iAReserved[6]; + + unsigned long Registration; + unsigned long TryLevel; + unsigned long Cookie; + unsigned long UnwindFunc; + + unsigned long UnwindData[6]; + + SETJMP_FLOAT128 FltS0; + SETJMP_FLOAT128 FltS1; + SETJMP_FLOAT128 FltS2; + SETJMP_FLOAT128 FltS3; + SETJMP_FLOAT128 FltS4; + SETJMP_FLOAT128 FltS5; + SETJMP_FLOAT128 FltS6; + SETJMP_FLOAT128 FltS7; + SETJMP_FLOAT128 FltS8; + SETJMP_FLOAT128 FltS9; + SETJMP_FLOAT128 FltS10; + SETJMP_FLOAT128 FltS11; + SETJMP_FLOAT128 FltS12; + SETJMP_FLOAT128 FltS13; + SETJMP_FLOAT128 FltS14; + SETJMP_FLOAT128 FltS15; + SETJMP_FLOAT128 FltS16; + SETJMP_FLOAT128 FltS17; + SETJMP_FLOAT128 FltS18; + SETJMP_FLOAT128 FltS19; + __int64 FPSR; + __int64 StIIP; + __int64 BrS0; + __int64 BrS1; + __int64 BrS2; + __int64 BrS3; + __int64 BrS4; + __int64 IntS0; + __int64 IntS1; + __int64 IntS2; + __int64 IntS3; + __int64 RsBSP; + __int64 RsPFS; + __int64 ApUNAT; + __int64 ApLC; + __int64 IntSp; + __int64 IntNats; + __int64 Preds; + + } _JUMP_BUFFER; +#elif defined(__x86_64) + typedef _CRT_ALIGN(16) struct _SETJMP_FLOAT128 { + unsigned __int64 Part[2]; + } SETJMP_FLOAT128; + +#define _JBLEN 16 + typedef SETJMP_FLOAT128 _JBTYPE; + + typedef struct _JUMP_BUFFER { + unsigned __int64 Frame; + unsigned __int64 Rbx; + unsigned __int64 Rsp; + unsigned __int64 Rbp; + unsigned __int64 Rsi; + unsigned __int64 Rdi; + unsigned __int64 R12; + unsigned __int64 R13; + unsigned __int64 R14; + unsigned __int64 R15; + unsigned __int64 Rip; + unsigned __int64 Spare; + SETJMP_FLOAT128 Xmm6; + SETJMP_FLOAT128 Xmm7; + SETJMP_FLOAT128 Xmm8; + SETJMP_FLOAT128 Xmm9; + SETJMP_FLOAT128 Xmm10; + SETJMP_FLOAT128 Xmm11; + SETJMP_FLOAT128 Xmm12; + SETJMP_FLOAT128 Xmm13; + SETJMP_FLOAT128 Xmm14; + SETJMP_FLOAT128 Xmm15; + } _JUMP_BUFFER; +#endif +#ifndef _JMP_BUF_DEFINED + typedef _JBTYPE jmp_buf[_JBLEN]; +#define _JMP_BUF_DEFINED +#endif + + void * __cdecl __attribute__ ((__nothrow__)) mingw_getsp(void); + +#ifdef USE_MINGW_SETJMP_TWO_ARGS +#ifndef _INC_SETJMPEX +#define setjmp(BUF) _setjmp((BUF),mingw_getsp()) + int __cdecl __attribute__ ((__nothrow__)) _setjmp(jmp_buf _Buf,void *_Ctx); +#else +#undef setjmp +#define setjmp(BUF) _setjmpex((BUF),mingw_getsp()) +#define setjmpex(BUF) _setjmpex((BUF),mingw_getsp()) + int __cdecl __attribute__ ((__nothrow__)) _setjmpex(jmp_buf _Buf,void *_Ctx); +#endif +#else +#ifndef _INC_SETJMPEX +#define setjmp _setjmp +#endif + int __cdecl __attribute__ ((__nothrow__)) setjmp(jmp_buf _Buf); +#endif + + __declspec(noreturn) __attribute__ ((__nothrow__)) void __cdecl ms_longjmp(jmp_buf _Buf,int _Value)/* throw(...)*/; + __declspec(noreturn) __attribute__ ((__nothrow__)) void __cdecl longjmp(jmp_buf _Buf,int _Value); + +#ifdef __cplusplus +} +#endif + +#pragma pack(pop) +#endif diff --git a/tinyc/win32/include/share.h b/tinyc/win32/include/share.h new file mode 100644 index 000000000..358855fe4 --- /dev/null +++ b/tinyc/win32/include/share.h @@ -0,0 +1,28 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _INC_SHARE +#define _INC_SHARE + +#ifndef _WIN32 +#error Only Win32 target is supported! +#endif + +#define _SH_COMPAT 0x00 +#define _SH_DENYRW 0x10 +#define _SH_DENYWR 0x20 +#define _SH_DENYRD 0x30 +#define _SH_DENYNO 0x40 +#define _SH_SECURE 0x80 + +#ifndef NO_OLDNAMES +#define SH_COMPAT _SH_COMPAT +#define SH_DENYRW _SH_DENYRW +#define SH_DENYWR _SH_DENYWR +#define SH_DENYRD _SH_DENYRD +#define SH_DENYNO _SH_DENYNO +#endif + +#endif diff --git a/tinyc/win32/include/signal.h b/tinyc/win32/include/signal.h new file mode 100644 index 000000000..a518f6b31 --- /dev/null +++ b/tinyc/win32/include/signal.h @@ -0,0 +1,63 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _INC_SIGNAL +#define _INC_SIGNAL + +#include <_mingw.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _SIG_ATOMIC_T_DEFINED +#define _SIG_ATOMIC_T_DEFINED + typedef int sig_atomic_t; +#endif + +#define NSIG 23 + +#define SIGHUP 1 /* hangup */ +#define SIGINT 2 +#define SIGQUIT 3 /* quit */ +#define SIGILL 4 +#define SIGTRAP 5 /* trace trap (not reset when caught) */ +#define SIGIOT 6 /* IOT instruction */ +#define SIGABRT 6 /* used by abort, replace SIGIOT in the future */ +#define SIGEMT 7 /* EMT instruction */ +#define SIGFPE 8 +#define SIGKILL 9 /* kill (cannot be caught or ignored) */ +#define SIGBUS 10 /* bus error */ +#define SIGSEGV 11 +#define SIGSYS 12 /* bad argument to system call */ +#define SIGPIPE 13 /* write on a pipe with no one to read it */ +#ifdef __USE_MINGW_ALARM +#define SIGALRM 14 /* alarm clock */ +#endif +#define SIGTERM 15 +#define SIGBREAK 21 +#define SIGABRT2 22 + +#define SIGABRT_COMPAT 6 + + typedef void (*__p_sig_fn_t)(int); + +#define SIG_DFL (__p_sig_fn_t)0 +#define SIG_IGN (__p_sig_fn_t)1 +#define SIG_GET (__p_sig_fn_t)2 +#define SIG_SGE (__p_sig_fn_t)3 +#define SIG_ACK (__p_sig_fn_t)4 +#define SIG_ERR (__p_sig_fn_t)-1 + + extern void **__cdecl __pxcptinfoptrs(void); +#define _pxcptinfoptrs (*__pxcptinfoptrs()) + + __p_sig_fn_t __cdecl signal(int _SigNum,__p_sig_fn_t _Func); + int __cdecl raise(int _SigNum); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/tinyc/win32/include/stdint.h b/tinyc/win32/include/stdint.h new file mode 100644 index 000000000..cde32b6e3 --- /dev/null +++ b/tinyc/win32/include/stdint.h @@ -0,0 +1,212 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +/* ISO C9x 7.18 Integer types + * Based on ISO/IEC SC22/WG14 9899 Committee draft (SC22 N2794) + * + * THIS SOFTWARE IS NOT COPYRIGHTED + * + * Contributor: Danny Smith + * + * This source code is offered for use in the public domain. You may + * use, modify or distribute it freely. + * + * This code is distributed in the hope that it will be useful but + * WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY + * DISCLAIMED. This includes but is not limited to warranties of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Date: 2000-12-02 + */ + + +#ifndef _STDINT_H +#define _STDINT_H + +#include <_mingw.h> + +#define __need_wint_t +#define __need_wchar_t +#include "stddef.h" + +#ifndef __int8_t_defined +#define __int8_t_defined +/* 7.18.1.1 Exact-width integer types */ +typedef signed char int8_t; +typedef unsigned char uint8_t; +typedef short int16_t; +typedef unsigned short uint16_t; +typedef int int32_t; +typedef unsigned uint32_t; +typedef long long int64_t; +typedef unsigned long long uint64_t; +#endif + +/* 7.18.1.2 Minimum-width integer types */ +typedef signed char int_least8_t; +typedef unsigned char uint_least8_t; +typedef short int_least16_t; +typedef unsigned short uint_least16_t; +typedef int int_least32_t; +typedef unsigned uint_least32_t; +typedef long long int_least64_t; +typedef unsigned long long uint_least64_t; + +/* 7.18.1.3 Fastest minimum-width integer types + * Not actually guaranteed to be fastest for all purposes + * Here we use the exact-width types for 8 and 16-bit ints. + */ +typedef char int_fast8_t; +typedef unsigned char uint_fast8_t; +typedef short int_fast16_t; +typedef unsigned short uint_fast16_t; +typedef int int_fast32_t; +typedef unsigned int uint_fast32_t; +typedef long long int_fast64_t; +typedef unsigned long long uint_fast64_t; + +/* 7.18.1.5 Greatest-width integer types */ +typedef long long intmax_t; +typedef unsigned long long uintmax_t; + +/* 7.18.2 Limits of specified-width integer types */ +#if !defined ( __cplusplus) || defined (__STDC_LIMIT_MACROS) + +/* 7.18.2.1 Limits of exact-width integer types */ +#define INT8_MIN (-128) +#define INT16_MIN (-32768) +#define INT32_MIN (-2147483647 - 1) +#define INT64_MIN (-9223372036854775807LL - 1) + +#define INT8_MAX 127 +#define INT16_MAX 32767 +#define INT32_MAX 2147483647 +#define INT64_MAX 9223372036854775807LL + +#define UINT8_MAX 0xff /* 255U */ +#define UINT16_MAX 0xffff /* 65535U */ +#define UINT32_MAX 0xffffffff /* 4294967295U */ +#define UINT64_MAX 0xffffffffffffffffULL /* 18446744073709551615ULL */ + +/* 7.18.2.2 Limits of minimum-width integer types */ +#define INT_LEAST8_MIN INT8_MIN +#define INT_LEAST16_MIN INT16_MIN +#define INT_LEAST32_MIN INT32_MIN +#define INT_LEAST64_MIN INT64_MIN + +#define INT_LEAST8_MAX INT8_MAX +#define INT_LEAST16_MAX INT16_MAX +#define INT_LEAST32_MAX INT32_MAX +#define INT_LEAST64_MAX INT64_MAX + +#define UINT_LEAST8_MAX UINT8_MAX +#define UINT_LEAST16_MAX UINT16_MAX +#define UINT_LEAST32_MAX UINT32_MAX +#define UINT_LEAST64_MAX UINT64_MAX + +/* 7.18.2.3 Limits of fastest minimum-width integer types */ +#define INT_FAST8_MIN INT8_MIN +#define INT_FAST16_MIN INT16_MIN +#define INT_FAST32_MIN INT32_MIN +#define INT_FAST64_MIN INT64_MIN + +#define INT_FAST8_MAX INT8_MAX +#define INT_FAST16_MAX INT16_MAX +#define INT_FAST32_MAX INT32_MAX +#define INT_FAST64_MAX INT64_MAX + +#define UINT_FAST8_MAX UINT8_MAX +#define UINT_FAST16_MAX UINT16_MAX +#define UINT_FAST32_MAX UINT32_MAX +#define UINT_FAST64_MAX UINT64_MAX + +/* 7.18.2.4 Limits of integer types capable of holding + object pointers */ +#ifdef _WIN64 +#define INTPTR_MIN INT64_MIN +#define INTPTR_MAX INT64_MAX +#define UINTPTR_MAX UINT64_MAX +#else +#define INTPTR_MIN INT32_MIN +#define INTPTR_MAX INT32_MAX +#define UINTPTR_MAX UINT32_MAX +#endif + +/* 7.18.2.5 Limits of greatest-width integer types */ +#define INTMAX_MIN INT64_MIN +#define INTMAX_MAX INT64_MAX +#define UINTMAX_MAX UINT64_MAX + +/* 7.18.3 Limits of other integer types */ +#ifdef _WIN64 +#define PTRDIFF_MIN INT64_MIN +#define PTRDIFF_MAX INT64_MAX +#else +#define PTRDIFF_MIN INT32_MIN +#define PTRDIFF_MAX INT32_MAX +#endif + +#define SIG_ATOMIC_MIN INT32_MIN +#define SIG_ATOMIC_MAX INT32_MAX + +#ifndef SIZE_MAX +#ifdef _WIN64 +#define SIZE_MAX UINT64_MAX +#else +#define SIZE_MAX UINT32_MAX +#endif +#endif + +#ifndef WCHAR_MIN /* also in wchar.h */ +#define WCHAR_MIN 0 +#define WCHAR_MAX ((wchar_t)-1) /* UINT16_MAX */ +#endif + +/* + * wint_t is unsigned short for compatibility with MS runtime + */ +#define WINT_MIN 0 +#define WINT_MAX ((wint_t)-1) /* UINT16_MAX */ + +#endif /* !defined ( __cplusplus) || defined __STDC_LIMIT_MACROS */ + + +/* 7.18.4 Macros for integer constants */ +#if !defined ( __cplusplus) || defined (__STDC_CONSTANT_MACROS) + +/* 7.18.4.1 Macros for minimum-width integer constants + + According to Douglas Gwyn : + "This spec was changed in ISO/IEC 9899:1999 TC1; in ISO/IEC + 9899:1999 as initially published, the expansion was required + to be an integer constant of precisely matching type, which + is impossible to accomplish for the shorter types on most + platforms, because C99 provides no standard way to designate + an integer constant with width less than that of type int. + TC1 changed this to require just an integer constant + *expression* with *promoted* type." + + The trick used here is from Clive D W Feather. +*/ + +#define INT8_C(val) (INT_LEAST8_MAX-INT_LEAST8_MAX+(val)) +#define INT16_C(val) (INT_LEAST16_MAX-INT_LEAST16_MAX+(val)) +#define INT32_C(val) (INT_LEAST32_MAX-INT_LEAST32_MAX+(val)) +/* The 'trick' doesn't work in C89 for long long because, without + suffix, (val) will be evaluated as int, not intmax_t */ +#define INT64_C(val) val##LL + +#define UINT8_C(val) (UINT_LEAST8_MAX-UINT_LEAST8_MAX+(val)) +#define UINT16_C(val) (UINT_LEAST16_MAX-UINT_LEAST16_MAX+(val)) +#define UINT32_C(val) (UINT_LEAST32_MAX-UINT_LEAST32_MAX+(val)) +#define UINT64_C(val) val##ULL + +/* 7.18.4.2 Macros for greatest-width integer constants */ +#define INTMAX_C(val) val##LL +#define UINTMAX_C(val) val##ULL + +#endif /* !defined ( __cplusplus) || defined __STDC_CONSTANT_MACROS */ + +#endif diff --git a/tinyc/win32/include/stdio.h b/tinyc/win32/include/stdio.h new file mode 100644 index 000000000..da887936a --- /dev/null +++ b/tinyc/win32/include/stdio.h @@ -0,0 +1,429 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _INC_STDIO +#define _INC_STDIO + +#include <_mingw.h> + +#pragma pack(push,_CRT_PACKING) + +#ifdef __cplusplus +extern "C" { +#endif + +#define BUFSIZ 512 +#define _NFILE _NSTREAM_ +#define _NSTREAM_ 512 +#define _IOB_ENTRIES 20 +#define EOF (-1) + +#ifndef _FILE_DEFINED + struct _iobuf { + char *_ptr; + int _cnt; + char *_base; + int _flag; + int _file; + int _charbuf; + int _bufsiz; + char *_tmpfname; + }; + typedef struct _iobuf FILE; +#define _FILE_DEFINED +#endif + +#ifdef _POSIX_ +#define _P_tmpdir "/" +#define _wP_tmpdir L"/" +#else +#define _P_tmpdir "\\" +#define _wP_tmpdir L"\\" +#endif + +#define L_tmpnam (sizeof(_P_tmpdir) + 12) + +#ifdef _POSIX_ +#define L_ctermid 9 +#define L_cuserid 32 +#endif + +#define SEEK_CUR 1 +#define SEEK_END 2 +#define SEEK_SET 0 + +#define STDIN_FILENO 0 +#define STDOUT_FILENO 1 +#define STDERR_FILENO 2 + +#define FILENAME_MAX 260 +#define FOPEN_MAX 20 +#define _SYS_OPEN 20 +#define TMP_MAX 32767 + +#ifndef NULL +#ifdef __cplusplus +#define NULL 0 +#else +#define NULL ((void *)0) +#endif +#endif + +#ifndef _OFF_T_DEFINED +#define _OFF_T_DEFINED +#ifndef _OFF_T_ +#define _OFF_T_ + typedef long _off_t; +#if !defined(NO_OLDNAMES) || defined(_POSIX) + typedef long off_t; +#endif +#endif +#endif + +#ifndef _OFF64_T_DEFINED +#define _OFF64_T_DEFINED + typedef long long _off64_t; +#if !defined(NO_OLDNAMES) || defined(_POSIX) + typedef long long off64_t; +#endif +#endif + +#ifndef _STDIO_DEFINED +#ifdef _WIN64 + _CRTIMP FILE *__cdecl __iob_func(void); +#else +#ifdef _MSVCRT_ +extern FILE _iob[]; /* A pointer to an array of FILE */ +#define __iob_func() (_iob) +#else +extern FILE (*_imp___iob)[]; /* A pointer to an array of FILE */ +#define __iob_func() (*_imp___iob) +#define _iob __iob_func() +#endif +#endif +#endif + +#ifndef _FPOS_T_DEFINED +#define _FPOS_T_DEFINED +#undef _FPOSOFF + +#if (!defined(NO_OLDNAMES) || defined(__GNUC__)) && _INTEGRAL_MAX_BITS >= 64 + typedef __int64 fpos_t; +#define _FPOSOFF(fp) ((long)(fp)) +#else + typedef long long fpos_t; +#define _FPOSOFF(fp) ((long)(fp)) +#endif + +#endif + +#ifndef _STDSTREAM_DEFINED +#define _STDSTREAM_DEFINED + +#define stdin (&__iob_func()[0]) +#define stdout (&__iob_func()[1]) +#define stderr (&__iob_func()[2]) +#endif + +#define _IOREAD 0x0001 +#define _IOWRT 0x0002 + +#define _IOFBF 0x0000 +#define _IOLBF 0x0040 +#define _IONBF 0x0004 + +#define _IOMYBUF 0x0008 +#define _IOEOF 0x0010 +#define _IOERR 0x0020 +#define _IOSTRG 0x0040 +#define _IORW 0x0080 +#ifdef _POSIX_ +#define _IOAPPEND 0x0200 +#endif + +#define _TWO_DIGIT_EXPONENT 0x1 + +#ifndef _STDIO_DEFINED + + _CRTIMP int __cdecl _filbuf(FILE *_File); + _CRTIMP int __cdecl _flsbuf(int _Ch,FILE *_File); +#ifdef _POSIX_ + _CRTIMP FILE *__cdecl _fsopen(const char *_Filename,const char *_Mode); +#else + _CRTIMP FILE *__cdecl _fsopen(const char *_Filename,const char *_Mode,int _ShFlag); +#endif + void __cdecl clearerr(FILE *_File); + int __cdecl fclose(FILE *_File); + _CRTIMP int __cdecl _fcloseall(void); +#ifdef _POSIX_ + FILE *__cdecl fdopen(int _FileHandle,const char *_Mode); +#else + _CRTIMP FILE *__cdecl _fdopen(int _FileHandle,const char *_Mode); +#endif + int __cdecl feof(FILE *_File); + int __cdecl ferror(FILE *_File); + int __cdecl fflush(FILE *_File); + int __cdecl fgetc(FILE *_File); + _CRTIMP int __cdecl _fgetchar(void); + int __cdecl fgetpos(FILE *_File ,fpos_t *_Pos); + char *__cdecl fgets(char *_Buf,int _MaxCount,FILE *_File); +#ifdef _POSIX_ + int __cdecl fileno(FILE *_File); +#else + _CRTIMP int __cdecl _fileno(FILE *_File); +#endif + _CRTIMP char *__cdecl _tempnam(const char *_DirName,const char *_FilePrefix); + _CRTIMP int __cdecl _flushall(void); + FILE *__cdecl fopen(const char *_Filename,const char *_Mode); + FILE *fopen64(const char *filename,const char *mode); + int __cdecl fprintf(FILE *_File,const char *_Format,...); + int __cdecl fputc(int _Ch,FILE *_File); + _CRTIMP int __cdecl _fputchar(int _Ch); + int __cdecl fputs(const char *_Str,FILE *_File); + size_t __cdecl fread(void *_DstBuf,size_t _ElementSize,size_t _Count,FILE *_File); + FILE *__cdecl freopen(const char *_Filename,const char *_Mode,FILE *_File); + int __cdecl fscanf(FILE *_File,const char *_Format,...); + int __cdecl fsetpos(FILE *_File,const fpos_t *_Pos); + int __cdecl fseek(FILE *_File,long _Offset,int _Origin); + int fseeko64(FILE* stream, _off64_t offset, int whence); + long __cdecl ftell(FILE *_File); + _off64_t ftello64(FILE * stream); + int __cdecl _fseeki64(FILE *_File,__int64 _Offset,int _Origin); + __int64 __cdecl _ftelli64(FILE *_File); + size_t __cdecl fwrite(const void *_Str,size_t _Size,size_t _Count,FILE *_File); + int __cdecl getc(FILE *_File); + int __cdecl getchar(void); + _CRTIMP int __cdecl _getmaxstdio(void); + char *__cdecl gets(char *_Buffer); + int __cdecl _getw(FILE *_File); +#ifndef _CRT_PERROR_DEFINED +#define _CRT_PERROR_DEFINED + void __cdecl perror(const char *_ErrMsg); +#endif + _CRTIMP int __cdecl _pclose(FILE *_File); + _CRTIMP FILE *__cdecl _popen(const char *_Command,const char *_Mode); +#if !defined(NO_OLDNAMES) && !defined(popen) +#define popen _popen +#define pclose _pclose +#endif + int __cdecl printf(const char *_Format,...); + int __cdecl putc(int _Ch,FILE *_File); + int __cdecl putchar(int _Ch); + int __cdecl puts(const char *_Str); + _CRTIMP int __cdecl _putw(int _Word,FILE *_File); +#ifndef _CRT_DIRECTORY_DEFINED +#define _CRT_DIRECTORY_DEFINED + int __cdecl remove(const char *_Filename); + int __cdecl rename(const char *_OldFilename,const char *_NewFilename); + _CRTIMP int __cdecl _unlink(const char *_Filename); +#ifndef NO_OLDNAMES + int __cdecl unlink(const char *_Filename); +#endif +#endif + void __cdecl rewind(FILE *_File); + _CRTIMP int __cdecl _rmtmp(void); + int __cdecl scanf(const char *_Format,...); + void __cdecl setbuf(FILE *_File,char *_Buffer); + _CRTIMP int __cdecl _setmaxstdio(int _Max); + _CRTIMP unsigned int __cdecl _set_output_format(unsigned int _Format); + _CRTIMP unsigned int __cdecl _get_output_format(void); + int __cdecl setvbuf(FILE *_File,char *_Buf,int _Mode,size_t _Size); + _CRTIMP int __cdecl _scprintf(const char *_Format,...); + int __cdecl sscanf(const char *_Src,const char *_Format,...); + _CRTIMP int __cdecl _snscanf(const char *_Src,size_t _MaxCount,const char *_Format,...); + FILE *__cdecl tmpfile(void); + char *__cdecl tmpnam(char *_Buffer); + int __cdecl ungetc(int _Ch,FILE *_File); + int __cdecl vfprintf(FILE *_File,const char *_Format,va_list _ArgList); + int __cdecl vprintf(const char *_Format,va_list _ArgList); + /* Make sure macros are not defined. */ +#pragma push_macro("vsnprintf") +#pragma push_macro("snprintf") +# undef vsnprintf +# undef snprintf + extern + __attribute__((format(gnu_printf, 3, 0))) __attribute__((nonnull (3))) + int __mingw_vsnprintf(char *_DstBuf,size_t _MaxCount,const char *_Format,va_list _ArgList); + extern + __attribute__((format(gnu_printf, 3, 4))) __attribute__((nonnull (3))) + int __mingw_snprintf(char* s, size_t n, const char* format, ...); + int __cdecl vsnprintf(char *_DstBuf,size_t _MaxCount,const char *_Format,va_list _ArgList); + _CRTIMP int __cdecl _snprintf(char *_Dest,size_t _Count,const char *_Format,...); + _CRTIMP int __cdecl _vsnprintf(char *_Dest,size_t _Count,const char *_Format,va_list _Args); + int __cdecl sprintf(char *_Dest,const char *_Format,...); + int __cdecl vsprintf(char *_Dest,const char *_Format,va_list _Args); +#ifndef __NO_ISOCEXT /* externs in libmingwex.a */ + int __cdecl snprintf(char* s, size_t n, const char* format, ...); + __CRT_INLINE int __cdecl vsnprintf (char* s, size_t n, const char* format,va_list arg) { + return _vsnprintf ( s, n, format, arg); + } + int __cdecl vscanf(const char * Format, va_list argp); + int __cdecl vfscanf (FILE * fp, const char * Format,va_list argp); + int __cdecl vsscanf (const char * _Str,const char * Format,va_list argp); +#endif +/* Restore may prior defined macros snprintf/vsnprintf. */ +#pragma pop_macro("snprintf") +#pragma pop_macro("vsnprintf") +/* Check if vsnprintf and snprintf are defaulting to gnu-style. */ +# if defined(USE_MINGW_GNU_SNPRINTF) && USE_MINGW_GNU_SNPRINTF +# ifndef vsnprint +# define vsnprintf __mingw_vsnprintf +# endif +# ifndef snprintf +# define snprintf __mingw_snprintf +# endif +# endif + _CRTIMP int __cdecl _vscprintf(const char *_Format,va_list _ArgList); + _CRTIMP int __cdecl _set_printf_count_output(int _Value); + _CRTIMP int __cdecl _get_printf_count_output(void); + +#ifndef _WSTDIO_DEFINED + +#ifndef WEOF +#define WEOF (wint_t)(0xFFFF) +#endif + +#ifdef _POSIX_ + _CRTIMP FILE *__cdecl _wfsopen(const wchar_t *_Filename,const wchar_t *_Mode); +#else + _CRTIMP FILE *__cdecl _wfsopen(const wchar_t *_Filename,const wchar_t *_Mode,int _ShFlag); +#endif + wint_t __cdecl fgetwc(FILE *_File); + _CRTIMP wint_t __cdecl _fgetwchar(void); + wint_t __cdecl fputwc(wchar_t _Ch,FILE *_File); + _CRTIMP wint_t __cdecl _fputwchar(wchar_t _Ch); + wint_t __cdecl getwc(FILE *_File); + wint_t __cdecl getwchar(void); + wint_t __cdecl putwc(wchar_t _Ch,FILE *_File); + wint_t __cdecl putwchar(wchar_t _Ch); + wint_t __cdecl ungetwc(wint_t _Ch,FILE *_File); + wchar_t *__cdecl fgetws(wchar_t *_Dst,int _SizeInWords,FILE *_File); + int __cdecl fputws(const wchar_t *_Str,FILE *_File); + _CRTIMP wchar_t *__cdecl _getws(wchar_t *_String); + _CRTIMP int __cdecl _putws(const wchar_t *_Str); + int __cdecl fwprintf(FILE *_File,const wchar_t *_Format,...); + int __cdecl wprintf(const wchar_t *_Format,...); + _CRTIMP int __cdecl _scwprintf(const wchar_t *_Format,...); + int __cdecl vfwprintf(FILE *_File,const wchar_t *_Format,va_list _ArgList); + int __cdecl vwprintf(const wchar_t *_Format,va_list _ArgList); + _CRTIMP int __cdecl swprintf(wchar_t*, const wchar_t*, ...); + _CRTIMP int __cdecl vswprintf(wchar_t*, const wchar_t*,va_list); + _CRTIMP int __cdecl _swprintf_c(wchar_t *_DstBuf,size_t _SizeInWords,const wchar_t *_Format,...); + _CRTIMP int __cdecl _vswprintf_c(wchar_t *_DstBuf,size_t _SizeInWords,const wchar_t *_Format,va_list _ArgList); + _CRTIMP int __cdecl _snwprintf(wchar_t *_Dest,size_t _Count,const wchar_t *_Format,...); + _CRTIMP int __cdecl _vsnwprintf(wchar_t *_Dest,size_t _Count,const wchar_t *_Format,va_list _Args); +#ifndef __NO_ISOCEXT /* externs in libmingwex.a */ + int __cdecl snwprintf (wchar_t* s, size_t n, const wchar_t* format, ...); + __CRT_INLINE int __cdecl vsnwprintf (wchar_t* s, size_t n, const wchar_t* format, va_list arg) { return _vsnwprintf(s,n,format,arg); } + int __cdecl vwscanf (const wchar_t *, va_list); + int __cdecl vfwscanf (FILE *,const wchar_t *,va_list); + int __cdecl vswscanf (const wchar_t *,const wchar_t *,va_list); +#endif + _CRTIMP int __cdecl _swprintf(wchar_t *_Dest,const wchar_t *_Format,...); + _CRTIMP int __cdecl _vswprintf(wchar_t *_Dest,const wchar_t *_Format,va_list _Args); + +#ifndef RC_INVOKED +#include +#endif + +#ifdef _CRT_NON_CONFORMING_SWPRINTFS +#ifndef __cplusplus +#define swprintf _swprintf +#define vswprintf _vswprintf +#define _swprintf_l __swprintf_l +#define _vswprintf_l __vswprintf_l +#endif +#endif + + _CRTIMP wchar_t *__cdecl _wtempnam(const wchar_t *_Directory,const wchar_t *_FilePrefix); + _CRTIMP int __cdecl _vscwprintf(const wchar_t *_Format,va_list _ArgList); + int __cdecl fwscanf(FILE *_File,const wchar_t *_Format,...); + int __cdecl swscanf(const wchar_t *_Src,const wchar_t *_Format,...); + _CRTIMP int __cdecl _snwscanf(const wchar_t *_Src,size_t _MaxCount,const wchar_t *_Format,...); + int __cdecl wscanf(const wchar_t *_Format,...); + _CRTIMP FILE *__cdecl _wfdopen(int _FileHandle ,const wchar_t *_Mode); + _CRTIMP FILE *__cdecl _wfopen(const wchar_t *_Filename,const wchar_t *_Mode); + _CRTIMP FILE *__cdecl _wfreopen(const wchar_t *_Filename,const wchar_t *_Mode,FILE *_OldFile); +#ifndef _CRT_WPERROR_DEFINED +#define _CRT_WPERROR_DEFINED + _CRTIMP void __cdecl _wperror(const wchar_t *_ErrMsg); +#endif + _CRTIMP FILE *__cdecl _wpopen(const wchar_t *_Command,const wchar_t *_Mode); +#if !defined(NO_OLDNAMES) && !defined(wpopen) +#define wpopen _wpopen +#endif + _CRTIMP int __cdecl _wremove(const wchar_t *_Filename); + _CRTIMP wchar_t *__cdecl _wtmpnam(wchar_t *_Buffer); + _CRTIMP wint_t __cdecl _fgetwc_nolock(FILE *_File); + _CRTIMP wint_t __cdecl _fputwc_nolock(wchar_t _Ch,FILE *_File); + _CRTIMP wint_t __cdecl _ungetwc_nolock(wint_t _Ch,FILE *_File); + +#undef _CRT_GETPUTWCHAR_NOINLINE + +#if !defined(__cplusplus) || defined(_CRT_GETPUTWCHAR_NOINLINE) +#define getwchar() fgetwc(stdin) +#define putwchar(_c) fputwc((_c),stdout) +#else + __CRT_INLINE wint_t __cdecl getwchar() { return (fgetwc(stdin)); } + __CRT_INLINE wint_t __cdecl putwchar(wchar_t _C) { return (fputwc(_C,stdout)); } +#endif + +#define getwc(_stm) fgetwc(_stm) +#define putwc(_c,_stm) fputwc(_c,_stm) +#define _putwc_nolock(_c,_stm) _fputwc_nolock(_c,_stm) +#define _getwc_nolock(_stm) _fgetwc_nolock(_stm) + +#define _WSTDIO_DEFINED +#endif + +#define _STDIO_DEFINED +#endif + +#define _fgetc_nolock(_stream) (--(_stream)->_cnt >= 0 ? 0xff & *(_stream)->_ptr++ : _filbuf(_stream)) +#define _fputc_nolock(_c,_stream) (--(_stream)->_cnt >= 0 ? 0xff & (*(_stream)->_ptr++ = (char)(_c)) : _flsbuf((_c),(_stream))) +#define _getc_nolock(_stream) _fgetc_nolock(_stream) +#define _putc_nolock(_c,_stream) _fputc_nolock(_c,_stream) +#define _getchar_nolock() _getc_nolock(stdin) +#define _putchar_nolock(_c) _putc_nolock((_c),stdout) +#define _getwchar_nolock() _getwc_nolock(stdin) +#define _putwchar_nolock(_c) _putwc_nolock((_c),stdout) + + _CRTIMP void __cdecl _lock_file(FILE *_File); + _CRTIMP void __cdecl _unlock_file(FILE *_File); + _CRTIMP int __cdecl _fclose_nolock(FILE *_File); + _CRTIMP int __cdecl _fflush_nolock(FILE *_File); + _CRTIMP size_t __cdecl _fread_nolock(void *_DstBuf,size_t _ElementSize,size_t _Count,FILE *_File); + _CRTIMP int __cdecl _fseek_nolock(FILE *_File,long _Offset,int _Origin); + _CRTIMP long __cdecl _ftell_nolock(FILE *_File); + _CRTIMP int __cdecl _fseeki64_nolock(FILE *_File,__int64 _Offset,int _Origin); + _CRTIMP __int64 __cdecl _ftelli64_nolock(FILE *_File); + _CRTIMP size_t __cdecl _fwrite_nolock(const void *_DstBuf,size_t _Size,size_t _Count,FILE *_File); + _CRTIMP int __cdecl _ungetc_nolock(int _Ch,FILE *_File); + +#if !defined(NO_OLDNAMES) || !defined(_POSIX) +#define P_tmpdir _P_tmpdir +#define SYS_OPEN _SYS_OPEN + + char *__cdecl tempnam(const char *_Directory,const char *_FilePrefix); + int __cdecl fcloseall(void); + FILE *__cdecl fdopen(int _FileHandle,const char *_Format); + int __cdecl fgetchar(void); + int __cdecl fileno(FILE *_File); + int __cdecl flushall(void); + int __cdecl fputchar(int _Ch); + int __cdecl getw(FILE *_File); + int __cdecl putw(int _Ch,FILE *_File); + int __cdecl rmtmp(void); +#endif + +#ifdef __cplusplus +} +#endif + +#pragma pack(pop) + +#include + +#endif diff --git a/tinyc/win32/include/stdlib.h b/tinyc/win32/include/stdlib.h new file mode 100644 index 000000000..96765b29e --- /dev/null +++ b/tinyc/win32/include/stdlib.h @@ -0,0 +1,580 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _INC_STDLIB +#define _INC_STDLIB + +#include <_mingw.h> +#include + +#pragma pack(push,_CRT_PACKING) + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef NULL +#ifdef __cplusplus +#define NULL 0 +#else +#define NULL ((void *)0) +#endif +#endif + +#define EXIT_SUCCESS 0 +#define EXIT_FAILURE 1 + +#ifndef _ONEXIT_T_DEFINED +#define _ONEXIT_T_DEFINED + + typedef int (__cdecl *_onexit_t)(void); + +#ifndef NO_OLDNAMES +#define onexit_t _onexit_t +#endif +#endif + +#ifndef _DIV_T_DEFINED +#define _DIV_T_DEFINED + + typedef struct _div_t { + int quot; + int rem; + } div_t; + + typedef struct _ldiv_t { + long quot; + long rem; + } ldiv_t; +#endif + +#ifndef _CRT_DOUBLE_DEC +#define _CRT_DOUBLE_DEC + +#pragma pack(4) + typedef struct { + unsigned char ld[10]; + } _LDOUBLE; +#pragma pack() + +#define _PTR_LD(x) ((unsigned char *)(&(x)->ld)) + + typedef struct { + double x; + } _CRT_DOUBLE; + + typedef struct { + float f; + } _CRT_FLOAT; + +#pragma push_macro("long") +#undef long + + typedef struct { + long double x; + } _LONGDOUBLE; + +#pragma pop_macro("long") + +#pragma pack(4) + typedef struct { + unsigned char ld12[12]; + } _LDBL12; +#pragma pack() +#endif + +#define RAND_MAX 0x7fff + +#ifndef MB_CUR_MAX +#define MB_CUR_MAX ___mb_cur_max_func() +#ifndef __mb_cur_max +#ifdef _MSVCRT_ + extern int __mb_cur_max; +#else +#define __mb_cur_max (*_imp____mb_cur_max) + extern int *_imp____mb_cur_max; +#endif +#endif +#ifdef _MSVCRT_ + extern int __mbcur_max; +#define ___mb_cur_max_func() (__mb_cur_max) +#else + extern int* _imp____mbcur_max; +#define ___mb_cur_max_func() (*_imp____mb_cur_max) +#endif +#endif + +#define __max(a,b) (((a) > (b)) ? (a) : (b)) +#define __min(a,b) (((a) < (b)) ? (a) : (b)) + +#define _MAX_PATH 260 +#define _MAX_DRIVE 3 +#define _MAX_DIR 256 +#define _MAX_FNAME 256 +#define _MAX_EXT 256 + +#define _OUT_TO_DEFAULT 0 +#define _OUT_TO_STDERR 1 +#define _OUT_TO_MSGBOX 2 +#define _REPORT_ERRMODE 3 + +#define _WRITE_ABORT_MSG 0x1 +#define _CALL_REPORTFAULT 0x2 + +#define _MAX_ENV 32767 + + typedef void (__cdecl *_purecall_handler)(void); + + _CRTIMP _purecall_handler __cdecl _set_purecall_handler(_purecall_handler _Handler); + _CRTIMP _purecall_handler __cdecl _get_purecall_handler(void); + + typedef void (__cdecl *_invalid_parameter_handler)(const wchar_t *,const wchar_t *,const wchar_t *,unsigned int,uintptr_t); + _invalid_parameter_handler __cdecl _set_invalid_parameter_handler(_invalid_parameter_handler _Handler); + _invalid_parameter_handler __cdecl _get_invalid_parameter_handler(void); + +#ifndef _CRT_ERRNO_DEFINED +#define _CRT_ERRNO_DEFINED + _CRTIMP extern int *__cdecl _errno(void); +#define errno (*_errno()) + errno_t __cdecl _set_errno(int _Value); + errno_t __cdecl _get_errno(int *_Value); +#endif + _CRTIMP unsigned long *__cdecl __doserrno(void); +#define _doserrno (*__doserrno()) + errno_t __cdecl _set_doserrno(unsigned long _Value); + errno_t __cdecl _get_doserrno(unsigned long *_Value); +#ifdef _MSVCRT_ + extern char *_sys_errlist[]; + extern int _sys_nerr; +#else + _CRTIMP char *_sys_errlist[1]; + _CRTIMP int _sys_nerr; +#endif +#if (defined(_X86_) && !defined(__x86_64)) + _CRTIMP int *__cdecl __p___argc(void); + _CRTIMP char ***__cdecl __p___argv(void); + _CRTIMP wchar_t ***__cdecl __p___wargv(void); + _CRTIMP char ***__cdecl __p__environ(void); + _CRTIMP wchar_t ***__cdecl __p__wenviron(void); + _CRTIMP char **__cdecl __p__pgmptr(void); + _CRTIMP wchar_t **__cdecl __p__wpgmptr(void); +#endif +#ifndef __argc +#ifdef _MSVCRT_ + extern int __argc; +#else +#define __argc (*_imp____argc) + extern int *_imp____argc; +#endif +#endif +#ifndef __argv +#ifdef _MSVCRT_ + extern char **__argv; +#else +#define __argv (*_imp____argv) + extern char ***_imp____argv; +#endif +#endif +#ifndef __wargv +#ifdef _MSVCRT_ + extern wchar_t **__wargv; +#else +#define __wargv (*_imp____wargv) + extern wchar_t ***_imp____wargv; +#endif +#endif + +#ifdef _POSIX_ + extern char **environ; +#else +#ifndef _environ +#ifdef _MSVCRT_ + extern char **_environ; +#else +#define _environ (*_imp___environ) + extern char ***_imp___environ; +#endif +#endif + +#ifndef _wenviron +#ifdef _MSVCRT_ + extern wchar_t **_wenviron; +#else +#define _wenviron (*_imp___wenviron) + extern wchar_t ***_imp___wenviron; +#endif +#endif +#endif +#ifndef _pgmptr +#ifdef _MSVCRT_ + extern char *_pgmptr; +#else +#define _pgmptr (*_imp___pgmptr) + extern char **_imp___pgmptr; +#endif +#endif + +#ifndef _wpgmptr +#ifdef _MSVCRT_ + extern wchar_t *_wpgmptr; +#else +#define _wpgmptr (*_imp___wpgmptr) + extern wchar_t **_imp___wpgmptr; +#endif +#endif + errno_t __cdecl _get_pgmptr(char **_Value); + errno_t __cdecl _get_wpgmptr(wchar_t **_Value); +#ifndef _fmode +#ifdef _MSVCRT_ + extern int _fmode; +#else +#define _fmode (*_imp___fmode) + extern int *_imp___fmode; +#endif +#endif + _CRTIMP errno_t __cdecl _set_fmode(int _Mode); + _CRTIMP errno_t __cdecl _get_fmode(int *_PMode); + +#ifndef _osplatform +#ifdef _MSVCRT_ + extern unsigned int _osplatform; +#else +#define _osplatform (*_imp___osplatform) + extern unsigned int *_imp___osplatform; +#endif +#endif + +#ifndef _osver +#ifdef _MSVCRT_ + extern unsigned int _osver; +#else +#define _osver (*_imp___osver) + extern unsigned int *_imp___osver; +#endif +#endif + +#ifndef _winver +#ifdef _MSVCRT_ + extern unsigned int _winver; +#else +#define _winver (*_imp___winver) + extern unsigned int *_imp___winver; +#endif +#endif + +#ifndef _winmajor +#ifdef _MSVCRT_ + extern unsigned int _winmajor; +#else +#define _winmajor (*_imp___winmajor) + extern unsigned int *_imp___winmajor; +#endif +#endif + +#ifndef _winminor +#ifdef _MSVCRT_ + extern unsigned int _winminor; +#else +#define _winminor (*_imp___winminor) + extern unsigned int *_imp___winminor; +#endif +#endif + + errno_t __cdecl _get_osplatform(unsigned int *_Value); + errno_t __cdecl _get_osver(unsigned int *_Value); + errno_t __cdecl _get_winver(unsigned int *_Value); + errno_t __cdecl _get_winmajor(unsigned int *_Value); + errno_t __cdecl _get_winminor(unsigned int *_Value); +#ifndef _countof +#ifndef __cplusplus +#define _countof(_Array) (sizeof(_Array) / sizeof(_Array[0])) +#else + extern "C++" { + template char (*__countof_helper(UNALIGNED _CountofType (&_Array)[_SizeOfArray]))[_SizeOfArray]; +#define _countof(_Array) sizeof(*__countof_helper(_Array)) + } +#endif +#endif + +#ifndef _CRT_TERMINATE_DEFINED +#define _CRT_TERMINATE_DEFINED + void __cdecl __MINGW_NOTHROW exit(int _Code) __MINGW_ATTRIB_NORETURN; + _CRTIMP void __cdecl __MINGW_NOTHROW _exit(int _Code) __MINGW_ATTRIB_NORETURN; +#if !defined __NO_ISOCEXT /* extern stub in static libmingwex.a */ + /* C99 function name */ + void __cdecl _Exit(int) __MINGW_ATTRIB_NORETURN; + __CRT_INLINE __MINGW_ATTRIB_NORETURN void __cdecl _Exit(int status) + { _exit(status); } +#endif + +#pragma push_macro("abort") +#undef abort + void __cdecl __declspec(noreturn) abort(void); +#pragma pop_macro("abort") + +#endif + + _CRTIMP unsigned int __cdecl _set_abort_behavior(unsigned int _Flags,unsigned int _Mask); + +#ifndef _CRT_ABS_DEFINED +#define _CRT_ABS_DEFINED + int __cdecl abs(int _X); + long __cdecl labs(long _X); +#endif + +#if _INTEGRAL_MAX_BITS >= 64 + __int64 __cdecl _abs64(__int64); +#endif + int __cdecl atexit(void (__cdecl *)(void)); +#ifndef _CRT_ATOF_DEFINED +#define _CRT_ATOF_DEFINED + double __cdecl atof(const char *_String); + double __cdecl _atof_l(const char *_String,_locale_t _Locale); +#endif + int __cdecl atoi(const char *_Str); + _CRTIMP int __cdecl _atoi_l(const char *_Str,_locale_t _Locale); + long __cdecl atol(const char *_Str); + _CRTIMP long __cdecl _atol_l(const char *_Str,_locale_t _Locale); +#ifndef _CRT_ALGO_DEFINED +#define _CRT_ALGO_DEFINED + void *__cdecl bsearch(const void *_Key,const void *_Base,size_t _NumOfElements,size_t _SizeOfElements,int (__cdecl *_PtFuncCompare)(const void *,const void *)); + void __cdecl qsort(void *_Base,size_t _NumOfElements,size_t _SizeOfElements,int (__cdecl *_PtFuncCompare)(const void *,const void *)); +#endif + unsigned short __cdecl _byteswap_ushort(unsigned short _Short); + /*unsigned long __cdecl _byteswap_ulong (unsigned long _Long); */ +#if _INTEGRAL_MAX_BITS >= 64 + unsigned __int64 __cdecl _byteswap_uint64(unsigned __int64 _Int64); +#endif + div_t __cdecl div(int _Numerator,int _Denominator); + char *__cdecl getenv(const char *_VarName); + _CRTIMP char *__cdecl _itoa(int _Value,char *_Dest,int _Radix); +#if _INTEGRAL_MAX_BITS >= 64 + _CRTIMP char *__cdecl _i64toa(__int64 _Val,char *_DstBuf,int _Radix); + _CRTIMP char *__cdecl _ui64toa(unsigned __int64 _Val,char *_DstBuf,int _Radix); + _CRTIMP __int64 __cdecl _atoi64(const char *_String); + _CRTIMP __int64 __cdecl _atoi64_l(const char *_String,_locale_t _Locale); + _CRTIMP __int64 __cdecl _strtoi64(const char *_String,char **_EndPtr,int _Radix); + _CRTIMP __int64 __cdecl _strtoi64_l(const char *_String,char **_EndPtr,int _Radix,_locale_t _Locale); + _CRTIMP unsigned __int64 __cdecl _strtoui64(const char *_String,char **_EndPtr,int _Radix); + _CRTIMP unsigned __int64 __cdecl _strtoui64_l(const char *_String,char **_EndPtr,int _Radix,_locale_t _Locale); +#endif + ldiv_t __cdecl ldiv(long _Numerator,long _Denominator); + _CRTIMP char *__cdecl _ltoa(long _Value,char *_Dest,int _Radix); + int __cdecl mblen(const char *_Ch,size_t _MaxCount); + _CRTIMP int __cdecl _mblen_l(const char *_Ch,size_t _MaxCount,_locale_t _Locale); + _CRTIMP size_t __cdecl _mbstrlen(const char *_Str); + _CRTIMP size_t __cdecl _mbstrlen_l(const char *_Str,_locale_t _Locale); + _CRTIMP size_t __cdecl _mbstrnlen(const char *_Str,size_t _MaxCount); + _CRTIMP size_t __cdecl _mbstrnlen_l(const char *_Str,size_t _MaxCount,_locale_t _Locale); + int __cdecl mbtowc(wchar_t *_DstCh,const char *_SrcCh,size_t _SrcSizeInBytes); + _CRTIMP int __cdecl _mbtowc_l(wchar_t *_DstCh,const char *_SrcCh,size_t _SrcSizeInBytes,_locale_t _Locale); + size_t __cdecl mbstowcs(wchar_t *_Dest,const char *_Source,size_t _MaxCount); + _CRTIMP size_t __cdecl _mbstowcs_l(wchar_t *_Dest,const char *_Source,size_t _MaxCount,_locale_t _Locale); + int __cdecl rand(void); + _CRTIMP int __cdecl _set_error_mode(int _Mode); + void __cdecl srand(unsigned int _Seed); + double __cdecl strtod(const char *_Str,char **_EndPtr); + float __cdecl strtof(const char *nptr, char **endptr); +#if !defined __NO_ISOCEXT /* in libmingwex.a */ + float __cdecl strtof (const char * __restrict__, char ** __restrict__); + long double __cdecl strtold(const char * __restrict__, char ** __restrict__); +#endif /* __NO_ISOCEXT */ + _CRTIMP double __cdecl _strtod_l(const char *_Str,char **_EndPtr,_locale_t _Locale); + long __cdecl strtol(const char *_Str,char **_EndPtr,int _Radix); + _CRTIMP long __cdecl _strtol_l(const char *_Str,char **_EndPtr,int _Radix,_locale_t _Locale); + unsigned long __cdecl strtoul(const char *_Str,char **_EndPtr,int _Radix); + _CRTIMP unsigned long __cdecl _strtoul_l(const char *_Str,char **_EndPtr,int _Radix,_locale_t _Locale); +#ifndef _CRT_SYSTEM_DEFINED +#define _CRT_SYSTEM_DEFINED + int __cdecl system(const char *_Command); +#endif + _CRTIMP char *__cdecl _ultoa(unsigned long _Value,char *_Dest,int _Radix); + int __cdecl wctomb(char *_MbCh,wchar_t _WCh); + _CRTIMP int __cdecl _wctomb_l(char *_MbCh,wchar_t _WCh,_locale_t _Locale); + size_t __cdecl wcstombs(char *_Dest,const wchar_t *_Source,size_t _MaxCount); + _CRTIMP size_t __cdecl _wcstombs_l(char *_Dest,const wchar_t *_Source,size_t _MaxCount,_locale_t _Locale); + +#ifndef _CRT_ALLOCATION_DEFINED +#define _CRT_ALLOCATION_DEFINED + void *__cdecl calloc(size_t _NumOfElements,size_t _SizeOfElements); + void __cdecl free(void *_Memory); + void *__cdecl malloc(size_t _Size); + void *__cdecl realloc(void *_Memory,size_t _NewSize); + _CRTIMP void *__cdecl _recalloc(void *_Memory,size_t _Count,size_t _Size); + //_CRTIMP void __cdecl _aligned_free(void *_Memory); + //_CRTIMP void *__cdecl _aligned_malloc(size_t _Size,size_t _Alignment); + _CRTIMP void *__cdecl _aligned_offset_malloc(size_t _Size,size_t _Alignment,size_t _Offset); + _CRTIMP void *__cdecl _aligned_realloc(void *_Memory,size_t _Size,size_t _Alignment); + _CRTIMP void *__cdecl _aligned_recalloc(void *_Memory,size_t _Count,size_t _Size,size_t _Alignment); + _CRTIMP void *__cdecl _aligned_offset_realloc(void *_Memory,size_t _Size,size_t _Alignment,size_t _Offset); + _CRTIMP void *__cdecl _aligned_offset_recalloc(void *_Memory,size_t _Count,size_t _Size,size_t _Alignment,size_t _Offset); +#endif + +#ifndef _WSTDLIB_DEFINED +#define _WSTDLIB_DEFINED + + _CRTIMP wchar_t *__cdecl _itow(int _Value,wchar_t *_Dest,int _Radix); + _CRTIMP wchar_t *__cdecl _ltow(long _Value,wchar_t *_Dest,int _Radix); + _CRTIMP wchar_t *__cdecl _ultow(unsigned long _Value,wchar_t *_Dest,int _Radix); + double __cdecl wcstod(const wchar_t *_Str,wchar_t **_EndPtr); + float __cdecl wcstof(const wchar_t *nptr, wchar_t **endptr); +#if !defined __NO_ISOCEXT /* in libmingwex.a */ + float __cdecl wcstof( const wchar_t * __restrict__, wchar_t ** __restrict__); + long double __cdecl wcstold(const wchar_t * __restrict__, wchar_t ** __restrict__); +#endif /* __NO_ISOCEXT */ + _CRTIMP double __cdecl _wcstod_l(const wchar_t *_Str,wchar_t **_EndPtr,_locale_t _Locale); + long __cdecl wcstol(const wchar_t *_Str,wchar_t **_EndPtr,int _Radix); + _CRTIMP long __cdecl _wcstol_l(const wchar_t *_Str,wchar_t **_EndPtr,int _Radix,_locale_t _Locale); + unsigned long __cdecl wcstoul(const wchar_t *_Str,wchar_t **_EndPtr,int _Radix); + _CRTIMP unsigned long __cdecl _wcstoul_l(const wchar_t *_Str,wchar_t **_EndPtr,int _Radix,_locale_t _Locale); + _CRTIMP wchar_t *__cdecl _wgetenv(const wchar_t *_VarName); +#ifndef _CRT_WSYSTEM_DEFINED +#define _CRT_WSYSTEM_DEFINED + _CRTIMP int __cdecl _wsystem(const wchar_t *_Command); +#endif + _CRTIMP double __cdecl _wtof(const wchar_t *_Str); + _CRTIMP double __cdecl _wtof_l(const wchar_t *_Str,_locale_t _Locale); + _CRTIMP int __cdecl _wtoi(const wchar_t *_Str); + _CRTIMP int __cdecl _wtoi_l(const wchar_t *_Str,_locale_t _Locale); + _CRTIMP long __cdecl _wtol(const wchar_t *_Str); + _CRTIMP long __cdecl _wtol_l(const wchar_t *_Str,_locale_t _Locale); + +#if _INTEGRAL_MAX_BITS >= 64 + _CRTIMP wchar_t *__cdecl _i64tow(__int64 _Val,wchar_t *_DstBuf,int _Radix); + _CRTIMP wchar_t *__cdecl _ui64tow(unsigned __int64 _Val,wchar_t *_DstBuf,int _Radix); + _CRTIMP __int64 __cdecl _wtoi64(const wchar_t *_Str); + _CRTIMP __int64 __cdecl _wtoi64_l(const wchar_t *_Str,_locale_t _Locale); + _CRTIMP __int64 __cdecl _wcstoi64(const wchar_t *_Str,wchar_t **_EndPtr,int _Radix); + _CRTIMP __int64 __cdecl _wcstoi64_l(const wchar_t *_Str,wchar_t **_EndPtr,int _Radix,_locale_t _Locale); + _CRTIMP unsigned __int64 __cdecl _wcstoui64(const wchar_t *_Str,wchar_t **_EndPtr,int _Radix); + _CRTIMP unsigned __int64 __cdecl _wcstoui64_l(const wchar_t *_Str ,wchar_t **_EndPtr,int _Radix,_locale_t _Locale); +#endif +#endif + +#ifndef _POSIX_ +#define _CVTBUFSIZE (309+40) + _CRTIMP char *__cdecl _fullpath(char *_FullPath,const char *_Path,size_t _SizeInBytes); + _CRTIMP char *__cdecl _ecvt(double _Val,int _NumOfDigits,int *_PtDec,int *_PtSign); + _CRTIMP char *__cdecl _fcvt(double _Val,int _NumOfDec,int *_PtDec,int *_PtSign); + _CRTIMP char *__cdecl _gcvt(double _Val,int _NumOfDigits,char *_DstBuf); + _CRTIMP int __cdecl _atodbl(_CRT_DOUBLE *_Result,char *_Str); + _CRTIMP int __cdecl _atoldbl(_LDOUBLE *_Result,char *_Str); + _CRTIMP int __cdecl _atoflt(_CRT_FLOAT *_Result,char *_Str); + _CRTIMP int __cdecl _atodbl_l(_CRT_DOUBLE *_Result,char *_Str,_locale_t _Locale); + _CRTIMP int __cdecl _atoldbl_l(_LDOUBLE *_Result,char *_Str,_locale_t _Locale); + _CRTIMP int __cdecl _atoflt_l(_CRT_FLOAT *_Result,char *_Str,_locale_t _Locale); + unsigned long __cdecl _lrotl(unsigned long _Val,int _Shift); + unsigned long __cdecl _lrotr(unsigned long _Val,int _Shift); + _CRTIMP void __cdecl _makepath(char *_Path,const char *_Drive,const char *_Dir,const char *_Filename,const char *_Ext); + _onexit_t __cdecl _onexit(_onexit_t _Func); + +#ifndef _CRT_PERROR_DEFINED +#define _CRT_PERROR_DEFINED + void __cdecl perror(const char *_ErrMsg); +#endif + _CRTIMP int __cdecl _putenv(const char *_EnvString); + unsigned int __cdecl _rotl(unsigned int _Val,int _Shift); +#if _INTEGRAL_MAX_BITS >= 64 + unsigned __int64 __cdecl _rotl64(unsigned __int64 _Val,int _Shift); +#endif + unsigned int __cdecl _rotr(unsigned int _Val,int _Shift); +#if _INTEGRAL_MAX_BITS >= 64 + unsigned __int64 __cdecl _rotr64(unsigned __int64 _Val,int _Shift); +#endif + _CRTIMP void __cdecl _searchenv(const char *_Filename,const char *_EnvVar,char *_ResultPath); + _CRTIMP void __cdecl _splitpath(const char *_FullPath,char *_Drive,char *_Dir,char *_Filename,char *_Ext); + _CRTIMP void __cdecl _swab(char *_Buf1,char *_Buf2,int _SizeInBytes); + +#ifndef _WSTDLIBP_DEFINED +#define _WSTDLIBP_DEFINED + _CRTIMP wchar_t *__cdecl _wfullpath(wchar_t *_FullPath,const wchar_t *_Path,size_t _SizeInWords); + _CRTIMP void __cdecl _wmakepath(wchar_t *_ResultPath,const wchar_t *_Drive,const wchar_t *_Dir,const wchar_t *_Filename,const wchar_t *_Ext); +#ifndef _CRT_WPERROR_DEFINED +#define _CRT_WPERROR_DEFINED + _CRTIMP void __cdecl _wperror(const wchar_t *_ErrMsg); +#endif + _CRTIMP int __cdecl _wputenv(const wchar_t *_EnvString); + _CRTIMP void __cdecl _wsearchenv(const wchar_t *_Filename,const wchar_t *_EnvVar,wchar_t *_ResultPath); + _CRTIMP void __cdecl _wsplitpath(const wchar_t *_FullPath,wchar_t *_Drive,wchar_t *_Dir,wchar_t *_Filename,wchar_t *_Ext); +#endif + + _CRTIMP void __cdecl _beep(unsigned _Frequency,unsigned _Duration) __MINGW_ATTRIB_DEPRECATED; + /* Not to be confused with _set_error_mode (int). */ + _CRTIMP void __cdecl _seterrormode(int _Mode) __MINGW_ATTRIB_DEPRECATED; + _CRTIMP void __cdecl _sleep(unsigned long _Duration) __MINGW_ATTRIB_DEPRECATED; +#endif + +#ifndef NO_OLDNAMES +#ifndef _POSIX_ +#if 0 +#ifndef __cplusplus +#ifndef NOMINMAX +#ifndef max +#define max(a,b) (((a) > (b)) ? (a) : (b)) +#endif +#ifndef min +#define min(a,b) (((a) < (b)) ? (a) : (b)) +#endif +#endif +#endif +#endif + +#define sys_errlist _sys_errlist +#define sys_nerr _sys_nerr +#define environ _environ + char *__cdecl ecvt(double _Val,int _NumOfDigits,int *_PtDec,int *_PtSign); + char *__cdecl fcvt(double _Val,int _NumOfDec,int *_PtDec,int *_PtSign); + char *__cdecl gcvt(double _Val,int _NumOfDigits,char *_DstBuf); + char *__cdecl itoa(int _Val,char *_DstBuf,int _Radix); + char *__cdecl ltoa(long _Val,char *_DstBuf,int _Radix); + int __cdecl putenv(const char *_EnvString); + void __cdecl swab(char *_Buf1,char *_Buf2,int _SizeInBytes); + char *__cdecl ultoa(unsigned long _Val,char *_Dstbuf,int _Radix); + onexit_t __cdecl onexit(onexit_t _Func); +#endif +#endif + +#if !defined __NO_ISOCEXT /* externs in static libmingwex.a */ + + typedef struct { long long quot, rem; } lldiv_t; + + lldiv_t __cdecl lldiv(long long, long long); + + __CRT_INLINE long long __cdecl llabs(long long _j) { return (_j >= 0 ? _j : -_j); } + + long long __cdecl strtoll(const char* __restrict__, char** __restrict, int); + unsigned long long __cdecl strtoull(const char* __restrict__, char** __restrict__, int); + + /* these are stubs for MS _i64 versions */ + long long __cdecl atoll (const char *); + +#ifndef __STRICT_ANSI__ + long long __cdecl wtoll (const wchar_t *); + char *__cdecl lltoa (long long, char *, int); + char *__cdecl ulltoa (unsigned long long , char *, int); + wchar_t *__cdecl lltow (long long, wchar_t *, int); + wchar_t *__cdecl ulltow (unsigned long long, wchar_t *, int); + + /* __CRT_INLINE using non-ansi functions */ + __CRT_INLINE long long __cdecl atoll (const char * _c) { return _atoi64 (_c); } + __CRT_INLINE char *__cdecl lltoa (long long _n, char * _c, int _i) { return _i64toa (_n, _c, _i); } + __CRT_INLINE char *__cdecl ulltoa (unsigned long long _n, char * _c, int _i) { return _ui64toa (_n, _c, _i); } + __CRT_INLINE long long __cdecl wtoll (const wchar_t * _w) { return _wtoi64 (_w); } + __CRT_INLINE wchar_t *__cdecl lltow (long long _n, wchar_t * _w, int _i) { return _i64tow (_n, _w, _i); } + __CRT_INLINE wchar_t *__cdecl ulltow (unsigned long long _n, wchar_t * _w, int _i) { return _ui64tow (_n, _w, _i); } +#endif /* (__STRICT_ANSI__) */ + +#endif /* !__NO_ISOCEXT */ + +#ifdef __cplusplus +} +#endif + +#pragma pack(pop) + +#include +#include + +#endif diff --git a/tinyc/win32/include/string.h b/tinyc/win32/include/string.h new file mode 100644 index 000000000..3249dc3ba --- /dev/null +++ b/tinyc/win32/include/string.h @@ -0,0 +1,164 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _INC_STRING +#define _INC_STRING + +#include <_mingw.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _NLSCMP_DEFINED +#define _NLSCMP_DEFINED +#define _NLSCMPERROR 2147483647 +#endif + +#ifndef NULL +#ifdef __cplusplus +#define NULL 0 +#else +#define NULL ((void *)0) +#endif +#endif + +#define _WConst_return _CONST_RETURN + +#ifndef _CRT_MEMORY_DEFINED +#define _CRT_MEMORY_DEFINED + _CRTIMP void *__cdecl _memccpy(void *_Dst,const void *_Src,int _Val,size_t _MaxCount); + _CONST_RETURN void *__cdecl memchr(const void *_Buf ,int _Val,size_t _MaxCount); + _CRTIMP int __cdecl _memicmp(const void *_Buf1,const void *_Buf2,size_t _Size); + _CRTIMP int __cdecl _memicmp_l(const void *_Buf1,const void *_Buf2,size_t _Size,_locale_t _Locale); + int __cdecl memcmp(const void *_Buf1,const void *_Buf2,size_t _Size); + void *__cdecl memcpy(void *_Dst,const void *_Src,size_t _Size); + void *__cdecl memset(void *_Dst,int _Val,size_t _Size); +#ifndef NO_OLDNAMES + void *__cdecl memccpy(void *_Dst,const void *_Src,int _Val,size_t _Size); + int __cdecl memicmp(const void *_Buf1,const void *_Buf2,size_t _Size); +#endif +#endif + char *__cdecl _strset(char *_Str,int _Val); + char *__cdecl strcpy(char *_Dest,const char *_Source); + char *__cdecl strcat(char *_Dest,const char *_Source); + int __cdecl strcmp(const char *_Str1,const char *_Str2); + size_t __cdecl strlen(const char *_Str); +#if 0 + size_t __cdecl strnlen(const char *_Str,size_t _MaxCount); +#endif + void *__cdecl memmove(void *_Dst,const void *_Src,size_t _Size); + _CRTIMP char *__cdecl _strdup(const char *_Src); + _CONST_RETURN char *__cdecl strchr(const char *_Str,int _Val); + _CRTIMP int __cdecl _stricmp(const char *_Str1,const char *_Str2); + _CRTIMP int __cdecl _strcmpi(const char *_Str1,const char *_Str2); + _CRTIMP int __cdecl _stricmp_l(const char *_Str1,const char *_Str2,_locale_t _Locale); + int __cdecl strcoll(const char *_Str1,const char *_Str2); + _CRTIMP int __cdecl _strcoll_l(const char *_Str1,const char *_Str2,_locale_t _Locale); + _CRTIMP int __cdecl _stricoll(const char *_Str1,const char *_Str2); + _CRTIMP int __cdecl _stricoll_l(const char *_Str1,const char *_Str2,_locale_t _Locale); + _CRTIMP int __cdecl _strncoll (const char *_Str1,const char *_Str2,size_t _MaxCount); + _CRTIMP int __cdecl _strncoll_l(const char *_Str1,const char *_Str2,size_t _MaxCount,_locale_t _Locale); + _CRTIMP int __cdecl _strnicoll (const char *_Str1,const char *_Str2,size_t _MaxCount); + _CRTIMP int __cdecl _strnicoll_l(const char *_Str1,const char *_Str2,size_t _MaxCount,_locale_t _Locale); + size_t __cdecl strcspn(const char *_Str,const char *_Control); + _CRTIMP char *__cdecl _strerror(const char *_ErrMsg); + char *__cdecl strerror(int); + _CRTIMP char *__cdecl _strlwr(char *_String); + char *strlwr_l(char *_String,_locale_t _Locale); + char *__cdecl strncat(char *_Dest,const char *_Source,size_t _Count); + int __cdecl strncmp(const char *_Str1,const char *_Str2,size_t _MaxCount); + _CRTIMP int __cdecl _strnicmp(const char *_Str1,const char *_Str2,size_t _MaxCount); + _CRTIMP int __cdecl _strnicmp_l(const char *_Str1,const char *_Str2,size_t _MaxCount,_locale_t _Locale); + char *strncpy(char *_Dest,const char *_Source,size_t _Count); + _CRTIMP char *__cdecl _strnset(char *_Str,int _Val,size_t _MaxCount); + _CONST_RETURN char *__cdecl strpbrk(const char *_Str,const char *_Control); + _CONST_RETURN char *__cdecl strrchr(const char *_Str,int _Ch); + _CRTIMP char *__cdecl _strrev(char *_Str); + size_t __cdecl strspn(const char *_Str,const char *_Control); + _CONST_RETURN char *__cdecl strstr(const char *_Str,const char *_SubStr); + char *__cdecl strtok(char *_Str,const char *_Delim); + _CRTIMP char *__cdecl _strupr(char *_String); + _CRTIMP char *_strupr_l(char *_String,_locale_t _Locale); + size_t __cdecl strxfrm(char *_Dst,const char *_Src,size_t _MaxCount); + _CRTIMP size_t __cdecl _strxfrm_l(char *_Dst,const char *_Src,size_t _MaxCount,_locale_t _Locale); + +#ifndef NO_OLDNAMES + char *__cdecl strdup(const char *_Src); + int __cdecl strcmpi(const char *_Str1,const char *_Str2); + int __cdecl stricmp(const char *_Str1,const char *_Str2); + char *__cdecl strlwr(char *_Str); + int __cdecl strnicmp(const char *_Str1,const char *_Str,size_t _MaxCount); + __CRT_INLINE int __cdecl strncasecmp (const char *__sz1, const char *__sz2, size_t __sizeMaxCompare) { return _strnicmp (__sz1, __sz2, __sizeMaxCompare); } + __CRT_INLINE int __cdecl strcasecmp (const char *__sz1, const char *__sz2) { return _stricmp (__sz1, __sz2); } + char *__cdecl strnset(char *_Str,int _Val,size_t _MaxCount); + char *__cdecl strrev(char *_Str); + char *__cdecl strset(char *_Str,int _Val); + char *__cdecl strupr(char *_Str); +#endif + +#ifndef _WSTRING_DEFINED +#define _WSTRING_DEFINED + + _CRTIMP wchar_t *__cdecl _wcsdup(const wchar_t *_Str); + wchar_t *__cdecl wcscat(wchar_t *_Dest,const wchar_t *_Source); + _CONST_RETURN wchar_t *__cdecl wcschr(const wchar_t *_Str,wchar_t _Ch); + int __cdecl wcscmp(const wchar_t *_Str1,const wchar_t *_Str2); + wchar_t *__cdecl wcscpy(wchar_t *_Dest,const wchar_t *_Source); + size_t __cdecl wcscspn(const wchar_t *_Str,const wchar_t *_Control); + size_t __cdecl wcslen(const wchar_t *_Str); + size_t __cdecl wcsnlen(const wchar_t *_Src,size_t _MaxCount); + wchar_t *wcsncat(wchar_t *_Dest,const wchar_t *_Source,size_t _Count); + int __cdecl wcsncmp(const wchar_t *_Str1,const wchar_t *_Str2,size_t _MaxCount); + wchar_t *wcsncpy(wchar_t *_Dest,const wchar_t *_Source,size_t _Count); + _CONST_RETURN wchar_t *__cdecl wcspbrk(const wchar_t *_Str,const wchar_t *_Control); + _CONST_RETURN wchar_t *__cdecl wcsrchr(const wchar_t *_Str,wchar_t _Ch); + size_t __cdecl wcsspn(const wchar_t *_Str,const wchar_t *_Control); + _CONST_RETURN wchar_t *__cdecl wcsstr(const wchar_t *_Str,const wchar_t *_SubStr); + wchar_t *__cdecl wcstok(wchar_t *_Str,const wchar_t *_Delim); + _CRTIMP wchar_t *__cdecl _wcserror(int _ErrNum); + _CRTIMP wchar_t *__cdecl __wcserror(const wchar_t *_Str); + _CRTIMP int __cdecl _wcsicmp(const wchar_t *_Str1,const wchar_t *_Str2); + _CRTIMP int __cdecl _wcsicmp_l(const wchar_t *_Str1,const wchar_t *_Str2,_locale_t _Locale); + _CRTIMP int __cdecl _wcsnicmp(const wchar_t *_Str1,const wchar_t *_Str2,size_t _MaxCount); + _CRTIMP int __cdecl _wcsnicmp_l(const wchar_t *_Str1,const wchar_t *_Str2,size_t _MaxCount,_locale_t _Locale); + _CRTIMP wchar_t *__cdecl _wcsnset(wchar_t *_Str,wchar_t _Val,size_t _MaxCount); + _CRTIMP wchar_t *__cdecl _wcsrev(wchar_t *_Str); + _CRTIMP wchar_t *__cdecl _wcsset(wchar_t *_Str,wchar_t _Val); + _CRTIMP wchar_t *__cdecl _wcslwr(wchar_t *_String); + _CRTIMP wchar_t *_wcslwr_l(wchar_t *_String,_locale_t _Locale); + _CRTIMP wchar_t *__cdecl _wcsupr(wchar_t *_String); + _CRTIMP wchar_t *_wcsupr_l(wchar_t *_String,_locale_t _Locale); + size_t __cdecl wcsxfrm(wchar_t *_Dst,const wchar_t *_Src,size_t _MaxCount); + _CRTIMP size_t __cdecl _wcsxfrm_l(wchar_t *_Dst,const wchar_t *_Src,size_t _MaxCount,_locale_t _Locale); + int __cdecl wcscoll(const wchar_t *_Str1,const wchar_t *_Str2); + _CRTIMP int __cdecl _wcscoll_l(const wchar_t *_Str1,const wchar_t *_Str2,_locale_t _Locale); + _CRTIMP int __cdecl _wcsicoll(const wchar_t *_Str1,const wchar_t *_Str2); + _CRTIMP int __cdecl _wcsicoll_l(const wchar_t *_Str1,const wchar_t *_Str2,_locale_t _Locale); + _CRTIMP int __cdecl _wcsncoll(const wchar_t *_Str1,const wchar_t *_Str2,size_t _MaxCount); + _CRTIMP int __cdecl _wcsncoll_l(const wchar_t *_Str1,const wchar_t *_Str2,size_t _MaxCount,_locale_t _Locale); + _CRTIMP int __cdecl _wcsnicoll(const wchar_t *_Str1,const wchar_t *_Str2,size_t _MaxCount); + _CRTIMP int __cdecl _wcsnicoll_l(const wchar_t *_Str1,const wchar_t *_Str2,size_t _MaxCount,_locale_t _Locale); + +#ifndef NO_OLDNAMES + wchar_t *__cdecl wcsdup(const wchar_t *_Str); +#define wcswcs wcsstr + int __cdecl wcsicmp(const wchar_t *_Str1,const wchar_t *_Str2); + int __cdecl wcsnicmp(const wchar_t *_Str1,const wchar_t *_Str2,size_t _MaxCount); + wchar_t *__cdecl wcsnset(wchar_t *_Str,wchar_t _Val,size_t _MaxCount); + wchar_t *__cdecl wcsrev(wchar_t *_Str); + wchar_t *__cdecl wcsset(wchar_t *_Str,wchar_t _Val); + wchar_t *__cdecl wcslwr(wchar_t *_Str); + wchar_t *__cdecl wcsupr(wchar_t *_Str); + int __cdecl wcsicoll(const wchar_t *_Str1,const wchar_t *_Str2); +#endif +#endif + +#ifdef __cplusplus +} +#endif + +#include +#endif diff --git a/tinyc/win32/include/sys/fcntl.h b/tinyc/win32/include/sys/fcntl.h new file mode 100644 index 000000000..29fd55a1f --- /dev/null +++ b/tinyc/win32/include/sys/fcntl.h @@ -0,0 +1,13 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +/* + * This file is part of the Mingw32 package. + * + * This fcntl.h maps to the root fcntl.h + */ +#ifndef __STRICT_ANSI__ +#include +#endif diff --git a/tinyc/win32/include/sys/file.h b/tinyc/win32/include/sys/file.h new file mode 100644 index 000000000..370f352d6 --- /dev/null +++ b/tinyc/win32/include/sys/file.h @@ -0,0 +1,14 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +/* + * This file is part of the Mingw32 package. + * + * This file.h maps to the root fcntl.h + * TODO? + */ +#ifndef __STRICT_ANSI__ +#include +#endif diff --git a/tinyc/win32/include/sys/locking.h b/tinyc/win32/include/sys/locking.h new file mode 100644 index 000000000..e3fc85b3a --- /dev/null +++ b/tinyc/win32/include/sys/locking.h @@ -0,0 +1,30 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _INC_LOCKING +#define _INC_LOCKING + +#ifndef _WIN32 +#error Only Win32 target is supported! +#endif + +/* All the headers include this file. */ +#include <_mingw.h> + +#define _LK_UNLCK 0 +#define _LK_LOCK 1 +#define _LK_NBLCK 2 +#define _LK_RLCK 3 +#define _LK_NBRLCK 4 + +#ifndef NO_OLDNAMES +#define LK_UNLCK _LK_UNLCK +#define LK_LOCK _LK_LOCK +#define LK_NBLCK _LK_NBLCK +#define LK_RLCK _LK_RLCK +#define LK_NBRLCK _LK_NBRLCK +#endif + +#endif diff --git a/tinyc/win32/include/sys/stat.h b/tinyc/win32/include/sys/stat.h new file mode 100644 index 000000000..344d4a249 --- /dev/null +++ b/tinyc/win32/include/sys/stat.h @@ -0,0 +1,290 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _INC_STAT +#define _INC_STAT + +#ifndef _WIN32 +#error Only Win32 target is supported! +#endif + +#include <_mingw.h> +#include + +#pragma pack(push,_CRT_PACKING) + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _CRTIMP +#define _CRTIMP __declspec(dllimport) +#endif + +#include + +#ifndef __TINYC__ /* gr */ +#ifdef _USE_32BIT_TIME_T +#ifdef _WIN64 +#undef _USE_32BIT_TIME_T +#endif +#else +#if _INTEGRAL_MAX_BITS < 64 +#define _USE_32BIT_TIME_T +#endif +#endif +#endif + +#ifndef _TIME32_T_DEFINED + typedef long __time32_t; +#define _TIME32_T_DEFINED +#endif + +#ifndef _TIME64_T_DEFINED +#if _INTEGRAL_MAX_BITS >= 64 + typedef __int64 __time64_t; +#endif +#define _TIME64_T_DEFINED +#endif + +#ifndef _TIME_T_DEFINED +#ifdef _USE_32BIT_TIME_T + typedef __time32_t time_t; +#else + typedef __time64_t time_t; +#endif +#define _TIME_T_DEFINED +#endif + +#ifndef _WCHAR_T_DEFINED + typedef unsigned short wchar_t; +#define _WCHAR_T_DEFINED +#endif + +#ifndef _STAT_DEFINED + +#ifdef _USE_32BIT_TIME_T +#ifndef _WIN64 +#define _fstat32 _fstat +#define _stat32 _stat +#define _wstat32 _wstat +#else +#define _fstat _fstat32 +#define _stat _stat32 +#define _wstat _wstat32 +#endif +#define _fstati64 _fstat32i64 +#define _stati64 _stat32i64 +#define _wstati64 _wstat32i64 +#else +#define _fstat _fstat64i32 +#define _fstati64 _fstat64 +#define _stat _stat64i32 +#define _stati64 _stat64 +#define _wstat _wstat64i32 +#define _wstati64 _wstat64 +#endif + + struct _stat32 { + _dev_t st_dev; + _ino_t st_ino; + unsigned short st_mode; + short st_nlink; + short st_uid; + short st_gid; + _dev_t st_rdev; + _off_t st_size; + __time32_t st_atime; + __time32_t st_mtime; + __time32_t st_ctime; + }; + +#ifndef NO_OLDNAMES + struct stat { + _dev_t st_dev; + _ino_t st_ino; + unsigned short st_mode; + short st_nlink; + short st_uid; + short st_gid; + _dev_t st_rdev; + _off_t st_size; + time_t st_atime; + time_t st_mtime; + time_t st_ctime; + }; +#endif + +#if _INTEGRAL_MAX_BITS >= 64 + struct _stat32i64 { + _dev_t st_dev; + _ino_t st_ino; + unsigned short st_mode; + short st_nlink; + short st_uid; + short st_gid; + _dev_t st_rdev; + __int64 st_size; + __time32_t st_atime; + __time32_t st_mtime; + __time32_t st_ctime; + }; + + struct _stat64i32 { + _dev_t st_dev; + _ino_t st_ino; + unsigned short st_mode; + short st_nlink; + short st_uid; + short st_gid; + _dev_t st_rdev; + _off_t st_size; + __time64_t st_atime; + __time64_t st_mtime; + __time64_t st_ctime; + }; + + struct _stat64 { + _dev_t st_dev; + _ino_t st_ino; + unsigned short st_mode; + short st_nlink; + short st_uid; + short st_gid; + _dev_t st_rdev; + __int64 st_size; + __time64_t st_atime; + __time64_t st_mtime; + __time64_t st_ctime; + }; +#endif + +#define __stat64 _stat64 + +#define _STAT_DEFINED +#endif + +#define _S_IFMT 0xF000 +#define _S_IFDIR 0x4000 +#define _S_IFCHR 0x2000 +#define _S_IFIFO 0x1000 +#define _S_IFREG 0x8000 +#define _S_IREAD 0x0100 +#define _S_IWRITE 0x0080 +#define _S_IEXEC 0x0040 + + _CRTIMP int __cdecl _fstat32(int _FileDes,struct _stat32 *_Stat); + _CRTIMP int __cdecl _stat32(const char *_Name,struct _stat32 *_Stat); +#if _INTEGRAL_MAX_BITS >= 64 + _CRTIMP int __cdecl _fstat64(int _FileDes,struct _stat64 *_Stat); + _CRTIMP int __cdecl _fstat32i64(int _FileDes,struct _stat32i64 *_Stat); + int __cdecl _fstat64i32(int _FileDes,struct _stat64i32 *_Stat); + __CRT_INLINE int __cdecl _fstat64i32(int _FileDes,struct _stat64i32 *_Stat) + { + struct _stat64 st; + int ret=_fstat64(_FileDes,&st); + _Stat->st_dev=st.st_dev; + _Stat->st_ino=st.st_ino; + _Stat->st_mode=st.st_mode; + _Stat->st_nlink=st.st_nlink; + _Stat->st_uid=st.st_uid; + _Stat->st_gid=st.st_gid; + _Stat->st_rdev=st.st_rdev; + _Stat->st_size=(_off_t) st.st_size; + _Stat->st_atime=st.st_atime; + _Stat->st_mtime=st.st_mtime; + _Stat->st_ctime=st.st_ctime; + return ret; + } + _CRTIMP int __cdecl _stat64(const char *_Name,struct _stat64 *_Stat); + _CRTIMP int __cdecl _stat32i64(const char *_Name,struct _stat32i64 *_Stat); + int __cdecl _stat64i32(const char *_Name,struct _stat64i32 *_Stat); + __CRT_INLINE int __cdecl _stat64i32(const char *_Name,struct _stat64i32 *_Stat) + { + struct _stat64 st; + int ret=_stat64(_Name,&st); + _Stat->st_dev=st.st_dev; + _Stat->st_ino=st.st_ino; + _Stat->st_mode=st.st_mode; + _Stat->st_nlink=st.st_nlink; + _Stat->st_uid=st.st_uid; + _Stat->st_gid=st.st_gid; + _Stat->st_rdev=st.st_rdev; + _Stat->st_size=(_off_t) st.st_size; + _Stat->st_atime=st.st_atime; + _Stat->st_mtime=st.st_mtime; + _Stat->st_ctime=st.st_ctime; + return ret; + } +#endif + +#ifndef _WSTAT_DEFINED +#define _WSTAT_DEFINED + _CRTIMP int __cdecl _wstat32(const wchar_t *_Name,struct _stat32 *_Stat); +#if _INTEGRAL_MAX_BITS >= 64 + _CRTIMP int __cdecl _wstat32i64(const wchar_t *_Name,struct _stat32i64 *_Stat); + int __cdecl _wstat64i32(const wchar_t *_Name,struct _stat64i32 *_Stat); + _CRTIMP int __cdecl _wstat64(const wchar_t *_Name,struct _stat64 *_Stat); +#endif +#endif + +#ifndef NO_OLDNAMES +#define _S_IFBLK 0x3000 /* Block: Is this ever set under w32? */ + +#define S_IFMT _S_IFMT +#define S_IFDIR _S_IFDIR +#define S_IFCHR _S_IFCHR +#define S_IFREG _S_IFREG +#define S_IREAD _S_IREAD +#define S_IWRITE _S_IWRITE +#define S_IEXEC _S_IEXEC +#define S_IFIFO _S_IFIFO +#define S_IFBLK _S_IFBLK + +#define _S_IRWXU (_S_IREAD | _S_IWRITE | _S_IEXEC) +#define _S_IXUSR _S_IEXEC +#define _S_IWUSR _S_IWRITE + +#define S_IRWXU _S_IRWXU +#define S_IXUSR _S_IXUSR +#define S_IWUSR _S_IWUSR +#define S_IRUSR _S_IRUSR +#define _S_IRUSR _S_IREAD + +#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) +#define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO) +#define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR) +#define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK) +#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) + +#endif + +#if !defined (RC_INVOKED) && !defined (NO_OLDNAMES) +int __cdecl stat(const char *_Filename,struct stat *_Stat); +int __cdecl fstat(int _Desc,struct stat *_Stat); +int __cdecl wstat(const wchar_t *_Filename,struct stat *_Stat); +#ifdef _USE_32BIT_TIME_T +__CRT_INLINE int __cdecl fstat(int _Desc,struct stat *_Stat) { + return _fstat32(_Desc,(struct _stat32 *)_Stat); +} +__CRT_INLINE int __cdecl stat(const char *_Filename,struct stat *_Stat) { + return _stat32(_Filename,(struct _stat32 *)_Stat); +} +#else +__CRT_INLINE int __cdecl fstat(int _Desc,struct stat *_Stat) { + return _fstat64i32(_Desc,(struct _stat64i32 *)_Stat); +} +__CRT_INLINE int __cdecl stat(const char *_Filename,struct stat *_Stat) { + return _stat64i32(_Filename,(struct _stat64i32 *)_Stat); +} +#endif +#endif + +#ifdef __cplusplus +} +#endif + +#pragma pack(pop) +#endif diff --git a/tinyc/win32/include/sys/time.h b/tinyc/win32/include/sys/time.h new file mode 100644 index 000000000..8ccab8319 --- /dev/null +++ b/tinyc/win32/include/sys/time.h @@ -0,0 +1,69 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ + +#ifndef _SYS_TIME_H_ +#define _SYS_TIME_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __STRICT_ANSI__ +#ifndef _TIMEVAL_DEFINED /* also in winsock[2].h */ +#define _TIMEVAL_DEFINED +struct timeval { + long tv_sec; + long tv_usec; +}; +#define timerisset(tvp) ((tvp)->tv_sec || (tvp)->tv_usec) +#define timercmp(tvp, uvp, cmp) \ + (((tvp)->tv_sec != (uvp)->tv_sec) ? \ + ((tvp)->tv_sec cmp (uvp)->tv_sec) : \ + ((tvp)->tv_usec cmp (uvp)->tv_usec)) +#define timerclear(tvp) (tvp)->tv_sec = (tvp)->tv_usec = 0 +#endif /* _TIMEVAL_DEFINED */ + +#ifndef _TIMEZONE_DEFINED /* also in sys/time.h */ +#define _TIMEZONE_DEFINED +/* Provided for compatibility with code that assumes that + the presence of gettimeofday function implies a definition + of struct timezone. */ +struct timezone +{ + int tz_minuteswest; /* of Greenwich */ + int tz_dsttime; /* type of dst correction to apply */ +}; + + extern int __cdecl mingw_gettimeofday (struct timeval *p, struct timezone *z); + +#endif + +/* + Implementation as per: + The Open Group Base Specifications, Issue 6 + IEEE Std 1003.1, 2004 Edition + + The timezone pointer arg is ignored. Errors are ignored. +*/ +#ifndef _GETTIMEOFDAY_DEFINED +#define _GETTIMEOFDAY_DEFINED +int __cdecl gettimeofday(struct timeval *__restrict__, + void *__restrict__ /* tzp (unused) */); +#endif + +#endif /* __STRICT_ANSI__ */ + +#ifdef __cplusplus +} +#endif + +/* Adding timespec definition. */ +#include + + +#endif /* _SYS_TIME_H_ */ diff --git a/tinyc/win32/include/sys/timeb.h b/tinyc/win32/include/sys/timeb.h new file mode 100644 index 000000000..34837738b --- /dev/null +++ b/tinyc/win32/include/sys/timeb.h @@ -0,0 +1,133 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _TIMEB_H_ +#define _TIMEB_H_ + +#include <_mingw.h> + +#ifndef _WIN32 +#error Only Win32 target is supported! +#endif + +#pragma pack(push,_CRT_PACKING) + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _CRTIMP +#define _CRTIMP __declspec(dllimport) +#endif + +#ifndef __TINYC__ /* gr */ +#ifdef _USE_32BIT_TIME_T +#ifdef _WIN64 +#undef _USE_32BIT_TIME_T +#endif +#else +#if _INTEGRAL_MAX_BITS < 64 +#define _USE_32BIT_TIME_T +#endif +#endif +#endif + +#ifndef _TIME32_T_DEFINED + typedef long __time32_t; +#define _TIME32_T_DEFINED +#endif + +#ifndef _TIME64_T_DEFINED +#if _INTEGRAL_MAX_BITS >= 64 + typedef __int64 __time64_t; +#endif +#define _TIME64_T_DEFINED +#endif + +#ifndef _TIME_T_DEFINED +#ifdef _USE_32BIT_TIME_T + typedef __time32_t time_t; +#else + typedef __time64_t time_t; +#endif +#define _TIME_T_DEFINED +#endif + +#ifndef _TIMEB_DEFINED +#define _TIMEB_DEFINED + + struct __timeb32 { + __time32_t time; + unsigned short millitm; + short timezone; + short dstflag; + }; + +#ifndef NO_OLDNAMES + struct timeb { + time_t time; + unsigned short millitm; + short timezone; + short dstflag; + }; +#endif + +#if _INTEGRAL_MAX_BITS >= 64 + struct __timeb64 { + __time64_t time; + unsigned short millitm; + short timezone; + short dstflag; + }; +#endif + +#ifdef _USE_32BIT_TIME_T +#define _timeb __timeb32 +//gr #define _ftime _ftime32 +#define _ftime32 _ftime +#else +#define _timeb __timeb64 +#define _ftime _ftime64 +#endif +#endif + + _CRTIMP void __cdecl _ftime32(struct __timeb32 *_Time); +#if _INTEGRAL_MAX_BITS >= 64 + _CRTIMP void __cdecl _ftime64(struct __timeb64 *_Time); +#endif + +#ifndef _TIMESPEC_DEFINED +#define _TIMESPEC_DEFINED +struct timespec { + time_t tv_sec; /* Seconds */ + long tv_nsec; /* Nanoseconds */ +}; + +struct itimerspec { + struct timespec it_interval; /* Timer period */ + struct timespec it_value; /* Timer expiration */ +}; +#endif + +#if !defined (RC_INVOKED) && !defined (NO_OLDNAMES) +#ifdef _USE_32BIT_TIME_T +__CRT_INLINE void __cdecl ftime(struct timeb *_Tmb) { + _ftime32((struct __timeb32 *)_Tmb); +} +#else +__CRT_INLINE void __cdecl ftime(struct timeb *_Tmb) { + _ftime64((struct __timeb64 *)_Tmb); +} +#endif +#endif + +#ifdef __cplusplus +} +#endif + +#pragma pack(pop) + +#include +#endif diff --git a/tinyc/win32/include/sys/types.h b/tinyc/win32/include/sys/types.h new file mode 100644 index 000000000..7379b0f1e --- /dev/null +++ b/tinyc/win32/include/sys/types.h @@ -0,0 +1,118 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _INC_TYPES +#define _INC_TYPES + +#ifndef _WIN32 +#error Only Win32 target is supported! +#endif + +#include <_mingw.h> + +#ifndef __TINYC__ /* gr */ +#ifdef _USE_32BIT_TIME_T +#ifdef _WIN64 +#undef _USE_32BIT_TIME_T +#endif +#else +#if _INTEGRAL_MAX_BITS < 64 +#define _USE_32BIT_TIME_T +#endif +#endif +#endif + +#ifndef _TIME32_T_DEFINED +#define _TIME32_T_DEFINED +typedef long __time32_t; +#endif + +#ifndef _TIME64_T_DEFINED +#define _TIME64_T_DEFINED +#if _INTEGRAL_MAX_BITS >= 64 +typedef __int64 __time64_t; +#endif +#endif + +#ifndef _TIME_T_DEFINED +#define _TIME_T_DEFINED +#ifdef _USE_32BIT_TIME_T +typedef __time32_t time_t; +#else +typedef __time64_t time_t; +#endif +#endif + +#ifndef _INO_T_DEFINED +#define _INO_T_DEFINED +typedef unsigned short _ino_t; +#ifndef NO_OLDNAMES +typedef unsigned short ino_t; +#endif +#endif + +#ifndef _DEV_T_DEFINED +#define _DEV_T_DEFINED +typedef unsigned int _dev_t; +#ifndef NO_OLDNAMES +typedef unsigned int dev_t; +#endif +#endif + +#ifndef _PID_T_ +#define _PID_T_ +#ifndef _WIN64 +typedef int _pid_t; +#else +typedef __int64 _pid_t; +#endif + +#ifndef NO_OLDNAMES +typedef _pid_t pid_t; +#endif +#endif /* Not _PID_T_ */ + +#ifndef _MODE_T_ +#define _MODE_T_ +typedef unsigned short _mode_t; + +#ifndef NO_OLDNAMES +typedef _mode_t mode_t; +#endif +#endif /* Not _MODE_T_ */ + +#ifndef _OFF_T_DEFINED +#define _OFF_T_DEFINED +#ifndef _OFF_T_ +#define _OFF_T_ + typedef long _off_t; +#if !defined(NO_OLDNAMES) || defined(_POSIX) + typedef long off_t; +#endif +#endif +#endif + +#ifndef _OFF64_T_DEFINED +#define _OFF64_T_DEFINED + typedef long long _off64_t; +#if !defined(NO_OLDNAMES) || defined(_POSIX) + typedef long long off64_t; +#endif +#endif + +#ifndef _TIMESPEC_DEFINED +#define _TIMESPEC_DEFINED +struct timespec { + time_t tv_sec; /* Seconds */ + long tv_nsec; /* Nanoseconds */ +}; + +struct itimerspec { + struct timespec it_interval; /* Timer period */ + struct timespec it_value; /* Timer expiration */ +}; +#endif + +#endif diff --git a/tinyc/win32/include/sys/unistd.h b/tinyc/win32/include/sys/unistd.h new file mode 100644 index 000000000..31006d325 --- /dev/null +++ b/tinyc/win32/include/sys/unistd.h @@ -0,0 +1,14 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +/* + * This file is part of the Mingw32 package. + * + * unistd.h maps (roughly) to io.h + */ +#ifndef __STRICT_ANSI__ +#include +#endif + diff --git a/tinyc/win32/include/sys/utime.h b/tinyc/win32/include/sys/utime.h new file mode 100644 index 000000000..fec8304ff --- /dev/null +++ b/tinyc/win32/include/sys/utime.h @@ -0,0 +1,146 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _INC_UTIME +#define _INC_UTIME + +#ifndef _WIN32 +#error Only Win32 target is supported! +#endif + +#include <_mingw.h> + +#pragma pack(push,_CRT_PACKING) + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _CRTIMP +#define _CRTIMP __declspec(dllimport) +#endif + +#ifndef _WCHAR_T_DEFINED + typedef unsigned short wchar_t; +#define _WCHAR_T_DEFINED +#endif + +#ifndef __TINYC__ /* gr */ +#ifdef _USE_32BIT_TIME_T +#ifdef _WIN64 +#undef _USE_32BIT_TIME_T +#endif +#else +#if _INTEGRAL_MAX_BITS < 64 +#define _USE_32BIT_TIME_T +#endif +#endif +#endif + +#ifndef _TIME32_T_DEFINED +#define _TIME32_T_DEFINED + typedef long __time32_t; +#endif + +#ifndef _TIME64_T_DEFINED +#define _TIME64_T_DEFINED +#if _INTEGRAL_MAX_BITS >= 64 + typedef __int64 __time64_t; +#endif +#endif + +#ifndef _TIME_T_DEFINED +#define _TIME_T_DEFINED +#ifdef _USE_32BIT_TIME_T + typedef __time32_t time_t; +#else + typedef __time64_t time_t; +#endif +#endif + +#ifndef _UTIMBUF_DEFINED +#define _UTIMBUF_DEFINED + + struct _utimbuf { + time_t actime; + time_t modtime; + }; + + struct __utimbuf32 { + __time32_t actime; + __time32_t modtime; + }; + +#if _INTEGRAL_MAX_BITS >= 64 + struct __utimbuf64 { + __time64_t actime; + __time64_t modtime; + }; +#endif + +#ifndef NO_OLDNAMES + struct utimbuf { + time_t actime; + time_t modtime; + }; + + struct utimbuf32 { + __time32_t actime; + __time32_t modtime; + }; +#endif +#endif + + _CRTIMP int __cdecl _utime32(const char *_Filename,struct __utimbuf32 *_Time); + _CRTIMP int __cdecl _futime32(int _FileDes,struct __utimbuf32 *_Time); + _CRTIMP int __cdecl _wutime32(const wchar_t *_Filename,struct __utimbuf32 *_Time); +#if _INTEGRAL_MAX_BITS >= 64 + _CRTIMP int __cdecl _utime64(const char *_Filename,struct __utimbuf64 *_Time); + _CRTIMP int __cdecl _futime64(int _FileDes,struct __utimbuf64 *_Time); + _CRTIMP int __cdecl _wutime64(const wchar_t *_Filename,struct __utimbuf64 *_Time); +#endif + +#ifndef RC_INVOKED +#ifdef _USE_32BIT_TIME_T +__CRT_INLINE int __cdecl _utime(const char *_Filename,struct _utimbuf *_Utimbuf) { + return _utime32(_Filename,(struct __utimbuf32 *)_Utimbuf); +} +__CRT_INLINE int __cdecl _futime(int _Desc,struct _utimbuf *_Utimbuf) { + return _futime32(_Desc,(struct __utimbuf32 *)_Utimbuf); +} +__CRT_INLINE int __cdecl _wutime(const wchar_t *_Filename,struct _utimbuf *_Utimbuf) { + return _wutime32(_Filename,(struct __utimbuf32 *)_Utimbuf); +} +#else +__CRT_INLINE int __cdecl _utime(const char *_Filename,struct _utimbuf *_Utimbuf) { + return _utime64(_Filename,(struct __utimbuf64 *)_Utimbuf); +} +__CRT_INLINE int __cdecl _futime(int _Desc,struct _utimbuf *_Utimbuf) { + return _futime64(_Desc,(struct __utimbuf64 *)_Utimbuf); +} +__CRT_INLINE int __cdecl _wutime(const wchar_t *_Filename,struct _utimbuf *_Utimbuf) { + return _wutime64(_Filename,(struct __utimbuf64 *)_Utimbuf); +} +#endif + +#ifndef NO_OLDNAMES +#ifdef _USE_32BIT_TIME_T +__CRT_INLINE int __cdecl utime(const char *_Filename,struct utimbuf *_Utimbuf) { + return _utime32(_Filename,(struct __utimbuf32 *)_Utimbuf); +} +#else +__CRT_INLINE int __cdecl utime(const char *_Filename,struct utimbuf *_Utimbuf) { + return _utime64(_Filename,(struct __utimbuf64 *)_Utimbuf); +} +#endif +#endif +#endif + +#ifdef __cplusplus +} +#endif + +#pragma pack(pop) +#endif diff --git a/tinyc/win32/include/tcc/tcc_libm.h b/tinyc/win32/include/tcc/tcc_libm.h new file mode 100644 index 000000000..0a62e6fb7 --- /dev/null +++ b/tinyc/win32/include/tcc/tcc_libm.h @@ -0,0 +1,201 @@ +#ifndef _TCC_LIBM_H_ +#define _TCC_LIBM_H_ + +#include "../math.h" + +/* TCC uses 8 bytes for double and long double, so effectively the l variants + * are never used. For now, they just run the normal (double) variant. + */ + +/* + * most of the code in this file is taken from MUSL rs-1.0 (MIT license) + * - musl-libc: http://git.musl-libc.org/cgit/musl/tree/src/math?h=rs-1.0 + * - License: http://git.musl-libc.org/cgit/musl/tree/COPYRIGHT?h=rs-1.0 + */ + +/******************************************************************************* + Start of code based on MUSL +*******************************************************************************/ +/* +musl as a whole is licensed under the following standard MIT license: + +---------------------------------------------------------------------- +Copyright © 2005-2014 Rich Felker, et al. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +---------------------------------------------------------------------- +*/ + +/* fpclassify */ + +__CRT_INLINE int __cdecl __fpclassify (double x) { + union {double f; uint64_t i;} u = {x}; + int e = u.i>>52 & 0x7ff; + if (!e) return u.i<<1 ? FP_SUBNORMAL : FP_ZERO; + if (e==0x7ff) return u.i<<12 ? FP_NAN : FP_INFINITE; + return FP_NORMAL; +} + +__CRT_INLINE int __cdecl __fpclassifyf (float x) { + union {float f; uint32_t i;} u = {x}; + int e = u.i>>23 & 0xff; + if (!e) return u.i<<1 ? FP_SUBNORMAL : FP_ZERO; + if (e==0xff) return u.i<<9 ? FP_NAN : FP_INFINITE; + return FP_NORMAL; +} + +__CRT_INLINE int __cdecl __fpclassifyl (long double x) { + return __fpclassify(x); +} + + +/* signbit */ + +__CRT_INLINE int __cdecl __signbit (double x) { + union {double d; uint64_t i;} y = { x }; + return y.i>>63; +} + +__CRT_INLINE int __cdecl __signbitf (float x) { + union {float f; uint32_t i; } y = { x }; + return y.i>>31; +} + +__CRT_INLINE int __cdecl __signbitl (long double x) { + return __signbit(x); +} + + +/* fmin*, fmax* */ + +#define TCCFP_FMIN_EVAL (isnan(x) ? y : \ + isnan(y) ? x : \ + (signbit(x) != signbit(y)) ? (signbit(x) ? x : y) : \ + x < y ? x : y) + +__CRT_INLINE double __cdecl fmin (double x, double y) { + return TCCFP_FMIN_EVAL; +} + +__CRT_INLINE float __cdecl fminf (float x, float y) { + return TCCFP_FMIN_EVAL; +} + +__CRT_INLINE long double __cdecl fminl (long double x, long double y) { + return TCCFP_FMIN_EVAL; +} + +#define TCCFP_FMAX_EVAL (isnan(x) ? y : \ + isnan(y) ? x : \ + (signbit(x) != signbit(y)) ? (signbit(x) ? y : x) : \ + x < y ? y : x) + +__CRT_INLINE double __cdecl fmax (double x, double y) { + return TCCFP_FMAX_EVAL; +} + +__CRT_INLINE float __cdecl fmaxf (float x, float y) { + return TCCFP_FMAX_EVAL; +} + +__CRT_INLINE long double __cdecl fmaxl (long double x, long double y) { + return TCCFP_FMAX_EVAL; +} + + +/* *round* */ + +#define TCCFP_FORCE_EVAL(x) do { \ +if (sizeof(x) == sizeof(float)) { \ + volatile float __x; \ + __x = (x); \ +} else if (sizeof(x) == sizeof(double)) { \ + volatile double __x; \ + __x = (x); \ +} else { \ + volatile long double __x; \ + __x = (x); \ +} \ +} while(0) + +__CRT_INLINE double __cdecl round (double x) { + union {double f; uint64_t i;} u = {x}; + int e = u.i >> 52 & 0x7ff; + double y; + + if (e >= 0x3ff+52) + return x; + if (u.i >> 63) + x = -x; + if (e < 0x3ff-1) { + /* raise inexact if x!=0 */ + TCCFP_FORCE_EVAL(x + 0x1p52); + return 0*u.f; + } + y = (double)(x + 0x1p52) - 0x1p52 - x; + if (y > 0.5) + y = y + x - 1; + else if (y <= -0.5) + y = y + x + 1; + else + y = y + x; + if (u.i >> 63) + y = -y; + return y; +} + +__CRT_INLINE long __cdecl lround (double x) { + return round(x); +} + +__CRT_INLINE long long __cdecl llround (double x) { + return round(x); +} + +__CRT_INLINE float __cdecl roundf (float x) { + return round(x); +} + +__CRT_INLINE long __cdecl lroundf (float x) { + return round(x); +} + +__CRT_INLINE long long __cdecl llroundf (float x) { + return round(x); +} + +__CRT_INLINE long double __cdecl roundl (long double x) { + return round(x); +} + +__CRT_INLINE long __cdecl lroundl (long double x) { + return round(x); +} + +__CRT_INLINE long long __cdecl llroundl (long double x) { + return round(x); +} + + +/******************************************************************************* + End of code based on MUSL +*******************************************************************************/ + +#endif /* _TCC_LIBM_H_ */ diff --git a/tinyc/win32/include/tchar.h b/tinyc/win32/include/tchar.h new file mode 100644 index 000000000..cd44beca1 --- /dev/null +++ b/tinyc/win32/include/tchar.h @@ -0,0 +1,1102 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#include <_mingw.h> + +#ifndef _INC_TCHAR +#define _INC_TCHAR + +#ifdef _STRSAFE_H_INCLUDED_ +#error Need to include strsafe.h after tchar.h +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#define _ftcscat _tcscat +#define _ftcschr _tcschr +#define _ftcscpy _tcscpy +#define _ftcscspn _tcscspn +#define _ftcslen _tcslen +#define _ftcsncat _tcsncat +#define _ftcsncpy _tcsncpy +#define _ftcspbrk _tcspbrk +#define _ftcsrchr _tcsrchr +#define _ftcsspn _tcsspn +#define _ftcsstr _tcsstr +#define _ftcstok _tcstok + +#define _ftcsdup _tcsdup +#define _ftcsnset _tcsnset +#define _ftcsrev _tcsrev +#define _ftcsset _tcsset + +#define _ftcscmp _tcscmp +#define _ftcsicmp _tcsicmp +#define _ftcsnccmp _tcsnccmp +#define _ftcsncmp _tcsncmp +#define _ftcsncicmp _tcsncicmp +#define _ftcsnicmp _tcsnicmp + +#define _ftcscoll _tcscoll +#define _ftcsicoll _tcsicoll +#define _ftcsnccoll _tcsnccoll +#define _ftcsncoll _tcsncoll +#define _ftcsncicoll _tcsncicoll +#define _ftcsnicoll _tcsnicoll + +#define _ftcsclen _tcsclen +#define _ftcsnccat _tcsnccat +#define _ftcsnccpy _tcsnccpy +#define _ftcsncset _tcsncset + +#define _ftcsdec _tcsdec +#define _ftcsinc _tcsinc +#define _ftcsnbcnt _tcsnbcnt +#define _ftcsnccnt _tcsnccnt +#define _ftcsnextc _tcsnextc +#define _ftcsninc _tcsninc +#define _ftcsspnp _tcsspnp + +#define _ftcslwr _tcslwr +#define _ftcsupr _tcsupr + +#define _ftclen _tclen +#define _ftccpy _tccpy +#define _ftccmp _tccmp + +#ifndef _CONST_RETURN +#ifdef __cplusplus +#define _CONST_RETURN const +#define _CRT_CONST_CORRECT_OVERLOADS +#else +#define _CONST_RETURN +#endif +#endif + +#define _WConst_return _CONST_RETURN + +#ifdef _UNICODE + +#ifdef __cplusplus +} +#endif + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _WCTYPE_T_DEFINED +#define _WCTYPE_T_DEFINED + typedef unsigned short wint_t; + typedef unsigned short wctype_t; +#endif + +#ifndef __TCHAR_DEFINED +#define __TCHAR_DEFINED + typedef wchar_t _TCHAR; + typedef wchar_t _TSCHAR; + typedef wchar_t _TUCHAR; + typedef wchar_t _TXCHAR; + typedef wint_t _TINT; +#endif + +#ifndef _TCHAR_DEFINED +#define _TCHAR_DEFINED +#ifndef NO_OLDNAMES + typedef wchar_t TCHAR; +#endif +#endif + +#define _TEOF WEOF + +#define __T(x) L##x + +#define _tmain wmain +#define _tWinMain wWinMain +#define _tenviron _wenviron +#define __targv __wargv + +#define _tprintf wprintf +#define _tprintf_l _wprintf_l +#define _tprintf_p _wprintf_p +#define _tprintf_p_l _wprintf_p_l +#define _tcprintf _cwprintf +#define _tcprintf_l _cwprintf_l +#define _tcprintf_p _cwprintf_p +#define _tcprintf_p_l _cwprintf_p_l +#define _vtcprintf _vcwprintf +#define _vtcprintf_l _vcwprintf_l +#define _vtcprintf_p _vcwprintf_p +#define _vtcprintf_p_l _vcwprintf_p_l +#define _ftprintf fwprintf +#define _ftprintf_l _fwprintf_l +#define _ftprintf_p _fwprintf_p +#define _ftprintf_p_l _fwprintf_p_l +#define _stprintf swprintf +#define _stprintf_l __swprintf_l +#define _stprintf_p _swprintf_p +#define _stprintf_p_l _swprintf_p_l +#define _sctprintf _scwprintf +#define _sctprintf_l _scwprintf_l +#define _sctprintf_p _scwprintf_p +#define _sctprintf_p_l _scwprintf_p_l +#define _sntprintf _snwprintf +#define _sntprintf_l _snwprintf_l +#define _vtprintf vwprintf +#define _vtprintf_l _vwprintf_l +#define _vtprintf_p _vwprintf_p +#define _vtprintf_p_l _vwprintf_p_l +#define _vftprintf vfwprintf +#define _vftprintf_l _vfwprintf_l +#define _vftprintf_p _vfwprintf_p +#define _vftprintf_p_l _vfwprintf_p_l +#define _vstprintf vswprintf +#define _vstprintf_l _vswprintf_l +#define _vstprintf_p _vswprintf_p +#define _vstprintf_p_l _vswprintf_p_l +#define _vsctprintf _vscwprintf +#define _vsctprintf_l _vscwprintf_l +#define _vsctprintf_p _vscwprintf_p +#define _vsctprintf_p_l _vscwprintf_p_l +#define _vsntprintf _vsnwprintf +#define _vsntprintf_l _vsnwprintf_l + +#define _tscanf wscanf +#define _tscanf_l _wscanf_l +#define _tcscanf _cwscanf +#define _tcscanf_l _cwscanf_l +#define _ftscanf fwscanf +#define _ftscanf_l _fwscanf_l +#define _stscanf swscanf +#define _stscanf_l _swscanf_l +#define _sntscanf _snwscanf +#define _sntscanf_l _snwscanf_l + +#define _fgettc fgetwc +#define _fgettc_nolock _fgetwc_nolock +#define _fgettchar _fgetwchar +#define _fgetts fgetws +#define _fputtc fputwc +#define _fputtc_nolock _fputwc_nolock +#define _fputtchar _fputwchar +#define _fputts fputws +#define _cputts _cputws +#define _cgetts _cgetws +#define _gettc getwc +#define _gettc_nolock _getwc_nolock +#define _gettch _getwch +#define _gettch_nolock _getwch_nolock +#define _gettche _getwche +#define _gettche_nolock _getwche_nolock +#define _gettchar getwchar +#define _gettchar_nolock _getwchar_nolock +#define _getts _getws +#define _puttc putwc +#define _puttc_nolock _putwc_nolock +#define _puttchar putwchar +#define _puttchar_nolock _putwchar_nolock +#define _puttch _putwch +#define _puttch_nolock _putwch_nolock +#define _putts _putws +#define _ungettc ungetwc +#define _ungettc_nolock _ungetwc_nolock +#define _ungettch _ungetwch +#define _ungettch_nolock _ungetwch_nolock + +#define _tcstod wcstod +#define _tcstol wcstol +#define _tcstoul wcstoul +#define _tcstoi64 _wcstoi64 +#define _tcstoui64 _wcstoui64 +#define _tstof _wtof +#define _tstol _wtol +#define _tstoi _wtoi +#define _tstoi64 _wtoi64 +#define _tcstod_l _wcstod_l +#define _tcstol_l _wcstol_l +#define _tcstoul_l _wcstoul_l +#define _tcstoi64_l _wcstoi64_l +#define _tcstoui64_l _wcstoui64_l +#define _tstof_l _wtof_l +#define _tstol_l _wtol_l +#define _tstoi_l _wtoi_l +#define _tstoi64_l _wtoi64_l + +#define _itot _itow +#define _ltot _ltow +#define _ultot _ultow +#define _ttoi _wtoi +#define _ttol _wtol + +#define _ttoi64 _wtoi64 +#define _i64tot _i64tow +#define _ui64tot _ui64tow + +#define _tcscat wcscat +#define _tcschr wcschr +#define _tcscpy wcscpy +#define _tcscspn wcscspn +#define _tcslen wcslen +#define _tcsnlen wcsnlen +#define _tcsncat wcsncat +#define _tcsncat_l _wcsncat_l +#define _tcsncpy wcsncpy +#define _tcsncpy_l _wcsncpy_l +#define _tcspbrk wcspbrk +#define _tcsrchr wcsrchr +#define _tcsspn wcsspn +#define _tcsstr wcsstr +#define _tcstok wcstok +#define _tcstok_l _wcstok_l +#define _tcserror _wcserror +#define __tcserror __wcserror + +#define _tcsdup _wcsdup +#define _tcsnset _wcsnset +#define _tcsnset_l _wcsnset_l +#define _tcsrev _wcsrev +#define _tcsset _wcsset +#define _tcsset_l _wcsset_l + +#define _tcscmp wcscmp +#define _tcsicmp _wcsicmp +#define _tcsicmp_l _wcsicmp_l +#define _tcsnccmp wcsncmp +#define _tcsncmp wcsncmp +#define _tcsncicmp _wcsnicmp +#define _tcsncicmp_l _wcsnicmp_l +#define _tcsnicmp _wcsnicmp +#define _tcsnicmp_l _wcsnicmp_l + +#define _tcscoll wcscoll +#define _tcscoll_l _wcscoll_l +#define _tcsicoll _wcsicoll +#define _tcsicoll_l _wcsicoll_l +#define _tcsnccoll _wcsncoll +#define _tcsnccoll_l _wcsncoll_l +#define _tcsncoll _wcsncoll +#define _tcsncoll_l _wcsncoll_l +#define _tcsncicoll _wcsnicoll +#define _tcsncicoll_l _wcsnicoll_l +#define _tcsnicoll _wcsnicoll +#define _tcsnicoll_l _wcsnicoll_l + +#define _texecl _wexecl +#define _texecle _wexecle +#define _texeclp _wexeclp +#define _texeclpe _wexeclpe +#define _texecv _wexecv +#define _texecve _wexecve +#define _texecvp _wexecvp +#define _texecvpe _wexecvpe + +#define _tspawnl _wspawnl +#define _tspawnle _wspawnle +#define _tspawnlp _wspawnlp +#define _tspawnlpe _wspawnlpe +#define _tspawnv _wspawnv +#define _tspawnve _wspawnve +#define _tspawnvp _wspawnvp +#define _tspawnvp _wspawnvp +#define _tspawnvpe _wspawnvpe + +#define _tsystem _wsystem + +#define _tasctime _wasctime +#define _tctime _wctime +#define _tctime32 _wctime32 +#define _tctime64 _wctime64 +#define _tstrdate _wstrdate +#define _tstrtime _wstrtime +#define _tutime _wutime +#define _tutime32 _wutime32 +#define _tutime64 _wutime64 +#define _tcsftime wcsftime +#define _tcsftime_l _wcsftime_l + +#define _tchdir _wchdir +#define _tgetcwd _wgetcwd +#define _tgetdcwd _wgetdcwd +#define _tgetdcwd_nolock _wgetdcwd_nolock +#define _tmkdir _wmkdir +#define _trmdir _wrmdir + +#define _tfullpath _wfullpath +#define _tgetenv _wgetenv +#define _tmakepath _wmakepath +#define _tpgmptr _wpgmptr +#define _get_tpgmptr _get_wpgmptr +#define _tputenv _wputenv +#define _tsearchenv _wsearchenv +#define _tsplitpath _wsplitpath + +#define _tfdopen _wfdopen +#define _tfsopen _wfsopen +#define _tfopen _wfopen +#define _tfreopen _wfreopen +#define _tperror _wperror +#define _tpopen _wpopen +#define _ttempnam _wtempnam +#define _ttmpnam _wtmpnam + +#define _taccess _waccess +#define _tchmod _wchmod +#define _tcreat _wcreat +#define _tfindfirst _wfindfirst +#define _tfindfirst32 _wfindfirst32 +#define _tfindfirst64 _wfindfirst64 +#define _tfindfirsti64 _wfindfirsti64 +#define _tfindfirst32i64 _wfindfirst32i64 +#define _tfindfirst64i32 _wfindfirst64i32 +#define _tfindnext _wfindnext +#define _tfindnext32 _wfindnext32 +#define _tfindnext64 _wfindnext64 +#define _tfindnexti64 _wfindnexti64 +#define _tfindnext32i64 _wfindnext32i64 +#define _tfindnext64i32 _wfindnext64i32 +#define _tmktemp _wmktemp +#define _topen _wopen +#define _tremove _wremove +#define _trename _wrename +#define _tsopen _wsopen +#define _tunlink _wunlink + +#define _tfinddata_t _wfinddata_t +#define _tfinddata32_t _wfinddata32_t +#define _tfinddata64_t _wfinddata64_t +#define _tfinddatai64_t _wfinddatai64_t +#define _tfinddata32i64_t _wfinddata32i64_t +#define _tfinddata64i32_t _wfinddata64i32_t + +#define _tstat _wstat +#define _tstat32 _wstat32 +#define _tstat32i64 _wstat32i64 +#define _tstat64 _wstat64 +#define _tstat64i32 _wstat64i32 +#define _tstati64 _wstati64 + +#define _tsetlocale _wsetlocale + +#define _tcsclen wcslen +#define _tcscnlen wcsnlen +#define _tcsclen_l(_String,_Locale) wcslen(_String) +#define _tcscnlen_l(_String,_Max_count,_Locale) wcsnlen_l((_String),(_Max_count)) +#define _tcsnccat wcsncat +#define _tcsnccat_l _wcsncat_l +#define _tcsnccpy wcsncpy +#define _tcsnccpy_l _wcsncpy_l +#define _tcsncset _wcsnset + +#define _tcsdec _wcsdec +#define _tcsinc _wcsinc +#define _tcsnbcnt _wcsncnt +#define _tcsnccnt _wcsncnt +#define _tcsnextc _wcsnextc +#define _tcsninc _wcsninc +#define _tcsspnp _wcsspnp + +#define _tcslwr _wcslwr +#define _tcslwr_l _wcslwr_l +#define _tcsupr _wcsupr +#define _tcsupr_l _wcsupr_l +#define _tcsxfrm wcsxfrm +#define _tcsxfrm_l _wcsxfrm_l + +#define _tclen(_pc) (1) +#define _tccpy(_pc1,_cpc2) ((*(_pc1) = *(_cpc2))) +#define _tccmp(_cpc1,_cpc2) ((*(_cpc1))-(*(_cpc2))) + +#define _istalnum iswalnum +#define _istalnum_l _iswalnum_l +#define _istalpha iswalpha +#define _istalpha_l _iswalpha_l +#define _istascii iswascii +#define _istcntrl iswcntrl +#define _istcntrl_l _iswcntrl_l +#define _istdigit iswdigit +#define _istdigit_l _iswdigit_l +#define _istgraph iswgraph +#define _istgraph_l _iswgraph_l +#define _istlower iswlower +#define _istlower_l _iswlower_l +#define _istprint iswprint +#define _istprint_l _iswprint_l +#define _istpunct iswpunct +#define _istpunct_l _iswpunct_l +#define _istspace iswspace +#define _istspace_l _iswspace_l +#define _istupper iswupper +#define _istupper_l _iswupper_l +#define _istxdigit iswxdigit +#define _istxdigit_l _iswxdigit_l + +#define _totupper towupper +#define _totupper_l _towupper_l +#define _totlower towlower +#define _totlower_l _towlower_l + +#define _istlegal(_Char) (1) +#define _istlead(_Char) (0) +#define _istleadbyte(_Char) (0) +#define _istleadbyte_l(_Char,_Locale) (0) + +#define _wcsdec(_cpc1,_cpc2) ((_cpc1)>=(_cpc2) ? NULL : (_cpc2)-1) +#define _wcsinc(_pc) ((_pc)+1) +#define _wcsnextc(_cpc) ((unsigned int) *(_cpc)) +#define _wcsninc(_pc,_sz) (((_pc)+(_sz))) + _CRTIMP size_t __cdecl __wcsncnt(const wchar_t *_Str,size_t _MaxCount); +#define _wcsncnt(_cpc,_sz) (__wcsncnt(_cpc,_sz)) +#define _wcsspnp(_cpc1,_cpc2) (!_cpc1 ? NULL : ((*((_cpc1)+wcsspn(_cpc1,_cpc2))) ? ((_cpc1)+wcsspn(_cpc1,_cpc2)) : NULL)) +#define _wcsncpy_l(_Destination,_Source,_Count,_Locale) (wcsncpy(_Destination,_Source,_Count)) +#define _wcsncat_l(_Destination,_Source,_Count,_Locale) (wcsncat(_Destination,_Source,_Count)) +#define _wcstok_l(_String,_Delimiters,_Locale) (wcstok(_String,_Delimiters)) +#define _wcsnset_l(_Destination,_Value,_Count,_Locale) (_wcsnset(_Destination,_Value,_Count)) +#define _wcsset_l(_Destination,_Value,_Locale) (_wcsset(_Destination,_Value)) + + /* dirent structures and functions */ +#define _tdirent _wdirent +#define _TDIR _WDIR +#define _topendir _wopendir +#define _tclosedir _wclosedir +#define _treaddir _wreaddir +#define _trewinddir _wrewinddir +#define _ttelldir _wtelldir +#define _tseekdir _wseekdir + +#else + +#ifdef __cplusplus +} +#endif + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define _TEOF EOF + +#define __T(x) x + +#define _tmain main +#define _tWinMain WinMain +#ifdef _POSIX_ +#define _tenviron environ +#else +#define _tenviron _environ +#endif +#define __targv __argv + +#define _tprintf printf +#define _tprintf_l _printf_l +#define _tprintf_p _printf_p +#define _tprintf_p_l _printf_p_l +#define _tcprintf _cprintf +#define _tcprintf_l _cprintf_l +#define _tcprintf_p _cprintf_p +#define _tcprintf_p_l _cprintf_p_l +#define _vtcprintf _vcprintf +#define _vtcprintf_l _vcprintf_l +#define _vtcprintf_p _vcprintf_p +#define _vtcprintf_p_l _vcprintf_p_l +#define _ftprintf fprintf +#define _ftprintf_l _fprintf_l +#define _ftprintf_p _fprintf_p +#define _ftprintf_p_l _fprintf_p_l +#define _stprintf sprintf +#define _stprintf_l _sprintf_l +#define _stprintf_p _sprintf_p +#define _stprintf_p_l _sprintf_p_l +#define _sctprintf _scprintf +#define _sctprintf_l _scprintf_l +#define _sctprintf_p _scprintf_p +#define _sctprintf_p_l _scprintf_p_l +#define _sntprintf _snprintf +#define _sntprintf_l _snprintf_l +#define _vtprintf vprintf +#define _vtprintf_l _vprintf_l +#define _vtprintf_p _vprintf_p +#define _vtprintf_p_l _vprintf_p_l +#define _vftprintf vfprintf +#define _vftprintf_l _vfprintf_l +#define _vftprintf_p _vfprintf_p +#define _vftprintf_p_l _vfprintf_p_l +#define _vstprintf vsprintf +#define _vstprintf_l _vsprintf_l +#define _vstprintf_p _vsprintf_p +#define _vstprintf_p_l _vsprintf_p_l +#define _vsctprintf _vscprintf +#define _vsctprintf_l _vscprintf_l +#define _vsctprintf_p _vscprintf_p +#define _vsctprintf_p_l _vscprintf_p_l +#define _vsntprintf _vsnprintf +#define _vsntprintf_l _vsnprintf_l + +#define _tscanf scanf +#define _tscanf_l _scanf_l +#define _tcscanf _cscanf +#define _tcscanf_l _cscanf_l +#define _ftscanf fscanf +#define _ftscanf_l _fscanf_l +#define _stscanf sscanf +#define _stscanf_l _sscanf_l +#define _sntscanf _snscanf +#define _sntscanf_l _snscanf_l + +#define _fgettc fgetc +#define _fgettc_nolock _fgetc_nolock +#define _fgettchar _fgetchar +#define _fgetts fgets +#define _fputtc fputc +#define _fputtc_nolock _fputc_nolock +#define _fputtchar _fputchar +#define _fputts fputs +#define _cputts _cputs +#define _gettc getc +#define _gettc_nolock _getc_nolock +#define _gettch _getch +#define _gettch_nolock _getch_nolock +#define _gettche _getche +#define _gettche_nolock _getche_nolock +#define _gettchar getchar +#define _gettchar_nolock _getchar_nolock +#define _getts gets +#define _cgetts _cgets +#define _puttc putc +#define _puttc_nolock _putc_nolock +#define _puttchar putchar +#define _puttchar_nolock _putchar_nolock +#define _puttch _putch +#define _puttch_nolock _putch_nolock +#define _putts puts +#define _ungettc ungetc +#define _ungettc_nolock _ungetc_nolock +#define _ungettch _ungetch +#define _ungettch_nolock _ungetch_nolock + +#define _tcstod strtod +#define _tcstol strtol +#define _tcstoul strtoul +#define _tstof atof +#define _tstol atol +#define _tstoi atoi +#define _tstoi64 _atoi64 +#define _tcstod_l _strtod_l +#define _tcstol_l _strtol_l +#define _tcstoul_l _strtoul_l +#define _tstof_l _atof_l +#define _tstol_l _atol_l +#define _tstoi_l _atoi_l +#define _tstoi64_l _atoi64_l + +#define _itot _itoa +#define _ltot _ltoa +#define _ultot _ultoa +#define _ttoi atoi +#define _ttol atol + +#define _ttoi64 _atoi64 +#define _tcstoi64 _strtoi64 +#define _tcstoi64_l _strtoi64_l +#define _tcstoui64 _strtoui64 +#define _tcstoui64_l _strtoui64_l +#define _i64tot _i64toa +#define _ui64tot _ui64toa + +#define _tcscat strcat +#define _tcscpy strcpy +#define _tcsdup _strdup +#define _tcslen strlen +#if 0 +#define _tcsnlen strnlen +#endif +#define _tcsxfrm strxfrm +#define _tcsxfrm_l _strxfrm_l +#define _tcserror strerror +#define __tcserror _strerror + +#define _texecl _execl +#define _texecle _execle +#define _texeclp _execlp +#define _texeclpe _execlpe +#define _texecv _execv +#define _texecve _execve +#define _texecvp _execvp +#define _texecvpe _execvpe + +#define _tspawnl _spawnl +#define _tspawnle _spawnle +#define _tspawnlp _spawnlp +#define _tspawnlpe _spawnlpe +#define _tspawnv _spawnv +#define _tspawnve _spawnve +#define _tspawnvp _spawnvp +#define _tspawnvpe _spawnvpe + +#define _tsystem system + +#define _tasctime asctime +#define _tctime ctime +#define _tctime32 _ctime32 +#define _tctime64 _ctime64 +#define _tstrdate _strdate +#define _tstrtime _strtime +#define _tutime _utime +#define _tutime32 _utime32 +#define _tutime64 _utime64 +#define _tcsftime strftime +#define _tcsftime_l _strftime_l + +#define _tchdir _chdir +#define _tgetcwd _getcwd +#define _tgetdcwd _getdcwd +#define _tgetdcwd_nolock _getdcwd_nolock +#define _tmkdir _mkdir +#define _trmdir _rmdir + +#define _tfullpath _fullpath +#define _tgetenv getenv +#define _tmakepath _makepath +#define _tpgmptr _pgmptr +#define _get_tpgmptr _get_pgmptr +#define _tputenv _putenv +#define _tsearchenv _searchenv +#define _tsplitpath _splitpath + +#ifdef _POSIX_ +#define _tfdopen fdopen +#else +#define _tfdopen _fdopen +#endif +#define _tfsopen _fsopen +#define _tfopen fopen +#define _tfreopen freopen +#define _tperror perror +#define _tpopen _popen +#define _ttempnam _tempnam +#define _ttmpnam tmpnam + +#define _tchmod _chmod +#define _tcreat _creat +#define _tfindfirst _findfirst +#define _tfindfirst32 _findfirst32 +#define _tfindfirst64 _findfirst64 +#define _tfindfirsti64 _findfirsti64 +#define _tfindfirst32i64 _findfirst32i64 +#define _tfindfirst64i32 _findfirst64i32 +#define _tfindnext _findnext +#define _tfindnext32 _findnext32 +#define _tfindnext64 _findnext64 +#define _tfindnexti64 _findnexti64 +#define _tfindnext32i64 _findnext32i64 +#define _tfindnext64i32 _findnext64i32 +#define _tmktemp _mktemp + +#ifdef _POSIX_ +#define _topen open +#define _taccess access +#else +#define _topen _open +#define _taccess _access +#endif + +#define _tremove remove +#define _trename rename +#define _tsopen _sopen +#define _tunlink _unlink + +#define _tfinddata_t _finddata_t +#define _tfinddata32_t _finddata32_t +#define _tfinddata64_t __finddata64_t +#define _tfinddatai64_t _finddatai64_t +#define _tfinddata32i64_t _finddata32i64_t +#define _tfinddata64i32_t _finddata64i32_t + +#define _istascii __isascii +#define _istcntrl iscntrl +#define _istcntrl_l _iscntrl_l +#define _istxdigit isxdigit +#define _istxdigit_l _isxdigit_l + +#define _tstat _stat +#define _tstat32 _stat32 +#define _tstat32i64 _stat32i64 +#define _tstat64 _stat64 +#define _tstat64i32 _stat64i32 +#define _tstati64 _stati64 + +#define _tsetlocale setlocale + +#ifdef _MBCS + +#ifdef __cplusplus +} +#endif + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __TCHAR_DEFINED + typedef char _TCHAR; + typedef signed char _TSCHAR; + typedef unsigned char _TUCHAR; + typedef unsigned char _TXCHAR; + typedef unsigned int _TINT; +#define __TCHAR_DEFINED +#endif + +#ifndef _TCHAR_DEFINED +#ifndef NO_OLDNAMES + typedef char TCHAR; +#endif +#define _TCHAR_DEFINED +#endif + +#ifdef _MB_MAP_DIRECT + +#define _tcschr _mbschr +#define _tcscspn _mbscspn +#define _tcsncat _mbsnbcat +#define _tcsncat_l _mbsnbcat_l +#define _tcsncpy _mbsnbcpy +#define _tcsncpy_l _mbsnbcpy_l +#define _tcspbrk _mbspbrk +#define _tcsrchr _mbsrchr +#define _tcsspn _mbsspn +#define _tcsstr _mbsstr +#define _tcstok _mbstok +#define _tcstok_l _mbstok_l + +#define _tcsnset _mbsnbset +#define _tcsnset_l _mbsnbset_l +#define _tcsrev _mbsrev +#define _tcsset _mbsset +#define _tcsset_l _mbsset_l + +#define _tcscmp _mbscmp +#define _tcsicmp _mbsicmp +#define _tcsicmp_l _mbsicmp_l +#define _tcsnccmp _mbsncmp +#define _tcsncmp _mbsnbcmp +#define _tcsncicmp _mbsnicmp +#define _tcsncicmp_l _mbsnicmp_l +#define _tcsnicmp _mbsnbicmp +#define _tcsnicmp_l _mbsnbicmp_l + +#define _tcscoll _mbscoll +#define _tcscoll_l _mbscoll_l +#define _tcsicoll _mbsicoll +#define _tcsicoll_l _mbsicoll_l +#define _tcsnccoll _mbsncoll +#define _tcsnccoll_l _mbsncoll_l +#define _tcsncoll _mbsnbcoll +#define _tcsncoll_l _mbsnbcoll_l +#define _tcsncicoll _mbsnicoll +#define _tcsncicoll_l _mbsnicoll_l +#define _tcsnicoll _mbsnbicoll +#define _tcsnicoll_l _mbsnbicoll_l + +#define _tcsclen _mbslen +#define _tcscnlen _mbsnlen +#define _tcsclen_l _mbslen_l +#define _tcscnlen_l _mbsnlen_l +#define _tcsnccat _mbsncat +#define _tcsnccat_l _mbsncat_l +#define _tcsnccpy _mbsncpy +#define _tcsnccpy_l _mbsncpy_l +#define _tcsncset _mbsnset +#define _tcsncset_l _mbsnset_l + +#define _tcsdec _mbsdec +#define _tcsinc _mbsinc +#define _tcsnbcnt _mbsnbcnt +#define _tcsnccnt _mbsnccnt +#define _tcsnextc _mbsnextc +#define _tcsninc _mbsninc +#define _tcsspnp _mbsspnp + +#define _tcslwr _mbslwr +#define _tcslwr_l _mbslwr_l +#define _tcsupr _mbsupr +#define _tcsupr_l _mbsupr_l + +#define _tclen _mbclen +#define _tccpy _mbccpy +#define _tccpy_l _mbccpy_l +#else + + _CRTIMP _CONST_RETURN char *__cdecl _tcschr(const char *_Str,unsigned int _Val); + _CRTIMP size_t __cdecl _tcscspn(const char *_Str,const char *_Control); + _CRTIMP char *__cdecl _tcsncat(char *_Dst,const char *_Src,size_t _MaxCount); + _CRTIMP char *__cdecl _tcsncat_l(char *_Dst,const char *_Src,size_t _MaxCount,_locale_t _Locale); + _CRTIMP char *__cdecl _tcsncpy(char *_Dst,const char *_Src,size_t _MaxCount); + _CRTIMP char *__cdecl _tcsncpy_l(char *_Dst,const char *_Src,size_t _MaxCount,_locale_t _Locale); + _CRTIMP _CONST_RETURN char *__cdecl _tcspbrk(const char *_Str,const char *_Control); + _CRTIMP _CONST_RETURN char *__cdecl _tcsrchr(const char *_Str,unsigned int _Ch); + _CRTIMP size_t __cdecl _tcsspn(const char *_Str,const char *_Control); + _CRTIMP _CONST_RETURN char *__cdecl _tcsstr(const char *_Str,const char *_Substr); + _CRTIMP char *__cdecl _tcstok(char *_Str,const char *_Delim); + _CRTIMP char *__cdecl _tcstok_l(char *_Str,const char *_Delim,_locale_t _Locale); + _CRTIMP char *__cdecl _tcsnset(char *_Str,unsigned int _Val,size_t _MaxCount); + _CRTIMP char *__cdecl _tcsrev(char *_Str); + _CRTIMP char *__cdecl _tcsset(char *_Str,unsigned int _Val); + _CRTIMP char *__cdecl _tcsset_l(char *_Str,unsigned int _Val,_locale_t _Locale); + _CRTIMP int __cdecl _tcscmp(const char *_Str1,const char *_Str); + _CRTIMP int __cdecl _tcsicmp(const char *_Str1,const char *_Str2); + _CRTIMP int __cdecl _tcsicmp_l(const char *_Str1,const char *_Str2,_locale_t _Locale); + _CRTIMP int __cdecl _tcsnccmp(const char *_Str1,const char *_Str2,size_t _MaxCount); + _CRTIMP int __cdecl _tcsncmp(const char *_Str1,const char *_Str2,size_t _MaxCount); + _CRTIMP int __cdecl _tcsncicmp(const char *_Str1,const char *_Str2,size_t _MaxCount); + _CRTIMP int __cdecl _tcsncicmp_l(const char *_Str1,const char *_Str2,size_t _MaxCount,_locale_t _Locale); + _CRTIMP int __cdecl _tcsnicmp(const char *_Str1,const char *_Str2,size_t _MaxCount); + _CRTIMP int __cdecl _tcsnicmp_l(const char *_Str1,const char *_Str2,size_t _MaxCount,_locale_t _Locale); + _CRTIMP int __cdecl _tcscoll(const char *_Str1,const char *_Str2); + _CRTIMP int __cdecl _tcscoll_l(const char *_Str1,const char *_Str2,_locale_t _Locale); + _CRTIMP int __cdecl _tcsicoll(const char *_Str1,const char *_Str2); + _CRTIMP int __cdecl _tcsicoll_l(const char *_Str1,const char *_Str2,_locale_t _Locale); + _CRTIMP int __cdecl _tcsnccoll(const char *_Str1,const char *_Str2,size_t _MaxCount); + _CRTIMP int __cdecl _tcsnccoll_l(const char *_Str1,const char *_Str2,size_t _MaxCount,_locale_t _Locale); + _CRTIMP int __cdecl _tcsncoll(const char *_Str1,const char *_Str2,size_t _MaxCount); + _CRTIMP int __cdecl _tcsncoll_l(const char *_Str1,const char *_Str2,size_t _MaxCount,_locale_t _Locale); + _CRTIMP int __cdecl _tcsncicoll(const char *_Str1,const char *_Str2,size_t _MaxCount); + _CRTIMP int __cdecl _tcsncicoll_l(const char *_Str1,const char *_Str2,size_t _MaxCount,_locale_t _Locale); + _CRTIMP int __cdecl _tcsnicoll(const char *_Str1,const char *_Str2,size_t _MaxCount); + _CRTIMP int __cdecl _tcsnicoll_l(const char *_Str1,const char *_Str2,size_t _MaxCount,_locale_t _Locale); + _CRTIMP size_t __cdecl _tcsclen(const char *_Str); + _CRTIMP size_t __cdecl _tcscnlen(const char *_Str,size_t _MaxCount); + _CRTIMP size_t __cdecl _tcsclen_l(const char *_Str,_locale_t _Locale); + _CRTIMP size_t __cdecl _tcscnlen_l(const char *_Str,size_t _MaxCount,_locale_t _Locale); + _CRTIMP char *__cdecl _tcsnccat(char *_Dst,const char *_Src,size_t _MaxCount); + _CRTIMP char *__cdecl _tcsnccat_l(char *_Dst,const char *_Src,size_t _MaxCount,_locale_t _Locale); + _CRTIMP char *__cdecl _tcsnccpy(char *_Dst,const char *_Src,size_t _MaxCount); + _CRTIMP char *__cdecl _tcsnccpy_l(char *_Dst,const char *_Src,size_t _MaxCount,_locale_t _Locale); + _CRTIMP char *__cdecl _tcsncset(char *_Str,unsigned int _Val,size_t _MaxCount); + _CRTIMP char *__cdecl _tcsdec(const char *_Start,const char *_Pos); + _CRTIMP char *__cdecl _tcsinc(const char *_Ptr); + _CRTIMP size_t __cdecl _tcsnbcnt(const char *_Str,size_t _MaxCount); + _CRTIMP size_t __cdecl _tcsnccnt(const char *_Str,size_t _MaxCount); + _CRTIMP unsigned int __cdecl _tcsnextc (const char *_Str); + _CRTIMP char *__cdecl _tcsninc(const char *_Ptr,size_t _Count); + _CRTIMP char *__cdecl _tcsspnp(const char *_Str1,const char *_Str2); + _CRTIMP char *__cdecl _tcslwr(char *_Str); + _CRTIMP char *__cdecl _tcslwr_l(char *_Str,_locale_t _Locale); + _CRTIMP char *__cdecl _tcsupr(char *_Str); + _CRTIMP char *__cdecl _tcsupr_l(char *_Str,_locale_t _Locale); + _CRTIMP size_t __cdecl _tclen(const char *_Str); + _CRTIMP void __cdecl _tccpy(char *_DstCh,const char *_SrcCh); + +#ifdef __cplusplus +#ifndef _CPP_TCHAR_INLINES_DEFINED +#define _CPP_TCHAR_INLINES_DEFINED + extern "C++" { + extern inline char *__cdecl _tcschr(char *_S,unsigned int _C) { return ((char *)_tcschr((const char *)_S,_C)); } + extern inline char *__cdecl _tcspbrk(char *_S,const char *_P) { return ((char *)_tcspbrk((const char *)_S,_P)); } + extern inline char *__cdecl _tcsrchr(char *_S,unsigned int _C) { return ((char *)_tcsrchr((const char *)_S,_C)); } + extern inline char *__cdecl _tcsstr(char *_S,const char *_P) { return ((char *)_tcsstr((const char *)_S,_P)); } + } +#endif +#endif +#endif + +#define _tccmp(_cp1,_cp2) _tcsnccmp(_cp1,_cp2,1) + +#define _istalnum _ismbcalnum +#define _istalnum_l _ismbcalnum_l +#define _istalpha _ismbcalpha +#define _istalpha_l _ismbcalpha_l +#define _istdigit _ismbcdigit +#define _istdigit_l _ismbcdigit_l +#define _istgraph _ismbcgraph +#define _istgraph_l _ismbcgraph_l +#define _istlegal _ismbclegal +#define _istlegal_l _ismbclegal_l +#define _istlower _ismbclower +#define _istlower_l _ismbclower_l +#define _istprint _ismbcprint +#define _istprint_l _ismbcprint_l +#define _istpunct _ismbcpunct +#define _istpunct_l _ismbcpunct_l +#define _istspace _ismbcspace +#define _istspace_l _ismbcspace_l +#define _istupper _ismbcupper +#define _istupper_l _ismbcupper_l + +#define _totupper _mbctoupper +#define _totupper_l _mbctoupper_l +#define _totlower _mbctolower +#define _totlower_l _mbctolower_l + +#define _istlead _ismbblead +#define _istleadbyte isleadbyte +#define _istleadbyte_l _isleadbyte_l +#else + +#ifndef __TCHAR_DEFINED +#define __TCHAR_DEFINED + typedef char _TCHAR; + typedef signed char _TSCHAR; + typedef unsigned char _TUCHAR; + typedef char _TXCHAR; + typedef int _TINT; +#endif + +#ifndef _TCHAR_DEFINED +#define _TCHAR_DEFINED +#ifndef NO_OLDNAMES + typedef char TCHAR; +#endif +#endif + +#define _tcschr strchr +#define _tcscspn strcspn +#define _tcsncat strncat +#define _tcsncat_l _strncat_l +#define _tcsncpy strncpy +#define _tcsncpy_l _strncpy_l +#define _tcspbrk strpbrk +#define _tcsrchr strrchr +#define _tcsspn strspn +#define _tcsstr strstr +#define _tcstok strtok +#define _tcstok_l _strtok_l + +#define _tcsnset _strnset +#define _tcsnset_l _strnset_l +#define _tcsrev _strrev +#define _tcsset _strset + +#define _tcscmp strcmp +#define _tcsicmp _stricmp +#define _tcsicmp_l _stricmp_l +#define _tcsnccmp strncmp +#define _tcsncmp strncmp +#define _tcsncicmp _strnicmp +#define _tcsncicmp_l _strnicmp_l +#define _tcsnicmp _strnicmp +#define _tcsnicmp_l _strnicmp_l + +#define _tcscoll strcoll +#define _tcscoll_l _strcoll_l +#define _tcsicoll _stricoll +#define _tcsicoll_l _stricoll_l +#define _tcsnccoll _strncoll +#define _tcsnccoll_l _strncoll_l +#define _tcsncoll _strncoll +#define _tcsncoll_l _strncoll_l +#define _tcsncicoll _strnicoll +#define _tcsncicoll_l _strnicoll_l +#define _tcsnicoll _strnicoll +#define _tcsnicoll_l _strnicoll_l + +#define _tcsclen strlen +#define _tcscnlen strnlen +#define _tcsclen_l(_String,_Locale) strlen(_String) +#define _tcscnlen_l(_String,_Max_count,_Locale) strnlen_l((_String),(_Max_count)) +#define _tcsnccat strncat +#define _tcsnccat_l _strncat_l +#define _tcsnccpy strncpy +#define _tcsnccpy_l _strncpy_l +#define _tcsncset _strnset + +#define _tcsdec _strdec +#define _tcsinc _strinc +#define _tcsnbcnt _strncnt +#define _tcsnccnt _strncnt +#define _tcsnextc _strnextc +#define _tcsninc _strninc +#define _tcsspnp _strspnp + +#define _tcslwr _strlwr +#define _tcslwr_l _strlwr_l +#define _tcsupr _strupr +#define _tcsupr_l _strupr_l +#define _tcsxfrm strxfrm +#define _tcsxfrm_l _strxfrm_l + +#define _istlead(_Char) (0) +#define _istleadbyte(_Char) (0) +#define _istleadbyte_l(_Char,_Locale) (0) + +#define _tclen(_pc) (1) +#define _tccpy(_pc1,_cpc2) (*(_pc1) = *(_cpc2)) +#define _tccmp(_cpc1,_cpc2) (((unsigned char)*(_cpc1))-((unsigned char)*(_cpc2))) + + /* dirent structures and functions */ +#define _tdirent dirent +#define _TDIR DIR +#define _topendir opendir +#define _tclosedir closedir +#define _treaddir readdir +#define _trewinddir rewinddir +#define _ttelldir telldir +#define _tseekdir seekdir + +#define _istalnum isalnum +#define _istalnum_l _isalnum_l +#define _istalpha isalpha +#define _istalpha_l _isalpha_l +#define _istdigit isdigit +#define _istdigit_l _isdigit_l +#define _istgraph isgraph +#define _istgraph_l _isgraph_l +#define _istlower islower +#define _istlower_l _islower_l +#define _istprint isprint +#define _istprint_l _isprint_l +#define _istpunct ispunct +#define _istpunct_l _ispunct_l +#define _istspace isspace +#define _istspace_l _isspace_l +#define _istupper isupper +#define _istupper_l _isupper_l + +#define _totupper toupper +#define _totupper_l _toupper_l +#define _totlower tolower +#define _totlower_l _tolower_l + +#define _istlegal(_c) (1) + +#ifndef NULL +#ifdef __cplusplus +#define NULL 0 +#else +#define NULL ((void *)0) +#endif +#endif + +#define _strdec(_cpc1,_cpc2) ((_cpc1)>=(_cpc2) ? NULL : (_cpc2)-1) +#define _strinc(_pc) ((_pc)+1) +#define _strnextc(_cpc) ((unsigned int) *(const unsigned char *)(_cpc)) +#define _strninc(_pc,_sz) (((_pc)+(_sz))) + _CRTIMP size_t __cdecl __strncnt(const char *_Str,size_t _Cnt); +#define _strncnt(_cpc,_sz) (__strncnt(_cpc,_sz)) +#define _strspnp(_cpc1,_cpc2) (!_cpc1 ? NULL : ((*((_cpc1)+strspn(_cpc1,_cpc2))) ? ((_cpc1)+strspn(_cpc1,_cpc2)) : NULL)) + +#define _strncpy_l(_Destination,_Source,_Count,_Locale) (strncpy(_Destination,_Source,_Count)) +#define _strncat_l(_Destination,_Source,_Count,_Locale) (strncat(_Destination,_Source,_Count)) +#define _strtok_l(_String,_Delimiters,_Locale) (strtok(_String,_Delimiters)) +#define _strnset_l(_Destination,_Value,_Count,_Locale) (_strnset(_Destination,_Value,_Count)) +#define _strset_l(_Destination,_Value,_Locale) (_strset(_Destination,_Value)) +#endif +#endif + +#define _T(x) __T(x) +#define _TEXT(x) __T(x) + +#ifdef __cplusplus +} +#endif + +#include +#endif diff --git a/tinyc/win32/include/time.h b/tinyc/win32/include/time.h new file mode 100644 index 000000000..6c72e2660 --- /dev/null +++ b/tinyc/win32/include/time.h @@ -0,0 +1,287 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _TIME_H_ +#define _TIME_H_ + +#include <_mingw.h> + +#ifndef _WIN32 +#error Only Win32 target is supported! +#endif + +#pragma pack(push,_CRT_PACKING) + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _CRTIMP +#define _CRTIMP __declspec(dllimport) +#endif + +#ifndef _WCHAR_T_DEFINED +#define _WCHAR_T_DEFINED + typedef unsigned short wchar_t; +#endif + +#ifndef _TIME32_T_DEFINED +#define _TIME32_T_DEFINED + typedef long __time32_t; +#endif + +#ifndef _TIME64_T_DEFINED +#define _TIME64_T_DEFINED +#if _INTEGRAL_MAX_BITS >= 64 +#if defined(__GNUC__) && defined(__STRICT_ANSI__) + typedef int _time64_t __attribute__ ((mode (DI))); +#else + typedef __int64 __time64_t; +#endif +#endif +#endif + +#ifndef _TIME_T_DEFINED +#define _TIME_T_DEFINED +#ifdef _USE_32BIT_TIME_T + typedef __time32_t time_t; +#else + typedef __time64_t time_t; +#endif +#endif + +#ifndef _CLOCK_T_DEFINED +#define _CLOCK_T_DEFINED + typedef long clock_t; +#endif + +#ifndef _SIZE_T_DEFINED +#define _SIZE_T_DEFINED +#undef size_t +#ifdef _WIN64 +#if defined(__GNUC__) && defined(__STRICT_ANSI__) + typedef unsigned int size_t __attribute__ ((mode (DI))); +#else + typedef unsigned __int64 size_t; +#endif +#else + typedef unsigned int size_t; +#endif +#endif + +#ifndef _SSIZE_T_DEFINED +#define _SSIZE_T_DEFINED +#undef ssize_t +#ifdef _WIN64 +#if defined(__GNUC__) && defined(__STRICT_ANSI__) + typedef int ssize_t __attribute__ ((mode (DI))); +#else + typedef __int64 ssize_t; +#endif +#else + typedef int ssize_t; +#endif +#endif + +#ifndef NULL +#ifdef __cplusplus +#define NULL 0 +#else +#define NULL ((void *)0) +#endif +#endif + +#ifdef _USE_32BIT_TIME_T +#define _localtime32 localtime +#define _difftime32 difftime +#define _ctime32 ctime +#define _gmtime32 gmtime +#define _mktime32 mktime +#define _time32 time +#endif + +#ifndef _TM_DEFINED +#define _TM_DEFINED + struct tm { + int tm_sec; + int tm_min; + int tm_hour; + int tm_mday; + int tm_mon; + int tm_year; + int tm_wday; + int tm_yday; + int tm_isdst; + }; +#endif + +#define CLOCKS_PER_SEC 1000 + + __MINGW_IMPORT int _daylight; + __MINGW_IMPORT long _dstbias; + __MINGW_IMPORT long _timezone; + __MINGW_IMPORT char * _tzname[2]; + _CRTIMP errno_t __cdecl _get_daylight(int *_Daylight); + _CRTIMP errno_t __cdecl _get_dstbias(long *_Daylight_savings_bias); + _CRTIMP errno_t __cdecl _get_timezone(long *_Timezone); + _CRTIMP errno_t __cdecl _get_tzname(size_t *_ReturnValue,char *_Buffer,size_t _SizeInBytes,int _Index); + char *__cdecl asctime(const struct tm *_Tm); + _CRTIMP char *__cdecl _ctime32(const __time32_t *_Time); + clock_t __cdecl clock(void); + _CRTIMP double __cdecl _difftime32(__time32_t _Time1,__time32_t _Time2); + _CRTIMP struct tm *__cdecl _gmtime32(const __time32_t *_Time); + _CRTIMP struct tm *__cdecl _localtime32(const __time32_t *_Time); + size_t __cdecl strftime(char *_Buf,size_t _SizeInBytes,const char *_Format,const struct tm *_Tm); + _CRTIMP size_t __cdecl _strftime_l(char *_Buf,size_t _Max_size,const char *_Format,const struct tm *_Tm,_locale_t _Locale); + _CRTIMP char *__cdecl _strdate(char *_Buffer); + _CRTIMP char *__cdecl _strtime(char *_Buffer); + _CRTIMP __time32_t __cdecl _time32(__time32_t *_Time); + _CRTIMP __time32_t __cdecl _mktime32(struct tm *_Tm); + _CRTIMP __time32_t __cdecl _mkgmtime32(struct tm *_Tm); +#if defined (_POSIX_) || defined(__GNUC__) + void __cdecl tzset(void); +#else + _CRTIMP void __cdecl _tzset(void); +#endif + +#if _INTEGRAL_MAX_BITS >= 64 + double __cdecl _difftime64(__time64_t _Time1,__time64_t _Time2); + _CRTIMP char *__cdecl _ctime64(const __time64_t *_Time); + _CRTIMP struct tm *__cdecl _gmtime64(const __time64_t *_Time); + _CRTIMP struct tm *__cdecl _localtime64(const __time64_t *_Time); + _CRTIMP __time64_t __cdecl _mktime64(struct tm *_Tm); + _CRTIMP __time64_t __cdecl _mkgmtime64(struct tm *_Tm); + _CRTIMP __time64_t __cdecl _time64(__time64_t *_Time); +#endif + unsigned __cdecl _getsystime(struct tm *_Tm); + unsigned __cdecl _setsystime(struct tm *_Tm,unsigned _MilliSec); + +#ifndef _SIZE_T_DEFINED +#define _SIZE_T_DEFINED +#ifdef _WIN64 +#if defined(__GNUC__) && defined(__STRICT_ANSI__) + typedef unsigned int size_t __attribute__ ((mode (DI))); +#else + typedef unsigned __int64 size_t; +#endif +#else + typedef unsigned long size_t; +#endif +#endif + +#ifndef _SSIZE_T_DEFINED +#define _SSIZE_T_DEFINED +#ifdef _WIN64 +#if defined(__GNUC__) && defined(__STRICT_ANSI__) + typedef int ssize_t __attribute__ ((mode (DI))); +#else + typedef __int64 ssize_t; +#endif +#else + typedef long ssize_t; +#endif +#endif + +#ifndef _WTIME_DEFINED + _CRTIMP wchar_t *__cdecl _wasctime(const struct tm *_Tm); + _CRTIMP wchar_t *__cdecl _wctime32(const __time32_t *_Time); + size_t __cdecl wcsftime(wchar_t *_Buf,size_t _SizeInWords,const wchar_t *_Format,const struct tm *_Tm); + _CRTIMP size_t __cdecl _wcsftime_l(wchar_t *_Buf,size_t _SizeInWords,const wchar_t *_Format,const struct tm *_Tm,_locale_t _Locale); + _CRTIMP wchar_t *__cdecl _wstrdate(wchar_t *_Buffer); + _CRTIMP wchar_t *__cdecl _wstrtime(wchar_t *_Buffer); +#if _INTEGRAL_MAX_BITS >= 64 + _CRTIMP wchar_t *__cdecl _wctime64(const __time64_t *_Time); +#endif + +#if !defined (RC_INVOKED) && !defined (_INC_WTIME_INL) +#define _INC_WTIME_INL +#ifdef _USE_32BIT_TIME_T +__CRT_INLINE wchar_t *__cdecl _wctime(const time_t *_Time) { return _wctime32(_Time); } +#else +__CRT_INLINE wchar_t *__cdecl _wctime(const time_t *_Time) { return _wctime64(_Time); } +#endif +#endif + +#define _WTIME_DEFINED +#endif + +#ifndef RC_INVOKED +double __cdecl difftime(time_t _Time1,time_t _Time2); +char *__cdecl ctime(const time_t *_Time); +struct tm *__cdecl gmtime(const time_t *_Time); +struct tm *__cdecl localtime(const time_t *_Time); +struct tm *__cdecl localtime_r(const time_t *_Time,struct tm *); + +time_t __cdecl mktime(struct tm *_Tm); +time_t __cdecl _mkgmtime(struct tm *_Tm); +time_t __cdecl time(time_t *_Time); + +#ifdef _USE_32BIT_TIME_T +#if 0 +__CRT_INLINE double __cdecl difftime(time_t _Time1,time_t _Time2) { return _difftime32(_Time1,_Time2); } +__CRT_INLINE char *__cdecl ctime(const time_t *_Time) { return _ctime32(_Time); } +__CRT_INLINE struct tm *__cdecl gmtime(const time_t *_Time) { return _gmtime32(_Time); } +__CRT_INLINE struct tm *__cdecl localtime(const time_t *_Time) { return _localtime32(_Time); } +__CRT_INLINE time_t __cdecl mktime(struct tm *_Tm) { return _mktime32(_Tm); } +__CRT_INLINE time_t __cdecl _mkgmtime(struct tm *_Tm) { return _mkgmtime32(_Tm); } +__CRT_INLINE time_t __cdecl time(time_t *_Time) { return _time32(_Time); } +#endif +#else +__CRT_INLINE double __cdecl difftime(time_t _Time1,time_t _Time2) { return _difftime64(_Time1,_Time2); } +__CRT_INLINE char *__cdecl ctime(const time_t *_Time) { return _ctime64(_Time); } +__CRT_INLINE struct tm *__cdecl gmtime(const time_t *_Time) { return _gmtime64(_Time); } +__CRT_INLINE struct tm *__cdecl localtime(const time_t *_Time) { return _localtime64(_Time); } +__CRT_INLINE time_t __cdecl mktime(struct tm *_Tm) { return _mktime64(_Tm); } +__CRT_INLINE time_t __cdecl _mkgmtime(struct tm *_Tm) { return _mkgmtime64(_Tm); } +__CRT_INLINE time_t __cdecl time(time_t *_Time) { return _time64(_Time); } +#endif +#endif + +#if !defined(NO_OLDNAMES) || defined(_POSIX) +#define CLK_TCK CLOCKS_PER_SEC + + __MINGW_IMPORT int daylight; + __MINGW_IMPORT long dstbias; + __MINGW_IMPORT long timezone; + __MINGW_IMPORT char *tzname[2]; + void __cdecl tzset(void); +#endif + +#ifndef _TIMEVAL_DEFINED /* also in winsock[2].h */ +#define _TIMEVAL_DEFINED +struct timeval { + long tv_sec; + long tv_usec; +}; +#define timerisset(tvp) ((tvp)->tv_sec || (tvp)->tv_usec) +#define timercmp(tvp,uvp,cmp) ((tvp)->tv_sec cmp (uvp)->tv_sec || (tvp)->tv_sec==(uvp)->tv_sec && (tvp)->tv_usec cmp (uvp)->tv_usec) +#define timerclear(tvp) (tvp)->tv_sec = (tvp)->tv_usec = 0 +#endif /* _TIMEVAL_DEFINED */ + +#ifndef __STRICT_ANSI__ +#ifndef _TIMEZONE_DEFINED /* also in sys/time.h */ +#define _TIMEZONE_DEFINED +struct timezone { + int tz_minuteswest; + int tz_dsttime; +}; + + extern int __cdecl mingw_gettimeofday (struct timeval *p, struct timezone *z); +#endif +#endif /* __STRICT_ANSI__ */ + +#ifdef __cplusplus +} +#endif + +#pragma pack(pop) + +#include + +/* Adding timespec definition. */ +#include + +#endif /* End _TIME_H_ */ + diff --git a/tinyc/win32/include/vadefs.h b/tinyc/win32/include/vadefs.h new file mode 100644 index 000000000..749b0bdde --- /dev/null +++ b/tinyc/win32/include/vadefs.h @@ -0,0 +1,11 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _INC_VADEFS +#define _INC_VADEFS + +//!__TINYC__: GNUC specific stuff removed + +#endif diff --git a/tinyc/win32/include/values.h b/tinyc/win32/include/values.h new file mode 100644 index 000000000..1cd643cef --- /dev/null +++ b/tinyc/win32/include/values.h @@ -0,0 +1,4 @@ +/* + * TODO: Nothing here yet. Should provide UNIX compatibility constants + * comparable to those in limits.h and float.h. + */ diff --git a/tinyc/win32/include/wchar.h b/tinyc/win32/include/wchar.h new file mode 100644 index 000000000..389196faf --- /dev/null +++ b/tinyc/win32/include/wchar.h @@ -0,0 +1,873 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _INC_WCHAR +#define _INC_WCHAR + +#include <_mingw.h> + +#pragma pack(push,_CRT_PACKING) + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef WCHAR_MIN /* also at stdint.h */ +#define WCHAR_MIN 0 +#define WCHAR_MAX ((wchar_t) -1) /* UINT16_MAX */ +#endif + +#ifndef __GNUC_VA_LIST +#define __GNUC_VA_LIST + typedef __builtin_va_list __gnuc_va_list; +#endif + +#ifndef _VA_LIST_DEFINED +#define _VA_LIST_DEFINED + typedef __gnuc_va_list va_list; +#endif + +#ifndef WEOF +#define WEOF (wint_t)(0xFFFF) +#endif + +#ifndef _FILE_DEFINED + struct _iobuf { + char *_ptr; + int _cnt; + char *_base; + int _flag; + int _file; + int _charbuf; + int _bufsiz; + char *_tmpfname; + }; + typedef struct _iobuf FILE; +#define _FILE_DEFINED +#endif + +#ifndef _STDIO_DEFINED +#ifdef _WIN64 + _CRTIMP FILE *__cdecl __iob_func(void); +#else +#ifdef _MSVCRT_ +extern FILE _iob[]; /* A pointer to an array of FILE */ +#define __iob_func() (_iob) +#else +extern FILE (*_imp___iob)[]; /* A pointer to an array of FILE */ +#define __iob_func() (*_imp___iob) +#define _iob __iob_func() +#endif +#endif + +#define _iob __iob_func() +#endif + +#ifndef _STDSTREAM_DEFINED +#define stdin (&__iob_func()[0]) +#define stdout (&__iob_func()[1]) +#define stderr (&__iob_func()[2]) +#define _STDSTREAM_DEFINED +#endif + +#ifndef _FSIZE_T_DEFINED + typedef unsigned long _fsize_t; +#define _FSIZE_T_DEFINED +#endif + +#ifndef _WFINDDATA_T_DEFINED + struct _wfinddata32_t { + unsigned attrib; + __time32_t time_create; + __time32_t time_access; + __time32_t time_write; + _fsize_t size; + wchar_t name[260]; + }; + +/* #if _INTEGRAL_MAX_BITS >= 64 */ + + struct _wfinddata32i64_t { + unsigned attrib; + __time32_t time_create; + __time32_t time_access; + __time32_t time_write; + __int64 size; + wchar_t name[260]; + }; + + struct _wfinddata64i32_t { + unsigned attrib; + __time64_t time_create; + __time64_t time_access; + __time64_t time_write; + _fsize_t size; + wchar_t name[260]; + }; + + struct _wfinddata64_t { + unsigned attrib; + __time64_t time_create; + __time64_t time_access; + __time64_t time_write; + __int64 size; + wchar_t name[260]; + }; +/* #endif */ + +#ifdef _USE_32BIT_TIME_T +#define _wfinddata_t _wfinddata32_t +#define _wfinddatai64_t _wfinddata32i64_t + +#define _wfindfirst _wfindfirst32 +#define _wfindnext _wfindnext32 +#define _wfindfirsti64 _wfindfirst32i64 +#define _wfindnexti64 _wfindnext32i64 +#else +#define _wfinddata_t _wfinddata64i32_t +#define _wfinddatai64_t _wfinddata64_t + +#define _wfindfirst _wfindfirst64i32 +#define _wfindnext _wfindnext64i32 +#define _wfindfirsti64 _wfindfirst64 +#define _wfindnexti64 _wfindnext64 +#endif + +#define _WFINDDATA_T_DEFINED +#endif + +#ifndef NULL +#ifdef __cplusplus +#define NULL 0 +#else +#define NULL ((void *)0) +#endif +#endif + +#ifndef _CONST_RETURN +#define _CONST_RETURN +#endif + +#define _WConst_return _CONST_RETURN + +#ifndef _CRT_CTYPEDATA_DEFINED +#define _CRT_CTYPEDATA_DEFINED +#ifndef _CTYPE_DISABLE_MACROS + +#ifndef __PCTYPE_FUNC +#define __PCTYPE_FUNC __pctype_func() +#ifdef _MSVCRT_ +#define __pctype_func() (_pctype) +#else +#define __pctype_func() (*_imp___pctype) +#endif +#endif + +#ifndef _pctype +#ifdef _MSVCRT_ + extern unsigned short *_pctype; +#else + extern unsigned short **_imp___pctype; +#define _pctype (*_imp___pctype) +#endif +#endif +#endif +#endif + +#ifndef _CRT_WCTYPEDATA_DEFINED +#define _CRT_WCTYPEDATA_DEFINED +#ifndef _CTYPE_DISABLE_MACROS +#ifndef _wctype +#ifdef _MSVCRT_ + extern unsigned short *_wctype; +#else + extern unsigned short **_imp___wctype; +#define _wctype (*_imp___wctype) +#endif +#endif + +#ifdef _MSVCRT_ +#define __pwctype_func() (_pwctype) +#else +#define __pwctype_func() (*_imp___pwctype) +#endif + +#ifndef _pwctype +#ifdef _MSVCRT_ + extern unsigned short *_pwctype; +#else + extern unsigned short **_imp___pwctype; +#define _pwctype (*_imp___pwctype) +#endif +#endif + +#endif +#endif + +#define _UPPER 0x1 +#define _LOWER 0x2 +#define _DIGIT 0x4 +#define _SPACE 0x8 + +#define _PUNCT 0x10 +#define _CONTROL 0x20 +#define _BLANK 0x40 +#define _HEX 0x80 + +#define _LEADBYTE 0x8000 +#define _ALPHA (0x0100|_UPPER|_LOWER) + +#ifndef _WCTYPE_DEFINED +#define _WCTYPE_DEFINED + + int __cdecl iswalpha(wint_t _C); + _CRTIMP int __cdecl _iswalpha_l(wint_t _C,_locale_t _Locale); + int __cdecl iswupper(wint_t _C); + _CRTIMP int __cdecl _iswupper_l(wint_t _C,_locale_t _Locale); + int __cdecl iswlower(wint_t _C); + _CRTIMP int __cdecl _iswlower_l(wint_t _C,_locale_t _Locale); + int __cdecl iswdigit(wint_t _C); + _CRTIMP int __cdecl _iswdigit_l(wint_t _C,_locale_t _Locale); + int __cdecl iswxdigit(wint_t _C); + _CRTIMP int __cdecl _iswxdigit_l(wint_t _C,_locale_t _Locale); + int __cdecl iswspace(wint_t _C); + _CRTIMP int __cdecl _iswspace_l(wint_t _C,_locale_t _Locale); + int __cdecl iswpunct(wint_t _C); + _CRTIMP int __cdecl _iswpunct_l(wint_t _C,_locale_t _Locale); + int __cdecl iswalnum(wint_t _C); + _CRTIMP int __cdecl _iswalnum_l(wint_t _C,_locale_t _Locale); + int __cdecl iswprint(wint_t _C); + _CRTIMP int __cdecl _iswprint_l(wint_t _C,_locale_t _Locale); + int __cdecl iswgraph(wint_t _C); + _CRTIMP int __cdecl _iswgraph_l(wint_t _C,_locale_t _Locale); + int __cdecl iswcntrl(wint_t _C); + _CRTIMP int __cdecl _iswcntrl_l(wint_t _C,_locale_t _Locale); + int __cdecl iswascii(wint_t _C); + int __cdecl isleadbyte(int _C); + _CRTIMP int __cdecl _isleadbyte_l(int _C,_locale_t _Locale); + wint_t __cdecl towupper(wint_t _C); + _CRTIMP wint_t __cdecl _towupper_l(wint_t _C,_locale_t _Locale); + wint_t __cdecl towlower(wint_t _C); + _CRTIMP wint_t __cdecl _towlower_l(wint_t _C,_locale_t _Locale); + int __cdecl iswctype(wint_t _C,wctype_t _Type); + _CRTIMP int __cdecl _iswctype_l(wint_t _C,wctype_t _Type,_locale_t _Locale); + _CRTIMP int __cdecl __iswcsymf(wint_t _C); + _CRTIMP int __cdecl _iswcsymf_l(wint_t _C,_locale_t _Locale); + _CRTIMP int __cdecl __iswcsym(wint_t _C); + _CRTIMP int __cdecl _iswcsym_l(wint_t _C,_locale_t _Locale); + int __cdecl is_wctype(wint_t _C,wctype_t _Type); +#endif + +#ifndef _WDIRECT_DEFINED +#define _WDIRECT_DEFINED + + _CRTIMP wchar_t *__cdecl _wgetcwd(wchar_t *_DstBuf,int _SizeInWords); + _CRTIMP wchar_t *__cdecl _wgetdcwd(int _Drive,wchar_t *_DstBuf,int _SizeInWords); + wchar_t *__cdecl _wgetdcwd_nolock(int _Drive,wchar_t *_DstBuf,int _SizeInWords); + _CRTIMP int __cdecl _wchdir(const wchar_t *_Path); + _CRTIMP int __cdecl _wmkdir(const wchar_t *_Path); + _CRTIMP int __cdecl _wrmdir(const wchar_t *_Path); +#endif + +#ifndef _WIO_DEFINED +#define _WIO_DEFINED + + _CRTIMP int __cdecl _waccess(const wchar_t *_Filename,int _AccessMode); + _CRTIMP int __cdecl _wchmod(const wchar_t *_Filename,int _Mode); + _CRTIMP int __cdecl _wcreat(const wchar_t *_Filename,int _PermissionMode); + _CRTIMP intptr_t __cdecl _wfindfirst32(const wchar_t *_Filename,struct _wfinddata32_t *_FindData); + _CRTIMP int __cdecl _wfindnext32(intptr_t _FindHandle,struct _wfinddata32_t *_FindData); + _CRTIMP int __cdecl _wunlink(const wchar_t *_Filename); + _CRTIMP int __cdecl _wrename(const wchar_t *_NewFilename,const wchar_t *_OldFilename); + _CRTIMP wchar_t *__cdecl _wmktemp(wchar_t *_TemplateName); +#if _INTEGRAL_MAX_BITS >= 64 + _CRTIMP intptr_t __cdecl _wfindfirst32i64(const wchar_t *_Filename,struct _wfinddata32i64_t *_FindData); + intptr_t __cdecl _wfindfirst64i32(const wchar_t *_Filename,struct _wfinddata64i32_t *_FindData); + _CRTIMP intptr_t __cdecl _wfindfirst64(const wchar_t *_Filename,struct _wfinddata64_t *_FindData); + _CRTIMP int __cdecl _wfindnext32i64(intptr_t _FindHandle,struct _wfinddata32i64_t *_FindData); + int __cdecl _wfindnext64i32(intptr_t _FindHandle,struct _wfinddata64i32_t *_FindData); + _CRTIMP int __cdecl _wfindnext64(intptr_t _FindHandle,struct _wfinddata64_t *_FindData); +#endif + _CRTIMP errno_t __cdecl _wsopen_s(int *_FileHandle,const wchar_t *_Filename,int _OpenFlag,int _ShareFlag,int _PermissionFlag); +#if !defined(__cplusplus) || !(defined(_X86_) && !defined(__x86_64)) + _CRTIMP int __cdecl _wopen(const wchar_t *_Filename,int _OpenFlag,...); + _CRTIMP int __cdecl _wsopen(const wchar_t *_Filename,int _OpenFlag,int _ShareFlag,...); +#else + extern "C++" _CRTIMP int __cdecl _wopen(const wchar_t *_Filename,int _OpenFlag,int _PermissionMode = 0); + extern "C++" _CRTIMP int __cdecl _wsopen(const wchar_t *_Filename,int _OpenFlag,int _ShareFlag,int _PermissionMode = 0); +#endif +#endif + +#ifndef _WLOCALE_DEFINED +#define _WLOCALE_DEFINED + _CRTIMP wchar_t *__cdecl _wsetlocale(int _Category,const wchar_t *_Locale); +#endif + +#ifndef _WPROCESS_DEFINED +#define _WPROCESS_DEFINED + + _CRTIMP intptr_t __cdecl _wexecl(const wchar_t *_Filename,const wchar_t *_ArgList,...); + _CRTIMP intptr_t __cdecl _wexecle(const wchar_t *_Filename,const wchar_t *_ArgList,...); + _CRTIMP intptr_t __cdecl _wexeclp(const wchar_t *_Filename,const wchar_t *_ArgList,...); + _CRTIMP intptr_t __cdecl _wexeclpe(const wchar_t *_Filename,const wchar_t *_ArgList,...); + _CRTIMP intptr_t __cdecl _wexecv(const wchar_t *_Filename,const wchar_t *const *_ArgList); + _CRTIMP intptr_t __cdecl _wexecve(const wchar_t *_Filename,const wchar_t *const *_ArgList,const wchar_t *const *_Env); + _CRTIMP intptr_t __cdecl _wexecvp(const wchar_t *_Filename,const wchar_t *const *_ArgList); + _CRTIMP intptr_t __cdecl _wexecvpe(const wchar_t *_Filename,const wchar_t *const *_ArgList,const wchar_t *const *_Env); + _CRTIMP intptr_t __cdecl _wspawnl(int _Mode,const wchar_t *_Filename,const wchar_t *_ArgList,...); + _CRTIMP intptr_t __cdecl _wspawnle(int _Mode,const wchar_t *_Filename,const wchar_t *_ArgList,...); + _CRTIMP intptr_t __cdecl _wspawnlp(int _Mode,const wchar_t *_Filename,const wchar_t *_ArgList,...); + _CRTIMP intptr_t __cdecl _wspawnlpe(int _Mode,const wchar_t *_Filename,const wchar_t *_ArgList,...); + _CRTIMP intptr_t __cdecl _wspawnv(int _Mode,const wchar_t *_Filename,const wchar_t *const *_ArgList); + _CRTIMP intptr_t __cdecl _wspawnve(int _Mode,const wchar_t *_Filename,const wchar_t *const *_ArgList,const wchar_t *const *_Env); + _CRTIMP intptr_t __cdecl _wspawnvp(int _Mode,const wchar_t *_Filename,const wchar_t *const *_ArgList); + _CRTIMP intptr_t __cdecl _wspawnvpe(int _Mode,const wchar_t *_Filename,const wchar_t *const *_ArgList,const wchar_t *const *_Env); +#ifndef _CRT_WSYSTEM_DEFINED +#define _CRT_WSYSTEM_DEFINED + _CRTIMP int __cdecl _wsystem(const wchar_t *_Command); +#endif +#endif + +#ifndef _WCTYPE_INLINE_DEFINED +#undef _CRT_WCTYPE_NOINLINE +#if !defined(__cplusplus) || defined(_CRT_WCTYPE_NOINLINE) +#define iswalpha(_c) (iswctype(_c,_ALPHA)) +#define iswupper(_c) (iswctype(_c,_UPPER)) +#define iswlower(_c) (iswctype(_c,_LOWER)) +#define iswdigit(_c) (iswctype(_c,_DIGIT)) +#define iswxdigit(_c) (iswctype(_c,_HEX)) +#define iswspace(_c) (iswctype(_c,_SPACE)) +#define iswpunct(_c) (iswctype(_c,_PUNCT)) +#define iswalnum(_c) (iswctype(_c,_ALPHA|_DIGIT)) +#define iswprint(_c) (iswctype(_c,_BLANK|_PUNCT|_ALPHA|_DIGIT)) +#define iswgraph(_c) (iswctype(_c,_PUNCT|_ALPHA|_DIGIT)) +#define iswcntrl(_c) (iswctype(_c,_CONTROL)) +#define iswascii(_c) ((unsigned)(_c) < 0x80) + +#define _iswalpha_l(_c,_p) (_iswctype_l(_c,_ALPHA,_p)) +#define _iswupper_l(_c,_p) (_iswctype_l(_c,_UPPER,_p)) +#define _iswlower_l(_c,_p) (_iswctype_l(_c,_LOWER,_p)) +#define _iswdigit_l(_c,_p) (_iswctype_l(_c,_DIGIT,_p)) +#define _iswxdigit_l(_c,_p) (_iswctype_l(_c,_HEX,_p)) +#define _iswspace_l(_c,_p) (_iswctype_l(_c,_SPACE,_p)) +#define _iswpunct_l(_c,_p) (_iswctype_l(_c,_PUNCT,_p)) +#define _iswalnum_l(_c,_p) (_iswctype_l(_c,_ALPHA|_DIGIT,_p)) +#define _iswprint_l(_c,_p) (_iswctype_l(_c,_BLANK|_PUNCT|_ALPHA|_DIGIT,_p)) +#define _iswgraph_l(_c,_p) (_iswctype_l(_c,_PUNCT|_ALPHA|_DIGIT,_p)) +#define _iswcntrl_l(_c,_p) (_iswctype_l(_c,_CONTROL,_p)) +#ifndef _CTYPE_DISABLE_MACROS +#define isleadbyte(_c) (__PCTYPE_FUNC[(unsigned char)(_c)] & _LEADBYTE) +#endif +#endif +#define _WCTYPE_INLINE_DEFINED +#endif + +#if !defined(_POSIX_) || defined(__GNUC__) +#ifndef _INO_T_DEFINED +#define _INO_T_DEFINED + typedef unsigned short _ino_t; +#ifndef NO_OLDNAMES + typedef unsigned short ino_t; +#endif +#endif + +#ifndef _DEV_T_DEFINED +#define _DEV_T_DEFINED + typedef unsigned int _dev_t; +#ifndef NO_OLDNAMES + typedef unsigned int dev_t; +#endif +#endif + +#ifndef _OFF_T_DEFINED +#define _OFF_T_DEFINED +#ifndef _OFF_T_ +#define _OFF_T_ + typedef long _off_t; +#if !defined(NO_OLDNAMES) || defined(_POSIX) + typedef long off_t; +#endif +#endif +#endif + +#ifndef _OFF64_T_DEFINED +#define _OFF64_T_DEFINED + typedef long long _off64_t; +#if !defined(NO_OLDNAMES) || defined(_POSIX) + typedef long long off64_t; +#endif +#endif + +#ifndef _STAT_DEFINED +#define _STAT_DEFINED + +#ifdef _USE_32BIT_TIME_T +#ifdef WIN64 +#define _fstat _fstat32 +#define _stat _stat32 +#define _wstat _wstat32 +#else +#define _fstat32 _fstat +#define _stat32 _stat +#define _wstat32 _wstat +#endif +#define _fstati64 _fstat32i64 +#define _stati64 _stat32i64 +#define _wstati64 _wstat32i64 +#else +#define _fstat _fstat64i32 +#define _fstati64 _fstat64 +#define _stat _stat64i32 +#define _stati64 _stat64 +#define _wstat _wstat64i32 +#define _wstati64 _wstat64 +#endif + + struct _stat32 { + _dev_t st_dev; + _ino_t st_ino; + unsigned short st_mode; + short st_nlink; + short st_uid; + short st_gid; + _dev_t st_rdev; + _off_t st_size; + __time32_t st_atime; + __time32_t st_mtime; + __time32_t st_ctime; + }; + +#ifndef NO_OLDNAMES + struct stat { + _dev_t st_dev; + _ino_t st_ino; + unsigned short st_mode; + short st_nlink; + short st_uid; + short st_gid; + _dev_t st_rdev; + _off_t st_size; + time_t st_atime; + time_t st_mtime; + time_t st_ctime; + }; +#endif + +#if _INTEGRAL_MAX_BITS >= 64 + + struct _stat32i64 { + _dev_t st_dev; + _ino_t st_ino; + unsigned short st_mode; + short st_nlink; + short st_uid; + short st_gid; + _dev_t st_rdev; + __int64 st_size; + __time32_t st_atime; + __time32_t st_mtime; + __time32_t st_ctime; + }; + + struct _stat64i32 { + _dev_t st_dev; + _ino_t st_ino; + unsigned short st_mode; + short st_nlink; + short st_uid; + short st_gid; + _dev_t st_rdev; + _off_t st_size; + __time64_t st_atime; + __time64_t st_mtime; + __time64_t st_ctime; + }; + + struct _stat64 { + _dev_t st_dev; + _ino_t st_ino; + unsigned short st_mode; + short st_nlink; + short st_uid; + short st_gid; + _dev_t st_rdev; + __int64 st_size; + __time64_t st_atime; + __time64_t st_mtime; + __time64_t st_ctime; + }; +#endif + +#define __stat64 _stat64 + +#endif + +#ifndef _WSTAT_DEFINED +#define _WSTAT_DEFINED + + _CRTIMP int __cdecl _wstat32(const wchar_t *_Name,struct _stat32 *_Stat); +#if _INTEGRAL_MAX_BITS >= 64 + _CRTIMP int __cdecl _wstat32i64(const wchar_t *_Name,struct _stat32i64 *_Stat); + int __cdecl _wstat64i32(const wchar_t *_Name,struct _stat64i32 *_Stat); + _CRTIMP int __cdecl _wstat64(const wchar_t *_Name,struct _stat64 *_Stat); +#endif +#endif +#endif + +#ifndef _WCONIO_DEFINED +#define _WCONIO_DEFINED + +#ifndef WEOF +#define WEOF (wint_t)(0xFFFF) +#endif + + _CRTIMP wchar_t *_cgetws(wchar_t *_Buffer); + _CRTIMP wint_t __cdecl _getwch(void); + _CRTIMP wint_t __cdecl _getwche(void); + _CRTIMP wint_t __cdecl _putwch(wchar_t _WCh); + _CRTIMP wint_t __cdecl _ungetwch(wint_t _WCh); + _CRTIMP int __cdecl _cputws(const wchar_t *_String); + _CRTIMP int __cdecl _cwprintf(const wchar_t *_Format,...); + _CRTIMP int __cdecl _cwscanf(const wchar_t *_Format,...); + _CRTIMP int __cdecl _cwscanf_l(const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vcwprintf(const wchar_t *_Format,va_list _ArgList); + _CRTIMP int __cdecl _cwprintf_p(const wchar_t *_Format,...); + _CRTIMP int __cdecl _vcwprintf_p(const wchar_t *_Format,va_list _ArgList); + + _CRTIMP int __cdecl _cwprintf_l(const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vcwprintf_l(const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _cwprintf_p_l(const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vcwprintf_p_l(const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); + wint_t __cdecl _putwch_nolock(wchar_t _WCh); + wint_t __cdecl _getwch_nolock(void); + wint_t __cdecl _getwche_nolock(void); + wint_t __cdecl _ungetwch_nolock(wint_t _WCh); +#endif + +#ifndef _WSTDIO_DEFINED +#define _WSTDIO_DEFINED + +#ifndef WEOF +#define WEOF (wint_t)(0xFFFF) +#endif + +#ifdef _POSIX_ + _CRTIMP FILE *__cdecl _wfsopen(const wchar_t *_Filename,const wchar_t *_Mode); +#else + _CRTIMP FILE *__cdecl _wfsopen(const wchar_t *_Filename,const wchar_t *_Mode,int _ShFlag); +#endif + + wint_t __cdecl fgetwc(FILE *_File); + _CRTIMP wint_t __cdecl _fgetwchar(void); + wint_t __cdecl fputwc(wchar_t _Ch,FILE *_File); + _CRTIMP wint_t __cdecl _fputwchar(wchar_t _Ch); + wint_t __cdecl getwc(FILE *_File); + wint_t __cdecl getwchar(void); + wint_t __cdecl putwc(wchar_t _Ch,FILE *_File); + wint_t __cdecl putwchar(wchar_t _Ch); + wint_t __cdecl ungetwc(wint_t _Ch,FILE *_File); + wchar_t *__cdecl fgetws(wchar_t *_Dst,int _SizeInWords,FILE *_File); + int __cdecl fputws(const wchar_t *_Str,FILE *_File); + _CRTIMP wchar_t *__cdecl _getws(wchar_t *_String); + _CRTIMP int __cdecl _putws(const wchar_t *_Str); + int __cdecl fwprintf(FILE *_File,const wchar_t *_Format,...); + int __cdecl wprintf(const wchar_t *_Format,...); + _CRTIMP int __cdecl _scwprintf(const wchar_t *_Format,...); + int __cdecl vfwprintf(FILE *_File,const wchar_t *_Format,va_list _ArgList); + int __cdecl vwprintf(const wchar_t *_Format,va_list _ArgList); + _CRTIMP int __cdecl swprintf(wchar_t*, const wchar_t*, ...); + _CRTIMP int __cdecl vswprintf(wchar_t*, const wchar_t*,va_list); + _CRTIMP int __cdecl _swprintf_c(wchar_t *_DstBuf,size_t _SizeInWords,const wchar_t *_Format,...); + _CRTIMP int __cdecl _vswprintf_c(wchar_t *_DstBuf,size_t _SizeInWords,const wchar_t *_Format,va_list _ArgList); + _CRTIMP int __cdecl _snwprintf(wchar_t *_Dest,size_t _Count,const wchar_t *_Format,...); + _CRTIMP int __cdecl _vsnwprintf(wchar_t *_Dest,size_t _Count,const wchar_t *_Format,va_list _Args); +#ifndef __NO_ISOCEXT /* externs in libmingwex.a */ + int __cdecl snwprintf (wchar_t *s, size_t n, const wchar_t * format, ...); + __CRT_INLINE int __cdecl vsnwprintf (wchar_t *s, size_t n, const wchar_t *format, va_list arg) { return _vsnwprintf(s,n,format,arg); } + int __cdecl vwscanf (const wchar_t *, va_list); + int __cdecl vfwscanf (FILE *,const wchar_t *,va_list); + int __cdecl vswscanf (const wchar_t *,const wchar_t *,va_list); +#endif + _CRTIMP int __cdecl _fwprintf_p(FILE *_File,const wchar_t *_Format,...); + _CRTIMP int __cdecl _wprintf_p(const wchar_t *_Format,...); + _CRTIMP int __cdecl _vfwprintf_p(FILE *_File,const wchar_t *_Format,va_list _ArgList); + _CRTIMP int __cdecl _vwprintf_p(const wchar_t *_Format,va_list _ArgList); + _CRTIMP int __cdecl _swprintf_p(wchar_t *_DstBuf,size_t _MaxCount,const wchar_t *_Format,...); + _CRTIMP int __cdecl _vswprintf_p(wchar_t *_DstBuf,size_t _MaxCount,const wchar_t *_Format,va_list _ArgList); + _CRTIMP int __cdecl _scwprintf_p(const wchar_t *_Format,...); + _CRTIMP int __cdecl _vscwprintf_p(const wchar_t *_Format,va_list _ArgList); + _CRTIMP int __cdecl _wprintf_l(const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _wprintf_p_l(const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vwprintf_l(const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _vwprintf_p_l(const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _fwprintf_l(FILE *_File,const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _fwprintf_p_l(FILE *_File,const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vfwprintf_l(FILE *_File,const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _vfwprintf_p_l(FILE *_File,const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _swprintf_c_l(wchar_t *_DstBuf,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _swprintf_p_l(wchar_t *_DstBuf,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vswprintf_c_l(wchar_t *_DstBuf,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _vswprintf_p_l(wchar_t *_DstBuf,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _scwprintf_l(const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _scwprintf_p_l(const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vscwprintf_p_l(const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _snwprintf_l(wchar_t *_DstBuf,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vsnwprintf_l(wchar_t *_DstBuf,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _swprintf(wchar_t *_Dest,const wchar_t *_Format,...); + _CRTIMP int __cdecl _vswprintf(wchar_t *_Dest,const wchar_t *_Format,va_list _Args); + _CRTIMP int __cdecl __swprintf_l(wchar_t *_Dest,const wchar_t *_Format,_locale_t _Plocinfo,...); + _CRTIMP int __cdecl __vswprintf_l(wchar_t *_Dest,const wchar_t *_Format,_locale_t _Plocinfo,va_list _Args); +#ifndef RC_INVOKED +#include +#endif + +#ifdef _CRT_NON_CONFORMING_SWPRINTFS +#ifndef __cplusplus +#define swprintf _swprintf +#define vswprintf _vswprintf +#define _swprintf_l __swprintf_l +#define _vswprintf_l __vswprintf_l +#endif +#endif + + _CRTIMP wchar_t *__cdecl _wtempnam(const wchar_t *_Directory,const wchar_t *_FilePrefix); + _CRTIMP int __cdecl _vscwprintf(const wchar_t *_Format,va_list _ArgList); + _CRTIMP int __cdecl _vscwprintf_l(const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); + int __cdecl fwscanf(FILE *_File,const wchar_t *_Format,...); + _CRTIMP int __cdecl _fwscanf_l(FILE *_File,const wchar_t *_Format,_locale_t _Locale,...); + int __cdecl swscanf(const wchar_t *_Src,const wchar_t *_Format,...); + _CRTIMP int __cdecl _swscanf_l(const wchar_t *_Src,const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _snwscanf(const wchar_t *_Src,size_t _MaxCount,const wchar_t *_Format,...); + _CRTIMP int __cdecl _snwscanf_l(const wchar_t *_Src,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,...); + int __cdecl wscanf(const wchar_t *_Format,...); + _CRTIMP int __cdecl _wscanf_l(const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP FILE *__cdecl _wfdopen(int _FileHandle ,const wchar_t *_Mode); + _CRTIMP FILE *__cdecl _wfopen(const wchar_t *_Filename,const wchar_t *_Mode); + _CRTIMP FILE *__cdecl _wfreopen(const wchar_t *_Filename,const wchar_t *_Mode,FILE *_OldFile); + +#ifndef _CRT_WPERROR_DEFINED +#define _CRT_WPERROR_DEFINED + _CRTIMP void __cdecl _wperror(const wchar_t *_ErrMsg); +#endif + _CRTIMP FILE *__cdecl _wpopen(const wchar_t *_Command,const wchar_t *_Mode); +#if !defined(NO_OLDNAMES) && !defined(wpopen) +#define wpopen _wpopen +#endif + _CRTIMP int __cdecl _wremove(const wchar_t *_Filename); + _CRTIMP wchar_t *__cdecl _wtmpnam(wchar_t *_Buffer); + _CRTIMP wint_t __cdecl _fgetwc_nolock(FILE *_File); + _CRTIMP wint_t __cdecl _fputwc_nolock(wchar_t _Ch,FILE *_File); + _CRTIMP wint_t __cdecl _ungetwc_nolock(wint_t _Ch,FILE *_File); + +#undef _CRT_GETPUTWCHAR_NOINLINE + +#if !defined(__cplusplus) || defined(_CRT_GETPUTWCHAR_NOINLINE) +#define getwchar() fgetwc(stdin) +#define putwchar(_c) fputwc((_c),stdout) +#else + __CRT_INLINE wint_t __cdecl getwchar() {return (fgetwc(stdin)); } + __CRT_INLINE wint_t __cdecl putwchar(wchar_t _C) {return (fputwc(_C,stdout)); } +#endif + +#define getwc(_stm) fgetwc(_stm) +#define putwc(_c,_stm) fputwc(_c,_stm) +#define _putwc_nolock(_c,_stm) _fputwc_nolock(_c,_stm) +#define _getwc_nolock(_c) _fgetwc_nolock(_c) +#endif + +#ifndef _WSTDLIB_DEFINED +#define _WSTDLIB_DEFINED + + _CRTIMP wchar_t *__cdecl _itow(int _Value,wchar_t *_Dest,int _Radix); + _CRTIMP wchar_t *__cdecl _ltow(long _Value,wchar_t *_Dest,int _Radix); + _CRTIMP wchar_t *__cdecl _ultow(unsigned long _Value,wchar_t *_Dest,int _Radix); + double __cdecl wcstod(const wchar_t *_Str,wchar_t **_EndPtr); + _CRTIMP double __cdecl _wcstod_l(const wchar_t *_Str,wchar_t **_EndPtr,_locale_t _Locale); + float __cdecl wcstof( const wchar_t *nptr, wchar_t **endptr); +#if !defined __NO_ISOCEXT /* in libmingwex.a */ + float __cdecl wcstof (const wchar_t * __restrict__, wchar_t ** __restrict__); + long double __cdecl wcstold (const wchar_t * __restrict__, wchar_t ** __restrict__); +#endif /* __NO_ISOCEXT */ + long __cdecl wcstol(const wchar_t *_Str,wchar_t **_EndPtr,int _Radix); + _CRTIMP long __cdecl _wcstol_l(const wchar_t *_Str,wchar_t **_EndPtr,int _Radix,_locale_t _Locale); + unsigned long __cdecl wcstoul(const wchar_t *_Str,wchar_t **_EndPtr,int _Radix); + _CRTIMP unsigned long __cdecl _wcstoul_l(const wchar_t *_Str,wchar_t **_EndPtr,int _Radix,_locale_t _Locale); + _CRTIMP wchar_t *__cdecl _wgetenv(const wchar_t *_VarName); +#ifndef _CRT_WSYSTEM_DEFINED +#define _CRT_WSYSTEM_DEFINED + _CRTIMP int __cdecl _wsystem(const wchar_t *_Command); +#endif + _CRTIMP double __cdecl _wtof(const wchar_t *_Str); + _CRTIMP double __cdecl _wtof_l(const wchar_t *_Str,_locale_t _Locale); + _CRTIMP int __cdecl _wtoi(const wchar_t *_Str); + _CRTIMP int __cdecl _wtoi_l(const wchar_t *_Str,_locale_t _Locale); + _CRTIMP long __cdecl _wtol(const wchar_t *_Str); + _CRTIMP long __cdecl _wtol_l(const wchar_t *_Str,_locale_t _Locale); + +#if _INTEGRAL_MAX_BITS >= 64 + _CRTIMP wchar_t *__cdecl _i64tow(__int64 _Val,wchar_t *_DstBuf,int _Radix); + _CRTIMP wchar_t *__cdecl _ui64tow(unsigned __int64 _Val,wchar_t *_DstBuf,int _Radix); + _CRTIMP __int64 __cdecl _wtoi64(const wchar_t *_Str); + _CRTIMP __int64 __cdecl _wtoi64_l(const wchar_t *_Str,_locale_t _Locale); + _CRTIMP __int64 __cdecl _wcstoi64(const wchar_t *_Str,wchar_t **_EndPtr,int _Radix); + _CRTIMP __int64 __cdecl _wcstoi64_l(const wchar_t *_Str,wchar_t **_EndPtr,int _Radix,_locale_t _Locale); + _CRTIMP unsigned __int64 __cdecl _wcstoui64(const wchar_t *_Str,wchar_t **_EndPtr,int _Radix); + _CRTIMP unsigned __int64 __cdecl _wcstoui64_l(const wchar_t *_Str,wchar_t **_EndPtr,int _Radix,_locale_t _Locale); +#endif +#endif + +#ifndef _POSIX_ +#ifndef _WSTDLIBP_DEFINED +#define _WSTDLIBP_DEFINED + _CRTIMP wchar_t *__cdecl _wfullpath(wchar_t *_FullPath,const wchar_t *_Path,size_t _SizeInWords); + _CRTIMP void __cdecl _wmakepath(wchar_t *_ResultPath,const wchar_t *_Drive,const wchar_t *_Dir,const wchar_t *_Filename,const wchar_t *_Ext); +#ifndef _CRT_WPERROR_DEFINED +#define _CRT_WPERROR_DEFINED + _CRTIMP void __cdecl _wperror(const wchar_t *_ErrMsg); +#endif + _CRTIMP int __cdecl _wputenv(const wchar_t *_EnvString); + _CRTIMP void __cdecl _wsearchenv(const wchar_t *_Filename,const wchar_t *_EnvVar,wchar_t *_ResultPath); + _CRTIMP void __cdecl _wsplitpath(const wchar_t *_FullPath,wchar_t *_Drive,wchar_t *_Dir,wchar_t *_Filename,wchar_t *_Ext); +#endif +#endif + +#ifndef _WSTRING_DEFINED +#define _WSTRING_DEFINED + _CRTIMP wchar_t *__cdecl _wcsdup(const wchar_t *_Str); + wchar_t *__cdecl wcscat(wchar_t *_Dest,const wchar_t *_Source); + _CONST_RETURN wchar_t *__cdecl wcschr(const wchar_t *_Str,wchar_t _Ch); + int __cdecl wcscmp(const wchar_t *_Str1,const wchar_t *_Str2); + wchar_t *__cdecl wcscpy(wchar_t *_Dest,const wchar_t *_Source); + size_t __cdecl wcscspn(const wchar_t *_Str,const wchar_t *_Control); + size_t __cdecl wcslen(const wchar_t *_Str); + size_t __cdecl wcsnlen(const wchar_t *_Src,size_t _MaxCount); + wchar_t *__cdecl wcsncat(wchar_t *_Dest,const wchar_t *_Source,size_t _Count); + int __cdecl wcsncmp(const wchar_t *_Str1,const wchar_t *_Str2,size_t _MaxCount); + wchar_t *__cdecl wcsncpy(wchar_t *_Dest,const wchar_t *_Source,size_t _Count); + _CONST_RETURN wchar_t *__cdecl wcspbrk(const wchar_t *_Str,const wchar_t *_Control); + _CONST_RETURN wchar_t *__cdecl wcsrchr(const wchar_t *_Str,wchar_t _Ch); + size_t __cdecl wcsspn(const wchar_t *_Str,const wchar_t *_Control); + _CONST_RETURN wchar_t *__cdecl wcsstr(const wchar_t *_Str,const wchar_t *_SubStr); + wchar_t *__cdecl wcstok(wchar_t *_Str,const wchar_t *_Delim); + _CRTIMP wchar_t *__cdecl _wcserror(int _ErrNum); + _CRTIMP wchar_t *__cdecl __wcserror(const wchar_t *_Str); + _CRTIMP int __cdecl _wcsicmp(const wchar_t *_Str1,const wchar_t *_Str2); + _CRTIMP int __cdecl _wcsicmp_l(const wchar_t *_Str1,const wchar_t *_Str2,_locale_t _Locale); + _CRTIMP int __cdecl _wcsnicmp(const wchar_t *_Str1,const wchar_t *_Str2,size_t _MaxCount); + _CRTIMP int __cdecl _wcsnicmp_l(const wchar_t *_Str1,const wchar_t *_Str2,size_t _MaxCount,_locale_t _Locale); + _CRTIMP wchar_t *__cdecl _wcsnset(wchar_t *_Str,wchar_t _Val,size_t _MaxCount); + _CRTIMP wchar_t *__cdecl _wcsrev(wchar_t *_Str); + _CRTIMP wchar_t *__cdecl _wcsset(wchar_t *_Str,wchar_t _Val); + _CRTIMP wchar_t *__cdecl _wcslwr(wchar_t *_String); + _CRTIMP wchar_t *_wcslwr_l(wchar_t *_String,_locale_t _Locale); + _CRTIMP wchar_t *__cdecl _wcsupr(wchar_t *_String); + _CRTIMP wchar_t *_wcsupr_l(wchar_t *_String,_locale_t _Locale); + size_t __cdecl wcsxfrm(wchar_t *_Dst,const wchar_t *_Src,size_t _MaxCount); + _CRTIMP size_t __cdecl _wcsxfrm_l(wchar_t *_Dst,const wchar_t *_Src,size_t _MaxCount,_locale_t _Locale); + int __cdecl wcscoll(const wchar_t *_Str1,const wchar_t *_Str2); + _CRTIMP int __cdecl _wcscoll_l(const wchar_t *_Str1,const wchar_t *_Str2,_locale_t _Locale); + _CRTIMP int __cdecl _wcsicoll(const wchar_t *_Str1,const wchar_t *_Str2); + _CRTIMP int __cdecl _wcsicoll_l(const wchar_t *_Str1,const wchar_t *_Str2,_locale_t _Locale); + _CRTIMP int __cdecl _wcsncoll(const wchar_t *_Str1,const wchar_t *_Str2,size_t _MaxCount); + _CRTIMP int __cdecl _wcsncoll_l(const wchar_t *_Str1,const wchar_t *_Str2,size_t _MaxCount,_locale_t _Locale); + _CRTIMP int __cdecl _wcsnicoll(const wchar_t *_Str1,const wchar_t *_Str2,size_t _MaxCount); + _CRTIMP int __cdecl _wcsnicoll_l(const wchar_t *_Str1,const wchar_t *_Str2,size_t _MaxCount,_locale_t _Locale); + +#ifndef NO_OLDNAMES + wchar_t *__cdecl wcsdup(const wchar_t *_Str); +#define wcswcs wcsstr + int __cdecl wcsicmp(const wchar_t *_Str1,const wchar_t *_Str2); + int __cdecl wcsnicmp(const wchar_t *_Str1,const wchar_t *_Str2,size_t _MaxCount); + wchar_t *__cdecl wcsnset(wchar_t *_Str,wchar_t _Val,size_t _MaxCount); + wchar_t *__cdecl wcsrev(wchar_t *_Str); + wchar_t *__cdecl wcsset(wchar_t *_Str,wchar_t _Val); + wchar_t *__cdecl wcslwr(wchar_t *_Str); + wchar_t *__cdecl wcsupr(wchar_t *_Str); + int __cdecl wcsicoll(const wchar_t *_Str1,const wchar_t *_Str2); +#endif +#endif + +#ifndef _TM_DEFINED +#define _TM_DEFINED + struct tm { + int tm_sec; + int tm_min; + int tm_hour; + int tm_mday; + int tm_mon; + int tm_year; + int tm_wday; + int tm_yday; + int tm_isdst; + }; +#endif + +#ifndef _WTIME_DEFINED +#define _WTIME_DEFINED + + _CRTIMP wchar_t *__cdecl _wasctime(const struct tm *_Tm); + _CRTIMP wchar_t *__cdecl _wctime32(const __time32_t *_Time); + size_t __cdecl wcsftime(wchar_t *_Buf,size_t _SizeInWords,const wchar_t *_Format,const struct tm *_Tm); + _CRTIMP size_t __cdecl _wcsftime_l(wchar_t *_Buf,size_t _SizeInWords,const wchar_t *_Format,const struct tm *_Tm,_locale_t _Locale); + _CRTIMP wchar_t *__cdecl _wstrdate(wchar_t *_Buffer); + _CRTIMP wchar_t *__cdecl _wstrtime(wchar_t *_Buffer); +#if _INTEGRAL_MAX_BITS >= 64 + _CRTIMP wchar_t *__cdecl _wctime64(const __time64_t *_Time); +#endif + +#if !defined (RC_INVOKED) && !defined (_INC_WTIME_INL) +#define _INC_WTIME_INL +#ifdef _USE_32BIT_TIME_T +__CRT_INLINE wchar_t *__cdecl _wctime(const time_t *_Time) { return _wctime32(_Time); } +#else +__CRT_INLINE wchar_t *__cdecl _wctime(const time_t *_Time) { return _wctime64(_Time); } +#endif +#endif +#endif + + typedef int mbstate_t; + typedef wchar_t _Wint_t; + + wint_t __cdecl btowc(int); + size_t __cdecl mbrlen(const char *_Ch,size_t _SizeInBytes,mbstate_t *_State); + size_t __cdecl mbrtowc(wchar_t *_DstCh,const char *_SrcCh,size_t _SizeInBytes,mbstate_t *_State); + size_t __cdecl mbsrtowcs(wchar_t *_Dest,const char **_PSrc,size_t _Count,mbstate_t *_State); + size_t __cdecl wcrtomb(char *_Dest,wchar_t _Source,mbstate_t *_State); + size_t __cdecl wcsrtombs(char *_Dest,const wchar_t **_PSource,size_t _Count,mbstate_t *_State); + int __cdecl wctob(wint_t _WCh); + +#ifndef __NO_ISOCEXT /* these need static lib libmingwex.a */ + wchar_t *__cdecl wmemset(wchar_t *s, wchar_t c, size_t n); + _CONST_RETURN wchar_t *__cdecl wmemchr(const wchar_t *s, wchar_t c, size_t n); + int wmemcmp(const wchar_t *s1, const wchar_t *s2,size_t n); + wchar_t *__cdecl wmemcpy(wchar_t *s1,const wchar_t *s2,size_t n); + wchar_t *__cdecl wmemmove(wchar_t *s1, const wchar_t *s2, size_t n); + long long __cdecl wcstoll(const wchar_t *nptr,wchar_t **endptr, int base); + unsigned long long __cdecl wcstoull(const wchar_t *nptr,wchar_t **endptr, int base); +#endif /* __NO_ISOCEXT */ + + void *__cdecl memmove(void *_Dst,const void *_Src,size_t _MaxCount); + void *__cdecl memcpy(void *_Dst,const void *_Src,size_t _MaxCount); + __CRT_INLINE int __cdecl fwide(FILE *_F,int _M) { (void)_F; return (_M); } + __CRT_INLINE int __cdecl mbsinit(const mbstate_t *_P) { return (!_P || *_P==0); } + __CRT_INLINE _CONST_RETURN wchar_t *__cdecl wmemchr(const wchar_t *_S,wchar_t _C,size_t _N) { for (;0<_N;++_S,--_N) if (*_S==_C) return (_CONST_RETURN wchar_t *)(_S); return (0); } + __CRT_INLINE int __cdecl wmemcmp(const wchar_t *_S1,const wchar_t *_S2,size_t _N) { for (; 0 < _N; ++_S1,++_S2,--_N) if (*_S1!=*_S2) return (*_S1 < *_S2 ? -1 : +1); return (0); } + __CRT_INLINE wchar_t *__cdecl wmemcpy(wchar_t *_S1,const wchar_t *_S2,size_t _N) { return (wchar_t *)memcpy(_S1,_S2,_N*sizeof(wchar_t)); } + __CRT_INLINE wchar_t *__cdecl wmemmove(wchar_t *_S1,const wchar_t *_S2,size_t _N) { return (wchar_t *)memmove(_S1,_S2,_N*sizeof(wchar_t)); } + __CRT_INLINE wchar_t *__cdecl wmemset(wchar_t *_S,wchar_t _C,size_t _N) { + wchar_t *_Su = _S; + for (;0<_N;++_Su,--_N) { + *_Su = _C; + } + return (_S); + } +#ifdef __cplusplus +} +#endif + +#pragma pack(pop) + +#include +#endif diff --git a/tinyc/win32/include/wctype.h b/tinyc/win32/include/wctype.h new file mode 100644 index 000000000..a44cb384a --- /dev/null +++ b/tinyc/win32/include/wctype.h @@ -0,0 +1,172 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _INC_WCTYPE +#define _INC_WCTYPE + +#ifndef _WIN32 +#error Only Win32 target is supported! +#endif + +#include <_mingw.h> + +#pragma pack(push,_CRT_PACKING) + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _CRTIMP +#define _CRTIMP __declspec(dllimport) +#endif + +#ifndef _WCHAR_T_DEFINED + typedef unsigned short wchar_t; +#define _WCHAR_T_DEFINED +#endif + +#ifndef _WCTYPE_T_DEFINED + typedef unsigned short wint_t; + typedef unsigned short wctype_t; +#define _WCTYPE_T_DEFINED +#endif + +#ifndef WEOF +#define WEOF (wint_t)(0xFFFF) +#endif + +#ifndef _CRT_CTYPEDATA_DEFINED +#define _CRT_CTYPEDATA_DEFINED +#ifndef _CTYPE_DISABLE_MACROS + +#ifndef __PCTYPE_FUNC +#define __PCTYPE_FUNC __pctype_func() +#ifdef _MSVCRT_ +#define __pctype_func() (_pctype) +#else +#define __pctype_func() (*_imp___pctype) +#endif +#endif + +#ifndef _pctype +#ifdef _MSVCRT_ + extern unsigned short *_pctype; +#else + extern unsigned short **_imp___pctype; +#define _pctype (*_imp___pctype) +#endif +#endif + +#endif +#endif + +#ifndef _CRT_WCTYPEDATA_DEFINED +#define _CRT_WCTYPEDATA_DEFINED +#ifndef _CTYPE_DISABLE_MACROS +#ifndef _wctype +#ifdef _MSVCRT_ + extern unsigned short *_wctype; +#else + extern unsigned short **_imp___wctype; +#define _wctype (*_imp___wctype) +#endif +#endif + +#ifndef _pwctype +#ifdef _MSVCRT_ + extern unsigned short *_pwctype; +#else + extern unsigned short **_imp___pwctype; +#define _pwctype (*_imp___pwctype) +#define __pwctype_func() (*_imp___pwctype) +#endif +#endif +#endif +#endif + +#define _UPPER 0x1 +#define _LOWER 0x2 +#define _DIGIT 0x4 +#define _SPACE 0x8 + +#define _PUNCT 0x10 +#define _CONTROL 0x20 +#define _BLANK 0x40 +#define _HEX 0x80 + +#define _LEADBYTE 0x8000 +#define _ALPHA (0x0100|_UPPER|_LOWER) + +#ifndef _WCTYPE_DEFINED +#define _WCTYPE_DEFINED + + int __cdecl iswalpha(wint_t); + int __cdecl iswupper(wint_t); + int __cdecl iswlower(wint_t); + int __cdecl iswdigit(wint_t); + int __cdecl iswxdigit(wint_t); + int __cdecl iswspace(wint_t); + int __cdecl iswpunct(wint_t); + int __cdecl iswalnum(wint_t); + int __cdecl iswprint(wint_t); + int __cdecl iswgraph(wint_t); + int __cdecl iswcntrl(wint_t); + int __cdecl iswascii(wint_t); + int __cdecl isleadbyte(int); + wint_t __cdecl towupper(wint_t); + wint_t __cdecl towlower(wint_t); + int __cdecl iswctype(wint_t,wctype_t); + _CRTIMP int __cdecl __iswcsymf(wint_t); + _CRTIMP int __cdecl __iswcsym(wint_t); + int __cdecl is_wctype(wint_t,wctype_t); +#if (defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || !defined (NO_OLDNAMES) +int __cdecl isblank(int _C); +#endif +#endif + +#ifndef _WCTYPE_INLINE_DEFINED +#define _WCTYPE_INLINE_DEFINED +#ifndef __cplusplus +#define iswalpha(_c) (iswctype(_c,_ALPHA)) +#define iswupper(_c) (iswctype(_c,_UPPER)) +#define iswlower(_c) (iswctype(_c,_LOWER)) +#define iswdigit(_c) (iswctype(_c,_DIGIT)) +#define iswxdigit(_c) (iswctype(_c,_HEX)) +#define iswspace(_c) (iswctype(_c,_SPACE)) +#define iswpunct(_c) (iswctype(_c,_PUNCT)) +#define iswalnum(_c) (iswctype(_c,_ALPHA|_DIGIT)) +#define iswprint(_c) (iswctype(_c,_BLANK|_PUNCT|_ALPHA|_DIGIT)) +#define iswgraph(_c) (iswctype(_c,_PUNCT|_ALPHA|_DIGIT)) +#define iswcntrl(_c) (iswctype(_c,_CONTROL)) +#define iswascii(_c) ((unsigned)(_c) < 0x80) +#define isleadbyte(c) (__pctype_func()[(unsigned char)(c)] & _LEADBYTE) +#else + __CRT_INLINE int __cdecl iswalpha(wint_t _C) {return (iswctype(_C,_ALPHA)); } + __CRT_INLINE int __cdecl iswupper(wint_t _C) {return (iswctype(_C,_UPPER)); } + __CRT_INLINE int __cdecl iswlower(wint_t _C) {return (iswctype(_C,_LOWER)); } + __CRT_INLINE int __cdecl iswdigit(wint_t _C) {return (iswctype(_C,_DIGIT)); } + __CRT_INLINE int __cdecl iswxdigit(wint_t _C) {return (iswctype(_C,_HEX)); } + __CRT_INLINE int __cdecl iswspace(wint_t _C) {return (iswctype(_C,_SPACE)); } + __CRT_INLINE int __cdecl iswpunct(wint_t _C) {return (iswctype(_C,_PUNCT)); } + __CRT_INLINE int __cdecl iswalnum(wint_t _C) {return (iswctype(_C,_ALPHA|_DIGIT)); } + __CRT_INLINE int __cdecl iswprint(wint_t _C) {return (iswctype(_C,_BLANK|_PUNCT|_ALPHA|_DIGIT)); } + __CRT_INLINE int __cdecl iswgraph(wint_t _C) {return (iswctype(_C,_PUNCT|_ALPHA|_DIGIT)); } + __CRT_INLINE int __cdecl iswcntrl(wint_t _C) {return (iswctype(_C,_CONTROL)); } + __CRT_INLINE int __cdecl iswascii(wint_t _C) {return ((unsigned)(_C) < 0x80); } + __CRT_INLINE int __cdecl isleadbyte(int _C) {return (__pctype_func()[(unsigned char)(_C)] & _LEADBYTE); } +#endif +#endif + + typedef wchar_t wctrans_t; + wint_t __cdecl towctrans(wint_t,wctrans_t); + wctrans_t __cdecl wctrans(const char *); + wctype_t __cdecl wctype(const char *); + +#ifdef __cplusplus +} +#endif + +#pragma pack(pop) +#endif diff --git a/tinyc/win32/include/winapi/basetsd.h b/tinyc/win32/include/winapi/basetsd.h new file mode 100644 index 000000000..47d78c4c3 --- /dev/null +++ b/tinyc/win32/include/winapi/basetsd.h @@ -0,0 +1,149 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _BASETSD_H_ +#define _BASETSD_H_ + +#if (defined(__x86_64) || defined(__ia64__)) && !defined(RC_INVOKED) +typedef unsigned __int64 POINTER_64_INT; +#else +typedef unsigned long POINTER_64_INT; +#endif + +#define POINTER_32 +#define POINTER_64 +#define FIRMWARE_PTR + +#ifdef __cplusplus +extern "C" { +#endif + + typedef signed char INT8,*PINT8; + typedef signed short INT16,*PINT16; + typedef signed int INT32,*PINT32; + typedef signed __int64 INT64,*PINT64; + typedef unsigned char UINT8,*PUINT8; + typedef unsigned short UINT16,*PUINT16; + typedef unsigned int UINT32,*PUINT32; + typedef unsigned __int64 UINT64,*PUINT64; + typedef signed int LONG32,*PLONG32; + typedef unsigned int ULONG32,*PULONG32; + typedef unsigned int DWORD32,*PDWORD32; + +#ifndef _W64 +#define _W64 +#endif + +#ifdef _WIN64 + typedef __int64 INT_PTR,*PINT_PTR; + typedef unsigned __int64 UINT_PTR,*PUINT_PTR; + typedef __int64 LONG_PTR,*PLONG_PTR; + typedef unsigned __int64 ULONG_PTR,*PULONG_PTR; +#define __int3264 __int64 +#else + typedef int INT_PTR,*PINT_PTR; + typedef unsigned int UINT_PTR,*PUINT_PTR; + typedef long LONG_PTR,*PLONG_PTR; + typedef unsigned long ULONG_PTR,*PULONG_PTR; +#define __int3264 __int32 +#endif + +#ifdef _WIN64 +#define ADDRESS_TAG_BIT 0x40000000000ULL + typedef __int64 SHANDLE_PTR; + typedef unsigned __int64 HANDLE_PTR; + typedef unsigned int UHALF_PTR,*PUHALF_PTR; + typedef int HALF_PTR,*PHALF_PTR; + + static __inline unsigned long HandleToULong(const void *h) { return((unsigned long) (ULONG_PTR) h); } + static __inline long HandleToLong(const void *h) { return((long) (LONG_PTR) h); } + static __inline void *ULongToHandle(const unsigned long h) { return((void *) (UINT_PTR) h); } + static __inline void *LongToHandle(const long h) { return((void *) (INT_PTR) h); } + static __inline unsigned long PtrToUlong(const void *p) { return((unsigned long) (ULONG_PTR) p); } + static __inline unsigned int PtrToUint(const void *p) { return((unsigned int) (UINT_PTR) p); } + static __inline unsigned short PtrToUshort(const void *p) { return((unsigned short) (unsigned long) (ULONG_PTR) p); } + static __inline long PtrToLong(const void *p) { return((long) (LONG_PTR) p); } + static __inline int PtrToInt(const void *p) { return((int) (INT_PTR) p); } + static __inline short PtrToShort(const void *p) { return((short) (long) (LONG_PTR) p); } + static __inline void *IntToPtr(const int i) { return((void *)(INT_PTR)i); } + static __inline void *UIntToPtr(const unsigned int ui) { return((void *)(UINT_PTR)ui); } + static __inline void *LongToPtr(const long l) { return((void *)(LONG_PTR)l); } + static __inline void *ULongToPtr(const unsigned long ul) { return((void *)(ULONG_PTR)ul); } + +#define PtrToPtr64(p) ((void *) p) +#define Ptr64ToPtr(p) ((void *) p) +#define HandleToHandle64(h) (PtrToPtr64(h)) +#define Handle64ToHandle(h) (Ptr64ToPtr(h)) + + static __inline void *Ptr32ToPtr(const void *p) { return (void *)p; } + static __inline void *Handle32ToHandle(const void *h) { return((void *) h); } + static __inline void *PtrToPtr32(const void *p) { return((void *) (ULONG_PTR) p); } + +#define HandleToHandle32(h) (PtrToPtr32(h)) +#else + +#define ADDRESS_TAG_BIT 0x80000000UL + + typedef unsigned short UHALF_PTR,*PUHALF_PTR; + typedef short HALF_PTR,*PHALF_PTR; + typedef long SHANDLE_PTR; + typedef unsigned long HANDLE_PTR; + +#define HandleToULong(h) ((ULONG)(ULONG_PTR)(h)) +#define HandleToLong(h) ((LONG)(LONG_PTR) (h)) +#define ULongToHandle(ul) ((HANDLE)(ULONG_PTR) (ul)) +#define LongToHandle(h) ((HANDLE)(LONG_PTR) (h)) +#define PtrToUlong(p) ((ULONG)(ULONG_PTR) (p)) +#define PtrToLong(p) ((LONG)(LONG_PTR) (p)) +#define PtrToUint(p) ((UINT)(UINT_PTR) (p)) +#define PtrToInt(p) ((INT)(INT_PTR) (p)) +#define PtrToUshort(p) ((unsigned short)(ULONG_PTR)(p)) +#define PtrToShort(p) ((short)(LONG_PTR)(p)) +#define IntToPtr(i) ((VOID *)(INT_PTR)((int)i)) +#define UIntToPtr(ui) ((VOID *)(UINT_PTR)((unsigned int)ui)) +#define LongToPtr(l) ((VOID *)(LONG_PTR)((long)l)) +#define ULongToPtr(ul) ((VOID *)(ULONG_PTR)((unsigned long)ul)) + + static __inline void *PtrToPtr64(const void *p) { return((void *) (ULONG_PTR)p); } + static __inline void *Ptr64ToPtr(const void *p) { return((void *) (ULONG_PTR) p); } + static __inline void *HandleToHandle64(const void *h) { return((void *) h); } + static __inline void *Handle64ToHandle(const void *h) { return((void *) (ULONG_PTR) h); } + +#define Ptr32ToPtr(p) ((void *) p) +#define Handle32ToHandle(h) (Ptr32ToPtr(h)) +#define PtrToPtr32(p) ((void *) p) +#define HandleToHandle32(h) (PtrToPtr32(h)) +#endif + +#define HandleToUlong(h) HandleToULong(h) +#define UlongToHandle(ul) ULongToHandle(ul) +#define UlongToPtr(ul) ULongToPtr(ul) +#define UintToPtr(ui) UIntToPtr(ui) + +#define MAXUINT_PTR (~((UINT_PTR)0)) +#define MAXINT_PTR ((INT_PTR)(MAXUINT_PTR >> 1)) +#define MININT_PTR (~MAXINT_PTR) + +#define MAXULONG_PTR (~((ULONG_PTR)0)) +#define MAXLONG_PTR ((LONG_PTR)(MAXULONG_PTR >> 1)) +#define MINLONG_PTR (~MAXLONG_PTR) + +#define MAXUHALF_PTR ((UHALF_PTR)~0) +#define MAXHALF_PTR ((HALF_PTR)(MAXUHALF_PTR >> 1)) +#define MINHALF_PTR (~MAXHALF_PTR) + + typedef ULONG_PTR SIZE_T,*PSIZE_T; + typedef LONG_PTR SSIZE_T,*PSSIZE_T; + typedef ULONG_PTR DWORD_PTR,*PDWORD_PTR; + typedef __int64 LONG64,*PLONG64; + typedef unsigned __int64 ULONG64,*PULONG64; + typedef unsigned __int64 DWORD64,*PDWORD64; + typedef ULONG_PTR KAFFINITY; + typedef KAFFINITY *PKAFFINITY; + +#ifdef __cplusplus +} +#endif +#endif diff --git a/tinyc/win32/include/winapi/basetyps.h b/tinyc/win32/include/winapi/basetyps.h new file mode 100644 index 000000000..376665e79 --- /dev/null +++ b/tinyc/win32/include/winapi/basetyps.h @@ -0,0 +1,85 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#if !defined(_BASETYPS_H_) +#define _BASETYPS_H_ + +#ifdef __cplusplus +#define EXTERN_C extern "C" +#else +#define EXTERN_C extern +#endif + +#define STDMETHODCALLTYPE WINAPI +#define STDMETHODVCALLTYPE __cdecl + +#define STDAPICALLTYPE WINAPI +#define STDAPIVCALLTYPE __cdecl + +#define STDAPI EXTERN_C HRESULT WINAPI +#define STDAPI_(type) EXTERN_C type WINAPI + +#define STDMETHODIMP HRESULT WINAPI +#define STDMETHODIMP_(type) type WINAPI + +#define STDAPIV EXTERN_C HRESULT STDAPIVCALLTYPE +#define STDAPIV_(type) EXTERN_C type STDAPIVCALLTYPE + +#define STDMETHODIMPV HRESULT STDMETHODVCALLTYPE +#define STDMETHODIMPV_(type) type STDMETHODVCALLTYPE + +#if defined(__cplusplus) && !defined(CINTERFACE) + +#define __STRUCT__ struct +#define STDMETHOD(method) virtual HRESULT WINAPI method +#define STDMETHOD_(type,method) virtual type WINAPI method +#define STDMETHODV(method) virtual HRESULT STDMETHODVCALLTYPE method +#define STDMETHODV_(type,method) virtual type STDMETHODVCALLTYPE method +#define PURE = 0 +#define THIS_ +#define THIS void +#define DECLARE_INTERFACE(iface) __STRUCT__ iface +#define DECLARE_INTERFACE_(iface,baseiface) __STRUCT__ iface : public baseiface +#else + +#ifndef __OBJC__ +#define interface struct +#endif + +#define STDMETHOD(method) HRESULT (WINAPI *method) +#define STDMETHOD_(type,method) type (WINAPI *method) +#define STDMETHODV(method) HRESULT (STDMETHODVCALLTYPE *method) +#define STDMETHODV_(type,method) type (STDMETHODVCALLTYPE *method) + +#define PURE +#define THIS_ INTERFACE *This, +#define THIS INTERFACE *This +#ifdef CONST_VTABLE +#define DECLARE_INTERFACE(iface) typedef struct iface { \ + const struct iface##Vtbl *lpVtbl; } iface; \ + typedef const struct iface##Vtbl iface##Vtbl; \ + const struct iface##Vtbl +#else +#define DECLARE_INTERFACE(iface) typedef struct iface { \ + struct iface##Vtbl *lpVtbl; \ + } iface; \ + typedef struct iface##Vtbl iface##Vtbl; \ + struct iface##Vtbl +#endif +#define DECLARE_INTERFACE_(iface,baseiface) DECLARE_INTERFACE(iface) +#endif + +#include + +#ifndef _ERROR_STATUS_T_DEFINED +#define _ERROR_STATUS_T_DEFINED +typedef unsigned long error_status_t; +#endif + +#ifndef _WCHAR_T_DEFINED +typedef unsigned short wchar_t; +#define _WCHAR_T_DEFINED +#endif +#endif diff --git a/tinyc/win32/include/winapi/guiddef.h b/tinyc/win32/include/winapi/guiddef.h new file mode 100644 index 000000000..4e7909a97 --- /dev/null +++ b/tinyc/win32/include/winapi/guiddef.h @@ -0,0 +1,156 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef GUID_DEFINED +#define GUID_DEFINED +typedef struct _GUID { + unsigned long Data1; + unsigned short Data2; + unsigned short Data3; + unsigned char Data4[8 ]; +} GUID; +#endif + +#ifndef UUID_DEFINED +#define UUID_DEFINED +typedef GUID UUID; +#endif + +#ifndef FAR +#define FAR +#endif + +#ifndef DECLSPEC_SELECTANY +#define DECLSPEC_SELECTANY __declspec(selectany) +#endif + +#ifndef EXTERN_C +#ifdef __cplusplus +#define EXTERN_C extern "C" +#else +#define EXTERN_C extern +#endif +#endif + +#ifdef DEFINE_GUID +#undef DEFINE_GUID +#endif + +#ifdef INITGUID +#ifdef __cplusplus +#define DEFINE_GUID(name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) EXTERN_C const GUID DECLSPEC_SELECTANY name = { l,w1,w2,{ b1,b2,b3,b4,b5,b6,b7,b8 } } +#else +#define DEFINE_GUID(name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) const GUID DECLSPEC_SELECTANY name = { l,w1,w2,{ b1,b2,b3,b4,b5,b6,b7,b8 } } +#endif +#else +#define DEFINE_GUID(name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) EXTERN_C const GUID name +#endif + +#define DEFINE_OLEGUID(name,l,w1,w2) DEFINE_GUID(name,l,w1,w2,0xC0,0,0,0,0,0,0,0x46) + +#ifndef _GUIDDEF_H_ +#define _GUIDDEF_H_ + +#ifndef __LPGUID_DEFINED__ +#define __LPGUID_DEFINED__ +typedef GUID *LPGUID; +#endif + +#ifndef __LPCGUID_DEFINED__ +#define __LPCGUID_DEFINED__ +typedef const GUID *LPCGUID; +#endif + +#ifndef __IID_DEFINED__ +#define __IID_DEFINED__ + +typedef GUID IID; +typedef IID *LPIID; +#define IID_NULL GUID_NULL +#define IsEqualIID(riid1,riid2) IsEqualGUID(riid1,riid2) +typedef GUID CLSID; +typedef CLSID *LPCLSID; +#define CLSID_NULL GUID_NULL +#define IsEqualCLSID(rclsid1,rclsid2) IsEqualGUID(rclsid1,rclsid2) +typedef GUID FMTID; +typedef FMTID *LPFMTID; +#define FMTID_NULL GUID_NULL +#define IsEqualFMTID(rfmtid1,rfmtid2) IsEqualGUID(rfmtid1,rfmtid2) + +#ifdef __midl_proxy +#define __MIDL_CONST +#else +#define __MIDL_CONST const +#endif + +#ifndef _REFGUID_DEFINED +#define _REFGUID_DEFINED +#ifdef __cplusplus +#define REFGUID const GUID & +#else +#define REFGUID const GUID *__MIDL_CONST +#endif +#endif + +#ifndef _REFIID_DEFINED +#define _REFIID_DEFINED +#ifdef __cplusplus +#define REFIID const IID & +#else +#define REFIID const IID *__MIDL_CONST +#endif +#endif + +#ifndef _REFCLSID_DEFINED +#define _REFCLSID_DEFINED +#ifdef __cplusplus +#define REFCLSID const IID & +#else +#define REFCLSID const IID *__MIDL_CONST +#endif +#endif + +#ifndef _REFFMTID_DEFINED +#define _REFFMTID_DEFINED +#ifdef __cplusplus +#define REFFMTID const IID & +#else +#define REFFMTID const IID *__MIDL_CONST +#endif +#endif +#endif + +#ifndef _SYS_GUID_OPERATORS_ +#define _SYS_GUID_OPERATORS_ +#include + +#ifdef __cplusplus +__inline int InlineIsEqualGUID(REFGUID rguid1,REFGUID rguid2) { + return (((unsigned long *) &rguid1)[0]==((unsigned long *) &rguid2)[0] && ((unsigned long *) &rguid1)[1]==((unsigned long *) &rguid2)[1] && + ((unsigned long *) &rguid1)[2]==((unsigned long *) &rguid2)[2] && ((unsigned long *) &rguid1)[3]==((unsigned long *) &rguid2)[3]); +} +__inline int IsEqualGUID(REFGUID rguid1,REFGUID rguid2) { return !memcmp(&rguid1,&rguid2,sizeof(GUID)); } +#else +#define InlineIsEqualGUID(rguid1,rguid2) (((unsigned long *) rguid1)[0]==((unsigned long *) rguid2)[0] && ((unsigned long *) rguid1)[1]==((unsigned long *) rguid2)[1] && ((unsigned long *) rguid1)[2]==((unsigned long *) rguid2)[2] && ((unsigned long *) rguid1)[3]==((unsigned long *) rguid2)[3]) +#define IsEqualGUID(rguid1,rguid2) (!memcmp(rguid1,rguid2,sizeof(GUID))) +#endif + +#ifdef __INLINE_ISEQUAL_GUID +#undef IsEqualGUID +#define IsEqualGUID(rguid1,rguid2) InlineIsEqualGUID(rguid1,rguid2) +#endif + +#define IsEqualIID(riid1,riid2) IsEqualGUID(riid1,riid2) +#define IsEqualCLSID(rclsid1,rclsid2) IsEqualGUID(rclsid1,rclsid2) + +#if !defined _SYS_GUID_OPERATOR_EQ_ && !defined _NO_SYS_GUID_OPERATOR_EQ_ +#define _SYS_GUID_OPERATOR_EQ_ +#ifdef __cplusplus +__inline int operator==(REFGUID guidOne,REFGUID guidOther) { return IsEqualGUID(guidOne,guidOther); } +__inline int operator!=(REFGUID guidOne,REFGUID guidOther) { return !(guidOne==guidOther); } +#endif +#endif +#endif +#endif diff --git a/tinyc/win32/include/winapi/poppack.h b/tinyc/win32/include/winapi/poppack.h new file mode 100644 index 000000000..b08cba222 --- /dev/null +++ b/tinyc/win32/include/winapi/poppack.h @@ -0,0 +1,8 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#if !(defined(lint) || defined(RC_INVOKED)) +#pragma pack(pop) +#endif diff --git a/tinyc/win32/include/winapi/pshpack1.h b/tinyc/win32/include/winapi/pshpack1.h new file mode 100644 index 000000000..d18d9e856 --- /dev/null +++ b/tinyc/win32/include/winapi/pshpack1.h @@ -0,0 +1,8 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#if !(defined(lint) || defined(RC_INVOKED)) +#pragma pack(push,1) +#endif diff --git a/tinyc/win32/include/winapi/pshpack2.h b/tinyc/win32/include/winapi/pshpack2.h new file mode 100644 index 000000000..7de16fd39 --- /dev/null +++ b/tinyc/win32/include/winapi/pshpack2.h @@ -0,0 +1,8 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#if !(defined(lint) || defined(RC_INVOKED)) +#pragma pack(push,2) +#endif diff --git a/tinyc/win32/include/winapi/pshpack4.h b/tinyc/win32/include/winapi/pshpack4.h new file mode 100644 index 000000000..1c8e61d7d --- /dev/null +++ b/tinyc/win32/include/winapi/pshpack4.h @@ -0,0 +1,8 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#if !(defined(lint) || defined(RC_INVOKED)) +#pragma pack(push,4) +#endif diff --git a/tinyc/win32/include/winapi/pshpack8.h b/tinyc/win32/include/winapi/pshpack8.h new file mode 100644 index 000000000..70a3c7f7c --- /dev/null +++ b/tinyc/win32/include/winapi/pshpack8.h @@ -0,0 +1,8 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#if !(defined(lint) || defined(RC_INVOKED)) +#pragma pack(push,8) +#endif diff --git a/tinyc/win32/include/winapi/winbase.h b/tinyc/win32/include/winapi/winbase.h new file mode 100644 index 000000000..4a38006ef --- /dev/null +++ b/tinyc/win32/include/winapi/winbase.h @@ -0,0 +1,2951 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _WINBASE_ +#define _WINBASE_ + +#define WINADVAPI DECLSPEC_IMPORT +#define WINBASEAPI DECLSPEC_IMPORT +#define ZAWPROXYAPI DECLSPEC_IMPORT + +#ifdef __cplusplus +extern "C" { +#endif + +#define DefineHandleTable(w) ((w),TRUE) +#define LimitEmsPages(dw) +#define SetSwapAreaSize(w) (w) +#define LockSegment(w) GlobalFix((HANDLE)(w)) +#define UnlockSegment(w) GlobalUnfix((HANDLE)(w)) +#define GetCurrentTime() GetTickCount() + +#define Yield() + +#define INVALID_HANDLE_VALUE ((HANDLE)(LONG_PTR)-1) +#define INVALID_FILE_SIZE ((DWORD)0xffffffff) +#define INVALID_SET_FILE_POINTER ((DWORD)-1) +#define INVALID_FILE_ATTRIBUTES ((DWORD)-1) + +#define FILE_BEGIN 0 +#define FILE_CURRENT 1 +#define FILE_END 2 + +#define TIME_ZONE_ID_INVALID ((DWORD)0xffffffff) + +#define WAIT_FAILED ((DWORD)0xffffffff) +#define WAIT_OBJECT_0 ((STATUS_WAIT_0) + 0) +#define WAIT_ABANDONED ((STATUS_ABANDONED_WAIT_0) + 0) +#define WAIT_ABANDONED_0 ((STATUS_ABANDONED_WAIT_0) + 0) +#define WAIT_IO_COMPLETION STATUS_USER_APC +#define STILL_ACTIVE STATUS_PENDING +#define EXCEPTION_ACCESS_VIOLATION STATUS_ACCESS_VIOLATION +#define EXCEPTION_DATATYPE_MISALIGNMENT STATUS_DATATYPE_MISALIGNMENT +#define EXCEPTION_BREAKPOINT STATUS_BREAKPOINT +#define EXCEPTION_SINGLE_STEP STATUS_SINGLE_STEP +#define EXCEPTION_ARRAY_BOUNDS_EXCEEDED STATUS_ARRAY_BOUNDS_EXCEEDED +#define EXCEPTION_FLT_DENORMAL_OPERAND STATUS_FLOAT_DENORMAL_OPERAND +#define EXCEPTION_FLT_DIVIDE_BY_ZERO STATUS_FLOAT_DIVIDE_BY_ZERO +#define EXCEPTION_FLT_INEXACT_RESULT STATUS_FLOAT_INEXACT_RESULT +#define EXCEPTION_FLT_INVALID_OPERATION STATUS_FLOAT_INVALID_OPERATION +#define EXCEPTION_FLT_OVERFLOW STATUS_FLOAT_OVERFLOW +#define EXCEPTION_FLT_STACK_CHECK STATUS_FLOAT_STACK_CHECK +#define EXCEPTION_FLT_UNDERFLOW STATUS_FLOAT_UNDERFLOW +#define EXCEPTION_INT_DIVIDE_BY_ZERO STATUS_INTEGER_DIVIDE_BY_ZERO +#define EXCEPTION_INT_OVERFLOW STATUS_INTEGER_OVERFLOW +#define EXCEPTION_PRIV_INSTRUCTION STATUS_PRIVILEGED_INSTRUCTION +#define EXCEPTION_IN_PAGE_ERROR STATUS_IN_PAGE_ERROR +#define EXCEPTION_ILLEGAL_INSTRUCTION STATUS_ILLEGAL_INSTRUCTION +#define EXCEPTION_NONCONTINUABLE_EXCEPTION STATUS_NONCONTINUABLE_EXCEPTION +#define EXCEPTION_STACK_OVERFLOW STATUS_STACK_OVERFLOW +#define EXCEPTION_INVALID_DISPOSITION STATUS_INVALID_DISPOSITION +#define EXCEPTION_GUARD_PAGE STATUS_GUARD_PAGE_VIOLATION +#define EXCEPTION_INVALID_HANDLE STATUS_INVALID_HANDLE +#define EXCEPTION_POSSIBLE_DEADLOCK STATUS_POSSIBLE_DEADLOCK +#define CONTROL_C_EXIT STATUS_CONTROL_C_EXIT +#define MoveMemory RtlMoveMemory +#define CopyMemory RtlCopyMemory +#define FillMemory RtlFillMemory +#define ZeroMemory RtlZeroMemory +#define SecureZeroMemory RtlSecureZeroMemory + +#define FILE_FLAG_WRITE_THROUGH 0x80000000 +#define FILE_FLAG_OVERLAPPED 0x40000000 +#define FILE_FLAG_NO_BUFFERING 0x20000000 +#define FILE_FLAG_RANDOM_ACCESS 0x10000000 +#define FILE_FLAG_SEQUENTIAL_SCAN 0x8000000 +#define FILE_FLAG_DELETE_ON_CLOSE 0x4000000 +#define FILE_FLAG_BACKUP_SEMANTICS 0x2000000 +#define FILE_FLAG_POSIX_SEMANTICS 0x1000000 +#define FILE_FLAG_OPEN_REPARSE_POINT 0x200000 +#define FILE_FLAG_OPEN_NO_RECALL 0x100000 +#define FILE_FLAG_FIRST_PIPE_INSTANCE 0x80000 + +#define CREATE_NEW 1 +#define CREATE_ALWAYS 2 +#define OPEN_EXISTING 3 +#define OPEN_ALWAYS 4 +#define TRUNCATE_EXISTING 5 + +#define PROGRESS_CONTINUE 0 +#define PROGRESS_CANCEL 1 +#define PROGRESS_STOP 2 +#define PROGRESS_QUIET 3 + +#define CALLBACK_CHUNK_FINISHED 0x0 +#define CALLBACK_STREAM_SWITCH 0x1 + +#define COPY_FILE_FAIL_IF_EXISTS 0x1 +#define COPY_FILE_RESTARTABLE 0x2 +#define COPY_FILE_OPEN_SOURCE_FOR_WRITE 0x4 +#define COPY_FILE_ALLOW_DECRYPTED_DESTINATION 0x8 + +#define REPLACEFILE_WRITE_THROUGH 0x1 +#define REPLACEFILE_IGNORE_MERGE_ERRORS 0x2 + +#define PIPE_ACCESS_INBOUND 0x1 +#define PIPE_ACCESS_OUTBOUND 0x2 +#define PIPE_ACCESS_DUPLEX 0x3 + +#define PIPE_CLIENT_END 0x0 +#define PIPE_SERVER_END 0x1 + +#define PIPE_WAIT 0x0 +#define PIPE_NOWAIT 0x1 +#define PIPE_READMODE_BYTE 0x0 +#define PIPE_READMODE_MESSAGE 0x2 +#define PIPE_TYPE_BYTE 0x0 +#define PIPE_TYPE_MESSAGE 0x4 + +#define PIPE_UNLIMITED_INSTANCES 255 + +#define SECURITY_ANONYMOUS (SecurityAnonymous << 16) +#define SECURITY_IDENTIFICATION (SecurityIdentification << 16) +#define SECURITY_IMPERSONATION (SecurityImpersonation << 16) +#define SECURITY_DELEGATION (SecurityDelegation << 16) + +#define SECURITY_CONTEXT_TRACKING 0x40000 +#define SECURITY_EFFECTIVE_ONLY 0x80000 + +#define SECURITY_SQOS_PRESENT 0x100000 +#define SECURITY_VALID_SQOS_FLAGS 0x1f0000 + + typedef struct _OVERLAPPED { + ULONG_PTR Internal; + ULONG_PTR InternalHigh; + union { + struct { + DWORD Offset; + DWORD OffsetHigh; + }; + PVOID Pointer; + }; + HANDLE hEvent; + } OVERLAPPED,*LPOVERLAPPED; + + typedef struct _SECURITY_ATTRIBUTES { + DWORD nLength; + LPVOID lpSecurityDescriptor; + WINBOOL bInheritHandle; + } SECURITY_ATTRIBUTES,*PSECURITY_ATTRIBUTES,*LPSECURITY_ATTRIBUTES; + + typedef struct _PROCESS_INFORMATION { + HANDLE hProcess; + HANDLE hThread; + DWORD dwProcessId; + DWORD dwThreadId; + } PROCESS_INFORMATION,*PPROCESS_INFORMATION,*LPPROCESS_INFORMATION; + +#ifndef _FILETIME_ +#define _FILETIME_ + typedef struct _FILETIME { + DWORD dwLowDateTime; + DWORD dwHighDateTime; + } FILETIME,*PFILETIME,*LPFILETIME; +#endif + + typedef struct _SYSTEMTIME { + WORD wYear; + WORD wMonth; + WORD wDayOfWeek; + WORD wDay; + WORD wHour; + WORD wMinute; + WORD wSecond; + WORD wMilliseconds; + } SYSTEMTIME,*PSYSTEMTIME,*LPSYSTEMTIME; + + typedef DWORD (WINAPI *PTHREAD_START_ROUTINE)(LPVOID lpThreadParameter); + typedef PTHREAD_START_ROUTINE LPTHREAD_START_ROUTINE; + typedef VOID (WINAPI *PFIBER_START_ROUTINE)(LPVOID lpFiberParameter); + typedef PFIBER_START_ROUTINE LPFIBER_START_ROUTINE; + + typedef RTL_CRITICAL_SECTION CRITICAL_SECTION; + typedef PRTL_CRITICAL_SECTION PCRITICAL_SECTION; + typedef PRTL_CRITICAL_SECTION LPCRITICAL_SECTION; + typedef RTL_CRITICAL_SECTION_DEBUG CRITICAL_SECTION_DEBUG; + typedef PRTL_CRITICAL_SECTION_DEBUG PCRITICAL_SECTION_DEBUG; + typedef PRTL_CRITICAL_SECTION_DEBUG LPCRITICAL_SECTION_DEBUG; + + WINBASEAPI PVOID WINAPI EncodePointer(PVOID Ptr); + WINBASEAPI PVOID WINAPI DecodePointer(PVOID Ptr); + WINBASEAPI PVOID WINAPI EncodeSystemPointer(PVOID Ptr); + WINBASEAPI PVOID WINAPI DecodeSystemPointer(PVOID Ptr); + +#ifdef I_X86_ + typedef PLDT_ENTRY LPLDT_ENTRY; +#else + typedef LPVOID LPLDT_ENTRY; +#endif + +#define MUTEX_MODIFY_STATE MUTANT_QUERY_STATE +#define MUTEX_ALL_ACCESS MUTANT_ALL_ACCESS + +#define SP_SERIALCOMM ((DWORD)0x1) + +#define PST_UNSPECIFIED ((DWORD)0x0) +#define PST_RS232 ((DWORD)0x1) +#define PST_PARALLELPORT ((DWORD)0x2) +#define PST_RS422 ((DWORD)0x3) +#define PST_RS423 ((DWORD)0x4) +#define PST_RS449 ((DWORD)0x5) +#define PST_MODEM ((DWORD)0x6) +#define PST_FAX ((DWORD)0x21) +#define PST_SCANNER ((DWORD)0x22) +#define PST_NETWORK_BRIDGE ((DWORD)0x100) +#define PST_LAT ((DWORD)0x101) +#define PST_TCPIP_TELNET ((DWORD)0x102) +#define PST_X25 ((DWORD)0x103) + +#define PCF_DTRDSR ((DWORD)0x1) +#define PCF_RTSCTS ((DWORD)0x2) +#define PCF_RLSD ((DWORD)0x4) +#define PCF_PARITY_CHECK ((DWORD)0x8) +#define PCF_XONXOFF ((DWORD)0x10) +#define PCF_SETXCHAR ((DWORD)0x20) +#define PCF_TOTALTIMEOUTS ((DWORD)0x40) +#define PCF_INTTIMEOUTS ((DWORD)0x80) +#define PCF_SPECIALCHARS ((DWORD)0x100) +#define PCF_16BITMODE ((DWORD)0x200) + +#define SP_PARITY ((DWORD)0x1) +#define SP_BAUD ((DWORD)0x2) +#define SP_DATABITS ((DWORD)0x4) +#define SP_STOPBITS ((DWORD)0x8) +#define SP_HANDSHAKING ((DWORD)0x10) +#define SP_PARITY_CHECK ((DWORD)0x20) +#define SP_RLSD ((DWORD)0x40) + +#define BAUD_075 ((DWORD)0x1) +#define BAUD_110 ((DWORD)0x2) +#define BAUD_134_5 ((DWORD)0x4) +#define BAUD_150 ((DWORD)0x8) +#define BAUD_300 ((DWORD)0x10) +#define BAUD_600 ((DWORD)0x20) +#define BAUD_1200 ((DWORD)0x40) +#define BAUD_1800 ((DWORD)0x80) +#define BAUD_2400 ((DWORD)0x100) +#define BAUD_4800 ((DWORD)0x200) +#define BAUD_7200 ((DWORD)0x400) +#define BAUD_9600 ((DWORD)0x800) +#define BAUD_14400 ((DWORD)0x1000) +#define BAUD_19200 ((DWORD)0x2000) +#define BAUD_38400 ((DWORD)0x4000) +#define BAUD_56K ((DWORD)0x8000) +#define BAUD_128K ((DWORD)0x10000) +#define BAUD_115200 ((DWORD)0x20000) +#define BAUD_57600 ((DWORD)0x40000) +#define BAUD_USER ((DWORD)0x10000000) + +#define DATABITS_5 ((WORD)0x1) +#define DATABITS_6 ((WORD)0x2) +#define DATABITS_7 ((WORD)0x4) +#define DATABITS_8 ((WORD)0x8) +#define DATABITS_16 ((WORD)0x10) +#define DATABITS_16X ((WORD)0x20) + +#define STOPBITS_10 ((WORD)0x1) +#define STOPBITS_15 ((WORD)0x2) +#define STOPBITS_20 ((WORD)0x4) +#define PARITY_NONE ((WORD)0x100) +#define PARITY_ODD ((WORD)0x200) +#define PARITY_EVEN ((WORD)0x400) +#define PARITY_MARK ((WORD)0x800) +#define PARITY_SPACE ((WORD)0x1000) + + typedef struct _COMMPROP { + WORD wPacketLength; + WORD wPacketVersion; + DWORD dwServiceMask; + DWORD dwReserved1; + DWORD dwMaxTxQueue; + DWORD dwMaxRxQueue; + DWORD dwMaxBaud; + DWORD dwProvSubType; + DWORD dwProvCapabilities; + DWORD dwSettableParams; + DWORD dwSettableBaud; + WORD wSettableData; + WORD wSettableStopParity; + DWORD dwCurrentTxQueue; + DWORD dwCurrentRxQueue; + DWORD dwProvSpec1; + DWORD dwProvSpec2; + WCHAR wcProvChar[1]; + } COMMPROP,*LPCOMMPROP; + +#define COMMPROP_INITIALIZED ((DWORD)0xE73CF52E) + + typedef struct _COMSTAT { + DWORD fCtsHold : 1; + DWORD fDsrHold : 1; + DWORD fRlsdHold : 1; + DWORD fXoffHold : 1; + DWORD fXoffSent : 1; + DWORD fEof : 1; + DWORD fTxim : 1; + DWORD fReserved : 25; + DWORD cbInQue; + DWORD cbOutQue; + } COMSTAT,*LPCOMSTAT; + +#define DTR_CONTROL_DISABLE 0x0 +#define DTR_CONTROL_ENABLE 0x1 +#define DTR_CONTROL_HANDSHAKE 0x2 + +#define RTS_CONTROL_DISABLE 0x0 +#define RTS_CONTROL_ENABLE 0x1 +#define RTS_CONTROL_HANDSHAKE 0x2 +#define RTS_CONTROL_TOGGLE 0x3 + + typedef struct _DCB { + DWORD DCBlength; + DWORD BaudRate; + DWORD fBinary: 1; + DWORD fParity: 1; + DWORD fOutxCtsFlow:1; + DWORD fOutxDsrFlow:1; + DWORD fDtrControl:2; + DWORD fDsrSensitivity:1; + DWORD fTXContinueOnXoff: 1; + DWORD fOutX: 1; + DWORD fInX: 1; + DWORD fErrorChar: 1; + DWORD fNull: 1; + DWORD fRtsControl:2; + DWORD fAbortOnError:1; + DWORD fDummy2:17; + WORD wReserved; + WORD XonLim; + WORD XoffLim; + BYTE ByteSize; + BYTE Parity; + BYTE StopBits; + char XonChar; + char XoffChar; + char ErrorChar; + char EofChar; + char EvtChar; + WORD wReserved1; + } DCB,*LPDCB; + + typedef struct _COMMTIMEOUTS { + DWORD ReadIntervalTimeout; + DWORD ReadTotalTimeoutMultiplier; + DWORD ReadTotalTimeoutConstant; + DWORD WriteTotalTimeoutMultiplier; + DWORD WriteTotalTimeoutConstant; + } COMMTIMEOUTS,*LPCOMMTIMEOUTS; + + typedef struct _COMMCONFIG { + DWORD dwSize; + WORD wVersion; + WORD wReserved; + DCB dcb; + DWORD dwProviderSubType; + DWORD dwProviderOffset; + DWORD dwProviderSize; + WCHAR wcProviderData[1]; + } COMMCONFIG,*LPCOMMCONFIG; + + typedef struct _SYSTEM_INFO { + union { + DWORD dwOemId; + struct { + WORD wProcessorArchitecture; + WORD wReserved; + }; + }; + DWORD dwPageSize; + LPVOID lpMinimumApplicationAddress; + LPVOID lpMaximumApplicationAddress; + DWORD_PTR dwActiveProcessorMask; + DWORD dwNumberOfProcessors; + DWORD dwProcessorType; + DWORD dwAllocationGranularity; + WORD wProcessorLevel; + WORD wProcessorRevision; + } SYSTEM_INFO,*LPSYSTEM_INFO; + +#define FreeModule(hLibModule) FreeLibrary((hLibModule)) +#define MakeProcInstance(lpProc,hInstance) (lpProc) +#define FreeProcInstance(lpProc) (lpProc) + +#define GMEM_FIXED 0x0 +#define GMEM_MOVEABLE 0x2 +#define GMEM_NOCOMPACT 0x10 +#define GMEM_NODISCARD 0x20 +#define GMEM_ZEROINIT 0x40 +#define GMEM_MODIFY 0x80 +#define GMEM_DISCARDABLE 0x100 +#define GMEM_NOT_BANKED 0x1000 +#define GMEM_SHARE 0x2000 +#define GMEM_DDESHARE 0x2000 +#define GMEM_NOTIFY 0x4000 +#define GMEM_LOWER GMEM_NOT_BANKED +#define GMEM_VALID_FLAGS 0x7F72 +#define GMEM_INVALID_HANDLE 0x8000 + +#define GHND (GMEM_MOVEABLE | GMEM_ZEROINIT) +#define GPTR (GMEM_FIXED | GMEM_ZEROINIT) + +#define GlobalLRUNewest(h) ((HANDLE)(h)) +#define GlobalLRUOldest(h) ((HANDLE)(h)) +#define GlobalDiscard(h) GlobalReAlloc((h),0,GMEM_MOVEABLE) + +#define GMEM_DISCARDED 0x4000 +#define GMEM_LOCKCOUNT 0xff + + typedef struct _MEMORYSTATUS { + DWORD dwLength; + DWORD dwMemoryLoad; + SIZE_T dwTotalPhys; + SIZE_T dwAvailPhys; + SIZE_T dwTotalPageFile; + SIZE_T dwAvailPageFile; + SIZE_T dwTotalVirtual; + SIZE_T dwAvailVirtual; + } MEMORYSTATUS,*LPMEMORYSTATUS; + +#define LMEM_FIXED 0x0 +#define LMEM_MOVEABLE 0x2 +#define LMEM_NOCOMPACT 0x10 +#define LMEM_NODISCARD 0x20 +#define LMEM_ZEROINIT 0x40 +#define LMEM_MODIFY 0x80 +#define LMEM_DISCARDABLE 0xf00 +#define LMEM_VALID_FLAGS 0xf72 +#define LMEM_INVALID_HANDLE 0x8000 + +#define LHND (LMEM_MOVEABLE | LMEM_ZEROINIT) +#define LPTR (LMEM_FIXED | LMEM_ZEROINIT) + +#define NONZEROLHND (LMEM_MOVEABLE) +#define NONZEROLPTR (LMEM_FIXED) + +#define LocalDiscard(h) LocalReAlloc((h),0,LMEM_MOVEABLE) + +#define LMEM_DISCARDED 0x4000 +#define LMEM_LOCKCOUNT 0xff + +#define DEBUG_PROCESS 0x1 +#define DEBUG_ONLY_THIS_PROCESS 0x2 +#define CREATE_SUSPENDED 0x4 +#define DETACHED_PROCESS 0x8 +#define CREATE_NEW_CONSOLE 0x10 +#define NORMAL_PRIORITY_CLASS 0x20 +#define IDLE_PRIORITY_CLASS 0x40 +#define HIGH_PRIORITY_CLASS 0x80 +#define REALTIME_PRIORITY_CLASS 0x100 +#define CREATE_NEW_PROCESS_GROUP 0x200 +#define CREATE_UNICODE_ENVIRONMENT 0x400 +#define CREATE_SEPARATE_WOW_VDM 0x800 +#define CREATE_SHARED_WOW_VDM 0x1000 +#define CREATE_FORCEDOS 0x2000 +#define BELOW_NORMAL_PRIORITY_CLASS 0x4000 +#define ABOVE_NORMAL_PRIORITY_CLASS 0x8000 +#define STACK_SIZE_PARAM_IS_A_RESERVATION 0x10000 + +#define CREATE_BREAKAWAY_FROM_JOB 0x1000000 +#define CREATE_PRESERVE_CODE_AUTHZ_LEVEL 0x2000000 + +#define CREATE_DEFAULT_ERROR_MODE 0x4000000 +#define CREATE_NO_WINDOW 0x8000000 + +#define PROFILE_USER 0x10000000 +#define PROFILE_KERNEL 0x20000000 +#define PROFILE_SERVER 0x40000000 + +#define CREATE_IGNORE_SYSTEM_DEFAULT 0x80000000 + +#define THREAD_PRIORITY_LOWEST THREAD_BASE_PRIORITY_MIN +#define THREAD_PRIORITY_BELOW_NORMAL (THREAD_PRIORITY_LOWEST+1) +#define THREAD_PRIORITY_NORMAL 0 +#define THREAD_PRIORITY_HIGHEST THREAD_BASE_PRIORITY_MAX +#define THREAD_PRIORITY_ABOVE_NORMAL (THREAD_PRIORITY_HIGHEST-1) +#define THREAD_PRIORITY_ERROR_RETURN (MAXLONG) + +#define THREAD_PRIORITY_TIME_CRITICAL THREAD_BASE_PRIORITY_LOWRT +#define THREAD_PRIORITY_IDLE THREAD_BASE_PRIORITY_IDLE + +#define EXCEPTION_DEBUG_EVENT 1 +#define CREATE_THREAD_DEBUG_EVENT 2 +#define CREATE_PROCESS_DEBUG_EVENT 3 +#define EXIT_THREAD_DEBUG_EVENT 4 +#define EXIT_PROCESS_DEBUG_EVENT 5 +#define LOAD_DLL_DEBUG_EVENT 6 +#define UNLOAD_DLL_DEBUG_EVENT 7 +#define OUTPUT_DEBUG_STRING_EVENT 8 +#define RIP_EVENT 9 + + typedef struct _EXCEPTION_DEBUG_INFO { + EXCEPTION_RECORD ExceptionRecord; + DWORD dwFirstChance; + } EXCEPTION_DEBUG_INFO,*LPEXCEPTION_DEBUG_INFO; + + typedef struct _CREATE_THREAD_DEBUG_INFO { + HANDLE hThread; + LPVOID lpThreadLocalBase; + LPTHREAD_START_ROUTINE lpStartAddress; + } CREATE_THREAD_DEBUG_INFO,*LPCREATE_THREAD_DEBUG_INFO; + + typedef struct _CREATE_PROCESS_DEBUG_INFO { + HANDLE hFile; + HANDLE hProcess; + HANDLE hThread; + LPVOID lpBaseOfImage; + DWORD dwDebugInfoFileOffset; + DWORD nDebugInfoSize; + LPVOID lpThreadLocalBase; + LPTHREAD_START_ROUTINE lpStartAddress; + LPVOID lpImageName; + WORD fUnicode; + } CREATE_PROCESS_DEBUG_INFO,*LPCREATE_PROCESS_DEBUG_INFO; + + typedef struct _EXIT_THREAD_DEBUG_INFO { + DWORD dwExitCode; + } EXIT_THREAD_DEBUG_INFO,*LPEXIT_THREAD_DEBUG_INFO; + + typedef struct _EXIT_PROCESS_DEBUG_INFO { + DWORD dwExitCode; + } EXIT_PROCESS_DEBUG_INFO,*LPEXIT_PROCESS_DEBUG_INFO; + + typedef struct _LOAD_DLL_DEBUG_INFO { + HANDLE hFile; + LPVOID lpBaseOfDll; + DWORD dwDebugInfoFileOffset; + DWORD nDebugInfoSize; + LPVOID lpImageName; + WORD fUnicode; + } LOAD_DLL_DEBUG_INFO,*LPLOAD_DLL_DEBUG_INFO; + + typedef struct _UNLOAD_DLL_DEBUG_INFO { + LPVOID lpBaseOfDll; + } UNLOAD_DLL_DEBUG_INFO,*LPUNLOAD_DLL_DEBUG_INFO; + + typedef struct _OUTPUT_DEBUG_STRING_INFO { + LPSTR lpDebugStringData; + WORD fUnicode; + WORD nDebugStringLength; + } OUTPUT_DEBUG_STRING_INFO,*LPOUTPUT_DEBUG_STRING_INFO; + + typedef struct _RIP_INFO { + DWORD dwError; + DWORD dwType; + } RIP_INFO,*LPRIP_INFO; + + typedef struct _DEBUG_EVENT { + DWORD dwDebugEventCode; + DWORD dwProcessId; + DWORD dwThreadId; + union { + EXCEPTION_DEBUG_INFO Exception; + CREATE_THREAD_DEBUG_INFO CreateThread; + CREATE_PROCESS_DEBUG_INFO CreateProcessInfo; + EXIT_THREAD_DEBUG_INFO ExitThread; + EXIT_PROCESS_DEBUG_INFO ExitProcess; + LOAD_DLL_DEBUG_INFO LoadDll; + UNLOAD_DLL_DEBUG_INFO UnloadDll; + OUTPUT_DEBUG_STRING_INFO DebugString; + RIP_INFO RipInfo; + } u; + } DEBUG_EVENT,*LPDEBUG_EVENT; + + typedef PCONTEXT LPCONTEXT; + typedef PEXCEPTION_RECORD LPEXCEPTION_RECORD; + typedef PEXCEPTION_POINTERS LPEXCEPTION_POINTERS; + +#define DRIVE_UNKNOWN 0 +#define DRIVE_NO_ROOT_DIR 1 +#define DRIVE_REMOVABLE 2 +#define DRIVE_FIXED 3 +#define DRIVE_REMOTE 4 +#define DRIVE_CDROM 5 +#define DRIVE_RAMDISK 6 + +#define GetFreeSpace(w) (0x100000L) +#define FILE_TYPE_UNKNOWN 0x0 +#define FILE_TYPE_DISK 0x1 +#define FILE_TYPE_CHAR 0x2 +#define FILE_TYPE_PIPE 0x3 +#define FILE_TYPE_REMOTE 0x8000 + +#define STD_INPUT_HANDLE ((DWORD)-10) +#define STD_OUTPUT_HANDLE ((DWORD)-11) +#define STD_ERROR_HANDLE ((DWORD)-12) + +#define NOPARITY 0 +#define ODDPARITY 1 +#define EVENPARITY 2 +#define MARKPARITY 3 +#define SPACEPARITY 4 + +#define ONESTOPBIT 0 +#define ONE5STOPBITS 1 +#define TWOSTOPBITS 2 + +#define IGNORE 0 +#define INFINITE 0xffffffff + +#define CBR_110 110 +#define CBR_300 300 +#define CBR_600 600 +#define CBR_1200 1200 +#define CBR_2400 2400 +#define CBR_4800 4800 +#define CBR_9600 9600 +#define CBR_14400 14400 +#define CBR_19200 19200 +#define CBR_38400 38400 +#define CBR_56000 56000 +#define CBR_57600 57600 +#define CBR_115200 115200 +#define CBR_128000 128000 +#define CBR_256000 256000 + +#define CE_RXOVER 0x1 +#define CE_OVERRUN 0x2 +#define CE_RXPARITY 0x4 +#define CE_FRAME 0x8 +#define CE_BREAK 0x10 +#define CE_TXFULL 0x100 +#define CE_PTO 0x200 +#define CE_IOE 0x400 +#define CE_DNS 0x800 +#define CE_OOP 0x1000 +#define CE_MODE 0x8000 + +#define IE_BADID (-1) +#define IE_OPEN (-2) +#define IE_NOPEN (-3) +#define IE_MEMORY (-4) +#define IE_DEFAULT (-5) +#define IE_HARDWARE (-10) +#define IE_BYTESIZE (-11) +#define IE_BAUDRATE (-12) + +#define EV_RXCHAR 0x1 +#define EV_RXFLAG 0x2 +#define EV_TXEMPTY 0x4 +#define EV_CTS 0x8 +#define EV_DSR 0x10 +#define EV_RLSD 0x20 +#define EV_BREAK 0x40 +#define EV_ERR 0x80 +#define EV_RING 0x100 +#define EV_PERR 0x200 +#define EV_RX80FULL 0x400 +#define EV_EVENT1 0x800 +#define EV_EVENT2 0x1000 + +#define SETXOFF 1 +#define SETXON 2 +#define SETRTS 3 +#define CLRRTS 4 +#define SETDTR 5 +#define CLRDTR 6 +#define RESETDEV 7 +#define SETBREAK 8 +#define CLRBREAK 9 + +#define PURGE_TXABORT 0x1 +#define PURGE_RXABORT 0x2 +#define PURGE_TXCLEAR 0x4 +#define PURGE_RXCLEAR 0x8 + +#define LPTx 0x80 + +#define MS_CTS_ON ((DWORD)0x10) +#define MS_DSR_ON ((DWORD)0x20) +#define MS_RING_ON ((DWORD)0x40) +#define MS_RLSD_ON ((DWORD)0x80) + +#define S_QUEUEEMPTY 0 +#define S_THRESHOLD 1 +#define S_ALLTHRESHOLD 2 + +#define S_NORMAL 0 +#define S_LEGATO 1 +#define S_STACCATO 2 + +#define S_PERIOD512 0 +#define S_PERIOD1024 1 +#define S_PERIOD2048 2 +#define S_PERIODVOICE 3 +#define S_WHITE512 4 +#define S_WHITE1024 5 +#define S_WHITE2048 6 +#define S_WHITEVOICE 7 + +#define S_SERDVNA (-1) +#define S_SEROFM (-2) +#define S_SERMACT (-3) +#define S_SERQFUL (-4) +#define S_SERBDNT (-5) +#define S_SERDLN (-6) +#define S_SERDCC (-7) +#define S_SERDTP (-8) +#define S_SERDVL (-9) +#define S_SERDMD (-10) +#define S_SERDSH (-11) +#define S_SERDPT (-12) +#define S_SERDFQ (-13) +#define S_SERDDR (-14) +#define S_SERDSR (-15) +#define S_SERDST (-16) + +#define NMPWAIT_WAIT_FOREVER 0xffffffff +#define NMPWAIT_NOWAIT 0x1 +#define NMPWAIT_USE_DEFAULT_WAIT 0x0 + +#define FS_CASE_IS_PRESERVED FILE_CASE_PRESERVED_NAMES +#define FS_CASE_SENSITIVE FILE_CASE_SENSITIVE_SEARCH +#define FS_UNICODE_STORED_ON_DISK FILE_UNICODE_ON_DISK +#define FS_PERSISTENT_ACLS FILE_PERSISTENT_ACLS +#define FS_VOL_IS_COMPRESSED FILE_VOLUME_IS_COMPRESSED +#define FS_FILE_COMPRESSION FILE_FILE_COMPRESSION +#define FS_FILE_ENCRYPTION FILE_SUPPORTS_ENCRYPTION + +#define FILE_MAP_COPY SECTION_QUERY +#define FILE_MAP_WRITE SECTION_MAP_WRITE +#define FILE_MAP_READ SECTION_MAP_READ +#define FILE_MAP_ALL_ACCESS SECTION_ALL_ACCESS +#define FILE_MAP_EXECUTE SECTION_MAP_EXECUTE_EXPLICIT + +#define OF_READ 0x0 +#define OF_WRITE 0x1 +#define OF_READWRITE 0x2 +#define OF_SHARE_COMPAT 0x0 +#define OF_SHARE_EXCLUSIVE 0x10 +#define OF_SHARE_DENY_WRITE 0x20 +#define OF_SHARE_DENY_READ 0x30 +#define OF_SHARE_DENY_NONE 0x40 +#define OF_PARSE 0x100 +#define OF_DELETE 0x200 +#define OF_VERIFY 0x400 +#define OF_CANCEL 0x800 +#define OF_CREATE 0x1000 +#define OF_PROMPT 0x2000 +#define OF_EXIST 0x4000 +#define OF_REOPEN 0x8000 + +#define OFS_MAXPATHNAME 128 + typedef struct _OFSTRUCT { + BYTE cBytes; + BYTE fFixedDisk; + WORD nErrCode; + WORD Reserved1; + WORD Reserved2; + CHAR szPathName[OFS_MAXPATHNAME]; + } OFSTRUCT,*LPOFSTRUCT,*POFSTRUCT; + +#ifndef NOWINBASEINTERLOCK + +#ifndef _NTOS_ + +#if defined(__ia64__) && !defined(RC_INVOKED) + +#define InterlockedIncrement _InterlockedIncrement +#define InterlockedIncrementAcquire _InterlockedIncrement_acq +#define InterlockedIncrementRelease _InterlockedIncrement_rel +#define InterlockedDecrement _InterlockedDecrement +#define InterlockedDecrementAcquire _InterlockedDecrement_acq +#define InterlockedDecrementRelease _InterlockedDecrement_rel +#define InterlockedExchange _InterlockedExchange +#define InterlockedExchangeAdd _InterlockedExchangeAdd +#define InterlockedCompareExchange _InterlockedCompareExchange +#define InterlockedCompareExchangeAcquire _InterlockedCompareExchange_acq +#define InterlockedCompareExchangeRelease _InterlockedCompareExchange_rel +#define InterlockedExchangePointer _InterlockedExchangePointer +#define InterlockedCompareExchangePointer _InterlockedCompareExchangePointer +#define InterlockedCompareExchangePointerRelease _InterlockedCompareExchangePointer_rel +#define InterlockedCompareExchangePointerAcquire _InterlockedCompareExchangePointer_acq + +#define InterlockedIncrement64 _InterlockedIncrement64 +#define InterlockedDecrement64 _InterlockedDecrement64 +#define InterlockedExchange64 _InterlockedExchange64 +#define InterlockedExchangeAcquire64 _InterlockedExchange64_acq +#define InterlockedExchangeAdd64 _InterlockedExchangeAdd64 +#define InterlockedCompareExchange64 _InterlockedCompareExchange64 +#define InterlockedCompareExchangeAcquire64 _InterlockedCompareExchange64_acq +#define InterlockedCompareExchangeRelease64 _InterlockedCompareExchange64_rel + + LONGLONG __cdecl InterlockedIncrement64(LONGLONG volatile *Addend); + LONGLONG __cdecl InterlockedDecrement64(LONGLONG volatile *Addend); + LONG __cdecl InterlockedIncrementAcquire(LONG volatile *Addend); + LONG __cdecl InterlockedDecrementAcquire(LONG volatile *Addend); + LONG __cdecl InterlockedIncrementRelease(LONG volatile *Addend); + LONG __cdecl InterlockedDecrementRelease(LONG volatile *Addend); + LONGLONG __cdecl InterlockedExchange64 (LONGLONG volatile *Target,LONGLONG Value); + LONGLONG __cdecl InterlockedExchangeAcquire64 (LONGLONG volatile *Target,LONGLONG Value); + LONGLONG __cdecl InterlockedExchangeAdd64 (LONGLONG volatile *Addend,LONGLONG Value); + LONGLONG __cdecl InterlockedCompareExchange64 (LONGLONG volatile *Destination,LONGLONG ExChange,LONGLONG Comperand); + LONGLONG __cdecl InterlockedCompareExchangeAcquire64 (LONGLONG volatile *Destination,LONGLONG ExChange,LONGLONG Comperand); + LONGLONG __cdecl InterlockedCompareExchangeRelease64 (LONGLONG volatile *Destination,LONGLONG ExChange,LONGLONG Comperand); + LONG __cdecl InterlockedIncrement(LONG volatile *lpAddend); + LONG __cdecl InterlockedDecrement(LONG volatile *lpAddend); + LONG __cdecl InterlockedExchange(LONG volatile *Target,LONG Value); + LONG __cdecl InterlockedExchangeAdd(LONG volatile *Addend,LONG Value); + LONG __cdecl InterlockedCompareExchange(LONG volatile *Destination,LONG ExChange,LONG Comperand); + LONG __cdecl InterlockedCompareExchangeRelease(LONG volatile *Destination,LONG ExChange,LONG Comperand); + LONG __cdecl InterlockedCompareExchangeAcquire(LONG volatile *Destination,LONG ExChange,LONG Comperand); + PVOID __cdecl InterlockedExchangePointer(PVOID volatile *Target,PVOID Value); + PVOID __cdecl InterlockedCompareExchangePointer(PVOID volatile *Destination,PVOID ExChange,PVOID Comperand); + PVOID __cdecl InterlockedCompareExchangePointerAcquire(PVOID volatile *Destination,PVOID Exchange,PVOID Comperand); + PVOID __cdecl InterlockedCompareExchangePointerRelease(PVOID volatile *Destination,PVOID Exchange,PVOID Comperand); + +#ifndef InterlockedAnd +#define InterlockedAnd InterlockedAnd_Inline + __CRT_INLINE LONG InterlockedAnd_Inline(LONG volatile *Target,LONG Set) { + LONG i; + LONG j; + j = *Target; + do { + i = j; + j = InterlockedCompareExchange(Target,i & Set,i); + } while(i!=j); + return j; + } +#endif + +#ifndef InterlockedOr +#define InterlockedOr InterlockedOr_Inline + + __CRT_INLINE LONG InterlockedOr_Inline(LONG volatile *Target,LONG Set) { + LONG i; + LONG j; + j = *Target; + do { + i = j; + j = InterlockedCompareExchange(Target,i | Set,i); + } while(i!=j); + return j; + } +#endif + +#ifndef InterlockedXor +#define InterlockedXor InterlockedXor_Inline + + __CRT_INLINE LONG InterlockedXor_Inline(LONG volatile *Target,LONG Set) { + LONG i; + LONG j; + j = *Target; + do { + i = j; + j = InterlockedCompareExchange(Target,i ^ Set,i); + } while(i!=j); + return j; + } +#endif + +#ifndef !defined (InterlockedAnd64) +#define InterlockedAnd64 InterlockedAnd64_Inline + + __CRT_INLINE LONGLONG InterlockedAnd64_Inline (LONGLONG volatile *Destination,LONGLONG Value) { + LONGLONG Old; + do { + Old = *Destination; + } while(InterlockedCompareExchange64(Destination,Old & Value,Old)!=Old); + return Old; + } +#endif + +#ifndef InterlockedOr64 +#define InterlockedOr64 InterlockedOr64_Inline + + __CRT_INLINE LONGLONG InterlockedOr64_Inline (LONGLONG volatile *Destination,LONGLONG Value) { + LONGLONG Old; + do { + Old = *Destination; + } while(InterlockedCompareExchange64(Destination,Old | Value,Old)!=Old); + return Old; + } +#endif + +#ifndef InterlockedXor64 +#define InterlockedXor64 InterlockedXor64_Inline + + __CRT_INLINE LONGLONG InterlockedXor64_Inline (LONGLONG volatile *Destination,LONGLONG Value) { + LONGLONG Old; + do { + Old = *Destination; + } while(InterlockedCompareExchange64(Destination,Old ^ Value,Old)!=Old); + return Old; + } +#endif + +#ifndef InterlockedBitTestAndSet +#define InterlockedBitTestAndSet InterlockedBitTestAndSet_Inline + + __CRT_INLINE BOOLEAN InterlockedBitTestAndSet_Inline(LONG *Base,LONG Bit) { + LONG tBit; + tBit = 1<<(Bit & (sizeof (*Base)*8-1)); + return (BOOLEAN)((InterlockedOr(&Base[Bit/(sizeof(*Base)*8)],tBit)&tBit)!=0); + } +#endif + +#ifndef InterlockedBitTestAndReset +#define InterlockedBitTestAndReset InterlockedBitTestAndReset_Inline + + __CRT_INLINE BOOLEAN InterlockedBitTestAndReset_Inline(LONG *Base,LONG Bit) { + LONG tBit; + tBit = 1<<(Bit & (sizeof (*Base)*8-1)); + return (BOOLEAN)((InterlockedAnd(&Base[Bit/(sizeof(*Base)*8)],~tBit)&tBit)!=0); + } +#endif + +#ifndef InterlockedBitTestAndComplement +#define InterlockedBitTestAndComplement InterlockedBitTestAndComplement_Inline + + __CRT_INLINE BOOLEAN InterlockedBitTestAndComplement_Inline(LONG *Base,LONG Bit) { + LONG tBit; + tBit = 1<<(Bit & (sizeof (*Base)*8-1)); + return (BOOLEAN)((InterlockedXor(&Base[Bit/(sizeof(*Base)*8)],tBit)&tBit)!=0); + } +#endif +#elif defined(__x86_64) && !defined(RC_INVOKED) + +#define InterlockedIncrement _InterlockedIncrement +#define InterlockedIncrementAcquire InterlockedIncrement +#define InterlockedIncrementRelease InterlockedIncrement +#define InterlockedDecrement _InterlockedDecrement +#define InterlockedDecrementAcquire InterlockedDecrement +#define InterlockedDecrementRelease InterlockedDecrement +#define InterlockedExchange _InterlockedExchange +#define InterlockedExchangeAdd _InterlockedExchangeAdd +#define InterlockedCompareExchange _InterlockedCompareExchange +#define InterlockedCompareExchangeAcquire InterlockedCompareExchange +#define InterlockedCompareExchangeRelease InterlockedCompareExchange +#define InterlockedExchangePointer _InterlockedExchangePointer +#define InterlockedCompareExchangePointer _InterlockedCompareExchangePointer +#define InterlockedCompareExchangePointerAcquire _InterlockedCompareExchangePointer +#define InterlockedCompareExchangePointerRelease _InterlockedCompareExchangePointer +#define InterlockedAnd64 _InterlockedAnd64 +#define InterlockedOr64 _InterlockedOr64 +#define InterlockedXor64 _InterlockedXor64 +#define InterlockedIncrement64 _InterlockedIncrement64 +#define InterlockedDecrement64 _InterlockedDecrement64 +#define InterlockedExchange64 _InterlockedExchange64 +#define InterlockedExchangeAdd64 _InterlockedExchangeAdd64 +#define InterlockedCompareExchange64 _InterlockedCompareExchange64 +#define InterlockedCompareExchangeAcquire64 InterlockedCompareExchange64 +#define InterlockedCompareExchangeRelease64 InterlockedCompareExchange64 + + LONG InterlockedIncrement(LONG volatile *Addend); + LONG InterlockedDecrement(LONG volatile *Addend); + LONG InterlockedExchange(LONG volatile *Target,LONG Value); + LONG InterlockedExchangeAdd(LONG volatile *Addend,LONG Value); + LONG InterlockedCompareExchange(LONG volatile *Destination,LONG ExChange,LONG Comperand); + PVOID InterlockedCompareExchangePointer(PVOID volatile *Destination,PVOID Exchange,PVOID Comperand); + PVOID InterlockedExchangePointer(PVOID volatile *Target,PVOID Value); + LONG64 InterlockedAnd64(LONG64 volatile *Destination,LONG64 Value); + LONG64 InterlockedOr64(LONG64 volatile *Destination,LONG64 Value); + LONG64 InterlockedXor64(LONG64 volatile *Destination,LONG64 Value); + LONG64 InterlockedIncrement64(LONG64 volatile *Addend); + LONG64 InterlockedDecrement64(LONG64 volatile *Addend); + LONG64 InterlockedExchange64(LONG64 volatile *Target,LONG64 Value); + LONG64 InterlockedExchangeAdd64(LONG64 volatile *Addend,LONG64 Value); + LONG64 InterlockedCompareExchange64(LONG64 volatile *Destination,LONG64 ExChange,LONG64 Comperand); +#else + LONG WINAPI InterlockedIncrement(LONG volatile *lpAddend); + LONG WINAPI InterlockedDecrement(LONG volatile *lpAddend); + LONG WINAPI InterlockedExchange(LONG volatile *Target,LONG Value); + +#define InterlockedExchangePointer(Target,Value) (PVOID)InterlockedExchange((PLONG)(Target),(LONG)(Value)) + + LONG WINAPI InterlockedExchangeAdd(LONG volatile *Addend,LONG Value); + LONG WINAPI InterlockedCompareExchange(LONG volatile *Destination,LONG Exchange,LONG Comperand); + LONGLONG WINAPI InterlockedCompareExchange64(LONGLONG volatile *Destination,LONGLONG Exchange,LONGLONG Comperand); + + __CRT_INLINE LONGLONG InterlockedAnd64 (LONGLONG volatile *Destination,LONGLONG Value) { + LONGLONG Old; + do { + Old = *Destination; + } while(InterlockedCompareExchange64(Destination,Old & Value,Old)!=Old); + return Old; + } + + __CRT_INLINE LONGLONG InterlockedOr64 (LONGLONG volatile *Destination,LONGLONG Value) { + LONGLONG Old; + do { + Old = *Destination; + } while(InterlockedCompareExchange64(Destination,Old | Value,Old)!=Old); + return Old; + } + + __CRT_INLINE LONGLONG InterlockedXor64 (LONGLONG volatile *Destination,LONGLONG Value) { + LONGLONG Old; + do { + Old = *Destination; + } while(InterlockedCompareExchange64(Destination,Old ^ Value,Old)!=Old); + + return Old; + } + + __CRT_INLINE LONGLONG InterlockedIncrement64(LONGLONG volatile *Addend) { + LONGLONG Old; + do { + Old = *Addend; + } while(InterlockedCompareExchange64(Addend,Old + 1,Old)!=Old); + return Old + 1; + } + + __CRT_INLINE LONGLONG InterlockedDecrement64(LONGLONG volatile *Addend) { + LONGLONG Old; + do { + Old = *Addend; + } while(InterlockedCompareExchange64(Addend,Old - 1,Old)!=Old); + return Old - 1; + } + + __CRT_INLINE LONGLONG InterlockedExchange64(LONGLONG volatile *Target,LONGLONG Value) { + LONGLONG Old; + do { + Old = *Target; + } while(InterlockedCompareExchange64(Target,Value,Old)!=Old); + return Old; + } + + __CRT_INLINE LONGLONG InterlockedExchangeAdd64(LONGLONG volatile *Addend,LONGLONG Value) { + LONGLONG Old; + do { + Old = *Addend; + } while(InterlockedCompareExchange64(Addend,Old + Value,Old)!=Old); + return Old; + } + +#ifdef __cplusplus + __CRT_INLINE PVOID __cdecl __InlineInterlockedCompareExchangePointer(PVOID volatile *Destination,PVOID ExChange,PVOID Comperand) { + return((PVOID)(LONG_PTR)InterlockedCompareExchange((LONG volatile *)Destination,(LONG)(LONG_PTR)ExChange,(LONG)(LONG_PTR)Comperand)); + } +#define InterlockedCompareExchangePointer __InlineInterlockedCompareExchangePointer +#else +#define InterlockedCompareExchangePointer(Destination,ExChange,Comperand)(PVOID)(LONG_PTR)InterlockedCompareExchange((LONG volatile *)(Destination),(LONG)(LONG_PTR)(ExChange),(LONG)(LONG_PTR)(Comperand)) +#endif + +#define InterlockedIncrementAcquire InterlockedIncrement +#define InterlockedIncrementRelease InterlockedIncrement +#define InterlockedDecrementAcquire InterlockedDecrement +#define InterlockedDecrementRelease InterlockedDecrement +#define InterlockedIncrementAcquire InterlockedIncrement +#define InterlockedIncrementRelease InterlockedIncrement +#define InterlockedCompareExchangeAcquire InterlockedCompareExchange +#define InterlockedCompareExchangeRelease InterlockedCompareExchange +#define InterlockedCompareExchangeAcquire64 InterlockedCompareExchange64 +#define InterlockedCompareExchangeRelease64 InterlockedCompareExchange64 +#define InterlockedCompareExchangePointerAcquire InterlockedCompareExchangePointer +#define InterlockedCompareExchangePointerRelease InterlockedCompareExchangePointer +#endif + +#if defined(_SLIST_HEADER_) && !defined(_NTOSP_) + WINBASEAPI VOID WINAPI InitializeSListHead(PSLIST_HEADER ListHead); + WINBASEAPI PSLIST_ENTRY WINAPI InterlockedPopEntrySList(PSLIST_HEADER ListHead); + WINBASEAPI PSLIST_ENTRY WINAPI InterlockedPushEntrySList(PSLIST_HEADER ListHead,PSLIST_ENTRY ListEntry); + WINBASEAPI PSLIST_ENTRY WINAPI InterlockedFlushSList(PSLIST_HEADER ListHead); + WINBASEAPI USHORT WINAPI QueryDepthSList(PSLIST_HEADER ListHead); +#endif +#endif +#endif + + WINBASEAPI WINBOOL WINAPI FreeResource(HGLOBAL hResData); + WINBASEAPI LPVOID WINAPI LockResource(HGLOBAL hResData); + +#define UnlockResource(hResData) ((hResData),0) +#define MAXINTATOM 0xC000 +#define MAKEINTATOM(i) (LPTSTR)((ULONG_PTR)((WORD)(i))) +#define INVALID_ATOM ((ATOM)0) + + int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nShowCmd); + WINBASEAPI WINBOOL WINAPI FreeLibrary(HMODULE hLibModule); + WINBASEAPI DECLSPEC_NORETURN VOID WINAPI FreeLibraryAndExitThread(HMODULE hLibModule,DWORD dwExitCode); + WINBASEAPI WINBOOL WINAPI DisableThreadLibraryCalls(HMODULE hLibModule); + WINBASEAPI FARPROC WINAPI GetProcAddress(HMODULE hModule,LPCSTR lpProcName); + WINBASEAPI DWORD WINAPI GetVersion(VOID); + WINBASEAPI HGLOBAL WINAPI GlobalAlloc(UINT uFlags,SIZE_T dwBytes); + WINBASEAPI HGLOBAL WINAPI GlobalReAlloc(HGLOBAL hMem,SIZE_T dwBytes,UINT uFlags); + WINBASEAPI SIZE_T WINAPI GlobalSize(HGLOBAL hMem); + WINBASEAPI UINT WINAPI GlobalFlags(HGLOBAL hMem); + WINBASEAPI LPVOID WINAPI GlobalLock(HGLOBAL hMem); + WINBASEAPI HGLOBAL WINAPI GlobalHandle(LPCVOID pMem); + WINBASEAPI WINBOOL WINAPI GlobalUnlock(HGLOBAL hMem); + WINBASEAPI HGLOBAL WINAPI GlobalFree(HGLOBAL hMem); + WINBASEAPI SIZE_T WINAPI GlobalCompact(DWORD dwMinFree); + WINBASEAPI VOID WINAPI GlobalFix(HGLOBAL hMem); + WINBASEAPI VOID WINAPI GlobalUnfix(HGLOBAL hMem); + WINBASEAPI LPVOID WINAPI GlobalWire(HGLOBAL hMem); + WINBASEAPI WINBOOL WINAPI GlobalUnWire(HGLOBAL hMem); + WINBASEAPI VOID WINAPI GlobalMemoryStatus(LPMEMORYSTATUS lpBuffer); + + typedef struct _MEMORYSTATUSEX { + DWORD dwLength; + DWORD dwMemoryLoad; + DWORDLONG ullTotalPhys; + DWORDLONG ullAvailPhys; + DWORDLONG ullTotalPageFile; + DWORDLONG ullAvailPageFile; + DWORDLONG ullTotalVirtual; + DWORDLONG ullAvailVirtual; + DWORDLONG ullAvailExtendedVirtual; + } MEMORYSTATUSEX,*LPMEMORYSTATUSEX; + + WINBASEAPI WINBOOL WINAPI GlobalMemoryStatusEx(LPMEMORYSTATUSEX lpBuffer); + WINBASEAPI HLOCAL WINAPI LocalAlloc(UINT uFlags,SIZE_T uBytes); + WINBASEAPI HLOCAL WINAPI LocalReAlloc(HLOCAL hMem,SIZE_T uBytes,UINT uFlags); + WINBASEAPI LPVOID WINAPI LocalLock(HLOCAL hMem); + WINBASEAPI HLOCAL WINAPI LocalHandle(LPCVOID pMem); + WINBASEAPI WINBOOL WINAPI LocalUnlock(HLOCAL hMem); + WINBASEAPI SIZE_T WINAPI LocalSize(HLOCAL hMem); + WINBASEAPI UINT WINAPI LocalFlags(HLOCAL hMem); + WINBASEAPI HLOCAL WINAPI LocalFree(HLOCAL hMem); + WINBASEAPI SIZE_T WINAPI LocalShrink(HLOCAL hMem,UINT cbNewSize); + WINBASEAPI SIZE_T WINAPI LocalCompact(UINT uMinFree); + WINBASEAPI WINBOOL WINAPI FlushInstructionCache(HANDLE hProcess,LPCVOID lpBaseAddress,SIZE_T dwSize); + WINBASEAPI LPVOID WINAPI VirtualAlloc(LPVOID lpAddress,SIZE_T dwSize,DWORD flAllocationType,DWORD flProtect); + WINBASEAPI WINBOOL WINAPI VirtualFree(LPVOID lpAddress,SIZE_T dwSize,DWORD dwFreeType); + WINBASEAPI WINBOOL WINAPI VirtualProtect(LPVOID lpAddress,SIZE_T dwSize,DWORD flNewProtect,PDWORD lpflOldProtect); + WINBASEAPI SIZE_T WINAPI VirtualQuery(LPCVOID lpAddress,PMEMORY_BASIC_INFORMATION lpBuffer,SIZE_T dwLength); + WINBASEAPI LPVOID WINAPI VirtualAllocEx(HANDLE hProcess,LPVOID lpAddress,SIZE_T dwSize,DWORD flAllocationType,DWORD flProtect); + WINBASEAPI UINT WINAPI GetWriteWatch(DWORD dwFlags,PVOID lpBaseAddress,SIZE_T dwRegionSize,PVOID *lpAddresses,ULONG_PTR *lpdwCount,PULONG lpdwGranularity); + WINBASEAPI UINT WINAPI ResetWriteWatch(LPVOID lpBaseAddress,SIZE_T dwRegionSize); + WINBASEAPI SIZE_T WINAPI GetLargePageMinimum(VOID); + WINBASEAPI UINT WINAPI EnumSystemFirmwareTables(DWORD FirmwareTableProviderSignature,PVOID pFirmwareTableEnumBuffer,DWORD BufferSize); + WINBASEAPI UINT WINAPI GetSystemFirmwareTable(DWORD FirmwareTableProviderSignature,DWORD FirmwareTableID,PVOID pFirmwareTableBuffer,DWORD BufferSize); + WINBASEAPI WINBOOL WINAPI VirtualFreeEx(HANDLE hProcess,LPVOID lpAddress,SIZE_T dwSize,DWORD dwFreeType); + WINBASEAPI WINBOOL WINAPI VirtualProtectEx(HANDLE hProcess,LPVOID lpAddress,SIZE_T dwSize,DWORD flNewProtect,PDWORD lpflOldProtect); + WINBASEAPI SIZE_T WINAPI VirtualQueryEx(HANDLE hProcess,LPCVOID lpAddress,PMEMORY_BASIC_INFORMATION lpBuffer,SIZE_T dwLength); + WINBASEAPI HANDLE WINAPI HeapCreate(DWORD flOptions,SIZE_T dwInitialSize,SIZE_T dwMaximumSize); + WINBASEAPI WINBOOL WINAPI HeapDestroy(HANDLE hHeap); + WINBASEAPI LPVOID WINAPI HeapAlloc(HANDLE hHeap,DWORD dwFlags,SIZE_T dwBytes); + WINBASEAPI LPVOID WINAPI HeapReAlloc(HANDLE hHeap,DWORD dwFlags,LPVOID lpMem,SIZE_T dwBytes); + WINBASEAPI WINBOOL WINAPI HeapFree(HANDLE hHeap,DWORD dwFlags,LPVOID lpMem); + WINBASEAPI SIZE_T WINAPI HeapSize(HANDLE hHeap,DWORD dwFlags,LPCVOID lpMem); + WINBASEAPI WINBOOL WINAPI HeapValidate(HANDLE hHeap,DWORD dwFlags,LPCVOID lpMem); + WINBASEAPI SIZE_T WINAPI HeapCompact(HANDLE hHeap,DWORD dwFlags); + WINBASEAPI HANDLE WINAPI GetProcessHeap(VOID); + WINBASEAPI DWORD WINAPI GetProcessHeaps(DWORD NumberOfHeaps,PHANDLE ProcessHeaps); + + typedef struct _PROCESS_HEAP_ENTRY { + PVOID lpData; + DWORD cbData; + BYTE cbOverhead; + BYTE iRegionIndex; + WORD wFlags; + union { + struct { + HANDLE hMem; + DWORD dwReserved[3]; + } Block; + struct { + DWORD dwCommittedSize; + DWORD dwUnCommittedSize; + LPVOID lpFirstBlock; + LPVOID lpLastBlock; + } Region; + }; + } PROCESS_HEAP_ENTRY,*LPPROCESS_HEAP_ENTRY,*PPROCESS_HEAP_ENTRY; + +#define PROCESS_HEAP_REGION 0x1 +#define PROCESS_HEAP_UNCOMMITTED_RANGE 0x2 +#define PROCESS_HEAP_ENTRY_BUSY 0x4 +#define PROCESS_HEAP_ENTRY_MOVEABLE 0x10 +#define PROCESS_HEAP_ENTRY_DDESHARE 0x20 + + WINBASEAPI WINBOOL WINAPI HeapLock(HANDLE hHeap); + WINBASEAPI WINBOOL WINAPI HeapUnlock(HANDLE hHeap); + WINBASEAPI WINBOOL WINAPI HeapWalk(HANDLE hHeap,LPPROCESS_HEAP_ENTRY lpEntry); + WINBASEAPI WINBOOL WINAPI HeapSetInformation(HANDLE HeapHandle,HEAP_INFORMATION_CLASS HeapInformationClass,PVOID HeapInformation,SIZE_T HeapInformationLength); + WINBASEAPI WINBOOL WINAPI HeapQueryInformation(HANDLE HeapHandle,HEAP_INFORMATION_CLASS HeapInformationClass,PVOID HeapInformation,SIZE_T HeapInformationLength,PSIZE_T ReturnLength); + +#define SCS_32BIT_BINARY 0 +#define SCS_DOS_BINARY 1 +#define SCS_WOW_BINARY 2 +#define SCS_PIF_BINARY 3 +#define SCS_POSIX_BINARY 4 +#define SCS_OS216_BINARY 5 +#define SCS_64BIT_BINARY 6 + +#ifdef UNICODE +#define GetBinaryType GetBinaryTypeW +#define GetShortPathName GetShortPathNameW +#define GetLongPathName GetLongPathNameW +#define GetEnvironmentStrings GetEnvironmentStringsW +#define SetEnvironmentStrings SetEnvironmentStringsW +#define FreeEnvironmentStrings FreeEnvironmentStringsW +#else +#define GetBinaryType GetBinaryTypeA +#define GetShortPathName GetShortPathNameA +#define GetLongPathName GetLongPathNameA +#define GetEnvironmentStringsA GetEnvironmentStrings +#define SetEnvironmentStrings SetEnvironmentStringsA +#define FreeEnvironmentStrings FreeEnvironmentStringsA +#endif + +#ifdef _WIN64 +#define SCS_THIS_PLATFORM_BINARY SCS_64BIT_BINARY +#else +#define SCS_THIS_PLATFORM_BINARY SCS_32BIT_BINARY +#endif + + WINBASEAPI WINBOOL WINAPI GetBinaryTypeA(LPCSTR lpApplicationName,LPDWORD lpBinaryType); + WINBASEAPI WINBOOL WINAPI GetBinaryTypeW(LPCWSTR lpApplicationName,LPDWORD lpBinaryType); + WINBASEAPI DWORD WINAPI GetShortPathNameA(LPCSTR lpszLongPath,LPSTR lpszShortPath,DWORD cchBuffer); + WINBASEAPI DWORD WINAPI GetShortPathNameW(LPCWSTR lpszLongPath,LPWSTR lpszShortPath,DWORD cchBuffer); + WINBASEAPI DWORD WINAPI GetLongPathNameA(LPCSTR lpszShortPath,LPSTR lpszLongPath,DWORD cchBuffer); + WINBASEAPI DWORD WINAPI GetLongPathNameW(LPCWSTR lpszShortPath,LPWSTR lpszLongPath,DWORD cchBuffer); + WINBASEAPI WINBOOL WINAPI GetProcessAffinityMask(HANDLE hProcess,PDWORD_PTR lpProcessAffinityMask,PDWORD_PTR lpSystemAffinityMask); + WINBASEAPI WINBOOL WINAPI SetProcessAffinityMask(HANDLE hProcess,DWORD_PTR dwProcessAffinityMask); + WINBASEAPI WINBOOL WINAPI GetProcessHandleCount(HANDLE hProcess,PDWORD pdwHandleCount); + WINBASEAPI WINBOOL WINAPI GetProcessTimes(HANDLE hProcess,LPFILETIME lpCreationTime,LPFILETIME lpExitTime,LPFILETIME lpKernelTime,LPFILETIME lpUserTime); + WINBASEAPI WINBOOL WINAPI GetProcessIoCounters(HANDLE hProcess,PIO_COUNTERS lpIoCounters); + WINBASEAPI WINBOOL WINAPI GetProcessWorkingSetSize(HANDLE hProcess,PSIZE_T lpMinimumWorkingSetSize,PSIZE_T lpMaximumWorkingSetSize); + WINBASEAPI WINBOOL WINAPI GetProcessWorkingSetSizeEx(HANDLE hProcess,PSIZE_T lpMinimumWorkingSetSize,PSIZE_T lpMaximumWorkingSetSize,PDWORD Flags); + WINBASEAPI WINBOOL WINAPI SetProcessWorkingSetSize(HANDLE hProcess,SIZE_T dwMinimumWorkingSetSize,SIZE_T dwMaximumWorkingSetSize); + WINBASEAPI WINBOOL WINAPI SetProcessWorkingSetSizeEx(HANDLE hProcess,SIZE_T dwMinimumWorkingSetSize,SIZE_T dwMaximumWorkingSetSize,DWORD Flags); + WINBASEAPI HANDLE WINAPI OpenProcess(DWORD dwDesiredAccess,WINBOOL bInheritHandle,DWORD dwProcessId); + WINBASEAPI HANDLE WINAPI GetCurrentProcess(VOID); + WINBASEAPI DWORD WINAPI GetCurrentProcessId(VOID); + WINBASEAPI DECLSPEC_NORETURN VOID WINAPI ExitProcess(UINT uExitCode); + WINBASEAPI WINBOOL WINAPI TerminateProcess(HANDLE hProcess,UINT uExitCode); + WINBASEAPI WINBOOL WINAPI GetExitCodeProcess(HANDLE hProcess,LPDWORD lpExitCode); + WINBASEAPI VOID WINAPI FatalExit(int ExitCode); + /* WINBASEAPI LPCH WINAPI GetEnvironmentStrings(VOID); */ + WINBASEAPI LPWCH WINAPI GetEnvironmentStringsW(VOID); + WINBASEAPI WINBOOL WINAPI SetEnvironmentStringsA(LPCH NewEnvironment); + WINBASEAPI WINBOOL WINAPI SetEnvironmentStringsW(LPWCH NewEnvironment); + WINBASEAPI WINBOOL WINAPI FreeEnvironmentStringsA(LPCH); + WINBASEAPI WINBOOL WINAPI FreeEnvironmentStringsW(LPWCH); + WINBASEAPI VOID WINAPI RaiseException(DWORD dwExceptionCode,DWORD dwExceptionFlags,DWORD nNumberOfArguments,CONST ULONG_PTR *lpArguments); + WINBASEAPI LONG WINAPI UnhandledExceptionFilter(struct _EXCEPTION_POINTERS *ExceptionInfo); + + typedef LONG (WINAPI *PTOP_LEVEL_EXCEPTION_FILTER)(struct _EXCEPTION_POINTERS *ExceptionInfo); + typedef PTOP_LEVEL_EXCEPTION_FILTER LPTOP_LEVEL_EXCEPTION_FILTER; + + WINBASEAPI LPTOP_LEVEL_EXCEPTION_FILTER WINAPI SetUnhandledExceptionFilter(LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter); + +#define FIBER_FLAG_FLOAT_SWITCH 0x1 + + WINBASEAPI LPVOID WINAPI CreateFiber(SIZE_T dwStackSize,LPFIBER_START_ROUTINE lpStartAddress,LPVOID lpParameter); + WINBASEAPI LPVOID WINAPI CreateFiberEx(SIZE_T dwStackCommitSize,SIZE_T dwStackReserveSize,DWORD dwFlags,LPFIBER_START_ROUTINE lpStartAddress,LPVOID lpParameter); + WINBASEAPI VOID WINAPI DeleteFiber(LPVOID lpFiber); + WINBASEAPI LPVOID WINAPI ConvertThreadToFiber(LPVOID lpParameter); + WINBASEAPI LPVOID WINAPI ConvertThreadToFiberEx(LPVOID lpParameter,DWORD dwFlags); + WINBASEAPI WINBOOL WINAPI ConvertFiberToThread(VOID); + WINBASEAPI VOID WINAPI SwitchToFiber(LPVOID lpFiber); + WINBASEAPI WINBOOL WINAPI SwitchToThread(VOID); + WINBASEAPI HANDLE WINAPI CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes,SIZE_T dwStackSize,LPTHREAD_START_ROUTINE lpStartAddress,LPVOID lpParameter,DWORD dwCreationFlags,LPDWORD lpThreadId); + WINBASEAPI HANDLE WINAPI CreateRemoteThread(HANDLE hProcess,LPSECURITY_ATTRIBUTES lpThreadAttributes,SIZE_T dwStackSize,LPTHREAD_START_ROUTINE lpStartAddress,LPVOID lpParameter,DWORD dwCreationFlags,LPDWORD lpThreadId); + WINBASEAPI HANDLE WINAPI GetCurrentThread(VOID); + WINBASEAPI DWORD WINAPI GetCurrentThreadId(VOID); + WINBASEAPI WINBOOL WINAPI SetThreadStackGuarantee (PULONG StackSizeInBytes); + WINBASEAPI DWORD WINAPI GetProcessIdOfThread(HANDLE Thread); + WINBASEAPI DWORD WINAPI GetThreadId(HANDLE Thread); + WINBASEAPI DWORD WINAPI GetProcessId(HANDLE Process); + WINBASEAPI DWORD WINAPI GetCurrentProcessorNumber(VOID); + WINBASEAPI DWORD_PTR WINAPI SetThreadAffinityMask(HANDLE hThread,DWORD_PTR dwThreadAffinityMask); + WINBASEAPI DWORD WINAPI SetThreadIdealProcessor(HANDLE hThread,DWORD dwIdealProcessor); + WINBASEAPI WINBOOL WINAPI SetProcessPriorityBoost(HANDLE hProcess,WINBOOL bDisablePriorityBoost); + WINBASEAPI WINBOOL WINAPI GetProcessPriorityBoost(HANDLE hProcess,PBOOL pDisablePriorityBoost); + WINBASEAPI WINBOOL WINAPI RequestWakeupLatency(LATENCY_TIME latency); + WINBASEAPI WINBOOL WINAPI IsSystemResumeAutomatic(VOID); + WINBASEAPI HANDLE WINAPI OpenThread(DWORD dwDesiredAccess,WINBOOL bInheritHandle,DWORD dwThreadId); + WINBASEAPI WINBOOL WINAPI SetThreadPriority(HANDLE hThread,int nPriority); + WINBASEAPI WINBOOL WINAPI SetThreadPriorityBoost(HANDLE hThread,WINBOOL bDisablePriorityBoost); + WINBASEAPI WINBOOL WINAPI GetThreadPriorityBoost(HANDLE hThread,PBOOL pDisablePriorityBoost); + WINBASEAPI int WINAPI GetThreadPriority(HANDLE hThread); + WINBASEAPI WINBOOL WINAPI GetThreadTimes(HANDLE hThread,LPFILETIME lpCreationTime,LPFILETIME lpExitTime,LPFILETIME lpKernelTime,LPFILETIME lpUserTime); + WINBASEAPI WINBOOL WINAPI GetThreadIOPendingFlag(HANDLE hThread,PBOOL lpIOIsPending); + WINBASEAPI DECLSPEC_NORETURN VOID WINAPI ExitThread(DWORD dwExitCode); + WINBASEAPI WINBOOL WINAPI TerminateThread(HANDLE hThread,DWORD dwExitCode); + WINBASEAPI WINBOOL WINAPI GetExitCodeThread(HANDLE hThread,LPDWORD lpExitCode); + WINBASEAPI WINBOOL WINAPI GetThreadSelectorEntry(HANDLE hThread,DWORD dwSelector,LPLDT_ENTRY lpSelectorEntry); + WINBASEAPI EXECUTION_STATE WINAPI SetThreadExecutionState(EXECUTION_STATE esFlags); + WINBASEAPI DWORD WINAPI GetLastError(VOID); + WINBASEAPI VOID WINAPI SetLastError(DWORD dwErrCode); + +#ifndef RC_INVOKED +#ifdef WINBASE_DECLARE_RESTORE_LAST_ERROR + WINBASEAPI VOID WINAPI RestoreLastError(DWORD dwErrCode); + + typedef VOID (WINAPI *PRESTORE_LAST_ERROR)(DWORD); + +#define RESTORE_LAST_ERROR_NAME_A "RestoreLastError" +#define RESTORE_LAST_ERROR_NAME_W L"RestoreLastError" +#define RESTORE_LAST_ERROR_NAME TEXT("RestoreLastError") +#endif +#endif + +#define HasOverlappedIoCompleted(lpOverlapped) (((DWORD)(lpOverlapped)->Internal)!=STATUS_PENDING) + + WINBASEAPI WINBOOL WINAPI GetOverlappedResult(HANDLE hFile,LPOVERLAPPED lpOverlapped,LPDWORD lpNumberOfBytesTransferred,WINBOOL bWait); + WINBASEAPI HANDLE WINAPI CreateIoCompletionPort(HANDLE FileHandle,HANDLE ExistingCompletionPort,ULONG_PTR CompletionKey,DWORD NumberOfConcurrentThreads); + WINBASEAPI WINBOOL WINAPI GetQueuedCompletionStatus(HANDLE CompletionPort,LPDWORD lpNumberOfBytesTransferred,PULONG_PTR lpCompletionKey,LPOVERLAPPED *lpOverlapped,DWORD dwMilliseconds); + WINBASEAPI WINBOOL WINAPI PostQueuedCompletionStatus(HANDLE CompletionPort,DWORD dwNumberOfBytesTransferred,ULONG_PTR dwCompletionKey,LPOVERLAPPED lpOverlapped); + +#define SEM_FAILCRITICALERRORS 0x1 +#define SEM_NOGPFAULTERRORBOX 0x2 +#define SEM_NOALIGNMENTFAULTEXCEPT 0x4 +#define SEM_NOOPENFILEERRORBOX 0x8000 + + WINBASEAPI UINT WINAPI SetErrorMode(UINT uMode); + WINBASEAPI WINBOOL WINAPI ReadProcessMemory(HANDLE hProcess,LPCVOID lpBaseAddress,LPVOID lpBuffer,SIZE_T nSize,SIZE_T *lpNumberOfBytesRead); + WINBASEAPI WINBOOL WINAPI WriteProcessMemory(HANDLE hProcess,LPVOID lpBaseAddress,LPCVOID lpBuffer,SIZE_T nSize,SIZE_T *lpNumberOfBytesWritten); + WINBASEAPI WINBOOL WINAPI GetThreadContext(HANDLE hThread,LPCONTEXT lpContext); + WINBASEAPI WINBOOL WINAPI SetThreadContext(HANDLE hThread,CONST CONTEXT *lpContext); + WINBASEAPI DWORD WINAPI SuspendThread(HANDLE hThread); + WINBASEAPI DWORD WINAPI ResumeThread(HANDLE hThread); + + typedef VOID (WINAPI *PAPCFUNC)(ULONG_PTR dwParam); + + WINBASEAPI DWORD WINAPI QueueUserAPC(PAPCFUNC pfnAPC,HANDLE hThread,ULONG_PTR dwData); + WINBASEAPI WINBOOL WINAPI IsDebuggerPresent(VOID); + WINBASEAPI WINBOOL WINAPI CheckRemoteDebuggerPresent(HANDLE hProcess,PBOOL pbDebuggerPresent); + WINBASEAPI VOID WINAPI DebugBreak(VOID); + WINBASEAPI WINBOOL WINAPI WaitForDebugEvent(LPDEBUG_EVENT lpDebugEvent,DWORD dwMilliseconds); + WINBASEAPI WINBOOL WINAPI ContinueDebugEvent(DWORD dwProcessId,DWORD dwThreadId,DWORD dwContinueStatus); + WINBASEAPI WINBOOL WINAPI DebugActiveProcess(DWORD dwProcessId); + WINBASEAPI WINBOOL WINAPI DebugActiveProcessStop(DWORD dwProcessId); + WINBASEAPI WINBOOL WINAPI DebugSetProcessKillOnExit(WINBOOL KillOnExit); + WINBASEAPI WINBOOL WINAPI DebugBreakProcess(HANDLE Process); + WINBASEAPI VOID WINAPI InitializeCriticalSection(LPCRITICAL_SECTION lpCriticalSection); + WINBASEAPI VOID WINAPI EnterCriticalSection(LPCRITICAL_SECTION lpCriticalSection); + WINBASEAPI VOID WINAPI LeaveCriticalSection(LPCRITICAL_SECTION lpCriticalSection); + WINBASEAPI WINBOOL WINAPI InitializeCriticalSectionAndSpinCount(LPCRITICAL_SECTION lpCriticalSection,DWORD dwSpinCount); + WINBASEAPI DWORD WINAPI SetCriticalSectionSpinCount(LPCRITICAL_SECTION lpCriticalSection,DWORD dwSpinCount); + WINBASEAPI WINBOOL WINAPI TryEnterCriticalSection(LPCRITICAL_SECTION lpCriticalSection); + WINBASEAPI VOID WINAPI DeleteCriticalSection(LPCRITICAL_SECTION lpCriticalSection); + WINBASEAPI WINBOOL WINAPI SetEvent(HANDLE hEvent); + WINBASEAPI WINBOOL WINAPI ResetEvent(HANDLE hEvent); + WINBASEAPI WINBOOL WINAPI PulseEvent(HANDLE hEvent); + WINBASEAPI WINBOOL WINAPI ReleaseSemaphore(HANDLE hSemaphore,LONG lReleaseCount,LPLONG lpPreviousCount); + WINBASEAPI WINBOOL WINAPI ReleaseMutex(HANDLE hMutex); + WINBASEAPI DWORD WINAPI WaitForSingleObject(HANDLE hHandle,DWORD dwMilliseconds); + WINBASEAPI DWORD WINAPI WaitForMultipleObjects(DWORD nCount,CONST HANDLE *lpHandles,WINBOOL bWaitAll,DWORD dwMilliseconds); + WINBASEAPI VOID WINAPI Sleep(DWORD dwMilliseconds); + WINBASEAPI HGLOBAL WINAPI LoadResource(HMODULE hModule,HRSRC hResInfo); + WINBASEAPI DWORD WINAPI SizeofResource(HMODULE hModule,HRSRC hResInfo); + WINBASEAPI ATOM WINAPI GlobalDeleteAtom(ATOM nAtom); + WINBASEAPI WINBOOL WINAPI InitAtomTable(DWORD nSize); + WINBASEAPI ATOM WINAPI DeleteAtom(ATOM nAtom); + WINBASEAPI UINT WINAPI SetHandleCount(UINT uNumber); + WINBASEAPI DWORD WINAPI GetLogicalDrives(VOID); + WINBASEAPI WINBOOL WINAPI LockFile(HANDLE hFile,DWORD dwFileOffsetLow,DWORD dwFileOffsetHigh,DWORD nNumberOfBytesToLockLow,DWORD nNumberOfBytesToLockHigh); + WINBASEAPI WINBOOL WINAPI UnlockFile(HANDLE hFile,DWORD dwFileOffsetLow,DWORD dwFileOffsetHigh,DWORD nNumberOfBytesToUnlockLow,DWORD nNumberOfBytesToUnlockHigh); + WINBASEAPI WINBOOL WINAPI LockFileEx(HANDLE hFile,DWORD dwFlags,DWORD dwReserved,DWORD nNumberOfBytesToLockLow,DWORD nNumberOfBytesToLockHigh,LPOVERLAPPED lpOverlapped); + +#define LOCKFILE_FAIL_IMMEDIATELY 0x1 +#define LOCKFILE_EXCLUSIVE_LOCK 0x2 + + WINBASEAPI WINBOOL WINAPI UnlockFileEx(HANDLE hFile,DWORD dwReserved,DWORD nNumberOfBytesToUnlockLow,DWORD nNumberOfBytesToUnlockHigh,LPOVERLAPPED lpOverlapped); + + typedef struct _BY_HANDLE_FILE_INFORMATION { + DWORD dwFileAttributes; + FILETIME ftCreationTime; + FILETIME ftLastAccessTime; + FILETIME ftLastWriteTime; + DWORD dwVolumeSerialNumber; + DWORD nFileSizeHigh; + DWORD nFileSizeLow; + DWORD nNumberOfLinks; + DWORD nFileIndexHigh; + DWORD nFileIndexLow; + } BY_HANDLE_FILE_INFORMATION,*PBY_HANDLE_FILE_INFORMATION,*LPBY_HANDLE_FILE_INFORMATION; + +#ifdef UNICODE +#define SetFileShortName SetFileShortNameW +#else +#define SetFileShortName SetFileShortNameA +#endif + + WINBASEAPI WINBOOL WINAPI GetFileInformationByHandle(HANDLE hFile,LPBY_HANDLE_FILE_INFORMATION lpFileInformation); + WINBASEAPI DWORD WINAPI GetFileType(HANDLE hFile); + WINBASEAPI DWORD WINAPI GetFileSize(HANDLE hFile,LPDWORD lpFileSizeHigh); + WINBASEAPI WINBOOL WINAPI GetFileSizeEx(HANDLE hFile,PLARGE_INTEGER lpFileSize); + WINBASEAPI HANDLE WINAPI GetStdHandle(DWORD nStdHandle); + WINBASEAPI WINBOOL WINAPI SetStdHandle(DWORD nStdHandle,HANDLE hHandle); + WINBASEAPI WINBOOL WINAPI WriteFile(HANDLE hFile,LPCVOID lpBuffer,DWORD nNumberOfBytesToWrite,LPDWORD lpNumberOfBytesWritten,LPOVERLAPPED lpOverlapped); + WINBASEAPI WINBOOL WINAPI ReadFile(HANDLE hFile,LPVOID lpBuffer,DWORD nNumberOfBytesToRead,LPDWORD lpNumberOfBytesRead,LPOVERLAPPED lpOverlapped); + WINBASEAPI WINBOOL WINAPI FlushFileBuffers(HANDLE hFile); + WINBASEAPI WINBOOL WINAPI DeviceIoControl(HANDLE hDevice,DWORD dwIoControlCode,LPVOID lpInBuffer,DWORD nInBufferSize,LPVOID lpOutBuffer,DWORD nOutBufferSize,LPDWORD lpBytesReturned,LPOVERLAPPED lpOverlapped); + WINBASEAPI WINBOOL WINAPI RequestDeviceWakeup(HANDLE hDevice); + WINBASEAPI WINBOOL WINAPI CancelDeviceWakeupRequest(HANDLE hDevice); + WINBASEAPI WINBOOL WINAPI GetDevicePowerState(HANDLE hDevice,WINBOOL *pfOn); + WINBASEAPI WINBOOL WINAPI SetMessageWaitingIndicator(HANDLE hMsgIndicator,ULONG ulMsgCount); + WINBASEAPI WINBOOL WINAPI SetEndOfFile(HANDLE hFile); + WINBASEAPI DWORD WINAPI SetFilePointer(HANDLE hFile,LONG lDistanceToMove,PLONG lpDistanceToMoveHigh,DWORD dwMoveMethod); + WINBASEAPI WINBOOL WINAPI SetFilePointerEx(HANDLE hFile,LARGE_INTEGER liDistanceToMove,PLARGE_INTEGER lpNewFilePointer,DWORD dwMoveMethod); + WINBASEAPI WINBOOL WINAPI FindClose(HANDLE hFindFile); + WINBASEAPI WINBOOL WINAPI GetFileTime(HANDLE hFile,LPFILETIME lpCreationTime,LPFILETIME lpLastAccessTime,LPFILETIME lpLastWriteTime); + WINBASEAPI WINBOOL WINAPI SetFileTime(HANDLE hFile,CONST FILETIME *lpCreationTime,CONST FILETIME *lpLastAccessTime,CONST FILETIME *lpLastWriteTime); + WINBASEAPI WINBOOL WINAPI SetFileValidData(HANDLE hFile,LONGLONG ValidDataLength); + WINBASEAPI WINBOOL WINAPI SetFileShortNameA(HANDLE hFile,LPCSTR lpShortName); + WINBASEAPI WINBOOL WINAPI SetFileShortNameW(HANDLE hFile,LPCWSTR lpShortName); + WINBASEAPI WINBOOL WINAPI CloseHandle(HANDLE hObject); + WINBASEAPI WINBOOL WINAPI DuplicateHandle(HANDLE hSourceProcessHandle,HANDLE hSourceHandle,HANDLE hTargetProcessHandle,LPHANDLE lpTargetHandle,DWORD dwDesiredAccess,WINBOOL bInheritHandle,DWORD dwOptions); + WINBASEAPI WINBOOL WINAPI GetHandleInformation(HANDLE hObject,LPDWORD lpdwFlags); + WINBASEAPI WINBOOL WINAPI SetHandleInformation(HANDLE hObject,DWORD dwMask,DWORD dwFlags); + +#define HANDLE_FLAG_INHERIT 0x1 +#define HANDLE_FLAG_PROTECT_FROM_CLOSE 0x2 + +#define HINSTANCE_ERROR 32 + + WINBASEAPI DWORD WINAPI LoadModule(LPCSTR lpModuleName,LPVOID lpParameterBlock); + WINBASEAPI UINT WINAPI WinExec(LPCSTR lpCmdLine,UINT uCmdShow); + WINBASEAPI WINBOOL WINAPI ClearCommBreak(HANDLE hFile); + WINBASEAPI WINBOOL WINAPI ClearCommError(HANDLE hFile,LPDWORD lpErrors,LPCOMSTAT lpStat); + WINBASEAPI WINBOOL WINAPI SetupComm(HANDLE hFile,DWORD dwInQueue,DWORD dwOutQueue); + WINBASEAPI WINBOOL WINAPI EscapeCommFunction(HANDLE hFile,DWORD dwFunc); + WINBASEAPI WINBOOL WINAPI GetCommConfig(HANDLE hCommDev,LPCOMMCONFIG lpCC,LPDWORD lpdwSize); + WINBASEAPI WINBOOL WINAPI GetCommMask(HANDLE hFile,LPDWORD lpEvtMask); + WINBASEAPI WINBOOL WINAPI GetCommProperties(HANDLE hFile,LPCOMMPROP lpCommProp); + WINBASEAPI WINBOOL WINAPI GetCommModemStatus(HANDLE hFile,LPDWORD lpModemStat); + WINBASEAPI WINBOOL WINAPI GetCommState(HANDLE hFile,LPDCB lpDCB); + WINBASEAPI WINBOOL WINAPI GetCommTimeouts(HANDLE hFile,LPCOMMTIMEOUTS lpCommTimeouts); + WINBASEAPI WINBOOL WINAPI PurgeComm(HANDLE hFile,DWORD dwFlags); + WINBASEAPI WINBOOL WINAPI SetCommBreak(HANDLE hFile); + WINBASEAPI WINBOOL WINAPI SetCommConfig(HANDLE hCommDev,LPCOMMCONFIG lpCC,DWORD dwSize); + WINBASEAPI WINBOOL WINAPI SetCommMask(HANDLE hFile,DWORD dwEvtMask); + WINBASEAPI WINBOOL WINAPI SetCommState(HANDLE hFile,LPDCB lpDCB); + WINBASEAPI WINBOOL WINAPI SetCommTimeouts(HANDLE hFile,LPCOMMTIMEOUTS lpCommTimeouts); + WINBASEAPI WINBOOL WINAPI TransmitCommChar(HANDLE hFile,char cChar); + WINBASEAPI WINBOOL WINAPI WaitCommEvent(HANDLE hFile,LPDWORD lpEvtMask,LPOVERLAPPED lpOverlapped); + WINBASEAPI DWORD WINAPI SetTapePosition(HANDLE hDevice,DWORD dwPositionMethod,DWORD dwPartition,DWORD dwOffsetLow,DWORD dwOffsetHigh,WINBOOL bImmediate); + WINBASEAPI DWORD WINAPI GetTapePosition(HANDLE hDevice,DWORD dwPositionType,LPDWORD lpdwPartition,LPDWORD lpdwOffsetLow,LPDWORD lpdwOffsetHigh); + WINBASEAPI DWORD WINAPI PrepareTape(HANDLE hDevice,DWORD dwOperation,WINBOOL bImmediate); + WINBASEAPI DWORD WINAPI EraseTape(HANDLE hDevice,DWORD dwEraseType,WINBOOL bImmediate); + WINBASEAPI DWORD WINAPI CreateTapePartition(HANDLE hDevice,DWORD dwPartitionMethod,DWORD dwCount,DWORD dwSize); + WINBASEAPI DWORD WINAPI WriteTapemark(HANDLE hDevice,DWORD dwTapemarkType,DWORD dwTapemarkCount,WINBOOL bImmediate); + WINBASEAPI DWORD WINAPI GetTapeStatus(HANDLE hDevice); + WINBASEAPI DWORD WINAPI GetTapeParameters(HANDLE hDevice,DWORD dwOperation,LPDWORD lpdwSize,LPVOID lpTapeInformation); + +#define GET_TAPE_MEDIA_INFORMATION 0 +#define GET_TAPE_DRIVE_INFORMATION 1 + + WINBASEAPI DWORD WINAPI SetTapeParameters(HANDLE hDevice,DWORD dwOperation,LPVOID lpTapeInformation); + +#define SET_TAPE_MEDIA_INFORMATION 0 +#define SET_TAPE_DRIVE_INFORMATION 1 + + WINBASEAPI WINBOOL WINAPI Beep(DWORD dwFreq,DWORD dwDuration); + WINBASEAPI int WINAPI MulDiv(int nNumber,int nNumerator,int nDenominator); + WINBASEAPI VOID WINAPI GetSystemTime(LPSYSTEMTIME lpSystemTime); + WINBASEAPI VOID WINAPI GetSystemTimeAsFileTime(LPFILETIME lpSystemTimeAsFileTime); + WINBASEAPI WINBOOL WINAPI SetSystemTime(CONST SYSTEMTIME *lpSystemTime); + WINBASEAPI VOID WINAPI GetLocalTime(LPSYSTEMTIME lpSystemTime); + WINBASEAPI WINBOOL WINAPI SetLocalTime(CONST SYSTEMTIME *lpSystemTime); + WINBASEAPI VOID WINAPI GetSystemInfo(LPSYSTEM_INFO lpSystemInfo); + WINBASEAPI WINBOOL WINAPI SetSystemFileCacheSize(SIZE_T MinimumFileCacheSize,SIZE_T MaximumFileCacheSize,DWORD Flags); + WINBASEAPI WINBOOL WINAPI GetSystemFileCacheSize(PSIZE_T lpMinimumFileCacheSize,PSIZE_T lpMaximumFileCacheSize,PDWORD lpFlags); + WINBASEAPI WINBOOL WINAPI GetSystemRegistryQuota(PDWORD pdwQuotaAllowed,PDWORD pdwQuotaUsed); + WINBOOL WINAPI GetSystemTimes(LPFILETIME lpIdleTime,LPFILETIME lpKernelTime,LPFILETIME lpUserTime); + WINBASEAPI VOID WINAPI GetNativeSystemInfo(LPSYSTEM_INFO lpSystemInfo); + WINBASEAPI WINBOOL WINAPI IsProcessorFeaturePresent(DWORD ProcessorFeature); + + typedef struct _TIME_ZONE_INFORMATION { + LONG Bias; + WCHAR StandardName[32]; + SYSTEMTIME StandardDate; + LONG StandardBias; + WCHAR DaylightName[32]; + SYSTEMTIME DaylightDate; + LONG DaylightBias; + } TIME_ZONE_INFORMATION,*PTIME_ZONE_INFORMATION,*LPTIME_ZONE_INFORMATION; + +#ifdef UNICODE +#define FormatMessage FormatMessageW +#else +#define FormatMessage FormatMessageA +#endif + + WINBASEAPI WINBOOL WINAPI SystemTimeToTzSpecificLocalTime(LPTIME_ZONE_INFORMATION lpTimeZoneInformation,LPSYSTEMTIME lpUniversalTime,LPSYSTEMTIME lpLocalTime); + WINBASEAPI WINBOOL WINAPI TzSpecificLocalTimeToSystemTime(LPTIME_ZONE_INFORMATION lpTimeZoneInformation,LPSYSTEMTIME lpLocalTime,LPSYSTEMTIME lpUniversalTime); + WINBASEAPI DWORD WINAPI GetTimeZoneInformation(LPTIME_ZONE_INFORMATION lpTimeZoneInformation); + WINBASEAPI WINBOOL WINAPI SetTimeZoneInformation(CONST TIME_ZONE_INFORMATION *lpTimeZoneInformation); + WINBASEAPI WINBOOL WINAPI SystemTimeToFileTime(CONST SYSTEMTIME *lpSystemTime,LPFILETIME lpFileTime); + WINBASEAPI WINBOOL WINAPI FileTimeToLocalFileTime(CONST FILETIME *lpFileTime,LPFILETIME lpLocalFileTime); + WINBASEAPI WINBOOL WINAPI LocalFileTimeToFileTime(CONST FILETIME *lpLocalFileTime,LPFILETIME lpFileTime); + WINBASEAPI WINBOOL WINAPI FileTimeToSystemTime(CONST FILETIME *lpFileTime,LPSYSTEMTIME lpSystemTime); + WINBASEAPI LONG WINAPI CompareFileTime(CONST FILETIME *lpFileTime1,CONST FILETIME *lpFileTime2); + WINBASEAPI WINBOOL WINAPI FileTimeToDosDateTime(CONST FILETIME *lpFileTime,LPWORD lpFatDate,LPWORD lpFatTime); + WINBASEAPI WINBOOL WINAPI DosDateTimeToFileTime(WORD wFatDate,WORD wFatTime,LPFILETIME lpFileTime); + WINBASEAPI DWORD WINAPI GetTickCount(VOID); + WINBASEAPI WINBOOL WINAPI SetSystemTimeAdjustment(DWORD dwTimeAdjustment,WINBOOL bTimeAdjustmentDisabled); + WINBASEAPI WINBOOL WINAPI GetSystemTimeAdjustment(PDWORD lpTimeAdjustment,PDWORD lpTimeIncrement,PBOOL lpTimeAdjustmentDisabled); + WINBASEAPI DWORD WINAPI FormatMessageA(DWORD dwFlags,LPCVOID lpSource,DWORD dwMessageId,DWORD dwLanguageId,LPSTR lpBuffer,DWORD nSize,va_list *Arguments); + WINBASEAPI DWORD WINAPI FormatMessageW(DWORD dwFlags,LPCVOID lpSource,DWORD dwMessageId,DWORD dwLanguageId,LPWSTR lpBuffer,DWORD nSize,va_list *Arguments); + +#define FORMAT_MESSAGE_ALLOCATE_BUFFER 0x100 +#define FORMAT_MESSAGE_IGNORE_INSERTS 0x200 +#define FORMAT_MESSAGE_FROM_STRING 0x400 +#define FORMAT_MESSAGE_FROM_HMODULE 0x800 +#define FORMAT_MESSAGE_FROM_SYSTEM 0x1000 +#define FORMAT_MESSAGE_ARGUMENT_ARRAY 0x2000 +#define FORMAT_MESSAGE_MAX_WIDTH_MASK 0xff + +#ifdef UNICODE +#define CreateMailslot CreateMailslotW +#define EncryptFile EncryptFileW +#define DecryptFile DecryptFileW +#define FileEncryptionStatus FileEncryptionStatusW +#else +#define CreateMailslot CreateMailslotA +#define EncryptFile EncryptFileA +#define DecryptFile DecryptFileA +#define FileEncryptionStatus FileEncryptionStatusA +#endif + + WINBASEAPI WINBOOL WINAPI CreatePipe(PHANDLE hReadPipe,PHANDLE hWritePipe,LPSECURITY_ATTRIBUTES lpPipeAttributes,DWORD nSize); + WINBASEAPI WINBOOL WINAPI ConnectNamedPipe(HANDLE hNamedPipe,LPOVERLAPPED lpOverlapped); + WINBASEAPI WINBOOL WINAPI DisconnectNamedPipe(HANDLE hNamedPipe); + WINBASEAPI WINBOOL WINAPI SetNamedPipeHandleState(HANDLE hNamedPipe,LPDWORD lpMode,LPDWORD lpMaxCollectionCount,LPDWORD lpCollectDataTimeout); + WINBASEAPI WINBOOL WINAPI GetNamedPipeInfo(HANDLE hNamedPipe,LPDWORD lpFlags,LPDWORD lpOutBufferSize,LPDWORD lpInBufferSize,LPDWORD lpMaxInstances); + WINBASEAPI WINBOOL WINAPI PeekNamedPipe(HANDLE hNamedPipe,LPVOID lpBuffer,DWORD nBufferSize,LPDWORD lpBytesRead,LPDWORD lpTotalBytesAvail,LPDWORD lpBytesLeftThisMessage); + WINBASEAPI WINBOOL WINAPI TransactNamedPipe(HANDLE hNamedPipe,LPVOID lpInBuffer,DWORD nInBufferSize,LPVOID lpOutBuffer,DWORD nOutBufferSize,LPDWORD lpBytesRead,LPOVERLAPPED lpOverlapped); + WINBASEAPI HANDLE WINAPI CreateMailslotA(LPCSTR lpName,DWORD nMaxMessageSize,DWORD lReadTimeout,LPSECURITY_ATTRIBUTES lpSecurityAttributes); + WINBASEAPI HANDLE WINAPI CreateMailslotW(LPCWSTR lpName,DWORD nMaxMessageSize,DWORD lReadTimeout,LPSECURITY_ATTRIBUTES lpSecurityAttributes); + WINBASEAPI WINBOOL WINAPI GetMailslotInfo(HANDLE hMailslot,LPDWORD lpMaxMessageSize,LPDWORD lpNextSize,LPDWORD lpMessageCount,LPDWORD lpReadTimeout); + WINBASEAPI WINBOOL WINAPI SetMailslotInfo(HANDLE hMailslot,DWORD lReadTimeout); + WINBASEAPI LPVOID WINAPI MapViewOfFile(HANDLE hFileMappingObject,DWORD dwDesiredAccess,DWORD dwFileOffsetHigh,DWORD dwFileOffsetLow,SIZE_T dwNumberOfBytesToMap); + WINBASEAPI WINBOOL WINAPI FlushViewOfFile(LPCVOID lpBaseAddress,SIZE_T dwNumberOfBytesToFlush); + WINBASEAPI WINBOOL WINAPI UnmapViewOfFile(LPCVOID lpBaseAddress); + WINADVAPI WINBOOL WINAPI EncryptFileA(LPCSTR lpFileName); + WINADVAPI WINBOOL WINAPI EncryptFileW(LPCWSTR lpFileName); + WINADVAPI WINBOOL WINAPI DecryptFileA(LPCSTR lpFileName,DWORD dwReserved); + WINADVAPI WINBOOL WINAPI DecryptFileW(LPCWSTR lpFileName,DWORD dwReserved); + +#define FILE_ENCRYPTABLE 0 +#define FILE_IS_ENCRYPTED 1 +#define FILE_SYSTEM_ATTR 2 +#define FILE_ROOT_DIR 3 +#define FILE_SYSTEM_DIR 4 +#define FILE_UNKNOWN 5 +#define FILE_SYSTEM_NOT_SUPPORT 6 +#define FILE_USER_DISALLOWED 7 +#define FILE_READ_ONLY 8 +#define FILE_DIR_DISALLOWED 9 + + WINADVAPI WINBOOL WINAPI FileEncryptionStatusA(LPCSTR lpFileName,LPDWORD lpStatus); + WINADVAPI WINBOOL WINAPI FileEncryptionStatusW(LPCWSTR lpFileName,LPDWORD lpStatus); + +#define EFS_USE_RECOVERY_KEYS (0x1) + + typedef DWORD (WINAPI *PFE_EXPORT_FUNC)(PBYTE pbData,PVOID pvCallbackContext,ULONG ulLength); + typedef DWORD (WINAPI *PFE_IMPORT_FUNC)(PBYTE pbData,PVOID pvCallbackContext,PULONG ulLength); + +#define CREATE_FOR_IMPORT (1) +#define CREATE_FOR_DIR (2) +#define OVERWRITE_HIDDEN (4) + +#ifdef UNICODE +#define OpenEncryptedFileRaw OpenEncryptedFileRawW +#define lstrcmp lstrcmpW +#define lstrcmpi lstrcmpiW +#define lstrcpyn lstrcpynW +#define lstrcpy lstrcpyW +#define lstrcat lstrcatW +#define lstrlen lstrlenW +#else +#define OpenEncryptedFileRaw OpenEncryptedFileRawA +#define lstrcmp lstrcmpA +#define lstrcmpi lstrcmpiA +#define lstrcpyn lstrcpynA +#define lstrcpy lstrcpyA +#define lstrcat lstrcatA +#define lstrlen lstrlenA +#endif + + WINADVAPI DWORD WINAPI OpenEncryptedFileRawA(LPCSTR lpFileName,ULONG ulFlags,PVOID *pvContext); + WINADVAPI DWORD WINAPI OpenEncryptedFileRawW(LPCWSTR lpFileName,ULONG ulFlags,PVOID *pvContext); + WINADVAPI DWORD WINAPI ReadEncryptedFileRaw(PFE_EXPORT_FUNC pfExportCallback,PVOID pvCallbackContext,PVOID pvContext); + WINADVAPI DWORD WINAPI WriteEncryptedFileRaw(PFE_IMPORT_FUNC pfImportCallback,PVOID pvCallbackContext,PVOID pvContext); + WINADVAPI VOID WINAPI CloseEncryptedFileRaw(PVOID pvContext); + WINBASEAPI int WINAPI lstrcmpA(LPCSTR lpString1,LPCSTR lpString2); + WINBASEAPI int WINAPI lstrcmpW(LPCWSTR lpString1,LPCWSTR lpString2); + WINBASEAPI int WINAPI lstrcmpiA(LPCSTR lpString1,LPCSTR lpString2); + WINBASEAPI int WINAPI lstrcmpiW(LPCWSTR lpString1,LPCWSTR lpString2); + WINBASEAPI LPSTR WINAPI lstrcpynA(LPSTR lpString1,LPCSTR lpString2,int iMaxLength); + WINBASEAPI LPWSTR WINAPI lstrcpynW(LPWSTR lpString1,LPCWSTR lpString2,int iMaxLength); + WINBASEAPI LPSTR WINAPI lstrcpyA(LPSTR lpString1,LPCSTR lpString2); + WINBASEAPI LPWSTR WINAPI lstrcpyW(LPWSTR lpString1,LPCWSTR lpString2); + WINBASEAPI LPSTR WINAPI lstrcatA(LPSTR lpString1,LPCSTR lpString2); + WINBASEAPI LPWSTR WINAPI lstrcatW(LPWSTR lpString1,LPCWSTR lpString2); + WINBASEAPI int WINAPI lstrlenA(LPCSTR lpString); + WINBASEAPI int WINAPI lstrlenW(LPCWSTR lpString); + WINBASEAPI HFILE WINAPI OpenFile(LPCSTR lpFileName,LPOFSTRUCT lpReOpenBuff,UINT uStyle); + WINBASEAPI HFILE WINAPI _lopen(LPCSTR lpPathName,int iReadWrite); + WINBASEAPI HFILE WINAPI _lcreat(LPCSTR lpPathName,int iAttribute); + WINBASEAPI UINT WINAPI _lread(HFILE hFile,LPVOID lpBuffer,UINT uBytes); + WINBASEAPI UINT WINAPI _lwrite(HFILE hFile,LPCCH lpBuffer,UINT uBytes); + WINBASEAPI long WINAPI _hread(HFILE hFile,LPVOID lpBuffer,long lBytes); + WINBASEAPI long WINAPI _hwrite(HFILE hFile,LPCCH lpBuffer,long lBytes); + WINBASEAPI HFILE WINAPI _lclose(HFILE hFile); + WINBASEAPI LONG WINAPI _llseek(HFILE hFile,LONG lOffset,int iOrigin); + WINADVAPI WINBOOL WINAPI IsTextUnicode(CONST VOID *lpv,int iSize,LPINT lpiResult); + +#define FLS_OUT_OF_INDEXES ((DWORD)0xffffffff) + + WINBASEAPI DWORD WINAPI FlsAlloc(PFLS_CALLBACK_FUNCTION lpCallback); + WINBASEAPI PVOID WINAPI FlsGetValue(DWORD dwFlsIndex); + WINBASEAPI WINBOOL WINAPI FlsSetValue(DWORD dwFlsIndex,PVOID lpFlsData); + WINBASEAPI WINBOOL WINAPI FlsFree(DWORD dwFlsIndex); + +#define TLS_OUT_OF_INDEXES ((DWORD)0xffffffff) + + WINBASEAPI DWORD WINAPI TlsAlloc(VOID); + WINBASEAPI LPVOID WINAPI TlsGetValue(DWORD dwTlsIndex); + WINBASEAPI WINBOOL WINAPI TlsSetValue(DWORD dwTlsIndex,LPVOID lpTlsValue); + WINBASEAPI WINBOOL WINAPI TlsFree(DWORD dwTlsIndex); + + typedef VOID (WINAPI *LPOVERLAPPED_COMPLETION_ROUTINE)(DWORD dwErrorCode,DWORD dwNumberOfBytesTransfered,LPOVERLAPPED lpOverlapped); + + WINBASEAPI DWORD WINAPI SleepEx(DWORD dwMilliseconds,WINBOOL bAlertable); + WINBASEAPI DWORD WINAPI WaitForSingleObjectEx(HANDLE hHandle,DWORD dwMilliseconds,WINBOOL bAlertable); + WINBASEAPI DWORD WINAPI WaitForMultipleObjectsEx(DWORD nCount,CONST HANDLE *lpHandles,WINBOOL bWaitAll,DWORD dwMilliseconds,WINBOOL bAlertable); + WINBASEAPI DWORD WINAPI SignalObjectAndWait(HANDLE hObjectToSignal,HANDLE hObjectToWaitOn,DWORD dwMilliseconds,WINBOOL bAlertable); + WINBASEAPI WINBOOL WINAPI ReadFileEx(HANDLE hFile,LPVOID lpBuffer,DWORD nNumberOfBytesToRead,LPOVERLAPPED lpOverlapped,LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine); + WINBASEAPI WINBOOL WINAPI WriteFileEx(HANDLE hFile,LPCVOID lpBuffer,DWORD nNumberOfBytesToWrite,LPOVERLAPPED lpOverlapped,LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine); + WINBASEAPI WINBOOL WINAPI BackupRead(HANDLE hFile,LPBYTE lpBuffer,DWORD nNumberOfBytesToRead,LPDWORD lpNumberOfBytesRead,WINBOOL bAbort,WINBOOL bProcessSecurity,LPVOID *lpContext); + WINBASEAPI WINBOOL WINAPI BackupSeek(HANDLE hFile,DWORD dwLowBytesToSeek,DWORD dwHighBytesToSeek,LPDWORD lpdwLowByteSeeked,LPDWORD lpdwHighByteSeeked,LPVOID *lpContext); + WINBASEAPI WINBOOL WINAPI BackupWrite(HANDLE hFile,LPBYTE lpBuffer,DWORD nNumberOfBytesToWrite,LPDWORD lpNumberOfBytesWritten,WINBOOL bAbort,WINBOOL bProcessSecurity,LPVOID *lpContext); + + typedef struct _WIN32_STREAM_ID { + DWORD dwStreamId; + DWORD dwStreamAttributes; + LARGE_INTEGER Size; + DWORD dwStreamNameSize; + WCHAR cStreamName[ANYSIZE_ARRAY]; + } WIN32_STREAM_ID,*LPWIN32_STREAM_ID; + +#define BACKUP_INVALID 0x0 +#define BACKUP_DATA 0x1 +#define BACKUP_EA_DATA 0x2 +#define BACKUP_SECURITY_DATA 0x3 +#define BACKUP_ALTERNATE_DATA 0x4 +#define BACKUP_LINK 0x5 +#define BACKUP_PROPERTY_DATA 0x6 +#define BACKUP_OBJECT_ID 0x7 +#define BACKUP_REPARSE_DATA 0x8 +#define BACKUP_SPARSE_BLOCK 0x9 + +#define STREAM_NORMAL_ATTRIBUTE 0x0 +#define STREAM_MODIFIED_WHEN_READ 0x1 +#define STREAM_CONTAINS_SECURITY 0x2 +#define STREAM_CONTAINS_PROPERTIES 0x4 +#define STREAM_SPARSE_ATTRIBUTE 0x8 + + WINBASEAPI WINBOOL WINAPI ReadFileScatter(HANDLE hFile,FILE_SEGMENT_ELEMENT aSegmentArray[],DWORD nNumberOfBytesToRead,LPDWORD lpReserved,LPOVERLAPPED lpOverlapped); + WINBASEAPI WINBOOL WINAPI WriteFileGather(HANDLE hFile,FILE_SEGMENT_ELEMENT aSegmentArray[],DWORD nNumberOfBytesToWrite,LPDWORD lpReserved,LPOVERLAPPED lpOverlapped); + +#define STARTF_USESHOWWINDOW 0x1 +#define STARTF_USESIZE 0x2 +#define STARTF_USEPOSITION 0x4 +#define STARTF_USECOUNTCHARS 0x8 +#define STARTF_USEFILLATTRIBUTE 0x10 +#define STARTF_RUNFULLSCREEN 0x20 +#define STARTF_FORCEONFEEDBACK 0x40 +#define STARTF_FORCEOFFFEEDBACK 0x80 +#define STARTF_USESTDHANDLES 0x100 + +#define STARTF_USEHOTKEY 0x200 + + typedef struct _STARTUPINFOA { + DWORD cb; + LPSTR lpReserved; + LPSTR lpDesktop; + LPSTR lpTitle; + DWORD dwX; + DWORD dwY; + DWORD dwXSize; + DWORD dwYSize; + DWORD dwXCountChars; + DWORD dwYCountChars; + DWORD dwFillAttribute; + DWORD dwFlags; + WORD wShowWindow; + WORD cbReserved2; + LPBYTE lpReserved2; + HANDLE hStdInput; + HANDLE hStdOutput; + HANDLE hStdError; + } STARTUPINFOA,*LPSTARTUPINFOA; + + typedef struct _STARTUPINFOW { + DWORD cb; + LPWSTR lpReserved; + LPWSTR lpDesktop; + LPWSTR lpTitle; + DWORD dwX; + DWORD dwY; + DWORD dwXSize; + DWORD dwYSize; + DWORD dwXCountChars; + DWORD dwYCountChars; + DWORD dwFillAttribute; + DWORD dwFlags; + WORD wShowWindow; + WORD cbReserved2; + LPBYTE lpReserved2; + HANDLE hStdInput; + HANDLE hStdOutput; + HANDLE hStdError; + } STARTUPINFOW,*LPSTARTUPINFOW; + +#ifdef UNICODE + typedef STARTUPINFOW STARTUPINFO; + typedef LPSTARTUPINFOW LPSTARTUPINFO; +#else + typedef STARTUPINFOA STARTUPINFO; + typedef LPSTARTUPINFOA LPSTARTUPINFO; +#endif + +#define SHUTDOWN_NORETRY 0x1 + + typedef struct _WIN32_FIND_DATAA { + DWORD dwFileAttributes; + FILETIME ftCreationTime; + FILETIME ftLastAccessTime; + FILETIME ftLastWriteTime; + DWORD nFileSizeHigh; + DWORD nFileSizeLow; + DWORD dwReserved0; + DWORD dwReserved1; + CHAR cFileName[MAX_PATH]; + CHAR cAlternateFileName[14]; + } WIN32_FIND_DATAA,*PWIN32_FIND_DATAA,*LPWIN32_FIND_DATAA; + + typedef struct _WIN32_FIND_DATAW { + DWORD dwFileAttributes; + FILETIME ftCreationTime; + FILETIME ftLastAccessTime; + FILETIME ftLastWriteTime; + DWORD nFileSizeHigh; + DWORD nFileSizeLow; + DWORD dwReserved0; + DWORD dwReserved1; + WCHAR cFileName[MAX_PATH]; + WCHAR cAlternateFileName[14]; + } WIN32_FIND_DATAW,*PWIN32_FIND_DATAW,*LPWIN32_FIND_DATAW; + +#ifdef UNICODE + typedef WIN32_FIND_DATAW WIN32_FIND_DATA; + typedef PWIN32_FIND_DATAW PWIN32_FIND_DATA; + typedef LPWIN32_FIND_DATAW LPWIN32_FIND_DATA; +#else + typedef WIN32_FIND_DATAA WIN32_FIND_DATA; + typedef PWIN32_FIND_DATAA PWIN32_FIND_DATA; + typedef LPWIN32_FIND_DATAA LPWIN32_FIND_DATA; +#endif + + typedef struct _WIN32_FILE_ATTRIBUTE_DATA { + DWORD dwFileAttributes; + FILETIME ftCreationTime; + FILETIME ftLastAccessTime; + FILETIME ftLastWriteTime; + DWORD nFileSizeHigh; + DWORD nFileSizeLow; + } WIN32_FILE_ATTRIBUTE_DATA,*LPWIN32_FILE_ATTRIBUTE_DATA; + +#ifdef UNICODE +#define CreateMutex CreateMutexW +#define OpenMutex OpenMutexW +#define CreateEvent CreateEventW +#define OpenEvent OpenEventW +#define CreateSemaphore CreateSemaphoreW +#define OpenSemaphore OpenSemaphoreW +#else +#define CreateMutex CreateMutexA +#define OpenMutex OpenMutexA +#define CreateEvent CreateEventA +#define OpenEvent OpenEventA +#define CreateSemaphore CreateSemaphoreA +#define OpenSemaphore OpenSemaphoreA +#endif + + WINBASEAPI HANDLE WINAPI CreateMutexA(LPSECURITY_ATTRIBUTES lpMutexAttributes,WINBOOL bInitialOwner,LPCSTR lpName); + WINBASEAPI HANDLE WINAPI CreateMutexW(LPSECURITY_ATTRIBUTES lpMutexAttributes,WINBOOL bInitialOwner,LPCWSTR lpName); + WINBASEAPI HANDLE WINAPI OpenMutexA(DWORD dwDesiredAccess,WINBOOL bInheritHandle,LPCSTR lpName); + WINBASEAPI HANDLE WINAPI OpenMutexW(DWORD dwDesiredAccess,WINBOOL bInheritHandle,LPCWSTR lpName); + WINBASEAPI HANDLE WINAPI CreateEventA(LPSECURITY_ATTRIBUTES lpEventAttributes,WINBOOL bManualReset,WINBOOL bInitialState,LPCSTR lpName); + WINBASEAPI HANDLE WINAPI CreateEventW(LPSECURITY_ATTRIBUTES lpEventAttributes,WINBOOL bManualReset,WINBOOL bInitialState,LPCWSTR lpName); + WINBASEAPI HANDLE WINAPI OpenEventA(DWORD dwDesiredAccess,WINBOOL bInheritHandle,LPCSTR lpName); + WINBASEAPI HANDLE WINAPI OpenEventW(DWORD dwDesiredAccess,WINBOOL bInheritHandle,LPCWSTR lpName); + WINBASEAPI HANDLE WINAPI CreateSemaphoreA(LPSECURITY_ATTRIBUTES lpSemaphoreAttributes,LONG lInitialCount,LONG lMaximumCount,LPCSTR lpName); + WINBASEAPI HANDLE WINAPI CreateSemaphoreW(LPSECURITY_ATTRIBUTES lpSemaphoreAttributes,LONG lInitialCount,LONG lMaximumCount,LPCWSTR lpName); + WINBASEAPI HANDLE WINAPI OpenSemaphoreA(DWORD dwDesiredAccess,WINBOOL bInheritHandle,LPCSTR lpName); + WINBASEAPI HANDLE WINAPI OpenSemaphoreW(DWORD dwDesiredAccess,WINBOOL bInheritHandle,LPCWSTR lpName); + + typedef VOID (WINAPI *PTIMERAPCROUTINE)(LPVOID lpArgToCompletionRoutine,DWORD dwTimerLowValue,DWORD dwTimerHighValue); + +#ifdef UNICODE +#define CreateWaitableTimer CreateWaitableTimerW +#define OpenWaitableTimer OpenWaitableTimerW +#define CreateFileMapping CreateFileMappingW +#define OpenFileMapping OpenFileMappingW +#define GetLogicalDriveStrings GetLogicalDriveStringsW +#define LoadLibrary LoadLibraryW +#define LoadLibraryEx LoadLibraryExW +#define GetModuleFileName GetModuleFileNameW +#define GetModuleHandle GetModuleHandleW +#else +#define CreateWaitableTimer CreateWaitableTimerA +#define OpenWaitableTimer OpenWaitableTimerA +#define CreateFileMapping CreateFileMappingA +#define OpenFileMapping OpenFileMappingA +#define GetLogicalDriveStrings GetLogicalDriveStringsA +#define LoadLibrary LoadLibraryA +#define LoadLibraryEx LoadLibraryExA +#define GetModuleFileName GetModuleFileNameA +#define GetModuleHandle GetModuleHandleA +#endif + + WINBASEAPI HANDLE WINAPI CreateWaitableTimerA(LPSECURITY_ATTRIBUTES lpTimerAttributes,WINBOOL bManualReset,LPCSTR lpTimerName); + WINBASEAPI HANDLE WINAPI CreateWaitableTimerW(LPSECURITY_ATTRIBUTES lpTimerAttributes,WINBOOL bManualReset,LPCWSTR lpTimerName); + WINBASEAPI HANDLE WINAPI OpenWaitableTimerA(DWORD dwDesiredAccess,WINBOOL bInheritHandle,LPCSTR lpTimerName); + WINBASEAPI HANDLE WINAPI OpenWaitableTimerW(DWORD dwDesiredAccess,WINBOOL bInheritHandle,LPCWSTR lpTimerName); + WINBASEAPI WINBOOL WINAPI SetWaitableTimer(HANDLE hTimer,const LARGE_INTEGER *lpDueTime,LONG lPeriod,PTIMERAPCROUTINE pfnCompletionRoutine,LPVOID lpArgToCompletionRoutine,WINBOOL fResume); + WINBASEAPI WINBOOL WINAPI CancelWaitableTimer(HANDLE hTimer); + WINBASEAPI HANDLE WINAPI CreateFileMappingA(HANDLE hFile,LPSECURITY_ATTRIBUTES lpFileMappingAttributes,DWORD flProtect,DWORD dwMaximumSizeHigh,DWORD dwMaximumSizeLow,LPCSTR lpName); + WINBASEAPI HANDLE WINAPI CreateFileMappingW(HANDLE hFile,LPSECURITY_ATTRIBUTES lpFileMappingAttributes,DWORD flProtect,DWORD dwMaximumSizeHigh,DWORD dwMaximumSizeLow,LPCWSTR lpName); + WINBASEAPI HANDLE WINAPI OpenFileMappingA(DWORD dwDesiredAccess,WINBOOL bInheritHandle,LPCSTR lpName); + WINBASEAPI HANDLE WINAPI OpenFileMappingW(DWORD dwDesiredAccess,WINBOOL bInheritHandle,LPCWSTR lpName); + WINBASEAPI DWORD WINAPI GetLogicalDriveStringsA(DWORD nBufferLength,LPSTR lpBuffer); + WINBASEAPI DWORD WINAPI GetLogicalDriveStringsW(DWORD nBufferLength,LPWSTR lpBuffer); + + typedef enum _MEMORY_RESOURCE_NOTIFICATION_TYPE { + LowMemoryResourceNotification,HighMemoryResourceNotification + } MEMORY_RESOURCE_NOTIFICATION_TYPE; + + WINBASEAPI HANDLE WINAPI CreateMemoryResourceNotification(MEMORY_RESOURCE_NOTIFICATION_TYPE NotificationType); + WINBASEAPI WINBOOL WINAPI QueryMemoryResourceNotification(HANDLE ResourceNotificationHandle,PBOOL ResourceState); + WINBASEAPI HMODULE WINAPI LoadLibraryA(LPCSTR lpLibFileName); + WINBASEAPI HMODULE WINAPI LoadLibraryW(LPCWSTR lpLibFileName); + WINBASEAPI HMODULE WINAPI LoadLibraryExA(LPCSTR lpLibFileName,HANDLE hFile,DWORD dwFlags); + WINBASEAPI HMODULE WINAPI LoadLibraryExW(LPCWSTR lpLibFileName,HANDLE hFile,DWORD dwFlags); + +#define DONT_RESOLVE_DLL_REFERENCES 0x1 +#define LOAD_LIBRARY_AS_DATAFILE 0x2 +#define LOAD_WITH_ALTERED_SEARCH_PATH 0x8 +#define LOAD_IGNORE_CODE_AUTHZ_LEVEL 0x10 +#define LOAD_LINRARY_AS_IMAGE_RESOURCE 0x20 +#define LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE 0x40 + + WINBASEAPI DWORD WINAPI GetModuleFileNameA(HMODULE hModule,LPCH lpFilename,DWORD nSize); + WINBASEAPI DWORD WINAPI GetModuleFileNameW(HMODULE hModule,LPWCH lpFilename,DWORD nSize); + WINBASEAPI HMODULE WINAPI GetModuleHandleA(LPCSTR lpModuleName); + WINBASEAPI HMODULE WINAPI GetModuleHandleW(LPCWSTR lpModuleName); + +#ifndef RC_INVOKED +#define GET_MODULE_HANDLE_EX_FLAG_PIN (0x1) +#define GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT (0x2) +#define GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS (0x4) + + typedef WINBOOL (WINAPI *PGET_MODULE_HANDLE_EXA)(DWORD dwFlags,LPCSTR lpModuleName,HMODULE *phModule); + typedef WINBOOL (WINAPI *PGET_MODULE_HANDLE_EXW)(DWORD dwFlags,LPCWSTR lpModuleName,HMODULE *phModule); + +#ifdef UNICODE +#define PGET_MODULE_HANDLE_EX PGET_MODULE_HANDLE_EXW +#define GetModuleHandleEx GetModuleHandleExW +#else +#define PGET_MODULE_HANDLE_EX PGET_MODULE_HANDLE_EXA +#define GetModuleHandleEx GetModuleHandleExA +#endif + + WINBASEAPI WINBOOL WINAPI GetModuleHandleExA(DWORD dwFlags,LPCSTR lpModuleName,HMODULE *phModule); + WINBASEAPI WINBOOL WINAPI GetModuleHandleExW(DWORD dwFlags,LPCWSTR lpModuleName,HMODULE *phModule); +#endif + +#ifdef UNICODE +#define NeedCurrentDirectoryForExePath NeedCurrentDirectoryForExePathW +#define CreateProcess CreateProcessW +#define FatalAppExit FatalAppExitW +#define GetStartupInfo GetStartupInfoW +#define GetCommandLine GetCommandLineW +#define GetEnvironmentVariable GetEnvironmentVariableW +#define SetEnvironmentVariable SetEnvironmentVariableW +#define ExpandEnvironmentStrings ExpandEnvironmentStringsW +#define GetFirmwareEnvironmentVariable GetFirmwareEnvironmentVariableW +#define SetFirmwareEnvironmentVariable SetFirmwareEnvironmentVariableW +#define OutputDebugString OutputDebugStringW +#define FindResource FindResourceW +#define FindResourceEx FindResourceExW +#else +#define NeedCurrentDirectoryForExePath NeedCurrentDirectoryForExePathA +#define CreateProcess CreateProcessA +#define FatalAppExit FatalAppExitA +#define GetStartupInfo GetStartupInfoA +#define GetCommandLine GetCommandLineA +#define GetEnvironmentVariable GetEnvironmentVariableA +#define SetEnvironmentVariable SetEnvironmentVariableA +#define ExpandEnvironmentStrings ExpandEnvironmentStringsA +#define GetFirmwareEnvironmentVariable GetFirmwareEnvironmentVariableA +#define SetFirmwareEnvironmentVariable SetFirmwareEnvironmentVariableA +#define OutputDebugString OutputDebugStringA +#define FindResource FindResourceA +#define FindResourceEx FindResourceExA +#endif + + WINBASEAPI WINBOOL WINAPI NeedCurrentDirectoryForExePathA(LPCSTR ExeName); + WINBASEAPI WINBOOL WINAPI NeedCurrentDirectoryForExePathW(LPCWSTR ExeName); + WINBASEAPI WINBOOL WINAPI CreateProcessA(LPCSTR lpApplicationName,LPSTR lpCommandLine,LPSECURITY_ATTRIBUTES lpProcessAttributes,LPSECURITY_ATTRIBUTES lpThreadAttributes,WINBOOL bInheritHandles,DWORD dwCreationFlags,LPVOID lpEnvironment,LPCSTR lpCurrentDirectory,LPSTARTUPINFOA lpStartupInfo,LPPROCESS_INFORMATION lpProcessInformation); + WINBASEAPI WINBOOL WINAPI CreateProcessW(LPCWSTR lpApplicationName,LPWSTR lpCommandLine,LPSECURITY_ATTRIBUTES lpProcessAttributes,LPSECURITY_ATTRIBUTES lpThreadAttributes,WINBOOL bInheritHandles,DWORD dwCreationFlags,LPVOID lpEnvironment,LPCWSTR lpCurrentDirectory,LPSTARTUPINFOW lpStartupInfo,LPPROCESS_INFORMATION lpProcessInformation); + WINBASEAPI DWORD WINAPI AddLocalAlternateComputerNameA(LPCSTR lpDnsFQHostname,ULONG ulFlags); + WINBASEAPI DWORD WINAPI AddLocalAlternateComputerNameW(LPCWSTR lpDnsFQHostname,ULONG ulFlags); + WINBASEAPI WINBOOL WINAPI SetProcessShutdownParameters(DWORD dwLevel,DWORD dwFlags); + WINBASEAPI WINBOOL WINAPI GetProcessShutdownParameters(LPDWORD lpdwLevel,LPDWORD lpdwFlags); + WINBASEAPI DWORD WINAPI GetProcessVersion(DWORD ProcessId); + WINBASEAPI VOID WINAPI FatalAppExitA(UINT uAction,LPCSTR lpMessageText); + WINBASEAPI VOID WINAPI FatalAppExitW(UINT uAction,LPCWSTR lpMessageText); + WINBASEAPI VOID WINAPI GetStartupInfoA(LPSTARTUPINFOA lpStartupInfo); + WINBASEAPI VOID WINAPI GetStartupInfoW(LPSTARTUPINFOW lpStartupInfo); + WINBASEAPI LPSTR WINAPI GetCommandLineA(VOID); + WINBASEAPI LPWSTR WINAPI GetCommandLineW(VOID); + WINBASEAPI DWORD WINAPI GetEnvironmentVariableA(LPCSTR lpName,LPSTR lpBuffer,DWORD nSize); + WINBASEAPI DWORD WINAPI GetEnvironmentVariableW(LPCWSTR lpName,LPWSTR lpBuffer,DWORD nSize); + WINBASEAPI WINBOOL WINAPI SetEnvironmentVariableA(LPCSTR lpName,LPCSTR lpValue); + WINBASEAPI WINBOOL WINAPI SetEnvironmentVariableW(LPCWSTR lpName,LPCWSTR lpValue); + WINBASEAPI DWORD WINAPI ExpandEnvironmentStringsA(LPCSTR lpSrc,LPSTR lpDst,DWORD nSize); + WINBASEAPI DWORD WINAPI ExpandEnvironmentStringsW(LPCWSTR lpSrc,LPWSTR lpDst,DWORD nSize); + WINBASEAPI DWORD WINAPI GetFirmwareEnvironmentVariableA(LPCSTR lpName,LPCSTR lpGuid,PVOID pBuffer,DWORD nSize); + WINBASEAPI DWORD WINAPI GetFirmwareEnvironmentVariableW(LPCWSTR lpName,LPCWSTR lpGuid,PVOID pBuffer,DWORD nSize); + WINBASEAPI WINBOOL WINAPI SetFirmwareEnvironmentVariableA(LPCSTR lpName,LPCSTR lpGuid,PVOID pValue,DWORD nSize); + WINBASEAPI WINBOOL WINAPI SetFirmwareEnvironmentVariableW(LPCWSTR lpName,LPCWSTR lpGuid,PVOID pValue,DWORD nSize); + WINBASEAPI VOID WINAPI OutputDebugStringA(LPCSTR lpOutputString); + WINBASEAPI VOID WINAPI OutputDebugStringW(LPCWSTR lpOutputString); + WINBASEAPI HRSRC WINAPI FindResourceA(HMODULE hModule,LPCSTR lpName,LPCSTR lpType); + WINBASEAPI HRSRC WINAPI FindResourceW(HMODULE hModule,LPCWSTR lpName,LPCWSTR lpType); + WINBASEAPI HRSRC WINAPI FindResourceExA(HMODULE hModule,LPCSTR lpType,LPCSTR lpName,WORD wLanguage); + WINBASEAPI HRSRC WINAPI FindResourceExW(HMODULE hModule,LPCWSTR lpType,LPCWSTR lpName,WORD wLanguage); + +#ifdef UNICODE +#define ENUMRESTYPEPROC ENUMRESTYPEPROCW +#define ENUMRESNAMEPROC ENUMRESNAMEPROCW +#define ENUMRESLANGPROC ENUMRESLANGPROCW +#define EnumResourceTypes EnumResourceTypesW +#define EnumResourceNames EnumResourceNamesW +#define EnumResourceLanguages EnumResourceLanguagesW +#define BeginUpdateResource BeginUpdateResourceW +#define UpdateResource UpdateResourceW +#define EndUpdateResource EndUpdateResourceW +#define GlobalAddAtom GlobalAddAtomW +#define GlobalFindAtom GlobalFindAtomW +#define GlobalGetAtomName GlobalGetAtomNameW +#define AddAtom AddAtomW +#define FindAtom FindAtomW +#define GetAtomName GetAtomNameW +#define GetProfileInt GetProfileIntW +#define GetProfileString GetProfileStringW +#define WriteProfileString WriteProfileStringW +#define GetProfileSection GetProfileSectionW +#define WriteProfileSection WriteProfileSectionW +#define GetPrivateProfileInt GetPrivateProfileIntW +#define GetPrivateProfileString GetPrivateProfileStringW +#define WritePrivateProfileString WritePrivateProfileStringW +#define GetPrivateProfileSection GetPrivateProfileSectionW +#define WritePrivateProfileSection WritePrivateProfileSectionW +#define GetPrivateProfileSectionNames GetPrivateProfileSectionNamesW +#define GetPrivateProfileStruct GetPrivateProfileStructW +#define WritePrivateProfileStruct WritePrivateProfileStructW +#define GetDriveType GetDriveTypeW +#define GetSystemDirectory GetSystemDirectoryW +#define GetTempPath GetTempPathW +#define GetTempFileName GetTempFileNameW +#define GetWindowsDirectory GetWindowsDirectoryW +#define GetSystemWindowsDirectory GetSystemWindowsDirectoryW +#define AddLocalAlternateComputerName AddLocalAlternateComputerNameW +#else +#define ENUMRESTYPEPROC ENUMRESTYPEPROCA +#define ENUMRESNAMEPROC ENUMRESNAMEPROCA +#define ENUMRESLANGPROC ENUMRESLANGPROCA +#define EnumResourceTypes EnumResourceTypesA +#define EnumResourceNames EnumResourceNamesA +#define EnumResourceLanguages EnumResourceLanguagesA +#define BeginUpdateResource BeginUpdateResourceA +#define UpdateResource UpdateResourceA +#define EndUpdateResource EndUpdateResourceA +#define GlobalAddAtom GlobalAddAtomA +#define GlobalFindAtom GlobalFindAtomA +#define GlobalGetAtomName GlobalGetAtomNameA +#define AddAtom AddAtomA +#define FindAtom FindAtomA +#define GetAtomName GetAtomNameA +#define GetProfileInt GetProfileIntA +#define GetProfileString GetProfileStringA +#define WriteProfileString WriteProfileStringA +#define GetProfileSection GetProfileSectionA +#define WriteProfileSection WriteProfileSectionA +#define GetPrivateProfileInt GetPrivateProfileIntA +#define GetPrivateProfileString GetPrivateProfileStringA +#define WritePrivateProfileString WritePrivateProfileStringA +#define GetPrivateProfileSection GetPrivateProfileSectionA +#define WritePrivateProfileSection WritePrivateProfileSectionA +#define GetPrivateProfileSectionNames GetPrivateProfileSectionNamesA +#define GetPrivateProfileStruct GetPrivateProfileStructA +#define WritePrivateProfileStruct WritePrivateProfileStructA +#define GetDriveType GetDriveTypeA +#define GetSystemDirectory GetSystemDirectoryA +#define GetTempPath GetTempPathA +#define GetTempFileName GetTempFileNameA +#define GetWindowsDirectory GetWindowsDirectoryA +#define GetSystemWindowsDirectory GetSystemWindowsDirectoryA +#define AddLocalAlternateComputerName AddLocalAlternateComputerNameA +#endif + + typedef WINBOOL (CALLBACK *ENUMRESTYPEPROCA)(HMODULE hModule,LPSTR lpType,LONG_PTR lParam); + typedef WINBOOL (CALLBACK *ENUMRESTYPEPROCW)(HMODULE hModule,LPWSTR lpType,LONG_PTR lParam); + typedef WINBOOL (CALLBACK *ENUMRESNAMEPROCA)(HMODULE hModule,LPCSTR lpType,LPSTR lpName,LONG_PTR lParam); + typedef WINBOOL (CALLBACK *ENUMRESNAMEPROCW)(HMODULE hModule,LPCWSTR lpType,LPWSTR lpName,LONG_PTR lParam); + typedef WINBOOL (CALLBACK *ENUMRESLANGPROCA)(HMODULE hModule,LPCSTR lpType,LPCSTR lpName,WORD wLanguage,LONG_PTR lParam); + typedef WINBOOL (CALLBACK *ENUMRESLANGPROCW)(HMODULE hModule,LPCWSTR lpType,LPCWSTR lpName,WORD wLanguage,LONG_PTR lParam); + + WINBASEAPI WINBOOL WINAPI EnumResourceTypesA(HMODULE hModule,ENUMRESTYPEPROCA lpEnumFunc,LONG_PTR lParam); + WINBASEAPI WINBOOL WINAPI EnumResourceTypesW(HMODULE hModule,ENUMRESTYPEPROCW lpEnumFunc,LONG_PTR lParam); + WINBASEAPI WINBOOL WINAPI EnumResourceNamesA(HMODULE hModule,LPCSTR lpType,ENUMRESNAMEPROCA lpEnumFunc,LONG_PTR lParam); + WINBASEAPI WINBOOL WINAPI EnumResourceNamesW(HMODULE hModule,LPCWSTR lpType,ENUMRESNAMEPROCW lpEnumFunc,LONG_PTR lParam); + WINBASEAPI WINBOOL WINAPI EnumResourceLanguagesA(HMODULE hModule,LPCSTR lpType,LPCSTR lpName,ENUMRESLANGPROCA lpEnumFunc,LONG_PTR lParam); + WINBASEAPI WINBOOL WINAPI EnumResourceLanguagesW(HMODULE hModule,LPCWSTR lpType,LPCWSTR lpName,ENUMRESLANGPROCW lpEnumFunc,LONG_PTR lParam); + WINBASEAPI HANDLE WINAPI BeginUpdateResourceA(LPCSTR pFileName,WINBOOL bDeleteExistingResources); + WINBASEAPI HANDLE WINAPI BeginUpdateResourceW(LPCWSTR pFileName,WINBOOL bDeleteExistingResources); + WINBASEAPI WINBOOL WINAPI UpdateResourceA(HANDLE hUpdate,LPCSTR lpType,LPCSTR lpName,WORD wLanguage,LPVOID lpData,DWORD cb); + WINBASEAPI WINBOOL WINAPI UpdateResourceW(HANDLE hUpdate,LPCWSTR lpType,LPCWSTR lpName,WORD wLanguage,LPVOID lpData,DWORD cb); + WINBASEAPI WINBOOL WINAPI EndUpdateResourceA(HANDLE hUpdate,WINBOOL fDiscard); + WINBASEAPI WINBOOL WINAPI EndUpdateResourceW(HANDLE hUpdate,WINBOOL fDiscard); + WINBASEAPI ATOM WINAPI GlobalAddAtomA(LPCSTR lpString); + WINBASEAPI ATOM WINAPI GlobalAddAtomW(LPCWSTR lpString); + WINBASEAPI ATOM WINAPI GlobalFindAtomA(LPCSTR lpString); + WINBASEAPI ATOM WINAPI GlobalFindAtomW(LPCWSTR lpString); + WINBASEAPI UINT WINAPI GlobalGetAtomNameA(ATOM nAtom,LPSTR lpBuffer,int nSize); + WINBASEAPI UINT WINAPI GlobalGetAtomNameW(ATOM nAtom,LPWSTR lpBuffer,int nSize); + WINBASEAPI ATOM WINAPI AddAtomA(LPCSTR lpString); + WINBASEAPI ATOM WINAPI AddAtomW(LPCWSTR lpString); + WINBASEAPI ATOM WINAPI FindAtomA(LPCSTR lpString); + WINBASEAPI ATOM WINAPI FindAtomW(LPCWSTR lpString); + WINBASEAPI UINT WINAPI GetAtomNameA(ATOM nAtom,LPSTR lpBuffer,int nSize); + WINBASEAPI UINT WINAPI GetAtomNameW(ATOM nAtom,LPWSTR lpBuffer,int nSize); + WINBASEAPI UINT WINAPI GetProfileIntA(LPCSTR lpAppName,LPCSTR lpKeyName,INT nDefault); + WINBASEAPI UINT WINAPI GetProfileIntW(LPCWSTR lpAppName,LPCWSTR lpKeyName,INT nDefault); + WINBASEAPI DWORD WINAPI GetProfileStringA(LPCSTR lpAppName,LPCSTR lpKeyName,LPCSTR lpDefault,LPSTR lpReturnedString,DWORD nSize); + WINBASEAPI DWORD WINAPI GetProfileStringW(LPCWSTR lpAppName,LPCWSTR lpKeyName,LPCWSTR lpDefault,LPWSTR lpReturnedString,DWORD nSize); + WINBASEAPI WINBOOL WINAPI WriteProfileStringA(LPCSTR lpAppName,LPCSTR lpKeyName,LPCSTR lpString); + WINBASEAPI WINBOOL WINAPI WriteProfileStringW(LPCWSTR lpAppName,LPCWSTR lpKeyName,LPCWSTR lpString); + WINBASEAPI DWORD WINAPI GetProfileSectionA(LPCSTR lpAppName,LPSTR lpReturnedString,DWORD nSize); + WINBASEAPI DWORD WINAPI GetProfileSectionW(LPCWSTR lpAppName,LPWSTR lpReturnedString,DWORD nSize); + WINBASEAPI WINBOOL WINAPI WriteProfileSectionA(LPCSTR lpAppName,LPCSTR lpString); + WINBASEAPI WINBOOL WINAPI WriteProfileSectionW(LPCWSTR lpAppName,LPCWSTR lpString); + WINBASEAPI UINT WINAPI GetPrivateProfileIntA(LPCSTR lpAppName,LPCSTR lpKeyName,INT nDefault,LPCSTR lpFileName); + WINBASEAPI UINT WINAPI GetPrivateProfileIntW(LPCWSTR lpAppName,LPCWSTR lpKeyName,INT nDefault,LPCWSTR lpFileName); + WINBASEAPI DWORD WINAPI GetPrivateProfileStringA(LPCSTR lpAppName,LPCSTR lpKeyName,LPCSTR lpDefault,LPSTR lpReturnedString,DWORD nSize,LPCSTR lpFileName); + WINBASEAPI DWORD WINAPI GetPrivateProfileStringW(LPCWSTR lpAppName,LPCWSTR lpKeyName,LPCWSTR lpDefault,LPWSTR lpReturnedString,DWORD nSize,LPCWSTR lpFileName); + WINBASEAPI WINBOOL WINAPI WritePrivateProfileStringA(LPCSTR lpAppName,LPCSTR lpKeyName,LPCSTR lpString,LPCSTR lpFileName); + WINBASEAPI WINBOOL WINAPI WritePrivateProfileStringW(LPCWSTR lpAppName,LPCWSTR lpKeyName,LPCWSTR lpString,LPCWSTR lpFileName); + WINBASEAPI DWORD WINAPI GetPrivateProfileSectionA(LPCSTR lpAppName,LPSTR lpReturnedString,DWORD nSize,LPCSTR lpFileName); + WINBASEAPI DWORD WINAPI GetPrivateProfileSectionW(LPCWSTR lpAppName,LPWSTR lpReturnedString,DWORD nSize,LPCWSTR lpFileName); + WINBASEAPI WINBOOL WINAPI WritePrivateProfileSectionA(LPCSTR lpAppName,LPCSTR lpString,LPCSTR lpFileName); + WINBASEAPI WINBOOL WINAPI WritePrivateProfileSectionW(LPCWSTR lpAppName,LPCWSTR lpString,LPCWSTR lpFileName); + WINBASEAPI DWORD WINAPI GetPrivateProfileSectionNamesA(LPSTR lpszReturnBuffer,DWORD nSize,LPCSTR lpFileName); + WINBASEAPI DWORD WINAPI GetPrivateProfileSectionNamesW(LPWSTR lpszReturnBuffer,DWORD nSize,LPCWSTR lpFileName); + WINBASEAPI WINBOOL WINAPI GetPrivateProfileStructA(LPCSTR lpszSection,LPCSTR lpszKey,LPVOID lpStruct,UINT uSizeStruct,LPCSTR szFile); + WINBASEAPI WINBOOL WINAPI GetPrivateProfileStructW(LPCWSTR lpszSection,LPCWSTR lpszKey,LPVOID lpStruct,UINT uSizeStruct,LPCWSTR szFile); + WINBASEAPI WINBOOL WINAPI WritePrivateProfileStructA(LPCSTR lpszSection,LPCSTR lpszKey,LPVOID lpStruct,UINT uSizeStruct,LPCSTR szFile); + WINBASEAPI WINBOOL WINAPI WritePrivateProfileStructW(LPCWSTR lpszSection,LPCWSTR lpszKey,LPVOID lpStruct,UINT uSizeStruct,LPCWSTR szFile); + WINBASEAPI UINT WINAPI GetDriveTypeA(LPCSTR lpRootPathName); + WINBASEAPI UINT WINAPI GetDriveTypeW(LPCWSTR lpRootPathName); + WINBASEAPI UINT WINAPI GetSystemDirectoryA(LPSTR lpBuffer,UINT uSize); + WINBASEAPI UINT WINAPI GetSystemDirectoryW(LPWSTR lpBuffer,UINT uSize); + WINBASEAPI DWORD WINAPI GetTempPathA(DWORD nBufferLength,LPSTR lpBuffer); + WINBASEAPI DWORD WINAPI GetTempPathW(DWORD nBufferLength,LPWSTR lpBuffer); + WINBASEAPI UINT WINAPI GetTempFileNameA(LPCSTR lpPathName,LPCSTR lpPrefixString,UINT uUnique,LPSTR lpTempFileName); + WINBASEAPI UINT WINAPI GetTempFileNameW(LPCWSTR lpPathName,LPCWSTR lpPrefixString,UINT uUnique,LPWSTR lpTempFileName); + WINBASEAPI UINT WINAPI GetWindowsDirectoryA(LPSTR lpBuffer,UINT uSize); + WINBASEAPI UINT WINAPI GetWindowsDirectoryW(LPWSTR lpBuffer,UINT uSize); + WINBASEAPI UINT WINAPI GetSystemWindowsDirectoryA(LPSTR lpBuffer,UINT uSize); + WINBASEAPI UINT WINAPI GetSystemWindowsDirectoryW(LPWSTR lpBuffer,UINT uSize); + +#ifndef RC_INVOKED +#ifdef UNICODE +#define GetSystemWow64Directory GetSystemWow64DirectoryW +#else +#define GetSystemWow64Directory GetSystemWow64DirectoryA +#endif + + WINBASEAPI UINT WINAPI GetSystemWow64DirectoryA(LPSTR lpBuffer,UINT uSize); + WINBASEAPI UINT WINAPI GetSystemWow64DirectoryW(LPWSTR lpBuffer,UINT uSize); + WINBASEAPI BOOLEAN WINAPI Wow64EnableWow64FsRedirection(BOOLEAN Wow64FsEnableRedirection); + WINBASEAPI WINBOOL WINAPI Wow64DisableWow64FsRedirection(PVOID *OldValue); + WINBASEAPI WINBOOL WINAPI Wow64RevertWow64FsRedirection(PVOID OlValue); + + typedef UINT (WINAPI *PGET_SYSTEM_WOW64_DIRECTORY_A)(LPSTR lpBuffer,UINT uSize); + typedef UINT (WINAPI *PGET_SYSTEM_WOW64_DIRECTORY_W)(LPWSTR lpBuffer,UINT uSize); + +#define GET_SYSTEM_WOW64_DIRECTORY_NAME_A_A "GetSystemWow64DirectoryA" +#define GET_SYSTEM_WOW64_DIRECTORY_NAME_A_W L"GetSystemWow64DirectoryA" +#define GET_SYSTEM_WOW64_DIRECTORY_NAME_A_T TEXT("GetSystemWow64DirectoryA") +#define GET_SYSTEM_WOW64_DIRECTORY_NAME_W_A "GetSystemWow64DirectoryW" +#define GET_SYSTEM_WOW64_DIRECTORY_NAME_W_W L"GetSystemWow64DirectoryW" +#define GET_SYSTEM_WOW64_DIRECTORY_NAME_W_T TEXT("GetSystemWow64DirectoryW") + +#ifdef UNICODE +#define GET_SYSTEM_WOW64_DIRECTORY_NAME_T_A GET_SYSTEM_WOW64_DIRECTORY_NAME_W_A +#define GET_SYSTEM_WOW64_DIRECTORY_NAME_T_W GET_SYSTEM_WOW64_DIRECTORY_NAME_W_W +#define GET_SYSTEM_WOW64_DIRECTORY_NAME_T_T GET_SYSTEM_WOW64_DIRECTORY_NAME_W_T +#else +#define GET_SYSTEM_WOW64_DIRECTORY_NAME_T_A GET_SYSTEM_WOW64_DIRECTORY_NAME_A_A +#define GET_SYSTEM_WOW64_DIRECTORY_NAME_T_W GET_SYSTEM_WOW64_DIRECTORY_NAME_A_W +#define GET_SYSTEM_WOW64_DIRECTORY_NAME_T_T GET_SYSTEM_WOW64_DIRECTORY_NAME_A_T +#endif +#endif + +#ifdef UNICODE +#define SetCurrentDirectory SetCurrentDirectoryW +#define GetCurrentDirectory GetCurrentDirectoryW +#define SetDllDirectory SetDllDirectoryW +#define GetDllDirectory GetDllDirectoryW +#define GetDiskFreeSpace GetDiskFreeSpaceW +#define GetDiskFreeSpaceEx GetDiskFreeSpaceExW +#define CreateDirectory CreateDirectoryW +#define CreateDirectoryEx CreateDirectoryExW +#define RemoveDirectory RemoveDirectoryW +#define GetFullPathName GetFullPathNameW +#define DefineDosDevice DefineDosDeviceW +#define QueryDosDevice QueryDosDeviceW +#define CreateFile CreateFileW +#define SetFileAttributes SetFileAttributesW +#define GetFileAttributes GetFileAttributesW +#else +#define SetCurrentDirectory SetCurrentDirectoryA +#define GetCurrentDirectory GetCurrentDirectoryA +#define SetDllDirectory SetDllDirectoryA +#define GetDllDirectory GetDllDirectoryA +#define GetDiskFreeSpace GetDiskFreeSpaceA +#define GetDiskFreeSpaceEx GetDiskFreeSpaceExA +#define CreateDirectory CreateDirectoryA +#define CreateDirectoryEx CreateDirectoryExA +#define RemoveDirectory RemoveDirectoryA +#define GetFullPathName GetFullPathNameA +#define DefineDosDevice DefineDosDeviceA +#define QueryDosDevice QueryDosDeviceA +#define CreateFile CreateFileA +#define SetFileAttributes SetFileAttributesA +#define GetFileAttributes GetFileAttributesA +#endif + + WINBASEAPI WINBOOL WINAPI SetCurrentDirectoryA(LPCSTR lpPathName); + WINBASEAPI WINBOOL WINAPI SetCurrentDirectoryW(LPCWSTR lpPathName); + WINBASEAPI DWORD WINAPI GetCurrentDirectoryA(DWORD nBufferLength,LPSTR lpBuffer); + WINBASEAPI DWORD WINAPI GetCurrentDirectoryW(DWORD nBufferLength,LPWSTR lpBuffer); + WINBASEAPI WINBOOL WINAPI SetDllDirectoryA(LPCSTR lpPathName); + WINBASEAPI WINBOOL WINAPI SetDllDirectoryW(LPCWSTR lpPathName); + WINBASEAPI DWORD WINAPI GetDllDirectoryA(DWORD nBufferLength,LPSTR lpBuffer); + WINBASEAPI DWORD WINAPI GetDllDirectoryW(DWORD nBufferLength,LPWSTR lpBuffer); + WINBASEAPI WINBOOL WINAPI GetDiskFreeSpaceA(LPCSTR lpRootPathName,LPDWORD lpSectorsPerCluster,LPDWORD lpBytesPerSector,LPDWORD lpNumberOfFreeClusters,LPDWORD lpTotalNumberOfClusters); + WINBASEAPI WINBOOL WINAPI GetDiskFreeSpaceW(LPCWSTR lpRootPathName,LPDWORD lpSectorsPerCluster,LPDWORD lpBytesPerSector,LPDWORD lpNumberOfFreeClusters,LPDWORD lpTotalNumberOfClusters); + WINBASEAPI WINBOOL WINAPI GetDiskFreeSpaceExA(LPCSTR lpDirectoryName,PULARGE_INTEGER lpFreeBytesAvailableToCaller,PULARGE_INTEGER lpTotalNumberOfBytes,PULARGE_INTEGER lpTotalNumberOfFreeBytes); + WINBASEAPI WINBOOL WINAPI GetDiskFreeSpaceExW(LPCWSTR lpDirectoryName,PULARGE_INTEGER lpFreeBytesAvailableToCaller,PULARGE_INTEGER lpTotalNumberOfBytes,PULARGE_INTEGER lpTotalNumberOfFreeBytes); + WINBASEAPI WINBOOL WINAPI CreateDirectoryA(LPCSTR lpPathName,LPSECURITY_ATTRIBUTES lpSecurityAttributes); + WINBASEAPI WINBOOL WINAPI CreateDirectoryW(LPCWSTR lpPathName,LPSECURITY_ATTRIBUTES lpSecurityAttributes); + WINBASEAPI WINBOOL WINAPI CreateDirectoryExA(LPCSTR lpTemplateDirectory,LPCSTR lpNewDirectory,LPSECURITY_ATTRIBUTES lpSecurityAttributes); + WINBASEAPI WINBOOL WINAPI CreateDirectoryExW(LPCWSTR lpTemplateDirectory,LPCWSTR lpNewDirectory,LPSECURITY_ATTRIBUTES lpSecurityAttributes); + WINBASEAPI WINBOOL WINAPI RemoveDirectoryA(LPCSTR lpPathName); + WINBASEAPI WINBOOL WINAPI RemoveDirectoryW(LPCWSTR lpPathName); + WINBASEAPI DWORD WINAPI GetFullPathNameA(LPCSTR lpFileName,DWORD nBufferLength,LPSTR lpBuffer,LPSTR *lpFilePart); + WINBASEAPI DWORD WINAPI GetFullPathNameW(LPCWSTR lpFileName,DWORD nBufferLength,LPWSTR lpBuffer,LPWSTR *lpFilePart); + +#define DDD_RAW_TARGET_PATH 0x1 +#define DDD_REMOVE_DEFINITION 0x2 +#define DDD_EXACT_MATCH_ON_REMOVE 0x4 +#define DDD_NO_BROADCAST_SYSTEM 0x8 +#define DDD_LUID_BROADCAST_DRIVE 0x10 + + WINBASEAPI WINBOOL WINAPI DefineDosDeviceA(DWORD dwFlags,LPCSTR lpDeviceName,LPCSTR lpTargetPath); + WINBASEAPI WINBOOL WINAPI DefineDosDeviceW(DWORD dwFlags,LPCWSTR lpDeviceName,LPCWSTR lpTargetPath); + WINBASEAPI DWORD WINAPI QueryDosDeviceA(LPCSTR lpDeviceName,LPSTR lpTargetPath,DWORD ucchMax); + WINBASEAPI DWORD WINAPI QueryDosDeviceW(LPCWSTR lpDeviceName,LPWSTR lpTargetPath,DWORD ucchMax); + +#define EXPAND_LOCAL_DRIVES + + WINBASEAPI HANDLE WINAPI CreateFileA(LPCSTR lpFileName,DWORD dwDesiredAccess,DWORD dwShareMode,LPSECURITY_ATTRIBUTES lpSecurityAttributes,DWORD dwCreationDisposition,DWORD dwFlagsAndAttributes,HANDLE hTemplateFile); + WINBASEAPI HANDLE WINAPI CreateFileW(LPCWSTR lpFileName,DWORD dwDesiredAccess,DWORD dwShareMode,LPSECURITY_ATTRIBUTES lpSecurityAttributes,DWORD dwCreationDisposition,DWORD dwFlagsAndAttributes,HANDLE hTemplateFile); + WINBASEAPI HANDLE WINAPI ReOpenFile(HANDLE hOriginalFile,DWORD dwDesiredAccess,DWORD dwShareMode,DWORD dwFlagsAndAttributes); + WINBASEAPI WINBOOL WINAPI SetFileAttributesA(LPCSTR lpFileName,DWORD dwFileAttributes); + WINBASEAPI WINBOOL WINAPI SetFileAttributesW(LPCWSTR lpFileName,DWORD dwFileAttributes); + WINBASEAPI DWORD WINAPI GetFileAttributesA(LPCSTR lpFileName); + WINBASEAPI DWORD WINAPI GetFileAttributesW(LPCWSTR lpFileName); + + typedef enum _GET_FILEEX_INFO_LEVELS { + GetFileExInfoStandard,GetFileExMaxInfoLevel + } GET_FILEEX_INFO_LEVELS; + +#ifdef UNICODE +#define GetFileAttributesEx GetFileAttributesExW +#define GetCompressedFileSize GetCompressedFileSizeW +#define DeleteFile DeleteFileW +#define CheckNameLegalDOS8Dot3 CheckNameLegalDOS8Dot3W +#else +#define GetFileAttributesEx GetFileAttributesExA +#define GetCompressedFileSize GetCompressedFileSizeA +#define DeleteFile DeleteFileA +#define CheckNameLegalDOS8Dot3 CheckNameLegalDOS8Dot3A +#endif + + WINBASEAPI WINBOOL WINAPI GetFileAttributesExA(LPCSTR lpFileName,GET_FILEEX_INFO_LEVELS fInfoLevelId,LPVOID lpFileInformation); + WINBASEAPI WINBOOL WINAPI GetFileAttributesExW(LPCWSTR lpFileName,GET_FILEEX_INFO_LEVELS fInfoLevelId,LPVOID lpFileInformation); + WINBASEAPI DWORD WINAPI GetCompressedFileSizeA(LPCSTR lpFileName,LPDWORD lpFileSizeHigh); + WINBASEAPI DWORD WINAPI GetCompressedFileSizeW(LPCWSTR lpFileName,LPDWORD lpFileSizeHigh); + WINBASEAPI WINBOOL WINAPI DeleteFileA(LPCSTR lpFileName); + WINBASEAPI WINBOOL WINAPI DeleteFileW(LPCWSTR lpFileName); + WINBASEAPI WINBOOL WINAPI CheckNameLegalDOS8Dot3A(LPCSTR lpName,LPSTR lpOemName,DWORD OemNameSize,PBOOL pbNameContainsSpaces,PBOOL pbNameLegal); + WINBASEAPI WINBOOL WINAPI CheckNameLegalDOS8Dot3W(LPCWSTR lpName,LPSTR lpOemName,DWORD OemNameSize,PBOOL pbNameContainsSpaces,PBOOL pbNameLegal); + + typedef enum _FINDEX_INFO_LEVELS { + FindExInfoStandard,FindExInfoMaxInfoLevel + } FINDEX_INFO_LEVELS; + + typedef enum _FINDEX_SEARCH_OPS { + FindExSearchNameMatch,FindExSearchLimitToDirectories,FindExSearchLimitToDevices,FindExSearchMaxSearchOp + } FINDEX_SEARCH_OPS; + +#define FIND_FIRST_EX_CASE_SENSITIVE 0x1 + +#ifdef UNICODE +#define FindFirstFileEx FindFirstFileExW +#define FindFirstFile FindFirstFileW +#define FindNextFile FindNextFileW +#define SearchPath SearchPathW +#define CopyFile CopyFileW +#define CopyFileEx CopyFileExW +#define MoveFile MoveFileW +#define MoveFileEx MoveFileExW +#define MoveFileWithProgress MoveFileWithProgressW +#define ReplaceFile ReplaceFileW +#define CreateHardLink CreateHardLinkW +#define CreateNamedPipe CreateNamedPipeW +#define GetNamedPipeHandleState GetNamedPipeHandleStateW +#define CallNamedPipe CallNamedPipeW +#define WaitNamedPipe WaitNamedPipeW +#define SetVolumeLabel SetVolumeLabelW +#define GetVolumeInformation GetVolumeInformationW +#define ClearEventLog ClearEventLogW +#define BackupEventLog BackupEventLogW +#define OpenEventLog OpenEventLogW +#define RegisterEventSource RegisterEventSourceW +#define OpenBackupEventLog OpenBackupEventLogW +#define ReadEventLog ReadEventLogW +#define ReportEvent ReportEventW +#define AccessCheckAndAuditAlarm AccessCheckAndAuditAlarmW +#define AccessCheckByTypeAndAuditAlarm AccessCheckByTypeAndAuditAlarmW +#define AccessCheckByTypeResultListAndAuditAlarm AccessCheckByTypeResultListAndAuditAlarmW +#define AccessCheckByTypeResultListAndAuditAlarmByHandle AccessCheckByTypeResultListAndAuditAlarmByHandleW +#define ObjectOpenAuditAlarm ObjectOpenAuditAlarmW +#define ObjectPrivilegeAuditAlarm ObjectPrivilegeAuditAlarmW +#define ObjectCloseAuditAlarm ObjectCloseAuditAlarmW +#define ObjectDeleteAuditAlarm ObjectDeleteAuditAlarmW +#define PrivilegedServiceAuditAlarm PrivilegedServiceAuditAlarmW +#define SetFileSecurity SetFileSecurityW +#define GetFileSecurity GetFileSecurityW +#define FindFirstChangeNotification FindFirstChangeNotificationW +#define IsBadStringPtr IsBadStringPtrW +#define LookupAccountSid LookupAccountSidW +#define LookupAccountName LookupAccountNameW +#define LookupPrivilegeValue LookupPrivilegeValueW +#define LookupPrivilegeName LookupPrivilegeNameW +#define LookupPrivilegeDisplayName LookupPrivilegeDisplayNameW +#define BuildCommDCB BuildCommDCBW +#define BuildCommDCBAndTimeouts BuildCommDCBAndTimeoutsW +#define CommConfigDialog CommConfigDialogW +#define GetDefaultCommConfig GetDefaultCommConfigW +#define SetDefaultCommConfig SetDefaultCommConfigW +#define GetComputerName GetComputerNameW +#define SetComputerName SetComputerNameW +#define GetComputerNameEx GetComputerNameExW +#define SetComputerNameEx SetComputerNameExW +#define DnsHostnameToComputerName DnsHostnameToComputerNameW +#define GetUserName GetUserNameW +#else +#define FindFirstFileEx FindFirstFileExA +#define FindFirstFile FindFirstFileA +#define FindNextFile FindNextFileA +#define SearchPath SearchPathA +#define CopyFile CopyFileA +#define CopyFileEx CopyFileExA +#define MoveFile MoveFileA +#define MoveFileEx MoveFileExA +#define MoveFileWithProgress MoveFileWithProgressA +#define ReplaceFile ReplaceFileA +#define CreateHardLink CreateHardLinkA +#define CreateNamedPipe CreateNamedPipeA +#define GetNamedPipeHandleState GetNamedPipeHandleStateA +#define CallNamedPipe CallNamedPipeA +#define WaitNamedPipe WaitNamedPipeA +#define SetVolumeLabel SetVolumeLabelA +#define GetVolumeInformation GetVolumeInformationA +#define ClearEventLog ClearEventLogA +#define BackupEventLog BackupEventLogA +#define OpenEventLog OpenEventLogA +#define RegisterEventSource RegisterEventSourceA +#define OpenBackupEventLog OpenBackupEventLogA +#define ReadEventLog ReadEventLogA +#define ReportEvent ReportEventA +#define AccessCheckAndAuditAlarm AccessCheckAndAuditAlarmA +#define AccessCheckByTypeAndAuditAlarm AccessCheckByTypeAndAuditAlarmA +#define AccessCheckByTypeResultListAndAuditAlarm AccessCheckByTypeResultListAndAuditAlarmA +#define AccessCheckByTypeResultListAndAuditAlarmByHandle AccessCheckByTypeResultListAndAuditAlarmByHandleA +#define ObjectOpenAuditAlarm ObjectOpenAuditAlarmA +#define ObjectPrivilegeAuditAlarm ObjectPrivilegeAuditAlarmA +#define ObjectCloseAuditAlarm ObjectCloseAuditAlarmA +#define ObjectDeleteAuditAlarm ObjectDeleteAuditAlarmA +#define PrivilegedServiceAuditAlarm PrivilegedServiceAuditAlarmA +#define SetFileSecurity SetFileSecurityA +#define GetFileSecurity GetFileSecurityA +#define FindFirstChangeNotification FindFirstChangeNotificationA +#define IsBadStringPtr IsBadStringPtrA +#define LookupAccountSid LookupAccountSidA +#define LookupAccountName LookupAccountNameA +#define LookupPrivilegeValue LookupPrivilegeValueA +#define LookupPrivilegeName LookupPrivilegeNameA +#define LookupPrivilegeDisplayName LookupPrivilegeDisplayNameA +#define BuildCommDCB BuildCommDCBA +#define BuildCommDCBAndTimeouts BuildCommDCBAndTimeoutsA +#define CommConfigDialog CommConfigDialogA +#define GetDefaultCommConfig GetDefaultCommConfigA +#define SetDefaultCommConfig SetDefaultCommConfigA +#define GetComputerName GetComputerNameA +#define SetComputerName SetComputerNameA +#define GetComputerNameEx GetComputerNameExA +#define SetComputerNameEx SetComputerNameExA +#define DnsHostnameToComputerName DnsHostnameToComputerNameA +#define GetUserName GetUserNameA +#endif + + WINBASEAPI HANDLE WINAPI FindFirstFileExA(LPCSTR lpFileName,FINDEX_INFO_LEVELS fInfoLevelId,LPVOID lpFindFileData,FINDEX_SEARCH_OPS fSearchOp,LPVOID lpSearchFilter,DWORD dwAdditionalFlags); + WINBASEAPI HANDLE WINAPI FindFirstFileExW(LPCWSTR lpFileName,FINDEX_INFO_LEVELS fInfoLevelId,LPVOID lpFindFileData,FINDEX_SEARCH_OPS fSearchOp,LPVOID lpSearchFilter,DWORD dwAdditionalFlags); + WINBASEAPI HANDLE WINAPI FindFirstFileA(LPCSTR lpFileName,LPWIN32_FIND_DATAA lpFindFileData); + WINBASEAPI HANDLE WINAPI FindFirstFileW(LPCWSTR lpFileName,LPWIN32_FIND_DATAW lpFindFileData); + WINBASEAPI WINBOOL WINAPI FindNextFileA(HANDLE hFindFile,LPWIN32_FIND_DATAA lpFindFileData); + WINBASEAPI WINBOOL WINAPI FindNextFileW(HANDLE hFindFile,LPWIN32_FIND_DATAW lpFindFileData); + WINBASEAPI DWORD WINAPI SearchPathA(LPCSTR lpPath,LPCSTR lpFileName,LPCSTR lpExtension,DWORD nBufferLength,LPSTR lpBuffer,LPSTR *lpFilePart); + WINBASEAPI DWORD WINAPI SearchPathW(LPCWSTR lpPath,LPCWSTR lpFileName,LPCWSTR lpExtension,DWORD nBufferLength,LPWSTR lpBuffer,LPWSTR *lpFilePart); + WINBASEAPI WINBOOL WINAPI CopyFileA(LPCSTR lpExistingFileName,LPCSTR lpNewFileName,WINBOOL bFailIfExists); + WINBASEAPI WINBOOL WINAPI CopyFileW(LPCWSTR lpExistingFileName,LPCWSTR lpNewFileName,WINBOOL bFailIfExists); + + typedef DWORD (WINAPI *LPPROGRESS_ROUTINE)(LARGE_INTEGER TotalFileSize,LARGE_INTEGER TotalBytesTransferred,LARGE_INTEGER StreamSize,LARGE_INTEGER StreamBytesTransferred,DWORD dwStreamNumber,DWORD dwCallbackReason,HANDLE hSourceFile,HANDLE hDestinationFile,LPVOID lpData); + + WINBASEAPI WINBOOL WINAPI CopyFileExA(LPCSTR lpExistingFileName,LPCSTR lpNewFileName,LPPROGRESS_ROUTINE lpProgressRoutine,LPVOID lpData,LPBOOL pbCancel,DWORD dwCopyFlags); + WINBASEAPI WINBOOL WINAPI CopyFileExW(LPCWSTR lpExistingFileName,LPCWSTR lpNewFileName,LPPROGRESS_ROUTINE lpProgressRoutine,LPVOID lpData,LPBOOL pbCancel,DWORD dwCopyFlags); + WINBASEAPI WINBOOL WINAPI MoveFileA(LPCSTR lpExistingFileName,LPCSTR lpNewFileName); + WINBASEAPI WINBOOL WINAPI MoveFileW(LPCWSTR lpExistingFileName,LPCWSTR lpNewFileName); + WINBASEAPI WINBOOL WINAPI MoveFileExA(LPCSTR lpExistingFileName,LPCSTR lpNewFileName,DWORD dwFlags); + WINBASEAPI WINBOOL WINAPI MoveFileExW(LPCWSTR lpExistingFileName,LPCWSTR lpNewFileName,DWORD dwFlags); + WINBASEAPI WINBOOL WINAPI MoveFileWithProgressA(LPCSTR lpExistingFileName,LPCSTR lpNewFileName,LPPROGRESS_ROUTINE lpProgressRoutine,LPVOID lpData,DWORD dwFlags); + WINBASEAPI WINBOOL WINAPI MoveFileWithProgressW(LPCWSTR lpExistingFileName,LPCWSTR lpNewFileName,LPPROGRESS_ROUTINE lpProgressRoutine,LPVOID lpData,DWORD dwFlags); + +#define MOVEFILE_REPLACE_EXISTING 0x1 +#define MOVEFILE_COPY_ALLOWED 0x2 +#define MOVEFILE_DELAY_UNTIL_REBOOT 0x4 +#define MOVEFILE_WRITE_THROUGH 0x8 +#define MOVEFILE_CREATE_HARDLINK 0x10 +#define MOVEFILE_FAIL_IF_NOT_TRACKABLE 0x20 + + WINBASEAPI WINBOOL WINAPI ReplaceFileA(LPCSTR lpReplacedFileName,LPCSTR lpReplacementFileName,LPCSTR lpBackupFileName,DWORD dwReplaceFlags,LPVOID lpExclude,LPVOID lpReserved); + WINBASEAPI WINBOOL WINAPI ReplaceFileW(LPCWSTR lpReplacedFileName,LPCWSTR lpReplacementFileName,LPCWSTR lpBackupFileName,DWORD dwReplaceFlags,LPVOID lpExclude,LPVOID lpReserved); + WINBASEAPI WINBOOL WINAPI CreateHardLinkA(LPCSTR lpFileName,LPCSTR lpExistingFileName,LPSECURITY_ATTRIBUTES lpSecurityAttributes); + WINBASEAPI WINBOOL WINAPI CreateHardLinkW(LPCWSTR lpFileName,LPCWSTR lpExistingFileName,LPSECURITY_ATTRIBUTES lpSecurityAttributes); + + typedef enum _STREAM_INFO_LEVELS { + FindStreamInfoStandard,FindStreamInfoMaxInfoLevel + } STREAM_INFO_LEVELS; + + typedef struct _WIN32_FIND_STREAM_DATA { + LARGE_INTEGER StreamSize; + WCHAR cStreamName[MAX_PATH + 36]; + } WIN32_FIND_STREAM_DATA,*PWIN32_FIND_STREAM_DATA; + + HANDLE WINAPI FindFirstStreamW(LPCWSTR lpFileName,STREAM_INFO_LEVELS InfoLevel,LPVOID lpFindStreamData,DWORD dwFlags); + WINBOOL WINAPI FindNextStreamW(HANDLE hFindStream,LPVOID lpFindStreamData); + WINBASEAPI HANDLE WINAPI CreateNamedPipeA(LPCSTR lpName,DWORD dwOpenMode,DWORD dwPipeMode,DWORD nMaxInstances,DWORD nOutBufferSize,DWORD nInBufferSize,DWORD nDefaultTimeOut,LPSECURITY_ATTRIBUTES lpSecurityAttributes); + WINBASEAPI HANDLE WINAPI CreateNamedPipeW(LPCWSTR lpName,DWORD dwOpenMode,DWORD dwPipeMode,DWORD nMaxInstances,DWORD nOutBufferSize,DWORD nInBufferSize,DWORD nDefaultTimeOut,LPSECURITY_ATTRIBUTES lpSecurityAttributes); + WINBASEAPI WINBOOL WINAPI GetNamedPipeHandleStateA(HANDLE hNamedPipe,LPDWORD lpState,LPDWORD lpCurInstances,LPDWORD lpMaxCollectionCount,LPDWORD lpCollectDataTimeout,LPSTR lpUserName,DWORD nMaxUserNameSize); + WINBASEAPI WINBOOL WINAPI GetNamedPipeHandleStateW(HANDLE hNamedPipe,LPDWORD lpState,LPDWORD lpCurInstances,LPDWORD lpMaxCollectionCount,LPDWORD lpCollectDataTimeout,LPWSTR lpUserName,DWORD nMaxUserNameSize); + WINBASEAPI WINBOOL WINAPI CallNamedPipeA(LPCSTR lpNamedPipeName,LPVOID lpInBuffer,DWORD nInBufferSize,LPVOID lpOutBuffer,DWORD nOutBufferSize,LPDWORD lpBytesRead,DWORD nTimeOut); + WINBASEAPI WINBOOL WINAPI CallNamedPipeW(LPCWSTR lpNamedPipeName,LPVOID lpInBuffer,DWORD nInBufferSize,LPVOID lpOutBuffer,DWORD nOutBufferSize,LPDWORD lpBytesRead,DWORD nTimeOut); + WINBASEAPI WINBOOL WINAPI WaitNamedPipeA(LPCSTR lpNamedPipeName,DWORD nTimeOut); + WINBASEAPI WINBOOL WINAPI WaitNamedPipeW(LPCWSTR lpNamedPipeName,DWORD nTimeOut); + WINBASEAPI WINBOOL WINAPI SetVolumeLabelA(LPCSTR lpRootPathName,LPCSTR lpVolumeName); + WINBASEAPI WINBOOL WINAPI SetVolumeLabelW(LPCWSTR lpRootPathName,LPCWSTR lpVolumeName); + WINBASEAPI VOID WINAPI SetFileApisToOEM(VOID); + WINBASEAPI VOID WINAPI SetFileApisToANSI(VOID); + WINBASEAPI WINBOOL WINAPI AreFileApisANSI(VOID); + WINBASEAPI WINBOOL WINAPI GetVolumeInformationA(LPCSTR lpRootPathName,LPSTR lpVolumeNameBuffer,DWORD nVolumeNameSize,LPDWORD lpVolumeSerialNumber,LPDWORD lpMaximumComponentLength,LPDWORD lpFileSystemFlags,LPSTR lpFileSystemNameBuffer,DWORD nFileSystemNameSize); + WINBASEAPI WINBOOL WINAPI GetVolumeInformationW(LPCWSTR lpRootPathName,LPWSTR lpVolumeNameBuffer,DWORD nVolumeNameSize,LPDWORD lpVolumeSerialNumber,LPDWORD lpMaximumComponentLength,LPDWORD lpFileSystemFlags,LPWSTR lpFileSystemNameBuffer,DWORD nFileSystemNameSize); + WINBASEAPI WINBOOL WINAPI CancelIo(HANDLE hFile); + WINADVAPI WINBOOL WINAPI ClearEventLogA(HANDLE hEventLog,LPCSTR lpBackupFileName); + WINADVAPI WINBOOL WINAPI ClearEventLogW(HANDLE hEventLog,LPCWSTR lpBackupFileName); + WINADVAPI WINBOOL WINAPI BackupEventLogA(HANDLE hEventLog,LPCSTR lpBackupFileName); + WINADVAPI WINBOOL WINAPI BackupEventLogW(HANDLE hEventLog,LPCWSTR lpBackupFileName); + WINADVAPI WINBOOL WINAPI CloseEventLog(HANDLE hEventLog); + WINADVAPI WINBOOL WINAPI DeregisterEventSource(HANDLE hEventLog); + WINADVAPI WINBOOL WINAPI NotifyChangeEventLog(HANDLE hEventLog,HANDLE hEvent); + WINADVAPI WINBOOL WINAPI GetNumberOfEventLogRecords(HANDLE hEventLog,PDWORD NumberOfRecords); + WINADVAPI WINBOOL WINAPI GetOldestEventLogRecord(HANDLE hEventLog,PDWORD OldestRecord); + WINADVAPI HANDLE WINAPI OpenEventLogA(LPCSTR lpUNCServerName,LPCSTR lpSourceName); + WINADVAPI HANDLE WINAPI OpenEventLogW(LPCWSTR lpUNCServerName,LPCWSTR lpSourceName); + WINADVAPI HANDLE WINAPI RegisterEventSourceA(LPCSTR lpUNCServerName,LPCSTR lpSourceName); + WINADVAPI HANDLE WINAPI RegisterEventSourceW(LPCWSTR lpUNCServerName,LPCWSTR lpSourceName); + WINADVAPI HANDLE WINAPI OpenBackupEventLogA(LPCSTR lpUNCServerName,LPCSTR lpFileName); + WINADVAPI HANDLE WINAPI OpenBackupEventLogW(LPCWSTR lpUNCServerName,LPCWSTR lpFileName); + WINADVAPI WINBOOL WINAPI ReadEventLogA(HANDLE hEventLog,DWORD dwReadFlags,DWORD dwRecordOffset,LPVOID lpBuffer,DWORD nNumberOfBytesToRead,DWORD *pnBytesRead,DWORD *pnMinNumberOfBytesNeeded); + WINADVAPI WINBOOL WINAPI ReadEventLogW(HANDLE hEventLog,DWORD dwReadFlags,DWORD dwRecordOffset,LPVOID lpBuffer,DWORD nNumberOfBytesToRead,DWORD *pnBytesRead,DWORD *pnMinNumberOfBytesNeeded); + WINADVAPI WINBOOL WINAPI ReportEventA(HANDLE hEventLog,WORD wType,WORD wCategory,DWORD dwEventID,PSID lpUserSid,WORD wNumStrings,DWORD dwDataSize,LPCSTR *lpStrings,LPVOID lpRawData); + WINADVAPI WINBOOL WINAPI ReportEventW(HANDLE hEventLog,WORD wType,WORD wCategory,DWORD dwEventID,PSID lpUserSid,WORD wNumStrings,DWORD dwDataSize,LPCWSTR *lpStrings,LPVOID lpRawData); + +#define EVENTLOG_FULL_INFO 0 + + typedef struct _EVENTLOG_FULL_INFORMATION { + DWORD dwFull; + } EVENTLOG_FULL_INFORMATION,*LPEVENTLOG_FULL_INFORMATION; + + WINADVAPI WINBOOL WINAPI GetEventLogInformation(HANDLE hEventLog,DWORD dwInfoLevel,LPVOID lpBuffer,DWORD cbBufSize,LPDWORD pcbBytesNeeded); + WINADVAPI WINBOOL WINAPI DuplicateToken(HANDLE ExistingTokenHandle,SECURITY_IMPERSONATION_LEVEL ImpersonationLevel,PHANDLE DuplicateTokenHandle); + WINADVAPI WINBOOL WINAPI GetKernelObjectSecurity(HANDLE Handle,SECURITY_INFORMATION RequestedInformation,PSECURITY_DESCRIPTOR pSecurityDescriptor,DWORD nLength,LPDWORD lpnLengthNeeded); + WINADVAPI WINBOOL WINAPI ImpersonateNamedPipeClient(HANDLE hNamedPipe); + WINADVAPI WINBOOL WINAPI ImpersonateSelf(SECURITY_IMPERSONATION_LEVEL ImpersonationLevel); + WINADVAPI WINBOOL WINAPI RevertToSelf(VOID); + WINADVAPI WINBOOL WINAPI SetThreadToken (PHANDLE Thread,HANDLE Token); + WINADVAPI WINBOOL WINAPI AccessCheck(PSECURITY_DESCRIPTOR pSecurityDescriptor,HANDLE ClientToken,DWORD DesiredAccess,PGENERIC_MAPPING GenericMapping,PPRIVILEGE_SET PrivilegeSet,LPDWORD PrivilegeSetLength,LPDWORD GrantedAccess,LPBOOL AccessStatus); + WINADVAPI WINBOOL WINAPI AccessCheckByType(PSECURITY_DESCRIPTOR pSecurityDescriptor,PSID PrincipalSelfSid,HANDLE ClientToken,DWORD DesiredAccess,POBJECT_TYPE_LIST ObjectTypeList,DWORD ObjectTypeListLength,PGENERIC_MAPPING GenericMapping,PPRIVILEGE_SET PrivilegeSet,LPDWORD PrivilegeSetLength,LPDWORD GrantedAccess,LPBOOL AccessStatus); + WINADVAPI WINBOOL WINAPI AccessCheckByTypeResultList(PSECURITY_DESCRIPTOR pSecurityDescriptor,PSID PrincipalSelfSid,HANDLE ClientToken,DWORD DesiredAccess,POBJECT_TYPE_LIST ObjectTypeList,DWORD ObjectTypeListLength,PGENERIC_MAPPING GenericMapping,PPRIVILEGE_SET PrivilegeSet,LPDWORD PrivilegeSetLength,LPDWORD GrantedAccessList,LPDWORD AccessStatusList); + WINADVAPI WINBOOL WINAPI OpenProcessToken(HANDLE ProcessHandle,DWORD DesiredAccess,PHANDLE TokenHandle); + WINADVAPI WINBOOL WINAPI OpenThreadToken(HANDLE ThreadHandle,DWORD DesiredAccess,WINBOOL OpenAsSelf,PHANDLE TokenHandle); + WINADVAPI WINBOOL WINAPI GetTokenInformation(HANDLE TokenHandle,TOKEN_INFORMATION_CLASS TokenInformationClass,LPVOID TokenInformation,DWORD TokenInformationLength,PDWORD ReturnLength); + WINADVAPI WINBOOL WINAPI SetTokenInformation(HANDLE TokenHandle,TOKEN_INFORMATION_CLASS TokenInformationClass,LPVOID TokenInformation,DWORD TokenInformationLength); + WINADVAPI WINBOOL WINAPI AdjustTokenPrivileges(HANDLE TokenHandle,WINBOOL DisableAllPrivileges,PTOKEN_PRIVILEGES NewState,DWORD BufferLength,PTOKEN_PRIVILEGES PreviousState,PDWORD ReturnLength); + WINADVAPI WINBOOL WINAPI AdjustTokenGroups(HANDLE TokenHandle,WINBOOL ResetToDefault,PTOKEN_GROUPS NewState,DWORD BufferLength,PTOKEN_GROUPS PreviousState,PDWORD ReturnLength); + WINADVAPI WINBOOL WINAPI PrivilegeCheck(HANDLE ClientToken,PPRIVILEGE_SET RequiredPrivileges,LPBOOL pfResult); + WINADVAPI WINBOOL WINAPI AccessCheckAndAuditAlarmA(LPCSTR SubsystemName,LPVOID HandleId,LPSTR ObjectTypeName,LPSTR ObjectName,PSECURITY_DESCRIPTOR SecurityDescriptor,DWORD DesiredAccess,PGENERIC_MAPPING GenericMapping,WINBOOL ObjectCreation,LPDWORD GrantedAccess,LPBOOL AccessStatus,LPBOOL pfGenerateOnClose); + WINADVAPI WINBOOL WINAPI AccessCheckAndAuditAlarmW(LPCWSTR SubsystemName,LPVOID HandleId,LPWSTR ObjectTypeName,LPWSTR ObjectName,PSECURITY_DESCRIPTOR SecurityDescriptor,DWORD DesiredAccess,PGENERIC_MAPPING GenericMapping,WINBOOL ObjectCreation,LPDWORD GrantedAccess,LPBOOL AccessStatus,LPBOOL pfGenerateOnClose); + WINADVAPI WINBOOL WINAPI AccessCheckByTypeAndAuditAlarmA(LPCSTR SubsystemName,LPVOID HandleId,LPCSTR ObjectTypeName,LPCSTR ObjectName,PSECURITY_DESCRIPTOR SecurityDescriptor,PSID PrincipalSelfSid,DWORD DesiredAccess,AUDIT_EVENT_TYPE AuditType,DWORD Flags,POBJECT_TYPE_LIST ObjectTypeList,DWORD ObjectTypeListLength,PGENERIC_MAPPING GenericMapping,WINBOOL ObjectCreation,LPDWORD GrantedAccess,LPBOOL AccessStatus,LPBOOL pfGenerateOnClose); + WINADVAPI WINBOOL WINAPI AccessCheckByTypeAndAuditAlarmW(LPCWSTR SubsystemName,LPVOID HandleId,LPCWSTR ObjectTypeName,LPCWSTR ObjectName,PSECURITY_DESCRIPTOR SecurityDescriptor,PSID PrincipalSelfSid,DWORD DesiredAccess,AUDIT_EVENT_TYPE AuditType,DWORD Flags,POBJECT_TYPE_LIST ObjectTypeList,DWORD ObjectTypeListLength,PGENERIC_MAPPING GenericMapping,WINBOOL ObjectCreation,LPDWORD GrantedAccess,LPBOOL AccessStatus,LPBOOL pfGenerateOnClose); + WINADVAPI WINBOOL WINAPI AccessCheckByTypeResultListAndAuditAlarmA(LPCSTR SubsystemName,LPVOID HandleId,LPCSTR ObjectTypeName,LPCSTR ObjectName,PSECURITY_DESCRIPTOR SecurityDescriptor,PSID PrincipalSelfSid,DWORD DesiredAccess,AUDIT_EVENT_TYPE AuditType,DWORD Flags,POBJECT_TYPE_LIST ObjectTypeList,DWORD ObjectTypeListLength,PGENERIC_MAPPING GenericMapping,WINBOOL ObjectCreation,LPDWORD GrantedAccess,LPDWORD AccessStatusList,LPBOOL pfGenerateOnClose); + WINADVAPI WINBOOL WINAPI AccessCheckByTypeResultListAndAuditAlarmW(LPCWSTR SubsystemName,LPVOID HandleId,LPCWSTR ObjectTypeName,LPCWSTR ObjectName,PSECURITY_DESCRIPTOR SecurityDescriptor,PSID PrincipalSelfSid,DWORD DesiredAccess,AUDIT_EVENT_TYPE AuditType,DWORD Flags,POBJECT_TYPE_LIST ObjectTypeList,DWORD ObjectTypeListLength,PGENERIC_MAPPING GenericMapping,WINBOOL ObjectCreation,LPDWORD GrantedAccess,LPDWORD AccessStatusList,LPBOOL pfGenerateOnClose); + WINADVAPI WINBOOL WINAPI AccessCheckByTypeResultListAndAuditAlarmByHandleA(LPCSTR SubsystemName,LPVOID HandleId,HANDLE ClientToken,LPCSTR ObjectTypeName,LPCSTR ObjectName,PSECURITY_DESCRIPTOR SecurityDescriptor,PSID PrincipalSelfSid,DWORD DesiredAccess,AUDIT_EVENT_TYPE AuditType,DWORD Flags,POBJECT_TYPE_LIST ObjectTypeList,DWORD ObjectTypeListLength,PGENERIC_MAPPING GenericMapping,WINBOOL ObjectCreation,LPDWORD GrantedAccess,LPDWORD AccessStatusList,LPBOOL pfGenerateOnClose); + WINADVAPI WINBOOL WINAPI AccessCheckByTypeResultListAndAuditAlarmByHandleW(LPCWSTR SubsystemName,LPVOID HandleId,HANDLE ClientToken,LPCWSTR ObjectTypeName,LPCWSTR ObjectName,PSECURITY_DESCRIPTOR SecurityDescriptor,PSID PrincipalSelfSid,DWORD DesiredAccess,AUDIT_EVENT_TYPE AuditType,DWORD Flags,POBJECT_TYPE_LIST ObjectTypeList,DWORD ObjectTypeListLength,PGENERIC_MAPPING GenericMapping,WINBOOL ObjectCreation,LPDWORD GrantedAccess,LPDWORD AccessStatusList,LPBOOL pfGenerateOnClose); + WINADVAPI WINBOOL WINAPI ObjectOpenAuditAlarmA(LPCSTR SubsystemName,LPVOID HandleId,LPSTR ObjectTypeName,LPSTR ObjectName,PSECURITY_DESCRIPTOR pSecurityDescriptor,HANDLE ClientToken,DWORD DesiredAccess,DWORD GrantedAccess,PPRIVILEGE_SET Privileges,WINBOOL ObjectCreation,WINBOOL AccessGranted,LPBOOL GenerateOnClose); + WINADVAPI WINBOOL WINAPI ObjectOpenAuditAlarmW(LPCWSTR SubsystemName,LPVOID HandleId,LPWSTR ObjectTypeName,LPWSTR ObjectName,PSECURITY_DESCRIPTOR pSecurityDescriptor,HANDLE ClientToken,DWORD DesiredAccess,DWORD GrantedAccess,PPRIVILEGE_SET Privileges,WINBOOL ObjectCreation,WINBOOL AccessGranted,LPBOOL GenerateOnClose); + WINADVAPI WINBOOL WINAPI ObjectPrivilegeAuditAlarmA(LPCSTR SubsystemName,LPVOID HandleId,HANDLE ClientToken,DWORD DesiredAccess,PPRIVILEGE_SET Privileges,WINBOOL AccessGranted); + WINADVAPI WINBOOL WINAPI ObjectPrivilegeAuditAlarmW(LPCWSTR SubsystemName,LPVOID HandleId,HANDLE ClientToken,DWORD DesiredAccess,PPRIVILEGE_SET Privileges,WINBOOL AccessGranted); + WINADVAPI WINBOOL WINAPI ObjectCloseAuditAlarmA(LPCSTR SubsystemName,LPVOID HandleId,WINBOOL GenerateOnClose); + WINADVAPI WINBOOL WINAPI ObjectCloseAuditAlarmW(LPCWSTR SubsystemName,LPVOID HandleId,WINBOOL GenerateOnClose); + WINADVAPI WINBOOL WINAPI ObjectDeleteAuditAlarmA(LPCSTR SubsystemName,LPVOID HandleId,WINBOOL GenerateOnClose); + WINADVAPI WINBOOL WINAPI ObjectDeleteAuditAlarmW(LPCWSTR SubsystemName,LPVOID HandleId,WINBOOL GenerateOnClose); + WINADVAPI WINBOOL WINAPI PrivilegedServiceAuditAlarmA(LPCSTR SubsystemName,LPCSTR ServiceName,HANDLE ClientToken,PPRIVILEGE_SET Privileges,WINBOOL AccessGranted); + WINADVAPI WINBOOL WINAPI PrivilegedServiceAuditAlarmW(LPCWSTR SubsystemName,LPCWSTR ServiceName,HANDLE ClientToken,PPRIVILEGE_SET Privileges,WINBOOL AccessGranted); + WINADVAPI WINBOOL WINAPI IsWellKnownSid(PSID pSid,WELL_KNOWN_SID_TYPE WellKnownSidType); + WINADVAPI WINBOOL WINAPI CreateWellKnownSid(WELL_KNOWN_SID_TYPE WellKnownSidType,PSID DomainSid,PSID pSid,DWORD *cbSid); + WINADVAPI WINBOOL WINAPI EqualDomainSid(PSID pSid1,PSID pSid2,WINBOOL *pfEqual); + WINADVAPI WINBOOL WINAPI GetWindowsAccountDomainSid(PSID pSid,PSID pDomainSid,DWORD *cbDomainSid); + WINADVAPI WINBOOL WINAPI IsValidSid(PSID pSid); + WINADVAPI WINBOOL WINAPI EqualSid(PSID pSid1,PSID pSid2); + WINADVAPI WINBOOL WINAPI EqualPrefixSid(PSID pSid1,PSID pSid2); + WINADVAPI DWORD WINAPI GetSidLengthRequired (UCHAR nSubAuthorityCount); + WINADVAPI WINBOOL WINAPI AllocateAndInitializeSid(PSID_IDENTIFIER_AUTHORITY pIdentifierAuthority,BYTE nSubAuthorityCount,DWORD nSubAuthority0,DWORD nSubAuthority1,DWORD nSubAuthority2,DWORD nSubAuthority3,DWORD nSubAuthority4,DWORD nSubAuthority5,DWORD nSubAuthority6,DWORD nSubAuthority7,PSID *pSid); + WINADVAPI PVOID WINAPI FreeSid(PSID pSid); + WINADVAPI WINBOOL WINAPI InitializeSid(PSID Sid,PSID_IDENTIFIER_AUTHORITY pIdentifierAuthority,BYTE nSubAuthorityCount); + WINADVAPI PSID_IDENTIFIER_AUTHORITY WINAPI GetSidIdentifierAuthority(PSID pSid); + WINADVAPI PDWORD WINAPI GetSidSubAuthority(PSID pSid,DWORD nSubAuthority); + WINADVAPI PUCHAR WINAPI GetSidSubAuthorityCount(PSID pSid); + WINADVAPI DWORD WINAPI GetLengthSid(PSID pSid); + WINADVAPI WINBOOL WINAPI CopySid(DWORD nDestinationSidLength,PSID pDestinationSid,PSID pSourceSid); + WINADVAPI WINBOOL WINAPI AreAllAccessesGranted(DWORD GrantedAccess,DWORD DesiredAccess); + WINADVAPI WINBOOL WINAPI AreAnyAccessesGranted(DWORD GrantedAccess,DWORD DesiredAccess); + WINADVAPI VOID WINAPI MapGenericMask(PDWORD AccessMask,PGENERIC_MAPPING GenericMapping); + WINADVAPI WINBOOL WINAPI IsValidAcl(PACL pAcl); + WINADVAPI WINBOOL WINAPI InitializeAcl(PACL pAcl,DWORD nAclLength,DWORD dwAclRevision); + WINADVAPI WINBOOL WINAPI GetAclInformation(PACL pAcl,LPVOID pAclInformation,DWORD nAclInformationLength,ACL_INFORMATION_CLASS dwAclInformationClass); + WINADVAPI WINBOOL WINAPI SetAclInformation(PACL pAcl,LPVOID pAclInformation,DWORD nAclInformationLength,ACL_INFORMATION_CLASS dwAclInformationClass); + WINADVAPI WINBOOL WINAPI AddAce(PACL pAcl,DWORD dwAceRevision,DWORD dwStartingAceIndex,LPVOID pAceList,DWORD nAceListLength); + WINADVAPI WINBOOL WINAPI DeleteAce(PACL pAcl,DWORD dwAceIndex); + WINADVAPI WINBOOL WINAPI GetAce(PACL pAcl,DWORD dwAceIndex,LPVOID *pAce); + WINADVAPI WINBOOL WINAPI AddAccessAllowedAce(PACL pAcl,DWORD dwAceRevision,DWORD AccessMask,PSID pSid); + WINADVAPI WINBOOL WINAPI AddAccessAllowedAceEx(PACL pAcl,DWORD dwAceRevision,DWORD AceFlags,DWORD AccessMask,PSID pSid); + WINADVAPI WINBOOL WINAPI AddAccessDeniedAce(PACL pAcl,DWORD dwAceRevision,DWORD AccessMask,PSID pSid); + WINADVAPI WINBOOL WINAPI AddAccessDeniedAceEx(PACL pAcl,DWORD dwAceRevision,DWORD AceFlags,DWORD AccessMask,PSID pSid); + WINADVAPI WINBOOL WINAPI AddAuditAccessAce(PACL pAcl,DWORD dwAceRevision,DWORD dwAccessMask,PSID pSid,WINBOOL bAuditSuccess,WINBOOL bAuditFailure); + WINADVAPI WINBOOL WINAPI AddAuditAccessAceEx(PACL pAcl,DWORD dwAceRevision,DWORD AceFlags,DWORD dwAccessMask,PSID pSid,WINBOOL bAuditSuccess,WINBOOL bAuditFailure); + WINADVAPI WINBOOL WINAPI AddAccessAllowedObjectAce(PACL pAcl,DWORD dwAceRevision,DWORD AceFlags,DWORD AccessMask,GUID *ObjectTypeGuid,GUID *InheritedObjectTypeGuid,PSID pSid); + WINADVAPI WINBOOL WINAPI AddAccessDeniedObjectAce(PACL pAcl,DWORD dwAceRevision,DWORD AceFlags,DWORD AccessMask,GUID *ObjectTypeGuid,GUID *InheritedObjectTypeGuid,PSID pSid); + WINADVAPI WINBOOL WINAPI AddAuditAccessObjectAce(PACL pAcl,DWORD dwAceRevision,DWORD AceFlags,DWORD AccessMask,GUID *ObjectTypeGuid,GUID *InheritedObjectTypeGuid,PSID pSid,WINBOOL bAuditSuccess,WINBOOL bAuditFailure); + WINADVAPI WINBOOL WINAPI FindFirstFreeAce(PACL pAcl,LPVOID *pAce); + WINADVAPI WINBOOL WINAPI InitializeSecurityDescriptor(PSECURITY_DESCRIPTOR pSecurityDescriptor,DWORD dwRevision); + WINADVAPI WINBOOL WINAPI IsValidSecurityDescriptor(PSECURITY_DESCRIPTOR pSecurityDescriptor); + WINADVAPI DWORD WINAPI GetSecurityDescriptorLength(PSECURITY_DESCRIPTOR pSecurityDescriptor); + WINADVAPI WINBOOL WINAPI GetSecurityDescriptorControl(PSECURITY_DESCRIPTOR pSecurityDescriptor,PSECURITY_DESCRIPTOR_CONTROL pControl,LPDWORD lpdwRevision); + WINADVAPI WINBOOL WINAPI SetSecurityDescriptorControl(PSECURITY_DESCRIPTOR pSecurityDescriptor,SECURITY_DESCRIPTOR_CONTROL ControlBitsOfInterest,SECURITY_DESCRIPTOR_CONTROL ControlBitsToSet); + WINADVAPI WINBOOL WINAPI SetSecurityDescriptorDacl(PSECURITY_DESCRIPTOR pSecurityDescriptor,WINBOOL bDaclPresent,PACL pDacl,WINBOOL bDaclDefaulted); + WINADVAPI WINBOOL WINAPI GetSecurityDescriptorDacl(PSECURITY_DESCRIPTOR pSecurityDescriptor,LPBOOL lpbDaclPresent,PACL *pDacl,LPBOOL lpbDaclDefaulted); + WINADVAPI WINBOOL WINAPI SetSecurityDescriptorSacl(PSECURITY_DESCRIPTOR pSecurityDescriptor,WINBOOL bSaclPresent,PACL pSacl,WINBOOL bSaclDefaulted); + WINADVAPI WINBOOL WINAPI GetSecurityDescriptorSacl(PSECURITY_DESCRIPTOR pSecurityDescriptor,LPBOOL lpbSaclPresent,PACL *pSacl,LPBOOL lpbSaclDefaulted); + WINADVAPI WINBOOL WINAPI SetSecurityDescriptorOwner(PSECURITY_DESCRIPTOR pSecurityDescriptor,PSID pOwner,WINBOOL bOwnerDefaulted); + WINADVAPI WINBOOL WINAPI GetSecurityDescriptorOwner(PSECURITY_DESCRIPTOR pSecurityDescriptor,PSID *pOwner,LPBOOL lpbOwnerDefaulted); + WINADVAPI WINBOOL WINAPI SetSecurityDescriptorGroup(PSECURITY_DESCRIPTOR pSecurityDescriptor,PSID pGroup,WINBOOL bGroupDefaulted); + WINADVAPI WINBOOL WINAPI GetSecurityDescriptorGroup(PSECURITY_DESCRIPTOR pSecurityDescriptor,PSID *pGroup,LPBOOL lpbGroupDefaulted); + WINADVAPI DWORD WINAPI SetSecurityDescriptorRMControl(PSECURITY_DESCRIPTOR SecurityDescriptor,PUCHAR RMControl); + WINADVAPI DWORD WINAPI GetSecurityDescriptorRMControl(PSECURITY_DESCRIPTOR SecurityDescriptor,PUCHAR RMControl); + WINADVAPI WINBOOL WINAPI CreatePrivateObjectSecurity(PSECURITY_DESCRIPTOR ParentDescriptor,PSECURITY_DESCRIPTOR CreatorDescriptor,PSECURITY_DESCRIPTOR *NewDescriptor,WINBOOL IsDirectoryObject,HANDLE Token,PGENERIC_MAPPING GenericMapping); + WINADVAPI WINBOOL WINAPI ConvertToAutoInheritPrivateObjectSecurity(PSECURITY_DESCRIPTOR ParentDescriptor,PSECURITY_DESCRIPTOR CurrentSecurityDescriptor,PSECURITY_DESCRIPTOR *NewSecurityDescriptor,GUID *ObjectType,BOOLEAN IsDirectoryObject,PGENERIC_MAPPING GenericMapping); + WINADVAPI WINBOOL WINAPI CreatePrivateObjectSecurityEx(PSECURITY_DESCRIPTOR ParentDescriptor,PSECURITY_DESCRIPTOR CreatorDescriptor,PSECURITY_DESCRIPTOR *NewDescriptor,GUID *ObjectType,WINBOOL IsContainerObject,ULONG AutoInheritFlags,HANDLE Token,PGENERIC_MAPPING GenericMapping); + WINADVAPI WINBOOL WINAPI CreatePrivateObjectSecurityWithMultipleInheritance(PSECURITY_DESCRIPTOR ParentDescriptor,PSECURITY_DESCRIPTOR CreatorDescriptor,PSECURITY_DESCRIPTOR *NewDescriptor,GUID **ObjectTypes,ULONG GuidCount,WINBOOL IsContainerObject,ULONG AutoInheritFlags,HANDLE Token,PGENERIC_MAPPING GenericMapping); + WINADVAPI WINBOOL WINAPI SetPrivateObjectSecurity (SECURITY_INFORMATION SecurityInformation,PSECURITY_DESCRIPTOR ModificationDescriptor,PSECURITY_DESCRIPTOR *ObjectsSecurityDescriptor,PGENERIC_MAPPING GenericMapping,HANDLE Token); + WINADVAPI WINBOOL WINAPI SetPrivateObjectSecurityEx (SECURITY_INFORMATION SecurityInformation,PSECURITY_DESCRIPTOR ModificationDescriptor,PSECURITY_DESCRIPTOR *ObjectsSecurityDescriptor,ULONG AutoInheritFlags,PGENERIC_MAPPING GenericMapping,HANDLE Token); + WINADVAPI WINBOOL WINAPI GetPrivateObjectSecurity(PSECURITY_DESCRIPTOR ObjectDescriptor,SECURITY_INFORMATION SecurityInformation,PSECURITY_DESCRIPTOR ResultantDescriptor,DWORD DescriptorLength,PDWORD ReturnLength); + WINADVAPI WINBOOL WINAPI DestroyPrivateObjectSecurity(PSECURITY_DESCRIPTOR *ObjectDescriptor); + WINADVAPI WINBOOL WINAPI MakeSelfRelativeSD(PSECURITY_DESCRIPTOR pAbsoluteSecurityDescriptor,PSECURITY_DESCRIPTOR pSelfRelativeSecurityDescriptor,LPDWORD lpdwBufferLength); + WINADVAPI WINBOOL WINAPI MakeAbsoluteSD(PSECURITY_DESCRIPTOR pSelfRelativeSecurityDescriptor,PSECURITY_DESCRIPTOR pAbsoluteSecurityDescriptor,LPDWORD lpdwAbsoluteSecurityDescriptorSize,PACL pDacl,LPDWORD lpdwDaclSize,PACL pSacl,LPDWORD lpdwSaclSize,PSID pOwner,LPDWORD lpdwOwnerSize,PSID pPrimaryGroup,LPDWORD lpdwPrimaryGroupSize); + WINADVAPI WINBOOL WINAPI MakeAbsoluteSD2(PSECURITY_DESCRIPTOR pSelfRelativeSecurityDescriptor,LPDWORD lpdwBufferSize); + WINADVAPI WINBOOL WINAPI SetFileSecurityA(LPCSTR lpFileName,SECURITY_INFORMATION SecurityInformation,PSECURITY_DESCRIPTOR pSecurityDescriptor); + WINADVAPI WINBOOL WINAPI SetFileSecurityW(LPCWSTR lpFileName,SECURITY_INFORMATION SecurityInformation,PSECURITY_DESCRIPTOR pSecurityDescriptor); + WINADVAPI WINBOOL WINAPI GetFileSecurityA(LPCSTR lpFileName,SECURITY_INFORMATION RequestedInformation,PSECURITY_DESCRIPTOR pSecurityDescriptor,DWORD nLength,LPDWORD lpnLengthNeeded); + WINADVAPI WINBOOL WINAPI GetFileSecurityW(LPCWSTR lpFileName,SECURITY_INFORMATION RequestedInformation,PSECURITY_DESCRIPTOR pSecurityDescriptor,DWORD nLength,LPDWORD lpnLengthNeeded); + WINADVAPI WINBOOL WINAPI SetKernelObjectSecurity(HANDLE Handle,SECURITY_INFORMATION SecurityInformation,PSECURITY_DESCRIPTOR SecurityDescriptor); + WINBASEAPI HANDLE WINAPI FindFirstChangeNotificationA(LPCSTR lpPathName,WINBOOL bWatchSubtree,DWORD dwNotifyFilter); + WINBASEAPI HANDLE WINAPI FindFirstChangeNotificationW(LPCWSTR lpPathName,WINBOOL bWatchSubtree,DWORD dwNotifyFilter); + WINBASEAPI WINBOOL WINAPI FindNextChangeNotification(HANDLE hChangeHandle); + WINBASEAPI WINBOOL WINAPI FindCloseChangeNotification(HANDLE hChangeHandle); + WINBASEAPI WINBOOL WINAPI ReadDirectoryChangesW(HANDLE hDirectory,LPVOID lpBuffer,DWORD nBufferLength,WINBOOL bWatchSubtree,DWORD dwNotifyFilter,LPDWORD lpBytesReturned,LPOVERLAPPED lpOverlapped,LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine); + WINBASEAPI WINBOOL WINAPI VirtualLock(LPVOID lpAddress,SIZE_T dwSize); + WINBASEAPI WINBOOL WINAPI VirtualUnlock(LPVOID lpAddress,SIZE_T dwSize); + WINBASEAPI LPVOID WINAPI MapViewOfFileEx(HANDLE hFileMappingObject,DWORD dwDesiredAccess,DWORD dwFileOffsetHigh,DWORD dwFileOffsetLow,SIZE_T dwNumberOfBytesToMap,LPVOID lpBaseAddress); + WINBASEAPI WINBOOL WINAPI SetPriorityClass(HANDLE hProcess,DWORD dwPriorityClass); + WINBASEAPI DWORD WINAPI GetPriorityClass(HANDLE hProcess); + WINBASEAPI WINBOOL WINAPI IsBadReadPtr(CONST VOID *lp,UINT_PTR ucb); + WINBASEAPI WINBOOL WINAPI IsBadWritePtr(LPVOID lp,UINT_PTR ucb); + WINBASEAPI WINBOOL WINAPI IsBadHugeReadPtr(CONST VOID *lp,UINT_PTR ucb); + WINBASEAPI WINBOOL WINAPI IsBadHugeWritePtr(LPVOID lp,UINT_PTR ucb); + WINBASEAPI WINBOOL WINAPI IsBadCodePtr(FARPROC lpfn); + WINBASEAPI WINBOOL WINAPI IsBadStringPtrA(LPCSTR lpsz,UINT_PTR ucchMax); + WINBASEAPI WINBOOL WINAPI IsBadStringPtrW(LPCWSTR lpsz,UINT_PTR ucchMax); + WINADVAPI WINBOOL WINAPI LookupAccountSidA(LPCSTR lpSystemName,PSID Sid,LPSTR Name,LPDWORD cchName,LPSTR ReferencedDomainName,LPDWORD cchReferencedDomainName,PSID_NAME_USE peUse); + WINADVAPI WINBOOL WINAPI LookupAccountSidW(LPCWSTR lpSystemName,PSID Sid,LPWSTR Name,LPDWORD cchName,LPWSTR ReferencedDomainName,LPDWORD cchReferencedDomainName,PSID_NAME_USE peUse); + WINADVAPI WINBOOL WINAPI LookupAccountNameA(LPCSTR lpSystemName,LPCSTR lpAccountName,PSID Sid,LPDWORD cbSid,LPSTR ReferencedDomainName,LPDWORD cchReferencedDomainName,PSID_NAME_USE peUse); + WINADVAPI WINBOOL WINAPI LookupAccountNameW(LPCWSTR lpSystemName,LPCWSTR lpAccountName,PSID Sid,LPDWORD cbSid,LPWSTR ReferencedDomainName,LPDWORD cchReferencedDomainName,PSID_NAME_USE peUse); + WINADVAPI WINBOOL WINAPI LookupPrivilegeValueA(LPCSTR lpSystemName,LPCSTR lpName,PLUID lpLuid); + WINADVAPI WINBOOL WINAPI LookupPrivilegeValueW(LPCWSTR lpSystemName,LPCWSTR lpName,PLUID lpLuid); + WINADVAPI WINBOOL WINAPI LookupPrivilegeNameA(LPCSTR lpSystemName,PLUID lpLuid,LPSTR lpName,LPDWORD cchName); + WINADVAPI WINBOOL WINAPI LookupPrivilegeNameW(LPCWSTR lpSystemName,PLUID lpLuid,LPWSTR lpName,LPDWORD cchName); + WINADVAPI WINBOOL WINAPI LookupPrivilegeDisplayNameA(LPCSTR lpSystemName,LPCSTR lpName,LPSTR lpDisplayName,LPDWORD cchDisplayName,LPDWORD lpLanguageId); + WINADVAPI WINBOOL WINAPI LookupPrivilegeDisplayNameW(LPCWSTR lpSystemName,LPCWSTR lpName,LPWSTR lpDisplayName,LPDWORD cchDisplayName,LPDWORD lpLanguageId); + WINADVAPI WINBOOL WINAPI AllocateLocallyUniqueId(PLUID Luid); + WINBASEAPI WINBOOL WINAPI BuildCommDCBA(LPCSTR lpDef,LPDCB lpDCB); + WINBASEAPI WINBOOL WINAPI BuildCommDCBW(LPCWSTR lpDef,LPDCB lpDCB); + WINBASEAPI WINBOOL WINAPI BuildCommDCBAndTimeoutsA(LPCSTR lpDef,LPDCB lpDCB,LPCOMMTIMEOUTS lpCommTimeouts); + WINBASEAPI WINBOOL WINAPI BuildCommDCBAndTimeoutsW(LPCWSTR lpDef,LPDCB lpDCB,LPCOMMTIMEOUTS lpCommTimeouts); + WINBASEAPI WINBOOL WINAPI CommConfigDialogA(LPCSTR lpszName,HWND hWnd,LPCOMMCONFIG lpCC); + WINBASEAPI WINBOOL WINAPI CommConfigDialogW(LPCWSTR lpszName,HWND hWnd,LPCOMMCONFIG lpCC); + WINBASEAPI WINBOOL WINAPI GetDefaultCommConfigA(LPCSTR lpszName,LPCOMMCONFIG lpCC,LPDWORD lpdwSize); + WINBASEAPI WINBOOL WINAPI GetDefaultCommConfigW(LPCWSTR lpszName,LPCOMMCONFIG lpCC,LPDWORD lpdwSize); + WINBASEAPI WINBOOL WINAPI SetDefaultCommConfigA(LPCSTR lpszName,LPCOMMCONFIG lpCC,DWORD dwSize); + WINBASEAPI WINBOOL WINAPI SetDefaultCommConfigW(LPCWSTR lpszName,LPCOMMCONFIG lpCC,DWORD dwSize); + +#define MAX_COMPUTERNAME_LENGTH 15 + + WINBASEAPI WINBOOL WINAPI GetComputerNameA(LPSTR lpBuffer,LPDWORD nSize); + WINBASEAPI WINBOOL WINAPI GetComputerNameW(LPWSTR lpBuffer,LPDWORD nSize); + WINBASEAPI WINBOOL WINAPI SetComputerNameA(LPCSTR lpComputerName); + WINBASEAPI WINBOOL WINAPI SetComputerNameW(LPCWSTR lpComputerName); + + typedef enum _COMPUTER_NAME_FORMAT { + ComputerNameNetBIOS,ComputerNameDnsHostname,ComputerNameDnsDomain,ComputerNameDnsFullyQualified,ComputerNamePhysicalNetBIOS,ComputerNamePhysicalDnsHostname,ComputerNamePhysicalDnsDomain,ComputerNamePhysicalDnsFullyQualified,ComputerNameMax + } COMPUTER_NAME_FORMAT; + + WINBASEAPI WINBOOL WINAPI GetComputerNameExA(COMPUTER_NAME_FORMAT NameType,LPSTR lpBuffer,LPDWORD nSize); + WINBASEAPI WINBOOL WINAPI GetComputerNameExW(COMPUTER_NAME_FORMAT NameType,LPWSTR lpBuffer,LPDWORD nSize); + WINBASEAPI WINBOOL WINAPI SetComputerNameExA(COMPUTER_NAME_FORMAT NameType,LPCSTR lpBuffer); + WINBASEAPI WINBOOL WINAPI SetComputerNameExW(COMPUTER_NAME_FORMAT NameType,LPCWSTR lpBuffer); + WINBASEAPI WINBOOL WINAPI DnsHostnameToComputerNameA(LPCSTR Hostname,LPSTR ComputerName,LPDWORD nSize); + WINBASEAPI WINBOOL WINAPI DnsHostnameToComputerNameW(LPCWSTR Hostname,LPWSTR ComputerName,LPDWORD nSize); + WINADVAPI WINBOOL WINAPI GetUserNameA(LPSTR lpBuffer,LPDWORD pcbBuffer); + WINADVAPI WINBOOL WINAPI GetUserNameW(LPWSTR lpBuffer,LPDWORD pcbBuffer); + +#define LOGON32_LOGON_INTERACTIVE 2 +#define LOGON32_LOGON_NETWORK 3 +#define LOGON32_LOGON_BATCH 4 +#define LOGON32_LOGON_SERVICE 5 +#define LOGON32_LOGON_UNLOCK 7 +#define LOGON32_LOGON_NETWORK_CLEARTEXT 8 +#define LOGON32_LOGON_NEW_CREDENTIALS 9 + +#define LOGON32_PROVIDER_DEFAULT 0 +#define LOGON32_PROVIDER_WINNT35 1 +#define LOGON32_PROVIDER_WINNT40 2 +#define LOGON32_PROVIDER_WINNT50 3 + +#ifdef UNICODE +#define LogonUser LogonUserW +#define LogonUserEx LogonUserExW +#define CreateProcessAsUser CreateProcessAsUserW +#else +#define LogonUser LogonUserA +#define LogonUserEx LogonUserExA +#define CreateProcessAsUser CreateProcessAsUserA +#endif + + WINADVAPI WINBOOL WINAPI LogonUserA(LPCSTR lpszUsername,LPCSTR lpszDomain,LPCSTR lpszPassword,DWORD dwLogonType,DWORD dwLogonProvider,PHANDLE phToken); + WINADVAPI WINBOOL WINAPI LogonUserW(LPCWSTR lpszUsername,LPCWSTR lpszDomain,LPCWSTR lpszPassword,DWORD dwLogonType,DWORD dwLogonProvider,PHANDLE phToken); + WINADVAPI WINBOOL WINAPI LogonUserExA(LPCSTR lpszUsername,LPCSTR lpszDomain,LPCSTR lpszPassword,DWORD dwLogonType,DWORD dwLogonProvider,PHANDLE phToken,PSID *ppLogonSid,PVOID *ppProfileBuffer,LPDWORD pdwProfileLength,PQUOTA_LIMITS pQuotaLimits); + WINADVAPI WINBOOL WINAPI LogonUserExW(LPCWSTR lpszUsername,LPCWSTR lpszDomain,LPCWSTR lpszPassword,DWORD dwLogonType,DWORD dwLogonProvider,PHANDLE phToken,PSID *ppLogonSid,PVOID *ppProfileBuffer,LPDWORD pdwProfileLength,PQUOTA_LIMITS pQuotaLimits); + WINADVAPI WINBOOL WINAPI ImpersonateLoggedOnUser(HANDLE hToken); + WINADVAPI WINBOOL WINAPI CreateProcessAsUserA(HANDLE hToken,LPCSTR lpApplicationName,LPSTR lpCommandLine,LPSECURITY_ATTRIBUTES lpProcessAttributes,LPSECURITY_ATTRIBUTES lpThreadAttributes,WINBOOL bInheritHandles,DWORD dwCreationFlags,LPVOID lpEnvironment,LPCSTR lpCurrentDirectory,LPSTARTUPINFOA lpStartupInfo,LPPROCESS_INFORMATION lpProcessInformation); + WINADVAPI WINBOOL WINAPI CreateProcessAsUserW(HANDLE hToken,LPCWSTR lpApplicationName,LPWSTR lpCommandLine,LPSECURITY_ATTRIBUTES lpProcessAttributes,LPSECURITY_ATTRIBUTES lpThreadAttributes,WINBOOL bInheritHandles,DWORD dwCreationFlags,LPVOID lpEnvironment,LPCWSTR lpCurrentDirectory,LPSTARTUPINFOW lpStartupInfo,LPPROCESS_INFORMATION lpProcessInformation); + +#define LOGON_WITH_PROFILE 0x1 +#define LOGON_NETCREDENTIALS_ONLY 0x2 +#define LOGON_ZERO_PASSWORD_BUFFER 0x80000000 + + WINADVAPI WINBOOL WINAPI CreateProcessWithLogonW(LPCWSTR lpUsername,LPCWSTR lpDomain,LPCWSTR lpPassword,DWORD dwLogonFlags,LPCWSTR lpApplicationName,LPWSTR lpCommandLine,DWORD dwCreationFlags,LPVOID lpEnvironment,LPCWSTR lpCurrentDirectory,LPSTARTUPINFOW lpStartupInfo,LPPROCESS_INFORMATION lpProcessInformation); + WINADVAPI WINBOOL WINAPI CreateProcessWithTokenW(HANDLE hToken,DWORD dwLogonFlags,LPCWSTR lpApplicationName,LPWSTR lpCommandLine,DWORD dwCreationFlags,LPVOID lpEnvironment,LPCWSTR lpCurrentDirectory,LPSTARTUPINFOW lpStartupInfo,LPPROCESS_INFORMATION lpProcessInformation); + WINADVAPI WINBOOL WINAPI ImpersonateAnonymousToken(HANDLE ThreadHandle); + WINADVAPI WINBOOL WINAPI DuplicateTokenEx(HANDLE hExistingToken,DWORD dwDesiredAccess,LPSECURITY_ATTRIBUTES lpTokenAttributes,SECURITY_IMPERSONATION_LEVEL ImpersonationLevel,TOKEN_TYPE TokenType,PHANDLE phNewToken); + WINADVAPI WINBOOL WINAPI CreateRestrictedToken(HANDLE ExistingTokenHandle,DWORD Flags,DWORD DisableSidCount,PSID_AND_ATTRIBUTES SidsToDisable,DWORD DeletePrivilegeCount,PLUID_AND_ATTRIBUTES PrivilegesToDelete,DWORD RestrictedSidCount,PSID_AND_ATTRIBUTES SidsToRestrict,PHANDLE NewTokenHandle); + WINADVAPI WINBOOL WINAPI IsTokenRestricted(HANDLE TokenHandle); + WINADVAPI WINBOOL WINAPI IsTokenUntrusted(HANDLE TokenHandle); + WINADVAPI WINBOOL WINAPI CheckTokenMembership(HANDLE TokenHandle,PSID SidToCheck,PBOOL IsMember); + + typedef WAITORTIMERCALLBACKFUNC WAITORTIMERCALLBACK; + + WINBASEAPI WINBOOL WINAPI RegisterWaitForSingleObject(PHANDLE phNewWaitObject,HANDLE hObject,WAITORTIMERCALLBACK Callback,PVOID Context,ULONG dwMilliseconds,ULONG dwFlags); + WINBASEAPI HANDLE WINAPI RegisterWaitForSingleObjectEx(HANDLE hObject,WAITORTIMERCALLBACK Callback,PVOID Context,ULONG dwMilliseconds,ULONG dwFlags); + WINBASEAPI WINBOOL WINAPI UnregisterWait(HANDLE WaitHandle); + WINBASEAPI WINBOOL WINAPI UnregisterWaitEx(HANDLE WaitHandle,HANDLE CompletionEvent); + WINBASEAPI WINBOOL WINAPI QueueUserWorkItem(LPTHREAD_START_ROUTINE Function,PVOID Context,ULONG Flags); + WINBASEAPI WINBOOL WINAPI BindIoCompletionCallback(HANDLE FileHandle,LPOVERLAPPED_COMPLETION_ROUTINE Function,ULONG Flags); + WINBASEAPI HANDLE WINAPI CreateTimerQueue(VOID); + WINBASEAPI WINBOOL WINAPI CreateTimerQueueTimer(PHANDLE phNewTimer,HANDLE TimerQueue,WAITORTIMERCALLBACK Callback,PVOID Parameter,DWORD DueTime,DWORD Period,ULONG Flags); + WINBASEAPI WINBOOL WINAPI ChangeTimerQueueTimer(HANDLE TimerQueue,HANDLE Timer,ULONG DueTime,ULONG Period); + WINBASEAPI WINBOOL WINAPI DeleteTimerQueueTimer(HANDLE TimerQueue,HANDLE Timer,HANDLE CompletionEvent); + WINBASEAPI WINBOOL WINAPI DeleteTimerQueueEx(HANDLE TimerQueue,HANDLE CompletionEvent); + WINBASEAPI HANDLE WINAPI SetTimerQueueTimer(HANDLE TimerQueue,WAITORTIMERCALLBACK Callback,PVOID Parameter,DWORD DueTime,DWORD Period,WINBOOL PreferIo); + WINBASEAPI WINBOOL WINAPI CancelTimerQueueTimer(HANDLE TimerQueue,HANDLE Timer); + WINBASEAPI WINBOOL WINAPI DeleteTimerQueue(HANDLE TimerQueue); + +#define HW_PROFILE_GUIDLEN 39 +#define MAX_PROFILE_LEN 80 + +#define DOCKINFO_UNDOCKED (0x1) +#define DOCKINFO_DOCKED (0x2) +#define DOCKINFO_USER_SUPPLIED (0x4) +#define DOCKINFO_USER_UNDOCKED (DOCKINFO_USER_SUPPLIED | DOCKINFO_UNDOCKED) +#define DOCKINFO_USER_DOCKED (DOCKINFO_USER_SUPPLIED | DOCKINFO_DOCKED) + + typedef struct tagHW_PROFILE_INFOA { + DWORD dwDockInfo; + CHAR szHwProfileGuid[HW_PROFILE_GUIDLEN]; + CHAR szHwProfileName[MAX_PROFILE_LEN]; + } HW_PROFILE_INFOA,*LPHW_PROFILE_INFOA; + + typedef struct tagHW_PROFILE_INFOW { + DWORD dwDockInfo; + WCHAR szHwProfileGuid[HW_PROFILE_GUIDLEN]; + WCHAR szHwProfileName[MAX_PROFILE_LEN]; + } HW_PROFILE_INFOW,*LPHW_PROFILE_INFOW; + +#ifdef UNICODE + typedef HW_PROFILE_INFOW HW_PROFILE_INFO; + typedef LPHW_PROFILE_INFOW LPHW_PROFILE_INFO; +#else + typedef HW_PROFILE_INFOA HW_PROFILE_INFO; + typedef LPHW_PROFILE_INFOA LPHW_PROFILE_INFO; +#endif + +#ifdef UNICODE +#define GetCurrentHwProfile GetCurrentHwProfileW +#define GetVersionEx GetVersionExW +#define VerifyVersionInfo VerifyVersionInfoW +#else +#define GetCurrentHwProfile GetCurrentHwProfileA +#define GetVersionEx GetVersionExA +#define VerifyVersionInfo VerifyVersionInfoA +#endif + + WINADVAPI WINBOOL WINAPI GetCurrentHwProfileA (LPHW_PROFILE_INFOA lpHwProfileInfo); + WINADVAPI WINBOOL WINAPI GetCurrentHwProfileW (LPHW_PROFILE_INFOW lpHwProfileInfo); + WINBASEAPI WINBOOL WINAPI QueryPerformanceCounter(LARGE_INTEGER *lpPerformanceCount); + WINBASEAPI WINBOOL WINAPI QueryPerformanceFrequency(LARGE_INTEGER *lpFrequency); + WINBASEAPI WINBOOL WINAPI GetVersionExA(LPOSVERSIONINFOA lpVersionInformation); + WINBASEAPI WINBOOL WINAPI GetVersionExW(LPOSVERSIONINFOW lpVersionInformation); + WINBASEAPI WINBOOL WINAPI VerifyVersionInfoA(LPOSVERSIONINFOEXA lpVersionInformation,DWORD dwTypeMask,DWORDLONG dwlConditionMask); + WINBASEAPI WINBOOL WINAPI VerifyVersionInfoW(LPOSVERSIONINFOEXW lpVersionInformation,DWORD dwTypeMask,DWORDLONG dwlConditionMask); + +#include + +#define TC_NORMAL 0 +#define TC_HARDERR 1 +#define TC_GP_TRAP 2 +#define TC_SIGNAL 3 + +#define AC_LINE_OFFLINE 0x0 +#define AC_LINE_ONLINE 0x1 +#define AC_LINE_BACKUP_POWER 0x2 +#define AC_LINE_UNKNOWN 0xff + +#define BATTERY_FLAG_HIGH 0x1 +#define BATTERY_FLAG_LOW 0x2 +#define BATTERY_FLAG_CRITICAL 0x4 +#define BATTERY_FLAG_CHARGING 0x8 +#define BATTERY_FLAG_NO_BATTERY 0x80 +#define BATTERY_FLAG_UNKNOWN 0xff + +#define BATTERY_PERCENTAGE_UNKNOWN 0xff + +#define BATTERY_LIFE_UNKNOWN 0xffffffff + + typedef struct _SYSTEM_POWER_STATUS { + BYTE ACLineStatus; + BYTE BatteryFlag; + BYTE BatteryLifePercent; + BYTE Reserved1; + DWORD BatteryLifeTime; + DWORD BatteryFullLifeTime; + } SYSTEM_POWER_STATUS,*LPSYSTEM_POWER_STATUS; + +#ifdef UNICODE +#define CreateJobObject CreateJobObjectW +#define OpenJobObject OpenJobObjectW +#define FindFirstVolume FindFirstVolumeW +#define FindNextVolume FindNextVolumeW +#define FindFirstVolumeMountPoint FindFirstVolumeMountPointW +#define FindNextVolumeMountPoint FindNextVolumeMountPointW +#define SetVolumeMountPoint SetVolumeMountPointW +#define DeleteVolumeMountPoint DeleteVolumeMountPointW +#define GetVolumeNameForVolumeMountPoint GetVolumeNameForVolumeMountPointW +#define GetVolumePathName GetVolumePathNameW +#define GetVolumePathNamesForVolumeName GetVolumePathNamesForVolumeNameW +#else +#define CreateJobObject CreateJobObjectA +#define OpenJobObject OpenJobObjectA +#define FindFirstVolume FindFirstVolumeA +#define FindNextVolume FindNextVolumeA +#define FindFirstVolumeMountPoint FindFirstVolumeMountPointA +#define FindNextVolumeMountPoint FindNextVolumeMountPointA +#define SetVolumeMountPoint SetVolumeMountPointA +#define DeleteVolumeMountPoint DeleteVolumeMountPointA +#define GetVolumeNameForVolumeMountPoint GetVolumeNameForVolumeMountPointA +#define GetVolumePathName GetVolumePathNameA +#define GetVolumePathNamesForVolumeName GetVolumePathNamesForVolumeNameA +#endif + + WINBOOL WINAPI GetSystemPowerStatus(LPSYSTEM_POWER_STATUS lpSystemPowerStatus); + WINBOOL WINAPI SetSystemPowerState(WINBOOL fSuspend,WINBOOL fForce); + WINBASEAPI WINBOOL WINAPI AllocateUserPhysicalPages(HANDLE hProcess,PULONG_PTR NumberOfPages,PULONG_PTR PageArray); + WINBASEAPI WINBOOL WINAPI FreeUserPhysicalPages(HANDLE hProcess,PULONG_PTR NumberOfPages,PULONG_PTR PageArray); + WINBASEAPI WINBOOL WINAPI MapUserPhysicalPages(PVOID VirtualAddress,ULONG_PTR NumberOfPages,PULONG_PTR PageArray); + WINBASEAPI WINBOOL WINAPI MapUserPhysicalPagesScatter(PVOID *VirtualAddresses,ULONG_PTR NumberOfPages,PULONG_PTR PageArray); + WINBASEAPI HANDLE WINAPI CreateJobObjectA(LPSECURITY_ATTRIBUTES lpJobAttributes,LPCSTR lpName); + WINBASEAPI HANDLE WINAPI CreateJobObjectW(LPSECURITY_ATTRIBUTES lpJobAttributes,LPCWSTR lpName); + WINBASEAPI HANDLE WINAPI OpenJobObjectA(DWORD dwDesiredAccess,WINBOOL bInheritHandle,LPCSTR lpName); + WINBASEAPI HANDLE WINAPI OpenJobObjectW(DWORD dwDesiredAccess,WINBOOL bInheritHandle,LPCWSTR lpName); + WINBASEAPI WINBOOL WINAPI AssignProcessToJobObject(HANDLE hJob,HANDLE hProcess); + WINBASEAPI WINBOOL WINAPI TerminateJobObject(HANDLE hJob,UINT uExitCode); + WINBASEAPI WINBOOL WINAPI QueryInformationJobObject(HANDLE hJob,JOBOBJECTINFOCLASS JobObjectInformationClass,LPVOID lpJobObjectInformation,DWORD cbJobObjectInformationLength,LPDWORD lpReturnLength); + WINBASEAPI WINBOOL WINAPI SetInformationJobObject(HANDLE hJob,JOBOBJECTINFOCLASS JobObjectInformationClass,LPVOID lpJobObjectInformation,DWORD cbJobObjectInformationLength); + WINBASEAPI WINBOOL WINAPI IsProcessInJob(HANDLE ProcessHandle,HANDLE JobHandle,PBOOL Result); + WINBASEAPI WINBOOL WINAPI CreateJobSet(ULONG NumJob,PJOB_SET_ARRAY UserJobSet,ULONG Flags); + WINBASEAPI PVOID WINAPI AddVectoredExceptionHandler (ULONG First,PVECTORED_EXCEPTION_HANDLER Handler); + WINBASEAPI ULONG WINAPI RemoveVectoredExceptionHandler(PVOID Handle); + WINBASEAPI PVOID WINAPI AddVectoredContinueHandler (ULONG First,PVECTORED_EXCEPTION_HANDLER Handler); + WINBASEAPI ULONG WINAPI RemoveVectoredContinueHandler(PVOID Handle); + WINBASEAPI HANDLE WINAPI FindFirstVolumeA(LPSTR lpszVolumeName,DWORD cchBufferLength); + WINBASEAPI HANDLE WINAPI FindFirstVolumeW(LPWSTR lpszVolumeName,DWORD cchBufferLength); + WINBASEAPI WINBOOL WINAPI FindNextVolumeA(HANDLE hFindVolume,LPSTR lpszVolumeName,DWORD cchBufferLength); + WINBASEAPI WINBOOL WINAPI FindNextVolumeW(HANDLE hFindVolume,LPWSTR lpszVolumeName,DWORD cchBufferLength); + WINBASEAPI WINBOOL WINAPI FindVolumeClose(HANDLE hFindVolume); + WINBASEAPI HANDLE WINAPI FindFirstVolumeMountPointA(LPCSTR lpszRootPathName,LPSTR lpszVolumeMountPoint,DWORD cchBufferLength); + WINBASEAPI HANDLE WINAPI FindFirstVolumeMountPointW(LPCWSTR lpszRootPathName,LPWSTR lpszVolumeMountPoint,DWORD cchBufferLength); + WINBASEAPI WINBOOL WINAPI FindNextVolumeMountPointA(HANDLE hFindVolumeMountPoint,LPSTR lpszVolumeMountPoint,DWORD cchBufferLength); + WINBASEAPI WINBOOL WINAPI FindNextVolumeMountPointW(HANDLE hFindVolumeMountPoint,LPWSTR lpszVolumeMountPoint,DWORD cchBufferLength); + WINBASEAPI WINBOOL WINAPI FindVolumeMountPointClose(HANDLE hFindVolumeMountPoint); + WINBASEAPI WINBOOL WINAPI SetVolumeMountPointA(LPCSTR lpszVolumeMountPoint,LPCSTR lpszVolumeName); + WINBASEAPI WINBOOL WINAPI SetVolumeMountPointW(LPCWSTR lpszVolumeMountPoint,LPCWSTR lpszVolumeName); + WINBASEAPI WINBOOL WINAPI DeleteVolumeMountPointA(LPCSTR lpszVolumeMountPoint); + WINBASEAPI WINBOOL WINAPI DeleteVolumeMountPointW(LPCWSTR lpszVolumeMountPoint); + WINBASEAPI WINBOOL WINAPI GetVolumeNameForVolumeMountPointA(LPCSTR lpszVolumeMountPoint,LPSTR lpszVolumeName,DWORD cchBufferLength); + WINBASEAPI WINBOOL WINAPI GetVolumeNameForVolumeMountPointW(LPCWSTR lpszVolumeMountPoint,LPWSTR lpszVolumeName,DWORD cchBufferLength); + WINBASEAPI WINBOOL WINAPI GetVolumePathNameA(LPCSTR lpszFileName,LPSTR lpszVolumePathName,DWORD cchBufferLength); + WINBASEAPI WINBOOL WINAPI GetVolumePathNameW(LPCWSTR lpszFileName,LPWSTR lpszVolumePathName,DWORD cchBufferLength); + WINBASEAPI WINBOOL WINAPI GetVolumePathNamesForVolumeNameA(LPCSTR lpszVolumeName,LPCH lpszVolumePathNames,DWORD cchBufferLength,PDWORD lpcchReturnLength); + WINBASEAPI WINBOOL WINAPI GetVolumePathNamesForVolumeNameW(LPCWSTR lpszVolumeName,LPWCH lpszVolumePathNames,DWORD cchBufferLength,PDWORD lpcchReturnLength); + +#define ACTCTX_FLAG_PROCESSOR_ARCHITECTURE_VALID 0x1 +#define ACTCTX_FLAG_LANGID_VALID 0x2 +#define ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID 0x4 +#define ACTCTX_FLAG_RESOURCE_NAME_VALID 0x8 +#define ACTCTX_FLAG_SET_PROCESS_DEFAULT 0x10 +#define ACTCTX_FLAG_APPLICATION_NAME_VALID 0x20 +#define ACTCTX_FLAG_SOURCE_IS_ASSEMBLYREF 0x40 +#define ACTCTX_FLAG_HMODULE_VALID 0x80 + + typedef struct tagACTCTXA { + ULONG cbSize; + DWORD dwFlags; + LPCSTR lpSource; + USHORT wProcessorArchitecture; + LANGID wLangId; + LPCSTR lpAssemblyDirectory; + LPCSTR lpResourceName; + LPCSTR lpApplicationName; + HMODULE hModule; + } ACTCTXA,*PACTCTXA; + + typedef struct tagACTCTXW { + ULONG cbSize; + DWORD dwFlags; + LPCWSTR lpSource; + USHORT wProcessorArchitecture; + LANGID wLangId; + LPCWSTR lpAssemblyDirectory; + LPCWSTR lpResourceName; + LPCWSTR lpApplicationName; + HMODULE hModule; + } ACTCTXW,*PACTCTXW; + + typedef const ACTCTXA *PCACTCTXA; + typedef const ACTCTXW *PCACTCTXW; + +#ifdef UNICODE + typedef ACTCTXW ACTCTX; + typedef PACTCTXW PACTCTX; + typedef PCACTCTXW PCACTCTX; +#else + typedef ACTCTXA ACTCTX; + typedef PACTCTXA PACTCTX; + typedef PCACTCTXA PCACTCTX; +#endif + +#ifdef UNICODE +#define CreateActCtx CreateActCtxW +#else +#define CreateActCtx CreateActCtxA +#endif + + WINBASEAPI HANDLE WINAPI CreateActCtxA(PCACTCTXA pActCtx); + WINBASEAPI HANDLE WINAPI CreateActCtxW(PCACTCTXW pActCtx); + WINBASEAPI VOID WINAPI AddRefActCtx(HANDLE hActCtx); + WINBASEAPI VOID WINAPI ReleaseActCtx(HANDLE hActCtx); + WINBASEAPI WINBOOL WINAPI ZombifyActCtx(HANDLE hActCtx); + WINBASEAPI WINBOOL WINAPI ActivateActCtx(HANDLE hActCtx,ULONG_PTR *lpCookie); + +#define DEACTIVATE_ACTCTX_FLAG_FORCE_EARLY_DEACTIVATION (0x1) + + WINBASEAPI WINBOOL WINAPI DeactivateActCtx(DWORD dwFlags,ULONG_PTR ulCookie); + WINBASEAPI WINBOOL WINAPI GetCurrentActCtx(HANDLE *lphActCtx); + + typedef struct tagACTCTX_SECTION_KEYED_DATA_2600 { + ULONG cbSize; + ULONG ulDataFormatVersion; + PVOID lpData; + ULONG ulLength; + PVOID lpSectionGlobalData; + ULONG ulSectionGlobalDataLength; + PVOID lpSectionBase; + ULONG ulSectionTotalLength; + HANDLE hActCtx; + ULONG ulAssemblyRosterIndex; + } ACTCTX_SECTION_KEYED_DATA_2600,*PACTCTX_SECTION_KEYED_DATA_2600; + + typedef const ACTCTX_SECTION_KEYED_DATA_2600 *PCACTCTX_SECTION_KEYED_DATA_2600; + + typedef struct tagACTCTX_SECTION_KEYED_DATA_ASSEMBLY_METADATA { + PVOID lpInformation; + PVOID lpSectionBase; + ULONG ulSectionLength; + PVOID lpSectionGlobalDataBase; + ULONG ulSectionGlobalDataLength; + } ACTCTX_SECTION_KEYED_DATA_ASSEMBLY_METADATA,*PACTCTX_SECTION_KEYED_DATA_ASSEMBLY_METADATA; + + typedef const ACTCTX_SECTION_KEYED_DATA_ASSEMBLY_METADATA *PCACTCTX_SECTION_KEYED_DATA_ASSEMBLY_METADATA; + + typedef struct tagACTCTX_SECTION_KEYED_DATA { + ULONG cbSize; + ULONG ulDataFormatVersion; + PVOID lpData; + ULONG ulLength; + PVOID lpSectionGlobalData; + ULONG ulSectionGlobalDataLength; + PVOID lpSectionBase; + ULONG ulSectionTotalLength; + HANDLE hActCtx; + ULONG ulAssemblyRosterIndex; + + ULONG ulFlags; + ACTCTX_SECTION_KEYED_DATA_ASSEMBLY_METADATA AssemblyMetadata; + } ACTCTX_SECTION_KEYED_DATA,*PACTCTX_SECTION_KEYED_DATA; + + typedef const ACTCTX_SECTION_KEYED_DATA *PCACTCTX_SECTION_KEYED_DATA; + +#define FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX 0x1 +#define FIND_ACTCTX_SECTION_KEY_RETURN_FLAGS 0x2 +#define FIND_ACTCTX_SECTION_KEY_RETURN_ASSEMBLY_METADATA 0x4 + +#ifdef UNICODE +#define FindActCtxSectionString FindActCtxSectionStringW +#else +#define FindActCtxSectionString FindActCtxSectionStringA +#endif + + WINBASEAPI WINBOOL WINAPI FindActCtxSectionStringA(DWORD dwFlags,const GUID *lpExtensionGuid,ULONG ulSectionId,LPCSTR lpStringToFind,PACTCTX_SECTION_KEYED_DATA ReturnedData); + WINBASEAPI WINBOOL WINAPI FindActCtxSectionStringW(DWORD dwFlags,const GUID *lpExtensionGuid,ULONG ulSectionId,LPCWSTR lpStringToFind,PACTCTX_SECTION_KEYED_DATA ReturnedData); + WINBASEAPI WINBOOL WINAPI FindActCtxSectionGuid(DWORD dwFlags,const GUID *lpExtensionGuid,ULONG ulSectionId,const GUID *lpGuidToFind,PACTCTX_SECTION_KEYED_DATA ReturnedData); + +#ifndef RC_INVOKED +#ifndef ACTIVATION_CONTEXT_BASIC_INFORMATION_DEFINED + + typedef struct _ACTIVATION_CONTEXT_BASIC_INFORMATION { + HANDLE hActCtx; + DWORD dwFlags; + } ACTIVATION_CONTEXT_BASIC_INFORMATION,*PACTIVATION_CONTEXT_BASIC_INFORMATION; + + typedef const struct _ACTIVATION_CONTEXT_BASIC_INFORMATION *PCACTIVATION_CONTEXT_BASIC_INFORMATION; + +#define ACTIVATION_CONTEXT_BASIC_INFORMATION_DEFINED 1 +#endif +#endif + +#define QUERY_ACTCTX_FLAG_USE_ACTIVE_ACTCTX 0x4 +#define QUERY_ACTCTX_FLAG_ACTCTX_IS_HMODULE 0x8 +#define QUERY_ACTCTX_FLAG_ACTCTX_IS_ADDRESS 0x10 +#define QUERY_ACTCTX_FLAG_NO_ADDREF 0x80000000 + + WINBASEAPI WINBOOL WINAPI QueryActCtxW(DWORD dwFlags,HANDLE hActCtx,PVOID pvSubInstance,ULONG ulInfoClass,PVOID pvBuffer,SIZE_T cbBuffer,SIZE_T *pcbWrittenOrRequired); + + typedef WINBOOL (WINAPI *PQUERYACTCTXW_FUNC)(DWORD dwFlags,HANDLE hActCtx,PVOID pvSubInstance,ULONG ulInfoClass,PVOID pvBuffer,SIZE_T cbBuffer,SIZE_T *pcbWrittenOrRequired); + + WINBASEAPI WINBOOL WINAPI ProcessIdToSessionId(DWORD dwProcessId,DWORD *pSessionId); + WINBASEAPI DWORD WINAPI WTSGetActiveConsoleSessionId(); + WINBASEAPI WINBOOL WINAPI IsWow64Process(HANDLE hProcess,PBOOL Wow64Process); + WINBASEAPI WINBOOL WINAPI GetLogicalProcessorInformation(PSYSTEM_LOGICAL_PROCESSOR_INFORMATION Buffer,PDWORD ReturnedLength); + WINBASEAPI WINBOOL WINAPI GetNumaHighestNodeNumber(PULONG HighestNodeNumber); + WINBASEAPI WINBOOL WINAPI GetNumaProcessorNode(UCHAR Processor,PUCHAR NodeNumber); + WINBASEAPI WINBOOL WINAPI GetNumaNodeProcessorMask(UCHAR Node,PULONGLONG ProcessorMask); + WINBASEAPI WINBOOL WINAPI GetNumaAvailableMemoryNode(UCHAR Node,PULONGLONG AvailableBytes); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/tinyc/win32/include/winapi/wincon.h b/tinyc/win32/include/winapi/wincon.h new file mode 100644 index 000000000..a3501ee70 --- /dev/null +++ b/tinyc/win32/include/winapi/wincon.h @@ -0,0 +1,301 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _WINCON_ +#define _WINCON_ + +#ifdef __cplusplus +extern "C" { +#endif + + typedef struct _COORD { + SHORT X; + SHORT Y; + } COORD,*PCOORD; + + typedef struct _SMALL_RECT { + SHORT Left; + SHORT Top; + SHORT Right; + SHORT Bottom; + } SMALL_RECT,*PSMALL_RECT; + + typedef struct _KEY_EVENT_RECORD { + WINBOOL bKeyDown; + WORD wRepeatCount; + WORD wVirtualKeyCode; + WORD wVirtualScanCode; + union { + WCHAR UnicodeChar; + CHAR AsciiChar; + } uChar; + DWORD dwControlKeyState; + } KEY_EVENT_RECORD,*PKEY_EVENT_RECORD; + +#define RIGHT_ALT_PRESSED 0x1 +#define LEFT_ALT_PRESSED 0x2 +#define RIGHT_CTRL_PRESSED 0x4 +#define LEFT_CTRL_PRESSED 0x8 +#define SHIFT_PRESSED 0x10 +#define NUMLOCK_ON 0x20 +#define SCROLLLOCK_ON 0x40 +#define CAPSLOCK_ON 0x80 +#define ENHANCED_KEY 0x100 +#define NLS_DBCSCHAR 0x10000 +#define NLS_ALPHANUMERIC 0x0 +#define NLS_KATAKANA 0x20000 +#define NLS_HIRAGANA 0x40000 +#define NLS_ROMAN 0x400000 +#define NLS_IME_CONVERSION 0x800000 +#define NLS_IME_DISABLE 0x20000000 + + typedef struct _MOUSE_EVENT_RECORD { + COORD dwMousePosition; + DWORD dwButtonState; + DWORD dwControlKeyState; + DWORD dwEventFlags; + } MOUSE_EVENT_RECORD,*PMOUSE_EVENT_RECORD; + +#define FROM_LEFT_1ST_BUTTON_PRESSED 0x1 +#define RIGHTMOST_BUTTON_PRESSED 0x2 +#define FROM_LEFT_2ND_BUTTON_PRESSED 0x4 +#define FROM_LEFT_3RD_BUTTON_PRESSED 0x8 +#define FROM_LEFT_4TH_BUTTON_PRESSED 0x10 + +#define MOUSE_MOVED 0x1 +#define DOUBLE_CLICK 0x2 +#define MOUSE_WHEELED 0x4 + + typedef struct _WINDOW_BUFFER_SIZE_RECORD { + COORD dwSize; + } WINDOW_BUFFER_SIZE_RECORD,*PWINDOW_BUFFER_SIZE_RECORD; + + typedef struct _MENU_EVENT_RECORD { + UINT dwCommandId; + } MENU_EVENT_RECORD,*PMENU_EVENT_RECORD; + + typedef struct _FOCUS_EVENT_RECORD { + WINBOOL bSetFocus; + } FOCUS_EVENT_RECORD,*PFOCUS_EVENT_RECORD; + + typedef struct _INPUT_RECORD { + WORD EventType; + union { + KEY_EVENT_RECORD KeyEvent; + MOUSE_EVENT_RECORD MouseEvent; + WINDOW_BUFFER_SIZE_RECORD WindowBufferSizeEvent; + MENU_EVENT_RECORD MenuEvent; + FOCUS_EVENT_RECORD FocusEvent; + } Event; + } INPUT_RECORD,*PINPUT_RECORD; + +#define KEY_EVENT 0x1 +#define MOUSE_EVENT 0x2 +#define WINDOW_BUFFER_SIZE_EVENT 0x4 +#define MENU_EVENT 0x8 +#define FOCUS_EVENT 0x10 + + typedef struct _CHAR_INFO { + union { + WCHAR UnicodeChar; + CHAR AsciiChar; + } Char; + WORD Attributes; + } CHAR_INFO,*PCHAR_INFO; + +#define FOREGROUND_BLUE 0x1 +#define FOREGROUND_GREEN 0x2 +#define FOREGROUND_RED 0x4 +#define FOREGROUND_INTENSITY 0x8 +#define BACKGROUND_BLUE 0x10 +#define BACKGROUND_GREEN 0x20 +#define BACKGROUND_RED 0x40 +#define BACKGROUND_INTENSITY 0x80 +#define COMMON_LVB_LEADING_BYTE 0x100 +#define COMMON_LVB_TRAILING_BYTE 0x200 +#define COMMON_LVB_GRID_HORIZONTAL 0x400 +#define COMMON_LVB_GRID_LVERTICAL 0x800 +#define COMMON_LVB_GRID_RVERTICAL 0x1000 +#define COMMON_LVB_REVERSE_VIDEO 0x4000 +#define COMMON_LVB_UNDERSCORE 0x8000 + +#define COMMON_LVB_SBCSDBCS 0x300 + + typedef struct _CONSOLE_SCREEN_BUFFER_INFO { + COORD dwSize; + COORD dwCursorPosition; + WORD wAttributes; + SMALL_RECT srWindow; + COORD dwMaximumWindowSize; + } CONSOLE_SCREEN_BUFFER_INFO,*PCONSOLE_SCREEN_BUFFER_INFO; + + typedef struct _CONSOLE_CURSOR_INFO { + DWORD dwSize; + WINBOOL bVisible; + } CONSOLE_CURSOR_INFO,*PCONSOLE_CURSOR_INFO; + + typedef struct _CONSOLE_FONT_INFO { + DWORD nFont; + COORD dwFontSize; + } CONSOLE_FONT_INFO,*PCONSOLE_FONT_INFO; + + typedef struct _CONSOLE_SELECTION_INFO { + DWORD dwFlags; + COORD dwSelectionAnchor; + SMALL_RECT srSelection; + } CONSOLE_SELECTION_INFO,*PCONSOLE_SELECTION_INFO; + +#define CONSOLE_NO_SELECTION 0x0 +#define CONSOLE_SELECTION_IN_PROGRESS 0x1 +#define CONSOLE_SELECTION_NOT_EMPTY 0x2 +#define CONSOLE_MOUSE_SELECTION 0x4 +#define CONSOLE_MOUSE_DOWN 0x8 + + typedef WINBOOL (WINAPI *PHANDLER_ROUTINE)(DWORD CtrlType); + +#define CTRL_C_EVENT 0 +#define CTRL_BREAK_EVENT 1 +#define CTRL_CLOSE_EVENT 2 + +#define CTRL_LOGOFF_EVENT 5 +#define CTRL_SHUTDOWN_EVENT 6 + +#define ENABLE_PROCESSED_INPUT 0x1 +#define ENABLE_LINE_INPUT 0x2 +#define ENABLE_ECHO_INPUT 0x4 +#define ENABLE_WINDOW_INPUT 0x8 +#define ENABLE_MOUSE_INPUT 0x10 + +#define ENABLE_PROCESSED_OUTPUT 0x1 +#define ENABLE_WRAP_AT_EOL_OUTPUT 0x2 + +#ifdef UNICODE +#define PeekConsoleInput PeekConsoleInputW +#define ReadConsoleInput ReadConsoleInputW +#define WriteConsoleInput WriteConsoleInputW +#define ReadConsoleOutput ReadConsoleOutputW +#define WriteConsoleOutput WriteConsoleOutputW +#define ReadConsoleOutputCharacter ReadConsoleOutputCharacterW +#define WriteConsoleOutputCharacter WriteConsoleOutputCharacterW +#define FillConsoleOutputCharacter FillConsoleOutputCharacterW +#define ScrollConsoleScreenBuffer ScrollConsoleScreenBufferW +#define GetConsoleTitle GetConsoleTitleW +#define SetConsoleTitle SetConsoleTitleW +#define ReadConsole ReadConsoleW +#define WriteConsole WriteConsoleW +#define AddConsoleAlias AddConsoleAliasW +#define GetConsoleAlias GetConsoleAliasW +#define GetConsoleAliasesLength GetConsoleAliasesLengthW +#define GetConsoleAliasExesLength GetConsoleAliasExesLengthW +#define GetConsoleAliases GetConsoleAliasesW +#define GetConsoleAliasExes GetConsoleAliasExesW +#else +#define PeekConsoleInput PeekConsoleInputA +#define ReadConsoleInput ReadConsoleInputA +#define WriteConsoleInput WriteConsoleInputA +#define ReadConsoleOutput ReadConsoleOutputA +#define WriteConsoleOutput WriteConsoleOutputA +#define ReadConsoleOutputCharacter ReadConsoleOutputCharacterA +#define WriteConsoleOutputCharacter WriteConsoleOutputCharacterA +#define FillConsoleOutputCharacter FillConsoleOutputCharacterA +#define ScrollConsoleScreenBuffer ScrollConsoleScreenBufferA +#define GetConsoleTitle GetConsoleTitleA +#define SetConsoleTitle SetConsoleTitleA +#define ReadConsole ReadConsoleA +#define WriteConsole WriteConsoleA +#define AddConsoleAlias AddConsoleAliasA +#define GetConsoleAlias GetConsoleAliasA +#define GetConsoleAliasesLength GetConsoleAliasesLengthA +#define GetConsoleAliasExesLength GetConsoleAliasExesLengthA +#define GetConsoleAliases GetConsoleAliasesA +#define GetConsoleAliasExes GetConsoleAliasExesA +#endif + + WINBASEAPI WINBOOL WINAPI PeekConsoleInputA(HANDLE hConsoleInput,PINPUT_RECORD lpBuffer,DWORD nLength,LPDWORD lpNumberOfEventsRead); + WINBASEAPI WINBOOL WINAPI PeekConsoleInputW(HANDLE hConsoleInput,PINPUT_RECORD lpBuffer,DWORD nLength,LPDWORD lpNumberOfEventsRead); + WINBASEAPI WINBOOL WINAPI ReadConsoleInputA(HANDLE hConsoleInput,PINPUT_RECORD lpBuffer,DWORD nLength,LPDWORD lpNumberOfEventsRead); + WINBASEAPI WINBOOL WINAPI ReadConsoleInputW(HANDLE hConsoleInput,PINPUT_RECORD lpBuffer,DWORD nLength,LPDWORD lpNumberOfEventsRead); + WINBASEAPI WINBOOL WINAPI WriteConsoleInputA(HANDLE hConsoleInput,CONST INPUT_RECORD *lpBuffer,DWORD nLength,LPDWORD lpNumberOfEventsWritten); + WINBASEAPI WINBOOL WINAPI WriteConsoleInputW(HANDLE hConsoleInput,CONST INPUT_RECORD *lpBuffer,DWORD nLength,LPDWORD lpNumberOfEventsWritten); + WINBASEAPI WINBOOL WINAPI ReadConsoleOutputA(HANDLE hConsoleOutput,PCHAR_INFO lpBuffer,COORD dwBufferSize,COORD dwBufferCoord,PSMALL_RECT lpReadRegion); + WINBASEAPI WINBOOL WINAPI ReadConsoleOutputW(HANDLE hConsoleOutput,PCHAR_INFO lpBuffer,COORD dwBufferSize,COORD dwBufferCoord,PSMALL_RECT lpReadRegion); + WINBASEAPI WINBOOL WINAPI WriteConsoleOutputA(HANDLE hConsoleOutput,CONST CHAR_INFO *lpBuffer,COORD dwBufferSize,COORD dwBufferCoord,PSMALL_RECT lpWriteRegion); + WINBASEAPI WINBOOL WINAPI WriteConsoleOutputW(HANDLE hConsoleOutput,CONST CHAR_INFO *lpBuffer,COORD dwBufferSize,COORD dwBufferCoord,PSMALL_RECT lpWriteRegion); + WINBASEAPI WINBOOL WINAPI ReadConsoleOutputCharacterA(HANDLE hConsoleOutput,LPSTR lpCharacter,DWORD nLength,COORD dwReadCoord,LPDWORD lpNumberOfCharsRead); + WINBASEAPI WINBOOL WINAPI ReadConsoleOutputCharacterW(HANDLE hConsoleOutput,LPWSTR lpCharacter,DWORD nLength,COORD dwReadCoord,LPDWORD lpNumberOfCharsRead); + WINBASEAPI WINBOOL WINAPI ReadConsoleOutputAttribute(HANDLE hConsoleOutput,LPWORD lpAttribute,DWORD nLength,COORD dwReadCoord,LPDWORD lpNumberOfAttrsRead); + WINBASEAPI WINBOOL WINAPI WriteConsoleOutputCharacterA(HANDLE hConsoleOutput,LPCSTR lpCharacter,DWORD nLength,COORD dwWriteCoord,LPDWORD lpNumberOfCharsWritten); + WINBASEAPI WINBOOL WINAPI WriteConsoleOutputCharacterW(HANDLE hConsoleOutput,LPCWSTR lpCharacter,DWORD nLength,COORD dwWriteCoord,LPDWORD lpNumberOfCharsWritten); + WINBASEAPI WINBOOL WINAPI WriteConsoleOutputAttribute(HANDLE hConsoleOutput,CONST WORD *lpAttribute,DWORD nLength,COORD dwWriteCoord,LPDWORD lpNumberOfAttrsWritten); + WINBASEAPI WINBOOL WINAPI FillConsoleOutputCharacterA(HANDLE hConsoleOutput,CHAR cCharacter,DWORD nLength,COORD dwWriteCoord,LPDWORD lpNumberOfCharsWritten); + WINBASEAPI WINBOOL WINAPI FillConsoleOutputCharacterW(HANDLE hConsoleOutput,WCHAR cCharacter,DWORD nLength,COORD dwWriteCoord,LPDWORD lpNumberOfCharsWritten); + WINBASEAPI WINBOOL WINAPI FillConsoleOutputAttribute(HANDLE hConsoleOutput,WORD wAttribute,DWORD nLength,COORD dwWriteCoord,LPDWORD lpNumberOfAttrsWritten); + WINBASEAPI WINBOOL WINAPI GetConsoleMode(HANDLE hConsoleHandle,LPDWORD lpMode); + WINBASEAPI WINBOOL WINAPI GetNumberOfConsoleInputEvents(HANDLE hConsoleInput,LPDWORD lpNumberOfEvents); + WINBASEAPI WINBOOL WINAPI GetConsoleScreenBufferInfo(HANDLE hConsoleOutput,PCONSOLE_SCREEN_BUFFER_INFO lpConsoleScreenBufferInfo); + WINBASEAPI COORD WINAPI GetLargestConsoleWindowSize(HANDLE hConsoleOutput); + WINBASEAPI WINBOOL WINAPI GetConsoleCursorInfo(HANDLE hConsoleOutput,PCONSOLE_CURSOR_INFO lpConsoleCursorInfo); + WINBASEAPI WINBOOL WINAPI GetCurrentConsoleFont(HANDLE hConsoleOutput,WINBOOL bMaximumWindow,PCONSOLE_FONT_INFO lpConsoleCurrentFont); + WINBASEAPI COORD WINAPI GetConsoleFontSize(HANDLE hConsoleOutput,DWORD nFont); + WINBASEAPI WINBOOL WINAPI GetConsoleSelectionInfo(PCONSOLE_SELECTION_INFO lpConsoleSelectionInfo); + WINBASEAPI WINBOOL WINAPI GetNumberOfConsoleMouseButtons(LPDWORD lpNumberOfMouseButtons); + WINBASEAPI WINBOOL WINAPI SetConsoleMode(HANDLE hConsoleHandle,DWORD dwMode); + WINBASEAPI WINBOOL WINAPI SetConsoleActiveScreenBuffer(HANDLE hConsoleOutput); + WINBASEAPI WINBOOL WINAPI FlushConsoleInputBuffer(HANDLE hConsoleInput); + WINBASEAPI WINBOOL WINAPI SetConsoleScreenBufferSize(HANDLE hConsoleOutput,COORD dwSize); + WINBASEAPI WINBOOL WINAPI SetConsoleCursorPosition(HANDLE hConsoleOutput,COORD dwCursorPosition); + WINBASEAPI WINBOOL WINAPI SetConsoleCursorInfo(HANDLE hConsoleOutput,CONST CONSOLE_CURSOR_INFO *lpConsoleCursorInfo); + WINBASEAPI WINBOOL WINAPI ScrollConsoleScreenBufferA(HANDLE hConsoleOutput,CONST SMALL_RECT *lpScrollRectangle,CONST SMALL_RECT *lpClipRectangle,COORD dwDestinationOrigin,CONST CHAR_INFO *lpFill); + WINBASEAPI WINBOOL WINAPI ScrollConsoleScreenBufferW(HANDLE hConsoleOutput,CONST SMALL_RECT *lpScrollRectangle,CONST SMALL_RECT *lpClipRectangle,COORD dwDestinationOrigin,CONST CHAR_INFO *lpFill); + WINBASEAPI WINBOOL WINAPI SetConsoleWindowInfo(HANDLE hConsoleOutput,WINBOOL bAbsolute,CONST SMALL_RECT *lpConsoleWindow); + WINBASEAPI WINBOOL WINAPI SetConsoleTextAttribute(HANDLE hConsoleOutput,WORD wAttributes); + WINBASEAPI WINBOOL WINAPI SetConsoleCtrlHandler(PHANDLER_ROUTINE HandlerRoutine,WINBOOL Add); + WINBASEAPI WINBOOL WINAPI GenerateConsoleCtrlEvent(DWORD dwCtrlEvent,DWORD dwProcessGroupId); + WINBASEAPI WINBOOL WINAPI AllocConsole(VOID); + WINBASEAPI WINBOOL WINAPI FreeConsole(VOID); + WINBASEAPI WINBOOL WINAPI AttachConsole(DWORD dwProcessId); + +#define ATTACH_PARENT_PROCESS ((DWORD)-1) + + WINBASEAPI DWORD WINAPI GetConsoleTitleA(LPSTR lpConsoleTitle,DWORD nSize); + WINBASEAPI DWORD WINAPI GetConsoleTitleW(LPWSTR lpConsoleTitle,DWORD nSize); + WINBASEAPI WINBOOL WINAPI SetConsoleTitleA(LPCSTR lpConsoleTitle); + WINBASEAPI WINBOOL WINAPI SetConsoleTitleW(LPCWSTR lpConsoleTitle); + WINBASEAPI WINBOOL WINAPI ReadConsoleA(HANDLE hConsoleInput,LPVOID lpBuffer,DWORD nNumberOfCharsToRead,LPDWORD lpNumberOfCharsRead,LPVOID lpReserved); + WINBASEAPI WINBOOL WINAPI ReadConsoleW(HANDLE hConsoleInput,LPVOID lpBuffer,DWORD nNumberOfCharsToRead,LPDWORD lpNumberOfCharsRead,LPVOID lpReserved); + WINBASEAPI WINBOOL WINAPI WriteConsoleA(HANDLE hConsoleOutput,CONST VOID *lpBuffer,DWORD nNumberOfCharsToWrite,LPDWORD lpNumberOfCharsWritten,LPVOID lpReserved); + WINBASEAPI WINBOOL WINAPI WriteConsoleW(HANDLE hConsoleOutput,CONST VOID *lpBuffer,DWORD nNumberOfCharsToWrite,LPDWORD lpNumberOfCharsWritten,LPVOID lpReserved); + +#define CONSOLE_TEXTMODE_BUFFER 1 + + WINBASEAPI HANDLE WINAPI CreateConsoleScreenBuffer(DWORD dwDesiredAccess,DWORD dwShareMode,CONST SECURITY_ATTRIBUTES *lpSecurityAttributes,DWORD dwFlags,LPVOID lpScreenBufferData); + WINBASEAPI UINT WINAPI GetConsoleCP(VOID); + WINBASEAPI WINBOOL WINAPI SetConsoleCP(UINT wCodePageID); + WINBASEAPI UINT WINAPI GetConsoleOutputCP(VOID); + WINBASEAPI WINBOOL WINAPI SetConsoleOutputCP(UINT wCodePageID); + +#define CONSOLE_FULLSCREEN 1 +#define CONSOLE_FULLSCREEN_HARDWARE 2 + + WINBASEAPI WINBOOL WINAPI GetConsoleDisplayMode(LPDWORD lpModeFlags); + WINBASEAPI HWND WINAPI GetConsoleWindow(VOID); + WINBASEAPI DWORD WINAPI GetConsoleProcessList(LPDWORD lpdwProcessList,DWORD dwProcessCount); + WINBASEAPI WINBOOL WINAPI AddConsoleAliasA(LPSTR Source,LPSTR Target,LPSTR ExeName); + WINBASEAPI WINBOOL WINAPI AddConsoleAliasW(LPWSTR Source,LPWSTR Target,LPWSTR ExeName); + WINBASEAPI DWORD WINAPI GetConsoleAliasA(LPSTR Source,LPSTR TargetBuffer,DWORD TargetBufferLength,LPSTR ExeName); + WINBASEAPI DWORD WINAPI GetConsoleAliasW(LPWSTR Source,LPWSTR TargetBuffer,DWORD TargetBufferLength,LPWSTR ExeName); + WINBASEAPI DWORD WINAPI GetConsoleAliasesLengthA(LPSTR ExeName); + WINBASEAPI DWORD WINAPI GetConsoleAliasesLengthW(LPWSTR ExeName); + WINBASEAPI DWORD WINAPI GetConsoleAliasExesLengthA(VOID); + WINBASEAPI DWORD WINAPI GetConsoleAliasExesLengthW(VOID); + WINBASEAPI DWORD WINAPI GetConsoleAliasesA(LPSTR AliasBuffer,DWORD AliasBufferLength,LPSTR ExeName); + WINBASEAPI DWORD WINAPI GetConsoleAliasesW(LPWSTR AliasBuffer,DWORD AliasBufferLength,LPWSTR ExeName); + WINBASEAPI DWORD WINAPI GetConsoleAliasExesA(LPSTR ExeNameBuffer,DWORD ExeNameBufferLength); + WINBASEAPI DWORD WINAPI GetConsoleAliasExesW(LPWSTR ExeNameBuffer,DWORD ExeNameBufferLength); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/tinyc/win32/include/winapi/windef.h b/tinyc/win32/include/winapi/windef.h new file mode 100644 index 000000000..d63bdef13 --- /dev/null +++ b/tinyc/win32/include/winapi/windef.h @@ -0,0 +1,293 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _WINDEF_ +#define _WINDEF_ + +#ifndef STRICT +#define STRICT 1 +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef WINVER +#define WINVER 0x0502 +#endif + +#ifndef BASETYPES +#define BASETYPES + typedef unsigned long ULONG; + typedef ULONG *PULONG; + typedef unsigned short USHORT; + typedef USHORT *PUSHORT; + typedef unsigned char UCHAR; + typedef UCHAR *PUCHAR; + typedef char *PSZ; +#endif + +#define MAX_PATH 260 + +#ifndef NULL +#ifdef __cplusplus +#define NULL 0 +#else +#define NULL ((void *)0) +#endif +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef IN +#define IN +#endif + +#ifndef OUT +#define OUT +#endif + +#ifndef OPTIONAL +#define OPTIONAL +#endif + +#undef far +#undef near +#undef pascal + +#define far +#define near +#define pascal __stdcall + +#define cdecl +#ifndef CDECL +#define CDECL +#endif +#ifndef CALLBACK +#define CALLBACK __stdcall +#endif +#ifndef WINAPI +#define WINAPI __stdcall +#endif +#define WINAPIV __cdecl +#define APIENTRY WINAPI +#define APIPRIVATE WINAPI +#define PASCAL WINAPI +#define WINAPI_INLINE WINAPI + +#undef FAR +#undef NEAR +#define FAR +#define NEAR +#ifndef CONST +#define CONST const +#endif + + typedef unsigned long DWORD; + typedef int WINBOOL; +#define BOOL WINBOOL + typedef unsigned char BYTE; + typedef unsigned short WORD; + typedef float FLOAT; + typedef FLOAT *PFLOAT; + typedef WINBOOL *PBOOL; + typedef WINBOOL *LPBOOL; + typedef BYTE *PBYTE; + typedef BYTE *LPBYTE; + typedef int *PINT; + typedef int *LPINT; + typedef WORD *PWORD; + typedef WORD *LPWORD; + typedef long *LPLONG; + typedef DWORD *PDWORD; + typedef DWORD *LPDWORD; + typedef void *LPVOID; +# ifndef _LPCVOID_DEFINED +#define _LPCVOID_DEFINED +typedef CONST void *LPCVOID; +#endif + typedef int INT; + typedef unsigned int UINT; + typedef unsigned int *PUINT; + +#ifndef NT_INCLUDED +#include +#endif + +//gr #include + + typedef UINT_PTR WPARAM; + typedef LONG_PTR LPARAM; + typedef LONG_PTR LRESULT; + +#ifndef __cplusplus +#ifndef NOMINMAX +#ifndef max +#define max(a,b) (((a) > (b)) ? (a) : (b)) +#endif + +#ifndef min +#define min(a,b) (((a) < (b)) ? (a) : (b)) +#endif +#endif +#endif + +#define MAKEWORD(a,b) ((WORD)(((BYTE)((DWORD_PTR)(a) & 0xff)) | ((WORD)((BYTE)((DWORD_PTR)(b) & 0xff))) << 8)) +#define MAKELONG(a,b) ((LONG)(((WORD)((DWORD_PTR)(a) & 0xffff)) | ((DWORD)((WORD)((DWORD_PTR)(b) & 0xffff))) << 16)) +#define LOWORD(l) ((WORD)((DWORD_PTR)(l) & 0xffff)) +#define HIWORD(l) ((WORD)((DWORD_PTR)(l) >> 16)) +#define LOBYTE(w) ((BYTE)((DWORD_PTR)(w) & 0xff)) +#define HIBYTE(w) ((BYTE)((DWORD_PTR)(w) >> 8)) + +#ifndef WIN_INTERNAL + DECLARE_HANDLE (HWND); + DECLARE_HANDLE (HHOOK); +#ifdef WINABLE + DECLARE_HANDLE (HEVENT); +#endif +#endif + + typedef WORD ATOM; + + typedef HANDLE *SPHANDLE; + typedef HANDLE *LPHANDLE; + typedef HANDLE HGLOBAL; + typedef HANDLE HLOCAL; + typedef HANDLE GLOBALHANDLE; + typedef HANDLE LOCALHANDLE; +#ifdef _WIN64 + typedef INT_PTR (WINAPI *FARPROC)(); + typedef INT_PTR (WINAPI *NEARPROC)(); + typedef INT_PTR (WINAPI *PROC)(); +#else + typedef int (WINAPI *FARPROC)(); + typedef int (WINAPI *NEARPROC)(); + typedef int (WINAPI *PROC)(); +#endif + + typedef void *HGDIOBJ; + + DECLARE_HANDLE(HKEY); + typedef HKEY *PHKEY; + + DECLARE_HANDLE(HACCEL); + DECLARE_HANDLE(HBITMAP); + DECLARE_HANDLE(HBRUSH); + DECLARE_HANDLE(HCOLORSPACE); + DECLARE_HANDLE(HDC); + DECLARE_HANDLE(HGLRC); + DECLARE_HANDLE(HDESK); + DECLARE_HANDLE(HENHMETAFILE); + DECLARE_HANDLE(HFONT); + DECLARE_HANDLE(HICON); + DECLARE_HANDLE(HMENU); + DECLARE_HANDLE(HMETAFILE); + DECLARE_HANDLE(HINSTANCE); + typedef HINSTANCE HMODULE; + DECLARE_HANDLE(HPALETTE); + DECLARE_HANDLE(HPEN); + DECLARE_HANDLE(HRGN); + DECLARE_HANDLE(HRSRC); + DECLARE_HANDLE(HSTR); + DECLARE_HANDLE(HTASK); + DECLARE_HANDLE(HWINSTA); + DECLARE_HANDLE(HKL); + DECLARE_HANDLE(HMONITOR); + DECLARE_HANDLE(HWINEVENTHOOK); + DECLARE_HANDLE(HUMPD); + + typedef int HFILE; + typedef HICON HCURSOR; + typedef DWORD COLORREF; + typedef DWORD *LPCOLORREF; + +#define HFILE_ERROR ((HFILE)-1) + + typedef struct tagRECT { + LONG left; + LONG top; + LONG right; + LONG bottom; + } RECT,*PRECT,*NPRECT,*LPRECT; + + typedef const RECT *LPCRECT; + + typedef struct _RECTL { + LONG left; + LONG top; + LONG right; + LONG bottom; + } RECTL,*PRECTL,*LPRECTL; + + typedef const RECTL *LPCRECTL; + + typedef struct tagPOINT { + LONG x; + LONG y; + } POINT,*PPOINT,*NPPOINT,*LPPOINT; + + typedef struct _POINTL { + LONG x; + LONG y; + } POINTL,*PPOINTL; + + typedef struct tagSIZE { + LONG cx; + LONG cy; + } SIZE,*PSIZE,*LPSIZE; + + typedef SIZE SIZEL; + typedef SIZE *PSIZEL,*LPSIZEL; + + typedef struct tagPOINTS { + SHORT x; + SHORT y; + } POINTS,*PPOINTS,*LPPOINTS; + + typedef struct _FILETIME { + DWORD dwLowDateTime; + DWORD dwHighDateTime; + } FILETIME,*PFILETIME,*LPFILETIME; +#define _FILETIME_ + +#define DM_UPDATE 1 +#define DM_COPY 2 +#define DM_PROMPT 4 +#define DM_MODIFY 8 + +#define DM_IN_BUFFER DM_MODIFY +#define DM_IN_PROMPT DM_PROMPT +#define DM_OUT_BUFFER DM_COPY +#define DM_OUT_DEFAULT DM_UPDATE + +#define DC_FIELDS 1 +#define DC_PAPERS 2 +#define DC_PAPERSIZE 3 +#define DC_MINEXTENT 4 +#define DC_MAXEXTENT 5 +#define DC_BINS 6 +#define DC_DUPLEX 7 +#define DC_SIZE 8 +#define DC_EXTRA 9 +#define DC_VERSION 10 +#define DC_DRIVER 11 +#define DC_BINNAMES 12 +#define DC_ENUMRESOLUTIONS 13 +#define DC_FILEDEPENDENCIES 14 +#define DC_TRUETYPE 15 +#define DC_PAPERNAMES 16 +#define DC_ORIENTATION 17 +#define DC_COPIES 18 + +#ifdef __cplusplus +} +#endif +#endif diff --git a/tinyc/win32/include/winapi/windows.h b/tinyc/win32/include/winapi/windows.h new file mode 100644 index 000000000..2660d7f08 --- /dev/null +++ b/tinyc/win32/include/winapi/windows.h @@ -0,0 +1,127 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _WINDOWS_ +#define _WINDOWS_ + +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN 1 +#endif + +#ifndef WINVER +#define WINVER 0x0502 +#endif + +#include <_mingw.h> + +#ifndef _INC_WINDOWS +#define _INC_WINDOWS + +#if defined(RC_INVOKED) && !defined(NOWINRES) + +#include +#else + +#ifdef RC_INVOKED +#define NOATOM +#define NOGDI +#define NOGDICAPMASKS +#define NOMETAFILE +#define NOMINMAX +#define NOMSG +#define NOOPENFILE +#define NORASTEROPS +#define NOSCROLL +#define NOSOUND +#define NOSYSMETRICS +#define NOTEXTMETRIC +#define NOWH +#define NOCOMM +#define NOKANJI +#define NOCRYPT +#define NOMCX +#endif + +#if !defined(I_X86_) && !defined(_IA64_) && !defined(_AMD64_) && (defined(_X86_) && !defined(__x86_64)) +#define I_X86_ +#endif + +#if !defined(I_X86_) && !defined(_IA64_) && !defined(_AMD64_) && defined(__x86_64) +#define _AMD64_ +#endif + +#if !defined(I_X86_) && !(defined(_X86_) && !defined(__x86_64)) && !defined(_AMD64_) && defined(__ia64__) +#if !defined(_IA64_) +#define _IA64_ +#endif +#endif + +#ifndef RC_INVOKED +#include +#include +#endif + +#include +#include +#include +#include +//gr #include +#include +#include +#include +//gr #include + +#ifndef WIN32_LEAN_AND_MEAN +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifndef NOCRYPT +#include +#include +#include +#endif + +#ifndef NOUSER +#ifndef NOGDI +#include +#ifdef INC_OLE1 +#include +#else +#include +#endif +#include +#endif +#endif +#endif + +//gr #include + +#ifdef INC_OLE2 +#include +#endif + +#ifndef NOSERVICE +#include +#endif + +#ifndef NOMCX +#include +#endif + +#ifndef NOIME +#include +#endif + +#endif +#endif +#endif diff --git a/tinyc/win32/include/winapi/winerror.h b/tinyc/win32/include/winapi/winerror.h new file mode 100644 index 000000000..77d85edc8 --- /dev/null +++ b/tinyc/win32/include/winapi/winerror.h @@ -0,0 +1,3166 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _WINERROR_ +#define _WINERROR_ + +#define FACILITY_WINDOWSUPDATE 36 +#define FACILITY_WINDOWS_CE 24 +#define FACILITY_WINDOWS 8 +#define FACILITY_URT 19 +#define FACILITY_UMI 22 +#define FACILITY_SXS 23 +#define FACILITY_STORAGE 3 +#define FACILITY_STATE_MANAGEMENT 34 +#define FACILITY_SSPI 9 +#define FACILITY_SCARD 16 +#define FACILITY_SETUPAPI 15 +#define FACILITY_SECURITY 9 +#define FACILITY_RPC 1 +#define FACILITY_WIN32 7 +#define FACILITY_CONTROL 10 +#define FACILITY_NULL 0 +#define FACILITY_METADIRECTORY 35 +#define FACILITY_MSMQ 14 +#define FACILITY_MEDIASERVER 13 +#define FACILITY_INTERNET 12 +#define FACILITY_ITF 4 +#define FACILITY_HTTP 25 +#define FACILITY_DPLAY 21 +#define FACILITY_DISPATCH 2 +#define FACILITY_DIRECTORYSERVICE 37 +#define FACILITY_CONFIGURATION 33 +#define FACILITY_COMPLUS 17 +#define FACILITY_CERT 11 +#define FACILITY_BACKGROUNDCOPY 32 +#define FACILITY_ACS 20 +#define FACILITY_AAF 18 +#define ERROR_SUCCESS 0L +#define NO_ERROR 0L +#define SEC_E_OK ((HRESULT)0x00000000L) +#define ERROR_INVALID_FUNCTION 1L +#define ERROR_FILE_NOT_FOUND 2L +#define ERROR_PATH_NOT_FOUND 3L +#define ERROR_TOO_MANY_OPEN_FILES 4L +#define ERROR_ACCESS_DENIED 5L +#define ERROR_INVALID_HANDLE 6L +#define ERROR_ARENA_TRASHED 7L +#define ERROR_NOT_ENOUGH_MEMORY 8L +#define ERROR_INVALID_BLOCK 9L +#define ERROR_BAD_ENVIRONMENT 10L +#define ERROR_BAD_FORMAT 11L +#define ERROR_INVALID_ACCESS 12L +#define ERROR_INVALID_DATA 13L +#define ERROR_OUTOFMEMORY 14L +#define ERROR_INVALID_DRIVE 15L +#define ERROR_CURRENT_DIRECTORY 16L +#define ERROR_NOT_SAME_DEVICE 17L +#define ERROR_NO_MORE_FILES 18L +#define ERROR_WRITE_PROTECT 19L +#define ERROR_BAD_UNIT 20L +#define ERROR_NOT_READY 21L +#define ERROR_BAD_COMMAND 22L +#define ERROR_CRC 23L +#define ERROR_BAD_LENGTH 24L +#define ERROR_SEEK 25L +#define ERROR_NOT_DOS_DISK 26L +#define ERROR_SECTOR_NOT_FOUND 27L +#define ERROR_OUT_OF_PAPER 28L +#define ERROR_WRITE_FAULT 29L +#define ERROR_READ_FAULT 30L +#define ERROR_GEN_FAILURE 31L +#define ERROR_SHARING_VIOLATION 32L +#define ERROR_LOCK_VIOLATION 33L +#define ERROR_WRONG_DISK 34L +#define ERROR_SHARING_BUFFER_EXCEEDED 36L +#define ERROR_HANDLE_EOF 38L +#define ERROR_HANDLE_DISK_FULL 39L +#define ERROR_NOT_SUPPORTED 50L +#define ERROR_REM_NOT_LIST 51L +#define ERROR_DUP_NAME 52L +#define ERROR_BAD_NETPATH 53L +#define ERROR_NETWORK_BUSY 54L +#define ERROR_DEV_NOT_EXIST 55L +#define ERROR_TOO_MANY_CMDS 56L +#define ERROR_ADAP_HDW_ERR 57L +#define ERROR_BAD_NET_RESP 58L +#define ERROR_UNEXP_NET_ERR 59L +#define ERROR_BAD_REM_ADAP 60L +#define ERROR_PRINTQ_FULL 61L +#define ERROR_NO_SPOOL_SPACE 62L +#define ERROR_PRINT_CANCELLED 63L +#define ERROR_NETNAME_DELETED 64L +#define ERROR_NETWORK_ACCESS_DENIED 65L +#define ERROR_BAD_DEV_TYPE 66L +#define ERROR_BAD_NET_NAME 67L +#define ERROR_TOO_MANY_NAMES 68L +#define ERROR_TOO_MANY_SESS 69L +#define ERROR_SHARING_PAUSED 70L +#define ERROR_REQ_NOT_ACCEP 71L +#define ERROR_REDIR_PAUSED 72L +#define ERROR_FILE_EXISTS 80L +#define ERROR_CANNOT_MAKE 82L +#define ERROR_FAIL_I24 83L +#define ERROR_OUT_OF_STRUCTURES 84L +#define ERROR_ALREADY_ASSIGNED 85L +#define ERROR_INVALID_PASSWORD 86L +#define ERROR_INVALID_PARAMETER 87L +#define ERROR_NET_WRITE_FAULT 88L +#define ERROR_NO_PROC_SLOTS 89L +#define ERROR_TOO_MANY_SEMAPHORES 100L +#define ERROR_EXCL_SEM_ALREADY_OWNED 101L +#define ERROR_SEM_IS_SET 102L +#define ERROR_TOO_MANY_SEM_REQUESTS 103L +#define ERROR_INVALID_AT_INTERRUPT_TIME 104L +#define ERROR_SEM_OWNER_DIED 105L +#define ERROR_SEM_USER_LIMIT 106L +#define ERROR_DISK_CHANGE 107L +#define ERROR_DRIVE_LOCKED 108L +#define ERROR_BROKEN_PIPE 109L +#define ERROR_OPEN_FAILED 110L +#define ERROR_BUFFER_OVERFLOW 111L +#define ERROR_DISK_FULL 112L +#define ERROR_NO_MORE_SEARCH_HANDLES 113L +#define ERROR_INVALID_TARGET_HANDLE 114L +#define ERROR_INVALID_CATEGORY 117L +#define ERROR_INVALID_VERIFY_SWITCH 118L +#define ERROR_BAD_DRIVER_LEVEL 119L +#define ERROR_CALL_NOT_IMPLEMENTED 120L +#define ERROR_SEM_TIMEOUT 121L +#define ERROR_INSUFFICIENT_BUFFER 122L +#define ERROR_INVALID_NAME 123L +#define ERROR_INVALID_LEVEL 124L +#define ERROR_NO_VOLUME_LABEL 125L +#define ERROR_MOD_NOT_FOUND 126L +#define ERROR_PROC_NOT_FOUND 127L +#define ERROR_WAIT_NO_CHILDREN 128L +#define ERROR_CHILD_NOT_COMPLETE 129L +#define ERROR_DIRECT_ACCESS_HANDLE 130L +#define ERROR_NEGATIVE_SEEK 131L +#define ERROR_SEEK_ON_DEVICE 132L +#define ERROR_IS_JOIN_TARGET 133L +#define ERROR_IS_JOINED 134L +#define ERROR_IS_SUBSTED 135L +#define ERROR_NOT_JOINED 136L +#define ERROR_NOT_SUBSTED 137L +#define ERROR_JOIN_TO_JOIN 138L +#define ERROR_SUBST_TO_SUBST 139L +#define ERROR_JOIN_TO_SUBST 140L +#define ERROR_SUBST_TO_JOIN 141L +#define ERROR_BUSY_DRIVE 142L +#define ERROR_SAME_DRIVE 143L +#define ERROR_DIR_NOT_ROOT 144L +#define ERROR_DIR_NOT_EMPTY 145L +#define ERROR_IS_SUBST_PATH 146L +#define ERROR_IS_JOIN_PATH 147L +#define ERROR_PATH_BUSY 148L +#define ERROR_IS_SUBST_TARGET 149L +#define ERROR_SYSTEM_TRACE 150L +#define ERROR_INVALID_EVENT_COUNT 151L +#define ERROR_TOO_MANY_MUXWAITERS 152L +#define ERROR_INVALID_LIST_FORMAT 153L +#define ERROR_LABEL_TOO_LONG 154L +#define ERROR_TOO_MANY_TCBS 155L +#define ERROR_SIGNAL_REFUSED 156L +#define ERROR_DISCARDED 157L +#define ERROR_NOT_LOCKED 158L +#define ERROR_BAD_THREADID_ADDR 159L +#define ERROR_BAD_ARGUMENTS 160L +#define ERROR_BAD_PATHNAME 161L +#define ERROR_SIGNAL_PENDING 162L +#define ERROR_MAX_THRDS_REACHED 164L +#define ERROR_LOCK_FAILED 167L +#define ERROR_BUSY 170L +#define ERROR_CANCEL_VIOLATION 173L +#define ERROR_ATOMIC_LOCKS_NOT_SUPPORTED 174L +#define ERROR_INVALID_SEGMENT_NUMBER 180L +#define ERROR_INVALID_ORDINAL 182L +#define ERROR_ALREADY_EXISTS 183L +#define ERROR_INVALID_FLAG_NUMBER 186L +#define ERROR_SEM_NOT_FOUND 187L +#define ERROR_INVALID_STARTING_CODESEG 188L +#define ERROR_INVALID_STACKSEG 189L +#define ERROR_INVALID_MODULETYPE 190L +#define ERROR_INVALID_EXE_SIGNATURE 191L +#define ERROR_EXE_MARKED_INVALID 192L +#define ERROR_BAD_EXE_FORMAT 193L +#define ERROR_ITERATED_DATA_EXCEEDS_64k 194L +#define ERROR_INVALID_MINALLOCSIZE 195L +#define ERROR_DYNLINK_FROM_INVALID_RING 196L +#define ERROR_IOPL_NOT_ENABLED 197L +#define ERROR_INVALID_SEGDPL 198L +#define ERROR_AUTODATASEG_EXCEEDS_64k 199L +#define ERROR_RING2SEG_MUST_BE_MOVABLE 200L +#define ERROR_RELOC_CHAIN_XEEDS_SEGLIM 201L +#define ERROR_INFLOOP_IN_RELOC_CHAIN 202L +#define ERROR_ENVVAR_NOT_FOUND 203L +#define ERROR_NO_SIGNAL_SENT 205L +#define ERROR_FILENAME_EXCED_RANGE 206L +#define ERROR_RING2_STACK_IN_USE 207L +#define ERROR_META_EXPANSION_TOO_LONG 208L +#define ERROR_INVALID_SIGNAL_NUMBER 209L +#define ERROR_THREAD_1_INACTIVE 210L +#define ERROR_LOCKED 212L +#define ERROR_TOO_MANY_MODULES 214L +#define ERROR_NESTING_NOT_ALLOWED 215L +#define ERROR_EXE_MACHINE_TYPE_MISMATCH 216L +#define ERROR_EXE_CANNOT_MODIFY_SIGNED_BINARY 217L +#define ERROR_EXE_CANNOT_MODIFY_STRONG_SIGNED_BINARY 218L +#define ERROR_BAD_PIPE 230L +#define ERROR_PIPE_BUSY 231L +#define ERROR_NO_DATA 232L +#define ERROR_PIPE_NOT_CONNECTED 233L +#define ERROR_MORE_DATA 234L +#define ERROR_VC_DISCONNECTED 240L +#define ERROR_INVALID_EA_NAME 254L +#define ERROR_EA_LIST_INCONSISTENT 255L +#define WAIT_TIMEOUT 258L +#define ERROR_NO_MORE_ITEMS 259L +#define ERROR_CANNOT_COPY 266L +#define ERROR_DIRECTORY 267L +#define ERROR_EAS_DIDNT_FIT 275L +#define ERROR_EA_FILE_CORRUPT 276L +#define ERROR_EA_TABLE_FULL 277L +#define ERROR_INVALID_EA_HANDLE 278L +#define ERROR_EAS_NOT_SUPPORTED 282L +#define ERROR_NOT_OWNER 288L +#define ERROR_TOO_MANY_POSTS 298L +#define ERROR_PARTIAL_COPY 299L +#define ERROR_OPLOCK_NOT_GRANTED 300L +#define ERROR_INVALID_OPLOCK_PROTOCOL 301L +#define ERROR_DISK_TOO_FRAGMENTED 302L +#define ERROR_DELETE_PENDING 303L +#define ERROR_MR_MID_NOT_FOUND 317L +#define ERROR_SCOPE_NOT_FOUND 318L +#define ERROR_INVALID_ADDRESS 487L +#define ERROR_ARITHMETIC_OVERFLOW 534L +#define ERROR_PIPE_CONNECTED 535L +#define ERROR_PIPE_LISTENING 536L +#define ERROR_EA_ACCESS_DENIED 994L +#define ERROR_OPERATION_ABORTED 995L +#define ERROR_IO_INCOMPLETE 996L +#define ERROR_IO_PENDING 997L +#define ERROR_NOACCESS 998L +#define ERROR_SWAPERROR 999L +#define ERROR_STACK_OVERFLOW 1001L +#define ERROR_INVALID_MESSAGE 1002L +#define ERROR_CAN_NOT_COMPLETE 1003L +#define ERROR_INVALID_FLAGS 1004L +#define ERROR_UNRECOGNIZED_VOLUME 1005L +#define ERROR_FILE_INVALID 1006L +#define ERROR_FULLSCREEN_MODE 1007L +#define ERROR_NO_TOKEN 1008L +#define ERROR_BADDB 1009L +#define ERROR_BADKEY 1010L +#define ERROR_CANTOPEN 1011L +#define ERROR_CANTREAD 1012L +#define ERROR_CANTWRITE 1013L +#define ERROR_REGISTRY_RECOVERED 1014L +#define ERROR_REGISTRY_CORRUPT 1015L +#define ERROR_REGISTRY_IO_FAILED 1016L +#define ERROR_NOT_REGISTRY_FILE 1017L +#define ERROR_KEY_DELETED 1018L +#define ERROR_NO_LOG_SPACE 1019L +#define ERROR_KEY_HAS_CHILDREN 1020L +#define ERROR_CHILD_MUST_BE_VOLATILE 1021L +#define ERROR_NOTIFY_ENUM_DIR 1022L +#define ERROR_DEPENDENT_SERVICES_RUNNING 1051L +#define ERROR_INVALID_SERVICE_CONTROL 1052L +#define ERROR_SERVICE_REQUEST_TIMEOUT 1053L +#define ERROR_SERVICE_NO_THREAD 1054L +#define ERROR_SERVICE_DATABASE_LOCKED 1055L +#define ERROR_SERVICE_ALREADY_RUNNING 1056L +#define ERROR_INVALID_SERVICE_ACCOUNT 1057L +#define ERROR_SERVICE_DISABLED 1058L +#define ERROR_CIRCULAR_DEPENDENCY 1059L +#define ERROR_SERVICE_DOES_NOT_EXIST 1060L +#define ERROR_SERVICE_CANNOT_ACCEPT_CTRL 1061L +#define ERROR_SERVICE_NOT_ACTIVE 1062L +#define ERROR_FAILED_SERVICE_CONTROLLER_CONNECT 1063L +#define ERROR_EXCEPTION_IN_SERVICE 1064L +#define ERROR_DATABASE_DOES_NOT_EXIST 1065L +#define ERROR_SERVICE_SPECIFIC_ERROR 1066L +#define ERROR_PROCESS_ABORTED 1067L +#define ERROR_SERVICE_DEPENDENCY_FAIL 1068L +#define ERROR_SERVICE_LOGON_FAILED 1069L +#define ERROR_SERVICE_START_HANG 1070L +#define ERROR_INVALID_SERVICE_LOCK 1071L +#define ERROR_SERVICE_MARKED_FOR_DELETE 1072L +#define ERROR_SERVICE_EXISTS 1073L +#define ERROR_ALREADY_RUNNING_LKG 1074L +#define ERROR_SERVICE_DEPENDENCY_DELETED 1075L +#define ERROR_BOOT_ALREADY_ACCEPTED 1076L +#define ERROR_SERVICE_NEVER_STARTED 1077L +#define ERROR_DUPLICATE_SERVICE_NAME 1078L +#define ERROR_DIFFERENT_SERVICE_ACCOUNT 1079L +#define ERROR_CANNOT_DETECT_DRIVER_FAILURE 1080L +#define ERROR_CANNOT_DETECT_PROCESS_ABORT 1081L +#define ERROR_NO_RECOVERY_PROGRAM 1082L +#define ERROR_SERVICE_NOT_IN_EXE 1083L +#define ERROR_NOT_SAFEBOOT_SERVICE 1084L +#define ERROR_END_OF_MEDIA 1100L +#define ERROR_FILEMARK_DETECTED 1101L +#define ERROR_BEGINNING_OF_MEDIA 1102L +#define ERROR_SETMARK_DETECTED 1103L +#define ERROR_NO_DATA_DETECTED 1104L +#define ERROR_PARTITION_FAILURE 1105L +#define ERROR_INVALID_BLOCK_LENGTH 1106L +#define ERROR_DEVICE_NOT_PARTITIONED 1107L +#define ERROR_UNABLE_TO_LOCK_MEDIA 1108L +#define ERROR_UNABLE_TO_UNLOAD_MEDIA 1109L +#define ERROR_MEDIA_CHANGED 1110L +#define ERROR_BUS_RESET 1111L +#define ERROR_NO_MEDIA_IN_DRIVE 1112L +#define ERROR_NO_UNICODE_TRANSLATION 1113L +#define ERROR_DLL_INIT_FAILED 1114L +#define ERROR_SHUTDOWN_IN_PROGRESS 1115L +#define ERROR_NO_SHUTDOWN_IN_PROGRESS 1116L +#define ERROR_IO_DEVICE 1117L +#define ERROR_SERIAL_NO_DEVICE 1118L +#define ERROR_IRQ_BUSY 1119L +#define ERROR_MORE_WRITES 1120L +#define ERROR_COUNTER_TIMEOUT 1121L +#define ERROR_FLOPPY_ID_MARK_NOT_FOUND 1122L +#define ERROR_FLOPPY_WRONG_CYLINDER 1123L +#define ERROR_FLOPPY_UNKNOWN_ERROR 1124L +#define ERROR_FLOPPY_BAD_REGISTERS 1125L +#define ERROR_DISK_RECALIBRATE_FAILED 1126L +#define ERROR_DISK_OPERATION_FAILED 1127L +#define ERROR_DISK_RESET_FAILED 1128L +#define ERROR_EOM_OVERFLOW 1129L +#define ERROR_NOT_ENOUGH_SERVER_MEMORY 1130L +#define ERROR_POSSIBLE_DEADLOCK 1131L +#define ERROR_MAPPED_ALIGNMENT 1132L +#define ERROR_SET_POWER_STATE_VETOED 1140L +#define ERROR_SET_POWER_STATE_FAILED 1141L +#define ERROR_TOO_MANY_LINKS 1142L +#define ERROR_OLD_WIN_VERSION 1150L +#define ERROR_APP_WRONG_OS 1151L +#define ERROR_SINGLE_INSTANCE_APP 1152L +#define ERROR_RMODE_APP 1153L +#define ERROR_INVALID_DLL 1154L +#define ERROR_NO_ASSOCIATION 1155L +#define ERROR_DDE_FAIL 1156L +#define ERROR_DLL_NOT_FOUND 1157L +#define ERROR_NO_MORE_USER_HANDLES 1158L +#define ERROR_MESSAGE_SYNC_ONLY 1159L +#define ERROR_SOURCE_ELEMENT_EMPTY 1160L +#define ERROR_DESTINATION_ELEMENT_FULL 1161L +#define ERROR_ILLEGAL_ELEMENT_ADDRESS 1162L +#define ERROR_MAGAZINE_NOT_PRESENT 1163L +#define ERROR_DEVICE_REINITIALIZATION_NEEDED 1164L +#define ERROR_DEVICE_REQUIRES_CLEANING 1165L +#define ERROR_DEVICE_DOOR_OPEN 1166L +#define ERROR_DEVICE_NOT_CONNECTED 1167L +#define ERROR_NOT_FOUND 1168L +#define ERROR_NO_MATCH 1169L +#define ERROR_SET_NOT_FOUND 1170L +#define ERROR_POINT_NOT_FOUND 1171L +#define ERROR_NO_TRACKING_SERVICE 1172L +#define ERROR_NO_VOLUME_ID 1173L +#define ERROR_UNABLE_TO_REMOVE_REPLACED 1175L +#define ERROR_UNABLE_TO_MOVE_REPLACEMENT 1176L +#define ERROR_UNABLE_TO_MOVE_REPLACEMENT_2 1177L +#define ERROR_JOURNAL_DELETE_IN_PROGRESS 1178L +#define ERROR_JOURNAL_NOT_ACTIVE 1179L +#define ERROR_POTENTIAL_FILE_FOUND 1180L +#define ERROR_JOURNAL_ENTRY_DELETED 1181L +#define ERROR_BAD_DEVICE 1200L +#define ERROR_CONNECTION_UNAVAIL 1201L +#define ERROR_DEVICE_ALREADY_REMEMBERED 1202L +#define ERROR_NO_NET_OR_BAD_PATH 1203L +#define ERROR_BAD_PROVIDER 1204L +#define ERROR_CANNOT_OPEN_PROFILE 1205L +#define ERROR_BAD_PROFILE 1206L +#define ERROR_NOT_CONTAINER 1207L +#define ERROR_EXTENDED_ERROR 1208L +#define ERROR_INVALID_GROUPNAME 1209L +#define ERROR_INVALID_COMPUTERNAME 1210L +#define ERROR_INVALID_EVENTNAME 1211L +#define ERROR_INVALID_DOMAINNAME 1212L +#define ERROR_INVALID_SERVICENAME 1213L +#define ERROR_INVALID_NETNAME 1214L +#define ERROR_INVALID_SHARENAME 1215L +#define ERROR_INVALID_PASSWORDNAME 1216L +#define ERROR_INVALID_MESSAGENAME 1217L +#define ERROR_INVALID_MESSAGEDEST 1218L +#define ERROR_SESSION_CREDENTIAL_CONFLICT 1219L +#define ERROR_REMOTE_SESSION_LIMIT_EXCEEDED 1220L +#define ERROR_DUP_DOMAINNAME 1221L +#define ERROR_NO_NETWORK 1222L +#define ERROR_CANCELLED 1223L +#define ERROR_USER_MAPPED_FILE 1224L +#define ERROR_CONNECTION_REFUSED 1225L +#define ERROR_GRACEFUL_DISCONNECT 1226L +#define ERROR_ADDRESS_ALREADY_ASSOCIATED 1227L +#define ERROR_ADDRESS_NOT_ASSOCIATED 1228L +#define ERROR_CONNECTION_INVALID 1229L +#define ERROR_CONNECTION_ACTIVE 1230L +#define ERROR_NETWORK_UNREACHABLE 1231L +#define ERROR_HOST_UNREACHABLE 1232L +#define ERROR_PROTOCOL_UNREACHABLE 1233L +#define ERROR_PORT_UNREACHABLE 1234L +#define ERROR_REQUEST_ABORTED 1235L +#define ERROR_CONNECTION_ABORTED 1236L +#define ERROR_RETRY 1237L +#define ERROR_CONNECTION_COUNT_LIMIT 1238L +#define ERROR_LOGIN_TIME_RESTRICTION 1239L +#define ERROR_LOGIN_WKSTA_RESTRICTION 1240L +#define ERROR_INCORRECT_ADDRESS 1241L +#define ERROR_ALREADY_REGISTERED 1242L +#define ERROR_SERVICE_NOT_FOUND 1243L +#define ERROR_NOT_AUTHENTICATED 1244L +#define ERROR_NOT_LOGGED_ON 1245L +#define ERROR_CONTINUE 1246L +#define ERROR_ALREADY_INITIALIZED 1247L +#define ERROR_NO_MORE_DEVICES 1248L +#define ERROR_NO_SUCH_SITE 1249L +#define ERROR_DOMAIN_CONTROLLER_EXISTS 1250L +#define ERROR_ONLY_IF_CONNECTED 1251L +#define ERROR_OVERRIDE_NOCHANGES 1252L +#define ERROR_BAD_USER_PROFILE 1253L +#define ERROR_NOT_SUPPORTED_ON_SBS 1254L +#define ERROR_SERVER_SHUTDOWN_IN_PROGRESS 1255L +#define ERROR_HOST_DOWN 1256L +#define ERROR_NON_ACCOUNT_SID 1257L +#define ERROR_NON_DOMAIN_SID 1258L +#define ERROR_APPHELP_BLOCK 1259L +#define ERROR_ACCESS_DISABLED_BY_POLICY 1260L +#define ERROR_REG_NAT_CONSUMPTION 1261L +#define ERROR_CSCSHARE_OFFLINE 1262L +#define ERROR_PKINIT_FAILURE 1263L +#define ERROR_SMARTCARD_SUBSYSTEM_FAILURE 1264L +#define ERROR_DOWNGRADE_DETECTED 1265L +#define ERROR_MACHINE_LOCKED 1271L +#define ERROR_CALLBACK_SUPPLIED_INVALID_DATA 1273L +#define ERROR_SYNC_FOREGROUND_REFRESH_REQUIRED 1274L +#define ERROR_DRIVER_BLOCKED 1275L +#define ERROR_INVALID_IMPORT_OF_NON_DLL 1276L +#define ERROR_ACCESS_DISABLED_WEBBLADE 1277L +#define ERROR_ACCESS_DISABLED_WEBBLADE_TAMPER 1278L +#define ERROR_RECOVERY_FAILURE 1279L +#define ERROR_ALREADY_FIBER 1280L +#define ERROR_ALREADY_THREAD 1281L +#define ERROR_STACK_BUFFER_OVERRUN 1282L +#define ERROR_PARAMETER_QUOTA_EXCEEDED 1283L +#define ERROR_DEBUGGER_INACTIVE 1284L +#define ERROR_DELAY_LOAD_FAILED 1285L +#define ERROR_VDM_DISALLOWED 1286L +#define ERROR_UNIDENTIFIED_ERROR 1287L +#define ERROR_NOT_ALL_ASSIGNED 1300L +#define ERROR_SOME_NOT_MAPPED 1301L +#define ERROR_NO_QUOTAS_FOR_ACCOUNT 1302L +#define ERROR_LOCAL_USER_SESSION_KEY 1303L +#define ERROR_NULL_LM_PASSWORD 1304L +#define ERROR_UNKNOWN_REVISION 1305L +#define ERROR_REVISION_MISMATCH 1306L +#define ERROR_INVALID_OWNER 1307L +#define ERROR_INVALID_PRIMARY_GROUP 1308L +#define ERROR_NO_IMPERSONATION_TOKEN 1309L +#define ERROR_CANT_DISABLE_MANDATORY 1310L +#define ERROR_NO_LOGON_SERVERS 1311L +#define ERROR_NO_SUCH_LOGON_SESSION 1312L +#define ERROR_NO_SUCH_PRIVILEGE 1313L +#define ERROR_PRIVILEGE_NOT_HELD 1314L +#define ERROR_INVALID_ACCOUNT_NAME 1315L +#define ERROR_USER_EXISTS 1316L +#define ERROR_NO_SUCH_USER 1317L +#define ERROR_GROUP_EXISTS 1318L +#define ERROR_NO_SUCH_GROUP 1319L +#define ERROR_MEMBER_IN_GROUP 1320L +#define ERROR_MEMBER_NOT_IN_GROUP 1321L +#define ERROR_LAST_ADMIN 1322L +#define ERROR_WRONG_PASSWORD 1323L +#define ERROR_ILL_FORMED_PASSWORD 1324L +#define ERROR_PASSWORD_RESTRICTION 1325L +#define ERROR_LOGON_FAILURE 1326L +#define ERROR_ACCOUNT_RESTRICTION 1327L +#define ERROR_INVALID_LOGON_HOURS 1328L +#define ERROR_INVALID_WORKSTATION 1329L +#define ERROR_PASSWORD_EXPIRED 1330L +#define ERROR_ACCOUNT_DISABLED 1331L +#define ERROR_NONE_MAPPED 1332L +#define ERROR_TOO_MANY_LUIDS_REQUESTED 1333L +#define ERROR_LUIDS_EXHAUSTED 1334L +#define ERROR_INVALID_SUB_AUTHORITY 1335L +#define ERROR_INVALID_ACL 1336L +#define ERROR_INVALID_SID 1337L +#define ERROR_INVALID_SECURITY_DESCR 1338L +#define ERROR_BAD_INHERITANCE_ACL 1340L +#define ERROR_SERVER_DISABLED 1341L +#define ERROR_SERVER_NOT_DISABLED 1342L +#define ERROR_INVALID_ID_AUTHORITY 1343L +#define ERROR_ALLOTTED_SPACE_EXCEEDED 1344L +#define ERROR_INVALID_GROUP_ATTRIBUTES 1345L +#define ERROR_BAD_IMPERSONATION_LEVEL 1346L +#define ERROR_CANT_OPEN_ANONYMOUS 1347L +#define ERROR_BAD_VALIDATION_CLASS 1348L +#define ERROR_BAD_TOKEN_TYPE 1349L +#define ERROR_NO_SECURITY_ON_OBJECT 1350L +#define ERROR_CANT_ACCESS_DOMAIN_INFO 1351L +#define ERROR_INVALID_SERVER_STATE 1352L +#define ERROR_INVALID_DOMAIN_STATE 1353L +#define ERROR_INVALID_DOMAIN_ROLE 1354L +#define ERROR_NO_SUCH_DOMAIN 1355L +#define ERROR_DOMAIN_EXISTS 1356L +#define ERROR_DOMAIN_LIMIT_EXCEEDED 1357L +#define ERROR_INTERNAL_DB_CORRUPTION 1358L +#define ERROR_INTERNAL_ERROR 1359L +#define ERROR_GENERIC_NOT_MAPPED 1360L +#define ERROR_BAD_DESCRIPTOR_FORMAT 1361L +#define ERROR_NOT_LOGON_PROCESS 1362L +#define ERROR_LOGON_SESSION_EXISTS 1363L +#define ERROR_NO_SUCH_PACKAGE 1364L +#define ERROR_BAD_LOGON_SESSION_STATE 1365L +#define ERROR_LOGON_SESSION_COLLISION 1366L +#define ERROR_INVALID_LOGON_TYPE 1367L +#define ERROR_CANNOT_IMPERSONATE 1368L +#define ERROR_RXACT_INVALID_STATE 1369L +#define ERROR_RXACT_COMMIT_FAILURE 1370L +#define ERROR_SPECIAL_ACCOUNT 1371L +#define ERROR_SPECIAL_GROUP 1372L +#define ERROR_SPECIAL_USER 1373L +#define ERROR_MEMBERS_PRIMARY_GROUP 1374L +#define ERROR_TOKEN_ALREADY_IN_USE 1375L +#define ERROR_NO_SUCH_ALIAS 1376L +#define ERROR_MEMBER_NOT_IN_ALIAS 1377L +#define ERROR_MEMBER_IN_ALIAS 1378L +#define ERROR_ALIAS_EXISTS 1379L +#define ERROR_LOGON_NOT_GRANTED 1380L +#define ERROR_TOO_MANY_SECRETS 1381L +#define ERROR_SECRET_TOO_LONG 1382L +#define ERROR_INTERNAL_DB_ERROR 1383L +#define ERROR_TOO_MANY_CONTEXT_IDS 1384L +#define ERROR_LOGON_TYPE_NOT_GRANTED 1385L +#define ERROR_NT_CROSS_ENCRYPTION_REQUIRED 1386L +#define ERROR_NO_SUCH_MEMBER 1387L +#define ERROR_INVALID_MEMBER 1388L +#define ERROR_TOO_MANY_SIDS 1389L +#define ERROR_LM_CROSS_ENCRYPTION_REQUIRED 1390L +#define ERROR_NO_INHERITANCE 1391L +#define ERROR_FILE_CORRUPT 1392L +#define ERROR_DISK_CORRUPT 1393L +#define ERROR_NO_USER_SESSION_KEY 1394L +#define ERROR_LICENSE_QUOTA_EXCEEDED 1395L +#define ERROR_WRONG_TARGET_NAME 1396L +#define ERROR_MUTUAL_AUTH_FAILED 1397L +#define ERROR_TIME_SKEW 1398L +#define ERROR_CURRENT_DOMAIN_NOT_ALLOWED 1399L +#define ERROR_INVALID_WINDOW_HANDLE 1400L +#define ERROR_INVALID_MENU_HANDLE 1401L +#define ERROR_INVALID_CURSOR_HANDLE 1402L +#define ERROR_INVALID_ACCEL_HANDLE 1403L +#define ERROR_INVALID_HOOK_HANDLE 1404L +#define ERROR_INVALID_DWP_HANDLE 1405L +#define ERROR_TLW_WITH_WSCHILD 1406L +#define ERROR_CANNOT_FIND_WND_CLASS 1407L +#define ERROR_WINDOW_OF_OTHER_THREAD 1408L +#define ERROR_HOTKEY_ALREADY_REGISTERED 1409L +#define ERROR_CLASS_ALREADY_EXISTS 1410L +#define ERROR_CLASS_DOES_NOT_EXIST 1411L +#define ERROR_CLASS_HAS_WINDOWS 1412L +#define ERROR_INVALID_INDEX 1413L +#define ERROR_INVALID_ICON_HANDLE 1414L +#define ERROR_PRIVATE_DIALOG_INDEX 1415L +#define ERROR_LISTBOX_ID_NOT_FOUND 1416L +#define ERROR_NO_WILDCARD_CHARACTERS 1417L +#define ERROR_CLIPBOARD_NOT_OPEN 1418L +#define ERROR_HOTKEY_NOT_REGISTERED 1419L +#define ERROR_WINDOW_NOT_DIALOG 1420L +#define ERROR_CONTROL_ID_NOT_FOUND 1421L +#define ERROR_INVALID_COMBOBOX_MESSAGE 1422L +#define ERROR_WINDOW_NOT_COMBOBOX 1423L +#define ERROR_INVALID_EDIT_HEIGHT 1424L +#define ERROR_DC_NOT_FOUND 1425L +#define ERROR_INVALID_HOOK_FILTER 1426L +#define ERROR_INVALID_FILTER_PROC 1427L +#define ERROR_HOOK_NEEDS_HMOD 1428L +#define ERROR_GLOBAL_ONLY_HOOK 1429L +#define ERROR_JOURNAL_HOOK_SET 1430L +#define ERROR_HOOK_NOT_INSTALLED 1431L +#define ERROR_INVALID_LB_MESSAGE 1432L +#define ERROR_SETCOUNT_ON_BAD_LB 1433L +#define ERROR_LB_WITHOUT_TABSTOPS 1434L +#define ERROR_DESTROY_OBJECT_OF_OTHER_THREAD 1435L +#define ERROR_CHILD_WINDOW_MENU 1436L +#define ERROR_NO_SYSTEM_MENU 1437L +#define ERROR_INVALID_MSGBOX_STYLE 1438L +#define ERROR_INVALID_SPI_VALUE 1439L +#define ERROR_SCREEN_ALREADY_LOCKED 1440L +#define ERROR_HWNDS_HAVE_DIFF_PARENT 1441L +#define ERROR_NOT_CHILD_WINDOW 1442L +#define ERROR_INVALID_GW_COMMAND 1443L +#define ERROR_INVALID_THREAD_ID 1444L +#define ERROR_NON_MDICHILD_WINDOW 1445L +#define ERROR_POPUP_ALREADY_ACTIVE 1446L +#define ERROR_NO_SCROLLBARS 1447L +#define ERROR_INVALID_SCROLLBAR_RANGE 1448L +#define ERROR_INVALID_SHOWWIN_COMMAND 1449L +#define ERROR_NO_SYSTEM_RESOURCES 1450L +#define ERROR_NONPAGED_SYSTEM_RESOURCES 1451L +#define ERROR_PAGED_SYSTEM_RESOURCES 1452L +#define ERROR_WORKING_SET_QUOTA 1453L +#define ERROR_PAGEFILE_QUOTA 1454L +#define ERROR_COMMITMENT_LIMIT 1455L +#define ERROR_MENU_ITEM_NOT_FOUND 1456L +#define ERROR_INVALID_KEYBOARD_HANDLE 1457L +#define ERROR_HOOK_TYPE_NOT_ALLOWED 1458L +#define ERROR_REQUIRES_INTERACTIVE_WINDOWSTATION 1459L +#define ERROR_TIMEOUT 1460L +#define ERROR_INVALID_MONITOR_HANDLE 1461L +#define ERROR_INCORRECT_SIZE 1462L +#define ERROR_EVENTLOG_FILE_CORRUPT 1500L +#define ERROR_EVENTLOG_CANT_START 1501L +#define ERROR_LOG_FILE_FULL 1502L +#define ERROR_EVENTLOG_FILE_CHANGED 1503L +#define ERROR_INSTALL_SERVICE_FAILURE 1601L +#define ERROR_INSTALL_USEREXIT 1602L +#define ERROR_INSTALL_FAILURE 1603L +#define ERROR_INSTALL_SUSPEND 1604L +#define ERROR_UNKNOWN_PRODUCT 1605L +#define ERROR_UNKNOWN_FEATURE 1606L +#define ERROR_UNKNOWN_COMPONENT 1607L +#define ERROR_UNKNOWN_PROPERTY 1608L +#define ERROR_INVALID_HANDLE_STATE 1609L +#define ERROR_BAD_CONFIGURATION 1610L +#define ERROR_INDEX_ABSENT 1611L +#define ERROR_INSTALL_SOURCE_ABSENT 1612L +#define ERROR_INSTALL_PACKAGE_VERSION 1613L +#define ERROR_PRODUCT_UNINSTALLED 1614L +#define ERROR_BAD_QUERY_SYNTAX 1615L +#define ERROR_INVALID_FIELD 1616L +#define ERROR_DEVICE_REMOVED 1617L +#define ERROR_INSTALL_ALREADY_RUNNING 1618L +#define ERROR_INSTALL_PACKAGE_OPEN_FAILED 1619L +#define ERROR_INSTALL_PACKAGE_INVALID 1620L +#define ERROR_INSTALL_UI_FAILURE 1621L +#define ERROR_INSTALL_LOG_FAILURE 1622L +#define ERROR_INSTALL_LANGUAGE_UNSUPPORTED 1623L +#define ERROR_INSTALL_TRANSFORM_FAILURE 1624L +#define ERROR_INSTALL_PACKAGE_REJECTED 1625L +#define ERROR_FUNCTION_NOT_CALLED 1626L +#define ERROR_FUNCTION_FAILED 1627L +#define ERROR_INVALID_TABLE 1628L +#define ERROR_DATATYPE_MISMATCH 1629L +#define ERROR_UNSUPPORTED_TYPE 1630L +#define ERROR_CREATE_FAILED 1631L +#define ERROR_INSTALL_TEMP_UNWRITABLE 1632L +#define ERROR_INSTALL_PLATFORM_UNSUPPORTED 1633L +#define ERROR_INSTALL_NOTUSED 1634L +#define ERROR_PATCH_PACKAGE_OPEN_FAILED 1635L +#define ERROR_PATCH_PACKAGE_INVALID 1636L +#define ERROR_PATCH_PACKAGE_UNSUPPORTED 1637L +#define ERROR_PRODUCT_VERSION 1638L +#define ERROR_INVALID_COMMAND_LINE 1639L +#define ERROR_INSTALL_REMOTE_DISALLOWED 1640L +#define ERROR_SUCCESS_REBOOT_INITIATED 1641L +#define ERROR_PATCH_TARGET_NOT_FOUND 1642L +#define ERROR_PATCH_PACKAGE_REJECTED 1643L +#define ERROR_INSTALL_TRANSFORM_REJECTED 1644L +#define ERROR_INSTALL_REMOTE_PROHIBITED 1645L +#define RPC_S_INVALID_STRING_BINDING 1700L +#define RPC_S_WRONG_KIND_OF_BINDING 1701L +#define RPC_S_INVALID_BINDING 1702L +#define RPC_S_PROTSEQ_NOT_SUPPORTED 1703L +#define RPC_S_INVALID_RPC_PROTSEQ 1704L +#define RPC_S_INVALID_STRING_UUID 1705L +#define RPC_S_INVALID_ENDPOINT_FORMAT 1706L +#define RPC_S_INVALID_NET_ADDR 1707L +#define RPC_S_NO_ENDPOINT_FOUND 1708L +#define RPC_S_INVALID_TIMEOUT 1709L +#define RPC_S_OBJECT_NOT_FOUND 1710L +#define RPC_S_ALREADY_REGISTERED 1711L +#define RPC_S_TYPE_ALREADY_REGISTERED 1712L +#define RPC_S_ALREADY_LISTENING 1713L +#define RPC_S_NO_PROTSEQS_REGISTERED 1714L +#define RPC_S_NOT_LISTENING 1715L +#define RPC_S_UNKNOWN_MGR_TYPE 1716L +#define RPC_S_UNKNOWN_IF 1717L +#define RPC_S_NO_BINDINGS 1718L +#define RPC_S_NO_PROTSEQS 1719L +#define RPC_S_CANT_CREATE_ENDPOINT 1720L +#define RPC_S_OUT_OF_RESOURCES 1721L +#define RPC_S_SERVER_UNAVAILABLE 1722L +#define RPC_S_SERVER_TOO_BUSY 1723L +#define RPC_S_INVALID_NETWORK_OPTIONS 1724L +#define RPC_S_NO_CALL_ACTIVE 1725L +#define RPC_S_CALL_FAILED 1726L +#define RPC_S_CALL_FAILED_DNE 1727L +#define RPC_S_PROTOCOL_ERROR 1728L +#define RPC_S_UNSUPPORTED_TRANS_SYN 1730L +#define RPC_S_UNSUPPORTED_TYPE 1732L +#define RPC_S_INVALID_TAG 1733L +#define RPC_S_INVALID_BOUND 1734L +#define RPC_S_NO_ENTRY_NAME 1735L +#define RPC_S_INVALID_NAME_SYNTAX 1736L +#define RPC_S_UNSUPPORTED_NAME_SYNTAX 1737L +#define RPC_S_UUID_NO_ADDRESS 1739L +#define RPC_S_DUPLICATE_ENDPOINT 1740L +#define RPC_S_UNKNOWN_AUTHN_TYPE 1741L +#define RPC_S_MAX_CALLS_TOO_SMALL 1742L +#define RPC_S_STRING_TOO_LONG 1743L +#define RPC_S_PROTSEQ_NOT_FOUND 1744L +#define RPC_S_PROCNUM_OUT_OF_RANGE 1745L +#define RPC_S_BINDING_HAS_NO_AUTH 1746L +#define RPC_S_UNKNOWN_AUTHN_SERVICE 1747L +#define RPC_S_UNKNOWN_AUTHN_LEVEL 1748L +#define RPC_S_INVALID_AUTH_IDENTITY 1749L +#define RPC_S_UNKNOWN_AUTHZ_SERVICE 1750L +#define EPT_S_INVALID_ENTRY 1751L +#define EPT_S_CANT_PERFORM_OP 1752L +#define EPT_S_NOT_REGISTERED 1753L +#define RPC_S_NOTHING_TO_EXPORT 1754L +#define RPC_S_INCOMPLETE_NAME 1755L +#define RPC_S_INVALID_VERS_OPTION 1756L +#define RPC_S_NO_MORE_MEMBERS 1757L +#define RPC_S_NOT_ALL_OBJS_UNEXPORTED 1758L +#define RPC_S_INTERFACE_NOT_FOUND 1759L +#define RPC_S_ENTRY_ALREADY_EXISTS 1760L +#define RPC_S_ENTRY_NOT_FOUND 1761L +#define RPC_S_NAME_SERVICE_UNAVAILABLE 1762L +#define RPC_S_INVALID_NAF_ID 1763L +#define RPC_S_CANNOT_SUPPORT 1764L +#define RPC_S_NO_CONTEXT_AVAILABLE 1765L +#define RPC_S_INTERNAL_ERROR 1766L +#define RPC_S_ZERO_DIVIDE 1767L +#define RPC_S_ADDRESS_ERROR 1768L +#define RPC_S_FP_DIV_ZERO 1769L +#define RPC_S_FP_UNDERFLOW 1770L +#define RPC_S_FP_OVERFLOW 1771L +#define RPC_X_NO_MORE_ENTRIES 1772L +#define RPC_X_SS_CHAR_TRANS_OPEN_FAIL 1773L +#define RPC_X_SS_CHAR_TRANS_SHORT_FILE 1774L +#define RPC_X_SS_IN_NULL_CONTEXT 1775L +#define RPC_X_SS_CONTEXT_DAMAGED 1777L +#define RPC_X_SS_HANDLES_MISMATCH 1778L +#define RPC_X_SS_CANNOT_GET_CALL_HANDLE 1779L +#define RPC_X_NULL_REF_POINTER 1780L +#define RPC_X_ENUM_VALUE_OUT_OF_RANGE 1781L +#define RPC_X_BYTE_COUNT_TOO_SMALL 1782L +#define RPC_X_BAD_STUB_DATA 1783L +#define ERROR_INVALID_USER_BUFFER 1784L +#define ERROR_UNRECOGNIZED_MEDIA 1785L +#define ERROR_NO_TRUST_LSA_SECRET 1786L +#define ERROR_NO_TRUST_SAM_ACCOUNT 1787L +#define ERROR_TRUSTED_DOMAIN_FAILURE 1788L +#define ERROR_TRUSTED_RELATIONSHIP_FAILURE 1789L +#define ERROR_TRUST_FAILURE 1790L +#define RPC_S_CALL_IN_PROGRESS 1791L +#define ERROR_NETLOGON_NOT_STARTED 1792L +#define ERROR_ACCOUNT_EXPIRED 1793L +#define ERROR_REDIRECTOR_HAS_OPEN_HANDLES 1794L +#define ERROR_PRINTER_DRIVER_ALREADY_INSTALLED 1795L +#define ERROR_UNKNOWN_PORT 1796L +#define ERROR_UNKNOWN_PRINTER_DRIVER 1797L +#define ERROR_UNKNOWN_PRINTPROCESSOR 1798L +#define ERROR_INVALID_SEPARATOR_FILE 1799L +#define ERROR_INVALID_PRIORITY 1800L +#define ERROR_INVALID_PRINTER_NAME 1801L +#define ERROR_PRINTER_ALREADY_EXISTS 1802L +#define ERROR_INVALID_PRINTER_COMMAND 1803L +#define ERROR_INVALID_DATATYPE 1804L +#define ERROR_INVALID_ENVIRONMENT 1805L +#define RPC_S_NO_MORE_BINDINGS 1806L +#define ERROR_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT 1807L +#define ERROR_NOLOGON_WORKSTATION_TRUST_ACCOUNT 1808L +#define ERROR_NOLOGON_SERVER_TRUST_ACCOUNT 1809L +#define ERROR_DOMAIN_TRUST_INCONSISTENT 1810L +#define ERROR_SERVER_HAS_OPEN_HANDLES 1811L +#define ERROR_RESOURCE_DATA_NOT_FOUND 1812L +#define ERROR_RESOURCE_TYPE_NOT_FOUND 1813L +#define ERROR_RESOURCE_NAME_NOT_FOUND 1814L +#define ERROR_RESOURCE_LANG_NOT_FOUND 1815L +#define ERROR_NOT_ENOUGH_QUOTA 1816L +#define RPC_S_NO_INTERFACES 1817L +#define RPC_S_CALL_CANCELLED 1818L +#define RPC_S_BINDING_INCOMPLETE 1819L +#define RPC_S_COMM_FAILURE 1820L +#define RPC_S_UNSUPPORTED_AUTHN_LEVEL 1821L +#define RPC_S_NO_PRINC_NAME 1822L +#define RPC_S_NOT_RPC_ERROR 1823L +#define RPC_S_UUID_LOCAL_ONLY 1824L +#define RPC_S_SEC_PKG_ERROR 1825L +#define RPC_S_NOT_CANCELLED 1826L +#define RPC_X_INVALID_ES_ACTION 1827L +#define RPC_X_WRONG_ES_VERSION 1828L +#define RPC_X_WRONG_STUB_VERSION 1829L +#define RPC_X_INVALID_PIPE_OBJECT 1830L +#define RPC_X_WRONG_PIPE_ORDER 1831L +#define RPC_X_WRONG_PIPE_VERSION 1832L +#define RPC_S_GROUP_MEMBER_NOT_FOUND 1898L +#define EPT_S_CANT_CREATE 1899L +#define RPC_S_INVALID_OBJECT 1900L +#define ERROR_INVALID_TIME 1901L +#define ERROR_INVALID_FORM_NAME 1902L +#define ERROR_INVALID_FORM_SIZE 1903L +#define ERROR_ALREADY_WAITING 1904L +#define ERROR_PRINTER_DELETED 1905L +#define ERROR_INVALID_PRINTER_STATE 1906L +#define ERROR_PASSWORD_MUST_CHANGE 1907L +#define ERROR_DOMAIN_CONTROLLER_NOT_FOUND 1908L +#define ERROR_ACCOUNT_LOCKED_OUT 1909L +#define OR_INVALID_OXID 1910L +#define OR_INVALID_OID 1911L +#define OR_INVALID_SET 1912L +#define RPC_S_SEND_INCOMPLETE 1913L +#define RPC_S_INVALID_ASYNC_HANDLE 1914L +#define RPC_S_INVALID_ASYNC_CALL 1915L +#define RPC_X_PIPE_CLOSED 1916L +#define RPC_X_PIPE_DISCIPLINE_ERROR 1917L +#define RPC_X_PIPE_EMPTY 1918L +#define ERROR_NO_SITENAME 1919L +#define ERROR_CANT_ACCESS_FILE 1920L +#define ERROR_CANT_RESOLVE_FILENAME 1921L +#define RPC_S_ENTRY_TYPE_MISMATCH 1922L +#define RPC_S_NOT_ALL_OBJS_EXPORTED 1923L +#define RPC_S_INTERFACE_NOT_EXPORTED 1924L +#define RPC_S_PROFILE_NOT_ADDED 1925L +#define RPC_S_PRF_ELT_NOT_ADDED 1926L +#define RPC_S_PRF_ELT_NOT_REMOVED 1927L +#define RPC_S_GRP_ELT_NOT_ADDED 1928L +#define RPC_S_GRP_ELT_NOT_REMOVED 1929L +#define ERROR_KM_DRIVER_BLOCKED 1930L +#define ERROR_CONTEXT_EXPIRED 1931L +#define ERROR_PER_USER_TRUST_QUOTA_EXCEEDED 1932L +#define ERROR_ALL_USER_TRUST_QUOTA_EXCEEDED 1933L +#define ERROR_USER_DELETE_TRUST_QUOTA_EXCEEDED 1934L +#define ERROR_AUTHENTICATION_FIREWALL_FAILED 1935L +#define ERROR_REMOTE_PRINT_CONNECTIONS_BLOCKED 1936L +#define ERROR_INVALID_PIXEL_FORMAT 2000L +#define ERROR_BAD_DRIVER 2001L +#define ERROR_INVALID_WINDOW_STYLE 2002L +#define ERROR_METAFILE_NOT_SUPPORTED 2003L +#define ERROR_TRANSFORM_NOT_SUPPORTED 2004L +#define ERROR_CLIPPING_NOT_SUPPORTED 2005L +#define ERROR_INVALID_CMM 2010L +#define ERROR_INVALID_PROFILE 2011L +#define ERROR_TAG_NOT_FOUND 2012L +#define ERROR_TAG_NOT_PRESENT 2013L +#define ERROR_DUPLICATE_TAG 2014L +#define ERROR_PROFILE_NOT_ASSOCIATED_WITH_DEVICE 2015L +#define ERROR_PROFILE_NOT_FOUND 2016L +#define ERROR_INVALID_COLORSPACE 2017L +#define ERROR_ICM_NOT_ENABLED 2018L +#define ERROR_DELETING_ICM_XFORM 2019L +#define ERROR_INVALID_TRANSFORM 2020L +#define ERROR_COLORSPACE_MISMATCH 2021L +#define ERROR_INVALID_COLORINDEX 2022L +#define ERROR_CONNECTED_OTHER_PASSWORD 2108L +#define ERROR_CONNECTED_OTHER_PASSWORD_DEFAULT 2109L +#define ERROR_BAD_USERNAME 2202L +#define ERROR_NOT_CONNECTED 2250L +#define ERROR_OPEN_FILES 2401L +#define ERROR_ACTIVE_CONNECTIONS 2402L +#define ERROR_DEVICE_IN_USE 2404L +#define ERROR_UNKNOWN_PRINT_MONITOR 3000L +#define ERROR_PRINTER_DRIVER_IN_USE 3001L +#define ERROR_SPOOL_FILE_NOT_FOUND 3002L +#define ERROR_SPL_NO_STARTDOC 3003L +#define ERROR_SPL_NO_ADDJOB 3004L +#define ERROR_PRINT_PROCESSOR_ALREADY_INSTALLED 3005L +#define ERROR_PRINT_MONITOR_ALREADY_INSTALLED 3006L +#define ERROR_INVALID_PRINT_MONITOR 3007L +#define ERROR_PRINT_MONITOR_IN_USE 3008L +#define ERROR_PRINTER_HAS_JOBS_QUEUED 3009L +#define ERROR_SUCCESS_REBOOT_REQUIRED 3010L +#define ERROR_SUCCESS_RESTART_REQUIRED 3011L +#define ERROR_PRINTER_NOT_FOUND 3012L +#define ERROR_PRINTER_DRIVER_WARNED 3013L +#define ERROR_PRINTER_DRIVER_BLOCKED 3014L +#define ERROR_WINS_INTERNAL 4000L +#define ERROR_CAN_NOT_DEL_LOCAL_WINS 4001L +#define ERROR_STATIC_INIT 4002L +#define ERROR_INC_BACKUP 4003L +#define ERROR_FULL_BACKUP 4004L +#define ERROR_REC_NON_EXISTENT 4005L +#define ERROR_RPL_NOT_ALLOWED 4006L +#define ERROR_DHCP_ADDRESS_CONFLICT 4100L +#define ERROR_WMI_GUID_NOT_FOUND 4200L +#define ERROR_WMI_INSTANCE_NOT_FOUND 4201L +#define ERROR_WMI_ITEMID_NOT_FOUND 4202L +#define ERROR_WMI_TRY_AGAIN 4203L +#define ERROR_WMI_DP_NOT_FOUND 4204L +#define ERROR_WMI_UNRESOLVED_INSTANCE_REF 4205L +#define ERROR_WMI_ALREADY_ENABLED 4206L +#define ERROR_WMI_GUID_DISCONNECTED 4207L +#define ERROR_WMI_SERVER_UNAVAILABLE 4208L +#define ERROR_WMI_DP_FAILED 4209L +#define ERROR_WMI_INVALID_MOF 4210L +#define ERROR_WMI_INVALID_REGINFO 4211L +#define ERROR_WMI_ALREADY_DISABLED 4212L +#define ERROR_WMI_READ_ONLY 4213L +#define ERROR_WMI_SET_FAILURE 4214L +#define ERROR_INVALID_MEDIA 4300L +#define ERROR_INVALID_LIBRARY 4301L +#define ERROR_INVALID_MEDIA_POOL 4302L +#define ERROR_DRIVE_MEDIA_MISMATCH 4303L +#define ERROR_MEDIA_OFFLINE 4304L +#define ERROR_LIBRARY_OFFLINE 4305L +#define ERROR_EMPTY 4306L +#define ERROR_NOT_EMPTY 4307L +#define ERROR_MEDIA_UNAVAILABLE 4308L +#define ERROR_RESOURCE_DISABLED 4309L +#define ERROR_INVALID_CLEANER 4310L +#define ERROR_UNABLE_TO_CLEAN 4311L +#define ERROR_OBJECT_NOT_FOUND 4312L +#define ERROR_DATABASE_FAILURE 4313L +#define ERROR_DATABASE_FULL 4314L +#define ERROR_MEDIA_INCOMPATIBLE 4315L +#define ERROR_RESOURCE_NOT_PRESENT 4316L +#define ERROR_INVALID_OPERATION 4317L +#define ERROR_MEDIA_NOT_AVAILABLE 4318L +#define ERROR_DEVICE_NOT_AVAILABLE 4319L +#define ERROR_REQUEST_REFUSED 4320L +#define ERROR_INVALID_DRIVE_OBJECT 4321L +#define ERROR_LIBRARY_FULL 4322L +#define ERROR_MEDIUM_NOT_ACCESSIBLE 4323L +#define ERROR_UNABLE_TO_LOAD_MEDIUM 4324L +#define ERROR_UNABLE_TO_INVENTORY_DRIVE 4325L +#define ERROR_UNABLE_TO_INVENTORY_SLOT 4326L +#define ERROR_UNABLE_TO_INVENTORY_TRANSPORT 4327L +#define ERROR_TRANSPORT_FULL 4328L +#define ERROR_CONTROLLING_IEPORT 4329L +#define ERROR_UNABLE_TO_EJECT_MOUNTED_MEDIA 4330L +#define ERROR_CLEANER_SLOT_SET 4331L +#define ERROR_CLEANER_SLOT_NOT_SET 4332L +#define ERROR_CLEANER_CARTRIDGE_SPENT 4333L +#define ERROR_UNEXPECTED_OMID 4334L +#define ERROR_CANT_DELETE_LAST_ITEM 4335L +#define ERROR_MESSAGE_EXCEEDS_MAX_SIZE 4336L +#define ERROR_VOLUME_CONTAINS_SYS_FILES 4337L +#define ERROR_INDIGENOUS_TYPE 4338L +#define ERROR_NO_SUPPORTING_DRIVES 4339L +#define ERROR_CLEANER_CARTRIDGE_INSTALLED 4340L +#define ERROR_IEPORT_FULL 4341L +#define ERROR_FILE_OFFLINE 4350L +#define ERROR_REMOTE_STORAGE_NOT_ACTIVE 4351L +#define ERROR_REMOTE_STORAGE_MEDIA_ERROR 4352L +#define ERROR_NOT_A_REPARSE_POINT 4390L +#define ERROR_REPARSE_ATTRIBUTE_CONFLICT 4391L +#define ERROR_INVALID_REPARSE_DATA 4392L +#define ERROR_REPARSE_TAG_INVALID 4393L +#define ERROR_REPARSE_TAG_MISMATCH 4394L +#define ERROR_VOLUME_NOT_SIS_ENABLED 4500L +#define ERROR_DEPENDENT_RESOURCE_EXISTS 5001L +#define ERROR_DEPENDENCY_NOT_FOUND 5002L +#define ERROR_DEPENDENCY_ALREADY_EXISTS 5003L +#define ERROR_RESOURCE_NOT_ONLINE 5004L +#define ERROR_HOST_NODE_NOT_AVAILABLE 5005L +#define ERROR_RESOURCE_NOT_AVAILABLE 5006L +#define ERROR_RESOURCE_NOT_FOUND 5007L +#define ERROR_SHUTDOWN_CLUSTER 5008L +#define ERROR_CANT_EVICT_ACTIVE_NODE 5009L +#define ERROR_OBJECT_ALREADY_EXISTS 5010L +#define ERROR_OBJECT_IN_LIST 5011L +#define ERROR_GROUP_NOT_AVAILABLE 5012L +#define ERROR_GROUP_NOT_FOUND 5013L +#define ERROR_GROUP_NOT_ONLINE 5014L +#define ERROR_HOST_NODE_NOT_RESOURCE_OWNER 5015L +#define ERROR_HOST_NODE_NOT_GROUP_OWNER 5016L +#define ERROR_RESMON_CREATE_FAILED 5017L +#define ERROR_RESMON_ONLINE_FAILED 5018L +#define ERROR_RESOURCE_ONLINE 5019L +#define ERROR_QUORUM_RESOURCE 5020L +#define ERROR_NOT_QUORUM_CAPABLE 5021L +#define ERROR_CLUSTER_SHUTTING_DOWN 5022L +#define ERROR_INVALID_STATE 5023L +#define ERROR_RESOURCE_PROPERTIES_STORED 5024L +#define ERROR_NOT_QUORUM_CLASS 5025L +#define ERROR_CORE_RESOURCE 5026L +#define ERROR_QUORUM_RESOURCE_ONLINE_FAILED 5027L +#define ERROR_QUORUMLOG_OPEN_FAILED 5028L +#define ERROR_CLUSTERLOG_CORRUPT 5029L +#define ERROR_CLUSTERLOG_RECORD_EXCEEDS_MAXSIZE 5030L +#define ERROR_CLUSTERLOG_EXCEEDS_MAXSIZE 5031L +#define ERROR_CLUSTERLOG_CHKPOINT_NOT_FOUND 5032L +#define ERROR_CLUSTERLOG_NOT_ENOUGH_SPACE 5033L +#define ERROR_QUORUM_OWNER_ALIVE 5034L +#define ERROR_NETWORK_NOT_AVAILABLE 5035L +#define ERROR_NODE_NOT_AVAILABLE 5036L +#define ERROR_ALL_NODES_NOT_AVAILABLE 5037L +#define ERROR_RESOURCE_FAILED 5038L +#define ERROR_CLUSTER_INVALID_NODE 5039L +#define ERROR_CLUSTER_NODE_EXISTS 5040L +#define ERROR_CLUSTER_JOIN_IN_PROGRESS 5041L +#define ERROR_CLUSTER_NODE_NOT_FOUND 5042L +#define ERROR_CLUSTER_LOCAL_NODE_NOT_FOUND 5043L +#define ERROR_CLUSTER_NETWORK_EXISTS 5044L +#define ERROR_CLUSTER_NETWORK_NOT_FOUND 5045L +#define ERROR_CLUSTER_NETINTERFACE_EXISTS 5046L +#define ERROR_CLUSTER_NETINTERFACE_NOT_FOUND 5047L +#define ERROR_CLUSTER_INVALID_REQUEST 5048L +#define ERROR_CLUSTER_INVALID_NETWORK_PROVIDER 5049L +#define ERROR_CLUSTER_NODE_DOWN 5050L +#define ERROR_CLUSTER_NODE_UNREACHABLE 5051L +#define ERROR_CLUSTER_NODE_NOT_MEMBER 5052L +#define ERROR_CLUSTER_JOIN_NOT_IN_PROGRESS 5053L +#define ERROR_CLUSTER_INVALID_NETWORK 5054L +#define ERROR_CLUSTER_NODE_UP 5056L +#define ERROR_CLUSTER_IPADDR_IN_USE 5057L +#define ERROR_CLUSTER_NODE_NOT_PAUSED 5058L +#define ERROR_CLUSTER_NO_SECURITY_CONTEXT 5059L +#define ERROR_CLUSTER_NETWORK_NOT_INTERNAL 5060L +#define ERROR_CLUSTER_NODE_ALREADY_UP 5061L +#define ERROR_CLUSTER_NODE_ALREADY_DOWN 5062L +#define ERROR_CLUSTER_NETWORK_ALREADY_ONLINE 5063L +#define ERROR_CLUSTER_NETWORK_ALREADY_OFFLINE 5064L +#define ERROR_CLUSTER_NODE_ALREADY_MEMBER 5065L +#define ERROR_CLUSTER_LAST_INTERNAL_NETWORK 5066L +#define ERROR_CLUSTER_NETWORK_HAS_DEPENDENTS 5067L +#define ERROR_INVALID_OPERATION_ON_QUORUM 5068L +#define ERROR_DEPENDENCY_NOT_ALLOWED 5069L +#define ERROR_CLUSTER_NODE_PAUSED 5070L +#define ERROR_NODE_CANT_HOST_RESOURCE 5071L +#define ERROR_CLUSTER_NODE_NOT_READY 5072L +#define ERROR_CLUSTER_NODE_SHUTTING_DOWN 5073L +#define ERROR_CLUSTER_JOIN_ABORTED 5074L +#define ERROR_CLUSTER_INCOMPATIBLE_VERSIONS 5075L +#define ERROR_CLUSTER_MAXNUM_OF_RESOURCES_EXCEEDED 5076L +#define ERROR_CLUSTER_SYSTEM_CONFIG_CHANGED 5077L +#define ERROR_CLUSTER_RESOURCE_TYPE_NOT_FOUND 5078L +#define ERROR_CLUSTER_RESTYPE_NOT_SUPPORTED 5079L +#define ERROR_CLUSTER_RESNAME_NOT_FOUND 5080L +#define ERROR_CLUSTER_NO_RPC_PACKAGES_REGISTERED 5081L +#define ERROR_CLUSTER_OWNER_NOT_IN_PREFLIST 5082L +#define ERROR_CLUSTER_DATABASE_SEQMISMATCH 5083L +#define ERROR_RESMON_INVALID_STATE 5084L +#define ERROR_CLUSTER_GUM_NOT_LOCKER 5085L +#define ERROR_QUORUM_DISK_NOT_FOUND 5086L +#define ERROR_DATABASE_BACKUP_CORRUPT 5087L +#define ERROR_CLUSTER_NODE_ALREADY_HAS_DFS_ROOT 5088L +#define ERROR_RESOURCE_PROPERTY_UNCHANGEABLE 5089L +#define ERROR_CLUSTER_MEMBERSHIP_INVALID_STATE 5890L +#define ERROR_CLUSTER_QUORUMLOG_NOT_FOUND 5891L +#define ERROR_CLUSTER_MEMBERSHIP_HALT 5892L +#define ERROR_CLUSTER_INSTANCE_ID_MISMATCH 5893L +#define ERROR_CLUSTER_NETWORK_NOT_FOUND_FOR_IP 5894L +#define ERROR_CLUSTER_PROPERTY_DATA_TYPE_MISMATCH 5895L +#define ERROR_CLUSTER_EVICT_WITHOUT_CLEANUP 5896L +#define ERROR_CLUSTER_PARAMETER_MISMATCH 5897L +#define ERROR_NODE_CANNOT_BE_CLUSTERED 5898L +#define ERROR_CLUSTER_WRONG_OS_VERSION 5899L +#define ERROR_CLUSTER_CANT_CREATE_DUP_CLUSTER_NAME 5900L +#define ERROR_CLUSCFG_ALREADY_COMMITTED 5901L +#define ERROR_CLUSCFG_ROLLBACK_FAILED 5902L +#define ERROR_CLUSCFG_SYSTEM_DISK_DRIVE_LETTER_CONFLICT 5903L +#define ERROR_CLUSTER_OLD_VERSION 5904L +#define ERROR_CLUSTER_MISMATCHED_COMPUTER_ACCT_NAME 5905L +#define ERROR_ENCRYPTION_FAILED 6000L +#define ERROR_DECRYPTION_FAILED 6001L +#define ERROR_FILE_ENCRYPTED 6002L +#define ERROR_NO_RECOVERY_POLICY 6003L +#define ERROR_NO_EFS 6004L +#define ERROR_WRONG_EFS 6005L +#define ERROR_NO_USER_KEYS 6006L +#define ERROR_FILE_NOT_ENCRYPTED 6007L +#define ERROR_NOT_EXPORT_FORMAT 6008L +#define ERROR_FILE_READ_ONLY 6009L +#define ERROR_DIR_EFS_DISALLOWED 6010L +#define ERROR_EFS_SERVER_NOT_TRUSTED 6011L +#define ERROR_BAD_RECOVERY_POLICY 6012L +#define ERROR_EFS_ALG_BLOB_TOO_BIG 6013L +#define ERROR_VOLUME_NOT_SUPPORT_EFS 6014L +#define ERROR_EFS_DISABLED 6015L +#define ERROR_EFS_VERSION_NOT_SUPPORT 6016L +#define ERROR_NO_BROWSER_SERVERS_FOUND 6118L +#define SCHED_E_SERVICE_NOT_LOCALSYSTEM 6200L +#define ERROR_CTX_WINSTATION_NAME_INVALID 7001L +#define ERROR_CTX_INVALID_PD 7002L +#define ERROR_CTX_PD_NOT_FOUND 7003L +#define ERROR_CTX_WD_NOT_FOUND 7004L +#define ERROR_CTX_CANNOT_MAKE_EVENTLOG_ENTRY 7005L +#define ERROR_CTX_SERVICE_NAME_COLLISION 7006L +#define ERROR_CTX_CLOSE_PENDING 7007L +#define ERROR_CTX_NO_OUTBUF 7008L +#define ERROR_CTX_MODEM_INF_NOT_FOUND 7009L +#define ERROR_CTX_INVALID_MODEMNAME 7010L +#define ERROR_CTX_MODEM_RESPONSE_ERROR 7011L +#define ERROR_CTX_MODEM_RESPONSE_TIMEOUT 7012L +#define ERROR_CTX_MODEM_RESPONSE_NO_CARRIER 7013L +#define ERROR_CTX_MODEM_RESPONSE_NO_DIALTONE 7014L +#define ERROR_CTX_MODEM_RESPONSE_BUSY 7015L +#define ERROR_CTX_MODEM_RESPONSE_VOICE 7016L +#define ERROR_CTX_TD_ERROR 7017L +#define ERROR_CTX_WINSTATION_NOT_FOUND 7022L +#define ERROR_CTX_WINSTATION_ALREADY_EXISTS 7023L +#define ERROR_CTX_WINSTATION_BUSY 7024L +#define ERROR_CTX_BAD_VIDEO_MODE 7025L +#define ERROR_CTX_GRAPHICS_INVALID 7035L +#define ERROR_CTX_LOGON_DISABLED 7037L +#define ERROR_CTX_NOT_CONSOLE 7038L +#define ERROR_CTX_CLIENT_QUERY_TIMEOUT 7040L +#define ERROR_CTX_CONSOLE_DISCONNECT 7041L +#define ERROR_CTX_CONSOLE_CONNECT 7042L +#define ERROR_CTX_SHADOW_DENIED 7044L +#define ERROR_CTX_WINSTATION_ACCESS_DENIED 7045L +#define ERROR_CTX_INVALID_WD 7049L +#define ERROR_CTX_SHADOW_INVALID 7050L +#define ERROR_CTX_SHADOW_DISABLED 7051L +#define ERROR_CTX_CLIENT_LICENSE_IN_USE 7052L +#define ERROR_CTX_CLIENT_LICENSE_NOT_SET 7053L +#define ERROR_CTX_LICENSE_NOT_AVAILABLE 7054L +#define ERROR_CTX_LICENSE_CLIENT_INVALID 7055L +#define ERROR_CTX_LICENSE_EXPIRED 7056L +#define ERROR_CTX_SHADOW_NOT_RUNNING 7057L +#define ERROR_CTX_SHADOW_ENDED_BY_MODE_CHANGE 7058L +#define ERROR_ACTIVATION_COUNT_EXCEEDED 7059L +#define FRS_ERR_INVALID_API_SEQUENCE 8001L +#define FRS_ERR_STARTING_SERVICE 8002L +#define FRS_ERR_STOPPING_SERVICE 8003L +#define FRS_ERR_INTERNAL_API 8004L +#define FRS_ERR_INTERNAL 8005L +#define FRS_ERR_SERVICE_COMM 8006L +#define FRS_ERR_INSUFFICIENT_PRIV 8007L +#define FRS_ERR_AUTHENTICATION 8008L +#define FRS_ERR_PARENT_INSUFFICIENT_PRIV 8009L +#define FRS_ERR_PARENT_AUTHENTICATION 8010L +#define FRS_ERR_CHILD_TO_PARENT_COMM 8011L +#define FRS_ERR_PARENT_TO_CHILD_COMM 8012L +#define FRS_ERR_SYSVOL_POPULATE 8013L +#define FRS_ERR_SYSVOL_POPULATE_TIMEOUT 8014L +#define FRS_ERR_SYSVOL_IS_BUSY 8015L +#define FRS_ERR_SYSVOL_DEMOTE 8016L +#define FRS_ERR_INVALID_SERVICE_PARAMETER 8017L +#define DS_S_SUCCESS NO_ERROR +#define ERROR_DS_NOT_INSTALLED 8200L +#define ERROR_DS_MEMBERSHIP_EVALUATED_LOCALLY 8201L +#define ERROR_DS_NO_ATTRIBUTE_OR_VALUE 8202L +#define ERROR_DS_INVALID_ATTRIBUTE_SYNTAX 8203L +#define ERROR_DS_ATTRIBUTE_TYPE_UNDEFINED 8204L +#define ERROR_DS_ATTRIBUTE_OR_VALUE_EXISTS 8205L +#define ERROR_DS_BUSY 8206L +#define ERROR_DS_UNAVAILABLE 8207L +#define ERROR_DS_NO_RIDS_ALLOCATED 8208L +#define ERROR_DS_NO_MORE_RIDS 8209L +#define ERROR_DS_INCORRECT_ROLE_OWNER 8210L +#define ERROR_DS_RIDMGR_INIT_ERROR 8211L +#define ERROR_DS_OBJ_CLASS_VIOLATION 8212L +#define ERROR_DS_CANT_ON_NON_LEAF 8213L +#define ERROR_DS_CANT_ON_RDN 8214L +#define ERROR_DS_CANT_MOD_OBJ_CLASS 8215L +#define ERROR_DS_CROSS_DOM_MOVE_ERROR 8216L +#define ERROR_DS_GC_NOT_AVAILABLE 8217L +#define ERROR_SHARED_POLICY 8218L +#define ERROR_POLICY_OBJECT_NOT_FOUND 8219L +#define ERROR_POLICY_ONLY_IN_DS 8220L +#define ERROR_PROMOTION_ACTIVE 8221L +#define ERROR_NO_PROMOTION_ACTIVE 8222L +#define ERROR_DS_OPERATIONS_ERROR 8224L +#define ERROR_DS_PROTOCOL_ERROR 8225L +#define ERROR_DS_TIMELIMIT_EXCEEDED 8226L +#define ERROR_DS_SIZELIMIT_EXCEEDED 8227L +#define ERROR_DS_ADMIN_LIMIT_EXCEEDED 8228L +#define ERROR_DS_COMPARE_FALSE 8229L +#define ERROR_DS_COMPARE_TRUE 8230L +#define ERROR_DS_AUTH_METHOD_NOT_SUPPORTED 8231L +#define ERROR_DS_STRONG_AUTH_REQUIRED 8232L +#define ERROR_DS_INAPPROPRIATE_AUTH 8233L +#define ERROR_DS_AUTH_UNKNOWN 8234L +#define ERROR_DS_REFERRAL 8235L +#define ERROR_DS_UNAVAILABLE_CRIT_EXTENSION 8236L +#define ERROR_DS_CONFIDENTIALITY_REQUIRED 8237L +#define ERROR_DS_INAPPROPRIATE_MATCHING 8238L +#define ERROR_DS_CONSTRAINT_VIOLATION 8239L +#define ERROR_DS_NO_SUCH_OBJECT 8240L +#define ERROR_DS_ALIAS_PROBLEM 8241L +#define ERROR_DS_INVALID_DN_SYNTAX 8242L +#define ERROR_DS_IS_LEAF 8243L +#define ERROR_DS_ALIAS_DEREF_PROBLEM 8244L +#define ERROR_DS_UNWILLING_TO_PERFORM 8245L +#define ERROR_DS_LOOP_DETECT 8246L +#define ERROR_DS_NAMING_VIOLATION 8247L +#define ERROR_DS_OBJECT_RESULTS_TOO_LARGE 8248L +#define ERROR_DS_AFFECTS_MULTIPLE_DSAS 8249L +#define ERROR_DS_SERVER_DOWN 8250L +#define ERROR_DS_LOCAL_ERROR 8251L +#define ERROR_DS_ENCODING_ERROR 8252L +#define ERROR_DS_DECODING_ERROR 8253L +#define ERROR_DS_FILTER_UNKNOWN 8254L +#define ERROR_DS_PARAM_ERROR 8255L +#define ERROR_DS_NOT_SUPPORTED 8256L +#define ERROR_DS_NO_RESULTS_RETURNED 8257L +#define ERROR_DS_CONTROL_NOT_FOUND 8258L +#define ERROR_DS_CLIENT_LOOP 8259L +#define ERROR_DS_REFERRAL_LIMIT_EXCEEDED 8260L +#define ERROR_DS_SORT_CONTROL_MISSING 8261L +#define ERROR_DS_OFFSET_RANGE_ERROR 8262L +#define ERROR_DS_ROOT_MUST_BE_NC 8301L +#define ERROR_DS_ADD_REPLICA_INHIBITED 8302L +#define ERROR_DS_ATT_NOT_DEF_IN_SCHEMA 8303L +#define ERROR_DS_MAX_OBJ_SIZE_EXCEEDED 8304L +#define ERROR_DS_OBJ_STRING_NAME_EXISTS 8305L +#define ERROR_DS_NO_RDN_DEFINED_IN_SCHEMA 8306L +#define ERROR_DS_RDN_DOESNT_MATCH_SCHEMA 8307L +#define ERROR_DS_NO_REQUESTED_ATTS_FOUND 8308L +#define ERROR_DS_USER_BUFFER_TO_SMALL 8309L +#define ERROR_DS_ATT_IS_NOT_ON_OBJ 8310L +#define ERROR_DS_ILLEGAL_MOD_OPERATION 8311L +#define ERROR_DS_OBJ_TOO_LARGE 8312L +#define ERROR_DS_BAD_INSTANCE_TYPE 8313L +#define ERROR_DS_MASTERDSA_REQUIRED 8314L +#define ERROR_DS_OBJECT_CLASS_REQUIRED 8315L +#define ERROR_DS_MISSING_REQUIRED_ATT 8316L +#define ERROR_DS_ATT_NOT_DEF_FOR_CLASS 8317L +#define ERROR_DS_ATT_ALREADY_EXISTS 8318L +#define ERROR_DS_CANT_ADD_ATT_VALUES 8320L +#define ERROR_DS_SINGLE_VALUE_CONSTRAINT 8321L +#define ERROR_DS_RANGE_CONSTRAINT 8322L +#define ERROR_DS_ATT_VAL_ALREADY_EXISTS 8323L +#define ERROR_DS_CANT_REM_MISSING_ATT 8324L +#define ERROR_DS_CANT_REM_MISSING_ATT_VAL 8325L +#define ERROR_DS_ROOT_CANT_BE_SUBREF 8326L +#define ERROR_DS_NO_CHAINING 8327L +#define ERROR_DS_NO_CHAINED_EVAL 8328L +#define ERROR_DS_NO_PARENT_OBJECT 8329L +#define ERROR_DS_PARENT_IS_AN_ALIAS 8330L +#define ERROR_DS_CANT_MIX_MASTER_AND_REPS 8331L +#define ERROR_DS_CHILDREN_EXIST 8332L +#define ERROR_DS_OBJ_NOT_FOUND 8333L +#define ERROR_DS_ALIASED_OBJ_MISSING 8334L +#define ERROR_DS_BAD_NAME_SYNTAX 8335L +#define ERROR_DS_ALIAS_POINTS_TO_ALIAS 8336L +#define ERROR_DS_CANT_DEREF_ALIAS 8337L +#define ERROR_DS_OUT_OF_SCOPE 8338L +#define ERROR_DS_OBJECT_BEING_REMOVED 8339L +#define ERROR_DS_CANT_DELETE_DSA_OBJ 8340L +#define ERROR_DS_GENERIC_ERROR 8341L +#define ERROR_DS_DSA_MUST_BE_INT_MASTER 8342L +#define ERROR_DS_CLASS_NOT_DSA 8343L +#define ERROR_DS_INSUFF_ACCESS_RIGHTS 8344L +#define ERROR_DS_ILLEGAL_SUPERIOR 8345L +#define ERROR_DS_ATTRIBUTE_OWNED_BY_SAM 8346L +#define ERROR_DS_NAME_TOO_MANY_PARTS 8347L +#define ERROR_DS_NAME_TOO_LONG 8348L +#define ERROR_DS_NAME_VALUE_TOO_LONG 8349L +#define ERROR_DS_NAME_UNPARSEABLE 8350L +#define ERROR_DS_NAME_TYPE_UNKNOWN 8351L +#define ERROR_DS_NOT_AN_OBJECT 8352L +#define ERROR_DS_SEC_DESC_TOO_SHORT 8353L +#define ERROR_DS_SEC_DESC_INVALID 8354L +#define ERROR_DS_NO_DELETED_NAME 8355L +#define ERROR_DS_SUBREF_MUST_HAVE_PARENT 8356L +#define ERROR_DS_NCNAME_MUST_BE_NC 8357L +#define ERROR_DS_CANT_ADD_SYSTEM_ONLY 8358L +#define ERROR_DS_CLASS_MUST_BE_CONCRETE 8359L +#define ERROR_DS_INVALID_DMD 8360L +#define ERROR_DS_OBJ_GUID_EXISTS 8361L +#define ERROR_DS_NOT_ON_BACKLINK 8362L +#define ERROR_DS_NO_CROSSREF_FOR_NC 8363L +#define ERROR_DS_SHUTTING_DOWN 8364L +#define ERROR_DS_UNKNOWN_OPERATION 8365L +#define ERROR_DS_INVALID_ROLE_OWNER 8366L +#define ERROR_DS_COULDNT_CONTACT_FSMO 8367L +#define ERROR_DS_CROSS_NC_DN_RENAME 8368L +#define ERROR_DS_CANT_MOD_SYSTEM_ONLY 8369L +#define ERROR_DS_REPLICATOR_ONLY 8370L +#define ERROR_DS_OBJ_CLASS_NOT_DEFINED 8371L +#define ERROR_DS_OBJ_CLASS_NOT_SUBCLASS 8372L +#define ERROR_DS_NAME_REFERENCE_INVALID 8373L +#define ERROR_DS_CROSS_REF_EXISTS 8374L +#define ERROR_DS_CANT_DEL_MASTER_CROSSREF 8375L +#define ERROR_DS_SUBTREE_NOTIFY_NOT_NC_HEAD 8376L +#define ERROR_DS_NOTIFY_FILTER_TOO_COMPLEX 8377L +#define ERROR_DS_DUP_RDN 8378L +#define ERROR_DS_DUP_OID 8379L +#define ERROR_DS_DUP_MAPI_ID 8380L +#define ERROR_DS_DUP_SCHEMA_ID_GUID 8381L +#define ERROR_DS_DUP_LDAP_DISPLAY_NAME 8382L +#define ERROR_DS_SEMANTIC_ATT_TEST 8383L +#define ERROR_DS_SYNTAX_MISMATCH 8384L +#define ERROR_DS_EXISTS_IN_MUST_HAVE 8385L +#define ERROR_DS_EXISTS_IN_MAY_HAVE 8386L +#define ERROR_DS_NONEXISTENT_MAY_HAVE 8387L +#define ERROR_DS_NONEXISTENT_MUST_HAVE 8388L +#define ERROR_DS_AUX_CLS_TEST_FAIL 8389L +#define ERROR_DS_NONEXISTENT_POSS_SUP 8390L +#define ERROR_DS_SUB_CLS_TEST_FAIL 8391L +#define ERROR_DS_BAD_RDN_ATT_ID_SYNTAX 8392L +#define ERROR_DS_EXISTS_IN_AUX_CLS 8393L +#define ERROR_DS_EXISTS_IN_SUB_CLS 8394L +#define ERROR_DS_EXISTS_IN_POSS_SUP 8395L +#define ERROR_DS_RECALCSCHEMA_FAILED 8396L +#define ERROR_DS_TREE_DELETE_NOT_FINISHED 8397L +#define ERROR_DS_CANT_DELETE 8398L +#define ERROR_DS_ATT_SCHEMA_REQ_ID 8399L +#define ERROR_DS_BAD_ATT_SCHEMA_SYNTAX 8400L +#define ERROR_DS_CANT_CACHE_ATT 8401L +#define ERROR_DS_CANT_CACHE_CLASS 8402L +#define ERROR_DS_CANT_REMOVE_ATT_CACHE 8403L +#define ERROR_DS_CANT_REMOVE_CLASS_CACHE 8404L +#define ERROR_DS_CANT_RETRIEVE_DN 8405L +#define ERROR_DS_MISSING_SUPREF 8406L +#define ERROR_DS_CANT_RETRIEVE_INSTANCE 8407L +#define ERROR_DS_CODE_INCONSISTENCY 8408L +#define ERROR_DS_DATABASE_ERROR 8409L +#define ERROR_DS_GOVERNSID_MISSING 8410L +#define ERROR_DS_MISSING_EXPECTED_ATT 8411L +#define ERROR_DS_NCNAME_MISSING_CR_REF 8412L +#define ERROR_DS_SECURITY_CHECKING_ERROR 8413L +#define ERROR_DS_SCHEMA_NOT_LOADED 8414L +#define ERROR_DS_SCHEMA_ALLOC_FAILED 8415L +#define ERROR_DS_ATT_SCHEMA_REQ_SYNTAX 8416L +#define ERROR_DS_GCVERIFY_ERROR 8417L +#define ERROR_DS_DRA_SCHEMA_MISMATCH 8418L +#define ERROR_DS_CANT_FIND_DSA_OBJ 8419L +#define ERROR_DS_CANT_FIND_EXPECTED_NC 8420L +#define ERROR_DS_CANT_FIND_NC_IN_CACHE 8421L +#define ERROR_DS_CANT_RETRIEVE_CHILD 8422L +#define ERROR_DS_SECURITY_ILLEGAL_MODIFY 8423L +#define ERROR_DS_CANT_REPLACE_HIDDEN_REC 8424L +#define ERROR_DS_BAD_HIERARCHY_FILE 8425L +#define ERROR_DS_BUILD_HIERARCHY_TABLE_FAILED 8426L +#define ERROR_DS_CONFIG_PARAM_MISSING 8427L +#define ERROR_DS_COUNTING_AB_INDICES_FAILED 8428L +#define ERROR_DS_HIERARCHY_TABLE_MALLOC_FAILED 8429L +#define ERROR_DS_INTERNAL_FAILURE 8430L +#define ERROR_DS_UNKNOWN_ERROR 8431L +#define ERROR_DS_ROOT_REQUIRES_CLASS_TOP 8432L +#define ERROR_DS_REFUSING_FSMO_ROLES 8433L +#define ERROR_DS_MISSING_FSMO_SETTINGS 8434L +#define ERROR_DS_UNABLE_TO_SURRENDER_ROLES 8435L +#define ERROR_DS_DRA_GENERIC 8436L +#define ERROR_DS_DRA_INVALID_PARAMETER 8437L +#define ERROR_DS_DRA_BUSY 8438L +#define ERROR_DS_DRA_BAD_DN 8439L +#define ERROR_DS_DRA_BAD_NC 8440L +#define ERROR_DS_DRA_DN_EXISTS 8441L +#define ERROR_DS_DRA_INTERNAL_ERROR 8442L +#define ERROR_DS_DRA_INCONSISTENT_DIT 8443L +#define ERROR_DS_DRA_CONNECTION_FAILED 8444L +#define ERROR_DS_DRA_BAD_INSTANCE_TYPE 8445L +#define ERROR_DS_DRA_OUT_OF_MEM 8446L +#define ERROR_DS_DRA_MAIL_PROBLEM 8447L +#define ERROR_DS_DRA_REF_ALREADY_EXISTS 8448L +#define ERROR_DS_DRA_REF_NOT_FOUND 8449L +#define ERROR_DS_DRA_OBJ_IS_REP_SOURCE 8450L +#define ERROR_DS_DRA_DB_ERROR 8451L +#define ERROR_DS_DRA_NO_REPLICA 8452L +#define ERROR_DS_DRA_ACCESS_DENIED 8453L +#define ERROR_DS_DRA_NOT_SUPPORTED 8454L +#define ERROR_DS_DRA_RPC_CANCELLED 8455L +#define ERROR_DS_DRA_SOURCE_DISABLED 8456L +#define ERROR_DS_DRA_SINK_DISABLED 8457L +#define ERROR_DS_DRA_NAME_COLLISION 8458L +#define ERROR_DS_DRA_SOURCE_REINSTALLED 8459L +#define ERROR_DS_DRA_MISSING_PARENT 8460L +#define ERROR_DS_DRA_PREEMPTED 8461L +#define ERROR_DS_DRA_ABANDON_SYNC 8462L +#define ERROR_DS_DRA_SHUTDOWN 8463L +#define ERROR_DS_DRA_INCOMPATIBLE_PARTIAL_SET 8464L +#define ERROR_DS_DRA_SOURCE_IS_PARTIAL_REPLICA 8465L +#define ERROR_DS_DRA_EXTN_CONNECTION_FAILED 8466L +#define ERROR_DS_INSTALL_SCHEMA_MISMATCH 8467L +#define ERROR_DS_DUP_LINK_ID 8468L +#define ERROR_DS_NAME_ERROR_RESOLVING 8469L +#define ERROR_DS_NAME_ERROR_NOT_FOUND 8470L +#define ERROR_DS_NAME_ERROR_NOT_UNIQUE 8471L +#define ERROR_DS_NAME_ERROR_NO_MAPPING 8472L +#define ERROR_DS_NAME_ERROR_DOMAIN_ONLY 8473L +#define ERROR_DS_NAME_ERROR_NO_SYNTACTICAL_MAPPING 8474L +#define ERROR_DS_CONSTRUCTED_ATT_MOD 8475L +#define ERROR_DS_WRONG_OM_OBJ_CLASS 8476L +#define ERROR_DS_DRA_REPL_PENDING 8477L +#define ERROR_DS_DS_REQUIRED 8478L +#define ERROR_DS_INVALID_LDAP_DISPLAY_NAME 8479L +#define ERROR_DS_NON_BASE_SEARCH 8480L +#define ERROR_DS_CANT_RETRIEVE_ATTS 8481L +#define ERROR_DS_BACKLINK_WITHOUT_LINK 8482L +#define ERROR_DS_EPOCH_MISMATCH 8483L +#define ERROR_DS_SRC_NAME_MISMATCH 8484L +#define ERROR_DS_SRC_AND_DST_NC_IDENTICAL 8485L +#define ERROR_DS_DST_NC_MISMATCH 8486L +#define ERROR_DS_NOT_AUTHORITIVE_FOR_DST_NC 8487L +#define ERROR_DS_SRC_GUID_MISMATCH 8488L +#define ERROR_DS_CANT_MOVE_DELETED_OBJECT 8489L +#define ERROR_DS_PDC_OPERATION_IN_PROGRESS 8490L +#define ERROR_DS_CROSS_DOMAIN_CLEANUP_REQD 8491L +#define ERROR_DS_ILLEGAL_XDOM_MOVE_OPERATION 8492L +#define ERROR_DS_CANT_WITH_ACCT_GROUP_MEMBERSHPS 8493L +#define ERROR_DS_NC_MUST_HAVE_NC_PARENT 8494L +#define ERROR_DS_CR_IMPOSSIBLE_TO_VALIDATE 8495L +#define ERROR_DS_DST_DOMAIN_NOT_NATIVE 8496L +#define ERROR_DS_MISSING_INFRASTRUCTURE_CONTAINER 8497L +#define ERROR_DS_CANT_MOVE_ACCOUNT_GROUP 8498L +#define ERROR_DS_CANT_MOVE_RESOURCE_GROUP 8499L +#define ERROR_DS_INVALID_SEARCH_FLAG 8500L +#define ERROR_DS_NO_TREE_DELETE_ABOVE_NC 8501L +#define ERROR_DS_COULDNT_LOCK_TREE_FOR_DELETE 8502L +#define ERROR_DS_COULDNT_IDENTIFY_OBJECTS_FOR_TREE_DELETE 8503L +#define ERROR_DS_SAM_INIT_FAILURE 8504L +#define ERROR_DS_SENSITIVE_GROUP_VIOLATION 8505L +#define ERROR_DS_CANT_MOD_PRIMARYGROUPID 8506L +#define ERROR_DS_ILLEGAL_BASE_SCHEMA_MOD 8507L +#define ERROR_DS_NONSAFE_SCHEMA_CHANGE 8508L +#define ERROR_DS_SCHEMA_UPDATE_DISALLOWED 8509L +#define ERROR_DS_CANT_CREATE_UNDER_SCHEMA 8510L +#define ERROR_DS_INSTALL_NO_SRC_SCH_VERSION 8511L +#define ERROR_DS_INSTALL_NO_SCH_VERSION_IN_INIFILE 8512L +#define ERROR_DS_INVALID_GROUP_TYPE 8513L +#define ERROR_DS_NO_NEST_GLOBALGROUP_IN_MIXEDDOMAIN 8514L +#define ERROR_DS_NO_NEST_LOCALGROUP_IN_MIXEDDOMAIN 8515L +#define ERROR_DS_GLOBAL_CANT_HAVE_LOCAL_MEMBER 8516L +#define ERROR_DS_GLOBAL_CANT_HAVE_UNIVERSAL_MEMBER 8517L +#define ERROR_DS_UNIVERSAL_CANT_HAVE_LOCAL_MEMBER 8518L +#define ERROR_DS_GLOBAL_CANT_HAVE_CROSSDOMAIN_MEMBER 8519L +#define ERROR_DS_LOCAL_CANT_HAVE_CROSSDOMAIN_LOCAL_MEMBER 8520L +#define ERROR_DS_HAVE_PRIMARY_MEMBERS 8521L +#define ERROR_DS_STRING_SD_CONVERSION_FAILED 8522L +#define ERROR_DS_NAMING_MASTER_GC 8523L +#define ERROR_DS_DNS_LOOKUP_FAILURE 8524L +#define ERROR_DS_COULDNT_UPDATE_SPNS 8525L +#define ERROR_DS_CANT_RETRIEVE_SD 8526L +#define ERROR_DS_KEY_NOT_UNIQUE 8527L +#define ERROR_DS_WRONG_LINKED_ATT_SYNTAX 8528L +#define ERROR_DS_SAM_NEED_BOOTKEY_PASSWORD 8529L +#define ERROR_DS_SAM_NEED_BOOTKEY_FLOPPY 8530L +#define ERROR_DS_CANT_START 8531L +#define ERROR_DS_INIT_FAILURE 8532L +#define ERROR_DS_NO_PKT_PRIVACY_ON_CONNECTION 8533L +#define ERROR_DS_SOURCE_DOMAIN_IN_FOREST 8534L +#define ERROR_DS_DESTINATION_DOMAIN_NOT_IN_FOREST 8535L +#define ERROR_DS_DESTINATION_AUDITING_NOT_ENABLED 8536L +#define ERROR_DS_CANT_FIND_DC_FOR_SRC_DOMAIN 8537L +#define ERROR_DS_SRC_OBJ_NOT_GROUP_OR_USER 8538L +#define ERROR_DS_SRC_SID_EXISTS_IN_FOREST 8539L +#define ERROR_DS_SRC_AND_DST_OBJECT_CLASS_MISMATCH 8540L +#define ERROR_SAM_INIT_FAILURE 8541L +#define ERROR_DS_DRA_SCHEMA_INFO_SHIP 8542L +#define ERROR_DS_DRA_SCHEMA_CONFLICT 8543L +#define ERROR_DS_DRA_EARLIER_SCHEMA_CONFLICT 8544L +#define ERROR_DS_DRA_OBJ_NC_MISMATCH 8545L +#define ERROR_DS_NC_STILL_HAS_DSAS 8546L +#define ERROR_DS_GC_REQUIRED 8547L +#define ERROR_DS_LOCAL_MEMBER_OF_LOCAL_ONLY 8548L +#define ERROR_DS_NO_FPO_IN_UNIVERSAL_GROUPS 8549L +#define ERROR_DS_CANT_ADD_TO_GC 8550L +#define ERROR_DS_NO_CHECKPOINT_WITH_PDC 8551L +#define ERROR_DS_SOURCE_AUDITING_NOT_ENABLED 8552L +#define ERROR_DS_CANT_CREATE_IN_NONDOMAIN_NC 8553L +#define ERROR_DS_INVALID_NAME_FOR_SPN 8554L +#define ERROR_DS_FILTER_USES_CONTRUCTED_ATTRS 8555L +#define ERROR_DS_UNICODEPWD_NOT_IN_QUOTES 8556L +#define ERROR_DS_MACHINE_ACCOUNT_QUOTA_EXCEEDED 8557L +#define ERROR_DS_MUST_BE_RUN_ON_DST_DC 8558L +#define ERROR_DS_SRC_DC_MUST_BE_SP4_OR_GREATER 8559L +#define ERROR_DS_CANT_TREE_DELETE_CRITICAL_OBJ 8560L +#define ERROR_DS_INIT_FAILURE_CONSOLE 8561L +#define ERROR_DS_SAM_INIT_FAILURE_CONSOLE 8562L +#define ERROR_DS_FOREST_VERSION_TOO_HIGH 8563L +#define ERROR_DS_DOMAIN_VERSION_TOO_HIGH 8564L +#define ERROR_DS_FOREST_VERSION_TOO_LOW 8565L +#define ERROR_DS_DOMAIN_VERSION_TOO_LOW 8566L +#define ERROR_DS_INCOMPATIBLE_VERSION 8567L +#define ERROR_DS_LOW_DSA_VERSION 8568L +#define ERROR_DS_NO_BEHAVIOR_VERSION_IN_MIXEDDOMAIN 8569L +#define ERROR_DS_NOT_SUPPORTED_SORT_ORDER 8570L +#define ERROR_DS_NAME_NOT_UNIQUE 8571L +#define ERROR_DS_MACHINE_ACCOUNT_CREATED_PRENT4 8572L +#define ERROR_DS_OUT_OF_VERSION_STORE 8573L +#define ERROR_DS_INCOMPATIBLE_CONTROLS_USED 8574L +#define ERROR_DS_NO_REF_DOMAIN 8575L +#define ERROR_DS_RESERVED_LINK_ID 8576L +#define ERROR_DS_LINK_ID_NOT_AVAILABLE 8577L +#define ERROR_DS_AG_CANT_HAVE_UNIVERSAL_MEMBER 8578L +#define ERROR_DS_MODIFYDN_DISALLOWED_BY_INSTANCE_TYPE 8579L +#define ERROR_DS_NO_OBJECT_MOVE_IN_SCHEMA_NC 8580L +#define ERROR_DS_MODIFYDN_DISALLOWED_BY_FLAG 8581L +#define ERROR_DS_MODIFYDN_WRONG_GRANDPARENT 8582L +#define ERROR_DS_NAME_ERROR_TRUST_REFERRAL 8583L +#define ERROR_NOT_SUPPORTED_ON_STANDARD_SERVER 8584L +#define ERROR_DS_CANT_ACCESS_REMOTE_PART_OF_AD 8585L +#define ERROR_DS_CR_IMPOSSIBLE_TO_VALIDATE_V2 8586L +#define ERROR_DS_THREAD_LIMIT_EXCEEDED 8587L +#define ERROR_DS_NOT_CLOSEST 8588L +#define ERROR_DS_CANT_DERIVE_SPN_WITHOUT_SERVER_REF 8589L +#define ERROR_DS_SINGLE_USER_MODE_FAILED 8590L +#define ERROR_DS_NTDSCRIPT_SYNTAX_ERROR 8591L +#define ERROR_DS_NTDSCRIPT_PROCESS_ERROR 8592L +#define ERROR_DS_DIFFERENT_REPL_EPOCHS 8593L +#define ERROR_DS_DRS_EXTENSIONS_CHANGED 8594L +#define ERROR_DS_REPLICA_SET_CHANGE_NOT_ALLOWED_ON_DISABLED_CR 8595L +#define ERROR_DS_NO_MSDS_INTID 8596L +#define ERROR_DS_DUP_MSDS_INTID 8597L +#define ERROR_DS_EXISTS_IN_RDNATTID 8598L +#define ERROR_DS_AUTHORIZATION_FAILED 8599L +#define ERROR_DS_INVALID_SCRIPT 8600L +#define ERROR_DS_REMOTE_CROSSREF_OP_FAILED 8601L +#define ERROR_DS_CROSS_REF_BUSY 8602L +#define ERROR_DS_CANT_DERIVE_SPN_FOR_DELETED_DOMAIN 8603L +#define ERROR_DS_CANT_DEMOTE_WITH_WRITEABLE_NC 8604L +#define ERROR_DS_DUPLICATE_ID_FOUND 8605L +#define ERROR_DS_INSUFFICIENT_ATTR_TO_CREATE_OBJECT 8606L +#define ERROR_DS_GROUP_CONVERSION_ERROR 8607L +#define ERROR_DS_CANT_MOVE_APP_BASIC_GROUP 8608L +#define ERROR_DS_CANT_MOVE_APP_QUERY_GROUP 8609L +#define ERROR_DS_ROLE_NOT_VERIFIED 8610L +#define ERROR_DS_WKO_CONTAINER_CANNOT_BE_SPECIAL 8611L +#define ERROR_DS_DOMAIN_RENAME_IN_PROGRESS 8612L +#define ERROR_DS_EXISTING_AD_CHILD_NC 8613L +#define ERROR_DS_REPL_LIFETIME_EXCEEDED 8614L +#define ERROR_DS_DISALLOWED_IN_SYSTEM_CONTAINER 8615L +#define ERROR_DS_LDAP_SEND_QUEUE_FULL 8616L +#define ERROR_DS_DRA_OUT_SCHEDULE_WINDOW 8617L +#define DNS_ERROR_RESPONSE_CODES_BASE 9000 +#define DNS_ERROR_RCODE_NO_ERROR NO_ERROR +#define DNS_ERROR_MASK 0x00002328 +#define DNS_ERROR_RCODE_FORMAT_ERROR 9001L +#define DNS_ERROR_RCODE_SERVER_FAILURE 9002L +#define DNS_ERROR_RCODE_NAME_ERROR 9003L +#define DNS_ERROR_RCODE_NOT_IMPLEMENTED 9004L +#define DNS_ERROR_RCODE_REFUSED 9005L +#define DNS_ERROR_RCODE_YXDOMAIN 9006L +#define DNS_ERROR_RCODE_YXRRSET 9007L +#define DNS_ERROR_RCODE_NXRRSET 9008L +#define DNS_ERROR_RCODE_NOTAUTH 9009L +#define DNS_ERROR_RCODE_NOTZONE 9010L +#define DNS_ERROR_RCODE_BADSIG 9016L +#define DNS_ERROR_RCODE_BADKEY 9017L +#define DNS_ERROR_RCODE_BADTIME 9018L +#define DNS_ERROR_RCODE_LAST DNS_ERROR_RCODE_BADTIME +#define DNS_ERROR_PACKET_FMT_BASE 9500 +#define DNS_INFO_NO_RECORDS 9501L +#define DNS_ERROR_BAD_PACKET 9502L +#define DNS_ERROR_NO_PACKET 9503L +#define DNS_ERROR_RCODE 9504L +#define DNS_ERROR_UNSECURE_PACKET 9505L +#define DNS_STATUS_PACKET_UNSECURE DNS_ERROR_UNSECURE_PACKET +#define DNS_ERROR_NO_MEMORY ERROR_OUTOFMEMORY +#define DNS_ERROR_INVALID_NAME ERROR_INVALID_NAME +#define DNS_ERROR_INVALID_DATA ERROR_INVALID_DATA +#define DNS_ERROR_GENERAL_API_BASE 9550 +#define DNS_ERROR_INVALID_TYPE 9551L +#define DNS_ERROR_INVALID_IP_ADDRESS 9552L +#define DNS_ERROR_INVALID_PROPERTY 9553L +#define DNS_ERROR_TRY_AGAIN_LATER 9554L +#define DNS_ERROR_NOT_UNIQUE 9555L +#define DNS_ERROR_NON_RFC_NAME 9556L +#define DNS_STATUS_FQDN 9557L +#define DNS_STATUS_DOTTED_NAME 9558L +#define DNS_STATUS_SINGLE_PART_NAME 9559L +#define DNS_ERROR_INVALID_NAME_CHAR 9560L +#define DNS_ERROR_NUMERIC_NAME 9561L +#define DNS_ERROR_NOT_ALLOWED_ON_ROOT_SERVER 9562L +#define DNS_ERROR_NOT_ALLOWED_UNDER_DELEGATION 9563L +#define DNS_ERROR_CANNOT_FIND_ROOT_HINTS 9564L +#define DNS_ERROR_INCONSISTENT_ROOT_HINTS 9565L +#define DNS_ERROR_ZONE_BASE 9600 +#define DNS_ERROR_ZONE_DOES_NOT_EXIST 9601L +#define DNS_ERROR_NO_ZONE_INFO 9602L +#define DNS_ERROR_INVALID_ZONE_OPERATION 9603L +#define DNS_ERROR_ZONE_CONFIGURATION_ERROR 9604L +#define DNS_ERROR_ZONE_HAS_NO_SOA_RECORD 9605L +#define DNS_ERROR_ZONE_HAS_NO_NS_RECORDS 9606L +#define DNS_ERROR_ZONE_LOCKED 9607L +#define DNS_ERROR_ZONE_CREATION_FAILED 9608L +#define DNS_ERROR_ZONE_ALREADY_EXISTS 9609L +#define DNS_ERROR_AUTOZONE_ALREADY_EXISTS 9610L +#define DNS_ERROR_INVALID_ZONE_TYPE 9611L +#define DNS_ERROR_SECONDARY_REQUIRES_MASTER_IP 9612L +#define DNS_ERROR_ZONE_NOT_SECONDARY 9613L +#define DNS_ERROR_NEED_SECONDARY_ADDRESSES 9614L +#define DNS_ERROR_WINS_INIT_FAILED 9615L +#define DNS_ERROR_NEED_WINS_SERVERS 9616L +#define DNS_ERROR_NBSTAT_INIT_FAILED 9617L +#define DNS_ERROR_SOA_DELETE_INVALID 9618L +#define DNS_ERROR_FORWARDER_ALREADY_EXISTS 9619L +#define DNS_ERROR_ZONE_REQUIRES_MASTER_IP 9620L +#define DNS_ERROR_ZONE_IS_SHUTDOWN 9621L +#define DNS_ERROR_DATAFILE_BASE 9650 +#define DNS_ERROR_PRIMARY_REQUIRES_DATAFILE 9651L +#define DNS_ERROR_INVALID_DATAFILE_NAME 9652L +#define DNS_ERROR_DATAFILE_OPEN_FAILURE 9653L +#define DNS_ERROR_FILE_WRITEBACK_FAILED 9654L +#define DNS_ERROR_DATAFILE_PARSING 9655L +#define DNS_ERROR_DATABASE_BASE 9700 +#define DNS_ERROR_RECORD_DOES_NOT_EXIST 9701L +#define DNS_ERROR_RECORD_FORMAT 9702L +#define DNS_ERROR_NODE_CREATION_FAILED 9703L +#define DNS_ERROR_UNKNOWN_RECORD_TYPE 9704L +#define DNS_ERROR_RECORD_TIMED_OUT 9705L +#define DNS_ERROR_NAME_NOT_IN_ZONE 9706L +#define DNS_ERROR_CNAME_LOOP 9707L +#define DNS_ERROR_NODE_IS_CNAME 9708L +#define DNS_ERROR_CNAME_COLLISION 9709L +#define DNS_ERROR_RECORD_ONLY_AT_ZONE_ROOT 9710L +#define DNS_ERROR_RECORD_ALREADY_EXISTS 9711L +#define DNS_ERROR_SECONDARY_DATA 9712L +#define DNS_ERROR_NO_CREATE_CACHE_DATA 9713L +#define DNS_ERROR_NAME_DOES_NOT_EXIST 9714L +#define DNS_WARNING_PTR_CREATE_FAILED 9715L +#define DNS_WARNING_DOMAIN_UNDELETED 9716L +#define DNS_ERROR_DS_UNAVAILABLE 9717L +#define DNS_ERROR_DS_ZONE_ALREADY_EXISTS 9718L +#define DNS_ERROR_NO_BOOTFILE_IF_DS_ZONE 9719L +#define DNS_ERROR_OPERATION_BASE 9750 +#define DNS_INFO_AXFR_COMPLETE 9751L +#define DNS_ERROR_AXFR 9752L +#define DNS_INFO_ADDED_LOCAL_WINS 9753L +#define DNS_ERROR_SECURE_BASE 9800 +#define DNS_STATUS_CONTINUE_NEEDED 9801L +#define DNS_ERROR_SETUP_BASE 9850 +#define DNS_ERROR_NO_TCPIP 9851L +#define DNS_ERROR_NO_DNS_SERVERS 9852L +#define DNS_ERROR_DP_BASE 9900 +#define DNS_ERROR_DP_DOES_NOT_EXIST 9901L +#define DNS_ERROR_DP_ALREADY_EXISTS 9902L +#define DNS_ERROR_DP_NOT_ENLISTED 9903L +#define DNS_ERROR_DP_ALREADY_ENLISTED 9904L +#define DNS_ERROR_DP_NOT_AVAILABLE 9905L +#define DNS_ERROR_DP_FSMO_ERROR 9906L + +#ifndef WSABASEERR +#define WSABASEERR 10000 +#define WSAEINTR 10004L +#define WSAEBADF 10009L +#define WSAEACCES 10013L +#define WSAEFAULT 10014L +#define WSAEINVAL 10022L +#define WSAEMFILE 10024L +#define WSAEWOULDBLOCK 10035L +#define WSAEINPROGRESS 10036L +#define WSAEALREADY 10037L +#define WSAENOTSOCK 10038L +#define WSAEDESTADDRREQ 10039L +#define WSAEMSGSIZE 10040L +#define WSAEPROTOTYPE 10041L +#define WSAENOPROTOOPT 10042L +#define WSAEPROTONOSUPPORT 10043L +#define WSAESOCKTNOSUPPORT 10044L +#define WSAEOPNOTSUPP 10045L +#define WSAEPFNOSUPPORT 10046L +#define WSAEAFNOSUPPORT 10047L +#define WSAEADDRINUSE 10048L +#define WSAEADDRNOTAVAIL 10049L +#define WSAENETDOWN 10050L +#define WSAENETUNREACH 10051L +#define WSAENETRESET 10052L +#define WSAECONNABORTED 10053L +#define WSAECONNRESET 10054L +#define WSAENOBUFS 10055L +#define WSAEISCONN 10056L +#define WSAENOTCONN 10057L +#define WSAESHUTDOWN 10058L +#define WSAETOOMANYREFS 10059L +#define WSAETIMEDOUT 10060L +#define WSAECONNREFUSED 10061L +#define WSAELOOP 10062L +#define WSAENAMETOOLONG 10063L +#define WSAEHOSTDOWN 10064L +#define WSAEHOSTUNREACH 10065L +#define WSAENOTEMPTY 10066L +#define WSAEPROCLIM 10067L +#define WSAEUSERS 10068L +#define WSAEDQUOT 10069L +#define WSAESTALE 10070L +#define WSAEREMOTE 10071L +#define WSASYSNOTREADY 10091L +#define WSAVERNOTSUPPORTED 10092L +#define WSANOTINITIALISED 10093L +#define WSAEDISCON 10101L +#define WSAENOMORE 10102L +#define WSAECANCELLED 10103L +#define WSAEINVALIDPROCTABLE 10104L +#define WSAEINVALIDPROVIDER 10105L +#define WSAEPROVIDERFAILEDINIT 10106L +#define WSASYSCALLFAILURE 10107L +#define WSASERVICE_NOT_FOUND 10108L +#define WSATYPE_NOT_FOUND 10109L +#define WSA_E_NO_MORE 10110L +#define WSA_E_CANCELLED 10111L +#define WSAEREFUSED 10112L +#ifndef WSAHOST_NOT_FOUND +#define WSAHOST_NOT_FOUND 11001L +#endif +#ifndef WSATRY_AGAIN +#define WSATRY_AGAIN 11002L +#endif +#ifndef WSANO_RECOVERY +#define WSANO_RECOVERY 11003L +#endif +#ifndef WSANO_DATA +#define WSANO_DATA 11004L +#endif +#ifndef WSA_QOS_RECEIVERS +#define WSA_QOS_RECEIVERS 11005L +#endif +#ifndef WSA_QOS_SENDERS +#define WSA_QOS_SENDERS 11006L +#endif +#ifndef WSA_QOS_NO_SENDERS +#define WSA_QOS_NO_SENDERS 11007L +#endif +#ifndef WSA_QOS_NO_RECEIVERS +#define WSA_QOS_NO_RECEIVERS 11008L +#endif +#ifndef WSA_QOS_REQUEST_CONFIRMED +#define WSA_QOS_REQUEST_CONFIRMED 11009L +#endif +#ifndef WSA_QOS_ADMISSION_FAILURE +#define WSA_QOS_ADMISSION_FAILURE 11010L +#endif +#ifndef WSA_QOS_POLICY_FAILURE +#define WSA_QOS_POLICY_FAILURE 11011L +#endif +#ifndef WSA_QOS_BAD_STYLE +#define WSA_QOS_BAD_STYLE 11012L +#endif +#ifndef WSA_QOS_BAD_OBJECT +#define WSA_QOS_BAD_OBJECT 11013L +#endif +#ifndef WSA_QOS_TRAFFIC_CTRL_ERROR +#define WSA_QOS_TRAFFIC_CTRL_ERROR 11014L +#endif +#ifndef WSA_QOS_GENERIC_ERROR +#define WSA_QOS_GENERIC_ERROR 11015L +#endif +#ifndef WSA_QOS_ESERVICETYPE +#define WSA_QOS_ESERVICETYPE 11016L +#endif +#ifndef WSA_QOS_EFLOWSPEC +#define WSA_QOS_EFLOWSPEC 11017L +#endif +#ifndef WSA_QOS_EPROVSPECBUF +#define WSA_QOS_EPROVSPECBUF 11018L +#endif +#ifndef WSA_QOS_EFILTERSTYLE +#define WSA_QOS_EFILTERSTYLE 11019L +#endif +#ifndef WSA_QOS_EFILTERTYPE +#define WSA_QOS_EFILTERTYPE 11020L +#endif +#ifndef WSA_QOS_EFILTERCOUNT +#define WSA_QOS_EFILTERCOUNT 11021L +#endif +#ifndef WSA_QOS_EOBJLENGTH +#define WSA_QOS_EOBJLENGTH 11022L +#endif +#ifndef WSA_QOS_EFLOWCOUNT +#define WSA_QOS_EFLOWCOUNT 11023L +#endif +#ifndef WSA_QOS_EUNKNOWNPSOBJ +#define WSA_QOS_EUNKNOWNPSOBJ 11024L +#endif +#ifndef WSA_QOS_EPOLICYOBJ +#define WSA_QOS_EPOLICYOBJ 11025L +#endif +#ifndef WSA_QOS_EFLOWDESC +#define WSA_QOS_EFLOWDESC 11026L +#endif +#ifndef WSA_QOS_EPSFLOWSPEC +#define WSA_QOS_EPSFLOWSPEC 11027L +#endif +#ifndef WSA_QOS_EPSFILTERSPEC +#define WSA_QOS_EPSFILTERSPEC 11028L +#endif +#ifndef WSA_QOS_ESDMODEOBJ +#define WSA_QOS_ESDMODEOBJ 11029L +#endif +#ifndef WSA_QOS_ESHAPERATEOBJ +#define WSA_QOS_ESHAPERATEOBJ 11030L +#endif +#ifndef WSA_QOS_RESERVED_PETYPE +#define WSA_QOS_RESERVED_PETYPE 11031L +#endif +#endif /* WSABASEERR */ + +#define ERROR_SXS_SECTION_NOT_FOUND 14000L +#define ERROR_SXS_CANT_GEN_ACTCTX 14001L +#define ERROR_SXS_INVALID_ACTCTXDATA_FORMAT 14002L +#define ERROR_SXS_ASSEMBLY_NOT_FOUND 14003L +#define ERROR_SXS_MANIFEST_FORMAT_ERROR 14004L +#define ERROR_SXS_MANIFEST_PARSE_ERROR 14005L +#define ERROR_SXS_ACTIVATION_CONTEXT_DISABLED 14006L +#define ERROR_SXS_KEY_NOT_FOUND 14007L +#define ERROR_SXS_VERSION_CONFLICT 14008L +#define ERROR_SXS_WRONG_SECTION_TYPE 14009L +#define ERROR_SXS_THREAD_QUERIES_DISABLED 14010L +#define ERROR_SXS_PROCESS_DEFAULT_ALREADY_SET 14011L +#define ERROR_SXS_UNKNOWN_ENCODING_GROUP 14012L +#define ERROR_SXS_UNKNOWN_ENCODING 14013L +#define ERROR_SXS_INVALID_XML_NAMESPACE_URI 14014L +#define ERROR_SXS_ROOT_MANIFEST_DEPENDENCY_NOT_INSTALLED 14015L +#define ERROR_SXS_LEAF_MANIFEST_DEPENDENCY_NOT_INSTALLED 14016L +#define ERROR_SXS_INVALID_ASSEMBLY_IDENTITY_ATTRIBUTE 14017L +#define ERROR_SXS_MANIFEST_MISSING_REQUIRED_DEFAULT_NAMESPACE 14018L +#define ERROR_SXS_MANIFEST_INVALID_REQUIRED_DEFAULT_NAMESPACE 14019L +#define ERROR_SXS_PRIVATE_MANIFEST_CROSS_PATH_WITH_REPARSE_POINT 14020L +#define ERROR_SXS_DUPLICATE_DLL_NAME 14021L +#define ERROR_SXS_DUPLICATE_WINDOWCLASS_NAME 14022L +#define ERROR_SXS_DUPLICATE_CLSID 14023L +#define ERROR_SXS_DUPLICATE_IID 14024L +#define ERROR_SXS_DUPLICATE_TLBID 14025L +#define ERROR_SXS_DUPLICATE_PROGID 14026L +#define ERROR_SXS_DUPLICATE_ASSEMBLY_NAME 14027L +#define ERROR_SXS_FILE_HASH_MISMATCH 14028L +#define ERROR_SXS_POLICY_PARSE_ERROR 14029L +#define ERROR_SXS_XML_E_MISSINGQUOTE 14030L +#define ERROR_SXS_XML_E_COMMENTSYNTAX 14031L +#define ERROR_SXS_XML_E_BADSTARTNAMECHAR 14032L +#define ERROR_SXS_XML_E_BADNAMECHAR 14033L +#define ERROR_SXS_XML_E_BADCHARINSTRING 14034L +#define ERROR_SXS_XML_E_XMLDECLSYNTAX 14035L +#define ERROR_SXS_XML_E_BADCHARDATA 14036L +#define ERROR_SXS_XML_E_MISSINGWHITESPACE 14037L +#define ERROR_SXS_XML_E_EXPECTINGTAGEND 14038L +#define ERROR_SXS_XML_E_MISSINGSEMICOLON 14039L +#define ERROR_SXS_XML_E_UNBALANCEDPAREN 14040L +#define ERROR_SXS_XML_E_INTERNALERROR 14041L +#define ERROR_SXS_XML_E_UNEXPECTED_WHITESPACE 14042L +#define ERROR_SXS_XML_E_INCOMPLETE_ENCODING 14043L +#define ERROR_SXS_XML_E_MISSING_PAREN 14044L +#define ERROR_SXS_XML_E_EXPECTINGCLOSEQUOTE 14045L +#define ERROR_SXS_XML_E_MULTIPLE_COLONS 14046L +#define ERROR_SXS_XML_E_INVALID_DECIMAL 14047L +#define ERROR_SXS_XML_E_INVALID_HEXIDECIMAL 14048L +#define ERROR_SXS_XML_E_INVALID_UNICODE 14049L +#define ERROR_SXS_XML_E_WHITESPACEORQUESTIONMARK 14050L +#define ERROR_SXS_XML_E_UNEXPECTEDENDTAG 14051L +#define ERROR_SXS_XML_E_UNCLOSEDTAG 14052L +#define ERROR_SXS_XML_E_DUPLICATEATTRIBUTE 14053L +#define ERROR_SXS_XML_E_MULTIPLEROOTS 14054L +#define ERROR_SXS_XML_E_INVALIDATROOTLEVEL 14055L +#define ERROR_SXS_XML_E_BADXMLDECL 14056L +#define ERROR_SXS_XML_E_MISSINGROOT 14057L +#define ERROR_SXS_XML_E_UNEXPECTEDEOF 14058L +#define ERROR_SXS_XML_E_BADPEREFINSUBSET 14059L +#define ERROR_SXS_XML_E_UNCLOSEDSTARTTAG 14060L +#define ERROR_SXS_XML_E_UNCLOSEDENDTAG 14061L +#define ERROR_SXS_XML_E_UNCLOSEDSTRING 14062L +#define ERROR_SXS_XML_E_UNCLOSEDCOMMENT 14063L +#define ERROR_SXS_XML_E_UNCLOSEDDECL 14064L +#define ERROR_SXS_XML_E_UNCLOSEDCDATA 14065L +#define ERROR_SXS_XML_E_RESERVEDNAMESPACE 14066L +#define ERROR_SXS_XML_E_INVALIDENCODING 14067L +#define ERROR_SXS_XML_E_INVALIDSWITCH 14068L +#define ERROR_SXS_XML_E_BADXMLCASE 14069L +#define ERROR_SXS_XML_E_INVALID_STANDALONE 14070L +#define ERROR_SXS_XML_E_UNEXPECTED_STANDALONE 14071L +#define ERROR_SXS_XML_E_INVALID_VERSION 14072L +#define ERROR_SXS_XML_E_MISSINGEQUALS 14073L +#define ERROR_SXS_PROTECTION_RECOVERY_FAILED 14074L +#define ERROR_SXS_PROTECTION_PUBLIC_KEY_TOO_SHORT 14075L +#define ERROR_SXS_PROTECTION_CATALOG_NOT_VALID 14076L +#define ERROR_SXS_UNTRANSLATABLE_HRESULT 14077L +#define ERROR_SXS_PROTECTION_CATALOG_FILE_MISSING 14078L +#define ERROR_SXS_MISSING_ASSEMBLY_IDENTITY_ATTRIBUTE 14079L +#define ERROR_SXS_INVALID_ASSEMBLY_IDENTITY_ATTRIBUTE_NAME 14080L +#define ERROR_IPSEC_QM_POLICY_EXISTS 13000L +#define ERROR_IPSEC_QM_POLICY_NOT_FOUND 13001L +#define ERROR_IPSEC_QM_POLICY_IN_USE 13002L +#define ERROR_IPSEC_MM_POLICY_EXISTS 13003L +#define ERROR_IPSEC_MM_POLICY_NOT_FOUND 13004L +#define ERROR_IPSEC_MM_POLICY_IN_USE 13005L +#define ERROR_IPSEC_MM_FILTER_EXISTS 13006L +#define ERROR_IPSEC_MM_FILTER_NOT_FOUND 13007L +#define ERROR_IPSEC_TRANSPORT_FILTER_EXISTS 13008L +#define ERROR_IPSEC_TRANSPORT_FILTER_NOT_FOUND 13009L +#define ERROR_IPSEC_MM_AUTH_EXISTS 13010L +#define ERROR_IPSEC_MM_AUTH_NOT_FOUND 13011L +#define ERROR_IPSEC_MM_AUTH_IN_USE 13012L +#define ERROR_IPSEC_DEFAULT_MM_POLICY_NOT_FOUND 13013L +#define ERROR_IPSEC_DEFAULT_MM_AUTH_NOT_FOUND 13014L +#define ERROR_IPSEC_DEFAULT_QM_POLICY_NOT_FOUND 13015L +#define ERROR_IPSEC_TUNNEL_FILTER_EXISTS 13016L +#define ERROR_IPSEC_TUNNEL_FILTER_NOT_FOUND 13017L +#define ERROR_IPSEC_MM_FILTER_PENDING_DELETION 13018L +#define ERROR_IPSEC_TRANSPORT_FILTER_PENDING_DELETION 13019L +#define ERROR_IPSEC_TUNNEL_FILTER_PENDING_DELETION 13020L +#define ERROR_IPSEC_MM_POLICY_PENDING_DELETION 13021L +#define ERROR_IPSEC_MM_AUTH_PENDING_DELETION 13022L +#define ERROR_IPSEC_QM_POLICY_PENDING_DELETION 13023L +#define WARNING_IPSEC_MM_POLICY_PRUNED 13024L +#define WARNING_IPSEC_QM_POLICY_PRUNED 13025L +#define ERROR_IPSEC_IKE_NEG_STATUS_BEGIN 13800L +#define ERROR_IPSEC_IKE_AUTH_FAIL 13801L +#define ERROR_IPSEC_IKE_ATTRIB_FAIL 13802L +#define ERROR_IPSEC_IKE_NEGOTIATION_PENDING 13803L +#define ERROR_IPSEC_IKE_GENERAL_PROCESSING_ERROR 13804L +#define ERROR_IPSEC_IKE_TIMED_OUT 13805L +#define ERROR_IPSEC_IKE_NO_CERT 13806L +#define ERROR_IPSEC_IKE_SA_DELETED 13807L +#define ERROR_IPSEC_IKE_SA_REAPED 13808L +#define ERROR_IPSEC_IKE_MM_ACQUIRE_DROP 13809L +#define ERROR_IPSEC_IKE_QM_ACQUIRE_DROP 13810L +#define ERROR_IPSEC_IKE_QUEUE_DROP_MM 13811L +#define ERROR_IPSEC_IKE_QUEUE_DROP_NO_MM 13812L +#define ERROR_IPSEC_IKE_DROP_NO_RESPONSE 13813L +#define ERROR_IPSEC_IKE_MM_DELAY_DROP 13814L +#define ERROR_IPSEC_IKE_QM_DELAY_DROP 13815L +#define ERROR_IPSEC_IKE_ERROR 13816L +#define ERROR_IPSEC_IKE_CRL_FAILED 13817L +#define ERROR_IPSEC_IKE_INVALID_KEY_USAGE 13818L +#define ERROR_IPSEC_IKE_INVALID_CERT_TYPE 13819L +#define ERROR_IPSEC_IKE_NO_PRIVATE_KEY 13820L +#define ERROR_IPSEC_IKE_DH_FAIL 13822L +#define ERROR_IPSEC_IKE_INVALID_HEADER 13824L +#define ERROR_IPSEC_IKE_NO_POLICY 13825L +#define ERROR_IPSEC_IKE_INVALID_SIGNATURE 13826L +#define ERROR_IPSEC_IKE_KERBEROS_ERROR 13827L +#define ERROR_IPSEC_IKE_NO_PUBLIC_KEY 13828L +#define ERROR_IPSEC_IKE_PROCESS_ERR 13829L +#define ERROR_IPSEC_IKE_PROCESS_ERR_SA 13830L +#define ERROR_IPSEC_IKE_PROCESS_ERR_PROP 13831L +#define ERROR_IPSEC_IKE_PROCESS_ERR_TRANS 13832L +#define ERROR_IPSEC_IKE_PROCESS_ERR_KE 13833L +#define ERROR_IPSEC_IKE_PROCESS_ERR_ID 13834L +#define ERROR_IPSEC_IKE_PROCESS_ERR_CERT 13835L +#define ERROR_IPSEC_IKE_PROCESS_ERR_CERT_REQ 13836L +#define ERROR_IPSEC_IKE_PROCESS_ERR_HASH 13837L +#define ERROR_IPSEC_IKE_PROCESS_ERR_SIG 13838L +#define ERROR_IPSEC_IKE_PROCESS_ERR_NONCE 13839L +#define ERROR_IPSEC_IKE_PROCESS_ERR_NOTIFY 13840L +#define ERROR_IPSEC_IKE_PROCESS_ERR_DELETE 13841L +#define ERROR_IPSEC_IKE_PROCESS_ERR_VENDOR 13842L +#define ERROR_IPSEC_IKE_INVALID_PAYLOAD 13843L +#define ERROR_IPSEC_IKE_LOAD_SOFT_SA 13844L +#define ERROR_IPSEC_IKE_SOFT_SA_TORN_DOWN 13845L +#define ERROR_IPSEC_IKE_INVALID_COOKIE 13846L +#define ERROR_IPSEC_IKE_NO_PEER_CERT 13847L +#define ERROR_IPSEC_IKE_PEER_CRL_FAILED 13848L +#define ERROR_IPSEC_IKE_POLICY_CHANGE 13849L +#define ERROR_IPSEC_IKE_NO_MM_POLICY 13850L +#define ERROR_IPSEC_IKE_NOTCBPRIV 13851L +#define ERROR_IPSEC_IKE_SECLOADFAIL 13852L +#define ERROR_IPSEC_IKE_FAILSSPINIT 13853L +#define ERROR_IPSEC_IKE_FAILQUERYSSP 13854L +#define ERROR_IPSEC_IKE_SRVACQFAIL 13855L +#define ERROR_IPSEC_IKE_SRVQUERYCRED 13856L +#define ERROR_IPSEC_IKE_GETSPIFAIL 13857L +#define ERROR_IPSEC_IKE_INVALID_FILTER 13858L +#define ERROR_IPSEC_IKE_OUT_OF_MEMORY 13859L +#define ERROR_IPSEC_IKE_ADD_UPDATE_KEY_FAILED 13860L +#define ERROR_IPSEC_IKE_INVALID_POLICY 13861L +#define ERROR_IPSEC_IKE_UNKNOWN_DOI 13862L +#define ERROR_IPSEC_IKE_INVALID_SITUATION 13863L +#define ERROR_IPSEC_IKE_DH_FAILURE 13864L +#define ERROR_IPSEC_IKE_INVALID_GROUP 13865L +#define ERROR_IPSEC_IKE_ENCRYPT 13866L +#define ERROR_IPSEC_IKE_DECRYPT 13867L +#define ERROR_IPSEC_IKE_POLICY_MATCH 13868L +#define ERROR_IPSEC_IKE_UNSUPPORTED_ID 13869L +#define ERROR_IPSEC_IKE_INVALID_HASH 13870L +#define ERROR_IPSEC_IKE_INVALID_HASH_ALG 13871L +#define ERROR_IPSEC_IKE_INVALID_HASH_SIZE 13872L +#define ERROR_IPSEC_IKE_INVALID_ENCRYPT_ALG 13873L +#define ERROR_IPSEC_IKE_INVALID_AUTH_ALG 13874L +#define ERROR_IPSEC_IKE_INVALID_SIG 13875L +#define ERROR_IPSEC_IKE_LOAD_FAILED 13876L +#define ERROR_IPSEC_IKE_RPC_DELETE 13877L +#define ERROR_IPSEC_IKE_BENIGN_REINIT 13878L +#define ERROR_IPSEC_IKE_INVALID_RESPONDER_LIFETIME_NOTIFY 13879L +#define ERROR_IPSEC_IKE_INVALID_CERT_KEYLEN 13881L +#define ERROR_IPSEC_IKE_MM_LIMIT 13882L +#define ERROR_IPSEC_IKE_NEGOTIATION_DISABLED 13883L +#define ERROR_IPSEC_IKE_NEG_STATUS_END 13884L +#define SEVERITY_SUCCESS 0 +#define SEVERITY_ERROR 1 +#define SUCCEEDED(hr) ((HRESULT)(hr) >= 0) +#define FAILED(hr) ((HRESULT)(hr) < 0) +#define IS_ERROR(Status) ((unsigned long)(Status) >> 31==SEVERITY_ERROR) +#define HRESULT_CODE(hr) ((hr) & 0xFFFF) +#define SCODE_CODE(sc) ((sc) & 0xFFFF) +#define HRESULT_FACILITY(hr) (((hr) >> 16) & 0x1fff) +#define SCODE_FACILITY(sc) (((sc) >> 16) & 0x1fff) +#define HRESULT_SEVERITY(hr) (((hr) >> 31) & 0x1) +#define SCODE_SEVERITY(sc) (((sc) >> 31) & 0x1) +#define MAKE_HRESULT(sev,fac,code) ((HRESULT) (((unsigned long)(sev)<<31) | ((unsigned long)(fac)<<16) | ((unsigned long)(code)))) +#define MAKE_SCODE(sev,fac,code) ((SCODE) (((unsigned long)(sev)<<31) | ((unsigned long)(fac)<<16) | ((unsigned long)(code)))) +#define FACILITY_NT_BIT 0x10000000 +#define __HRESULT_FROM_WIN32(x) ((HRESULT)(x) <= 0 ? ((HRESULT)(x)) : ((HRESULT) (((x) & 0x0000FFFF) | (FACILITY_WIN32 << 16) | 0x80000000))) +#ifdef INLINE_HRESULT_FROM_WIN32 +#ifndef _HRESULT_DEFINED +#define _HRESULT_DEFINED +typedef long HRESULT; +#endif +__CRT_INLINE HRESULT HRESULT_FROM_WIN32(long x) { return x <= 0 ? (HRESULT)x : (HRESULT) (((x) & 0x0000FFFF) | (FACILITY_WIN32 << 16) | 0x80000000);} +#else +#define HRESULT_FROM_WIN32(x) __HRESULT_FROM_WIN32(x) +#endif +#define HRESULT_FROM_NT(x) ((HRESULT) ((x) | FACILITY_NT_BIT)) +#define GetScode(hr) ((SCODE) (hr)) +#define ResultFromScode(sc) ((HRESULT) (sc)) +#define PropagateResult(hrPrevious,scBase) ((HRESULT) scBase) +#ifdef RC_INVOKED +#define _HRESULT_TYPEDEF_(_sc) _sc +#else +#define _HRESULT_TYPEDEF_(_sc) ((HRESULT)_sc) +#endif +#define NOERROR 0 +#define E_UNEXPECTED _HRESULT_TYPEDEF_(0x8000FFFFL) +#define E_NOTIMPL _HRESULT_TYPEDEF_(0x80004001L) +#define E_OUTOFMEMORY _HRESULT_TYPEDEF_(0x8007000EL) +#define E_INVALIDARG _HRESULT_TYPEDEF_(0x80070057L) +#define E_NOINTERFACE _HRESULT_TYPEDEF_(0x80004002L) +#define E_POINTER _HRESULT_TYPEDEF_(0x80004003L) +#define E_HANDLE _HRESULT_TYPEDEF_(0x80070006L) +#define E_ABORT _HRESULT_TYPEDEF_(0x80004004L) +#define E_FAIL _HRESULT_TYPEDEF_(0x80004005L) +#define E_ACCESSDENIED _HRESULT_TYPEDEF_(0x80070005L) +#define E_PENDING _HRESULT_TYPEDEF_(0x8000000AL) +#define CO_E_INIT_TLS _HRESULT_TYPEDEF_(0x80004006L) +#define CO_E_INIT_SHARED_ALLOCATOR _HRESULT_TYPEDEF_(0x80004007L) +#define CO_E_INIT_MEMORY_ALLOCATOR _HRESULT_TYPEDEF_(0x80004008L) +#define CO_E_INIT_CLASS_CACHE _HRESULT_TYPEDEF_(0x80004009L) +#define CO_E_INIT_RPC_CHANNEL _HRESULT_TYPEDEF_(0x8000400AL) +#define CO_E_INIT_TLS_SET_CHANNEL_CONTROL _HRESULT_TYPEDEF_(0x8000400BL) +#define CO_E_INIT_TLS_CHANNEL_CONTROL _HRESULT_TYPEDEF_(0x8000400CL) +#define CO_E_INIT_UNACCEPTED_USER_ALLOCATOR _HRESULT_TYPEDEF_(0x8000400DL) +#define CO_E_INIT_SCM_MUTEX_EXISTS _HRESULT_TYPEDEF_(0x8000400EL) +#define CO_E_INIT_SCM_FILE_MAPPING_EXISTS _HRESULT_TYPEDEF_(0x8000400FL) +#define CO_E_INIT_SCM_MAP_VIEW_OF_FILE _HRESULT_TYPEDEF_(0x80004010L) +#define CO_E_INIT_SCM_EXEC_FAILURE _HRESULT_TYPEDEF_(0x80004011L) +#define CO_E_INIT_ONLY_SINGLE_THREADED _HRESULT_TYPEDEF_(0x80004012L) +#define CO_E_CANT_REMOTE _HRESULT_TYPEDEF_(0x80004013L) +#define CO_E_BAD_SERVER_NAME _HRESULT_TYPEDEF_(0x80004014L) +#define CO_E_WRONG_SERVER_IDENTITY _HRESULT_TYPEDEF_(0x80004015L) +#define CO_E_OLE1DDE_DISABLED _HRESULT_TYPEDEF_(0x80004016L) +#define CO_E_RUNAS_SYNTAX _HRESULT_TYPEDEF_(0x80004017L) +#define CO_E_CREATEPROCESS_FAILURE _HRESULT_TYPEDEF_(0x80004018L) +#define CO_E_RUNAS_CREATEPROCESS_FAILURE _HRESULT_TYPEDEF_(0x80004019L) +#define CO_E_RUNAS_LOGON_FAILURE _HRESULT_TYPEDEF_(0x8000401AL) +#define CO_E_LAUNCH_PERMSSION_DENIED _HRESULT_TYPEDEF_(0x8000401BL) +#define CO_E_START_SERVICE_FAILURE _HRESULT_TYPEDEF_(0x8000401CL) +#define CO_E_REMOTE_COMMUNICATION_FAILURE _HRESULT_TYPEDEF_(0x8000401DL) +#define CO_E_SERVER_START_TIMEOUT _HRESULT_TYPEDEF_(0x8000401EL) +#define CO_E_CLSREG_INCONSISTENT _HRESULT_TYPEDEF_(0x8000401FL) +#define CO_E_IIDREG_INCONSISTENT _HRESULT_TYPEDEF_(0x80004020L) +#define CO_E_NOT_SUPPORTED _HRESULT_TYPEDEF_(0x80004021L) +#define CO_E_RELOAD_DLL _HRESULT_TYPEDEF_(0x80004022L) +#define CO_E_MSI_ERROR _HRESULT_TYPEDEF_(0x80004023L) +#define CO_E_ATTEMPT_TO_CREATE_OUTSIDE_CLIENT_CONTEXT _HRESULT_TYPEDEF_(0x80004024L) +#define CO_E_SERVER_PAUSED _HRESULT_TYPEDEF_(0x80004025L) +#define CO_E_SERVER_NOT_PAUSED _HRESULT_TYPEDEF_(0x80004026L) +#define CO_E_CLASS_DISABLED _HRESULT_TYPEDEF_(0x80004027L) +#define CO_E_CLRNOTAVAILABLE _HRESULT_TYPEDEF_(0x80004028L) +#define CO_E_ASYNC_WORK_REJECTED _HRESULT_TYPEDEF_(0x80004029L) +#define CO_E_SERVER_INIT_TIMEOUT _HRESULT_TYPEDEF_(0x8000402AL) +#define CO_E_NO_SECCTX_IN_ACTIVATE _HRESULT_TYPEDEF_(0x8000402BL) +#define CO_E_TRACKER_CONFIG _HRESULT_TYPEDEF_(0x80004030L) +#define CO_E_THREADPOOL_CONFIG _HRESULT_TYPEDEF_(0x80004031L) +#define CO_E_SXS_CONFIG _HRESULT_TYPEDEF_(0x80004032L) +#define CO_E_MALFORMED_SPN _HRESULT_TYPEDEF_(0x80004033L) +#define S_OK ((HRESULT)0x00000000L) +#define S_FALSE ((HRESULT)0x00000001L) +#define OLE_E_FIRST ((HRESULT)0x80040000L) +#define OLE_E_LAST ((HRESULT)0x800400FFL) +#define OLE_S_FIRST ((HRESULT)0x00040000L) +#define OLE_S_LAST ((HRESULT)0x000400FFL) +#define OLE_E_OLEVERB _HRESULT_TYPEDEF_(0x80040000L) +#define OLE_E_ADVF _HRESULT_TYPEDEF_(0x80040001L) +#define OLE_E_ENUM_NOMORE _HRESULT_TYPEDEF_(0x80040002L) +#define OLE_E_ADVISENOTSUPPORTED _HRESULT_TYPEDEF_(0x80040003L) +#define OLE_E_NOCONNECTION _HRESULT_TYPEDEF_(0x80040004L) +#define OLE_E_NOTRUNNING _HRESULT_TYPEDEF_(0x80040005L) +#define OLE_E_NOCACHE _HRESULT_TYPEDEF_(0x80040006L) +#define OLE_E_BLANK _HRESULT_TYPEDEF_(0x80040007L) +#define OLE_E_CLASSDIFF _HRESULT_TYPEDEF_(0x80040008L) +#define OLE_E_CANT_GETMONIKER _HRESULT_TYPEDEF_(0x80040009L) +#define OLE_E_CANT_BINDTOSOURCE _HRESULT_TYPEDEF_(0x8004000AL) +#define OLE_E_STATIC _HRESULT_TYPEDEF_(0x8004000BL) +#define OLE_E_PROMPTSAVECANCELLED _HRESULT_TYPEDEF_(0x8004000CL) +#define OLE_E_INVALIDRECT _HRESULT_TYPEDEF_(0x8004000DL) +#define OLE_E_WRONGCOMPOBJ _HRESULT_TYPEDEF_(0x8004000EL) +#define OLE_E_INVALIDHWND _HRESULT_TYPEDEF_(0x8004000FL) +#define OLE_E_NOT_INPLACEACTIVE _HRESULT_TYPEDEF_(0x80040010L) +#define OLE_E_CANTCONVERT _HRESULT_TYPEDEF_(0x80040011L) +#define OLE_E_NOSTORAGE _HRESULT_TYPEDEF_(0x80040012L) +#define DV_E_FORMATETC _HRESULT_TYPEDEF_(0x80040064L) +#define DV_E_DVTARGETDEVICE _HRESULT_TYPEDEF_(0x80040065L) +#define DV_E_STGMEDIUM _HRESULT_TYPEDEF_(0x80040066L) +#define DV_E_STATDATA _HRESULT_TYPEDEF_(0x80040067L) +#define DV_E_LINDEX _HRESULT_TYPEDEF_(0x80040068L) +#define DV_E_TYMED _HRESULT_TYPEDEF_(0x80040069L) +#define DV_E_CLIPFORMAT _HRESULT_TYPEDEF_(0x8004006AL) +#define DV_E_DVASPECT _HRESULT_TYPEDEF_(0x8004006BL) +#define DV_E_DVTARGETDEVICE_SIZE _HRESULT_TYPEDEF_(0x8004006CL) +#define DV_E_NOIVIEWOBJECT _HRESULT_TYPEDEF_(0x8004006DL) +#define DRAGDROP_E_FIRST 0x80040100L +#define DRAGDROP_E_LAST 0x8004010FL +#define DRAGDROP_S_FIRST 0x00040100L +#define DRAGDROP_S_LAST 0x0004010FL +#define DRAGDROP_E_NOTREGISTERED _HRESULT_TYPEDEF_(0x80040100L) +#define DRAGDROP_E_ALREADYREGISTERED _HRESULT_TYPEDEF_(0x80040101L) +#define DRAGDROP_E_INVALIDHWND _HRESULT_TYPEDEF_(0x80040102L) +#define CLASSFACTORY_E_FIRST 0x80040110L +#define CLASSFACTORY_E_LAST 0x8004011FL +#define CLASSFACTORY_S_FIRST 0x00040110L +#define CLASSFACTORY_S_LAST 0x0004011FL +#define CLASS_E_NOAGGREGATION _HRESULT_TYPEDEF_(0x80040110L) +#define CLASS_E_CLASSNOTAVAILABLE _HRESULT_TYPEDEF_(0x80040111L) +#define CLASS_E_NOTLICENSED _HRESULT_TYPEDEF_(0x80040112L) +#define MARSHAL_E_FIRST 0x80040120L +#define MARSHAL_E_LAST 0x8004012FL +#define MARSHAL_S_FIRST 0x00040120L +#define MARSHAL_S_LAST 0x0004012FL +#define DATA_E_FIRST 0x80040130L +#define DATA_E_LAST 0x8004013FL +#define DATA_S_FIRST 0x00040130L +#define DATA_S_LAST 0x0004013FL +#define VIEW_E_FIRST 0x80040140L +#define VIEW_E_LAST 0x8004014FL +#define VIEW_S_FIRST 0x00040140L +#define VIEW_S_LAST 0x0004014FL +#define VIEW_E_DRAW _HRESULT_TYPEDEF_(0x80040140L) +#define REGDB_E_FIRST 0x80040150L +#define REGDB_E_LAST 0x8004015FL +#define REGDB_S_FIRST 0x00040150L +#define REGDB_S_LAST 0x0004015FL +#define REGDB_E_READREGDB _HRESULT_TYPEDEF_(0x80040150L) +#define REGDB_E_WRITEREGDB _HRESULT_TYPEDEF_(0x80040151L) +#define REGDB_E_KEYMISSING _HRESULT_TYPEDEF_(0x80040152L) +#define REGDB_E_INVALIDVALUE _HRESULT_TYPEDEF_(0x80040153L) +#define REGDB_E_CLASSNOTREG _HRESULT_TYPEDEF_(0x80040154L) +#define REGDB_E_IIDNOTREG _HRESULT_TYPEDEF_(0x80040155L) +#define REGDB_E_BADTHREADINGMODEL _HRESULT_TYPEDEF_(0x80040156L) +#define CAT_E_FIRST 0x80040160L +#define CAT_E_LAST 0x80040161L +#define CAT_E_CATIDNOEXIST _HRESULT_TYPEDEF_(0x80040160L) +#define CAT_E_NODESCRIPTION _HRESULT_TYPEDEF_(0x80040161L) +#define CS_E_FIRST 0x80040164L +#define CS_E_LAST 0x8004016FL +#define CS_E_PACKAGE_NOTFOUND _HRESULT_TYPEDEF_(0x80040164L) +#define CS_E_NOT_DELETABLE _HRESULT_TYPEDEF_(0x80040165L) +#define CS_E_CLASS_NOTFOUND _HRESULT_TYPEDEF_(0x80040166L) +#define CS_E_INVALID_VERSION _HRESULT_TYPEDEF_(0x80040167L) +#define CS_E_NO_CLASSSTORE _HRESULT_TYPEDEF_(0x80040168L) +#define CS_E_OBJECT_NOTFOUND _HRESULT_TYPEDEF_(0x80040169L) +#define CS_E_OBJECT_ALREADY_EXISTS _HRESULT_TYPEDEF_(0x8004016AL) +#define CS_E_INVALID_PATH _HRESULT_TYPEDEF_(0x8004016BL) +#define CS_E_NETWORK_ERROR _HRESULT_TYPEDEF_(0x8004016CL) +#define CS_E_ADMIN_LIMIT_EXCEEDED _HRESULT_TYPEDEF_(0x8004016DL) +#define CS_E_SCHEMA_MISMATCH _HRESULT_TYPEDEF_(0x8004016EL) +#define CS_E_INTERNAL_ERROR _HRESULT_TYPEDEF_(0x8004016FL) +#define CACHE_E_FIRST 0x80040170L +#define CACHE_E_LAST 0x8004017FL +#define CACHE_S_FIRST 0x00040170L +#define CACHE_S_LAST 0x0004017FL +#define CACHE_E_NOCACHE_UPDATED _HRESULT_TYPEDEF_(0x80040170L) +#define OLEOBJ_E_FIRST 0x80040180L +#define OLEOBJ_E_LAST 0x8004018FL +#define OLEOBJ_S_FIRST 0x00040180L +#define OLEOBJ_S_LAST 0x0004018FL +#define OLEOBJ_E_NOVERBS _HRESULT_TYPEDEF_(0x80040180L) +#define OLEOBJ_E_INVALIDVERB _HRESULT_TYPEDEF_(0x80040181L) +#define CLIENTSITE_E_FIRST 0x80040190L +#define CLIENTSITE_E_LAST 0x8004019FL +#define CLIENTSITE_S_FIRST 0x00040190L +#define CLIENTSITE_S_LAST 0x0004019FL +#define INPLACE_E_NOTUNDOABLE _HRESULT_TYPEDEF_(0x800401A0L) +#define INPLACE_E_NOTOOLSPACE _HRESULT_TYPEDEF_(0x800401A1L) +#define INPLACE_E_FIRST 0x800401A0L +#define INPLACE_E_LAST 0x800401AFL +#define INPLACE_S_FIRST 0x000401A0L +#define INPLACE_S_LAST 0x000401AFL +#define ENUM_E_FIRST 0x800401B0L +#define ENUM_E_LAST 0x800401BFL +#define ENUM_S_FIRST 0x000401B0L +#define ENUM_S_LAST 0x000401BFL +#define CONVERT10_E_FIRST 0x800401C0L +#define CONVERT10_E_LAST 0x800401CFL +#define CONVERT10_S_FIRST 0x000401C0L +#define CONVERT10_S_LAST 0x000401CFL +#define CONVERT10_E_OLESTREAM_GET _HRESULT_TYPEDEF_(0x800401C0L) +#define CONVERT10_E_OLESTREAM_PUT _HRESULT_TYPEDEF_(0x800401C1L) +#define CONVERT10_E_OLESTREAM_FMT _HRESULT_TYPEDEF_(0x800401C2L) +#define CONVERT10_E_OLESTREAM_BITMAP_TO_DIB _HRESULT_TYPEDEF_(0x800401C3L) +#define CONVERT10_E_STG_FMT _HRESULT_TYPEDEF_(0x800401C4L) +#define CONVERT10_E_STG_NO_STD_STREAM _HRESULT_TYPEDEF_(0x800401C5L) +#define CONVERT10_E_STG_DIB_TO_BITMAP _HRESULT_TYPEDEF_(0x800401C6L) +#define CLIPBRD_E_FIRST 0x800401D0L +#define CLIPBRD_E_LAST 0x800401DFL +#define CLIPBRD_S_FIRST 0x000401D0L +#define CLIPBRD_S_LAST 0x000401DFL +#define CLIPBRD_E_CANT_OPEN _HRESULT_TYPEDEF_(0x800401D0L) +#define CLIPBRD_E_CANT_EMPTY _HRESULT_TYPEDEF_(0x800401D1L) +#define CLIPBRD_E_CANT_SET _HRESULT_TYPEDEF_(0x800401D2L) +#define CLIPBRD_E_BAD_DATA _HRESULT_TYPEDEF_(0x800401D3L) +#define CLIPBRD_E_CANT_CLOSE _HRESULT_TYPEDEF_(0x800401D4L) +#define MK_E_FIRST 0x800401E0L +#define MK_E_LAST 0x800401EFL +#define MK_S_FIRST 0x000401E0L +#define MK_S_LAST 0x000401EFL +#define MK_E_CONNECTMANUALLY _HRESULT_TYPEDEF_(0x800401E0L) +#define MK_E_EXCEEDEDDEADLINE _HRESULT_TYPEDEF_(0x800401E1L) +#define MK_E_NEEDGENERIC _HRESULT_TYPEDEF_(0x800401E2L) +#define MK_E_UNAVAILABLE _HRESULT_TYPEDEF_(0x800401E3L) +#define MK_E_SYNTAX _HRESULT_TYPEDEF_(0x800401E4L) +#define MK_E_NOOBJECT _HRESULT_TYPEDEF_(0x800401E5L) +#define MK_E_INVALIDEXTENSION _HRESULT_TYPEDEF_(0x800401E6L) +#define MK_E_INTERMEDIATEINTERFACENOTSUPPORTED _HRESULT_TYPEDEF_(0x800401E7L) +#define MK_E_NOTBINDABLE _HRESULT_TYPEDEF_(0x800401E8L) +#define MK_E_NOTBOUND _HRESULT_TYPEDEF_(0x800401E9L) +#define MK_E_CANTOPENFILE _HRESULT_TYPEDEF_(0x800401EAL) +#define MK_E_MUSTBOTHERUSER _HRESULT_TYPEDEF_(0x800401EBL) +#define MK_E_NOINVERSE _HRESULT_TYPEDEF_(0x800401ECL) +#define MK_E_NOSTORAGE _HRESULT_TYPEDEF_(0x800401EDL) +#define MK_E_NOPREFIX _HRESULT_TYPEDEF_(0x800401EEL) +#define MK_E_ENUMERATION_FAILED _HRESULT_TYPEDEF_(0x800401EFL) +#define CO_E_FIRST 0x800401F0L +#define CO_E_LAST 0x800401FFL +#define CO_S_FIRST 0x000401F0L +#define CO_S_LAST 0x000401FFL +#define CO_E_NOTINITIALIZED _HRESULT_TYPEDEF_(0x800401F0L) +#define CO_E_ALREADYINITIALIZED _HRESULT_TYPEDEF_(0x800401F1L) +#define CO_E_CANTDETERMINECLASS _HRESULT_TYPEDEF_(0x800401F2L) +#define CO_E_CLASSSTRING _HRESULT_TYPEDEF_(0x800401F3L) +#define CO_E_IIDSTRING _HRESULT_TYPEDEF_(0x800401F4L) +#define CO_E_APPNOTFOUND _HRESULT_TYPEDEF_(0x800401F5L) +#define CO_E_APPSINGLEUSE _HRESULT_TYPEDEF_(0x800401F6L) +#define CO_E_ERRORINAPP _HRESULT_TYPEDEF_(0x800401F7L) +#define CO_E_DLLNOTFOUND _HRESULT_TYPEDEF_(0x800401F8L) +#define CO_E_ERRORINDLL _HRESULT_TYPEDEF_(0x800401F9L) +#define CO_E_WRONGOSFORAPP _HRESULT_TYPEDEF_(0x800401FAL) +#define CO_E_OBJNOTREG _HRESULT_TYPEDEF_(0x800401FBL) +#define CO_E_OBJISREG _HRESULT_TYPEDEF_(0x800401FCL) +#define CO_E_OBJNOTCONNECTED _HRESULT_TYPEDEF_(0x800401FDL) +#define CO_E_APPDIDNTREG _HRESULT_TYPEDEF_(0x800401FEL) +#define CO_E_RELEASED _HRESULT_TYPEDEF_(0x800401FFL) +#define EVENT_E_FIRST 0x80040200L +#define EVENT_E_LAST 0x8004021FL +#define EVENT_S_FIRST 0x00040200L +#define EVENT_S_LAST 0x0004021FL +#define EVENT_S_SOME_SUBSCRIBERS_FAILED _HRESULT_TYPEDEF_(0x00040200L) +#define EVENT_E_ALL_SUBSCRIBERS_FAILED _HRESULT_TYPEDEF_(0x80040201L) +#define EVENT_S_NOSUBSCRIBERS _HRESULT_TYPEDEF_(0x00040202L) +#define EVENT_E_QUERYSYNTAX _HRESULT_TYPEDEF_(0x80040203L) +#define EVENT_E_QUERYFIELD _HRESULT_TYPEDEF_(0x80040204L) +#define EVENT_E_INTERNALEXCEPTION _HRESULT_TYPEDEF_(0x80040205L) +#define EVENT_E_INTERNALERROR _HRESULT_TYPEDEF_(0x80040206L) +#define EVENT_E_INVALID_PER_USER_SID _HRESULT_TYPEDEF_(0x80040207L) +#define EVENT_E_USER_EXCEPTION _HRESULT_TYPEDEF_(0x80040208L) +#define EVENT_E_TOO_MANY_METHODS _HRESULT_TYPEDEF_(0x80040209L) +#define EVENT_E_MISSING_EVENTCLASS _HRESULT_TYPEDEF_(0x8004020AL) +#define EVENT_E_NOT_ALL_REMOVED _HRESULT_TYPEDEF_(0x8004020BL) +#define EVENT_E_COMPLUS_NOT_INSTALLED _HRESULT_TYPEDEF_(0x8004020CL) +#define EVENT_E_CANT_MODIFY_OR_DELETE_UNCONFIGURED_OBJECT _HRESULT_TYPEDEF_(0x8004020DL) +#define EVENT_E_CANT_MODIFY_OR_DELETE_CONFIGURED_OBJECT _HRESULT_TYPEDEF_(0x8004020EL) +#define EVENT_E_INVALID_EVENT_CLASS_PARTITION _HRESULT_TYPEDEF_(0x8004020FL) +#define EVENT_E_PER_USER_SID_NOT_LOGGED_ON _HRESULT_TYPEDEF_(0x80040210L) +#define XACT_E_FIRST 0x8004D000 +#define XACT_E_LAST 0x8004D029 +#define XACT_S_FIRST 0x0004D000 +#define XACT_S_LAST 0x0004D010 +#define XACT_E_ALREADYOTHERSINGLEPHASE _HRESULT_TYPEDEF_(0x8004D000L) +#define XACT_E_CANTRETAIN _HRESULT_TYPEDEF_(0x8004D001L) +#define XACT_E_COMMITFAILED _HRESULT_TYPEDEF_(0x8004D002L) +#define XACT_E_COMMITPREVENTED _HRESULT_TYPEDEF_(0x8004D003L) +#define XACT_E_HEURISTICABORT _HRESULT_TYPEDEF_(0x8004D004L) +#define XACT_E_HEURISTICCOMMIT _HRESULT_TYPEDEF_(0x8004D005L) +#define XACT_E_HEURISTICDAMAGE _HRESULT_TYPEDEF_(0x8004D006L) +#define XACT_E_HEURISTICDANGER _HRESULT_TYPEDEF_(0x8004D007L) +#define XACT_E_ISOLATIONLEVEL _HRESULT_TYPEDEF_(0x8004D008L) +#define XACT_E_NOASYNC _HRESULT_TYPEDEF_(0x8004D009L) +#define XACT_E_NOENLIST _HRESULT_TYPEDEF_(0x8004D00AL) +#define XACT_E_NOISORETAIN _HRESULT_TYPEDEF_(0x8004D00BL) +#define XACT_E_NORESOURCE _HRESULT_TYPEDEF_(0x8004D00CL) +#define XACT_E_NOTCURRENT _HRESULT_TYPEDEF_(0x8004D00DL) +#define XACT_E_NOTRANSACTION _HRESULT_TYPEDEF_(0x8004D00EL) +#define XACT_E_NOTSUPPORTED _HRESULT_TYPEDEF_(0x8004D00FL) +#define XACT_E_UNKNOWNRMGRID _HRESULT_TYPEDEF_(0x8004D010L) +#define XACT_E_WRONGSTATE _HRESULT_TYPEDEF_(0x8004D011L) +#define XACT_E_WRONGUOW _HRESULT_TYPEDEF_(0x8004D012L) +#define XACT_E_XTIONEXISTS _HRESULT_TYPEDEF_(0x8004D013L) +#define XACT_E_NOIMPORTOBJECT _HRESULT_TYPEDEF_(0x8004D014L) +#define XACT_E_INVALIDCOOKIE _HRESULT_TYPEDEF_(0x8004D015L) +#define XACT_E_INDOUBT _HRESULT_TYPEDEF_(0x8004D016L) +#define XACT_E_NOTIMEOUT _HRESULT_TYPEDEF_(0x8004D017L) +#define XACT_E_ALREADYINPROGRESS _HRESULT_TYPEDEF_(0x8004D018L) +#define XACT_E_ABORTED _HRESULT_TYPEDEF_(0x8004D019L) +#define XACT_E_LOGFULL _HRESULT_TYPEDEF_(0x8004D01AL) +#define XACT_E_TMNOTAVAILABLE _HRESULT_TYPEDEF_(0x8004D01BL) +#define XACT_E_CONNECTION_DOWN _HRESULT_TYPEDEF_(0x8004D01CL) +#define XACT_E_CONNECTION_DENIED _HRESULT_TYPEDEF_(0x8004D01DL) +#define XACT_E_REENLISTTIMEOUT _HRESULT_TYPEDEF_(0x8004D01EL) +#define XACT_E_TIP_CONNECT_FAILED _HRESULT_TYPEDEF_(0x8004D01FL) +#define XACT_E_TIP_PROTOCOL_ERROR _HRESULT_TYPEDEF_(0x8004D020L) +#define XACT_E_TIP_PULL_FAILED _HRESULT_TYPEDEF_(0x8004D021L) +#define XACT_E_DEST_TMNOTAVAILABLE _HRESULT_TYPEDEF_(0x8004D022L) +#define XACT_E_TIP_DISABLED _HRESULT_TYPEDEF_(0x8004D023L) +#define XACT_E_NETWORK_TX_DISABLED _HRESULT_TYPEDEF_(0x8004D024L) +#define XACT_E_PARTNER_NETWORK_TX_DISABLED _HRESULT_TYPEDEF_(0x8004D025L) +#define XACT_E_XA_TX_DISABLED _HRESULT_TYPEDEF_(0x8004D026L) +#define XACT_E_UNABLE_TO_READ_DTC_CONFIG _HRESULT_TYPEDEF_(0x8004D027L) +#define XACT_E_UNABLE_TO_LOAD_DTC_PROXY _HRESULT_TYPEDEF_(0x8004D028L) +#define XACT_E_ABORTING _HRESULT_TYPEDEF_(0x8004D029L) +#define XACT_E_CLERKNOTFOUND _HRESULT_TYPEDEF_(0x8004D080L) +#define XACT_E_CLERKEXISTS _HRESULT_TYPEDEF_(0x8004D081L) +#define XACT_E_RECOVERYINPROGRESS _HRESULT_TYPEDEF_(0x8004D082L) +#define XACT_E_TRANSACTIONCLOSED _HRESULT_TYPEDEF_(0x8004D083L) +#define XACT_E_INVALIDLSN _HRESULT_TYPEDEF_(0x8004D084L) +#define XACT_E_REPLAYREQUEST _HRESULT_TYPEDEF_(0x8004D085L) +#define XACT_S_ASYNC _HRESULT_TYPEDEF_(0x0004D000L) +#define XACT_S_DEFECT _HRESULT_TYPEDEF_(0x0004D001L) +#define XACT_S_READONLY _HRESULT_TYPEDEF_(0x0004D002L) +#define XACT_S_SOMENORETAIN _HRESULT_TYPEDEF_(0x0004D003L) +#define XACT_S_OKINFORM _HRESULT_TYPEDEF_(0x0004D004L) +#define XACT_S_MADECHANGESCONTENT _HRESULT_TYPEDEF_(0x0004D005L) +#define XACT_S_MADECHANGESINFORM _HRESULT_TYPEDEF_(0x0004D006L) +#define XACT_S_ALLNORETAIN _HRESULT_TYPEDEF_(0x0004D007L) +#define XACT_S_ABORTING _HRESULT_TYPEDEF_(0x0004D008L) +#define XACT_S_SINGLEPHASE _HRESULT_TYPEDEF_(0x0004D009L) +#define XACT_S_LOCALLY_OK _HRESULT_TYPEDEF_(0x0004D00AL) +#define XACT_S_LASTRESOURCEMANAGER _HRESULT_TYPEDEF_(0x0004D010L) +#define CONTEXT_E_FIRST 0x8004E000L +#define CONTEXT_E_LAST 0x8004E02FL +#define CONTEXT_S_FIRST 0x0004E000L +#define CONTEXT_S_LAST 0x0004E02FL +#define CONTEXT_E_ABORTED _HRESULT_TYPEDEF_(0x8004E002L) +#define CONTEXT_E_ABORTING _HRESULT_TYPEDEF_(0x8004E003L) +#define CONTEXT_E_NOCONTEXT _HRESULT_TYPEDEF_(0x8004E004L) +#define CONTEXT_E_WOULD_DEADLOCK _HRESULT_TYPEDEF_(0x8004E005L) +#define CONTEXT_E_SYNCH_TIMEOUT _HRESULT_TYPEDEF_(0x8004E006L) +#define CONTEXT_E_OLDREF _HRESULT_TYPEDEF_(0x8004E007L) +#define CONTEXT_E_ROLENOTFOUND _HRESULT_TYPEDEF_(0x8004E00CL) +#define CONTEXT_E_TMNOTAVAILABLE _HRESULT_TYPEDEF_(0x8004E00FL) +#define CO_E_ACTIVATIONFAILED _HRESULT_TYPEDEF_(0x8004E021L) +#define CO_E_ACTIVATIONFAILED_EVENTLOGGED _HRESULT_TYPEDEF_(0x8004E022L) +#define CO_E_ACTIVATIONFAILED_CATALOGERROR _HRESULT_TYPEDEF_(0x8004E023L) +#define CO_E_ACTIVATIONFAILED_TIMEOUT _HRESULT_TYPEDEF_(0x8004E024L) +#define CO_E_INITIALIZATIONFAILED _HRESULT_TYPEDEF_(0x8004E025L) +#define CONTEXT_E_NOJIT _HRESULT_TYPEDEF_(0x8004E026L) +#define CONTEXT_E_NOTRANSACTION _HRESULT_TYPEDEF_(0x8004E027L) +#define CO_E_THREADINGMODEL_CHANGED _HRESULT_TYPEDEF_(0x8004E028L) +#define CO_E_NOIISINTRINSICS _HRESULT_TYPEDEF_(0x8004E029L) +#define CO_E_NOCOOKIES _HRESULT_TYPEDEF_(0x8004E02AL) +#define CO_E_DBERROR _HRESULT_TYPEDEF_(0x8004E02BL) +#define CO_E_NOTPOOLED _HRESULT_TYPEDEF_(0x8004E02CL) +#define CO_E_NOTCONSTRUCTED _HRESULT_TYPEDEF_(0x8004E02DL) +#define CO_E_NOSYNCHRONIZATION _HRESULT_TYPEDEF_(0x8004E02EL) +#define CO_E_ISOLEVELMISMATCH _HRESULT_TYPEDEF_(0x8004E02FL) +#define OLE_S_USEREG _HRESULT_TYPEDEF_(0x00040000L) +#define OLE_S_STATIC _HRESULT_TYPEDEF_(0x00040001L) +#define OLE_S_MAC_CLIPFORMAT _HRESULT_TYPEDEF_(0x00040002L) +#define DRAGDROP_S_DROP _HRESULT_TYPEDEF_(0x00040100L) +#define DRAGDROP_S_CANCEL _HRESULT_TYPEDEF_(0x00040101L) +#define DRAGDROP_S_USEDEFAULTCURSORS _HRESULT_TYPEDEF_(0x00040102L) +#define DATA_S_SAMEFORMATETC _HRESULT_TYPEDEF_(0x00040130L) +#define VIEW_S_ALREADY_FROZEN _HRESULT_TYPEDEF_(0x00040140L) +#define CACHE_S_FORMATETC_NOTSUPPORTED _HRESULT_TYPEDEF_(0x00040170L) +#define CACHE_S_SAMECACHE _HRESULT_TYPEDEF_(0x00040171L) +#define CACHE_S_SOMECACHES_NOTUPDATED _HRESULT_TYPEDEF_(0x00040172L) +#define OLEOBJ_S_INVALIDVERB _HRESULT_TYPEDEF_(0x00040180L) +#define OLEOBJ_S_CANNOT_DOVERB_NOW _HRESULT_TYPEDEF_(0x00040181L) +#define OLEOBJ_S_INVALIDHWND _HRESULT_TYPEDEF_(0x00040182L) +#define INPLACE_S_TRUNCATED _HRESULT_TYPEDEF_(0x000401A0L) +#define CONVERT10_S_NO_PRESENTATION _HRESULT_TYPEDEF_(0x000401C0L) +#define MK_S_REDUCED_TO_SELF _HRESULT_TYPEDEF_(0x000401E2L) +#define MK_S_ME _HRESULT_TYPEDEF_(0x000401E4L) +#define MK_S_HIM _HRESULT_TYPEDEF_(0x000401E5L) +#define MK_S_US _HRESULT_TYPEDEF_(0x000401E6L) +#define MK_S_MONIKERALREADYREGISTERED _HRESULT_TYPEDEF_(0x000401E7L) +#define SCHED_S_TASK_READY _HRESULT_TYPEDEF_(0x00041300L) +#define SCHED_S_TASK_RUNNING _HRESULT_TYPEDEF_(0x00041301L) +#define SCHED_S_TASK_DISABLED _HRESULT_TYPEDEF_(0x00041302L) +#define SCHED_S_TASK_HAS_NOT_RUN _HRESULT_TYPEDEF_(0x00041303L) +#define SCHED_S_TASK_NO_MORE_RUNS _HRESULT_TYPEDEF_(0x00041304L) +#define SCHED_S_TASK_NOT_SCHEDULED _HRESULT_TYPEDEF_(0x00041305L) +#define SCHED_S_TASK_TERMINATED _HRESULT_TYPEDEF_(0x00041306L) +#define SCHED_S_TASK_NO_VALID_TRIGGERS _HRESULT_TYPEDEF_(0x00041307L) +#define SCHED_S_EVENT_TRIGGER _HRESULT_TYPEDEF_(0x00041308L) +#define SCHED_E_TRIGGER_NOT_FOUND _HRESULT_TYPEDEF_(0x80041309L) +#define SCHED_E_TASK_NOT_READY _HRESULT_TYPEDEF_(0x8004130AL) +#define SCHED_E_TASK_NOT_RUNNING _HRESULT_TYPEDEF_(0x8004130BL) +#define SCHED_E_SERVICE_NOT_INSTALLED _HRESULT_TYPEDEF_(0x8004130CL) +#define SCHED_E_CANNOT_OPEN_TASK _HRESULT_TYPEDEF_(0x8004130DL) +#define SCHED_E_INVALID_TASK _HRESULT_TYPEDEF_(0x8004130EL) +#define SCHED_E_ACCOUNT_INFORMATION_NOT_SET _HRESULT_TYPEDEF_(0x8004130FL) +#define SCHED_E_ACCOUNT_NAME_NOT_FOUND _HRESULT_TYPEDEF_(0x80041310L) +#define SCHED_E_ACCOUNT_DBASE_CORRUPT _HRESULT_TYPEDEF_(0x80041311L) +#define SCHED_E_NO_SECURITY_SERVICES _HRESULT_TYPEDEF_(0x80041312L) +#define SCHED_E_UNKNOWN_OBJECT_VERSION _HRESULT_TYPEDEF_(0x80041313L) +#define SCHED_E_UNSUPPORTED_ACCOUNT_OPTION _HRESULT_TYPEDEF_(0x80041314L) +#define SCHED_E_SERVICE_NOT_RUNNING _HRESULT_TYPEDEF_(0x80041315L) +#define CO_E_CLASS_CREATE_FAILED _HRESULT_TYPEDEF_(0x80080001L) +#define CO_E_SCM_ERROR _HRESULT_TYPEDEF_(0x80080002L) +#define CO_E_SCM_RPC_FAILURE _HRESULT_TYPEDEF_(0x80080003L) +#define CO_E_BAD_PATH _HRESULT_TYPEDEF_(0x80080004L) +#define CO_E_SERVER_EXEC_FAILURE _HRESULT_TYPEDEF_(0x80080005L) +#define CO_E_OBJSRV_RPC_FAILURE _HRESULT_TYPEDEF_(0x80080006L) +#define MK_E_NO_NORMALIZED _HRESULT_TYPEDEF_(0x80080007L) +#define CO_E_SERVER_STOPPING _HRESULT_TYPEDEF_(0x80080008L) +#define MEM_E_INVALID_ROOT _HRESULT_TYPEDEF_(0x80080009L) +#define MEM_E_INVALID_LINK _HRESULT_TYPEDEF_(0x80080010L) +#define MEM_E_INVALID_SIZE _HRESULT_TYPEDEF_(0x80080011L) +#define CO_S_NOTALLINTERFACES _HRESULT_TYPEDEF_(0x00080012L) +#define CO_S_MACHINENAMENOTFOUND _HRESULT_TYPEDEF_(0x00080013L) +#define DISP_E_UNKNOWNINTERFACE _HRESULT_TYPEDEF_(0x80020001L) +#define DISP_E_MEMBERNOTFOUND _HRESULT_TYPEDEF_(0x80020003L) +#define DISP_E_PARAMNOTFOUND _HRESULT_TYPEDEF_(0x80020004L) +#define DISP_E_TYPEMISMATCH _HRESULT_TYPEDEF_(0x80020005L) +#define DISP_E_UNKNOWNNAME _HRESULT_TYPEDEF_(0x80020006L) +#define DISP_E_NONAMEDARGS _HRESULT_TYPEDEF_(0x80020007L) +#define DISP_E_BADVARTYPE _HRESULT_TYPEDEF_(0x80020008L) +#define DISP_E_EXCEPTION _HRESULT_TYPEDEF_(0x80020009L) +#define DISP_E_OVERFLOW _HRESULT_TYPEDEF_(0x8002000AL) +#define DISP_E_BADINDEX _HRESULT_TYPEDEF_(0x8002000BL) +#define DISP_E_UNKNOWNLCID _HRESULT_TYPEDEF_(0x8002000CL) +#define DISP_E_ARRAYISLOCKED _HRESULT_TYPEDEF_(0x8002000DL) +#define DISP_E_BADPARAMCOUNT _HRESULT_TYPEDEF_(0x8002000EL) +#define DISP_E_PARAMNOTOPTIONAL _HRESULT_TYPEDEF_(0x8002000FL) +#define DISP_E_BADCALLEE _HRESULT_TYPEDEF_(0x80020010L) +#define DISP_E_NOTACOLLECTION _HRESULT_TYPEDEF_(0x80020011L) +#define DISP_E_DIVBYZERO _HRESULT_TYPEDEF_(0x80020012L) +#define DISP_E_BUFFERTOOSMALL _HRESULT_TYPEDEF_(0x80020013L) +#define TYPE_E_BUFFERTOOSMALL _HRESULT_TYPEDEF_(0x80028016L) +#define TYPE_E_FIELDNOTFOUND _HRESULT_TYPEDEF_(0x80028017L) +#define TYPE_E_INVDATAREAD _HRESULT_TYPEDEF_(0x80028018L) +#define TYPE_E_UNSUPFORMAT _HRESULT_TYPEDEF_(0x80028019L) +#define TYPE_E_REGISTRYACCESS _HRESULT_TYPEDEF_(0x8002801CL) +#define TYPE_E_LIBNOTREGISTERED _HRESULT_TYPEDEF_(0x8002801DL) +#define TYPE_E_UNDEFINEDTYPE _HRESULT_TYPEDEF_(0x80028027L) +#define TYPE_E_QUALIFIEDNAMEDISALLOWED _HRESULT_TYPEDEF_(0x80028028L) +#define TYPE_E_INVALIDSTATE _HRESULT_TYPEDEF_(0x80028029L) +#define TYPE_E_WRONGTYPEKIND _HRESULT_TYPEDEF_(0x8002802AL) +#define TYPE_E_ELEMENTNOTFOUND _HRESULT_TYPEDEF_(0x8002802BL) +#define TYPE_E_AMBIGUOUSNAME _HRESULT_TYPEDEF_(0x8002802CL) +#define TYPE_E_NAMECONFLICT _HRESULT_TYPEDEF_(0x8002802DL) +#define TYPE_E_UNKNOWNLCID _HRESULT_TYPEDEF_(0x8002802EL) +#define TYPE_E_DLLFUNCTIONNOTFOUND _HRESULT_TYPEDEF_(0x8002802FL) +#define TYPE_E_BADMODULEKIND _HRESULT_TYPEDEF_(0x800288BDL) +#define TYPE_E_SIZETOOBIG _HRESULT_TYPEDEF_(0x800288C5L) +#define TYPE_E_DUPLICATEID _HRESULT_TYPEDEF_(0x800288C6L) +#define TYPE_E_INVALIDID _HRESULT_TYPEDEF_(0x800288CFL) +#define TYPE_E_TYPEMISMATCH _HRESULT_TYPEDEF_(0x80028CA0L) +#define TYPE_E_OUTOFBOUNDS _HRESULT_TYPEDEF_(0x80028CA1L) +#define TYPE_E_IOERROR _HRESULT_TYPEDEF_(0x80028CA2L) +#define TYPE_E_CANTCREATETMPFILE _HRESULT_TYPEDEF_(0x80028CA3L) +#define TYPE_E_CANTLOADLIBRARY _HRESULT_TYPEDEF_(0x80029C4AL) +#define TYPE_E_INCONSISTENTPROPFUNCS _HRESULT_TYPEDEF_(0x80029C83L) +#define TYPE_E_CIRCULARTYPE _HRESULT_TYPEDEF_(0x80029C84L) +#define STG_E_INVALIDFUNCTION _HRESULT_TYPEDEF_(0x80030001L) +#define STG_E_FILENOTFOUND _HRESULT_TYPEDEF_(0x80030002L) +#define STG_E_PATHNOTFOUND _HRESULT_TYPEDEF_(0x80030003L) +#define STG_E_TOOMANYOPENFILES _HRESULT_TYPEDEF_(0x80030004L) +#define STG_E_ACCESSDENIED _HRESULT_TYPEDEF_(0x80030005L) +#define STG_E_INVALIDHANDLE _HRESULT_TYPEDEF_(0x80030006L) +#define STG_E_INSUFFICIENTMEMORY _HRESULT_TYPEDEF_(0x80030008L) +#define STG_E_INVALIDPOINTER _HRESULT_TYPEDEF_(0x80030009L) +#define STG_E_NOMOREFILES _HRESULT_TYPEDEF_(0x80030012L) +#define STG_E_DISKISWRITEPROTECTED _HRESULT_TYPEDEF_(0x80030013L) +#define STG_E_SEEKERROR _HRESULT_TYPEDEF_(0x80030019L) +#define STG_E_WRITEFAULT _HRESULT_TYPEDEF_(0x8003001DL) +#define STG_E_READFAULT _HRESULT_TYPEDEF_(0x8003001EL) +#define STG_E_SHAREVIOLATION _HRESULT_TYPEDEF_(0x80030020L) +#define STG_E_LOCKVIOLATION _HRESULT_TYPEDEF_(0x80030021L) +#define STG_E_FILEALREADYEXISTS _HRESULT_TYPEDEF_(0x80030050L) +#define STG_E_INVALIDPARAMETER _HRESULT_TYPEDEF_(0x80030057L) +#define STG_E_MEDIUMFULL _HRESULT_TYPEDEF_(0x80030070L) +#define STG_E_PROPSETMISMATCHED _HRESULT_TYPEDEF_(0x800300F0L) +#define STG_E_ABNORMALAPIEXIT _HRESULT_TYPEDEF_(0x800300FAL) +#define STG_E_INVALIDHEADER _HRESULT_TYPEDEF_(0x800300FBL) +#define STG_E_INVALIDNAME _HRESULT_TYPEDEF_(0x800300FCL) +#define STG_E_UNKNOWN _HRESULT_TYPEDEF_(0x800300FDL) +#define STG_E_UNIMPLEMENTEDFUNCTION _HRESULT_TYPEDEF_(0x800300FEL) +#define STG_E_INVALIDFLAG _HRESULT_TYPEDEF_(0x800300FFL) +#define STG_E_INUSE _HRESULT_TYPEDEF_(0x80030100L) +#define STG_E_NOTCURRENT _HRESULT_TYPEDEF_(0x80030101L) +#define STG_E_REVERTED _HRESULT_TYPEDEF_(0x80030102L) +#define STG_E_CANTSAVE _HRESULT_TYPEDEF_(0x80030103L) +#define STG_E_OLDFORMAT _HRESULT_TYPEDEF_(0x80030104L) +#define STG_E_OLDDLL _HRESULT_TYPEDEF_(0x80030105L) +#define STG_E_SHAREREQUIRED _HRESULT_TYPEDEF_(0x80030106L) +#define STG_E_NOTFILEBASEDSTORAGE _HRESULT_TYPEDEF_(0x80030107L) +#define STG_E_EXTANTMARSHALLINGS _HRESULT_TYPEDEF_(0x80030108L) +#define STG_E_DOCFILECORRUPT _HRESULT_TYPEDEF_(0x80030109L) +#define STG_E_BADBASEADDRESS _HRESULT_TYPEDEF_(0x80030110L) +#define STG_E_DOCFILETOOLARGE _HRESULT_TYPEDEF_(0x80030111L) +#define STG_E_NOTSIMPLEFORMAT _HRESULT_TYPEDEF_(0x80030112L) +#define STG_E_INCOMPLETE _HRESULT_TYPEDEF_(0x80030201L) +#define STG_E_TERMINATED _HRESULT_TYPEDEF_(0x80030202L) +#define STG_S_CONVERTED _HRESULT_TYPEDEF_(0x00030200L) +#define STG_S_BLOCK _HRESULT_TYPEDEF_(0x00030201L) +#define STG_S_RETRYNOW _HRESULT_TYPEDEF_(0x00030202L) +#define STG_S_MONITORING _HRESULT_TYPEDEF_(0x00030203L) +#define STG_S_MULTIPLEOPENS _HRESULT_TYPEDEF_(0x00030204L) +#define STG_S_CONSOLIDATIONFAILED _HRESULT_TYPEDEF_(0x00030205L) +#define STG_S_CANNOTCONSOLIDATE _HRESULT_TYPEDEF_(0x00030206L) +#define STG_E_STATUS_COPY_PROTECTION_FAILURE _HRESULT_TYPEDEF_(0x80030305L) +#define STG_E_CSS_AUTHENTICATION_FAILURE _HRESULT_TYPEDEF_(0x80030306L) +#define STG_E_CSS_KEY_NOT_PRESENT _HRESULT_TYPEDEF_(0x80030307L) +#define STG_E_CSS_KEY_NOT_ESTABLISHED _HRESULT_TYPEDEF_(0x80030308L) +#define STG_E_CSS_SCRAMBLED_SECTOR _HRESULT_TYPEDEF_(0x80030309L) +#define STG_E_CSS_REGION_MISMATCH _HRESULT_TYPEDEF_(0x8003030AL) +#define STG_E_RESETS_EXHAUSTED _HRESULT_TYPEDEF_(0x8003030BL) +#define RPC_E_CALL_REJECTED _HRESULT_TYPEDEF_(0x80010001L) +#define RPC_E_CALL_CANCELED _HRESULT_TYPEDEF_(0x80010002L) +#define RPC_E_CANTPOST_INSENDCALL _HRESULT_TYPEDEF_(0x80010003L) +#define RPC_E_CANTCALLOUT_INASYNCCALL _HRESULT_TYPEDEF_(0x80010004L) +#define RPC_E_CANTCALLOUT_INEXTERNALCALL _HRESULT_TYPEDEF_(0x80010005L) +#define RPC_E_CONNECTION_TERMINATED _HRESULT_TYPEDEF_(0x80010006L) +#define RPC_E_SERVER_DIED _HRESULT_TYPEDEF_(0x80010007L) +#define RPC_E_CLIENT_DIED _HRESULT_TYPEDEF_(0x80010008L) +#define RPC_E_INVALID_DATAPACKET _HRESULT_TYPEDEF_(0x80010009L) +#define RPC_E_CANTTRANSMIT_CALL _HRESULT_TYPEDEF_(0x8001000AL) +#define RPC_E_CLIENT_CANTMARSHAL_DATA _HRESULT_TYPEDEF_(0x8001000BL) +#define RPC_E_CLIENT_CANTUNMARSHAL_DATA _HRESULT_TYPEDEF_(0x8001000CL) +#define RPC_E_SERVER_CANTMARSHAL_DATA _HRESULT_TYPEDEF_(0x8001000DL) +#define RPC_E_SERVER_CANTUNMARSHAL_DATA _HRESULT_TYPEDEF_(0x8001000EL) +#define RPC_E_INVALID_DATA _HRESULT_TYPEDEF_(0x8001000FL) +#define RPC_E_INVALID_PARAMETER _HRESULT_TYPEDEF_(0x80010010L) +#define RPC_E_CANTCALLOUT_AGAIN _HRESULT_TYPEDEF_(0x80010011L) +#define RPC_E_SERVER_DIED_DNE _HRESULT_TYPEDEF_(0x80010012L) +#define RPC_E_SYS_CALL_FAILED _HRESULT_TYPEDEF_(0x80010100L) +#define RPC_E_OUT_OF_RESOURCES _HRESULT_TYPEDEF_(0x80010101L) +#define RPC_E_ATTEMPTED_MULTITHREAD _HRESULT_TYPEDEF_(0x80010102L) +#define RPC_E_NOT_REGISTERED _HRESULT_TYPEDEF_(0x80010103L) +#define RPC_E_FAULT _HRESULT_TYPEDEF_(0x80010104L) +#define RPC_E_SERVERFAULT _HRESULT_TYPEDEF_(0x80010105L) +#define RPC_E_CHANGED_MODE _HRESULT_TYPEDEF_(0x80010106L) +#define RPC_E_INVALIDMETHOD _HRESULT_TYPEDEF_(0x80010107L) +#define RPC_E_DISCONNECTED _HRESULT_TYPEDEF_(0x80010108L) +#define RPC_E_RETRY _HRESULT_TYPEDEF_(0x80010109L) +#define RPC_E_SERVERCALL_RETRYLATER _HRESULT_TYPEDEF_(0x8001010AL) +#define RPC_E_SERVERCALL_REJECTED _HRESULT_TYPEDEF_(0x8001010BL) +#define RPC_E_INVALID_CALLDATA _HRESULT_TYPEDEF_(0x8001010CL) +#define RPC_E_CANTCALLOUT_ININPUTSYNCCALL _HRESULT_TYPEDEF_(0x8001010DL) +#define RPC_E_WRONG_THREAD _HRESULT_TYPEDEF_(0x8001010EL) +#define RPC_E_THREAD_NOT_INIT _HRESULT_TYPEDEF_(0x8001010FL) +#define RPC_E_VERSION_MISMATCH _HRESULT_TYPEDEF_(0x80010110L) +#define RPC_E_INVALID_HEADER _HRESULT_TYPEDEF_(0x80010111L) +#define RPC_E_INVALID_EXTENSION _HRESULT_TYPEDEF_(0x80010112L) +#define RPC_E_INVALID_IPID _HRESULT_TYPEDEF_(0x80010113L) +#define RPC_E_INVALID_OBJECT _HRESULT_TYPEDEF_(0x80010114L) +#define RPC_S_CALLPENDING _HRESULT_TYPEDEF_(0x80010115L) +#define RPC_S_WAITONTIMER _HRESULT_TYPEDEF_(0x80010116L) +#define RPC_E_CALL_COMPLETE _HRESULT_TYPEDEF_(0x80010117L) +#define RPC_E_UNSECURE_CALL _HRESULT_TYPEDEF_(0x80010118L) +#define RPC_E_TOO_LATE _HRESULT_TYPEDEF_(0x80010119L) +#define RPC_E_NO_GOOD_SECURITY_PACKAGES _HRESULT_TYPEDEF_(0x8001011AL) +#define RPC_E_ACCESS_DENIED _HRESULT_TYPEDEF_(0x8001011BL) +#define RPC_E_REMOTE_DISABLED _HRESULT_TYPEDEF_(0x8001011CL) +#define RPC_E_INVALID_OBJREF _HRESULT_TYPEDEF_(0x8001011DL) +#define RPC_E_NO_CONTEXT _HRESULT_TYPEDEF_(0x8001011EL) +#define RPC_E_TIMEOUT _HRESULT_TYPEDEF_(0x8001011FL) +#define RPC_E_NO_SYNC _HRESULT_TYPEDEF_(0x80010120L) +#define RPC_E_FULLSIC_REQUIRED _HRESULT_TYPEDEF_(0x80010121L) +#define RPC_E_INVALID_STD_NAME _HRESULT_TYPEDEF_(0x80010122L) +#define CO_E_FAILEDTOIMPERSONATE _HRESULT_TYPEDEF_(0x80010123L) +#define CO_E_FAILEDTOGETSECCTX _HRESULT_TYPEDEF_(0x80010124L) +#define CO_E_FAILEDTOOPENTHREADTOKEN _HRESULT_TYPEDEF_(0x80010125L) +#define CO_E_FAILEDTOGETTOKENINFO _HRESULT_TYPEDEF_(0x80010126L) +#define CO_E_TRUSTEEDOESNTMATCHCLIENT _HRESULT_TYPEDEF_(0x80010127L) +#define CO_E_FAILEDTOQUERYCLIENTBLANKET _HRESULT_TYPEDEF_(0x80010128L) +#define CO_E_FAILEDTOSETDACL _HRESULT_TYPEDEF_(0x80010129L) +#define CO_E_ACCESSCHECKFAILED _HRESULT_TYPEDEF_(0x8001012AL) +#define CO_E_NETACCESSAPIFAILED _HRESULT_TYPEDEF_(0x8001012BL) +#define CO_E_WRONGTRUSTEENAMESYNTAX _HRESULT_TYPEDEF_(0x8001012CL) +#define CO_E_INVALIDSID _HRESULT_TYPEDEF_(0x8001012DL) +#define CO_E_CONVERSIONFAILED _HRESULT_TYPEDEF_(0x8001012EL) +#define CO_E_NOMATCHINGSIDFOUND _HRESULT_TYPEDEF_(0x8001012FL) +#define CO_E_LOOKUPACCSIDFAILED _HRESULT_TYPEDEF_(0x80010130L) +#define CO_E_NOMATCHINGNAMEFOUND _HRESULT_TYPEDEF_(0x80010131L) +#define CO_E_LOOKUPACCNAMEFAILED _HRESULT_TYPEDEF_(0x80010132L) +#define CO_E_SETSERLHNDLFAILED _HRESULT_TYPEDEF_(0x80010133L) +#define CO_E_FAILEDTOGETWINDIR _HRESULT_TYPEDEF_(0x80010134L) +#define CO_E_PATHTOOLONG _HRESULT_TYPEDEF_(0x80010135L) +#define CO_E_FAILEDTOGENUUID _HRESULT_TYPEDEF_(0x80010136L) +#define CO_E_FAILEDTOCREATEFILE _HRESULT_TYPEDEF_(0x80010137L) +#define CO_E_FAILEDTOCLOSEHANDLE _HRESULT_TYPEDEF_(0x80010138L) +#define CO_E_EXCEEDSYSACLLIMIT _HRESULT_TYPEDEF_(0x80010139L) +#define CO_E_ACESINWRONGORDER _HRESULT_TYPEDEF_(0x8001013AL) +#define CO_E_INCOMPATIBLESTREAMVERSION _HRESULT_TYPEDEF_(0x8001013BL) +#define CO_E_FAILEDTOOPENPROCESSTOKEN _HRESULT_TYPEDEF_(0x8001013CL) +#define CO_E_DECODEFAILED _HRESULT_TYPEDEF_(0x8001013DL) +#define CO_E_ACNOTINITIALIZED _HRESULT_TYPEDEF_(0x8001013FL) +#define CO_E_CANCEL_DISABLED _HRESULT_TYPEDEF_(0x80010140L) +#define RPC_E_UNEXPECTED _HRESULT_TYPEDEF_(0x8001FFFFL) +#define ERROR_AUDITING_DISABLED _HRESULT_TYPEDEF_(0xC0090001L) +#define ERROR_ALL_SIDS_FILTERED _HRESULT_TYPEDEF_(0xC0090002L) +#define NTE_BAD_UID _HRESULT_TYPEDEF_(0x80090001L) +#define NTE_BAD_HASH _HRESULT_TYPEDEF_(0x80090002L) +#define NTE_BAD_KEY _HRESULT_TYPEDEF_(0x80090003L) +#define NTE_BAD_LEN _HRESULT_TYPEDEF_(0x80090004L) +#define NTE_BAD_DATA _HRESULT_TYPEDEF_(0x80090005L) +#define NTE_BAD_SIGNATURE _HRESULT_TYPEDEF_(0x80090006L) +#define NTE_BAD_VER _HRESULT_TYPEDEF_(0x80090007L) +#define NTE_BAD_ALGID _HRESULT_TYPEDEF_(0x80090008L) +#define NTE_BAD_FLAGS _HRESULT_TYPEDEF_(0x80090009L) +#define NTE_BAD_TYPE _HRESULT_TYPEDEF_(0x8009000AL) +#define NTE_BAD_KEY_STATE _HRESULT_TYPEDEF_(0x8009000BL) +#define NTE_BAD_HASH_STATE _HRESULT_TYPEDEF_(0x8009000CL) +#define NTE_NO_KEY _HRESULT_TYPEDEF_(0x8009000DL) +#define NTE_NO_MEMORY _HRESULT_TYPEDEF_(0x8009000EL) +#define NTE_EXISTS _HRESULT_TYPEDEF_(0x8009000FL) +#define NTE_PERM _HRESULT_TYPEDEF_(0x80090010L) +#define NTE_NOT_FOUND _HRESULT_TYPEDEF_(0x80090011L) +#define NTE_DOUBLE_ENCRYPT _HRESULT_TYPEDEF_(0x80090012L) +#define NTE_BAD_PROVIDER _HRESULT_TYPEDEF_(0x80090013L) +#define NTE_BAD_PROV_TYPE _HRESULT_TYPEDEF_(0x80090014L) +#define NTE_BAD_PUBLIC_KEY _HRESULT_TYPEDEF_(0x80090015L) +#define NTE_BAD_KEYSET _HRESULT_TYPEDEF_(0x80090016L) +#define NTE_PROV_TYPE_NOT_DEF _HRESULT_TYPEDEF_(0x80090017L) +#define NTE_PROV_TYPE_ENTRY_BAD _HRESULT_TYPEDEF_(0x80090018L) +#define NTE_KEYSET_NOT_DEF _HRESULT_TYPEDEF_(0x80090019L) +#define NTE_KEYSET_ENTRY_BAD _HRESULT_TYPEDEF_(0x8009001AL) +#define NTE_PROV_TYPE_NO_MATCH _HRESULT_TYPEDEF_(0x8009001BL) +#define NTE_SIGNATURE_FILE_BAD _HRESULT_TYPEDEF_(0x8009001CL) +#define NTE_PROVIDER_DLL_FAIL _HRESULT_TYPEDEF_(0x8009001DL) +#define NTE_PROV_DLL_NOT_FOUND _HRESULT_TYPEDEF_(0x8009001EL) +#define NTE_BAD_KEYSET_PARAM _HRESULT_TYPEDEF_(0x8009001FL) +#define NTE_FAIL _HRESULT_TYPEDEF_(0x80090020L) +#define NTE_SYS_ERR _HRESULT_TYPEDEF_(0x80090021L) +#define NTE_SILENT_CONTEXT _HRESULT_TYPEDEF_(0x80090022L) +#define NTE_TOKEN_KEYSET_STORAGE_FULL _HRESULT_TYPEDEF_(0x80090023L) +#define NTE_TEMPORARY_PROFILE _HRESULT_TYPEDEF_(0x80090024L) +#define NTE_FIXEDPARAMETER _HRESULT_TYPEDEF_(0x80090025L) +#define SEC_E_INSUFFICIENT_MEMORY _HRESULT_TYPEDEF_(0x80090300L) +#define SEC_E_INVALID_HANDLE _HRESULT_TYPEDEF_(0x80090301L) +#define SEC_E_UNSUPPORTED_FUNCTION _HRESULT_TYPEDEF_(0x80090302L) +#define SEC_E_TARGET_UNKNOWN _HRESULT_TYPEDEF_(0x80090303L) +#define SEC_E_INTERNAL_ERROR _HRESULT_TYPEDEF_(0x80090304L) +#define SEC_E_SECPKG_NOT_FOUND _HRESULT_TYPEDEF_(0x80090305L) +#define SEC_E_NOT_OWNER _HRESULT_TYPEDEF_(0x80090306L) +#define SEC_E_CANNOT_INSTALL _HRESULT_TYPEDEF_(0x80090307L) +#define SEC_E_INVALID_TOKEN _HRESULT_TYPEDEF_(0x80090308L) +#define SEC_E_CANNOT_PACK _HRESULT_TYPEDEF_(0x80090309L) +#define SEC_E_QOP_NOT_SUPPORTED _HRESULT_TYPEDEF_(0x8009030AL) +#define SEC_E_NO_IMPERSONATION _HRESULT_TYPEDEF_(0x8009030BL) +#define SEC_E_LOGON_DENIED _HRESULT_TYPEDEF_(0x8009030CL) +#define SEC_E_UNKNOWN_CREDENTIALS _HRESULT_TYPEDEF_(0x8009030DL) +#define SEC_E_NO_CREDENTIALS _HRESULT_TYPEDEF_(0x8009030EL) +#define SEC_E_MESSAGE_ALTERED _HRESULT_TYPEDEF_(0x8009030FL) +#define SEC_E_OUT_OF_SEQUENCE _HRESULT_TYPEDEF_(0x80090310L) +#define SEC_E_NO_AUTHENTICATING_AUTHORITY _HRESULT_TYPEDEF_(0x80090311L) +#define SEC_I_CONTINUE_NEEDED _HRESULT_TYPEDEF_(0x00090312L) +#define SEC_I_COMPLETE_NEEDED _HRESULT_TYPEDEF_(0x00090313L) +#define SEC_I_COMPLETE_AND_CONTINUE _HRESULT_TYPEDEF_(0x00090314L) +#define SEC_I_LOCAL_LOGON _HRESULT_TYPEDEF_(0x00090315L) +#define SEC_E_BAD_PKGID _HRESULT_TYPEDEF_(0x80090316L) +#define SEC_E_CONTEXT_EXPIRED _HRESULT_TYPEDEF_(0x80090317L) +#define SEC_I_CONTEXT_EXPIRED _HRESULT_TYPEDEF_(0x00090317L) +#define SEC_E_INCOMPLETE_MESSAGE _HRESULT_TYPEDEF_(0x80090318L) +#define SEC_E_INCOMPLETE_CREDENTIALS _HRESULT_TYPEDEF_(0x80090320L) +#define SEC_E_BUFFER_TOO_SMALL _HRESULT_TYPEDEF_(0x80090321L) +#define SEC_I_INCOMPLETE_CREDENTIALS _HRESULT_TYPEDEF_(0x00090320L) +#define SEC_I_RENEGOTIATE _HRESULT_TYPEDEF_(0x00090321L) +#define SEC_E_WRONG_PRINCIPAL _HRESULT_TYPEDEF_(0x80090322L) +#define SEC_I_NO_LSA_CONTEXT _HRESULT_TYPEDEF_(0x00090323L) +#define SEC_E_TIME_SKEW _HRESULT_TYPEDEF_(0x80090324L) +#define SEC_E_UNTRUSTED_ROOT _HRESULT_TYPEDEF_(0x80090325L) +#define SEC_E_ILLEGAL_MESSAGE _HRESULT_TYPEDEF_(0x80090326L) +#define SEC_E_CERT_UNKNOWN _HRESULT_TYPEDEF_(0x80090327L) +#define SEC_E_CERT_EXPIRED _HRESULT_TYPEDEF_(0x80090328L) +#define SEC_E_ENCRYPT_FAILURE _HRESULT_TYPEDEF_(0x80090329L) +#define SEC_E_DECRYPT_FAILURE _HRESULT_TYPEDEF_(0x80090330L) +#define SEC_E_ALGORITHM_MISMATCH _HRESULT_TYPEDEF_(0x80090331L) +#define SEC_E_SECURITY_QOS_FAILED _HRESULT_TYPEDEF_(0x80090332L) +#define SEC_E_UNFINISHED_CONTEXT_DELETED _HRESULT_TYPEDEF_(0x80090333L) +#define SEC_E_NO_TGT_REPLY _HRESULT_TYPEDEF_(0x80090334L) +#define SEC_E_NO_IP_ADDRESSES _HRESULT_TYPEDEF_(0x80090335L) +#define SEC_E_WRONG_CREDENTIAL_HANDLE _HRESULT_TYPEDEF_(0x80090336L) +#define SEC_E_CRYPTO_SYSTEM_INVALID _HRESULT_TYPEDEF_(0x80090337L) +#define SEC_E_MAX_REFERRALS_EXCEEDED _HRESULT_TYPEDEF_(0x80090338L) +#define SEC_E_MUST_BE_KDC _HRESULT_TYPEDEF_(0x80090339L) +#define SEC_E_STRONG_CRYPTO_NOT_SUPPORTED _HRESULT_TYPEDEF_(0x8009033AL) +#define SEC_E_TOO_MANY_PRINCIPALS _HRESULT_TYPEDEF_(0x8009033BL) +#define SEC_E_NO_PA_DATA _HRESULT_TYPEDEF_(0x8009033CL) +#define SEC_E_PKINIT_NAME_MISMATCH _HRESULT_TYPEDEF_(0x8009033DL) +#define SEC_E_SMARTCARD_LOGON_REQUIRED _HRESULT_TYPEDEF_(0x8009033EL) +#define SEC_E_SHUTDOWN_IN_PROGRESS _HRESULT_TYPEDEF_(0x8009033FL) +#define SEC_E_KDC_INVALID_REQUEST _HRESULT_TYPEDEF_(0x80090340L) +#define SEC_E_KDC_UNABLE_TO_REFER _HRESULT_TYPEDEF_(0x80090341L) +#define SEC_E_KDC_UNKNOWN_ETYPE _HRESULT_TYPEDEF_(0x80090342L) +#define SEC_E_UNSUPPORTED_PREAUTH _HRESULT_TYPEDEF_(0x80090343L) +#define SEC_E_DELEGATION_REQUIRED _HRESULT_TYPEDEF_(0x80090345L) +#define SEC_E_BAD_BINDINGS _HRESULT_TYPEDEF_(0x80090346L) +#define SEC_E_MULTIPLE_ACCOUNTS _HRESULT_TYPEDEF_(0x80090347L) +#define SEC_E_NO_KERB_KEY _HRESULT_TYPEDEF_(0x80090348L) +#define SEC_E_CERT_WRONG_USAGE _HRESULT_TYPEDEF_(0x80090349L) +#define SEC_E_DOWNGRADE_DETECTED _HRESULT_TYPEDEF_(0x80090350L) +#define SEC_E_SMARTCARD_CERT_REVOKED _HRESULT_TYPEDEF_(0x80090351L) +#define SEC_E_ISSUING_CA_UNTRUSTED _HRESULT_TYPEDEF_(0x80090352L) +#define SEC_E_REVOCATION_OFFLINE_C _HRESULT_TYPEDEF_(0x80090353L) +#define SEC_E_PKINIT_CLIENT_FAILURE _HRESULT_TYPEDEF_(0x80090354L) +#define SEC_E_SMARTCARD_CERT_EXPIRED _HRESULT_TYPEDEF_(0x80090355L) +#define SEC_E_NO_S4U_PROT_SUPPORT _HRESULT_TYPEDEF_(0x80090356L) +#define SEC_E_CROSSREALM_DELEGATION_FAILURE _HRESULT_TYPEDEF_(0x80090357L) +#define SEC_E_REVOCATION_OFFLINE_KDC _HRESULT_TYPEDEF_(0x80090358L) +#define SEC_E_ISSUING_CA_UNTRUSTED_KDC _HRESULT_TYPEDEF_(0x80090359L) +#define SEC_E_KDC_CERT_EXPIRED _HRESULT_TYPEDEF_(0x8009035AL) +#define SEC_E_KDC_CERT_REVOKED _HRESULT_TYPEDEF_(0x8009035BL) +#define SEC_E_NO_SPM SEC_E_INTERNAL_ERROR +#define SEC_E_NOT_SUPPORTED SEC_E_UNSUPPORTED_FUNCTION +#define CRYPT_E_MSG_ERROR _HRESULT_TYPEDEF_(0x80091001L) +#define CRYPT_E_UNKNOWN_ALGO _HRESULT_TYPEDEF_(0x80091002L) +#define CRYPT_E_OID_FORMAT _HRESULT_TYPEDEF_(0x80091003L) +#define CRYPT_E_INVALID_MSG_TYPE _HRESULT_TYPEDEF_(0x80091004L) +#define CRYPT_E_UNEXPECTED_ENCODING _HRESULT_TYPEDEF_(0x80091005L) +#define CRYPT_E_AUTH_ATTR_MISSING _HRESULT_TYPEDEF_(0x80091006L) +#define CRYPT_E_HASH_VALUE _HRESULT_TYPEDEF_(0x80091007L) +#define CRYPT_E_INVALID_INDEX _HRESULT_TYPEDEF_(0x80091008L) +#define CRYPT_E_ALREADY_DECRYPTED _HRESULT_TYPEDEF_(0x80091009L) +#define CRYPT_E_NOT_DECRYPTED _HRESULT_TYPEDEF_(0x8009100AL) +#define CRYPT_E_RECIPIENT_NOT_FOUND _HRESULT_TYPEDEF_(0x8009100BL) +#define CRYPT_E_CONTROL_TYPE _HRESULT_TYPEDEF_(0x8009100CL) +#define CRYPT_E_ISSUER_SERIALNUMBER _HRESULT_TYPEDEF_(0x8009100DL) +#define CRYPT_E_SIGNER_NOT_FOUND _HRESULT_TYPEDEF_(0x8009100EL) +#define CRYPT_E_ATTRIBUTES_MISSING _HRESULT_TYPEDEF_(0x8009100FL) +#define CRYPT_E_STREAM_MSG_NOT_READY _HRESULT_TYPEDEF_(0x80091010L) +#define CRYPT_E_STREAM_INSUFFICIENT_DATA _HRESULT_TYPEDEF_(0x80091011L) +#define CRYPT_I_NEW_PROTECTION_REQUIRED _HRESULT_TYPEDEF_(0x00091012L) +#define CRYPT_E_BAD_LEN _HRESULT_TYPEDEF_(0x80092001L) +#define CRYPT_E_BAD_ENCODE _HRESULT_TYPEDEF_(0x80092002L) +#define CRYPT_E_FILE_ERROR _HRESULT_TYPEDEF_(0x80092003L) +#define CRYPT_E_NOT_FOUND _HRESULT_TYPEDEF_(0x80092004L) +#define CRYPT_E_EXISTS _HRESULT_TYPEDEF_(0x80092005L) +#define CRYPT_E_NO_PROVIDER _HRESULT_TYPEDEF_(0x80092006L) +#define CRYPT_E_SELF_SIGNED _HRESULT_TYPEDEF_(0x80092007L) +#define CRYPT_E_DELETED_PREV _HRESULT_TYPEDEF_(0x80092008L) +#define CRYPT_E_NO_MATCH _HRESULT_TYPEDEF_(0x80092009L) +#define CRYPT_E_UNEXPECTED_MSG_TYPE _HRESULT_TYPEDEF_(0x8009200AL) +#define CRYPT_E_NO_KEY_PROPERTY _HRESULT_TYPEDEF_(0x8009200BL) +#define CRYPT_E_NO_DECRYPT_CERT _HRESULT_TYPEDEF_(0x8009200CL) +#define CRYPT_E_BAD_MSG _HRESULT_TYPEDEF_(0x8009200DL) +#define CRYPT_E_NO_SIGNER _HRESULT_TYPEDEF_(0x8009200EL) +#define CRYPT_E_PENDING_CLOSE _HRESULT_TYPEDEF_(0x8009200FL) +#define CRYPT_E_REVOKED _HRESULT_TYPEDEF_(0x80092010L) +#define CRYPT_E_NO_REVOCATION_DLL _HRESULT_TYPEDEF_(0x80092011L) +#define CRYPT_E_NO_REVOCATION_CHECK _HRESULT_TYPEDEF_(0x80092012L) +#define CRYPT_E_REVOCATION_OFFLINE _HRESULT_TYPEDEF_(0x80092013L) +#define CRYPT_E_NOT_IN_REVOCATION_DATABASE _HRESULT_TYPEDEF_(0x80092014L) +#define CRYPT_E_INVALID_NUMERIC_STRING _HRESULT_TYPEDEF_(0x80092020L) +#define CRYPT_E_INVALID_PRINTABLE_STRING _HRESULT_TYPEDEF_(0x80092021L) +#define CRYPT_E_INVALID_IA5_STRING _HRESULT_TYPEDEF_(0x80092022L) +#define CRYPT_E_INVALID_X500_STRING _HRESULT_TYPEDEF_(0x80092023L) +#define CRYPT_E_NOT_CHAR_STRING _HRESULT_TYPEDEF_(0x80092024L) +#define CRYPT_E_FILERESIZED _HRESULT_TYPEDEF_(0x80092025L) +#define CRYPT_E_SECURITY_SETTINGS _HRESULT_TYPEDEF_(0x80092026L) +#define CRYPT_E_NO_VERIFY_USAGE_DLL _HRESULT_TYPEDEF_(0x80092027L) +#define CRYPT_E_NO_VERIFY_USAGE_CHECK _HRESULT_TYPEDEF_(0x80092028L) +#define CRYPT_E_VERIFY_USAGE_OFFLINE _HRESULT_TYPEDEF_(0x80092029L) +#define CRYPT_E_NOT_IN_CTL _HRESULT_TYPEDEF_(0x8009202AL) +#define CRYPT_E_NO_TRUSTED_SIGNER _HRESULT_TYPEDEF_(0x8009202BL) +#define CRYPT_E_MISSING_PUBKEY_PARA _HRESULT_TYPEDEF_(0x8009202CL) +#define CRYPT_E_OSS_ERROR _HRESULT_TYPEDEF_(0x80093000L) +#define OSS_MORE_BUF _HRESULT_TYPEDEF_(0x80093001L) +#define OSS_NEGATIVE_UINTEGER _HRESULT_TYPEDEF_(0x80093002L) +#define OSS_PDU_RANGE _HRESULT_TYPEDEF_(0x80093003L) +#define OSS_MORE_INPUT _HRESULT_TYPEDEF_(0x80093004L) +#define OSS_DATA_ERROR _HRESULT_TYPEDEF_(0x80093005L) +#define OSS_BAD_ARG _HRESULT_TYPEDEF_(0x80093006L) +#define OSS_BAD_VERSION _HRESULT_TYPEDEF_(0x80093007L) +#define OSS_OUT_MEMORY _HRESULT_TYPEDEF_(0x80093008L) +#define OSS_PDU_MISMATCH _HRESULT_TYPEDEF_(0x80093009L) +#define OSS_LIMITED _HRESULT_TYPEDEF_(0x8009300AL) +#define OSS_BAD_PTR _HRESULT_TYPEDEF_(0x8009300BL) +#define OSS_BAD_TIME _HRESULT_TYPEDEF_(0x8009300CL) +#define OSS_INDEFINITE_NOT_SUPPORTED _HRESULT_TYPEDEF_(0x8009300DL) +#define OSS_MEM_ERROR _HRESULT_TYPEDEF_(0x8009300EL) +#define OSS_BAD_TABLE _HRESULT_TYPEDEF_(0x8009300FL) +#define OSS_TOO_LONG _HRESULT_TYPEDEF_(0x80093010L) +#define OSS_CONSTRAINT_VIOLATED _HRESULT_TYPEDEF_(0x80093011L) +#define OSS_FATAL_ERROR _HRESULT_TYPEDEF_(0x80093012L) +#define OSS_ACCESS_SERIALIZATION_ERROR _HRESULT_TYPEDEF_(0x80093013L) +#define OSS_NULL_TBL _HRESULT_TYPEDEF_(0x80093014L) +#define OSS_NULL_FCN _HRESULT_TYPEDEF_(0x80093015L) +#define OSS_BAD_ENCRULES _HRESULT_TYPEDEF_(0x80093016L) +#define OSS_UNAVAIL_ENCRULES _HRESULT_TYPEDEF_(0x80093017L) +#define OSS_CANT_OPEN_TRACE_WINDOW _HRESULT_TYPEDEF_(0x80093018L) +#define OSS_UNIMPLEMENTED _HRESULT_TYPEDEF_(0x80093019L) +#define OSS_OID_DLL_NOT_LINKED _HRESULT_TYPEDEF_(0x8009301AL) +#define OSS_CANT_OPEN_TRACE_FILE _HRESULT_TYPEDEF_(0x8009301BL) +#define OSS_TRACE_FILE_ALREADY_OPEN _HRESULT_TYPEDEF_(0x8009301CL) +#define OSS_TABLE_MISMATCH _HRESULT_TYPEDEF_(0x8009301DL) +#define OSS_TYPE_NOT_SUPPORTED _HRESULT_TYPEDEF_(0x8009301EL) +#define OSS_REAL_DLL_NOT_LINKED _HRESULT_TYPEDEF_(0x8009301FL) +#define OSS_REAL_CODE_NOT_LINKED _HRESULT_TYPEDEF_(0x80093020L) +#define OSS_OUT_OF_RANGE _HRESULT_TYPEDEF_(0x80093021L) +#define OSS_COPIER_DLL_NOT_LINKED _HRESULT_TYPEDEF_(0x80093022L) +#define OSS_CONSTRAINT_DLL_NOT_LINKED _HRESULT_TYPEDEF_(0x80093023L) +#define OSS_COMPARATOR_DLL_NOT_LINKED _HRESULT_TYPEDEF_(0x80093024L) +#define OSS_COMPARATOR_CODE_NOT_LINKED _HRESULT_TYPEDEF_(0x80093025L) +#define OSS_MEM_MGR_DLL_NOT_LINKED _HRESULT_TYPEDEF_(0x80093026L) +#define OSS_PDV_DLL_NOT_LINKED _HRESULT_TYPEDEF_(0x80093027L) +#define OSS_PDV_CODE_NOT_LINKED _HRESULT_TYPEDEF_(0x80093028L) +#define OSS_API_DLL_NOT_LINKED _HRESULT_TYPEDEF_(0x80093029L) +#define OSS_BERDER_DLL_NOT_LINKED _HRESULT_TYPEDEF_(0x8009302AL) +#define OSS_PER_DLL_NOT_LINKED _HRESULT_TYPEDEF_(0x8009302BL) +#define OSS_OPEN_TYPE_ERROR _HRESULT_TYPEDEF_(0x8009302CL) +#define OSS_MUTEX_NOT_CREATED _HRESULT_TYPEDEF_(0x8009302DL) +#define OSS_CANT_CLOSE_TRACE_FILE _HRESULT_TYPEDEF_(0x8009302EL) +#define CRYPT_E_ASN1_ERROR _HRESULT_TYPEDEF_(0x80093100L) +#define CRYPT_E_ASN1_INTERNAL _HRESULT_TYPEDEF_(0x80093101L) +#define CRYPT_E_ASN1_EOD _HRESULT_TYPEDEF_(0x80093102L) +#define CRYPT_E_ASN1_CORRUPT _HRESULT_TYPEDEF_(0x80093103L) +#define CRYPT_E_ASN1_LARGE _HRESULT_TYPEDEF_(0x80093104L) +#define CRYPT_E_ASN1_CONSTRAINT _HRESULT_TYPEDEF_(0x80093105L) +#define CRYPT_E_ASN1_MEMORY _HRESULT_TYPEDEF_(0x80093106L) +#define CRYPT_E_ASN1_OVERFLOW _HRESULT_TYPEDEF_(0x80093107L) +#define CRYPT_E_ASN1_BADPDU _HRESULT_TYPEDEF_(0x80093108L) +#define CRYPT_E_ASN1_BADARGS _HRESULT_TYPEDEF_(0x80093109L) +#define CRYPT_E_ASN1_BADREAL _HRESULT_TYPEDEF_(0x8009310AL) +#define CRYPT_E_ASN1_BADTAG _HRESULT_TYPEDEF_(0x8009310BL) +#define CRYPT_E_ASN1_CHOICE _HRESULT_TYPEDEF_(0x8009310CL) +#define CRYPT_E_ASN1_RULE _HRESULT_TYPEDEF_(0x8009310DL) +#define CRYPT_E_ASN1_UTF8 _HRESULT_TYPEDEF_(0x8009310EL) +#define CRYPT_E_ASN1_PDU_TYPE _HRESULT_TYPEDEF_(0x80093133L) +#define CRYPT_E_ASN1_NYI _HRESULT_TYPEDEF_(0x80093134L) +#define CRYPT_E_ASN1_EXTENDED _HRESULT_TYPEDEF_(0x80093201L) +#define CRYPT_E_ASN1_NOEOD _HRESULT_TYPEDEF_(0x80093202L) +#define CERTSRV_E_BAD_REQUESTSUBJECT _HRESULT_TYPEDEF_(0x80094001L) +#define CERTSRV_E_NO_REQUEST _HRESULT_TYPEDEF_(0x80094002L) +#define CERTSRV_E_BAD_REQUESTSTATUS _HRESULT_TYPEDEF_(0x80094003L) +#define CERTSRV_E_PROPERTY_EMPTY _HRESULT_TYPEDEF_(0x80094004L) +#define CERTSRV_E_INVALID_CA_CERTIFICATE _HRESULT_TYPEDEF_(0x80094005L) +#define CERTSRV_E_SERVER_SUSPENDED _HRESULT_TYPEDEF_(0x80094006L) +#define CERTSRV_E_ENCODING_LENGTH _HRESULT_TYPEDEF_(0x80094007L) +#define CERTSRV_E_ROLECONFLICT _HRESULT_TYPEDEF_(0x80094008L) +#define CERTSRV_E_RESTRICTEDOFFICER _HRESULT_TYPEDEF_(0x80094009L) +#define CERTSRV_E_KEY_ARCHIVAL_NOT_CONFIGURED _HRESULT_TYPEDEF_(0x8009400AL) +#define CERTSRV_E_NO_VALID_KRA _HRESULT_TYPEDEF_(0x8009400BL) +#define CERTSRV_E_BAD_REQUEST_KEY_ARCHIVAL _HRESULT_TYPEDEF_(0x8009400CL) +#define CERTSRV_E_NO_CAADMIN_DEFINED _HRESULT_TYPEDEF_(0x8009400DL) +#define CERTSRV_E_BAD_RENEWAL_CERT_ATTRIBUTE _HRESULT_TYPEDEF_(0x8009400EL) +#define CERTSRV_E_NO_DB_SESSIONS _HRESULT_TYPEDEF_(0x8009400FL) +#define CERTSRV_E_ALIGNMENT_FAULT _HRESULT_TYPEDEF_(0x80094010L) +#define CERTSRV_E_ENROLL_DENIED _HRESULT_TYPEDEF_(0x80094011L) +#define CERTSRV_E_TEMPLATE_DENIED _HRESULT_TYPEDEF_(0x80094012L) +#define CERTSRV_E_DOWNLEVEL_DC_SSL_OR_UPGRADE _HRESULT_TYPEDEF_(0x80094013L) +#define CERTSRV_E_UNSUPPORTED_CERT_TYPE _HRESULT_TYPEDEF_(0x80094800L) +#define CERTSRV_E_NO_CERT_TYPE _HRESULT_TYPEDEF_(0x80094801L) +#define CERTSRV_E_TEMPLATE_CONFLICT _HRESULT_TYPEDEF_(0x80094802L) +#define CERTSRV_E_SUBJECT_ALT_NAME_REQUIRED _HRESULT_TYPEDEF_(0x80094803L) +#define CERTSRV_E_ARCHIVED_KEY_REQUIRED _HRESULT_TYPEDEF_(0x80094804L) +#define CERTSRV_E_SMIME_REQUIRED _HRESULT_TYPEDEF_(0x80094805L) +#define CERTSRV_E_BAD_RENEWAL_SUBJECT _HRESULT_TYPEDEF_(0x80094806L) +#define CERTSRV_E_BAD_TEMPLATE_VERSION _HRESULT_TYPEDEF_(0x80094807L) +#define CERTSRV_E_TEMPLATE_POLICY_REQUIRED _HRESULT_TYPEDEF_(0x80094808L) +#define CERTSRV_E_SIGNATURE_POLICY_REQUIRED _HRESULT_TYPEDEF_(0x80094809L) +#define CERTSRV_E_SIGNATURE_COUNT _HRESULT_TYPEDEF_(0x8009480AL) +#define CERTSRV_E_SIGNATURE_REJECTED _HRESULT_TYPEDEF_(0x8009480BL) +#define CERTSRV_E_ISSUANCE_POLICY_REQUIRED _HRESULT_TYPEDEF_(0x8009480CL) +#define CERTSRV_E_SUBJECT_UPN_REQUIRED _HRESULT_TYPEDEF_(0x8009480DL) +#define CERTSRV_E_SUBJECT_DIRECTORY_GUID_REQUIRED _HRESULT_TYPEDEF_(0x8009480EL) +#define CERTSRV_E_SUBJECT_DNS_REQUIRED _HRESULT_TYPEDEF_(0x8009480FL) +#define CERTSRV_E_ARCHIVED_KEY_UNEXPECTED _HRESULT_TYPEDEF_(0x80094810L) +#define CERTSRV_E_KEY_LENGTH _HRESULT_TYPEDEF_(0x80094811L) +#define CERTSRV_E_SUBJECT_EMAIL_REQUIRED _HRESULT_TYPEDEF_(0x80094812L) +#define CERTSRV_E_UNKNOWN_CERT_TYPE _HRESULT_TYPEDEF_(0x80094813L) +#define CERTSRV_E_CERT_TYPE_OVERLAP _HRESULT_TYPEDEF_(0x80094814L) +#define XENROLL_E_KEY_NOT_EXPORTABLE _HRESULT_TYPEDEF_(0x80095000L) +#define XENROLL_E_CANNOT_ADD_ROOT_CERT _HRESULT_TYPEDEF_(0x80095001L) +#define XENROLL_E_RESPONSE_KA_HASH_NOT_FOUND _HRESULT_TYPEDEF_(0x80095002L) +#define XENROLL_E_RESPONSE_UNEXPECTED_KA_HASH _HRESULT_TYPEDEF_(0x80095003L) +#define XENROLL_E_RESPONSE_KA_HASH_MISMATCH _HRESULT_TYPEDEF_(0x80095004L) +#define XENROLL_E_KEYSPEC_SMIME_MISMATCH _HRESULT_TYPEDEF_(0x80095005L) +#define TRUST_E_SYSTEM_ERROR _HRESULT_TYPEDEF_(0x80096001L) +#define TRUST_E_NO_SIGNER_CERT _HRESULT_TYPEDEF_(0x80096002L) +#define TRUST_E_COUNTER_SIGNER _HRESULT_TYPEDEF_(0x80096003L) +#define TRUST_E_CERT_SIGNATURE _HRESULT_TYPEDEF_(0x80096004L) +#define TRUST_E_TIME_STAMP _HRESULT_TYPEDEF_(0x80096005L) +#define TRUST_E_BAD_DIGEST _HRESULT_TYPEDEF_(0x80096010L) +#define TRUST_E_BASIC_CONSTRAINTS _HRESULT_TYPEDEF_(0x80096019L) +#define TRUST_E_FINANCIAL_CRITERIA _HRESULT_TYPEDEF_(0x8009601EL) +#define MSSIPOTF_E_OUTOFMEMRANGE _HRESULT_TYPEDEF_(0x80097001L) +#define MSSIPOTF_E_CANTGETOBJECT _HRESULT_TYPEDEF_(0x80097002L) +#define MSSIPOTF_E_NOHEADTABLE _HRESULT_TYPEDEF_(0x80097003L) +#define MSSIPOTF_E_BAD_MAGICNUMBER _HRESULT_TYPEDEF_(0x80097004L) +#define MSSIPOTF_E_BAD_OFFSET_TABLE _HRESULT_TYPEDEF_(0x80097005L) +#define MSSIPOTF_E_TABLE_TAGORDER _HRESULT_TYPEDEF_(0x80097006L) +#define MSSIPOTF_E_TABLE_LONGWORD _HRESULT_TYPEDEF_(0x80097007L) +#define MSSIPOTF_E_BAD_FIRST_TABLE_PLACEMENT _HRESULT_TYPEDEF_(0x80097008L) +#define MSSIPOTF_E_TABLES_OVERLAP _HRESULT_TYPEDEF_(0x80097009L) +#define MSSIPOTF_E_TABLE_PADBYTES _HRESULT_TYPEDEF_(0x8009700AL) +#define MSSIPOTF_E_FILETOOSMALL _HRESULT_TYPEDEF_(0x8009700BL) +#define MSSIPOTF_E_TABLE_CHECKSUM _HRESULT_TYPEDEF_(0x8009700CL) +#define MSSIPOTF_E_FILE_CHECKSUM _HRESULT_TYPEDEF_(0x8009700DL) +#define MSSIPOTF_E_FAILED_POLICY _HRESULT_TYPEDEF_(0x80097010L) +#define MSSIPOTF_E_FAILED_HINTS_CHECK _HRESULT_TYPEDEF_(0x80097011L) +#define MSSIPOTF_E_NOT_OPENTYPE _HRESULT_TYPEDEF_(0x80097012L) +#define MSSIPOTF_E_FILE _HRESULT_TYPEDEF_(0x80097013L) +#define MSSIPOTF_E_CRYPT _HRESULT_TYPEDEF_(0x80097014L) +#define MSSIPOTF_E_BADVERSION _HRESULT_TYPEDEF_(0x80097015L) +#define MSSIPOTF_E_DSIG_STRUCTURE _HRESULT_TYPEDEF_(0x80097016L) +#define MSSIPOTF_E_PCONST_CHECK _HRESULT_TYPEDEF_(0x80097017L) +#define MSSIPOTF_E_STRUCTURE _HRESULT_TYPEDEF_(0x80097018L) +#define NTE_OP_OK 0 +#define TRUST_E_PROVIDER_UNKNOWN _HRESULT_TYPEDEF_(0x800B0001L) +#define TRUST_E_ACTION_UNKNOWN _HRESULT_TYPEDEF_(0x800B0002L) +#define TRUST_E_SUBJECT_FORM_UNKNOWN _HRESULT_TYPEDEF_(0x800B0003L) +#define TRUST_E_SUBJECT_NOT_TRUSTED _HRESULT_TYPEDEF_(0x800B0004L) +#define DIGSIG_E_ENCODE _HRESULT_TYPEDEF_(0x800B0005L) +#define DIGSIG_E_DECODE _HRESULT_TYPEDEF_(0x800B0006L) +#define DIGSIG_E_EXTENSIBILITY _HRESULT_TYPEDEF_(0x800B0007L) +#define DIGSIG_E_CRYPTO _HRESULT_TYPEDEF_(0x800B0008L) +#define PERSIST_E_SIZEDEFINITE _HRESULT_TYPEDEF_(0x800B0009L) +#define PERSIST_E_SIZEINDEFINITE _HRESULT_TYPEDEF_(0x800B000AL) +#define PERSIST_E_NOTSELFSIZING _HRESULT_TYPEDEF_(0x800B000BL) +#define TRUST_E_NOSIGNATURE _HRESULT_TYPEDEF_(0x800B0100L) +#define CERT_E_EXPIRED _HRESULT_TYPEDEF_(0x800B0101L) +#define CERT_E_VALIDITYPERIODNESTING _HRESULT_TYPEDEF_(0x800B0102L) +#define CERT_E_ROLE _HRESULT_TYPEDEF_(0x800B0103L) +#define CERT_E_PATHLENCONST _HRESULT_TYPEDEF_(0x800B0104L) +#define CERT_E_CRITICAL _HRESULT_TYPEDEF_(0x800B0105L) +#define CERT_E_PURPOSE _HRESULT_TYPEDEF_(0x800B0106L) +#define CERT_E_ISSUERCHAINING _HRESULT_TYPEDEF_(0x800B0107L) +#define CERT_E_MALFORMED _HRESULT_TYPEDEF_(0x800B0108L) +#define CERT_E_UNTRUSTEDROOT _HRESULT_TYPEDEF_(0x800B0109L) +#define CERT_E_CHAINING _HRESULT_TYPEDEF_(0x800B010AL) +#define TRUST_E_FAIL _HRESULT_TYPEDEF_(0x800B010BL) +#define CERT_E_REVOKED _HRESULT_TYPEDEF_(0x800B010CL) +#define CERT_E_UNTRUSTEDTESTROOT _HRESULT_TYPEDEF_(0x800B010DL) +#define CERT_E_REVOCATION_FAILURE _HRESULT_TYPEDEF_(0x800B010EL) +#define CERT_E_CN_NO_MATCH _HRESULT_TYPEDEF_(0x800B010FL) +#define CERT_E_WRONG_USAGE _HRESULT_TYPEDEF_(0x800B0110L) +#define TRUST_E_EXPLICIT_DISTRUST _HRESULT_TYPEDEF_(0x800B0111L) +#define CERT_E_UNTRUSTEDCA _HRESULT_TYPEDEF_(0x800B0112L) +#define CERT_E_INVALID_POLICY _HRESULT_TYPEDEF_(0x800B0113L) +#define CERT_E_INVALID_NAME _HRESULT_TYPEDEF_(0x800B0114L) +#define HRESULT_FROM_SETUPAPI(x) ((((x) & (APPLICATION_ERROR_MASK|ERROR_SEVERITY_ERROR))==(APPLICATION_ERROR_MASK|ERROR_SEVERITY_ERROR)) ? ((HRESULT) (((x) & 0x0000FFFF) | (FACILITY_SETUPAPI << 16) | 0x80000000)) : HRESULT_FROM_WIN32(x)) +#define SPAPI_E_EXPECTED_SECTION_NAME _HRESULT_TYPEDEF_(0x800F0000L) +#define SPAPI_E_BAD_SECTION_NAME_LINE _HRESULT_TYPEDEF_(0x800F0001L) +#define SPAPI_E_SECTION_NAME_TOO_LONG _HRESULT_TYPEDEF_(0x800F0002L) +#define SPAPI_E_GENERAL_SYNTAX _HRESULT_TYPEDEF_(0x800F0003L) +#define SPAPI_E_WRONG_INF_STYLE _HRESULT_TYPEDEF_(0x800F0100L) +#define SPAPI_E_SECTION_NOT_FOUND _HRESULT_TYPEDEF_(0x800F0101L) +#define SPAPI_E_LINE_NOT_FOUND _HRESULT_TYPEDEF_(0x800F0102L) +#define SPAPI_E_NO_BACKUP _HRESULT_TYPEDEF_(0x800F0103L) +#define SPAPI_E_NO_ASSOCIATED_CLASS _HRESULT_TYPEDEF_(0x800F0200L) +#define SPAPI_E_CLASS_MISMATCH _HRESULT_TYPEDEF_(0x800F0201L) +#define SPAPI_E_DUPLICATE_FOUND _HRESULT_TYPEDEF_(0x800F0202L) +#define SPAPI_E_NO_DRIVER_SELECTED _HRESULT_TYPEDEF_(0x800F0203L) +#define SPAPI_E_KEY_DOES_NOT_EXIST _HRESULT_TYPEDEF_(0x800F0204L) +#define SPAPI_E_INVALID_DEVINST_NAME _HRESULT_TYPEDEF_(0x800F0205L) +#define SPAPI_E_INVALID_CLASS _HRESULT_TYPEDEF_(0x800F0206L) +#define SPAPI_E_DEVINST_ALREADY_EXISTS _HRESULT_TYPEDEF_(0x800F0207L) +#define SPAPI_E_DEVINFO_NOT_REGISTERED _HRESULT_TYPEDEF_(0x800F0208L) +#define SPAPI_E_INVALID_REG_PROPERTY _HRESULT_TYPEDEF_(0x800F0209L) +#define SPAPI_E_NO_INF _HRESULT_TYPEDEF_(0x800F020AL) +#define SPAPI_E_NO_SUCH_DEVINST _HRESULT_TYPEDEF_(0x800F020BL) +#define SPAPI_E_CANT_LOAD_CLASS_ICON _HRESULT_TYPEDEF_(0x800F020CL) +#define SPAPI_E_INVALID_CLASS_INSTALLER _HRESULT_TYPEDEF_(0x800F020DL) +#define SPAPI_E_DI_DO_DEFAULT _HRESULT_TYPEDEF_(0x800F020EL) +#define SPAPI_E_DI_NOFILECOPY _HRESULT_TYPEDEF_(0x800F020FL) +#define SPAPI_E_INVALID_HWPROFILE _HRESULT_TYPEDEF_(0x800F0210L) +#define SPAPI_E_NO_DEVICE_SELECTED _HRESULT_TYPEDEF_(0x800F0211L) +#define SPAPI_E_DEVINFO_LIST_LOCKED _HRESULT_TYPEDEF_(0x800F0212L) +#define SPAPI_E_DEVINFO_DATA_LOCKED _HRESULT_TYPEDEF_(0x800F0213L) +#define SPAPI_E_DI_BAD_PATH _HRESULT_TYPEDEF_(0x800F0214L) +#define SPAPI_E_NO_CLASSINSTALL_PARAMS _HRESULT_TYPEDEF_(0x800F0215L) +#define SPAPI_E_FILEQUEUE_LOCKED _HRESULT_TYPEDEF_(0x800F0216L) +#define SPAPI_E_BAD_SERVICE_INSTALLSECT _HRESULT_TYPEDEF_(0x800F0217L) +#define SPAPI_E_NO_CLASS_DRIVER_LIST _HRESULT_TYPEDEF_(0x800F0218L) +#define SPAPI_E_NO_ASSOCIATED_SERVICE _HRESULT_TYPEDEF_(0x800F0219L) +#define SPAPI_E_NO_DEFAULT_DEVICE_INTERFACE _HRESULT_TYPEDEF_(0x800F021AL) +#define SPAPI_E_DEVICE_INTERFACE_ACTIVE _HRESULT_TYPEDEF_(0x800F021BL) +#define SPAPI_E_DEVICE_INTERFACE_REMOVED _HRESULT_TYPEDEF_(0x800F021CL) +#define SPAPI_E_BAD_INTERFACE_INSTALLSECT _HRESULT_TYPEDEF_(0x800F021DL) +#define SPAPI_E_NO_SUCH_INTERFACE_CLASS _HRESULT_TYPEDEF_(0x800F021EL) +#define SPAPI_E_INVALID_REFERENCE_STRING _HRESULT_TYPEDEF_(0x800F021FL) +#define SPAPI_E_INVALID_MACHINENAME _HRESULT_TYPEDEF_(0x800F0220L) +#define SPAPI_E_REMOTE_COMM_FAILURE _HRESULT_TYPEDEF_(0x800F0221L) +#define SPAPI_E_MACHINE_UNAVAILABLE _HRESULT_TYPEDEF_(0x800F0222L) +#define SPAPI_E_NO_CONFIGMGR_SERVICES _HRESULT_TYPEDEF_(0x800F0223L) +#define SPAPI_E_INVALID_PROPPAGE_PROVIDER _HRESULT_TYPEDEF_(0x800F0224L) +#define SPAPI_E_NO_SUCH_DEVICE_INTERFACE _HRESULT_TYPEDEF_(0x800F0225L) +#define SPAPI_E_DI_POSTPROCESSING_REQUIRED _HRESULT_TYPEDEF_(0x800F0226L) +#define SPAPI_E_INVALID_COINSTALLER _HRESULT_TYPEDEF_(0x800F0227L) +#define SPAPI_E_NO_COMPAT_DRIVERS _HRESULT_TYPEDEF_(0x800F0228L) +#define SPAPI_E_NO_DEVICE_ICON _HRESULT_TYPEDEF_(0x800F0229L) +#define SPAPI_E_INVALID_INF_LOGCONFIG _HRESULT_TYPEDEF_(0x800F022AL) +#define SPAPI_E_DI_DONT_INSTALL _HRESULT_TYPEDEF_(0x800F022BL) +#define SPAPI_E_INVALID_FILTER_DRIVER _HRESULT_TYPEDEF_(0x800F022CL) +#define SPAPI_E_NON_WINDOWS_NT_DRIVER _HRESULT_TYPEDEF_(0x800F022DL) +#define SPAPI_E_NON_WINDOWS_DRIVER _HRESULT_TYPEDEF_(0x800F022EL) +#define SPAPI_E_NO_CATALOG_FOR_OEM_INF _HRESULT_TYPEDEF_(0x800F022FL) +#define SPAPI_E_DEVINSTALL_QUEUE_NONNATIVE _HRESULT_TYPEDEF_(0x800F0230L) +#define SPAPI_E_NOT_DISABLEABLE _HRESULT_TYPEDEF_(0x800F0231L) +#define SPAPI_E_CANT_REMOVE_DEVINST _HRESULT_TYPEDEF_(0x800F0232L) +#define SPAPI_E_INVALID_TARGET _HRESULT_TYPEDEF_(0x800F0233L) +#define SPAPI_E_DRIVER_NONNATIVE _HRESULT_TYPEDEF_(0x800F0234L) +#define SPAPI_E_IN_WOW64 _HRESULT_TYPEDEF_(0x800F0235L) +#define SPAPI_E_SET_SYSTEM_RESTORE_POINT _HRESULT_TYPEDEF_(0x800F0236L) +#define SPAPI_E_INCORRECTLY_COPIED_INF _HRESULT_TYPEDEF_(0x800F0237L) +#define SPAPI_E_SCE_DISABLED _HRESULT_TYPEDEF_(0x800F0238L) +#define SPAPI_E_UNKNOWN_EXCEPTION _HRESULT_TYPEDEF_(0x800F0239L) +#define SPAPI_E_PNP_REGISTRY_ERROR _HRESULT_TYPEDEF_(0x800F023AL) +#define SPAPI_E_REMOTE_REQUEST_UNSUPPORTED _HRESULT_TYPEDEF_(0x800F023BL) +#define SPAPI_E_NOT_AN_INSTALLED_OEM_INF _HRESULT_TYPEDEF_(0x800F023CL) +#define SPAPI_E_INF_IN_USE_BY_DEVICES _HRESULT_TYPEDEF_(0x800F023DL) +#define SPAPI_E_DI_FUNCTION_OBSOLETE _HRESULT_TYPEDEF_(0x800F023EL) +#define SPAPI_E_NO_AUTHENTICODE_CATALOG _HRESULT_TYPEDEF_(0x800F023FL) +#define SPAPI_E_AUTHENTICODE_DISALLOWED _HRESULT_TYPEDEF_(0x800F0240L) +#define SPAPI_E_AUTHENTICODE_TRUSTED_PUBLISHER _HRESULT_TYPEDEF_(0x800F0241L) +#define SPAPI_E_AUTHENTICODE_TRUST_NOT_ESTABLISHED _HRESULT_TYPEDEF_(0x800F0242L) +#define SPAPI_E_AUTHENTICODE_PUBLISHER_NOT_TRUSTED _HRESULT_TYPEDEF_(0x800F0243L) +#define SPAPI_E_SIGNATURE_OSATTRIBUTE_MISMATCH _HRESULT_TYPEDEF_(0x800F0244L) +#define SPAPI_E_ONLY_VALIDATE_VIA_AUTHENTICODE _HRESULT_TYPEDEF_(0x800F0245L) +#define SPAPI_E_UNRECOVERABLE_STACK_OVERFLOW _HRESULT_TYPEDEF_(0x800F0300L) +#define SPAPI_E_ERROR_NOT_INSTALLED _HRESULT_TYPEDEF_(0x800F1000L) +#define SCARD_S_SUCCESS NO_ERROR +#define SCARD_F_INTERNAL_ERROR _HRESULT_TYPEDEF_(0x80100001L) +#define SCARD_E_CANCELLED _HRESULT_TYPEDEF_(0x80100002L) +#define SCARD_E_INVALID_HANDLE _HRESULT_TYPEDEF_(0x80100003L) +#define SCARD_E_INVALID_PARAMETER _HRESULT_TYPEDEF_(0x80100004L) +#define SCARD_E_INVALID_TARGET _HRESULT_TYPEDEF_(0x80100005L) +#define SCARD_E_NO_MEMORY _HRESULT_TYPEDEF_(0x80100006L) +#define SCARD_F_WAITED_TOO_LONG _HRESULT_TYPEDEF_(0x80100007L) +#define SCARD_E_INSUFFICIENT_BUFFER _HRESULT_TYPEDEF_(0x80100008L) +#define SCARD_E_UNKNOWN_READER _HRESULT_TYPEDEF_(0x80100009L) +#define SCARD_E_TIMEOUT _HRESULT_TYPEDEF_(0x8010000AL) +#define SCARD_E_SHARING_VIOLATION _HRESULT_TYPEDEF_(0x8010000BL) +#define SCARD_E_NO_SMARTCARD _HRESULT_TYPEDEF_(0x8010000CL) +#define SCARD_E_UNKNOWN_CARD _HRESULT_TYPEDEF_(0x8010000DL) +#define SCARD_E_CANT_DISPOSE _HRESULT_TYPEDEF_(0x8010000EL) +#define SCARD_E_PROTO_MISMATCH _HRESULT_TYPEDEF_(0x8010000FL) +#define SCARD_E_NOT_READY _HRESULT_TYPEDEF_(0x80100010L) +#define SCARD_E_INVALID_VALUE _HRESULT_TYPEDEF_(0x80100011L) +#define SCARD_E_SYSTEM_CANCELLED _HRESULT_TYPEDEF_(0x80100012L) +#define SCARD_F_COMM_ERROR _HRESULT_TYPEDEF_(0x80100013L) +#define SCARD_F_UNKNOWN_ERROR _HRESULT_TYPEDEF_(0x80100014L) +#define SCARD_E_INVALID_ATR _HRESULT_TYPEDEF_(0x80100015L) +#define SCARD_E_NOT_TRANSACTED _HRESULT_TYPEDEF_(0x80100016L) +#define SCARD_E_READER_UNAVAILABLE _HRESULT_TYPEDEF_(0x80100017L) +#define SCARD_P_SHUTDOWN _HRESULT_TYPEDEF_(0x80100018L) +#define SCARD_E_PCI_TOO_SMALL _HRESULT_TYPEDEF_(0x80100019L) +#define SCARD_E_READER_UNSUPPORTED _HRESULT_TYPEDEF_(0x8010001AL) +#define SCARD_E_DUPLICATE_READER _HRESULT_TYPEDEF_(0x8010001BL) +#define SCARD_E_CARD_UNSUPPORTED _HRESULT_TYPEDEF_(0x8010001CL) +#define SCARD_E_NO_SERVICE _HRESULT_TYPEDEF_(0x8010001DL) +#define SCARD_E_SERVICE_STOPPED _HRESULT_TYPEDEF_(0x8010001EL) +#define SCARD_E_UNEXPECTED _HRESULT_TYPEDEF_(0x8010001FL) +#define SCARD_E_ICC_INSTALLATION _HRESULT_TYPEDEF_(0x80100020L) +#define SCARD_E_ICC_CREATEORDER _HRESULT_TYPEDEF_(0x80100021L) +#define SCARD_E_UNSUPPORTED_FEATURE _HRESULT_TYPEDEF_(0x80100022L) +#define SCARD_E_DIR_NOT_FOUND _HRESULT_TYPEDEF_(0x80100023L) +#define SCARD_E_FILE_NOT_FOUND _HRESULT_TYPEDEF_(0x80100024L) +#define SCARD_E_NO_DIR _HRESULT_TYPEDEF_(0x80100025L) +#define SCARD_E_NO_FILE _HRESULT_TYPEDEF_(0x80100026L) +#define SCARD_E_NO_ACCESS _HRESULT_TYPEDEF_(0x80100027L) +#define SCARD_E_WRITE_TOO_MANY _HRESULT_TYPEDEF_(0x80100028L) +#define SCARD_E_BAD_SEEK _HRESULT_TYPEDEF_(0x80100029L) +#define SCARD_E_INVALID_CHV _HRESULT_TYPEDEF_(0x8010002AL) +#define SCARD_E_UNKNOWN_RES_MNG _HRESULT_TYPEDEF_(0x8010002BL) +#define SCARD_E_NO_SUCH_CERTIFICATE _HRESULT_TYPEDEF_(0x8010002CL) +#define SCARD_E_CERTIFICATE_UNAVAILABLE _HRESULT_TYPEDEF_(0x8010002DL) +#define SCARD_E_NO_READERS_AVAILABLE _HRESULT_TYPEDEF_(0x8010002EL) +#define SCARD_E_COMM_DATA_LOST _HRESULT_TYPEDEF_(0x8010002FL) +#define SCARD_E_NO_KEY_CONTAINER _HRESULT_TYPEDEF_(0x80100030L) +#define SCARD_E_SERVER_TOO_BUSY _HRESULT_TYPEDEF_(0x80100031L) +#define SCARD_W_UNSUPPORTED_CARD _HRESULT_TYPEDEF_(0x80100065L) +#define SCARD_W_UNRESPONSIVE_CARD _HRESULT_TYPEDEF_(0x80100066L) +#define SCARD_W_UNPOWERED_CARD _HRESULT_TYPEDEF_(0x80100067L) +#define SCARD_W_RESET_CARD _HRESULT_TYPEDEF_(0x80100068L) +#define SCARD_W_REMOVED_CARD _HRESULT_TYPEDEF_(0x80100069L) +#define SCARD_W_SECURITY_VIOLATION _HRESULT_TYPEDEF_(0x8010006AL) +#define SCARD_W_WRONG_CHV _HRESULT_TYPEDEF_(0x8010006BL) +#define SCARD_W_CHV_BLOCKED _HRESULT_TYPEDEF_(0x8010006CL) +#define SCARD_W_EOF _HRESULT_TYPEDEF_(0x8010006DL) +#define SCARD_W_CANCELLED_BY_USER _HRESULT_TYPEDEF_(0x8010006EL) +#define SCARD_W_CARD_NOT_AUTHENTICATED _HRESULT_TYPEDEF_(0x8010006FL) +#define COMADMIN_E_OBJECTERRORS _HRESULT_TYPEDEF_(0x80110401L) +#define COMADMIN_E_OBJECTINVALID _HRESULT_TYPEDEF_(0x80110402L) +#define COMADMIN_E_KEYMISSING _HRESULT_TYPEDEF_(0x80110403L) +#define COMADMIN_E_ALREADYINSTALLED _HRESULT_TYPEDEF_(0x80110404L) +#define COMADMIN_E_APP_FILE_WRITEFAIL _HRESULT_TYPEDEF_(0x80110407L) +#define COMADMIN_E_APP_FILE_READFAIL _HRESULT_TYPEDEF_(0x80110408L) +#define COMADMIN_E_APP_FILE_VERSION _HRESULT_TYPEDEF_(0x80110409L) +#define COMADMIN_E_BADPATH _HRESULT_TYPEDEF_(0x8011040AL) +#define COMADMIN_E_APPLICATIONEXISTS _HRESULT_TYPEDEF_(0x8011040BL) +#define COMADMIN_E_ROLEEXISTS _HRESULT_TYPEDEF_(0x8011040CL) +#define COMADMIN_E_CANTCOPYFILE _HRESULT_TYPEDEF_(0x8011040DL) +#define COMADMIN_E_NOUSER _HRESULT_TYPEDEF_(0x8011040FL) +#define COMADMIN_E_INVALIDUSERIDS _HRESULT_TYPEDEF_(0x80110410L) +#define COMADMIN_E_NOREGISTRYCLSID _HRESULT_TYPEDEF_(0x80110411L) +#define COMADMIN_E_BADREGISTRYPROGID _HRESULT_TYPEDEF_(0x80110412L) +#define COMADMIN_E_AUTHENTICATIONLEVEL _HRESULT_TYPEDEF_(0x80110413L) +#define COMADMIN_E_USERPASSWDNOTVALID _HRESULT_TYPEDEF_(0x80110414L) +#define COMADMIN_E_CLSIDORIIDMISMATCH _HRESULT_TYPEDEF_(0x80110418L) +#define COMADMIN_E_REMOTEINTERFACE _HRESULT_TYPEDEF_(0x80110419L) +#define COMADMIN_E_DLLREGISTERSERVER _HRESULT_TYPEDEF_(0x8011041AL) +#define COMADMIN_E_NOSERVERSHARE _HRESULT_TYPEDEF_(0x8011041BL) +#define COMADMIN_E_DLLLOADFAILED _HRESULT_TYPEDEF_(0x8011041DL) +#define COMADMIN_E_BADREGISTRYLIBID _HRESULT_TYPEDEF_(0x8011041EL) +#define COMADMIN_E_APPDIRNOTFOUND _HRESULT_TYPEDEF_(0x8011041FL) +#define COMADMIN_E_REGISTRARFAILED _HRESULT_TYPEDEF_(0x80110423L) +#define COMADMIN_E_COMPFILE_DOESNOTEXIST _HRESULT_TYPEDEF_(0x80110424L) +#define COMADMIN_E_COMPFILE_LOADDLLFAIL _HRESULT_TYPEDEF_(0x80110425L) +#define COMADMIN_E_COMPFILE_GETCLASSOBJ _HRESULT_TYPEDEF_(0x80110426L) +#define COMADMIN_E_COMPFILE_CLASSNOTAVAIL _HRESULT_TYPEDEF_(0x80110427L) +#define COMADMIN_E_COMPFILE_BADTLB _HRESULT_TYPEDEF_(0x80110428L) +#define COMADMIN_E_COMPFILE_NOTINSTALLABLE _HRESULT_TYPEDEF_(0x80110429L) +#define COMADMIN_E_NOTCHANGEABLE _HRESULT_TYPEDEF_(0x8011042AL) +#define COMADMIN_E_NOTDELETEABLE _HRESULT_TYPEDEF_(0x8011042BL) +#define COMADMIN_E_SESSION _HRESULT_TYPEDEF_(0x8011042CL) +#define COMADMIN_E_COMP_MOVE_LOCKED _HRESULT_TYPEDEF_(0x8011042DL) +#define COMADMIN_E_COMP_MOVE_BAD_DEST _HRESULT_TYPEDEF_(0x8011042EL) +#define COMADMIN_E_REGISTERTLB _HRESULT_TYPEDEF_(0x80110430L) +#define COMADMIN_E_SYSTEMAPP _HRESULT_TYPEDEF_(0x80110433L) +#define COMADMIN_E_COMPFILE_NOREGISTRAR _HRESULT_TYPEDEF_(0x80110434L) +#define COMADMIN_E_COREQCOMPINSTALLED _HRESULT_TYPEDEF_(0x80110435L) +#define COMADMIN_E_SERVICENOTINSTALLED _HRESULT_TYPEDEF_(0x80110436L) +#define COMADMIN_E_PROPERTYSAVEFAILED _HRESULT_TYPEDEF_(0x80110437L) +#define COMADMIN_E_OBJECTEXISTS _HRESULT_TYPEDEF_(0x80110438L) +#define COMADMIN_E_COMPONENTEXISTS _HRESULT_TYPEDEF_(0x80110439L) +#define COMADMIN_E_REGFILE_CORRUPT _HRESULT_TYPEDEF_(0x8011043BL) +#define COMADMIN_E_PROPERTY_OVERFLOW _HRESULT_TYPEDEF_(0x8011043CL) +#define COMADMIN_E_NOTINREGISTRY _HRESULT_TYPEDEF_(0x8011043EL) +#define COMADMIN_E_OBJECTNOTPOOLABLE _HRESULT_TYPEDEF_(0x8011043FL) +#define COMADMIN_E_APPLID_MATCHES_CLSID _HRESULT_TYPEDEF_(0x80110446L) +#define COMADMIN_E_ROLE_DOES_NOT_EXIST _HRESULT_TYPEDEF_(0x80110447L) +#define COMADMIN_E_START_APP_NEEDS_COMPONENTS _HRESULT_TYPEDEF_(0x80110448L) +#define COMADMIN_E_REQUIRES_DIFFERENT_PLATFORM _HRESULT_TYPEDEF_(0x80110449L) +#define COMADMIN_E_CAN_NOT_EXPORT_APP_PROXY _HRESULT_TYPEDEF_(0x8011044AL) +#define COMADMIN_E_CAN_NOT_START_APP _HRESULT_TYPEDEF_(0x8011044BL) +#define COMADMIN_E_CAN_NOT_EXPORT_SYS_APP _HRESULT_TYPEDEF_(0x8011044CL) +#define COMADMIN_E_CANT_SUBSCRIBE_TO_COMPONENT _HRESULT_TYPEDEF_(0x8011044DL) +#define COMADMIN_E_EVENTCLASS_CANT_BE_SUBSCRIBER _HRESULT_TYPEDEF_(0x8011044EL) +#define COMADMIN_E_LIB_APP_PROXY_INCOMPATIBLE _HRESULT_TYPEDEF_(0x8011044FL) +#define COMADMIN_E_BASE_PARTITION_ONLY _HRESULT_TYPEDEF_(0x80110450L) +#define COMADMIN_E_START_APP_DISABLED _HRESULT_TYPEDEF_(0x80110451L) +#define COMADMIN_E_CAT_DUPLICATE_PARTITION_NAME _HRESULT_TYPEDEF_(0x80110457L) +#define COMADMIN_E_CAT_INVALID_PARTITION_NAME _HRESULT_TYPEDEF_(0x80110458L) +#define COMADMIN_E_CAT_PARTITION_IN_USE _HRESULT_TYPEDEF_(0x80110459L) +#define COMADMIN_E_FILE_PARTITION_DUPLICATE_FILES _HRESULT_TYPEDEF_(0x8011045AL) +#define COMADMIN_E_CAT_IMPORTED_COMPONENTS_NOT_ALLOWED _HRESULT_TYPEDEF_(0x8011045BL) +#define COMADMIN_E_AMBIGUOUS_APPLICATION_NAME _HRESULT_TYPEDEF_(0x8011045CL) +#define COMADMIN_E_AMBIGUOUS_PARTITION_NAME _HRESULT_TYPEDEF_(0x8011045DL) +#define COMADMIN_E_REGDB_NOTINITIALIZED _HRESULT_TYPEDEF_(0x80110472L) +#define COMADMIN_E_REGDB_NOTOPEN _HRESULT_TYPEDEF_(0x80110473L) +#define COMADMIN_E_REGDB_SYSTEMERR _HRESULT_TYPEDEF_(0x80110474L) +#define COMADMIN_E_REGDB_ALREADYRUNNING _HRESULT_TYPEDEF_(0x80110475L) +#define COMADMIN_E_MIG_VERSIONNOTSUPPORTED _HRESULT_TYPEDEF_(0x80110480L) +#define COMADMIN_E_MIG_SCHEMANOTFOUND _HRESULT_TYPEDEF_(0x80110481L) +#define COMADMIN_E_CAT_BITNESSMISMATCH _HRESULT_TYPEDEF_(0x80110482L) +#define COMADMIN_E_CAT_UNACCEPTABLEBITNESS _HRESULT_TYPEDEF_(0x80110483L) +#define COMADMIN_E_CAT_WRONGAPPBITNESS _HRESULT_TYPEDEF_(0x80110484L) +#define COMADMIN_E_CAT_PAUSE_RESUME_NOT_SUPPORTED _HRESULT_TYPEDEF_(0x80110485L) +#define COMADMIN_E_CAT_SERVERFAULT _HRESULT_TYPEDEF_(0x80110486L) +#define COMQC_E_APPLICATION_NOT_QUEUED _HRESULT_TYPEDEF_(0x80110600L) +#define COMQC_E_NO_QUEUEABLE_INTERFACES _HRESULT_TYPEDEF_(0x80110601L) +#define COMQC_E_QUEUING_SERVICE_NOT_AVAILABLE _HRESULT_TYPEDEF_(0x80110602L) +#define COMQC_E_NO_IPERSISTSTREAM _HRESULT_TYPEDEF_(0x80110603L) +#define COMQC_E_BAD_MESSAGE _HRESULT_TYPEDEF_(0x80110604L) +#define COMQC_E_UNAUTHENTICATED _HRESULT_TYPEDEF_(0x80110605L) +#define COMQC_E_UNTRUSTED_ENQUEUER _HRESULT_TYPEDEF_(0x80110606L) +#define MSDTC_E_DUPLICATE_RESOURCE _HRESULT_TYPEDEF_(0x80110701L) +#define COMADMIN_E_OBJECT_PARENT_MISSING _HRESULT_TYPEDEF_(0x80110808L) +#define COMADMIN_E_OBJECT_DOES_NOT_EXIST _HRESULT_TYPEDEF_(0x80110809L) +#define COMADMIN_E_APP_NOT_RUNNING _HRESULT_TYPEDEF_(0x8011080AL) +#define COMADMIN_E_INVALID_PARTITION _HRESULT_TYPEDEF_(0x8011080BL) +#define COMADMIN_E_SVCAPP_NOT_POOLABLE_OR_RECYCLABLE _HRESULT_TYPEDEF_(0x8011080DL) +#define COMADMIN_E_USER_IN_SET _HRESULT_TYPEDEF_(0x8011080EL) +#define COMADMIN_E_CANTRECYCLELIBRARYAPPS _HRESULT_TYPEDEF_(0x8011080FL) +#define COMADMIN_E_CANTRECYCLESERVICEAPPS _HRESULT_TYPEDEF_(0x80110811L) +#define COMADMIN_E_PROCESSALREADYRECYCLED _HRESULT_TYPEDEF_(0x80110812L) +#define COMADMIN_E_PAUSEDPROCESSMAYNOTBERECYCLED _HRESULT_TYPEDEF_(0x80110813L) +#define COMADMIN_E_CANTMAKEINPROCSERVICE _HRESULT_TYPEDEF_(0x80110814L) +#define COMADMIN_E_PROGIDINUSEBYCLSID _HRESULT_TYPEDEF_(0x80110815L) +#define COMADMIN_E_DEFAULT_PARTITION_NOT_IN_SET _HRESULT_TYPEDEF_(0x80110816L) +#define COMADMIN_E_RECYCLEDPROCESSMAYNOTBEPAUSED _HRESULT_TYPEDEF_(0x80110817L) +#define COMADMIN_E_PARTITION_ACCESSDENIED _HRESULT_TYPEDEF_(0x80110818L) +#define COMADMIN_E_PARTITION_MSI_ONLY _HRESULT_TYPEDEF_(0x80110819L) +#define COMADMIN_E_LEGACYCOMPS_NOT_ALLOWED_IN_1_0_FORMAT _HRESULT_TYPEDEF_(0x8011081AL) +#define COMADMIN_E_LEGACYCOMPS_NOT_ALLOWED_IN_NONBASE_PARTITIONS _HRESULT_TYPEDEF_(0x8011081BL) +#define COMADMIN_E_COMP_MOVE_SOURCE _HRESULT_TYPEDEF_(0x8011081CL) +#define COMADMIN_E_COMP_MOVE_DEST _HRESULT_TYPEDEF_(0x8011081DL) +#define COMADMIN_E_COMP_MOVE_PRIVATE _HRESULT_TYPEDEF_(0x8011081EL) +#define COMADMIN_E_BASEPARTITION_REQUIRED_IN_SET _HRESULT_TYPEDEF_(0x8011081FL) +#define COMADMIN_E_CANNOT_ALIAS_EVENTCLASS _HRESULT_TYPEDEF_(0x80110820L) +#define COMADMIN_E_PRIVATE_ACCESSDENIED _HRESULT_TYPEDEF_(0x80110821L) +#define COMADMIN_E_SAFERINVALID _HRESULT_TYPEDEF_(0x80110822L) +#define COMADMIN_E_REGISTRY_ACCESSDENIED _HRESULT_TYPEDEF_(0x80110823L) +#define COMADMIN_E_PARTITIONS_DISABLED _HRESULT_TYPEDEF_(0x80110824L) +#endif /* _WINERROR_ */ diff --git a/tinyc/win32/include/winapi/wingdi.h b/tinyc/win32/include/winapi/wingdi.h new file mode 100644 index 000000000..63d389178 --- /dev/null +++ b/tinyc/win32/include/winapi/wingdi.h @@ -0,0 +1,4080 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _WINGDI_ +#define _WINGDI_ + +#define WINGDIAPI DECLSPEC_IMPORT +#define WINSPOOLAPI DECLSPEC_IMPORT + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef WINVER +#define WINVER 0x0502 +#endif + +#ifndef NOGDI +#ifndef NORASTEROPS +#define R2_BLACK 1 +#define R2_NOTMERGEPEN 2 +#define R2_MASKNOTPEN 3 +#define R2_NOTCOPYPEN 4 +#define R2_MASKPENNOT 5 +#define R2_NOT 6 +#define R2_XORPEN 7 +#define R2_NOTMASKPEN 8 +#define R2_MASKPEN 9 +#define R2_NOTXORPEN 10 +#define R2_NOP 11 +#define R2_MERGENOTPEN 12 +#define R2_COPYPEN 13 +#define R2_MERGEPENNOT 14 +#define R2_MERGEPEN 15 +#define R2_WHITE 16 +#define R2_LAST 16 + +#define SRCCOPY (DWORD)0x00CC0020 +#define SRCPAINT (DWORD)0x00EE0086 +#define SRCAND (DWORD)0x008800C6 +#define SRCINVERT (DWORD)0x00660046 +#define SRCERASE (DWORD)0x00440328 +#define NOTSRCCOPY (DWORD)0x00330008 +#define NOTSRCERASE (DWORD)0x001100A6 +#define MERGECOPY (DWORD)0x00C000CA +#define MERGEPAINT (DWORD)0x00BB0226 +#define PATCOPY (DWORD)0x00F00021 +#define PATPAINT (DWORD)0x00FB0A09 +#define PATINVERT (DWORD)0x005A0049 +#define DSTINVERT (DWORD)0x00550009 +#define BLACKNESS (DWORD)0x00000042 +#define WHITENESS (DWORD)0x00FF0062 +#define NOMIRRORBITMAP (DWORD)0x80000000 +#define CAPTUREBLT (DWORD)0x40000000 +#define MAKEROP4(fore,back) (DWORD)((((back) << 8) & 0xFF000000) | (fore)) +#endif + +#define GDI_ERROR (0xFFFFFFFFL) +#define HGDI_ERROR (LongToHandle(0xFFFFFFFFL)) + +#define ERROR 0 +#define NULLREGION 1 +#define SIMPLEREGION 2 +#define COMPLEXREGION 3 +#define RGN_ERROR ERROR + +#define RGN_AND 1 +#define RGN_OR 2 +#define RGN_XOR 3 +#define RGN_DIFF 4 +#define RGN_COPY 5 +#define RGN_MIN RGN_AND +#define RGN_MAX RGN_COPY + +#define BLACKONWHITE 1 +#define WHITEONBLACK 2 +#define COLORONCOLOR 3 +#define HALFTONE 4 +#define MAXSTRETCHBLTMODE 4 + +#define STRETCH_ANDSCANS BLACKONWHITE +#define STRETCH_ORSCANS WHITEONBLACK +#define STRETCH_DELETESCANS COLORONCOLOR +#define STRETCH_HALFTONE HALFTONE + +#define ALTERNATE 1 +#define WINDING 2 +#define POLYFILL_LAST 2 + +#define LAYOUT_RTL 0x00000001 +#define LAYOUT_BTT 0x00000002 +#define LAYOUT_VBH 0x00000004 +#define LAYOUT_ORIENTATIONMASK (LAYOUT_RTL | LAYOUT_BTT | LAYOUT_VBH) +#define LAYOUT_BITMAPORIENTATIONPRESERVED 0x00000008 + +#define TA_NOUPDATECP 0 +#define TA_UPDATECP 1 + +#define TA_LEFT 0 +#define TA_RIGHT 2 +#define TA_CENTER 6 + +#define TA_TOP 0 +#define TA_BOTTOM 8 +#define TA_BASELINE 24 +#define TA_RTLREADING 256 +#define TA_MASK (TA_BASELINE+TA_CENTER+TA_UPDATECP+TA_RTLREADING) + +#define VTA_BASELINE TA_BASELINE +#define VTA_LEFT TA_BOTTOM +#define VTA_RIGHT TA_TOP +#define VTA_CENTER TA_CENTER +#define VTA_BOTTOM TA_RIGHT +#define VTA_TOP TA_LEFT + +#define ETO_OPAQUE 0x0002 +#define ETO_CLIPPED 0x0004 +#define ETO_GLYPH_INDEX 0x0010 +#define ETO_RTLREADING 0x0080 +#define ETO_NUMERICSLOCAL 0x0400 +#define ETO_NUMERICSLATIN 0x0800 +#define ETO_IGNORELANGUAGE 0x1000 +#define ETO_PDY 0x2000 + +#define ASPECT_FILTERING 0x0001 + +#define DCB_RESET 0x0001 +#define DCB_ACCUMULATE 0x0002 +#define DCB_DIRTY DCB_ACCUMULATE +#define DCB_SET (DCB_RESET | DCB_ACCUMULATE) +#define DCB_ENABLE 0x0004 +#define DCB_DISABLE 0x0008 + +#ifndef NOMETAFILE + +#define META_SETBKCOLOR 0x0201 +#define META_SETBKMODE 0x0102 +#define META_SETMAPMODE 0x0103 +#define META_SETROP2 0x0104 +#define META_SETRELABS 0x0105 +#define META_SETPOLYFILLMODE 0x0106 +#define META_SETSTRETCHBLTMODE 0x0107 +#define META_SETTEXTCHAREXTRA 0x0108 +#define META_SETTEXTCOLOR 0x0209 +#define META_SETTEXTJUSTIFICATION 0x020A +#define META_SETWINDOWORG 0x020B +#define META_SETWINDOWEXT 0x020C +#define META_SETVIEWPORTORG 0x020D +#define META_SETVIEWPORTEXT 0x020E +#define META_OFFSETWINDOWORG 0x020F +#define META_SCALEWINDOWEXT 0x0410 +#define META_OFFSETVIEWPORTORG 0x0211 +#define META_SCALEVIEWPORTEXT 0x0412 +#define META_LINETO 0x0213 +#define META_MOVETO 0x0214 +#define META_EXCLUDECLIPRECT 0x0415 +#define META_INTERSECTCLIPRECT 0x0416 +#define META_ARC 0x0817 +#define META_ELLIPSE 0x0418 +#define META_FLOODFILL 0x0419 +#define META_PIE 0x081A +#define META_RECTANGLE 0x041B +#define META_ROUNDRECT 0x061C +#define META_PATBLT 0x061D +#define META_SAVEDC 0x001E +#define META_SETPIXEL 0x041F +#define META_OFFSETCLIPRGN 0x0220 +#define META_TEXTOUT 0x0521 +#define META_BITBLT 0x0922 +#define META_STRETCHBLT 0x0B23 +#define META_POLYGON 0x0324 +#define META_POLYLINE 0x0325 +#define META_ESCAPE 0x0626 +#define META_RESTOREDC 0x0127 +#define META_FILLREGION 0x0228 +#define META_FRAMEREGION 0x0429 +#define META_INVERTREGION 0x012A +#define META_PAINTREGION 0x012B +#define META_SELECTCLIPREGION 0x012C +#define META_SELECTOBJECT 0x012D +#define META_SETTEXTALIGN 0x012E +#define META_CHORD 0x0830 +#define META_SETMAPPERFLAGS 0x0231 +#define META_EXTTEXTOUT 0x0a32 +#define META_SETDIBTODEV 0x0d33 +#define META_SELECTPALETTE 0x0234 +#define META_REALIZEPALETTE 0x0035 +#define META_ANIMATEPALETTE 0x0436 +#define META_SETPALENTRIES 0x0037 +#define META_POLYPOLYGON 0x0538 +#define META_RESIZEPALETTE 0x0139 +#define META_DIBBITBLT 0x0940 +#define META_DIBSTRETCHBLT 0x0b41 +#define META_DIBCREATEPATTERNBRUSH 0x0142 +#define META_STRETCHDIB 0x0f43 +#define META_EXTFLOODFILL 0x0548 +#define META_SETLAYOUT 0x0149 +#define META_DELETEOBJECT 0x01f0 +#define META_CREATEPALETTE 0x00f7 +#define META_CREATEPATTERNBRUSH 0x01F9 +#define META_CREATEPENINDIRECT 0x02FA +#define META_CREATEFONTINDIRECT 0x02FB +#define META_CREATEBRUSHINDIRECT 0x02FC +#define META_CREATEREGION 0x06FF + + typedef struct _DRAWPATRECT { + POINT ptPosition; + POINT ptSize; + WORD wStyle; + WORD wPattern; + } DRAWPATRECT,*PDRAWPATRECT; +#endif + +#define NEWFRAME 1 +#define ABORTDOC 2 +#define NEXTBAND 3 +#define SETCOLORTABLE 4 +#define GETCOLORTABLE 5 +#define FLUSHOUTPUT 6 +#define DRAFTMODE 7 +#define QUERYESCSUPPORT 8 +#define SETABORTPROC 9 +#define STARTDOC 10 +#define ENDDOC 11 +#define GETPHYSPAGESIZE 12 +#define GETPRINTINGOFFSET 13 +#define GETSCALINGFACTOR 14 +#define MFCOMMENT 15 +#define GETPENWIDTH 16 +#define SETCOPYCOUNT 17 +#define SELECTPAPERSOURCE 18 +#define DEVICEDATA 19 +#define PASSTHROUGH 19 +#define GETTECHNOLGY 20 +#define GETTECHNOLOGY 20 +#define SETLINECAP 21 +#define SETLINEJOIN 22 +#define SETMITERLIMIT 23 +#define BANDINFO 24 +#define DRAWPATTERNRECT 25 +#define GETVECTORPENSIZE 26 +#define GETVECTORBRUSHSIZE 27 +#define ENABLEDUPLEX 28 +#define GETSETPAPERBINS 29 +#define GETSETPRINTORIENT 30 +#define ENUMPAPERBINS 31 +#define SETDIBSCALING 32 +#define EPSPRINTING 33 +#define ENUMPAPERMETRICS 34 +#define GETSETPAPERMETRICS 35 +#define POSTSCRIPT_DATA 37 +#define POSTSCRIPT_IGNORE 38 +#define MOUSETRAILS 39 +#define GETDEVICEUNITS 42 + +#define GETEXTENDEDTEXTMETRICS 256 +#define GETEXTENTTABLE 257 +#define GETPAIRKERNTABLE 258 +#define GETTRACKKERNTABLE 259 +#define EXTTEXTOUT 512 +#define GETFACENAME 513 +#define DOWNLOADFACE 514 +#define ENABLERELATIVEWIDTHS 768 +#define ENABLEPAIRKERNING 769 +#define SETKERNTRACK 770 +#define SETALLJUSTVALUES 771 +#define SETCHARSET 772 + +#define STRETCHBLT 2048 +#define METAFILE_DRIVER 2049 +#define GETSETSCREENPARAMS 3072 +#define QUERYDIBSUPPORT 3073 +#define BEGIN_PATH 4096 +#define CLIP_TO_PATH 4097 +#define END_PATH 4098 +#define EXT_DEVICE_CAPS 4099 +#define RESTORE_CTM 4100 +#define SAVE_CTM 4101 +#define SET_ARC_DIRECTION 4102 +#define SET_BACKGROUND_COLOR 4103 +#define SET_POLY_MODE 4104 +#define SET_SCREEN_ANGLE 4105 +#define SET_SPREAD 4106 +#define TRANSFORM_CTM 4107 +#define SET_CLIP_BOX 4108 +#define SET_BOUNDS 4109 +#define SET_MIRROR_MODE 4110 +#define OPENCHANNEL 4110 +#define DOWNLOADHEADER 4111 +#define CLOSECHANNEL 4112 +#define POSTSCRIPT_PASSTHROUGH 4115 +#define ENCAPSULATED_POSTSCRIPT 4116 + +#define POSTSCRIPT_IDENTIFY 4117 +#define POSTSCRIPT_INJECTION 4118 + +#define CHECKJPEGFORMAT 4119 +#define CHECKPNGFORMAT 4120 + +#define GET_PS_FEATURESETTING 4121 + +#define SPCLPASSTHROUGH2 4568 + +#define PSIDENT_GDICENTRIC 0 +#define PSIDENT_PSCENTRIC 1 + + typedef struct _PSINJECTDATA { + DWORD DataBytes; + WORD InjectionPoint; + WORD PageNumber; + } PSINJECTDATA,*PPSINJECTDATA; + +#define PSINJECT_BEGINSTREAM 1 +#define PSINJECT_PSADOBE 2 +#define PSINJECT_PAGESATEND 3 +#define PSINJECT_PAGES 4 + +#define PSINJECT_DOCNEEDEDRES 5 +#define PSINJECT_DOCSUPPLIEDRES 6 +#define PSINJECT_PAGEORDER 7 +#define PSINJECT_ORIENTATION 8 +#define PSINJECT_BOUNDINGBOX 9 +#define PSINJECT_DOCUMENTPROCESSCOLORS 10 + +#define PSINJECT_COMMENTS 11 +#define PSINJECT_BEGINDEFAULTS 12 +#define PSINJECT_ENDDEFAULTS 13 +#define PSINJECT_BEGINPROLOG 14 +#define PSINJECT_ENDPROLOG 15 +#define PSINJECT_BEGINSETUP 16 +#define PSINJECT_ENDSETUP 17 +#define PSINJECT_TRAILER 18 +#define PSINJECT_EOF 19 +#define PSINJECT_ENDSTREAM 20 +#define PSINJECT_DOCUMENTPROCESSCOLORSATEND 21 + +#define PSINJECT_PAGENUMBER 100 +#define PSINJECT_BEGINPAGESETUP 101 +#define PSINJECT_ENDPAGESETUP 102 +#define PSINJECT_PAGETRAILER 103 +#define PSINJECT_PLATECOLOR 104 + +#define PSINJECT_SHOWPAGE 105 +#define PSINJECT_PAGEBBOX 106 +#define PSINJECT_ENDPAGECOMMENTS 107 + +#define PSINJECT_VMSAVE 200 +#define PSINJECT_VMRESTORE 201 + +#define FEATURESETTING_NUP 0 +#define FEATURESETTING_OUTPUT 1 +#define FEATURESETTING_PSLEVEL 2 +#define FEATURESETTING_CUSTPAPER 3 +#define FEATURESETTING_MIRROR 4 +#define FEATURESETTING_NEGATIVE 5 +#define FEATURESETTING_PROTOCOL 6 + +#define FEATURESETTING_PRIVATE_BEGIN 0x1000 +#define FEATURESETTING_PRIVATE_END 0x1FFF + + typedef struct _PSFEATURE_OUTPUT { + WINBOOL bPageIndependent; + WINBOOL bSetPageDevice; + } PSFEATURE_OUTPUT,*PPSFEATURE_OUTPUT; + + typedef struct _PSFEATURE_CUSTPAPER { + LONG lOrientation; + LONG lWidth; + LONG lHeight; + LONG lWidthOffset; + LONG lHeightOffset; + } PSFEATURE_CUSTPAPER,*PPSFEATURE_CUSTPAPER; + +#define PSPROTOCOL_ASCII 0 +#define PSPROTOCOL_BCP 1 +#define PSPROTOCOL_TBCP 2 +#define PSPROTOCOL_BINARY 3 + +#define QDI_SETDIBITS 1 +#define QDI_GETDIBITS 2 +#define QDI_DIBTOSCREEN 4 +#define QDI_STRETCHDIB 8 + +#define SP_NOTREPORTED 0x4000 +#define SP_ERROR (-1) +#define SP_APPABORT (-2) +#define SP_USERABORT (-3) +#define SP_OUTOFDISK (-4) +#define SP_OUTOFMEMORY (-5) + +#define PR_JOBSTATUS 0x0000 + +#define OBJ_PEN 1 +#define OBJ_BRUSH 2 +#define OBJ_DC 3 +#define OBJ_METADC 4 +#define OBJ_PAL 5 +#define OBJ_FONT 6 +#define OBJ_BITMAP 7 +#define OBJ_REGION 8 +#define OBJ_METAFILE 9 +#define OBJ_MEMDC 10 +#define OBJ_EXTPEN 11 +#define OBJ_ENHMETADC 12 +#define OBJ_ENHMETAFILE 13 +#define OBJ_COLORSPACE 14 + +#define MWT_IDENTITY 1 +#define MWT_LEFTMULTIPLY 2 +#define MWT_RIGHTMULTIPLY 3 + +#define MWT_MIN MWT_IDENTITY +#define MWT_MAX MWT_RIGHTMULTIPLY + +#define _XFORM_ + typedef struct tagXFORM { + FLOAT eM11; + FLOAT eM12; + FLOAT eM21; + FLOAT eM22; + FLOAT eDx; + FLOAT eDy; + } XFORM,*PXFORM,*LPXFORM; + + typedef struct tagBITMAP { + LONG bmType; + LONG bmWidth; + LONG bmHeight; + LONG bmWidthBytes; + WORD bmPlanes; + WORD bmBitsPixel; + LPVOID bmBits; + } BITMAP,*PBITMAP,*NPBITMAP,*LPBITMAP; + +#include + typedef struct tagRGBTRIPLE { + BYTE rgbtBlue; + BYTE rgbtGreen; + BYTE rgbtRed; + } RGBTRIPLE; +#include + + typedef struct tagRGBQUAD { + BYTE rgbBlue; + BYTE rgbGreen; + BYTE rgbRed; + BYTE rgbReserved; + } RGBQUAD; + typedef RGBQUAD *LPRGBQUAD; + +#define CS_ENABLE 0x00000001L +#define CS_DISABLE 0x00000002L +#define CS_DELETE_TRANSFORM 0x00000003L + +//!__TINYC__: #define LCS_SIGNATURE 'PSOC' +//!__TINYC__: #define LCS_sRGB 'sRGB' +//!__TINYC__: #define LCS_WINDOWS_COLOR_SPACE 'Win ' + + typedef LONG LCSCSTYPE; +#define LCS_CALIBRATED_RGB 0x00000000L + + typedef LONG LCSGAMUTMATCH; +#define LCS_GM_BUSINESS 0x00000001L +#define LCS_GM_GRAPHICS 0x00000002L +#define LCS_GM_IMAGES 0x00000004L +#define LCS_GM_ABS_COLORIMETRIC 0x00000008L + +#define CM_OUT_OF_GAMUT 255 +#define CM_IN_GAMUT 0 + +#define ICM_ADDPROFILE 1 +#define ICM_DELETEPROFILE 2 +#define ICM_QUERYPROFILE 3 +#define ICM_SETDEFAULTPROFILE 4 +#define ICM_REGISTERICMATCHER 5 +#define ICM_UNREGISTERICMATCHER 6 +#define ICM_QUERYMATCH 7 + +#define GetKValue(cmyk) ((BYTE)(cmyk)) +#define GetYValue(cmyk) ((BYTE)((cmyk)>> 8)) +#define GetMValue(cmyk) ((BYTE)((cmyk)>>16)) +#define GetCValue(cmyk) ((BYTE)((cmyk)>>24)) + +#define CMYK(c,m,y,k) ((COLORREF)((((BYTE)(k)|((WORD)((BYTE)(y))<<8))|(((DWORD)(BYTE)(m))<<16))|(((DWORD)(BYTE)(c))<<24))) + + typedef long FXPT16DOT16,*LPFXPT16DOT16; + typedef long FXPT2DOT30,*LPFXPT2DOT30; + + typedef struct tagCIEXYZ { + FXPT2DOT30 ciexyzX; + FXPT2DOT30 ciexyzY; + FXPT2DOT30 ciexyzZ; + } CIEXYZ; + typedef CIEXYZ *LPCIEXYZ; + + typedef struct tagICEXYZTRIPLE { + CIEXYZ ciexyzRed; + CIEXYZ ciexyzGreen; + CIEXYZ ciexyzBlue; + } CIEXYZTRIPLE; + + typedef CIEXYZTRIPLE *LPCIEXYZTRIPLE; + + typedef struct tagLOGCOLORSPACEA { + DWORD lcsSignature; + DWORD lcsVersion; + DWORD lcsSize; + LCSCSTYPE lcsCSType; + LCSGAMUTMATCH lcsIntent; + CIEXYZTRIPLE lcsEndpoints; + DWORD lcsGammaRed; + DWORD lcsGammaGreen; + DWORD lcsGammaBlue; + CHAR lcsFilename[MAX_PATH]; + } LOGCOLORSPACEA,*LPLOGCOLORSPACEA; + + typedef struct tagLOGCOLORSPACEW { + DWORD lcsSignature; + DWORD lcsVersion; + DWORD lcsSize; + LCSCSTYPE lcsCSType; + LCSGAMUTMATCH lcsIntent; + CIEXYZTRIPLE lcsEndpoints; + DWORD lcsGammaRed; + DWORD lcsGammaGreen; + DWORD lcsGammaBlue; + WCHAR lcsFilename[MAX_PATH]; + } LOGCOLORSPACEW,*LPLOGCOLORSPACEW; + +#ifdef UNICODE + typedef LOGCOLORSPACEW LOGCOLORSPACE; + typedef LPLOGCOLORSPACEW LPLOGCOLORSPACE; +#else + typedef LOGCOLORSPACEA LOGCOLORSPACE; + typedef LPLOGCOLORSPACEA LPLOGCOLORSPACE; +#endif + + typedef struct tagBITMAPCOREHEADER { + DWORD bcSize; + WORD bcWidth; + WORD bcHeight; + WORD bcPlanes; + WORD bcBitCount; + } BITMAPCOREHEADER,*LPBITMAPCOREHEADER,*PBITMAPCOREHEADER; + + typedef struct tagBITMAPINFOHEADER { + DWORD biSize; + LONG biWidth; + LONG biHeight; + WORD biPlanes; + WORD biBitCount; + DWORD biCompression; + DWORD biSizeImage; + LONG biXPelsPerMeter; + LONG biYPelsPerMeter; + DWORD biClrUsed; + DWORD biClrImportant; + } BITMAPINFOHEADER,*LPBITMAPINFOHEADER,*PBITMAPINFOHEADER; + + typedef struct { + DWORD bV4Size; + LONG bV4Width; + LONG bV4Height; + WORD bV4Planes; + WORD bV4BitCount; + DWORD bV4V4Compression; + DWORD bV4SizeImage; + LONG bV4XPelsPerMeter; + LONG bV4YPelsPerMeter; + DWORD bV4ClrUsed; + DWORD bV4ClrImportant; + DWORD bV4RedMask; + DWORD bV4GreenMask; + DWORD bV4BlueMask; + DWORD bV4AlphaMask; + DWORD bV4CSType; + CIEXYZTRIPLE bV4Endpoints; + DWORD bV4GammaRed; + DWORD bV4GammaGreen; + DWORD bV4GammaBlue; + } BITMAPV4HEADER,*LPBITMAPV4HEADER,*PBITMAPV4HEADER; + + typedef struct { + DWORD bV5Size; + LONG bV5Width; + LONG bV5Height; + WORD bV5Planes; + WORD bV5BitCount; + DWORD bV5Compression; + DWORD bV5SizeImage; + LONG bV5XPelsPerMeter; + LONG bV5YPelsPerMeter; + DWORD bV5ClrUsed; + DWORD bV5ClrImportant; + DWORD bV5RedMask; + DWORD bV5GreenMask; + DWORD bV5BlueMask; + DWORD bV5AlphaMask; + DWORD bV5CSType; + CIEXYZTRIPLE bV5Endpoints; + DWORD bV5GammaRed; + DWORD bV5GammaGreen; + DWORD bV5GammaBlue; + DWORD bV5Intent; + DWORD bV5ProfileData; + DWORD bV5ProfileSize; + DWORD bV5Reserved; + } BITMAPV5HEADER,*LPBITMAPV5HEADER,*PBITMAPV5HEADER; + +//!__TINYC__: #define PROFILE_LINKED 'LINK' +//!__TINYC__: #define PROFILE_EMBEDDED 'MBED' + +#define BI_RGB 0L +#define BI_RLE8 1L +#define BI_RLE4 2L +#define BI_BITFIELDS 3L +#define BI_JPEG 4L +#define BI_PNG 5L + + typedef struct tagBITMAPINFO { + BITMAPINFOHEADER bmiHeader; + RGBQUAD bmiColors[1]; + } BITMAPINFO,*LPBITMAPINFO,*PBITMAPINFO; + + typedef struct tagBITMAPCOREINFO { + BITMAPCOREHEADER bmciHeader; + RGBTRIPLE bmciColors[1]; + } BITMAPCOREINFO,*LPBITMAPCOREINFO,*PBITMAPCOREINFO; + +#include + typedef struct tagBITMAPFILEHEADER { + WORD bfType; + DWORD bfSize; + WORD bfReserved1; + WORD bfReserved2; + DWORD bfOffBits; + } BITMAPFILEHEADER,*LPBITMAPFILEHEADER,*PBITMAPFILEHEADER; +#include + +#define MAKEPOINTS(l) (*((POINTS *)&(l))) + +#ifndef NOFONTSIG + typedef struct tagFONTSIGNATURE { + DWORD fsUsb[4]; + DWORD fsCsb[2]; + } FONTSIGNATURE,*PFONTSIGNATURE,*LPFONTSIGNATURE; + + typedef struct tagCHARSETINFO { + UINT ciCharset; + UINT ciACP; + FONTSIGNATURE fs; + } CHARSETINFO,*PCHARSETINFO,*NPCHARSETINFO,*LPCHARSETINFO; + +#define TCI_SRCCHARSET 1 +#define TCI_SRCCODEPAGE 2 +#define TCI_SRCFONTSIG 3 +#define TCI_SRCLOCALE 0x1000 + + typedef struct tagLOCALESIGNATURE { + DWORD lsUsb[4]; + DWORD lsCsbDefault[2]; + DWORD lsCsbSupported[2]; + } LOCALESIGNATURE,*PLOCALESIGNATURE,*LPLOCALESIGNATURE; +#endif + + +#ifndef NOMETAFILE + typedef struct tagHANDLETABLE { + HGDIOBJ objectHandle[1]; + } HANDLETABLE,*PHANDLETABLE,*LPHANDLETABLE; + + typedef struct tagMETARECORD { + DWORD rdSize; + WORD rdFunction; + WORD rdParm[1]; + } METARECORD; + typedef struct tagMETARECORD UNALIGNED *PMETARECORD; + typedef struct tagMETARECORD UNALIGNED *LPMETARECORD; + + typedef struct tagMETAFILEPICT { + LONG mm; + LONG xExt; + LONG yExt; + HMETAFILE hMF; + } METAFILEPICT,*LPMETAFILEPICT; + +#include + typedef struct tagMETAHEADER { + WORD mtType; + WORD mtHeaderSize; + WORD mtVersion; + DWORD mtSize; + WORD mtNoObjects; + DWORD mtMaxRecord; + WORD mtNoParameters; + } METAHEADER; + typedef struct tagMETAHEADER UNALIGNED *PMETAHEADER; + typedef struct tagMETAHEADER UNALIGNED *LPMETAHEADER; + +#include + + typedef struct tagENHMETARECORD { + DWORD iType; + DWORD nSize; + DWORD dParm[1]; + } ENHMETARECORD,*PENHMETARECORD,*LPENHMETARECORD; + + typedef struct tagENHMETAHEADER { + DWORD iType; + DWORD nSize; + RECTL rclBounds; + RECTL rclFrame; + DWORD dSignature; + DWORD nVersion; + DWORD nBytes; + DWORD nRecords; + WORD nHandles; + WORD sReserved; + DWORD nDescription; + DWORD offDescription; + DWORD nPalEntries; + SIZEL szlDevice; + SIZEL szlMillimeters; + DWORD cbPixelFormat; + DWORD offPixelFormat; + DWORD bOpenGL; + SIZEL szlMicrometers; + } ENHMETAHEADER,*PENHMETAHEADER,*LPENHMETAHEADER; +#endif + +#ifndef NOTEXTMETRIC +#define TMPF_FIXED_PITCH 0x01 +#define TMPF_VECTOR 0x02 +#define TMPF_DEVICE 0x08 +#define TMPF_TRUETYPE 0x04 + +#ifdef UNICODE + typedef WCHAR BCHAR; +#else + typedef BYTE BCHAR; +#endif + +#ifndef _TEXTMETRIC_DEFINED +#define _TEXTMETRIC_DEFINED + typedef struct tagTEXTMETRICA { + LONG tmHeight; + LONG tmAscent; + LONG tmDescent; + LONG tmInternalLeading; + LONG tmExternalLeading; + LONG tmAveCharWidth; + LONG tmMaxCharWidth; + LONG tmWeight; + LONG tmOverhang; + LONG tmDigitizedAspectX; + LONG tmDigitizedAspectY; + BYTE tmFirstChar; + BYTE tmLastChar; + BYTE tmDefaultChar; + BYTE tmBreakChar; + BYTE tmItalic; + BYTE tmUnderlined; + BYTE tmStruckOut; + BYTE tmPitchAndFamily; + BYTE tmCharSet; + } TEXTMETRICA,*PTEXTMETRICA,*NPTEXTMETRICA,*LPTEXTMETRICA; + + typedef struct tagTEXTMETRICW { + LONG tmHeight; + LONG tmAscent; + LONG tmDescent; + LONG tmInternalLeading; + LONG tmExternalLeading; + LONG tmAveCharWidth; + LONG tmMaxCharWidth; + LONG tmWeight; + LONG tmOverhang; + LONG tmDigitizedAspectX; + LONG tmDigitizedAspectY; + WCHAR tmFirstChar; + WCHAR tmLastChar; + WCHAR tmDefaultChar; + WCHAR tmBreakChar; + BYTE tmItalic; + BYTE tmUnderlined; + BYTE tmStruckOut; + BYTE tmPitchAndFamily; + BYTE tmCharSet; + } TEXTMETRICW,*PTEXTMETRICW,*NPTEXTMETRICW,*LPTEXTMETRICW; +#ifdef UNICODE + typedef TEXTMETRICW TEXTMETRIC; + typedef PTEXTMETRICW PTEXTMETRIC; + typedef NPTEXTMETRICW NPTEXTMETRIC; + typedef LPTEXTMETRICW LPTEXTMETRIC; +#else + typedef TEXTMETRICA TEXTMETRIC; + typedef PTEXTMETRICA PTEXTMETRIC; + typedef NPTEXTMETRICA NPTEXTMETRIC; + typedef LPTEXTMETRICA LPTEXTMETRIC; +#endif +#endif + +#define NTM_REGULAR 0x00000040L +#define NTM_BOLD 0x00000020L +#define NTM_ITALIC 0x00000001L + +#define NTM_NONNEGATIVE_AC 0x00010000 +#define NTM_PS_OPENTYPE 0x00020000 +#define NTM_TT_OPENTYPE 0x00040000 +#define NTM_MULTIPLEMASTER 0x00080000 +#define NTM_TYPE1 0x00100000 +#define NTM_DSIG 0x00200000 + +#include + typedef struct tagNEWTEXTMETRICA { + LONG tmHeight; + LONG tmAscent; + LONG tmDescent; + LONG tmInternalLeading; + LONG tmExternalLeading; + LONG tmAveCharWidth; + LONG tmMaxCharWidth; + LONG tmWeight; + LONG tmOverhang; + LONG tmDigitizedAspectX; + LONG tmDigitizedAspectY; + BYTE tmFirstChar; + BYTE tmLastChar; + BYTE tmDefaultChar; + BYTE tmBreakChar; + BYTE tmItalic; + BYTE tmUnderlined; + BYTE tmStruckOut; + BYTE tmPitchAndFamily; + BYTE tmCharSet; + DWORD ntmFlags; + UINT ntmSizeEM; + UINT ntmCellHeight; + UINT ntmAvgWidth; + } NEWTEXTMETRICA,*PNEWTEXTMETRICA,*NPNEWTEXTMETRICA,*LPNEWTEXTMETRICA; + + typedef struct tagNEWTEXTMETRICW { + LONG tmHeight; + LONG tmAscent; + LONG tmDescent; + LONG tmInternalLeading; + LONG tmExternalLeading; + LONG tmAveCharWidth; + LONG tmMaxCharWidth; + LONG tmWeight; + LONG tmOverhang; + LONG tmDigitizedAspectX; + LONG tmDigitizedAspectY; + WCHAR tmFirstChar; + WCHAR tmLastChar; + WCHAR tmDefaultChar; + WCHAR tmBreakChar; + BYTE tmItalic; + BYTE tmUnderlined; + BYTE tmStruckOut; + BYTE tmPitchAndFamily; + BYTE tmCharSet; + DWORD ntmFlags; + UINT ntmSizeEM; + UINT ntmCellHeight; + UINT ntmAvgWidth; + } NEWTEXTMETRICW,*PNEWTEXTMETRICW,*NPNEWTEXTMETRICW,*LPNEWTEXTMETRICW; +#ifdef UNICODE + typedef NEWTEXTMETRICW NEWTEXTMETRIC; + typedef PNEWTEXTMETRICW PNEWTEXTMETRIC; + typedef NPNEWTEXTMETRICW NPNEWTEXTMETRIC; + typedef LPNEWTEXTMETRICW LPNEWTEXTMETRIC; +#else + typedef NEWTEXTMETRICA NEWTEXTMETRIC; + typedef PNEWTEXTMETRICA PNEWTEXTMETRIC; + typedef NPNEWTEXTMETRICA NPNEWTEXTMETRIC; + typedef LPNEWTEXTMETRICA LPNEWTEXTMETRIC; +#endif +#include + + typedef struct tagNEWTEXTMETRICEXA { + NEWTEXTMETRICA ntmTm; + FONTSIGNATURE ntmFontSig; + } NEWTEXTMETRICEXA; + + typedef struct tagNEWTEXTMETRICEXW { + NEWTEXTMETRICW ntmTm; + FONTSIGNATURE ntmFontSig; + } NEWTEXTMETRICEXW; +#ifdef UNICODE + typedef NEWTEXTMETRICEXW NEWTEXTMETRICEX; +#else + typedef NEWTEXTMETRICEXA NEWTEXTMETRICEX; +#endif +#endif + + typedef struct tagPELARRAY { + LONG paXCount; + LONG paYCount; + LONG paXExt; + LONG paYExt; + BYTE paRGBs; + } PELARRAY,*PPELARRAY,*NPPELARRAY,*LPPELARRAY; + + typedef struct tagLOGBRUSH { + UINT lbStyle; + COLORREF lbColor; + ULONG_PTR lbHatch; + } LOGBRUSH,*PLOGBRUSH,*NPLOGBRUSH,*LPLOGBRUSH; + + typedef struct tagLOGBRUSH32 { + UINT lbStyle; + COLORREF lbColor; + ULONG lbHatch; + } LOGBRUSH32,*PLOGBRUSH32,*NPLOGBRUSH32,*LPLOGBRUSH32; + + typedef LOGBRUSH PATTERN; + typedef PATTERN *PPATTERN; + typedef PATTERN *NPPATTERN; + typedef PATTERN *LPPATTERN; + + typedef struct tagLOGPEN { + UINT lopnStyle; + POINT lopnWidth; + COLORREF lopnColor; + } LOGPEN,*PLOGPEN,*NPLOGPEN,*LPLOGPEN; + + typedef struct tagEXTLOGPEN { + DWORD elpPenStyle; + DWORD elpWidth; + UINT elpBrushStyle; + COLORREF elpColor; + ULONG_PTR elpHatch; + DWORD elpNumEntries; + DWORD elpStyleEntry[1]; + } EXTLOGPEN,*PEXTLOGPEN,*NPEXTLOGPEN,*LPEXTLOGPEN; + +#ifndef _PALETTEENTRY_DEFINED +#define _PALETTEENTRY_DEFINED + typedef struct tagPALETTEENTRY { + BYTE peRed; + BYTE peGreen; + BYTE peBlue; + BYTE peFlags; + } PALETTEENTRY,*PPALETTEENTRY,*LPPALETTEENTRY; +#endif + +#ifndef _LOGPALETTE_DEFINED +#define _LOGPALETTE_DEFINED + + typedef struct tagLOGPALETTE { + WORD palVersion; + WORD palNumEntries; + PALETTEENTRY palPalEntry[1]; + } LOGPALETTE,*PLOGPALETTE,*NPLOGPALETTE,*LPLOGPALETTE; +#endif + +#define LF_FACESIZE 32 + + typedef struct tagLOGFONTA { + LONG lfHeight; + LONG lfWidth; + LONG lfEscapement; + LONG lfOrientation; + LONG lfWeight; + BYTE lfItalic; + BYTE lfUnderline; + BYTE lfStrikeOut; + BYTE lfCharSet; + BYTE lfOutPrecision; + BYTE lfClipPrecision; + BYTE lfQuality; + BYTE lfPitchAndFamily; + CHAR lfFaceName[LF_FACESIZE]; + } LOGFONTA,*PLOGFONTA,*NPLOGFONTA,*LPLOGFONTA; + + typedef struct tagLOGFONTW { + LONG lfHeight; + LONG lfWidth; + LONG lfEscapement; + LONG lfOrientation; + LONG lfWeight; + BYTE lfItalic; + BYTE lfUnderline; + BYTE lfStrikeOut; + BYTE lfCharSet; + BYTE lfOutPrecision; + BYTE lfClipPrecision; + BYTE lfQuality; + BYTE lfPitchAndFamily; + WCHAR lfFaceName[LF_FACESIZE]; + } LOGFONTW,*PLOGFONTW,*NPLOGFONTW,*LPLOGFONTW; +#ifdef UNICODE + typedef LOGFONTW LOGFONT; + typedef PLOGFONTW PLOGFONT; + typedef NPLOGFONTW NPLOGFONT; + typedef LPLOGFONTW LPLOGFONT; +#else + typedef LOGFONTA LOGFONT; + typedef PLOGFONTA PLOGFONT; + typedef NPLOGFONTA NPLOGFONT; + typedef LPLOGFONTA LPLOGFONT; +#endif + +#define LF_FULLFACESIZE 64 + + typedef struct tagENUMLOGFONTA { + LOGFONTA elfLogFont; + BYTE elfFullName[LF_FULLFACESIZE]; + BYTE elfStyle[LF_FACESIZE]; + } ENUMLOGFONTA,*LPENUMLOGFONTA; + + typedef struct tagENUMLOGFONTW { + LOGFONTW elfLogFont; + WCHAR elfFullName[LF_FULLFACESIZE]; + WCHAR elfStyle[LF_FACESIZE]; + } ENUMLOGFONTW,*LPENUMLOGFONTW; +#ifdef UNICODE + typedef ENUMLOGFONTW ENUMLOGFONT; + typedef LPENUMLOGFONTW LPENUMLOGFONT; +#else + typedef ENUMLOGFONTA ENUMLOGFONT; + typedef LPENUMLOGFONTA LPENUMLOGFONT; +#endif + + typedef struct tagENUMLOGFONTEXA { + LOGFONTA elfLogFont; + BYTE elfFullName[LF_FULLFACESIZE]; + BYTE elfStyle[LF_FACESIZE]; + BYTE elfScript[LF_FACESIZE]; + } ENUMLOGFONTEXA,*LPENUMLOGFONTEXA; + + typedef struct tagENUMLOGFONTEXW { + LOGFONTW elfLogFont; + WCHAR elfFullName[LF_FULLFACESIZE]; + WCHAR elfStyle[LF_FACESIZE]; + WCHAR elfScript[LF_FACESIZE]; + } ENUMLOGFONTEXW,*LPENUMLOGFONTEXW; +#ifdef UNICODE + typedef ENUMLOGFONTEXW ENUMLOGFONTEX; + typedef LPENUMLOGFONTEXW LPENUMLOGFONTEX; +#else + typedef ENUMLOGFONTEXA ENUMLOGFONTEX; + typedef LPENUMLOGFONTEXA LPENUMLOGFONTEX; +#endif + +#define OUT_DEFAULT_PRECIS 0 +#define OUT_STRING_PRECIS 1 +#define OUT_CHARACTER_PRECIS 2 +#define OUT_STROKE_PRECIS 3 +#define OUT_TT_PRECIS 4 +#define OUT_DEVICE_PRECIS 5 +#define OUT_RASTER_PRECIS 6 +#define OUT_TT_ONLY_PRECIS 7 +#define OUT_OUTLINE_PRECIS 8 +#define OUT_SCREEN_OUTLINE_PRECIS 9 +#define OUT_PS_ONLY_PRECIS 10 + +#define CLIP_DEFAULT_PRECIS 0 +#define CLIP_CHARACTER_PRECIS 1 +#define CLIP_STROKE_PRECIS 2 +#define CLIP_MASK 0xf +#define CLIP_LH_ANGLES (1<<4) +#define CLIP_TT_ALWAYS (2<<4) +#define CLIP_DFA_DISABLE (4<<4) +#define CLIP_EMBEDDED (8<<4) + +#define DEFAULT_QUALITY 0 +#define DRAFT_QUALITY 1 +#define PROOF_QUALITY 2 +#define NONANTIALIASED_QUALITY 3 +#define ANTIALIASED_QUALITY 4 + +#define CLEARTYPE_QUALITY 5 +#define CLEARTYPE_NATURAL_QUALITY 6 + +#define DEFAULT_PITCH 0 +#define FIXED_PITCH 1 +#define VARIABLE_PITCH 2 +#define MONO_FONT 8 + +#define ANSI_CHARSET 0 +#define DEFAULT_CHARSET 1 +#define SYMBOL_CHARSET 2 +#define SHIFTJIS_CHARSET 128 +#define HANGEUL_CHARSET 129 +#define HANGUL_CHARSET 129 +#define GB2312_CHARSET 134 +#define CHINESEBIG5_CHARSET 136 +#define OEM_CHARSET 255 +#define JOHAB_CHARSET 130 +#define HEBREW_CHARSET 177 +#define ARABIC_CHARSET 178 +#define GREEK_CHARSET 161 +#define TURKISH_CHARSET 162 +#define VIETNAMESE_CHARSET 163 +#define THAI_CHARSET 222 +#define EASTEUROPE_CHARSET 238 +#define RUSSIAN_CHARSET 204 + +#define MAC_CHARSET 77 +#define BALTIC_CHARSET 186 + +#define FS_LATIN1 0x00000001L +#define FS_LATIN2 0x00000002L +#define FS_CYRILLIC 0x00000004L +#define FS_GREEK 0x00000008L +#define FS_TURKISH 0x00000010L +#define FS_HEBREW 0x00000020L +#define FS_ARABIC 0x00000040L +#define FS_BALTIC 0x00000080L +#define FS_VIETNAMESE 0x00000100L +#define FS_THAI 0x00010000L +#define FS_JISJAPAN 0x00020000L +#define FS_CHINESESIMP 0x00040000L +#define FS_WANSUNG 0x00080000L +#define FS_CHINESETRAD 0x00100000L +#define FS_JOHAB 0x00200000L +#define FS_SYMBOL 0x80000000L + +#define FF_DONTCARE (0<<4) +#define FF_ROMAN (1<<4) + +#define FF_SWISS (2<<4) + +#define FF_MODERN (3<<4) + +#define FF_SCRIPT (4<<4) +#define FF_DECORATIVE (5<<4) + +#define FW_DONTCARE 0 +#define FW_THIN 100 +#define FW_EXTRALIGHT 200 +#define FW_LIGHT 300 +#define FW_NORMAL 400 +#define FW_MEDIUM 500 +#define FW_SEMIBOLD 600 +#define FW_BOLD 700 +#define FW_EXTRABOLD 800 +#define FW_HEAVY 900 + +#define FW_ULTRALIGHT FW_EXTRALIGHT +#define FW_REGULAR FW_NORMAL +#define FW_DEMIBOLD FW_SEMIBOLD +#define FW_ULTRABOLD FW_EXTRABOLD +#define FW_BLACK FW_HEAVY + +#define PANOSE_COUNT 10 +#define PAN_FAMILYTYPE_INDEX 0 +#define PAN_SERIFSTYLE_INDEX 1 +#define PAN_WEIGHT_INDEX 2 +#define PAN_PROPORTION_INDEX 3 +#define PAN_CONTRAST_INDEX 4 +#define PAN_STROKEVARIATION_INDEX 5 +#define PAN_ARMSTYLE_INDEX 6 +#define PAN_LETTERFORM_INDEX 7 +#define PAN_MIDLINE_INDEX 8 +#define PAN_XHEIGHT_INDEX 9 + +#define PAN_CULTURE_LATIN 0 + + typedef struct tagPANOSE { + BYTE bFamilyType; + BYTE bSerifStyle; + BYTE bWeight; + BYTE bProportion; + BYTE bContrast; + BYTE bStrokeVariation; + BYTE bArmStyle; + BYTE bLetterform; + BYTE bMidline; + BYTE bXHeight; + } PANOSE,*LPPANOSE; + +#define PAN_ANY 0 +#define PAN_NO_FIT 1 + +#define PAN_FAMILY_TEXT_DISPLAY 2 +#define PAN_FAMILY_SCRIPT 3 +#define PAN_FAMILY_DECORATIVE 4 +#define PAN_FAMILY_PICTORIAL 5 + +#define PAN_SERIF_COVE 2 +#define PAN_SERIF_OBTUSE_COVE 3 +#define PAN_SERIF_SQUARE_COVE 4 +#define PAN_SERIF_OBTUSE_SQUARE_COVE 5 +#define PAN_SERIF_SQUARE 6 +#define PAN_SERIF_THIN 7 +#define PAN_SERIF_BONE 8 +#define PAN_SERIF_EXAGGERATED 9 +#define PAN_SERIF_TRIANGLE 10 +#define PAN_SERIF_NORMAL_SANS 11 +#define PAN_SERIF_OBTUSE_SANS 12 +#define PAN_SERIF_PERP_SANS 13 +#define PAN_SERIF_FLARED 14 +#define PAN_SERIF_ROUNDED 15 + +#define PAN_WEIGHT_VERY_LIGHT 2 +#define PAN_WEIGHT_LIGHT 3 +#define PAN_WEIGHT_THIN 4 +#define PAN_WEIGHT_BOOK 5 +#define PAN_WEIGHT_MEDIUM 6 +#define PAN_WEIGHT_DEMI 7 +#define PAN_WEIGHT_BOLD 8 +#define PAN_WEIGHT_HEAVY 9 +#define PAN_WEIGHT_BLACK 10 +#define PAN_WEIGHT_NORD 11 + +#define PAN_PROP_OLD_STYLE 2 +#define PAN_PROP_MODERN 3 +#define PAN_PROP_EVEN_WIDTH 4 +#define PAN_PROP_EXPANDED 5 +#define PAN_PROP_CONDENSED 6 +#define PAN_PROP_VERY_EXPANDED 7 +#define PAN_PROP_VERY_CONDENSED 8 +#define PAN_PROP_MONOSPACED 9 + +#define PAN_CONTRAST_NONE 2 +#define PAN_CONTRAST_VERY_LOW 3 +#define PAN_CONTRAST_LOW 4 +#define PAN_CONTRAST_MEDIUM_LOW 5 +#define PAN_CONTRAST_MEDIUM 6 +#define PAN_CONTRAST_MEDIUM_HIGH 7 +#define PAN_CONTRAST_HIGH 8 +#define PAN_CONTRAST_VERY_HIGH 9 + +#define PAN_STROKE_GRADUAL_DIAG 2 +#define PAN_STROKE_GRADUAL_TRAN 3 +#define PAN_STROKE_GRADUAL_VERT 4 +#define PAN_STROKE_GRADUAL_HORZ 5 +#define PAN_STROKE_RAPID_VERT 6 +#define PAN_STROKE_RAPID_HORZ 7 +#define PAN_STROKE_INSTANT_VERT 8 + +#define PAN_STRAIGHT_ARMS_HORZ 2 +#define PAN_STRAIGHT_ARMS_WEDGE 3 +#define PAN_STRAIGHT_ARMS_VERT 4 +#define PAN_STRAIGHT_ARMS_SINGLE_SERIF 5 +#define PAN_STRAIGHT_ARMS_DOUBLE_SERIF 6 +#define PAN_BENT_ARMS_HORZ 7 +#define PAN_BENT_ARMS_WEDGE 8 +#define PAN_BENT_ARMS_VERT 9 +#define PAN_BENT_ARMS_SINGLE_SERIF 10 +#define PAN_BENT_ARMS_DOUBLE_SERIF 11 + +#define PAN_LETT_NORMAL_CONTACT 2 +#define PAN_LETT_NORMAL_WEIGHTED 3 +#define PAN_LETT_NORMAL_BOXED 4 +#define PAN_LETT_NORMAL_FLATTENED 5 +#define PAN_LETT_NORMAL_ROUNDED 6 +#define PAN_LETT_NORMAL_OFF_CENTER 7 +#define PAN_LETT_NORMAL_SQUARE 8 +#define PAN_LETT_OBLIQUE_CONTACT 9 +#define PAN_LETT_OBLIQUE_WEIGHTED 10 +#define PAN_LETT_OBLIQUE_BOXED 11 +#define PAN_LETT_OBLIQUE_FLATTENED 12 +#define PAN_LETT_OBLIQUE_ROUNDED 13 +#define PAN_LETT_OBLIQUE_OFF_CENTER 14 +#define PAN_LETT_OBLIQUE_SQUARE 15 + +#define PAN_MIDLINE_STANDARD_TRIMMED 2 +#define PAN_MIDLINE_STANDARD_POINTED 3 +#define PAN_MIDLINE_STANDARD_SERIFED 4 +#define PAN_MIDLINE_HIGH_TRIMMED 5 +#define PAN_MIDLINE_HIGH_POINTED 6 +#define PAN_MIDLINE_HIGH_SERIFED 7 +#define PAN_MIDLINE_CONSTANT_TRIMMED 8 +#define PAN_MIDLINE_CONSTANT_POINTED 9 +#define PAN_MIDLINE_CONSTANT_SERIFED 10 +#define PAN_MIDLINE_LOW_TRIMMED 11 +#define PAN_MIDLINE_LOW_POINTED 12 +#define PAN_MIDLINE_LOW_SERIFED 13 + +#define PAN_XHEIGHT_CONSTANT_SMALL 2 +#define PAN_XHEIGHT_CONSTANT_STD 3 +#define PAN_XHEIGHT_CONSTANT_LARGE 4 +#define PAN_XHEIGHT_DUCKING_SMALL 5 +#define PAN_XHEIGHT_DUCKING_STD 6 +#define PAN_XHEIGHT_DUCKING_LARGE 7 + +#define ELF_VENDOR_SIZE 4 + + typedef struct tagEXTLOGFONTA { + LOGFONTA elfLogFont; + BYTE elfFullName[LF_FULLFACESIZE]; + BYTE elfStyle[LF_FACESIZE]; + DWORD elfVersion; + DWORD elfStyleSize; + DWORD elfMatch; + DWORD elfReserved; + BYTE elfVendorId[ELF_VENDOR_SIZE]; + DWORD elfCulture; + PANOSE elfPanose; + } EXTLOGFONTA,*PEXTLOGFONTA,*NPEXTLOGFONTA,*LPEXTLOGFONTA; + + typedef struct tagEXTLOGFONTW { + LOGFONTW elfLogFont; + WCHAR elfFullName[LF_FULLFACESIZE]; + WCHAR elfStyle[LF_FACESIZE]; + DWORD elfVersion; + DWORD elfStyleSize; + DWORD elfMatch; + DWORD elfReserved; + BYTE elfVendorId[ELF_VENDOR_SIZE]; + DWORD elfCulture; + PANOSE elfPanose; + } EXTLOGFONTW,*PEXTLOGFONTW,*NPEXTLOGFONTW,*LPEXTLOGFONTW; +#ifdef UNICODE + typedef EXTLOGFONTW EXTLOGFONT; + typedef PEXTLOGFONTW PEXTLOGFONT; + typedef NPEXTLOGFONTW NPEXTLOGFONT; + typedef LPEXTLOGFONTW LPEXTLOGFONT; +#else + typedef EXTLOGFONTA EXTLOGFONT; + typedef PEXTLOGFONTA PEXTLOGFONT; + typedef NPEXTLOGFONTA NPEXTLOGFONT; + typedef LPEXTLOGFONTA LPEXTLOGFONT; +#endif + +#define ELF_VERSION 0 +#define ELF_CULTURE_LATIN 0 + +#define RASTER_FONTTYPE 0x0001 +#define DEVICE_FONTTYPE 0x002 +#define TRUETYPE_FONTTYPE 0x004 + +#define RGB(r,g,b) ((COLORREF)(((BYTE)(r)|((WORD)((BYTE)(g))<<8))|(((DWORD)(BYTE)(b))<<16))) +#define PALETTERGB(r,g,b) (0x02000000 | RGB(r,g,b)) +#define PALETTEINDEX(i) ((COLORREF)(0x01000000 | (DWORD)(WORD)(i))) + +#define PC_RESERVED 0x01 +#define PC_EXPLICIT 0x02 +#define PC_NOCOLLAPSE 0x04 + +#define GetRValue(rgb) (LOBYTE(rgb)) +#define GetGValue(rgb) (LOBYTE(((WORD)(rgb)) >> 8)) +#define GetBValue(rgb) (LOBYTE((rgb)>>16)) + +#define TRANSPARENT 1 +#define OPAQUE 2 +#define BKMODE_LAST 2 + +#define GM_COMPATIBLE 1 +#define GM_ADVANCED 2 +#define GM_LAST 2 + +#define PT_CLOSEFIGURE 0x01 +#define PT_LINETO 0x02 +#define PT_BEZIERTO 0x04 +#define PT_MOVETO 0x06 + +#define MM_TEXT 1 +#define MM_LOMETRIC 2 +#define MM_HIMETRIC 3 +#define MM_LOENGLISH 4 +#define MM_HIENGLISH 5 +#define MM_TWIPS 6 +#define MM_ISOTROPIC 7 +#define MM_ANISOTROPIC 8 + +#define MM_MIN MM_TEXT +#define MM_MAX MM_ANISOTROPIC +#define MM_MAX_FIXEDSCALE MM_TWIPS + +#define ABSOLUTE 1 +#define RELATIVE 2 + +#define WHITE_BRUSH 0 +#define LTGRAY_BRUSH 1 +#define GRAY_BRUSH 2 +#define DKGRAY_BRUSH 3 +#define BLACK_BRUSH 4 +#define NULL_BRUSH 5 +#define HOLLOW_BRUSH NULL_BRUSH +#define WHITE_PEN 6 +#define BLACK_PEN 7 +#define NULL_PEN 8 +#define OEM_FIXED_FONT 10 +#define ANSI_FIXED_FONT 11 +#define ANSI_VAR_FONT 12 +#define SYSTEM_FONT 13 +#define DEVICE_DEFAULT_FONT 14 +#define DEFAULT_PALETTE 15 +#define SYSTEM_FIXED_FONT 16 + +#define DEFAULT_GUI_FONT 17 + +#define DC_BRUSH 18 +#define DC_PEN 19 + +#define STOCK_LAST 19 + +#define CLR_INVALID 0xFFFFFFFF + +#define BS_SOLID 0 +#define BS_NULL 1 +#define BS_HOLLOW BS_NULL +#define BS_HATCHED 2 +#define BS_PATTERN 3 +#define BS_INDEXED 4 +#define BS_DIBPATTERN 5 +#define BS_DIBPATTERNPT 6 +#define BS_PATTERN8X8 7 +#define BS_DIBPATTERN8X8 8 +#define BS_MONOPATTERN 9 + +#define HS_HORIZONTAL 0 +#define HS_VERTICAL 1 +#define HS_FDIAGONAL 2 +#define HS_BDIAGONAL 3 +#define HS_CROSS 4 +#define HS_DIAGCROSS 5 + +#define PS_SOLID 0 +#define PS_DASH 1 +#define PS_DOT 2 +#define PS_DASHDOT 3 +#define PS_DASHDOTDOT 4 +#define PS_NULL 5 +#define PS_INSIDEFRAME 6 +#define PS_USERSTYLE 7 +#define PS_ALTERNATE 8 +#define PS_STYLE_MASK 0x0000000F + +#define PS_ENDCAP_ROUND 0x00000000 +#define PS_ENDCAP_SQUARE 0x00000100 +#define PS_ENDCAP_FLAT 0x00000200 +#define PS_ENDCAP_MASK 0x00000F00 + +#define PS_JOIN_ROUND 0x00000000 +#define PS_JOIN_BEVEL 0x00001000 +#define PS_JOIN_MITER 0x00002000 +#define PS_JOIN_MASK 0x0000F000 + +#define PS_COSMETIC 0x00000000 +#define PS_GEOMETRIC 0x00010000 +#define PS_TYPE_MASK 0x000F0000 + +#define AD_COUNTERCLOCKWISE 1 +#define AD_CLOCKWISE 2 + +#define DRIVERVERSION 0 +#define TECHNOLOGY 2 +#define HORZSIZE 4 +#define VERTSIZE 6 +#define HORZRES 8 +#define VERTRES 10 +#define BITSPIXEL 12 +#define PLANES 14 +#define NUMBRUSHES 16 +#define NUMPENS 18 +#define NUMMARKERS 20 +#define NUMFONTS 22 +#define NUMCOLORS 24 +#define PDEVICESIZE 26 +#define CURVECAPS 28 +#define LINECAPS 30 +#define POLYGONALCAPS 32 +#define TEXTCAPS 34 +#define CLIPCAPS 36 +#define RASTERCAPS 38 +#define ASPECTX 40 +#define ASPECTY 42 +#define ASPECTXY 44 + +#define LOGPIXELSX 88 +#define LOGPIXELSY 90 + +#define SIZEPALETTE 104 +#define NUMRESERVED 106 +#define COLORRES 108 + +#define PHYSICALWIDTH 110 +#define PHYSICALHEIGHT 111 +#define PHYSICALOFFSETX 112 +#define PHYSICALOFFSETY 113 +#define SCALINGFACTORX 114 +#define SCALINGFACTORY 115 + +#define VREFRESH 116 + +#define DESKTOPVERTRES 117 + +#define DESKTOPHORZRES 118 + +#define BLTALIGNMENT 119 + +#define SHADEBLENDCAPS 120 +#define COLORMGMTCAPS 121 + +#ifndef NOGDICAPMASKS +#define DT_PLOTTER 0 +#define DT_RASDISPLAY 1 +#define DT_RASPRINTER 2 +#define DT_RASCAMERA 3 +#define DT_CHARSTREAM 4 +#define DT_METAFILE 5 +#define DT_DISPFILE 6 + +#define CC_NONE 0 +#define CC_CIRCLES 1 +#define CC_PIE 2 +#define CC_CHORD 4 +#define CC_ELLIPSES 8 +#define CC_WIDE 16 +#define CC_STYLED 32 +#define CC_WIDESTYLED 64 +#define CC_INTERIORS 128 +#define CC_ROUNDRECT 256 + +#define LC_NONE 0 +#define LC_POLYLINE 2 +#define LC_MARKER 4 +#define LC_POLYMARKER 8 +#define LC_WIDE 16 +#define LC_STYLED 32 +#define LC_WIDESTYLED 64 +#define LC_INTERIORS 128 + +#define PC_NONE 0 +#define PC_POLYGON 1 +#define PC_RECTANGLE 2 +#define PC_WINDPOLYGON 4 +#define PC_TRAPEZOID 4 +#define PC_SCANLINE 8 +#define PC_WIDE 16 +#define PC_STYLED 32 +#define PC_WIDESTYLED 64 +#define PC_INTERIORS 128 +#define PC_POLYPOLYGON 256 +#define PC_PATHS 512 + +#define CP_NONE 0 +#define CP_RECTANGLE 1 +#define CP_REGION 2 + +#define TC_OP_CHARACTER 0x00000001 +#define TC_OP_STROKE 0x00000002 +#define TC_CP_STROKE 0x00000004 +#define TC_CR_90 0x00000008 +#define TC_CR_ANY 0x00000010 +#define TC_SF_X_YINDEP 0x00000020 +#define TC_SA_DOUBLE 0x00000040 +#define TC_SA_INTEGER 0x00000080 +#define TC_SA_CONTIN 0x00000100 +#define TC_EA_DOUBLE 0x00000200 +#define TC_IA_ABLE 0x00000400 +#define TC_UA_ABLE 0x00000800 +#define TC_SO_ABLE 0x00001000 +#define TC_RA_ABLE 0x00002000 +#define TC_VA_ABLE 0x00004000 +#define TC_RESERVED 0x00008000 +#define TC_SCROLLBLT 0x00010000 +#endif + +#define RC_NONE +#define RC_BITBLT 1 +#define RC_BANDING 2 +#define RC_SCALING 4 +#define RC_BITMAP64 8 +#define RC_GDI20_OUTPUT 0x0010 +#define RC_GDI20_STATE 0x0020 +#define RC_SAVEBITMAP 0x0040 +#define RC_DI_BITMAP 0x0080 +#define RC_PALETTE 0x0100 +#define RC_DIBTODEV 0x0200 +#define RC_BIGFONT 0x0400 +#define RC_STRETCHBLT 0x0800 +#define RC_FLOODFILL 0x1000 +#define RC_STRETCHDIB 0x2000 +#define RC_OP_DX_OUTPUT 0x4000 +#define RC_DEVBITS 0x8000 + +#define SB_NONE 0x00000000 +#define SB_CONST_ALPHA 0x00000001 +#define SB_PIXEL_ALPHA 0x00000002 +#define SB_PREMULT_ALPHA 0x00000004 + +#define SB_GRAD_RECT 0x00000010 +#define SB_GRAD_TRI 0x00000020 + +#define CM_NONE 0x00000000 +#define CM_DEVICE_ICM 0x00000001 +#define CM_GAMMA_RAMP 0x00000002 +#define CM_CMYK_COLOR 0x00000004 + +#define DIB_RGB_COLORS 0 +#define DIB_PAL_COLORS 1 + +#define SYSPAL_ERROR 0 +#define SYSPAL_STATIC 1 +#define SYSPAL_NOSTATIC 2 +#define SYSPAL_NOSTATIC256 3 + +#define CBM_INIT 0x04L + +#define FLOODFILLBORDER 0 +#define FLOODFILLSURFACE 1 + +#define CCHDEVICENAME 32 + +#define CCHFORMNAME 32 + + typedef struct _devicemodeA { + BYTE dmDeviceName[CCHDEVICENAME]; + WORD dmSpecVersion; + WORD dmDriverVersion; + WORD dmSize; + WORD dmDriverExtra; + DWORD dmFields; + union { + struct { + short dmOrientation; + short dmPaperSize; + short dmPaperLength; + short dmPaperWidth; + short dmScale; + short dmCopies; + short dmDefaultSource; + short dmPrintQuality; + }; + struct { + POINTL dmPosition; + DWORD dmDisplayOrientation; + DWORD dmDisplayFixedOutput; + }; + }; + short dmColor; + short dmDuplex; + short dmYResolution; + short dmTTOption; + short dmCollate; + BYTE dmFormName[CCHFORMNAME]; + WORD dmLogPixels; + DWORD dmBitsPerPel; + DWORD dmPelsWidth; + DWORD dmPelsHeight; + union { + DWORD dmDisplayFlags; + DWORD dmNup; + }; + DWORD dmDisplayFrequency; + DWORD dmICMMethod; + DWORD dmICMIntent; + DWORD dmMediaType; + DWORD dmDitherType; + DWORD dmReserved1; + DWORD dmReserved2; + DWORD dmPanningWidth; + DWORD dmPanningHeight; + } DEVMODEA,*PDEVMODEA,*NPDEVMODEA,*LPDEVMODEA; + + typedef struct _devicemodeW { + WCHAR dmDeviceName[CCHDEVICENAME]; + WORD dmSpecVersion; + WORD dmDriverVersion; + WORD dmSize; + WORD dmDriverExtra; + DWORD dmFields; + union { + struct { + short dmOrientation; + short dmPaperSize; + short dmPaperLength; + short dmPaperWidth; + short dmScale; + short dmCopies; + short dmDefaultSource; + short dmPrintQuality; + }; + struct { + POINTL dmPosition; + DWORD dmDisplayOrientation; + DWORD dmDisplayFixedOutput; + }; + }; + short dmColor; + short dmDuplex; + short dmYResolution; + short dmTTOption; + short dmCollate; + WCHAR dmFormName[CCHFORMNAME]; + WORD dmLogPixels; + DWORD dmBitsPerPel; + DWORD dmPelsWidth; + DWORD dmPelsHeight; + union { + DWORD dmDisplayFlags; + DWORD dmNup; + }; + DWORD dmDisplayFrequency; + DWORD dmICMMethod; + DWORD dmICMIntent; + DWORD dmMediaType; + DWORD dmDitherType; + DWORD dmReserved1; + DWORD dmReserved2; + DWORD dmPanningWidth; + DWORD dmPanningHeight; + } DEVMODEW,*PDEVMODEW,*NPDEVMODEW,*LPDEVMODEW; +#ifdef UNICODE + typedef DEVMODEW DEVMODE; + typedef PDEVMODEW PDEVMODE; + typedef NPDEVMODEW NPDEVMODE; + typedef LPDEVMODEW LPDEVMODE; +#else + typedef DEVMODEA DEVMODE; + typedef PDEVMODEA PDEVMODE; + typedef NPDEVMODEA NPDEVMODE; + typedef LPDEVMODEA LPDEVMODE; +#endif + +#define DM_SPECVERSION 0x0401 + +#define DM_ORIENTATION 0x00000001L +#define DM_PAPERSIZE 0x00000002L +#define DM_PAPERLENGTH 0x00000004L +#define DM_PAPERWIDTH 0x00000008L +#define DM_SCALE 0x00000010L +#define DM_POSITION 0x00000020L +#define DM_NUP 0x00000040L +#define DM_DISPLAYORIENTATION 0x00000080L +#define DM_COPIES 0x00000100L +#define DM_DEFAULTSOURCE 0x00000200L +#define DM_PRINTQUALITY 0x00000400L +#define DM_COLOR 0x00000800L +#define DM_DUPLEX 0x00001000L +#define DM_YRESOLUTION 0x00002000L +#define DM_TTOPTION 0x00004000L +#define DM_COLLATE 0x00008000L +#define DM_FORMNAME 0x00010000L +#define DM_LOGPIXELS 0x00020000L +#define DM_BITSPERPEL 0x00040000L +#define DM_PELSWIDTH 0x00080000L +#define DM_PELSHEIGHT 0x00100000L +#define DM_DISPLAYFLAGS 0x00200000L +#define DM_DISPLAYFREQUENCY 0x00400000L +#define DM_ICMMETHOD 0x00800000L +#define DM_ICMINTENT 0x01000000L +#define DM_MEDIATYPE 0x02000000L +#define DM_DITHERTYPE 0x04000000L +#define DM_PANNINGWIDTH 0x08000000L +#define DM_PANNINGHEIGHT 0x10000000L +#define DM_DISPLAYFIXEDOUTPUT 0x20000000L + +#define DMORIENT_PORTRAIT 1 +#define DMORIENT_LANDSCAPE 2 + +#define DMPAPER_FIRST DMPAPER_LETTER +#define DMPAPER_LETTER 1 +#define DMPAPER_LETTERSMALL 2 +#define DMPAPER_TABLOID 3 +#define DMPAPER_LEDGER 4 +#define DMPAPER_LEGAL 5 +#define DMPAPER_STATEMENT 6 +#define DMPAPER_EXECUTIVE 7 +#define DMPAPER_A3 8 +#define DMPAPER_A4 9 +#define DMPAPER_A4SMALL 10 +#define DMPAPER_A5 11 +#define DMPAPER_B4 12 +#define DMPAPER_B5 13 +#define DMPAPER_FOLIO 14 +#define DMPAPER_QUARTO 15 +#define DMPAPER_10X14 16 +#define DMPAPER_11X17 17 +#define DMPAPER_NOTE 18 +#define DMPAPER_ENV_9 19 +#define DMPAPER_ENV_10 20 +#define DMPAPER_ENV_11 21 +#define DMPAPER_ENV_12 22 +#define DMPAPER_ENV_14 23 +#define DMPAPER_CSHEET 24 +#define DMPAPER_DSHEET 25 +#define DMPAPER_ESHEET 26 +#define DMPAPER_ENV_DL 27 +#define DMPAPER_ENV_C5 28 +#define DMPAPER_ENV_C3 29 +#define DMPAPER_ENV_C4 30 +#define DMPAPER_ENV_C6 31 +#define DMPAPER_ENV_C65 32 +#define DMPAPER_ENV_B4 33 +#define DMPAPER_ENV_B5 34 +#define DMPAPER_ENV_B6 35 +#define DMPAPER_ENV_ITALY 36 +#define DMPAPER_ENV_MONARCH 37 +#define DMPAPER_ENV_PERSONAL 38 +#define DMPAPER_FANFOLD_US 39 +#define DMPAPER_FANFOLD_STD_GERMAN 40 +#define DMPAPER_FANFOLD_LGL_GERMAN 41 +#define DMPAPER_ISO_B4 42 +#define DMPAPER_JAPANESE_POSTCARD 43 +#define DMPAPER_9X11 44 +#define DMPAPER_10X11 45 +#define DMPAPER_15X11 46 +#define DMPAPER_ENV_INVITE 47 +#define DMPAPER_RESERVED_48 48 +#define DMPAPER_RESERVED_49 49 +#define DMPAPER_LETTER_EXTRA 50 +#define DMPAPER_LEGAL_EXTRA 51 +#define DMPAPER_TABLOID_EXTRA 52 +#define DMPAPER_A4_EXTRA 53 +#define DMPAPER_LETTER_TRANSVERSE 54 +#define DMPAPER_A4_TRANSVERSE 55 +#define DMPAPER_LETTER_EXTRA_TRANSVERSE 56 +#define DMPAPER_A_PLUS 57 +#define DMPAPER_B_PLUS 58 +#define DMPAPER_LETTER_PLUS 59 +#define DMPAPER_A4_PLUS 60 +#define DMPAPER_A5_TRANSVERSE 61 +#define DMPAPER_B5_TRANSVERSE 62 +#define DMPAPER_A3_EXTRA 63 +#define DMPAPER_A5_EXTRA 64 +#define DMPAPER_B5_EXTRA 65 +#define DMPAPER_A2 66 +#define DMPAPER_A3_TRANSVERSE 67 +#define DMPAPER_A3_EXTRA_TRANSVERSE 68 +#define DMPAPER_DBL_JAPANESE_POSTCARD 69 +#define DMPAPER_A6 70 +#define DMPAPER_JENV_KAKU2 71 +#define DMPAPER_JENV_KAKU3 72 +#define DMPAPER_JENV_CHOU3 73 +#define DMPAPER_JENV_CHOU4 74 +#define DMPAPER_LETTER_ROTATED 75 +#define DMPAPER_A3_ROTATED 76 +#define DMPAPER_A4_ROTATED 77 +#define DMPAPER_A5_ROTATED 78 +#define DMPAPER_B4_JIS_ROTATED 79 +#define DMPAPER_B5_JIS_ROTATED 80 +#define DMPAPER_JAPANESE_POSTCARD_ROTATED 81 +#define DMPAPER_DBL_JAPANESE_POSTCARD_ROTATED 82 +#define DMPAPER_A6_ROTATED 83 +#define DMPAPER_JENV_KAKU2_ROTATED 84 +#define DMPAPER_JENV_KAKU3_ROTATED 85 +#define DMPAPER_JENV_CHOU3_ROTATED 86 +#define DMPAPER_JENV_CHOU4_ROTATED 87 +#define DMPAPER_B6_JIS 88 +#define DMPAPER_B6_JIS_ROTATED 89 +#define DMPAPER_12X11 90 +#define DMPAPER_JENV_YOU4 91 +#define DMPAPER_JENV_YOU4_ROTATED 92 +#define DMPAPER_P16K 93 +#define DMPAPER_P32K 94 +#define DMPAPER_P32KBIG 95 +#define DMPAPER_PENV_1 96 +#define DMPAPER_PENV_2 97 +#define DMPAPER_PENV_3 98 +#define DMPAPER_PENV_4 99 +#define DMPAPER_PENV_5 100 +#define DMPAPER_PENV_6 101 +#define DMPAPER_PENV_7 102 +#define DMPAPER_PENV_8 103 +#define DMPAPER_PENV_9 104 +#define DMPAPER_PENV_10 105 +#define DMPAPER_P16K_ROTATED 106 +#define DMPAPER_P32K_ROTATED 107 +#define DMPAPER_P32KBIG_ROTATED 108 +#define DMPAPER_PENV_1_ROTATED 109 +#define DMPAPER_PENV_2_ROTATED 110 +#define DMPAPER_PENV_3_ROTATED 111 +#define DMPAPER_PENV_4_ROTATED 112 +#define DMPAPER_PENV_5_ROTATED 113 +#define DMPAPER_PENV_6_ROTATED 114 +#define DMPAPER_PENV_7_ROTATED 115 +#define DMPAPER_PENV_8_ROTATED 116 +#define DMPAPER_PENV_9_ROTATED 117 +#define DMPAPER_PENV_10_ROTATED 118 + +#define DMPAPER_LAST DMPAPER_PENV_10_ROTATED + +#define DMPAPER_USER 256 + +#define DMBIN_FIRST DMBIN_UPPER +#define DMBIN_UPPER 1 +#define DMBIN_ONLYONE 1 +#define DMBIN_LOWER 2 +#define DMBIN_MIDDLE 3 +#define DMBIN_MANUAL 4 +#define DMBIN_ENVELOPE 5 +#define DMBIN_ENVMANUAL 6 +#define DMBIN_AUTO 7 +#define DMBIN_TRACTOR 8 +#define DMBIN_SMALLFMT 9 +#define DMBIN_LARGEFMT 10 +#define DMBIN_LARGECAPACITY 11 +#define DMBIN_CASSETTE 14 +#define DMBIN_FORMSOURCE 15 +#define DMBIN_LAST DMBIN_FORMSOURCE + +#define DMBIN_USER 256 + +#define DMRES_DRAFT (-1) +#define DMRES_LOW (-2) +#define DMRES_MEDIUM (-3) +#define DMRES_HIGH (-4) + +#define DMCOLOR_MONOCHROME 1 +#define DMCOLOR_COLOR 2 + +#define DMDUP_SIMPLEX 1 +#define DMDUP_VERTICAL 2 +#define DMDUP_HORIZONTAL 3 + +#define DMTT_BITMAP 1 +#define DMTT_DOWNLOAD 2 +#define DMTT_SUBDEV 3 +#define DMTT_DOWNLOAD_OUTLINE 4 + +#define DMCOLLATE_FALSE 0 +#define DMCOLLATE_TRUE 1 + +#define DMDO_DEFAULT 0 +#define DMDO_90 1 +#define DMDO_180 2 +#define DMDO_270 3 + +#define DMDFO_DEFAULT 0 +#define DMDFO_STRETCH 1 +#define DMDFO_CENTER 2 + +#define DMDISPLAYFLAGS_TEXTMODE 0x00000004 + +#define DMNUP_SYSTEM 1 +#define DMNUP_ONEUP 2 + +#define DMICMMETHOD_NONE 1 +#define DMICMMETHOD_SYSTEM 2 +#define DMICMMETHOD_DRIVER 3 +#define DMICMMETHOD_DEVICE 4 + +#define DMICMMETHOD_USER 256 + +#define DMICM_SATURATE 1 +#define DMICM_CONTRAST 2 +#define DMICM_COLORIMETRIC 3 +#define DMICM_ABS_COLORIMETRIC 4 + +#define DMICM_USER 256 + +#define DMMEDIA_STANDARD 1 +#define DMMEDIA_TRANSPARENCY 2 +#define DMMEDIA_GLOSSY 3 + +#define DMMEDIA_USER 256 + +#define DMDITHER_NONE 1 +#define DMDITHER_COARSE 2 +#define DMDITHER_FINE 3 +#define DMDITHER_LINEART 4 +#define DMDITHER_ERRORDIFFUSION 5 +#define DMDITHER_RESERVED6 6 +#define DMDITHER_RESERVED7 7 +#define DMDITHER_RESERVED8 8 +#define DMDITHER_RESERVED9 9 +#define DMDITHER_GRAYSCALE 10 + +#define DMDITHER_USER 256 + + typedef struct _DISPLAY_DEVICEA { + DWORD cb; + CHAR DeviceName[32]; + CHAR DeviceString[128]; + DWORD StateFlags; + CHAR DeviceID[128]; + CHAR DeviceKey[128]; + } DISPLAY_DEVICEA,*PDISPLAY_DEVICEA,*LPDISPLAY_DEVICEA; + typedef struct _DISPLAY_DEVICEW { + DWORD cb; + WCHAR DeviceName[32]; + WCHAR DeviceString[128]; + DWORD StateFlags; + WCHAR DeviceID[128]; + WCHAR DeviceKey[128]; + } DISPLAY_DEVICEW,*PDISPLAY_DEVICEW,*LPDISPLAY_DEVICEW; +#ifdef UNICODE + typedef DISPLAY_DEVICEW DISPLAY_DEVICE; + typedef PDISPLAY_DEVICEW PDISPLAY_DEVICE; + typedef LPDISPLAY_DEVICEW LPDISPLAY_DEVICE; +#else + typedef DISPLAY_DEVICEA DISPLAY_DEVICE; + typedef PDISPLAY_DEVICEA PDISPLAY_DEVICE; + typedef LPDISPLAY_DEVICEA LPDISPLAY_DEVICE; +#endif + +#define DISPLAY_DEVICE_ATTACHED_TO_DESKTOP 0x00000001 +#define DISPLAY_DEVICE_MULTI_DRIVER 0x00000002 +#define DISPLAY_DEVICE_PRIMARY_DEVICE 0x00000004 +#define DISPLAY_DEVICE_MIRRORING_DRIVER 0x00000008 +#define DISPLAY_DEVICE_VGA_COMPATIBLE 0x00000010 +#define DISPLAY_DEVICE_REMOVABLE 0x00000020 +#define DISPLAY_DEVICE_MODESPRUNED 0x08000000 +#define DISPLAY_DEVICE_REMOTE 0x04000000 +#define DISPLAY_DEVICE_DISCONNECT 0x02000000 + +#define DISPLAY_DEVICE_ACTIVE 0x00000001 +#define DISPLAY_DEVICE_ATTACHED 0x00000002 + +#define RDH_RECTANGLES 1 + + typedef struct _RGNDATAHEADER { + DWORD dwSize; + DWORD iType; + DWORD nCount; + DWORD nRgnSize; + RECT rcBound; + } RGNDATAHEADER,*PRGNDATAHEADER; + + typedef struct _RGNDATA { + RGNDATAHEADER rdh; + char Buffer[1]; + } RGNDATA,*PRGNDATA,*NPRGNDATA,*LPRGNDATA; + +#define SYSRGN 4 + + typedef struct _ABC { + int abcA; + UINT abcB; + int abcC; + } ABC,*PABC,*NPABC,*LPABC; + + typedef struct _ABCFLOAT { + FLOAT abcfA; + FLOAT abcfB; + FLOAT abcfC; + } ABCFLOAT,*PABCFLOAT,*NPABCFLOAT,*LPABCFLOAT; + +#ifndef NOTEXTMETRIC + + typedef struct _OUTLINETEXTMETRICA { + UINT otmSize; + TEXTMETRICA otmTextMetrics; + BYTE otmFiller; + PANOSE otmPanoseNumber; + UINT otmfsSelection; + UINT otmfsType; + int otmsCharSlopeRise; + int otmsCharSlopeRun; + int otmItalicAngle; + UINT otmEMSquare; + int otmAscent; + int otmDescent; + UINT otmLineGap; + UINT otmsCapEmHeight; + UINT otmsXHeight; + RECT otmrcFontBox; + int otmMacAscent; + int otmMacDescent; + UINT otmMacLineGap; + UINT otmusMinimumPPEM; + POINT otmptSubscriptSize; + POINT otmptSubscriptOffset; + POINT otmptSuperscriptSize; + POINT otmptSuperscriptOffset; + UINT otmsStrikeoutSize; + int otmsStrikeoutPosition; + int otmsUnderscoreSize; + int otmsUnderscorePosition; + PSTR otmpFamilyName; + PSTR otmpFaceName; + PSTR otmpStyleName; + PSTR otmpFullName; + } OUTLINETEXTMETRICA,*POUTLINETEXTMETRICA,*NPOUTLINETEXTMETRICA,*LPOUTLINETEXTMETRICA; + + typedef struct _OUTLINETEXTMETRICW { + UINT otmSize; + TEXTMETRICW otmTextMetrics; + BYTE otmFiller; + PANOSE otmPanoseNumber; + UINT otmfsSelection; + UINT otmfsType; + int otmsCharSlopeRise; + int otmsCharSlopeRun; + int otmItalicAngle; + UINT otmEMSquare; + int otmAscent; + int otmDescent; + UINT otmLineGap; + UINT otmsCapEmHeight; + UINT otmsXHeight; + RECT otmrcFontBox; + int otmMacAscent; + int otmMacDescent; + UINT otmMacLineGap; + UINT otmusMinimumPPEM; + POINT otmptSubscriptSize; + POINT otmptSubscriptOffset; + POINT otmptSuperscriptSize; + POINT otmptSuperscriptOffset; + UINT otmsStrikeoutSize; + int otmsStrikeoutPosition; + int otmsUnderscoreSize; + int otmsUnderscorePosition; + PSTR otmpFamilyName; + PSTR otmpFaceName; + PSTR otmpStyleName; + PSTR otmpFullName; + } OUTLINETEXTMETRICW,*POUTLINETEXTMETRICW,*NPOUTLINETEXTMETRICW,*LPOUTLINETEXTMETRICW; +#ifdef UNICODE + typedef OUTLINETEXTMETRICW OUTLINETEXTMETRIC; + typedef POUTLINETEXTMETRICW POUTLINETEXTMETRIC; + typedef NPOUTLINETEXTMETRICW NPOUTLINETEXTMETRIC; + typedef LPOUTLINETEXTMETRICW LPOUTLINETEXTMETRIC; +#else + typedef OUTLINETEXTMETRICA OUTLINETEXTMETRIC; + typedef POUTLINETEXTMETRICA POUTLINETEXTMETRIC; + typedef NPOUTLINETEXTMETRICA NPOUTLINETEXTMETRIC; + typedef LPOUTLINETEXTMETRICA LPOUTLINETEXTMETRIC; +#endif +#endif + + typedef struct tagPOLYTEXTA { + int x; + int y; + UINT n; + LPCSTR lpstr; + UINT uiFlags; + RECT rcl; + int *pdx; + } POLYTEXTA,*PPOLYTEXTA,*NPPOLYTEXTA,*LPPOLYTEXTA; + + typedef struct tagPOLYTEXTW { + int x; + int y; + UINT n; + LPCWSTR lpstr; + UINT uiFlags; + RECT rcl; + int *pdx; + } POLYTEXTW,*PPOLYTEXTW,*NPPOLYTEXTW,*LPPOLYTEXTW; +#ifdef UNICODE + typedef POLYTEXTW POLYTEXT; + typedef PPOLYTEXTW PPOLYTEXT; + typedef NPPOLYTEXTW NPPOLYTEXT; + typedef LPPOLYTEXTW LPPOLYTEXT; +#else + typedef POLYTEXTA POLYTEXT; + typedef PPOLYTEXTA PPOLYTEXT; + typedef NPPOLYTEXTA NPPOLYTEXT; + typedef LPPOLYTEXTA LPPOLYTEXT; +#endif + + typedef struct _FIXED { + WORD fract; + short value; + } FIXED; + + typedef struct _MAT2 { + FIXED eM11; + FIXED eM12; + FIXED eM21; + FIXED eM22; + } MAT2,*LPMAT2; + + typedef struct _GLYPHMETRICS { + UINT gmBlackBoxX; + UINT gmBlackBoxY; + POINT gmptGlyphOrigin; + short gmCellIncX; + short gmCellIncY; + } GLYPHMETRICS,*LPGLYPHMETRICS; + +#define GGO_METRICS 0 +#define GGO_BITMAP 1 +#define GGO_NATIVE 2 +#define GGO_BEZIER 3 + +#define GGO_GRAY2_BITMAP 4 +#define GGO_GRAY4_BITMAP 5 +#define GGO_GRAY8_BITMAP 6 +#define GGO_GLYPH_INDEX 0x0080 +#define GGO_UNHINTED 0x0100 + +#define TT_POLYGON_TYPE 24 + +#define TT_PRIM_LINE 1 +#define TT_PRIM_QSPLINE 2 +#define TT_PRIM_CSPLINE 3 + + typedef struct tagPOINTFX { + FIXED x; + FIXED y; + } POINTFX,*LPPOINTFX; + + typedef struct tagTTPOLYCURVE { + WORD wType; + WORD cpfx; + POINTFX apfx[1]; + } TTPOLYCURVE,*LPTTPOLYCURVE; + + typedef struct tagTTPOLYGONHEADER { + DWORD cb; + DWORD dwType; + POINTFX pfxStart; + } TTPOLYGONHEADER,*LPTTPOLYGONHEADER; + +#define GCP_DBCS 0x0001 +#define GCP_REORDER 0x0002 +#define GCP_USEKERNING 0x0008 +#define GCP_GLYPHSHAPE 0x0010 +#define GCP_LIGATE 0x0020 + +#define GCP_DIACRITIC 0x0100 +#define GCP_KASHIDA 0x0400 +#define GCP_ERROR 0x8000 +#define FLI_MASK 0x103B + +#define GCP_JUSTIFY 0x00010000L + +#define FLI_GLYPHS 0x00040000L +#define GCP_CLASSIN 0x00080000L +#define GCP_MAXEXTENT 0x00100000L +#define GCP_JUSTIFYIN 0x00200000L +#define GCP_DISPLAYZWG 0x00400000L +#define GCP_SYMSWAPOFF 0x00800000L +#define GCP_NUMERICOVERRIDE 0x01000000L +#define GCP_NEUTRALOVERRIDE 0x02000000L +#define GCP_NUMERICSLATIN 0x04000000L +#define GCP_NUMERICSLOCAL 0x08000000L + +#define GCPCLASS_LATIN 1 +#define GCPCLASS_HEBREW 2 +#define GCPCLASS_ARABIC 2 +#define GCPCLASS_NEUTRAL 3 +#define GCPCLASS_LOCALNUMBER 4 +#define GCPCLASS_LATINNUMBER 5 +#define GCPCLASS_LATINNUMERICTERMINATOR 6 +#define GCPCLASS_LATINNUMERICSEPARATOR 7 +#define GCPCLASS_NUMERICSEPARATOR 8 +#define GCPCLASS_PREBOUNDLTR 0x80 +#define GCPCLASS_PREBOUNDRTL 0x40 +#define GCPCLASS_POSTBOUNDLTR 0x20 +#define GCPCLASS_POSTBOUNDRTL 0x10 + +#define GCPGLYPH_LINKBEFORE 0x8000 +#define GCPGLYPH_LINKAFTER 0x4000 + + typedef struct tagGCP_RESULTSA { + DWORD lStructSize; + LPSTR lpOutString; + UINT *lpOrder; + int *lpDx; + int *lpCaretPos; + LPSTR lpClass; + LPWSTR lpGlyphs; + UINT nGlyphs; + int nMaxFit; + } GCP_RESULTSA,*LPGCP_RESULTSA; + typedef struct tagGCP_RESULTSW { + DWORD lStructSize; + LPWSTR lpOutString; + UINT *lpOrder; + int *lpDx; + int *lpCaretPos; + LPSTR lpClass; + LPWSTR lpGlyphs; + UINT nGlyphs; + int nMaxFit; + } GCP_RESULTSW,*LPGCP_RESULTSW; +#ifdef UNICODE + typedef GCP_RESULTSW GCP_RESULTS; + typedef LPGCP_RESULTSW LPGCP_RESULTS; +#else + typedef GCP_RESULTSA GCP_RESULTS; + typedef LPGCP_RESULTSA LPGCP_RESULTS; +#endif + + typedef struct _RASTERIZER_STATUS { + short nSize; + short wFlags; + short nLanguageID; + } RASTERIZER_STATUS,*LPRASTERIZER_STATUS; + +#define TT_AVAILABLE 0x0001 +#define TT_ENABLED 0x0002 + + typedef struct tagPIXELFORMATDESCRIPTOR { + WORD nSize; + WORD nVersion; + DWORD dwFlags; + BYTE iPixelType; + BYTE cColorBits; + BYTE cRedBits; + BYTE cRedShift; + BYTE cGreenBits; + BYTE cGreenShift; + BYTE cBlueBits; + BYTE cBlueShift; + BYTE cAlphaBits; + BYTE cAlphaShift; + BYTE cAccumBits; + BYTE cAccumRedBits; + BYTE cAccumGreenBits; + BYTE cAccumBlueBits; + BYTE cAccumAlphaBits; + BYTE cDepthBits; + BYTE cStencilBits; + BYTE cAuxBuffers; + BYTE iLayerType; + BYTE bReserved; + DWORD dwLayerMask; + DWORD dwVisibleMask; + DWORD dwDamageMask; + } PIXELFORMATDESCRIPTOR,*PPIXELFORMATDESCRIPTOR,*LPPIXELFORMATDESCRIPTOR; + +#define PFD_TYPE_RGBA 0 +#define PFD_TYPE_COLORINDEX 1 + +#define PFD_MAIN_PLANE 0 +#define PFD_OVERLAY_PLANE 1 +#define PFD_UNDERLAY_PLANE (-1) + +#define PFD_DOUBLEBUFFER 0x00000001 +#define PFD_STEREO 0x00000002 +#define PFD_DRAW_TO_WINDOW 0x00000004 +#define PFD_DRAW_TO_BITMAP 0x00000008 +#define PFD_SUPPORT_GDI 0x00000010 +#define PFD_SUPPORT_OPENGL 0x00000020 +#define PFD_GENERIC_FORMAT 0x00000040 +#define PFD_NEED_PALETTE 0x00000080 +#define PFD_NEED_SYSTEM_PALETTE 0x00000100 +#define PFD_SWAP_EXCHANGE 0x00000200 +#define PFD_SWAP_COPY 0x00000400 +#define PFD_SWAP_LAYER_BUFFERS 0x00000800 +#define PFD_GENERIC_ACCELERATED 0x00001000 +#define PFD_SUPPORT_DIRECTDRAW 0x00002000 + +#define PFD_DEPTH_DONTCARE 0x20000000 +#define PFD_DOUBLEBUFFER_DONTCARE 0x40000000 +#define PFD_STEREO_DONTCARE 0x80000000 + +#ifndef NOTEXTMETRIC + typedef int (CALLBACK *OLDFONTENUMPROCA)(CONST LOGFONTA *,CONST TEXTMETRICA *,DWORD,LPARAM); + typedef int (CALLBACK *OLDFONTENUMPROCW)(CONST LOGFONTW *,CONST TEXTMETRICW *,DWORD,LPARAM); +#ifdef UNICODE +#define OLDFONTENUMPROC OLDFONTENUMPROCW +#else +#define OLDFONTENUMPROC OLDFONTENUMPROCA +#endif +#else + typedef int (CALLBACK *OLDFONTENUMPROCA)(CONST LOGFONTA *,CONST VOID *,DWORD,LPARAM); + typedef int (CALLBACK *OLDFONTENUMPROCW)(CONST LOGFONTW *,CONST VOID *,DWORD,LPARAM); +#ifdef UNICODE +#define OLDFONTENUMPROC OLDFONTENUMPROCW +#else +#define OLDFONTENUMPROC OLDFONTENUMPROCA +#endif +#endif + + typedef OLDFONTENUMPROCA FONTENUMPROCA; + typedef OLDFONTENUMPROCW FONTENUMPROCW; +#ifdef UNICODE + typedef FONTENUMPROCW FONTENUMPROC; +#else + typedef FONTENUMPROCA FONTENUMPROC; +#endif + + typedef int (CALLBACK *GOBJENUMPROC)(LPVOID,LPARAM); + typedef VOID (CALLBACK *LINEDDAPROC)(int,int,LPARAM); + +#ifdef UNICODE +#define AddFontResource AddFontResourceW +#define CopyMetaFile CopyMetaFileW +#define CreateDC CreateDCW +#define CreateFontIndirect CreateFontIndirectW +#define CreateFont CreateFontW +#define CreateIC CreateICW +#define CreateMetaFile CreateMetaFileW +#define CreateScalableFontResource CreateScalableFontResourceW +#else +#define AddFontResource AddFontResourceA +#define CopyMetaFile CopyMetaFileA +#define CreateDC CreateDCA +#define CreateFontIndirect CreateFontIndirectA +#define CreateFont CreateFontA +#define CreateIC CreateICA +#define CreateMetaFile CreateMetaFileA +#define CreateScalableFontResource CreateScalableFontResourceA +#endif + + WINGDIAPI int WINAPI AddFontResourceA(LPCSTR); + WINGDIAPI int WINAPI AddFontResourceW(LPCWSTR); + WINGDIAPI WINBOOL WINAPI AnimatePalette(HPALETTE hPal,UINT iStartIndex,UINT cEntries,CONST PALETTEENTRY *ppe); + WINGDIAPI WINBOOL WINAPI Arc(HDC hdc,int x1,int y1,int x2,int y2,int x3,int y3,int x4,int y4); + WINGDIAPI WINBOOL WINAPI BitBlt(HDC hdc,int x,int y,int cx,int cy,HDC hdcSrc,int x1,int y1,DWORD rop); + WINGDIAPI WINBOOL WINAPI CancelDC(HDC hdc); + WINGDIAPI WINBOOL WINAPI Chord(HDC hdc,int x1,int y1,int x2,int y2,int x3,int y3,int x4,int y4); + WINGDIAPI int WINAPI ChoosePixelFormat(HDC hdc,CONST PIXELFORMATDESCRIPTOR *ppfd); + WINGDIAPI HMETAFILE WINAPI CloseMetaFile(HDC hdc); + WINGDIAPI int WINAPI CombineRgn(HRGN hrgnDst,HRGN hrgnSrc1,HRGN hrgnSrc2,int iMode); + WINGDIAPI HMETAFILE WINAPI CopyMetaFileA(HMETAFILE,LPCSTR); + WINGDIAPI HMETAFILE WINAPI CopyMetaFileW(HMETAFILE,LPCWSTR); + WINGDIAPI HBITMAP WINAPI CreateBitmap(int nWidth,int nHeight,UINT nPlanes,UINT nBitCount,CONST VOID *lpBits); + WINGDIAPI HBITMAP WINAPI CreateBitmapIndirect(CONST BITMAP *pbm); + WINGDIAPI HBRUSH WINAPI CreateBrushIndirect(CONST LOGBRUSH *plbrush); + WINGDIAPI HBITMAP WINAPI CreateCompatibleBitmap(HDC hdc,int cx,int cy); + WINGDIAPI HBITMAP WINAPI CreateDiscardableBitmap(HDC hdc,int cx,int cy); + WINGDIAPI HDC WINAPI CreateCompatibleDC(HDC hdc); + WINGDIAPI HDC WINAPI CreateDCA(LPCSTR pwszDriver,LPCSTR pwszDevice,LPCSTR pszPort,CONST DEVMODEA *pdm); + WINGDIAPI HDC WINAPI CreateDCW(LPCWSTR pwszDriver,LPCWSTR pwszDevice,LPCWSTR pszPort,CONST DEVMODEW *pdm); + WINGDIAPI HBITMAP WINAPI CreateDIBitmap(HDC hdc,CONST BITMAPINFOHEADER *pbmih,DWORD flInit,CONST VOID *pjBits,CONST BITMAPINFO *pbmi,UINT iUsage); + WINGDIAPI HBRUSH WINAPI CreateDIBPatternBrush(HGLOBAL h,UINT iUsage); + WINGDIAPI HBRUSH WINAPI CreateDIBPatternBrushPt(CONST VOID *lpPackedDIB,UINT iUsage); + WINGDIAPI HRGN WINAPI CreateEllipticRgn(int x1,int y1,int x2,int y2); + WINGDIAPI HRGN WINAPI CreateEllipticRgnIndirect(CONST RECT *lprect); + WINGDIAPI HFONT WINAPI CreateFontIndirectA(CONST LOGFONTA *lplf); + WINGDIAPI HFONT WINAPI CreateFontIndirectW(CONST LOGFONTW *lplf); + WINGDIAPI HFONT WINAPI CreateFontA(int cHeight,int cWidth,int cEscapement,int cOrientation,int cWeight,DWORD bItalic,DWORD bUnderline,DWORD bStrikeOut,DWORD iCharSet,DWORD iOutPrecision,DWORD iClipPrecision,DWORD iQuality,DWORD iPitchAndFamily,LPCSTR pszFaceName); + WINGDIAPI HFONT WINAPI CreateFontW(int cHeight,int cWidth,int cEscapement,int cOrientation,int cWeight,DWORD bItalic,DWORD bUnderline,DWORD bStrikeOut,DWORD iCharSet,DWORD iOutPrecision,DWORD iClipPrecision,DWORD iQuality,DWORD iPitchAndFamily,LPCWSTR pszFaceName); + WINGDIAPI HBRUSH WINAPI CreateHatchBrush(int iHatch,COLORREF color); + WINGDIAPI HDC WINAPI CreateICA(LPCSTR pszDriver,LPCSTR pszDevice,LPCSTR pszPort,CONST DEVMODEA *pdm); + WINGDIAPI HDC WINAPI CreateICW(LPCWSTR pszDriver,LPCWSTR pszDevice,LPCWSTR pszPort,CONST DEVMODEW *pdm); + WINGDIAPI HDC WINAPI CreateMetaFileA(LPCSTR pszFile); + WINGDIAPI HDC WINAPI CreateMetaFileW(LPCWSTR pszFile); + WINGDIAPI HPALETTE WINAPI CreatePalette(CONST LOGPALETTE *plpal); + WINGDIAPI HPEN WINAPI CreatePen(int iStyle,int cWidth,COLORREF color); + WINGDIAPI HPEN WINAPI CreatePenIndirect(CONST LOGPEN *plpen); + WINGDIAPI HRGN WINAPI CreatePolyPolygonRgn(CONST POINT *pptl,CONST INT *pc,int cPoly,int iMode); + WINGDIAPI HBRUSH WINAPI CreatePatternBrush(HBITMAP hbm); + WINGDIAPI HRGN WINAPI CreateRectRgn(int x1,int y1,int x2,int y2); + WINGDIAPI HRGN WINAPI CreateRectRgnIndirect(CONST RECT *lprect); + WINGDIAPI HRGN WINAPI CreateRoundRectRgn(int x1,int y1,int x2,int y2,int w,int h); + WINGDIAPI WINBOOL WINAPI CreateScalableFontResourceA(DWORD fdwHidden,LPCSTR lpszFont,LPCSTR lpszFile,LPCSTR lpszPath); + WINGDIAPI WINBOOL WINAPI CreateScalableFontResourceW(DWORD fdwHidden,LPCWSTR lpszFont,LPCWSTR lpszFile,LPCWSTR lpszPath); + WINGDIAPI HBRUSH WINAPI CreateSolidBrush(COLORREF color); + WINGDIAPI WINBOOL WINAPI DeleteDC(HDC hdc); + WINGDIAPI WINBOOL WINAPI DeleteMetaFile(HMETAFILE hmf); + WINGDIAPI WINBOOL WINAPI DeleteObject(HGDIOBJ ho); + WINGDIAPI int WINAPI DescribePixelFormat(HDC hdc,int iPixelFormat,UINT nBytes,LPPIXELFORMATDESCRIPTOR ppfd); + + typedef UINT (CALLBACK *LPFNDEVMODE)(HWND,HMODULE,LPDEVMODE,LPSTR,LPSTR,LPDEVMODE,LPSTR,UINT); + typedef DWORD (CALLBACK *LPFNDEVCAPS)(LPSTR,LPSTR,UINT,LPSTR,LPDEVMODE); + +#define DM_UPDATE 1 +#define DM_COPY 2 +#define DM_PROMPT 4 +#define DM_MODIFY 8 + +#define DM_IN_BUFFER DM_MODIFY +#define DM_IN_PROMPT DM_PROMPT +#define DM_OUT_BUFFER DM_COPY +#define DM_OUT_DEFAULT DM_UPDATE + +#define DC_FIELDS 1 +#define DC_PAPERS 2 +#define DC_PAPERSIZE 3 +#define DC_MINEXTENT 4 +#define DC_MAXEXTENT 5 +#define DC_BINS 6 +#define DC_DUPLEX 7 +#define DC_SIZE 8 +#define DC_EXTRA 9 +#define DC_VERSION 10 +#define DC_DRIVER 11 +#define DC_BINNAMES 12 +#define DC_ENUMRESOLUTIONS 13 +#define DC_FILEDEPENDENCIES 14 +#define DC_TRUETYPE 15 +#define DC_PAPERNAMES 16 +#define DC_ORIENTATION 17 +#define DC_COPIES 18 +#define DC_BINADJUST 19 +#define DC_EMF_COMPLIANT 20 +#define DC_DATATYPE_PRODUCED 21 +#define DC_COLLATE 22 +#define DC_MANUFACTURER 23 +#define DC_MODEL 24 +#define DC_PERSONALITY 25 +#define DC_PRINTRATE 26 +#define DC_PRINTRATEUNIT 27 +#define PRINTRATEUNIT_PPM 1 +#define PRINTRATEUNIT_CPS 2 +#define PRINTRATEUNIT_LPM 3 +#define PRINTRATEUNIT_IPM 4 +#define DC_PRINTERMEM 28 +#define DC_MEDIAREADY 29 +#define DC_STAPLE 30 +#define DC_PRINTRATEPPM 31 +#define DC_COLORDEVICE 32 +#define DC_NUP 33 +#define DC_MEDIATYPENAMES 34 +#define DC_MEDIATYPES 35 + +#define DCTT_BITMAP 0x0000001L +#define DCTT_DOWNLOAD 0x0000002L +#define DCTT_SUBDEV 0x0000004L +#define DCTT_DOWNLOAD_OUTLINE 0x0000008L + +#define DCBA_FACEUPNONE 0x0000 +#define DCBA_FACEUPCENTER 0x0001 +#define DCBA_FACEUPLEFT 0x0002 +#define DCBA_FACEUPRIGHT 0x0003 +#define DCBA_FACEDOWNNONE 0x0100 +#define DCBA_FACEDOWNCENTER 0x0101 +#define DCBA_FACEDOWNLEFT 0x0102 +#define DCBA_FACEDOWNRIGHT 0x0103 + +#ifdef UNICODE +#define DeviceCapabilities DeviceCapabilitiesW +#define EnumFontFamiliesEx EnumFontFamiliesExW +#define EnumFontFamilies EnumFontFamiliesW +#define EnumFonts EnumFontsW +#define GetCharWidth GetCharWidthW +#define GetCharWidth32 GetCharWidth32W +#define GetCharWidthFloat GetCharWidthFloatW +#define GetCharABCWidths GetCharABCWidthsW +#define GetCharABCWidthsFloat GetCharABCWidthsFloatW +#define GetGlyphOutline GetGlyphOutlineW +#define GetMetaFile GetMetaFileW +#else +#define DeviceCapabilities DeviceCapabilitiesA +#define EnumFontFamiliesEx EnumFontFamiliesExA +#define EnumFontFamilies EnumFontFamiliesA +#define EnumFonts EnumFontsA +#define GetCharWidth GetCharWidthA +#define GetCharWidth32 GetCharWidth32A +#define GetCharWidthFloat GetCharWidthFloatA +#define GetCharABCWidths GetCharABCWidthsA +#define GetCharABCWidthsFloat GetCharABCWidthsFloatA +#define GetGlyphOutline GetGlyphOutlineA +#define GetMetaFile GetMetaFileA +#endif + + WINSPOOLAPI int WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort,WORD fwCapability,LPSTR pOutput,CONST DEVMODEA *pDevMode); + WINSPOOLAPI int WINAPI DeviceCapabilitiesW(LPCWSTR pDevice,LPCWSTR pPort,WORD fwCapability,LPWSTR pOutput,CONST DEVMODEW *pDevMode); + WINGDIAPI int WINAPI DrawEscape(HDC hdc,int iEscape,int cjIn,LPCSTR lpIn); + WINGDIAPI WINBOOL WINAPI Ellipse(HDC hdc,int left,int top,int right,int bottom); + WINGDIAPI int WINAPI EnumFontFamiliesExA(HDC hdc,LPLOGFONTA lpLogfont,FONTENUMPROCA lpProc,LPARAM lParam,DWORD dwFlags); + WINGDIAPI int WINAPI EnumFontFamiliesExW(HDC hdc,LPLOGFONTW lpLogfont,FONTENUMPROCW lpProc,LPARAM lParam,DWORD dwFlags); + WINGDIAPI int WINAPI EnumFontFamiliesA(HDC hdc,LPCSTR lpLogfont,FONTENUMPROCA lpProc,LPARAM lParam); + WINGDIAPI int WINAPI EnumFontFamiliesW(HDC hdc,LPCWSTR lpLogfont,FONTENUMPROCW lpProc,LPARAM lParam); + WINGDIAPI int WINAPI EnumFontsA(HDC hdc,LPCSTR lpLogfont,FONTENUMPROCA lpProc,LPARAM lParam); + WINGDIAPI int WINAPI EnumFontsW(HDC hdc,LPCWSTR lpLogfont,FONTENUMPROCW lpProc,LPARAM lParam); + WINGDIAPI int WINAPI EnumObjects(HDC hdc,int nType,GOBJENUMPROC lpFunc,LPARAM lParam); + WINGDIAPI WINBOOL WINAPI EqualRgn(HRGN hrgn1,HRGN hrgn2); + WINGDIAPI int WINAPI Escape(HDC hdc,int iEscape,int cjIn,LPCSTR pvIn,LPVOID pvOut); + WINGDIAPI int WINAPI ExtEscape(HDC hdc,int iEscape,int cjInput,LPCSTR lpInData,int cjOutput,LPSTR lpOutData); + WINGDIAPI int WINAPI ExcludeClipRect(HDC hdc,int left,int top,int right,int bottom); + WINGDIAPI HRGN WINAPI ExtCreateRegion(CONST XFORM *lpx,DWORD nCount,CONST RGNDATA *lpData); + WINGDIAPI WINBOOL WINAPI ExtFloodFill(HDC hdc,int x,int y,COLORREF color,UINT type); + WINGDIAPI WINBOOL WINAPI FillRgn(HDC hdc,HRGN hrgn,HBRUSH hbr); + WINGDIAPI WINBOOL WINAPI FloodFill(HDC hdc,int x,int y,COLORREF color); + WINGDIAPI WINBOOL WINAPI FrameRgn(HDC hdc,HRGN hrgn,HBRUSH hbr,int w,int h); + WINGDIAPI int WINAPI GetROP2(HDC hdc); + WINGDIAPI WINBOOL WINAPI GetAspectRatioFilterEx(HDC hdc,LPSIZE lpsize); + WINGDIAPI COLORREF WINAPI GetBkColor(HDC hdc); + WINGDIAPI COLORREF WINAPI GetDCBrushColor(HDC hdc); + WINGDIAPI COLORREF WINAPI GetDCPenColor(HDC hdc); + WINGDIAPI int WINAPI GetBkMode(HDC hdc); + WINGDIAPI LONG WINAPI GetBitmapBits(HBITMAP hbit,LONG cb,LPVOID lpvBits); + WINGDIAPI WINBOOL WINAPI GetBitmapDimensionEx(HBITMAP hbit,LPSIZE lpsize); + WINGDIAPI UINT WINAPI GetBoundsRect(HDC hdc,LPRECT lprect,UINT flags); + WINGDIAPI WINBOOL WINAPI GetBrushOrgEx(HDC hdc,LPPOINT lppt); + WINGDIAPI WINBOOL WINAPI GetCharWidthA(HDC hdc,UINT iFirst,UINT iLast,LPINT lpBuffer); + WINGDIAPI WINBOOL WINAPI GetCharWidthW(HDC hdc,UINT iFirst,UINT iLast,LPINT lpBuffer); + WINGDIAPI WINBOOL WINAPI GetCharWidth32A(HDC hdc,UINT iFirst,UINT iLast,LPINT lpBuffer); + WINGDIAPI WINBOOL WINAPI GetCharWidth32W(HDC hdc,UINT iFirst,UINT iLast,LPINT lpBuffer); + WINGDIAPI WINBOOL WINAPI GetCharWidthFloatA(HDC hdc,UINT iFirst,UINT iLast,PFLOAT lpBuffer); + WINGDIAPI WINBOOL WINAPI GetCharWidthFloatW(HDC hdc,UINT iFirst,UINT iLast,PFLOAT lpBuffer); + WINGDIAPI WINBOOL WINAPI GetCharABCWidthsA(HDC hdc,UINT wFirst,UINT wLast,LPABC lpABC); + WINGDIAPI WINBOOL WINAPI GetCharABCWidthsW(HDC hdc,UINT wFirst,UINT wLast,LPABC lpABC); + WINGDIAPI WINBOOL WINAPI GetCharABCWidthsFloatA(HDC hdc,UINT iFirst,UINT iLast,LPABCFLOAT lpABC); + WINGDIAPI WINBOOL WINAPI GetCharABCWidthsFloatW(HDC hdc,UINT iFirst,UINT iLast,LPABCFLOAT lpABC); + WINGDIAPI int WINAPI GetClipBox(HDC hdc,LPRECT lprect); + WINGDIAPI int WINAPI GetClipRgn(HDC hdc,HRGN hrgn); + WINGDIAPI int WINAPI GetMetaRgn(HDC hdc,HRGN hrgn); + WINGDIAPI HGDIOBJ WINAPI GetCurrentObject(HDC hdc,UINT type); + WINGDIAPI WINBOOL WINAPI GetCurrentPositionEx(HDC hdc,LPPOINT lppt); + WINGDIAPI int WINAPI GetDeviceCaps(HDC hdc,int index); + WINGDIAPI int WINAPI GetDIBits(HDC hdc,HBITMAP hbm,UINT start,UINT cLines,LPVOID lpvBits,LPBITMAPINFO lpbmi,UINT usage); + WINGDIAPI DWORD WINAPI GetFontData (HDC hdc,DWORD dwTable,DWORD dwOffset,PVOID pvBuffer,DWORD cjBuffer); + WINGDIAPI DWORD WINAPI GetGlyphOutlineA(HDC hdc,UINT uChar,UINT fuFormat,LPGLYPHMETRICS lpgm,DWORD cjBuffer,LPVOID pvBuffer,CONST MAT2 *lpmat2); + WINGDIAPI DWORD WINAPI GetGlyphOutlineW(HDC hdc,UINT uChar,UINT fuFormat,LPGLYPHMETRICS lpgm,DWORD cjBuffer,LPVOID pvBuffer,CONST MAT2 *lpmat2); + WINGDIAPI int WINAPI GetGraphicsMode(HDC hdc); + WINGDIAPI int WINAPI GetMapMode(HDC hdc); + WINGDIAPI UINT WINAPI GetMetaFileBitsEx(HMETAFILE hMF,UINT cbBuffer,LPVOID lpData); + WINGDIAPI HMETAFILE WINAPI GetMetaFileA(LPCSTR lpName); + WINGDIAPI HMETAFILE WINAPI GetMetaFileW(LPCWSTR lpName); + WINGDIAPI COLORREF WINAPI GetNearestColor(HDC hdc,COLORREF color); + WINGDIAPI UINT WINAPI GetNearestPaletteIndex(HPALETTE h,COLORREF color); + WINGDIAPI DWORD WINAPI GetObjectType(HGDIOBJ h); + +#ifndef NOTEXTMETRIC +#ifdef UNICODE +#define GetOutlineTextMetrics GetOutlineTextMetricsW +#else +#define GetOutlineTextMetrics GetOutlineTextMetricsA +#endif + + WINGDIAPI UINT WINAPI GetOutlineTextMetricsA(HDC hdc,UINT cjCopy,LPOUTLINETEXTMETRICA potm); + WINGDIAPI UINT WINAPI GetOutlineTextMetricsW(HDC hdc,UINT cjCopy,LPOUTLINETEXTMETRICW potm); +#endif + +#ifdef UNICODE +#define GetTextExtentPoint GetTextExtentPointW +#define GetTextExtentPoint32 GetTextExtentPoint32W +#define GetTextExtentExPoint GetTextExtentExPointW +#define GetCharacterPlacement GetCharacterPlacementW +#else +#define GetTextExtentPoint GetTextExtentPointA +#define GetTextExtentPoint32 GetTextExtentPoint32A +#define GetTextExtentExPoint GetTextExtentExPointA +#define GetCharacterPlacement GetCharacterPlacementA +#endif + + WINGDIAPI UINT WINAPI GetPaletteEntries(HPALETTE hpal,UINT iStart,UINT cEntries,LPPALETTEENTRY pPalEntries); + WINGDIAPI COLORREF WINAPI GetPixel(HDC hdc,int x,int y); + WINGDIAPI int WINAPI GetPixelFormat(HDC hdc); + WINGDIAPI int WINAPI GetPolyFillMode(HDC hdc); + WINGDIAPI WINBOOL WINAPI GetRasterizerCaps(LPRASTERIZER_STATUS lpraststat,UINT cjBytes); + WINGDIAPI int WINAPI GetRandomRgn (HDC hdc,HRGN hrgn,INT i); + WINGDIAPI DWORD WINAPI GetRegionData(HRGN hrgn,DWORD nCount,LPRGNDATA lpRgnData); + WINGDIAPI int WINAPI GetRgnBox(HRGN hrgn,LPRECT lprc); + WINGDIAPI HGDIOBJ WINAPI GetStockObject(int i); + WINGDIAPI int WINAPI GetStretchBltMode(HDC hdc); + WINGDIAPI UINT WINAPI GetSystemPaletteEntries(HDC hdc,UINT iStart,UINT cEntries,LPPALETTEENTRY pPalEntries); + WINGDIAPI UINT WINAPI GetSystemPaletteUse(HDC hdc); + WINGDIAPI int WINAPI GetTextCharacterExtra(HDC hdc); + WINGDIAPI UINT WINAPI GetTextAlign(HDC hdc); + WINGDIAPI COLORREF WINAPI GetTextColor(HDC hdc); + WINGDIAPI WINBOOL WINAPI GetTextExtentPointA(HDC hdc,LPCSTR lpString,int c,LPSIZE lpsz); + WINGDIAPI WINBOOL WINAPI GetTextExtentPointW(HDC hdc,LPCWSTR lpString,int c,LPSIZE lpsz); + WINGDIAPI WINBOOL WINAPI GetTextExtentPoint32A(HDC hdc,LPCSTR lpString,int c,LPSIZE psizl); + WINGDIAPI WINBOOL WINAPI GetTextExtentPoint32W(HDC hdc,LPCWSTR lpString,int c,LPSIZE psizl); + WINGDIAPI WINBOOL WINAPI GetTextExtentExPointA(HDC hdc,LPCSTR lpszString,int cchString,int nMaxExtent,LPINT lpnFit,LPINT lpnDx,LPSIZE lpSize); + WINGDIAPI WINBOOL WINAPI GetTextExtentExPointW(HDC hdc,LPCWSTR lpszString,int cchString,int nMaxExtent,LPINT lpnFit,LPINT lpnDx,LPSIZE lpSize); + WINGDIAPI int WINAPI GetTextCharset(HDC hdc); + WINGDIAPI int WINAPI GetTextCharsetInfo(HDC hdc,LPFONTSIGNATURE lpSig,DWORD dwFlags); + WINGDIAPI WINBOOL WINAPI TranslateCharsetInfo(DWORD *lpSrc,LPCHARSETINFO lpCs,DWORD dwFlags); + WINGDIAPI DWORD WINAPI GetFontLanguageInfo(HDC hdc); + WINGDIAPI DWORD WINAPI GetCharacterPlacementA(HDC hdc,LPCSTR lpString,int nCount,int nMexExtent,LPGCP_RESULTSA lpResults,DWORD dwFlags); + WINGDIAPI DWORD WINAPI GetCharacterPlacementW(HDC hdc,LPCWSTR lpString,int nCount,int nMexExtent,LPGCP_RESULTSW lpResults,DWORD dwFlags); + + typedef struct tagWCRANGE { + WCHAR wcLow; + USHORT cGlyphs; + } WCRANGE,*PWCRANGE,*LPWCRANGE; + + typedef struct tagGLYPHSET { + DWORD cbThis; + DWORD flAccel; + DWORD cGlyphsSupported; + DWORD cRanges; + WCRANGE ranges[1]; + } GLYPHSET,*PGLYPHSET,*LPGLYPHSET; + +#define GS_8BIT_INDICES 0x00000001 + +#define GGI_MARK_NONEXISTING_GLYPHS 0X0001 + +#ifdef UNICODE +#define GetGlyphIndices GetGlyphIndicesW +#else +#define GetGlyphIndices GetGlyphIndicesA +#endif + + WINGDIAPI DWORD WINAPI GetFontUnicodeRanges(HDC hdc,LPGLYPHSET lpgs); + WINGDIAPI DWORD WINAPI GetGlyphIndicesA(HDC hdc,LPCSTR lpstr,int c,LPWORD pgi,DWORD fl); + WINGDIAPI DWORD WINAPI GetGlyphIndicesW(HDC hdc,LPCWSTR lpstr,int c,LPWORD pgi,DWORD fl); + WINGDIAPI WINBOOL WINAPI GetTextExtentPointI(HDC hdc,LPWORD pgiIn,int cgi,LPSIZE psize); + WINGDIAPI WINBOOL WINAPI GetTextExtentExPointI (HDC hdc,LPWORD lpwszString,int cwchString,int nMaxExtent,LPINT lpnFit,LPINT lpnDx,LPSIZE lpSize); + WINGDIAPI WINBOOL WINAPI GetCharWidthI(HDC hdc,UINT giFirst,UINT cgi,LPWORD pgi,LPINT piWidths); + WINGDIAPI WINBOOL WINAPI GetCharABCWidthsI(HDC hdc,UINT giFirst,UINT cgi,LPWORD pgi,LPABC pabc); + +#define STAMP_DESIGNVECTOR (0x8000000 + 'd' + ('v' << 8)) +#define STAMP_AXESLIST (0x8000000 + 'a' + ('l' << 8)) +#define MM_MAX_NUMAXES 16 + + typedef struct tagDESIGNVECTOR { + DWORD dvReserved; + DWORD dvNumAxes; + LONG dvValues[MM_MAX_NUMAXES]; + } DESIGNVECTOR,*PDESIGNVECTOR,*LPDESIGNVECTOR; + +#ifdef UNICODE +#define AddFontResourceEx AddFontResourceExW +#define RemoveFontResourceEx RemoveFontResourceExW +#else +#define AddFontResourceEx AddFontResourceExA +#define RemoveFontResourceEx RemoveFontResourceExA +#endif + + WINGDIAPI int WINAPI AddFontResourceExA(LPCSTR name,DWORD fl,PVOID res); + WINGDIAPI int WINAPI AddFontResourceExW(LPCWSTR name,DWORD fl,PVOID res); + WINGDIAPI WINBOOL WINAPI RemoveFontResourceExA(LPCSTR name,DWORD fl,PVOID pdv); + WINGDIAPI WINBOOL WINAPI RemoveFontResourceExW(LPCWSTR name,DWORD fl,PVOID pdv); + WINGDIAPI HANDLE WINAPI AddFontMemResourceEx(PVOID pFileView,DWORD cjSize,PVOID pvResrved,DWORD *pNumFonts); + WINGDIAPI WINBOOL WINAPI RemoveFontMemResourceEx(HANDLE h); + +#define FR_PRIVATE 0x10 +#define FR_NOT_ENUM 0x20 + +#define MM_MAX_AXES_NAMELEN 16 + + typedef struct tagAXISINFOA { + LONG axMinValue; + LONG axMaxValue; + BYTE axAxisName[MM_MAX_AXES_NAMELEN]; + } AXISINFOA,*PAXISINFOA,*LPAXISINFOA; + + typedef struct tagAXISINFOW { + LONG axMinValue; + LONG axMaxValue; + WCHAR axAxisName[MM_MAX_AXES_NAMELEN]; + } AXISINFOW,*PAXISINFOW,*LPAXISINFOW; +#ifdef UNICODE + typedef AXISINFOW AXISINFO; + typedef PAXISINFOW PAXISINFO; + typedef LPAXISINFOW LPAXISINFO; +#else + typedef AXISINFOA AXISINFO; + typedef PAXISINFOA PAXISINFO; + typedef LPAXISINFOA LPAXISINFO; +#endif + + typedef struct tagAXESLISTA { + DWORD axlReserved; + DWORD axlNumAxes; + AXISINFOA axlAxisInfo[MM_MAX_NUMAXES]; + } AXESLISTA,*PAXESLISTA,*LPAXESLISTA; + + typedef struct tagAXESLISTW { + DWORD axlReserved; + DWORD axlNumAxes; + AXISINFOW axlAxisInfo[MM_MAX_NUMAXES]; + } AXESLISTW,*PAXESLISTW,*LPAXESLISTW; +#ifdef UNICODE + typedef AXESLISTW AXESLIST; + typedef PAXESLISTW PAXESLIST; + typedef LPAXESLISTW LPAXESLIST; +#else + typedef AXESLISTA AXESLIST; + typedef PAXESLISTA PAXESLIST; + typedef LPAXESLISTA LPAXESLIST; +#endif + + typedef struct tagENUMLOGFONTEXDVA { + ENUMLOGFONTEXA elfEnumLogfontEx; + DESIGNVECTOR elfDesignVector; + } ENUMLOGFONTEXDVA,*PENUMLOGFONTEXDVA,*LPENUMLOGFONTEXDVA; + + typedef struct tagENUMLOGFONTEXDVW { + ENUMLOGFONTEXW elfEnumLogfontEx; + DESIGNVECTOR elfDesignVector; + } ENUMLOGFONTEXDVW,*PENUMLOGFONTEXDVW,*LPENUMLOGFONTEXDVW; +#ifdef UNICODE + typedef ENUMLOGFONTEXDVW ENUMLOGFONTEXDV; + typedef PENUMLOGFONTEXDVW PENUMLOGFONTEXDV; + typedef LPENUMLOGFONTEXDVW LPENUMLOGFONTEXDV; +#else + typedef ENUMLOGFONTEXDVA ENUMLOGFONTEXDV; + typedef PENUMLOGFONTEXDVA PENUMLOGFONTEXDV; + typedef LPENUMLOGFONTEXDVA LPENUMLOGFONTEXDV; +#endif + +#ifdef UNICODE +#define CreateFontIndirectEx CreateFontIndirectExW +#else +#define CreateFontIndirectEx CreateFontIndirectExA +#endif + + WINGDIAPI HFONT WINAPI CreateFontIndirectExA(CONST ENUMLOGFONTEXDVA *); + WINGDIAPI HFONT WINAPI CreateFontIndirectExW(CONST ENUMLOGFONTEXDVW *); + +#ifndef NOTEXTMETRIC + typedef struct tagENUMTEXTMETRICA { + NEWTEXTMETRICEXA etmNewTextMetricEx; + AXESLISTA etmAxesList; + } ENUMTEXTMETRICA,*PENUMTEXTMETRICA,*LPENUMTEXTMETRICA; + typedef struct tagENUMTEXTMETRICW + { + NEWTEXTMETRICEXW etmNewTextMetricEx; + AXESLISTW etmAxesList; + } ENUMTEXTMETRICW,*PENUMTEXTMETRICW,*LPENUMTEXTMETRICW; +#ifdef UNICODE + typedef ENUMTEXTMETRICW ENUMTEXTMETRIC; + typedef PENUMTEXTMETRICW PENUMTEXTMETRIC; + typedef LPENUMTEXTMETRICW LPENUMTEXTMETRIC; +#else + typedef ENUMTEXTMETRICA ENUMTEXTMETRIC; + typedef PENUMTEXTMETRICA PENUMTEXTMETRIC; + typedef LPENUMTEXTMETRICA LPENUMTEXTMETRIC; +#endif +#endif + +#ifdef UNICODE +#define ResetDC ResetDCW +#define RemoveFontResource RemoveFontResourceW +#else +#define ResetDC ResetDCA +#define RemoveFontResource RemoveFontResourceA +#endif + + WINGDIAPI WINBOOL WINAPI GetViewportExtEx(HDC hdc,LPSIZE lpsize); + WINGDIAPI WINBOOL WINAPI GetViewportOrgEx(HDC hdc,LPPOINT lppoint); + WINGDIAPI WINBOOL WINAPI GetWindowExtEx(HDC hdc,LPSIZE lpsize); + WINGDIAPI WINBOOL WINAPI GetWindowOrgEx(HDC hdc,LPPOINT lppoint); + WINGDIAPI int WINAPI IntersectClipRect(HDC hdc,int left,int top,int right,int bottom); + WINGDIAPI WINBOOL WINAPI InvertRgn(HDC hdc,HRGN hrgn); + WINGDIAPI WINBOOL WINAPI LineDDA(int xStart,int yStart,int xEnd,int yEnd,LINEDDAPROC lpProc,LPARAM data); + WINGDIAPI WINBOOL WINAPI LineTo(HDC hdc,int x,int y); + WINGDIAPI WINBOOL WINAPI MaskBlt(HDC hdcDest,int xDest,int yDest,int width,int height,HDC hdcSrc,int xSrc,int ySrc,HBITMAP hbmMask,int xMask,int yMask,DWORD rop); + WINGDIAPI WINBOOL WINAPI PlgBlt(HDC hdcDest,CONST POINT *lpPoint,HDC hdcSrc,int xSrc,int ySrc,int width,int height,HBITMAP hbmMask,int xMask,int yMask); + WINGDIAPI int WINAPI OffsetClipRgn(HDC hdc,int x,int y); + WINGDIAPI int WINAPI OffsetRgn(HRGN hrgn,int x,int y); + WINGDIAPI WINBOOL WINAPI PatBlt(HDC hdc,int x,int y,int w,int h,DWORD rop); + WINGDIAPI WINBOOL WINAPI Pie(HDC hdc,int left,int top,int right,int bottom,int xr1,int yr1,int xr2,int yr2); + WINGDIAPI WINBOOL WINAPI PlayMetaFile(HDC hdc,HMETAFILE hmf); + WINGDIAPI WINBOOL WINAPI PaintRgn(HDC hdc,HRGN hrgn); + WINGDIAPI WINBOOL WINAPI PolyPolygon(HDC hdc,CONST POINT *apt,CONST INT *asz,int csz); + WINGDIAPI WINBOOL WINAPI PtInRegion(HRGN hrgn,int x,int y); + WINGDIAPI WINBOOL WINAPI PtVisible(HDC hdc,int x,int y); + WINGDIAPI WINBOOL WINAPI RectInRegion(HRGN hrgn,CONST RECT *lprect); + WINGDIAPI WINBOOL WINAPI RectVisible(HDC hdc,CONST RECT *lprect); + WINGDIAPI WINBOOL WINAPI Rectangle(HDC hdc,int left,int top,int right,int bottom); + WINGDIAPI WINBOOL WINAPI RestoreDC(HDC hdc,int nSavedDC); + WINGDIAPI HDC WINAPI ResetDCA(HDC hdc,CONST DEVMODEA *lpdm); + WINGDIAPI HDC WINAPI ResetDCW(HDC hdc,CONST DEVMODEW *lpdm); + WINGDIAPI UINT WINAPI RealizePalette(HDC hdc); + WINGDIAPI WINBOOL WINAPI RemoveFontResourceA(LPCSTR lpFileName); + WINGDIAPI WINBOOL WINAPI RemoveFontResourceW(LPCWSTR lpFileName); + WINGDIAPI WINBOOL WINAPI RoundRect(HDC hdc,int left,int top,int right,int bottom,int width,int height); + WINGDIAPI WINBOOL WINAPI ResizePalette(HPALETTE hpal,UINT n); + WINGDIAPI int WINAPI SaveDC(HDC hdc); + WINGDIAPI int WINAPI SelectClipRgn(HDC hdc,HRGN hrgn); + WINGDIAPI int WINAPI ExtSelectClipRgn(HDC hdc,HRGN hrgn,int mode); + WINGDIAPI int WINAPI SetMetaRgn(HDC hdc); + WINGDIAPI HGDIOBJ WINAPI SelectObject(HDC hdc,HGDIOBJ h); + WINGDIAPI HPALETTE WINAPI SelectPalette(HDC hdc,HPALETTE hPal,WINBOOL bForceBkgd); + WINGDIAPI COLORREF WINAPI SetBkColor(HDC hdc,COLORREF color); + WINGDIAPI COLORREF WINAPI SetDCBrushColor(HDC hdc,COLORREF color); + WINGDIAPI COLORREF WINAPI SetDCPenColor(HDC hdc,COLORREF color); + WINGDIAPI int WINAPI SetBkMode(HDC hdc,int mode); + WINGDIAPI LONG WINAPI SetBitmapBits(HBITMAP hbm,DWORD cb,CONST VOID *pvBits); + WINGDIAPI UINT WINAPI SetBoundsRect(HDC hdc,CONST RECT *lprect,UINT flags); + WINGDIAPI int WINAPI SetDIBits(HDC hdc,HBITMAP hbm,UINT start,UINT cLines,CONST VOID *lpBits,CONST BITMAPINFO *lpbmi,UINT ColorUse); + WINGDIAPI int WINAPI SetDIBitsToDevice(HDC hdc,int xDest,int yDest,DWORD w,DWORD h,int xSrc,int ySrc,UINT StartScan,UINT cLines,CONST VOID *lpvBits,CONST BITMAPINFO *lpbmi,UINT ColorUse); + WINGDIAPI DWORD WINAPI SetMapperFlags(HDC hdc,DWORD flags); + WINGDIAPI int WINAPI SetGraphicsMode(HDC hdc,int iMode); + WINGDIAPI int WINAPI SetMapMode(HDC hdc,int iMode); + WINGDIAPI DWORD WINAPI SetLayout(HDC hdc,DWORD l); + WINGDIAPI DWORD WINAPI GetLayout(HDC hdc); + WINGDIAPI HMETAFILE WINAPI SetMetaFileBitsEx(UINT cbBuffer,CONST BYTE *lpData); + WINGDIAPI UINT WINAPI SetPaletteEntries(HPALETTE hpal,UINT iStart,UINT cEntries,CONST PALETTEENTRY *pPalEntries); + WINGDIAPI COLORREF WINAPI SetPixel(HDC hdc,int x,int y,COLORREF color); + WINGDIAPI WINBOOL WINAPI SetPixelV(HDC hdc,int x,int y,COLORREF color); + WINGDIAPI WINBOOL WINAPI SetPixelFormat(HDC hdc,int format,CONST PIXELFORMATDESCRIPTOR *ppfd); + WINGDIAPI int WINAPI SetPolyFillMode(HDC hdc,int mode); + WINGDIAPI WINBOOL WINAPI StretchBlt(HDC hdcDest,int xDest,int yDest,int wDest,int hDest,HDC hdcSrc,int xSrc,int ySrc,int wSrc,int hSrc,DWORD rop); + WINGDIAPI WINBOOL WINAPI SetRectRgn(HRGN hrgn,int left,int top,int right,int bottom); + WINGDIAPI int WINAPI StretchDIBits(HDC hdc,int xDest,int yDest,int DestWidth,int DestHeight,int xSrc,int ySrc,int SrcWidth,int SrcHeight,CONST VOID *lpBits,CONST BITMAPINFO *lpbmi,UINT iUsage,DWORD rop); + WINGDIAPI int WINAPI SetROP2(HDC hdc,int rop2); + WINGDIAPI int WINAPI SetStretchBltMode(HDC hdc,int mode); + WINGDIAPI UINT WINAPI SetSystemPaletteUse(HDC hdc,UINT use); + WINGDIAPI int WINAPI SetTextCharacterExtra(HDC hdc,int extra); + WINGDIAPI COLORREF WINAPI SetTextColor(HDC hdc,COLORREF color); + WINGDIAPI UINT WINAPI SetTextAlign(HDC hdc,UINT align); + WINGDIAPI WINBOOL WINAPI SetTextJustification(HDC hdc,int extra,int count); + WINGDIAPI WINBOOL WINAPI UpdateColors(HDC hdc); + + typedef USHORT COLOR16; + + typedef struct _TRIVERTEX { + LONG x; + LONG y; + COLOR16 Red; + COLOR16 Green; + COLOR16 Blue; + COLOR16 Alpha; + } TRIVERTEX,*PTRIVERTEX,*LPTRIVERTEX; + + typedef struct _GRADIENT_TRIANGLE { + ULONG Vertex1; + ULONG Vertex2; + ULONG Vertex3; + } GRADIENT_TRIANGLE,*PGRADIENT_TRIANGLE,*LPGRADIENT_TRIANGLE; + + typedef struct _GRADIENT_RECT { + ULONG UpperLeft; + ULONG LowerRight; + } GRADIENT_RECT,*PGRADIENT_RECT,*LPGRADIENT_RECT; + + typedef struct _BLENDFUNCTION { + BYTE BlendOp; + BYTE BlendFlags; + BYTE SourceConstantAlpha; + BYTE AlphaFormat; + } BLENDFUNCTION,*PBLENDFUNCTION; + +#define AC_SRC_OVER 0x00 +#define AC_SRC_ALPHA 0x01 + + WINGDIAPI WINBOOL WINAPI AlphaBlend(HDC hdcDest,int xoriginDest,int yoriginDest,int wDest,int hDest,HDC hdcSrc,int xoriginSrc,int yoriginSrc,int wSrc,int hSrc,BLENDFUNCTION ftn); + WINGDIAPI WINBOOL WINAPI TransparentBlt(HDC hdcDest,int xoriginDest,int yoriginDest,int wDest,int hDest,HDC hdcSrc,int xoriginSrc,int yoriginSrc,int wSrc,int hSrc,UINT crTransparent); + +#define GRADIENT_FILL_RECT_H 0x00000000 +#define GRADIENT_FILL_RECT_V 0x00000001 +#define GRADIENT_FILL_TRIANGLE 0x00000002 +#define GRADIENT_FILL_OP_FLAG 0x000000ff + + WINGDIAPI WINBOOL WINAPI GradientFill(HDC hdc,PTRIVERTEX pVertex,ULONG nVertex,PVOID pMesh,ULONG nMesh,ULONG ulMode); + +#ifndef NOMETAFILE + +#ifdef UNICODE +#define CopyEnhMetaFile CopyEnhMetaFileW +#define CreateEnhMetaFile CreateEnhMetaFileW +#define GetEnhMetaFile GetEnhMetaFileW +#define GetEnhMetaFileDescription GetEnhMetaFileDescriptionW +#else +#define CopyEnhMetaFile CopyEnhMetaFileA +#define CreateEnhMetaFile CreateEnhMetaFileA +#define GetEnhMetaFile GetEnhMetaFileA +#define GetEnhMetaFileDescription GetEnhMetaFileDescriptionA +#endif + + WINGDIAPI WINBOOL WINAPI PlayMetaFileRecord(HDC hdc,LPHANDLETABLE lpHandleTable,LPMETARECORD lpMR,UINT noObjs); + + typedef int (CALLBACK *MFENUMPROC)(HDC hdc,HANDLETABLE *lpht,METARECORD *lpMR,int nObj,LPARAM param); + + WINGDIAPI WINBOOL WINAPI EnumMetaFile(HDC hdc,HMETAFILE hmf,MFENUMPROC proc,LPARAM param); + + typedef int (CALLBACK *ENHMFENUMPROC)(HDC hdc,HANDLETABLE *lpht,CONST ENHMETARECORD *lpmr,int hHandles,LPARAM data); + + WINGDIAPI HENHMETAFILE WINAPI CloseEnhMetaFile(HDC hdc); + WINGDIAPI HENHMETAFILE WINAPI CopyEnhMetaFileA(HENHMETAFILE hEnh,LPCSTR lpFileName); + WINGDIAPI HENHMETAFILE WINAPI CopyEnhMetaFileW(HENHMETAFILE hEnh,LPCWSTR lpFileName); + WINGDIAPI HDC WINAPI CreateEnhMetaFileA(HDC hdc,LPCSTR lpFilename,CONST RECT *lprc,LPCSTR lpDesc); + WINGDIAPI HDC WINAPI CreateEnhMetaFileW(HDC hdc,LPCWSTR lpFilename,CONST RECT *lprc,LPCWSTR lpDesc); + WINGDIAPI WINBOOL WINAPI DeleteEnhMetaFile(HENHMETAFILE hmf); + WINGDIAPI WINBOOL WINAPI EnumEnhMetaFile(HDC hdc,HENHMETAFILE hmf,ENHMFENUMPROC proc,LPVOID param,CONST RECT *lpRect); + WINGDIAPI HENHMETAFILE WINAPI GetEnhMetaFileA(LPCSTR lpName); + WINGDIAPI HENHMETAFILE WINAPI GetEnhMetaFileW(LPCWSTR lpName); + WINGDIAPI UINT WINAPI GetEnhMetaFileBits(HENHMETAFILE hEMF,UINT nSize,LPBYTE lpData); + WINGDIAPI UINT WINAPI GetEnhMetaFileDescriptionA(HENHMETAFILE hemf,UINT cchBuffer,LPSTR lpDescription); + WINGDIAPI UINT WINAPI GetEnhMetaFileDescriptionW(HENHMETAFILE hemf,UINT cchBuffer,LPWSTR lpDescription); + WINGDIAPI UINT WINAPI GetEnhMetaFileHeader(HENHMETAFILE hemf,UINT nSize,LPENHMETAHEADER lpEnhMetaHeader); + WINGDIAPI UINT WINAPI GetEnhMetaFilePaletteEntries(HENHMETAFILE hemf,UINT nNumEntries,LPPALETTEENTRY lpPaletteEntries); + WINGDIAPI UINT WINAPI GetEnhMetaFilePixelFormat(HENHMETAFILE hemf,UINT cbBuffer,PIXELFORMATDESCRIPTOR *ppfd); + WINGDIAPI UINT WINAPI GetWinMetaFileBits(HENHMETAFILE hemf,UINT cbData16,LPBYTE pData16,INT iMapMode,HDC hdcRef); + WINGDIAPI WINBOOL WINAPI PlayEnhMetaFile(HDC hdc,HENHMETAFILE hmf,CONST RECT *lprect); + WINGDIAPI WINBOOL WINAPI PlayEnhMetaFileRecord(HDC hdc,LPHANDLETABLE pht,CONST ENHMETARECORD *pmr,UINT cht); + WINGDIAPI HENHMETAFILE WINAPI SetEnhMetaFileBits(UINT nSize,CONST BYTE *pb); + WINGDIAPI HENHMETAFILE WINAPI SetWinMetaFileBits(UINT nSize,CONST BYTE *lpMeta16Data,HDC hdcRef,CONST METAFILEPICT *lpMFP); + WINGDIAPI WINBOOL WINAPI GdiComment(HDC hdc,UINT nSize,CONST BYTE *lpData); +#endif + +#ifndef NOTEXTMETRIC +#ifdef UNICODE +#define GetTextMetrics GetTextMetricsW +#else +#define GetTextMetrics GetTextMetricsA +#endif + + WINGDIAPI WINBOOL WINAPI GetTextMetricsA(HDC hdc,LPTEXTMETRICA lptm); + WINGDIAPI WINBOOL WINAPI GetTextMetricsW(HDC hdc,LPTEXTMETRICW lptm); +#endif + + typedef struct tagDIBSECTION { + BITMAP dsBm; + BITMAPINFOHEADER dsBmih; + DWORD dsBitfields[3]; + HANDLE dshSection; + DWORD dsOffset; + } DIBSECTION,*LPDIBSECTION,*PDIBSECTION; + + WINGDIAPI WINBOOL WINAPI AngleArc(HDC hdc,int x,int y,DWORD r,FLOAT StartAngle,FLOAT SweepAngle); + WINGDIAPI WINBOOL WINAPI PolyPolyline(HDC hdc,CONST POINT *apt,CONST DWORD *asz,DWORD csz); + WINGDIAPI WINBOOL WINAPI GetWorldTransform(HDC hdc,LPXFORM lpxf); + WINGDIAPI WINBOOL WINAPI SetWorldTransform(HDC hdc,CONST XFORM *lpxf); + WINGDIAPI WINBOOL WINAPI ModifyWorldTransform(HDC hdc,CONST XFORM *lpxf,DWORD mode); + WINGDIAPI WINBOOL WINAPI CombineTransform(LPXFORM lpxfOut,CONST XFORM *lpxf1,CONST XFORM *lpxf2); + WINGDIAPI HBITMAP WINAPI CreateDIBSection(HDC hdc,CONST BITMAPINFO *lpbmi,UINT usage,VOID **ppvBits,HANDLE hSection,DWORD offset); + WINGDIAPI UINT WINAPI GetDIBColorTable(HDC hdc,UINT iStart,UINT cEntries,RGBQUAD *prgbq); + WINGDIAPI UINT WINAPI SetDIBColorTable(HDC hdc,UINT iStart,UINT cEntries,CONST RGBQUAD *prgbq); + +#define CA_NEGATIVE 0x0001 +#define CA_LOG_FILTER 0x0002 + +#define ILLUMINANT_DEVICE_DEFAULT 0 +#define ILLUMINANT_A 1 +#define ILLUMINANT_B 2 +#define ILLUMINANT_C 3 +#define ILLUMINANT_D50 4 +#define ILLUMINANT_D55 5 +#define ILLUMINANT_D65 6 +#define ILLUMINANT_D75 7 +#define ILLUMINANT_F2 8 +#define ILLUMINANT_MAX_INDEX ILLUMINANT_F2 + +#define ILLUMINANT_TUNGSTEN ILLUMINANT_A +#define ILLUMINANT_DAYLIGHT ILLUMINANT_C +#define ILLUMINANT_FLUORESCENT ILLUMINANT_F2 +#define ILLUMINANT_NTSC ILLUMINANT_C + +#define RGB_GAMMA_MIN (WORD)02500 +#define RGB_GAMMA_MAX (WORD)65000 + +#define REFERENCE_WHITE_MIN (WORD)6000 +#define REFERENCE_WHITE_MAX (WORD)10000 +#define REFERENCE_BLACK_MIN (WORD)0 +#define REFERENCE_BLACK_MAX (WORD)4000 + +#define COLOR_ADJ_MIN (SHORT)-100 +#define COLOR_ADJ_MAX (SHORT)100 + + typedef struct tagCOLORADJUSTMENT { + WORD caSize; + WORD caFlags; + WORD caIlluminantIndex; + WORD caRedGamma; + WORD caGreenGamma; + WORD caBlueGamma; + WORD caReferenceBlack; + WORD caReferenceWhite; + SHORT caContrast; + SHORT caBrightness; + SHORT caColorfulness; + SHORT caRedGreenTint; + } COLORADJUSTMENT,*PCOLORADJUSTMENT,*LPCOLORADJUSTMENT; + + WINGDIAPI WINBOOL WINAPI SetColorAdjustment(HDC hdc,CONST COLORADJUSTMENT *lpca); + WINGDIAPI WINBOOL WINAPI GetColorAdjustment(HDC hdc,LPCOLORADJUSTMENT lpca); + WINGDIAPI HPALETTE WINAPI CreateHalftonePalette(HDC hdc); + + typedef WINBOOL (CALLBACK *ABORTPROC)(HDC,int); + + typedef struct _DOCINFOA { + int cbSize; + LPCSTR lpszDocName; + LPCSTR lpszOutput; + LPCSTR lpszDatatype; + DWORD fwType; + } DOCINFOA,*LPDOCINFOA; + + typedef struct _DOCINFOW { + int cbSize; + LPCWSTR lpszDocName; + LPCWSTR lpszOutput; + LPCWSTR lpszDatatype; + DWORD fwType; + } DOCINFOW,*LPDOCINFOW; + +#ifdef UNICODE + typedef DOCINFOW DOCINFO; + typedef LPDOCINFOW LPDOCINFO; +#else + typedef DOCINFOA DOCINFO; + typedef LPDOCINFOA LPDOCINFO; +#endif + +#define DI_APPBANDING 0x00000001 +#define DI_ROPS_READ_DESTINATION 0x00000002 + +#ifdef UNICODE +#define StartDoc StartDocW +#define GetObject GetObjectW +#define TextOut TextOutW +#define ExtTextOut ExtTextOutW +#define PolyTextOut PolyTextOutW +#define GetTextFace GetTextFaceW +#else +#define StartDoc StartDocA +#define GetObject GetObjectA +#define TextOut TextOutA +#define ExtTextOut ExtTextOutA +#define PolyTextOut PolyTextOutA +#define GetTextFace GetTextFaceA +#endif + + WINGDIAPI int WINAPI StartDocA(HDC hdc,CONST DOCINFOA *lpdi); + WINGDIAPI int WINAPI StartDocW(HDC hdc,CONST DOCINFOW *lpdi); + WINGDIAPI int WINAPI EndDoc(HDC hdc); + WINGDIAPI int WINAPI StartPage(HDC hdc); + WINGDIAPI int WINAPI EndPage(HDC hdc); + WINGDIAPI int WINAPI AbortDoc(HDC hdc); + WINGDIAPI int WINAPI SetAbortProc(HDC hdc,ABORTPROC proc); + WINGDIAPI WINBOOL WINAPI AbortPath(HDC hdc); + WINGDIAPI WINBOOL WINAPI ArcTo(HDC hdc,int left,int top,int right,int bottom,int xr1,int yr1,int xr2,int yr2); + WINGDIAPI WINBOOL WINAPI BeginPath(HDC hdc); + WINGDIAPI WINBOOL WINAPI CloseFigure(HDC hdc); + WINGDIAPI WINBOOL WINAPI EndPath(HDC hdc); + WINGDIAPI WINBOOL WINAPI FillPath(HDC hdc); + WINGDIAPI WINBOOL WINAPI FlattenPath(HDC hdc); + WINGDIAPI int WINAPI GetPath(HDC hdc,LPPOINT apt,LPBYTE aj,int cpt); + WINGDIAPI HRGN WINAPI PathToRegion(HDC hdc); + WINGDIAPI WINBOOL WINAPI PolyDraw(HDC hdc,CONST POINT *apt,CONST BYTE *aj,int cpt); + WINGDIAPI WINBOOL WINAPI SelectClipPath(HDC hdc,int mode); + WINGDIAPI int WINAPI SetArcDirection(HDC hdc,int dir); + WINGDIAPI WINBOOL WINAPI SetMiterLimit(HDC hdc,FLOAT limit,PFLOAT old); + WINGDIAPI WINBOOL WINAPI StrokeAndFillPath(HDC hdc); + WINGDIAPI WINBOOL WINAPI StrokePath(HDC hdc); + WINGDIAPI WINBOOL WINAPI WidenPath(HDC hdc); + WINGDIAPI HPEN WINAPI ExtCreatePen(DWORD iPenStyle,DWORD cWidth,CONST LOGBRUSH *plbrush,DWORD cStyle,CONST DWORD *pstyle); + WINGDIAPI WINBOOL WINAPI GetMiterLimit(HDC hdc,PFLOAT plimit); + WINGDIAPI int WINAPI GetArcDirection(HDC hdc); + WINGDIAPI int WINAPI GetObjectA(HANDLE h,int c,LPVOID pv); + WINGDIAPI int WINAPI GetObjectW(HANDLE h,int c,LPVOID pv); + WINGDIAPI WINBOOL WINAPI MoveToEx(HDC hdc,int x,int y,LPPOINT lppt); + WINGDIAPI WINBOOL WINAPI TextOutA(HDC hdc,int x,int y,LPCSTR lpString,int c); + WINGDIAPI WINBOOL WINAPI TextOutW(HDC hdc,int x,int y,LPCWSTR lpString,int c); + WINGDIAPI WINBOOL WINAPI ExtTextOutA(HDC hdc,int x,int y,UINT options,CONST RECT *lprect,LPCSTR lpString,UINT c,CONST INT *lpDx); + WINGDIAPI WINBOOL WINAPI ExtTextOutW(HDC hdc,int x,int y,UINT options,CONST RECT *lprect,LPCWSTR lpString,UINT c,CONST INT *lpDx); + WINGDIAPI WINBOOL WINAPI PolyTextOutA(HDC hdc,CONST POLYTEXTA *ppt,int nstrings); + WINGDIAPI WINBOOL WINAPI PolyTextOutW(HDC hdc,CONST POLYTEXTW *ppt,int nstrings); + WINGDIAPI HRGN WINAPI CreatePolygonRgn(CONST POINT *pptl,int cPoint,int iMode); + WINGDIAPI WINBOOL WINAPI DPtoLP(HDC hdc,LPPOINT lppt,int c); + WINGDIAPI WINBOOL WINAPI LPtoDP(HDC hdc,LPPOINT lppt,int c); + WINGDIAPI WINBOOL WINAPI Polygon(HDC hdc,CONST POINT *apt,int cpt); + WINGDIAPI WINBOOL WINAPI Polyline(HDC hdc,CONST POINT *apt,int cpt); + WINGDIAPI WINBOOL WINAPI PolyBezier(HDC hdc,CONST POINT *apt,DWORD cpt); + WINGDIAPI WINBOOL WINAPI PolyBezierTo(HDC hdc,CONST POINT *apt,DWORD cpt); + WINGDIAPI WINBOOL WINAPI PolylineTo(HDC hdc,CONST POINT *apt,DWORD cpt); + WINGDIAPI WINBOOL WINAPI SetViewportExtEx(HDC hdc,int x,int y,LPSIZE lpsz); + WINGDIAPI WINBOOL WINAPI SetViewportOrgEx(HDC hdc,int x,int y,LPPOINT lppt); + WINGDIAPI WINBOOL WINAPI SetWindowExtEx(HDC hdc,int x,int y,LPSIZE lpsz); + WINGDIAPI WINBOOL WINAPI SetWindowOrgEx(HDC hdc,int x,int y,LPPOINT lppt); + WINGDIAPI WINBOOL WINAPI OffsetViewportOrgEx(HDC hdc,int x,int y,LPPOINT lppt); + WINGDIAPI WINBOOL WINAPI OffsetWindowOrgEx(HDC hdc,int x,int y,LPPOINT lppt); + WINGDIAPI WINBOOL WINAPI ScaleViewportExtEx(HDC hdc,int xn,int dx,int yn,int yd,LPSIZE lpsz); + WINGDIAPI WINBOOL WINAPI ScaleWindowExtEx(HDC hdc,int xn,int xd,int yn,int yd,LPSIZE lpsz); + WINGDIAPI WINBOOL WINAPI SetBitmapDimensionEx(HBITMAP hbm,int w,int h,LPSIZE lpsz); + WINGDIAPI WINBOOL WINAPI SetBrushOrgEx(HDC hdc,int x,int y,LPPOINT lppt); + WINGDIAPI int WINAPI GetTextFaceA(HDC hdc,int c,LPSTR lpName); + WINGDIAPI int WINAPI GetTextFaceW(HDC hdc,int c,LPWSTR lpName); + +#define FONTMAPPER_MAX 10 + + typedef struct tagKERNINGPAIR { + WORD wFirst; + WORD wSecond; + int iKernAmount; + } KERNINGPAIR,*LPKERNINGPAIR; + +#ifdef UNICODE +#define GetKerningPairs GetKerningPairsW +#else +#define GetKerningPairs GetKerningPairsA +#endif + + WINGDIAPI DWORD WINAPI GetKerningPairsA(HDC hdc,DWORD nPairs,LPKERNINGPAIR lpKernPair); + WINGDIAPI DWORD WINAPI GetKerningPairsW(HDC hdc,DWORD nPairs,LPKERNINGPAIR lpKernPair); + WINGDIAPI WINBOOL WINAPI GetDCOrgEx(HDC hdc,LPPOINT lppt); + WINGDIAPI WINBOOL WINAPI FixBrushOrgEx(HDC hdc,int x,int y,LPPOINT ptl); + WINGDIAPI WINBOOL WINAPI UnrealizeObject(HGDIOBJ h); + WINGDIAPI WINBOOL WINAPI GdiFlush(); + WINGDIAPI DWORD WINAPI GdiSetBatchLimit(DWORD dw); + WINGDIAPI DWORD WINAPI GdiGetBatchLimit(); + +#define ICM_OFF 1 +#define ICM_ON 2 +#define ICM_QUERY 3 +#define ICM_DONE_OUTSIDEDC 4 + + typedef int (CALLBACK *ICMENUMPROCA)(LPSTR,LPARAM); + typedef int (CALLBACK *ICMENUMPROCW)(LPWSTR,LPARAM); + +#ifdef UNICODE +#define ICMENUMPROC ICMENUMPROCW +#define EnumICMProfiles EnumICMProfilesW +#define UpdateICMRegKey UpdateICMRegKeyW +#define GetLogColorSpace GetLogColorSpaceW +#define CreateColorSpace CreateColorSpaceW +#define GetICMProfile GetICMProfileW +#define SetICMProfile SetICMProfileW +#else +#define ICMENUMPROC ICMENUMPROCA +#define EnumICMProfiles EnumICMProfilesA +#define UpdateICMRegKey UpdateICMRegKeyA +#define GetLogColorSpace GetLogColorSpaceA +#define CreateColorSpace CreateColorSpaceA +#define GetICMProfile GetICMProfileA +#define SetICMProfile SetICMProfileA +#endif + + WINGDIAPI int WINAPI SetICMMode(HDC hdc,int mode); + WINGDIAPI WINBOOL WINAPI CheckColorsInGamut(HDC hdc,LPVOID lpRGBTriple,LPVOID dlpBuffer,DWORD nCount); + WINGDIAPI HCOLORSPACE WINAPI GetColorSpace(HDC hdc); + WINGDIAPI WINBOOL WINAPI GetLogColorSpaceA(HCOLORSPACE hColorSpace,LPLOGCOLORSPACEA lpBuffer,DWORD nSize); + WINGDIAPI WINBOOL WINAPI GetLogColorSpaceW(HCOLORSPACE hColorSpace,LPLOGCOLORSPACEW lpBuffer,DWORD nSize); + WINGDIAPI HCOLORSPACE WINAPI CreateColorSpaceA(LPLOGCOLORSPACEA lplcs); + WINGDIAPI HCOLORSPACE WINAPI CreateColorSpaceW(LPLOGCOLORSPACEW lplcs); + WINGDIAPI HCOLORSPACE WINAPI SetColorSpace(HDC hdc,HCOLORSPACE hcs); + WINGDIAPI WINBOOL WINAPI DeleteColorSpace(HCOLORSPACE hcs); + WINGDIAPI WINBOOL WINAPI GetICMProfileA(HDC hdc,LPDWORD pBufSize,LPSTR pszFilename); + WINGDIAPI WINBOOL WINAPI GetICMProfileW(HDC hdc,LPDWORD pBufSize,LPWSTR pszFilename); + WINGDIAPI WINBOOL WINAPI SetICMProfileA(HDC hdc,LPSTR lpFileName); + WINGDIAPI WINBOOL WINAPI SetICMProfileW(HDC hdc,LPWSTR lpFileName); + WINGDIAPI WINBOOL WINAPI GetDeviceGammaRamp(HDC hdc,LPVOID lpRamp); + WINGDIAPI WINBOOL WINAPI SetDeviceGammaRamp(HDC hdc,LPVOID lpRamp); + WINGDIAPI WINBOOL WINAPI ColorMatchToTarget(HDC hdc,HDC hdcTarget,DWORD action); + WINGDIAPI int WINAPI EnumICMProfilesA(HDC hdc,ICMENUMPROCA proc,LPARAM param); + WINGDIAPI int WINAPI EnumICMProfilesW(HDC hdc,ICMENUMPROCW proc,LPARAM param); + WINGDIAPI WINBOOL WINAPI UpdateICMRegKeyA(DWORD reserved,LPSTR lpszCMID,LPSTR lpszFileName,UINT command); + WINGDIAPI WINBOOL WINAPI UpdateICMRegKeyW(DWORD reserved,LPWSTR lpszCMID,LPWSTR lpszFileName,UINT command); + WINGDIAPI WINBOOL WINAPI ColorCorrectPalette(HDC hdc,HPALETTE hPal,DWORD deFirst,DWORD num); + +#ifndef NOMETAFILE + +#define ENHMETA_SIGNATURE 0x464D4520 +#define ENHMETA_STOCK_OBJECT 0x80000000 + +#define EMR_HEADER 1 +#define EMR_POLYBEZIER 2 +#define EMR_POLYGON 3 +#define EMR_POLYLINE 4 +#define EMR_POLYBEZIERTO 5 +#define EMR_POLYLINETO 6 +#define EMR_POLYPOLYLINE 7 +#define EMR_POLYPOLYGON 8 +#define EMR_SETWINDOWEXTEX 9 +#define EMR_SETWINDOWORGEX 10 +#define EMR_SETVIEWPORTEXTEX 11 +#define EMR_SETVIEWPORTORGEX 12 +#define EMR_SETBRUSHORGEX 13 +#define EMR_EOF 14 +#define EMR_SETPIXELV 15 +#define EMR_SETMAPPERFLAGS 16 +#define EMR_SETMAPMODE 17 +#define EMR_SETBKMODE 18 +#define EMR_SETPOLYFILLMODE 19 +#define EMR_SETROP2 20 +#define EMR_SETSTRETCHBLTMODE 21 +#define EMR_SETTEXTALIGN 22 +#define EMR_SETCOLORADJUSTMENT 23 +#define EMR_SETTEXTCOLOR 24 +#define EMR_SETBKCOLOR 25 +#define EMR_OFFSETCLIPRGN 26 +#define EMR_MOVETOEX 27 +#define EMR_SETMETARGN 28 +#define EMR_EXCLUDECLIPRECT 29 +#define EMR_INTERSECTCLIPRECT 30 +#define EMR_SCALEVIEWPORTEXTEX 31 +#define EMR_SCALEWINDOWEXTEX 32 +#define EMR_SAVEDC 33 +#define EMR_RESTOREDC 34 +#define EMR_SETWORLDTRANSFORM 35 +#define EMR_MODIFYWORLDTRANSFORM 36 +#define EMR_SELECTOBJECT 37 +#define EMR_CREATEPEN 38 +#define EMR_CREATEBRUSHINDIRECT 39 +#define EMR_DELETEOBJECT 40 +#define EMR_ANGLEARC 41 +#define EMR_ELLIPSE 42 +#define EMR_RECTANGLE 43 +#define EMR_ROUNDRECT 44 +#define EMR_ARC 45 +#define EMR_CHORD 46 +#define EMR_PIE 47 +#define EMR_SELECTPALETTE 48 +#define EMR_CREATEPALETTE 49 +#define EMR_SETPALETTEENTRIES 50 +#define EMR_RESIZEPALETTE 51 +#define EMR_REALIZEPALETTE 52 +#define EMR_EXTFLOODFILL 53 +#define EMR_LINETO 54 +#define EMR_ARCTO 55 +#define EMR_POLYDRAW 56 +#define EMR_SETARCDIRECTION 57 +#define EMR_SETMITERLIMIT 58 +#define EMR_BEGINPATH 59 +#define EMR_ENDPATH 60 +#define EMR_CLOSEFIGURE 61 +#define EMR_FILLPATH 62 +#define EMR_STROKEANDFILLPATH 63 +#define EMR_STROKEPATH 64 +#define EMR_FLATTENPATH 65 +#define EMR_WIDENPATH 66 +#define EMR_SELECTCLIPPATH 67 +#define EMR_ABORTPATH 68 + +#define EMR_GDICOMMENT 70 +#define EMR_FILLRGN 71 +#define EMR_FRAMERGN 72 +#define EMR_INVERTRGN 73 +#define EMR_PAINTRGN 74 +#define EMR_EXTSELECTCLIPRGN 75 +#define EMR_BITBLT 76 +#define EMR_STRETCHBLT 77 +#define EMR_MASKBLT 78 +#define EMR_PLGBLT 79 +#define EMR_SETDIBITSTODEVICE 80 +#define EMR_STRETCHDIBITS 81 +#define EMR_EXTCREATEFONTINDIRECTW 82 +#define EMR_EXTTEXTOUTA 83 +#define EMR_EXTTEXTOUTW 84 +#define EMR_POLYBEZIER16 85 +#define EMR_POLYGON16 86 +#define EMR_POLYLINE16 87 +#define EMR_POLYBEZIERTO16 88 +#define EMR_POLYLINETO16 89 +#define EMR_POLYPOLYLINE16 90 +#define EMR_POLYPOLYGON16 91 +#define EMR_POLYDRAW16 92 +#define EMR_CREATEMONOBRUSH 93 +#define EMR_CREATEDIBPATTERNBRUSHPT 94 +#define EMR_EXTCREATEPEN 95 +#define EMR_POLYTEXTOUTA 96 +#define EMR_POLYTEXTOUTW 97 + +#define EMR_SETICMMODE 98 +#define EMR_CREATECOLORSPACE 99 +#define EMR_SETCOLORSPACE 100 +#define EMR_DELETECOLORSPACE 101 +#define EMR_GLSRECORD 102 +#define EMR_GLSBOUNDEDRECORD 103 +#define EMR_PIXELFORMAT 104 +#define EMR_RESERVED_105 105 +#define EMR_RESERVED_106 106 +#define EMR_RESERVED_107 107 +#define EMR_RESERVED_108 108 +#define EMR_RESERVED_109 109 +#define EMR_RESERVED_110 110 +#define EMR_COLORCORRECTPALETTE 111 +#define EMR_SETICMPROFILEA 112 +#define EMR_SETICMPROFILEW 113 +#define EMR_ALPHABLEND 114 +#define EMR_SETLAYOUT 115 +#define EMR_TRANSPARENTBLT 116 +#define EMR_RESERVED_117 117 +#define EMR_GRADIENTFILL 118 +#define EMR_RESERVED_119 119 +#define EMR_RESERVED_120 120 +#define EMR_COLORMATCHTOTARGETW 121 +#define EMR_CREATECOLORSPACEW 122 + +#define EMR_MIN 1 + +#define EMR_MAX 122 + + typedef struct tagEMR { + DWORD iType; + DWORD nSize; + } EMR,*PEMR; + + typedef struct tagEMRTEXT { + POINTL ptlReference; + DWORD nChars; + DWORD offString; + DWORD fOptions; + RECTL rcl; + DWORD offDx; + } EMRTEXT,*PEMRTEXT; + + typedef struct tagABORTPATH { + EMR emr; + } EMRABORTPATH,*PEMRABORTPATH,EMRBEGINPATH,*PEMRBEGINPATH,EMRENDPATH,*PEMRENDPATH,EMRCLOSEFIGURE,*PEMRCLOSEFIGURE,EMRFLATTENPATH,*PEMRFLATTENPATH,EMRWIDENPATH,*PEMRWIDENPATH,EMRSETMETARGN,*PEMRSETMETARGN,EMRSAVEDC,*PEMRSAVEDC,EMRREALIZEPALETTE,*PEMRREALIZEPALETTE; + + typedef struct tagEMRSELECTCLIPPATH { + EMR emr; + DWORD iMode; + } EMRSELECTCLIPPATH,*PEMRSELECTCLIPPATH,EMRSETBKMODE,*PEMRSETBKMODE,EMRSETMAPMODE,*PEMRSETMAPMODE,EMRSETLAYOUT,*PEMRSETLAYOUT, + EMRSETPOLYFILLMODE,*PEMRSETPOLYFILLMODE,EMRSETROP2,*PEMRSETROP2,EMRSETSTRETCHBLTMODE,*PEMRSETSTRETCHBLTMODE,EMRSETICMMODE, + *PEMRSETICMMODE,EMRSETTEXTALIGN,*PEMRSETTEXTALIGN; + + typedef struct tagEMRSETMITERLIMIT { + EMR emr; + FLOAT eMiterLimit; + } EMRSETMITERLIMIT,*PEMRSETMITERLIMIT; + + typedef struct tagEMRRESTOREDC { + EMR emr; + LONG iRelative; + } EMRRESTOREDC,*PEMRRESTOREDC; + + typedef struct tagEMRSETARCDIRECTION { + EMR emr; + DWORD iArcDirection; + + } EMRSETARCDIRECTION,*PEMRSETARCDIRECTION; + + typedef struct tagEMRSETMAPPERFLAGS { + EMR emr; + DWORD dwFlags; + } EMRSETMAPPERFLAGS,*PEMRSETMAPPERFLAGS; + + typedef struct tagEMRSETTEXTCOLOR { + EMR emr; + COLORREF crColor; + } EMRSETBKCOLOR,*PEMRSETBKCOLOR,EMRSETTEXTCOLOR,*PEMRSETTEXTCOLOR; + + typedef struct tagEMRSELECTOBJECT { + EMR emr; + DWORD ihObject; + } EMRSELECTOBJECT,*PEMRSELECTOBJECT,EMRDELETEOBJECT,*PEMRDELETEOBJECT; + + typedef struct tagEMRSELECTPALETTE { + EMR emr; + DWORD ihPal; + } EMRSELECTPALETTE,*PEMRSELECTPALETTE; + + typedef struct tagEMRRESIZEPALETTE { + EMR emr; + DWORD ihPal; + DWORD cEntries; + } EMRRESIZEPALETTE,*PEMRRESIZEPALETTE; + + typedef struct tagEMRSETPALETTEENTRIES { + EMR emr; + DWORD ihPal; + DWORD iStart; + DWORD cEntries; + PALETTEENTRY aPalEntries[1]; + } EMRSETPALETTEENTRIES,*PEMRSETPALETTEENTRIES; + + typedef struct tagEMRSETCOLORADJUSTMENT { + EMR emr; + COLORADJUSTMENT ColorAdjustment; + } EMRSETCOLORADJUSTMENT,*PEMRSETCOLORADJUSTMENT; + + typedef struct tagEMRGDICOMMENT { + EMR emr; + DWORD cbData; + BYTE Data[1]; + } EMRGDICOMMENT,*PEMRGDICOMMENT; + + typedef struct tagEMREOF { + EMR emr; + DWORD nPalEntries; + DWORD offPalEntries; + DWORD nSizeLast; + } EMREOF,*PEMREOF; + + typedef struct tagEMRLINETO { + EMR emr; + POINTL ptl; + } EMRLINETO,*PEMRLINETO,EMRMOVETOEX,*PEMRMOVETOEX; + + typedef struct tagEMROFFSETCLIPRGN { + EMR emr; + POINTL ptlOffset; + } EMROFFSETCLIPRGN,*PEMROFFSETCLIPRGN; + + typedef struct tagEMRFILLPATH { + EMR emr; + RECTL rclBounds; + } EMRFILLPATH,*PEMRFILLPATH,EMRSTROKEANDFILLPATH,*PEMRSTROKEANDFILLPATH,EMRSTROKEPATH,*PEMRSTROKEPATH; + + typedef struct tagEMREXCLUDECLIPRECT { + EMR emr; + RECTL rclClip; + } EMREXCLUDECLIPRECT,*PEMREXCLUDECLIPRECT,EMRINTERSECTCLIPRECT,*PEMRINTERSECTCLIPRECT; + + typedef struct tagEMRSETVIEWPORTORGEX { + EMR emr; + POINTL ptlOrigin; + } EMRSETVIEWPORTORGEX,*PEMRSETVIEWPORTORGEX,EMRSETWINDOWORGEX,*PEMRSETWINDOWORGEX,EMRSETBRUSHORGEX,*PEMRSETBRUSHORGEX; + + typedef struct tagEMRSETVIEWPORTEXTEX { + EMR emr; + SIZEL szlExtent; + } EMRSETVIEWPORTEXTEX,*PEMRSETVIEWPORTEXTEX,EMRSETWINDOWEXTEX,*PEMRSETWINDOWEXTEX; + + typedef struct tagEMRSCALEVIEWPORTEXTEX { + EMR emr; + LONG xNum; + LONG xDenom; + LONG yNum; + LONG yDenom; + } EMRSCALEVIEWPORTEXTEX,*PEMRSCALEVIEWPORTEXTEX,EMRSCALEWINDOWEXTEX,*PEMRSCALEWINDOWEXTEX; + + typedef struct tagEMRSETWORLDTRANSFORM { + EMR emr; + XFORM xform; + } EMRSETWORLDTRANSFORM,*PEMRSETWORLDTRANSFORM; + + typedef struct tagEMRMODIFYWORLDTRANSFORM { + EMR emr; + XFORM xform; + DWORD iMode; + } EMRMODIFYWORLDTRANSFORM,*PEMRMODIFYWORLDTRANSFORM; + + typedef struct tagEMRSETPIXELV { + EMR emr; + POINTL ptlPixel; + COLORREF crColor; + } EMRSETPIXELV,*PEMRSETPIXELV; + + typedef struct tagEMREXTFLOODFILL { + EMR emr; + POINTL ptlStart; + COLORREF crColor; + DWORD iMode; + } EMREXTFLOODFILL,*PEMREXTFLOODFILL; + + typedef struct tagEMRELLIPSE { + EMR emr; + RECTL rclBox; + } EMRELLIPSE,*PEMRELLIPSE,EMRRECTANGLE,*PEMRRECTANGLE; + + typedef struct tagEMRROUNDRECT { + EMR emr; + RECTL rclBox; + SIZEL szlCorner; + } EMRROUNDRECT,*PEMRROUNDRECT; + + typedef struct tagEMRARC { + EMR emr; + RECTL rclBox; + POINTL ptlStart; + POINTL ptlEnd; + } EMRARC,*PEMRARC,EMRARCTO,*PEMRARCTO,EMRCHORD,*PEMRCHORD,EMRPIE,*PEMRPIE; + + typedef struct tagEMRANGLEARC { + EMR emr; + POINTL ptlCenter; + DWORD nRadius; + FLOAT eStartAngle; + FLOAT eSweepAngle; + } EMRANGLEARC,*PEMRANGLEARC; + + typedef struct tagEMRPOLYLINE { + EMR emr; + RECTL rclBounds; + DWORD cptl; + POINTL aptl[1]; + } EMRPOLYLINE,*PEMRPOLYLINE,EMRPOLYBEZIER,*PEMRPOLYBEZIER,EMRPOLYGON,*PEMRPOLYGON,EMRPOLYBEZIERTO,*PEMRPOLYBEZIERTO,EMRPOLYLINETO,*PEMRPOLYLINETO; + + typedef struct tagEMRPOLYLINE16 { + EMR emr; + RECTL rclBounds; + DWORD cpts; + POINTS apts[1]; + } EMRPOLYLINE16,*PEMRPOLYLINE16,EMRPOLYBEZIER16,*PEMRPOLYBEZIER16,EMRPOLYGON16,*PEMRPOLYGON16,EMRPOLYBEZIERTO16,*PEMRPOLYBEZIERTO16,EMRPOLYLINETO16,*PEMRPOLYLINETO16; + + typedef struct tagEMRPOLYDRAW { + EMR emr; + RECTL rclBounds; + DWORD cptl; + POINTL aptl[1]; + BYTE abTypes[1]; + } EMRPOLYDRAW,*PEMRPOLYDRAW; + + typedef struct tagEMRPOLYDRAW16 { + EMR emr; + RECTL rclBounds; + DWORD cpts; + POINTS apts[1]; + BYTE abTypes[1]; + } EMRPOLYDRAW16,*PEMRPOLYDRAW16; + + typedef struct tagEMRPOLYPOLYLINE { + EMR emr; + RECTL rclBounds; + DWORD nPolys; + DWORD cptl; + DWORD aPolyCounts[1]; + POINTL aptl[1]; + } EMRPOLYPOLYLINE,*PEMRPOLYPOLYLINE,EMRPOLYPOLYGON,*PEMRPOLYPOLYGON; + + typedef struct tagEMRPOLYPOLYLINE16 { + EMR emr; + RECTL rclBounds; + DWORD nPolys; + DWORD cpts; + DWORD aPolyCounts[1]; + POINTS apts[1]; + } EMRPOLYPOLYLINE16,*PEMRPOLYPOLYLINE16,EMRPOLYPOLYGON16,*PEMRPOLYPOLYGON16; + + typedef struct tagEMRINVERTRGN { + EMR emr; + RECTL rclBounds; + DWORD cbRgnData; + BYTE RgnData[1]; + } EMRINVERTRGN,*PEMRINVERTRGN,EMRPAINTRGN,*PEMRPAINTRGN; + + typedef struct tagEMRFILLRGN { + EMR emr; + RECTL rclBounds; + DWORD cbRgnData; + DWORD ihBrush; + BYTE RgnData[1]; + } EMRFILLRGN,*PEMRFILLRGN; + + typedef struct tagEMRFRAMERGN { + EMR emr; + RECTL rclBounds; + DWORD cbRgnData; + DWORD ihBrush; + SIZEL szlStroke; + BYTE RgnData[1]; + } EMRFRAMERGN,*PEMRFRAMERGN; + + typedef struct tagEMREXTSELECTCLIPRGN { + EMR emr; + DWORD cbRgnData; + DWORD iMode; + BYTE RgnData[1]; + } EMREXTSELECTCLIPRGN,*PEMREXTSELECTCLIPRGN; + + typedef struct tagEMREXTTEXTOUTA { + EMR emr; + RECTL rclBounds; + DWORD iGraphicsMode; + FLOAT exScale; + FLOAT eyScale; + EMRTEXT emrtext; + } EMREXTTEXTOUTA,*PEMREXTTEXTOUTA,EMREXTTEXTOUTW,*PEMREXTTEXTOUTW; + + typedef struct tagEMRPOLYTEXTOUTA { + EMR emr; + RECTL rclBounds; + DWORD iGraphicsMode; + FLOAT exScale; + FLOAT eyScale; + LONG cStrings; + EMRTEXT aemrtext[1]; + } EMRPOLYTEXTOUTA,*PEMRPOLYTEXTOUTA,EMRPOLYTEXTOUTW,*PEMRPOLYTEXTOUTW; + + typedef struct tagEMRBITBLT { + EMR emr; + RECTL rclBounds; + LONG xDest; + LONG yDest; + LONG cxDest; + LONG cyDest; + DWORD dwRop; + LONG xSrc; + LONG ySrc; + XFORM xformSrc; + COLORREF crBkColorSrc; + DWORD iUsageSrc; + DWORD offBmiSrc; + DWORD cbBmiSrc; + DWORD offBitsSrc; + DWORD cbBitsSrc; + } EMRBITBLT,*PEMRBITBLT; + + typedef struct tagEMRSTRETCHBLT { + EMR emr; + RECTL rclBounds; + LONG xDest; + LONG yDest; + LONG cxDest; + LONG cyDest; + DWORD dwRop; + LONG xSrc; + LONG ySrc; + XFORM xformSrc; + COLORREF crBkColorSrc; + DWORD iUsageSrc; + DWORD offBmiSrc; + DWORD cbBmiSrc; + DWORD offBitsSrc; + DWORD cbBitsSrc; + LONG cxSrc; + LONG cySrc; + } EMRSTRETCHBLT,*PEMRSTRETCHBLT; + + typedef struct tagEMRMASKBLT { + EMR emr; + RECTL rclBounds; + LONG xDest; + LONG yDest; + LONG cxDest; + LONG cyDest; + DWORD dwRop; + LONG xSrc; + LONG ySrc; + XFORM xformSrc; + COLORREF crBkColorSrc; + DWORD iUsageSrc; + DWORD offBmiSrc; + DWORD cbBmiSrc; + DWORD offBitsSrc; + DWORD cbBitsSrc; + LONG xMask; + LONG yMask; + DWORD iUsageMask; + DWORD offBmiMask; + DWORD cbBmiMask; + DWORD offBitsMask; + DWORD cbBitsMask; + } EMRMASKBLT,*PEMRMASKBLT; + + typedef struct tagEMRPLGBLT { + EMR emr; + RECTL rclBounds; + POINTL aptlDest[3]; + LONG xSrc; + LONG ySrc; + LONG cxSrc; + LONG cySrc; + XFORM xformSrc; + COLORREF crBkColorSrc; + DWORD iUsageSrc; + DWORD offBmiSrc; + DWORD cbBmiSrc; + DWORD offBitsSrc; + DWORD cbBitsSrc; + LONG xMask; + LONG yMask; + DWORD iUsageMask; + DWORD offBmiMask; + DWORD cbBmiMask; + DWORD offBitsMask; + DWORD cbBitsMask; + } EMRPLGBLT,*PEMRPLGBLT; + + typedef struct tagEMRSETDIBITSTODEVICE { + EMR emr; + RECTL rclBounds; + LONG xDest; + LONG yDest; + LONG xSrc; + LONG ySrc; + LONG cxSrc; + LONG cySrc; + DWORD offBmiSrc; + DWORD cbBmiSrc; + DWORD offBitsSrc; + DWORD cbBitsSrc; + DWORD iUsageSrc; + DWORD iStartScan; + DWORD cScans; + } EMRSETDIBITSTODEVICE,*PEMRSETDIBITSTODEVICE; + + typedef struct tagEMRSTRETCHDIBITS { + EMR emr; + RECTL rclBounds; + LONG xDest; + LONG yDest; + LONG xSrc; + LONG ySrc; + LONG cxSrc; + LONG cySrc; + DWORD offBmiSrc; + DWORD cbBmiSrc; + DWORD offBitsSrc; + DWORD cbBitsSrc; + DWORD iUsageSrc; + DWORD dwRop; + LONG cxDest; + LONG cyDest; + } EMRSTRETCHDIBITS,*PEMRSTRETCHDIBITS; + + typedef struct tagEMREXTCREATEFONTINDIRECTW { + EMR emr; + DWORD ihFont; + EXTLOGFONTW elfw; + } EMREXTCREATEFONTINDIRECTW,*PEMREXTCREATEFONTINDIRECTW; + + typedef struct tagEMRCREATEPALETTE { + EMR emr; + DWORD ihPal; + LOGPALETTE lgpl; + } EMRCREATEPALETTE,*PEMRCREATEPALETTE; + + typedef struct tagEMRCREATEPEN { + EMR emr; + DWORD ihPen; + LOGPEN lopn; + } EMRCREATEPEN,*PEMRCREATEPEN; + + typedef struct tagEMREXTCREATEPEN { + EMR emr; + DWORD ihPen; + DWORD offBmi; + DWORD cbBmi; + DWORD offBits; + DWORD cbBits; + EXTLOGPEN elp; + } EMREXTCREATEPEN,*PEMREXTCREATEPEN; + + typedef struct tagEMRCREATEBRUSHINDIRECT { + EMR emr; + DWORD ihBrush; + LOGBRUSH32 lb; + } EMRCREATEBRUSHINDIRECT,*PEMRCREATEBRUSHINDIRECT; + + typedef struct tagEMRCREATEMONOBRUSH { + EMR emr; + DWORD ihBrush; + DWORD iUsage; + DWORD offBmi; + DWORD cbBmi; + DWORD offBits; + DWORD cbBits; + } EMRCREATEMONOBRUSH,*PEMRCREATEMONOBRUSH; + + typedef struct tagEMRCREATEDIBPATTERNBRUSHPT { + EMR emr; + DWORD ihBrush; + DWORD iUsage; + DWORD offBmi; + DWORD cbBmi; + DWORD offBits; + DWORD cbBits; + } EMRCREATEDIBPATTERNBRUSHPT,*PEMRCREATEDIBPATTERNBRUSHPT; + + typedef struct tagEMRFORMAT { + DWORD dSignature; + DWORD nVersion; + DWORD cbData; + DWORD offData; + } EMRFORMAT,*PEMRFORMAT; + + typedef struct tagEMRGLSRECORD { + EMR emr; + DWORD cbData; + BYTE Data[1]; + } EMRGLSRECORD,*PEMRGLSRECORD; + + typedef struct tagEMRGLSBOUNDEDRECORD { + EMR emr; + RECTL rclBounds; + DWORD cbData; + BYTE Data[1]; + } EMRGLSBOUNDEDRECORD,*PEMRGLSBOUNDEDRECORD; + + typedef struct tagEMRPIXELFORMAT { + EMR emr; + PIXELFORMATDESCRIPTOR pfd; + } EMRPIXELFORMAT,*PEMRPIXELFORMAT; + + typedef struct tagEMRCREATECOLORSPACE { + EMR emr; + DWORD ihCS; + LOGCOLORSPACEA lcs; + } EMRCREATECOLORSPACE,*PEMRCREATECOLORSPACE; + + typedef struct tagEMRSETCOLORSPACE { + EMR emr; + DWORD ihCS; + } EMRSETCOLORSPACE,*PEMRSETCOLORSPACE,EMRSELECTCOLORSPACE,*PEMRSELECTCOLORSPACE,EMRDELETECOLORSPACE,*PEMRDELETECOLORSPACE; + + typedef struct tagEMREXTESCAPE { + EMR emr; + INT iEscape; + INT cbEscData; + BYTE EscData[1]; + } EMREXTESCAPE,*PEMREXTESCAPE,EMRDRAWESCAPE,*PEMRDRAWESCAPE; + + typedef struct tagEMRNAMEDESCAPE { + EMR emr; + INT iEscape; + INT cbDriver; + INT cbEscData; + BYTE EscData[1]; + } EMRNAMEDESCAPE,*PEMRNAMEDESCAPE; + +#define SETICMPROFILE_EMBEDED 0x00000001 + + typedef struct tagEMRSETICMPROFILE { + EMR emr; + DWORD dwFlags; + DWORD cbName; + DWORD cbData; + BYTE Data[1]; + } EMRSETICMPROFILE,*PEMRSETICMPROFILE,EMRSETICMPROFILEA,*PEMRSETICMPROFILEA,EMRSETICMPROFILEW,*PEMRSETICMPROFILEW; + +#define CREATECOLORSPACE_EMBEDED 0x00000001 + + typedef struct tagEMRCREATECOLORSPACEW { + EMR emr; + DWORD ihCS; + LOGCOLORSPACEW lcs; + DWORD dwFlags; + DWORD cbData; + BYTE Data[1]; + } EMRCREATECOLORSPACEW,*PEMRCREATECOLORSPACEW; + +#define COLORMATCHTOTARGET_EMBEDED 0x00000001 + + typedef struct tagCOLORMATCHTOTARGET { + EMR emr; + DWORD dwAction; + DWORD dwFlags; + DWORD cbName; + DWORD cbData; + BYTE Data[1]; + } EMRCOLORMATCHTOTARGET,*PEMRCOLORMATCHTOTARGET; + + typedef struct tagCOLORCORRECTPALETTE { + EMR emr; + DWORD ihPalette; + DWORD nFirstEntry; + DWORD nPalEntries; + DWORD nReserved; + } EMRCOLORCORRECTPALETTE,*PEMRCOLORCORRECTPALETTE; + + typedef struct tagEMRALPHABLEND { + EMR emr; + RECTL rclBounds; + LONG xDest; + LONG yDest; + LONG cxDest; + LONG cyDest; + DWORD dwRop; + LONG xSrc; + LONG ySrc; + XFORM xformSrc; + COLORREF crBkColorSrc; + DWORD iUsageSrc; + DWORD offBmiSrc; + DWORD cbBmiSrc; + DWORD offBitsSrc; + DWORD cbBitsSrc; + LONG cxSrc; + LONG cySrc; + } EMRALPHABLEND,*PEMRALPHABLEND; + + typedef struct tagEMRGRADIENTFILL { + EMR emr; + RECTL rclBounds; + DWORD nVer; + DWORD nTri; + ULONG ulMode; + TRIVERTEX Ver[1]; + } EMRGRADIENTFILL,*PEMRGRADIENTFILL; + + typedef struct tagEMRTRANSPARENTBLT { + EMR emr; + RECTL rclBounds; + LONG xDest; + LONG yDest; + LONG cxDest; + LONG cyDest; + DWORD dwRop; + LONG xSrc; + LONG ySrc; + XFORM xformSrc; + COLORREF crBkColorSrc; + DWORD iUsageSrc; + DWORD offBmiSrc; + DWORD cbBmiSrc; + DWORD offBitsSrc; + DWORD cbBitsSrc; + LONG cxSrc; + LONG cySrc; + } EMRTRANSPARENTBLT,*PEMRTRANSPARENTBLT; + +#define GDICOMMENT_IDENTIFIER 0x43494447 +#define GDICOMMENT_WINDOWS_METAFILE 0x80000001 +#define GDICOMMENT_BEGINGROUP 0x00000002 +#define GDICOMMENT_ENDGROUP 0x00000003 +#define GDICOMMENT_MULTIFORMATS 0x40000004 +#define EPS_SIGNATURE 0x46535045 +#define GDICOMMENT_UNICODE_STRING 0x00000040 +#define GDICOMMENT_UNICODE_END 0x00000080 +#endif + +#ifdef UNICODE +#define wglUseFontBitmaps wglUseFontBitmapsW +#else +#define wglUseFontBitmaps wglUseFontBitmapsA +#endif + + WINGDIAPI WINBOOL WINAPI wglCopyContext(HGLRC,HGLRC,UINT); + WINGDIAPI HGLRC WINAPI wglCreateContext(HDC); + WINGDIAPI HGLRC WINAPI wglCreateLayerContext(HDC,int); + WINGDIAPI WINBOOL WINAPI wglDeleteContext(HGLRC); + WINGDIAPI HGLRC WINAPI wglGetCurrentContext(VOID); + WINGDIAPI HDC WINAPI wglGetCurrentDC(VOID); + WINGDIAPI PROC WINAPI wglGetProcAddress(LPCSTR); + WINGDIAPI WINBOOL WINAPI wglMakeCurrent(HDC,HGLRC); + WINGDIAPI WINBOOL WINAPI wglShareLists(HGLRC,HGLRC); + WINGDIAPI WINBOOL WINAPI wglUseFontBitmapsA(HDC,DWORD,DWORD,DWORD); + WINGDIAPI WINBOOL WINAPI wglUseFontBitmapsW(HDC,DWORD,DWORD,DWORD); + WINGDIAPI WINBOOL WINAPI SwapBuffers(HDC); + + typedef struct _POINTFLOAT { + FLOAT x; + FLOAT y; + } POINTFLOAT,*PPOINTFLOAT; + + typedef struct _GLYPHMETRICSFLOAT { + FLOAT gmfBlackBoxX; + FLOAT gmfBlackBoxY; + POINTFLOAT gmfptGlyphOrigin; + FLOAT gmfCellIncX; + FLOAT gmfCellIncY; + } GLYPHMETRICSFLOAT,*PGLYPHMETRICSFLOAT,*LPGLYPHMETRICSFLOAT; + +#define WGL_FONT_LINES 0 +#define WGL_FONT_POLYGONS 1 + +#ifdef UNICODE +#define wglUseFontOutlines wglUseFontOutlinesW +#else +#define wglUseFontOutlines wglUseFontOutlinesA +#endif + + WINGDIAPI WINBOOL WINAPI wglUseFontOutlinesA(HDC,DWORD,DWORD,DWORD,FLOAT,FLOAT,int,LPGLYPHMETRICSFLOAT); + WINGDIAPI WINBOOL WINAPI wglUseFontOutlinesW(HDC,DWORD,DWORD,DWORD,FLOAT,FLOAT,int,LPGLYPHMETRICSFLOAT); + + typedef struct tagLAYERPLANEDESCRIPTOR { + WORD nSize; + WORD nVersion; + DWORD dwFlags; + BYTE iPixelType; + BYTE cColorBits; + BYTE cRedBits; + BYTE cRedShift; + BYTE cGreenBits; + BYTE cGreenShift; + BYTE cBlueBits; + BYTE cBlueShift; + BYTE cAlphaBits; + BYTE cAlphaShift; + BYTE cAccumBits; + BYTE cAccumRedBits; + BYTE cAccumGreenBits; + BYTE cAccumBlueBits; + BYTE cAccumAlphaBits; + BYTE cDepthBits; + BYTE cStencilBits; + BYTE cAuxBuffers; + BYTE iLayerPlane; + BYTE bReserved; + COLORREF crTransparent; + } LAYERPLANEDESCRIPTOR,*PLAYERPLANEDESCRIPTOR,*LPLAYERPLANEDESCRIPTOR; + +#define LPD_DOUBLEBUFFER 0x00000001 +#define LPD_STEREO 0x00000002 +#define LPD_SUPPORT_GDI 0x00000010 +#define LPD_SUPPORT_OPENGL 0x00000020 +#define LPD_SHARE_DEPTH 0x00000040 +#define LPD_SHARE_STENCIL 0x00000080 +#define LPD_SHARE_ACCUM 0x00000100 +#define LPD_SWAP_EXCHANGE 0x00000200 +#define LPD_SWAP_COPY 0x00000400 +#define LPD_TRANSPARENT 0x00001000 + +#define LPD_TYPE_RGBA 0 +#define LPD_TYPE_COLORINDEX 1 + +#define WGL_SWAP_MAIN_PLANE 0x00000001 +#define WGL_SWAP_OVERLAY1 0x00000002 +#define WGL_SWAP_OVERLAY2 0x00000004 +#define WGL_SWAP_OVERLAY3 0x00000008 +#define WGL_SWAP_OVERLAY4 0x00000010 +#define WGL_SWAP_OVERLAY5 0x00000020 +#define WGL_SWAP_OVERLAY6 0x00000040 +#define WGL_SWAP_OVERLAY7 0x00000080 +#define WGL_SWAP_OVERLAY8 0x00000100 +#define WGL_SWAP_OVERLAY9 0x00000200 +#define WGL_SWAP_OVERLAY10 0x00000400 +#define WGL_SWAP_OVERLAY11 0x00000800 +#define WGL_SWAP_OVERLAY12 0x00001000 +#define WGL_SWAP_OVERLAY13 0x00002000 +#define WGL_SWAP_OVERLAY14 0x00004000 +#define WGL_SWAP_OVERLAY15 0x00008000 +#define WGL_SWAP_UNDERLAY1 0x00010000 +#define WGL_SWAP_UNDERLAY2 0x00020000 +#define WGL_SWAP_UNDERLAY3 0x00040000 +#define WGL_SWAP_UNDERLAY4 0x00080000 +#define WGL_SWAP_UNDERLAY5 0x00100000 +#define WGL_SWAP_UNDERLAY6 0x00200000 +#define WGL_SWAP_UNDERLAY7 0x00400000 +#define WGL_SWAP_UNDERLAY8 0x00800000 +#define WGL_SWAP_UNDERLAY9 0x01000000 +#define WGL_SWAP_UNDERLAY10 0x02000000 +#define WGL_SWAP_UNDERLAY11 0x04000000 +#define WGL_SWAP_UNDERLAY12 0x08000000 +#define WGL_SWAP_UNDERLAY13 0x10000000 +#define WGL_SWAP_UNDERLAY14 0x20000000 +#define WGL_SWAP_UNDERLAY15 0x40000000 + + WINGDIAPI WINBOOL WINAPI wglDescribeLayerPlane(HDC,int,int,UINT,LPLAYERPLANEDESCRIPTOR); + WINGDIAPI int WINAPI wglSetLayerPaletteEntries(HDC,int,int,int,CONST COLORREF *); + WINGDIAPI int WINAPI wglGetLayerPaletteEntries(HDC,int,int,int,COLORREF *); + WINGDIAPI WINBOOL WINAPI wglRealizeLayerPalette(HDC,int,WINBOOL); + WINGDIAPI WINBOOL WINAPI wglSwapLayerBuffers(HDC,UINT); + + typedef struct _WGLSWAP { + HDC hdc; + UINT uiFlags; + } WGLSWAP,*PWGLSWAP,*LPWGLSWAP; + +#define WGL_SWAPMULTIPLE_MAX 16 + + WINGDIAPI DWORD WINAPI wglSwapMultipleBuffers(UINT,CONST WGLSWAP *); +#endif + +#ifdef __cplusplus +} +#endif +#endif diff --git a/tinyc/win32/include/winapi/winnt.h b/tinyc/win32/include/winapi/winnt.h new file mode 100644 index 000000000..4cf685d2a --- /dev/null +++ b/tinyc/win32/include/winapi/winnt.h @@ -0,0 +1,5835 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _WINNT_ +#define _WINNT_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#define ANYSIZE_ARRAY 1 + +//gr #include + +#define RESTRICTED_POINTER + +#ifndef __CRT_UNALIGNED +#define __CRT_UNALIGNED +#endif + +#if defined(__ia64__) || defined(__x86_64) +#define UNALIGNED __CRT_UNALIGNED +#ifdef _WIN64 +#define UNALIGNED64 __CRT_UNALIGNED +#else +#define UNALIGNED64 +#endif +#else +#define UNALIGNED +#define UNALIGNED64 +#endif + +#if !defined(I_X86_) && !defined(_IA64_) && !defined(_AMD64_) && (defined(_X86_) && !defined(__x86_64)) +#define I_X86_ +#endif + +#if !defined(I_X86_) && !defined(_IA64_) && !defined(_AMD64_) && defined(__x86_64) +#define _AMD64_ +#endif + +#if !defined(I_X86_) && !(defined(_X86_) && !defined(__x86_64)) && !defined(_AMD64_) && defined(__ia64__) +#if !defined(_IA64_) +#define _IA64_ +#endif +#endif + + +#ifdef _WIN64 +#define MAX_NATURAL_ALIGNMENT sizeof(ULONGLONG) +#define MEMORY_ALLOCATION_ALIGNMENT 16 +#else +#define MAX_NATURAL_ALIGNMENT sizeof(DWORD) +#define MEMORY_ALLOCATION_ALIGNMENT 8 +#endif + +#ifdef __cplusplus +#define TYPE_ALIGNMENT(t) __alignof__ (t) +#else +#define TYPE_ALIGNMENT(t) FIELD_OFFSET(struct { char x; t test; },test) +#endif + +#ifdef _WIN64 +#ifdef _AMD64_ +#define PROBE_ALIGNMENT(_s) TYPE_ALIGNMENT(DWORD) +#elif defined(_IA64_) +#define PROBE_ALIGNMENT(_s) (TYPE_ALIGNMENT(_s) > TYPE_ALIGNMENT(DWORD) ? TYPE_ALIGNMENT(_s) : TYPE_ALIGNMENT(DWORD)) +#else +#error No Target Architecture +#endif +#define PROBE_ALIGNMENT32(_s) TYPE_ALIGNMENT(DWORD) +#else +#define PROBE_ALIGNMENT(_s) TYPE_ALIGNMENT(DWORD) +#endif + +#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1] + +#include + +#if defined(_X86_) || defined(__ia64__) || defined(__x86_64) +#define DECLSPEC_IMPORT __declspec(dllimport) +#else +#define DECLSPEC_IMPORT +#endif + +#ifndef DECLSPEC_NORETURN +#define DECLSPEC_NORETURN __declspec(noreturn) +#endif + +#ifndef DECLSPEC_ALIGN +#define DECLSPEC_ALIGN(x) __attribute__ ((aligned(x))) +#endif + +#ifndef SYSTEM_CACHE_ALIGNMENT_SIZE +#if defined(_AMD64_) || defined(I_X86_) +#define SYSTEM_CACHE_ALIGNMENT_SIZE 64 +#else +#define SYSTEM_CACHE_ALIGNMENT_SIZE 128 +#endif +#endif + +#ifndef DECLSPEC_CACHEALIGN +#define DECLSPEC_CACHEALIGN DECLSPEC_ALIGN(SYSTEM_CACHE_ALIGNMENT_SIZE) +#endif + +#ifndef DECLSPEC_UUID +#define DECLSPEC_UUID(x) +#endif + +#ifndef DECLSPEC_NOVTABLE +#define DECLSPEC_NOVTABLE +#endif + +#ifndef DECLSPEC_SELECTANY +#define DECLSPEC_SELECTANY __declspec(selectany) +#endif + +#ifndef NOP_FUNCTION +#define NOP_FUNCTION (void)0 +#endif + +#ifndef DECLSPEC_NOINLINE +#define DECLSPEC_NOINLINE +#endif + +#ifndef FORCEINLINE +#define FORCEINLINE static __inline__ +#endif + +#ifndef DECLSPEC_DEPRECATED +#define DECLSPEC_DEPRECATED __declspec(deprecated) +#define DEPRECATE_SUPPORTED +#endif + +#define DECLSPEC_DEPRECATED_DDK +#define PRAGMA_DEPRECATED_DDK 0 + + typedef void *PVOID; + typedef void *PVOID64; + +#define NTAPI __stdcall +#define NTSYSAPI DECLSPEC_IMPORT +#define NTSYSCALLAPI DECLSPEC_IMPORT + +#ifndef VOID +#define VOID void + typedef char CHAR; + typedef short SHORT; + typedef long LONG; +#endif + + typedef wchar_t WCHAR; + typedef WCHAR *PWCHAR,*LPWCH,*PWCH; + typedef CONST WCHAR *LPCWCH,*PCWCH; + typedef WCHAR *NWPSTR,*LPWSTR,*PWSTR; + typedef PWSTR *PZPWSTR; + typedef CONST PWSTR *PCZPWSTR; + typedef WCHAR UNALIGNED *LPUWSTR,*PUWSTR; + typedef CONST WCHAR *LPCWSTR,*PCWSTR; + typedef PCWSTR *PZPCWSTR; + typedef CONST WCHAR UNALIGNED *LPCUWSTR,*PCUWSTR; + typedef CHAR *PCHAR,*LPCH,*PCH; + typedef CONST CHAR *LPCCH,*PCCH; + typedef CHAR *NPSTR,*LPSTR,*PSTR; + typedef PSTR *PZPSTR; + typedef CONST PSTR *PCZPSTR; + typedef CONST CHAR *LPCSTR,*PCSTR; + typedef PCSTR *PZPCSTR; + +#ifdef UNICODE +#ifndef _TCHAR_DEFINED +#define _TCHAR_DEFINED + typedef WCHAR TCHAR,*PTCHAR; + typedef WCHAR TBYTE ,*PTBYTE; +#endif + + typedef LPWSTR LPTCH,PTCH; + typedef LPWSTR PTSTR,LPTSTR; + typedef LPCWSTR PCTSTR,LPCTSTR; + typedef LPUWSTR PUTSTR,LPUTSTR; + typedef LPCUWSTR PCUTSTR,LPCUTSTR; + typedef LPWSTR LP; +#define __TEXT(quote) L##quote +#else +#ifndef _TCHAR_DEFINED +#define _TCHAR_DEFINED + typedef char TCHAR,*PTCHAR; + typedef unsigned char TBYTE ,*PTBYTE; +#endif + + typedef LPSTR LPTCH,PTCH; + typedef LPSTR PTSTR,LPTSTR,PUTSTR,LPUTSTR; + typedef LPCSTR PCTSTR,LPCTSTR,PCUTSTR,LPCUTSTR; +#define __TEXT(quote) quote +#endif + +#define TEXT(quote) __TEXT(quote) + + typedef SHORT *PSHORT; + typedef LONG *PLONG; + + typedef void *HANDLE; +#define DECLARE_HANDLE(name) struct name##__ { int unused; }; typedef struct name##__ *name + typedef HANDLE *PHANDLE; + + typedef BYTE FCHAR; + typedef WORD FSHORT; + typedef DWORD FLONG; + +#ifndef _HRESULT_DEFINED +#define _HRESULT_DEFINED + typedef LONG HRESULT; +#endif + +#ifdef __cplusplus +#define EXTERN_C extern "C" +#else +#define EXTERN_C extern +#endif + +#define STDMETHODCALLTYPE WINAPI +#define STDMETHODVCALLTYPE __cdecl +#define STDAPICALLTYPE WINAPI +#define STDAPIVCALLTYPE __cdecl +#define STDAPI EXTERN_C HRESULT WINAPI +#define STDAPI_(type) EXTERN_C type WINAPI +#define STDMETHODIMP HRESULT WINAPI +#define STDMETHODIMP_(type) type WINAPI +#define STDAPIV EXTERN_C HRESULT STDAPIVCALLTYPE +#define STDAPIV_(type) EXTERN_C type STDAPIVCALLTYPE +#define STDMETHODIMPV HRESULT STDMETHODVCALLTYPE +#define STDMETHODIMPV_(type) type STDMETHODVCALLTYPE + + typedef char CCHAR; +#ifndef _LCID_DEFINED +#define _LCID_DEFINED +typedef DWORD LCID; +#endif + typedef PDWORD PLCID; +#ifndef _LANGID_DEFINED +#define _LANGID_DEFINED + typedef WORD LANGID; +#endif +#define APPLICATION_ERROR_MASK 0x20000000 +#define ERROR_SEVERITY_SUCCESS 0x00000000 +#define ERROR_SEVERITY_INFORMATIONAL 0x40000000 +#define ERROR_SEVERITY_WARNING 0x80000000 +#define ERROR_SEVERITY_ERROR 0xC0000000 + +#ifdef __ia64__ + __declspec(align(16)) +#endif + typedef struct _FLOAT128 { + __int64 LowPart; + __int64 HighPart; + } FLOAT128; + + typedef FLOAT128 *PFLOAT128; + +#define _ULONGLONG_ +#if((!(defined(_X86_) && !defined(__x86_64)) || (defined(_INTEGRAL_MAX_BITS) && _INTEGRAL_MAX_BITS >= 64))) + typedef __int64 LONGLONG; + typedef unsigned __int64 ULONGLONG; + +#define MAXLONGLONG (0x7fffffffffffffff) +#else + + typedef double LONGLONG; + typedef double ULONGLONG; +#endif + + typedef LONGLONG *PLONGLONG; + typedef ULONGLONG *PULONGLONG; + + typedef LONGLONG USN; + + typedef union _LARGE_INTEGER { + struct { + DWORD LowPart; + LONG HighPart; + }; + struct { + DWORD LowPart; + LONG HighPart; + } u; + LONGLONG QuadPart; + } LARGE_INTEGER; + + typedef LARGE_INTEGER *PLARGE_INTEGER; + + typedef union _ULARGE_INTEGER { + struct { + DWORD LowPart; + DWORD HighPart; + }; + struct { + DWORD LowPart; + DWORD HighPart; + } u; + ULONGLONG QuadPart; + } ULARGE_INTEGER; + + typedef ULARGE_INTEGER *PULARGE_INTEGER; + + typedef struct _LUID { + DWORD LowPart; + LONG HighPart; + } LUID,*PLUID; + +#define _DWORDLONG_ + typedef ULONGLONG DWORDLONG; + typedef DWORDLONG *PDWORDLONG; + +#ifdef RC_INVOKED +#define Int32x32To64(a,b) ((LONGLONG)((LONG)(a)) *(LONGLONG)((LONG)(b))) +#define UInt32x32To64(a,b) ((ULONGLONG)((DWORD)(a)) *(ULONGLONG)((DWORD)(b))) +#define Int64ShrlMod32(a,b) ((ULONGLONG)(a) >> (b)) +#elif (defined(_X86_) && !defined(__x86_64)) +#define Int32x32To64(a,b) (LONGLONG)((LONGLONG)(LONG)(a) *(LONG)(b)) +#define UInt32x32To64(a,b) (ULONGLONG)((ULONGLONG)(DWORD)(a) *(DWORD)(b)) +#define Int64ShrlMod32(a,b) ((DWORDLONG)(a)>>(b)) +#elif defined(__ia64__) || defined(__x86_64) +#define Int32x32To64(a,b) ((LONGLONG)((LONG)(a)) *(LONGLONG)((LONG)(b))) +#define UInt32x32To64(a,b) ((ULONGLONG)((DWORD)(a)) *(ULONGLONG)((DWORD)(b))) +#define Int64ShrlMod32(a,b) ((ULONGLONG)(a) >> (b)) +#else +#error Must define a target architecture. +#endif + +#define Int64ShraMod32(a,b) ((LONGLONG)(a) >> (b)) +#define Int64ShllMod32(a,b) ((ULONGLONG)(a) << (b)) + +#ifdef __cplusplus + extern "C" { +#endif + +#ifdef __x86_64 + +#define RotateLeft8 _rotl8 +#define RotateLeft16 _rotl16 +#define RotateRight8 _rotr8 +#define RotateRight16 _rotr16 + + unsigned char __cdecl _rotl8(unsigned char Value,unsigned char Shift); + unsigned short __cdecl _rotl16(unsigned short Value,unsigned char Shift); + unsigned char __cdecl _rotr8(unsigned char Value,unsigned char Shift); + unsigned short __cdecl _rotr16(unsigned short Value,unsigned char Shift); +#endif + +#define RotateLeft32 _rotl +#define RotateLeft64 _rotl64 +#define RotateRight32 _rotr +#define RotateRight64 _rotr64 + + unsigned int __cdecl _rotl(unsigned int Value,int Shift); + unsigned __int64 __cdecl _rotl64(unsigned __int64 Value,int Shift); + unsigned int __cdecl _rotr(unsigned int Value,int Shift); + unsigned __int64 __cdecl _rotr64(unsigned __int64 Value,int Shift); +#ifdef __cplusplus + } +#endif + +#define ANSI_NULL ((CHAR)0) +#define UNICODE_NULL ((WCHAR)0) +#define UNICODE_STRING_MAX_BYTES ((WORD) 65534) +#define UNICODE_STRING_MAX_CHARS (32767) + +#ifndef _BOOLEAN_ +#define _BOOLEAN_ + typedef BYTE BOOLEAN; +#endif + typedef BOOLEAN *PBOOLEAN; + + typedef struct _LIST_ENTRY { + struct _LIST_ENTRY *Flink; + struct _LIST_ENTRY *Blink; + } LIST_ENTRY,*PLIST_ENTRY,*RESTRICTED_POINTER PRLIST_ENTRY; + + typedef struct _SINGLE_LIST_ENTRY { + struct _SINGLE_LIST_ENTRY *Next; + } SINGLE_LIST_ENTRY,*PSINGLE_LIST_ENTRY; + + typedef struct LIST_ENTRY32 { + DWORD Flink; + DWORD Blink; + } LIST_ENTRY32; + typedef LIST_ENTRY32 *PLIST_ENTRY32; + + typedef struct LIST_ENTRY64 { + ULONGLONG Flink; + ULONGLONG Blink; + } LIST_ENTRY64; + typedef LIST_ENTRY64 *PLIST_ENTRY64; + +#include + +#ifndef __OBJECTID_DEFINED +#define __OBJECTID_DEFINED + typedef struct _OBJECTID { + GUID Lineage; + DWORD Uniquifier; + } OBJECTID; +#endif + +#define MINCHAR 0x80 +#define MAXCHAR 0x7f +#define MINSHORT 0x8000 +#define MAXSHORT 0x7fff +#define MINLONG 0x80000000 +#define MAXLONG 0x7fffffff +#define MAXBYTE 0xff +#define MAXWORD 0xffff +#define MAXDWORD 0xffffffff + +#define FIELD_OFFSET(type,field) ((LONG)(LONG_PTR)&(((type *)0)->field)) +#define RTL_FIELD_SIZE(type,field) (sizeof(((type *)0)->field)) +#define RTL_SIZEOF_THROUGH_FIELD(type,field) (FIELD_OFFSET(type,field) + RTL_FIELD_SIZE(type,field)) +#define RTL_CONTAINS_FIELD(Struct,Size,Field) ((((PCHAR)(&(Struct)->Field)) + sizeof((Struct)->Field)) <= (((PCHAR)(Struct))+(Size))) +#define RTL_NUMBER_OF_V1(A) (sizeof(A)/sizeof((A)[0])) +#define RTL_NUMBER_OF_V2(A) RTL_NUMBER_OF_V1(A) + +#ifdef ENABLE_RTL_NUMBER_OF_V2 +#define RTL_NUMBER_OF(A) RTL_NUMBER_OF_V2(A) +#else +#define RTL_NUMBER_OF(A) RTL_NUMBER_OF_V1(A) +#endif + +#define ARRAYSIZE(A) RTL_NUMBER_OF_V2(A) +#define _ARRAYSIZE(A) RTL_NUMBER_OF_V1(A) + +#define RTL_FIELD_TYPE(type,field) (((type*)0)->field) +#define RTL_NUMBER_OF_FIELD(type,field) (RTL_NUMBER_OF(RTL_FIELD_TYPE(type,field))) +#define RTL_PADDING_BETWEEN_FIELDS(T,F1,F2) ((FIELD_OFFSET(T,F2) > FIELD_OFFSET(T,F1)) ? (FIELD_OFFSET(T,F2) - FIELD_OFFSET(T,F1) - RTL_FIELD_SIZE(T,F1)) : (FIELD_OFFSET(T,F1) - FIELD_OFFSET(T,F2) - RTL_FIELD_SIZE(T,F2))) + +#ifdef __cplusplus +#define RTL_CONST_CAST(type) const_cast +#else +#define RTL_CONST_CAST(type) (type) +#endif + +#define RTL_BITS_OF(sizeOfArg) (sizeof(sizeOfArg) *8) +#define RTL_BITS_OF_FIELD(type,field) (RTL_BITS_OF(RTL_FIELD_TYPE(type,field))) +#define CONTAINING_RECORD(address,type,field) ((type *)((PCHAR)(address) - (ULONG_PTR)(&((type *)0)->field))) + +#define VER_SERVER_NT 0x80000000 +#define VER_WORKSTATION_NT 0x40000000 +#define VER_SUITE_SMALLBUSINESS 0x00000001 +#define VER_SUITE_ENTERPRISE 0x00000002 +#define VER_SUITE_BACKOFFICE 0x00000004 +#define VER_SUITE_COMMUNICATIONS 0x00000008 +#define VER_SUITE_TERMINAL 0x00000010 +#define VER_SUITE_SMALLBUSINESS_RESTRICTED 0x00000020 +#define VER_SUITE_EMBEDDEDNT 0x00000040 +#define VER_SUITE_DATACENTER 0x00000080 +#define VER_SUITE_SINGLEUSERTS 0x00000100 +#define VER_SUITE_PERSONAL 0x00000200 +#define VER_SUITE_BLADE 0x00000400 +#define VER_SUITE_EMBEDDED_RESTRICTED 0x00000800 +#define VER_SUITE_SECURITY_APPLIANCE 0x00001000 +#define VER_SUITE_STORAGE_SERVER 0x00002000 +#define VER_SUITE_COMPUTE_SERVER 0x00004000 + +#define PRODUCT_UNDEFINED 0x0 + +#define PRODUCT_ULTIMATE 0x1 +#define PRODUCT_HOME_BASIC 0x2 +#define PRODUCT_HOME_PREMIUM 0x3 +#define PRODUCT_ENTERPRISE 0x4 +#define PRODUCT_HOME_BASIC_N 0x5 +#define PRODUCT_BUSINESS 0x6 +#define PRODUCT_STANDARD_SERVER 0x7 +#define PRODUCT_DATACENTER_SERVER 0x8 +#define PRODUCT_SMALLBUSINESS_SERVER 0x9 +#define PRODUCT_ENTERPRISE_SERVER 0xa +#define PRODUCT_STARTER 0xb +#define PRODUCT_DATACENTER_SERVER_CORE 0xc +#define PRODUCT_STANDARD_SERVER_CORE 0xd +#define PRODUCT_ENTERPRISE_SERVER_CORE 0xe +#define PRODUCT_ENTERPRISE_SERVER_IA64 0xf +#define PRODUCT_BUSINESS_N 0x10 +#define PRODUCT_WEB_SERVER 0x11 +#define PRODUCT_CLUSTER_SERVER 0x12 +#define PRODUCT_HOME_SERVER 0x13 +#define PRODUCT_STORAGE_EXPRESS_SERVER 0x14 +#define PRODUCT_STORAGE_STANDARD_SERVER 0x15 +#define PRODUCT_STORAGE_WORKGROUP_SERVER 0x16 +#define PRODUCT_STORAGE_ENTERPRISE_SERVER 0x17 +#define PRODUCT_SERVER_FOR_SMALLBUSINESS 0x18 +#define PRODUCT_SMALLBUSINESS_SERVER_PREMIUM 0x19 + +#define PRODUCT_UNLICENSED 0xabcdabcd + +#define LANG_NEUTRAL 0x00 +#define LANG_INVARIANT 0x7f + +#define LANG_AFRIKAANS 0x36 +#define LANG_ALBANIAN 0x1c +#define LANG_ALSATIAN 0x84 +#define LANG_AMHARIC 0x5e +#define LANG_ARABIC 0x01 +#define LANG_ARMENIAN 0x2b +#define LANG_ASSAMESE 0x4d +#define LANG_AZERI 0x2c +#define LANG_BASHKIR 0x6d +#define LANG_BASQUE 0x2d +#define LANG_BELARUSIAN 0x23 +#define LANG_BENGALI 0x45 +#define LANG_BRETON 0x7e +#define LANG_BOSNIAN 0x1a +#define LANG_BOSNIAN_NEUTRAL 0x781a +#define LANG_BULGARIAN 0x02 +#define LANG_CATALAN 0x03 +#define LANG_CHINESE 0x04 +#define LANG_CHINESE_SIMPLIFIED 0x04 +#define LANG_CHINESE_TRADITIONAL 0x7c04 +#define LANG_CORSICAN 0x83 +#define LANG_CROATIAN 0x1a +#define LANG_CZECH 0x05 +#define LANG_DANISH 0x06 +#define LANG_DARI 0x8c +#define LANG_DIVEHI 0x65 +#define LANG_DUTCH 0x13 +#define LANG_ENGLISH 0x09 +#define LANG_ESTONIAN 0x25 +#define LANG_FAEROESE 0x38 +#define LANG_FARSI 0x29 +#define LANG_FILIPINO 0x64 +#define LANG_FINNISH 0x0b +#define LANG_FRENCH 0x0c +#define LANG_FRISIAN 0x62 +#define LANG_GALICIAN 0x56 +#define LANG_GEORGIAN 0x37 +#define LANG_GERMAN 0x07 +#define LANG_GREEK 0x08 +#define LANG_GREENLANDIC 0x6f +#define LANG_GUJARATI 0x47 +#define LANG_HAUSA 0x68 +#define LANG_HEBREW 0x0d +#define LANG_HINDI 0x39 +#define LANG_HUNGARIAN 0x0e +#define LANG_ICELANDIC 0x0f +#define LANG_IGBO 0x70 +#define LANG_INDONESIAN 0x21 +#define LANG_INUKTITUT 0x5d +#define LANG_IRISH 0x3c +#define LANG_ITALIAN 0x10 +#define LANG_JAPANESE 0x11 +#define LANG_KANNADA 0x4b +#define LANG_KASHMIRI 0x60 +#define LANG_KAZAK 0x3f +#define LANG_KHMER 0x53 +#define LANG_KICHE 0x86 +#define LANG_KINYARWANDA 0x87 +#define LANG_KONKANI 0x57 +#define LANG_KOREAN 0x12 +#define LANG_KYRGYZ 0x40 +#define LANG_LAO 0x54 +#define LANG_LATVIAN 0x26 +#define LANG_LITHUANIAN 0x27 +#define LANG_LOWER_SORBIAN 0x2e +#define LANG_LUXEMBOURGISH 0x6e +#define LANG_MACEDONIAN 0x2f +#define LANG_MALAY 0x3e +#define LANG_MALAYALAM 0x4c +#define LANG_MALTESE 0x3a +#define LANG_MANIPURI 0x58 +#define LANG_MAORI 0x81 +#define LANG_MAPUDUNGUN 0x7a +#define LANG_MARATHI 0x4e +#define LANG_MOHAWK 0x7c +#define LANG_MONGOLIAN 0x50 +#define LANG_NEPALI 0x61 +#define LANG_NORWEGIAN 0x14 +#define LANG_OCCITAN 0x82 +#define LANG_ORIYA 0x48 +#define LANG_PASHTO 0x63 +#define LANG_PERSIAN 0x29 +#define LANG_POLISH 0x15 +#define LANG_PORTUGUESE 0x16 +#define LANG_PUNJABI 0x46 +#define LANG_QUECHUA 0x6b +#define LANG_ROMANIAN 0x18 +#define LANG_RUSSIAN 0x19 +#define LANG_SAMI 0x3b +#define LANG_ROMANSH 0x17 +#define LANG_SANSKRIT 0x4f +#define LANG_SERBIAN 0x1a +#define LANG_SERBIAN_NEUTRAL 0x7c1a +#define LANG_SINDHI 0x59 +#define LANG_SINHALESE 0x5b +#define LANG_SLOVAK 0x1b +#define LANG_SLOVENIAN 0x24 +#define LANG_SOTHO 0x6c +#define LANG_SPANISH 0x0a +#define LANG_SWAHILI 0x41 +#define LANG_SWEDISH 0x1d +#define LANG_SYRIAC 0x5a +#define LANG_TAJIK 0x28 +#define LANG_TAMAZIGHT 0x5f +#define LANG_TAMIL 0x49 +#define LANG_TATAR 0x44 +#define LANG_TELUGU 0x4a +#define LANG_THAI 0x1e +#define LANG_TIBETAN 0x51 +#define LANG_TIGRIGNA 0x73 +#define LANG_TSWANA 0x32 +#define LANG_TURKISH 0x1f +#define LANG_TURKMEN 0x42 +#define LANG_UIGHUR 0x80 +#define LANG_UKRAINIAN 0x22 +#define LANG_UPPER_SORBIAN 0x2e +#define LANG_URDU 0x20 +#define LANG_UZBEK 0x43 +#define LANG_VIETNAMESE 0x2a +#define LANG_WELSH 0x52 +#define LANG_WOLOF 0x88 +#define LANG_XHOSA 0x34 +#define LANG_YAKUT 0x85 +#define LANG_YI 0x78 +#define LANG_YORUBA 0x6a +#define LANG_ZULU 0x35 + +#define SUBLANG_NEUTRAL 0x0 +#define SUBLANG_DEFAULT 0x1 +#define SUBLANG_SYS_DEFAULT 0x2 +#define SUBLANG_CUSTOM_DEFAULT 0x3 +#define SUBLANG_CUSTOM_UNSPECIFIED 0x4 +#define SUBLANG_UI_CUSTOM_DEFAULT 0x5 + +#define SUBLANG_ARABIC_SAUDI_ARABIA 0x01 +#define SUBLANG_ARABIC_IRAQ 0x02 +#define SUBLANG_ARABIC_EGYPT 0x03 +#define SUBLANG_ARABIC_LIBYA 0x04 +#define SUBLANG_ARABIC_ALGERIA 0x05 +#define SUBLANG_ARABIC_MOROCCO 0x06 +#define SUBLANG_ARABIC_TUNISIA 0x07 +#define SUBLANG_ARABIC_OMAN 0x08 +#define SUBLANG_ARABIC_YEMEN 0x09 +#define SUBLANG_ARABIC_SYRIA 0x0a +#define SUBLANG_ARABIC_JORDAN 0x0b +#define SUBLANG_ARABIC_LEBANON 0x0c +#define SUBLANG_ARABIC_KUWAIT 0x0d +#define SUBLANG_ARABIC_UAE 0x0e +#define SUBLANG_ARABIC_BAHRAIN 0x0f +#define SUBLANG_ARABIC_QATAR 0x10 +#define SUBLANG_AZERI_LATIN 0x01 +#define SUBLANG_AZERI_CYRILLIC 0x02 +#define SUBLANG_CHINESE_TRADITIONAL 0x01 +#define SUBLANG_CHINESE_SIMPLIFIED 0x02 +#define SUBLANG_CHINESE_HONGKONG 0x03 +#define SUBLANG_CHINESE_SINGAPORE 0x04 +#define SUBLANG_CHINESE_MACAU 0x05 +#define SUBLANG_DUTCH 0x01 +#define SUBLANG_DUTCH_BELGIAN 0x02 +#define SUBLANG_ENGLISH_US 0x01 +#define SUBLANG_ENGLISH_UK 0x02 +#define SUBLANG_ENGLISH_AUS 0x03 +#define SUBLANG_ENGLISH_CAN 0x04 +#define SUBLANG_ENGLISH_NZ 0x05 +#define SUBLANG_ENGLISH_EIRE 0x06 +#define SUBLANG_ENGLISH_SOUTH_AFRICA 0x07 +#define SUBLANG_ENGLISH_JAMAICA 0x08 +#define SUBLANG_ENGLISH_CARIBBEAN 0x09 +#define SUBLANG_ENGLISH_BELIZE 0x0a +#define SUBLANG_ENGLISH_TRINIDAD 0x0b +#define SUBLANG_ENGLISH_ZIMBABWE 0x0c +#define SUBLANG_ENGLISH_PHILIPPINES 0x0d +#define SUBLANG_FRENCH 0x01 +#define SUBLANG_FRENCH_BELGIAN 0x02 +#define SUBLANG_FRENCH_CANADIAN 0x03 +#define SUBLANG_FRENCH_SWISS 0x04 +#define SUBLANG_FRENCH_LUXEMBOURG 0x05 +#define SUBLANG_FRENCH_MONACO 0x06 +#define SUBLANG_GERMAN 0x01 +#define SUBLANG_GERMAN_SWISS 0x02 +#define SUBLANG_GERMAN_AUSTRIAN 0x03 +#define SUBLANG_GERMAN_LUXEMBOURG 0x04 +#define SUBLANG_GERMAN_LIECHTENSTEIN 0x05 +#define SUBLANG_ITALIAN 0x01 +#define SUBLANG_ITALIAN_SWISS 0x02 +#define SUBLANG_KASHMIRI_SASIA 0x02 +#define SUBLANG_KASHMIRI_INDIA 0x02 +#define SUBLANG_KOREAN 0x01 +#define SUBLANG_LITHUANIAN 0x01 +#define SUBLANG_MALAY_MALAYSIA 0x01 +#define SUBLANG_MALAY_BRUNEI_DARUSSALAM 0x02 +#define SUBLANG_NEPALI_INDIA 0x02 +#define SUBLANG_NORWEGIAN_BOKMAL 0x01 +#define SUBLANG_NORWEGIAN_NYNORSK 0x02 +#define SUBLANG_PORTUGUESE 0x02 +#define SUBLANG_PORTUGUESE_BRAZILIAN 0x01 +#define SUBLANG_SERBIAN_LATIN 0x02 +#define SUBLANG_SERBIAN_CYRILLIC 0x03 +#define SUBLANG_SPANISH 0x01 +#define SUBLANG_SPANISH_MEXICAN 0x02 +#define SUBLANG_SPANISH_MODERN 0x03 +#define SUBLANG_SPANISH_GUATEMALA 0x04 +#define SUBLANG_SPANISH_COSTA_RICA 0x05 +#define SUBLANG_SPANISH_PANAMA 0x06 +#define SUBLANG_SPANISH_DOMINICAN_REPUBLIC 0x07 +#define SUBLANG_SPANISH_VENEZUELA 0x08 +#define SUBLANG_SPANISH_COLOMBIA 0x09 +#define SUBLANG_SPANISH_PERU 0x0a +#define SUBLANG_SPANISH_ARGENTINA 0x0b +#define SUBLANG_SPANISH_ECUADOR 0x0c +#define SUBLANG_SPANISH_CHILE 0x0d +#define SUBLANG_SPANISH_URUGUAY 0x0e +#define SUBLANG_SPANISH_PARAGUAY 0x0f +#define SUBLANG_SPANISH_BOLIVIA 0x10 +#define SUBLANG_SPANISH_EL_SALVADOR 0x11 +#define SUBLANG_SPANISH_HONDURAS 0x12 +#define SUBLANG_SPANISH_NICARAGUA 0x13 +#define SUBLANG_SPANISH_PUERTO_RICO 0x14 +#define SUBLANG_SWEDISH 0x01 +#define SUBLANG_SWEDISH_FINLAND 0x02 +#define SUBLANG_URDU_PAKISTAN 0x01 +#define SUBLANG_URDU_INDIA 0x02 +#define SUBLANG_UZBEK_LATIN 0x01 +#define SUBLANG_UZBEK_CYRILLIC 0x02 + +#define SORT_DEFAULT 0x0 +#define SORT_INVARIANT_MATH 0x1 + +#define SORT_JAPANESE_XJIS 0x0 +#define SORT_JAPANESE_UNICODE 0x1 +#define SORT_JAPANESE_RADICALSTROKE 0x4 + +#define SORT_CHINESE_BIG5 0x0 +#define SORT_CHINESE_PRCP 0x0 +#define SORT_CHINESE_UNICODE 0x1 +#define SORT_CHINESE_PRC 0x2 +#define SORT_CHINESE_BOPOMOFO 0x3 + +#define SORT_KOREAN_KSC 0x0 +#define SORT_KOREAN_UNICODE 0x1 + +#define SORT_GERMAN_PHONE_BOOK 0x1 + +#define SORT_HUNGARIAN_DEFAULT 0x0 +#define SORT_HUNGARIAN_TECHNICAL 0x1 + +#define SORT_GEORGIAN_TRADITIONAL 0x0 +#define SORT_GEORGIAN_MODERN 0x1 + +#define MAKELANGID(p,s) ((((WORD)(s)) << 10) | (WORD)(p)) +#define PRIMARYLANGID(lgid) ((WORD)(lgid) & 0x3ff) +#define SUBLANGID(lgid) ((WORD)(lgid) >> 10) + +#define NLS_VALID_LOCALE_MASK 0x000fffff + +#define MAKELCID(lgid,srtid) ((DWORD)((((DWORD)((WORD)(srtid))) << 16) | ((DWORD)((WORD)(lgid))))) +#define MAKESORTLCID(lgid,srtid,ver) ((DWORD)((MAKELCID(lgid,srtid)) | (((DWORD)((WORD)(ver))) << 20))) +#define LANGIDFROMLCID(lcid) ((WORD)(lcid)) +#define SORTIDFROMLCID(lcid) ((WORD)((((DWORD)(lcid)) >> 16) & 0xf)) +#define SORTVERSIONFROMLCID(lcid) ((WORD)((((DWORD)(lcid)) >> 20) & 0xf)) + +#define LOCALE_NAME_MAX_LENGTH 85 +#define LANG_SYSTEM_DEFAULT (MAKELANGID(LANG_NEUTRAL,SUBLANG_SYS_DEFAULT)) +#define LANG_USER_DEFAULT (MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT)) + +#define LOCALE_SYSTEM_DEFAULT (MAKELCID(LANG_SYSTEM_DEFAULT,SORT_DEFAULT)) +#define LOCALE_USER_DEFAULT (MAKELCID(LANG_USER_DEFAULT,SORT_DEFAULT)) + +#define LOCALE_NEUTRAL (MAKELCID(MAKELANGID(LANG_NEUTRAL,SUBLANG_NEUTRAL),SORT_DEFAULT)) + +#define LOCALE_CUSTOM_DEFAULT (MAKELCID(MAKELANGID(LANG_NEUTRAL, SUBLANG_CUSTOM_DEFAULT), SORT_DEFAULT)) +#define LOCALE_CUSTOM_UNSPECIFIED (MAKELCID(MAKELANGID(LANG_NEUTRAL, SUBLANG_CUSTOM_UNSPECIFIED), SORT_DEFAULT)) +#define LOCALE_CUSTOM_UI_DEFAULT (MAKELCID(MAKELANGID(LANG_NEUTRAL, SUBLANG_UI_CUSTOM_DEFAULT), SORT_DEFAULT)) + +#define LOCALE_INVARIANT (MAKELCID(MAKELANGID(LANG_INVARIANT,SUBLANG_NEUTRAL),SORT_DEFAULT)) + +#define UNREFERENCED_PARAMETER(P) (P) +#define DBG_UNREFERENCED_PARAMETER(P) (P) +#define DBG_UNREFERENCED_LOCAL_VARIABLE(V) (V) + +#define DEFAULT_UNREACHABLE + +#ifndef WIN32_NO_STATUS +#define STATUS_WAIT_0 ((DWORD)0x00000000L) +#define STATUS_ABANDONED_WAIT_0 ((DWORD)0x00000080L) +#define STATUS_USER_APC ((DWORD)0x000000C0L) +#define STATUS_TIMEOUT ((DWORD)0x00000102L) +#define STATUS_PENDING ((DWORD)0x00000103L) +#define DBG_EXCEPTION_HANDLED ((DWORD)0x00010001L) +#define DBG_CONTINUE ((DWORD)0x00010002L) +#define STATUS_SEGMENT_NOTIFICATION ((DWORD)0x40000005L) +#define DBG_TERMINATE_THREAD ((DWORD)0x40010003L) +#define DBG_TERMINATE_PROCESS ((DWORD)0x40010004L) +#define DBG_CONTROL_C ((DWORD)0x40010005L) +#define DBG_CONTROL_BREAK ((DWORD)0x40010008L) +#define DBG_COMMAND_EXCEPTION ((DWORD)0x40010009L) +#define STATUS_GUARD_PAGE_VIOLATION ((DWORD)0x80000001L) +#define STATUS_DATATYPE_MISALIGNMENT ((DWORD)0x80000002L) +#define STATUS_BREAKPOINT ((DWORD)0x80000003L) +#define STATUS_SINGLE_STEP ((DWORD)0x80000004L) +#define DBG_EXCEPTION_NOT_HANDLED ((DWORD)0x80010001L) +#define STATUS_ACCESS_VIOLATION ((DWORD)0xC0000005L) +#define STATUS_IN_PAGE_ERROR ((DWORD)0xC0000006L) +#define STATUS_INVALID_HANDLE ((DWORD)0xC0000008L) +#define STATUS_NO_MEMORY ((DWORD)0xC0000017L) +#define STATUS_ILLEGAL_INSTRUCTION ((DWORD)0xC000001DL) +#define STATUS_NONCONTINUABLE_EXCEPTION ((DWORD)0xC0000025L) +#define STATUS_INVALID_DISPOSITION ((DWORD)0xC0000026L) +#define STATUS_ARRAY_BOUNDS_EXCEEDED ((DWORD)0xC000008CL) +#define STATUS_FLOAT_DENORMAL_OPERAND ((DWORD)0xC000008DL) +#define STATUS_FLOAT_DIVIDE_BY_ZERO ((DWORD)0xC000008EL) +#define STATUS_FLOAT_INEXACT_RESULT ((DWORD)0xC000008FL) +#define STATUS_FLOAT_INVALID_OPERATION ((DWORD)0xC0000090L) +#define STATUS_FLOAT_OVERFLOW ((DWORD)0xC0000091L) +#define STATUS_FLOAT_STACK_CHECK ((DWORD)0xC0000092L) +#define STATUS_FLOAT_UNDERFLOW ((DWORD)0xC0000093L) +#define STATUS_INTEGER_DIVIDE_BY_ZERO ((DWORD)0xC0000094L) +#define STATUS_INTEGER_OVERFLOW ((DWORD)0xC0000095L) +#define STATUS_PRIVILEGED_INSTRUCTION ((DWORD)0xC0000096L) +#define STATUS_STACK_OVERFLOW ((DWORD)0xC00000FDL) +#define STATUS_CONTROL_C_EXIT ((DWORD)0xC000013AL) +#define STATUS_FLOAT_MULTIPLE_FAULTS ((DWORD)0xC00002B4L) +#define STATUS_FLOAT_MULTIPLE_TRAPS ((DWORD)0xC00002B5L) +#define STATUS_REG_NAT_CONSUMPTION ((DWORD)0xC00002C9L) +#define STATUS_SXS_EARLY_DEACTIVATION ((DWORD)0xC015000FL) +#define STATUS_SXS_INVALID_DEACTIVATION ((DWORD)0xC0150010L) +#endif + +#define MAXIMUM_WAIT_OBJECTS 64 +#define MAXIMUM_SUSPEND_COUNT MAXCHAR + + typedef ULONG_PTR KSPIN_LOCK; + typedef KSPIN_LOCK *PKSPIN_LOCK; + +#ifdef _AMD64_ + +#if defined(__x86_64) && !defined(RC_INVOKED) + +#ifdef __cplusplus + extern "C" { +#endif + +#define BitTest _bittest +#define BitTestAndComplement _bittestandcomplement +#define BitTestAndSet _bittestandset +#define BitTestAndReset _bittestandreset +#define InterlockedBitTestAndSet _interlockedbittestandset +#define InterlockedBitTestAndReset _interlockedbittestandreset +#define BitTest64 _bittest64 +#define BitTestAndComplement64 _bittestandcomplement64 +#define BitTestAndSet64 _bittestandset64 +#define BitTestAndReset64 _bittestandreset64 +#define InterlockedBitTestAndSet64 _interlockedbittestandset64 +#define InterlockedBitTestAndReset64 _interlockedbittestandreset64 + + __CRT_INLINE BOOLEAN _bittest(LONG const *Base,LONG Offset) { + int old = 0; + __asm__ __volatile__("btl %2,%1\n\tsbbl %0,%0 " + :"=r" (old),"=m" ((*(volatile long *) Base)) + :"Ir" (Offset)); + return (BOOLEAN) (old!=0); + } + __CRT_INLINE BOOLEAN _bittestandcomplement(LONG *Base,LONG Offset) { + int old = 0; + __asm__ __volatile__("btcl %2,%1\n\tsbbl %0,%0 " + :"=r" (old),"=m" ((*(volatile long *) Base)) + :"Ir" (Offset)); + return (BOOLEAN) (old!=0); + } + __CRT_INLINE BOOLEAN InterlockedBitTestAndComplement(LONG *Base,LONG Bit) { + int old = 0; + __asm__ __volatile__("lock ; btcl %2,%1\n\tsbbl %0,%0 " + :"=r" (old),"=m" ((*(volatile long *) Base)) + :"Ir" (Bit)); + return (BOOLEAN) (old!=0); + } + __CRT_INLINE BOOLEAN _bittestandset(LONG *Base,LONG Offset) { + int old = 0; + __asm__ __volatile__("btsl %2,%1\n\tsbbl %0,%0 " + :"=r" (old),"=m" ((*(volatile long *) Base)) + :"Ir" (Offset)); + return (BOOLEAN) (old!=0); + } + __CRT_INLINE BOOLEAN _bittestandreset(LONG *Base,LONG Offset) { + int old = 0; + __asm__ __volatile__("btrl %2,%1\n\tsbbl %0,%0 " + :"=r" (old),"=m" ((*(volatile long *) Base)) + :"Ir" (Offset)); + return (BOOLEAN) (old!=0); + } + __CRT_INLINE BOOLEAN _interlockedbittestandset(LONG *Base,LONG Offset) { + int old = 0; + __asm__ __volatile__("lock ; btsl %2,%1\n\tsbbl %0,%0 " + :"=r" (old),"=m" ((*(volatile long *) Base)) + :"Ir" (Offset)); + return (BOOLEAN) (old!=0); + } + __CRT_INLINE BOOLEAN _interlockedbittestandreset(LONG *Base,LONG Offset) { + int old = 0; + __asm__ __volatile__("lock ; btrl %2,%1\n\tsbbl %0,%0 " + :"=r" (old),"=m" ((*(volatile long *) Base)) + :"Ir" (Offset)); + return (BOOLEAN) (old!=0); + } + __CRT_INLINE BOOLEAN _bittest64(LONG64 const *Base,LONG64 Offset) { + int old = 0; + __asm__ __volatile__("btq %2,%1\n\tsbbl %0,%0 " + :"=r" (old),"=m" ((*(volatile long long *) Base)) + :"Ir" (Offset)); + return (BOOLEAN) (old!=0); + } + __CRT_INLINE BOOLEAN _bittestandcomplement64(LONG64 *Base,LONG64 Offset) { + int old = 0; + __asm__ __volatile__("btcq %2,%1\n\tsbbl %0,%0 " + :"=r" (old),"=m" ((*(volatile long long *) Base)) + :"Ir" (Offset)); + return (BOOLEAN) (old!=0); + } + __CRT_INLINE BOOLEAN _bittestandset64(LONG64 *Base,LONG64 Offset) { + int old = 0; + __asm__ __volatile__("btsq %2,%1\n\tsbbl %0,%0 " + :"=r" (old),"=m" ((*(volatile long long *) Base)) + :"Ir" (Offset)); + return (BOOLEAN) (old!=0); + } + __CRT_INLINE BOOLEAN _bittestandreset64(LONG64 *Base,LONG64 Offset) { + int old = 0; + __asm__ __volatile__("btrq %2,%1\n\tsbbl %0,%0 " + :"=r" (old),"=m" ((*(volatile long long *) Base)) + :"Ir" (Offset)); + return (BOOLEAN) (old!=0); + } + __CRT_INLINE BOOLEAN _interlockedbittestandset64(LONG64 *Base,LONG64 Offset) { + int old = 0; + __asm__ __volatile__("lock ; btsq %2,%1\n\tsbbl %0,%0 " + :"=r" (old),"=m" ((*(volatile long long *) Base)) + :"Ir" (Offset)); + return (BOOLEAN) (old!=0); + } + __CRT_INLINE BOOLEAN _interlockedbittestandreset64(LONG64 *Base,LONG64 Offset) { + int old = 0; + __asm__ __volatile__("lock ; btrq %2,%1\n\tsbbl %0,%0 " + :"=r" (old),"=m" ((*(volatile long long *) Base)) + :"Ir" (Offset)); + return (BOOLEAN) (old!=0); + } +#define BitScanForward _BitScanForward +#define BitScanReverse _BitScanReverse +#define BitScanForward64 _BitScanForward64 +#define BitScanReverse64 _BitScanReverse64 + + __CRT_INLINE BOOLEAN _BitScanForward(DWORD *Index,DWORD Mask) { + __asm__ __volatile__("bsfl %1,%0" : "=r" (Mask),"=m" ((*(volatile long *)Index))); + return Mask!=0; + } + __CRT_INLINE BOOLEAN _BitScanReverse(DWORD *Index,DWORD Mask) { + __asm__ __volatile__("bsrl %1,%0" : "=r" (Mask),"=m" ((*(volatile long *)Index))); + return Mask!=0; + } + __CRT_INLINE BOOLEAN _BitScanForward64(DWORD *Index,DWORD64 Mask) { + __asm__ __volatile__("bsfq %1,%0" : "=r" (Mask),"=m" ((*(volatile long long *)Index))); + return Mask!=0; + } + __CRT_INLINE BOOLEAN _BitScanReverse64(DWORD *Index,DWORD64 Mask) { + __asm__ __volatile__("bsrq %1,%0" : "=r" (Mask),"=m" ((*(volatile long long *)Index))); + return Mask!=0; + } + +#define InterlockedIncrement16 _InterlockedIncrement16 +#define InterlockedDecrement16 _InterlockedDecrement16 +#define InterlockedCompareExchange16 _InterlockedCompareExchange16 + +#define InterlockedAnd _InterlockedAnd +#define InterlockedOr _InterlockedOr +#define InterlockedXor _InterlockedXor +#define InterlockedIncrement _InterlockedIncrement +#define InterlockedIncrementAcquire InterlockedIncrement +#define InterlockedIncrementRelease InterlockedIncrement +#define InterlockedDecrement _InterlockedDecrement +#define InterlockedDecrementAcquire InterlockedDecrement +#define InterlockedDecrementRelease InterlockedDecrement +#define InterlockedAdd _InterlockedAdd +#define InterlockedExchange _InterlockedExchange +#define InterlockedExchangeAdd _InterlockedExchangeAdd +#define InterlockedCompareExchange _InterlockedCompareExchange +#define InterlockedCompareExchangeAcquire InterlockedCompareExchange +#define InterlockedCompareExchangeRelease InterlockedCompareExchange + +#define InterlockedAnd64 _InterlockedAnd64 +#define InterlockedAndAffinity InterlockedAnd64 +#define InterlockedOr64 _InterlockedOr64 +#define InterlockedOrAffinity InterlockedOr64 +#define InterlockedXor64 _InterlockedXor64 +#define InterlockedIncrement64 _InterlockedIncrement64 +#define InterlockedDecrement64 _InterlockedDecrement64 +#define InterlockedAdd64 _InterlockedAdd64 +#define InterlockedExchange64 _InterlockedExchange64 +#define InterlockedExchangeAcquire64 InterlockedExchange64 +#define InterlockedExchangeAdd64 _InterlockedExchangeAdd64 +#define InterlockedCompareExchange64 _InterlockedCompareExchange64 +#define InterlockedCompareExchangeAcquire64 InterlockedCompareExchange64 +#define InterlockedCompareExchangeRelease64 InterlockedCompareExchange64 + +#define InterlockedExchangePointer _InterlockedExchangePointer +#define InterlockedCompareExchangePointer _InterlockedCompareExchangePointer +#define InterlockedCompareExchangePointerAcquire _InterlockedCompareExchangePointer +#define InterlockedCompareExchangePointerRelease _InterlockedCompareExchangePointer + +#define InterlockedExchangeAddSizeT(a,b) InterlockedExchangeAdd64((LONG64 *)a,b) +#define InterlockedIncrementSizeT(a) InterlockedIncrement64((LONG64 *)a) +#define InterlockedDecrementSizeT(a) InterlockedDecrement64((LONG64 *)a) + + __CRT_INLINE SHORT InterlockedIncrement16(SHORT volatile *Addend) { + unsigned char c; + unsigned char s; + __asm__ __volatile__( + "lock ; addw $1,%0; sete %1 ; sets %2" + :"=m" (*Addend), "=qm" (c), "=qm" (s) + :"m" (*Addend) : "memory"); + return (c != 0 ? 0 : (s != 0 ? -1 : 1)); + } + __CRT_INLINE SHORT InterlockedDecrement16(SHORT volatile *Addend) { + unsigned char c; + unsigned char s; + __asm__ __volatile__( + "lock ; subw $1,%0; sete %1 ; sets %2" + :"=m" (*Addend), "=qm" (c), "=qm" (s) + :"m" (*Addend) : "memory"); + return (c != 0 ? 0 : (s != 0 ? -1 : 1)); + } + __CRT_INLINE SHORT InterlockedCompareExchange16(SHORT volatile *Destination,SHORT ExChange,SHORT Comperand) { + SHORT prev; + __asm__ __volatile__("lock ; cmpxchgw %w1,%2" + :"=a"(prev) + :"q"(ExChange), "m"(*Destination), "0"(Comperand) + : "memory"); + return prev; + } + __CRT_INLINE LONG InterlockedAnd(LONG volatile *Destination,LONG Value) { + __asm__ __volatile__("lock ; andl %0,%1" + : :"r"(Value),"m"(*Destination) + : "memory"); + return *Destination; + } + __CRT_INLINE LONG InterlockedOr(LONG volatile *Destination,LONG Value) { + __asm__ __volatile__("lock ; orl %0,%1" + : : "r"(Value),"m"(*Destination) : "memory"); + return *Destination; + } + __CRT_INLINE LONG InterlockedXor(LONG volatile *Destination,LONG Value) { + __asm__ __volatile__("lock ; xorl %0,%1" + : : "r"(Value),"m"(*Destination) : "memory"); + return *Destination; + } + // $$$$ + __CRT_INLINE LONG64 InterlockedAnd64(LONG64 volatile *Destination,LONG64 Value) { + __asm__ __volatile__("lock ; andq %0,%1" + : : "r"(Value),"m"(*Destination) : "memory"); + return *Destination; + } + __CRT_INLINE LONG64 InterlockedOr64(LONG64 volatile *Destination,LONG64 Value) { + __asm__ __volatile__("lock ; orq %0,%1" + : : "r"(Value),"m"(*Destination) : "memory"); + return *Destination; + } + __CRT_INLINE LONG64 InterlockedXor64(LONG64 volatile *Destination,LONG64 Value) { + __asm__ __volatile__("lock ; xorq %0,%1" + : : "r"(Value),"m"(*Destination) : "memory"); + return *Destination; + } + __CRT_INLINE LONG InterlockedIncrement(LONG volatile *Addend) { + unsigned char c; + unsigned char s; + __asm__ __volatile__( + "lock ; addl $1,%0; sete %1 ; sets %2" + :"=m" (*Addend), "=qm" (c), "=qm" (s) + :"m" (*Addend) : "memory"); + return (c != 0 ? 0 : (s != 0 ? -1 : 1)); + } + __CRT_INLINE LONG InterlockedDecrement(LONG volatile *Addend) { + unsigned char c; + unsigned char s; + __asm__ __volatile__( + "lock ; subl $1,%0; sete %1 ; sets %2" + :"=m" (*Addend), "=qm" (c), "=qm" (s) + :"m" (*Addend) : "memory"); + return (c != 0 ? 0 : (s != 0 ? -1 : 1)); + } + __CRT_INLINE LONG InterlockedExchange(LONG volatile *Target,LONG Value) { + __asm__ __volatile("lock ; xchgl %0,%1" + : "=r"(Value) + : "m"(*Target),"0"(Value) + : "memory"); + return Value; + } + LONG InterlockedExchangeAdd(LONG volatile *Addend,LONG Value); + +#ifndef _X86AMD64_ + __CRT_INLINE LONG InterlockedAdd(LONG volatile *Addend,LONG Value) { return InterlockedExchangeAdd(Addend,Value) + Value; } +#endif + __CRT_INLINE LONG InterlockedCompareExchange(LONG volatile *Destination,LONG ExChange,LONG Comperand) { + LONG prev; + __asm__ __volatile__("lock ; cmpxchgl %1,%2" : "=a" (prev) : "q" (ExChange),"m" (*Destination), "0" (Comperand) : "memory"); + return prev; + } + __CRT_INLINE LONG64 InterlockedIncrement64(LONG64 volatile *Addend) { + unsigned char c; + unsigned char s; + __asm__ __volatile__( + "lock ; addq $1,%0; sete %1 ; sets %2" + :"=m" (*Addend), "=qm" (c), "=qm" (s) + :"m" (*Addend) : "memory"); + return (c != 0 ? 0 : (s != 0 ? -1 : 1)); + } + __CRT_INLINE LONG64 InterlockedDecrement64(LONG64 volatile *Addend) { + unsigned char c; + unsigned char s; + __asm__ __volatile__( + "lock ; subq $1,%0; sete %1 ; sets %2" + :"=m" (*Addend), "=qm" (c), "=qm" (s) + :"m" (*Addend) : "memory"); + return (c != 0 ? 0 : (s != 0 ? -1 : 1)); + } + __CRT_INLINE LONG64 InterlockedExchange64(LONG64 volatile *Target,LONG64 Value) { + __asm__ __volatile("lock ; xchgq %0,%1" + : "=r"(Value) + : "m"(*Target),"0"(Value) + : "memory"); + return Value; + } + LONG64 InterlockedExchangeAdd64(LONG64 volatile *Addend,LONG64 Value); + +#ifndef _X86AMD64_ + __CRT_INLINE LONG64 InterlockedAdd64(LONG64 volatile *Addend,LONG64 Value) { return InterlockedExchangeAdd64(Addend,Value) + Value; } +#endif + + __CRT_INLINE LONG64 InterlockedCompareExchange64(LONG64 volatile *Destination,LONG64 ExChange,LONG64 Comperand) { + LONG64 prev; + __asm__ __volatile__("lock ; cmpxchgq %1,%2" : "=a" (prev) : "q" (ExChange),"m" (*Destination), "0" (Comperand) : "memory"); + return prev; + } + __CRT_INLINE PVOID InterlockedCompareExchangePointer(PVOID volatile *Destination,PVOID ExChange,PVOID Comperand) { + PVOID prev; + __asm__ __volatile__("lock ; cmpxchgq %1,%2" : "=a" (prev) : "q" (ExChange),"m" (*Destination), "0" (Comperand) : "memory"); + return prev; + } + __CRT_INLINE PVOID InterlockedExchangePointer(PVOID volatile *Target,PVOID Value) { + __asm__ __volatile("lock ; xchgq %0,%1" + : "=r"(Value) + : "m"(*Target),"0"(Value) + : "memory"); + return Value; + } + +#define CacheLineFlush(Address) _mm_clflush(Address) + + VOID _ReadWriteBarrier(VOID); + +#define FastFence __faststorefence +#define LoadFence _mm_lfence +#define MemoryFence _mm_mfence +#define StoreFence _mm_sfence + + VOID __faststorefence(VOID); + VOID _m_prefetchw(volatile CONST VOID *Source); + +//!__TINYC__: #include + +#define YieldProcessor _mm_pause +#define MemoryBarrier __faststorefence +#define PreFetchCacheLine(l,a) _mm_prefetch((CHAR CONST *) a,l) +#define PrefetchForWrite(p) _m_prefetchw(p) +#define ReadForWriteAccess(p) (_m_prefetchw(p),*(p)) + +#define PF_TEMPORAL_LEVEL_1 _MM_HINT_T0 +#define PF_TEMPORAL_LEVEL_2 _MM_HINT_T1 +#define PF_TEMPORAL_LEVEL_3 _MM_HINT_T2 +#define PF_NON_TEMPORAL_LEVEL_ALL _MM_HINT_NTA + +#define ReadMxCsr _mm_getcsr +#define WriteMxCsr _mm_setcsr + + VOID __int2c(VOID); + +#define DbgRaiseAssertionFailure() __int2c() +#define GetCallersEflags() __getcallerseflags() + + unsigned __int32 __getcallerseflags(VOID); + +#define GetSegmentLimit __segmentlimit + + DWORD __segmentlimit(DWORD Selector); + +#define ReadTimeStampCounter() __rdtsc() + + DWORD64 __rdtsc(VOID); + VOID __movsb(PBYTE Destination,BYTE const *Source,SIZE_T Count); + VOID __movsw(PWORD Destination,WORD const *Source,SIZE_T Count); + VOID __movsd(PDWORD Destination,DWORD const *Source,SIZE_T Count); + VOID __movsq(PDWORD64 Destination,DWORD64 const *Source,SIZE_T Count); + VOID __stosb(PBYTE Destination,BYTE Value,SIZE_T Count); + VOID __stosw(PWORD Destination,WORD Value,SIZE_T Count); + VOID __stosd(PDWORD Destination,DWORD Value,SIZE_T Count); + VOID __stosq(PDWORD64 Destination,DWORD64 Value,SIZE_T Count); + +#define MultiplyHigh __mulh +#define UnsignedMultiplyHigh __umulh + + LONGLONG MultiplyHigh(LONGLONG Multiplier,LONGLONG Multiplicand); + ULONGLONG UnsignedMultiplyHigh(ULONGLONG Multiplier,ULONGLONG Multiplicand); + +#define ShiftLeft128 __shiftleft128 +#define ShiftRight128 __shiftright128 + + DWORD64 ShiftLeft128(DWORD64 LowPart,DWORD64 HighPart,BYTE Shift); + DWORD64 ShiftRight128(DWORD64 LowPart,DWORD64 HighPart,BYTE Shift); + +#define Multiply128 _mul128 + + LONG64 Multiply128(LONG64 Multiplier,LONG64 Multiplicand,LONG64 *HighProduct); + +#define UnsignedMultiply128 _umul128 + + DWORD64 UnsignedMultiply128(DWORD64 Multiplier,DWORD64 Multiplicand,DWORD64 *HighProduct); + + __CRT_INLINE LONG64 MultiplyExtract128(LONG64 Multiplier,LONG64 Multiplicand,BYTE Shift) { + LONG64 extractedProduct; + LONG64 highProduct; + LONG64 lowProduct; + lowProduct = Multiply128(Multiplier,Multiplicand,&highProduct); + extractedProduct = (LONG64)ShiftRight128((LONG64)lowProduct,(LONG64)highProduct,Shift); + return extractedProduct; + } + + __CRT_INLINE DWORD64 UnsignedMultiplyExtract128(DWORD64 Multiplier,DWORD64 Multiplicand,BYTE Shift) { + DWORD64 extractedProduct; + DWORD64 highProduct; + DWORD64 lowProduct; + lowProduct = UnsignedMultiply128(Multiplier,Multiplicand,&highProduct); + extractedProduct = ShiftRight128(lowProduct,highProduct,Shift); + return extractedProduct; + } + + __CRT_INLINE BYTE __readgsbyte(DWORD Offset) { + BYTE ret; + __asm__ volatile ("movb %%gs:%1,%0" + : "=r" (ret) ,"=m" ((*(volatile long *) (DWORD64) Offset))); + return ret; + } + __CRT_INLINE WORD __readgsword(DWORD Offset) { + WORD ret; + __asm__ volatile ("movw %%gs:%1,%0" + : "=r" (ret) ,"=m" ((*(volatile long *) (DWORD64) Offset))); + return ret; + } + __CRT_INLINE DWORD __readgsdword(DWORD Offset) { + DWORD ret; + __asm__ volatile ("movl %%gs:%1,%0" + : "=r" (ret) ,"=m" ((*(volatile long *) (DWORD64) Offset))); + return ret; + } + __CRT_INLINE DWORD64 __readgsqword(DWORD Offset) { + void *ret; + __asm__ volatile ("movq %%gs:%1,%0" + : "=r" (ret) ,"=m" ((*(volatile long *) (DWORD64) Offset))); + return (DWORD64) ret; + } + __CRT_INLINE VOID __writegsbyte(DWORD Offset,BYTE Data) { + __asm__ volatile ("movb %0,%%gs:%1" + : "=r" (Data) ,"=m" ((*(volatile long *) (DWORD64) Offset))); + } + __CRT_INLINE VOID __writegsword(DWORD Offset,WORD Data) { + __asm__ volatile ("movw %0,%%gs:%1" + : "=r" (Data) ,"=m" ((*(volatile long *) (DWORD64) Offset))); + } + __CRT_INLINE VOID __writegsdword(DWORD Offset,DWORD Data) { + __asm__ volatile ("movl %0,%%gs:%1" + : "=r" (Data) ,"=m" ((*(volatile long *) (DWORD64) Offset))); + } + __CRT_INLINE VOID __writegsqword(DWORD Offset,DWORD64 Data) { + __asm__ volatile ("movq %0,%%gs:%1" + : "=r" (Data) ,"=m" ((*(volatile long *) (DWORD64) Offset))); + } + +#ifdef __cplusplus + } +#endif +#endif + +#define EXCEPTION_READ_FAULT 0 +#define EXCEPTION_WRITE_FAULT 1 +#define EXCEPTION_EXECUTE_FAULT 8 + +#if !defined(RC_INVOKED) + +#define CONTEXT_AMD64 0x100000 + +#define CONTEXT_CONTROL (CONTEXT_AMD64 | 0x1L) +#define CONTEXT_INTEGER (CONTEXT_AMD64 | 0x2L) +#define CONTEXT_SEGMENTS (CONTEXT_AMD64 | 0x4L) +#define CONTEXT_FLOATING_POINT (CONTEXT_AMD64 | 0x8L) +#define CONTEXT_DEBUG_REGISTERS (CONTEXT_AMD64 | 0x10L) + +#define CONTEXT_FULL (CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_FLOATING_POINT) +#define CONTEXT_ALL (CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS | CONTEXT_FLOATING_POINT | CONTEXT_DEBUG_REGISTERS) + +#define CONTEXT_EXCEPTION_ACTIVE 0x8000000 +#define CONTEXT_SERVICE_ACTIVE 0x10000000 +#define CONTEXT_EXCEPTION_REQUEST 0x40000000 +#define CONTEXT_EXCEPTION_REPORTING 0x80000000 +#endif + +#define INITIAL_MXCSR 0x1f80 +#define INITIAL_FPCSR 0x027f + + typedef DECLSPEC_ALIGN(16) struct _M128A { + ULONGLONG Low; + LONGLONG High; + } M128A,*PM128A; + + typedef struct _XMM_SAVE_AREA32 { + WORD ControlWord; + WORD StatusWord; + BYTE TagWord; + BYTE Reserved1; + WORD ErrorOpcode; + DWORD ErrorOffset; + WORD ErrorSelector; + WORD Reserved2; + DWORD DataOffset; + WORD DataSelector; + WORD Reserved3; + DWORD MxCsr; + DWORD MxCsr_Mask; + M128A FloatRegisters[8]; + M128A XmmRegisters[16]; + BYTE Reserved4[96]; + } XMM_SAVE_AREA32,*PXMM_SAVE_AREA32; + +#define LEGACY_SAVE_AREA_LENGTH sizeof(XMM_SAVE_AREA32) + + typedef DECLSPEC_ALIGN(16) struct _CONTEXT { + DWORD64 P1Home; + DWORD64 P2Home; + DWORD64 P3Home; + DWORD64 P4Home; + DWORD64 P5Home; + DWORD64 P6Home; + DWORD ContextFlags; + DWORD MxCsr; + WORD SegCs; + WORD SegDs; + WORD SegEs; + WORD SegFs; + WORD SegGs; + WORD SegSs; + DWORD EFlags; + DWORD64 Dr0; + DWORD64 Dr1; + DWORD64 Dr2; + DWORD64 Dr3; + DWORD64 Dr6; + DWORD64 Dr7; + DWORD64 Rax; + DWORD64 Rcx; + DWORD64 Rdx; + DWORD64 Rbx; + DWORD64 Rsp; + DWORD64 Rbp; + DWORD64 Rsi; + DWORD64 Rdi; + DWORD64 R8; + DWORD64 R9; + DWORD64 R10; + DWORD64 R11; + DWORD64 R12; + DWORD64 R13; + DWORD64 R14; + DWORD64 R15; + DWORD64 Rip; + union { + XMM_SAVE_AREA32 FltSave; + XMM_SAVE_AREA32 FloatSave; + struct { + M128A Header[2]; + M128A Legacy[8]; + M128A Xmm0; + M128A Xmm1; + M128A Xmm2; + M128A Xmm3; + M128A Xmm4; + M128A Xmm5; + M128A Xmm6; + M128A Xmm7; + M128A Xmm8; + M128A Xmm9; + M128A Xmm10; + M128A Xmm11; + M128A Xmm12; + M128A Xmm13; + M128A Xmm14; + M128A Xmm15; + }; + }; + M128A VectorRegister[26]; + DWORD64 VectorControl; + DWORD64 DebugControl; + DWORD64 LastBranchToRip; + DWORD64 LastBranchFromRip; + DWORD64 LastExceptionToRip; + DWORD64 LastExceptionFromRip; + } CONTEXT,*PCONTEXT; + +#define RUNTIME_FUNCTION_INDIRECT 0x1 + + typedef struct _RUNTIME_FUNCTION { + DWORD BeginAddress; + DWORD EndAddress; + DWORD UnwindData; + } RUNTIME_FUNCTION,*PRUNTIME_FUNCTION; + + typedef PRUNTIME_FUNCTION (*PGET_RUNTIME_FUNCTION_CALLBACK)(DWORD64 ControlPc,PVOID Context); + typedef DWORD (*POUT_OF_PROCESS_FUNCTION_TABLE_CALLBACK)(HANDLE Process,PVOID TableAddress,PDWORD Entries,PRUNTIME_FUNCTION *Functions); + +#define OUT_OF_PROCESS_FUNCTION_TABLE_CALLBACK_EXPORT_NAME "OutOfProcessFunctionTableCallback" + + NTSYSAPI VOID __cdecl RtlRestoreContext (PCONTEXT ContextRecord,struct _EXCEPTION_RECORD *ExceptionRecord); + NTSYSAPI BOOLEAN __cdecl RtlAddFunctionTable(PRUNTIME_FUNCTION FunctionTable,DWORD EntryCount,DWORD64 BaseAddress); + NTSYSAPI BOOLEAN __cdecl RtlInstallFunctionTableCallback(DWORD64 TableIdentifier,DWORD64 BaseAddress,DWORD Length,PGET_RUNTIME_FUNCTION_CALLBACK Callback,PVOID Context,PCWSTR OutOfProcessCallbackDll); + NTSYSAPI BOOLEAN __cdecl RtlDeleteFunctionTable(PRUNTIME_FUNCTION FunctionTable); +#endif + +#ifdef I_X86_ +#if(defined(_X86_) && !defined(__x86_64)) && !defined(RC_INVOKED) +#ifdef __cplusplus + extern "C" { +#endif + + __CRT_INLINE BOOLEAN InterlockedBitTestAndSet(LONG *Base,LONG Bit) { + int old = 0; + __asm__ __volatile__("lock ; btsl %2,%1\n\tsbbl %0,%0 " + :"=r" (old),"=m" ((*(volatile long *) Base)) + :"Ir" (Bit)); + return (BOOLEAN) (old!=0); + } + + __CRT_INLINE BOOLEAN InterlockedBitTestAndReset(LONG *Base,LONG Bit) { + int old = 0; + __asm__ __volatile__("lock ; btrl %2,%1\n\tsbbl %0,%0 " + :"=r" (old),"=m" ((*(volatile long *) Base)) + :"Ir" (Bit)); + return (BOOLEAN) (old!=0); + } + + __CRT_INLINE BOOLEAN InterlockedBitTestAndComplement(LONG *Base,LONG Bit) { + int old = 0; + __asm__ __volatile__("lock ; btcl %2,%1\n\tsbbl %0,%0 " + :"=r" (old),"=m" ((*(volatile long *) Base)) + :"Ir" (Bit)); + return (BOOLEAN) (old!=0); + } + +#ifdef _PREFIX_ + BYTE __readfsbyte(DWORD Offset); + WORD __readfsword(DWORD Offset); + DWORD __readfsdword(DWORD Offset); + VOID __writefsbyte(DWORD Offset,BYTE Data); + VOID __writefsword(DWORD Offset,WORD Data); + VOID __writefsdword(DWORD Offset,DWORD Data); +#endif + +#ifdef __cplusplus + } +#endif +#endif + +#if(defined(_X86_) && !defined(__x86_64)) + __CRT_INLINE VOID MemoryBarrier(VOID) { + LONG Barrier; + __asm__ __volatile__("xchgl %eax,%0 " + :"=r" (Barrier)); + } +#define YieldProcessor() __asm__ __volatile__("rep nop "); + +#define PreFetchCacheLine(l,a) +#define ReadForWriteAccess(p) (*(p)) + +#define PF_TEMPORAL_LEVEL_1 +#define PF_NON_TEMPORAL_LEVEL_ALL + + __CRT_INLINE VOID DbgRaiseAssertionFailure(void) { + __asm__ __volatile__("int 0x2c "); + } + PVOID GetCurrentFiber(void); + __CRT_INLINE PVOID GetCurrentFiber(void) + { + void *ret; + __asm__ volatile ("movl %%fs:0x10,%0" + : "=r" (ret)); + return ret; + } + PVOID GetFiberData(void); + __CRT_INLINE PVOID GetFiberData(void) + { + void *ret; + __asm__ volatile ("movl %%fs:0x10,%0\n" + "movl (%0),%0" + : "=r" (ret)); + return ret; + } +#endif + +#define EXCEPTION_READ_FAULT 0 +#define EXCEPTION_WRITE_FAULT 1 +#define EXCEPTION_EXECUTE_FAULT 8 + +#define SIZE_OF_80387_REGISTERS 80 + +#if !defined(RC_INVOKED) + +#define CONTEXT_i386 0x00010000 +#define CONTEXT_i486 0x00010000 + +#define CONTEXT_CONTROL (CONTEXT_i386 | 0x00000001L) +#define CONTEXT_INTEGER (CONTEXT_i386 | 0x00000002L) +#define CONTEXT_SEGMENTS (CONTEXT_i386 | 0x00000004L) +#define CONTEXT_FLOATING_POINT (CONTEXT_i386 | 0x00000008L) +#define CONTEXT_DEBUG_REGISTERS (CONTEXT_i386 | 0x00000010L) +#define CONTEXT_EXTENDED_REGISTERS (CONTEXT_i386 | 0x00000020L) + +#define CONTEXT_FULL (CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS) + +#define CONTEXT_ALL (CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS | CONTEXT_FLOATING_POINT | CONTEXT_DEBUG_REGISTERS | CONTEXT_EXTENDED_REGISTERS) +#endif + +#define MAXIMUM_SUPPORTED_EXTENSION 512 + + typedef struct _FLOATING_SAVE_AREA { + DWORD ControlWord; + DWORD StatusWord; + DWORD TagWord; + DWORD ErrorOffset; + DWORD ErrorSelector; + DWORD DataOffset; + DWORD DataSelector; + BYTE RegisterArea[SIZE_OF_80387_REGISTERS]; + DWORD Cr0NpxState; + } FLOATING_SAVE_AREA; + + typedef FLOATING_SAVE_AREA *PFLOATING_SAVE_AREA; + + typedef struct _CONTEXT { + DWORD ContextFlags; + DWORD Dr0; + DWORD Dr1; + DWORD Dr2; + DWORD Dr3; + DWORD Dr6; + DWORD Dr7; + FLOATING_SAVE_AREA FloatSave; + DWORD SegGs; + DWORD SegFs; + DWORD SegEs; + DWORD SegDs; + + DWORD Edi; + DWORD Esi; + DWORD Ebx; + DWORD Edx; + DWORD Ecx; + DWORD Eax; + DWORD Ebp; + DWORD Eip; + DWORD SegCs; + DWORD EFlags; + DWORD Esp; + DWORD SegSs; + BYTE ExtendedRegisters[MAXIMUM_SUPPORTED_EXTENSION]; + } CONTEXT; + + typedef CONTEXT *PCONTEXT; +#endif + +#ifndef _LDT_ENTRY_DEFINED +#define _LDT_ENTRY_DEFINED + + typedef struct _LDT_ENTRY { + WORD LimitLow; + WORD BaseLow; + union { + struct { + BYTE BaseMid; + BYTE Flags1; + BYTE Flags2; + BYTE BaseHi; + } Bytes; + struct { + DWORD BaseMid : 8; + DWORD Type : 5; + DWORD Dpl : 2; + DWORD Pres : 1; + DWORD LimitHi : 4; + DWORD Sys : 1; + DWORD Reserved_0 : 1; + DWORD Default_Big : 1; + DWORD Granularity : 1; + DWORD BaseHi : 8; + } Bits; + } HighWord; + } LDT_ENTRY,*PLDT_ENTRY; +#endif + +#if defined(__ia64__) && !defined(RC_INVOKED) + +#ifdef __cplusplus + extern "C" { +#endif + + BOOLEAN BitScanForward64(DWORD *Index,DWORD64 Mask); + BOOLEAN BitScanReverse64(DWORD *Index,DWORD64 Mask); + +#ifdef __cplusplus + } +#endif +#endif + +#if !defined(GENUTIL) && !defined(_GENIA64_) && defined(_IA64_) + + void *_cdecl _rdteb(void); +#ifdef __ia64__ + +#define NtCurrentTeb() ((struct _TEB *)_rdteb()) +#define GetCurrentFiber() (((PNT_TIB)NtCurrentTeb())->FiberData) +#define GetFiberData() (*(PVOID *)(GetCurrentFiber())) + +#ifdef __cplusplus + extern "C" { +#endif + + void __break(int); + void __yield(void); + void __mf(void); + void __lfetch(int Level,VOID CONST *Address); + void __lfetchfault(int Level,VOID CONST *Address); + void __lfetch_excl(int Level,VOID CONST *Address); + void __lfetchfault_excl(int Level,VOID CONST *Address); + +#define MD_LFHINT_NONE 0x00 +#define MD_LFHINT_NT1 0x01 +#define MD_LFHINT_NT2 0x02 +#define MD_LFHINT_NTA 0x03 + +#ifdef __cplusplus + } +#endif + +#define YieldProcessor __yield +#define MemoryBarrier __mf +#define PreFetchCacheLine __lfetch +#define ReadForWriteAccess(p) (*(p)) +#define DbgRaiseAssertionFailure() __break(ASSERT_BREAKPOINT) + +#define PF_TEMPORAL_LEVEL_1 MD_LFHINT_NONE +#define PF_NON_TEMPORAL_LEVEL_ALL MD_LFHINT_NTA + +#define UnsignedMultiplyHigh __UMULH + + ULONGLONG UnsignedMultiplyHigh(ULONGLONG Multiplier,ULONGLONG Multiplicand); +#else + struct _TEB *NtCurrentTeb(void); +#endif +#endif + +#ifdef _IA64_ + +#define EXCEPTION_READ_FAULT 0 +#define EXCEPTION_WRITE_FAULT 1 +#define EXCEPTION_EXECUTE_FAULT 2 + +#if !defined(RC_INVOKED) + +#define CONTEXT_IA64 0x00080000 + +#define CONTEXT_CONTROL (CONTEXT_IA64 | 0x00000001L) +#define CONTEXT_LOWER_FLOATING_POINT (CONTEXT_IA64 | 0x00000002L) +#define CONTEXT_HIGHER_FLOATING_POINT (CONTEXT_IA64 | 0x00000004L) +#define CONTEXT_INTEGER (CONTEXT_IA64 | 0x00000008L) +#define CONTEXT_DEBUG (CONTEXT_IA64 | 0x00000010L) +#define CONTEXT_IA32_CONTROL (CONTEXT_IA64 | 0x00000020L) + +#define CONTEXT_FLOATING_POINT (CONTEXT_LOWER_FLOATING_POINT | CONTEXT_HIGHER_FLOATING_POINT) +#define CONTEXT_FULL (CONTEXT_CONTROL | CONTEXT_FLOATING_POINT | CONTEXT_INTEGER | CONTEXT_IA32_CONTROL) +#define CONTEXT_ALL (CONTEXT_CONTROL | CONTEXT_FLOATING_POINT | CONTEXT_INTEGER | CONTEXT_DEBUG | CONTEXT_IA32_CONTROL) + +#define CONTEXT_EXCEPTION_ACTIVE 0x8000000 +#define CONTEXT_SERVICE_ACTIVE 0x10000000 +#define CONTEXT_EXCEPTION_REQUEST 0x40000000 +#define CONTEXT_EXCEPTION_REPORTING 0x80000000 +#endif + + typedef struct _CONTEXT { + DWORD ContextFlags; + DWORD Fill1[3]; + ULONGLONG DbI0; + ULONGLONG DbI1; + ULONGLONG DbI2; + ULONGLONG DbI3; + ULONGLONG DbI4; + ULONGLONG DbI5; + ULONGLONG DbI6; + ULONGLONG DbI7; + ULONGLONG DbD0; + ULONGLONG DbD1; + ULONGLONG DbD2; + ULONGLONG DbD3; + ULONGLONG DbD4; + ULONGLONG DbD5; + ULONGLONG DbD6; + ULONGLONG DbD7; + FLOAT128 FltS0; + FLOAT128 FltS1; + FLOAT128 FltS2; + FLOAT128 FltS3; + FLOAT128 FltT0; + FLOAT128 FltT1; + FLOAT128 FltT2; + FLOAT128 FltT3; + FLOAT128 FltT4; + FLOAT128 FltT5; + FLOAT128 FltT6; + FLOAT128 FltT7; + FLOAT128 FltT8; + FLOAT128 FltT9; + FLOAT128 FltS4; + FLOAT128 FltS5; + FLOAT128 FltS6; + FLOAT128 FltS7; + FLOAT128 FltS8; + FLOAT128 FltS9; + FLOAT128 FltS10; + FLOAT128 FltS11; + FLOAT128 FltS12; + FLOAT128 FltS13; + FLOAT128 FltS14; + FLOAT128 FltS15; + FLOAT128 FltS16; + FLOAT128 FltS17; + FLOAT128 FltS18; + FLOAT128 FltS19; + FLOAT128 FltF32; + FLOAT128 FltF33; + FLOAT128 FltF34; + FLOAT128 FltF35; + FLOAT128 FltF36; + FLOAT128 FltF37; + FLOAT128 FltF38; + FLOAT128 FltF39; + FLOAT128 FltF40; + FLOAT128 FltF41; + FLOAT128 FltF42; + FLOAT128 FltF43; + FLOAT128 FltF44; + FLOAT128 FltF45; + FLOAT128 FltF46; + FLOAT128 FltF47; + FLOAT128 FltF48; + FLOAT128 FltF49; + FLOAT128 FltF50; + FLOAT128 FltF51; + FLOAT128 FltF52; + FLOAT128 FltF53; + FLOAT128 FltF54; + FLOAT128 FltF55; + FLOAT128 FltF56; + FLOAT128 FltF57; + FLOAT128 FltF58; + FLOAT128 FltF59; + FLOAT128 FltF60; + FLOAT128 FltF61; + FLOAT128 FltF62; + FLOAT128 FltF63; + FLOAT128 FltF64; + FLOAT128 FltF65; + FLOAT128 FltF66; + FLOAT128 FltF67; + FLOAT128 FltF68; + FLOAT128 FltF69; + FLOAT128 FltF70; + FLOAT128 FltF71; + FLOAT128 FltF72; + FLOAT128 FltF73; + FLOAT128 FltF74; + FLOAT128 FltF75; + FLOAT128 FltF76; + FLOAT128 FltF77; + FLOAT128 FltF78; + FLOAT128 FltF79; + FLOAT128 FltF80; + FLOAT128 FltF81; + FLOAT128 FltF82; + FLOAT128 FltF83; + FLOAT128 FltF84; + FLOAT128 FltF85; + FLOAT128 FltF86; + FLOAT128 FltF87; + FLOAT128 FltF88; + FLOAT128 FltF89; + FLOAT128 FltF90; + FLOAT128 FltF91; + FLOAT128 FltF92; + FLOAT128 FltF93; + FLOAT128 FltF94; + FLOAT128 FltF95; + FLOAT128 FltF96; + FLOAT128 FltF97; + FLOAT128 FltF98; + FLOAT128 FltF99; + FLOAT128 FltF100; + FLOAT128 FltF101; + FLOAT128 FltF102; + FLOAT128 FltF103; + FLOAT128 FltF104; + FLOAT128 FltF105; + FLOAT128 FltF106; + FLOAT128 FltF107; + FLOAT128 FltF108; + FLOAT128 FltF109; + FLOAT128 FltF110; + FLOAT128 FltF111; + FLOAT128 FltF112; + FLOAT128 FltF113; + FLOAT128 FltF114; + FLOAT128 FltF115; + FLOAT128 FltF116; + FLOAT128 FltF117; + FLOAT128 FltF118; + FLOAT128 FltF119; + FLOAT128 FltF120; + FLOAT128 FltF121; + FLOAT128 FltF122; + FLOAT128 FltF123; + FLOAT128 FltF124; + FLOAT128 FltF125; + FLOAT128 FltF126; + FLOAT128 FltF127; + ULONGLONG StFPSR; + ULONGLONG IntGp; + ULONGLONG IntT0; + ULONGLONG IntT1; + ULONGLONG IntS0; + ULONGLONG IntS1; + ULONGLONG IntS2; + ULONGLONG IntS3; + ULONGLONG IntV0; + ULONGLONG IntT2; + ULONGLONG IntT3; + ULONGLONG IntT4; + ULONGLONG IntSp; + ULONGLONG IntTeb; + ULONGLONG IntT5; + ULONGLONG IntT6; + ULONGLONG IntT7; + ULONGLONG IntT8; + ULONGLONG IntT9; + ULONGLONG IntT10; + ULONGLONG IntT11; + ULONGLONG IntT12; + ULONGLONG IntT13; + ULONGLONG IntT14; + ULONGLONG IntT15; + ULONGLONG IntT16; + ULONGLONG IntT17; + ULONGLONG IntT18; + ULONGLONG IntT19; + ULONGLONG IntT20; + ULONGLONG IntT21; + ULONGLONG IntT22; + ULONGLONG IntNats; + ULONGLONG Preds; + ULONGLONG BrRp; + ULONGLONG BrS0; + ULONGLONG BrS1; + ULONGLONG BrS2; + ULONGLONG BrS3; + ULONGLONG BrS4; + ULONGLONG BrT0; + ULONGLONG BrT1; + ULONGLONG ApUNAT; + ULONGLONG ApLC; + ULONGLONG ApEC; + ULONGLONG ApCCV; + ULONGLONG ApDCR; + ULONGLONG RsPFS; + ULONGLONG RsBSP; + ULONGLONG RsBSPSTORE; + ULONGLONG RsRSC; + ULONGLONG RsRNAT; + ULONGLONG StIPSR; + ULONGLONG StIIP; + ULONGLONG StIFS; + ULONGLONG StFCR; + ULONGLONG Eflag; + ULONGLONG SegCSD; + ULONGLONG SegSSD; + ULONGLONG Cflag; + ULONGLONG StFSR; + ULONGLONG StFIR; + ULONGLONG StFDR; + ULONGLONG UNUSEDPACK; + } CONTEXT,*PCONTEXT; + + typedef struct _PLABEL_DESCRIPTOR { + ULONGLONG EntryPoint; + ULONGLONG GlobalPointer; + } PLABEL_DESCRIPTOR,*PPLABEL_DESCRIPTOR; + + typedef struct _RUNTIME_FUNCTION { + DWORD BeginAddress; + DWORD EndAddress; + DWORD UnwindInfoAddress; + } RUNTIME_FUNCTION,*PRUNTIME_FUNCTION; + + typedef PRUNTIME_FUNCTION (*PGET_RUNTIME_FUNCTION_CALLBACK)(DWORD64 ControlPc,PVOID Context); + typedef DWORD (*POUT_OF_PROCESS_FUNCTION_TABLE_CALLBACK)(HANDLE Process,PVOID TableAddress,PDWORD Entries,PRUNTIME_FUNCTION *Functions); + +#define OUT_OF_PROCESS_FUNCTION_TABLE_CALLBACK_EXPORT_NAME "OutOfProcessFunctionTableCallback" + + BOOLEAN RtlAddFunctionTable(PRUNTIME_FUNCTION FunctionTable,DWORD EntryCount,ULONGLONG BaseAddress,ULONGLONG TargetGp); + BOOLEAN RtlInstallFunctionTableCallback(DWORD64 TableIdentifier,DWORD64 BaseAddress,DWORD Length,DWORD64 TargetGp,PGET_RUNTIME_FUNCTION_CALLBACK Callback,PVOID Context,PCWSTR OutOfProcessCallbackDll); + BOOLEAN RtlDeleteFunctionTable(PRUNTIME_FUNCTION FunctionTable); + VOID RtlRestoreContext (PCONTEXT ContextRecord,struct _EXCEPTION_RECORD *ExceptionRecord); + VOID __jump_unwind(ULONGLONG TargetMsFrame,ULONGLONG TargetBsFrame,ULONGLONG TargetPc); +#endif + +#define EXCEPTION_NONCONTINUABLE 0x1 +#define EXCEPTION_MAXIMUM_PARAMETERS 15 + + typedef struct _EXCEPTION_RECORD { + DWORD ExceptionCode; + DWORD ExceptionFlags; + struct _EXCEPTION_RECORD *ExceptionRecord; + PVOID ExceptionAddress; + DWORD NumberParameters; + ULONG_PTR ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS]; + } EXCEPTION_RECORD; + + typedef EXCEPTION_RECORD *PEXCEPTION_RECORD; + + typedef struct _EXCEPTION_RECORD32 { + DWORD ExceptionCode; + DWORD ExceptionFlags; + DWORD ExceptionRecord; + DWORD ExceptionAddress; + DWORD NumberParameters; + DWORD ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS]; + } EXCEPTION_RECORD32,*PEXCEPTION_RECORD32; + + typedef struct _EXCEPTION_RECORD64 { + DWORD ExceptionCode; + DWORD ExceptionFlags; + DWORD64 ExceptionRecord; + DWORD64 ExceptionAddress; + DWORD NumberParameters; + DWORD __unusedAlignment; + DWORD64 ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS]; + } EXCEPTION_RECORD64,*PEXCEPTION_RECORD64; + + typedef struct _EXCEPTION_POINTERS { + PEXCEPTION_RECORD ExceptionRecord; + PCONTEXT ContextRecord; + } EXCEPTION_POINTERS,*PEXCEPTION_POINTERS; + +#ifdef __x86_64 + + typedef EXCEPTION_DISPOSITION NTAPI EXCEPTION_ROUTINE (struct _EXCEPTION_RECORD *ExceptionRecord, PVOID EstablisherFrame, struct _CONTEXT *ContextRecord, PVOID DispatcherContext); +#ifndef __PEXCEPTION_ROUTINE_DEFINED +#define __PEXCEPTION_ROUTINE_DEFINED + typedef EXCEPTION_ROUTINE *PEXCEPTION_ROUTINE; +#endif + + /* http://msdn.microsoft.com/en-us/library/ms680597(VS.85).aspx */ + +#define UNWIND_HISTORY_TABLE_SIZE 12 + + typedef struct _UNWIND_HISTORY_TABLE_ENTRY { + ULONG64 ImageBase; + PRUNTIME_FUNCTION FunctionEntry; + } UNWIND_HISTORY_TABLE_ENTRY, *PUNWIND_HISTORY_TABLE_ENTRY; + +#define UNWIND_HISTORY_TABLE_NONE 0 +#define UNWIND_HISTORY_TABLE_GLOBAL 1 +#define UNWIND_HISTORY_TABLE_LOCAL 2 + + typedef struct _UNWIND_HISTORY_TABLE { + ULONG Count; + UCHAR Search; + ULONG64 LowAddress; + ULONG64 HighAddress; + UNWIND_HISTORY_TABLE_ENTRY Entry[UNWIND_HISTORY_TABLE_SIZE]; + } UNWIND_HISTORY_TABLE, *PUNWIND_HISTORY_TABLE; + + /* http://msdn.microsoft.com/en-us/library/b6sf5kbd(VS.80).aspx */ + + struct _DISPATCHER_CONTEXT; + typedef struct _DISPATCHER_CONTEXT DISPATCHER_CONTEXT; + typedef struct _DISPATCHER_CONTEXT *PDISPATCHER_CONTEXT; + + struct _DISPATCHER_CONTEXT { + ULONG64 ControlPc; + ULONG64 ImageBase; + PRUNTIME_FUNCTION FunctionEntry; + ULONG64 EstablisherFrame; + ULONG64 TargetIp; + PCONTEXT ContextRecord; + PEXCEPTION_ROUTINE LanguageHandler; + PVOID HandlerData; + /* http://www.nynaeve.net/?p=99 */ + PUNWIND_HISTORY_TABLE HistoryTable; + ULONG ScopeIndex; + ULONG Fill0; + }; + + /* http://msdn.microsoft.com/en-us/library/ms680617(VS.85).aspx */ + + typedef struct _KNONVOLATILE_CONTEXT_POINTERS + { + PM128A FloatingContext[16]; + PULONG64 IntegerContext[16]; + } KNONVOLATILE_CONTEXT_POINTERS, *PKNONVOLATILE_CONTEXT_POINTERS; +#endif /* defined(__x86_64) */ + + typedef PVOID PACCESS_TOKEN; + typedef PVOID PSECURITY_DESCRIPTOR; + typedef PVOID PSID; + + typedef DWORD ACCESS_MASK; + typedef ACCESS_MASK *PACCESS_MASK; + +#define DELETE (0x00010000L) +#define READ_CONTROL (0x00020000L) +#define WRITE_DAC (0x00040000L) +#define WRITE_OWNER (0x00080000L) +#define SYNCHRONIZE (0x00100000L) + +#define STANDARD_RIGHTS_REQUIRED (0x000F0000L) +#define STANDARD_RIGHTS_READ (READ_CONTROL) +#define STANDARD_RIGHTS_WRITE (READ_CONTROL) +#define STANDARD_RIGHTS_EXECUTE (READ_CONTROL) +#define STANDARD_RIGHTS_ALL (0x001F0000L) + +#define SPECIFIC_RIGHTS_ALL (0x0000FFFFL) + +#define ACCESS_SYSTEM_SECURITY (0x01000000L) + +#define MAXIMUM_ALLOWED (0x02000000L) + +#define GENERIC_READ (0x80000000L) +#define GENERIC_WRITE (0x40000000L) +#define GENERIC_EXECUTE (0x20000000L) +#define GENERIC_ALL (0x10000000L) + + typedef struct _GENERIC_MAPPING { + ACCESS_MASK GenericRead; + ACCESS_MASK GenericWrite; + ACCESS_MASK GenericExecute; + ACCESS_MASK GenericAll; + } GENERIC_MAPPING; + typedef GENERIC_MAPPING *PGENERIC_MAPPING; + +#include + + typedef struct _LUID_AND_ATTRIBUTES { + LUID Luid; + DWORD Attributes; + } LUID_AND_ATTRIBUTES,*PLUID_AND_ATTRIBUTES; + typedef LUID_AND_ATTRIBUTES LUID_AND_ATTRIBUTES_ARRAY[ANYSIZE_ARRAY]; + typedef LUID_AND_ATTRIBUTES_ARRAY *PLUID_AND_ATTRIBUTES_ARRAY; + +#include + +#ifndef SID_IDENTIFIER_AUTHORITY_DEFINED +#define SID_IDENTIFIER_AUTHORITY_DEFINED + typedef struct _SID_IDENTIFIER_AUTHORITY { + BYTE Value[6]; + } SID_IDENTIFIER_AUTHORITY,*PSID_IDENTIFIER_AUTHORITY; +#endif + +#ifndef SID_DEFINED +#define SID_DEFINED + typedef struct _SID { + BYTE Revision; + BYTE SubAuthorityCount; + SID_IDENTIFIER_AUTHORITY IdentifierAuthority; + DWORD SubAuthority[ANYSIZE_ARRAY]; + } SID,*PISID; +#endif + +#define SID_REVISION (1) +#define SID_MAX_SUB_AUTHORITIES (15) +#define SID_RECOMMENDED_SUB_AUTHORITIES (1) + +#define SECURITY_MAX_SID_SIZE (sizeof(SID) - sizeof(DWORD) + (SID_MAX_SUB_AUTHORITIES *sizeof(DWORD))) + + typedef enum _SID_NAME_USE { + SidTypeUser = 1,SidTypeGroup,SidTypeDomain,SidTypeAlias,SidTypeWellKnownGroup,SidTypeDeletedAccount,SidTypeInvalid,SidTypeUnknown,SidTypeComputer + } SID_NAME_USE,*PSID_NAME_USE; + + typedef struct _SID_AND_ATTRIBUTES { + PSID Sid; + DWORD Attributes; + } SID_AND_ATTRIBUTES,*PSID_AND_ATTRIBUTES; + + typedef SID_AND_ATTRIBUTES SID_AND_ATTRIBUTES_ARRAY[ANYSIZE_ARRAY]; + typedef SID_AND_ATTRIBUTES_ARRAY *PSID_AND_ATTRIBUTES_ARRAY; + +#define SECURITY_NULL_SID_AUTHORITY {0,0,0,0,0,0} +#define SECURITY_WORLD_SID_AUTHORITY {0,0,0,0,0,1} +#define SECURITY_LOCAL_SID_AUTHORITY {0,0,0,0,0,2} +#define SECURITY_CREATOR_SID_AUTHORITY {0,0,0,0,0,3} +#define SECURITY_NON_UNIQUE_AUTHORITY {0,0,0,0,0,4} +#define SECURITY_RESOURCE_MANAGER_AUTHORITY {0,0,0,0,0,9} + +#define SECURITY_NULL_RID (0x00000000L) +#define SECURITY_WORLD_RID (0x00000000L) +#define SECURITY_LOCAL_RID (0x00000000L) + +#define SECURITY_CREATOR_OWNER_RID (0x00000000L) +#define SECURITY_CREATOR_GROUP_RID (0x00000001L) + +#define SECURITY_CREATOR_OWNER_SERVER_RID (0x00000002L) +#define SECURITY_CREATOR_GROUP_SERVER_RID (0x00000003L) + +#define SECURITY_NT_AUTHORITY {0,0,0,0,0,5} + +#define SECURITY_DIALUP_RID (0x00000001L) +#define SECURITY_NETWORK_RID (0x00000002L) +#define SECURITY_BATCH_RID (0x00000003L) +#define SECURITY_INTERACTIVE_RID (0x00000004L) +#define SECURITY_LOGON_IDS_RID (0x00000005L) +#define SECURITY_LOGON_IDS_RID_COUNT (3L) +#define SECURITY_SERVICE_RID (0x00000006L) +#define SECURITY_ANONYMOUS_LOGON_RID (0x00000007L) +#define SECURITY_PROXY_RID (0x00000008L) +#define SECURITY_ENTERPRISE_CONTROLLERS_RID (0x00000009L) +#define SECURITY_SERVER_LOGON_RID SECURITY_ENTERPRISE_CONTROLLERS_RID +#define SECURITY_PRINCIPAL_SELF_RID (0x0000000AL) +#define SECURITY_AUTHENTICATED_USER_RID (0x0000000BL) +#define SECURITY_RESTRICTED_CODE_RID (0x0000000CL) +#define SECURITY_TERMINAL_SERVER_RID (0x0000000DL) +#define SECURITY_REMOTE_LOGON_RID (0x0000000EL) +#define SECURITY_THIS_ORGANIZATION_RID (0x0000000FL) +#define SECURITY_IUSER_RID (0x00000011L) + +#define SECURITY_LOCAL_SYSTEM_RID (0x00000012L) +#define SECURITY_LOCAL_SERVICE_RID (0x00000013L) +#define SECURITY_NETWORK_SERVICE_RID (0x00000014L) + +#define SECURITY_NT_NON_UNIQUE (0x00000015L) +#define SECURITY_NT_NON_UNIQUE_SUB_AUTH_COUNT (3L) + +#define SECURITY_ENTERPRISE_READONLY_CONTROLLERS_RID (0x00000016L) + +#define SECURITY_BUILTIN_DOMAIN_RID (0x00000020L) +#define SECURITY_WRITE_RESTRICTED_CODE_RID (0x00000021L) + +#define SECURITY_PACKAGE_BASE_RID (0x00000040L) +#define SECURITY_PACKAGE_RID_COUNT (2L) +#define SECURITY_PACKAGE_NTLM_RID (0x0000000AL) +#define SECURITY_PACKAGE_SCHANNEL_RID (0x0000000EL) +#define SECURITY_PACKAGE_DIGEST_RID (0x00000015L) + +#define SECURITY_SERVICE_ID_BASE_RID (0x00000050L) +#define SECURITY_SERVICE_ID_RID_COUNT (6L) + +#define SECURITY_RESERVED_ID_BASE_RID (0x00000051L) + +#define SECURITY_MAX_ALWAYS_FILTERED (0x000003E7L) +#define SECURITY_MIN_NEVER_FILTERED (0x000003E8L) + +#define SECURITY_OTHER_ORGANIZATION_RID (0x000003E8L) + +#define FOREST_USER_RID_MAX (0x000001F3L) + +#define DOMAIN_USER_RID_ADMIN (0x000001F4L) +#define DOMAIN_USER_RID_GUEST (0x000001F5L) +#define DOMAIN_USER_RID_KRBTGT (0x000001F6L) + +#define DOMAIN_USER_RID_MAX (0x000003E7L) + +#define DOMAIN_GROUP_RID_ADMINS (0x00000200L) +#define DOMAIN_GROUP_RID_USERS (0x00000201L) +#define DOMAIN_GROUP_RID_GUESTS (0x00000202L) +#define DOMAIN_GROUP_RID_COMPUTERS (0x00000203L) +#define DOMAIN_GROUP_RID_CONTROLLERS (0x00000204L) +#define DOMAIN_GROUP_RID_CERT_ADMINS (0x00000205L) +#define DOMAIN_GROUP_RID_SCHEMA_ADMINS (0x00000206L) +#define DOMAIN_GROUP_RID_ENTERPRISE_ADMINS (0x00000207L) +#define DOMAIN_GROUP_RID_POLICY_ADMINS (0x00000208L) +#define DOMAIN_GROUP_RID_READONLY_CONTROLLERS (0x00000209L) + +#define DOMAIN_ALIAS_RID_ADMINS (0x00000220L) +#define DOMAIN_ALIAS_RID_USERS (0x00000221L) +#define DOMAIN_ALIAS_RID_GUESTS (0x00000222L) +#define DOMAIN_ALIAS_RID_POWER_USERS (0x00000223L) + +#define DOMAIN_ALIAS_RID_ACCOUNT_OPS (0x00000224L) +#define DOMAIN_ALIAS_RID_SYSTEM_OPS (0x00000225L) +#define DOMAIN_ALIAS_RID_PRINT_OPS (0x00000226L) +#define DOMAIN_ALIAS_RID_BACKUP_OPS (0x00000227L) + +#define DOMAIN_ALIAS_RID_REPLICATOR (0x00000228L) +#define DOMAIN_ALIAS_RID_RAS_SERVERS (0x00000229L) +#define DOMAIN_ALIAS_RID_PREW2KCOMPACCESS (0x0000022AL) +#define DOMAIN_ALIAS_RID_REMOTE_DESKTOP_USERS (0x0000022BL) +#define DOMAIN_ALIAS_RID_NETWORK_CONFIGURATION_OPS (0x0000022CL) +#define DOMAIN_ALIAS_RID_INCOMING_FOREST_TRUST_BUILDERS (0x0000022DL) + +#define DOMAIN_ALIAS_RID_MONITORING_USERS (0x0000022EL) +#define DOMAIN_ALIAS_RID_LOGGING_USERS (0x0000022FL) +#define DOMAIN_ALIAS_RID_AUTHORIZATIONACCESS (0x00000230L) +#define DOMAIN_ALIAS_RID_TS_LICENSE_SERVERS (0x00000231L) +#define DOMAIN_ALIAS_RID_DCOM_USERS (0x00000232L) + +#define DOMAIN_ALIAS_RID_IUSERS (0x00000238L) +#define DOMAIN_ALIAS_RID_CRYPTO_OPERATORS (0x00000239L) +#define DOMAIN_ALIAS_RID_CACHEABLE_PRINCIPALS_GROUP (0x0000023BL) +#define DOMAIN_ALIAS_RID_NON_CACHEABLE_PRINCIPALS_GROUP (0x0000023CL) +#define DOMAIN_ALIAS_RID_EVENT_LOG_READERS_GROUP (0x0000023DL) + +#define SECURITY_MANDATORY_LABEL_AUTHORITY {0,0,0,0,0,16} +#define SECURITY_MANDATORY_UNTRUSTED_RID (0x00000000L) +#define SECURITY_MANDATORY_LOW_RID (0x00001000L) +#define SECURITY_MANDATORY_MEDIUM_RID (0x00002000L) +#define SECURITY_MANDATORY_HIGH_RID (0x00003000L) +#define SECURITY_MANDATORY_SYSTEM_RID (0x00004000L) +#define SECURITY_MANDATORY_PROTECTED_PROCESS_RID (0x00005000L) + +#define SECURITY_MANDATORY_MAXIMUM_USER_RID SECURITY_MANDATORY_SYSTEM_RID + +#define MANDATORY_LEVEL_TO_MANDATORY_RID(IL) (IL * 0x1000) + + typedef enum { + WinNullSid = 0,WinWorldSid = 1,WinLocalSid = 2,WinCreatorOwnerSid = 3,WinCreatorGroupSid = 4,WinCreatorOwnerServerSid = 5,WinCreatorGroupServerSid = 6,WinNtAuthoritySid = 7,WinDialupSid = 8,WinNetworkSid = 9,WinBatchSid = 10,WinInteractiveSid = 11,WinServiceSid = 12,WinAnonymousSid = 13,WinProxySid = 14,WinEnterpriseControllersSid = 15,WinSelfSid = 16,WinAuthenticatedUserSid = 17,WinRestrictedCodeSid = 18,WinTerminalServerSid = 19,WinRemoteLogonIdSid = 20,WinLogonIdsSid = 21,WinLocalSystemSid = 22,WinLocalServiceSid = 23,WinNetworkServiceSid = 24,WinBuiltinDomainSid = 25,WinBuiltinAdministratorsSid = 26,WinBuiltinUsersSid = 27,WinBuiltinGuestsSid = 28,WinBuiltinPowerUsersSid = 29,WinBuiltinAccountOperatorsSid = 30,WinBuiltinSystemOperatorsSid = 31,WinBuiltinPrintOperatorsSid = 32,WinBuiltinBackupOperatorsSid = 33,WinBuiltinReplicatorSid = 34,WinBuiltinPreWindows2000CompatibleAccessSid = 35,WinBuiltinRemoteDesktopUsersSid = 36,WinBuiltinNetworkConfigurationOperatorsSid = 37,WinAccountAdministratorSid = 38,WinAccountGuestSid = 39,WinAccountKrbtgtSid = 40,WinAccountDomainAdminsSid = 41,WinAccountDomainUsersSid = 42,WinAccountDomainGuestsSid = 43,WinAccountComputersSid = 44,WinAccountControllersSid = 45,WinAccountCertAdminsSid = 46,WinAccountSchemaAdminsSid = 47,WinAccountEnterpriseAdminsSid = 48,WinAccountPolicyAdminsSid = 49,WinAccountRasAndIasServersSid = 50,WinNTLMAuthenticationSid = 51,WinDigestAuthenticationSid = 52,WinSChannelAuthenticationSid = 53,WinThisOrganizationSid = 54,WinOtherOrganizationSid = 55,WinBuiltinIncomingForestTrustBuildersSid = 56,WinBuiltinPerfMonitoringUsersSid = 57,WinBuiltinPerfLoggingUsersSid = 58,WinBuiltinAuthorizationAccessSid = 59,WinBuiltinTerminalServerLicenseServersSid = 60,WinBuiltinDCOMUsersSid = 61 + } WELL_KNOWN_SID_TYPE; + +#define SYSTEM_LUID { 0x3E7,0x0 } +#define ANONYMOUS_LOGON_LUID { 0x3e6,0x0 } +#define LOCALSERVICE_LUID { 0x3e5,0x0 } +#define NETWORKSERVICE_LUID { 0x3e4,0x0 } +#define IUSER_LUID { 0x3e3, 0x0 } + +#define SE_GROUP_MANDATORY (0x00000001L) +#define SE_GROUP_ENABLED_BY_DEFAULT (0x00000002L) +#define SE_GROUP_ENABLED (0x00000004L) +#define SE_GROUP_OWNER (0x00000008L) +#define SE_GROUP_USE_FOR_DENY_ONLY (0x00000010L) +#define SE_GROUP_INTEGRITY (0x00000020L) +#define SE_GROUP_INTEGRITY_ENABLED (0x00000040L) +#define SE_GROUP_LOGON_ID (0xC0000000L) +#define SE_GROUP_RESOURCE (0x20000000L) + +#define ACL_REVISION (2) +#define ACL_REVISION_DS (4) + +#define ACL_REVISION1 (1) +#define MIN_ACL_REVISION ACL_REVISION2 +#define ACL_REVISION2 (2) +#define ACL_REVISION3 (3) +#define ACL_REVISION4 (4) +#define MAX_ACL_REVISION ACL_REVISION4 + + typedef struct _ACL { + BYTE AclRevision; + BYTE Sbz1; + WORD AclSize; + WORD AceCount; + WORD Sbz2; + } ACL; + typedef ACL *PACL; + + typedef struct _ACE_HEADER { + BYTE AceType; + BYTE AceFlags; + WORD AceSize; + } ACE_HEADER; + typedef ACE_HEADER *PACE_HEADER; + +#define ACCESS_MIN_MS_ACE_TYPE (0x0) +#define ACCESS_ALLOWED_ACE_TYPE (0x0) +#define ACCESS_DENIED_ACE_TYPE (0x1) +#define SYSTEM_AUDIT_ACE_TYPE (0x2) +#define SYSTEM_ALARM_ACE_TYPE (0x3) +#define ACCESS_MAX_MS_V2_ACE_TYPE (0x3) + +#define ACCESS_ALLOWED_COMPOUND_ACE_TYPE (0x4) +#define ACCESS_MAX_MS_V3_ACE_TYPE (0x4) + +#define ACCESS_MIN_MS_OBJECT_ACE_TYPE (0x5) +#define ACCESS_ALLOWED_OBJECT_ACE_TYPE (0x5) +#define ACCESS_DENIED_OBJECT_ACE_TYPE (0x6) +#define SYSTEM_AUDIT_OBJECT_ACE_TYPE (0x7) +#define SYSTEM_ALARM_OBJECT_ACE_TYPE (0x8) +#define ACCESS_MAX_MS_OBJECT_ACE_TYPE (0x8) + +#define ACCESS_MAX_MS_V4_ACE_TYPE (0x8) +#define ACCESS_MAX_MS_ACE_TYPE (0x8) + +#define ACCESS_ALLOWED_CALLBACK_ACE_TYPE (0x9) +#define ACCESS_DENIED_CALLBACK_ACE_TYPE (0xA) +#define ACCESS_ALLOWED_CALLBACK_OBJECT_ACE_TYPE (0xB) +#define ACCESS_DENIED_CALLBACK_OBJECT_ACE_TYPE (0xC) +#define SYSTEM_AUDIT_CALLBACK_ACE_TYPE (0xD) +#define SYSTEM_ALARM_CALLBACK_ACE_TYPE (0xE) +#define SYSTEM_AUDIT_CALLBACK_OBJECT_ACE_TYPE (0xF) +#define SYSTEM_ALARM_CALLBACK_OBJECT_ACE_TYPE (0x10) + +#define SYSTEM_MANDATORY_LABEL_ACE_TYPE (0x11) +#define ACCESS_MAX_MS_V5_ACE_TYPE (0x11) + +#define OBJECT_INHERIT_ACE (0x1) +#define CONTAINER_INHERIT_ACE (0x2) +#define NO_PROPAGATE_INHERIT_ACE (0x4) +#define INHERIT_ONLY_ACE (0x8) +#define INHERITED_ACE (0x10) +#define VALID_INHERIT_FLAGS (0x1F) + +#define SUCCESSFUL_ACCESS_ACE_FLAG (0x40) +#define FAILED_ACCESS_ACE_FLAG (0x80) + + typedef struct _ACCESS_ALLOWED_ACE { + ACE_HEADER Header; + ACCESS_MASK Mask; + DWORD SidStart; + } ACCESS_ALLOWED_ACE; + + typedef ACCESS_ALLOWED_ACE *PACCESS_ALLOWED_ACE; + + typedef struct _ACCESS_DENIED_ACE { + ACE_HEADER Header; + ACCESS_MASK Mask; + DWORD SidStart; + } ACCESS_DENIED_ACE; + typedef ACCESS_DENIED_ACE *PACCESS_DENIED_ACE; + + typedef struct _SYSTEM_AUDIT_ACE { + ACE_HEADER Header; + ACCESS_MASK Mask; + DWORD SidStart; + } SYSTEM_AUDIT_ACE; + typedef SYSTEM_AUDIT_ACE *PSYSTEM_AUDIT_ACE; + + typedef struct _SYSTEM_ALARM_ACE { + ACE_HEADER Header; + ACCESS_MASK Mask; + DWORD SidStart; + } SYSTEM_ALARM_ACE; + typedef SYSTEM_ALARM_ACE *PSYSTEM_ALARM_ACE; + + typedef struct _ACCESS_ALLOWED_OBJECT_ACE { + ACE_HEADER Header; + ACCESS_MASK Mask; + DWORD Flags; + GUID ObjectType; + GUID InheritedObjectType; + DWORD SidStart; + } ACCESS_ALLOWED_OBJECT_ACE,*PACCESS_ALLOWED_OBJECT_ACE; + + typedef struct _ACCESS_DENIED_OBJECT_ACE { + ACE_HEADER Header; + ACCESS_MASK Mask; + DWORD Flags; + GUID ObjectType; + GUID InheritedObjectType; + DWORD SidStart; + } ACCESS_DENIED_OBJECT_ACE,*PACCESS_DENIED_OBJECT_ACE; + + typedef struct _SYSTEM_AUDIT_OBJECT_ACE { + ACE_HEADER Header; + ACCESS_MASK Mask; + DWORD Flags; + GUID ObjectType; + GUID InheritedObjectType; + DWORD SidStart; + } SYSTEM_AUDIT_OBJECT_ACE,*PSYSTEM_AUDIT_OBJECT_ACE; + + typedef struct _SYSTEM_ALARM_OBJECT_ACE { + ACE_HEADER Header; + ACCESS_MASK Mask; + DWORD Flags; + GUID ObjectType; + GUID InheritedObjectType; + DWORD SidStart; + } SYSTEM_ALARM_OBJECT_ACE,*PSYSTEM_ALARM_OBJECT_ACE; + + typedef struct _ACCESS_ALLOWED_CALLBACK_ACE { + ACE_HEADER Header; + ACCESS_MASK Mask; + DWORD SidStart; + + } ACCESS_ALLOWED_CALLBACK_ACE,*PACCESS_ALLOWED_CALLBACK_ACE; + + typedef struct _ACCESS_DENIED_CALLBACK_ACE { + ACE_HEADER Header; + ACCESS_MASK Mask; + DWORD SidStart; + + } ACCESS_DENIED_CALLBACK_ACE,*PACCESS_DENIED_CALLBACK_ACE; + + typedef struct _SYSTEM_AUDIT_CALLBACK_ACE { + ACE_HEADER Header; + ACCESS_MASK Mask; + DWORD SidStart; + + } SYSTEM_AUDIT_CALLBACK_ACE,*PSYSTEM_AUDIT_CALLBACK_ACE; + + typedef struct _SYSTEM_ALARM_CALLBACK_ACE { + ACE_HEADER Header; + ACCESS_MASK Mask; + DWORD SidStart; + + } SYSTEM_ALARM_CALLBACK_ACE,*PSYSTEM_ALARM_CALLBACK_ACE; + + typedef struct _ACCESS_ALLOWED_CALLBACK_OBJECT_ACE { + ACE_HEADER Header; + ACCESS_MASK Mask; + DWORD Flags; + GUID ObjectType; + GUID InheritedObjectType; + DWORD SidStart; + + } ACCESS_ALLOWED_CALLBACK_OBJECT_ACE,*PACCESS_ALLOWED_CALLBACK_OBJECT_ACE; + + typedef struct _ACCESS_DENIED_CALLBACK_OBJECT_ACE { + ACE_HEADER Header; + ACCESS_MASK Mask; + DWORD Flags; + GUID ObjectType; + GUID InheritedObjectType; + DWORD SidStart; + + } ACCESS_DENIED_CALLBACK_OBJECT_ACE,*PACCESS_DENIED_CALLBACK_OBJECT_ACE; + + typedef struct _SYSTEM_AUDIT_CALLBACK_OBJECT_ACE { + ACE_HEADER Header; + ACCESS_MASK Mask; + DWORD Flags; + GUID ObjectType; + GUID InheritedObjectType; + DWORD SidStart; + + } SYSTEM_AUDIT_CALLBACK_OBJECT_ACE,*PSYSTEM_AUDIT_CALLBACK_OBJECT_ACE; + + typedef struct _SYSTEM_ALARM_CALLBACK_OBJECT_ACE { + ACE_HEADER Header; + ACCESS_MASK Mask; + DWORD Flags; + GUID ObjectType; + GUID InheritedObjectType; + DWORD SidStart; + + } SYSTEM_ALARM_CALLBACK_OBJECT_ACE,*PSYSTEM_ALARM_CALLBACK_OBJECT_ACE; + +#define ACE_OBJECT_TYPE_PRESENT 0x1 +#define ACE_INHERITED_OBJECT_TYPE_PRESENT 0x2 + + typedef enum _ACL_INFORMATION_CLASS { + AclRevisionInformation = 1,AclSizeInformation + } ACL_INFORMATION_CLASS; + + typedef struct _ACL_REVISION_INFORMATION { + DWORD AclRevision; + } ACL_REVISION_INFORMATION; + typedef ACL_REVISION_INFORMATION *PACL_REVISION_INFORMATION; + + typedef struct _ACL_SIZE_INFORMATION { + DWORD AceCount; + DWORD AclBytesInUse; + DWORD AclBytesFree; + } ACL_SIZE_INFORMATION; + typedef ACL_SIZE_INFORMATION *PACL_SIZE_INFORMATION; + +#define SECURITY_DESCRIPTOR_REVISION (1) +#define SECURITY_DESCRIPTOR_REVISION1 (1) + +#define SECURITY_DESCRIPTOR_MIN_LENGTH (sizeof(SECURITY_DESCRIPTOR)) + + typedef WORD SECURITY_DESCRIPTOR_CONTROL,*PSECURITY_DESCRIPTOR_CONTROL; + +#define SE_OWNER_DEFAULTED (0x0001) +#define SE_GROUP_DEFAULTED (0x0002) +#define SE_DACL_PRESENT (0x0004) +#define SE_DACL_DEFAULTED (0x0008) +#define SE_SACL_PRESENT (0x0010) +#define SE_SACL_DEFAULTED (0x0020) +#define SE_DACL_AUTO_INHERIT_REQ (0x0100) +#define SE_SACL_AUTO_INHERIT_REQ (0x0200) +#define SE_DACL_AUTO_INHERITED (0x0400) +#define SE_SACL_AUTO_INHERITED (0x0800) +#define SE_DACL_PROTECTED (0x1000) +#define SE_SACL_PROTECTED (0x2000) +#define SE_RM_CONTROL_VALID (0x4000) +#define SE_SELF_RELATIVE (0x8000) + + typedef struct _SECURITY_DESCRIPTOR_RELATIVE { + BYTE Revision; + BYTE Sbz1; + SECURITY_DESCRIPTOR_CONTROL Control; + DWORD Owner; + DWORD Group; + DWORD Sacl; + DWORD Dacl; + } SECURITY_DESCRIPTOR_RELATIVE,*PISECURITY_DESCRIPTOR_RELATIVE; + + typedef struct _SECURITY_DESCRIPTOR { + BYTE Revision; + BYTE Sbz1; + SECURITY_DESCRIPTOR_CONTROL Control; + PSID Owner; + PSID Group; + PACL Sacl; + PACL Dacl; + + } SECURITY_DESCRIPTOR,*PISECURITY_DESCRIPTOR; + + typedef struct _OBJECT_TYPE_LIST { + WORD Level; + WORD Sbz; + GUID *ObjectType; + } OBJECT_TYPE_LIST,*POBJECT_TYPE_LIST; + +#define ACCESS_OBJECT_GUID 0 +#define ACCESS_PROPERTY_SET_GUID 1 +#define ACCESS_PROPERTY_GUID 2 + +#define ACCESS_MAX_LEVEL 4 + + typedef enum _AUDIT_EVENT_TYPE { + AuditEventObjectAccess,AuditEventDirectoryServiceAccess + } AUDIT_EVENT_TYPE,*PAUDIT_EVENT_TYPE; + +#define AUDIT_ALLOW_NO_PRIVILEGE 0x1 + +#define ACCESS_DS_SOURCE_A "DS" +#define ACCESS_DS_SOURCE_W L"DS" +#define ACCESS_DS_OBJECT_TYPE_NAME_A "Directory Service Object" +#define ACCESS_DS_OBJECT_TYPE_NAME_W L"Directory Service Object" + +#define SE_PRIVILEGE_ENABLED_BY_DEFAULT (0x00000001L) +#define SE_PRIVILEGE_ENABLED (0x00000002L) +#define SE_PRIVILEGE_REMOVED (0X00000004L) +#define SE_PRIVILEGE_USED_FOR_ACCESS (0x80000000L) + +#define PRIVILEGE_SET_ALL_NECESSARY (1) + + typedef struct _PRIVILEGE_SET { + DWORD PrivilegeCount; + DWORD Control; + LUID_AND_ATTRIBUTES Privilege[ANYSIZE_ARRAY]; + } PRIVILEGE_SET,*PPRIVILEGE_SET; + +#define SE_CREATE_TOKEN_NAME TEXT("SeCreateTokenPrivilege") +#define SE_ASSIGNPRIMARYTOKEN_NAME TEXT("SeAssignPrimaryTokenPrivilege") +#define SE_LOCK_MEMORY_NAME TEXT("SeLockMemoryPrivilege") +#define SE_INCREASE_QUOTA_NAME TEXT("SeIncreaseQuotaPrivilege") +#define SE_UNSOLICITED_INPUT_NAME TEXT("SeUnsolicitedInputPrivilege") +#define SE_MACHINE_ACCOUNT_NAME TEXT("SeMachineAccountPrivilege") +#define SE_TCB_NAME TEXT("SeTcbPrivilege") +#define SE_SECURITY_NAME TEXT("SeSecurityPrivilege") +#define SE_TAKE_OWNERSHIP_NAME TEXT("SeTakeOwnershipPrivilege") +#define SE_LOAD_DRIVER_NAME TEXT("SeLoadDriverPrivilege") +#define SE_SYSTEM_PROFILE_NAME TEXT("SeSystemProfilePrivilege") +#define SE_SYSTEMTIME_NAME TEXT("SeSystemtimePrivilege") +#define SE_PROF_SINGLE_PROCESS_NAME TEXT("SeProfileSingleProcessPrivilege") +#define SE_INC_BASE_PRIORITY_NAME TEXT("SeIncreaseBasePriorityPrivilege") +#define SE_CREATE_PAGEFILE_NAME TEXT("SeCreatePagefilePrivilege") +#define SE_CREATE_PERMANENT_NAME TEXT("SeCreatePermanentPrivilege") +#define SE_BACKUP_NAME TEXT("SeBackupPrivilege") +#define SE_RESTORE_NAME TEXT("SeRestorePrivilege") +#define SE_SHUTDOWN_NAME TEXT("SeShutdownPrivilege") +#define SE_DEBUG_NAME TEXT("SeDebugPrivilege") +#define SE_AUDIT_NAME TEXT("SeAuditPrivilege") +#define SE_SYSTEM_ENVIRONMENT_NAME TEXT("SeSystemEnvironmentPrivilege") +#define SE_CHANGE_NOTIFY_NAME TEXT("SeChangeNotifyPrivilege") +#define SE_REMOTE_SHUTDOWN_NAME TEXT("SeRemoteShutdownPrivilege") +#define SE_UNDOCK_NAME TEXT("SeUndockPrivilege") +#define SE_SYNC_AGENT_NAME TEXT("SeSyncAgentPrivilege") +#define SE_ENABLE_DELEGATION_NAME TEXT("SeEnableDelegationPrivilege") +#define SE_MANAGE_VOLUME_NAME TEXT("SeManageVolumePrivilege") +#define SE_IMPERSONATE_NAME TEXT("SeImpersonatePrivilege") +#define SE_CREATE_GLOBAL_NAME TEXT("SeCreateGlobalPrivilege") + + typedef enum _SECURITY_IMPERSONATION_LEVEL { + SecurityAnonymous,SecurityIdentification,SecurityImpersonation,SecurityDelegation + } SECURITY_IMPERSONATION_LEVEL,*PSECURITY_IMPERSONATION_LEVEL; + +#define SECURITY_MAX_IMPERSONATION_LEVEL SecurityDelegation +#define SECURITY_MIN_IMPERSONATION_LEVEL SecurityAnonymous +#define DEFAULT_IMPERSONATION_LEVEL SecurityImpersonation +#define VALID_IMPERSONATION_LEVEL(L) (((L) >= SECURITY_MIN_IMPERSONATION_LEVEL) && ((L) <= SECURITY_MAX_IMPERSONATION_LEVEL)) + +#define TOKEN_ASSIGN_PRIMARY (0x0001) +#define TOKEN_DUPLICATE (0x0002) +#define TOKEN_IMPERSONATE (0x0004) +#define TOKEN_QUERY (0x0008) +#define TOKEN_QUERY_SOURCE (0x0010) +#define TOKEN_ADJUST_PRIVILEGES (0x0020) +#define TOKEN_ADJUST_GROUPS (0x0040) +#define TOKEN_ADJUST_DEFAULT (0x0080) +#define TOKEN_ADJUST_SESSIONID (0x0100) + +#define TOKEN_ALL_ACCESS_P (STANDARD_RIGHTS_REQUIRED | TOKEN_ASSIGN_PRIMARY | TOKEN_DUPLICATE | TOKEN_IMPERSONATE | TOKEN_QUERY | TOKEN_QUERY_SOURCE | TOKEN_ADJUST_PRIVILEGES | TOKEN_ADJUST_GROUPS | TOKEN_ADJUST_DEFAULT) +#define TOKEN_ALL_ACCESS (TOKEN_ALL_ACCESS_P | TOKEN_ADJUST_SESSIONID) +#define TOKEN_READ (STANDARD_RIGHTS_READ | TOKEN_QUERY) + +#define TOKEN_WRITE (STANDARD_RIGHTS_WRITE | TOKEN_ADJUST_PRIVILEGES | TOKEN_ADJUST_GROUPS | TOKEN_ADJUST_DEFAULT) + +#define TOKEN_EXECUTE (STANDARD_RIGHTS_EXECUTE) + + typedef enum _TOKEN_TYPE { + TokenPrimary = 1,TokenImpersonation + } TOKEN_TYPE; + typedef TOKEN_TYPE *PTOKEN_TYPE; + + typedef enum _TOKEN_INFORMATION_CLASS { + TokenUser = 1,TokenGroups,TokenPrivileges,TokenOwner,TokenPrimaryGroup,TokenDefaultDacl,TokenSource,TokenType,TokenImpersonationLevel, + TokenStatistics,TokenRestrictedSids,TokenSessionId,TokenGroupsAndPrivileges,TokenSessionReference,TokenSandBoxInert,TokenAuditPolicy, + TokenOrigin,MaxTokenInfoClass + } TOKEN_INFORMATION_CLASS,*PTOKEN_INFORMATION_CLASS; + + typedef struct _TOKEN_USER { + SID_AND_ATTRIBUTES User; + } TOKEN_USER,*PTOKEN_USER; + + typedef struct _TOKEN_GROUPS { + DWORD GroupCount; + SID_AND_ATTRIBUTES Groups[ANYSIZE_ARRAY]; + } TOKEN_GROUPS,*PTOKEN_GROUPS; + + typedef struct _TOKEN_PRIVILEGES { + DWORD PrivilegeCount; + LUID_AND_ATTRIBUTES Privileges[ANYSIZE_ARRAY]; + } TOKEN_PRIVILEGES,*PTOKEN_PRIVILEGES; + + typedef struct _TOKEN_OWNER { + PSID Owner; + } TOKEN_OWNER,*PTOKEN_OWNER; + + typedef struct _TOKEN_PRIMARY_GROUP { + PSID PrimaryGroup; + } TOKEN_PRIMARY_GROUP,*PTOKEN_PRIMARY_GROUP; + + typedef struct _TOKEN_DEFAULT_DACL { + PACL DefaultDacl; + } TOKEN_DEFAULT_DACL,*PTOKEN_DEFAULT_DACL; + + typedef struct _TOKEN_GROUPS_AND_PRIVILEGES { + DWORD SidCount; + DWORD SidLength; + PSID_AND_ATTRIBUTES Sids; + DWORD RestrictedSidCount; + DWORD RestrictedSidLength; + PSID_AND_ATTRIBUTES RestrictedSids; + DWORD PrivilegeCount; + DWORD PrivilegeLength; + PLUID_AND_ATTRIBUTES Privileges; + LUID AuthenticationId; + } TOKEN_GROUPS_AND_PRIVILEGES,*PTOKEN_GROUPS_AND_PRIVILEGES; + +#define TOKEN_AUDIT_SUCCESS_INCLUDE 0x1 +#define TOKEN_AUDIT_SUCCESS_EXCLUDE 0x2 +#define TOKEN_AUDIT_FAILURE_INCLUDE 0x4 +#define TOKEN_AUDIT_FAILURE_EXCLUDE 0x8 + +#define VALID_AUDIT_POLICY_BITS (TOKEN_AUDIT_SUCCESS_INCLUDE | TOKEN_AUDIT_SUCCESS_EXCLUDE | TOKEN_AUDIT_FAILURE_INCLUDE | TOKEN_AUDIT_FAILURE_EXCLUDE) +#define VALID_TOKEN_AUDIT_POLICY_ELEMENT(P) ((((P).PolicyMask & ~VALID_AUDIT_POLICY_BITS)==0) && ((P).Category <= AuditEventMaxType)) + + typedef struct _TOKEN_AUDIT_POLICY_ELEMENT { + DWORD Category; + DWORD PolicyMask; + } TOKEN_AUDIT_POLICY_ELEMENT,*PTOKEN_AUDIT_POLICY_ELEMENT; + + typedef struct _TOKEN_AUDIT_POLICY { + DWORD PolicyCount; + TOKEN_AUDIT_POLICY_ELEMENT Policy[ANYSIZE_ARRAY]; + } TOKEN_AUDIT_POLICY,*PTOKEN_AUDIT_POLICY; + +#define PER_USER_AUDITING_POLICY_SIZE(p) (sizeof(TOKEN_AUDIT_POLICY) + (((p)->PolicyCount > ANYSIZE_ARRAY) ? (sizeof(TOKEN_AUDIT_POLICY_ELEMENT) *((p)->PolicyCount - ANYSIZE_ARRAY)) : 0)) +#define PER_USER_AUDITING_POLICY_SIZE_BY_COUNT(C) (sizeof(TOKEN_AUDIT_POLICY) + (((C) > ANYSIZE_ARRAY) ? (sizeof(TOKEN_AUDIT_POLICY_ELEMENT) *((C) - ANYSIZE_ARRAY)) : 0)) + +#define TOKEN_SOURCE_LENGTH 8 + + typedef struct _TOKEN_SOURCE { + CHAR SourceName[TOKEN_SOURCE_LENGTH]; + LUID SourceIdentifier; + } TOKEN_SOURCE,*PTOKEN_SOURCE; + + typedef struct _TOKEN_STATISTICS { + LUID TokenId; + LUID AuthenticationId; + LARGE_INTEGER ExpirationTime; + TOKEN_TYPE TokenType; + SECURITY_IMPERSONATION_LEVEL ImpersonationLevel; + DWORD DynamicCharged; + DWORD DynamicAvailable; + DWORD GroupCount; + DWORD PrivilegeCount; + LUID ModifiedId; + } TOKEN_STATISTICS,*PTOKEN_STATISTICS; + + typedef struct _TOKEN_CONTROL { + LUID TokenId; + LUID AuthenticationId; + LUID ModifiedId; + TOKEN_SOURCE TokenSource; + } TOKEN_CONTROL,*PTOKEN_CONTROL; + + typedef struct _TOKEN_ORIGIN { + LUID OriginatingLogonSession; + } TOKEN_ORIGIN,*PTOKEN_ORIGIN; + +#define SECURITY_DYNAMIC_TRACKING (TRUE) +#define SECURITY_STATIC_TRACKING (FALSE) + + typedef BOOLEAN SECURITY_CONTEXT_TRACKING_MODE,*PSECURITY_CONTEXT_TRACKING_MODE; + + typedef struct _SECURITY_QUALITY_OF_SERVICE { + DWORD Length; + SECURITY_IMPERSONATION_LEVEL ImpersonationLevel; + SECURITY_CONTEXT_TRACKING_MODE ContextTrackingMode; + BOOLEAN EffectiveOnly; + } SECURITY_QUALITY_OF_SERVICE,*PSECURITY_QUALITY_OF_SERVICE; + + typedef struct _SE_IMPERSONATION_STATE { + PACCESS_TOKEN Token; + BOOLEAN CopyOnOpen; + BOOLEAN EffectiveOnly; + SECURITY_IMPERSONATION_LEVEL Level; + } SE_IMPERSONATION_STATE,*PSE_IMPERSONATION_STATE; + +#define DISABLE_MAX_PRIVILEGE 0x1 +#define SANDBOX_INERT 0x2 + + typedef DWORD SECURITY_INFORMATION,*PSECURITY_INFORMATION; + +#define OWNER_SECURITY_INFORMATION (0x00000001L) +#define GROUP_SECURITY_INFORMATION (0x00000002L) +#define DACL_SECURITY_INFORMATION (0x00000004L) +#define SACL_SECURITY_INFORMATION (0x00000008L) + +#define PROTECTED_DACL_SECURITY_INFORMATION (0x80000000L) +#define PROTECTED_SACL_SECURITY_INFORMATION (0x40000000L) +#define UNPROTECTED_DACL_SECURITY_INFORMATION (0x20000000L) +#define UNPROTECTED_SACL_SECURITY_INFORMATION (0x10000000L) + +#define PROCESS_TERMINATE (0x0001) +#define PROCESS_CREATE_THREAD (0x0002) +#define PROCESS_SET_SESSIONID (0x0004) +#define PROCESS_VM_OPERATION (0x0008) +#define PROCESS_VM_READ (0x0010) +#define PROCESS_VM_WRITE (0x0020) +#define PROCESS_DUP_HANDLE (0x0040) +#define PROCESS_CREATE_PROCESS (0x0080) +#define PROCESS_SET_QUOTA (0x0100) +#define PROCESS_SET_INFORMATION (0x0200) +#define PROCESS_QUERY_INFORMATION (0x0400) +#define PROCESS_SUSPEND_RESUME (0x0800) +#define PROCESS_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0xFFF) + +#ifdef _WIN64 +#define MAXIMUM_PROCESSORS 64 +#else +#define MAXIMUM_PROCESSORS 32 +#endif + +#define THREAD_TERMINATE (0x0001) +#define THREAD_SUSPEND_RESUME (0x0002) +#define THREAD_GET_CONTEXT (0x0008) +#define THREAD_SET_CONTEXT (0x0010) +#define THREAD_SET_INFORMATION (0x0020) +#define THREAD_QUERY_INFORMATION (0x0040) +#define THREAD_SET_THREAD_TOKEN (0x0080) +#define THREAD_IMPERSONATE (0x0100) +#define THREAD_DIRECT_IMPERSONATION (0x0200) + +#define THREAD_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x3FF) + +#define JOB_OBJECT_ASSIGN_PROCESS (0x0001) +#define JOB_OBJECT_SET_ATTRIBUTES (0x0002) +#define JOB_OBJECT_QUERY (0x0004) +#define JOB_OBJECT_TERMINATE (0x0008) +#define JOB_OBJECT_SET_SECURITY_ATTRIBUTES (0x0010) +#define JOB_OBJECT_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x1F) + + typedef struct _JOB_SET_ARRAY { + HANDLE JobHandle; + DWORD MemberLevel; + DWORD Flags; + } JOB_SET_ARRAY,*PJOB_SET_ARRAY; + +#define FLS_MAXIMUM_AVAILABLE 128 +#define TLS_MINIMUM_AVAILABLE 64 + +#ifndef _NT_TIB_DEFINED +#define _NT_TIB_DEFINED + typedef struct _NT_TIB { + struct _EXCEPTION_REGISTRATION_RECORD *ExceptionList; + PVOID StackBase; + PVOID StackLimit; + PVOID SubSystemTib; + union { + PVOID FiberData; + DWORD Version; + }; + PVOID ArbitraryUserPointer; + struct _NT_TIB *Self; + } NT_TIB; + typedef NT_TIB *PNT_TIB; +#endif + + typedef struct _NT_TIB32 { + DWORD ExceptionList; + DWORD StackBase; + DWORD StackLimit; + DWORD SubSystemTib; + union { + DWORD FiberData; + DWORD Version; + }; + DWORD ArbitraryUserPointer; + DWORD Self; + } NT_TIB32,*PNT_TIB32; + + typedef struct _NT_TIB64 { + DWORD64 ExceptionList; + DWORD64 StackBase; + DWORD64 StackLimit; + DWORD64 SubSystemTib; + union { + DWORD64 FiberData; + DWORD Version; + }; + DWORD64 ArbitraryUserPointer; + DWORD64 Self; + } NT_TIB64,*PNT_TIB64; + +#if !defined(I_X86_) && !defined(_IA64_) && !defined(_AMD64_) +#define WX86 +#endif + +#define THREAD_BASE_PRIORITY_LOWRT 15 +#define THREAD_BASE_PRIORITY_MAX 2 +#define THREAD_BASE_PRIORITY_MIN (-2) +#define THREAD_BASE_PRIORITY_IDLE (-15) + + typedef struct _QUOTA_LIMITS { + SIZE_T PagedPoolLimit; + SIZE_T NonPagedPoolLimit; + SIZE_T MinimumWorkingSetSize; + SIZE_T MaximumWorkingSetSize; + SIZE_T PagefileLimit; + LARGE_INTEGER TimeLimit; + } QUOTA_LIMITS,*PQUOTA_LIMITS; + +#define QUOTA_LIMITS_HARDWS_MIN_ENABLE 0x00000001 +#define QUOTA_LIMITS_HARDWS_MIN_DISABLE 0x00000002 +#define QUOTA_LIMITS_HARDWS_MAX_ENABLE 0x00000004 +#define QUOTA_LIMITS_HARDWS_MAX_DISABLE 0x00000008 + + typedef struct _QUOTA_LIMITS_EX { + SIZE_T PagedPoolLimit; + SIZE_T NonPagedPoolLimit; + SIZE_T MinimumWorkingSetSize; + SIZE_T MaximumWorkingSetSize; + SIZE_T PagefileLimit; + LARGE_INTEGER TimeLimit; + SIZE_T Reserved1; + SIZE_T Reserved2; + SIZE_T Reserved3; + SIZE_T Reserved4; + DWORD Flags; + DWORD Reserved5; + } QUOTA_LIMITS_EX,*PQUOTA_LIMITS_EX; + + typedef struct _IO_COUNTERS { + ULONGLONG ReadOperationCount; + ULONGLONG WriteOperationCount; + ULONGLONG OtherOperationCount; + ULONGLONG ReadTransferCount; + ULONGLONG WriteTransferCount; + ULONGLONG OtherTransferCount; + } IO_COUNTERS; + typedef IO_COUNTERS *PIO_COUNTERS; + + typedef struct _JOBOBJECT_BASIC_ACCOUNTING_INFORMATION { + LARGE_INTEGER TotalUserTime; + LARGE_INTEGER TotalKernelTime; + LARGE_INTEGER ThisPeriodTotalUserTime; + LARGE_INTEGER ThisPeriodTotalKernelTime; + DWORD TotalPageFaultCount; + DWORD TotalProcesses; + DWORD ActiveProcesses; + DWORD TotalTerminatedProcesses; + } JOBOBJECT_BASIC_ACCOUNTING_INFORMATION,*PJOBOBJECT_BASIC_ACCOUNTING_INFORMATION; + + typedef struct _JOBOBJECT_BASIC_LIMIT_INFORMATION { + LARGE_INTEGER PerProcessUserTimeLimit; + LARGE_INTEGER PerJobUserTimeLimit; + DWORD LimitFlags; + SIZE_T MinimumWorkingSetSize; + SIZE_T MaximumWorkingSetSize; + DWORD ActiveProcessLimit; + ULONG_PTR Affinity; + DWORD PriorityClass; + DWORD SchedulingClass; + } JOBOBJECT_BASIC_LIMIT_INFORMATION,*PJOBOBJECT_BASIC_LIMIT_INFORMATION; + + typedef struct _JOBOBJECT_EXTENDED_LIMIT_INFORMATION { + JOBOBJECT_BASIC_LIMIT_INFORMATION BasicLimitInformation; + IO_COUNTERS IoInfo; + SIZE_T ProcessMemoryLimit; + SIZE_T JobMemoryLimit; + SIZE_T PeakProcessMemoryUsed; + SIZE_T PeakJobMemoryUsed; + } JOBOBJECT_EXTENDED_LIMIT_INFORMATION,*PJOBOBJECT_EXTENDED_LIMIT_INFORMATION; + + typedef struct _JOBOBJECT_BASIC_PROCESS_ID_LIST { + DWORD NumberOfAssignedProcesses; + DWORD NumberOfProcessIdsInList; + ULONG_PTR ProcessIdList[1]; + } JOBOBJECT_BASIC_PROCESS_ID_LIST,*PJOBOBJECT_BASIC_PROCESS_ID_LIST; + + typedef struct _JOBOBJECT_BASIC_UI_RESTRICTIONS { + DWORD UIRestrictionsClass; + } JOBOBJECT_BASIC_UI_RESTRICTIONS,*PJOBOBJECT_BASIC_UI_RESTRICTIONS; + + typedef struct _JOBOBJECT_SECURITY_LIMIT_INFORMATION { + DWORD SecurityLimitFlags; + HANDLE JobToken; + PTOKEN_GROUPS SidsToDisable; + PTOKEN_PRIVILEGES PrivilegesToDelete; + PTOKEN_GROUPS RestrictedSids; + } JOBOBJECT_SECURITY_LIMIT_INFORMATION,*PJOBOBJECT_SECURITY_LIMIT_INFORMATION; + + typedef struct _JOBOBJECT_END_OF_JOB_TIME_INFORMATION { + DWORD EndOfJobTimeAction; + } JOBOBJECT_END_OF_JOB_TIME_INFORMATION,*PJOBOBJECT_END_OF_JOB_TIME_INFORMATION; + + typedef struct _JOBOBJECT_ASSOCIATE_COMPLETION_PORT { + PVOID CompletionKey; + HANDLE CompletionPort; + } JOBOBJECT_ASSOCIATE_COMPLETION_PORT,*PJOBOBJECT_ASSOCIATE_COMPLETION_PORT; + + typedef struct _JOBOBJECT_BASIC_AND_IO_ACCOUNTING_INFORMATION { + JOBOBJECT_BASIC_ACCOUNTING_INFORMATION BasicInfo; + IO_COUNTERS IoInfo; + } JOBOBJECT_BASIC_AND_IO_ACCOUNTING_INFORMATION,*PJOBOBJECT_BASIC_AND_IO_ACCOUNTING_INFORMATION; + + typedef struct _JOBOBJECT_JOBSET_INFORMATION { + DWORD MemberLevel; + } JOBOBJECT_JOBSET_INFORMATION,*PJOBOBJECT_JOBSET_INFORMATION; + +#define JOB_OBJECT_TERMINATE_AT_END_OF_JOB 0 +#define JOB_OBJECT_POST_AT_END_OF_JOB 1 + +#define JOB_OBJECT_MSG_END_OF_JOB_TIME 1 +#define JOB_OBJECT_MSG_END_OF_PROCESS_TIME 2 +#define JOB_OBJECT_MSG_ACTIVE_PROCESS_LIMIT 3 +#define JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO 4 +#define JOB_OBJECT_MSG_NEW_PROCESS 6 +#define JOB_OBJECT_MSG_EXIT_PROCESS 7 +#define JOB_OBJECT_MSG_ABNORMAL_EXIT_PROCESS 8 +#define JOB_OBJECT_MSG_PROCESS_MEMORY_LIMIT 9 +#define JOB_OBJECT_MSG_JOB_MEMORY_LIMIT 10 + +#define JOB_OBJECT_LIMIT_WORKINGSET 0x00000001 +#define JOB_OBJECT_LIMIT_PROCESS_TIME 0x00000002 +#define JOB_OBJECT_LIMIT_JOB_TIME 0x00000004 +#define JOB_OBJECT_LIMIT_ACTIVE_PROCESS 0x00000008 +#define JOB_OBJECT_LIMIT_AFFINITY 0x00000010 +#define JOB_OBJECT_LIMIT_PRIORITY_CLASS 0x00000020 +#define JOB_OBJECT_LIMIT_PRESERVE_JOB_TIME 0x00000040 +#define JOB_OBJECT_LIMIT_SCHEDULING_CLASS 0x00000080 + +#define JOB_OBJECT_LIMIT_PROCESS_MEMORY 0x00000100 +#define JOB_OBJECT_LIMIT_JOB_MEMORY 0x00000200 +#define JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION 0x00000400 +#define JOB_OBJECT_LIMIT_BREAKAWAY_OK 0x00000800 +#define JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK 0x00001000 +#define JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE 0x00002000 + +#define JOB_OBJECT_LIMIT_RESERVED2 0x00004000 +#define JOB_OBJECT_LIMIT_RESERVED3 0x00008000 +#define JOB_OBJECT_LIMIT_RESERVED4 0x00010000 +#define JOB_OBJECT_LIMIT_RESERVED5 0x00020000 +#define JOB_OBJECT_LIMIT_RESERVED6 0x00040000 + +#define JOB_OBJECT_LIMIT_VALID_FLAGS 0x0007ffff + +#define JOB_OBJECT_BASIC_LIMIT_VALID_FLAGS 0x000000ff +#define JOB_OBJECT_EXTENDED_LIMIT_VALID_FLAGS 0x00003fff +#define JOB_OBJECT_RESERVED_LIMIT_VALID_FLAGS 0x0007ffff + +#define JOB_OBJECT_UILIMIT_NONE 0x00000000 + +#define JOB_OBJECT_UILIMIT_HANDLES 0x00000001 +#define JOB_OBJECT_UILIMIT_READCLIPBOARD 0x00000002 +#define JOB_OBJECT_UILIMIT_WRITECLIPBOARD 0x00000004 +#define JOB_OBJECT_UILIMIT_SYSTEMPARAMETERS 0x00000008 +#define JOB_OBJECT_UILIMIT_DISPLAYSETTINGS 0x00000010 +#define JOB_OBJECT_UILIMIT_GLOBALATOMS 0x00000020 +#define JOB_OBJECT_UILIMIT_DESKTOP 0x00000040 +#define JOB_OBJECT_UILIMIT_EXITWINDOWS 0x00000080 + +#define JOB_OBJECT_UILIMIT_ALL 0x000000FF + +#define JOB_OBJECT_UI_VALID_FLAGS 0x000000FF + +#define JOB_OBJECT_SECURITY_NO_ADMIN 0x00000001 +#define JOB_OBJECT_SECURITY_RESTRICTED_TOKEN 0x00000002 +#define JOB_OBJECT_SECURITY_ONLY_TOKEN 0x00000004 +#define JOB_OBJECT_SECURITY_FILTER_TOKENS 0x00000008 + +#define JOB_OBJECT_SECURITY_VALID_FLAGS 0x0000000f + + typedef enum _JOBOBJECTINFOCLASS { + JobObjectBasicAccountingInformation = 1,JobObjectBasicLimitInformation,JobObjectBasicProcessIdList,JobObjectBasicUIRestrictions, + JobObjectSecurityLimitInformation,JobObjectEndOfJobTimeInformation,JobObjectAssociateCompletionPortInformation, + JobObjectBasicAndIoAccountingInformation,JobObjectExtendedLimitInformation,JobObjectJobSetInformation,MaxJobObjectInfoClass + } JOBOBJECTINFOCLASS; + +#define EVENT_MODIFY_STATE 0x0002 +#define EVENT_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|0x3) + +#define MUTANT_QUERY_STATE 0x0001 + +#define MUTANT_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE| MUTANT_QUERY_STATE) +#define SEMAPHORE_MODIFY_STATE 0x0002 +#define SEMAPHORE_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|0x3) + +#define TIMER_QUERY_STATE 0x0001 +#define TIMER_MODIFY_STATE 0x0002 + +#define TIMER_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE| TIMER_QUERY_STATE|TIMER_MODIFY_STATE) + +#define TIME_ZONE_ID_UNKNOWN 0 +#define TIME_ZONE_ID_STANDARD 1 +#define TIME_ZONE_ID_DAYLIGHT 2 + + typedef enum _LOGICAL_PROCESSOR_RELATIONSHIP { + RelationProcessorCore,RelationNumaNode,RelationCache + } LOGICAL_PROCESSOR_RELATIONSHIP; + +#define LTP_PC_SMT 0x1 + + typedef enum _PROCESSOR_CACHE_TYPE { + CacheUnified,CacheInstruction,CacheData,CacheTrace + } PROCESSOR_CACHE_TYPE; + +#define CACHE_FULLY_ASSOCIATIVE 0xFF + + typedef struct _CACHE_DESCRIPTOR { + BYTE Level; + BYTE Associativity; + WORD LineSize; + DWORD Size; + PROCESSOR_CACHE_TYPE Type; + } CACHE_DESCRIPTOR,*PCACHE_DESCRIPTOR; + + typedef struct _SYSTEM_LOGICAL_PROCESSOR_INFORMATION { + ULONG_PTR ProcessorMask; + LOGICAL_PROCESSOR_RELATIONSHIP Relationship; + union { + struct { + BYTE Flags; + } ProcessorCore; + struct { + DWORD NodeNumber; + } NumaNode; + CACHE_DESCRIPTOR Cache; + ULONGLONG Reserved[2]; + }; + } SYSTEM_LOGICAL_PROCESSOR_INFORMATION,*PSYSTEM_LOGICAL_PROCESSOR_INFORMATION; + +#define PROCESSOR_INTEL_386 386 +#define PROCESSOR_INTEL_486 486 +#define PROCESSOR_INTEL_PENTIUM 586 +#define PROCESSOR_INTEL_IA64 2200 +#define PROCESSOR_AMD_X8664 8664 +#define PROCESSOR_MIPS_R4000 4000 +#define PROCESSOR_ALPHA_21064 21064 +#define PROCESSOR_PPC_601 601 +#define PROCESSOR_PPC_603 603 +#define PROCESSOR_PPC_604 604 +#define PROCESSOR_PPC_620 620 +#define PROCESSOR_HITACHI_SH3 10003 +#define PROCESSOR_HITACHI_SH3E 10004 +#define PROCESSOR_HITACHI_SH4 10005 +#define PROCESSOR_MOTOROLA_821 821 +#define PROCESSOR_SHx_SH3 103 +#define PROCESSOR_SHx_SH4 104 +#define PROCESSOR_STRONGARM 2577 +#define PROCESSOR_ARM720 1824 +#define PROCESSOR_ARM820 2080 +#define PROCESSOR_ARM920 2336 +#define PROCESSOR_ARM_7TDMI 70001 +#define PROCESSOR_OPTIL 0x494f + +#define PROCESSOR_ARCHITECTURE_INTEL 0 +#define PROCESSOR_ARCHITECTURE_MIPS 1 +#define PROCESSOR_ARCHITECTURE_ALPHA 2 +#define PROCESSOR_ARCHITECTURE_PPC 3 +#define PROCESSOR_ARCHITECTURE_SHX 4 +#define PROCESSOR_ARCHITECTURE_ARM 5 +#define PROCESSOR_ARCHITECTURE_IA64 6 +#define PROCESSOR_ARCHITECTURE_ALPHA64 7 +#define PROCESSOR_ARCHITECTURE_MSIL 8 +#define PROCESSOR_ARCHITECTURE_AMD64 9 +#define PROCESSOR_ARCHITECTURE_IA32_ON_WIN64 10 + +#define PROCESSOR_ARCHITECTURE_UNKNOWN 0xFFFF + +#define PF_FLOATING_POINT_PRECISION_ERRATA 0 +#define PF_FLOATING_POINT_EMULATED 1 +#define PF_COMPARE_EXCHANGE_DOUBLE 2 +#define PF_MMX_INSTRUCTIONS_AVAILABLE 3 +#define PF_PPC_MOVEMEM_64BIT_OK 4 +#define PF_ALPHA_BYTE_INSTRUCTIONS 5 +#define PF_XMMI_INSTRUCTIONS_AVAILABLE 6 +#define PF_3DNOW_INSTRUCTIONS_AVAILABLE 7 +#define PF_RDTSC_INSTRUCTION_AVAILABLE 8 +#define PF_PAE_ENABLED 9 +#define PF_XMMI64_INSTRUCTIONS_AVAILABLE 10 +#define PF_SSE_DAZ_MODE_AVAILABLE 11 +#define PF_NX_ENABLED 12 + + typedef struct _MEMORY_BASIC_INFORMATION { + PVOID BaseAddress; + PVOID AllocationBase; + DWORD AllocationProtect; + SIZE_T RegionSize; + DWORD State; + DWORD Protect; + DWORD Type; + } MEMORY_BASIC_INFORMATION,*PMEMORY_BASIC_INFORMATION; + + typedef struct _MEMORY_BASIC_INFORMATION32 { + DWORD BaseAddress; + DWORD AllocationBase; + DWORD AllocationProtect; + DWORD RegionSize; + DWORD State; + DWORD Protect; + DWORD Type; + } MEMORY_BASIC_INFORMATION32,*PMEMORY_BASIC_INFORMATION32; + + typedef DECLSPEC_ALIGN(16) struct _MEMORY_BASIC_INFORMATION64 { + ULONGLONG BaseAddress; + ULONGLONG AllocationBase; + DWORD AllocationProtect; + DWORD __alignment1; + ULONGLONG RegionSize; + DWORD State; + DWORD Protect; + DWORD Type; + DWORD __alignment2; + } MEMORY_BASIC_INFORMATION64,*PMEMORY_BASIC_INFORMATION64; + +#define SECTION_QUERY 0x0001 +#define SECTION_MAP_WRITE 0x0002 +#define SECTION_MAP_READ 0x0004 +#define SECTION_MAP_EXECUTE 0x0008 +#define SECTION_EXTEND_SIZE 0x0010 +#define SECTION_MAP_EXECUTE_EXPLICIT 0x0020 + +#define SECTION_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED|SECTION_QUERY| SECTION_MAP_WRITE | SECTION_MAP_READ | SECTION_MAP_EXECUTE | SECTION_EXTEND_SIZE) +#define PAGE_NOACCESS 0x01 +#define PAGE_READONLY 0x02 +#define PAGE_READWRITE 0x04 +#define PAGE_WRITECOPY 0x08 +#define PAGE_EXECUTE 0x10 +#define PAGE_EXECUTE_READ 0x20 +#define PAGE_EXECUTE_READWRITE 0x40 +#define PAGE_EXECUTE_WRITECOPY 0x80 +#define PAGE_GUARD 0x100 +#define PAGE_NOCACHE 0x200 +#define PAGE_WRITECOMBINE 0x400 +#define MEM_COMMIT 0x1000 +#define MEM_RESERVE 0x2000 +#define MEM_DECOMMIT 0x4000 +#define MEM_RELEASE 0x8000 +#define MEM_FREE 0x10000 +#define MEM_PRIVATE 0x20000 +#define MEM_MAPPED 0x40000 +#define MEM_RESET 0x80000 +#define MEM_TOP_DOWN 0x100000 +#define MEM_WRITE_WATCH 0x200000 +#define MEM_PHYSICAL 0x400000 +#define MEM_LARGE_PAGES 0x20000000 +#define MEM_4MB_PAGES 0x80000000 +#define SEC_FILE 0x800000 +#define SEC_IMAGE 0x1000000 +#define SEC_RESERVE 0x4000000 +#define SEC_COMMIT 0x8000000 +#define SEC_NOCACHE 0x10000000 +#define SEC_LARGE_PAGES 0x80000000 +#define MEM_IMAGE SEC_IMAGE +#define WRITE_WATCH_FLAG_RESET 0x01 + +#define FILE_READ_DATA (0x0001) +#define FILE_LIST_DIRECTORY (0x0001) + +#define FILE_WRITE_DATA (0x0002) +#define FILE_ADD_FILE (0x0002) + +#define FILE_APPEND_DATA (0x0004) +#define FILE_ADD_SUBDIRECTORY (0x0004) +#define FILE_CREATE_PIPE_INSTANCE (0x0004) + +#define FILE_READ_EA (0x0008) + +#define FILE_WRITE_EA (0x0010) + +#define FILE_EXECUTE (0x0020) +#define FILE_TRAVERSE (0x0020) + +#define FILE_DELETE_CHILD (0x0040) + +#define FILE_READ_ATTRIBUTES (0x0080) + +#define FILE_WRITE_ATTRIBUTES (0x0100) + +#define FILE_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x1FF) +#define FILE_GENERIC_READ (STANDARD_RIGHTS_READ | FILE_READ_DATA | FILE_READ_ATTRIBUTES | FILE_READ_EA | SYNCHRONIZE) +#define FILE_GENERIC_WRITE (STANDARD_RIGHTS_WRITE | FILE_WRITE_DATA | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA | FILE_APPEND_DATA | SYNCHRONIZE) +#define FILE_GENERIC_EXECUTE (STANDARD_RIGHTS_EXECUTE | FILE_READ_ATTRIBUTES | FILE_EXECUTE | SYNCHRONIZE) + +#define FILE_SHARE_READ 0x00000001 +#define FILE_SHARE_WRITE 0x00000002 +#define FILE_SHARE_DELETE 0x00000004 +#define FILE_ATTRIBUTE_READONLY 0x00000001 +#define FILE_ATTRIBUTE_HIDDEN 0x00000002 +#define FILE_ATTRIBUTE_SYSTEM 0x00000004 +#define FILE_ATTRIBUTE_DIRECTORY 0x00000010 +#define FILE_ATTRIBUTE_ARCHIVE 0x00000020 +#define FILE_ATTRIBUTE_DEVICE 0x00000040 +#define FILE_ATTRIBUTE_NORMAL 0x00000080 +#define FILE_ATTRIBUTE_TEMPORARY 0x00000100 +#define FILE_ATTRIBUTE_SPARSE_FILE 0x00000200 +#define FILE_ATTRIBUTE_REPARSE_POINT 0x00000400 +#define FILE_ATTRIBUTE_COMPRESSED 0x00000800 +#define FILE_ATTRIBUTE_OFFLINE 0x00001000 +#define FILE_ATTRIBUTE_NOT_CONTENT_INDEXED 0x00002000 +#define FILE_ATTRIBUTE_ENCRYPTED 0x00004000 +#define FILE_NOTIFY_CHANGE_FILE_NAME 0x00000001 +#define FILE_NOTIFY_CHANGE_DIR_NAME 0x00000002 +#define FILE_NOTIFY_CHANGE_ATTRIBUTES 0x00000004 +#define FILE_NOTIFY_CHANGE_SIZE 0x00000008 +#define FILE_NOTIFY_CHANGE_LAST_WRITE 0x00000010 +#define FILE_NOTIFY_CHANGE_LAST_ACCESS 0x00000020 +#define FILE_NOTIFY_CHANGE_CREATION 0x00000040 +#define FILE_NOTIFY_CHANGE_SECURITY 0x00000100 +#define FILE_ACTION_ADDED 0x00000001 +#define FILE_ACTION_REMOVED 0x00000002 +#define FILE_ACTION_MODIFIED 0x00000003 +#define FILE_ACTION_RENAMED_OLD_NAME 0x00000004 +#define FILE_ACTION_RENAMED_NEW_NAME 0x00000005 +#define MAILSLOT_NO_MESSAGE ((DWORD)-1) +#define MAILSLOT_WAIT_FOREVER ((DWORD)-1) +#define FILE_CASE_SENSITIVE_SEARCH 0x00000001 +#define FILE_CASE_PRESERVED_NAMES 0x00000002 +#define FILE_UNICODE_ON_DISK 0x00000004 +#define FILE_PERSISTENT_ACLS 0x00000008 +#define FILE_FILE_COMPRESSION 0x00000010 +#define FILE_VOLUME_QUOTAS 0x00000020 +#define FILE_SUPPORTS_SPARSE_FILES 0x00000040 +#define FILE_SUPPORTS_REPARSE_POINTS 0x00000080 +#define FILE_SUPPORTS_REMOTE_STORAGE 0x00000100 +#define FILE_VOLUME_IS_COMPRESSED 0x00008000 +#define FILE_SUPPORTS_OBJECT_IDS 0x00010000 +#define FILE_SUPPORTS_ENCRYPTION 0x00020000 +#define FILE_NAMED_STREAMS 0x00040000 +#define FILE_READ_ONLY_VOLUME 0x00080000 + + typedef struct _FILE_NOTIFY_INFORMATION { + DWORD NextEntryOffset; + DWORD Action; + DWORD FileNameLength; + WCHAR FileName[1]; + } FILE_NOTIFY_INFORMATION,*PFILE_NOTIFY_INFORMATION; + + typedef union _FILE_SEGMENT_ELEMENT { + PVOID64 Buffer; + ULONGLONG Alignment; + }FILE_SEGMENT_ELEMENT,*PFILE_SEGMENT_ELEMENT; + + typedef struct _REPARSE_GUID_DATA_BUFFER { + DWORD ReparseTag; + WORD ReparseDataLength; + WORD Reserved; + GUID ReparseGuid; + struct { + BYTE DataBuffer[1]; + } GenericReparseBuffer; + } REPARSE_GUID_DATA_BUFFER,*PREPARSE_GUID_DATA_BUFFER; + +#define REPARSE_GUID_DATA_BUFFER_HEADER_SIZE FIELD_OFFSET(REPARSE_GUID_DATA_BUFFER,GenericReparseBuffer) + +#define MAXIMUM_REPARSE_DATA_BUFFER_SIZE (16 *1024) + +#define IO_REPARSE_TAG_RESERVED_ZERO (0) +#define IO_REPARSE_TAG_RESERVED_ONE (1) + +#define IO_REPARSE_TAG_RESERVED_RANGE IO_REPARSE_TAG_RESERVED_ONE + +#define IsReparseTagMicrosoft(_tag) (((_tag) & 0x80000000)) +#define IsReparseTagNameSurrogate(_tag) (((_tag) & 0x20000000)) + +#define IO_REPARSE_TAG_MOUNT_POINT (0xA0000003L) +#define IO_REPARSE_TAG_HSM (0xC0000004L) +#define IO_REPARSE_TAG_SIS (0x80000007L) +#define IO_REPARSE_TAG_DFS (0x8000000AL) +#define IO_REPARSE_TAG_FILTER_MANAGER (0x8000000BL) +#define IO_COMPLETION_MODIFY_STATE 0x0002 +#define IO_COMPLETION_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|0x3) +#define DUPLICATE_CLOSE_SOURCE 0x00000001 +#define DUPLICATE_SAME_ACCESS 0x00000002 + + typedef enum _SYSTEM_POWER_STATE { + PowerSystemUnspecified = 0,PowerSystemWorking = 1,PowerSystemSleeping1 = 2,PowerSystemSleeping2 = 3,PowerSystemSleeping3 = 4,PowerSystemHibernate = 5,PowerSystemShutdown = 6,PowerSystemMaximum = 7 + } SYSTEM_POWER_STATE,*PSYSTEM_POWER_STATE; + +#define POWER_SYSTEM_MAXIMUM 7 + + typedef enum { + PowerActionNone = 0,PowerActionReserved,PowerActionSleep,PowerActionHibernate,PowerActionShutdown,PowerActionShutdownReset,PowerActionShutdownOff,PowerActionWarmEject + } POWER_ACTION,*PPOWER_ACTION; + + typedef enum _DEVICE_POWER_STATE { + PowerDeviceUnspecified = 0,PowerDeviceD0,PowerDeviceD1,PowerDeviceD2,PowerDeviceD3,PowerDeviceMaximum + } DEVICE_POWER_STATE,*PDEVICE_POWER_STATE; + +#define ES_SYSTEM_REQUIRED ((DWORD)0x00000001) +#define ES_DISPLAY_REQUIRED ((DWORD)0x00000002) +#define ES_USER_PRESENT ((DWORD)0x00000004) +#define ES_CONTINUOUS ((DWORD)0x80000000) + + typedef DWORD EXECUTION_STATE; + + typedef enum { + LT_DONT_CARE,LT_LOWEST_LATENCY + } LATENCY_TIME; + +#define PDCAP_D0_SUPPORTED 0x00000001 +#define PDCAP_D1_SUPPORTED 0x00000002 +#define PDCAP_D2_SUPPORTED 0x00000004 +#define PDCAP_D3_SUPPORTED 0x00000008 +#define PDCAP_WAKE_FROM_D0_SUPPORTED 0x00000010 +#define PDCAP_WAKE_FROM_D1_SUPPORTED 0x00000020 +#define PDCAP_WAKE_FROM_D2_SUPPORTED 0x00000040 +#define PDCAP_WAKE_FROM_D3_SUPPORTED 0x00000080 +#define PDCAP_WARM_EJECT_SUPPORTED 0x00000100 + + typedef struct CM_Power_Data_s { + DWORD PD_Size; + DEVICE_POWER_STATE PD_MostRecentPowerState; + DWORD PD_Capabilities; + DWORD PD_D1Latency; + DWORD PD_D2Latency; + DWORD PD_D3Latency; + DEVICE_POWER_STATE PD_PowerStateMapping[POWER_SYSTEM_MAXIMUM]; + SYSTEM_POWER_STATE PD_DeepestSystemWake; + } CM_POWER_DATA,*PCM_POWER_DATA; + + typedef enum { + SystemPowerPolicyAc,SystemPowerPolicyDc,VerifySystemPolicyAc,VerifySystemPolicyDc,SystemPowerCapabilities,SystemBatteryState,SystemPowerStateHandler,ProcessorStateHandler,SystemPowerPolicyCurrent,AdministratorPowerPolicy,SystemReserveHiberFile,ProcessorInformation,SystemPowerInformation,ProcessorStateHandler2,LastWakeTime,LastSleepTime,SystemExecutionState,SystemPowerStateNotifyHandler,ProcessorPowerPolicyAc,ProcessorPowerPolicyDc,VerifyProcessorPowerPolicyAc,VerifyProcessorPowerPolicyDc,ProcessorPowerPolicyCurrent,SystemPowerStateLogging,SystemPowerLoggingEntry + } POWER_INFORMATION_LEVEL; + + typedef struct { + DWORD Granularity; + DWORD Capacity; + } BATTERY_REPORTING_SCALE,*PBATTERY_REPORTING_SCALE; + + typedef struct { + POWER_ACTION Action; + DWORD Flags; + DWORD EventCode; + } POWER_ACTION_POLICY,*PPOWER_ACTION_POLICY; + +#define POWER_ACTION_QUERY_ALLOWED 0x00000001 +#define POWER_ACTION_UI_ALLOWED 0x00000002 +#define POWER_ACTION_OVERRIDE_APPS 0x00000004 +#define POWER_ACTION_LIGHTEST_FIRST 0x10000000 +#define POWER_ACTION_LOCK_CONSOLE 0x20000000 +#define POWER_ACTION_DISABLE_WAKES 0x40000000 +#define POWER_ACTION_CRITICAL 0x80000000 + +#define POWER_LEVEL_USER_NOTIFY_TEXT 0x00000001 +#define POWER_LEVEL_USER_NOTIFY_SOUND 0x00000002 +#define POWER_LEVEL_USER_NOTIFY_EXEC 0x00000004 +#define POWER_USER_NOTIFY_BUTTON 0x00000008 +#define POWER_USER_NOTIFY_SHUTDOWN 0x00000010 +#define POWER_FORCE_TRIGGER_RESET 0x80000000 + + typedef struct { + BOOLEAN Enable; + BYTE Spare[3]; + DWORD BatteryLevel; + POWER_ACTION_POLICY PowerPolicy; + SYSTEM_POWER_STATE MinSystemState; + } SYSTEM_POWER_LEVEL,*PSYSTEM_POWER_LEVEL; + +#define NUM_DISCHARGE_POLICIES 4 +#define DISCHARGE_POLICY_CRITICAL 0 +#define DISCHARGE_POLICY_LOW 1 + +#define PO_THROTTLE_NONE 0 +#define PO_THROTTLE_CONSTANT 1 +#define PO_THROTTLE_DEGRADE 2 +#define PO_THROTTLE_ADAPTIVE 3 +#define PO_THROTTLE_MAXIMUM 4 + + typedef struct _SYSTEM_POWER_POLICY { + DWORD Revision; + POWER_ACTION_POLICY PowerButton; + POWER_ACTION_POLICY SleepButton; + POWER_ACTION_POLICY LidClose; + SYSTEM_POWER_STATE LidOpenWake; + DWORD Reserved; + POWER_ACTION_POLICY Idle; + DWORD IdleTimeout; + BYTE IdleSensitivity; + BYTE DynamicThrottle; + BYTE Spare2[2]; + SYSTEM_POWER_STATE MinSleep; + SYSTEM_POWER_STATE MaxSleep; + SYSTEM_POWER_STATE ReducedLatencySleep; + DWORD WinLogonFlags; + DWORD Spare3; + DWORD DozeS4Timeout; + DWORD BroadcastCapacityResolution; + SYSTEM_POWER_LEVEL DischargePolicy[NUM_DISCHARGE_POLICIES]; + DWORD VideoTimeout; + BOOLEAN VideoDimDisplay; + DWORD VideoReserved[3]; + DWORD SpindownTimeout; + BOOLEAN OptimizeForPower; + BYTE FanThrottleTolerance; + BYTE ForcedThrottle; + BYTE MinThrottle; + POWER_ACTION_POLICY OverThrottled; + } SYSTEM_POWER_POLICY,*PSYSTEM_POWER_POLICY; + + typedef struct _PROCESSOR_POWER_POLICY_INFO { + DWORD TimeCheck; + DWORD DemoteLimit; + DWORD PromoteLimit; + BYTE DemotePercent; + BYTE PromotePercent; + BYTE Spare[2]; + DWORD AllowDemotion:1; + DWORD AllowPromotion:1; + DWORD Reserved:30; + } PROCESSOR_POWER_POLICY_INFO,*PPROCESSOR_POWER_POLICY_INFO; + + typedef struct _PROCESSOR_POWER_POLICY { + DWORD Revision; + BYTE DynamicThrottle; + BYTE Spare[3]; + DWORD DisableCStates:1; + DWORD Reserved:31; + DWORD PolicyCount; + PROCESSOR_POWER_POLICY_INFO Policy[3]; + } PROCESSOR_POWER_POLICY,*PPROCESSOR_POWER_POLICY; + + typedef struct _ADMINISTRATOR_POWER_POLICY { + SYSTEM_POWER_STATE MinSleep; + SYSTEM_POWER_STATE MaxSleep; + DWORD MinVideoTimeout; + DWORD MaxVideoTimeout; + DWORD MinSpindownTimeout; + DWORD MaxSpindownTimeout; + } ADMINISTRATOR_POWER_POLICY,*PADMINISTRATOR_POWER_POLICY; + + typedef struct { + BOOLEAN PowerButtonPresent; + BOOLEAN SleepButtonPresent; + BOOLEAN LidPresent; + BOOLEAN SystemS1; + BOOLEAN SystemS2; + BOOLEAN SystemS3; + BOOLEAN SystemS4; + BOOLEAN SystemS5; + BOOLEAN HiberFilePresent; + BOOLEAN FullWake; + BOOLEAN VideoDimPresent; + BOOLEAN ApmPresent; + BOOLEAN UpsPresent; + BOOLEAN ThermalControl; + BOOLEAN ProcessorThrottle; + BYTE ProcessorMinThrottle; + BYTE ProcessorMaxThrottle; + BYTE spare2[4]; + BOOLEAN DiskSpinDown; + BYTE spare3[8]; + BOOLEAN SystemBatteriesPresent; + BOOLEAN BatteriesAreShortTerm; + BATTERY_REPORTING_SCALE BatteryScale[3]; + SYSTEM_POWER_STATE AcOnLineWake; + SYSTEM_POWER_STATE SoftLidWake; + SYSTEM_POWER_STATE RtcWake; + SYSTEM_POWER_STATE MinDeviceWakeState; + SYSTEM_POWER_STATE DefaultLowLatencyWake; + } SYSTEM_POWER_CAPABILITIES,*PSYSTEM_POWER_CAPABILITIES; + + typedef struct { + BOOLEAN AcOnLine; + BOOLEAN BatteryPresent; + BOOLEAN Charging; + BOOLEAN Discharging; + BOOLEAN Spare1[4]; + DWORD MaxCapacity; + DWORD RemainingCapacity; + DWORD Rate; + DWORD EstimatedTime; + DWORD DefaultAlert1; + DWORD DefaultAlert2; + } SYSTEM_BATTERY_STATE,*PSYSTEM_BATTERY_STATE; + +#include "pshpack4.h" + +#define IMAGE_DOS_SIGNATURE 0x5A4D +#define IMAGE_OS2_SIGNATURE 0x454E +#define IMAGE_OS2_SIGNATURE_LE 0x454C +#define IMAGE_VXD_SIGNATURE 0x454C +#define IMAGE_NT_SIGNATURE 0x00004550 + +#include "pshpack2.h" + + typedef struct _IMAGE_DOS_HEADER { + WORD e_magic; + WORD e_cblp; + WORD e_cp; + WORD e_crlc; + WORD e_cparhdr; + WORD e_minalloc; + WORD e_maxalloc; + WORD e_ss; + WORD e_sp; + WORD e_csum; + WORD e_ip; + WORD e_cs; + WORD e_lfarlc; + WORD e_ovno; + WORD e_res[4]; + WORD e_oemid; + WORD e_oeminfo; + WORD e_res2[10]; + LONG e_lfanew; + } IMAGE_DOS_HEADER,*PIMAGE_DOS_HEADER; + + typedef struct _IMAGE_OS2_HEADER { + WORD ne_magic; + CHAR ne_ver; + CHAR ne_rev; + WORD ne_enttab; + WORD ne_cbenttab; + LONG ne_crc; + WORD ne_flags; + WORD ne_autodata; + WORD ne_heap; + WORD ne_stack; + LONG ne_csip; + LONG ne_sssp; + WORD ne_cseg; + WORD ne_cmod; + WORD ne_cbnrestab; + WORD ne_segtab; + WORD ne_rsrctab; + WORD ne_restab; + WORD ne_modtab; + WORD ne_imptab; + LONG ne_nrestab; + WORD ne_cmovent; + WORD ne_align; + WORD ne_cres; + BYTE ne_exetyp; + BYTE ne_flagsothers; + WORD ne_pretthunks; + WORD ne_psegrefbytes; + WORD ne_swaparea; + WORD ne_expver; + } IMAGE_OS2_HEADER,*PIMAGE_OS2_HEADER; + + typedef struct _IMAGE_VXD_HEADER { + WORD e32_magic; + BYTE e32_border; + BYTE e32_worder; + DWORD e32_level; + WORD e32_cpu; + WORD e32_os; + DWORD e32_ver; + DWORD e32_mflags; + DWORD e32_mpages; + DWORD e32_startobj; + DWORD e32_eip; + DWORD e32_stackobj; + DWORD e32_esp; + DWORD e32_pagesize; + DWORD e32_lastpagesize; + DWORD e32_fixupsize; + DWORD e32_fixupsum; + DWORD e32_ldrsize; + DWORD e32_ldrsum; + DWORD e32_objtab; + DWORD e32_objcnt; + DWORD e32_objmap; + DWORD e32_itermap; + DWORD e32_rsrctab; + DWORD e32_rsrccnt; + DWORD e32_restab; + DWORD e32_enttab; + DWORD e32_dirtab; + DWORD e32_dircnt; + DWORD e32_fpagetab; + DWORD e32_frectab; + DWORD e32_impmod; + DWORD e32_impmodcnt; + DWORD e32_impproc; + DWORD e32_pagesum; + DWORD e32_datapage; + DWORD e32_preload; + DWORD e32_nrestab; + DWORD e32_cbnrestab; + DWORD e32_nressum; + DWORD e32_autodata; + DWORD e32_debuginfo; + DWORD e32_debuglen; + DWORD e32_instpreload; + DWORD e32_instdemand; + DWORD e32_heapsize; + BYTE e32_res3[12]; + DWORD e32_winresoff; + DWORD e32_winreslen; + WORD e32_devid; + WORD e32_ddkver; + } IMAGE_VXD_HEADER,*PIMAGE_VXD_HEADER; + +#include "poppack.h" + + typedef struct _IMAGE_FILE_HEADER { + WORD Machine; + WORD NumberOfSections; + DWORD TimeDateStamp; + DWORD PointerToSymbolTable; + DWORD NumberOfSymbols; + WORD SizeOfOptionalHeader; + WORD Characteristics; + } IMAGE_FILE_HEADER,*PIMAGE_FILE_HEADER; + +#define IMAGE_SIZEOF_FILE_HEADER 20 + +#define IMAGE_FILE_RELOCS_STRIPPED 0x0001 +#define IMAGE_FILE_EXECUTABLE_IMAGE 0x0002 +#define IMAGE_FILE_LINE_NUMS_STRIPPED 0x0004 +#define IMAGE_FILE_LOCAL_SYMS_STRIPPED 0x0008 +#define IMAGE_FILE_AGGRESIVE_WS_TRIM 0x0010 +#define IMAGE_FILE_LARGE_ADDRESS_AWARE 0x0020 +#define IMAGE_FILE_BYTES_REVERSED_LO 0x0080 +#define IMAGE_FILE_32BIT_MACHINE 0x0100 +#define IMAGE_FILE_DEBUG_STRIPPED 0x0200 +#define IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP 0x0400 +#define IMAGE_FILE_NET_RUN_FROM_SWAP 0x0800 +#define IMAGE_FILE_SYSTEM 0x1000 +#define IMAGE_FILE_DLL 0x2000 +#define IMAGE_FILE_UP_SYSTEM_ONLY 0x4000 +#define IMAGE_FILE_BYTES_REVERSED_HI 0x8000 + +#define IMAGE_FILE_MACHINE_UNKNOWN 0 +#define IMAGE_FILE_MACHINE_I386 0x014c +#define IMAGE_FILE_MACHINE_R3000 0x0162 +#define IMAGE_FILE_MACHINE_R4000 0x0166 +#define IMAGE_FILE_MACHINE_R10000 0x0168 +#define IMAGE_FILE_MACHINE_WCEMIPSV2 0x0169 +#define IMAGE_FILE_MACHINE_ALPHA 0x0184 +#define IMAGE_FILE_MACHINE_SH3 0x01a2 +#define IMAGE_FILE_MACHINE_SH3DSP 0x01a3 +#define IMAGE_FILE_MACHINE_SH3E 0x01a4 +#define IMAGE_FILE_MACHINE_SH4 0x01a6 +#define IMAGE_FILE_MACHINE_SH5 0x01a8 +#define IMAGE_FILE_MACHINE_ARM 0x01c0 +#define IMAGE_FILE_MACHINE_THUMB 0x01c2 +#define IMAGE_FILE_MACHINE_AM33 0x01d3 +#define IMAGE_FILE_MACHINE_POWERPC 0x01F0 +#define IMAGE_FILE_MACHINE_POWERPCFP 0x01f1 +#define IMAGE_FILE_MACHINE_IA64 0x0200 +#define IMAGE_FILE_MACHINE_MIPS16 0x0266 +#define IMAGE_FILE_MACHINE_ALPHA64 0x0284 +#define IMAGE_FILE_MACHINE_MIPSFPU 0x0366 +#define IMAGE_FILE_MACHINE_MIPSFPU16 0x0466 +#define IMAGE_FILE_MACHINE_AXP64 IMAGE_FILE_MACHINE_ALPHA64 +#define IMAGE_FILE_MACHINE_TRICORE 0x0520 +#define IMAGE_FILE_MACHINE_CEF 0x0CEF +#define IMAGE_FILE_MACHINE_EBC 0x0EBC +#define IMAGE_FILE_MACHINE_AMD64 0x8664 +#define IMAGE_FILE_MACHINE_M32R 0x9041 +#define IMAGE_FILE_MACHINE_CEE 0xC0EE + + typedef struct _IMAGE_DATA_DIRECTORY { + DWORD VirtualAddress; + DWORD Size; + } IMAGE_DATA_DIRECTORY,*PIMAGE_DATA_DIRECTORY; + +#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16 + + typedef struct _IMAGE_OPTIONAL_HEADER { + + WORD Magic; + BYTE MajorLinkerVersion; + BYTE MinorLinkerVersion; + DWORD SizeOfCode; + DWORD SizeOfInitializedData; + DWORD SizeOfUninitializedData; + DWORD AddressOfEntryPoint; + DWORD BaseOfCode; + DWORD BaseOfData; + DWORD ImageBase; + DWORD SectionAlignment; + DWORD FileAlignment; + WORD MajorOperatingSystemVersion; + WORD MinorOperatingSystemVersion; + WORD MajorImageVersion; + WORD MinorImageVersion; + WORD MajorSubsystemVersion; + WORD MinorSubsystemVersion; + DWORD Win32VersionValue; + DWORD SizeOfImage; + DWORD SizeOfHeaders; + DWORD CheckSum; + WORD Subsystem; + WORD DllCharacteristics; + DWORD SizeOfStackReserve; + DWORD SizeOfStackCommit; + DWORD SizeOfHeapReserve; + DWORD SizeOfHeapCommit; + DWORD LoaderFlags; + DWORD NumberOfRvaAndSizes; + IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; + } IMAGE_OPTIONAL_HEADER32,*PIMAGE_OPTIONAL_HEADER32; + + typedef struct _IMAGE_ROM_OPTIONAL_HEADER { + WORD Magic; + BYTE MajorLinkerVersion; + BYTE MinorLinkerVersion; + DWORD SizeOfCode; + DWORD SizeOfInitializedData; + DWORD SizeOfUninitializedData; + DWORD AddressOfEntryPoint; + DWORD BaseOfCode; + DWORD BaseOfData; + DWORD BaseOfBss; + DWORD GprMask; + DWORD CprMask[4]; + DWORD GpValue; + } IMAGE_ROM_OPTIONAL_HEADER,*PIMAGE_ROM_OPTIONAL_HEADER; + + typedef struct _IMAGE_OPTIONAL_HEADER64 { + WORD Magic; + BYTE MajorLinkerVersion; + BYTE MinorLinkerVersion; + DWORD SizeOfCode; + DWORD SizeOfInitializedData; + DWORD SizeOfUninitializedData; + DWORD AddressOfEntryPoint; + DWORD BaseOfCode; + ULONGLONG ImageBase; + DWORD SectionAlignment; + DWORD FileAlignment; + WORD MajorOperatingSystemVersion; + WORD MinorOperatingSystemVersion; + WORD MajorImageVersion; + WORD MinorImageVersion; + WORD MajorSubsystemVersion; + WORD MinorSubsystemVersion; + DWORD Win32VersionValue; + DWORD SizeOfImage; + DWORD SizeOfHeaders; + DWORD CheckSum; + WORD Subsystem; + WORD DllCharacteristics; + ULONGLONG SizeOfStackReserve; + ULONGLONG SizeOfStackCommit; + ULONGLONG SizeOfHeapReserve; + ULONGLONG SizeOfHeapCommit; + DWORD LoaderFlags; + DWORD NumberOfRvaAndSizes; + IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; + } IMAGE_OPTIONAL_HEADER64,*PIMAGE_OPTIONAL_HEADER64; + +#define IMAGE_SIZEOF_ROM_OPTIONAL_HEADER 56 +#define IMAGE_SIZEOF_STD_OPTIONAL_HEADER 28 +#define IMAGE_SIZEOF_NT_OPTIONAL32_HEADER 224 +#define IMAGE_SIZEOF_NT_OPTIONAL64_HEADER 240 + +#define IMAGE_NT_OPTIONAL_HDR32_MAGIC 0x10b +#define IMAGE_NT_OPTIONAL_HDR64_MAGIC 0x20b +#define IMAGE_ROM_OPTIONAL_HDR_MAGIC 0x107 + +#ifdef _WIN64 + typedef IMAGE_OPTIONAL_HEADER64 IMAGE_OPTIONAL_HEADER; + typedef PIMAGE_OPTIONAL_HEADER64 PIMAGE_OPTIONAL_HEADER; +#define IMAGE_SIZEOF_NT_OPTIONAL_HEADER IMAGE_SIZEOF_NT_OPTIONAL64_HEADER +#define IMAGE_NT_OPTIONAL_HDR_MAGIC IMAGE_NT_OPTIONAL_HDR64_MAGIC +#else + typedef IMAGE_OPTIONAL_HEADER32 IMAGE_OPTIONAL_HEADER; + typedef PIMAGE_OPTIONAL_HEADER32 PIMAGE_OPTIONAL_HEADER; +#define IMAGE_SIZEOF_NT_OPTIONAL_HEADER IMAGE_SIZEOF_NT_OPTIONAL32_HEADER +#define IMAGE_NT_OPTIONAL_HDR_MAGIC IMAGE_NT_OPTIONAL_HDR32_MAGIC +#endif + + typedef struct _IMAGE_NT_HEADERS64 { + DWORD Signature; + IMAGE_FILE_HEADER FileHeader; + IMAGE_OPTIONAL_HEADER64 OptionalHeader; + } IMAGE_NT_HEADERS64,*PIMAGE_NT_HEADERS64; + + typedef struct _IMAGE_NT_HEADERS { + DWORD Signature; + IMAGE_FILE_HEADER FileHeader; + IMAGE_OPTIONAL_HEADER32 OptionalHeader; + } IMAGE_NT_HEADERS32,*PIMAGE_NT_HEADERS32; + + typedef struct _IMAGE_ROM_HEADERS { + IMAGE_FILE_HEADER FileHeader; + IMAGE_ROM_OPTIONAL_HEADER OptionalHeader; + } IMAGE_ROM_HEADERS,*PIMAGE_ROM_HEADERS; + +#ifdef _WIN64 + typedef IMAGE_NT_HEADERS64 IMAGE_NT_HEADERS; + typedef PIMAGE_NT_HEADERS64 PIMAGE_NT_HEADERS; +#else + typedef IMAGE_NT_HEADERS32 IMAGE_NT_HEADERS; + typedef PIMAGE_NT_HEADERS32 PIMAGE_NT_HEADERS; +#endif + +#define IMAGE_FIRST_SECTION(ntheader) ((PIMAGE_SECTION_HEADER) ((ULONG_PTR)ntheader + FIELD_OFFSET(IMAGE_NT_HEADERS,OptionalHeader) + ((PIMAGE_NT_HEADERS)(ntheader))->FileHeader.SizeOfOptionalHeader)) + +#define IMAGE_SUBSYSTEM_UNKNOWN 0 +#define IMAGE_SUBSYSTEM_NATIVE 1 +#define IMAGE_SUBSYSTEM_WINDOWS_GUI 2 +#define IMAGE_SUBSYSTEM_WINDOWS_CUI 3 +#define IMAGE_SUBSYSTEM_OS2_CUI 5 +#define IMAGE_SUBSYSTEM_POSIX_CUI 7 +#define IMAGE_SUBSYSTEM_NATIVE_WINDOWS 8 +#define IMAGE_SUBSYSTEM_WINDOWS_CE_GUI 9 +#define IMAGE_SUBSYSTEM_EFI_APPLICATION 10 +#define IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER 11 +#define IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER 12 +#define IMAGE_SUBSYSTEM_EFI_ROM 13 +#define IMAGE_SUBSYSTEM_XBOX 14 + +#define IMAGE_DLLCHARACTERISTICS_NO_ISOLATION 0x0200 +#define IMAGE_DLLCHARACTERISTICS_NO_SEH 0x0400 +#define IMAGE_DLLCHARACTERISTICS_NO_BIND 0x0800 +#define IMAGE_DLLCHARACTERISTICS_WDM_DRIVER 0x2000 +#define IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE 0x8000 + +#define IMAGE_DIRECTORY_ENTRY_EXPORT 0 +#define IMAGE_DIRECTORY_ENTRY_IMPORT 1 +#define IMAGE_DIRECTORY_ENTRY_RESOURCE 2 +#define IMAGE_DIRECTORY_ENTRY_EXCEPTION 3 +#define IMAGE_DIRECTORY_ENTRY_SECURITY 4 +#define IMAGE_DIRECTORY_ENTRY_BASERELOC 5 +#define IMAGE_DIRECTORY_ENTRY_DEBUG 6 + +#define IMAGE_DIRECTORY_ENTRY_ARCHITECTURE 7 +#define IMAGE_DIRECTORY_ENTRY_GLOBALPTR 8 +#define IMAGE_DIRECTORY_ENTRY_TLS 9 +#define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 10 +#define IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT 11 +#define IMAGE_DIRECTORY_ENTRY_IAT 12 +#define IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT 13 +#define IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR 14 + + typedef struct ANON_OBJECT_HEADER { + WORD Sig1; + WORD Sig2; + WORD Version; + WORD Machine; + DWORD TimeDateStamp; + CLSID ClassID; + DWORD SizeOfData; + } ANON_OBJECT_HEADER; + +#define IMAGE_SIZEOF_SHORT_NAME 8 + + typedef struct _IMAGE_SECTION_HEADER { + BYTE Name[IMAGE_SIZEOF_SHORT_NAME]; + union { + DWORD PhysicalAddress; + DWORD VirtualSize; + } Misc; + DWORD VirtualAddress; + DWORD SizeOfRawData; + DWORD PointerToRawData; + DWORD PointerToRelocations; + DWORD PointerToLinenumbers; + WORD NumberOfRelocations; + WORD NumberOfLinenumbers; + DWORD Characteristics; + } IMAGE_SECTION_HEADER,*PIMAGE_SECTION_HEADER; + +#define IMAGE_SIZEOF_SECTION_HEADER 40 + +#define IMAGE_SCN_TYPE_NO_PAD 0x00000008 + +#define IMAGE_SCN_CNT_CODE 0x00000020 +#define IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040 +#define IMAGE_SCN_CNT_UNINITIALIZED_DATA 0x00000080 +#define IMAGE_SCN_LNK_OTHER 0x00000100 +#define IMAGE_SCN_LNK_INFO 0x00000200 +#define IMAGE_SCN_LNK_REMOVE 0x00000800 +#define IMAGE_SCN_LNK_COMDAT 0x00001000 +#define IMAGE_SCN_NO_DEFER_SPEC_EXC 0x00004000 +#define IMAGE_SCN_GPREL 0x00008000 +#define IMAGE_SCN_MEM_FARDATA 0x00008000 +#define IMAGE_SCN_MEM_PURGEABLE 0x00020000 +#define IMAGE_SCN_MEM_16BIT 0x00020000 +#define IMAGE_SCN_MEM_LOCKED 0x00040000 +#define IMAGE_SCN_MEM_PRELOAD 0x00080000 + +#define IMAGE_SCN_ALIGN_1BYTES 0x00100000 +#define IMAGE_SCN_ALIGN_2BYTES 0x00200000 +#define IMAGE_SCN_ALIGN_4BYTES 0x00300000 +#define IMAGE_SCN_ALIGN_8BYTES 0x00400000 +#define IMAGE_SCN_ALIGN_16BYTES 0x00500000 +#define IMAGE_SCN_ALIGN_32BYTES 0x00600000 +#define IMAGE_SCN_ALIGN_64BYTES 0x00700000 +#define IMAGE_SCN_ALIGN_128BYTES 0x00800000 +#define IMAGE_SCN_ALIGN_256BYTES 0x00900000 +#define IMAGE_SCN_ALIGN_512BYTES 0x00A00000 +#define IMAGE_SCN_ALIGN_1024BYTES 0x00B00000 +#define IMAGE_SCN_ALIGN_2048BYTES 0x00C00000 +#define IMAGE_SCN_ALIGN_4096BYTES 0x00D00000 +#define IMAGE_SCN_ALIGN_8192BYTES 0x00E00000 + +#define IMAGE_SCN_ALIGN_MASK 0x00F00000 + +#define IMAGE_SCN_LNK_NRELOC_OVFL 0x01000000 +#define IMAGE_SCN_MEM_DISCARDABLE 0x02000000 +#define IMAGE_SCN_MEM_NOT_CACHED 0x04000000 +#define IMAGE_SCN_MEM_NOT_PAGED 0x08000000 +#define IMAGE_SCN_MEM_SHARED 0x10000000 +#define IMAGE_SCN_MEM_EXECUTE 0x20000000 +#define IMAGE_SCN_MEM_READ 0x40000000 +#define IMAGE_SCN_MEM_WRITE 0x80000000 + +#define IMAGE_SCN_SCALE_INDEX 0x00000001 + +#include "pshpack2.h" + + typedef struct _IMAGE_SYMBOL { + union { + BYTE ShortName[8]; + struct { + DWORD Short; + DWORD Long; + } Name; + DWORD LongName[2]; + } N; + DWORD Value; + SHORT SectionNumber; + WORD Type; + BYTE StorageClass; + BYTE NumberOfAuxSymbols; + } IMAGE_SYMBOL; + typedef IMAGE_SYMBOL UNALIGNED *PIMAGE_SYMBOL; + +#define IMAGE_SIZEOF_SYMBOL 18 + +#define IMAGE_SYM_UNDEFINED (SHORT)0 +#define IMAGE_SYM_ABSOLUTE (SHORT)-1 +#define IMAGE_SYM_DEBUG (SHORT)-2 +#define IMAGE_SYM_SECTION_MAX 0xFEFF + +#define IMAGE_SYM_TYPE_NULL 0x0000 +#define IMAGE_SYM_TYPE_VOID 0x0001 +#define IMAGE_SYM_TYPE_CHAR 0x0002 +#define IMAGE_SYM_TYPE_SHORT 0x0003 +#define IMAGE_SYM_TYPE_INT 0x0004 +#define IMAGE_SYM_TYPE_LONG 0x0005 +#define IMAGE_SYM_TYPE_FLOAT 0x0006 +#define IMAGE_SYM_TYPE_DOUBLE 0x0007 +#define IMAGE_SYM_TYPE_STRUCT 0x0008 +#define IMAGE_SYM_TYPE_UNION 0x0009 +#define IMAGE_SYM_TYPE_ENUM 0x000A +#define IMAGE_SYM_TYPE_MOE 0x000B +#define IMAGE_SYM_TYPE_BYTE 0x000C +#define IMAGE_SYM_TYPE_WORD 0x000D +#define IMAGE_SYM_TYPE_UINT 0x000E +#define IMAGE_SYM_TYPE_DWORD 0x000F +#define IMAGE_SYM_TYPE_PCODE 0x8000 + +#define IMAGE_SYM_DTYPE_NULL 0 +#define IMAGE_SYM_DTYPE_POINTER 1 +#define IMAGE_SYM_DTYPE_FUNCTION 2 +#define IMAGE_SYM_DTYPE_ARRAY 3 + +#define IMAGE_SYM_CLASS_END_OF_FUNCTION (BYTE)-1 +#define IMAGE_SYM_CLASS_NULL 0x0000 +#define IMAGE_SYM_CLASS_AUTOMATIC 0x0001 +#define IMAGE_SYM_CLASS_EXTERNAL 0x0002 +#define IMAGE_SYM_CLASS_STATIC 0x0003 +#define IMAGE_SYM_CLASS_REGISTER 0x0004 +#define IMAGE_SYM_CLASS_EXTERNAL_DEF 0x0005 +#define IMAGE_SYM_CLASS_LABEL 0x0006 +#define IMAGE_SYM_CLASS_UNDEFINED_LABEL 0x0007 +#define IMAGE_SYM_CLASS_MEMBER_OF_STRUCT 0x0008 +#define IMAGE_SYM_CLASS_ARGUMENT 0x0009 +#define IMAGE_SYM_CLASS_STRUCT_TAG 0x000A +#define IMAGE_SYM_CLASS_MEMBER_OF_UNION 0x000B +#define IMAGE_SYM_CLASS_UNION_TAG 0x000C +#define IMAGE_SYM_CLASS_TYPE_DEFINITION 0x000D +#define IMAGE_SYM_CLASS_UNDEFINED_STATIC 0x000E +#define IMAGE_SYM_CLASS_ENUM_TAG 0x000F +#define IMAGE_SYM_CLASS_MEMBER_OF_ENUM 0x0010 +#define IMAGE_SYM_CLASS_REGISTER_PARAM 0x0011 +#define IMAGE_SYM_CLASS_BIT_FIELD 0x0012 +#define IMAGE_SYM_CLASS_FAR_EXTERNAL 0x0044 +#define IMAGE_SYM_CLASS_BLOCK 0x0064 +#define IMAGE_SYM_CLASS_FUNCTION 0x0065 +#define IMAGE_SYM_CLASS_END_OF_STRUCT 0x0066 +#define IMAGE_SYM_CLASS_FILE 0x0067 +#define IMAGE_SYM_CLASS_SECTION 0x0068 +#define IMAGE_SYM_CLASS_WEAK_EXTERNAL 0x0069 +#define IMAGE_SYM_CLASS_CLR_TOKEN 0x006B + +#define N_BTMASK 0x000F +#define N_TMASK 0x0030 +#define N_TMASK1 0x00C0 +#define N_TMASK2 0x00F0 +#define N_BTSHFT 4 +#define N_TSHIFT 2 + +#define BTYPE(x) ((x) & N_BTMASK) + +#ifndef ISPTR +#define ISPTR(x) (((x) & N_TMASK)==(IMAGE_SYM_DTYPE_POINTER << N_BTSHFT)) +#endif + +#ifndef ISFCN +#define ISFCN(x) (((x) & N_TMASK)==(IMAGE_SYM_DTYPE_FUNCTION << N_BTSHFT)) +#endif + +#ifndef ISARY +#define ISARY(x) (((x) & N_TMASK)==(IMAGE_SYM_DTYPE_ARRAY << N_BTSHFT)) +#endif + +#ifndef ISTAG +#define ISTAG(x) ((x)==IMAGE_SYM_CLASS_STRUCT_TAG || (x)==IMAGE_SYM_CLASS_UNION_TAG || (x)==IMAGE_SYM_CLASS_ENUM_TAG) +#endif + +#ifndef INCREF +#define INCREF(x) ((((x)&~N_BTMASK)<>N_TSHIFT)&~N_BTMASK)|((x)&N_BTMASK)) +#endif + + typedef union _IMAGE_AUX_SYMBOL { + struct { + DWORD TagIndex; + union { + struct { + WORD Linenumber; + WORD Size; + } LnSz; + DWORD TotalSize; + } Misc; + union { + struct { + DWORD PointerToLinenumber; + DWORD PointerToNextFunction; + } Function; + struct { + WORD Dimension[4]; + } Array; + } FcnAry; + WORD TvIndex; + } Sym; + struct { + BYTE Name[IMAGE_SIZEOF_SYMBOL]; + } File; + struct { + DWORD Length; + WORD NumberOfRelocations; + WORD NumberOfLinenumbers; + DWORD CheckSum; + SHORT Number; + BYTE Selection; + } Section; + } IMAGE_AUX_SYMBOL; + typedef IMAGE_AUX_SYMBOL UNALIGNED *PIMAGE_AUX_SYMBOL; + +#define IMAGE_SIZEOF_AUX_SYMBOL 18 + + typedef enum IMAGE_AUX_SYMBOL_TYPE { + IMAGE_AUX_SYMBOL_TYPE_TOKEN_DEF = 1 + } IMAGE_AUX_SYMBOL_TYPE; + +#include + + typedef struct IMAGE_AUX_SYMBOL_TOKEN_DEF { + BYTE bAuxType; + BYTE bReserved; + DWORD SymbolTableIndex; + BYTE rgbReserved[12]; + } IMAGE_AUX_SYMBOL_TOKEN_DEF; + + typedef IMAGE_AUX_SYMBOL_TOKEN_DEF UNALIGNED *PIMAGE_AUX_SYMBOL_TOKEN_DEF; + +#include + +#define IMAGE_COMDAT_SELECT_NODUPLICATES 1 +#define IMAGE_COMDAT_SELECT_ANY 2 +#define IMAGE_COMDAT_SELECT_SAME_SIZE 3 +#define IMAGE_COMDAT_SELECT_EXACT_MATCH 4 +#define IMAGE_COMDAT_SELECT_ASSOCIATIVE 5 +#define IMAGE_COMDAT_SELECT_LARGEST 6 +#define IMAGE_COMDAT_SELECT_NEWEST 7 + +#define IMAGE_WEAK_EXTERN_SEARCH_NOLIBRARY 1 +#define IMAGE_WEAK_EXTERN_SEARCH_LIBRARY 2 +#define IMAGE_WEAK_EXTERN_SEARCH_ALIAS 3 + + typedef struct _IMAGE_RELOCATION { + union { + DWORD VirtualAddress; + DWORD RelocCount; + }; + DWORD SymbolTableIndex; + WORD Type; + } IMAGE_RELOCATION; + typedef IMAGE_RELOCATION UNALIGNED *PIMAGE_RELOCATION; + +#define IMAGE_SIZEOF_RELOCATION 10 + +#define IMAGE_REL_I386_ABSOLUTE 0x0000 +#define IMAGE_REL_I386_DIR16 0x0001 +#define IMAGE_REL_I386_REL16 0x0002 +#define IMAGE_REL_I386_DIR32 0x0006 +#define IMAGE_REL_I386_DIR32NB 0x0007 +#define IMAGE_REL_I386_SEG12 0x0009 +#define IMAGE_REL_I386_SECTION 0x000A +#define IMAGE_REL_I386_SECREL 0x000B +#define IMAGE_REL_I386_TOKEN 0x000C +#define IMAGE_REL_I386_SECREL7 0x000D +#define IMAGE_REL_I386_REL32 0x0014 + +#define IMAGE_REL_MIPS_ABSOLUTE 0x0000 +#define IMAGE_REL_MIPS_REFHALF 0x0001 +#define IMAGE_REL_MIPS_REFWORD 0x0002 +#define IMAGE_REL_MIPS_JMPADDR 0x0003 +#define IMAGE_REL_MIPS_REFHI 0x0004 +#define IMAGE_REL_MIPS_REFLO 0x0005 +#define IMAGE_REL_MIPS_GPREL 0x0006 +#define IMAGE_REL_MIPS_LITERAL 0x0007 +#define IMAGE_REL_MIPS_SECTION 0x000A +#define IMAGE_REL_MIPS_SECREL 0x000B +#define IMAGE_REL_MIPS_SECRELLO 0x000C +#define IMAGE_REL_MIPS_SECRELHI 0x000D +#define IMAGE_REL_MIPS_TOKEN 0x000E +#define IMAGE_REL_MIPS_JMPADDR16 0x0010 +#define IMAGE_REL_MIPS_REFWORDNB 0x0022 +#define IMAGE_REL_MIPS_PAIR 0x0025 + +#define IMAGE_REL_ALPHA_ABSOLUTE 0x0000 +#define IMAGE_REL_ALPHA_REFLONG 0x0001 +#define IMAGE_REL_ALPHA_REFQUAD 0x0002 +#define IMAGE_REL_ALPHA_GPREL32 0x0003 +#define IMAGE_REL_ALPHA_LITERAL 0x0004 +#define IMAGE_REL_ALPHA_LITUSE 0x0005 +#define IMAGE_REL_ALPHA_GPDISP 0x0006 +#define IMAGE_REL_ALPHA_BRADDR 0x0007 +#define IMAGE_REL_ALPHA_HINT 0x0008 +#define IMAGE_REL_ALPHA_INLINE_REFLONG 0x0009 +#define IMAGE_REL_ALPHA_REFHI 0x000A +#define IMAGE_REL_ALPHA_REFLO 0x000B +#define IMAGE_REL_ALPHA_PAIR 0x000C +#define IMAGE_REL_ALPHA_MATCH 0x000D +#define IMAGE_REL_ALPHA_SECTION 0x000E +#define IMAGE_REL_ALPHA_SECREL 0x000F +#define IMAGE_REL_ALPHA_REFLONGNB 0x0010 +#define IMAGE_REL_ALPHA_SECRELLO 0x0011 +#define IMAGE_REL_ALPHA_SECRELHI 0x0012 +#define IMAGE_REL_ALPHA_REFQ3 0x0013 +#define IMAGE_REL_ALPHA_REFQ2 0x0014 +#define IMAGE_REL_ALPHA_REFQ1 0x0015 +#define IMAGE_REL_ALPHA_GPRELLO 0x0016 +#define IMAGE_REL_ALPHA_GPRELHI 0x0017 + +#define IMAGE_REL_PPC_ABSOLUTE 0x0000 +#define IMAGE_REL_PPC_ADDR64 0x0001 +#define IMAGE_REL_PPC_ADDR32 0x0002 +#define IMAGE_REL_PPC_ADDR24 0x0003 +#define IMAGE_REL_PPC_ADDR16 0x0004 +#define IMAGE_REL_PPC_ADDR14 0x0005 +#define IMAGE_REL_PPC_REL24 0x0006 +#define IMAGE_REL_PPC_REL14 0x0007 +#define IMAGE_REL_PPC_TOCREL16 0x0008 +#define IMAGE_REL_PPC_TOCREL14 0x0009 +#define IMAGE_REL_PPC_ADDR32NB 0x000A +#define IMAGE_REL_PPC_SECREL 0x000B +#define IMAGE_REL_PPC_SECTION 0x000C +#define IMAGE_REL_PPC_IFGLUE 0x000D +#define IMAGE_REL_PPC_IMGLUE 0x000E +#define IMAGE_REL_PPC_SECREL16 0x000F +#define IMAGE_REL_PPC_REFHI 0x0010 +#define IMAGE_REL_PPC_REFLO 0x0011 +#define IMAGE_REL_PPC_PAIR 0x0012 +#define IMAGE_REL_PPC_SECRELLO 0x0013 +#define IMAGE_REL_PPC_SECRELHI 0x0014 +#define IMAGE_REL_PPC_GPREL 0x0015 +#define IMAGE_REL_PPC_TOKEN 0x0016 +#define IMAGE_REL_PPC_TYPEMASK 0x00FF +#define IMAGE_REL_PPC_NEG 0x0100 +#define IMAGE_REL_PPC_BRTAKEN 0x0200 +#define IMAGE_REL_PPC_BRNTAKEN 0x0400 +#define IMAGE_REL_PPC_TOCDEFN 0x0800 + +#define IMAGE_REL_SH3_ABSOLUTE 0x0000 +#define IMAGE_REL_SH3_DIRECT16 0x0001 +#define IMAGE_REL_SH3_DIRECT32 0x0002 +#define IMAGE_REL_SH3_DIRECT8 0x0003 +#define IMAGE_REL_SH3_DIRECT8_WORD 0x0004 +#define IMAGE_REL_SH3_DIRECT8_LONG 0x0005 +#define IMAGE_REL_SH3_DIRECT4 0x0006 +#define IMAGE_REL_SH3_DIRECT4_WORD 0x0007 +#define IMAGE_REL_SH3_DIRECT4_LONG 0x0008 +#define IMAGE_REL_SH3_PCREL8_WORD 0x0009 +#define IMAGE_REL_SH3_PCREL8_LONG 0x000A +#define IMAGE_REL_SH3_PCREL12_WORD 0x000B +#define IMAGE_REL_SH3_STARTOF_SECTION 0x000C +#define IMAGE_REL_SH3_SIZEOF_SECTION 0x000D +#define IMAGE_REL_SH3_SECTION 0x000E +#define IMAGE_REL_SH3_SECREL 0x000F +#define IMAGE_REL_SH3_DIRECT32_NB 0x0010 +#define IMAGE_REL_SH3_GPREL4_LONG 0x0011 +#define IMAGE_REL_SH3_TOKEN 0x0012 + +#define IMAGE_REL_SHM_PCRELPT 0x0013 +#define IMAGE_REL_SHM_REFLO 0x0014 +#define IMAGE_REL_SHM_REFHALF 0x0015 +#define IMAGE_REL_SHM_RELLO 0x0016 +#define IMAGE_REL_SHM_RELHALF 0x0017 +#define IMAGE_REL_SHM_PAIR 0x0018 + +#define IMAGE_REL_SH_NOMODE 0x8000 + +#define IMAGE_REL_ARM_ABSOLUTE 0x0000 +#define IMAGE_REL_ARM_ADDR32 0x0001 +#define IMAGE_REL_ARM_ADDR32NB 0x0002 +#define IMAGE_REL_ARM_BRANCH24 0x0003 +#define IMAGE_REL_ARM_BRANCH11 0x0004 +#define IMAGE_REL_ARM_TOKEN 0x0005 +#define IMAGE_REL_ARM_GPREL12 0x0006 +#define IMAGE_REL_ARM_GPREL7 0x0007 +#define IMAGE_REL_ARM_BLX24 0x0008 +#define IMAGE_REL_ARM_BLX11 0x0009 +#define IMAGE_REL_ARM_SECTION 0x000E +#define IMAGE_REL_ARM_SECREL 0x000F + +#define IMAGE_REL_AM_ABSOLUTE 0x0000 +#define IMAGE_REL_AM_ADDR32 0x0001 +#define IMAGE_REL_AM_ADDR32NB 0x0002 +#define IMAGE_REL_AM_CALL32 0x0003 +#define IMAGE_REL_AM_FUNCINFO 0x0004 +#define IMAGE_REL_AM_REL32_1 0x0005 +#define IMAGE_REL_AM_REL32_2 0x0006 +#define IMAGE_REL_AM_SECREL 0x0007 +#define IMAGE_REL_AM_SECTION 0x0008 +#define IMAGE_REL_AM_TOKEN 0x0009 + +#define IMAGE_REL_AMD64_ABSOLUTE 0x0000 +#define IMAGE_REL_AMD64_ADDR64 0x0001 +#define IMAGE_REL_AMD64_ADDR32 0x0002 +#define IMAGE_REL_AMD64_ADDR32NB 0x0003 +#define IMAGE_REL_AMD64_REL32 0x0004 +#define IMAGE_REL_AMD64_REL32_1 0x0005 +#define IMAGE_REL_AMD64_REL32_2 0x0006 +#define IMAGE_REL_AMD64_REL32_3 0x0007 +#define IMAGE_REL_AMD64_REL32_4 0x0008 +#define IMAGE_REL_AMD64_REL32_5 0x0009 +#define IMAGE_REL_AMD64_SECTION 0x000A +#define IMAGE_REL_AMD64_SECREL 0x000B +#define IMAGE_REL_AMD64_SECREL7 0x000C +#define IMAGE_REL_AMD64_TOKEN 0x000D +#define IMAGE_REL_AMD64_SREL32 0x000E +#define IMAGE_REL_AMD64_PAIR 0x000F +#define IMAGE_REL_AMD64_SSPAN32 0x0010 + +#define IMAGE_REL_IA64_ABSOLUTE 0x0000 +#define IMAGE_REL_IA64_IMM14 0x0001 +#define IMAGE_REL_IA64_IMM22 0x0002 +#define IMAGE_REL_IA64_IMM64 0x0003 +#define IMAGE_REL_IA64_DIR32 0x0004 +#define IMAGE_REL_IA64_DIR64 0x0005 +#define IMAGE_REL_IA64_PCREL21B 0x0006 +#define IMAGE_REL_IA64_PCREL21M 0x0007 +#define IMAGE_REL_IA64_PCREL21F 0x0008 +#define IMAGE_REL_IA64_GPREL22 0x0009 +#define IMAGE_REL_IA64_LTOFF22 0x000A +#define IMAGE_REL_IA64_SECTION 0x000B +#define IMAGE_REL_IA64_SECREL22 0x000C +#define IMAGE_REL_IA64_SECREL64I 0x000D +#define IMAGE_REL_IA64_SECREL32 0x000E + +#define IMAGE_REL_IA64_DIR32NB 0x0010 +#define IMAGE_REL_IA64_SREL14 0x0011 +#define IMAGE_REL_IA64_SREL22 0x0012 +#define IMAGE_REL_IA64_SREL32 0x0013 +#define IMAGE_REL_IA64_UREL32 0x0014 +#define IMAGE_REL_IA64_PCREL60X 0x0015 +#define IMAGE_REL_IA64_PCREL60B 0x0016 +#define IMAGE_REL_IA64_PCREL60F 0x0017 +#define IMAGE_REL_IA64_PCREL60I 0x0018 +#define IMAGE_REL_IA64_PCREL60M 0x0019 +#define IMAGE_REL_IA64_IMMGPREL64 0x001A +#define IMAGE_REL_IA64_TOKEN 0x001B +#define IMAGE_REL_IA64_GPREL32 0x001C +#define IMAGE_REL_IA64_ADDEND 0x001F + +#define IMAGE_REL_CEF_ABSOLUTE 0x0000 +#define IMAGE_REL_CEF_ADDR32 0x0001 +#define IMAGE_REL_CEF_ADDR64 0x0002 +#define IMAGE_REL_CEF_ADDR32NB 0x0003 +#define IMAGE_REL_CEF_SECTION 0x0004 +#define IMAGE_REL_CEF_SECREL 0x0005 +#define IMAGE_REL_CEF_TOKEN 0x0006 + +#define IMAGE_REL_CEE_ABSOLUTE 0x0000 +#define IMAGE_REL_CEE_ADDR32 0x0001 +#define IMAGE_REL_CEE_ADDR64 0x0002 +#define IMAGE_REL_CEE_ADDR32NB 0x0003 +#define IMAGE_REL_CEE_SECTION 0x0004 +#define IMAGE_REL_CEE_SECREL 0x0005 +#define IMAGE_REL_CEE_TOKEN 0x0006 + +#define IMAGE_REL_M32R_ABSOLUTE 0x0000 +#define IMAGE_REL_M32R_ADDR32 0x0001 +#define IMAGE_REL_M32R_ADDR32NB 0x0002 +#define IMAGE_REL_M32R_ADDR24 0x0003 +#define IMAGE_REL_M32R_GPREL16 0x0004 +#define IMAGE_REL_M32R_PCREL24 0x0005 +#define IMAGE_REL_M32R_PCREL16 0x0006 +#define IMAGE_REL_M32R_PCREL8 0x0007 +#define IMAGE_REL_M32R_REFHALF 0x0008 +#define IMAGE_REL_M32R_REFHI 0x0009 +#define IMAGE_REL_M32R_REFLO 0x000A +#define IMAGE_REL_M32R_PAIR 0x000B +#define IMAGE_REL_M32R_SECTION 0x000C +#define IMAGE_REL_M32R_SECREL32 0x000D +#define IMAGE_REL_M32R_TOKEN 0x000E + +#define EXT_IMM64(Value,Address,Size,InstPos,ValPos) Value |= (((ULONGLONG)((*(Address) >> InstPos) & (((ULONGLONG)1 << Size) - 1))) << ValPos) +#define INS_IMM64(Value,Address,Size,InstPos,ValPos) *(PDWORD)Address = (*(PDWORD)Address & ~(((1 << Size) - 1) << InstPos)) | ((DWORD)((((ULONGLONG)Value >> ValPos) & (((ULONGLONG)1 << Size) - 1))) << InstPos) + +#define EMARCH_ENC_I17_IMM7B_INST_WORD_X 3 +#define EMARCH_ENC_I17_IMM7B_SIZE_X 7 +#define EMARCH_ENC_I17_IMM7B_INST_WORD_POS_X 4 +#define EMARCH_ENC_I17_IMM7B_VAL_POS_X 0 + +#define EMARCH_ENC_I17_IMM9D_INST_WORD_X 3 +#define EMARCH_ENC_I17_IMM9D_SIZE_X 9 +#define EMARCH_ENC_I17_IMM9D_INST_WORD_POS_X 18 +#define EMARCH_ENC_I17_IMM9D_VAL_POS_X 7 + +#define EMARCH_ENC_I17_IMM5C_INST_WORD_X 3 +#define EMARCH_ENC_I17_IMM5C_SIZE_X 5 +#define EMARCH_ENC_I17_IMM5C_INST_WORD_POS_X 13 +#define EMARCH_ENC_I17_IMM5C_VAL_POS_X 16 + +#define EMARCH_ENC_I17_IC_INST_WORD_X 3 +#define EMARCH_ENC_I17_IC_SIZE_X 1 +#define EMARCH_ENC_I17_IC_INST_WORD_POS_X 12 +#define EMARCH_ENC_I17_IC_VAL_POS_X 21 + +#define EMARCH_ENC_I17_IMM41a_INST_WORD_X 1 +#define EMARCH_ENC_I17_IMM41a_SIZE_X 10 +#define EMARCH_ENC_I17_IMM41a_INST_WORD_POS_X 14 +#define EMARCH_ENC_I17_IMM41a_VAL_POS_X 22 + +#define EMARCH_ENC_I17_IMM41b_INST_WORD_X 1 +#define EMARCH_ENC_I17_IMM41b_SIZE_X 8 +#define EMARCH_ENC_I17_IMM41b_INST_WORD_POS_X 24 +#define EMARCH_ENC_I17_IMM41b_VAL_POS_X 32 + +#define EMARCH_ENC_I17_IMM41c_INST_WORD_X 2 +#define EMARCH_ENC_I17_IMM41c_SIZE_X 23 +#define EMARCH_ENC_I17_IMM41c_INST_WORD_POS_X 0 +#define EMARCH_ENC_I17_IMM41c_VAL_POS_X 40 + +#define EMARCH_ENC_I17_SIGN_INST_WORD_X 3 +#define EMARCH_ENC_I17_SIGN_SIZE_X 1 +#define EMARCH_ENC_I17_SIGN_INST_WORD_POS_X 27 +#define EMARCH_ENC_I17_SIGN_VAL_POS_X 63 + +#define X3_OPCODE_INST_WORD_X 3 +#define X3_OPCODE_SIZE_X 4 +#define X3_OPCODE_INST_WORD_POS_X 28 +#define X3_OPCODE_SIGN_VAL_POS_X 0 + +#define X3_I_INST_WORD_X 3 +#define X3_I_SIZE_X 1 +#define X3_I_INST_WORD_POS_X 27 +#define X3_I_SIGN_VAL_POS_X 59 + +#define X3_D_WH_INST_WORD_X 3 +#define X3_D_WH_SIZE_X 3 +#define X3_D_WH_INST_WORD_POS_X 24 +#define X3_D_WH_SIGN_VAL_POS_X 0 + +#define X3_IMM20_INST_WORD_X 3 +#define X3_IMM20_SIZE_X 20 +#define X3_IMM20_INST_WORD_POS_X 4 +#define X3_IMM20_SIGN_VAL_POS_X 0 + +#define X3_IMM39_1_INST_WORD_X 2 +#define X3_IMM39_1_SIZE_X 23 +#define X3_IMM39_1_INST_WORD_POS_X 0 +#define X3_IMM39_1_SIGN_VAL_POS_X 36 + +#define X3_IMM39_2_INST_WORD_X 1 +#define X3_IMM39_2_SIZE_X 16 +#define X3_IMM39_2_INST_WORD_POS_X 16 +#define X3_IMM39_2_SIGN_VAL_POS_X 20 + +#define X3_P_INST_WORD_X 3 +#define X3_P_SIZE_X 4 +#define X3_P_INST_WORD_POS_X 0 +#define X3_P_SIGN_VAL_POS_X 0 + +#define X3_TMPLT_INST_WORD_X 0 +#define X3_TMPLT_SIZE_X 4 +#define X3_TMPLT_INST_WORD_POS_X 0 +#define X3_TMPLT_SIGN_VAL_POS_X 0 + +#define X3_BTYPE_QP_INST_WORD_X 2 +#define X3_BTYPE_QP_SIZE_X 9 +#define X3_BTYPE_QP_INST_WORD_POS_X 23 +#define X3_BTYPE_QP_INST_VAL_POS_X 0 + +#define X3_EMPTY_INST_WORD_X 1 +#define X3_EMPTY_SIZE_X 2 +#define X3_EMPTY_INST_WORD_POS_X 14 +#define X3_EMPTY_INST_VAL_POS_X 0 + + typedef struct _IMAGE_LINENUMBER { + union { + DWORD SymbolTableIndex; + DWORD VirtualAddress; + } Type; + WORD Linenumber; + } IMAGE_LINENUMBER; + typedef IMAGE_LINENUMBER UNALIGNED *PIMAGE_LINENUMBER; + +#define IMAGE_SIZEOF_LINENUMBER 6 + +#include "poppack.h" + + typedef struct _IMAGE_BASE_RELOCATION { + DWORD VirtualAddress; + DWORD SizeOfBlock; + + } IMAGE_BASE_RELOCATION; + typedef IMAGE_BASE_RELOCATION UNALIGNED *PIMAGE_BASE_RELOCATION; + +#define IMAGE_SIZEOF_BASE_RELOCATION 8 + +#define IMAGE_REL_BASED_ABSOLUTE 0 +#define IMAGE_REL_BASED_HIGH 1 +#define IMAGE_REL_BASED_LOW 2 +#define IMAGE_REL_BASED_HIGHLOW 3 +#define IMAGE_REL_BASED_HIGHADJ 4 +#define IMAGE_REL_BASED_MIPS_JMPADDR 5 +#define IMAGE_REL_BASED_MIPS_JMPADDR16 9 +#define IMAGE_REL_BASED_IA64_IMM64 9 +#define IMAGE_REL_BASED_DIR64 10 + +#define IMAGE_ARCHIVE_START_SIZE 8 +#define IMAGE_ARCHIVE_START "!\n" +#define IMAGE_ARCHIVE_END "`\n" +#define IMAGE_ARCHIVE_PAD "\n" +#define IMAGE_ARCHIVE_LINKER_MEMBER "/ " +#define IMAGE_ARCHIVE_LONGNAMES_MEMBER "// " + + typedef struct _IMAGE_ARCHIVE_MEMBER_HEADER { + BYTE Name[16]; + BYTE Date[12]; + BYTE UserID[6]; + BYTE GroupID[6]; + BYTE Mode[8]; + BYTE Size[10]; + BYTE EndHeader[2]; + } IMAGE_ARCHIVE_MEMBER_HEADER,*PIMAGE_ARCHIVE_MEMBER_HEADER; + +#define IMAGE_SIZEOF_ARCHIVE_MEMBER_HDR 60 + + typedef struct _IMAGE_EXPORT_DIRECTORY { + DWORD Characteristics; + DWORD TimeDateStamp; + WORD MajorVersion; + WORD MinorVersion; + DWORD Name; + DWORD Base; + DWORD NumberOfFunctions; + DWORD NumberOfNames; + DWORD AddressOfFunctions; + DWORD AddressOfNames; + DWORD AddressOfNameOrdinals; + } IMAGE_EXPORT_DIRECTORY,*PIMAGE_EXPORT_DIRECTORY; + + typedef struct _IMAGE_IMPORT_BY_NAME { + WORD Hint; + BYTE Name[1]; + } IMAGE_IMPORT_BY_NAME,*PIMAGE_IMPORT_BY_NAME; + +#include "pshpack8.h" + + typedef struct _IMAGE_THUNK_DATA64 { + union { + ULONGLONG ForwarderString; + ULONGLONG Function; + ULONGLONG Ordinal; + ULONGLONG AddressOfData; + } u1; + } IMAGE_THUNK_DATA64; + typedef IMAGE_THUNK_DATA64 *PIMAGE_THUNK_DATA64; + +#include "poppack.h" + + typedef struct _IMAGE_THUNK_DATA32 { + union { + DWORD ForwarderString; + DWORD Function; + DWORD Ordinal; + DWORD AddressOfData; + } u1; + } IMAGE_THUNK_DATA32; + typedef IMAGE_THUNK_DATA32 *PIMAGE_THUNK_DATA32; + +#define IMAGE_ORDINAL_FLAG64 0x8000000000000000ull +#define IMAGE_ORDINAL_FLAG32 0x80000000 +#define IMAGE_ORDINAL64(Ordinal) (Ordinal & 0xffffull) +#define IMAGE_ORDINAL32(Ordinal) (Ordinal & 0xffff) +#define IMAGE_SNAP_BY_ORDINAL64(Ordinal) ((Ordinal & IMAGE_ORDINAL_FLAG64)!=0) +#define IMAGE_SNAP_BY_ORDINAL32(Ordinal) ((Ordinal & IMAGE_ORDINAL_FLAG32)!=0) + + typedef VOID + (NTAPI *PIMAGE_TLS_CALLBACK)(PVOID DllHandle,DWORD Reason,PVOID Reserved); + + typedef struct _IMAGE_TLS_DIRECTORY64 { + ULONGLONG StartAddressOfRawData; + ULONGLONG EndAddressOfRawData; + ULONGLONG AddressOfIndex; + ULONGLONG AddressOfCallBacks; + DWORD SizeOfZeroFill; + DWORD Characteristics; + } IMAGE_TLS_DIRECTORY64; + typedef IMAGE_TLS_DIRECTORY64 *PIMAGE_TLS_DIRECTORY64; + + typedef struct _IMAGE_TLS_DIRECTORY32 { + DWORD StartAddressOfRawData; + DWORD EndAddressOfRawData; + DWORD AddressOfIndex; + DWORD AddressOfCallBacks; + DWORD SizeOfZeroFill; + DWORD Characteristics; + } IMAGE_TLS_DIRECTORY32; + typedef IMAGE_TLS_DIRECTORY32 *PIMAGE_TLS_DIRECTORY32; + +#ifdef _WIN64 +#define IMAGE_ORDINAL_FLAG IMAGE_ORDINAL_FLAG64 +#define IMAGE_ORDINAL(Ordinal) IMAGE_ORDINAL64(Ordinal) + typedef IMAGE_THUNK_DATA64 IMAGE_THUNK_DATA; + typedef PIMAGE_THUNK_DATA64 PIMAGE_THUNK_DATA; +#define IMAGE_SNAP_BY_ORDINAL(Ordinal) IMAGE_SNAP_BY_ORDINAL64(Ordinal) + typedef IMAGE_TLS_DIRECTORY64 IMAGE_TLS_DIRECTORY; + typedef PIMAGE_TLS_DIRECTORY64 PIMAGE_TLS_DIRECTORY; +#else +#define IMAGE_ORDINAL_FLAG IMAGE_ORDINAL_FLAG32 +#define IMAGE_ORDINAL(Ordinal) IMAGE_ORDINAL32(Ordinal) + typedef IMAGE_THUNK_DATA32 IMAGE_THUNK_DATA; + typedef PIMAGE_THUNK_DATA32 PIMAGE_THUNK_DATA; +#define IMAGE_SNAP_BY_ORDINAL(Ordinal) IMAGE_SNAP_BY_ORDINAL32(Ordinal) + typedef IMAGE_TLS_DIRECTORY32 IMAGE_TLS_DIRECTORY; + typedef PIMAGE_TLS_DIRECTORY32 PIMAGE_TLS_DIRECTORY; +#endif + + typedef struct _IMAGE_IMPORT_DESCRIPTOR { + union { + DWORD Characteristics; + DWORD OriginalFirstThunk; + }; + DWORD TimeDateStamp; + + DWORD ForwarderChain; + DWORD Name; + DWORD FirstThunk; + } IMAGE_IMPORT_DESCRIPTOR; + typedef IMAGE_IMPORT_DESCRIPTOR UNALIGNED *PIMAGE_IMPORT_DESCRIPTOR; + + typedef struct _IMAGE_BOUND_IMPORT_DESCRIPTOR { + DWORD TimeDateStamp; + WORD OffsetModuleName; + WORD NumberOfModuleForwarderRefs; + } IMAGE_BOUND_IMPORT_DESCRIPTOR,*PIMAGE_BOUND_IMPORT_DESCRIPTOR; + + typedef struct _IMAGE_BOUND_FORWARDER_REF { + DWORD TimeDateStamp; + WORD OffsetModuleName; + WORD Reserved; + } IMAGE_BOUND_FORWARDER_REF,*PIMAGE_BOUND_FORWARDER_REF; + + typedef struct _IMAGE_RESOURCE_DIRECTORY { + DWORD Characteristics; + DWORD TimeDateStamp; + WORD MajorVersion; + WORD MinorVersion; + WORD NumberOfNamedEntries; + WORD NumberOfIdEntries; + } IMAGE_RESOURCE_DIRECTORY,*PIMAGE_RESOURCE_DIRECTORY; + +#define IMAGE_RESOURCE_NAME_IS_STRING 0x80000000 +#define IMAGE_RESOURCE_DATA_IS_DIRECTORY 0x80000000 + + typedef struct _IMAGE_RESOURCE_DIRECTORY_ENTRY { + union { + struct { + DWORD NameOffset:31; + DWORD NameIsString:1; + }; + DWORD Name; + WORD Id; + }; + union { + DWORD OffsetToData; + struct { + DWORD OffsetToDirectory:31; + DWORD DataIsDirectory:1; + }; + }; + } IMAGE_RESOURCE_DIRECTORY_ENTRY,*PIMAGE_RESOURCE_DIRECTORY_ENTRY; + + typedef struct _IMAGE_RESOURCE_DIRECTORY_STRING { + WORD Length; + CHAR NameString[1]; + } IMAGE_RESOURCE_DIRECTORY_STRING,*PIMAGE_RESOURCE_DIRECTORY_STRING; + + typedef struct _IMAGE_RESOURCE_DIR_STRING_U { + WORD Length; + WCHAR NameString[1]; + } IMAGE_RESOURCE_DIR_STRING_U,*PIMAGE_RESOURCE_DIR_STRING_U; + + typedef struct _IMAGE_RESOURCE_DATA_ENTRY { + DWORD OffsetToData; + DWORD Size; + DWORD CodePage; + DWORD Reserved; + } IMAGE_RESOURCE_DATA_ENTRY,*PIMAGE_RESOURCE_DATA_ENTRY; + + typedef struct { + DWORD Size; + DWORD TimeDateStamp; + WORD MajorVersion; + WORD MinorVersion; + DWORD GlobalFlagsClear; + DWORD GlobalFlagsSet; + DWORD CriticalSectionDefaultTimeout; + DWORD DeCommitFreeBlockThreshold; + DWORD DeCommitTotalFreeThreshold; + DWORD LockPrefixTable; + DWORD MaximumAllocationSize; + DWORD VirtualMemoryThreshold; + DWORD ProcessHeapFlags; + DWORD ProcessAffinityMask; + WORD CSDVersion; + WORD Reserved1; + DWORD EditList; + DWORD SecurityCookie; + DWORD SEHandlerTable; + DWORD SEHandlerCount; + } IMAGE_LOAD_CONFIG_DIRECTORY32,*PIMAGE_LOAD_CONFIG_DIRECTORY32; + + typedef struct { + DWORD Size; + DWORD TimeDateStamp; + WORD MajorVersion; + WORD MinorVersion; + DWORD GlobalFlagsClear; + DWORD GlobalFlagsSet; + DWORD CriticalSectionDefaultTimeout; + ULONGLONG DeCommitFreeBlockThreshold; + ULONGLONG DeCommitTotalFreeThreshold; + ULONGLONG LockPrefixTable; + ULONGLONG MaximumAllocationSize; + ULONGLONG VirtualMemoryThreshold; + ULONGLONG ProcessAffinityMask; + DWORD ProcessHeapFlags; + WORD CSDVersion; + WORD Reserved1; + ULONGLONG EditList; + ULONGLONG SecurityCookie; + ULONGLONG SEHandlerTable; + ULONGLONG SEHandlerCount; + } IMAGE_LOAD_CONFIG_DIRECTORY64,*PIMAGE_LOAD_CONFIG_DIRECTORY64; + +#ifdef _WIN64 + typedef IMAGE_LOAD_CONFIG_DIRECTORY64 IMAGE_LOAD_CONFIG_DIRECTORY; + typedef PIMAGE_LOAD_CONFIG_DIRECTORY64 PIMAGE_LOAD_CONFIG_DIRECTORY; +#else + typedef IMAGE_LOAD_CONFIG_DIRECTORY32 IMAGE_LOAD_CONFIG_DIRECTORY; + typedef PIMAGE_LOAD_CONFIG_DIRECTORY32 PIMAGE_LOAD_CONFIG_DIRECTORY; +#endif + + typedef struct _IMAGE_CE_RUNTIME_FUNCTION_ENTRY { + DWORD FuncStart; + DWORD PrologLen : 8; + DWORD FuncLen : 22; + DWORD ThirtyTwoBit : 1; + DWORD ExceptionFlag : 1; + } IMAGE_CE_RUNTIME_FUNCTION_ENTRY,*PIMAGE_CE_RUNTIME_FUNCTION_ENTRY; + + typedef struct _IMAGE_ALPHA64_RUNTIME_FUNCTION_ENTRY { + ULONGLONG BeginAddress; + ULONGLONG EndAddress; + ULONGLONG ExceptionHandler; + ULONGLONG HandlerData; + ULONGLONG PrologEndAddress; + } IMAGE_ALPHA64_RUNTIME_FUNCTION_ENTRY,*PIMAGE_ALPHA64_RUNTIME_FUNCTION_ENTRY; + + typedef struct _IMAGE_ALPHA_RUNTIME_FUNCTION_ENTRY { + DWORD BeginAddress; + DWORD EndAddress; + DWORD ExceptionHandler; + DWORD HandlerData; + DWORD PrologEndAddress; + } IMAGE_ALPHA_RUNTIME_FUNCTION_ENTRY,*PIMAGE_ALPHA_RUNTIME_FUNCTION_ENTRY; + + typedef struct _IMAGE_RUNTIME_FUNCTION_ENTRY { + DWORD BeginAddress; + DWORD EndAddress; + DWORD UnwindInfoAddress; + } _IMAGE_RUNTIME_FUNCTION_ENTRY,*_PIMAGE_RUNTIME_FUNCTION_ENTRY; + + typedef _IMAGE_RUNTIME_FUNCTION_ENTRY IMAGE_IA64_RUNTIME_FUNCTION_ENTRY; + typedef _PIMAGE_RUNTIME_FUNCTION_ENTRY PIMAGE_IA64_RUNTIME_FUNCTION_ENTRY; + + typedef _IMAGE_RUNTIME_FUNCTION_ENTRY IMAGE_RUNTIME_FUNCTION_ENTRY; + typedef _PIMAGE_RUNTIME_FUNCTION_ENTRY PIMAGE_RUNTIME_FUNCTION_ENTRY; + + typedef struct _IMAGE_DEBUG_DIRECTORY { + DWORD Characteristics; + DWORD TimeDateStamp; + WORD MajorVersion; + WORD MinorVersion; + DWORD Type; + DWORD SizeOfData; + DWORD AddressOfRawData; + DWORD PointerToRawData; + } IMAGE_DEBUG_DIRECTORY,*PIMAGE_DEBUG_DIRECTORY; + +#define IMAGE_DEBUG_TYPE_UNKNOWN 0 +#define IMAGE_DEBUG_TYPE_COFF 1 +#define IMAGE_DEBUG_TYPE_CODEVIEW 2 +#define IMAGE_DEBUG_TYPE_FPO 3 +#define IMAGE_DEBUG_TYPE_MISC 4 +#define IMAGE_DEBUG_TYPE_EXCEPTION 5 +#define IMAGE_DEBUG_TYPE_FIXUP 6 +#define IMAGE_DEBUG_TYPE_OMAP_TO_SRC 7 +#define IMAGE_DEBUG_TYPE_OMAP_FROM_SRC 8 +#define IMAGE_DEBUG_TYPE_BORLAND 9 +#define IMAGE_DEBUG_TYPE_RESERVED10 10 +#define IMAGE_DEBUG_TYPE_CLSID 11 + + typedef struct _IMAGE_COFF_SYMBOLS_HEADER { + DWORD NumberOfSymbols; + DWORD LvaToFirstSymbol; + DWORD NumberOfLinenumbers; + DWORD LvaToFirstLinenumber; + DWORD RvaToFirstByteOfCode; + DWORD RvaToLastByteOfCode; + DWORD RvaToFirstByteOfData; + DWORD RvaToLastByteOfData; + } IMAGE_COFF_SYMBOLS_HEADER,*PIMAGE_COFF_SYMBOLS_HEADER; + +#define FRAME_FPO 0 +#define FRAME_TRAP 1 +#define FRAME_TSS 2 +#define FRAME_NONFPO 3 + + typedef struct _FPO_DATA { + DWORD ulOffStart; + DWORD cbProcSize; + DWORD cdwLocals; + WORD cdwParams; + WORD cbProlog : 8; + WORD cbRegs : 3; + WORD fHasSEH : 1; + WORD fUseBP : 1; + WORD reserved : 1; + WORD cbFrame : 2; + } FPO_DATA,*PFPO_DATA; +#define SIZEOF_RFPO_DATA 16 + +#define IMAGE_DEBUG_MISC_EXENAME 1 + + typedef struct _IMAGE_DEBUG_MISC { + DWORD DataType; + DWORD Length; + BOOLEAN Unicode; + BYTE Reserved[3]; + BYTE Data[1]; + } IMAGE_DEBUG_MISC,*PIMAGE_DEBUG_MISC; + + typedef struct _IMAGE_FUNCTION_ENTRY { + DWORD StartingAddress; + DWORD EndingAddress; + DWORD EndOfPrologue; + } IMAGE_FUNCTION_ENTRY,*PIMAGE_FUNCTION_ENTRY; + + typedef struct _IMAGE_FUNCTION_ENTRY64 { + ULONGLONG StartingAddress; + ULONGLONG EndingAddress; + union { + ULONGLONG EndOfPrologue; + ULONGLONG UnwindInfoAddress; + }; + } IMAGE_FUNCTION_ENTRY64,*PIMAGE_FUNCTION_ENTRY64; + + typedef struct _IMAGE_SEPARATE_DEBUG_HEADER { + WORD Signature; + WORD Flags; + WORD Machine; + WORD Characteristics; + DWORD TimeDateStamp; + DWORD CheckSum; + DWORD ImageBase; + DWORD SizeOfImage; + DWORD NumberOfSections; + DWORD ExportedNamesSize; + DWORD DebugDirectorySize; + DWORD SectionAlignment; + DWORD Reserved[2]; + } IMAGE_SEPARATE_DEBUG_HEADER,*PIMAGE_SEPARATE_DEBUG_HEADER; + + typedef struct _NON_PAGED_DEBUG_INFO { + WORD Signature; + WORD Flags; + DWORD Size; + WORD Machine; + WORD Characteristics; + DWORD TimeDateStamp; + DWORD CheckSum; + DWORD SizeOfImage; + ULONGLONG ImageBase; + + } NON_PAGED_DEBUG_INFO,*PNON_PAGED_DEBUG_INFO; + +#define IMAGE_SEPARATE_DEBUG_SIGNATURE 0x4944 +#define NON_PAGED_DEBUG_SIGNATURE 0x494E + +#define IMAGE_SEPARATE_DEBUG_FLAGS_MASK 0x8000 +#define IMAGE_SEPARATE_DEBUG_MISMATCH 0x8000 + + typedef struct _ImageArchitectureHeader { + unsigned int AmaskValue: 1; + int Adummy1 :7; + unsigned int AmaskShift: 8; + int Adummy2 :16; + DWORD FirstEntryRVA; + } IMAGE_ARCHITECTURE_HEADER,*PIMAGE_ARCHITECTURE_HEADER; + + typedef struct _ImageArchitectureEntry { + DWORD FixupInstRVA; + DWORD NewInst; + } IMAGE_ARCHITECTURE_ENTRY,*PIMAGE_ARCHITECTURE_ENTRY; + +#include "poppack.h" + +#define IMPORT_OBJECT_HDR_SIG2 0xffff + + typedef struct IMPORT_OBJECT_HEADER { + WORD Sig1; + WORD Sig2; + WORD Version; + WORD Machine; + DWORD TimeDateStamp; + DWORD SizeOfData; + union { + WORD Ordinal; + WORD Hint; + }; + WORD Type : 2; + WORD NameType : 3; + WORD Reserved : 11; + } IMPORT_OBJECT_HEADER; + + typedef enum IMPORT_OBJECT_TYPE { + IMPORT_OBJECT_CODE = 0,IMPORT_OBJECT_DATA = 1,IMPORT_OBJECT_CONST = 2 + } IMPORT_OBJECT_TYPE; + + typedef enum IMPORT_OBJECT_NAME_TYPE { + IMPORT_OBJECT_ORDINAL = 0,IMPORT_OBJECT_NAME = 1,IMPORT_OBJECT_NAME_NO_PREFIX = 2,IMPORT_OBJECT_NAME_UNDECORATE = 3 + } IMPORT_OBJECT_NAME_TYPE; + +#ifndef __IMAGE_COR20_HEADER_DEFINED__ +#define __IMAGE_COR20_HEADER_DEFINED__ + typedef enum ReplacesCorHdrNumericDefines { + COMIMAGE_FLAGS_ILONLY =0x00000001,COMIMAGE_FLAGS_32BITREQUIRED =0x00000002,COMIMAGE_FLAGS_IL_LIBRARY =0x00000004, + COMIMAGE_FLAGS_STRONGNAMESIGNED =0x00000008,COMIMAGE_FLAGS_TRACKDEBUGDATA =0x00010000,COR_VERSION_MAJOR_V2 =2, + COR_VERSION_MAJOR =COR_VERSION_MAJOR_V2,COR_VERSION_MINOR =0,COR_DELETED_NAME_LENGTH =8,COR_VTABLEGAP_NAME_LENGTH =8, + NATIVE_TYPE_MAX_CB =1,COR_ILMETHOD_SECT_SMALL_MAX_DATASIZE=0xFF,IMAGE_COR_MIH_METHODRVA =0x01,IMAGE_COR_MIH_EHRVA =0x02, + IMAGE_COR_MIH_BASICBLOCK =0x08,COR_VTABLE_32BIT =0x01,COR_VTABLE_64BIT =0x02,COR_VTABLE_FROM_UNMANAGED =0x04, + COR_VTABLE_CALL_MOST_DERIVED =0x10,IMAGE_COR_EATJ_THUNK_SIZE =32,MAX_CLASS_NAME =1024,MAX_PACKAGE_NAME =1024 + } ReplacesCorHdrNumericDefines; + + typedef struct IMAGE_COR20_HEADER { + DWORD cb; + WORD MajorRuntimeVersion; + WORD MinorRuntimeVersion; + IMAGE_DATA_DIRECTORY MetaData; + DWORD Flags; + DWORD EntryPointToken; + IMAGE_DATA_DIRECTORY Resources; + IMAGE_DATA_DIRECTORY StrongNameSignature; + IMAGE_DATA_DIRECTORY CodeManagerTable; + IMAGE_DATA_DIRECTORY VTableFixups; + IMAGE_DATA_DIRECTORY ExportAddressTableJumps; + IMAGE_DATA_DIRECTORY ManagedNativeHeader; + } IMAGE_COR20_HEADER,*PIMAGE_COR20_HEADER; +#endif + +#if defined (__x86_64) + NTSYSAPI PRUNTIME_FUNCTION NTAPI RtlLookupFunctionEntry (DWORD64 ControlPc, PDWORD64 ImageBase, PUNWIND_HISTORY_TABLE HistoryTable); + NTSYSAPI VOID NTAPI RtlUnwindEx (PVOID TargetFrame, PVOID TargetIp, PEXCEPTION_RECORD ExceptionRecord, PVOID ReturnValue, PCONTEXT ContextRecord, PUNWIND_HISTORY_TABLE HistoryTable); +#endif + +#include + +#ifndef _SLIST_HEADER_ +#define _SLIST_HEADER_ + +#ifdef _WIN64 + typedef struct _SLIST_ENTRY *PSLIST_ENTRY; + typedef DECLSPEC_ALIGN(16) struct _SLIST_ENTRY { + PSLIST_ENTRY Next; + } SLIST_ENTRY; +#else + +#define SLIST_ENTRY SINGLE_LIST_ENTRY +#define _SLIST_ENTRY _SINGLE_LIST_ENTRY +#define PSLIST_ENTRY PSINGLE_LIST_ENTRY +#endif + +#if defined(_WIN64) + + typedef DECLSPEC_ALIGN(16) struct _SLIST_HEADER { + ULONGLONG Alignment; + ULONGLONG Region; + } SLIST_HEADER; + + typedef struct _SLIST_HEADER *PSLIST_HEADER; +#else + + typedef union _SLIST_HEADER { + ULONGLONG Alignment; + struct { + SLIST_ENTRY Next; + WORD Depth; + WORD Sequence; + }; + } SLIST_HEADER,*PSLIST_HEADER; +#endif +#endif + + NTSYSAPI VOID NTAPI RtlInitializeSListHead(PSLIST_HEADER ListHead); + NTSYSAPI PSLIST_ENTRY NTAPI RtlFirstEntrySList(const SLIST_HEADER *ListHead); + NTSYSAPI PSLIST_ENTRY NTAPI RtlInterlockedPopEntrySList(PSLIST_HEADER ListHead); + NTSYSAPI PSLIST_ENTRY NTAPI RtlInterlockedPushEntrySList(PSLIST_HEADER ListHead,PSLIST_ENTRY ListEntry); + NTSYSAPI PSLIST_ENTRY NTAPI RtlInterlockedFlushSList(PSLIST_HEADER ListHead); + NTSYSAPI WORD NTAPI RtlQueryDepthSList(PSLIST_HEADER ListHead); + +#define HEAP_NO_SERIALIZE 0x00000001 +#define HEAP_GROWABLE 0x00000002 +#define HEAP_GENERATE_EXCEPTIONS 0x00000004 +#define HEAP_ZERO_MEMORY 0x00000008 +#define HEAP_REALLOC_IN_PLACE_ONLY 0x00000010 +#define HEAP_TAIL_CHECKING_ENABLED 0x00000020 +#define HEAP_FREE_CHECKING_ENABLED 0x00000040 +#define HEAP_DISABLE_COALESCE_ON_FREE 0x00000080 +#define HEAP_CREATE_ALIGN_16 0x00010000 +#define HEAP_CREATE_ENABLE_TRACING 0x00020000 +#define HEAP_CREATE_ENABLE_EXECUTE 0x00040000 +#define HEAP_MAXIMUM_TAG 0x0FFF +#define HEAP_PSEUDO_TAG_FLAG 0x8000 +#define HEAP_TAG_SHIFT 18 +#define HEAP_MAKE_TAG_FLAGS(b,o) ((DWORD)((b) + ((o) << 18))) + + NTSYSAPI VOID NTAPI RtlCaptureContext(PCONTEXT ContextRecord); + +#define IS_TEXT_UNICODE_ASCII16 0x0001 +#define IS_TEXT_UNICODE_REVERSE_ASCII16 0x0010 + +#define IS_TEXT_UNICODE_STATISTICS 0x0002 +#define IS_TEXT_UNICODE_REVERSE_STATISTICS 0x0020 + +#define IS_TEXT_UNICODE_CONTROLS 0x0004 +#define IS_TEXT_UNICODE_REVERSE_CONTROLS 0x0040 + +#define IS_TEXT_UNICODE_SIGNATURE 0x0008 +#define IS_TEXT_UNICODE_REVERSE_SIGNATURE 0x0080 + +#define IS_TEXT_UNICODE_ILLEGAL_CHARS 0x0100 +#define IS_TEXT_UNICODE_ODD_LENGTH 0x0200 +#define IS_TEXT_UNICODE_DBCS_LEADBYTE 0x0400 +#define IS_TEXT_UNICODE_NULL_BYTES 0x1000 + +#define IS_TEXT_UNICODE_UNICODE_MASK 0x000F +#define IS_TEXT_UNICODE_REVERSE_MASK 0x00F0 +#define IS_TEXT_UNICODE_NOT_UNICODE_MASK 0x0F00 +#define IS_TEXT_UNICODE_NOT_ASCII_MASK 0xF000 + +#define COMPRESSION_FORMAT_NONE (0x0000) +#define COMPRESSION_FORMAT_DEFAULT (0x0001) +#define COMPRESSION_FORMAT_LZNT1 (0x0002) +#define COMPRESSION_ENGINE_STANDARD (0x0000) +#define COMPRESSION_ENGINE_MAXIMUM (0x0100) +#define COMPRESSION_ENGINE_HIBER (0x0200) + +#if _DBG_MEMCPY_INLINE_ && !defined(_MEMCPY_INLINE_) && !defined(_CRTBLD) +#define _MEMCPY_INLINE_ + __CRT_INLINE PVOID __cdecl memcpy_inline(void *dst,const void *src,size_t size) { + if(((char *)dst > (char *)src) && ((char *)dst < ((char *)src + size))) { + __debugbreak(); + } + return memcpy(dst,src,size); + } +#define memcpy memcpy_inline +#endif + + NTSYSAPI SIZE_T NTAPI RtlCompareMemory(const VOID *Source1,const VOID *Source2,SIZE_T Length); + +#define RtlEqualMemory(Destination,Source,Length) (!memcmp((Destination),(Source),(Length))) +#define RtlMoveMemory(Destination,Source,Length) memmove((Destination),(Source),(Length)) +#define RtlCopyMemory(Destination,Source,Length) memcpy((Destination),(Source),(Length)) +#define RtlFillMemory(Destination,Length,Fill) memset((Destination),(Fill),(Length)) +#define RtlZeroMemory(Destination,Length) memset((Destination),0,(Length)) + + __CRT_INLINE PVOID RtlSecureZeroMemory(PVOID ptr,SIZE_T cnt) { + volatile char *vptr =(volatile char *)ptr; +#ifdef __x86_64 + __stosb((PBYTE)((DWORD64)vptr),0,cnt); +#else + while(cnt) { + *vptr = 0; + vptr++; + cnt--; + } +#endif + return ptr; + } + + typedef struct _MESSAGE_RESOURCE_ENTRY { + WORD Length; + WORD Flags; + BYTE Text[1]; + } MESSAGE_RESOURCE_ENTRY,*PMESSAGE_RESOURCE_ENTRY; + +#define MESSAGE_RESOURCE_UNICODE 0x0001 + + typedef struct _MESSAGE_RESOURCE_BLOCK { + DWORD LowId; + DWORD HighId; + DWORD OffsetToEntries; + } MESSAGE_RESOURCE_BLOCK,*PMESSAGE_RESOURCE_BLOCK; + + typedef struct _MESSAGE_RESOURCE_DATA { + DWORD NumberOfBlocks; + MESSAGE_RESOURCE_BLOCK Blocks[1]; + } MESSAGE_RESOURCE_DATA,*PMESSAGE_RESOURCE_DATA; + + typedef struct _OSVERSIONINFOA { + DWORD dwOSVersionInfoSize; + DWORD dwMajorVersion; + DWORD dwMinorVersion; + DWORD dwBuildNumber; + DWORD dwPlatformId; + CHAR szCSDVersion[128]; + } OSVERSIONINFOA,*POSVERSIONINFOA,*LPOSVERSIONINFOA; + + typedef struct _OSVERSIONINFOW { + DWORD dwOSVersionInfoSize; + DWORD dwMajorVersion; + DWORD dwMinorVersion; + DWORD dwBuildNumber; + DWORD dwPlatformId; + WCHAR szCSDVersion[128]; + } OSVERSIONINFOW,*POSVERSIONINFOW,*LPOSVERSIONINFOW,RTL_OSVERSIONINFOW,*PRTL_OSVERSIONINFOW; + +#ifdef UNICODE + typedef OSVERSIONINFOW OSVERSIONINFO; + typedef POSVERSIONINFOW POSVERSIONINFO; + typedef LPOSVERSIONINFOW LPOSVERSIONINFO; +#else + typedef OSVERSIONINFOA OSVERSIONINFO; + typedef POSVERSIONINFOA POSVERSIONINFO; + typedef LPOSVERSIONINFOA LPOSVERSIONINFO; +#endif + + typedef struct _OSVERSIONINFOEXA { + DWORD dwOSVersionInfoSize; + DWORD dwMajorVersion; + DWORD dwMinorVersion; + DWORD dwBuildNumber; + DWORD dwPlatformId; + CHAR szCSDVersion[128]; + WORD wServicePackMajor; + WORD wServicePackMinor; + WORD wSuiteMask; + BYTE wProductType; + BYTE wReserved; + } OSVERSIONINFOEXA,*POSVERSIONINFOEXA,*LPOSVERSIONINFOEXA; + + typedef struct _OSVERSIONINFOEXW { + DWORD dwOSVersionInfoSize; + DWORD dwMajorVersion; + DWORD dwMinorVersion; + DWORD dwBuildNumber; + DWORD dwPlatformId; + WCHAR szCSDVersion[128]; + WORD wServicePackMajor; + WORD wServicePackMinor; + WORD wSuiteMask; + BYTE wProductType; + BYTE wReserved; + } OSVERSIONINFOEXW,*POSVERSIONINFOEXW,*LPOSVERSIONINFOEXW,RTL_OSVERSIONINFOEXW,*PRTL_OSVERSIONINFOEXW; +#ifdef UNICODE + typedef OSVERSIONINFOEXW OSVERSIONINFOEX; + typedef POSVERSIONINFOEXW POSVERSIONINFOEX; + typedef LPOSVERSIONINFOEXW LPOSVERSIONINFOEX; +#else + typedef OSVERSIONINFOEXA OSVERSIONINFOEX; + typedef POSVERSIONINFOEXA POSVERSIONINFOEX; + typedef LPOSVERSIONINFOEXA LPOSVERSIONINFOEX; +#endif + +#define VER_EQUAL 1 +#define VER_GREATER 2 +#define VER_GREATER_EQUAL 3 +#define VER_LESS 4 +#define VER_LESS_EQUAL 5 +#define VER_AND 6 +#define VER_OR 7 + +#define VER_CONDITION_MASK 7 +#define VER_NUM_BITS_PER_CONDITION_MASK 3 + +#define VER_MINORVERSION 0x0000001 +#define VER_MAJORVERSION 0x0000002 +#define VER_BUILDNUMBER 0x0000004 +#define VER_PLATFORMID 0x0000008 +#define VER_SERVICEPACKMINOR 0x0000010 +#define VER_SERVICEPACKMAJOR 0x0000020 +#define VER_SUITENAME 0x0000040 +#define VER_PRODUCT_TYPE 0x0000080 + +#define VER_NT_WORKSTATION 0x0000001 +#define VER_NT_DOMAIN_CONTROLLER 0x0000002 +#define VER_NT_SERVER 0x0000003 + +#define VER_PLATFORM_WIN32s 0 +#define VER_PLATFORM_WIN32_WINDOWS 1 +#define VER_PLATFORM_WIN32_NT 2 + +#define VER_SET_CONDITION(_m_,_t_,_c_) ((_m_)=VerSetConditionMask((_m_),(_t_),(_c_))) + + NTSYSAPI ULONGLONG NTAPI VerSetConditionMask(ULONGLONG ConditionMask,DWORD TypeMask,BYTE Condition); + + typedef struct _RTL_CRITICAL_SECTION_DEBUG { + WORD Type; + WORD CreatorBackTraceIndex; + struct _RTL_CRITICAL_SECTION *CriticalSection; + LIST_ENTRY ProcessLocksList; + DWORD EntryCount; + DWORD ContentionCount; + DWORD Spare[2]; + } RTL_CRITICAL_SECTION_DEBUG,*PRTL_CRITICAL_SECTION_DEBUG,RTL_RESOURCE_DEBUG,*PRTL_RESOURCE_DEBUG; + +#define RTL_CRITSECT_TYPE 0 +#define RTL_RESOURCE_TYPE 1 + + typedef struct _RTL_CRITICAL_SECTION { + PRTL_CRITICAL_SECTION_DEBUG DebugInfo; + LONG LockCount; + LONG RecursionCount; + HANDLE OwningThread; + HANDLE LockSemaphore; + ULONG_PTR SpinCount; + } RTL_CRITICAL_SECTION,*PRTL_CRITICAL_SECTION; + + typedef VOID (NTAPI *RTL_VERIFIER_DLL_LOAD_CALLBACK) (PWSTR DllName,PVOID DllBase,SIZE_T DllSize,PVOID Reserved); + typedef VOID (NTAPI *RTL_VERIFIER_DLL_UNLOAD_CALLBACK) (PWSTR DllName,PVOID DllBase,SIZE_T DllSize,PVOID Reserved); + typedef VOID (NTAPI *RTL_VERIFIER_NTDLLHEAPFREE_CALLBACK)(PVOID AllocationBase,SIZE_T AllocationSize); + + typedef struct _RTL_VERIFIER_THUNK_DESCRIPTOR { + PCHAR ThunkName; + PVOID ThunkOldAddress; + PVOID ThunkNewAddress; + } RTL_VERIFIER_THUNK_DESCRIPTOR,*PRTL_VERIFIER_THUNK_DESCRIPTOR; + + typedef struct _RTL_VERIFIER_DLL_DESCRIPTOR { + PWCHAR DllName; + DWORD DllFlags; + PVOID DllAddress; + PRTL_VERIFIER_THUNK_DESCRIPTOR DllThunks; + } RTL_VERIFIER_DLL_DESCRIPTOR,*PRTL_VERIFIER_DLL_DESCRIPTOR; + + typedef struct _RTL_VERIFIER_PROVIDER_DESCRIPTOR { + DWORD Length; + PRTL_VERIFIER_DLL_DESCRIPTOR ProviderDlls; + RTL_VERIFIER_DLL_LOAD_CALLBACK ProviderDllLoadCallback; + RTL_VERIFIER_DLL_UNLOAD_CALLBACK ProviderDllUnloadCallback; + PWSTR VerifierImage; + DWORD VerifierFlags; + DWORD VerifierDebug; + PVOID RtlpGetStackTraceAddress; + PVOID RtlpDebugPageHeapCreate; + PVOID RtlpDebugPageHeapDestroy; + RTL_VERIFIER_NTDLLHEAPFREE_CALLBACK ProviderNtdllHeapFreeCallback; + } RTL_VERIFIER_PROVIDER_DESCRIPTOR,*PRTL_VERIFIER_PROVIDER_DESCRIPTOR; + +#define RTL_VRF_FLG_FULL_PAGE_HEAP 0x00000001 +#define RTL_VRF_FLG_RESERVED_DONOTUSE 0x00000002 +#define RTL_VRF_FLG_HANDLE_CHECKS 0x00000004 +#define RTL_VRF_FLG_STACK_CHECKS 0x00000008 +#define RTL_VRF_FLG_APPCOMPAT_CHECKS 0x00000010 +#define RTL_VRF_FLG_TLS_CHECKS 0x00000020 +#define RTL_VRF_FLG_DIRTY_STACKS 0x00000040 +#define RTL_VRF_FLG_RPC_CHECKS 0x00000080 +#define RTL_VRF_FLG_COM_CHECKS 0x00000100 +#define RTL_VRF_FLG_DANGEROUS_APIS 0x00000200 +#define RTL_VRF_FLG_RACE_CHECKS 0x00000400 +#define RTL_VRF_FLG_DEADLOCK_CHECKS 0x00000800 +#define RTL_VRF_FLG_FIRST_CHANCE_EXCEPTION_CHECKS 0x00001000 +#define RTL_VRF_FLG_VIRTUAL_MEM_CHECKS 0x00002000 +#define RTL_VRF_FLG_ENABLE_LOGGING 0x00004000 +#define RTL_VRF_FLG_FAST_FILL_HEAP 0x00008000 +#define RTL_VRF_FLG_VIRTUAL_SPACE_TRACKING 0x00010000 +#define RTL_VRF_FLG_ENABLED_SYSTEM_WIDE 0x00020000 +#define RTL_VRF_FLG_MISCELLANEOUS_CHECKS 0x00020000 +#define RTL_VRF_FLG_LOCK_CHECKS 0x00040000 + +#define APPLICATION_VERIFIER_INTERNAL_ERROR 0x80000000 +#define APPLICATION_VERIFIER_INTERNAL_WARNING 0x40000000 +#define APPLICATION_VERIFIER_NO_BREAK 0x20000000 +#define APPLICATION_VERIFIER_CONTINUABLE_BREAK 0x10000000 + +#define APPLICATION_VERIFIER_UNKNOWN_ERROR 0x0001 +#define APPLICATION_VERIFIER_ACCESS_VIOLATION 0x0002 +#define APPLICATION_VERIFIER_UNSYNCHRONIZED_ACCESS 0x0003 +#define APPLICATION_VERIFIER_EXTREME_SIZE_REQUEST 0x0004 +#define APPLICATION_VERIFIER_BAD_HEAP_HANDLE 0x0005 +#define APPLICATION_VERIFIER_SWITCHED_HEAP_HANDLE 0x0006 +#define APPLICATION_VERIFIER_DOUBLE_FREE 0x0007 +#define APPLICATION_VERIFIER_CORRUPTED_HEAP_BLOCK 0x0008 +#define APPLICATION_VERIFIER_DESTROY_PROCESS_HEAP 0x0009 +#define APPLICATION_VERIFIER_UNEXPECTED_EXCEPTION 0x000A +#define APPLICATION_VERIFIER_CORRUPTED_HEAP_BLOCK_EXCEPTION_RAISED_FOR_HEADER 0x000B +#define APPLICATION_VERIFIER_CORRUPTED_HEAP_BLOCK_EXCEPTION_RAISED_FOR_PROBING 0x000C +#define APPLICATION_VERIFIER_CORRUPTED_HEAP_BLOCK_HEADER 0x000D +#define APPLICATION_VERIFIER_CORRUPTED_FREED_HEAP_BLOCK 0x000E +#define APPLICATION_VERIFIER_CORRUPTED_HEAP_BLOCK_SUFFIX 0x000F +#define APPLICATION_VERIFIER_CORRUPTED_HEAP_BLOCK_START_STAMP 0x0010 +#define APPLICATION_VERIFIER_CORRUPTED_HEAP_BLOCK_END_STAMP 0x0011 +#define APPLICATION_VERIFIER_CORRUPTED_HEAP_BLOCK_PREFIX 0x0012 +#define APPLICATION_VERIFIER_FIRST_CHANCE_ACCESS_VIOLATION 0x0013 +#define APPLICATION_VERIFIER_CORRUPTED_HEAP_LIST 0x0014 + +#define APPLICATION_VERIFIER_TERMINATE_THREAD_CALL 0x0100 +#define APPLICATION_VERIFIER_STACK_OVERFLOW 0x0101 +#define APPLICATION_VERIFIER_INVALID_EXIT_PROCESS_CALL 0x0102 + +#define APPLICATION_VERIFIER_EXIT_THREAD_OWNS_LOCK 0x0200 +#define APPLICATION_VERIFIER_LOCK_IN_UNLOADED_DLL 0x0201 +#define APPLICATION_VERIFIER_LOCK_IN_FREED_HEAP 0x0202 +#define APPLICATION_VERIFIER_LOCK_DOUBLE_INITIALIZE 0x0203 +#define APPLICATION_VERIFIER_LOCK_IN_FREED_MEMORY 0x0204 +#define APPLICATION_VERIFIER_LOCK_CORRUPTED 0x0205 +#define APPLICATION_VERIFIER_LOCK_INVALID_OWNER 0x0206 +#define APPLICATION_VERIFIER_LOCK_INVALID_RECURSION_COUNT 0x0207 +#define APPLICATION_VERIFIER_LOCK_INVALID_LOCK_COUNT 0x0208 +#define APPLICATION_VERIFIER_LOCK_OVER_RELEASED 0x0209 +#define APPLICATION_VERIFIER_LOCK_NOT_INITIALIZED 0x0210 +#define APPLICATION_VERIFIER_LOCK_ALREADY_INITIALIZED 0x0211 +#define APPLICATION_VERIFIER_LOCK_IN_FREED_VMEM 0x0212 +#define APPLICATION_VERIFIER_LOCK_IN_UNMAPPED_MEM 0x0213 +#define APPLICATION_VERIFIER_THREAD_NOT_LOCK_OWNER 0x0214 + +#define APPLICATION_VERIFIER_INVALID_HANDLE 0x0300 +#define APPLICATION_VERIFIER_INVALID_TLS_VALUE 0x0301 +#define APPLICATION_VERIFIER_INCORRECT_WAIT_CALL 0x0302 +#define APPLICATION_VERIFIER_NULL_HANDLE 0x0303 +#define APPLICATION_VERIFIER_WAIT_IN_DLLMAIN 0x0304 + +#define APPLICATION_VERIFIER_COM_ERROR 0x0400 +#define APPLICATION_VERIFIER_COM_API_IN_DLLMAIN 0x0401 +#define APPLICATION_VERIFIER_COM_UNHANDLED_EXCEPTION 0x0402 +#define APPLICATION_VERIFIER_COM_UNBALANCED_COINIT 0x0403 +#define APPLICATION_VERIFIER_COM_UNBALANCED_OLEINIT 0x0404 +#define APPLICATION_VERIFIER_COM_UNBALANCED_SWC 0x0405 +#define APPLICATION_VERIFIER_COM_NULL_DACL 0x0406 +#define APPLICATION_VERIFIER_COM_UNSAFE_IMPERSONATION 0x0407 +#define APPLICATION_VERIFIER_COM_SMUGGLED_WRAPPER 0x0408 +#define APPLICATION_VERIFIER_COM_SMUGGLED_PROXY 0x0409 +#define APPLICATION_VERIFIER_COM_CF_SUCCESS_WITH_NULL 0x040A +#define APPLICATION_VERIFIER_COM_GCO_SUCCESS_WITH_NULL 0x040B +#define APPLICATION_VERIFIER_COM_OBJECT_IN_FREED_MEMORY 0x040C +#define APPLICATION_VERIFIER_COM_OBJECT_IN_UNLOADED_DLL 0x040D +#define APPLICATION_VERIFIER_COM_VTBL_IN_FREED_MEMORY 0x040E +#define APPLICATION_VERIFIER_COM_VTBL_IN_UNLOADED_DLL 0x040F +#define APPLICATION_VERIFIER_COM_HOLDING_LOCKS_ON_CALL 0x0410 + +#define APPLICATION_VERIFIER_RPC_ERROR 0x0500 + +#define APPLICATION_VERIFIER_INVALID_FREEMEM 0x0600 +#define APPLICATION_VERIFIER_INVALID_ALLOCMEM 0x0601 +#define APPLICATION_VERIFIER_INVALID_MAPVIEW 0x0602 +#define APPLICATION_VERIFIER_PROBE_INVALID_ADDRESS 0x0603 +#define APPLICATION_VERIFIER_PROBE_FREE_MEM 0x0604 +#define APPLICATION_VERIFIER_PROBE_GUARD_PAGE 0x0605 +#define APPLICATION_VERIFIER_PROBE_NULL 0x0606 +#define APPLICATION_VERIFIER_PROBE_INVALID_START_OR_SIZE 0x0607 +#define APPLICATION_VERIFIER_SIZE_HEAP_UNEXPECTED_EXCEPTION 0x0618 + +#define VERIFIER_STOP(Code,Msg,P1,S1,P2,S2,P3,S3,P4,S4) { RtlApplicationVerifierStop ((Code),(Msg),(ULONG_PTR)(P1),(S1),(ULONG_PTR)(P2),(S2),(ULONG_PTR)(P3),(S3),(ULONG_PTR)(P4),(S4)); } + + VOID NTAPI RtlApplicationVerifierStop(ULONG_PTR Code,PSTR Message,ULONG_PTR Param1,PSTR Description1,ULONG_PTR Param2,PSTR Description2,ULONG_PTR Param3,PSTR Description3,ULONG_PTR Param4,PSTR Description4); + + typedef LONG (NTAPI *PVECTORED_EXCEPTION_HANDLER)(struct _EXCEPTION_POINTERS *ExceptionInfo); +#define SEF_DACL_AUTO_INHERIT 0x01 +#define SEF_SACL_AUTO_INHERIT 0x02 +#define SEF_DEFAULT_DESCRIPTOR_FOR_OBJECT 0x04 +#define SEF_AVOID_PRIVILEGE_CHECK 0x08 +#define SEF_AVOID_OWNER_CHECK 0x10 +#define SEF_DEFAULT_OWNER_FROM_PARENT 0x20 +#define SEF_DEFAULT_GROUP_FROM_PARENT 0x40 + + typedef enum _HEAP_INFORMATION_CLASS { + HeapCompatibilityInformation + } HEAP_INFORMATION_CLASS; + + NTSYSAPI DWORD NTAPI RtlSetHeapInformation(PVOID HeapHandle,HEAP_INFORMATION_CLASS HeapInformationClass,PVOID HeapInformation,SIZE_T HeapInformationLength); + NTSYSAPI DWORD NTAPI RtlQueryHeapInformation(PVOID HeapHandle,HEAP_INFORMATION_CLASS HeapInformationClass,PVOID HeapInformation,SIZE_T HeapInformationLength,PSIZE_T ReturnLength); + DWORD NTAPI RtlMultipleAllocateHeap(PVOID HeapHandle,DWORD Flags,SIZE_T Size,DWORD Count,PVOID *Array); + DWORD NTAPI RtlMultipleFreeHeap(PVOID HeapHandle,DWORD Flags,DWORD Count,PVOID *Array); + +#define WT_EXECUTEDEFAULT 0x00000000 +#define WT_EXECUTEINIOTHREAD 0x00000001 +#define WT_EXECUTEINUITHREAD 0x00000002 +#define WT_EXECUTEINWAITTHREAD 0x00000004 +#define WT_EXECUTEONLYONCE 0x00000008 +#define WT_EXECUTEINTIMERTHREAD 0x00000020 +#define WT_EXECUTELONGFUNCTION 0x00000010 +#define WT_EXECUTEINPERSISTENTIOTHREAD 0x00000040 +#define WT_EXECUTEINPERSISTENTTHREAD 0x00000080 +#define WT_TRANSFER_IMPERSONATION 0x00000100 +#define WT_SET_MAX_THREADPOOL_THREADS(Flags,Limit) ((Flags) |= (Limit)<<16) + typedef VOID (NTAPI *WAITORTIMERCALLBACKFUNC)(PVOID,BOOLEAN); + typedef VOID (NTAPI *WORKERCALLBACKFUNC)(PVOID); + typedef VOID (NTAPI *APC_CALLBACK_FUNCTION)(DWORD ,PVOID,PVOID); + typedef + VOID + (NTAPI *PFLS_CALLBACK_FUNCTION)(PVOID lpFlsData); +#define WT_EXECUTEINLONGTHREAD 0x00000010 +#define WT_EXECUTEDELETEWAIT 0x00000008 + + typedef enum _ACTIVATION_CONTEXT_INFO_CLASS { + ActivationContextBasicInformation = 1,ActivationContextDetailedInformation = 2,AssemblyDetailedInformationInActivationContext = 3,FileInformationInAssemblyOfAssemblyInActivationContext = 4,MaxActivationContextInfoClass,AssemblyDetailedInformationInActivationContxt = 3,FileInformationInAssemblyOfAssemblyInActivationContxt = 4 + } ACTIVATION_CONTEXT_INFO_CLASS; + +#define ACTIVATIONCONTEXTINFOCLASS ACTIVATION_CONTEXT_INFO_CLASS + + typedef struct _ACTIVATION_CONTEXT_QUERY_INDEX { + DWORD ulAssemblyIndex; + DWORD ulFileIndexInAssembly; + } ACTIVATION_CONTEXT_QUERY_INDEX,*PACTIVATION_CONTEXT_QUERY_INDEX; + + typedef const struct _ACTIVATION_CONTEXT_QUERY_INDEX *PCACTIVATION_CONTEXT_QUERY_INDEX; + +#define ACTIVATION_CONTEXT_PATH_TYPE_NONE (1) +#define ACTIVATION_CONTEXT_PATH_TYPE_WIN32_FILE (2) +#define ACTIVATION_CONTEXT_PATH_TYPE_URL (3) +#define ACTIVATION_CONTEXT_PATH_TYPE_ASSEMBLYREF (4) + + typedef struct _ASSEMBLY_FILE_DETAILED_INFORMATION { + DWORD ulFlags; + DWORD ulFilenameLength; + DWORD ulPathLength; + + PCWSTR lpFileName; + PCWSTR lpFilePath; + } ASSEMBLY_FILE_DETAILED_INFORMATION,*PASSEMBLY_FILE_DETAILED_INFORMATION; + typedef const ASSEMBLY_FILE_DETAILED_INFORMATION *PCASSEMBLY_FILE_DETAILED_INFORMATION; + +#define _ASSEMBLY_DLL_REDIRECTION_DETAILED_INFORMATION _ASSEMBLY_FILE_DETAILED_INFORMATION +#define ASSEMBLY_DLL_REDIRECTION_DETAILED_INFORMATION ASSEMBLY_FILE_DETAILED_INFORMATION +#define PASSEMBLY_DLL_REDIRECTION_DETAILED_INFORMATION PASSEMBLY_FILE_DETAILED_INFORMATION +#define PCASSEMBLY_DLL_REDIRECTION_DETAILED_INFORMATION PCASSEMBLY_FILE_DETAILED_INFORMATION + + typedef struct _ACTIVATION_CONTEXT_ASSEMBLY_DETAILED_INFORMATION { + DWORD ulFlags; + DWORD ulEncodedAssemblyIdentityLength; + DWORD ulManifestPathType; + DWORD ulManifestPathLength; + LARGE_INTEGER liManifestLastWriteTime; + DWORD ulPolicyPathType; + DWORD ulPolicyPathLength; + LARGE_INTEGER liPolicyLastWriteTime; + DWORD ulMetadataSatelliteRosterIndex; + DWORD ulManifestVersionMajor; + DWORD ulManifestVersionMinor; + DWORD ulPolicyVersionMajor; + DWORD ulPolicyVersionMinor; + DWORD ulAssemblyDirectoryNameLength; + PCWSTR lpAssemblyEncodedAssemblyIdentity; + PCWSTR lpAssemblyManifestPath; + PCWSTR lpAssemblyPolicyPath; + PCWSTR lpAssemblyDirectoryName; + DWORD ulFileCount; + } ACTIVATION_CONTEXT_ASSEMBLY_DETAILED_INFORMATION,*PACTIVATION_CONTEXT_ASSEMBLY_DETAILED_INFORMATION; + + typedef const struct _ACTIVATION_CONTEXT_ASSEMBLY_DETAILED_INFORMATION *PCACTIVATION_CONTEXT_ASSEMBLY_DETAILED_INFORMATION; + + typedef struct _ACTIVATION_CONTEXT_DETAILED_INFORMATION { + DWORD dwFlags; + DWORD ulFormatVersion; + DWORD ulAssemblyCount; + DWORD ulRootManifestPathType; + DWORD ulRootManifestPathChars; + DWORD ulRootConfigurationPathType; + DWORD ulRootConfigurationPathChars; + DWORD ulAppDirPathType; + DWORD ulAppDirPathChars; + PCWSTR lpRootManifestPath; + PCWSTR lpRootConfigurationPath; + PCWSTR lpAppDirPath; + } ACTIVATION_CONTEXT_DETAILED_INFORMATION,*PACTIVATION_CONTEXT_DETAILED_INFORMATION; + + typedef const struct _ACTIVATION_CONTEXT_DETAILED_INFORMATION *PCACTIVATION_CONTEXT_DETAILED_INFORMATION; + +#define DLL_PROCESS_ATTACH 1 +#define DLL_THREAD_ATTACH 2 +#define DLL_THREAD_DETACH 3 +#define DLL_PROCESS_DETACH 0 +#define DLL_PROCESS_VERIFIER 4 + +#define EVENTLOG_SEQUENTIAL_READ 0x0001 +#define EVENTLOG_SEEK_READ 0x0002 +#define EVENTLOG_FORWARDS_READ 0x0004 +#define EVENTLOG_BACKWARDS_READ 0x0008 + +#define EVENTLOG_SUCCESS 0x0000 +#define EVENTLOG_ERROR_TYPE 0x0001 +#define EVENTLOG_WARNING_TYPE 0x0002 +#define EVENTLOG_INFORMATION_TYPE 0x0004 +#define EVENTLOG_AUDIT_SUCCESS 0x0008 +#define EVENTLOG_AUDIT_FAILURE 0x0010 + +#define EVENTLOG_START_PAIRED_EVENT 0x0001 +#define EVENTLOG_END_PAIRED_EVENT 0x0002 +#define EVENTLOG_END_ALL_PAIRED_EVENTS 0x0004 +#define EVENTLOG_PAIRED_EVENT_ACTIVE 0x0008 +#define EVENTLOG_PAIRED_EVENT_INACTIVE 0x0010 + + typedef struct _EVENTLOGRECORD { + DWORD Length; + DWORD Reserved; + DWORD RecordNumber; + DWORD TimeGenerated; + DWORD TimeWritten; + DWORD EventID; + WORD EventType; + WORD NumStrings; + WORD EventCategory; + WORD ReservedFlags; + DWORD ClosingRecordNumber; + DWORD StringOffset; + DWORD UserSidLength; + DWORD UserSidOffset; + DWORD DataLength; + DWORD DataOffset; + } EVENTLOGRECORD,*PEVENTLOGRECORD; + +#define MAXLOGICALLOGNAMESIZE 256 + + typedef struct _EVENTSFORLOGFILE{ + DWORD ulSize; + WCHAR szLogicalLogFile[MAXLOGICALLOGNAMESIZE]; + DWORD ulNumRecords; + EVENTLOGRECORD pEventLogRecords[]; + } EVENTSFORLOGFILE,*PEVENTSFORLOGFILE; + + typedef struct _PACKEDEVENTINFO{ + DWORD ulSize; + DWORD ulNumEventsForLogFile; + DWORD ulOffsets[]; + } PACKEDEVENTINFO,*PPACKEDEVENTINFO; + +#define KEY_QUERY_VALUE (0x0001) +#define KEY_SET_VALUE (0x0002) +#define KEY_CREATE_SUB_KEY (0x0004) +#define KEY_ENUMERATE_SUB_KEYS (0x0008) +#define KEY_NOTIFY (0x0010) +#define KEY_CREATE_LINK (0x0020) +#define KEY_WOW64_32KEY (0x0200) +#define KEY_WOW64_64KEY (0x0100) +#define KEY_WOW64_RES (0x0300) + +#define KEY_READ ((STANDARD_RIGHTS_READ | KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS | KEY_NOTIFY) & (~SYNCHRONIZE)) +#define KEY_WRITE ((STANDARD_RIGHTS_WRITE | KEY_SET_VALUE | KEY_CREATE_SUB_KEY) & (~SYNCHRONIZE)) +#define KEY_EXECUTE ((KEY_READ) & (~SYNCHRONIZE)) +#define KEY_ALL_ACCESS ((STANDARD_RIGHTS_ALL | KEY_QUERY_VALUE | KEY_SET_VALUE | KEY_CREATE_SUB_KEY | KEY_ENUMERATE_SUB_KEYS | KEY_NOTIFY | KEY_CREATE_LINK) & (~SYNCHRONIZE)) +#define REG_OPTION_RESERVED (0x00000000L) + +#define REG_OPTION_NON_VOLATILE (0x00000000L) +#define REG_OPTION_VOLATILE (0x00000001L) +#define REG_OPTION_CREATE_LINK (0x00000002L) +#define REG_OPTION_BACKUP_RESTORE (0x00000004L) +#define REG_OPTION_OPEN_LINK (0x00000008L) +#define REG_LEGAL_OPTION (REG_OPTION_RESERVED | REG_OPTION_NON_VOLATILE | REG_OPTION_VOLATILE | REG_OPTION_CREATE_LINK | REG_OPTION_BACKUP_RESTORE | REG_OPTION_OPEN_LINK) +#define REG_CREATED_NEW_KEY (0x00000001L) +#define REG_OPENED_EXISTING_KEY (0x00000002L) +#define REG_STANDARD_FORMAT 1 +#define REG_LATEST_FORMAT 2 +#define REG_NO_COMPRESSION 4 +#define REG_WHOLE_HIVE_VOLATILE (0x00000001L) +#define REG_REFRESH_HIVE (0x00000002L) +#define REG_NO_LAZY_FLUSH (0x00000004L) +#define REG_FORCE_RESTORE (0x00000008L) +#define REG_FORCE_UNLOAD 1 + +#define REG_NOTIFY_CHANGE_NAME (0x00000001L) +#define REG_NOTIFY_CHANGE_ATTRIBUTES (0x00000002L) +#define REG_NOTIFY_CHANGE_LAST_SET (0x00000004L) +#define REG_NOTIFY_CHANGE_SECURITY (0x00000008L) + +#define REG_LEGAL_CHANGE_FILTER (REG_NOTIFY_CHANGE_NAME | REG_NOTIFY_CHANGE_ATTRIBUTES | REG_NOTIFY_CHANGE_LAST_SET | REG_NOTIFY_CHANGE_SECURITY) + +#define REG_NONE (0) +#define REG_SZ (1) +#define REG_EXPAND_SZ (2) + +#define REG_BINARY (3) +#define REG_DWORD (4) +#define REG_DWORD_LITTLE_ENDIAN (4) +#define REG_DWORD_BIG_ENDIAN (5) +#define REG_LINK (6) +#define REG_MULTI_SZ (7) +#define REG_RESOURCE_LIST (8) +#define REG_FULL_RESOURCE_DESCRIPTOR (9) +#define REG_RESOURCE_REQUIREMENTS_LIST (10) +#define REG_QWORD (11) +#define REG_QWORD_LITTLE_ENDIAN (11) + +#define SERVICE_KERNEL_DRIVER 0x00000001 +#define SERVICE_FILE_SYSTEM_DRIVER 0x00000002 +#define SERVICE_ADAPTER 0x00000004 +#define SERVICE_RECOGNIZER_DRIVER 0x00000008 + +#define SERVICE_DRIVER (SERVICE_KERNEL_DRIVER | SERVICE_FILE_SYSTEM_DRIVER | SERVICE_RECOGNIZER_DRIVER) + +#define SERVICE_WIN32_OWN_PROCESS 0x00000010 +#define SERVICE_WIN32_SHARE_PROCESS 0x00000020 +#define SERVICE_WIN32 (SERVICE_WIN32_OWN_PROCESS | SERVICE_WIN32_SHARE_PROCESS) + +#define SERVICE_INTERACTIVE_PROCESS 0x00000100 + +#define SERVICE_TYPE_ALL (SERVICE_WIN32 | SERVICE_ADAPTER | SERVICE_DRIVER | SERVICE_INTERACTIVE_PROCESS) + +#define SERVICE_BOOT_START 0x00000000 +#define SERVICE_SYSTEM_START 0x00000001 +#define SERVICE_AUTO_START 0x00000002 +#define SERVICE_DEMAND_START 0x00000003 +#define SERVICE_DISABLED 0x00000004 + +#define SERVICE_ERROR_IGNORE 0x00000000 +#define SERVICE_ERROR_NORMAL 0x00000001 +#define SERVICE_ERROR_SEVERE 0x00000002 +#define SERVICE_ERROR_CRITICAL 0x00000003 + + typedef enum _CM_SERVICE_NODE_TYPE { + DriverType = SERVICE_KERNEL_DRIVER,FileSystemType = SERVICE_FILE_SYSTEM_DRIVER,Win32ServiceOwnProcess = SERVICE_WIN32_OWN_PROCESS, + Win32ServiceShareProcess = SERVICE_WIN32_SHARE_PROCESS,AdapterType = SERVICE_ADAPTER,RecognizerType = SERVICE_RECOGNIZER_DRIVER + } SERVICE_NODE_TYPE; + + typedef enum _CM_SERVICE_LOAD_TYPE { + BootLoad = SERVICE_BOOT_START,SystemLoad = SERVICE_SYSTEM_START,AutoLoad = SERVICE_AUTO_START,DemandLoad = SERVICE_DEMAND_START, + DisableLoad = SERVICE_DISABLED + } SERVICE_LOAD_TYPE; + + typedef enum _CM_ERROR_CONTROL_TYPE { + IgnoreError = SERVICE_ERROR_IGNORE,NormalError = SERVICE_ERROR_NORMAL,SevereError = SERVICE_ERROR_SEVERE,CriticalError = SERVICE_ERROR_CRITICAL + } SERVICE_ERROR_TYPE; + +#define TAPE_ERASE_SHORT 0L +#define TAPE_ERASE_LONG 1L + + typedef struct _TAPE_ERASE { + DWORD Type; + BOOLEAN Immediate; + } TAPE_ERASE,*PTAPE_ERASE; + +#define TAPE_LOAD 0L +#define TAPE_UNLOAD 1L +#define TAPE_TENSION 2L +#define TAPE_LOCK 3L +#define TAPE_UNLOCK 4L +#define TAPE_FORMAT 5L + + typedef struct _TAPE_PREPARE { + DWORD Operation; + BOOLEAN Immediate; + } TAPE_PREPARE,*PTAPE_PREPARE; + +#define TAPE_SETMARKS 0L +#define TAPE_FILEMARKS 1L +#define TAPE_SHORT_FILEMARKS 2L +#define TAPE_LONG_FILEMARKS 3L + + typedef struct _TAPE_WRITE_MARKS { + DWORD Type; + DWORD Count; + BOOLEAN Immediate; + } TAPE_WRITE_MARKS,*PTAPE_WRITE_MARKS; + +#define TAPE_ABSOLUTE_POSITION 0L +#define TAPE_LOGICAL_POSITION 1L +#define TAPE_PSEUDO_LOGICAL_POSITION 2L + + typedef struct _TAPE_GET_POSITION { + DWORD Type; + DWORD Partition; + LARGE_INTEGER Offset; + } TAPE_GET_POSITION,*PTAPE_GET_POSITION; + +#define TAPE_REWIND 0L +#define TAPE_ABSOLUTE_BLOCK 1L +#define TAPE_LOGICAL_BLOCK 2L +#define TAPE_PSEUDO_LOGICAL_BLOCK 3L +#define TAPE_SPACE_END_OF_DATA 4L +#define TAPE_SPACE_RELATIVE_BLOCKS 5L +#define TAPE_SPACE_FILEMARKS 6L +#define TAPE_SPACE_SEQUENTIAL_FMKS 7L +#define TAPE_SPACE_SETMARKS 8L +#define TAPE_SPACE_SEQUENTIAL_SMKS 9L + + typedef struct _TAPE_SET_POSITION { + DWORD Method; + DWORD Partition; + LARGE_INTEGER Offset; + BOOLEAN Immediate; + } TAPE_SET_POSITION,*PTAPE_SET_POSITION; + +#define TAPE_DRIVE_FIXED 0x00000001 +#define TAPE_DRIVE_SELECT 0x00000002 +#define TAPE_DRIVE_INITIATOR 0x00000004 + +#define TAPE_DRIVE_ERASE_SHORT 0x00000010 +#define TAPE_DRIVE_ERASE_LONG 0x00000020 +#define TAPE_DRIVE_ERASE_BOP_ONLY 0x00000040 +#define TAPE_DRIVE_ERASE_IMMEDIATE 0x00000080 + +#define TAPE_DRIVE_TAPE_CAPACITY 0x00000100 +#define TAPE_DRIVE_TAPE_REMAINING 0x00000200 +#define TAPE_DRIVE_FIXED_BLOCK 0x00000400 +#define TAPE_DRIVE_VARIABLE_BLOCK 0x00000800 + +#define TAPE_DRIVE_WRITE_PROTECT 0x00001000 +#define TAPE_DRIVE_EOT_WZ_SIZE 0x00002000 + +#define TAPE_DRIVE_ECC 0x00010000 +#define TAPE_DRIVE_COMPRESSION 0x00020000 +#define TAPE_DRIVE_PADDING 0x00040000 +#define TAPE_DRIVE_REPORT_SMKS 0x00080000 + +#define TAPE_DRIVE_GET_ABSOLUTE_BLK 0x00100000 +#define TAPE_DRIVE_GET_LOGICAL_BLK 0x00200000 +#define TAPE_DRIVE_SET_EOT_WZ_SIZE 0x00400000 + +#define TAPE_DRIVE_EJECT_MEDIA 0x01000000 +#define TAPE_DRIVE_CLEAN_REQUESTS 0x02000000 +#define TAPE_DRIVE_SET_CMP_BOP_ONLY 0x04000000 + +#define TAPE_DRIVE_RESERVED_BIT 0x80000000 + +#define TAPE_DRIVE_LOAD_UNLOAD 0x80000001 +#define TAPE_DRIVE_TENSION 0x80000002 +#define TAPE_DRIVE_LOCK_UNLOCK 0x80000004 +#define TAPE_DRIVE_REWIND_IMMEDIATE 0x80000008 + +#define TAPE_DRIVE_SET_BLOCK_SIZE 0x80000010 +#define TAPE_DRIVE_LOAD_UNLD_IMMED 0x80000020 +#define TAPE_DRIVE_TENSION_IMMED 0x80000040 +#define TAPE_DRIVE_LOCK_UNLK_IMMED 0x80000080 + +#define TAPE_DRIVE_SET_ECC 0x80000100 +#define TAPE_DRIVE_SET_COMPRESSION 0x80000200 +#define TAPE_DRIVE_SET_PADDING 0x80000400 +#define TAPE_DRIVE_SET_REPORT_SMKS 0x80000800 + +#define TAPE_DRIVE_ABSOLUTE_BLK 0x80001000 +#define TAPE_DRIVE_ABS_BLK_IMMED 0x80002000 +#define TAPE_DRIVE_LOGICAL_BLK 0x80004000 +#define TAPE_DRIVE_LOG_BLK_IMMED 0x80008000 + +#define TAPE_DRIVE_END_OF_DATA 0x80010000 +#define TAPE_DRIVE_RELATIVE_BLKS 0x80020000 +#define TAPE_DRIVE_FILEMARKS 0x80040000 +#define TAPE_DRIVE_SEQUENTIAL_FMKS 0x80080000 + +#define TAPE_DRIVE_SETMARKS 0x80100000 +#define TAPE_DRIVE_SEQUENTIAL_SMKS 0x80200000 +#define TAPE_DRIVE_REVERSE_POSITION 0x80400000 +#define TAPE_DRIVE_SPACE_IMMEDIATE 0x80800000 + +#define TAPE_DRIVE_WRITE_SETMARKS 0x81000000 +#define TAPE_DRIVE_WRITE_FILEMARKS 0x82000000 +#define TAPE_DRIVE_WRITE_SHORT_FMKS 0x84000000 +#define TAPE_DRIVE_WRITE_LONG_FMKS 0x88000000 + +#define TAPE_DRIVE_WRITE_MARK_IMMED 0x90000000 +#define TAPE_DRIVE_FORMAT 0xA0000000 +#define TAPE_DRIVE_FORMAT_IMMEDIATE 0xC0000000 +#define TAPE_DRIVE_HIGH_FEATURES 0x80000000 + + typedef struct _TAPE_GET_DRIVE_PARAMETERS { + BOOLEAN ECC; + BOOLEAN Compression; + BOOLEAN DataPadding; + BOOLEAN ReportSetmarks; + DWORD DefaultBlockSize; + DWORD MaximumBlockSize; + DWORD MinimumBlockSize; + DWORD MaximumPartitionCount; + DWORD FeaturesLow; + DWORD FeaturesHigh; + DWORD EOTWarningZoneSize; + } TAPE_GET_DRIVE_PARAMETERS,*PTAPE_GET_DRIVE_PARAMETERS; + + typedef struct _TAPE_SET_DRIVE_PARAMETERS { + BOOLEAN ECC; + BOOLEAN Compression; + BOOLEAN DataPadding; + BOOLEAN ReportSetmarks; + DWORD EOTWarningZoneSize; + } TAPE_SET_DRIVE_PARAMETERS,*PTAPE_SET_DRIVE_PARAMETERS; + + typedef struct _TAPE_GET_MEDIA_PARAMETERS { + LARGE_INTEGER Capacity; + LARGE_INTEGER Remaining; + DWORD BlockSize; + DWORD PartitionCount; + BOOLEAN WriteProtected; + } TAPE_GET_MEDIA_PARAMETERS,*PTAPE_GET_MEDIA_PARAMETERS; + + typedef struct _TAPE_SET_MEDIA_PARAMETERS { + DWORD BlockSize; + } TAPE_SET_MEDIA_PARAMETERS,*PTAPE_SET_MEDIA_PARAMETERS; + +#define TAPE_FIXED_PARTITIONS 0L +#define TAPE_SELECT_PARTITIONS 1L +#define TAPE_INITIATOR_PARTITIONS 2L + + typedef struct _TAPE_CREATE_PARTITION { + DWORD Method; + DWORD Count; + DWORD Size; + } TAPE_CREATE_PARTITION,*PTAPE_CREATE_PARTITION; + +#define TAPE_QUERY_DRIVE_PARAMETERS 0L +#define TAPE_QUERY_MEDIA_CAPACITY 1L +#define TAPE_CHECK_FOR_DRIVE_PROBLEM 2L +#define TAPE_QUERY_IO_ERROR_DATA 3L +#define TAPE_QUERY_DEVICE_ERROR_DATA 4L + + typedef struct _TAPE_WMI_OPERATIONS { + DWORD Method; + DWORD DataBufferSize; + PVOID DataBuffer; + } TAPE_WMI_OPERATIONS,*PTAPE_WMI_OPERATIONS; + + typedef enum _TAPE_DRIVE_PROBLEM_TYPE { + TapeDriveProblemNone,TapeDriveReadWriteWarning,TapeDriveReadWriteError,TapeDriveReadWarning,TapeDriveWriteWarning,TapeDriveReadError,TapeDriveWriteError,TapeDriveHardwareError,TapeDriveUnsupportedMedia,TapeDriveScsiConnectionError,TapeDriveTimetoClean,TapeDriveCleanDriveNow,TapeDriveMediaLifeExpired,TapeDriveSnappedTape + } TAPE_DRIVE_PROBLEM_TYPE; + +#if defined(__x86_64) + __CRT_INLINE struct _TEB *NtCurrentTeb(VOID) { return (struct _TEB *)__readgsqword(FIELD_OFFSET(NT_TIB,Self)); } + __CRT_INLINE PVOID GetCurrentFiber(VOID) { return(PVOID)__readgsqword(FIELD_OFFSET(NT_TIB,FiberData)); } + __CRT_INLINE PVOID GetFiberData(VOID) { + return *(PVOID *)GetCurrentFiber(); + } +#endif + +#if(defined(_X86_) && !defined(__x86_64)) +#define PcTeb 0x18 + __CRT_INLINE struct _TEB *NtCurrentTeb(void) { + struct _TEB *ret; + __asm__ volatile ("movl %%fs:0x18,%0" + : "=r" (ret)); + return ret; + } +#endif + +#define ACTIVATION_CONTEXT_SECTION_ASSEMBLY_INFORMATION (1) +#define ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION (2) +#define ACTIVATION_CONTEXT_SECTION_WINDOW_CLASS_REDIRECTION (3) +#define ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION (4) +#define ACTIVATION_CONTEXT_SECTION_COM_INTERFACE_REDIRECTION (5) +#define ACTIVATION_CONTEXT_SECTION_COM_TYPE_LIBRARY_REDIRECTION (6) +#define ACTIVATION_CONTEXT_SECTION_COM_PROGID_REDIRECTION (7) +#define ACTIVATION_CONTEXT_SECTION_GLOBAL_OBJECT_RENAME_TABLE (8) +#define ACTIVATION_CONTEXT_SECTION_CLR_SURROGATES (9) +#define ACTIVATION_CONTEXT_SECTION_APPLICATION_SETTINGS (10) + +#ifdef __cplusplus + } +#endif +#endif diff --git a/tinyc/win32/include/winapi/winreg.h b/tinyc/win32/include/winapi/winreg.h new file mode 100644 index 000000000..f158d2820 --- /dev/null +++ b/tinyc/win32/include/winapi/winreg.h @@ -0,0 +1,272 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _WINREG_ +#define _WINREG_ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef WINVER +#define WINVER 0x0502 +#endif + +#define RRF_RT_REG_NONE 0x00000001 +#define RRF_RT_REG_SZ 0x00000002 +#define RRF_RT_REG_EXPAND_SZ 0x00000004 +#define RRF_RT_REG_BINARY 0x00000008 +#define RRF_RT_REG_DWORD 0x00000010 +#define RRF_RT_REG_MULTI_SZ 0x00000020 +#define RRF_RT_REG_QWORD 0x00000040 + +#define RRF_RT_DWORD (RRF_RT_REG_BINARY | RRF_RT_REG_DWORD) +#define RRF_RT_QWORD (RRF_RT_REG_BINARY | RRF_RT_REG_QWORD) +#define RRF_RT_ANY 0x0000ffff + +#define RRF_NOEXPAND 0x10000000 +#define RRF_ZEROONFAILURE 0x20000000 + + typedef ACCESS_MASK REGSAM; + +#define HKEY_CLASSES_ROOT ((HKEY) (ULONG_PTR)((LONG)0x80000000)) +#define HKEY_CURRENT_USER ((HKEY) (ULONG_PTR)((LONG)0x80000001)) +#define HKEY_LOCAL_MACHINE ((HKEY) (ULONG_PTR)((LONG)0x80000002)) +#define HKEY_USERS ((HKEY) (ULONG_PTR)((LONG)0x80000003)) +#define HKEY_PERFORMANCE_DATA ((HKEY) (ULONG_PTR)((LONG)0x80000004)) +#define HKEY_PERFORMANCE_TEXT ((HKEY) (ULONG_PTR)((LONG)0x80000050)) +#define HKEY_PERFORMANCE_NLSTEXT ((HKEY) (ULONG_PTR)((LONG)0x80000060)) +#define HKEY_CURRENT_CONFIG ((HKEY) (ULONG_PTR)((LONG)0x80000005)) +#define HKEY_DYN_DATA ((HKEY) (ULONG_PTR)((LONG)0x80000006)) + +#define REG_SECURE_CONNECTION 1 + +#ifndef _PROVIDER_STRUCTS_DEFINED +#define _PROVIDER_STRUCTS_DEFINED + +#define PROVIDER_KEEPS_VALUE_LENGTH 0x1 + struct val_context { + int valuelen; + LPVOID value_context; + LPVOID val_buff_ptr; + }; + + typedef struct val_context *PVALCONTEXT; + + typedef struct pvalueA { + LPSTR pv_valuename; + int pv_valuelen; + LPVOID pv_value_context; + DWORD pv_type; + }PVALUEA,*PPVALUEA; + + typedef struct pvalueW { + LPWSTR pv_valuename; + int pv_valuelen; + LPVOID pv_value_context; + DWORD pv_type; + }PVALUEW,*PPVALUEW; + +#ifdef UNICODE + typedef PVALUEW PVALUE; + typedef PPVALUEW PPVALUE; +#else + typedef PVALUEA PVALUE; + typedef PPVALUEA PPVALUE; +#endif + + typedef DWORD __cdecl QUERYHANDLER(LPVOID keycontext,PVALCONTEXT val_list,DWORD num_vals,LPVOID outputbuffer,DWORD *total_outlen,DWORD input_blen); + + typedef QUERYHANDLER *PQUERYHANDLER; + + typedef struct provider_info { + PQUERYHANDLER pi_R0_1val; + PQUERYHANDLER pi_R0_allvals; + PQUERYHANDLER pi_R3_1val; + PQUERYHANDLER pi_R3_allvals; + DWORD pi_flags; + LPVOID pi_key_context; + } REG_PROVIDER; + + typedef struct provider_info *PPROVIDER; + + typedef struct value_entA { + LPSTR ve_valuename; + DWORD ve_valuelen; + DWORD_PTR ve_valueptr; + DWORD ve_type; + } VALENTA,*PVALENTA; + + typedef struct value_entW { + LPWSTR ve_valuename; + DWORD ve_valuelen; + DWORD_PTR ve_valueptr; + DWORD ve_type; + } VALENTW,*PVALENTW; + +#ifdef UNICODE + typedef VALENTW VALENT; + typedef PVALENTW PVALENT; +#else + typedef VALENTA VALENT; + typedef PVALENTA PVALENT; +#endif +#endif + +#define WIN31_CLASS NULL + +#ifdef UNICODE +#define RegConnectRegistry RegConnectRegistryW +#define RegConnectRegistryEx RegConnectRegistryExW +#define RegCreateKey RegCreateKeyW +#define RegCreateKeyEx RegCreateKeyExW +#define RegDeleteKey RegDeleteKeyW +#define RegDeleteKeyEx RegDeleteKeyExW +#define RegDeleteValue RegDeleteValueW +#define RegEnumKey RegEnumKeyW +#define RegEnumKeyEx RegEnumKeyExW +#define RegEnumValue RegEnumValueW +#define RegLoadKey RegLoadKeyW +#define RegOpenKey RegOpenKeyW +#define RegOpenKeyEx RegOpenKeyExW +#define RegQueryInfoKey RegQueryInfoKeyW +#define RegQueryValue RegQueryValueW +#define RegQueryMultipleValues RegQueryMultipleValuesW +#define RegQueryValueEx RegQueryValueExW +#define RegReplaceKey RegReplaceKeyW +#define RegRestoreKey RegRestoreKeyW +#define RegSaveKey RegSaveKeyW +#define RegSetValue RegSetValueW +#define RegSetValueEx RegSetValueExW +#define RegUnLoadKey RegUnLoadKeyW +#define RegGetValue RegGetValueW +#define InitiateSystemShutdown InitiateSystemShutdownW +#define AbortSystemShutdown AbortSystemShutdownW +#else +#define RegConnectRegistry RegConnectRegistryA +#define RegConnectRegistryEx RegConnectRegistryExA +#define RegCreateKey RegCreateKeyA +#define RegCreateKeyEx RegCreateKeyExA +#define RegDeleteKey RegDeleteKeyA +#define RegDeleteKeyEx RegDeleteKeyExA +#define RegDeleteValue RegDeleteValueA +#define RegEnumKey RegEnumKeyA +#define RegEnumKeyEx RegEnumKeyExA +#define RegEnumValue RegEnumValueA +#define RegLoadKey RegLoadKeyA +#define RegOpenKey RegOpenKeyA +#define RegOpenKeyEx RegOpenKeyExA +#define RegQueryInfoKey RegQueryInfoKeyA +#define RegQueryValue RegQueryValueA +#define RegQueryMultipleValues RegQueryMultipleValuesA +#define RegQueryValueEx RegQueryValueExA +#define RegReplaceKey RegReplaceKeyA +#define RegRestoreKey RegRestoreKeyA +#define RegSaveKey RegSaveKeyA +#define RegSetValue RegSetValueA +#define RegSetValueEx RegSetValueExA +#define RegUnLoadKey RegUnLoadKeyA +#define RegGetValue RegGetValueA +#define InitiateSystemShutdown InitiateSystemShutdownA +#define AbortSystemShutdown AbortSystemShutdownA +#endif + + WINADVAPI LONG WINAPI RegCloseKey(HKEY hKey); + WINADVAPI LONG WINAPI RegOverridePredefKey(HKEY hKey,HKEY hNewHKey); + WINADVAPI LONG WINAPI RegOpenUserClassesRoot(HANDLE hToken,DWORD dwOptions,REGSAM samDesired,PHKEY phkResult); + WINADVAPI LONG WINAPI RegOpenCurrentUser(REGSAM samDesired,PHKEY phkResult); + WINADVAPI LONG WINAPI RegDisablePredefinedCache(); + WINADVAPI LONG WINAPI RegConnectRegistryA(LPCSTR lpMachineName,HKEY hKey,PHKEY phkResult); + WINADVAPI LONG WINAPI RegConnectRegistryW(LPCWSTR lpMachineName,HKEY hKey,PHKEY phkResult); + WINADVAPI LONG WINAPI RegConnectRegistryExA(LPCSTR lpMachineName,HKEY hKey,ULONG Flags,PHKEY phkResult); + WINADVAPI LONG WINAPI RegConnectRegistryExW(LPCWSTR lpMachineName,HKEY hKey,ULONG Flags,PHKEY phkResult); + WINADVAPI LONG WINAPI RegCreateKeyA(HKEY hKey,LPCSTR lpSubKey,PHKEY phkResult); + WINADVAPI LONG WINAPI RegCreateKeyW(HKEY hKey,LPCWSTR lpSubKey,PHKEY phkResult); + WINADVAPI LONG WINAPI RegCreateKeyExA(HKEY hKey,LPCSTR lpSubKey,DWORD Reserved,LPSTR lpClass,DWORD dwOptions,REGSAM samDesired,LPSECURITY_ATTRIBUTES lpSecurityAttributes,PHKEY phkResult,LPDWORD lpdwDisposition); + WINADVAPI LONG WINAPI RegCreateKeyExW(HKEY hKey,LPCWSTR lpSubKey,DWORD Reserved,LPWSTR lpClass,DWORD dwOptions,REGSAM samDesired,LPSECURITY_ATTRIBUTES lpSecurityAttributes,PHKEY phkResult,LPDWORD lpdwDisposition); + WINADVAPI LONG WINAPI RegDeleteKeyA(HKEY hKey,LPCSTR lpSubKey); + WINADVAPI LONG WINAPI RegDeleteKeyW(HKEY hKey,LPCWSTR lpSubKey); + WINADVAPI LONG WINAPI RegDeleteKeyExA(HKEY hKey,LPCSTR lpSubKey,REGSAM samDesired,DWORD Reserved); + WINADVAPI LONG WINAPI RegDeleteKeyExW(HKEY hKey,LPCWSTR lpSubKey,REGSAM samDesired,DWORD Reserved); + WINADVAPI LONG WINAPI RegDisableReflectionKey(HKEY hBase); + WINADVAPI LONG WINAPI RegEnableReflectionKey(HKEY hBase); + WINADVAPI LONG WINAPI RegQueryReflectionKey(HKEY hBase,WINBOOL *bIsReflectionDisabled); + WINADVAPI LONG WINAPI RegDeleteValueA(HKEY hKey,LPCSTR lpValueName); + WINADVAPI LONG WINAPI RegDeleteValueW(HKEY hKey,LPCWSTR lpValueName); + WINADVAPI LONG WINAPI RegEnumKeyA(HKEY hKey,DWORD dwIndex,LPSTR lpName,DWORD cchName); + WINADVAPI LONG WINAPI RegEnumKeyW(HKEY hKey,DWORD dwIndex,LPWSTR lpName,DWORD cchName); + WINADVAPI LONG WINAPI RegEnumKeyExA(HKEY hKey,DWORD dwIndex,LPSTR lpName,LPDWORD lpcchName,LPDWORD lpReserved,LPSTR lpClass,LPDWORD lpcchClass,PFILETIME lpftLastWriteTime); + WINADVAPI LONG WINAPI RegEnumKeyExW(HKEY hKey,DWORD dwIndex,LPWSTR lpName,LPDWORD lpcchName,LPDWORD lpReserved,LPWSTR lpClass,LPDWORD lpcchClass,PFILETIME lpftLastWriteTime); + WINADVAPI LONG WINAPI RegEnumValueA(HKEY hKey,DWORD dwIndex,LPSTR lpValueName,LPDWORD lpcchValueName,LPDWORD lpReserved,LPDWORD lpType,LPBYTE lpData,LPDWORD lpcbData); + WINADVAPI LONG WINAPI RegEnumValueW(HKEY hKey,DWORD dwIndex,LPWSTR lpValueName,LPDWORD lpcchValueName,LPDWORD lpReserved,LPDWORD lpType,LPBYTE lpData,LPDWORD lpcbData); + WINADVAPI LONG WINAPI RegFlushKey(HKEY hKey); + WINADVAPI LONG WINAPI RegGetKeySecurity(HKEY hKey,SECURITY_INFORMATION SecurityInformation,PSECURITY_DESCRIPTOR pSecurityDescriptor,LPDWORD lpcbSecurityDescriptor); + WINADVAPI LONG WINAPI RegLoadKeyA(HKEY hKey,LPCSTR lpSubKey,LPCSTR lpFile); + WINADVAPI LONG WINAPI RegLoadKeyW(HKEY hKey,LPCWSTR lpSubKey,LPCWSTR lpFile); + WINADVAPI LONG WINAPI RegNotifyChangeKeyValue(HKEY hKey,WINBOOL bWatchSubtree,DWORD dwNotifyFilter,HANDLE hEvent,WINBOOL fAsynchronous); + WINADVAPI LONG WINAPI RegOpenKeyA(HKEY hKey,LPCSTR lpSubKey,PHKEY phkResult); + WINADVAPI LONG WINAPI RegOpenKeyW(HKEY hKey,LPCWSTR lpSubKey,PHKEY phkResult); + WINADVAPI LONG WINAPI RegOpenKeyExA(HKEY hKey,LPCSTR lpSubKey,DWORD ulOptions,REGSAM samDesired,PHKEY phkResult); + WINADVAPI LONG WINAPI RegOpenKeyExW(HKEY hKey,LPCWSTR lpSubKey,DWORD ulOptions,REGSAM samDesired,PHKEY phkResult); + WINADVAPI LONG WINAPI RegQueryInfoKeyA(HKEY hKey,LPSTR lpClass,LPDWORD lpcchClass,LPDWORD lpReserved,LPDWORD lpcSubKeys,LPDWORD lpcbMaxSubKeyLen,LPDWORD lpcbMaxClassLen,LPDWORD lpcValues,LPDWORD lpcbMaxValueNameLen,LPDWORD lpcbMaxValueLen,LPDWORD lpcbSecurityDescriptor,PFILETIME lpftLastWriteTime); + WINADVAPI LONG WINAPI RegQueryInfoKeyW(HKEY hKey,LPWSTR lpClass,LPDWORD lpcchClass,LPDWORD lpReserved,LPDWORD lpcSubKeys,LPDWORD lpcbMaxSubKeyLen,LPDWORD lpcbMaxClassLen,LPDWORD lpcValues,LPDWORD lpcbMaxValueNameLen,LPDWORD lpcbMaxValueLen,LPDWORD lpcbSecurityDescriptor,PFILETIME lpftLastWriteTime); + WINADVAPI LONG WINAPI RegQueryValueA(HKEY hKey,LPCSTR lpSubKey,LPSTR lpData,PLONG lpcbData); + WINADVAPI LONG WINAPI RegQueryValueW(HKEY hKey,LPCWSTR lpSubKey,LPWSTR lpData,PLONG lpcbData); + WINADVAPI LONG WINAPI RegQueryMultipleValuesA(HKEY hKey,PVALENTA val_list,DWORD num_vals,LPSTR lpValueBuf,LPDWORD ldwTotsize); + WINADVAPI LONG WINAPI RegQueryMultipleValuesW(HKEY hKey,PVALENTW val_list,DWORD num_vals,LPWSTR lpValueBuf,LPDWORD ldwTotsize); + WINADVAPI LONG WINAPI RegQueryValueExA(HKEY hKey,LPCSTR lpValueName,LPDWORD lpReserved,LPDWORD lpType,LPBYTE lpData,LPDWORD lpcbData); + WINADVAPI LONG WINAPI RegQueryValueExW(HKEY hKey,LPCWSTR lpValueName,LPDWORD lpReserved,LPDWORD lpType,LPBYTE lpData,LPDWORD lpcbData); + WINADVAPI LONG WINAPI RegReplaceKeyA(HKEY hKey,LPCSTR lpSubKey,LPCSTR lpNewFile,LPCSTR lpOldFile); + WINADVAPI LONG WINAPI RegReplaceKeyW(HKEY hKey,LPCWSTR lpSubKey,LPCWSTR lpNewFile,LPCWSTR lpOldFile); + WINADVAPI LONG WINAPI RegRestoreKeyA(HKEY hKey,LPCSTR lpFile,DWORD dwFlags); + WINADVAPI LONG WINAPI RegRestoreKeyW(HKEY hKey,LPCWSTR lpFile,DWORD dwFlags); + WINADVAPI LONG WINAPI RegSaveKeyA(HKEY hKey,LPCSTR lpFile,LPSECURITY_ATTRIBUTES lpSecurityAttributes); + WINADVAPI LONG WINAPI RegSaveKeyW(HKEY hKey,LPCWSTR lpFile,LPSECURITY_ATTRIBUTES lpSecurityAttributes); + WINADVAPI LONG WINAPI RegSetKeySecurity(HKEY hKey,SECURITY_INFORMATION SecurityInformation,PSECURITY_DESCRIPTOR pSecurityDescriptor); + WINADVAPI LONG WINAPI RegSetValueA(HKEY hKey,LPCSTR lpSubKey,DWORD dwType,LPCSTR lpData,DWORD cbData); + WINADVAPI LONG WINAPI RegSetValueW(HKEY hKey,LPCWSTR lpSubKey,DWORD dwType,LPCWSTR lpData,DWORD cbData); + WINADVAPI LONG WINAPI RegSetValueExA(HKEY hKey,LPCSTR lpValueName,DWORD Reserved,DWORD dwType,CONST BYTE *lpData,DWORD cbData); + WINADVAPI LONG WINAPI RegSetValueExW(HKEY hKey,LPCWSTR lpValueName,DWORD Reserved,DWORD dwType,CONST BYTE *lpData,DWORD cbData); + WINADVAPI LONG WINAPI RegUnLoadKeyA(HKEY hKey,LPCSTR lpSubKey); + WINADVAPI LONG WINAPI RegUnLoadKeyW(HKEY hKey,LPCWSTR lpSubKey); + WINADVAPI LONG WINAPI RegGetValueA(HKEY hkey,LPCSTR lpSubKey,LPCSTR lpValue,DWORD dwFlags,LPDWORD pdwType,PVOID pvData,LPDWORD pcbData); + WINADVAPI LONG WINAPI RegGetValueW(HKEY hkey,LPCWSTR lpSubKey,LPCWSTR lpValue,DWORD dwFlags,LPDWORD pdwType,PVOID pvData,LPDWORD pcbData); + WINADVAPI WINBOOL WINAPI InitiateSystemShutdownA(LPSTR lpMachineName,LPSTR lpMessage,DWORD dwTimeout,WINBOOL bForceAppsClosed,WINBOOL bRebootAfterShutdown); + WINADVAPI WINBOOL WINAPI InitiateSystemShutdownW(LPWSTR lpMachineName,LPWSTR lpMessage,DWORD dwTimeout,WINBOOL bForceAppsClosed,WINBOOL bRebootAfterShutdown); + WINADVAPI WINBOOL WINAPI AbortSystemShutdownA(LPSTR lpMachineName); + WINADVAPI WINBOOL WINAPI AbortSystemShutdownW(LPWSTR lpMachineName); + +//gr #include + +#define REASON_SWINSTALL SHTDN_REASON_MAJOR_SOFTWARE|SHTDN_REASON_MINOR_INSTALLATION +#define REASON_HWINSTALL SHTDN_REASON_MAJOR_HARDWARE|SHTDN_REASON_MINOR_INSTALLATION +#define REASON_SERVICEHANG SHTDN_REASON_MAJOR_SOFTWARE|SHTDN_REASON_MINOR_HUNG +#define REASON_UNSTABLE SHTDN_REASON_MAJOR_SYSTEM|SHTDN_REASON_MINOR_UNSTABLE +#define REASON_SWHWRECONF SHTDN_REASON_MAJOR_SOFTWARE|SHTDN_REASON_MINOR_RECONFIG +#define REASON_OTHER SHTDN_REASON_MAJOR_OTHER|SHTDN_REASON_MINOR_OTHER +#define REASON_UNKNOWN SHTDN_REASON_UNKNOWN +#define REASON_LEGACY_API SHTDN_REASON_LEGACY_API +#define REASON_PLANNED_FLAG SHTDN_REASON_FLAG_PLANNED + +#define MAX_SHUTDOWN_TIMEOUT (10*365*24*60*60) + +#ifdef UNICODE +#define InitiateSystemShutdownEx InitiateSystemShutdownExW +#define RegSaveKeyEx RegSaveKeyExW +#else +#define InitiateSystemShutdownEx InitiateSystemShutdownExA +#define RegSaveKeyEx RegSaveKeyExA +#endif + + WINADVAPI WINBOOL WINAPI InitiateSystemShutdownExA(LPSTR lpMachineName,LPSTR lpMessage,DWORD dwTimeout,WINBOOL bForceAppsClosed,WINBOOL bRebootAfterShutdown,DWORD dwReason); + WINADVAPI WINBOOL WINAPI InitiateSystemShutdownExW(LPWSTR lpMachineName,LPWSTR lpMessage,DWORD dwTimeout,WINBOOL bForceAppsClosed,WINBOOL bRebootAfterShutdown,DWORD dwReason); + WINADVAPI LONG WINAPI RegSaveKeyExA(HKEY hKey,LPCSTR lpFile,LPSECURITY_ATTRIBUTES lpSecurityAttributes,DWORD Flags); + WINADVAPI LONG WINAPI RegSaveKeyExW(HKEY hKey,LPCWSTR lpFile,LPSECURITY_ATTRIBUTES lpSecurityAttributes,DWORD Flags); + WINADVAPI LONG WINAPI Wow64Win32ApiEntry (DWORD dwFuncNumber,DWORD dwFlag,DWORD dwRes); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/tinyc/win32/include/winapi/winuser.h b/tinyc/win32/include/winapi/winuser.h new file mode 100644 index 000000000..4cd9ffb56 --- /dev/null +++ b/tinyc/win32/include/winapi/winuser.h @@ -0,0 +1,5651 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _WINUSER_ +#define _WINUSER_ + +#define WINUSERAPI DECLSPEC_IMPORT + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef WINVER +#define WINVER 0x0502 +#endif + +#include + +#ifndef NOUSER + typedef HANDLE HDWP; + typedef VOID MENUTEMPLATEA; + typedef VOID MENUTEMPLATEW; + typedef PVOID LPMENUTEMPLATEA; + typedef PVOID LPMENUTEMPLATEW; + +#ifdef UNICODE + typedef MENUTEMPLATEW MENUTEMPLATE; + typedef LPMENUTEMPLATEW LPMENUTEMPLATE; +#else + typedef MENUTEMPLATEA MENUTEMPLATE; + typedef LPMENUTEMPLATEA LPMENUTEMPLATE; +#endif + + typedef LRESULT (CALLBACK *WNDPROC)(HWND,UINT,WPARAM,LPARAM); + typedef INT_PTR (CALLBACK *DLGPROC)(HWND,UINT,WPARAM,LPARAM); + typedef VOID (CALLBACK *TIMERPROC)(HWND,UINT,UINT_PTR,DWORD); + typedef WINBOOL (CALLBACK *GRAYSTRINGPROC)(HDC,LPARAM,int); + typedef WINBOOL (CALLBACK *WNDENUMPROC)(HWND,LPARAM); + typedef LRESULT (CALLBACK *HOOKPROC)(int code,WPARAM wParam,LPARAM lParam); + typedef VOID (CALLBACK *SENDASYNCPROC)(HWND,UINT,ULONG_PTR,LRESULT); + typedef WINBOOL (CALLBACK *PROPENUMPROCA)(HWND,LPCSTR,HANDLE); + typedef WINBOOL (CALLBACK *PROPENUMPROCW)(HWND,LPCWSTR,HANDLE); + typedef WINBOOL (CALLBACK *PROPENUMPROCEXA)(HWND,LPSTR,HANDLE,ULONG_PTR); + typedef WINBOOL (CALLBACK *PROPENUMPROCEXW)(HWND,LPWSTR,HANDLE,ULONG_PTR); + typedef int (CALLBACK *EDITWORDBREAKPROCA)(LPSTR lpch,int ichCurrent,int cch,int code); + typedef int (CALLBACK *EDITWORDBREAKPROCW)(LPWSTR lpch,int ichCurrent,int cch,int code); + typedef WINBOOL (CALLBACK *DRAWSTATEPROC)(HDC hdc,LPARAM lData,WPARAM wData,int cx,int cy); + +#ifdef UNICODE + typedef PROPENUMPROCW PROPENUMPROC; + typedef PROPENUMPROCEXW PROPENUMPROCEX; + typedef EDITWORDBREAKPROCW EDITWORDBREAKPROC; +#else + typedef PROPENUMPROCA PROPENUMPROC; + typedef PROPENUMPROCEXA PROPENUMPROCEX; + typedef EDITWORDBREAKPROCA EDITWORDBREAKPROC; +#endif + + typedef WINBOOL (CALLBACK *NAMEENUMPROCA)(LPSTR,LPARAM); + typedef WINBOOL (CALLBACK *NAMEENUMPROCW)(LPWSTR,LPARAM); + typedef NAMEENUMPROCA WINSTAENUMPROCA; + typedef NAMEENUMPROCA DESKTOPENUMPROCA; + typedef NAMEENUMPROCW WINSTAENUMPROCW; + typedef NAMEENUMPROCW DESKTOPENUMPROCW; + +#ifdef UNICODE + typedef WINSTAENUMPROCW WINSTAENUMPROC; + typedef DESKTOPENUMPROCW DESKTOPENUMPROC; +#else + typedef WINSTAENUMPROCA WINSTAENUMPROC; + typedef DESKTOPENUMPROCA DESKTOPENUMPROC; +#endif + +#define IS_INTRESOURCE(_r) ((((ULONG_PTR)(_r)) >> 16)==0) +#define MAKEINTRESOURCEA(i) ((LPSTR)((ULONG_PTR)((WORD)(i)))) +#define MAKEINTRESOURCEW(i) ((LPWSTR)((ULONG_PTR)((WORD)(i)))) +#ifdef UNICODE +#define MAKEINTRESOURCE MAKEINTRESOURCEW +#else +#define MAKEINTRESOURCE MAKEINTRESOURCEA +#endif + +#ifndef NORESOURCE + +#define RT_CURSOR MAKEINTRESOURCE(1) +#define RT_BITMAP MAKEINTRESOURCE(2) +#define RT_ICON MAKEINTRESOURCE(3) +#define RT_MENU MAKEINTRESOURCE(4) +#define RT_DIALOG MAKEINTRESOURCE(5) +#define RT_STRING MAKEINTRESOURCE(6) +#define RT_FONTDIR MAKEINTRESOURCE(7) +#define RT_FONT MAKEINTRESOURCE(8) +#define RT_ACCELERATOR MAKEINTRESOURCE(9) +#define RT_RCDATA MAKEINTRESOURCE(10) +#define RT_MESSAGETABLE MAKEINTRESOURCE(11) + +#define DIFFERENCE 11 +#define RT_GROUP_CURSOR MAKEINTRESOURCE((ULONG_PTR)RT_CURSOR + DIFFERENCE) +#define RT_GROUP_ICON MAKEINTRESOURCE((ULONG_PTR)RT_ICON + DIFFERENCE) +#define RT_VERSION MAKEINTRESOURCE(16) +#define RT_DLGINCLUDE MAKEINTRESOURCE(17) +#define RT_PLUGPLAY MAKEINTRESOURCE(19) +#define RT_VXD MAKEINTRESOURCE(20) +#define RT_ANICURSOR MAKEINTRESOURCE(21) +#define RT_ANIICON MAKEINTRESOURCE(22) +#define RT_HTML MAKEINTRESOURCE(23) +#ifdef RC_INVOKED +#define RT_MANIFEST 24 +#define CREATEPROCESS_MANIFEST_RESOURCE_ID 1 +#define ISOLATIONAWARE_MANIFEST_RESOURCE_ID 2 +#define ISOLATIONAWARE_NOSTATICIMPORT_MANIFEST_RESOURCE_ID 3 +#define MINIMUM_RESERVED_MANIFEST_RESOURCE_ID 1 +#define MAXIMUM_RESERVED_MANIFEST_RESOURCE_ID 16 +#else +#define RT_MANIFEST MAKEINTRESOURCE(24) +#define CREATEPROCESS_MANIFEST_RESOURCE_ID MAKEINTRESOURCE(1) +#define ISOLATIONAWARE_MANIFEST_RESOURCE_ID MAKEINTRESOURCE(2) +#define ISOLATIONAWARE_NOSTATICIMPORT_MANIFEST_RESOURCE_ID MAKEINTRESOURCE(3) +#define MINIMUM_RESERVED_MANIFEST_RESOURCE_ID MAKEINTRESOURCE(1) +#define MAXIMUM_RESERVED_MANIFEST_RESOURCE_ID MAKEINTRESOURCE(16) +#endif +#endif + +#ifdef UNICODE +#define wvsprintf wvsprintfW +#define wsprintf wsprintfW +#else +#define wvsprintf wvsprintfA +#define wsprintf wsprintfA +#endif + + WINUSERAPI int WINAPI wvsprintfA(LPSTR,LPCSTR,va_list arglist); + WINUSERAPI int WINAPI wvsprintfW(LPWSTR,LPCWSTR,va_list arglist); + WINUSERAPI int WINAPIV wsprintfA(LPSTR,LPCSTR,...); + WINUSERAPI int WINAPIV wsprintfW(LPWSTR,LPCWSTR,...); + +#define SETWALLPAPER_DEFAULT ((LPWSTR)-1) + +#ifndef NOSCROLL +#define SB_HORZ 0 +#define SB_VERT 1 +#define SB_CTL 2 +#define SB_BOTH 3 + +#define SB_LINEUP 0 +#define SB_LINELEFT 0 +#define SB_LINEDOWN 1 +#define SB_LINERIGHT 1 +#define SB_PAGEUP 2 +#define SB_PAGELEFT 2 +#define SB_PAGEDOWN 3 +#define SB_PAGERIGHT 3 +#define SB_THUMBPOSITION 4 +#define SB_THUMBTRACK 5 +#define SB_TOP 6 +#define SB_LEFT 6 +#define SB_BOTTOM 7 +#define SB_RIGHT 7 +#define SB_ENDSCROLL 8 +#endif + +#ifndef NOSHOWWINDOW +#define SW_HIDE 0 +#define SW_SHOWNORMAL 1 +#define SW_NORMAL 1 +#define SW_SHOWMINIMIZED 2 +#define SW_SHOWMAXIMIZED 3 +#define SW_MAXIMIZE 3 +#define SW_SHOWNOACTIVATE 4 +#define SW_SHOW 5 +#define SW_MINIMIZE 6 +#define SW_SHOWMINNOACTIVE 7 +#define SW_SHOWNA 8 +#define SW_RESTORE 9 +#define SW_SHOWDEFAULT 10 +#define SW_FORCEMINIMIZE 11 +#define SW_MAX 11 + +#define HIDE_WINDOW 0 +#define SHOW_OPENWINDOW 1 +#define SHOW_ICONWINDOW 2 +#define SHOW_FULLSCREEN 3 +#define SHOW_OPENNOACTIVATE 4 + +#define SW_PARENTCLOSING 1 +#define SW_OTHERZOOM 2 +#define SW_PARENTOPENING 3 +#define SW_OTHERUNZOOM 4 +#endif + +#define AW_HOR_POSITIVE 0x00000001 +#define AW_HOR_NEGATIVE 0x00000002 +#define AW_VER_POSITIVE 0x00000004 +#define AW_VER_NEGATIVE 0x00000008 +#define AW_CENTER 0x00000010 +#define AW_HIDE 0x00010000 +#define AW_ACTIVATE 0x00020000 +#define AW_SLIDE 0x00040000 +#define AW_BLEND 0x00080000 + +#define KF_EXTENDED 0x0100 +#define KF_DLGMODE 0x0800 +#define KF_MENUMODE 0x1000 +#define KF_ALTDOWN 0x2000 +#define KF_REPEAT 0x4000 +#define KF_UP 0x8000 + +#ifndef NOVIRTUALKEYCODES + +#define VK_LBUTTON 0x01 +#define VK_RBUTTON 0x02 +#define VK_CANCEL 0x03 +#define VK_MBUTTON 0x04 +#define VK_XBUTTON1 0x05 +#define VK_XBUTTON2 0x06 +#define VK_BACK 0x08 +#define VK_TAB 0x09 +#define VK_CLEAR 0x0C +#define VK_RETURN 0x0D +#define VK_SHIFT 0x10 +#define VK_CONTROL 0x11 +#define VK_MENU 0x12 +#define VK_PAUSE 0x13 +#define VK_CAPITAL 0x14 +#define VK_KANA 0x15 +#define VK_HANGEUL 0x15 +#define VK_HANGUL 0x15 +#define VK_JUNJA 0x17 +#define VK_FINAL 0x18 +#define VK_HANJA 0x19 +#define VK_KANJI 0x19 +#define VK_ESCAPE 0x1B +#define VK_CONVERT 0x1C +#define VK_NONCONVERT 0x1D +#define VK_ACCEPT 0x1E +#define VK_MODECHANGE 0x1F +#define VK_SPACE 0x20 +#define VK_PRIOR 0x21 +#define VK_NEXT 0x22 +#define VK_END 0x23 +#define VK_HOME 0x24 +#define VK_LEFT 0x25 +#define VK_UP 0x26 +#define VK_RIGHT 0x27 +#define VK_DOWN 0x28 +#define VK_SELECT 0x29 +#define VK_PRINT 0x2A +#define VK_EXECUTE 0x2B +#define VK_SNAPSHOT 0x2C +#define VK_INSERT 0x2D +#define VK_DELETE 0x2E +#define VK_HELP 0x2F + +#define VK_LWIN 0x5B +#define VK_RWIN 0x5C +#define VK_APPS 0x5D +#define VK_SLEEP 0x5F +#define VK_NUMPAD0 0x60 +#define VK_NUMPAD1 0x61 +#define VK_NUMPAD2 0x62 +#define VK_NUMPAD3 0x63 +#define VK_NUMPAD4 0x64 +#define VK_NUMPAD5 0x65 +#define VK_NUMPAD6 0x66 +#define VK_NUMPAD7 0x67 +#define VK_NUMPAD8 0x68 +#define VK_NUMPAD9 0x69 +#define VK_MULTIPLY 0x6A +#define VK_ADD 0x6B +#define VK_SEPARATOR 0x6C +#define VK_SUBTRACT 0x6D +#define VK_DECIMAL 0x6E +#define VK_DIVIDE 0x6F +#define VK_F1 0x70 +#define VK_F2 0x71 +#define VK_F3 0x72 +#define VK_F4 0x73 +#define VK_F5 0x74 +#define VK_F6 0x75 +#define VK_F7 0x76 +#define VK_F8 0x77 +#define VK_F9 0x78 +#define VK_F10 0x79 +#define VK_F11 0x7A +#define VK_F12 0x7B +#define VK_F13 0x7C +#define VK_F14 0x7D +#define VK_F15 0x7E +#define VK_F16 0x7F +#define VK_F17 0x80 +#define VK_F18 0x81 +#define VK_F19 0x82 +#define VK_F20 0x83 +#define VK_F21 0x84 +#define VK_F22 0x85 +#define VK_F23 0x86 +#define VK_F24 0x87 +#define VK_NUMLOCK 0x90 +#define VK_SCROLL 0x91 +#define VK_OEM_NEC_EQUAL 0x92 +#define VK_OEM_FJ_JISHO 0x92 +#define VK_OEM_FJ_MASSHOU 0x93 +#define VK_OEM_FJ_TOUROKU 0x94 +#define VK_OEM_FJ_LOYA 0x95 +#define VK_OEM_FJ_ROYA 0x96 +#define VK_LSHIFT 0xA0 +#define VK_RSHIFT 0xA1 +#define VK_LCONTROL 0xA2 +#define VK_RCONTROL 0xA3 +#define VK_LMENU 0xA4 +#define VK_RMENU 0xA5 +#define VK_BROWSER_BACK 0xA6 +#define VK_BROWSER_FORWARD 0xA7 +#define VK_BROWSER_REFRESH 0xA8 +#define VK_BROWSER_STOP 0xA9 +#define VK_BROWSER_SEARCH 0xAA +#define VK_BROWSER_FAVORITES 0xAB +#define VK_BROWSER_HOME 0xAC +#define VK_VOLUME_MUTE 0xAD +#define VK_VOLUME_DOWN 0xAE +#define VK_VOLUME_UP 0xAF +#define VK_MEDIA_NEXT_TRACK 0xB0 +#define VK_MEDIA_PREV_TRACK 0xB1 +#define VK_MEDIA_STOP 0xB2 +#define VK_MEDIA_PLAY_PAUSE 0xB3 +#define VK_LAUNCH_MAIL 0xB4 +#define VK_LAUNCH_MEDIA_SELECT 0xB5 +#define VK_LAUNCH_APP1 0xB6 +#define VK_LAUNCH_APP2 0xB7 +#define VK_OEM_1 0xBA +#define VK_OEM_PLUS 0xBB +#define VK_OEM_COMMA 0xBC +#define VK_OEM_MINUS 0xBD +#define VK_OEM_PERIOD 0xBE +#define VK_OEM_2 0xBF +#define VK_OEM_3 0xC0 +#define VK_OEM_4 0xDB +#define VK_OEM_5 0xDC +#define VK_OEM_6 0xDD +#define VK_OEM_7 0xDE +#define VK_OEM_8 0xDF +#define VK_OEM_AX 0xE1 +#define VK_OEM_102 0xE2 +#define VK_ICO_HELP 0xE3 +#define VK_ICO_00 0xE4 +#define VK_PROCESSKEY 0xE5 +#define VK_ICO_CLEAR 0xE6 +#define VK_PACKET 0xE7 +#define VK_OEM_RESET 0xE9 +#define VK_OEM_JUMP 0xEA +#define VK_OEM_PA1 0xEB +#define VK_OEM_PA2 0xEC +#define VK_OEM_PA3 0xED +#define VK_OEM_WSCTRL 0xEE +#define VK_OEM_CUSEL 0xEF +#define VK_OEM_ATTN 0xF0 +#define VK_OEM_FINISH 0xF1 +#define VK_OEM_COPY 0xF2 +#define VK_OEM_AUTO 0xF3 +#define VK_OEM_ENLW 0xF4 +#define VK_OEM_BACKTAB 0xF5 +#define VK_ATTN 0xF6 +#define VK_CRSEL 0xF7 +#define VK_EXSEL 0xF8 +#define VK_EREOF 0xF9 +#define VK_PLAY 0xFA +#define VK_ZOOM 0xFB +#define VK_NONAME 0xFC +#define VK_PA1 0xFD +#define VK_OEM_CLEAR 0xFE +#endif + +#ifndef NOWH + +#define WH_MIN (-1) +#define WH_MSGFILTER (-1) +#define WH_JOURNALRECORD 0 +#define WH_JOURNALPLAYBACK 1 +#define WH_KEYBOARD 2 +#define WH_GETMESSAGE 3 +#define WH_CALLWNDPROC 4 +#define WH_CBT 5 +#define WH_SYSMSGFILTER 6 +#define WH_MOUSE 7 +#define WH_HARDWARE 8 +#define WH_DEBUG 9 +#define WH_SHELL 10 +#define WH_FOREGROUNDIDLE 11 +#define WH_CALLWNDPROCRET 12 + +#define WH_KEYBOARD_LL 13 +#define WH_MOUSE_LL 14 + +#define WH_MAX 14 + +#define WH_MINHOOK WH_MIN +#define WH_MAXHOOK WH_MAX + +#define HC_ACTION 0 +#define HC_GETNEXT 1 +#define HC_SKIP 2 +#define HC_NOREMOVE 3 +#define HC_NOREM HC_NOREMOVE +#define HC_SYSMODALON 4 +#define HC_SYSMODALOFF 5 + +#define HCBT_MOVESIZE 0 +#define HCBT_MINMAX 1 +#define HCBT_QS 2 +#define HCBT_CREATEWND 3 +#define HCBT_DESTROYWND 4 +#define HCBT_ACTIVATE 5 +#define HCBT_CLICKSKIPPED 6 +#define HCBT_KEYSKIPPED 7 +#define HCBT_SYSCOMMAND 8 +#define HCBT_SETFOCUS 9 + + typedef struct tagCBT_CREATEWNDA { + struct tagCREATESTRUCTA *lpcs; + HWND hwndInsertAfter; + } CBT_CREATEWNDA,*LPCBT_CREATEWNDA; + + typedef struct tagCBT_CREATEWNDW { + struct tagCREATESTRUCTW *lpcs; + HWND hwndInsertAfter; + } CBT_CREATEWNDW,*LPCBT_CREATEWNDW; +#ifdef UNICODE + typedef CBT_CREATEWNDW CBT_CREATEWND; + typedef LPCBT_CREATEWNDW LPCBT_CREATEWND; +#else + typedef CBT_CREATEWNDA CBT_CREATEWND; + typedef LPCBT_CREATEWNDA LPCBT_CREATEWND; +#endif + + typedef struct tagCBTACTIVATESTRUCT + { + WINBOOL fMouse; + HWND hWndActive; + } CBTACTIVATESTRUCT,*LPCBTACTIVATESTRUCT; + + typedef struct tagWTSSESSION_NOTIFICATION { + DWORD cbSize; + DWORD dwSessionId; + + } WTSSESSION_NOTIFICATION,*PWTSSESSION_NOTIFICATION; + +#define WTS_CONSOLE_CONNECT 0x1 +#define WTS_CONSOLE_DISCONNECT 0x2 +#define WTS_REMOTE_CONNECT 0x3 +#define WTS_REMOTE_DISCONNECT 0x4 +#define WTS_SESSION_LOGON 0x5 +#define WTS_SESSION_LOGOFF 0x6 +#define WTS_SESSION_LOCK 0x7 +#define WTS_SESSION_UNLOCK 0x8 +#define WTS_SESSION_REMOTE_CONTROL 0x9 + +#define MSGF_DIALOGBOX 0 +#define MSGF_MESSAGEBOX 1 +#define MSGF_MENU 2 +#define MSGF_SCROLLBAR 5 +#define MSGF_NEXTWINDOW 6 +#define MSGF_MAX 8 +#define MSGF_USER 4096 + +#define HSHELL_WINDOWCREATED 1 +#define HSHELL_WINDOWDESTROYED 2 +#define HSHELL_ACTIVATESHELLWINDOW 3 + +#define HSHELL_WINDOWACTIVATED 4 +#define HSHELL_GETMINRECT 5 +#define HSHELL_REDRAW 6 +#define HSHELL_TASKMAN 7 +#define HSHELL_LANGUAGE 8 +#define HSHELL_SYSMENU 9 +#define HSHELL_ENDTASK 10 +#define HSHELL_ACCESSIBILITYSTATE 11 +#define HSHELL_APPCOMMAND 12 +#define HSHELL_WINDOWREPLACED 13 +#define HSHELL_WINDOWREPLACING 14 +#define HSHELL_HIGHBIT 0x8000 +#define HSHELL_FLASH (HSHELL_REDRAW|HSHELL_HIGHBIT) +#define HSHELL_RUDEAPPACTIVATED (HSHELL_WINDOWACTIVATED|HSHELL_HIGHBIT) + +#define ACCESS_STICKYKEYS 0x0001 +#define ACCESS_FILTERKEYS 0x0002 +#define ACCESS_MOUSEKEYS 0x0003 + +#define APPCOMMAND_BROWSER_BACKWARD 1 +#define APPCOMMAND_BROWSER_FORWARD 2 +#define APPCOMMAND_BROWSER_REFRESH 3 +#define APPCOMMAND_BROWSER_STOP 4 +#define APPCOMMAND_BROWSER_SEARCH 5 +#define APPCOMMAND_BROWSER_FAVORITES 6 +#define APPCOMMAND_BROWSER_HOME 7 +#define APPCOMMAND_VOLUME_MUTE 8 +#define APPCOMMAND_VOLUME_DOWN 9 +#define APPCOMMAND_VOLUME_UP 10 +#define APPCOMMAND_MEDIA_NEXTTRACK 11 +#define APPCOMMAND_MEDIA_PREVIOUSTRACK 12 +#define APPCOMMAND_MEDIA_STOP 13 +#define APPCOMMAND_MEDIA_PLAY_PAUSE 14 +#define APPCOMMAND_LAUNCH_MAIL 15 +#define APPCOMMAND_LAUNCH_MEDIA_SELECT 16 +#define APPCOMMAND_LAUNCH_APP1 17 +#define APPCOMMAND_LAUNCH_APP2 18 +#define APPCOMMAND_BASS_DOWN 19 +#define APPCOMMAND_BASS_BOOST 20 +#define APPCOMMAND_BASS_UP 21 +#define APPCOMMAND_TREBLE_DOWN 22 +#define APPCOMMAND_TREBLE_UP 23 +#define APPCOMMAND_MICROPHONE_VOLUME_MUTE 24 +#define APPCOMMAND_MICROPHONE_VOLUME_DOWN 25 +#define APPCOMMAND_MICROPHONE_VOLUME_UP 26 +#define APPCOMMAND_HELP 27 +#define APPCOMMAND_FIND 28 +#define APPCOMMAND_NEW 29 +#define APPCOMMAND_OPEN 30 +#define APPCOMMAND_CLOSE 31 +#define APPCOMMAND_SAVE 32 +#define APPCOMMAND_PRINT 33 +#define APPCOMMAND_UNDO 34 +#define APPCOMMAND_REDO 35 +#define APPCOMMAND_COPY 36 +#define APPCOMMAND_CUT 37 +#define APPCOMMAND_PASTE 38 +#define APPCOMMAND_REPLY_TO_MAIL 39 +#define APPCOMMAND_FORWARD_MAIL 40 +#define APPCOMMAND_SEND_MAIL 41 +#define APPCOMMAND_SPELL_CHECK 42 +#define APPCOMMAND_DICTATE_OR_COMMAND_CONTROL_TOGGLE 43 +#define APPCOMMAND_MIC_ON_OFF_TOGGLE 44 +#define APPCOMMAND_CORRECTION_LIST 45 +#define APPCOMMAND_MEDIA_PLAY 46 +#define APPCOMMAND_MEDIA_PAUSE 47 +#define APPCOMMAND_MEDIA_RECORD 48 +#define APPCOMMAND_MEDIA_FAST_FORWARD 49 +#define APPCOMMAND_MEDIA_REWIND 50 +#define APPCOMMAND_MEDIA_CHANNEL_UP 51 +#define APPCOMMAND_MEDIA_CHANNEL_DOWN 52 + +#define FAPPCOMMAND_MOUSE 0x8000 +#define FAPPCOMMAND_KEY 0 +#define FAPPCOMMAND_OEM 0x1000 +#define FAPPCOMMAND_MASK 0xF000 + +#define GET_APPCOMMAND_LPARAM(lParam) ((short)(HIWORD(lParam) & ~FAPPCOMMAND_MASK)) +#define GET_DEVICE_LPARAM(lParam) ((WORD)(HIWORD(lParam) & FAPPCOMMAND_MASK)) +#define GET_MOUSEORKEY_LPARAM GET_DEVICE_LPARAM +#define GET_FLAGS_LPARAM(lParam) (LOWORD(lParam)) +#define GET_KEYSTATE_LPARAM(lParam) GET_FLAGS_LPARAM(lParam) + + typedef struct { + HWND hwnd; + RECT rc; + } SHELLHOOKINFO,*LPSHELLHOOKINFO; + + typedef struct tagEVENTMSG { + UINT message; + UINT paramL; + UINT paramH; + DWORD time; + HWND hwnd; + } EVENTMSG,*PEVENTMSGMSG,*NPEVENTMSGMSG,*LPEVENTMSGMSG; + + typedef struct tagEVENTMSG *PEVENTMSG,*NPEVENTMSG,*LPEVENTMSG; + + typedef struct tagCWPSTRUCT { + LPARAM lParam; + WPARAM wParam; + UINT message; + HWND hwnd; + } CWPSTRUCT,*PCWPSTRUCT,*NPCWPSTRUCT,*LPCWPSTRUCT; + + typedef struct tagCWPRETSTRUCT { + LRESULT lResult; + LPARAM lParam; + WPARAM wParam; + UINT message; + HWND hwnd; + } CWPRETSTRUCT,*PCWPRETSTRUCT,*NPCWPRETSTRUCT,*LPCWPRETSTRUCT; + +#define LLKHF_EXTENDED (KF_EXTENDED >> 8) +#define LLKHF_INJECTED 0x00000010 +#define LLKHF_ALTDOWN (KF_ALTDOWN >> 8) +#define LLKHF_UP (KF_UP >> 8) + +#define LLMHF_INJECTED 0x00000001 + + typedef struct tagKBDLLHOOKSTRUCT { + DWORD vkCode; + DWORD scanCode; + DWORD flags; + DWORD time; + ULONG_PTR dwExtraInfo; + } KBDLLHOOKSTRUCT,*LPKBDLLHOOKSTRUCT,*PKBDLLHOOKSTRUCT; + + typedef struct tagMSLLHOOKSTRUCT { + POINT pt; + DWORD mouseData; + DWORD flags; + DWORD time; + ULONG_PTR dwExtraInfo; + } MSLLHOOKSTRUCT,*LPMSLLHOOKSTRUCT,*PMSLLHOOKSTRUCT; + + typedef struct tagDEBUGHOOKINFO { + DWORD idThread; + DWORD idThreadInstaller; + LPARAM lParam; + WPARAM wParam; + int code; + } DEBUGHOOKINFO,*PDEBUGHOOKINFO,*NPDEBUGHOOKINFO,*LPDEBUGHOOKINFO; + + typedef struct tagMOUSEHOOKSTRUCT { + POINT pt; + HWND hwnd; + UINT wHitTestCode; + ULONG_PTR dwExtraInfo; + } MOUSEHOOKSTRUCT,*LPMOUSEHOOKSTRUCT,*PMOUSEHOOKSTRUCT; + +#ifdef __cplusplus + typedef struct tagMOUSEHOOKSTRUCTEX : public tagMOUSEHOOKSTRUCT { + DWORD mouseData; + } MOUSEHOOKSTRUCTEX,*LPMOUSEHOOKSTRUCTEX,*PMOUSEHOOKSTRUCTEX; +#else + typedef struct tagMOUSEHOOKSTRUCTEX { + MOUSEHOOKSTRUCT _unnamed; + DWORD mouseData; + } MOUSEHOOKSTRUCTEX,*LPMOUSEHOOKSTRUCTEX,*PMOUSEHOOKSTRUCTEX; +#endif + + typedef struct tagHARDWAREHOOKSTRUCT { + HWND hwnd; + UINT message; + WPARAM wParam; + LPARAM lParam; + } HARDWAREHOOKSTRUCT,*LPHARDWAREHOOKSTRUCT,*PHARDWAREHOOKSTRUCT; +#endif + +#define HKL_PREV 0 +#define HKL_NEXT 1 + +#define KLF_ACTIVATE 0x00000001 +#define KLF_SUBSTITUTE_OK 0x00000002 +#define KLF_REORDER 0x00000008 +#define KLF_REPLACELANG 0x00000010 +#define KLF_NOTELLSHELL 0x00000080 +#define KLF_SETFORPROCESS 0x00000100 +#define KLF_SHIFTLOCK 0x00010000 +#define KLF_RESET 0x40000000 + +#define INPUTLANGCHANGE_SYSCHARSET 0x0001 +#define INPUTLANGCHANGE_FORWARD 0x0002 +#define INPUTLANGCHANGE_BACKWARD 0x0004 + +#define KL_NAMELENGTH 9 + +#ifdef UNICODE +#define LoadKeyboardLayout LoadKeyboardLayoutW +#define GetKeyboardLayoutName GetKeyboardLayoutNameW +#else +#define LoadKeyboardLayout LoadKeyboardLayoutA +#define GetKeyboardLayoutName GetKeyboardLayoutNameA +#endif + + WINUSERAPI HKL WINAPI LoadKeyboardLayoutA(LPCSTR pwszKLID,UINT Flags); + WINUSERAPI HKL WINAPI LoadKeyboardLayoutW(LPCWSTR pwszKLID,UINT Flags); + WINUSERAPI HKL WINAPI ActivateKeyboardLayout(HKL hkl,UINT Flags); + WINUSERAPI int WINAPI ToUnicodeEx(UINT wVirtKey,UINT wScanCode,CONST BYTE *lpKeyState,LPWSTR pwszBuff,int cchBuff,UINT wFlags,HKL dwhkl); + WINUSERAPI WINBOOL WINAPI UnloadKeyboardLayout(HKL hkl); + WINUSERAPI WINBOOL WINAPI GetKeyboardLayoutNameA(LPSTR pwszKLID); + WINUSERAPI WINBOOL WINAPI GetKeyboardLayoutNameW(LPWSTR pwszKLID); + WINUSERAPI int WINAPI GetKeyboardLayoutList(int nBuff,HKL *lpList); + WINUSERAPI HKL WINAPI GetKeyboardLayout(DWORD idThread); + + typedef struct tagMOUSEMOVEPOINT { + int x; + int y; + DWORD time; + ULONG_PTR dwExtraInfo; + } MOUSEMOVEPOINT,*PMOUSEMOVEPOINT,*LPMOUSEMOVEPOINT; + +#define GMMP_USE_DISPLAY_POINTS 1 +#define GMMP_USE_HIGH_RESOLUTION_POINTS 2 + + WINUSERAPI int WINAPI GetMouseMovePointsEx(UINT cbSize,LPMOUSEMOVEPOINT lppt,LPMOUSEMOVEPOINT lpptBuf,int nBufPoints,DWORD resolution); + +#ifndef NODESKTOP + +#define DESKTOP_READOBJECTS 0x0001L +#define DESKTOP_CREATEWINDOW 0x0002L +#define DESKTOP_CREATEMENU 0x0004L +#define DESKTOP_HOOKCONTROL 0x0008L +#define DESKTOP_JOURNALRECORD 0x0010L +#define DESKTOP_JOURNALPLAYBACK 0x0020L +#define DESKTOP_ENUMERATE 0x0040L +#define DESKTOP_WRITEOBJECTS 0x0080L +#define DESKTOP_SWITCHDESKTOP 0x0100L + +#define DF_ALLOWOTHERACCOUNTHOOK 0x0001L + +#ifdef _WINGDI_ +#ifndef NOGDI +#ifdef UNICODE +#define CreateDesktop CreateDesktopW +#else +#define CreateDesktop CreateDesktopA +#endif + + WINUSERAPI HDESK WINAPI CreateDesktopA(LPCSTR lpszDesktop,LPCSTR lpszDevice,LPDEVMODEA pDevmode,DWORD dwFlags,ACCESS_MASK dwDesiredAccess,LPSECURITY_ATTRIBUTES lpsa); + WINUSERAPI HDESK WINAPI CreateDesktopW(LPCWSTR lpszDesktop,LPCWSTR lpszDevice,LPDEVMODEW pDevmode,DWORD dwFlags,ACCESS_MASK dwDesiredAccess,LPSECURITY_ATTRIBUTES lpsa); +#endif +#endif + +#ifdef UNICODE +#define OpenDesktop OpenDesktopW +#define EnumDesktops EnumDesktopsW +#else +#define OpenDesktop OpenDesktopA +#define EnumDesktops EnumDesktopsA +#endif + + WINUSERAPI HDESK WINAPI OpenDesktopA(LPCSTR lpszDesktop,DWORD dwFlags,WINBOOL fInherit,ACCESS_MASK dwDesiredAccess); + WINUSERAPI HDESK WINAPI OpenDesktopW(LPCWSTR lpszDesktop,DWORD dwFlags,WINBOOL fInherit,ACCESS_MASK dwDesiredAccess); + WINUSERAPI HDESK WINAPI OpenInputDesktop(DWORD dwFlags,WINBOOL fInherit,ACCESS_MASK dwDesiredAccess); + WINUSERAPI WINBOOL WINAPI EnumDesktopsA(HWINSTA hwinsta,DESKTOPENUMPROCA lpEnumFunc,LPARAM lParam); + WINUSERAPI WINBOOL WINAPI EnumDesktopsW(HWINSTA hwinsta,DESKTOPENUMPROCW lpEnumFunc,LPARAM lParam); + WINUSERAPI WINBOOL WINAPI EnumDesktopWindows(HDESK hDesktop,WNDENUMPROC lpfn,LPARAM lParam); + WINUSERAPI WINBOOL WINAPI SwitchDesktop(HDESK hDesktop); + WINUSERAPI WINBOOL WINAPI SetThreadDesktop(HDESK hDesktop); + WINUSERAPI WINBOOL WINAPI CloseDesktop(HDESK hDesktop); + WINUSERAPI HDESK WINAPI GetThreadDesktop(DWORD dwThreadId); +#endif + +#ifndef NOWINDOWSTATION +#define WINSTA_ENUMDESKTOPS 0x0001L +#define WINSTA_READATTRIBUTES 0x0002L +#define WINSTA_ACCESSCLIPBOARD 0x0004L +#define WINSTA_CREATEDESKTOP 0x0008L +#define WINSTA_WRITEATTRIBUTES 0x0010L +#define WINSTA_ACCESSGLOBALATOMS 0x0020L +#define WINSTA_EXITWINDOWS 0x0040L +#define WINSTA_ENUMERATE 0x0100L +#define WINSTA_READSCREEN 0x0200L +#define WINSTA_ALL_ACCESS (WINSTA_ENUMDESKTOPS | WINSTA_READATTRIBUTES | WINSTA_ACCESSCLIPBOARD | WINSTA_CREATEDESKTOP | WINSTA_WRITEATTRIBUTES | WINSTA_ACCESSGLOBALATOMS | WINSTA_EXITWINDOWS | WINSTA_ENUMERATE | WINSTA_READSCREEN) + +#define CWF_CREATE_ONLY 0x0001L + +#define WSF_VISIBLE 0x0001L + +#ifdef UNICODE +#define CreateWindowStation CreateWindowStationW +#define OpenWindowStation OpenWindowStationW +#define EnumWindowStations EnumWindowStationsW +#else +#define CreateWindowStation CreateWindowStationA +#define OpenWindowStation OpenWindowStationA +#define EnumWindowStations EnumWindowStationsA +#endif + + WINUSERAPI HWINSTA WINAPI CreateWindowStationA(LPCSTR lpwinsta,DWORD dwFlags,ACCESS_MASK dwDesiredAccess,LPSECURITY_ATTRIBUTES lpsa); + WINUSERAPI HWINSTA WINAPI CreateWindowStationW(LPCWSTR lpwinsta,DWORD dwFlags,ACCESS_MASK dwDesiredAccess,LPSECURITY_ATTRIBUTES lpsa); + WINUSERAPI HWINSTA WINAPI OpenWindowStationA(LPCSTR lpszWinSta,WINBOOL fInherit,ACCESS_MASK dwDesiredAccess); + WINUSERAPI HWINSTA WINAPI OpenWindowStationW(LPCWSTR lpszWinSta,WINBOOL fInherit,ACCESS_MASK dwDesiredAccess); + WINUSERAPI WINBOOL WINAPI EnumWindowStationsA(WINSTAENUMPROCA lpEnumFunc,LPARAM lParam); + WINUSERAPI WINBOOL WINAPI EnumWindowStationsW(WINSTAENUMPROCW lpEnumFunc,LPARAM lParam); + WINUSERAPI WINBOOL WINAPI CloseWindowStation(HWINSTA hWinSta); + WINUSERAPI WINBOOL WINAPI SetProcessWindowStation(HWINSTA hWinSta); + WINUSERAPI HWINSTA WINAPI GetProcessWindowStation(VOID); +#endif + +#ifndef NOSECURITY + WINUSERAPI WINBOOL WINAPI SetUserObjectSecurity(HANDLE hObj,PSECURITY_INFORMATION pSIRequested,PSECURITY_DESCRIPTOR pSID); + WINUSERAPI WINBOOL WINAPI GetUserObjectSecurity(HANDLE hObj,PSECURITY_INFORMATION pSIRequested,PSECURITY_DESCRIPTOR pSID,DWORD nLength,LPDWORD lpnLengthNeeded); + +#define UOI_FLAGS 1 +#define UOI_NAME 2 +#define UOI_TYPE 3 +#define UOI_USER_SID 4 + + typedef struct tagUSEROBJECTFLAGS { + WINBOOL fInherit; + WINBOOL fReserved; + DWORD dwFlags; + } USEROBJECTFLAGS,*PUSEROBJECTFLAGS; + +#ifdef UNICODE +#define GetUserObjectInformation GetUserObjectInformationW +#define SetUserObjectInformation SetUserObjectInformationW +#else +#define GetUserObjectInformation GetUserObjectInformationA +#define SetUserObjectInformation SetUserObjectInformationA +#endif + + WINUSERAPI WINBOOL WINAPI GetUserObjectInformationA(HANDLE hObj,int nIndex,PVOID pvInfo,DWORD nLength,LPDWORD lpnLengthNeeded); + WINUSERAPI WINBOOL WINAPI GetUserObjectInformationW(HANDLE hObj,int nIndex,PVOID pvInfo,DWORD nLength,LPDWORD lpnLengthNeeded); + WINUSERAPI WINBOOL WINAPI SetUserObjectInformationA(HANDLE hObj,int nIndex,PVOID pvInfo,DWORD nLength); + WINUSERAPI WINBOOL WINAPI SetUserObjectInformationW(HANDLE hObj,int nIndex,PVOID pvInfo,DWORD nLength); +#endif + + typedef struct tagWNDCLASSEXA { + UINT cbSize; + UINT style; + WNDPROC lpfnWndProc; + int cbClsExtra; + int cbWndExtra; + HINSTANCE hInstance; + HICON hIcon; + HCURSOR hCursor; + HBRUSH hbrBackground; + LPCSTR lpszMenuName; + LPCSTR lpszClassName; + HICON hIconSm; + } WNDCLASSEXA,*PWNDCLASSEXA,*NPWNDCLASSEXA,*LPWNDCLASSEXA; + + typedef struct tagWNDCLASSEXW { + UINT cbSize; + UINT style; + WNDPROC lpfnWndProc; + int cbClsExtra; + int cbWndExtra; + HINSTANCE hInstance; + HICON hIcon; + HCURSOR hCursor; + HBRUSH hbrBackground; + LPCWSTR lpszMenuName; + LPCWSTR lpszClassName; + + HICON hIconSm; + } WNDCLASSEXW,*PWNDCLASSEXW,*NPWNDCLASSEXW,*LPWNDCLASSEXW; + +#ifdef UNICODE + typedef WNDCLASSEXW WNDCLASSEX; + typedef PWNDCLASSEXW PWNDCLASSEX; + typedef NPWNDCLASSEXW NPWNDCLASSEX; + typedef LPWNDCLASSEXW LPWNDCLASSEX; +#else + typedef WNDCLASSEXA WNDCLASSEX; + typedef PWNDCLASSEXA PWNDCLASSEX; + typedef NPWNDCLASSEXA NPWNDCLASSEX; + typedef LPWNDCLASSEXA LPWNDCLASSEX; +#endif + + typedef struct tagWNDCLASSA { + UINT style; + WNDPROC lpfnWndProc; + int cbClsExtra; + int cbWndExtra; + HINSTANCE hInstance; + HICON hIcon; + HCURSOR hCursor; + HBRUSH hbrBackground; + LPCSTR lpszMenuName; + LPCSTR lpszClassName; + } WNDCLASSA,*PWNDCLASSA,*NPWNDCLASSA,*LPWNDCLASSA; + + typedef struct tagWNDCLASSW { + UINT style; + WNDPROC lpfnWndProc; + int cbClsExtra; + int cbWndExtra; + HINSTANCE hInstance; + HICON hIcon; + HCURSOR hCursor; + HBRUSH hbrBackground; + LPCWSTR lpszMenuName; + LPCWSTR lpszClassName; + } WNDCLASSW,*PWNDCLASSW,*NPWNDCLASSW,*LPWNDCLASSW; + +#ifdef UNICODE + typedef WNDCLASSW WNDCLASS; + typedef PWNDCLASSW PWNDCLASS; + typedef NPWNDCLASSW NPWNDCLASS; + typedef LPWNDCLASSW LPWNDCLASS; +#else + typedef WNDCLASSA WNDCLASS; + typedef PWNDCLASSA PWNDCLASS; + typedef NPWNDCLASSA NPWNDCLASS; + typedef LPWNDCLASSA LPWNDCLASS; +#endif + + WINUSERAPI WINBOOL WINAPI IsHungAppWindow(HWND hwnd); + WINUSERAPI VOID WINAPI DisableProcessWindowsGhosting(VOID); + +#ifndef NOMSG + typedef struct tagMSG { + HWND hwnd; + UINT message; + WPARAM wParam; + LPARAM lParam; + DWORD time; + POINT pt; + } MSG,*PMSG,*NPMSG,*LPMSG; + +#define POINTSTOPOINT(pt,pts) { (pt).x = (LONG)(SHORT)LOWORD(*(LONG*)&pts); (pt).y = (LONG)(SHORT)HIWORD(*(LONG*)&pts); } + +#define POINTTOPOINTS(pt) (MAKELONG((short)((pt).x),(short)((pt).y))) +#define MAKEWPARAM(l,h) ((WPARAM)(DWORD)MAKELONG(l,h)) +#define MAKELPARAM(l,h) ((LPARAM)(DWORD)MAKELONG(l,h)) +#define MAKELRESULT(l,h) ((LRESULT)(DWORD)MAKELONG(l,h)) +#endif + +#ifndef NOWINOFFSETS +#define GWL_WNDPROC (-4) +#define GWL_HINSTANCE (-6) +#define GWL_HWNDPARENT (-8) +#define GWL_STYLE (-16) +#define GWL_EXSTYLE (-20) +#define GWL_USERDATA (-21) +#define GWL_ID (-12) + +#ifdef _WIN64 +#undef GWL_WNDPROC +#undef GWL_HINSTANCE +#undef GWL_HWNDPARENT +#undef GWL_USERDATA +#endif + +#define GWLP_WNDPROC (-4) +#define GWLP_HINSTANCE (-6) +#define GWLP_HWNDPARENT (-8) +#define GWLP_USERDATA (-21) +#define GWLP_ID (-12) + +#define GCL_MENUNAME (-8) +#define GCL_HBRBACKGROUND (-10) +#define GCL_HCURSOR (-12) +#define GCL_HICON (-14) +#define GCL_HMODULE (-16) +#define GCL_CBWNDEXTRA (-18) +#define GCL_CBCLSEXTRA (-20) +#define GCL_WNDPROC (-24) +#define GCL_STYLE (-26) +#define GCW_ATOM (-32) +#define GCL_HICONSM (-34) + +#ifdef _WIN64 + +#undef GCL_MENUNAME +#undef GCL_HBRBACKGROUND +#undef GCL_HCURSOR +#undef GCL_HICON +#undef GCL_HMODULE +#undef GCL_WNDPROC +#undef GCL_HICONSM +#endif + +#define GCLP_MENUNAME (-8) +#define GCLP_HBRBACKGROUND (-10) +#define GCLP_HCURSOR (-12) +#define GCLP_HICON (-14) +#define GCLP_HMODULE (-16) +#define GCLP_WNDPROC (-24) +#define GCLP_HICONSM (-34) +#endif + +#ifndef NOWINMESSAGES + +#define WM_NULL 0x0000 +#define WM_CREATE 0x0001 +#define WM_DESTROY 0x0002 +#define WM_MOVE 0x0003 +#define WM_SIZE 0x0005 + +#define WM_ACTIVATE 0x0006 + +#define WA_INACTIVE 0 +#define WA_ACTIVE 1 +#define WA_CLICKACTIVE 2 + +#define WM_SETFOCUS 0x0007 +#define WM_KILLFOCUS 0x0008 +#define WM_ENABLE 0x000A +#define WM_SETREDRAW 0x000B +#define WM_SETTEXT 0x000C +#define WM_GETTEXT 0x000D +#define WM_GETTEXTLENGTH 0x000E +#define WM_PAINT 0x000F +#define WM_CLOSE 0x0010 +#ifndef _WIN32_WCE +#define WM_QUERYENDSESSION 0x0011 +#define WM_QUERYOPEN 0x0013 +#define WM_ENDSESSION 0x0016 +#endif +#define WM_QUIT 0x0012 +#define WM_ERASEBKGND 0x0014 +#define WM_SYSCOLORCHANGE 0x0015 +#define WM_SHOWWINDOW 0x0018 +#define WM_WININICHANGE 0x001A +#define WM_SETTINGCHANGE WM_WININICHANGE +#define WM_DEVMODECHANGE 0x001B +#define WM_ACTIVATEAPP 0x001C +#define WM_FONTCHANGE 0x001D +#define WM_TIMECHANGE 0x001E +#define WM_CANCELMODE 0x001F +#define WM_SETCURSOR 0x0020 +#define WM_MOUSEACTIVATE 0x0021 +#define WM_CHILDACTIVATE 0x0022 +#define WM_QUEUESYNC 0x0023 + +#define WM_GETMINMAXINFO 0x0024 + + typedef struct tagMINMAXINFO { + POINT ptReserved; + POINT ptMaxSize; + POINT ptMaxPosition; + POINT ptMinTrackSize; + POINT ptMaxTrackSize; + } MINMAXINFO,*PMINMAXINFO,*LPMINMAXINFO; + +#define WM_PAINTICON 0x0026 +#define WM_ICONERASEBKGND 0x0027 +#define WM_NEXTDLGCTL 0x0028 +#define WM_SPOOLERSTATUS 0x002A +#define WM_DRAWITEM 0x002B +#define WM_MEASUREITEM 0x002C +#define WM_DELETEITEM 0x002D +#define WM_VKEYTOITEM 0x002E +#define WM_CHARTOITEM 0x002F +#define WM_SETFONT 0x0030 +#define WM_GETFONT 0x0031 +#define WM_SETHOTKEY 0x0032 +#define WM_GETHOTKEY 0x0033 +#define WM_QUERYDRAGICON 0x0037 +#define WM_COMPAREITEM 0x0039 +#ifndef _WIN32_WCE +#define WM_GETOBJECT 0x003D +#endif +#define WM_COMPACTING 0x0041 +#define WM_COMMNOTIFY 0x0044 +#define WM_WINDOWPOSCHANGING 0x0046 +#define WM_WINDOWPOSCHANGED 0x0047 + +#define WM_POWER 0x0048 + +#define PWR_OK 1 +#define PWR_FAIL (-1) +#define PWR_SUSPENDREQUEST 1 +#define PWR_SUSPENDRESUME 2 +#define PWR_CRITICALRESUME 3 + +#define WM_COPYDATA 0x004A +#define WM_CANCELJOURNAL 0x004B + + typedef struct tagCOPYDATASTRUCT { + ULONG_PTR dwData; + DWORD cbData; + PVOID lpData; + } COPYDATASTRUCT,*PCOPYDATASTRUCT; + + typedef struct tagMDINEXTMENU { + HMENU hmenuIn; + HMENU hmenuNext; + HWND hwndNext; + } MDINEXTMENU,*PMDINEXTMENU,*LPMDINEXTMENU; + +#define WM_NOTIFY 0x004E +#define WM_INPUTLANGCHANGEREQUEST 0x0050 +#define WM_INPUTLANGCHANGE 0x0051 +#define WM_TCARD 0x0052 +#define WM_HELP 0x0053 +#define WM_USERCHANGED 0x0054 +#define WM_NOTIFYFORMAT 0x0055 + +#define NFR_ANSI 1 +#define NFR_UNICODE 2 +#define NF_QUERY 3 +#define NF_REQUERY 4 + +#define WM_CONTEXTMENU 0x007B +#define WM_STYLECHANGING 0x007C +#define WM_STYLECHANGED 0x007D +#define WM_DISPLAYCHANGE 0x007E +#define WM_GETICON 0x007F +#define WM_SETICON 0x0080 + +#define WM_NCCREATE 0x0081 +#define WM_NCDESTROY 0x0082 +#define WM_NCCALCSIZE 0x0083 +#define WM_NCHITTEST 0x0084 +#define WM_NCPAINT 0x0085 +#define WM_NCACTIVATE 0x0086 +#define WM_GETDLGCODE 0x0087 +#ifndef _WIN32_WCE +#define WM_SYNCPAINT 0x0088 +#endif +#define WM_NCMOUSEMOVE 0x00A0 +#define WM_NCLBUTTONDOWN 0x00A1 +#define WM_NCLBUTTONUP 0x00A2 +#define WM_NCLBUTTONDBLCLK 0x00A3 +#define WM_NCRBUTTONDOWN 0x00A4 +#define WM_NCRBUTTONUP 0x00A5 +#define WM_NCRBUTTONDBLCLK 0x00A6 +#define WM_NCMBUTTONDOWN 0x00A7 +#define WM_NCMBUTTONUP 0x00A8 +#define WM_NCMBUTTONDBLCLK 0x00A9 + +#define WM_NCXBUTTONDOWN 0x00AB +#define WM_NCXBUTTONUP 0x00AC +#define WM_NCXBUTTONDBLCLK 0x00AD +#define WM_INPUT 0x00FF +#define WM_KEYFIRST 0x0100 +#define WM_KEYDOWN 0x0100 +#define WM_KEYUP 0x0101 +#define WM_CHAR 0x0102 +#define WM_DEADCHAR 0x0103 +#define WM_SYSKEYDOWN 0x0104 +#define WM_SYSKEYUP 0x0105 +#define WM_SYSCHAR 0x0106 +#define WM_SYSDEADCHAR 0x0107 +#define WM_UNICHAR 0x0109 +#define WM_KEYLAST 0x0109 +#define UNICODE_NOCHAR 0xFFFF +#define WM_IME_STARTCOMPOSITION 0x010D +#define WM_IME_ENDCOMPOSITION 0x010E +#define WM_IME_COMPOSITION 0x010F +#define WM_IME_KEYLAST 0x010F +#define WM_INITDIALOG 0x0110 +#define WM_COMMAND 0x0111 +#define WM_SYSCOMMAND 0x0112 +#define WM_TIMER 0x0113 +#define WM_HSCROLL 0x0114 +#define WM_VSCROLL 0x0115 +#define WM_INITMENU 0x0116 +#define WM_INITMENUPOPUP 0x0117 +#define WM_MENUSELECT 0x011F +#define WM_MENUCHAR 0x0120 +#define WM_ENTERIDLE 0x0121 +#ifndef _WIN32_WCE +#define WM_MENURBUTTONUP 0x0122 +#define WM_MENUDRAG 0x0123 +#define WM_MENUGETOBJECT 0x0124 +#define WM_UNINITMENUPOPUP 0x0125 +#define WM_MENUCOMMAND 0x0126 + +#ifndef _WIN32_WCE +#define WM_CHANGEUISTATE 0x0127 +#define WM_UPDATEUISTATE 0x0128 +#define WM_QUERYUISTATE 0x0129 + +#define UIS_SET 1 +#define UIS_CLEAR 2 +#define UIS_INITIALIZE 3 + +#define UISF_HIDEFOCUS 0x1 +#define UISF_HIDEACCEL 0x2 +#define UISF_ACTIVE 0x4 +#endif +#endif + +#define WM_CTLCOLORMSGBOX 0x0132 +#define WM_CTLCOLOREDIT 0x0133 +#define WM_CTLCOLORLISTBOX 0x0134 +#define WM_CTLCOLORBTN 0x0135 +#define WM_CTLCOLORDLG 0x0136 +#define WM_CTLCOLORSCROLLBAR 0x0137 +#define WM_CTLCOLORSTATIC 0x0138 +#define MN_GETHMENU 0x01E1 + +#define WM_MOUSEFIRST 0x0200 +#define WM_MOUSEMOVE 0x0200 +#define WM_LBUTTONDOWN 0x0201 +#define WM_LBUTTONUP 0x0202 +#define WM_LBUTTONDBLCLK 0x0203 +#define WM_RBUTTONDOWN 0x0204 +#define WM_RBUTTONUP 0x0205 +#define WM_RBUTTONDBLCLK 0x0206 +#define WM_MBUTTONDOWN 0x0207 +#define WM_MBUTTONUP 0x0208 +#define WM_MBUTTONDBLCLK 0x0209 +#define WM_MOUSEWHEEL 0x020A +#define WM_XBUTTONDOWN 0x020B +#define WM_XBUTTONUP 0x020C +#define WM_XBUTTONDBLCLK 0x020D +#define WM_MOUSELAST 0x020D + +#define WHEEL_DELTA 120 +#define GET_WHEEL_DELTA_WPARAM(wParam) ((short)HIWORD(wParam)) + +#define WHEEL_PAGESCROLL (UINT_MAX) + +#define GET_KEYSTATE_WPARAM(wParam) (LOWORD(wParam)) +#define GET_NCHITTEST_WPARAM(wParam) ((short)LOWORD(wParam)) +#define GET_XBUTTON_WPARAM(wParam) (HIWORD(wParam)) + +#define XBUTTON1 0x0001 +#define XBUTTON2 0x0002 + +#define WM_PARENTNOTIFY 0x0210 +#define WM_ENTERMENULOOP 0x0211 +#define WM_EXITMENULOOP 0x0212 + +#define WM_NEXTMENU 0x0213 +#define WM_SIZING 0x0214 +#define WM_CAPTURECHANGED 0x0215 +#define WM_MOVING 0x0216 + +#define WM_POWERBROADCAST 0x0218 + +#ifndef _WIN32_WCE +#define PBT_APMQUERYSUSPEND 0x0000 +#define PBT_APMQUERYSTANDBY 0x0001 + +#define PBT_APMQUERYSUSPENDFAILED 0x0002 +#define PBT_APMQUERYSTANDBYFAILED 0x0003 + +#define PBT_APMSUSPEND 0x0004 +#define PBT_APMSTANDBY 0x0005 + +#define PBT_APMRESUMECRITICAL 0x0006 +#define PBT_APMRESUMESUSPEND 0x0007 +#define PBT_APMRESUMESTANDBY 0x0008 + +#define PBTF_APMRESUMEFROMFAILURE 0x00000001 + +#define PBT_APMBATTERYLOW 0x0009 +#define PBT_APMPOWERSTATUSCHANGE 0x000A + +#define PBT_APMOEMEVENT 0x000B +#define PBT_APMRESUMEAUTOMATIC 0x0012 +#endif + +#define WM_DEVICECHANGE 0x0219 + +#define WM_MDICREATE 0x0220 +#define WM_MDIDESTROY 0x0221 +#define WM_MDIACTIVATE 0x0222 +#define WM_MDIRESTORE 0x0223 +#define WM_MDINEXT 0x0224 +#define WM_MDIMAXIMIZE 0x0225 +#define WM_MDITILE 0x0226 +#define WM_MDICASCADE 0x0227 +#define WM_MDIICONARRANGE 0x0228 +#define WM_MDIGETACTIVE 0x0229 + +#define WM_MDISETMENU 0x0230 +#define WM_ENTERSIZEMOVE 0x0231 +#define WM_EXITSIZEMOVE 0x0232 +#define WM_DROPFILES 0x0233 +#define WM_MDIREFRESHMENU 0x0234 + +#define WM_IME_SETCONTEXT 0x0281 +#define WM_IME_NOTIFY 0x0282 +#define WM_IME_CONTROL 0x0283 +#define WM_IME_COMPOSITIONFULL 0x0284 +#define WM_IME_SELECT 0x0285 +#define WM_IME_CHAR 0x0286 +#define WM_IME_REQUEST 0x0288 +#define WM_IME_KEYDOWN 0x0290 +#define WM_IME_KEYUP 0x0291 + +#define WM_MOUSEHOVER 0x02A1 +#define WM_MOUSELEAVE 0x02A3 +#define WM_NCMOUSEHOVER 0x02A0 +#define WM_NCMOUSELEAVE 0x02A2 +#define WM_WTSSESSION_CHANGE 0x02B1 +#define WM_TABLET_FIRST 0x02c0 +#define WM_TABLET_LAST 0x02df +#define WM_CUT 0x0300 +#define WM_COPY 0x0301 +#define WM_PASTE 0x0302 +#define WM_CLEAR 0x0303 +#define WM_UNDO 0x0304 +#define WM_RENDERFORMAT 0x0305 +#define WM_RENDERALLFORMATS 0x0306 +#define WM_DESTROYCLIPBOARD 0x0307 +#define WM_DRAWCLIPBOARD 0x0308 +#define WM_PAINTCLIPBOARD 0x0309 +#define WM_VSCROLLCLIPBOARD 0x030A +#define WM_SIZECLIPBOARD 0x030B +#define WM_ASKCBFORMATNAME 0x030C +#define WM_CHANGECBCHAIN 0x030D +#define WM_HSCROLLCLIPBOARD 0x030E +#define WM_QUERYNEWPALETTE 0x030F +#define WM_PALETTEISCHANGING 0x0310 +#define WM_PALETTECHANGED 0x0311 +#define WM_HOTKEY 0x0312 +#define WM_PRINT 0x0317 +#define WM_PRINTCLIENT 0x0318 +#define WM_APPCOMMAND 0x0319 +#define WM_THEMECHANGED 0x031A +#define WM_HANDHELDFIRST 0x0358 +#define WM_HANDHELDLAST 0x035F +#define WM_AFXFIRST 0x0360 +#define WM_AFXLAST 0x037F +#define WM_PENWINFIRST 0x0380 +#define WM_PENWINLAST 0x038F +#define WM_APP 0x8000 +#define WM_USER 0x0400 + +#define WMSZ_LEFT 1 +#define WMSZ_RIGHT 2 +#define WMSZ_TOP 3 +#define WMSZ_TOPLEFT 4 +#define WMSZ_TOPRIGHT 5 +#define WMSZ_BOTTOM 6 +#define WMSZ_BOTTOMLEFT 7 +#define WMSZ_BOTTOMRIGHT 8 + +#ifndef NONCMESSAGES + +#define HTERROR (-2) +#define HTTRANSPARENT (-1) +#define HTNOWHERE 0 +#define HTCLIENT 1 +#define HTCAPTION 2 +#define HTSYSMENU 3 +#define HTGROWBOX 4 +#define HTSIZE HTGROWBOX +#define HTMENU 5 +#define HTHSCROLL 6 +#define HTVSCROLL 7 +#define HTMINBUTTON 8 +#define HTMAXBUTTON 9 +#define HTLEFT 10 +#define HTRIGHT 11 +#define HTTOP 12 +#define HTTOPLEFT 13 +#define HTTOPRIGHT 14 +#define HTBOTTOM 15 +#define HTBOTTOMLEFT 16 +#define HTBOTTOMRIGHT 17 +#define HTBORDER 18 +#define HTREDUCE HTMINBUTTON +#define HTZOOM HTMAXBUTTON +#define HTSIZEFIRST HTLEFT +#define HTSIZELAST HTBOTTOMRIGHT +#define HTOBJECT 19 +#define HTCLOSE 20 +#define HTHELP 21 + +#define SMTO_NORMAL 0x0000 +#define SMTO_BLOCK 0x0001 +#define SMTO_ABORTIFHUNG 0x0002 +#define SMTO_NOTIMEOUTIFNOTHUNG 0x0008 +#endif + +#define MA_ACTIVATE 1 +#define MA_ACTIVATEANDEAT 2 +#define MA_NOACTIVATE 3 +#define MA_NOACTIVATEANDEAT 4 + +#define ICON_SMALL 0 +#define ICON_BIG 1 +#define ICON_SMALL2 2 + +#ifdef UNICODE +#define RegisterWindowMessage RegisterWindowMessageW +#else +#define RegisterWindowMessage RegisterWindowMessageA +#endif + + WINUSERAPI UINT WINAPI RegisterWindowMessageA(LPCSTR lpString); + WINUSERAPI UINT WINAPI RegisterWindowMessageW(LPCWSTR lpString); + +#define SIZE_RESTORED 0 +#define SIZE_MINIMIZED 1 +#define SIZE_MAXIMIZED 2 +#define SIZE_MAXSHOW 3 +#define SIZE_MAXHIDE 4 + +#define SIZENORMAL SIZE_RESTORED +#define SIZEICONIC SIZE_MINIMIZED +#define SIZEFULLSCREEN SIZE_MAXIMIZED +#define SIZEZOOMSHOW SIZE_MAXSHOW +#define SIZEZOOMHIDE SIZE_MAXHIDE + + typedef struct tagWINDOWPOS { + HWND hwnd; + HWND hwndInsertAfter; + int x; + int y; + int cx; + int cy; + UINT flags; + } WINDOWPOS,*LPWINDOWPOS,*PWINDOWPOS; + + typedef struct tagNCCALCSIZE_PARAMS { + RECT rgrc[3]; + PWINDOWPOS lppos; + } NCCALCSIZE_PARAMS,*LPNCCALCSIZE_PARAMS; + +#define WVR_ALIGNTOP 0x0010 +#define WVR_ALIGNLEFT 0x0020 +#define WVR_ALIGNBOTTOM 0x0040 +#define WVR_ALIGNRIGHT 0x0080 +#define WVR_HREDRAW 0x0100 +#define WVR_VREDRAW 0x0200 +#define WVR_REDRAW (WVR_HREDRAW | WVR_VREDRAW) +#define WVR_VALIDRECTS 0x0400 + +#ifndef NOKEYSTATES + +#define MK_LBUTTON 0x0001 +#define MK_RBUTTON 0x0002 +#define MK_SHIFT 0x0004 +#define MK_CONTROL 0x0008 +#define MK_MBUTTON 0x0010 +#define MK_XBUTTON1 0x0020 +#define MK_XBUTTON2 0x0040 +#endif + +#ifndef NOTRACKMOUSEEVENT +#define TME_HOVER 0x00000001 +#define TME_LEAVE 0x00000002 +#define TME_NONCLIENT 0x00000010 +#define TME_QUERY 0x40000000 +#define TME_CANCEL 0x80000000 + +#define HOVER_DEFAULT 0xFFFFFFFF +#endif + + typedef struct tagTRACKMOUSEEVENT { + DWORD cbSize; + DWORD dwFlags; + HWND hwndTrack; + DWORD dwHoverTime; + } TRACKMOUSEEVENT,*LPTRACKMOUSEEVENT; + + WINUSERAPI WINBOOL WINAPI TrackMouseEvent(LPTRACKMOUSEEVENT lpEventTrack); +#endif + +#ifndef NOWINSTYLES + +#define WS_OVERLAPPED 0x00000000L +#define WS_POPUP 0x80000000L +#define WS_CHILD 0x40000000L +#define WS_MINIMIZE 0x20000000L +#define WS_VISIBLE 0x10000000L +#define WS_DISABLED 0x08000000L +#define WS_CLIPSIBLINGS 0x04000000L +#define WS_CLIPCHILDREN 0x02000000L +#define WS_MAXIMIZE 0x01000000L +#define WS_CAPTION 0x00C00000L +#define WS_BORDER 0x00800000L +#define WS_DLGFRAME 0x00400000L +#define WS_VSCROLL 0x00200000L +#define WS_HSCROLL 0x00100000L +#define WS_SYSMENU 0x00080000L +#define WS_THICKFRAME 0x00040000L +#define WS_GROUP 0x00020000L +#define WS_TABSTOP 0x00010000L +#define WS_MINIMIZEBOX 0x00020000L +#define WS_MAXIMIZEBOX 0x00010000L +#define WS_TILED WS_OVERLAPPED +#define WS_ICONIC WS_MINIMIZE +#define WS_SIZEBOX WS_THICKFRAME +#define WS_TILEDWINDOW WS_OVERLAPPEDWINDOW +#define WS_OVERLAPPEDWINDOW (WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX) +#define WS_POPUPWINDOW (WS_POPUP | WS_BORDER | WS_SYSMENU) +#define WS_CHILDWINDOW (WS_CHILD) + +#define WS_EX_DLGMODALFRAME 0x00000001L +#define WS_EX_NOPARENTNOTIFY 0x00000004L +#define WS_EX_TOPMOST 0x00000008L +#define WS_EX_ACCEPTFILES 0x00000010L +#define WS_EX_TRANSPARENT 0x00000020L +#define WS_EX_MDICHILD 0x00000040L +#define WS_EX_TOOLWINDOW 0x00000080L +#define WS_EX_WINDOWEDGE 0x00000100L +#define WS_EX_CLIENTEDGE 0x00000200L +#define WS_EX_CONTEXTHELP 0x00000400L +#define WS_EX_RIGHT 0x00001000L +#define WS_EX_LEFT 0x00000000L +#define WS_EX_RTLREADING 0x00002000L +#define WS_EX_LTRREADING 0x00000000L +#define WS_EX_LEFTSCROLLBAR 0x00004000L +#define WS_EX_RIGHTSCROLLBAR 0x00000000L +#define WS_EX_CONTROLPARENT 0x00010000L +#define WS_EX_STATICEDGE 0x00020000L +#define WS_EX_APPWINDOW 0x00040000L +#define WS_EX_OVERLAPPEDWINDOW (WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE) +#define WS_EX_PALETTEWINDOW (WS_EX_WINDOWEDGE | WS_EX_TOOLWINDOW | WS_EX_TOPMOST) +#define WS_EX_LAYERED 0x00080000 +#define WS_EX_NOINHERITLAYOUT 0x00100000L +#define WS_EX_LAYOUTRTL 0x00400000L +#define WS_EX_COMPOSITED 0x02000000L +#define WS_EX_NOACTIVATE 0x08000000L + +#define CS_VREDRAW 0x0001 +#define CS_HREDRAW 0x0002 +#define CS_DBLCLKS 0x0008 +#define CS_OWNDC 0x0020 +#define CS_CLASSDC 0x0040 +#define CS_PARENTDC 0x0080 +#define CS_NOCLOSE 0x0200 +#define CS_SAVEBITS 0x0800 +#define CS_BYTEALIGNCLIENT 0x1000 +#define CS_BYTEALIGNWINDOW 0x2000 +#define CS_GLOBALCLASS 0x4000 +#define CS_IME 0x00010000 +#define CS_DROPSHADOW 0x00020000 +#endif + +#define PRF_CHECKVISIBLE 0x00000001L +#define PRF_NONCLIENT 0x00000002L +#define PRF_CLIENT 0x00000004L +#define PRF_ERASEBKGND 0x00000008L +#define PRF_CHILDREN 0x00000010L +#define PRF_OWNED 0x00000020L + +#define BDR_RAISEDOUTER 0x0001 +#define BDR_SUNKENOUTER 0x0002 +#define BDR_RAISEDINNER 0x0004 +#define BDR_SUNKENINNER 0x0008 + +#define BDR_OUTER (BDR_RAISEDOUTER | BDR_SUNKENOUTER) +#define BDR_INNER (BDR_RAISEDINNER | BDR_SUNKENINNER) +#define BDR_RAISED (BDR_RAISEDOUTER | BDR_RAISEDINNER) +#define BDR_SUNKEN (BDR_SUNKENOUTER | BDR_SUNKENINNER) + +#define EDGE_RAISED (BDR_RAISEDOUTER | BDR_RAISEDINNER) +#define EDGE_SUNKEN (BDR_SUNKENOUTER | BDR_SUNKENINNER) +#define EDGE_ETCHED (BDR_SUNKENOUTER | BDR_RAISEDINNER) +#define EDGE_BUMP (BDR_RAISEDOUTER | BDR_SUNKENINNER) + +#define BF_LEFT 0x0001 +#define BF_TOP 0x0002 +#define BF_RIGHT 0x0004 +#define BF_BOTTOM 0x0008 + +#define BF_TOPLEFT (BF_TOP | BF_LEFT) +#define BF_TOPRIGHT (BF_TOP | BF_RIGHT) +#define BF_BOTTOMLEFT (BF_BOTTOM | BF_LEFT) +#define BF_BOTTOMRIGHT (BF_BOTTOM | BF_RIGHT) +#define BF_RECT (BF_LEFT | BF_TOP | BF_RIGHT | BF_BOTTOM) + +#define BF_DIAGONAL 0x0010 + +#define BF_DIAGONAL_ENDTOPRIGHT (BF_DIAGONAL | BF_TOP | BF_RIGHT) +#define BF_DIAGONAL_ENDTOPLEFT (BF_DIAGONAL | BF_TOP | BF_LEFT) +#define BF_DIAGONAL_ENDBOTTOMLEFT (BF_DIAGONAL | BF_BOTTOM | BF_LEFT) +#define BF_DIAGONAL_ENDBOTTOMRIGHT (BF_DIAGONAL | BF_BOTTOM | BF_RIGHT) + +#define BF_MIDDLE 0x0800 +#define BF_SOFT 0x1000 +#define BF_ADJUST 0x2000 +#define BF_FLAT 0x4000 +#define BF_MONO 0x8000 + + WINUSERAPI WINBOOL WINAPI DrawEdge(HDC hdc,LPRECT qrc,UINT edge,UINT grfFlags); + +#define DFC_CAPTION 1 +#define DFC_MENU 2 +#define DFC_SCROLL 3 +#define DFC_BUTTON 4 +#define DFC_POPUPMENU 5 + +#define DFCS_CAPTIONCLOSE 0x0000 +#define DFCS_CAPTIONMIN 0x0001 +#define DFCS_CAPTIONMAX 0x0002 +#define DFCS_CAPTIONRESTORE 0x0003 +#define DFCS_CAPTIONHELP 0x0004 + +#define DFCS_MENUARROW 0x0000 +#define DFCS_MENUCHECK 0x0001 +#define DFCS_MENUBULLET 0x0002 +#define DFCS_MENUARROWRIGHT 0x0004 +#define DFCS_SCROLLUP 0x0000 +#define DFCS_SCROLLDOWN 0x0001 +#define DFCS_SCROLLLEFT 0x0002 +#define DFCS_SCROLLRIGHT 0x0003 +#define DFCS_SCROLLCOMBOBOX 0x0005 +#define DFCS_SCROLLSIZEGRIP 0x0008 +#define DFCS_SCROLLSIZEGRIPRIGHT 0x0010 + +#define DFCS_BUTTONCHECK 0x0000 +#define DFCS_BUTTONRADIOIMAGE 0x0001 +#define DFCS_BUTTONRADIOMASK 0x0002 +#define DFCS_BUTTONRADIO 0x0004 +#define DFCS_BUTTON3STATE 0x0008 +#define DFCS_BUTTONPUSH 0x0010 + +#define DFCS_INACTIVE 0x0100 +#define DFCS_PUSHED 0x0200 +#define DFCS_CHECKED 0x0400 + +#define DFCS_TRANSPARENT 0x0800 +#define DFCS_HOT 0x1000 + +#define DFCS_ADJUSTRECT 0x2000 +#define DFCS_FLAT 0x4000 +#define DFCS_MONO 0x8000 + + WINUSERAPI WINBOOL WINAPI DrawFrameControl(HDC,LPRECT,UINT,UINT); + +#define DC_ACTIVE 0x0001 +#define DC_SMALLCAP 0x0002 +#define DC_ICON 0x0004 +#define DC_TEXT 0x0008 +#define DC_INBUTTON 0x0010 +#define DC_GRADIENT 0x0020 +#define DC_BUTTONS 0x1000 + + WINUSERAPI WINBOOL WINAPI DrawCaption(HWND hwnd,HDC hdc,CONST RECT *lprect,UINT flags); + +#define IDANI_OPEN 1 +#define IDANI_CAPTION 3 + + WINUSERAPI WINBOOL WINAPI DrawAnimatedRects(HWND hwnd,int idAni,CONST RECT *lprcFrom,CONST RECT *lprcTo); + +#ifndef NOCLIPBOARD + +#define CF_TEXT 1 +#define CF_BITMAP 2 +#define CF_METAFILEPICT 3 +#define CF_SYLK 4 +#define CF_DIF 5 +#define CF_TIFF 6 +#define CF_OEMTEXT 7 +#define CF_DIB 8 +#define CF_PALETTE 9 +#define CF_PENDATA 10 +#define CF_RIFF 11 +#define CF_WAVE 12 +#define CF_UNICODETEXT 13 +#define CF_ENHMETAFILE 14 +#define CF_HDROP 15 +#define CF_LOCALE 16 +#define CF_DIBV5 17 +#define CF_MAX 18 + +#define CF_OWNERDISPLAY 0x0080 +#define CF_DSPTEXT 0x0081 +#define CF_DSPBITMAP 0x0082 +#define CF_DSPMETAFILEPICT 0x0083 +#define CF_DSPENHMETAFILE 0x008E + +#define CF_PRIVATEFIRST 0x0200 +#define CF_PRIVATELAST 0x02FF + +#define CF_GDIOBJFIRST 0x0300 +#define CF_GDIOBJLAST 0x03FF +#endif + +#define FVIRTKEY TRUE +#define FNOINVERT 0x02 +#define FSHIFT 0x04 +#define FCONTROL 0x08 +#define FALT 0x10 + + typedef struct tagACCEL { + BYTE fVirt; + WORD key; + WORD cmd; + } ACCEL,*LPACCEL; + + typedef struct tagPAINTSTRUCT { + HDC hdc; + WINBOOL fErase; + RECT rcPaint; + WINBOOL fRestore; + WINBOOL fIncUpdate; + BYTE rgbReserved[32]; + } PAINTSTRUCT,*PPAINTSTRUCT,*NPPAINTSTRUCT,*LPPAINTSTRUCT; + + typedef struct tagCREATESTRUCTA { + LPVOID lpCreateParams; + HINSTANCE hInstance; + HMENU hMenu; + HWND hwndParent; + int cy; + int cx; + int y; + int x; + LONG style; + LPCSTR lpszName; + LPCSTR lpszClass; + DWORD dwExStyle; + } CREATESTRUCTA,*LPCREATESTRUCTA; + + typedef struct tagCREATESTRUCTW { + LPVOID lpCreateParams; + HINSTANCE hInstance; + HMENU hMenu; + HWND hwndParent; + int cy; + int cx; + int y; + int x; + LONG style; + LPCWSTR lpszName; + LPCWSTR lpszClass; + DWORD dwExStyle; + } CREATESTRUCTW,*LPCREATESTRUCTW; + +#ifdef UNICODE + typedef CREATESTRUCTW CREATESTRUCT; + typedef LPCREATESTRUCTW LPCREATESTRUCT; +#else + typedef CREATESTRUCTA CREATESTRUCT; + typedef LPCREATESTRUCTA LPCREATESTRUCT; +#endif + + typedef struct tagWINDOWPLACEMENT { + UINT length; + UINT flags; + UINT showCmd; + POINT ptMinPosition; + POINT ptMaxPosition; + RECT rcNormalPosition; + } WINDOWPLACEMENT; + typedef WINDOWPLACEMENT *PWINDOWPLACEMENT,*LPWINDOWPLACEMENT; + +#define WPF_SETMINPOSITION 0x0001 +#define WPF_RESTORETOMAXIMIZED 0x0002 +#define WPF_ASYNCWINDOWPLACEMENT 0x0004 + + typedef struct tagNMHDR { + HWND hwndFrom; + UINT_PTR idFrom; + UINT code; + } NMHDR; + + typedef NMHDR *LPNMHDR; + + typedef struct tagSTYLESTRUCT { + DWORD styleOld; + DWORD styleNew; + } STYLESTRUCT,*LPSTYLESTRUCT; + +#define ODT_MENU 1 +#define ODT_LISTBOX 2 +#define ODT_COMBOBOX 3 +#define ODT_BUTTON 4 +#define ODT_STATIC 5 + +#define ODA_DRAWENTIRE 0x0001 +#define ODA_SELECT 0x0002 +#define ODA_FOCUS 0x0004 + +#define ODS_SELECTED 0x0001 +#define ODS_GRAYED 0x0002 +#define ODS_DISABLED 0x0004 +#define ODS_CHECKED 0x0008 +#define ODS_FOCUS 0x0010 +#define ODS_DEFAULT 0x0020 +#define ODS_COMBOBOXEDIT 0x1000 +#define ODS_HOTLIGHT 0x0040 +#define ODS_INACTIVE 0x0080 +#define ODS_NOACCEL 0x0100 +#define ODS_NOFOCUSRECT 0x0200 + + typedef struct tagMEASUREITEMSTRUCT { + UINT CtlType; + UINT CtlID; + UINT itemID; + UINT itemWidth; + UINT itemHeight; + ULONG_PTR itemData; + } MEASUREITEMSTRUCT,*PMEASUREITEMSTRUCT,*LPMEASUREITEMSTRUCT; + + typedef struct tagDRAWITEMSTRUCT { + UINT CtlType; + UINT CtlID; + UINT itemID; + UINT itemAction; + UINT itemState; + HWND hwndItem; + HDC hDC; + RECT rcItem; + ULONG_PTR itemData; + } DRAWITEMSTRUCT,*PDRAWITEMSTRUCT,*LPDRAWITEMSTRUCT; + + typedef struct tagDELETEITEMSTRUCT { + UINT CtlType; + UINT CtlID; + UINT itemID; + HWND hwndItem; + ULONG_PTR itemData; + } DELETEITEMSTRUCT,*PDELETEITEMSTRUCT,*LPDELETEITEMSTRUCT; + + typedef struct tagCOMPAREITEMSTRUCT { + UINT CtlType; + UINT CtlID; + HWND hwndItem; + UINT itemID1; + ULONG_PTR itemData1; + UINT itemID2; + ULONG_PTR itemData2; + DWORD dwLocaleId; + } COMPAREITEMSTRUCT,*PCOMPAREITEMSTRUCT,*LPCOMPAREITEMSTRUCT; + +#ifndef NOMSG +#ifdef UNICODE +#define GetMessage GetMessageW +#define DispatchMessage DispatchMessageW +#define PeekMessage PeekMessageW +#else +#define GetMessage GetMessageA +#define DispatchMessage DispatchMessageA +#define PeekMessage PeekMessageA +#endif + + WINUSERAPI WINBOOL WINAPI GetMessageA(LPMSG lpMsg,HWND hWnd,UINT wMsgFilterMin,UINT wMsgFilterMax); + WINUSERAPI WINBOOL WINAPI GetMessageW(LPMSG lpMsg,HWND hWnd,UINT wMsgFilterMin,UINT wMsgFilterMax); + WINUSERAPI WINBOOL WINAPI TranslateMessage(CONST MSG *lpMsg); + WINUSERAPI LRESULT WINAPI DispatchMessageA(CONST MSG *lpMsg); + WINUSERAPI LRESULT WINAPI DispatchMessageW(CONST MSG *lpMsg); + WINUSERAPI WINBOOL WINAPI SetMessageQueue(int cMessagesMax); + WINUSERAPI WINBOOL WINAPI PeekMessageA(LPMSG lpMsg,HWND hWnd,UINT wMsgFilterMin,UINT wMsgFilterMax,UINT wRemoveMsg); + WINUSERAPI WINBOOL WINAPI PeekMessageW(LPMSG lpMsg,HWND hWnd,UINT wMsgFilterMin,UINT wMsgFilterMax,UINT wRemoveMsg); + +#define PM_NOREMOVE 0x0000 +#define PM_REMOVE 0x0001 +#define PM_NOYIELD 0x0002 +#define PM_QS_INPUT (QS_INPUT << 16) +#define PM_QS_POSTMESSAGE ((QS_POSTMESSAGE | QS_HOTKEY | QS_TIMER) << 16) +#define PM_QS_PAINT (QS_PAINT << 16) +#define PM_QS_SENDMESSAGE (QS_SENDMESSAGE << 16) +#endif + + WINUSERAPI WINBOOL WINAPI RegisterHotKey(HWND hWnd,int id,UINT fsModifiers,UINT vk); + WINUSERAPI WINBOOL WINAPI UnregisterHotKey(HWND hWnd,int id); + +#define MOD_ALT 0x0001 +#define MOD_CONTROL 0x0002 +#define MOD_SHIFT 0x0004 +#define MOD_WIN 0x0008 + +#define IDHOT_SNAPWINDOW (-1) +#define IDHOT_SNAPDESKTOP (-2) + +#ifdef WIN_INTERNAL +#ifndef LSTRING +#define NOLSTRING +#endif +#ifndef LFILEIO +#define NOLFILEIO +#endif +#endif + +#define ENDSESSION_LOGOFF 0x80000000 + +#define EWX_LOGOFF 0 +#define EWX_SHUTDOWN 0x00000001 +#define EWX_REBOOT 0x00000002 +#define EWX_FORCE 0x00000004 +#define EWX_POWEROFF 0x00000008 +#define EWX_FORCEIFHUNG 0x00000010 + +#define ExitWindows(dwReserved,Code) ExitWindowsEx(EWX_LOGOFF,0xFFFFFFFF) + +#ifdef UNICODE +#define SendMessage SendMessageW +#define SendMessageTimeout SendMessageTimeoutW +#define SendNotifyMessage SendNotifyMessageW +#define SendMessageCallback SendMessageCallbackW +#else +#define SendMessage SendMessageA +#define SendMessageTimeout SendMessageTimeoutA +#define SendNotifyMessage SendNotifyMessageA +#define SendMessageCallback SendMessageCallbackA +#endif + + WINUSERAPI WINBOOL WINAPI ExitWindowsEx(UINT uFlags,DWORD dwReason); + WINUSERAPI WINBOOL WINAPI SwapMouseButton(WINBOOL fSwap); + WINUSERAPI DWORD WINAPI GetMessagePos(VOID); + WINUSERAPI LONG WINAPI GetMessageTime(VOID); + WINUSERAPI LPARAM WINAPI GetMessageExtraInfo(VOID); + WINUSERAPI WINBOOL WINAPI IsWow64Message(VOID); + WINUSERAPI LPARAM WINAPI SetMessageExtraInfo(LPARAM lParam); + WINUSERAPI LRESULT WINAPI SendMessageA(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam); + WINUSERAPI LRESULT WINAPI SendMessageW(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam); + WINUSERAPI LRESULT WINAPI SendMessageTimeoutA(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam,UINT fuFlags,UINT uTimeout,PDWORD_PTR lpdwResult); + WINUSERAPI LRESULT WINAPI SendMessageTimeoutW(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam,UINT fuFlags,UINT uTimeout,PDWORD_PTR lpdwResult); + WINUSERAPI WINBOOL WINAPI SendNotifyMessageA(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam); + WINUSERAPI WINBOOL WINAPI SendNotifyMessageW(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam); + WINUSERAPI WINBOOL WINAPI SendMessageCallbackA(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam,SENDASYNCPROC lpResultCallBack,ULONG_PTR dwData); + WINUSERAPI WINBOOL WINAPI SendMessageCallbackW(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam,SENDASYNCPROC lpResultCallBack,ULONG_PTR dwData); + + typedef struct { + UINT cbSize; + HDESK hdesk; + HWND hwnd; + LUID luid; + } BSMINFO,*PBSMINFO; + +#ifdef UNICODE +#define BroadcastSystemMessageEx BroadcastSystemMessageExW +#define BroadcastSystemMessage BroadcastSystemMessageW +#else +#define BroadcastSystemMessageEx BroadcastSystemMessageExA +#define BroadcastSystemMessage BroadcastSystemMessageA +#endif + + WINUSERAPI long WINAPI BroadcastSystemMessageExA(DWORD flags,LPDWORD lpInfo,UINT Msg,WPARAM wParam,LPARAM lParam,PBSMINFO pbsmInfo); + WINUSERAPI long WINAPI BroadcastSystemMessageExW(DWORD flags,LPDWORD lpInfo,UINT Msg,WPARAM wParam,LPARAM lParam,PBSMINFO pbsmInfo); + WINUSERAPI long WINAPI BroadcastSystemMessageA(DWORD flags,LPDWORD lpInfo,UINT Msg,WPARAM wParam,LPARAM lParam); + WINUSERAPI long WINAPI BroadcastSystemMessageW(DWORD flags,LPDWORD lpInfo,UINT Msg,WPARAM wParam,LPARAM lParam); + +#define BSM_ALLCOMPONENTS 0x00000000 +#define BSM_VXDS 0x00000001 +#define BSM_NETDRIVER 0x00000002 +#define BSM_INSTALLABLEDRIVERS 0x00000004 +#define BSM_APPLICATIONS 0x00000008 +#define BSM_ALLDESKTOPS 0x00000010 + +#define BSF_QUERY 0x00000001 +#define BSF_IGNORECURRENTTASK 0x00000002 +#define BSF_FLUSHDISK 0x00000004 +#define BSF_NOHANG 0x00000008 +#define BSF_POSTMESSAGE 0x00000010 +#define BSF_FORCEIFHUNG 0x00000020 +#define BSF_NOTIMEOUTIFNOTHUNG 0x00000040 +#define BSF_ALLOWSFW 0x00000080 +#define BSF_SENDNOTIFYMESSAGE 0x00000100 +#define BSF_RETURNHDESK 0x00000200 +#define BSF_LUID 0x00000400 + +#define BROADCAST_QUERY_DENY 0x424D5144 + + typedef PVOID HDEVNOTIFY; + typedef HDEVNOTIFY *PHDEVNOTIFY; + +#define DEVICE_NOTIFY_WINDOW_HANDLE 0x00000000 +#define DEVICE_NOTIFY_SERVICE_HANDLE 0x00000001 +#define DEVICE_NOTIFY_ALL_INTERFACE_CLASSES 0x00000004 + +#ifdef UNICODE +#define RegisterDeviceNotification RegisterDeviceNotificationW +#define PostMessage PostMessageW +#define PostThreadMessage PostThreadMessageW +#define PostAppMessage PostAppMessageW +#define DefWindowProc DefWindowProcW +#define CallWindowProc CallWindowProcW +#define RegisterClass RegisterClassW +#define UnregisterClass UnregisterClassW +#define GetClassInfo GetClassInfoW +#define RegisterClassEx RegisterClassExW +#define GetClassInfoEx GetClassInfoExW +#else +#define RegisterDeviceNotification RegisterDeviceNotificationA +#define PostMessage PostMessageA +#define PostThreadMessage PostThreadMessageA +#define PostAppMessage PostAppMessageA +#define DefWindowProc DefWindowProcA +#define CallWindowProc CallWindowProcA +#define RegisterClass RegisterClassA +#define UnregisterClass UnregisterClassA +#define GetClassInfo GetClassInfoA +#define RegisterClassEx RegisterClassExA +#define GetClassInfoEx GetClassInfoExA +#endif + + WINUSERAPI HDEVNOTIFY WINAPI RegisterDeviceNotificationA(HANDLE hRecipient,LPVOID NotificationFilter,DWORD Flags); + WINUSERAPI HDEVNOTIFY WINAPI RegisterDeviceNotificationW(HANDLE hRecipient,LPVOID NotificationFilter,DWORD Flags); + WINUSERAPI WINBOOL WINAPI UnregisterDeviceNotification(HDEVNOTIFY Handle); + WINUSERAPI WINBOOL WINAPI PostMessageA(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam); + WINUSERAPI WINBOOL WINAPI PostMessageW(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam); + WINUSERAPI WINBOOL WINAPI PostThreadMessageA(DWORD idThread,UINT Msg,WPARAM wParam,LPARAM lParam); + WINUSERAPI WINBOOL WINAPI PostThreadMessageW(DWORD idThread,UINT Msg,WPARAM wParam,LPARAM lParam); +#define PostAppMessageA(idThread,wMsg,wParam,lParam) PostThreadMessageA((DWORD)idThread,wMsg,wParam,lParam) +#define PostAppMessageW(idThread,wMsg,wParam,lParam) PostThreadMessageW((DWORD)idThread,wMsg,wParam,lParam) + +#define HWND_BROADCAST ((HWND)0xffff) +#define HWND_MESSAGE ((HWND)-3) + + WINUSERAPI WINBOOL WINAPI AttachThreadInput(DWORD idAttach,DWORD idAttachTo,WINBOOL fAttach); + WINUSERAPI WINBOOL WINAPI ReplyMessage(LRESULT lResult); + WINUSERAPI WINBOOL WINAPI WaitMessage(VOID); + WINUSERAPI DWORD WINAPI WaitForInputIdle(HANDLE hProcess,DWORD dwMilliseconds); + WINUSERAPI LRESULT WINAPI DefWindowProcA(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam); + WINUSERAPI LRESULT WINAPI DefWindowProcW(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam); + WINUSERAPI VOID WINAPI PostQuitMessage(int nExitCode); + WINUSERAPI LRESULT WINAPI CallWindowProcA(WNDPROC lpPrevWndFunc,HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam); + WINUSERAPI LRESULT WINAPI CallWindowProcW(WNDPROC lpPrevWndFunc,HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam); + WINUSERAPI WINBOOL WINAPI InSendMessage(VOID); + WINUSERAPI DWORD WINAPI InSendMessageEx(LPVOID lpReserved); + +#define ISMEX_NOSEND 0x00000000 +#define ISMEX_SEND 0x00000001 +#define ISMEX_NOTIFY 0x00000002 +#define ISMEX_CALLBACK 0x00000004 +#define ISMEX_REPLIED 0x00000008 + + WINUSERAPI UINT WINAPI GetDoubleClickTime(VOID); + WINUSERAPI WINBOOL WINAPI SetDoubleClickTime(UINT); + WINUSERAPI ATOM WINAPI RegisterClassA(CONST WNDCLASSA *lpWndClass); + WINUSERAPI ATOM WINAPI RegisterClassW(CONST WNDCLASSW *lpWndClass); + WINUSERAPI WINBOOL WINAPI UnregisterClassA(LPCSTR lpClassName,HINSTANCE hInstance); + WINUSERAPI WINBOOL WINAPI UnregisterClassW(LPCWSTR lpClassName,HINSTANCE hInstance); + WINUSERAPI WINBOOL WINAPI GetClassInfoA(HINSTANCE hInstance,LPCSTR lpClassName,LPWNDCLASSA lpWndClass); + WINUSERAPI WINBOOL WINAPI GetClassInfoW(HINSTANCE hInstance,LPCWSTR lpClassName,LPWNDCLASSW lpWndClass); + WINUSERAPI ATOM WINAPI RegisterClassExA(CONST WNDCLASSEXA *); + WINUSERAPI ATOM WINAPI RegisterClassExW(CONST WNDCLASSEXW *); + WINUSERAPI WINBOOL WINAPI GetClassInfoExA(HINSTANCE hInstance,LPCSTR lpszClass,LPWNDCLASSEXA lpwcx); + WINUSERAPI WINBOOL WINAPI GetClassInfoExW(HINSTANCE hInstance,LPCWSTR lpszClass,LPWNDCLASSEXW lpwcx); + +#define CW_USEDEFAULT ((int)0x80000000) + +#define HWND_DESKTOP ((HWND)0) + + typedef BOOLEAN (WINAPI *PREGISTERCLASSNAMEW)(LPCWSTR); + +#ifdef UNICODE +#define CreateWindowEx CreateWindowExW +#define CreateWindow CreateWindowW +#else +#define CreateWindowEx CreateWindowExA +#define CreateWindow CreateWindowA +#endif + + WINUSERAPI HWND WINAPI CreateWindowExA(DWORD dwExStyle,LPCSTR lpClassName,LPCSTR lpWindowName,DWORD dwStyle,int X,int Y,int nWidth,int nHeight,HWND hWndParent,HMENU hMenu,HINSTANCE hInstance,LPVOID lpParam); + WINUSERAPI HWND WINAPI CreateWindowExW(DWORD dwExStyle,LPCWSTR lpClassName,LPCWSTR lpWindowName,DWORD dwStyle,int X,int Y,int nWidth,int nHeight,HWND hWndParent,HMENU hMenu,HINSTANCE hInstance,LPVOID lpParam); +#define CreateWindowA(lpClassName,lpWindowName,dwStyle,x,y,nWidth,nHeight,hWndParent,hMenu,hInstance,lpParam) CreateWindowExA(0L,lpClassName,lpWindowName,dwStyle,x,y,nWidth,nHeight,hWndParent,hMenu,hInstance,lpParam) +#define CreateWindowW(lpClassName,lpWindowName,dwStyle,x,y,nWidth,nHeight,hWndParent,hMenu,hInstance,lpParam) CreateWindowExW(0L,lpClassName,lpWindowName,dwStyle,x,y,nWidth,nHeight,hWndParent,hMenu,hInstance,lpParam) + WINUSERAPI WINBOOL WINAPI IsWindow(HWND hWnd); + WINUSERAPI WINBOOL WINAPI IsMenu(HMENU hMenu); + WINUSERAPI WINBOOL WINAPI IsChild(HWND hWndParent,HWND hWnd); + WINUSERAPI WINBOOL WINAPI DestroyWindow(HWND hWnd); + WINUSERAPI WINBOOL WINAPI ShowWindow(HWND hWnd,int nCmdShow); + WINUSERAPI WINBOOL WINAPI AnimateWindow(HWND hWnd,DWORD dwTime,DWORD dwFlags); + +#if defined(_WINGDI_) && !defined(NOGDI) + WINUSERAPI WINBOOL WINAPI UpdateLayeredWindow(HWND hWnd,HDC hdcDst,POINT *pptDst,SIZE *psize,HDC hdcSrc,POINT *pptSrc,COLORREF crKey,BLENDFUNCTION *pblend,DWORD dwFlags); + + typedef struct tagUPDATELAYEREDWINDOWINFO { + DWORD cbSize; + HDC hdcDst; + POINT CONST *pptDst; + SIZE CONST *psize; + HDC hdcSrc; + POINT CONST *pptSrc; + COLORREF crKey; + BLENDFUNCTION CONST *pblend; + DWORD dwFlags; + RECT CONST *prcDirty; + } UPDATELAYEREDWINDOWINFO,*PUPDATELAYEREDWINDOWINFO; + + WINUSERAPI WINBOOL WINAPI UpdateLayeredWindowIndirect(HWND hWnd,UPDATELAYEREDWINDOWINFO CONST *pULWInfo); + WINUSERAPI WINBOOL WINAPI GetLayeredWindowAttributes(HWND hwnd,COLORREF *pcrKey,BYTE *pbAlpha,DWORD *pdwFlags); + +#define PW_CLIENTONLY 0x00000001 + + WINUSERAPI WINBOOL WINAPI PrintWindow(HWND hwnd,HDC hdcBlt,UINT nFlags); + WINUSERAPI WINBOOL WINAPI SetLayeredWindowAttributes(HWND hwnd,COLORREF crKey,BYTE bAlpha,DWORD dwFlags); + +#define LWA_COLORKEY 0x00000001 +#define LWA_ALPHA 0x00000002 + +#define ULW_COLORKEY 0x00000001 +#define ULW_ALPHA 0x00000002 +#define ULW_OPAQUE 0x00000004 + +#define ULW_EX_NORESIZE 0x00000008 + + WINUSERAPI WINBOOL WINAPI ShowWindowAsync(HWND hWnd,int nCmdShow); + WINUSERAPI WINBOOL WINAPI FlashWindow(HWND hWnd,WINBOOL bInvert); + + typedef struct { + UINT cbSize; + HWND hwnd; + DWORD dwFlags; + UINT uCount; + DWORD dwTimeout; + } FLASHWINFO,*PFLASHWINFO; + + WINUSERAPI WINBOOL WINAPI FlashWindowEx(PFLASHWINFO pfwi); + +#define FLASHW_STOP 0 +#define FLASHW_CAPTION 0x00000001 +#define FLASHW_TRAY 0x00000002 +#define FLASHW_ALL (FLASHW_CAPTION | FLASHW_TRAY) +#define FLASHW_TIMER 0x00000004 +#define FLASHW_TIMERNOFG 0x0000000C + + WINUSERAPI WINBOOL WINAPI ShowOwnedPopups(HWND hWnd,WINBOOL fShow); + WINUSERAPI WINBOOL WINAPI OpenIcon(HWND hWnd); + WINUSERAPI WINBOOL WINAPI CloseWindow(HWND hWnd); + WINUSERAPI WINBOOL WINAPI MoveWindow(HWND hWnd,int X,int Y,int nWidth,int nHeight,WINBOOL bRepaint); + WINUSERAPI WINBOOL WINAPI SetWindowPos(HWND hWnd,HWND hWndInsertAfter,int X,int Y,int cx,int cy,UINT uFlags); + WINUSERAPI WINBOOL WINAPI GetWindowPlacement(HWND hWnd,WINDOWPLACEMENT *lpwndpl); + WINUSERAPI WINBOOL WINAPI SetWindowPlacement(HWND hWnd,CONST WINDOWPLACEMENT *lpwndpl); + +#ifndef NODEFERWINDOWPOS + WINUSERAPI HDWP WINAPI BeginDeferWindowPos(int nNumWindows); + WINUSERAPI HDWP WINAPI DeferWindowPos(HDWP hWinPosInfo,HWND hWnd,HWND hWndInsertAfter,int x,int y,int cx,int cy,UINT uFlags); + WINUSERAPI WINBOOL WINAPI EndDeferWindowPos(HDWP hWinPosInfo); +#endif + + WINUSERAPI WINBOOL WINAPI IsWindowVisible(HWND hWnd); + WINUSERAPI WINBOOL WINAPI IsIconic(HWND hWnd); + WINUSERAPI WINBOOL WINAPI AnyPopup(VOID); + WINUSERAPI WINBOOL WINAPI BringWindowToTop(HWND hWnd); + WINUSERAPI WINBOOL WINAPI IsZoomed(HWND hWnd); + +#define SWP_NOSIZE 0x0001 +#define SWP_NOMOVE 0x0002 +#define SWP_NOZORDER 0x0004 +#define SWP_NOREDRAW 0x0008 +#define SWP_NOACTIVATE 0x0010 +#define SWP_FRAMECHANGED 0x0020 +#define SWP_SHOWWINDOW 0x0040 +#define SWP_HIDEWINDOW 0x0080 +#define SWP_NOCOPYBITS 0x0100 +#define SWP_NOOWNERZORDER 0x0200 +#define SWP_NOSENDCHANGING 0x0400 + +#define SWP_DRAWFRAME SWP_FRAMECHANGED +#define SWP_NOREPOSITION SWP_NOOWNERZORDER +#define SWP_DEFERERASE 0x2000 +#define SWP_ASYNCWINDOWPOS 0x4000 + +#define HWND_TOP ((HWND)0) +#define HWND_BOTTOM ((HWND)1) +#define HWND_TOPMOST ((HWND)-1) +#define HWND_NOTOPMOST ((HWND)-2) + +#ifndef NOCTLMGR + +#include + + typedef struct { + DWORD style; + DWORD dwExtendedStyle; + WORD cdit; + short x; + short y; + short cx; + short cy; + } DLGTEMPLATE; + + typedef DLGTEMPLATE *LPDLGTEMPLATEA; + typedef DLGTEMPLATE *LPDLGTEMPLATEW; + +#ifdef UNICODE + typedef LPDLGTEMPLATEW LPDLGTEMPLATE; +#else + typedef LPDLGTEMPLATEA LPDLGTEMPLATE; +#endif + + typedef CONST DLGTEMPLATE *LPCDLGTEMPLATEA; + typedef CONST DLGTEMPLATE *LPCDLGTEMPLATEW; + +#ifdef UNICODE + typedef LPCDLGTEMPLATEW LPCDLGTEMPLATE; +#else + typedef LPCDLGTEMPLATEA LPCDLGTEMPLATE; +#endif + + typedef struct { + DWORD style; + DWORD dwExtendedStyle; + short x; + short y; + short cx; + short cy; + WORD id; + } DLGITEMTEMPLATE; + + typedef DLGITEMTEMPLATE *PDLGITEMTEMPLATEA; + typedef DLGITEMTEMPLATE *PDLGITEMTEMPLATEW; + +#ifdef UNICODE + typedef PDLGITEMTEMPLATEW PDLGITEMTEMPLATE; +#else + typedef PDLGITEMTEMPLATEA PDLGITEMTEMPLATE; +#endif + + typedef DLGITEMTEMPLATE *LPDLGITEMTEMPLATEA; + typedef DLGITEMTEMPLATE *LPDLGITEMTEMPLATEW; + +#ifdef UNICODE + typedef LPDLGITEMTEMPLATEW LPDLGITEMTEMPLATE; +#else + typedef LPDLGITEMTEMPLATEA LPDLGITEMTEMPLATE; +#endif + +#include + +#ifdef UNICODE +#define CreateDialogParam CreateDialogParamW +#define CreateDialogIndirectParam CreateDialogIndirectParamW +#define CreateDialog CreateDialogW +#define CreateDialogIndirect CreateDialogIndirectW +#define DialogBoxParam DialogBoxParamW +#define DialogBoxIndirectParam DialogBoxIndirectParamW +#define DialogBox DialogBoxW +#define DialogBoxIndirect DialogBoxIndirectW +#define SetDlgItemText SetDlgItemTextW +#define GetDlgItemText GetDlgItemTextW +#define SendDlgItemMessage SendDlgItemMessageW +#define DefDlgProc DefDlgProcW +#else +#define CreateDialogParam CreateDialogParamA +#define CreateDialogIndirectParam CreateDialogIndirectParamA +#define CreateDialog CreateDialogA +#define CreateDialogIndirect CreateDialogIndirectA +#define DialogBoxParam DialogBoxParamA +#define DialogBoxIndirectParam DialogBoxIndirectParamA +#define DialogBox DialogBoxA +#define DialogBoxIndirect DialogBoxIndirectA +#define SetDlgItemText SetDlgItemTextA +#define GetDlgItemText GetDlgItemTextA +#define SendDlgItemMessage SendDlgItemMessageA +#define DefDlgProc DefDlgProcA +#endif + + WINUSERAPI HWND WINAPI CreateDialogParamA(HINSTANCE hInstance,LPCSTR lpTemplateName,HWND hWndParent,DLGPROC lpDialogFunc,LPARAM dwInitParam); + WINUSERAPI HWND WINAPI CreateDialogParamW(HINSTANCE hInstance,LPCWSTR lpTemplateName,HWND hWndParent,DLGPROC lpDialogFunc,LPARAM dwInitParam); + WINUSERAPI HWND WINAPI CreateDialogIndirectParamA(HINSTANCE hInstance,LPCDLGTEMPLATEA lpTemplate,HWND hWndParent,DLGPROC lpDialogFunc,LPARAM dwInitParam); + WINUSERAPI HWND WINAPI CreateDialogIndirectParamW(HINSTANCE hInstance,LPCDLGTEMPLATEW lpTemplate,HWND hWndParent,DLGPROC lpDialogFunc,LPARAM dwInitParam); +#define CreateDialogA(hInstance,lpName,hWndParent,lpDialogFunc) CreateDialogParamA(hInstance,lpName,hWndParent,lpDialogFunc,0L) +#define CreateDialogW(hInstance,lpName,hWndParent,lpDialogFunc) CreateDialogParamW(hInstance,lpName,hWndParent,lpDialogFunc,0L) +#define CreateDialogIndirectA(hInstance,lpTemplate,hWndParent,lpDialogFunc) CreateDialogIndirectParamA(hInstance,lpTemplate,hWndParent,lpDialogFunc,0L) +#define CreateDialogIndirectW(hInstance,lpTemplate,hWndParent,lpDialogFunc) CreateDialogIndirectParamW(hInstance,lpTemplate,hWndParent,lpDialogFunc,0L) + WINUSERAPI INT_PTR WINAPI DialogBoxParamA(HINSTANCE hInstance,LPCSTR lpTemplateName,HWND hWndParent,DLGPROC lpDialogFunc,LPARAM dwInitParam); + WINUSERAPI INT_PTR WINAPI DialogBoxParamW(HINSTANCE hInstance,LPCWSTR lpTemplateName,HWND hWndParent,DLGPROC lpDialogFunc,LPARAM dwInitParam); + WINUSERAPI INT_PTR WINAPI DialogBoxIndirectParamA(HINSTANCE hInstance,LPCDLGTEMPLATEA hDialogTemplate,HWND hWndParent,DLGPROC lpDialogFunc,LPARAM dwInitParam); + WINUSERAPI INT_PTR WINAPI DialogBoxIndirectParamW(HINSTANCE hInstance,LPCDLGTEMPLATEW hDialogTemplate,HWND hWndParent,DLGPROC lpDialogFunc,LPARAM dwInitParam); +#define DialogBoxA(hInstance,lpTemplate,hWndParent,lpDialogFunc) DialogBoxParamA(hInstance,lpTemplate,hWndParent,lpDialogFunc,0L) +#define DialogBoxW(hInstance,lpTemplate,hWndParent,lpDialogFunc) DialogBoxParamW(hInstance,lpTemplate,hWndParent,lpDialogFunc,0L) +#define DialogBoxIndirectA(hInstance,lpTemplate,hWndParent,lpDialogFunc) DialogBoxIndirectParamA(hInstance,lpTemplate,hWndParent,lpDialogFunc,0L) +#define DialogBoxIndirectW(hInstance,lpTemplate,hWndParent,lpDialogFunc) DialogBoxIndirectParamW(hInstance,lpTemplate,hWndParent,lpDialogFunc,0L) + WINUSERAPI WINBOOL WINAPI EndDialog(HWND hDlg,INT_PTR nResult); + WINUSERAPI HWND WINAPI GetDlgItem(HWND hDlg,int nIDDlgItem); + WINUSERAPI WINBOOL WINAPI SetDlgItemInt(HWND hDlg,int nIDDlgItem,UINT uValue,WINBOOL bSigned); + WINUSERAPI UINT WINAPI GetDlgItemInt(HWND hDlg,int nIDDlgItem,WINBOOL *lpTranslated,WINBOOL bSigned); + WINUSERAPI WINBOOL WINAPI SetDlgItemTextA(HWND hDlg,int nIDDlgItem,LPCSTR lpString); + WINUSERAPI WINBOOL WINAPI SetDlgItemTextW(HWND hDlg,int nIDDlgItem,LPCWSTR lpString); + WINUSERAPI UINT WINAPI GetDlgItemTextA(HWND hDlg,int nIDDlgItem,LPSTR lpString,int cchMax); + WINUSERAPI UINT WINAPI GetDlgItemTextW(HWND hDlg,int nIDDlgItem,LPWSTR lpString,int cchMax); + WINUSERAPI WINBOOL WINAPI CheckDlgButton(HWND hDlg,int nIDButton,UINT uCheck); + WINUSERAPI WINBOOL WINAPI CheckRadioButton(HWND hDlg,int nIDFirstButton,int nIDLastButton,int nIDCheckButton); + WINUSERAPI UINT WINAPI IsDlgButtonChecked(HWND hDlg,int nIDButton); + WINUSERAPI LRESULT WINAPI SendDlgItemMessageA(HWND hDlg,int nIDDlgItem,UINT Msg,WPARAM wParam,LPARAM lParam); + WINUSERAPI LRESULT WINAPI SendDlgItemMessageW(HWND hDlg,int nIDDlgItem,UINT Msg,WPARAM wParam,LPARAM lParam); + WINUSERAPI HWND WINAPI GetNextDlgGroupItem(HWND hDlg,HWND hCtl,WINBOOL bPrevious); + WINUSERAPI HWND WINAPI GetNextDlgTabItem(HWND hDlg,HWND hCtl,WINBOOL bPrevious); + WINUSERAPI int WINAPI GetDlgCtrlID(HWND hWnd); + WINUSERAPI long WINAPI GetDialogBaseUnits(VOID); + WINUSERAPI LRESULT WINAPI DefDlgProcA(HWND hDlg,UINT Msg,WPARAM wParam,LPARAM lParam); + WINUSERAPI LRESULT WINAPI DefDlgProcW(HWND hDlg,UINT Msg,WPARAM wParam,LPARAM lParam); + +#define DLGWINDOWEXTRA 30 +#endif + +#ifndef NOMSG + +#ifdef UNICODE +#define CallMsgFilter CallMsgFilterW +#else +#define CallMsgFilter CallMsgFilterA +#endif + + WINUSERAPI WINBOOL WINAPI CallMsgFilterA(LPMSG lpMsg,int nCode); + WINUSERAPI WINBOOL WINAPI CallMsgFilterW(LPMSG lpMsg,int nCode); +#endif + +#ifndef NOCLIPBOARD + +#ifdef UNICODE +#define RegisterClipboardFormat RegisterClipboardFormatW +#define GetClipboardFormatName GetClipboardFormatNameW +#else +#define RegisterClipboardFormat RegisterClipboardFormatA +#define GetClipboardFormatName GetClipboardFormatNameA +#endif + + WINUSERAPI WINBOOL WINAPI OpenClipboard(HWND hWndNewOwner); + WINUSERAPI WINBOOL WINAPI CloseClipboard(VOID); + WINUSERAPI DWORD WINAPI GetClipboardSequenceNumber(VOID); + WINUSERAPI HWND WINAPI GetClipboardOwner(VOID); + WINUSERAPI HWND WINAPI SetClipboardViewer(HWND hWndNewViewer); + WINUSERAPI HWND WINAPI GetClipboardViewer(VOID); + WINUSERAPI WINBOOL WINAPI ChangeClipboardChain(HWND hWndRemove,HWND hWndNewNext); + WINUSERAPI HANDLE WINAPI SetClipboardData(UINT uFormat,HANDLE hMem); + WINUSERAPI HANDLE WINAPI GetClipboardData(UINT uFormat); + WINUSERAPI UINT WINAPI RegisterClipboardFormatA(LPCSTR lpszFormat); + WINUSERAPI UINT WINAPI RegisterClipboardFormatW(LPCWSTR lpszFormat); + WINUSERAPI int WINAPI CountClipboardFormats(VOID); + WINUSERAPI UINT WINAPI EnumClipboardFormats(UINT format); + WINUSERAPI int WINAPI GetClipboardFormatNameA(UINT format,LPSTR lpszFormatName,int cchMaxCount); + WINUSERAPI int WINAPI GetClipboardFormatNameW(UINT format,LPWSTR lpszFormatName,int cchMaxCount); + WINUSERAPI WINBOOL WINAPI EmptyClipboard(VOID); + WINUSERAPI WINBOOL WINAPI IsClipboardFormatAvailable(UINT format); + WINUSERAPI int WINAPI GetPriorityClipboardFormat(UINT *paFormatPriorityList,int cFormats); + WINUSERAPI HWND WINAPI GetOpenClipboardWindow(VOID); +#endif + +#ifdef UNICODE +#define CharToOem CharToOemW +#define OemToChar OemToCharW +#define CharToOemBuff CharToOemBuffW +#define OemToCharBuff OemToCharBuffW +#define CharUpper CharUpperW +#define CharUpperBuff CharUpperBuffW +#define CharLower CharLowerW +#define CharLowerBuff CharLowerBuffW +#define CharNext CharNextW +#define CharPrev CharPrevW +#else +#define CharToOem CharToOemA +#define OemToChar OemToCharA +#define CharToOemBuff CharToOemBuffA +#define OemToCharBuff OemToCharBuffA +#define CharUpper CharUpperA +#define CharUpperBuff CharUpperBuffA +#define CharLower CharLowerA +#define CharLowerBuff CharLowerBuffA +#define CharNext CharNextA +#define CharPrev CharPrevA +#endif + + WINUSERAPI WINBOOL WINAPI CharToOemA(LPCSTR lpszSrc,LPSTR lpszDst); + WINUSERAPI WINBOOL WINAPI CharToOemW(LPCWSTR lpszSrc,LPSTR lpszDst); + WINUSERAPI WINBOOL WINAPI OemToCharA(LPCSTR lpszSrc,LPSTR lpszDst); + WINUSERAPI WINBOOL WINAPI OemToCharW(LPCSTR lpszSrc,LPWSTR lpszDst); + WINUSERAPI WINBOOL WINAPI CharToOemBuffA(LPCSTR lpszSrc,LPSTR lpszDst,DWORD cchDstLength); + WINUSERAPI WINBOOL WINAPI CharToOemBuffW(LPCWSTR lpszSrc,LPSTR lpszDst,DWORD cchDstLength); + WINUSERAPI WINBOOL WINAPI OemToCharBuffA(LPCSTR lpszSrc,LPSTR lpszDst,DWORD cchDstLength); + WINUSERAPI WINBOOL WINAPI OemToCharBuffW(LPCSTR lpszSrc,LPWSTR lpszDst,DWORD cchDstLength); + WINUSERAPI LPSTR WINAPI CharUpperA(LPSTR lpsz); + WINUSERAPI LPWSTR WINAPI CharUpperW(LPWSTR lpsz); + WINUSERAPI DWORD WINAPI CharUpperBuffA(LPSTR lpsz,DWORD cchLength); + WINUSERAPI DWORD WINAPI CharUpperBuffW(LPWSTR lpsz,DWORD cchLength); + WINUSERAPI LPSTR WINAPI CharLowerA(LPSTR lpsz); + WINUSERAPI LPWSTR WINAPI CharLowerW(LPWSTR lpsz); + WINUSERAPI DWORD WINAPI CharLowerBuffA(LPSTR lpsz,DWORD cchLength); + WINUSERAPI DWORD WINAPI CharLowerBuffW(LPWSTR lpsz,DWORD cchLength); + WINUSERAPI LPSTR WINAPI CharNextA(LPCSTR lpsz); + WINUSERAPI LPWSTR WINAPI CharNextW(LPCWSTR lpsz); + WINUSERAPI LPSTR WINAPI CharPrevA(LPCSTR lpszStart,LPCSTR lpszCurrent); + WINUSERAPI LPWSTR WINAPI CharPrevW(LPCWSTR lpszStart,LPCWSTR lpszCurrent); + WINUSERAPI LPSTR WINAPI CharNextExA(WORD CodePage,LPCSTR lpCurrentChar,DWORD dwFlags); + WINUSERAPI LPSTR WINAPI CharPrevExA(WORD CodePage,LPCSTR lpStart,LPCSTR lpCurrentChar,DWORD dwFlags); + +#define AnsiToOem CharToOemA +#define OemToAnsi OemToCharA +#define AnsiToOemBuff CharToOemBuffA +#define OemToAnsiBuff OemToCharBuffA +#define AnsiUpper CharUpperA +#define AnsiUpperBuff CharUpperBuffA +#define AnsiLower CharLowerA +#define AnsiLowerBuff CharLowerBuffA +#define AnsiNext CharNextA +#define AnsiPrev CharPrevA + +#ifndef NOLANGUAGE + +#ifdef UNICODE +#define IsCharAlpha IsCharAlphaW +#define IsCharAlphaNumeric IsCharAlphaNumericW +#define IsCharUpper IsCharUpperW +#define IsCharLower IsCharLowerW +#else +#define IsCharAlpha IsCharAlphaA +#define IsCharAlphaNumeric IsCharAlphaNumericA +#define IsCharUpper IsCharUpperA +#define IsCharLower IsCharLowerA +#endif + + WINUSERAPI WINBOOL WINAPI IsCharAlphaA(CHAR ch); + WINUSERAPI WINBOOL WINAPI IsCharAlphaW(WCHAR ch); + WINUSERAPI WINBOOL WINAPI IsCharAlphaNumericA(CHAR ch); + WINUSERAPI WINBOOL WINAPI IsCharAlphaNumericW(WCHAR ch); + WINUSERAPI WINBOOL WINAPI IsCharUpperA(CHAR ch); + WINUSERAPI WINBOOL WINAPI IsCharUpperW(WCHAR ch); + WINUSERAPI WINBOOL WINAPI IsCharLowerA(CHAR ch); + WINUSERAPI WINBOOL WINAPI IsCharLowerW(WCHAR ch); +#endif + +#ifdef UNICODE +#define GetKeyNameText GetKeyNameTextW +#define VkKeyScan VkKeyScanW +#define VkKeyScanEx VkKeyScanExW +#else +#define GetKeyNameText GetKeyNameTextA +#define VkKeyScan VkKeyScanA +#define VkKeyScanEx VkKeyScanExA +#endif + + WINUSERAPI HWND WINAPI SetFocus(HWND hWnd); + WINUSERAPI HWND WINAPI GetActiveWindow(VOID); + WINUSERAPI HWND WINAPI GetFocus(VOID); + WINUSERAPI UINT WINAPI GetKBCodePage(VOID); + WINUSERAPI SHORT WINAPI GetKeyState(int nVirtKey); + WINUSERAPI SHORT WINAPI GetAsyncKeyState(int vKey); + WINUSERAPI WINBOOL WINAPI GetKeyboardState(PBYTE lpKeyState); + WINUSERAPI WINBOOL WINAPI SetKeyboardState(LPBYTE lpKeyState); + WINUSERAPI int WINAPI GetKeyNameTextA(LONG lParam,LPSTR lpString,int cchSize); + WINUSERAPI int WINAPI GetKeyNameTextW(LONG lParam,LPWSTR lpString,int cchSize); + WINUSERAPI int WINAPI GetKeyboardType(int nTypeFlag); + WINUSERAPI int WINAPI ToAscii(UINT uVirtKey,UINT uScanCode,CONST BYTE *lpKeyState,LPWORD lpChar,UINT uFlags); + WINUSERAPI int WINAPI ToAsciiEx(UINT uVirtKey,UINT uScanCode,CONST BYTE *lpKeyState,LPWORD lpChar,UINT uFlags,HKL dwhkl); + WINUSERAPI int WINAPI ToUnicode(UINT wVirtKey,UINT wScanCode,CONST BYTE *lpKeyState,LPWSTR pwszBuff,int cchBuff,UINT wFlags); + WINUSERAPI DWORD WINAPI OemKeyScan(WORD wOemChar); + WINUSERAPI SHORT WINAPI VkKeyScanA(CHAR ch); + WINUSERAPI SHORT WINAPI VkKeyScanW(WCHAR ch); + WINUSERAPI SHORT WINAPI VkKeyScanExA(CHAR ch,HKL dwhkl); + WINUSERAPI SHORT WINAPI VkKeyScanExW(WCHAR ch,HKL dwhkl); + +#define KEYEVENTF_EXTENDEDKEY 0x0001 +#define KEYEVENTF_KEYUP 0x0002 +#define KEYEVENTF_UNICODE 0x0004 +#define KEYEVENTF_SCANCODE 0x0008 + + WINUSERAPI VOID WINAPI keybd_event(BYTE bVk,BYTE bScan,DWORD dwFlags,ULONG_PTR dwExtraInfo); + +#define MOUSEEVENTF_MOVE 0x0001 +#define MOUSEEVENTF_LEFTDOWN 0x0002 +#define MOUSEEVENTF_LEFTUP 0x0004 +#define MOUSEEVENTF_RIGHTDOWN 0x0008 +#define MOUSEEVENTF_RIGHTUP 0x0010 +#define MOUSEEVENTF_MIDDLEDOWN 0x0020 +#define MOUSEEVENTF_MIDDLEUP 0x0040 +#define MOUSEEVENTF_XDOWN 0x0080 +#define MOUSEEVENTF_XUP 0x0100 +#define MOUSEEVENTF_WHEEL 0x0800 +#define MOUSEEVENTF_VIRTUALDESK 0x4000 +#define MOUSEEVENTF_ABSOLUTE 0x8000 + + WINUSERAPI VOID WINAPI mouse_event(DWORD dwFlags,DWORD dx,DWORD dy,DWORD dwData,ULONG_PTR dwExtraInfo); + + typedef struct tagMOUSEINPUT { + LONG dx; + LONG dy; + DWORD mouseData; + DWORD dwFlags; + DWORD time; + ULONG_PTR dwExtraInfo; + } MOUSEINPUT,*PMOUSEINPUT,*LPMOUSEINPUT; + + typedef struct tagKEYBDINPUT { + WORD wVk; + WORD wScan; + DWORD dwFlags; + DWORD time; + ULONG_PTR dwExtraInfo; + } KEYBDINPUT,*PKEYBDINPUT,*LPKEYBDINPUT; + + typedef struct tagHARDWAREINPUT { + DWORD uMsg; + WORD wParamL; + WORD wParamH; + } HARDWAREINPUT,*PHARDWAREINPUT,*LPHARDWAREINPUT; + +#define INPUT_MOUSE 0 +#define INPUT_KEYBOARD 1 +#define INPUT_HARDWARE 2 + + typedef struct tagINPUT { + DWORD type; + union { + MOUSEINPUT mi; + KEYBDINPUT ki; + HARDWAREINPUT hi; + }; + } INPUT,*PINPUT,*LPINPUT; + + WINUSERAPI UINT WINAPI SendInput(UINT cInputs,LPINPUT pInputs,int cbSize); + + typedef struct tagLASTINPUTINFO { + UINT cbSize; + DWORD dwTime; + } LASTINPUTINFO,*PLASTINPUTINFO; + +#ifdef UNICODE +#define MapVirtualKey MapVirtualKeyW +#define MapVirtualKeyEx MapVirtualKeyExW +#else +#define MapVirtualKey MapVirtualKeyA +#define MapVirtualKeyEx MapVirtualKeyExA +#endif + + WINUSERAPI WINBOOL WINAPI GetLastInputInfo(PLASTINPUTINFO plii); + WINUSERAPI UINT WINAPI MapVirtualKeyA(UINT uCode,UINT uMapType); + WINUSERAPI UINT WINAPI MapVirtualKeyW(UINT uCode,UINT uMapType); + WINUSERAPI UINT WINAPI MapVirtualKeyExA(UINT uCode,UINT uMapType,HKL dwhkl); + WINUSERAPI UINT WINAPI MapVirtualKeyExW(UINT uCode,UINT uMapType,HKL dwhkl); + WINUSERAPI WINBOOL WINAPI GetInputState(VOID); + WINUSERAPI DWORD WINAPI GetQueueStatus(UINT flags); + WINUSERAPI HWND WINAPI GetCapture(VOID); + WINUSERAPI HWND WINAPI SetCapture(HWND hWnd); + WINUSERAPI WINBOOL WINAPI ReleaseCapture(VOID); + WINUSERAPI DWORD WINAPI MsgWaitForMultipleObjects(DWORD nCount,CONST HANDLE *pHandles,WINBOOL fWaitAll,DWORD dwMilliseconds,DWORD dwWakeMask); + WINUSERAPI DWORD WINAPI MsgWaitForMultipleObjectsEx(DWORD nCount,CONST HANDLE *pHandles,DWORD dwMilliseconds,DWORD dwWakeMask,DWORD dwFlags); + +#define MWMO_WAITALL 0x0001 +#define MWMO_ALERTABLE 0x0002 +#define MWMO_INPUTAVAILABLE 0x0004 + +#define QS_KEY 0x0001 +#define QS_MOUSEMOVE 0x0002 +#define QS_MOUSEBUTTON 0x0004 +#define QS_POSTMESSAGE 0x0008 +#define QS_TIMER 0x0010 +#define QS_PAINT 0x0020 +#define QS_SENDMESSAGE 0x0040 +#define QS_HOTKEY 0x0080 +#define QS_ALLPOSTMESSAGE 0x0100 +#define QS_RAWINPUT 0x0400 +#define QS_MOUSE (QS_MOUSEMOVE | QS_MOUSEBUTTON) +#define QS_INPUT (QS_MOUSE | QS_KEY | QS_RAWINPUT) +#define QS_ALLEVENTS (QS_INPUT | QS_POSTMESSAGE | QS_TIMER | QS_PAINT | QS_HOTKEY) +#define QS_ALLINPUT (QS_INPUT | QS_POSTMESSAGE | QS_TIMER | QS_PAINT | QS_HOTKEY | QS_SENDMESSAGE) + +#define USER_TIMER_MAXIMUM 0x7FFFFFFF +#define USER_TIMER_MINIMUM 0x0000000A + +#ifdef UNICODE +#define LoadAccelerators LoadAcceleratorsW +#define CreateAcceleratorTable CreateAcceleratorTableW +#define CopyAcceleratorTable CopyAcceleratorTableW +#else +#define LoadAccelerators LoadAcceleratorsA +#define CreateAcceleratorTable CreateAcceleratorTableA +#define CopyAcceleratorTable CopyAcceleratorTableA +#endif + + WINUSERAPI UINT_PTR WINAPI SetTimer(HWND hWnd,UINT_PTR nIDEvent,UINT uElapse,TIMERPROC lpTimerFunc); + WINUSERAPI WINBOOL WINAPI KillTimer(HWND hWnd,UINT_PTR uIDEvent); + WINUSERAPI WINBOOL WINAPI IsWindowUnicode(HWND hWnd); + WINUSERAPI WINBOOL WINAPI EnableWindow(HWND hWnd,WINBOOL bEnable); + WINUSERAPI WINBOOL WINAPI IsWindowEnabled(HWND hWnd); + WINUSERAPI HACCEL WINAPI LoadAcceleratorsA(HINSTANCE hInstance,LPCSTR lpTableName); + WINUSERAPI HACCEL WINAPI LoadAcceleratorsW(HINSTANCE hInstance,LPCWSTR lpTableName); + WINUSERAPI HACCEL WINAPI CreateAcceleratorTableA(LPACCEL paccel,int cAccel); + WINUSERAPI HACCEL WINAPI CreateAcceleratorTableW(LPACCEL paccel,int cAccel); + WINUSERAPI WINBOOL WINAPI DestroyAcceleratorTable(HACCEL hAccel); + WINUSERAPI int WINAPI CopyAcceleratorTableA(HACCEL hAccelSrc,LPACCEL lpAccelDst,int cAccelEntries); + WINUSERAPI int WINAPI CopyAcceleratorTableW(HACCEL hAccelSrc,LPACCEL lpAccelDst,int cAccelEntries); + +#ifndef NOMSG + +#ifdef UNICODE +#define TranslateAccelerator TranslateAcceleratorW +#else +#define TranslateAccelerator TranslateAcceleratorA +#endif + + WINUSERAPI int WINAPI TranslateAcceleratorA(HWND hWnd,HACCEL hAccTable,LPMSG lpMsg); + WINUSERAPI int WINAPI TranslateAcceleratorW(HWND hWnd,HACCEL hAccTable,LPMSG lpMsg); +#endif + +#ifndef NOSYSMETRICS + +#define SM_CXSCREEN 0 +#define SM_CYSCREEN 1 +#define SM_CXVSCROLL 2 +#define SM_CYHSCROLL 3 +#define SM_CYCAPTION 4 +#define SM_CXBORDER 5 +#define SM_CYBORDER 6 +#define SM_CXDLGFRAME 7 +#define SM_CYDLGFRAME 8 +#define SM_CYVTHUMB 9 +#define SM_CXHTHUMB 10 +#define SM_CXICON 11 +#define SM_CYICON 12 +#define SM_CXCURSOR 13 +#define SM_CYCURSOR 14 +#define SM_CYMENU 15 +#define SM_CXFULLSCREEN 16 +#define SM_CYFULLSCREEN 17 +#define SM_CYKANJIWINDOW 18 +#define SM_MOUSEPRESENT 19 +#define SM_CYVSCROLL 20 +#define SM_CXHSCROLL 21 +#define SM_DEBUG 22 +#define SM_SWAPBUTTON 23 +#define SM_RESERVED1 24 +#define SM_RESERVED2 25 +#define SM_RESERVED3 26 +#define SM_RESERVED4 27 +#define SM_CXMIN 28 +#define SM_CYMIN 29 +#define SM_CXSIZE 30 +#define SM_CYSIZE 31 +#define SM_CXFRAME 32 +#define SM_CYFRAME 33 +#define SM_CXMINTRACK 34 +#define SM_CYMINTRACK 35 +#define SM_CXDOUBLECLK 36 +#define SM_CYDOUBLECLK 37 +#define SM_CXICONSPACING 38 +#define SM_CYICONSPACING 39 +#define SM_MENUDROPALIGNMENT 40 +#define SM_PENWINDOWS 41 +#define SM_DBCSENABLED 42 +#define SM_CMOUSEBUTTONS 43 + +#define SM_CXFIXEDFRAME SM_CXDLGFRAME +#define SM_CYFIXEDFRAME SM_CYDLGFRAME +#define SM_CXSIZEFRAME SM_CXFRAME +#define SM_CYSIZEFRAME SM_CYFRAME + +#define SM_SECURE 44 +#define SM_CXEDGE 45 +#define SM_CYEDGE 46 +#define SM_CXMINSPACING 47 +#define SM_CYMINSPACING 48 +#define SM_CXSMICON 49 +#define SM_CYSMICON 50 +#define SM_CYSMCAPTION 51 +#define SM_CXSMSIZE 52 +#define SM_CYSMSIZE 53 +#define SM_CXMENUSIZE 54 +#define SM_CYMENUSIZE 55 +#define SM_ARRANGE 56 +#define SM_CXMINIMIZED 57 +#define SM_CYMINIMIZED 58 +#define SM_CXMAXTRACK 59 +#define SM_CYMAXTRACK 60 +#define SM_CXMAXIMIZED 61 +#define SM_CYMAXIMIZED 62 +#define SM_NETWORK 63 +#define SM_CLEANBOOT 67 +#define SM_CXDRAG 68 +#define SM_CYDRAG 69 +#define SM_SHOWSOUNDS 70 +#define SM_CXMENUCHECK 71 +#define SM_CYMENUCHECK 72 +#define SM_SLOWMACHINE 73 +#define SM_MIDEASTENABLED 74 +#define SM_MOUSEWHEELPRESENT 75 +#define SM_XVIRTUALSCREEN 76 +#define SM_YVIRTUALSCREEN 77 +#define SM_CXVIRTUALSCREEN 78 +#define SM_CYVIRTUALSCREEN 79 +#define SM_CMONITORS 80 +#define SM_SAMEDISPLAYFORMAT 81 +#define SM_IMMENABLED 82 +#define SM_CXFOCUSBORDER 83 +#define SM_CYFOCUSBORDER 84 +#define SM_TABLETPC 86 +#define SM_MEDIACENTER 87 +#define SM_STARTER 88 +#define SM_SERVERR2 89 +#define SM_CMETRICS 90 +#define SM_REMOTESESSION 0x1000 +#define SM_SHUTTINGDOWN 0x2000 +#define SM_REMOTECONTROL 0x2001 +#define SM_CARETBLINKINGENABLED 0x2002 + + WINUSERAPI int WINAPI GetSystemMetrics(int nIndex); +#endif + +#ifndef NOMENUS + +#ifdef UNICODE +#define LoadMenu LoadMenuW +#define LoadMenuIndirect LoadMenuIndirectW +#define ChangeMenu ChangeMenuW +#define GetMenuString GetMenuStringW +#define InsertMenu InsertMenuW +#define AppendMenu AppendMenuW +#define ModifyMenu ModifyMenuW +#else +#define LoadMenu LoadMenuA +#define LoadMenuIndirect LoadMenuIndirectA +#define ChangeMenu ChangeMenuA +#define GetMenuString GetMenuStringA +#define InsertMenu InsertMenuA +#define AppendMenu AppendMenuA +#define ModifyMenu ModifyMenuA +#endif + + WINUSERAPI HMENU WINAPI LoadMenuA(HINSTANCE hInstance,LPCSTR lpMenuName); + WINUSERAPI HMENU WINAPI LoadMenuW(HINSTANCE hInstance,LPCWSTR lpMenuName); + WINUSERAPI HMENU WINAPI LoadMenuIndirectA(CONST MENUTEMPLATEA *lpMenuTemplate); + WINUSERAPI HMENU WINAPI LoadMenuIndirectW(CONST MENUTEMPLATEW *lpMenuTemplate); + WINUSERAPI HMENU WINAPI GetMenu(HWND hWnd); + WINUSERAPI WINBOOL WINAPI SetMenu(HWND hWnd,HMENU hMenu); + WINUSERAPI WINBOOL WINAPI ChangeMenuA(HMENU hMenu,UINT cmd,LPCSTR lpszNewItem,UINT cmdInsert,UINT flags); + WINUSERAPI WINBOOL WINAPI ChangeMenuW(HMENU hMenu,UINT cmd,LPCWSTR lpszNewItem,UINT cmdInsert,UINT flags); + WINUSERAPI WINBOOL WINAPI HiliteMenuItem(HWND hWnd,HMENU hMenu,UINT uIDHiliteItem,UINT uHilite); + WINUSERAPI int WINAPI GetMenuStringA(HMENU hMenu,UINT uIDItem,LPSTR lpString,int cchMax,UINT flags); + WINUSERAPI int WINAPI GetMenuStringW(HMENU hMenu,UINT uIDItem,LPWSTR lpString,int cchMax,UINT flags); + WINUSERAPI UINT WINAPI GetMenuState(HMENU hMenu,UINT uId,UINT uFlags); + WINUSERAPI WINBOOL WINAPI DrawMenuBar(HWND hWnd); + +#define PMB_ACTIVE 0x00000001 + + WINUSERAPI HMENU WINAPI GetSystemMenu(HWND hWnd,WINBOOL bRevert); + WINUSERAPI HMENU WINAPI CreateMenu(VOID); + WINUSERAPI HMENU WINAPI CreatePopupMenu(VOID); + WINUSERAPI WINBOOL WINAPI DestroyMenu(HMENU hMenu); + WINUSERAPI DWORD WINAPI CheckMenuItem(HMENU hMenu,UINT uIDCheckItem,UINT uCheck); + WINUSERAPI WINBOOL WINAPI EnableMenuItem(HMENU hMenu,UINT uIDEnableItem,UINT uEnable); + WINUSERAPI HMENU WINAPI GetSubMenu(HMENU hMenu,int nPos); + WINUSERAPI UINT WINAPI GetMenuItemID(HMENU hMenu,int nPos); + WINUSERAPI int WINAPI GetMenuItemCount(HMENU hMenu); + WINUSERAPI WINBOOL WINAPI InsertMenuA(HMENU hMenu,UINT uPosition,UINT uFlags,UINT_PTR uIDNewItem,LPCSTR lpNewItem); + WINUSERAPI WINBOOL WINAPI InsertMenuW(HMENU hMenu,UINT uPosition,UINT uFlags,UINT_PTR uIDNewItem,LPCWSTR lpNewItem); + WINUSERAPI WINBOOL WINAPI AppendMenuA(HMENU hMenu,UINT uFlags,UINT_PTR uIDNewItem,LPCSTR lpNewItem); + WINUSERAPI WINBOOL WINAPI AppendMenuW(HMENU hMenu,UINT uFlags,UINT_PTR uIDNewItem,LPCWSTR lpNewItem); + WINUSERAPI WINBOOL WINAPI ModifyMenuA(HMENU hMnu,UINT uPosition,UINT uFlags,UINT_PTR uIDNewItem,LPCSTR lpNewItem); + WINUSERAPI WINBOOL WINAPI ModifyMenuW(HMENU hMnu,UINT uPosition,UINT uFlags,UINT_PTR uIDNewItem,LPCWSTR lpNewItem); + WINUSERAPI WINBOOL WINAPI RemoveMenu(HMENU hMenu,UINT uPosition,UINT uFlags); + WINUSERAPI WINBOOL WINAPI DeleteMenu(HMENU hMenu,UINT uPosition,UINT uFlags); + WINUSERAPI WINBOOL WINAPI SetMenuItemBitmaps(HMENU hMenu,UINT uPosition,UINT uFlags,HBITMAP hBitmapUnchecked,HBITMAP hBitmapChecked); + WINUSERAPI LONG WINAPI GetMenuCheckMarkDimensions(VOID); + WINUSERAPI WINBOOL WINAPI TrackPopupMenu(HMENU hMenu,UINT uFlags,int x,int y,int nReserved,HWND hWnd,CONST RECT *prcRect); + +#define MNC_IGNORE 0 +#define MNC_CLOSE 1 +#define MNC_EXECUTE 2 +#define MNC_SELECT 3 + + typedef struct tagTPMPARAMS { + UINT cbSize; + RECT rcExclude; + } TPMPARAMS; + + typedef TPMPARAMS *LPTPMPARAMS; + + WINUSERAPI WINBOOL WINAPI TrackPopupMenuEx(HMENU,UINT,int,int,HWND,LPTPMPARAMS); + +#define MNS_NOCHECK 0x80000000 +#define MNS_MODELESS 0x40000000 +#define MNS_DRAGDROP 0x20000000 +#define MNS_AUTODISMISS 0x10000000 +#define MNS_NOTIFYBYPOS 0x08000000 +#define MNS_CHECKORBMP 0x04000000 + +#define MIM_MAXHEIGHT 0x00000001 +#define MIM_BACKGROUND 0x00000002 +#define MIM_HELPID 0x00000004 +#define MIM_MENUDATA 0x00000008 +#define MIM_STYLE 0x00000010 +#define MIM_APPLYTOSUBMENUS 0x80000000 + + typedef struct tagMENUINFO { + DWORD cbSize; + DWORD fMask; + DWORD dwStyle; + UINT cyMax; + HBRUSH hbrBack; + DWORD dwContextHelpID; + ULONG_PTR dwMenuData; + } MENUINFO,*LPMENUINFO; + + typedef MENUINFO CONST *LPCMENUINFO; + + WINUSERAPI WINBOOL WINAPI GetMenuInfo(HMENU,LPMENUINFO); + WINUSERAPI WINBOOL WINAPI SetMenuInfo(HMENU,LPCMENUINFO); + WINUSERAPI WINBOOL WINAPI EndMenu(VOID); + +#define MND_CONTINUE 0 +#define MND_ENDMENU 1 + + typedef struct tagMENUGETOBJECTINFO { + DWORD dwFlags; + UINT uPos; + HMENU hmenu; + PVOID riid; + PVOID pvObj; + } MENUGETOBJECTINFO,*PMENUGETOBJECTINFO; + +#define MNGOF_TOPGAP 0x00000001 +#define MNGOF_BOTTOMGAP 0x00000002 + +#define MNGO_NOINTERFACE 0x00000000 +#define MNGO_NOERROR 0x00000001 + +#define MIIM_STATE 0x00000001 +#define MIIM_ID 0x00000002 +#define MIIM_SUBMENU 0x00000004 +#define MIIM_CHECKMARKS 0x00000008 +#define MIIM_TYPE 0x00000010 +#define MIIM_DATA 0x00000020 + +#define MIIM_STRING 0x00000040 +#define MIIM_BITMAP 0x00000080 +#define MIIM_FTYPE 0x00000100 + +#define HBMMENU_CALLBACK ((HBITMAP) -1) +#define HBMMENU_SYSTEM ((HBITMAP) 1) +#define HBMMENU_MBAR_RESTORE ((HBITMAP) 2) +#define HBMMENU_MBAR_MINIMIZE ((HBITMAP) 3) +#define HBMMENU_MBAR_CLOSE ((HBITMAP) 5) +#define HBMMENU_MBAR_CLOSE_D ((HBITMAP) 6) +#define HBMMENU_MBAR_MINIMIZE_D ((HBITMAP) 7) +#define HBMMENU_POPUP_CLOSE ((HBITMAP) 8) +#define HBMMENU_POPUP_RESTORE ((HBITMAP) 9) +#define HBMMENU_POPUP_MAXIMIZE ((HBITMAP) 10) +#define HBMMENU_POPUP_MINIMIZE ((HBITMAP) 11) + + typedef struct tagMENUITEMINFOA { + UINT cbSize; + UINT fMask; + UINT fType; + UINT fState; + UINT wID; + HMENU hSubMenu; + HBITMAP hbmpChecked; + HBITMAP hbmpUnchecked; + ULONG_PTR dwItemData; + LPSTR dwTypeData; + UINT cch; + HBITMAP hbmpItem; + } MENUITEMINFOA,*LPMENUITEMINFOA; + + typedef struct tagMENUITEMINFOW { + UINT cbSize; + UINT fMask; + UINT fType; + UINT fState; + UINT wID; + HMENU hSubMenu; + HBITMAP hbmpChecked; + HBITMAP hbmpUnchecked; + ULONG_PTR dwItemData; + LPWSTR dwTypeData; + UINT cch; + HBITMAP hbmpItem; + } MENUITEMINFOW,*LPMENUITEMINFOW; + +#ifdef UNICODE + typedef MENUITEMINFOW MENUITEMINFO; + typedef LPMENUITEMINFOW LPMENUITEMINFO; +#else + typedef MENUITEMINFOA MENUITEMINFO; + typedef LPMENUITEMINFOA LPMENUITEMINFO; +#endif + typedef MENUITEMINFOA CONST *LPCMENUITEMINFOA; + typedef MENUITEMINFOW CONST *LPCMENUITEMINFOW; +#ifdef UNICODE + typedef LPCMENUITEMINFOW LPCMENUITEMINFO; +#else + typedef LPCMENUITEMINFOA LPCMENUITEMINFO; +#endif + +#ifdef UNICODE +#define InsertMenuItem InsertMenuItemW +#define GetMenuItemInfo GetMenuItemInfoW +#define SetMenuItemInfo SetMenuItemInfoW +#else +#define InsertMenuItem InsertMenuItemA +#define GetMenuItemInfo GetMenuItemInfoA +#define SetMenuItemInfo SetMenuItemInfoA +#endif + + WINUSERAPI WINBOOL WINAPI InsertMenuItemA(HMENU hmenu,UINT item,WINBOOL fByPosition,LPCMENUITEMINFOA lpmi); + WINUSERAPI WINBOOL WINAPI InsertMenuItemW(HMENU hmenu,UINT item,WINBOOL fByPosition,LPCMENUITEMINFOW lpmi); + WINUSERAPI WINBOOL WINAPI GetMenuItemInfoA(HMENU hmenu,UINT item,WINBOOL fByPosition,LPMENUITEMINFOA lpmii); + WINUSERAPI WINBOOL WINAPI GetMenuItemInfoW(HMENU hmenu,UINT item,WINBOOL fByPosition,LPMENUITEMINFOW lpmii); + WINUSERAPI WINBOOL WINAPI SetMenuItemInfoA(HMENU hmenu,UINT item,WINBOOL fByPositon,LPCMENUITEMINFOA lpmii); + WINUSERAPI WINBOOL WINAPI SetMenuItemInfoW(HMENU hmenu,UINT item,WINBOOL fByPositon,LPCMENUITEMINFOW lpmii); + +#define GMDI_USEDISABLED 0x0001L +#define GMDI_GOINTOPOPUPS 0x0002L + + WINUSERAPI UINT WINAPI GetMenuDefaultItem(HMENU hMenu,UINT fByPos,UINT gmdiFlags); + WINUSERAPI WINBOOL WINAPI SetMenuDefaultItem(HMENU hMenu,UINT uItem,UINT fByPos); + WINUSERAPI WINBOOL WINAPI GetMenuItemRect(HWND hWnd,HMENU hMenu,UINT uItem,LPRECT lprcItem); + WINUSERAPI int WINAPI MenuItemFromPoint(HWND hWnd,HMENU hMenu,POINT ptScreen); + +#define TPM_LEFTBUTTON 0x0000L +#define TPM_RIGHTBUTTON 0x0002L +#define TPM_LEFTALIGN 0x0000L +#define TPM_CENTERALIGN 0x0004L +#define TPM_RIGHTALIGN 0x0008L +#define TPM_TOPALIGN 0x0000L +#define TPM_VCENTERALIGN 0x0010L +#define TPM_BOTTOMALIGN 0x0020L + +#define TPM_HORIZONTAL 0x0000L +#define TPM_VERTICAL 0x0040L +#define TPM_NONOTIFY 0x0080L +#define TPM_RETURNCMD 0x0100L +#define TPM_RECURSE 0x0001L +#define TPM_HORPOSANIMATION 0x0400L +#define TPM_HORNEGANIMATION 0x0800L +#define TPM_VERPOSANIMATION 0x1000L +#define TPM_VERNEGANIMATION 0x2000L +#define TPM_NOANIMATION 0x4000L +#define TPM_LAYOUTRTL 0x8000L +#endif + + typedef struct tagDROPSTRUCT { + HWND hwndSource; + HWND hwndSink; + DWORD wFmt; + ULONG_PTR dwData; + POINT ptDrop; + DWORD dwControlData; + } DROPSTRUCT,*PDROPSTRUCT,*LPDROPSTRUCT; + +#define DOF_EXECUTABLE 0x8001 +#define DOF_DOCUMENT 0x8002 +#define DOF_DIRECTORY 0x8003 +#define DOF_MULTIPLE 0x8004 +#define DOF_PROGMAN 0x0001 +#define DOF_SHELLDATA 0x0002 + +#define DO_DROPFILE 0x454C4946L +#define DO_PRINTFILE 0x544E5250L + + WINUSERAPI DWORD WINAPI DragObject(HWND hwndParent,HWND hwndFrom,UINT fmt,ULONG_PTR data,HCURSOR hcur); + WINUSERAPI WINBOOL WINAPI DragDetect(HWND hwnd,POINT pt); + WINUSERAPI WINBOOL WINAPI DrawIcon(HDC hDC,int X,int Y,HICON hIcon); + +#ifndef NODRAWTEXT + +#define DT_TOP 0x00000000 +#define DT_LEFT 0x00000000 +#define DT_CENTER 0x00000001 +#define DT_RIGHT 0x00000002 +#define DT_VCENTER 0x00000004 +#define DT_BOTTOM 0x00000008 +#define DT_WORDBREAK 0x00000010 +#define DT_SINGLELINE 0x00000020 +#define DT_EXPANDTABS 0x00000040 +#define DT_TABSTOP 0x00000080 +#define DT_NOCLIP 0x00000100 +#define DT_EXTERNALLEADING 0x00000200 +#define DT_CALCRECT 0x00000400 +#define DT_NOPREFIX 0x00000800 +#define DT_INTERNAL 0x00001000 + +#define DT_EDITCONTROL 0x00002000 +#define DT_PATH_ELLIPSIS 0x00004000 +#define DT_END_ELLIPSIS 0x00008000 +#define DT_MODIFYSTRING 0x00010000 +#define DT_RTLREADING 0x00020000 +#define DT_WORD_ELLIPSIS 0x00040000 +#define DT_NOFULLWIDTHCHARBREAK 0x00080000 +#define DT_HIDEPREFIX 0x00100000 +#define DT_PREFIXONLY 0x00200000 + + typedef struct tagDRAWTEXTPARAMS { + UINT cbSize; + int iTabLength; + int iLeftMargin; + int iRightMargin; + UINT uiLengthDrawn; + } DRAWTEXTPARAMS,*LPDRAWTEXTPARAMS; + +#ifdef UNICODE +#define DrawText DrawTextW +#define DrawTextEx DrawTextExW +#else +#define DrawText DrawTextA +#define DrawTextEx DrawTextExA +#endif + + WINUSERAPI int WINAPI DrawTextA(HDC hdc,LPCSTR lpchText,int cchText,LPRECT lprc,UINT format); + WINUSERAPI int WINAPI DrawTextW(HDC hdc,LPCWSTR lpchText,int cchText,LPRECT lprc,UINT format); + WINUSERAPI int WINAPI DrawTextExA(HDC hdc,LPSTR lpchText,int cchText,LPRECT lprc,UINT format,LPDRAWTEXTPARAMS lpdtp); + WINUSERAPI int WINAPI DrawTextExW(HDC hdc,LPWSTR lpchText,int cchText,LPRECT lprc,UINT format,LPDRAWTEXTPARAMS lpdtp); +#endif + +#ifdef UNICODE +#define GrayString GrayStringW +#define DrawState DrawStateW +#define TabbedTextOut TabbedTextOutW +#define GetTabbedTextExtent GetTabbedTextExtentW +#else +#define GrayString GrayStringA +#define DrawState DrawStateA +#define TabbedTextOut TabbedTextOutA +#define GetTabbedTextExtent GetTabbedTextExtentA +#endif + + WINUSERAPI WINBOOL WINAPI GrayStringA(HDC hDC,HBRUSH hBrush,GRAYSTRINGPROC lpOutputFunc,LPARAM lpData,int nCount,int X,int Y,int nWidth,int nHeight); + WINUSERAPI WINBOOL WINAPI GrayStringW(HDC hDC,HBRUSH hBrush,GRAYSTRINGPROC lpOutputFunc,LPARAM lpData,int nCount,int X,int Y,int nWidth,int nHeight); + +#define DST_COMPLEX 0x0000 +#define DST_TEXT 0x0001 +#define DST_PREFIXTEXT 0x0002 +#define DST_ICON 0x0003 +#define DST_BITMAP 0x0004 + +#define DSS_NORMAL 0x0000 +#define DSS_UNION 0x0010 +#define DSS_DISABLED 0x0020 +#define DSS_MONO 0x0080 +#define DSS_HIDEPREFIX 0x0200 +#define DSS_PREFIXONLY 0x0400 +#define DSS_RIGHT 0x8000 + + WINUSERAPI WINBOOL WINAPI DrawStateA(HDC hdc,HBRUSH hbrFore,DRAWSTATEPROC qfnCallBack,LPARAM lData,WPARAM wData,int x,int y,int cx,int cy,UINT uFlags); + WINUSERAPI WINBOOL WINAPI DrawStateW(HDC hdc,HBRUSH hbrFore,DRAWSTATEPROC qfnCallBack,LPARAM lData,WPARAM wData,int x,int y,int cx,int cy,UINT uFlags); + WINUSERAPI LONG WINAPI TabbedTextOutA(HDC hdc,int x,int y,LPCSTR lpString,int chCount,int nTabPositions,CONST INT *lpnTabStopPositions,int nTabOrigin); + WINUSERAPI LONG WINAPI TabbedTextOutW(HDC hdc,int x,int y,LPCWSTR lpString,int chCount,int nTabPositions,CONST INT *lpnTabStopPositions,int nTabOrigin); + WINUSERAPI DWORD WINAPI GetTabbedTextExtentA(HDC hdc,LPCSTR lpString,int chCount,int nTabPositions,CONST INT *lpnTabStopPositions); + WINUSERAPI DWORD WINAPI GetTabbedTextExtentW(HDC hdc,LPCWSTR lpString,int chCount,int nTabPositions,CONST INT *lpnTabStopPositions); + WINUSERAPI WINBOOL WINAPI UpdateWindow(HWND hWnd); + WINUSERAPI HWND WINAPI SetActiveWindow(HWND hWnd); + WINUSERAPI HWND WINAPI GetForegroundWindow(VOID); + WINUSERAPI WINBOOL WINAPI PaintDesktop(HDC hdc); + WINUSERAPI VOID WINAPI SwitchToThisWindow(HWND hwnd,WINBOOL fUnknown); + WINUSERAPI WINBOOL WINAPI SetForegroundWindow(HWND hWnd); + WINUSERAPI WINBOOL WINAPI AllowSetForegroundWindow(DWORD dwProcessId); + +#define ASFW_ANY ((DWORD)-1) + + WINUSERAPI WINBOOL WINAPI LockSetForegroundWindow(UINT uLockCode); + +#define LSFW_LOCK 1 +#define LSFW_UNLOCK 2 + + WINUSERAPI HWND WINAPI WindowFromDC(HDC hDC); + WINUSERAPI HDC WINAPI GetDC(HWND hWnd); + WINUSERAPI HDC WINAPI GetDCEx(HWND hWnd,HRGN hrgnClip,DWORD flags); + +#define DCX_WINDOW 0x00000001L +#define DCX_CACHE 0x00000002L +#define DCX_NORESETATTRS 0x00000004L +#define DCX_CLIPCHILDREN 0x00000008L +#define DCX_CLIPSIBLINGS 0x00000010L +#define DCX_PARENTCLIP 0x00000020L +#define DCX_EXCLUDERGN 0x00000040L +#define DCX_INTERSECTRGN 0x00000080L +#define DCX_EXCLUDEUPDATE 0x00000100L +#define DCX_INTERSECTUPDATE 0x00000200L +#define DCX_LOCKWINDOWUPDATE 0x00000400L + +#define DCX_VALIDATE 0x00200000L + + WINUSERAPI HDC WINAPI GetWindowDC(HWND hWnd); + WINUSERAPI int WINAPI ReleaseDC(HWND hWnd,HDC hDC); + WINUSERAPI HDC WINAPI BeginPaint(HWND hWnd,LPPAINTSTRUCT lpPaint); + WINUSERAPI WINBOOL WINAPI EndPaint(HWND hWnd,CONST PAINTSTRUCT *lpPaint); + WINUSERAPI WINBOOL WINAPI GetUpdateRect(HWND hWnd,LPRECT lpRect,WINBOOL bErase); + WINUSERAPI int WINAPI GetUpdateRgn(HWND hWnd,HRGN hRgn,WINBOOL bErase); + WINUSERAPI int WINAPI SetWindowRgn(HWND hWnd,HRGN hRgn,WINBOOL bRedraw); + WINUSERAPI int WINAPI GetWindowRgn(HWND hWnd,HRGN hRgn); + WINUSERAPI int WINAPI GetWindowRgnBox(HWND hWnd,LPRECT lprc); + WINUSERAPI int WINAPI ExcludeUpdateRgn(HDC hDC,HWND hWnd); + WINUSERAPI WINBOOL WINAPI InvalidateRect(HWND hWnd,CONST RECT *lpRect,WINBOOL bErase); + WINUSERAPI WINBOOL WINAPI ValidateRect(HWND hWnd,CONST RECT *lpRect); + WINUSERAPI WINBOOL WINAPI InvalidateRgn(HWND hWnd,HRGN hRgn,WINBOOL bErase); + WINUSERAPI WINBOOL WINAPI ValidateRgn(HWND hWnd,HRGN hRgn); + WINUSERAPI WINBOOL WINAPI RedrawWindow(HWND hWnd,CONST RECT *lprcUpdate,HRGN hrgnUpdate,UINT flags); + +#define RDW_INVALIDATE 0x0001 +#define RDW_INTERNALPAINT 0x0002 +#define RDW_ERASE 0x0004 + +#define RDW_VALIDATE 0x0008 +#define RDW_NOINTERNALPAINT 0x0010 +#define RDW_NOERASE 0x0020 + +#define RDW_NOCHILDREN 0x0040 +#define RDW_ALLCHILDREN 0x0080 + +#define RDW_UPDATENOW 0x0100 +#define RDW_ERASENOW 0x0200 + +#define RDW_FRAME 0x0400 +#define RDW_NOFRAME 0x0800 + + WINUSERAPI WINBOOL WINAPI LockWindowUpdate(HWND hWndLock); + WINUSERAPI WINBOOL WINAPI ScrollWindow(HWND hWnd,int XAmount,int YAmount,CONST RECT *lpRect,CONST RECT *lpClipRect); + WINUSERAPI WINBOOL WINAPI ScrollDC(HDC hDC,int dx,int dy,CONST RECT *lprcScroll,CONST RECT *lprcClip,HRGN hrgnUpdate,LPRECT lprcUpdate); + WINUSERAPI int WINAPI ScrollWindowEx(HWND hWnd,int dx,int dy,CONST RECT *prcScroll,CONST RECT *prcClip,HRGN hrgnUpdate,LPRECT prcUpdate,UINT flags); + +#define SW_SCROLLCHILDREN 0x0001 +#define SW_INVALIDATE 0x0002 +#define SW_ERASE 0x0004 +#define SW_SMOOTHSCROLL 0x0010 + +#ifndef NOSCROLL + WINUSERAPI int WINAPI SetScrollPos(HWND hWnd,int nBar,int nPos,WINBOOL bRedraw); + WINUSERAPI int WINAPI GetScrollPos(HWND hWnd,int nBar); + WINUSERAPI WINBOOL WINAPI SetScrollRange(HWND hWnd,int nBar,int nMinPos,int nMaxPos,WINBOOL bRedraw); + WINUSERAPI WINBOOL WINAPI GetScrollRange(HWND hWnd,int nBar,LPINT lpMinPos,LPINT lpMaxPos); + WINUSERAPI WINBOOL WINAPI ShowScrollBar(HWND hWnd,int wBar,WINBOOL bShow); + WINUSERAPI WINBOOL WINAPI EnableScrollBar(HWND hWnd,UINT wSBflags,UINT wArrows); + +#define ESB_ENABLE_BOTH 0x0000 +#define ESB_DISABLE_BOTH 0x0003 + +#define ESB_DISABLE_LEFT 0x0001 +#define ESB_DISABLE_RIGHT 0x0002 + +#define ESB_DISABLE_UP 0x0001 +#define ESB_DISABLE_DOWN 0x0002 + +#define ESB_DISABLE_LTUP ESB_DISABLE_LEFT +#define ESB_DISABLE_RTDN ESB_DISABLE_RIGHT +#endif + +#ifdef UNICODE +#define SetProp SetPropW +#define GetProp GetPropW +#define RemoveProp RemovePropW +#define EnumPropsEx EnumPropsExW +#define EnumProps EnumPropsW +#define SetWindowText SetWindowTextW +#define GetWindowText GetWindowTextW +#define GetWindowTextLength GetWindowTextLengthW +#else +#define SetProp SetPropA +#define GetProp GetPropA +#define RemoveProp RemovePropA +#define EnumPropsEx EnumPropsExA +#define EnumProps EnumPropsA +#define SetWindowText SetWindowTextA +#define GetWindowText GetWindowTextA +#define GetWindowTextLength GetWindowTextLengthA +#endif + + WINUSERAPI WINBOOL WINAPI SetPropA(HWND hWnd,LPCSTR lpString,HANDLE hData); + WINUSERAPI WINBOOL WINAPI SetPropW(HWND hWnd,LPCWSTR lpString,HANDLE hData); + WINUSERAPI HANDLE WINAPI GetPropA(HWND hWnd,LPCSTR lpString); + WINUSERAPI HANDLE WINAPI GetPropW(HWND hWnd,LPCWSTR lpString); + WINUSERAPI HANDLE WINAPI RemovePropA(HWND hWnd,LPCSTR lpString); + WINUSERAPI HANDLE WINAPI RemovePropW(HWND hWnd,LPCWSTR lpString); + WINUSERAPI int WINAPI EnumPropsExA(HWND hWnd,PROPENUMPROCEXA lpEnumFunc,LPARAM lParam); + WINUSERAPI int WINAPI EnumPropsExW(HWND hWnd,PROPENUMPROCEXW lpEnumFunc,LPARAM lParam); + WINUSERAPI int WINAPI EnumPropsA(HWND hWnd,PROPENUMPROCA lpEnumFunc); + WINUSERAPI int WINAPI EnumPropsW(HWND hWnd,PROPENUMPROCW lpEnumFunc); + WINUSERAPI WINBOOL WINAPI SetWindowTextA(HWND hWnd,LPCSTR lpString); + WINUSERAPI WINBOOL WINAPI SetWindowTextW(HWND hWnd,LPCWSTR lpString); + WINUSERAPI int WINAPI GetWindowTextA(HWND hWnd,LPSTR lpString,int nMaxCount); + WINUSERAPI int WINAPI GetWindowTextW(HWND hWnd,LPWSTR lpString,int nMaxCount); + WINUSERAPI int WINAPI GetWindowTextLengthA(HWND hWnd); + WINUSERAPI int WINAPI GetWindowTextLengthW(HWND hWnd); + WINUSERAPI WINBOOL WINAPI GetClientRect(HWND hWnd,LPRECT lpRect); + WINUSERAPI WINBOOL WINAPI GetWindowRect(HWND hWnd,LPRECT lpRect); + WINUSERAPI WINBOOL WINAPI AdjustWindowRect(LPRECT lpRect,DWORD dwStyle,WINBOOL bMenu); + WINUSERAPI WINBOOL WINAPI AdjustWindowRectEx(LPRECT lpRect,DWORD dwStyle,WINBOOL bMenu,DWORD dwExStyle); + +#define HELPINFO_WINDOW 0x0001 +#define HELPINFO_MENUITEM 0x0002 + + typedef struct tagHELPINFO { + UINT cbSize; + int iContextType; + int iCtrlId; + HANDLE hItemHandle; + DWORD_PTR dwContextId; + POINT MousePos; + } HELPINFO,*LPHELPINFO; + + WINUSERAPI WINBOOL WINAPI SetWindowContextHelpId(HWND,DWORD); + WINUSERAPI DWORD WINAPI GetWindowContextHelpId(HWND); + WINUSERAPI WINBOOL WINAPI SetMenuContextHelpId(HMENU,DWORD); + WINUSERAPI DWORD WINAPI GetMenuContextHelpId(HMENU); + +#ifndef NOMB + +#define MB_OK 0x00000000L +#define MB_OKCANCEL 0x00000001L +#define MB_ABORTRETRYIGNORE 0x00000002L +#define MB_YESNOCANCEL 0x00000003L +#define MB_YESNO 0x00000004L +#define MB_RETRYCANCEL 0x00000005L +#define MB_CANCELTRYCONTINUE 0x00000006L +#define MB_ICONHAND 0x00000010L +#define MB_ICONQUESTION 0x00000020L +#define MB_ICONEXCLAMATION 0x00000030L +#define MB_ICONASTERISK 0x00000040L +#define MB_USERICON 0x00000080L +#define MB_ICONWARNING MB_ICONEXCLAMATION +#define MB_ICONERROR MB_ICONHAND +#define MB_ICONINFORMATION MB_ICONASTERISK +#define MB_ICONSTOP MB_ICONHAND +#define MB_DEFBUTTON1 0x00000000L +#define MB_DEFBUTTON2 0x00000100L +#define MB_DEFBUTTON3 0x00000200L +#define MB_DEFBUTTON4 0x00000300L +#define MB_APPLMODAL 0x00000000L +#define MB_SYSTEMMODAL 0x00001000L +#define MB_TASKMODAL 0x00002000L +#define MB_HELP 0x00004000L +#define MB_NOFOCUS 0x00008000L +#define MB_SETFOREGROUND 0x00010000L +#define MB_DEFAULT_DESKTOP_ONLY 0x00020000L +#define MB_TOPMOST 0x00040000L +#define MB_RIGHT 0x00080000L +#define MB_RTLREADING 0x00100000L +#define MB_SERVICE_NOTIFICATION 0x00200000L +#define MB_SERVICE_NOTIFICATION_NT3X 0x00040000L +#define MB_TYPEMASK 0x0000000FL +#define MB_ICONMASK 0x000000F0L +#define MB_DEFMASK 0x00000F00L +#define MB_MODEMASK 0x00003000L +#define MB_MISCMASK 0x0000C000L + +#ifdef UNICODE +#define MessageBox MessageBoxW +#define MessageBoxEx MessageBoxExW +#else +#define MessageBox MessageBoxA +#define MessageBoxEx MessageBoxExA +#endif + + WINUSERAPI int WINAPI MessageBoxA(HWND hWnd,LPCSTR lpText,LPCSTR lpCaption,UINT uType); + WINUSERAPI int WINAPI MessageBoxW(HWND hWnd,LPCWSTR lpText,LPCWSTR lpCaption,UINT uType); + WINUSERAPI int WINAPI MessageBoxExA(HWND hWnd,LPCSTR lpText,LPCSTR lpCaption,UINT uType,WORD wLanguageId); + WINUSERAPI int WINAPI MessageBoxExW(HWND hWnd,LPCWSTR lpText,LPCWSTR lpCaption,UINT uType,WORD wLanguageId); + + typedef VOID (CALLBACK *MSGBOXCALLBACK)(LPHELPINFO lpHelpInfo); + + typedef struct tagMSGBOXPARAMSA { + UINT cbSize; + HWND hwndOwner; + HINSTANCE hInstance; + LPCSTR lpszText; + LPCSTR lpszCaption; + DWORD dwStyle; + LPCSTR lpszIcon; + DWORD_PTR dwContextHelpId; + MSGBOXCALLBACK lpfnMsgBoxCallback; + DWORD dwLanguageId; + } MSGBOXPARAMSA,*PMSGBOXPARAMSA,*LPMSGBOXPARAMSA; + + typedef struct tagMSGBOXPARAMSW { + UINT cbSize; + HWND hwndOwner; + HINSTANCE hInstance; + LPCWSTR lpszText; + LPCWSTR lpszCaption; + DWORD dwStyle; + LPCWSTR lpszIcon; + DWORD_PTR dwContextHelpId; + MSGBOXCALLBACK lpfnMsgBoxCallback; + DWORD dwLanguageId; + } MSGBOXPARAMSW,*PMSGBOXPARAMSW,*LPMSGBOXPARAMSW; + +#ifdef UNICODE + typedef MSGBOXPARAMSW MSGBOXPARAMS; + typedef PMSGBOXPARAMSW PMSGBOXPARAMS; + typedef LPMSGBOXPARAMSW LPMSGBOXPARAMS; +#else + typedef MSGBOXPARAMSA MSGBOXPARAMS; + typedef PMSGBOXPARAMSA PMSGBOXPARAMS; + typedef LPMSGBOXPARAMSA LPMSGBOXPARAMS; +#endif + +#ifdef UNICODE +#define MessageBoxIndirect MessageBoxIndirectW +#else +#define MessageBoxIndirect MessageBoxIndirectA +#endif + + WINUSERAPI int WINAPI MessageBoxIndirectA(CONST MSGBOXPARAMSA *lpmbp); + WINUSERAPI int WINAPI MessageBoxIndirectW(CONST MSGBOXPARAMSW *lpmbp); + WINUSERAPI WINBOOL WINAPI MessageBeep(UINT uType); +#endif + + WINUSERAPI int WINAPI ShowCursor(WINBOOL bShow); + WINUSERAPI WINBOOL WINAPI SetCursorPos(int X,int Y); + WINUSERAPI HCURSOR WINAPI SetCursor(HCURSOR hCursor); + WINUSERAPI WINBOOL WINAPI GetCursorPos(LPPOINT lpPoint); + WINUSERAPI WINBOOL WINAPI ClipCursor(CONST RECT *lpRect); + WINUSERAPI WINBOOL WINAPI GetClipCursor(LPRECT lpRect); + WINUSERAPI HCURSOR WINAPI GetCursor(VOID); + WINUSERAPI WINBOOL WINAPI CreateCaret(HWND hWnd,HBITMAP hBitmap,int nWidth,int nHeight); + WINUSERAPI UINT WINAPI GetCaretBlinkTime(VOID); + WINUSERAPI WINBOOL WINAPI SetCaretBlinkTime(UINT uMSeconds); + WINUSERAPI WINBOOL WINAPI DestroyCaret(VOID); + WINUSERAPI WINBOOL WINAPI HideCaret(HWND hWnd); + WINUSERAPI WINBOOL WINAPI ShowCaret(HWND hWnd); + WINUSERAPI WINBOOL WINAPI SetCaretPos(int X,int Y); + WINUSERAPI WINBOOL WINAPI GetCaretPos(LPPOINT lpPoint); + WINUSERAPI WINBOOL WINAPI ClientToScreen(HWND hWnd,LPPOINT lpPoint); + WINUSERAPI WINBOOL WINAPI ScreenToClient(HWND hWnd,LPPOINT lpPoint); + WINUSERAPI int WINAPI MapWindowPoints(HWND hWndFrom,HWND hWndTo,LPPOINT lpPoints,UINT cPoints); + WINUSERAPI HWND WINAPI WindowFromPoint(POINT Point); + WINUSERAPI HWND WINAPI ChildWindowFromPoint(HWND hWndParent,POINT Point); + +#define CWP_ALL 0x0000 +#define CWP_SKIPINVISIBLE 0x0001 +#define CWP_SKIPDISABLED 0x0002 +#define CWP_SKIPTRANSPARENT 0x0004 + + WINUSERAPI HWND WINAPI ChildWindowFromPointEx(HWND hwnd,POINT pt,UINT flags); + +#ifndef NOCOLOR + +#define CTLCOLOR_MSGBOX 0 +#define CTLCOLOR_EDIT 1 +#define CTLCOLOR_LISTBOX 2 +#define CTLCOLOR_BTN 3 +#define CTLCOLOR_DLG 4 +#define CTLCOLOR_SCROLLBAR 5 +#define CTLCOLOR_STATIC 6 +#define CTLCOLOR_MAX 7 + +#define COLOR_SCROLLBAR 0 +#define COLOR_BACKGROUND 1 +#define COLOR_ACTIVECAPTION 2 +#define COLOR_INACTIVECAPTION 3 +#define COLOR_MENU 4 +#define COLOR_WINDOW 5 +#define COLOR_WINDOWFRAME 6 +#define COLOR_MENUTEXT 7 +#define COLOR_WINDOWTEXT 8 +#define COLOR_CAPTIONTEXT 9 +#define COLOR_ACTIVEBORDER 10 +#define COLOR_INACTIVEBORDER 11 +#define COLOR_APPWORKSPACE 12 +#define COLOR_HIGHLIGHT 13 +#define COLOR_HIGHLIGHTTEXT 14 +#define COLOR_BTNFACE 15 +#define COLOR_BTNSHADOW 16 +#define COLOR_GRAYTEXT 17 +#define COLOR_BTNTEXT 18 +#define COLOR_INACTIVECAPTIONTEXT 19 +#define COLOR_BTNHIGHLIGHT 20 + +#define COLOR_3DDKSHADOW 21 +#define COLOR_3DLIGHT 22 +#define COLOR_INFOTEXT 23 +#define COLOR_INFOBK 24 + +#define COLOR_HOTLIGHT 26 +#define COLOR_GRADIENTACTIVECAPTION 27 +#define COLOR_GRADIENTINACTIVECAPTION 28 +#define COLOR_MENUHILIGHT 29 +#define COLOR_MENUBAR 30 + +#define COLOR_DESKTOP COLOR_BACKGROUND +#define COLOR_3DFACE COLOR_BTNFACE +#define COLOR_3DSHADOW COLOR_BTNSHADOW +#define COLOR_3DHIGHLIGHT COLOR_BTNHIGHLIGHT +#define COLOR_3DHILIGHT COLOR_BTNHIGHLIGHT +#define COLOR_BTNHILIGHT COLOR_BTNHIGHLIGHT + + WINUSERAPI DWORD WINAPI GetSysColor(int nIndex); + WINUSERAPI HBRUSH WINAPI GetSysColorBrush(int nIndex); + WINUSERAPI WINBOOL WINAPI SetSysColors(int cElements,CONST INT *lpaElements,CONST COLORREF *lpaRgbValues); +#endif + + WINUSERAPI WINBOOL WINAPI DrawFocusRect(HDC hDC,CONST RECT *lprc); + WINUSERAPI int WINAPI FillRect(HDC hDC,CONST RECT *lprc,HBRUSH hbr); + WINUSERAPI int WINAPI FrameRect(HDC hDC,CONST RECT *lprc,HBRUSH hbr); + WINUSERAPI WINBOOL WINAPI InvertRect(HDC hDC,CONST RECT *lprc); + WINUSERAPI WINBOOL WINAPI SetRect(LPRECT lprc,int xLeft,int yTop,int xRight,int yBottom); + WINUSERAPI WINBOOL WINAPI SetRectEmpty(LPRECT lprc); + WINUSERAPI WINBOOL WINAPI CopyRect(LPRECT lprcDst,CONST RECT *lprcSrc); + WINUSERAPI WINBOOL WINAPI InflateRect(LPRECT lprc,int dx,int dy); + WINUSERAPI WINBOOL WINAPI IntersectRect(LPRECT lprcDst,CONST RECT *lprcSrc1,CONST RECT *lprcSrc2); + WINUSERAPI WINBOOL WINAPI UnionRect(LPRECT lprcDst,CONST RECT *lprcSrc1,CONST RECT *lprcSrc2); + WINUSERAPI WINBOOL WINAPI SubtractRect(LPRECT lprcDst,CONST RECT *lprcSrc1,CONST RECT *lprcSrc2); + WINUSERAPI WINBOOL WINAPI OffsetRect(LPRECT lprc,int dx,int dy); + WINUSERAPI WINBOOL WINAPI IsRectEmpty(CONST RECT *lprc); + WINUSERAPI WINBOOL WINAPI EqualRect(CONST RECT *lprc1,CONST RECT *lprc2); + WINUSERAPI WINBOOL WINAPI PtInRect(CONST RECT *lprc,POINT pt); + +#ifndef NOWINOFFSETS + +#ifdef UNICODE +#define GetWindowLong GetWindowLongW +#define SetWindowLong SetWindowLongW +#else +#define GetWindowLong GetWindowLongA +#define SetWindowLong SetWindowLongA +#endif + + WINUSERAPI WORD WINAPI GetWindowWord(HWND hWnd,int nIndex); + WINUSERAPI WORD WINAPI SetWindowWord(HWND hWnd,int nIndex,WORD wNewWord); + WINUSERAPI LONG WINAPI GetWindowLongA(HWND hWnd,int nIndex); + WINUSERAPI LONG WINAPI GetWindowLongW(HWND hWnd,int nIndex); + WINUSERAPI LONG WINAPI SetWindowLongA(HWND hWnd,int nIndex,LONG dwNewLong); + WINUSERAPI LONG WINAPI SetWindowLongW(HWND hWnd,int nIndex,LONG dwNewLong); + +#ifdef _WIN64 + +#ifdef UNICODE +#define GetWindowLongPtr GetWindowLongPtrW +#define SetWindowLongPtr SetWindowLongPtrW +#else +#define GetWindowLongPtr GetWindowLongPtrA +#define SetWindowLongPtr SetWindowLongPtrA +#endif + + WINUSERAPI LONG_PTR WINAPI GetWindowLongPtrA(HWND hWnd,int nIndex); + WINUSERAPI LONG_PTR WINAPI GetWindowLongPtrW(HWND hWnd,int nIndex); + WINUSERAPI LONG_PTR WINAPI SetWindowLongPtrA(HWND hWnd,int nIndex,LONG_PTR dwNewLong); + WINUSERAPI LONG_PTR WINAPI SetWindowLongPtrW(HWND hWnd,int nIndex,LONG_PTR dwNewLong); +#else + +#ifdef UNICODE +#define GetWindowLongPtr GetWindowLongPtrW +#define SetWindowLongPtr SetWindowLongPtrW +#else +#define GetWindowLongPtr GetWindowLongPtrA +#define SetWindowLongPtr SetWindowLongPtrA +#endif + +#define GetWindowLongPtrA GetWindowLongA +#define GetWindowLongPtrW GetWindowLongW +#define SetWindowLongPtrA SetWindowLongA +#define SetWindowLongPtrW SetWindowLongW +#endif + +#ifdef UNICODE +#define GetClassLong GetClassLongW +#define SetClassLong SetClassLongW +#else +#define GetClassLong GetClassLongA +#define SetClassLong SetClassLongA +#endif + + WINUSERAPI WORD WINAPI GetClassWord(HWND hWnd,int nIndex); + WINUSERAPI WORD WINAPI SetClassWord(HWND hWnd,int nIndex,WORD wNewWord); + WINUSERAPI DWORD WINAPI GetClassLongA(HWND hWnd,int nIndex); + WINUSERAPI DWORD WINAPI GetClassLongW(HWND hWnd,int nIndex); + WINUSERAPI DWORD WINAPI SetClassLongA(HWND hWnd,int nIndex,LONG dwNewLong); + WINUSERAPI DWORD WINAPI SetClassLongW(HWND hWnd,int nIndex,LONG dwNewLong); + +#ifdef _WIN64 + +#ifdef UNICODE +#define GetClassLongPtr GetClassLongPtrW +#define SetClassLongPtr SetClassLongPtrW +#else +#define GetClassLongPtr GetClassLongPtrA +#define SetClassLongPtr SetClassLongPtrA +#endif + + WINUSERAPI ULONG_PTR WINAPI GetClassLongPtrA(HWND hWnd,int nIndex); + WINUSERAPI ULONG_PTR WINAPI GetClassLongPtrW(HWND hWnd,int nIndex); + WINUSERAPI ULONG_PTR WINAPI SetClassLongPtrA(HWND hWnd,int nIndex,LONG_PTR dwNewLong); + WINUSERAPI ULONG_PTR WINAPI SetClassLongPtrW(HWND hWnd,int nIndex,LONG_PTR dwNewLong); +#else +#ifdef UNICODE +#define GetClassLongPtr GetClassLongPtrW +#define SetClassLongPtr SetClassLongPtrW +#else +#define GetClassLongPtr GetClassLongPtrA +#define SetClassLongPtr SetClassLongPtrA +#endif + +#define GetClassLongPtrA GetClassLongA +#define GetClassLongPtrW GetClassLongW +#define SetClassLongPtrA SetClassLongA +#define SetClassLongPtrW SetClassLongW +#endif +#endif + +#ifdef UNICODE +#define FindWindow FindWindowW +#define FindWindowEx FindWindowExW +#define GetClassName GetClassNameW +#else +#define FindWindow FindWindowA +#define FindWindowEx FindWindowExA +#define GetClassName GetClassNameA +#endif + + WINUSERAPI WINBOOL WINAPI GetProcessDefaultLayout(DWORD *pdwDefaultLayout); + WINUSERAPI WINBOOL WINAPI SetProcessDefaultLayout(DWORD dwDefaultLayout); + WINUSERAPI HWND WINAPI GetDesktopWindow(VOID); + WINUSERAPI HWND WINAPI GetParent(HWND hWnd); + WINUSERAPI HWND WINAPI SetParent(HWND hWndChild,HWND hWndNewParent); + WINUSERAPI WINBOOL WINAPI EnumChildWindows(HWND hWndParent,WNDENUMPROC lpEnumFunc,LPARAM lParam); + WINUSERAPI HWND WINAPI FindWindowA(LPCSTR lpClassName,LPCSTR lpWindowName); + WINUSERAPI HWND WINAPI FindWindowW(LPCWSTR lpClassName,LPCWSTR lpWindowName); + WINUSERAPI HWND WINAPI FindWindowExA(HWND hWndParent,HWND hWndChildAfter,LPCSTR lpszClass,LPCSTR lpszWindow); + WINUSERAPI HWND WINAPI FindWindowExW(HWND hWndParent,HWND hWndChildAfter,LPCWSTR lpszClass,LPCWSTR lpszWindow); + WINUSERAPI HWND WINAPI GetShellWindow(VOID); + WINUSERAPI WINBOOL WINAPI RegisterShellHookWindow(HWND hwnd); + WINUSERAPI WINBOOL WINAPI DeregisterShellHookWindow(HWND hwnd); + WINUSERAPI WINBOOL WINAPI EnumWindows(WNDENUMPROC lpEnumFunc,LPARAM lParam); + WINUSERAPI WINBOOL WINAPI EnumThreadWindows(DWORD dwThreadId,WNDENUMPROC lpfn,LPARAM lParam); + +#define EnumTaskWindows(hTask,lpfn,lParam) EnumThreadWindows(HandleToUlong(hTask),lpfn,lParam) + + WINUSERAPI int WINAPI GetClassNameA(HWND hWnd,LPSTR lpClassName,int nMaxCount); + WINUSERAPI int WINAPI GetClassNameW(HWND hWnd,LPWSTR lpClassName,int nMaxCount); + WINUSERAPI HWND WINAPI GetTopWindow(HWND hWnd); + +#define GetNextWindow(hWnd,wCmd) GetWindow(hWnd,wCmd) +#define GetSysModalWindow() (NULL) +#define SetSysModalWindow(hWnd) (NULL) + + WINUSERAPI DWORD WINAPI GetWindowThreadProcessId(HWND hWnd,LPDWORD lpdwProcessId); + WINUSERAPI WINBOOL WINAPI IsGUIThread(WINBOOL bConvert); + +#define GetWindowTask(hWnd) ((HANDLE)(DWORD_PTR)GetWindowThreadProcessId(hWnd,NULL)) + + WINUSERAPI HWND WINAPI GetLastActivePopup(HWND hWnd); + +#define GW_HWNDFIRST 0 +#define GW_HWNDLAST 1 +#define GW_HWNDNEXT 2 +#define GW_HWNDPREV 3 +#define GW_OWNER 4 +#define GW_CHILD 5 +#define GW_ENABLEDPOPUP 6 +#define GW_MAX 6 + + WINUSERAPI HWND WINAPI GetWindow(HWND hWnd,UINT uCmd); + +#ifndef NOWH + +#ifdef UNICODE +#define SetWindowsHook SetWindowsHookW +#define SetWindowsHookEx SetWindowsHookExW +#else +#define SetWindowsHook SetWindowsHookA +#define SetWindowsHookEx SetWindowsHookExA +#endif + + WINUSERAPI HHOOK WINAPI SetWindowsHookA(int nFilterType,HOOKPROC pfnFilterProc); + WINUSERAPI HHOOK WINAPI SetWindowsHookW(int nFilterType,HOOKPROC pfnFilterProc); + WINUSERAPI WINBOOL WINAPI UnhookWindowsHook(int nCode,HOOKPROC pfnFilterProc); + WINUSERAPI HHOOK WINAPI SetWindowsHookExA(int idHook,HOOKPROC lpfn,HINSTANCE hmod,DWORD dwThreadId); + WINUSERAPI HHOOK WINAPI SetWindowsHookExW(int idHook,HOOKPROC lpfn,HINSTANCE hmod,DWORD dwThreadId); + WINUSERAPI WINBOOL WINAPI UnhookWindowsHookEx(HHOOK hhk); + WINUSERAPI LRESULT WINAPI CallNextHookEx(HHOOK hhk,int nCode,WPARAM wParam,LPARAM lParam); +#define DefHookProc(nCode,wParam,lParam,phhk) CallNextHookEx(*phhk,nCode,wParam,lParam) +#endif + +#ifndef NOMENUS + +#define MF_INSERT 0x00000000L +#define MF_CHANGE 0x00000080L +#define MF_APPEND 0x00000100L +#define MF_DELETE 0x00000200L +#define MF_REMOVE 0x00001000L +#define MF_BYCOMMAND 0x00000000L +#define MF_BYPOSITION 0x00000400L +#define MF_SEPARATOR 0x00000800L +#define MF_ENABLED 0x00000000L +#define MF_GRAYED 0x00000001L +#define MF_DISABLED 0x00000002L +#define MF_UNCHECKED 0x00000000L +#define MF_CHECKED 0x00000008L +#define MF_USECHECKBITMAPS 0x00000200L +#define MF_STRING 0x00000000L +#define MF_BITMAP 0x00000004L +#define MF_OWNERDRAW 0x00000100L +#define MF_POPUP 0x00000010L +#define MF_MENUBARBREAK 0x00000020L +#define MF_MENUBREAK 0x00000040L +#define MF_UNHILITE 0x00000000L +#define MF_HILITE 0x00000080L +#define MF_DEFAULT 0x00001000L +#define MF_SYSMENU 0x00002000L +#define MF_HELP 0x00004000L +#define MF_RIGHTJUSTIFY 0x00004000L +#define MF_MOUSESELECT 0x00008000L +#define MF_END 0x00000080L + +#define MFT_STRING MF_STRING +#define MFT_BITMAP MF_BITMAP +#define MFT_MENUBARBREAK MF_MENUBARBREAK +#define MFT_MENUBREAK MF_MENUBREAK +#define MFT_OWNERDRAW MF_OWNERDRAW +#define MFT_RADIOCHECK 0x00000200L +#define MFT_SEPARATOR MF_SEPARATOR +#define MFT_RIGHTORDER 0x00002000L +#define MFT_RIGHTJUSTIFY MF_RIGHTJUSTIFY + +#define MFS_GRAYED 0x00000003L +#define MFS_DISABLED MFS_GRAYED +#define MFS_CHECKED MF_CHECKED +#define MFS_HILITE MF_HILITE +#define MFS_ENABLED MF_ENABLED +#define MFS_UNCHECKED MF_UNCHECKED +#define MFS_UNHILITE MF_UNHILITE +#define MFS_DEFAULT MF_DEFAULT + + WINUSERAPI WINBOOL WINAPI CheckMenuRadioItem(HMENU hmenu,UINT first,UINT last,UINT check,UINT flags); + + typedef struct { + WORD versionNumber; + WORD offset; + } MENUITEMTEMPLATEHEADER,*PMENUITEMTEMPLATEHEADER; + + typedef struct { + WORD mtOption; + WORD mtID; + WCHAR mtString[1]; + } MENUITEMTEMPLATE,*PMENUITEMTEMPLATE; +#define MF_END 0x00000080L +#endif + +#ifndef NOSYSCOMMANDS + +#define SC_SIZE 0xF000 +#define SC_MOVE 0xF010 +#define SC_MINIMIZE 0xF020 +#define SC_MAXIMIZE 0xF030 +#define SC_NEXTWINDOW 0xF040 +#define SC_PREVWINDOW 0xF050 +#define SC_CLOSE 0xF060 +#define SC_VSCROLL 0xF070 +#define SC_HSCROLL 0xF080 +#define SC_MOUSEMENU 0xF090 +#define SC_KEYMENU 0xF100 +#define SC_ARRANGE 0xF110 +#define SC_RESTORE 0xF120 +#define SC_TASKLIST 0xF130 +#define SC_SCREENSAVE 0xF140 +#define SC_HOTKEY 0xF150 +#define SC_DEFAULT 0xF160 +#define SC_MONITORPOWER 0xF170 +#define SC_CONTEXTHELP 0xF180 +#define SC_SEPARATOR 0xF00F +#define SC_ICON SC_MINIMIZE +#define SC_ZOOM SC_MAXIMIZE +#endif + +#ifdef UNICODE +#define LoadBitmap LoadBitmapW +#define LoadCursor LoadCursorW +#define LoadCursorFromFile LoadCursorFromFileW +#else +#define LoadBitmap LoadBitmapA +#define LoadCursor LoadCursorA +#define LoadCursorFromFile LoadCursorFromFileA +#endif + + WINUSERAPI HBITMAP WINAPI LoadBitmapA(HINSTANCE hInstance,LPCSTR lpBitmapName); + WINUSERAPI HBITMAP WINAPI LoadBitmapW(HINSTANCE hInstance,LPCWSTR lpBitmapName); + WINUSERAPI HCURSOR WINAPI LoadCursorA(HINSTANCE hInstance,LPCSTR lpCursorName); + WINUSERAPI HCURSOR WINAPI LoadCursorW(HINSTANCE hInstance,LPCWSTR lpCursorName); + WINUSERAPI HCURSOR WINAPI LoadCursorFromFileA(LPCSTR lpFileName); + WINUSERAPI HCURSOR WINAPI LoadCursorFromFileW(LPCWSTR lpFileName); + WINUSERAPI HCURSOR WINAPI CreateCursor(HINSTANCE hInst,int xHotSpot,int yHotSpot,int nWidth,int nHeight,CONST VOID *pvANDPlane,CONST VOID *pvXORPlane); + WINUSERAPI WINBOOL WINAPI DestroyCursor(HCURSOR hCursor); + +#define CopyCursor(pcur) ((HCURSOR)CopyIcon((HICON)(pcur))) + +#define IDC_ARROW MAKEINTRESOURCE(32512) +#define IDC_IBEAM MAKEINTRESOURCE(32513) +#define IDC_WAIT MAKEINTRESOURCE(32514) +#define IDC_CROSS MAKEINTRESOURCE(32515) +#define IDC_UPARROW MAKEINTRESOURCE(32516) +#define IDC_SIZE MAKEINTRESOURCE(32640) +#define IDC_ICON MAKEINTRESOURCE(32641) +#define IDC_SIZENWSE MAKEINTRESOURCE(32642) +#define IDC_SIZENESW MAKEINTRESOURCE(32643) +#define IDC_SIZEWE MAKEINTRESOURCE(32644) +#define IDC_SIZENS MAKEINTRESOURCE(32645) +#define IDC_SIZEALL MAKEINTRESOURCE(32646) +#define IDC_NO MAKEINTRESOURCE(32648) +#define IDC_HAND MAKEINTRESOURCE(32649) +#define IDC_APPSTARTING MAKEINTRESOURCE(32650) +#define IDC_HELP MAKEINTRESOURCE(32651) + + WINUSERAPI WINBOOL WINAPI SetSystemCursor(HCURSOR hcur,DWORD id); + + typedef struct _ICONINFO { + WINBOOL fIcon; + DWORD xHotspot; + DWORD yHotspot; + HBITMAP hbmMask; + HBITMAP hbmColor; + } ICONINFO; + typedef ICONINFO *PICONINFO; + +#ifdef UNICODE +#define LoadIcon LoadIconW +#define PrivateExtractIcons PrivateExtractIconsW +#else +#define LoadIcon LoadIconA +#define PrivateExtractIcons PrivateExtractIconsA +#endif + + WINUSERAPI HICON WINAPI LoadIconA(HINSTANCE hInstance,LPCSTR lpIconName); + WINUSERAPI HICON WINAPI LoadIconW(HINSTANCE hInstance,LPCWSTR lpIconName); + WINUSERAPI UINT WINAPI PrivateExtractIconsA(LPCSTR szFileName,int nIconIndex,int cxIcon,int cyIcon,HICON *phicon,UINT *piconid,UINT nIcons,UINT flags); + WINUSERAPI UINT WINAPI PrivateExtractIconsW(LPCWSTR szFileName,int nIconIndex,int cxIcon,int cyIcon,HICON *phicon,UINT *piconid,UINT nIcons,UINT flags); + WINUSERAPI HICON WINAPI CreateIcon(HINSTANCE hInstance,int nWidth,int nHeight,BYTE cPlanes,BYTE cBitsPixel,CONST BYTE *lpbANDbits,CONST BYTE *lpbXORbits); + WINUSERAPI WINBOOL WINAPI DestroyIcon(HICON hIcon); + WINUSERAPI int WINAPI LookupIconIdFromDirectory(PBYTE presbits,WINBOOL fIcon); + WINUSERAPI int WINAPI LookupIconIdFromDirectoryEx(PBYTE presbits,WINBOOL fIcon,int cxDesired,int cyDesired,UINT Flags); + WINUSERAPI HICON WINAPI CreateIconFromResource(PBYTE presbits,DWORD dwResSize,WINBOOL fIcon,DWORD dwVer); + WINUSERAPI HICON WINAPI CreateIconFromResourceEx(PBYTE presbits,DWORD dwResSize,WINBOOL fIcon,DWORD dwVer,int cxDesired,int cyDesired,UINT Flags); + + typedef struct tagCURSORSHAPE { + int xHotSpot; + int yHotSpot; + int cx; + int cy; + int cbWidth; + BYTE Planes; + BYTE BitsPixel; + } CURSORSHAPE,*LPCURSORSHAPE; + +#define IMAGE_BITMAP 0 +#define IMAGE_ICON 1 +#define IMAGE_CURSOR 2 +#define IMAGE_ENHMETAFILE 3 + +#define LR_DEFAULTCOLOR 0x0000 +#define LR_MONOCHROME 0x0001 +#define LR_COLOR 0x0002 +#define LR_COPYRETURNORG 0x0004 +#define LR_COPYDELETEORG 0x0008 +#define LR_LOADFROMFILE 0x0010 +#define LR_LOADTRANSPARENT 0x0020 +#define LR_DEFAULTSIZE 0x0040 +#define LR_VGACOLOR 0x0080 +#define LR_LOADMAP3DCOLORS 0x1000 +#define LR_CREATEDIBSECTION 0x2000 +#define LR_COPYFROMRESOURCE 0x4000 +#define LR_SHARED 0x8000 + +#ifdef UNICODE +#define LoadImage LoadImageW +#else +#define LoadImage LoadImageA +#endif + + WINUSERAPI HANDLE WINAPI LoadImageA(HINSTANCE hInst,LPCSTR name,UINT type,int cx,int cy,UINT fuLoad); + WINUSERAPI HANDLE WINAPI LoadImageW(HINSTANCE hInst,LPCWSTR name,UINT type,int cx,int cy,UINT fuLoad); + WINUSERAPI HANDLE WINAPI CopyImage(HANDLE h,UINT type,int cx,int cy,UINT flags); + +#define DI_MASK 0x0001 +#define DI_IMAGE 0x0002 +#define DI_NORMAL 0x0003 +#define DI_COMPAT 0x0004 +#define DI_DEFAULTSIZE 0x0008 +#define DI_NOMIRROR 0x0010 + + WINUSERAPI WINBOOL WINAPI DrawIconEx(HDC hdc,int xLeft,int yTop,HICON hIcon,int cxWidth,int cyWidth,UINT istepIfAniCur,HBRUSH hbrFlickerFreeDraw,UINT diFlags); + WINUSERAPI HICON WINAPI CreateIconIndirect(PICONINFO piconinfo); + WINUSERAPI HICON WINAPI CopyIcon(HICON hIcon); + WINUSERAPI WINBOOL WINAPI GetIconInfo(HICON hIcon,PICONINFO piconinfo); + +#define RES_ICON 1 +#define RES_CURSOR 2 + +#ifdef OEMRESOURCE + +#define OBM_CLOSE 32754 +#define OBM_UPARROW 32753 +#define OBM_DNARROW 32752 +#define OBM_RGARROW 32751 +#define OBM_LFARROW 32750 +#define OBM_REDUCE 32749 +#define OBM_ZOOM 32748 +#define OBM_RESTORE 32747 +#define OBM_REDUCED 32746 +#define OBM_ZOOMD 32745 +#define OBM_RESTORED 32744 +#define OBM_UPARROWD 32743 +#define OBM_DNARROWD 32742 +#define OBM_RGARROWD 32741 +#define OBM_LFARROWD 32740 +#define OBM_MNARROW 32739 +#define OBM_COMBO 32738 +#define OBM_UPARROWI 32737 +#define OBM_DNARROWI 32736 +#define OBM_RGARROWI 32735 +#define OBM_LFARROWI 32734 + +#define OBM_OLD_CLOSE 32767 +#define OBM_SIZE 32766 +#define OBM_OLD_UPARROW 32765 +#define OBM_OLD_DNARROW 32764 +#define OBM_OLD_RGARROW 32763 +#define OBM_OLD_LFARROW 32762 +#define OBM_BTSIZE 32761 +#define OBM_CHECK 32760 +#define OBM_CHECKBOXES 32759 +#define OBM_BTNCORNERS 32758 +#define OBM_OLD_REDUCE 32757 +#define OBM_OLD_ZOOM 32756 +#define OBM_OLD_RESTORE 32755 + +#define OCR_NORMAL 32512 +#define OCR_IBEAM 32513 +#define OCR_WAIT 32514 +#define OCR_CROSS 32515 +#define OCR_UP 32516 +#define OCR_SIZE 32640 +#define OCR_ICON 32641 +#define OCR_SIZENWSE 32642 +#define OCR_SIZENESW 32643 +#define OCR_SIZEWE 32644 +#define OCR_SIZENS 32645 +#define OCR_SIZEALL 32646 +#define OCR_ICOCUR 32647 +#define OCR_NO 32648 +#define OCR_HAND 32649 +#define OCR_APPSTARTING 32650 + +#define OIC_SAMPLE 32512 +#define OIC_HAND 32513 +#define OIC_QUES 32514 +#define OIC_BANG 32515 +#define OIC_NOTE 32516 +#define OIC_WINLOGO 32517 +#define OIC_WARNING OIC_BANG +#define OIC_ERROR OIC_HAND +#define OIC_INFORMATION OIC_NOTE +#endif + +#define ORD_LANGDRIVER 1 + +#ifndef NOICONS + +#ifdef RC_INVOKED +#define IDI_APPLICATION 32512 +#define IDI_HAND 32513 +#define IDI_QUESTION 32514 +#define IDI_EXCLAMATION 32515 +#define IDI_ASTERISK 32516 +#define IDI_WINLOGO 32517 +#else +#define IDI_APPLICATION MAKEINTRESOURCE(32512) +#define IDI_HAND MAKEINTRESOURCE(32513) +#define IDI_QUESTION MAKEINTRESOURCE(32514) +#define IDI_EXCLAMATION MAKEINTRESOURCE(32515) +#define IDI_ASTERISK MAKEINTRESOURCE(32516) +#define IDI_WINLOGO MAKEINTRESOURCE(32517) +#endif + +#define IDI_WARNING IDI_EXCLAMATION +#define IDI_ERROR IDI_HAND +#define IDI_INFORMATION IDI_ASTERISK +#endif + +#ifdef UNICODE +#define LoadString LoadStringW +#else +#define LoadString LoadStringA +#endif + + WINUSERAPI int WINAPI LoadStringA(HINSTANCE hInstance,UINT uID,LPSTR lpBuffer,int cchBufferMax); + WINUSERAPI int WINAPI LoadStringW(HINSTANCE hInstance,UINT uID,LPWSTR lpBuffer,int cchBufferMax); + +#define IDOK 1 +#define IDCANCEL 2 +#define IDABORT 3 +#define IDRETRY 4 +#define IDIGNORE 5 +#define IDYES 6 +#define IDNO 7 +#define IDCLOSE 8 +#define IDHELP 9 +#define IDTRYAGAIN 10 +#define IDCONTINUE 11 + +#ifndef IDTIMEOUT +#define IDTIMEOUT 32000 +#endif + +#ifndef NOCTLMGR + +#ifndef NOWINSTYLES +#define ES_LEFT 0x0000L +#define ES_CENTER 0x0001L +#define ES_RIGHT 0x0002L +#define ES_MULTILINE 0x0004L +#define ES_UPPERCASE 0x0008L +#define ES_LOWERCASE 0x0010L +#define ES_PASSWORD 0x0020L +#define ES_AUTOVSCROLL 0x0040L +#define ES_AUTOHSCROLL 0x0080L +#define ES_NOHIDESEL 0x0100L +#define ES_OEMCONVERT 0x0400L +#define ES_READONLY 0x0800L +#define ES_WANTRETURN 0x1000L +#define ES_NUMBER 0x2000L +#endif + +#define EN_SETFOCUS 0x0100 +#define EN_KILLFOCUS 0x0200 +#define EN_CHANGE 0x0300 +#define EN_UPDATE 0x0400 +#define EN_ERRSPACE 0x0500 +#define EN_MAXTEXT 0x0501 +#define EN_HSCROLL 0x0601 +#define EN_VSCROLL 0x0602 +#define EN_ALIGN_LTR_EC 0x0700 +#define EN_ALIGN_RTL_EC 0x0701 + +#define EC_LEFTMARGIN 0x0001 +#define EC_RIGHTMARGIN 0x0002 +#define EC_USEFONTINFO 0xffff + +#define EMSIS_COMPOSITIONSTRING 0x0001 + +#define EIMES_GETCOMPSTRATONCE 0x0001 +#define EIMES_CANCELCOMPSTRINFOCUS 0x0002 +#define EIMES_COMPLETECOMPSTRKILLFOCUS 0x0004 + +#ifndef NOWINMESSAGES + +#define EM_GETSEL 0x00B0 +#define EM_SETSEL 0x00B1 +#define EM_GETRECT 0x00B2 +#define EM_SETRECT 0x00B3 +#define EM_SETRECTNP 0x00B4 +#define EM_SCROLL 0x00B5 +#define EM_LINESCROLL 0x00B6 +#define EM_SCROLLCARET 0x00B7 +#define EM_GETMODIFY 0x00B8 +#define EM_SETMODIFY 0x00B9 +#define EM_GETLINECOUNT 0x00BA +#define EM_LINEINDEX 0x00BB +#define EM_SETHANDLE 0x00BC +#define EM_GETHANDLE 0x00BD +#define EM_GETTHUMB 0x00BE +#define EM_LINELENGTH 0x00C1 +#define EM_REPLACESEL 0x00C2 +#define EM_GETLINE 0x00C4 +#define EM_LIMITTEXT 0x00C5 +#define EM_CANUNDO 0x00C6 +#define EM_UNDO 0x00C7 +#define EM_FMTLINES 0x00C8 +#define EM_LINEFROMCHAR 0x00C9 +#define EM_SETTABSTOPS 0x00CB +#define EM_SETPASSWORDCHAR 0x00CC +#define EM_EMPTYUNDOBUFFER 0x00CD +#define EM_GETFIRSTVISIBLELINE 0x00CE +#define EM_SETREADONLY 0x00CF +#define EM_SETWORDBREAKPROC 0x00D0 +#define EM_GETWORDBREAKPROC 0x00D1 +#define EM_GETPASSWORDCHAR 0x00D2 +#define EM_SETMARGINS 0x00D3 +#define EM_GETMARGINS 0x00D4 +#define EM_SETLIMITTEXT EM_LIMITTEXT +#define EM_GETLIMITTEXT 0x00D5 +#define EM_POSFROMCHAR 0x00D6 +#define EM_CHARFROMPOS 0x00D7 +#define EM_SETIMESTATUS 0x00D8 +#define EM_GETIMESTATUS 0x00D9 +#endif + +#define WB_LEFT 0 +#define WB_RIGHT 1 +#define WB_ISDELIMITER 2 + +#define BS_PUSHBUTTON 0x00000000L +#define BS_DEFPUSHBUTTON 0x00000001L +#define BS_CHECKBOX 0x00000002L +#define BS_AUTOCHECKBOX 0x00000003L +#define BS_RADIOBUTTON 0x00000004L +#define BS_3STATE 0x00000005L +#define BS_AUTO3STATE 0x00000006L +#define BS_GROUPBOX 0x00000007L +#define BS_USERBUTTON 0x00000008L +#define BS_AUTORADIOBUTTON 0x00000009L +#define BS_PUSHBOX 0x0000000AL +#define BS_OWNERDRAW 0x0000000BL +#define BS_TYPEMASK 0x0000000FL +#define BS_LEFTTEXT 0x00000020L +#define BS_TEXT 0x00000000L +#define BS_ICON 0x00000040L +#define BS_BITMAP 0x00000080L +#define BS_LEFT 0x00000100L +#define BS_RIGHT 0x00000200L +#define BS_CENTER 0x00000300L +#define BS_TOP 0x00000400L +#define BS_BOTTOM 0x00000800L +#define BS_VCENTER 0x00000C00L +#define BS_PUSHLIKE 0x00001000L +#define BS_MULTILINE 0x00002000L +#define BS_NOTIFY 0x00004000L +#define BS_FLAT 0x00008000L +#define BS_RIGHTBUTTON BS_LEFTTEXT + +#define BN_CLICKED 0 +#define BN_PAINT 1 +#define BN_HILITE 2 +#define BN_UNHILITE 3 +#define BN_DISABLE 4 +#define BN_DOUBLECLICKED 5 +#define BN_PUSHED BN_HILITE +#define BN_UNPUSHED BN_UNHILITE +#define BN_DBLCLK BN_DOUBLECLICKED +#define BN_SETFOCUS 6 +#define BN_KILLFOCUS 7 + +#define BM_GETCHECK 0x00F0 +#define BM_SETCHECK 0x00F1 +#define BM_GETSTATE 0x00F2 +#define BM_SETSTATE 0x00F3 +#define BM_SETSTYLE 0x00F4 +#define BM_CLICK 0x00F5 +#define BM_GETIMAGE 0x00F6 +#define BM_SETIMAGE 0x00F7 + +#define BST_UNCHECKED 0x0000 +#define BST_CHECKED 0x0001 +#define BST_INDETERMINATE 0x0002 +#define BST_PUSHED 0x0004 +#define BST_FOCUS 0x0008 + +#define SS_LEFT 0x00000000L +#define SS_CENTER 0x00000001L +#define SS_RIGHT 0x00000002L +#define SS_ICON 0x00000003L +#define SS_BLACKRECT 0x00000004L +#define SS_GRAYRECT 0x00000005L +#define SS_WHITERECT 0x00000006L +#define SS_BLACKFRAME 0x00000007L +#define SS_GRAYFRAME 0x00000008L +#define SS_WHITEFRAME 0x00000009L +#define SS_USERITEM 0x0000000AL +#define SS_SIMPLE 0x0000000BL +#define SS_LEFTNOWORDWRAP 0x0000000CL +#define SS_OWNERDRAW 0x0000000DL +#define SS_BITMAP 0x0000000EL +#define SS_ENHMETAFILE 0x0000000FL +#define SS_ETCHEDHORZ 0x00000010L +#define SS_ETCHEDVERT 0x00000011L +#define SS_ETCHEDFRAME 0x00000012L +#define SS_TYPEMASK 0x0000001FL +#define SS_REALSIZECONTROL 0x00000040L +#define SS_NOPREFIX 0x00000080L +#define SS_NOTIFY 0x00000100L +#define SS_CENTERIMAGE 0x00000200L +#define SS_RIGHTJUST 0x00000400L +#define SS_REALSIZEIMAGE 0x00000800L +#define SS_SUNKEN 0x00001000L +#define SS_EDITCONTROL 0x00002000L +#define SS_ENDELLIPSIS 0x00004000L +#define SS_PATHELLIPSIS 0x00008000L +#define SS_WORDELLIPSIS 0x0000C000L +#define SS_ELLIPSISMASK 0x0000C000L + +#ifndef NOWINMESSAGES + +#define STM_SETICON 0x0170 +#define STM_GETICON 0x0171 +#define STM_SETIMAGE 0x0172 +#define STM_GETIMAGE 0x0173 +#define STN_CLICKED 0 +#define STN_DBLCLK 1 +#define STN_ENABLE 2 +#define STN_DISABLE 3 +#define STM_MSGMAX 0x0174 +#endif + +#define WC_DIALOG (MAKEINTATOM(0x8002)) + +#define DWL_MSGRESULT 0 +#define DWL_DLGPROC 4 +#define DWL_USER 8 + +#ifdef _WIN64 + +#undef DWL_MSGRESULT +#undef DWL_DLGPROC +#undef DWL_USER +#endif + +#define DWLP_MSGRESULT 0 +#define DWLP_DLGPROC DWLP_MSGRESULT + sizeof(LRESULT) +#define DWLP_USER DWLP_DLGPROC + sizeof(DLGPROC) + +#ifndef NOMSG + +#ifdef UNICODE +#define IsDialogMessage IsDialogMessageW +#else +#define IsDialogMessage IsDialogMessageA +#endif + + WINUSERAPI WINBOOL WINAPI IsDialogMessageA(HWND hDlg,LPMSG lpMsg); + WINUSERAPI WINBOOL WINAPI IsDialogMessageW(HWND hDlg,LPMSG lpMsg); +#endif + +#ifdef UNICODE +#define DlgDirList DlgDirListW +#define DlgDirSelectEx DlgDirSelectExW +#define DlgDirListComboBox DlgDirListComboBoxW +#define DlgDirSelectComboBoxEx DlgDirSelectComboBoxExW +#else +#define DlgDirList DlgDirListA +#define DlgDirSelectEx DlgDirSelectExA +#define DlgDirListComboBox DlgDirListComboBoxA +#define DlgDirSelectComboBoxEx DlgDirSelectComboBoxExA +#endif + + WINUSERAPI WINBOOL WINAPI MapDialogRect(HWND hDlg,LPRECT lpRect); + WINUSERAPI int WINAPI DlgDirListA(HWND hDlg,LPSTR lpPathSpec,int nIDListBox,int nIDStaticPath,UINT uFileType); + WINUSERAPI int WINAPI DlgDirListW(HWND hDlg,LPWSTR lpPathSpec,int nIDListBox,int nIDStaticPath,UINT uFileType); + +#define DDL_READWRITE 0x0000 +#define DDL_READONLY 0x0001 +#define DDL_HIDDEN 0x0002 +#define DDL_SYSTEM 0x0004 +#define DDL_DIRECTORY 0x0010 +#define DDL_ARCHIVE 0x0020 + +#define DDL_POSTMSGS 0x2000 +#define DDL_DRIVES 0x4000 +#define DDL_EXCLUSIVE 0x8000 + + WINUSERAPI WINBOOL WINAPI DlgDirSelectExA(HWND hwndDlg,LPSTR lpString,int chCount,int idListBox); + WINUSERAPI WINBOOL WINAPI DlgDirSelectExW(HWND hwndDlg,LPWSTR lpString,int chCount,int idListBox); + WINUSERAPI int WINAPI DlgDirListComboBoxA(HWND hDlg,LPSTR lpPathSpec,int nIDComboBox,int nIDStaticPath,UINT uFiletype); + WINUSERAPI int WINAPI DlgDirListComboBoxW(HWND hDlg,LPWSTR lpPathSpec,int nIDComboBox,int nIDStaticPath,UINT uFiletype); + WINUSERAPI WINBOOL WINAPI DlgDirSelectComboBoxExA(HWND hwndDlg,LPSTR lpString,int cchOut,int idComboBox); + WINUSERAPI WINBOOL WINAPI DlgDirSelectComboBoxExW(HWND hwndDlg,LPWSTR lpString,int cchOut,int idComboBox); + +#define DS_ABSALIGN 0x01L +#define DS_SYSMODAL 0x02L +#define DS_LOCALEDIT 0x20L +#define DS_SETFONT 0x40L +#define DS_MODALFRAME 0x80L +#define DS_NOIDLEMSG 0x100L +#define DS_SETFOREGROUND 0x200L + +#define DS_3DLOOK 0x0004L +#define DS_FIXEDSYS 0x0008L +#define DS_NOFAILCREATE 0x0010L +#define DS_CONTROL 0x0400L +#define DS_CENTER 0x0800L +#define DS_CENTERMOUSE 0x1000L +#define DS_CONTEXTHELP 0x2000L + +#define DS_SHELLFONT (DS_SETFONT | DS_FIXEDSYS) + +#if(_WIN32_WCE >= 0x0500) +#define DS_USEPIXELS 0x8000L +#endif + +#define DM_GETDEFID (WM_USER+0) +#define DM_SETDEFID (WM_USER+1) +#define DM_REPOSITION (WM_USER+2) + +#define DC_HASDEFID 0x534B + +#define DLGC_WANTARROWS 0x0001 +#define DLGC_WANTTAB 0x0002 +#define DLGC_WANTALLKEYS 0x0004 +#define DLGC_WANTMESSAGE 0x0004 +#define DLGC_HASSETSEL 0x0008 +#define DLGC_DEFPUSHBUTTON 0x0010 +#define DLGC_UNDEFPUSHBUTTON 0x0020 +#define DLGC_RADIOBUTTON 0x0040 +#define DLGC_WANTCHARS 0x0080 +#define DLGC_STATIC 0x0100 +#define DLGC_BUTTON 0x2000 + +#define LB_CTLCODE 0L + +#define LB_OKAY 0 +#define LB_ERR (-1) +#define LB_ERRSPACE (-2) + +#define LBN_ERRSPACE (-2) +#define LBN_SELCHANGE 1 +#define LBN_DBLCLK 2 +#define LBN_SELCANCEL 3 +#define LBN_SETFOCUS 4 +#define LBN_KILLFOCUS 5 + +#ifndef NOWINMESSAGES + +#define LB_ADDSTRING 0x0180 +#define LB_INSERTSTRING 0x0181 +#define LB_DELETESTRING 0x0182 +#define LB_SELITEMRANGEEX 0x0183 +#define LB_RESETCONTENT 0x0184 +#define LB_SETSEL 0x0185 +#define LB_SETCURSEL 0x0186 +#define LB_GETSEL 0x0187 +#define LB_GETCURSEL 0x0188 +#define LB_GETTEXT 0x0189 +#define LB_GETTEXTLEN 0x018A +#define LB_GETCOUNT 0x018B +#define LB_SELECTSTRING 0x018C +#define LB_DIR 0x018D +#define LB_GETTOPINDEX 0x018E +#define LB_FINDSTRING 0x018F +#define LB_GETSELCOUNT 0x0190 +#define LB_GETSELITEMS 0x0191 +#define LB_SETTABSTOPS 0x0192 +#define LB_GETHORIZONTALEXTENT 0x0193 +#define LB_SETHORIZONTALEXTENT 0x0194 +#define LB_SETCOLUMNWIDTH 0x0195 +#define LB_ADDFILE 0x0196 +#define LB_SETTOPINDEX 0x0197 +#define LB_GETITEMRECT 0x0198 +#define LB_GETITEMDATA 0x0199 +#define LB_SETITEMDATA 0x019A +#define LB_SELITEMRANGE 0x019B +#define LB_SETANCHORINDEX 0x019C +#define LB_GETANCHORINDEX 0x019D +#define LB_SETCARETINDEX 0x019E +#define LB_GETCARETINDEX 0x019F +#define LB_SETITEMHEIGHT 0x01A0 +#define LB_GETITEMHEIGHT 0x01A1 +#define LB_FINDSTRINGEXACT 0x01A2 +#define LB_SETLOCALE 0x01A5 +#define LB_GETLOCALE 0x01A6 +#define LB_SETCOUNT 0x01A7 +#define LB_INITSTORAGE 0x01A8 +#define LB_ITEMFROMPOINT 0x01A9 +#if(_WIN32_WCE >= 0x0400) +#define LB_MULTIPLEADDSTRING 0x01B1 +#endif +#define LB_GETLISTBOXINFO 0x01B2 +#define LB_MSGMAX 0x01B3 +#endif + +#ifndef NOWINSTYLES + +#define LBS_NOTIFY 0x0001L +#define LBS_SORT 0x0002L +#define LBS_NOREDRAW 0x0004L +#define LBS_MULTIPLESEL 0x0008L +#define LBS_OWNERDRAWFIXED 0x0010L +#define LBS_OWNERDRAWVARIABLE 0x0020L +#define LBS_HASSTRINGS 0x0040L +#define LBS_USETABSTOPS 0x0080L +#define LBS_NOINTEGRALHEIGHT 0x0100L +#define LBS_MULTICOLUMN 0x0200L +#define LBS_WANTKEYBOARDINPUT 0x0400L +#define LBS_EXTENDEDSEL 0x0800L +#define LBS_DISABLENOSCROLL 0x1000L +#define LBS_NODATA 0x2000L +#define LBS_NOSEL 0x4000L +#define LBS_COMBOBOX 0x8000L + +#define LBS_STANDARD (LBS_NOTIFY | LBS_SORT | WS_VSCROLL | WS_BORDER) +#endif + +#define CB_OKAY 0 +#define CB_ERR (-1) +#define CB_ERRSPACE (-2) + +#define CBN_ERRSPACE (-1) +#define CBN_SELCHANGE 1 +#define CBN_DBLCLK 2 +#define CBN_SETFOCUS 3 +#define CBN_KILLFOCUS 4 +#define CBN_EDITCHANGE 5 +#define CBN_EDITUPDATE 6 +#define CBN_DROPDOWN 7 +#define CBN_CLOSEUP 8 +#define CBN_SELENDOK 9 +#define CBN_SELENDCANCEL 10 + +#ifndef NOWINSTYLES + +#define CBS_SIMPLE 0x0001L +#define CBS_DROPDOWN 0x0002L +#define CBS_DROPDOWNLIST 0x0003L +#define CBS_OWNERDRAWFIXED 0x0010L +#define CBS_OWNERDRAWVARIABLE 0x0020L +#define CBS_AUTOHSCROLL 0x0040L +#define CBS_OEMCONVERT 0x0080L +#define CBS_SORT 0x0100L +#define CBS_HASSTRINGS 0x0200L +#define CBS_NOINTEGRALHEIGHT 0x0400L +#define CBS_DISABLENOSCROLL 0x0800L +#define CBS_UPPERCASE 0x2000L +#define CBS_LOWERCASE 0x4000L +#endif + +#ifndef NOWINMESSAGES +#define CB_GETEDITSEL 0x0140 +#define CB_LIMITTEXT 0x0141 +#define CB_SETEDITSEL 0x0142 +#define CB_ADDSTRING 0x0143 +#define CB_DELETESTRING 0x0144 +#define CB_DIR 0x0145 +#define CB_GETCOUNT 0x0146 +#define CB_GETCURSEL 0x0147 +#define CB_GETLBTEXT 0x0148 +#define CB_GETLBTEXTLEN 0x0149 +#define CB_INSERTSTRING 0x014A +#define CB_RESETCONTENT 0x014B +#define CB_FINDSTRING 0x014C +#define CB_SELECTSTRING 0x014D +#define CB_SETCURSEL 0x014E +#define CB_SHOWDROPDOWN 0x014F +#define CB_GETITEMDATA 0x0150 +#define CB_SETITEMDATA 0x0151 +#define CB_GETDROPPEDCONTROLRECT 0x0152 +#define CB_SETITEMHEIGHT 0x0153 +#define CB_GETITEMHEIGHT 0x0154 +#define CB_SETEXTENDEDUI 0x0155 +#define CB_GETEXTENDEDUI 0x0156 +#define CB_GETDROPPEDSTATE 0x0157 +#define CB_FINDSTRINGEXACT 0x0158 +#define CB_SETLOCALE 0x0159 +#define CB_GETLOCALE 0x015A +#define CB_GETTOPINDEX 0x015b +#define CB_SETTOPINDEX 0x015c +#define CB_GETHORIZONTALEXTENT 0x015d +#define CB_SETHORIZONTALEXTENT 0x015e +#define CB_GETDROPPEDWIDTH 0x015f +#define CB_SETDROPPEDWIDTH 0x0160 +#define CB_INITSTORAGE 0x0161 +#if(_WIN32_WCE >= 0x0400) +#define CB_MULTIPLEADDSTRING 0x0163 +#endif +#define CB_GETCOMBOBOXINFO 0x0164 +#define CB_MSGMAX 0x0165 +#endif + +#ifndef NOWINSTYLES + +#define SBS_HORZ 0x0000L +#define SBS_VERT 0x0001L +#define SBS_TOPALIGN 0x0002L +#define SBS_LEFTALIGN 0x0002L +#define SBS_BOTTOMALIGN 0x0004L +#define SBS_RIGHTALIGN 0x0004L +#define SBS_SIZEBOXTOPLEFTALIGN 0x0002L +#define SBS_SIZEBOXBOTTOMRIGHTALIGN 0x0004L +#define SBS_SIZEBOX 0x0008L +#define SBS_SIZEGRIP 0x0010L +#endif + +#ifndef NOWINMESSAGES +#define SBM_SETPOS 0x00E0 +#define SBM_GETPOS 0x00E1 +#define SBM_SETRANGE 0x00E2 +#define SBM_SETRANGEREDRAW 0x00E6 +#define SBM_GETRANGE 0x00E3 +#define SBM_ENABLE_ARROWS 0x00E4 +#define SBM_SETSCROLLINFO 0x00E9 +#define SBM_GETSCROLLINFO 0x00EA +#define SBM_GETSCROLLBARINFO 0x00EB + +#define SIF_RANGE 0x0001 +#define SIF_PAGE 0x0002 +#define SIF_POS 0x0004 +#define SIF_DISABLENOSCROLL 0x0008 +#define SIF_TRACKPOS 0x0010 +#define SIF_ALL (SIF_RANGE | SIF_PAGE | SIF_POS | SIF_TRACKPOS) + + typedef struct tagSCROLLINFO { + UINT cbSize; + UINT fMask; + int nMin; + int nMax; + UINT nPage; + int nPos; + int nTrackPos; + } SCROLLINFO,*LPSCROLLINFO; + typedef SCROLLINFO CONST *LPCSCROLLINFO; + + WINUSERAPI int WINAPI SetScrollInfo(HWND hwnd,int nBar,LPCSCROLLINFO lpsi,WINBOOL redraw); + WINUSERAPI WINBOOL WINAPI GetScrollInfo(HWND hwnd,int nBar,LPSCROLLINFO lpsi); +#endif +#endif + +#ifndef NOMDI + +#define MDIS_ALLCHILDSTYLES 0x0001 + +#define MDITILE_VERTICAL 0x0000 +#define MDITILE_HORIZONTAL 0x0001 +#define MDITILE_SKIPDISABLED 0x0002 +#define MDITILE_ZORDER 0x0004 + + typedef struct tagMDICREATESTRUCTA { + LPCSTR szClass; + LPCSTR szTitle; + HANDLE hOwner; + int x; + int y; + int cx; + int cy; + DWORD style; + LPARAM lParam; + } MDICREATESTRUCTA,*LPMDICREATESTRUCTA; + + typedef struct tagMDICREATESTRUCTW { + LPCWSTR szClass; + LPCWSTR szTitle; + HANDLE hOwner; + int x; + int y; + int cx; + int cy; + DWORD style; + LPARAM lParam; + } MDICREATESTRUCTW,*LPMDICREATESTRUCTW; + +#ifdef UNICODE + typedef MDICREATESTRUCTW MDICREATESTRUCT; + typedef LPMDICREATESTRUCTW LPMDICREATESTRUCT; +#else + typedef MDICREATESTRUCTA MDICREATESTRUCT; + typedef LPMDICREATESTRUCTA LPMDICREATESTRUCT; +#endif + + typedef struct tagCLIENTCREATESTRUCT { + HANDLE hWindowMenu; + UINT idFirstChild; + } CLIENTCREATESTRUCT,*LPCLIENTCREATESTRUCT; + +#ifdef UNICODE +#define DefFrameProc DefFrameProcW +#define DefMDIChildProc DefMDIChildProcW +#define CreateMDIWindow CreateMDIWindowW +#else +#define DefFrameProc DefFrameProcA +#define DefMDIChildProc DefMDIChildProcA +#define CreateMDIWindow CreateMDIWindowA +#endif + + WINUSERAPI LRESULT WINAPI DefFrameProcA(HWND hWnd,HWND hWndMDIClient,UINT uMsg,WPARAM wParam,LPARAM lParam); + WINUSERAPI LRESULT WINAPI DefFrameProcW(HWND hWnd,HWND hWndMDIClient,UINT uMsg,WPARAM wParam,LPARAM lParam); + WINUSERAPI LRESULT WINAPI DefMDIChildProcA(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam); + WINUSERAPI LRESULT WINAPI DefMDIChildProcW(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam); + +#ifndef NOMSG + WINUSERAPI WINBOOL WINAPI TranslateMDISysAccel(HWND hWndClient,LPMSG lpMsg); +#endif + + WINUSERAPI UINT WINAPI ArrangeIconicWindows(HWND hWnd); + WINUSERAPI HWND WINAPI CreateMDIWindowA(LPCSTR lpClassName,LPCSTR lpWindowName,DWORD dwStyle,int X,int Y,int nWidth,int nHeight,HWND hWndParent,HINSTANCE hInstance,LPARAM lParam); + WINUSERAPI HWND WINAPI CreateMDIWindowW(LPCWSTR lpClassName,LPCWSTR lpWindowName,DWORD dwStyle,int X,int Y,int nWidth,int nHeight,HWND hWndParent,HINSTANCE hInstance,LPARAM lParam); + WINUSERAPI WORD WINAPI TileWindows(HWND hwndParent,UINT wHow,CONST RECT *lpRect,UINT cKids,const HWND *lpKids); + WINUSERAPI WORD WINAPI CascadeWindows(HWND hwndParent,UINT wHow,CONST RECT *lpRect,UINT cKids,const HWND *lpKids); +#endif +#endif + +#ifndef NOHELP + + typedef DWORD HELPPOLY; + typedef struct tagMULTIKEYHELPA { + DWORD mkSize; + CHAR mkKeylist; + CHAR szKeyphrase[1]; + } MULTIKEYHELPA,*PMULTIKEYHELPA,*LPMULTIKEYHELPA; + + typedef struct tagMULTIKEYHELPW { + DWORD mkSize; + WCHAR mkKeylist; + WCHAR szKeyphrase[1]; + } MULTIKEYHELPW,*PMULTIKEYHELPW,*LPMULTIKEYHELPW; + +#ifdef UNICODE + typedef MULTIKEYHELPW MULTIKEYHELP; + typedef PMULTIKEYHELPW PMULTIKEYHELP; + typedef LPMULTIKEYHELPW LPMULTIKEYHELP; +#else + typedef MULTIKEYHELPA MULTIKEYHELP; + typedef PMULTIKEYHELPA PMULTIKEYHELP; + typedef LPMULTIKEYHELPA LPMULTIKEYHELP; +#endif + + typedef struct tagHELPWININFOA { + int wStructSize; + int x; + int y; + int dx; + int dy; + int wMax; + CHAR rgchMember[2]; + } HELPWININFOA,*PHELPWININFOA,*LPHELPWININFOA; + + typedef struct tagHELPWININFOW { + int wStructSize; + int x; + int y; + int dx; + int dy; + int wMax; + WCHAR rgchMember[2]; + } HELPWININFOW,*PHELPWININFOW,*LPHELPWININFOW; + +#ifdef UNICODE + typedef HELPWININFOW HELPWININFO; + typedef PHELPWININFOW PHELPWININFO; + typedef LPHELPWININFOW LPHELPWININFO; +#else + typedef HELPWININFOA HELPWININFO; + typedef PHELPWININFOA PHELPWININFO; + typedef LPHELPWININFOA LPHELPWININFO; +#endif + +#define HELP_CONTEXT 0x0001L +#define HELP_QUIT 0x0002L +#define HELP_INDEX 0x0003L +#define HELP_CONTENTS 0x0003L +#define HELP_HELPONHELP 0x0004L +#define HELP_SETINDEX 0x0005L +#define HELP_SETCONTENTS 0x0005L +#define HELP_CONTEXTPOPUP 0x0008L +#define HELP_FORCEFILE 0x0009L +#define HELP_KEY 0x0101L +#define HELP_COMMAND 0x0102L +#define HELP_PARTIALKEY 0x0105L +#define HELP_MULTIKEY 0x0201L +#define HELP_SETWINPOS 0x0203L +#define HELP_CONTEXTMENU 0x000a +#define HELP_FINDER 0x000b +#define HELP_WM_HELP 0x000c +#define HELP_SETPOPUP_POS 0x000d + +#define HELP_TCARD 0x8000 +#define HELP_TCARD_DATA 0x0010 +#define HELP_TCARD_OTHER_CALLER 0x0011 + +#define IDH_NO_HELP 28440 +#define IDH_MISSING_CONTEXT 28441 +#define IDH_GENERIC_HELP_BUTTON 28442 +#define IDH_OK 28443 +#define IDH_CANCEL 28444 +#define IDH_HELP 28445 + +#ifdef UNICODE +#define WinHelp WinHelpW +#else +#define WinHelp WinHelpA +#endif + + WINUSERAPI WINBOOL WINAPI WinHelpA(HWND hWndMain,LPCSTR lpszHelp,UINT uCommand,ULONG_PTR dwData); + WINUSERAPI WINBOOL WINAPI WinHelpW(HWND hWndMain,LPCWSTR lpszHelp,UINT uCommand,ULONG_PTR dwData); +#endif + +#define GR_GDIOBJECTS 0 +#define GR_USEROBJECTS 1 + + WINUSERAPI DWORD WINAPI GetGuiResources(HANDLE hProcess,DWORD uiFlags); + +#ifndef NOSYSPARAMSINFO + +#define SPI_GETBEEP 0x0001 +#define SPI_SETBEEP 0x0002 +#define SPI_GETMOUSE 0x0003 +#define SPI_SETMOUSE 0x0004 +#define SPI_GETBORDER 0x0005 +#define SPI_SETBORDER 0x0006 +#define SPI_GETKEYBOARDSPEED 0x000A +#define SPI_SETKEYBOARDSPEED 0x000B +#define SPI_LANGDRIVER 0x000C +#define SPI_ICONHORIZONTALSPACING 0x000D +#define SPI_GETSCREENSAVETIMEOUT 0x000E +#define SPI_SETSCREENSAVETIMEOUT 0x000F +#define SPI_GETSCREENSAVEACTIVE 0x0010 +#define SPI_SETSCREENSAVEACTIVE 0x0011 +#define SPI_GETGRIDGRANULARITY 0x0012 +#define SPI_SETGRIDGRANULARITY 0x0013 +#define SPI_SETDESKWALLPAPER 0x0014 +#define SPI_SETDESKPATTERN 0x0015 +#define SPI_GETKEYBOARDDELAY 0x0016 +#define SPI_SETKEYBOARDDELAY 0x0017 +#define SPI_ICONVERTICALSPACING 0x0018 +#define SPI_GETICONTITLEWRAP 0x0019 +#define SPI_SETICONTITLEWRAP 0x001A +#define SPI_GETMENUDROPALIGNMENT 0x001B +#define SPI_SETMENUDROPALIGNMENT 0x001C +#define SPI_SETDOUBLECLKWIDTH 0x001D +#define SPI_SETDOUBLECLKHEIGHT 0x001E +#define SPI_GETICONTITLELOGFONT 0x001F +#define SPI_SETDOUBLECLICKTIME 0x0020 +#define SPI_SETMOUSEBUTTONSWAP 0x0021 +#define SPI_SETICONTITLELOGFONT 0x0022 +#define SPI_GETFASTTASKSWITCH 0x0023 +#define SPI_SETFASTTASKSWITCH 0x0024 +#define SPI_SETDRAGFULLWINDOWS 0x0025 +#define SPI_GETDRAGFULLWINDOWS 0x0026 +#define SPI_GETNONCLIENTMETRICS 0x0029 +#define SPI_SETNONCLIENTMETRICS 0x002A +#define SPI_GETMINIMIZEDMETRICS 0x002B +#define SPI_SETMINIMIZEDMETRICS 0x002C +#define SPI_GETICONMETRICS 0x002D +#define SPI_SETICONMETRICS 0x002E +#define SPI_SETWORKAREA 0x002F +#define SPI_GETWORKAREA 0x0030 +#define SPI_SETPENWINDOWS 0x0031 + +#define SPI_GETHIGHCONTRAST 0x0042 +#define SPI_SETHIGHCONTRAST 0x0043 +#define SPI_GETKEYBOARDPREF 0x0044 +#define SPI_SETKEYBOARDPREF 0x0045 +#define SPI_GETSCREENREADER 0x0046 +#define SPI_SETSCREENREADER 0x0047 +#define SPI_GETANIMATION 0x0048 +#define SPI_SETANIMATION 0x0049 +#define SPI_GETFONTSMOOTHING 0x004A +#define SPI_SETFONTSMOOTHING 0x004B +#define SPI_SETDRAGWIDTH 0x004C +#define SPI_SETDRAGHEIGHT 0x004D +#define SPI_SETHANDHELD 0x004E +#define SPI_GETLOWPOWERTIMEOUT 0x004F +#define SPI_GETPOWEROFFTIMEOUT 0x0050 +#define SPI_SETLOWPOWERTIMEOUT 0x0051 +#define SPI_SETPOWEROFFTIMEOUT 0x0052 +#define SPI_GETLOWPOWERACTIVE 0x0053 +#define SPI_GETPOWEROFFACTIVE 0x0054 +#define SPI_SETLOWPOWERACTIVE 0x0055 +#define SPI_SETPOWEROFFACTIVE 0x0056 +#define SPI_SETCURSORS 0x0057 +#define SPI_SETICONS 0x0058 +#define SPI_GETDEFAULTINPUTLANG 0x0059 +#define SPI_SETDEFAULTINPUTLANG 0x005A +#define SPI_SETLANGTOGGLE 0x005B +#define SPI_GETWINDOWSEXTENSION 0x005C +#define SPI_SETMOUSETRAILS 0x005D +#define SPI_GETMOUSETRAILS 0x005E +#define SPI_SETSCREENSAVERRUNNING 0x0061 +#define SPI_SCREENSAVERRUNNING SPI_SETSCREENSAVERRUNNING +#define SPI_GETFILTERKEYS 0x0032 +#define SPI_SETFILTERKEYS 0x0033 +#define SPI_GETTOGGLEKEYS 0x0034 +#define SPI_SETTOGGLEKEYS 0x0035 +#define SPI_GETMOUSEKEYS 0x0036 +#define SPI_SETMOUSEKEYS 0x0037 +#define SPI_GETSHOWSOUNDS 0x0038 +#define SPI_SETSHOWSOUNDS 0x0039 +#define SPI_GETSTICKYKEYS 0x003A +#define SPI_SETSTICKYKEYS 0x003B +#define SPI_GETACCESSTIMEOUT 0x003C +#define SPI_SETACCESSTIMEOUT 0x003D +#define SPI_GETSERIALKEYS 0x003E +#define SPI_SETSERIALKEYS 0x003F +#define SPI_GETSOUNDSENTRY 0x0040 +#define SPI_SETSOUNDSENTRY 0x0041 +#define SPI_GETSNAPTODEFBUTTON 0x005F +#define SPI_SETSNAPTODEFBUTTON 0x0060 +#define SPI_GETMOUSEHOVERWIDTH 0x0062 +#define SPI_SETMOUSEHOVERWIDTH 0x0063 +#define SPI_GETMOUSEHOVERHEIGHT 0x0064 +#define SPI_SETMOUSEHOVERHEIGHT 0x0065 +#define SPI_GETMOUSEHOVERTIME 0x0066 +#define SPI_SETMOUSEHOVERTIME 0x0067 +#define SPI_GETWHEELSCROLLLINES 0x0068 +#define SPI_SETWHEELSCROLLLINES 0x0069 +#define SPI_GETMENUSHOWDELAY 0x006A +#define SPI_SETMENUSHOWDELAY 0x006B +#define SPI_GETSHOWIMEUI 0x006E +#define SPI_SETSHOWIMEUI 0x006F +#define SPI_GETMOUSESPEED 0x0070 +#define SPI_SETMOUSESPEED 0x0071 +#define SPI_GETSCREENSAVERRUNNING 0x0072 +#define SPI_GETDESKWALLPAPER 0x0073 + +#define SPI_GETACTIVEWINDOWTRACKING 0x1000 +#define SPI_SETACTIVEWINDOWTRACKING 0x1001 +#define SPI_GETMENUANIMATION 0x1002 +#define SPI_SETMENUANIMATION 0x1003 +#define SPI_GETCOMBOBOXANIMATION 0x1004 +#define SPI_SETCOMBOBOXANIMATION 0x1005 +#define SPI_GETLISTBOXSMOOTHSCROLLING 0x1006 +#define SPI_SETLISTBOXSMOOTHSCROLLING 0x1007 +#define SPI_GETGRADIENTCAPTIONS 0x1008 +#define SPI_SETGRADIENTCAPTIONS 0x1009 +#define SPI_GETKEYBOARDCUES 0x100A +#define SPI_SETKEYBOARDCUES 0x100B +#define SPI_GETMENUUNDERLINES SPI_GETKEYBOARDCUES +#define SPI_SETMENUUNDERLINES SPI_SETKEYBOARDCUES +#define SPI_GETACTIVEWNDTRKZORDER 0x100C +#define SPI_SETACTIVEWNDTRKZORDER 0x100D +#define SPI_GETHOTTRACKING 0x100E +#define SPI_SETHOTTRACKING 0x100F +#define SPI_GETMENUFADE 0x1012 +#define SPI_SETMENUFADE 0x1013 +#define SPI_GETSELECTIONFADE 0x1014 +#define SPI_SETSELECTIONFADE 0x1015 +#define SPI_GETTOOLTIPANIMATION 0x1016 +#define SPI_SETTOOLTIPANIMATION 0x1017 +#define SPI_GETTOOLTIPFADE 0x1018 +#define SPI_SETTOOLTIPFADE 0x1019 +#define SPI_GETCURSORSHADOW 0x101A +#define SPI_SETCURSORSHADOW 0x101B +#define SPI_GETMOUSESONAR 0x101C +#define SPI_SETMOUSESONAR 0x101D +#define SPI_GETMOUSECLICKLOCK 0x101E +#define SPI_SETMOUSECLICKLOCK 0x101F +#define SPI_GETMOUSEVANISH 0x1020 +#define SPI_SETMOUSEVANISH 0x1021 +#define SPI_GETFLATMENU 0x1022 +#define SPI_SETFLATMENU 0x1023 +#define SPI_GETDROPSHADOW 0x1024 +#define SPI_SETDROPSHADOW 0x1025 +#define SPI_GETBLOCKSENDINPUTRESETS 0x1026 +#define SPI_SETBLOCKSENDINPUTRESETS 0x1027 +#define SPI_GETUIEFFECTS 0x103E +#define SPI_SETUIEFFECTS 0x103F +#define SPI_GETFOREGROUNDLOCKTIMEOUT 0x2000 +#define SPI_SETFOREGROUNDLOCKTIMEOUT 0x2001 +#define SPI_GETACTIVEWNDTRKTIMEOUT 0x2002 +#define SPI_SETACTIVEWNDTRKTIMEOUT 0x2003 +#define SPI_GETFOREGROUNDFLASHCOUNT 0x2004 +#define SPI_SETFOREGROUNDFLASHCOUNT 0x2005 +#define SPI_GETCARETWIDTH 0x2006 +#define SPI_SETCARETWIDTH 0x2007 +#define SPI_GETMOUSECLICKLOCKTIME 0x2008 +#define SPI_SETMOUSECLICKLOCKTIME 0x2009 +#define SPI_GETFONTSMOOTHINGTYPE 0x200A +#define SPI_SETFONTSMOOTHINGTYPE 0x200B + +#define FE_FONTSMOOTHINGSTANDARD 0x0001 +#define FE_FONTSMOOTHINGCLEARTYPE 0x0002 +#define FE_FONTSMOOTHINGDOCKING 0x8000 + +#define SPI_GETFONTSMOOTHINGCONTRAST 0x200C +#define SPI_SETFONTSMOOTHINGCONTRAST 0x200D +#define SPI_GETFOCUSBORDERWIDTH 0x200E +#define SPI_SETFOCUSBORDERWIDTH 0x200F +#define SPI_GETFOCUSBORDERHEIGHT 0x2010 +#define SPI_SETFOCUSBORDERHEIGHT 0x2011 +#define SPI_GETFONTSMOOTHINGORIENTATION 0x2012 +#define SPI_SETFONTSMOOTHINGORIENTATION 0x2013 + +#define FE_FONTSMOOTHINGORIENTATIONBGR 0x0000 +#define FE_FONTSMOOTHINGORIENTATIONRGB 0x0001 + +#define SPIF_UPDATEINIFILE 0x0001 +#define SPIF_SENDWININICHANGE 0x0002 +#define SPIF_SENDCHANGE SPIF_SENDWININICHANGE + +#define METRICS_USEDEFAULT -1 +#ifdef _WINGDI_ +#ifndef NOGDI + typedef struct tagNONCLIENTMETRICSA { + UINT cbSize; + int iBorderWidth; + int iScrollWidth; + int iScrollHeight; + int iCaptionWidth; + int iCaptionHeight; + LOGFONTA lfCaptionFont; + int iSmCaptionWidth; + int iSmCaptionHeight; + LOGFONTA lfSmCaptionFont; + int iMenuWidth; + int iMenuHeight; + LOGFONTA lfMenuFont; + LOGFONTA lfStatusFont; + LOGFONTA lfMessageFont; + } NONCLIENTMETRICSA,*PNONCLIENTMETRICSA,*LPNONCLIENTMETRICSA; + + typedef struct tagNONCLIENTMETRICSW { + UINT cbSize; + int iBorderWidth; + int iScrollWidth; + int iScrollHeight; + int iCaptionWidth; + int iCaptionHeight; + LOGFONTW lfCaptionFont; + int iSmCaptionWidth; + int iSmCaptionHeight; + LOGFONTW lfSmCaptionFont; + int iMenuWidth; + int iMenuHeight; + LOGFONTW lfMenuFont; + LOGFONTW lfStatusFont; + LOGFONTW lfMessageFont; + } NONCLIENTMETRICSW,*PNONCLIENTMETRICSW,*LPNONCLIENTMETRICSW; + +#ifdef UNICODE + typedef NONCLIENTMETRICSW NONCLIENTMETRICS; + typedef PNONCLIENTMETRICSW PNONCLIENTMETRICS; + typedef LPNONCLIENTMETRICSW LPNONCLIENTMETRICS; +#else + typedef NONCLIENTMETRICSA NONCLIENTMETRICS; + typedef PNONCLIENTMETRICSA PNONCLIENTMETRICS; + typedef LPNONCLIENTMETRICSA LPNONCLIENTMETRICS; +#endif +#endif +#endif + +#define ARW_BOTTOMLEFT 0x0000L +#define ARW_BOTTOMRIGHT 0x0001L +#define ARW_TOPLEFT 0x0002L +#define ARW_TOPRIGHT 0x0003L +#define ARW_STARTMASK 0x0003L +#define ARW_STARTRIGHT 0x0001L +#define ARW_STARTTOP 0x0002L + +#define ARW_LEFT 0x0000L +#define ARW_RIGHT 0x0000L +#define ARW_UP 0x0004L +#define ARW_DOWN 0x0004L +#define ARW_HIDE 0x0008L + + typedef struct tagMINIMIZEDMETRICS { + UINT cbSize; + int iWidth; + int iHorzGap; + int iVertGap; + int iArrange; + } MINIMIZEDMETRICS,*PMINIMIZEDMETRICS,*LPMINIMIZEDMETRICS; + +#ifdef _WINGDI_ +#ifndef NOGDI + typedef struct tagICONMETRICSA { + UINT cbSize; + int iHorzSpacing; + int iVertSpacing; + int iTitleWrap; + LOGFONTA lfFont; + } ICONMETRICSA,*PICONMETRICSA,*LPICONMETRICSA; + + typedef struct tagICONMETRICSW { + UINT cbSize; + int iHorzSpacing; + int iVertSpacing; + int iTitleWrap; + LOGFONTW lfFont; + } ICONMETRICSW,*PICONMETRICSW,*LPICONMETRICSW; + +#ifdef UNICODE + typedef ICONMETRICSW ICONMETRICS; + typedef PICONMETRICSW PICONMETRICS; + typedef LPICONMETRICSW LPICONMETRICS; +#else + typedef ICONMETRICSA ICONMETRICS; + typedef PICONMETRICSA PICONMETRICS; + typedef LPICONMETRICSA LPICONMETRICS; +#endif +#endif +#endif + + typedef struct tagANIMATIONINFO { + UINT cbSize; + int iMinAnimate; + } ANIMATIONINFO,*LPANIMATIONINFO; + + typedef struct tagSERIALKEYSA { + UINT cbSize; + DWORD dwFlags; + LPSTR lpszActivePort; + LPSTR lpszPort; + UINT iBaudRate; + UINT iPortState; + UINT iActive; + } SERIALKEYSA,*LPSERIALKEYSA; + + typedef struct tagSERIALKEYSW { + UINT cbSize; + DWORD dwFlags; + LPWSTR lpszActivePort; + LPWSTR lpszPort; + UINT iBaudRate; + UINT iPortState; + UINT iActive; + } SERIALKEYSW,*LPSERIALKEYSW; + +#ifdef UNICODE + typedef SERIALKEYSW SERIALKEYS; + typedef LPSERIALKEYSW LPSERIALKEYS; +#else + typedef SERIALKEYSA SERIALKEYS; + typedef LPSERIALKEYSA LPSERIALKEYS; +#endif + +#define SERKF_SERIALKEYSON 0x00000001 +#define SERKF_AVAILABLE 0x00000002 +#define SERKF_INDICATOR 0x00000004 + + typedef struct tagHIGHCONTRASTA { + UINT cbSize; + DWORD dwFlags; + LPSTR lpszDefaultScheme; + } HIGHCONTRASTA,*LPHIGHCONTRASTA; + + typedef struct tagHIGHCONTRASTW { + UINT cbSize; + DWORD dwFlags; + LPWSTR lpszDefaultScheme; + } HIGHCONTRASTW,*LPHIGHCONTRASTW; + +#ifdef UNICODE + typedef HIGHCONTRASTW HIGHCONTRAST; + typedef LPHIGHCONTRASTW LPHIGHCONTRAST; +#else + typedef HIGHCONTRASTA HIGHCONTRAST; + typedef LPHIGHCONTRASTA LPHIGHCONTRAST; +#endif + +#define HCF_HIGHCONTRASTON 0x00000001 +#define HCF_AVAILABLE 0x00000002 +#define HCF_HOTKEYACTIVE 0x00000004 +#define HCF_CONFIRMHOTKEY 0x00000008 +#define HCF_HOTKEYSOUND 0x00000010 +#define HCF_INDICATOR 0x00000020 +#define HCF_HOTKEYAVAILABLE 0x00000040 +#define HCF_LOGONDESKTOP 0x00000100 +#define HCF_DEFAULTDESKTOP 0x00000200 + +#define CDS_UPDATEREGISTRY 0x00000001 +#define CDS_TEST 0x00000002 +#define CDS_FULLSCREEN 0x00000004 +#define CDS_GLOBAL 0x00000008 +#define CDS_SET_PRIMARY 0x00000010 +#define CDS_VIDEOPARAMETERS 0x00000020 +#define CDS_RESET 0x40000000 +#define CDS_NORESET 0x10000000 + +//gr #include + +#define DISP_CHANGE_SUCCESSFUL 0 +#define DISP_CHANGE_RESTART 1 +#define DISP_CHANGE_FAILED -1 +#define DISP_CHANGE_BADMODE -2 +#define DISP_CHANGE_NOTUPDATED -3 +#define DISP_CHANGE_BADFLAGS -4 +#define DISP_CHANGE_BADPARAM -5 +#define DISP_CHANGE_BADDUALVIEW -6 + +#ifdef _WINGDI_ +#ifndef NOGDI + +#ifdef UNICODE +#define ChangeDisplaySettings ChangeDisplaySettingsW +#define ChangeDisplaySettingsEx ChangeDisplaySettingsExW +#define EnumDisplaySettings EnumDisplaySettingsW +#define EnumDisplaySettingsEx EnumDisplaySettingsExW +#define EnumDisplayDevices EnumDisplayDevicesW +#else +#define ChangeDisplaySettings ChangeDisplaySettingsA +#define ChangeDisplaySettingsEx ChangeDisplaySettingsExA +#define EnumDisplaySettings EnumDisplaySettingsA +#define EnumDisplaySettingsEx EnumDisplaySettingsExA +#define EnumDisplayDevices EnumDisplayDevicesA +#endif + + WINUSERAPI LONG WINAPI ChangeDisplaySettingsA(LPDEVMODEA lpDevMode,DWORD dwFlags); + WINUSERAPI LONG WINAPI ChangeDisplaySettingsW(LPDEVMODEW lpDevMode,DWORD dwFlags); + WINUSERAPI LONG WINAPI ChangeDisplaySettingsExA(LPCSTR lpszDeviceName,LPDEVMODEA lpDevMode,HWND hwnd,DWORD dwflags,LPVOID lParam); + WINUSERAPI LONG WINAPI ChangeDisplaySettingsExW(LPCWSTR lpszDeviceName,LPDEVMODEW lpDevMode,HWND hwnd,DWORD dwflags,LPVOID lParam); + +#define ENUM_CURRENT_SETTINGS ((DWORD)-1) +#define ENUM_REGISTRY_SETTINGS ((DWORD)-2) + + WINUSERAPI WINBOOL WINAPI EnumDisplaySettingsA(LPCSTR lpszDeviceName,DWORD iModeNum,LPDEVMODEA lpDevMode); + WINUSERAPI WINBOOL WINAPI EnumDisplaySettingsW(LPCWSTR lpszDeviceName,DWORD iModeNum,LPDEVMODEW lpDevMode); + WINUSERAPI WINBOOL WINAPI EnumDisplaySettingsExA(LPCSTR lpszDeviceName,DWORD iModeNum,LPDEVMODEA lpDevMode,DWORD dwFlags); + WINUSERAPI WINBOOL WINAPI EnumDisplaySettingsExW(LPCWSTR lpszDeviceName,DWORD iModeNum,LPDEVMODEW lpDevMode,DWORD dwFlags); + +#define EDS_RAWMODE 0x00000002 + + WINUSERAPI WINBOOL WINAPI EnumDisplayDevicesA(LPCSTR lpDevice,DWORD iDevNum,PDISPLAY_DEVICEA lpDisplayDevice,DWORD dwFlags); + WINUSERAPI WINBOOL WINAPI EnumDisplayDevicesW(LPCWSTR lpDevice,DWORD iDevNum,PDISPLAY_DEVICEW lpDisplayDevice,DWORD dwFlags); +#endif +#endif + +#ifdef UNICODE +#define SystemParametersInfo SystemParametersInfoW +#else +#define SystemParametersInfo SystemParametersInfoA +#endif + + WINUSERAPI WINBOOL WINAPI SystemParametersInfoA(UINT uiAction,UINT uiParam,PVOID pvParam,UINT fWinIni); + WINUSERAPI WINBOOL WINAPI SystemParametersInfoW(UINT uiAction,UINT uiParam,PVOID pvParam,UINT fWinIni); +#endif + + typedef struct tagFILTERKEYS { + UINT cbSize; + DWORD dwFlags; + DWORD iWaitMSec; + DWORD iDelayMSec; + DWORD iRepeatMSec; + DWORD iBounceMSec; + } FILTERKEYS,*LPFILTERKEYS; + +#define FKF_FILTERKEYSON 0x00000001 +#define FKF_AVAILABLE 0x00000002 +#define FKF_HOTKEYACTIVE 0x00000004 +#define FKF_CONFIRMHOTKEY 0x00000008 +#define FKF_HOTKEYSOUND 0x00000010 +#define FKF_INDICATOR 0x00000020 +#define FKF_CLICKON 0x00000040 + + typedef struct tagSTICKYKEYS { + UINT cbSize; + DWORD dwFlags; + } STICKYKEYS,*LPSTICKYKEYS; + +#define SKF_STICKYKEYSON 0x00000001 +#define SKF_AVAILABLE 0x00000002 +#define SKF_HOTKEYACTIVE 0x00000004 +#define SKF_CONFIRMHOTKEY 0x00000008 +#define SKF_HOTKEYSOUND 0x00000010 +#define SKF_INDICATOR 0x00000020 +#define SKF_AUDIBLEFEEDBACK 0x00000040 +#define SKF_TRISTATE 0x00000080 +#define SKF_TWOKEYSOFF 0x00000100 +#define SKF_LALTLATCHED 0x10000000 +#define SKF_LCTLLATCHED 0x04000000 +#define SKF_LSHIFTLATCHED 0x01000000 +#define SKF_RALTLATCHED 0x20000000 +#define SKF_RCTLLATCHED 0x08000000 +#define SKF_RSHIFTLATCHED 0x02000000 +#define SKF_LWINLATCHED 0x40000000 +#define SKF_RWINLATCHED 0x80000000 +#define SKF_LALTLOCKED 0x00100000 +#define SKF_LCTLLOCKED 0x00040000 +#define SKF_LSHIFTLOCKED 0x00010000 +#define SKF_RALTLOCKED 0x00200000 +#define SKF_RCTLLOCKED 0x00080000 +#define SKF_RSHIFTLOCKED 0x00020000 +#define SKF_LWINLOCKED 0x00400000 +#define SKF_RWINLOCKED 0x00800000 + + typedef struct tagMOUSEKEYS { + UINT cbSize; + DWORD dwFlags; + DWORD iMaxSpeed; + DWORD iTimeToMaxSpeed; + DWORD iCtrlSpeed; + DWORD dwReserved1; + DWORD dwReserved2; + } MOUSEKEYS,*LPMOUSEKEYS; + +#define MKF_MOUSEKEYSON 0x00000001 +#define MKF_AVAILABLE 0x00000002 +#define MKF_HOTKEYACTIVE 0x00000004 +#define MKF_CONFIRMHOTKEY 0x00000008 +#define MKF_HOTKEYSOUND 0x00000010 +#define MKF_INDICATOR 0x00000020 +#define MKF_MODIFIERS 0x00000040 +#define MKF_REPLACENUMBERS 0x00000080 +#define MKF_LEFTBUTTONSEL 0x10000000 +#define MKF_RIGHTBUTTONSEL 0x20000000 +#define MKF_LEFTBUTTONDOWN 0x01000000 +#define MKF_RIGHTBUTTONDOWN 0x02000000 +#define MKF_MOUSEMODE 0x80000000 + + typedef struct tagACCESSTIMEOUT { + UINT cbSize; + DWORD dwFlags; + DWORD iTimeOutMSec; + } ACCESSTIMEOUT,*LPACCESSTIMEOUT; + +#define ATF_TIMEOUTON 0x00000001 +#define ATF_ONOFFFEEDBACK 0x00000002 + +#define SSGF_NONE 0 +#define SSGF_DISPLAY 3 + +#define SSTF_NONE 0 +#define SSTF_CHARS 1 +#define SSTF_BORDER 2 +#define SSTF_DISPLAY 3 + +#define SSWF_NONE 0 +#define SSWF_TITLE 1 +#define SSWF_WINDOW 2 +#define SSWF_DISPLAY 3 +#define SSWF_CUSTOM 4 + + typedef struct tagSOUNDSENTRYA { + UINT cbSize; + DWORD dwFlags; + DWORD iFSTextEffect; + DWORD iFSTextEffectMSec; + DWORD iFSTextEffectColorBits; + DWORD iFSGrafEffect; + DWORD iFSGrafEffectMSec; + DWORD iFSGrafEffectColor; + DWORD iWindowsEffect; + DWORD iWindowsEffectMSec; + LPSTR lpszWindowsEffectDLL; + DWORD iWindowsEffectOrdinal; + } SOUNDSENTRYA,*LPSOUNDSENTRYA; + + typedef struct tagSOUNDSENTRYW { + UINT cbSize; + DWORD dwFlags; + DWORD iFSTextEffect; + DWORD iFSTextEffectMSec; + DWORD iFSTextEffectColorBits; + DWORD iFSGrafEffect; + DWORD iFSGrafEffectMSec; + DWORD iFSGrafEffectColor; + DWORD iWindowsEffect; + DWORD iWindowsEffectMSec; + LPWSTR lpszWindowsEffectDLL; + DWORD iWindowsEffectOrdinal; + } SOUNDSENTRYW,*LPSOUNDSENTRYW; + +#ifdef UNICODE + typedef SOUNDSENTRYW SOUNDSENTRY; + typedef LPSOUNDSENTRYW LPSOUNDSENTRY; +#else + typedef SOUNDSENTRYA SOUNDSENTRY; + typedef LPSOUNDSENTRYA LPSOUNDSENTRY; +#endif + +#define SSF_SOUNDSENTRYON 0x00000001 +#define SSF_AVAILABLE 0x00000002 +#define SSF_INDICATOR 0x00000004 + + typedef struct tagTOGGLEKEYS { + UINT cbSize; + DWORD dwFlags; + } TOGGLEKEYS,*LPTOGGLEKEYS; + +#define TKF_TOGGLEKEYSON 0x00000001 +#define TKF_AVAILABLE 0x00000002 +#define TKF_HOTKEYACTIVE 0x00000004 +#define TKF_CONFIRMHOTKEY 0x00000008 +#define TKF_HOTKEYSOUND 0x00000010 +#define TKF_INDICATOR 0x00000020 + + WINUSERAPI VOID WINAPI SetDebugErrorLevel(DWORD dwLevel); + +#define SLE_ERROR 0x00000001 +#define SLE_MINORERROR 0x00000002 +#define SLE_WARNING 0x00000003 + + WINUSERAPI VOID WINAPI SetLastErrorEx(DWORD dwErrCode,DWORD dwType); + WINUSERAPI int WINAPI InternalGetWindowText(HWND hWnd,LPWSTR pString,int cchMaxCount); + +#ifdef WINNT + WINUSERAPI WINBOOL WINAPI EndTask(HWND hWnd,WINBOOL fShutDown,WINBOOL fForce); +#endif + +#define MONITOR_DEFAULTTONULL 0x00000000 +#define MONITOR_DEFAULTTOPRIMARY 0x00000001 +#define MONITOR_DEFAULTTONEAREST 0x00000002 + + WINUSERAPI HMONITOR WINAPI MonitorFromPoint(POINT pt,DWORD dwFlags); + WINUSERAPI HMONITOR WINAPI MonitorFromRect(LPCRECT lprc,DWORD dwFlags); + WINUSERAPI HMONITOR WINAPI MonitorFromWindow(HWND hwnd,DWORD dwFlags); + +#define MONITORINFOF_PRIMARY 0x00000001 + +#ifndef CCHDEVICENAME +#define CCHDEVICENAME 32 +#endif + + typedef struct tagMONITORINFO { + DWORD cbSize; + RECT rcMonitor; + RECT rcWork; + DWORD dwFlags; + } MONITORINFO,*LPMONITORINFO; + +#ifdef __cplusplus + typedef struct tagMONITORINFOEXA : public tagMONITORINFO { + CHAR szDevice[CCHDEVICENAME]; + } MONITORINFOEXA,*LPMONITORINFOEXA; + + typedef struct tagMONITORINFOEXW : public tagMONITORINFO { + WCHAR szDevice[CCHDEVICENAME]; + } MONITORINFOEXW,*LPMONITORINFOEXW; + +#ifdef UNICODE + typedef MONITORINFOEXW MONITORINFOEX; + typedef LPMONITORINFOEXW LPMONITORINFOEX; +#else + typedef MONITORINFOEXA MONITORINFOEX; + typedef LPMONITORINFOEXA LPMONITORINFOEX; +#endif +#else + typedef struct tagMONITORINFOEXA { + MONITORINFO mi; + CHAR szDevice[CCHDEVICENAME]; + } MONITORINFOEXA,*LPMONITORINFOEXA; + + typedef struct tagMONITORINFOEXW { + MONITORINFO mi; + WCHAR szDevice[CCHDEVICENAME]; + } MONITORINFOEXW,*LPMONITORINFOEXW; +#ifdef UNICODE + typedef MONITORINFOEXW MONITORINFOEX; + typedef LPMONITORINFOEXW LPMONITORINFOEX; +#else + typedef MONITORINFOEXA MONITORINFOEX; + typedef LPMONITORINFOEXA LPMONITORINFOEX; +#endif +#endif + +#ifdef UNICODE +#define GetMonitorInfo GetMonitorInfoW +#else +#define GetMonitorInfo GetMonitorInfoA +#endif + + WINUSERAPI WINBOOL WINAPI GetMonitorInfoA(HMONITOR hMonitor,LPMONITORINFO lpmi); + WINUSERAPI WINBOOL WINAPI GetMonitorInfoW(HMONITOR hMonitor,LPMONITORINFO lpmi); + + typedef WINBOOL (CALLBACK *MONITORENUMPROC)(HMONITOR,HDC,LPRECT,LPARAM); + + WINUSERAPI WINBOOL WINAPI EnumDisplayMonitors(HDC hdc,LPCRECT lprcClip,MONITORENUMPROC lpfnEnum,LPARAM dwData); + +#ifndef NOWINABLE + WINUSERAPI VOID WINAPI NotifyWinEvent(DWORD event,HWND hwnd,LONG idObject,LONG idChild); + + typedef VOID (CALLBACK *WINEVENTPROC)(HWINEVENTHOOK hWinEventHook,DWORD event,HWND hwnd,LONG idObject,LONG idChild,DWORD idEventThread,DWORD dwmsEventTime); + + WINUSERAPI HWINEVENTHOOK WINAPI SetWinEventHook(DWORD eventMin,DWORD eventMax,HMODULE hmodWinEventProc,WINEVENTPROC pfnWinEventProc,DWORD idProcess,DWORD idThread,DWORD dwFlags); + WINUSERAPI WINBOOL WINAPI IsWinEventHookInstalled(DWORD event); + +#define WINEVENT_OUTOFCONTEXT 0x0000 +#define WINEVENT_SKIPOWNTHREAD 0x0001 +#define WINEVENT_SKIPOWNPROCESS 0x0002 +#define WINEVENT_INCONTEXT 0x0004 + + WINUSERAPI WINBOOL WINAPI UnhookWinEvent(HWINEVENTHOOK hWinEventHook); + +#define CHILDID_SELF 0 +#define INDEXID_OBJECT 0 +#define INDEXID_CONTAINER 0 + +#define OBJID_WINDOW ((LONG)0x00000000) +#define OBJID_SYSMENU ((LONG)0xFFFFFFFF) +#define OBJID_TITLEBAR ((LONG)0xFFFFFFFE) +#define OBJID_MENU ((LONG)0xFFFFFFFD) +#define OBJID_CLIENT ((LONG)0xFFFFFFFC) +#define OBJID_VSCROLL ((LONG)0xFFFFFFFB) +#define OBJID_HSCROLL ((LONG)0xFFFFFFFA) +#define OBJID_SIZEGRIP ((LONG)0xFFFFFFF9) +#define OBJID_CARET ((LONG)0xFFFFFFF8) +#define OBJID_CURSOR ((LONG)0xFFFFFFF7) +#define OBJID_ALERT ((LONG)0xFFFFFFF6) +#define OBJID_SOUND ((LONG)0xFFFFFFF5) +#define OBJID_QUERYCLASSNAMEIDX ((LONG)0xFFFFFFF4) +#define OBJID_NATIVEOM ((LONG)0xFFFFFFF0) + +#define EVENT_MIN 0x00000001 +#define EVENT_MAX 0x7FFFFFFF + +#define EVENT_SYSTEM_SOUND 0x0001 +#define EVENT_SYSTEM_ALERT 0x0002 +#define EVENT_SYSTEM_FOREGROUND 0x0003 +#define EVENT_SYSTEM_MENUSTART 0x0004 +#define EVENT_SYSTEM_MENUEND 0x0005 +#define EVENT_SYSTEM_MENUPOPUPSTART 0x0006 +#define EVENT_SYSTEM_MENUPOPUPEND 0x0007 +#define EVENT_SYSTEM_CAPTURESTART 0x0008 +#define EVENT_SYSTEM_CAPTUREEND 0x0009 +#define EVENT_SYSTEM_MOVESIZESTART 0x000A +#define EVENT_SYSTEM_MOVESIZEEND 0x000B +#define EVENT_SYSTEM_CONTEXTHELPSTART 0x000C +#define EVENT_SYSTEM_CONTEXTHELPEND 0x000D +#define EVENT_SYSTEM_DRAGDROPSTART 0x000E +#define EVENT_SYSTEM_DRAGDROPEND 0x000F +#define EVENT_SYSTEM_DIALOGSTART 0x0010 +#define EVENT_SYSTEM_DIALOGEND 0x0011 +#define EVENT_SYSTEM_SCROLLINGSTART 0x0012 +#define EVENT_SYSTEM_SCROLLINGEND 0x0013 +#define EVENT_SYSTEM_SWITCHSTART 0x0014 +#define EVENT_SYSTEM_SWITCHEND 0x0015 +#define EVENT_SYSTEM_MINIMIZESTART 0x0016 +#define EVENT_SYSTEM_MINIMIZEEND 0x0017 + +#define EVENT_CONSOLE_CARET 0x4001 +#define EVENT_CONSOLE_UPDATE_REGION 0x4002 +#define EVENT_CONSOLE_UPDATE_SIMPLE 0x4003 +#define EVENT_CONSOLE_UPDATE_SCROLL 0x4004 +#define EVENT_CONSOLE_LAYOUT 0x4005 +#define EVENT_CONSOLE_START_APPLICATION 0x4006 +#define EVENT_CONSOLE_END_APPLICATION 0x4007 + +#define CONSOLE_APPLICATION_16BIT 0x0001 + +#define CONSOLE_CARET_SELECTION 0x0001 +#define CONSOLE_CARET_VISIBLE 0x0002 + +#define EVENT_OBJECT_CREATE 0x8000 +#define EVENT_OBJECT_DESTROY 0x8001 +#define EVENT_OBJECT_SHOW 0x8002 +#define EVENT_OBJECT_HIDE 0x8003 +#define EVENT_OBJECT_REORDER 0x8004 + +#define EVENT_OBJECT_FOCUS 0x8005 +#define EVENT_OBJECT_SELECTION 0x8006 +#define EVENT_OBJECT_SELECTIONADD 0x8007 +#define EVENT_OBJECT_SELECTIONREMOVE 0x8008 +#define EVENT_OBJECT_SELECTIONWITHIN 0x8009 + +#define EVENT_OBJECT_STATECHANGE 0x800A + +#define EVENT_OBJECT_LOCATIONCHANGE 0x800B + +#define EVENT_OBJECT_NAMECHANGE 0x800C +#define EVENT_OBJECT_DESCRIPTIONCHANGE 0x800D +#define EVENT_OBJECT_VALUECHANGE 0x800E +#define EVENT_OBJECT_PARENTCHANGE 0x800F +#define EVENT_OBJECT_HELPCHANGE 0x8010 +#define EVENT_OBJECT_DEFACTIONCHANGE 0x8011 +#define EVENT_OBJECT_ACCELERATORCHANGE 0x8012 + +#define SOUND_SYSTEM_STARTUP 1 +#define SOUND_SYSTEM_SHUTDOWN 2 +#define SOUND_SYSTEM_BEEP 3 +#define SOUND_SYSTEM_ERROR 4 +#define SOUND_SYSTEM_QUESTION 5 +#define SOUND_SYSTEM_WARNING 6 +#define SOUND_SYSTEM_INFORMATION 7 +#define SOUND_SYSTEM_MAXIMIZE 8 +#define SOUND_SYSTEM_MINIMIZE 9 +#define SOUND_SYSTEM_RESTOREUP 10 +#define SOUND_SYSTEM_RESTOREDOWN 11 +#define SOUND_SYSTEM_APPSTART 12 +#define SOUND_SYSTEM_FAULT 13 +#define SOUND_SYSTEM_APPEND 14 +#define SOUND_SYSTEM_MENUCOMMAND 15 +#define SOUND_SYSTEM_MENUPOPUP 16 +#define CSOUND_SYSTEM 16 + +#define ALERT_SYSTEM_INFORMATIONAL 1 +#define ALERT_SYSTEM_WARNING 2 +#define ALERT_SYSTEM_ERROR 3 +#define ALERT_SYSTEM_QUERY 4 +#define ALERT_SYSTEM_CRITICAL 5 +#define CALERT_SYSTEM 6 + + typedef struct tagGUITHREADINFO { + DWORD cbSize; + DWORD flags; + HWND hwndActive; + HWND hwndFocus; + HWND hwndCapture; + HWND hwndMenuOwner; + HWND hwndMoveSize; + HWND hwndCaret; + RECT rcCaret; + } GUITHREADINFO,*PGUITHREADINFO,*LPGUITHREADINFO; + +#define GUI_CARETBLINKING 0x00000001 +#define GUI_INMOVESIZE 0x00000002 +#define GUI_INMENUMODE 0x00000004 +#define GUI_SYSTEMMENUMODE 0x00000008 +#define GUI_POPUPMENUMODE 0x00000010 +#define GUI_16BITTASK 0x00000020 + +#ifdef UNICODE +#define GetWindowModuleFileName GetWindowModuleFileNameW +#else +#define GetWindowModuleFileName GetWindowModuleFileNameA +#endif + + WINUSERAPI WINBOOL WINAPI GetGUIThreadInfo(DWORD idThread,PGUITHREADINFO pgui); + WINUSERAPI UINT WINAPI GetWindowModuleFileNameA(HWND hwnd,LPSTR pszFileName,UINT cchFileNameMax); + WINUSERAPI UINT WINAPI GetWindowModuleFileNameW(HWND hwnd,LPWSTR pszFileName,UINT cchFileNameMax); + +#ifndef NO_STATE_FLAGS +#define STATE_SYSTEM_UNAVAILABLE 0x00000001 +#define STATE_SYSTEM_SELECTED 0x00000002 +#define STATE_SYSTEM_FOCUSED 0x00000004 +#define STATE_SYSTEM_PRESSED 0x00000008 +#define STATE_SYSTEM_CHECKED 0x00000010 +#define STATE_SYSTEM_MIXED 0x00000020 +#define STATE_SYSTEM_INDETERMINATE STATE_SYSTEM_MIXED +#define STATE_SYSTEM_READONLY 0x00000040 +#define STATE_SYSTEM_HOTTRACKED 0x00000080 +#define STATE_SYSTEM_DEFAULT 0x00000100 +#define STATE_SYSTEM_EXPANDED 0x00000200 +#define STATE_SYSTEM_COLLAPSED 0x00000400 +#define STATE_SYSTEM_BUSY 0x00000800 +#define STATE_SYSTEM_FLOATING 0x00001000 +#define STATE_SYSTEM_MARQUEED 0x00002000 +#define STATE_SYSTEM_ANIMATED 0x00004000 +#define STATE_SYSTEM_INVISIBLE 0x00008000 +#define STATE_SYSTEM_OFFSCREEN 0x00010000 +#define STATE_SYSTEM_SIZEABLE 0x00020000 +#define STATE_SYSTEM_MOVEABLE 0x00040000 +#define STATE_SYSTEM_SELFVOICING 0x00080000 +#define STATE_SYSTEM_FOCUSABLE 0x00100000 +#define STATE_SYSTEM_SELECTABLE 0x00200000 +#define STATE_SYSTEM_LINKED 0x00400000 +#define STATE_SYSTEM_TRAVERSED 0x00800000 +#define STATE_SYSTEM_MULTISELECTABLE 0x01000000 +#define STATE_SYSTEM_EXTSELECTABLE 0x02000000 +#define STATE_SYSTEM_ALERT_LOW 0x04000000 +#define STATE_SYSTEM_ALERT_MEDIUM 0x08000000 +#define STATE_SYSTEM_ALERT_HIGH 0x10000000 +#define STATE_SYSTEM_PROTECTED 0x20000000 +#define STATE_SYSTEM_VALID 0x3FFFFFFF +#endif + +#define CCHILDREN_TITLEBAR 5 +#define CCHILDREN_SCROLLBAR 5 + + typedef struct tagCURSORINFO { + DWORD cbSize; + DWORD flags; + HCURSOR hCursor; + POINT ptScreenPos; + } CURSORINFO,*PCURSORINFO,*LPCURSORINFO; + +#define CURSOR_SHOWING 0x00000001 + + WINUSERAPI WINBOOL WINAPI GetCursorInfo(PCURSORINFO pci); + + typedef struct tagWINDOWINFO { + DWORD cbSize; + RECT rcWindow; + RECT rcClient; + DWORD dwStyle; + DWORD dwExStyle; + DWORD dwWindowStatus; + UINT cxWindowBorders; + UINT cyWindowBorders; + ATOM atomWindowType; + WORD wCreatorVersion; + } WINDOWINFO,*PWINDOWINFO,*LPWINDOWINFO; + +#define WS_ACTIVECAPTION 0x0001 + + WINUSERAPI WINBOOL WINAPI GetWindowInfo(HWND hwnd,PWINDOWINFO pwi); + + typedef struct tagTITLEBARINFO { + DWORD cbSize; + RECT rcTitleBar; + DWORD rgstate[CCHILDREN_TITLEBAR + 1]; + } TITLEBARINFO,*PTITLEBARINFO,*LPTITLEBARINFO; + + WINUSERAPI WINBOOL WINAPI GetTitleBarInfo(HWND hwnd,PTITLEBARINFO pti); + + typedef struct tagMENUBARINFO { + DWORD cbSize; + RECT rcBar; + HMENU hMenu; + HWND hwndMenu; + WINBOOL fBarFocused:1; + WINBOOL fFocused:1; + } MENUBARINFO,*PMENUBARINFO,*LPMENUBARINFO; + + WINUSERAPI WINBOOL WINAPI GetMenuBarInfo(HWND hwnd,LONG idObject,LONG idItem,PMENUBARINFO pmbi); + + typedef struct tagSCROLLBARINFO { + DWORD cbSize; + RECT rcScrollBar; + int dxyLineButton; + int xyThumbTop; + int xyThumbBottom; + int reserved; + DWORD rgstate[CCHILDREN_SCROLLBAR + 1]; + } SCROLLBARINFO,*PSCROLLBARINFO,*LPSCROLLBARINFO; + + WINUSERAPI WINBOOL WINAPI GetScrollBarInfo(HWND hwnd,LONG idObject,PSCROLLBARINFO psbi); + + typedef struct tagCOMBOBOXINFO { + DWORD cbSize; + RECT rcItem; + RECT rcButton; + DWORD stateButton; + HWND hwndCombo; + HWND hwndItem; + HWND hwndList; + } COMBOBOXINFO,*PCOMBOBOXINFO,*LPCOMBOBOXINFO; + + WINUSERAPI WINBOOL WINAPI GetComboBoxInfo(HWND hwndCombo,PCOMBOBOXINFO pcbi); + +#define GA_PARENT 1 +#define GA_ROOT 2 +#define GA_ROOTOWNER 3 + + WINUSERAPI HWND WINAPI GetAncestor(HWND hwnd,UINT gaFlags); + WINUSERAPI HWND WINAPI RealChildWindowFromPoint(HWND hwndParent,POINT ptParentClientCoords); + WINUSERAPI UINT WINAPI RealGetWindowClassA(HWND hwnd,LPSTR ptszClassName,UINT cchClassNameMax); + WINUSERAPI UINT WINAPI RealGetWindowClassW(HWND hwnd,LPWSTR ptszClassName,UINT cchClassNameMax); +#ifdef UNICODE +#define RealGetWindowClass RealGetWindowClassW +#else +#define RealGetWindowClass RealGetWindowClassA +#endif + + typedef struct tagALTTABINFO { + DWORD cbSize; + int cItems; + int cColumns; + int cRows; + int iColFocus; + int iRowFocus; + int cxItem; + int cyItem; + POINT ptStart; + } ALTTABINFO,*PALTTABINFO,*LPALTTABINFO; + +#ifdef UNICODE +#define GetAltTabInfo GetAltTabInfoW +#else +#define GetAltTabInfo GetAltTabInfoA +#endif + + WINUSERAPI WINBOOL WINAPI GetAltTabInfoA(HWND hwnd,int iItem,PALTTABINFO pati,LPSTR pszItemText,UINT cchItemText); + WINUSERAPI WINBOOL WINAPI GetAltTabInfoW(HWND hwnd,int iItem,PALTTABINFO pati,LPWSTR pszItemText,UINT cchItemText); + WINUSERAPI DWORD WINAPI GetListBoxInfo(HWND hwnd); +#endif + + WINUSERAPI WINBOOL WINAPI LockWorkStation(VOID); + WINUSERAPI WINBOOL WINAPI UserHandleGrantAccess(HANDLE hUserHandle,HANDLE hJob,WINBOOL bGrant); + + DECLARE_HANDLE(HRAWINPUT); + +#define GET_RAWINPUT_CODE_WPARAM(wParam) ((wParam) & 0xff) + +#define RIM_INPUT 0 +#define RIM_INPUTSINK 1 + + typedef struct tagRAWINPUTHEADER { + DWORD dwType; + DWORD dwSize; + HANDLE hDevice; + WPARAM wParam; + } RAWINPUTHEADER,*PRAWINPUTHEADER,*LPRAWINPUTHEADER; + +#define RIM_TYPEMOUSE 0 +#define RIM_TYPEKEYBOARD 1 +#define RIM_TYPEHID 2 + + typedef struct tagRAWMOUSE { + USHORT usFlags; + union { + ULONG ulButtons; + struct { + USHORT usButtonFlags; + USHORT usButtonData; + }; + }; + ULONG ulRawButtons; + LONG lLastX; + LONG lLastY; + ULONG ulExtraInformation; + } RAWMOUSE,*PRAWMOUSE,*LPRAWMOUSE; + +#define RI_MOUSE_LEFT_BUTTON_DOWN 0x0001 +#define RI_MOUSE_LEFT_BUTTON_UP 0x0002 +#define RI_MOUSE_RIGHT_BUTTON_DOWN 0x0004 +#define RI_MOUSE_RIGHT_BUTTON_UP 0x0008 +#define RI_MOUSE_MIDDLE_BUTTON_DOWN 0x0010 +#define RI_MOUSE_MIDDLE_BUTTON_UP 0x0020 + +#define RI_MOUSE_BUTTON_1_DOWN RI_MOUSE_LEFT_BUTTON_DOWN +#define RI_MOUSE_BUTTON_1_UP RI_MOUSE_LEFT_BUTTON_UP +#define RI_MOUSE_BUTTON_2_DOWN RI_MOUSE_RIGHT_BUTTON_DOWN +#define RI_MOUSE_BUTTON_2_UP RI_MOUSE_RIGHT_BUTTON_UP +#define RI_MOUSE_BUTTON_3_DOWN RI_MOUSE_MIDDLE_BUTTON_DOWN +#define RI_MOUSE_BUTTON_3_UP RI_MOUSE_MIDDLE_BUTTON_UP + +#define RI_MOUSE_BUTTON_4_DOWN 0x0040 +#define RI_MOUSE_BUTTON_4_UP 0x0080 +#define RI_MOUSE_BUTTON_5_DOWN 0x0100 +#define RI_MOUSE_BUTTON_5_UP 0x0200 + +#define RI_MOUSE_WHEEL 0x0400 + +#define MOUSE_MOVE_RELATIVE 0 +#define MOUSE_MOVE_ABSOLUTE 1 +#define MOUSE_VIRTUAL_DESKTOP 0x02 +#define MOUSE_ATTRIBUTES_CHANGED 0x04 + + typedef struct tagRAWKEYBOARD { + USHORT MakeCode; + USHORT Flags; + USHORT Reserved; + USHORT VKey; + UINT Message; + ULONG ExtraInformation; + } RAWKEYBOARD,*PRAWKEYBOARD,*LPRAWKEYBOARD; + +#define KEYBOARD_OVERRUN_MAKE_CODE 0xFF + +#define RI_KEY_MAKE 0 +#define RI_KEY_BREAK 1 +#define RI_KEY_E0 2 +#define RI_KEY_E1 4 +#define RI_KEY_TERMSRV_SET_LED 8 +#define RI_KEY_TERMSRV_SHADOW 0x10 + + typedef struct tagRAWHID { + DWORD dwSizeHid; + DWORD dwCount; + BYTE bRawData[1]; + } RAWHID,*PRAWHID,*LPRAWHID; + + typedef struct tagRAWINPUT { + RAWINPUTHEADER header; + union { + RAWMOUSE mouse; + RAWKEYBOARD keyboard; + RAWHID hid; + } data; + } RAWINPUT,*PRAWINPUT,*LPRAWINPUT; + +#ifdef _WIN64 +#define RAWINPUT_ALIGN(x) (((x) + sizeof(QWORD) - 1) & ~(sizeof(QWORD) - 1)) +#else +#define RAWINPUT_ALIGN(x) (((x) + sizeof(DWORD) - 1) & ~(sizeof(DWORD) - 1)) +#endif + +#define NEXTRAWINPUTBLOCK(ptr) ((PRAWINPUT)RAWINPUT_ALIGN((ULONG_PTR)((PBYTE)(ptr) + (ptr)->header.dwSize))) + +#define RID_INPUT 0x10000003 +#define RID_HEADER 0x10000005 + + WINUSERAPI UINT WINAPI GetRawInputData(HRAWINPUT hRawInput,UINT uiCommand,LPVOID pData,PUINT pcbSize,UINT cbSizeHeader); + +#define RIDI_PREPARSEDDATA 0x20000005 +#define RIDI_DEVICENAME 0x20000007 +#define RIDI_DEVICEINFO 0x2000000b + + typedef struct tagRID_DEVICE_INFO_MOUSE { + DWORD dwId; + DWORD dwNumberOfButtons; + DWORD dwSampleRate; + } RID_DEVICE_INFO_MOUSE,*PRID_DEVICE_INFO_MOUSE; + + typedef struct tagRID_DEVICE_INFO_KEYBOARD { + DWORD dwType; + DWORD dwSubType; + DWORD dwKeyboardMode; + DWORD dwNumberOfFunctionKeys; + DWORD dwNumberOfIndicators; + DWORD dwNumberOfKeysTotal; + } RID_DEVICE_INFO_KEYBOARD,*PRID_DEVICE_INFO_KEYBOARD; + + typedef struct tagRID_DEVICE_INFO_HID { + DWORD dwVendorId; + DWORD dwProductId; + DWORD dwVersionNumber; + USHORT usUsagePage; + USHORT usUsage; + } RID_DEVICE_INFO_HID,*PRID_DEVICE_INFO_HID; + + typedef struct tagRID_DEVICE_INFO { + DWORD cbSize; + DWORD dwType; + union { + RID_DEVICE_INFO_MOUSE mouse; + RID_DEVICE_INFO_KEYBOARD keyboard; + RID_DEVICE_INFO_HID hid; + }; + } RID_DEVICE_INFO,*PRID_DEVICE_INFO,*LPRID_DEVICE_INFO; + +#ifdef UNICODE +#define GetRawInputDeviceInfo GetRawInputDeviceInfoW +#else +#define GetRawInputDeviceInfo GetRawInputDeviceInfoA +#endif + + WINUSERAPI UINT WINAPI GetRawInputDeviceInfoA(HANDLE hDevice,UINT uiCommand,LPVOID pData,PUINT pcbSize); + WINUSERAPI UINT WINAPI GetRawInputDeviceInfoW(HANDLE hDevice,UINT uiCommand,LPVOID pData,PUINT pcbSize); + WINUSERAPI UINT WINAPI GetRawInputBuffer(PRAWINPUT pData,PUINT pcbSize,UINT cbSizeHeader); + + typedef struct tagRAWINPUTDEVICE { + USHORT usUsagePage; + USHORT usUsage; + DWORD dwFlags; + HWND hwndTarget; + } RAWINPUTDEVICE,*PRAWINPUTDEVICE,*LPRAWINPUTDEVICE; + + typedef CONST RAWINPUTDEVICE *PCRAWINPUTDEVICE; + +#define RIDEV_REMOVE 0x00000001 +#define RIDEV_EXCLUDE 0x00000010 +#define RIDEV_PAGEONLY 0x00000020 +#define RIDEV_NOLEGACY 0x00000030 +#define RIDEV_INPUTSINK 0x00000100 +#define RIDEV_CAPTUREMOUSE 0x00000200 +#define RIDEV_NOHOTKEYS 0x00000200 +#define RIDEV_APPKEYS 0x00000400 +#define RIDEV_EXMODEMASK 0x000000F0 +#define RIDEV_EXMODE(mode) ((mode) & RIDEV_EXMODEMASK) + + WINUSERAPI WINBOOL WINAPI RegisterRawInputDevices(PCRAWINPUTDEVICE pRawInputDevices,UINT uiNumDevices,UINT cbSize); + WINUSERAPI UINT WINAPI GetRegisteredRawInputDevices(PRAWINPUTDEVICE pRawInputDevices,PUINT puiNumDevices,UINT cbSize); + + typedef struct tagRAWINPUTDEVICELIST { + HANDLE hDevice; + DWORD dwType; + } RAWINPUTDEVICELIST,*PRAWINPUTDEVICELIST; + + WINUSERAPI UINT WINAPI GetRawInputDeviceList(PRAWINPUTDEVICELIST pRawInputDeviceList,PUINT puiNumDevices,UINT cbSize); + WINUSERAPI LRESULT WINAPI DefRawInputProc(PRAWINPUT *paRawInput,INT nInput,UINT cbSizeHeader); + +#endif /* NOUSER */ + +#ifdef __cplusplus +} +#endif +#endif diff --git a/tinyc/win32/include/winapi/winver.h b/tinyc/win32/include/winapi/winver.h new file mode 100644 index 000000000..5c0f036bc --- /dev/null +++ b/tinyc/win32/include/winapi/winver.h @@ -0,0 +1,160 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef VER_H +#define VER_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define VS_FILE_INFO RT_VERSION +#define VS_VERSION_INFO 1 +#define VS_USER_DEFINED 100 + +#define VS_FFI_SIGNATURE 0xFEEF04BDL +#define VS_FFI_STRUCVERSION 0x00010000L +#define VS_FFI_FILEFLAGSMASK 0x0000003FL + +#define VS_FF_DEBUG 0x00000001L +#define VS_FF_PRERELEASE 0x00000002L +#define VS_FF_PATCHED 0x00000004L +#define VS_FF_PRIVATEBUILD 0x00000008L +#define VS_FF_INFOINFERRED 0x00000010L +#define VS_FF_SPECIALBUILD 0x00000020L + +#define VOS_UNKNOWN 0x00000000L +#define VOS_DOS 0x00010000L +#define VOS_OS216 0x00020000L +#define VOS_OS232 0x00030000L +#define VOS_NT 0x00040000L +#define VOS_WINCE 0x00050000L + +#define VOS__BASE 0x00000000L +#define VOS__WINDOWS16 0x00000001L +#define VOS__PM16 0x00000002L +#define VOS__PM32 0x00000003L +#define VOS__WINDOWS32 0x00000004L + +#define VOS_DOS_WINDOWS16 0x00010001L +#define VOS_DOS_WINDOWS32 0x00010004L +#define VOS_OS216_PM16 0x00020002L +#define VOS_OS232_PM32 0x00030003L +#define VOS_NT_WINDOWS32 0x00040004L + +#define VFT_UNKNOWN 0x00000000L +#define VFT_APP 0x00000001L +#define VFT_DLL 0x00000002L +#define VFT_DRV 0x00000003L +#define VFT_FONT 0x00000004L +#define VFT_VXD 0x00000005L +#define VFT_STATIC_LIB 0x00000007L + +#define VFT2_UNKNOWN 0x00000000L +#define VFT2_DRV_PRINTER 0x00000001L +#define VFT2_DRV_KEYBOARD 0x00000002L +#define VFT2_DRV_LANGUAGE 0x00000003L +#define VFT2_DRV_DISPLAY 0x00000004L +#define VFT2_DRV_MOUSE 0x00000005L +#define VFT2_DRV_NETWORK 0x00000006L +#define VFT2_DRV_SYSTEM 0x00000007L +#define VFT2_DRV_INSTALLABLE 0x00000008L +#define VFT2_DRV_SOUND 0x00000009L +#define VFT2_DRV_COMM 0x0000000AL +#define VFT2_DRV_INPUTMETHOD 0x0000000BL +#define VFT2_DRV_VERSIONED_PRINTER 0x0000000CL + +#define VFT2_FONT_RASTER 0x00000001L +#define VFT2_FONT_VECTOR 0x00000002L +#define VFT2_FONT_TRUETYPE 0x00000003L + +#define VFFF_ISSHAREDFILE 0x0001 + +#define VFF_CURNEDEST 0x0001 +#define VFF_FILEINUSE 0x0002 +#define VFF_BUFFTOOSMALL 0x0004 + +#define VIFF_FORCEINSTALL 0x0001 +#define VIFF_DONTDELETEOLD 0x0002 + +#define VIF_TEMPFILE 0x00000001L +#define VIF_MISMATCH 0x00000002L +#define VIF_SRCOLD 0x00000004L + +#define VIF_DIFFLANG 0x00000008L +#define VIF_DIFFCODEPG 0x00000010L +#define VIF_DIFFTYPE 0x00000020L + +#define VIF_WRITEPROT 0x00000040L +#define VIF_FILEINUSE 0x00000080L +#define VIF_OUTOFSPACE 0x00000100L +#define VIF_ACCESSVIOLATION 0x00000200L +#define VIF_SHARINGVIOLATION 0x00000400L +#define VIF_CANNOTCREATE 0x00000800L +#define VIF_CANNOTDELETE 0x00001000L +#define VIF_CANNOTRENAME 0x00002000L +#define VIF_CANNOTDELETECUR 0x00004000L +#define VIF_OUTOFMEMORY 0x00008000L + +#define VIF_CANNOTREADSRC 0x00010000L +#define VIF_CANNOTREADDST 0x00020000L + +#define VIF_BUFFTOOSMALL 0x00040000L +#define VIF_CANNOTLOADLZ32 0x00080000L +#define VIF_CANNOTLOADCABINET 0x00100000L + +#ifndef RC_INVOKED + + typedef struct tagVS_FIXEDFILEINFO + { + DWORD dwSignature; + DWORD dwStrucVersion; + DWORD dwFileVersionMS; + DWORD dwFileVersionLS; + DWORD dwProductVersionMS; + DWORD dwProductVersionLS; + DWORD dwFileFlagsMask; + DWORD dwFileFlags; + DWORD dwFileOS; + DWORD dwFileType; + DWORD dwFileSubtype; + DWORD dwFileDateMS; + DWORD dwFileDateLS; + } VS_FIXEDFILEINFO; + +#ifdef UNICODE +#define VerFindFile VerFindFileW +#define VerInstallFile VerInstallFileW +#define GetFileVersionInfoSize GetFileVersionInfoSizeW +#define GetFileVersionInfo GetFileVersionInfoW +#define VerLanguageName VerLanguageNameW +#define VerQueryValue VerQueryValueW +#else +#define VerFindFile VerFindFileA +#define VerInstallFile VerInstallFileA +#define GetFileVersionInfoSize GetFileVersionInfoSizeA +#define GetFileVersionInfo GetFileVersionInfoA +#define VerLanguageName VerLanguageNameA +#define VerQueryValue VerQueryValueA +#endif + + DWORD WINAPI VerFindFileA(DWORD uFlags,LPSTR szFileName,LPSTR szWinDir,LPSTR szAppDir,LPSTR szCurDir,PUINT lpuCurDirLen,LPSTR szDestDir,PUINT lpuDestDirLen); + DWORD WINAPI VerFindFileW(DWORD uFlags,LPWSTR szFileName,LPWSTR szWinDir,LPWSTR szAppDir,LPWSTR szCurDir,PUINT lpuCurDirLen,LPWSTR szDestDir,PUINT lpuDestDirLen); + DWORD WINAPI VerInstallFileA(DWORD uFlags,LPSTR szSrcFileName,LPSTR szDestFileName,LPSTR szSrcDir,LPSTR szDestDir,LPSTR szCurDir,LPSTR szTmpFile,PUINT lpuTmpFileLen); + DWORD WINAPI VerInstallFileW(DWORD uFlags,LPWSTR szSrcFileName,LPWSTR szDestFileName,LPWSTR szSrcDir,LPWSTR szDestDir,LPWSTR szCurDir,LPWSTR szTmpFile,PUINT lpuTmpFileLen); + DWORD WINAPI GetFileVersionInfoSizeA(LPCSTR lptstrFilename,LPDWORD lpdwHandle); + DWORD WINAPI GetFileVersionInfoSizeW(LPCWSTR lptstrFilename,LPDWORD lpdwHandle); + WINBOOL WINAPI GetFileVersionInfoA(LPCSTR lptstrFilename,DWORD dwHandle,DWORD dwLen,LPVOID lpData); + WINBOOL WINAPI GetFileVersionInfoW(LPCWSTR lptstrFilename,DWORD dwHandle,DWORD dwLen,LPVOID lpData); + DWORD WINAPI VerLanguageNameA(DWORD wLang,LPSTR szLang,DWORD nSize); + DWORD WINAPI VerLanguageNameW(DWORD wLang,LPWSTR szLang,DWORD nSize); + WINBOOL WINAPI VerQueryValueA(const LPVOID pBlock,LPSTR lpSubBlock,LPVOID *lplpBuffer,PUINT puLen); + WINBOOL WINAPI VerQueryValueW(const LPVOID pBlock,LPWSTR lpSubBlock,LPVOID *lplpBuffer,PUINT puLen); +#endif + +#ifdef __cplusplus +} +#endif +#endif diff --git a/tinyc/win32/lib/chkstk.S b/tinyc/win32/lib/chkstk.S new file mode 100644 index 000000000..ec5c07ff8 --- /dev/null +++ b/tinyc/win32/lib/chkstk.S @@ -0,0 +1,191 @@ +/* ---------------------------------------------- */ +/* chkstk86.s */ + +/* ---------------------------------------------- */ +#ifndef __x86_64__ +/* ---------------------------------------------- */ + +.globl __chkstk + +__chkstk: + xchg (%esp),%ebp /* store ebp, get ret.addr */ + push %ebp /* push ret.addr */ + lea 4(%esp),%ebp /* setup frame ptr */ + push %ecx /* save ecx */ + mov %ebp,%ecx +P0: + sub $4096,%ecx + test %eax,(%ecx) + sub $4096,%eax + cmp $4096,%eax + jge P0 + sub %eax,%ecx + test %eax,(%ecx) + + mov %esp,%eax + mov %ecx,%esp + mov (%eax),%ecx /* restore ecx */ + jmp *4(%eax) + +/* ---------------------------------------------- */ +#else +/* ---------------------------------------------- */ + +.globl __chkstk + +__chkstk: + xchg (%rsp),%rbp /* store ebp, get ret.addr */ + push %rbp /* push ret.addr */ + lea 8(%rsp),%rbp /* setup frame ptr */ + push %rcx /* save ecx */ + mov %rbp,%rcx + movslq %eax,%rax +P0: + sub $4096,%rcx + test %rax,(%rcx) + sub $4096,%rax + cmp $4096,%rax + jge P0 + sub %rax,%rcx + test %rax,(%rcx) + + mov %rsp,%rax + mov %rcx,%rsp + mov (%rax),%rcx /* restore ecx */ + jmp *8(%rax) + +/* ---------------------------------------------- */ +/* setjmp/longjmp support */ + +.globl tinyc_getbp +tinyc_getbp: + mov %rbp,%rax + ret + +/* ---------------------------------------------- */ +#endif +/* ---------------------------------------------- */ + + +/* ---------------------------------------------- */ +#ifndef __x86_64__ +/* ---------------------------------------------- */ + +/* + int _except_handler3( + PEXCEPTION_RECORD exception_record, + PEXCEPTION_REGISTRATION registration, + PCONTEXT context, + PEXCEPTION_REGISTRATION dispatcher + ); + + int __cdecl _XcptFilter( + unsigned long xcptnum, + PEXCEPTION_POINTERS pxcptinfoptrs + ); + + struct _sehrec { + void *esp; // 0 + void *exception_pointers; // 1 + void *prev; // 2 + void *handler; // 3 + void *scopetable; // 4 + int trylevel; // 5 + void *ebp // 6 + }; + + // this is what the assembler code below means: + __try + { + // ... + } + __except (_XcptFilter(GetExceptionCode(), GetExceptionInformation())) + { + exit(GetExceptionCode()); + } +*/ + +.globl _exception_info +_exception_info: + mov 1*4-24(%ebp),%eax + ret + +.globl _exception_code +_exception_code: + call _exception_info + mov (%eax),%eax + mov (%eax),%eax + ret + +seh_filter: + call _exception_info + push %eax + call _exception_code + push %eax + call _XcptFilter + add $ 8,%esp + ret + +seh_except: + mov 0*4-24(%ebp),%esp + call _exception_code + push %eax + call _exit + +// msvcrt wants scopetables aligned and in read-only segment (using .text) +.align 4 +seh_scopetable: + .long -1 + .long seh_filter + .long seh_except + +seh_handler: + jmp _except_handler3 + +.globl ___try__ +___try__: +.globl __try__ +__try__: + push %ebp + mov 8(%esp),%ebp + +// void *esp; + lea 12(%esp),%eax + mov %eax,0*4(%ebp) + +// void *exception_pointers; + xor %eax,%eax + mov %eax,1*4(%ebp) + +// void *prev; + mov %fs:0,%eax + mov %eax,2*4(%ebp) + +// void *handler; + mov $ seh_handler,%eax + mov %eax,3*4(%ebp) + +// void *scopetable; + mov $ seh_scopetable,%eax + mov %eax,4*4(%ebp) + +// int trylevel; + xor %eax,%eax + mov %eax,5*4(%ebp) + +// register new SEH + lea 2*4(%ebp),%eax + mov %eax,%fs:0 + + pop %ebp + ret + +/* ---------------------------------------------- */ +#else +/* ---------------------------------------------- */ + +/* SEH on x86-64 not implemented */ + +/* ---------------------------------------------- */ +#endif +/* ---------------------------------------------- */ diff --git a/tinyc/win32/lib/crt1.c b/tinyc/win32/lib/crt1.c new file mode 100644 index 000000000..0e04fc012 --- /dev/null +++ b/tinyc/win32/lib/crt1.c @@ -0,0 +1,79 @@ +// ============================================= +// crt1.c + +// _UNICODE for tchar.h, UNICODE for API +#include + +#include +#include + +#define _UNKNOWN_APP 0 +#define _CONSOLE_APP 1 +#define _GUI_APP 2 + +#define _MCW_PC 0x00030000 // Precision Control +#define _PC_24 0x00020000 // 24 bits +#define _PC_53 0x00010000 // 53 bits +#define _PC_64 0x00000000 // 64 bits + +#ifdef _UNICODE +#define __tgetmainargs __wgetmainargs +#define _tstart _wstart +#define _tmain wmain +#define _runtmain _runwmain +#else +#define __tgetmainargs __getmainargs +#define _tstart _start +#define _tmain main +#define _runtmain _runmain +#endif + +typedef struct { int newmode; } _startupinfo; +int __cdecl __tgetmainargs(int *pargc, _TCHAR ***pargv, _TCHAR ***penv, int globb, _startupinfo*); +void __cdecl __set_app_type(int apptype); +unsigned int __cdecl _controlfp(unsigned int new_value, unsigned int mask); +extern int _tmain(int argc, _TCHAR * argv[], _TCHAR * env[]); + +/* Allow command-line globbing with "int _dowildcard = 1;" in the user source */ +int _dowildcard; + +void _tstart(void) +{ + __TRY__ + _startupinfo start_info = {0}; + + // Sets the current application type + __set_app_type(_CONSOLE_APP); + + // Set default FP precision to 53 bits (8-byte double) + // _MCW_PC (Precision control) is not supported on ARM +#if defined __i386__ || defined __x86_64__ + _controlfp(_PC_53, _MCW_PC); +#endif + + __tgetmainargs( &__argc, &__targv, &_tenviron, _dowildcard, &start_info); + exit(_tmain(__argc, __targv, _tenviron)); +} + +int _runtmain(int argc, /* as tcc passed in */ char **argv) +{ +#ifdef UNICODE + _startupinfo start_info = {0}; + + __tgetmainargs(&__argc, &__targv, &_tenviron, _dowildcard, &start_info); + /* may be wrong when tcc has received wildcards (*.c) */ + if (argc < __argc) { + __targv += __argc - argc; + __argc = argc; + } +#else + __argc = argc; + __targv = argv; +#endif +#if defined __i386__ || defined __x86_64__ + _controlfp(_PC_53, _MCW_PC); +#endif + return _tmain(__argc, __targv, _tenviron); +} + +// ============================================= diff --git a/tinyc/win32/lib/crt1w.c b/tinyc/win32/lib/crt1w.c new file mode 100644 index 000000000..2b8bbc8bc --- /dev/null +++ b/tinyc/win32/lib/crt1w.c @@ -0,0 +1,3 @@ +#define _UNICODE 1 +#define UNICODE 1 +#include "crt1.c" diff --git a/tinyc/win32/lib/dllcrt1.c b/tinyc/win32/lib/dllcrt1.c new file mode 100644 index 000000000..ba1dbd048 --- /dev/null +++ b/tinyc/win32/lib/dllcrt1.c @@ -0,0 +1,13 @@ +//+--------------------------------------------------------------------------- + +#include + +BOOL WINAPI DllMain (HINSTANCE hDll, DWORD dwReason, LPVOID lpReserved); + +BOOL WINAPI _dllstart(HINSTANCE hDll, DWORD dwReason, LPVOID lpReserved) +{ + BOOL bRet; + bRet = DllMain (hDll, dwReason, lpReserved); + return bRet; +} + diff --git a/tinyc/win32/lib/dllmain.c b/tinyc/win32/lib/dllmain.c new file mode 100644 index 000000000..2c25b98b8 --- /dev/null +++ b/tinyc/win32/lib/dllmain.c @@ -0,0 +1,9 @@ +//+--------------------------------------------------------------------------- + +#include + +BOOL WINAPI DllMain (HINSTANCE hDll, DWORD dwReason, LPVOID lpReserved) +{ + return TRUE; +} + diff --git a/tinyc/win32/lib/gdi32.def b/tinyc/win32/lib/gdi32.def new file mode 100644 index 000000000..02766da43 --- /dev/null +++ b/tinyc/win32/lib/gdi32.def @@ -0,0 +1,337 @@ +LIBRARY gdi32.dll + +EXPORTS +AbortDoc +AbortPath +AddFontResourceA +AddFontResourceW +AngleArc +AnimatePalette +Arc +ArcTo +BeginPath +BitBlt +ByeByeGDI +CancelDC +CheckColorsInGamut +ChoosePixelFormat +Chord +CloseEnhMetaFile +CloseFigure +CloseMetaFile +ColorCorrectPalette +ColorMatchToTarget +CombineRgn +CombineTransform +CopyEnhMetaFileA +CopyEnhMetaFileW +CopyMetaFileA +CopyMetaFileW +CreateBitmap +CreateBitmapIndirect +CreateBrushIndirect +CreateColorSpaceA +CreateColorSpaceW +CreateCompatibleBitmap +CreateCompatibleDC +CreateDCA +CreateDCW +CreateDIBPatternBrush +CreateDIBPatternBrushPt +CreateDIBSection +CreateDIBitmap +CreateDiscardableBitmap +CreateEllipticRgn +CreateEllipticRgnIndirect +CreateEnhMetaFileA +CreateEnhMetaFileW +CreateFontA +CreateFontIndirectA +CreateFontIndirectW +CreateFontW +CreateHalftonePalette +CreateHatchBrush +CreateICA +CreateICW +CreateMetaFileA +CreateMetaFileW +CreatePalette +CreatePatternBrush +CreatePen +CreatePenIndirect +CreatePolyPolygonRgn +CreatePolygonRgn +CreateRectRgn +CreateRectRgnIndirect +CreateRoundRectRgn +CreateScalableFontResourceA +CreateScalableFontResourceW +CreateSolidBrush +DPtoLP +DeleteColorSpace +DeleteDC +DeleteEnhMetaFile +DeleteMetaFile +DeleteObject +DescribePixelFormat +DeviceCapabilitiesEx +DeviceCapabilitiesExA +DeviceCapabilitiesExW +DrawEscape +Ellipse +EnableEUDC +EndDoc +EndPage +EndPath +EnumEnhMetaFile +EnumFontFamiliesA +EnumFontFamiliesExA +EnumFontFamiliesExW +EnumFontFamiliesW +EnumFontsA +EnumFontsW +EnumICMProfilesA +EnumICMProfilesW +EnumMetaFile +EnumObjects +EqualRgn +Escape +ExcludeClipRect +ExtCreatePen +ExtCreateRegion +ExtEscape +ExtFloodFill +ExtSelectClipRgn +ExtTextOutA +ExtTextOutW +FillPath +FillRgn +FixBrushOrgEx +FlattenPath +FloodFill +FrameRgn +GdiComment +GdiFlush +GdiGetBatchLimit +GdiPlayDCScript +GdiPlayJournal +GdiPlayScript +GdiSetBatchLimit +GetArcDirection +GetAspectRatioFilterEx +GetBitmapBits +GetBitmapDimensionEx +GetBkColor +GetBkMode +GetBoundsRect +GetBrushOrgEx +GetCharABCWidthsA +GetCharABCWidthsFloatA +GetCharABCWidthsFloatW +GetCharABCWidthsW +GetCharWidth32A +GetCharWidth32W +GetCharWidthA +GetCharWidthFloatA +GetCharWidthFloatW +GetCharWidthW +GetCharacterPlacementA +GetCharacterPlacementW +GetClipBox +GetClipRgn +GetColorAdjustment +GetColorSpace +GetCurrentObject +GetCurrentPositionEx +GetDCOrgEx +GetDIBColorTable +GetDIBits +GetDeviceCaps +GetDeviceGammaRamp +GetEnhMetaFileA +GetEnhMetaFileBits +GetEnhMetaFileDescriptionA +GetEnhMetaFileDescriptionW +GetEnhMetaFileHeader +GetEnhMetaFilePaletteEntries +GetEnhMetaFileW +GetFontData +GetFontLanguageInfo +GetFontResourceInfo +GetGlyphOutline +GetGlyphOutlineA +GetGlyphOutlineW +GetGraphicsMode +GetICMProfileA +GetICMProfileW +GetKerningPairs +GetKerningPairsA +GetKerningPairsW +GetLayout +GetLogColorSpaceA +GetLogColorSpaceW +GetMapMode +GetMetaFileA +GetMetaFileBitsEx +GetMetaFileW +GetMetaRgn +GetMiterLimit +GetNearestColor +GetNearestPaletteIndex +GetObjectA +GetObjectType +GetObjectW +GetOutlineTextMetricsA +GetOutlineTextMetricsW +GetPaletteEntries +GetPath +GetPixel +GetPixelFormat +GetPolyFillMode +GetROP2 +GetRandomRgn +GetRasterizerCaps +GetRegionData +GetRgnBox +GetStockObject +GetStretchBltMode +GetSystemPaletteEntries +GetSystemPaletteUse +GetTextAlign +GetTextCharacterExtra +GetTextCharset +GetTextCharsetInfo +GetTextColor +GetTextExtentExPointA +GetTextExtentExPointW +GetTextExtentPoint32A +GetTextExtentPoint32W +GetTextExtentPointA +GetTextExtentPointW +GetTextFaceA +GetTextFaceW +GetTextMetricsA +GetTextMetricsW +GetViewportExtEx +GetViewportOrgEx +GetWinMetaFileBits +GetWindowExtEx +GetWindowOrgEx +GetWorldTransform +IntersectClipRect +InvertRgn +LPtoDP +LineDDA +LineTo +MaskBlt +ModifyWorldTransform +MoveToEx +OffsetClipRgn +OffsetRgn +OffsetViewportOrgEx +OffsetWindowOrgEx +PaintRgn +PatBlt +PathToRegion +Pie +PlayEnhMetaFile +PlayEnhMetaFileRecord +PlayMetaFile +PlayMetaFileRecord +PlgBlt +PolyBezier +PolyBezierTo +PolyDraw +PolyPolygon +PolyPolyline +PolyTextOutA +PolyTextOutW +Polygon +Polyline +PolylineTo +PtInRegion +PtVisible +RealizePalette +RectInRegion +RectVisible +Rectangle +RemoveFontResourceA +RemoveFontResourceW +ResetDCA +ResetDCW +ResizePalette +RestoreDC +RoundRect +SaveDC +ScaleViewportExtEx +ScaleWindowExtEx +SelectClipPath +SelectClipRgn +SelectObject +SelectPalette +SetAbortProc +SetArcDirection +SetBitmapBits +SetBitmapDimensionEx +SetBkColor +SetBkMode +SetBoundsRect +SetBrushOrgEx +SetColorAdjustment +SetColorSpace +SetDIBColorTable +SetDIBits +SetDIBitsToDevice +SetDeviceGammaRamp +SetEnhMetaFileBits +SetFontEnumeration +SetGraphicsMode +SetICMMode +SetICMProfileA +SetICMProfileW +SetLayout +SetMagicColors +SetMapMode +SetMapperFlags +SetMetaFileBitsEx +SetMetaRgn +SetMiterLimit +SetObjectOwner +SetPaletteEntries +SetPixel +SetPixelFormat +SetPixelV +SetPolyFillMode +SetROP2 +SetRectRgn +SetStretchBltMode +SetSystemPaletteUse +SetTextAlign +SetTextCharacterExtra +SetTextColor +SetTextJustification +SetViewportExtEx +SetViewportOrgEx +SetWinMetaFileBits +SetWindowExtEx +SetWindowOrgEx +SetWorldTransform +StartDocA +StartDocW +StartPage +StretchBlt +StretchDIBits +StrokeAndFillPath +StrokePath +SwapBuffers +TextOutA +TextOutW +TranslateCharsetInfo +UnrealizeObject +UpdateColors +UpdateICMRegKeyA +UpdateICMRegKeyW +WidenPath +gdiPlaySpoolStream +pfnRealizePalette +pfnSelectPalette diff --git a/tinyc/win32/lib/kernel32.def b/tinyc/win32/lib/kernel32.def new file mode 100644 index 000000000..f03e17ba4 --- /dev/null +++ b/tinyc/win32/lib/kernel32.def @@ -0,0 +1,770 @@ +LIBRARY kernel32.dll + +EXPORTS +AddAtomA +AddAtomW +AllocConsole +AllocLSCallback +AllocSLCallback +AreFileApisANSI +BackupRead +BackupSeek +BackupWrite +Beep +BeginUpdateResourceA +BeginUpdateResourceW +BuildCommDCBA +BuildCommDCBAndTimeoutsA +BuildCommDCBAndTimeoutsW +BuildCommDCBW +CallNamedPipeA +CallNamedPipeW +Callback12 +Callback16 +Callback20 +Callback24 +Callback28 +Callback32 +Callback36 +Callback4 +Callback40 +Callback44 +Callback48 +Callback52 +Callback56 +Callback60 +Callback64 +Callback8 +CancelDeviceWakeupRequest +CancelIo +CancelWaitableTimer +ClearCommBreak +ClearCommError +CloseHandle +CloseProfileUserMapping +CloseSystemHandle +CommConfigDialogA +CommConfigDialogW +CompareFileTime +CompareStringA +CompareStringW +ConnectNamedPipe +ContinueDebugEvent +ConvertDefaultLocale +ConvertThreadToFiber +ConvertToGlobalHandle +CopyFileA +CopyFileExA +CopyFileExW +CopyFileW +CreateConsoleScreenBuffer +CreateDirectoryA +CreateDirectoryExA +CreateDirectoryExW +CreateDirectoryW +CreateEventA +CreateEventW +CreateFiber +CreateFileA +CreateFileMappingA +CreateFileMappingW +CreateFileW +CreateIoCompletionPort +CreateKernelThread +CreateMailslotA +CreateMailslotW +CreateMutexA +CreateMutexW +CreateNamedPipeA +CreateNamedPipeW +CreatePipe +CreateProcessA +CreateProcessW +CreateRemoteThread +CreateSemaphoreA +CreateSemaphoreW +CreateSocketHandle +CreateTapePartition +CreateThread +CreateToolhelp32Snapshot +CreateWaitableTimerA +CreateWaitableTimerW +DebugActiveProcess +DebugBreak +DefineDosDeviceA +DefineDosDeviceW +DeleteAtom +DeleteCriticalSection +DeleteFiber +DeleteFileA +DeleteFileW +DeviceIoControl +DisableThreadLibraryCalls +DisconnectNamedPipe +DosDateTimeToFileTime +DuplicateHandle +EndUpdateResourceA +EndUpdateResourceW +EnterCriticalSection +EnumCalendarInfoA +EnumCalendarInfoExA +EnumCalendarInfoExW +EnumCalendarInfoW +EnumDateFormatsA +EnumDateFormatsExA +EnumDateFormatsExW +EnumDateFormatsW +EnumLanguageGroupLocalesA +EnumLanguageGroupLocalesW +EnumResourceLanguagesA +EnumResourceLanguagesW +EnumResourceNamesA +EnumResourceNamesW +EnumResourceTypesA +EnumResourceTypesW +EnumSystemCodePagesA +EnumSystemCodePagesW +EnumSystemGeoID +EnumSystemLanguageGroupsA +EnumSystemLanguageGroupsW +EnumSystemLocalesA +EnumSystemLocalesW +EnumTimeFormatsA +EnumTimeFormatsW +EnumUILanguagesA +EnumUILanguagesW +EraseTape +EscapeCommFunction +ExitProcess +ExitThread +ExpandEnvironmentStringsA +ExpandEnvironmentStringsW +FT_Exit0 +FT_Exit12 +FT_Exit16 +FT_Exit20 +FT_Exit24 +FT_Exit28 +FT_Exit32 +FT_Exit36 +FT_Exit4 +FT_Exit40 +FT_Exit44 +FT_Exit48 +FT_Exit52 +FT_Exit56 +FT_Exit8 +FT_Prolog +FT_Thunk +FatalAppExitA +FatalAppExitW +FatalExit +FileTimeToDosDateTime +FileTimeToLocalFileTime +FileTimeToSystemTime +FillConsoleOutputAttribute +FillConsoleOutputCharacterA +FillConsoleOutputCharacterW +FindAtomA +FindAtomW +FindClose +FindCloseChangeNotification +FindFirstChangeNotificationA +FindFirstChangeNotificationW +FindFirstFileA +FindFirstFileExA +FindFirstFileExW +FindFirstFileW +FindNextChangeNotification +FindNextFileA +FindNextFileW +FindResourceA +FindResourceExA +FindResourceExW +FindResourceW +FlushConsoleInputBuffer +FlushFileBuffers +FlushInstructionCache +FlushViewOfFile +FoldStringA +FoldStringW +FormatMessageA +FormatMessageW +FreeConsole +FreeEnvironmentStringsA +FreeEnvironmentStringsW +FreeLSCallback +FreeLibrary +FreeLibraryAndExitThread +FreeResource +FreeSLCallback +GenerateConsoleCtrlEvent +GetACP +GetAtomNameA +GetAtomNameW +GetBinaryType +GetBinaryTypeA +GetBinaryTypeW +GetCPInfo +GetCPInfoExA +GetCPInfoExW +GetCalendarInfoA +GetCalendarInfoW +GetCommConfig +GetCommMask +GetCommModemStatus +GetCommProperties +GetCommState +GetCommTimeouts +GetCommandLineA +GetCommandLineW +GetCompressedFileSizeA +GetCompressedFileSizeW +GetComputerNameA +GetComputerNameW +GetConsoleCP +GetConsoleCursorInfo +GetConsoleMode +GetConsoleOutputCP +GetConsoleScreenBufferInfo +GetConsoleTitleA +GetConsoleTitleW +GetCurrencyFormatA +GetCurrencyFormatW +GetCurrentDirectoryA +GetCurrentDirectoryW +GetCurrentProcess +GetCurrentProcessId +GetCurrentThread +GetCurrentThreadId +GetDateFormatA +GetDateFormatW +GetDaylightFlag +GetDefaultCommConfigA +GetDefaultCommConfigW +GetDevicePowerState +GetDiskFreeSpaceA +GetDiskFreeSpaceExA +GetDiskFreeSpaceExW +GetDiskFreeSpaceW +GetDriveTypeA +GetDriveTypeW +GetEnvironmentStrings +GetEnvironmentStringsA +GetEnvironmentStringsW +GetEnvironmentVariableA +GetEnvironmentVariableW +GetErrorMode +GetExitCodeProcess +GetExitCodeThread +GetFileAttributesA +GetFileAttributesExA +GetFileAttributesExW +GetFileAttributesW +GetFileInformationByHandle +GetFileSize +GetFileTime +GetFileType +GetFullPathNameA +GetFullPathNameW +GetGeoInfoA +GetGeoInfoW +GetHandleContext +GetHandleInformation +GetLSCallbackTarget +GetLSCallbackTemplate +GetLargestConsoleWindowSize +GetLastError +GetLocalTime +GetLocaleInfoA +GetLocaleInfoW +GetLogicalDriveStringsA +GetLogicalDriveStringsW +GetLogicalDrives +GetLongPathNameA +GetLongPathNameW +GetMailslotInfo +GetModuleFileNameA +GetModuleFileNameW +GetModuleHandleA +GetModuleHandleW +GetModuleHandleExA +GetModuleHandleExW +GetNamedPipeHandleStateA +GetNamedPipeHandleStateW +GetNamedPipeInfo +GetNumberFormatA +GetNumberFormatW +GetNumberOfConsoleInputEvents +GetNumberOfConsoleMouseButtons +GetOEMCP +GetOverlappedResult +GetPriorityClass +GetPrivateProfileIntA +GetPrivateProfileIntW +GetPrivateProfileSectionA +GetPrivateProfileSectionNamesA +GetPrivateProfileSectionNamesW +GetPrivateProfileSectionW +GetPrivateProfileStringA +GetPrivateProfileStringW +GetPrivateProfileStructA +GetPrivateProfileStructW +GetProcAddress +GetProcessAffinityMask +GetProcessFlags +GetProcessHeap +GetProcessHeaps +GetProcessPriorityBoost +GetProcessShutdownParameters +GetProcessTimes +GetProcessVersion +GetProcessWorkingSetSize +GetProductName +GetProfileIntA +GetProfileIntW +GetProfileSectionA +GetProfileSectionW +GetProfileStringA +GetProfileStringW +GetQueuedCompletionStatus +GetSLCallbackTarget +GetSLCallbackTemplate +GetShortPathNameA +GetShortPathNameW +GetStartupInfoA +GetStartupInfoW +GetStdHandle +GetStringTypeA +GetStringTypeExA +GetStringTypeExW +GetStringTypeW +GetSystemDefaultLCID +GetSystemDefaultLangID +GetSystemDefaultUILanguage +GetSystemDirectoryA +GetSystemDirectoryW +GetSystemInfo +GetSystemPowerStatus +GetSystemTime +GetSystemTimeAdjustment +GetSystemTimeAsFileTime +GetTapeParameters +GetTapePosition +GetTapeStatus +GetTempFileNameA +GetTempFileNameW +GetTempPathA +GetTempPathW +GetThreadContext +GetThreadLocale +GetThreadPriority +GetThreadPriorityBoost +GetThreadSelectorEntry +GetThreadTimes +GetTickCount +GetTimeFormatA +GetTimeFormatW +GetTimeZoneInformation +GetUserDefaultLCID +GetUserDefaultLangID +GetUserDefaultUILanguage +GetUserGeoID +GetVersion +GetVersionExA +GetVersionExW +GetVolumeInformationA +GetVolumeInformationW +GetWindowsDirectoryA +GetWindowsDirectoryW +GetWriteWatch +GlobalAddAtomA +GlobalAddAtomW +GlobalAlloc +GlobalCompact +GlobalDeleteAtom +GlobalFindAtomA +GlobalFindAtomW +GlobalFix +GlobalFlags +GlobalFree +GlobalGetAtomNameA +GlobalGetAtomNameW +GlobalHandle +GlobalLock +GlobalMemoryStatus +GlobalReAlloc +GlobalSize +GlobalUnWire +GlobalUnfix +GlobalUnlock +GlobalWire +Heap32First +Heap32ListFirst +Heap32ListNext +Heap32Next +HeapAlloc +HeapCompact +HeapCreate +HeapDestroy +HeapFree +HeapLock +HeapReAlloc +HeapSetFlags +HeapSize +HeapUnlock +HeapValidate +HeapWalk +InitAtomTable +InitializeCriticalSection +InitializeCriticalSectionAndSpinCount +InterlockedCompareExchange +InterlockedDecrement +InterlockedExchange +InterlockedExchangeAdd +InterlockedIncrement +InvalidateNLSCache +IsBadCodePtr +IsBadHugeReadPtr +IsBadHugeWritePtr +IsBadReadPtr +IsBadStringPtrA +IsBadStringPtrW +IsBadWritePtr +IsDBCSLeadByte +IsDBCSLeadByteEx +IsDebuggerPresent +IsLSCallback +IsProcessorFeaturePresent +IsSLCallback +IsSystemResumeAutomatic +IsValidCodePage +IsValidLanguageGroup +IsValidLocale +K32Thk1632Epilog +K32Thk1632Prolog +K32_NtCreateFile +K32_RtlNtStatusToDosError +LCMapStringA +LCMapStringW +LeaveCriticalSection +LoadLibraryA +LoadLibraryExA +LoadLibraryExW +LoadLibraryW +LoadModule +LoadResource +LocalAlloc +LocalCompact +LocalFileTimeToFileTime +LocalFlags +LocalFree +LocalHandle +LocalLock +LocalReAlloc +LocalShrink +LocalSize +LocalUnlock +LockFile +LockFileEx +LockResource +MakeCriticalSectionGlobal +MapHInstLS +MapHInstLS_PN +MapHInstSL +MapHInstSL_PN +MapHModuleLS +MapHModuleSL +MapLS +MapSL +MapSLFix +MapViewOfFile +MapViewOfFileEx +Module32First +Module32Next +MoveFileA +MoveFileExA +MoveFileExW +MoveFileW +MulDiv +MultiByteToWideChar +NotifyNLSUserCache +OpenEventA +OpenEventW +OpenFile +OpenFileMappingA +OpenFileMappingW +OpenMutexA +OpenMutexW +OpenProcess +OpenProfileUserMapping +OpenSemaphoreA +OpenSemaphoreW +OpenThread +OpenVxDHandle +OpenWaitableTimerA +OpenWaitableTimerW +OutputDebugStringA +OutputDebugStringW +PeekConsoleInputA +PeekConsoleInputW +PeekNamedPipe +PostQueuedCompletionStatus +PrepareTape +Process32First +Process32Next +PulseEvent +PurgeComm +QT_Thunk +QueryDosDeviceA +QueryDosDeviceW +QueryNumberOfEventLogRecords +QueryOldestEventLogRecord +QueryPerformanceCounter +QueryPerformanceFrequency +QueueUserAPC +RaiseException +ReadConsoleA +ReadConsoleInputA +ReadConsoleInputW +ReadConsoleOutputA +ReadConsoleOutputAttribute +ReadConsoleOutputCharacterA +ReadConsoleOutputCharacterW +ReadConsoleOutputW +ReadConsoleW +ReadDirectoryChangesW +ReadFile +ReadFileEx +ReadFileScatter +ReadProcessMemory +RegisterServiceProcess +RegisterSysMsgHandler +ReinitializeCriticalSection +ReleaseMutex +ReleaseSemaphore +RemoveDirectoryA +RemoveDirectoryW +RequestDeviceWakeup +RequestWakeupLatency +ResetEvent +ResetNLSUserInfoCache +ResetWriteWatch +ResumeThread +RtlAddFunctionTable +RtlDeleteFunctionTable +RtlFillMemory +RtlInstallFunctionTableCallback +RtlMoveMemory +RtlUnwind +RtlUnwindEx +RtlZeroMemory +SMapLS +SMapLS_IP_EBP_12 +SMapLS_IP_EBP_16 +SMapLS_IP_EBP_20 +SMapLS_IP_EBP_24 +SMapLS_IP_EBP_28 +SMapLS_IP_EBP_32 +SMapLS_IP_EBP_36 +SMapLS_IP_EBP_40 +SMapLS_IP_EBP_8 +SUnMapLS +SUnMapLS_IP_EBP_12 +SUnMapLS_IP_EBP_16 +SUnMapLS_IP_EBP_20 +SUnMapLS_IP_EBP_24 +SUnMapLS_IP_EBP_28 +SUnMapLS_IP_EBP_32 +SUnMapLS_IP_EBP_36 +SUnMapLS_IP_EBP_40 +SUnMapLS_IP_EBP_8 +ScrollConsoleScreenBufferA +ScrollConsoleScreenBufferW +SearchPathA +SearchPathW +SetCalendarInfoA +SetCalendarInfoW +SetCommBreak +SetCommConfig +SetCommMask +SetCommState +SetCommTimeouts +SetComputerNameA +SetComputerNameW +SetConsoleActiveScreenBuffer +SetConsoleCP +SetConsoleCtrlHandler +SetConsoleCursorInfo +SetConsoleCursorPosition +SetConsoleMode +SetConsoleOutputCP +SetConsoleScreenBufferSize +SetConsoleTextAttribute +SetConsoleTitleA +SetConsoleTitleW +SetConsoleWindowInfo +SetCriticalSectionSpinCount +SetCurrentDirectoryA +SetCurrentDirectoryW +SetDaylightFlag +SetDefaultCommConfigA +SetDefaultCommConfigW +SetEndOfFile +SetEnvironmentVariableA +SetEnvironmentVariableW +SetErrorMode +SetEvent +SetFileApisToANSI +SetFileApisToOEM +SetFileAttributesA +SetFileAttributesW +SetFilePointer +SetFilePointerEx +SetFileTime +SetHandleContext +SetHandleCount +SetHandleInformation +SetLastError +SetLocalTime +SetLocaleInfoA +SetLocaleInfoW +SetMailslotInfo +SetMessageWaitingIndicator +SetNamedPipeHandleState +SetPriorityClass +SetProcessAffinityMask +SetProcessPriorityBoost +SetProcessShutdownParameters +SetProcessWorkingSetSize +SetStdHandle +SetSystemPowerState +SetSystemTime +SetSystemTimeAdjustment +SetTapeParameters +SetTapePosition +SetThreadAffinityMask +SetThreadContext +SetThreadExecutionState +SetThreadIdealProcessor +SetThreadLocale +SetThreadPriority +SetThreadPriorityBoost +SetTimeZoneInformation +SetUnhandledExceptionFilter +SetUserGeoID +SetVolumeLabelA +SetVolumeLabelW +SetWaitableTimer +SetupComm +SignalObjectAndWait +SignalSysMsgHandlers +SizeofResource +Sleep +SleepEx +SuspendThread +SwitchToFiber +SwitchToThread +SystemTimeToFileTime +SystemTimeToTzSpecificLocalTime +TerminateProcess +TerminateThread +Thread32First +Thread32Next +ThunkConnect32 +TlsAlloc +TlsAllocInternal +TlsFree +TlsFreeInternal +TlsGetValue +TlsSetValue +Toolhelp32ReadProcessMemory +TransactNamedPipe +TransmitCommChar +TryEnterCriticalSection +UTRegister +UTUnRegister +UnMapLS +UnMapSLFixArray +UnhandledExceptionFilter +UninitializeCriticalSection +UnlockFile +UnlockFileEx +UnmapViewOfFile +UpdateResourceA +UpdateResourceW +VerLanguageNameA +VerLanguageNameW +VirtualAlloc +VirtualAllocEx +VirtualFree +VirtualFreeEx +VirtualLock +VirtualProtect +VirtualProtectEx +VirtualQuery +VirtualQueryEx +VirtualUnlock +WaitCommEvent +WaitForDebugEvent +WaitForMultipleObjects +WaitForMultipleObjectsEx +WaitForSingleObject +WaitForSingleObjectEx +WaitNamedPipeA +WaitNamedPipeW +WideCharToMultiByte +WinExec +WriteConsoleA +WriteConsoleInputA +WriteConsoleInputW +WriteConsoleOutputA +WriteConsoleOutputAttribute +WriteConsoleOutputCharacterA +WriteConsoleOutputCharacterW +WriteConsoleOutputW +WriteConsoleW +WriteFile +WriteFileEx +WriteFileGather +WritePrivateProfileSectionA +WritePrivateProfileSectionW +WritePrivateProfileStringA +WritePrivateProfileStringW +WritePrivateProfileStructA +WritePrivateProfileStructW +WriteProcessMemory +WriteProfileSectionA +WriteProfileSectionW +WriteProfileStringA +WriteProfileStringW +WriteTapemark +_DebugOut +_DebugPrintf +_hread +_hwrite +_lclose +_lcreat +_llseek +_lopen +_lread +_lwrite +dprintf +lstrcat +lstrcatA +lstrcatW +lstrcmp +lstrcmpA +lstrcmpW +lstrcmpi +lstrcmpiA +lstrcmpiW +lstrcpy +lstrcpyA +lstrcpyW +lstrcpyn +lstrcpynA +lstrcpynW +lstrlen +lstrlenA +lstrlenW diff --git a/tinyc/win32/lib/msvcrt.def b/tinyc/win32/lib/msvcrt.def new file mode 100644 index 000000000..742acb8bb --- /dev/null +++ b/tinyc/win32/lib/msvcrt.def @@ -0,0 +1,1399 @@ +LIBRARY msvcrt.dll + +EXPORTS +$I10_OUTPUT +??0__non_rtti_object@@QAE@ABV0@@Z +??0__non_rtti_object@@QAE@PBD@Z +??0bad_cast@@AAE@PBQBD@Z +??0bad_cast@@QAE@ABQBD@Z +??0bad_cast@@QAE@ABV0@@Z +??0bad_cast@@QAE@PBD@Z +??0bad_typeid@@QAE@ABV0@@Z +??0bad_typeid@@QAE@PBD@Z +??0exception@@QAE@ABQBD@Z +??0exception@@QAE@ABQBDH@Z +??0exception@@QAE@ABV0@@Z +??0exception@@QAE@XZ +??1__non_rtti_object@@UAE@XZ +??1bad_cast@@UAE@XZ +??1bad_typeid@@UAE@XZ +??1exception@@UAE@XZ +??1type_info@@UAE@XZ +??2@YAPAXI@Z +??2@YAPAXIHPBDH@Z +??3@YAXPAX@Z +??4__non_rtti_object@@QAEAAV0@ABV0@@Z +??4bad_cast@@QAEAAV0@ABV0@@Z +??4bad_typeid@@QAEAAV0@ABV0@@Z +??4exception@@QAEAAV0@ABV0@@Z +??8type_info@@QBEHABV0@@Z +??9type_info@@QBEHABV0@@Z +??_7__non_rtti_object@@6B@ +??_7bad_cast@@6B@ +??_7bad_typeid@@6B@ +??_7exception@@6B@ +??_E__non_rtti_object@@UAEPAXI@Z +??_Ebad_cast@@UAEPAXI@Z +??_Ebad_typeid@@UAEPAXI@Z +??_Eexception@@UAEPAXI@Z +??_Fbad_cast@@QAEXXZ +??_Fbad_typeid@@QAEXXZ +??_G__non_rtti_object@@UAEPAXI@Z +??_Gbad_cast@@UAEPAXI@Z +??_Gbad_typeid@@UAEPAXI@Z +??_Gexception@@UAEPAXI@Z +??_U@YAPAXI@Z +??_U@YAPAXIHPBDH@Z +??_V@YAXPAX@Z +?_query_new_handler@@YAP6AHI@ZXZ +?_query_new_mode@@YAHXZ +?_set_new_handler@@YAP6AHI@ZP6AHI@Z@Z +?_set_new_mode@@YAHH@Z +?_set_se_translator@@YAP6AXIPAU_EXCEPTION_POINTERS@@@ZP6AXI0@Z@Z +?before@type_info@@QBEHABV1@@Z +?name@type_info@@QBEPBDXZ +?raw_name@type_info@@QBEPBDXZ +?set_new_handler@@YAP6AXXZP6AXXZ@Z +?set_terminate@@YAP6AXXZP6AXXZ@Z +?set_unexpected@@YAP6AXXZP6AXXZ@Z +?terminate@@YAXXZ +?unexpected@@YAXXZ +?what@exception@@UBEPBDXZ +_CIacos +_CIasin +_CIatan +_CIatan2 +_CIcos +_CIcosh +_CIexp +_CIfmod +_CIlog +_CIlog10 +_CIpow +_CIsin +_CIsinh +_CIsqrt +_CItan +_CItanh +_CrtCheckMemory +_CrtDbgBreak +_CrtDbgReport +_CrtDbgReportV +_CrtDbgReportW +_CrtDbgReportWV +_CrtDoForAllClientObjects +_CrtDumpMemoryLeaks +_CrtIsMemoryBlock +_CrtIsValidHeapPointer +_CrtIsValidPointer +_CrtMemCheckpoint +_CrtMemDifference +_CrtMemDumpAllObjectsSince +_CrtMemDumpStatistics +_CrtReportBlockType +_CrtSetAllocHook +_CrtSetBreakAlloc +_CrtSetDbgBlockType +_CrtSetDbgFlag +_CrtSetDumpClient +_CrtSetReportFile +_CrtSetReportHook +_CrtSetReportHook2 +_CrtSetReportMode +_CxxThrowException +_EH_prolog +_Getdays +_Getmonths +_Gettnames +_HUGE +_Strftime +_XcptFilter +__CppXcptFilter +__CxxCallUnwindDelDtor +__CxxCallUnwindDtor +__CxxCallUnwindVecDtor +__CxxDetectRethrow +__CxxExceptionFilter +__CxxFrameHandler +__CxxFrameHandler2 +__CxxFrameHandler3 +__CxxLongjmpUnwind +__CxxQueryExceptionSize +__CxxRegisterExceptionObject +__CxxUnregisterExceptionObject +__DestructExceptionObject +__RTCastToVoid +__RTDynamicCast +__RTtypeid +__STRINGTOLD +___lc_codepage_func +___lc_collate_cp_func +___lc_handle_func +___mb_cur_max_func +___setlc_active_func +___unguarded_readlc_active_add_func +__argc +__argv +__badioinfo +__crtCompareStringA +__crtCompareStringW +__crtGetLocaleInfoW +__crtGetStringTypeW +__crtLCMapStringA +__crtLCMapStringW +__daylight +__dllonexit +__doserrno +__dstbias +__fpecode +__getmainargs +__initenv +__iob_func +__isascii +__iscsym +__iscsymf +__lc_codepage +__lc_collate_cp +__lc_handle +__lconv_init +__libm_sse2_acos +__libm_sse2_acosf +__libm_sse2_asin +__libm_sse2_asinf +__libm_sse2_atan +__libm_sse2_atan2 +__libm_sse2_atanf +__libm_sse2_cos +__libm_sse2_cosf +__libm_sse2_exp +__libm_sse2_expf +__libm_sse2_log +__libm_sse2_log10 +__libm_sse2_log10f +__libm_sse2_logf +__libm_sse2_pow +__libm_sse2_powf +__libm_sse2_sin +__libm_sse2_sinf +__libm_sse2_tan +__libm_sse2_tanf +__mb_cur_max +__p___argc +__p___argv +__p___initenv +__p___mb_cur_max +__p___wargv +__p___winitenv +__p__acmdln +__p__amblksiz +__p__commode +__p__daylight +__p__dstbias +__p__environ +__p__fileinfo +__p__fmode +__p__iob +__p__mbcasemap +__p__mbctype +__p__osver +__p__pctype +__p__pgmptr +__p__pwctype +__p__timezone +__p__tzname +__p__wcmdln +__p__wenviron +__p__winmajor +__p__winminor +__p__winver +__p__wpgmptr +__pctype_func +__pioinfo +__pwctype_func +__pxcptinfoptrs +__set_app_type +__setlc_active +__setusermatherr +__strncnt +__threadhandle +__threadid +__toascii +__unDName +__unDNameEx +__uncaught_exception +__unguarded_readlc_active +__wargv +__wcserror +__wcserror_s +__wcsncnt +__wgetmainargs +__winitenv +_abnormal_termination +_abs64 +_access +_access_s +_acmdln +_adj_fdiv_m16i +_adj_fdiv_m32 +_adj_fdiv_m32i +_adj_fdiv_m64 +_adj_fdiv_r +_adj_fdivr_m16i +_adj_fdivr_m32 +_adj_fdivr_m32i +_adj_fdivr_m64 +_adj_fpatan +_adj_fprem +_adj_fprem1 +_adj_fptan +_adjust_fdiv +_aexit_rtn +_aligned_free +_aligned_free_dbg +_aligned_malloc +_aligned_malloc_dbg +_aligned_offset_malloc +_aligned_offset_malloc_dbg +_aligned_offset_realloc +_aligned_offset_realloc_dbg +_aligned_realloc +_aligned_realloc_dbg +_amsg_exit +_assert +_atodbl +_atodbl_l +_atof_l +_atoflt_l +_atoi64 +_atoi64_l +_atoi_l +_atol_l +_atoldbl +_atoldbl_l +_beep +_beginthread +_beginthreadex +_c_exit +_cabs +_callnewh +_calloc_dbg +_cexit +_cgets +_cgets_s +_cgetws +_cgetws_s +_chdir +_chdrive +_chgsign +_chkesp +_chmod +_chsize +_chsize_s +_chvalidator +_chvalidator_l +_clearfp +_close +_commit +_commode +_control87 +_controlfp +_controlfp_s +_copysign +_cprintf +_cprintf_l +_cprintf_p +_cprintf_p_l +_cprintf_s +_cprintf_s_l +_cputs +_cputws +_creat +_crtAssertBusy +_crtBreakAlloc +_crtDbgFlag +_cscanf +_cscanf_l +_cscanf_s +_cscanf_s_l +_ctime32 +_ctime32_s +_ctime64 +_ctime64_s +_ctype +_cwait +_cwprintf +_cwprintf_l +_cwprintf_p +_cwprintf_p_l +_cwprintf_s +_cwprintf_s_l +_cwscanf +_cwscanf_l +_cwscanf_s +_cwscanf_s_l +_daylight +_difftime32 +_difftime64 +_dstbias +_dup +_dup2 +_ecvt +_ecvt_s +_endthread +_endthreadex +_environ +_eof +_errno +_except_handler2 +_except_handler3 +_except_handler4_common +_execl +_execle +_execlp +_execlpe +_execv +_execve +_execvp +_execvpe +_exit +_expand +_expand_dbg +_fcloseall +_fcvt +_fcvt_s +_fdopen +_fgetchar +_fgetwchar +_filbuf +_fileinfo +_filelength +_filelengthi64 +_fileno +_findclose +_findfirst +_findfirst64 +_findfirsti64 +_findnext +_findnext64 +_findnexti64 +_finite +_flsbuf +_flushall +_fmode +_fpclass +_fpieee_flt +_fpreset +_fprintf_l +_fprintf_p +_fprintf_p_l +_fprintf_s_l +_fputchar +_fputwchar +_free_dbg +_freea +_freea_s +_fscanf_l +_fscanf_s_l +_fseeki64 +_fsopen +_fstat +_fstat64 +_fstati64 +_ftime +_ftime32 +_ftime32_s +_ftime64 +_ftime64_s +_ftol +_ftol2 +_ftol2_sse +_ftol2_sse_excpt +_fullpath +_fullpath_dbg +_futime +_futime32 +_futime64 +_fwprintf_l +_fwprintf_p +_fwprintf_p_l +_fwprintf_s_l +_fwscanf_l +_fwscanf_s_l +_gcvt +_gcvt_s +_get_doserrno +_get_environ +_get_errno +_get_fileinfo +_get_fmode +_get_heap_handle +_get_osfhandle +_get_osplatform +_get_osver +_get_output_format +_get_pgmptr +_get_sbh_threshold +_get_wenviron +_get_winmajor +_get_winminor +_get_winver +_get_wpgmptr +_getch +_getche +_getcwd +_getdcwd +_getdiskfree +_getdllprocaddr +_getdrive +_getdrives +_getmaxstdio +_getmbcp +_getpid +_getsystime +_getw +_getwch +_getwche +_getws +_global_unwind2 +_gmtime32 +_gmtime32_s +_gmtime64 +_gmtime64_s +_heapadd +_heapchk +_heapmin +_heapset +_heapused +_heapwalk +_hypot +_i64toa +_i64toa_s +_i64tow +_i64tow_s +_initterm +_initterm_e +_inp +_inpd +_inpw +_invalid_parameter +_iob +_isalnum_l +_isalpha_l +_isatty +_iscntrl_l +_isctype +_isctype_l +_isdigit_l +_isgraph_l +_isleadbyte_l +_islower_l +_ismbbalnum +_ismbbalnum_l +_ismbbalpha +_ismbbalpha_l +_ismbbgraph +_ismbbgraph_l +_ismbbkalnum +_ismbbkalnum_l +_ismbbkana +_ismbbkana_l +_ismbbkprint +_ismbbkprint_l +_ismbbkpunct +_ismbbkpunct_l +_ismbblead +_ismbblead_l +_ismbbprint +_ismbbprint_l +_ismbbpunct +_ismbbpunct_l +_ismbbtrail +_ismbbtrail_l +_ismbcalnum +_ismbcalnum_l +_ismbcalpha +_ismbcalpha_l +_ismbcdigit +_ismbcdigit_l +_ismbcgraph +_ismbcgraph_l +_ismbchira +_ismbchira_l +_ismbckata +_ismbckata_l +_ismbcl0 +_ismbcl0_l +_ismbcl1 +_ismbcl1_l +_ismbcl2 +_ismbcl2_l +_ismbclegal +_ismbclegal_l +_ismbclower +_ismbclower_l +_ismbcprint +_ismbcprint_l +_ismbcpunct +_ismbcpunct_l +_ismbcspace +_ismbcspace_l +_ismbcsymbol +_ismbcsymbol_l +_ismbcupper +_ismbcupper_l +_ismbslead +_ismbslead_l +_ismbstrail +_ismbstrail_l +_isnan +_isprint_l +_isspace_l +_isupper_l +_iswalnum_l +_iswalpha_l +_iswcntrl_l +_iswctype_l +_iswdigit_l +_iswgraph_l +_iswlower_l +_iswprint_l +_iswpunct_l +_iswspace_l +_iswupper_l +_iswxdigit_l +_isxdigit_l +_itoa +_itoa_s +_itow +_itow_s +_j0 +_j1 +_jn +_kbhit +_lfind +_lfind_s +_loaddll +_local_unwind2 +_local_unwind4 +_localtime32 +_localtime32_s +_localtime64 +_localtime64_s +_lock +_locking +_logb +_longjmpex +_lrotl +_lrotr +_lsearch +_lsearch_s +_lseek +_lseeki64 +_ltoa +_ltoa_s +_ltow +_ltow_s +_makepath +_makepath_s +_malloc_dbg +_mbbtombc +_mbbtombc_l +_mbbtype +_mbcasemap +_mbccpy +_mbccpy_l +_mbccpy_s +_mbccpy_s_l +_mbcjistojms +_mbcjistojms_l +_mbcjmstojis +_mbcjmstojis_l +_mbclen +_mbclen_l +_mbctohira +_mbctohira_l +_mbctokata +_mbctokata_l +_mbctolower +_mbctolower_l +_mbctombb +_mbctombb_l +_mbctoupper +_mbctoupper_l +_mbctype +_mblen_l +_mbsbtype +_mbsbtype_l +_mbscat +_mbscat_s +_mbscat_s_l +_mbschr +_mbschr_l +_mbscmp +_mbscmp_l +_mbscoll +_mbscoll_l +_mbscpy +_mbscpy_s +_mbscpy_s_l +_mbscspn +_mbscspn_l +_mbsdec +_mbsdec_l +_mbsdup +_mbsicmp +_mbsicmp_l +_mbsicoll +_mbsicoll_l +_mbsinc +_mbsinc_l +_mbslen +_mbslen_l +_mbslwr +_mbslwr_l +_mbslwr_s +_mbslwr_s_l +_mbsnbcat +_mbsnbcat_l +_mbsnbcat_s +_mbsnbcat_s_l +_mbsnbcmp +_mbsnbcmp_l +_mbsnbcnt +_mbsnbcnt_l +_mbsnbcoll +_mbsnbcoll_l +_mbsnbcpy +_mbsnbcpy_l +_mbsnbcpy_s +_mbsnbcpy_s_l +_mbsnbicmp +_mbsnbicmp_l +_mbsnbicoll +_mbsnbicoll_l +_mbsnbset +_mbsnbset_l +_mbsnbset_s +_mbsnbset_s_l +_mbsncat +_mbsncat_l +_mbsncat_s +_mbsncat_s_l +_mbsnccnt +_mbsnccnt_l +_mbsncmp +_mbsncmp_l +_mbsncoll +_mbsncoll_l +_mbsncpy +_mbsncpy_l +_mbsncpy_s +_mbsncpy_s_l +_mbsnextc +_mbsnextc_l +_mbsnicmp +_mbsnicmp_l +_mbsnicoll +_mbsnicoll_l +_mbsninc +_mbsninc_l +_mbsnlen +_mbsnlen_l +_mbsnset +_mbsnset_l +_mbsnset_s +_mbsnset_s_l +_mbspbrk +_mbspbrk_l +_mbsrchr +_mbsrchr_l +_mbsrev +_mbsrev_l +_mbsset +_mbsset_l +_mbsset_s +_mbsset_s_l +_mbsspn +_mbsspn_l +_mbsspnp +_mbsspnp_l +_mbsstr +_mbsstr_l +_mbstok +_mbstok_l +_mbstok_s +_mbstok_s_l +_mbstowcs_l +_mbstowcs_s_l +_mbstrlen +_mbstrlen_l +_mbstrnlen +_mbstrnlen_l +_mbsupr +_mbsupr_l +_mbsupr_s +_mbsupr_s_l +_mbtowc_l +_memccpy +_memicmp +_memicmp_l +_mkdir +_mkgmtime +_mkgmtime32 +_mkgmtime64 +_mktemp +_mktemp_s +_mktime32 +_mktime64 +_msize +_msize_debug +_nextafter +_onexit +_open +_open_osfhandle +_osplatform +_osver +_outp +_outpd +_outpw +_pclose +_pctype +_pgmptr +_pipe +_popen +_printf_l +_printf_p +_printf_p_l +_printf_s_l +_purecall +_putch +_putenv +_putenv_s +_putw +_putwch +_putws +_pwctype +_read +_realloc_dbg +_resetstkoflw +_rmdir +_rmtmp +_rotl +_rotl64 +_rotr +_rotr64 +_safe_fdiv +_safe_fdivr +_safe_fprem +_safe_fprem1 +_scalb +_scanf_l +_scanf_s_l +_scprintf +_scprintf_l +_scprintf_p_l +_scwprintf +_scwprintf_l +_scwprintf_p_l +_searchenv +_searchenv_s +_seh_longjmp_unwind +_seh_longjmp_unwind4 +_set_SSE2_enable +_set_controlfp +_set_doserrno +_set_errno +_set_error_mode +_set_fileinfo +_set_fmode +_set_output_format +_set_sbh_threshold +_seterrormode +_setjmp +_setjmp3 +_setmaxstdio +_setmbcp +_setmode +_setsystime +_sleep +_snprintf +_snprintf_c +_snprintf_c_l +_snprintf_l +_snprintf_s +_snprintf_s_l +_snscanf +_snscanf_l +_snscanf_s +_snscanf_s_l +_snwprintf +_snwprintf_l +_snwprintf_s +_snwprintf_s_l +_snwscanf +_snwscanf_l +_snwscanf_s +_snwscanf_s_l +_sopen +_sopen_s +_spawnl +_spawnle +_spawnlp +_spawnlpe +_spawnv +_spawnve +_spawnvp +_spawnvpe +_splitpath +_splitpath_s +_sprintf_l +_sprintf_p_l +_sprintf_s_l +_sscanf_l +_sscanf_s_l +_stat +_stat64 +_stati64 +_statusfp +_strcmpi +_strcoll_l +_strdate +_strdate_s +_strdup +_strdup_dbg +_strerror +_strerror_s +_stricmp +_stricmp_l +_stricoll +_stricoll_l +_strlwr +_strlwr_l +_strlwr_s +_strlwr_s_l +_strncoll +_strncoll_l +_strnicmp +_strnicmp_l +_strnicoll +_strnicoll_l +_strnset +_strnset_s +_strrev +_strset +_strset_s +_strtime +_strtime_s +_strtod_l +_strtoi64 +_strtoi64_l +_strtol_l +_strtoui64 +_strtoui64_l +_strtoul_l +_strupr +_strupr_l +_strupr_s +_strupr_s_l +_strxfrm_l +_swab +_swprintf +_swprintf_c +_swprintf_c_l +_swprintf_p_l +_swprintf_s_l +_swscanf_l +_swscanf_s_l +_sys_errlist +_sys_nerr +_tell +_telli64 +_tempnam +_tempnam_dbg +_time32 +_time64 +_timezone +_tolower +_tolower_l +_toupper +_toupper_l +_towlower_l +_towupper_l +_tzname +_tzset +_ui64toa +_ui64toa_s +_ui64tow +_ui64tow_s +_ultoa +_ultoa_s +_ultow +_ultow_s +_umask +_umask_s +_ungetch +_ungetwch +_unlink +_unloaddll +_unlock +_utime +_utime32 +_utime64 +_vcprintf +_vcprintf_l +_vcprintf_p +_vcprintf_p_l +_vcprintf_s +_vcprintf_s_l +_vcwprintf +_vcwprintf_l +_vcwprintf_p +_vcwprintf_p_l +_vcwprintf_s +_vcwprintf_s_l +_vfprintf_l +_vfprintf_p +_vfprintf_p_l +_vfprintf_s_l +_vfwprintf_l +_vfwprintf_p +_vfwprintf_p_l +_vfwprintf_s_l +_vprintf_l +_vprintf_p +_vprintf_p_l +_vprintf_s_l +_vscprintf +_vscprintf_l +_vscprintf_p_l +_vscwprintf +_vscwprintf_l +_vscwprintf_p_l +_vsnprintf +_vsnprintf_c +_vsnprintf_c_l +_vsnprintf_l +_vsnprintf_s +_vsnprintf_s_l +_vsnwprintf +_vsnwprintf_l +_vsnwprintf_s +_vsnwprintf_s_l +_vsprintf_l +_vsprintf_p +_vsprintf_p_l +_vsprintf_s_l +_vswprintf +_vswprintf_c +_vswprintf_c_l +_vswprintf_l +_vswprintf_p_l +_vswprintf_s_l +_vwprintf_l +_vwprintf_p +_vwprintf_p_l +_vwprintf_s_l +_waccess +_waccess_s +_wasctime +_wasctime_s +_wassert +_wchdir +_wchmod +_wcmdln +_wcreat +_wcscoll_l +_wcsdup +_wcsdup_dbg +_wcserror +_wcserror_s +_wcsftime_l +_wcsicmp +_wcsicmp_l +_wcsicoll +_wcsicoll_l +_wcslwr +_wcslwr_l +_wcslwr_s +_wcslwr_s_l +_wcsncoll +_wcsncoll_l +_wcsnicmp +_wcsnicmp_l +_wcsnicoll +_wcsnicoll_l +_wcsnset +_wcsnset_s +_wcsrev +_wcsset +_wcsset_s +_wcstoi64 +_wcstoi64_l +_wcstol_l +_wcstombs_l +_wcstombs_s_l +_wcstoui64 +_wcstoui64_l +_wcstoul_l +_wcsupr +_wcsupr_l +_wcsupr_s +_wcsupr_s_l +_wcsxfrm_l +_wctime +_wctime32 +_wctime32_s +_wctime64 +_wctime64_s +_wctomb_l +_wctomb_s_l +_wctype +_wenviron +_wexecl +_wexecle +_wexeclp +_wexeclpe +_wexecv +_wexecve +_wexecvp +_wexecvpe +_wfdopen +_wfindfirst +_wfindfirst64 +_wfindfirsti64 +_wfindnext +_wfindnext64 +_wfindnexti64 +_wfopen +_wfopen_s +_wfreopen +_wfreopen_s +_wfsopen +_wfullpath +_wfullpath_dbg +_wgetcwd +_wgetdcwd +_wgetenv +_wgetenv_s +_winmajor +_winminor +_winput_s +_winver +_wmakepath +_wmakepath_s +_wmkdir +_wmktemp +_wmktemp_s +_wopen +_woutput_s +_wperror +_wpgmptr +_wpopen +_wprintf_l +_wprintf_p +_wprintf_p_l +_wprintf_s_l +_wputenv +_wputenv_s +_wremove +_wrename +_write +_wrmdir +_wscanf_l +_wscanf_s_l +_wsearchenv +_wsearchenv_s +_wsetlocale +_wsopen +_wsopen_s +_wspawnl +_wspawnle +_wspawnlp +_wspawnlpe +_wspawnv +_wspawnve +_wspawnvp +_wspawnvpe +_wsplitpath +_wsplitpath_s +_wstat +_wstat64 +_wstati64 +_wstrdate +_wstrdate_s +_wstrtime +_wstrtime_s +_wsystem +_wtempnam +_wtempnam_dbg +_wtmpnam +_wtmpnam_s +_wtof +_wtof_l +_wtoi +_wtoi64 +_wtoi64_l +_wtoi_l +_wtol +_wtol_l +_wunlink +_wutime +_wutime32 +_wutime64 +_y0 +_y1 +_yn +abort +abs +acos +asctime +asctime_s +asin +atan +atan2 +atexit +atof +atoi +atol +bsearch +bsearch_s +btowc +calloc +ceil +clearerr +clearerr_s +clock +cos +cosh +ctime +difftime +div +exit +exp +fabs +fclose +feof +ferror +fflush +fgetc +fgetpos +fgets +fgetwc +fgetws +floor +fmod +fopen +fopen_s +fprintf +fprintf_s +fputc +fputs +fputwc +fputws +fread +free +freopen +freopen_s +frexp +fscanf +fscanf_s +fseek +fsetpos +ftell +fwprintf +fwprintf_s +fwrite +fwscanf +fwscanf_s +getc +getchar +getenv +getenv_s +gets +getwc +getwchar +gmtime +is_wctype +isalnum +isalpha +iscntrl +isdigit +isgraph +isleadbyte +islower +isprint +ispunct +isspace +isupper +iswalnum +iswalpha +iswascii +iswcntrl +iswctype +iswdigit +iswgraph +iswlower +iswprint +iswpunct +iswspace +iswupper +iswxdigit +isxdigit +labs +ldexp +ldiv +localeconv +localtime +log +log10 +longjmp +malloc +mblen +mbrlen +mbrtowc +mbsdup_dbg +mbsrtowcs +mbsrtowcs_s +mbstowcs +mbstowcs_s +mbtowc +memchr +memcmp +memcpy +memcpy_s +memmove +memmove_s +memset +mktime +modf +perror +pow +printf +printf_s +putc +putchar +puts +putwc +putwchar +qsort +qsort_s +raise +rand +rand_s +realloc +remove +rename +rewind +scanf +scanf_s +setbuf +setlocale +setvbuf +signal +sin +sinh +sprintf +sprintf_s +sqrt +srand +sscanf +sscanf_s +strcat +strcat_s +strchr +strcmp +strcoll +strcpy +strcpy_s +strcspn +strerror +strerror_s +strftime +strlen +strncat +strncat_s +strncmp +strncpy +strncpy_s +strnlen +strpbrk +strrchr +strspn +strstr +strtod +strtok +strtok_s +strtol +strtoul +strxfrm +swprintf +swprintf_s +swscanf +swscanf_s +system +tan +tanh +time +tmpfile +tmpfile_s +tmpnam +tmpnam_s +tolower +toupper +towlower +towupper +ungetc +ungetwc +utime +vfprintf +vfprintf_s +vfwprintf +vfwprintf_s +vprintf +vprintf_s +vsnprintf +vsprintf +vsprintf_s +vswprintf +vswprintf_s +vwprintf +vwprintf_s +wcrtomb +wcrtomb_s +wcscat +wcscat_s +wcschr +wcscmp +wcscoll +wcscpy +wcscpy_s +wcscspn +wcsftime +wcslen +wcsncat +wcsncat_s +wcsncmp +wcsncpy +wcsncpy_s +wcsnlen +wcspbrk +wcsrchr +wcsrtombs +wcsrtombs_s +wcsspn +wcsstr +wcstod +wcstok +wcstok_s +wcstol +wcstombs +wcstombs_s +wcstoul +wcsxfrm +wctob +wctomb +wctomb_s +wprintf +wprintf_s +wscanf +wscanf_s diff --git a/tinyc/win32/lib/user32.def b/tinyc/win32/lib/user32.def new file mode 100644 index 000000000..a034dac20 --- /dev/null +++ b/tinyc/win32/lib/user32.def @@ -0,0 +1,658 @@ +LIBRARY user32.dll + +EXPORTS +ActivateKeyboardLayout +AdjustWindowRect +AdjustWindowRectEx +AlignRects +AllowSetForegroundWindow +AnimateWindow +AnyPopup +AppendMenuA +AppendMenuW +ArrangeIconicWindows +AttachThreadInput +BeginDeferWindowPos +BeginPaint +BlockInput +BringWindowToTop +BroadcastSystemMessage +BroadcastSystemMessageA +BroadcastSystemMessageW +CalcChildScroll +CallMsgFilter +CallMsgFilterA +CallMsgFilterW +CallNextHookEx +CallWindowProcA +CallWindowProcW +CascadeChildWindows +CascadeWindows +ChangeClipboardChain +ChangeDisplaySettingsA +ChangeDisplaySettingsExA +ChangeDisplaySettingsExW +ChangeDisplaySettingsW +ChangeMenuA +ChangeMenuW +CharLowerA +CharLowerBuffA +CharLowerBuffW +CharLowerW +CharNextA +CharNextExA +CharNextExW +CharNextW +CharPrevA +CharPrevExA +CharPrevExW +CharPrevW +CharToOemA +CharToOemBuffA +CharToOemBuffW +CharToOemW +CharUpperA +CharUpperBuffA +CharUpperBuffW +CharUpperW +CheckDlgButton +CheckMenuItem +CheckMenuRadioItem +CheckRadioButton +ChildWindowFromPoint +ChildWindowFromPointEx +ClientThreadConnect +ClientToScreen +ClipCursor +CloseClipboard +CloseDesktop +CloseWindow +CloseWindowStation +CopyAcceleratorTableA +CopyAcceleratorTableW +CopyIcon +CopyImage +CopyRect +CountClipboardFormats +CreateAcceleratorTableA +CreateAcceleratorTableW +CreateCaret +CreateCursor +CreateDesktopA +CreateDesktopW +CreateDialogIndirectParamA +CreateDialogIndirectParamW +CreateDialogParamA +CreateDialogParamW +CreateIcon +CreateIconFromResource +CreateIconFromResourceEx +CreateIconIndirect +CreateMDIWindowA +CreateMDIWindowW +CreateMenu +CreatePopupMenu +CreateWindowExA +CreateWindowExW +CreateWindowStationA +CreateWindowStationW +DdeAbandonTransaction +DdeAccessData +DdeAddData +DdeClientTransaction +DdeCmpStringHandles +DdeConnect +DdeConnectList +DdeCreateDataHandle +DdeCreateStringHandleA +DdeCreateStringHandleW +DdeDisconnect +DdeDisconnectList +DdeEnableCallback +DdeFreeDataHandle +DdeFreeStringHandle +DdeGetData +DdeGetLastError +DdeImpersonateClient +DdeInitializeA +DdeInitializeW +DdeKeepStringHandle +DdeNameService +DdePostAdvise +DdeQueryConvInfo +DdeQueryNextServer +DdeQueryStringA +DdeQueryStringW +DdeReconnect +DdeSetQualityOfService +DdeSetUserHandle +DdeUnaccessData +DdeUninitialize +DefDlgProcA +DefDlgProcW +DefFrameProcA +DefFrameProcW +DefMDIChildProcA +DefMDIChildProcW +DefWindowProcA +DefWindowProcW +DeferWindowPos +DeleteMenu +DestroyAcceleratorTable +DestroyCaret +DestroyCursor +DestroyIcon +DestroyMenu +DestroyWindow +DialogBoxIndirectParamA +DialogBoxIndirectParamW +DialogBoxParamA +DialogBoxParamW +DispatchMessageA +DispatchMessageW +DlgDirListA +DlgDirListComboBoxA +DlgDirListComboBoxW +DlgDirListW +DlgDirSelectComboBoxExA +DlgDirSelectComboBoxExW +DlgDirSelectExA +DlgDirSelectExW +DragDetect +DragObject +DrawAnimatedRects +DrawCaption +DrawCaptionTempA +DrawCaptionTempW +DrawEdge +DrawFocusRect +DrawFrame +DrawFrameControl +DrawIcon +DrawIconEx +DrawMenuBar +DrawMenuBarTemp +DrawStateA +DrawStateW +DrawTextA +DrawTextExA +DrawTextExW +DrawTextW +EditWndProc +EmptyClipboard +EnableMenuItem +EnableScrollBar +EnableWindow +EndDeferWindowPos +EndDialog +EndMenu +EndPaint +EndTask +EnumChildWindows +EnumClipboardFormats +EnumDesktopWindows +EnumDesktopsA +EnumDesktopsW +EnumDisplayDevicesA +EnumDisplayDevicesW +EnumDisplayMonitors +EnumDisplaySettingsA +EnumDisplaySettingsExA +EnumDisplaySettingsExW +EnumDisplaySettingsW +EnumPropsA +EnumPropsExA +EnumPropsExW +EnumPropsW +EnumThreadWindows +EnumWindowStationsA +EnumWindowStationsW +EnumWindows +EqualRect +ExcludeUpdateRgn +ExitWindowsEx +FillRect +FindWindowA +FindWindowExA +FindWindowExW +FindWindowW +FlashWindow +FlashWindowEx +FrameRect +FreeDDElParam +GetActiveWindow +GetAltTabInfo +GetAncestor +GetAsyncKeyState +GetCapture +GetCaretBlinkTime +GetCaretPos +GetClassInfoA +GetClassInfoExA +GetClassInfoExW +GetClassInfoW +GetClassLongA +GetClassLongW +GetClassNameA +GetClassNameW +GetClassWord +GetClientRect +GetClipCursor +GetClipboardData +GetClipboardFormatNameA +GetClipboardFormatNameW +GetClipboardOwner +GetClipboardSequenceNumber +GetClipboardViewer +GetComboBoxInfo +GetCursor +GetCursorInfo +GetCursorPos +GetDC +GetDCEx +GetDesktopWindow +GetDialogBaseUnits +GetDlgCtrlID +GetDlgItem +GetDlgItemInt +GetDlgItemTextA +GetDlgItemTextW +GetDoubleClickTime +GetFocus +GetForegroundWindow +GetGUIThreadInfo +GetGuiResources +GetIconInfo +GetInputDesktop +GetInputState +GetInternalWindowPos +GetKBCodePage +GetKeyNameTextA +GetKeyNameTextW +GetKeyState +GetKeyboardLayout +GetKeyboardLayoutList +GetKeyboardLayoutNameA +GetKeyboardLayoutNameW +GetKeyboardState +GetKeyboardType +GetLastActivePopup +GetListBoxInfo +GetMenu +GetMenuBarInfo +GetMenuCheckMarkDimensions +GetMenuContextHelpId +GetMenuDefaultItem +GetMenuInfo +GetMenuItemCount +GetMenuItemID +GetMenuItemInfoA +GetMenuItemInfoW +GetMenuItemRect +GetMenuState +GetMenuStringA +GetMenuStringW +GetMessageA +GetMessageExtraInfo +GetMessagePos +GetMessageTime +GetMessageW +GetMonitorInfoA +GetMonitorInfoW +GetMouseMovePoints +GetMouseMovePointsEx +GetNextDlgGroupItem +GetNextDlgTabItem +GetNextQueueWindow +GetOpenClipboardWindow +GetParent +GetPriorityClipboardFormat +GetProcessDefaultLayout +GetProcessWindowStation +GetPropA +GetPropW +GetQueueStatus +GetScrollBarInfo +GetScrollInfo +GetScrollPos +GetScrollRange +GetShellWindow +GetSubMenu +GetSysColor +GetSysColorBrush +GetSystemMenu +GetSystemMetrics +GetTabbedTextExtentA +GetTabbedTextExtentW +GetThreadDesktop +GetTitleBarInfo +GetTopWindow +GetUpdateRect +GetUpdateRgn +GetUserObjectInformationA +GetUserObjectInformationW +GetUserObjectSecurity +GetWindow +GetWindowContextHelpId +GetWindowDC +GetWindowInfo +GetWindowLongPtrA +GetWindowLongPtrW +SetWindowLongPtrA +SetWindowLongPtrW +GetWindowLongA +GetWindowLongW +GetWindowModuleFileNameA +GetWindowModuleFileNameW +GetWindowPlacement +GetWindowRect +GetWindowRgn +GetWindowTextA +GetWindowTextLengthA +GetWindowTextLengthW +GetWindowTextW +GetWindowThreadProcessId +GetWindowWord +GrayStringA +GrayStringW +HasSystemSleepStarted +HideCaret +HiliteMenuItem +IMPGetIMEA +IMPGetIMEW +IMPQueryIMEA +IMPQueryIMEW +IMPSetIMEA +IMPSetIMEW +ImpersonateDdeClientWindow +InSendMessage +InSendMessageEx +InflateRect +InitSharedTable +InitTask +InsertMenuA +InsertMenuItemA +InsertMenuItemW +InsertMenuW +InternalGetWindowText +IntersectRect +InvalidateRect +InvalidateRgn +InvertRect +IsCharAlphaA +IsCharAlphaNumericA +IsCharAlphaNumericW +IsCharAlphaW +IsCharLowerA +IsCharLowerW +IsCharUpperA +IsCharUpperW +IsChild +IsClipboardFormatAvailable +IsDialogMessage +IsDialogMessageA +IsDialogMessageW +IsDlgButtonChecked +IsHungThread +IsIconic +IsMenu +IsRectEmpty +IsWindow +IsWindowEnabled +IsWindowUnicode +IsWindowVisible +IsZoomed +KillTimer +LoadAcceleratorsA +LoadAcceleratorsW +LoadBitmapA +LoadBitmapW +LoadCursorA +LoadCursorFromFileA +LoadCursorFromFileW +LoadCursorW +LoadIconA +LoadIconW +LoadImageA +LoadImageW +LoadKeyboardLayoutA +LoadKeyboardLayoutW +LoadMenuA +LoadMenuIndirectA +LoadMenuIndirectW +LoadMenuW +LoadStringA +LoadStringW +LockSetForegroundWindow +LockWindowStation +LockWindowUpdate +LookupIconIdFromDirectory +LookupIconIdFromDirectoryEx +MapDialogRect +MapVirtualKeyA +MapVirtualKeyExA +MapVirtualKeyExW +MapVirtualKeyW +MapWindowPoints +MenuItemFromPoint +MessageBeep +MessageBoxA +MessageBoxExA +MessageBoxExW +MessageBoxIndirectA +MessageBoxIndirectW +MessageBoxW +ModifyAccess +ModifyMenuA +ModifyMenuW +MonitorFromPoint +MonitorFromRect +MonitorFromWindow +MoveWindow +MsgWaitForMultipleObjects +MsgWaitForMultipleObjectsEx +NotifyWinEvent +OemKeyScan +OemToCharA +OemToCharBuffA +OemToCharBuffW +OemToCharW +OffsetRect +OpenClipboard +OpenDesktopA +OpenDesktopW +OpenIcon +OpenInputDesktop +OpenWindowStationA +OpenWindowStationW +PackDDElParam +PaintDesktop +PeekMessageA +PeekMessageW +PlaySoundEvent +PostMessageA +PostMessageW +PostQuitMessage +PostThreadMessageA +PostThreadMessageW +PtInRect +RealChildWindowFromPoint +RealGetWindowClass +RedrawWindow +RegisterClassA +RegisterClassExA +RegisterClassExW +RegisterClassW +RegisterClipboardFormatA +RegisterClipboardFormatW +RegisterDeviceNotificationA +RegisterDeviceNotificationW +RegisterHotKey +RegisterLogonProcess +RegisterNetworkCapabilities +RegisterSystemThread +RegisterTasklist +RegisterWindowMessageA +RegisterWindowMessageW +ReleaseCapture +ReleaseDC +RemoveMenu +RemovePropA +RemovePropW +ReplyMessage +ReuseDDElParam +ScreenToClient +ScrollDC +ScrollWindow +ScrollWindowEx +SendDlgItemMessageA +SendDlgItemMessageW +SendIMEMessageExA +SendIMEMessageExW +SendInput +SendMessageA +SendMessageCallbackA +SendMessageCallbackW +SendMessageTimeoutA +SendMessageTimeoutW +SendMessageW +SendNotifyMessageA +SendNotifyMessageW +SetActiveWindow +SetCapture +SetCaretBlinkTime +SetCaretPos +SetClassLongA +SetClassLongW +SetClassWord +SetClipboardData +SetClipboardViewer +SetCursor +SetCursorPos +SetDebugErrorLevel +SetDeskWallpaper +SetDesktopBitmap +SetDlgItemInt +SetDlgItemTextA +SetDlgItemTextW +SetDoubleClickTime +SetFocus +SetForegroundWindow +SetInternalWindowPos +SetKeyboardState +SetLastErrorEx +SetLogonNotifyWindow +SetMenu +SetMenuContextHelpId +SetMenuDefaultItem +SetMenuInfo +SetMenuItemBitmaps +SetMenuItemInfoA +SetMenuItemInfoW +SetMessageExtraInfo +SetMessageQueue +SetParent +SetProcessDefaultLayout +SetProcessWindowStation +SetPropA +SetPropW +SetRect +SetRectEmpty +SetScrollInfo +SetScrollPos +SetScrollRange +SetShellWindow +SetSysColors +SetSysColorsTemp +SetSystemCursor +SetThreadDesktop +SetTimer +SetUserObjectInformationA +SetUserObjectInformationW +SetUserObjectSecurity +SetWinEventHook +SetWindowContextHelpId +SetWindowFullScreenState +SetWindowLongA +SetWindowLongW +SetWindowPlacement +SetWindowPos +SetWindowRgn +SetWindowTextA +SetWindowTextW +SetWindowWord +SetWindowsHookA +SetWindowsHookExA +SetWindowsHookExW +SetWindowsHookW +ShowCaret +ShowCursor +ShowOwnedPopups +ShowScrollBar +ShowWindow +ShowWindowAsync +SubtractRect +SwapMouseButton +SwitchDesktop +SwitchToThisWindow +SysErrorBox +SystemParametersInfoA +SystemParametersInfoW +TabbedTextOutA +TabbedTextOutW +TileChildWindows +TileWindows +ToAscii +ToAsciiEx +ToUnicode +ToUnicodeEx +TrackMouseEvent +TrackPopupMenu +TrackPopupMenuEx +TranslateAccelerator +TranslateAcceleratorA +TranslateAcceleratorW +TranslateMDISysAccel +TranslateMessage +UnhookWinEvent +UnhookWindowsHook +UnhookWindowsHookEx +UnionRect +UnloadKeyboardLayout +UnlockWindowStation +UnpackDDElParam +UnregisterClassA +UnregisterClassW +UnregisterDeviceNotification +UnregisterHotKey +UpdateWindow +UserClientDllInitialize +UserIsSystemResumeAutomatic +UserSetDeviceHoldState +UserSignalProc +UserTickleTimer +ValidateRect +ValidateRgn +VkKeyScanA +VkKeyScanExA +VkKeyScanExW +VkKeyScanW +WINNLSEnableIME +WINNLSGetEnableStatus +WINNLSGetIMEHotkey +WNDPROC_CALLBACK +WaitForInputIdle +WaitMessage +WinHelpA +WinHelpW +WinOldAppHackoMatic +WindowFromDC +WindowFromPoint +YieldTask +_SetProcessDefaultLayout +keybd_event +mouse_event +wsprintfA +wsprintfW +wvsprintfA +wvsprintfW diff --git a/tinyc/win32/lib/wincrt1.c b/tinyc/win32/lib/wincrt1.c new file mode 100644 index 000000000..ce3a63f13 --- /dev/null +++ b/tinyc/win32/lib/wincrt1.c @@ -0,0 +1,75 @@ +//+--------------------------------------------------------------------------- + +// _UNICODE for tchar.h, UNICODE for API +#include + +#include +#include + +#define __UNKNOWN_APP 0 +#define __CONSOLE_APP 1 +#define __GUI_APP 2 +void __set_app_type(int); +void _controlfp(unsigned a, unsigned b); + +#ifdef _UNICODE +#define __tgetmainargs __wgetmainargs +#define _twinstart _wwinstart +#define _runtwinmain _runwwinmain +int APIENTRY wWinMain(HINSTANCE, HINSTANCE, LPWSTR, int); +#else +#define __tgetmainargs __getmainargs +#define _twinstart _winstart +#define _runtwinmain _runwinmain +#endif + +typedef struct { int newmode; } _startupinfo; +int __cdecl __tgetmainargs(int *pargc, _TCHAR ***pargv, _TCHAR ***penv, int globb, _startupinfo*); + +static int go_winmain(TCHAR *arg1) +{ + STARTUPINFO si; + _TCHAR *szCmd, *p; + int fShow; + + GetStartupInfo(&si); + if (si.dwFlags & STARTF_USESHOWWINDOW) + fShow = si.wShowWindow; + else + fShow = SW_SHOWDEFAULT; + + szCmd = NULL, p = GetCommandLine(); + if (arg1) + szCmd = _tcsstr(p, arg1); + if (NULL == szCmd) + szCmd = _tcsdup(__T("")); + else if (szCmd > p && szCmd[-1] == __T('"')) + --szCmd; +#if defined __i386__ || defined __x86_64__ + _controlfp(0x10000, 0x30000); +#endif + return _tWinMain(GetModuleHandle(NULL), NULL, szCmd, fShow); +} + +int _twinstart(void) +{ + __TRY__ + _startupinfo start_info_con = {0}; + __set_app_type(__GUI_APP); + __tgetmainargs(&__argc, &__targv, &_tenviron, 0, &start_info_con); + exit(go_winmain(__argc > 1 ? __targv[1] : NULL)); +} + +int _runtwinmain(int argc, /* as tcc passed in */ char **argv) +{ +#ifdef UNICODE + _startupinfo start_info = {0}; + __tgetmainargs(&__argc, &__targv, &_tenviron, 0, &start_info); + /* may be wrong when tcc has received wildcards (*.c) */ + if (argc < __argc) + __targv += __argc - argc, __argc = argc; +#else + __argc = argc, __targv = argv; +#endif + return go_winmain(__argc > 1 ? __targv[1] : NULL); +} diff --git a/tinyc/win32/lib/wincrt1w.c b/tinyc/win32/lib/wincrt1w.c new file mode 100644 index 000000000..a7d349e10 --- /dev/null +++ b/tinyc/win32/lib/wincrt1w.c @@ -0,0 +1,3 @@ +#define _UNICODE 1 +#define UNICODE 1 +#include "wincrt1.c" diff --git a/tinyc/win32/tcc-win32.txt b/tinyc/win32/tcc-win32.txt new file mode 100644 index 000000000..751a8e074 --- /dev/null +++ b/tinyc/win32/tcc-win32.txt @@ -0,0 +1,168 @@ + + TinyCC + ====== + + This file contains specific information for usage of TinyCC + under MS-Windows. See tcc-doc.html to have all the features. + + + Installation from the binary ZIP package: + ----------------------------------------- + Unzip the package to a directory of your choice. + + + Set the system PATH: + -------------------- + To be able to invoke the compiler from everywhere on your computer by + just typing "tcc", please add the directory containing tcc.exe to your + system PATH. + + + Include and library search paths + -------------------------------- + On windows, the standard "include" and "lib" directories are searched + relatively from the location of the executables (tcc.exe, libtcc.dll). + + + Examples: + --------- + Open a console window (DOS box) and 'cd' to the examples directory. + + For the 'Fibonacci' example type: + + tcc fib.c + + For the 'Hello Windows' GUI example type: + + tcc hello_win.c + + For the 'Hello DLL' example type + + tcc -shared dll.c + tcc -impdef dll.dll (optional) + tcc hello_dll.c dll.def + + + Using libtcc as JIT compiler in your program + -------------------------------------------- + Check out the 'libtcc_test' example: + + - Running it from source: + tcc -I libtcc libtcc/libtcc.def -run examples/libtcc_test.c + + - Compiling with TCC: + tcc examples/libtcc_test.c -I libtcc libtcc/libtcc.def + + - Compiling with MinGW: + gcc examples/libtcc_test.c -I libtcc libtcc.dll -o libtcc_test.exe + + - Compiling with MSVC: + lib /def:libtcc\libtcc.def /out:libtcc.lib + cl /MD examples/libtcc_test.c -I libtcc libtcc.lib + + + Import Definition Files: + ------------------------ + To link with Windows system DLLs, TCC uses import definition + files (.def) instead of libraries. + + The now built-in 'tiny_impdef' program may be used to make + additional .def files for any DLL. For example + + tcc -impdef [-v] opengl32.dll [-o opengl32.def] + + Put opengl32.def into the tcc/lib directory. Specify -lopengl32 at + the TCC commandline to link a program that uses opengl32.dll. + + + Header Files: + ------------- + The system header files (except _mingw.h) are from the MinGW + distribution: + + http://www.mingw.org/ + + From the windows headers, only a minimal set is included. If you need + more, get MinGW's "w32api" package. Extract the files from "include" + into your "tcc/include/winapi" directory. + + + Resource Files: + --------------- + TCC can link windows resources in coff format as generated by MinGW's + windres.exe. For example: + + windres -O coff app.rc -o appres.o + tcc app.c appres.o -o app.exe + + + Tiny Libmaker: + -------------- + The now built-in tiny_libmaker tool by Timovj Lahde can be used as + 'ar' replacement to make a library from several object files: + + tcc -ar [rcsv] library objectfiles ... + + + Compilation from source: + ------------------------ + * You can use the MinGW and MSYS tools available at + http://www.mingw.org + http://www.mingw-w64.org + http://www.msys2.org + + Untar the TCC archive and type in the MSYS shell: + ./configure [--prefix installpath] + make + make install + + The default install location is c:\Program Files\tcc + + Cygwin can be used too with its mingw cross-compiler installed: + ./configure --cross-prefix=i686-w64-mingw32- + (the prefix may vary) + + * Alternatively you can compile TCC with just GCC from MinGW using + > build-tcc.bat (from the win32 directory) + + Also MSVC can be used with the "VSTools Developer Command Prompt": + > build-tcc.bat -c cl + + or with an existing tcc (needs to be in a different directory) + > build-tcc.bat -c some-tcc-dir\tcc.exe + + Also you can copy/install everything into another directory: + > build-tcc.bat -i + + Limitations: + ------------ + - On the object file level, currently TCC supports only the ELF format, + not COFF as used by MinGW and MSVC. It is not possible to exchange + object files or libraries between TCC and these compilers. + + However libraries for TCC from objects by TCC can be made using + tcc -ar lib.a files.o ,,, + + - No leading underscore is generated in the ELF symbols. + + Documentation and License: + -------------------------- + TCC is distributed under the GNU Lesser General Public License. (See + COPYING file or http://www.gnu.org/licenses/lgpl-2.1.html) + + TinyCC homepage is at: + + http://fabrice.bellard.free.fr/tcc/ + + + WinAPI Help and 3rd-party tools: + -------------------------------- + The Windows API documentation (Win95) in a single .hlp file is + available on the lcc-win32 site as "win32hlp.exe" or from other + locations as "win32hlp_big.zip". + + A nice RAD tool to create windows resources (dialog boxes etc.) is + "ResEd", available at the RadASM website. + + + --- grischka diff --git a/tinyc/x86_64-asm.h b/tinyc/x86_64-asm.h new file mode 100644 index 000000000..cb9eb16c8 --- /dev/null +++ b/tinyc/x86_64-asm.h @@ -0,0 +1,525 @@ + DEF_ASM_OP0(clc, 0xf8) /* must be first OP0 */ + DEF_ASM_OP0(cld, 0xfc) + DEF_ASM_OP0(cli, 0xfa) + DEF_ASM_OP0(clts, 0x0f06) + DEF_ASM_OP0(cmc, 0xf5) + DEF_ASM_OP0(lahf, 0x9f) + DEF_ASM_OP0(sahf, 0x9e) + DEF_ASM_OP0(pushfq, 0x9c) + DEF_ASM_OP0(popfq, 0x9d) + DEF_ASM_OP0(pushf, 0x9c) + DEF_ASM_OP0(popf, 0x9d) + DEF_ASM_OP0(stc, 0xf9) + DEF_ASM_OP0(std, 0xfd) + DEF_ASM_OP0(sti, 0xfb) + DEF_ASM_OP0(aaa, 0x37) + DEF_ASM_OP0(aas, 0x3f) + DEF_ASM_OP0(daa, 0x27) + DEF_ASM_OP0(das, 0x2f) + DEF_ASM_OP0(aad, 0xd50a) + DEF_ASM_OP0(aam, 0xd40a) + DEF_ASM_OP0(cbw, 0x6698) + DEF_ASM_OP0(cwd, 0x6699) + DEF_ASM_OP0(cwde, 0x98) + DEF_ASM_OP0(cdq, 0x99) + DEF_ASM_OP0(cbtw, 0x6698) + DEF_ASM_OP0(cwtl, 0x98) + DEF_ASM_OP0(cwtd, 0x6699) + DEF_ASM_OP0(cltd, 0x99) + DEF_ASM_OP0(cqto, 0x4899) + DEF_ASM_OP0(int3, 0xcc) + DEF_ASM_OP0(into, 0xce) + DEF_ASM_OP0(iret, 0xcf) + DEF_ASM_OP0(rsm, 0x0faa) + DEF_ASM_OP0(hlt, 0xf4) + DEF_ASM_OP0(wait, 0x9b) + DEF_ASM_OP0(nop, 0x90) + DEF_ASM_OP0(pause, 0xf390) + DEF_ASM_OP0(xlat, 0xd7) + + /* strings */ +ALT(DEF_ASM_OP0L(cmpsb, 0xa6, 0, OPC_BWLX)) +ALT(DEF_ASM_OP0L(scmpb, 0xa6, 0, OPC_BWLX)) + +ALT(DEF_ASM_OP0L(insb, 0x6c, 0, OPC_BWL)) +ALT(DEF_ASM_OP0L(outsb, 0x6e, 0, OPC_BWL)) + +ALT(DEF_ASM_OP0L(lodsb, 0xac, 0, OPC_BWLX)) +ALT(DEF_ASM_OP0L(slodb, 0xac, 0, OPC_BWLX)) + +ALT(DEF_ASM_OP0L(movsb, 0xa4, 0, OPC_BWLX)) +ALT(DEF_ASM_OP0L(smovb, 0xa4, 0, OPC_BWLX)) + +ALT(DEF_ASM_OP0L(scasb, 0xae, 0, OPC_BWLX)) +ALT(DEF_ASM_OP0L(sscab, 0xae, 0, OPC_BWLX)) + +ALT(DEF_ASM_OP0L(stosb, 0xaa, 0, OPC_BWLX)) +ALT(DEF_ASM_OP0L(sstob, 0xaa, 0, OPC_BWLX)) + + /* bits */ + +ALT(DEF_ASM_OP2(bsfw, 0x0fbc, 0, OPC_MODRM | OPC_WLX, OPT_REGW | OPT_EA, OPT_REGW)) +ALT(DEF_ASM_OP2(bsrw, 0x0fbd, 0, OPC_MODRM | OPC_WLX, OPT_REGW | OPT_EA, OPT_REGW)) + +ALT(DEF_ASM_OP2(btw, 0x0fa3, 0, OPC_MODRM | OPC_WLX, OPT_REGW, OPT_REGW | OPT_EA)) +ALT(DEF_ASM_OP2(btw, 0x0fba, 4, OPC_MODRM | OPC_WLX, OPT_IM8, OPT_REGW | OPT_EA)) + +ALT(DEF_ASM_OP2(btsw, 0x0fab, 0, OPC_MODRM | OPC_WLX, OPT_REGW, OPT_REGW | OPT_EA)) +ALT(DEF_ASM_OP2(btsw, 0x0fba, 5, OPC_MODRM | OPC_WLX, OPT_IM8, OPT_REGW | OPT_EA)) + +ALT(DEF_ASM_OP2(btrw, 0x0fb3, 0, OPC_MODRM | OPC_WLX, OPT_REGW, OPT_REGW | OPT_EA)) +ALT(DEF_ASM_OP2(btrw, 0x0fba, 6, OPC_MODRM | OPC_WLX, OPT_IM8, OPT_REGW | OPT_EA)) + +ALT(DEF_ASM_OP2(btcw, 0x0fbb, 0, OPC_MODRM | OPC_WLX, OPT_REGW, OPT_REGW | OPT_EA)) +ALT(DEF_ASM_OP2(btcw, 0x0fba, 7, OPC_MODRM | OPC_WLX, OPT_IM8, OPT_REGW | OPT_EA)) + + /* prefixes */ + DEF_ASM_OP0(lock, 0xf0) + DEF_ASM_OP0(rep, 0xf3) + DEF_ASM_OP0(repe, 0xf3) + DEF_ASM_OP0(repz, 0xf3) + DEF_ASM_OP0(repne, 0xf2) + DEF_ASM_OP0(repnz, 0xf2) + + DEF_ASM_OP0(invd, 0x0f08) + DEF_ASM_OP0(wbinvd, 0x0f09) + DEF_ASM_OP0(cpuid, 0x0fa2) + DEF_ASM_OP0(wrmsr, 0x0f30) + DEF_ASM_OP0(rdtsc, 0x0f31) + DEF_ASM_OP0(rdmsr, 0x0f32) + DEF_ASM_OP0(rdpmc, 0x0f33) + + DEF_ASM_OP0(syscall, 0x0f05) + DEF_ASM_OP0(sysret, 0x0f07) + DEF_ASM_OP0L(sysretq, 0x480f07, 0, 0) + DEF_ASM_OP0(ud2, 0x0f0b) + + /* NOTE: we took the same order as gas opcode definition order */ +/* Right now we can't express the fact that 0xa1/0xa3 can't use $eax and a + 32 bit moffset as operands. +ALT(DEF_ASM_OP2(movb, 0xa0, 0, OPC_BWLX, OPT_ADDR, OPT_EAX)) +ALT(DEF_ASM_OP2(movb, 0xa2, 0, OPC_BWLX, OPT_EAX, OPT_ADDR)) */ +ALT(DEF_ASM_OP2(movb, 0x88, 0, OPC_MODRM | OPC_BWLX, OPT_REG, OPT_EA | OPT_REG)) +ALT(DEF_ASM_OP2(movb, 0x8a, 0, OPC_MODRM | OPC_BWLX, OPT_EA | OPT_REG, OPT_REG)) +/* The moves are special: the 0xb8 form supports IM64 (the only insn that + does) with REG64. It doesn't support IM32 with REG64, it would use + the full movabs form (64bit immediate). For IM32->REG64 we prefer + the 0xc7 opcode. So disallow all 64bit forms and code the rest by hand. */ +ALT(DEF_ASM_OP2(movb, 0xb0, 0, OPC_REG | OPC_BWLX, OPT_IM, OPT_REG)) +ALT(DEF_ASM_OP2(mov, 0xb8, 0, OPC_REG, OPT_IM64, OPT_REG64)) +ALT(DEF_ASM_OP2(movq, 0xb8, 0, OPC_REG, OPT_IM64, OPT_REG64)) +ALT(DEF_ASM_OP2(movb, 0xc6, 0, OPC_MODRM | OPC_BWLX, OPT_IM, OPT_REG | OPT_EA)) + +ALT(DEF_ASM_OP2(movw, 0x8c, 0, OPC_MODRM | OPC_WLX, OPT_SEG, OPT_EA | OPT_REG)) +ALT(DEF_ASM_OP2(movw, 0x8e, 0, OPC_MODRM | OPC_WLX, OPT_EA | OPT_REG, OPT_SEG)) + +ALT(DEF_ASM_OP2(movw, 0x0f20, 0, OPC_MODRM | OPC_WLX, OPT_CR, OPT_REG64)) +ALT(DEF_ASM_OP2(movw, 0x0f21, 0, OPC_MODRM | OPC_WLX, OPT_DB, OPT_REG64)) +ALT(DEF_ASM_OP2(movw, 0x0f22, 0, OPC_MODRM | OPC_WLX, OPT_REG64, OPT_CR)) +ALT(DEF_ASM_OP2(movw, 0x0f23, 0, OPC_MODRM | OPC_WLX, OPT_REG64, OPT_DB)) + +ALT(DEF_ASM_OP2(movsbw, 0x660fbe, 0, OPC_MODRM, OPT_REG8 | OPT_EA, OPT_REG16)) +ALT(DEF_ASM_OP2(movsbl, 0x0fbe, 0, OPC_MODRM, OPT_REG8 | OPT_EA, OPT_REG32)) +ALT(DEF_ASM_OP2(movsbq, 0x0fbe, 0, OPC_MODRM, OPT_REG8 | OPT_EA, OPT_REGW)) +ALT(DEF_ASM_OP2(movswl, 0x0fbf, 0, OPC_MODRM, OPT_REG16 | OPT_EA, OPT_REG32)) +ALT(DEF_ASM_OP2(movswq, 0x0fbf, 0, OPC_MODRM, OPT_REG16 | OPT_EA, OPT_REG)) +ALT(DEF_ASM_OP2(movslq, 0x63, 0, OPC_MODRM, OPT_REG32 | OPT_EA, OPT_REG)) +ALT(DEF_ASM_OP2(movzbw, 0x0fb6, 0, OPC_MODRM | OPC_WLX, OPT_REG8 | OPT_EA, OPT_REGW)) +ALT(DEF_ASM_OP2(movzwl, 0x0fb7, 0, OPC_MODRM, OPT_REG16 | OPT_EA, OPT_REG32)) +ALT(DEF_ASM_OP2(movzwq, 0x0fb7, 0, OPC_MODRM, OPT_REG16 | OPT_EA, OPT_REG)) + +ALT(DEF_ASM_OP1(pushq, 0x6a, 0, 0, OPT_IM8S)) +ALT(DEF_ASM_OP1(push, 0x6a, 0, 0, OPT_IM8S)) +ALT(DEF_ASM_OP1(pushw, 0x666a, 0, 0, OPT_IM8S)) +ALT(DEF_ASM_OP1(pushw, 0x50, 0, OPC_REG | OPC_WLX, OPT_REG64)) +ALT(DEF_ASM_OP1(pushw, 0x50, 0, OPC_REG | OPC_WLX, OPT_REG16)) +ALT(DEF_ASM_OP1(pushw, 0xff, 6, OPC_MODRM | OPC_WLX, OPT_REG64 | OPT_EA)) +ALT(DEF_ASM_OP1(pushw, 0x6668, 0, 0, OPT_IM16)) +ALT(DEF_ASM_OP1(pushw, 0x68, 0, OPC_WLX, OPT_IM32)) +ALT(DEF_ASM_OP1(pushw, 0x06, 0, OPC_WLX, OPT_SEG)) + +ALT(DEF_ASM_OP1(popw, 0x58, 0, OPC_REG | OPC_WLX, OPT_REG64)) +ALT(DEF_ASM_OP1(popw, 0x58, 0, OPC_REG | OPC_WLX, OPT_REG16)) +ALT(DEF_ASM_OP1(popw, 0x8f, 0, OPC_MODRM | OPC_WLX, OPT_REGW | OPT_EA)) +ALT(DEF_ASM_OP1(popw, 0x07, 0, OPC_WLX, OPT_SEG)) + +ALT(DEF_ASM_OP2(xchgw, 0x90, 0, OPC_REG | OPC_WLX, OPT_REGW, OPT_EAX)) +ALT(DEF_ASM_OP2(xchgw, 0x90, 0, OPC_REG | OPC_WLX, OPT_EAX, OPT_REGW)) +ALT(DEF_ASM_OP2(xchgb, 0x86, 0, OPC_MODRM | OPC_BWLX, OPT_REG, OPT_EA | OPT_REG)) +ALT(DEF_ASM_OP2(xchgb, 0x86, 0, OPC_MODRM | OPC_BWLX, OPT_EA | OPT_REG, OPT_REG)) + +ALT(DEF_ASM_OP2(inb, 0xe4, 0, OPC_BWL, OPT_IM8, OPT_EAX)) +ALT(DEF_ASM_OP1(inb, 0xe4, 0, OPC_BWL, OPT_IM8)) +ALT(DEF_ASM_OP2(inb, 0xec, 0, OPC_BWL, OPT_DX, OPT_EAX)) +ALT(DEF_ASM_OP1(inb, 0xec, 0, OPC_BWL, OPT_DX)) + +ALT(DEF_ASM_OP2(outb, 0xe6, 0, OPC_BWL, OPT_EAX, OPT_IM8)) +ALT(DEF_ASM_OP1(outb, 0xe6, 0, OPC_BWL, OPT_IM8)) +ALT(DEF_ASM_OP2(outb, 0xee, 0, OPC_BWL, OPT_EAX, OPT_DX)) +ALT(DEF_ASM_OP1(outb, 0xee, 0, OPC_BWL, OPT_DX)) + +ALT(DEF_ASM_OP2(leaw, 0x8d, 0, OPC_MODRM | OPC_WLX, OPT_EA, OPT_REG)) + +ALT(DEF_ASM_OP2(les, 0xc4, 0, OPC_MODRM, OPT_EA, OPT_REG32)) +ALT(DEF_ASM_OP2(lds, 0xc5, 0, OPC_MODRM, OPT_EA, OPT_REG32)) +ALT(DEF_ASM_OP2(lss, 0x0fb2, 0, OPC_MODRM, OPT_EA, OPT_REG32)) +ALT(DEF_ASM_OP2(lfs, 0x0fb4, 0, OPC_MODRM, OPT_EA, OPT_REG32)) +ALT(DEF_ASM_OP2(lgs, 0x0fb5, 0, OPC_MODRM, OPT_EA, OPT_REG32)) + + /* arith */ +ALT(DEF_ASM_OP2(addb, 0x00, 0, OPC_ARITH | OPC_MODRM | OPC_BWLX, OPT_REG, OPT_EA | OPT_REG)) /* XXX: use D bit ? */ +ALT(DEF_ASM_OP2(addb, 0x02, 0, OPC_ARITH | OPC_MODRM | OPC_BWLX, OPT_EA | OPT_REG, OPT_REG)) +ALT(DEF_ASM_OP2(addb, 0x04, 0, OPC_ARITH | OPC_BWLX, OPT_IM, OPT_EAX)) +ALT(DEF_ASM_OP2(addw, 0x83, 0, OPC_ARITH | OPC_MODRM | OPC_WLX, OPT_IM8S, OPT_EA | OPT_REGW)) +ALT(DEF_ASM_OP2(addb, 0x80, 0, OPC_ARITH | OPC_MODRM | OPC_BWLX, OPT_IM, OPT_EA | OPT_REG)) + +ALT(DEF_ASM_OP2(testb, 0x84, 0, OPC_MODRM | OPC_BWLX, OPT_REG, OPT_EA | OPT_REG)) +ALT(DEF_ASM_OP2(testb, 0x84, 0, OPC_MODRM | OPC_BWLX, OPT_EA | OPT_REG, OPT_REG)) +ALT(DEF_ASM_OP2(testb, 0xa8, 0, OPC_BWLX, OPT_IM, OPT_EAX)) +ALT(DEF_ASM_OP2(testb, 0xf6, 0, OPC_MODRM | OPC_BWLX, OPT_IM, OPT_EA | OPT_REG)) + +ALT(DEF_ASM_OP1(incb, 0xfe, 0, OPC_MODRM | OPC_BWLX, OPT_REG | OPT_EA)) +ALT(DEF_ASM_OP1(decb, 0xfe, 1, OPC_MODRM | OPC_BWLX, OPT_REG | OPT_EA)) + +ALT(DEF_ASM_OP1(notb, 0xf6, 2, OPC_MODRM | OPC_BWLX, OPT_REG | OPT_EA)) +ALT(DEF_ASM_OP1(negb, 0xf6, 3, OPC_MODRM | OPC_BWLX, OPT_REG | OPT_EA)) + +ALT(DEF_ASM_OP1(mulb, 0xf6, 4, OPC_MODRM | OPC_BWLX, OPT_REG | OPT_EA)) +ALT(DEF_ASM_OP1(imulb, 0xf6, 5, OPC_MODRM | OPC_BWLX, OPT_REG | OPT_EA)) + +ALT(DEF_ASM_OP2(imulw, 0x0faf, 0, OPC_MODRM | OPC_WLX, OPT_REG | OPT_EA, OPT_REG)) +ALT(DEF_ASM_OP3(imulw, 0x6b, 0, OPC_MODRM | OPC_WLX, OPT_IM8S, OPT_REGW | OPT_EA, OPT_REGW)) +ALT(DEF_ASM_OP2(imulw, 0x6b, 0, OPC_MODRM | OPC_WLX, OPT_IM8S, OPT_REGW)) +ALT(DEF_ASM_OP3(imulw, 0x69, 0, OPC_MODRM | OPC_WLX, OPT_IMW, OPT_REGW | OPT_EA, OPT_REGW)) +ALT(DEF_ASM_OP2(imulw, 0x69, 0, OPC_MODRM | OPC_WLX, OPT_IMW, OPT_REGW)) + +ALT(DEF_ASM_OP1(divb, 0xf6, 6, OPC_MODRM | OPC_BWLX, OPT_REG | OPT_EA)) +ALT(DEF_ASM_OP2(divb, 0xf6, 6, OPC_MODRM | OPC_BWLX, OPT_REG | OPT_EA, OPT_EAX)) +ALT(DEF_ASM_OP1(idivb, 0xf6, 7, OPC_MODRM | OPC_BWLX, OPT_REG | OPT_EA)) +ALT(DEF_ASM_OP2(idivb, 0xf6, 7, OPC_MODRM | OPC_BWLX, OPT_REG | OPT_EA, OPT_EAX)) + + /* shifts */ +ALT(DEF_ASM_OP2(rolb, 0xc0, 0, OPC_MODRM | OPC_BWLX | OPC_SHIFT, OPT_IM8, OPT_EA | OPT_REG)) +ALT(DEF_ASM_OP2(rolb, 0xd2, 0, OPC_MODRM | OPC_BWLX | OPC_SHIFT, OPT_CL, OPT_EA | OPT_REG)) +ALT(DEF_ASM_OP1(rolb, 0xd0, 0, OPC_MODRM | OPC_BWLX | OPC_SHIFT, OPT_EA | OPT_REG)) + +ALT(DEF_ASM_OP3(shldw, 0x0fa4, 0, OPC_MODRM | OPC_WLX, OPT_IM8, OPT_REGW, OPT_EA | OPT_REGW)) +ALT(DEF_ASM_OP3(shldw, 0x0fa5, 0, OPC_MODRM | OPC_WLX, OPT_CL, OPT_REGW, OPT_EA | OPT_REGW)) +ALT(DEF_ASM_OP2(shldw, 0x0fa5, 0, OPC_MODRM | OPC_WLX, OPT_REGW, OPT_EA | OPT_REGW)) +ALT(DEF_ASM_OP3(shrdw, 0x0fac, 0, OPC_MODRM | OPC_WLX, OPT_IM8, OPT_REGW, OPT_EA | OPT_REGW)) +ALT(DEF_ASM_OP3(shrdw, 0x0fad, 0, OPC_MODRM | OPC_WLX, OPT_CL, OPT_REGW, OPT_EA | OPT_REGW)) +ALT(DEF_ASM_OP2(shrdw, 0x0fad, 0, OPC_MODRM | OPC_WLX, OPT_REGW, OPT_EA | OPT_REGW)) + +ALT(DEF_ASM_OP1(call, 0xff, 2, OPC_MODRM, OPT_INDIR)) +ALT(DEF_ASM_OP1(call, 0xe8, 0, 0, OPT_DISP)) +ALT(DEF_ASM_OP1(jmp, 0xff, 4, OPC_MODRM, OPT_INDIR)) +ALT(DEF_ASM_OP1(jmp, 0xeb, 0, 0, OPT_DISP8)) + +ALT(DEF_ASM_OP1(lcall, 0xff, 3, OPC_MODRM, OPT_EA)) +ALT(DEF_ASM_OP1(ljmp, 0xff, 5, OPC_MODRM, OPT_EA)) + DEF_ASM_OP1(ljmpw, 0x66ff, 5, OPC_MODRM, OPT_EA) + DEF_ASM_OP1(ljmpl, 0xff, 5, OPC_MODRM, OPT_EA) + +ALT(DEF_ASM_OP1(int, 0xcd, 0, 0, OPT_IM8)) +ALT(DEF_ASM_OP1(seto, 0x0f90, 0, OPC_MODRM | OPC_TEST, OPT_REG8 | OPT_EA)) +ALT(DEF_ASM_OP1(setob, 0x0f90, 0, OPC_MODRM | OPC_TEST, OPT_REG8 | OPT_EA)) + DEF_ASM_OP2(enter, 0xc8, 0, 0, OPT_IM16, OPT_IM8) + DEF_ASM_OP0(leave, 0xc9) + DEF_ASM_OP0(ret, 0xc3) + DEF_ASM_OP0(retq, 0xc3) +ALT(DEF_ASM_OP1(retq, 0xc2, 0, 0, OPT_IM16)) +ALT(DEF_ASM_OP1(ret, 0xc2, 0, 0, OPT_IM16)) + DEF_ASM_OP0(lret, 0xcb) +ALT(DEF_ASM_OP1(lret, 0xca, 0, 0, OPT_IM16)) + +ALT(DEF_ASM_OP1(jo, 0x70, 0, OPC_TEST, OPT_DISP8)) + DEF_ASM_OP1(loopne, 0xe0, 0, 0, OPT_DISP8) + DEF_ASM_OP1(loopnz, 0xe0, 0, 0, OPT_DISP8) + DEF_ASM_OP1(loope, 0xe1, 0, 0, OPT_DISP8) + DEF_ASM_OP1(loopz, 0xe1, 0, 0, OPT_DISP8) + DEF_ASM_OP1(loop, 0xe2, 0, 0, OPT_DISP8) + DEF_ASM_OP1(jecxz, 0x67e3, 0, 0, OPT_DISP8) + + /* float */ + /* specific fcomp handling */ +ALT(DEF_ASM_OP0L(fcomp, 0xd8d9, 0, 0)) + +ALT(DEF_ASM_OP1(fadd, 0xd8c0, 0, OPC_FARITH | OPC_REG, OPT_ST)) +ALT(DEF_ASM_OP2(fadd, 0xd8c0, 0, OPC_FARITH | OPC_REG, OPT_ST, OPT_ST0)) +ALT(DEF_ASM_OP2(fadd, 0xdcc0, 0, OPC_FARITH | OPC_REG, OPT_ST0, OPT_ST)) +ALT(DEF_ASM_OP2(fmul, 0xdcc8, 0, OPC_FARITH | OPC_REG, OPT_ST0, OPT_ST)) +ALT(DEF_ASM_OP0L(fadd, 0xdec1, 0, OPC_FARITH)) +ALT(DEF_ASM_OP1(faddp, 0xdec0, 0, OPC_FARITH | OPC_REG, OPT_ST)) +ALT(DEF_ASM_OP2(faddp, 0xdec0, 0, OPC_FARITH | OPC_REG, OPT_ST, OPT_ST0)) +ALT(DEF_ASM_OP2(faddp, 0xdec0, 0, OPC_FARITH | OPC_REG, OPT_ST0, OPT_ST)) +ALT(DEF_ASM_OP0L(faddp, 0xdec1, 0, OPC_FARITH)) +ALT(DEF_ASM_OP1(fadds, 0xd8, 0, OPC_FARITH | OPC_MODRM, OPT_EA)) +ALT(DEF_ASM_OP1(fiaddl, 0xda, 0, OPC_FARITH | OPC_MODRM, OPT_EA)) +ALT(DEF_ASM_OP1(faddl, 0xdc, 0, OPC_FARITH | OPC_MODRM, OPT_EA)) +ALT(DEF_ASM_OP1(fiadds, 0xde, 0, OPC_FARITH | OPC_MODRM, OPT_EA)) + + DEF_ASM_OP0(fucompp, 0xdae9) + DEF_ASM_OP0(ftst, 0xd9e4) + DEF_ASM_OP0(fxam, 0xd9e5) + DEF_ASM_OP0(fld1, 0xd9e8) + DEF_ASM_OP0(fldl2t, 0xd9e9) + DEF_ASM_OP0(fldl2e, 0xd9ea) + DEF_ASM_OP0(fldpi, 0xd9eb) + DEF_ASM_OP0(fldlg2, 0xd9ec) + DEF_ASM_OP0(fldln2, 0xd9ed) + DEF_ASM_OP0(fldz, 0xd9ee) + + DEF_ASM_OP0(f2xm1, 0xd9f0) + DEF_ASM_OP0(fyl2x, 0xd9f1) + DEF_ASM_OP0(fptan, 0xd9f2) + DEF_ASM_OP0(fpatan, 0xd9f3) + DEF_ASM_OP0(fxtract, 0xd9f4) + DEF_ASM_OP0(fprem1, 0xd9f5) + DEF_ASM_OP0(fdecstp, 0xd9f6) + DEF_ASM_OP0(fincstp, 0xd9f7) + DEF_ASM_OP0(fprem, 0xd9f8) + DEF_ASM_OP0(fyl2xp1, 0xd9f9) + DEF_ASM_OP0(fsqrt, 0xd9fa) + DEF_ASM_OP0(fsincos, 0xd9fb) + DEF_ASM_OP0(frndint, 0xd9fc) + DEF_ASM_OP0(fscale, 0xd9fd) + DEF_ASM_OP0(fsin, 0xd9fe) + DEF_ASM_OP0(fcos, 0xd9ff) + DEF_ASM_OP0(fchs, 0xd9e0) + DEF_ASM_OP0(fabs, 0xd9e1) + DEF_ASM_OP0(fninit, 0xdbe3) + DEF_ASM_OP0(fnclex, 0xdbe2) + DEF_ASM_OP0(fnop, 0xd9d0) + DEF_ASM_OP0(fwait, 0x9b) + + /* fp load */ + DEF_ASM_OP1(fld, 0xd9c0, 0, OPC_REG, OPT_ST) + DEF_ASM_OP1(fldl, 0xd9c0, 0, OPC_REG, OPT_ST) + DEF_ASM_OP1(flds, 0xd9, 0, OPC_MODRM, OPT_EA) +ALT(DEF_ASM_OP1(fldl, 0xdd, 0, OPC_MODRM, OPT_EA)) + DEF_ASM_OP1(fildl, 0xdb, 0, OPC_MODRM, OPT_EA) + DEF_ASM_OP1(fildq, 0xdf, 5, OPC_MODRM, OPT_EA) + DEF_ASM_OP1(fildll, 0xdf, 5, OPC_MODRM,OPT_EA) + DEF_ASM_OP1(fldt, 0xdb, 5, OPC_MODRM, OPT_EA) + DEF_ASM_OP1(fbld, 0xdf, 4, OPC_MODRM, OPT_EA) + + /* fp store */ + DEF_ASM_OP1(fst, 0xddd0, 0, OPC_REG, OPT_ST) + DEF_ASM_OP1(fstl, 0xddd0, 0, OPC_REG, OPT_ST) + DEF_ASM_OP1(fsts, 0xd9, 2, OPC_MODRM, OPT_EA) + DEF_ASM_OP1(fstps, 0xd9, 3, OPC_MODRM, OPT_EA) +ALT(DEF_ASM_OP1(fstl, 0xdd, 2, OPC_MODRM, OPT_EA)) + DEF_ASM_OP1(fstpl, 0xdd, 3, OPC_MODRM, OPT_EA) + DEF_ASM_OP1(fist, 0xdf, 2, OPC_MODRM, OPT_EA) + DEF_ASM_OP1(fistp, 0xdf, 3, OPC_MODRM, OPT_EA) + DEF_ASM_OP1(fistl, 0xdb, 2, OPC_MODRM, OPT_EA) + DEF_ASM_OP1(fistpl, 0xdb, 3, OPC_MODRM, OPT_EA) + + DEF_ASM_OP1(fstp, 0xddd8, 0, OPC_REG, OPT_ST) + DEF_ASM_OP1(fistpq, 0xdf, 7, OPC_MODRM, OPT_EA) + DEF_ASM_OP1(fistpll, 0xdf, 7, OPC_MODRM, OPT_EA) + DEF_ASM_OP1(fstpt, 0xdb, 7, OPC_MODRM, OPT_EA) + DEF_ASM_OP1(fbstp, 0xdf, 6, OPC_MODRM, OPT_EA) + + /* exchange */ + DEF_ASM_OP0(fxch, 0xd9c9) +ALT(DEF_ASM_OP1(fxch, 0xd9c8, 0, OPC_REG, OPT_ST)) + + /* misc FPU */ + DEF_ASM_OP1(fucom, 0xdde0, 0, OPC_REG, OPT_ST ) + DEF_ASM_OP1(fucomp, 0xdde8, 0, OPC_REG, OPT_ST ) + + DEF_ASM_OP0L(finit, 0xdbe3, 0, OPC_FWAIT) + DEF_ASM_OP1(fldcw, 0xd9, 5, OPC_MODRM, OPT_EA ) + DEF_ASM_OP1(fnstcw, 0xd9, 7, OPC_MODRM, OPT_EA ) + DEF_ASM_OP1(fstcw, 0xd9, 7, OPC_MODRM | OPC_FWAIT, OPT_EA ) + DEF_ASM_OP0(fnstsw, 0xdfe0) +ALT(DEF_ASM_OP1(fnstsw, 0xdfe0, 0, 0, OPT_EAX )) +ALT(DEF_ASM_OP1(fnstsw, 0xdd, 7, OPC_MODRM, OPT_EA )) + DEF_ASM_OP1(fstsw, 0xdfe0, 0, OPC_FWAIT, OPT_EAX ) +ALT(DEF_ASM_OP0L(fstsw, 0xdfe0, 0, OPC_FWAIT)) +ALT(DEF_ASM_OP1(fstsw, 0xdd, 7, OPC_MODRM | OPC_FWAIT, OPT_EA )) + DEF_ASM_OP0L(fclex, 0xdbe2, 0, OPC_FWAIT) + DEF_ASM_OP1(fnstenv, 0xd9, 6, OPC_MODRM, OPT_EA ) + DEF_ASM_OP1(fstenv, 0xd9, 6, OPC_MODRM | OPC_FWAIT, OPT_EA ) + DEF_ASM_OP1(fldenv, 0xd9, 4, OPC_MODRM, OPT_EA ) + DEF_ASM_OP1(fnsave, 0xdd, 6, OPC_MODRM, OPT_EA ) + DEF_ASM_OP1(fsave, 0xdd, 6, OPC_MODRM | OPC_FWAIT, OPT_EA ) + DEF_ASM_OP1(frstor, 0xdd, 4, OPC_MODRM, OPT_EA ) + DEF_ASM_OP1(ffree, 0xddc0, 4, OPC_REG, OPT_ST ) + DEF_ASM_OP1(ffreep, 0xdfc0, 4, OPC_REG, OPT_ST ) + DEF_ASM_OP1(fxsave, 0x0fae, 0, OPC_MODRM, OPT_EA ) + DEF_ASM_OP1(fxrstor, 0x0fae, 1, OPC_MODRM, OPT_EA ) + /* The *q forms of fxrstor/fxsave use a REX prefix. + If the operand would use extended registers we would have to modify + it instead of generating a second one. Currently that's no + problem with TCC, we don't use extended registers. */ + DEF_ASM_OP1(fxsaveq, 0x0fae, 0, OPC_MODRM | OPC_48, OPT_EA ) + DEF_ASM_OP1(fxrstorq, 0x0fae, 1, OPC_MODRM | OPC_48, OPT_EA ) + + /* segments */ + DEF_ASM_OP2(arpl, 0x63, 0, OPC_MODRM, OPT_REG16, OPT_REG16 | OPT_EA) +ALT(DEF_ASM_OP2(larw, 0x0f02, 0, OPC_MODRM | OPC_WLX, OPT_REG | OPT_EA, OPT_REG)) + DEF_ASM_OP1(lgdt, 0x0f01, 2, OPC_MODRM, OPT_EA) + DEF_ASM_OP1(lgdtq, 0x0f01, 2, OPC_MODRM, OPT_EA) + DEF_ASM_OP1(lidt, 0x0f01, 3, OPC_MODRM, OPT_EA) + DEF_ASM_OP1(lidtq, 0x0f01, 3, OPC_MODRM, OPT_EA) + DEF_ASM_OP1(lldt, 0x0f00, 2, OPC_MODRM, OPT_EA | OPT_REG) + DEF_ASM_OP1(lmsw, 0x0f01, 6, OPC_MODRM, OPT_EA | OPT_REG) +ALT(DEF_ASM_OP2(lslw, 0x0f03, 0, OPC_MODRM | OPC_WLX, OPT_EA | OPT_REG, OPT_REG)) + DEF_ASM_OP1(ltr, 0x0f00, 3, OPC_MODRM, OPT_EA | OPT_REG16) + DEF_ASM_OP1(sgdt, 0x0f01, 0, OPC_MODRM, OPT_EA) + DEF_ASM_OP1(sgdtq, 0x0f01, 0, OPC_MODRM, OPT_EA) + DEF_ASM_OP1(sidt, 0x0f01, 1, OPC_MODRM, OPT_EA) + DEF_ASM_OP1(sidtq, 0x0f01, 1, OPC_MODRM, OPT_EA) + DEF_ASM_OP1(sldt, 0x0f00, 0, OPC_MODRM, OPT_REG | OPT_EA) + DEF_ASM_OP1(smsw, 0x0f01, 4, OPC_MODRM, OPT_REG | OPT_EA) + DEF_ASM_OP1(str, 0x0f00, 1, OPC_MODRM, OPT_REG32 | OPT_EA) +ALT(DEF_ASM_OP1(str, 0x660f00, 1, OPC_MODRM, OPT_REG16)) +ALT(DEF_ASM_OP1(str, 0x0f00, 1, OPC_MODRM | OPC_48, OPT_REG64)) + DEF_ASM_OP1(verr, 0x0f00, 4, OPC_MODRM, OPT_REG | OPT_EA) + DEF_ASM_OP1(verw, 0x0f00, 5, OPC_MODRM, OPT_REG | OPT_EA) + DEF_ASM_OP0L(swapgs, 0x0f01, 7, OPC_MODRM) + + /* 486 */ + /* bswap can't be applied to 16bit regs */ + DEF_ASM_OP1(bswap, 0x0fc8, 0, OPC_REG, OPT_REG32 ) + DEF_ASM_OP1(bswapl, 0x0fc8, 0, OPC_REG, OPT_REG32 ) + DEF_ASM_OP1(bswapq, 0x0fc8, 0, OPC_REG | OPC_48, OPT_REG64 ) + +ALT(DEF_ASM_OP2(xaddb, 0x0fc0, 0, OPC_MODRM | OPC_BWLX, OPT_REG, OPT_REG | OPT_EA )) +ALT(DEF_ASM_OP2(cmpxchgb, 0x0fb0, 0, OPC_MODRM | OPC_BWLX, OPT_REG, OPT_REG | OPT_EA )) + DEF_ASM_OP1(invlpg, 0x0f01, 7, OPC_MODRM, OPT_EA ) + + /* pentium */ + DEF_ASM_OP1(cmpxchg8b, 0x0fc7, 1, OPC_MODRM, OPT_EA ) + + /* AMD 64 */ + DEF_ASM_OP1(cmpxchg16b, 0x0fc7, 1, OPC_MODRM | OPC_48, OPT_EA ) + + /* pentium pro */ +ALT(DEF_ASM_OP2(cmovo, 0x0f40, 0, OPC_MODRM | OPC_TEST | OPC_WLX, OPT_REGW | OPT_EA, OPT_REGW)) + + DEF_ASM_OP2(fcmovb, 0xdac0, 0, OPC_REG, OPT_ST, OPT_ST0 ) + DEF_ASM_OP2(fcmove, 0xdac8, 0, OPC_REG, OPT_ST, OPT_ST0 ) + DEF_ASM_OP2(fcmovbe, 0xdad0, 0, OPC_REG, OPT_ST, OPT_ST0 ) + DEF_ASM_OP2(fcmovu, 0xdad8, 0, OPC_REG, OPT_ST, OPT_ST0 ) + DEF_ASM_OP2(fcmovnb, 0xdbc0, 0, OPC_REG, OPT_ST, OPT_ST0 ) + DEF_ASM_OP2(fcmovne, 0xdbc8, 0, OPC_REG, OPT_ST, OPT_ST0 ) + DEF_ASM_OP2(fcmovnbe, 0xdbd0, 0, OPC_REG, OPT_ST, OPT_ST0 ) + DEF_ASM_OP2(fcmovnu, 0xdbd8, 0, OPC_REG, OPT_ST, OPT_ST0 ) + + DEF_ASM_OP2(fucomi, 0xdbe8, 0, OPC_REG, OPT_ST, OPT_ST0 ) + DEF_ASM_OP2(fcomi, 0xdbf0, 0, OPC_REG, OPT_ST, OPT_ST0 ) + DEF_ASM_OP2(fucomip, 0xdfe8, 0, OPC_REG, OPT_ST, OPT_ST0 ) + DEF_ASM_OP2(fcomip, 0xdff0, 0, OPC_REG, OPT_ST, OPT_ST0 ) + + /* mmx */ + DEF_ASM_OP0(emms, 0x0f77) /* must be last OP0 */ + DEF_ASM_OP2(movd, 0x0f6e, 0, OPC_MODRM, OPT_EA | OPT_REG32, OPT_MMXSSE ) + /* movd shouldn't accept REG64, but AMD64 spec uses it for 32 and 64 bit + moves, so let's be compatible. */ +ALT(DEF_ASM_OP2(movd, 0x0f6e, 0, OPC_MODRM, OPT_EA | OPT_REG64, OPT_MMXSSE )) +ALT(DEF_ASM_OP2(movq, 0x0f6e, 0, OPC_MODRM | OPC_48, OPT_REG64, OPT_MMXSSE )) +ALT(DEF_ASM_OP2(movq, 0x0f6f, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )) +ALT(DEF_ASM_OP2(movd, 0x0f7e, 0, OPC_MODRM, OPT_MMXSSE, OPT_EA | OPT_REG32 )) +ALT(DEF_ASM_OP2(movd, 0x0f7e, 0, OPC_MODRM, OPT_MMXSSE, OPT_EA | OPT_REG64 )) +ALT(DEF_ASM_OP2(movq, 0x0f7f, 0, OPC_MODRM, OPT_MMX, OPT_EA | OPT_MMX )) +ALT(DEF_ASM_OP2(movq, 0x660fd6, 0, OPC_MODRM, OPT_SSE, OPT_EA | OPT_SSE )) +ALT(DEF_ASM_OP2(movq, 0xf30f7e, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE )) +ALT(DEF_ASM_OP2(movq, 0x0f7e, 0, OPC_MODRM, OPT_MMXSSE, OPT_EA | OPT_REG64 )) + + DEF_ASM_OP2(packssdw, 0x0f6b, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(packsswb, 0x0f63, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(packuswb, 0x0f67, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(paddb, 0x0ffc, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(paddw, 0x0ffd, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(paddd, 0x0ffe, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(paddsb, 0x0fec, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(paddsw, 0x0fed, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(paddusb, 0x0fdc, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(paddusw, 0x0fdd, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(pand, 0x0fdb, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(pandn, 0x0fdf, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(pcmpeqb, 0x0f74, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(pcmpeqw, 0x0f75, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(pcmpeqd, 0x0f76, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(pcmpgtb, 0x0f64, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(pcmpgtw, 0x0f65, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(pcmpgtd, 0x0f66, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(pmaddwd, 0x0ff5, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(pmulhw, 0x0fe5, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(pmullw, 0x0fd5, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(por, 0x0feb, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(psllw, 0x0ff1, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) +ALT(DEF_ASM_OP2(psllw, 0x0f71, 6, OPC_MODRM, OPT_IM8, OPT_MMXSSE )) + DEF_ASM_OP2(pslld, 0x0ff2, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) +ALT(DEF_ASM_OP2(pslld, 0x0f72, 6, OPC_MODRM, OPT_IM8, OPT_MMXSSE )) + DEF_ASM_OP2(psllq, 0x0ff3, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) +ALT(DEF_ASM_OP2(psllq, 0x0f73, 6, OPC_MODRM, OPT_IM8, OPT_MMXSSE )) + DEF_ASM_OP2(psraw, 0x0fe1, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) +ALT(DEF_ASM_OP2(psraw, 0x0f71, 4, OPC_MODRM, OPT_IM8, OPT_MMXSSE )) + DEF_ASM_OP2(psrad, 0x0fe2, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) +ALT(DEF_ASM_OP2(psrad, 0x0f72, 4, OPC_MODRM, OPT_IM8, OPT_MMXSSE )) + DEF_ASM_OP2(psrlw, 0x0fd1, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) +ALT(DEF_ASM_OP2(psrlw, 0x0f71, 2, OPC_MODRM, OPT_IM8, OPT_MMXSSE )) + DEF_ASM_OP2(psrld, 0x0fd2, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) +ALT(DEF_ASM_OP2(psrld, 0x0f72, 2, OPC_MODRM, OPT_IM8, OPT_MMXSSE )) + DEF_ASM_OP2(psrlq, 0x0fd3, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) +ALT(DEF_ASM_OP2(psrlq, 0x0f73, 2, OPC_MODRM, OPT_IM8, OPT_MMXSSE )) + DEF_ASM_OP2(psubb, 0x0ff8, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(psubw, 0x0ff9, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(psubd, 0x0ffa, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(psubsb, 0x0fe8, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(psubsw, 0x0fe9, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(psubusb, 0x0fd8, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(psubusw, 0x0fd9, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(punpckhbw, 0x0f68, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(punpckhwd, 0x0f69, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(punpckhdq, 0x0f6a, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(punpcklbw, 0x0f60, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(punpcklwd, 0x0f61, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(punpckldq, 0x0f62, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(pxor, 0x0fef, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + + /* sse */ + DEF_ASM_OP2(movups, 0x0f10, 0, OPC_MODRM, OPT_EA | OPT_REG32, OPT_SSE ) +ALT(DEF_ASM_OP2(movups, 0x0f11, 0, OPC_MODRM, OPT_SSE, OPT_EA | OPT_REG32 )) + DEF_ASM_OP2(movaps, 0x0f28, 0, OPC_MODRM, OPT_EA | OPT_REG32, OPT_SSE ) +ALT(DEF_ASM_OP2(movaps, 0x0f29, 0, OPC_MODRM, OPT_SSE, OPT_EA | OPT_REG32 )) + DEF_ASM_OP2(movhps, 0x0f16, 0, OPC_MODRM, OPT_EA | OPT_REG32, OPT_SSE ) +ALT(DEF_ASM_OP2(movhps, 0x0f17, 0, OPC_MODRM, OPT_SSE, OPT_EA | OPT_REG32 )) + DEF_ASM_OP2(addps, 0x0f58, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE ) + DEF_ASM_OP2(cvtpi2ps, 0x0f2a, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_SSE ) + DEF_ASM_OP2(cvtps2pi, 0x0f2d, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_MMX ) + DEF_ASM_OP2(cvttps2pi, 0x0f2c, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_MMX ) + DEF_ASM_OP2(divps, 0x0f5e, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE ) + DEF_ASM_OP2(maxps, 0x0f5f, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE ) + DEF_ASM_OP2(minps, 0x0f5d, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE ) + DEF_ASM_OP2(mulps, 0x0f59, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE ) + DEF_ASM_OP2(pavgb, 0x0fe0, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE ) + DEF_ASM_OP2(pavgw, 0x0fe3, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE ) + DEF_ASM_OP2(pmaxsw, 0x0fee, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(pmaxub, 0x0fde, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(pminsw, 0x0fea, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(pminub, 0x0fda, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(rcpss, 0x0f53, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE ) + DEF_ASM_OP2(rsqrtps, 0x0f52, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE ) + DEF_ASM_OP2(sqrtps, 0x0f51, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE ) + DEF_ASM_OP2(subps, 0x0f5c, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE ) + + DEF_ASM_OP1(prefetchnta, 0x0f18, 0, OPC_MODRM, OPT_EA) + DEF_ASM_OP1(prefetcht0, 0x0f18, 1, OPC_MODRM, OPT_EA) + DEF_ASM_OP1(prefetcht1, 0x0f18, 2, OPC_MODRM, OPT_EA) + DEF_ASM_OP1(prefetcht2, 0x0f18, 3, OPC_MODRM, OPT_EA) + DEF_ASM_OP1(prefetchw, 0x0f0d, 1, OPC_MODRM, OPT_EA) + DEF_ASM_OP0L(lfence, 0x0fae, 5, OPC_MODRM) + DEF_ASM_OP0L(mfence, 0x0fae, 6, OPC_MODRM) + DEF_ASM_OP0L(sfence, 0x0fae, 7, OPC_MODRM) + DEF_ASM_OP1(clflush, 0x0fae, 7, OPC_MODRM, OPT_EA) +#undef ALT +#undef DEF_ASM_OP0 +#undef DEF_ASM_OP0L +#undef DEF_ASM_OP1 +#undef DEF_ASM_OP2 +#undef DEF_ASM_OP3 diff --git a/tinyc/x86_64-gen.c b/tinyc/x86_64-gen.c new file mode 100644 index 000000000..f4d86e1b7 --- /dev/null +++ b/tinyc/x86_64-gen.c @@ -0,0 +1,2229 @@ +/* + * x86-64 code generator for TCC + * + * Copyright (c) 2008 Shinichiro Hamaji + * + * Based on i386-gen.c by Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifdef TARGET_DEFS_ONLY + +/* number of available registers */ +#define NB_REGS 25 +#define NB_ASM_REGS 16 +#define CONFIG_TCC_ASM + +/* a register can belong to several classes. The classes must be + sorted from more general to more precise (see gv2() code which does + assumptions on it). */ +#define RC_INT 0x0001 /* generic integer register */ +#define RC_FLOAT 0x0002 /* generic float register */ +#define RC_RAX 0x0004 +#define RC_RCX 0x0008 +#define RC_RDX 0x0010 +#define RC_ST0 0x0080 /* only for long double */ +#define RC_R8 0x0100 +#define RC_R9 0x0200 +#define RC_R10 0x0400 +#define RC_R11 0x0800 +#define RC_XMM0 0x1000 +#define RC_XMM1 0x2000 +#define RC_XMM2 0x4000 +#define RC_XMM3 0x8000 +#define RC_XMM4 0x10000 +#define RC_XMM5 0x20000 +#define RC_XMM6 0x40000 +#define RC_XMM7 0x80000 +#define RC_IRET RC_RAX /* function return: integer register */ +#define RC_LRET RC_RDX /* function return: second integer register */ +#define RC_FRET RC_XMM0 /* function return: float register */ +#define RC_QRET RC_XMM1 /* function return: second float register */ + +/* pretty names for the registers */ +enum { + TREG_RAX = 0, + TREG_RCX = 1, + TREG_RDX = 2, + TREG_RSP = 4, + TREG_RSI = 6, + TREG_RDI = 7, + + TREG_R8 = 8, + TREG_R9 = 9, + TREG_R10 = 10, + TREG_R11 = 11, + + TREG_XMM0 = 16, + TREG_XMM1 = 17, + TREG_XMM2 = 18, + TREG_XMM3 = 19, + TREG_XMM4 = 20, + TREG_XMM5 = 21, + TREG_XMM6 = 22, + TREG_XMM7 = 23, + + TREG_ST0 = 24, + + TREG_MEM = 0x20 +}; + +#define REX_BASE(reg) (((reg) >> 3) & 1) +#define REG_VALUE(reg) ((reg) & 7) + +/* return registers for function */ +#define REG_IRET TREG_RAX /* single word int return register */ +#define REG_LRET TREG_RDX /* second word return register (for long long) */ +#define REG_FRET TREG_XMM0 /* float return register */ +#define REG_QRET TREG_XMM1 /* second float return register */ + +/* defined if function parameters must be evaluated in reverse order */ +#define INVERT_FUNC_PARAMS + +/* pointer size, in bytes */ +#define PTR_SIZE 8 + +/* long double size and alignment, in bytes */ +#define LDOUBLE_SIZE 16 +#define LDOUBLE_ALIGN 16 +/* maximum alignment (for aligned attribute support) */ +#define MAX_ALIGN 16 + +/******************************************************/ +#else /* ! TARGET_DEFS_ONLY */ +/******************************************************/ +#include "tcc.h" +#include + +ST_DATA const int reg_classes[NB_REGS] = { + /* eax */ RC_INT | RC_RAX, + /* ecx */ RC_INT | RC_RCX, + /* edx */ RC_INT | RC_RDX, + 0, + 0, + 0, + 0, + 0, + RC_R8, + RC_R9, + RC_R10, + RC_R11, + 0, + 0, + 0, + 0, + /* xmm0 */ RC_FLOAT | RC_XMM0, + /* xmm1 */ RC_FLOAT | RC_XMM1, + /* xmm2 */ RC_FLOAT | RC_XMM2, + /* xmm3 */ RC_FLOAT | RC_XMM3, + /* xmm4 */ RC_FLOAT | RC_XMM4, + /* xmm5 */ RC_FLOAT | RC_XMM5, + /* xmm6 an xmm7 are included so gv() can be used on them, + but they are not tagged with RC_FLOAT because they are + callee saved on Windows */ + RC_XMM6, + RC_XMM7, + /* st0 */ RC_ST0 +}; + +static unsigned long func_sub_sp_offset; +static int func_ret_sub; + +/* XXX: make it faster ? */ +ST_FUNC void g(int c) +{ + int ind1; + if (nocode_wanted) + return; + ind1 = ind + 1; + if (ind1 > cur_text_section->data_allocated) + section_realloc(cur_text_section, ind1); + cur_text_section->data[ind] = c; + ind = ind1; +} + +ST_FUNC void o(unsigned int c) +{ + while (c) { + g(c); + c = c >> 8; + } +} + +ST_FUNC void gen_le16(int v) +{ + g(v); + g(v >> 8); +} + +ST_FUNC void gen_le32(int c) +{ + g(c); + g(c >> 8); + g(c >> 16); + g(c >> 24); +} + +ST_FUNC void gen_le64(int64_t c) +{ + g(c); + g(c >> 8); + g(c >> 16); + g(c >> 24); + g(c >> 32); + g(c >> 40); + g(c >> 48); + g(c >> 56); +} + +static void orex(int ll, int r, int r2, int b) +{ + if ((r & VT_VALMASK) >= VT_CONST) + r = 0; + if ((r2 & VT_VALMASK) >= VT_CONST) + r2 = 0; + if (ll || REX_BASE(r) || REX_BASE(r2)) + o(0x40 | REX_BASE(r) | (REX_BASE(r2) << 2) | (ll << 3)); + o(b); +} + +/* output a symbol and patch all calls to it */ +ST_FUNC void gsym_addr(int t, int a) +{ + while (t) { + unsigned char *ptr = cur_text_section->data + t; + uint32_t n = read32le(ptr); /* next value */ + write32le(ptr, a - t - 4); + t = n; + } +} + +void gsym(int t) +{ + gsym_addr(t, ind); +} + + +static int is64_type(int t) +{ + return ((t & VT_BTYPE) == VT_PTR || + (t & VT_BTYPE) == VT_FUNC || + (t & VT_BTYPE) == VT_LLONG); +} + +/* instruction + 4 bytes data. Return the address of the data */ +static int oad(int c, int s) +{ + int t; + if (nocode_wanted) + return s; + o(c); + t = ind; + gen_le32(s); + return t; +} + +/* generate jmp to a label */ +#define gjmp2(instr,lbl) oad(instr,lbl) + +ST_FUNC void gen_addr32(int r, Sym *sym, int c) +{ + if (r & VT_SYM) + greloca(cur_text_section, sym, ind, R_X86_64_32S, c), c=0; + gen_le32(c); +} + +/* output constant with relocation if 'r & VT_SYM' is true */ +ST_FUNC void gen_addr64(int r, Sym *sym, int64_t c) +{ + if (r & VT_SYM) + greloca(cur_text_section, sym, ind, R_X86_64_64, c), c=0; + gen_le64(c); +} + +/* output constant with relocation if 'r & VT_SYM' is true */ +ST_FUNC void gen_addrpc32(int r, Sym *sym, int c) +{ + greloca(cur_text_section, sym, ind, R_X86_64_PC32, 0); + gen_le32(c-4); +} + +/* output got address with relocation */ +static void gen_gotpcrel(int r, Sym *sym, int c) +{ +#ifdef TCC_TARGET_PE + tcc_error("internal error: no GOT on PE: %s %x %x | %02x %02x %02x\n", + get_tok_str(sym->v, NULL), c, r, + cur_text_section->data[ind-3], + cur_text_section->data[ind-2], + cur_text_section->data[ind-1] + ); +#endif + greloca(cur_text_section, sym, ind, R_X86_64_GOTPCREL, -4); + gen_le32(0); + if (c) { + /* we use add c, %xxx for displacement */ + orex(1, r, 0, 0x81); + o(0xc0 + REG_VALUE(r)); + gen_le32(c); + } +} + +static void gen_modrm_impl(int op_reg, int r, Sym *sym, int c, int is_got) +{ + op_reg = REG_VALUE(op_reg) << 3; + if ((r & VT_VALMASK) == VT_CONST) { + /* constant memory reference */ + o(0x05 | op_reg); + if (is_got) { + gen_gotpcrel(r, sym, c); + } else { + gen_addrpc32(r, sym, c); + } + } else if ((r & VT_VALMASK) == VT_LOCAL) { + /* currently, we use only ebp as base */ + if (c == (char)c) { + /* short reference */ + o(0x45 | op_reg); + g(c); + } else { + oad(0x85 | op_reg, c); + } + } else if ((r & VT_VALMASK) >= TREG_MEM) { + if (c) { + g(0x80 | op_reg | REG_VALUE(r)); + gen_le32(c); + } else { + g(0x00 | op_reg | REG_VALUE(r)); + } + } else { + g(0x00 | op_reg | REG_VALUE(r)); + } +} + +/* generate a modrm reference. 'op_reg' contains the additional 3 + opcode bits */ +static void gen_modrm(int op_reg, int r, Sym *sym, int c) +{ + gen_modrm_impl(op_reg, r, sym, c, 0); +} + +/* generate a modrm reference. 'op_reg' contains the additional 3 + opcode bits */ +static void gen_modrm64(int opcode, int op_reg, int r, Sym *sym, int c) +{ + int is_got; + is_got = (op_reg & TREG_MEM) && !(sym->type.t & VT_STATIC); + orex(1, r, op_reg, opcode); + gen_modrm_impl(op_reg, r, sym, c, is_got); +} + + +/* load 'r' from value 'sv' */ +void load(int r, SValue *sv) +{ + int v, t, ft, fc, fr; + SValue v1; + +#ifdef TCC_TARGET_PE + SValue v2; + sv = pe_getimport(sv, &v2); +#endif + + fr = sv->r; + ft = sv->type.t & ~VT_DEFSIGN; + fc = sv->c.i; + if (fc != sv->c.i && (fr & VT_SYM)) + tcc_error("64 bit addend in load"); + + ft &= ~(VT_VOLATILE | VT_CONSTANT); + +#ifndef TCC_TARGET_PE + /* we use indirect access via got */ + if ((fr & VT_VALMASK) == VT_CONST && (fr & VT_SYM) && + (fr & VT_LVAL) && !(sv->sym->type.t & VT_STATIC)) { + /* use the result register as a temporal register */ + int tr = r | TREG_MEM; + if (is_float(ft)) { + /* we cannot use float registers as a temporal register */ + tr = get_reg(RC_INT) | TREG_MEM; + } + gen_modrm64(0x8b, tr, fr, sv->sym, 0); + + /* load from the temporal register */ + fr = tr | VT_LVAL; + } +#endif + + v = fr & VT_VALMASK; + if (fr & VT_LVAL) { + int b, ll; + if (v == VT_LLOCAL) { + v1.type.t = VT_PTR; + v1.r = VT_LOCAL | VT_LVAL; + v1.c.i = fc; + fr = r; + if (!(reg_classes[fr] & (RC_INT|RC_R11))) + fr = get_reg(RC_INT); + load(fr, &v1); + } + ll = 0; + /* Like GCC we can load from small enough properly sized + structs and unions as well. + XXX maybe move to generic operand handling, but should + occur only with asm, so tccasm.c might also be a better place */ + if ((ft & VT_BTYPE) == VT_STRUCT) { + int align; + switch (type_size(&sv->type, &align)) { + case 1: ft = VT_BYTE; break; + case 2: ft = VT_SHORT; break; + case 4: ft = VT_INT; break; + case 8: ft = VT_LLONG; break; + default: + tcc_error("invalid aggregate type for register load"); + break; + } + } + if ((ft & VT_BTYPE) == VT_FLOAT) { + b = 0x6e0f66; + r = REG_VALUE(r); /* movd */ + } else if ((ft & VT_BTYPE) == VT_DOUBLE) { + b = 0x7e0ff3; /* movq */ + r = REG_VALUE(r); + } else if ((ft & VT_BTYPE) == VT_LDOUBLE) { + b = 0xdb, r = 5; /* fldt */ + } else if ((ft & VT_TYPE) == VT_BYTE || (ft & VT_TYPE) == VT_BOOL) { + b = 0xbe0f; /* movsbl */ + } else if ((ft & VT_TYPE) == (VT_BYTE | VT_UNSIGNED)) { + b = 0xb60f; /* movzbl */ + } else if ((ft & VT_TYPE) == VT_SHORT) { + b = 0xbf0f; /* movswl */ + } else if ((ft & VT_TYPE) == (VT_SHORT | VT_UNSIGNED)) { + b = 0xb70f; /* movzwl */ + } else { + assert(((ft & VT_BTYPE) == VT_INT) + || ((ft & VT_BTYPE) == VT_LLONG) + || ((ft & VT_BTYPE) == VT_PTR) + || ((ft & VT_BTYPE) == VT_FUNC) + ); + ll = is64_type(ft); + b = 0x8b; + } + if (ll) { + gen_modrm64(b, r, fr, sv->sym, fc); + } else { + orex(ll, fr, r, b); + gen_modrm(r, fr, sv->sym, fc); + } + } else { + if (v == VT_CONST) { + if (fr & VT_SYM) { +#ifdef TCC_TARGET_PE + orex(1,0,r,0x8d); + o(0x05 + REG_VALUE(r) * 8); /* lea xx(%rip), r */ + gen_addrpc32(fr, sv->sym, fc); +#else + if (sv->sym->type.t & VT_STATIC) { + orex(1,0,r,0x8d); + o(0x05 + REG_VALUE(r) * 8); /* lea xx(%rip), r */ + gen_addrpc32(fr, sv->sym, fc); + } else { + orex(1,0,r,0x8b); + o(0x05 + REG_VALUE(r) * 8); /* mov xx(%rip), r */ + gen_gotpcrel(r, sv->sym, fc); + } +#endif + } else if (is64_type(ft)) { + orex(1,r,0, 0xb8 + REG_VALUE(r)); /* mov $xx, r */ + gen_le64(sv->c.i); + } else { + orex(0,r,0, 0xb8 + REG_VALUE(r)); /* mov $xx, r */ + gen_le32(fc); + } + } else if (v == VT_LOCAL) { + orex(1,0,r,0x8d); /* lea xxx(%ebp), r */ + gen_modrm(r, VT_LOCAL, sv->sym, fc); + } else if (v == VT_CMP) { + orex(0,r,0,0); + if ((fc & ~0x100) != TOK_NE) + oad(0xb8 + REG_VALUE(r), 0); /* mov $0, r */ + else + oad(0xb8 + REG_VALUE(r), 1); /* mov $1, r */ + if (fc & 0x100) + { + /* This was a float compare. If the parity bit is + set the result was unordered, meaning false for everything + except TOK_NE, and true for TOK_NE. */ + fc &= ~0x100; + o(0x037a + (REX_BASE(r) << 8)); + } + orex(0,r,0, 0x0f); /* setxx %br */ + o(fc); + o(0xc0 + REG_VALUE(r)); + } else if (v == VT_JMP || v == VT_JMPI) { + t = v & 1; + orex(0,r,0,0); + oad(0xb8 + REG_VALUE(r), t); /* mov $1, r */ + o(0x05eb + (REX_BASE(r) << 8)); /* jmp after */ + gsym(fc); + orex(0,r,0,0); + oad(0xb8 + REG_VALUE(r), t ^ 1); /* mov $0, r */ + } else if (v != r) { + if ((r >= TREG_XMM0) && (r <= TREG_XMM7)) { + if (v == TREG_ST0) { + /* gen_cvt_ftof(VT_DOUBLE); */ + o(0xf0245cdd); /* fstpl -0x10(%rsp) */ + /* movsd -0x10(%rsp),%xmmN */ + o(0x100ff2); + o(0x44 + REG_VALUE(r)*8); /* %xmmN */ + o(0xf024); + } else { + assert((v >= TREG_XMM0) && (v <= TREG_XMM7)); + if ((ft & VT_BTYPE) == VT_FLOAT) { + o(0x100ff3); + } else { + assert((ft & VT_BTYPE) == VT_DOUBLE); + o(0x100ff2); + } + o(0xc0 + REG_VALUE(v) + REG_VALUE(r)*8); + } + } else if (r == TREG_ST0) { + assert((v >= TREG_XMM0) && (v <= TREG_XMM7)); + /* gen_cvt_ftof(VT_LDOUBLE); */ + /* movsd %xmmN,-0x10(%rsp) */ + o(0x110ff2); + o(0x44 + REG_VALUE(r)*8); /* %xmmN */ + o(0xf024); + o(0xf02444dd); /* fldl -0x10(%rsp) */ + } else { + orex(1,r,v, 0x89); + o(0xc0 + REG_VALUE(r) + REG_VALUE(v) * 8); /* mov v, r */ + } + } + } +} + +/* store register 'r' in lvalue 'v' */ +void store(int r, SValue *v) +{ + int fr, bt, ft, fc; + int op64 = 0; + /* store the REX prefix in this variable when PIC is enabled */ + int pic = 0; + +#ifdef TCC_TARGET_PE + SValue v2; + v = pe_getimport(v, &v2); +#endif + + fr = v->r & VT_VALMASK; + ft = v->type.t; + fc = v->c.i; + if (fc != v->c.i && (fr & VT_SYM)) + tcc_error("64 bit addend in store"); + ft &= ~(VT_VOLATILE | VT_CONSTANT); + bt = ft & VT_BTYPE; + +#ifndef TCC_TARGET_PE + /* we need to access the variable via got */ + if (fr == VT_CONST && (v->r & VT_SYM)) { + /* mov xx(%rip), %r11 */ + o(0x1d8b4c); + gen_gotpcrel(TREG_R11, v->sym, v->c.i); + pic = is64_type(bt) ? 0x49 : 0x41; + } +#endif + + /* XXX: incorrect if float reg to reg */ + if (bt == VT_FLOAT) { + o(0x66); + o(pic); + o(0x7e0f); /* movd */ + r = REG_VALUE(r); + } else if (bt == VT_DOUBLE) { + o(0x66); + o(pic); + o(0xd60f); /* movq */ + r = REG_VALUE(r); + } else if (bt == VT_LDOUBLE) { + o(0xc0d9); /* fld %st(0) */ + o(pic); + o(0xdb); /* fstpt */ + r = 7; + } else { + if (bt == VT_SHORT) + o(0x66); + o(pic); + if (bt == VT_BYTE || bt == VT_BOOL) + orex(0, 0, r, 0x88); + else if (is64_type(bt)) + op64 = 0x89; + else + orex(0, 0, r, 0x89); + } + if (pic) { + /* xxx r, (%r11) where xxx is mov, movq, fld, or etc */ + if (op64) + o(op64); + o(3 + (r << 3)); + } else if (op64) { + if (fr == VT_CONST || fr == VT_LOCAL || (v->r & VT_LVAL)) { + gen_modrm64(op64, r, v->r, v->sym, fc); + } else if (fr != r) { + /* XXX: don't we really come here? */ + abort(); + o(0xc0 + fr + r * 8); /* mov r, fr */ + } + } else { + if (fr == VT_CONST || fr == VT_LOCAL || (v->r & VT_LVAL)) { + gen_modrm(r, v->r, v->sym, fc); + } else if (fr != r) { + /* XXX: don't we really come here? */ + abort(); + o(0xc0 + fr + r * 8); /* mov r, fr */ + } + } +} + +/* 'is_jmp' is '1' if it is a jump */ +static void gcall_or_jmp(int is_jmp) +{ + int r; + if ((vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST && + ((vtop->r & VT_SYM) || (vtop->c.i-4) == (int)(vtop->c.i-4))) { + /* constant case */ + if (vtop->r & VT_SYM) { + /* relocation case */ +#ifdef TCC_TARGET_PE + greloca(cur_text_section, vtop->sym, ind + 1, R_X86_64_PC32, (int)(vtop->c.i-4)); +#else + greloca(cur_text_section, vtop->sym, ind + 1, R_X86_64_PLT32, (int)(vtop->c.i-4)); +#endif + } else { + /* put an empty PC32 relocation */ + put_elf_reloca(symtab_section, cur_text_section, + ind + 1, R_X86_64_PC32, 0, (int)(vtop->c.i-4)); + } + oad(0xe8 + is_jmp, 0); /* call/jmp im */ + } else { + /* otherwise, indirect call */ + r = TREG_R11; + load(r, vtop); + o(0x41); /* REX */ + o(0xff); /* call/jmp *r */ + o(0xd0 + REG_VALUE(r) + (is_jmp << 4)); + } +} + +#if defined(CONFIG_TCC_BCHECK) +#ifndef TCC_TARGET_PE +static addr_t func_bound_offset; +static unsigned long func_bound_ind; +#endif + +static void gen_static_call(int v) +{ + Sym *sym = external_global_sym(v, &func_old_type, 0); + oad(0xe8, 0); + greloca(cur_text_section, sym, ind-4, R_X86_64_PC32, -4); +} + +/* generate a bounded pointer addition */ +ST_FUNC void gen_bounded_ptr_add(void) +{ + /* save all temporary registers */ + save_regs(0); + + /* prepare fast x86_64 function call */ + gv(RC_RAX); + o(0xc68948); // mov %rax,%rsi ## second arg in %rsi, this must be size + vtop--; + + gv(RC_RAX); + o(0xc78948); // mov %rax,%rdi ## first arg in %rdi, this must be ptr + vtop--; + + /* do a fast function call */ + gen_static_call(TOK___bound_ptr_add); + + /* returned pointer is in rax */ + vtop++; + vtop->r = TREG_RAX | VT_BOUNDED; + + + /* relocation offset of the bounding function call point */ + vtop->c.i = (cur_text_section->reloc->data_offset - sizeof(ElfW(Rela))); +} + +/* patch pointer addition in vtop so that pointer dereferencing is + also tested */ +ST_FUNC void gen_bounded_ptr_deref(void) +{ + addr_t func; + int size, align; + ElfW(Rela) *rel; + Sym *sym; + + size = 0; + /* XXX: put that code in generic part of tcc */ + if (!is_float(vtop->type.t)) { + if (vtop->r & VT_LVAL_BYTE) + size = 1; + else if (vtop->r & VT_LVAL_SHORT) + size = 2; + } + if (!size) + size = type_size(&vtop->type, &align); + switch(size) { + case 1: func = TOK___bound_ptr_indir1; break; + case 2: func = TOK___bound_ptr_indir2; break; + case 4: func = TOK___bound_ptr_indir4; break; + case 8: func = TOK___bound_ptr_indir8; break; + case 12: func = TOK___bound_ptr_indir12; break; + case 16: func = TOK___bound_ptr_indir16; break; + default: + tcc_error("unhandled size when dereferencing bounded pointer"); + func = 0; + break; + } + + sym = external_global_sym(func, &func_old_type, 0); + if (!sym->c) + put_extern_sym(sym, NULL, 0, 0); + + /* patch relocation */ + /* XXX: find a better solution ? */ + + rel = (ElfW(Rela) *)(cur_text_section->reloc->data + vtop->c.i); + rel->r_info = ELF64_R_INFO(sym->c, ELF64_R_TYPE(rel->r_info)); +} +#endif + +#ifdef TCC_TARGET_PE + +#define REGN 4 +static const uint8_t arg_regs[REGN] = { + TREG_RCX, TREG_RDX, TREG_R8, TREG_R9 +}; + +/* Prepare arguments in R10 and R11 rather than RCX and RDX + because gv() will not ever use these */ +static int arg_prepare_reg(int idx) { + if (idx == 0 || idx == 1) + /* idx=0: r10, idx=1: r11 */ + return idx + 10; + else + return arg_regs[idx]; +} + +static int func_scratch, func_alloca; + +/* Generate function call. The function address is pushed first, then + all the parameters in call order. This functions pops all the + parameters and the function address. */ + +static void gen_offs_sp(int b, int r, int d) +{ + orex(1,0,r & 0x100 ? 0 : r, b); + if (d == (char)d) { + o(0x2444 | (REG_VALUE(r) << 3)); + g(d); + } else { + o(0x2484 | (REG_VALUE(r) << 3)); + gen_le32(d); + } +} + +static int using_regs(int size) +{ + return !(size > 8 || (size & (size - 1))); +} + +/* Return the number of registers needed to return the struct, or 0 if + returning via struct pointer. */ +ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *ret_align, int *regsize) +{ + int size, align; + *ret_align = 1; // Never have to re-align return values for x86-64 + *regsize = 8; + size = type_size(vt, &align); + if (!using_regs(size)) + return 0; + if (size == 8) + ret->t = VT_LLONG; + else if (size == 4) + ret->t = VT_INT; + else if (size == 2) + ret->t = VT_SHORT; + else + ret->t = VT_BYTE; + ret->ref = NULL; + return 1; +} + +static int is_sse_float(int t) { + int bt; + bt = t & VT_BTYPE; + return bt == VT_DOUBLE || bt == VT_FLOAT; +} + +static int gfunc_arg_size(CType *type) { + int align; + if (type->t & (VT_ARRAY|VT_BITFIELD)) + return 8; + return type_size(type, &align); +} + +void gfunc_call(int nb_args) +{ + int size, r, args_size, i, d, bt, struct_size; + int arg; + + args_size = (nb_args < REGN ? REGN : nb_args) * PTR_SIZE; + arg = nb_args; + + /* for struct arguments, we need to call memcpy and the function + call breaks register passing arguments we are preparing. + So, we process arguments which will be passed by stack first. */ + struct_size = args_size; + for(i = 0; i < nb_args; i++) { + SValue *sv; + + --arg; + sv = &vtop[-i]; + bt = (sv->type.t & VT_BTYPE); + size = gfunc_arg_size(&sv->type); + + if (using_regs(size)) + continue; /* arguments smaller than 8 bytes passed in registers or on stack */ + + if (bt == VT_STRUCT) { + /* align to stack align size */ + size = (size + 15) & ~15; + /* generate structure store */ + r = get_reg(RC_INT); + gen_offs_sp(0x8d, r, struct_size); + struct_size += size; + + /* generate memcpy call */ + vset(&sv->type, r | VT_LVAL, 0); + vpushv(sv); + vstore(); + --vtop; + } else if (bt == VT_LDOUBLE) { + gv(RC_ST0); + gen_offs_sp(0xdb, 0x107, struct_size); + struct_size += 16; + } + } + + if (func_scratch < struct_size) + func_scratch = struct_size; + + arg = nb_args; + struct_size = args_size; + + for(i = 0; i < nb_args; i++) { + --arg; + bt = (vtop->type.t & VT_BTYPE); + + size = gfunc_arg_size(&vtop->type); + if (!using_regs(size)) { + /* align to stack align size */ + size = (size + 15) & ~15; + if (arg >= REGN) { + d = get_reg(RC_INT); + gen_offs_sp(0x8d, d, struct_size); + gen_offs_sp(0x89, d, arg*8); + } else { + d = arg_prepare_reg(arg); + gen_offs_sp(0x8d, d, struct_size); + } + struct_size += size; + } else { + if (is_sse_float(vtop->type.t)) { + if (tcc_state->nosse) + tcc_error("SSE disabled"); + gv(RC_XMM0); /* only use one float register */ + if (arg >= REGN) { + /* movq %xmm0, j*8(%rsp) */ + gen_offs_sp(0xd60f66, 0x100, arg*8); + } else { + /* movaps %xmm0, %xmmN */ + o(0x280f); + o(0xc0 + (arg << 3)); + d = arg_prepare_reg(arg); + /* mov %xmm0, %rxx */ + o(0x66); + orex(1,d,0, 0x7e0f); + o(0xc0 + REG_VALUE(d)); + } + } else { + if (bt == VT_STRUCT) { + vtop->type.ref = NULL; + vtop->type.t = size > 4 ? VT_LLONG : size > 2 ? VT_INT + : size > 1 ? VT_SHORT : VT_BYTE; + } + + r = gv(RC_INT); + if (arg >= REGN) { + gen_offs_sp(0x89, r, arg*8); + } else { + d = arg_prepare_reg(arg); + orex(1,d,r,0x89); /* mov */ + o(0xc0 + REG_VALUE(r) * 8 + REG_VALUE(d)); + } + } + } + vtop--; + } + save_regs(0); + + /* Copy R10 and R11 into RCX and RDX, respectively */ + if (nb_args > 0) { + o(0xd1894c); /* mov %r10, %rcx */ + if (nb_args > 1) { + o(0xda894c); /* mov %r11, %rdx */ + } + } + + gcall_or_jmp(0); + + if ((vtop->r & VT_SYM) && vtop->sym->v == TOK_alloca) { + /* need to add the "func_scratch" area after alloca */ + o(0x0548), gen_le32(func_alloca), func_alloca = ind - 4; + } + + /* other compilers don't clear the upper bits when returning char/short */ + bt = vtop->type.ref->type.t & (VT_BTYPE | VT_UNSIGNED); + if (bt == (VT_BYTE | VT_UNSIGNED)) + o(0xc0b60f); /* movzbl %al, %eax */ + else if (bt == VT_BYTE) + o(0xc0be0f); /* movsbl %al, %eax */ + else if (bt == VT_SHORT) + o(0x98); /* cwtl */ + else if (bt == (VT_SHORT | VT_UNSIGNED)) + o(0xc0b70f); /* movzbl %al, %eax */ +#if 0 /* handled in gen_cast() */ + else if (bt == VT_INT) + o(0x9848); /* cltq */ + else if (bt == (VT_INT | VT_UNSIGNED)) + o(0xc089); /* mov %eax,%eax */ +#endif + vtop--; +} + + +#define FUNC_PROLOG_SIZE 11 + +/* generate function prolog of type 't' */ +void gfunc_prolog(CType *func_type) +{ + int addr, reg_param_index, bt, size; + Sym *sym; + CType *type; + + func_ret_sub = 0; + func_scratch = 0; + func_alloca = 0; + loc = 0; + + addr = PTR_SIZE * 2; + ind += FUNC_PROLOG_SIZE; + func_sub_sp_offset = ind; + reg_param_index = 0; + + sym = func_type->ref; + + /* if the function returns a structure, then add an + implicit pointer parameter */ + func_vt = sym->type; + func_var = (sym->f.func_type == FUNC_ELLIPSIS); + size = gfunc_arg_size(&func_vt); + if (!using_regs(size)) { + gen_modrm64(0x89, arg_regs[reg_param_index], VT_LOCAL, NULL, addr); + func_vc = addr; + reg_param_index++; + addr += 8; + } + + /* define parameters */ + while ((sym = sym->next) != NULL) { + type = &sym->type; + bt = type->t & VT_BTYPE; + size = gfunc_arg_size(type); + if (!using_regs(size)) { + if (reg_param_index < REGN) { + gen_modrm64(0x89, arg_regs[reg_param_index], VT_LOCAL, NULL, addr); + } + sym_push(sym->v & ~SYM_FIELD, type, VT_LLOCAL | VT_LVAL, addr); + } else { + if (reg_param_index < REGN) { + /* save arguments passed by register */ + if ((bt == VT_FLOAT) || (bt == VT_DOUBLE)) { + if (tcc_state->nosse) + tcc_error("SSE disabled"); + o(0xd60f66); /* movq */ + gen_modrm(reg_param_index, VT_LOCAL, NULL, addr); + } else { + gen_modrm64(0x89, arg_regs[reg_param_index], VT_LOCAL, NULL, addr); + } + } + sym_push(sym->v & ~SYM_FIELD, type, VT_LOCAL | VT_LVAL, addr); + } + addr += 8; + reg_param_index++; + } + + while (reg_param_index < REGN) { + if (func_type->ref->f.func_type == FUNC_ELLIPSIS) { + gen_modrm64(0x89, arg_regs[reg_param_index], VT_LOCAL, NULL, addr); + addr += 8; + } + reg_param_index++; + } +} + +/* generate function epilog */ +void gfunc_epilog(void) +{ + int v, saved_ind; + + o(0xc9); /* leave */ + if (func_ret_sub == 0) { + o(0xc3); /* ret */ + } else { + o(0xc2); /* ret n */ + g(func_ret_sub); + g(func_ret_sub >> 8); + } + + saved_ind = ind; + ind = func_sub_sp_offset - FUNC_PROLOG_SIZE; + /* align local size to word & save local variables */ + v = (func_scratch + -loc + 15) & -16; + + if (v >= 4096) { + Sym *sym = external_global_sym(TOK___chkstk, &func_old_type, 0); + oad(0xb8, v); /* mov stacksize, %eax */ + oad(0xe8, 0); /* call __chkstk, (does the stackframe too) */ + greloca(cur_text_section, sym, ind-4, R_X86_64_PC32, -4); + o(0x90); /* fill for FUNC_PROLOG_SIZE = 11 bytes */ + } else { + o(0xe5894855); /* push %rbp, mov %rsp, %rbp */ + o(0xec8148); /* sub rsp, stacksize */ + gen_le32(v); + } + + /* add the "func_scratch" area after each alloca seen */ + while (func_alloca) { + unsigned char *ptr = cur_text_section->data + func_alloca; + func_alloca = read32le(ptr); + write32le(ptr, func_scratch); + } + + cur_text_section->data_offset = saved_ind; + pe_add_unwind_data(ind, saved_ind, v); + ind = cur_text_section->data_offset; +} + +#else + +static void gadd_sp(int val) +{ + if (val == (char)val) { + o(0xc48348); + g(val); + } else { + oad(0xc48148, val); /* add $xxx, %rsp */ + } +} + +typedef enum X86_64_Mode { + x86_64_mode_none, + x86_64_mode_memory, + x86_64_mode_integer, + x86_64_mode_sse, + x86_64_mode_x87 +} X86_64_Mode; + +static X86_64_Mode classify_x86_64_merge(X86_64_Mode a, X86_64_Mode b) +{ + if (a == b) + return a; + else if (a == x86_64_mode_none) + return b; + else if (b == x86_64_mode_none) + return a; + else if ((a == x86_64_mode_memory) || (b == x86_64_mode_memory)) + return x86_64_mode_memory; + else if ((a == x86_64_mode_integer) || (b == x86_64_mode_integer)) + return x86_64_mode_integer; + else if ((a == x86_64_mode_x87) || (b == x86_64_mode_x87)) + return x86_64_mode_memory; + else + return x86_64_mode_sse; +} + +static X86_64_Mode classify_x86_64_inner(CType *ty) +{ + X86_64_Mode mode; + Sym *f; + + switch (ty->t & VT_BTYPE) { + case VT_VOID: return x86_64_mode_none; + + case VT_INT: + case VT_BYTE: + case VT_SHORT: + case VT_LLONG: + case VT_BOOL: + case VT_PTR: + case VT_FUNC: + return x86_64_mode_integer; + + case VT_FLOAT: + case VT_DOUBLE: return x86_64_mode_sse; + + case VT_LDOUBLE: return x86_64_mode_x87; + + case VT_STRUCT: + f = ty->ref; + + mode = x86_64_mode_none; + for (f = f->next; f; f = f->next) + mode = classify_x86_64_merge(mode, classify_x86_64_inner(&f->type)); + + return mode; + } + assert(0); + return 0; +} + +static X86_64_Mode classify_x86_64_arg(CType *ty, CType *ret, int *psize, int *palign, int *reg_count) +{ + X86_64_Mode mode; + int size, align, ret_t = 0; + + if (ty->t & (VT_BITFIELD|VT_ARRAY)) { + *psize = 8; + *palign = 8; + *reg_count = 1; + ret_t = ty->t; + mode = x86_64_mode_integer; + } else { + size = type_size(ty, &align); + *psize = (size + 7) & ~7; + *palign = (align + 7) & ~7; + + if (size > 16) { + mode = x86_64_mode_memory; + } else { + mode = classify_x86_64_inner(ty); + switch (mode) { + case x86_64_mode_integer: + if (size > 8) { + *reg_count = 2; + ret_t = VT_QLONG; + } else { + *reg_count = 1; + ret_t = (size > 4) ? VT_LLONG : VT_INT; + } + break; + + case x86_64_mode_x87: + *reg_count = 1; + ret_t = VT_LDOUBLE; + break; + + case x86_64_mode_sse: + if (size > 8) { + *reg_count = 2; + ret_t = VT_QFLOAT; + } else { + *reg_count = 1; + ret_t = (size > 4) ? VT_DOUBLE : VT_FLOAT; + } + break; + default: break; /* nothing to be done for x86_64_mode_memory and x86_64_mode_none*/ + } + } + } + + if (ret) { + ret->ref = NULL; + ret->t = ret_t; + } + + return mode; +} + +ST_FUNC int classify_x86_64_va_arg(CType *ty) +{ + /* This definition must be synced with stdarg.h */ + enum __va_arg_type { + __va_gen_reg, __va_float_reg, __va_stack + }; + int size, align, reg_count; + X86_64_Mode mode = classify_x86_64_arg(ty, NULL, &size, &align, ®_count); + switch (mode) { + default: return __va_stack; + case x86_64_mode_integer: return __va_gen_reg; + case x86_64_mode_sse: return __va_float_reg; + } +} + +/* Return the number of registers needed to return the struct, or 0 if + returning via struct pointer. */ +ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *ret_align, int *regsize) +{ + int size, align, reg_count; + *ret_align = 1; // Never have to re-align return values for x86-64 + *regsize = 8; + return (classify_x86_64_arg(vt, ret, &size, &align, ®_count) != x86_64_mode_memory); +} + +#define REGN 6 +static const uint8_t arg_regs[REGN] = { + TREG_RDI, TREG_RSI, TREG_RDX, TREG_RCX, TREG_R8, TREG_R9 +}; + +static int arg_prepare_reg(int idx) { + if (idx == 2 || idx == 3) + /* idx=2: r10, idx=3: r11 */ + return idx + 8; + else + return arg_regs[idx]; +} + +/* Generate function call. The function address is pushed first, then + all the parameters in call order. This functions pops all the + parameters and the function address. */ +void gfunc_call(int nb_args) +{ + X86_64_Mode mode; + CType type; + int size, align, r, args_size, stack_adjust, i, reg_count; + int nb_reg_args = 0; + int nb_sse_args = 0; + int sse_reg, gen_reg; + char _onstack[nb_args], *onstack = _onstack; + + /* calculate the number of integer/float register arguments, remember + arguments to be passed via stack (in onstack[]), and also remember + if we have to align the stack pointer to 16 (onstack[i] == 2). Needs + to be done in a left-to-right pass over arguments. */ + stack_adjust = 0; + for(i = nb_args - 1; i >= 0; i--) { + mode = classify_x86_64_arg(&vtop[-i].type, NULL, &size, &align, ®_count); + if (mode == x86_64_mode_sse && nb_sse_args + reg_count <= 8) { + nb_sse_args += reg_count; + onstack[i] = 0; + } else if (mode == x86_64_mode_integer && nb_reg_args + reg_count <= REGN) { + nb_reg_args += reg_count; + onstack[i] = 0; + } else if (mode == x86_64_mode_none) { + onstack[i] = 0; + } else { + if (align == 16 && (stack_adjust &= 15)) { + onstack[i] = 2; + stack_adjust = 0; + } else + onstack[i] = 1; + stack_adjust += size; + } + } + + if (nb_sse_args && tcc_state->nosse) + tcc_error("SSE disabled but floating point arguments passed"); + + /* fetch cpu flag before generating any code */ + if (vtop >= vstack && (vtop->r & VT_VALMASK) == VT_CMP) + gv(RC_INT); + + /* for struct arguments, we need to call memcpy and the function + call breaks register passing arguments we are preparing. + So, we process arguments which will be passed by stack first. */ + gen_reg = nb_reg_args; + sse_reg = nb_sse_args; + args_size = 0; + stack_adjust &= 15; + for (i = 0; i < nb_args;) { + mode = classify_x86_64_arg(&vtop[-i].type, NULL, &size, &align, ®_count); + if (!onstack[i]) { + ++i; + continue; + } + /* Possibly adjust stack to align SSE boundary. We're processing + args from right to left while allocating happens left to right + (stack grows down), so the adjustment needs to happen _after_ + an argument that requires it. */ + if (stack_adjust) { + o(0x50); /* push %rax; aka sub $8,%rsp */ + args_size += 8; + stack_adjust = 0; + } + if (onstack[i] == 2) + stack_adjust = 1; + + vrotb(i+1); + + switch (vtop->type.t & VT_BTYPE) { + case VT_STRUCT: + /* allocate the necessary size on stack */ + o(0x48); + oad(0xec81, size); /* sub $xxx, %rsp */ + /* generate structure store */ + r = get_reg(RC_INT); + orex(1, r, 0, 0x89); /* mov %rsp, r */ + o(0xe0 + REG_VALUE(r)); + vset(&vtop->type, r | VT_LVAL, 0); + vswap(); + vstore(); + break; + + case VT_LDOUBLE: + gv(RC_ST0); + oad(0xec8148, size); /* sub $xxx, %rsp */ + o(0x7cdb); /* fstpt 0(%rsp) */ + g(0x24); + g(0x00); + break; + + case VT_FLOAT: + case VT_DOUBLE: + assert(mode == x86_64_mode_sse); + r = gv(RC_FLOAT); + o(0x50); /* push $rax */ + /* movq %xmmN, (%rsp) */ + o(0xd60f66); + o(0x04 + REG_VALUE(r)*8); + o(0x24); + break; + + default: + assert(mode == x86_64_mode_integer); + /* simple type */ + /* XXX: implicit cast ? */ + r = gv(RC_INT); + orex(0,r,0,0x50 + REG_VALUE(r)); /* push r */ + break; + } + args_size += size; + + vpop(); + --nb_args; + onstack++; + } + + /* XXX This should be superfluous. */ + save_regs(0); /* save used temporary registers */ + + /* then, we prepare register passing arguments. + Note that we cannot set RDX and RCX in this loop because gv() + may break these temporary registers. Let's use R10 and R11 + instead of them */ + assert(gen_reg <= REGN); + assert(sse_reg <= 8); + for(i = 0; i < nb_args; i++) { + mode = classify_x86_64_arg(&vtop->type, &type, &size, &align, ®_count); + /* Alter stack entry type so that gv() knows how to treat it */ + vtop->type = type; + if (mode == x86_64_mode_sse) { + if (reg_count == 2) { + sse_reg -= 2; + gv(RC_FRET); /* Use pair load into xmm0 & xmm1 */ + if (sse_reg) { /* avoid redundant movaps %xmm0, %xmm0 */ + /* movaps %xmm0, %xmmN */ + o(0x280f); + o(0xc0 + (sse_reg << 3)); + /* movaps %xmm1, %xmmN */ + o(0x280f); + o(0xc1 + ((sse_reg+1) << 3)); + } + } else { + assert(reg_count == 1); + --sse_reg; + /* Load directly to register */ + gv(RC_XMM0 << sse_reg); + } + } else if (mode == x86_64_mode_integer) { + /* simple type */ + /* XXX: implicit cast ? */ + int d; + gen_reg -= reg_count; + r = gv(RC_INT); + d = arg_prepare_reg(gen_reg); + orex(1,d,r,0x89); /* mov */ + o(0xc0 + REG_VALUE(r) * 8 + REG_VALUE(d)); + if (reg_count == 2) { + d = arg_prepare_reg(gen_reg+1); + orex(1,d,vtop->r2,0x89); /* mov */ + o(0xc0 + REG_VALUE(vtop->r2) * 8 + REG_VALUE(d)); + } + } + vtop--; + } + assert(gen_reg == 0); + assert(sse_reg == 0); + + /* We shouldn't have many operands on the stack anymore, but the + call address itself is still there, and it might be in %eax + (or edx/ecx) currently, which the below writes would clobber. + So evict all remaining operands here. */ + save_regs(0); + + /* Copy R10 and R11 into RDX and RCX, respectively */ + if (nb_reg_args > 2) { + o(0xd2894c); /* mov %r10, %rdx */ + if (nb_reg_args > 3) { + o(0xd9894c); /* mov %r11, %rcx */ + } + } + + if (vtop->type.ref->f.func_type != FUNC_NEW) /* implies FUNC_OLD or FUNC_ELLIPSIS */ + oad(0xb8, nb_sse_args < 8 ? nb_sse_args : 8); /* mov nb_sse_args, %eax */ + gcall_or_jmp(0); + if (args_size) + gadd_sp(args_size); + vtop--; +} + + +#define FUNC_PROLOG_SIZE 11 + +static void push_arg_reg(int i) { + loc -= 8; + gen_modrm64(0x89, arg_regs[i], VT_LOCAL, NULL, loc); +} + +/* generate function prolog of type 't' */ +void gfunc_prolog(CType *func_type) +{ + X86_64_Mode mode; + int i, addr, align, size, reg_count; + int param_addr = 0, reg_param_index, sse_param_index; + Sym *sym; + CType *type; + + sym = func_type->ref; + addr = PTR_SIZE * 2; + loc = 0; + ind += FUNC_PROLOG_SIZE; + func_sub_sp_offset = ind; + func_ret_sub = 0; + + if (sym->f.func_type == FUNC_ELLIPSIS) { + int seen_reg_num, seen_sse_num, seen_stack_size; + seen_reg_num = seen_sse_num = 0; + /* frame pointer and return address */ + seen_stack_size = PTR_SIZE * 2; + /* count the number of seen parameters */ + sym = func_type->ref; + while ((sym = sym->next) != NULL) { + type = &sym->type; + mode = classify_x86_64_arg(type, NULL, &size, &align, ®_count); + switch (mode) { + default: + stack_arg: + seen_stack_size = ((seen_stack_size + align - 1) & -align) + size; + break; + + case x86_64_mode_integer: + if (seen_reg_num + reg_count > REGN) + goto stack_arg; + seen_reg_num += reg_count; + break; + + case x86_64_mode_sse: + if (seen_sse_num + reg_count > 8) + goto stack_arg; + seen_sse_num += reg_count; + break; + } + } + + loc -= 16; + /* movl $0x????????, -0x10(%rbp) */ + o(0xf045c7); + gen_le32(seen_reg_num * 8); + /* movl $0x????????, -0xc(%rbp) */ + o(0xf445c7); + gen_le32(seen_sse_num * 16 + 48); + /* movl $0x????????, -0x8(%rbp) */ + o(0xf845c7); + gen_le32(seen_stack_size); + + /* save all register passing arguments */ + for (i = 0; i < 8; i++) { + loc -= 16; + if (!tcc_state->nosse) { + o(0xd60f66); /* movq */ + gen_modrm(7 - i, VT_LOCAL, NULL, loc); + } + /* movq $0, loc+8(%rbp) */ + o(0x85c748); + gen_le32(loc + 8); + gen_le32(0); + } + for (i = 0; i < REGN; i++) { + push_arg_reg(REGN-1-i); + } + } + + sym = func_type->ref; + reg_param_index = 0; + sse_param_index = 0; + + /* if the function returns a structure, then add an + implicit pointer parameter */ + func_vt = sym->type; + mode = classify_x86_64_arg(&func_vt, NULL, &size, &align, ®_count); + if (mode == x86_64_mode_memory) { + push_arg_reg(reg_param_index); + func_vc = loc; + reg_param_index++; + } + /* define parameters */ + while ((sym = sym->next) != NULL) { + type = &sym->type; + mode = classify_x86_64_arg(type, NULL, &size, &align, ®_count); + switch (mode) { + case x86_64_mode_sse: + if (tcc_state->nosse) + tcc_error("SSE disabled but floating point arguments used"); + if (sse_param_index + reg_count <= 8) { + /* save arguments passed by register */ + loc -= reg_count * 8; + param_addr = loc; + for (i = 0; i < reg_count; ++i) { + o(0xd60f66); /* movq */ + gen_modrm(sse_param_index, VT_LOCAL, NULL, param_addr + i*8); + ++sse_param_index; + } + } else { + addr = (addr + align - 1) & -align; + param_addr = addr; + addr += size; + } + break; + + case x86_64_mode_memory: + case x86_64_mode_x87: + addr = (addr + align - 1) & -align; + param_addr = addr; + addr += size; + break; + + case x86_64_mode_integer: { + if (reg_param_index + reg_count <= REGN) { + /* save arguments passed by register */ + loc -= reg_count * 8; + param_addr = loc; + for (i = 0; i < reg_count; ++i) { + gen_modrm64(0x89, arg_regs[reg_param_index], VT_LOCAL, NULL, param_addr + i*8); + ++reg_param_index; + } + } else { + addr = (addr + align - 1) & -align; + param_addr = addr; + addr += size; + } + break; + } + default: break; /* nothing to be done for x86_64_mode_none */ + } + sym_push(sym->v & ~SYM_FIELD, type, + VT_LOCAL | VT_LVAL, param_addr); + } + +#ifdef CONFIG_TCC_BCHECK + /* leave some room for bound checking code */ + if (tcc_state->do_bounds_check) { + func_bound_offset = lbounds_section->data_offset; + func_bound_ind = ind; + oad(0xb8, 0); /* lbound section pointer */ + o(0xc78948); /* mov %rax,%rdi ## first arg in %rdi, this must be ptr */ + oad(0xb8, 0); /* call to function */ + } +#endif +} + +/* generate function epilog */ +void gfunc_epilog(void) +{ + int v, saved_ind; + +#ifdef CONFIG_TCC_BCHECK + if (tcc_state->do_bounds_check + && func_bound_offset != lbounds_section->data_offset) + { + addr_t saved_ind; + addr_t *bounds_ptr; + Sym *sym_data; + + /* add end of table info */ + bounds_ptr = section_ptr_add(lbounds_section, sizeof(addr_t)); + *bounds_ptr = 0; + + /* generate bound local allocation */ + sym_data = get_sym_ref(&char_pointer_type, lbounds_section, + func_bound_offset, lbounds_section->data_offset); + saved_ind = ind; + ind = func_bound_ind; + greloca(cur_text_section, sym_data, ind + 1, R_X86_64_64, 0); + ind = ind + 5 + 3; + gen_static_call(TOK___bound_local_new); + ind = saved_ind; + + /* generate bound check local freeing */ + o(0x5250); /* save returned value, if any */ + greloca(cur_text_section, sym_data, ind + 1, R_X86_64_64, 0); + oad(0xb8, 0); /* mov xxx, %rax */ + o(0xc78948); /* mov %rax,%rdi # first arg in %rdi, this must be ptr */ + gen_static_call(TOK___bound_local_delete); + o(0x585a); /* restore returned value, if any */ + } +#endif + o(0xc9); /* leave */ + if (func_ret_sub == 0) { + o(0xc3); /* ret */ + } else { + o(0xc2); /* ret n */ + g(func_ret_sub); + g(func_ret_sub >> 8); + } + /* align local size to word & save local variables */ + v = (-loc + 15) & -16; + saved_ind = ind; + ind = func_sub_sp_offset - FUNC_PROLOG_SIZE; + o(0xe5894855); /* push %rbp, mov %rsp, %rbp */ + o(0xec8148); /* sub rsp, stacksize */ + gen_le32(v); + ind = saved_ind; +} + +#endif /* not PE */ + +/* generate a jump to a label */ +int gjmp(int t) +{ + return gjmp2(0xe9, t); +} + +/* generate a jump to a fixed address */ +void gjmp_addr(int a) +{ + int r; + r = a - ind - 2; + if (r == (char)r) { + g(0xeb); + g(r); + } else { + oad(0xe9, a - ind - 5); + } +} + +ST_FUNC void gtst_addr(int inv, int a) +{ + int v = vtop->r & VT_VALMASK; + if (v == VT_CMP) { + inv ^= (vtop--)->c.i; + a -= ind + 2; + if (a == (char)a) { + g(inv - 32); + g(a); + } else { + g(0x0f); + oad(inv - 16, a - 4); + } + } else if ((v & ~1) == VT_JMP) { + if ((v & 1) != inv) { + gjmp_addr(a); + gsym(vtop->c.i); + } else { + gsym(vtop->c.i); + o(0x05eb); + gjmp_addr(a); + } + vtop--; + } +} + +/* generate a test. set 'inv' to invert test. Stack entry is popped */ +ST_FUNC int gtst(int inv, int t) +{ + int v = vtop->r & VT_VALMASK; + + if (nocode_wanted) { + ; + } else if (v == VT_CMP) { + /* fast case : can jump directly since flags are set */ + if (vtop->c.i & 0x100) + { + /* This was a float compare. If the parity flag is set + the result was unordered. For anything except != this + means false and we don't jump (anding both conditions). + For != this means true (oring both). + Take care about inverting the test. We need to jump + to our target if the result was unordered and test wasn't NE, + otherwise if unordered we don't want to jump. */ + vtop->c.i &= ~0x100; + if (inv == (vtop->c.i == TOK_NE)) + o(0x067a); /* jp +6 */ + else + { + g(0x0f); + t = gjmp2(0x8a, t); /* jp t */ + } + } + g(0x0f); + t = gjmp2((vtop->c.i - 16) ^ inv, t); + } else if (v == VT_JMP || v == VT_JMPI) { + /* && or || optimization */ + if ((v & 1) == inv) { + /* insert vtop->c jump list in t */ + uint32_t n1, n = vtop->c.i; + if (n) { + while ((n1 = read32le(cur_text_section->data + n))) + n = n1; + write32le(cur_text_section->data + n, t); + t = vtop->c.i; + } + } else { + t = gjmp(t); + gsym(vtop->c.i); + } + } + vtop--; + return t; +} + +/* generate an integer binary operation */ +void gen_opi(int op) +{ + int r, fr, opc, c; + int ll, uu, cc; + + ll = is64_type(vtop[-1].type.t); + uu = (vtop[-1].type.t & VT_UNSIGNED) != 0; + cc = (vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST; + + switch(op) { + case '+': + case TOK_ADDC1: /* add with carry generation */ + opc = 0; + gen_op8: + if (cc && (!ll || (int)vtop->c.i == vtop->c.i)) { + /* constant case */ + vswap(); + r = gv(RC_INT); + vswap(); + c = vtop->c.i; + if (c == (char)c) { + /* XXX: generate inc and dec for smaller code ? */ + orex(ll, r, 0, 0x83); + o(0xc0 | (opc << 3) | REG_VALUE(r)); + g(c); + } else { + orex(ll, r, 0, 0x81); + oad(0xc0 | (opc << 3) | REG_VALUE(r), c); + } + } else { + gv2(RC_INT, RC_INT); + r = vtop[-1].r; + fr = vtop[0].r; + orex(ll, r, fr, (opc << 3) | 0x01); + o(0xc0 + REG_VALUE(r) + REG_VALUE(fr) * 8); + } + vtop--; + if (op >= TOK_ULT && op <= TOK_GT) { + vtop->r = VT_CMP; + vtop->c.i = op; + } + break; + case '-': + case TOK_SUBC1: /* sub with carry generation */ + opc = 5; + goto gen_op8; + case TOK_ADDC2: /* add with carry use */ + opc = 2; + goto gen_op8; + case TOK_SUBC2: /* sub with carry use */ + opc = 3; + goto gen_op8; + case '&': + opc = 4; + goto gen_op8; + case '^': + opc = 6; + goto gen_op8; + case '|': + opc = 1; + goto gen_op8; + case '*': + gv2(RC_INT, RC_INT); + r = vtop[-1].r; + fr = vtop[0].r; + orex(ll, fr, r, 0xaf0f); /* imul fr, r */ + o(0xc0 + REG_VALUE(fr) + REG_VALUE(r) * 8); + vtop--; + break; + case TOK_SHL: + opc = 4; + goto gen_shift; + case TOK_SHR: + opc = 5; + goto gen_shift; + case TOK_SAR: + opc = 7; + gen_shift: + opc = 0xc0 | (opc << 3); + if (cc) { + /* constant case */ + vswap(); + r = gv(RC_INT); + vswap(); + orex(ll, r, 0, 0xc1); /* shl/shr/sar $xxx, r */ + o(opc | REG_VALUE(r)); + g(vtop->c.i & (ll ? 63 : 31)); + } else { + /* we generate the shift in ecx */ + gv2(RC_INT, RC_RCX); + r = vtop[-1].r; + orex(ll, r, 0, 0xd3); /* shl/shr/sar %cl, r */ + o(opc | REG_VALUE(r)); + } + vtop--; + break; + case TOK_UDIV: + case TOK_UMOD: + uu = 1; + goto divmod; + case '/': + case '%': + case TOK_PDIV: + uu = 0; + divmod: + /* first operand must be in eax */ + /* XXX: need better constraint for second operand */ + gv2(RC_RAX, RC_RCX); + r = vtop[-1].r; + fr = vtop[0].r; + vtop--; + save_reg(TREG_RDX); + orex(ll, 0, 0, uu ? 0xd231 : 0x99); /* xor %edx,%edx : cqto */ + orex(ll, fr, 0, 0xf7); /* div fr, %eax */ + o((uu ? 0xf0 : 0xf8) + REG_VALUE(fr)); + if (op == '%' || op == TOK_UMOD) + r = TREG_RDX; + else + r = TREG_RAX; + vtop->r = r; + break; + default: + opc = 7; + goto gen_op8; + } +} + +void gen_opl(int op) +{ + gen_opi(op); +} + +/* generate a floating point operation 'v = t1 op t2' instruction. The + two operands are guaranteed to have the same floating point type */ +/* XXX: need to use ST1 too */ +void gen_opf(int op) +{ + int a, ft, fc, swapped, r; + int float_type = + (vtop->type.t & VT_BTYPE) == VT_LDOUBLE ? RC_ST0 : RC_FLOAT; + + /* convert constants to memory references */ + if ((vtop[-1].r & (VT_VALMASK | VT_LVAL)) == VT_CONST) { + vswap(); + gv(float_type); + vswap(); + } + if ((vtop[0].r & (VT_VALMASK | VT_LVAL)) == VT_CONST) + gv(float_type); + + /* must put at least one value in the floating point register */ + if ((vtop[-1].r & VT_LVAL) && + (vtop[0].r & VT_LVAL)) { + vswap(); + gv(float_type); + vswap(); + } + swapped = 0; + /* swap the stack if needed so that t1 is the register and t2 is + the memory reference */ + if (vtop[-1].r & VT_LVAL) { + vswap(); + swapped = 1; + } + if ((vtop->type.t & VT_BTYPE) == VT_LDOUBLE) { + if (op >= TOK_ULT && op <= TOK_GT) { + /* load on stack second operand */ + load(TREG_ST0, vtop); + save_reg(TREG_RAX); /* eax is used by FP comparison code */ + if (op == TOK_GE || op == TOK_GT) + swapped = !swapped; + else if (op == TOK_EQ || op == TOK_NE) + swapped = 0; + if (swapped) + o(0xc9d9); /* fxch %st(1) */ + if (op == TOK_EQ || op == TOK_NE) + o(0xe9da); /* fucompp */ + else + o(0xd9de); /* fcompp */ + o(0xe0df); /* fnstsw %ax */ + if (op == TOK_EQ) { + o(0x45e480); /* and $0x45, %ah */ + o(0x40fC80); /* cmp $0x40, %ah */ + } else if (op == TOK_NE) { + o(0x45e480); /* and $0x45, %ah */ + o(0x40f480); /* xor $0x40, %ah */ + op = TOK_NE; + } else if (op == TOK_GE || op == TOK_LE) { + o(0x05c4f6); /* test $0x05, %ah */ + op = TOK_EQ; + } else { + o(0x45c4f6); /* test $0x45, %ah */ + op = TOK_EQ; + } + vtop--; + vtop->r = VT_CMP; + vtop->c.i = op; + } else { + /* no memory reference possible for long double operations */ + load(TREG_ST0, vtop); + swapped = !swapped; + + switch(op) { + default: + case '+': + a = 0; + break; + case '-': + a = 4; + if (swapped) + a++; + break; + case '*': + a = 1; + break; + case '/': + a = 6; + if (swapped) + a++; + break; + } + ft = vtop->type.t; + fc = vtop->c.i; + o(0xde); /* fxxxp %st, %st(1) */ + o(0xc1 + (a << 3)); + vtop--; + } + } else { + if (op >= TOK_ULT && op <= TOK_GT) { + /* if saved lvalue, then we must reload it */ + r = vtop->r; + fc = vtop->c.i; + if ((r & VT_VALMASK) == VT_LLOCAL) { + SValue v1; + r = get_reg(RC_INT); + v1.type.t = VT_PTR; + v1.r = VT_LOCAL | VT_LVAL; + v1.c.i = fc; + load(r, &v1); + fc = 0; + } + + if (op == TOK_EQ || op == TOK_NE) { + swapped = 0; + } else { + if (op == TOK_LE || op == TOK_LT) + swapped = !swapped; + if (op == TOK_LE || op == TOK_GE) { + op = 0x93; /* setae */ + } else { + op = 0x97; /* seta */ + } + } + + if (swapped) { + gv(RC_FLOAT); + vswap(); + } + assert(!(vtop[-1].r & VT_LVAL)); + + if ((vtop->type.t & VT_BTYPE) == VT_DOUBLE) + o(0x66); + if (op == TOK_EQ || op == TOK_NE) + o(0x2e0f); /* ucomisd */ + else + o(0x2f0f); /* comisd */ + + if (vtop->r & VT_LVAL) { + gen_modrm(vtop[-1].r, r, vtop->sym, fc); + } else { + o(0xc0 + REG_VALUE(vtop[0].r) + REG_VALUE(vtop[-1].r)*8); + } + + vtop--; + vtop->r = VT_CMP; + vtop->c.i = op | 0x100; + } else { + assert((vtop->type.t & VT_BTYPE) != VT_LDOUBLE); + switch(op) { + default: + case '+': + a = 0; + break; + case '-': + a = 4; + break; + case '*': + a = 1; + break; + case '/': + a = 6; + break; + } + ft = vtop->type.t; + fc = vtop->c.i; + assert((ft & VT_BTYPE) != VT_LDOUBLE); + + r = vtop->r; + /* if saved lvalue, then we must reload it */ + if ((vtop->r & VT_VALMASK) == VT_LLOCAL) { + SValue v1; + r = get_reg(RC_INT); + v1.type.t = VT_PTR; + v1.r = VT_LOCAL | VT_LVAL; + v1.c.i = fc; + load(r, &v1); + fc = 0; + } + + assert(!(vtop[-1].r & VT_LVAL)); + if (swapped) { + assert(vtop->r & VT_LVAL); + gv(RC_FLOAT); + vswap(); + } + + if ((ft & VT_BTYPE) == VT_DOUBLE) { + o(0xf2); + } else { + o(0xf3); + } + o(0x0f); + o(0x58 + a); + + if (vtop->r & VT_LVAL) { + gen_modrm(vtop[-1].r, r, vtop->sym, fc); + } else { + o(0xc0 + REG_VALUE(vtop[0].r) + REG_VALUE(vtop[-1].r)*8); + } + + vtop--; + } + } +} + +/* convert integers to fp 't' type. Must handle 'int', 'unsigned int' + and 'long long' cases. */ +void gen_cvt_itof(int t) +{ + if ((t & VT_BTYPE) == VT_LDOUBLE) { + save_reg(TREG_ST0); + gv(RC_INT); + if ((vtop->type.t & VT_BTYPE) == VT_LLONG) { + /* signed long long to float/double/long double (unsigned case + is handled generically) */ + o(0x50 + (vtop->r & VT_VALMASK)); /* push r */ + o(0x242cdf); /* fildll (%rsp) */ + o(0x08c48348); /* add $8, %rsp */ + } else if ((vtop->type.t & (VT_BTYPE | VT_UNSIGNED)) == + (VT_INT | VT_UNSIGNED)) { + /* unsigned int to float/double/long double */ + o(0x6a); /* push $0 */ + g(0x00); + o(0x50 + (vtop->r & VT_VALMASK)); /* push r */ + o(0x242cdf); /* fildll (%rsp) */ + o(0x10c48348); /* add $16, %rsp */ + } else { + /* int to float/double/long double */ + o(0x50 + (vtop->r & VT_VALMASK)); /* push r */ + o(0x2404db); /* fildl (%rsp) */ + o(0x08c48348); /* add $8, %rsp */ + } + vtop->r = TREG_ST0; + } else { + int r = get_reg(RC_FLOAT); + gv(RC_INT); + o(0xf2 + ((t & VT_BTYPE) == VT_FLOAT?1:0)); + if ((vtop->type.t & (VT_BTYPE | VT_UNSIGNED)) == + (VT_INT | VT_UNSIGNED) || + (vtop->type.t & VT_BTYPE) == VT_LLONG) { + o(0x48); /* REX */ + } + o(0x2a0f); + o(0xc0 + (vtop->r & VT_VALMASK) + REG_VALUE(r)*8); /* cvtsi2sd */ + vtop->r = r; + } +} + +/* convert from one floating point type to another */ +void gen_cvt_ftof(int t) +{ + int ft, bt, tbt; + + ft = vtop->type.t; + bt = ft & VT_BTYPE; + tbt = t & VT_BTYPE; + + if (bt == VT_FLOAT) { + gv(RC_FLOAT); + if (tbt == VT_DOUBLE) { + o(0x140f); /* unpcklps */ + o(0xc0 + REG_VALUE(vtop->r)*9); + o(0x5a0f); /* cvtps2pd */ + o(0xc0 + REG_VALUE(vtop->r)*9); + } else if (tbt == VT_LDOUBLE) { + save_reg(RC_ST0); + /* movss %xmm0,-0x10(%rsp) */ + o(0x110ff3); + o(0x44 + REG_VALUE(vtop->r)*8); + o(0xf024); + o(0xf02444d9); /* flds -0x10(%rsp) */ + vtop->r = TREG_ST0; + } + } else if (bt == VT_DOUBLE) { + gv(RC_FLOAT); + if (tbt == VT_FLOAT) { + o(0x140f66); /* unpcklpd */ + o(0xc0 + REG_VALUE(vtop->r)*9); + o(0x5a0f66); /* cvtpd2ps */ + o(0xc0 + REG_VALUE(vtop->r)*9); + } else if (tbt == VT_LDOUBLE) { + save_reg(RC_ST0); + /* movsd %xmm0,-0x10(%rsp) */ + o(0x110ff2); + o(0x44 + REG_VALUE(vtop->r)*8); + o(0xf024); + o(0xf02444dd); /* fldl -0x10(%rsp) */ + vtop->r = TREG_ST0; + } + } else { + int r; + gv(RC_ST0); + r = get_reg(RC_FLOAT); + if (tbt == VT_DOUBLE) { + o(0xf0245cdd); /* fstpl -0x10(%rsp) */ + /* movsd -0x10(%rsp),%xmm0 */ + o(0x100ff2); + o(0x44 + REG_VALUE(r)*8); + o(0xf024); + vtop->r = r; + } else if (tbt == VT_FLOAT) { + o(0xf0245cd9); /* fstps -0x10(%rsp) */ + /* movss -0x10(%rsp),%xmm0 */ + o(0x100ff3); + o(0x44 + REG_VALUE(r)*8); + o(0xf024); + vtop->r = r; + } + } +} + +/* convert fp to int 't' type */ +void gen_cvt_ftoi(int t) +{ + int ft, bt, size, r; + ft = vtop->type.t; + bt = ft & VT_BTYPE; + if (bt == VT_LDOUBLE) { + gen_cvt_ftof(VT_DOUBLE); + bt = VT_DOUBLE; + } + + gv(RC_FLOAT); + if (t != VT_INT) + size = 8; + else + size = 4; + + r = get_reg(RC_INT); + if (bt == VT_FLOAT) { + o(0xf3); + } else if (bt == VT_DOUBLE) { + o(0xf2); + } else { + assert(0); + } + orex(size == 8, r, 0, 0x2c0f); /* cvttss2si or cvttsd2si */ + o(0xc0 + REG_VALUE(vtop->r) + REG_VALUE(r)*8); + vtop->r = r; +} + +/* computed goto support */ +void ggoto(void) +{ + gcall_or_jmp(1); + vtop--; +} + +/* Save the stack pointer onto the stack and return the location of its address */ +ST_FUNC void gen_vla_sp_save(int addr) { + /* mov %rsp,addr(%rbp)*/ + gen_modrm64(0x89, TREG_RSP, VT_LOCAL, NULL, addr); +} + +/* Restore the SP from a location on the stack */ +ST_FUNC void gen_vla_sp_restore(int addr) { + gen_modrm64(0x8b, TREG_RSP, VT_LOCAL, NULL, addr); +} + +/* Subtract from the stack pointer, and push the resulting value onto the stack */ +ST_FUNC void gen_vla_alloc(CType *type, int align) { +#ifdef TCC_TARGET_PE + /* alloca does more than just adjust %rsp on Windows */ + vpush_global_sym(&func_old_type, TOK_alloca); + vswap(); /* Move alloca ref past allocation size */ + gfunc_call(1); +#else + int r; + r = gv(RC_INT); /* allocation size */ + /* sub r,%rsp */ + o(0x2b48); + o(0xe0 | REG_VALUE(r)); + /* We align to 16 bytes rather than align */ + /* and ~15, %rsp */ + o(0xf0e48348); + vpop(); +#endif +} + + +/* end of x86-64 code generator */ +/*************************************************************/ +#endif /* ! TARGET_DEFS_ONLY */ +/******************************************************/ diff --git a/tinyc/x86_64-link.c b/tinyc/x86_64-link.c new file mode 100644 index 000000000..c0c5e13bf --- /dev/null +++ b/tinyc/x86_64-link.c @@ -0,0 +1,295 @@ +#ifdef TARGET_DEFS_ONLY + +#define EM_TCC_TARGET EM_X86_64 + +/* relocation type for 32 bit data relocation */ +#define R_DATA_32 R_X86_64_32S +#define R_DATA_PTR R_X86_64_64 +#define R_JMP_SLOT R_X86_64_JUMP_SLOT +#define R_GLOB_DAT R_X86_64_GLOB_DAT +#define R_COPY R_X86_64_COPY +#define R_RELATIVE R_X86_64_RELATIVE + +#define R_NUM R_X86_64_NUM + +#define ELF_START_ADDR 0x400000 +#define ELF_PAGE_SIZE 0x200000 + +#define PCRELATIVE_DLLPLT 1 +#define RELOCATE_DLLPLT 1 + +#else /* !TARGET_DEFS_ONLY */ + +#include "tcc.h" + +/* Returns 1 for a code relocation, 0 for a data relocation. For unknown + relocations, returns -1. */ +int code_reloc (int reloc_type) +{ + switch (reloc_type) { + case R_X86_64_32: + case R_X86_64_32S: + case R_X86_64_64: + case R_X86_64_GOTPC32: + case R_X86_64_GOTPC64: + case R_X86_64_GOTPCREL: + case R_X86_64_GOTPCRELX: + case R_X86_64_REX_GOTPCRELX: + case R_X86_64_GOTTPOFF: + case R_X86_64_GOT32: + case R_X86_64_GOT64: + case R_X86_64_GLOB_DAT: + case R_X86_64_COPY: + case R_X86_64_RELATIVE: + case R_X86_64_GOTOFF64: + return 0; + + case R_X86_64_PC32: + case R_X86_64_PC64: + case R_X86_64_PLT32: + case R_X86_64_PLTOFF64: + case R_X86_64_JUMP_SLOT: + return 1; + } + + tcc_error ("Unknown relocation type: %d", reloc_type); + return -1; +} + +/* Returns an enumerator to describe whether and when the relocation needs a + GOT and/or PLT entry to be created. See tcc.h for a description of the + different values. */ +int gotplt_entry_type (int reloc_type) +{ + switch (reloc_type) { + case R_X86_64_GLOB_DAT: + case R_X86_64_JUMP_SLOT: + case R_X86_64_COPY: + case R_X86_64_RELATIVE: + return NO_GOTPLT_ENTRY; + + /* The following relocs wouldn't normally need GOT or PLT + slots, but we need them for simplicity in the link + editor part. See our caller for comments. */ + case R_X86_64_32: + case R_X86_64_32S: + case R_X86_64_64: + case R_X86_64_PC32: + case R_X86_64_PC64: + return AUTO_GOTPLT_ENTRY; + + case R_X86_64_GOTTPOFF: + return BUILD_GOT_ONLY; + + case R_X86_64_GOT32: + case R_X86_64_GOT64: + case R_X86_64_GOTPC32: + case R_X86_64_GOTPC64: + case R_X86_64_GOTOFF64: + case R_X86_64_GOTPCREL: + case R_X86_64_GOTPCRELX: + case R_X86_64_REX_GOTPCRELX: + case R_X86_64_PLT32: + case R_X86_64_PLTOFF64: + return ALWAYS_GOTPLT_ENTRY; + } + + tcc_error ("Unknown relocation type: %d", reloc_type); + return -1; +} + +ST_FUNC unsigned create_plt_entry(TCCState *s1, unsigned got_offset, struct sym_attr *attr) +{ + Section *plt = s1->plt; + uint8_t *p; + int modrm; + unsigned plt_offset, relofs; + + modrm = 0x25; + + /* empty PLT: create PLT0 entry that pushes the library identifier + (GOT + PTR_SIZE) and jumps to ld.so resolution routine + (GOT + 2 * PTR_SIZE) */ + if (plt->data_offset == 0) { + p = section_ptr_add(plt, 16); + p[0] = 0xff; /* pushl got + PTR_SIZE */ + p[1] = modrm + 0x10; + write32le(p + 2, PTR_SIZE); + p[6] = 0xff; /* jmp *(got + PTR_SIZE * 2) */ + p[7] = modrm; + write32le(p + 8, PTR_SIZE * 2); + } + plt_offset = plt->data_offset; + + /* The PLT slot refers to the relocation entry it needs via offset. + The reloc entry is created below, so its offset is the current + data_offset */ + relofs = s1->got->reloc ? s1->got->reloc->data_offset : 0; + + /* Jump to GOT entry where ld.so initially put the address of ip + 4 */ + p = section_ptr_add(plt, 16); + p[0] = 0xff; /* jmp *(got + x) */ + p[1] = modrm; + write32le(p + 2, got_offset); + p[6] = 0x68; /* push $xxx */ + /* On x86-64, the relocation is referred to by _index_ */ + write32le(p + 7, relofs / sizeof (ElfW_Rel)); + p[11] = 0xe9; /* jmp plt_start */ + write32le(p + 12, -(plt->data_offset)); + return plt_offset; +} + +/* relocate the PLT: compute addresses and offsets in the PLT now that final + address for PLT and GOT are known (see fill_program_header) */ +ST_FUNC void relocate_plt(TCCState *s1) +{ + uint8_t *p, *p_end; + + if (!s1->plt) + return; + + p = s1->plt->data; + p_end = p + s1->plt->data_offset; + + if (p < p_end) { + int x = s1->got->sh_addr - s1->plt->sh_addr - 6; + add32le(p + 2, x); + add32le(p + 8, x - 6); + p += 16; + while (p < p_end) { + add32le(p + 2, x + s1->plt->data - p); + p += 16; + } + } +} + +static ElfW_Rel *qrel; /* ptr to next reloc entry reused */ + +void relocate_init(Section *sr) +{ + qrel = (ElfW_Rel *) sr->data; +} + +void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t addr, addr_t val) +{ + int sym_index, esym_index; + + sym_index = ELFW(R_SYM)(rel->r_info); + + switch (type) { + case R_X86_64_64: + if (s1->output_type == TCC_OUTPUT_DLL) { + esym_index = s1->sym_attrs[sym_index].dyn_index; + qrel->r_offset = rel->r_offset; + if (esym_index) { + qrel->r_info = ELFW(R_INFO)(esym_index, R_X86_64_64); + qrel->r_addend = rel->r_addend; + qrel++; + break; + } else { + qrel->r_info = ELFW(R_INFO)(0, R_X86_64_RELATIVE); + qrel->r_addend = read64le(ptr) + val; + qrel++; + } + } + add64le(ptr, val); + break; + case R_X86_64_32: + case R_X86_64_32S: + if (s1->output_type == TCC_OUTPUT_DLL) { + /* XXX: this logic may depend on TCC's codegen + now TCC uses R_X86_64_32 even for a 64bit pointer */ + qrel->r_info = ELFW(R_INFO)(0, R_X86_64_RELATIVE); + /* Use sign extension! */ + qrel->r_addend = (int)read32le(ptr) + val; + qrel++; + } + add32le(ptr, val); + break; + + case R_X86_64_PC32: + if (s1->output_type == TCC_OUTPUT_DLL) { + /* DLL relocation */ + esym_index = s1->sym_attrs[sym_index].dyn_index; + if (esym_index) { + qrel->r_offset = rel->r_offset; + qrel->r_info = ELFW(R_INFO)(esym_index, R_X86_64_PC32); + /* Use sign extension! */ + qrel->r_addend = (int)read32le(ptr) + rel->r_addend; + qrel++; + break; + } + } + goto plt32pc32; + + case R_X86_64_PLT32: + /* fallthrough: val already holds the PLT slot address */ + + plt32pc32: + { + long long diff; + diff = (long long)val - addr; + if (diff < -2147483648LL || diff > 2147483647LL) { + tcc_error("internal error: relocation failed"); + } + add32le(ptr, diff); + } + break; + + case R_X86_64_PLTOFF64: + add64le(ptr, val - s1->got->sh_addr + rel->r_addend); + break; + + case R_X86_64_PC64: + if (s1->output_type == TCC_OUTPUT_DLL) { + /* DLL relocation */ + esym_index = s1->sym_attrs[sym_index].dyn_index; + if (esym_index) { + qrel->r_offset = rel->r_offset; + qrel->r_info = ELFW(R_INFO)(esym_index, R_X86_64_PC64); + qrel->r_addend = read64le(ptr) + rel->r_addend; + qrel++; + break; + } + } + add64le(ptr, val - addr); + break; + + case R_X86_64_GLOB_DAT: + case R_X86_64_JUMP_SLOT: + /* They don't need addend */ + write64le(ptr, val - rel->r_addend); + break; + case R_X86_64_GOTPCREL: + case R_X86_64_GOTPCRELX: + case R_X86_64_REX_GOTPCRELX: + add32le(ptr, s1->got->sh_addr - addr + + s1->sym_attrs[sym_index].got_offset - 4); + break; + case R_X86_64_GOTPC32: + add32le(ptr, s1->got->sh_addr - addr + rel->r_addend); + break; + case R_X86_64_GOTPC64: + add64le(ptr, s1->got->sh_addr - addr + rel->r_addend); + break; + case R_X86_64_GOTTPOFF: + add32le(ptr, val - s1->got->sh_addr); + break; + case R_X86_64_GOT32: + /* we load the got offset */ + add32le(ptr, s1->sym_attrs[sym_index].got_offset); + break; + case R_X86_64_GOT64: + /* we load the got offset */ + add64le(ptr, s1->sym_attrs[sym_index].got_offset); + break; + case R_X86_64_GOTOFF64: + add64le(ptr, val - s1->got->sh_addr); + break; + case R_X86_64_RELATIVE: + /* do nothing */ + break; + } +} + +#endif /* !TARGET_DEFS_ONLY */ diff --git a/tools/atlas/atlas.md b/tools/atlas/atlas.md deleted file mode 100644 index ee770cd62..000000000 --- a/tools/atlas/atlas.md +++ /dev/null @@ -1,81 +0,0 @@ -# Atlas Package Cloner - -Atlas is a simple package cloner tool that automates some of the -workflows and needs for Nim's stdlib evolution. - -Atlas is compatible with Nimble in the sense that it supports the Nimble -file format. - - -## How it works - -Atlas uses git commits internally; version requirements are translated -to git commits via `git show-ref --tags`. - -Atlas uses URLs internally; Nimble package names are translated to URLs -via Nimble's `packages.json` file. - -Atlas does not call the Nim compiler for a build, instead it creates/patches -a `nim.cfg` file for the compiler. For example: - -``` -############# begin Atlas config section ########## ---noNimblePath ---path:"../nimx" ---path:"../sdl2/src" ---path:"../opengl/src" -############# end Atlas config section ########## -``` - -The version selection is deterministic, it picks up the *minimum* required -version. Thanks to this design, lock files are much less important. - - -## Dependencies - -Dependencies are neither installed globally, nor locally into the current -project. Instead a "workspace" is used. The workspace is the nearest parent -directory of the current directory that does not contain a `.git` subdirectory. -Dependencies are managed as **siblings**, not as children. Dependencies are -kept as git repositories. - -Thanks to this setup, it's easy to develop multiple projects at the same time. - -A project plus its dependencies are stored in a workspace: - - $workspace / main project - $workspace / dependency A - $workspace / dependency B - - -No attempts are being made at keeping directory hygiene inside the -workspace, you're supposed to create appropriate `$workspace` directories -at your own leisure. - - -## Commands - -Atlas supports the following commands: - - -### Clone - -Clones a URL and all of its dependencies (recursively) into the workspace. -Creates or patches a `nim.cfg` file with the required `--path` entries. - - -### Clone - -The `` is translated into an URL via `packages.json` and -then `clone ` is performed. - - -### Search - -Search the package index `packages.json` for a package that the given terms -in its description (or name or list of tags). - - -### Install - -Use the .nimble file to setup the project's dependencies. diff --git a/tools/atlas/atlas.nim b/tools/atlas/atlas.nim deleted file mode 100644 index 274e94517..000000000 --- a/tools/atlas/atlas.nim +++ /dev/null @@ -1,559 +0,0 @@ -# -# Atlas Package Cloner -# (c) Copyright 2021 Andreas Rumpf -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# - -## Simple tool to automate frequent workflows: Can "clone" -## a Nimble dependency and its dependencies recursively. - -import std/[parseopt, strutils, os, osproc, unicode, tables, sets, json, jsonutils] -import parse_requires, osutils, packagesjson - -const - Version = "0.2" - Usage = "atlas - Nim Package Cloner Version " & Version & """ - - (c) 2021 Andreas Rumpf -Usage: - atlas [options] [command] [arguments] -Command: - clone url|pkgname clone a package and all of its dependencies - install proj.nimble use the .nimble file to setup the project's dependencies - search keyw keywB... search for package that contains the given keywords - extract file.nimble extract the requirements and custom commands from - the given Nimble file - -Options: - --keepCommits do not perform any `git checkouts` - --cfgHere also create/maintain a nim.cfg in the current - working directory - --workspace=DIR use DIR as workspace - --version show the version - --help show this help -""" - -proc writeHelp() = - stdout.write(Usage) - stdout.flushFile() - quit(0) - -proc writeVersion() = - stdout.write(Version & "\n") - stdout.flushFile() - quit(0) - -const - MockupRun = defined(atlasTests) - TestsDir = "tools/atlas/tests" - -type - PackageName = distinct string - DepRelation = enum - normal, strictlyLess, strictlyGreater - - Dependency = object - name: PackageName - url, commit: string - rel: DepRelation # "requires x < 1.0" is silly, but Nimble allows it so we have too. - AtlasContext = object - projectDir, workspace: string - hasPackageList: bool - keepCommits: bool - cfgHere: bool - p: Table[string, string] # name -> url mapping - processed: HashSet[string] # the key is (url / commit) - errors: int - when MockupRun: - currentDir: string - step: int - mockupSuccess: bool - -const - InvalidCommit = "" - ProduceTest = false - -type - Command = enum - GitDiff = "git diff", - GitTags = "git show-ref --tags", - GitRevParse = "git rev-parse", - GitCheckout = "git checkout", - GitPull = "git pull", - GitCurrentCommit = "git log -n 1 --format=%H" - GitMergeBase = "git merge-base" - -include testdata - -proc exec(c: var AtlasContext; cmd: Command; args: openArray[string]): (string, int) = - when MockupRun: - assert TestLog[c.step].cmd == cmd, $(TestLog[c.step].cmd, cmd) - case cmd - of GitDiff, GitTags, GitRevParse, GitPull, GitCurrentCommit: - result = (TestLog[c.step].output, TestLog[c.step].exitCode) - of GitCheckout: - assert args[0] == TestLog[c.step].output - of GitMergeBase: - let tmp = TestLog[c.step].output.splitLines() - assert tmp.len == 4, $tmp.len - assert tmp[0] == args[0] - assert tmp[1] == args[1] - assert tmp[3] == "" - result[0] = tmp[2] - result[1] = TestLog[c.step].exitCode - inc c.step - else: - var cmdLine = $cmd - for i in 0.. ", result - -proc cloneUrl(c: var AtlasContext; url, dest: string; cloneUsingHttps: bool): string = - when MockupRun: - result = "" - else: - result = osutils.cloneUrl(url, dest, cloneUsingHttps) - when ProduceTest: - echo "cloned ", url, " into ", dest - -template withDir*(c: var AtlasContext; dir: string; body: untyped) = - when MockupRun: - c.currentDir = dir - body - else: - let oldDir = getCurrentDir() - try: - when ProduceTest: - echo "Current directory is now ", dir - setCurrentDir(dir) - body - finally: - setCurrentDir(oldDir) - -proc extractRequiresInfo(c: var AtlasContext; nimbleFile: string): NimbleFileInfo = - result = extractRequiresInfo(nimbleFile) - when ProduceTest: - echo "nimble ", nimbleFile, " info ", result - -proc toDepRelation(s: string): DepRelation = - case s - of "<": strictlyLess - of ">": strictlyGreater - else: normal - -proc isCleanGit(c: var AtlasContext; dir: string): string = - result = "" - let (outp, status) = exec(c, GitDiff, []) - if outp.len != 0: - result = "'git diff' not empty" - elif status != 0: - result = "'git diff' returned non-zero" - -proc message(c: var AtlasContext; category: string; p: PackageName; args: varargs[string]) = - var msg = category & "(" & p.string & ")" - for a in args: - msg.add ' ' - msg.add a - stdout.writeLine msg - inc c.errors - -proc warn(c: var AtlasContext; p: PackageName; args: varargs[string]) = - message(c, "[Warning] ", p, args) - -proc error(c: var AtlasContext; p: PackageName; args: varargs[string]) = - message(c, "[Error] ", p, args) - -proc sameVersionAs(tag, ver: string): bool = - const VersionChars = {'0'..'9', '.'} - - proc safeCharAt(s: string; i: int): char {.inline.} = - if i >= 0 and i < s.len: s[i] else: '\0' - - let idx = find(tag, ver) - if idx >= 0: - # we found the version as a substring inside the `tag`. But we - # need to watch out the the boundaries are not part of a - # larger/different version number: - result = safeCharAt(tag, idx-1) notin VersionChars and - safeCharAt(tag, idx+ver.len) notin VersionChars - -proc versionToCommit(c: var AtlasContext; d: Dependency): string = - let (outp, status) = exec(c, GitTags, []) - if status == 0: - var useNextOne = false - for line in splitLines(outp): - let commitsAndTags = strutils.splitWhitespace(line) - if commitsAndTags.len == 2: - case d.rel - of normal: - if commitsAndTags[1].sameVersionAs(d.commit): - return commitsAndTags[0] - of strictlyLess: - if d.commit == InvalidCommit or not commitsAndTags[1].sameVersionAs(d.commit): - return commitsAndTags[0] - of strictlyGreater: - if commitsAndTags[1].sameVersionAs(d.commit): - useNextOne = true - elif useNextOne: - return commitsAndTags[0] - - return "" - -proc shortToCommit(c: var AtlasContext; short: string): string = - let (cc, status) = exec(c, GitRevParse, [short]) - result = if status == 0: strutils.strip(cc) else: "" - -proc checkoutGitCommit(c: var AtlasContext; p: PackageName; commit: string) = - let (_, status) = exec(c, GitCheckout, [commit]) - if status != 0: - error(c, p, "could not checkout commit", commit) - -proc gitPull(c: var AtlasContext; p: PackageName) = - let (_, status) = exec(c, GitPull, []) - if status != 0: - error(c, p, "could not 'git pull'") - -proc updatePackages(c: var AtlasContext) = - if dirExists(c.workspace / PackagesDir): - withDir(c, c.workspace / PackagesDir): - gitPull(c, PackageName PackagesDir) - else: - withDir c, c.workspace: - let err = cloneUrl(c, "https://github.com/nim-lang/packages", PackagesDir, false) - if err != "": - error c, PackageName(PackagesDir), err - -proc fillPackageLookupTable(c: var AtlasContext) = - if not c.hasPackageList: - c.hasPackageList = true - when not MockupRun: - updatePackages(c) - let plist = getPackages(when MockupRun: TestsDir else: c.workspace) - for entry in plist: - c.p[unicode.toLower entry.name] = entry.url - -proc toUrl(c: var AtlasContext; p: string): string = - if p.isUrl: - result = p - else: - fillPackageLookupTable(c) - result = c.p.getOrDefault(unicode.toLower p) - if result.len == 0: - inc c.errors - -proc toName(p: string): PackageName = - if p.isUrl: - result = PackageName splitFile(p).name - else: - result = PackageName p - -proc needsCommitLookup(commit: string): bool {.inline.} = - '.' in commit or commit == InvalidCommit - -proc isShortCommitHash(commit: string): bool {.inline.} = - commit.len >= 4 and commit.len < 40 - -proc checkoutCommit(c: var AtlasContext; w: Dependency) = - let dir = c.workspace / w.name.string - withDir c, dir: - if w.commit.len == 0 or cmpIgnoreCase(w.commit, "head") == 0: - gitPull(c, w.name) - else: - let err = isCleanGit(c, dir) - if err != "": - warn c, w.name, err - else: - let requiredCommit = - if needsCommitLookup(w.commit): versionToCommit(c, w) - elif isShortCommitHash(w.commit): shortToCommit(c, w.commit) - else: w.commit - let (cc, status) = exec(c, GitCurrentCommit, []) - let currentCommit = strutils.strip(cc) - if requiredCommit == "" or status != 0: - if requiredCommit == "" and w.commit == InvalidCommit: - warn c, w.name, "package has no tagged releases" - else: - warn c, w.name, "cannot find specified version/commit", w.commit - else: - if currentCommit != requiredCommit: - # checkout the later commit: - # git merge-base --is-ancestor - let (cc, status) = exec(c, GitMergeBase, [currentCommit, requiredCommit]) - let mergeBase = strutils.strip(cc) - if status == 0 and (mergeBase == currentCommit or mergeBase == requiredCommit): - # conflict resolution: pick the later commit: - if mergeBase == currentCommit: - checkoutGitCommit(c, w.name, requiredCommit) - else: - checkoutGitCommit(c, w.name, requiredCommit) - when false: - warn c, w.name, "do not know which commit is more recent:", - currentCommit, "(current) or", w.commit, " =", requiredCommit, "(required)" - -proc findNimbleFile(c: AtlasContext; dep: Dependency): string = - when MockupRun: - result = TestsDir / dep.name.string & ".nimble" - doAssert fileExists(result), "file does not exist " & result - else: - result = c.workspace / dep.name.string / (dep.name.string & ".nimble") - if not fileExists(result): - result = "" - for x in walkFiles(c.workspace / dep.name.string / "*.nimble"): - if result.len == 0: - result = x - else: - # ambiguous .nimble file - return "" - -proc addUniqueDep(c: var AtlasContext; work: var seq[Dependency]; - tokens: seq[string]) = - let oldErrors = c.errors - let url = toUrl(c, tokens[0]) - if oldErrors != c.errors: - warn c, toName(tokens[0]), "cannot resolve package name" - elif not c.processed.containsOrIncl(url / tokens[2]): - work.add Dependency(name: toName(tokens[0]), url: url, commit: tokens[2], - rel: toDepRelation(tokens[1])) - -template toDestDir(p: PackageName): string = p.string - -proc collectDeps(c: var AtlasContext; work: var seq[Dependency]; - dep: Dependency; nimbleFile: string): string = - # If there is a .nimble file, return the dependency path & srcDir - # else return "". - assert nimbleFile != "" - let nimbleInfo = extractRequiresInfo(c, nimbleFile) - for r in nimbleInfo.requires: - var tokens: seq[string] = @[] - for token in tokenizeRequires(r): - tokens.add token - if tokens.len == 1: - # nimx uses dependencies like 'requires "sdl2"'. - # Via this hack we map them to the first tagged release. - # (See the `isStrictlySmallerThan` logic.) - tokens.add "<" - tokens.add InvalidCommit - elif tokens.len == 2 and tokens[1].startsWith("#"): - # Dependencies can also look like 'requires "sdl2#head" - var commit = tokens[1][1 .. ^1] - tokens[1] = "==" - tokens.add commit - - if tokens.len >= 3 and cmpIgnoreCase(tokens[0], "nim") != 0: - c.addUniqueDep work, tokens - result = toDestDir(dep.name) / nimbleInfo.srcDir - -proc collectNewDeps(c: var AtlasContext; work: var seq[Dependency]; - dep: Dependency; result: var seq[string]; - isMainProject: bool) = - let nimbleFile = findNimbleFile(c, dep) - if nimbleFile != "": - let x = collectDeps(c, work, dep, nimbleFile) - result.add x - else: - result.add toDestDir(dep.name) - -proc cloneLoop(c: var AtlasContext; work: var seq[Dependency]): seq[string] = - result = @[] - var i = 0 - while i < work.len: - let w = work[i] - let destDir = toDestDir(w.name) - let oldErrors = c.errors - - if not dirExists(c.workspace / destDir): - withDir c, c.workspace: - let err = cloneUrl(c, w.url, destDir, false) - if err != "": - error c, w.name, err - if oldErrors == c.errors: - if not c.keepCommits: checkoutCommit(c, w) - # even if the checkout fails, we can make use of the somewhat - # outdated .nimble file to clone more of the most likely still relevant - # dependencies: - collectNewDeps(c, work, w, result, i == 0) - inc i - -proc clone(c: var AtlasContext; start: string): seq[string] = - # non-recursive clone. - let url = toUrl(c, start) - var work = @[Dependency(name: toName(start), url: url, commit: "")] - - if url == "": - error c, toName(start), "cannot resolve package name" - return - - c.projectDir = c.workspace / toDestDir(work[0].name) - result = cloneLoop(c, work) - -const - configPatternBegin = "############# begin Atlas config section ##########\n" - configPatternEnd = "############# end Atlas config section ##########\n" - -proc patchNimCfg(c: var AtlasContext; deps: seq[string]; cfgPath: string) = - var paths = "--noNimblePath\n" - for d in deps: - let pkgname = toDestDir d.PackageName - let x = relativePath(c.workspace / pkgname, cfgPath, '/') - paths.add "--path:\"" & x & "\"\n" - var cfgContent = configPatternBegin & paths & configPatternEnd - - when MockupRun: - assert readFile(TestsDir / "nim.cfg") == cfgContent - c.mockupSuccess = true - else: - let cfg = cfgPath / "nim.cfg" - if cfgPath.len > 0 and not dirExists(cfgPath): - error(c, c.projectDir.PackageName, "could not write the nim.cfg") - elif not fileExists(cfg): - writeFile(cfg, cfgContent) - else: - let content = readFile(cfg) - let start = content.find(configPatternBegin) - if start >= 0: - cfgContent = content.substr(0, start-1) & cfgContent - let theEnd = content.find(configPatternEnd, start) - if theEnd >= 0: - cfgContent.add content.substr(theEnd+len(configPatternEnd)) - else: - cfgContent = content & "\n" & cfgContent - if cfgContent != content: - # do not touch the file if nothing changed - # (preserves the file date information): - writeFile(cfg, cfgContent) - -proc error*(msg: string) = - when defined(debug): - writeStackTrace() - quit "[Error] " & msg - -proc findSrcDir(c: var AtlasContext): string = - for nimbleFile in walkPattern("*.nimble"): - let nimbleInfo = extractRequiresInfo(c, nimbleFile) - return nimbleInfo.srcDir - return "" - -proc installDependencies(c: var AtlasContext; nimbleFile: string) = - # 1. find .nimble file in CWD - # 2. install deps from .nimble - var work: seq[Dependency] = @[] - let (path, pkgname, _) = splitFile(nimbleFile) - let dep = Dependency(name: toName(pkgname), url: "", commit: "") - discard collectDeps(c, work, dep, nimbleFile) - let paths = cloneLoop(c, work) - patchNimCfg(c, paths, if c.cfgHere: getCurrentDir() else: findSrcDir(c)) - -proc main = - var action = "" - var args: seq[string] = @[] - template singleArg() = - if args.len != 1: - error action & " command takes a single package name" - - template noArgs() = - if args.len != 0: - error action & " command takes no arguments" - - var c = AtlasContext( - projectDir: getCurrentDir(), - workspace: "") - - for kind, key, val in getopt(): - case kind - of cmdArgument: - if action.len == 0: - action = key.normalize - else: - args.add key - of cmdLongOption, cmdShortOption: - case normalize(key) - of "help", "h": writeHelp() - of "version", "v": writeVersion() - of "keepcommits": c.keepCommits = true - of "workspace": - if val.len > 0: - c.workspace = val - createDir(val) - else: - writeHelp() - of "cfghere": c.cfgHere = true - else: writeHelp() - of cmdEnd: assert false, "cannot happen" - - if c.workspace.len > 0: - if not dirExists(c.workspace): error "Workspace directory '" & c.workspace & "' not found." - else: - c.workspace = getCurrentDir() - while c.workspace.len > 0 and dirExists(c.workspace / ".git"): - c.workspace = c.workspace.parentDir() - echo "Using workspace ", c.workspace - - case action - of "": - error "No action." - of "clone": - singleArg() - let deps = clone(c, args[0]) - patchNimCfg c, deps, if c.cfgHere: getCurrentDir() else: findSrcDir(c) - when MockupRun: - if not c.mockupSuccess: - error "There were problems." - else: - if c.errors > 0: - error "There were problems." - of "install": - if args.len > 1: - error "install command takes a single argument" - var nimbleFile = "" - if args.len == 1: - nimbleFile = args[0] - else: - for x in walkPattern("*.nimble"): - nimbleFile = x - break - if nimbleFile.len == 0: - error "could not find a .nimble file" - installDependencies(c, nimbleFile) - of "refresh": - noArgs() - updatePackages(c) - of "search", "list": - updatePackages(c) - search getPackages(c.workspace), args - of "extract": - singleArg() - if fileExists(args[0]): - echo toJson(extractRequiresInfo(args[0])) - else: - error "File does not exist: " & args[0] - else: - error "Invalid action: " & action - -when isMainModule: - main() - -when false: - # some testing code for the `patchNimCfg` logic: - var c = AtlasContext( - projectDir: getCurrentDir(), - workspace: getCurrentDir().parentDir) - - patchNimCfg(c, @[PackageName"abc", PackageName"xyz"]) - -when false: - assert sameVersionAs("v0.2.0", "0.2.0") - assert sameVersionAs("v1", "1") - - assert sameVersionAs("1.90", "1.90") - - assert sameVersionAs("v1.2.3-zuzu", "1.2.3") - assert sameVersionAs("foo-1.2.3.4", "1.2.3.4") - - assert not sameVersionAs("foo-1.2.3.4", "1.2.3") - assert not sameVersionAs("foo", "1.2.3") - assert not sameVersionAs("", "1.2.3") diff --git a/tools/atlas/osutils.nim b/tools/atlas/osutils.nim deleted file mode 100644 index 6134830b5..000000000 --- a/tools/atlas/osutils.nim +++ /dev/null @@ -1,51 +0,0 @@ -## OS utilities like 'withDir'. -## (c) 2021 Andreas Rumpf - -import os, strutils, osproc - -proc isUrl*(x: string): bool = - x.startsWith("git://") or x.startsWith("https://") or x.startsWith("http://") - -proc cloneUrl*(url, dest: string; cloneUsingHttps: bool): string = - ## Returns an error message on error or else "". - result = "" - var modUrl = - if url.startsWith("git://") and cloneUsingHttps: - "https://" & url[6 .. ^1] - else: url - - # github + https + trailing url slash causes a - # checkout/ls-remote to fail with Repository not found - var isGithub = false - if modUrl.contains("github.com") and modUrl.endsWith("/"): - modUrl = modUrl[0 .. ^2] - isGithub = true - - let (_, exitCode) = execCmdEx("git ls-remote --quiet --tags " & modUrl) - var xcode = exitCode - if isGithub and exitCode != QuitSuccess: - # retry multiple times to avoid annoying github timeouts: - for i in 0..4: - os.sleep(4000) - xcode = execCmdEx("git ls-remote --quiet --tags " & modUrl)[1] - if xcode == QuitSuccess: break - - if xcode == QuitSuccess: - # retry multiple times to avoid annoying github timeouts: - let cmd = "git clone " & modUrl & " " & dest - for i in 0..4: - if execShellCmd(cmd) == 0: return "" - os.sleep(4000) - result = "exernal program failed: " & cmd - elif not isGithub: - let (_, exitCode) = execCmdEx("hg identify " & modUrl) - if exitCode == QuitSuccess: - let cmd = "hg clone " & modUrl & " " & dest - for i in 0..4: - if execShellCmd(cmd) == 0: return "" - os.sleep(4000) - result = "exernal program failed: " & cmd - else: - result = "Unable to identify url: " & modUrl - else: - result = "Unable to identify url: " & modUrl diff --git a/tools/atlas/packagesjson.nim b/tools/atlas/packagesjson.nim deleted file mode 100644 index 0b8599769..000000000 --- a/tools/atlas/packagesjson.nim +++ /dev/null @@ -1,114 +0,0 @@ - -import std / [json, os, sets, strutils] - -type - Package* = ref object - # Required fields in a package. - name*: string - url*: string # Download location. - license*: string - downloadMethod*: string - description*: string - tags*: seq[string] # \ - # From here on, optional fields set to the empty string if not available. - version*: string - dvcsTag*: string - web*: string # Info url for humans. - -proc optionalField(obj: JsonNode, name: string, default = ""): string = - if hasKey(obj, name) and obj[name].kind == JString: - result = obj[name].str - else: - result = default - -proc requiredField(obj: JsonNode, name: string): string = - result = optionalField(obj, name, "") - -proc fromJson*(obj: JSonNode): Package = - result = Package() - result.name = obj.requiredField("name") - if result.name.len == 0: return nil - result.version = obj.optionalField("version") - result.url = obj.requiredField("url") - if result.url.len == 0: return nil - result.downloadMethod = obj.requiredField("method") - if result.downloadMethod.len == 0: return nil - result.dvcsTag = obj.optionalField("dvcs-tag") - result.license = obj.optionalField("license") - result.tags = @[] - for t in obj["tags"]: - result.tags.add(t.str) - result.description = obj.requiredField("description") - result.web = obj.optionalField("web") - -const PackagesDir* = "packages" - -proc getPackages*(workspaceDir: string): seq[Package] = - result = @[] - var uniqueNames = initHashSet[string]() - var jsonFiles = 0 - for kind, path in walkDir(workspaceDir / PackagesDir): - if kind == pcFile and path.endsWith(".json"): - inc jsonFiles - let packages = json.parseFile(path) - for p in packages: - let pkg = p.fromJson() - if pkg != nil and not uniqueNames.containsOrIncl(pkg.name): - result.add(pkg) - -proc `$`*(pkg: Package): string = - result = pkg.name & ":\n" - result &= " url: " & pkg.url & " (" & pkg.downloadMethod & ")\n" - result &= " tags: " & pkg.tags.join(", ") & "\n" - result &= " description: " & pkg.description & "\n" - result &= " license: " & pkg.license & "\n" - if pkg.web.len > 0: - result &= " website: " & pkg.web & "\n" - -proc search*(pkgList: seq[Package]; terms: seq[string]) = - var found = false - template onFound = - echo pkg - found = true - break forPackage - - for pkg in pkgList: - if terms.len > 0: - block forPackage: - for term in terms: - let word = term.toLower - # Search by name. - if word in pkg.name.toLower: - onFound() - # Search by tag. - for tag in pkg.tags: - if word in tag.toLower: - onFound() - else: - echo(pkg) - - if not found and terms.len > 0: - echo("No package found.") - -type PkgCandidates* = array[3, seq[Package]] - -proc determineCandidates*(pkgList: seq[Package]; - terms: seq[string]): PkgCandidates = - result[0] = @[] - result[1] = @[] - result[2] = @[] - for pkg in pkgList: - block termLoop: - for term in terms: - let word = term.toLower - if word == pkg.name.toLower: - result[0].add pkg - break termLoop - elif word in pkg.name.toLower: - result[1].add pkg - break termLoop - else: - for tag in pkg.tags: - if word in tag.toLower: - result[2].add pkg - break termLoop diff --git a/tools/atlas/parse_requires.nim b/tools/atlas/parse_requires.nim deleted file mode 100644 index 7e26a1656..000000000 --- a/tools/atlas/parse_requires.nim +++ /dev/null @@ -1,101 +0,0 @@ -## Utility API for Nim package managers. -## (c) 2021 Andreas Rumpf - -import std / strutils -import ".." / compiler / [ast, idents, msgs, syntaxes, options, pathutils] - -type - NimbleFileInfo* = object - requires*: seq[string] - srcDir*: string - tasks*: seq[(string, string)] - -proc extract(n: PNode; conf: ConfigRef; result: var NimbleFileInfo) = - case n.kind - of nkStmtList, nkStmtListExpr: - for child in n: - extract(child, conf, result) - of nkCallKinds: - if n[0].kind == nkIdent: - case n[0].ident.s - of "requires": - for i in 1.. 0: ch = ch.lastSon - if ch.kind in {nkStrLit..nkTripleStrLit}: - result.requires.add ch.strVal - else: - localError(conf, ch.info, "'requires' takes string literals") - of "task": - if n.len >= 3 and n[1].kind == nkIdent and n[2].kind in {nkStrLit..nkTripleStrLit}: - result.tasks.add((n[1].ident.s, n[2].strVal)) - else: discard - of nkAsgn, nkFastAsgn: - if n[0].kind == nkIdent and cmpIgnoreCase(n[0].ident.s, "srcDir") == 0: - if n[1].kind in {nkStrLit..nkTripleStrLit}: - result.srcDir = n[1].strVal - else: - localError(conf, n[1].info, "assignments to 'srcDir' must be string literals") - else: - discard - -proc extractRequiresInfo*(nimbleFile: string): NimbleFileInfo = - ## Extract the `requires` information from a Nimble file. This does **not** - ## evaluate the Nimble file. Errors are produced on stderr/stdout and are - ## formatted as the Nim compiler does it. The parser uses the Nim compiler - ## as an API. The result can be empty, this is not an error, only parsing - ## errors are reported. - var conf = newConfigRef() - conf.foreignPackageNotes = {} - conf.notes = {} - conf.mainPackageNotes = {} - - let fileIdx = fileInfoIdx(conf, AbsoluteFile nimbleFile) - var parser: Parser - if setupParser(parser, fileIdx, newIdentCache(), conf): - extract(parseAll(parser), conf, result) - closeParser(parser) - -const Operators* = {'<', '>', '=', '&', '@', '!', '^'} - -proc token(s: string; idx: int; lit: var string): int = - var i = idx - if i >= s.len: return i - while s[i] in Whitespace: inc(i) - case s[i] - of Letters, '#': - lit.add s[i] - inc i - while i < s.len and s[i] notin (Whitespace + {'@', '#'}): - lit.add s[i] - inc i - of '0'..'9': - while i < s.len and s[i] in {'0'..'9', '.'}: - lit.add s[i] - inc i - of '"': - inc i - while i < s.len and s[i] != '"': - lit.add s[i] - inc i - inc i - of Operators: - while i < s.len and s[i] in Operators: - lit.add s[i] - inc i - else: - lit.add s[i] - inc i - result = i - -iterator tokenizeRequires*(s: string): string = - var start = 0 - var tok = "" - while start < s.len: - tok.setLen 0 - start = token(s, start, tok) - yield tok - -when isMainModule: - for x in tokenizeRequires("jester@#head >= 1.5 & <= 1.8"): - echo x diff --git a/tools/atlas/testdata.nim b/tools/atlas/testdata.nim deleted file mode 100644 index aefaeacd2..000000000 --- a/tools/atlas/testdata.nim +++ /dev/null @@ -1,63 +0,0 @@ - -type - PerDirData = object - dirname: string - cmd: Command - exitCode: int - output: string - -template toData(a, b, c, d): untyped = - PerDirData(dirname: a, cmd: b, exitCode: c, output: d) - -const - TestLog = [ - toData("balls", GitPull, 0, "Already up to date.\n"), - toData("grok", GitDiff, 0, ""), - toData("grok", GitTags, 0, "2ca193c31fa2377c1e991a080d60ca3215ff6cf0 refs/tags/0.0.1\n48007554b21ba2f65c726ae2fdda88d621865b4a refs/tags/0.0.2\n7092a0286421c7818cd335cca9ebc72d03d866c2 refs/tags/0.0.3\n62707b8ac684efac35d301dbde57dc750880268e refs/tags/0.0.4\n876f2504e0c2f785ffd2cf65a78e2aea474fa8aa refs/tags/0.0.5\nb7eb1f2501aa2382cb3a38353664a13af62a9888 refs/tags/0.0.6\nf5d818bfd6038884b3d8b531c58484ded20a58a4 refs/tags/0.1.0\n961eaddea49c3144d130d105195583d3f11fb6c6 refs/tags/0.2.0\n15ab8ed8d4f896232a976a9008548bd53af72a66 refs/tags/0.2.1\n426a7d7d4603f77ced658e73ad7f3f582413f6cd refs/tags/0.3.0\n83cf7a39b2fe897786fb0fe01a7a5933c3add286 refs/tags/0.3.1\n8d2e3c900edbc95fa0c036fd76f8e4f814aef2c1 refs/tags/0.3.2\n48b43372f49a3bb4dc0969d82a0fca183fb94662 refs/tags/0.3.3\n9ca947a3009ea6ba17814b20eb953272064eb2e6 refs/tags/0.4.0\n1b5643d04fba6d996a16d1ffc13d034a40003f8f refs/tags/0.5.0\n486b0eb580b1c465453d264ac758cc490c19c33e refs/tags/0.5.1\naedb0d9497390e20b9d2541cef2bb05a5cda7a71 refs/tags/0.5.2\n"), - toData("grok", GitCurrentCommit, 0, "349c15fd1e03f1fcdd81a1edefba3fa6116ab911\n"), - toData("grok", GitMergeBase, 0, "349c15fd1e03f1fcdd81a1edefba3fa6116ab911\n1b5643d04fba6d996a16d1ffc13d034a40003f8f\n349c15fd1e03f1fcdd81a1edefba3fa6116ab911\n"), - toData("grok", GitCheckout, 0, "1b5643d04fba6d996a16d1ffc13d034a40003f8f"), # watch out! - - toData("ups", GitDiff, 0, ""), - toData("ups", GitTags, 0, "4008f9339cd22b30e180bc87a6cca7270fd28ac1 refs/tags/0.0.2\n19bc490c22b4f5b0628c31cdedead1375b279356 refs/tags/0.0.3\nff34602aaea824cb46d6588cd5fe1178132e9702 refs/tags/0.0.4\n09de599138f20b745133b6e4fe563e204415a7e8 refs/tags/0.0.5\n85fee3b74798311108a105635df31f892150f5d0 refs/tags/0.0.6\nfd303913b22b121dc42f332109e9c44950b9acd4 refs/tags/0.0.7\n"), - toData("ups", GitCurrentCommit, 0, "74c31af8030112dac758440aa51ef175992f71f3\n"), - toData("ups", GitMergeBase, 0, "74c31af8030112dac758440aa51ef175992f71f3\n4008f9339cd22b30e180bc87a6cca7270fd28ac1\n74c31af8030112dac758440aa51ef175992f71f3\n"), - toData("ups", GitCheckout, 0, "4008f9339cd22b30e180bc87a6cca7270fd28ac1"), - - toData("sync", GitDiff, 0, ""), - toData("sync", GitRevParse, 0, "810bd2d75e9f6e182534ae2488670b51a9f13fc3\n"), - toData("sync", GitCurrentCommit, 0, "de5c7337ebc22422190e8aeca37d05651735f440\n"), - toData("sync", GitMergeBase, 0, "de5c7337ebc22422190e8aeca37d05651735f440\n810bd2d75e9f6e182534ae2488670b51a9f13fc3\n810bd2d75e9f6e182534ae2488670b51a9f13fc3\n"), - - toData("npeg", GitDiff, 0, ""), - toData("npeg", GitTags, 0, "8df2f0c9391995fd086b8aab00e8ab7aded1e8f0 refs/tags/0.1.0\n4c959a72db5283b55eeef491076eefb5e02316f1 refs/tags/0.10.0\n802f47c0f7f4318a4f0858ba5a6a6ed2333bde71 refs/tags/0.11.0\n82c8d92837108dce225358ace2c416bf9a3f30ce refs/tags/0.12.0\n87d2f2c4f6ef7da350d45beb5a336611bde7f518 refs/tags/0.13.0\n39964f0d220bfaade47a568bf03c1cf28aa2bc37 refs/tags/0.14.0\nbe9f03f92304cbeab70572944a8563db9b23b2fb refs/tags/0.14.1\na933fb9832566fc95273e417597bfb4faf564ca6 refs/tags/0.15.0\n6aad2e438c52ff0636c7bfb64338e444ac3e83ba refs/tags/0.16.0\nf4ddffb5848c42c6151743dd9c7eddcaaabc56cc refs/tags/0.17.0\n30b446b39442cdbc53a97018ab8a54149aa7c3b7 refs/tags/0.17.1\n1a9d36aa3b34a6169d4530463f1c17a3fe1e075e refs/tags/0.18.0\ndd34f903a9a63b876cb2db19b7a4ce0bcc252134 refs/tags/0.19.0\nd93d49c81fc8722d7929ac463b435c0f2e10c53b refs/tags/0.2.0\neeae7746c9b1118bcf27744ab2aee26969051256 refs/tags/0.20.0\n8c3471a548129f3bf62df15cd0fd8cca1787d852 refs/tags/0.21.0\nc0e873a17bc713c80e74fec3c30cb62dcd5d194a refs/tags/0.21.1\nbae84c47a1bb259b209b6f6be1582327b784539d refs/tags/0.21.2\nbfcb4bcae76a917c3c88736ca773e4cb67dbb2d8 refs/tags/0.21.3\n0eabb7c462d30932049f0b7e6a030c1562cf9fee refs/tags/0.22.0\n2e75367095f54d4351005078bad98041a55b14c1 refs/tags/0.22.1\n814ea235dd398108d7b18f966694c3d951575701 refs/tags/0.22.2\na812064587d983c129737f8500bf74990e6b8dab refs/tags/0.23.0\nbd969ad3745db0d66022564cac76cf9424651104 refs/tags/0.23.1\na037c646a47623b92718efadc2bb74d03664b360 refs/tags/0.23.2\n078475ccceeaca0fac947492acdd24514da8d863 refs/tags/0.24.0\ne7bd87dc992512fd5825a557a56907647e03c979 refs/tags/0.24.1\n45ea601e1c7f64fb857bc99df984b86673621d2c refs/tags/0.3.0\n1ea9868a3fee3aa487ab7ec9129208a4dd483d0d refs/tags/0.4.0\n39afdb5733d3245386d29d08c5ff61c89268f499 refs/tags/0.5.0\n458c7b5910fcb157af3fc51bc3b3e663fdb3ed4a refs/tags/0.6.0\n06c38bd8563d822455bc237c2a98c153d938ed1b refs/tags/0.7.0\nf446b6056eef6d8dc9d8b47a79aca93d17dc8230 refs/tags/0.8.0\nbb25a195133f9f7af06386d0809793923cc5e8ab refs/tags/0.9.0\n"), - toData("npeg", GitCurrentCommit, 0, "5d80f93aa720898936668b3bc47d0fff101ec414\n"), - toData("npeg", GitMergeBase, 0, "5d80f93aa720898936668b3bc47d0fff101ec414\na037c646a47623b92718efadc2bb74d03664b360\na037c646a47623b92718efadc2bb74d03664b360\n"), - - toData("testes", GitDiff, 0, ""), - toData("testes", GitTags, 0, "3ce9b2968b5f644755a0ced1baa3eece88c2f12e refs/tags/0.1.0\nf73af8318b54737678fab8b54bdcd8a451015e0d refs/tags/0.1.1\nd21d84d37b161a123a43318bae353108755916de refs/tags/0.1.2\n5c36b6095353ed03b08ac939d00aff2d73f79a35 refs/tags/0.1.3\na1220d11237ee8f135f772ff9731c11b2d91ba31 refs/tags/0.1.4\n574f741b90d04a7ce8c9b990e6077708d7ad076e refs/tags/0.1.5\nced0a9e58234b680def6931578e09165a32e6291 refs/tags/0.1.6\nbb248952e8742a6011eb1a45a9d2059aeb0341d7 refs/tags/0.1.7\nabb7d7c552da0a8e0ddc586c15ccf7e74b0d068b refs/tags/0.10.0\n6e42a768a90d6442196b344bcdcb6f834b76e7b7 refs/tags/0.2.0\n9d136c3a0851ca2c021f5fb4f7b63f0a0ef77232 refs/tags/0.2.1\ndcb282b2da863fd2939e1969cec7a99788feb456 refs/tags/0.2.2\nf708a632afaa40a322a1a61c1c13722edac8e8c5 refs/tags/0.3.0\n3213f59e3f9ba052452c59f01d1418360d856af6 refs/tags/0.3.1\nf7bb1743dffd327958dfcebae4cfb6f61cc1cb8c refs/tags/0.3.2\n6b64569ebecad6bc60cc8697713701e7659204f4 refs/tags/0.3.3\nb51c25a4367bd17f419f78cb5a27f319e9d820f5 refs/tags/0.3.4\nb265612710cbd5ddb1b173c94ece8ec5c7ceccac refs/tags/0.3.5\ne404bcfe42e92d7509717a2dfa115cacb4964c5d refs/tags/0.3.6\n5e4d0d5b7e7f314dde701c546c4365c59782d3dc refs/tags/0.3.7\ne13f91c9c913d2b81c59adeaad687efa2b35293a refs/tags/0.3.8\n17599625f09af0ae4b525e63ab726a3002540702 refs/tags/0.3.9\n13e907f70571dd146d8dc29ddec4599b40ba4e85 refs/tags/0.4.0\n155a74cf676495df1e0674dd07b5e4a0291a9a4a refs/tags/0.4.1\nf37abccdc148cb02ca637a6f0bc8821491cce358 refs/tags/0.4.2\n0250d29ebdd02f28f9020445adb5a4e51fd1902c refs/tags/0.5.0\n2fb87db6d9f34109a70205876030c53f815739b7 refs/tags/0.5.1\n629d17ba8d6a1a4eca8145eb089ed5bca4473dfc refs/tags/0.6.0\ne926130f5f1b7903f68be49cc1563225bd9d948d refs/tags/0.7.0\n7365303897e6185796c274425c079916047e3f14 refs/tags/0.7.1\na735c4adabeba637409f41c4325dd8fc5fb91e2d refs/tags/0.7.10\nfe023fd27404889c5122f902456cbba14b767405 refs/tags/0.7.11\n4430e72972c77a5e9c1555d59bba11d840682691 refs/tags/0.7.12\nf0e53eb490a9558c7f594d2e095b70665e36ca88 refs/tags/0.7.13\nf6520e25e7c329c2957cda447f149fc6a930db0d refs/tags/0.7.2\nd509762f7191757c240d3c79c9ecda53f8c0cfe3 refs/tags/0.7.3\nc02e7a783d1c42fd1f91bca7142f7c3733950c05 refs/tags/0.7.4\n8c8a9e496e9b86ba7602709438980ca31e6989d9 refs/tags/0.7.5\n29839c18b4ac83c0111a178322b57ebb8a8d402c refs/tags/0.7.6\n3b62973cf74fafd8ea906644d89ac34d29a8a6cf refs/tags/0.7.7\ne67ff99dc43c391e89a37f97a9d298c3428bbde2 refs/tags/0.7.8\n4b72ecda0d40ed8e5ab8ad4095a0691d30ec6cd0 refs/tags/0.7.9\n2512b8cc3d7f001d277e89978da2049a5feee5c4 refs/tags/0.8.0\n86c47029690bd2731d204245f3f54462227bba0d refs/tags/0.9.0\n9a7f94f78588e9b5ba7ca077e1f7eae0607c6cf6 refs/tags/0.9.1\n08c915dc016d16c1dfa9a77d0b045ec29c9f2074 refs/tags/0.9.2\n3fb658b1ce1e1efa37d6f9f14322bdac8def02a5 refs/tags/0.9.3\n738fda0add962379ffe6aa6ca5f01a6943a98a2e refs/tags/0.9.4\n48d821add361f7ad768ecb35a0b19c38f90c919e refs/tags/0.9.5\nff9ae890f597dac301b2ac6e6805eb9ac5afd49a refs/tags/0.9.6\n483c78f06e60b0ec5e79fc3476df075ee7286890 refs/tags/0.9.7\n416eec87a5ae39a1a6035552e9e9a47d76b13026 refs/tags/1.0.0\na935cfe9445cc5218fbdd7e0afb35aa1587fff61 refs/tags/1.0.1\n4b83863a9181f054bb695b11b5d663406dfd85d2 refs/tags/1.0.2\n295145fddaa4fe29c1e71a5044d968a84f9dbf69 refs/tags/1.1.0\n8f74ea4e5718436c47305b4488842e6458a13dac refs/tags/1.1.1\n4135bb291e53d615a976e997c44fb2bd9e1ad343 refs/tags/1.1.10\n8c09dbcd16612f5989065db02ea2e7a752dd2656 refs/tags/1.1.11\naedfebdb6c016431d84b0c07cf181b957a900640 refs/tags/1.1.12\n2c2e958366ef6998115740bdf110588d730e5738 refs/tags/1.1.2\nbecc77258321e6ec40d89efdddf37bafd0d07fc3 refs/tags/1.1.3\ne070d7c9853bf94c35b81cf0c0a8980c2449bb22 refs/tags/1.1.4\n12c986cbbf65e8571a486e9230808bf887e5f04f refs/tags/1.1.5\n63df8986f5b56913b02d26954fa033eeaf43714c refs/tags/1.1.6\n38e02c9c6bd728b043036fe0d1894d774cab3108 refs/tags/1.1.7\n3c3879fff16450d28ade79a6b08982bf5cefc061 refs/tags/1.1.8\ne32b811b3b2e70a1d189d7a663bc2583e9c18f96 refs/tags/1.1.9\n0c1b4277c08197ce7e7e0aa2bad91d909fcd96ac refs/tags/2.0.0\n"), - toData("testes", GitCurrentCommit, 0, "d9db2ad09aa38fc26625341e1b666602959e144f\n"), - toData("testes", GitMergeBase, 0, "d9db2ad09aa38fc26625341e1b666602959e144f\n416eec87a5ae39a1a6035552e9e9a47d76b13026\nd9db2ad09aa38fc26625341e1b666602959e144f\n"), - toData("testes", GitCheckout, 0, "416eec87a5ae39a1a6035552e9e9a47d76b13026"), - - toData("grok", GitDiff, 0, ""), - toData("grok", GitTags, 0, "2ca193c31fa2377c1e991a080d60ca3215ff6cf0 refs/tags/0.0.1\n48007554b21ba2f65c726ae2fdda88d621865b4a refs/tags/0.0.2\n7092a0286421c7818cd335cca9ebc72d03d866c2 refs/tags/0.0.3\n62707b8ac684efac35d301dbde57dc750880268e refs/tags/0.0.4\n876f2504e0c2f785ffd2cf65a78e2aea474fa8aa refs/tags/0.0.5\nb7eb1f2501aa2382cb3a38353664a13af62a9888 refs/tags/0.0.6\nf5d818bfd6038884b3d8b531c58484ded20a58a4 refs/tags/0.1.0\n961eaddea49c3144d130d105195583d3f11fb6c6 refs/tags/0.2.0\n15ab8ed8d4f896232a976a9008548bd53af72a66 refs/tags/0.2.1\n426a7d7d4603f77ced658e73ad7f3f582413f6cd refs/tags/0.3.0\n83cf7a39b2fe897786fb0fe01a7a5933c3add286 refs/tags/0.3.1\n8d2e3c900edbc95fa0c036fd76f8e4f814aef2c1 refs/tags/0.3.2\n48b43372f49a3bb4dc0969d82a0fca183fb94662 refs/tags/0.3.3\n9ca947a3009ea6ba17814b20eb953272064eb2e6 refs/tags/0.4.0\n1b5643d04fba6d996a16d1ffc13d034a40003f8f refs/tags/0.5.0\n486b0eb580b1c465453d264ac758cc490c19c33e refs/tags/0.5.1\naedb0d9497390e20b9d2541cef2bb05a5cda7a71 refs/tags/0.5.2\n"), - toData("grok", GitCurrentCommit, 0, "4e6526a91a23eaec778184e16ce9a34d25d48bdc\n"), - toData("grok", GitMergeBase, 0, "4e6526a91a23eaec778184e16ce9a34d25d48bdc\n62707b8ac684efac35d301dbde57dc750880268e\n349c15fd1e03f1fcdd81a1edefba3fa6116ab911\n"), - toData("grok", GitCheckout, 0, "62707b8ac684efac35d301dbde57dc750880268e"), - - toData("nim-bytes2human", GitDiff, 0, ""), - toData("nim-bytes2human", GitTags, 0, ""), - toData("nim-bytes2human", GitCurrentcommit, 0, "ec2c1a758cabdd4751a06c8ebf2b923f19e32731\n") - ] - -#[ -Current directory is now E:\atlastest\nim-bytes2human -cmd git diff args [] --> ("", 0) -cmd git show-ref --tags args [] --> ("", 1) -cmd git log -n 1 --format=%H args [] --> (, 0) -[Warning] (nim-bytes2human) package has no tagged releases -nimble E:\atlastest\nim-bytes2human\bytes2human.nimble info (requires: @["nim >= 1.0.0"], srcDir: "src", tasks: @[]) -[Error] There were problems. -Error: execution of an external program failed: 'E:\nim\tools\atlas\atlas.exe clone https://github.com/disruptek/balls' -]# diff --git a/tools/atlas/tests/balls.nimble b/tools/atlas/tests/balls.nimble deleted file mode 100644 index 143e757e9..000000000 --- a/tools/atlas/tests/balls.nimble +++ /dev/null @@ -1,32 +0,0 @@ -version = "3.4.1" -author = "disruptek" -description = "a unittest framework with balls 🔴🟡🟢" -license = "MIT" - -# requires newTreeFrom -requires "https://github.com/disruptek/grok >= 0.5.0 & < 1.0.0" -requires "https://github.com/disruptek/ups < 1.0.0" -requires "https://github.com/planetis-m/sync#810bd2d" -#requires "https://github.com/c-blake/cligen < 2.0.0" - -bin = @["balls"] # build the binary for basic test running -installExt = @["nim"] # we need to install balls.nim also -skipDirs = @["tests"] # so stupid... who doesn't want tests? -#installFiles = @["balls.nim"] # https://github.com/nim-lang/Nim/issues/16661 - -task test, "run tests for ci": - when defined(windows): - exec "balls.cmd" - else: - exec "balls" - -task demo, "produce a demo": - exec "nim c --define:release balls.nim" - when (NimMajor, NimMinor) != (1, 0): - echo "due to nim bug #16307, use nim-1.0" - quit 1 - exec """demo docs/demo.svg "nim c --out=\$1 examples/fails.nim"""" - exec """demo docs/clean.svg "nim c --define:danger -f --out=\$1 tests/test.nim"""" - exec "nim c --define:release --define:ballsDry balls.nim" - exec """demo docs/runner.svg "balls"""" - diff --git a/tools/atlas/tests/grok.nimble b/tools/atlas/tests/grok.nimble deleted file mode 100644 index 1b6d77c08..000000000 --- a/tools/atlas/tests/grok.nimble +++ /dev/null @@ -1,5 +0,0 @@ -version = "0.0.4" -author = "disruptek" -description = "don't read too much into it" -license = "MIT" -requires "nim >= 1.0.0" diff --git a/tools/atlas/tests/nim-bytes2human.nimble b/tools/atlas/tests/nim-bytes2human.nimble deleted file mode 100644 index 9f3ae2479..000000000 --- a/tools/atlas/tests/nim-bytes2human.nimble +++ /dev/null @@ -1,7 +0,0 @@ -version = "0.2.2" -author = "Juan Carlos" -description = "Convert bytes to kilobytes, megabytes, gigabytes, etc." -license = "MIT" -srcDir = "src" - -requires "nim >= 1.0.0" # https://github.com/juancarlospaco/nim-bytes2human/issues/2#issue-714338524 diff --git a/tools/atlas/tests/nim.cfg b/tools/atlas/tests/nim.cfg deleted file mode 100644 index 5f568569b..000000000 --- a/tools/atlas/tests/nim.cfg +++ /dev/null @@ -1,11 +0,0 @@ -############# begin Atlas config section ########## ---noNimblePath ---path:"../balls" ---path:"../grok" ---path:"../ups" ---path:"../sync" ---path:"../npeg/src" ---path:"../testes" ---path:"../grok" ---path:"../nim-bytes2human/src" -############# end Atlas config section ########## diff --git a/tools/atlas/tests/npeg.nimble b/tools/atlas/tests/npeg.nimble deleted file mode 100644 index e71fc5aa5..000000000 --- a/tools/atlas/tests/npeg.nimble +++ /dev/null @@ -1,48 +0,0 @@ -# Package - -version = "0.24.1" -author = "Ico Doornekamp" -description = "a PEG library" -license = "MIT" -srcDir = "src" -installExt = @["nim"] - -# Dependencies - -requires "nim >= 0.19.0" - -# Test - -task test, "Runs the test suite": - exec "nimble testc && nimble testcpp && nimble testarc && nimble testjs" - -task testc, "C tests": - exec "nim c -r tests/tests.nim" - -task testcpp, "CPP tests": - exec "nim cpp -r tests/tests.nim" - -task testjs, "JS tests": - exec "nim js -r tests/tests.nim" - -task testdanger, "Runs the test suite in danger mode": - exec "nim c -d:danger -r tests/tests.nim" - -task testwin, "Mingw tests": - exec "nim c -d:mingw tests/tests.nim && wine tests/tests.exe" - -task test32, "32 bit tests": - exec "nim c --cpu:i386 --passC:-m32 --passL:-m32 tests/tests.nim && tests/tests" - -task testall, "Test all": - exec "nimble test && nimble testcpp && nimble testdanger && nimble testjs && nimble testwin" - -when (NimMajor, NimMinor) >= (1, 1): - task testarc, "--gc:arc tests": - exec "nim c --gc:arc -r tests/tests.nim" -else: - task testarc, "--gc:arc tests": - exec "true" - -task perf, "Test performance": - exec "nim cpp -r -d:danger tests/performance.nim" diff --git a/tools/atlas/tests/packages/packages.json b/tools/atlas/tests/packages/packages.json deleted file mode 100644 index d054a201b..000000000 --- a/tools/atlas/tests/packages/packages.json +++ /dev/null @@ -1,36 +0,0 @@ -[ - { - "name": "bytes2human", - "url": "https://github.com/juancarlospaco/nim-bytes2human", - "method": "git", - "tags": [ - "bytes", - "human", - "minimalism", - "size" - ], - "description": "Convert bytes to kilobytes, megabytes, gigabytes, etc.", - "license": "LGPLv3", - "web": "https://github.com/juancarlospaco/nim-bytes2human" - }, - { - "name": "npeg", - "url": "https://github.com/zevv/npeg", - "method": "git", - "tags": [ - "PEG", - "parser", - "parsing", - "regexp", - "regular", - "grammar", - "lexer", - "lexing", - "pattern", - "matching" - ], - "description": "PEG (Parsing Expression Grammars) string matching library for Nim", - "license": "MIT", - "web": "https://github.com/zevv/npeg" - } -] diff --git a/tools/atlas/tests/sync.nimble b/tools/atlas/tests/sync.nimble deleted file mode 100644 index a07ae8925..000000000 --- a/tools/atlas/tests/sync.nimble +++ /dev/null @@ -1,10 +0,0 @@ -# Package - -version = "1.4.0" -author = "Antonis Geralis" -description = "Useful synchronization primitives." -license = "MIT" - -# Deps - -requires "nim >= 1.0.0" diff --git a/tools/atlas/tests/testes.nimble b/tools/atlas/tests/testes.nimble deleted file mode 100644 index 60fe1d508..000000000 --- a/tools/atlas/tests/testes.nimble +++ /dev/null @@ -1,23 +0,0 @@ -version = "1.0.0" -author = "disruptek" -description = "a cure for salty testes" -license = "MIT" - -#requires "cligen >= 0.9.41 & <= 0.9.45" -#requires "bump >= 1.8.18 & < 2.0.0" -requires "https://github.com/disruptek/grok >= 0.0.4 & < 1.0.0" -requires "https://github.com/juancarlospaco/nim-bytes2human" - -bin = @["testes"] # build the binary for basic test running -installExt = @["nim"] # we need to install testes.nim also -skipDirs = @["tests"] # so stupid... who doesn't want tests? - -task test, "run tests for ci": - exec "nim c --run testes.nim" - -task demo, "produce a demo": - when (NimMajor, NimMinor) != (1, 0): - echo "due to nim bug #16307, use nim-1.0" - quit 1 - exec """demo docs/demo.svg "nim c --out=\$1 examples/balls.nim"""" - exec """demo docs/clean.svg "nim c --define:danger --out=\$1 tests/testicles.nim"""" diff --git a/tools/atlas/tests/ups.nimble b/tools/atlas/tests/ups.nimble deleted file mode 100644 index d91abbe60..000000000 --- a/tools/atlas/tests/ups.nimble +++ /dev/null @@ -1,13 +0,0 @@ -version = "0.0.2" -author = "disruptek" -description = "a package handler" -license = "MIT" - -requires "npeg >= 0.23.2 & < 1.0.0" -requires "https://github.com/disruptek/testes >= 1.0.0 & < 2.0.0" - -task test, "run tests": - when defined(windows): - exec "testes.cmd" - else: - exec findExe"testes" diff --git a/tools/ci_generate.nim b/tools/ci_generate.nim deleted file mode 100644 index 46bc39470..000000000 --- a/tools/ci_generate.nim +++ /dev/null @@ -1,141 +0,0 @@ -##[ -avoid code duplication in CI pipelines. -For now, this is only used for openbsd + freebsd, but there is a lot of other code -duplication that could be removed. - -## usage -edit this file as needed and then re-generate via: -``` -nim r tools/ci_generate.nim -``` -]## - -import std/[strformat, os] - -const doNotEdit = "DO NO EDIT DIRECTLY! auto-generated by `nim r tools/ci_generate.nim`" -proc genCiBsd(header: string, batch: int, num: int): string = - result = fmt""" -## {doNotEdit} - -{header} - -sources: -- https://github.com/nim-lang/Nim -environment: - NIM_TESTAMENT_BATCH: "{batch}_{num}" - CC: /usr/bin/clang -tasks: -- setup: | - set -e - cd Nim - . ci/funs.sh && nimBuildCsourcesIfNeeded - echo 'export PATH=$HOME/Nim/bin:$PATH' >> $HOME/.buildenv -- test: | - set -e - cd Nim - . ci/funs.sh && nimInternalBuildKochAndRunCI -triggers: -- action: email - condition: failure - to: Andreas Rumpf -""" - -proc genBuildExtras(echoRun, koch, nim: string): string = - result = fmt""" -{echoRun} {nim} c --noNimblePath --skipUserCfg --skipParentCfg --hints:off koch -{echoRun} {koch} boot -d:release --skipUserCfg --skipParentCfg --hints:off -{echoRun} {koch} tools --skipUserCfg --skipParentCfg --hints:off -""" - -proc genWindowsScript(buildAll: bool): string = - result = fmt""" -@echo off -rem {doNotEdit} -rem Build development version of the compiler; can be rerun safely -rem bare bones version of ci/funs.sh adapted for windows. - -rem Read in some common shared variables (shared with other tools), -rem see https://stackoverflow.com/questions/3068929/how-to-read-file-contents-into-a-variable-in-a-batch-file -for /f "delims== tokens=1,2" %%G in (config/build_config.txt) do set %%G=%%H -SET nim_csources=bin\nim_csources_%nim_csourcesHash%.exe -echo "building from csources: %nim_csources%" - -if not exist %nim_csourcesDir% ( - git clone -q --depth 1 -b %nim_csourcesBranch% %nim_csourcesUrl% %nim_csourcesDir% -) - -if not exist %nim_csources% ( - cd %nim_csourcesDir% - git checkout %nim_csourcesHash% - echo "%PROCESSOR_ARCHITECTURE%" - if "%PROCESSOR_ARCHITECTURE%"=="AMD64" ( - SET ARCH=64 - ) - CALL build.bat - cd .. - copy /y bin\nim.exe %nim_csources% -) -""" - - if buildAll: - result.add genBuildExtras("", "koch", r"bin\nim.exe") - -proc genPosixScript(): string = - result = fmt""" -#!/bin/sh -# {doNotEdit} - -# build development version of the compiler; can be rerun safely. -# arguments can be passed, e.g.: -# CC=gcc ucpu=amd64 uos=darwin - -set -u # error on undefined variables -set -e # exit on first error - -. ci/funs.sh -nimBuildCsourcesIfNeeded "$@" - -{genBuildExtras("echo_run", "./koch", "bin/nim")} -""" - -proc main()= - let dir = ".builds" - # not too large to be resource friendly, refs bug #17107 - let num = 2 - # if you reduce this, make sure to remove files that shouldn't be generated, - # or better, do the cleanup logic here e.g.: `rm .builds/openbsd_*` - let headerFreebsd = """ -# see https://man.sr.ht/builds.sr.ht/compatibility.md#freebsd -image: freebsd/latest -packages: -- databases/sqlite3 -- devel/boehm-gc-threaded -- devel/pcre -- devel/sdl20 -- devel/sfml -- www/node -- devel/gmake -""" - - let headerOpenbsd = """ -image: openbsd/latest -packages: -- gmake -- sqlite3 -- node -- boehm-gc -- pcre -- sfml -- sdl2 -- libffi -""" - - for i in 0.. lldb.SBValue: - if isinstance(name, str): - return self.GetChildMemberWithName(name) - else: - return self.GetChildAtIndex(name) - - -# Make this easier to work with -lldb.SBValue.__getitem__ = sbvaluegetitem - - -def colored(in_str, *args, **kwargs): - # TODO: Output in color if user is in terminal - return in_str - - -def reprEnum(val, typ): - """ - this is a port of the nim runtime function `reprEnum` to python - NOTE: DOES NOT WORK WITH ORC - """ - val = int(val) - n = typ["node"] - sons_type = n["sons"].type.GetPointeeType().GetPointeeType() - sons = n["sons"].deref.Cast(sons_type.GetPointerType().GetArrayType(3)) - flags = int(typ["flags"].unsigned) - # 1 << 6 is {ntfEnumHole} - if ((1 << 6) & flags) == 0: - offset = val - sons[0]["offset"].unsigned - if offset >= 0 and 0 < n["len"].unsigned: - return NCSTRING(sons[offset]["name"])[1:-1] - else: - # ugh we need a slow linear search: - for i in range(n["len"].unsigned): - if sons[i]["offset"].unsigned == val: - return NCSTRING(sons[i]["name"])[1:-1] - - return str(val) + " (invalid data!)" - - -def get_nti(value, nim_name=None): - """DOES NOT WORK WITH ORC""" - name_split = value.type.name.split("_") - type_nim_name = nim_name or name_split[1] - id_string = name_split[-1].split(" ")[0] - - type_info_name = "NTI" + type_nim_name.lower() + "__" + id_string + "_" - print("TYPEINFONAME: ", type_info_name) - nti = value.target.FindFirstGlobalVariable(type_info_name) - if nti is None: - type_info_name = "NTI" + "__" + id_string + "_" - nti = value.target.FindFirstGlobalVariable(type_info_name) - if nti is None: - print( - f"NimEnumPrinter: lookup global symbol: '{type_info_name}' failed for {value.type.name}.\n" - ) - return type_nim_name, nti - - -def enum_to_string(value): - type_nim_name, nti = get_nti(value) - if nti is None: - return type_nim_name + "(" + str(value.unsigned) + ")" - return reprEnum(value.signed, nti), nti - - -def to_string(value): - # For getting NimStringDesc * value - data = value["data"] - try: - size = int(value["Sup"]["len"].unsigned) - if size > 2**14: - return None - except TypeError: - return None - - cast = data.Cast(value.target.FindFirstType("char").GetArrayType(size)) - return bytearray(cast.data.uint8s).decode("utf-8") - - -def to_stringV2(value: lldb.SBValue): - # For getting NimStringDesc * value - data = value["p"]["data"] - try: - size = int(value["len"].signed) - if size > 2**14: - return "... (too long)" - except TypeError: - return "" - - base_data_type = data.type.GetArrayElementType().GetTypedefedType() - cast = data.Cast(base_data_type.GetArrayType(size)) - return bytearray(cast.data.uint8s).decode("utf-8") - - -def NimStringDesc(value, internal_dict): - res = to_string(value) - if res: - return colored('"' + res + '"', "red") - else: - return str(value) - - -def NimStringV2(value: lldb.SBValue, internal_dict): - res = to_stringV2(value.GetNonSyntheticValue()) - if res is not None: - return colored('"' + res + '"', "red") - else: - return str(value) - - -def NCSTRING(value: lldb.SBValue, internal_dict=None): - ty = value.Dereference().type - val = value.target.CreateValueFromAddress( - value.name or "temp", lldb.SBAddress(value.unsigned, value.target), ty - ).AddressOf() - return val.summary - - -def ObjectV1(value, internal_dict): - if not value.num_children and not value.value: - return "" - - ignore_fields = set() - if "colonObjectType" in value.type.name: - value = value.Dereference() - ignore_fields.add("Sup") - - if not value.type.name: - return "" - - summary = value.summary - if summary is not None: - return summary - - if "_" in value.type.name: - obj_name = value.type.name.split("_")[1].replace("colonObjectType", "") - else: - obj_name = value.type.name - - obj_name = colored(obj_name, "green") - - num_children = value.num_children - - fields = ", ".join( - [ - value[i].name - + ": " - + (value[i].summary or value[i].value or value[i].type.name or "not found") - for i in range(num_children) - if value[i].name not in ignore_fields - ] - ) - - res = f"{obj_name}({fields})" - return res - - -def ObjectV2(value: lldb.SBValue, internal_dict): - custom_summary = get_summary(value) - if not custom_summary is None: - return custom_summary - - orig_value = value.GetNonSyntheticValue() - while orig_value.type.is_pointer: - orig_value = orig_value.Dereference() - - if "_" in orig_value.type.name: - obj_name = orig_value.type.name.split("_")[1].replace("colonObjectType", "") - else: - obj_name = orig_value.type.name - - num_children = value.num_children - fields = [] - - for i in range(num_children): - fields.append(f"{value[i].name}: {value[i].summary}") - - res = f"{obj_name}(" + ", ".join(fields) + ")" - return res - - -def Number(value: lldb.SBValue, internal_dict): - while value.type.is_pointer: - value = value.Dereference() - return colored(str(value.signed), "yellow") - - -def Float(value: lldb.SBValue, internal_dict): - while value.type.is_pointer: - value = value.Dereference() - return colored(str(value.value), "yellow") - - -def UnsignedNumber(value: lldb.SBValue, internal_dict): - while value.type.is_pointer: - value = value.Dereference() - return colored(str(value.unsigned), "yellow") - - -def Bool(value: lldb.SBValue, internal_dict): - while value.type.is_pointer: - value = value.Dereference() - return colored(str(value.GetValue()), "red") - - -def CharArray(value: lldb.SBValue, internal_dict): - return str([colored(f"'{char}'", "red") for char in value.uint8s]) - - -def Array(value: lldb.SBValue, internal_dict): - value = value.GetNonSyntheticValue() - return "[" + ", ".join([value[i].summary for i in range(value.num_children)]) + "]" - - -def Tuple(value: lldb.SBValue, internal_dict): - while value.type.is_pointer: - value = value.Dereference() - - num_children = value.num_children - - fields = [] - - for i in range(num_children): - key = value[i].name - val = value[i].summary - if key.startswith("Field"): - fields.append(f"{val}") - else: - fields.append(f"{key}: {val}") - - return "(" + ", ".join(fields) + f")" - - -def Enum(value, internal_dict): - tname = value.type.name.split("_")[1] - return colored(f"{tname}." + str(value.signed), "blue") - - -def EnumSet(value, internal_dict): - type_nim_name = value.type.name.split("_")[2] - # type_nim_name, nti = get_nti(value, type_nim_name) - - val = int(value.signed) - # if nti: - # enum_strings = [] - # i = 0 - # while val > 0: - # if (val & 1) == 1: - # enum_strings.append(reprEnum(i, nti)) - # val = val >> 1 - # i += 1 - - # return '{' + ', '.join(enum_strings) + '}' - return colored(f"{type_nim_name}." + str(val), "blue") - - -def Set(value, internal_dict): - vals = [] - max_vals = 7 - for child in value.children: - vals.append(child.value) - if len(vals) > max_vals: - vals.append("...") - break - - return "{" + ", ".join(vals) + "}" - - -def Table(value: lldb.SBValue, internal_dict): - fields = [] - - for i in range(value.num_children): - key = value[i].name - val = value[i].summary - fields.append(f"{key}: {val}") - - table_suffix = "Table" - return "{" + ", ".join(fields) + f"}}.{table_suffix}" - - -def HashSet(value: lldb.SBValue, internal_dict): - fields = [] - - for i in range(value.num_children): - fields.append(f"{value[i].summary}") - - table_suffix = "HashSet" - - return "{" + ", ".join(fields) + f"}}.{table_suffix}" - - -def StringTable(value: lldb.SBValue, internal_dict): - table = value.GetNonSyntheticValue() - mode = table["mode"].unsigned - - table_suffix = "StringTable" - - table_mode = "" - if mode == 0: - table_mode = "Case Sensitive" - elif mode == 1: - table_mode = "Case Insensitive" - elif mode == 2: - table_mode = "Style Insensitive" - - fields = [] - - for i in range(value.num_children): - key = value[i].name - val = value[i].summary - fields.append(f"{key}: {val}") - - return "{" + ", ".join(fields) + f"}}.{table_suffix}({table_mode})" - - -def Sequence(value: lldb.SBValue, internal_dict): - value = value.GetNonSyntheticValue() - - data_len = int(value["len"].unsigned) - data = value["p"]["data"] - base_data_type = data.type.GetArrayElementType() - - cast = data.Cast(base_data_type.GetArrayType(data_len)) - - return ( - "@[" - + ", ".join([cast[i].summary or cast[i].type.name for i in range(data_len)]) - + "]" - ) - - -class StringChildrenProvider: - def __init__(self, value: lldb.SBValue, internalDict): - self.value = value - self.data_type: lldb.SBType - self.first_element: lldb.SBValue - self.update() - self.count = 0 - - def num_children(self): - return self.count - - def get_child_index(self, name): - return int(name.lstrip("[").rstrip("]")) - - def get_child_at_index(self, index): - offset = index * self.data_size - return self.first_element.CreateChildAtOffset( - "[" + str(index) + "]", offset, self.data_type - ) - - def update(self): - data = self.value["p"]["data"] - size = int(self.value["len"].unsigned) - - self.count = size - self.first_element = data - - self.data_type = data.type.GetArrayElementType().GetTypedefedType() - self.data_size = self.data_type.GetByteSize() - - def has_children(self): - return bool(self.num_children()) - - -class ArrayChildrenProvider: - def __init__(self, value: lldb.SBValue, internalDict): - self.value = value - self.data_type: lldb.SBType - self.first_element: lldb.SBValue - self.update() - - def num_children(self): - return self.value.num_children - - def get_child_index(self, name: str): - return int(name.lstrip("[").rstrip("]")) - - def get_child_at_index(self, index): - offset = index * self.value[index].GetByteSize() - return self.first_element.CreateChildAtOffset( - "[" + str(index) + "]", offset, self.data_type - ) - - def update(self): - if not self.has_children(): - return - - self.first_element = self.value[0] - self.data_type = self.value.type.GetArrayElementType() - - def has_children(self): - return bool(self.num_children()) - - -class SeqChildrenProvider: - def __init__(self, value: lldb.SBValue, internalDict): - self.value = value - self.data_type: lldb.SBType - self.first_element: lldb.SBValue - self.data: lldb.SBValue - self.update() - - def num_children(self): - return int(self.value["len"].unsigned) - - def get_child_index(self, name: str): - return int(name.lstrip("[").rstrip("]")) - - def get_child_at_index(self, index): - offset = index * self.data[index].GetByteSize() - return self.first_element.CreateChildAtOffset( - "[" + str(index) + "]", offset, self.data_type - ) - - def update(self): - if not self.has_children(): - return - - data = self.value["p"]["data"] - self.data_type = data.type.GetArrayElementType() - - self.data = data.Cast(self.data_type.GetArrayType(self.num_children())) - self.first_element = self.data - - def has_children(self): - return bool(self.num_children()) - - -class ObjectChildrenProvider: - def __init__(self, value: lldb.SBValue, internalDict): - self.value = value - self.data_type: lldb.SBType - self.first_element: lldb.SBValue - self.data: lldb.SBValue - self.children: OrderedDict[str, int] = OrderedDict() - self.child_list: list[lldb.SBValue] = [] - self.update() - - def num_children(self): - return len(self.children) - - def get_child_index(self, name: str): - return self.children[name] - - def get_child_at_index(self, index): - return self.child_list[index] - - def populate_children(self): - self.children.clear() - self.child_list = [] - stack = [self.value] - - index = 0 - - while stack: - cur_val = stack.pop() - while cur_val.type.is_pointer: - cur_val = cur_val.Dereference() - - if cur_val.num_children > 0 and cur_val[0].name == "m_type": - if "_" in cur_val.type.name: - tname = cur_val.type.name.split("_")[1].replace( - "colonObjectType", "" - ) - else: - tname = cur_val.type.name - if tname == "TNimTypeV2": - # We've reached the end - break - - if ( - cur_val.num_children > 0 - and cur_val[0].name == "Sup" - and cur_val[0].type.name.startswith("tyObject") - ): - stack.append(cur_val[0]) - - for i in range(cur_val.num_children): - child = cur_val[i] - if child.name == "Sup": - continue - self.children[child.name] = index - self.child_list.append(child) - index += 1 - - def update(self): - self.populate_children() - - def has_children(self): - return bool(self.num_children()) - - -class HashSetChildrenProvider: - def __init__(self, value: lldb.SBValue, internalDict): - self.value = value - self.child_list: list[lldb.SBValue] = [] - self.update() - - def num_children(self): - return len(self.child_list) - - def get_child_index(self, name: str): - return int(name.lstrip("[").rstrip("]")) - - def get_child_at_index(self, index): - return self.child_list[index] - - def update(self): - self.child_list = [] - data = self.value["data"] - - tuple_len = int(data["len"].unsigned) - tuple = data["p"]["data"] - - base_data_type = tuple.type.GetArrayElementType() - - cast = tuple.Cast(base_data_type.GetArrayType(tuple_len)) - - index = 0 - for i in range(tuple_len): - el = cast[i] - field0 = int(el["Field0"].unsigned) - if field0 == 0: - continue - key = el["Field1"] - child = key.CreateValueFromAddress( - f"[{str(index)}]", key.GetLoadAddress(), key.GetType() - ) - index += 1 - - self.child_list.append(child) - - def has_children(self): - return bool(self.num_children()) - - -class SetCharChildrenProvider: - def __init__(self, value: lldb.SBValue, internalDict): - self.value = value - self.ty = self.value.target.FindFirstType("char") - self.child_list: list[lldb.SBValue] = [] - self.update() - - def num_children(self): - return len(self.child_list) - - def get_child_index(self, name: str): - return int(name.lstrip("[").rstrip("]")) - - def get_child_at_index(self, index): - return self.child_list[index] - - def update(self): - self.child_list = [] - cur_pos = 0 - for child in self.value.children: - child_val = child.signed - if child_val != 0: - temp = child_val - num_bits = 8 - while temp != 0: - is_set = temp & 1 - if is_set == 1: - data = lldb.SBData.CreateDataFromInt(cur_pos) - child = self.value.synthetic_child_from_data( - f"[{len(self.child_list)}]", data, self.ty - ) - self.child_list.append(child) - temp = temp >> 1 - cur_pos += 1 - num_bits -= 1 - cur_pos += num_bits - else: - cur_pos += 8 - - def has_children(self): - return bool(self.num_children()) - - -class SetIntChildrenProvider: - def __init__(self, value: lldb.SBValue, internalDict): - self.value = value - self.ty = self.value.target.FindFirstType(f"NI64") - self.child_list: list[lldb.SBValue] = [] - self.update() - - def num_children(self): - return len(self.child_list) - - def get_child_index(self, name: str): - return int(name.lstrip("[").rstrip("]")) - - def get_child_at_index(self, index): - return self.child_list[index] - - def update(self): - self.child_list = [] - bits = self.value.GetByteSize() * 8 - - cur_pos = -(bits // 2) - - if self.value.num_children > 0: - children = self.value.children - else: - children = [self.value] - - for child in children: - child_val = child.signed - if child_val != 0: - temp = child_val - num_bits = 8 - while temp != 0: - is_set = temp & 1 - if is_set == 1: - data = lldb.SBData.CreateDataFromInt(cur_pos) - child = self.value.synthetic_child_from_data( - f"[{len(self.child_list)}]", data, self.ty - ) - self.child_list.append(child) - temp = temp >> 1 - cur_pos += 1 - num_bits -= 1 - cur_pos += num_bits - else: - cur_pos += 8 - - def has_children(self): - return bool(self.num_children()) - - -class SetUIntChildrenProvider: - def __init__(self, value: lldb.SBValue, internalDict): - self.value = value - self.ty = self.value.target.FindFirstType(f"NU64") - self.child_list: list[lldb.SBValue] = [] - self.update() - - def num_children(self): - return len(self.child_list) - - def get_child_index(self, name: str): - return int(name.lstrip("[").rstrip("]")) - - def get_child_at_index(self, index): - return self.child_list[index] - - def update(self): - self.child_list = [] - - cur_pos = 0 - if self.value.num_children > 0: - children = self.value.children - else: - children = [self.value] - - for child in children: - child_val = child.signed - if child_val != 0: - temp = child_val - num_bits = 8 - while temp != 0: - is_set = temp & 1 - if is_set == 1: - data = lldb.SBData.CreateDataFromInt(cur_pos) - child = self.value.synthetic_child_from_data( - f"[{len(self.child_list)}]", data, self.ty - ) - self.child_list.append(child) - temp = temp >> 1 - cur_pos += 1 - num_bits -= 1 - cur_pos += num_bits - else: - cur_pos += 8 - - def has_children(self): - return bool(self.num_children()) - - -class SetEnumChildrenProvider: - def __init__(self, value: lldb.SBValue, internalDict): - self.value = value - self.ty = self.value.target.FindFirstType(f"NU64") - self.child_list: list[lldb.SBValue] = [] - self.update() - - def num_children(self): - return len(self.child_list) - - def get_child_index(self, name: str): - return int(name.lstrip("[").rstrip("]")) - - def get_child_at_index(self, index): - return self.child_list[index] - - def update(self): - self.child_list = [] - - cur_pos = 0 - if self.value.num_children > 0: - children = self.value.children - else: - children = [self.value] - - for child in children: - child_val = child.unsigned - if child_val != 0: - temp = child_val - num_bits = 8 - while temp != 0: - is_set = temp & 1 - if is_set == 1: - data = lldb.SBData.CreateDataFromInt(cur_pos) - child = self.value.synthetic_child_from_data( - f"[{len(self.child_list)}]", data, self.ty - ) - self.child_list.append(child) - temp = temp >> 1 - cur_pos += 1 - num_bits -= 1 - cur_pos += num_bits - else: - cur_pos += 8 - - def has_children(self): - return bool(self.num_children()) - - -class TableChildrenProvider: - def __init__(self, value: lldb.SBValue, internalDict): - self.value = value - self.children: OrderedDict[str, int] = OrderedDict() - self.child_list: list[lldb.SBValue] = [] - self.update() - - def num_children(self): - return len(self.child_list) - - def get_child_index(self, name: str): - return self.children[name] - - def get_child_at_index(self, index): - return self.child_list[index] - - def update(self): - self.child_list = [] - data = self.value["data"] - - tuple_len = int(data["len"].unsigned) - tuple = data["p"]["data"] - - base_data_type = tuple.type.GetArrayElementType() - - cast = tuple.Cast(base_data_type.GetArrayType(tuple_len)) - - index = 0 - for i in range(tuple_len): - el = cast[i] - field0 = int(el["Field0"].unsigned) - if field0 == 0: - continue - key = el["Field1"] - val = el["Field2"] - child = val.CreateValueFromAddress( - key.summary, val.GetLoadAddress(), val.GetType() - ) - self.child_list.append(child) - self.children[key.summary] = index - index += 1 - - def has_children(self): - return bool(self.num_children()) - - -class StringTableChildrenProvider: - def __init__(self, value: lldb.SBValue, internalDict): - self.value = value - self.children: OrderedDict[str, int] = OrderedDict() - self.child_list: list[lldb.SBValue] = [] - self.update() - - def num_children(self): - return len(self.child_list) - - def get_child_index(self, name: str): - return self.children[name] - - def get_child_at_index(self, index): - return self.child_list[index] - - def update(self): - self.children.clear() - self.child_list = [] - data = self.value["data"] - - tuple_len = int(data["len"].unsigned) - tuple = data["p"]["data"] - - base_data_type = tuple.type.GetArrayElementType() - - cast = tuple.Cast(base_data_type.GetArrayType(tuple_len)) - - index = 0 - for i in range(tuple_len): - el = cast[i] - field0 = int(el["Field2"].unsigned) - if field0 == 0: - continue - key = el["Field0"] - val = el["Field1"] - child = val.CreateValueFromAddress( - key.summary, val.GetLoadAddress(), val.GetType() - ) - self.child_list.append(child) - self.children[key.summary] = index - index += 1 - - def has_children(self): - return bool(self.num_children()) - - -class CustomObjectChildrenProvider: - def __init__(self, value: lldb.SBValue, internalDict): - print("CUSTOMOBJ: ", value.name) - self.value: lldb.SBValue = get_synthetic(value) or value - for child in self.value.children: - print(child) - - def num_children(self): - return self.value.num_children - - def get_child_index(self, name: str): - return self.value.GetIndexOfChildWithName(name) - - def get_child_at_index(self, index): - return self.value.GetChildAtIndex(index) - - def update(self): - pass - - def has_children(self): - return self.num_children() > 0 - - -def echo(debugger: lldb.SBDebugger, command: str, result, internal_dict): - debugger.HandleCommand("po " + command) - - -SUMMARY_FUNCTIONS: dict[str, lldb.SBFunction] = {} -SYNTHETIC_FUNCTIONS: dict[str, lldb.SBFunction] = {} - - -def get_summary(value: lldb.SBValue) -> Union[str, None]: - base_type = get_base_type(value.type) - - fn = SUMMARY_FUNCTIONS.get(base_type.name) - if fn is None: - return None - - res = executeCommand( - f"{fn.name}(*({base_type.GetPointerType().name})" + str(value.GetLoadAddress()) + ");" - ) - - if res.error.fail: - return None - - return res.summary.strip('"') - - -def get_synthetic(value: lldb.SBValue) -> Union[lldb.SBValue, None]: - base_type = get_base_type(value.type) - - fn = SYNTHETIC_FUNCTIONS.get(base_type.name) - if fn is None: - return None - - res = executeCommand( - f"{fn.name}(*({base_type.GetPointerType().name})" + str(value.GetLoadAddress()) + ");" - ) - - if res.error.fail: - return None - - return res - - -def get_base_type(ty: lldb.SBType) -> lldb.SBType: - temp = ty - while temp.IsPointerType(): - temp = temp.GetPointeeType() - return temp - - -def breakpoint_function_wrapper(frame: lldb.SBFrame, bp_loc, internal_dict): - """This allows function calls to Nim for custom object summaries and synthetic children""" - debugger = lldb.debugger - - global SUMMARY_FUNCTIONS - global SYNTHETIC_FUNCTIONS - for tname, fn in SYNTHETIC_FUNCTIONS.items(): - print("DELETING SYNTH: ", tname) - debugger.HandleCommand(f"type synthetic delete -w nim {tname}") - - SUMMARY_FUNCTIONS = {} - SYNTHETIC_FUNCTIONS = {} - - target: lldb.SBTarget = debugger.GetSelectedTarget() - print("BREAKPOINT") - module = frame.GetSymbolContext(lldb.eSymbolContextModule).module - - for sym in module: - if not sym.name.startswith("lldbDebugSummary") and not sym.name.startswith( - "lldbDebugSynthetic" - ): - continue - - print("SYM: ", sym.name) - - fn_syms: lldb.SBSymbolContextList = target.FindFunctions(sym.name) - if not fn_syms.GetSize() > 0: - continue - fn_sym: lldb.SBSymbolContext = fn_syms.GetContextAtIndex(0) - - print("fn found!") - - fn: lldb.SBFunction = fn_sym.function - fn_type: lldb.SBType = fn.type - arg_types: lldb.SBTypeList = fn_type.GetFunctionArgumentTypes() - - if not arg_types.GetSize() > 0: - continue - arg_type: lldb.SBType = get_base_type(arg_types.GetTypeAtIndex(0)) - - print("FIRST ARG TYPE: ", arg_type.name) - - if sym.name.startswith("lldbDebugSummary"): - SUMMARY_FUNCTIONS[arg_type.name] = fn - elif sym.name.startswith("lldbDebugSynthetic"): - SYNTHETIC_FUNCTIONS[arg_type.name] = fn - debugger.HandleCommand( - f"type synthetic add -w nim -l {__name__}.CustomObjectChildrenProvider -x {arg_type.name}$" - ) - - -def executeCommand(command, *args): - debugger = lldb.debugger - process = debugger.GetSelectedTarget().GetProcess() - frame: lldb.SBFrame = process.GetSelectedThread().GetSelectedFrame() - # module = frame.GetSymbolContext(lldb.eSymbolContextModule).module - # for sym in module: - # print("SYM: ", sym.name) - # target = debugger.GetSelectedTarget() - - expr_options = lldb.SBExpressionOptions() - expr_options.SetIgnoreBreakpoints(False) - expr_options.SetFetchDynamicValue(lldb.eDynamicCanRunTarget) - expr_options.SetTimeoutInMicroSeconds(30 * 1000 * 1000) # 30 second timeout - expr_options.SetTryAllThreads(True) - expr_options.SetUnwindOnError(False) - expr_options.SetGenerateDebugInfo(True) - expr_options.SetLanguage(lldb.eLanguageTypeC) - expr_options.SetCoerceResultToId(True) - res = frame.EvaluateExpression(command, expr_options) - # if res.error.fail: - # print("ERROR: ", res.error.GetError()) - # return str(res.error) - return res - - -def __lldb_init_module(debugger, internal_dict): - # debugger.HandleCommand(f"type summary add -w nim -n any -F {__name__}.CatchAll -x .*") - debugger.HandleCommand(f"type summary add -w nim -n sequence -F {__name__}.Sequence -x tySequence_+[[:alnum:]]+$") - debugger.HandleCommand(f"type synthetic add -w nim -l {__name__}.SeqChildrenProvider -x tySequence_+[[:alnum:]]+$") - - debugger.HandleCommand(f"type summary add -w nim -n chararray -F {__name__}.CharArray -x char\s+[\d+]") - debugger.HandleCommand(f"type summary add -w nim -n array -F {__name__}.Array -x tyArray_+[[:alnum:]]+") - debugger.HandleCommand(f"type synthetic add -w nim -l {__name__}.ArrayChildrenProvider -x tyArray_+[[:alnum:]]+") - debugger.HandleCommand(f"type summary add -w nim -n string -F {__name__}.NimStringDesc NimStringDesc") - - debugger.HandleCommand(f"type summary add -w nim -n stringv2 -F {__name__}.NimStringV2 -x NimStringV2$") - debugger.HandleCommand(f"type synthetic add -w nim -l {__name__}.StringChildrenProvider -x NimStringV2$") - - debugger.HandleCommand(f"type summary add -w nim -n cstring -F {__name__}.NCSTRING NCSTRING") - - debugger.HandleCommand(f"type summary add -w nim -n object -F {__name__}.ObjectV2 -x tyObject_+[[:alnum:]]+_+[[:alnum:]]+") - debugger.HandleCommand(f"type synthetic add -w nim -l {__name__}.ObjectChildrenProvider -x tyObject_+[[:alnum:]]+_+[[:alnum:]]+$") - - debugger.HandleCommand(f"type summary add -w nim -n tframe -F {__name__}.ObjectV2 -x TFrame$") - - debugger.HandleCommand(f"type summary add -w nim -n rootobj -F {__name__}.ObjectV2 -x RootObj$") - - debugger.HandleCommand(f"type summary add -w nim -n enum -F {__name__}.Enum -x tyEnum_+[[:alnum:]]+_+[[:alnum:]]+") - debugger.HandleCommand(f"type summary add -w nim -n hashset -F {__name__}.HashSet -x tyObject_+HashSet_+[[:alnum:]]+") - debugger.HandleCommand(f"type synthetic add -w nim -l {__name__}.HashSetChildrenProvider -x tyObject_+HashSet_+[[:alnum:]]+") - debugger.HandleCommand(f"type summary add -w nim -n setuint -F {__name__}.Set -x tySet_+tyInt_+[[:alnum:]]+") - debugger.HandleCommand(f"type synthetic add -w nim -l {__name__}.SetIntChildrenProvider -x tySet_+tyInt[0-9]+_+[[:alnum:]]+") - debugger.HandleCommand(f"type summary add -w nim -n setint -F {__name__}.Set -x tySet_+tyInt[0-9]+_+[[:alnum:]]+") - debugger.HandleCommand(f"type summary add -w nim -n setuint2 -F {__name__}.Set -x tySet_+tyUInt[0-9]+_+[[:alnum:]]+") - debugger.HandleCommand(f"type synthetic add -w nim -l {__name__}.SetUIntChildrenProvider -x tySet_+tyUInt[0-9]+_+[[:alnum:]]+") - debugger.HandleCommand(f"type synthetic add -w nim -l {__name__}.SetUIntChildrenProvider -x tySet_+tyInt_+[[:alnum:]]+") - debugger.HandleCommand(f"type summary add -w nim -n setenum -F {__name__}.EnumSet -x tySet_+tyEnum_+[[:alnum:]]+_+[[:alnum:]]+") - debugger.HandleCommand(f"type synthetic add -w nim -l {__name__}.SetUIntChildrenProvider -x tySet_+tyEnum_+[[:alnum:]]+_+[[:alnum:]]+") - debugger.HandleCommand(f"type summary add -w nim -n setchar -F {__name__}.Set -x tySet_+tyChar_+[[:alnum:]]+") - debugger.HandleCommand(f"type synthetic add -w nim -l {__name__}.SetCharChildrenProvider -x tySet_+tyChar_+[[:alnum:]]+") - debugger.HandleCommand(f"type summary add -w nim -n table -F {__name__}.Table -x tyObject_+Table_+[[:alnum:]]+") - debugger.HandleCommand(f"type synthetic add -w nim -l {__name__}.TableChildrenProvider -x tyObject_+Table_+[[:alnum:]]+") - debugger.HandleCommand(f"type summary add -w nim -n stringtable -F {__name__}.StringTable -x tyObject_+StringTableObj_+[[:alnum:]]+") - debugger.HandleCommand(f"type synthetic add -w nim -l {__name__}.StringTableChildrenProvider -x tyObject_+StringTableObj_+[[:alnum:]]+") - debugger.HandleCommand(f"type summary add -w nim -n tuple2 -F {__name__}.Tuple -x tyObject_+Tuple_+[[:alnum:]]+") - debugger.HandleCommand(f"type summary add -w nim -n tuple -F {__name__}.Tuple -x tyTuple_+[[:alnum:]]+") - # debugger.HandleCommand(f"type summary add -w nim -n TNimType -F {__name__}.Object TNimType") - debugger.HandleCommand(f"type summary add -w nim -n TNimTypeV2 -F {__name__}.ObjectV2 TNimTypeV2") - # debugger.HandleCommand(f"type summary add -w nim -n TNimNode -F {__name__}.Object TNimNode") - debugger.HandleCommand(f"type summary add -w nim -n float -F {__name__}.Float NF") - debugger.HandleCommand(f"type summary add -w nim -n float32 -F {__name__}.Float NF32") - debugger.HandleCommand(f"type summary add -w nim -n float64 -F {__name__}.Float NF64") - debugger.HandleCommand(f"type summary add -w nim -n integer -F {__name__}.Number -x NI") - debugger.HandleCommand(f"type summary add -w nim -n integer8 -F {__name__}.Number -x NI8") - debugger.HandleCommand(f"type summary add -w nim -n integer16 -F {__name__}.Number -x NI16") - debugger.HandleCommand(f"type summary add -w nim -n integer32 -F {__name__}.Number -x NI32") - debugger.HandleCommand(f"type summary add -w nim -n integer64 -F {__name__}.Number -x NI64") - debugger.HandleCommand(f"type summary add -w nim -n bool -F {__name__}.Bool -x bool") - debugger.HandleCommand(f"type summary add -w nim -n bool2 -F {__name__}.Bool -x NIM_BOOL") - debugger.HandleCommand(f"type summary add -w nim -n uinteger -F {__name__}.UnsignedNumber -x NU") - debugger.HandleCommand(f"type summary add -w nim -n uinteger8 -F {__name__}.UnsignedNumber -x NU8") - debugger.HandleCommand(f"type summary add -w nim -n uinteger16 -F {__name__}.UnsignedNumber -x NU16") - debugger.HandleCommand(f"type summary add -w nim -n uinteger32 -F {__name__}.UnsignedNumber -x NU32") - debugger.HandleCommand(f"type summary add -w nim -n uinteger64 -F {__name__}.UnsignedNumber -x NU64") - debugger.HandleCommand("type category enable nim") - debugger.HandleCommand(f"command script add -f {__name__}.echo echo") - debugger.HandleCommand(f"command script add -f {__name__}.handle_command ddp") - debugger.HandleCommand(f"breakpoint command add -F {__name__}.breakpoint_function_wrapper --script-type python 1") \ No newline at end of file diff --git a/tools/deps.nim b/tools/deps.nim deleted file mode 100644 index e43f7a2b4..000000000 --- a/tools/deps.nim +++ /dev/null @@ -1,44 +0,0 @@ -import std/[os, uri, strformat, strutils] -import std/private/gitutils - -when defined(nimPreviewSlimSystem): - import std/assertions - -proc exec(cmd: string) = - echo "deps.cmd: " & cmd - let status = execShellCmd(cmd) - doAssert status == 0, cmd - -proc execRetry(cmd: string) = - let ok = retryCall(call = block: - let status = execShellCmd(cmd) - let result = status == 0 - if not result: - echo fmt"failed command: '{cmd}', status: {status}" - result) - doAssert ok, cmd - -proc cloneDependency*(destDirBase: string, url: string, commit = commitHead, - appendRepoName = true, allowBundled = false) = - let destDirBase = destDirBase.absolutePath - let p = url.parseUri.path - let name = p.splitFile.name - var destDir = destDirBase - if appendRepoName: destDir = destDir / name - let quotedDestDir = destDir.quoteShell - if not dirExists(destDir): - # note: old code used `destDir / .git` but that wouldn't prevent git clone - # from failing - execRetry fmt"git clone -q {url} {quotedDestDir}" - if isGitRepo(destDir): - let oldDir = getCurrentDir() - setCurrentDir(destDir) - try: - execRetry "git fetch -q" - exec fmt"git checkout -q {commit}" - finally: - setCurrentDir(oldDir) - elif allowBundled: - discard "this dependency was bundled with Nim, don't do anything" - else: - quit "FAILURE: " & destdir & " already exists but is not a git repo" diff --git a/tools/detect/detect.nim b/tools/detect/detect.nim index ed1caf78c..fcbedcfcd 100644 --- a/tools/detect/detect.nim +++ b/tools/detect/detect.nim @@ -12,27 +12,14 @@ # The second one is more portable, and less semantically correct. It only works # when there's a backing C compiler available as well, preventing standalone # compilation. -import std/[os, strutils] - -when defined(nimPreviewSlimSystem): - import std/syncio - -when defined(openbsd) or defined(freebsd) or defined(netbsd): - const - cc = "cc -o $# $#.c" - cpp = "cc -E -o $#.i $#.c" - ccLinkMath = "cc -lm -o $# $#.c" - cppLinkMath = "cc -lm -E -o $#.i $#.c" -else: - const - cc = "gcc -o $# $#.c" - cpp = "gcc -E -o $#.i $#.c" +import os, strutils const + cc = "gcc -o $# $#.c" + cpp = "gcc -E -o $#.i $#.c" + cfile = """ /* Generated by detect.nim */ -#define _GNU_SOURCE -#define _POSIX_C_SOURCE 200809L #include #include @@ -100,11 +87,8 @@ proc main = if open(f, "other_consts.nim", fmWrite): f.write(nimfile % [other]) close(f) - - let cCompile = when defined(openbsd) or defined(freebsd) or defined(netbsd): ccLinkMath else: cc - let cppCompile = when defined(openbsd) or defined(freebsd) or defined(netbsd): cppLinkMath else: cpp - if not myExec(cCompile % [gen.addFileExt(ExeExt), gen]): quit(1) - if not myExec(cppCompile % [pre.addFileExt(ExeExt), pre]): quit(1) + if not myExec(cc % [gen.addFileExt(ExeExt), gen]): quit(1) + if not myExec(cpp % [pre.addFileExt(ExeExt), pre]): quit(1) when defined(windows): if not myExec(gen.addFileExt(ExeExt)): quit(1) else: @@ -135,14 +119,10 @@ proc v(name: string, typ = "cint", no_other = false) = addf(tl, "#ifdef $3\n fprintf(f, \"const $1* = $2(%ld)\\n\", $3);\n#endif\n", n, t, name) - of "cint", "cshort", "TSa_Family": + of "cint", "cshort", "InAddrScalar", "TSa_Family": addf(tl, "#ifdef $3\n fprintf(f, \"const $1* = $2(%d)\\n\", $3);\n#endif\n", n, t, name) - of "InAddrScalar": - addf(tl, - "#ifdef $3\n fprintf(f, \"const $1* = $2(%u)\\n\", $3);\n#endif\n", - n, t, name) else: addf(tl, "#ifdef $3\n fprintf(f, \"const $1* = cast[$2](%d)\\n\", $3);\n#endif\n", @@ -248,7 +228,6 @@ v("EXDEV") header("") v("F_DUPFD") -v("F_DUPFD_CLOEXEC") v("F_GETFD") v("F_SETFD") v("F_GETFL") @@ -275,11 +254,6 @@ v("O_ACCMODE") v("O_RDONLY") v("O_RDWR") v("O_WRONLY") -v("O_CLOEXEC") -v("O_DIRECT") -v("O_PATH") -v("O_NOATIME") -v("O_TMPFILE") v("POSIX_FADV_NORMAL") v("POSIX_FADV_SEQUENTIAL") v("POSIX_FADV_RANDOM") @@ -457,7 +431,6 @@ header("") v("IPPROTO_IP") v("IPPROTO_IPV6") v("IPPROTO_ICMP") -v("IPPROTO_ICMPV6") v("IPPROTO_RAW") v("IPPROTO_TCP") v("IPPROTO_UDP") @@ -648,7 +621,6 @@ v("SOCK_DGRAM") v("SOCK_RAW") v("SOCK_SEQPACKET") v("SOCK_STREAM") -v("SOCK_CLOEXEC", no_other = true) v("SOL_SOCKET") v("SOMAXCONN") v("SO_REUSEPORT", no_other = true) @@ -656,10 +628,10 @@ v("MSG_NOSIGNAL", no_other = true) v("MSG_PEEK") v("MSG_TRUNC") v("MSG_WAITALL") -v("AF_INET") -v("AF_INET6") -v("AF_UNIX") -v("AF_UNSPEC") +v("AF_INET", "TSa_Family") +v("AF_INET6", "TSa_Family") +v("AF_UNIX", "TSa_Family") +v("AF_UNSPEC", "TSa_Family") v("SHUT_RD") v("SHUT_RDWR") v("SHUT_WR") diff --git a/tools/dochack/dochack.nim b/tools/dochack/dochack.nim index 0753248bc..2f8465a63 100644 --- a/tools/dochack/dochack.nim +++ b/tools/dochack/dochack.nim @@ -1,52 +1,49 @@ import dom import fuzzysearch -import std/[jsfetch, asyncjs] +proc textContent(e: Element): cstring {. + importcpp: "#.textContent", nodecl.} -proc setTheme(theme: cstring) {.exportc.} = - document.documentElement.setAttribute("data-theme", theme) - window.localStorage.setItem("theme", theme) +proc textContent(e: Node): cstring {. + importcpp: "#.textContent", nodecl.} -# set `data-theme` attribute early to prevent white flash -setTheme: - let t = window.localStorage.getItem("theme") - if t.isNil: cstring"auto" else: t - -proc onDOMLoaded(e: Event) {.exportc.} = - # set theme select value - document.getElementById("theme-select").value = window.localStorage.getItem("theme") - - for pragmaDots in document.getElementsByClassName("pragmadots"): - pragmaDots.onclick = proc (event: Event) = - # Hide tease - event.target.parentNode.style.display = "none" - # Show actual - event.target.parentNode.nextSibling.style.display = "inline" - - -proc tree(tag: cstring; kids: varargs[Element]): Element = +proc tree(tag: string; kids: varargs[Element]): Element = result = document.createElement tag for k in kids: result.appendChild k proc add(parent, kid: Element) = - if parent.nodeName == "TR" and (kid.nodeName == "TD" or kid.nodeName == "TH"): + if parent.nodeName == cstring"TR" and ( + kid.nodeName == cstring"TD" or kid.nodeName == cstring"TH"): let k = document.createElement("TD") appendChild(k, kid) appendChild(parent, k) else: appendChild(parent, kid) -proc setClass(e: Element; value: cstring) = +proc setClass(e: Element; value: string) = e.setAttribute("class", value) +proc text(s: string): Element = cast[Element](document.createTextNode(s)) proc text(s: cstring): Element = cast[Element](document.createTextNode(s)) +proc getElementById(id: cstring): Element {.importc: "document.getElementById", nodecl.} + proc replaceById(id: cstring; newTree: Node) = - let x = document.getElementById(id) + let x = getElementById(id) x.parentNode.replaceChild(newTree, x) newTree.id = id +proc findNodeWith(x: Element; tag, content: cstring): Element = + if x.nodeName == tag and x.textContent == content: + return x + for i in 0..`. - var s = "" - for c in x: - case c - of '<': s.add("<") - of '>': s.add(">") - else: s.add(c) - x = s.cstring +template normalize(x: cstring): cstring = x.toLower.replace("_", "") proc dosearch(value: cstring): Element = if db.len == 0: - return + var stuff: Element + {.emit: """ + var request = new XMLHttpRequest(); + request.open("GET", "theindex.html", false); + request.send(null); + + var doc = document.implementation.createHTMLDocument("theindex"); + doc.documentElement.innerHTML = request.responseText; + + //parser=new DOMParser(); + //doc=parser.parseFromString("", "text/html"); + + `stuff` = doc.documentElement; + """.} + db = stuff.getElementsByClass"reference" + contents = @[] + for ahref in db: + contents.add ahref.getAttribute("data-doc-search-tag") let ul = tree("UL") result = tree("DIV") result.setClass"search_results" var matches: seq[(Node, int)] = @[] for i in 0.. { - - const div = document.createElement("div") - div.classList.add("copyToClipBoard") - - const preTag = document.createElement("pre") - preTag.innerHTML = e.innerHTML - - const button = document.createElement("button") - button.value = e.textContent.replace('...', '') - button.classList.add("copyToClipBoardBtn") - button.style.cursor = "pointer" - - div.appendChild(preTag) - div.appendChild(button) - - e.outerHTML = div.outerHTML - - }) - } - - - function copyTextToClipboard(e) { - const clipBoardContent = e.target.value - navigator.clipboard.writeText(clipBoardContent).then(function() { - e.target.style.setProperty("--clipboard-image", "var(--clipboard-image-selected)") - }, function(err) { - console.error("Could not copy text: ", err); - }); - } - - window.addEventListener("click", (e) => { - if (e.target.classList.contains("copyToClipBoardBtn")) { - copyTextToClipboard(e) - } - }) - - window.addEventListener("mouseover", (e) => { - if (e.target.nodeName === "PRE") { - e.target.nextElementSibling.style.setProperty("--clipboard-image", "var(--clipboard-image-normal)") - } - }) - - window.addEventListener("DOMContentLoaded", updatePreTags) - - """ - .} - -copyToClipboard() -window.addEventListener("DOMContentLoaded", onDOMLoaded) diff --git a/tools/dochack/fuzzysearch.nim b/tools/dochack/fuzzysearch.nim index fecbaf4f0..05f61bc11 100644 --- a/tools/dochack/fuzzysearch.nim +++ b/tools/dochack/fuzzysearch.nim @@ -132,9 +132,6 @@ proc fuzzyMatch*(pattern, str: cstring) : tuple[score: int, matched: bool] = strIndex += 1 - if patIndex == pattern.len and (strIndex == str.len or str[strIndex] notin Letters): - score += 10 - result = ( score: max(0, score), matched: (score > 0), diff --git a/tools/finish.nim b/tools/finish.nim index 69838829c..ccbb698f4 100644 --- a/tools/finish.nim +++ b/tools/finish.nim @@ -41,7 +41,7 @@ proc downloadMingw(): DownloadResult = let curl = findExe"curl" var cmd: string if curl.len > 0: - cmd = quoteShell(curl) & " --output " & "dist" / mingw & " " & url + cmd = quoteShell(curl) & " --out " & "dist" / mingw & " " & url elif fileExists"bin/nimgrab.exe": cmd = r"bin\nimgrab.exe " & url & " dist" / mingw if cmd.len > 0: @@ -123,11 +123,12 @@ when defined(windows): proc addToPathEnv*(e: string) = var p = tryGetUnicodeValue(r"Environment", "Path", HKEY_CURRENT_USER) + let x = if e.contains(Whitespace): "\"" & e & "\"" else: e if p.len > 0: p.add ";" - p.add e + p.add x else: - p = e + p = x setUnicodeValue(r"Environment", "Path", p, HKEY_CURRENT_USER) proc createShortcut(src, dest: string; icon = "") = diff --git a/tools/grammar_nanny.nim b/tools/grammar_nanny.nim index bcb3a044f..d07c2bf8c 100644 --- a/tools/grammar_nanny.nim +++ b/tools/grammar_nanny.nim @@ -3,11 +3,8 @@ import std / [strutils, sets] -when defined(nimPreviewSlimSystem): - import std/syncio - import ".." / compiler / [ - llstream, lexer, options, msgs, idents, + llstream, ast, lexer, options, msgs, idents, lineinfos, pathutils] proc checkGrammarFileImpl(cache: IdentCache, config: ConfigRef) = @@ -16,12 +13,11 @@ proc checkGrammarFileImpl(cache: IdentCache, config: ConfigRef) = var stream = llStreamOpen(data) var declaredSyms = initHashSet[string]() var usedSyms = initHashSet[string]() - usedSyms.incl "module" # 'module' is the start rule. if stream != nil: declaredSyms.incl "section" # special case for 'section(RULE)' in the grammar var - L: Lexer - tok: Token + L: TLexer + tok: TToken initToken(tok) openLexer(L, f, stream, cache, config) # load the first token: @@ -39,10 +35,6 @@ proc checkGrammarFileImpl(cache: IdentCache, config: ConfigRef) = usedSyms.incl word else: rawGetTok(L, tok) - for u in declaredSyms: - if u notin usedSyms: - echo "Unused non-terminal: ", u - for u in usedSyms: if u notin declaredSyms: echo "Undeclared non-terminal: ", u diff --git a/tools/heapdump2dot.nim b/tools/heapdump2dot.nim index 6704cdfb0..4cee6d674 100644 --- a/tools/heapdump2dot.nim +++ b/tools/heapdump2dot.nim @@ -1,5 +1,5 @@ -include std/prelude +include prelude proc main(input, output: string) = type NodeKind = enum diff --git a/tools/heapdumprepl.nim b/tools/heapdumprepl.nim index 4f06cf111..dbaef2f2c 100644 --- a/tools/heapdumprepl.nim +++ b/tools/heapdumprepl.nim @@ -1,4 +1,5 @@ -include std/prelude + +include prelude import intsets type @@ -16,6 +17,7 @@ type roots: Table[int, NodeKind] proc add(father: Node; son: int) = + if father.kids.isNil: father.kids = @[] father.kids.add(son) proc renderNode(g: Graph; id: int) = @@ -139,8 +141,8 @@ proc importData(input: string): Graph = close(i) else: quit "error: cannot open " & input - result.nodes = move nodes - result.roots = move roots + shallowCopy(result.nodes, nodes) + shallowCopy(result.roots, roots) if paramCount() == 1: repl(importData(paramStr(1))) diff --git a/tools/kochdocs.nim b/tools/kochdocs.nim index f63aea030..09b3268d1 100644 --- a/tools/kochdocs.nim +++ b/tools/kochdocs.nim @@ -1,70 +1,57 @@ ## Part of 'koch' responsible for the documentation generation. -import std/[os, strutils, osproc, sets, pathnorm, sequtils] - -import officialpackages -export exec - -when defined(nimPreviewSlimSystem): - import std/assertions - -# XXX: Remove this feature check once the csources supports it. -when defined(nimHasCastPragmaBlocks): - import std/pegs -from std/private/globs import nativeToUnixPath, walkDirRecFilter, PathEntry -import "../compiler/nimpaths" +import os, strutils, osproc, sets const gaCode* = " --doc.googleAnalytics:UA-48159761-1" - paCode* = " --doc.plausibleAnalytics:nim-lang.org" - # errormax: subsequent errors are probably consequences of 1st one; a simple - # bug could cause unlimited number of errors otherwise, hard to debug in CI. - docDefines = "-d:nimExperimentalLinenoiseExtra" - nimArgs = "--errormax:3 --hint:Conf:off --hint:Path:off --hint:Processing:off --hint:XDeclaredButNotUsed:off --warning:UnusedImport:off -d:boot --putenv:nimversion=$# $#" % [system.NimVersion, docDefines] + # --warning[LockLevel]:off pending #13218 + nimArgs = "--warning[LockLevel]:off --hint[Conf]:off --hint[Path]:off --hint[Processing]:off -d:boot --putenv:nimversion=$#" % system.NimVersion gitUrl = "https://github.com/nim-lang/Nim" docHtmlOutput = "doc/html" webUploadOutput = "web/upload" + docHackDir = "tools/dochack" var nimExe*: string -const allowList = ["jsbigints.nim", "jsheaders.nim", "jsformdata.nim", "jsfetch.nim", "jsutils.nim"] - -template isJsOnly(file: string): bool = - file.isRelativeTo("lib/js") or - file.extractFilename in allowList proc exe*(f: string): string = result = addFileExt(f, ExeExt) when defined(windows): result = result.replace('/','\\') -proc findNimImpl*(): tuple[path: string, ok: bool] = - if nimExe.len > 0: return (nimExe, true) - let nim = "nim".exe - result.path = "bin" / nim - result.ok = true - if fileExists(result.path): return +proc findNim*(): string = + if nimExe.len > 0: return nimExe + var nim = "nim".exe + result = "bin" / nim + if existsFile(result): return for dir in split(getEnv("PATH"), PathSep): - result.path = dir / nim - if fileExists(result.path): return + if existsFile(dir / nim): return dir / nim # assume there is a symlink to the exe or something: - return (nim, false) + return nim -proc findNim*(): string = findNimImpl().path +proc exec*(cmd: string, errorcode: int = QuitFailure, additionalPath = "") = + let prevPath = getEnv("PATH") + if additionalPath.len > 0: + var absolute = additionalPath + if not absolute.isAbsolute: + absolute = getCurrentDir() / absolute + echo("Adding to $PATH: ", absolute) + putEnv("PATH", (if prevPath.len > 0: prevPath & PathSep else: "") & absolute) + echo(cmd) + if execShellCmd(cmd) != 0: quit("FAILURE", errorcode) + putEnv("PATH", prevPath) template inFold*(desc, body) = - if existsEnv("GITHUB_ACTIONS"): - echo "::group::" & desc - elif existsEnv("TF_BUILD"): - echo "##[group]" & desc + if existsEnv("TRAVIS"): + echo "travis_fold:start:" & desc.replace(" ", "_") + body - if existsEnv("GITHUB_ACTIONS"): - echo "::endgroup::" - elif existsEnv("TF_BUILD"): - echo "##[endgroup]" + + if existsEnv("TRAVIS"): + echo "travis_fold:end:" & desc.replace(" ", "_") proc execFold*(desc, cmd: string, errorcode: int = QuitFailure, additionalPath = "") = - ## Execute shell command. Add log folding for various CI services. - let desc = if desc.len == 0: cmd else: desc + ## Execute shell command. Add log folding on Travis CI. + # https://github.com/travis-ci/travis-ci/issues/2285#issuecomment-42724719 inFold(desc): exec(cmd, errorcode, additionalPath) @@ -90,49 +77,79 @@ proc nimCompile*(input: string, outputDir = "bin", mode = "c", options = "") = let cmd = findNim().quoteShell() & " " & mode & " -o:" & output & " " & options & " " & input exec cmd -proc nimCompileFold*(desc, input: string, outputDir = "bin", mode = "c", options = "", outputName = "") = - let outputName2 = if outputName.len == 0: input.splitFile.name.exe else: outputName.exe - let output = outputDir / outputName2 +proc nimCompileFold*(desc, input: string, outputDir = "bin", mode = "c", options = "") = + let output = outputDir / input.splitFile.name.exe let cmd = findNim().quoteShell() & " " & mode & " -o:" & output & " " & options & " " & input execFold(desc, cmd) -proc getMd2html(): seq[string] = - for a in walkDirRecFilter("doc"): - let path = a.path - if a.kind == pcFile and path.splitFile.ext == ".md" and path.lastPathPart notin - ["docs.md", "nimfix.md", - "docstyle.md" # docstyle.md shouldn't be converted to html separately; - # it's included in contributing.md. - ]: - # maybe we should still show nimfix, could help reviving it - # `docs` is redundant with `overview`, might as well remove that file? - result.add path - doAssert "doc/manual/var_t_return.md".unixToNativePath in result # sanity check - const - mdPdfList = """ -manual.md -lib.md -tut1.md -tut2.md -tut3.md -nimc.md -niminst.md -mm.md -""".splitWhitespace().mapIt("doc" / it) + pdf = """ +doc/manual.rst +doc/lib.rst +doc/tut1.rst +doc/tut2.rst +doc/tut3.rst +doc/nimc.rst +doc/niminst.rst +doc/gc.rst +""".splitWhitespace() + + rst2html = """ +doc/intern.rst +doc/apis.rst +doc/lib.rst +doc/manual.rst +doc/manual_experimental.rst +doc/destructors.rst +doc/tut1.rst +doc/tut2.rst +doc/tut3.rst +doc/nimc.rst +doc/hcr.rst +doc/overview.rst +doc/filters.rst +doc/tools.rst +doc/niminst.rst +doc/nimgrep.rst +doc/gc.rst +doc/estp.rst +doc/idetools.rst +doc/docgen.rst +doc/koch.rst +doc/backends.rst +doc/nimsuggest.rst +doc/nep1.rst +doc/nims.rst +doc/contributing.rst +doc/codeowners.rst +doc/packaging.rst +doc/manual/var_t_return.rst +""".splitWhitespace() + + doc0 = """ +lib/system/threads.nim +lib/system/channels.nim +""".splitWhitespace() # ran by `nim doc0` instead of `nim doc` withoutIndex = """ +lib/wrappers/mysql.nim +lib/wrappers/iup.nim +lib/wrappers/sqlite3.nim +lib/wrappers/postgres.nim lib/wrappers/tinyc.nim +lib/wrappers/odbcsql.nim lib/wrappers/pcre.nim lib/wrappers/openssl.nim lib/posix/posix.nim lib/posix/linux.nim lib/posix/termios.nim +lib/js/jscore.nim """.splitWhitespace() - # some of these are include files so shouldn't be docgen'd ignoredModules = """ lib/pure/future.nim +lib/impure/osinfo_posix.nim +lib/impure/osinfo_win.nim lib/pure/collections/hashcommon.nim lib/pure/collections/tableimpl.nim lib/pure/collections/setimpl.nim @@ -147,74 +164,119 @@ lib/posix/posix_nintendoswitch_consts.nim lib/posix/posix_linux_amd64.nim lib/posix/posix_linux_amd64_consts.nim lib/posix/posix_other_consts.nim -lib/posix/posix_freertos_consts.nim lib/posix/posix_openbsd_amd64.nim -lib/posix/posix_haiku.nim """.splitWhitespace() - - officialPackagesList = """ -pkgs/asyncftpclient/src/asyncftpclient.nim -pkgs/smtp/src/smtp.nim -pkgs/punycode/src/punycode.nim -pkgs/db_connector/src/db_connector/db_common.nim -pkgs/db_connector/src/db_connector/db_mysql.nim -pkgs/db_connector/src/db_connector/db_odbc.nim -pkgs/db_connector/src/db_connector/db_postgres.nim -pkgs/db_connector/src/db_connector/db_sqlite.nim -""".splitWhitespace() - - officialPackagesListWithoutIndex = """ -pkgs/db_connector/src/db_connector/mysql.nim -pkgs/db_connector/src/db_connector/sqlite3.nim -pkgs/db_connector/src/db_connector/postgres.nim -pkgs/db_connector/src/db_connector/odbcsql.nim -pkgs/db_connector/src/db_connector/private/dbutils.nim -""".splitWhitespace() - -proc findName(name: string): string = - doAssert name[0..4] == "pkgs/" - var i = 5 - while i < name.len: - if name[i] != '/': - inc i - result.add name[i] - else: - break + # some of these (eg lib/posix/posix_macos_amd64.nim) are include files + # but contain potentially valuable docs on OS-specific symbols (eg OSX) that + # don't end up in the main docs; we ignore these for now. 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 ".." proc getDocList(): seq[string] = - var docIgnore: HashSet[string] - for a in withoutIndex: docIgnore.incl a - for a in ignoredModules: docIgnore.incl a + var t: HashSet[string] + for a in doc0: + doAssert a notin t + t.incl a + for a in withoutIndex: + doAssert a notin t, a + t.incl a - # don't ignore these even though in lib/system (not include files) + for a in ignoredModules: + doAssert a notin t, a + t.incl a + + var t2: HashSet[string] + template myadd(a)= + result.add a + doAssert a notin t2, a + t2.incl a + + # don't ignore these even though in lib/system const goodSystem = """ +lib/system/io.nim lib/system/nimscript.nim lib/system/assertions.nim lib/system/iterators.nim -lib/system/exceptions.nim lib/system/dollars.nim -lib/system/ctypes.nim +lib/system/widestrs.nim """.splitWhitespace() - proc follow(a: PathEntry): bool = - result = a.path.lastPathPart notin ["nimcache", htmldocsDirname, - "includes", "deprecated", "genode"] and - not a.path.isRelativeTo("lib/fusion") # fusion was un-bundled but we need to keep this in case user has it installed - for entry in walkDirRecFilter("lib", follow = follow): - let a = entry.path - if entry.kind != pcFile or a.splitFile.ext != ".nim" or - (a.isRelativeTo("lib/system") and a.nativeToUnixPath notin goodSystem) or - a.nativeToUnixPath in docIgnore: - continue + for a in walkDirRec("lib"): + if a.splitFile.ext != ".nim": continue + if a.isRelativeTo("lib/pure/includes"): continue + if a.isRelativeTo("lib/genode"): continue + if a.isRelativeTo("lib/deprecated"): + if a notin @["lib/deprecated/pure/ospaths.nim"]: # REMOVE + continue + if a.isRelativeTo("lib/system"): + if a notin goodSystem: + continue + if a notin t: + result.add a + doAssert a notin t2, a + t2.incl a + + myadd "nimsuggest/sexp.nim" + # these are include files, even though some of them don't specify `included from ...` + const ignore = """ +compiler/ccgcalls.nim +compiler/ccgexprs.nim +compiler/ccgliterals.nim +compiler/ccgstmts.nim +compiler/ccgthreadvars.nim +compiler/ccgtrav.nim +compiler/ccgtypes.nim +compiler/jstypes.nim +compiler/semcall.nim +compiler/semexprs.nim +compiler/semfields.nim +compiler/semgnrc.nim +compiler/seminst.nim +compiler/semmagic.nim +compiler/semobjconstr.nim +compiler/semstmts.nim +compiler/semtempl.nim +compiler/semtypes.nim +compiler/sizealignoffsetimpl.nim +compiler/suggest.nim +compiler/packagehandling.nim +compiler/hlo.nim +compiler/rodimpl.nim +compiler/vmops.nim +compiler/vmhooks.nim +""".splitWhitespace() + + # not include files but doesn't work; not included/imported anywhere; dead code? + const bad = """ +compiler/debuginfo.nim +compiler/canonicalizer.nim +compiler/forloops.nim +""".splitWhitespace() + + # these cause errors even though they're imported (some of which are mysterious) + const bad2 = """ +compiler/closureiters.nim +compiler/tccgen.nim +compiler/lambdalifting.nim +compiler/layouter.nim +compiler/evalffi.nim +compiler/nimfix/nimfix.nim +compiler/plugins/active.nim +compiler/plugins/itersgen.nim +""".splitWhitespace() + + for a in walkDirRec("compiler"): + if a.splitFile.ext != ".nim": continue + if a in ignore: continue + if a in bad: continue + if a in bad2: continue result.add a - result.add normalizePath("nimsuggest/sexp.nim") let doc = getDocList() @@ -240,148 +302,84 @@ proc buildDocSamples(nimArgs, destPath: string) = exec(findNim().quoteShell() & " doc $# -o:$# $#" % [nimArgs, destPath / "docgen_sample.html", "doc" / "docgen_sample.nim"]) -proc buildDocPackages(nimArgs, destPath: string, indexOnly: bool) = - # compiler docs; later, other packages (perhaps tools, testament etc) - let nim = findNim().quoteShell() - # to avoid broken links to manual from compiler dir, but a multi-package - # structure could be supported later - - proc docProject(outdir, options, mainproj: string) = - exec("$nim doc --project --outdir:$outdir $nimArgs --git.url:$gitUrl $index $options $mainproj" % [ - "nim", nim, - "outdir", outdir, - "nimArgs", nimArgs, - "gitUrl", gitUrl, - "options", options, - "mainproj", mainproj, - "index", if indexOnly: "--index:only" else: "" - ]) - let extra = "-u:boot" - # xxx keep in sync with what's in $nim_prs_D/config/nimdoc.cfg, or, rather, - # start using nims instead of nimdoc.cfg - docProject(destPath/"compiler", extra, "compiler/index.nim") - -proc buildDoc(nimArgs, destPath: string, indexOnly: bool) = +proc buildDoc(nimArgs, destPath: string) = # call nim for the documentation: - let rst2html = getMd2html() var - commands = newSeq[string](rst2html.len + len(doc) + withoutIndex.len + - officialPackagesList.len + officialPackagesListWithoutIndex.len) + commands = newSeq[string](rst2html.len + len(doc0) + len(doc) + withoutIndex.len) i = 0 let nim = findNim().quoteShell() - - let index = if indexOnly: "--index:only" else: "" for d in items(rst2html): - commands[i] = nim & " md2html $# --git.url:$# -o:$# $# $#" % - [nimArgs, gitUrl, - destPath / changeFileExt(splitFile(d).name, "html"), index, d] - i.inc - for d in items(doc): - let extra = if isJsOnly(d): "--backend:js" else: "" - var nimArgs2 = nimArgs - if d.isRelativeTo("compiler"): doAssert false - commands[i] = nim & " doc $# $# --git.url:$# --outdir:$# $# $#" % - [extra, nimArgs2, gitUrl, destPath, index, d] - i.inc - for d in items(withoutIndex): - commands[i] = nim & " doc $# --git.url:$# -o:$# $#" % + commands[i] = nim & " rst2html $# --git.url:$# -o:$# --index:on $#" % [nimArgs, gitUrl, destPath / changeFileExt(splitFile(d).name, "html"), d] i.inc - - - for d in items(officialPackagesList): - var nimArgs2 = nimArgs - if d.isRelativeTo("compiler"): doAssert false - commands[i] = nim & " doc $# --outdir:$# --index:on $#" % - [nimArgs2, destPath, d] + for d in items(doc0): + commands[i] = nim & " doc0 $# --git.url:$# -o:$# --index:on $#" % + [nimArgs, gitUrl, + destPath / changeFileExt(splitFile(d).name, "html"), d] i.inc - for d in items(officialPackagesListWithoutIndex): - commands[i] = nim & " doc $# -o:$# $#" % - [nimArgs, + for d in items(doc): + var nimArgs2 = nimArgs + if d.isRelativeTo("compiler"): + nimArgs2.add " --docroot" + commands[i] = nim & " doc $# --git.url:$# --outdir:$# --index:on $#" % + [nimArgs2, gitUrl, destPath, d] + i.inc + for d in items(withoutIndex): + commands[i] = nim & " doc2 $# --git.url:$# -o:$# $#" % + [nimArgs, gitUrl, destPath / changeFileExt(splitFile(d).name, "html"), d] i.inc mexec(commands) - -proc nim2pdf(src: string, dst: string, nimArgs: string) = - # xxx expose as a `nim` command or in some other reusable way. - let outDir = "build" / "xelatextmp" # xxx factor pending https://github.com/timotheecour/Nim/issues/616 - # note: this will generate temporary files in gitignored `outDir`: aux toc log out tex - exec("$# md2tex $# --outdir:$# $#" % [findNim().quoteShell(), nimArgs, outDir.quoteShell, src.quoteShell]) - let texFile = outDir / src.lastPathPart.changeFileExt("tex") - for i in 0..<3: # call LaTeX three times to get cross references right: - let xelatexLog = outDir / "xelatex.log" - # `>` should work on windows, if not, we can use `execCmdEx` - let cmd = "xelatex -interaction=nonstopmode -output-directory=$# $# > $#" % [outDir.quoteShell, texFile.quoteShell, xelatexLog.quoteShell] - exec(cmd) # on error, user can inspect `xelatexLog` - if i == 1: # build .ind file - var texFileBase = texFile - texFileBase.removeSuffix(".tex") - let cmd = "makeindex $# > $#" % [ - texFileBase.quoteShell, xelatexLog.quoteShell] - exec(cmd) - moveFile(texFile.changeFileExt("pdf"), dst) + exec(nim & " buildIndex -o:$1/theindex.html $1" % [destPath]) proc buildPdfDoc*(nimArgs, destPath: string) = - var pdfList: seq[string] createDir(destPath) - if os.execShellCmd("xelatex -version") != 0: - doAssert false, "xelatex not found" # or, raise an exception + if os.execShellCmd("pdflatex -version") != 0: + echo "pdflatex not found; no PDF documentation generated" else: - for src in items(mdPdfList): - let dst = destPath / src.lastPathPart.changeFileExt("pdf") - pdfList.add dst - nim2pdf(src, dst, nimArgs) - echo "\nOutput PDF files: \n ", pdfList.join(" ") # because `nim2pdf` is a bit verbose + const pdflatexcmd = "pdflatex -interaction=nonstopmode " + for d in items(pdf): + exec(findNim().quoteShell() & " rst2tex $# $#" % [nimArgs, d]) + # call LaTeX twice to get cross references right: + exec(pdflatexcmd & changeFileExt(d, "tex")) + exec(pdflatexcmd & changeFileExt(d, "tex")) + # delete all the crappy temporary files: + let pdf = splitFile(d).name & ".pdf" + let dest = destPath / pdf + removeFile(dest) + moveFile(dest=dest, source=pdf) + removeFile(changeFileExt(pdf, "aux")) + if existsFile(changeFileExt(pdf, "toc")): + removeFile(changeFileExt(pdf, "toc")) + removeFile(changeFileExt(pdf, "log")) + removeFile(changeFileExt(pdf, "out")) + removeFile(changeFileExt(d, "tex")) -proc buildJS(): string = - let nim = findNim() - exec("$# js -d:release --out:$# tools/nimblepkglist.nim" % - [nim.quoteShell(), webUploadOutput / "nimblepkglist.js"]) - # xxx deadcode? and why is it only for webUploadOutput, not for local docs? - result = getDocHacksJs(nimr = getCurrentDir(), nim) +proc buildJS() = + exec(findNim().quoteShell() & " js -d:release --out:$1 tools/nimblepkglist.nim" % + [webUploadOutput / "nimblepkglist.js"]) + exec(findNim().quoteShell() & " js " & (docHackDir / "dochack.nim")) -proc buildDocsDir*(args: string, dir: string) = - let args = nimArgs & " " & args - let docHackJsSource = buildJS() - gitClonePackages(@["asyncftpclient", "punycode", "smtp", "db_connector"]) - createDir(dir) - buildDocSamples(args, dir) +proc buildDocs*(args: string) = + const + docHackJs = "dochack.js" + let + a = nimArgs & " " & args + docHackJsSource = docHackDir / docHackJs + docHackJsDest = docHtmlOutput / docHackJs - # generate `.idx` files and top-level `theindex.html`: - buildDoc(args, dir, indexOnly=true) # bottleneck - let nim = findNim().quoteShell() - exec(nim & " buildIndex -o:$1/theindex.html $1" % [dir]) - # caveat: this works so long it's called before `buildDocPackages` which - # populates `compiler/` with unrelated idx files that shouldn't be in index, - # so should work in CI but you may need to remove your generated html files - # locally after calling `./koch docs`. The clean fix would be for `idx` files - # to be transient with `--project` (eg all in memory). - buildDocPackages(args, dir, indexOnly=true) + buildJS() # This call generates docHackJsSource + let docup = webUploadOutput / NimVersion + createDir(docup) + buildDocSamples(a, docup) + buildDoc(a, docup) - # generate HTML and package-level `theindex.html`: - buildDoc(args, dir, indexOnly=false) # bottleneck - buildDocPackages(args, dir, indexOnly=false) - - copyFile(dir / "overview.html", dir / "index.html") - copyFile(docHackJsSource, dir / docHackJsSource.lastPathPart) - -proc buildDocs*(args: string, localOnly = false, localOutDir = "") = - let localOutDir = - if localOutDir.len == 0: - docHtmlOutput - else: - localOutDir - - var args = args - - if not localOnly: - buildDocsDir(args, webUploadOutput / NimVersion) - - # XXX: Remove this feature check once the csources supports it. - when defined(nimHasCastPragmaBlocks): - let gaFilter = peg"@( y'--doc.googleAnalytics:' @(\s / $) )" - args = args.replace(gaFilter) - - buildDocsDir(args, localOutDir) + # 'nimArgs' instead of 'a' is correct here because we don't want + # that the offline docs contain the 'gaCode'! + createDir(docHtmlOutput) + buildDocSamples(nimArgs, docHtmlOutput) + buildDoc(nimArgs, docHtmlOutput) + copyFile(docHackJsSource, docHackJsDest) + copyFile(docHackJsSource, docup / docHackJs) diff --git a/tools/debug/nim-gdb.py b/tools/nim-gdb.py similarity index 64% rename from tools/debug/nim-gdb.py rename to tools/nim-gdb.py index 1050197c9..e994531b6 100644 --- a/tools/debug/nim-gdb.py +++ b/tools/nim-gdb.py @@ -1,7 +1,6 @@ import gdb import re import sys -import traceback # some feedback that the nim runtime support is loading, isn't a bad # thing at all. @@ -14,23 +13,14 @@ def printErrorOnce(id, message): global errorSet if id not in errorSet: errorSet.add(id) - gdb.write("printErrorOnce: " + message, gdb.STDERR) + gdb.write(message, gdb.STDERR) -def debugPrint(x): - gdb.write(str(x) + "\n", gdb.STDERR) - -NIM_STRING_TYPES = ["NimStringDesc", "NimStringV2"] ################################################################################ ##### Type pretty printers ################################################################################ -type_hash_regex = re.compile("^([A-Za-z0-9]*)_([A-Za-z0-9]*)_+([A-Za-z0-9]*)$") - -def getNimName(typ): - if m := type_hash_regex.match(typ): - return m.group(2) - return f"unknown <{typ}>" +type_hash_regex = re.compile("^\w*_([A-Za-z0-9]*)$") def getNimRti(type_name): """ Return a ``gdb.Value`` object for the Nim Runtime Information of ``type_name``. """ @@ -39,25 +29,10 @@ def getNimRti(type_name): # every non trivial Nim type. m = type_hash_regex.match(type_name) if m: - lookups = [ - "NTI" + m.group(2).lower() + "__" + m.group(3) + "_", - "NTI" + "__" + m.group(3) + "_", - "NTI" + m.group(2).replace("colon", "58").lower() + "__" + m.group(3) + "_" - ] - for l in lookups: - try: - return gdb.parse_and_eval(l) - except: - pass - None - -def getNameFromNimRti(rti): - """ Return name (or None) given a Nim RTI ``gdb.Value`` """ - try: - # sometimes there isn't a name field -- example enums - return rti['name'].string(encoding="utf-8", errors="ignore") - except: - return None + try: + return gdb.parse_and_eval("NTI__" + m.group(1) + "_") + except: + return None class NimTypeRecognizer: # this type map maps from types that are generated in the C files to @@ -67,25 +42,30 @@ class NimTypeRecognizer: # ``int``. type_map_static = { - 'NI': 'system.int', 'NI8': 'int8', 'NI16': 'int16', 'NI32': 'int32', - 'NI64': 'int64', - - 'NU': 'uint', 'NU8': 'uint8','NU16': 'uint16', 'NU32': 'uint32', - 'NU64': 'uint64', - + 'NI': 'system.int', 'NI8': 'int8', 'NI16': 'int16', 'NI32': 'int32', 'NI64': 'int64', + 'NU': 'uint', 'NU8': 'uint8','NU16': 'uint16', 'NU32': 'uint32', 'NU64': 'uint64', 'NF': 'float', 'NF32': 'float32', 'NF64': 'float64', - - 'NIM_BOOL': 'bool', - - 'NIM_CHAR': 'char', 'NCSTRING': 'cstring', 'NimStringDesc': 'string', 'NimStringV2': 'string' + 'NIM_BOOL': 'bool', 'NIM_CHAR': 'char', 'NCSTRING': 'cstring', + 'NimStringDesc': 'string' } - # object_type_pattern = re.compile("^(\w*):ObjectType$") + # Normally gdb distinguishes between the command `ptype` and + # `whatis`. `ptype` prints a very detailed view of the type, and + # `whatis` a very brief representation of the type. I haven't + # figured out a way to know from the type printer that is + # implemented here how to know if a type printer should print the + # short representation or the long representation. As a hacky + # workaround I just say I am not resposible for printing pointer + # types (seq and string are exception as they are semantically + # values). this way the default type printer will handle pointer + # types and dive into the members of that type. So I can still + # control with `ptype myval` and `ptype *myval` if I want to have + # detail or not. I this this method stinks but I could not figure + # out a better solution. + + object_type_pattern = re.compile("^(\w*):ObjectType$") def recognize(self, type_obj): - # skip things we can't handle like functions - if type_obj.code in [gdb.TYPE_CODE_FUNC, gdb.TYPE_CODE_VOID]: - return None tname = None if type_obj.tag is not None: @@ -95,49 +75,44 @@ class NimTypeRecognizer: # handle pointer types if not tname: - target_type = type_obj - if type_obj.code in [gdb.TYPE_CODE_PTR]: + if type_obj.code == gdb.TYPE_CODE_PTR: target_type = type_obj.target() + target_type_name = target_type.name + if target_type_name: + # visualize 'string' as non pointer type (unpack pointer type). + if target_type_name == "NimStringDesc": + tname = target_type_name # could also just return 'string' + # visualize 'seq[T]' as non pointer type. + if target_type_name.find('tySequence_') == 0: + tname = target_type_name - if target_type.name: - # visualize 'string' as non pointer type (unpack pointer type). - if target_type.name == "NimStringDesc": - tname = target_type.name # could also just return 'string' - else: - rti = getNimRti(target_type.name) - if rti: - return getNameFromNimRti(rti) + if not tname: + # We are not resposible for this type printing. + # Basically this means we don't print pointer types. + return None - if tname: - result = self.type_map_static.get(tname, None) - if result: - return result - elif tname.startswith("tyEnum_"): - return getNimName(tname) - elif tname.startswith("tyTuple__"): - # We make the name be the field types (Just like in Nim) - fields = ", ".join([self.recognize(field.type) for field in type_obj.fields()]) - return f"({fields})" + result = self.type_map_static.get(tname, None) + if result: + return result - rti = getNimRti(tname) - if rti: - return getNameFromNimRti(rti) - - return None + rti = getNimRti(tname) + if rti: + return rti['name'].string("utf-8", "ignore") + else: + return None class NimTypePrinter: """Nim type printer. One printer for all Nim types.""" + # enabling and disabling of type printers can be done with the # following gdb commands: # # enable type-printer NimTypePrinter # disable type-printer NimTypePrinter - # relevant docs: https://sourceware.org/gdb/onlinedocs/gdb/Type-Printing-API.html name = "NimTypePrinter" - - def __init__(self): + def __init__ (self): self.enabled = True def instantiate(self): @@ -151,7 +126,7 @@ class DollarPrintFunction (gdb.Function): "Nim's equivalent of $ operator as a gdb function, available in expressions `print $dollar(myvalue)" dollar_functions = re.findall( - '(?:NimStringDesc \*|NimStringV2)\s?(dollar__[A-z0-9_]+?)\(([^,)]*)\);', + 'NimStringDesc \*(dollar__[A-z0-9_]+?)\(([^,)]*)\);', gdb.execute("info functions dollar__", True, True) ) @@ -160,10 +135,13 @@ class DollarPrintFunction (gdb.Function): @staticmethod - def invoke_static(arg, ignore_errors = False): - if arg.type.code == gdb.TYPE_CODE_PTR and arg.type.target().name in NIM_STRING_TYPES: + def invoke_static(arg): + + if arg.type.code == gdb.TYPE_CODE_PTR and arg.type.target().name == "NimStringDesc": return arg + argTypeName = str(arg.type) + for func, arg_typ in DollarPrintFunction.dollar_functions: # this way of overload resolution cannot deal with type aliases, # therefore it won't find all overloads. @@ -175,8 +153,7 @@ class DollarPrintFunction (gdb.Function): func_value = gdb.lookup_global_symbol(func, gdb.SYMBOL_FUNCTIONS_DOMAIN).value() return func_value(arg.address) - if not ignore_errors: - debugPrint(f"No suitable Nim $ operator found for type: {getNimName(argTypeName)}\n") + printErrorOnce(argTypeName, "No suitable Nim $ operator found for type: " + argTypeName + "\n") return None def invoke(self, arg): @@ -197,11 +174,11 @@ class NimStringEqFunction (gdb.Function): @staticmethod def invoke_static(arg1,arg2): - if arg1.type.code == gdb.TYPE_CODE_PTR and arg1.type.target().name in NIM_STRING_TYPES: + if arg1.type.code == gdb.TYPE_CODE_PTR and arg1.type.target().name == "NimStringDesc": str1 = NimStringPrinter(arg1).to_string() else: str1 = arg1.string() - if arg2.type.code == gdb.TYPE_CODE_PTR and arg2.type.target().name in NIM_STRING_TYPES: + if arg2.type.code == gdb.TYPE_CODE_PTR and arg2.type.target().name == "NimStringDesc": str2 = NimStringPrinter(arg1).to_string() else: str2 = arg2.string() @@ -213,7 +190,6 @@ class NimStringEqFunction (gdb.Function): NimStringEqFunction() - ################################################################################ ##### GDB Command, equivalent of Nim's $ operator ################################################################################ @@ -229,7 +205,7 @@ class DollarPrintCmd (gdb.Command): strValue = DollarPrintFunction.invoke_static(param) if strValue: gdb.write( - str(NimStringPrinter(strValue)) + "\n", + NimStringPrinter(strValue).to_string() + "\n", gdb.STDOUT ) @@ -267,6 +243,7 @@ class KochCmd (gdb.Command): os.path.dirname(os.path.dirname(__file__)), "koch") def invoke(self, argument, from_tty): + import os subprocess.run([self.binary] + gdb.string_to_argv(argument)) KochCmd() @@ -320,14 +297,8 @@ class NimBoolPrinter: ################################################################################ -def strFromLazy(strVal): - if isinstance(strVal, str): - return strVal - else: - return strVal.value().string("utf-8") - class NimStringPrinter: - pattern = re.compile(r'^(NimStringDesc \*|NimStringV2)$') + pattern = re.compile(r'^NimStringDesc \*$') def __init__(self, val): self.val = val @@ -337,18 +308,10 @@ class NimStringPrinter: def to_string(self): if self.val: - if self.val.type.name == "NimStringV2": - l = int(self.val["len"]) - data = self.val["p"]["data"] - else: - l = int(self.val['Sup']['len']) - data = self.val["data"] - return data.lazy_string(encoding="utf-8", length=l) + l = int(self.val['Sup']['len']) + return self.val['data'][0].address.string("utf-8", "ignore", l) else: - return "" - - def __str__(self): - return strFromLazy(self.to_string()) + return "" class NimRopePrinter: pattern = re.compile(r'^tyObject_RopeObj__([A-Za-z0-9]*) \*$') @@ -371,43 +334,58 @@ class NimRopePrinter: ################################################################################ -def reprEnum(e, typ): - # Casts the value to the enum type and then calls the enum printer - e = int(e) - val = gdb.Value(e).cast(typ) - return strFromLazy(NimEnumPrinter(val).to_string()) +# proc reprEnum(e: int, typ: PNimType): string {.compilerRtl.} = +# ## Return string representation for enumeration values +# var n = typ.node +# if ntfEnumHole notin typ.flags: +# let o = e - n.sons[0].offset +# if o >= 0 and o <% typ.node.len: +# return $n.sons[o].name +# else: +# # ugh we need a slow linear search: +# var s = n.sons +# for i in 0 .. n.len-1: +# if s[i].offset == e: +# return $s[i].name +# result = $e & " (invalid data!)" -def enumNti(typeNimName, idString): - typeInfoName = "NTI" + typeNimName.lower() + "__" + idString + "_" - nti = gdb.lookup_global_symbol(typeInfoName) - if nti is None: - typeInfoName = "NTI" + "__" + idString + "_" - nti = gdb.lookup_global_symbol(typeInfoName) - return (typeInfoName, nti) +def reprEnum(e, typ): + """ this is a port of the nim runtime function `reprEnum` to python """ + e = int(e) + n = typ["node"] + flags = int(typ["flags"]) + # 1 << 2 is {ntfEnumHole} + if ((1 << 2) & flags) == 0: + o = e - int(n["sons"][0]["offset"]) + if o >= 0 and 0 < int(n["len"]): + return n["sons"][o]["name"].string("utf-8", "ignore") + else: + # ugh we need a slow linear search: + s = n["sons"] + for i in range(0, int(n["len"])): + if int(s[i]["offset"]) == e: + return s[i]["name"].string("utf-8", "ignore") + + return str(e) + " (invalid data!)" class NimEnumPrinter: - pattern = re.compile(r'^tyEnum_([A-Za-z0-9]+)__([A-Za-z0-9]*)$') - enumReprProc = gdb.lookup_global_symbol("reprEnum", gdb.SYMBOL_FUNCTIONS_DOMAIN) + pattern = re.compile(r'^tyEnum_(\w*)__([A-Za-z0-9]*)$') def __init__(self, val): - self.val = val - typeName = self.val.type.name - match = self.pattern.match(typeName) + self.val = val + match = self.pattern.match(self.val.type.name) self.typeNimName = match.group(1) - typeInfoName, self.nti = enumNti(self.typeNimName, match.group(2)) + typeInfoName = "NTI__" + match.group(2) + "_" + self.nti = gdb.lookup_global_symbol(typeInfoName) + + if self.nti is None: + printErrorOnce(typeInfoName, "NimEnumPrinter: lookup global symbol '" + typeInfoName + " failed for " + self.val.type.name + ".\n") def to_string(self): - if NimEnumPrinter.enumReprProc and self.nti: - # Use the old runtimes enumRepr function. - # We call the Nim proc itself so that the implementation is correct - f = gdb.newest_frame() - # We need to strip the quotes so it looks like an enum instead of a string - reprProc = NimEnumPrinter.enumReprProc.value() - return str(reprProc(self.val, self.nti.value(f).address)).strip('"') - elif dollarResult := DollarPrintFunction.invoke_static(self.val): - # New runtime doesn't use enumRepr so we instead try and call the - # dollar function for it - return str(NimStringPrinter(dollarResult)) + if self.nti: + arg0 = self.val + arg1 = self.nti.value(gdb.newest_frame()) + return reprEnum(arg0, arg1) else: return self.typeNimName + "(" + str(int(self.val)) + ")" @@ -417,27 +395,34 @@ class NimSetPrinter: ## the set printer is limited to sets that fit in an integer. Other ## sets are compiled to `NU8 *` (ptr uint8) and are invisible to ## gdb (currently). - pattern = re.compile(r'^tySet_tyEnum_([A-Za-z0-9]+)__([A-Za-z0-9]*)$') + pattern = re.compile(r'^tySet_tyEnum_(\w*)_([A-Za-z0-9]*)$') def __init__(self, val): self.val = val - typeName = self.val.type.name - match = self.pattern.match(typeName) - self.typeNimName = match.group(1) + match = self.pattern.match(self.val.type.name) + self.typeNimName = match.group(1) + + typeInfoName = "NTI__" + match.group(2) + "_" + self.nti = gdb.lookup_global_symbol(typeInfoName) + + if self.nti is None: + printErrorOnce(typeInfoName, "NimSetPrinter: lookup global symbol '"+ typeInfoName +" failed for " + self.val.type.name + ".\n") def to_string(self): - # Remove the tySet from the type name - typ = gdb.lookup_type(self.val.type.name[6:]) - enumStrings = [] - val = int(self.val) - i = 0 - while val > 0: - if (val & 1) == 1: - enumStrings.append(reprEnum(i, typ)) - val = val >> 1 - i += 1 + if self.nti: + nti = self.nti.value(gdb.newest_frame()) + enumStrings = [] + val = int(self.val) + i = 0 + while val > 0: + if (val & 1) == 1: + enumStrings.append(reprEnum(i, nti)) + val = val >> 1 + i += 1 - return '{' + ', '.join(enumStrings) + '}' + return '{' + ', '.join(enumStrings) + '}' + else: + return str(int(self.val)) ################################################################################ @@ -469,93 +454,33 @@ class NimHashSetPrinter: ################################################################################ -class NimSeq: - # Wrapper around sequences. - # This handles the differences between old and new runtime +class NimSeqPrinter: + # the pointer is explicity part of the type. So it is part of + # ``pattern``. + pattern = re.compile(r'^tySequence_\w* \*$') def __init__(self, val): self.val = val - # new runtime has sequences on stack, old has them on heap - self.new = val.type.code != gdb.TYPE_CODE_PTR - if self.new: - # Some seqs are just the content and to save repeating ourselves we do - # handle them here. Only thing that needs to check this is the len/data getters - self.isContent = val.type.name.endswith("Content") - - def __bool__(self): - if self.new: - return self.val is not None - else: - return bool(self.val) - - def __len__(self): - if not self: - return 0 - if self.new: - if self.isContent: - return int(self.val["cap"]) - else: - return int(self.val["len"]) - else: - return self.val["Sup"]["len"] - - @property - def data(self): - if self.new: - if self.isContent: - return self.val["data"] - elif self.val["p"]: - return self.val["p"]["data"] - else: - return self.val["data"] - - @property - def cap(self): - if not self: - return 0 - if self.new: - if self.isContent: - return int(self.val["cap"]) - elif self.val["p"]: - return int(self.val["p"]["cap"]) - else: - return 0 - return int(self.val['Sup']['reserved']) - -class NimSeqPrinter: - pattern = re.compile(r'^tySequence_\w*\s?\*?$') - - def __init__(self, val): - self.val = NimSeq(val) - def display_hint(self): return 'array' def to_string(self): - return f'seq({len(self.val)}, {self.val.cap})' + len = 0 + cap = 0 + if self.val: + len = int(self.val['Sup']['len']) + cap = int(self.val['Sup']['reserved']) + + return 'seq({0}, {1})'.format(len, cap) def children(self): if self.val: - val = self.val - length = len(val) - - if length <= 0: - return - - data = val.data - - inaccessible = False + length = int(self.val['Sup']['len']) + #align = len(str(length - 1)) for i in range(length): - if inaccessible: - return - try: - str(data[i]) - yield "data[{0}]".format(i), data[i] - except RuntimeError: - inaccessible = True - yield "data[{0}]".format(i), "inaccessible" - + yield ("data[{0}]".format(i), self.val["data"][i]) + ################################################################################ class NimArrayPrinter: @@ -599,9 +524,9 @@ class NimStringTablePrinter: def children(self): if self.val: - data = NimSeqPrinter(self.val['data'].referenced_value()) + data = NimSeqPrinter(self.val['data']) for idxStr, entry in data.children(): - if int(entry['Field0']) != 0: + if int(entry['Field2']) > 0: yield (idxStr + ".Field0", entry['Field0']) yield (idxStr + ".Field1", entry['Field1']) @@ -612,6 +537,7 @@ class NimTablePrinter: def __init__(self, val): self.val = val + # match = self.pattern.match(self.val.type.name) def display_hint(self): return 'map' @@ -622,7 +548,7 @@ class NimTablePrinter: if self.val: counter = int(self.val['counter']) if self.val['data']: - capacity = NimSeq(self.val["data"]).cap + capacity = int(self.val['data']['Sup']['len']) return 'Table({0}, {1})'.format(counter, capacity) @@ -630,22 +556,66 @@ class NimTablePrinter: if self.val: data = NimSeqPrinter(self.val['data']) for idxStr, entry in data.children(): - if int(entry['Field0']) != 0: + if int(entry['Field0']) > 0: yield (idxStr + '.Field1', entry['Field1']) yield (idxStr + '.Field2', entry['Field2']) -################################################################################ -class NimTuplePrinter: - pattern = re.compile(r"^tyTuple__([A-Za-z0-9]*)") +################################################################ - def __init__(self, val): - self.val = val +# this is untested, therefore disabled + +# class NimObjectPrinter: +# pattern = re.compile(r'^tyObject_.*$') + +# def __init__(self, val): +# self.val = val + +# def display_hint(self): +# return 'object' + +# def to_string(self): +# return str(self.val.type) + +# def children(self): +# if not self.val: +# yield "object", "" +# raise StopIteration + +# for (i, field) in enumerate(self.val.type.fields()): +# if field.type.code == gdb.TYPE_CODE_UNION: +# yield _union_field +# else: +# yield (field.name, self.val[field]) + +# def _union_field(self, i, field): +# rti = getNimRti(self.val.type.name) +# if rti is None: +# return (field.name, "UNION field can't be displayed without RTI") + +# node_sons = rti['node'].dereference()['sons'] +# prev_field = self.val.type.fields()[i - 1] + +# descriminant_node = None +# for i in range(int(node['len'])): +# son = node_sons[i].dereference() +# if son['name'].string("utf-8", "ignore") == str(prev_field.name): +# descriminant_node = son +# break +# if descriminant_node is None: +# raise ValueError("Can't find union descriminant field in object RTI") + +# if descriminant_node is None: raise ValueError("Can't find union field in object RTI") +# union_node = descriminant_node['sons'][int(self.val[prev_field])].dereference() +# union_val = self.val[field] + +# for f1 in union_val.type.fields(): +# for f2 in union_val[f1].type.fields(): +# if str(f2.name) == union_node['name'].string("utf-8", "ignore"): +# return (str(f2.name), union_val[f1][f2]) + +# raise ValueError("RTI is absent or incomplete, can't find union definition in RTI") - def to_string(self): - # We don't have field names so just print out the tuple as if it was anonymous - tupleValues = [str(self.val[field.name]) for field in self.val.type.fields()] - return f"({', '.join(tupleValues)})" ################################################################################ @@ -681,7 +651,7 @@ def register_nim_pretty_printers_for_object(objfile): if nimMainSym and nimMainSym.symtab.objfile == objfile: print("set Nim pretty printers for ", objfile.filename) - gdb.types.register_type_printer(objfile, NimTypePrinter()) + objfile.type_printers = [NimTypePrinter()] objfile.pretty_printers = [makematcher(var) for var in list(globals().values()) if hasattr(var, 'pattern')] # Register pretty printers for all objfiles that are already loaded. diff --git a/tools/nim.zsh-completion b/tools/nim.zsh-completion index 1c3670fd9..38ed93f73 100644 --- a/tools/nim.zsh-completion +++ b/tools/nim.zsh-completion @@ -1,120 +1,74 @@ #compdef nim -# Installation note: -# Please name this file as _nim (with underscore!) and copy it to a -# completions directory, either: -# - system wide one, like /usr/share/zsh/functions/Completion/Unix/ on Linux -# - or to a user directory like ~/scripts. Then you also need to add -# that directory in your ~/.zshrc to `fpath` array like so: -# fpath=( ~/scripts "${fpath[@]}" ) - _nim() { - local -a nimCommands=( - {compile,c}:'compile project with default code generator C' - {compileToC,cc}:'compile project with C code generator' - {compileToCpp,cpp}:'compile project to C++ code' - {compileToOC,objc}:'compile project to Objective C code' - 'js:compile project to Javascript' - 'e:run a Nimscript file' - 'doc:generate the HTML documentation for inputfile' - 'rst2html:convert a reStructuredText file to HTML' - 'doc2tex:generate the documentation for inputfile to LaTeX' - 'rst2tex:convert a reStructuredText file to TeX' - 'jsondoc:extract the documentation to a json file' - 'buildIndex:build an index for the whole documentation' - 'genDepend:generate a DOT file containing the module dependency graph' - 'dump:dump all defined conditionals and search paths' - 'check:checks the project for syntax and semantic' - {--help,-h}:'basic help' - '--fullhelp:show all switches' - {-v,--version}:'show version' - ) - - _arguments '*:: :->anyState' && return 0 - - if (( CURRENT == 1 )); then - _describe -t commands "Nim commands" nimCommands -V1 - return - fi - - local -a conditionalSymbols=( - release danger mingw androidNDK useNimRtl useMalloc noSignalHandler ssl - debug leanCompiler gcDestructors) - local -a sharedOpts=( - {--define\\:-,-d\\:-}'[define a conditional symbol]:x:($conditionalSymbols)' - {--undef\\:-,-u\\:-}'[undefine a conditional symbol]:x:($conditionalSymbols)' - {--path\\:-,-p\\:-}'[add path to search paths]:x:_files' - '--verbosity\:-[set verbosity level (default\: 1)]:x:(0 1 2 3)' - '--hints\:-[print compilation hints? (or `list`)]:x:(on off list)' - ) - local runOpts=( - {--run,-r}'[run the application]' - ) - local docOpts=( - '--index\:-[enable index .idx files?]:x:(on off)' - '--project\:-[output any dependency for doc?]:x:(on off)' - '--docInternal\:-[generate module-private documentation?]:x:(on off)' - ) - local -a codeOpts=( - {--forceBuild,-f}'[force rebuilding of all modules]' - '--stackTrace\:-[enable stack tracing?]:x:(on off)' - '--lineTrace\:-[enable line tracing?]:x:(on off)' - '--threads\:-[enable support for multi-threading?]:x:(on off)' - {--checks\\:-,-x\\:-}'[enable/disable all runtime checks?]:x:(on off)' - '--objChecks\:-[enable obj conversion checks]:x:(on off)' - '--fieldChecks\:-[enable case variant field checks?]:x:(on off)' - '--rangeChecks\:-[enable range checks?]:x:(on off)' - '--boundChecks\:-[enable bound checks?]:x:(on off)' - '--overflowChecks\:-[enable integer over-/underflow checks?]:x:(on off)' - {--assertions\\:-,-a\\:-}'[enable assertions?]:x:(on off)' - '--floatChecks\:-[enable floating point (NaN/Inf) checks?]:x:(on off)' - '--nanChecks\:-[enable NaN checks?]:x:(on off)' - '--infChecks\:-[enable Inf checks?]:x:(on off)' - '--nilChecks\:-[enable nil checks?]:x:(on off)' - '--expandArc\:-[show how given proc looks before final backend pass]' - '--expandMacro\:-[dump every generated AST from given macro]' - ) - local -a nativeOpts=( - '--opt\:-[optimization mode]:x:(none speed size)' - '--debugger\:native[use native debugger (gdb)]' - '--app\:-[generate this type of app (lib=dynamic)]:x:(console gui lib staticlib)' - '--cpu\:-[target architecture]:x:(alpha amd64 arm arm64 avr e2k esp hppa i386 ia64 js loongarch64 m68k mips mipsel mips64 mips64el msp430 nimvm powerpc powerpc64 powerpc64el riscv32 riscv64 sparc sparc64 vm wasm32)' - '--gc\:-[memory management algorithm to use (default\: refc)]:x:(refc arc orc markAndSweep boehm go regions none)' - '--os\:-[operating system to compile for]:x:(AIX Amiga Android Any Atari DOS DragonFly FreeBSD FreeRTOS Genode Haiku iOS Irix JS Linux MacOS MacOSX MorphOS NetBSD Netware NimVM NintendoSwitch OS2 OpenBSD PalmOS Standalone QNX SkyOS Solaris VxWorks Windows)' - '--panics\:-[turn panics into process termination (default\: off)]:x:(off on)' - ) - - case "$words[1]" in - compile|c|compileToC|cpp|compileToCpp|compileToOC|objc) - _arguments $codeOpts $runOpts $sharedOpts $nativeOpts \ - '*:filename:_files -g"*.nim"' - ;; - js) - _arguments $codeOpts $runOpts $sharedOpts \ - '*:filename:_files -g"*.nim"' - ;; - e) - _arguments $codeOpts $runOpts $sharedOpts \ - '*:filename:_files -g"*.nims"' - ;; - doc|doc2tex|jsondoc) - _arguments $runOpts $sharedOpts '*:filename:_files -g"*.nim"' - ;; - rst2html|rst2tex) - _arguments $runOpts $sharedOpts $docOpts '*:filename:_files -g"*.rst"' - ;; - buildIndex|genDepend|check) - _arguments $sharedOpts '*:filename:_files -g"*.nim"' - ;; - dump) - _arguments $sharedOpts - ;; - *) - _arguments '*:filename:_files -g"*"' - ;; - esac - - return 1 + _arguments -C \ + ':command:(( + {compile,c}\:compile\ project\ with\ default\ code\ generator\ C + doc\:generate\ the\ documentation\ for\ inputfile + {compileToC,cc}\:compile\ project\ with\ C\ code\ generator + {compileToCpp,cpp}\:compile\ project\ to\ C++\ code + {compileToOC,objc}\:compile\ project\ to\ Objective\ C\ code + js\:compile\ project\ to\ Javascript + e\:run\ a\ Nimscript\ file + rst2html\:convert\ a\ reStructuredText\ file\ to\ HTML + rst2tex\:convert\ a\ reStructuredText\ file\ to\ TeX + jsondoc\:extract\ the\ documentation\ to\ a\ json\ file + buildIndex\:build\ an\ index\ for\ the\ whole\ documentation + genDepend\:generate\ a\ DOT\ file\ containing\ the\ module\ dependency\ graph + dump\:dump\ all\ defined\ conditionals\ and\ search\ paths + check\:checks\ the\ project\ for\ syntax\ and\ semantic + ))' \ + '*-r[run the application]' \ + '*--run[run the application]' \ + '*-p=[add path to search paths]' \ + '*--path=[add path to search paths]' \ + '*-d=[define a conditional symbol]' \ + '*--define=[define a conditional symbol]' \ + '*-u=[undefine a conditional symbol]' \ + '*--undef=[undefine a conditional symbol]' \ + '*-f[force rebuilding of all modules]' \ + '*--forceBuild[force rebuilding of all modules]' \ + '*--stackTrace=on[turn stack tracing on]' \ + '*--stackTrace=off[turn stack tracing off]' \ + '*--lineTrace=on[turn line tracing on]' \ + '*--lineTrace=off[turn line tracing off]' \ + '*--threads=on[turn support for multi-threading on]' \ + '*--threads=off[turn support for multi-threading off]' \ + '*-x=on[turn all runtime checks on]' \ + '*-x=off[turn all runtime checks off]' \ + '*--checks=on[turn all runtime checks on]' \ + '*--checks=off[turn all runtime checks off]' \ + '*--objChecks=on[turn obj conversion checks on]' \ + '*--objChecks=off[turn obj conversion checks off]' \ + '*--fieldChecks=on[turn case variant field checks on]' \ + '*--fieldChecks=off[turn case variant field checks off]' \ + '*--rangeChecks=on[turn range checks on]' \ + '*--rangeChecks=off[turn range checks off]' \ + '*--boundChecks=on[turn bound checks on]' \ + '*--boundChecks=off[turn bound checks off]' \ + '*--overflowChecks=on[turn int over-/underflow checks on]' \ + '*--overflowChecks=off[turn int over-/underflow checks off]' \ + '*-a[turn assertions on]' \ + '*-a[turn assertions off]' \ + '*--assertions=on[turn assertions on]' \ + '*--assertions=off[turn assertions off]' \ + '*--floatChecks=on[turn all floating point (NaN/Inf) checks on]' \ + '*--floatChecks=off[turn all floating point (NaN/Inf) checks off]' \ + '*--nanChecks=on[turn NaN checks on]' \ + '*--nanChecks=off[turn NaN checks off]' \ + '*--infChecks=on[turn Inf checks on]' \ + '*--infChecks=off[turn Inf checks off]' \ + '*--nilChecks=on[turn nil checks on]' \ + '*--nilChecks=off[turn nil checks off]' \ + '*--opt=none[do not optimize]' \ + '*--opt=speed[optimize for speed|size - use -d:release for a release build]' \ + '*--opt=size[optimize for size]' \ + '*--debugger:native[use native debugger (gdb)]' \ + '*--app=console[generate a console app]' \ + '*--app=gui[generate a GUI app]' \ + '*--app=lib[generate a dynamic library]' \ + '*--app=staticlib[generate a static library]' \ + ':filename:_files -g"*.nim"' } _nim "$@" diff --git a/tools/nimblepkglist.nim b/tools/nimblepkglist.nim index 92e1cad20..870944ab0 100644 --- a/tools/nimblepkglist.nim +++ b/tools/nimblepkglist.nim @@ -1,6 +1,3 @@ -#[ -deadcode? -]# import base64, strutils, json, htmlgen, dom, algorithm type @@ -56,16 +53,16 @@ proc processContent(content: string) = var officialPkgListDiv = document.getElementById("officialPkgList") officialPkgListDiv.innerHTML = - (p("There are currently " & $officialCount & + p("There are currently " & $officialCount & " official packages in the Nimble package repository.") & - ul(officialList)).cstring + ul(officialList) var unofficialPkgListDiv = document.getElementById("unofficialPkgList") unofficialPkgListDiv.innerHTML = - (p("There are currently " & $unofficialCount & + p("There are currently " & $unofficialCount & " unofficial packages in the Nimble package repository.") & - ul(unofficialList)).cstring + ul(unofficialList) proc gotPackageList(apiReply: TData) {.exportc.} = let decoded = decodeContent($apiReply.content) @@ -76,5 +73,5 @@ proc gotPackageList(apiReply: TData) {.exportc.} = var unofficialPkgListDiv = document.getElementById("unofficialPkgList") let msg = p("Unable to retrieve package list: ", code(getCurrentExceptionMsg())) - officialPkgListDiv.innerHTML = msg.cstring - unofficialPkgListDiv.innerHTML = msg.cstring + officialPkgListDiv.innerHTML = msg + unofficialPkgListDiv.innerHTML = msg diff --git a/tools/nimfind.nim b/tools/nimfind.nim new file mode 100644 index 000000000..eca3d8eb2 --- /dev/null +++ b/tools/nimfind.nim @@ -0,0 +1,235 @@ +# +# +# The Nim Compiler +# (c) Copyright 2018 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +## Nimfind is a tool that helps to give editors IDE like capabilities. + +when not defined(nimcore): + {.error: "nimcore MUST be defined for Nim's core tooling".} +when not defined(nimfind): + {.error: "nimfind MUST be defined for Nim's nimfind tool".} + +const Usage = """ +Nimfind - Tool to find declarations or usages for Nim symbols +Usage: + nimfind [options] file.nim:line:col + +Options: + --help, -h show this help + --rebuild rebuild the index + --project:file.nim use file.nim as the entry point + +In addition, all command line options of Nim that do not affect code generation +are supported. +""" + +import strutils, os, parseopt + +import "../compiler" / [options, commands, modules, sem, + passes, passaux, msgs, ast, + idents, modulegraphs, lineinfos, cmdlinehelper, + pathutils] + +import db_sqlite + +proc createDb(db: DbConn) = + db.exec(sql""" + create table if not exists filenames( + id integer primary key, + fullpath varchar(8000) not null + ); + """) + db.exec sql"create index if not exists FilenameIx on filenames(fullpath);" + + # every sym can have potentially 2 different definitions due to forward + # declarations. + db.exec(sql""" + create table if not exists syms( + id integer primary key, + nimid integer not null, + name varchar(256) not null, + defline integer not null, + defcol integer not null, + deffile integer not null, + deflineB integer not null default 0, + defcolB integer not null default 0, + deffileB integer not null default 0, + foreign key (deffile) references filenames(id), + foreign key (deffileB) references filenames(id) + ); + """) + + db.exec(sql""" + create table if not exists usages( + id integer primary key, + nimid integer not null, + line integer not null, + col integer not null, + colB integer not null, + file integer not null, + foreign key (file) references filenames(id), + foreign key (nimid) references syms(nimid) + ); + """) + db.exec sql"create index if not exists UsagesIx on usages(file, line);" + +proc toDbFileId*(db: DbConn; conf: ConfigRef; fileIdx: FileIndex): int = + if fileIdx == FileIndex(-1): return -1 + let fullpath = toFullPath(conf, fileIdx) + let row = db.getRow(sql"select id from filenames where fullpath = ?", fullpath) + let id = row[0] + if id.len == 0: + result = int db.insertID(sql"insert into filenames(fullpath) values (?)", + fullpath) + else: + result = parseInt(id) + +type + FinderRef = ref object of RootObj + db: DbConn + +proc writeDef(graph: ModuleGraph; s: PSym; info: TLineInfo) = + let f = FinderRef(graph.backend) + f.db.exec(sql"""insert into syms(nimid, name, defline, defcol, deffile) values (?, ?, ?, ?, ?)""", + s.id, s.name.s, info.line, info.col, + toDbFileId(f.db, graph.config, info.fileIndex)) + +proc writeDefResolveForward(graph: ModuleGraph; s: PSym; info: TLineInfo) = + let f = FinderRef(graph.backend) + f.db.exec(sql"""update syms set deflineB = ?, defcolB = ?, deffileB = ? + where nimid = ?""", info.line, info.col, + toDbFileId(f.db, graph.config, info.fileIndex), s.id) + +proc writeUsage(graph: ModuleGraph; s: PSym; info: TLineInfo) = + let f = FinderRef(graph.backend) + f.db.exec(sql"""insert into usages(nimid, line, col, colB, file) values (?, ?, ?, ?, ?)""", + s.id, info.line, info.col, info.col + s.name.s.len - 1, + toDbFileId(f.db, graph.config, info.fileIndex)) + +proc performSearch(conf: ConfigRef; dbfile: AbsoluteFile) = + var db = open(connection=string dbfile, user="nim", password="", + database="nim") + let pos = conf.m.trackPos + let fid = toDbFileId(db, conf, pos.fileIndex) + let known = toFullPath(conf, pos.fileIndex) + let nimids = db.getRow(sql"""select distinct nimid from usages where line = ? and file = ? and ? between col and colB""", + pos.line, fid, pos.col) + if nimids.len > 0: + var idSet = "" + for id in nimids: + if idSet.len > 0: idSet.add ", " + idSet.add id + var outputLater = "" + for r in db.rows(sql"""select line, col, filenames.fullpath from usages + inner join filenames on filenames.id = file + where nimid in (?)""", idSet): + let line = parseInt(r[0]) + let col = parseInt(r[1]) + let file = r[2] + if file == known and line == pos.line.int: + # output the line we already know last: + outputLater.add file & ":" & $line & ":" & $(col+1) & "\n" + else: + echo file, ":", line, ":", col+1 + if outputLater.len > 0: stdout.write outputLater + close(db) + +proc setupDb(g: ModuleGraph; dbfile: AbsoluteFile) = + var f = FinderRef() + removeFile(dbfile) + f.db = open(connection=string dbfile, user="nim", password="", + database="nim") + createDb(f.db) + f.db.exec(sql"pragma journal_mode=off") + # This MUST be turned off, otherwise it's way too slow even for testing purposes: + f.db.exec(sql"pragma SYNCHRONOUS=off") + f.db.exec(sql"pragma LOCKING_MODE=exclusive") + g.backend = f + +proc mainCommand(graph: ModuleGraph) = + let conf = graph.config + let dbfile = getNimcacheDir(conf) / RelativeFile"nimfind.db" + if not fileExists(dbfile) or optForceFullMake in conf.globalOptions: + clearPasses(graph) + registerPass graph, verbosePass + registerPass graph, semPass + conf.cmd = cmdIdeTools + wantMainModule(conf) + setupDb(graph, dbfile) + + graph.onDefinition = writeUsage # writeDef + graph.onDefinitionResolveForward = writeUsage # writeDefResolveForward + graph.onUsage = writeUsage + + if not fileExists(conf.projectFull): + quit "cannot find file: " & conf.projectFull.string + add(conf.searchPaths, conf.libpath) + # do not stop after the first error: + conf.errorMax = high(int) + try: + compileProject(graph) + finally: + close(FinderRef(graph.backend).db) + performSearch(conf, dbfile) + +proc processCmdLine*(pass: TCmdLinePass, cmd: string; conf: ConfigRef) = + var p = parseopt.initOptParser(cmd) + while true: + parseopt.next(p) + case p.kind + of cmdEnd: break + of cmdLongOption, cmdShortOption: + case p.key.normalize + of "help", "h": + stdout.writeLine(Usage) + quit() + of "project": + conf.projectName = p.val + of "rebuild": + incl conf.globalOptions, optForceFullMake + else: processSwitch(pass, p, conf) + of cmdArgument: + let info = p.key.split(':') + if info.len == 3: + let (dir, file, ext) = info[0].splitFile() + conf.projectName = findProjectNimFile(conf, dir) + if conf.projectName.len == 0: conf.projectName = info[0] + try: + conf.m.trackPos = newLineInfo(conf, AbsoluteFile info[0], + parseInt(info[1]), parseInt(info[2])-1) + except ValueError: + quit "invalid command line" + else: + quit "invalid command line" + +proc handleCmdLine(cache: IdentCache; conf: ConfigRef) = + let self = NimProg( + suggestMode: true, + processCmdLine: processCmdLine, + mainCommand: mainCommand + ) + self.initDefinesProg(conf, "nimfind") + + if paramCount() == 0: + stdout.writeLine(Usage) + return + + self.processCmdLineAndProjectPath(conf) + + # Find Nim's prefix dir. + let binaryPath = findExe("nim") + if binaryPath == "": + raise newException(IOError, + "Cannot find Nim standard library: Nim compiler not in PATH") + conf.prefixDir = AbsoluteDir binaryPath.splitPath().head.parentDir() + if not dirExists(conf.prefixDir / RelativeDir"lib"): + conf.prefixDir = AbsoluteDir"" + + discard self.loadConfigsAndRunMainCommand(cache, conf) + +handleCmdLine(newIdentCache(), newConfigRef()) diff --git a/tools/nimfind.nims b/tools/nimfind.nims new file mode 100644 index 000000000..3013c360d --- /dev/null +++ b/tools/nimfind.nims @@ -0,0 +1,2 @@ +--define:nimfind +--define:nimcore diff --git a/tools/nimgrab.nim b/tools/nimgrab.nim index 7e4161faf..937a5dcd4 100644 --- a/tools/nimgrab.nim +++ b/tools/nimgrab.nim @@ -1,14 +1,33 @@ -import std/[os, httpclient] -proc syncDownload(url, file: string) = - var client = newHttpClient() - proc onProgressChanged(total, progress, speed: BiggestInt) = - echo "Downloading " & url & " " & $(speed div 1000) & "kb/s" - echo clamp(int(progress*100 div total), 0, 100), "%" - client.onProgressChanged = onProgressChanged - client.downloadFile(url, file) - echo "100%" +when defined(windows): + import os, urldownloader + + proc syncDownload(url, file: string) = + proc progress(status: DownloadStatus, progress: uint, total: uint, + message: string) {.procvar, gcsafe.} = + echo "Downloading " & url + let t = total.BiggestInt + if t != 0: + echo clamp(int(progress.BiggestInt*100 div t), 0, 100), "%" + else: + echo "0%" + + downloadToFile(url, file, {optUseCache}, progress) + echo "100%" + +else: + import os, asyncdispatch, httpclient + + proc syncDownload(url, file: string) = + var client = newHttpClient() + proc onProgressChanged(total, progress, speed: BiggestInt) = + echo "Downloading " & url & " " & $(speed div 1000) & "kb/s" + echo clamp(int(progress*100 div total), 0, 100), "%" + + client.onProgressChanged = onProgressChanged + client.downloadFile(url, file) + echo "100%" if os.paramCount() != 2: quit "Usage: nimgrab " diff --git a/tools/nimgrep.nim b/tools/nimgrep.nim index 599c616ba..51685e556 100644 --- a/tools/nimgrep.nim +++ b/tools/nimgrep.nim @@ -8,156 +8,86 @@ # import - os, strutils, parseopt, pegs, re, terminal, osproc, tables, algorithm, times + os, strutils, parseopt, pegs, re, terminal const - Version = "2.0.0" - Usage = "nimgrep - Nim Grep Searching and Replacement Utility Version " & - Version & """ + Version = "1.5" + Usage = "nimgrep - Nim Grep Utility Version " & Version & """ - (c) 2012-2020 Andreas Rumpf -""" & slurp "../doc/nimgrep_cmdline.txt" - -# Limitations / ideas / TODO: -# * No unicode support with --cols -# * Consider making --onlyAscii default, since dumping binary data has -# stability and security repercussions -# * Mode - reads entire buffer by whole from stdin, which is bad for streaming. -# To implement line-by-line reading after adding option to turn off -# multiline matches -# * Add some form of file pre-processing, e.g. feed binary files to utility -# `strings` and then do the search inside these strings -# * Add --showCol option to also show column (of match), not just line; it -# makes it easier when jump to line+col in an editor or on terminal - - -# Search results for a file are modelled by these levels: -# FileResult -> Block -> Output/Chunk -> SubLine -# -# 1. SubLine is an entire line or its part. -# -# 2. Chunk, which is a sequence of SubLine, represents a match and its -# surrounding context. -# Output is a Chunk or one of auxiliary results like an openError. -# -# 3. Block, which is a sequence of Chunks, is not present as a separate type. -# It will just be separated from another Block by newline when there is -# more than 3 lines in it. -# Here is an example of a Block where only 1 match is found and -# 1 line before and 1 line after of context are required: -# -# ...a_line_before...................................... <<\n") - elif newLine and optFilenames notin options and optPipe notin options: + elif newLine: if oneline: printBlockFile(filename) printBlockLineN(":" & $line & ":") @@ -314,437 +231,232 @@ proc blockHeader(filename: string, line: int|string, replMode=false) = printBlockLineN($line.`$`.align(alignment) & ":") stdout.write("\n") -proc newLn(curCol: var Column) = - stdout.write("\n") - curCol.file = 0 - curCol.terminal = 0 - -# We reserve 10+3 chars on the right in --cols mode (optLimitChars). -# If the current match touches this right margin, subLine before it will -# be cropped (even if space is enough for subLine after the match — we -# currently don't have a way to know it since we get it afterwards). -const matchPaddingFromRight = 10 -const ellipsis = "..." - -proc lineHeader(filename: string, line: int|string, isMatch: bool, - curCol: var Column) = +proc lineHeader(filename: string, line: int|string, isMatch: bool) = let lineSym = if isMatch: $line & ":" else: $line & " " - if not newLine and optFilenames notin options and optPipe notin options: + if not newLine: if oneline: printFile(filename) printLineN(":" & lineSym, isMatch) - curcol.terminal += filename.len + 1 + lineSym.len else: printLineN(lineSym.align(alignment+1), isMatch) - curcol.terminal += lineSym.align(alignment+1).len - stdout.write(" "); curCol.terminal += 1 - curCol.terminal = curCol.terminal mod termWidth - if optLimitChars in options and - curCol.terminal > limitCharUsr - matchPaddingFromRight - ellipsis.len: - newLn(curCol) + stdout.write(" ") -proc reserveChars(mi: MatchInfo): int = - if optLimitChars in options: - let patternChars = afterPattern(mi.match, 0) + 1 - result = patternChars + ellipsis.len + matchPaddingFromRight - else: - result = 0 - -# Our substitutions of non-printable symbol to ASCII character are similar to -# those of programm 'less'. -const lowestAscii = 0x20 # lowest ASCII Latin printable symbol (@) -const largestAscii = 0x7e -const by2ascii = 2 # number of ASCII chars to represent chars < lowestAscii -const by3ascii = 3 # number of ASCII chars to represent chars > largestAscii - -proc printExpanded(s: string, curCol: var Column, isMatch: bool, - limitChar: int) = - # Print taking into account tabs and optOnlyAscii (and also optLimitChar: - # the proc called from printCropped but we need to check column < limitChar - # also here, since exact cut points are known only after tab expansion). - # With optOnlyAscii non-ascii chars are highlighted even in matches. - # - # use buffer because: - # 1) we need to print non-ascii character inside matches while keeping the - # amount of color escape sequences minimal. - # 2) there is a report that fwrite buffering is slow on MacOS - # https://github.com/nim-lang/Nim/pull/15612#discussion_r510538326 - const bufSize = 8192 # typical for fwrite too - var buffer: string - const normal = 0 - const special = 1 - var lastAdded = normal - template dumpBuf() = - if lastAdded == normal: - printContents(buffer, isMatch) - else: - printSpecial(buffer) - template addBuf(i: int, s: char|string, size: int) = - if lastAdded != i or buffer.len + size > bufSize: - dumpBuf() - buffer.setlen(0) - buffer.add s - lastAdded = i - for c in s: - let charsAllowed = limitChar - curCol.terminal - if charsAllowed <= 0: - break - if lowestAscii <= int(c) and int(c) <= largestAscii: # ASCII latin - addBuf(normal, c, 1) - curCol.file += 1; curCol.terminal += 1 - elif (not optOnlyAscii) and c != '\t': # the same, print raw - addBuf(normal, c, 1) - curCol.file += 1; curCol.terminal += 1 - elif c == '\t': - let spaces = 8 - (curCol.file mod 8) - let spacesAllowed = min(spaces, charsAllowed) - curCol.file += spaces - curCol.terminal += spacesAllowed - if expandTabs: - if optOnlyAscii: # print a nice box for tab - addBuf(special, " ", 1) - addBuf(normal, " ".repeat(spacesAllowed-1), spacesAllowed-1) - else: - addBuf(normal, " ".repeat(spacesAllowed), spacesAllowed) - else: - addBuf(normal, '\t', 1) - else: # substitute characters that are not ACSII Latin - if int(c) < lowestAscii: - let substitute = char(int(c) + 0x40) # use common "control codes" - addBuf(special, "^" & substitute, by2ascii) - curCol.terminal += by2ascii - else: # int(c) > largestAscii - curCol.terminal += by3ascii - let substitute = '\'' & c.BiggestUInt.toHex(2) - addBuf(special, substitute, by3ascii) - curCol.file += 1 - if buffer.len > 0: - dumpBuf() - -template nextCharacter(c: char, file: var int, term: var int) = - if lowestAscii <= int(c) and int(c) <= largestAscii: # ASCII latin - file += 1 - term += 1 - elif (not optOnlyAscii) and c != '\t': # the same, print raw - file += 1 - term += 1 - elif c == '\t': - term += 8 - (file mod 8) - file += 8 - (file mod 8) - elif int(c) < lowestAscii: - file += 1 - term += by2ascii - else: # int(c) > largestAscii: - file += 1 - term += by3ascii - -proc calcTermLen(s: string, firstCol: int, chars: int, fromLeft: bool): int = - # calculate additional length added by Tabs expansion and substitutions - var col = firstCol - var first, last: int - if fromLeft: - first = max(0, s.len - chars) - last = s.len - 1 - else: - first = 0 - last = min(s.len - 1, chars - 1) - for c in s[first .. last]: - nextCharacter(c, col, result) - -proc printCropped(s: string, curCol: var Column, fromLeft: bool, - limitChar: int, isMatch = false) = - # print line `s`, may be cropped if option --cols was set - const eL = ellipsis.len - if optLimitChars notin options: - if not expandTabs and not optOnlyAscii: # for speed mostly - printContents(s, isMatch) - else: - printExpanded(s, curCol, isMatch, limitChar) - else: # limit columns, expand Tabs is also forced - var charsAllowed = limitChar - curCol.terminal - if fromLeft and charsAllowed < eL: - charsAllowed = eL - if (not fromLeft) and charsAllowed <= 0: - # already overflown and ellipsis shold be in place - return - let fullLenWithin = calcTermLen(s, curCol.file, charsAllowed, fromLeft) - # additional length from Tabs and special symbols - let addLen = fullLenWithin - min(s.len, charsAllowed) - # determine that the string is guaranteed to fit within `charsAllowed` - let fits = - if s.len > charsAllowed: - false - else: - if isMatch: fullLenWithin <= charsAllowed - eL - else: fullLenWithin <= charsAllowed - if fits: - printExpanded(s, curCol, isMatch, limitChar = high(int)) - else: - if fromLeft: - printBold ellipsis - curCol.terminal += eL - # find position `pos` where the right side of line will fit charsAllowed - var col = 0 - var term = 0 - var pos = min(s.len, max(0, s.len - (charsAllowed - eL))) - while pos <= s.len - 1: - let c = s[pos] - nextCharacter(c, col, term) - if term >= addLen: - break - inc pos - curCol.file = pos - # TODO don't expand tabs when cropped from the left - difficult, meaningless - printExpanded(s[pos .. s.len - 1], curCol, isMatch, - limitChar = high(int)) - else: - let last = max(-1, min(s.len - 1, charsAllowed - eL - 1)) - printExpanded(s[0 .. last], curCol, isMatch, limitChar-eL) - let numDots = limitChar - curCol.terminal - printBold ".".repeat(numDots) - curCol.terminal = limitChar - -proc printMatch(fileName: string, mi: MatchInfo, curCol: var Column) = - let sLines = mi.match.splitLines() - for i, l in sLines: +proc printMatch(fileName: string, mi: MatchInfo) = + let lines = mi.match.splitLines() + for i, l in lines: if i > 0: - lineHeader(filename, mi.lineBeg + i, isMatch = true, curCol) - let charsAllowed = limitCharUsr - curCol.terminal - if charsAllowed > 0: - printCropped(l, curCol, fromLeft = false, limitCharUsr, isMatch = true) - else: - curCol.overflowMatches += 1 - if i < sLines.len - 1: - newLn(curCol) + lineHeader(filename, mi.lineBeg + i, isMatch = true) + writeColored(l) + if i < lines.len - 1: + stdout.write("\n") -proc getSubLinesBefore(buf: string, curMi: MatchInfo): string = - let first = beforePattern(buf, curMi.first-1, linesBefore+1) - result = substr(buf, first, curMi.first-1) - -proc printSubLinesBefore(filename: string, beforeMatch: string, lineBeg: int, - curCol: var Column, reserveChars: int, - replMode=false) = +proc printLinesBefore(si: SearchInfo, curMi: MatchInfo, nLines: int, + replMode=false) = # start block: print 'linesBefore' lines before current match `curMi` - let sLines = splitLines(beforeMatch) - let startLine = lineBeg - sLines.len + 1 - blockHeader(filename, lineBeg, replMode=replMode) - for i, l in sLines: - let isLastLine = i == sLines.len - 1 - lineHeader(filename, startLine + i, isMatch = isLastLine, curCol) - let limit = if isLastLine: limitCharUsr - reserveChars else: limitCharUsr - l.printCropped(curCol, fromLeft = isLastLine, limitChar = limit) - if not isLastLine: - newLn(curCol) + let first = beforePattern(si.buf, curMi.first-1, nLines) + let lines = splitLines(substr(si.buf, first, curMi.first-1)) + let startLine = curMi.lineBeg - lines.len + 1 + blockHeader(si.filename, curMi.lineBeg, replMode=replMode) + for i, l in lines: + lineHeader(si.filename, startLine + i, isMatch = (i == lines.len - 1)) + stdout.write(l) + if i < lines.len - 1: + stdout.write("\n") -proc getSubLinesAfter(buf: string, mi: MatchInfo): string = - let last = afterPattern(buf, mi.last+1, 1+linesAfter) - let skipByte = # workaround posix: suppress extra line at the end of file - if (last == buf.len-1 and buf.len >= 2 and - buf[^1] == '\l' and buf[^2] != '\c'): 1 - else: 0 - result = substr(buf, mi.last+1, last - skipByte) - -proc printOverflow(filename: string, line: int, curCol: var Column) = - if curCol.overflowMatches > 0: - lineHeader(filename, line, isMatch = true, curCol) - printBold("(" & $curCol.overflowMatches & " matches skipped)") - newLn(curCol) - curCol.overflowMatches = 0 - -proc printSubLinesAfter(filename: string, afterMatch: string, matchLineEnd: int, - curCol: var Column) = +proc printLinesAfter(si: SearchInfo, mi: MatchInfo, nLines: int) = # finish block: print 'linesAfter' lines after match `mi` - let sLines = splitLines(afterMatch) - if sLines.len == 0: # EOF - newLn(curCol) + let s = si.buf + let last = afterPattern(s, mi.last+1, nLines) + let lines = splitLines(substr(s, mi.last+1, last)) + if lines.len == 0: # EOF + stdout.write("\n") else: - sLines[0].printCropped(curCol, fromLeft = false, limitCharUsr) - # complete the line after the match itself - newLn(curCol) - printOverflow(filename, matchLineEnd, curCol) - for i in 1 ..< sLines.len: - lineHeader(filename, matchLineEnd + i, isMatch = false, curCol) - sLines[i].printCropped(curCol, fromLeft = false, limitCharUsr) - newLn(curCol) + stdout.write(lines[0]) # complete the line after match itself + stdout.write("\n") + let skipLine = # workaround posix line ending at the end of file + if last == s.len-1 and s.len >= 2 and s[^1] == '\l' and s[^2] != '\c': 1 + else: 0 + for i in 1 ..< lines.len - skipLine: + lineHeader(si.filename, mi.lineEnd + i, isMatch = false) + stdout.write(lines[i]) + stdout.write("\n") + if linesAfter + linesBefore >= 2 and not newLine: stdout.write("\n") -proc getSubLinesBetween(buf: string, prevMi: MatchInfo, - curMi: MatchInfo): string = - buf.substr(prevMi.last+1, curMi.first-1) - -proc printBetweenMatches(filename: string, betweenMatches: string, - lastLineBeg: int, - curCol: var Column, reserveChars: int) = +proc printBetweenMatches(si: SearchInfo, prevMi: MatchInfo, curMi: MatchInfo) = # continue block: print between `prevMi` and `curMi` - let sLines = betweenMatches.splitLines() - sLines[0].printCropped(curCol, fromLeft = false, limitCharUsr) - # finish the line of previous Match - if sLines.len > 1: - newLn(curCol) - printOverflow(filename, lastLineBeg - sLines.len + 1, curCol) - for i in 1 ..< sLines.len: - let isLastLine = i == sLines.len - 1 - lineHeader(filename, lastLineBeg - sLines.len + i + 1, - isMatch = isLastLine, curCol) - let limit = if isLastLine: limitCharUsr - reserveChars else: limitCharUsr - sLines[i].printCropped(curCol, fromLeft = isLastLine, limitChar = limit) - if not isLastLine: - newLn(curCol) + let lines = si.buf.substr(prevMi.last+1, curMi.first-1).splitLines() + stdout.write(lines[0]) # finish the line of previous Match + if lines.len > 1: + stdout.write("\n") + for i in 1 ..< lines.len: + lineHeader(si.filename, prevMi.lineEnd + i, + isMatch = (i == lines.len - 1)) + stdout.write(lines[i]) + if i < lines.len - 1: + stdout.write("\n") -proc printReplacement(fileName: string, buf: string, mi: MatchInfo, - repl: string, showRepl: bool, curPos: int, +proc printContextBetween(si: SearchInfo, prevMi, curMi: MatchInfo) = + # print context after previous match prevMi and before current match curMi + let nLinesBetween = curMi.lineBeg - prevMi.lineEnd + if nLinesBetween <= linesAfter + linesBefore + 1: # print as 1 block + printBetweenMatches(si, prevMi, curMi) + else: # finalize previous block and then print next block + printLinesAfter(si, prevMi, 1+linesAfter) + printLinesBefore(si, curMi, linesBefore+1) + +proc printReplacement(si: SearchInfo, mi: MatchInfo, repl: string, + showRepl: bool, curPos: int, newBuf: string, curLine: int) = - var curCol: Column - printSubLinesBefore(fileName, getSubLinesBefore(buf, mi), mi.lineBeg, - curCol, reserveChars(mi)) - printMatch(fileName, mi, curCol) - printSubLinesAfter(fileName, getSubLinesAfter(buf, mi), mi.lineEnd, curCol) + printLinesBefore(si, mi, linesBefore+1) + printMatch(si.fileName, mi) + printLinesAfter(si, mi, 1+linesAfter) stdout.flushFile() if showRepl: + let newSi: SearchInfo = (buf: newBuf, filename: si.filename) let miForNewBuf: MatchInfo = (first: newBuf.len, last: newBuf.len, lineBeg: curLine, lineEnd: curLine, match: "") - printSubLinesBefore(fileName, getSubLinesBefore(newBuf, miForNewBuf), - miForNewBuf.lineBeg, curCol, reserveChars(miForNewBuf), - replMode=true) + printLinesBefore(newSi, miForNewBuf, linesBefore+1, replMode=true) let replLines = countLineBreaks(repl, 0, repl.len-1) let miFixLines: MatchInfo = (first: mi.first, last: mi.last, lineBeg: curLine, lineEnd: curLine + replLines, match: repl) - printMatch(fileName, miFixLines, curCol) - printSubLinesAfter(fileName, getSubLinesAfter(buf, miFixLines), - miFixLines.lineEnd, curCol) - if linesAfter + linesBefore >= 2 and not newLine: stdout.write("\n") + printMatch(si.fileName, miFixLines) + printLinesAfter(si, miFixLines, 1+linesAfter) stdout.flushFile() -proc replace1match(filename: string, buf: string, mi: MatchInfo, i: int, - r: string; newBuf: var string, curLine: var int): bool = - newBuf.add(buf.substr(i, mi.first-1)) - inc(curLine, countLineBreaks(buf, i, mi.first-1)) +proc doReplace(si: SearchInfo, mi: MatchInfo, i: int, r: string; + newBuf: var string, curLine: var int, reallyReplace: var bool) = + newBuf.add(si.buf.substr(i, mi.first-1)) + inc(curLine, countLineBreaks(si.buf, i, mi.first-1)) if optConfirm in options: - printReplacement(filename, buf, mi, r, showRepl=true, i, newBuf, curLine) + printReplacement(si, mi, r, showRepl=true, i, newBuf, curLine) case confirm() of ceAbort: quit(0) - of ceYes: gVar.reallyReplace = true + of ceYes: reallyReplace = true of ceAll: - gVar.reallyReplace = true + reallyReplace = true options.excl(optConfirm) of ceNo: - gVar.reallyReplace = false + reallyReplace = false of ceNone: - gVar.reallyReplace = false + reallyReplace = false options.excl(optConfirm) - elif optPipe notin options: - printReplacement(filename, buf, mi, r, showRepl=gVar.reallyReplace, i, - newBuf, curLine) - if gVar.reallyReplace: - result = true + else: + printReplacement(si, mi, r, showRepl=reallyReplace, i, newBuf, curLine) + if reallyReplace: newBuf.add(r) inc(curLine, countLineBreaks(r, 0, r.len-1)) else: newBuf.add(mi.match) inc(curLine, countLineBreaks(mi.match, 0, mi.match.len-1)) -template updateCounters(output: Output) = - case output.kind - of blockFirstMatch, blockNextMatch: inc(gVar.matches) - of justCount: inc(gVar.matches, output.matches) - of openError: inc(gVar.errors) - of rejected, blockEnd, fileContents, outputFileName: discard +proc processFile(pattern; filename: string; counter: var int, errors: var int) = + var filenameShown = false + template beforeHighlight = + if not filenameShown and optVerbose notin options and not oneline: + printBlockFile(filename) + stdout.write("\n") + stdout.flushFile() + filenameShown = true -proc printInfo(filename:string, output: Output) = - case output.kind - of openError: - printError("cannot open path '" & filename & "': " & output.msg) - of rejected: - if optVerbose in options: - echo "(rejected: ", output.reason, ")" - of justCount: - echo " (" & $output.matches & " matches)" - of blockFirstMatch, blockNextMatch, blockEnd, fileContents, outputFileName: - discard + var buffer: string + if optFilenames in options: + buffer = filename + else: + try: + buffer = system.readFile(filename) + except IOError: + printError "Error: cannot open file: " & filename + inc(errors) + return + if optVerbose in options: + printFile(filename) + stdout.write("\n") + stdout.flushFile() + var result: string -proc printOutput(filename: string, output: Output, curCol: var Column) = - case output.kind - of openError, rejected, justCount: printInfo(filename, output) - of fileContents: discard # impossible - of outputFileName: - printCropped(output.name, curCol, fromLeft=false, limitCharUsr) - newLn(curCol) - of blockFirstMatch: - printSubLinesBefore(filename, output.pre, output.match.lineBeg, - curCol, reserveChars(output.match)) - printMatch(filename, output.match, curCol) - of blockNextMatch: - printBetweenMatches(filename, output.pre, output.match.lineBeg, - curCol, reserveChars(output.match)) - printMatch(filename, output.match, curCol) - of blockEnd: - printSubLinesAfter(filename, output.blockEnding, output.firstLine, curCol) - if linesAfter + linesBefore >= 2 and not newLine and - optFilenames notin options: stdout.write("\n") + if optReplace in options: + result = newStringOfCap(buffer.len) -iterator searchFile(pattern: Pattern; buffer: string): Output = + var lineRepl = 1 + let si: SearchInfo = (buf: buffer, filename: filename) var prevMi, curMi: MatchInfo - prevMi.lineEnd = 1 + curMi.lineEnd = 1 var i = 0 var matches: array[0..re.MaxSubpatterns-1, string] for j in 0..high(matches): matches[j] = "" - while true: + var reallyReplace = true + while i < buffer.len: let t = findBounds(buffer, pattern, matches, i) if t.first < 0 or t.last < t.first: - if prevMi.lineBeg != 0: # finalize last match - yield Output(kind: blockEnd, - blockEnding: getSubLinesAfter(buffer, prevMi), - firstLine: prevMi.lineEnd) + if optReplace notin options and prevMi.lineBeg != 0: # finalize last match + printLinesAfter(si, prevMi, 1+linesAfter) + stdout.flushFile() break - let lineBeg = prevMi.lineEnd + countLineBreaks(buffer, i, t.first-1) + let lineBeg = curMi.lineEnd + countLineBreaks(buffer, i, t.first-1) curMi = (first: t.first, last: t.last, lineBeg: lineBeg, lineEnd: lineBeg + countLineBreaks(buffer, t.first, t.last), match: buffer.substr(t.first, t.last)) - if prevMi.lineBeg == 0: # no prev. match, so no prev. block to finalize - let pre = getSubLinesBefore(buffer, curMi) - prevMi = curMi - yield Output(kind: blockFirstMatch, pre: pre, match: move(curMi)) + beforeHighlight() + inc counter + if optReplace notin options: + if prevMi.lineBeg == 0: # no previous match, so no previous block to finalize + printLinesBefore(si, curMi, linesBefore+1) + else: + printContextBetween(si, prevMi, curMi) + printMatch(si.fileName, curMi) + stdout.flushFile() else: - let nLinesBetween = curMi.lineBeg - prevMi.lineEnd - if nLinesBetween <= linesAfter + linesBefore + 1: # print as 1 block - let pre = getSubLinesBetween(buffer, prevMi, curMi) - prevMi = curMi - yield Output(kind: blockNextMatch, pre: pre, match: move(curMi)) - else: # finalize previous block and then print next block - let after = getSubLinesAfter(buffer, prevMi) - yield Output(kind: blockEnd, blockEnding: after, - firstLine: prevMi.lineEnd) - let pre = getSubLinesBefore(buffer, curMi) - prevMi = curMi - yield Output(kind: blockFirstMatch, - pre: pre, - match: move(curMi)) + let r = replace(curMi.match, pattern, replacement % matches) + doReplace(si, curMi, i, r, result, lineRepl, reallyReplace) + i = t.last+1 - when typeof(pattern) is Regex: - if buffer.len > MaxReBufSize: - yield Output(kind: openError, msg: "PCRE size limit is " & $MaxReBufSize) + prevMi = curMi -func detectBin(buffer: string): bool = - for i in 0 ..< min(1024, buffer.len): - if buffer[i] == '\0': - return true + if optReplace in options: + result.add(substr(buffer, i)) # finalize new buffer after last match + var f: File + if open(f, filename, fmWrite): + f.write(result) + f.close() + else: + quit "cannot open file for overwriting: " & filename -proc compilePeg(initPattern: string): Peg = - var pattern = initPattern - if optWord in options: - pattern = r"(^ / !\letter)(" & pattern & r") !\letter" - if optIgnoreStyle in options: - pattern = "\\y " & pattern - elif optIgnoreCase in options: - pattern = "\\i " & pattern - result = peg(pattern) +proc hasRightFileName(path: string): bool = + let filename = path.lastPathPart + let ex = filename.splitFile.ext.substr(1) # skip leading '.' + if extensions.len != 0: + var matched = false + for x in items(extensions): + if os.cmpPaths(x, ex) == 0: + matched = true + break + if not matched: return false + for x in items(skipExtensions): + if os.cmpPaths(x, ex) == 0: return false + if includeFile.len != 0: + var matched = false + for x in items(includeFile): + if filename.match(x): + matched = true + break + if not matched: return false + for x in items(excludeFile): + if filename.match(x): return false + result = true + +proc hasRightDirectory(path: string): bool = + let dirname = path.lastPathPart + for x in items(excludeDir): + if dirname.match(x): return false + result = true proc styleInsensitive(s: string): string = template addx = @@ -780,438 +492,28 @@ proc styleInsensitive(s: string): string = addx() else: addx() -proc compileRegex(initPattern: string): Regex = - var pattern = initPattern - var reflags = {reStudy} - if optIgnoreStyle in options: - pattern = styleInsensitive(pattern) - if optWord in options: - # see https://github.com/nim-lang/Nim/issues/13528#issuecomment-592786443 - pattern = r"(^|\W)(:?" & pattern & r")($|\W)" - if {optIgnoreCase, optIgnoreStyle} * options != {}: - reflags.incl reIgnoreCase - result = if optRex in options: rex(pattern, reflags) - else: re(pattern, reflags) - -template declareCompiledPatterns(compiledStruct: untyped, - StructType: untyped, - body: untyped) = - {.hint[XDeclaredButNotUsed]: off.} - if optRegex notin options: - var compiledStruct: StructType[Peg] - template compile1Pattern(p: string, pat: Peg) = - if p!="": pat = p.compilePeg() - proc compileArray(initPattern: seq[string]): seq[Peg] = - for pat in initPattern: - result.add pat.compilePeg() - body - else: - var compiledStruct: StructType[Regex] - template compile1Pattern(p: string, pat: Regex) = - if p!="": pat = p.compileRegex() - proc compileArray(initPattern: seq[string]): seq[Regex] = - for pat in initPattern: - result.add pat.compileRegex() - body - {.hint[XDeclaredButNotUsed]: on.} - -template ensureIncluded(includePat: seq[Pattern], str: string, - body: untyped) = - if includePat.len != 0: - var matched = false - for pat in includePat: - if str.contains(pat): - matched = true - break - if not matched: - body - -template ensureExcluded(excludePat: seq[Pattern], str: string, - body: untyped) = - {.warning[UnreachableCode]: off.} - for pat in excludePat: - if str.contains(pat, 0): - body - break - {.warning[UnreachableCode]: on.} - -func checkContext(context: string, searchOptC: SearchOptComp[Pattern]): bool = - ensureIncluded searchOptC.inContext, context: - return false - ensureExcluded searchOptC.notInContext, context: - return false - result = true - -iterator processFile(searchOptC: SearchOptComp[Pattern], filename: string, - yieldContents=false): Output = - var buffer: string - - var error = false - if optFilenames in options: - buffer = filename - elif optPipe in options: - buffer = stdin.readAll() - else: - try: - buffer = system.readFile(filename) - except IOError as e: - yield Output(kind: openError, msg: "readFile failed") - error = true - - if not error: - var reject = false - var reason: string - if searchOpt.checkBin in {biOff, biOnly}: - let isBin = detectBin(buffer) - if isBin and searchOpt.checkBin == biOff: - reject = true - reason = "binary file" - if (not isBin) and searchOpt.checkBin == biOnly: - reject = true - reason = "text file" - - if not reject: - ensureIncluded searchOptC.inFile, buffer: - reject = true - reason = "doesn't contain a requested match" - - if not reject: - ensureExcluded searchOptC.notInFile, buffer: - reject = true - reason = "contains a forbidden match" - - if reject: - yield Output(kind: rejected, reason: move(reason)) - elif optFilenames in options and searchOpt.pattern == "": - yield Output(kind: outputFileName, name: move(buffer)) - else: - var found = false - var cnt = 0 - let skipCheckContext = (searchOpt.notInContext.len == 0 and - searchOpt.inContext.len == 0) - if skipCheckContext: - for output in searchFile(searchOptC.pattern, buffer): - found = true - if optCount notin options: - yield output - else: - if output.kind in {blockFirstMatch, blockNextMatch}: - inc(cnt) - else: - var context: string - var outputAccumulator: seq[Output] - for outp in searchFile(searchOptC.pattern, buffer): - if outp.kind in {blockFirstMatch, blockNextMatch}: - outputAccumulator.add outp - context.add outp.pre - context.add outp.match.match - elif outp.kind == blockEnd: - outputAccumulator.add outp - context.add outp.blockEnding - # context has been formed, now check it: - if checkContext(context, searchOptC): - found = true - for output in outputAccumulator: - if optCount notin options: - yield output - else: - if output.kind in {blockFirstMatch, blockNextMatch}: - inc(cnt) - context = "" - outputAccumulator.setLen 0 - # end `if skipCheckContext`. - if optCount in options and cnt > 0: - yield Output(kind: justCount, matches: cnt) - if yieldContents and found and optCount notin options: - yield Output(kind: fileContents, buffer: move(buffer)) - -proc hasRightPath(path: string, walkOptC: WalkOptComp[Pattern]): bool = - if not ( - walkOpt.extensions.len > 0 or walkOpt.notExtensions.len > 0 or - walkOpt.filename.len > 0 or walkOpt.notFilename.len > 0 or - walkOpt.notDirPath.len > 0 or walkOpt.dirPath.len > 0): - return true - let filename = path.lastPathPart - let ex = filename.splitFile.ext.substr(1) # skip leading '.' - if walkOpt.extensions.len != 0: - var matched = false - for x in walkOpt.extensions: - if os.cmpPaths(x, ex) == 0: - matched = true - break - if not matched: return false - for x in walkOpt.notExtensions: - if os.cmpPaths(x, ex) == 0: return false - ensureIncluded walkOptC.filename, filename: - return false - ensureExcluded walkOptC.notFilename, filename: - return false - let parent = path.parentDir - ensureExcluded walkOptC.notDirPath, parent: - return false - ensureIncluded walkOptC.dirPath, parent: - return false - result = true - -proc isRightDirectory(path: string, walkOptC: WalkOptComp[Pattern]): bool = - ## --dirname can be only checked when the final path is known - ## so this proc is suitable for files only. - if walkOptC.dirname.len > 0: - var badDirname = false - var (nextParent, dirname) = splitPath(path) - # check that --dirname matches for one of directories in parent path: - while dirname != "": - badDirname = false - ensureIncluded walkOptC.dirname, dirname: - badDirname = true - if not badDirname: - break - (nextParent, dirname) = splitPath(nextParent) - if badDirname: # badDirname was set to true for all the dirs - return false - result = true - -proc descendToDirectory(path: string, walkOptC: WalkOptComp[Pattern]): bool = - ## --notdirname can be checked for directories immediately for optimization to - ## prevent descending into undesired directories. - if walkOptC.notDirname.len > 0: - let dirname = path.lastPathPart - ensureExcluded walkOptC.notDirname, dirname: - return false - result = true - -iterator walkDirBasic(dir: string, walkOptC: WalkOptComp[Pattern]): string - {.closure.} = - var dirStack = @[dir] # stack of directories - var timeFiles = newSeq[(times.Time, string)]() - while dirStack.len > 0: - let d = dirStack.pop() - let rightDirForFiles = d.isRightDirectory(walkOptC) - var files = newSeq[string]() - var dirs = newSeq[string]() - for kind, path in walkDir(d, skipSpecial = true): +proc walker(pattern; dir: string; counter: var int, errors: var int) = + if existsDir(dir): + for kind, path in walkDir(dir): case kind of pcFile: - if path.hasRightPath(walkOptC) and rightDirForFiles: - files.add(path) + if path.hasRightFileName: + processFile(pattern, path, counter, errors) of pcLinkToFile: - if optFollow in options and path.hasRightPath(walkOptC) and - rightDirForFiles: - files.add(path) + if optFollow in options and path.hasRightFileName: + processFile(pattern, path, counter, errors) of pcDir: - if optRecursive in options and path.descendToDirectory(walkOptC): - dirs.add path + if optRecursive in options and path.hasRightDirectory: + walker(pattern, path, counter, errors) of pcLinkToDir: if optFollow in options and optRecursive in options and - path.descendToDirectory(walkOptC): - dirs.add path - if sortTime: # sort by time - collect files before yielding - for file in files: - var time: Time - try: - time = getLastModificationTime(file) # can fail for broken symlink - except: - discard - timeFiles.add((time, file)) - else: # alphanumeric sort, yield immediately after sorting - files.sort() - for file in files: - yield file - dirs.sort(order = SortOrder.Descending) - for dir in dirs: - dirStack.add(dir) - if sortTime: - timeFiles.sort(sortTimeOrder) - for (_, file) in timeFiles: - yield file - -iterator walkRec(paths: seq[string]): tuple[error: string, filename: string] - {.closure.} = - declareCompiledPatterns(walkOptC, WalkOptComp): - walkOptC.notFilename.add walkOpt.notFilename.compileArray() - walkOptC.filename.add walkOpt.filename.compileArray() - walkOptC.dirname.add walkOpt.dirname.compileArray() - walkOptC.notDirname.add walkOpt.notDirname.compileArray() - walkOptC.dirPath.add walkOpt.dirPath.compileArray() - walkOptC.notDirPath.add walkOpt.notDirPath.compileArray() - for path in paths: - if dirExists(path): - for p in walkDirBasic(path, walkOptC): - yield ("", p) - else: - yield ( - if fileExists(path): ("", path) - else: ("Error: no such file or directory: ", path)) - -proc replaceMatches(pattern: Pattern; filename: string, buffer: string, - fileResult: FileResult) = - var newBuf = newStringOfCap(buffer.len) - - var changed = false - var lineRepl = 1 - var i = 0 - for output in fileResult: - if output.kind in {blockFirstMatch, blockNextMatch}: - let curMi = output.match - let r = replacef(curMi.match, pattern, replacement) - if replace1match(filename, buffer, curMi, i, r, newBuf, lineRepl): - changed = true - i = curMi.last + 1 - if changed and optPipe notin options: - newBuf.add(substr(buffer, i)) # finalize new buffer after last match - var f: File - if open(f, filename, fmWrite): - f.write(newBuf) - f.close() - else: - printError "cannot open file for overwriting: " & filename - inc(gVar.errors) - elif optPipe in options: # always print new buffer to stdout in pipe mode - newBuf.add(substr(buffer, i)) # finalize new buffer after last match - stdout.write(newBuf) - -template processFileResult(pattern: Pattern; filename: string, - fileResult: untyped) = - var filenameShown = false - template showFilename = - if not filenameShown: - printBlockFile(filename) - stdout.write("\n") - stdout.flushFile() - filenameShown = true - if optVerbose in options: - showFilename - if optReplace notin options: - var curCol: Column - var toFlush: bool - for output in fileResult: - updateCounters(output) - toFlush = true - if output.kind notin {rejected, openError, justCount} and not oneline: - showFilename - if output.kind == justCount and oneline: - printFile(filename & ":") - printOutput(filename, output, curCol) - if nWorkers == 0 and output.kind in {blockFirstMatch, blockNextMatch}: - stdout.flushFile() # flush immediately in single thread mode - if toFlush: stdout.flushFile() + path.hasRightDirectory: + walker(pattern, path, counter, errors) + elif existsFile(dir): + processFile(pattern, dir, counter, errors) else: - var buffer = "" - var matches: FileResult - for output in fileResult: - updateCounters(output) - case output.kind - of rejected, openError, justCount, outputFileName: - printInfo(filename, output) - of blockFirstMatch, blockNextMatch, blockEnd: - matches.add(output) - of fileContents: buffer = output.buffer - if matches.len > 0: - replaceMatches(pattern, filename, buffer, matches) - -proc run1Thread() = - declareCompiledPatterns(searchOptC, SearchOptComp): - compile1Pattern(searchOpt.pattern, searchOptC.pattern) - searchOptC.inFile.add searchOpt.inFile.compileArray() - searchOptC.notInFile.add searchOpt.notInFile.compileArray() - searchOptC.inContext.add searchOpt.inContext.compileArray() - searchOptC.notInContext.add searchOpt.notInContext.compileArray() - if optPipe in options: - processFileResult(searchOptC.pattern, "-", - processFile(searchOptC, "-", - yieldContents=optReplace in options)) - for entry in walkRec(paths): - if entry.error != "": - inc(gVar.errors) - printError (entry.error & entry.filename) - continue - processFileResult(searchOptC.pattern, entry.filename, - processFile(searchOptC, entry.filename, - yieldContents=optReplace in options)) - -# Multi-threaded version: all printing is being done in the Main thread. -# Totally nWorkers+1 additional threads are created (workers + pathProducer). -# An example of case nWorkers=2: -# -# ------------------ initial paths ------------------- -# | Main thread |----------------->| pathProducer | -# ------------------ ------------------- -# ^ | | -# resultsChan | walking errors, | | searchRequestsChan -# | number of files | -----+----- -# ----+--------------------------- | | -# | | (when walking finished) |a path |a path to file -# | | | | -# | | V V -# | | ------------ ------------ -# | | | worker 1 | | worker 2 | -# | | ------------ ------------ -# | | matches in the file | | -# | -------------------------------- | -# | matches in the file | -# ---------------------------------------------- -# -# The matches from each file are passed at once as FileResult type. - -proc worker(initSearchOpt: SearchOpt) {.thread.} = - searchOpt = initSearchOpt # init thread-local var - declareCompiledPatterns(searchOptC, SearchOptComp): - compile1Pattern(searchOpt.pattern, searchOptC.pattern) - searchOptC.inFile.add searchOpt.inFile.compileArray() - searchOptC.notInFile.add searchOpt.notInFile.compileArray() - searchOptC.inContext.add searchOpt.inContext.compileArray() - searchOptC.notInContext.add searchOpt.notInContext.compileArray() - while true: - let (fileNo, filename) = searchRequestsChan.recv() - var fileResult: FileResult - for output in processFile(searchOptC, filename, - yieldContents=(optReplace in options)): - fileResult.add(output) - resultsChan.send((false, fileNo, filename, move(fileResult))) - -proc pathProducer(arg: (seq[string], WalkOpt)) {.thread.} = - let paths = arg[0] - walkOpt = arg[1] # init thread-local copy of opt - var - nextFileN = 0 - for entry in walkRec(paths): - if entry.error == "": - searchRequestsChan.send((nextFileN, entry.filename)) - else: - resultsChan.send((false, nextFileN, entry.filename, - @[Output(kind: openError, msg: entry.error)])) - nextFileN += 1 - resultsChan.send((true, nextFileN, "", @[])) # pass total number of files - -proc runMultiThread() = - var - workers = newSeq[Thread[SearchOpt]](nWorkers) - storage = newTable[int, (string, FileResult) ]() - # file number -> tuple[filename, fileResult - accumulated data structure] - firstUnprocessedFile = 0 # for always processing files in the same order - open(searchRequestsChan) - open(resultsChan) - for n in 0 ..< nWorkers: - createThread(workers[n], worker, searchOpt) - var producerThread: Thread[(seq[string], WalkOpt)] - createThread(producerThread, pathProducer, (paths, walkOpt)) - declareCompiledPatterns(pat, SinglePattern): - compile1Pattern(searchOpt.pattern, pat.pattern) - template add1fileResult(fileNo: int, fname: string, fResult: FileResult) = - storage[fileNo] = (fname, fResult) - while storage.haskey(firstUnprocessedFile): - let fileResult = storage[firstUnprocessedFile][1] - let filename = storage[firstUnprocessedFile][0] - processFileResult(pat.pattern, filename, fileResult) - storage.del(firstUnprocessedFile) - firstUnprocessedFile += 1 - var totalFiles = -1 # will be known when pathProducer finishes - while totalFiles == -1 or firstUnprocessedFile < totalFiles: - let msg = resultsChan.recv() - if msg.finished: - totalFiles = msg.fileNo - else: - add1fileResult(msg.fileNo, msg.filename, msg.fileResult) + printError "Error: no such file or directory: " & dir + inc(errors) proc reportError(msg: string) = printError "Error: " & msg @@ -1231,15 +533,6 @@ proc checkOptions(subset: TOptions, a, b: string) = if subset <= options: quit("cannot specify both '$#' and '$#'" % [a, b]) -proc parseNonNegative(str: string, key: string): int = - try: - result = parseInt(str) - except ValueError: - reportError("Option " & key & " requires an integer but '" & - str & "' was given") - if result < 0: - reportError("A positive integer is expected for option " & key) - when defined(posix): useWriteStyled = terminal.isatty(stdout) # that should be before option processing to allow override of useWriteStyled @@ -1248,21 +541,14 @@ for kind, key, val in getopt(): case kind of cmdArgument: if options.contains(optStdin): - paths.add(key) - elif not searchOpt.patternSet: - searchOpt.pattern = key - searchOpt.patternSet = true - elif options.contains(optReplace) and not replacementSet: + filenames.add(key) + elif pattern.len == 0: + pattern = key + elif options.contains(optReplace) and replacement.len == 0: replacement = key - replacementSet = true else: - paths.add(key) + filenames.add(key) of cmdLongOption, cmdShortOption: - proc addNotEmpty(s: var seq[string], name: string) = - if name == "": - reportError("empty string given for option --" & key & - " (did you forget `:`?)") - s.add name case normalize(key) of "find", "f": incl(options, optFind) of "replace", "!": incl(options, optReplace) @@ -1281,154 +567,99 @@ for kind, key, val in getopt(): of "confirm": incl(options, optConfirm) of "stdin": incl(options, optStdin) of "word", "w": incl(options, optWord) - of "ignorecase", "ignore-case", "i": incl(options, optIgnoreCase) - of "ignorestyle", "ignore-style", "y": incl(options, optIgnoreStyle) - of "threads", "j": - if val == "": - nWorkers = countProcessors() - else: - nWorkers = parseNonNegative(val, key) - of "extensions", "ex", "ext": walkOpt.extensions.add val.split('|') - of "nextensions", "notextensions", "nex", "notex", - "noext", "no-ext": # 2 deprecated options - walkOpt.notExtensions.add val.split('|') - of "dirname", "di": - walkOpt.dirname.addNotEmpty val - of "ndirname", "notdirname", "ndi", "notdi", - "excludedir", "exclude-dir", "ed": # 3 deprecated options - walkOpt.notDirname.addNotEmpty val - of "dirpath", "dirp", - "includedir", "include-dir", "id": # 3 deprecated options - walkOpt.dirPath.addNotEmpty val - of "ndirpath", "notdirpath", "ndirp", "notdirp": - walkOpt.notDirPath.addNotEmpty val - of "filename", "fi", - "includefile", "include-file", "if": # 3 deprecated options - walkOpt.filename.addNotEmpty val - of "nfilename", "nfi", "notfilename", "notfi", - "excludefile", "exclude-file", "ef": # 3 deprecated options - walkOpt.notFilename.addNotEmpty val - of "infile", "inf", - "matchfile", "match", "mf": # 3 deprecated options - searchOpt.inFile.addNotEmpty val - of "ninfile", "notinfile", "ninf", "notinf", - "nomatchfile", "nomatch", "nf": # 3 options are deprecated - searchOpt.notInFile.addNotEmpty val - of "incontext", "inc": - searchOpt.inContext.addNotEmpty val - of "nincontext", "notincontext", "ninc", "notinc": - searchOpt.notInContext.addNotEmpty val - of "bin": - case val - of "on": searchOpt.checkBin = biOn - of "off": searchOpt.checkBin = biOff - of "only": searchOpt.checkBin = biOnly - else: reportError("unknown value for --bin") - of "text", "t": searchOpt.checkBin = biOff - of "count": incl(options, optCount) - of "sorttime", "sort-time", "s": - case normalize(val) - of "off": sortTime = false - of "", "on", "asc", "ascending": - sortTime = true - sortTimeOrder = SortOrder.Ascending - of "desc", "descending": - sortTime = true - sortTimeOrder = SortOrder.Descending - else: reportError("invalid value '" & val & "' for --sortTime") - of "nocolor", "no-color": useWriteStyled = false + of "ignorecase", "i": incl(options, optIgnoreCase) + of "ignorestyle", "y": incl(options, optIgnoreStyle) + of "ext": extensions.add val.split('|') + of "noext": skipExtensions.add val.split('|') + of "excludedir", "exclude-dir": excludeDir.add rex(val) + of "includefile", "include-file": includeFile.add rex(val) + of "excludefile", "exclude-file": excludeFile.add rex(val) + of "nocolor": useWriteStyled = false of "color": case val of "auto": discard - of "off", "never", "false": useWriteStyled = false - of "", "on", "always", "true": useWriteStyled = true + of "never", "false": useWriteStyled = false + of "", "always", "true": useWriteStyled = true else: reportError("invalid value '" & val & "' for --color") - of "colortheme", "color-theme": + of "colortheme": colortheme = normalize(val) if colortheme notin ["simple", "bnw", "ack", "gnu"]: reportError("unknown colortheme '" & val & "'") of "beforecontext", "before-context", "b": - linesBefore = parseNonNegative(val, key) + try: + linesBefore = parseInt(val) + except ValueError: + reportError("option " & key & " requires an integer but '" & + val & "' was given") of "aftercontext", "after-context", "a": - linesAfter = parseNonNegative(val, key) + try: + linesAfter = parseInt(val) + except ValueError: + reportError("option " & key & " requires an integer but '" & + val & "' was given") of "context", "c": - linesContext = parseNonNegative(val, key) - of "newline", "l": - newLine = true - # Tabs are aligned automatically for --group, --newLine, --filenames - expandTabs = false - of "group", "g": - oneline = false - expandTabs = false - of "cols", "%": - incl(options, optLimitChars) - termWidth = terminalWidth() - if val == "auto" or key == "%": - limitCharUsr = termWidth - when defined(windows): # Windows cmd & powershell add an empty line - limitCharUsr -= 1 # when printing '\n' right after the last column - elif val == "": - limitCharUsr = 80 - else: - limitCharUsr = parseNonNegative(val, key) - of "onlyascii", "only-ascii", "@": - if val == "" or val == "on" or key == "@": - optOnlyAscii = true - elif val == "off": - optOnlyAscii = false - else: - printError("unknown value for --onlyAscii option") + try: + linesContext = parseInt(val) + except ValueError: + reportError("option --context requires an integer but '" & + val & "' was given") + of "newline", "l": newLine = true + of "oneline": oneline = true + of "group", "g": oneline = false of "verbose": incl(options, optVerbose) - of "filenames": - incl(options, optFilenames) - expandTabs = false + of "filenames": incl(options, optFilenames) of "help", "h": writeHelp() of "version", "v": writeVersion() - of "": incl(options, optPipe) else: reportError("unrecognized option '" & key & "'") of cmdEnd: assert(false) # cannot happen checkOptions({optFind, optReplace}, "find", "replace") -checkOptions({optCount, optReplace}, "count", "replace") checkOptions({optPeg, optRegex}, "peg", "re") checkOptions({optIgnoreCase, optIgnoreStyle}, "ignore_case", "ignore_style") checkOptions({optFilenames, optReplace}, "filenames", "replace") -checkOptions({optPipe, optStdin}, "-", "stdin") -checkOptions({optPipe, optFilenames}, "-", "filenames") -checkOptions({optPipe, optConfirm}, "-", "confirm") -checkOptions({optPipe, optRecursive}, "-", "recursive") linesBefore = max(linesBefore, linesContext) linesAfter = max(linesAfter, linesContext) -if optPipe in options and paths.len != 0: - reportError("both - and paths are specified") - if optStdin in options: - searchOpt.pattern = ask("pattern [ENTER to exit]: ") - if searchOpt.pattern.len == 0: quit(0) + pattern = ask("pattern [ENTER to exit]: ") + if pattern.len == 0: quit(0) if optReplace in options: replacement = ask("replacement [supports $1, $# notations]: ") -if optReplace in options and not replacementSet: - reportError("provide REPLACEMENT as second argument (use \"\" for empty one)") -if optReplace in options and paths.len == 0 and optPipe notin options: - reportError("provide paths for replacement explicitly (use . for current directory)") - -if searchOpt.pattern == "" and optFilenames notin options: +if pattern.len == 0: reportError("empty pattern was given") else: - if paths.len == 0 and optPipe notin options: - paths.add(".") - if optPipe in options or nWorkers == 0: - run1Thread() + var counter = 0 + var errors = 0 + if filenames.len == 0: + filenames.add(os.getCurrentDir()) + if optRegex notin options: + if optWord in options: + pattern = r"(^ / !\letter)(" & pattern & r") !\letter" + if optIgnoreStyle in options: + pattern = "\\y " & pattern + elif optIgnoreCase in options: + pattern = "\\i " & pattern + let pegp = peg(pattern) + for f in items(filenames): + walker(pegp, f, counter, errors) else: - runMultiThread() - if gVar.errors != 0: - printError $gVar.errors & " errors" - if searchOpt.pattern != "": - # PATTERN allowed to be empty if --filenames is given - printBold($gVar.matches & " matches") + var reflags = {reStudy} + if optIgnoreStyle in options: + pattern = styleInsensitive(pattern) + if optWord in options: + pattern = r"\b(:?" & pattern & r")\b" + if {optIgnoreCase, optIgnoreStyle} * options != {}: + reflags.incl reIgnoreCase + let rep = if optRex in options: rex(pattern, reflags) + else: re(pattern, reflags) + for f in items(filenames): + walker(rep, f, counter, errors) + if errors != 0: + printError $errors & " errors" + if counter == 1: stdout.write("\n") - if gVar.errors != 0: + stdout.write($counter & " matches\n") + if errors != 0: quit(1) diff --git a/tools/nimgrep.nim.cfg b/tools/nimgrep.nim.cfg index 64d3edc7a..6d0ea5aad 100644 --- a/tools/nimgrep.nim.cfg +++ b/tools/nimgrep.nim.cfg @@ -1,4 +1,5 @@ -# don't use --gc:refc because of bug -# https://github.com/nim-lang/Nim/issues/14138 . -# --gc:orc and --gc:markandsweep work well. ---threads:on --gc:orc +# The GC is stable enough now: + +#--gc:none + + diff --git a/tools/niminst/buildsh.nimf b/tools/niminst/buildsh.nimf index 6b99c49ee..9289feb90 100644 --- a/tools/niminst/buildsh.nimf +++ b/tools/niminst/buildsh.nimf @@ -1,6 +1,6 @@ #? stdtmpl(subsChar='?') | standard #proc generateBuildShellScript(c: ConfigData): string = -# result = "#!/bin/sh\n# Generated from niminst\n" & +# result = "#! /bin/sh\n# Generated from niminst\n" & # "# Template is in tools/niminst/buildsh.nimf\n" & # "# To regenerate run ``niminst csource`` or ``koch csource``\n" @@ -21,23 +21,10 @@ do optosname=$2 shift 2 ;; - --parallel) - parallel=$2 - shift 2 - ;; --extraBuildArgs) extraBuildArgs=" $2" shift 2 ;; - -h | --help) - echo "Options:" - echo " --os " - echo " --cpu " - echo " --osname Additional OS specification (used for Android)" - echo " --extraBuildArgs Additional arguments passed to the compiler" - echo " --parallel Multiprocess build. Requires GNU parallel" - exit 0 - ;; --) # End of all options shift break; @@ -52,15 +39,7 @@ do esac done -parallel="${parallel:-0}" CC="${CC:-gcc}" -if [ "$parallel" -gt 1 ]; then - if ! command -v sem > /dev/null; then - echo "Error: GNU parallel is required to use --parallel" - exit 1 - fi - CC="sem -j $parallel --id $$ ${CC}" -fi COMP_FLAGS="${CPPFLAGS:-} ${CFLAGS:-} ?{c.ccompiler.flags}$extraBuildArgs" LINK_FLAGS="${LDFLAGS:-} ?{c.linker.flags}" PS4="" @@ -109,14 +88,8 @@ case $uos in CC="clang" LINK_FLAGS="$LINK_FLAGS -lm" ;; - *crossos* ) - myos="crossos" - CC="clang" - LINK_FLAGS="$LINK_FLAGS -lm" - ;; *openbsd* ) myos="openbsd" - CC="clang" LINK_FLAGS="$LINK_FLAGS -lm" ;; *netbsd* ) @@ -139,11 +112,6 @@ case $uos in myos="solaris" LINK_FLAGS="$LINK_FLAGS -ldl -lm -lsocket -lnsl" ;; - *SunOS* ) - myos="solaris" - LINK_FLAGS="$LINK_FLAGS -ldl -lm -lsocket -lnsl" - isOpenIndiana="yes" - ;; *haiku* ) myos="haiku" LINK_FLAGS="$LINK_FLAGS -lroot -lnetwork" @@ -164,12 +132,7 @@ esac case $ucpu in *i386* | *i486* | *i586* | *i686* | *bepc* | *i86pc* ) - if [ "$isOpenIndiana" = "yes" ] || [ `uname -o` == "illumos" ] ; then - mycpu="amd64" - else - mycpu="i386" - fi - ;; + mycpu="i386" ;; *amd*64* | *x86-64* | *x86_64* ) mycpu="amd64" ;; *sparc*|*sun* ) @@ -192,16 +155,10 @@ case $ucpu in mycpu="powerpc64" ;; *power*|*ppc* ) if [ "$myos" = "freebsd" ] ; then - if [ "$ucpu" != "powerpc" ] ; then - COMP_FLAGS="$COMP_FLAGS -m64" - LINK_FLAGS="$LINK_FLAGS -m64" - fi + COMP_FLAGS="$COMP_FLAGS -m64" + LINK_FLAGS="$LINK_FLAGS -m64" mycpu=`uname -p` - case $mycpu in - powerpc64le) - mycpu="powerpc64el" - esac - else + else mycpu="powerpc" fi ;; @@ -223,16 +180,12 @@ case $ucpu in ;; *alpha* ) mycpu="alpha" ;; - *aarch64*|*arm64* ) - mycpu="arm64" ;; - *arm*|*armv6l*|*armv7l*|*armv8l* ) + *arm*|*armv6l*|*armv71* ) mycpu="arm" ;; - *riscv64|riscv* ) + *aarch64* ) + mycpu="arm64" ;; + *riscv64* ) mycpu="riscv64" ;; - *e2k* ) - mycpu="e2k" ;; - *loongarch64* ) - mycpu="loongarch64" ;; *) echo 2>&1 "Error: unknown processor: $ucpu" exit 1 @@ -264,9 +217,6 @@ case $myos in $CC $COMP_FLAGS -Ic_code -c ?{f} -o ?{changeFileExt(f, "o")} # add(linkCmd, " \\\n" & changeFileExt(f, "o")) # end for - if [ "$parallel" -gt 0 ]; then - sem --wait --id $$ - fi $CC -o ?{"$binDir/" & toLowerAscii(c.name)} ?linkCmd $LINK_FLAGS ;; # end for diff --git a/tools/niminst/debcreation.nim b/tools/niminst/debcreation.nim index 219cb44ce..60aa48639 100644 --- a/tools/niminst/debcreation.nim +++ b/tools/niminst/debcreation.nim @@ -9,10 +9,6 @@ import osproc, times, os, strutils - -when defined(nimPreviewSlimSystem): - import std/[assertions, syncio] - # http://www.debian.org/doc/manuals/maint-guide/ # Required files for debhelper. @@ -105,7 +101,7 @@ proc createChangelog(pkgName, version, maintainer: string): string = addN(" * Initial release.") addN("") addN(" -- " & maintainer & " " & - formatDateTime(utc(getTime()), "+0000")) + formatDateTime(getGMTime(getTime()), "+0000")) proc createRules(): string = ## Creates a nim application-agnostic rules file for building deb packages. diff --git a/tools/niminst/deinstall.nimf b/tools/niminst/deinstall.nimf index 0dcfda75e..8b4477369 100644 --- a/tools/niminst/deinstall.nimf +++ b/tools/niminst/deinstall.nimf @@ -1,6 +1,6 @@ #? stdtmpl(subsChar='?') | standard #proc generateDeinstallScript(c: ConfigData): string = -# result = "#!/bin/sh\n# Generated by niminst\n" +# result = "#! /bin/sh\n# Generated by niminst\n" # var proj = c.name.toLowerAscii if [ $# -eq 1 ] ; then diff --git a/tools/niminst/install.nimf b/tools/niminst/install.nimf index 75ff9ce11..a78914ecd 100644 --- a/tools/niminst/install.nimf +++ b/tools/niminst/install.nimf @@ -1,24 +1,24 @@ #? stdtmpl(subsChar = '?') | standard #proc generateInstallScript(c: ConfigData): string = -# result = "#!/bin/sh\n# Generated by niminst\n" +# result = "#! /bin/sh\n# Generated by niminst\n" # var proj = c.name.toLowerAscii set -e if [ $# -eq 1 ] ; then -#if c.cat[fcUnixBin].len > 0: - if [ -f "?{c.cat[fcUnixBin][0].toUnix}" ] +# if c.cat[fcUnixBin].len > 0: + if test -f ?{c.cat[fcUnixBin][0].toUnix} then echo "?c.displayName build detected" else echo "Please build ?c.displayName before installing it" exit 1 fi -#end if +# end if case $1 in "--help"|"-h"|"help"|"h") echo "?c.displayName installation script" - echo "Usage: [sudo] [env DESTDIR=...] sh install.sh DIR" + echo "Usage: [sudo] sh install.sh DIR" echo "Where DIR may be:" echo " /usr/bin" echo " /usr/local/bin" @@ -29,19 +29,19 @@ if [ $# -eq 1 ] ; then exit 1 ;; "/usr/bin") - bindir=$1 - configdir="/etc/?proj" - libdir="/usr/lib/?proj" - docdir="/usr/share/?proj/doc" - datadir="/usr/share/?proj/data" + bindir=/usr/bin + configdir=/etc/?proj + libdir=/usr/lib/?proj + docdir=/usr/share/?proj/doc + datadir=/usr/share/?proj/data nimbleDir="/opt/nimble/pkgs/?c.nimblePkgName-?c.version" ;; "/usr/local/bin") - bindir=$1 - configdir="/etc/?proj" - libdir="/usr/local/lib/?proj" - docdir="/usr/local/share/?proj/doc" - datadir="/usr/local/share/?proj/data" + bindir=/usr/local/bin + configdir=/etc/?proj + libdir=/usr/local/lib/?proj + docdir=/usr/local/share/?proj/doc + datadir=/usr/local/share/?proj/data nimbleDir="/opt/nimble/pkgs/?c.nimblePkgName-?c.version" ;; "/opt") @@ -51,6 +51,9 @@ if [ $# -eq 1 ] ; then docdir="/opt/?proj/doc" datadir="/opt/?proj/data" nimbleDir="/opt/nimble/pkgs/?c.nimblePkgName-?c.version" + mkdir -p /opt/?proj + mkdir -p $bindir + mkdir -p $configdir ;; *) bindir="$1/?proj/bin" @@ -59,22 +62,16 @@ if [ $# -eq 1 ] ; then docdir="$1/?proj/doc" datadir="$1/?proj/data" nimbleDir="$1/?proj" + mkdir -p $1/?proj + mkdir -p $bindir + mkdir -p $configdir ;; esac - bindir="${DESTDIR}${bindir}" - configdir="${DESTDIR}${configdir}" - libdir="${DESTDIR}${libdir}" - docdir="${DESTDIR}${docdir}" - datadir="${DESTDIR}${datadir}" - nimbleDir="${DESTDIR}${nimbleDir}" - - mkdir -p "$bindir" - mkdir -p "$configdir" - mkdir -p "$libdir" - mkdir -p "$docdir" - mkdir -p "$datadir" - mkdir -p "$nimbleDir" + mkdir -p $libdir + mkdir -p $docdir + mkdir -p $configdir + mkdir -p $nimbleDir/ echo "copying files..." #var createdDirs = newStringTable() #for cat in {fcConfig..fcLib, fcNimble}: @@ -87,46 +84,46 @@ if [ $# -eq 1 ] ; then # end if # if mk.len > 0 and not createdDirs.hasKey(mk): # createdDirs[mk] = "true" - mkdir -p "?{mk.toUnix}" + mkdir -p ?{mk.toUnix} # end if # end for #end for #for f in items(c.cat[fcUnixBin]): - cp "?f.toUnix" "$bindir/?f.skipRoot.toUnix" - chmod 755 "$bindir/?f.skipRoot.toUnix" + cp ?f.toUnix $bindir/?f.skipRoot.toUnix + chmod 755 $bindir/?f.skipRoot.toUnix #end for #for f in items(c.cat[fcConfig]): - cp "?f.toUnix" "$configdir/?f.skipRoot.toUnix" - chmod 644 "$configdir/?f.skipRoot.toUnix" + cp ?f.toUnix $configdir/?f.skipRoot.toUnix + chmod 644 $configdir/?f.skipRoot.toUnix #end for #for f in items(c.cat[fcData]): - if [ -f "?f.toUnix" ]; then - cp "?f.toUnix" "$datadir/?f.skipRoot.toUnix" - chmod 644 "$datadir/?f.skipRoot.toUnix" + if [ -f ?f.toUnix ]; then + cp ?f.toUnix $datadir/?f.skipRoot.toUnix + chmod 644 $datadir/?f.skipRoot.toUnix fi #end for #for f in items(c.cat[fcDoc]): - if [ -f "?f.toUnix" ]; then - cp "?f.toUnix" "$docdir/?f.skipRoot.toUnix" - chmod 644 "$docdir/?f.skipRoot.toUnix" + if [ -f ?f.toUnix ]; then + cp ?f.toUnix $docdir/?f.skipRoot.toUnix + chmod 644 $docdir/?f.skipRoot.toUnix fi #end for #for f in items(c.cat[fcLib]): - cp "?f.toUnix" "$libdir/?f.skipRoot.toUnix" - chmod 644 "$libdir/?f.skipRoot.toUnix" + cp ?f.toUnix $libdir/?f.skipRoot.toUnix + chmod 644 $libdir/?f.skipRoot.toUnix #end for #for f in items(c.cat[fcNimble]): - cp "?f.toUnix" "$nimbleDir/?f.toUnix" - chmod 644 "$nimbleDir/?f.toUnix" + cp ?f.toUnix $nimbleDir/?f.toUnix + chmod 644 $nimbleDir/?f.toUnix #end for -cp "?{c.nimblePkgName}.nimble" "$nimbleDir/?{c.nimblePkgName}.nimble" -chmod 644 "$nimbleDir/?{c.nimblePkgName}.nimble" +cp ?{c.nimblePkgName}.nimble $nimbleDir/?{c.nimblePkgName}.nimble +chmod 644 $nimbleDir/?{c.nimblePkgName}.nimble echo "installation successful" else echo "?c.displayName installation script" - echo "Usage: [sudo] [env DESTDIR=...] sh install.sh DIR" + echo "Usage: [sudo] sh install.sh DIR" echo "Where DIR may be:" echo " /usr/bin" echo " /usr/local/bin" diff --git a/tools/niminst/makefile.nimf b/tools/niminst/makefile.nimf index b392ab472..ad9d55c03 100644 --- a/tools/niminst/makefile.nimf +++ b/tools/niminst/makefile.nimf @@ -16,7 +16,6 @@ endif target := ?{"$(binDir)/" & toLowerAscii(c.name)} - ucpu := $(shell sh -c 'uname -m | tr "[:upper:]" "[:lower:]"') ifeq ($(OS),Windows_NT) uos := windows @@ -26,8 +25,7 @@ endif ifeq ($(uos),linux) myos = linux - ## add -lrt to avoid "undefined reference to `clock_gettime'" with glibc<2.17 - LDFLAGS += -ldl -lm -lrt + LDFLAGS += -ldl -lm endif ifeq ($(uos),dragonfly) myos = freebsd @@ -104,18 +102,9 @@ endif ifeq ($(ucpu),x86_64) mycpu = amd64 endif -ifeq ($(ucpu),parisc64) - mycpu = hppa -endif -ifeq ($(ucpu),s390x) - mycpu = s390x -endif ifeq ($(ucpu),sparc) mycpu = sparc endif -ifeq ($(ucpu),sparc64) - mycpu = sparc64 -endif ifeq ($(ucpu),sun) mycpu = sparc endif @@ -135,13 +124,10 @@ ifeq ($(ucpu),powerpc) mycpu = $(shell sh -c 'uname -p | tr "[:upper:]" "[:lower:]"') CFLAGS += -m64 LDFLAGS += -m64 - ifeq ($(mycpu),powerpc64le) - mycpu = powerpc64el - endif endif endif ifeq ($(ucpu),ppc) - mycpu = powerpc + mycpu = ppc endif ifneq (,$(filter $(ucpu), mips mips64)) mycpu = $(shell /bin/sh -c '"$(CC)" -dumpmachine | sed "s/-.*//"') @@ -167,26 +153,14 @@ endif ifeq ($(ucpu),armv7hl) mycpu = arm endif -ifeq ($(ucpu),armv8l) - mycpu = arm -endif ifeq ($(ucpu),aarch64) mycpu = arm64 endif -ifeq ($(ucpu),arm64) - mycpu = arm64 -endif ifeq ($(ucpu),riscv64) mycpu = riscv64 endif -ifeq ($(ucpu),e2k) - mycpu = e2k -endif -ifeq ($(ucpu),loongarch64) - mycpu = loongarch64 -endif ifndef mycpu - $(error unknown CPU architecture: $(ucpu) See makefile.nimf) + $(error unknown processor: $(ucpu)) endif # for osA in 1..c.oses.len: diff --git a/tools/niminst/nim-file.ico b/tools/niminst/nim-file.ico deleted file mode 100644 index 0685fedcb..000000000 Binary files a/tools/niminst/nim-file.ico and /dev/null differ diff --git a/tools/niminst/niminst.nim b/tools/niminst/niminst.nim index 81b46653d..d821a68bb 100644 --- a/tools/niminst/niminst.nim +++ b/tools/niminst/niminst.nim @@ -7,17 +7,16 @@ # distribution, for details about the copyright. # +const + haveZipLib = false # zip not in stdlib anymore + +when haveZipLib: + import zipfiles + import os, strutils, parseopt, parsecfg, strtabs, streams, debcreation, std / sha1 - -when defined(nimPreviewSlimSystem): - import std/syncio - -when not defined(nimHasEffectsOf): - {.pragma: effectsOf.} - const maxOS = 20 # max number of OSes maxCPU = 20 # max number of CPUs @@ -37,7 +36,7 @@ type actionInno, # action: create Inno Setup installer actionNsis, # action: create NSIS installer actionScripts # action: create install and deinstall scripts - actionZip # action: create zip file + actionZip, # action: create zip file actionXz, # action: create xz file actionDeb # action: prepare deb package @@ -76,7 +75,7 @@ const "$configdir", "$datadir", "$docdir", "$libdir" ] -func iniConfigData(c: var ConfigData) = +proc iniConfigData(c: var ConfigData) = c.actions = {} for i in low(FileCategory)..high(FileCategory): c.cat[i] = @[] c.binPaths = @[] @@ -108,17 +107,17 @@ func iniConfigData(c: var ConfigData) = c.debOpts.shortDesc = "" c.debOpts.licenses = @[] -func firstBinPath(c: ConfigData): string = +proc firstBinPath(c: ConfigData): string = if c.binPaths.len > 0: result = c.binPaths[0] else: result = "" -func `\`(a, b: string): string = +proc `\`(a, b: string): string = result = if a.len == 0: b else: a & '\\' & b template toUnix(s: string): string = s.replace('\\', '/') template toWin(s: string): string = s.replace('/', '\\') -func skipRoot(f: string): string = +proc skipRoot(f: string): string = # "abc/def/xyz" --> "def/xyz" var i = 0 result = "" @@ -168,11 +167,11 @@ proc parseCmdLine(c: var ConfigData) = next(p) var kind = p.kind var key = p.key - var val = p.val + var val = p.val.string case kind of cmdArgument: if c.actions == {}: - for a in split(normalize(key), {';', ','}): + for a in split(normalize(key.string), {';', ','}): case a of "csource": incl(c.actions, actionCSource) of "scripts": incl(c.actions, actionScripts) @@ -183,11 +182,11 @@ proc parseCmdLine(c: var ConfigData) = of "deb": incl(c.actions, actionDeb) else: quit(Usage) else: - c.infile = addFileExt(key, "ini") - c.nimArgs = cmdLineRest(p) + c.infile = addFileExt(key.string, "ini") + c.nimArgs = cmdLineRest(p).string break of cmdLongOption, cmdShortOption: - case normalize(key) + case normalize(key.string) of "help", "h": stdout.write(Usage) quit(0) @@ -205,7 +204,7 @@ proc parseCmdLine(c: var ConfigData) = if c.infile.len == 0: quit(Usage) if c.mainfile.len == 0: c.mainfile = changeFileExt(c.infile, "nim") -proc eqT(a, b: string; t: proc (a: char): char {.nimcall.}): bool {.effectsOf: t.} = +proc eqT(a, b: string; t: proc (a: char): char{.nimcall.}): bool = ## equality under a transformation ``t``. candidate for the stdlib? var i = 0 var j = 0 @@ -222,11 +221,11 @@ proc eqT(a, b: string; t: proc (a: char): char {.nimcall.}): bool {.effectsOf: t inc j result = i >= a.len and j >= b.len -func tPath(c: char): char = +proc tPath(c: char): char = if c == '\\': '/' else: c -func ignoreFile(f, explicit: string, allowHtml: bool): bool = +proc ignoreFile(f, explicit: string, allowHtml: bool): bool = let (_, name, ext) = splitFile(f) let html = if not allowHtml: ".html" else: "" result = (ext in ["", ".exe", ".idx", ".o", ".obj", ".dylib"] or @@ -252,12 +251,12 @@ proc walkDirRecursively(s: var seq[string], root, explicit: string, proc addFiles(s: var seq[string], patterns: seq[string]) = for p in items(patterns): - if dirExists(p): + if existsDir(p): walkDirRecursively(s, p, p, false) else: var i = 0 for f in walkPattern(p): - if dirExists(f): + if existsDir(f): walkDirRecursively(s, f, p, false) elif not ignoreFile(f, p, false): add(s, unixToNativePath(f)) @@ -284,13 +283,13 @@ proc yesno(p: var CfgParser, v: string): bool = result = false else: quit(errorStr(p, "unknown value; use: yes|no")) -func incl(s: var seq[string], x: string): int = +proc incl(s: var seq[string], x: string): int = for i in 0 ..< s.len: if cmpIgnoreStyle(s[i], x) == 0: return i s.add(x) result = s.len-1 -func platforms(c: var ConfigData, v: string) = +proc platforms(c: var ConfigData, v: string) = for line in splitLines(v): let p = line.find(": ") if p <= 1: continue @@ -463,10 +462,10 @@ proc readCFiles(c: var ConfigData, osA, cpuA: int) = else: quit("Cannot open: " & f) -func buildDir(os, cpu: int): string = - "c_code" / ($os & "_" & $cpu) +proc buildDir(os, cpu: int): string = + return "c_code" / ($os & "_" & $cpu) -func getOutputDir(c: var ConfigData): string = +proc getOutputDir(c: var ConfigData): string = if c.outdir.len > 0: c.outdir else: "build" proc writeFile(filename, content, newline: string) = @@ -484,6 +483,8 @@ proc deduplicateFiles(c: var ConfigData) = let build = getOutputDir(c) for osA in countup(1, c.oses.len): for cpuA in countup(1, c.cpus.len): + when not defined(nimNoNilSeqs): + if c.cfiles[osA][cpuA].isNil: c.cfiles[osA][cpuA] = @[] if c.explicitPlatforms and not c.platforms[osA][cpuA]: continue for dup in mitems(c.cfiles[osA][cpuA]): let key = $secureHashFile(build / dup) @@ -512,23 +513,11 @@ template gatherFiles(fun, libpath, outDir) = fun(src, dst) for f in walkFiles(libpath / "lib/*.h"): copySrc(f) - # commenting out for now, see discussion in https://github.com/nim-lang/Nim/pull/13413 - # copySrc(libpath / "lib/wrappers/linenoise/linenoise.h") - -proc exe(f: string): string = - result = addFileExt(f, ExeExt) - when defined(windows): - result = result.replace('/','\\') - -proc findNim(): string = - let nim = "nim".exe - result = quoteShell("bin" / nim) - if not fileExists(result): - result = "nim" + copySrc(libpath / "lib/wrappers/linenoise/linenoise.h") proc srcdist(c: var ConfigData) = let cCodeDir = getOutputDir(c) / "c_code" - if not dirExists(cCodeDir): createDir(cCodeDir) + if not existsDir(cCodeDir): createDir(cCodeDir) gatherFiles(copyFile, c.libpath, cCodeDir) var winIndex = -1 var intel32Index = -1 @@ -542,12 +531,12 @@ proc srcdist(c: var ConfigData) = if cpuname.cmpIgnoreStyle("i386") == 0: intel32Index = cpuA elif cpuname.cmpIgnoreStyle("amd64") == 0: intel64Index = cpuA var dir = getOutputDir(c) / buildDir(osA, cpuA) - if dirExists(dir): removeDir(dir) + if existsDir(dir): removeDir(dir) createDir(dir) - var cmd = ("$# compile -f --incremental:off --compileonly " & + var cmd = ("nim compile -f --symbolfiles:off --compileonly " & "--gen_mapping --cc:gcc --skipUserCfg" & " --os:$# --cpu:$# $# $#") % - [findNim(), osname, cpuname, c.nimArgs, c.mainfile] + [osname, cpuname, c.nimArgs, c.mainfile] echo(cmd) if execShellCmd(cmd) != 0: quit("Error: call to nim compiler failed") @@ -606,6 +595,42 @@ proc setupDist2(c: var ConfigData) = else: quit("External program failed") +# ------------------ generate ZIP file --------------------------------------- +when haveZipLib: + proc zipDist(c: var ConfigData) = + var proj = toLowerAscii(c.name) & "-" & c.version + var n = "$#.zip" % proj + if c.outdir.len == 0: n = "build" / n + else: n = c.outdir / n + var z: ZipArchive + if open(z, n, fmWrite): + addFile(z, proj / buildBatFile, "build" / buildBatFile) + addFile(z, proj / buildBatFile32, "build" / buildBatFile32) + addFile(z, proj / buildBatFile64, "build" / buildBatFile64) + addFile(z, proj / buildShFile, "build" / buildShFile) + addFile(z, proj / makeFile, "build" / makeFile) + addFile(z, proj / installShFile, installShFile) + addFile(z, proj / deinstallShFile, deinstallShFile) + + template addFileAux(src, dst) = addFile(z, dst, src) + gatherFiles(addFileAux, c.libpath, proj / "c_code") + for osA in 1..c.oses.len: + for cpuA in 1..c.cpus.len: + var dir = buildDir(osA, cpuA) + for k, f in walkDir("build" / dir): + if k == pcFile: addFile(z, proj / dir / extractFilename(f), f) + + for cat in items({fcConfig..fcOther, fcUnix, fcNimble}): + for f in items(c.cat[cat]): addFile(z, proj / f, f) + + # Copy the .nimble file over + let nimbleFile = c.nimblePkgName & ".nimble" + processFile(z, proj / nimbleFile, nimbleFile) + + close(z) + else: + quit("Cannot open for writing: " & n) + proc xzDist(c: var ConfigData; windowsZip=false) = let proj = toLowerAscii(c.name) & "-" & c.version let tmpDir = if c.outdir.len == 0: "build" else: c.outdir @@ -613,15 +638,15 @@ proc xzDist(c: var ConfigData; windowsZip=false) = proc processFile(destFile, src: string) = let dest = tmpDir / destFile when false: echo "Copying ", src, " to ", dest - if not fileExists(src): + if not existsFile(src): echo "[Warning] Source file doesn't exist: ", src let destDir = dest.splitFile.dir if not dirExists(destDir): createDir(destDir) copyFileWithPermissions(src, dest) - if not windowsZip and not fileExists("build" / buildBatFile): + if not windowsZip and not existsFile("build" / buildBatFile): quit("No C sources found in ./build/, please build by running " & - "./koch csource -d:danger.") + "./koch csource -d:release.") if not windowsZip: processFile(proj / buildBatFile, "build" / buildBatFile) @@ -682,8 +707,8 @@ RunProgram="tools\downloader.exe" # -- prepare build files for .deb creation proc debDist(c: var ConfigData) = - if not fileExists(getOutputDir(c) / "build.sh"): quit("No build.sh found.") - if not fileExists(getOutputDir(c) / "install.sh"): quit("No install.sh found.") + if not existsFile(getOutputDir(c) / "build.sh"): quit("No build.sh found.") + if not existsFile(getOutputDir(c) / "install.sh"): quit("No install.sh found.") if c.debOpts.shortDesc == "": quit("shortDesc must be set in the .ini file.") if c.debOpts.licenses.len == 0: @@ -727,25 +752,21 @@ proc debDist(c: var ConfigData) = # ------------------- main ---------------------------------------------------- -proc main() = - var c: ConfigData - iniConfigData(c) - parseCmdLine(c) - parseIniFile(c) - if actionInno in c.actions: - setupDist(c) - if actionNsis in c.actions: - setupDist2(c) - if actionCSource in c.actions: - srcdist(c) - if actionScripts in c.actions: - writeInstallScripts(c) - if actionZip in c.actions: - xzDist(c, true) - if actionXz in c.actions: - xzDist(c) - if actionDeb in c.actions: - debDist(c) - -when isMainModule: - main() +var c: ConfigData +iniConfigData(c) +parseCmdLine(c) +parseIniFile(c) +if actionInno in c.actions: + setupDist(c) +if actionNsis in c.actions: + setupDist2(c) +if actionCSource in c.actions: + srcdist(c) +if actionScripts in c.actions: + writeInstallScripts(c) +if actionZip in c.actions: + xzDist(c, true) +if actionXz in c.actions: + xzDist(c) +if actionDeb in c.actions: + debDist(c) diff --git a/tools/niminst/setup.ico b/tools/niminst/setup.ico deleted file mode 100644 index 867163046..000000000 Binary files a/tools/niminst/setup.ico and /dev/null differ diff --git a/tools/niminst/uninstall.ico b/tools/niminst/uninstall.ico deleted file mode 100644 index aff054644..000000000 Binary files a/tools/niminst/uninstall.ico and /dev/null differ diff --git a/tools/nimrepl.nim b/tools/nimrepl.nim new file mode 100644 index 000000000..ac82d8b75 --- /dev/null +++ b/tools/nimrepl.nim @@ -0,0 +1,172 @@ +# +# +# Nim REPL +# (c) Copyright 2012 Dominik Picheta +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +import glib2, gtk2, gdk2, os, osproc, dialogs, strutils + +when defined(tinyc): + const runCmd = "run" +else: + const runCmd = "c -r" + +var nimExe = findExe("nim") +if nimExe.len == 0: nimExe = "../bin" / addFileExt("nim", os.ExeExt) + +proc execCode(code: string): string = + var f: File + if open(f, "temp.nim", fmWrite): + f.write(code) + f.close() + result = osproc.execProcess( + "$# $# --verbosity:0 --hint[Conf]:off temp.nim" % [nimExe, runCmd], + options = {poStdErrToStdOut}) + else: + result = "cannot open file 'temp.nim'" + +var shiftPressed = false +var w: gtk2.PWindow +var inputTextBuffer: PTextBuffer +var outputTextBuffer: PTextBuffer + +proc destroy(widget: PWidget, data: pointer){.cdecl.} = + main_quit() + +proc fileOpenClicked(menuitem: PMenuItem, userdata: pointer) {.cdecl.} = + var path = chooseFileToOpen(w) + if path != "": + var file = readFile(path) + if file != nil: + set_text(inputTextBuffer, file, len(file).gint) + else: + error(w, "Unable to read from file") + +proc fileSaveClicked(menuitem: PMenuItem, userdata: pointer) {.cdecl.} = + var path = chooseFileToSave(w) + + if path == "": return + var startIter: TTextIter + var endIter: TTextIter + get_start_iter(inputTextBuffer, addr(startIter)) + get_end_iter(inputTextBuffer, addr(endIter)) + var inputText = get_text(inputTextBuffer, addr(startIter), + addr(endIter), false) + var f: File + if open(f, path, fmWrite): + f.write(inputText) + f.close() + else: + error(w, "Unable to write to file") + +proc inputKeyPressed(widget: PWidget, event: PEventKey, + userdata: pointer): bool {.cdecl.} = + if ($keyval_name(event.keyval)).tolower() == "shift_l": + # SHIFT is pressed + shiftPressed = true + +proc setError(msg: string) = + outputTextBuffer.setText(msg, msg.len.gint) + +proc inputKeyReleased(widget: PWidget, event: PEventKey, + userdata: pointer): bool {.cdecl.} = + #echo(keyval_name(event.keyval)) + if ($keyval_name(event.keyval)).tolower() == "shift_l": + # SHIFT is released + shiftPressed = false + + if ($keyval_name(event.keyval)).tolower() == "return": + #echo($keyval_name(event.keyval), "Shift_L") + # Enter pressed + if not shiftPressed: + var startIter: TTextIter + var endIter: TTextIter + get_start_iter(inputTextBuffer, addr(startIter)) + get_end_iter(inputTextBuffer, addr(endIter)) + var inputText = get_text(inputTextBuffer, addr(startIter), + addr(endIter), false) + + try: + var r = execCode($inputText) + set_text(outputTextBuffer, r, len(r).gint) + except IOError: + setError("Error: Could not open file temp.nim") + + +proc initControls() = + w = window_new(gtk2.WINDOW_TOPLEVEL) + set_default_size(w, 500, 600) + set_title(w, "Nim REPL") + discard signal_connect(w, "destroy", SIGNAL_FUNC(nimrepl.destroy), nil) + + # MainBox (vbox) + var mainBox = vbox_new(false, 0) + add(w, mainBox) + + # TopMenu (MenuBar) + var topMenu = menu_bar_new() + show(topMenu) + + var fileMenu = menu_new() + var openMenuItem = menu_item_new("Open") + append(fileMenu, openMenuItem) + show(openMenuItem) + discard signal_connect(openMenuItem, "activate", + SIGNAL_FUNC(fileOpenClicked), nil) + var saveMenuItem = menu_item_new("Save...") + append(fileMenu, saveMenuItem) + show(saveMenuItem) + discard signal_connect(saveMenuItem, "activate", + SIGNAL_FUNC(fileSaveClicked), nil) + var fileMenuItem = menu_item_new("File") + + + set_submenu(fileMenuItem, fileMenu) + show(fileMenuItem) + append(topMenu, fileMenuItem) + + pack_start(mainBox, topMenu, false, false, 0) + + # VPaned - Separates the InputTextView and the OutputTextView + var paned = vpaned_new() + set_position(paned, 450) + pack_start(mainBox, paned, true, true, 0) + show(paned) + + # Init the TextBuffers + inputTextBuffer = text_buffer_new(nil) + outputTextBuffer = text_buffer_new(nil) + + # InputTextView (TextView) + var inputScrolledWindow = scrolled_window_new(nil, nil) + set_policy(inputScrolledWindow, POLICY_AUTOMATIC, POLICY_AUTOMATIC) + var inputTextView = text_view_new(inputTextBuffer) + add_with_viewport(inputScrolledWindow, inputTextView) + add1(paned, inputScrolledWindow) + show(inputScrolledWindow) + show(inputTextView) + + discard signal_connect(inputTextView, "key-release-event", + SIGNAL_FUNC(inputKeyReleased), nil) + discard signal_connect(inputTextView, "key-press-event", + SIGNAL_FUNC(inputKeyPressed), nil) + + # OutputTextView (TextView) + var outputScrolledWindow = scrolled_window_new(nil, nil) + set_policy(outputScrolledWindow, POLICY_AUTOMATIC, POLICY_AUTOMATIC) + var outputTextView = text_view_new(outputTextBuffer) + add_with_viewport(outputScrolledWindow, outputTextView) + add2(paned, outputScrolledWindow) + show(outputScrolledWindow) + show(outputTextView) + + show(w) + show(mainBox) + +nim_init() +initControls() +main() + diff --git a/tools/nimweb.nim b/tools/nimweb.nim new file mode 100644 index 000000000..460135f49 --- /dev/null +++ b/tools/nimweb.nim @@ -0,0 +1,556 @@ +# +# +# Nim Website Generator +# (c) Copyright 2015 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +import + os, strutils, times, parseopt, parsecfg, streams, strtabs, tables, + re, htmlgen, macros, md5, osproc, parsecsv, algorithm + +from xmltree import escape + +type + TKeyValPair = tuple[key, id, val: string] + TConfigData = object of RootObj + tabs, links: seq[TKeyValPair] + doc, srcdoc, srcdoc2, webdoc, pdf: seq[string] + authors, projectName, projectTitle, logo, infile, ticker: string + vars: StringTableRef + nimCompiler: string + nimArgs: string + gitURL: string + docHTMLOutput: string + webUploadOutput: string + quotations: Table[string, tuple[quote, author: string]] + numProcessors: int # Set by parallelBuild:n, only works for values > 0. + gaId: string # google analytics ID, nil means analytics are disabled + TRssItem = object + year, month, day, title, url, content: string + TAction = enum + actAll, actOnlyWebsite, actPdf, actJson2, actOnlyDocs + + Sponsor = object + logo: string + name: string + url: string + thisMonth: int + allTime: int + since: string + level: int + +var action: TAction + +proc initConfigData(c: var TConfigData) = + c.tabs = @[] + c.links = @[] + c.doc = @[] + c.srcdoc = @[] + c.srcdoc2 = @[] + c.webdoc = @[] + c.pdf = @[] + c.infile = "" + c.nimArgs = "--hint[Conf]:off --hint[Path]:off --hint[Processing]:off -d:boot " + c.gitURL = "https://github.com/nim-lang/Nim" + c.docHTMLOutput = "doc/html" + c.webUploadOutput = "web/upload" + c.authors = "" + c.projectTitle = "" + c.projectName = "" + c.logo = "" + c.ticker = "" + c.vars = newStringTable(modeStyleInsensitive) + c.numProcessors = countProcessors() + # Attempts to obtain the git current commit. + when false: + let (output, code) = execCmdEx("git log -n 1 --format=%H") + if code == 0 and output.strip.len == 40: + c.gitCommit = output.strip + c.quotations = initTable[string, tuple[quote, author: string]]() + +include "website.nimf" + +# ------------------------- configuration file ------------------------------- + +const + version = "0.8" + usage = "nimweb - Nim Website Generator Version " & version & """ + + (c) 2015 Andreas Rumpf +Usage: + nimweb [options] ini-file[.ini] [compile_options] +Options: + -h, --help shows this help + -v, --version shows the version + -o, --output overrides output directory instead of default + web/upload and doc/html + --nimCompiler overrides nim compiler; default = bin/nim + --var:name=value set the value of a variable + --website only build the website, not the full documentation + --pdf build the PDF version of the documentation + --json2 build JSON of the documentation + --onlyDocs build only the documentation + --git.url override base url in generated doc links + --git.commit override commit/branch in generated doc links 'source' + --git.devel override devel branch in generated doc links 'edit' +Compile_options: + will be passed to the Nim compiler +""" + + rYearMonthDay = r"on\s+(\d{2})\/(\d{2})\/(\d{4})" + rssUrl = "http://nim-lang.org/news.xml" + rssNewsUrl = "http://nim-lang.org/news.html" + activeSponsors = "web/sponsors.csv" + inactiveSponsors = "web/inactive_sponsors.csv" + validAnchorCharacters = Letters + Digits + + +macro id(e: untyped): untyped = + ## generates the rss xml ``id`` element. + let e = callsite() + result = xmlCheckedTag(e, "id") + +macro updated(e: varargs[untyped]): untyped = + ## generates the rss xml ``updated`` element. + let e = callsite() + result = xmlCheckedTag(e, "updated") + +proc updatedDate(year, month, day: string): string = + ## wrapper around the update macro with easy input. + result = updated("$1-$2-$3T00:00:00Z" % [year, + repeat("0", 2 - len(month)) & month, + repeat("0", 2 - len(day)) & day]) + +macro entry(e: varargs[untyped]): untyped = + ## generates the rss xml ``entry`` element. + let e = callsite() + result = xmlCheckedTag(e, "entry") + +macro content(e: varargs[untyped]): untyped = + ## generates the rss xml ``content`` element. + let e = callsite() + result = xmlCheckedTag(e, "content", reqAttr = "type") + +proc parseCmdLine(c: var TConfigData) = + var p = initOptParser() + while true: + next(p) + var kind = p.kind + var key = p.key + var val = p.val + case kind + of cmdArgument: + c.infile = addFileExt(key, "ini") + c.nimArgs.add(cmdLineRest(p)) + break + of cmdLongOption, cmdShortOption: + case normalize(key) + of "help", "h": + stdout.write(usage) + quit(0) + of "version", "v": + stdout.write(version & "\n") + quit(0) + of "output", "o": + c.webUploadOutput = val + c.docHTMLOutput = val / "docs" + of "nimcompiler": + c.nimCompiler = val + of "parallelbuild": + try: + let num = parseInt(val) + if num != 0: c.numProcessors = num + except ValueError: + quit("invalid numeric value for --parallelBuild") + of "var": + var idx = val.find('=') + if idx < 0: quit("invalid command line") + c.vars[substr(val, 0, idx-1)] = substr(val, idx+1) + of "website": action = actOnlyWebsite + of "pdf": action = actPdf + of "json2": action = actJson2 + of "onlydocs": action = actOnlyDocs + of "googleanalytics": + c.gaId = val + c.nimArgs.add("--doc.googleAnalytics:" & val & " ") + of "git.url": + c.gitURL = val + of "git.commit": + c.nimArgs.add("--git.commit:" & val & " ") + of "git.devel": + c.nimArgs.add("--git.devel:" & val & " ") + else: + echo("Invalid argument '$1'" % [key]) + quit(usage) + of cmdEnd: break + if c.infile.len == 0: quit(usage) + +proc walkDirRecursively(s: var seq[string], root, ext: string) = + for k, f in walkDir(root): + case k + of pcFile, pcLinkToFile: + if cmpIgnoreCase(ext, splitFile(f).ext) == 0: + add(s, f) + of pcDir: walkDirRecursively(s, f, ext) + of pcLinkToDir: discard + +proc addFiles(s: var seq[string], dir, ext: string, patterns: seq[string]) = + for p in items(patterns): + if existsFile(dir / addFileExt(p, ext)): + s.add(dir / addFileExt(p, ext)) + if existsDir(dir / p): + walkDirRecursively(s, dir / p, ext) + +proc parseIniFile(c: var TConfigData) = + var + p: CfgParser + section: string # current section + var input = newFileStream(c.infile, fmRead) + if input == nil: quit("cannot open: " & c.infile) + open(p, input, c.infile) + while true: + var k = next(p) + case k.kind + of cfgEof: break + of cfgSectionStart: + section = normalize(k.section) + case section + of "project", "links", "tabs", "ticker", "documentation", "var": discard + else: echo("[Warning] Skipping unknown section: " & section) + + of cfgKeyValuePair: + var v = k.value % c.vars + c.vars[k.key] = v + + case section + of "project": + case normalize(k.key) + of "name": c.projectName = v + of "title": c.projectTitle = v + of "logo": c.logo = v + of "authors": c.authors = v + else: quit(errorStr(p, "unknown variable: " & k.key)) + of "var": discard + of "links": + let valID = v.split(';') + add(c.links, (k.key.replace('_', ' '), valID[1], valID[0])) + of "tabs": add(c.tabs, (k.key, "", v)) + of "ticker": c.ticker = v + of "documentation": + case normalize(k.key) + of "doc": addFiles(c.doc, "doc", ".rst", split(v, {';'})) + of "pdf": addFiles(c.pdf, "doc", ".rst", split(v, {';'})) + of "srcdoc": addFiles(c.srcdoc, "lib", ".nim", split(v, {';'})) + of "srcdoc2": addFiles(c.srcdoc2, "lib", ".nim", split(v, {';'})) + of "webdoc": addFiles(c.webdoc, "lib", ".nim", split(v, {';'})) + of "parallelbuild": + try: + let num = parseInt(v) + if num != 0: c.numProcessors = num + except ValueError: + quit("invalid numeric value for --parallelBuild in config") + else: quit(errorStr(p, "unknown variable: " & k.key)) + of "quotations": + let vSplit = v.split('-') + doAssert vSplit.len == 2 + c.quotations[k.key.normalize] = (vSplit[0], vSplit[1]) + else: discard + of cfgOption: quit(errorStr(p, "syntax error")) + of cfgError: quit(errorStr(p, k.msg)) + close(p) + if c.projectName.len == 0: + c.projectName = changeFileExt(extractFilename(c.infile), "") + +# ------------------- main ---------------------------------------------------- + + +proc exe(f: string): string = return addFileExt(f, ExeExt) + +proc findNim(c: TConfigData): string = + if c.nimCompiler.len > 0: return c.nimCompiler + var nim = "nim".exe + result = "bin" / nim + if existsFile(result): return + for dir in split(getEnv("PATH"), PathSep): + if existsFile(dir / nim): return dir / nim + # assume there is a symlink to the exe or something: + return nim + +proc exec(cmd: string) = + echo(cmd) + let (outp, exitCode) = osproc.execCmdEx(cmd) + if exitCode != 0: quit outp + +proc sexec(cmds: openarray[string]) = + ## Serial queue wrapper around exec. + for cmd in cmds: exec(cmd) + +proc mexec(cmds: openarray[string], processors: int) = + ## Multiprocessor version of exec + doAssert processors > 0, "nimweb needs at least one processor" + if processors == 1: + sexec(cmds) + return + let r = execProcesses(cmds, {poStdErrToStdOut, poParentStreams, poEchoCmd}, + n = processors) + if r != 0: + echo "external program failed, retrying serial work queue for logs!" + sexec(cmds) + +proc buildDocSamples(c: var TConfigData, destPath: string) = + ## Special case documentation sample proc. + ## + ## TODO: consider integrating into the existing generic documentation builders + ## now that we have a single `doc` command. + exec(findNim(c) & " doc $# -o:$# $#" % + [c.nimArgs, destPath / "docgen_sample.html", "doc" / "docgen_sample.nim"]) + +proc pathPart(d: string): string = splitFile(d).dir.replace('\\', '/') + +proc buildDoc(c: var TConfigData, destPath: string) = + # call nim for the documentation: + var + commands = newSeq[string](len(c.doc) + len(c.srcdoc) + len(c.srcdoc2)) + i = 0 + for d in items(c.doc): + commands[i] = findNim(c) & " rst2html $# --git.url:$# -o:$# --index:on $#" % + [c.nimArgs, c.gitURL, + destPath / changeFileExt(splitFile(d).name, "html"), d] + i.inc + for d in items(c.srcdoc): + commands[i] = findNim(c) & " doc0 $# --git.url:$# -o:$# --index:on $#" % + [c.nimArgs, c.gitURL, + destPath / changeFileExt(splitFile(d).name, "html"), d] + i.inc + for d in items(c.srcdoc2): + commands[i] = findNim(c) & " doc2 $# --git.url:$# -o:$# --index:on $#" % + [c.nimArgs, c.gitURL, + destPath / changeFileExt(splitFile(d).name, "html"), d] + i.inc + + mexec(commands, c.numProcessors) + exec(findNim(c) & " buildIndex -o:$1/theindex.html $1" % [destPath]) + +proc buildPdfDoc(c: var TConfigData, destPath: string) = + createDir(destPath) + if os.execShellCmd("pdflatex -version") != 0: + echo "pdflatex not found; no PDF documentation generated" + else: + const pdflatexcmd = "pdflatex -interaction=nonstopmode " + for d in items(c.pdf): + exec(findNim(c) & " rst2tex $# $#" % [c.nimArgs, d]) + # call LaTeX twice to get cross references right: + exec(pdflatexcmd & changeFileExt(d, "tex")) + exec(pdflatexcmd & changeFileExt(d, "tex")) + # delete all the crappy temporary files: + let pdf = splitFile(d).name & ".pdf" + let dest = destPath / pdf + removeFile(dest) + moveFile(dest=dest, source=pdf) + removeFile(changeFileExt(pdf, "aux")) + if existsFile(changeFileExt(pdf, "toc")): + removeFile(changeFileExt(pdf, "toc")) + removeFile(changeFileExt(pdf, "log")) + removeFile(changeFileExt(pdf, "out")) + removeFile(changeFileExt(d, "tex")) + +proc buildAddDoc(c: var TConfigData, destPath: string) = + # build additional documentation (without the index): + var commands = newSeq[string](c.webdoc.len) + for i, doc in pairs(c.webdoc): + commands[i] = findNim(c) & " doc2 $# --git.url:$# -o:$# $#" % + [c.nimArgs, c.gitURL, + destPath / changeFileExt(splitFile(doc).name, "html"), doc] + mexec(commands, c.numProcessors) + +proc parseNewsTitles(inputFilename: string): seq[TRssItem] = + # Goes through each news file, returns its date/title. + result = @[] + var matches: array[3, string] + let reYearMonthDay = re(rYearMonthDay) + for kind, path in walkDir(inputFilename): + let (dir, name, ext) = path.splitFile + if ext == ".rst": + let content = readFile(path) + let title = content.splitLines()[0] + let urlPath = "news/" & name & ".html" + if content.find(reYearMonthDay, matches) >= 0: + result.add(TRssItem(year: matches[2], month: matches[1], day: matches[0], + title: title, url: "http://nim-lang.org/" & urlPath, + content: content)) + result.reverse() + +proc genUUID(text: string): string = + # Returns a valid RSS uuid, which is basically md5 with dashes and a prefix. + result = getMD5(text) + result.insert("-", 20) + result.insert("-", 16) + result.insert("-", 12) + result.insert("-", 8) + result.insert("urn:uuid:") + +proc genNewsLink(title: string): string = + # Mangles a title string into an expected news.html anchor. + result = title + result.insert("Z") + for i in 1..len(result)-1: + let letter = result[i].toLowerAscii() + if letter in validAnchorCharacters: + result[i] = letter + else: + result[i] = '-' + result.insert(rssNewsUrl & "#") + +proc generateRss(outputFilename: string, news: seq[TRssItem]) = + # Given a list of rss items generates an rss overwriting destination. + var + output: File + + if not open(output, outputFilename, mode = fmWrite): + quit("Could not write to $1 for rss generation" % [outputFilename]) + defer: output.close() + + output.write(""" + +""") + output.write(title("Nim website news")) + output.write(link(href = rssUrl, rel = "self")) + output.write(link(href = rssNewsUrl)) + output.write(id(rssNewsUrl)) + + let now = getGMTime(getTime()) + output.write(updatedDate($now.year, $(int(now.month) + 1), $now.monthday)) + + for rss in news: + output.write(entry( + title(xmltree.escape(rss.title)), + id(genUUID(rss.title)), + link(`type` = "text/html", rel = "alternate", + href = rss.url), + updatedDate(rss.year, rss.month, rss.day), + "Nim", + content(xmltree.escape(rss.content), `type` = "text") + )) + + output.write("""""") + +proc buildNewsRss(c: var TConfigData, destPath: string) = + # generates an xml feed from the web/news.rst file + let + srcFilename = "web" / "news" + destFilename = destPath / changeFileExt(splitFile(srcFilename).name, "xml") + + generateRss(destFilename, parseNewsTitles(srcFilename)) + +proc readSponsors(sponsorsFile: string): seq[Sponsor] = + result = @[] + var fileStream = newFileStream(sponsorsFile, fmRead) + if fileStream == nil: quit("Cannot open sponsors.csv file: " & sponsorsFile) + var parser: CsvParser + open(parser, fileStream, sponsorsFile) + discard readRow(parser) # Skip the header row. + while readRow(parser): + result.add(Sponsor(logo: parser.row[0], name: parser.row[1], + url: parser.row[2], thisMonth: parser.row[3].parseInt, + allTime: parser.row[4].parseInt, + since: parser.row[5], level: parser.row[6].parseInt)) + parser.close() + +proc buildSponsors(c: var TConfigData, outputDir: string) = + let sponsors = generateSponsorsPage(readSponsors(activeSponsors), + readSponsors(inactiveSponsors)) + let outFile = outputDir / "sponsors.html" + var f: File + if open(f, outFile, fmWrite): + writeLine(f, generateHtmlPage(c, "", "Our Sponsors", sponsors, "")) + close(f) + else: + quit("[Error] Cannot write file: " & outFile) + +const + cmdRst2Html = " rst2html --compileonly $1 -o:web/$2.temp web/$2.rst" + +proc buildPage(c: var TConfigData, file, title, rss: string, assetDir = "") = + exec(findNim(c) & cmdRst2Html % [c.nimArgs, file]) + var temp = "web" / changeFileExt(file, "temp") + var content: string + try: + content = readFile(temp) + except IOError: + quit("[Error] cannot open: " & temp) + var f: File + var outfile = c.webUploadOutput / "$#.html" % file + if not existsDir(outfile.splitFile.dir): + createDir(outfile.splitFile.dir) + if open(f, outfile, fmWrite): + writeLine(f, generateHTMLPage(c, file, title, content, rss, assetDir)) + close(f) + else: + quit("[Error] cannot write file: " & outfile) + removeFile(temp) + +proc buildNews(c: var TConfigData, newsDir: string, outputDir: string) = + for kind, path in walkDir(newsDir): + let (dir, name, ext) = path.splitFile + if ext == ".rst": + let title = readFile(path).splitLines()[0] + buildPage(c, tailDir(dir) / name, title, "", "../") + else: + echo("Skipping file in news directory: ", path) + +proc buildWebsite(c: var TConfigData) = + if c.ticker.len > 0: + try: + c.ticker = readFile("web" / c.ticker) + except IOError: + quit("[Error] cannot open: " & c.ticker) + for i in 0..c.tabs.len-1: + var file = c.tabs[i].val + let rss = if file in ["news", "index"]: extractFilename(rssUrl) else: "" + if '.' in file: continue + buildPage(c, file, if file == "question": "FAQ" else: file, rss) + copyDir("web/assets", c.webUploadOutput / "assets") + buildNewsRss(c, c.webUploadOutput) + buildSponsors(c, c.webUploadOutput) + buildNews(c, "web/news", c.webUploadOutput / "news") + +proc onlyDocs(c: var TConfigData) = + createDir(c.docHTMLOutput) + buildDocSamples(c, c.docHTMLOutput) + buildDoc(c, c.docHTMLOutput) + +proc main(c: var TConfigData) = + buildWebsite(c) + let docup = c.webUploadOutput / NimVersion + createDir(docup) + buildAddDoc(c, docup) + buildDocSamples(c, docup) + buildDoc(c, docup) + onlyDocs(c) + +proc json2(c: var TConfigData) = + const destPath = "web/json2" + var commands = newSeq[string](c.srcdoc2.len) + var i = 0 + for d in items(c.srcdoc2): + createDir(destPath / splitFile(d).dir) + commands[i] = findNim(c) & " jsondoc2 $# --git.url:$# -o:$# --index:on $#" % + [c.nimArgs, c.gitURL, + destPath / changeFileExt(d, "json"), d] + i.inc + + mexec(commands, c.numProcessors) + +var c: TConfigData +initConfigData(c) +parseCmdLine(c) +parseIniFile(c) +case action +of actOnlyWebsite: buildWebsite(c) +of actPdf: buildPdfDoc(c, "doc/pdf") +of actOnlyDocs: onlyDocs(c) +of actAll: main(c) +of actJson2: json2(c) diff --git a/tools/officialpackages.nim b/tools/officialpackages.nim deleted file mode 100644 index 633944a14..000000000 --- a/tools/officialpackages.nim +++ /dev/null @@ -1,21 +0,0 @@ -import std/[strformat, paths, dirs, envvars] -from std/os import execShellCmd - -proc exec*(cmd: string, errorcode: int = QuitFailure, additionalPath = "") = - let prevPath = getEnv("PATH") - if additionalPath.len > 0: - var absolute = Path(additionalPath) - if not absolute.isAbsolute: - absolute = getCurrentDir() / absolute - echo("Adding to $PATH: ", string(absolute)) - putEnv("PATH", (if prevPath.len > 0: prevPath & PathSep else: "") & string(absolute)) - echo(cmd) - if execShellCmd(cmd) != 0: quit("FAILURE", errorcode) - putEnv("PATH", prevPath) - -proc gitClonePackages*(names: seq[string]) = - if not dirExists(Path"pkgs"): - createDir(Path"pkgs") - for name in names: - if not dirExists(Path"pkgs" / Path(name)): - exec fmt"git clone https://github.com/nim-lang/{name} pkgs/{name}" diff --git a/tools/ssl_config_parser.nim b/tools/ssl_config_parser.nim deleted file mode 100644 index 6c0cccf1c..000000000 --- a/tools/ssl_config_parser.nim +++ /dev/null @@ -1,64 +0,0 @@ -# -# -# SSL configuration generator -# (c) Copyright 2020 Leorize -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# - -import httpclient, json, net, strformat, strutils, sequtils, times - -const - ConfigSource = "https://ssl-config.mozilla.org/guidelines/latest.json" - OutputFile = "ssl_config.nim" - -proc main() = - let - client = newHttpClient(sslContext = newContext(verifyMode = CVerifyPeer)) - resp = client.get(ConfigSource) - defer: client.close() - if not resp.code.is2xx: - quit "Couldn't fetch configuration, server returned: " & $resp.code - - let configs = resp.bodyStream.parseJson("ssl-config.json") - - let generationTime = now().utc() - let output = open(OutputFile, fmWrite) - echo "Generating ", OutputFile - output.writeLine(&""" -# This file was automatically generated by tools/ssl_config_parser on {generationTime}. DO NOT EDIT. - -## This module contains SSL configuration parameters obtained from -## `Mozilla OpSec `_. -## -## The configuration file used to generate this module: {configs["href"].getStr} -""") - - for name, config in configs["configurations"]: - let - constantName = "Ciphers" & name[0].toUpperAscii & name[1..^1] - - var ciphers: string - for c in config["ciphersuites"].getElems & config["ciphers"]["openssl"].getElems: - if ciphers.len == 0: - ciphers.add c.getStr - else: - ciphers.add ':' - ciphers.add c.getStr - - var constant = &""" -const {constantName}* = "{ciphers}" - ## An OpenSSL-compatible list of secure ciphers for ``{name}`` compatibility - ## per Mozilla's recommendations. - ## - ## Oldest clients supported by this list: -""" - - for c in config["oldest_clients"]: - constant.add " ## * " & c.getStr - constant.add '\n' - - output.writeLine constant - -when isMainModule: main() diff --git a/tools/ssl_config_parser.nims b/tools/ssl_config_parser.nims deleted file mode 100644 index 796d18894..000000000 --- a/tools/ssl_config_parser.nims +++ /dev/null @@ -1 +0,0 @@ ---d:ssl diff --git a/tools/trimcc.nim b/tools/trimcc.nim index 41795e1aa..959eaf310 100644 --- a/tools/trimcc.nim +++ b/tools/trimcc.nim @@ -31,7 +31,7 @@ proc processIncludes(dir: string, whitelist: StringTableRef) = if ('.' notin name and "include" in path) or ("c++" in path): let n = whitelist.getOrDefault(name) if n != "processed": whitelist[name] = "found" - if name.endsWith(".h"): + if name.endswith(".h"): let n = whitelist.getOrDefault(name) if n == "found": includes(path, name, whitelist) of pcDir: processIncludes(path, whitelist) diff --git a/tools/urldownloader.nim b/tools/urldownloader.nim new file mode 100644 index 000000000..b29a6c138 --- /dev/null +++ b/tools/urldownloader.nim @@ -0,0 +1,431 @@ + +# +# +# Windows native FTP/HTTP/HTTPS file downloader +# (c) Copyright 2017 Eugene Kabanov +# +# See the file "LICENSE", included in this +# distribution, for details about the copyright. +# + +## This module implements native Windows FTP/HTTP/HTTPS downloading feature, +## using ``urlmon.UrlDownloadToFile()``. +## +## + +when not (defined(windows) or defined(nimdoc)): + {.error: "Platform is not supported.".} + +import os + +type + DownloadOptions* = enum + ## Available download options + optUseCache, ## Use Windows cache. + optUseProgressCallback, ## Report progress via callback. + optIgnoreSecurity ## Ignore HTTPS security problems. + + DownloadStatus* = enum + ## Available download status sent to ``progress`` callback. + statusProxyDetecting, ## Automatic Proxy detection. + statusCookieSent ## Cookie will be sent with request. + statusResolving, ## Resolving URL with DNS. + statusConnecting, ## Establish connection to server. + statusRedirecting ## HTTP redirection pending. + statusRequesting, ## Sending request to server. + statusMimetypeAvailable, ## Mimetype received from server. + statusBeginDownloading, ## Download process starting. + statusDownloading, ## Download process pending. + statusEndDownloading, ## Download process finished. + statusCacheAvailable ## File found in Windows cache. + statusUnsupported ## Unsupported status. + statusError ## Error happens. + + DownloadProgressCallback* = proc(status: DownloadStatus, progress: uint, + progressMax: uint, + message: string) + ## Progress callback. + ## + ## status + ## Indicate current stage of downloading process. + ## + ## progress + ## Number of bytes currently downloaded. Available only, if ``status`` is + ## ``statusBeginDownloading``, ``statusDownloading`` or + ## ``statusEndDownloading``. + ## + ## progressMax + ## Number of bytes expected to download. Available only, if ``status`` is + ## ``statusBeginDownloading``, ``statusDownloading`` or + ## ``statusEndDownloading``. + ## + ## message + ## Status message, which depends on ``status`` code. + ## + ## Available messages' values: + ## + ## statusResolving + ## URL hostname to be resolved. + ## statusConnecting + ## IP address + ## statusMimetypeAvailable + ## Downloading resource MIME type. + ## statusCacheAvailable + ## Path to filename stored in Windows cache. + +type + UUID = array[4, uint32] + + LONG = clong + ULONG = culong + HRESULT = clong + DWORD = uint32 + OLECHAR = uint16 + OLESTR = ptr OLECHAR + LPWSTR = OLESTR + UINT = cuint + REFIID = ptr UUID + +const + E_NOINTERFACE = 0x80004002'i32 + E_NOTIMPL = 0x80004001'i32 + S_OK = 0x00000000'i32 + + CP_UTF8 = 65001'u32 + + IID_IUnknown = UUID([0'u32, 0'u32, 192'u32, 1174405120'u32]) + IID_IBindStatusCallback = UUID([2045430209'u32, 298760953'u32, + 2852160140'u32, 195644160'u32]) + + BINDF_GETNEWESTVERSION = 0x00000010'u32 + BINDF_IGNORESECURITYPROBLEM = 0x00000100'u32 + BINDF_RESYNCHRONIZE = 0x00000200'u32 + BINDF_NO_UI = 0x00000800'u32 + BINDF_SILENTOPERATION = 0x00001000'u32 + BINDF_PRAGMA_NO_CACHE = 0x00002000'u32 + + ERROR_FILE_NOT_FOUND = 2 + ERROR_ACCESS_DENIED = 5 + + BINDSTATUS_FINDINGRESOURCE = 1 + BINDSTATUS_CONNECTING = 2 + BINDSTATUS_REDIRECTING = 3 + BINDSTATUS_BEGINDOWNLOADDATA = 4 + BINDSTATUS_DOWNLOADINGDATA = 5 + BINDSTATUS_ENDDOWNLOADDATA = 6 + BINDSTATUS_SENDINGREQUEST = 11 + BINDSTATUS_MIMETYPEAVAILABLE = 13 + BINDSTATUS_CACHEFILENAMEAVAILABLE = 14 + BINDSTATUS_PROXYDETECTING = 32 + BINDSTATUS_COOKIE_SENT = 34 + +type + STGMEDIUM = object + tymed: DWORD + pstg: pointer + pUnkForRelease: pointer + + SECURITY_ATTRIBUTES = object + nLength*: uint32 + lpSecurityDescriptor*: pointer + bInheritHandle*: int32 + + BINDINFO = object + cbSize: ULONG + stgmedData: STGMEDIUM + szExtraInfo: LPWSTR + grfBindInfoF: DWORD + dwBindVerb: DWORD + szCustomVerb: LPWSTR + cbstgmedData: DWORD + dwOptions: DWORD + dwOptionsFlags: DWORD + dwCodePage: DWORD + securityAttributes: SECURITY_ATTRIBUTES + iid: UUID + pUnk: pointer + dwReserved: DWORD + + IBindStatusCallback = object + vtable: ptr IBindStatusCallbackVTable + options: set[DownloadOptions] + objectRefCount: ULONG + binfoFlags: DWORD + progressCallback: DownloadProgressCallback + + PIBindStatusCallback = ptr IBindStatusCallback + LPBINDSTATUSCALLBACK = PIBindStatusCallback + + IBindStatusCallbackVTable = object + QueryInterface: proc (self: PIBindStatusCallback, + riid: ptr UUID, + pvObject: ptr pointer): HRESULT {.gcsafe,stdcall.} + AddRef: proc(self: PIBindStatusCallback): ULONG {.gcsafe, stdcall.} + Release: proc(self: PIBindStatusCallback): ULONG {.gcsafe, stdcall.} + OnStartBinding: proc(self: PIBindStatusCallback, + dwReserved: DWORD, pib: pointer): HRESULT + {.gcsafe, stdcall.} + GetPriority: proc(self: PIBindStatusCallback, pnPriority: ptr LONG): HRESULT + {.gcsafe, stdcall.} + OnLowResource: proc(self: PIBindStatusCallback, dwReserved: DWORD): HRESULT + {.gcsafe, stdcall.} + OnProgress: proc(self: PIBindStatusCallback, ulProgress: ULONG, + ulProgressMax: ULONG, ulStatusCode: ULONG, + szStatusText: LPWSTR): HRESULT + {.gcsafe, stdcall.} + OnStopBinding: proc(self: PIBindStatusCallback, hresult: HRESULT, + szError: LPWSTR): HRESULT + {.gcsafe, stdcall.} + GetBindInfo: proc(self: PIBindStatusCallback, grfBINDF: ptr DWORD, + pbindinfo: ptr BINDINFO): HRESULT + {.gcsafe, stdcall.} + OnDataAvailable: proc(self: PIBindStatusCallback, grfBSCF: DWORD, + dwSize: DWORD, pformatetc: pointer, + pstgmed: pointer): HRESULT + {.gcsafe, stdcall.} + OnObjectAvailable: proc(self: PIBindStatusCallback, riid: REFIID, + punk: pointer): HRESULT + {.gcsafe, stdcall.} + +template FAILED(hr: HRESULT): bool = + (hr < 0) + +proc URLDownloadToFile(pCaller: pointer, szUrl: LPWSTR, szFileName: LPWSTR, + dwReserved: DWORD, + lpfnCb: LPBINDSTATUSCALLBACK): HRESULT + {.stdcall, dynlib: "urlmon.dll", importc: "URLDownloadToFileW".} + +proc WideCharToMultiByte(CodePage: UINT, dwFlags: DWORD, + lpWideCharStr: ptr OLECHAR, cchWideChar: cint, + lpMultiByteStr: ptr char, cbMultiByte: cint, + lpDefaultChar: ptr char, + lpUsedDefaultChar: ptr uint32): cint + {.stdcall, dynlib: "kernel32.dll", importc: "WideCharToMultiByte".} + +proc MultiByteToWideChar(CodePage: UINT, dwFlags: DWORD, + lpMultiByteStr: ptr char, cbMultiByte: cint, + lpWideCharStr: ptr OLECHAR, cchWideChar: cint): cint + {.stdcall, dynlib: "kernel32.dll", importc: "MultiByteToWideChar".} +proc DeleteUrlCacheEntry(lpszUrlName: LPWSTR): int32 + {.stdcall, dynlib: "wininet.dll", importc: "DeleteUrlCacheEntryW".} + +proc `==`(a, b: UUID): bool = + result = false + if a[0] == b[0] and a[1] == b[1] and + a[2] == b[2] and a[3] == b[3]: + result = true + +proc `$`(bstr: LPWSTR): string = + var buffer: char + var count = WideCharToMultiByte(CP_UTF8, 0, bstr, -1, addr(buffer), 0, + nil, nil) + if count == 0: + raiseOsError(osLastError()) + else: + result = newString(count + 8) + let res = WideCharToMultiByte(CP_UTF8, 0, bstr, -1, addr(result[0]), count, + nil, nil) + if res == 0: + raiseOsError(osLastError()) + result.setLen(res - 1) + +proc toBstring(str: string): LPWSTR = + var buffer: OLECHAR + var count = MultiByteToWideChar(CP_UTF8, 0, unsafeAddr(str[0]), -1, + addr(buffer), 0) + if count == 0: + raiseOsError(osLastError()) + else: + result = cast[LPWSTR](alloc0((count + 1) * sizeof(OLECHAR))) + let res = MultiByteToWideChar(CP_UTF8, 0, unsafeAddr(str[0]), -1, + result, count) + if res == 0: + raiseOsError(osLastError()) + +proc freeBstring(bstr: LPWSTR) = + dealloc(bstr) + +proc getStatus(scode: ULONG): DownloadStatus = + case scode + of 0: result = statusError + of BINDSTATUS_PROXYDETECTING: result = statusProxyDetecting + of BINDSTATUS_REDIRECTING: result = statusRedirecting + of BINDSTATUS_COOKIE_SENT: result = statusCookieSent + of BINDSTATUS_FINDINGRESOURCE: result = statusResolving + of BINDSTATUS_CONNECTING: result = statusConnecting + of BINDSTATUS_SENDINGREQUEST: result = statusRequesting + of BINDSTATUS_MIMETYPEAVAILABLE: result = statusMimetypeAvailable + of BINDSTATUS_BEGINDOWNLOADDATA: result = statusBeginDownloading + of BINDSTATUS_DOWNLOADINGDATA: result = statusDownloading + of BINDSTATUS_ENDDOWNLOADDATA: result = statusEndDownloading + of BINDSTATUS_CACHEFILENAMEAVAILABLE: result = statusCacheAvailable + else: result = statusUnsupported + +proc addRef(self: PIBindStatusCallback): ULONG {.gcsafe, stdcall.} = + inc(self.objectRefCount) + result = self.objectRefCount + +proc release(self: PIBindStatusCallback): ULONG {.gcsafe, stdcall.} = + dec(self.objectRefCount) + result = self.objectRefCount + +proc queryInterface(self: PIBindStatusCallback, riid: ptr UUID, + pvObject: ptr pointer): HRESULT {.gcsafe,stdcall.} = + pvObject[] = nil + + if riid[] == IID_IUnknown: + pvObject[] = cast[pointer](self) + elif riid[] == IID_IBindStatusCallback: + pvObject[] = cast[pointer](self) + + if not isNil(pvObject[]): + discard addRef(self) + result = S_OK + else: + result = E_NOINTERFACE + +proc onStartBinding(self: PIBindStatusCallback, dwReserved: DWORD, + pib: pointer): HRESULT {.gcsafe, stdcall.} = + result = S_OK + +proc getPriority(self: PIBindStatusCallback, + pnPriority: ptr LONG): HRESULT {.gcsafe, stdcall.} = + result = E_NOTIMPL + +proc onLowResource(self: PIBindStatusCallback, + dwReserved: DWORD): HRESULT {.gcsafe, stdcall.} = + result = S_OK + +proc onStopBinding(self: PIBindStatusCallback, + hresult: HRESULT, szError: LPWSTR): HRESULT + {.gcsafe, stdcall.} = + result = S_OK + +proc getBindInfo(self: PIBindStatusCallback, + grfBINDF: ptr DWORD, pbindinfo: ptr BINDINFO): HRESULT + {.gcsafe, stdcall.} = + var cbSize = pbindinfo.cbSize + zeroMem(cast[pointer](pbindinfo), cbSize) + pbindinfo.cbSize = cbSize + grfBINDF[] = self.binfoFlags + result = S_OK + +proc onDataAvailable(self: PIBindStatusCallback, + grfBSCF: DWORD, dwSize: DWORD, pformatetc: pointer, + pstgmed: pointer): HRESULT {.gcsafe, stdcall.} = + result = S_OK + +proc onObjectAvailable(self: PIBindStatusCallback, + riid: REFIID, punk: pointer): HRESULT + {.gcsafe, stdcall.} = + result = S_OK + +proc onProgress(self: PIBindStatusCallback, + ulProgress: ULONG, ulProgressMax: ULONG, ulStatusCode: ULONG, + szStatusText: LPWSTR): HRESULT {.gcsafe, stdcall.} = + var message: string + if optUseProgressCallback in self.options: + if not isNil(szStatusText): + message = $szStatusText + else: + message = "" + self.progressCallback(getStatus(ulStatusCode), uint(ulProgress), + uint(ulProgressMax), message) + result = S_OK + +proc newBindStatusCallback(): IBindStatusCallback = + result = IBindStatusCallback() + result.vtable = cast[ptr IBindStatusCallbackVTable]( + alloc0(sizeof(IBindStatusCallbackVTable)) + ) + result.vtable.QueryInterface = queryInterface + result.vtable.AddRef = addRef + result.vtable.Release = release + result.vtable.OnStartBinding = onStartBinding + result.vtable.GetPriority = getPriority + result.vtable.OnLowResource = onLowResource + result.vtable.OnStopBinding = onStopBinding + result.vtable.GetBindInfo = getBindInfo + result.vtable.OnDataAvailable = onDataAvailable + result.vtable.OnObjectAvailable = onObjectAvailable + result.vtable.OnProgress = onProgress + result.objectRefCount = 1 + +proc freeBindStatusCallback(v: var IBindStatusCallback) = + dealloc(v.vtable) + +proc downloadToFile*(szUrl: string, szFileName: string, + options: set[DownloadOptions] = {}, + progresscb: DownloadProgressCallback = nil) = + ## Downloads from URL specified in ``szUrl`` to local filesystem path + ## specified in ``szFileName``. + ## + ## szUrl + ## URL to download, international names are supported. + ## szFileName + ## Destination path for downloading resource. + ## options + ## Downloading options. Currently only 2 options supported. + ## progresscb + ## Callback procedure, which will be called throughout the download + ## process, indicating status and progress. + ## + ## Available downloading options: + ## + ## optUseCache + ## Try to use Windows cache when downloading. + ## optIgnoreSecurity + ## Ignore HTTPS security problems, e.g. self-signed HTTPS certificate. + ## + var bszUrl = szUrl.toBstring() + var bszFile = szFileName.toBstring() + var bstatus = newBindStatusCallback() + + bstatus.options = {} + + if optUseCache notin options: + bstatus.options.incl(optUseCache) + let res = DeleteUrlCacheEntry(bszUrl) + if res == 0: + let err = osLastError() + if err.int notin {ERROR_ACCESS_DENIED, ERROR_FILE_NOT_FOUND}: + freeBindStatusCallback(bstatus) + freeBstring(bszUrl) + freeBstring(bszFile) + raiseOsError(err) + + bstatus.binfoFlags = BINDF_GETNEWESTVERSION or BINDF_RESYNCHRONIZE or + BINDF_PRAGMA_NO_CACHE or BINDF_NO_UI or + BINDF_SILENTOPERATION + + if optIgnoreSecurity in options: + bstatus.binfoFlags = bstatus.binfoFlags or BINDF_IGNORESECURITYPROBLEM + + if not isNil(progresscb): + bstatus.options.incl(optUseProgressCallback) + bstatus.progressCallback = progresscb + + let res = URLDownloadToFile(nil, bszUrl, bszFile, 0, addr bstatus) + if FAILED(res): + freeBindStatusCallback(bstatus) + freeBstring(bszUrl) + freeBstring(bszFile) + raiseOsError(OSErrorCode(res)) + + freeBindStatusCallback(bstatus) + freeBstring(bszUrl) + freeBstring(bszFile) + +when isMainModule: + proc progress(status: DownloadStatus, progress: uint, progressMax: uint, + message: string) {.procvar,gcsafe.} = + const downset: set[DownloadStatus] = {statusBeginDownloading, + statusDownloading, statusEndDownloading} + if status in downset: + var message = "Downloaded " & $progress & " of " & $progressMax & "\c" + stdout.write(message) + else: + echo "Status [" & $status & "] message = [" & $message & "]" + + downloadToFile("https://nim-lang.org/download/mingw64.7z", + "test.zip", {optUseCache}, progress) diff --git a/tools/vccexe/vccexe.nim b/tools/vccexe/vccexe.nim index d548666b9..1b5b2fb82 100644 --- a/tools/vccexe/vccexe.nim +++ b/tools/vccexe/vccexe.nim @@ -41,7 +41,6 @@ const platformPrefix = "--platform" sdktypePrefix = "--sdktype" sdkversionPrefix = "--sdkversion" - vctoolsetPrefix = "--vctoolset" verbosePrefix = "--verbose" vccversionSepIdx = vccversionPrefix.len @@ -50,7 +49,6 @@ const platformSepIdx = platformPrefix.len sdktypeSepIdx = sdktypePrefix.len sdkversionSepIdx = sdkversionPrefix.len - vctoolsetSepIdx = vctoolsetPrefix.len vcvarsallDefaultPath = "vcvarsall.bat" @@ -95,12 +93,10 @@ Options: --sdktype: Specify the SDK flavor to use. Defaults to the Desktop SDK. : {empty} | store | uwp | onecore --sdkversion: Use a specific Windows SDK version: - is either the full Windows 10 SDK version number or + is either the full Windows 10 SDK version number or "8.1" to use the windows 8.1 SDK --verbose Echoes the command line for loading the Developer Command Prompt and the command line passed on to the secondary command. - --vctoolset Optionally specifies the Visual Studio compiler toolset to use. - By default, the environment is set to use the current Visual Studio compiler toolset. Other command line arguments are passed on to the secondary command specified by --command or to the @@ -108,12 +104,12 @@ Microsoft (R) C/C++ Optimizing Compiler if no secondary command was specified """ -proc parseVccexeCmdLine(argseq: seq[string], +proc parseVccexeCmdLine(argseq: seq[TaintedString], vccversionArg: var seq[string], printPathArg: var bool, vcvarsallArg: var string, commandArg: var string, noCommandArg: var bool, platformArg: var VccArch, sdkTypeArg: var VccPlatformType, - sdkVersionArg: var string, vctoolsetArg: var string, verboseArg: var bool, - clArgs: var seq[string]) = + sdkVersionArg: var string, verboseArg: var bool, + clArgs: var seq[TaintedString]) = ## Cannot use usual command-line argument parser here ## Since vccexe command-line arguments are intermingled ## with the secondary command-line arguments which have @@ -129,7 +125,7 @@ proc parseVccexeCmdLine(argseq: seq[string], responseargs = parseCmdLine(responsecontent) parseVccexeCmdLine(responseargs, vccversionArg, printPathArg, vcvarsallArg, commandArg, noCommandArg, platformArg, sdkTypeArg, - sdkVersionArg, vctoolsetArg, verboseArg, clArgs) + sdkVersionArg, verboseArg, clArgs) elif wargv.startsWith(vccversionPrefix): # Check for vccversion vccversionArg.add(wargv.substr(vccversionSepIdx + 1)) elif wargv.cmpIgnoreCase(printPathPrefix) == 0: # Check for printPath @@ -146,8 +142,6 @@ proc parseVccexeCmdLine(argseq: seq[string], sdkTypeArg = parseEnum[VccPlatformType](wargv.substr(sdktypeSepIdx + 1)) elif wargv.startsWith(sdkversionPrefix): # Check for sdkversion sdkVersionArg = wargv.substr(sdkversionSepIdx + 1) - elif wargv.startsWith(vctoolsetPrefix): # Check for vctoolset - vctoolsetArg = wargv.substr(vctoolsetSepIdx + 1) elif wargv.startsWith(verbosePrefix): verboseArg = true else: # Regular cl.exe argument -> store for final cl.exe invocation @@ -164,14 +158,13 @@ when isMainModule: var platformArg: VccArch var sdkTypeArg: VccPlatformType var sdkVersionArg: string - var vctoolsetArg: string var verboseArg: bool = false - var clArgs: seq[string] = @[] + var clArgs: seq[TaintedString] = @[] let wrapperArgs = commandLineParams() parseVccexeCmdLine(wrapperArgs, vccversionArg, printPathArg, vcvarsallArg, - commandArg, noCommandArg, platformArg, sdkTypeArg, sdkVersionArg, vctoolsetArg, + commandArg, noCommandArg, platformArg, sdkTypeArg, sdkVersionArg, verboseArg, clArgs) @@ -202,7 +195,7 @@ when isMainModule: echo "$1: $2" % [head, vcvarsallArg] # Call vcvarsall to get the appropriate VCC process environment - var vcvars = vccVarsAll(vcvarsallArg, platformArg, sdkTypeArg, sdkVersionArg, vctoolsetArg, verboseArg) + var vcvars = vccVarsAll(vcvarsallArg, platformArg, sdkTypeArg, sdkVersionArg, verboseArg) if vcvars != nil: for vccEnvKey, vccEnvVal in vcvars: putEnv(vccEnvKey, vccEnvVal) diff --git a/tools/vccexe/vccvswhere.nim b/tools/vccexe/vccvswhere.nim index 8f62f06ca..11ad39ce9 100644 --- a/tools/vccexe/vccvswhere.nim +++ b/tools/vccexe/vccvswhere.nim @@ -18,7 +18,7 @@ proc vccVswhereExtractVcVarsAllPath(vswherePath: string): string = let vsPath = execProcess(&"\"{vswherePath}\" {vswhereArgs}").strip() if vsPath.len > 0: let vcvarsallPath = joinPath(vsPath, vcvarsRelativePath) - if fileExists(vcvarsallPath): + if existsFile(vcvarsallPath): return vcvarsallPath proc vccVswhereGeneratePath(envName: string): string = @@ -41,7 +41,7 @@ proc vccVswhereVcVarsAllPath*(): string = for tryEnv in ["ProgramFiles(x86)", "ProgramFiles"]: let vswherePath = vccVswhereGeneratePath(tryEnv) - if vswherePath.len > 0 and fileExists(vswherePath): + if vswherePath.len > 0 and existsFile(vswherePath): let vcVarsAllPath = vccVswhereExtractVcVarsAllPath(vswherePath) if vcVarsAllPath.len > 0: return vcVarsAllPath diff --git a/tools/vccexe/vcvarsall.nim b/tools/vccexe/vcvarsall.nim index 73b103e3c..29d13cc7e 100644 --- a/tools/vccexe/vcvarsall.nim +++ b/tools/vccexe/vcvarsall.nim @@ -33,7 +33,7 @@ type vccplatUWP = "uwp", ## Universal Windows Platform (UWP) Application vccplatOneCore = "onecore" # Undocumented platform type in the Windows SDK, probably XBox One SDK platform type. -proc vccVarsAll*(path: string, arch: VccArch = vccarchUnspecified, platform_type: VccPlatformType = vccplatEmpty, sdk_version, vctoolset: string = "", verbose: bool = false): StringTableRef = +proc vccVarsAll*(path: string, arch: VccArch = vccarchUnspecified, platform_type: VccPlatformType = vccplatEmpty, sdk_version: string = "", verbose: bool = false): StringTableRef = ## Returns a string table containing the proper process environment to successfully execute VCC compile commands for the specified SDK version, CPU architecture and platform type. ## ## path @@ -44,8 +44,6 @@ proc vccVarsAll*(path: string, arch: VccArch = vccarchUnspecified, platform_type ## The compile target Platform Type. Defaults to the Windows Desktop platform, i.e. a regular Windows executable binary. ## sdk_version ## The Windows SDK version to use. - ## vctoolset - ## Visual Studio compiler toolset to use. ## verbose ## Echo the command-line passed on to the system to load the VCC environment. Defaults to `false`. @@ -65,9 +63,6 @@ proc vccVarsAll*(path: string, arch: VccArch = vccarchUnspecified, platform_type if sdk_version.len > 0: args.add(sdk_version) - - if vctoolset.len > 0: - args.add("-vcvars_ver="&vctoolset) let argStr = args.join " " diff --git a/tools/website.nimf b/tools/website.nimf new file mode 100644 index 000000000..9e5eb2460 --- /dev/null +++ b/tools/website.nimf @@ -0,0 +1,266 @@ +#? stdtmpl | standard +#proc generateHTMLPage(c: var TConfigData, currentTab, title, content, rss, +# rootDir = ""): string = +# result = "" + + + + + ${title} - $c.projectTitle + + + #if len(rss) > 0: + + #end if + + + + + + +# if currentTab == "index": +
    +# else: +
    +# end +
    +
    + +# if currentTab == "index": +
    + +
    +
    +

    Nim is simple..

    +
    +# compute average line length
    +var
    +  sum = 0
    +  count = 0
    +
    +for line in stdin.lines:
    +  sum += line.len
    +  count += 1
    +
    +echo("Average line length: ",
    +  if count > 0: sum / count else: 0)
    +
    +
    +
    +

    ..and type safe...

    +
    +# create and greet someone
    +type Person = object
    +  name: string
    +  age: int
    +
    +proc greet(p: Person) =
    +  echo "Hi, I'm ", p.name, "."
    +  echo "I am ", p.age, " years old."
    +
    +let p = Person(name:"Jon", age:18)
    +p.greet() # or greet(p)
    +
    +
    +
    +
    +
    +

    C FFI is easy in Nim..

    +
    +# declare a C procedure..
    +proc unsafeScanf(f: File, s: cstring)
    +  {.varargs,
    +    importc: "fscanf",
    +    header: "<stdio.h>".}
    +
    +# ..and use it...
    +var x: cint
    +stdin.unsafeScanf("%d", addr x)
    +
    +

    Compile and run with:
        $ nim c -r example.nim

    +
    +
    +

    ..and DSLs are too...

    +
    +# a simple html server
    +import
    +  jester, asyncdispatch, htmlgen
    +
    +routes:
    +  get "/":
    +    resp h1("Hello world")
    +
    +runForever()
    +
    +

    View in browser at:
        localhost:5000

    +
    +
    +
    + + A printed copy of Nim in Action should be available in March 2017! + +
    +
    + + Meet our BountySource sponsors! + +
    +
    +
    +
    +
    +
    +
    +
    +# end + +
    +
    + +
    +
    +
    +
    +
    + $content +
    +
    +
    + + + + +# if currentTab == "index": + +# end if +# if c.gaId.len != 0: + +# end if + + +#end proc +# +# +#proc generateSponsors(sponsors: seq[Sponsor]): string = +#result = "" +#for sponsor in sponsors: +
    + #if sponsor.url.len > 0: + ${sponsor.name} + #else: + ${sponsor.name} + #end if +
    + +
    + Donated $$${sponsor.thisMonth} this month +
    +
    + Donated $$${sponsor.allTime} in total since ${sponsor.since} +
    +#end for +#end proc +#proc generateSponsorsPage(activeSponsors, inactiveSponsors: seq[Sponsor]): string = +#result = "" +

    Our Current Sponsors

    +

    This section lists the companies and individuals that are, very kindly, contributing a +monthly amount to help sustain Nim's development. For more details take a +look at the Bountysource campaign.

    +

    Last updated: ${getTime().getGMTime().format("dd/MM/yyyy")}

    +
    +${generateSponsors(activeSponsors)} +
    +# +

    Our Past Sponsors

    +

    This section lists the companies and individuals that have contributed +money in the past to help sustain Nim's development. For more details take a +look at the Bountysource campaign.

    +
    +${generateSponsors(inactiveSponsors)} +
    +# +#end proc
    text1